From c6c4d7bbbb498c38afa05688dfc2784948a0c4e2 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Thu, 11 Oct 2007 01:20:06 +0800 Subject: [PATCH 0001/2804] Blackfin arch: update platform driver resource information to all board files Signed-off-by: Bryan Wu --- arch/blackfin/mach-bf533/boards/cm_bf533.c | 81 ++- arch/blackfin/mach-bf533/boards/ezkit.c | 91 +++- arch/blackfin/mach-bf533/boards/stamp.c | 119 ++++- arch/blackfin/mach-bf537/boards/cm_bf537.c | 87 +++- .../mach-bf537/boards/generic_board.c | 397 +++++++++++++-- arch/blackfin/mach-bf537/boards/pnav10.c | 53 +- arch/blackfin/mach-bf537/boards/stamp.c | 142 +++++- arch/blackfin/mach-bf548/boards/ezkit.c | 477 +++++++++++++++++- arch/blackfin/mach-bf561/boards/cm_bf561.c | 84 ++- arch/blackfin/mach-bf561/boards/ezkit.c | 82 ++- 10 files changed, 1448 insertions(+), 165 deletions(-) diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c index 4545f363e641..a57b52d207cd 100644 --- a/arch/blackfin/mach-bf533/boards/cm_bf533.c +++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include #include /* @@ -93,7 +95,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { /* the modalias must be the same as spi device driver name */ .modalias = "m25p80", /* Name of spi_driver for this device */ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ .platform_data = &bfin_spi_flash_data, .controller_data = &spi_flash_chip_info, @@ -101,7 +103,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }, { .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 2, /* Framework chip select. */ .platform_data = NULL, /* No spi_driver specific config */ .controller_data = &spi_adc_chip_info, @@ -110,24 +112,40 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad1836-spi", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, .controller_data = &ad1836_spi_chip_info, }, #endif }; +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI, + .end = CH_SPI, + .flags = IORESOURCE_IRQ, + } +}; + /* SPI controller data */ -static struct bfin5xx_spi_master spi_bfin_master_info = { +static struct bfin5xx_spi_master bfin_spi0_info = { .num_chipselect = 8, .enable_dma = 1, /* master has the ability to do dma transfer */ }; -static struct platform_device spi_bfin_master_device = { - .name = "bfin-spi-master", - .id = 1, /* Bus number */ +static struct platform_device bfin_spi0_device = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, .dev = { - .platform_data = &spi_bfin_master_info, /* Passed to driver */ + .platform_data = &bfin_spi0_info, /* Passed to driver */ }, }; #endif /* spi master and devices */ @@ -227,6 +245,43 @@ static struct platform_device isp1362_hcd_device = { }; #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) +#define PATA_INT 38 + +static struct pata_platform_info bfin_pata_platform_data = { + .ioport_shift = 2, + .irq_type = IRQF_TRIGGER_HIGH | IRQF_DISABLED, +}; + +static struct resource bfin_pata_resources[] = { + { + .start = 0x2030C000, + .end = 0x2030C01F, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x2030D018, + .end = 0x2030D01B, + .flags = IORESOURCE_MEM, + }, + { + .start = PATA_INT, + .end = PATA_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pata_resources), + .resource = bfin_pata_resources, + .dev = { + .platform_data = &bfin_pata_platform_data, + } +}; +#endif + static struct platform_device *cm_bf533_devices[] __initdata = { #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) &bfin_uart_device, @@ -250,7 +305,11 @@ static struct platform_device *cm_bf533_devices[] __initdata = { #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - &spi_bfin_master_device, + &bfin_spi0_device, +#endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + &bfin_pata_device, #endif }; @@ -261,6 +320,10 @@ static int __init cm_bf533_init(void) #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); #endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + irq_desc[PATA_INT].status |= IRQ_NOAUTOEN; +#endif return 0; } diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c index 0000b8f1239c..5c1e35d3c012 100644 --- a/arch/blackfin/mach-bf533/boards/ezkit.c +++ b/arch/blackfin/mach-bf533/boards/ezkit.c @@ -35,7 +35,9 @@ #include #include #include +#include #include +#include #include /* @@ -50,6 +52,12 @@ static struct platform_device rtc_device = { }; #endif +#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE) +static struct platform_device bfin_fb_adv7393_device = { + .name = "bfin-adv7393", +}; +#endif + /* * USB-LAN EzExtender board * Driver needs to know address, irq and flag pin. @@ -131,7 +139,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { /* the modalias must be the same as spi device driver name */ .modalias = "m25p80", /* Name of spi_driver for this device */ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/ .platform_data = &bfin_spi_flash_data, .controller_data = &spi_flash_chip_info, @@ -143,7 +151,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. */ .platform_data = NULL, /* No spi_driver specific config */ .controller_data = &spi_adc_chip_info, @@ -154,24 +162,40 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad1836-spi", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, .controller_data = &ad1836_spi_chip_info, }, #endif }; +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI, + .end = CH_SPI, + .flags = IORESOURCE_IRQ, + } +}; + /* SPI controller data */ -static struct bfin5xx_spi_master spi_bfin_master_info = { +static struct bfin5xx_spi_master bfin_spi0_info = { .num_chipselect = 8, .enable_dma = 1, /* master has the ability to do dma transfer */ }; -static struct platform_device spi_bfin_master_device = { - .name = "bfin-spi-master", - .id = 1, /* Bus number */ +static struct platform_device bfin_spi0_device = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, .dev = { - .platform_data = &spi_bfin_master_info, /* Passed to driver */ + .platform_data = &bfin_spi0_info, /* Passed to driver */ }, }; #endif /* spi master and devices */ @@ -193,13 +217,54 @@ static struct platform_device bfin_uart_device = { }; #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) +#define PATA_INT 55 + +static struct pata_platform_info bfin_pata_platform_data = { + .ioport_shift = 1, + .irq_type = IRQF_TRIGGER_HIGH | IRQF_DISABLED, +}; + +static struct resource bfin_pata_resources[] = { + { + .start = 0x20314020, + .end = 0x2031403F, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x2031401C, + .end = 0x2031401F, + .flags = IORESOURCE_MEM, + }, + { + .start = PATA_INT, + .end = PATA_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pata_resources), + .resource = bfin_pata_resources, + .dev = { + .platform_data = &bfin_pata_platform_data, + } +}; +#endif + static struct platform_device *ezkit_devices[] __initdata = { #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) &smc91x_device, #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - &spi_bfin_master_device, + &bfin_spi0_device, +#endif + +#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE) + &bfin_fb_adv7393_device, #endif #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) @@ -209,6 +274,10 @@ static struct platform_device *ezkit_devices[] __initdata = { #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) &bfin_uart_device, #endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + &bfin_pata_device, +#endif }; static int __init ezkit_init(void) @@ -218,6 +287,10 @@ static int __init ezkit_init(void) #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); #endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + irq_desc[PATA_INT].status |= IRQ_NOAUTOEN; +#endif return 0; } diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c index a9143c4cbdcd..8975e06ea158 100644 --- a/arch/blackfin/mach-bf533/boards/stamp.c +++ b/arch/blackfin/mach-bf533/boards/stamp.c @@ -37,8 +37,11 @@ #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) #include #endif +#include #include +#include #include +#include /* * Name the Board for the /proc/cpuinfo @@ -77,6 +80,12 @@ static struct platform_device smc91x_device = { }; #endif +#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE) +static struct platform_device bfin_fb_adv7393_device = { + .name = "bfin-adv7393", +}; +#endif + #if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) static struct resource net2272_bfin_resources[] = { { @@ -177,7 +186,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { /* the modalias must be the same as spi device driver name */ .modalias = "m25p80", /* Name of spi_driver for this device */ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/ .platform_data = &bfin_spi_flash_data, .controller_data = &spi_flash_chip_info, @@ -189,7 +198,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. */ .platform_data = NULL, /* No spi_driver specific config */ .controller_data = &spi_adc_chip_info, @@ -200,7 +209,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad1836-spi", .max_speed_hz = 31250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, .controller_data = &ad1836_spi_chip_info, }, @@ -210,7 +219,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc_dummy", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 0, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -219,7 +228,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SPI_MMC_CS_CHAN, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -231,16 +240,16 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "fxs-spi", .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, - .chip_select = 3, + .bus_num = 0, + .chip_select = 8 - CONFIG_J11_JUMPER, .controller_data = &spi_si3xxx_chip_info, .mode = SPI_MODE_3, }, { .modalias = "fxo-spi", .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, - .chip_select = 2, + .bus_num = 0, + .chip_select = 8 - CONFIG_J19_JUMPER, .controller_data = &spi_si3xxx_chip_info, .mode = SPI_MODE_3, }, @@ -250,7 +259,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad5304_spi", .max_speed_hz = 1000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 2, .platform_data = NULL, .controller_data = &ad5304_chip_info, @@ -259,17 +268,33 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { #endif }; +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI, + .end = CH_SPI, + .flags = IORESOURCE_IRQ, + } +}; + /* SPI controller data */ -static struct bfin5xx_spi_master spi_bfin_master_info = { +static struct bfin5xx_spi_master bfin_spi0_info = { .num_chipselect = 8, .enable_dma = 1, /* master has the ability to do dma transfer */ }; -static struct platform_device spi_bfin_master_device = { - .name = "bfin-spi-master", - .id = 1, /* Bus number */ +static struct platform_device bfin_spi0_device = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, .dev = { - .platform_data = &spi_bfin_master_info, /* Passed to driver */ + .platform_data = &bfin_spi0_info, /* Passed to driver */ }, }; #endif /* spi master and devices */ @@ -309,6 +334,43 @@ static struct platform_device bfin_sport1_uart_device = { }; #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) +#define PATA_INT 55 + +static struct pata_platform_info bfin_pata_platform_data = { + .ioport_shift = 1, + .irq_type = IRQF_TRIGGER_HIGH | IRQF_DISABLED, +}; + +static struct resource bfin_pata_resources[] = { + { + .start = 0x20314020, + .end = 0x2031403F, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x2031401C, + .end = 0x2031401F, + .flags = IORESOURCE_MEM, + }, + { + .start = PATA_INT, + .end = PATA_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pata_resources), + .resource = bfin_pata_resources, + .dev = { + .platform_data = &bfin_pata_platform_data, + } +}; +#endif + static struct platform_device *stamp_devices[] __initdata = { #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) &rtc_device, @@ -318,12 +380,16 @@ static struct platform_device *stamp_devices[] __initdata = { &smc91x_device, #endif +#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE) + &bfin_fb_adv7393_device, +#endif + #if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) &net2272_bfin_device, #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - &spi_bfin_master_device, + &bfin_spi0_device, #endif #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) @@ -334,6 +400,10 @@ static struct platform_device *stamp_devices[] __initdata = { &bfin_sport0_uart_device, &bfin_sport1_uart_device, #endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + &bfin_pata_device, +#endif }; static int __init stamp_init(void) @@ -355,8 +425,23 @@ static int __init stamp_init(void) #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - return spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); + spi_register_board_info(bfin_spi_board_info, + ARRAY_SIZE(bfin_spi_board_info)); #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + irq_desc[PATA_INT].status |= IRQ_NOAUTOEN; +#endif + return 0; } arch_initcall(stamp_init); + +void native_machine_restart(char *cmd) +{ +#if defined(CONFIG_BFIN_SHARED_FLASH_ENET) +# define BIT_TO_SET (1 << CONFIG_ENET_FLASH_PIN) + bfin_write_FIO_INEN(~BIT_TO_SET); + bfin_write_FIO_DIR(BIT_TO_SET); + bfin_write_FIO_FLAG_C(BIT_TO_SET); +#endif +} diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c index a8f947b72754..44dea05e1d03 100644 --- a/arch/blackfin/mach-bf537/boards/cm_bf537.c +++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c @@ -35,7 +35,9 @@ #include #include #include +#include #include +#include #include /* @@ -113,7 +115,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { /* the modalias must be the same as spi device driver name */ .modalias = "m25p80", /* Name of spi_driver for this device */ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ .platform_data = &bfin_spi_flash_data, .controller_data = &spi_flash_chip_info, @@ -125,7 +127,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. */ .platform_data = NULL, /* No spi_driver specific config */ .controller_data = &spi_adc_chip_info, @@ -136,7 +138,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad1836-spi", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, .controller_data = &ad1836_spi_chip_info, }, @@ -146,7 +148,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad9960-spi", .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 1, .controller_data = &ad9960_spi_chip_info, }, @@ -156,7 +158,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc_dummy", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 7, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -165,7 +167,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SPI_MMC_CS_CHAN, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -174,17 +176,33 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { #endif }; +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI, + .end = CH_SPI, + .flags = IORESOURCE_IRQ, + } +}; + /* SPI controller data */ -static struct bfin5xx_spi_master spi_bfin_master_info = { +static struct bfin5xx_spi_master bfin_spi0_info = { .num_chipselect = 8, .enable_dma = 1, /* master has the ability to do dma transfer */ }; -static struct platform_device spi_bfin_master_device = { - .name = "bfin-spi-master", - .id = 1, /* Bus number */ +static struct platform_device bfin_spi0_device = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, .dev = { - .platform_data = &spi_bfin_master_info, /* Passed to driver */ + .platform_data = &bfin_spi0_info, /* Passed to driver */ }, }; #endif /* spi master and devices */ @@ -316,6 +334,43 @@ static struct platform_device bfin_mac_device = { }; #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) +#define PATA_INT 64 + +static struct pata_platform_info bfin_pata_platform_data = { + .ioport_shift = 2, + .irq_type = IRQF_TRIGGER_HIGH | IRQF_DISABLED, +}; + +static struct resource bfin_pata_resources[] = { + { + .start = 0x2030C000, + .end = 0x2030C01F, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x2030D018, + .end = 0x2030D01B, + .flags = IORESOURCE_MEM, + }, + { + .start = PATA_INT, + .end = PATA_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pata_resources), + .resource = bfin_pata_resources, + .dev = { + .platform_data = &bfin_pata_platform_data, + } +}; +#endif + static struct platform_device *cm_bf537_devices[] __initdata = { #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) &rtc_device, @@ -347,7 +402,11 @@ static struct platform_device *cm_bf537_devices[] __initdata = { #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - &spi_bfin_master_device, + &bfin_spi0_device, +#endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + &bfin_pata_device, #endif }; @@ -358,6 +417,10 @@ static int __init cm_bf537_init(void) #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); #endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + irq_desc[PATA_INT].status |= IRQ_NOAUTOEN; +#endif return 0; } diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c index 648d984e98d6..5e9d09eb8579 100644 --- a/arch/blackfin/mach-bf537/boards/generic_board.c +++ b/arch/blackfin/mach-bf537/boards/generic_board.c @@ -8,7 +8,7 @@ * * Modified: * Copyright 2005 National ICT Australia (NICTA) - * Copyright 2004-2006 Analog Devices Inc. + * Copyright 2004-2007 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -34,20 +34,74 @@ #include #include #include +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) #include +#endif +#include #include +#include #include +#include #include +#include +#include /* * Name the Board for the /proc/cpuinfo */ -char *bfin_board_name = "UNKNOWN BOARD"; +char *bfin_board_name = "GENERIC Board"; /* * Driver needs to know address, irq and flag pin. */ +#define ISP1761_BASE 0x203C0000 +#define ISP1761_IRQ IRQ_PF7 + +#if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE) +static struct resource bfin_isp1761_resources[] = { + [0] = { + .name = "isp1761-regs", + .start = ISP1761_BASE + 0x00000000, + .end = ISP1761_BASE + 0x000fffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ISP1761_IRQ, + .end = ISP1761_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_isp1761_device = { + .name = "isp1761", + .id = 0, + .num_resources = ARRAY_SIZE(bfin_isp1761_resources), + .resource = bfin_isp1761_resources, +}; + +static struct platform_device *bfin_isp1761_devices[] = { + &bfin_isp1761_device, +}; + +int __init bfin_isp1761_init(void) +{ + unsigned int num_devices = ARRAY_SIZE(bfin_isp1761_devices); + + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING); + + return platform_add_devices(bfin_isp1761_devices, num_devices); +} + +void __exit bfin_isp1761_exit(void) +{ + platform_device_unregister(&bfin_isp1761_device); +} + +arch_initcall(bfin_isp1761_init); +#endif + #if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE) static struct resource bfin_pcmcia_cf_resources[] = { { @@ -58,10 +112,6 @@ static struct resource bfin_pcmcia_cf_resources[] = { .start = 0x20311000, /* Attribute Memory */ .end = 0x20311FFF, .flags = IORESOURCE_MEM, - }, { - .start = IRQ_PROG_INTA, - .end = IRQ_PROG_INTA, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, }, { .start = IRQ_PF4, .end = IRQ_PF4, @@ -96,14 +146,7 @@ static struct resource smc91x_resources[] = { .end = 0x20300300 + 16, .flags = IORESOURCE_MEM, }, { - .start = IRQ_PROG_INTB, - .end = IRQ_PROG_INTB, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, - }, { - /* - * denotes the flag pin and is used directly if - * CONFIG_IRQCHIP_DEMUX_GPIO is defined. - */ + .start = IRQ_PF7, .end = IRQ_PF7, .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, @@ -117,6 +160,28 @@ static struct platform_device smc91x_device = { }; #endif +#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE) +static struct resource dm9000_resources[] = { + [0] = { + .start = 0x203FB800, + .end = 0x203FB800 + 8, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_PF9, + .end = IRQ_PF9, + .flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE), + }, +}; + +static struct platform_device dm9000_device = { + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(dm9000_resources), + .resource = dm9000_resources, +}; +#endif + #if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE) static struct resource sl811_hcd_resources[] = { { @@ -128,12 +193,8 @@ static struct resource sl811_hcd_resources[] = { .end = 0x20340004, .flags = IORESOURCE_MEM, }, { - .start = IRQ_PROG_INTA, - .end = IRQ_PROG_INTA, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, - }, { - .start = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO, - .end = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO, + .start = CONFIG_USB_SL811_BFIN_IRQ, + .end = CONFIG_USB_SL811_BFIN_IRQ, .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; @@ -141,21 +202,19 @@ static struct resource sl811_hcd_resources[] = { #if defined(CONFIG_USB_SL811_BFIN_USE_VBUS) void sl811_port_power(struct device *dev, int is_on) { - unsigned short mask = (1< #endif #include +#include #include #include @@ -130,15 +131,13 @@ static struct resource sl811_hcd_resources[] = { #if defined(CONFIG_USB_SL811_BFIN_USE_VBUS) void sl811_port_power(struct device *dev, int is_on) { - unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS); - - bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask); - bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask); + gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS"); + gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS); if (is_on) - bfin_write_FIO_FLAG_S(mask); + gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1); else - bfin_write_FIO_FLAG_C(mask); + gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0); } #endif @@ -323,7 +322,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { /* the modalias must be the same as spi device driver name */ .modalias = "m25p80", /* Name of spi_driver for this device */ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ .platform_data = &bfin_spi_flash_data, .controller_data = &spi_flash_chip_info, @@ -336,7 +335,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. */ .platform_data = NULL, /* No spi_driver specific config */ .controller_data = &spi_adc_chip_info, @@ -348,7 +347,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad1836-spi", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, .controller_data = &ad1836_spi_chip_info, }, @@ -357,7 +356,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad9960-spi", .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 1, .controller_data = &ad9960_spi_chip_info, }, @@ -366,7 +365,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc_dummy", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 7, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -375,7 +374,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SPI_MMC_CS_CHAN, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -396,24 +395,40 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }; +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI, + .end = CH_SPI, + .flags = IORESOURCE_IRQ, + } +}; + /* SPI controller data */ -static struct bfin5xx_spi_master spi_bfin_master_info = { +static struct bfin5xx_spi_master bfin_spi0_info = { .num_chipselect = 8, .enable_dma = 1, /* master has the ability to do dma transfer */ }; -static struct platform_device spi_bfin_master_device = { - .name = "bfin-spi-master", - .id = 1, /* Bus number */ +static struct platform_device bfin_spi0_device = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, .dev = { - .platform_data = &spi_bfin_master_info, /* Passed to driver */ + .platform_data = &bfin_spi0_info, /* Passed to driver */ }, }; #endif /* spi master and devices */ #if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) static struct platform_device bfin_fb_device = { - .name = "bf537-fb", + .name = "bf537-lq035", }; #endif @@ -469,7 +484,7 @@ static struct platform_device *stamp_devices[] __initdata = { #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - &spi_bfin_master_device, + &bfin_spi0_device, #endif #if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index 9c43d7756510..47d7d4a0e73d 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -37,10 +37,13 @@ #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) #include #endif +#include #include #include #include +#include #include +#include #include /* @@ -199,15 +202,13 @@ static struct resource sl811_hcd_resources[] = { #if defined(CONFIG_USB_SL811_BFIN_USE_VBUS) void sl811_port_power(struct device *dev, int is_on) { - unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS); - - bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask); - bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask); + gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS"); + gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS); if (is_on) - bfin_write_FIO_FLAG_S(mask); + gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1); else - bfin_write_FIO_FLAG_C(mask); + gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0); } #endif @@ -407,7 +408,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { /* the modalias must be the same as spi device driver name */ .modalias = "m25p80", /* Name of spi_driver for this device */ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ .platform_data = &bfin_spi_flash_data, .controller_data = &spi_flash_chip_info, @@ -420,7 +421,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. */ .platform_data = NULL, /* No spi_driver specific config */ .controller_data = &spi_adc_chip_info, @@ -432,7 +433,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad1836-spi", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, .controller_data = &ad1836_spi_chip_info, }, @@ -441,7 +442,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad9960-spi", .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 1, .controller_data = &ad9960_spi_chip_info, }, @@ -450,7 +451,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc_dummy", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 0, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -459,7 +460,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SPI_MMC_CS_CHAN, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -470,16 +471,16 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "fxs-spi", .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, - .chip_select = 3, + .bus_num = 0, + .chip_select = 8 - CONFIG_J11_JUMPER, .controller_data = &spi_si3xxx_chip_info, .mode = SPI_MODE_3, }, { .modalias = "fxo-spi", .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, - .chip_select = 2, + .bus_num = 0, + .chip_select = 8 - CONFIG_J19_JUMPER, .controller_data = &spi_si3xxx_chip_info, .mode = SPI_MODE_3, }, @@ -488,7 +489,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad5304_spi", .max_speed_hz = 1250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 2, .platform_data = NULL, .controller_data = &ad5304_chip_info, @@ -509,23 +510,45 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { }; /* SPI controller data */ -static struct bfin5xx_spi_master spi_bfin_master_info = { +static struct bfin5xx_spi_master bfin_spi0_info = { .num_chipselect = 8, .enable_dma = 1, /* master has the ability to do dma transfer */ }; -static struct platform_device spi_bfin_master_device = { - .name = "bfin-spi-master", - .id = 1, /* Bus number */ +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI, + .end = CH_SPI, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_spi0_device = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, .dev = { - .platform_data = &spi_bfin_master_info, /* Passed to driver */ + .platform_data = &bfin_spi0_info, /* Passed to driver */ }, }; #endif /* spi master and devices */ #if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) static struct platform_device bfin_fb_device = { - .name = "bf537-fb", + .name = "bf537-lq035", +}; +#endif + +#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE) +static struct platform_device bfin_fb_adv7393_device = { + .name = "bfin-adv7393", }; #endif @@ -551,9 +574,24 @@ static struct platform_device bfin_uart_device = { #endif #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE) +static struct resource bfin_twi0_resource[] = { + [0] = { + .start = TWI0_REGBASE, + .end = TWI0_REGBASE, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TWI, + .end = IRQ_TWI, + .flags = IORESOURCE_IRQ, + }, +}; + static struct platform_device i2c_bfin_twi_device = { .name = "i2c-bfin-twi", .id = 0, + .num_resources = ARRAY_SIZE(bfin_twi0_resource), + .resource = bfin_twi0_resource, }; #endif @@ -569,6 +607,43 @@ static struct platform_device bfin_sport1_uart_device = { }; #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) +#define PATA_INT 55 + +static struct pata_platform_info bfin_pata_platform_data = { + .ioport_shift = 1, + .irq_type = IRQF_TRIGGER_HIGH | IRQF_DISABLED, +}; + +static struct resource bfin_pata_resources[] = { + { + .start = 0x20314020, + .end = 0x2031403F, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x2031401C, + .end = 0x2031401F, + .flags = IORESOURCE_MEM, + }, + { + .start = PATA_INT, + .end = PATA_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pata_resources), + .resource = bfin_pata_resources, + .dev = { + .platform_data = &bfin_pata_platform_data, + } +}; +#endif + static struct platform_device *stamp_devices[] __initdata = { #if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE) &bfin_pcmcia_cf_device, @@ -603,13 +678,17 @@ static struct platform_device *stamp_devices[] __initdata = { #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - &spi_bfin_master_device, + &bfin_spi0_device, #endif #if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) &bfin_fb_device, #endif +#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE) + &bfin_fb_adv7393_device, +#endif + #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) &bfin_uart_device, #endif @@ -622,6 +701,10 @@ static struct platform_device *stamp_devices[] __initdata = { &bfin_sport0_uart_device, &bfin_sport1_uart_device, #endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + &bfin_pata_device, +#endif }; static int __init stamp_init(void) @@ -632,7 +715,18 @@ static int __init stamp_init(void) spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); #endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + irq_desc[PATA_INT].status |= IRQ_NOAUTOEN; +#endif return 0; } arch_initcall(stamp_init); + +void native_machine_restart(char *cmd) +{ + /* workaround reboot hang when booting from SPI */ + if ((bfin_read_SYSCR() & 0x7) == 0x3) + bfin_gpio_reset_spi0_ssel1(); +} diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c index 96ad95fab1a8..2c47db494f7d 100644 --- a/arch/blackfin/mach-bf548/boards/ezkit.c +++ b/arch/blackfin/mach-bf548/boards/ezkit.c @@ -35,9 +35,16 @@ #include #include #include -#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include /* * Name the Board for the /proc/cpuinfo @@ -48,6 +55,88 @@ char *bfin_board_name = "ADSP-BF548-EZKIT"; * Driver needs to know address, irq and flag pin. */ +#if defined(CONFIG_FB_BF54X_LQ043) || defined(CONFIG_FB_BF54X_LQ043_MODULE) + +#include + +static struct bfin_bf54xfb_mach_info bf54x_lq043_data = { + .width = 480, + .height = 272, + .xres = {480, 480, 480}, + .yres = {272, 272, 272}, + .bpp = {24, 24, 24}, + .disp = GPIO_PE3, +}; + +static struct resource bf54x_lq043_resources[] = { + { + .start = IRQ_EPPI0_ERR, + .end = IRQ_EPPI0_ERR, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bf54x_lq043_device = { + .name = "bf54x-lq043", + .id = -1, + .num_resources = ARRAY_SIZE(bf54x_lq043_resources), + .resource = bf54x_lq043_resources, + .dev = { + .platform_data = &bf54x_lq043_data, + }, +}; +#endif + +#if defined(CONFIG_KEYBOARD_BFIN) || defined(CONFIG_KEYBOARD_BFIN_MODULE) +static int bf548_keymap[] = { + KEYVAL(0, 0, KEY_ENTER), + KEYVAL(0, 1, KEY_HELP), + KEYVAL(0, 2, KEY_0), + KEYVAL(0, 3, KEY_BACKSPACE), + KEYVAL(1, 0, KEY_TAB), + KEYVAL(1, 1, KEY_9), + KEYVAL(1, 2, KEY_8), + KEYVAL(1, 3, KEY_7), + KEYVAL(2, 0, KEY_DOWN), + KEYVAL(2, 1, KEY_6), + KEYVAL(2, 2, KEY_5), + KEYVAL(2, 3, KEY_4), + KEYVAL(3, 0, KEY_UP), + KEYVAL(3, 1, KEY_3), + KEYVAL(3, 2, KEY_2), + KEYVAL(3, 3, KEY_1), +}; + +static struct bfin_kpad_platform_data bf54x_kpad_data = { + .rows = 4, + .cols = 4, + .keymap = bf548_keymap, + .keymapsize = ARRAY_SIZE(bf548_keymap), + .repeat = 0, + .debounce_time = 5000, /* ns (5ms) */ + .coldrive_time = 1000, /* ns (1ms) */ + .keyup_test_interval = 50, /* ms (50ms) */ +}; + +static struct resource bf54x_kpad_resources[] = { + { + .start = IRQ_KEY, + .end = IRQ_KEY, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bf54x_kpad_device = { + .name = "bf54x-keys", + .id = -1, + .num_resources = ARRAY_SIZE(bf54x_kpad_resources), + .resource = bf54x_kpad_resources, + .dev = { + .platform_data = &bf54x_kpad_data, + }, +}; +#endif + #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) static struct platform_device rtc_device = { .name = "rtc-bfin", @@ -94,6 +183,344 @@ static struct platform_device bfin_uart_device = { }; #endif +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) +static struct resource smsc911x_resources[] = { + { + .name = "smsc911x-memory", + .start = 0x24000000, + .end = 0x24000000 + 0xFF, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_PE8, + .end = IRQ_PE8, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + }, +}; +static struct platform_device smsc911x_device = { + .name = "smsc911x", + .id = 0, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, +}; +#endif + +#if defined(CONFIG_USB_BF54x_HCD) || defined(CONFIG_USB_BF54x_HCD_MODULE) +static struct resource bf54x_hcd_resources[] = { + { + .start = 0xFFC03C00, + .end = 0xFFC040FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bf54x_hcd = { + .name = "bf54x-hcd", + .id = 0, + .num_resources = ARRAY_SIZE(bf54x_hcd_resources), + .resource = bf54x_hcd_resources, +}; +#endif + +#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE) +static struct resource musb_resources[] = { + [0] = { + .start = 0xFFC03C00, + .end = 0xFFC040FF, + .flags = IORESOURCE_MEM, + }, + [1] = { /* general IRQ */ + .start = IRQ_USB_INT0, + .end = IRQ_USB_INT0, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, + [2] = { /* DMA IRQ */ + .start = IRQ_USB_DMA, + .end = IRQ_USB_DMA, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct musb_hdrc_platform_data musb_plat = { +#ifdef CONFIG_USB_MUSB_OTG + .mode = MUSB_OTG, +#elif CONFIG_USB_MUSB_HDRC_HCD + .mode = MUSB_HOST, +#elif CONFIG_USB_GADGET_MUSB_HDRC + .mode = MUSB_PERIPHERAL, +#endif + .multipoint = 1, +}; + +static u64 musb_dmamask = ~(u32)0; + +static struct platform_device musb_device = { + .name = "musb_hdrc", + .id = 0, + .dev = { + .dma_mask = &musb_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &musb_plat, + }, + .num_resources = ARRAY_SIZE(musb_resources), + .resource = musb_resources, +}; +#endif + +#if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE) +static struct resource bfin_atapi_resources[] = { + { + .start = 0xFFC03800, + .end = 0xFFC0386F, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_ATAPI_ERR, + .end = IRQ_ATAPI_ERR, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_atapi_device = { + .name = "pata-bf54x", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_atapi_resources), + .resource = bfin_atapi_resources, +}; +#endif + +#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE) +static struct mtd_partition partition_info[] = { + { + .name = "Linux Kernel", + .offset = 0, + .size = 4 * SIZE_1M, + }, + { + .name = "File System", + .offset = 4 * SIZE_1M, + .size = (256 - 4) * SIZE_1M, + }, +}; + +static struct bf5xx_nand_platform bf5xx_nand_platform = { + .page_size = NFC_PG_SIZE_256, + .data_width = NFC_NWIDTH_8, + .partitions = partition_info, + .nr_partitions = ARRAY_SIZE(partition_info), + .rd_dly = 3, + .wr_dly = 3, +}; + +static struct resource bf5xx_nand_resources[] = { + { + .start = 0xFFC03B00, + .end = 0xFFC03B4F, + .flags = IORESOURCE_MEM, + }, + { + .start = CH_NFC, + .end = CH_NFC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bf5xx_nand_device = { + .name = "bf5xx-nand", + .id = 0, + .num_resources = ARRAY_SIZE(bf5xx_nand_resources), + .resource = bf5xx_nand_resources, + .dev = { + .platform_data = &bf5xx_nand_platform, + }, +}; +#endif + +#if defined(CONFIG_SDH_BFIN) || defined(CONFIG_SDH_BFIN) +static struct platform_device bf54x_sdh_device = { + .name = "bfin-sdh", + .id = 0, +}; +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) +/* all SPI peripherals info goes here */ +#if defined(CONFIG_MTD_M25P80) \ + || defined(CONFIG_MTD_M25P80_MODULE) +/* SPI flash chip (m25p16) */ +static struct mtd_partition bfin_spi_flash_partitions[] = { + { + .name = "bootloader", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_CAP_ROM + }, { + .name = "linux kernel", + .size = 0x1c0000, + .offset = 0x40000 + } +}; + +static struct flash_platform_data bfin_spi_flash_data = { + .name = "m25p80", + .parts = bfin_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), + .type = "m25p16", +}; + +static struct bfin5xx_spi_chip spi_flash_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, + .cs_change_per_word = 0, +}; +#endif + +#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .cs_change_per_word = 1, + .enable_dma = 0, + .bits_per_word = 16, +}; + +static const struct ad7877_platform_data bfin_ad7877_ts_info = { + .model = 7877, + .vref_delay_usecs = 50, /* internal, no capacitor */ + .x_plate_ohms = 419, + .y_plate_ohms = 486, + .pressure_max = 1000, + .pressure_min = 0, + .stopacq_polarity = 1, + .first_conversion_delay = 3, + .acquisition_time = 1, + .averaging = 1, + .pen_down_acc_interval = 1, +}; +#endif + +static struct spi_board_info bf54x_spi_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) \ + || defined(CONFIG_MTD_M25P80_MODULE) + { + /* the modalias must be the same as spi device driver name */ + .modalias = "m25p80", /* Name of spi_driver for this device */ + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, /* Framework bus number */ + .chip_select = 1, /* SPI_SSEL1*/ + .platform_data = &bfin_spi_flash_data, + .controller_data = &spi_flash_chip_info, + .mode = SPI_MODE_3, + }, +#endif +#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +{ + .modalias = "ad7877", + .platform_data = &bfin_ad7877_ts_info, + .irq = IRQ_PJ11, + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, + .chip_select = 2, + .controller_data = &spi_ad7877_chip_info, +}, +#endif +}; + +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI0, + .end = CH_SPI0, + .flags = IORESOURCE_IRQ, + } +}; + +/* SPI (1) */ +static struct resource bfin_spi1_resource[] = { + [0] = { + .start = SPI1_REGBASE, + .end = SPI1_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI1, + .end = CH_SPI1, + .flags = IORESOURCE_IRQ, + } +}; + +/* SPI controller data */ +static struct bfin5xx_spi_master bf54x_spi_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device bf54x_spi_master0 = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, + .dev = { + .platform_data = &bf54x_spi_master_info, /* Passed to driver */ + }, +}; + +static struct platform_device bf54x_spi_master1 = { + .name = "bfin-spi", + .id = 1, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi1_resource), + .resource = bfin_spi1_resource, + .dev = { + .platform_data = &bf54x_spi_master_info, /* Passed to driver */ + }, +}; +#endif /* spi master and devices */ + +#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE) +static struct resource bfin_twi0_resource[] = { + [0] = { + .start = TWI0_REGBASE, + .end = TWI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TWI0, + .end = IRQ_TWI0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device i2c_bfin_twi0_device = { + .name = "i2c-bfin-twi", + .id = 0, + .num_resources = ARRAY_SIZE(bfin_twi0_resource), + .resource = bfin_twi0_resource, +}; + +static struct resource bfin_twi1_resource[] = { + [0] = { + .start = TWI1_REGBASE, + .end = TWI1_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_TWI1, + .end = IRQ_TWI1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device i2c_bfin_twi1_device = { + .name = "i2c-bfin-twi", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_twi1_resource), + .resource = bfin_twi1_resource, +}; +#endif + static struct platform_device *ezkit_devices[] __initdata = { #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) &rtc_device, @@ -102,12 +529,60 @@ static struct platform_device *ezkit_devices[] __initdata = { #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) &bfin_uart_device, #endif + +#if defined(CONFIG_FB_BF54X_LQ043) || defined(CONFIG_FB_BF54X_LQ043_MODULE) + &bf54x_lq043_device, +#endif + +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) + &smsc911x_device, +#endif + +#if defined(CONFIG_USB_BF54x_HCD) || defined(CONFIG_USB_BF54x_HCD_MODULE) + &bf54x_hcd, +#endif + +#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE) + &musb_device, +#endif + +#if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE) + &bfin_atapi_device, +#endif + +#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE) + &bf5xx_nand_device, +#endif + +#if defined(CONFIG_SDH_BFIN) || defined(CONFIG_SDH_BFIN) + &bf54x_sdh_device, +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &bf54x_spi_master0, +/* &bf54x_spi_master1,*/ +#endif + +#if defined(CONFIG_KEYBOARD_BFIN) || defined(CONFIG_KEYBOARD_BFIN_MODULE) + &bf54x_kpad_device, +#endif + +#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE) + &i2c_bfin_twi0_device, + &i2c_bfin_twi1_device, +#endif }; static int __init stamp_init(void) { printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices)); + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bf54x_spi_board_info, + ARRAY_SIZE(bf54x_spi_board_info)); +#endif + return 0; } diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c index 5b2b544529a1..cd827a1b6ba1 100644 --- a/arch/blackfin/mach-bf561/boards/cm_bf561.c +++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include #include /* @@ -112,7 +114,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { /* the modalias must be the same as spi device driver name */ .modalias = "m25p80", /* Name of spi_driver for this device */ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ .platform_data = &bfin_spi_flash_data, .controller_data = &spi_flash_chip_info, @@ -124,7 +126,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, /* Framework bus number */ + .bus_num = 0, /* Framework bus number */ .chip_select = 1, /* Framework chip select. */ .platform_data = NULL, /* No spi_driver specific config */ .controller_data = &spi_adc_chip_info, @@ -135,7 +137,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad1836-spi", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, .controller_data = &ad1836_spi_chip_info, }, @@ -144,7 +146,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad9960-spi", .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = 1, .controller_data = &ad9960_spi_chip_info, }, @@ -153,7 +155,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "spi_mmc", .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SPI_MMC_CS_CHAN, .platform_data = NULL, .controller_data = &spi_mmc_chip_info, @@ -162,17 +164,33 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { #endif }; +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI, + .end = CH_SPI, + .flags = IORESOURCE_IRQ, + } +}; + /* SPI controller data */ -static struct bfin5xx_spi_master spi_bfin_master_info = { +static struct bfin5xx_spi_master bfin_spi0_info = { .num_chipselect = 8, .enable_dma = 1, /* master has the ability to do dma transfer */ }; -static struct platform_device spi_bfin_master_device = { - .name = "bfin-spi-master", - .id = 1, /* Bus number */ +static struct platform_device bfin_spi0_device = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, .dev = { - .platform_data = &spi_bfin_master_info, /* Passed to driver */ + .platform_data = &bfin_spi0_info, /* Passed to driver */ }, }; #endif /* spi master and devices */ @@ -256,6 +274,43 @@ static struct platform_device bfin_uart_device = { }; #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) +#define PATA_INT 119 + +static struct pata_platform_info bfin_pata_platform_data = { + .ioport_shift = 2, + .irq_type = IRQF_TRIGGER_HIGH | IRQF_DISABLED, +}; + +static struct resource bfin_pata_resources[] = { + { + .start = 0x2400C000, + .end = 0x2400C001F, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x2400D018, + .end = 0x2400D01B, + .flags = IORESOURCE_MEM, + }, + { + .start = PATA_INT, + .end = PATA_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pata_resources), + .resource = bfin_pata_resources, + .dev = { + .platform_data = &bfin_pata_platform_data, + } +}; +#endif + static struct platform_device *cm_bf561_devices[] __initdata = { #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) @@ -271,9 +326,12 @@ static struct platform_device *cm_bf561_devices[] __initdata = { #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - &spi_bfin_master_device, + &bfin_spi0_device, #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + &bfin_pata_device, +#endif }; static int __init cm_bf561_init(void) @@ -283,6 +341,10 @@ static int __init cm_bf561_init(void) #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); #endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + irq_desc[PATA_INT].status |= IRQ_NOAUTOEN; +#endif return 0; } diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c index 724191da20a2..57e14edca8b1 100644 --- a/arch/blackfin/mach-bf561/boards/ezkit.c +++ b/arch/blackfin/mach-bf561/boards/ezkit.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include /* @@ -140,17 +142,33 @@ static struct bfin5xx_spi_chip ad1836_spi_chip_info = { #endif #endif +/* SPI (0) */ +static struct resource bfin_spi0_resource[] = { + [0] = { + .start = SPI0_REGBASE, + .end = SPI0_REGBASE + 0xFF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = CH_SPI, + .end = CH_SPI, + .flags = IORESOURCE_IRQ, + } +}; + /* SPI controller data */ -static struct bfin5xx_spi_master spi_bfin_master_info = { +static struct bfin5xx_spi_master bfin_spi0_info = { .num_chipselect = 8, .enable_dma = 1, /* master has the ability to do dma transfer */ }; -static struct platform_device spi_bfin_master_device = { - .name = "bfin-spi-master", - .id = 1, /* Bus number */ +static struct platform_device bfin_spi0_device = { + .name = "bfin-spi", + .id = 0, /* Bus number */ + .num_resources = ARRAY_SIZE(bfin_spi0_resource), + .resource = bfin_spi0_resource, .dev = { - .platform_data = &spi_bfin_master_info, /* Passed to driver */ + .platform_data = &bfin_spi0_info, /* Passed to driver */ }, }; @@ -160,23 +178,63 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { { .modalias = "ad1836-spi", .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ - .bus_num = 1, + .bus_num = 0, .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, .controller_data = &ad1836_spi_chip_info, }, #endif }; +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) +#define PATA_INT 55 + +static struct pata_platform_info bfin_pata_platform_data = { + .ioport_shift = 1, + .irq_type = IRQF_TRIGGER_HIGH | IRQF_DISABLED, +}; + +static struct resource bfin_pata_resources[] = { + { + .start = 0x20314020, + .end = 0x2031403F, + .flags = IORESOURCE_MEM, + }, + { + .start = 0x2031401C, + .end = 0x2031401F, + .flags = IORESOURCE_MEM, + }, + { + .start = PATA_INT, + .end = PATA_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pata_resources), + .resource = bfin_pata_resources, + .dev = { + .platform_data = &bfin_pata_platform_data, + } +}; +#endif + static struct platform_device *ezkit_devices[] __initdata = { #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) &smc91x_device, #endif #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) - &spi_bfin_master_device, + &bfin_spi0_device, #endif #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) &bfin_uart_device, #endif +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + &bfin_pata_device, +#endif }; static int __init ezkit_init(void) @@ -194,7 +252,15 @@ static int __init ezkit_init(void) SSYNC(); #endif - return spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bfin_spi_board_info, + ARRAY_SIZE(bfin_spi_board_info)); +#endif + +#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE) + irq_desc[PATA_INT].status |= IRQ_NOAUTOEN; +#endif + return 0; } arch_initcall(ezkit_init); From 287050fe13bf34824f03b4351002b0e2db4ee5cb Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 24 Jul 2007 15:23:20 +0800 Subject: [PATCH 0002/2804] Blackfin arch: cleanup and standardize anomaly.h file format -- no functional changes Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf533/anomaly.h | 136 +++++++++----------- include/asm-blackfin/mach-bf537/anomaly.h | 90 +++++-------- include/asm-blackfin/mach-bf548/anomaly.h | 67 ++++------ include/asm-blackfin/mach-bf561/anomaly.h | 147 +++++++++------------- 4 files changed, 174 insertions(+), 266 deletions(-) diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h index 7302f290b93d..2a63ffc250a1 100644 --- a/include/asm-blackfin/mach-bf533/anomaly.h +++ b/include/asm-blackfin/mach-bf533/anomaly.h @@ -1,31 +1,9 @@ /* - * File: include/asm-blackfin/mach-bf533/anomaly.h - * Based on: - * Author: + * File: include/asm-blackfin/mach-bf533/anomaly.h + * Bugs: Enter bugs at http://blackfin.uclinux.org/ * - * Created: - * Description: - * - * Rev: - * - * 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, 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, - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Copyright (C) 2004-2007 Analog Devices Inc. + * Licensed under the GPL-2 or later. */ /* This file shoule be up to date with: @@ -43,44 +21,44 @@ #endif /* Issues that are common to 0.5, 0.4, and 0.3 silicon */ -#if (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_4) \ +#if (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_4) \ || defined(CONFIG_BF_REV_0_3)) #define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in - slot1 and store of a P register in slot 2 is not - supported */ + * slot1 and store of a P register in slot 2 is not + * supported */ #define ANOMALY_05000105 /* Watchpoint Status Register (WPSTAT) bits are set on - every corresponding match */ + * every corresponding match */ #define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive - Channel DMA stops */ + * Channel DMA stops */ #define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR - registers. */ + * registers. */ #define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out - upper bits*/ + * upper bits*/ #define ANOMALY_05000167 /* Turning Serial Ports on With External Frame Syncs */ #define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame - syncs */ + * syncs */ #define ANOMALY_05000208 /* VSTAT status bit in PLL_STAT register is not - functional */ + * functional */ #define ANOMALY_05000219 /* NMI event at boot time results in unpredictable - state */ + * state */ #define ANOMALY_05000229 /* SPI Slave Boot Mode modifies registers */ #define ANOMALY_05000272 /* Certain data cache write through modes fail for - VDDint <=0.9V */ + * VDDint <=0.9V */ #define ANOMALY_05000273 /* Writes to Synchronous SDRAM memory may be lost */ #define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after - an edge is detected may clear interrupt */ + * an edge is detected may clear interrupt */ #define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause - DMA system instability */ + * DMA system instability */ #define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is - not restored */ + * not restored */ #define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic - control */ + * control */ #define ANOMALY_05000283 /* A system MMR write is stalled indefinitely when - killed in a particular stage*/ + * killed in a particular stage*/ #define ANOMALY_05000311 /* Erroneous flag pin operations under specific - sequences */ + * sequences */ #define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC - registers are interrupted */ + * registers are interrupted */ #define ANOMALY_05000313 /* PPI Is Level-Sensitive on First Transfer */ #define ANOMALY_05000315 /* Killed System MMR Write Completes Erroneously On * Next System MMR Access */ @@ -91,90 +69,90 @@ /* These issues only occur on 0.3 or 0.4 BF533 */ #if (defined(CONFIG_BF_REV_0_4) || defined(CONFIG_BF_REV_0_3)) #define ANOMALY_05000099 /* UART Line Status Register (UART_LSR) bits are not - updated at the same time. */ + * updated at the same time. */ #define ANOMALY_05000158 /* Boot fails when data cache enabled: Data from a Data - Cache Fill can be corrupted after or during - Instruction DMA if certain core stalls exist */ + * Cache Fill can be corrupted after or during + * Instruction DMA if certain core stalls exist */ #define ANOMALY_05000179 /* PPI_COUNT cannot be programmed to 0 in General - Purpose TX or RX modes */ + * Purpose TX or RX modes */ #define ANOMALY_05000198 /* Failing SYSTEM MMR accesses when stalled by - preceding memory read */ + * preceding memory read */ #define ANOMALY_05000200 /* SPORT TFS and DT are incorrectly driven during - inactive channels in certain conditions */ + * inactive channels in certain conditions */ #define ANOMALY_05000202 /* Possible infinite stall with specific dual dag - situation */ + * situation */ #define ANOMALY_05000215 /* UART TX Interrupt masked erroneously */ #define ANOMALY_05000225 /* Incorrect pulse-width of UART start-bit */ #define ANOMALY_05000227 /* Scratchpad memory bank reads may return incorrect - data*/ + * data*/ #define ANOMALY_05000230 /* UART Receiver is less robust against Baudrate - Differences in certain Conditions */ + * Differences in certain Conditions */ #define ANOMALY_05000231 /* UART STB bit incorrectly affects receiver setting */ #define ANOMALY_05000242 /* DF bit in PLL_CTL register does not respond to - hardware reset */ + * hardware reset */ #define ANOMALY_05000244 /* With instruction cache enabled, a CSYNC or SSYNC or - IDLE around a Change of Control causes - unpredictable results */ + * IDLE around a Change of Control causes + * unpredictable results */ #define ANOMALY_05000245 /* Spurious Hardware Error from an access in the - shadow of a conditional branch */ + * shadow of a conditional branch */ #define ANOMALY_05000246 /* Data CPLB's should prevent spurious hardware - errors */ + * errors */ #define ANOMALY_05000253 /* Maximum external clock speed for Timers */ #define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event - interrupt not functional */ + * interrupt not functional */ #define ANOMALY_05000257 /* An interrupt or exception during short Hardware - loops may cause the instruction fetch unit to - malfunction */ + * loops may cause the instruction fetch unit to + * malfunction */ #define ANOMALY_05000258 /* Instruction Cache is corrupted when bit 9 and 12 of - the ICPLB Data registers differ */ + * the ICPLB Data registers differ */ #define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */ #define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */ #define ANOMALY_05000262 /* Stores to data cache may be lost */ #define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB exception */ #define ANOMALY_05000264 /* A Sync instruction (CSYNC, SSYNC) or an IDLE - instruction will cause an infinite stall in the - second to last instruction in a hardware loop */ + * instruction will cause an infinite stall in the + * second to last instruction in a hardware loop */ #define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on - SPORT external receive and transmit clocks. */ + * SPORT external receive and transmit clocks. */ #define ANOMALY_05000269 /* High I/O activity causes the output voltage of the - internal voltage regulator (VDDint) to increase. */ + * internal voltage regulator (VDDint) to increase. */ #define ANOMALY_05000270 /* High I/O activity causes the output voltage of the - internal voltage regulator (VDDint) to decrease */ + * internal voltage regulator (VDDint) to decrease */ #endif /* issues only occur on 0.3 or 0.4 BF533 */ /* These issues are only on 0.4 silicon */ #if (defined(CONFIG_BF_REV_0_4)) #define ANOMALY_05000234 /* Incorrect Revision Number in DSPID Register */ #define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel - (TDM) */ + * (TDM) */ #endif /* issues are only on 0.4 silicon */ /* These issues are only on 0.3 silicon */ #if defined(CONFIG_BF_REV_0_3) #define ANOMALY_05000183 /* Timer Pin limitations for PPI TX Modes with - External Frame Syncs */ + * External Frame Syncs */ #define ANOMALY_05000189 /* False Protection Exceptions caused by Speculative - Instruction or Data Fetches, or by Fetches at the - boundary of reserved memory space */ + * Instruction or Data Fetches, or by Fetches at the + * boundary of reserved memory space */ #define ANOMALY_05000193 /* False Flag Pin Interrupts on Edge Sensitive Inputs - when polarity setting is changed */ + * when polarity setting is changed */ #define ANOMALY_05000194 /* Sport Restarting in specific modes may cause data - corruption */ + * corruption */ #define ANOMALY_05000199 /* DMA current address shows wrong value during carry - fix */ + * fix */ #define ANOMALY_05000201 /* Receive frame sync not ignored during active - frames in sport MCM */ + * frames in sport MCM */ #define ANOMALY_05000203 /* Specific sequence that can cause DMA error or DMA - stopping */ + * stopping */ #if defined(CONFIG_BF533) #define ANOMALY_05000204 /* Incorrect data read with write-through cache and - allocate cache lines on reads only mode */ + * allocate cache lines on reads only mode */ #endif /* CONFIG_BF533 */ #define ANOMALY_05000207 /* Recovery from "brown-out" condition */ #define ANOMALY_05000209 /* Speed-Path in computational unit affects certain - instructions */ + * instructions */ #define ANOMALY_05000233 /* PPI_FS3 is not driven in 2 or 3 internal Frame - Sync Transmit Mode */ + * Sync Transmit Mode */ #define ANOMALY_05000271 /* Spontaneous reset of Internal Voltage Regulator */ #endif /* only on 0.3 silicon */ diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h index 4453e614c3b1..5c5e33dec5f1 100644 --- a/include/asm-blackfin/mach-bf537/anomaly.h +++ b/include/asm-blackfin/mach-bf537/anomaly.h @@ -1,33 +1,9 @@ - /* - * File: include/asm-blackfin/mach-bf537/anomaly.h - * Based on: - * Author: + * File: include/asm-blackfin/mach-bf537/anomaly.h + * Bugs: Enter bugs at http://blackfin.uclinux.org/ * - * Created: - * Description: - * - * Rev: - * - * 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, 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, - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Copyright (C) 2004-2007 Analog Devices Inc. + * Licensed under the GPL-2 or later. */ /* This file shoule be up to date with: @@ -46,37 +22,37 @@ #if (defined(CONFIG_BF_REV_0_3) || defined(CONFIG_BF_REV_0_2)) #define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in - slot1 and store of a P register in slot 2 is not - supported */ + * slot1 and store of a P register in slot 2 is not + * supported */ #define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive - Channel DMA stops */ + * Channel DMA stops */ #define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR - registers. */ + * registers. */ #define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out - upper bits*/ + * upper bits*/ #define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame - syncs */ + * syncs */ #if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) #define ANOMALY_05000247 /* CLKIN Buffer Output Enable Reset Behavior Is - Changed */ + * Changed */ #endif #define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on - SPORT external receive and transmit clocks. */ + * SPORT external receive and transmit clocks. */ #define ANOMALY_05000272 /* Certain data cache write through modes fail for - VDDint <=0.9V */ + * VDDint <=0.9V */ #define ANOMALY_05000273 /* Writes to Synchronous SDRAM memory may be lost */ #define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after - an edge is detected may clear interrupt */ + * an edge is detected may clear interrupt */ #define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is - not restored */ + * not restored */ #define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic - control */ + * control */ #define ANOMALY_05000283 /* A system MMR write is stalled indefinitely when - killed in a particular stage*/ + * killed in a particular stage*/ #define ANOMALY_05000310 /* False hardware errors caused by fetches at the * boundary of reserved memory */ #define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC - registers are interrupted */ + * registers are interrupted */ #define ANOMALY_05000313 /* PPI is level sensitive on first transfer */ #define ANOMALY_05000322 /* EMAC RMII mode at 10-Base-T speed: RX frames not * received properly */ @@ -84,41 +60,41 @@ #if defined(CONFIG_BF_REV_0_2) #define ANOMALY_05000244 /* With instruction cache enabled, a CSYNC or SSYNC or - IDLE around a Change of Control causes - unpredictable results */ + * IDLE around a Change of Control causes + * unpredictable results */ #define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel - (TDM) */ + * (TDM) */ #if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) #define ANOMALY_05000252 /* EMAC Tx DMA error after an early frame abort */ #endif #define ANOMALY_05000253 /* Maximum external clock speed for Timers */ #define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event - interrupt not functional */ + * interrupt not functional */ #if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) #define ANOMALY_05000256 /* EMAC MDIO input latched on wrong MDC edge */ #endif #define ANOMALY_05000257 /* An interrupt or exception during short Hardware - loops may cause the instruction fetch unit to - malfunction */ + * loops may cause the instruction fetch unit to + * malfunction */ #define ANOMALY_05000258 /* Instruction Cache is corrupted when bit 9 and 12 of - the ICPLB Data registers differ */ + * the ICPLB Data registers differ */ #define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */ #define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */ #define ANOMALY_05000262 /* Stores to data cache may be lost */ #define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB exception */ #define ANOMALY_05000264 /* A Sync instruction (CSYNC, SSYNC) or an IDLE - instruction will cause an infinite stall in the - second to last instruction in a hardware loop */ + * instruction will cause an infinite stall in the + * second to last instruction in a hardware loop */ #define ANOMALY_05000268 /* Memory DMA error when peripheral DMA is running - and non-zero DEB_TRAFFIC_PERIOD value */ + * and non-zero DEB_TRAFFIC_PERIOD value */ #define ANOMALY_05000270 /* High I/O activity causes the output voltage of the - internal voltage regulator (VDDint) to decrease */ + * internal voltage regulator (VDDint) to decrease */ #define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after - an edge is detected may clear interrupt */ + * an edge is detected may clear interrupt */ #define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause - DMA system instability */ + * DMA system instability */ #define ANOMALY_05000280 /* SPI Master boot mode does not work well with - Atmel Dataflash devices */ + * Atmel Dataflash devices */ #define ANOMALY_05000281 /* False Hardware Error Exception when ISR context * is not restored */ #define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic @@ -134,6 +110,6 @@ * mode */ #define ANOMALY_05000321 /* EMAC RMII mode: TX frames in half duplex fail with * status No Carrier */ -#endif /* CONFIG_BF_REV_0_2 */ +#endif /* CONFIG_BF_REV_0_2 */ #endif /* _MACH_ANOMALY_H_ */ diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h index aca1d4ba145c..964a1c0ea637 100644 --- a/include/asm-blackfin/mach-bf548/anomaly.h +++ b/include/asm-blackfin/mach-bf548/anomaly.h @@ -1,74 +1,51 @@ - /* - * File: include/asm-blackfin/mach-bf548/anomaly.h - * Based on: - * Author: + * File: include/asm-blackfin/mach-bf548/anomaly.h + * Bugs: Enter bugs at http://blackfin.uclinux.org/ * - * Created: - * Description: - * - * Rev: - * - * 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, 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, - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Copyright (C) 2004-2007 Analog Devices Inc. + * Licensed under the GPL-2 or later. */ #ifndef _MACH_ANOMALY_H_ #define _MACH_ANOMALY_H_ + #define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in - slot1 and store of a P register in slot 2 is not - supported */ + * slot1 and store of a P register in slot 2 is not + * supported */ #define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive - Channel DMA stops */ + * Channel DMA stops */ #define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR - registers. */ + * registers. */ #define ANOMALY_05000245 /* Spurious Hardware Error from an Access in the - Shadow of a Conditional Branch */ + * Shadow of a Conditional Branch */ #define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event - interrupt not functional */ + * interrupt not functional */ #define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on - SPORT external receive and transmit clocks. */ + * SPORT external receive and transmit clocks. */ #define ANOMALY_05000272 /* Certain data cache write through modes fail for - VDDint <=0.9V */ + * VDDint <=0.9V */ #define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is - not restored */ + * not restored */ #define ANOMALY_05000310 /* False Hardware Errors Caused by Fetches at the - Boundary of Reserved Memory */ + * Boundary of Reserved Memory */ #define ANOMALY_05000312 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and - LC Registers Are Interrupted */ + * LC Registers Are Interrupted */ #define ANOMALY_05000324 /* TWI Slave Boot Mode Is Not Functional */ #define ANOMALY_05000325 /* External FIFO Boot Mode Is Not Functional */ #define ANOMALY_05000327 /* Data Lost When Core and DMA Accesses Are Made to - the USB FIFO Simultaneously */ + * the USB FIFO Simultaneously */ #define ANOMALY_05000328 /* Incorrect Access of OTP_STATUS During otp_write() - function */ + * function */ #define ANOMALY_05000329 /* Synchronous Burst Flash Boot Mode Is Not Functional - */ + * */ #define ANOMALY_05000330 /* Host DMA Boot Mode Is Not Functional */ #define ANOMALY_05000334 /* Inadequate Timing Margins on DDR DQS to DQ and DQM - Skew */ + * Skew */ #define ANOMALY_05000335 /* Inadequate Rotary Debounce Logic Duration */ #define ANOMALY_05000336 /* Phantom Interrupt Occurs After First Configuration - of Host DMA Port */ + * of Host DMA Port */ #define ANOMALY_05000337 /* Disallowed Configuration Prevents Subsequent - Allowed Configuration on Host DMA Port */ + * Allowed Configuration on Host DMA Port */ #define ANOMALY_05000338 /* Slave-Mode SPI0 MISO Failure With CPHA = 0 */ #endif /* _MACH_ANOMALY_H_ */ diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h index f5b32d66517d..5a7986a83bee 100644 --- a/include/asm-blackfin/mach-bf561/anomaly.h +++ b/include/asm-blackfin/mach-bf561/anomaly.h @@ -1,36 +1,13 @@ - /* - * File: include/asm-blackfin/mach-bf561/anomaly.h - * Based on: - * Author: + * File: include/asm-blackfin/mach-bf561/anomaly.h + * Bugs: Enter bugs at http://blackfin.uclinux.org/ * - * Created: - * Description: - * - * Rev: - * - * 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, 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, - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Copyright (C) 2004-2007 Analog Devices Inc. + * Licensed under the GPL-2 or later. */ /* This file shoule be up to date with: - * - Revision L, 10Aug2006; ADSP-BF561 Silicon Anomaly List + * - Revision L, Aug 10, 2006; ADSP-BF561 Silicon Anomaly List */ #ifndef _MACH_ANOMALY_H_ @@ -42,142 +19,142 @@ #endif /* Issues that are common to 0.5 and 0.3 silicon */ -#if (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3)) +#if (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3)) #define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in - slot1 and store of a P register in slot 2 is not - supported */ + * slot1 and store of a P register in slot 2 is not + * supported */ #define ANOMALY_05000099 /* UART Line Status Register (UART_LSR) bits are not - updated at the same time. */ + * updated at the same time. */ #define ANOMALY_05000120 /* Testset instructions restricted to 32-bit aligned - memory locations */ + * memory locations */ #define ANOMALY_05000122 /* Rx.H cannot be used to access 16-bit System MMR - registers */ + * registers */ #define ANOMALY_05000127 /* Signbits instruction not functional under certain - conditions */ + * conditions */ #define ANOMALY_05000149 /* IMDMA S1/D1 channel may stall */ #define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out - upper bits */ + * upper bits */ #define ANOMALY_05000167 /* Turning Serial Ports on With External Frame Syncs */ #define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame - syncs */ + * syncs */ #define ANOMALY_05000182 /* IMDMA does not operate to full speed for 600MHz - and higher devices */ + * and higher devices */ #define ANOMALY_05000187 /* IMDMA Corrupted Data after a Halt */ #define ANOMALY_05000190 /* PPI not functional at core voltage < 1Volt */ #define ANOMALY_05000208 /* VSTAT status bit in PLL_STAT register is not - functional */ + * functional */ #define ANOMALY_05000245 /* Spurious Hardware Error from an access in the - shadow of a conditional branch */ + * shadow of a conditional branch */ #define ANOMALY_05000257 /* Interrupt/Exception during short hardware loop - may cause bad instruction fetches */ + * may cause bad instruction fetches */ #define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on - external SPORT TX and RX clocks */ + * external SPORT TX and RX clocks */ #define ANOMALY_05000267 /* IMDMA may corrupt data under certain conditions */ #define ANOMALY_05000269 /* High I/O activity causes output voltage of internal - voltage regulator (VDDint) to increase */ + * voltage regulator (VDDint) to increase */ #define ANOMALY_05000270 /* High I/O activity causes output voltage of internal - voltage regulator (VDDint) to decrease */ + * voltage regulator (VDDint) to decrease */ #define ANOMALY_05000272 /* Certain data cache write through modes fail for - VDDint <=0.9V */ + * VDDint <=0.9V */ #define ANOMALY_05000274 /* Data cache write back to external synchronous memory - may be lost */ + * may be lost */ #define ANOMALY_05000275 /* PPI Timing and sampling informaton updates */ #define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC - registers are interrupted */ + * registers are interrupted */ #endif /* (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3)) */ -#if (defined(CONFIG_BF_REV_0_5)) +#if (defined(CONFIG_BF_REV_0_5)) #define ANOMALY_05000254 /* Incorrect Timer Pulse Width in Single-Shot PWM_OUT - mode with external clock */ + * mode with external clock */ #define ANOMALY_05000266 /* IMDMA destination IRQ status must be read prior to - using IMDMA */ + * using IMDMA */ #endif -#if (defined(CONFIG_BF_REV_0_3)) +#if (defined(CONFIG_BF_REV_0_3)) #define ANOMALY_05000156 /* Timers in PWM-Out Mode with PPI GP Receive (Input) - Mode with 0 Frame Syncs */ + * Mode with 0 Frame Syncs */ #define ANOMALY_05000168 /* SDRAM auto-refresh and subsequent Power Ups */ #define ANOMALY_05000169 /* DATA CPLB page miss can result in lost write-through - cache data writes */ + * cache data writes */ #define ANOMALY_05000171 /* Boot-ROM code modifies SICA_IWRx wakeup registers */ #define ANOMALY_05000174 /* Cache Fill Buffer Data lost */ #define ANOMALY_05000175 /* Overlapping Sequencer and Memory Stalls */ #define ANOMALY_05000176 /* Multiplication of (-1) by (-1) followed by an - accumulator saturation */ + * accumulator saturation */ #define ANOMALY_05000179 /* PPI_COUNT cannot be programmed to 0 in General - Purpose TX or RX modes */ + * Purpose TX or RX modes */ #define ANOMALY_05000181 /* Disabling the PPI resets the PPI configuration - registers */ + * registers */ #define ANOMALY_05000184 /* Timer Pin limitations for PPI TX Modes with - External Frame Syncs */ + * External Frame Syncs */ #define ANOMALY_05000185 /* PPI TX Mode with 2 External Frame Syncs */ #define ANOMALY_05000186 /* PPI packing with Data Length greater than 8 bits - (not a meaningful mode) */ + * (not a meaningful mode) */ #define ANOMALY_05000188 /* IMDMA Restrictions on Descriptor and Buffer - Placement in Memory */ + * Placement in Memory */ #define ANOMALY_05000189 /* False Protection Exception */ #define ANOMALY_05000193 /* False Flag Pin Interrupts on Edge Sensitive Inputs - when polarity setting is changed */ + * when polarity setting is changed */ #define ANOMALY_05000194 /* Restarting SPORT in specific modes may cause data - corruption */ + * corruption */ #define ANOMALY_05000198 /* Failing MMR accesses when stalled by preceding - memory read */ + * memory read */ #define ANOMALY_05000199 /* DMA current address shows wrong value during carry - fix */ + * fix */ #define ANOMALY_05000200 /* SPORT TFS and DT are incorrectly driven during - inactive channels in certain conditions */ + * inactive channels in certain conditions */ #define ANOMALY_05000202 /* Possible infinite stall with specific dual-DAG - situation */ + * situation */ #define ANOMALY_05000204 /* Incorrect data read with write-through cache and - allocate cache lines on reads only mode */ + * allocate cache lines on reads only mode */ #define ANOMALY_05000205 /* Specific sequence that can cause DMA error or DMA - stopping */ + * stopping */ #define ANOMALY_05000207 /* Recovery from "brown-out" condition */ #define ANOMALY_05000209 /* Speed-Path in computational unit affects certain - instructions */ + * instructions */ #define ANOMALY_05000215 /* UART TX Interrupt masked erroneously */ #define ANOMALY_05000219 /* NMI event at boot time results in unpredictable - state */ + * state */ #define ANOMALY_05000220 /* Data Corruption with Cached External Memory and - Non-Cached On-Chip L2 Memory */ + * Non-Cached On-Chip L2 Memory */ #define ANOMALY_05000225 /* Incorrect pulse-width of UART start-bit */ #define ANOMALY_05000227 /* Scratchpad memory bank reads may return incorrect - data */ + * data */ #define ANOMALY_05000230 /* UART Receiver is less robust against Baudrate - Differences in certain Conditions */ + * Differences in certain Conditions */ #define ANOMALY_05000231 /* UART STB bit incorrectly affects receiver setting */ #define ANOMALY_05000232 /* SPORT data transmit lines are incorrectly driven in - multichannel mode */ + * multichannel mode */ #define ANOMALY_05000242 /* DF bit in PLL_CTL register does not respond to - hardware reset */ + * hardware reset */ #define ANOMALY_05000244 /* If i-cache is on, CSYNC/SSYNC/IDLE around Change of - Control causes failures */ + * Control causes failures */ #define ANOMALY_05000248 /* TESTSET operation forces stall on the other core */ #define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel - (TDM) mode in certain conditions */ + * (TDM) mode in certain conditions */ #define ANOMALY_05000251 /* Exception not generated for MMR accesses in - reserved region */ + * reserved region */ #define ANOMALY_05000253 /* Maximum external clock speed for Timers */ #define ANOMALY_05000258 /* Instruction Cache is corrupted when bits 9 and 12 - of the ICPLB Data registers differ */ + * of the ICPLB Data registers differ */ #define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */ #define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */ #define ANOMALY_05000262 /* Stores to data cache may be lost */ #define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB - exception */ + * exception */ #define ANOMALY_05000264 /* CSYNC/SSYNC/IDLE causes infinite stall in second - to last instruction in hardware loop */ + * to last instruction in hardware loop */ #define ANOMALY_05000276 /* Timing requirements change for External Frame - Sync PPI Modes with non-zero PPI_DELAY */ + * Sync PPI Modes with non-zero PPI_DELAY */ #define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause - DMA system instability */ + * DMA system instability */ #define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is - not restored */ + * not restored */ #define ANOMALY_05000283 /* An MMR write is stalled indefinitely when killed - in a particular stage */ + * in a particular stage */ #define ANOMALY_05000287 /* A read will receive incorrect data under certain - conditions */ + * conditions */ #define ANOMALY_05000288 /* SPORTs may receive bad data if FIFOs fill up */ #endif From 1aafd9091226a02b481298315f959f777294684e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 25 Jul 2007 11:19:14 +0800 Subject: [PATCH 0003/2804] Blackfin arch: revise anomaly handling by basing things on the compiler not the kconfig defines revise anomaly handling by basing things on the compiler not the kconfig defines, so the header is stable and usable outside of the kernel. This also allows us to move some code from preprocessing to compiling (gcc culls dead code) which should help with code quality (readability, catch minor bugs, etc...). Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_gpio.c | 10 +- arch/blackfin/kernel/cplbinit.c | 4 +- arch/blackfin/kernel/setup.c | 20 +- arch/blackfin/lib/memcmp.S | 2 +- arch/blackfin/lib/memcpy.S | 2 +- arch/blackfin/lib/memmove.S | 4 +- arch/blackfin/mach-bf533/head.S | 10 +- arch/blackfin/mach-bf537/head.S | 18 +- arch/blackfin/mach-bf548/head.S | 2 +- arch/blackfin/mach-bf561/head.S | 11 +- arch/blackfin/mach-common/cacheinit.S | 2 +- arch/blackfin/mach-common/cplbmgr.S | 2 +- arch/blackfin/mach-common/entry.S | 10 +- arch/blackfin/mach-common/interrupt.S | 6 +- include/asm-blackfin/blackfin.h | 118 +++-- include/asm-blackfin/mach-bf533/anomaly.h | 445 ++++++++++-------- include/asm-blackfin/mach-bf533/bf533.h | 2 +- include/asm-blackfin/mach-bf537/anomaly.h | 216 +++++---- include/asm-blackfin/mach-bf537/bf537.h | 2 +- include/asm-blackfin/mach-bf548/anomaly.h | 94 ++-- include/asm-blackfin/mach-bf561/anomaly.h | 378 +++++++++------ include/asm-blackfin/mach-bf561/bf561.h | 2 +- .../mach-common/cdef_LPBlackfin.h | 4 +- .../asm-blackfin/mach-common/def_LPBlackfin.h | 132 +++--- include/asm-blackfin/system.h | 93 ++-- 25 files changed, 879 insertions(+), 710 deletions(-) diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 5d488ef965ce..b818a8da1215 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -330,7 +330,7 @@ EXPORT_SYMBOL(set_gpio_ ## name); SET_GPIO_SC(maska) SET_GPIO_SC(maskb) -#if defined(ANOMALY_05000311) +#if ANOMALY_05000311 void set_gpio_data(unsigned short gpio, unsigned short arg) { unsigned long flags; @@ -349,7 +349,7 @@ SET_GPIO_SC(data) #endif -#if defined(ANOMALY_05000311) +#if ANOMALY_05000311 void set_gpio_toggle(unsigned short gpio) { unsigned long flags; @@ -387,7 +387,7 @@ SET_GPIO_P(maska) SET_GPIO_P(maskb) -#if defined(ANOMALY_05000311) +#if ANOMALY_05000311 void set_gpiop_data(unsigned short gpio, unsigned short arg) { unsigned long flags; @@ -421,7 +421,7 @@ GET_GPIO(maska) GET_GPIO(maskb) -#if defined(ANOMALY_05000311) +#if ANOMALY_05000311 unsigned short get_gpio_data(unsigned short gpio) { unsigned long flags; @@ -455,7 +455,7 @@ GET_GPIO_P(both) GET_GPIO_P(maska) GET_GPIO_P(maskb) -#if defined(ANOMALY_05000311) +#if ANOMALY_05000311 unsigned short get_gpiop_data(unsigned short gpio) { unsigned long flags; diff --git a/arch/blackfin/kernel/cplbinit.c b/arch/blackfin/kernel/cplbinit.c index bbdb403fcb55..3b1c87c9fd51 100644 --- a/arch/blackfin/kernel/cplbinit.c +++ b/arch/blackfin/kernel/cplbinit.c @@ -230,8 +230,8 @@ static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_en cplb_data[i].psize, cplb_data[i].i_conf); } else { -#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) - if (i == SDRAM_KERN) { +#if defined(CONFIG_BLKFIN_CACHE) + if (ANOMALY_05000263 && i == SDRAM_KERN) { fill_cplbtab(t, cplb_data[i].start, cplb_data[i].end, diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 88f221b89b33..02c15272f8ef 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -179,14 +179,16 @@ void __init setup_arch(char **cmdline_p) cclk = get_cclk(); sclk = get_sclk(); -#if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273) - if (cclk == sclk) +#if !defined(CONFIG_BFIN_KERNEL_CLOCK) + if (ANOMALY_05000273 && cclk == sclk) panic("ANOMALY 05000273, SCLK can not be same as CCLK"); #endif -#if defined(ANOMALY_05000266) - bfin_read_IMDMA_D0_IRQ_STATUS(); - bfin_read_IMDMA_D1_IRQ_STATUS(); +#ifdef BF561_FAMILY + if (ANOMALY_05000266) { + bfin_read_IMDMA_D0_IRQ_STATUS(); + bfin_read_IMDMA_D1_IRQ_STATUS(); + } #endif #ifdef DEBUG_SERIAL_EARLY_INIT @@ -260,7 +262,7 @@ void __init setup_arch(char **cmdline_p) && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1) mtd_size = PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2])); -# if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) +# if (defined(CONFIG_BLKFIN_CACHE) && ANOMALY_05000263) /* Due to a Hardware Anomaly we need to limit the size of usable * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on * 05000263 - Hardware loop corrupted when taking an ICPLB exception @@ -289,7 +291,7 @@ void __init setup_arch(char **cmdline_p) _ebss = memory_mtd_start; /* define _ebss for compatible */ #endif /* CONFIG_MTD_UCLINUX */ -#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) +#if (defined(CONFIG_BLKFIN_CACHE) && ANOMALY_05000263) /* Due to a Hardware Anomaly we need to limit the size of usable * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on * 05000263 - Hardware loop corrupted when taking an ICPLB exception @@ -337,10 +339,8 @@ void __init setup_arch(char **cmdline_p) printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n", cclk / 1000000, sclk / 1000000); -#if defined(ANOMALY_05000273) - if ((cclk >> 1) <= sclk) + if (ANOMALY_05000273 && (cclk >> 1) <= sclk) printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n"); -#endif printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20); printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20); diff --git a/arch/blackfin/lib/memcmp.S b/arch/blackfin/lib/memcmp.S index b88c5d2d1ebe..219fa2877c62 100644 --- a/arch/blackfin/lib/memcmp.S +++ b/arch/blackfin/lib/memcmp.S @@ -61,7 +61,7 @@ ENTRY(_memcmp) LSETUP (.Lquad_loop_s, .Lquad_loop_e) LC0=P1; .Lquad_loop_s: -#ifdef ANOMALY_05000202 +#if ANOMALY_05000202 R0 = [P0++]; R1 = [I0++]; #else diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S index 14a5585bbd02..2e6336492b4b 100644 --- a/arch/blackfin/lib/memcpy.S +++ b/arch/blackfin/lib/memcpy.S @@ -98,7 +98,7 @@ ENTRY(_memcpy) R0 = R1; I1 = P1; R3 = [I1++]; -#ifdef ANOMALY_05000202 +#if ANOMALY_05000202 .Lword_loops: [P0++] = R3; .Lword_loope: diff --git a/arch/blackfin/lib/memmove.S b/arch/blackfin/lib/memmove.S index 6ee6e206e77c..33f8653145b7 100644 --- a/arch/blackfin/lib/memmove.S +++ b/arch/blackfin/lib/memmove.S @@ -70,7 +70,7 @@ ENTRY(_memmove) R1 = [I0++]; LSETUP (.Lquad_loops, .Lquad_loope) LC0=P1; -#ifdef ANOMALY_05000202 +#if ANOMALY_05000202 .Lquad_loops: [P0++] = R1; .Lquad_loope: @@ -102,7 +102,7 @@ ENTRY(_memmove) R1 = B[P3--] (Z); CC = P2 == 0; IF CC JUMP .Lno_loop; -#ifdef ANOMALY_05000245 +#if ANOMALY_05000245 NOP; NOP; #endif diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S index 7dd0e9c3a936..5aeffd06fe71 100644 --- a/arch/blackfin/mach-bf533/head.S +++ b/arch/blackfin/mach-bf533/head.S @@ -151,13 +151,13 @@ ENTRY(__start) R0 = R0 & R1; /* Anomaly 05000125 */ -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 CLI R2; SSYNC; #endif [p0] = R0; SSYNC; -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 STI R2; #endif @@ -169,13 +169,13 @@ ENTRY(__start) R0 = R0 & R1; /* Anomaly 05000125 */ -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 CLI R2; SSYNC; #endif [p0] = R0; SSYNC; -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 STI R2; #endif @@ -264,7 +264,7 @@ ENTRY(__start) p0.l = .LWAIT_HERE; p0.h = .LWAIT_HERE; reti = p0; -#if defined(ANOMALY_05000281) +#if ANOMALY_05000281 nop; nop; nop; #endif rti; diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S index 429c8a1019da..d9b411adf6a7 100644 --- a/arch/blackfin/mach-bf537/head.S +++ b/arch/blackfin/mach-bf537/head.S @@ -107,13 +107,13 @@ ENTRY(__start) R0 = R0 & R1; /* Anomaly 05000125 */ -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 CLI R2; SSYNC; #endif [p0] = R0; SSYNC; -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 STI R2; #endif @@ -125,13 +125,13 @@ ENTRY(__start) R0 = R0 & R1; /* Anomaly 05000125 */ -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 CLI R2; SSYNC; #endif [p0] = R0; SSYNC; -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 STI R2; #endif @@ -141,12 +141,12 @@ ENTRY(__start) */ p0.h = hi(BFIN_PORT_MUX); p0.l = lo(BFIN_PORT_MUX); -#ifdef ANOMALY_05000212 +#if ANOMALY_05000212 R0.L = W[P0]; /* Read */ SSYNC; #endif R0 = (PGDE_UART | PFTE_UART)(Z); -#ifdef ANOMALY_05000212 +#if ANOMALY_05000212 W[P0] = R0.L; /* Write */ SSYNC; #endif @@ -155,12 +155,12 @@ ENTRY(__start) p0.h = hi(PORTF_FER); p0.l = lo(PORTF_FER); -#ifdef ANOMALY_05000212 +#if ANOMALY_05000212 R0.L = W[P0]; /* Read */ SSYNC; #endif R0 = 0x000F(Z); -#ifdef ANOMALY_05000212 +#if ANOMALY_05000212 W[P0] = R0.L; /* Write */ SSYNC; #endif @@ -274,7 +274,7 @@ ENTRY(__start) p0.l = .LWAIT_HERE; p0.h = .LWAIT_HERE; reti = p0; -#if defined(ANOMALY_05000281) +#if ANOMALY_05000281 nop; nop; nop; #endif rti; diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S index 06751ae8b857..e5e56df3bf46 100644 --- a/arch/blackfin/mach-bf548/head.S +++ b/arch/blackfin/mach-bf548/head.S @@ -172,7 +172,7 @@ ENTRY(__stext) p0.l = .LWAIT_HERE; p0.h = .LWAIT_HERE; reti = p0; -#if defined (ANOMALY_05000281) +#if ANOMALY_05000281 nop; nop; nop; diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S index 38650a628980..b1d0e54a97a9 100644 --- a/arch/blackfin/mach-bf561/head.S +++ b/arch/blackfin/mach-bf561/head.S @@ -106,14 +106,13 @@ ENTRY(__start) R0 = ~ENICPLB; R0 = R0 & R1; - /* Anomaly 05000125 */ -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 CLI R2; SSYNC; #endif [p0] = R0; SSYNC; -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 STI R2; #endif @@ -125,13 +124,13 @@ ENTRY(__start) R0 = R0 & R1; /* Anomaly 05000125 */ -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 CLI R2; SSYNC; #endif [p0] = R0; SSYNC; -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 STI R2; #endif @@ -220,7 +219,7 @@ ENTRY(__start) p0.l = .LWAIT_HERE; p0.h = .LWAIT_HERE; reti = p0; -#if defined(ANOMALY_05000281) +#if ANOMALY_05000281 nop; nop; nop; #endif rti; diff --git a/arch/blackfin/mach-common/cacheinit.S b/arch/blackfin/mach-common/cacheinit.S index 5be6b975ae4a..05c0c77510b2 100644 --- a/arch/blackfin/mach-common/cacheinit.S +++ b/arch/blackfin/mach-common/cacheinit.S @@ -38,7 +38,7 @@ .text -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 #if defined(CONFIG_BLKFIN_CACHE) ENTRY(_bfin_write_IMEM_CONTROL) diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S index e4b47e09cf13..6c256baf087d 100644 --- a/arch/blackfin/mach-common/cplbmgr.S +++ b/arch/blackfin/mach-common/cplbmgr.S @@ -405,7 +405,7 @@ ENTRY(_cplb_mgr) P3.L = _page_size_table; /* retrieve end address */ P3.H = _page_size_table; /* retrieve end address */ R3 = 0x1002; /* 16th - position, 2 bits -length */ -#ifdef ANOMALY_05000209 +#if ANOMALY_05000209 nop; /* Anomaly 05000209 */ #endif R7 = EXTRACT(R1,R3.l); diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 960458808344..207e69786b40 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -69,7 +69,7 @@ * patch up CPLB misses on the kernel stack. */ ENTRY(_ex_dcplb) -#if defined(ANOMALY_05000261) +#if ANOMALY_05000261 /* * Work around an anomaly: if we see a new DCPLB fault, return * without doing anything. Then, if we get the same fault again, @@ -137,7 +137,7 @@ ENTRY(_ex_single_step) _return_from_exception: DEBUG_START_HWTRACE(p5, r7) -#ifdef ANOMALY_05000257 +#if ANOMALY_05000257 R7=LC0; LC0=R7; R7=LC1; @@ -634,7 +634,7 @@ ENTRY(_return_from_int) p1.h = _schedule_and_signal_from_int; [p0] = p1; csync; -#if defined(ANOMALY_05000281) +#if ANOMALY_05000281 r0.l = lo(CONFIG_BOOT_LOAD); r0.h = hi(CONFIG_BOOT_LOAD); reti = r0; @@ -648,7 +648,7 @@ ENTRY(_return_from_int) ENDPROC(_return_from_int) ENTRY(_lower_to_irq14) -#if defined(ANOMALY_05000281) +#if ANOMALY_05000281 r0.l = lo(CONFIG_BOOT_LOAD); r0.h = hi(CONFIG_BOOT_LOAD); reti = r0; @@ -1184,7 +1184,7 @@ _exception_stack: .endr _exception_stack_top: -#if defined(ANOMALY_05000261) +#if ANOMALY_05000261 /* Used by the assembly entry point to work around an anomaly. */ _last_cplb_fault_retx: .long 0; diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 203e20709163..14ef800a564d 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -140,7 +140,7 @@ __common_int_entry: fp = 0; #endif -#if defined (ANOMALY_05000283) || defined (ANOMALY_05000315) +#if ANOMALY_05000283 || ANOMALY_05000315 cc = r7 == r7; p5.h = 0xffc0; p5.l = 0x0014; @@ -163,7 +163,7 @@ ENTRY(_evt_ivhw) #ifdef CONFIG_FRAME_POINTER fp = 0; #endif -#ifdef ANOMALY_05000283 +#if ANOMALY_05000283 cc = r7 == r7; p5.h = 0xffc0; p5.l = 0x0014; @@ -207,7 +207,7 @@ ENTRY(_evt_evt2) #ifdef CONFIG_FRAME_POINTER fp = 0; #endif -#ifdef ANOMALY_05000283 +#if ANOMALY_05000283 cc = r7 == r7; p5.h = 0xffc0; p5.l = 0x0014; diff --git a/include/asm-blackfin/blackfin.h b/include/asm-blackfin/blackfin.h index 25b934b7f829..1b2dd5a3fe7a 100644 --- a/include/asm-blackfin/blackfin.h +++ b/include/asm-blackfin/blackfin.h @@ -17,72 +17,66 @@ #ifndef __ASSEMBLY__ /* SSYNC implementation for C file */ -#if defined(ANOMALY_05000312) && defined(ANOMALY_05000244) -static inline void SSYNC (void) +static inline void SSYNC(void) { int _tmp; - __asm__ __volatile__ ("cli %0;\n\t" - "nop;nop;\n\t" - "ssync;\n\t" - "sti %0;\n\t" - :"=d"(_tmp):); + if (ANOMALY_05000312 && ANOMALY_05000244) + __asm__ __volatile__( + "cli %0;" + "nop;" + "nop;" + "ssync;" + "sti %0;" + : "=d" (_tmp) + ); + else if (ANOMALY_05000312 && !ANOMALY_05000244) + __asm__ __volatile__( + "cli %0;" + "ssync;" + "sti %0;" + : "=d" (_tmp) + ); + else if (!ANOMALY_05000312 && ANOMALY_05000244) + __asm__ __volatile__( + "nop;" + "nop;" + "nop;" + "ssync;" + ); + else + __asm__ __volatile__("ssync;"); } -#elif defined(ANOMALY_05000312) && !defined(ANOMALY_05000244) -static inline void SSYNC (void) -{ - int _tmp; - __asm__ __volatile__ ("cli %0;\n\t" - "ssync;\n\t" - "sti %0;\n\t" - :"=d"(_tmp):); -} -#elif !defined(ANOMALY_05000312) && defined(ANOMALY_05000244) -static inline void SSYNC (void) -{ - __asm__ __volatile__ ("nop; nop; nop;\n\t" - "ssync;\n\t" - ::); -} -#elif !defined(ANOMALY_05000312) && !defined(ANOMALY_05000244) -static inline void SSYNC (void) -{ - __asm__ __volatile__ ("ssync;\n\t"); -} -#endif /* CSYNC implementation for C file */ -#if defined(ANOMALY_05000312) && defined(ANOMALY_05000244) -static inline void CSYNC (void) +static inline void CSYNC(void) { int _tmp; - __asm__ __volatile__ ("cli %0;\n\t" - "nop;nop;\n\t" - "csync;\n\t" - "sti %0;\n\t" - :"=d"(_tmp):); + if (ANOMALY_05000312 && ANOMALY_05000244) + __asm__ __volatile__( + "cli %0;" + "nop;" + "nop;" + "csync;" + "sti %0;" + : "=d" (_tmp) + ); + else if (ANOMALY_05000312 && !ANOMALY_05000244) + __asm__ __volatile__( + "cli %0;" + "csync;" + "sti %0;" + : "=d" (_tmp) + ); + else if (!ANOMALY_05000312 && ANOMALY_05000244) + __asm__ __volatile__( + "nop;" + "nop;" + "nop;" + "ssync;" + ); + else + __asm__ __volatile__("csync;"); } -#elif defined(ANOMALY_05000312) && !defined(ANOMALY_05000244) -static inline void CSYNC (void) -{ - int _tmp; - __asm__ __volatile__ ("cli %0;\n\t" - "csync;\n\t" - "sti %0;\n\t" - :"=d"(_tmp):); -} -#elif !defined(ANOMALY_05000312) && defined(ANOMALY_05000244) -static inline void CSYNC (void) -{ - __asm__ __volatile__ ("nop; nop; nop;\n\t" - "ssync;\n\t" - ::); -} -#elif !defined(ANOMALY_05000312) && !defined(ANOMALY_05000244) -static inline void CSYNC (void) -{ - __asm__ __volatile__ ("csync;\n\t"); -} -#endif #else /* __ASSEMBLY__ */ @@ -91,19 +85,19 @@ static inline void CSYNC (void) #define ssync(x) SSYNC(x) #define csync(x) CSYNC(x) -#if defined(ANOMALY_05000312) && defined(ANOMALY_05000244) +#if ANOMALY_05000312 && ANOMALY_05000244 #define SSYNC(scratch) cli scratch; nop; nop; SSYNC; sti scratch; #define CSYNC(scratch) cli scratch; nop; nop; CSYNC; sti scratch; -#elif defined(ANOMALY_05000312) && !defined(ANOMALY_05000244) +#elif ANOMALY_05000312 && !ANOMALY_05000244 #define SSYNC(scratch) cli scratch; nop; nop; SSYNC; sti scratch; #define CSYNC(scratch) cli scratch; nop; nop; CSYNC; sti scratch; -#elif !defined(ANOMALY_05000312) && defined(ANOMALY_05000244) +#elif !ANOMALY_05000312 && ANOMALY_05000244 #define SSYNC(scratch) nop; nop; nop; SSYNC; #define CSYNC(scratch) nop; nop; nop; CSYNC; -#elif !defined(ANOMALY_05000312) && !defined(ANOMALY_05000244) +#elif !ANOMALY_05000312 && !ANOMALY_05000244 #define SSYNC(scratch) SSYNC; #define CSYNC(scratch) CSYNC; diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h index 2a63ffc250a1..caea0b0f8326 100644 --- a/include/asm-blackfin/mach-bf533/anomaly.h +++ b/include/asm-blackfin/mach-bf533/anomaly.h @@ -7,219 +7,252 @@ */ /* This file shoule be up to date with: - * - Revision U, May 17, 2006; ADSP-BF533 Blackfin Processor Anomaly List - * - Revision Y, May 17, 2006; ADSP-BF532 Blackfin Processor Anomaly List - * - Revision T, May 17, 2006; ADSP-BF531 Blackfin Processor Anomaly List + * - Revision X, March 23, 2007; ADSP-BF533 Blackfin Processor Anomaly List + * - Revision AB, March 23, 2007; ADSP-BF532 Blackfin Processor Anomaly List + * - Revision W, March 23, 2007; ADSP-BF531 Blackfin Processor Anomaly List */ #ifndef _MACH_ANOMALY_H_ #define _MACH_ANOMALY_H_ /* We do not support 0.1 or 0.2 silicon - sorry */ -#if (defined(CONFIG_BF_REV_0_1) || defined(CONFIG_BF_REV_0_2)) -#error Kernel will not work on BF533 Version 0.1 or 0.2 +#if __SILICON_REVISION__ < 3 +# error Kernel will not work on BF533 silicon version 0.0, 0.1, or 0.2 #endif -/* Issues that are common to 0.5, 0.4, and 0.3 silicon */ -#if (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_4) \ - || defined(CONFIG_BF_REV_0_3)) -#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in - * slot1 and store of a P register in slot 2 is not - * supported */ -#define ANOMALY_05000105 /* Watchpoint Status Register (WPSTAT) bits are set on - * every corresponding match */ -#define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive - * Channel DMA stops */ -#define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR - * registers. */ -#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out - * upper bits*/ -#define ANOMALY_05000167 /* Turning Serial Ports on With External Frame Syncs */ -#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame - * syncs */ -#define ANOMALY_05000208 /* VSTAT status bit in PLL_STAT register is not - * functional */ -#define ANOMALY_05000219 /* NMI event at boot time results in unpredictable - * state */ -#define ANOMALY_05000229 /* SPI Slave Boot Mode modifies registers */ -#define ANOMALY_05000272 /* Certain data cache write through modes fail for - * VDDint <=0.9V */ -#define ANOMALY_05000273 /* Writes to Synchronous SDRAM memory may be lost */ -#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after - * an edge is detected may clear interrupt */ -#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause - * DMA system instability */ -#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is - * not restored */ -#define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic - * control */ -#define ANOMALY_05000283 /* A system MMR write is stalled indefinitely when - * killed in a particular stage*/ -#define ANOMALY_05000311 /* Erroneous flag pin operations under specific - * sequences */ -#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC - * registers are interrupted */ -#define ANOMALY_05000313 /* PPI Is Level-Sensitive on First Transfer */ -#define ANOMALY_05000315 /* Killed System MMR Write Completes Erroneously On - * Next System MMR Access */ -#define ANOMALY_05000319 /* Internal Voltage Regulator Values of 1.05V, 1.10V - * and 1.15V Not Allowed for LQFP Packages */ -#endif /* Issues that are common to 0.5, 0.4, and 0.3 silicon */ - -/* These issues only occur on 0.3 or 0.4 BF533 */ -#if (defined(CONFIG_BF_REV_0_4) || defined(CONFIG_BF_REV_0_3)) -#define ANOMALY_05000099 /* UART Line Status Register (UART_LSR) bits are not - * updated at the same time. */ -#define ANOMALY_05000158 /* Boot fails when data cache enabled: Data from a Data - * Cache Fill can be corrupted after or during - * Instruction DMA if certain core stalls exist */ -#define ANOMALY_05000179 /* PPI_COUNT cannot be programmed to 0 in General - * Purpose TX or RX modes */ -#define ANOMALY_05000198 /* Failing SYSTEM MMR accesses when stalled by - * preceding memory read */ -#define ANOMALY_05000200 /* SPORT TFS and DT are incorrectly driven during - * inactive channels in certain conditions */ -#define ANOMALY_05000202 /* Possible infinite stall with specific dual dag - * situation */ -#define ANOMALY_05000215 /* UART TX Interrupt masked erroneously */ -#define ANOMALY_05000225 /* Incorrect pulse-width of UART start-bit */ -#define ANOMALY_05000227 /* Scratchpad memory bank reads may return incorrect - * data*/ -#define ANOMALY_05000230 /* UART Receiver is less robust against Baudrate - * Differences in certain Conditions */ -#define ANOMALY_05000231 /* UART STB bit incorrectly affects receiver setting */ -#define ANOMALY_05000242 /* DF bit in PLL_CTL register does not respond to - * hardware reset */ -#define ANOMALY_05000244 /* With instruction cache enabled, a CSYNC or SSYNC or - * IDLE around a Change of Control causes - * unpredictable results */ -#define ANOMALY_05000245 /* Spurious Hardware Error from an access in the - * shadow of a conditional branch */ -#define ANOMALY_05000246 /* Data CPLB's should prevent spurious hardware - * errors */ -#define ANOMALY_05000253 /* Maximum external clock speed for Timers */ -#define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event - * interrupt not functional */ -#define ANOMALY_05000257 /* An interrupt or exception during short Hardware - * loops may cause the instruction fetch unit to - * malfunction */ -#define ANOMALY_05000258 /* Instruction Cache is corrupted when bit 9 and 12 of - * the ICPLB Data registers differ */ -#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */ -#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */ -#define ANOMALY_05000262 /* Stores to data cache may be lost */ -#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB exception */ -#define ANOMALY_05000264 /* A Sync instruction (CSYNC, SSYNC) or an IDLE - * instruction will cause an infinite stall in the - * second to last instruction in a hardware loop */ -#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on - * SPORT external receive and transmit clocks. */ -#define ANOMALY_05000269 /* High I/O activity causes the output voltage of the - * internal voltage regulator (VDDint) to increase. */ -#define ANOMALY_05000270 /* High I/O activity causes the output voltage of the - * internal voltage regulator (VDDint) to decrease */ -#endif /* issues only occur on 0.3 or 0.4 BF533 */ - -/* These issues are only on 0.4 silicon */ -#if (defined(CONFIG_BF_REV_0_4)) -#define ANOMALY_05000234 /* Incorrect Revision Number in DSPID Register */ -#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel - * (TDM) */ -#endif /* issues are only on 0.4 silicon */ - -/* These issues are only on 0.3 silicon */ -#if defined(CONFIG_BF_REV_0_3) -#define ANOMALY_05000183 /* Timer Pin limitations for PPI TX Modes with - * External Frame Syncs */ -#define ANOMALY_05000189 /* False Protection Exceptions caused by Speculative - * Instruction or Data Fetches, or by Fetches at the - * boundary of reserved memory space */ -#define ANOMALY_05000193 /* False Flag Pin Interrupts on Edge Sensitive Inputs - * when polarity setting is changed */ -#define ANOMALY_05000194 /* Sport Restarting in specific modes may cause data - * corruption */ -#define ANOMALY_05000199 /* DMA current address shows wrong value during carry - * fix */ -#define ANOMALY_05000201 /* Receive frame sync not ignored during active - * frames in sport MCM */ -#define ANOMALY_05000203 /* Specific sequence that can cause DMA error or DMA - * stopping */ -#if defined(CONFIG_BF533) -#define ANOMALY_05000204 /* Incorrect data read with write-through cache and - * allocate cache lines on reads only mode */ -#endif /* CONFIG_BF533 */ -#define ANOMALY_05000207 /* Recovery from "brown-out" condition */ -#define ANOMALY_05000209 /* Speed-Path in computational unit affects certain - * instructions */ -#define ANOMALY_05000233 /* PPI_FS3 is not driven in 2 or 3 internal Frame - * Sync Transmit Mode */ -#define ANOMALY_05000271 /* Spontaneous reset of Internal Voltage Regulator */ -#endif /* only on 0.3 silicon */ - -#if defined(CONFIG_BF_REV_0_2) -#define ANOMALY_05000067 /* Watchpoints (Hardware Breakpoints) are not - * supported */ -#define ANOMALY_05000109 /* Reserved bits in SYSCFG register not set at - * power on */ -#define ANOMALY_05000116 /* Trace Buffers may record discontinuities into - * emulation mode and/or exception, NMI, reset - * handlers */ -#define ANOMALY_05000123 /* DTEST_COMMAND initiated memory access may be - * incorrect if data cache or DMA is active */ -#define ANOMALY_05000124 /* DMA Lock-up at CCLK to SCLK ratios of 4:1, 2:1, - * or 1:1 */ -#define ANOMALY_05000125 /* Erroneous exception when enabling cache */ -#define ANOMALY_05000126 /* SPI clock polarity and phase bits incorrect - * during booting */ -#define ANOMALY_05000137 /* DMEM_CONTROL is not set on Reset */ -#define ANOMALY_05000138 /* SPI boot will not complete if there is a zero fill - * block in the loader file */ -#define ANOMALY_05000140 /* Allowing the SPORT RX FIFO to fill will cause an - * overflow */ -#define ANOMALY_05000141 /* An Infinite Stall occurs with a particular sequence - * of consecutive dual dag events */ -#define ANOMALY_05000142 /* Interrupts may be lost when a programmable input - * flag is configured to be edge sensitive */ -#define ANOMALY_05000143 /* A read from external memory may return a wrong - * value with data cache enabled */ -#define ANOMALY_05000144 /* DMA and TESTSET conflict when both are accessing - * external memory */ -#define ANOMALY_05000145 /* In PWM_OUT mode, you must enable the PPI block to - * generate a waveform from PPI_CLK */ -#define ANOMALY_05000146 /* MDMA may lose the first few words of a descriptor - * chain */ -#define ANOMALY_05000147 /* The source MDMA descriptor may stop with a DMA - * Error */ -#define ANOMALY_05000148 /* When booting from a 16-bit asynchronous memory - * device, the upper 8-bits of each word must be - * 0x00 */ -#define ANOMALY_05000153 /* Frame Delay in SPORT Multichannel Mode */ -#define ANOMALY_05000154 /* SPORT TFS signal is active in Multi-channel mode - * outside of valid channels */ -#define ANOMALY_05000155 /* Timer1 can not be used for PWMOUT mode when a - * certain PPI mode is in use */ -#define ANOMALY_05000157 /* A killed 32-bit System MMR write will lead to - * the next system MMR access thinking it should be - * 32-bit. */ -#define ANOMALY_05000163 /* SPORT transmit data is not gated by external frame - * sync in certain conditions */ -#define ANOMALY_05000168 /* SDRAM auto-refresh and subsequent Power Ups */ -#define ANOMALY_05000169 /* DATA CPLB page miss can result in lost - * write-through cache data writes */ -#define ANOMALY_05000173 /* DMA vs Core accesses to external memory */ -#define ANOMALY_05000174 /* Cache Fill Buffer Data lost */ -#define ANOMALY_05000175 /* Overlapping Sequencer and Memory Stalls */ -#define ANOMALY_05000176 /* Multiplication of (-1) by (-1) followed by an - * accumulator saturation */ -#define ANOMALY_05000181 /* Disabling the PPI resets the PPI configuration - * registers */ -#define ANOMALY_05000185 /* PPI TX Mode with 2 External Frame Syncs */ -#define ANOMALY_05000191 /* PPI does not invert the Driving PPICLK edge in - * Transmit Modes */ -#define ANOMALY_05000192 /* In PPI Transmit Modes with External Frame Syncs - * POLC */ -#define ANOMALY_05000206 /* Internal Voltage Regulator may not start up */ - +#if defined(__ADSPBF531__) +# define ANOMALY_BF531 1 +#else +# define ANOMALY_BF531 0 +#endif +#if defined(__ADSPBF532__) +# define ANOMALY_BF532 1 +#else +# define ANOMALY_BF532 0 +#endif +#if defined(__ADSPBF533__) +# define ANOMALY_BF533 1 +#else +# define ANOMALY_BF533 0 #endif -#endif /* _MACH_ANOMALY_H_ */ +/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */ +#define ANOMALY_05000074 (1) +/* UART Line Status Register (UART_LSR) Bits Are Not Updated at the Same Time */ +#define ANOMALY_05000099 (__SILICON_REVISION__ < 5) +/* Watchpoint Status Register (WPSTAT) Bits Are Set on Every Corresponding Match */ +#define ANOMALY_05000105 (1) +/* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */ +#define ANOMALY_05000119 (1) +/* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */ +#define ANOMALY_05000122 (1) +/* Instruction DMA Can Cause Data Cache Fills to Fail (Boot Implications) */ +#define ANOMALY_05000158 (__SILICON_REVISION__ < 5) +/* PPI Data Lengths Between 8 and 16 Do Not Zero Out Upper Bits */ +#define ANOMALY_05000166 (1) +/* Turning Serial Ports on with External Frame Syncs */ +#define ANOMALY_05000167 (1) +/* PPI_COUNT Cannot Be Programmed to 0 in General Purpose TX or RX Modes */ +#define ANOMALY_05000179 (__SILICON_REVISION__ < 5) +/* PPI_DELAY Not Functional in PPI Modes with 0 Frame Syncs */ +#define ANOMALY_05000180 (1) +/* Timer Pin Limitations for PPI TX Modes with External Frame Syncs */ +#define ANOMALY_05000183 (__SILICON_REVISION__ < 4) +/* False Protection Exceptions */ +#define ANOMALY_05000189 (__SILICON_REVISION__ < 4) +/* False I/O Pin Interrupts on Edge-Sensitive Inputs When Polarity Setting Is Changed */ +#define ANOMALY_05000193 (__SILICON_REVISION__ < 4) +/* Restarting SPORT in Specific Modes May Cause Data Corruption */ +#define ANOMALY_05000194 (__SILICON_REVISION__ < 4) +/* Failing MMR Accesses When Stalled by Preceding Memory Read */ +#define ANOMALY_05000198 (__SILICON_REVISION__ < 5) +/* Current DMA Address Shows Wrong Value During Carry Fix */ +#define ANOMALY_05000199 (__SILICON_REVISION__ < 4) +/* SPORT TFS and DT Are Incorrectly Driven During Inactive Channels in Certain Conditions */ +#define ANOMALY_05000200 (__SILICON_REVISION__ < 5) +/* Receive Frame Sync Not Ignored During Active Frames in SPORT Multi-Channel Mode */ +#define ANOMALY_05000201 (__SILICON_REVISION__ < 4) +/* Possible Infinite Stall with Specific Dual-DAG Situation */ +#define ANOMALY_05000202 (__SILICON_REVISION__ < 5) +/* Specific Sequence That Can Cause DMA Error or DMA Stopping */ +#define ANOMALY_05000203 (__SILICON_REVISION__ < 4) +/* Incorrect data read with write-through cache and allocate cache lines on reads only mode */ +#define ANOMALY_05000204 (__SILICON_REVISION__ < 4 && ANOMALY_BF533) +/* Recovery from "Brown-Out" Condition */ +#define ANOMALY_05000207 (__SILICON_REVISION__ < 4) +/* VSTAT Status Bit in PLL_STAT Register Is Not Functional */ +#define ANOMALY_05000208 (1) +/* Speed Path in Computational Unit Affects Certain Instructions */ +#define ANOMALY_05000209 (__SILICON_REVISION__ < 4) +/* UART TX Interrupt Masked Erroneously */ +#define ANOMALY_05000215 (__SILICON_REVISION__ < 5) +/* NMI Event at Boot Time Results in Unpredictable State */ +#define ANOMALY_05000219 (1) +/* Incorrect Pulse-Width of UART Start Bit */ +#define ANOMALY_05000225 (__SILICON_REVISION__ < 5) +/* Scratchpad Memory Bank Reads May Return Incorrect Data */ +#define ANOMALY_05000227 (__SILICON_REVISION__ < 5) +/* SPI Slave Boot Mode Modifies Registers from Reset Value */ +#define ANOMALY_05000229 (1) +/* UART Receiver is Less Robust Against Baudrate Differences in Certain Conditions */ +#define ANOMALY_05000230 (__SILICON_REVISION__ < 5) +/* UART STB Bit Incorrectly Affects Receiver Setting */ +#define ANOMALY_05000231 (__SILICON_REVISION__ < 5) +/* PPI_FS3 Is Not Driven in 2 or 3 Internal Frame Sync Transmit Modes */ +#define ANOMALY_05000233 (__SILICON_REVISION__ < 4) +/* Incorrect Revision Number in DSPID Register */ +#define ANOMALY_05000234 (__SILICON_REVISION__ == 4) +/* DF Bit in PLL_CTL Register Does Not Respond to Hardware Reset */ +#define ANOMALY_05000242 (__SILICON_REVISION__ < 4) +/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */ +#define ANOMALY_05000244 (__SILICON_REVISION__ < 5) +/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */ +#define ANOMALY_05000245 (1) +/* Data CPLBs Should Prevent Spurious Hardware Errors */ +#define ANOMALY_05000246 (__SILICON_REVISION__ < 5) +/* Incorrect Bit Shift of Data Word in Multichannel (TDM) Mode in Certain Conditions */ +#define ANOMALY_05000250 (__SILICON_REVISION__ == 4) +/* Maximum External Clock Speed for Timers */ +#define ANOMALY_05000253 (__SILICON_REVISION__ < 5) +/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT Mode with External Clock */ +#define ANOMALY_05000254 (__SILICON_REVISION__ > 4) +/* Entering Hibernate State with RTC Seconds Interrupt Not Functional */ +#define ANOMALY_05000255 (__SILICON_REVISION__ < 5) +/* Interrupt/Exception During Short Hardware Loop May Cause Bad Instruction Fetches */ +#define ANOMALY_05000257 (__SILICON_REVISION__ < 5) +/* Instruction Cache Is Corrupted When Bits 9 and 12 of the ICPLB Data Registers Differ */ +#define ANOMALY_05000258 (__SILICON_REVISION__ < 5) +/* ICPLB_STATUS MMR Register May Be Corrupted */ +#define ANOMALY_05000260 (__SILICON_REVISION__ < 5) +/* DCPLB_FAULT_ADDR MMR Register May Be Corrupted */ +#define ANOMALY_05000261 (__SILICON_REVISION__ < 5) +/* Stores To Data Cache May Be Lost */ +#define ANOMALY_05000262 (__SILICON_REVISION__ < 5) +/* Hardware Loop Corrupted When Taking an ICPLB Exception */ +#define ANOMALY_05000263 (__SILICON_REVISION__ < 5) +/* CSYNC/SSYNC/IDLE Causes Infinite Stall in Penultimate Instruction in Hardware Loop */ +#define ANOMALY_05000264 (__SILICON_REVISION__ < 5) +/* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */ +#define ANOMALY_05000265 (__SILICON_REVISION__ < 5) +/* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Increase */ +#define ANOMALY_05000269 (__SILICON_REVISION__ < 5) +/* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */ +#define ANOMALY_05000270 (__SILICON_REVISION__ < 5) +/* Spontaneous Reset of Internal Voltage Regulator */ +#define ANOMALY_05000271 (__SILICON_REVISION__ < 4) +/* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */ +#define ANOMALY_05000272 (1) +/* Writes to Synchronous SDRAM Memory May Be Lost */ +#define ANOMALY_05000273 (1) +/* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */ +#define ANOMALY_05000276 (1) +/* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */ +#define ANOMALY_05000277 (1) +/* Disabling Peripherals with DMA Running May Cause DMA System Instability */ +#define ANOMALY_05000278 (1) +/* False Hardware Error Exception When ISR Context Is Not Restored */ +#define ANOMALY_05000281 (1) +/* Memory DMA Corruption with 32-Bit Data and Traffic Control */ +#define ANOMALY_05000282 (1) +/* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */ +#define ANOMALY_05000283 (1) +/* SPORTs May Receive Bad Data If FIFOs Fill Up */ +#define ANOMALY_05000288 (1) +/* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */ +#define ANOMALY_05000301 (1) +/* SSYNCs After Writes To DMA MMR Registers May Not Be Handled Correctly */ +#define ANOMALY_05000302 (__SILICON_REVISION__ < 5) +/* New Feature: Additional Hysteresis on SPORT Input Pins (Not Available On Older Silicon) */ +#define ANOMALY_05000305 (__SILICON_REVISION__ < 5) +/* New Feature: Additional PPI Frame Sync Sampling Options (Not Available On Older Silicon) */ +#define ANOMALY_05000306 (__SILICON_REVISION__ < 5) +/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */ +#define ANOMALY_05000310 (1) +/* Erroneous Flag (GPIO) Pin Operations under Specific Sequences */ +#define ANOMALY_05000311 (1) +/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */ +#define ANOMALY_05000312 (1) +/* PPI Is Level-Sensitive on First Transfer */ +#define ANOMALY_05000313 (1) +/* Killed System MMR Write Completes Erroneously On Next System MMR Access */ +#define ANOMALY_05000315 (1) +/* Internal Voltage Regulator Values of 1.05V, 1.10V and 1.15V Not Allowed for LQFP Packages */ +#define ANOMALY_05000319 (ANOMALY_BF531 || ANOMALY_BF532) + +/* These anomalies have been "phased" out of analog.com anomaly sheets and are + * here to show running on older silicon just isn't feasible. + */ + +/* Watchpoints (Hardware Breakpoints) are not supported */ +#define ANOMALY_05000067 (__SILICON_REVISION__ < 3) +/* Reserved bits in SYSCFG register not set at power on */ +#define ANOMALY_05000109 (__SILICON_REVISION__ < 3) +/* Trace Buffers may record discontinuities into emulation mode and/or exception, NMI, reset handlers */ +#define ANOMALY_05000116 (__SILICON_REVISION__ < 3) +/* DTEST_COMMAND initiated memory access may be incorrect if data cache or DMA is active */ +#define ANOMALY_05000123 (__SILICON_REVISION__ < 3) +/* DMA Lock-up at CCLK to SCLK ratios of 4:1, 2:1, or 1:1 */ +#define ANOMALY_05000124 (__SILICON_REVISION__ < 3) +/* Erroneous exception when enabling cache */ +#define ANOMALY_05000125 (__SILICON_REVISION__ < 3) +/* SPI clock polarity and phase bits incorrect during booting */ +#define ANOMALY_05000126 (__SILICON_REVISION__ < 3) +/* DMEM_CONTROL is not set on Reset */ +#define ANOMALY_05000137 (__SILICON_REVISION__ < 3) +/* SPI boot will not complete if there is a zero fill block in the loader file */ +#define ANOMALY_05000138 (__SILICON_REVISION__ < 3) +/* Allowing the SPORT RX FIFO to fill will cause an overflow */ +#define ANOMALY_05000140 (__SILICON_REVISION__ < 3) +/* An Infinite Stall occurs with a particular sequence of consecutive dual dag events */ +#define ANOMALY_05000141 (__SILICON_REVISION__ < 3) +/* Interrupts may be lost when a programmable input flag is configured to be edge sensitive */ +#define ANOMALY_05000142 (__SILICON_REVISION__ < 3) +/* A read from external memory may return a wrong value with data cache enabled */ +#define ANOMALY_05000143 (__SILICON_REVISION__ < 3) +/* DMA and TESTSET conflict when both are accessing external memory */ +#define ANOMALY_05000144 (__SILICON_REVISION__ < 3) +/* In PWM_OUT mode, you must enable the PPI block to generate a waveform from PPI_CLK */ +#define ANOMALY_05000145 (__SILICON_REVISION__ < 3) +/* MDMA may lose the first few words of a descriptor chain */ +#define ANOMALY_05000146 (__SILICON_REVISION__ < 3) +/* The source MDMA descriptor may stop with a DMA Error */ +#define ANOMALY_05000147 (__SILICON_REVISION__ < 3) +/* When booting from a 16-bit asynchronous memory device, the upper 8-bits of each word must be 0x00 */ +#define ANOMALY_05000148 (__SILICON_REVISION__ < 3) +/* Frame Delay in SPORT Multichannel Mode */ +#define ANOMALY_05000153 (__SILICON_REVISION__ < 3) +/* SPORT TFS signal is active in Multi-channel mode outside of valid channels */ +#define ANOMALY_05000154 (__SILICON_REVISION__ < 3) +/* Timer1 can not be used for PWMOUT mode when a certain PPI mode is in use */ +#define ANOMALY_05000155 (__SILICON_REVISION__ < 3) +/* A killed 32-bit System MMR write will lead to the next system MMR access thinking it should be 32-bit. */ +#define ANOMALY_05000157 (__SILICON_REVISION__ < 3) +/* SPORT transmit data is not gated by external frame sync in certain conditions */ +#define ANOMALY_05000163 (__SILICON_REVISION__ < 3) +/* SDRAM auto-refresh and subsequent Power Ups */ +#define ANOMALY_05000168 (__SILICON_REVISION__ < 3) +/* DATA CPLB page miss can result in lost write-through cache data writes */ +#define ANOMALY_05000169 (__SILICON_REVISION__ < 3) +/* DMA vs Core accesses to external memory */ +#define ANOMALY_05000173 (__SILICON_REVISION__ < 3) +/* Cache Fill Buffer Data lost */ +#define ANOMALY_05000174 (__SILICON_REVISION__ < 3) +/* Overlapping Sequencer and Memory Stalls */ +#define ANOMALY_05000175 (__SILICON_REVISION__ < 3) +/* Multiplication of (-1) by (-1) followed by an accumulator saturation */ +#define ANOMALY_05000176 (__SILICON_REVISION__ < 3) +/* Disabling the PPI resets the PPI configuration registers */ +#define ANOMALY_05000181 (__SILICON_REVISION__ < 3) +/* PPI TX Mode with 2 External Frame Syncs */ +#define ANOMALY_05000185 (__SILICON_REVISION__ < 3) +/* PPI does not invert the Driving PPICLK edge in Transmit Modes */ +#define ANOMALY_05000191 (__SILICON_REVISION__ < 3) +/* In PPI Transmit Modes with External Frame Syncs POLC */ +#define ANOMALY_05000192 (__SILICON_REVISION__ < 3) +/* Internal Voltage Regulator may not start up */ +#define ANOMALY_05000206 (__SILICON_REVISION__ < 3) + +/* Anomalies that don't exist on this proc */ +#define ANOMALY_05000266 (0) + +#endif diff --git a/include/asm-blackfin/mach-bf533/bf533.h b/include/asm-blackfin/mach-bf533/bf533.h index 185fc1284858..41e4e834e2d3 100644 --- a/include/asm-blackfin/mach-bf533/bf533.h +++ b/include/asm-blackfin/mach-bf533/bf533.h @@ -226,7 +226,7 @@ #define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly #endif -#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1) +#if ANOMALY_05000273 && (CONFIG_CCLK_DIV == 1) #error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK #endif diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h index 5c5e33dec5f1..dc736c61980f 100644 --- a/include/asm-blackfin/mach-bf537/anomaly.h +++ b/include/asm-blackfin/mach-bf537/anomaly.h @@ -7,109 +7,137 @@ */ /* This file shoule be up to date with: - * - Revision J, June 1, 2006; ADSP-BF537 Blackfin Processor Anomaly List - * - Revision I, June 1, 2006; ADSP-BF536 Blackfin Processor Anomaly List - * - Revision J, June 1, 2006; ADSP-BF534 Blackfin Processor Anomaly List + * - Revision M, March 13, 2007; ADSP-BF537 Blackfin Processor Anomaly List + * - Revision L, March 13, 2007; ADSP-BF536 Blackfin Processor Anomaly List + * - Revision M, March 13, 2007; ADSP-BF534 Blackfin Processor Anomaly List */ #ifndef _MACH_ANOMALY_H_ #define _MACH_ANOMALY_H_ /* We do not support 0.1 silicon - sorry */ -#if (defined(CONFIG_BF_REV_0_1)) -#error Kernel will not work on BF537/6/4 Version 0.1 +#if __SILICON_REVISION__ < 2 +# error Kernel will not work on BF537 silicon version 0.0 or 0.1 #endif -#if (defined(CONFIG_BF_REV_0_3) || defined(CONFIG_BF_REV_0_2)) -#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in - * slot1 and store of a P register in slot 2 is not - * supported */ -#define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive - * Channel DMA stops */ -#define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR - * registers. */ -#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out - * upper bits*/ -#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame - * syncs */ -#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) -#define ANOMALY_05000247 /* CLKIN Buffer Output Enable Reset Behavior Is - * Changed */ +#if defined(__ADSPBF534__) +# define ANOMALY_BF534 1 +#else +# define ANOMALY_BF534 0 #endif -#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on - * SPORT external receive and transmit clocks. */ -#define ANOMALY_05000272 /* Certain data cache write through modes fail for - * VDDint <=0.9V */ -#define ANOMALY_05000273 /* Writes to Synchronous SDRAM memory may be lost */ -#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after - * an edge is detected may clear interrupt */ -#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is - * not restored */ -#define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic - * control */ -#define ANOMALY_05000283 /* A system MMR write is stalled indefinitely when - * killed in a particular stage*/ -#define ANOMALY_05000310 /* False hardware errors caused by fetches at the - * boundary of reserved memory */ -#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC - * registers are interrupted */ -#define ANOMALY_05000313 /* PPI is level sensitive on first transfer */ -#define ANOMALY_05000322 /* EMAC RMII mode at 10-Base-T speed: RX frames not - * received properly */ +#if defined(__ADSPBF536__) +# define ANOMALY_BF536 1 +#else +# define ANOMALY_BF536 0 +#endif +#if defined(__ADSPBF537__) +# define ANOMALY_BF537 1 +#else +# define ANOMALY_BF537 0 #endif -#if defined(CONFIG_BF_REV_0_2) -#define ANOMALY_05000244 /* With instruction cache enabled, a CSYNC or SSYNC or - * IDLE around a Change of Control causes - * unpredictable results */ -#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel - * (TDM) */ -#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) -#define ANOMALY_05000252 /* EMAC Tx DMA error after an early frame abort */ -#endif -#define ANOMALY_05000253 /* Maximum external clock speed for Timers */ -#define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event - * interrupt not functional */ -#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) -#define ANOMALY_05000256 /* EMAC MDIO input latched on wrong MDC edge */ -#endif -#define ANOMALY_05000257 /* An interrupt or exception during short Hardware - * loops may cause the instruction fetch unit to - * malfunction */ -#define ANOMALY_05000258 /* Instruction Cache is corrupted when bit 9 and 12 of - * the ICPLB Data registers differ */ -#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */ -#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */ -#define ANOMALY_05000262 /* Stores to data cache may be lost */ -#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB exception */ -#define ANOMALY_05000264 /* A Sync instruction (CSYNC, SSYNC) or an IDLE - * instruction will cause an infinite stall in the - * second to last instruction in a hardware loop */ -#define ANOMALY_05000268 /* Memory DMA error when peripheral DMA is running - * and non-zero DEB_TRAFFIC_PERIOD value */ -#define ANOMALY_05000270 /* High I/O activity causes the output voltage of the - * internal voltage regulator (VDDint) to decrease */ -#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after - * an edge is detected may clear interrupt */ -#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause - * DMA system instability */ -#define ANOMALY_05000280 /* SPI Master boot mode does not work well with - * Atmel Dataflash devices */ -#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context - * is not restored */ -#define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic - * control */ -#define ANOMALY_05000283 /* System MMR Write Is Stalled Indefinitely When - * Killed in a Particular Stage */ -#define ANOMALY_05000285 /* New Feature: EMAC TX DMA Word Alignment - * (Not Available On Older Silicon) */ -#define ANOMALY_05000288 /* SPORTs may receive bad data if FIFOs fill up */ -#define ANOMALY_05000315 /* Killed System MMR Write Completes Erroneously - * On Next System MMR Access */ -#define ANOMALY_05000316 /* EMAC RMII mode: collisions occur in Full Duplex - * mode */ -#define ANOMALY_05000321 /* EMAC RMII mode: TX frames in half duplex fail with - * status No Carrier */ -#endif /* CONFIG_BF_REV_0_2 */ +/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */ +#define ANOMALY_05000074 (1) +/* DMA_RUN bit is not valid after a Peripheral Receive Channel DMA stops */ +#define ANOMALY_05000119 (1) +/* Rx.H cannot be used to access 16-bit System MMR registers */ +#define ANOMALY_05000122 (1) +/* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */ +#define ANOMALY_05000157 (__SILICON_REVISION__ < 2) +/* PPI Data Lengths Between 8 and 16 do not zero out upper bits*/ +#define ANOMALY_05000166 (1) /* XXX: deleted from BF537 sheet ? */ +/* PPI_DELAY not functional in PPI modes with 0 frame syncs */ +#define ANOMALY_05000180 (1) +/* Instruction Cache Is Not Functional */ +#define ANOMALY_05000237 (__SILICON_REVISION__ < 2) +/* If i-cache is on, CSYNC/SSYNC/IDLE around Change of Control causes failures */ +#define ANOMALY_05000244 (__SILICON_REVISION__ < 3) +/* Spurious Hardware Error from an access in the shadow of a conditional branch */ +#define ANOMALY_05000245 (1) +/* CLKIN Buffer Output Enable Reset Behavior Is Changed */ +#define ANOMALY_05000247 (1) +/* Incorrect Bit-Shift of Data Word in Multichannel (TDM) mode in certain conditions */ +#define ANOMALY_05000250 (__SILICON_REVISION__ < 3) +/* EMAC Tx DMA error after an early frame abort */ +#define ANOMALY_05000252 (__SILICON_REVISION__ < 3) +/* Maximum external clock speed for Timers */ +#define ANOMALY_05000253 (__SILICON_REVISION__ < 3) +/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT mode with external clock */ +#define ANOMALY_05000254 (__SILICON_REVISION__ > 2) +/* Entering Hibernate Mode with RTC Seconds event interrupt not functional */ +#define ANOMALY_05000255 (__SILICON_REVISION__ < 3) +/* EMAC MDIO input latched on wrong MDC edge */ +#define ANOMALY_05000256 (__SILICON_REVISION__ < 3) +/* Interrupt/Exception during short hardware loop may cause bad instruction fetches */ +#define ANOMALY_05000257 (__SILICON_REVISION__ < 3) +/* Instruction Cache is corrupted when bits 9 and 12 of the ICPLB Data registers differ */ +#define ANOMALY_05000258 (((ANOMALY_BF536 || ANOMALY_BF537) && __SILICON_REVISION__ == 1) || __SILICON_REVISION__ == 2) +/* ICPLB_STATUS MMR register may be corrupted */ +#define ANOMALY_05000260 (__SILICON_REVISION__ == 2) +/* DCPLB_FAULT_ADDR MMR register may be corrupted */ +#define ANOMALY_05000261 (__SILICON_REVISION__ < 3) +/* Stores to data cache may be lost */ +#define ANOMALY_05000262 (__SILICON_REVISION__ < 3) +/* Hardware loop corrupted when taking an ICPLB exception */ +#define ANOMALY_05000263 (__SILICON_REVISION__ == 2) +/* CSYNC/SSYNC/IDLE causes infinite stall in second to last instruction in hardware loop */ +#define ANOMALY_05000264 (__SILICON_REVISION__ < 3) +/* Sensitivity to noise with slow input edge rates on external SPORT TX and RX clocks */ +#define ANOMALY_05000265 (1) +/* Memory DMA error when peripheral DMA is running with non-zero DEB_TRAFFIC_PERIOD */ +#define ANOMALY_05000268 (__SILICON_REVISION__ < 3) +/* High I/O activity causes output voltage of internal voltage regulator (VDDint) to decrease */ +#define ANOMALY_05000270 (__SILICON_REVISION__ < 3) +/* Certain data cache write through modes fail for VDDint <=0.9V */ +#define ANOMALY_05000272 (1) +/* Writes to Synchronous SDRAM memory may be lost */ +#define ANOMALY_05000273 (__SILICON_REVISION__ < 3) +/* Writes to an I/O data register one SCLK cycle after an edge is detected may clear interrupt */ +#define ANOMALY_05000277 (__SILICON_REVISION__ < 3) +/* Disabling Peripherals with DMA running may cause DMA system instability */ +#define ANOMALY_05000278 (((ANOMALY_BF536 || ANOMALY_BF537) && __SILICON_REVISION__ < 3) || (ANOMALY_BF534 && __SILICON_REVISION__ < 2)) +/* SPI Master boot mode does not work well with Atmel Data flash devices */ +#define ANOMALY_05000280 (1) +/* False Hardware Error Exception when ISR context is not restored */ +#define ANOMALY_05000281 (__SILICON_REVISION__ < 3) +/* Memory DMA corruption with 32-bit data and traffic control */ +#define ANOMALY_05000282 (__SILICON_REVISION__ < 3) +/* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */ +#define ANOMALY_05000283 (__SILICON_REVISION__ < 3) +/* New Feature: EMAC TX DMA Word Alignment (Not Available On Older Silicon) */ +#define ANOMALY_05000285 (__SILICON_REVISION__ < 3) +/* SPORTs may receive bad data if FIFOs fill up */ +#define ANOMALY_05000288 (__SILICON_REVISION__ < 3) +/* Memory to memory DMA source/destination descriptors must be in same memory space */ +#define ANOMALY_05000301 (1) +/* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */ +#define ANOMALY_05000304 (__SILICON_REVISION__ < 3) +/* New Feature: Additional Hysteresis on SPORT Input Pins (Not Available On Older Silicon) */ +#define ANOMALY_05000305 (__SILICON_REVISION__ < 3) +/* SCKELOW Bit Does Not Maintain State Through Hibernate */ +#define ANOMALY_05000307 (__SILICON_REVISION__ < 3) +/* Writing UART_THR while UART clock is disabled sends erroneous start bit */ +#define ANOMALY_05000309 (__SILICON_REVISION__ < 3) +/* False hardware errors caused by fetches at the boundary of reserved memory */ +#define ANOMALY_05000310 (1) +/* Errors when SSYNC, CSYNC, or loads to LT, LB and LC registers are interrupted */ +#define ANOMALY_05000312 (1) +/* PPI is level sensitive on first transfer */ +#define ANOMALY_05000313 (1) +/* Killed System MMR Write Completes Erroneously On Next System MMR Access */ +#define ANOMALY_05000315 (__SILICON_REVISION__ < 3) +/* EMAC RMII mode: collisions occur in Full Duplex mode */ +#define ANOMALY_05000316 (__SILICON_REVISION__ < 3) +/* EMAC RMII mode: TX frames in half duplex fail with status No Carrier */ +#define ANOMALY_05000321 (__SILICON_REVISION__ < 3) +/* EMAC RMII mode at 10-Base-T speed: RX frames not received properly */ +#define ANOMALY_05000322 (1) -#endif /* _MACH_ANOMALY_H_ */ +/* Anomalies that don't exist on this proc */ +#define ANOMALY_05000125 (0) +#define ANOMALY_05000183 (0) +#define ANOMALY_05000198 (0) +#define ANOMALY_05000266 (0) +#define ANOMALY_05000311 (0) + +#endif diff --git a/include/asm-blackfin/mach-bf537/bf537.h b/include/asm-blackfin/mach-bf537/bf537.h index b8924cd7730c..04b08164e292 100644 --- a/include/asm-blackfin/mach-bf537/bf537.h +++ b/include/asm-blackfin/mach-bf537/bf537.h @@ -206,7 +206,7 @@ #define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly #endif -#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1) +#if ANOMALY_05000273 && (CONFIG_CCLK_DIV == 1) #error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK #endif diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h index 964a1c0ea637..952f03e140f2 100644 --- a/include/asm-blackfin/mach-bf548/anomaly.h +++ b/include/asm-blackfin/mach-bf548/anomaly.h @@ -6,46 +6,62 @@ * Licensed under the GPL-2 or later. */ +/* This file shoule be up to date with: + * - Revision B, April 6, 2007; ADSP-BF549 Silicon Anomaly List + */ + #ifndef _MACH_ANOMALY_H_ #define _MACH_ANOMALY_H_ -#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in - * slot1 and store of a P register in slot 2 is not - * supported */ -#define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive - * Channel DMA stops */ -#define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR - * registers. */ -#define ANOMALY_05000245 /* Spurious Hardware Error from an Access in the - * Shadow of a Conditional Branch */ -#define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event - * interrupt not functional */ -#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on - * SPORT external receive and transmit clocks. */ -#define ANOMALY_05000272 /* Certain data cache write through modes fail for - * VDDint <=0.9V */ -#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is - * not restored */ -#define ANOMALY_05000310 /* False Hardware Errors Caused by Fetches at the - * Boundary of Reserved Memory */ -#define ANOMALY_05000312 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and - * LC Registers Are Interrupted */ -#define ANOMALY_05000324 /* TWI Slave Boot Mode Is Not Functional */ -#define ANOMALY_05000325 /* External FIFO Boot Mode Is Not Functional */ -#define ANOMALY_05000327 /* Data Lost When Core and DMA Accesses Are Made to - * the USB FIFO Simultaneously */ -#define ANOMALY_05000328 /* Incorrect Access of OTP_STATUS During otp_write() - * function */ -#define ANOMALY_05000329 /* Synchronous Burst Flash Boot Mode Is Not Functional - * */ -#define ANOMALY_05000330 /* Host DMA Boot Mode Is Not Functional */ -#define ANOMALY_05000334 /* Inadequate Timing Margins on DDR DQS to DQ and DQM - * Skew */ -#define ANOMALY_05000335 /* Inadequate Rotary Debounce Logic Duration */ -#define ANOMALY_05000336 /* Phantom Interrupt Occurs After First Configuration - * of Host DMA Port */ -#define ANOMALY_05000337 /* Disallowed Configuration Prevents Subsequent - * Allowed Configuration on Host DMA Port */ -#define ANOMALY_05000338 /* Slave-Mode SPI0 MISO Failure With CPHA = 0 */ +/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */ +#define ANOMALY_05000074 (1) +/* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */ +#define ANOMALY_05000119 (1) +/* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */ +#define ANOMALY_05000122 (1) +/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */ +#define ANOMALY_05000245 (1) +/* Entering Hibernate State with RTC Seconds Interrupt Not Functional */ +#define ANOMALY_05000255 (1) +/* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */ +#define ANOMALY_05000265 (1) +/* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */ +#define ANOMALY_05000272 (1) +/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */ +#define ANOMALY_05000310 (1) +/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */ +#define ANOMALY_05000312 (1) +/* TWI Slave Boot Mode Is Not Functional */ +#define ANOMALY_05000324 (1) +/* External FIFO Boot Mode Is Not Functional */ +#define ANOMALY_05000325 (1) +/* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */ +#define ANOMALY_05000327 (1) +/* Incorrect Access of OTP_STATUS During otp_write() Function */ +#define ANOMALY_05000328 (1) +/* Synchronous Burst Flash Boot Mode Is Not Functional */ +#define ANOMALY_05000329 (1) +/* Host DMA Boot Mode Is Not Functional */ +#define ANOMALY_05000330 (1) +/* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */ +#define ANOMALY_05000334 (1) +/* Inadequate Rotary Debounce Logic Duration */ +#define ANOMALY_05000335 (1) +/* Phantom Interrupt Occurs After First Configuration of Host DMA Port */ +#define ANOMALY_05000336 (1) +/* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */ +#define ANOMALY_05000337 (1) +/* Slave-Mode SPI0 MISO Failure With CPHA = 0 */ +#define ANOMALY_05000338 (1) -#endif /* _MACH_ANOMALY_H_ */ +/* Anomalies that don't exist on this proc */ +#define ANOMALY_05000125 (0) +#define ANOMALY_05000183 (0) +#define ANOMALY_05000198 (0) +#define ANOMALY_05000244 (0) +#define ANOMALY_05000263 (0) +#define ANOMALY_05000266 (0) +#define ANOMALY_05000273 (0) +#define ANOMALY_05000311 (0) + +#endif diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h index 5a7986a83bee..4cb3337d45ee 100644 --- a/include/asm-blackfin/mach-bf561/anomaly.h +++ b/include/asm-blackfin/mach-bf561/anomaly.h @@ -7,155 +7,249 @@ */ /* This file shoule be up to date with: - * - Revision L, Aug 10, 2006; ADSP-BF561 Silicon Anomaly List + * - Revision N, March 28, 2007; ADSP-BF561 Silicon Anomaly List */ #ifndef _MACH_ANOMALY_H_ #define _MACH_ANOMALY_H_ -/* We do not support 0.1 or 0.4 silicon - sorry */ -#if (defined(CONFIG_BF_REV_0_1) || defined(CONFIG_BF_REV_0_2) || defined(CONFIG_BF_REV_0_4)) -#error Kernel will not work on BF561 Version 0.1, 0.2, or 0.4 +/* We do not support 0.1, 0.2, or 0.4 silicon - sorry */ +#if __SILICON_REVISION__ < 3 || __SILICON_REVISION__ == 4 +# error Kernel will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4 #endif -/* Issues that are common to 0.5 and 0.3 silicon */ -#if (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3)) -#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in - * slot1 and store of a P register in slot 2 is not - * supported */ -#define ANOMALY_05000099 /* UART Line Status Register (UART_LSR) bits are not - * updated at the same time. */ -#define ANOMALY_05000120 /* Testset instructions restricted to 32-bit aligned - * memory locations */ -#define ANOMALY_05000122 /* Rx.H cannot be used to access 16-bit System MMR - * registers */ -#define ANOMALY_05000127 /* Signbits instruction not functional under certain - * conditions */ -#define ANOMALY_05000149 /* IMDMA S1/D1 channel may stall */ -#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out - * upper bits */ -#define ANOMALY_05000167 /* Turning Serial Ports on With External Frame Syncs */ -#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame - * syncs */ -#define ANOMALY_05000182 /* IMDMA does not operate to full speed for 600MHz - * and higher devices */ -#define ANOMALY_05000187 /* IMDMA Corrupted Data after a Halt */ -#define ANOMALY_05000190 /* PPI not functional at core voltage < 1Volt */ -#define ANOMALY_05000208 /* VSTAT status bit in PLL_STAT register is not - * functional */ -#define ANOMALY_05000245 /* Spurious Hardware Error from an access in the - * shadow of a conditional branch */ -#define ANOMALY_05000257 /* Interrupt/Exception during short hardware loop - * may cause bad instruction fetches */ -#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on - * external SPORT TX and RX clocks */ -#define ANOMALY_05000267 /* IMDMA may corrupt data under certain conditions */ -#define ANOMALY_05000269 /* High I/O activity causes output voltage of internal - * voltage regulator (VDDint) to increase */ -#define ANOMALY_05000270 /* High I/O activity causes output voltage of internal - * voltage regulator (VDDint) to decrease */ -#define ANOMALY_05000272 /* Certain data cache write through modes fail for - * VDDint <=0.9V */ -#define ANOMALY_05000274 /* Data cache write back to external synchronous memory - * may be lost */ -#define ANOMALY_05000275 /* PPI Timing and sampling informaton updates */ -#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC - * registers are interrupted */ +/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */ +#define ANOMALY_05000074 (1) +/* UART Line Status Register (UART_LSR) Bits Are Not Updated at the Same Time */ +#define ANOMALY_05000099 (__SILICON_REVISION__ < 5) +/* Trace Buffers may contain errors in emulation mode and/or exception, NMI, reset handlers */ +#define ANOMALY_05000116 (__SILICON_REVISION__ < 3) +/* Testset instructions restricted to 32-bit aligned memory locations */ +#define ANOMALY_05000120 (1) +/* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */ +#define ANOMALY_05000122 (1) +/* Erroneous exception when enabling cache */ +#define ANOMALY_05000125 (__SILICON_REVISION__ < 3) +/* Signbits instruction not functional under certain conditions */ +#define ANOMALY_05000127 (1) +/* Two bits in the Watchpoint Status Register (WPSTAT) are swapped */ +#define ANOMALY_05000134 (__SILICON_REVISION__ < 3) +/* Enable wires from the Data Watchpoint Address Control Register (WPDACTL) are swapped */ +#define ANOMALY_05000135 (__SILICON_REVISION__ < 3) +/* Stall in multi-unit DMA operations */ +#define ANOMALY_05000136 (__SILICON_REVISION__ < 3) +/* Allowing the SPORT RX FIFO to fill will cause an overflow */ +#define ANOMALY_05000140 (__SILICON_REVISION__ < 3) +/* Infinite Stall may occur with a particular sequence of consecutive dual dag events */ +#define ANOMALY_05000141 (__SILICON_REVISION__ < 3) +/* Interrupts may be lost when a programmable input flag is configured to be edge sensitive */ +#define ANOMALY_05000142 (__SILICON_REVISION__ < 3) +/* DMA and TESTSET conflict when both are accessing external memory */ +#define ANOMALY_05000144 (__SILICON_REVISION__ < 3) +/* In PWM_OUT mode, you must enable the PPI block to generate a waveform from PPI_CLK */ +#define ANOMALY_05000145 (__SILICON_REVISION__ < 3) +/* MDMA may lose the first few words of a descriptor chain */ +#define ANOMALY_05000146 (__SILICON_REVISION__ < 3) +/* Source MDMA descriptor may stop with a DMA Error near beginning of descriptor fetch */ +#define ANOMALY_05000147 (__SILICON_REVISION__ < 3) +/* IMDMA S1/D1 channel may stall */ +#define ANOMALY_05000149 (1) +/* DMA engine may lose data due to incorrect handshaking */ +#define ANOMALY_05000150 (__SILICON_REVISION__ < 3) +/* DMA stalls when all three controllers read data from the same source */ +#define ANOMALY_05000151 (__SILICON_REVISION__ < 3) +/* Execution stall when executing in L2 and doing external accesses */ +#define ANOMALY_05000152 (__SILICON_REVISION__ < 3) +/* Frame Delay in SPORT Multichannel Mode */ +#define ANOMALY_05000153 (__SILICON_REVISION__ < 3) +/* SPORT TFS signal stays active in multichannel mode outside of valid channels */ +#define ANOMALY_05000154 (__SILICON_REVISION__ < 3) +/* Timers in PWM-Out Mode with PPI GP Receive (Input) Mode with 0 Frame Syncs */ +#define ANOMALY_05000156 (__SILICON_REVISION__ < 4) +/* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */ +#define ANOMALY_05000157 (__SILICON_REVISION__ < 3) +/* DMA Lock-up at CCLK to SCLK ratios of 4:1, 2:1, or 1:1 */ +#define ANOMALY_05000159 (__SILICON_REVISION__ < 3) +/* A read from external memory may return a wrong value with data cache enabled */ +#define ANOMALY_05000160 (__SILICON_REVISION__ < 3) +/* Data Cache Fill data can be corrupted after/during Instruction DMA if certain core stalls exist */ +#define ANOMALY_05000161 (__SILICON_REVISION__ < 3) +/* DMEM_CONTROL<12> is not set on Reset */ +#define ANOMALY_05000162 (__SILICON_REVISION__ < 3) +/* SPORT transmit data is not gated by external frame sync in certain conditions */ +#define ANOMALY_05000163 (__SILICON_REVISION__ < 3) +/* PPI Data Lengths Between 8 and 16 Do Not Zero Out Upper Bits */ +#define ANOMALY_05000166 (1) +/* Turning Serial Ports on with External Frame Syncs */ +#define ANOMALY_05000167 (1) +/* SDRAM auto-refresh and subsequent Power Ups */ +#define ANOMALY_05000168 (__SILICON_REVISION__ < 5) +/* DATA CPLB page miss can result in lost write-through cache data writes */ +#define ANOMALY_05000169 (__SILICON_REVISION__ < 5) +/* Boot-ROM code modifies SICA_IWRx wakeup registers */ +#define ANOMALY_05000171 (__SILICON_REVISION__ < 5) +/* DSPID register values incorrect */ +#define ANOMALY_05000172 (__SILICON_REVISION__ < 3) +/* DMA vs Core accesses to external memory */ +#define ANOMALY_05000173 (__SILICON_REVISION__ < 3) +/* Cache Fill Buffer Data lost */ +#define ANOMALY_05000174 (__SILICON_REVISION__ < 5) +/* Overlapping Sequencer and Memory Stalls */ +#define ANOMALY_05000175 (__SILICON_REVISION__ < 5) +/* Multiplication of (-1) by (-1) followed by an accumulator saturation */ +#define ANOMALY_05000176 (__SILICON_REVISION__ < 5) +/* PPI_COUNT Cannot Be Programmed to 0 in General Purpose TX or RX Modes */ +#define ANOMALY_05000179 (__SILICON_REVISION__ < 5) +/* PPI_DELAY Not Functional in PPI Modes with 0 Frame Syncs */ +#define ANOMALY_05000180 (1) +/* Disabling the PPI resets the PPI configuration registers */ +#define ANOMALY_05000181 (__SILICON_REVISION__ < 5) +/* IMDMA does not operate to full speed for 600MHz and higher devices */ +#define ANOMALY_05000182 (1) +/* Timer Pin limitations for PPI TX Modes with External Frame Syncs */ +#define ANOMALY_05000184 (__SILICON_REVISION__ < 5) +/* PPI TX Mode with 2 External Frame Syncs */ +#define ANOMALY_05000185 (__SILICON_REVISION__ < 5) +/* PPI packing with Data Length greater than 8 bits (not a meaningful mode) */ +#define ANOMALY_05000186 (__SILICON_REVISION__ < 5) +/* IMDMA Corrupted Data after a Halt */ +#define ANOMALY_05000187 (1) +/* IMDMA Restrictions on Descriptor and Buffer Placement in Memory */ +#define ANOMALY_05000188 (__SILICON_REVISION__ < 5) +/* False Protection Exceptions */ +#define ANOMALY_05000189 (__SILICON_REVISION__ < 5) +/* PPI not functional at core voltage < 1Volt */ +#define ANOMALY_05000190 (1) +/* PPI does not invert the Driving PPICLK edge in Transmit Modes */ +#define ANOMALY_05000191 (__SILICON_REVISION__ < 3) +/* False I/O Pin Interrupts on Edge-Sensitive Inputs When Polarity Setting Is Changed */ +#define ANOMALY_05000193 (__SILICON_REVISION__ < 5) +/* Restarting SPORT in Specific Modes May Cause Data Corruption */ +#define ANOMALY_05000194 (__SILICON_REVISION__ < 5) +/* Failing MMR Accesses When Stalled by Preceding Memory Read */ +#define ANOMALY_05000198 (__SILICON_REVISION__ < 5) +/* Current DMA Address Shows Wrong Value During Carry Fix */ +#define ANOMALY_05000199 (__SILICON_REVISION__ < 5) +/* SPORT TFS and DT Are Incorrectly Driven During Inactive Channels in Certain Conditions */ +#define ANOMALY_05000200 (__SILICON_REVISION__ < 5) +/* Possible Infinite Stall with Specific Dual-DAG Situation */ +#define ANOMALY_05000202 (__SILICON_REVISION__ < 5) +/* Incorrect data read with write-through cache and allocate cache lines on reads only mode */ +#define ANOMALY_05000204 (__SILICON_REVISION__ < 5) +/* Specific sequence that can cause DMA error or DMA stopping */ +#define ANOMALY_05000205 (__SILICON_REVISION__ < 5) +/* Recovery from "Brown-Out" Condition */ +#define ANOMALY_05000207 (__SILICON_REVISION__ < 5) +/* VSTAT Status Bit in PLL_STAT Register Is Not Functional */ +#define ANOMALY_05000208 (1) +/* Speed Path in Computational Unit Affects Certain Instructions */ +#define ANOMALY_05000209 (__SILICON_REVISION__ < 5) +/* UART TX Interrupt Masked Erroneously */ +#define ANOMALY_05000215 (__SILICON_REVISION__ < 5) +/* NMI Event at Boot Time Results in Unpredictable State */ +#define ANOMALY_05000219 (__SILICON_REVISION__ < 5) +/* Data Corruption with Cached External Memory and Non-Cached On-Chip L2 Memory */ +#define ANOMALY_05000220 (__SILICON_REVISION__ < 5) +/* Incorrect Pulse-Width of UART Start Bit */ +#define ANOMALY_05000225 (__SILICON_REVISION__ < 5) +/* Scratchpad Memory Bank Reads May Return Incorrect Data */ +#define ANOMALY_05000227 (__SILICON_REVISION__ < 5) +/* UART Receiver is Less Robust Against Baudrate Differences in Certain Conditions */ +#define ANOMALY_05000230 (__SILICON_REVISION__ < 5) +/* UART STB Bit Incorrectly Affects Receiver Setting */ +#define ANOMALY_05000231 (__SILICON_REVISION__ < 5) +/* SPORT data transmit lines are incorrectly driven in multichannel mode */ +#define ANOMALY_05000232 (__SILICON_REVISION__ < 5) +/* DF Bit in PLL_CTL Register Does Not Respond to Hardware Reset */ +#define ANOMALY_05000242 (__SILICON_REVISION__ < 5) +/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */ +#define ANOMALY_05000244 (__SILICON_REVISION__ < 5) +/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */ +#define ANOMALY_05000245 (__SILICON_REVISION__ < 5) +/* TESTSET operation forces stall on the other core */ +#define ANOMALY_05000248 (__SILICON_REVISION__ < 5) +/* Incorrect Bit Shift of Data Word in Multichannel (TDM) Mode in Certain Conditions */ +#define ANOMALY_05000250 (__SILICON_REVISION__ > 2 && __SILICON_REVISION__ < 5) +/* Exception Not Generated for MMR Accesses in Reserved Region */ +#define ANOMALY_05000251 (__SILICON_REVISION__ < 5) +/* Maximum External Clock Speed for Timers */ +#define ANOMALY_05000253 (__SILICON_REVISION__ < 5) +/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT Mode with External Clock */ +#define ANOMALY_05000254 (__SILICON_REVISION__ > 3) +/* Interrupt/Exception During Short Hardware Loop May Cause Bad Instruction Fetches */ +#define ANOMALY_05000257 (__SILICON_REVISION__ < 5) +/* Instruction Cache Is Corrupted When Bits 9 and 12 of the ICPLB Data Registers Differ */ +#define ANOMALY_05000258 (__SILICON_REVISION__ < 5) +/* ICPLB_STATUS MMR Register May Be Corrupted */ +#define ANOMALY_05000260 (__SILICON_REVISION__ < 5) +/* DCPLB_FAULT_ADDR MMR Register May Be Corrupted */ +#define ANOMALY_05000261 (__SILICON_REVISION__ < 5) +/* Stores To Data Cache May Be Lost */ +#define ANOMALY_05000262 (__SILICON_REVISION__ < 5) +/* Hardware Loop Corrupted When Taking an ICPLB Exception */ +#define ANOMALY_05000263 (__SILICON_REVISION__ < 5) +/* CSYNC/SSYNC/IDLE Causes Infinite Stall in Penultimate Instruction in Hardware Loop */ +#define ANOMALY_05000264 (__SILICON_REVISION__ < 5) +/* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */ +#define ANOMALY_05000265 (__SILICON_REVISION__ < 5) +/* IMDMA destination IRQ status must be read prior to using IMDMA */ +#define ANOMALY_05000266 (__SILICON_REVISION__ > 3) +/* IMDMA may corrupt data under certain conditions */ +#define ANOMALY_05000267 (1) +/* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Increase */ +#define ANOMALY_05000269 (1) +/* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */ +#define ANOMALY_05000270 (1) +/* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */ +#define ANOMALY_05000272 (1) +/* Data cache write back to external synchronous memory may be lost */ +#define ANOMALY_05000274 (1) +/* PPI Timing and Sampling Information Updates */ +#define ANOMALY_05000275 (__SILICON_REVISION__ > 2) +/* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */ +#define ANOMALY_05000276 (__SILICON_REVISION__ < 5) +/* Disabling Peripherals with DMA Running May Cause DMA System Instability */ +#define ANOMALY_05000278 (__SILICON_REVISION__ < 5) +/* False Hardware Error Exception When ISR Context Is Not Restored */ +#define ANOMALY_05000281 (__SILICON_REVISION__ < 5) +/* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */ +#define ANOMALY_05000283 (1) +/* A read will receive incorrect data under certain conditions */ +#define ANOMALY_05000287 (__SILICON_REVISION__ < 5) +/* SPORTs May Receive Bad Data If FIFOs Fill Up */ +#define ANOMALY_05000288 (__SILICON_REVISION__ < 5) +/* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */ +#define ANOMALY_05000301 (1) +/* SSYNCs After Writes To DMA MMR Registers May Not Be Handled Correctly */ +#define ANOMALY_05000302 (1) +/* New Feature: Additional Hysteresis on SPORT Input Pins (Not Available On Older Silicon) */ +#define ANOMALY_05000305 (__SILICON_REVISION__ < 5) +/* SCKELOW Bit Does Not Maintain State Through Hibernate */ +#define ANOMALY_05000307 (__SILICON_REVISION__ < 5) +/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */ +#define ANOMALY_05000310 (1) +/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */ +#define ANOMALY_05000312 (1) +/* PPI Is Level-Sensitive on First Transfer */ +#define ANOMALY_05000313 (1) +/* Killed System MMR Write Completes Erroneously On Next System MMR Access */ +#define ANOMALY_05000315 (1) +/* PF2 Output Remains Asserted After SPI Master Boot */ +#define ANOMALY_05000320 (__SILICON_REVISION__ > 3) +/* Erroneous GPIO Flag Pin Operations Under Specific Sequences */ +#define ANOMALY_05000323 (1) +/* SPORT Secondary Receive Channel Not Functional When Word Length Exceeds 16 Bits */ +#define ANOMALY_05000326 (__SILICON_REVISION__ > 3) +/* New Feature: 24-Bit SPI Boot Mode Support (Not Available On Older Silicon) */ +#define ANOMALY_05000331 (__SILICON_REVISION__ < 5) +/* New Feature: Slave SPI Boot Mode Supported (Not Available On Older Silicon) */ +#define ANOMALY_05000332 (__SILICON_REVISION__ < 5) +/* Flag Data Register Writes One SCLK Cycle After Edge Is Detected May Clear Interrupt Status */ +#define ANOMALY_05000333 (__SILICON_REVISION__ < 5) -#endif /* (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3)) */ +/* Anomalies that don't exist on this proc */ +#define ANOMALY_05000183 (0) +#define ANOMALY_05000273 (0) +#define ANOMALY_05000311 (0) -#if (defined(CONFIG_BF_REV_0_5)) -#define ANOMALY_05000254 /* Incorrect Timer Pulse Width in Single-Shot PWM_OUT - * mode with external clock */ -#define ANOMALY_05000266 /* IMDMA destination IRQ status must be read prior to - * using IMDMA */ #endif - -#if (defined(CONFIG_BF_REV_0_3)) -#define ANOMALY_05000156 /* Timers in PWM-Out Mode with PPI GP Receive (Input) - * Mode with 0 Frame Syncs */ -#define ANOMALY_05000168 /* SDRAM auto-refresh and subsequent Power Ups */ -#define ANOMALY_05000169 /* DATA CPLB page miss can result in lost write-through - * cache data writes */ -#define ANOMALY_05000171 /* Boot-ROM code modifies SICA_IWRx wakeup registers */ -#define ANOMALY_05000174 /* Cache Fill Buffer Data lost */ -#define ANOMALY_05000175 /* Overlapping Sequencer and Memory Stalls */ -#define ANOMALY_05000176 /* Multiplication of (-1) by (-1) followed by an - * accumulator saturation */ -#define ANOMALY_05000179 /* PPI_COUNT cannot be programmed to 0 in General - * Purpose TX or RX modes */ -#define ANOMALY_05000181 /* Disabling the PPI resets the PPI configuration - * registers */ -#define ANOMALY_05000184 /* Timer Pin limitations for PPI TX Modes with - * External Frame Syncs */ -#define ANOMALY_05000185 /* PPI TX Mode with 2 External Frame Syncs */ -#define ANOMALY_05000186 /* PPI packing with Data Length greater than 8 bits - * (not a meaningful mode) */ -#define ANOMALY_05000188 /* IMDMA Restrictions on Descriptor and Buffer - * Placement in Memory */ -#define ANOMALY_05000189 /* False Protection Exception */ -#define ANOMALY_05000193 /* False Flag Pin Interrupts on Edge Sensitive Inputs - * when polarity setting is changed */ -#define ANOMALY_05000194 /* Restarting SPORT in specific modes may cause data - * corruption */ -#define ANOMALY_05000198 /* Failing MMR accesses when stalled by preceding - * memory read */ -#define ANOMALY_05000199 /* DMA current address shows wrong value during carry - * fix */ -#define ANOMALY_05000200 /* SPORT TFS and DT are incorrectly driven during - * inactive channels in certain conditions */ -#define ANOMALY_05000202 /* Possible infinite stall with specific dual-DAG - * situation */ -#define ANOMALY_05000204 /* Incorrect data read with write-through cache and - * allocate cache lines on reads only mode */ -#define ANOMALY_05000205 /* Specific sequence that can cause DMA error or DMA - * stopping */ -#define ANOMALY_05000207 /* Recovery from "brown-out" condition */ -#define ANOMALY_05000209 /* Speed-Path in computational unit affects certain - * instructions */ -#define ANOMALY_05000215 /* UART TX Interrupt masked erroneously */ -#define ANOMALY_05000219 /* NMI event at boot time results in unpredictable - * state */ -#define ANOMALY_05000220 /* Data Corruption with Cached External Memory and - * Non-Cached On-Chip L2 Memory */ -#define ANOMALY_05000225 /* Incorrect pulse-width of UART start-bit */ -#define ANOMALY_05000227 /* Scratchpad memory bank reads may return incorrect - * data */ -#define ANOMALY_05000230 /* UART Receiver is less robust against Baudrate - * Differences in certain Conditions */ -#define ANOMALY_05000231 /* UART STB bit incorrectly affects receiver setting */ -#define ANOMALY_05000232 /* SPORT data transmit lines are incorrectly driven in - * multichannel mode */ -#define ANOMALY_05000242 /* DF bit in PLL_CTL register does not respond to - * hardware reset */ -#define ANOMALY_05000244 /* If i-cache is on, CSYNC/SSYNC/IDLE around Change of - * Control causes failures */ -#define ANOMALY_05000248 /* TESTSET operation forces stall on the other core */ -#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel - * (TDM) mode in certain conditions */ -#define ANOMALY_05000251 /* Exception not generated for MMR accesses in - * reserved region */ -#define ANOMALY_05000253 /* Maximum external clock speed for Timers */ -#define ANOMALY_05000258 /* Instruction Cache is corrupted when bits 9 and 12 - * of the ICPLB Data registers differ */ -#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */ -#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */ -#define ANOMALY_05000262 /* Stores to data cache may be lost */ -#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB - * exception */ -#define ANOMALY_05000264 /* CSYNC/SSYNC/IDLE causes infinite stall in second - * to last instruction in hardware loop */ -#define ANOMALY_05000276 /* Timing requirements change for External Frame - * Sync PPI Modes with non-zero PPI_DELAY */ -#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause - * DMA system instability */ -#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is - * not restored */ -#define ANOMALY_05000283 /* An MMR write is stalled indefinitely when killed - * in a particular stage */ -#define ANOMALY_05000287 /* A read will receive incorrect data under certain - * conditions */ -#define ANOMALY_05000288 /* SPORTs may receive bad data if FIFOs fill up */ -#endif - -#endif /* _MACH_ANOMALY_H_ */ diff --git a/include/asm-blackfin/mach-bf561/bf561.h b/include/asm-blackfin/mach-bf561/bf561.h index 96a5d3a47e45..8cc2e0033e0a 100644 --- a/include/asm-blackfin/mach-bf561/bf561.h +++ b/include/asm-blackfin/mach-bf561/bf561.h @@ -311,7 +311,7 @@ #define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly #endif -#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1) +#if ANOMALY_05000273 && (CONFIG_CCLK_DIV == 1) #error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK #endif diff --git a/include/asm-blackfin/mach-common/cdef_LPBlackfin.h b/include/asm-blackfin/mach-common/cdef_LPBlackfin.h index 94ed381e5606..ede210eca4ec 100644 --- a/include/asm-blackfin/mach-common/cdef_LPBlackfin.h +++ b/include/asm-blackfin/mach-common/cdef_LPBlackfin.h @@ -39,7 +39,7 @@ #define bfin_read_SRAM_BASE_ADDRESS() bfin_read32(SRAM_BASE_ADDRESS) #define bfin_write_SRAM_BASE_ADDRESS(val) bfin_write32(SRAM_BASE_ADDRESS,val) #define bfin_read_DMEM_CONTROL() bfin_read32(DMEM_CONTROL) -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 extern void bfin_write_DMEM_CONTROL(unsigned int val); #else #define bfin_write_DMEM_CONTROL(val) bfin_write32(DMEM_CONTROL,val) @@ -129,7 +129,7 @@ extern void bfin_write_DMEM_CONTROL(unsigned int val); #define DTEST_DATA3 0xFFE0040C */ #define bfin_read_IMEM_CONTROL() bfin_read32(IMEM_CONTROL) -#ifdef ANOMALY_05000125 +#if ANOMALY_05000125 extern void bfin_write_IMEM_CONTROL(unsigned int val); #else #define bfin_write_IMEM_CONTROL(val) bfin_write32(IMEM_CONTROL,val) diff --git a/include/asm-blackfin/mach-common/def_LPBlackfin.h b/include/asm-blackfin/mach-common/def_LPBlackfin.h index be1ece8c0c27..260515d15280 100644 --- a/include/asm-blackfin/mach-common/def_LPBlackfin.h +++ b/include/asm-blackfin/mach-common/def_LPBlackfin.h @@ -33,81 +33,77 @@ #include -/*#if !defined(__ADSPLPBLACKFIN__) -#warning def_LPBlackfin.h should only be included for 532 compatible chips. -#endif -*/ - #define MK_BMSK_(x) (1< +#if ANOMALY_05000198 +# define NOP_PAD_ANOMALY_05000198 "nop;" #else - -#define bfin_read8(addr) ({ unsigned char __v; \ - __asm__ __volatile__ ( \ - "%0 = b[%1] (z);\n\t" \ - :"=d"(__v) : "a"(addr)); \ - __v; }) - -#define bfin_read16(addr) ({ unsigned __v; \ - __asm__ __volatile__ (\ - "%0 = w[%1] (z);\n\t"\ - : "=d"(__v) : "a"(addr)); (unsigned short)__v; }) - -#define bfin_read32(addr) ({ unsigned __v; \ - __asm__ __volatile__ (\ - "%0 = [%1];\n\t"\ - : "=d"(__v) : "a"(addr)); __v; }) - -#define bfin_write8(addr, val) ({ \ - __asm__ __volatile__ ( \ - "b[%0] = %1; \n\t" \ - ::"a"(addr), "d"(val) : "memory");}) - -#define bfin_write16(addr,val) ({\ - __asm__ __volatile__ (\ - "w[%0] = %1;\n\t"\ - : : "a"(addr) , "d"(val) : "memory");}) - -#define bfin_write32(addr,val) ({\ - __asm__ __volatile__ (\ - "[%0] = %1;\n\t"\ - : : "a"(addr) , "d"(val) : "memory");}) - +# define NOP_PAD_ANOMALY_05000198 #endif +#define bfin_read8(addr) ({ \ + uint8_t __v; \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000198 \ + "%0 = b[%1] (z);" \ + : "=d" (__v) \ + : "a" (addr) \ + ); \ + __v; }) + +#define bfin_read16(addr) ({ \ + uint16_t __v; \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000198 \ + "%0 = w[%1] (z);" \ + : "=d" (__v) \ + : "a" (addr) \ + ); \ + __v; }) + +#define bfin_read32(addr) ({ \ + uint32_t __v; \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000198 \ + "%0 = [%1];" \ + : "=d" (__v) \ + : "a" (addr) \ + ); \ + __v; }) + +#define bfin_write8(addr, val) \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000198 \ + "b[%0] = %1;" \ + : \ + : "a" (addr), "d" (val) \ + : "memory" \ + ) + +#define bfin_write16(addr, val) \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000198 \ + "w[%0] = %1;" \ + : \ + : "a" (addr), "d" (val) \ + : "memory" \ + ) + +#define bfin_write32(addr, val) \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000198 \ + "[%0] = %1;" \ + : \ + : "a" (addr), "d" (val) \ + : "memory" \ + ) + +#endif /* __ASSEMBLY__ */ + /************************************************** * System Register Bits **************************************************/ diff --git a/include/asm-blackfin/system.h b/include/asm-blackfin/system.h index 5e5f1a0566c0..b03cf7d5b9a3 100644 --- a/include/asm-blackfin/system.h +++ b/include/asm-blackfin/system.h @@ -36,6 +36,7 @@ #include #include +#include /* * Interrupt configuring macros. @@ -43,53 +44,60 @@ extern unsigned long irq_flags; -#define local_irq_enable() do { \ - __asm__ __volatile__ ( \ - "sti %0;" \ - ::"d"(irq_flags)); \ -} while (0) +#define local_irq_enable() \ + __asm__ __volatile__( \ + "sti %0;" \ + : \ + : "d" (irq_flags) \ + ) -#define local_irq_disable() do { \ - int _tmp_dummy; \ - __asm__ __volatile__ ( \ - "cli %0;" \ - :"=d" (_tmp_dummy):); \ -} while (0) +#define local_irq_disable() \ + do { \ + int __tmp_dummy; \ + __asm__ __volatile__( \ + "cli %0;" \ + : "=d" (__tmp_dummy) \ + ); \ + } while (0) -#if defined(ANOMALY_05000244) && defined (CONFIG_BLKFIN_CACHE) -#define idle_with_irq_disabled() do { \ - __asm__ __volatile__ ( \ - "nop; nop;\n" \ - ".align 8;\n" \ - "sti %0; idle;\n" \ - ::"d" (irq_flags)); \ -} while (0) +#if ANOMALY_05000244 && defined(CONFIG_BLKFIN_CACHE) +# define NOP_PAD_ANOMALY_05000244 "nop; nop;" #else -#define idle_with_irq_disabled() do { \ - __asm__ __volatile__ ( \ - ".align 8;\n" \ - "sti %0; idle;\n" \ - ::"d" (irq_flags)); \ -} while (0) +# define NOP_PAD_ANOMALY_05000244 #endif +#define idle_with_irq_disabled() \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000244 \ + ".align 8;" \ + "sti %0;" \ + "idle;" \ + : \ + : "d" (irq_flags) \ + ) + #ifdef CONFIG_DEBUG_HWERR -#define __save_and_cli(x) do { \ - __asm__ __volatile__ ( \ - "cli %0;\n\tsti %1;" \ - :"=&d"(x): "d" (0x3F)); \ -} while (0) +# define __save_and_cli(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + "sti %1;" \ + : "=&d" (x) \ + : "d" (0x3F) \ + ) #else -#define __save_and_cli(x) do { \ - __asm__ __volatile__ ( \ - "cli %0;" \ - :"=&d"(x):); \ -} while (0) +# define __save_and_cli(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + : "=&d" (x) \ + ) #endif -#define local_save_flags(x) asm volatile ("cli %0;" \ - "sti %0;" \ - :"=d"(x):); +#define local_save_flags(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + "sti %0;" \ + : "=d" (x) \ + ) #ifdef CONFIG_DEBUG_HWERR #define irqs_enabled_from_flags(x) (((x) & ~0x3f) != 0) @@ -97,10 +105,11 @@ extern unsigned long irq_flags; #define irqs_enabled_from_flags(x) ((x) != 0x1f) #endif -#define local_irq_restore(x) do { \ - if (irqs_enabled_from_flags(x)) \ - local_irq_enable (); \ -} while (0) +#define local_irq_restore(x) \ + do { \ + if (irqs_enabled_from_flags(x)) \ + local_irq_enable(); \ + } while (0) /* For spinlocks etc */ #define local_irq_save(x) __save_and_cli(x) From 60e9356d770ca3622fe5e84680b78fc376e53fbf Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 25 Jul 2007 11:56:01 +0800 Subject: [PATCH 0004/2804] Blackfin arch: update BF54x anomaly list Signed-off-by: Mike Frysinger Signed-off-by: Roy Huang Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf548/anomaly.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h index 952f03e140f2..37e0bd22b64b 100644 --- a/include/asm-blackfin/mach-bf548/anomaly.h +++ b/include/asm-blackfin/mach-bf548/anomaly.h @@ -27,6 +27,8 @@ #define ANOMALY_05000265 (1) /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */ #define ANOMALY_05000272 (1) +/* False Hardware Error Exception when ISR context is not restored */ +#define ANOMALY_05000281 (1) /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */ #define ANOMALY_05000310 (1) /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */ @@ -59,6 +61,7 @@ #define ANOMALY_05000183 (0) #define ANOMALY_05000198 (0) #define ANOMALY_05000244 (0) +#define ANOMALY_05000261 (0) #define ANOMALY_05000263 (0) #define ANOMALY_05000266 (0) #define ANOMALY_05000273 (0) From d5148ffa600e6a655b458bedc593020e0574f967 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 25 Jul 2007 11:57:42 +0800 Subject: [PATCH 0005/2804] Blackfin arch: use the [CS]SYNC() macros which include anomaly workarounds rather than __builtin_bfin_[cs]sync() Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/oprofile/op_blackfin.h | 8 ++++---- drivers/serial/bfin_5xx.c | 14 +++++++------- include/asm-blackfin/mach-bf533/cdefBF532.h | 2 +- include/asm-blackfin/mach-bf537/cdefBF534.h | 2 +- include/asm-blackfin/mach-bf548/cdefBF54x_base.h | 2 +- include/asm-blackfin/mach-bf561/cdefBF561.h | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/blackfin/oprofile/op_blackfin.h b/arch/blackfin/oprofile/op_blackfin.h index f88f446c814f..05dd08c9d154 100644 --- a/arch/blackfin/oprofile/op_blackfin.h +++ b/arch/blackfin/oprofile/op_blackfin.h @@ -68,7 +68,7 @@ static inline unsigned int ctr_read(void) unsigned int tmp; tmp = bfin_read_PFCTL(); - __builtin_bfin_csync(); + CSYNC(); return tmp; } @@ -76,21 +76,21 @@ static inline unsigned int ctr_read(void) static inline void ctr_write(unsigned int val) { bfin_write_PFCTL(val); - __builtin_bfin_csync(); + CSYNC(); } static inline void count_read(unsigned int *count) { count[0] = bfin_read_PFCNTR0(); count[1] = bfin_read_PFCNTR1(); - __builtin_bfin_csync(); + CSYNC(); } static inline void count_write(unsigned int *count) { bfin_write_PFCNTR0(count[0]); bfin_write_PFCNTR1(count[1]); - __builtin_bfin_csync(); + CSYNC(); } extern int pm_overflow_handler(int irq, struct pt_regs *regs); diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 66c92bc36f3d..1e79ee605d93 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -173,12 +173,12 @@ void kgdb_put_debug_char(int chr) uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; while (!(UART_GET_LSR(uart) & THRE)) { - __builtin_bfin_ssync(); + SSYNC(); } UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); - __builtin_bfin_ssync(); + SSYNC(); UART_PUT_CHAR(uart, (unsigned char)chr); - __builtin_bfin_ssync(); + SSYNC(); } int kgdb_get_debug_char(void) @@ -192,12 +192,12 @@ int kgdb_get_debug_char(void) uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; while(!(UART_GET_LSR(uart) & DR)) { - __builtin_bfin_ssync(); + SSYNC(); } UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); - __builtin_bfin_ssync(); + SSYNC(); chr = UART_GET_CHAR(uart); - __builtin_bfin_ssync(); + SSYNC(); return chr; } @@ -1203,7 +1203,7 @@ static int __init bfin_serial_init(void) IRQF_DISABLED, "BFIN_UART_RX", uart); pr_info("Request irq for kgdb uart port\n"); UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI); - __builtin_bfin_ssync(); + SSYNC(); t.c_cflag = CS8|B57600; t.c_iflag = 0; t.c_oflag = 0; diff --git a/include/asm-blackfin/mach-bf533/cdefBF532.h b/include/asm-blackfin/mach-bf533/cdefBF532.h index 74f967b235e2..67a6dc49c521 100644 --- a/include/asm-blackfin/mach-bf533/cdefBF532.h +++ b/include/asm-blackfin/mach-bf533/cdefBF532.h @@ -65,7 +65,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SIC_IWR, IWR_ENABLE(0)); bfin_write16(VR_CTL, val); - __builtin_bfin_ssync(); + SSYNC(); local_irq_save(flags); asm("IDLE;"); diff --git a/include/asm-blackfin/mach-bf537/cdefBF534.h b/include/asm-blackfin/mach-bf537/cdefBF534.h index 84e58fa73dce..5dab41fb9c75 100644 --- a/include/asm-blackfin/mach-bf537/cdefBF534.h +++ b/include/asm-blackfin/mach-bf537/cdefBF534.h @@ -57,7 +57,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SIC_IWR, IWR_ENABLE(0)); bfin_write16(VR_CTL, val); - __builtin_bfin_ssync(); + SSYNC(); local_irq_save(flags); asm("IDLE;"); diff --git a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h index cdf29e75ea59..10475bbfc7dd 100644 --- a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h +++ b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h @@ -60,7 +60,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SIC_IWR2, 0); bfin_write16(VR_CTL, val); - __builtin_bfin_ssync(); + SSYNC(); local_irq_save(flags); asm("IDLE;"); diff --git a/include/asm-blackfin/mach-bf561/cdefBF561.h b/include/asm-blackfin/mach-bf561/cdefBF561.h index 73d4d65249cd..2efcd2c663ab 100644 --- a/include/asm-blackfin/mach-bf561/cdefBF561.h +++ b/include/asm-blackfin/mach-bf561/cdefBF561.h @@ -67,7 +67,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SICA_IWR1, 0); bfin_write16(VR_CTL, val); - __builtin_bfin_ssync(); + SSYNC(); local_irq_save(flags); asm("IDLE;"); From 36a1548f99e54520f049a703e1b91bae95e72481 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 25 Jul 2007 12:01:19 +0800 Subject: [PATCH 0006/2804] Blackfin arch: reorganize headers slightly so we can be sure things are defined early enough Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- include/asm-blackfin/blackfin.h | 6 ++++-- include/asm-blackfin/mach-bf533/cdefBF532.h | 8 +++----- include/asm-blackfin/mach-bf537/cdefBF534.h | 2 ++ include/asm-blackfin/mach-bf548/cdefBF54x_base.h | 2 ++ include/asm-blackfin/mach-bf561/cdefBF561.h | 7 ++----- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/asm-blackfin/blackfin.h b/include/asm-blackfin/blackfin.h index 1b2dd5a3fe7a..5ecf0aa22347 100644 --- a/include/asm-blackfin/blackfin.h +++ b/include/asm-blackfin/blackfin.h @@ -11,8 +11,7 @@ #define HI(con32) (((con32) >> 16) & 0xFFFF) #define hi(con32) (((con32) >> 16) & 0xFFFF) -#include -#include +#include #ifndef __ASSEMBLY__ @@ -105,4 +104,7 @@ static inline void CSYNC(void) #endif /* __ASSEMBLY__ */ +#include +#include + #endif /* _BLACKFIN_H_ */ diff --git a/include/asm-blackfin/mach-bf533/cdefBF532.h b/include/asm-blackfin/mach-bf533/cdefBF532.h index 67a6dc49c521..40c1ad39dcab 100644 --- a/include/asm-blackfin/mach-bf533/cdefBF532.h +++ b/include/asm-blackfin/mach-bf533/cdefBF532.h @@ -30,11 +30,9 @@ #ifndef _CDEF_BF532_H #define _CDEF_BF532_H -/* -#if !defined(__ADSPLPBLACKFIN__) -#warning cdefBF532.h should only be included for 532 compatible chips. -#endif -*/ + +#include + /*include all Core registers and bit definitions*/ #include "defBF532.h" diff --git a/include/asm-blackfin/mach-bf537/cdefBF534.h b/include/asm-blackfin/mach-bf537/cdefBF534.h index 5dab41fb9c75..78227bc855df 100644 --- a/include/asm-blackfin/mach-bf537/cdefBF534.h +++ b/include/asm-blackfin/mach-bf537/cdefBF534.h @@ -32,6 +32,8 @@ #ifndef _CDEF_BF534_H #define _CDEF_BF534_H +#include + /* Include all Core registers and bit definitions */ #include "defBF534.h" diff --git a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h index 10475bbfc7dd..aefab3f618c1 100644 --- a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h +++ b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h @@ -31,6 +31,8 @@ #ifndef _CDEF_BF54X_H #define _CDEF_BF54X_H +#include + #include "defBF54x_base.h" #include diff --git a/include/asm-blackfin/mach-bf561/cdefBF561.h b/include/asm-blackfin/mach-bf561/cdefBF561.h index 2efcd2c663ab..d667816486c0 100644 --- a/include/asm-blackfin/mach-bf561/cdefBF561.h +++ b/include/asm-blackfin/mach-bf561/cdefBF561.h @@ -31,11 +31,8 @@ #ifndef _CDEF_BF561_H #define _CDEF_BF561_H -/* -#if !defined(__ADSPBF561__) -#warning cdefBF561.h should only be included for BF561 chip. -#endif -*/ +#include + /* include all Core registers and bit definitions */ #include "defBF561.h" From e208f83a7aa4ebf6c0a68e814903e8aa33f9439a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 25 Jul 2007 10:11:42 +0800 Subject: [PATCH 0007/2804] Blackfin arch: use HI/LO macros rather than masking the bit ranges ourselves Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/mach-bf533/head.S | 12 +++---- arch/blackfin/mach-bf537/head.S | 12 +++---- arch/blackfin/mach-bf548/head.S | 12 +++---- arch/blackfin/mach-bf561/head.S | 12 +++---- arch/blackfin/mach-common/cache.S | 8 ++--- arch/blackfin/mach-common/cacheinit.S | 4 +-- arch/blackfin/mach-common/cplbmgr.S | 52 +++++++++++++-------------- arch/blackfin/mach-common/dpmc.S | 52 +++++++++++++-------------- arch/blackfin/mach-common/lock.S | 20 +++++------ 9 files changed, 92 insertions(+), 92 deletions(-) diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S index 5aeffd06fe71..69da0e8b7732 100644 --- a/arch/blackfin/mach-bf533/head.S +++ b/arch/blackfin/mach-bf533/head.S @@ -144,8 +144,8 @@ ENTRY(__start) ssync; /* Turn off the icache */ - p0.l = (IMEM_CONTROL & 0xFFFF); - p0.h = (IMEM_CONTROL >> 16); + p0.l = LO(IMEM_CONTROL); + p0.h = HI(IMEM_CONTROL); R1 = [p0]; R0 = ~ENICPLB; R0 = R0 & R1; @@ -162,8 +162,8 @@ ENTRY(__start) #endif /* Turn off the dcache */ - p0.l = (DMEM_CONTROL & 0xFFFF); - p0.h = (DMEM_CONTROL >> 16); + p0.l = LO(DMEM_CONTROL); + p0.h = HI(DMEM_CONTROL); R1 = [p0]; R0 = ~ENDCPLB; R0 = R0 & R1; @@ -417,8 +417,8 @@ ENTRY(_start_dma_code) w[p0] = r0.l; ssync; - p0.l = (EBIU_SDBCTL & 0xFFFF); - p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */ + p0.l = LO(EBIU_SDBCTL); + p0.h = HI(EBIU_SDBCTL); /* SDRAM Memory Bank Control Register */ r0 = mem_SDBCTL; w[p0] = r0.l; ssync; diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S index d9b411adf6a7..b1d4b91b7aed 100644 --- a/arch/blackfin/mach-bf537/head.S +++ b/arch/blackfin/mach-bf537/head.S @@ -100,8 +100,8 @@ ENTRY(__start) R0 = R1; /* Turn off the icache */ - p0.l = (IMEM_CONTROL & 0xFFFF); - p0.h = (IMEM_CONTROL >> 16); + p0.l = LO(IMEM_CONTROL); + p0.h = HI(IMEM_CONTROL); R1 = [p0]; R0 = ~ENICPLB; R0 = R0 & R1; @@ -118,8 +118,8 @@ ENTRY(__start) #endif /* Turn off the dcache */ - p0.l = (DMEM_CONTROL & 0xFFFF); - p0.h = (DMEM_CONTROL >> 16); + p0.l = LO(DMEM_CONTROL); + p0.h = HI(DMEM_CONTROL); R1 = [p0]; R0 = ~ENDCPLB; R0 = R0 & R1; @@ -436,8 +436,8 @@ ENTRY(_start_dma_code) w[p0] = r0.l; ssync; - p0.l = (EBIU_SDBCTL & 0xFFFF); - p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */ + p0.l = LO(EBIU_SDBCTL); + p0.h = HI(EBIU_SDBCTL); /* SDRAM Memory Bank Control Register */ r0 = mem_SDBCTL; w[p0] = r0.l; ssync; diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S index e5e56df3bf46..47cd91777a3b 100644 --- a/arch/blackfin/mach-bf548/head.S +++ b/arch/blackfin/mach-bf548/head.S @@ -97,8 +97,8 @@ ENTRY(__stext) R0 = R1; /* Turn off the icache */ - p0.l = (IMEM_CONTROL & 0xFFFF); - p0.h = (IMEM_CONTROL >> 16); + p0.l = LO(IMEM_CONTROL); + p0.h = HI(IMEM_CONTROL); R1 = [p0]; R0 = ~ENICPLB; R0 = R0 & R1; @@ -106,8 +106,8 @@ ENTRY(__stext) SSYNC; /* Turn off the dcache */ - p0.l = (DMEM_CONTROL & 0xFFFF); - p0.h = (DMEM_CONTROL >> 16); + p0.l = LO(DMEM_CONTROL); + p0.h = HI(DMEM_CONTROL); R1 = [p0]; R0 = ~ENDCPLB; R0 = R0 & R1; @@ -335,8 +335,8 @@ ENTRY(_start_dma_code) w[p0] = r0.l; ssync; - p0.l = (EBIU_SDBCTL & 0xFFFF); - p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */ + p0.l = LO(EBIU_SDBCTL); + p0.h = HI(EBIU_SDBCTL); /* SDRAM Memory Bank Control Register */ r0 = mem_SDBCTL; w[p0] = r0.l; ssync; diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S index b1d0e54a97a9..173893429b04 100644 --- a/arch/blackfin/mach-bf561/head.S +++ b/arch/blackfin/mach-bf561/head.S @@ -100,8 +100,8 @@ ENTRY(__start) R0 = R1; /* Turn off the icache */ - p0.l = (IMEM_CONTROL & 0xFFFF); - p0.h = (IMEM_CONTROL >> 16); + p0.l = LO(IMEM_CONTROL); + p0.h = HI(IMEM_CONTROL); R1 = [p0]; R0 = ~ENICPLB; R0 = R0 & R1; @@ -117,8 +117,8 @@ ENTRY(__start) #endif /* Turn off the dcache */ - p0.l = (DMEM_CONTROL & 0xFFFF); - p0.h = (DMEM_CONTROL >> 16); + p0.l = LO(DMEM_CONTROL); + p0.h = HI(DMEM_CONTROL); R1 = [p0]; R0 = ~ENDCPLB; R0 = R0 & R1; @@ -371,8 +371,8 @@ ENTRY(_start_dma_code) w[p0] = r0.l; ssync; - p0.l = (EBIU_SDBCTL & 0xFFFF); - p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */ + p0.l = LO(EBIU_SDBCTL); + p0.h = HI(EBIU_SDBCTL); /* SDRAM Memory Bank Control Register */ r0 = mem_SDBCTL; w[p0] = r0.l; ssync; diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S index 7063795eb7c0..0521b1588204 100644 --- a/arch/blackfin/mach-common/cache.S +++ b/arch/blackfin/mach-common/cache.S @@ -79,8 +79,8 @@ ENTRY(_icache_invalidate) ENTRY(_invalidate_entire_icache) [--SP] = ( R7:5); - P0.L = (IMEM_CONTROL & 0xFFFF); - P0.H = (IMEM_CONTROL >> 16); + P0.L = LO(IMEM_CONTROL); + P0.H = HI(IMEM_CONTROL); R7 = [P0]; /* Clear the IMC bit , All valid bits in the instruction @@ -197,8 +197,8 @@ ENTRY(_invalidate_entire_dcache) ENTRY(_dcache_invalidate) [--SP] = ( R7:6); - P0.L = (DMEM_CONTROL & 0xFFFF); - P0.H = (DMEM_CONTROL >> 16); + P0.L = LO(DMEM_CONTROL); + P0.H = HI(DMEM_CONTROL); R7 = [P0]; /* Clear the DMC[1:0] bits, All valid bits in the data diff --git a/arch/blackfin/mach-common/cacheinit.S b/arch/blackfin/mach-common/cacheinit.S index 05c0c77510b2..afa0adfac6c3 100644 --- a/arch/blackfin/mach-common/cacheinit.S +++ b/arch/blackfin/mach-common/cacheinit.S @@ -43,8 +43,8 @@ ENTRY(_bfin_write_IMEM_CONTROL) /* Enable Instruction Cache */ - P0.l = (IMEM_CONTROL & 0xFFFF); - P0.h = (IMEM_CONTROL >> 16); + P0.l = LO(IMEM_CONTROL); + P0.h = HI(IMEM_CONTROL); /* Anomaly 05000125 */ CLI R1; diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S index 6c256baf087d..cef94c13f956 100644 --- a/arch/blackfin/mach-common/cplbmgr.S +++ b/arch/blackfin/mach-common/cplbmgr.S @@ -75,15 +75,15 @@ ENTRY(_cplb_mgr) * from the configuration table. */ - P4.L = (ICPLB_FAULT_ADDR & 0xFFFF); - P4.H = (ICPLB_FAULT_ADDR >> 16); + P4.L = LO(ICPLB_FAULT_ADDR); + P4.H = HI(ICPLB_FAULT_ADDR); P1 = 16; P5.L = _page_size_table; P5.H = _page_size_table; - P0.L = (ICPLB_DATA0 & 0xFFFF); - P0.H = (ICPLB_DATA0 >> 16); + P0.L = LO(ICPLB_DATA0); + P0.H = HI(ICPLB_DATA0); R4 = [P4]; /* Get faulting address*/ R6 = 64; /* Advance past the fault address, which*/ R6 = R6 + R4; /* we'll use if we find a match*/ @@ -117,13 +117,13 @@ ENTRY(_cplb_mgr) I0 = R4; /* Fault address we'll search for*/ /* set up pointers */ - P0.L = (ICPLB_DATA0 & 0xFFFF); - P0.H = (ICPLB_DATA0 >> 16); + P0.L = LO(ICPLB_DATA0); + P0.H = HI(ICPLB_DATA0); /* The replacement procedure for ICPLBs */ - P4.L = (IMEM_CONTROL & 0xFFFF); - P4.H = (IMEM_CONTROL >> 16); + P4.L = LO(IMEM_CONTROL); + P4.H = HI(IMEM_CONTROL); /* disable cplbs */ R5 = [P4]; /* Control Register*/ @@ -243,8 +243,8 @@ ENTRY(_cplb_mgr) * last entry of the table. */ - P1.L = (ICPLB_DATA15 & 0xFFFF); /* ICPLB_DATA15 */ - P1.H = (ICPLB_DATA15 >> 16); + P1.L = LO(ICPLB_DATA15); /* ICPLB_DATA15 */ + P1.H = HI(ICPLB_DATA15); [P1] = R2; [P1-0x100] = R4; #ifdef CONFIG_CPLB_INFO @@ -292,10 +292,10 @@ ENTRY(_cplb_mgr) * pending writes associated with the CPLB. */ - P4.L = (DCPLB_STATUS & 0xFFFF); - P4.H = (DCPLB_STATUS >> 16); - P3.L = (DCPLB_DATA0 & 0xFFFF); - P3.H = (DCPLB_DATA0 >> 16); + P4.L = LO(DCPLB_STATUS); + P4.H = HI(DCPLB_STATUS); + P3.L = LO(DCPLB_DATA0); + P3.H = HI(DCPLB_DATA0); R5 = [P4]; /* A protection violation can be caused by more than just writes @@ -355,11 +355,11 @@ ENTRY(_cplb_mgr) * config table, that covers the faulting address. */ - P1.L = (DCPLB_DATA15 & 0xFFFF); - P1.H = (DCPLB_DATA15 >> 16); + P1.L = LO(DCPLB_DATA15); + P1.H = HI(DCPLB_DATA15); - P4.L = (DCPLB_FAULT_ADDR & 0xFFFF); - P4.H = (DCPLB_FAULT_ADDR >> 16); + P4.L = LO(DCPLB_FAULT_ADDR); + P4.H = HI(DCPLB_FAULT_ADDR); R4 = [P4]; I0 = R4; @@ -368,8 +368,8 @@ ENTRY(_cplb_mgr) R6 = R1; /* Save for later*/ /* Turn off CPLBs while we work.*/ - P4.L = (DMEM_CONTROL & 0xFFFF); - P4.H = (DMEM_CONTROL >> 16); + P4.L = LO(DMEM_CONTROL); + P4.H = HI(DMEM_CONTROL); R5 = [P4]; BITCLR(R5,ENDCPLB_P); CLI R0; @@ -384,8 +384,8 @@ ENTRY(_cplb_mgr) * are no good. */ - I1.L = (DCPLB_DATA0 & 0xFFFF); - I1.H = (DCPLB_DATA0 >> 16); + I1.L = LO(DCPLB_DATA0); + I1.H = HI(DCPLB_DATA0); P1 = 2; P2 = 16; I2.L = _dcplb_preference; @@ -475,8 +475,8 @@ ENTRY(_cplb_mgr) * one space closer to the start. */ - R1.L = (DCPLB_DATA16 & 0xFFFF); /* DCPLB_DATA15 + 4 */ - R1.H = (DCPLB_DATA16 >> 16); + R1.L = LO(DCPLB_DATA16); /* DCPLB_DATA15 + 4 */ + R1.H = HI(DCPLB_DATA16); R0 = P0; /* If the victim happens to be in DCPLB15, @@ -549,8 +549,8 @@ ENTRY(_cplb_mgr) * if necessary. */ - P1.L = (DCPLB_DATA15 & 0xFFFF); - P1.H = (DCPLB_DATA15 >> 16); + P1.L = LO(DCPLB_DATA15); + P1.H = HI(DCPLB_DATA15); /* If the DCPLB has cache bits set, but caching hasn't * been enabled, then we want to mask off the cache-in-L1 diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S index 97cdcd6a00d4..04194dca0151 100644 --- a/arch/blackfin/mach-common/dpmc.S +++ b/arch/blackfin/mach-common/dpmc.S @@ -39,8 +39,8 @@ ENTRY(_unmask_wdog_wakeup_evt) P0.H = hi(SICA_IWR1); P0.L = lo(SICA_IWR1); #else - P0.h = (SIC_IWR >> 16); - P0.l = (SIC_IWR & 0xFFFF); + P0.h = HI(SIC_IWR); + P0.l = LO(SIC_IWR); #endif R7 = [P0]; #if defined(CONFIG_BF561) @@ -60,11 +60,11 @@ ENTRY(_unmask_wdog_wakeup_evt) */ R7 = 0x0000(z); #if defined(CONFIG_BF561) - P0.h = (WDOGA_STAT >> 16); - P0.l = (WDOGA_STAT & 0xFFFF); + P0.h = HI(WDOGA_STAT); + P0.l = LO(WDOGA_STAT); #else - P0.h = (WDOG_STAT >> 16); - P0.l = (WDOG_STAT & 0xFFFF); + P0.h = HI(WDOG_STAT); + P0.l = LO(WDOG_STAT); #endif [P0] = R7; SSYNC; @@ -73,21 +73,21 @@ ENTRY(_unmask_wdog_wakeup_evt) ENTRY(_program_wdog_timer) [--SP] = ( R7:0, P5:0 ); #if defined(CONFIG_BF561) - P0.h = (WDOGA_CNT >> 16); - P0.l = (WDOGA_CNT & 0xFFFF); + P0.h = HI(WDOGA_CNT); + P0.l = LO(WDOGA_CNT); #else - P0.h = (WDOG_CNT >> 16); - P0.l = (WDOG_CNT & 0xFFFF); + P0.h = HI(WDOG_CNT); + P0.l = LO(WDOG_CNT); #endif [P0] = R0; SSYNC; #if defined(CONFIG_BF561) - P0.h = (WDOGA_CTL >> 16); - P0.l = (WDOGA_CTL & 0xFFFF); + P0.h = HI(WDOGA_CTL); + P0.l = LO(WDOGA_CTL); #else - P0.h = (WDOG_CTL >> 16); - P0.l = (WDOG_CTL & 0xFFFF); + P0.h = HI(WDOG_CTL); + P0.l = LO(WDOG_CTL); #endif R7 = W[P0](Z); CC = BITTST(R7,1); @@ -97,11 +97,11 @@ ENTRY(_program_wdog_timer) .LSKIP_WRITE_TO_STAT: #if defined(CONFIG_BF561) - P0.h = (WDOGA_CTL >> 16); - P0.l = (WDOGA_CTL & 0xFFFF); + P0.h = HI(WDOGA_CTL); + P0.l = LO(WDOGA_CTL); #else - P0.h = (WDOG_CTL >> 16); - P0.l = (WDOG_CTL & 0xFFFF); + P0.h = HI(WDOG_CTL); + P0.l = LO(WDOG_CTL); #endif R7 = W[P0](Z); BITCLR(R7,1); /* Enable GP event */ @@ -122,11 +122,11 @@ ENTRY(_clear_wdog_wakeup_evt) [--SP] = ( R7:0, P5:0 ); #if defined(CONFIG_BF561) - P0.h = (WDOGA_CTL >> 16); - P0.l = (WDOGA_CTL & 0xFFFF); + P0.h = HI(WDOGA_CTL); + P0.l = LO(WDOGA_CTL); #else - P0.h = (WDOG_CTL >> 16); - P0.l = (WDOG_CTL & 0xFFFF); + P0.h = HI(WDOG_CTL); + P0.l = LO(WDOG_CTL); #endif R7 = 0x0AD6(Z); W[P0] = R7.L; @@ -149,11 +149,11 @@ ENTRY(_clear_wdog_wakeup_evt) ENTRY(_disable_wdog_timer) [--SP] = ( R7:0, P5:0 ); #if defined(CONFIG_BF561) - P0.h = (WDOGA_CTL >> 16); - P0.l = (WDOGA_CTL & 0xFFFF); + P0.h = HI(WDOGA_CTL); + P0.l = LO(WDOGA_CTL); #else - P0.h = (WDOG_CTL >> 16); - P0.l = (WDOG_CTL & 0xFFFF); + P0.h = HI(WDOG_CTL); + P0.l = LO(WDOG_CTL); #endif R7 = 0xAD6(Z); W[P0] = R7.L; diff --git a/arch/blackfin/mach-common/lock.S b/arch/blackfin/mach-common/lock.S index 386ac8dda076..190edb3cdc84 100644 --- a/arch/blackfin/mach-common/lock.S +++ b/arch/blackfin/mach-common/lock.S @@ -43,12 +43,12 @@ ENTRY(_cache_grab_lock) [--SP]=( R7:0,P5:0 ); - P1.H = (IMEM_CONTROL >> 16); - P1.L = (IMEM_CONTROL & 0xFFFF); - P5.H = (ICPLB_ADDR0 >> 16); - P5.L = (ICPLB_ADDR0 & 0xFFFF); - P4.H = (ICPLB_DATA0 >> 16); - P4.L = (ICPLB_DATA0 & 0xFFFF); + P1.H = HI(IMEM_CONTROL); + P1.L = LO(IMEM_CONTROL); + P5.H = HI(ICPLB_ADDR0); + P5.L = LO(ICPLB_ADDR0); + P4.H = HI(ICPLB_DATA0); + P4.L = LO(ICPLB_DATA0); R7 = R0; /* If the code of interest already resides in the cache @@ -167,8 +167,8 @@ ENTRY(_cache_lock) [--SP]=( R7:0,P5:0 ); - P1.H = (IMEM_CONTROL >> 16); - P1.L = (IMEM_CONTROL & 0xFFFF); + P1.H = HI(IMEM_CONTROL); + P1.L = LO(IMEM_CONTROL); /* Disable the Interrupts*/ CLI R3; @@ -195,8 +195,8 @@ ENDPROC(_cache_lock) */ ENTRY(_read_iloc) - P1.H = (IMEM_CONTROL >> 16); - P1.L = (IMEM_CONTROL & 0xFFFF); + P1.H = HI(IMEM_CONTROL); + P1.L = LO(IMEM_CONTROL); R1 = 0xF; R0 = [P1]; R0 = R0 >> 3; From 35c724f310c4b73dbfa6503a46bf86a4c55f8193 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 3 Aug 2007 16:48:13 +0800 Subject: [PATCH 0008/2804] Blackfin arch: fix typo... we want csync in CSYNC(), not ssync Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- include/asm-blackfin/blackfin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-blackfin/blackfin.h b/include/asm-blackfin/blackfin.h index 5ecf0aa22347..3c6e597dced4 100644 --- a/include/asm-blackfin/blackfin.h +++ b/include/asm-blackfin/blackfin.h @@ -71,7 +71,7 @@ static inline void CSYNC(void) "nop;" "nop;" "nop;" - "ssync;" + "csync;" ); else __asm__ __volatile__("csync;"); From fb51d566803413d2682ca718aef1c6f946fdab05 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Fri, 3 Aug 2007 17:56:29 +0800 Subject: [PATCH 0009/2804] Blackfin arch: Fix Anomaly hanlding, as pointed out by Mike Signed-off-by: Robin Getz Cc: Mike Frysinger Signed-off-by: Bryan Wu --- include/asm-blackfin/blackfin.h | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/include/asm-blackfin/blackfin.h b/include/asm-blackfin/blackfin.h index 3c6e597dced4..984b74f0a2ec 100644 --- a/include/asm-blackfin/blackfin.h +++ b/include/asm-blackfin/blackfin.h @@ -19,7 +19,7 @@ static inline void SSYNC(void) { int _tmp; - if (ANOMALY_05000312 && ANOMALY_05000244) + if (ANOMALY_05000312) __asm__ __volatile__( "cli %0;" "nop;" @@ -28,14 +28,7 @@ static inline void SSYNC(void) "sti %0;" : "=d" (_tmp) ); - else if (ANOMALY_05000312 && !ANOMALY_05000244) - __asm__ __volatile__( - "cli %0;" - "ssync;" - "sti %0;" - : "=d" (_tmp) - ); - else if (!ANOMALY_05000312 && ANOMALY_05000244) + else if (ANOMALY_05000244) __asm__ __volatile__( "nop;" "nop;" @@ -50,7 +43,7 @@ static inline void SSYNC(void) static inline void CSYNC(void) { int _tmp; - if (ANOMALY_05000312 && ANOMALY_05000244) + if (ANOMALY_05000312) __asm__ __volatile__( "cli %0;" "nop;" @@ -59,14 +52,7 @@ static inline void CSYNC(void) "sti %0;" : "=d" (_tmp) ); - else if (ANOMALY_05000312 && !ANOMALY_05000244) - __asm__ __volatile__( - "cli %0;" - "csync;" - "sti %0;" - : "=d" (_tmp) - ); - else if (!ANOMALY_05000312 && ANOMALY_05000244) + else if (ANOMALY_05000244) __asm__ __volatile__( "nop;" "nop;" @@ -84,19 +70,15 @@ static inline void CSYNC(void) #define ssync(x) SSYNC(x) #define csync(x) CSYNC(x) -#if ANOMALY_05000312 && ANOMALY_05000244 +#if ANOMALY_05000312 #define SSYNC(scratch) cli scratch; nop; nop; SSYNC; sti scratch; #define CSYNC(scratch) cli scratch; nop; nop; CSYNC; sti scratch; -#elif ANOMALY_05000312 && !ANOMALY_05000244 -#define SSYNC(scratch) cli scratch; nop; nop; SSYNC; sti scratch; -#define CSYNC(scratch) cli scratch; nop; nop; CSYNC; sti scratch; - -#elif !ANOMALY_05000312 && ANOMALY_05000244 +#elif ANOMALY_05000244 #define SSYNC(scratch) nop; nop; nop; SSYNC; #define CSYNC(scratch) nop; nop; nop; CSYNC; -#elif !ANOMALY_05000312 && !ANOMALY_05000244 +#else #define SSYNC(scratch) SSYNC; #define CSYNC(scratch) CSYNC; From bc8c84c947ad65cd2850c43f96bea825e426f9eb Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 17:32:25 +0800 Subject: [PATCH 0010/2804] Blackfin arch: update to latest anomaly sheets Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf527/anomaly.h | 39 +++++++++++++++++++++++ include/asm-blackfin/mach-bf537/anomaly.h | 2 -- include/asm-blackfin/mach-bf548/anomaly.h | 18 +++++++++-- include/asm-blackfin/mach-bf561/anomaly.h | 1 + 4 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 include/asm-blackfin/mach-bf527/anomaly.h diff --git a/include/asm-blackfin/mach-bf527/anomaly.h b/include/asm-blackfin/mach-bf527/anomaly.h new file mode 100644 index 000000000000..6112bc38282f --- /dev/null +++ b/include/asm-blackfin/mach-bf527/anomaly.h @@ -0,0 +1,39 @@ +/* + * File: include/asm-blackfin/mach-bf527/anomaly.h + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * Copyright (C) 2004-2007 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +/* This file shoule be up to date with: + * - Revision A, May 30, 2007; ADSP-BF527 Blackfin Processor Anomaly List + */ + +#ifndef _MACH_ANOMALY_H_ +#define _MACH_ANOMALY_H_ + +/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */ +#define ANOMALY_05000074 (1) +/* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */ +#define ANOMALY_05000119 (1) +/* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */ +#define ANOMALY_05000122 (1) +/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */ +#define ANOMALY_05000245 (1) +/* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */ +#define ANOMALY_05000265 (1) +/* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */ +#define ANOMALY_05000301 (1) +/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */ +#define ANOMALY_05000312 (1) +/* Incorrect Access of OTP_STATUS During otp_write() Function */ +#define ANOMALY_05000328 (1) +/* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */ +#define ANOMALY_05000337 (1) +/* TWI Does Not Operate Correctly Under Certain Signal Termination Conditions */ +#define ANOMALY_05000342 (1) +/* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */ +#define ANOMALY_05000347 (1) + +#endif diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h index dc736c61980f..3803f156bf1c 100644 --- a/include/asm-blackfin/mach-bf537/anomaly.h +++ b/include/asm-blackfin/mach-bf537/anomaly.h @@ -44,8 +44,6 @@ #define ANOMALY_05000122 (1) /* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */ #define ANOMALY_05000157 (__SILICON_REVISION__ < 2) -/* PPI Data Lengths Between 8 and 16 do not zero out upper bits*/ -#define ANOMALY_05000166 (1) /* XXX: deleted from BF537 sheet ? */ /* PPI_DELAY not functional in PPI modes with 0 frame syncs */ #define ANOMALY_05000180 (1) /* Instruction Cache Is Not Functional */ diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h index 37e0bd22b64b..224837845c7c 100644 --- a/include/asm-blackfin/mach-bf548/anomaly.h +++ b/include/asm-blackfin/mach-bf548/anomaly.h @@ -7,7 +7,7 @@ */ /* This file shoule be up to date with: - * - Revision B, April 6, 2007; ADSP-BF549 Silicon Anomaly List + * - Revision C, July 16, 2007; ADSP-BF549 Silicon Anomaly List */ #ifndef _MACH_ANOMALY_H_ @@ -21,14 +21,14 @@ #define ANOMALY_05000122 (1) /* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */ #define ANOMALY_05000245 (1) -/* Entering Hibernate State with RTC Seconds Interrupt Not Functional */ -#define ANOMALY_05000255 (1) /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */ #define ANOMALY_05000265 (1) /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */ #define ANOMALY_05000272 (1) /* False Hardware Error Exception when ISR context is not restored */ #define ANOMALY_05000281 (1) +/* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */ +#define ANOMALY_05000304 (1) /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */ #define ANOMALY_05000310 (1) /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */ @@ -55,6 +55,18 @@ #define ANOMALY_05000337 (1) /* Slave-Mode SPI0 MISO Failure With CPHA = 0 */ #define ANOMALY_05000338 (1) +/* If Memory Reads Are Enabled on SDH or HOSTDP, Other DMAC1 Peripherals Cannot Read */ +#define ANOMALY_05000340 (1) +/* Boot Host Wait (HWAIT) and Boot Host Wait Alternate (HWAITA) Signals Are Swapped */ +#define ANOMALY_05000344 (1) +/* USB Calibration Value Is Not Intialized */ +#define ANOMALY_05000346 (1) +/* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */ +#define ANOMALY_05000347 (1) +/* Data Lost when Core Reads SDH Data FIFO */ +#define ANOMALY_05000349 (1) +/* PLL Status Register Is Inaccurate */ +#define ANOMALY_05000351 (1) /* Anomalies that don't exist on this proc */ #define ANOMALY_05000125 (0) diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h index 4cb3337d45ee..bed956456884 100644 --- a/include/asm-blackfin/mach-bf561/anomaly.h +++ b/include/asm-blackfin/mach-bf561/anomaly.h @@ -248,6 +248,7 @@ #define ANOMALY_05000333 (__SILICON_REVISION__ < 5) /* Anomalies that don't exist on this proc */ +#define ANOMALY_05000158 (0) #define ANOMALY_05000183 (0) #define ANOMALY_05000273 (0) #define ANOMALY_05000311 (0) From 301af2952b35fa527c89b4c0c0c1003d50afc378 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 24 Jul 2007 15:35:53 +0800 Subject: [PATCH 0011/2804] Blackfin arch: Finalize the generic gpio support - add gpio_to_irq and irq_to_gpio Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- include/asm-blackfin/gpio.h | 13 +++++++++++++ include/asm-blackfin/mach-bf533/irq.h | 2 ++ include/asm-blackfin/mach-bf537/irq.h | 2 ++ include/asm-blackfin/mach-bf548/irq.h | 2 ++ include/asm-blackfin/mach-bf561/irq.h | 2 ++ 5 files changed, 21 insertions(+) diff --git a/include/asm-blackfin/gpio.h b/include/asm-blackfin/gpio.h index 7480cfa7e2d6..e714363bc4ed 100644 --- a/include/asm-blackfin/gpio.h +++ b/include/asm-blackfin/gpio.h @@ -421,6 +421,19 @@ unsigned short gpio_get_value(unsigned short gpio); void gpio_direction_input(unsigned short gpio); void gpio_direction_output(unsigned short gpio); +#include /* cansleep wrappers */ +#include + +static inline int gpio_to_irq(unsigned gpio) +{ + return (gpio + GPIO_IRQ_BASE); +} + +static inline int irq_to_gpio(unsigned irq) +{ + return (irq - GPIO_IRQ_BASE); +} + #endif /* __ASSEMBLY__ */ #endif /* __ARCH_BLACKFIN_GPIO_H__ */ diff --git a/include/asm-blackfin/mach-bf533/irq.h b/include/asm-blackfin/mach-bf533/irq.h index 9879e68e315c..452fb825d891 100644 --- a/include/asm-blackfin/mach-bf533/irq.h +++ b/include/asm-blackfin/mach-bf533/irq.h @@ -128,6 +128,8 @@ Core Emulation ** #define IRQ_PF14 47 #define IRQ_PF15 48 +#define GPIO_IRQ_BASE IRQ_PF0 + #ifdef CONFIG_IRQCHIP_DEMUX_GPIO #define NR_IRQS (IRQ_PF15+1) #else diff --git a/include/asm-blackfin/mach-bf537/irq.h b/include/asm-blackfin/mach-bf537/irq.h index 8af2a832ef6b..36c44bc1a917 100644 --- a/include/asm-blackfin/mach-bf537/irq.h +++ b/include/asm-blackfin/mach-bf537/irq.h @@ -160,6 +160,8 @@ Core Emulation ** #define IRQ_PH14 96 #define IRQ_PH15 97 +#define GPIO_IRQ_BASE IRQ_PF0 + #ifdef CONFIG_IRQCHIP_DEMUX_GPIO #define NR_IRQS (IRQ_PH15+1) #else diff --git a/include/asm-blackfin/mach-bf548/irq.h b/include/asm-blackfin/mach-bf548/irq.h index e548d3cd81e3..21f06f710be6 100644 --- a/include/asm-blackfin/mach-bf548/irq.h +++ b/include/asm-blackfin/mach-bf548/irq.h @@ -337,6 +337,8 @@ Events (highest priority) EMU 0 #define IRQ_PJ14 BFIN_PJ_IRQ(14) /* N/A */ #define IRQ_PJ15 BFIN_PJ_IRQ(15) /* N/A */ +#define GPIO_IRQ_BASE IRQ_PA0 + #ifdef CONFIG_IRQCHIP_DEMUX_GPIO #define NR_IRQS (IRQ_PJ15+1) #else diff --git a/include/asm-blackfin/mach-bf561/irq.h b/include/asm-blackfin/mach-bf561/irq.h index a753ce720d74..12789927db3d 100644 --- a/include/asm-blackfin/mach-bf561/irq.h +++ b/include/asm-blackfin/mach-bf561/irq.h @@ -289,6 +289,8 @@ #define IRQ_PF46 119 #define IRQ_PF47 120 +#define GPIO_IRQ_BASE IRQ_PF0 + #ifdef CONFIG_IRQCHIP_DEMUX_GPIO #define NR_IRQS (IRQ_PF47 + 1) #else From b2d1583f8e33c5472485fb99b29e065db373b675 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 24 Jul 2007 15:46:36 +0800 Subject: [PATCH 0012/2804] Blackfin arch: Advertise GENERIC_GPIO and remove duplicated GENERIC_CALIBRATE_DELAY Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 017defaa525b..5c1e215c8b6f 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -57,7 +57,7 @@ config GENERIC_TIME bool default n -config GENERIC_CALIBRATE_DELAY +config GENERIC_GPIO bool default y From 40d63406a0dfc070fff9336c182619a0b167f165 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 10 Oct 2007 22:55:30 +0800 Subject: [PATCH 0013/2804] Blackfin arch: store labels so we later know who allocated GPIO/Peripheral resources Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/mach-bf548/gpio.c | 87 +++++++++++++++++++++----- include/asm-blackfin/mach-bf548/gpio.h | 5 -- 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/arch/blackfin/mach-bf548/gpio.c b/arch/blackfin/mach-bf548/gpio.c index 0da5f0003b8c..c073ab36066d 100644 --- a/arch/blackfin/mach-bf548/gpio.c +++ b/arch/blackfin/mach-bf548/gpio.c @@ -49,6 +49,9 @@ static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; +char *str_ident = NULL; + +#define RESOURCE_LABEL_SIZE 16 inline int check_gpio(unsigned short gpio) { @@ -70,7 +73,6 @@ inline void portmux_setup(unsigned short portno, unsigned short function) pmux |= (function & 0x3) << (2 * gpio_sub_n(portno)); gpio_array[gpio_bank(portno)]->port_mux = pmux; - } inline u16 get_portmux(unsigned short portno) @@ -80,16 +82,11 @@ inline u16 get_portmux(unsigned short portno) pmux = gpio_array[gpio_bank(portno)]->port_mux; return (pmux >> (2 * gpio_sub_n(portno)) & 0x3); - } static void port_setup(unsigned short gpio, unsigned short usage) { if (usage == GPIO_USAGE) { - if (gpio_array[gpio_bank(gpio)]->port_fer & gpio_bit(gpio)) - printk(KERN_WARNING - "bfin-gpio: Possible Conflict with Peripheral " - "usage and GPIO %d detected!\n", gpio); gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); } else gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); @@ -98,6 +95,11 @@ static void port_setup(unsigned short gpio, unsigned short usage) static int __init bfin_gpio_init(void) { + + str_ident = kzalloc(RESOURCE_LABEL_SIZE * 256, GFP_KERNEL); + if (!str_ident) + return -ENOMEM; + printk(KERN_INFO "Blackfin GPIO Controller\n"); return 0; @@ -105,11 +107,47 @@ static int __init bfin_gpio_init(void) arch_initcall(bfin_gpio_init); +static void set_label(unsigned short ident, const char *label) +{ + + if (label && str_ident) { + strncpy(str_ident + ident * RESOURCE_LABEL_SIZE, label, + RESOURCE_LABEL_SIZE); + str_ident[ident * RESOURCE_LABEL_SIZE + + RESOURCE_LABEL_SIZE - 1] = 0; + } +} + +static char *get_label(unsigned short ident) +{ + if (!str_ident) + return "UNKNOWN"; + + return (str_ident[ident * RESOURCE_LABEL_SIZE] ? + (str_ident + ident * RESOURCE_LABEL_SIZE) : "UNKNOWN"); +} + +static int cmp_label(unsigned short ident, const char *label) +{ + if (label && str_ident) + return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE, + label, strlen(label)); + else + return -EINVAL; +} + int peripheral_request(unsigned short per, const char *label) { unsigned long flags; unsigned short ident = P_IDENT(per); + /* + * Don't cares are pins with only one dedicated function + */ + + if (per & P_DONTCARE) + return 0; + if (!(per & P_DEFINED)) return -ENODEV; @@ -120,8 +158,8 @@ int peripheral_request(unsigned short per, const char *label) if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { printk(KERN_ERR - "%s: Peripheral %d is already reserved as GPIO!\n", - __FUNCTION__, per); + "%s: Peripheral %d is already reserved as GPIO by %s !\n", + __FUNCTION__, ident, get_label(ident)); dump_stack(); local_irq_restore(flags); return -EBUSY; @@ -131,22 +169,38 @@ int peripheral_request(unsigned short per, const char *label) u16 funct = get_portmux(ident); + /* + * Pin functions like AMC address strobes my + * be requested and used by several drivers + */ + if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) { + + /* + * Allow that the identical pin function can + * be requested from the same driver twice + */ + + if (cmp_label(ident, label) == 0) + goto anyway; + printk(KERN_ERR - "%s: Peripheral %d is already reserved!\n", - __FUNCTION__, per); + "%s: Peripheral %d function %d is already reserved by %s !\n", + __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident)); dump_stack(); local_irq_restore(flags); return -EBUSY; } } +anyway: reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); portmux_setup(ident, P_FUNCT2MUX(per)); port_setup(ident, PERIPHERAL_USAGE); local_irq_restore(flags); + set_label(ident, label); return 0; } @@ -154,7 +208,6 @@ EXPORT_SYMBOL(peripheral_request); int peripheral_request_list(unsigned short per[], const char *label) { - u16 cnt; int ret; @@ -173,6 +226,9 @@ void peripheral_free(unsigned short per) unsigned long flags; unsigned short ident = P_IDENT(per); + if (per & P_DONTCARE) + return; + if (!(per & P_DEFINED)) return; @@ -182,8 +238,6 @@ void peripheral_free(unsigned short per) local_irq_save(flags); if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) { - printk(KERN_ERR "bfin-gpio: Peripheral %d wasn't reserved!\n", per); - dump_stack(); local_irq_restore(flags); return; } @@ -234,7 +288,8 @@ int gpio_request(unsigned short gpio, const char *label) local_irq_save(flags); if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { - printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio); + printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", + gpio, get_label(gpio)); dump_stack(); local_irq_restore(flags); return -EBUSY; @@ -242,7 +297,8 @@ int gpio_request(unsigned short gpio, const char *label) if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { printk(KERN_ERR - "bfin-gpio: GPIO %d is already reserved as Peripheral!\n", gpio); + "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", + gpio, get_label(gpio)); dump_stack(); local_irq_restore(flags); return -EBUSY; @@ -253,6 +309,7 @@ int gpio_request(unsigned short gpio, const char *label) local_irq_restore(flags); port_setup(gpio, GPIO_USAGE); + set_label(gpio, label); return 0; } diff --git a/include/asm-blackfin/mach-bf548/gpio.h b/include/asm-blackfin/mach-bf548/gpio.h index dbf66bcabe35..cb8b0f15c9a6 100644 --- a/include/asm-blackfin/mach-bf548/gpio.h +++ b/include/asm-blackfin/mach-bf548/gpio.h @@ -209,8 +209,3 @@ struct gpio_port_t { unsigned short dummy7; unsigned int port_mux; }; - -int gpio_request(unsigned short gpio, const char *label); -void peripheral_free(unsigned short per); -int peripheral_request_list(unsigned short per[], const char *label); -void peripheral_free_list(unsigned short per[]); From 6782ea9ae8c2aa82dfeab84cb168126fbcbf4526 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 24 Jul 2007 15:16:59 +0800 Subject: [PATCH 0014/2804] Blackfin arch: Add label to call new GPIO API Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/mach-common/ints-priority-dc.c | 4 ++-- arch/blackfin/mach-common/ints-priority-sc.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c index 660f881b620a..d5d9e57813dd 100644 --- a/arch/blackfin/mach-common/ints-priority-dc.c +++ b/arch/blackfin/mach-common/ints-priority-dc.c @@ -221,7 +221,7 @@ static unsigned int bf561_gpio_irq_startup(unsigned int irq) if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { - ret = gpio_request(gpionr, NULL); + ret = gpio_request(gpionr, "IRQ"); if (ret) return ret; @@ -261,7 +261,7 @@ static int bf561_gpio_irq_type(unsigned int irq, unsigned int type) if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { - ret = gpio_request(gpionr, NULL); + ret = gpio_request(gpionr, "IRQ"); if (ret) return ret; diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c index 4708023fe716..505b9484497a 100644 --- a/arch/blackfin/mach-common/ints-priority-sc.c +++ b/arch/blackfin/mach-common/ints-priority-sc.c @@ -343,7 +343,7 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq) u16 gpionr = irq - IRQ_PF0; if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { - ret = gpio_request(gpionr, NULL); + ret = gpio_request(gpionr, "IRQ"); if (ret) return ret; } @@ -377,7 +377,7 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { - ret = gpio_request(gpionr, NULL); + ret = gpio_request(gpionr, "IRQ"); if (ret) return ret; } @@ -587,7 +587,7 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq) } if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { - ret = gpio_request(gpionr, NULL); + ret = gpio_request(gpionr, "IRQ"); if (ret) return ret; } @@ -627,7 +627,7 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { - ret = gpio_request(gpionr, NULL); + ret = gpio_request(gpionr, "IRQ"); if (ret) return ret; } From 31430ba58a3c33cf32aa89117876f6e24f1b9a6e Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 24 Jul 2007 16:27:25 +0800 Subject: [PATCH 0015/2804] Blackfin arch: Add PORT_J.High (needed for BF548-EZkit Touchscreen interrupts) - remove PORT_C.H Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/mach-bf548/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/blackfin/mach-bf548/Kconfig b/arch/blackfin/mach-bf548/Kconfig index e78b03d56c7c..3976b7f523c3 100644 --- a/arch/blackfin/mach-bf548/Kconfig +++ b/arch/blackfin/mach-bf548/Kconfig @@ -282,7 +282,7 @@ menu "Assignment" config PINTx_REASSIGN bool "Reprogram PINT Assignment" - default n + default y help The interrupt assignment registers controls the pin-to-interrupt assignment in a byte-wide manner. Each option allows you to select @@ -303,7 +303,7 @@ config PINT1_ASSIGN config PINT2_ASSIGN hex "PINT2_ASSIGN" depends on PINTx_REASSIGN - default 0x00000101 + default 0x07000101 config PINT3_ASSIGN hex "PINT3_ASSIGN" depends on PINTx_REASSIGN From 214cccbbb22136566e72956fcd23c48c2a4abb33 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 25 Jul 2007 14:42:03 +0800 Subject: [PATCH 0016/2804] Blackfin arch: bug fixing, add missing BF533_FAMILY GPIO_PFx definition Signed-off-by: Bryan Wu --- include/asm-blackfin/gpio.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/asm-blackfin/gpio.h b/include/asm-blackfin/gpio.h index e714363bc4ed..dd203cd93796 100644 --- a/include/asm-blackfin/gpio.h +++ b/include/asm-blackfin/gpio.h @@ -144,6 +144,24 @@ #ifdef BF533_FAMILY #define MAX_BLACKFIN_GPIOS 16 + +#define GPIO_PF0 0 +#define GPIO_PF1 1 +#define GPIO_PF2 2 +#define GPIO_PF3 3 +#define GPIO_PF4 4 +#define GPIO_PF5 5 +#define GPIO_PF6 6 +#define GPIO_PF7 7 +#define GPIO_PF8 8 +#define GPIO_PF9 9 +#define GPIO_PF10 10 +#define GPIO_PF11 11 +#define GPIO_PF12 12 +#define GPIO_PF13 13 +#define GPIO_PF14 14 +#define GPIO_PF15 15 + #endif #ifdef BF537_FAMILY From 7c100f3b9073a8e64d843536f72a9414024f1969 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Sun, 5 Aug 2007 15:43:03 +0800 Subject: [PATCH 0017/2804] Blackfin arch: fix bugs report by Andy Liu , AD1836 can't be probed in BF561-EZ Cc: Andy Liu Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf561/portmux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-blackfin/mach-bf561/portmux.h b/include/asm-blackfin/mach-bf561/portmux.h index 10d11d5ffe23..132ad31665e3 100644 --- a/include/asm-blackfin/mach-bf561/portmux.h +++ b/include/asm-blackfin/mach-bf561/portmux.h @@ -81,7 +81,7 @@ #define P_TMR1 (P_DEFINED | P_IDENT(GPIO_PF1)) #define P_TMR0 (P_DEFINED | P_IDENT(GPIO_PF0)) #define P_SPI0_MOSI (P_DONTCARE) -#define P_SPI0_MIS0 (P_DONTCARE) +#define P_SPI0_MISO (P_DONTCARE) #define P_SPI0_SCK (P_DONTCARE) #endif /* _MACH_PORTMUX_H_ */ From 06039e90b90af4029184d577b3c66e59f6039a9e Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Aug 2007 16:57:55 +0800 Subject: [PATCH 0018/2804] Blackfin arch: Fix define - SPORT0_DTPRI is first function Sigend-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf537/portmux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-blackfin/mach-bf537/portmux.h b/include/asm-blackfin/mach-bf537/portmux.h index ae6c53b28452..5a3f7d3bf73d 100644 --- a/include/asm-blackfin/mach-bf537/portmux.h +++ b/include/asm-blackfin/mach-bf537/portmux.h @@ -99,7 +99,7 @@ #define P_SPORT0_DRPRI (P_DEFINED | P_IDENT(PORT_PJ8) | P_FUNCT(0)) #define P_SPORT0_TSCLK (P_DEFINED | P_IDENT(PORT_PJ9) | P_FUNCT(0)) #define P_SPORT0_TFS (P_DEFINED | P_IDENT(PORT_PJ10) | P_FUNCT(0)) -#define P_SPORT0_DTPRI (P_DEFINED | P_IDENT(PORT_PJ11) | P_FUNCT(1)) +#define P_SPORT0_DTPRI (P_DEFINED | P_IDENT(PORT_PJ11) | P_FUNCT(0)) #define P_CAN0_RX (P_DEFINED | P_IDENT(PORT_PJ4) | P_FUNCT(1)) #define P_CAN0_TX (P_DEFINED | P_IDENT(PORT_PJ5) | P_FUNCT(1)) #define P_SPI0_SSEL3 (P_DEFINED | P_IDENT(PORT_PJ10) | P_FUNCT(1)) From 314c98d589b9da40af42cfe7213eff04c74caea3 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 24 Jul 2007 18:03:45 +0800 Subject: [PATCH 0019/2804] Blackfin arch: add missing gpio error handling to make sure we roll back requests in case one fails Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_gpio.c | 10 ++++++++-- arch/blackfin/mach-bf548/gpio.c | 11 +++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index b818a8da1215..979cf79d3799 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -711,9 +711,15 @@ int peripheral_request_list(unsigned short per[], const char *label) int ret; for (cnt = 0; per[cnt] != 0; cnt++) { + ret = peripheral_request(per[cnt], label); - if (ret < 0) - return ret; + + if (ret < 0) { + for ( ; cnt > 0; cnt--) { + peripheral_free(per[cnt - 1]); + } + return ret; + } } return 0; diff --git a/arch/blackfin/mach-bf548/gpio.c b/arch/blackfin/mach-bf548/gpio.c index c073ab36066d..f3b9deacd332 100644 --- a/arch/blackfin/mach-bf548/gpio.c +++ b/arch/blackfin/mach-bf548/gpio.c @@ -212,11 +212,18 @@ int peripheral_request_list(unsigned short per[], const char *label) int ret; for (cnt = 0; per[cnt] != 0; cnt++) { + ret = peripheral_request(per[cnt], label); - if (ret < 0) - return ret; + + if (ret < 0) { + for ( ; cnt > 0; cnt--) { + peripheral_free(per[cnt - 1]); + } + return ret; + } } + return 0; } EXPORT_SYMBOL(peripheral_request_list); From 1708268f7ee5177c35826f047b91d7324f099ab0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 25 Jul 2007 11:50:42 +0800 Subject: [PATCH 0020/2804] Blackfin arch: scrub remaining ASSEMBLY usage since the switch to __ASSEMBLY__ Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf533/blackfin.h | 2 +- include/asm-blackfin/mach-bf537/blackfin.h | 2 +- include/asm-blackfin/mach-bf548/blackfin.h | 2 +- include/asm-blackfin/mach-bf561/blackfin.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/asm-blackfin/mach-bf533/blackfin.h b/include/asm-blackfin/mach-bf533/blackfin.h index e4384491e972..f3b240abf170 100644 --- a/include/asm-blackfin/mach-bf533/blackfin.h +++ b/include/asm-blackfin/mach-bf533/blackfin.h @@ -38,7 +38,7 @@ #include "defBF532.h" #include "anomaly.h" -#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY)) +#if !defined(__ASSEMBLY__) #include "cdefBF532.h" #endif diff --git a/include/asm-blackfin/mach-bf537/blackfin.h b/include/asm-blackfin/mach-bf537/blackfin.h index bbd97051ec9c..f196588a3ad0 100644 --- a/include/asm-blackfin/mach-bf537/blackfin.h +++ b/include/asm-blackfin/mach-bf537/blackfin.h @@ -43,7 +43,7 @@ #include "defBF537.h" #endif -#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY)) +#if !defined(__ASSEMBLY__) #include "cdefBF534.h" /* UART 0*/ diff --git a/include/asm-blackfin/mach-bf548/blackfin.h b/include/asm-blackfin/mach-bf548/blackfin.h index 791218fe7d94..19e84dd4c99c 100644 --- a/include/asm-blackfin/mach-bf548/blackfin.h +++ b/include/asm-blackfin/mach-bf548/blackfin.h @@ -54,7 +54,7 @@ #include "defBF549.h" #endif -#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY)) +#if !defined(__ASSEMBLY__) #ifdef CONFIG_BF542 #include "cdefBF542.h" #endif diff --git a/include/asm-blackfin/mach-bf561/blackfin.h b/include/asm-blackfin/mach-bf561/blackfin.h index 2537c845e8b0..562aee39895c 100644 --- a/include/asm-blackfin/mach-bf561/blackfin.h +++ b/include/asm-blackfin/mach-bf561/blackfin.h @@ -38,7 +38,7 @@ #include "defBF561.h" #include "anomaly.h" -#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY)) +#if !defined(__ASSEMBLY__) #include "cdefBF561.h" #endif From 8c61362377970cd35cc37960b5cbed03cecd57e7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 3 Aug 2007 17:48:09 +0800 Subject: [PATCH 0021/2804] Blackfin arch: Some cosmetics based on LKML feedback from Joe Perches Signed-off-by: Michael Hennerich Cc: Joe Perches Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_gpio.c | 102 ++++++++++++++++++++----------- arch/blackfin/mach-bf548/gpio.c | 25 +++++--- 2 files changed, 81 insertions(+), 46 deletions(-) diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 979cf79d3799..0182ce1fc4fb 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -118,9 +118,14 @@ static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = { static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)]; -char *str_ident = NULL; -#define RESOURCE_LABEL_SIZE 16 +#define MAX_RESOURCES 256 +#define RESOURCE_LABEL_SIZE 16 + +struct str_ident { + char name[RESOURCE_LABEL_SIZE]; +} *str_ident; + #ifdef CONFIG_PM static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; @@ -152,10 +157,9 @@ static void set_label(unsigned short ident, const char *label) { if (label && str_ident) { - strncpy(str_ident + ident * RESOURCE_LABEL_SIZE, label, + strncpy(str_ident[ident].name, label, RESOURCE_LABEL_SIZE); - str_ident[ident * RESOURCE_LABEL_SIZE + - RESOURCE_LABEL_SIZE - 1] = 0; + str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; } } @@ -164,14 +168,13 @@ static char *get_label(unsigned short ident) if (!str_ident) return "UNKNOWN"; - return (str_ident[ident * RESOURCE_LABEL_SIZE] ? - (str_ident + ident * RESOURCE_LABEL_SIZE) : "UNKNOWN"); + return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); } static int cmp_label(unsigned short ident, const char *label) { if (label && str_ident) - return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE, + return strncmp(str_ident[ident].name, label, strlen(label)); else return -EINVAL; @@ -194,37 +197,63 @@ static void port_setup(unsigned short gpio, unsigned short usage) #ifdef BF537_FAMILY -#define PMUX_LUT_RES 0 -#define PMUX_LUT_OFFSET 1 -#define PMUX_LUT_ENTRIES 41 -#define PMUX_LUT_SIZE 2 - -static unsigned short port_mux_lut[PMUX_LUT_ENTRIES][PMUX_LUT_SIZE] = { - {P_PPI0_D13, 11}, {P_PPI0_D14, 11}, {P_PPI0_D15, 11}, - {P_SPORT1_TFS, 11}, {P_SPORT1_TSCLK, 11}, {P_SPORT1_DTPRI, 11}, - {P_PPI0_D10, 10}, {P_PPI0_D11, 10}, {P_PPI0_D12, 10}, - {P_SPORT1_RSCLK, 10}, {P_SPORT1_RFS, 10}, {P_SPORT1_DRPRI, 10}, - {P_PPI0_D8, 9}, {P_PPI0_D9, 9}, {P_SPORT1_DRSEC, 9}, - {P_SPORT1_DTSEC, 9}, {P_TMR2, 8}, {P_PPI0_FS3, 8}, {P_TMR3, 7}, - {P_SPI0_SSEL4, 7}, {P_TMR4, 6}, {P_SPI0_SSEL5, 6}, {P_TMR5, 5}, - {P_SPI0_SSEL6, 5}, {P_UART1_RX, 4}, {P_UART1_TX, 4}, {P_TMR6, 4}, - {P_TMR7, 4}, {P_UART0_RX, 3}, {P_UART0_TX, 3}, {P_DMAR0, 3}, - {P_DMAR1, 3}, {P_SPORT0_DTSEC, 1}, {P_SPORT0_DRSEC, 1}, - {P_CAN0_RX, 1}, {P_CAN0_TX, 1}, {P_SPI0_SSEL7, 1}, - {P_SPORT0_TFS, 0}, {P_SPORT0_DTPRI, 0}, {P_SPI0_SSEL2, 0}, - {P_SPI0_SSEL3, 0} +static struct { + unsigned short res; + unsigned short offset; +} port_mux_lut[] = { + {.res = P_PPI0_D13, .offset = 11}, + {.res = P_PPI0_D14, .offset = 11}, + {.res = P_PPI0_D15, .offset = 11}, + {.res = P_SPORT1_TFS, .offset = 11}, + {.res = P_SPORT1_TSCLK, .offset = 11}, + {.res = P_SPORT1_DTPRI, .offset = 11}, + {.res = P_PPI0_D10, .offset = 10}, + {.res = P_PPI0_D11, .offset = 10}, + {.res = P_PPI0_D12, .offset = 10}, + {.res = P_SPORT1_RSCLK, .offset = 10}, + {.res = P_SPORT1_RFS, .offset = 10}, + {.res = P_SPORT1_DRPRI, .offset = 10}, + {.res = P_PPI0_D8, .offset = 9}, + {.res = P_PPI0_D9, .offset = 9}, + {.res = P_SPORT1_DRSEC, .offset = 9}, + {.res = P_SPORT1_DTSEC, .offset = 9}, + {.res = P_TMR2, .offset = 8}, + {.res = P_PPI0_FS3, .offset = 8}, + {.res = P_TMR3, .offset = 7}, + {.res = P_SPI0_SSEL4, .offset = 7}, + {.res = P_TMR4, .offset = 6}, + {.res = P_SPI0_SSEL5, .offset = 6}, + {.res = P_TMR5, .offset = 5}, + {.res = P_SPI0_SSEL6, .offset = 5}, + {.res = P_UART1_RX, .offset = 4}, + {.res = P_UART1_TX, .offset = 4}, + {.res = P_TMR6, .offset = 4}, + {.res = P_TMR7, .offset = 4}, + {.res = P_UART0_RX, .offset = 3}, + {.res = P_UART0_TX, .offset = 3}, + {.res = P_DMAR0, .offset = 3}, + {.res = P_DMAR1, .offset = 3}, + {.res = P_SPORT0_DTSEC, .offset = 1}, + {.res = P_SPORT0_DRSEC, .offset = 1}, + {.res = P_CAN0_RX, .offset = 1}, + {.res = P_CAN0_TX, .offset = 1}, + {.res = P_SPI0_SSEL7, .offset = 1}, + {.res = P_SPORT0_TFS, .offset = 0}, + {.res = P_SPORT0_DTPRI, .offset = 0}, + {.res = P_SPI0_SSEL2, .offset = 0}, + {.res = P_SPI0_SSEL3, .offset = 0}, }; static void portmux_setup(unsigned short per, unsigned short function) { - u16 y, muxreg, offset; + u16 y, offset, muxreg; - for (y = 0; y < PMUX_LUT_ENTRIES; y++) { - if (port_mux_lut[y][PMUX_LUT_RES] == per) { + for (y = 0; y < ARRAY_SIZE(port_mux_lut); y++) { + if (port_mux_lut[y].res == per) { /* SET PORTMUX REG */ - offset = port_mux_lut[y][PMUX_LUT_OFFSET]; + offset = port_mux_lut[y].offset; muxreg = bfin_read_PORT_MUX(); if (offset != 1) { @@ -262,17 +291,18 @@ static void default_gpio(unsigned short gpio) static int __init bfin_gpio_init(void) { - - str_ident = kzalloc(RESOURCE_LABEL_SIZE * 256, GFP_KERNEL); - if (!str_ident) + str_ident = kcalloc(MAX_RESOURCES, + sizeof(struct str_ident), GFP_KERNEL); + if (str_ident == NULL) return -ENOMEM; + memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident)); + printk(KERN_INFO "Blackfin GPIO Controller\n"); return 0; } - arch_initcall(bfin_gpio_init); @@ -680,7 +710,7 @@ int peripheral_request(unsigned short per, const char *label) printk(KERN_ERR "%s: Peripheral %d function %d is already" - "reserved by %s !\n", + " reserved by %s !\n", __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident)); dump_stack(); diff --git a/arch/blackfin/mach-bf548/gpio.c b/arch/blackfin/mach-bf548/gpio.c index f3b9deacd332..390dd8c12430 100644 --- a/arch/blackfin/mach-bf548/gpio.c +++ b/arch/blackfin/mach-bf548/gpio.c @@ -49,9 +49,13 @@ static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; -char *str_ident = NULL; -#define RESOURCE_LABEL_SIZE 16 +#define MAX_RESOURCES 256 +#define RESOURCE_LABEL_SIZE 16 + +struct str_ident { + char name[RESOURCE_LABEL_SIZE]; +} *str_ident; inline int check_gpio(unsigned short gpio) { @@ -96,10 +100,13 @@ static void port_setup(unsigned short gpio, unsigned short usage) static int __init bfin_gpio_init(void) { - str_ident = kzalloc(RESOURCE_LABEL_SIZE * 256, GFP_KERNEL); - if (!str_ident) + str_ident = kcalloc(MAX_RESOURCES, + sizeof(struct str_ident), GFP_KERNEL); + if (str_ident == NULL) return -ENOMEM; + memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident)); + printk(KERN_INFO "Blackfin GPIO Controller\n"); return 0; @@ -111,10 +118,9 @@ static void set_label(unsigned short ident, const char *label) { if (label && str_ident) { - strncpy(str_ident + ident * RESOURCE_LABEL_SIZE, label, + strncpy(str_ident[ident].name, label, RESOURCE_LABEL_SIZE); - str_ident[ident * RESOURCE_LABEL_SIZE + - RESOURCE_LABEL_SIZE - 1] = 0; + str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; } } @@ -123,14 +129,13 @@ static char *get_label(unsigned short ident) if (!str_ident) return "UNKNOWN"; - return (str_ident[ident * RESOURCE_LABEL_SIZE] ? - (str_ident + ident * RESOURCE_LABEL_SIZE) : "UNKNOWN"); + return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); } static int cmp_label(unsigned short ident, const char *label) { if (label && str_ident) - return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE, + return strncmp(str_ident[ident].name, label, strlen(label)); else return -EINVAL; From b99ab54d4f11141b2ef3e50c3543b7243d3f49fb Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 11 Oct 2007 10:57:54 +0800 Subject: [PATCH 0022/2804] Blackfin serial driver: use new GPIO API Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- .../asm-blackfin/mach-bf548/bfin_serial_5xx.h | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h index 2f4afc90db11..f21a1620e6bd 100644 --- a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h +++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h @@ -1,5 +1,6 @@ #include #include +#include #define NR_PORTS 4 @@ -143,50 +144,48 @@ struct bfin_serial_res bfin_serial_resource[] = { int nr_ports = ARRAY_SIZE(bfin_serial_resource); +#define DRIVER_NAME "bfin-uart" + static void bfin_serial_hw_init(struct bfin_serial_port *uart) { #ifdef CONFIG_SERIAL_BFIN_UART0 - /* Enable UART0 RX and TX on pin 7 & 8 of PORT E */ - bfin_write_PORTE_FER(0x180 | bfin_read_PORTE_FER()); - bfin_write_PORTE_MUX(0x3C000 | bfin_read_PORTE_MUX()); + peripheral_request(P_UART0_TX, DRIVER_NAME); + peripheral_request(P_UART0_RX, DRIVER_NAME); #endif #ifdef CONFIG_SERIAL_BFIN_UART1 - /* Enable UART1 RX and TX on pin 0 & 1 of PORT H */ - bfin_write_PORTH_FER(0x3 | bfin_read_PORTH_FER()); - bfin_write_PORTH_MUX(~0xF & bfin_read_PORTH_MUX()); + peripheral_request(P_UART1_TX, DRIVER_NAME); + peripheral_request(P_UART1_RX, DRIVER_NAME); + #ifdef CONFIG_BFIN_UART1_CTSRTS - /* Enable UART1 RTS and CTS on pin 9 & 10 of PORT E */ - bfin_write_PORTE_FER(0x600 | bfin_read_PORTE_FER()); - bfin_write_PORTE_MUX(~0x3C0000 & bfin_read_PORTE_MUX()); + peripheral_request(P_UART1_RTS, DRIVER_NAME); + peripheral_request(P_UART1_CTS DRIVER_NAME); #endif #endif #ifdef CONFIG_SERIAL_BFIN_UART2 - /* Enable UART2 RX and TX on pin 4 & 5 of PORT B */ - bfin_write_PORTB_FER(0x30 | bfin_read_PORTB_FER()); - bfin_write_PORTB_MUX(~0xF00 & bfin_read_PORTB_MUX()); + peripheral_request(P_UART2_TX, DRIVER_NAME); + peripheral_request(P_UART2_RX, DRIVER_NAME); #endif #ifdef CONFIG_SERIAL_BFIN_UART3 - /* Enable UART3 RX and TX on pin 6 & 7 of PORT B */ - bfin_write_PORTB_FER(0xC0 | bfin_read_PORTB_FER()); - bfin_write_PORTB_MUX(~0xF000 | bfin_read_PORTB_MUX()); + peripheral_request(P_UART3_TX, DRIVER_NAME); + peripheral_request(P_UART3_RX, DRIVER_NAME); + #ifdef CONFIG_BFIN_UART3_CTSRTS - /* Enable UART3 RTS and CTS on pin 2 & 3 of PORT B */ - bfin_write_PORTB_FER(0xC | bfin_read_PORTB_FER()); - bfin_write_PORTB_MUX(~0xF0 | bfin_read_PORTB_MUX()); + peripheral_request(P_UART3_RTS, DRIVER_NAME); + peripheral_request(P_UART3_CTS DRIVER_NAME); #endif #endif SSYNC(); #ifdef CONFIG_SERIAL_BFIN_CTSRTS if (uart->cts_pin >= 0) { - gpio_request(uart->cts_pin, NULL); + gpio_request(uart->cts_pin, DRIVER_NAME); gpio_direction_input(uart->cts_pin); } if (uart->rts_pin >= 0) { - gpio_request(uart->rts_pin, NULL); + gpio_request(uart->rts_pin, DRIVER_NAME); gpio_direction_output(uart->rts_pin); } #endif From f16295e7e7f2a2a15876f570f10d6dc8f1f36ab8 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Fri, 3 Aug 2007 18:07:17 +0800 Subject: [PATCH 0023/2804] Blackfin arch: Fix CCLK and SCLK checks Fix CCLK and SCLK checks, combine all arch checks into one file for maintance. Checkins that remove more lines than they add are always good. Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 175 ++++++++++++++-------- arch/blackfin/mach-bf533/head.S | 1 + arch/blackfin/mach-bf537/head.S | 1 + arch/blackfin/mach-bf548/head.S | 1 + arch/blackfin/mach-bf561/head.S | 1 + arch/blackfin/mach-common/Makefile | 2 +- arch/blackfin/mach-common/arch_checks.c | 55 +++++++ arch/blackfin/mach-common/dpmc.S | 2 +- include/asm-blackfin/mach-bf533/bf533.h | 91 ----------- include/asm-blackfin/mach-bf537/bf537.h | 91 ----------- include/asm-blackfin/mach-bf548/bf548.h | 87 ----------- include/asm-blackfin/mach-bf561/bf561.h | 87 ----------- include/asm-blackfin/mach-common/clocks.h | 68 +++++++++ 13 files changed, 242 insertions(+), 420 deletions(-) create mode 100644 arch/blackfin/mach-common/arch_checks.c create mode 100644 include/asm-blackfin/mach-common/clocks.h diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 5c1e215c8b6f..9ce675e80260 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -323,7 +323,7 @@ config CMDLINE to the kernel, you may specify one here. As a minimum, you should specify the memory size and the root device (e.g., mem=8M, root=/dev/nfs). -comment "Board Setup" +comment "Clock/PLL Setup" config CLKIN_HZ int "Crystal Frequency in Hz" @@ -335,6 +335,118 @@ config CLKIN_HZ help The frequency of CLKIN crystal oscillator on the board in Hz. +config BFIN_KERNEL_CLOCK + bool "Re-program Clocks while Kernel boots?" + default n + help + This option decides if kernel clocks are re-programed from the + bootloader settings. If the clocks are not set, the SDRAM settings + are also not changed, and the Bootloader does 100% of the hardware + configuration. + +config PLL_BYPASS + bool "Bypass PLL" + depends on BFIN_KERNEL_CLOCK + default n + +config CLKIN_HALF + bool "Half Clock In" + depends on BFIN_KERNEL_CLOCK && (! PLL_BYPASS) + default n + help + If this is set the clock will be divided by 2, before it goes to the PLL. + +config VCO_MULT + int "VCO Multiplier" + depends on BFIN_KERNEL_CLOCK && (! PLL_BYPASS) + range 1 64 + default "22" if BFIN533_EZKIT + default "45" if BFIN533_STAMP + default "20" if BFIN537_STAMP + default "22" if BFIN533_BLUETECHNIX_CM + default "20" if BFIN537_BLUETECHNIX_CM + default "20" if BFIN561_BLUETECHNIX_CM + default "20" if BFIN561_EZKIT + help + This controls the frequency of the on-chip PLL. This can be between 1 and 64. + PLL Frequency = (Crystal Frequency) * (this setting) + +choice + prompt "Core Clock Divider" + depends on BFIN_KERNEL_CLOCK + default CCLK_DIV_1 + help + This sets the frequency of the core. It can be 1, 2, 4 or 8 + Core Frequency = (PLL frequency) / (this setting) + +config CCLK_DIV_1 + bool "1" + +config CCLK_DIV_2 + bool "2" + +config CCLK_DIV_4 + bool "4" + +config CCLK_DIV_8 + bool "8" +endchoice + +config SCLK_DIV + int "System Clock Divider" + depends on BFIN_KERNEL_CLOCK + range 1 15 + default 5 if BFIN533_EZKIT + default 5 if BFIN533_STAMP + default 4 if BFIN537_STAMP + default 5 if BFIN533_BLUETECHNIX_CM + default 4 if BFIN537_BLUETECHNIX_CM + default 4 if BFIN561_BLUETECHNIX_CM + default 5 if BFIN561_EZKIT + help + This sets the frequency of the system clock (including SDRAM or DDR). + This can be between 1 and 15 + System Clock = (PLL frequency) / (this setting) + +# +# Max & Min Speeds for various Chips +# +config MAX_VCO_HZ + int + default 600000000 if BF522 + default 600000000 if BF525 + default 600000000 if BF527 + default 400000000 if BF531 + default 400000000 if BF532 + default 750000000 if BF533 + default 500000000 if BF534 + default 400000000 if BF536 + default 600000000 if BF537 + default 533000000 if BF538 + default 533000000 if BF539 + default 600000000 if BF542 + default 533000000 if BF544 + default 533000000 if BF549 + default 600000000 if BF561 + +config MIN_VCO_HZ + int + default 50000000 + +config MAX_SCLK_HZ + int + default 133000000 + +config MIN_SCLK_HZ + int + default 27000000 + +comment "Kernel Timer/Scheduler" + +source kernel/Kconfig.hz + +comment "Memory Setup" + config MEM_SIZE int "SDRAM Memory Size in MBytes" default 32 if BFIN533_EZKIT @@ -448,10 +560,6 @@ endmenu menu "Blackfin Kernel Optimizations" -comment "Timer Tick" - -source kernel/Kconfig.hz - comment "Memory Optimizations" config I_ENTRY_L1 @@ -672,63 +780,6 @@ config L1_MAX_PIECE Set the max memory pieces for the L1 SRAM allocation algorithm. Min value is 16. Max value is 1024. -menu "Clock Settings" - - -config BFIN_KERNEL_CLOCK - bool "Re-program Clocks while Kernel boots?" - default n - help - This option decides if kernel clocks are re-programed from the - bootloader settings. If the clocks are not set, the SDRAM settings - are also not changed, and the Bootloader does 100% of the hardware - configuration. - -config VCO_MULT - int "VCO Multiplier" - depends on BFIN_KERNEL_CLOCK - default "22" if BFIN533_EZKIT - default "45" if BFIN533_STAMP - default "20" if BFIN537_STAMP - default "22" if BFIN533_BLUETECHNIX_CM - default "20" if BFIN537_BLUETECHNIX_CM - default "20" if BFIN561_BLUETECHNIX_CM - default "20" if BFIN561_EZKIT - -config CCLK_DIV - int "Core Clock Divider" - depends on BFIN_KERNEL_CLOCK - default 1 if BFIN533_EZKIT - default 1 if BFIN533_STAMP - default 1 if BFIN537_STAMP - default 1 if BFIN533_BLUETECHNIX_CM - default 1 if BFIN537_BLUETECHNIX_CM - default 1 if BFIN561_BLUETECHNIX_CM - default 1 if BFIN561_EZKIT - -config SCLK_DIV - int "System Clock Divider" - depends on BFIN_KERNEL_CLOCK - default 5 if BFIN533_EZKIT - default 5 if BFIN533_STAMP - default 4 if BFIN537_STAMP - default 5 if BFIN533_BLUETECHNIX_CM - default 4 if BFIN537_BLUETECHNIX_CM - default 4 if BFIN561_BLUETECHNIX_CM - default 5 if BFIN561_EZKIT - -config CLKIN_HALF - bool "Half ClockIn" - depends on BFIN_KERNEL_CLOCK - default n - -config PLL_BYPASS - bool "Bypass PLL" - depends on BFIN_KERNEL_CLOCK - default n - -endmenu - comment "Asynchonous Memory Configuration" menu "EBIU_AMBCTL Global Control" diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S index 69da0e8b7732..9c5378bb8a28 100644 --- a/arch/blackfin/mach-bf533/head.S +++ b/arch/blackfin/mach-bf533/head.S @@ -32,6 +32,7 @@ #include #include #if CONFIG_BFIN_KERNEL_CLOCK +#include #include #endif #if CONFIG_DEBUG_KERNEL_START diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S index b1d4b91b7aed..82ea04705917 100644 --- a/arch/blackfin/mach-bf537/head.S +++ b/arch/blackfin/mach-bf537/head.S @@ -33,6 +33,7 @@ #include #if CONFIG_BFIN_KERNEL_CLOCK +#include #include #endif diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S index 47cd91777a3b..72087c2e6a83 100644 --- a/arch/blackfin/mach-bf548/head.S +++ b/arch/blackfin/mach-bf548/head.S @@ -31,6 +31,7 @@ #include #include #if CONFIG_BFIN_KERNEL_CLOCK +#include #include #endif diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S index 173893429b04..83cd3f9bbf2d 100644 --- a/arch/blackfin/mach-bf561/head.S +++ b/arch/blackfin/mach-bf561/head.S @@ -33,6 +33,7 @@ #include #if CONFIG_BFIN_KERNEL_CLOCK +#include #include #endif diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile index 0279ede70392..4d7733dfd5de 100644 --- a/arch/blackfin/mach-common/Makefile +++ b/arch/blackfin/mach-common/Makefile @@ -4,7 +4,7 @@ obj-y := \ cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \ - interrupt.o lock.o irqpanic.o + interrupt.o lock.o irqpanic.o arch_checks.o obj-$(CONFIG_CPLB_INFO) += cplbinfo.o obj-$(CONFIG_BFIN_SINGLE_CORE) += ints-priority-sc.o diff --git a/arch/blackfin/mach-common/arch_checks.c b/arch/blackfin/mach-common/arch_checks.c new file mode 100644 index 000000000000..f9160d83b91f --- /dev/null +++ b/arch/blackfin/mach-common/arch_checks.c @@ -0,0 +1,55 @@ +/* + * File: arch/blackfin/mach-common/arch_checks.c + * Based on: + * Author: Robin Getz + * + * Created: 25Jul07 + * Description: Do some checking to make sure things are OK + * + * Modified: + * Copyright 2004-2007 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 + +#ifdef CONFIG_BFIN_KERNEL_CLOCK + +# if (CONFIG_VCO_HZ > CONFIG_MAX_VCO_HZ) +# error "VCO selected is more than maximum value. Please change the VCO multipler" +# endif + +# if (CONFIG_SCLK_HZ > CONFIG_MAX_SCLK_HZ) +# error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier" +# endif + +# if (CONFIG_SCLK_HZ < CONFIG_MIN_SCLK_HZ) +# error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier" +# endif + +# if (ANOMALY_05000273) && (CONFIG_SCLK_HZ * 2 > CONFIG_CCLK_HZ) +# error "ANOMALY 05000273, please make sure CCLK is at least 2x SCLK" +# endif + +# if (CONFIG_SCLK_HZ > CONFIG_CCLK_HZ) && (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ) && (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ) +# error "Please select sclk less than cclk" +# endif + +#endif /* CONFIG_BFIN_KERNEL_CLOCK */ diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S index 04194dca0151..39fbc2861107 100644 --- a/arch/blackfin/mach-common/dpmc.S +++ b/arch/blackfin/mach-common/dpmc.S @@ -300,7 +300,7 @@ ENTRY(_sleep_deeper) P0.H = hi(PLL_CTL); P0.L = lo(PLL_CTL); R5 = W[P0](z); - R0.L = (MIN_VC/CONFIG_CLKIN_HZ) << 9; + R0.L = (CONFIG_MIN_VCO_HZ/CONFIG_CLKIN_HZ) << 9; W[P0] = R0.l; SSYNC; diff --git a/include/asm-blackfin/mach-bf533/bf533.h b/include/asm-blackfin/mach-bf533/bf533.h index 41e4e834e2d3..cb210f6f7689 100644 --- a/include/asm-blackfin/mach-bf533/bf533.h +++ b/include/asm-blackfin/mach-bf533/bf533.h @@ -141,97 +141,6 @@ #define AMGCTLVAL (V_AMBEN | V_AMCKEN | V_CDPRIO) -#define MAX_VC 650000000 -#define MIN_VC 50000000 - -#ifdef CONFIG_BFIN_KERNEL_CLOCK -/********************************PLL Settings **************************************/ -#if (CONFIG_VCO_MULT < 0) -#error "VCO Multiplier is less than 0. Please select a different value" -#endif - -#if (CONFIG_VCO_MULT == 0) -#error "VCO Multiplier should be greater than 0. Please select a different value" -#endif - -#if (CONFIG_VCO_MULT > 64) -#error "VCO Multiplier is more than 64. Please select a different value" -#endif - -#ifndef CONFIG_CLKIN_HALF -#define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) -#else -#define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2) -#endif - -#ifndef CONFIG_PLL_BYPASS -#define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV) -#define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV) -#else -#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ -#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ -#endif - -#if (CONFIG_SCLK_DIV < 1) -#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value" -#endif - -#if (CONFIG_SCLK_DIV > 15) -#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value" -#endif - -#if (CONFIG_CCLK_DIV != 1) -#if (CONFIG_CCLK_DIV != 2) -#if (CONFIG_CCLK_DIV != 4) -#if (CONFIG_CCLK_DIV != 8) -#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value" -#endif -#endif -#endif -#endif - -#if (CONFIG_VCO_HZ > MAX_VC) -#error "VCO selected is more than maximum value. Please change the VCO multipler" -#endif - -#if (CONFIG_SCLK_HZ > 133000000) -#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier" -#endif - -#if (CONFIG_SCLK_HZ < 27000000) -#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier" -#endif - -#if (CONFIG_SCLK_HZ > CONFIG_CCLK_HZ) -#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ) -#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ) -#error "Please select sclk less than cclk" -#endif -#endif -#endif - -#if (CONFIG_CCLK_DIV == 1) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 -#endif -#if (CONFIG_CCLK_DIV == 2) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 -#endif -#if (CONFIG_CCLK_DIV == 4) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 -#endif -#if (CONFIG_CCLK_DIV == 8) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 -#endif -#ifndef CONFIG_CCLK_ACT_DIV -#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly -#endif - -#if ANOMALY_05000273 && (CONFIG_CCLK_DIV == 1) -#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK -#endif - -#endif /* CONFIG_BFIN_KERNEL_CLOCK */ - #ifdef CONFIG_BF533 #define CPU "BF533" #define CPUID 0x027a5000 diff --git a/include/asm-blackfin/mach-bf537/bf537.h b/include/asm-blackfin/mach-bf537/bf537.h index 04b08164e292..603823f51ca0 100644 --- a/include/asm-blackfin/mach-bf537/bf537.h +++ b/include/asm-blackfin/mach-bf537/bf537.h @@ -121,97 +121,6 @@ #define AMGCTLVAL (V_AMBEN | V_AMCKEN | V_CDPRIO) -#define MAX_VC 650000000 -#define MIN_VC 50000000 - -/********************************PLL Settings **************************************/ -#ifdef CONFIG_BFIN_KERNEL_CLOCK -#if (CONFIG_VCO_MULT < 0) -#error "VCO Multiplier is less than 0. Please select a different value" -#endif - -#if (CONFIG_VCO_MULT == 0) -#error "VCO Multiplier should be greater than 0. Please select a different value" -#endif - -#if (CONFIG_VCO_MULT > 64) -#error "VCO Multiplier is more than 64. Please select a different value" -#endif - -#ifndef CONFIG_CLKIN_HALF -#define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) -#else -#define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2) -#endif - -#ifndef CONFIG_PLL_BYPASS -#define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV) -#define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV) -#else -#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ -#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ -#endif - -#if (CONFIG_SCLK_DIV < 1) -#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value" -#endif - -#if (CONFIG_SCLK_DIV > 15) -#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value" -#endif - -#if (CONFIG_CCLK_DIV != 1) -#if (CONFIG_CCLK_DIV != 2) -#if (CONFIG_CCLK_DIV != 4) -#if (CONFIG_CCLK_DIV != 8) -#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value" -#endif -#endif -#endif -#endif - -#if (CONFIG_VCO_HZ > MAX_VC) -#error "VCO selected is more than maximum value. Please change the VCO multipler" -#endif - -#if (CONFIG_SCLK_HZ > 133000000) -#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier" -#endif - -#if (CONFIG_SCLK_HZ < 27000000) -#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier" -#endif - -#if (CONFIG_SCLK_HZ >= CONFIG_CCLK_HZ) -#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ) -#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ) -#error "Please select sclk less than cclk" -#endif -#endif -#endif - -#if (CONFIG_CCLK_DIV == 1) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 -#endif -#if (CONFIG_CCLK_DIV == 2) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 -#endif -#if (CONFIG_CCLK_DIV == 4) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 -#endif -#if (CONFIG_CCLK_DIV == 8) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 -#endif -#ifndef CONFIG_CCLK_ACT_DIV -#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly -#endif - -#if ANOMALY_05000273 && (CONFIG_CCLK_DIV == 1) -#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK -#endif - -#endif /* CONFIG_BFIN_KERNEL_CLOCK */ - #ifdef CONFIG_BF537 #define CPU "BF537" #define CPUID 0x027c8000 diff --git a/include/asm-blackfin/mach-bf548/bf548.h b/include/asm-blackfin/mach-bf548/bf548.h index 9498313a2cb7..50306a846628 100644 --- a/include/asm-blackfin/mach-bf548/bf548.h +++ b/include/asm-blackfin/mach-bf548/bf548.h @@ -106,93 +106,6 @@ #define AMGCTLVAL (V_AMBEN | V_AMCKEN) -#define MAX_VC 650000000 -#define MIN_VC 50000000 - -/********************************PLL Settings **************************************/ -#ifdef CONFIG_BFIN_KERNEL_CLOCK -#if (CONFIG_VCO_MULT < 0) -#error "VCO Multiplier is less than 0. Please select a different value" -#endif - -#if (CONFIG_VCO_MULT == 0) -#error "VCO Multiplier should be greater than 0. Please select a different value" -#endif - -#if (CONFIG_VCO_MULT > 64) -#error "VCO Multiplier is more than 64. Please select a different value" -#endif - -#ifndef CONFIG_CLKIN_HALF -#define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) -#else -#define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2) -#endif - -#ifndef CONFIG_PLL_BYPASS -#define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV) -#define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV) -#else -#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ -#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ -#endif - -#if (CONFIG_SCLK_DIV < 1) -#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value" -#endif - -#if (CONFIG_SCLK_DIV > 15) -#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value" -#endif - -#if (CONFIG_CCLK_DIV != 1) -#if (CONFIG_CCLK_DIV != 2) -#if (CONFIG_CCLK_DIV != 4) -#if (CONFIG_CCLK_DIV != 8) -#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value" -#endif -#endif -#endif -#endif - -#if (CONFIG_VCO_HZ > MAX_VC) -#error "VCO selected is more than maximum value. Please change the VCO multipler" -#endif - -#if (CONFIG_SCLK_HZ > 133000000) -#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier" -#endif - -#if (CONFIG_SCLK_HZ < 27000000) -#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier" -#endif - -#if (CONFIG_SCLK_HZ >= CONFIG_CCLK_HZ) -#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ) -#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ) -#error "Please select sclk less than cclk" -#endif -#endif -#endif - -#if (CONFIG_CCLK_DIV == 1) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 -#endif -#if (CONFIG_CCLK_DIV == 2) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 -#endif -#if (CONFIG_CCLK_DIV == 4) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 -#endif -#if (CONFIG_CCLK_DIV == 8) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 -#endif -#ifndef CONFIG_CCLK_ACT_DIV -#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly -#endif - -#endif /* CONFIG_BFIN_KERNEL_CLOCK */ - #ifdef CONFIG_BF542 #define CPU "BF542" #define CPUID 0x027c8000 diff --git a/include/asm-blackfin/mach-bf561/bf561.h b/include/asm-blackfin/mach-bf561/bf561.h index 8cc2e0033e0a..53b650f31342 100644 --- a/include/asm-blackfin/mach-bf561/bf561.h +++ b/include/asm-blackfin/mach-bf561/bf561.h @@ -230,93 +230,6 @@ #define AMGCTLVAL (V_AMBEN | V_AMCKEN | V_CDPRIO | V_B0PEN | V_B1PEN | V_B2PEN | V_B3PEN | 0x0002) -#define MAX_VC 600000000 -#define MIN_VC 50000000 - -/******************************* PLL Settings ********************************/ -#ifdef CONFIG_BFIN_KERNEL_CLOCK -#if (CONFIG_VCO_MULT < 0) -#error "VCO Multiplier is less than 0. Please select a different value" -#endif - -#if (CONFIG_VCO_MULT == 0) -#error "VCO Multiplier should be greater than 0. Please select a different value" -#endif - -#ifndef CONFIG_CLKIN_HALF -#define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) -#else -#define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2) -#endif - -#ifndef CONFIG_PLL_BYPASS -#define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV) -#define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV) -#else -#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ -#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ -#endif - -#if (CONFIG_SCLK_DIV < 1) -#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value" -#endif - -#if (CONFIG_SCLK_DIV > 15) -#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value" -#endif - -#if (CONFIG_CCLK_DIV != 1) -#if (CONFIG_CCLK_DIV != 2) -#if (CONFIG_CCLK_DIV != 4) -#if (CONFIG_CCLK_DIV != 8) -#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value" -#endif -#endif -#endif -#endif - -#if (CONFIG_VCO_HZ > MAX_VC) -#error "VCO selected is more than maximum value. Please change the VCO multipler" -#endif - -#if (CONFIG_SCLK_HZ > 133000000) -#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier" -#endif - -#if (CONFIG_SCLK_HZ < 27000000) -#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier" -#endif - -#if (CONFIG_SCLK_HZ >= CONFIG_CCLK_HZ) -#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ) -#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ) -#error "Please select sclk less than cclk" -#endif -#endif -#endif - -#if (CONFIG_CCLK_DIV == 1) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 -#endif -#if (CONFIG_CCLK_DIV == 2) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 -#endif -#if (CONFIG_CCLK_DIV == 4) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 -#endif -#if (CONFIG_CCLK_DIV == 8) -#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 -#endif -#ifndef CONFIG_CCLK_ACT_DIV -#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly -#endif - -#if ANOMALY_05000273 && (CONFIG_CCLK_DIV == 1) -#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK -#endif - -#endif /* CONFIG_BFIN_KERNEL_CLOCK */ - #ifdef CONFIG_BF561 #define CPU "BF561" #define CPUID 0x027bb000 diff --git a/include/asm-blackfin/mach-common/clocks.h b/include/asm-blackfin/mach-common/clocks.h new file mode 100644 index 000000000000..5e8113ee8939 --- /dev/null +++ b/include/asm-blackfin/mach-common/clocks.h @@ -0,0 +1,68 @@ +/* + * File: include/asm-blackfin/mach-common/clocks.h + * Based on: include/asm-blackfin/mach-bf537/bf537.h + * Author: Robin Getz + * + * Created: 25Jul07 + * Description: Common Clock definitions for various kernel files + * + * Modified: + * Copyright 2004-2007 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 + */ + + + +#ifdef CONFIG_CCLK_DIV_1 +# define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +# define CONFIG_CCLK_DIV 1 +#endif + +#ifdef CONFIG_CCLK_DIV_2 +# define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +# define CONFIG_CCLK_DIV 2 +#endif + +#ifdef CONFIG_CCLK_DIV_4 +# define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +# define CONFIG_CCLK_DIV 4 +#endif + +#ifdef CONFIG_CCLK_DIV_8 +# define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +# define CONFIG_CCLK_DIV 8 +#endif + +#ifndef CONFIG_PLL_BYPASS +# ifndef CONFIG_CLKIN_HALF +# define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) +# else +# define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2) +# endif + +# define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV) +# define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV) + +#else +# define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ) +# define CONFIG_CCLK_HZ (CONFIG_CLKIN_HZ) +# define CONFIG_SCLK_HZ (CONFIG_CLKIN_HZ) +# define CONFIG_VCO_MULT 0 +#endif + From 518039bc24cbb9ce34665814fe120eac50bedd9a Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 25 Jul 2007 11:03:28 +0800 Subject: [PATCH 0024/2804] Blackfin arch: Add ability to expend the hardware trace buffer Add ability to expend the hardware trace buffer via a configurable software buffer - so you can have lots of history when a crash occurs. The interesting way we do printk in the traps.c confusese the checking script Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 81 +++++++++++++++++++++++++++++++ arch/blackfin/kernel/irqchip.c | 9 ++++ arch/blackfin/kernel/traps.c | 53 +++++++++++++++++--- arch/blackfin/mach-bf533/head.S | 2 +- arch/blackfin/mach-bf537/head.S | 2 +- arch/blackfin/mach-bf548/head.S | 2 +- arch/blackfin/mach-bf561/head.S | 2 +- arch/blackfin/mach-common/entry.S | 73 ++++++++++++++++++++++++++++ include/asm-blackfin/trace.h | 55 +++++++++++++++++---- 9 files changed, 259 insertions(+), 20 deletions(-) diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 9ce675e80260..a7a6e0c5827d 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -1024,8 +1024,89 @@ config DEBUG_HUNT_FOR_ZERO Enabling this option will take up an extra entry in CPLB table. Otherwise, there is no extra overhead. +config DEBUG_BFIN_HWTRACE_ON + bool "Turn on Blackfin's Hardware Trace" + default y + help + All Blackfins include a Trace Unit which stores a history of the last + 16 changes in program flow taken by the program sequencer. The history + allows the user to recreate the program sequencerโ€™s recent path. This + can be handy when an application dies - we print out the execution + path of how it got to the offending instruction. + + By turning this off, you may save a tiny amount of power. + +choice + prompt "Omit loop Tracing" + default DEBUG_BFIN_HWTRACE_COMPRESSION_OFF + depends on DEBUG_BFIN_HWTRACE_ON + help + The trace buffer can be configured to omit recording of changes in + program flow that match either the last entry or one of the last + two entries. Omitting one of these entries from the record prevents + the trace buffer from overflowing because of any sort of loop (for, do + while, etc) in the program. + + Because zero-overhead Hardware loops are not recorded in the trace buffer, + this feature can be used to prevent trace overflow from loops that + are nested four deep. + +config DEBUG_BFIN_HWTRACE_COMPRESSION_OFF + bool "Trace all Loops" + help + The trace buffer records all changes of flow + +config DEBUG_BFIN_HWTRACE_COMPRESSION_ONE + bool "Compress single-level loops" + help + The trace buffer does not record single loops - helpful if trace + is spinning on a while or do loop. + +config DEBUG_BFIN_HWTRACE_COMPRESSION_TWO + bool "Compress two-level loops" + help + The trace buffer does not record loops two levels deep. Helpful if + the trace is spinning in a nested loop + +endchoice + +config DEBUG_BFIN_HWTRACE_COMPRESSION + int + depends on DEBUG_BFIN_HWTRACE_ON + default 0 if DEBUG_BFIN_HWTRACE_COMPRESSION_OFF + default 1 if DEBUG_BFIN_HWTRACE_COMPRESSION_ONE + default 2 if DEBUG_BFIN_HWTRACE_COMPRESSION_TWO + + +config DEBUG_BFIN_HWTRACE_EXPAND + bool "Expand Trace Buffer greater than 16 entries" + depends on DEBUG_BFIN_HWTRACE_ON + default n + help + By selecting this option, every time the 16 hardware entries in + the Blackfin's HW Trace buffer are full, the kernel will move them + into a software buffer, for dumping when there is an issue. This + has a great impact on performance, (an interrupt every 16 change of + flows) and should normally be turned off, except in those nasty + debugging sessions + +config DEBUG_BFIN_HWTRACE_EXPAND_LEN + int "Size of Trace buffer (in power of 2k)" + range 0 4 + depends on DEBUG_BFIN_HWTRACE_EXPAND + default 1 + help + This sets the size of the software buffer that the trace information + is kept in. + 0 for (2^0) 1k, or 256 entries, + 1 for (2^1) 2k, or 512 entries, + 2 for (2^2) 4k, or 1024 entries, + 3 for (2^3) 8k, or 2048 entries, + 4 for (2^4) 16k, or 4096 entries + config DEBUG_BFIN_NO_KERN_HWTRACE bool "Trace user apps (turn off hwtrace in kernel)" + depends on DEBUG_BFIN_HWTRACE_ON default n help Some pieces of the kernel contain a lot of flow changes which can diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c index 1fc001c7abda..462ae41144c7 100644 --- a/arch/blackfin/kernel/irqchip.c +++ b/arch/blackfin/kernel/irqchip.c @@ -34,6 +34,7 @@ #include #include #include +#include static unsigned long irq_err_count; static spinlock_t irq_controller_lock; @@ -144,4 +145,12 @@ void __init init_IRQ(void) } init_arch_irq(); + +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND + /* Now that evt_ivhw is set up, turn this on */ + trace_buff_offset = 0; + bfin_write_TBUFCTL(BFIN_TRACE_ON); + printk(KERN_INFO "Hardware Trace expanded to %ik\n", + 1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN); +#endif } diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 792a8416fe10..0ec02fe663e9 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -55,6 +55,7 @@ asmlinkage void trap_c(struct pt_regs *fp); int kstack_depth_to_print = 48; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON static int printk_address(unsigned long address) { struct vm_list_struct *vml; @@ -131,10 +132,14 @@ static int printk_address(unsigned long address) /* we were unable to find this address anywhere */ return printk("[<0x%p>]", (void *)address); } +#endif asmlinkage void trap_c(struct pt_regs *fp) { - int j, sig = 0; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON + int j; +#endif + int sig = 0; siginfo_t info; unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; @@ -429,24 +434,56 @@ asmlinkage void trap_c(struct pt_regs *fp) /* Typical exception handling routines */ +#define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1) + void dump_bfin_trace_buffer(void) { - int tflags; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON + int tflags, i = 0; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND + int j, index; +#endif + trace_buffer_save(tflags); + printk(KERN_EMERG "Hardware Trace:\n"); + if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { - int i; - printk(KERN_EMERG "Hardware Trace:\n"); - for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) { - printk(KERN_EMERG "%2i Target : ", i); + for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) { + printk(KERN_EMERG "%4i Target : ", i); printk_address((unsigned long)bfin_read_TBUF()); - printk("\n" KERN_EMERG " Source : "); + printk("\n" KERN_EMERG " Source : "); printk_address((unsigned long)bfin_read_TBUF()); printk("\n"); } } +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND + if (trace_buff_offset) + index = trace_buff_offset/4 - 1; + else + index = EXPAND_LEN; + + j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128; + while (j) { + printk(KERN_EMERG "%4i Target : ", i); + printk_address(software_trace_buff[index]); + index -= 1; + if (index < 0 ) + index = EXPAND_LEN; + printk("\n" KERN_EMERG " Source : "); + printk_address(software_trace_buff[index]); + index -= 1; + if (index < 0) + index = EXPAND_LEN; + printk("\n"); + j--; + i++; + } +#endif + trace_buffer_restore(tflags); +#endif } EXPORT_SYMBOL(dump_bfin_trace_buffer); @@ -510,7 +547,9 @@ void show_stack(struct task_struct *task, unsigned long *stack) void dump_stack(void) { unsigned long stack; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON int tflags; +#endif trace_buffer_save(tflags); dump_bfin_trace_buffer(); show_stack(current, &stack); diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S index 9c5378bb8a28..1d5b9dbbbaa7 100644 --- a/arch/blackfin/mach-bf533/head.S +++ b/arch/blackfin/mach-bf533/head.S @@ -98,7 +98,7 @@ ENTRY(__start) M2 = r0; M3 = r0; - trace_buffer_start(p0,r0); + trace_buffer_init(p0,r0); P0 = R1; R0 = R1; diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S index 82ea04705917..6dbcb77c8d36 100644 --- a/arch/blackfin/mach-bf537/head.S +++ b/arch/blackfin/mach-bf537/head.S @@ -96,7 +96,7 @@ ENTRY(__start) M2 = r0; M3 = r0; - trace_buffer_start(p0,r0); + trace_buffer_init(p0,r0); P0 = R1; R0 = R1; diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S index 72087c2e6a83..e53d74d4c0a2 100644 --- a/arch/blackfin/mach-bf548/head.S +++ b/arch/blackfin/mach-bf548/head.S @@ -93,7 +93,7 @@ ENTRY(__stext) M2 = r0; M3 = r0; - trace_buffer_start(p0,r0); + trace_buffer_init(p0,r0); P0 = R1; R0 = R1; diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S index 83cd3f9bbf2d..8c9f73b8e579 100644 --- a/arch/blackfin/mach-bf561/head.S +++ b/arch/blackfin/mach-bf561/head.S @@ -96,7 +96,7 @@ ENTRY(__start) M2 = r0; M3 = r0; - trace_buffer_start(p0,r0); + trace_buffer_init(p0,r0); P0 = R1; R0 = R1; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 207e69786b40..ab278a72f282 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -731,6 +731,75 @@ ENTRY(_init_exception_buff) rts; ENDPROC(_init_exception_buff) +/* We handle this 100% in exception space - to reduce overhead + * Only potiential problem is if the software buffer gets swapped out of the + * CPLB table - then double fault. - so we don't let this happen in other places + */ +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND +ENTRY(_ex_trace_buff_full) + [--sp] = P3; + [--sp] = P2; + [--sp] = LC0; + [--sp] = LT0; + [--sp] = LB0; + P5.L = _trace_buff_offset; + P5.H = _trace_buff_offset; + P3 = [P5]; /* trace_buff_offset */ + P5.L = lo(TBUFSTAT); + P5.H = hi(TBUFSTAT); + R7 = [P5]; + R7 <<= 1; /* double, since we need to read twice */ + LC0 = R7; + R7 <<= 2; /* need to shift over again, + * to get the number of bytes */ + P5.L = lo(TBUF); + P5.H = hi(TBUF); + R6 = ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*1024) - 1; + + P2 = R7; + P3 = P3 + P2; + R7 = P3; + R7 = R7 & R6; + P3 = R7; + P2.L = _trace_buff_offset; + P2.H = _trace_buff_offset; + [P2] = P3; + + P2.L = _software_trace_buff; + P2.H = _software_trace_buff; + + LSETUP (.Lstart, .Lend) LC0; +.Lstart: + R7 = [P5]; /* read TBUF */ + P4 = P3 + P2; + [P4] = R7; + P3 += -4; + R7 = P3; + R7 = R7 & R6; +.Lend: + P3 = R7; + + LB0 = [sp++]; + LT0 = [sp++]; + LC0 = [sp++]; + P2 = [sp++]; + P3 = [sp++]; + jump _return_from_exception; + +#if CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN == 4 +.data +#else +.section .l1.data.B +#endif +ENTRY(_trace_buff_offset) + .long 0; +ALIGN +ENTRY(_software_trace_buff) + .rept ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*256); + .long 0 + .endr +#endif + /* * Put these in the kernel data section - that should always be covered by * a CPLB. This is needed to ensure we don't get double fault conditions @@ -764,7 +833,11 @@ _extable: .long _ex_trap_c /* 0x0E - User Defined */ .long _ex_trap_c /* 0x0F - User Defined */ .long _ex_single_step /* 0x10 - HW Single step */ +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND + .long _ex_trace_buff_full /* 0x11 - Trace Buffer Full */ +#else .long _ex_trap_c /* 0x11 - Trace Buffer Full */ +#endif .long _ex_trap_c /* 0x12 - Reserved */ .long _ex_trap_c /* 0x13 - Reserved */ .long _ex_trap_c /* 0x14 - Reserved */ diff --git a/include/asm-blackfin/trace.h b/include/asm-blackfin/trace.h index 9c2474c9a589..6313aace9d59 100644 --- a/include/asm-blackfin/trace.h +++ b/include/asm-blackfin/trace.h @@ -6,23 +6,46 @@ #ifndef _BLACKFIN_TRACE_ #define _BLACKFIN_TRACE_ +/* Normally, we use ON, but you can't turn on software expansion until + * interrupts subsystem is ready + */ + +#define BFIN_TRACE_INIT ((CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION << 4) | 0x03) +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND +#define BFIN_TRACE_ON (BFIN_TRACE_INIT | (CONFIG_DEBUG_BFIN_HWTRACE_EXPAND << 2)) +#else +#define BFIN_TRACE_ON (BFIN_TRACE_INIT) +#endif + #ifndef __ASSEMBLY__ +extern unsigned long trace_buff_offset; +extern unsigned long software_trace_buff[]; + /* Trace Macros for C files */ +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON + #define trace_buffer_save(x) \ - do { \ - (x) = bfin_read_TBUFCTL(); \ - bfin_write_TBUFCTL((x) & ~TBUFEN); \ - } while (0) + do { \ + (x) = bfin_read_TBUFCTL(); \ + bfin_write_TBUFCTL((x) & ~TBUFEN); \ + } while (0) #define trace_buffer_restore(x) \ - do { \ - bfin_write_TBUFCTL((x)); \ - } while (0) + do { \ + bfin_write_TBUFCTL((x)); \ + } while (0) +#else /* DEBUG_BFIN_HWTRACE_ON */ + +#define trace_buffer_save(x) +#define trace_buffer_restore(x) +#endif /* CONFIG_DEBUG_BFIN_HWTRACE_ON */ #else /* Trace Macros for Assembly files */ +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON + #define TRACE_BUFFER_START(preg, dreg) trace_buffer_start(preg, dreg) #define TRACE_BUFFER_STOP(preg, dreg) trace_buffer_stop(preg, dreg) @@ -32,12 +55,26 @@ dreg = 0x1; \ [preg] = dreg; -#define trace_buffer_start(preg, dreg) \ +#define trace_buffer_start(preg, dreg) \ preg.L = LO(TBUFCTL); \ preg.H = HI(TBUFCTL); \ - dreg = 0x13; \ + dreg = BFIN_TRACE_ON; \ [preg] = dreg; +#define trace_buffer_init(preg, dreg) \ + preg.L = LO(TBUFCTL); \ + preg.H = HI(TBUFCTL); \ + dreg = BFIN_TRACE_INIT; \ + [preg] = dreg; + +#else /* CONFIG_DEBUG_BFIN_HWTRACE_ON */ + +#define trace_buffer_stop(preg, dreg) +#define trace_buffer_start(preg, dreg) +#define trace_buffer_init(preg, dreg) + +#endif /* CONFIG_DEBUG_BFIN_HWTRACE_ON */ + #ifdef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE # define DEBUG_START_HWTRACE(preg, dreg) trace_buffer_start(preg, dreg) # define DEBUG_STOP_HWTRACE(preg, dreg) trace_buffer_stop(preg, dreg) From 1d945e2b3e421f2ce01b2eb260392f888406933f Mon Sep 17 00:00:00 2001 From: Roy Huang Date: Wed, 10 Oct 2007 23:31:19 +0800 Subject: [PATCH 0025/2804] Blackfin arch: add set_dma_curr_addr DMA API to support sound driver recording function Signed-off-by: Roy Huang Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_dma_5xx.c | 10 ++++++++++ include/asm-blackfin/dma.h | 1 + 2 files changed, 11 insertions(+) diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 7cf02f02a1db..7e2201908356 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -345,6 +345,16 @@ void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg) } EXPORT_SYMBOL(set_dma_sg); +void set_dma_curr_addr(unsigned int channel, unsigned long addr) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->curr_addr_ptr = addr; + SSYNC(); +} +EXPORT_SYMBOL(set_dma_curr_addr); + /*------------------------------------------------------------------------------ * Get the DMA status of a specific DMA channel from the system. *-----------------------------------------------------------------------------*/ diff --git a/include/asm-blackfin/dma.h b/include/asm-blackfin/dma.h index be0d913e5516..4269082b154a 100644 --- a/include/asm-blackfin/dma.h +++ b/include/asm-blackfin/dma.h @@ -159,6 +159,7 @@ void set_dma_y_modify(unsigned int channel, short y_modify); void set_dma_config(unsigned int channel, unsigned short config); unsigned short set_bfin_dma_config(char direction, char flow_mode, char intr_mode, char dma_mode, char width); +void set_dma_curr_addr(unsigned int channel, unsigned long addr); /* get curr status for polling */ unsigned short get_dma_curr_irqstat(unsigned int channel); From 7735cefc4583175486685fced2f457fbe0fd5855 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Sun, 5 Aug 2007 18:55:30 +0800 Subject: [PATCH 0026/2804] Blackfin arch: Add support for the M25P16 SPI FLash Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/mach-bf548/head.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S index e53d74d4c0a2..4c7d49f41187 100644 --- a/arch/blackfin/mach-bf548/head.S +++ b/arch/blackfin/mach-bf548/head.S @@ -379,6 +379,7 @@ ENTRY(_bfin_reset) CLI R6; SSYNC; +#if 0 /* Need to determine later if this is here necessary for BF54x */ #if defined(CONFIG_MTD_M25P80) /* * The following code fix the SPI flash reboot issue, @@ -413,6 +414,7 @@ _delay_lab0_end: nop; _delay_lab1_end: nop; +#endif #endif /* Clear the bits 13-15 in SWRST if they werent cleared */ From a924db7c00655447c5228bd74da070c69b7cadbc Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 3 Aug 2007 17:43:29 +0800 Subject: [PATCH 0027/2804] Blackfin arch: Add option to priorize DMA over Core Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_dma_5xx.c | 5 +++++ arch/blackfin/mach-bf548/Kconfig | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 7e2201908356..62f5a35c13ee 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -73,6 +73,11 @@ static int __init blackfin_dma_init(void) /* Mark MEMDMA Channel 0 as requested since we're using it internally */ dma_ch[CH_MEM_STREAM0_DEST].chan_status = DMA_CHANNEL_REQUESTED; dma_ch[CH_MEM_STREAM0_SRC].chan_status = DMA_CHANNEL_REQUESTED; + +#if defined(CONFIG_DEB_DMA_URGENT) + bfin_write_EBIU_DDRQUE(bfin_read_EBIU_DDRQUE() + | DEB1_URGENT | DEB2_URGENT | DEB3_URGENT); +#endif return 0; } diff --git a/arch/blackfin/mach-bf548/Kconfig b/arch/blackfin/mach-bf548/Kconfig index 3976b7f523c3..08d8dc83701c 100644 --- a/arch/blackfin/mach-bf548/Kconfig +++ b/arch/blackfin/mach-bf548/Kconfig @@ -2,6 +2,13 @@ if (BF54x) menu "BF548 Specific Configuration" +config DEB_DMA_URGENT + bool "DMA has priority over core for ext. accesses" + depends on BF54x + default n + help + Treat any DEB1, DEB2 and DEB3 request as Urgent + comment "Interrupt Priority Assignment" menu "Priority" From a298049180d2c56fc8ac1796b24973bf4f019cc7 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 3 Aug 2007 18:29:15 +0800 Subject: [PATCH 0028/2804] Blackfin arch: remove unused code -- EVT0 is not controllable by software Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/mach-common/interrupt.S | 24 -------------------- arch/blackfin/mach-common/ints-priority-dc.c | 3 --- arch/blackfin/mach-common/ints-priority-sc.c | 3 --- include/asm-blackfin/irq_handler.h | 1 - 4 files changed, 31 deletions(-) diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 14ef800a564d..1d5ba5e3d91c 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -46,30 +46,6 @@ .align 4 /* just in case */ -/* - * initial interrupt handlers - */ - -#ifndef CONFIG_KGDB - /* interrupt routine for emulation - 0 */ - /* Currently used only if GDB stub is not in - invalid */ - /* gdb-stub set the evt itself */ - /* save registers for post-mortem only */ -ENTRY(_evt_emulation) - SAVE_ALL_SYS -#ifdef CONFIG_FRAME_POINTER - fp = 0; -#endif - r0 = IRQ_EMU; - r1 = sp; - SP += -12; - call _irq_panic; - SP += 12; - /* - GDB stub fills this in by itself (if defined) */ - rte; -ENDPROC(_evt_emulation) -#endif - /* Common interrupt entry code. First we do CLI, then push * RETI, to keep interrupts disabled, but to allow this state to be changed * by local_bh_enable. diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c index d5d9e57813dd..684d306ab6bb 100644 --- a/arch/blackfin/mach-common/ints-priority-dc.c +++ b/arch/blackfin/mach-common/ints-priority-dc.c @@ -362,9 +362,6 @@ void __init init_exception_vectors(void) { SSYNC(); -#ifndef CONFIG_KGDB - bfin_write_EVT0(evt_emulation); -#endif bfin_write_EVT2(evt_evt2); bfin_write_EVT3(trap); bfin_write_EVT5(evt_ivhw); diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c index 505b9484497a..a2016af65eb0 100644 --- a/arch/blackfin/mach-common/ints-priority-sc.c +++ b/arch/blackfin/mach-common/ints-priority-sc.c @@ -721,9 +721,6 @@ void __init init_exception_vectors(void) { SSYNC(); -#ifndef CONFIG_KGDB - bfin_write_EVT0(evt_emulation); -#endif bfin_write_EVT2(evt_evt2); bfin_write_EVT3(trap); bfin_write_EVT5(evt_ivhw); diff --git a/include/asm-blackfin/irq_handler.h b/include/asm-blackfin/irq_handler.h index d830f0a49a1c..6a768315bbf7 100644 --- a/include/asm-blackfin/irq_handler.h +++ b/include/asm-blackfin/irq_handler.h @@ -2,7 +2,6 @@ #define _IRQ_HANDLER_H /* BASE LEVEL interrupt handler routines */ -asmlinkage void evt_emulation(void); asmlinkage void evt_exception(void); asmlinkage void trap(void); asmlinkage void evt_ivhw(void); From 3bebca2d20796dd3dc62c5d3e74148087c7ce5bd Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 10 Oct 2007 23:55:26 +0800 Subject: [PATCH 0029/2804] Blackfin arch: to do some consolidation of common code and common name spaces now all BLKFIN should be BFIN, should be no functional changes. Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 20 ++-- arch/blackfin/configs/BF533-EZKIT_defconfig | 12 +-- arch/blackfin/configs/BF533-STAMP_defconfig | 12 +-- arch/blackfin/configs/BF537-STAMP_defconfig | 12 +-- arch/blackfin/configs/BF548-EZKIT_defconfig | 12 +-- arch/blackfin/configs/BF561-EZKIT_defconfig | 12 +-- arch/blackfin/configs/PNAV-10_defconfig | 12 +-- arch/blackfin/kernel/cacheinit.c | 5 +- arch/blackfin/kernel/cplbinit.c | 5 +- arch/blackfin/kernel/process.c | 2 +- arch/blackfin/kernel/setup.c | 29 +++--- arch/blackfin/mach-common/arch_checks.c | 5 + arch/blackfin/mach-common/cacheinit.S | 8 +- arch/blackfin/mach-common/cplbhdlr.S | 8 +- arch/blackfin/mach-common/cplbmgr.S | 2 +- arch/blackfin/mach-common/lock.S | 4 +- include/asm-blackfin/cacheflush.h | 14 +-- include/asm-blackfin/cplb.h | 89 ++++++++++++++++-- include/asm-blackfin/mach-bf533/bf533.h | 16 ++-- include/asm-blackfin/mach-bf533/mem_map.h | 56 ++++++------ include/asm-blackfin/mach-bf537/anomaly.h | 1 + include/asm-blackfin/mach-bf537/bf537.h | 67 ++------------ include/asm-blackfin/mach-bf537/mem_map.h | 60 ++++++------ include/asm-blackfin/mach-bf548/bf548.h | 67 ++------------ include/asm-blackfin/mach-bf548/mem_map.h | 24 ++--- include/asm-blackfin/mach-bf561/bf561.h | 91 ++----------------- include/asm-blackfin/mach-bf561/mem_map.h | 24 ++--- include/asm-blackfin/mach-common/clocks.h | 4 +- .../asm-blackfin/mach-common/def_LPBlackfin.h | 3 + include/asm-blackfin/pgtable.h | 2 +- include/asm-blackfin/system.h | 2 +- 31 files changed, 289 insertions(+), 391 deletions(-) diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index a7a6e0c5827d..17f946920159 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -722,22 +722,22 @@ endchoice comment "Cache Support" -config BLKFIN_CACHE +config BFIN_ICACHE bool "Enable ICACHE" -config BLKFIN_DCACHE +config BFIN_DCACHE bool "Enable DCACHE" -config BLKFIN_DCACHE_BANKA +config BFIN_DCACHE_BANKA bool "Enable only 16k BankA DCACHE - BankB is SRAM" - depends on BLKFIN_DCACHE && !BF531 + depends on BFIN_DCACHE && !BF531 default n -config BLKFIN_CACHE_LOCK - bool "Enable Cache Locking" +config BFIN_ICACHE_LOCK + bool "Enable Instruction Cache Locking" choice prompt "Policy" - depends on BLKFIN_DCACHE - default BLKFIN_WB -config BLKFIN_WB + depends on BFIN_DCACHE + default BFIN_WB +config BFIN_WB bool "Write back" help Write Back Policy: @@ -754,7 +754,7 @@ config BLKFIN_WB If you are unsure of the options and you want to be safe, then go with Write Through. -config BLKFIN_WT +config BFIN_WT bool "Write through" help Write Back Policy: diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig index 1cf1ab28dc66..02141827e595 100644 --- a/arch/blackfin/configs/BF533-EZKIT_defconfig +++ b/arch/blackfin/configs/BF533-EZKIT_defconfig @@ -243,12 +243,12 @@ CONFIG_DMA_UNCACHED_1M=y # # Cache Support # -CONFIG_BLKFIN_CACHE=y -CONFIG_BLKFIN_DCACHE=y -# CONFIG_BLKFIN_DCACHE_BANKA is not set -# CONFIG_BLKFIN_CACHE_LOCK is not set -# CONFIG_BLKFIN_WB is not set -CONFIG_BLKFIN_WT=y +CONFIG_BFIN_ICACHE=y +CONFIG_BFIN_DCACHE=y +# CONFIG_BFIN_DCACHE_BANKA is not set +# CONFIG_BFIN_ICACHE_LOCK is not set +# CONFIG_BFIN_WB is not set +CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 # diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig index 64b7f1b3b2af..3dbe22d7d909 100644 --- a/arch/blackfin/configs/BF533-STAMP_defconfig +++ b/arch/blackfin/configs/BF533-STAMP_defconfig @@ -255,12 +255,12 @@ CONFIG_DMA_UNCACHED_1M=y # # Cache Support # -CONFIG_BLKFIN_CACHE=y -CONFIG_BLKFIN_DCACHE=y -# CONFIG_BLKFIN_DCACHE_BANKA is not set -# CONFIG_BLKFIN_CACHE_LOCK is not set -# CONFIG_BLKFIN_WB is not set -CONFIG_BLKFIN_WT=y +CONFIG_BFIN_ICACHE=y +CONFIG_BFIN_DCACHE=y +# CONFIG_BFIN_DCACHE_BANKA is not set +# CONFIG_BFIN_ICACHE_LOCK is not set +# CONFIG_BFIN_WB is not set +CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 # diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig index ccf09dc09a18..a28e0316e90c 100644 --- a/arch/blackfin/configs/BF537-STAMP_defconfig +++ b/arch/blackfin/configs/BF537-STAMP_defconfig @@ -258,12 +258,12 @@ CONFIG_DMA_UNCACHED_1M=y # # Cache Support # -CONFIG_BLKFIN_CACHE=y -CONFIG_BLKFIN_DCACHE=y -# CONFIG_BLKFIN_DCACHE_BANKA is not set -# CONFIG_BLKFIN_CACHE_LOCK is not set -# CONFIG_BLKFIN_WB is not set -CONFIG_BLKFIN_WT=y +CONFIG_BFIN_ICACHE=y +CONFIG_BFIN_DCACHE=y +# CONFIG_BFIN_DCACHE_BANKA is not set +# CONFIG_BFIN_ICACHE_LOCK is not set +# CONFIG_BFIN_WB is not set +CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 # diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig index ac8390fafa9c..8f3b1de6a939 100644 --- a/arch/blackfin/configs/BF548-EZKIT_defconfig +++ b/arch/blackfin/configs/BF548-EZKIT_defconfig @@ -306,12 +306,12 @@ CONFIG_DMA_UNCACHED_1M=y # # Cache Support # -CONFIG_BLKFIN_CACHE=y -CONFIG_BLKFIN_DCACHE=y -# CONFIG_BLKFIN_DCACHE_BANKA is not set -# CONFIG_BLKFIN_CACHE_LOCK is not set -# CONFIG_BLKFIN_WB is not set -CONFIG_BLKFIN_WT=y +CONFIG_BFIN_ICACHE=y +CONFIG_BFIN_DCACHE=y +# CONFIG_BFIN_DCACHE_BANKA is not set +# CONFIG_BFIN_ICACHE_LOCK is not set +# CONFIG_BFIN_WB is not set +CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 # diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig index 51c0b6f97798..698a2492424e 100644 --- a/arch/blackfin/configs/BF561-EZKIT_defconfig +++ b/arch/blackfin/configs/BF561-EZKIT_defconfig @@ -288,12 +288,12 @@ CONFIG_DMA_UNCACHED_1M=y # # Cache Support # -CONFIG_BLKFIN_CACHE=y -CONFIG_BLKFIN_DCACHE=y -# CONFIG_BLKFIN_DCACHE_BANKA is not set -# CONFIG_BLKFIN_CACHE_LOCK is not set -# CONFIG_BLKFIN_WB is not set -CONFIG_BLKFIN_WT=y +CONFIG_BFIN_ICACHE=y +CONFIG_BFIN_DCACHE=y +# CONFIG_BFIN_DCACHE_BANKA is not set +# CONFIG_BFIN_ICACHE_LOCK is not set +# CONFIG_BFIN_WB is not set +CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 # diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig index 983ed181c896..dbb0c4f399fb 100644 --- a/arch/blackfin/configs/PNAV-10_defconfig +++ b/arch/blackfin/configs/PNAV-10_defconfig @@ -257,12 +257,12 @@ CONFIG_DMA_UNCACHED_1M=y # # Cache Support # -CONFIG_BLKFIN_CACHE=y -CONFIG_BLKFIN_DCACHE=y -# CONFIG_BLKFIN_DCACHE_BANKA is not set -# CONFIG_BLKFIN_CACHE_LOCK is not set -CONFIG_BLKFIN_WB=y -# CONFIG_BLKFIN_WT is not set +CONFIG_BFIN_ICACHE=y +CONFIG_BFIN_DCACHE=y +# CONFIG_BFIN_DCACHE_BANKA is not set +# CONFIG_BFIN_ICACHE_LOCK is not set +CONFIG_BFIN_WB=y +# CONFIG_BFIN_WT is not set CONFIG_L1_MAX_PIECE=16 # diff --git a/arch/blackfin/kernel/cacheinit.c b/arch/blackfin/kernel/cacheinit.c index 4d41a40e8133..62cbba7364b0 100644 --- a/arch/blackfin/kernel/cacheinit.c +++ b/arch/blackfin/kernel/cacheinit.c @@ -21,9 +21,10 @@ #include #include +#include #include -#if defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_ICACHE) void bfin_icache_init(void) { unsigned long *table = icplb_table; @@ -44,7 +45,7 @@ void bfin_icache_init(void) } #endif -#if defined(CONFIG_BLKFIN_DCACHE) +#if defined(CONFIG_BFIN_DCACHE) void bfin_dcache_init(void) { unsigned long *table = dcplb_table; diff --git a/arch/blackfin/kernel/cplbinit.c b/arch/blackfin/kernel/cplbinit.c index 3b1c87c9fd51..f2db6a5e2b5b 100644 --- a/arch/blackfin/kernel/cplbinit.c +++ b/arch/blackfin/kernel/cplbinit.c @@ -23,6 +23,7 @@ #include #include +#include #include u_long icplb_table[MAX_CPLBS+1]; @@ -56,7 +57,7 @@ struct s_cplb { struct cplb_tab switch_d; }; -#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) static struct cplb_desc cplb_data[] = { { .start = 0, @@ -230,7 +231,7 @@ static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_en cplb_data[i].psize, cplb_data[i].i_conf); } else { -#if defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_ICACHE) if (ANOMALY_05000263 && i == SDRAM_KERN) { fill_cplbtab(t, cplb_data[i].start, diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 6a7aefe48346..22e790419868 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -136,7 +136,7 @@ void cpu_idle(void) void machine_restart(char *__unused) { -#if defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_ICACHE) bfin_write_IMEM_CONTROL(0x01); SSYNC(); #endif diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 02c15272f8ef..448e6aab73ac 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -66,21 +67,21 @@ char __initdata command_line[COMMAND_LINE_SIZE]; void __init bf53x_cache_init(void) { -#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) generate_cpl_tables(); #endif -#ifdef CONFIG_BLKFIN_CACHE +#ifdef CONFIG_BFIN_ICACHE bfin_icache_init(); printk(KERN_INFO "Instruction Cache Enabled\n"); #endif -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE bfin_dcache_init(); printk(KERN_INFO "Data Cache Enabled" -# if defined CONFIG_BLKFIN_WB +# if defined CONFIG_BFIN_WB " (write-back)" -# elif defined CONFIG_BLKFIN_WT +# elif defined CONFIG_BFIN_WT " (write-through)" # endif "\n"); @@ -262,7 +263,7 @@ void __init setup_arch(char **cmdline_p) && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1) mtd_size = PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2])); -# if (defined(CONFIG_BLKFIN_CACHE) && ANOMALY_05000263) +# if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263) /* Due to a Hardware Anomaly we need to limit the size of usable * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on * 05000263 - Hardware loop corrupted when taking an ICPLB exception @@ -291,7 +292,7 @@ void __init setup_arch(char **cmdline_p) _ebss = memory_mtd_start; /* define _ebss for compatible */ #endif /* CONFIG_MTD_UCLINUX */ -#if (defined(CONFIG_BLKFIN_CACHE) && ANOMALY_05000263) +#if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263) /* Due to a Hardware Anomaly we need to limit the size of usable * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on * 05000263 - Hardware loop corrupted when taking an ICPLB exception @@ -535,9 +536,9 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "I-CACHE:\tOFF\n"); if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE)) seq_printf(m, "D-CACHE:\tON" -#if defined CONFIG_BLKFIN_WB +#if defined CONFIG_BFIN_WB " (write-back)" -#elif defined CONFIG_BLKFIN_WT +#elif defined CONFIG_BFIN_WT " (write-through)" #endif "\n"); @@ -566,15 +567,15 @@ static int show_cpuinfo(struct seq_file *m, void *v) } - seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024); + seq_printf(m, "I-CACHE Size:\t%dKB\n", BFIN_ICACHESIZE / 1024); seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size); seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n", - BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES); + BFIN_ISUBBANKS, BFIN_IWAYS, BFIN_ILINES); seq_printf(m, "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n", - dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS, - BLKFIN_DLINES); -#ifdef CONFIG_BLKFIN_CACHE_LOCK + dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS, + BFIN_DLINES); +#ifdef CONFIG_BFIN_ICACHE_LOCK switch (read_iloc()) { case WAY0_L: seq_printf(m, "Way0 Locked-Down\n"); diff --git a/arch/blackfin/mach-common/arch_checks.c b/arch/blackfin/mach-common/arch_checks.c index f9160d83b91f..2f6ce397780f 100644 --- a/arch/blackfin/mach-common/arch_checks.c +++ b/arch/blackfin/mach-common/arch_checks.c @@ -53,3 +53,8 @@ # endif #endif /* CONFIG_BFIN_KERNEL_CLOCK */ + +#if (CONFIG_MEM_SIZE % 4) +#error "SDRAM mem size must be multible of 4MB" +#endif + diff --git a/arch/blackfin/mach-common/cacheinit.S b/arch/blackfin/mach-common/cacheinit.S index afa0adfac6c3..22fada0c1cb3 100644 --- a/arch/blackfin/mach-common/cacheinit.S +++ b/arch/blackfin/mach-common/cacheinit.S @@ -39,7 +39,7 @@ .text #if ANOMALY_05000125 -#if defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_ICACHE) ENTRY(_bfin_write_IMEM_CONTROL) /* Enable Instruction Cache */ @@ -58,10 +58,10 @@ ENTRY(_bfin_write_IMEM_CONTROL) ENDPROC(_bfin_write_IMEM_CONTROL) #endif -#if defined(CONFIG_BLKFIN_DCACHE) +#if defined(CONFIG_BFIN_DCACHE) ENTRY(_bfin_write_DMEM_CONTROL) - P0.l = (DMEM_CONTROL & 0xFFFF); - P0.h = (DMEM_CONTROL >> 16); + P0.l = LO(DMEM_CONTROL); + P0.h = HI(DMEM_CONTROL); CLI R1; SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ diff --git a/arch/blackfin/mach-common/cplbhdlr.S b/arch/blackfin/mach-common/cplbhdlr.S index 2f3c72c23997..2788532de72b 100644 --- a/arch/blackfin/mach-common/cplbhdlr.S +++ b/arch/blackfin/mach-common/cplbhdlr.S @@ -69,14 +69,14 @@ ENTRY(__cplb_hdr) .Lis_icplb_miss: -#if defined(CONFIG_BLKFIN_CACHE) || defined(CONFIG_BLKFIN_DCACHE) -# if defined(CONFIG_BLKFIN_CACHE) && !defined(CONFIG_BLKFIN_DCACHE) +#if defined(CONFIG_BFIN_ICACHE) || defined(CONFIG_BFIN_DCACHE) +# if defined(CONFIG_BFIN_ICACHE) && !defined(CONFIG_BFIN_DCACHE) R1 = CPLB_ENABLE_ICACHE; # endif -# if !defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE) +# if !defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE) R1 = CPLB_ENABLE_DCACHE; # endif -# if defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE) +# if defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE) R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE; # endif #else diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S index cef94c13f956..946703ef48ff 100644 --- a/arch/blackfin/mach-common/cplbmgr.S +++ b/arch/blackfin/mach-common/cplbmgr.S @@ -565,7 +565,7 @@ ENTRY(_cplb_mgr) * cost of first-write exceptions to mark the page as dirty. */ -#ifdef CONFIG_BLKFIN_WT +#ifdef CONFIG_BFIN_WT BITSET(R6, 14); /* Set WT*/ #endif diff --git a/arch/blackfin/mach-common/lock.S b/arch/blackfin/mach-common/lock.S index 190edb3cdc84..28b87fe9ce3c 100644 --- a/arch/blackfin/mach-common/lock.S +++ b/arch/blackfin/mach-common/lock.S @@ -33,7 +33,7 @@ .text -#ifdef CONFIG_BLKFIN_CACHE_LOCK +#ifdef CONFIG_BFIN_ICACHE_LOCK /* When you come here, it is assumed that * R0 - Which way to be locked @@ -189,7 +189,7 @@ ENTRY(_cache_lock) RTS; ENDPROC(_cache_lock) -#endif /* BLKFIN_CACHE_LOCK */ +#endif /* BFIN_ICACHE_LOCK */ /* Return the ILOC bits of IMEM_CONTROL */ diff --git a/include/asm-blackfin/cacheflush.h b/include/asm-blackfin/cacheflush.h index e5e000de3c36..d81a77545a04 100644 --- a/include/asm-blackfin/cacheflush.h +++ b/include/asm-blackfin/cacheflush.h @@ -48,9 +48,9 @@ extern void blackfin_dflush_page(void *); static inline void flush_icache_range(unsigned start, unsigned end) { -#if defined(CONFIG_BLKFIN_DCACHE) && defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_ICACHE) -# if defined(CONFIG_BLKFIN_WT) +# if defined(CONFIG_BFIN_WT) blackfin_icache_flush_range((start), (end)); # else blackfin_icache_dcache_flush_range((start), (end)); @@ -58,10 +58,10 @@ static inline void flush_icache_range(unsigned start, unsigned end) #else -# if defined(CONFIG_BLKFIN_CACHE) +# if defined(CONFIG_BFIN_ICACHE) blackfin_icache_flush_range((start), (end)); # endif -# if defined(CONFIG_BLKFIN_DCACHE) +# if defined(CONFIG_BFIN_DCACHE) blackfin_dcache_flush_range((start), (end)); # endif @@ -74,12 +74,12 @@ do { memcpy(dst, src, len); \ } while (0) #define copy_from_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len) -#if defined(CONFIG_BLKFIN_DCACHE) +#if defined(CONFIG_BFIN_DCACHE) # define invalidate_dcache_range(start,end) blackfin_dcache_invalidate_range((start), (end)) #else # define invalidate_dcache_range(start,end) do { } while (0) #endif -#if defined(CONFIG_BLKFIN_DCACHE) && defined(CONFIG_BLKFIN_WB) +#if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_WB) # define flush_dcache_range(start,end) blackfin_dcache_flush_range((start), (end)) # define flush_dcache_page(page) blackfin_dflush_page(page_address(page)) #else @@ -87,4 +87,4 @@ do { memcpy(dst, src, len); \ # define flush_dcache_page(page) do { } while (0) #endif -#endif /* _BLACKFIN_CACHEFLUSH_H */ +#endif /* _BLACKFIN_ICACHEFLUSH_H */ diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h index e0dd56bfa4c7..c9fc77684fb2 100644 --- a/include/asm-blackfin/cplb.h +++ b/include/asm-blackfin/cplb.h @@ -1,18 +1,93 @@ -/************************************************************************ +/* + * File: include/asm-blackfin/cplb.h + * Based on: include/asm-blackfin/mach-bf537/bf537.h + * Author: Robin Getz * - * cplb.h + * Created: 2000 + * Description: Common CPLB definitions for CPLB init * - * (c) Copyright 2002-2003 Analog Devices, Inc. All rights reserved. + * Modified: + * Copyright 2004-2007 Analog Devices Inc. * - ************************************************************************/ - -/* Defines necessary for cplb initialisation routines. */ + * 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 _CPLB_H #define _CPLB_H # include +#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO) +#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK) +#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK) +#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID) + +/*Use the menuconfig cache policy here - CONFIG_BFIN_WT/CONFIG_BFIN_WB*/ + +#if ANOMALY_05000158 +#define ANOMALY_05000158_WORKAROUND 0x200 +#else +#define ANOMALY_05000158_WORKAROUND 0x0 +#endif + +#define CPLB_COMMON (CPLB_DIRTY | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND) + +#ifdef CONFIG_BFIN_WB /*Write Back Policy */ +#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_COMMON) +#else /*Write Through */ +#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_COMMON) +#endif + +#define L1_DMEMORY (CPLB_LOCK | CPLB_COMMON) +#define SDRAM_DNON_CHBL (CPLB_COMMON) +#define SDRAM_EBIU (CPLB_COMMON) +#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY) + +#define SIZE_1K 0x00000400 /* 1K */ +#define SIZE_4K 0x00001000 /* 4K */ +#define SIZE_1M 0x00100000 /* 1M */ +#define SIZE_4M 0x00400000 /* 4M */ + +#define MAX_CPLBS (16 * 2) + +/* +* Number of required data CPLB switchtable entries +* MEMSIZE / 4 (we mostly install 4M page size CPLBs +* approx 16 for smaller 1MB page size CPLBs for allignment purposes +* 1 for L1 Data Memory +* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO +* 1 for ASYNC Memory +*/ + + +#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2) + +/* +* Number of required instruction CPLB switchtable entries +* MEMSIZE / 4 (we mostly install 4M page size CPLBs +* approx 12 for smaller 1MB page size CPLBs for allignment purposes +* 1 for L1 Instruction Memory +* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO +*/ + +#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2) + + #define CPLB_ENABLE_ICACHE_P 0 #define CPLB_ENABLE_DCACHE_P 1 #define CPLB_ENABLE_DCACHE2_P 2 @@ -39,8 +114,6 @@ #define CPLB_DEF_CACHE CPLB_L1_CHBL | CPLB_WT #define CPLB_CACHE_ENABLED CPLB_L1_CHBL | CPLB_DIRTY -#define CPLB_ALL_ACCESS CPLB_SUPV_WR | CPLB_USER_RD | CPLB_USER_WR - #define CPLB_I_PAGE_MGMT CPLB_LOCK | CPLB_VALID #define CPLB_D_PAGE_MGMT CPLB_LOCK | CPLB_ALL_ACCESS | CPLB_VALID #define CPLB_DNOCACHE CPLB_ALL_ACCESS | CPLB_VALID diff --git a/include/asm-blackfin/mach-bf533/bf533.h b/include/asm-blackfin/mach-bf533/bf533.h index cb210f6f7689..cb0785768b35 100644 --- a/include/asm-blackfin/mach-bf533/bf533.h +++ b/include/asm-blackfin/mach-bf533/bf533.h @@ -52,12 +52,12 @@ /***************************/ -#define BLKFIN_DSUBBANKS 4 -#define BLKFIN_DWAYS 2 -#define BLKFIN_DLINES 64 -#define BLKFIN_ISUBBANKS 4 -#define BLKFIN_IWAYS 4 -#define BLKFIN_ILINES 32 +#define BFIN_DSUBBANKS 4 +#define BFIN_DWAYS 2 +#define BFIN_DLINES 64 +#define BFIN_ISUBBANKS 4 +#define BFIN_IWAYS 4 +#define BFIN_ILINES 32 #define WAY0_L 0x1 #define WAY1_L 0x2 @@ -167,10 +167,10 @@ #define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK) #define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID) -/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/ +/*Use the menuconfig cache policy here - CONFIG_BFIN_WT/CONFIG_BFIN_WB*/ #define ANOMALY_05000158_WORKAROUND 0x200 -#ifdef CONFIG_BLKFIN_WB /*Write Back Policy */ +#ifdef CONFIG_BFIN_WB /*Write Back Policy */ #define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND) #else /*Write Through */ diff --git a/include/asm-blackfin/mach-bf533/mem_map.h b/include/asm-blackfin/mach-bf533/mem_map.h index e84baa3e939d..94d8c4062eb7 100644 --- a/include/asm-blackfin/mach-bf533/mem_map.h +++ b/include/asm-blackfin/mach-bf533/mem_map.h @@ -51,10 +51,10 @@ /* Level 1 Memory */ -#ifdef CONFIG_BLKFIN_CACHE -#define BLKFIN_ICACHESIZE (16*1024) +#ifdef CONFIG_BFIN_ICACHE +#define BFIN_ICACHESIZE (16*1024) #else -#define BLKFIN_ICACHESIZE (0*1024) +#define BFIN_ICACHESIZE (0*1024) #endif /* Memory Map for ADSP-BF533 processors */ @@ -64,35 +64,35 @@ #define L1_DATA_A_START 0xFF800000 #define L1_DATA_B_START 0xFF900000 -#ifdef CONFIG_BLKFIN_CACHE +#ifdef CONFIG_BFIN_ICACHE #define L1_CODE_LENGTH (0x14000 - 0x4000) #else #define L1_CODE_LENGTH 0x14000 #endif -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE -#ifdef CONFIG_BLKFIN_DCACHE_BANKA +#ifdef CONFIG_BFIN_DCACHE_BANKA #define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (16*1024) -#define BLKFIN_DSUPBANKS 1 +#define BFIN_DCACHESIZE (16*1024) +#define BFIN_DSUPBANKS 1 #else #define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH (0x8000 - 0x4000) -#define BLKFIN_DCACHESIZE (32*1024) -#define BLKFIN_DSUPBANKS 2 +#define BFIN_DCACHESIZE (32*1024) +#define BFIN_DSUPBANKS 2 #endif #else #define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH 0x8000 #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (0*1024) -#define BLKFIN_DSUPBANKS 0 -#endif /*CONFIG_BLKFIN_DCACHE*/ +#define BFIN_DCACHESIZE (0*1024) +#define BFIN_DSUPBANKS 0 +#endif /*CONFIG_BFIN_DCACHE*/ #endif /* Memory Map for ADSP-BF532 processors */ @@ -102,36 +102,36 @@ #define L1_DATA_A_START 0xFF804000 #define L1_DATA_B_START 0xFF904000 -#ifdef CONFIG_BLKFIN_CACHE +#ifdef CONFIG_BFIN_ICACHE #define L1_CODE_LENGTH (0xC000 - 0x4000) #else #define L1_CODE_LENGTH 0xC000 #endif -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE -#ifdef CONFIG_BLKFIN_DCACHE_BANKA +#ifdef CONFIG_BFIN_DCACHE_BANKA #define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x4000 - 0x4000) #define L1_DATA_B_LENGTH 0x4000 -#define BLKFIN_DCACHESIZE (16*1024) -#define BLKFIN_DSUPBANKS 1 +#define BFIN_DCACHESIZE (16*1024) +#define BFIN_DSUPBANKS 1 #else #define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x4000 - 0x4000) #define L1_DATA_B_LENGTH (0x4000 - 0x4000) -#define BLKFIN_DCACHESIZE (32*1024) -#define BLKFIN_DSUPBANKS 2 +#define BFIN_DCACHESIZE (32*1024) +#define BFIN_DSUPBANKS 2 #endif #else #define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH 0x4000 #define L1_DATA_B_LENGTH 0x4000 -#define BLKFIN_DCACHESIZE (0*1024) -#define BLKFIN_DSUPBANKS 0 -#endif /*CONFIG_BLKFIN_DCACHE*/ +#define BFIN_DCACHESIZE (0*1024) +#define BFIN_DSUPBANKS 0 +#endif /*CONFIG_BFIN_DCACHE*/ #endif /* Memory Map for ADSP-BF531 processors */ @@ -144,16 +144,16 @@ #define L1_DATA_B_LENGTH 0x0000 -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE #define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x4000 - 0x4000) -#define BLKFIN_DCACHESIZE (16*1024) -#define BLKFIN_DSUPBANKS 1 +#define BFIN_DCACHESIZE (16*1024) +#define BFIN_DSUPBANKS 1 #else #define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH 0x4000 -#define BLKFIN_DCACHESIZE (0*1024) -#define BLKFIN_DSUPBANKS 0 +#define BFIN_DCACHESIZE (0*1024) +#define BFIN_DSUPBANKS 0 #endif #endif diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h index 3803f156bf1c..e377064b307c 100644 --- a/include/asm-blackfin/mach-bf537/anomaly.h +++ b/include/asm-blackfin/mach-bf537/anomaly.h @@ -133,6 +133,7 @@ /* Anomalies that don't exist on this proc */ #define ANOMALY_05000125 (0) +#define ANOMALY_05000158 (0) #define ANOMALY_05000183 (0) #define ANOMALY_05000198 (0) #define ANOMALY_05000266 (0) diff --git a/include/asm-blackfin/mach-bf537/bf537.h b/include/asm-blackfin/mach-bf537/bf537.h index 603823f51ca0..cfe2a221112e 100644 --- a/include/asm-blackfin/mach-bf537/bf537.h +++ b/include/asm-blackfin/mach-bf537/bf537.h @@ -62,12 +62,12 @@ /***************************/ -#define BLKFIN_DSUBBANKS 4 -#define BLKFIN_DWAYS 2 -#define BLKFIN_DLINES 64 -#define BLKFIN_ISUBBANKS 4 -#define BLKFIN_IWAYS 4 -#define BLKFIN_ILINES 32 +#define BFIN_DSUBBANKS 4 +#define BFIN_DWAYS 2 +#define BFIN_DLINES 64 +#define BFIN_ISUBBANKS 4 +#define BFIN_IWAYS 4 +#define BFIN_ILINES 32 #define WAY0_L 0x1 #define WAY1_L 0x2 @@ -138,59 +138,4 @@ #define CPUID 0x0 #endif -#if (CONFIG_MEM_SIZE % 4) -#error "SDRAM mem size must be multible of 4MB" -#endif - -#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO) -#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK) -#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK) -#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID) - -/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/ - -#define ANOMALY_05000158_WORKAROUND 0x200 -#ifdef CONFIG_BLKFIN_WB /*Write Back Policy */ -#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \ - | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND) -#else /*Write Through */ -#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW \ - | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY ) -#endif - - -#define L1_DMEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY ) -#define SDRAM_DNON_CHBL (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY ) -#define SDRAM_EBIU (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY ) -#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY ) - -#define SIZE_1K 0x00000400 /* 1K */ -#define SIZE_4K 0x00001000 /* 4K */ -#define SIZE_1M 0x00100000 /* 1M */ -#define SIZE_4M 0x00400000 /* 4M */ - -#define MAX_CPLBS (16 * 2) - -/* -* Number of required data CPLB switchtable entries -* MEMSIZE / 4 (we mostly install 4M page size CPLBs -* approx 16 for smaller 1MB page size CPLBs for allignment purposes -* 1 for L1 Data Memory -* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO -* 1 for ASYNC Memory -*/ - - -#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2) - -/* -* Number of required instruction CPLB switchtable entries -* MEMSIZE / 4 (we mostly install 4M page size CPLBs -* approx 12 for smaller 1MB page size CPLBs for allignment purposes -* 1 for L1 Instruction Memory -* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO -*/ - -#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2) - #endif /* __MACH_BF537_H__ */ diff --git a/include/asm-blackfin/mach-bf537/mem_map.h b/include/asm-blackfin/mach-bf537/mem_map.h index 2a808c1202bf..18759e38eaae 100644 --- a/include/asm-blackfin/mach-bf537/mem_map.h +++ b/include/asm-blackfin/mach-bf537/mem_map.h @@ -52,10 +52,10 @@ /* Memory Map for ADSP-BF537 processors */ -#ifdef CONFIG_BLKFIN_CACHE -#define BLKFIN_ICACHESIZE (16*1024) +#ifdef CONFIG_BFIN_ICACHE +#define BFIN_ICACHESIZE (16*1024) #else -#define BLKFIN_ICACHESIZE (0*1024) +#define BFIN_ICACHESIZE (0*1024) #endif @@ -66,29 +66,29 @@ #define L1_CODE_LENGTH 0xC000 -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE -#ifdef CONFIG_BLKFIN_DCACHE_BANKA +#ifdef CONFIG_BFIN_DCACHE_BANKA #define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (16*1024) -#define BLKFIN_DSUPBANKS 1 +#define BFIN_DCACHESIZE (16*1024) +#define BFIN_DSUPBANKS 1 #else #define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH (0x8000 - 0x4000) -#define BLKFIN_DCACHESIZE (32*1024) -#define BLKFIN_DSUPBANKS 2 +#define BFIN_DCACHESIZE (32*1024) +#define BFIN_DSUPBANKS 2 #endif #else #define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH 0x8000 #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (0*1024) -#define BLKFIN_DSUPBANKS 0 -#endif /*CONFIG_BLKFIN_DCACHE*/ +#define BFIN_DCACHESIZE (0*1024) +#define BFIN_DSUPBANKS 0 +#endif /*CONFIG_BFIN_DCACHE*/ #endif /*CONFIG_BF537*/ @@ -102,30 +102,30 @@ #define L1_CODE_LENGTH 0xC000 -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE -#ifdef CONFIG_BLKFIN_DCACHE_BANKA +#ifdef CONFIG_BFIN_DCACHE_BANKA #define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x4000 - 0x4000) #define L1_DATA_B_LENGTH 0x4000 -#define BLKFIN_DCACHESIZE (16*1024) -#define BLKFIN_DSUPBANKS 1 +#define BFIN_DCACHESIZE (16*1024) +#define BFIN_DSUPBANKS 1 #else #define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x4000 - 0x4000) #define L1_DATA_B_LENGTH (0x4000 - 0x4000) -#define BLKFIN_DCACHESIZE (32*1024) -#define BLKFIN_DSUPBANKS 2 +#define BFIN_DCACHESIZE (32*1024) +#define BFIN_DSUPBANKS 2 #endif #else #define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH 0x4000 #define L1_DATA_B_LENGTH 0x4000 -#define BLKFIN_DCACHESIZE (0*1024) -#define BLKFIN_DSUPBANKS 0 -#endif /*CONFIG_BLKFIN_DCACHE*/ +#define BFIN_DCACHESIZE (0*1024) +#define BFIN_DSUPBANKS 0 +#endif /*CONFIG_BFIN_DCACHE*/ #endif @@ -138,30 +138,30 @@ #define L1_CODE_LENGTH 0xC000 -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE -#ifdef CONFIG_BLKFIN_DCACHE_BANKA +#ifdef CONFIG_BFIN_DCACHE_BANKA #define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (16*1024) -#define BLKFIN_DSUPBANKS 1 +#define BFIN_DCACHESIZE (16*1024) +#define BFIN_DSUPBANKS 1 #else #define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH (0x8000 - 0x4000) -#define BLKFIN_DCACHESIZE (32*1024) -#define BLKFIN_DSUPBANKS 2 +#define BFIN_DCACHESIZE (32*1024) +#define BFIN_DSUPBANKS 2 #endif #else #define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH 0x8000 #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (0*1024) -#define BLKFIN_DSUPBANKS 0 -#endif /*CONFIG_BLKFIN_DCACHE*/ +#define BFIN_DCACHESIZE (0*1024) +#define BFIN_DSUPBANKS 0 +#endif /*CONFIG_BFIN_DCACHE*/ #endif diff --git a/include/asm-blackfin/mach-bf548/bf548.h b/include/asm-blackfin/mach-bf548/bf548.h index 50306a846628..7e6d349beb08 100644 --- a/include/asm-blackfin/mach-bf548/bf548.h +++ b/include/asm-blackfin/mach-bf548/bf548.h @@ -52,12 +52,12 @@ /***************************/ -#define BLKFIN_DSUBBANKS 4 -#define BLKFIN_DWAYS 2 -#define BLKFIN_DLINES 64 -#define BLKFIN_ISUBBANKS 4 -#define BLKFIN_IWAYS 4 -#define BLKFIN_ILINES 32 +#define BFIN_DSUBBANKS 4 +#define BFIN_DWAYS 2 +#define BFIN_DLINES 64 +#define BFIN_ISUBBANKS 4 +#define BFIN_IWAYS 4 +#define BFIN_ILINES 32 #define WAY0_L 0x1 #define WAY1_L 0x2 @@ -126,59 +126,4 @@ #define CPUID 0x0 #endif -#if (CONFIG_MEM_SIZE % 4) -#error "SDRAM mem size must be multible of 4MB" -#endif - -#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO) -#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK) -#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK) -#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID) - -/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/ - -#define ANOMALY_05000158_WORKAROUND 0x200 -#ifdef CONFIG_BLKFIN_WB /*Write Back Policy */ -#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \ - | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND) -#else /*Write Through */ -#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW \ - | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY ) -#endif - - -#define L1_DMEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY ) -#define SDRAM_DNON_CHBL (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY ) -#define SDRAM_EBIU (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY ) -#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY ) - -#define SIZE_1K 0x00000400 /* 1K */ -#define SIZE_4K 0x00001000 /* 4K */ -#define SIZE_1M 0x00100000 /* 1M */ -#define SIZE_4M 0x00400000 /* 4M */ - -#define MAX_CPLBS (16 * 2) - -/* -* Number of required data CPLB switchtable entries -* MEMSIZE / 4 (we mostly install 4M page size CPLBs -* approx 16 for smaller 1MB page size CPLBs for allignment purposes -* 1 for L1 Data Memory -* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO -* 1 for ASYNC Memory -*/ - - -#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2) - -/* -* Number of required instruction CPLB switchtable entries -* MEMSIZE / 4 (we mostly install 4M page size CPLBs -* approx 12 for smaller 1MB page size CPLBs for allignment purposes -* 1 for L1 Instruction Memory -* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO -*/ - -#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2) - #endif /* __MACH_BF48_H__ */ diff --git a/include/asm-blackfin/mach-bf548/mem_map.h b/include/asm-blackfin/mach-bf548/mem_map.h index 72d80e8a6e81..ec1597e31831 100644 --- a/include/asm-blackfin/mach-bf548/mem_map.h +++ b/include/asm-blackfin/mach-bf548/mem_map.h @@ -51,10 +51,10 @@ /* Level 1 Memory */ /* Memory Map for ADSP-BF548 processors */ -#ifdef CONFIG_BLKFIN_ICACHE -#define BLKFIN_ICACHESIZE (16*1024) +#ifdef CONFIG_BFIN_ICACHE +#define BFIN_ICACHESIZE (16*1024) #else -#define BLKFIN_ICACHESIZE (0*1024) +#define BFIN_ICACHESIZE (0*1024) #endif #define L1_CODE_START 0xFFA00000 @@ -63,29 +63,29 @@ #define L1_CODE_LENGTH 0xC000 -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE -#ifdef CONFIG_BLKFIN_DCACHE_BANKA +#ifdef CONFIG_BFIN_DCACHE_BANKA #define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (16*1024) -#define BLKFIN_DSUPBANKS 1 +#define BFIN_DCACHESIZE (16*1024) +#define BFIN_DSUPBANKS 1 #else #define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH (0x8000 - 0x4000) -#define BLKFIN_DCACHESIZE (32*1024) -#define BLKFIN_DSUPBANKS 2 +#define BFIN_DCACHESIZE (32*1024) +#define BFIN_DSUPBANKS 2 #endif #else #define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH 0x8000 #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (0*1024) -#define BLKFIN_DSUPBANKS 0 -#endif /*CONFIG_BLKFIN_DCACHE*/ +#define BFIN_DCACHESIZE (0*1024) +#define BFIN_DSUPBANKS 0 +#endif /*CONFIG_BFIN_DCACHE*/ /* Scratch Pad Memory */ diff --git a/include/asm-blackfin/mach-bf561/bf561.h b/include/asm-blackfin/mach-bf561/bf561.h index 53b650f31342..17e1d5dcef02 100644 --- a/include/asm-blackfin/mach-bf561/bf561.h +++ b/include/asm-blackfin/mach-bf561/bf561.h @@ -73,13 +73,13 @@ */ -#define BLKFIN_ISUBBANKS 4 -#define BLKFIN_IWAYS 4 -#define BLKFIN_ILINES 32 +#define BFIN_ISUBBANKS 4 +#define BFIN_IWAYS 4 +#define BFIN_ILINES 32 -#define BLKFIN_DSUBBANKS 4 -#define BLKFIN_DWAYS 2 -#define BLKFIN_DLINES 64 +#define BFIN_DSUBBANKS 4 +#define BFIN_DWAYS 2 +#define BFIN_DLINES 64 #define WAY0_L 0x1 #define WAY1_L 0x2 @@ -239,83 +239,4 @@ #define CPUID 0x0 #endif -#if (CONFIG_MEM_SIZE % 4) -#error "SDRAM memory size must be a multiple of 4MB!" -#endif -#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO) -#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK) -#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK) -#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID) - -/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/ - -#define ANOMALY_05000158_WORKAROUND 0x200 -#ifdef CONFIG_BLKFIN_WB /*Write Back Policy */ -#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \ - | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND) -#else /*Write Through */ -#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_DIRTY \ - | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND) -#endif - - -#define L1_DMEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY) -#define SDRAM_DNON_CHBL (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY) -#define SDRAM_EBIU (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY) -#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY) - -#define L2_MEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY) - -#define SIZE_1K 0x00000400 /* 1K */ -#define SIZE_4K 0x00001000 /* 4K */ -#define SIZE_1M 0x00100000 /* 1M */ -#define SIZE_4M 0x00400000 /* 4M */ - -#define MAX_CPLBS (16 * 2) - -/* -* Number of required data CPLB switchtable entries -* MEMSIZE / 4 (we mostly install 4M page size CPLBs -* approx 16 for smaller 1MB page size CPLBs for allignment purposes -* 1 for L1 Data Memory -* 1 for L2 Data Memory -* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO -* 64 for ASYNC Memory -*/ - - -#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1 + 64) * 2) - -/* -* Number of required instruction CPLB switchtable entries -* MEMSIZE / 4 (we mostly install 4M page size CPLBs -* approx 12 for smaller 1MB page size CPLBs for allignment purposes -* 1 for L1 Instruction Memory -* 1 for L2 Instruction Memory -* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO -*/ - -#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1 + 1) * 2) - -#if 0 /* comment by mhfan */ -/* Event Vector Table Address */ -#define EVT_EMULATION_ADDR 0xffe02000 -#define EVT_RESET_ADDR 0xffe02004 -#define EVT_NMI_ADDR 0xffe02008 -#define EVT_EXCEPTION_ADDR 0xffe0200c -#define EVT_GLOBAL_INT_ENB_ADDR 0xffe02010 -#define EVT_HARDWARE_ERROR_ADDR 0xffe02014 -#define EVT_TIMER_ADDR 0xffe02018 -#define EVT_IVG7_ADDR 0xffe0201c -#define EVT_IVG8_ADDR 0xffe02020 -#define EVT_IVG9_ADDR 0xffe02024 -#define EVT_IVG10_ADDR 0xffe02028 -#define EVT_IVG11_ADDR 0xffe0202c -#define EVT_IVG12_ADDR 0xffe02030 -#define EVT_IVG13_ADDR 0xffe02034 -#define EVT_IVG14_ADDR 0xffe02038 -#define EVT_IVG15_ADDR 0xffe0203c -#define EVT_OVERRIDE_ADDR 0xffe02100 -#endif /* comment by mhfan */ - #endif /* __MACH_BF561_H__ */ diff --git a/include/asm-blackfin/mach-bf561/mem_map.h b/include/asm-blackfin/mach-bf561/mem_map.h index ebac9a8d838d..f7ac09cf2c3d 100644 --- a/include/asm-blackfin/mach-bf561/mem_map.h +++ b/include/asm-blackfin/mach-bf561/mem_map.h @@ -21,10 +21,10 @@ /* Level 1 Memory */ -#ifdef CONFIG_BLKFIN_CACHE -#define BLKFIN_ICACHESIZE (16*1024) +#ifdef CONFIG_BFIN_ICACHE +#define BFIN_ICACHESIZE (16*1024) #else -#define BLKFIN_ICACHESIZE (0*1024) +#define BFIN_ICACHESIZE (0*1024) #endif /* Memory Map for ADSP-BF561 processors */ @@ -36,29 +36,29 @@ #define L1_CODE_LENGTH 0x4000 -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE -#ifdef CONFIG_BLKFIN_DCACHE_BANKA +#ifdef CONFIG_BFIN_DCACHE_BANKA #define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (16*1024) -#define BLKFIN_DSUPBANKS 1 +#define BFIN_DCACHESIZE (16*1024) +#define BFIN_DSUPBANKS 1 #else #define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH (0x8000 - 0x4000) #define L1_DATA_B_LENGTH (0x8000 - 0x4000) -#define BLKFIN_DCACHESIZE (32*1024) -#define BLKFIN_DSUPBANKS 2 +#define BFIN_DCACHESIZE (32*1024) +#define BFIN_DSUPBANKS 2 #endif #else #define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0) #define L1_DATA_A_LENGTH 0x8000 #define L1_DATA_B_LENGTH 0x8000 -#define BLKFIN_DCACHESIZE (0*1024) -#define BLKFIN_DSUPBANKS 0 -#endif /*CONFIG_BLKFIN_DCACHE*/ +#define BFIN_DCACHESIZE (0*1024) +#define BFIN_DSUPBANKS 0 +#endif /*CONFIG_BFIN_DCACHE*/ #endif /* Level 2 Memory */ diff --git a/include/asm-blackfin/mach-common/clocks.h b/include/asm-blackfin/mach-common/clocks.h index 5e8113ee8939..033bba92d61c 100644 --- a/include/asm-blackfin/mach-common/clocks.h +++ b/include/asm-blackfin/mach-common/clocks.h @@ -27,7 +27,8 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - +#ifndef _BFIN_CLOCKS_H +#define _BFIN_CLOCKS_H #ifdef CONFIG_CCLK_DIV_1 # define CONFIG_CCLK_ACT_DIV CCLK_DIV1 @@ -66,3 +67,4 @@ # define CONFIG_VCO_MULT 0 #endif +#endif diff --git a/include/asm-blackfin/mach-common/def_LPBlackfin.h b/include/asm-blackfin/mach-common/def_LPBlackfin.h index 260515d15280..c1d8c4a78fcf 100644 --- a/include/asm-blackfin/mach-common/def_LPBlackfin.h +++ b/include/asm-blackfin/mach-common/def_LPBlackfin.h @@ -639,6 +639,7 @@ #define CPLB_USER_RD 0x00000004 /* 0=no read access, 1=read access * allowed (user mode) */ + #define PAGE_SIZE_1KB 0x00000000 /* 1 KB page size */ #define PAGE_SIZE_4KB 0x00010000 /* 4 KB page size */ #define PAGE_SIZE_1MB 0x00020000 /* 1 MB page size */ @@ -671,6 +672,8 @@ */ #define CPLB_WT 0x00004000 /* 0=write-back, 1=write-through */ +#define CPLB_ALL_ACCESS CPLB_SUPV_WR | CPLB_USER_RD | CPLB_USER_WR + /* TBUFCTL Masks */ #define TBUFPWR 0x0001 #define TBUFEN 0x0002 diff --git a/include/asm-blackfin/pgtable.h b/include/asm-blackfin/pgtable.h index 5a8f9e431c40..b11b114689c0 100644 --- a/include/asm-blackfin/pgtable.h +++ b/include/asm-blackfin/pgtable.h @@ -4,7 +4,7 @@ #include #include -#include +#include typedef pte_t *pte_addr_t; /* diff --git a/include/asm-blackfin/system.h b/include/asm-blackfin/system.h index b03cf7d5b9a3..2b3d47d0bbb6 100644 --- a/include/asm-blackfin/system.h +++ b/include/asm-blackfin/system.h @@ -60,7 +60,7 @@ extern unsigned long irq_flags; ); \ } while (0) -#if ANOMALY_05000244 && defined(CONFIG_BLKFIN_CACHE) +#if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE) # define NOP_PAD_ANOMALY_05000244 "nop; nop;" #else # define NOP_PAD_ANOMALY_05000244 From 07bdda02623d6d9078e45f6b6451bc3508878db1 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Aug 2007 15:29:35 +0800 Subject: [PATCH 0030/2804] Blackfin arch: bug fixing restore mach dependent ASYNC memory size Bug: When SMC921X driver is enabled, kernel boot crash on EZKIT548 http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=3460 Fixed by restoring mach dependent ASYNC memory size CPLB coverage. Once we have a more dynamic memory layout we should come up with a better solution for these hard-coded values. Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- include/asm-blackfin/cplb.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h index c9fc77684fb2..df4766892767 100644 --- a/include/asm-blackfin/cplb.h +++ b/include/asm-blackfin/cplb.h @@ -65,27 +65,33 @@ #define MAX_CPLBS (16 * 2) +#define ASYNC_MEMORY_CPLB_COVERAGE ((ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \ + ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE) / SIZE_4M) + /* * Number of required data CPLB switchtable entries * MEMSIZE / 4 (we mostly install 4M page size CPLBs * approx 16 for smaller 1MB page size CPLBs for allignment purposes * 1 for L1 Data Memory +* possibly 1 for L2 Data Memory * 1 for CONFIG_DEBUG_HUNT_FOR_ZERO * 1 for ASYNC Memory */ -#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2) +#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1 \ + + ASYNC_MEMORY_CPLB_COVERAGE) * 2) /* * Number of required instruction CPLB switchtable entries * MEMSIZE / 4 (we mostly install 4M page size CPLBs * approx 12 for smaller 1MB page size CPLBs for allignment purposes * 1 for L1 Instruction Memory +* possibly 1 for L2 Instruction Memory * 1 for CONFIG_DEBUG_HUNT_FOR_ZERO */ -#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2) +#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1 + 1) * 2) #define CPLB_ENABLE_ICACHE_P 0 From b4055d733d58135371c0c3a7f8c8899ca7b4f658 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 14:00:11 +0800 Subject: [PATCH 0031/2804] Blackfin arch: remove spurious KERN_EMERG log level in output Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/traps.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 0ec02fe663e9..0d2052abe41b 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -598,8 +598,7 @@ void dump_bfin_regs(struct pt_regs *fp, void *retaddr) unsigned short x = 0; for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) { if (!(i & 0xF)) - printk(KERN_EMERG "\n" KERN_EMERG - "0x%08x: ", i); + printk("\n" KERN_EMERG "0x%08x: ", i); if (get_user(x, (unsigned short *)i)) break; From be7b0d3711ec198a20edd769b9f1ad4f935a9bc2 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Sun, 5 Aug 2007 14:14:42 +0800 Subject: [PATCH 0032/2804] Blackfin arch: fix up header for BF533 Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf533/bf533.h | 54 ------------------------- 1 file changed, 54 deletions(-) diff --git a/include/asm-blackfin/mach-bf533/bf533.h b/include/asm-blackfin/mach-bf533/bf533.h index cb0785768b35..12a416931991 100644 --- a/include/asm-blackfin/mach-bf533/bf533.h +++ b/include/asm-blackfin/mach-bf533/bf533.h @@ -158,58 +158,4 @@ #define CPUID 0x0 #endif -#if (CONFIG_MEM_SIZE % 4) -#error "SDRAM mem size must be multible of 4MB" -#endif - -#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO) -#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK) -#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK) -#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID) - -/*Use the menuconfig cache policy here - CONFIG_BFIN_WT/CONFIG_BFIN_WB*/ - -#define ANOMALY_05000158_WORKAROUND 0x200 -#ifdef CONFIG_BFIN_WB /*Write Back Policy */ -#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \ - | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND) -#else /*Write Through */ -#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_DIRTY \ - | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND) -#endif - -#define L1_DMEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY) -#define SDRAM_DNON_CHBL (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY) -#define SDRAM_EBIU (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY) -#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY) - -#define SIZE_1K 0x00000400 /* 1K */ -#define SIZE_4K 0x00001000 /* 4K */ -#define SIZE_1M 0x00100000 /* 1M */ -#define SIZE_4M 0x00400000 /* 4M */ - -#define MAX_CPLBS (16 * 2) - -/* -* Number of required data CPLB switchtable entries -* MEMSIZE / 4 (we mostly install 4M page size CPLBs -* approx 16 for smaller 1MB page size CPLBs for allignment purposes -* 1 for L1 Data Memory -* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO -* 1 for ASYNC Memory -*/ - - -#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2) - -/* -* Number of required instruction CPLB switchtable entries -* MEMSIZE / 4 (we mostly install 4M page size CPLBs -* approx 12 for smaller 1MB page size CPLBs for allignment purposes -* 1 for L1 Instruction Memory -* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO -*/ - -#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2) - #endif /* __MACH_BF533_H__ */ From 2d8f161fe3d6f8d4a2a6f7d068757261b49191f7 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 14:06:16 +0800 Subject: [PATCH 0033/2804] Blackfin arch: update BOOT_LOAD update BOOT_LOAD help to reflect current state of the first 4k of our address space as well as add a memory range option to prevent invalid values Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 17f946920159..cdce8cc5b7b3 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -476,15 +476,16 @@ config ENET_FLASH_PIN config BOOT_LOAD hex "Kernel load address for booting" default "0x1000" + range 0x1000 0x20000000 help This option allows you to set the load address of the kernel. This can be useful if you are on a board which has a small amount of memory or you wish to reserve some memory at the beginning of the address space. - Note that you generally want to keep this value at or above 4k - (0x1000) as this will allow the kernel to capture NULL pointer - references. + Note that you need to keep this value above 4k (0x1000) as this + memory region is used to capture NULL pointer references as well + as some core kernel functions. comment "LED Status Indicators" depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM) From 2cbfe107434b9651168afb21015f3285e02beed3 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Sun, 5 Aug 2007 15:31:16 +0800 Subject: [PATCH 0034/2804] Blackfin arch: kill ezkit548 compiling warning kill ezkit548 compiling warning: - include/asm/cplb.h:42:5: warning: "ANOMALY_05000158" is not defined Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf548/anomaly.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h index 224837845c7c..d3638e3dfa9d 100644 --- a/include/asm-blackfin/mach-bf548/anomaly.h +++ b/include/asm-blackfin/mach-bf548/anomaly.h @@ -70,6 +70,7 @@ /* Anomalies that don't exist on this proc */ #define ANOMALY_05000125 (0) +#define ANOMALY_05000158 (0) #define ANOMALY_05000183 (0) #define ANOMALY_05000198 (0) #define ANOMALY_05000244 (0) From 8a26ac7043b0cb3b446ad9f9a3ec0992d0fea1f7 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Sun, 5 Aug 2007 16:14:58 +0800 Subject: [PATCH 0035/2804] Blackfin arch: Add DMA API to set curr descriptor address This API is necessary for DMA descriptor array mode. Signed-off-by: Sonic Zhang Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_dma_5xx.c | 15 ++++++++++++++- include/asm-blackfin/dma.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 62f5a35c13ee..f0db6c5c8d1a 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -270,10 +270,23 @@ void set_dma_next_desc_addr(unsigned int channel, unsigned long addr) dma_ch[channel].regs->next_desc_ptr = addr; SSYNC(); - pr_debug("set_dma_start_addr() : END\n"); + pr_debug("set_dma_next_desc_addr() : END\n"); } EXPORT_SYMBOL(set_dma_next_desc_addr); +void set_dma_curr_desc_addr(unsigned int channel, unsigned long addr) +{ + pr_debug("set_dma_curr_desc_addr() : BEGIN \n"); + + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->curr_desc_ptr = addr; + SSYNC(); + pr_debug("set_dma_curr_desc_addr() : END\n"); +} +EXPORT_SYMBOL(set_dma_curr_desc_addr); + void set_dma_x_count(unsigned int channel, unsigned short x_count) { BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE diff --git a/include/asm-blackfin/dma.h b/include/asm-blackfin/dma.h index 4269082b154a..b42a531e7a1b 100644 --- a/include/asm-blackfin/dma.h +++ b/include/asm-blackfin/dma.h @@ -152,6 +152,7 @@ struct dma_channel { /* functions to set register mode */ void set_dma_start_addr(unsigned int channel, unsigned long addr); void set_dma_next_desc_addr(unsigned int channel, unsigned long addr); +void set_dma_curr_desc_addr(unsigned int channel, unsigned long addr); void set_dma_x_count(unsigned int channel, unsigned short x_count); void set_dma_x_modify(unsigned int channel, short x_modify); void set_dma_y_count(unsigned int channel, unsigned short y_count); From 2615639758c0a9e0f0e14267c9cd2b83801eb8cf Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Sun, 5 Aug 2007 16:25:23 +0800 Subject: [PATCH 0036/2804] Blackfin arch: Allow ptrace access the fixed code. Signed-off-by: Jie Zhang Signed-off-by: Bryan Wu --- arch/blackfin/kernel/ptrace.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index ed800c7456dd..64ce5fea8609 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -44,6 +44,7 @@ #include #include #include +#include #define MAX_SHARED_LIBS 3 #define TEXT_OFFSET 0 @@ -169,6 +170,9 @@ static inline int is_user_addr_valid(struct task_struct *child, && start + len <= (unsigned long)sraml->addr + sraml->length) return 0; + if (start >= FIXED_CODE_START && start + len <= FIXED_CODE_END) + return 0; + return -EIO; } @@ -215,9 +219,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) copied = sizeof(tmp); } else #endif - copied = - access_process_vm(child, addr + add, &tmp, - sizeof(tmp), 0); + if (addr + add >= FIXED_CODE_START + && addr + add + sizeof(tmp) <= FIXED_CODE_END) { + memcpy(&tmp, (const void *)(addr + add), sizeof(tmp)); + copied = sizeof(tmp); + } else + copied = access_process_vm(child, addr + add, &tmp, + sizeof(tmp), 0); pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); if (copied != sizeof(tmp)) break; @@ -281,9 +289,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) copied = sizeof(data); } else #endif - copied = - access_process_vm(child, addr + add, &data, - sizeof(data), 1); + if (addr + add >= FIXED_CODE_START + && addr + add + sizeof(data) <= FIXED_CODE_END) { + memcpy((void *)(addr + add), &data, sizeof(data)); + copied = sizeof(data); + } else + copied = access_process_vm(child, addr + add, &data, + sizeof(data), 1); pr_debug("ptrace: copied size %d\n", copied); if (copied != sizeof(data)) break; From 0174dd59bb5f343e8981b5ea7a3dc782fad5b644 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 16:53:10 +0800 Subject: [PATCH 0037/2804] Blackfin arch: make sure to stub out ANOMALY_05000230 were appropriate Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf537/anomaly.h | 1 + include/asm-blackfin/mach-bf548/anomaly.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h index e377064b307c..71380ad29dfd 100644 --- a/include/asm-blackfin/mach-bf537/anomaly.h +++ b/include/asm-blackfin/mach-bf537/anomaly.h @@ -136,6 +136,7 @@ #define ANOMALY_05000158 (0) #define ANOMALY_05000183 (0) #define ANOMALY_05000198 (0) +#define ANOMALY_05000230 (0) #define ANOMALY_05000266 (0) #define ANOMALY_05000311 (0) diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h index d3638e3dfa9d..0d12dbe5232e 100644 --- a/include/asm-blackfin/mach-bf548/anomaly.h +++ b/include/asm-blackfin/mach-bf548/anomaly.h @@ -73,6 +73,7 @@ #define ANOMALY_05000158 (0) #define ANOMALY_05000183 (0) #define ANOMALY_05000198 (0) +#define ANOMALY_05000230 (0) #define ANOMALY_05000244 (0) #define ANOMALY_05000261 (0) #define ANOMALY_05000263 (0) From f0b5d12f2b3226c85258519d7725e63d9daf5e90 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 17:03:59 +0800 Subject: [PATCH 0038/2804] Blackfin arch: allow people to select the feature that is unavailable to the kernel - allow people to select the feature that is unavailable to the kernel: NMI, JTAG, or CYCLES. - change default NMI handler to simply dump hardware trace buffer. - remove default NMI handler completely as calling into kernel code is not safe move example handler to wiki so people dont haphazardly copy and paste this stuff thinking its safe Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 46 ++++++++++++++++++++ arch/blackfin/kernel/irqchip.c | 3 +- arch/blackfin/mach-bf533/head.S | 10 +++-- arch/blackfin/mach-bf537/head.S | 10 +++-- arch/blackfin/mach-bf548/head.S | 10 +++-- arch/blackfin/mach-bf561/head.S | 10 +++-- arch/blackfin/mach-common/entry.S | 18 +++++--- arch/blackfin/mach-common/interrupt.S | 28 ++++-------- arch/blackfin/mach-common/ints-priority-dc.c | 6 ++- arch/blackfin/mach-common/ints-priority-sc.c | 6 ++- include/asm-blackfin/irq_handler.h | 5 ++- 11 files changed, 107 insertions(+), 45 deletions(-) diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index cdce8cc5b7b3..26ebb0e8c431 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -521,6 +521,52 @@ config BFIN_IDLE_LED_NUM help Select the LED (marked on the board) for you to blink. +choice + prompt "Blackfin Exception Scratch Register" + default BFIN_SCRATCH_REG_RETN + help + Select the resource to reserve for the Exception handler: + - RETN: Non-Maskable Interrupt (NMI) + - RETE: Exception Return (JTAG/ICE) + - CYCLES: Performance counter + + If you are unsure, please select "RETN". + +config BFIN_SCRATCH_REG_RETN + bool "RETN" + help + Use the RETN register in the Blackfin exception handler + as a stack scratch register. This means you cannot + safely use NMI on the Blackfin while running Linux, but + you can debug the system with a JTAG ICE and use the + CYCLES performance registers. + + If you are unsure, please select "RETN". + +config BFIN_SCRATCH_REG_RETE + bool "RETE" + help + Use the RETE register in the Blackfin exception handler + as a stack scratch register. This means you cannot + safely use a JTAG ICE while debugging a Blackfin board, + but you can safely use the CYCLES performance registers + and the NMI. + + If you are unsure, please select "RETN". + +config BFIN_SCRATCH_REG_CYCLES + bool "CYCLES" + help + Use the CYCLES register in the Blackfin exception handler + as a stack scratch register. This means you cannot + safely use the CYCLES performance registers on a Blackfin + board at anytime, but you can debug the system with a JTAG + ICE and use the NMI. + + If you are unsure, please select "RETN". + +endchoice + # # Sorry - but you need to put the hex address here - # diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c index 462ae41144c7..73647c158774 100644 --- a/arch/blackfin/kernel/irqchip.c +++ b/arch/blackfin/kernel/irqchip.c @@ -98,9 +98,8 @@ int show_interrupts(struct seq_file *p, void *v) */ #ifdef CONFIG_DO_IRQ_L1 -asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text)); +__attribute__((l1_text)) #endif - asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs; diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S index 1d5b9dbbbaa7..3be6feefa8a9 100644 --- a/arch/blackfin/mach-bf533/head.S +++ b/arch/blackfin/mach-bf533/head.S @@ -53,10 +53,12 @@ __INIT ENTRY(__start) /* R0: argument of command line string, passed from uboot, save it */ R7 = R0; - /* Set the SYSCFG register: - * Enable Cycle Counter and Nesting Of Interrupts (3rd Bit) - */ - R0 = 0x36; + /* Enable Cycle Counter and Nesting Of Interrupts */ +#ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES + R0 = SYSCFG_SNEN; +#else + R0 = SYSCFG_SNEN | SYSCFG_CCEN; +#endif SYSCFG = R0; R0 = 0; diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S index 6dbcb77c8d36..0836bfdcc6c5 100644 --- a/arch/blackfin/mach-bf537/head.S +++ b/arch/blackfin/mach-bf537/head.S @@ -51,10 +51,12 @@ __INIT ENTRY(__start) /* R0: argument of command line string, passed from uboot, save it */ R7 = R0; - /* Set the SYSCFG register: - * Enable Cycle Counter and Nesting Of Interrupts (3rd Bit) - */ - R0 = 0x36; + /* Enable Cycle Counter and Nesting Of Interrupts */ +#ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES + R0 = SYSCFG_SNEN; +#else + R0 = SYSCFG_SNEN | SYSCFG_CCEN; +#endif SYSCFG = R0; R0 = 0; diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S index 4c7d49f41187..937fbef26a51 100644 --- a/arch/blackfin/mach-bf548/head.S +++ b/arch/blackfin/mach-bf548/head.S @@ -50,9 +50,13 @@ ENTRY(__start) ENTRY(__stext) /* R0: argument of command line string, passed from uboot, save it */ R7 = R0; - /* Set the SYSCFG register */ - R0 = 0x36; - SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/ + /* Enable Cycle Counter and Nesting Of Interrupts */ +#ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES + R0 = SYSCFG_SNEN; +#else + R0 = SYSCFG_SNEN | SYSCFG_CCEN; +#endif + SYSCFG = R0; R0 = 0; /* Clear Out All the data and pointer Registers*/ diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S index 8c9f73b8e579..139f4cff801b 100644 --- a/arch/blackfin/mach-bf561/head.S +++ b/arch/blackfin/mach-bf561/head.S @@ -51,10 +51,12 @@ __INIT ENTRY(__start) /* R0: argument of command line string, passed from uboot, save it */ R7 = R0; - /* Set the SYSCFG register: - * Enable Cycle Counter and Nesting Of Interrupts (3rd Bit) - */ - R0 = 0x36; + /* Enable Cycle Counter and Nesting Of Interrupts */ +#ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES + R0 = SYSCFG_SNEN; +#else + R0 = SYSCFG_SNEN | SYSCFG_CCEN; +#endif SYSCFG = R0; R0 = 0; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index ab278a72f282..2188f81c6456 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -58,6 +58,14 @@ #include +#if defined(CONFIG_BFIN_SCRATCH_REG_RETN) +# define EX_SCRATCH_REG RETN +#elif defined(CONFIG_BFIN_SCRATCH_REG_RETE) +# define EX_SCRATCH_REG RETE +#else +# define EX_SCRATCH_REG CYCLES +#endif + #ifdef CONFIG_EXCPT_IRQ_SYSC_L1 .section .l1.text #else @@ -93,7 +101,7 @@ ENTRY(_ex_icplb) call __cplb_hdr; DEBUG_START_HWTRACE(p5, r7) RESTORE_ALL_SYS - SP = RETN; + SP = EX_SCRATCH_REG; rtx; ENDPROC(_ex_icplb) @@ -102,7 +110,7 @@ ENTRY(_ex_syscall) (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; raise 15; /* invoked by TRAP #0, for sys call */ - sp = retn; + sp = EX_SCRATCH_REG; rtx ENDPROC(_ex_syscall) @@ -145,7 +153,7 @@ _return_from_exception: #endif (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; - sp = retn; + sp = EX_SCRATCH_REG; rtx; ENDPROC(_ex_soft_bp) @@ -204,7 +212,7 @@ ENTRY(_ex_trap_c) DEBUG_START_HWTRACE(p5, r7) (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; - SP = RETN; + SP = EX_SCRATCH_REG; raise 5; rtx; ENDPROC(_ex_trap_c) @@ -279,7 +287,7 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ * covered by a CPLB. Switch to an exception stack; use RETN as a * scratch register (for want of a better option). */ - retn = sp; + EX_SCRATCH_REG = sp; sp.l = _exception_stack_top; sp.h = _exception_stack_top; /* Try to deal with syscalls quickly. */ diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 1d5ba5e3d91c..c6b32fe0f6e9 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -177,27 +177,15 @@ ENTRY(_evt_ivhw) jump .Lcommon_restore_context; #endif -/* interrupt routine for evt2 - 2. This is NMI. */ -ENTRY(_evt_evt2) - SAVE_CONTEXT -#ifdef CONFIG_FRAME_POINTER - fp = 0; -#endif -#if ANOMALY_05000283 - cc = r7 == r7; - p5.h = 0xffc0; - p5.l = 0x0014; - if cc jump 1f; - r7.l = W[p5]; -1: -#endif - r0 = IRQ_NMI; - r1 = sp; - SP += -12; - call _asm_do_IRQ; - SP += 12; - RESTORE_CONTEXT +/* Interrupt routine for evt2 (NMI). + * We don't actually use this, so just return. + * For inner circle type details, please see: + * http://docs.blackfin.uclinux.org/doku.php?id=linux:nmi + */ +ENTRY(_evt_nmi) +.weak _evt_nmi rtn; +ENDPROC(_evt_nmi) /* interrupt routine for core timer - 6 */ ENTRY(_evt_timer) diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c index 684d306ab6bb..2db3546fc874 100644 --- a/arch/blackfin/mach-common/ints-priority-dc.c +++ b/arch/blackfin/mach-common/ints-priority-dc.c @@ -362,7 +362,11 @@ void __init init_exception_vectors(void) { SSYNC(); - bfin_write_EVT2(evt_evt2); + /* cannot program in software: + * evt0 - emulation (jtag) + * evt1 - reset + */ + bfin_write_EVT2(evt_nmi); bfin_write_EVT3(trap); bfin_write_EVT5(evt_ivhw); bfin_write_EVT6(evt_timer); diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c index a2016af65eb0..d3b7672b2b94 100644 --- a/arch/blackfin/mach-common/ints-priority-sc.c +++ b/arch/blackfin/mach-common/ints-priority-sc.c @@ -721,7 +721,11 @@ void __init init_exception_vectors(void) { SSYNC(); - bfin_write_EVT2(evt_evt2); + /* cannot program in software: + * evt0 - emulation (jtag) + * evt1 - reset + */ + bfin_write_EVT2(evt_nmi); bfin_write_EVT3(trap); bfin_write_EVT5(evt_ivhw); bfin_write_EVT6(evt_timer); diff --git a/include/asm-blackfin/irq_handler.h b/include/asm-blackfin/irq_handler.h index 6a768315bbf7..f13cd73b0966 100644 --- a/include/asm-blackfin/irq_handler.h +++ b/include/asm-blackfin/irq_handler.h @@ -1,12 +1,15 @@ #ifndef _IRQ_HANDLER_H #define _IRQ_HANDLER_H +#include +#include + /* BASE LEVEL interrupt handler routines */ asmlinkage void evt_exception(void); asmlinkage void trap(void); asmlinkage void evt_ivhw(void); asmlinkage void evt_timer(void); -asmlinkage void evt_evt2(void); +asmlinkage void evt_nmi(void); asmlinkage void evt_evt7(void); asmlinkage void evt_evt8(void); asmlinkage void evt_evt9(void); From dbcc78bebe9daed8998d9f7c4e30bd3b73a4a169 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 17:06:48 +0800 Subject: [PATCH 0039/2804] Blackfin arch: all our other ports call this SIZE rather than SPI_LEN Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf533/defBF532.h | 2 +- include/asm-blackfin/mach-bf537/defBF534.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-blackfin/mach-bf533/defBF532.h b/include/asm-blackfin/mach-bf533/defBF532.h index 6a3cf93f8b57..81b4af17c6a3 100644 --- a/include/asm-blackfin/mach-bf533/defBF532.h +++ b/include/asm-blackfin/mach-bf533/defBF532.h @@ -928,7 +928,7 @@ #define GM 0x00000008 /* When RDBR full, get more (=1) data or discard (=0) incoming Data */ #define PSSE 0x00000010 /* Enable (=1) Slave-Select input for Master. */ #define EMISO 0x00000020 /* Enable (=1) MISO pin as an output. */ -#define SPI_LEN 0x00000100 /* Word length (0 => 8 bits, 1 => 16 bits) */ +#define SIZE 0x00000100 /* Word length (0 => 8 bits, 1 => 16 bits) */ #define LSBF 0x00000200 /* Data format (0 => MSB sent/received first 1 => LSB sent/received first) */ #define CPHA 0x00000400 /* Clock phase (0 => SPICLK starts toggling in middle of xfer, 1 => SPICLK toggles at the beginning of xfer. */ #define CPOL 0x00000800 /* Clock polarity (0 => active-high, 1 => active-low) */ diff --git a/include/asm-blackfin/mach-bf537/defBF534.h b/include/asm-blackfin/mach-bf537/defBF534.h index 1859f2fee5a7..dce4c543a339 100644 --- a/include/asm-blackfin/mach-bf537/defBF534.h +++ b/include/asm-blackfin/mach-bf537/defBF534.h @@ -1165,7 +1165,7 @@ #define GM 0x0008 /* Get More (When RDBR Full, Overwrite/Discard*) */ #define PSSE 0x0010 /* Slave-Select Input Enable */ #define EMISO 0x0020 /* Enable MISO As Output */ -#define SPI_SIZE 0x0100 /* Size of Words (16/8* Bits) */ +#define SIZE 0x0100 /* Size of Words (16/8* Bits) */ #define LSBF 0x0200 /* LSB First */ #define CPHA 0x0400 /* Clock Phase */ #define CPOL 0x0800 /* Clock Polarity */ From 1ffe6646babf8471714e649849ec2c9662bf410c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 17:14:04 +0800 Subject: [PATCH 0040/2804] Blackfin arch: add an exception request/free api add an exception request/free api similar to the interrupt request/fre api so people can utilize the free software based exceptions for their own purposes Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/traps.c | 38 +++++++++++++++++++++++++-- arch/blackfin/mach-common/entry.S | 42 ++++++++++++++++-------------- include/asm-blackfin/irq_handler.h | 8 ++++++ 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 0d2052abe41b..1a8a5f171bc8 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -51,8 +51,6 @@ void __init trap_init(void) CSYNC(); } -asmlinkage void trap_c(struct pt_regs *fp); - int kstack_depth_to_print = 48; #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON @@ -693,6 +691,42 @@ asmlinkage int sys_bfin_spinlock(int *spinlock) return ret; } +int bfin_request_exception(unsigned int exception, void (*handler)(void)) +{ + void (*curr_handler)(void); + + if (exception > 0x3F) + return -EINVAL; + + curr_handler = ex_table[exception]; + + if (curr_handler != ex_replaceable) + return -EBUSY; + + ex_table[exception] = handler; + + return 0; +} +EXPORT_SYMBOL(bfin_request_exception); + +int bfin_free_exception(unsigned int exception, void (*handler)(void)) +{ + void (*curr_handler)(void); + + if (exception > 0x3F) + return -EINVAL; + + curr_handler = ex_table[exception]; + + if (curr_handler != handler) + return -EBUSY; + + ex_table[exception] = ex_replaceable; + + return 0; +} +EXPORT_SYMBOL(bfin_free_exception); + void panic_cplb_error(int cplb_panic, struct pt_regs *fp) { switch (cplb_panic) { diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 2188f81c6456..3feca05694f8 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -143,7 +143,7 @@ ENTRY(_ex_single_step) cc = r6 == r7; if !cc jump _ex_trap_c; -_return_from_exception: +ENTRY(_return_from_exception) DEBUG_START_HWTRACE(p5, r7) #if ANOMALY_05000257 R7=LC0; @@ -171,6 +171,9 @@ ENTRY(_handle_bad_cplb) [--sp] = ASTAT; [--sp] = (R7:6, P5:4); +ENTRY(_ex_replaceable) + nop; + ENTRY(_ex_trap_c) /* Call C code (trap_c) to handle the exception, which most * likely involves sending a signal to the current process. @@ -298,8 +301,8 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ r6.l = lo(SEQSTAT_EXCAUSE); r6.h = hi(SEQSTAT_EXCAUSE); r7 = r7 & r6; - p5.h = _extable; - p5.l = _extable; + p5.h = _ex_table; + p5.l = _ex_table; p4 = r7; p5 = p5 + (p4 << 2); p4 = [p5]; @@ -818,28 +821,27 @@ ENTRY(_software_trace_buff) #else .data #endif -ALIGN -_extable: +ENTRY(_ex_table) /* entry for each EXCAUSE[5:0] * This table must be in sync with the table in ./kernel/traps.c * EXCPT instruction can provide 4 bits of EXCAUSE, allowing 16 to be user defined */ - .long _ex_syscall; /* 0x00 - User Defined - Linux Syscall */ + .long _ex_syscall /* 0x00 - User Defined - Linux Syscall */ .long _ex_soft_bp /* 0x01 - User Defined - Software breakpoint */ - .long _ex_trap_c /* 0x02 - User Defined */ + .long _ex_replaceable /* 0x02 - User Defined */ .long _ex_trap_c /* 0x03 - User Defined - userspace stack overflow */ - .long _ex_trap_c /* 0x04 - User Defined */ - .long _ex_trap_c /* 0x05 - User Defined */ - .long _ex_trap_c /* 0x06 - User Defined */ - .long _ex_trap_c /* 0x07 - User Defined */ - .long _ex_trap_c /* 0x08 - User Defined */ - .long _ex_trap_c /* 0x09 - User Defined */ - .long _ex_trap_c /* 0x0A - User Defined */ - .long _ex_trap_c /* 0x0B - User Defined */ - .long _ex_trap_c /* 0x0C - User Defined */ - .long _ex_trap_c /* 0x0D - User Defined */ - .long _ex_trap_c /* 0x0E - User Defined */ - .long _ex_trap_c /* 0x0F - User Defined */ + .long _ex_replaceable /* 0x04 - User Defined */ + .long _ex_replaceable /* 0x05 - User Defined */ + .long _ex_replaceable /* 0x06 - User Defined */ + .long _ex_replaceable /* 0x07 - User Defined */ + .long _ex_replaceable /* 0x08 - User Defined */ + .long _ex_replaceable /* 0x09 - User Defined */ + .long _ex_replaceable /* 0x0A - User Defined */ + .long _ex_replaceable /* 0x0B - User Defined */ + .long _ex_replaceable /* 0x0C - User Defined */ + .long _ex_replaceable /* 0x0D - User Defined */ + .long _ex_replaceable /* 0x0E - User Defined */ + .long _ex_replaceable /* 0x0F - User Defined */ .long _ex_single_step /* 0x10 - HW Single step */ #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND .long _ex_trace_buff_full /* 0x11 - Trace Buffer Full */ @@ -893,8 +895,8 @@ _extable: .long _ex_trap_c /* 0x3D - Reserved */ .long _ex_trap_c /* 0x3E - Reserved */ .long _ex_trap_c /* 0x3F - Reserved */ +END(_ex_table) -ALIGN ENTRY(_sys_call_table) .long _sys_restart_syscall /* 0 */ .long _sys_exit diff --git a/include/asm-blackfin/irq_handler.h b/include/asm-blackfin/irq_handler.h index f13cd73b0966..19534c133c93 100644 --- a/include/asm-blackfin/irq_handler.h +++ b/include/asm-blackfin/irq_handler.h @@ -20,5 +20,13 @@ asmlinkage void evt_evt13(void); asmlinkage void evt_soft_int1(void); asmlinkage void evt_system_call(void); asmlinkage void init_exception_buff(void); +asmlinkage void trap_c(struct pt_regs *fp); +asmlinkage void ex_replaceable(void); + +extern void *ex_table[]; +extern void return_from_exception(void); + +extern int bfin_request_exception(unsigned int exception, void (*handler)(void)); +extern int bfin_free_exception(unsigned int exception, void (*handler)(void)); #endif From fbeb7370b6eef14bf12787d05c7460fae562d0be Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 27 Aug 2007 15:02:20 +0800 Subject: [PATCH 0041/2804] Blackfin arch: parse input sections properly when using -ffunction-sections/-fdata-sections Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/vmlinux.lds.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index fb53780247bc..e40b66ae1b79 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -46,6 +46,7 @@ SECTIONS __text = .; _text = .; __stext = .; + *(.text.*) TEXT_TEXT SCHED_TEXT LOCK_TEXT @@ -73,6 +74,7 @@ SECTIONS . = ALIGN(THREAD_SIZE); *(.data.init_task) DATA_DATA + *(.data.*) CONSTRUCTORS . = ALIGN(32); @@ -164,7 +166,7 @@ SECTIONS { . = ALIGN(4); ___bss_start = .; - *(.bss) + *(.bss .bss.*) *(COMMON) . = ALIGN(4); ___bss_stop = .; From d8350e704e5a47784d108d57c27dbb7b9c0a4369 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Thu, 11 Oct 2007 00:03:39 +0800 Subject: [PATCH 0042/2804] Blackfin arch: Board defconfig updating Signed-off-by: Bryan Wu --- arch/blackfin/configs/BF533-EZKIT_defconfig | 233 ++++------ arch/blackfin/configs/BF533-STAMP_defconfig | 272 +++++------ arch/blackfin/configs/BF537-STAMP_defconfig | 286 ++++++------ arch/blackfin/configs/BF548-EZKIT_defconfig | 490 +++++++++++++------- arch/blackfin/configs/BF561-EZKIT_defconfig | 213 ++++----- arch/blackfin/configs/PNAV-10_defconfig | 286 ++++++------ 6 files changed, 918 insertions(+), 862 deletions(-) diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig index 02141827e595..57f58d5cd47a 100644 --- a/arch/blackfin/configs/BF533-EZKIT_defconfig +++ b/arch/blackfin/configs/BF533-EZKIT_defconfig @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21.5 +# Linux kernel version: 2.6.22.6 # # CONFIG_MMU is not set # CONFIG_FPU is not set @@ -15,8 +15,9 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y # CONFIG_GENERIC_TIME is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_GPIO=y CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_IRQCHIP_DEMUX_GPIO=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -40,7 +41,9 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_TASKSTATS is not set # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set CONFIG_BLK_DEV_INITRD=y @@ -58,15 +61,20 @@ CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_VM_EVENT_COUNTERS=y CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3 -CONFIG_BUDDY=y # CONFIG_NP2 is not set CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set # # Loadable module support @@ -184,19 +192,17 @@ CONFIG_WDTIMER=13 # CONFIG_CMDLINE_BOOL is not set # -# Board Setup +# Clock/PLL Setup # CONFIG_CLKIN_HZ=27000000 -CONFIG_MEM_SIZE=32 -CONFIG_MEM_ADD_WIDTH=9 -CONFIG_BOOT_LOAD=0x1000 +# CONFIG_BFIN_KERNEL_CLOCK is not set +CONFIG_MAX_VCO_HZ=750000000 +CONFIG_MIN_VCO_HZ=50000000 +CONFIG_MAX_SCLK_HZ=133000000 +CONFIG_MIN_SCLK_HZ=27000000 # -# Blackfin Kernel Optimizations -# - -# -# Timer Tick +# Kernel Timer/Scheduler # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y @@ -204,6 +210,20 @@ CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# +# Memory Setup +# +CONFIG_MEM_SIZE=32 +CONFIG_MEM_ADD_WIDTH=9 +CONFIG_BOOT_LOAD=0x1000 +CONFIG_BFIN_SCRATCH_REG_RETN=y +# CONFIG_BFIN_SCRATCH_REG_RETE is not set +# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set + +# +# Blackfin Kernel Optimizations +# + # # Memory Optimizations # @@ -251,11 +271,6 @@ CONFIG_BFIN_DCACHE=y CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 -# -# Clock Settings -# -# CONFIG_BFIN_KERNEL_CLOCK is not set - # # Asynchonous Memory Configuration # @@ -277,22 +292,19 @@ CONFIG_C_AMBEN_ALL=y CONFIG_BANK_0=0x7BB0 CONFIG_BANK_1=0x7BB0 CONFIG_BANK_2=0x7BB0 -CONFIG_BANK_3=0x99B3 +CONFIG_BANK_3=0xAAC3 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # # CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set -# -# PCI Hotplug Support -# - # # Executable file formats # @@ -327,7 +339,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -368,20 +379,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_NETLABEL is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -448,7 +447,16 @@ CONFIG_IRTTY_SIR=m # FIR device drivers # # CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set # # Device Drivers @@ -466,10 +474,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set @@ -513,7 +517,6 @@ CONFIG_MTD_MW320D=m CONFIG_MTD_RAM=y CONFIG_MTD_ROM=m # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access @@ -550,16 +553,13 @@ CONFIG_BFIN_FLASH_BANK_3=0x7BB0 # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# # CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set # -# OneNAND Flash Device Drivers +# UBI - Unsorted block images # -# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_UBI is not set # # Parallel port support @@ -587,10 +587,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # Misc devices # - -# -# ATA/ATAPI/MFM/RLL support -# # CONFIG_IDE is not set # @@ -599,10 +595,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # CONFIG_SCSI_NETLINK is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# # CONFIG_ATA is not set # @@ -610,19 +602,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_MD is not set -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - # # Network device support # @@ -631,10 +610,6 @@ CONFIG_NETDEVICES=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set - -# -# PHY device support -# # CONFIG_PHYLIB is not set # @@ -644,27 +619,15 @@ CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_SMC91X=y # CONFIG_SMSC911X is not set +# CONFIG_DM9000 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y # -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces +# Wireless LAN # +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -688,6 +651,7 @@ CONFIG_SMC91X=y # CONFIG_INPUT=m # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -704,6 +668,7 @@ CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set @@ -718,7 +683,7 @@ CONFIG_INPUT_EVDEV=m # # CONFIG_AD9960 is not set # CONFIG_SPI_ADC_BF533 is not set -# CONFIG_BF5xx_PFLAGS is not set +# CONFIG_BFIN_PFLAGS is not set # CONFIG_BF5xx_PPIFCD is not set # CONFIG_BF5xx_TIMERS is not set # CONFIG_BF5xx_PPI is not set @@ -758,10 +723,6 @@ CONFIG_UNIX98_PTYS=y # IPMI # # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -773,7 +734,6 @@ CONFIG_BFIN_WDT=y CONFIG_HW_RANDOM=y # CONFIG_GEN_RTC is not set CONFIG_BLACKFIN_DPMC=y -# CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set @@ -781,10 +741,6 @@ CONFIG_BLACKFIN_DPMC=y # TPM devices # # CONFIG_TCG_TPM is not set - -# -# I2C support -# # CONFIG_I2C is not set # @@ -803,22 +759,22 @@ CONFIG_SPI_BFIN=y # SPI Protocol Masters # # CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set # # Dallas's 1-wire bus # # CONFIG_W1 is not set - -# -# Hardware Monitoring support -# CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_F71805F is not set # CONFIG_SENSORS_LM70 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83627HF is not set # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -830,16 +786,19 @@ CONFIG_HWMON=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y # # Graphics support # # CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set # CONFIG_FB is not set # @@ -861,6 +820,10 @@ CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB is not set +# +# Enable Host or Gadget support to see Inventra options +# + # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # @@ -869,11 +832,6 @@ CONFIG_USB_ARCH_HAS_HCD=y # USB Gadget Support # # CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_SPI_MMC is not set # CONFIG_MMC is not set # @@ -913,17 +871,29 @@ CONFIG_RTC_INTF_SYSFS=y CONFIG_RTC_INTF_PROC=y CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set # -# RTC drivers +# I2C RTC drivers +# + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set + +# +# Platform RTC drivers # # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_TEST is not set -# CONFIG_RTC_DRV_MAX6902 is not set # CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# CONFIG_RTC_DRV_BFIN=y # @@ -939,14 +909,6 @@ CONFIG_RTC_DRV_BFIN=y # DMA Devices # -# -# Auxiliary Display support -# - -# -# Virtualization -# - # # PBX support # @@ -1047,6 +1009,7 @@ CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m @@ -1124,14 +1087,20 @@ CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set +CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_SERIAL_EARLY_INIT is not set +CONFIG_DEBUG_MMRS=y CONFIG_DEBUG_HUNT_FOR_ZERO=y +CONFIG_DEBUG_BFIN_HWTRACE_ON=y +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0 +# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set +CONFIG_EARLY_PRINTK=y CONFIG_CPLB_INFO=y CONFIG_ACCESS_CHECK=y @@ -1154,6 +1123,7 @@ CONFIG_SECURITY_CAPABILITIES=m CONFIG_BITREVERSE=y CONFIG_CRC_CCITT=m # CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y @@ -1161,3 +1131,4 @@ CONFIG_ZLIB_DEFLATE=m CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig index 3dbe22d7d909..306302baff06 100644 --- a/arch/blackfin/configs/BF533-STAMP_defconfig +++ b/arch/blackfin/configs/BF533-STAMP_defconfig @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21.5 +# Linux kernel version: 2.6.22.6 # # CONFIG_MMU is not set # CONFIG_FPU is not set @@ -15,8 +15,9 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y # CONFIG_GENERIC_TIME is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_GPIO=y CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_IRQCHIP_DEMUX_GPIO=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -40,7 +41,9 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_TASKSTATS is not set # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set CONFIG_BLK_DEV_INITRD=y @@ -58,15 +61,20 @@ CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_VM_EVENT_COUNTERS=y CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3 -CONFIG_BUDDY=y # CONFIG_NP2 is not set CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set # # Loadable module support @@ -185,9 +193,27 @@ CONFIG_WDTIMER=13 # CONFIG_CMDLINE_BOOL is not set # -# Board Setup +# Clock/PLL Setup # CONFIG_CLKIN_HZ=11059200 +# CONFIG_BFIN_KERNEL_CLOCK is not set +CONFIG_MAX_VCO_HZ=750000000 +CONFIG_MIN_VCO_HZ=50000000 +CONFIG_MAX_SCLK_HZ=133000000 +CONFIG_MIN_SCLK_HZ=27000000 + +# +# Kernel Timer/Scheduler +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 + +# +# Memory Setup +# CONFIG_MEM_SIZE=128 CONFIG_MEM_ADD_WIDTH=11 CONFIG_ENET_FLASH_PIN=0 @@ -198,6 +224,9 @@ CONFIG_BOOT_LOAD=0x1000 # # CONFIG_BFIN_ALIVE_LED is not set # CONFIG_BFIN_IDLE_LED is not set +CONFIG_BFIN_SCRATCH_REG_RETN=y +# CONFIG_BFIN_SCRATCH_REG_RETE is not set +# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set CONFIG_BFIN_ALIVE_LED_PORT=0xFFC00700 CONFIG_BFIN_ALIVE_LED_DPORT=0xFFC00730 CONFIG_BFIN_IDLE_LED_PORT=0xFFC00700 @@ -207,15 +236,6 @@ CONFIG_BFIN_IDLE_LED_DPORT=0xFFC00730 # Blackfin Kernel Optimizations # -# -# Timer Tick -# -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_300 is not set -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 - # # Memory Optimizations # @@ -263,11 +283,6 @@ CONFIG_BFIN_DCACHE=y CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 -# -# Clock Settings -# -# CONFIG_BFIN_KERNEL_CLOCK is not set - # # Asynchonous Memory Configuration # @@ -289,22 +304,19 @@ CONFIG_C_AMBEN_ALL=y CONFIG_BANK_0=0x7BB0 CONFIG_BANK_1=0x7BB0 CONFIG_BANK_2=0x7BB0 -CONFIG_BANK_3=0x99B3 +CONFIG_BANK_3=0xAAC3 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # # CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set -# -# PCI Hotplug Support -# - # # Executable file formats # @@ -339,7 +351,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -380,20 +391,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_NETLABEL is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -460,7 +459,16 @@ CONFIG_IRTTY_SIR=m # FIR device drivers # # CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set # # Device Drivers @@ -478,10 +486,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set @@ -525,7 +529,6 @@ CONFIG_MTD_MW320D=m CONFIG_MTD_RAM=y CONFIG_MTD_ROM=m # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access @@ -562,16 +565,13 @@ CONFIG_BFIN_FLASH_BANK_3=0x7BB0 # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# # CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set # -# OneNAND Flash Device Drivers +# UBI - Unsorted block images # -# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_UBI is not set # # Parallel port support @@ -599,10 +599,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # Misc devices # - -# -# ATA/ATAPI/MFM/RLL support -# # CONFIG_IDE is not set # @@ -611,10 +607,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # CONFIG_SCSI_NETLINK is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# # CONFIG_ATA is not set # @@ -622,19 +614,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_MD is not set -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - # # Network device support # @@ -643,10 +622,6 @@ CONFIG_NETDEVICES=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set - -# -# PHY device support -# # CONFIG_PHYLIB is not set # @@ -656,27 +631,15 @@ CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_SMC91X=y # CONFIG_SMSC911X is not set +# CONFIG_DM9000 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y # -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces +# Wireless LAN # +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -700,6 +663,7 @@ CONFIG_SMC91X=y # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -716,8 +680,14 @@ CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set # CONFIG_INPUT_TOUCHSCREEN is not set CONFIG_INPUT_MISC=y +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set # CONFIG_INPUT_UINPUT is not set # CONFIG_BF53X_PFBUTTONS is not set CONFIG_TWI_KEYPAD=m @@ -734,7 +704,7 @@ CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=39 # # CONFIG_AD9960 is not set # CONFIG_SPI_ADC_BF533 is not set -# CONFIG_BF5xx_PFLAGS is not set +# CONFIG_BFIN_PFLAGS is not set # CONFIG_BF5xx_PPIFCD is not set # CONFIG_BF5xx_TIMERS is not set # CONFIG_BF5xx_PPI is not set @@ -777,10 +747,6 @@ CONFIG_UNIX98_PTYS=y # IPMI # # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -792,7 +758,6 @@ CONFIG_BFIN_WDT=y CONFIG_HW_RANDOM=y # CONFIG_GEN_RTC is not set CONFIG_BLACKFIN_DPMC=y -# CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set @@ -800,11 +765,8 @@ CONFIG_BLACKFIN_DPMC=y # TPM devices # # CONFIG_TCG_TPM is not set - -# -# I2C support -# CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y CONFIG_I2C_CHARDEV=m # @@ -818,10 +780,11 @@ CONFIG_I2C_ALGOBIT=m # I2C Hardware Bus support # # CONFIG_I2C_BLACKFIN_GPIO is not set +# CONFIG_I2C_GPIO is not set # CONFIG_I2C_OCORES is not set # CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_SIMTEC is not set # CONFIG_I2C_STUB is not set -# CONFIG_I2C_PCA_ISA is not set # # Miscellaneous I2C Chip support @@ -857,18 +820,16 @@ CONFIG_SPI_BFIN=y # SPI Protocol Masters # # CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set # # Dallas's 1-wire bus # # CONFIG_W1 is not set - -# -# Hardware Monitoring support -# CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_AD7418 is not set # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -896,6 +857,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_SMSC47M1 is not set @@ -920,22 +882,30 @@ CONFIG_HWMON=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y # # Graphics support # # CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set CONFIG_FB=m CONFIG_FIRMWARE_EDID=y # CONFIG_FB_DDC is not set CONFIG_FB_CFB_FILLRECT=m CONFIG_FB_CFB_COPYAREA=m CONFIG_FB_CFB_IMAGEBLIT=m +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y # CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set @@ -957,10 +927,6 @@ CONFIG_ADV7393_1XMEM=y # CONFIG_ADV7393_2XMEM is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set - -# -# Logo configuration -# # CONFIG_LOGO is not set # @@ -1001,7 +967,6 @@ CONFIG_SND_BLACKFIN_AD1836_TDM=y # CONFIG_SND_BLACKFIN_AD1836_I2S is not set CONFIG_SND_BLACKFIN_AD1836_MULSUB=y # CONFIG_SND_BLACKFIN_AD1836_5P1 is not set -CONFIG_SND_BLACKFIN_AD1981B=m CONFIG_SND_BLACKFIN_SPORT=0 CONFIG_SND_BLACKFIN_SPI_PFBIT=4 CONFIG_SND_BFIN_AD73311=m @@ -1009,10 +974,15 @@ CONFIG_SND_BFIN_SPORT=0 CONFIG_SND_BFIN_AD73311_SE=4 # -# SoC audio support +# System on Chip audio support # # CONFIG_SND_SOC is not set +# +# SoC Audio for the ADI Blackfin +# +# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set + # # Open Sound System # @@ -1032,6 +1002,10 @@ CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB is not set +# +# Enable Host or Gadget support to see Inventra options +# + # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # @@ -1040,11 +1014,6 @@ CONFIG_USB_ARCH_HAS_HCD=y # USB Gadget Support # # CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_SPI_MMC is not set # CONFIG_MMC is not set # @@ -1084,23 +1053,37 @@ CONFIG_RTC_INTF_SYSFS=y CONFIG_RTC_INTF_PROC=y CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set # -# RTC drivers +# I2C RTC drivers # -# CONFIG_RTC_DRV_X1205 is not set # CONFIG_RTC_DRV_DS1307 is not set -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_ISL1208 is not set # CONFIG_RTC_DRV_DS1672 is not set -# CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_PCF8563 is not set -# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6900 is not set # CONFIG_RTC_DRV_RS5C372 is not set -# CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_MAX6902 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# CONFIG_RTC_DRV_BFIN=y # @@ -1116,14 +1099,6 @@ CONFIG_RTC_DRV_BFIN=y # DMA Devices # -# -# Auxiliary Display support -# - -# -# Virtualization -# - # # PBX support # @@ -1224,6 +1199,7 @@ CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m @@ -1301,14 +1277,20 @@ CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set +CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_SERIAL_EARLY_INIT is not set +CONFIG_DEBUG_MMRS=y CONFIG_DEBUG_HUNT_FOR_ZERO=y +CONFIG_DEBUG_BFIN_HWTRACE_ON=y +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0 +# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set +CONFIG_EARLY_PRINTK=y CONFIG_CPLB_INFO=y CONFIG_ACCESS_CHECK=y @@ -1331,6 +1313,7 @@ CONFIG_SECURITY_CAPABILITIES=m CONFIG_BITREVERSE=y CONFIG_CRC_CCITT=m # CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y @@ -1338,3 +1321,4 @@ CONFIG_ZLIB_DEFLATE=m CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig index a28e0316e90c..828b604438eb 100644 --- a/arch/blackfin/configs/BF537-STAMP_defconfig +++ b/arch/blackfin/configs/BF537-STAMP_defconfig @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21.5 +# Linux kernel version: 2.6.22.6 # # CONFIG_MMU is not set # CONFIG_FPU is not set @@ -15,8 +15,9 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y # CONFIG_GENERIC_TIME is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_GPIO=y CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_IRQCHIP_DEMUX_GPIO=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -40,7 +41,9 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_TASKSTATS is not set # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set CONFIG_BLK_DEV_INITRD=y @@ -58,15 +61,20 @@ CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_VM_EVENT_COUNTERS=y CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3 -CONFIG_BUDDY=y # CONFIG_NP2 is not set CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set # # Loadable module support @@ -147,13 +155,6 @@ CONFIG_IRQ_PLL_WAKEUP=7 # BF537 Specific Configuration # -# -# PORT F/G Selection -# -CONFIG_BF537_PORT_F=y -# CONFIG_BF537_PORT_G is not set -# CONFIG_BF537_PORT_H is not set - # # Interrupt Priority Assignment # @@ -199,19 +200,17 @@ CONFIG_IRQ_WATCH=13 # CONFIG_CMDLINE_BOOL is not set # -# Board Setup +# Clock/PLL Setup # CONFIG_CLKIN_HZ=25000000 -CONFIG_MEM_SIZE=64 -CONFIG_MEM_ADD_WIDTH=10 -CONFIG_BOOT_LOAD=0x1000 +# CONFIG_BFIN_KERNEL_CLOCK is not set +CONFIG_MAX_VCO_HZ=600000000 +CONFIG_MIN_VCO_HZ=50000000 +CONFIG_MAX_SCLK_HZ=133000000 +CONFIG_MIN_SCLK_HZ=27000000 # -# Blackfin Kernel Optimizations -# - -# -# Timer Tick +# Kernel Timer/Scheduler # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y @@ -219,6 +218,20 @@ CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# +# Memory Setup +# +CONFIG_MEM_SIZE=64 +CONFIG_MEM_ADD_WIDTH=10 +CONFIG_BOOT_LOAD=0x1000 +CONFIG_BFIN_SCRATCH_REG_RETN=y +# CONFIG_BFIN_SCRATCH_REG_RETE is not set +# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set + +# +# Blackfin Kernel Optimizations +# + # # Memory Optimizations # @@ -266,11 +279,6 @@ CONFIG_BFIN_DCACHE=y CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 -# -# Clock Settings -# -# CONFIG_BFIN_KERNEL_CLOCK is not set - # # Asynchonous Memory Configuration # @@ -298,16 +306,13 @@ CONFIG_BANK_3=0x99B3 # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # # CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set -# -# PCI Hotplug Support -# - # # Executable file formats # @@ -342,7 +347,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -383,20 +387,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_NETLABEL is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -463,7 +455,16 @@ CONFIG_IRTTY_SIR=m # FIR device drivers # # CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set # # Device Drivers @@ -481,10 +482,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set @@ -528,7 +525,6 @@ CONFIG_MTD_MW320D=m CONFIG_MTD_RAM=y CONFIG_MTD_ROM=m # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access @@ -565,13 +561,10 @@ CONFIG_BFIN_FLASH_BANK_3=0x7BB0 # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# CONFIG_MTD_NAND=m # CONFIG_MTD_NAND_VERIFY_WRITE is not set # CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set CONFIG_MTD_NAND_BFIN=m CONFIG_BFIN_NAND_BASE=0x20212000 CONFIG_BFIN_NAND_CLE=2 @@ -580,11 +573,13 @@ CONFIG_BFIN_NAND_READY=3 CONFIG_MTD_NAND_IDS=m # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ONENAND is not set # -# OneNAND Flash Device Drivers +# UBI - Unsorted block images # -# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_UBI is not set # # Parallel port support @@ -612,10 +607,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # Misc devices # - -# -# ATA/ATAPI/MFM/RLL support -# # CONFIG_IDE is not set # @@ -624,10 +615,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # CONFIG_SCSI_NETLINK is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# # CONFIG_ATA is not set # @@ -635,19 +622,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_MD is not set -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - # # Network device support # @@ -656,11 +630,20 @@ CONFIG_NETDEVICES=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +CONFIG_PHYLIB=y # -# PHY device support +# MII PHY device drivers # -# CONFIG_PHYLIB is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_FIXED_PHY is not set # # Ethernet (10 or 100Mbit) @@ -674,27 +657,15 @@ CONFIG_BFIN_TX_DESC_NUM=10 CONFIG_BFIN_RX_DESC_NUM=20 # CONFIG_BFIN_MAC_RMII is not set # CONFIG_SMSC911X is not set +# CONFIG_DM9000 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y # -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces +# Wireless LAN # +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -718,6 +689,7 @@ CONFIG_BFIN_RX_DESC_NUM=20 # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -734,8 +706,14 @@ CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set # CONFIG_INPUT_TOUCHSCREEN is not set CONFIG_INPUT_MISC=y +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set # CONFIG_INPUT_UINPUT is not set # CONFIG_BF53X_PFBUTTONS is not set CONFIG_TWI_KEYPAD=m @@ -752,7 +730,7 @@ CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=72 # # CONFIG_AD9960 is not set # CONFIG_SPI_ADC_BF533 is not set -# CONFIG_BF5xx_PFLAGS is not set +# CONFIG_BFIN_PFLAGS is not set # CONFIG_BF5xx_PPIFCD is not set # CONFIG_BF5xx_TIMERS is not set # CONFIG_BF5xx_PPI is not set @@ -803,10 +781,6 @@ CONFIG_CAN_BLACKFIN=m # IPMI # # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -818,7 +792,6 @@ CONFIG_BFIN_WDT=y CONFIG_HW_RANDOM=y # CONFIG_GEN_RTC is not set CONFIG_BLACKFIN_DPMC=y -# CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set @@ -826,11 +799,8 @@ CONFIG_BLACKFIN_DPMC=y # TPM devices # # CONFIG_TCG_TPM is not set - -# -# I2C support -# CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y CONFIG_I2C_CHARDEV=m # @@ -846,10 +816,11 @@ CONFIG_I2C_CHARDEV=m # CONFIG_I2C_BLACKFIN_GPIO is not set CONFIG_I2C_BLACKFIN_TWI=m CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50 +# CONFIG_I2C_GPIO is not set # CONFIG_I2C_OCORES is not set # CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_SIMTEC is not set # CONFIG_I2C_STUB is not set -# CONFIG_I2C_PCA_ISA is not set # # Miscellaneous I2C Chip support @@ -885,18 +856,16 @@ CONFIG_SPI_BFIN=y # SPI Protocol Masters # # CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set # # Dallas's 1-wire bus # # CONFIG_W1 is not set - -# -# Hardware Monitoring support -# CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_AD7418 is not set # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -924,6 +893,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_SMSC47M1 is not set @@ -948,11 +918,8 @@ CONFIG_HWMON=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y # # Graphics support @@ -960,12 +927,23 @@ CONFIG_HWMON=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=m CONFIG_LCD_CLASS_DEVICE=m + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set CONFIG_FB=m CONFIG_FIRMWARE_EDID=y # CONFIG_FB_DDC is not set CONFIG_FB_CFB_FILLRECT=m CONFIG_FB_CFB_COPYAREA=m CONFIG_FB_CFB_IMAGEBLIT=m +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y # CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set @@ -991,10 +969,6 @@ CONFIG_LQ035_SLAVE_ADDR=0x58 # CONFIG_FB_BFIN_BGR is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set - -# -# Logo configuration -# # CONFIG_LOGO is not set # @@ -1035,7 +1009,6 @@ CONFIG_SND_BLACKFIN_AD1836_TDM=y # CONFIG_SND_BLACKFIN_AD1836_I2S is not set CONFIG_SND_BLACKFIN_AD1836_MULSUB=y # CONFIG_SND_BLACKFIN_AD1836_5P1 is not set -CONFIG_SND_BLACKFIN_AD1981B=m CONFIG_SND_BLACKFIN_SPORT=0 CONFIG_SND_BLACKFIN_SPI_PFBIT=4 CONFIG_SND_BFIN_AD73311=m @@ -1043,10 +1016,15 @@ CONFIG_SND_BFIN_SPORT=0 CONFIG_SND_BFIN_AD73311_SE=4 # -# SoC audio support +# System on Chip audio support # # CONFIG_SND_SOC is not set +# +# SoC Audio for the ADI Blackfin +# +# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set + # # Open Sound System # @@ -1066,6 +1044,10 @@ CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB is not set +# +# Enable Host or Gadget support to see Inventra options +# + # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # @@ -1074,11 +1056,6 @@ CONFIG_USB_ARCH_HAS_HCD=y # USB Gadget Support # # CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_SPI_MMC is not set # CONFIG_MMC is not set # @@ -1118,23 +1095,37 @@ CONFIG_RTC_INTF_SYSFS=y CONFIG_RTC_INTF_PROC=y CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set # -# RTC drivers +# I2C RTC drivers # -# CONFIG_RTC_DRV_X1205 is not set # CONFIG_RTC_DRV_DS1307 is not set -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_ISL1208 is not set # CONFIG_RTC_DRV_DS1672 is not set -# CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_PCF8563 is not set -# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6900 is not set # CONFIG_RTC_DRV_RS5C372 is not set -# CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_MAX6902 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# CONFIG_RTC_DRV_BFIN=y # @@ -1150,14 +1141,6 @@ CONFIG_RTC_DRV_BFIN=y # DMA Devices # -# -# Auxiliary Display support -# - -# -# Virtualization -# - # # PBX support # @@ -1258,6 +1241,7 @@ CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m @@ -1335,14 +1319,20 @@ CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set +CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_SERIAL_EARLY_INIT is not set +CONFIG_DEBUG_MMRS=y CONFIG_DEBUG_HUNT_FOR_ZERO=y +CONFIG_DEBUG_BFIN_HWTRACE_ON=y +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0 +# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set +CONFIG_EARLY_PRINTK=y CONFIG_CPLB_INFO=y CONFIG_ACCESS_CHECK=y @@ -1365,6 +1355,7 @@ CONFIG_SECURITY_CAPABILITIES=m CONFIG_BITREVERSE=y CONFIG_CRC_CCITT=m # CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y @@ -1372,3 +1363,4 @@ CONFIG_ZLIB_DEFLATE=m CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig index 8f3b1de6a939..e80f3d59c283 100644 --- a/arch/blackfin/configs/BF548-EZKIT_defconfig +++ b/arch/blackfin/configs/BF548-EZKIT_defconfig @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21.5 +# Linux kernel version: 2.6.22.6 # # CONFIG_MMU is not set # CONFIG_FPU is not set @@ -15,8 +15,9 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y # CONFIG_GENERIC_TIME is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_GPIO=y CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_IRQCHIP_DEMUX_GPIO=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -40,7 +41,9 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_TASKSTATS is not set # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set CONFIG_BLK_DEV_INITRD=y @@ -51,7 +54,6 @@ CONFIG_EMBEDDED=y CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y @@ -59,14 +61,20 @@ CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_VM_EVENT_COUNTERS=y CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3 # CONFIG_NP2 is not set CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set # # Loadable module support @@ -165,6 +173,7 @@ CONFIG_IRQ_UART1_TX=10 # # BF548 Specific Configuration # +# CONFIG_DEB_DMA_URGENT is not set # # Interrupt Priority Assignment @@ -241,25 +250,36 @@ CONFIG_IRQ_OTPSEC=11 CONFIG_IRQ_PINT2=11 CONFIG_IRQ_PINT3=11 +# +# Pin Interrupt to Port Assignment +# + +# +# Assignment +# +CONFIG_PINTx_REASSIGN=y +CONFIG_PINT0_ASSIGN=0x00000101 +CONFIG_PINT1_ASSIGN=0x01010000 +CONFIG_PINT2_ASSIGN=0x07000101 +CONFIG_PINT3_ASSIGN=0x02020303 + # # Board customizations # # CONFIG_CMDLINE_BOOL is not set # -# Board Setup +# Clock/PLL Setup # CONFIG_CLKIN_HZ=25000000 -CONFIG_MEM_SIZE=64 -CONFIG_MEM_ADD_WIDTH=10 -CONFIG_BOOT_LOAD=0x1000 +# CONFIG_BFIN_KERNEL_CLOCK is not set +CONFIG_MAX_VCO_HZ=533000000 +CONFIG_MIN_VCO_HZ=50000000 +CONFIG_MAX_SCLK_HZ=133000000 +CONFIG_MIN_SCLK_HZ=27000000 # -# Blackfin Kernel Optimizations -# - -# -# Timer Tick +# Kernel Timer/Scheduler # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y @@ -267,6 +287,20 @@ CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# +# Memory Setup +# +CONFIG_MEM_SIZE=64 +CONFIG_MEM_ADD_WIDTH=10 +CONFIG_BOOT_LOAD=0x1000 +CONFIG_BFIN_SCRATCH_REG_RETN=y +# CONFIG_BFIN_SCRATCH_REG_RETE is not set +# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set + +# +# Blackfin Kernel Optimizations +# + # # Memory Optimizations # @@ -275,12 +309,12 @@ CONFIG_EXCPT_IRQ_SYSC_L1=y CONFIG_DO_IRQ_L1=y CONFIG_CORE_TIMER_IRQ_L1=y CONFIG_IDLE_L1=y -CONFIG_SCHEDULE_L1=y +# CONFIG_SCHEDULE_L1 is not set CONFIG_ARITHMETIC_OPS_L1=y CONFIG_ACCESS_OK_L1=y -CONFIG_MEMSET_L1=y -CONFIG_MEMCPY_L1=y -CONFIG_SYS_BFIN_SPINLOCK_L1=y +# CONFIG_MEMSET_L1 is not set +# CONFIG_MEMCPY_L1 is not set +# CONFIG_SYS_BFIN_SPINLOCK_L1 is not set # CONFIG_IP_CHECKSUM_L1 is not set CONFIG_CACHELINE_ALIGNED_L1=y # CONFIG_SYSCALL_TAB_L1 is not set @@ -314,11 +348,6 @@ CONFIG_BFIN_DCACHE=y CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 -# -# Clock Settings -# -# CONFIG_BFIN_KERNEL_CLOCK is not set - # # Asynchonous Memory Configuration # @@ -327,7 +356,6 @@ CONFIG_L1_MAX_PIECE=16 # EBIU_AMBCTL Global Control # CONFIG_C_AMCKEN=y -CONFIG_C_CDPRIO=y # CONFIG_C_AMBEN is not set # CONFIG_C_AMBEN_B0 is not set # CONFIG_C_AMBEN_B0_B1 is not set @@ -338,7 +366,7 @@ CONFIG_C_AMBEN_ALL=y # EBIU_AMBCTL Control # CONFIG_BANK_0=0x7BB0 -CONFIG_BANK_1=0x7BB0 +CONFIG_BANK_1=0x5554 CONFIG_BANK_2=0x7BB0 CONFIG_BANK_3=0x99B3 @@ -346,16 +374,13 @@ CONFIG_BANK_3=0x99B3 # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # # CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set -# -# PCI Hotplug Support -# - # # Executable file formats # @@ -383,7 +408,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -424,20 +448,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_NETLABEL is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -463,7 +475,16 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set # # Device Drivers @@ -475,29 +496,23 @@ CONFIG_DEFAULT_TCP_CONG="cubic" CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_REDBOOT_PARTS is not set -# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y # # User Modules And Translation Layers # -# CONFIG_MTD_CHAR is not set +CONFIG_MTD_CHAR=y CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set @@ -509,8 +524,10 @@ CONFIG_MTD_BLOCK=y # # RAM/ROM/Flash chip drivers # -# CONFIG_MTD_CFI is not set +CONFIG_MTD_CFI=y # CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set CONFIG_MTD_MAP_BANK_WIDTH_1=y CONFIG_MTD_MAP_BANK_WIDTH_2=y CONFIG_MTD_MAP_BANK_WIDTH_4=y @@ -521,22 +538,32 @@ CONFIG_MTD_CFI_I1=y CONFIG_MTD_CFI_I2=y # CONFIG_MTD_CFI_I4 is not set # CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_MW320D is not set +CONFIG_MTD_CFI_UTIL=y CONFIG_MTD_RAM=y # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access # CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x20000000 +CONFIG_MTD_PHYSMAP_LEN=0x400000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 # CONFIG_MTD_BF5xx is not set -CONFIG_MTD_UCLINUX=y +# CONFIG_MTD_UCLINUX is not set # CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers # +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set @@ -548,17 +575,24 @@ CONFIG_MTD_UCLINUX=y # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# -# CONFIG_MTD_NAND is not set - -# -# OneNAND Flash Device Drivers -# +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_BFIN is not set +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_NAND_BF5XX=y +CONFIG_MTD_NAND_BF5XX_HWECC=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set # CONFIG_MTD_ONENAND is not set +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set + # # Parallel port support # @@ -585,42 +619,62 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # Misc devices # - -# -# ATA/ATAPI/MFM/RLL support -# # CONFIG_IDE is not set # # SCSI device support # # CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set # CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y # -# Serial ATA (prod) and Parallel ATA (experimental) drivers +# SCSI support type (disk, tape, CD-ROM) # -# CONFIG_ATA is not set +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_PATA_PLATFORM is not set +CONFIG_PATA_BF54X=y +CONFIG_PATA_BF54X_DMA=y # # Multi-device support (RAID and LVM) # # CONFIG_MD is not set -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - # # Network device support # @@ -629,10 +683,6 @@ CONFIG_NETDEVICES=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set - -# -# PHY device support -# # CONFIG_PHYLIB is not set # @@ -641,28 +691,16 @@ CONFIG_NETDEVICES=y CONFIG_NET_ETHERNET=y CONFIG_MII=y # CONFIG_SMC91X is not set -# CONFIG_SMSC911X is not set +CONFIG_SMSC911X=y +# CONFIG_DM9000 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y # -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces +# Wireless LAN # +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -686,6 +724,7 @@ CONFIG_MII=y # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -702,10 +741,17 @@ CONFIG_INPUT=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set # CONFIG_INPUT_TOUCHSCREEN is not set CONFIG_INPUT_MISC=y +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set # CONFIG_INPUT_UINPUT is not set # CONFIG_BF53X_PFBUTTONS is not set +# CONFIG_TWI_KEYPAD is not set # # Hardware I/O ports @@ -718,12 +764,15 @@ CONFIG_INPUT_MISC=y # # CONFIG_AD9960 is not set # CONFIG_SPI_ADC_BF533 is not set -# CONFIG_BF5xx_PFLAGS is not set +# CONFIG_BFIN_PFLAGS is not set # CONFIG_BF5xx_PPIFCD is not set # CONFIG_BF5xx_TIMERS is not set # CONFIG_BF5xx_PPI is not set # CONFIG_BFIN_SPORT is not set # CONFIG_BFIN_TIMER_LATENCY is not set +# CONFIG_TWI_LCD is not set +# CONFIG_AD5304 is not set +# CONFIG_BF5xx_TEA5764 is not set # CONFIG_BF5xx_FBDMA is not set # CONFIG_VT is not set # CONFIG_SERIAL_NONSTANDARD is not set @@ -760,14 +809,9 @@ CONFIG_UNIX98_PTYS=y # IPMI # # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# # CONFIG_WATCHDOG is not set CONFIG_HW_RANDOM=y # CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set @@ -775,32 +819,114 @@ CONFIG_HW_RANDOM=y # TPM devices # # CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y # -# I2C support +# I2C Algorithms # -# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_BLACKFIN_GPIO is not set +CONFIG_I2C_BLACKFIN_TWI=y +CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50 +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_AD5252 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8575 is not set +# CONFIG_SENSORS_PCA9543 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set # # SPI support # -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BFIN=y +# CONFIG_SPI_BITBANG is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set # # Dallas's 1-wire bus # # CONFIG_W1 is not set - -# -# Hardware Monitoring support -# CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -812,16 +938,19 @@ CONFIG_HWMON=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y # # Graphics support # # CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set # CONFIG_FB is not set # @@ -843,6 +972,10 @@ CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB is not set +# +# Enable Host or Gadget support to see Inventra options +# + # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # @@ -851,11 +984,20 @@ CONFIG_USB_ARCH_HAS_HCD=y # USB Gadget Support # # CONFIG_USB_GADGET is not set +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set # -# MMC/SD Card support +# MMC/SD Card Drivers # -# CONFIG_MMC is not set +CONFIG_MMC_BLOCK=m + +# +# MMC/SD Host Controller Drivers +# +CONFIG_SDH_BFIN=m +# CONFIG_SPI_MMC is not set # # LED devices @@ -894,15 +1036,37 @@ CONFIG_RTC_INTF_SYSFS=y CONFIG_RTC_INTF_PROC=y CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set # -# RTC drivers +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set + +# +# Platform RTC drivers # # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set # CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_TEST is not set # CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# CONFIG_RTC_DRV_BFIN=y # @@ -918,14 +1082,6 @@ CONFIG_RTC_DRV_BFIN=y # DMA Devices # -# -# Auxiliary Display support -# - -# -# Virtualization -# - # # PBX support # @@ -991,8 +1147,25 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_YAFFS_FS is not set -# CONFIG_JFFS2_FS is not set +CONFIG_YAFFS_FS=m +CONFIG_YAFFS_YAFFS1=y +# CONFIG_YAFFS_DOES_ECC is not set +CONFIG_YAFFS_YAFFS2=y +CONFIG_YAFFS_AUTO_YAFFS2=y +# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set +CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 +# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set +# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set +CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -1040,36 +1213,20 @@ CONFIG_MSDOS_PARTITION=y CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set +CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_DETECT_SOFTLOCKUP=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_TIMER_STATS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KERNEL is not set # CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_LIST is not set -CONFIG_FRAME_POINTER=y -CONFIG_FORCED_INLINING=y -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_FAULT_INJECTION is not set -CONFIG_DEBUG_HWERR=y -# CONFIG_DEBUG_ICACHE_CHECK is not set -# CONFIG_DEBUG_KERNEL_START is not set -# CONFIG_DEBUG_SERIAL_EARLY_INIT is not set +CONFIG_DEBUG_MMRS=y CONFIG_DEBUG_HUNT_FOR_ZERO=y +CONFIG_DEBUG_BFIN_HWTRACE_ON=y +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0 +# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set +CONFIG_EARLY_PRINTK=y CONFIG_CPLB_INFO=y CONFIG_ACCESS_CHECK=y @@ -1092,9 +1249,12 @@ CONFIG_SECURITY_CAPABILITIES=y CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig index 698a2492424e..85e647f87759 100644 --- a/arch/blackfin/configs/BF561-EZKIT_defconfig +++ b/arch/blackfin/configs/BF561-EZKIT_defconfig @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21.5 +# Linux kernel version: 2.6.22.6 # # CONFIG_MMU is not set # CONFIG_FPU is not set @@ -15,8 +15,9 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y # CONFIG_GENERIC_TIME is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_GPIO=y CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_IRQCHIP_DEMUX_GPIO=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -40,7 +41,9 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_TASKSTATS is not set # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set CONFIG_BLK_DEV_INITRD=y @@ -58,15 +61,20 @@ CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_VM_EVENT_COUNTERS=y CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3 -CONFIG_BUDDY=y # CONFIG_NP2 is not set CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set # # Loadable module support @@ -229,19 +237,17 @@ CONFIG_IRQ_WDTIMER=13 # CONFIG_CMDLINE_BOOL is not set # -# Board Setup +# Clock/PLL Setup # CONFIG_CLKIN_HZ=30000000 -CONFIG_MEM_SIZE=64 -CONFIG_MEM_ADD_WIDTH=9 -CONFIG_BOOT_LOAD=0x1000 +# CONFIG_BFIN_KERNEL_CLOCK is not set +CONFIG_MAX_VCO_HZ=600000000 +CONFIG_MIN_VCO_HZ=50000000 +CONFIG_MAX_SCLK_HZ=133000000 +CONFIG_MIN_SCLK_HZ=27000000 # -# Blackfin Kernel Optimizations -# - -# -# Timer Tick +# Kernel Timer/Scheduler # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y @@ -249,6 +255,20 @@ CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# +# Memory Setup +# +CONFIG_MEM_SIZE=64 +CONFIG_MEM_ADD_WIDTH=9 +CONFIG_BOOT_LOAD=0x1000 +CONFIG_BFIN_SCRATCH_REG_RETN=y +# CONFIG_BFIN_SCRATCH_REG_RETE is not set +# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set + +# +# Blackfin Kernel Optimizations +# + # # Memory Optimizations # @@ -296,11 +316,6 @@ CONFIG_BFIN_DCACHE=y CONFIG_BFIN_WT=y CONFIG_L1_MAX_PIECE=16 -# -# Clock Settings -# -# CONFIG_BFIN_KERNEL_CLOCK is not set - # # Asynchonous Memory Configuration # @@ -326,22 +341,19 @@ CONFIG_C_AMBEN_ALL=y CONFIG_BANK_0=0x7BB0 CONFIG_BANK_1=0x7BB0 CONFIG_BANK_2=0x7BB0 -CONFIG_BANK_3=0x99B3 +CONFIG_BANK_3=0xAAC3 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # # CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set -# -# PCI Hotplug Support -# - # # Executable file formats # @@ -364,7 +376,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -405,20 +416,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_NETLABEL is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -485,7 +484,16 @@ CONFIG_IRTTY_SIR=m # FIR device drivers # # CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set # # Device Drivers @@ -503,10 +511,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set @@ -550,7 +554,6 @@ CONFIG_MTD_MW320D=m CONFIG_MTD_RAM=y CONFIG_MTD_ROM=m # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access @@ -588,16 +591,13 @@ CONFIG_BFIN_FLASH_BANK_3=0x7BB0 # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# # CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set # -# OneNAND Flash Device Drivers +# UBI - Unsorted block images # -# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_UBI is not set # # Parallel port support @@ -625,10 +625,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # Misc devices # - -# -# ATA/ATAPI/MFM/RLL support -# # CONFIG_IDE is not set # @@ -637,10 +633,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # CONFIG_SCSI_NETLINK is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# # CONFIG_ATA is not set # @@ -648,19 +640,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_MD is not set -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - # # Network device support # @@ -669,10 +648,6 @@ CONFIG_NETDEVICES=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set - -# -# PHY device support -# # CONFIG_PHYLIB is not set # @@ -682,27 +657,15 @@ CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_SMC91X=y # CONFIG_SMSC911X is not set +# CONFIG_DM9000 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y # -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces +# Wireless LAN # +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -726,6 +689,7 @@ CONFIG_SMC91X=y # CONFIG_INPUT=m # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -742,6 +706,7 @@ CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set @@ -756,7 +721,7 @@ CONFIG_INPUT_EVDEV=m # # CONFIG_AD9960 is not set # CONFIG_SPI_ADC_BF533 is not set -# CONFIG_BF5xx_PFLAGS is not set +# CONFIG_BFIN_PFLAGS is not set # CONFIG_BF5xx_PPIFCD is not set # CONFIG_BF5xx_TIMERS is not set # CONFIG_BF5xx_PPI is not set @@ -796,10 +761,6 @@ CONFIG_UNIX98_PTYS=y # IPMI # # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -810,7 +771,6 @@ CONFIG_WATCHDOG=y CONFIG_BFIN_WDT=y CONFIG_HW_RANDOM=y # CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set @@ -818,10 +778,6 @@ CONFIG_HW_RANDOM=y # TPM devices # # CONFIG_TCG_TPM is not set - -# -# I2C support -# # CONFIG_I2C is not set # @@ -840,22 +796,22 @@ CONFIG_SPI_BFIN=y # SPI Protocol Masters # # CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set # # Dallas's 1-wire bus # # CONFIG_W1 is not set - -# -# Hardware Monitoring support -# CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_F71805F is not set # CONFIG_SENSORS_LM70 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83627HF is not set # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -867,16 +823,19 @@ CONFIG_HWMON=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y # # Graphics support # # CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set # CONFIG_FB is not set # @@ -898,6 +857,10 @@ CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB is not set +# +# Enable Host or Gadget support to see Inventra options +# + # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # @@ -906,11 +869,6 @@ CONFIG_USB_ARCH_HAS_HCD=y # USB Gadget Support # # CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_SPI_MMC is not set # CONFIG_MMC is not set # @@ -952,14 +910,6 @@ CONFIG_USB_ARCH_HAS_HCD=y # DMA Devices # -# -# Auxiliary Display support -# - -# -# Virtualization -# - # # PBX support # @@ -1060,6 +1010,7 @@ CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m @@ -1137,14 +1088,20 @@ CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set +CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_SERIAL_EARLY_INIT is not set +CONFIG_DEBUG_MMRS=y CONFIG_DEBUG_HUNT_FOR_ZERO=y +CONFIG_DEBUG_BFIN_HWTRACE_ON=y +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0 +# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set +CONFIG_EARLY_PRINTK=y # CONFIG_DUAL_CORE_TEST_MODULE is not set CONFIG_CPLB_INFO=y CONFIG_ACCESS_CHECK=y @@ -1168,6 +1125,7 @@ CONFIG_SECURITY_CAPABILITIES=m CONFIG_BITREVERSE=y CONFIG_CRC_CCITT=m # CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y @@ -1175,3 +1133,4 @@ CONFIG_ZLIB_DEFLATE=m CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig index dbb0c4f399fb..15e36aaf2186 100644 --- a/arch/blackfin/configs/PNAV-10_defconfig +++ b/arch/blackfin/configs/PNAV-10_defconfig @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21.5 +# Linux kernel version: 2.6.22.6 # # CONFIG_MMU is not set # CONFIG_FPU is not set @@ -15,8 +15,9 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y # CONFIG_GENERIC_TIME is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_GPIO=y CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_IRQCHIP_DEMUX_GPIO=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -41,6 +42,7 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set # CONFIG_BLK_DEV_INITRD is not set @@ -57,15 +59,20 @@ CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_VM_EVENT_COUNTERS=y CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=9 -CONFIG_BUDDY=y # CONFIG_NP2 is not set CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set # # Loadable module support @@ -146,13 +153,6 @@ CONFIG_IRQ_PLL_WAKEUP=7 # BF537 Specific Configuration # -# -# PORT F/G Selection -# -CONFIG_BF537_PORT_F=y -# CONFIG_BF537_PORT_G is not set -# CONFIG_BF537_PORT_H is not set - # # Interrupt Priority Assignment # @@ -198,19 +198,17 @@ CONFIG_IRQ_WATCH=13 # CONFIG_CMDLINE_BOOL is not set # -# Board Setup +# Clock/PLL Setup # CONFIG_CLKIN_HZ=24576000 -CONFIG_MEM_SIZE=64 -CONFIG_MEM_ADD_WIDTH=10 -CONFIG_BOOT_LOAD=0x1000 +# CONFIG_BFIN_KERNEL_CLOCK is not set +CONFIG_MAX_VCO_HZ=600000000 +CONFIG_MIN_VCO_HZ=50000000 +CONFIG_MAX_SCLK_HZ=133000000 +CONFIG_MIN_SCLK_HZ=27000000 # -# Blackfin Kernel Optimizations -# - -# -# Timer Tick +# Kernel Timer/Scheduler # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y @@ -218,6 +216,20 @@ CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# +# Memory Setup +# +CONFIG_MEM_SIZE=64 +CONFIG_MEM_ADD_WIDTH=10 +CONFIG_BOOT_LOAD=0x1000 +CONFIG_BFIN_SCRATCH_REG_RETN=y +# CONFIG_BFIN_SCRATCH_REG_RETE is not set +# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set + +# +# Blackfin Kernel Optimizations +# + # # Memory Optimizations # @@ -265,11 +277,6 @@ CONFIG_BFIN_WB=y # CONFIG_BFIN_WT is not set CONFIG_L1_MAX_PIECE=16 -# -# Clock Settings -# -# CONFIG_BFIN_KERNEL_CLOCK is not set - # # Asynchonous Memory Configuration # @@ -297,16 +304,13 @@ CONFIG_BANK_3=0x99B3 # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # # CONFIG_PCI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set -# -# PCI Hotplug Support -# - # # Executable file formats # @@ -334,7 +338,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -375,20 +378,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_NETLABEL is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -414,7 +405,16 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set # # Device Drivers @@ -432,10 +432,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set @@ -473,7 +469,6 @@ CONFIG_MTD_CFI_I2=y CONFIG_MTD_RAM=y # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access @@ -499,13 +494,10 @@ CONFIG_MTD_UCLINUX=y # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# CONFIG_MTD_NAND=y # CONFIG_MTD_NAND_VERIFY_WRITE is not set # CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set CONFIG_MTD_NAND_BFIN=y CONFIG_BFIN_NAND_BASE=0x20100000 CONFIG_BFIN_NAND_CLE=2 @@ -514,11 +506,13 @@ CONFIG_BFIN_NAND_READY=44 CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ONENAND is not set # -# OneNAND Flash Device Drivers +# UBI - Unsorted block images # -# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_UBI is not set # # Parallel port support @@ -546,10 +540,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # Misc devices # - -# -# ATA/ATAPI/MFM/RLL support -# # CONFIG_IDE is not set # @@ -558,10 +548,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # CONFIG_SCSI_NETLINK is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# # CONFIG_ATA is not set # @@ -569,19 +555,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_MD is not set -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - # # Network device support # @@ -590,11 +563,20 @@ CONFIG_NETDEVICES=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +CONFIG_PHYLIB=y # -# PHY device support +# MII PHY device drivers # -# CONFIG_PHYLIB is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_FIXED_PHY is not set # # Ethernet (10 or 100Mbit) @@ -608,27 +590,15 @@ CONFIG_BFIN_TX_DESC_NUM=100 CONFIG_BFIN_RX_DESC_NUM=100 CONFIG_BFIN_MAC_RMII=y # CONFIG_SMSC911X is not set +# CONFIG_DM9000 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y # -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces +# Wireless LAN # +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -652,6 +622,7 @@ CONFIG_BFIN_MAC_RMII=y # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -670,6 +641,7 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_ADS7846 is not set CONFIG_TOUCHSCREEN_AD7877=y @@ -681,7 +653,13 @@ CONFIG_TOUCHSCREEN_AD7877=y # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set # CONFIG_TOUCHSCREEN_TOUCHWIN is not set # CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set CONFIG_INPUT_MISC=y +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set CONFIG_INPUT_UINPUT=y # CONFIG_BF53X_PFBUTTONS is not set # CONFIG_TWI_KEYPAD is not set @@ -697,7 +675,7 @@ CONFIG_INPUT_UINPUT=y # # CONFIG_AD9960 is not set # CONFIG_SPI_ADC_BF533 is not set -# CONFIG_BF5xx_PFLAGS is not set +# CONFIG_BFIN_PFLAGS is not set # CONFIG_BF5xx_PPIFCD is not set # CONFIG_BF5xx_TIMERS is not set # CONFIG_BF5xx_PPI is not set @@ -749,14 +727,9 @@ CONFIG_CAN_BLACKFIN=m # IPMI # # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# # CONFIG_WATCHDOG is not set CONFIG_HW_RANDOM=y # CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set @@ -764,11 +737,8 @@ CONFIG_HW_RANDOM=y # TPM devices # # CONFIG_TCG_TPM is not set - -# -# I2C support -# CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y CONFIG_I2C_CHARDEV=y # @@ -784,10 +754,11 @@ CONFIG_I2C_CHARDEV=y # CONFIG_I2C_BLACKFIN_GPIO is not set CONFIG_I2C_BLACKFIN_TWI=y CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50 +# CONFIG_I2C_GPIO is not set # CONFIG_I2C_OCORES is not set # CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_SIMTEC is not set # CONFIG_I2C_STUB is not set -# CONFIG_I2C_PCA_ISA is not set # # Miscellaneous I2C Chip support @@ -823,18 +794,16 @@ CONFIG_SPI_BFIN=y # SPI Protocol Masters # # CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set # # Dallas's 1-wire bus # # CONFIG_W1 is not set - -# -# Hardware Monitoring support -# CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_AD7418 is not set # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -862,6 +831,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_SMSC47M1 is not set @@ -886,11 +856,8 @@ CONFIG_HWMON=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y # # Graphics support @@ -898,12 +865,23 @@ CONFIG_HWMON=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_LCD_CLASS_DEVICE=y + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set CONFIG_FB=y CONFIG_FIRMWARE_EDID=y # CONFIG_FB_DDC is not set CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y # CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set @@ -921,10 +899,6 @@ CONFIG_FB_BFIN_LANDSCAPE=y # CONFIG_FB_BFIN_BGR is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set - -# -# Logo configuration -# # CONFIG_LOGO is not set # @@ -936,8 +910,6 @@ CONFIG_SOUND=y # Advanced Linux Sound Architecture # CONFIG_SND=m -CONFIG_SND_TIMER=m -CONFIG_SND_PCM=m # CONFIG_SND_SEQUENCER is not set # CONFIG_SND_MIXER_OSS is not set # CONFIG_SND_PCM_OSS is not set @@ -959,19 +931,23 @@ CONFIG_SND_PCM=m # ALSA Blackfin devices # # CONFIG_SND_BLACKFIN_AD1836 is not set -CONFIG_SND_BLACKFIN_AD1981B=m # CONFIG_SND_BFIN_AD73311 is not set # -# SoC audio support +# System on Chip audio support # # CONFIG_SND_SOC is not set +# +# SoC Audio for the ADI Blackfin +# +# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set + # # Open Sound System # CONFIG_SOUND_PRIME=y -# CONFIG_OBSOLETE_OSS is not set +# CONFIG_OSS_OBSOLETE is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set @@ -988,6 +964,10 @@ CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB is not set +# +# Enable Host or Gadget support to see Inventra options +# + # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # @@ -996,11 +976,6 @@ CONFIG_USB_ARCH_HAS_HCD=y # USB Gadget Support # # CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_SPI_MMC is not set # CONFIG_MMC is not set # @@ -1040,23 +1015,37 @@ CONFIG_RTC_INTF_SYSFS=y CONFIG_RTC_INTF_PROC=y CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set # -# RTC drivers +# I2C RTC drivers # -# CONFIG_RTC_DRV_X1205 is not set # CONFIG_RTC_DRV_DS1307 is not set -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_ISL1208 is not set # CONFIG_RTC_DRV_DS1672 is not set -# CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_PCF8563 is not set -# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6900 is not set # CONFIG_RTC_DRV_RS5C372 is not set -# CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_MAX6902 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# CONFIG_RTC_DRV_BFIN=y # @@ -1072,14 +1061,6 @@ CONFIG_RTC_DRV_BFIN=y # DMA Devices # -# -# Auxiliary Display support -# - -# -# Virtualization -# - # # PBX support # @@ -1176,6 +1157,7 @@ CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=m +# CONFIG_SUNRPC_BIND34 is not set # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set CONFIG_SMB_FS=m @@ -1256,11 +1238,17 @@ CONFIG_ENABLE_MUST_CHECK=y # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_SERIAL_EARLY_INIT is not set +# CONFIG_DEBUG_MMRS is not set # CONFIG_DEBUG_HUNT_FOR_ZERO is not set +CONFIG_DEBUG_BFIN_HWTRACE_ON=y +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set +# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set +CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0 +# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set +# CONFIG_EARLY_PRINTK is not set # CONFIG_CPLB_INFO is not set # CONFIG_ACCESS_CHECK is not set @@ -1283,9 +1271,11 @@ CONFIG_SECURITY_CAPABILITIES=y CONFIG_BITREVERSE=y CONFIG_CRC_CCITT=m # CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y From 27d875f2c134c4b26860ccdd03b4c52cce4efc2c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 27 Aug 2007 16:08:53 +0800 Subject: [PATCH 0043/2804] Blackfin arch: vmlinux.lds.S, break up our .init into separate sections Break up our .init into separate section like all other ports do and so that we dont mix text and data (causes disassembly headaches as pointed out by Robin) Cc: Robin Getz Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/vmlinux.lds.S | 42 +++++++++++++++++++----------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index e40b66ae1b79..cd1cea05f1a8 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -46,11 +46,11 @@ SECTIONS __text = .; _text = .; __stext = .; - *(.text.*) TEXT_TEXT SCHED_TEXT LOCK_TEXT - *(.text.lock) + KPROBES_TEXT + *(.text.*) *(.fixup) . = ALIGN(16); @@ -62,7 +62,7 @@ SECTIONS __etext = .; } - RODATA + RO_DATA(PAGE_SIZE) .data : { @@ -73,51 +73,63 @@ SECTIONS __sdata = .; . = ALIGN(THREAD_SIZE); *(.data.init_task) - DATA_DATA - *(.data.*) - CONSTRUCTORS . = ALIGN(32); *(.data.cacheline_aligned) + DATA_DATA + *(.data.*) + CONSTRUCTORS + . = ALIGN(THREAD_SIZE); __edata = .; } ___init_begin = .; - .init : + + .init.text : { . = ALIGN(PAGE_SIZE); __sinittext = .; *(.init.text) __einittext = .; + } + .init.data : + { + . = ALIGN(16); *(.init.data) + } + .init.setup : + { . = ALIGN(16); ___setup_start = .; *(.init.setup) ___setup_end = .; - ___start___param = .; - *(__param) - ___stop___param = .; + } + .initcall.init : + { ___initcall_start = .; INITCALLS ___initcall_end = .; + } + .con_initcall.init : + { ___con_initcall_start = .; *(.con_initcall.init) ___con_initcall_end = .; - ___security_initcall_start = .; - *(.security_initcall.init) - ___security_initcall_end = .; + } + SECURITY_INIT + .init.ramfs : + { . = ALIGN(4); ___initramfs_start = .; *(.init.ramfs) ___initramfs_end = .; - . = ALIGN(4); } __l1_lma_start = .; - .text_l1 L1_CODE_START : AT(LOADADDR(.init) + SIZEOF(.init)) + .text_l1 L1_CODE_START : AT(LOADADDR(.init.ramfs) + SIZEOF(.init.ramfs)) { . = ALIGN(4); __stext_l1 = .; From 168f1212c098727f2509fe0f66bd30d7209a8159 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 11 Oct 2007 00:22:35 +0800 Subject: [PATCH 0044/2804] Blackfin arch: rewrite our reboot code in C rewrite our reboot code in C rather than assembly to be like other architectures and to allow board maintainers to define custom behavior Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/Makefile | 2 +- arch/blackfin/kernel/bfin_gpio.c | 18 +++++ arch/blackfin/kernel/process.c | 25 ------- arch/blackfin/mach-bf533/head.S | 60 --------------- arch/blackfin/mach-bf537/head.S | 79 ------------------- arch/blackfin/mach-bf548/head.S | 125 ------------------------------- arch/blackfin/mach-bf561/head.S | 60 --------------- 7 files changed, 19 insertions(+), 350 deletions(-) diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index f429ebc3a961..ae0a2203c3da 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := init_task.o vmlinux.lds obj-y := \ entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \ sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \ - fixed_code.o cplbinit.o cacheinit.o + fixed_code.o cplbinit.o cacheinit.o reboot.o obj-$(CONFIG_BF53x) += bfin_gpio.o obj-$(CONFIG_BF561) += bfin_gpio.o diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 0182ce1fc4fb..d9284d7dc9fc 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -80,6 +80,7 @@ * GPIO_47 PH15 PF47 */ +#include #include #include #include @@ -888,3 +889,20 @@ void gpio_direction_output(unsigned short gpio) local_irq_restore(flags); } EXPORT_SYMBOL(gpio_direction_output); + +/* If we are booting from SPI and our board lacks a strong enough pull up, + * the core can reset and execute the bootrom faster than the resistor can + * pull the signal logically high. To work around this (common) error in + * board design, we explicitly set the pin back to GPIO mode, force /CS + * high, and wait for the electrons to do their thing. + * + * This function only makes sense to be called from reset code, but it + * lives here as we need to force all the GPIO states w/out going through + * BUG() checks and such. + */ +void bfin_gpio_reset_spi0_ssel1(void) +{ + port_setup(P_SPI0_SSEL1, GPIO_USAGE); + gpio_bankb[gpio_bank(P_SPI0_SSEL1)]->data_set = gpio_bit(P_SPI0_SSEL1); + udelay(1); +} diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 22e790419868..de7d048bd4ee 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -134,31 +134,6 @@ void cpu_idle(void) } } -void machine_restart(char *__unused) -{ -#if defined(CONFIG_BFIN_ICACHE) - bfin_write_IMEM_CONTROL(0x01); - SSYNC(); -#endif - bfin_reset(); - /* Dont do anything till the reset occurs */ - while (1) { - SSYNC(); - } -} - -void machine_halt(void) -{ - for (;;) - asm volatile ("idle"); -} - -void machine_power_off(void) -{ - for (;;) - asm volatile ("idle"); -} - void show_regs(struct pt_regs *regs) { printk(KERN_NOTICE "\n"); diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S index 3be6feefa8a9..6e1b5f6da5ca 100644 --- a/arch/blackfin/mach-bf533/head.S +++ b/arch/blackfin/mach-bf533/head.S @@ -459,66 +459,6 @@ ENTRY(_start_dma_code) ENDPROC(_start_dma_code) #endif /* CONFIG_BFIN_KERNEL_CLOCK */ -ENTRY(_bfin_reset) - /* No more interrupts to be handled*/ - CLI R6; - SSYNC; - -#if defined(CONFIG_BFIN_SHARED_FLASH_ENET) - p0.h = hi(FIO_INEN); - p0.l = lo(FIO_INEN); - r0.l = ~(1 << CONFIG_ENET_FLASH_PIN); - w[p0] = r0.l; - - p0.h = hi(FIO_DIR); - p0.l = lo(FIO_DIR); - r0.l = (1 << CONFIG_ENET_FLASH_PIN); - w[p0] = r0.l; - - p0.h = hi(FIO_FLAG_C); - p0.l = lo(FIO_FLAG_C); - r0.l = (1 << CONFIG_ENET_FLASH_PIN); - w[p0] = r0.l; -#endif - - /* Clear the IMASK register */ - p0.h = hi(IMASK); - p0.l = lo(IMASK); - r0 = 0x0; - [p0] = r0; - - /* Clear the ILAT register */ - p0.h = hi(ILAT); - p0.l = lo(ILAT); - r0 = [p0]; - [p0] = r0; - SSYNC; - - /* make sure SYSCR is set to use BMODE */ - P0.h = hi(SYSCR); - P0.l = lo(SYSCR); - R0.l = 0x0; - W[P0] = R0.l; - SSYNC; - - /* issue a system soft reset */ - P1.h = hi(SWRST); - P1.l = lo(SWRST); - R1.l = 0x0007; - W[P1] = R1; - SSYNC; - - /* clear system soft reset */ - R0.l = 0x0000; - W[P0] = R0; - SSYNC; - - /* issue core reset */ - raise 1; - - RTS; -ENDPROC(_bfin_reset) - #if CONFIG_DEBUG_KERNEL_START debug_kernel_start_trap: /* Set up a temp stack in L1 - SDRAM might not be working */ diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S index 0836bfdcc6c5..2c4ae466d4e9 100644 --- a/arch/blackfin/mach-bf537/head.S +++ b/arch/blackfin/mach-bf537/head.S @@ -478,85 +478,6 @@ ENTRY(_start_dma_code) ENDPROC(_start_dma_code) #endif /* CONFIG_BFIN_KERNEL_CLOCK */ -ENTRY(_bfin_reset) - /* No more interrupts to be handled*/ - CLI R6; - SSYNC; - -#if defined(CONFIG_MTD_M25P80) - /* - * The following code fix the SPI flash reboot issue, - * /CS signal of the chip which is using PF10 return to GPIO mode - */ - p0.h = hi(PORTF_FER); - p0.l = lo(PORTF_FER); - r0.l = 0x0000; - w[p0] = r0.l; - SSYNC; - - /* /CS return to high */ - p0.h = hi(PORTFIO); - p0.l = lo(PORTFIO); - r0.l = 0xFFFF; - w[p0] = r0.l; - SSYNC; - - /* Delay some time, This is necessary */ - r1.h = 0; - r1.l = 0x400; - p1 = r1; - lsetup (.L_delay_lab1, .L_delay_lab1_end) lc1 = p1; -.L_delay_lab1: - r0.h = 0; - r0.l = 0x8000; - p0 = r0; - lsetup (.L_delay_lab0, .L_delay_lab0_end) lc0 = p0; -.L_delay_lab0: - nop; -.L_delay_lab0_end: - nop; -.L_delay_lab1_end: - nop; -#endif - - /* Clear the IMASK register */ - p0.h = hi(IMASK); - p0.l = lo(IMASK); - r0 = 0x0; - [p0] = r0; - - /* Clear the ILAT register */ - p0.h = hi(ILAT); - p0.l = lo(ILAT); - r0 = [p0]; - [p0] = r0; - SSYNC; - - /* make sure SYSCR is set to use BMODE */ - P0.h = hi(SYSCR); - P0.l = lo(SYSCR); - R0.l = 0x0; - W[P0] = R0.l; - SSYNC; - - /* issue a system soft reset */ - P1.h = hi(SWRST); - P1.l = lo(SWRST); - R1.l = 0x0007; - W[P1] = R1; - SSYNC; - - /* clear system soft reset */ - R0.l = 0x0000; - W[P0] = R0; - SSYNC; - - /* issue core reset */ - raise 1; - - RTS; -ENDPROC(_bfin_reset) - .data /* diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S index 937fbef26a51..532ed0930b5e 100644 --- a/arch/blackfin/mach-bf548/head.S +++ b/arch/blackfin/mach-bf548/head.S @@ -378,131 +378,6 @@ ENTRY(_start_dma_code) RTS; #endif /* CONFIG_BFIN_KERNEL_CLOCK */ -ENTRY(_bfin_reset) - /* No more interrupts to be handled*/ - CLI R6; - SSYNC; - -#if 0 /* Need to determine later if this is here necessary for BF54x */ -#if defined(CONFIG_MTD_M25P80) -/* - * The following code fix the SPI flash reboot issue, - * /CS signal of the chip which is using PF10 return to GPIO mode - */ - p0.h = hi(PORTF_FER); - p0.l = lo(PORTF_FER); - r0.l = 0x0000; - w[p0] = r0.l; - SSYNC; - -/* /CS return to high */ - p0.h = hi(PORTFIO); - p0.l = lo(PORTFIO); - r0.l = 0xFFFF; - w[p0] = r0.l; - SSYNC; - -/* Delay some time, This is necessary */ - r1.h = 0; - r1.l = 0x400; - p1 = r1; - lsetup (_delay_lab1,_delay_lab1_end ) lc1 = p1; -_delay_lab1: - r0.h = 0; - r0.l = 0x8000; - p0 = r0; - lsetup (_delay_lab0,_delay_lab0_end ) lc0 = p0; -_delay_lab0: - nop; -_delay_lab0_end: - nop; -_delay_lab1_end: - nop; -#endif -#endif - - /* Clear the bits 13-15 in SWRST if they werent cleared */ - p0.h = hi(SWRST); - p0.l = lo(SWRST); - csync; - r0.l = w[p0]; - - /* Clear the IMASK register */ - p0.h = hi(IMASK); - p0.l = lo(IMASK); - r0 = 0x0; - [p0] = r0; - - /* Clear the ILAT register */ - p0.h = hi(ILAT); - p0.l = lo(ILAT); - r0 = [p0]; - [p0] = r0; - SSYNC; - - /* Disable the WDOG TIMER */ - p0.h = hi(WDOG_CTL); - p0.l = lo(WDOG_CTL); - r0.l = 0xAD6; - w[p0] = r0.l; - SSYNC; - - /* Clear the sticky bit incase it is already set */ - p0.h = hi(WDOG_CTL); - p0.l = lo(WDOG_CTL); - r0.l = 0x8AD6; - w[p0] = r0.l; - SSYNC; - - /* Program the count value */ - R0.l = 0x100; - R0.h = 0x0; - P0.h = hi(WDOG_CNT); - P0.l = lo(WDOG_CNT); - [P0] = R0; - SSYNC; - - /* Program WDOG_STAT if necessary */ - P0.h = hi(WDOG_CTL); - P0.l = lo(WDOG_CTL); - R0 = W[P0](Z); - CC = BITTST(R0,1); - if !CC JUMP .LWRITESTAT; - CC = BITTST(R0,2); - if !CC JUMP .LWRITESTAT; - JUMP .LSKIP_WRITE; - -.LWRITESTAT: - /* When watch dog timer is enabled, - * a write to STAT will load the contents of CNT to STAT - */ - R0 = 0x0000(z); - P0.h = hi(WDOG_STAT); - P0.l = lo(WDOG_STAT) - [P0] = R0; - SSYNC; - -.LSKIP_WRITE: - /* Enable the reset event */ - P0.h = hi(WDOG_CTL); - P0.l = lo(WDOG_CTL); - R0 = W[P0](Z); - BITCLR(R0,1); - BITCLR(R0,2); - W[P0] = R0.L; - SSYNC; - NOP; - - /* Enable the wdog counter */ - R0 = W[P0](Z); - BITCLR(R0,4); - W[P0] = R0.L; - SSYNC; - - IDLE; - - RTS; - .data /* diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S index 139f4cff801b..fd39891ae0fe 100644 --- a/arch/blackfin/mach-bf561/head.S +++ b/arch/blackfin/mach-bf561/head.S @@ -406,66 +406,6 @@ ENTRY(_start_dma_code) ENDPROC(_start_dma_code) #endif /* CONFIG_BFIN_KERNEL_CLOCK */ -ENTRY(_bfin_reset) - /* No more interrupts to be handled*/ - CLI R6; - SSYNC; - -#if defined(CONFIG_BFIN_SHARED_FLASH_ENET) - p0.h = hi(FIO_INEN); - p0.l = lo(FIO_INEN); - r0.l = ~(PF1 | PF0); - w[p0] = r0.l; - - p0.h = hi(FIO_DIR); - p0.l = lo(FIO_DIR); - r0.l = (PF1 | PF0); - w[p0] = r0.l; - - p0.h = hi(FIO_FLAG_C); - p0.l = lo(FIO_FLAG_C); - r0.l = (PF1 | PF0); - w[p0] = r0.l; -#endif - - /* Clear the IMASK register */ - p0.h = hi(IMASK); - p0.l = lo(IMASK); - r0 = 0x0; - [p0] = r0; - - /* Clear the ILAT register */ - p0.h = hi(ILAT); - p0.l = lo(ILAT); - r0 = [p0]; - [p0] = r0; - SSYNC; - - /* make sure SYSCR is set to use BMODE */ - P0.h = hi(SYSCR); - P0.l = lo(SYSCR); - R0.l = 0x20; /* on BF561, disable core b */ - W[P0] = R0.l; - SSYNC; - - /* issue a system soft reset */ - P1.h = hi(SWRST); - P1.l = lo(SWRST); - R1.l = 0x0007; - W[P1] = R1; - SSYNC; - - /* clear system soft reset */ - R0.l = 0x0000; - W[P0] = R0; - SSYNC; - - /* issue core reset */ - raise 1; - - RTS; -ENDPROC(_bfin_reset) - .data /* From 4d5f4ed3fb797021523fc9fb6804047e8e35b33d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 27 Aug 2007 16:46:17 +0800 Subject: [PATCH 0045/2804] Blackfin arch: extract gpio number from PIN function Singed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_gpio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index d9284d7dc9fc..0d1e87b9c93d 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -902,7 +902,9 @@ EXPORT_SYMBOL(gpio_direction_output); */ void bfin_gpio_reset_spi0_ssel1(void) { - port_setup(P_SPI0_SSEL1, GPIO_USAGE); - gpio_bankb[gpio_bank(P_SPI0_SSEL1)]->data_set = gpio_bit(P_SPI0_SSEL1); + u16 gpio = P_IDENT(P_SPI0_SSEL1); + + port_setup(gpio, GPIO_USAGE); + gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio); udelay(1); } From 2296fb7ff04531dd8d50394da24f49302ecf103b Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Thu, 13 Sep 2007 11:49:33 +0800 Subject: [PATCH 0046/2804] Blackfin arch: Fix bug missing L2_MEMORY definition for EZKIT-BF561 compiling error Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- include/asm-blackfin/cplb.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h index df4766892767..06828d77a58f 100644 --- a/include/asm-blackfin/cplb.h +++ b/include/asm-blackfin/cplb.h @@ -30,7 +30,8 @@ #ifndef _CPLB_H #define _CPLB_H -# include +#include +#include #define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO) #define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK) @@ -54,6 +55,7 @@ #endif #define L1_DMEMORY (CPLB_LOCK | CPLB_COMMON) +#define L2_MEMORY (CPLB_COMMON) #define SDRAM_DNON_CHBL (CPLB_COMMON) #define SDRAM_EBIU (CPLB_COMMON) #define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY) From d2b11a468a49716debd96532552a72b6078f1cf5 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 28 Aug 2007 16:47:46 +0800 Subject: [PATCH 0047/2804] Blackfin arch: Merge GPIO/Peripheral Resource Allocation back into a single file Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/Makefile | 4 +- arch/blackfin/kernel/bfin_gpio.c | 225 ++++++++++++++++- arch/blackfin/mach-bf548/Makefile | 2 +- arch/blackfin/mach-bf548/gpio.c | 392 ------------------------------ 4 files changed, 216 insertions(+), 407 deletions(-) delete mode 100644 arch/blackfin/mach-bf548/gpio.c diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index ae0a2203c3da..243883ec6de1 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -7,10 +7,8 @@ extra-y := init_task.o vmlinux.lds obj-y := \ entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \ sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \ - fixed_code.o cplbinit.o cacheinit.o reboot.o + fixed_code.o cplbinit.o cacheinit.o reboot.o bfin_gpio.o -obj-$(CONFIG_BF53x) += bfin_gpio.o -obj-$(CONFIG_BF561) += bfin_gpio.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 0d1e87b9c93d..78438d88d22a 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -7,7 +7,7 @@ * Description: GPIO Abstraction Layer * * Modified: - * Copyright 2006 Analog Devices Inc. + * Copyright 2007 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -28,9 +28,9 @@ */ /* -* Number BF537/6/4 BF561 BF533/2/1 +* Number BF537/6/4 BF561 BF533/2/1 BF549/8/4/2 * -* GPIO_0 PF0 PF0 PF0 +* GPIO_0 PF0 PF0 PF0 PA0...PJ13 * GPIO_1 PF1 PF1 PF1 * GPIO_2 PF2 PF2 PF2 * GPIO_3 PF3 PF3 PF3 @@ -117,6 +117,21 @@ static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = { }; #endif +#ifdef BF548_FAMILY +static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { + (struct gpio_port_t *)PORTA_FER, + (struct gpio_port_t *)PORTB_FER, + (struct gpio_port_t *)PORTC_FER, + (struct gpio_port_t *)PORTD_FER, + (struct gpio_port_t *)PORTE_FER, + (struct gpio_port_t *)PORTF_FER, + (struct gpio_port_t *)PORTG_FER, + (struct gpio_port_t *)PORTH_FER, + (struct gpio_port_t *)PORTI_FER, + (struct gpio_port_t *)PORTJ_FER, +}; +#endif + static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)]; @@ -147,12 +162,24 @@ static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INT #endif /* CONFIG_PM */ +#if defined(BF548_FAMILY) +inline int check_gpio(unsigned short gpio) +{ + if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 + || gpio == GPIO_PH14 || gpio == GPIO_PH15 + || gpio == GPIO_PJ14 || gpio == GPIO_PJ15 + || gpio > MAX_BLACKFIN_GPIOS) + return -EINVAL; + return 0; +} +#else inline int check_gpio(unsigned short gpio) { if (gpio >= MAX_BLACKFIN_GPIOS) return -EINVAL; return 0; } +#endif static void set_label(unsigned short ident, const char *label) { @@ -185,19 +212,27 @@ static int cmp_label(unsigned short ident, const char *label) static void port_setup(unsigned short gpio, unsigned short usage) { if (!check_gpio(gpio)) { - if (usage == GPIO_USAGE) { + if (usage == GPIO_USAGE) *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); - } else + else *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); SSYNC(); } } +#elif defined(BF548_FAMILY) +static void port_setup(unsigned short gpio, unsigned short usage) +{ + if (usage == GPIO_USAGE) + gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); + else + gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); + SSYNC(); +} #else # define port_setup(...) do { } while (0) #endif #ifdef BF537_FAMILY - static struct { unsigned short res; unsigned short offset; @@ -268,11 +303,32 @@ static void portmux_setup(unsigned short per, unsigned short function) } } } +#elif defined(BF548_FAMILY) +inline void portmux_setup(unsigned short portno, unsigned short function) +{ + u32 pmux; + pmux = gpio_array[gpio_bank(portno)]->port_mux; + + pmux &= ~(0x3 << (2 * gpio_sub_n(portno))); + pmux |= (function & 0x3) << (2 * gpio_sub_n(portno)); + + gpio_array[gpio_bank(portno)]->port_mux = pmux; +} + +inline u16 get_portmux(unsigned short portno) +{ + u32 pmux; + + pmux = gpio_array[gpio_bank(portno)]->port_mux; + + return (pmux >> (2 * gpio_sub_n(portno)) & 0x3); +} #else # define portmux_setup(...) do { } while (0) #endif +#ifndef BF548_FAMILY static void default_gpio(unsigned short gpio) { unsigned short bank, bitmask; @@ -289,6 +345,9 @@ static void default_gpio(unsigned short gpio) gpio_bankb[bank]->both &= ~bitmask; gpio_bankb[bank]->edge &= ~bitmask; } +#else +# define default_gpio(...) do { } while (0) +#endif static int __init bfin_gpio_init(void) { @@ -307,6 +366,7 @@ static int __init bfin_gpio_init(void) arch_initcall(bfin_gpio_init); +#ifndef BF548_FAMILY /*********************************************************** * * FUNCTIONS: Blackfin General Purpose Ports Access Functions @@ -658,9 +718,95 @@ void gpio_pm_restore(void) } #endif +#endif /* BF548_FAMILY */ +/*********************************************************** +* +* FUNCTIONS: Blackfin Peripheral Resource Allocation +* and PortMux Setup +* +* INPUTS/OUTPUTS: +* per Peripheral Identifier +* label String +* +* DESCRIPTION: Blackfin Peripheral Resource Allocation and Setup API +* +* CAUTION: +************************************************************* +* MODIFICATION HISTORY : +**************************************************************/ +#ifdef BF548_FAMILY +int peripheral_request(unsigned short per, const char *label) +{ + unsigned long flags; + unsigned short ident = P_IDENT(per); + /* + * Don't cares are pins with only one dedicated function + */ + + if (per & P_DONTCARE) + return 0; + + if (!(per & P_DEFINED)) + return -ENODEV; + + if (check_gpio(ident) < 0) + return -EINVAL; + + local_irq_save(flags); + + if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { + printk(KERN_ERR + "%s: Peripheral %d is already reserved as GPIO by %s !\n", + __FUNCTION__, ident, get_label(ident)); + dump_stack(); + local_irq_restore(flags); + return -EBUSY; + } + + if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) { + + u16 funct = get_portmux(ident); + + /* + * Pin functions like AMC address strobes my + * be requested and used by several drivers + */ + + if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) { + + /* + * Allow that the identical pin function can + * be requested from the same driver twice + */ + + if (cmp_label(ident, label) == 0) + goto anyway; + + printk(KERN_ERR + "%s: Peripheral %d function %d is already reserved by %s !\n", + __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident)); + dump_stack(); + local_irq_restore(flags); + return -EBUSY; + } + } + +anyway: + reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); + + portmux_setup(ident, P_FUNCT2MUX(per)); + port_setup(ident, PERIPHERAL_USAGE); + + local_irq_restore(flags); + set_label(ident, label); + + return 0; +} +EXPORT_SYMBOL(peripheral_request); +#else int peripheral_request(unsigned short per, const char *label) { @@ -722,8 +868,6 @@ int peripheral_request(unsigned short per, const char *label) } anyway: - - portmux_setup(per, P_FUNCT2MUX(per)); port_setup(ident, PERIPHERAL_USAGE); @@ -735,6 +879,7 @@ anyway: return 0; } EXPORT_SYMBOL(peripheral_request); +#endif int peripheral_request_list(unsigned short per[], const char *label) { @@ -805,8 +950,8 @@ EXPORT_SYMBOL(peripheral_free_list); * FUNCTIONS: Blackfin GPIO Driver * * INPUTS/OUTPUTS: -* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS -* +* gpio PIO Number between 0 and MAX_BLACKFIN_GPIOS +* label String * * DESCRIPTION: Blackfin GPIO Driver API * @@ -825,16 +970,27 @@ int gpio_request(unsigned short gpio, const char *label) local_irq_save(flags); if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { - printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio); + printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", + gpio, get_label(gpio)); dump_stack(); local_irq_restore(flags); return -EBUSY; } + if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + printk(KERN_ERR + "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", + gpio, get_label(gpio)); + dump_stack(); + local_irq_restore(flags); + return -EBUSY; + } + reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); local_irq_restore(flags); port_setup(gpio, GPIO_USAGE); + set_label(gpio, label); return 0; } @@ -864,6 +1020,51 @@ void gpio_free(unsigned short gpio) } EXPORT_SYMBOL(gpio_free); +#ifdef BF548_FAMILY +void gpio_direction_input(unsigned short gpio) +{ + unsigned long flags; + + BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); + + local_irq_save(flags); + gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio); + gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio); + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_direction_input); + +void gpio_direction_output(unsigned short gpio) +{ + unsigned long flags; + + BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); + + local_irq_save(flags); + gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio); + gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio); + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_direction_output); + +void gpio_set_value(unsigned short gpio, unsigned short arg) +{ + if (arg) + gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio); + else + gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio); + +} +EXPORT_SYMBOL(gpio_set_value); + +unsigned short gpio_get_value(unsigned short gpio) +{ + return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio))); +} +EXPORT_SYMBOL(gpio_get_value); + +#else + void gpio_direction_input(unsigned short gpio) { unsigned long flags; @@ -908,3 +1109,5 @@ void bfin_gpio_reset_spi0_ssel1(void) gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio); udelay(1); } + +#endif /*BF548_FAMILY */ diff --git a/arch/blackfin/mach-bf548/Makefile b/arch/blackfin/mach-bf548/Makefile index 060ad78ebf1d..7e7c9c8ac5b2 100644 --- a/arch/blackfin/mach-bf548/Makefile +++ b/arch/blackfin/mach-bf548/Makefile @@ -4,6 +4,6 @@ extra-y := head.o -obj-y := ints-priority.o dma.o gpio.o +obj-y := ints-priority.o dma.o obj-$(CONFIG_CPU_FREQ) += cpu.o diff --git a/arch/blackfin/mach-bf548/gpio.c b/arch/blackfin/mach-bf548/gpio.c deleted file mode 100644 index 390dd8c12430..000000000000 --- a/arch/blackfin/mach-bf548/gpio.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * File: arch/blackfin/mach-bf548/gpio.c - * Based on: - * Author: Michael Hennerich (hennerich@blackfin.uclinux.org) - * - * Created: - * Description: GPIO Abstraction Layer - * - * Modified: - * Copyright 2007 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 - -static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { - (struct gpio_port_t *)PORTA_FER, - (struct gpio_port_t *)PORTB_FER, - (struct gpio_port_t *)PORTC_FER, - (struct gpio_port_t *)PORTD_FER, - (struct gpio_port_t *)PORTE_FER, - (struct gpio_port_t *)PORTF_FER, - (struct gpio_port_t *)PORTG_FER, - (struct gpio_port_t *)PORTH_FER, - (struct gpio_port_t *)PORTI_FER, - (struct gpio_port_t *)PORTJ_FER, -}; - -static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; -static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; - -#define MAX_RESOURCES 256 -#define RESOURCE_LABEL_SIZE 16 - -struct str_ident { - char name[RESOURCE_LABEL_SIZE]; -} *str_ident; - -inline int check_gpio(unsigned short gpio) -{ - if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 - || gpio == GPIO_PH14 || gpio == GPIO_PH15 - || gpio == GPIO_PJ14 || gpio == GPIO_PJ15 - || gpio > MAX_BLACKFIN_GPIOS) - return -EINVAL; - return 0; -} - -inline void portmux_setup(unsigned short portno, unsigned short function) -{ - u32 pmux; - - pmux = gpio_array[gpio_bank(portno)]->port_mux; - - pmux &= ~(0x3 << (2 * gpio_sub_n(portno))); - pmux |= (function & 0x3) << (2 * gpio_sub_n(portno)); - - gpio_array[gpio_bank(portno)]->port_mux = pmux; -} - -inline u16 get_portmux(unsigned short portno) -{ - u32 pmux; - - pmux = gpio_array[gpio_bank(portno)]->port_mux; - - return (pmux >> (2 * gpio_sub_n(portno)) & 0x3); -} - -static void port_setup(unsigned short gpio, unsigned short usage) -{ - if (usage == GPIO_USAGE) { - gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); - } else - gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); - SSYNC(); -} - -static int __init bfin_gpio_init(void) -{ - - str_ident = kcalloc(MAX_RESOURCES, - sizeof(struct str_ident), GFP_KERNEL); - if (str_ident == NULL) - return -ENOMEM; - - memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident)); - - printk(KERN_INFO "Blackfin GPIO Controller\n"); - - return 0; -} - -arch_initcall(bfin_gpio_init); - -static void set_label(unsigned short ident, const char *label) -{ - - if (label && str_ident) { - strncpy(str_ident[ident].name, label, - RESOURCE_LABEL_SIZE); - str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; - } -} - -static char *get_label(unsigned short ident) -{ - if (!str_ident) - return "UNKNOWN"; - - return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); -} - -static int cmp_label(unsigned short ident, const char *label) -{ - if (label && str_ident) - return strncmp(str_ident[ident].name, - label, strlen(label)); - else - return -EINVAL; -} - -int peripheral_request(unsigned short per, const char *label) -{ - unsigned long flags; - unsigned short ident = P_IDENT(per); - - /* - * Don't cares are pins with only one dedicated function - */ - - if (per & P_DONTCARE) - return 0; - - if (!(per & P_DEFINED)) - return -ENODEV; - - if (check_gpio(ident) < 0) - return -EINVAL; - - local_irq_save(flags); - - if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { - printk(KERN_ERR - "%s: Peripheral %d is already reserved as GPIO by %s !\n", - __FUNCTION__, ident, get_label(ident)); - dump_stack(); - local_irq_restore(flags); - return -EBUSY; - } - - if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) { - - u16 funct = get_portmux(ident); - - /* - * Pin functions like AMC address strobes my - * be requested and used by several drivers - */ - - if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) { - - /* - * Allow that the identical pin function can - * be requested from the same driver twice - */ - - if (cmp_label(ident, label) == 0) - goto anyway; - - printk(KERN_ERR - "%s: Peripheral %d function %d is already reserved by %s !\n", - __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident)); - dump_stack(); - local_irq_restore(flags); - return -EBUSY; - } - } - -anyway: - reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); - - portmux_setup(ident, P_FUNCT2MUX(per)); - port_setup(ident, PERIPHERAL_USAGE); - - local_irq_restore(flags); - set_label(ident, label); - - return 0; -} -EXPORT_SYMBOL(peripheral_request); - -int peripheral_request_list(unsigned short per[], const char *label) -{ - u16 cnt; - int ret; - - for (cnt = 0; per[cnt] != 0; cnt++) { - - ret = peripheral_request(per[cnt], label); - - if (ret < 0) { - for ( ; cnt > 0; cnt--) { - peripheral_free(per[cnt - 1]); - } - return ret; - } - } - - - return 0; -} -EXPORT_SYMBOL(peripheral_request_list); - -void peripheral_free(unsigned short per) -{ - unsigned long flags; - unsigned short ident = P_IDENT(per); - - if (per & P_DONTCARE) - return; - - if (!(per & P_DEFINED)) - return; - - if (check_gpio(ident) < 0) - return; - - local_irq_save(flags); - - if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) { - local_irq_restore(flags); - return; - } - - if (!(per & P_MAYSHARE)) { - port_setup(ident, GPIO_USAGE); - } - - reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident); - - local_irq_restore(flags); -} -EXPORT_SYMBOL(peripheral_free); - -void peripheral_free_list(unsigned short per[]) -{ - u16 cnt; - - for (cnt = 0; per[cnt] != 0; cnt++) { - peripheral_free(per[cnt]); - } - -} -EXPORT_SYMBOL(peripheral_free_list); - -/*********************************************************** -* -* FUNCTIONS: Blackfin GPIO Driver -* -* INPUTS/OUTPUTS: -* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS -* -* -* DESCRIPTION: Blackfin GPIO Driver API -* -* CAUTION: -************************************************************* -* MODIFICATION HISTORY : -**************************************************************/ - -int gpio_request(unsigned short gpio, const char *label) -{ - unsigned long flags; - - if (check_gpio(gpio) < 0) - return -EINVAL; - - local_irq_save(flags); - - if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { - printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", - gpio, get_label(gpio)); - dump_stack(); - local_irq_restore(flags); - return -EBUSY; - } - - if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { - printk(KERN_ERR - "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", - gpio, get_label(gpio)); - dump_stack(); - local_irq_restore(flags); - return -EBUSY; - } - - reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); - - local_irq_restore(flags); - - port_setup(gpio, GPIO_USAGE); - set_label(gpio, label); - - return 0; -} -EXPORT_SYMBOL(gpio_request); - -void gpio_free(unsigned short gpio) -{ - unsigned long flags; - - if (check_gpio(gpio) < 0) - return; - - local_irq_save(flags); - - if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { - printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio); - dump_stack(); - local_irq_restore(flags); - return; - } - - reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); - - local_irq_restore(flags); -} -EXPORT_SYMBOL(gpio_free); - -void gpio_direction_input(unsigned short gpio) -{ - unsigned long flags; - - BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); - - local_irq_save(flags); - gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio); - gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio); - local_irq_restore(flags); -} -EXPORT_SYMBOL(gpio_direction_input); - -void gpio_direction_output(unsigned short gpio) -{ - unsigned long flags; - - BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); - - local_irq_save(flags); - gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio); - gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio); - local_irq_restore(flags); -} -EXPORT_SYMBOL(gpio_direction_output); - -void gpio_set_value(unsigned short gpio, unsigned short arg) -{ - if (arg) - gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio); - else - gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio); - -} -EXPORT_SYMBOL(gpio_set_value); - -unsigned short gpio_get_value(unsigned short gpio) -{ - return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio))); -} -EXPORT_SYMBOL(gpio_get_value); From 02f13f9d5c1d3104c5c4e7f4ae30c43d595d1d75 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Mon, 27 Aug 2007 17:38:40 +0800 Subject: [PATCH 0048/2804] Blackfin arch: Remove cruft - CONFIG_DEBUG_SERIAL_EARLY_INIT didn't work that well with DEBUG_KERNEL_START Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/kernel/setup.c | 5 - arch/blackfin/mach-bf533/head.S | 243 -------------------------------- 2 files changed, 248 deletions(-) diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 448e6aab73ac..dfc464d8048e 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -192,11 +192,6 @@ void __init setup_arch(char **cmdline_p) } #endif -#ifdef DEBUG_SERIAL_EARLY_INIT - bfin_console_init(); /* early console registration */ - /* this give a chance to get printk() working before crash. */ -#endif - printk(KERN_INFO "Hardware Trace "); if (bfin_read_TBUFCTL() & 0x1 ) printk("Active "); diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S index 6e1b5f6da5ca..fa6dc0d8593b 100644 --- a/arch/blackfin/mach-bf533/head.S +++ b/arch/blackfin/mach-bf533/head.S @@ -35,9 +35,6 @@ #include #include #endif -#if CONFIG_DEBUG_KERNEL_START -#include -#endif .global __rambase .global __ramstart @@ -104,36 +101,6 @@ ENTRY(__start) P0 = R1; R0 = R1; -#if CONFIG_DEBUG_KERNEL_START - -/* - * Set up a temporary Event Vector Table, so if something bad happens before - * the kernel is fully started, it doesn't vector off into the bootloaders - * table - */ - P0.l = lo(EVT2); - P0.h = hi(EVT2); - P1.l = lo(EVT15); - P1.h = hi(EVT15); - P2.l = debug_kernel_start_trap; - P2.h = debug_kernel_start_trap; - - RTS = P2; - RTI = P2; - RTX = P2; - RTN = P2; - RTE = P2; - -.Lfill_temp_vector_table: - [P0++] = P2; /* Core Event Vector Table */ - CC = P0 == P1; - if !CC JUMP .Lfill_temp_vector_table - P0 = r0; - P1 = r0; - P2 = r0; - -#endif - p0.h = hi(FIO_MASKA_C); p0.l = lo(FIO_MASKA_C); r0 = 0xFFFF(Z); @@ -459,216 +426,6 @@ ENTRY(_start_dma_code) ENDPROC(_start_dma_code) #endif /* CONFIG_BFIN_KERNEL_CLOCK */ -#if CONFIG_DEBUG_KERNEL_START -debug_kernel_start_trap: - /* Set up a temp stack in L1 - SDRAM might not be working */ - P0.L = lo(L1_DATA_A_START + 0x100); - P0.H = hi(L1_DATA_A_START + 0x100); - SP = P0; - - /* Make sure the Clocks are the way I think they should be */ - r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ - r0 = r0 << 9; /* Shift it over, */ - r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ - r0 = r1 | r0; - r1 = PLL_BYPASS; /* Bypass the PLL? */ - r1 = r1 << 8; /* Shift it over */ - r0 = r1 | r0; /* add them all together */ - - p0.h = hi(PLL_CTL); - p0.l = lo(PLL_CTL); /* Load the address */ - cli r2; /* Disable interrupts */ - ssync; - w[p0] = r0.l; /* Set the value */ - idle; /* Wait for the PLL to stablize */ - sti r2; /* Enable interrupts */ - -.Lcheck_again1: - p0.h = hi(PLL_STAT); - p0.l = lo(PLL_STAT); - R0 = W[P0](Z); - CC = BITTST(R0,5); - if ! CC jump .Lcheck_again1; - - /* Configure SCLK & CCLK Dividers */ - r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); - p0.h = hi(PLL_DIV); - p0.l = lo(PLL_DIV); - w[p0] = r0.l; - ssync; - - /* Make sure UART is enabled - you can never be sure */ - -/* - * Setup for console. Argument comes from the menuconfig - */ - -#ifdef CONFIG_BAUD_9600 -#define CONSOLE_BAUD_RATE 9600 -#elif CONFIG_BAUD_19200 -#define CONSOLE_BAUD_RATE 19200 -#elif CONFIG_BAUD_38400 -#define CONSOLE_BAUD_RATE 38400 -#elif CONFIG_BAUD_57600 -#define CONSOLE_BAUD_RATE 57600 -#elif CONFIG_BAUD_115200 -#define CONSOLE_BAUD_RATE 115200 -#endif - - p0.h = hi(UART_GCTL); - p0.l = lo(UART_GCTL); - r0 = 0x00(Z); - w[p0] = r0.L; /* To Turn off UART clocks */ - ssync; - - p0.h = hi(UART_LCR); - p0.l = lo(UART_LCR); - r0 = 0x83(Z); - w[p0] = r0.L; /* To enable DLL writes */ - ssync; - - R1 = (((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_SCLK_DIV) / (CONSOLE_BAUD_RATE * 16)); - - p0.h = hi(UART_DLL); - p0.l = lo(UART_DLL); - r0 = 0xFF(Z); - r0 = R1 & R0; - w[p0] = r0.L; - ssync; - - p0.h = hi(UART_DLH); - p0.l = lo(UART_DLH); - r1 >>= 8 ; - w[p0] = r1.L; - ssync; - - p0.h = hi(UART_GCTL); - p0.l = lo(UART_GCTL); - r0 = 0x0(Z); - w[p0] = r0.L; /* To enable UART clock */ - ssync; - - p0.h = hi(UART_LCR); - p0.l = lo(UART_LCR); - r0 = 0x03(Z); - w[p0] = r0.L; /* To Turn on UART */ - ssync; - - p0.h = hi(UART_GCTL); - p0.l = lo(UART_GCTL); - r0 = 0x01(Z); - w[p0] = r0.L; /* To Turn on UART Clocks */ - ssync; - - P0.h = hi(UART_THR); - P0.l = lo(UART_THR); - P1.h = hi(UART_LSR); - P1.l = lo(UART_LSR); - - R0.L = 'K'; - call .Lwait_char; - R0.L='e'; - call .Lwait_char; - R0.L='r'; - call .Lwait_char; - R0.L='n' - call .Lwait_char; - R0.L='e' - call .Lwait_char; - R0.L='l'; - call .Lwait_char; - R0.L=' '; - call .Lwait_char; - R0.L='c'; - call .Lwait_char; - R0.L='r'; - call .Lwait_char; - R0.L='a'; - call .Lwait_char; - R0.L='s'; - call .Lwait_char; - R0.L='h'; - call .Lwait_char; - R0.L='\r'; - call .Lwait_char; - R0.L='\n'; - call .Lwait_char; - - R0.L='S'; - call .Lwait_char; - R0.L='E'; - call .Lwait_char; - R0.L='Q' - call .Lwait_char; - R0.L='S' - call .Lwait_char; - R0.L='T'; - call .Lwait_char; - R0.L='A'; - call .Lwait_char; - R0.L='T'; - call .Lwait_char; - R0.L='='; - call .Lwait_char; - R2 = SEQSTAT; - call .Ldump_reg; - - R0.L=' '; - call .Lwait_char; - R0.L='R'; - call .Lwait_char; - R0.L='E' - call .Lwait_char; - R0.L='T' - call .Lwait_char; - R0.L='X'; - call .Lwait_char; - R0.L='='; - call .Lwait_char; - R2 = RETX; - call .Ldump_reg; - - R0.L='\r'; - call .Lwait_char; - R0.L='\n'; - call .Lwait_char; - -.Ldebug_kernel_start_trap_done: - JUMP .Ldebug_kernel_start_trap_done; -.Ldump_reg: - R3 = 32; - R4 = 0x0F; - R5 = ':'; /* one past 9 */ - -.Ldump_reg2: - R0 = R2; - R3 += -4; - R0 >>>= R3; - R0 = R0 & R4; - R0 += 0x30; - CC = R0 <= R5; - if CC JUMP .Ldump_reg1; - R0 += 7; - -.Ldump_reg1: - R1.l = W[P1]; - CC = BITTST(R1, 5); - if !CC JUMP .Ldump_reg1; - W[P0] = r0; - - CC = R3 == 0; - if !CC JUMP .Ldump_reg2 - RTS; - -.Lwait_char: - R1.l = W[P1]; - CC = BITTST(R1, 5); - if !CC JUMP .Lwait_char; - W[P0] = r0; - RTS; - -#endif /* CONFIG_DEBUG_KERNEL_START */ - .data /* From 55249e9e3d07617e00cc6c52b83f7d1a7eb7e64d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 11 Oct 2007 00:06:31 +0800 Subject: [PATCH 0049/2804] Blackfin arch: For compatibility reasons change IRQ_XXX_ERR into IRQ_XXX_ERROR like on any other supported Blackfin derivative Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf548/irq.h | 563 ++++++++++++++------------ 1 file changed, 295 insertions(+), 268 deletions(-) diff --git a/include/asm-blackfin/mach-bf548/irq.h b/include/asm-blackfin/mach-bf548/irq.h index 21f06f710be6..3b08cf9bd6f3 100644 --- a/include/asm-blackfin/mach-bf548/irq.h +++ b/include/asm-blackfin/mach-bf548/irq.h @@ -55,287 +55,286 @@ Events (highest priority) EMU 0 /* The ABSTRACT IRQ definitions */ /** the first seven of the following are fixed, the rest you change if you need to **/ -#define IRQ_EMU 0 /* Emulation */ -#define IRQ_RST 1 /* reset */ -#define IRQ_NMI 2 /* Non Maskable */ -#define IRQ_EVX 3 /* Exception */ -#define IRQ_UNUSED 4 /* - unused interrupt*/ -#define IRQ_HWERR 5 /* Hardware Error */ -#define IRQ_CORETMR 6 /* Core timer */ +#define IRQ_EMU 0 /* Emulation */ +#define IRQ_RST 1 /* reset */ +#define IRQ_NMI 2 /* Non Maskable */ +#define IRQ_EVX 3 /* Exception */ +#define IRQ_UNUSED 4 /* - unused interrupt*/ +#define IRQ_HWERR 5 /* Hardware Error */ +#define IRQ_CORETMR 6 /* Core timer */ -#define BFIN_IRQ(x) ((x) + 7) +#define BFIN_IRQ(x) ((x) + 7) -#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */ -#define IRQ_DMAC0_ERR BFIN_IRQ(1) /* DMAC0 Status Interrupt */ -#define IRQ_EPPI0_ERR BFIN_IRQ(2) /* EPPI0 Error Interrupt */ -#define IRQ_SPORT0_ERR BFIN_IRQ(3) /* SPORT0 Error Interrupt */ -#define IRQ_SPORT1_ERR BFIN_IRQ(4) /* SPORT1 Error Interrupt */ -#define IRQ_SPI0_ERR BFIN_IRQ(5) /* SPI0 Status(Error) Interrupt */ -#define IRQ_UART0_ERR BFIN_IRQ(6) /* UART0 Status(Error) Interrupt */ -#define IRQ_RTC BFIN_IRQ(7) /* RTC Interrupt */ -#define IRQ_EPPI0 BFIN_IRQ(8) /* EPPI0 Interrupt (DMA12) */ -#define IRQ_SPORT0_RX BFIN_IRQ(9) /* SPORT0 RX Interrupt (DMA0) */ -#define IRQ_SPORT0_TX BFIN_IRQ(10) /* SPORT0 TX Interrupt (DMA1) */ -#define IRQ_SPORT1_RX BFIN_IRQ(11) /* SPORT1 RX Interrupt (DMA2) */ -#define IRQ_SPORT1_TX BFIN_IRQ(12) /* SPORT1 TX Interrupt (DMA3) */ -#define IRQ_SPI0 BFIN_IRQ(13) /* SPI0 Interrupt (DMA4) */ -#define IRQ_UART0_RX BFIN_IRQ(14) /* UART0 RX Interrupt (DMA6) */ -#define IRQ_UART0_TX BFIN_IRQ(15) /* UART0 TX Interrupt (DMA7) */ -#define IRQ_TIMER8 BFIN_IRQ(16) /* TIMER 8 Interrupt */ -#define IRQ_TIMER9 BFIN_IRQ(17) /* TIMER 9 Interrupt */ -#define IRQ_TIMER10 BFIN_IRQ(18) /* TIMER 10 Interrupt */ -#define IRQ_PINT0 BFIN_IRQ(19) /* PINT0 Interrupt */ -#define IRQ_PINT1 BFIN_IRQ(20) /* PINT1 Interrupt */ -#define IRQ_MDMAS0 BFIN_IRQ(21) /* MDMA Stream 0 Interrupt */ -#define IRQ_MDMAS1 BFIN_IRQ(22) /* MDMA Stream 1 Interrupt */ -#define IRQ_WATCHDOG BFIN_IRQ(23) /* Watchdog Interrupt */ -#define IRQ_DMAC1_ERR BFIN_IRQ(24) /* DMAC1 Status (Error) Interrupt */ -#define IRQ_SPORT2_ERR BFIN_IRQ(25) /* SPORT2 Error Interrupt */ -#define IRQ_SPORT3_ERR BFIN_IRQ(26) /* SPORT3 Error Interrupt */ -#define IRQ_MXVR_DATA BFIN_IRQ(27) /* MXVR Data Interrupt */ -#define IRQ_SPI1_ERR BFIN_IRQ(28) /* SPI1 Status (Error) Interrupt */ -#define IRQ_SPI2_ERR BFIN_IRQ(29) /* SPI2 Status (Error) Interrupt */ -#define IRQ_UART1_ERR BFIN_IRQ(30) /* UART1 Status (Error) Interrupt */ -#define IRQ_UART2_ERR BFIN_IRQ(31) /* UART2 Status (Error) Interrupt */ -#define IRQ_CAN0_ERR BFIN_IRQ(32) /* CAN0 Status (Error) Interrupt */ -#define IRQ_SPORT2_RX BFIN_IRQ(33) /* SPORT2 RX (DMA18) Interrupt */ -#define IRQ_SPORT2_TX BFIN_IRQ(34) /* SPORT2 TX (DMA19) Interrupt */ -#define IRQ_SPORT3_RX BFIN_IRQ(35) /* SPORT3 RX (DMA20) Interrupt */ -#define IRQ_SPORT3_TX BFIN_IRQ(36) /* SPORT3 TX (DMA21) Interrupt */ -#define IRQ_EPPI1 BFIN_IRQ(37) /* EPP1 (DMA13) Interrupt */ -#define IRQ_EPPI2 BFIN_IRQ(38) /* EPP2 (DMA14) Interrupt */ -#define IRQ_SPI1 BFIN_IRQ(39) /* SPI1 (DMA5) Interrupt */ -#define IRQ_SPI2 BFIN_IRQ(40) /* SPI2 (DMA23) Interrupt */ -#define IRQ_UART1_RX BFIN_IRQ(41) /* UART1 RX (DMA8) Interrupt */ -#define IRQ_UART1_TX BFIN_IRQ(42) /* UART1 TX (DMA9) Interrupt */ -#define IRQ_ATAPI_RX BFIN_IRQ(43) /* ATAPI RX (DMA10) Interrupt */ -#define IRQ_ATAPI_TX BFIN_IRQ(44) /* ATAPI TX (DMA11) Interrupt */ -#define IRQ_TWI0 BFIN_IRQ(45) /* TWI0 Interrupt */ -#define IRQ_TWI1 BFIN_IRQ(46) /* TWI1 Interrupt */ -#define IRQ_TWI IRQ_TWI0 /* TWI Interrupt */ -#define IRQ_CAN0_RX BFIN_IRQ(47) /* CAN0 Receive Interrupt */ -#define IRQ_CAN0_TX BFIN_IRQ(48) /* CAN0 Transmit Interrupt */ -#define IRQ_MDMAS2 BFIN_IRQ(49) /* MDMA Stream 2 Interrupt */ -#define IRQ_MDMAS3 BFIN_IRQ(50) /* MDMA Stream 3 Interrupt */ -#define IRQ_MXVR_ERR BFIN_IRQ(51) /* MXVR Status (Error) Interrupt */ -#define IRQ_MXVR_MSG BFIN_IRQ(52) /* MXVR Message Interrupt */ -#define IRQ_MXVR_PKT BFIN_IRQ(53) /* MXVR Packet Interrupt */ -#define IRQ_EPP1_ERR BFIN_IRQ(54) /* EPPI1 Error Interrupt */ -#define IRQ_EPP2_ERR BFIN_IRQ(55) /* EPPI2 Error Interrupt */ -#define IRQ_UART3_ERR BFIN_IRQ(56) /* UART3 Status (Error) Interrupt */ -#define IRQ_HOST_ERR BFIN_IRQ(57) /* HOST Status (Error) Interrupt */ -#define IRQ_PIXC_ERR BFIN_IRQ(59) /* PIXC Status (Error) Interrupt */ -#define IRQ_NFC_ERR BFIN_IRQ(60) /* NFC Error Interrupt */ -#define IRQ_ATAPI_ERR BFIN_IRQ(61) /* ATAPI Error Interrupt */ -#define IRQ_CAN1_ERR BFIN_IRQ(62) /* CAN1 Status (Error) Interrupt */ -#define IRQ_HS_DMA_ERR BFIN_IRQ(63) /* Handshake DMA Status Interrupt */ -#define IRQ_PIXC_IN0 BFIN_IRQ(64) /* PIXC IN0 (DMA15) Interrupt */ -#define IRQ_PIXC_IN1 BFIN_IRQ(65) /* PIXC IN1 (DMA16) Interrupt */ -#define IRQ_PIXC_OUT BFIN_IRQ(66) /* PIXC OUT (DMA17) Interrupt */ -#define IRQ_SDH BFIN_IRQ(67) /* SDH/NFC (DMA22) Interrupt */ -#define IRQ_CNT BFIN_IRQ(68) /* CNT Interrupt */ -#define IRQ_KEY BFIN_IRQ(69) /* KEY Interrupt */ -#define IRQ_CAN1_RX BFIN_IRQ(70) /* CAN1 RX Interrupt */ -#define IRQ_CAN1_TX BFIN_IRQ(71) /* CAN1 TX Interrupt */ -#define IRQ_SDH_MASK0 BFIN_IRQ(72) /* SDH Mask 0 Interrupt */ -#define IRQ_SDH_MASK1 BFIN_IRQ(73) /* SDH Mask 1 Interrupt */ -#define IRQ_USB_INT0 BFIN_IRQ(75) /* USB INT0 Interrupt */ -#define IRQ_USB_INT1 BFIN_IRQ(76) /* USB INT1 Interrupt */ -#define IRQ_USB_INT2 BFIN_IRQ(77) /* USB INT2 Interrupt */ -#define IRQ_USB_DMA BFIN_IRQ(78) /* USB DMA Interrupt */ -#define IRQ_OPTSEC BFIN_IRQ(79) /* OTPSEC Interrupt */ -#define IRQ_TIMER0 BFIN_IRQ(86) /* Timer 0 Interrupt */ -#define IRQ_TIMER1 BFIN_IRQ(87) /* Timer 1 Interrupt */ -#define IRQ_TIMER2 BFIN_IRQ(88) /* Timer 2 Interrupt */ -#define IRQ_TIMER3 BFIN_IRQ(89) /* Timer 3 Interrupt */ -#define IRQ_TIMER4 BFIN_IRQ(90) /* Timer 4 Interrupt */ -#define IRQ_TIMER5 BFIN_IRQ(91) /* Timer 5 Interrupt */ -#define IRQ_TIMER6 BFIN_IRQ(92) /* Timer 6 Interrupt */ -#define IRQ_TIMER7 BFIN_IRQ(93) /* Timer 7 Interrupt */ -#define IRQ_PINT2 BFIN_IRQ(94) /* PINT2 Interrupt */ -#define IRQ_PINT3 BFIN_IRQ(95) /* PINT3 Interrupt */ +#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */ +#define IRQ_DMAC0_ERROR BFIN_IRQ(1) /* DMAC0 Status Interrupt */ +#define IRQ_EPPI0_ERROR BFIN_IRQ(2) /* EPPI0 Error Interrupt */ +#define IRQ_SPORT0_ERROR BFIN_IRQ(3) /* SPORT0 Error Interrupt */ +#define IRQ_SPORT1_ERROR BFIN_IRQ(4) /* SPORT1 Error Interrupt */ +#define IRQ_SPI0_ERROR BFIN_IRQ(5) /* SPI0 Status(Error) Interrupt */ +#define IRQ_UART0_ERROR BFIN_IRQ(6) /* UART0 Status(Error) Interrupt */ +#define IRQ_RTC BFIN_IRQ(7) /* RTC Interrupt */ +#define IRQ_EPPI0 BFIN_IRQ(8) /* EPPI0 Interrupt (DMA12) */ +#define IRQ_SPORT0_RX BFIN_IRQ(9) /* SPORT0 RX Interrupt (DMA0) */ +#define IRQ_SPORT0_TX BFIN_IRQ(10) /* SPORT0 TX Interrupt (DMA1) */ +#define IRQ_SPORT1_RX BFIN_IRQ(11) /* SPORT1 RX Interrupt (DMA2) */ +#define IRQ_SPORT1_TX BFIN_IRQ(12) /* SPORT1 TX Interrupt (DMA3) */ +#define IRQ_SPI0 BFIN_IRQ(13) /* SPI0 Interrupt (DMA4) */ +#define IRQ_UART0_RX BFIN_IRQ(14) /* UART0 RX Interrupt (DMA6) */ +#define IRQ_UART0_TX BFIN_IRQ(15) /* UART0 TX Interrupt (DMA7) */ +#define IRQ_TIMER8 BFIN_IRQ(16) /* TIMER 8 Interrupt */ +#define IRQ_TIMER9 BFIN_IRQ(17) /* TIMER 9 Interrupt */ +#define IRQ_TIMER10 BFIN_IRQ(18) /* TIMER 10 Interrupt */ +#define IRQ_PINT0 BFIN_IRQ(19) /* PINT0 Interrupt */ +#define IRQ_PINT1 BFIN_IRQ(20) /* PINT1 Interrupt */ +#define IRQ_MDMAS0 BFIN_IRQ(21) /* MDMA Stream 0 Interrupt */ +#define IRQ_MDMAS1 BFIN_IRQ(22) /* MDMA Stream 1 Interrupt */ +#define IRQ_WATCHDOG BFIN_IRQ(23) /* Watchdog Interrupt */ +#define IRQ_DMAC1_ERROR BFIN_IRQ(24) /* DMAC1 Status (Error) Interrupt */ +#define IRQ_SPORT2_ERROR BFIN_IRQ(25) /* SPORT2 Error Interrupt */ +#define IRQ_SPORT3_ERROR BFIN_IRQ(26) /* SPORT3 Error Interrupt */ +#define IRQ_MXVR_DATA BFIN_IRQ(27) /* MXVR Data Interrupt */ +#define IRQ_SPI1_ERROR BFIN_IRQ(28) /* SPI1 Status (Error) Interrupt */ +#define IRQ_SPI2_ERROR BFIN_IRQ(29) /* SPI2 Status (Error) Interrupt */ +#define IRQ_UART1_ERROR BFIN_IRQ(30) /* UART1 Status (Error) Interrupt */ +#define IRQ_UART2_ERROR BFIN_IRQ(31) /* UART2 Status (Error) Interrupt */ +#define IRQ_CAN0_ERROR BFIN_IRQ(32) /* CAN0 Status (Error) Interrupt */ +#define IRQ_SPORT2_RX BFIN_IRQ(33) /* SPORT2 RX (DMA18) Interrupt */ +#define IRQ_SPORT2_TX BFIN_IRQ(34) /* SPORT2 TX (DMA19) Interrupt */ +#define IRQ_SPORT3_RX BFIN_IRQ(35) /* SPORT3 RX (DMA20) Interrupt */ +#define IRQ_SPORT3_TX BFIN_IRQ(36) /* SPORT3 TX (DMA21) Interrupt */ +#define IRQ_EPPI1 BFIN_IRQ(37) /* EPP1 (DMA13) Interrupt */ +#define IRQ_EPPI2 BFIN_IRQ(38) /* EPP2 (DMA14) Interrupt */ +#define IRQ_SPI1 BFIN_IRQ(39) /* SPI1 (DMA5) Interrupt */ +#define IRQ_SPI2 BFIN_IRQ(40) /* SPI2 (DMA23) Interrupt */ +#define IRQ_UART1_RX BFIN_IRQ(41) /* UART1 RX (DMA8) Interrupt */ +#define IRQ_UART1_TX BFIN_IRQ(42) /* UART1 TX (DMA9) Interrupt */ +#define IRQ_ATAPI_RX BFIN_IRQ(43) /* ATAPI RX (DMA10) Interrupt */ +#define IRQ_ATAPI_TX BFIN_IRQ(44) /* ATAPI TX (DMA11) Interrupt */ +#define IRQ_TWI0 BFIN_IRQ(45) /* TWI0 Interrupt */ +#define IRQ_TWI1 BFIN_IRQ(46) /* TWI1 Interrupt */ +#define IRQ_CAN0_RX BFIN_IRQ(47) /* CAN0 Receive Interrupt */ +#define IRQ_CAN0_TX BFIN_IRQ(48) /* CAN0 Transmit Interrupt */ +#define IRQ_MDMAS2 BFIN_IRQ(49) /* MDMA Stream 2 Interrupt */ +#define IRQ_MDMAS3 BFIN_IRQ(50) /* MDMA Stream 3 Interrupt */ +#define IRQ_MXVR_ERROR BFIN_IRQ(51) /* MXVR Status (Error) Interrupt */ +#define IRQ_MXVR_MSG BFIN_IRQ(52) /* MXVR Message Interrupt */ +#define IRQ_MXVR_PKT BFIN_IRQ(53) /* MXVR Packet Interrupt */ +#define IRQ_EPP1_ERROR BFIN_IRQ(54) /* EPPI1 Error Interrupt */ +#define IRQ_EPP2_ERROR BFIN_IRQ(55) /* EPPI2 Error Interrupt */ +#define IRQ_UART3_ERROR BFIN_IRQ(56) /* UART3 Status (Error) Interrupt */ +#define IRQ_HOST_ERROR BFIN_IRQ(57) /* HOST Status (Error) Interrupt */ +#define IRQ_PIXC_ERROR BFIN_IRQ(59) /* PIXC Status (Error) Interrupt */ +#define IRQ_NFC_ERROR BFIN_IRQ(60) /* NFC Error Interrupt */ +#define IRQ_ATAPI_ERROR BFIN_IRQ(61) /* ATAPI Error Interrupt */ +#define IRQ_CAN1_ERROR BFIN_IRQ(62) /* CAN1 Status (Error) Interrupt */ +#define IRQ_HS_DMA_ERROR BFIN_IRQ(63) /* Handshake DMA Status Interrupt */ +#define IRQ_PIXC_IN0 BFIN_IRQ(64) /* PIXC IN0 (DMA15) Interrupt */ +#define IRQ_PIXC_IN1 BFIN_IRQ(65) /* PIXC IN1 (DMA16) Interrupt */ +#define IRQ_PIXC_OUT BFIN_IRQ(66) /* PIXC OUT (DMA17) Interrupt */ +#define IRQ_SDH BFIN_IRQ(67) /* SDH/NFC (DMA22) Interrupt */ +#define IRQ_CNT BFIN_IRQ(68) /* CNT Interrupt */ +#define IRQ_KEY BFIN_IRQ(69) /* KEY Interrupt */ +#define IRQ_CAN1_RX BFIN_IRQ(70) /* CAN1 RX Interrupt */ +#define IRQ_CAN1_TX BFIN_IRQ(71) /* CAN1 TX Interrupt */ +#define IRQ_SDH_MASK0 BFIN_IRQ(72) /* SDH Mask 0 Interrupt */ +#define IRQ_SDH_MASK1 BFIN_IRQ(73) /* SDH Mask 1 Interrupt */ +#define IRQ_USB_INT0 BFIN_IRQ(75) /* USB INT0 Interrupt */ +#define IRQ_USB_INT1 BFIN_IRQ(76) /* USB INT1 Interrupt */ +#define IRQ_USB_INT2 BFIN_IRQ(77) /* USB INT2 Interrupt */ +#define IRQ_USB_DMA BFIN_IRQ(78) /* USB DMA Interrupt */ +#define IRQ_OPTSEC BFIN_IRQ(79) /* OTPSEC Interrupt */ +#define IRQ_TIMER0 BFIN_IRQ(86) /* Timer 0 Interrupt */ +#define IRQ_TIMER1 BFIN_IRQ(87) /* Timer 1 Interrupt */ +#define IRQ_TIMER2 BFIN_IRQ(88) /* Timer 2 Interrupt */ +#define IRQ_TIMER3 BFIN_IRQ(89) /* Timer 3 Interrupt */ +#define IRQ_TIMER4 BFIN_IRQ(90) /* Timer 4 Interrupt */ +#define IRQ_TIMER5 BFIN_IRQ(91) /* Timer 5 Interrupt */ +#define IRQ_TIMER6 BFIN_IRQ(92) /* Timer 6 Interrupt */ +#define IRQ_TIMER7 BFIN_IRQ(93) /* Timer 7 Interrupt */ +#define IRQ_PINT2 BFIN_IRQ(94) /* PINT2 Interrupt */ +#define IRQ_PINT3 BFIN_IRQ(95) /* PINT3 Interrupt */ -#define SYS_IRQS IRQ_PINT3 +#define SYS_IRQS IRQ_PINT3 -#define BFIN_PA_IRQ(x) ((x) + SYS_IRQS + 1) -#define IRQ_PA0 BFIN_PA_IRQ(0) -#define IRQ_PA1 BFIN_PA_IRQ(1) -#define IRQ_PA2 BFIN_PA_IRQ(2) -#define IRQ_PA3 BFIN_PA_IRQ(3) -#define IRQ_PA4 BFIN_PA_IRQ(4) -#define IRQ_PA5 BFIN_PA_IRQ(5) -#define IRQ_PA6 BFIN_PA_IRQ(6) -#define IRQ_PA7 BFIN_PA_IRQ(7) -#define IRQ_PA8 BFIN_PA_IRQ(8) -#define IRQ_PA9 BFIN_PA_IRQ(9) -#define IRQ_PA10 BFIN_PA_IRQ(10) -#define IRQ_PA11 BFIN_PA_IRQ(11) -#define IRQ_PA12 BFIN_PA_IRQ(12) -#define IRQ_PA13 BFIN_PA_IRQ(13) -#define IRQ_PA14 BFIN_PA_IRQ(14) -#define IRQ_PA15 BFIN_PA_IRQ(15) +#define BFIN_PA_IRQ(x) ((x) + SYS_IRQS + 1) +#define IRQ_PA0 BFIN_PA_IRQ(0) +#define IRQ_PA1 BFIN_PA_IRQ(1) +#define IRQ_PA2 BFIN_PA_IRQ(2) +#define IRQ_PA3 BFIN_PA_IRQ(3) +#define IRQ_PA4 BFIN_PA_IRQ(4) +#define IRQ_PA5 BFIN_PA_IRQ(5) +#define IRQ_PA6 BFIN_PA_IRQ(6) +#define IRQ_PA7 BFIN_PA_IRQ(7) +#define IRQ_PA8 BFIN_PA_IRQ(8) +#define IRQ_PA9 BFIN_PA_IRQ(9) +#define IRQ_PA10 BFIN_PA_IRQ(10) +#define IRQ_PA11 BFIN_PA_IRQ(11) +#define IRQ_PA12 BFIN_PA_IRQ(12) +#define IRQ_PA13 BFIN_PA_IRQ(13) +#define IRQ_PA14 BFIN_PA_IRQ(14) +#define IRQ_PA15 BFIN_PA_IRQ(15) -#define BFIN_PB_IRQ(x) ((x) + IRQ_PA15 + 1) -#define IRQ_PB0 BFIN_PB_IRQ(0) -#define IRQ_PB1 BFIN_PB_IRQ(1) -#define IRQ_PB2 BFIN_PB_IRQ(2) -#define IRQ_PB3 BFIN_PB_IRQ(3) -#define IRQ_PB4 BFIN_PB_IRQ(4) -#define IRQ_PB5 BFIN_PB_IRQ(5) -#define IRQ_PB6 BFIN_PB_IRQ(6) -#define IRQ_PB7 BFIN_PB_IRQ(7) -#define IRQ_PB8 BFIN_PB_IRQ(8) -#define IRQ_PB9 BFIN_PB_IRQ(9) -#define IRQ_PB10 BFIN_PB_IRQ(10) -#define IRQ_PB11 BFIN_PB_IRQ(11) -#define IRQ_PB12 BFIN_PB_IRQ(12) -#define IRQ_PB13 BFIN_PB_IRQ(13) -#define IRQ_PB14 BFIN_PB_IRQ(14) -#define IRQ_PB15 BFIN_PB_IRQ(15) /* N/A */ +#define BFIN_PB_IRQ(x) ((x) + IRQ_PA15 + 1) +#define IRQ_PB0 BFIN_PB_IRQ(0) +#define IRQ_PB1 BFIN_PB_IRQ(1) +#define IRQ_PB2 BFIN_PB_IRQ(2) +#define IRQ_PB3 BFIN_PB_IRQ(3) +#define IRQ_PB4 BFIN_PB_IRQ(4) +#define IRQ_PB5 BFIN_PB_IRQ(5) +#define IRQ_PB6 BFIN_PB_IRQ(6) +#define IRQ_PB7 BFIN_PB_IRQ(7) +#define IRQ_PB8 BFIN_PB_IRQ(8) +#define IRQ_PB9 BFIN_PB_IRQ(9) +#define IRQ_PB10 BFIN_PB_IRQ(10) +#define IRQ_PB11 BFIN_PB_IRQ(11) +#define IRQ_PB12 BFIN_PB_IRQ(12) +#define IRQ_PB13 BFIN_PB_IRQ(13) +#define IRQ_PB14 BFIN_PB_IRQ(14) +#define IRQ_PB15 BFIN_PB_IRQ(15) /* N/A */ -#define BFIN_PC_IRQ(x) ((x) + IRQ_PB15 + 1) -#define IRQ_PC0 BFIN_PC_IRQ(0) -#define IRQ_PC1 BFIN_PC_IRQ(1) -#define IRQ_PC2 BFIN_PC_IRQ(2) -#define IRQ_PC3 BFIN_PC_IRQ(3) -#define IRQ_PC4 BFIN_PC_IRQ(4) -#define IRQ_PC5 BFIN_PC_IRQ(5) -#define IRQ_PC6 BFIN_PC_IRQ(6) -#define IRQ_PC7 BFIN_PC_IRQ(7) -#define IRQ_PC8 BFIN_PC_IRQ(8) -#define IRQ_PC9 BFIN_PC_IRQ(9) -#define IRQ_PC10 BFIN_PC_IRQ(10) -#define IRQ_PC11 BFIN_PC_IRQ(11) -#define IRQ_PC12 BFIN_PC_IRQ(12) -#define IRQ_PC13 BFIN_PC_IRQ(13) -#define IRQ_PC14 BFIN_PC_IRQ(14) /* N/A */ -#define IRQ_PC15 BFIN_PC_IRQ(15) /* N/A */ +#define BFIN_PC_IRQ(x) ((x) + IRQ_PB15 + 1) +#define IRQ_PC0 BFIN_PC_IRQ(0) +#define IRQ_PC1 BFIN_PC_IRQ(1) +#define IRQ_PC2 BFIN_PC_IRQ(2) +#define IRQ_PC3 BFIN_PC_IRQ(3) +#define IRQ_PC4 BFIN_PC_IRQ(4) +#define IRQ_PC5 BFIN_PC_IRQ(5) +#define IRQ_PC6 BFIN_PC_IRQ(6) +#define IRQ_PC7 BFIN_PC_IRQ(7) +#define IRQ_PC8 BFIN_PC_IRQ(8) +#define IRQ_PC9 BFIN_PC_IRQ(9) +#define IRQ_PC10 BFIN_PC_IRQ(10) +#define IRQ_PC11 BFIN_PC_IRQ(11) +#define IRQ_PC12 BFIN_PC_IRQ(12) +#define IRQ_PC13 BFIN_PC_IRQ(13) +#define IRQ_PC14 BFIN_PC_IRQ(14) /* N/A */ +#define IRQ_PC15 BFIN_PC_IRQ(15) /* N/A */ -#define BFIN_PD_IRQ(x) ((x) + IRQ_PC15 + 1) -#define IRQ_PD0 BFIN_PD_IRQ(0) -#define IRQ_PD1 BFIN_PD_IRQ(1) -#define IRQ_PD2 BFIN_PD_IRQ(2) -#define IRQ_PD3 BFIN_PD_IRQ(3) -#define IRQ_PD4 BFIN_PD_IRQ(4) -#define IRQ_PD5 BFIN_PD_IRQ(5) -#define IRQ_PD6 BFIN_PD_IRQ(6) -#define IRQ_PD7 BFIN_PD_IRQ(7) -#define IRQ_PD8 BFIN_PD_IRQ(8) -#define IRQ_PD9 BFIN_PD_IRQ(9) -#define IRQ_PD10 BFIN_PD_IRQ(10) -#define IRQ_PD11 BFIN_PD_IRQ(11) -#define IRQ_PD12 BFIN_PD_IRQ(12) -#define IRQ_PD13 BFIN_PD_IRQ(13) -#define IRQ_PD14 BFIN_PD_IRQ(14) -#define IRQ_PD15 BFIN_PD_IRQ(15) +#define BFIN_PD_IRQ(x) ((x) + IRQ_PC15 + 1) +#define IRQ_PD0 BFIN_PD_IRQ(0) +#define IRQ_PD1 BFIN_PD_IRQ(1) +#define IRQ_PD2 BFIN_PD_IRQ(2) +#define IRQ_PD3 BFIN_PD_IRQ(3) +#define IRQ_PD4 BFIN_PD_IRQ(4) +#define IRQ_PD5 BFIN_PD_IRQ(5) +#define IRQ_PD6 BFIN_PD_IRQ(6) +#define IRQ_PD7 BFIN_PD_IRQ(7) +#define IRQ_PD8 BFIN_PD_IRQ(8) +#define IRQ_PD9 BFIN_PD_IRQ(9) +#define IRQ_PD10 BFIN_PD_IRQ(10) +#define IRQ_PD11 BFIN_PD_IRQ(11) +#define IRQ_PD12 BFIN_PD_IRQ(12) +#define IRQ_PD13 BFIN_PD_IRQ(13) +#define IRQ_PD14 BFIN_PD_IRQ(14) +#define IRQ_PD15 BFIN_PD_IRQ(15) -#define BFIN_PE_IRQ(x) ((x) + IRQ_PD15 + 1) -#define IRQ_PE0 BFIN_PE_IRQ(0) -#define IRQ_PE1 BFIN_PE_IRQ(1) -#define IRQ_PE2 BFIN_PE_IRQ(2) -#define IRQ_PE3 BFIN_PE_IRQ(3) -#define IRQ_PE4 BFIN_PE_IRQ(4) -#define IRQ_PE5 BFIN_PE_IRQ(5) -#define IRQ_PE6 BFIN_PE_IRQ(6) -#define IRQ_PE7 BFIN_PE_IRQ(7) -#define IRQ_PE8 BFIN_PE_IRQ(8) -#define IRQ_PE9 BFIN_PE_IRQ(9) -#define IRQ_PE10 BFIN_PE_IRQ(10) -#define IRQ_PE11 BFIN_PE_IRQ(11) -#define IRQ_PE12 BFIN_PE_IRQ(12) -#define IRQ_PE13 BFIN_PE_IRQ(13) -#define IRQ_PE14 BFIN_PE_IRQ(14) -#define IRQ_PE15 BFIN_PE_IRQ(15) +#define BFIN_PE_IRQ(x) ((x) + IRQ_PD15 + 1) +#define IRQ_PE0 BFIN_PE_IRQ(0) +#define IRQ_PE1 BFIN_PE_IRQ(1) +#define IRQ_PE2 BFIN_PE_IRQ(2) +#define IRQ_PE3 BFIN_PE_IRQ(3) +#define IRQ_PE4 BFIN_PE_IRQ(4) +#define IRQ_PE5 BFIN_PE_IRQ(5) +#define IRQ_PE6 BFIN_PE_IRQ(6) +#define IRQ_PE7 BFIN_PE_IRQ(7) +#define IRQ_PE8 BFIN_PE_IRQ(8) +#define IRQ_PE9 BFIN_PE_IRQ(9) +#define IRQ_PE10 BFIN_PE_IRQ(10) +#define IRQ_PE11 BFIN_PE_IRQ(11) +#define IRQ_PE12 BFIN_PE_IRQ(12) +#define IRQ_PE13 BFIN_PE_IRQ(13) +#define IRQ_PE14 BFIN_PE_IRQ(14) +#define IRQ_PE15 BFIN_PE_IRQ(15) -#define BFIN_PF_IRQ(x) ((x) + IRQ_PE15 + 1) -#define IRQ_PF0 BFIN_PF_IRQ(0) -#define IRQ_PF1 BFIN_PF_IRQ(1) -#define IRQ_PF2 BFIN_PF_IRQ(2) -#define IRQ_PF3 BFIN_PF_IRQ(3) -#define IRQ_PF4 BFIN_PF_IRQ(4) -#define IRQ_PF5 BFIN_PF_IRQ(5) -#define IRQ_PF6 BFIN_PF_IRQ(6) -#define IRQ_PF7 BFIN_PF_IRQ(7) -#define IRQ_PF8 BFIN_PF_IRQ(8) -#define IRQ_PF9 BFIN_PF_IRQ(9) -#define IRQ_PF10 BFIN_PF_IRQ(10) -#define IRQ_PF11 BFIN_PF_IRQ(11) -#define IRQ_PF12 BFIN_PF_IRQ(12) -#define IRQ_PF13 BFIN_PF_IRQ(13) -#define IRQ_PF14 BFIN_PF_IRQ(14) -#define IRQ_PF15 BFIN_PF_IRQ(15) +#define BFIN_PF_IRQ(x) ((x) + IRQ_PE15 + 1) +#define IRQ_PF0 BFIN_PF_IRQ(0) +#define IRQ_PF1 BFIN_PF_IRQ(1) +#define IRQ_PF2 BFIN_PF_IRQ(2) +#define IRQ_PF3 BFIN_PF_IRQ(3) +#define IRQ_PF4 BFIN_PF_IRQ(4) +#define IRQ_PF5 BFIN_PF_IRQ(5) +#define IRQ_PF6 BFIN_PF_IRQ(6) +#define IRQ_PF7 BFIN_PF_IRQ(7) +#define IRQ_PF8 BFIN_PF_IRQ(8) +#define IRQ_PF9 BFIN_PF_IRQ(9) +#define IRQ_PF10 BFIN_PF_IRQ(10) +#define IRQ_PF11 BFIN_PF_IRQ(11) +#define IRQ_PF12 BFIN_PF_IRQ(12) +#define IRQ_PF13 BFIN_PF_IRQ(13) +#define IRQ_PF14 BFIN_PF_IRQ(14) +#define IRQ_PF15 BFIN_PF_IRQ(15) -#define BFIN_PG_IRQ(x) ((x) + IRQ_PF15 + 1) -#define IRQ_PG0 BFIN_PG_IRQ(0) -#define IRQ_PG1 BFIN_PG_IRQ(1) -#define IRQ_PG2 BFIN_PG_IRQ(2) -#define IRQ_PG3 BFIN_PG_IRQ(3) -#define IRQ_PG4 BFIN_PG_IRQ(4) -#define IRQ_PG5 BFIN_PG_IRQ(5) -#define IRQ_PG6 BFIN_PG_IRQ(6) -#define IRQ_PG7 BFIN_PG_IRQ(7) -#define IRQ_PG8 BFIN_PG_IRQ(8) -#define IRQ_PG9 BFIN_PG_IRQ(9) -#define IRQ_PG10 BFIN_PG_IRQ(10) -#define IRQ_PG11 BFIN_PG_IRQ(11) -#define IRQ_PG12 BFIN_PG_IRQ(12) -#define IRQ_PG13 BFIN_PG_IRQ(13) -#define IRQ_PG14 BFIN_PG_IRQ(14) -#define IRQ_PG15 BFIN_PG_IRQ(15) +#define BFIN_PG_IRQ(x) ((x) + IRQ_PF15 + 1) +#define IRQ_PG0 BFIN_PG_IRQ(0) +#define IRQ_PG1 BFIN_PG_IRQ(1) +#define IRQ_PG2 BFIN_PG_IRQ(2) +#define IRQ_PG3 BFIN_PG_IRQ(3) +#define IRQ_PG4 BFIN_PG_IRQ(4) +#define IRQ_PG5 BFIN_PG_IRQ(5) +#define IRQ_PG6 BFIN_PG_IRQ(6) +#define IRQ_PG7 BFIN_PG_IRQ(7) +#define IRQ_PG8 BFIN_PG_IRQ(8) +#define IRQ_PG9 BFIN_PG_IRQ(9) +#define IRQ_PG10 BFIN_PG_IRQ(10) +#define IRQ_PG11 BFIN_PG_IRQ(11) +#define IRQ_PG12 BFIN_PG_IRQ(12) +#define IRQ_PG13 BFIN_PG_IRQ(13) +#define IRQ_PG14 BFIN_PG_IRQ(14) +#define IRQ_PG15 BFIN_PG_IRQ(15) -#define BFIN_PH_IRQ(x) ((x) + IRQ_PG15 + 1) -#define IRQ_PH0 BFIN_PH_IRQ(0) -#define IRQ_PH1 BFIN_PH_IRQ(1) -#define IRQ_PH2 BFIN_PH_IRQ(2) -#define IRQ_PH3 BFIN_PH_IRQ(3) -#define IRQ_PH4 BFIN_PH_IRQ(4) -#define IRQ_PH5 BFIN_PH_IRQ(5) -#define IRQ_PH6 BFIN_PH_IRQ(6) -#define IRQ_PH7 BFIN_PH_IRQ(7) -#define IRQ_PH8 BFIN_PH_IRQ(8) -#define IRQ_PH9 BFIN_PH_IRQ(9) -#define IRQ_PH10 BFIN_PH_IRQ(10) -#define IRQ_PH11 BFIN_PH_IRQ(11) -#define IRQ_PH12 BFIN_PH_IRQ(12) -#define IRQ_PH13 BFIN_PH_IRQ(13) -#define IRQ_PH14 BFIN_PH_IRQ(14) /* N/A */ -#define IRQ_PH15 BFIN_PH_IRQ(15) /* N/A */ +#define BFIN_PH_IRQ(x) ((x) + IRQ_PG15 + 1) +#define IRQ_PH0 BFIN_PH_IRQ(0) +#define IRQ_PH1 BFIN_PH_IRQ(1) +#define IRQ_PH2 BFIN_PH_IRQ(2) +#define IRQ_PH3 BFIN_PH_IRQ(3) +#define IRQ_PH4 BFIN_PH_IRQ(4) +#define IRQ_PH5 BFIN_PH_IRQ(5) +#define IRQ_PH6 BFIN_PH_IRQ(6) +#define IRQ_PH7 BFIN_PH_IRQ(7) +#define IRQ_PH8 BFIN_PH_IRQ(8) +#define IRQ_PH9 BFIN_PH_IRQ(9) +#define IRQ_PH10 BFIN_PH_IRQ(10) +#define IRQ_PH11 BFIN_PH_IRQ(11) +#define IRQ_PH12 BFIN_PH_IRQ(12) +#define IRQ_PH13 BFIN_PH_IRQ(13) +#define IRQ_PH14 BFIN_PH_IRQ(14) /* N/A */ +#define IRQ_PH15 BFIN_PH_IRQ(15) /* N/A */ -#define BFIN_PI_IRQ(x) ((x) + IRQ_PH15 + 1) -#define IRQ_PI0 BFIN_PI_IRQ(0) -#define IRQ_PI1 BFIN_PI_IRQ(1) -#define IRQ_PI2 BFIN_PI_IRQ(2) -#define IRQ_PI3 BFIN_PI_IRQ(3) -#define IRQ_PI4 BFIN_PI_IRQ(4) -#define IRQ_PI5 BFIN_PI_IRQ(5) -#define IRQ_PI6 BFIN_PI_IRQ(6) -#define IRQ_PI7 BFIN_PI_IRQ(7) -#define IRQ_PI8 BFIN_PI_IRQ(8) -#define IRQ_PI9 BFIN_PI_IRQ(9) -#define IRQ_PI10 BFIN_PI_IRQ(10) -#define IRQ_PI11 BFIN_PI_IRQ(11) -#define IRQ_PI12 BFIN_PI_IRQ(12) -#define IRQ_PI13 BFIN_PI_IRQ(13) -#define IRQ_PI14 BFIN_PI_IRQ(14) -#define IRQ_PI15 BFIN_PI_IRQ(15) +#define BFIN_PI_IRQ(x) ((x) + IRQ_PH15 + 1) +#define IRQ_PI0 BFIN_PI_IRQ(0) +#define IRQ_PI1 BFIN_PI_IRQ(1) +#define IRQ_PI2 BFIN_PI_IRQ(2) +#define IRQ_PI3 BFIN_PI_IRQ(3) +#define IRQ_PI4 BFIN_PI_IRQ(4) +#define IRQ_PI5 BFIN_PI_IRQ(5) +#define IRQ_PI6 BFIN_PI_IRQ(6) +#define IRQ_PI7 BFIN_PI_IRQ(7) +#define IRQ_PI8 BFIN_PI_IRQ(8) +#define IRQ_PI9 BFIN_PI_IRQ(9) +#define IRQ_PI10 BFIN_PI_IRQ(10) +#define IRQ_PI11 BFIN_PI_IRQ(11) +#define IRQ_PI12 BFIN_PI_IRQ(12) +#define IRQ_PI13 BFIN_PI_IRQ(13) +#define IRQ_PI14 BFIN_PI_IRQ(14) +#define IRQ_PI15 BFIN_PI_IRQ(15) -#define BFIN_PJ_IRQ(x) ((x) + IRQ_PI15 + 1) -#define IRQ_PJ0 BFIN_PJ_IRQ(0) -#define IRQ_PJ1 BFIN_PJ_IRQ(1) -#define IRQ_PJ2 BFIN_PJ_IRQ(2) -#define IRQ_PJ3 BFIN_PJ_IRQ(3) -#define IRQ_PJ4 BFIN_PJ_IRQ(4) -#define IRQ_PJ5 BFIN_PJ_IRQ(5) -#define IRQ_PJ6 BFIN_PJ_IRQ(6) -#define IRQ_PJ7 BFIN_PJ_IRQ(7) -#define IRQ_PJ8 BFIN_PJ_IRQ(8) -#define IRQ_PJ9 BFIN_PJ_IRQ(9) -#define IRQ_PJ10 BFIN_PJ_IRQ(10) -#define IRQ_PJ11 BFIN_PJ_IRQ(11) -#define IRQ_PJ12 BFIN_PJ_IRQ(12) -#define IRQ_PJ13 BFIN_PJ_IRQ(13) -#define IRQ_PJ14 BFIN_PJ_IRQ(14) /* N/A */ -#define IRQ_PJ15 BFIN_PJ_IRQ(15) /* N/A */ +#define BFIN_PJ_IRQ(x) ((x) + IRQ_PI15 + 1) +#define IRQ_PJ0 BFIN_PJ_IRQ(0) +#define IRQ_PJ1 BFIN_PJ_IRQ(1) +#define IRQ_PJ2 BFIN_PJ_IRQ(2) +#define IRQ_PJ3 BFIN_PJ_IRQ(3) +#define IRQ_PJ4 BFIN_PJ_IRQ(4) +#define IRQ_PJ5 BFIN_PJ_IRQ(5) +#define IRQ_PJ6 BFIN_PJ_IRQ(6) +#define IRQ_PJ7 BFIN_PJ_IRQ(7) +#define IRQ_PJ8 BFIN_PJ_IRQ(8) +#define IRQ_PJ9 BFIN_PJ_IRQ(9) +#define IRQ_PJ10 BFIN_PJ_IRQ(10) +#define IRQ_PJ11 BFIN_PJ_IRQ(11) +#define IRQ_PJ12 BFIN_PJ_IRQ(12) +#define IRQ_PJ13 BFIN_PJ_IRQ(13) +#define IRQ_PJ14 BFIN_PJ_IRQ(14) /* N/A */ +#define IRQ_PJ15 BFIN_PJ_IRQ(15) /* N/A */ #define GPIO_IRQ_BASE IRQ_PA0 @@ -345,6 +344,34 @@ Events (highest priority) EMU 0 #define NR_IRQS (SYS_IRQS+1) #endif +/* For compatibility reasons with existing code */ + +#define IRQ_DMAC0_ERR IRQ_DMAC0_ERROR +#define IRQ_EPPI0_ERR IRQ_EPPI0_ERROR +#define IRQ_SPORT0_ERR IRQ_SPORT0_ERROR +#define IRQ_SPORT1_ERR IRQ_SPORT1_ERROR +#define IRQ_SPI0_ERR IRQ_SPI0_ERROR +#define IRQ_UART0_ERR IRQ_UART0_ERROR +#define IRQ_DMAC1_ERR IRQ_DMAC1_ERROR +#define IRQ_SPORT2_ERR IRQ_SPORT2_ERROR +#define IRQ_SPORT3_ERR IRQ_SPORT3_ERROR +#define IRQ_SPI1_ERR IRQ_SPI1_ERROR +#define IRQ_SPI2_ERR IRQ_SPI2_ERROR +#define IRQ_UART1_ERR IRQ_UART1_ERROR +#define IRQ_UART2_ERR IRQ_UART2_ERROR +#define IRQ_CAN0_ERR IRQ_CAN0_ERROR +#define IRQ_MXVR_ERR IRQ_MXVR_ERROR +#define IRQ_EPP1_ERR IRQ_EPP1_ERROR +#define IRQ_EPP2_ERR IRQ_EPP2_ERROR +#define IRQ_UART3_ERR IRQ_UART3_ERROR +#define IRQ_HOST_ERR IRQ_HOST_ERROR +#define IRQ_PIXC_ERR IRQ_PIXC_ERROR +#define IRQ_NFC_ERR IRQ_NFC_ERROR +#define IRQ_ATAPI_ERR IRQ_ATAPI_ERROR +#define IRQ_CAN1_ERR IRQ_CAN1_ERROR +#define IRQ_HS_DMA_ERR IRQ_HS_DMA_ERROR + + #define IVG7 7 #define IVG8 8 #define IVG9 9 From 2acde902301f73e824101e5ca9eb95dc733dc17d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 11 Oct 2007 00:24:40 +0800 Subject: [PATCH 0050/2804] Blackfin arch: a few things still use bfin_read_PORT_FER() - Update gpio_request to allow multiple request with the same signature (label) - Use generic GPIO API where applicable - Update generic board support form stamp board Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_gpio.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 78438d88d22a..b58b0de3c907 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -930,6 +930,8 @@ void peripheral_free(unsigned short per) reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident); + set_label(ident, "free"); + local_irq_restore(flags); } EXPORT_SYMBOL(peripheral_free); @@ -969,6 +971,17 @@ int gpio_request(unsigned short gpio, const char *label) local_irq_save(flags); + /* + * Allow that the identical GPIO can + * be requested from the same driver twice + * Do nothing and return - + */ + + if (cmp_label(gpio, label) == 0) { + local_irq_restore(flags); + return 0; + } + if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", gpio, get_label(gpio)); @@ -1016,6 +1029,8 @@ void gpio_free(unsigned short gpio) reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); + set_label(gpio, "free"); + local_irq_restore(flags); } EXPORT_SYMBOL(gpio_free); From eabb5a5e0b1ff6b7d36ac80bf39773fa6a0fc872 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 28 Aug 2007 14:57:05 +0800 Subject: [PATCH 0051/2804] Blackfin arch: Remove legacy support Now that there is a generic GPIO driver framework remove GPIO register unified name space legacy support. Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/mach-bf537/Kconfig | 27 -- include/asm-blackfin/mach-bf537/blackfin.h | 278 --------------------- 2 files changed, 305 deletions(-) diff --git a/arch/blackfin/mach-bf537/Kconfig b/arch/blackfin/mach-bf537/Kconfig index cc9ae38a4dda..e6648db09519 100644 --- a/arch/blackfin/mach-bf537/Kconfig +++ b/arch/blackfin/mach-bf537/Kconfig @@ -2,33 +2,6 @@ if (BF537 || BF534 || BF536) menu "BF537 Specific Configuration" -comment "PORT F/G Selection" -choice - prompt "Select BF537/6/4 default GPIO PFx PORTx" - help - Quick Hack for BF537/6/4 default GPIO PFx PORTF. - -config BF537_PORT_F - bool "Select BF537/6/4 default GPIO PFx PORTF" - depends on (BF537 || BF536 || BF534) - help - Quick Hack for BF537/6/4 default GPIO PFx PORTF. - -config BF537_PORT_G - bool "Select BF537/6/4 default GPIO PFx PORTG" - depends on (BF537 || BF536 || BF534) - help - Quick Hack for BF537/6/4 default GPIO PFx PORTG. - -config BF537_PORT_H - bool "Select BF537/6/4 default GPIO PFx PORTH" - depends on (BF537 || BF536 || BF534) - help - Quick Hack for BF537/6/4 default GPIO PFx PORTH - Use only when Blackfin EMAC support is not required. - -endchoice - comment "Interrupt Priority Assignment" menu "Priority" diff --git a/include/asm-blackfin/mach-bf537/blackfin.h b/include/asm-blackfin/mach-bf537/blackfin.h index f196588a3ad0..53fcfa3408d0 100644 --- a/include/asm-blackfin/mach-bf537/blackfin.h +++ b/include/asm-blackfin/mach-bf537/blackfin.h @@ -143,284 +143,6 @@ #define bfin_write_STOPCK_OFF(val) bfin_write_STOPCK(val) #define STOPCK_OFF STOPCK -/* FIO USE PORT F*/ -#ifdef CONFIG_BF537_PORT_F -#define bfin_read_PORT_FER() bfin_read_PORTF_FER() -#define bfin_write_PORT_FER(val) bfin_write_PORTF_FER(val) -#define bfin_read_FIO_FLAG_D() bfin_read_PORTFIO() -#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTFIO(val) -#define bfin_read_FIO_FLAG_C() bfin_read_PORTFIO_CLEAR() -#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTFIO_CLEAR(val) -#define bfin_read_FIO_FLAG_S() bfin_read_PORTFIO_SET() -#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTFIO_SET(val) -#define bfin_read_FIO_FLAG_T() bfin_read_PORTFIO_TOGGLE() -#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTFIO_TOGGLE(val) -#define bfin_read_FIO_MASKA_D() bfin_read_PORTFIO_MASKA() -#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTFIO_MASKA(val) -#define bfin_read_FIO_MASKA_C() bfin_read_PORTFIO_MASKA_CLEAR() -#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTFIO_MASKA_CLEAR(val) -#define bfin_read_FIO_MASKA_S() bfin_read_PORTFIO_MASKA_SET() -#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTFIO_MASKA_SET(val) -#define bfin_read_FIO_MASKA_T() bfin_read_PORTFIO_MASKA_TOGGLE() -#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTFIO_MASKA_TOGGLE(val) -#define bfin_read_FIO_MASKB_D() bfin_read_PORTFIO_MASKB() -#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTFIO_MASKB(val) -#define bfin_read_FIO_MASKB_C() bfin_read_PORTFIO_MASKB_CLEAR() -#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTFIO_MASKB_CLEAR(val) -#define bfin_read_FIO_MASKB_S() bfin_read_PORTFIO_MASKB_SET() -#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTFIO_MASKB_SET(val) -#define bfin_read_FIO_MASKB_T() bfin_read_PORTFIO_MASKB_TOGGLE() -#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTFIO_MASKB_TOGGLE(val) -#define bfin_read_FIO_DIR() bfin_read_PORTFIO_DIR() -#define bfin_write_FIO_DIR(val) bfin_write_PORTFIO_DIR(val) -#define bfin_read_FIO_POLAR() bfin_read_PORTFIO_POLAR() -#define bfin_write_FIO_POLAR(val) bfin_write_PORTFIO_POLAR(val) -#define bfin_read_FIO_EDGE() bfin_read_PORTFIO_EDGE() -#define bfin_write_FIO_EDGE(val) bfin_write_PORTFIO_EDGE(val) -#define bfin_read_FIO_BOTH() bfin_read_PORTFIO_BOTH() -#define bfin_write_FIO_BOTH(val) bfin_write_PORTFIO_BOTH(val) -#define bfin_read_FIO_INEN() bfin_read_PORTFIO_INEN() -#define bfin_write_FIO_INEN(val) bfin_write_PORTFIO_INEN(val) - -#define bfin_read_FIO_FLAG_D() bfin_read_PORTFIO() -#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTFIO(val) -#define FIO_FLAG_D PORTFIO -#define bfin_read_FIO_FLAG_C() bfin_read_PORTFIO_CLEAR() -#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTFIO_CLEAR(val) -#define FIO_FLAG_C PORTFIO_CLEAR -#define bfin_read_FIO_FLAG_S() bfin_read_PORTFIO_SET() -#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTFIO_SET(val) -#define FIO_FLAG_S PORTFIO_SET -#define bfin_read_FIO_FLAG_T() bfin_read_PORTFIO_TOGGLE() -#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTFIO_TOGGLE(val) -#define FIO_FLAG_T PORTFIO_TOGGLE -#define bfin_read_FIO_MASKA_D() bfin_read_PORTFIO_MASKA() -#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTFIO_MASKA(val) -#define FIO_MASKA_D PORTFIO_MASKA -#define bfin_read_FIO_MASKA_C() bfin_read_PORTFIO_MASKA_CLEAR() -#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTFIO_MASKA_CLEAR(val) -#define FIO_MASKA_C PORTFIO_MASKA_CLEAR -#define bfin_read_FIO_MASKA_S() bfin_read_PORTFIO_MASKA_SET() -#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTFIO_MASKA_SET(val) -#define FIO_MASKA_S PORTFIO_MASKA_SET -#define bfin_read_FIO_MASKA_T() bfin_read_PORTFIO_MASKA_TOGGLE() -#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTFIO_MASKA_TOGGLE(val) -#define FIO_MASKA_T PORTFIO_MASKA_TOGGLE -#define bfin_read_FIO_MASKB_D() bfin_read_PORTFIO_MASKB() -#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTFIO_MASKB(val) -#define FIO_MASKB_D PORTFIO_MASKB -#define bfin_read_FIO_MASKB_C() bfin_read_PORTFIO_MASKB_CLEAR() -#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTFIO_MASKB_CLEAR(val) -#define FIO_MASKB_C PORTFIO_MASKB_CLEAR -#define bfin_read_FIO_MASKB_S() bfin_read_PORTFIO_MASKB_SET() -#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTFIO_MASKB_SET(val) -#define FIO_MASKB_S PORTFIO_MASKB_SET -#define bfin_read_FIO_MASKB_T() bfin_read_PORTFIO_MASKB_TOGGLE() -#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTFIO_MASKB_TOGGLE(val) -#define FIO_MASKB_T PORTFIO_MASKB_TOGGLE -#define bfin_read_FIO_DIR() bfin_read_PORTFIO_DIR() -#define bfin_write_FIO_DIR(val) bfin_write_PORTFIO_DIR(val) -#define FIO_DIR PORTFIO_DIR -#define bfin_read_FIO_POLAR() bfin_read_PORTFIO_POLAR() -#define bfin_write_FIO_POLAR(val) bfin_write_PORTFIO_POLAR(val) -#define FIO_POLAR PORTFIO_POLAR -#define bfin_read_FIO_EDGE() bfin_read_PORTFIO_EDGE() -#define bfin_write_FIO_EDGE(val) bfin_write_PORTFIO_EDGE(val) -#define FIO_EDGE PORTFIO_EDGE -#define bfin_read_FIO_BOTH() bfin_read_PORTFIO_BOTH() -#define bfin_write_FIO_BOTH(val) bfin_write_PORTFIO_BOTH(val) -#define FIO_BOTH PORTFIO_BOTH -#define bfin_read_FIO_INEN() bfin_read_PORTFIO_INEN() -#define bfin_write_FIO_INEN(val) bfin_write_PORTFIO_INEN(val) -#define FIO_INEN PORTFIO_INEN -#endif - -/* FIO USE PORT G*/ -#ifdef CONFIG_BF537_PORT_G -#define bfin_read_PORT_FER() bfin_read_PORTG_FER() -#define bfin_write_PORT_FER(val) bfin_write_PORTG_FER(val) -#define bfin_read_FIO_FLAG_D() bfin_read_PORTGIO() -#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTGIO(val) -#define bfin_read_FIO_FLAG_C() bfin_read_PORTGIO_CLEAR() -#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTGIO_CLEAR(val) -#define bfin_read_FIO_FLAG_S() bfin_read_PORTGIO_SET() -#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTGIO_SET(val) -#define bfin_read_FIO_FLAG_T() bfin_read_PORTGIO_TOGGLE() -#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTGIO_TOGGLE(val) -#define bfin_read_FIO_MASKA_D() bfin_read_PORTGIO_MASKA() -#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTGIO_MASKA(val) -#define bfin_read_FIO_MASKA_C() bfin_read_PORTGIO_MASKA_CLEAR() -#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTGIO_MASKA_CLEAR(val) -#define bfin_read_FIO_MASKA_S() bfin_read_PORTGIO_MASKA_SET() -#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTGIO_MASKA_SET(val) -#define bfin_read_FIO_MASKA_T() bfin_read_PORTGIO_MASKA_TOGGLE() -#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTGIO_MASKA_TOGGLE(val) -#define bfin_read_FIO_MASKB_D() bfin_read_PORTGIO_MASKB() -#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTGIO_MASKB(val) -#define bfin_read_FIO_MASKB_C() bfin_read_PORTGIO_MASKB_CLEAR() -#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTGIO_MASKB_CLEAR(val) -#define bfin_read_FIO_MASKB_S() bfin_read_PORTGIO_MASKB_SET() -#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTGIO_MASKB_SET(val) -#define bfin_read_FIO_MASKB_T() bfin_read_PORTGIO_MASKB_TOGGLE() -#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTGIO_MASKB_TOGGLE(val) -#define bfin_read_FIO_DIR() bfin_read_PORTGIO_DIR() -#define bfin_write_FIO_DIR(val) bfin_write_PORTGIO_DIR(val) -#define bfin_read_FIO_POLAR() bfin_read_PORTGIO_POLAR() -#define bfin_write_FIO_POLAR(val) bfin_write_PORTGIO_POLAR(val) -#define bfin_read_FIO_EDGE() bfin_read_PORTGIO_EDGE() -#define bfin_write_FIO_EDGE(val) bfin_write_PORTGIO_EDGE(val) -#define bfin_read_FIO_BOTH() bfin_read_PORTGIO_BOTH() -#define bfin_write_FIO_BOTH(val) bfin_write_PORTGIO_BOTH(val) -#define bfin_read_FIO_INEN() bfin_read_PORTGIO_INEN() -#define bfin_write_FIO_INEN(val) bfin_write_PORTGIO_INEN(val) - -#define bfin_read_FIO_FLAG_D() bfin_read_PORTGIO() -#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTGIO(val) -#define FIO_FLAG_D PORTGIO -#define bfin_read_FIO_FLAG_C() bfin_read_PORTGIO_CLEAR() -#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTGIO_CLEAR(val) -#define FIO_FLAG_C PORTGIO_CLEAR -#define bfin_read_FIO_FLAG_S() bfin_read_PORTGIO_SET() -#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTGIO_SET(val) -#define FIO_FLAG_S PORTGIO_SET -#define bfin_read_FIO_FLAG_T() bfin_read_PORTGIO_TOGGLE() -#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTGIO_TOGGLE(val) -#define FIO_FLAG_T PORTGIO_TOGGLE -#define bfin_read_FIO_MASKA_D() bfin_read_PORTGIO_MASKA() -#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTGIO_MASKA(val) -#define FIO_MASKA_D PORTGIO_MASKA -#define bfin_read_FIO_MASKA_C() bfin_read_PORTGIO_MASKA_CLEAR() -#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTGIO_MASKA_CLEAR(val) -#define FIO_MASKA_C PORTGIO_MASKA_CLEAR -#define bfin_read_FIO_MASKA_S() bfin_read_PORTGIO_MASKA_SET() -#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTGIO_MASKA_SET(val) -#define FIO_MASKA_S PORTGIO_MASKA_SET -#define bfin_read_FIO_MASKA_T() bfin_read_PORTGIO_MASKA_TOGGLE() -#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTGIO_MASKA_TOGGLE(val) -#define FIO_MASKA_T PORTGIO_MASKA_TOGGLE -#define bfin_read_FIO_MASKB_D() bfin_read_PORTGIO_MASKB() -#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTGIO_MASKB(val) -#define FIO_MASKB_D PORTGIO_MASKB -#define bfin_read_FIO_MASKB_C() bfin_read_PORTGIO_MASKB_CLEAR() -#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTGIO_MASKB_CLEAR(val) -#define FIO_MASKB_C PORTGIO_MASKB_CLEAR -#define bfin_read_FIO_MASKB_S() bfin_read_PORTGIO_MASKB_SET() -#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTGIO_MASKB_SET(val) -#define FIO_MASKB_S PORTGIO_MASKB_SET -#define bfin_read_FIO_MASKB_T() bfin_read_PORTGIO_MASKB_TOGGLE() -#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTGIO_MASKB_TOGGLE(val) -#define FIO_MASKB_T PORTGIO_MASKB_TOGGLE -#define bfin_read_FIO_DIR() bfin_read_PORTGIO_DIR() -#define bfin_write_FIO_DIR(val) bfin_write_PORTGIO_DIR(val) -#define FIO_DIR PORTGIO_DIR -#define bfin_read_FIO_POLAR() bfin_read_PORTGIO_POLAR() -#define bfin_write_FIO_POLAR(val) bfin_write_PORTGIO_POLAR(val) -#define FIO_POLAR PORTGIO_POLAR -#define bfin_read_FIO_EDGE() bfin_read_PORTGIO_EDGE() -#define bfin_write_FIO_EDGE(val) bfin_write_PORTGIO_EDGE(val) -#define FIO_EDGE PORTGIO_EDGE -#define bfin_read_FIO_BOTH() bfin_read_PORTGIO_BOTH() -#define bfin_write_FIO_BOTH(val) bfin_write_PORTGIO_BOTH(val) -#define FIO_BOTH PORTGIO_BOTH -#define bfin_read_FIO_INEN() bfin_read_PORTGIO_INEN() -#define bfin_write_FIO_INEN(val) bfin_write_PORTGIO_INEN(val) -#define FIO_INEN PORTGIO_INEN - -#endif - -/* FIO USE PORT H*/ -#ifdef CONFIG_BF537_PORT_H -#define bfin_read_PORT_FER() bfin_read_PORTH_FER() -#define bfin_write_PORT_FER(val) bfin_write_PORTH_FER(val) -#define bfin_read_FIO_FLAG_D() bfin_read_PORTHIO() -#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTHIO(val) -#define bfin_read_FIO_FLAG_C() bfin_read_PORTHIO_CLEAR() -#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTHIO_CLEAR(val) -#define bfin_read_FIO_FLAG_S() bfin_read_PORTHIO_SET() -#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTHIO_SET(val) -#define bfin_read_FIO_FLAG_T() bfin_read_PORTHIO_TOGGLE() -#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTHIO_TOGGLE(val) -#define bfin_read_FIO_MASKA_D() bfin_read_PORTHIO_MASKA() -#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTHIO_MASKA(val) -#define bfin_read_FIO_MASKA_C() bfin_read_PORTHIO_MASKA_CLEAR() -#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTHIO_MASKA_CLEAR(val) -#define bfin_read_FIO_MASKA_S() bfin_read_PORTHIO_MASKA_SET() -#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTHIO_MASKA_SET(val) -#define bfin_read_FIO_MASKA_T() bfin_read_PORTHIO_MASKA_TOGGLE() -#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTHIO_MASKA_TOGGLE(val) -#define bfin_read_FIO_MASKB_D() bfin_read_PORTHIO_MASKB() -#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTHIO_MASKB(val) -#define bfin_read_FIO_MASKB_C() bfin_read_PORTHIO_MASKB_CLEAR() -#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTHIO_MASKB_CLEAR(val) -#define bfin_read_FIO_MASKB_S() bfin_read_PORTHIO_MASKB_SET() -#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTHIO_MASKB_SET(val) -#define bfin_read_FIO_MASKB_T() bfin_read_PORTHIO_MASKB_TOGGLE() -#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTHIO_MASKB_TOGGLE(val) -#define bfin_read_FIO_DIR() bfin_read_PORTHIO_DIR() -#define bfin_write_FIO_DIR(val) bfin_write_PORTHIO_DIR(val) -#define bfin_read_FIO_POLAR() bfin_read_PORTHIO_POLAR() -#define bfin_write_FIO_POLAR(val) bfin_write_PORTHIO_POLAR(val) -#define bfin_read_FIO_EDGE() bfin_read_PORTHIO_EDGE() -#define bfin_write_FIO_EDGE(val) bfin_write_PORTHIO_EDGE(val) -#define bfin_read_FIO_BOTH() bfin_read_PORTHIO_BOTH() -#define bfin_write_FIO_BOTH(val) bfin_write_PORTHIO_BOTH(val) -#define bfin_read_FIO_INEN() bfin_read_PORTHIO_INEN() -#define bfin_write_FIO_INEN(val) bfin_write_PORTHIO_INEN(val) - -#define bfin_read_FIO_FLAG_D() bfin_read_PORTHIO() -#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTHIO(val) -#define FIO_FLAG_D PORTHIO -#define bfin_read_FIO_FLAG_C() bfin_read_PORTHIO_CLEAR() -#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTHIO_CLEAR(val) -#define FIO_FLAG_C PORTHIO_CLEAR -#define bfin_read_FIO_FLAG_S() bfin_read_PORTHIO_SET() -#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTHIO_SET(val) -#define FIO_FLAG_S PORTHIO_SET -#define bfin_read_FIO_FLAG_T() bfin_read_PORTHIO_TOGGLE() -#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTHIO_TOGGLE(val) -#define FIO_FLAG_T PORTHIO_TOGGLE -#define bfin_read_FIO_MASKA_D() bfin_read_PORTHIO_MASKA() -#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTHIO_MASKA(val) -#define FIO_MASKA_D PORTHIO_MASKA -#define bfin_read_FIO_MASKA_C() bfin_read_PORTHIO_MASKA_CLEAR() -#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTHIO_MASKA_CLEAR(val) -#define FIO_MASKA_C PORTHIO_MASKA_CLEAR -#define bfin_read_FIO_MASKA_S() bfin_read_PORTHIO_MASKA_SET() -#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTHIO_MASKA_SET(val) -#define FIO_MASKA_S PORTHIO_MASKA_SET -#define bfin_read_FIO_MASKA_T() bfin_read_PORTHIO_MASKA_TOGGLE() -#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTHIO_MASKA_TOGGLE(val) -#define FIO_MASKA_T PORTHIO_MASKA_TOGGLE -#define bfin_read_FIO_MASKB_D() bfin_read_PORTHIO_MASKB() -#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTHIO_MASKB(val) -#define FIO_MASKB_D PORTHIO_MASKB -#define bfin_read_FIO_MASKB_C() bfin_read_PORTHIO_MASKB_CLEAR() -#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTHIO_MASKB_CLEAR(val) -#define FIO_MASKB_C PORTHIO_MASKB_CLEAR -#define bfin_read_FIO_MASKB_S() bfin_read_PORTHIO_MASKB_SET() -#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTHIO_MASKB_SET(val) -#define FIO_MASKB_S PORTHIO_MASKB_SET -#define bfin_read_FIO_MASKB_T() bfin_read_PORTHIO_MASKB_TOGGLE() -#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTHIO_MASKB_TOGGLE(val) -#define FIO_MASKB_T PORTHIO_MASKB_TOGGLE -#define bfin_read_FIO_DIR() bfin_read_PORTHIO_DIR() -#define bfin_write_FIO_DIR(val) bfin_write_PORTHIO_DIR(val) -#define FIO_DIR PORTHIO_DIR -#define bfin_read_FIO_POLAR() bfin_read_PORTHIO_POLAR() -#define bfin_write_FIO_POLAR(val) bfin_write_PORTHIO_POLAR(val) -#define FIO_POLAR PORTHIO_POLAR -#define bfin_read_FIO_EDGE() bfin_read_PORTHIO_EDGE() -#define bfin_write_FIO_EDGE(val) bfin_write_PORTHIO_EDGE(val) -#define FIO_EDGE PORTHIO_EDGE -#define bfin_read_FIO_BOTH() bfin_read_PORTHIO_BOTH() -#define bfin_write_FIO_BOTH(val) bfin_write_PORTHIO_BOTH(val) -#define FIO_BOTH PORTHIO_BOTH -#define bfin_read_FIO_INEN() bfin_read_PORTHIO_INEN() -#define bfin_write_FIO_INEN(val) bfin_write_PORTHIO_INEN(val) -#define FIO_INEN PORTHIO_INEN - -#endif - /* PLL_DIV Masks */ #define CCLK_DIV1 CSEL_DIV1 /* CCLK = VCO / 1 */ #define CCLK_DIV2 CSEL_DIV2 /* CCLK = VCO / 2 */ From 4b3f058a7a34a10d99937e86bb28da118710ca9a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 12 Sep 2007 14:50:28 +0800 Subject: [PATCH 0052/2804] Blackfin arch: Add ANOMALY_05000311 Workaround - for those who doesnt use the generic GPIO driver Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- include/asm-blackfin/mach-bf533/cdefBF532.h | 52 +++++++++++++++++---- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/include/asm-blackfin/mach-bf533/cdefBF532.h b/include/asm-blackfin/mach-bf533/cdefBF532.h index 40c1ad39dcab..c803e14b529c 100644 --- a/include/asm-blackfin/mach-bf533/cdefBF532.h +++ b/include/asm-blackfin/mach-bf533/cdefBF532.h @@ -130,10 +130,6 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) /* General Purpose IO (0xFFC0 2400-0xFFC0 27FF) */ #define bfin_read_FIO_DIR() bfin_read16(FIO_DIR) #define bfin_write_FIO_DIR(val) bfin_write16(FIO_DIR,val) -#define bfin_read_FIO_FLAG_C() bfin_read16(FIO_FLAG_C) -#define bfin_write_FIO_FLAG_C(val) bfin_write16(FIO_FLAG_C,val) -#define bfin_read_FIO_FLAG_S() bfin_read16(FIO_FLAG_S) -#define bfin_write_FIO_FLAG_S(val) bfin_write16(FIO_FLAG_S,val) #define bfin_read_FIO_MASKA_C() bfin_read16(FIO_MASKA_C) #define bfin_write_FIO_MASKA_C(val) bfin_write16(FIO_MASKA_C,val) #define bfin_read_FIO_MASKA_S() bfin_read16(FIO_MASKA_S) @@ -150,10 +146,6 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) #define bfin_write_FIO_BOTH(val) bfin_write16(FIO_BOTH,val) #define bfin_read_FIO_INEN() bfin_read16(FIO_INEN) #define bfin_write_FIO_INEN(val) bfin_write16(FIO_INEN,val) -#define bfin_read_FIO_FLAG_D() bfin_read16(FIO_FLAG_D) -#define bfin_write_FIO_FLAG_D(val) bfin_write16(FIO_FLAG_D,val) -#define bfin_read_FIO_FLAG_T() bfin_read16(FIO_FLAG_T) -#define bfin_write_FIO_FLAG_T(val) bfin_write16(FIO_FLAG_T,val) #define bfin_read_FIO_MASKA_D() bfin_read16(FIO_MASKA_D) #define bfin_write_FIO_MASKA_D(val) bfin_write16(FIO_MASKA_D,val) #define bfin_read_FIO_MASKA_T() bfin_read16(FIO_MASKA_T) @@ -163,6 +155,50 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) #define bfin_read_FIO_MASKB_T() bfin_read16(FIO_MASKB_T) #define bfin_write_FIO_MASKB_T(val) bfin_write16(FIO_MASKB_T,val) + +#if ANOMALY_05000311 +#define BFIN_WRITE_FIO_FLAG(name) \ +static __inline__ void bfin_write_FIO_FLAG_ ## name (unsigned short val)\ +{\ + unsigned long flags;\ + local_irq_save(flags);\ + bfin_write16(FIO_FLAG_ ## name,val);\ + bfin_read_CHIPID();\ + local_irq_restore(flags);\ +} +BFIN_WRITE_FIO_FLAG(D) +BFIN_WRITE_FIO_FLAG(C) +BFIN_WRITE_FIO_FLAG(S) +BFIN_WRITE_FIO_FLAG(T) + +#define BFIN_READ_FIO_FLAG(name) \ +static __inline__ unsigned short bfin_read_FIO_FLAG_ ## name (void)\ +{\ + unsigned long flags;\ + unsigned short ret;\ + local_irq_save(flags);\ + ret = bfin_read16(FIO_FLAG_ ## name);\ + bfin_read_CHIPID();\ + local_irq_restore(flags);\ + return ret;\ +} +BFIN_READ_FIO_FLAG(D) +BFIN_READ_FIO_FLAG(C) +BFIN_READ_FIO_FLAG(S) +BFIN_READ_FIO_FLAG(T) + +#else +#define bfin_write_FIO_FLAG_D(val) bfin_write16(FIO_FLAG_D,val) +#define bfin_write_FIO_FLAG_C(val) bfin_write16(FIO_FLAG_C,val) +#define bfin_write_FIO_FLAG_S(val) bfin_write16(FIO_FLAG_S,val) +#define bfin_write_FIO_FLAG_T(val) bfin_write16(FIO_FLAG_T,val) +#define bfin_read_FIO_FLAG_T() bfin_read16(FIO_FLAG_T) +#define bfin_read_FIO_FLAG_C() bfin_read16(FIO_FLAG_C) +#define bfin_read_FIO_FLAG_S() bfin_read16(FIO_FLAG_S) +#define bfin_read_FIO_FLAG_D() bfin_read16(FIO_FLAG_D) +#endif + + /* DMA Controller */ #define bfin_read_DMA0_CONFIG() bfin_read16(DMA0_CONFIG) #define bfin_write_DMA0_CONFIG(val) bfin_write16(DMA0_CONFIG,val) From 2714d9a6d1e68d30f5be8871722a7cff388c2d74 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 11 Oct 2007 00:29:49 +0800 Subject: [PATCH 0053/2804] Blackfin arch: Workaround reboot bug, issue SSYNC at the start of bfin_reset reboot failes on BF533 http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=3500 Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/reboot.c | 78 +++++++++++++++++++++++++++++++++++ include/asm-blackfin/reboot.h | 20 +++++++++ 2 files changed, 98 insertions(+) create mode 100644 arch/blackfin/kernel/reboot.c create mode 100644 include/asm-blackfin/reboot.h diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c new file mode 100644 index 000000000000..356078ec462b --- /dev/null +++ b/arch/blackfin/kernel/reboot.c @@ -0,0 +1,78 @@ +/* + * arch/blackfin/kernel/reboot.c - handle shutdown/reboot + * + * Copyright 2004-2007 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#if defined(BF537_FAMILY) || defined(BF533_FAMILY) +#define SYSCR_VAL 0x0 +#elif defined(BF561_FAMILY) +#define SYSCR_VAL 0x20 +#elif defined(BF548_FAMILY) +#define SYSCR_VAL 0x10 +#endif + +/* A system soft reset makes external memory unusable + * so force this function into L1. + */ +__attribute__((l1_text)) +void bfin_reset(void) +{ + /* force BMODE and disable Core B (as needed) */ + bfin_write_SYSCR(SYSCR_VAL); + + /* we use asm ssync here because it's save and we save some L1 */ + asm("ssync;"); + + while (1) { + /* initiate system soft reset with magic 0x7 */ + bfin_write_SWRST(0x7); + asm("ssync;"); + /* clear system soft reset */ + bfin_write_SWRST(0); + asm("ssync;"); + /* issue core reset */ + asm("raise 1"); + } +} + +__attribute__((weak)) +void native_machine_restart(char *cmd) +{ +} + +void machine_restart(char *cmd) +{ + native_machine_restart(cmd); + local_irq_disable(); + bfin_reset(); +} + +__attribute__((weak)) +void native_machine_halt(void) +{ + idle_with_irq_disabled(); +} + +void machine_halt(void) +{ + native_machine_halt(); +} + +__attribute__((weak)) +void native_machine_power_off(void) +{ + idle_with_irq_disabled(); +} + +void machine_power_off(void) +{ + native_machine_power_off(); +} diff --git a/include/asm-blackfin/reboot.h b/include/asm-blackfin/reboot.h new file mode 100644 index 000000000000..6d448b5f5985 --- /dev/null +++ b/include/asm-blackfin/reboot.h @@ -0,0 +1,20 @@ +/* + * include/asm-blackfin/reboot.h - shutdown/reboot header + * + * Copyright 2004-2007 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __ASM_REBOOT_H__ +#define __ASM_REBOOT_H__ + +/* optional board specific hooks */ +extern void native_machine_restart(char *cmd); +extern void native_machine_halt(void); +extern void native_machine_power_off(void); + +/* common reboot workarounds */ +extern void bfin_gpio_reset_spi0_ssel1(void); + +#endif From b5c0e2e8068ca31eb2547f2e2e677516ce9d8800 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 12 Sep 2007 17:31:59 +0800 Subject: [PATCH 0054/2804] Blackfin arch: fix typo pointed out by David Rowe (Mhz -> MHz) Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index dfc464d8048e..abf34a8dd070 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -332,7 +332,7 @@ void __init setup_arch(char **cmdline_p) CPU, bfin_revid()); printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n"); - printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n", + printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n", cclk / 1000000, sclk / 1000000); if (ANOMALY_05000273 && (cclk >> 1) <= sclk) From fb282a72f13305a74fb105bce1ee232b3492b654 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 12 Sep 2007 17:48:25 +0800 Subject: [PATCH 0055/2804] Blackfin arch: cleanup IO and DMA_IO API function definitions according to other arches Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_dma_5xx.c | 6 +++--- include/asm-blackfin/io.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index f0db6c5c8d1a..858cca6a2afc 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -583,7 +583,7 @@ void *safe_dma_memcpy(void *dest, const void *src, size_t size) } EXPORT_SYMBOL(safe_dma_memcpy); -void dma_outsb(void __iomem *addr, const void *buf, unsigned short len) +void dma_outsb(const void __iomem *addr, const void *buf, unsigned short len) { unsigned long flags; @@ -647,7 +647,7 @@ void dma_insb(const void __iomem *addr, void *buf, unsigned short len) } EXPORT_SYMBOL(dma_insb); -void dma_outsw(void __iomem *addr, const void *buf, unsigned short len) +void dma_outsw(const void __iomem *addr, const void *buf, unsigned short len) { unsigned long flags; @@ -711,7 +711,7 @@ void dma_insw(const void __iomem *addr, void *buf, unsigned short len) } EXPORT_SYMBOL(dma_insw); -void dma_outsl(void __iomem *addr, const void *buf, unsigned short len) +void dma_outsl(const void __iomem *addr, const void *buf, unsigned short len) { unsigned long flags; diff --git a/include/asm-blackfin/io.h b/include/asm-blackfin/io.h index 142cb333db29..3f48f8feb5c9 100644 --- a/include/asm-blackfin/io.h +++ b/include/asm-blackfin/io.h @@ -115,17 +115,17 @@ static inline unsigned int readl(const volatile void __iomem *addr) #ifndef __ASSEMBLY__ -extern void outsb(void __iomem *port, const void *addr, unsigned short count); -extern void outsw(void __iomem *port, const void *addr, unsigned short count); -extern void outsl(void __iomem *port, const void *addr, unsigned short count); +extern void outsb(const void __iomem *port, const void *addr, unsigned short count); +extern void outsw(const void __iomem *port, const void *addr, unsigned short count); +extern void outsl(const void __iomem *port, const void *addr, unsigned short count); extern void insb(const void __iomem *port, void *addr, unsigned short count); extern void insw(const void __iomem *port, void *addr, unsigned short count); extern void insl(const void __iomem *port, void *addr, unsigned short count); -extern void dma_outsb(void __iomem *port, const void *addr, unsigned short count); -extern void dma_outsw(void __iomem *port, const void *addr, unsigned short count); -extern void dma_outsl(void __iomem *port, const void *addr, unsigned short count); +extern void dma_outsb(const void __iomem *port, const void *addr, unsigned short count); +extern void dma_outsw(const void __iomem *port, const void *addr, unsigned short count); +extern void dma_outsl(const void __iomem *port, const void *addr, unsigned short count); extern void dma_insb(const void __iomem *port, void *addr, unsigned short count); extern void dma_insw(const void __iomem *port, void *addr, unsigned short count); From c11b5776bfef671cd6eea4479f345ec042638643 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 11 Oct 2007 00:12:41 +0800 Subject: [PATCH 0056/2804] Blackfin arch: add more common defines for output sections Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/vmlinux.lds.S | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index cd1cea05f1a8..eec43674a465 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -185,6 +185,12 @@ SECTIONS __end = .; } + STABS_DEBUG + + DWARF_DEBUG + + NOTES + /DISCARD/ : { *(.exit.text) From b7b2d344e7f7027497547a8b786a407047ee5e26 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Tue, 9 Oct 2007 15:09:49 +0800 Subject: [PATCH 0057/2804] Blackfin arch: modify the insX/outsX and dma_insX/dma_outsX to be compatible with other archs Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_dma_5xx.c | 12 ++++++------ include/asm-blackfin/io.h | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 858cca6a2afc..17edd6599959 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -583,7 +583,7 @@ void *safe_dma_memcpy(void *dest, const void *src, size_t size) } EXPORT_SYMBOL(safe_dma_memcpy); -void dma_outsb(const void __iomem *addr, const void *buf, unsigned short len) +void dma_outsb(unsigned long addr, const void *buf, unsigned short len) { unsigned long flags; @@ -616,7 +616,7 @@ void dma_outsb(const void __iomem *addr, const void *buf, unsigned short len) EXPORT_SYMBOL(dma_outsb); -void dma_insb(const void __iomem *addr, void *buf, unsigned short len) +void dma_insb(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; @@ -647,7 +647,7 @@ void dma_insb(const void __iomem *addr, void *buf, unsigned short len) } EXPORT_SYMBOL(dma_insb); -void dma_outsw(const void __iomem *addr, const void *buf, unsigned short len) +void dma_outsw(unsigned long addr, const void *buf, unsigned short len) { unsigned long flags; @@ -679,7 +679,7 @@ void dma_outsw(const void __iomem *addr, const void *buf, unsigned short len) } EXPORT_SYMBOL(dma_outsw); -void dma_insw(const void __iomem *addr, void *buf, unsigned short len) +void dma_insw(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; @@ -711,7 +711,7 @@ void dma_insw(const void __iomem *addr, void *buf, unsigned short len) } EXPORT_SYMBOL(dma_insw); -void dma_outsl(const void __iomem *addr, const void *buf, unsigned short len) +void dma_outsl(unsigned long addr, const void *buf, unsigned short len) { unsigned long flags; @@ -743,7 +743,7 @@ void dma_outsl(const void __iomem *addr, const void *buf, unsigned short len) } EXPORT_SYMBOL(dma_outsl); -void dma_insl(const void __iomem *addr, void *buf, unsigned short len) +void dma_insl(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; diff --git a/include/asm-blackfin/io.h b/include/asm-blackfin/io.h index 3f48f8feb5c9..525179bf43d7 100644 --- a/include/asm-blackfin/io.h +++ b/include/asm-blackfin/io.h @@ -115,21 +115,21 @@ static inline unsigned int readl(const volatile void __iomem *addr) #ifndef __ASSEMBLY__ -extern void outsb(const void __iomem *port, const void *addr, unsigned short count); -extern void outsw(const void __iomem *port, const void *addr, unsigned short count); -extern void outsl(const void __iomem *port, const void *addr, unsigned short count); +extern void outsb(unsigned long port, const void *addr, unsigned long count); +extern void outsw(unsigned long port, const void *addr, unsigned long count); +extern void outsl(unsigned long port, const void *addr, unsigned long count); -extern void insb(const void __iomem *port, void *addr, unsigned short count); -extern void insw(const void __iomem *port, void *addr, unsigned short count); -extern void insl(const void __iomem *port, void *addr, unsigned short count); +extern void insb(unsigned long port, void *addr, unsigned long count); +extern void insw(unsigned long port, void *addr, unsigned long count); +extern void insl(unsigned long port, void *addr, unsigned long count); -extern void dma_outsb(const void __iomem *port, const void *addr, unsigned short count); -extern void dma_outsw(const void __iomem *port, const void *addr, unsigned short count); -extern void dma_outsl(const void __iomem *port, const void *addr, unsigned short count); +extern void dma_outsb(unsigned long port, const void *addr, unsigned short count); +extern void dma_outsw(unsigned long port, const void *addr, unsigned short count); +extern void dma_outsl(unsigned long port, const void *addr, unsigned short count); -extern void dma_insb(const void __iomem *port, void *addr, unsigned short count); -extern void dma_insw(const void __iomem *port, void *addr, unsigned short count); -extern void dma_insl(const void __iomem *port, void *addr, unsigned short count); +extern void dma_insb(unsigned long port, void *addr, unsigned short count); +extern void dma_insw(unsigned long port, void *addr, unsigned short count); +extern void dma_insl(unsigned long port, void *addr, unsigned short count); /* * Map some physical address range into the kernel address space. From 1d487f468de75b8a5c664db60e106935f9dc753b Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Thu, 11 Oct 2007 00:30:56 +0800 Subject: [PATCH 0058/2804] Blackfin arch: add TWIx_REGBASE and SPIx_REGBASE to specific CPU header files, use the new REGBASE for board platform resources Signed-off-by: Bryan Wu --- include/asm-blackfin/bfin5xx_spi.h | 2 -- include/asm-blackfin/mach-bf527/defBF52x_base.h | 2 ++ include/asm-blackfin/mach-bf533/defBF532.h | 1 + include/asm-blackfin/mach-bf537/defBF534.h | 2 ++ include/asm-blackfin/mach-bf548/defBF544.h | 1 + include/asm-blackfin/mach-bf548/defBF548.h | 2 ++ include/asm-blackfin/mach-bf548/defBF549.h | 2 ++ include/asm-blackfin/mach-bf548/defBF54x_base.h | 3 +++ include/asm-blackfin/mach-bf561/defBF561.h | 1 + 9 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/asm-blackfin/bfin5xx_spi.h b/include/asm-blackfin/bfin5xx_spi.h index 95c1c952e7c1..f617d8765451 100644 --- a/include/asm-blackfin/bfin5xx_spi.h +++ b/include/asm-blackfin/bfin5xx_spi.h @@ -21,8 +21,6 @@ #ifndef _SPI_CHANNEL_H_ #define _SPI_CHANNEL_H_ -#define SPI0_REGBASE 0xffc00500 - #define SPI_READ 0 #define SPI_WRITE 1 diff --git a/include/asm-blackfin/mach-bf527/defBF52x_base.h b/include/asm-blackfin/mach-bf527/defBF52x_base.h index 0b2fb5036ed0..b1ff67db01f8 100644 --- a/include/asm-blackfin/mach-bf527/defBF52x_base.h +++ b/include/asm-blackfin/mach-bf527/defBF52x_base.h @@ -102,6 +102,7 @@ /* SPI Controller (0xFFC00500 - 0xFFC005FF) */ +#define SPI0_REGBASE 0xFFC00500 #define SPI_CTL 0xFFC00500 /* SPI Control Register */ #define SPI_FLG 0xFFC00504 /* SPI Flag register */ #define SPI_STAT 0xFFC00508 /* SPI Status register */ @@ -480,6 +481,7 @@ /* Two-Wire Interface (0xFFC01400 - 0xFFC014FF) */ +#define TWI0_REGBASE 0xFFC01400 #define TWI_CLKDIV 0xFFC01400 /* Serial Clock Divider Register */ #define TWI_CONTROL 0xFFC01404 /* TWI Control Register */ #define TWI_SLAVE_CTL 0xFFC01408 /* Slave Mode Control Register */ diff --git a/include/asm-blackfin/mach-bf533/defBF532.h b/include/asm-blackfin/mach-bf533/defBF532.h index 81b4af17c6a3..37134aaf9954 100644 --- a/include/asm-blackfin/mach-bf533/defBF532.h +++ b/include/asm-blackfin/mach-bf533/defBF532.h @@ -104,6 +104,7 @@ #define UART_GCTL 0xFFC00424 /* Global Control Register */ /* SPI Controller (0xFFC00500 - 0xFFC005FF) */ +#define SPI0_REGBASE 0xFFC00500 #define SPI_CTL 0xFFC00500 /* SPI Control Register */ #define SPI_FLG 0xFFC00504 /* SPI Flag register */ #define SPI_STAT 0xFFC00508 /* SPI Status register */ diff --git a/include/asm-blackfin/mach-bf537/defBF534.h b/include/asm-blackfin/mach-bf537/defBF534.h index dce4c543a339..d0d80d3152ba 100644 --- a/include/asm-blackfin/mach-bf537/defBF534.h +++ b/include/asm-blackfin/mach-bf537/defBF534.h @@ -86,6 +86,7 @@ #define UART0_GCTL 0xFFC00424 /* Global Control Register */ /* SPI Controller (0xFFC00500 - 0xFFC005FF) */ +#define SPI0_REGBASE 0xFFC00500 #define SPI_CTL 0xFFC00500 /* SPI Control Register */ #define SPI_FLG 0xFFC00504 /* SPI Flag register */ #define SPI_STAT 0xFFC00508 /* SPI Status register */ @@ -456,6 +457,7 @@ #define PPI_FRAME 0xFFC01010 /* PPI Frame Length Register */ /* Two-Wire Interface (0xFFC01400 - 0xFFC014FF) */ +#define TWI0_REGBASE 0xFFC01400 #define TWI_CLKDIV 0xFFC01400 /* Serial Clock Divider Register */ #define TWI_CONTROL 0xFFC01404 /* TWI Control Register */ #define TWI_SLAVE_CTL 0xFFC01408 /* Slave Mode Control Register */ diff --git a/include/asm-blackfin/mach-bf548/defBF544.h b/include/asm-blackfin/mach-bf548/defBF544.h index dd955dcd39b8..760307e34b9e 100644 --- a/include/asm-blackfin/mach-bf548/defBF544.h +++ b/include/asm-blackfin/mach-bf548/defBF544.h @@ -81,6 +81,7 @@ /* Two Wire Interface Registers (TWI1) */ +#define TWI1_REGBASE 0xffc02200 #define TWI1_CLKDIV 0xffc02200 /* Clock Divider Register */ #define TWI1_CONTROL 0xffc02204 /* TWI Control Register */ #define TWI1_SLAVE_CTRL 0xffc02208 /* TWI Slave Mode Control Register */ diff --git a/include/asm-blackfin/mach-bf548/defBF548.h b/include/asm-blackfin/mach-bf548/defBF548.h index 8d4214e0807c..70af33c963b0 100644 --- a/include/asm-blackfin/mach-bf548/defBF548.h +++ b/include/asm-blackfin/mach-bf548/defBF548.h @@ -120,6 +120,7 @@ /* Two Wire Interface Registers (TWI1) */ +#define TWI1_REGBASE 0xffc02200 #define TWI1_CLKDIV 0xffc02200 /* Clock Divider Register */ #define TWI1_CONTROL 0xffc02204 /* TWI Control Register */ #define TWI1_SLAVE_CTRL 0xffc02208 /* TWI Slave Mode Control Register */ @@ -139,6 +140,7 @@ /* SPI2 Registers */ +#define SPI2_REGBASE 0xffc02400 #define SPI2_CTL 0xffc02400 /* SPI2 Control Register */ #define SPI2_FLG 0xffc02404 /* SPI2 Flag Register */ #define SPI2_STAT 0xffc02408 /* SPI2 Status Register */ diff --git a/include/asm-blackfin/mach-bf548/defBF549.h b/include/asm-blackfin/mach-bf548/defBF549.h index c2f4734da48d..50b3fe55ef0c 100644 --- a/include/asm-blackfin/mach-bf548/defBF549.h +++ b/include/asm-blackfin/mach-bf548/defBF549.h @@ -121,6 +121,7 @@ /* Two Wire Interface Registers (TWI1) */ +#define TWI1_REGBASE 0xffc02200 #define TWI1_CLKDIV 0xffc02200 /* Clock Divider Register */ #define TWI1_CONTROL 0xffc02204 /* TWI Control Register */ #define TWI1_SLAVE_CTRL 0xffc02208 /* TWI Slave Mode Control Register */ @@ -140,6 +141,7 @@ /* SPI2 Registers */ +#define SPI2_REGBASE 0xffc02400 #define SPI2_CTL 0xffc02400 /* SPI2 Control Register */ #define SPI2_FLG 0xffc02404 /* SPI2 Flag Register */ #define SPI2_STAT 0xffc02408 /* SPI2 Status Register */ diff --git a/include/asm-blackfin/mach-bf548/defBF54x_base.h b/include/asm-blackfin/mach-bf548/defBF54x_base.h index 895ddd40a838..e2632db74baa 100644 --- a/include/asm-blackfin/mach-bf548/defBF54x_base.h +++ b/include/asm-blackfin/mach-bf548/defBF54x_base.h @@ -109,6 +109,7 @@ /* SPI0 Registers */ +#define SPI0_REGBASE 0xffc00500 #define SPI0_CTL 0xffc00500 /* SPI0 Control Register */ #define SPI0_FLG 0xffc00504 /* SPI0 Flag Register */ #define SPI0_STAT 0xffc00508 /* SPI0 Status Register */ @@ -121,6 +122,7 @@ /* Two Wire Interface Registers (TWI0) */ +#define TWI0_REGBASE 0xffc00700 #define TWI0_CLKDIV 0xffc00700 /* Clock Divider Register */ #define TWI0_CONTROL 0xffc00704 /* TWI Control Register */ #define TWI0_SLAVE_CTRL 0xffc00708 /* TWI Slave Mode Control Register */ @@ -978,6 +980,7 @@ /* SPI1 Registers */ +#define SPI1_REGBASE 0xffc02300 #define SPI1_CTL 0xffc02300 /* SPI1 Control Register */ #define SPI1_FLG 0xffc02304 /* SPI1 Flag Register */ #define SPI1_STAT 0xffc02308 /* SPI1 Status Register */ diff --git a/include/asm-blackfin/mach-bf561/defBF561.h b/include/asm-blackfin/mach-bf561/defBF561.h index 0f2dc6e6335b..bf7dc4e00065 100644 --- a/include/asm-blackfin/mach-bf561/defBF561.h +++ b/include/asm-blackfin/mach-bf561/defBF561.h @@ -120,6 +120,7 @@ #define UART_GCTL 0xFFC00424 /* Global Control Register */ /* SPI Controller (0xFFC00500 - 0xFFC005FF) */ +#define SPI0_REGBASE 0xFFC00500 #define SPI_CTL 0xFFC00500 /* SPI Control Register */ #define SPI_FLG 0xFFC00504 /* SPI Flag register */ #define SPI_STAT 0xFFC00508 /* SPI Status register */ From 0ae53640b54f2c30e52044f7102ba08915b988a7 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Tue, 9 Oct 2007 17:24:49 +0800 Subject: [PATCH 0059/2804] Blackfin arch: Initial patch to add earlyprintk support This allows debugging of problems which happen eary in the kernel boot process (after bootargs are parsed, but before serial subsystem is fully initialized) Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- Documentation/kernel-parameters.txt | 3 +- arch/blackfin/Kconfig | 14 +++ arch/blackfin/kernel/Makefile | 1 + arch/blackfin/kernel/early_printk.c | 161 ++++++++++++++++++++++++++++ drivers/serial/bfin_5xx.c | 129 +++++++++++++++++----- include/asm-blackfin/early_printk.h | 28 +++++ 6 files changed, 307 insertions(+), 29 deletions(-) create mode 100644 arch/blackfin/kernel/early_printk.c create mode 100644 include/asm-blackfin/early_printk.h diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4d175c751246..a57c1f216b21 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -35,6 +35,7 @@ parameter is applicable: APIC APIC support is enabled. APM Advanced Power Management support is enabled. AX25 Appropriate AX.25 support is enabled. + BLACKFIN Blackfin architecture is enabled. DRM Direct Rendering Management support is enabled. EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EFI EFI Partitioning (GPT) is enabled @@ -550,7 +551,7 @@ and is between 256 and 4096 characters. It is defined in the file dtc3181e= [HW,SCSI] - earlyprintk= [X86-32,X86-64,SH] + earlyprintk= [X86-32,X86-64,SH,BLACKFIN] earlyprintk=vga earlyprintk=serial[,ttySn[,baudrate]] diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 26ebb0e8c431..cc789b988f3a 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -1164,6 +1164,20 @@ config DEBUG_BFIN_NO_KERN_HWTRACE Say Y here to disable hardware tracing in some known "jumpy" pieces of code so that the trace buffer will extend further back. +config EARLY_PRINTK + bool "Early printk" + default n + help + This option enables special console drivers which allow the kernel + to print messages very early in the bootup process. + + This is useful for kernel debugging when your machine crashes very + early before the console code is initialized. After enabling this + feature, you must add "earlyprintk=serial,uart0,57600" to the + command line (bootargs). It is safe to say Y here in all cases, as + all of this lives in the init section and is thrown away after the + kernel boots completely. + config DUAL_CORE_TEST_MODULE tristate "Dual Core Test Module" depends on (BF561) diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index 243883ec6de1..8aeb6066b19b 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o obj-$(CONFIG_KGDB) += kgdb.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c new file mode 100644 index 000000000000..9bf61706694f --- /dev/null +++ b/arch/blackfin/kernel/early_printk.c @@ -0,0 +1,161 @@ +/* + * File: arch/blackfin/kernel/early_printk.c + * Based on: arch/x86_64/kernel/early_printk.c + * Author: Robin Getz +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_BFIN +extern struct console *bfin_earlyserial_init(unsigned int port, + unsigned int cflag); +#endif + +static struct console *early_console; + +/* Default console + * Port n == ttyBFn + * cflags == UART output modes + */ +#define DEFAULT_PORT 0 +#define DEFAULT_CFLAG CS8|B57600 + +#ifdef CONFIG_SERIAL_CORE +/* What should get here is "0,57600" */ +static struct console * __init earlyserial_init(char *buf) +{ + int baud, bit; + char parity; + unsigned int serial_port = DEFAULT_PORT; + unsigned int cflag = DEFAULT_CFLAG; + + serial_port = simple_strtoul(buf, &buf, 10); + buf++; + + cflag = 0; + baud = simple_strtoul(buf, &buf, 10); + switch (baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 9600: + cflag |= B9600; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 115200: + cflag |= B115200; + break; + default: + cflag |= B57600; + } + + parity = buf[0]; + buf++; + switch (parity) { + case 'e': + cflag |= PARENB; + break; + case 'o': + cflag |= PARODD; + break; + } + + bit = simple_strtoul(buf, &buf, 10); + switch (bit) { + case 5: + cflag |= CS5; + break; + case 6: + cflag |= CS5; + break; + case 7: + cflag |= CS5; + break; + default: + cflag |= CS8; + } + +#ifdef CONFIG_SERIAL_BFIN + return bfin_earlyserial_init(serial_port, cflag); +#else + return NULL; +#endif + +} +#endif + +int __init setup_early_printk(char *buf) +{ + + /* Crashing in here would be really bad, so check both the var + and the pointer before we start using it + */ + if (!buf) + return 0; + + if (!*buf) + return 0; + + if (early_console != NULL) + return 0; + +#ifdef CONFIG_SERIAL_BFIN + /* Check for Blackfin Serial */ + if (!strncmp(buf, "serial,uart", 11)) { + buf += 11; + early_console = earlyserial_init(buf); + } +#endif +#ifdef CONFIG_FB + /* TODO: add framebuffer console support */ +#endif + + if (likely(early_console)) { + early_console->flags |= CON_BOOT; + + register_console(early_console); + printk(KERN_INFO "early printk enabled on %s%d\n", + early_console->name, + early_console->index); + } + + return 0; +} + +early_param("earlyprintk", setup_early_printk); diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 1e79ee605d93..5039e2675abc 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -962,30 +962,6 @@ static void __init bfin_serial_init_ports(void) } #ifdef CONFIG_SERIAL_BFIN_CONSOLE -static void bfin_serial_console_putchar(struct uart_port *port, int ch) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - while (!(UART_GET_LSR(uart) & THRE)) - barrier(); - UART_PUT_CHAR(uart, ch); - SSYNC(); -} - -/* - * Interrupts are disabled on entering - */ -static void -bfin_serial_console_write(struct console *co, const char *s, unsigned int count) -{ - struct bfin_serial_port *uart = &bfin_serial_ports[co->index]; - int flags = 0; - - spin_lock_irqsave(&uart->port.lock, flags); - uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); - spin_unlock_irqrestore(&uart->port.lock, flags); - -} - /* * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. @@ -1038,19 +1014,25 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, } pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits); } +#endif + +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) +static struct uart_driver bfin_serial_reg; static int __init bfin_serial_console_setup(struct console *co, char *options) { struct bfin_serial_port *uart; +# ifdef CONFIG_SERIAL_BFIN_CONSOLE int baud = 57600; int bits = 8; int parity = 'n'; -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +# ifdef CONFIG_SERIAL_BFIN_CTSRTS int flow = 'r'; -#else +# else int flow = 'n'; -#endif +# endif +# endif /* * Check whether an invalid uart number has been specified, and @@ -1061,15 +1043,45 @@ bfin_serial_console_setup(struct console *co, char *options) co->index = 0; uart = &bfin_serial_ports[co->index]; +# ifdef CONFIG_SERIAL_BFIN_CONSOLE if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else bfin_serial_console_get_options(uart, &baud, &parity, &bits); return uart_set_options(&uart->port, co, baud, parity, bits, flow); +# else + return 0; +# endif +} +#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) || + defined (CONFIG_EARLY_PRINTK) */ + +#ifdef CONFIG_SERIAL_BFIN_CONSOLE +static void bfin_serial_console_putchar(struct uart_port *port, int ch) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + while (!(UART_GET_LSR(uart) & THRE)) + barrier(); + UART_PUT_CHAR(uart, ch); + SSYNC(); +} + +/* + * Interrupts are disabled on entering + */ +static void +bfin_serial_console_write(struct console *co, const char *s, unsigned int count) +{ + struct bfin_serial_port *uart = &bfin_serial_ports[co->index]; + int flags = 0; + + spin_lock_irqsave(&uart->port.lock, flags); + uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); + spin_unlock_irqrestore(&uart->port.lock, flags); + } -static struct uart_driver bfin_serial_reg; static struct console bfin_serial_console = { .name = BFIN_SERIAL_NAME, .write = bfin_serial_console_write, @@ -1095,7 +1107,68 @@ console_initcall(bfin_serial_rs_console_init); #define BFIN_SERIAL_CONSOLE &bfin_serial_console #else #define BFIN_SERIAL_CONSOLE NULL +#endif /* CONFIG_SERIAL_BFIN_CONSOLE */ + + +#ifdef CONFIG_EARLY_PRINTK +static __init void early_serial_putc(struct uart_port *port, int ch) +{ + unsigned timeout = 0xffff; + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + while ((!(UART_GET_LSR(uart) & THRE)) && --timeout) + cpu_relax(); + UART_PUT_CHAR(uart, ch); +} + +static __init void early_serial_write(struct console *con, const char *s, + unsigned int n) +{ + struct bfin_serial_port *uart = &bfin_serial_ports[con->index]; + unsigned int i; + + for (i = 0; i < n; i++, s++) { + if (*s == '\n') + early_serial_putc(&uart->port, '\r'); + early_serial_putc(&uart->port, *s); + } +} + +static struct __init console bfin_early_serial_console = { + .name = "early_BFuart", + .write = early_serial_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .setup = bfin_serial_console_setup, + .index = -1, + .data = &bfin_serial_reg, +}; + +struct console __init *bfin_earlyserial_init(unsigned int port, + unsigned int cflag) +{ + struct bfin_serial_port *uart; + struct ktermios t; + + if (port == -1 || port >= nr_ports) + port = 0; + bfin_serial_init_ports(); + bfin_early_serial_console.index = port; +#ifdef CONFIG_KGDB_UART + kgdb_entry_state = 0; + init_kgdb_uart(); #endif + uart = &bfin_serial_ports[port]; + t.c_cflag = cflag; + t.c_iflag = 0; + t.c_oflag = 0; + t.c_lflag = ICANON; + t.c_line = port; + bfin_serial_set_termios(&uart->port, &t, &t); + return &bfin_early_serial_console; +} + +#endif /* CONFIG_SERIAL_BFIN_CONSOLE */ static struct uart_driver bfin_serial_reg = { .owner = THIS_MODULE, diff --git a/include/asm-blackfin/early_printk.h b/include/asm-blackfin/early_printk.h new file mode 100644 index 000000000000..110f1c1f845c --- /dev/null +++ b/include/asm-blackfin/early_printk.h @@ -0,0 +1,28 @@ +/* + * File: include/asm-blackfin/early_printk.h + * Author: Robin Getz Date: Tue, 9 Oct 2007 17:24:30 +0800 Subject: [PATCH 0060/2804] Blackfin arch: fix endless loop bug when a double fault happens Today when a double fault happens (exception during an exception handling event), we go into an endless loop, with nothing comming out the UART. With this patch, we actually see that we have commited a double fault event Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/kernel/traps.c | 8 ++++ arch/blackfin/mach-common/entry.S | 69 ++++++++++++++++++++++++------- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 1a8a5f171bc8..ba68eb2ec929 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -132,6 +132,14 @@ static int printk_address(unsigned long address) } #endif +asmlinkage void double_fault_c(struct pt_regs *fp) +{ + printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); + dump_bfin_regs(fp, (void *)fp->retx); + panic("Double Fault - unrecoverable event\n"); + +} + asmlinkage void trap_c(struct pt_regs *fp) { #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 3feca05694f8..e2239361cac3 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -29,21 +29,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * 25-Dec-2004 - LG Soft India - * 1. Fix in return_from_int, to make sure any pending - * system call in ILAT for this process to get - * executed, otherwise in case context switch happens, - * system call of first process (i.e in ILAT) will be - * carried forward to the switched process. - * 2. Removed Constant references for the following - * a. IPEND - * b. EXCAUSE mask - * c. PAGE Mask - */ - -/* - * NOTE: This code handles signal-recognition, which happens every time +/* NOTE: This code handles signal-recognition, which happens every time * after a timer-interrupt and after each system call. */ @@ -175,6 +161,13 @@ ENTRY(_ex_replaceable) nop; ENTRY(_ex_trap_c) + /* Make sure we are not in a double fault */ + p4.l = lo(IPEND); + p4.h = hi(IPEND); + r7 = [p4]; + CC = BITTST (r7, 5); + if CC jump _double_fault; + /* Call C code (trap_c) to handle the exception, which most * likely involves sending a signal to the current process. * To avoid double faults, lower our priority to IRQ5 first. @@ -220,6 +213,52 @@ ENTRY(_ex_trap_c) rtx; ENDPROC(_ex_trap_c) +/* We just realized we got an exception, while we were processing a different + * exception. This is a unrecoverable event, so crash + */ +ENTRY(_double_fault) + /* Turn caches & protection off, to ensure we don't get any more + * double exceptions + */ + + P4.L = LO(IMEM_CONTROL); + P4.H = HI(IMEM_CONTROL); + + R5 = [P4]; /* Control Register*/ + BITCLR(R5,ENICPLB_P); + SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + + P4.L = LO(DMEM_CONTROL); + P4.H = HI(DMEM_CONTROL); + R5 = [P4]; + BITCLR(R5,ENDCPLB_P); + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + + /* Fix up the stack */ + (R7:6,P5:4) = [sp++]; + ASTAT = [sp++]; + SP = EX_SCRATCH_REG; + + /* We should be out of the exception stack, and back down into + * kernel or user space stack + */ + SAVE_ALL_SYS + + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ + SP += -12; + call _double_fault_c; + SP += 12; +.L_double_fault_panic: + JUMP .L_double_fault_panic + +ENDPROC(_double_fault) + ENTRY(_exception_to_level5) SAVE_ALL_SYS From ce3afa1c043ab3d4125671441a57353d80f5f6f7 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Tue, 9 Oct 2007 17:28:36 +0800 Subject: [PATCH 0061/2804] Blackfin arch: Enable earlyprintk earlier - so any error after our interrupt tables are set up will print out Also ensure that the traps_c code doesn't cause a double fault, by sending a signal to a faulting kernel before the memory subsystem is fully initialized, by printing out the error message before sending the signal. Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/kernel/setup.c | 38 ++++++++++++++++++++---------------- arch/blackfin/kernel/traps.c | 8 ++++---- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index abf34a8dd070..8dcd76e87ed5 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -44,6 +44,7 @@ #include #include #include +#include u16 _bfin_swrst; @@ -157,8 +158,10 @@ static __init void parse_cmdline_early(char *cmdline_p) 1; } } + } else if (!memcmp(to, "earlyprintk=", 12)) { + to += 12; + setup_early_printk(to); } - } c = *(to++); if (!c) @@ -177,6 +180,23 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + +#if defined(CONFIG_CMDLINE_BOOL) + strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line)); + command_line[sizeof(command_line) - 1] = 0; +#endif + + /* Keep a copy of command line */ + *cmdline_p = &command_line[0]; + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + + /* setup memory defaults from the user config */ + physical_mem_end = 0; + _ramend = CONFIG_MEM_SIZE * 1024 * 1024; + + parse_cmdline_early(&command_line[0]); + cclk = get_cclk(); sclk = get_sclk(); @@ -210,22 +230,6 @@ void __init setup_arch(char **cmdline_p) flash_probe(); #endif -#if defined(CONFIG_CMDLINE_BOOL) - strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line)); - command_line[sizeof(command_line) - 1] = 0; -#endif - - /* Keep a copy of command line */ - *cmdline_p = &command_line[0]; - memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); - boot_command_line[COMMAND_LINE_SIZE - 1] = '\0'; - - /* setup memory defaults from the user config */ - physical_mem_end = 0; - _ramend = CONFIG_MEM_SIZE * 1024 * 1024; - - parse_cmdline_early(&command_line[0]); - if (physical_mem_end == 0) physical_mem_end = _ramend; diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index ba68eb2ec929..8823e9ade584 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -402,10 +402,6 @@ asmlinkage void trap_c(struct pt_regs *fp) break; } - info.si_signo = sig; - info.si_errno = 0; - info.si_addr = (void *)fp->pc; - force_sig_info(sig, &info, current); if (sig != 0 && sig != SIGTRAP) { unsigned long stack; dump_bfin_regs(fp, (void *)fp->retx); @@ -414,6 +410,10 @@ asmlinkage void trap_c(struct pt_regs *fp) if (current->mm == NULL) panic("Kernel exception"); } + info.si_signo = sig; + info.si_errno = 0; + info.si_addr = (void *)fp->pc; + force_sig_info(sig, &info, current); /* if the address that we are about to return to is not valid, set it * to a valid address, if we have a current application or panic From 337d390b3a9c1ce92a12bdb77b9ae6ded6273b12 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Tue, 9 Oct 2007 17:31:46 +0800 Subject: [PATCH 0062/2804] Blackfin arch: Print out debug info, as early as possible Print out debug info, as early as possible - even before the kernel initializes the interrupt vectors. Now we can print out debug messages almost anytime during the boot process. Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/kernel/early_printk.c | 61 +++++++++++++++++++++++++++-- arch/blackfin/mach-bf533/head.S | 6 +++ arch/blackfin/mach-bf537/head.S | 6 +++ arch/blackfin/mach-bf548/head.S | 6 +++ arch/blackfin/mach-bf561/head.S | 6 +++ arch/blackfin/mach-common/entry.S | 43 +++++++++++++++++++- include/asm-blackfin/irq_handler.h | 1 + 7 files changed, 123 insertions(+), 6 deletions(-) diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c index 9bf61706694f..6ec518a81113 100644 --- a/arch/blackfin/kernel/early_printk.c +++ b/arch/blackfin/kernel/early_printk.c @@ -38,13 +38,13 @@ extern struct console *bfin_earlyserial_init(unsigned int port, static struct console *early_console; -/* Default console - * Port n == ttyBFn - * cflags == UART output modes - */ +/* Default console */ #define DEFAULT_PORT 0 #define DEFAULT_CFLAG CS8|B57600 +/* Default console for early crashes */ +#define DEFAULT_EARLY_PORT "serial,uart0,57600" + #ifdef CONFIG_SERIAL_CORE /* What should get here is "0,57600" */ static struct console * __init earlyserial_init(char *buf) @@ -158,4 +158,57 @@ int __init setup_early_printk(char *buf) return 0; } +/* + * Set up a temporary Event Vector Table, so if something bad happens before + * the kernel is fully started, it doesn't vector off into somewhere we don't + * know + */ + +asmlinkage void __init init_early_exception_vectors(void) +{ + SSYNC(); + + /* cannot program in software: + * evt0 - emulation (jtag) + * evt1 - reset + */ + bfin_write_EVT2(early_trap); + bfin_write_EVT3(early_trap); + bfin_write_EVT5(early_trap); + bfin_write_EVT6(early_trap); + bfin_write_EVT7(early_trap); + bfin_write_EVT8(early_trap); + bfin_write_EVT9(early_trap); + bfin_write_EVT10(early_trap); + bfin_write_EVT11(early_trap); + bfin_write_EVT12(early_trap); + bfin_write_EVT13(early_trap); + bfin_write_EVT14(early_trap); + bfin_write_EVT15(early_trap); + CSYNC(); + + /* Set all the return from interupt, exception, NMI to a known place + * so if we do a RETI, RETX or RETN by mistake - we go somewhere known + * Note - don't change RETS - we are in a subroutine, or + * RETE - since it might screw up if emulator is attached + */ + asm("\tRETI = %0; RETX = %0; RETN = %0;\n" + : : "p"(early_trap)); + +} + +asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr) +{ + /* This can happen before the uart is initialized, so initialize + * the UART now + */ + if (likely(early_console == NULL)) + setup_early_printk(DEFAULT_EARLY_PORT); + + dump_bfin_regs(fp, retaddr); + dump_bfin_trace_buffer(); + + panic("Died early"); +} + early_param("earlyprintk", setup_early_printk); diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S index fa6dc0d8593b..1ded945a6fa0 100644 --- a/arch/blackfin/mach-bf533/head.S +++ b/arch/blackfin/mach-bf533/head.S @@ -181,6 +181,12 @@ ENTRY(__start) fp = sp; usp = sp; +#ifdef CONFIG_EARLY_PRINTK + SP += -12; + call _init_early_exception_vectors; + SP += 12; +#endif + /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ call _bf53x_relocate_l1_mem; #if CONFIG_BFIN_KERNEL_CLOCK diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S index 2c4ae466d4e9..3014fe8dd155 100644 --- a/arch/blackfin/mach-bf537/head.S +++ b/arch/blackfin/mach-bf537/head.S @@ -224,6 +224,12 @@ ENTRY(__start) fp = sp; usp = sp; +#ifdef CONFIG_EARLY_PRINTK + SP += -12; + call _init_early_exception_vectors; + SP += 12; +#endif + /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ call _bf53x_relocate_l1_mem; #if CONFIG_BFIN_KERNEL_CLOCK diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S index 532ed0930b5e..3071c243d426 100644 --- a/arch/blackfin/mach-bf548/head.S +++ b/arch/blackfin/mach-bf548/head.S @@ -125,6 +125,12 @@ ENTRY(__stext) FP = SP; USP = SP; +#ifdef CONFIG_EARLY_PRINTK + SP += -12; + call _init_early_exception_vectors; + SP += 12; +#endif + /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ call _bf53x_relocate_l1_mem; #if CONFIG_BFIN_KERNEL_CLOCK diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S index fd39891ae0fe..96a3d456fb6d 100644 --- a/arch/blackfin/mach-bf561/head.S +++ b/arch/blackfin/mach-bf561/head.S @@ -169,6 +169,12 @@ ENTRY(__start) fp = sp; usp = sp; +#ifdef CONFIG_EARLY_PRINTK + SP += -12; + call _init_early_exception_vectors; + SP += 12; +#endif + /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ call _bf53x_relocate_l1_mem; #if CONFIG_BFIN_KERNEL_CLOCK diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index e2239361cac3..a56b231d94ce 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -835,12 +835,13 @@ ENTRY(_ex_trace_buff_full) P2 = [sp++]; P3 = [sp++]; jump _return_from_exception; +ENDPROC(_ex_trace_buff_full) #if CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN == 4 .data #else .section .l1.data.B -#endif +#endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN */ ENTRY(_trace_buff_offset) .long 0; ALIGN @@ -848,7 +849,45 @@ ENTRY(_software_trace_buff) .rept ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*256); .long 0 .endr -#endif +#endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND */ + +#if CONFIG_EARLY_PRINTK +.section .init.text +ENTRY(_early_trap) + SAVE_ALL_SYS + trace_buffer_stop(p0,r0); + + /* Turn caches off, to ensure we don't get double exceptions */ + + P4.L = LO(IMEM_CONTROL); + P4.H = HI(IMEM_CONTROL); + + R5 = [P4]; /* Control Register*/ + BITCLR(R5,ENICPLB_P); + CLI R1; + SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + + P4.L = LO(DMEM_CONTROL); + P4.H = HI(DMEM_CONTROL); + R5 = [P4]; + BITCLR(R5,ENDCPLB_P); + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + STI R1; + + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ + r1 = RETX; + + SP += -12; + call _early_trap_c; + SP += 12; +ENDPROC(_early_trap) +#endif /* CONFIG_EARLY_PRINTK */ /* * Put these in the kernel data section - that should always be covered by diff --git a/include/asm-blackfin/irq_handler.h b/include/asm-blackfin/irq_handler.h index 19534c133c93..139b5208f9d8 100644 --- a/include/asm-blackfin/irq_handler.h +++ b/include/asm-blackfin/irq_handler.h @@ -22,6 +22,7 @@ asmlinkage void evt_system_call(void); asmlinkage void init_exception_buff(void); asmlinkage void trap_c(struct pt_regs *fp); asmlinkage void ex_replaceable(void); +asmlinkage void early_trap(void); extern void *ex_table[]; extern void return_from_exception(void); From 2b39331a282c3a03415653d4e188910a11c9db8a Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 10 Oct 2007 16:58:49 +0800 Subject: [PATCH 0063/2804] Blackfin arch: Comply with revised Anomaly Workarounds for BF533 05000311 and BF561 05000323 Comply with revised Anomaly Workarounds for BF533 05000311 and BF561 05000323 accoring to BF533 anomaly sheet Rev. A 09/04/07 Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_gpio.c | 177 +++++++++++++--------- include/asm-blackfin/mach-bf527/anomaly.h | 2 + include/asm-blackfin/mach-bf533/anomaly.h | 1 + include/asm-blackfin/mach-bf537/anomaly.h | 1 + include/asm-blackfin/mach-bf548/anomaly.h | 1 + 5 files changed, 112 insertions(+), 70 deletions(-) diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index b58b0de3c907..3fe0cd49e8db 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -88,6 +88,36 @@ #include #include +#if ANOMALY_05000311 || ANOMALY_05000323 +enum { + AWA_data = SYSCR, + AWA_data_clear = SYSCR, + AWA_data_set = SYSCR, + AWA_toggle = SYSCR, + AWA_maska = UART_SCR, + AWA_maska_clear = UART_SCR, + AWA_maska_set = UART_SCR, + AWA_maska_toggle = UART_SCR, + AWA_maskb = UART_GCTL, + AWA_maskb_clear = UART_GCTL, + AWA_maskb_set = UART_GCTL, + AWA_maskb_toggle = UART_GCTL, + AWA_dir = SPORT1_STAT, + AWA_polar = SPORT1_STAT, + AWA_edge = SPORT1_STAT, + AWA_both = SPORT1_STAT, +#if ANOMALY_05000311 + AWA_inen = TIMER_ENABLE, +#elif ANOMALY_05000323 + AWA_inen = DMA1_1_CONFIG, +#endif +}; + /* Anomaly Workaround */ +#define AWA_DUMMY_READ(name) bfin_read16(AWA_ ## name) +#else +#define AWA_DUMMY_READ(...) do { } while (0) +#endif + #ifdef BF533_FAMILY static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = { (struct gpio_port_t *) FIO_FLAG_D, @@ -332,10 +362,13 @@ inline u16 get_portmux(unsigned short portno) static void default_gpio(unsigned short gpio) { unsigned short bank, bitmask; + unsigned long flags; bank = gpio_bank(gpio); bitmask = gpio_bit(gpio); + local_irq_save(flags); + gpio_bankb[bank]->maska_clear = bitmask; gpio_bankb[bank]->maskb_clear = bitmask; SSYNC(); @@ -344,6 +377,9 @@ static void default_gpio(unsigned short gpio) gpio_bankb[bank]->polar &= ~bitmask; gpio_bankb[bank]->both &= ~bitmask; gpio_bankb[bank]->edge &= ~bitmask; + AWA_DUMMY_READ(edge); + local_irq_restore(flags); + } #else # define default_gpio(...) do { } while (0) @@ -396,6 +432,7 @@ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \ else \ gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \ + AWA_DUMMY_READ(name); \ local_irq_restore(flags); \ } \ EXPORT_SYMBOL(set_gpio_ ## name); @@ -407,6 +444,22 @@ SET_GPIO(edge) SET_GPIO(both) +#if ANOMALY_05000311 || ANOMALY_05000323 +#define SET_GPIO_SC(name) \ +void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ +{ \ + unsigned long flags; \ + BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \ + local_irq_save(flags); \ + if (arg) \ + gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \ + else \ + gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ +} \ +EXPORT_SYMBOL(set_gpio_ ## name); +#else #define SET_GPIO_SC(name) \ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ { \ @@ -417,37 +470,20 @@ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ } \ EXPORT_SYMBOL(set_gpio_ ## name); +#endif SET_GPIO_SC(maska) SET_GPIO_SC(maskb) - -#if ANOMALY_05000311 -void set_gpio_data(unsigned short gpio, unsigned short arg) -{ - unsigned long flags; - BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); - local_irq_save(flags); - if (arg) - gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio); - else - gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio); - bfin_read_CHIPID(); - local_irq_restore(flags); -} -EXPORT_SYMBOL(set_gpio_data); -#else SET_GPIO_SC(data) -#endif - -#if ANOMALY_05000311 +#if ANOMALY_05000311 || ANOMALY_05000323 void set_gpio_toggle(unsigned short gpio) { unsigned long flags; BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); local_irq_save(flags); gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio); - bfin_read_CHIPID(); + AWA_DUMMY_READ(toggle); local_irq_restore(flags); } #else @@ -462,13 +498,27 @@ EXPORT_SYMBOL(set_gpio_toggle); /*Set current PORT date (16-bit word)*/ +#if ANOMALY_05000311 || ANOMALY_05000323 +#define SET_GPIO_P(name) \ +void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \ +{ \ + unsigned long flags; \ + local_irq_save(flags); \ + gpio_bankb[gpio_bank(gpio)]->name = arg; \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ +} \ +EXPORT_SYMBOL(set_gpiop_ ## name); +#else #define SET_GPIO_P(name) \ void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \ { \ gpio_bankb[gpio_bank(gpio)]->name = arg; \ } \ EXPORT_SYMBOL(set_gpiop_ ## name); +#endif +SET_GPIO_P(data) SET_GPIO_P(dir) SET_GPIO_P(inen) SET_GPIO_P(polar) @@ -478,31 +528,30 @@ SET_GPIO_P(maska) SET_GPIO_P(maskb) -#if ANOMALY_05000311 -void set_gpiop_data(unsigned short gpio, unsigned short arg) -{ - unsigned long flags; - local_irq_save(flags); - gpio_bankb[gpio_bank(gpio)]->data = arg; - bfin_read_CHIPID(); - local_irq_restore(flags); -} -EXPORT_SYMBOL(set_gpiop_data); -#else -SET_GPIO_P(data) -#endif - - - /* Get a specific bit */ - +#if ANOMALY_05000311 || ANOMALY_05000323 +#define GET_GPIO(name) \ +unsigned short get_gpio_ ## name(unsigned short gpio) \ +{ \ + unsigned long flags; \ + unsigned short ret; \ + local_irq_save(flags); \ + ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ + return ret; \ +} \ +EXPORT_SYMBOL(get_gpio_ ## name); +#else #define GET_GPIO(name) \ unsigned short get_gpio_ ## name(unsigned short gpio) \ { \ return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \ } \ EXPORT_SYMBOL(get_gpio_ ## name); +#endif +GET_GPIO(data) GET_GPIO(dir) GET_GPIO(inen) GET_GPIO(polar) @@ -511,33 +560,31 @@ GET_GPIO(both) GET_GPIO(maska) GET_GPIO(maskb) - -#if ANOMALY_05000311 -unsigned short get_gpio_data(unsigned short gpio) -{ - unsigned long flags; - unsigned short ret; - BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); - local_irq_save(flags); - ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio)); - bfin_read_CHIPID(); - local_irq_restore(flags); - return ret; -} -EXPORT_SYMBOL(get_gpio_data); -#else -GET_GPIO(data) -#endif - /*Get current PORT date (16-bit word)*/ +#if ANOMALY_05000311 || ANOMALY_05000323 +#define GET_GPIO_P(name) \ +unsigned short get_gpiop_ ## name(unsigned short gpio) \ +{ \ + unsigned long flags; \ + unsigned short ret; \ + local_irq_save(flags); \ + ret = (gpio_bankb[gpio_bank(gpio)]->name); \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ + return ret; \ +} \ +EXPORT_SYMBOL(get_gpiop_ ## name); +#else #define GET_GPIO_P(name) \ unsigned short get_gpiop_ ## name(unsigned short gpio) \ { \ return (gpio_bankb[gpio_bank(gpio)]->name);\ } \ EXPORT_SYMBOL(get_gpiop_ ## name); +#endif +GET_GPIO_P(data) GET_GPIO_P(dir) GET_GPIO_P(inen) GET_GPIO_P(polar) @@ -546,21 +593,6 @@ GET_GPIO_P(both) GET_GPIO_P(maska) GET_GPIO_P(maskb) -#if ANOMALY_05000311 -unsigned short get_gpiop_data(unsigned short gpio) -{ - unsigned long flags; - unsigned short ret; - local_irq_save(flags); - ret = gpio_bankb[gpio_bank(gpio)]->data; - bfin_read_CHIPID(); - local_irq_restore(flags); - return ret; -} -EXPORT_SYMBOL(get_gpiop_data); -#else -GET_GPIO_P(data) -#endif #ifdef CONFIG_PM /*********************************************************** @@ -684,6 +716,8 @@ u32 gpio_pm_setup(void) } } + AWA_DUMMY_READ(maskb_set); + if (sic_iwr) return sic_iwr; else @@ -715,6 +749,7 @@ void gpio_pm_restore(void) gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb; } + AWA_DUMMY_READ(maskb); } #endif @@ -1089,6 +1124,7 @@ void gpio_direction_input(unsigned short gpio) local_irq_save(flags); gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio); gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio); + AWA_DUMMY_READ(inen); local_irq_restore(flags); } EXPORT_SYMBOL(gpio_direction_input); @@ -1102,6 +1138,7 @@ void gpio_direction_output(unsigned short gpio) local_irq_save(flags); gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio); + AWA_DUMMY_READ(dir); local_irq_restore(flags); } EXPORT_SYMBOL(gpio_direction_output); diff --git a/include/asm-blackfin/mach-bf527/anomaly.h b/include/asm-blackfin/mach-bf527/anomaly.h index 6112bc38282f..991db986cd4b 100644 --- a/include/asm-blackfin/mach-bf527/anomaly.h +++ b/include/asm-blackfin/mach-bf527/anomaly.h @@ -36,4 +36,6 @@ /* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */ #define ANOMALY_05000347 (1) +/* Anomalies that don't exist on this proc */ +#define ANOMALY_05000323 (0) #endif diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h index caea0b0f8326..f36ff5af1b91 100644 --- a/include/asm-blackfin/mach-bf533/anomaly.h +++ b/include/asm-blackfin/mach-bf533/anomaly.h @@ -254,5 +254,6 @@ /* Anomalies that don't exist on this proc */ #define ANOMALY_05000266 (0) +#define ANOMALY_05000323 (0) #endif diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h index 71380ad29dfd..2b66ecf489f7 100644 --- a/include/asm-blackfin/mach-bf537/anomaly.h +++ b/include/asm-blackfin/mach-bf537/anomaly.h @@ -139,5 +139,6 @@ #define ANOMALY_05000230 (0) #define ANOMALY_05000266 (0) #define ANOMALY_05000311 (0) +#define ANOMALY_05000323 (0) #endif diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h index 0d12dbe5232e..c5b63759cdee 100644 --- a/include/asm-blackfin/mach-bf548/anomaly.h +++ b/include/asm-blackfin/mach-bf548/anomaly.h @@ -80,5 +80,6 @@ #define ANOMALY_05000266 (0) #define ANOMALY_05000273 (0) #define ANOMALY_05000311 (0) +#define ANOMALY_05000323 (0) #endif From a359cca71e73a83612b5bbecea41d3b7a47160ca Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 10 Oct 2007 16:47:58 +0800 Subject: [PATCH 0064/2804] Blackfin arch: update kgdb patch Signed-off-by: Sonic Zhang Signed-off-by: Bryan Wu --- drivers/serial/bfin_5xx.c | 44 ++++++++++++++++++++++--------------- include/asm-blackfin/kgdb.h | 1 + 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 5039e2675abc..3f39e1814693 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -86,10 +86,8 @@ static void bfin_serial_stop_tx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -#ifdef CONFIG_BF54x while (!(UART_GET_LSR(uart) & TEMT)) continue; -#endif #ifdef CONFIG_SERIAL_BFIN_DMA disable_dma(uart->tx_dma_channel); @@ -128,8 +126,8 @@ static void bfin_serial_start_tx(struct uart_port *port) ier = UART_GET_IER(uart); ier |= ETBEI; UART_PUT_IER(uart, ier); - bfin_serial_tx_chars(uart); #endif + bfin_serial_tx_chars(uart); #endif } @@ -139,18 +137,21 @@ static void bfin_serial_start_tx(struct uart_port *port) static void bfin_serial_stop_rx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; +#ifdef CONFIG_KGDB_UART + if (uart->port.line != CONFIG_KGDB_UART_PORT) { +#endif #ifdef CONFIG_BF54x UART_CLEAR_IER(uart, ERBFI); #else unsigned short ier; ier = UART_GET_IER(uart); -#ifdef CONFIG_KGDB_UART - if (uart->port.line != CONFIG_KGDB_UART_PORT) -#endif ier &= ~ERBFI; UART_PUT_IER(uart, ier); #endif +#ifdef CONFIG_KGDB_UART + } +#endif } /* @@ -175,8 +176,11 @@ void kgdb_put_debug_char(int chr) while (!(UART_GET_LSR(uart) & THRE)) { SSYNC(); } + +#ifndef CONFIG_BF54x UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); SSYNC(); +#endif UART_PUT_CHAR(uart, (unsigned char)chr); SSYNC(); } @@ -194,8 +198,10 @@ int kgdb_get_debug_char(void) while(!(UART_GET_LSR(uart) & DR)) { SSYNC(); } +#ifndef CONFIG_BF54x UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); SSYNC(); +#endif chr = UART_GET_CHAR(uart); SSYNC(); @@ -697,17 +703,19 @@ static int bfin_serial_startup(struct uart_port *port) uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; add_timer(&(uart->rx_dma_timer)); #else -# ifdef CONFIG_KGDB_UART - if (uart->port.line != CONFIG_KGDB_UART_PORT && request_irq -# else - if (request_irq -# endif - (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, + if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, "BFIN_UART_RX", uart)) { +# ifdef CONFIG_KGDB_UART + if (uart->port.line != CONFIG_KGDB_UART_PORT) { +# endif printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); return -EBUSY; +# ifdef CONFIG_KGDB_UART + } +# endif } + if (request_irq (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED, "BFIN_UART_TX", uart)) { @@ -1154,10 +1162,6 @@ struct console __init *bfin_earlyserial_init(unsigned int port, port = 0; bfin_serial_init_ports(); bfin_early_serial_console.index = port; -#ifdef CONFIG_KGDB_UART - kgdb_entry_state = 0; - init_kgdb_uart(); -#endif uart = &bfin_serial_ports[port]; t.c_cflag = cflag; t.c_iflag = 0; @@ -1255,7 +1259,7 @@ static int __init bfin_serial_init(void) int ret; #ifdef CONFIG_KGDB_UART struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - struct termios t; + struct ktermios t; #endif pr_info("Serial: Blackfin serial driver\n"); @@ -1272,10 +1276,14 @@ static int __init bfin_serial_init(void) } #ifdef CONFIG_KGDB_UART if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) { - request_irq(uart->port.irq, bfin_serial_int, + request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, "BFIN_UART_RX", uart); pr_info("Request irq for kgdb uart port\n"); +#ifdef CONFIG_BF54x + UART_SET_IER(uart, ERBFI); +#else UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI); +#endif SSYNC(); t.c_cflag = CS8|B57600; t.c_iflag = 0; diff --git a/include/asm-blackfin/kgdb.h b/include/asm-blackfin/kgdb.h index 532bd9052004..0f73847fd6bc 100644 --- a/include/asm-blackfin/kgdb.h +++ b/include/asm-blackfin/kgdb.h @@ -179,5 +179,6 @@ enum regnames { #define STATDA1 0x80 extern void kgdb_print(const char *fmt, ...); +extern void init_kgdb_uart(void); #endif From 1a7d91d651f25005c4f507aebf9eab17e508889c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 10 Oct 2007 17:42:55 +0800 Subject: [PATCH 0065/2804] Blackfin arch: flush/inv the correct range when using write back cache and fix bugs find by dmacopy - flush/inv the correct range - dmacopy test failed when policy is write_back - invalidate before dma http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=3367 It's the cache invalidate what is causing the issue. There is no invalidate only instruction it's always: FLUSHINV So when we "invalidate" after the DMA we might (do) overwrite freshly dma'ed data by dirty Cache WB content. Fixed by moving the "invalidate" at the beginning of dma_memcpy. Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_dma_5xx.c | 39 ++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 17edd6599959..e19164fb4cd1 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -436,6 +436,10 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) blackfin_dcache_flush_range((unsigned int)src, (unsigned int)(src + size)); + if ((unsigned long)dest < memory_end) + blackfin_dcache_invalidate_range((unsigned int)dest, + (unsigned int)(dest + size)); + bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); if ((unsigned long)src < (unsigned long)dest) @@ -543,6 +547,8 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) } } + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)) ; @@ -552,9 +558,6 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) bfin_write_MDMA_S0_CONFIG(0); bfin_write_MDMA_D0_CONFIG(0); - if ((unsigned long)dest < memory_end) - blackfin_dcache_invalidate_range((unsigned int)dest, - (unsigned int)(dest + size)); local_irq_restore(flags); return dest; @@ -589,7 +592,8 @@ void dma_outsb(unsigned long addr, const void *buf, unsigned short len) local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + blackfin_dcache_flush_range((unsigned int)buf, + (unsigned int)(buf) + len); bfin_write_MDMA_D0_START_ADDR(addr); bfin_write_MDMA_D0_X_COUNT(len); @@ -604,6 +608,8 @@ void dma_outsb(unsigned long addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_8); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_8); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -620,6 +626,9 @@ void dma_insb(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); bfin_write_MDMA_D0_X_COUNT(len); @@ -634,7 +643,7 @@ void dma_insb(unsigned long addr, void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_8); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_8); - blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); @@ -653,7 +662,8 @@ void dma_outsw(unsigned long addr, const void *buf, unsigned short len) local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + blackfin_dcache_flush_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(short)); bfin_write_MDMA_D0_START_ADDR(addr); bfin_write_MDMA_D0_X_COUNT(len); @@ -668,6 +678,8 @@ void dma_outsw(unsigned long addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -683,6 +695,9 @@ void dma_insw(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(short)); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); @@ -698,7 +713,7 @@ void dma_insw(unsigned long addr, void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16); - blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); @@ -717,7 +732,8 @@ void dma_outsl(unsigned long addr, const void *buf, unsigned short len) local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + blackfin_dcache_flush_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(long)); bfin_write_MDMA_D0_START_ADDR(addr); bfin_write_MDMA_D0_X_COUNT(len); @@ -732,6 +748,8 @@ void dma_outsl(unsigned long addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_32); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_32); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -747,6 +765,9 @@ void dma_insl(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(long)); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); @@ -762,7 +783,7 @@ void dma_insl(unsigned long addr, void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_32); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_32); - blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); From b76f98761acc909c20c1e65c8af11dc1decae935 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 10 Oct 2007 17:25:15 +0800 Subject: [PATCH 0066/2804] Blackfin arch: show_mem can not be marked as init, since it is called during OOM condition show_mem can not be marked as init, since it is called during OOM condition from /mm/oom_kill.c:out_of_memory() and /mm/page_alloc.c:__alloc_pages() Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/mm/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c index 68459cc052a1..e97ea8fc8dc4 100644 --- a/arch/blackfin/mm/init.c +++ b/arch/blackfin/mm/init.c @@ -53,7 +53,7 @@ static unsigned long empty_bad_page; unsigned long empty_zero_page; -void __init show_mem(void) +void show_mem(void) { unsigned long i; int free = 0, total = 0, reserved = 0, shared = 0; From b3f8b9276314f4942ef9033aa5f4dc184901d640 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 10 Oct 2007 17:28:27 +0800 Subject: [PATCH 0067/2804] Blackfin arch: the load address is not safe to point to as a workaround for ANOMALY 05000281 Now that we have moved head.S into the init section, the load address is not safe to point to as a workaround for ANOMALY 05000281 Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/mach-common/entry.S | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index a56b231d94ce..e3ad5802868a 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -52,6 +52,15 @@ # define EX_SCRATCH_REG CYCLES #endif +#if ANOMALY_05000281 +ENTRY(_safe_speculative_execution) + NOP; + NOP; + NOP; + jump _safe_speculative_execution; +ENDPROC(_safe_speculative_execution) +#endif + #ifdef CONFIG_EXCPT_IRQ_SYSC_L1 .section .l1.text #else @@ -685,8 +694,8 @@ ENTRY(_return_from_int) [p0] = p1; csync; #if ANOMALY_05000281 - r0.l = lo(CONFIG_BOOT_LOAD); - r0.h = hi(CONFIG_BOOT_LOAD); + r0.l = _safe_speculative_execution; + r0.h = _safe_speculative_execution; reti = r0; #endif r0 = 0x801f (z); @@ -699,8 +708,8 @@ ENDPROC(_return_from_int) ENTRY(_lower_to_irq14) #if ANOMALY_05000281 - r0.l = lo(CONFIG_BOOT_LOAD); - r0.h = hi(CONFIG_BOOT_LOAD); + r0.l = _safe_speculative_execution; + r0.h = _safe_speculative_execution; reti = r0; #endif r0 = 0x401f; From ef4a47db52cd8c15b5de07a318e5758d2f1e1bb9 Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Wed, 10 Oct 2007 17:45:22 +0800 Subject: [PATCH 0068/2804] Blackfin arch: Export strcpy - occasionally get module link failures otherwise Signed-off-by: Bernd Schmidt Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_ksyms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c index 70455949cfd2..2198afe40f33 100644 --- a/arch/blackfin/kernel/bfin_ksyms.c +++ b/arch/blackfin/kernel/bfin_ksyms.c @@ -60,6 +60,7 @@ EXPORT_SYMBOL(csum_partial_copy); * their interface isn't gonna change any time soon now, so * it's OK to leave it out of version control. */ +EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcmp); From bc41bb11654f7fbb8cae2d316a7c2ac5ebf759d2 Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Wed, 10 Oct 2007 17:54:19 +0800 Subject: [PATCH 0069/2804] Blackfin arch: fix bug libstdc++ calling writev with an iovec containing { NULL, 0 } fails on Blackfin Fix a problem reported in the forums - libstdc++ can call writev with an iovec containing { NULL, 0 }, which works fine on i686-linux, but fails on Blackfin. Fixed by allowing size 0 transfers to/from userspace regardless of the address. Signed-off-by: Bernd Schmidt Signed-off-by: Bryan Wu --- arch/blackfin/kernel/process.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index de7d048bd4ee..9124467651c4 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -395,7 +395,8 @@ void finish_atomic_sections (struct pt_regs *regs) #if defined(CONFIG_ACCESS_CHECK) int _access_ok(unsigned long addr, unsigned long size) { - + if (size == 0) + return 1; if (addr > (addr + size)) return 0; if (segment_eq(get_fs(), KERNEL_DS)) From c3f2294f8cb161f568e244e283e1aa3eee397ef5 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 10 Oct 2007 17:54:46 +0800 Subject: [PATCH 0070/2804] Blackfin arch: trim the Blackfin arch MAINTAINERS list Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- MAINTAINERS | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9a91d9e3f1f2..0b7f7ddccdf6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -718,34 +718,8 @@ M: rpurdie@rpsys.net S: Maintained BLACKFIN ARCHITECTURE -P: Aubrey Li -M: aubrey.li@analog.com -P: Bernd Schmidt -M: bernd.schmidt@analog.com P: Bryan Wu M: bryan.wu@analog.com -P: Grace Pan -M: grace.pan@analog.com -P: Marc Hoffman -M: marc.hoffman@analog.com -P: Michael Hennerich -M: michael.hennerich@analog.com -P: Mike Frysinger -M: michael.frysinger@analog.com -P: Jerry Zeng -M: jerry.zeng@analog.com -P: Jie Zhang -M: jie.zhang@analog.com -P: Robin Getz -M: robin.getz@analog.com -P: Roy Huang -M: roy.huang@analog.com -P: Sonic Zhang -M: sonic.zhang@analog.com -P: Vivi Li -M: vivi.li@analog.com -P: Yi Li -M: yi.li@analog.com L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) W: http://blackfin.uclinux.org S: Supported From ddf416b2bce842105d29b170438fd1bc080456d0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 10 Oct 2007 18:06:47 +0800 Subject: [PATCH 0071/2804] Blackfin arch: fix typo in register name Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index cc789b988f3a..c35f549b54f1 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -829,7 +829,7 @@ config L1_MAX_PIECE comment "Asynchonous Memory Configuration" -menu "EBIU_AMBCTL Global Control" +menu "EBIU_AMGCTL Global Control" config C_AMCKEN bool "Enable CLKOUT" default y From 7417c8fe2e792b771b093c14e763816f154b62b4 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 10 Oct 2007 22:26:33 +0800 Subject: [PATCH 0072/2804] Blackfin arch: Remove cruft - CONFIG_DEBUG_SERIAL_EARLY_INIT and DEBUG_KERNEL_START Remove cruft - CONFIG_DEBUG_SERIAL_EARLY_INIT didn't work that well, and DEBUG_KERNEL_START was just implmented poorly. Will replace with a new checkin. Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index c35f549b54f1..b24f4535ffe0 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -1039,24 +1039,6 @@ config DEBUG_ICACHE_CHECK also relocates the irq_panic() function to L1 memory, (which is un-cached). -config DEBUG_KERNEL_START - bool "Debug Kernel Startup" - depends on DEBUG_KERNEL - help - Say Y here to put in an mini-execption handler before the kernel - replaces the bootloader exception handler. This will stop kernels - from dieing at startup with no visible error messages. - -config DEBUG_SERIAL_EARLY_INIT - bool "Initialize serial driver early" - default n - depends on SERIAL_BFIN - help - Say Y here if you want to get kernel output early when kernel - crashes before the normal console initialization. If this option - is enable, console output will always go to the ttyBF0, no matter - what kernel boot paramters you set. - config DEBUG_HUNT_FOR_ZERO bool "Catch NULL pointer reads/writes" default y From 85a75996edd0e49477cc7c9eb4bac33f02b07685 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 5 Aug 2007 19:16:05 +0800 Subject: [PATCH 0073/2804] blackfin enable arbitary speed serial setting Add the needed definitions to activate arbitary speed support on the blackfin platform. Signed-off-by: Alan Cox Acked-by: Aubrey Li Signed-off-by: Andrew Morton Signed-off-by: Bryan Wu --- include/asm-blackfin/ioctls.h | 9 +++++++-- include/asm-blackfin/termbits.h | 5 ++++- include/asm-blackfin/termios.h | 10 ++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/include/asm-blackfin/ioctls.h b/include/asm-blackfin/ioctls.h index 8356204151db..895e3173165d 100644 --- a/include/asm-blackfin/ioctls.h +++ b/include/asm-blackfin/ioctls.h @@ -47,8 +47,13 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#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) +/* Get Pty Number (of pty-mux device) */ +#define TIOCGPTN _IOR('T', 0x30, unsigned int) +#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIOCLEX 0x5451 diff --git a/include/asm-blackfin/termbits.h b/include/asm-blackfin/termbits.h index 4eac38de8ce1..f37feb7cf895 100644 --- a/include/asm-blackfin/termbits.h +++ b/include/asm-blackfin/termbits.h @@ -140,6 +140,7 @@ struct ktermios { #define HUPCL 0002000 #define CLOCAL 0004000 #define CBAUDEX 0010000 +#define BOTHER 0010000 #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 @@ -155,10 +156,12 @@ struct ktermios { #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 -#define CIBAUD 002003600000 /* input baud rate (not used) */ +#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 diff --git a/include/asm-blackfin/termios.h b/include/asm-blackfin/termios.h index 5c41478a51c6..e31fe859650b 100644 --- a/include/asm-blackfin/termios.h +++ b/include/asm-blackfin/termios.h @@ -98,8 +98,14 @@ struct termio { copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ }) -#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) -#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) +#define user_termios_to_kernel_termios(k, u) \ + copy_from_user(k, u, sizeof(struct termios2)) +#define kernel_termios_to_user_termios(u, k) \ + copy_to_user(u, k, sizeof(struct termios2)) +#define user_termios_to_kernel_termios_1(k, u) \ + copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios_1(u, k) \ + copy_to_user(u, k, sizeof(struct termios)) #endif /* __KERNEL__ */ From bbf275f092b1b2a9bc8a504500ec387f9ddff859 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 16:48:08 +0800 Subject: [PATCH 0074/2804] Blackfin serial driver: pending a unique anomaly id, tie the break flood issue to ANOMALY_05000230 pending a unique anomaly id, tie the break flood issue to ANOMALY_05000230 as when that was fixed, the fallout also fixed the break flood Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- drivers/serial/bfin_5xx.c | 43 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 3f39e1814693..6f475b609864 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -231,12 +231,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { struct tty_struct *tty = uart->port.info->tty; unsigned int status, ch, flg; + static int in_break = 0; #ifdef CONFIG_KGDB_UART struct pt_regs *regs = get_irq_regs(); #endif -#ifdef BF533_FAMILY - static int in_break = 0; -#endif status = UART_GET_LSR(uart); ch = UART_GET_CHAR(uart); @@ -262,29 +260,30 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) } } #endif - -#ifdef BF533_FAMILY - /* The BF533 family of processors have a nice misbehavior where - * they continuously generate characters for a "single" break. - * We have to basically ignore this flood until the "next" valid - * character comes across. All other Blackfin families operate - * properly though. - */ - if (in_break) { - if (ch != 0) { - in_break = 0; - ch = UART_GET_CHAR(uart); - if (bfin_revid() < 5) + + if (ANOMALY_05000230) { + /* The BF533 family of processors have a nice misbehavior where + * they continuously generate characters for a "single" break. + * We have to basically ignore this flood until the "next" valid + * character comes across. All other Blackfin families operate + * properly though. + * Note: While Anomaly 05000230 does not directly address this, + * the changes that went in for it also fixed this issue. + */ + if (in_break) { + if (ch != 0) { + in_break = 0; + ch = UART_GET_CHAR(uart); + if (bfin_revid() < 5) + return; + } else return; - } else - return; + } } -#endif if (status & BI) { -#ifdef BF533_FAMILY - in_break = 1; -#endif + if (ANOMALY_05000230) + in_break = 1; uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto ignore_char; From e5b9187b16993e4bb6799185e266f68e26663bee Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Thu, 26 Jul 2007 19:59:17 +1000 Subject: [PATCH 0075/2804] [POWERPC] Fix celleb pci section warnings Fix following warnings: WARNING: vmlinux.o(.text+0x44ad0): Section mismatch: reference to .init.text:.__alloc_bootmem (between '.celleb_setup_phb' and '.celleb_fake_pci_write_config') WARNING: vmlinux.o(.text+0x44dd8): Section mismatch: reference to .init.text:.free_bootmem (between '.celleb_setup_phb' and '.celleb_fake_pci_write_config') Signed-off-by: Kou Ishizaki Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/pci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c index e9ac19c4bba4..e0d97e02ef1f 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/celleb/pci.c @@ -288,8 +288,8 @@ static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, celleb_config_write_fake(config, PCI_COMMAND, 2, val); } -static int __devinit celleb_setup_fake_pci_device(struct device_node *node, - struct pci_controller *hose) +static int __init celleb_setup_fake_pci_device(struct device_node *node, + struct pci_controller *hose) { unsigned int rlen; int num_base_addr = 0; @@ -418,8 +418,8 @@ error: return 1; } -static int __devinit phb_set_bus_ranges(struct device_node *dev, - struct pci_controller *phb) +static int __init phb_set_bus_ranges(struct device_node *dev, + struct pci_controller *phb) { const int *bus_range; unsigned int len; @@ -434,7 +434,7 @@ static int __devinit phb_set_bus_ranges(struct device_node *dev, return 0; } -static void __devinit celleb_alloc_private_mem(struct pci_controller *hose) +static void __init celleb_alloc_private_mem(struct pci_controller *hose) { if (mem_init_done) hose->private_data = @@ -444,7 +444,7 @@ static void __devinit celleb_alloc_private_mem(struct pci_controller *hose) alloc_bootmem(sizeof(struct celleb_pci_private)); } -int __devinit celleb_setup_phb(struct pci_controller *phb) +int __init celleb_setup_phb(struct pci_controller *phb) { const char *name; struct device_node *dev = phb->arch_data; From b090b3388b6ea5d1003260daa0a997f4a1c4acc5 Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Thu, 26 Jul 2007 20:00:56 +1000 Subject: [PATCH 0076/2804] [POWERPC] Fix celleb sio section warning Fix following warning: WARNING: vmlinux.o(.text+0x45fd4): Section mismatch: reference to .init.text:.early_serial_txx9_setup (between '.txx9_serial_init' and '.txx9_serial_config') Signed-off-by: Kou Ishizaki Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/scc_sio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c index bcd25f54d986..d219b60a4a8c 100644 --- a/arch/powerpc/platforms/celleb/scc_sio.c +++ b/arch/powerpc/platforms/celleb/scc_sio.c @@ -39,7 +39,7 @@ static struct { { 0x800, 1 } /* 0xFF2800 */ }; -static int txx9_serial_init(void) +static int __init txx9_serial_init(void) { extern int early_serial_txx9_setup(struct uart_port *port); struct device_node *node; From a4ebd0174724193cbabf989352702ff37b1eb060 Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Thu, 26 Jul 2007 20:02:27 +1000 Subject: [PATCH 0077/2804] [POWERPC] Init markings for celleb There are some variables and functions that we should place in init section. And this patch changes some '__devinit' to '__init', because the device is platform device and not hot-pluggable. Signed-off-by: Kou Ishizaki Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/scc_epci.c | 4 ++-- arch/powerpc/platforms/celleb/scc_sio.c | 6 +++--- arch/powerpc/platforms/celleb/setup.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c index c4b011094bd6..881fd7d1806a 100644 --- a/arch/powerpc/platforms/celleb/scc_epci.c +++ b/arch/powerpc/platforms/celleb/scc_epci.c @@ -283,7 +283,7 @@ struct pci_ops celleb_epci_ops = { }; /* to be moved in FW */ -static int __devinit celleb_epci_init(struct pci_controller *hose) +static int __init celleb_epci_init(struct pci_controller *hose) { u32 val; volatile void __iomem *reg, *epci_base; @@ -403,7 +403,7 @@ static int __devinit celleb_epci_init(struct pci_controller *hose) return 0; } -int __devinit celleb_setup_epci(struct device_node *node, +int __init celleb_setup_epci(struct device_node *node, struct pci_controller *hose) { struct resource r; diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c index d219b60a4a8c..bb98735ac46f 100644 --- a/arch/powerpc/platforms/celleb/scc_sio.c +++ b/arch/powerpc/platforms/celleb/scc_sio.c @@ -28,12 +28,12 @@ /* sio irq0=0xb00010022 irq0=0xb00010023 irq2=0xb00010024 mmio=0xfff000-0x1000,0xff2000-0x1000 */ -static int txx9_serial_bitmap = 0; +static int txx9_serial_bitmap __initdata = 0; static struct { uint32_t offset; uint32_t index; -} txx9_scc_tab[3] = { +} txx9_scc_tab[3] __initdata = { { 0x300, 0 }, /* 0xFFF300 */ { 0x400, 0 }, /* 0xFFF400 */ { 0x800, 1 } /* 0xFF2800 */ @@ -79,7 +79,7 @@ static int __init txx9_serial_init(void) return 0; } -static int txx9_serial_config(char *ptr) +static int __init txx9_serial_config(char *ptr) { int i; diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c index 5e9f7f163571..1fca3f23533b 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/celleb/setup.c @@ -73,7 +73,7 @@ static void celleb_show_cpuinfo(struct seq_file *m) of_node_put(root); } -static int celleb_machine_type_hack(char *ptr) +static int __init celleb_machine_type_hack(char *ptr) { strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type)); celleb_machine_type[sizeof(celleb_machine_type)-1] = 0; @@ -135,7 +135,7 @@ static void celleb_kexec_cpu_down(int crash, int secondary) } #endif -static struct of_device_id celleb_bus_ids[] = { +static struct of_device_id celleb_bus_ids[] __initdata = { { .type = "scc", }, { .type = "ioif", }, /* old style */ {}, From 301d9cb80b4f64ba24d4b141ad3ca58165a29afb Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Thu, 26 Jul 2007 20:06:08 +1000 Subject: [PATCH 0078/2804] [POWERPC] Init markings for hvc_beat Fix warnings about section mismatch. Signed-off-by: Kou Ishizaki Signed-off-by: Paul Mackerras --- drivers/char/hvc_beat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c index 6f019f19be71..e74bb949c289 100644 --- a/drivers/char/hvc_beat.c +++ b/drivers/char/hvc_beat.c @@ -97,7 +97,7 @@ static int hvc_beat_config(char *p) return 0; } -static int hvc_beat_console_init(void) +static int __init hvc_beat_console_init(void) { if (hvc_beat_useit && machine_is_compatible("Beat")) { hvc_instantiate(0, 0, &hvc_beat_get_put_ops); @@ -106,7 +106,7 @@ static int hvc_beat_console_init(void) } /* temp */ -static int hvc_beat_init(void) +static int __init hvc_beat_init(void) { struct hvc_struct *hp; From 12588da7cb57edc25355c8ae2a245f66d0d067d1 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 27 Jul 2007 08:30:26 +1000 Subject: [PATCH 0079/2804] [POWERPC] EEH: Tweak printk message Print return code to print message. Also fix whitespace. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/eeh.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index b8770395013d..34f87682e092 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -750,12 +750,12 @@ int rtas_set_slot_reset(struct pci_dn *pdn) return 0; if (rc < 0) { - printk (KERN_ERR "EEH: unrecoverable slot failure %s\n", - pdn->node->full_name); + printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", + pdn->node->full_name); return -1; } - printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n", - i+1, pdn->node->full_name); + printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", + i+1, pdn->node->full_name, rc); } return -1; From 093eda3ce5dc3758c9a5e806ea6573bfffed3ff7 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 27 Jul 2007 08:33:58 +1000 Subject: [PATCH 0080/2804] [POWERPC] EEH: Fix PCI bridge handling bug The EEH code needs to ignore PCI bridges; sort-of. It was ignoring them in the wrong place, and thus failing to set up the PCI_DN(dn)->pcidev pointer. Imprudent dereferencing of this pointer would lead to a crash on cards with bridges. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/eeh_cache.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh_cache.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index e49c815eae23..1e83fcd0df31 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -225,6 +225,10 @@ void pci_addr_cache_insert_device(struct pci_dev *dev) { unsigned long flags; + /* Ignore PCI bridges */ + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) + return; + spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); __pci_addr_cache_insert_device(dev); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); @@ -285,16 +289,13 @@ void __init pci_addr_cache_build(void) spin_lock_init(&pci_io_addr_cache_root.piar_lock); while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - /* Ignore PCI bridges */ - if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) - continue; pci_addr_cache_insert_device(dev); dn = pci_device_to_OF_node(dev); if (!dn) continue; - pci_dev_get (dev); /* matching put is in eeh_remove_device() */ + pci_dev_get(dev); /* matching put is in eeh_remove_device() */ PCI_DN(dn)->pcidev = dev; eeh_sysfs_add_device(dev); From 0b9369f4934eb9933a1fbe991c5e8a4f9725da37 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 27 Jul 2007 08:35:40 +1000 Subject: [PATCH 0081/2804] [POWERPC] EEH: Dump PCI bridge status on event Gather bridge-specific data on EEH events. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/eeh.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 34f87682e092..41b64b370fc6 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -169,6 +169,8 @@ static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, */ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) { + struct device_node *dn; + struct pci_dev *dev = pdn->pcidev; u32 cfg; int cap, i; int n = 0; @@ -184,6 +186,17 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); + /* Gather bridge-specific registers */ + if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { + rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); + n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); + printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); + + rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); + n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); + printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); + } + /* Dump out the PCI-X command and status regs */ cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_PCIX); if (cap) { @@ -209,7 +222,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); } - cap = pci_find_ext_capability(pdn->pcidev,PCI_EXT_CAP_ID_ERR); + cap = pci_find_ext_capability(pdn->pcidev, PCI_EXT_CAP_ID_ERR); if (cap) { n += scnprintf(buf+n, len-n, "pci-e AER:\n"); printk(KERN_WARNING @@ -222,6 +235,18 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) } } } + + /* Gather status on devices under the bridge */ + if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { + dn = pdn->node->child; + while (dn) { + pdn = PCI_DN(dn); + if (pdn) + n += gather_pci_data(pdn, buf+n, len-n); + dn = dn->sibling; + } + } + return n; } From 7888fbf7bbf8840e83078eae3a537fd1cde46e6e Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 28 Jul 2007 04:24:52 +1000 Subject: [PATCH 0082/2804] [POWERPC] 52xx: Remove unnecessary loops_per_jiffy initialization code Signed-off-by: Jon Loeliger Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/52xx/lite5200.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 5c46e898fd45..84bd3da43afd 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -109,22 +109,13 @@ static void lite5200_resume_finish(void __iomem *mbar) static void __init lite5200_setup_arch(void) { +#ifdef CONFIG_PCI struct device_node *np; +#endif if (ppc_md.progress) ppc_md.progress("lite5200_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np) { - const unsigned int *fp = - of_get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } - /* CPU & Port mux setup */ mpc52xx_setup_cpu(); /* Generic */ lite5200_setup_cpu(); /* Platorm specific */ From c3ca32fdb820d59e63c95115ec5caf2862c85040 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 28 Jul 2007 04:24:59 +1000 Subject: [PATCH 0083/2804] [POWERPC] 8xx: Remove unnecessary loops_per_jiffy initialization code Signed-off-by: Jon Loeliger Acked-by: Vitaly Bordug Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/8xx/mpc86xads_setup.c | 14 -------------- arch/powerpc/platforms/8xx/mpc885ads_setup.c | 14 -------------- 2 files changed, 28 deletions(-) diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c index cf0e7bc8c2e7..d881647e9923 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -254,20 +254,6 @@ int platform_device_skip(const char *model, int id) static void __init mpc86xads_setup_arch(void) { - struct device_node *cpu; - - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } - cpm_reset(); mpc86xads_board_setup(); diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index 5a808d611ae3..bd5ff7a892e0 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -406,20 +406,6 @@ int platform_device_skip(const char *model, int id) static void __init mpc885ads_setup_arch(void) { - struct device_node *cpu; - - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } - cpm_reset(); mpc885ads_board_setup(); From 2a4a9fbf26b109a748a336560ae3155c54f89de8 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 28 Jul 2007 04:25:09 +1000 Subject: [PATCH 0084/2804] [POWERPC] embedded6xx: Remove unnecessary loops_per_jiffy initialization code Signed-off-by: Jon Loeliger Acked-by: Mark A. Greer Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/embedded6xx/holly.c | 12 ------------ arch/powerpc/platforms/embedded6xx/prpmc2800.c | 7 ------- 2 files changed, 19 deletions(-) diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 6292e36dc577..76620913a9dc 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -113,23 +113,11 @@ static void holly_remap_bridge(void) static void __init holly_setup_arch(void) { - struct device_node *cpu; struct device_node *np; if (ppc_md.progress) ppc_md.progress("holly_setup_arch():set_bridge", 0); - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } tsi108_csr_vir_base = get_vir_csrbase(); /* setup PCI host bridge */ diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c index 53420951dc53..54675648d6de 100644 --- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c +++ b/arch/powerpc/platforms/embedded6xx/prpmc2800.c @@ -44,7 +44,6 @@ static void __init prpmc2800_setup_arch(void) struct device_node *np; phys_addr_t paddr; const unsigned int *reg; - const unsigned int *prop; /* * ioremap mpp and gpp registers in case they are later @@ -62,12 +61,6 @@ static void __init prpmc2800_setup_arch(void) of_node_put(np); mv64x60_gpp_reg_base = ioremap(paddr, reg[1]); - np = of_find_node_by_type(NULL, "cpu"); - prop = of_get_property(np, "clock-frequency", NULL); - if (prop) - loops_per_jiffy = *prop / HZ; - of_node_put(np); - #ifdef CONFIG_PCI mv64x60_pci_init(); #endif From 9420dc65ff9e6b67c032286efde823aeb8684670 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 30 Jul 2007 08:18:25 +1000 Subject: [PATCH 0085/2804] [POWERPC] Clean out a bunch of duplicate includes This removes several duplicate includes from arch/powerpc/. Signed-off-by: Jesper Juhl Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/btext.c | 1 - arch/powerpc/kernel/crash.c | 1 - arch/powerpc/kernel/iommu.c | 1 - arch/powerpc/kernel/prom.c | 1 - arch/powerpc/kernel/time.c | 1 - arch/powerpc/mm/hash_utils_64.c | 1 - arch/powerpc/mm/hugetlbpage.c | 3 --- arch/powerpc/mm/init_32.c | 1 - arch/powerpc/mm/mem.c | 1 - arch/powerpc/platforms/52xx/mpc52xx_pic.c | 1 - arch/powerpc/platforms/chrp/setup.c | 1 - arch/powerpc/platforms/chrp/smp.c | 1 - arch/powerpc/platforms/iseries/setup.c | 1 - arch/powerpc/platforms/powermac/low_i2c.c | 1 - arch/powerpc/platforms/powermac/udbg_adb.c | 1 - arch/powerpc/platforms/pseries/lpar.c | 1 - 16 files changed, 18 deletions(-) diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index e7b684689e04..3ef51fb6f107 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 37658ea417fa..77c749a13378 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index c08ceca6277d..e4ec6eee81a8 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index a38197b12d3e..0028fe68e09e 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -52,7 +52,6 @@ #include #include #include -#include #ifdef DEBUG #define DBG(fmt...) printk(KERN_ERR fmt) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 727a6699f2f4..c85d9b0d9042 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -72,7 +72,6 @@ #include #include #endif -#include /* keep track of when we need to update the rtc */ time_t last_rtc_update; diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index a47151e806ca..c74af42eb9c1 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 4835f73af304..ba5f12a60467 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -22,11 +22,8 @@ #include #include #include -#include #include -#include - #define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT) #define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT) diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index e1f5ded851f6..d65995ae8273 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index f0e7eedb1ba3..32dcfc9b0082 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index fbfff95b4437..8c464c55b5d0 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 373de4c063db..dde5ef4dde35 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index 3ea0eb78568e..a137d13008bc 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 13a8b1908ded..fad493e29d37 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index efdf5eb81ecc..da2007e3db0e 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c index 6124e59e1038..b1882e40525a 100644 --- a/arch/powerpc/platforms/powermac/udbg_adb.c +++ b/arch/powerpc/platforms/powermac/udbg_adb.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 8cc6eeeaae2f..ea327ca345c6 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include From 0d279d47612d1b63155a1d9637a6fc5143dad594 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 30 Jul 2007 15:55:02 +1000 Subject: [PATCH 0086/2804] [POWERPC] Fixes to allow use of Ebony's flash chips through physmap_of This patch contains a handful of small fixes to allow the Ebony's flash to be exposed as MTD devices via the physmap_of driver. Specifically it: - Makes a small addition to the device tree and zImage wrapper to record the correct address for the flash in the device tree based on the board switches as reported via an FPGA register. - Prohibits building the old hard-coded "Ebony" flash map on arch/powerpc kernels, in favour of using physmap_of's device tree based approach. - Enables MTD and physmap_of in the Ebony defconfig. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/dts/ebony.dts | 1 + arch/powerpc/boot/ebony.c | 39 ++++ arch/powerpc/configs/ebony_defconfig | 258 +++++++++++++-------------- drivers/mtd/maps/Kconfig | 2 +- 4 files changed, 168 insertions(+), 132 deletions(-) diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts index c5f99613fc7b..27a1463b6ab0 100644 --- a/arch/powerpc/boot/dts/ebony.dts +++ b/arch/powerpc/boot/dts/ebony.dts @@ -175,6 +175,7 @@ fpga@7,0 { compatible = "Ebony-FPGA"; reg = <7 0 10>; + virtual-reg = ; }; }; diff --git a/arch/powerpc/boot/ebony.c b/arch/powerpc/boot/ebony.c index 75daedafd0a4..eaf0b9bb68d6 100644 --- a/arch/powerpc/boot/ebony.c +++ b/arch/powerpc/boot/ebony.c @@ -24,6 +24,7 @@ #include "page.h" #include "ops.h" #include "reg.h" +#include "io.h" #include "dcr.h" #include "44x.h" @@ -92,6 +93,43 @@ void ibm440gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) dt_fixup_clock("/plb/opb/serial@40000300", uart1); } +#define EBONY_FPGA_PATH "/plb/opb/ebc/fpga" +#define EBONY_FPGA_FLASH_SEL 0x01 +#define EBONY_SMALL_FLASH_PATH "/plb/opb/ebc/small-flash" + +static void ebony_flashsel_fixup(void) +{ + void *devp; + u32 reg[3] = {0x0, 0x0, 0x80000}; + u8 *fpga; + u8 fpga_reg0 = 0x0; + + devp = finddevice(EBONY_FPGA_PATH); + if (!devp) + fatal("Couldn't locate FPGA node %s\n\r", EBONY_FPGA_PATH); + + if (getprop(devp, "virtual-reg", &fpga, sizeof(fpga)) != sizeof(fpga)) + fatal("%s has missing or invalid virtual-reg property\n\r", + EBONY_FPGA_PATH); + + fpga_reg0 = in_8(fpga); + + devp = finddevice(EBONY_SMALL_FLASH_PATH); + if (!devp) + fatal("Couldn't locate small flash node %s\n\r", + EBONY_SMALL_FLASH_PATH); + + if (getprop(devp, "reg", reg, sizeof(reg)) != sizeof(reg)) + fatal("%s has reg property of unexpected size\n\r", + EBONY_SMALL_FLASH_PATH); + + /* Invert address bit 14 (IBM-endian) if FLASH_SEL fpga bit is set */ + if (fpga_reg0 & EBONY_FPGA_FLASH_SEL) + reg[1] ^= 0x80000; + + setprop(devp, "reg", reg, sizeof(reg)); +} + static void ebony_fixups(void) { // FIXME: sysclk should be derived by reading the FPGA registers @@ -101,6 +139,7 @@ static void ebony_fixups(void) ibm44x_fixup_memsize(); dt_fixup_mac_addresses(ebony_mac0, ebony_mac1); ibm4xx_fixup_ebc_ranges("/plb/opb/ebc"); + ebony_flashsel_fixup(); } void ebony_init(void *mac0, void *mac1) diff --git a/arch/powerpc/configs/ebony_defconfig b/arch/powerpc/configs/ebony_defconfig index 5762cddfc148..d8dc7e63aab5 100644 --- a/arch/powerpc/configs/ebony_defconfig +++ b/arch/powerpc/configs/ebony_defconfig @@ -1,9 +1,25 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.22-rc6 -# Tue Jun 26 12:38:33 2007 +# Linux kernel version: 2.6.23-rc1-powerpc-ebony-mtd +# Mon Jul 30 15:47:59 2007 # # CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +CONFIG_44x=y +# CONFIG_E200 is not set +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y CONFIG_PPC32=y CONFIG_PPC_MERGE=y CONFIG_MMU=y @@ -14,39 +30,22 @@ CONFIG_ARCH_HAS_ILOG2_U32=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set CONFIG_PPC=y CONFIG_EARLY_PRINTK=y CONFIG_GENERIC_NVRAM=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_PPC_OF=y +CONFIG_OF=y # CONFIG_PPC_UDBG_16550 is not set # CONFIG_GENERIC_TBSYNC is not set CONFIG_AUDIT_ARCH=y CONFIG_GENERIC_BUG=y # CONFIG_DEFAULT_UIMAGE is not set - -# -# Processor support -# -# CONFIG_CLASSIC32 is not set -# CONFIG_PPC_82xx is not set -# CONFIG_PPC_83xx is not set -# CONFIG_PPC_85xx is not set -# CONFIG_PPC_86xx is not set -# CONFIG_PPC_8xx is not set -# CONFIG_40x is not set -CONFIG_44x=y -# CONFIG_E200 is not set CONFIG_PPC_DCR_NATIVE=y # CONFIG_PPC_DCR_MMIO is not set CONFIG_PPC_DCR=y -CONFIG_4xx=y -CONFIG_BOOKE=y -CONFIG_PTE_64BIT=y -CONFIG_PHYS_64BIT=y -# CONFIG_PPC_MM_SLICES is not set -CONFIG_NOT_COHERENT_CACHE=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -63,12 +62,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 @@ -102,24 +100,17 @@ CONFIG_SLAB=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y - -# -# Block layer -# CONFIG_BLOCK=y CONFIG_LBD=y # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -184,6 +175,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set CONFIG_SECCOMP=y @@ -196,9 +189,9 @@ CONFIG_ISA_DMA_API=y # CONFIG_ZONE_DMA=y CONFIG_PPC_INDIRECT_PCI=y -# CONFIG_PPC_INDIRECT_PCI_BE is not set CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y # CONFIG_PCIEPORTBUS is not set CONFIG_ARCH_SUPPORTS_MSI=y # CONFIG_PCI_MSI is not set @@ -306,6 +299,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set # CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -320,27 +314,85 @@ CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# CONFIG_CONNECTOR=y CONFIG_PROC_EVENTS=y -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set # -# Parallel port support +# User Modules And Translation Layers # +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_DEVICE=y # CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# +CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set @@ -356,14 +408,12 @@ CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set - -# -# Misc devices -# +# CONFIG_XILINX_SYSACE is not set +CONFIG_MISC_DEVICES=y # CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set # CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set -# CONFIG_BLINK is not set # CONFIG_IDE is not set # @@ -371,12 +421,9 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set # CONFIG_SCSI_NETLINK is not set # CONFIG_ATA is not set - -# -# Multi-device support (RAID and LVM) -# # CONFIG_MD is not set # @@ -389,35 +436,17 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_FIREWIRE is not set # CONFIG_IEEE1394 is not set - -# -# I2O device support -# # CONFIG_I2O is not set # CONFIG_MACINTOSH_DRIVERS is not set - -# -# Network device support -# CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ARCNET is not set - -# -# Ethernet (10 or 100Mbit) -# # CONFIG_NET_ETHERNET is not set -CONFIG_IBM_EMAC=y -CONFIG_IBM_EMAC_RXB=128 -CONFIG_IBM_EMAC_TXB=64 -CONFIG_IBM_EMAC_POLL_WEIGHT=32 -CONFIG_IBM_EMAC_RX_COPY_THRESHOLD=256 -CONFIG_IBM_EMAC_RX_SKB_HEADROOM=0 -# CONFIG_IBM_EMAC_DEBUG is not set -CONFIG_IBM_EMAC_ZMII=y CONFIG_NETDEV_1000=y # CONFIG_ACENIC is not set # CONFIG_DL2K is not set @@ -429,7 +458,6 @@ CONFIG_NETDEV_1000=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set -# CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set @@ -459,15 +487,7 @@ CONFIG_NETDEV_10000=y # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# # CONFIG_ISDN is not set - -# -# Telephony Support -# # CONFIG_PHONE is not set # @@ -512,10 +532,6 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set # CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set @@ -526,10 +542,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_AGP is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y # CONFIG_I2C is not set @@ -539,11 +551,8 @@ CONFIG_DEVPORT=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# # CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set # @@ -568,6 +577,7 @@ CONFIG_DEVPORT=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set # CONFIG_FB is not set # CONFIG_FB_IBM_GXT4500 is not set @@ -575,10 +585,7 @@ CONFIG_DEVPORT=y # Sound # # CONFIG_SOUND is not set - -# -# USB support -# +CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y @@ -593,28 +600,9 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# # CONFIG_INFINIBAND is not set - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# +# CONFIG_EDAC is not set # # Real Time Clock @@ -634,6 +622,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y # DMA Devices # +# +# Userspace I/O +# +# CONFIG_UIO is not set + # # File systems # @@ -694,6 +687,15 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -723,7 +725,6 @@ CONFIG_SUNRPC=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set # # Partition Types @@ -750,8 +751,10 @@ CONFIG_BITREVERSE=y # CONFIG_CRC16 is not set # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y @@ -774,6 +777,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SHIRQ is not set CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set # CONFIG_DEBUG_SLAB is not set @@ -796,7 +800,6 @@ CONFIG_FORCED_INLINING=y # CONFIG_DEBUG_PAGEALLOC is not set # CONFIG_DEBUGGER is not set # CONFIG_BDI_SWITCH is not set -# CONFIG_BOOTX_TEXT is not set # CONFIG_PPC_EARLY_DEBUG is not set # @@ -804,10 +807,6 @@ CONFIG_FORCED_INLINING=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_BLKCIPHER=y @@ -845,7 +844,4 @@ CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_CAMELLIA is not set # CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# +CONFIG_CRYPTO_HW=y diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index cc6c73442435..6cd132c75187 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -362,7 +362,7 @@ config MTD_WALNUT config MTD_EBONY tristate "Flash devices mapped on IBM 440GP Ebony" - depends on MTD_JEDECPROBE && EBONY + depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE help This enables access routines for the flash chips on the IBM 440GP Ebony board. If you have one of these boards and would like to From cc61f957f486871536cc5531e83337fff4fe48f3 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 1 Aug 2007 08:10:03 +1000 Subject: [PATCH 0087/2804] [POWERPC] drivers/macintosh/therm_adt746x.c: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Signed-off-by: Paul Mackerras --- drivers/macintosh/therm_adt746x.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index f25685b9b7cf..276945d51513 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -379,13 +379,10 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, if (thermostat) return 0; - th = (struct thermostat *) - kmalloc(sizeof(struct thermostat), GFP_KERNEL); - + th = kzalloc(sizeof(struct thermostat), GFP_KERNEL); if (!th) return -ENOMEM; - memset(th, 0, sizeof(*th)); th->clt.addr = addr; th->clt.adapter = adapter; th->clt.driver = &thermostat_driver; From 33567a023e734b640c27fc9cc4e7c6b45987b083 Mon Sep 17 00:00:00 2001 From: Gabriel C Date: Wed, 1 Aug 2007 19:41:09 +1000 Subject: [PATCH 0088/2804] [POWERPC] Typo fixes interrrupt -> interrupt This fixes some interrrupt -> interrupt typos. Signed-off-by: Gabriel Craciunescu Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/embedded6xx/holly.c | 2 +- arch/powerpc/platforms/embedded6xx/linkstation.c | 2 +- arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 2 +- arch/powerpc/platforms/iseries/it_lp_naca.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 76620913a9dc..b6de2b5223dd 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -135,7 +135,7 @@ static void __init holly_setup_arch(void) } /* - * Interrupt setup and service. Interrrupts on the holly come + * Interrupt setup and service. Interrupts on the holly come * from the four external INT pins, PCI interrupts are routed via * PCI interrupt control registers, it generates internal IRQ23 * diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index bd5ca58345a1..8c60e0207d02 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -99,7 +99,7 @@ static void __init linkstation_setup_arch(void) } /* - * Interrupt setup and service. Interrrupts on the linkstation come + * Interrupt setup and service. Interrupts on the linkstation come * from the four PCI slots plus onboard 8241 devices: I2C, DUART. */ static void __init linkstation_init_IRQ(void) diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 1e3cc69487b5..25c29bc94988 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -91,7 +91,7 @@ static void __init mpc7448_hpc2_setup_arch(void) } /* - * Interrupt setup and service. Interrrupts on the mpc7448_hpc2 come + * Interrupt setup and service. Interrupts on the mpc7448_hpc2 come * from the four external INT pins, PCI interrupts are routed via * PCI interrupt control registers, it generates internal IRQ23 * diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h index 9bbf58986819..cf6dcf6ef07b 100644 --- a/arch/powerpc/platforms/iseries/it_lp_naca.h +++ b/arch/powerpc/platforms/iseries/it_lp_naca.h @@ -60,7 +60,7 @@ struct ItLpNaca { u8 xRsvd2_0[128]; // Reserved x00-x7F // CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators -// NB: Padding required to keep xInterrruptHdlr at x300 which is required +// NB: Padding required to keep xInterruptHdlr at x300 which is required // for v4r4 PLIC. u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F u8 xRsvd3_0[384]; // Reserved 180-2FF From c05129bd8190fd702426f93f9fe0a00fa6cacb31 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 1 Aug 2007 23:53:28 +1000 Subject: [PATCH 0089/2804] [POWERPC] Only ignore arch/ppc/include, not arch/ppc/boot/include arch/ppc/.gitignore shouldn't exclude arch/ppc/boot/include, so this makes arch/ppc/.gitignore more specific. Signed-off-by: Paul Mackerras --- arch/ppc/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/.gitignore b/arch/ppc/.gitignore index a1a869c8c840..1e79a0ae4473 100644 --- a/arch/ppc/.gitignore +++ b/arch/ppc/.gitignore @@ -1 +1 @@ -include +/include From f774216d465959a4777ac3de67f33bf75ecd4a76 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Thu, 2 Aug 2007 01:41:15 +1000 Subject: [PATCH 0090/2804] [POWERPC] Replace a few #defines with empty inline functions ...so that GCC doesn't complain about unused variables in the callers of these. Signed-off-by: Segher Boessenkool Signed-off-by: Paul Mackerras --- include/asm-powerpc/dma-mapping.h | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h index 744d6bb24116..d05891608f74 100644 --- a/include/asm-powerpc/dma-mapping.h +++ b/include/asm-powerpc/dma-mapping.h @@ -249,8 +249,12 @@ dma_map_single(struct device *dev, void *ptr, size_t size, return virt_to_bus(ptr); } -/* We do nothing. */ -#define dma_unmap_single(dev, addr, size, dir) ((void)0) +static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction) +{ + /* We do nothing. */ +} static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, @@ -264,8 +268,12 @@ dma_map_page(struct device *dev, struct page *page, return page_to_bus(page) + offset; } -/* We do nothing. */ -#define dma_unmap_page(dev, handle, size, dir) ((void)0) +static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, + enum dma_data_direction direction) +{ + /* We do nothing. */ +} static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, @@ -284,8 +292,12 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, return nents; } -/* We don't do anything here. */ -#define dma_unmap_sg(dev, sg, nents, dir) ((void)0) +static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nhwentries, + enum dma_data_direction direction) +{ + /* We don't do anything here. */ +} #endif /* CONFIG_PPC64 */ From a4fc3a3cead7f9e00dc0f6e00238b11c030f94cc Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 10 Aug 2007 07:01:50 +1000 Subject: [PATCH 0091/2804] [POWERPC] pseries: Avoid excess rtas_token calls We don't need to look up the rtas event token once per cpu per second. This avoids some misc device-tree lookups and string ops and so provides some minor performance improvement. Signed-off-by: Linas Vepstas ---- Revised commit-log message. arch/powerpc/platforms/pseries/rtasd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/rtasd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 9797b10b2935..762fe87629ff 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -44,10 +44,13 @@ static unsigned long rtas_log_start; static unsigned long rtas_log_size; static int surveillance_timeout = -1; -static unsigned int rtas_event_scan_rate; static unsigned int rtas_error_log_max; static unsigned int rtas_error_log_buffer_max; +/* RTAS service tokens */ +static unsigned int event_scan; +static unsigned int rtas_event_scan_rate; + static int full_rtas_msgs = 0; extern int no_logging; @@ -381,7 +384,7 @@ static int get_eventscan_parms(void) return 0; } -static void do_event_scan(int event_scan) +static void do_event_scan(void) { int error; do { @@ -408,7 +411,7 @@ static void do_event_scan_all_cpus(long delay) cpu = first_cpu(cpu_online_map); for (;;) { set_cpus_allowed(current, cpumask_of_cpu(cpu)); - do_event_scan(rtas_token("event-scan")); + do_event_scan(); set_cpus_allowed(current, CPU_MASK_ALL); /* Drop hotplug lock, and sleep for the specified delay */ @@ -426,12 +429,11 @@ static void do_event_scan_all_cpus(long delay) static int rtasd(void *unused) { unsigned int err_type; - int event_scan = rtas_token("event-scan"); int rc; daemonize("rtasd"); - if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1) + if (get_eventscan_parms() == -1) goto error; rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); @@ -486,7 +488,8 @@ static int __init rtas_init(void) return 0; /* No RTAS */ - if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { + event_scan = rtas_token("event-scan"); + if (event_scan == RTAS_UNKNOWN_SERVICE) { printk(KERN_DEBUG "rtasd: no event-scan on system\n"); return -ENODEV; } From ba28cc09316510aacb17f8421fdaae37969a4d5b Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 9 Aug 2007 06:02:10 +1000 Subject: [PATCH 0092/2804] [POWERPC] pseries: Use rtas_token instead of hand-rolled code The rtas_token() call does the same thing as this hand-rolled code. This makes the code easier to read. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/rtasd.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/rtasd.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 762fe87629ff..48e6dc0ae15a 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -361,26 +361,17 @@ static int enable_surveillance(int timeout) static int get_eventscan_parms(void) { - struct device_node *node; - const int *ip; - - node = of_find_node_by_path("/rtas"); - - ip = of_get_property(node, "rtas-event-scan-rate", NULL); - if (ip == NULL) { + rtas_event_scan_rate = rtas_token("rtas-event-scan-rate"); + if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) { printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n"); - of_node_put(node); return -1; } - rtas_event_scan_rate = *ip; DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate); /* Make room for the sequence number */ rtas_error_log_max = rtas_get_error_log_max(); rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); - of_node_put(node); - return 0; } From 4511dad42a8da41fc2f5a58066c519c2228896ac Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 9 Aug 2007 06:03:37 +1000 Subject: [PATCH 0093/2804] [POWERPC] pseries: Simplify rtasd initialization Simplify rtasd initialization code; this also fixes a buglet, where the /proc entries weren't being cleaned up in case of failure. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/rtasd.c | 53 +++++++++++---------------------- 1 file changed, 19 insertions(+), 34 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/rtasd.c | 53 +++++++++----------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 48e6dc0ae15a..d902097646b7 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -64,8 +64,6 @@ volatile int error_log_cnt = 0; */ static unsigned char logdata[RTAS_ERROR_LOG_MAX]; -static int get_eventscan_parms(void); - static char *rtas_type[] = { "Unknown", "Retry", "TCE Error", "Internal Device Failure", "Timeout", "Data Parity", "Address Parity", "Cache Parity", @@ -169,9 +167,9 @@ static int log_rtas_len(char * buf) len += err->extended_log_length; } - if (rtas_error_log_max == 0) { - get_eventscan_parms(); - } + if (rtas_error_log_max == 0) + rtas_error_log_max = rtas_get_error_log_max(); + if (len > rtas_error_log_max) len = rtas_error_log_max; @@ -359,22 +357,6 @@ static int enable_surveillance(int timeout) return -1; } -static int get_eventscan_parms(void) -{ - rtas_event_scan_rate = rtas_token("rtas-event-scan-rate"); - if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) { - printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n"); - return -1; - } - DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate); - - /* Make room for the sequence number */ - rtas_error_log_max = rtas_get_error_log_max(); - rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); - - return 0; -} - static void do_event_scan(void) { int error; @@ -424,22 +406,11 @@ static int rtasd(void *unused) daemonize("rtasd"); - if (get_eventscan_parms() == -1) - goto error; - - rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); - if (!rtas_log_buf) { - printk(KERN_ERR "rtasd: no memory\n"); - goto error; - } - printk(KERN_DEBUG "RTAS daemon started\n"); - DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); /* See if we have any error stored in NVRAM */ memset(logdata, 0, rtas_error_log_max); - rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type); /* We can use rtas_log_buf now */ @@ -466,8 +437,6 @@ static int rtasd(void *unused) for (;;) do_event_scan_all_cpus(30000/rtas_event_scan_rate); -error: - /* Should delete proc entries */ return -EINVAL; } @@ -485,6 +454,22 @@ static int __init rtas_init(void) return -ENODEV; } + rtas_event_scan_rate = rtas_token("rtas-event-scan-rate"); + if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) { + printk(KERN_ERR "rtasd: no rtas-event-scan-rate on system\n"); + return -ENODEV; + } + + /* Make room for the sequence number */ + rtas_error_log_max = rtas_get_error_log_max(); + rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); + + rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); + if (!rtas_log_buf) { + printk(KERN_ERR "rtasd: no memory\n"); + return -ENOMEM; + } + entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL); if (entry) entry->proc_fops = &proc_rtas_log_operations; From 72755f44075d34cdb9bc467c6cd9a229292b5aff Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 9 Aug 2007 06:04:48 +1000 Subject: [PATCH 0094/2804] [POWERPC] Remove nvram forward declarations Forward declarations serve no purpose in this file. Signed-off-by: Linas Vepstas ---- arch/powerpc/kernel/nvram_64.c | 5 ----- 1 file changed, 5 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/nvram_64.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index f9676f52c6d8..ba979908d17d 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -34,11 +34,6 @@ #undef DEBUG_NVRAM -static int nvram_scan_partitions(void); -static int nvram_setup_partition(void); -static int nvram_create_os_partition(void); -static int nvram_remove_os_partition(void); - static struct nvram_partition * nvram_part; static long nvram_error_log_index = -1; static long nvram_error_log_size = 0; From 79c0108d1b9db4864ab77b2a95dfa04f2dcf264c Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 9 Aug 2007 06:06:15 +1000 Subject: [PATCH 0095/2804] [POWERPC] pseries: Fix jumbled no_logging flag Get rid of the jumbled usage of the no_logging flag. Its use spans several directories, and is incorrectly/misleadingly documented. Instead, two changes: 1) nvram will accept error log as soon as its ready. 2) logging to nvram stops on the first fatal error reported. Signed-off-by: Linas Vepstas ---- arch/powerpc/kernel/nvram_64.c | 8 -------- arch/powerpc/platforms/pseries/rtasd.c | 14 ++++++-------- 2 files changed, 6 insertions(+), 16 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/nvram_64.c | 8 -------- arch/powerpc/platforms/pseries/rtasd.c | 14 ++++++-------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index ba979908d17d..4a4d785a08d3 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -38,10 +38,6 @@ static struct nvram_partition * nvram_part; static long nvram_error_log_index = -1; static long nvram_error_log_size = 0; -int no_logging = 1; /* Until we initialize everything, - * make sure we don't try logging - * anything */ - extern volatile int error_log_cnt; struct err_log_info { @@ -637,10 +633,6 @@ int nvram_write_error_log(char * buff, int length, unsigned int err_type) loff_t tmp_index; struct err_log_info info; - if (no_logging) { - return -EPERM; - } - if (nvram_error_log_index == -1) { return -ESPIPE; } diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index d902097646b7..b802a272bd29 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -53,7 +53,8 @@ static unsigned int rtas_event_scan_rate; static int full_rtas_msgs = 0; -extern int no_logging; +/* Stop logging to nvram after first fatal error */ +static int no_more_logging; volatile int error_log_cnt = 0; @@ -216,7 +217,7 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) } /* Write error to NVRAM */ - if (!no_logging && !(err_type & ERR_FLAG_BOOT)) + if (!no_more_logging && !(err_type & ERR_FLAG_BOOT)) nvram_write_error_log(buf, len, err_type); /* @@ -228,8 +229,8 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) printk_log_rtas(buf, len); /* Check to see if we need to or have stopped logging */ - if (fatal || no_logging) { - no_logging = 1; + if (fatal || no_more_logging) { + no_more_logging = 1; spin_unlock_irqrestore(&rtasd_log_lock, s); return; } @@ -301,7 +302,7 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf, spin_lock_irqsave(&rtasd_log_lock, s); /* if it's 0, then we know we got the last one (the one in NVRAM) */ - if (rtas_log_size == 0 && !no_logging) + if (rtas_log_size == 0 && !no_more_logging) nvram_clear_error_log(); spin_unlock_irqrestore(&rtasd_log_lock, s); @@ -413,9 +414,6 @@ static int rtasd(void *unused) memset(logdata, 0, rtas_error_log_max); rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type); - /* We can use rtas_log_buf now */ - no_logging = 0; - if (!rc) { if (err_type != ERR_FLAG_ALREADY_LOGGED) { pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0); From 0f2342c85df4248bc1cd72421b13969a0782ed6a Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 10 Aug 2007 06:56:41 +1000 Subject: [PATCH 0096/2804] [POWERPC] pseries: Eliminate global error_log_cnt variable Eliminate the use of error_log_cnt as a global var shared across different directories. Pass it as a parameter instead. Signed-off-by: Linas Vepstas ---- Respin of earlier patch, with the CONFIG_PSERIES junk removed from the header file. arch/powerpc/kernel/nvram_64.c | 10 +++++----- arch/powerpc/platforms/pseries/rtasd.c | 7 ++++--- include/asm-powerpc/nvram.h | 6 ++++-- 3 files changed, 13 insertions(+), 10 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/nvram_64.c | 10 +++++----- arch/powerpc/platforms/pseries/rtasd.c | 7 ++++--- include/asm-powerpc/nvram.h | 6 ++++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 4a4d785a08d3..0ed31f220482 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -38,8 +38,6 @@ static struct nvram_partition * nvram_part; static long nvram_error_log_index = -1; static long nvram_error_log_size = 0; -extern volatile int error_log_cnt; - struct err_log_info { int error_type; unsigned int seq_num; @@ -627,7 +625,8 @@ void __exit nvram_cleanup(void) * sequence #: The unique sequence # for each event. (until it wraps) * error log: The error log from event_scan */ -int nvram_write_error_log(char * buff, int length, unsigned int err_type) +int nvram_write_error_log(char * buff, int length, + unsigned int err_type, unsigned int error_log_cnt) { int rc; loff_t tmp_index; @@ -665,7 +664,8 @@ int nvram_write_error_log(char * buff, int length, unsigned int err_type) * * Reads nvram for error log for at most 'length' */ -int nvram_read_error_log(char * buff, int length, unsigned int * err_type) +int nvram_read_error_log(char * buff, int length, + unsigned int * err_type, unsigned int * error_log_cnt) { int rc; loff_t tmp_index; @@ -691,7 +691,7 @@ int nvram_read_error_log(char * buff, int length, unsigned int * err_type) return rc; } - error_log_cnt = info.seq_num; + *error_log_cnt = info.seq_num; *err_type = info.error_type; return 0; diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index b802a272bd29..30925d29bcea 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -56,7 +56,7 @@ static int full_rtas_msgs = 0; /* Stop logging to nvram after first fatal error */ static int no_more_logging; -volatile int error_log_cnt = 0; +static int error_log_cnt; /* * Since we use 32 bit RTAS, the physical address of this must be below @@ -218,7 +218,7 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) /* Write error to NVRAM */ if (!no_more_logging && !(err_type & ERR_FLAG_BOOT)) - nvram_write_error_log(buf, len, err_type); + nvram_write_error_log(buf, len, err_type, error_log_cnt); /* * rtas errors can occur during boot, and we do want to capture @@ -412,7 +412,8 @@ static int rtasd(void *unused) /* See if we have any error stored in NVRAM */ memset(logdata, 0, rtas_error_log_max); - rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type); + rc = nvram_read_error_log(logdata, rtas_error_log_max, + &err_type, &error_log_cnt); if (!rc) { if (err_type != ERR_FLAG_ALREADY_LOGGED) { diff --git a/include/asm-powerpc/nvram.h b/include/asm-powerpc/nvram.h index f3563e11e260..9877982508bf 100644 --- a/include/asm-powerpc/nvram.h +++ b/include/asm-powerpc/nvram.h @@ -63,8 +63,10 @@ struct nvram_partition { }; -extern int nvram_write_error_log(char * buff, int length, unsigned int err_type); -extern int nvram_read_error_log(char * buff, int length, unsigned int * err_type); +extern int nvram_write_error_log(char * buff, int length, + unsigned int err_type, unsigned int err_seq); +extern int nvram_read_error_log(char * buff, int length, + unsigned int * err_type, unsigned int *err_seq); extern int nvram_clear_error_log(void); extern struct nvram_partition *nvram_find_partition(int sig, const char *name); From 96b952dd4b8aaa752b6086ad8bcaf2af23729b5f Mon Sep 17 00:00:00 2001 From: Murali Iyer Date: Thu, 9 Aug 2007 07:46:49 +1000 Subject: [PATCH 0097/2804] [POWERPC] Export DCR symbols for modules In order to compile drivers as modules that uses some of the DCR functions, we need to export the symbols. Example, EMAC driver and other drivers that are under development use these functions. Signed-off-by: Murali Iyer Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/dcr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c index 574b6ef44e0b..e82d54de8a8d 100644 --- a/arch/powerpc/sysdev/dcr.c +++ b/arch/powerpc/sysdev/dcr.c @@ -33,6 +33,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index) return dr[index * 2]; } +EXPORT_SYMBOL_GPL(dcr_resource_start); unsigned int dcr_resource_len(struct device_node *np, unsigned int index) { @@ -44,6 +45,7 @@ unsigned int dcr_resource_len(struct device_node *np, unsigned int index) return dr[index * 2 + 1]; } +EXPORT_SYMBOL_GPL(dcr_resource_len); #ifndef CONFIG_PPC_DCR_NATIVE @@ -122,6 +124,7 @@ dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n, ret.token -= dcr_n * ret.stride; return ret; } +EXPORT_SYMBOL_GPL(dcr_map); void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c) { @@ -133,5 +136,6 @@ void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c) iounmap(h.token); h.token = NULL; } +EXPORT_SYMBOL_GPL(dcr_unmap); #endif /* !defined(CONFIG_PPC_DCR_NATIVE) */ From 1bdb2867e5f0bca7c94f7df92f23fdd20524a488 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Thu, 9 Aug 2007 10:50:44 +1000 Subject: [PATCH 0098/2804] [POWERPC] Remove gratuitous reads from maple PCI config space methods The maple PCI configuration space write methods read the written location immediately after the write is performed, presumably in order to flush the write. However, configuration space writes are not allowed to be posted, making these reads gratuitous. Furthermore, this behavior potentially causes us to violate the PCI PM spec when changing between e.g. D0 and D3 states, because a delay of up to 10ms may be required before the OS accesses configuration space after the write which initiates the transition. It definitely causes a system hang for me with a Broadcom 5721 PCIE network adapter, which is fixed by this change. Therefore this removes the gratuitous reads from u3_agp_write_config, u3_ht_write_config, and u4_pcie_write_config. Signed-off-by: Nathan Lynch Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/maple/pci.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 2542403288f9..b095eaabf623 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -169,15 +169,12 @@ static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -268,15 +265,12 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -376,15 +370,12 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; From 8674e0c9e570fcce948518e8fe518f4b61ac91fe Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:36 +1000 Subject: [PATCH 0099/2804] [POWERPC] rtas_pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/rtas_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index a5de6211b97a..21f14e57d1f3 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -171,8 +171,8 @@ static int rtas_pci_write_config(struct pci_bus *bus, } struct pci_ops rtas_pci_ops = { - rtas_pci_read_config, - rtas_pci_write_config + .read = rtas_pci_read_config, + .write = rtas_pci_write_config, }; int is_python(struct device_node *dev) From aec249bc1944c5359c6d3aa2f674be6a9fb3d076 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:37 +1000 Subject: [PATCH 0100/2804] [POWERPC] celleb_fake_pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c index e0d97e02ef1f..11336b40feca 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/celleb/pci.c @@ -242,8 +242,8 @@ static int celleb_fake_pci_write_config(struct pci_bus *bus, } static struct pci_ops celleb_fake_pci_ops = { - celleb_fake_pci_read_config, - celleb_fake_pci_write_config + .read = celleb_fake_pci_read_config, + .write = celleb_fake_pci_write_config, }; static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, From 3e02aebbca47174d4263cac5ff5b68ea29a7bcff Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:38 +1000 Subject: [PATCH 0101/2804] [POWERPC] celleb_epci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/scc_epci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c index 881fd7d1806a..506fc8447554 100644 --- a/arch/powerpc/platforms/celleb/scc_epci.c +++ b/arch/powerpc/platforms/celleb/scc_epci.c @@ -278,8 +278,8 @@ static int celleb_epci_write_config(struct pci_bus *bus, } struct pci_ops celleb_epci_ops = { - celleb_epci_read_config, - celleb_epci_write_config, + .read = celleb_epci_read_config, + .write = celleb_epci_write_config, }; /* to be moved in FW */ From 2e67d40762215bcd7c9b81e828ef6de453a09bc4 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:39 +1000 Subject: [PATCH 0102/2804] [POWERPC] maple pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/maple/pci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index b095eaabf623..771ed0cf29a5 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -182,8 +182,8 @@ static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u3_agp_pci_ops = { - u3_agp_read_config, - u3_agp_write_config + .read = u3_agp_read_config, + .write = u3_agp_write_config, }; static unsigned long u3_ht_cfa0(u8 devfn, u8 off) @@ -278,8 +278,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u3_ht_pci_ops = { - u3_ht_read_config, - u3_ht_write_config + .read = u3_ht_read_config, + .write = u3_ht_write_config, }; static unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off) @@ -383,8 +383,8 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u4_pcie_pci_ops = { - u4_pcie_read_config, - u4_pcie_write_config + .read = u4_pcie_read_config, + .write = u4_pcie_write_config, }; static void __init setup_u3_agp(struct pci_controller* hose) From 1bb8c6216f08519c16ce20b82e6f6a59fe0ce717 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:40 +1000 Subject: [PATCH 0103/2804] [POWERPC] pa_pxp_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index ab1f5f62bcd8..882b571ba92c 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -122,8 +122,8 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops pa_pxp_ops = { - pa_pxp_read_config, - pa_pxp_write_config, + .read = pa_pxp_read_config, + .write = pa_pxp_write_config, }; static void __init setup_pa_pxp(struct pci_controller *hose) From 3fac10e7f5a6dfa4a08938d24af2775cd9b9e267 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:41 +1000 Subject: [PATCH 0104/2804] [POWERPC] powermac pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/pci.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 92586db19754..69d67ff07004 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -225,8 +225,8 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops macrisc_pci_ops = { - macrisc_read_config, - macrisc_write_config + .read = macrisc_read_config, + .write = macrisc_write_config, }; #ifdef CONFIG_PPC32 @@ -280,8 +280,8 @@ chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset, static struct pci_ops chaos_pci_ops = { - chaos_read_config, - chaos_write_config + .read = chaos_read_config, + .write = chaos_write_config, }; static void __init setup_chaos(struct pci_controller *hose, @@ -456,8 +456,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u3_ht_pci_ops = { - u3_ht_read_config, - u3_ht_write_config + .read = u3_ht_read_config, + .write = u3_ht_write_config, }; #define U4_PCIE_CFA0(devfn, off) \ @@ -561,8 +561,8 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u4_pcie_pci_ops = { - u4_pcie_read_config, - u4_pcie_write_config + .read = u4_pcie_read_config, + .write = u4_pcie_write_config, }; #endif /* CONFIG_PPC64 */ From 6127d1c0b097b2e9acc83dede1c1cb64ce76e7d5 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:42 +1000 Subject: [PATCH 0105/2804] [POWERPC] null_pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 04a3109ae3c6..0e2bee46304c 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -1457,8 +1457,8 @@ null_write_config(struct pci_bus *bus, unsigned int devfn, int offset, static struct pci_ops null_pci_ops = { - null_read_config, - null_write_config + .read = null_read_config, + .write = null_write_config, }; /* From 21d8f6c728a0eb852b521626a41b2bba6a6216d9 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:43 +1000 Subject: [PATCH 0106/2804] [POWERPC] efika rtas_pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/52xx/efika.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 4be6e7a17b66..4263158b3274 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -78,8 +78,8 @@ static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops rtas_pci_ops = { - rtas_read_config, - rtas_write_config + .read = rtas_read_config, + .write = rtas_write_config, }; From f1d645f42849ce3c12781514e6ced97748ada6b1 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:44 +1000 Subject: [PATCH 0107/2804] [POWERPC] chrp pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/chrp/pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index 28d1647b204e..0c6dba9823e9 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -86,8 +86,8 @@ int gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off, static struct pci_ops gg2_pci_ops = { - gg2_read_config, - gg2_write_config + .read = gg2_read_config, + .write = gg2_write_config, }; /* @@ -124,8 +124,8 @@ int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, static struct pci_ops rtas_pci_ops = { - rtas_read_config, - rtas_write_config + .read = rtas_read_config, + .write = rtas_write_config, }; volatile struct Hydra __iomem *Hydra = NULL; From c78d453b6f95ff38a2226f6f77a4b08a6e27fc42 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:45 +1000 Subject: [PATCH 0108/2804] [POWERPC] indirect_pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/indirect_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index 5294560c7b00..b5d068204aa3 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -144,8 +144,8 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, static struct pci_ops indirect_pci_ops = { - indirect_read_config, - indirect_write_config + .read = indirect_read_config, + .write = indirect_write_config, }; void __init From 8935fa0fe6f87c4df806f605de04aed4353c7600 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 05:18:46 +1000 Subject: [PATCH 0109/2804] [POWERPC] tsi108_direct_pci_ops: Use named structure member initializers Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/tsi108_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 90db8a720fed..cf0bfbd73401 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -193,8 +193,8 @@ void tsi108_clear_pci_cfg_error(void) } static struct pci_ops tsi108_direct_pci_ops = { - tsi108_direct_read_config, - tsi108_direct_write_config + .read = tsi108_direct_read_config, + .write = tsi108_direct_write_config, }; int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary) From b139f1fb0f1e4bfe06f2c88ba8c9a55d9513d871 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 07:37:27 +1000 Subject: [PATCH 0110/2804] [POWERPC] Remove gratuitous reads from pasemi pci config space methods The pasemi pci configuration space write method reads the written location immediately after the write is performed, presumably in order to flush the write. However, configuration space writes are not allowed to be posted, making these reads gratuitous. Furthermore, this behavior potentially causes us to violate the PCI PM spec when changing between e.g. D0 and D3 states, because a delay of up to 10ms may be required before the OS accesses configuration space after the write which initiates the transition. Remove the unnecessary reads from pa_pxp_write_config. Signed-off-by: Nathan Lynch Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/pci.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index 882b571ba92c..03d1d07aa2ac 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -107,15 +107,12 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; From 0f7f2fb85a67953acd6bf379681f22f5c83d4f60 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 10 Aug 2007 07:43:28 +1000 Subject: [PATCH 0111/2804] [POWERPC] Remove gratuitous reads from powermac pci config space methods The powermac pci configuration space write methods read the written location immediately after the write is performed, presumably in order to flush the write. However, configuration space writes are not allowed to be posted, making these reads gratuitous. Furthermore, this behavior potentially causes us to violate the PCI PM spec when changing between e.g. D0 and D3 states, because a delay of up to 10ms may be required before the OS accesses configuration space after the write which initiates the transition. Remove the unnecessary reads from macrisc_write_config, u3_ht_write_config, and u4_pcie_write_config. Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/pci.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 69d67ff07004..ec49099830d5 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -209,15 +209,12 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -440,15 +437,12 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32((u32 __iomem *)addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -545,15 +539,12 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; From 09a54101e15f43607722dee55f33d1962653c6cb Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 10 Aug 2007 09:28:11 +1000 Subject: [PATCH 0112/2804] [POWERPC] pseries: Remove dead EEH video code Remove dead code, and a misleading comment about EEH checking for video devices. The removed code is a left-over from the olden days where there was concern over how video devices worked in Linux. We are never going to go that way again, so kill this. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/eeh.c | 17 ----------------- 1 file changed, 17 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 41b64b370fc6..b242c6c34f81 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -969,23 +969,6 @@ static void *early_enable_eeh(struct device_node *dn, void *data) } pdn->class_code = *class_code; - /* - * Now decide if we are going to "Disable" EEH checking - * for this device. We still run with the EEH hardware active, - * but we won't be checking for ff's. This means a driver - * could return bad data (very bad!), an interrupt handler could - * hang waiting on status bits that won't change, etc. - * But there are a few cases like display devices that make sense. - */ - enable = 1; /* i.e. we will do checking */ -#if 0 - if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY) - enable = 0; -#endif - - if (!enable) - pdn->eeh_mode |= EEH_MODE_NOCHECK; - /* Ok... see if this device supports EEH. Some do, some don't, * and the only way to find out is to check each and every one. */ regs = of_get_property(dn, "reg", NULL); From c6d4267eced79775399f256fbb4adb671e9b597e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 10 Aug 2007 14:07:38 +1000 Subject: [PATCH 0113/2804] [POWERPC] Handle alignment faults on new FP load/store instructions This adds code to handle alignment traps generated by the following new floating-point load/store instructions, by emulating the instruction in the kernel (as is done for other instructions that generate alignment traps): lfiwax load floating-point as integer word algebraic indexed stfiwx store floating-point as integer word indexed lfdp load floating-point double pair lfdpx load floating-point double pair indexed stfdp store floating-point double pair stfdpx store floating-point double pair indexed All these except stfiwx are new in POWER6. lfdp/lfdpx/stfdp/stfdpx load and store 16 bytes of memory into an even/odd FP register pair. In little-endian mode each 8-byte value is byte-reversed separately (i.e. not as a 16-byte unit). lfiwax/stfiwx load or store the lower 4 bytes of a floating-point register from/to memory; lfiwax sets the upper 4 bytes of the FP register to the sign extension of the value loaded. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/align.c | 57 +++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index 5c9ff7f5c44e..4c47f9cc0d9a 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -38,7 +38,7 @@ struct aligninfo { /* Bits in the flags field */ #define LD 0 /* load */ #define ST 1 /* store */ -#define SE 2 /* sign-extend value */ +#define SE 2 /* sign-extend value, or FP ld/st as word */ #define F 4 /* to/from fp regs */ #define U 8 /* update index register */ #define M 0x10 /* multiple load/store */ @@ -87,9 +87,9 @@ static struct aligninfo aligninfo[128] = { { 8, LD+F+U }, /* 00 1 1001: lfdu */ { 4, ST+F+S+U }, /* 00 1 1010: stfsu */ { 8, ST+F+U }, /* 00 1 1011: stfdu */ - INVALID, /* 00 1 1100 */ + { 16, LD+F }, /* 00 1 1100: lfdp */ INVALID, /* 00 1 1101 */ - INVALID, /* 00 1 1110 */ + { 16, ST+F }, /* 00 1 1110: stfdp */ INVALID, /* 00 1 1111 */ { 8, LD }, /* 01 0 0000: ldx */ INVALID, /* 01 0 0001 */ @@ -167,10 +167,10 @@ static struct aligninfo aligninfo[128] = { { 8, LD+F }, /* 11 0 1001: lfdx */ { 4, ST+F+S }, /* 11 0 1010: stfsx */ { 8, ST+F }, /* 11 0 1011: stfdx */ - INVALID, /* 11 0 1100 */ - { 8, LD+M }, /* 11 0 1101: lmd */ - INVALID, /* 11 0 1110 */ - { 8, ST+M }, /* 11 0 1111: stmd */ + { 16, LD+F }, /* 11 0 1100: lfdpx */ + { 4, LD+F+SE }, /* 11 0 1101: lfiwax */ + { 16, ST+F }, /* 11 0 1110: stfdpx */ + { 4, ST+F }, /* 11 0 1111: stfiwx */ { 4, LD+U }, /* 11 1 0000: lwzux */ INVALID, /* 11 1 0001 */ { 4, ST+U }, /* 11 1 0010: stwux */ @@ -356,6 +356,42 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, return 1; } +/* + * Emulate floating-point pair loads and stores. + * Only POWER6 has these instructions, and it does true little-endian, + * so we don't need the address swizzling. + */ +static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr, + unsigned int reg, unsigned int flags) +{ + char *ptr = (char *) ¤t->thread.fpr[reg]; + int i, ret; + + if (!(flags & F)) + return 0; + if (reg & 1) + return 0; /* invalid form: FRS/FRT must be even */ + if (!(flags & SW)) { + /* not byte-swapped - easy */ + if (!(flags & ST)) + ret = __copy_from_user(ptr, addr, 16); + else + ret = __copy_to_user(addr, ptr, 16); + } else { + /* each FPR value is byte-swapped separately */ + ret = 0; + for (i = 0; i < 16; ++i) { + if (!(flags & ST)) + ret |= __get_user(ptr[i^7], addr + i); + else + ret |= __put_user(ptr[i^7], addr + i); + } + } + if (ret) + return -EFAULT; + return 1; /* exception handled and fixed up */ +} + /* * Called on alignment exception. Attempts to fixup @@ -471,6 +507,10 @@ int fix_alignment(struct pt_regs *regs) flush_fp_to_thread(current); } + /* Special case for 16-byte FP loads and stores */ + if (nb == 16) + return emulate_fp_pair(regs, addr, reg, flags); + /* If we are loading, get the data from user space, else * get it from register values */ @@ -531,7 +571,8 @@ int fix_alignment(struct pt_regs *regs) * or floating point single precision conversion */ switch (flags & ~(U|SW)) { - case LD+SE: /* sign extend */ + case LD+SE: /* sign extending integer loads */ + case LD+F+SE: /* sign extend for lfiwax */ if ( nb == 2 ) data.ll = data.x16.low16; else /* nb must be 4 */ From 9f0cbea0d8cc47801b853d3c61d0e17475b0cc89 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Sat, 11 Aug 2007 10:15:30 +1000 Subject: [PATCH 0114/2804] [POWERPC] Implement atomic{, 64}_{read, write}() without volatile Instead, use asm() like all other atomic operations already do. Also use inline functions instead of macros; this actually improves code generation (some code becomes a little smaller, probably because of improved alias information -- just a few hundred bytes total on a default kernel build, nothing shocking). Signed-off-by: Segher Boessenkool Signed-off-by: Paul Mackerras --- include/asm-powerpc/atomic.h | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h index c44810b9d322..f3fc733758f5 100644 --- a/include/asm-powerpc/atomic.h +++ b/include/asm-powerpc/atomic.h @@ -5,7 +5,7 @@ * PowerPC atomic operations */ -typedef struct { volatile int counter; } atomic_t; +typedef struct { int counter; } atomic_t; #ifdef __KERNEL__ #include @@ -15,8 +15,19 @@ typedef struct { volatile int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } -#define atomic_read(v) ((v)->counter) -#define atomic_set(v,i) (((v)->counter) = (i)) +static __inline__ int atomic_read(const atomic_t *v) +{ + int t; + + __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter)); + + return t; +} + +static __inline__ void atomic_set(atomic_t *v, int i) +{ + __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); +} static __inline__ void atomic_add(int a, atomic_t *v) { @@ -240,12 +251,23 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v) #ifdef __powerpc64__ -typedef struct { volatile long counter; } atomic64_t; +typedef struct { long counter; } atomic64_t; #define ATOMIC64_INIT(i) { (i) } -#define atomic64_read(v) ((v)->counter) -#define atomic64_set(v,i) (((v)->counter) = (i)) +static __inline__ long atomic64_read(const atomic64_t *v) +{ + long t; + + __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter)); + + return t; +} + +static __inline__ void atomic64_set(atomic64_t *v, long i) +{ + __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); +} static __inline__ void atomic64_add(long a, atomic64_t *v) { From 7b52b440d37d669ec93297cf589984a110518d43 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Aug 2007 06:38:34 +1000 Subject: [PATCH 0115/2804] [POWERPC] via-pmu: Fix typo in printk This fixes a typo in a printk message. Signed-off-by: Michael Buesch Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/macintosh/via-pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 157080b3b468..5eee480245f3 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -410,7 +410,7 @@ static int __init via_pmu_start(void) irq = irq_of_parse_and_map(vias, 0); if (irq == NO_IRQ) { - printk(KERN_ERR "via-pmu: can't map interruptn"); + printk(KERN_ERR "via-pmu: can't map interrupt\n"); return -ENODEV; } if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) { From 1ac9f1f71dea5944085b7b4954516794a9dab35a Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Wed, 15 Aug 2007 04:45:44 +1000 Subject: [PATCH 0116/2804] [POWERPC] Update lmb.h include protection to ASM_POWERPC This file was protected by _PPC64_LMB_H, which is confusing, as the 32-bit code also uses the lmb these days. Changed to _ASM_POWERPC_LMB_H. Signed-off-by: Becky Bruce Signed-off-by: Paul Mackerras --- include/asm-powerpc/lmb.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-powerpc/lmb.h b/include/asm-powerpc/lmb.h index 0c5880f70225..b5f9f4c9c294 100644 --- a/include/asm-powerpc/lmb.h +++ b/include/asm-powerpc/lmb.h @@ -1,5 +1,5 @@ -#ifndef _PPC64_LMB_H -#define _PPC64_LMB_H +#ifndef _ASM_POWERPC_LMB_H +#define _ASM_POWERPC_LMB_H #ifdef __KERNEL__ /* @@ -77,4 +77,4 @@ lmb_end_pfn(struct lmb_region *type, unsigned long region_nr) } #endif /* __KERNEL__ */ -#endif /* _PPC64_LMB_H */ +#endif /* _ASM_POWERPC_LMB_H */ From 9dfe5c53d0fcc08e9efc1e13bb6702fac74f4a12 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 16:33:55 +1000 Subject: [PATCH 0117/2804] [POWERPC] Fix non HUGETLB_PAGE build warning arch/powerpc/mm/mmu_context_64.c: In function 'init_new_context': arch/powerpc/mm/mmu_context_64.c:31: warning: unused variable 'new_context' Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/mm/mmu_context_64.c | 5 ++--- arch/powerpc/mm/slice.c | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_64.c index 7a78cdc0515a..901ea765f146 100644 --- a/arch/powerpc/mm/mmu_context_64.c +++ b/arch/powerpc/mm/mmu_context_64.c @@ -28,7 +28,6 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { int index; int err; - int new_context = (mm->context.id == 0); again: if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) @@ -50,19 +49,19 @@ again: return -ENOMEM; } - mm->context.id = index; #ifdef CONFIG_PPC_MM_SLICES /* The old code would re-promote on fork, we don't do that * when using slices as it could cause problem promoting slices * that have been forced down to 4K */ - if (new_context) + if (mm->context.id == 0) slice_set_user_psize(mm, mmu_virtual_psize); #else mm->context.user_psize = mmu_virtual_psize; mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[mmu_virtual_psize].sllp; #endif + mm->context.id = index; return 0; } diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index d5fd3909d13a..319826ef1645 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -551,6 +551,7 @@ EXPORT_SYMBOL_GPL(get_slice_psize); * * This is also called in init_new_context() to change back the user * psize from whatever the parent context had it set to + * N.B. This may be called before mm->context.id has been set. * * This function will only change the content of the {low,high)_slice_psize * masks, it will not flush SLBs as this shall be handled lazily by the From 9c25099db74b384e16345622071552f9f10dd045 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 16:42:12 +1000 Subject: [PATCH 0118/2804] [POWERPC] Use of_get_property in ipmi code get_property has been renamed to of_get_property. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/char/ipmi/ipmi_si_intf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 96d2f9ee42d6..d57083a9e4e0 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2251,19 +2251,19 @@ static int __devinit ipmi_of_probe(struct of_device *dev, return ret; } - regsize = get_property(np, "reg-size", &proplen); + regsize = of_get_property(np, "reg-size", &proplen); if (regsize && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regsize from OF\n"); return -EINVAL; } - regspacing = get_property(np, "reg-spacing", &proplen); + regspacing = of_get_property(np, "reg-spacing", &proplen); if (regspacing && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regspacing from OF\n"); return -EINVAL; } - regshift = get_property(np, "reg-shift", &proplen); + regshift = of_get_property(np, "reg-shift", &proplen); if (regshift && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regshift from OF\n"); return -EINVAL; From 0b8188a44def37f4f8ef01653da199ca3a3e0a2a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 16:45:15 +1000 Subject: [PATCH 0119/2804] [POWERPC] Remove get_property and device_is_compatible They were only needed for backwards compatibility and all in tree uses have now been changed. Signed-off-by: Stephen Rothwell Acked-by: David S. Miller Signed-off-by: Paul Mackerras --- include/asm-powerpc/prom.h | 1 - include/asm-ppc/prom.h | 1 - include/linux/of.h | 1 - 3 files changed, 3 deletions(-) diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 672083787a1d..920b75620f74 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -145,7 +145,6 @@ extern void of_detach_node(struct device_node *); extern void finish_device_tree(void); extern void unflatten_device_tree(void); extern void early_init_devtree(void *); -#define device_is_compatible(d, c) of_device_is_compatible((d), (c)) extern int machine_is_compatible(const char *compat); extern void print_properties(struct device_node *node); extern int prom_n_intr_cells(struct device_node* np); diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h index 901f7fa8b2d7..71f4c996fe75 100644 --- a/include/asm-ppc/prom.h +++ b/include/asm-ppc/prom.h @@ -35,7 +35,6 @@ extern unsigned long sub_reloc_offset(unsigned long); #define machine_is_compatible(x) 0 #define of_find_compatible_node(f, t, c) NULL #define of_get_property(p, n, l) NULL -#define get_property(a, b, c) of_get_property((a), (b), (c)) #endif /* _PPC_PROM_H */ #endif /* __KERNEL__ */ diff --git a/include/linux/of.h b/include/linux/of.h index 47734ffd9745..6df80e985914 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -54,7 +54,6 @@ extern int of_device_is_compatible(const struct device_node *device, extern const void *of_get_property(const struct device_node *node, const char *name, int *lenp); -#define get_property(a, b, c) of_get_property((a), (b), (c)) extern int of_n_addr_cells(struct device_node *np); extern int of_n_size_cells(struct device_node *np); From e8ff0646e5df850ff084be9c97a2e69fff5697b4 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 16:51:18 +1000 Subject: [PATCH 0120/2804] [POWERPC] Tidy up CONFIG_PPC_MM_SLICES code This removes some of the #ifdefs from .c files. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/mm/hash_utils_64.c | 6 ------ arch/powerpc/mm/mmu_context_64.c | 8 +------- include/asm-powerpc/page_64.h | 7 +++++++ 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index c74af42eb9c1..d525f2eba313 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -601,13 +601,7 @@ static void demote_segment_4k(struct mm_struct *mm, unsigned long addr) { if (mm->context.user_psize == MMU_PAGE_4K) return; -#ifdef CONFIG_PPC_MM_SLICES slice_set_user_psize(mm, MMU_PAGE_4K); -#else /* CONFIG_PPC_MM_SLICES */ - mm->context.user_psize = MMU_PAGE_4K; - mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp; -#endif /* CONFIG_PPC_MM_SLICES */ - #ifdef CONFIG_SPU_BASE spu_flush_all_slbs(mm); #endif diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_64.c index 901ea765f146..1db38ba1f544 100644 --- a/arch/powerpc/mm/mmu_context_64.c +++ b/arch/powerpc/mm/mmu_context_64.c @@ -49,18 +49,12 @@ again: return -ENOMEM; } -#ifdef CONFIG_PPC_MM_SLICES /* The old code would re-promote on fork, we don't do that * when using slices as it could cause problem promoting slices * that have been forced down to 4K */ - if (mm->context.id == 0) + if (slice_mm_new_context(mm)) slice_set_user_psize(mm, mmu_virtual_psize); -#else - mm->context.user_psize = mmu_virtual_psize; - mm->context.sllp = SLB_VSID_USER | - mmu_psize_defs[mmu_virtual_psize].sllp; -#endif mm->context.id = index; return 0; diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h index 3448a3d4bc64..4ceb1132c480 100644 --- a/include/asm-powerpc/page_64.h +++ b/include/asm-powerpc/page_64.h @@ -121,6 +121,7 @@ extern unsigned int get_slice_psize(struct mm_struct *mm, extern void slice_init_context(struct mm_struct *mm, unsigned int psize); extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize); +#define slice_mm_new_context(mm) ((mm)->context.id == 0) #define ARCH_HAS_HUGEPAGE_ONLY_RANGE extern int is_hugepage_only_range(struct mm_struct *m, @@ -130,6 +131,12 @@ extern int is_hugepage_only_range(struct mm_struct *m, #endif /* __ASSEMBLY__ */ #else #define slice_init() +#define slice_set_user_psize(mm, psize) \ +do { \ + (mm)->context.user_psize = (psize); \ + (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \ +} while (0) +#define slice_mm_new_context(mm) 1 #endif /* CONFIG_PPC_MM_SLICES */ #ifdef CONFIG_HUGETLB_PAGE From a05afe9146f7611d40a58be34ee8442727a6af1f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 16:54:04 +1000 Subject: [PATCH 0121/2804] [POWERPC] Comment out a currently unused function Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/macintosh/windfarm_smu_sat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 351982bcec1b..f449d775cdf4 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -380,10 +380,12 @@ static int __init sat_sensors_init(void) return i2c_add_driver(&wf_sat_driver); } +#if 0 /* uncomment when module_exit() below is uncommented */ static void __exit sat_sensors_exit(void) { i2c_del_driver(&wf_sat_driver); } +#endif module_init(sat_sensors_init); /*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */ From 4dc7b4b0405fd7320940849b6e31ea8ea68fd0df Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 14 Aug 2007 13:52:42 +1000 Subject: [PATCH 0122/2804] [POWERPC] Fix setting of irq trigger type in UIC driver The UIC (interrupt controller in 4xx embedded CPUs) driver currently missets the IRQ_lEVEL flag in desc->status, due to a thinko. This patch fixes the bug. Currently this is only a cosmetic problem (affects the output in /proc/interrupts), however subsequent patches will use the IRQ_LEVEL flag to affect flow handling. Signed-off-by: Valentine Barshak Signed-off-by: David Gibson Acked-by: Josh Boyer Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/uic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 89059895a20d..ef8eb5bc6bba 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -142,7 +142,7 @@ static int uic_set_irq_type(unsigned int virq, unsigned int flow_type) desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; - if (trigger) + if (!trigger) desc->status |= IRQ_LEVEL; spin_unlock_irqrestore(&uic->lock, flags); From 868afce21fdadcecc7bde9263321065948508c56 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 14 Aug 2007 13:52:42 +1000 Subject: [PATCH 0123/2804] [POWERPC] Fix irq flow handler for 4xx UIC At present the driver for the UIC (the embedded interrupt controller in 4xx chips) uses the handle_level_irq() flow handler. It turns out this does not correctly handle level triggered interrupts on the UIC. Specifically, acknowledging an irq on the UIC (i.e. clearing the relevant bit in UIC_SR) will have no effect for a level interrupt which is still asserted by the external device, even if the irq is already masked. Therefore, unlike handle_level_irq() we must ack the interrupt after invoking the ISR (which should cause the device to stop asserting the irq) instead of acking it when we mask it, before the ISR. This patch implements this change, in a new handle_uic_irq(), a customised irq flow handler for the UIC. For edge triggered interrupts, handle_uic_irq() still uses the old flow - we must ack edge triggered interrupt before the ISR not after, or we could miss a second event which occurred between invoking the ISR and acking the irq. Signed-off-by: David Gibson Acked-by: Josh Boyer Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/uic.c | 61 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index ef8eb5bc6bba..22c219e448d4 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -159,6 +160,64 @@ static struct irq_chip uic_irq_chip = { .set_type = uic_set_irq_type, }; +/** + * handle_uic_irq - irq flow handler for UIC + * @irq: the interrupt number + * @desc: the interrupt description structure for this irq + * + * This is modified version of the generic handle_level_irq() suitable + * for the UIC. On the UIC, acking (i.e. clearing the SR bit) a level + * irq will have no effect if the interrupt is still asserted by the + * device, even if the interrupt is already masked. Therefore, unlike + * the standard handle_level_irq(), we must ack the interrupt *after* + * invoking the ISR (which should have de-asserted the interrupt in + * the external source). For edge interrupts we ack at the beginning + * instead of the end, to keep the window in which we can miss an + * interrupt as small as possible. + */ +void fastcall handle_uic_irq(unsigned int irq, struct irq_desc *desc) +{ + unsigned int cpu = smp_processor_id(); + struct irqaction *action; + irqreturn_t action_ret; + + spin_lock(&desc->lock); + if (desc->status & IRQ_LEVEL) + desc->chip->mask(irq); + else + desc->chip->mask_ack(irq); + + if (unlikely(desc->status & IRQ_INPROGRESS)) + goto out_unlock; + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); + kstat_cpu(cpu).irqs[irq]++; + + /* + * If its disabled or no action available + * keep it masked and get out of here + */ + action = desc->action; + if (unlikely(!action || (desc->status & IRQ_DISABLED))) { + desc->status |= IRQ_PENDING; + goto out_unlock; + } + + desc->status |= IRQ_INPROGRESS; + desc->status &= ~IRQ_PENDING; + spin_unlock(&desc->lock); + + action_ret = handle_IRQ_event(irq, action); + + spin_lock(&desc->lock); + desc->status &= ~IRQ_INPROGRESS; + if (desc->status & IRQ_LEVEL) + desc->chip->ack(irq); + if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) + desc->chip->unmask(irq); +out_unlock: + spin_unlock(&desc->lock); +} + static int uic_host_match(struct irq_host *h, struct device_node *node) { struct uic *uic = h->host_data; @@ -173,7 +232,7 @@ static int uic_host_map(struct irq_host *h, unsigned int virq, set_irq_chip_data(virq, uic); /* Despite the name, handle_level_irq() works for both level * and edge irqs on UIC. FIXME: check this is correct */ - set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq); + set_irq_chip_and_handler(virq, &uic_irq_chip, handle_uic_irq); /* Set default irq type */ set_irq_type(virq, IRQ_TYPE_NONE); From 553fdff633b1cb8cfccf554768444c5580a8d7f7 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 14 Aug 2007 13:52:42 +1000 Subject: [PATCH 0124/2804] [POWERPC] Improve robustness of the UIC cascade handler At present the cascade interrupt handler for the UIC (interrupt controller on 4xx embedded chips) will misbehave badly if it is called spuriously - that is if the handler is invoked when no interrupts are asserted in the child UIC. Although spurious interrupts shouldn't happen, it's good to behave robustly if they do. This patch does so by checking for and ignoring spurious interrupts. Signed-off-by: Valentine Barshak Signed-off-by: David Gibson Acked-by: Josh Boyer Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/uic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 22c219e448d4..47180b3fca56 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -266,6 +266,9 @@ irqreturn_t uic_cascade(int virq, void *data) int subvirq; msr = mfdcr(uic->dcrbase + UIC_MSR); + if (!msr) /* spurious interrupt */ + return IRQ_HANDLED; + src = 32 - ffs(msr); subvirq = irq_linear_revmap(uic->irqhost, src); From d56c3aaa9f660e5f5f295da74f5d3db510de0ede Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 20:53:26 +1000 Subject: [PATCH 0125/2804] [POWERPC] Fix section mismatch in crash_dump.c WARNING: vmlinux.o(.text+0x23258): Section mismatch: reference to .init.text:.lmb_reserve (between '.reserve_kdump_trampoline' and '.restore_processor_state') Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/crash_dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 2f6f5a7bc69e..ffa91d673ec8 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -25,7 +25,7 @@ #define DBG(fmt...) #endif -void reserve_kdump_trampoline(void) +void __init reserve_kdump_trampoline(void) { lmb_reserve(0, KDUMP_RESERVE_LIMIT); } From 109b60f0bc1306192c765875badcaa5f3850a0a1 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 20:54:32 +1000 Subject: [PATCH 0126/2804] [POWERPC] Fix section mismatch in dart_iommu.c These functions are only called from __init functions. WARNING: vmlinux.o(.text+0x398f4): Section mismatch: reference to .init.text:.lmb_alloc (between '.iommu_init_early_dart' and '.pci_dma_bus_setup_dart') Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/dart_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index a1d2042bb304..e0e24b01e3a6 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -204,7 +204,7 @@ static void dart_free(struct iommu_table *tbl, long index, long npages) } -static int dart_init(struct device_node *dart_node) +static int __init dart_init(struct device_node *dart_node) { unsigned int i; unsigned long tmp, base, size; @@ -313,7 +313,7 @@ static void pci_dma_bus_setup_dart(struct pci_bus *bus) PCI_DN(dn)->iommu_table = &iommu_table_dart; } -void iommu_init_early_dart(void) +void __init iommu_init_early_dart(void) { struct device_node *dn; From 124d795d16b018b054956c9be561f889acf95ac4 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 20:55:57 +1000 Subject: [PATCH 0127/2804] [POWERPC] Fix section mismatches in udbg_adb.c The functions are only called from __init functions. WARNING: vmlinux.o(.text+0x45ed0): Section mismatch: reference to .init.text:.btext_find_display (between '.udbg_adb_init_early' and '.udbg_adb_init') WARNING: vmlinux.o(.text+0x45f9c): Section mismatch: reference to .init.text:.btext_find_display (between '.udbg_adb_init' and '.udbg_adb_getc_poll') WARNING: vmlinux.o(.text+0x46000): Section mismatch: reference to .init.text:.find_via_pmu (between '.udbg_adb_init' and '.udbg_adb_getc_poll') Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/udbg_adb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c index b1882e40525a..44e0b55a2a02 100644 --- a/arch/powerpc/platforms/powermac/udbg_adb.c +++ b/arch/powerpc/platforms/powermac/udbg_adb.c @@ -149,7 +149,7 @@ static void udbg_adb_putc(char c) return udbg_adb_old_putc(c); } -void udbg_adb_init_early(void) +void __init udbg_adb_init_early(void) { #ifdef CONFIG_BOOTX_TEXT if (btext_find_display(1) == 0) { @@ -159,7 +159,7 @@ void udbg_adb_init_early(void) #endif } -int udbg_adb_init(int force_btext) +int __init udbg_adb_init(int force_btext) { struct device_node *np; From 750d1d1ca1d2e94e15393927fd3c30222d1c5203 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 20:58:23 +1000 Subject: [PATCH 0128/2804] [POWERPC] Fix section mismatch in pasemi/iommu.c These functions are only called by __init functions. WARNING: vmlinux.o(.text+0x56aa0): Section mismatch: reference to .init.text:.lmb_alloc (between '.iob_init' and '.iommu_init_early_pasemi') Signed-off-by: Stephen Rothwell Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index f33b21b9f5d4..c910ec9c2bdf 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -187,7 +187,7 @@ static void pci_dma_dev_setup_pasemi(struct pci_dev *dev) static void pci_dma_bus_setup_null(struct pci_bus *b) { } static void pci_dma_dev_setup_null(struct pci_dev *d) { } -int iob_init(struct device_node *dn) +int __init iob_init(struct device_node *dn) { unsigned long tmp; u32 regword; @@ -233,7 +233,7 @@ int iob_init(struct device_node *dn) /* These are called very early. */ -void iommu_init_early_pasemi(void) +void __init iommu_init_early_pasemi(void) { int iommu_off; From e78bb5dc2e0515dce2ac2c590d66405028b7ccd6 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 16 Aug 2007 05:15:03 +1000 Subject: [PATCH 0129/2804] [POWERPC] Fix i2c device string format Use strlcpy() to guarantee strings in i2c device type and driver_name fields are 0-terminated. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/fsl_soc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 727453d3e8b9..565f57d777fe 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -320,21 +320,26 @@ static struct i2c_driver_device i2c_devices[] __initdata = { {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",}, }; -static int __init of_find_i2c_driver(struct device_node *node, struct i2c_board_info *info) +static int __init of_find_i2c_driver(struct device_node *node, + struct i2c_board_info *info) { int i; for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) { if (!of_device_is_compatible(node, i2c_devices[i].of_device)) continue; - strncpy(info->driver_name, i2c_devices[i].i2c_driver, KOBJ_NAME_LEN); - strncpy(info->type, i2c_devices[i].i2c_type, I2C_NAME_SIZE); + if (strlcpy(info->driver_name, i2c_devices[i].i2c_driver, + KOBJ_NAME_LEN) >= KOBJ_NAME_LEN || + strlcpy(info->type, i2c_devices[i].i2c_type, + I2C_NAME_SIZE) >= I2C_NAME_SIZE) + return -ENOMEM; return 0; } return -ENODEV; } -static void __init of_register_i2c_devices(struct device_node *adap_node, int bus_num) +static void __init of_register_i2c_devices(struct device_node *adap_node, + int bus_num) { struct device_node *node = NULL; From a65517f857bf6657839957617af942a4b631fba5 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 16 Aug 2007 11:19:19 +1000 Subject: [PATCH 0130/2804] [POWERPC] Remove some duplicate declarations from pmac.h Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/pmac.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 6e090a7dea83..fcde070f7054 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -22,9 +22,6 @@ extern void pmac_read_rtc_time(void); extern void pmac_calibrate_decr(void); extern void pmac_pci_irq_fixup(struct pci_dev *); extern void pmac_pci_init(void); -extern unsigned long pmac_ide_get_base(int index); -extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, - unsigned long data_port, unsigned long ctrl_port, int *irq); extern void pmac_nvram_update(void); extern unsigned char pmac_nvram_read_byte(int addr); @@ -33,7 +30,6 @@ extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); extern void pmac_pcibios_after_init(void); extern int of_show_percpuinfo(struct seq_file *m, int i); -extern void pmac_pci_init(void); extern void pmac_setup_pci_dma(void); extern void pmac_check_ht_link(void); From 15f6527e8e63e793f8ab1ddce4ed3c487ebd0d42 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:27:07 -0500 Subject: [PATCH 0131/2804] [POWERPC] Rename 4xx paths to 40x 4xx is a bit of a misnomer for certain things, as they really apply to PowerPC 40x only. Rename some of the files to clean this up. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/Makefile | 2 +- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/{head_4xx.S => head_40x.S} | 0 arch/powerpc/mm/{4xx_mmu.c => 40x_mmu.c} | 0 arch/powerpc/mm/Makefile | 2 +- arch/powerpc/platforms/{4xx => 40x}/Kconfig | 0 arch/powerpc/platforms/{4xx => 40x}/Makefile | 0 7 files changed, 3 insertions(+), 3 deletions(-) rename arch/powerpc/kernel/{head_4xx.S => head_40x.S} (100%) rename arch/powerpc/mm/{4xx_mmu.c => 40x_mmu.c} (100%) rename arch/powerpc/platforms/{4xx => 40x}/Kconfig (100%) rename arch/powerpc/platforms/{4xx => 40x}/Makefile (100%) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 6c1e36c33faa..8e59c0c405ad 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -123,7 +123,7 @@ CFLAGS += $(cpu-as-y) head-y := arch/powerpc/kernel/head_32.o head-$(CONFIG_PPC64) := arch/powerpc/kernel/head_64.o head-$(CONFIG_8xx) := arch/powerpc/kernel/head_8xx.o -head-$(CONFIG_4xx) := arch/powerpc/kernel/head_4xx.o +head-$(CONFIG_40x) := arch/powerpc/kernel/head_40x.o head-$(CONFIG_44x) := arch/powerpc/kernel/head_44x.o head-$(CONFIG_FSL_BOOKE) := arch/powerpc/kernel/head_fsl_booke.o diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b0cb2e662c25..a4850dd8764f 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -46,7 +46,7 @@ ifeq ($(CONFIG_PPC_MERGE),y) extra-$(CONFIG_PPC_STD_MMU) := head_32.o extra-$(CONFIG_PPC64) := head_64.o -extra-$(CONFIG_40x) := head_4xx.o +extra-$(CONFIG_40x) := head_40x.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o diff --git a/arch/powerpc/kernel/head_4xx.S b/arch/powerpc/kernel/head_40x.S similarity index 100% rename from arch/powerpc/kernel/head_4xx.S rename to arch/powerpc/kernel/head_40x.S diff --git a/arch/powerpc/mm/4xx_mmu.c b/arch/powerpc/mm/40x_mmu.c similarity index 100% rename from arch/powerpc/mm/4xx_mmu.c rename to arch/powerpc/mm/40x_mmu.c diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 7e4d27ad3dee..bf20fa688809 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_PPC64) += init_64.o pgtable_64.o mmu_context_64.o \ hash_utils_64.o hash_low_64.o tlb_64.o \ slb_low.o slb.o stab.o mmap.o $(hash-y) obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o tlb_32.o -obj-$(CONFIG_40x) += 4xx_mmu.o +obj-$(CONFIG_40x) += 40x_mmu.o obj-$(CONFIG_44x) += 44x_mmu.o obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o diff --git a/arch/powerpc/platforms/4xx/Kconfig b/arch/powerpc/platforms/40x/Kconfig similarity index 100% rename from arch/powerpc/platforms/4xx/Kconfig rename to arch/powerpc/platforms/40x/Kconfig diff --git a/arch/powerpc/platforms/4xx/Makefile b/arch/powerpc/platforms/40x/Makefile similarity index 100% rename from arch/powerpc/platforms/4xx/Makefile rename to arch/powerpc/platforms/40x/Makefile From 3cc248ae6eaac4175047d1fdc4fadd8a94651f83 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:27:42 -0500 Subject: [PATCH 0132/2804] [POWERPC] 4xx Kconfig cleanup Remove some leftover cruft in the 40x Kconfig file. Also make sure we select WANT_DEVICE_TREE for 40x. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/platforms/40x/Kconfig | 77 -------------------------- arch/powerpc/platforms/Kconfig.cputype | 1 + 2 files changed, 1 insertion(+), 77 deletions(-) diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index ded357c17414..2cc7343b468c 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -1,16 +1,3 @@ -config 4xx - bool - depends on 40x || 44x - default y - -config BOOKE - bool - depends on 44x - default y - -menu "AMCC 40x options" - depends on 40x - #config BUBINGA # bool "Bubinga" # depends on 40x @@ -82,8 +69,6 @@ menu "AMCC 40x options" # help # This option enables support for the Xilinx ML300 evaluation board. -endmenu - # 40x specific CPU modules, selected based on the board above. config NP405H bool @@ -126,68 +111,6 @@ config IBM405_ERR77 config IBM405_ERR51 bool -menu "AMCC 44x options" - depends on 44x - -#config BAMBOO -# bool "Bamboo" -# depends on 44x -# default n -# select 440EP -# help -# This option enables support for the IBM PPC440EP evaluation board. - -config EBONY - bool "Ebony" - depends on 44x - default y - select 440GP - help - This option enables support for the IBM PPC440GP evaluation board. - -#config LUAN -# bool "Luan" -# depends on 44x -# default n -# select 440SP -# help -# This option enables support for the IBM PPC440SP evaluation board. - -#config OCOTEA -# bool "Ocotea" -# depends on 44x -# default n -# select 440GX -# help -# This option enables support for the IBM PPC440GX evaluation board. - -endmenu - -# 44x specific CPU modules, selected based on the board above. -config 440EP - bool - select PPC_FPU - select IBM440EP_ERR42 - -config 440GP - bool - select IBM_NEW_EMAC_ZMII - -config 440GX - bool - -config 440SP - bool - -config 440A - bool - depends on 440GX - default y - -# 44x errata/workaround config symbols, selected by the CPU models above -config IBM440EP_ERR42 - bool - #config XILINX_OCP # bool # depends on XILINX_ML300 diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index e4b2aee53a73..643bee223ec5 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -40,6 +40,7 @@ config PPC_8xx config 40x bool "AMCC 40x" select PPC_DCR_NATIVE + select WANT_DEVICE_TREE config 44x bool "AMCC 44x" From 869680c16fb028ac4ad9a449283e0514789c654a Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:28:05 -0500 Subject: [PATCH 0133/2804] [POWERPC] Rename 44x bootwrapper Rename the 44x.c wrapper file to 4xx.c. This will allow us to add common functions in a single file that can be shared across all of 4xx. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/boot/{44x.c => 4xx.c} | 0 arch/powerpc/boot/Makefile | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/powerpc/boot/{44x.c => 4xx.c} (100%) diff --git a/arch/powerpc/boot/44x.c b/arch/powerpc/boot/4xx.c similarity index 100% rename from arch/powerpc/boot/44x.c rename to arch/powerpc/boot/4xx.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 61a6f34ca5ed..b4869e61b738 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -31,7 +31,7 @@ endif BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj) -$(obj)/44x.o: BOOTCFLAGS += -mcpu=440 +$(obj)/4xx.o: BOOTCFLAGS += -mcpu=440 $(obj)/ebony.o: BOOTCFLAGS += -mcpu=440 zlib := inffast.c inflate.c inftrees.c @@ -44,7 +44,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ - 44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c + 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c From e90f3b74d884d0f2826e06dbab4f615ca346eaa4 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:28:30 -0500 Subject: [PATCH 0134/2804] [POWERPC] 4xx bootwrapper reworks Make the fixup_memsize function common for all of 4xx as several chips share the same SDRAM controller. Also add functions to reset 40x chips and quiesce the ethernet. Signed-off-by: Josh Boyer --- arch/powerpc/boot/44x.h | 4 ---- arch/powerpc/boot/4xx.c | 35 ++++++++++++++++++++++++++++++----- arch/powerpc/boot/4xx.h | 20 ++++++++++++++++++++ arch/powerpc/boot/dcr.h | 3 +++ arch/powerpc/boot/ebony.c | 3 ++- 5 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 arch/powerpc/boot/4xx.h diff --git a/arch/powerpc/boot/44x.h b/arch/powerpc/boot/44x.h index 577982c9a3cd..490a1cbdf1ed 100644 --- a/arch/powerpc/boot/44x.h +++ b/arch/powerpc/boot/44x.h @@ -10,10 +10,6 @@ #ifndef _PPC_BOOT_44X_H_ #define _PPC_BOOT_44X_H_ -void ibm44x_fixup_memsize(void); -void ibm4xx_fixup_ebc_ranges(const char *ebc); - -void ibm44x_dbcr_reset(void); void ebony_init(void *mac0, void *mac1); #endif /* _PPC_BOOT_44X_H_ */ diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c index 9f64e840bef6..59026e4585dc 100644 --- a/arch/powerpc/boot/4xx.c +++ b/arch/powerpc/boot/4xx.c @@ -21,8 +21,8 @@ #include "reg.h" #include "dcr.h" -/* Read the 44x memory controller to get size of system memory. */ -void ibm44x_fixup_memsize(void) +/* Read the 4xx SDRAM controller to get size of system memory. */ +void ibm4xx_fixup_memsize(void) { int i; unsigned long memsize, bank_config; @@ -39,8 +39,9 @@ void ibm44x_fixup_memsize(void) dt_fixup_memory(0, memsize); } -#define SPRN_DBCR0 0x134 -#define DBCR0_RST_SYSTEM 0x30000000 +#define SPRN_DBCR0_40X 0x3F2 +#define SPRN_DBCR0_44X 0x134 +#define DBCR0_RST_SYSTEM 0x30000000 void ibm44x_dbcr_reset(void) { @@ -50,11 +51,35 @@ void ibm44x_dbcr_reset(void) "mfspr %0,%1\n" "oris %0,%0,%2@h\n" "mtspr %1,%0" - : "=&r"(tmp) : "i"(SPRN_DBCR0), "i"(DBCR0_RST_SYSTEM) + : "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM) ); } +void ibm40x_dbcr_reset(void) +{ + unsigned long tmp; + + asm volatile ( + "mfspr %0,%1\n" + "oris %0,%0,%2@h\n" + "mtspr %1,%0" + : "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM) + ); +} + +#define EMAC_RESET 0x20000000 +void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1) +{ + /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't do this for us */ + if (emac0) + *emac0 = EMAC_RESET; + if (emac1) + *emac1 = EMAC_RESET; + + mtdcr(DCRN_MAL0_CFG, MAL_RESET); +} + /* Read 4xx EBC bus bridge registers to get mappings of the peripheral * banks into the OPB address space */ void ibm4xx_fixup_ebc_ranges(const char *ebc) diff --git a/arch/powerpc/boot/4xx.h b/arch/powerpc/boot/4xx.h new file mode 100644 index 000000000000..65008427e03f --- /dev/null +++ b/arch/powerpc/boot/4xx.h @@ -0,0 +1,20 @@ +/* + * PowerPC 4xx related functions + * + * Copyright 2007 IBM Corporation. + * Josh Boyer + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ +#ifndef _POWERPC_BOOT_4XX_H_ +#define _POWERPC_BOOT_4XX_H_ + +void ibm4xx_fixup_memsize(void); +void ibm44x_dbcr_reset(void); +void ibm40x_dbcr_reset(void); +void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1); +void ibm4xx_fixup_ebc_ranges(const char *ebc); + +#endif /* _POWERPC_BOOT_4XX_H_ */ diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h index 14b44aa96fea..c95d1a9222c9 100644 --- a/arch/powerpc/boot/dcr.h +++ b/arch/powerpc/boot/dcr.h @@ -121,4 +121,7 @@ static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR, SDRAM0_B2C #define DCRN_CPC0_MIRQ1 0x0ed #define DCRN_CPC0_JTAGID 0x0ef +#define DCRN_MAL0_CFG 0x180 +#define MAL_RESET 0x80000000 + #endif /* _PPC_BOOT_DCR_H_ */ diff --git a/arch/powerpc/boot/ebony.c b/arch/powerpc/boot/ebony.c index eaf0b9bb68d6..2b9a809bcd74 100644 --- a/arch/powerpc/boot/ebony.c +++ b/arch/powerpc/boot/ebony.c @@ -26,6 +26,7 @@ #include "reg.h" #include "io.h" #include "dcr.h" +#include "4xx.h" #include "44x.h" extern char _dtb_start[]; @@ -136,7 +137,7 @@ static void ebony_fixups(void) unsigned long sysclk = 33000000; ibm440gp_fixup_clocks(sysclk, 6 * 1843200); - ibm44x_fixup_memsize(); + ibm4xx_fixup_memsize(); dt_fixup_mac_addresses(ebony_mac0, ebony_mac1); ibm4xx_fixup_ebc_ranges("/plb/opb/ebc"); ebony_flashsel_fixup(); From 4d922c8dc332f4c7bc156fa832187661d4899cee Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:28:48 -0500 Subject: [PATCH 0135/2804] [POWERPC] 40x MMU Add MMU definitions for 40x platforms. Also fixes two warnings in 40x_mmu.c. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/kernel/head_40x.S | 2 +- arch/powerpc/mm/40x_mmu.c | 4 +-- include/asm-powerpc/mmu-40x.h | 65 ++++++++++++++++++++++++++++++++++ include/asm-powerpc/mmu.h | 3 ++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 include/asm-powerpc/mmu-40x.h diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index adc7f8097cd4..fe8afb60290e 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -772,7 +772,7 @@ finish_tlb_load: */ lwz r9, tlb_4xx_index@l(0) addi r9, r9, 1 - andi. r9, r9, (PPC4XX_TLB_SIZE-1) + andi. r9, r9, (PPC40X_TLB_SIZE-1) stw r9, tlb_4xx_index@l(0) 6: diff --git a/arch/powerpc/mm/40x_mmu.c b/arch/powerpc/mm/40x_mmu.c index 7ff2609b64d1..e067df836be2 100644 --- a/arch/powerpc/mm/40x_mmu.c +++ b/arch/powerpc/mm/40x_mmu.c @@ -108,7 +108,7 @@ unsigned long __init mmu_mapin_ram(void) pmd_t *pmdp; unsigned long val = p | _PMD_SIZE_16M | _PAGE_HWEXEC | _PAGE_HWWRITE; - pmdp = pmd_offset(pgd_offset_k(v), v); + pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v); pmd_val(*pmdp++) = val; pmd_val(*pmdp++) = val; pmd_val(*pmdp++) = val; @@ -123,7 +123,7 @@ unsigned long __init mmu_mapin_ram(void) pmd_t *pmdp; unsigned long val = p | _PMD_SIZE_4M | _PAGE_HWEXEC | _PAGE_HWWRITE; - pmdp = pmd_offset(pgd_offset_k(v), v); + pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v); pmd_val(*pmdp) = val; v += LARGE_PAGE_SIZE_4M; diff --git a/include/asm-powerpc/mmu-40x.h b/include/asm-powerpc/mmu-40x.h new file mode 100644 index 000000000000..7d37f77043ac --- /dev/null +++ b/include/asm-powerpc/mmu-40x.h @@ -0,0 +1,65 @@ +#ifndef _ASM_POWERPC_MMU_40X_H_ +#define _ASM_POWERPC_MMU_40X_H_ + +/* + * PPC40x support + */ + +#define PPC40X_TLB_SIZE 64 + +/* + * TLB entries are defined by a "high" tag portion and a "low" data + * portion. On all architectures, the data portion is 32-bits. + * + * TLB entries are managed entirely under software control by reading, + * writing, and searchoing using the 4xx-specific tlbre, tlbwr, and tlbsx + * instructions. + */ + +#define TLB_LO 1 +#define TLB_HI 0 + +#define TLB_DATA TLB_LO +#define TLB_TAG TLB_HI + +/* Tag portion */ + +#define TLB_EPN_MASK 0xFFFFFC00 /* Effective Page Number */ +#define TLB_PAGESZ_MASK 0x00000380 +#define TLB_PAGESZ(x) (((x) & 0x7) << 7) +#define PAGESZ_1K 0 +#define PAGESZ_4K 1 +#define PAGESZ_16K 2 +#define PAGESZ_64K 3 +#define PAGESZ_256K 4 +#define PAGESZ_1M 5 +#define PAGESZ_4M 6 +#define PAGESZ_16M 7 +#define TLB_VALID 0x00000040 /* Entry is valid */ + +/* Data portion */ + +#define TLB_RPN_MASK 0xFFFFFC00 /* Real Page Number */ +#define TLB_PERM_MASK 0x00000300 +#define TLB_EX 0x00000200 /* Instruction execution allowed */ +#define TLB_WR 0x00000100 /* Writes permitted */ +#define TLB_ZSEL_MASK 0x000000F0 +#define TLB_ZSEL(x) (((x) & 0xF) << 4) +#define TLB_ATTR_MASK 0x0000000F +#define TLB_W 0x00000008 /* Caching is write-through */ +#define TLB_I 0x00000004 /* Caching is inhibited */ +#define TLB_M 0x00000002 /* Memory is coherent */ +#define TLB_G 0x00000001 /* Memory is guarded from prefetch */ + +#ifndef __ASSEMBLY__ + +typedef unsigned long phys_addr_t; + +typedef struct { + unsigned long id; + unsigned long vdso_base; +} mm_context_t; + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_POWERPC_MMU_40X_H_ */ diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index d44d211e7588..4c0e1b4f975c 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h @@ -8,6 +8,9 @@ #elif defined(CONFIG_PPC_STD_MMU) /* 32-bit classic hash table MMU */ # include +#elif defined(CONFIG_40x) +/* 40x-style software loaded TLB */ +# include #elif defined(CONFIG_44x) /* 44x-style software loaded TLB */ # include From aab69292e4efd38181cd300d9b83b12592643d6c Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:29:11 -0500 Subject: [PATCH 0136/2804] [POWERPC] 40x decrementer fixes Allow generic_calibrate_decr to work for 40x platforms. Given that the hardware behavior is identical, this also changes the set_dec function to reload the PIT on 40x to match the behavior 44x currently has. Signed-off-by: Josh Boyer --- arch/powerpc/kernel/time.c | 2 +- include/asm-powerpc/time.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index c85d9b0d9042..b5944d8e3802 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -866,7 +866,7 @@ void __init generic_calibrate_decr(void) "(not found)\n"); } -#ifdef CONFIG_BOOKE +#if defined(CONFIG_BOOKE) || defined(CONFIG_40x) /* Set the time base to zero */ mtspr(SPRN_TBWL, 0); mtspr(SPRN_TBWU, 0); diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h index d7f5ddfbaac7..fdc271ebe41c 100644 --- a/include/asm-powerpc/time.h +++ b/include/asm-powerpc/time.h @@ -174,7 +174,7 @@ static inline unsigned int get_dec(void) static inline void set_dec(int val) { #if defined(CONFIG_40x) - return; /* Have to let it auto-reload */ + mtspr(SPRN_PIT, val); #elif defined(CONFIG_8xx_CPU6) set_dec_cpu6(val); #else From 1daa194a87b3ea77760b4b5361eb47900dfc00a9 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:29:36 -0500 Subject: [PATCH 0137/2804] [POWERPC] Fix 40x build Remove inclusion of __res on 40x. We don't need it in arch/powerpc Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/kernel/head_40x.S | 1 - arch/powerpc/kernel/ppc_ksyms.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index fe8afb60290e..a8e045773a92 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index a20f1951a5ce..430c502179c3 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -180,7 +180,7 @@ EXPORT_SYMBOL(cacheable_memcpy); EXPORT_SYMBOL(cpm_install_handler); EXPORT_SYMBOL(cpm_free_handler); #endif /* CONFIG_8xx */ -#if defined(CONFIG_8xx) || defined(CONFIG_40x) +#if defined(CONFIG_8xx) EXPORT_SYMBOL(__res); #endif From 142b58ee5600e592e83ff7d2e4672e6cb0b39c27 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:29:55 -0500 Subject: [PATCH 0138/2804] [POWERPC] Bamboo DTS AMCC Bamboo board DTS Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/bamboo.dts | 244 +++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 arch/powerpc/boot/dts/bamboo.dts diff --git a/arch/powerpc/boot/dts/bamboo.dts b/arch/powerpc/boot/dts/bamboo.dts new file mode 100644 index 000000000000..bdd56b0e9460 --- /dev/null +++ b/arch/powerpc/boot/dts/bamboo.dts @@ -0,0 +1,244 @@ +/* + * Device Tree Source for AMCC Bamboo + * + * Copyright (c) 2006, 2007 IBM Corp. + * Josh Boyer + * + * FIXME: Draft only! + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/ { + #address-cells = <2>; + #size-cells = <1>; + model = "amcc,bamboo"; + compatible = "amcc,bamboo"; + dcr-parent = <&/cpus/PowerPC,440EP@0>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,440EP@0 { + device_type = "cpu"; + reg = <0>; + clock-frequency = <0>; /* Filled in by zImage */ + timebase-frequency = <0>; /* Filled in by zImage */ + i-cache-line-size = <20>; + d-cache-line-size = <20>; + i-cache-size = <8000>; + d-cache-size = <8000>; + dcr-controller; + dcr-access-method = "native"; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0 0>; /* Filled in by zImage */ + }; + + UIC0: interrupt-controller0 { + compatible = "ibm,uic-440ep","ibm,uic"; + interrupt-controller; + cell-index = <0>; + dcr-reg = <0c0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + }; + + UIC1: interrupt-controller1 { + compatible = "ibm,uic-440ep","ibm,uic"; + interrupt-controller; + cell-index = <1>; + dcr-reg = <0d0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <1e 4 1f 4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + SDR0: sdr { + compatible = "ibm,sdr-440ep"; + dcr-reg = <00e 002>; + }; + + CPR0: cpr { + compatible = "ibm,cpr-440ep"; + dcr-reg = <00c 002>; + }; + + plb { + compatible = "ibm,plb-440ep", "ibm,plb-440gp", "ibm,plb4"; + #address-cells = <2>; + #size-cells = <1>; + ranges; + clock-frequency = <0>; /* Filled in by zImage */ + + SDRAM0: sdram { + compatible = "ibm,sdram-440ep", "ibm,sdram-405gp"; + dcr-reg = <010 2>; + }; + + DMA0: dma { + compatible = "ibm,dma-440ep", "ibm,dma-440gp"; + dcr-reg = <100 027>; + }; + + MAL0: mcmal { + compatible = "ibm,mcmal-440ep", "ibm,mcmal-440gp", "ibm,mcmal"; + dcr-reg = <180 62>; + num-tx-chans = <4>; + num-rx-chans = <4>; + interrupt-parent = <&MAL0>; + interrupts = <0 1 2 3 4>; + #interrupt-cells = <1>; + interrupt-map = ; + }; + + POB0: opb { + compatible = "ibm,opb-440ep", "ibm,opb-440gp", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + /* Bamboo is oddball in the 44x world and doesn't use the ERPN + * bits. + */ + ranges = <00000000 0 00000000 80000000 + 80000000 0 80000000 80000000>; + interrupt-parent = <&UIC1>; + interrupts = <7 4>; + clock-frequency = <0>; /* Filled in by zImage */ + + EBC0: ebc { + compatible = "ibm,ebc-440ep", "ibm,ebc-440gp", "ibm,ebc"; + dcr-reg = <012 2>; + #address-cells = <2>; + #size-cells = <1>; + clock-frequency = <0>; /* Filled in by zImage */ + ranges; + interrupts = <5 1>; + interrupt-parent = <&UIC1>; + }; + + UART0: serial@ef600300 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; /* Filled in by zImage */ + current-speed = <1c200>; + interrupt-parent = <&UIC0>; + interrupts = <0 4>; + }; + + UART1: serial@ef600400 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <1 4>; + }; + + UART2: serial@ef600500 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <3 4>; + }; + + UART3: serial@ef600600 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <4 4>; + }; + + IIC0: i2c@ef600700 { + device_type = "i2c"; + compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <2 4>; + }; + + IIC1: i2c@ef600800 { + device_type = "i2c"; + compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <7 4>; + }; + + ZMII0: emac-zmii@ef600d00 { + device_type = "zmii-interface"; + compatible = "ibm,zmii-440ep", "ibm,zmii-440gp", "ibm,zmii"; + reg = ; + }; + + EMAC0: ethernet@ef600e00 { + device_type = "network"; + compatible = "ibm,emac-440ep", "ibm,emac-440gp", "ibm,emac"; + interrupt-parent = <&UIC1>; + interrupts = <1c 4 1d 4>; + reg = ; + local-mac-address = [000000000000]; + mal-device = <&MAL0>; + mal-tx-channel = <0 1>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000001>; + zmii-device = <&ZMII0>; + zmii-channel = <0>; + }; + + EMAC1: ethernet@ef600f00 { + device_type = "network"; + compatible = "ibm,emac-440ep", "ibm,emac-440gp", "ibm,emac"; + interrupt-parent = <&UIC1>; + interrupts = <1e 4 1f 4>; + reg = ; + local-mac-address = [000000000000]; + mal-device = <&MAL0>; + mal-tx-channel = <2 3>; + mal-rx-channel = <1>; + cell-index = <1>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000001>; + zmii-device = <&ZMII0>; + zmii-channel = <1>; + }; + }; + }; + + chosen { + linux,stdout-path = "/plb/opb/serial@ef600300"; + bootargs = "console=ttyS0,115200"; + }; +}; From 8c1449bdb4c7e9c4492ba18ded70fd8669eeffae Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:30:14 -0500 Subject: [PATCH 0139/2804] [POWERPC] Bamboo board support Add support for the AMCC Bamboo board Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/configs/bamboo_defconfig | 775 ++++++++++++++++++++++++++ arch/powerpc/platforms/44x/Kconfig | 15 +- arch/powerpc/platforms/44x/Makefile | 1 + arch/powerpc/platforms/44x/bamboo.c | 66 +++ 4 files changed, 850 insertions(+), 7 deletions(-) create mode 100644 arch/powerpc/configs/bamboo_defconfig create mode 100644 arch/powerpc/platforms/44x/bamboo.c diff --git a/arch/powerpc/configs/bamboo_defconfig b/arch/powerpc/configs/bamboo_defconfig new file mode 100644 index 000000000000..b592dec4640f --- /dev/null +++ b/arch/powerpc/configs/bamboo_defconfig @@ -0,0 +1,775 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc1 +# Fri Aug 3 10:46:53 2007 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +CONFIG_44x=y +# CONFIG_E200 is not set +CONFIG_PPC_FPU=y +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set +CONFIG_PPC_DCR_NATIVE=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_DCR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +CONFIG_BAMBOO=y +# CONFIG_EBONY is not set +CONFIG_440EP=y +CONFIG_IBM440EP_ERR42=y +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPM2 is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_PROC_DEVICETREE=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +CONFIG_SECCOMP=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="bamboo.dts" +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x01000000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +# CONFIG_MTD is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=35000 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_XILINX_SYSACE is not set +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +CONFIG_MACINTOSH_DRIVERS=y +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ARCNET is not set +# CONFIG_NET_ETHERNET is not set +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +CONFIG_NETDEV_10000=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_DEBUGGER=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set +# CONFIG_BDI_SWITCH is not set +CONFIG_PPC_EARLY_DEBUG=y +# CONFIG_PPC_EARLY_DEBUG_LPAR is not set +# CONFIG_PPC_EARLY_DEBUG_G5 is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set +# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set +# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set +# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set +# CONFIG_PPC_EARLY_DEBUG_BEAT is not set +CONFIG_PPC_EARLY_DEBUG_44x=y +CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0xef600300 +CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x0 + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_HW=y diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 1b3e008fd148..c7cc12a2f269 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -1,10 +1,10 @@ -#config BAMBOO -# bool "Bamboo" -# depends on 44x -# default n -# select 440EP -# help -# This option enables support for the IBM PPC440EP evaluation board. +config BAMBOO + bool "Bamboo" + depends on 44x + default n + select 440EP + help + This option enables support for the IBM PPC440EP evaluation board. config EBONY bool "Ebony" @@ -35,6 +35,7 @@ config 440EP bool select PPC_FPU select IBM440EP_ERR42 +# select IBM_NEW_EMAC_ZMII config 440GP bool diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index 41d0a18a0e44..47ccc3659e34 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_44x) := misc_44x.o obj-$(CONFIG_EBONY) += ebony.o +obj-$(CONFIG_BAMBOO) += bamboo.o diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c new file mode 100644 index 000000000000..5522f1f9642e --- /dev/null +++ b/arch/powerpc/platforms/44x/bamboo.c @@ -0,0 +1,66 @@ +/* + * Bamboo board specific routines + * + * Wade Farnsworth + * Copyright 2004 MontaVista Software Inc. + * + * Rewritten and ported to the merged powerpc tree: + * Josh Boyer + * Copyright 2007 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 "44x.h" + +static struct of_device_id bamboo_of_bus[] = { + { .compatible = "ibm,plb", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init bamboo_device_probe(void) +{ + if (!machine_is(bamboo)) + return 0; + + of_platform_bus_probe(NULL, bamboo_of_bus, NULL); + + return 0; +} +device_initcall(bamboo_device_probe); + +static int __init bamboo_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "amcc,bamboo")) + return 0; + + return 1; +} + +static void __init bamboo_setup_arch(void) +{ +} + +define_machine(bamboo) { + .name = "Bamboo", + .probe = bamboo_probe, + .setup_arch = bamboo_setup_arch, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .restart = ppc44x_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; From 2ba4573cdaf98b0f3acb8795a66f412c1c41284a Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 20 Aug 2007 07:30:32 -0500 Subject: [PATCH 0140/2804] [POWERPC] Bamboo zImage wrapper Add a bootwrapper for the AMCC 440EP Bamboo Eval board. This also adds a common fixup_clock function for all 440EP(x) chips. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/boot/44x.h | 1 + arch/powerpc/boot/4xx.c | 82 +++++++++++++++++++++++++++++ arch/powerpc/boot/4xx.h | 1 + arch/powerpc/boot/Makefile | 5 +- arch/powerpc/boot/bamboo.c | 45 ++++++++++++++++ arch/powerpc/boot/dcr.h | 10 ++++ arch/powerpc/boot/treeboot-bamboo.c | 27 ++++++++++ 7 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/boot/bamboo.c create mode 100644 arch/powerpc/boot/treeboot-bamboo.c diff --git a/arch/powerpc/boot/44x.h b/arch/powerpc/boot/44x.h index 490a1cbdf1ed..ad33dcc95ae5 100644 --- a/arch/powerpc/boot/44x.h +++ b/arch/powerpc/boot/44x.h @@ -11,5 +11,6 @@ #define _PPC_BOOT_44X_H_ void ebony_init(void *mac0, void *mac1); +void bamboo_init(void); #endif /* _PPC_BOOT_44X_H_ */ diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c index 59026e4585dc..642d8780bb31 100644 --- a/arch/powerpc/boot/4xx.c +++ b/arch/powerpc/boot/4xx.c @@ -108,3 +108,85 @@ void ibm4xx_fixup_ebc_ranges(const char *ebc) setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32)); } + +#define SPRN_CCR1 0x378 +void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) +{ + u32 cpu, plb, opb, ebc, tb, uart0, m, vco; + u32 reg; + u32 fwdva, fwdvb, fbdv, lfbdv, opbdv0, perdv0, spcid0, prbdv0, tmp; + + mtdcr(DCRN_CPR0_ADDR, CPR0_PLLD0); + reg = mfdcr(DCRN_CPR0_DATA); + tmp = (reg & 0x000F0000) >> 16; + fwdva = tmp ? tmp : 16; + tmp = (reg & 0x00000700) >> 8; + fwdvb = tmp ? tmp : 8; + tmp = (reg & 0x1F000000) >> 24; + fbdv = tmp ? tmp : 32; + lfbdv = (reg & 0x0000007F); + + mtdcr(DCRN_CPR0_ADDR, CPR0_OPBD0); + reg = mfdcr(DCRN_CPR0_DATA); + tmp = (reg & 0x03000000) >> 24; + opbdv0 = tmp ? tmp : 4; + + mtdcr(DCRN_CPR0_ADDR, CPR0_PERD0); + reg = mfdcr(DCRN_CPR0_DATA); + tmp = (reg & 0x07000000) >> 24; + perdv0 = tmp ? tmp : 8; + + mtdcr(DCRN_CPR0_ADDR, CPR0_PRIMBD0); + reg = mfdcr(DCRN_CPR0_DATA); + tmp = (reg & 0x07000000) >> 24; + prbdv0 = tmp ? tmp : 8; + + mtdcr(DCRN_CPR0_ADDR, CPR0_SCPID); + reg = mfdcr(DCRN_CPR0_DATA); + tmp = (reg & 0x03000000) >> 24; + spcid0 = tmp ? tmp : 4; + + /* Calculate M */ + mtdcr(DCRN_CPR0_ADDR, CPR0_PLLC0); + reg = mfdcr(DCRN_CPR0_DATA); + tmp = (reg & 0x03000000) >> 24; + if (tmp == 0) { /* PLL output */ + tmp = (reg & 0x20000000) >> 29; + if (!tmp) /* PLLOUTA */ + m = fbdv * lfbdv * fwdva; + else + m = fbdv * lfbdv * fwdvb; + } + else if (tmp == 1) /* CPU output */ + m = fbdv * fwdva; + else + m = perdv0 * opbdv0 * fwdvb; + + vco = (m * sysclk) + (m >> 1); + cpu = vco / fwdva; + plb = vco / fwdvb / prbdv0; + opb = plb / opbdv0; + ebc = plb / perdv0; + + /* FIXME */ + uart0 = ser_clk; + + /* Figure out timebase. Either CPU or default TmrClk */ + asm volatile ( + "mfspr %0,%1\n" + : + "=&r"(reg) : "i"(SPRN_CCR1)); + if (reg & 0x0080) + tb = 25000000; /* TmrClk is 25MHz */ + else + tb = cpu; + + dt_fixup_cpu_clocks(cpu, tb, 0); + dt_fixup_clock("/plb", plb); + dt_fixup_clock("/plb/opb", opb); + dt_fixup_clock("/plb/opb/ebc", ebc); + dt_fixup_clock("/plb/opb/serial@ef600300", uart0); + dt_fixup_clock("/plb/opb/serial@ef600400", uart0); + dt_fixup_clock("/plb/opb/serial@ef600500", uart0); + dt_fixup_clock("/plb/opb/serial@ef600600", uart0); +} diff --git a/arch/powerpc/boot/4xx.h b/arch/powerpc/boot/4xx.h index 65008427e03f..8f26e480dcd3 100644 --- a/arch/powerpc/boot/4xx.h +++ b/arch/powerpc/boot/4xx.h @@ -16,5 +16,6 @@ void ibm44x_dbcr_reset(void); void ibm40x_dbcr_reset(void); void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1); void ibm4xx_fixup_ebc_ranges(const char *ebc); +void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk); #endif /* _POWERPC_BOOT_4XX_H_ */ diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index b4869e61b738..54a72108bcc3 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -44,10 +44,10 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ - 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c + 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ - ps3-head.S ps3-hvcall.S ps3.c + ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -142,6 +142,7 @@ ifneq ($(CONFIG_DEVICE_TREE),"") image-$(CONFIG_PPC_83xx) += cuImage.83xx image-$(CONFIG_PPC_85xx) += cuImage.85xx image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony +image-$(CONFIG_BAMBOO) += treeImage.bamboo endif # For 32-bit powermacs, build the COFF and miboot images diff --git a/arch/powerpc/boot/bamboo.c b/arch/powerpc/boot/bamboo.c new file mode 100644 index 000000000000..bc097694b445 --- /dev/null +++ b/arch/powerpc/boot/bamboo.c @@ -0,0 +1,45 @@ +/* + * Copyright IBM Corporation, 2007 + * Josh Boyer + * + * Based on ebony wrapper: + * Copyright 2007 David Gibson, IBM Corporation. + * + * Clocking code based on code by: + * Stefan Roese + * + * 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 + */ +#include +#include +#include "types.h" +#include "elf.h" +#include "string.h" +#include "stdio.h" +#include "page.h" +#include "ops.h" +#include "dcr.h" +#include "4xx.h" +#include "44x.h" + +extern char _dtb_start[]; +extern char _dtb_end[]; + +static void bamboo_fixups(void) +{ + unsigned long sysclk = 33333333; + + ibm440ep_fixup_clocks(sysclk, 11059200); + ibm4xx_fixup_memsize(); + ibm4xx_quiesce_eth((u32 *)0xef600e00, (u32 *)0xef600f00); +} + +void bamboo_init(void) +{ + platform_ops.fixups = bamboo_fixups; + platform_ops.exit = ibm44x_dbcr_reset; + ft_init(_dtb_start, 0, 32); + serial_console_init(); +} diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h index c95d1a9222c9..e158311c501b 100644 --- a/arch/powerpc/boot/dcr.h +++ b/arch/powerpc/boot/dcr.h @@ -124,4 +124,14 @@ static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR, SDRAM0_B2C #define DCRN_MAL0_CFG 0x180 #define MAL_RESET 0x80000000 +/* 440EP Clock/Power-on Reset regs */ +#define DCRN_CPR0_ADDR 0xc +#define DCRN_CPR0_DATA 0xd +#define CPR0_PLLD0 0x60 +#define CPR0_OPBD0 0xc0 +#define CPR0_PERD0 0xe0 +#define CPR0_PRIMBD0 0xa0 +#define CPR0_SCPID 0x120 +#define CPR0_PLLC0 0x40 + #endif /* _PPC_BOOT_DCR_H_ */ diff --git a/arch/powerpc/boot/treeboot-bamboo.c b/arch/powerpc/boot/treeboot-bamboo.c new file mode 100644 index 000000000000..1f1fe5aaac12 --- /dev/null +++ b/arch/powerpc/boot/treeboot-bamboo.c @@ -0,0 +1,27 @@ +/* + * Copyright IBM Corporation, 2007 + * Josh Boyer + * + * Based on ebony wrapper: + * Copyright 2007 David Gibson, 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; version 2 of the License + */ +#include "ops.h" +#include "stdio.h" +#include "44x.h" + +extern char _end[]; + +BSS_STACK(4096); + +void platform_init(void) +{ + unsigned long end_of_ram = 0x8000000; + unsigned long avail_ram = end_of_ram - (unsigned long)_end; + + simple_alloc_init(_end, avail_ram, 32, 64); + bamboo_init(); +} From 556ecf9be66f4d493e19bc71a7ce84366d512b71 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sat, 18 Aug 2007 04:27:17 +1000 Subject: [PATCH 0141/2804] [POWERPC] Advertise correct IDE mode on Pegasos2 The built-in IDE controller is configured in legacy mode, but the PCI registers advertise native mode. Force the PCI class into legacy mode. This allows pata_via to access two drives. The Pegasos specific irq enforcement in the via82cxxx driver must stay because there is apparently no generic way to setup irq per channel. Tested on Pegasos2 with firmware version 20040810, and two IDE disks. Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 11 ++++++++--- arch/powerpc/platforms/chrp/pci.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index a1d582e38627..29c2160bcbb5 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -2046,6 +2046,7 @@ static void __init fixup_device_tree_maple(void) /* * Pegasos and BriQ lacks the "ranges" property in the isa node * Pegasos needs decimal IRQ 14/15, not hexadecimal + * Pegasos has the IDE configured in legacy mode, but advertised as native */ static void __init fixup_device_tree_chrp(void) { @@ -2083,9 +2084,13 @@ static void __init fixup_device_tree_chrp(void) prom_printf("Fixing up IDE interrupt on Pegasos...\n"); prop[0] = 14; prop[1] = 0x0; - prop[2] = 15; - prop[3] = 0x0; - prom_setprop(ph, name, "interrupts", prop, 4*sizeof(u32)); + prom_setprop(ph, name, "interrupts", prop, 2*sizeof(u32)); + prom_printf("Fixing up IDE class-code on Pegasos...\n"); + rc = prom_getprop(ph, "class-code", prop, sizeof(u32)); + if (rc == sizeof(u32)) { + prop[0] &= ~0x5; + prom_setprop(ph, name, "class-code", prop, sizeof(u32)); + } } } #else diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index 0c6dba9823e9..974952ed15cb 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -338,3 +338,32 @@ void chrp_pci_fixup_winbond_ata(struct pci_dev *sl82c105) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, chrp_pci_fixup_winbond_ata); + +/* Pegasos2 firmware version 20040810 configures the built-in IDE controller + * in legacy mode, but sets the PCI registers to PCI native mode. + * The chip can only operate in legacy mode, so force the PCI class into legacy + * mode as well. The same fixup must be done to the class-code property in + * the IDE node /pci@80000000/ide@C,1 + */ +static void chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) +{ + u8 progif; + struct pci_dev *viaisa; + + if (!machine_is(chrp) || _chrp_type != _CHRP_Pegasos) + return; + if (viaide->irq != 14) + return; + + viaisa = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); + if (!viaisa) + return; + printk("Fixing VIA IDE, force legacy mode on '%s'\n", viaide->dev.bus_id); + + pci_read_config_byte(viaide, PCI_CLASS_PROG, &progif); + pci_write_config_byte(viaide, PCI_CLASS_PROG, progif & ~0x5); + viaide->class &= ~0x5; + + pci_dev_put(viaisa); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); From 16a15a30f8a09af6ce2dc4fd6eec9b454c1fe488 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 20 Aug 2007 14:58:36 +1000 Subject: [PATCH 0142/2804] [POWERPC] iSeries: Clean up lparmap mess We need to have xLparMap in head_64.S so that it is at a fixed address (because the linker will not resolve (address & 0xffffffff) for us). But the assembler miscalculates the KERNEL_VSID() expressions. So put the confusing expressions into asm-offsets.c. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 7 ------ arch/powerpc/kernel/asm-offsets.c | 8 +++++++ arch/powerpc/kernel/head_64.S | 27 +++++++++++++++------- arch/powerpc/kernel/lparmap.c | 32 -------------------------- include/asm-powerpc/iseries/lpar_map.h | 3 +++ include/asm-powerpc/page_64.h | 2 +- 6 files changed, 31 insertions(+), 48 deletions(-) delete mode 100644 arch/powerpc/kernel/lparmap.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index a4850dd8764f..967afc517d8f 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -80,13 +80,6 @@ ifneq ($(CONFIG_PPC_INDIRECT_IO),y) obj-y += iomap.o endif -ifeq ($(CONFIG_PPC_ISERIES),y) -CFLAGS_lparmap.s += -g0 -extra-y += lparmap.s -$(obj)/head_64.o: $(obj)/lparmap.s -AFLAGS_head_64.o += -I$(obj) -endif - else # stuff used from here for ARCH=ppc smpobj-$(CONFIG_SMP) += smp.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 2cb1d9487796..a40805328f9b 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -312,5 +312,13 @@ int main(void) #ifdef CONFIG_BUG DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); #endif + +#ifdef CONFIG_PPC_ISERIES + /* the assembler miscalculates the VSID values */ + DEFINE(PAGE_OFFSET_ESID, GET_ESID(PAGE_OFFSET)); + DEFINE(PAGE_OFFSET_VSID, KERNEL_VSID(PAGE_OFFSET)); + DEFINE(VMALLOC_START_ESID, GET_ESID(VMALLOC_START)); + DEFINE(VMALLOC_START_VSID, KERNEL_VSID(VMALLOC_START)); +#endif return 0; } diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 171800002ede..1e6d9cc06ca0 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -34,6 +34,7 @@ #include #include #include +#include #define DO_SOFT_DISABLE @@ -1519,8 +1520,8 @@ _GLOBAL(do_stab_bolted) * Space for CPU0's segment table. * * On iSeries, the hypervisor must fill in at least one entry before - * we get control (with relocate on). The address is give to the hv - * as a page number (see xLparMap in lpardata.c), so this must be at a + * we get control (with relocate on). The address is given to the hv + * as a page number (see xLparMap below), so this must be at a * fixed address (the linker can't compute (u64)&initial_stab >> * PAGE_SHIFT). */ @@ -1542,12 +1543,22 @@ fwnmi_data_area: * both pSeries and iSeries */ #ifdef CONFIG_PPC_ISERIES . = LPARMAP_PHYS -#include "lparmap.s" -/* - * This ".text" is here for old compilers that generate a trailing - * .note section when compiling .c files to .s - */ - .text + .globl xLparMap +xLparMap: + .quad HvEsidsToMap /* xNumberEsids */ + .quad HvRangesToMap /* xNumberRanges */ + .quad STAB0_PAGE /* xSegmentTableOffs */ + .zero 40 /* xRsvd */ + /* xEsids (HvEsidsToMap entries of 2 quads) */ + .quad PAGE_OFFSET_ESID /* xKernelEsid */ + .quad PAGE_OFFSET_VSID /* xKernelVsid */ + .quad VMALLOC_START_ESID /* xKernelEsid */ + .quad VMALLOC_START_VSID /* xKernelVsid */ + /* xRanges (HvRangesToMap entries of 3 quads) */ + .quad HvPagesToMap /* xPages */ + .quad 0 /* xOffset */ + .quad PAGE_OFFSET_VSID << (SID_SHIFT - HW_PAGE_SHIFT) /* xVPN */ + #endif /* CONFIG_PPC_ISERIES */ . = 0x8000 diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c deleted file mode 100644 index af11285ffbd1..000000000000 --- a/arch/powerpc/kernel/lparmap.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2005 Stephen Rothwell IBM Corp. - * - * 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 - -/* The # is to stop gcc trying to make .text nonexecutable */ -const struct LparMap __attribute__((__section__(".text #"))) xLparMap = { - .xNumberEsids = HvEsidsToMap, - .xNumberRanges = HvRangesToMap, - .xSegmentTableOffs = STAB0_PAGE, - - .xEsids = { - { .xKernelEsid = GET_ESID(PAGE_OFFSET), - .xKernelVsid = KERNEL_VSID(PAGE_OFFSET), }, - { .xKernelEsid = GET_ESID(VMALLOC_START), - .xKernelVsid = KERNEL_VSID(VMALLOC_START), }, - }, - - .xRanges = { - { .xPages = HvPagesToMap, - .xOffset = 0, - .xVPN = KERNEL_VSID(PAGE_OFFSET) << (SID_SHIFT - HW_PAGE_SHIFT), - }, - }, -}; diff --git a/include/asm-powerpc/iseries/lpar_map.h b/include/asm-powerpc/iseries/lpar_map.h index 2ec384d66abb..5e9f3e128ee2 100644 --- a/include/asm-powerpc/iseries/lpar_map.h +++ b/include/asm-powerpc/iseries/lpar_map.h @@ -22,6 +22,8 @@ #include +#endif + /* * The iSeries hypervisor will set up mapping for one or more * ESID/VSID pairs (in SLB/segment registers) and will set up @@ -56,6 +58,7 @@ /* Hypervisor initially maps 32MB of the load area */ #define HvPagesToMap 8192 +#ifndef __ASSEMBLY__ struct LparMap { u64 xNumberEsids; // Number of ESID/VSID pairs u64 xNumberRanges; // Number of VA ranges to map diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h index 4ceb1132c480..56a2df0f6836 100644 --- a/include/asm-powerpc/page_64.h +++ b/include/asm-powerpc/page_64.h @@ -28,7 +28,7 @@ /* Segment size */ #define SID_SHIFT 28 -#define SID_MASK 0xfffffffffUL +#define SID_MASK ASM_CONST(0xfffffffff) #define ESID_MASK 0xfffffffff0000000UL #define GET_ESID(x) (((x) >> SID_SHIFT) & SID_MASK) From 4b218e9bb2fbbc57b5a05de41d77c056a134528c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 02:36:19 +1000 Subject: [PATCH 0143/2804] [POWERPC] Whitespace cleanup in arch/powerpc Signed-off-by: Scott Wood Signed-off-by: Paul Mackerras --- arch/powerpc/boot/dts/mpc8272ads.dts | 346 ++++++++++++------------ arch/powerpc/kernel/irq.c | 4 +- arch/powerpc/platforms/8xx/m8xx_setup.c | 70 ++--- arch/powerpc/sysdev/commproc.c | 20 +- arch/powerpc/sysdev/cpm2_common.c | 2 +- 5 files changed, 222 insertions(+), 220 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts index 1934b800278e..4d09dcad2537 100644 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -10,207 +10,209 @@ */ / { - model = "MPC8272ADS"; - compatible = "MPC8260ADS"; - #address-cells = <1>; - #size-cells = <1>; + model = "MPC8272ADS"; + compatible = "MPC8260ADS"; + #address-cells = <1>; + #size-cells = <1>; - cpus { - #address-cells = <1>; - #size-cells = <0>; + cpus { + #address-cells = <1>; + #size-cells = <0>; - PowerPC,8272@0 { - device_type = "cpu"; - reg = <0>; - d-cache-line-size = <20>; // 32 bytes - i-cache-line-size = <20>; // 32 bytes - d-cache-size = <4000>; // L1, 16K - i-cache-size = <4000>; // L1, 16K - timebase-frequency = <0>; - bus-frequency = <0>; - clock-frequency = <0>; - 32-bit; - }; - }; + PowerPC,8272@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <4000>; // L1, 16K + i-cache-size = <4000>; // L1, 16K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + 32-bit; + }; + }; - pci_pic: interrupt-controller@f8200000 { - #address-cells = <0>; - #interrupt-cells = <2>; - interrupt-controller; - reg = ; - built-in; - device_type = "pci-pic"; - }; - memory { - device_type = "memory"; - reg = <00000000 4000000 f4500000 00000020>; - }; + pci_pic: interrupt-controller@f8200000 { + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + reg = ; + built-in; + device_type = "pci-pic"; + }; - chosen { - name = "chosen"; - linux,platform = <0>; + memory { + device_type = "memory"; + reg = <00000000 4000000 f4500000 00000020>; + }; + + chosen { + name = "chosen"; + linux,platform = <0>; interrupt-controller = <&Cpm_pic>; - }; + }; - soc8272@f0000000 { - #address-cells = <1>; - #size-cells = <1>; - #interrupt-cells = <2>; - device_type = "soc"; - ranges = <00000000 f0000000 00053000>; - reg = ; + soc8272@f0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <00000000 f0000000 00053000>; + reg = ; + + mdio@0 { + device_type = "mdio"; + compatible = "fs_enet"; + reg = <0 0>; + #address-cells = <1>; + #size-cells = <0>; - mdio@0 { - device_type = "mdio"; - compatible = "fs_enet"; - reg = <0 0>; - #address-cells = <1>; - #size-cells = <0>; phy0:ethernet-phy@0 { interrupt-parent = <&Cpm_pic>; - interrupts = <17 4>; - reg = <0>; - bitbang = [ 12 12 13 02 02 01 ]; - device_type = "ethernet-phy"; - }; + interrupts = <17 4>; + reg = <0>; + bitbang = [ 12 12 13 02 02 01 ]; + device_type = "ethernet-phy"; + }; + phy1:ethernet-phy@1 { interrupt-parent = <&Cpm_pic>; - interrupts = <17 4>; - bitbang = [ 12 12 13 02 02 01 ]; - reg = <3>; - device_type = "ethernet-phy"; - }; - }; + interrupts = <17 4>; + bitbang = [ 12 12 13 02 02 01 ]; + reg = <3>; + device_type = "ethernet-phy"; + }; + }; - ethernet@24000 { - #address-cells = <1>; - #size-cells = <0>; - device_type = "network"; - device-id = <1>; - compatible = "fs_enet"; - model = "FCC"; - reg = <11300 20 8400 100 11380 30>; - mac-address = [ 00 11 2F 99 43 54 ]; - interrupts = <20 2>; + ethernet@24000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + device-id = <1>; + compatible = "fs_enet"; + model = "FCC"; + reg = <11300 20 8400 100 11380 30>; + mac-address = [ 00 11 2F 99 43 54 ]; + interrupts = <20 2>; interrupt-parent = <&Cpm_pic>; phy-handle = <&Phy0>; - rx-clock = <13>; - tx-clock = <12>; - }; + rx-clock = <13>; + tx-clock = <12>; + }; - ethernet@25000 { - device_type = "network"; - device-id = <2>; - compatible = "fs_enet"; - model = "FCC"; - reg = <11320 20 8500 100 113b0 30>; - mac-address = [ 00 11 2F 99 44 54 ]; - interrupts = <21 2>; + ethernet@25000 { + device_type = "network"; + device-id = <2>; + compatible = "fs_enet"; + model = "FCC"; + reg = <11320 20 8500 100 113b0 30>; + mac-address = [ 00 11 2F 99 44 54 ]; + interrupts = <21 2>; interrupt-parent = <&Cpm_pic>; phy-handle = <&Phy1>; - rx-clock = <17>; - tx-clock = <18>; - }; + rx-clock = <17>; + tx-clock = <18>; + }; - cpm@f0000000 { - #address-cells = <1>; - #size-cells = <1>; - #interrupt-cells = <2>; - device_type = "cpm"; - model = "CPM2"; - ranges = <00000000 00000000 20000>; - reg = <0 20000>; - command-proc = <119c0>; - brg-frequency = <17D7840>; - cpm_clk = ; + cpm@f0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "cpm"; + model = "CPM2"; + ranges = <00000000 00000000 20000>; + reg = <0 20000>; + command-proc = <119c0>; + brg-frequency = <17D7840>; + cpm_clk = ; - scc@11a00 { - device_type = "serial"; - compatible = "cpm_uart"; - model = "SCC"; - device-id = <1>; - reg = <11a00 20 8000 100>; - current-speed = <1c200>; - interrupts = <28 2>; + scc@11a00 { + device_type = "serial"; + compatible = "cpm_uart"; + model = "SCC"; + device-id = <1>; + reg = <11a00 20 8000 100>; + current-speed = <1c200>; + interrupts = <28 2>; interrupt-parent = <&Cpm_pic>; - clock-setup = <0 00ffffff>; - rx-clock = <1>; - tx-clock = <1>; - }; + clock-setup = <0 00ffffff>; + rx-clock = <1>; + tx-clock = <1>; + }; - scc@11a60 { - device_type = "serial"; - compatible = "cpm_uart"; - model = "SCC"; - device-id = <4>; - reg = <11a60 20 8300 100>; - current-speed = <1c200>; - interrupts = <2b 2>; + scc@11a60 { + device_type = "serial"; + compatible = "cpm_uart"; + model = "SCC"; + device-id = <4>; + reg = <11a60 20 8300 100>; + current-speed = <1c200>; + interrupts = <2b 2>; interrupt-parent = <&Cpm_pic>; - clock-setup = <1b ffffff00>; - rx-clock = <4>; - tx-clock = <4>; - }; + clock-setup = <1b ffffff00>; + rx-clock = <4>; + tx-clock = <4>; + }; + }; - }; - cpm_pic:interrupt-controller@10c00 { - #address-cells = <0>; - #interrupt-cells = <2>; - interrupt-controller; - reg = <10c00 80>; - built-in; - device_type = "cpm-pic"; - compatible = "CPM2"; - }; - pci@0500 { - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "8272"; - device_type = "pci"; - reg = <10430 4dc>; - clock-frequency = <3f940aa>; - interrupt-map-mask = ; - interrupt-map = < + cpm_pic:interrupt-controller@10c00 { + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + reg = <10c00 80>; + built-in; + device_type = "cpm-pic"; + compatible = "CPM2"; + }; - /* IDSEL 0x16 */ - b000 0 0 1 f8200000 40 8 - b000 0 0 2 f8200000 41 8 - b000 0 0 3 f8200000 42 8 - b000 0 0 4 f8200000 43 8 + pci@0500 { + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "8272"; + device_type = "pci"; + reg = <10430 4dc>; + clock-frequency = <3f940aa>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x16 */ + b000 0 0 1 f8200000 40 8 + b000 0 0 2 f8200000 41 8 + b000 0 0 3 f8200000 42 8 + b000 0 0 4 f8200000 43 8 - /* IDSEL 0x17 */ - b800 0 0 1 f8200000 43 8 - b800 0 0 2 f8200000 40 8 - b800 0 0 3 f8200000 41 8 - b800 0 0 4 f8200000 42 8 + /* IDSEL 0x17 */ + b800 0 0 1 f8200000 43 8 + b800 0 0 2 f8200000 40 8 + b800 0 0 3 f8200000 41 8 + b800 0 0 4 f8200000 42 8 - /* IDSEL 0x18 */ - c000 0 0 1 f8200000 42 8 - c000 0 0 2 f8200000 43 8 - c000 0 0 3 f8200000 40 8 - c000 0 0 4 f8200000 41 8>; + /* IDSEL 0x18 */ + c000 0 0 1 f8200000 42 8 + c000 0 0 2 f8200000 43 8 + c000 0 0 3 f8200000 40 8 + c000 0 0 4 f8200000 41 8>; interrupt-parent = <&Cpm_pic>; - interrupts = <14 8>; - bus-range = <0 0>; - ranges = <02000000 0 80000000 80000000 0 40000000 - 01000000 0 00000000 f6000000 0 02000000>; - }; + interrupts = <14 8>; + bus-range = <0 0>; + ranges = <02000000 0 80000000 80000000 0 40000000 + 01000000 0 00000000 f6000000 0 02000000>; + }; /* May need to remove if on a part without crypto engine */ - crypto@30000 { - device_type = "crypto"; - model = "SEC2"; - compatible = "talitos"; - reg = <30000 10000>; - interrupts = ; + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 10000>; + interrupts = ; interrupt-parent = <&Cpm_pic>; - num-channels = <4>; - channel-fifo-len = <18>; - exec-units-mask = <0000007e>; + num-channels = <4>; + channel-fifo-len = <18>; + exec-units-mask = <0000007e>; /* desc mask is for rev1.x, we need runtime fixup for >=2.x */ - descriptor-types-mask = <01010ebf>; - }; - - }; + descriptor-types-mask = <01010ebf>; + }; + }; }; diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 24bea97c736c..dfad0e469eec 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -272,7 +272,7 @@ void do_IRQ(struct pt_regs *regs) struct thread_info *curtp, *irqtp; #endif - irq_enter(); + irq_enter(); #ifdef CONFIG_DEBUG_STACKOVERFLOW /* Debugging check for stack overflow: is there less than 2KB free? */ @@ -321,7 +321,7 @@ void do_IRQ(struct pt_regs *regs) /* That's not SMP safe ... but who cares ? */ ppc_spurious_interrupts++; - irq_exit(); + irq_exit(); set_irq_regs(old_regs); #ifdef CONFIG_PPC_ISERIES diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index f1693550c70c..601b389b570b 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -89,24 +89,24 @@ init_internal_rtc(void) static int __init get_freq(char *name, unsigned long *val) { - struct device_node *cpu; - const unsigned int *fp; - int found = 0; + struct device_node *cpu; + const unsigned int *fp; + int found = 0; - /* The cpu node should have timebase and clock frequency properties */ - cpu = of_find_node_by_type(NULL, "cpu"); + /* The cpu node should have timebase and clock frequency properties */ + cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu) { - fp = of_get_property(cpu, name, NULL); - if (fp) { - found = 1; - *val = *fp; - } + if (cpu) { + fp = of_get_property(cpu, name, NULL); + if (fp) { + found = 1; + *val = *fp; + } - of_node_put(cpu); - } + of_node_put(cpu); + } - return found; + return found; } /* The decrementer counts at the system (internal) clock frequency divided by @@ -122,7 +122,7 @@ void __init mpc8xx_calibrate_decr(void) sit8xx_t *sys_tmr2; int irq, virq; - clk_r1 = (cark8xx_t *) immr_map(im_clkrstk); + clk_r1 = (cark8xx_t *) immr_map(im_clkrstk); /* Unlock the SCCR. */ out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY); @@ -130,24 +130,24 @@ void __init mpc8xx_calibrate_decr(void) immr_unmap(clk_r1); /* Force all 8xx processors to use divide by 16 processor clock. */ - clk_r2 = (car8xx_t *) immr_map(im_clkrst); + clk_r2 = (car8xx_t *) immr_map(im_clkrst); setbits32(&clk_r2->car_sccr, 0x02000000); immr_unmap(clk_r2); /* Processor frequency is MHz. */ - ppc_tb_freq = 50000000; - if (!get_freq("bus-frequency", &ppc_tb_freq)) { - printk(KERN_ERR "WARNING: Estimating decrementer frequency " - "(not found)\n"); - } - ppc_tb_freq /= 16; - ppc_proc_freq = 50000000; - if (!get_freq("clock-frequency", &ppc_proc_freq)) - printk(KERN_ERR "WARNING: Estimating processor frequency" - "(not found)\n"); + ppc_tb_freq = 50000000; + if (!get_freq("bus-frequency", &ppc_tb_freq)) { + printk(KERN_ERR "WARNING: Estimating decrementer frequency " + "(not found)\n"); + } + ppc_tb_freq /= 16; + ppc_proc_freq = 50000000; + if (!get_freq("clock-frequency", &ppc_proc_freq)) + printk(KERN_ERR "WARNING: Estimating processor frequency" + "(not found)\n"); - printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); + printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); /* Perform some more timer/timebase initialization. This used * to be done elsewhere, but other changes caused it to get @@ -164,7 +164,7 @@ void __init mpc8xx_calibrate_decr(void) * we guarantee the registers are locked, then we unlock them * for our use. */ - sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); + sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY); out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY); out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY); @@ -180,8 +180,8 @@ void __init mpc8xx_calibrate_decr(void) * we have to enable the timebase). The decrementer interrupt * is wired into the vector table, nothing to do here for that. */ - cpu = of_find_node_by_type(NULL, "cpu"); - virq= irq_of_parse_and_map(cpu, 0); + cpu = of_find_node_by_type(NULL, "cpu"); + virq= irq_of_parse_and_map(cpu, 0); irq = irq_map[virq].hwirq; sys_tmr2 = (sit8xx_t *) immr_map(im_sit); @@ -211,10 +211,10 @@ int mpc8xx_set_rtc_time(struct rtc_time *tm) sit8xx_t *sys_tmr2; int time; - sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); + sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); sys_tmr2 = (sit8xx_t *) immr_map(im_sit); time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + tm->tm_hour, tm->tm_min, tm->tm_sec); out_be32(&sys_tmr1->sitk_rtck, KAPWR_KEY); out_be32(&sys_tmr2->sit_rtc, time); @@ -233,8 +233,8 @@ void mpc8xx_get_rtc_time(struct rtc_time *tm) /* Get time from the RTC. */ data = in_be32(&sys_tmr->sit_rtc); to_tm(data, tm); - tm->tm_year -= 1900; - tm->tm_mon -= 1; + tm->tm_year -= 1900; + tm->tm_mon -= 1; immr_unmap(sys_tmr); return; } @@ -298,7 +298,7 @@ void __init m8xx_pic_init(void) int irq; if (mpc8xx_pic_init()) { - printk(KERN_ERR "Failed interrupt 8xx controller initialization\n"); + printk(KERN_ERR "Failed interrupt 8xx controller initialization\n"); return; } diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c index 4f67b89ba1d0..e8e79f83d198 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/commproc.c @@ -45,10 +45,10 @@ #define CPM_MAP_SIZE (0x4000) static void m8xx_cpm_dpinit(void); -static uint host_buffer; /* One page of host buffer */ -static uint host_end; /* end + 1 */ -cpm8xx_t *cpmp; /* Pointer to comm processor space */ -cpic8xx_t *cpic_reg; +static uint host_buffer; /* One page of host buffer */ +static uint host_end; /* end + 1 */ +cpm8xx_t *cpmp; /* Pointer to comm processor space */ +cpic8xx_t *cpic_reg; static struct device_node *cpm_pic_node; static struct irq_host *cpm_pic_host; @@ -115,7 +115,7 @@ static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, * and return. This is a no-op function so we don't need any special * tests in the interrupt handler. */ -static irqreturn_t cpm_error_interrupt(int irq, void *dev) +static irqreturn_t cpm_error_interrupt(int irq, void *dev) { return IRQ_HANDLED; } @@ -181,7 +181,7 @@ unsigned int cpm_pic_init(void) printk(KERN_ERR "CPM PIC init: can not find cpm node\n"); goto end; } - eirq= irq_of_parse_and_map(np, 0); + eirq = irq_of_parse_and_map(np, 0); if (eirq == NO_IRQ) goto end; @@ -197,15 +197,15 @@ end: void cpm_reset(void) { - cpm8xx_t *commproc; - sysconf8xx_t *siu_conf; + cpm8xx_t *commproc; + sysconf8xx_t *siu_conf; commproc = (cpm8xx_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE); #ifdef CONFIG_UCODE_PATCH /* Perform a reset. */ - out_be16(&commproc->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); + out_be16(&commproc->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); /* Wait for it. */ @@ -307,7 +307,7 @@ static rh_block_t cpm_boot_dpmem_rh_block[16]; static rh_info_t cpm_dpmem_info; #define CPM_DPMEM_ALIGNMENT 8 -static u8* dpram_vbase; +static u8 *dpram_vbase; static uint dpram_pbase; void m8xx_cpm_dpinit(void) diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c index 924412974795..dbe8d1802189 100644 --- a/arch/powerpc/sysdev/cpm2_common.c +++ b/arch/powerpc/sysdev/cpm2_common.c @@ -201,7 +201,7 @@ int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) } if (mode == CPM_CLK_RX) - shift +=3; + shift += 3; for (i=0; i<24; i++) { if (clk_map[i][0] == target && clk_map[i][1] == clock) { From 12cdac34c6e90d887de23ab9747185731cba254a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 02:36:58 +1000 Subject: [PATCH 0144/2804] [POWERPC] Add clrbits8 and setbits8 Signed-off-by: Scott Wood Signed-off-by: Paul Mackerras --- include/asm-powerpc/io.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h index bb8d965f96c6..4c0b55087dc7 100644 --- a/include/asm-powerpc/io.h +++ b/include/asm-powerpc/io.h @@ -734,6 +734,9 @@ static inline void * bus_to_virt(unsigned long address) #define setbits16(_addr, _v) out_be16((_addr), in_be16(_addr) | (_v)) #define clrbits16(_addr, _v) out_be16((_addr), in_be16(_addr) & ~(_v)) +#define setbits8(_addr, _v) out_8((_addr), in_8(_addr) | (_v)) +#define clrbits8(_addr, _v) out_8((_addr), in_8(_addr) & ~(_v)) + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_IO_H */ From 804ace8881d211ac448082e871dd312132393049 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 02:36:59 +1000 Subject: [PATCH 0145/2804] [POWERPC] Use strcasecmp() rather than strncasecmp() when determining device node compatibility The current code assumes "foo-bar" must always be compatible with a node compatible with "foo", which breaks device trees where this is not so. The "case" part is also wrong according to Open Firmware, but it's more likely to have drivers and/or device trees depending on it, and thus needs to be handled more carefully. Signed-off-by: Scott Wood Signed-off-by: Paul Mackerras --- include/asm-powerpc/prom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 920b75620f74..925e2d384bb3 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -24,7 +24,7 @@ #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 -#define of_compat_cmp(s1, s2, l) strncasecmp((s1), (s2), (l)) +#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) #define of_prop_cmp(s1, s2) strcmp((s1), (s2)) #define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) From 44d06ba72990893eb5506516b25ccaf3a757ffc0 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:20 +1000 Subject: [PATCH 0146/2804] [POWERPC] bootwrapper: Update .gitignore All cuImage types are ignored, as well as preprocessed .lds files, and the forthcoming zImage.bin files and embedded planet board images. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/.gitignore | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore index eec7af7e5993..2c187ca05982 100644 --- a/arch/powerpc/boot/.gitignore +++ b/arch/powerpc/boot/.gitignore @@ -18,14 +18,14 @@ kernel-vmlinux.strip.c kernel-vmlinux.strip.gz mktree uImage -cuImage -cuImage.bin.gz -cuImage.elf +cuImage.* zImage +zImage.bin.* zImage.chrp zImage.coff zImage.coff.lds -zImage.lds +zImage.ep* +zImage.*lds zImage.miboot zImage.pmac zImage.pseries From 643d3c139b0a5289d7f0ba19fdcb24be6d7e768f Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:45 +1000 Subject: [PATCH 0147/2804] [POWERPC] bootwrapper: Set timebase_period_ns from dt_fixup_cpu_clocks This lets udelay() work properly on platforms which use dt_fixup_cpu_clocks. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/devtree.c | 2 ++ arch/powerpc/boot/ops.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c index c9951550ed2c..ae8b886f5a1d 100644 --- a/arch/powerpc/boot/devtree.c +++ b/arch/powerpc/boot/devtree.c @@ -74,6 +74,8 @@ void dt_fixup_cpu_clocks(u32 cpu, u32 tb, u32 bus) if (bus > 0) setprop_val(devp, "bus-frequency", bus); } + + timebase_period_ns = 1000000000 / tb; } void dt_fixup_clock(const char *path, u32 freq) diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index 86077066cd7c..aebd6edc9a90 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -191,4 +191,6 @@ static inline void exit(void) static char _bss_stack[size]; \ void *_platform_stack_top = _bss_stack + sizeof(_bss_stack); +extern unsigned long timebase_period_ns; + #endif /* _PPC_BOOT_OPS_H_ */ From 0602801c22ea1767cd0298b11da140bd5cb764d2 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:46 +1000 Subject: [PATCH 0148/2804] [POWERPC] bootwrapper: dt_xlate_range() bugfixes 1. The check whether ranges fits in the buffer was using elements rather than bytes. 2. Empty ranges were not properly treated as transparent, and missing ranges were treated as transparent. 3. The loop terminated when translating from the root rather than to. Once bug #2 was fixed, it failed due to a missing ranges in the root node. 4. In decoding the ranges property, the #size-cells used was that of the parent, not the child. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/devtree.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c index ae8b886f5a1d..129e6d9b8d43 100644 --- a/arch/powerpc/boot/devtree.c +++ b/arch/powerpc/boot/devtree.c @@ -218,7 +218,7 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, u32 this_addr[MAX_ADDR_CELLS]; void *parent; u64 ret_addr, ret_size; - u32 naddr, nsize, prev_naddr; + u32 naddr, nsize, prev_naddr, prev_nsize; int buflen, offset; parent = get_parent(node); @@ -233,7 +233,7 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, offset = (naddr + nsize) * res; if (reglen < offset + naddr + nsize || - sizeof(dt_xlate_buf) < offset + naddr + nsize) + sizeof(dt_xlate_buf) < (offset + naddr + nsize) * 4) return 0; copy_val(last_addr, dt_xlate_buf + offset, naddr); @@ -244,20 +244,26 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, ret_size |= dt_xlate_buf[offset + naddr + 1]; } - while ((node = get_parent(node))) { + for (;;) { prev_naddr = naddr; + prev_nsize = nsize; + node = parent; - get_reg_format(node, &naddr, &nsize); + parent = get_parent(node); + if (!parent) + break; + + get_reg_format(parent, &naddr, &nsize); buflen = getprop(node, "ranges", dt_xlate_buf, sizeof(dt_xlate_buf)); - if (buflen < 0) + if (buflen == 0) continue; - if (buflen > sizeof(dt_xlate_buf)) + if (buflen < 0 || buflen > sizeof(dt_xlate_buf)) return 0; offset = find_range(last_addr, dt_xlate_buf, prev_naddr, - naddr, nsize, buflen / 4); + naddr, prev_nsize, buflen / 4); if (offset < 0) return 0; From a73ac50c4787b1b28d5c94bb18c60352f5dd7d6f Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:48 +1000 Subject: [PATCH 0149/2804] [POWERPC] bootwrapper: Add dt_is_compatible() This can be used rather than doing a simple strcmp, which will fail to handle multiple compatible entries. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/devtree.c | 48 +++++++++++++++++++++++++------------ arch/powerpc/boot/ops.h | 1 + 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c index 129e6d9b8d43..3a18bfe0fdf7 100644 --- a/arch/powerpc/boot/devtree.c +++ b/arch/powerpc/boot/devtree.c @@ -113,7 +113,6 @@ void __dt_fixup_mac_addresses(u32 startindex, ...) } #define MAX_ADDR_CELLS 4 -#define MAX_RANGES 8 static void get_reg_format(void *node, u32 *naddr, u32 *nsize) { @@ -209,7 +208,7 @@ static int find_range(u32 *reg, u32 *ranges, int nregaddr, * In particular, PCI is not supported. Also, only the beginning of the * reg block is tracked; size is ignored except in ranges. */ -static u32 dt_xlate_buf[MAX_ADDR_CELLS * MAX_RANGES * 3]; +static u32 prop_buf[MAX_PROP_LEN / 4]; static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, unsigned long *size) @@ -233,15 +232,15 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, offset = (naddr + nsize) * res; if (reglen < offset + naddr + nsize || - sizeof(dt_xlate_buf) < (offset + naddr + nsize) * 4) + MAX_PROP_LEN < (offset + naddr + nsize) * 4) return 0; - copy_val(last_addr, dt_xlate_buf + offset, naddr); + copy_val(last_addr, prop_buf + offset, naddr); - ret_size = dt_xlate_buf[offset + naddr]; + ret_size = prop_buf[offset + naddr]; if (nsize == 2) { ret_size <<= 32; - ret_size |= dt_xlate_buf[offset + naddr + 1]; + ret_size |= prop_buf[offset + naddr + 1]; } for (;;) { @@ -255,25 +254,25 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, get_reg_format(parent, &naddr, &nsize); - buflen = getprop(node, "ranges", dt_xlate_buf, - sizeof(dt_xlate_buf)); + buflen = getprop(node, "ranges", prop_buf, + sizeof(prop_buf)); if (buflen == 0) continue; - if (buflen < 0 || buflen > sizeof(dt_xlate_buf)) + if (buflen < 0 || buflen > sizeof(prop_buf)) return 0; - offset = find_range(last_addr, dt_xlate_buf, prev_naddr, + offset = find_range(last_addr, prop_buf, prev_naddr, naddr, prev_nsize, buflen / 4); if (offset < 0) return 0; - copy_val(this_addr, dt_xlate_buf + offset, prev_naddr); + copy_val(this_addr, prop_buf + offset, prev_naddr); if (!sub_reg(last_addr, this_addr)) return 0; - copy_val(this_addr, dt_xlate_buf + offset + prev_naddr, naddr); + copy_val(this_addr, prop_buf + offset + prev_naddr, naddr); if (!add_reg(last_addr, this_addr, naddr)) return 0; @@ -300,16 +299,35 @@ int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size) { int reglen; - reglen = getprop(node, "reg", dt_xlate_buf, sizeof(dt_xlate_buf)) / 4; + reglen = getprop(node, "reg", prop_buf, sizeof(prop_buf)) / 4; return dt_xlate(node, res, reglen, addr, size); } int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr) { - if (buflen > sizeof(dt_xlate_buf)) + if (buflen > sizeof(prop_buf)) return 0; - memcpy(dt_xlate_buf, buf, buflen); + memcpy(prop_buf, buf, buflen); return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL); } + +int dt_is_compatible(void *node, const char *compat) +{ + char *buf = (char *)prop_buf; + int len, pos; + + len = getprop(node, "compatible", buf, MAX_PROP_LEN); + if (len < 0) + return 0; + + for (pos = 0; pos < len; pos++) { + if (!strcmp(buf + pos, compat)) + return 1; + + pos += strnlen(&buf[pos], len - pos); + } + + return 0; +} diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index aebd6edc9a90..a10bf5a153d5 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -87,6 +87,7 @@ void *simple_alloc_init(char *base, unsigned long heap_size, extern void flush_cache(void *, unsigned long); int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size); int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr); +int dt_is_compatible(void *node, const char *compat); static inline void *finddevice(const char *name) { From 6e913c67b3eb93e2b8bc1dc0ff854f00a760f41b Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:51 +1000 Subject: [PATCH 0150/2804] [POWERPC] bootwrapper: Add 16-bit I/O, sync(), eieio(), and barrier() Also, include types.h from io.h, so callers don't have to. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/io.h | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/arch/powerpc/boot/io.h b/arch/powerpc/boot/io.h index 32974ed49e02..ccaedaec50d5 100644 --- a/arch/powerpc/boot/io.h +++ b/arch/powerpc/boot/io.h @@ -1,5 +1,8 @@ #ifndef _IO_H #define __IO_H + +#include "types.h" + /* * Low-level I/O routines. * @@ -20,6 +23,37 @@ static inline void out_8(volatile unsigned char *addr, int val) : "=m" (*addr) : "r" (val)); } +static inline unsigned in_le16(const volatile u16 *addr) +{ + unsigned ret; + + __asm__ __volatile__("lhbrx %0,0,%1; twi 0,%0,0; isync" + : "=r" (ret) : "r" (addr), "m" (*addr)); + + return ret; +} + +static inline unsigned in_be16(const volatile u16 *addr) +{ + unsigned ret; + + __asm__ __volatile__("lhz%U1%X1 %0,%1; twi 0,%0,0; isync" + : "=r" (ret) : "m" (*addr)); + return ret; +} + +static inline void out_le16(volatile u16 *addr, int val) +{ + __asm__ __volatile__("sthbrx %1,0,%2; sync" : "=m" (*addr) + : "r" (val), "r" (addr)); +} + +static inline void out_be16(volatile u16 *addr, int val) +{ + __asm__ __volatile__("sth%U0%X0 %1,%0; sync" + : "=m" (*addr) : "r" (val)); +} + static inline unsigned in_le32(const volatile unsigned *addr) { unsigned ret; @@ -50,4 +84,19 @@ static inline void out_be32(volatile unsigned *addr, int val) : "=m" (*addr) : "r" (val)); } +static inline void sync(void) +{ + asm volatile("sync" : : : "memory"); +} + +static inline void eieio(void) +{ + asm volatile("eieio" : : : "memory"); +} + +static inline void barrier(void) +{ + asm volatile("" : : : "memory"); +} + #endif /* _IO_H */ From 61d3b949b70802c4f32d540b11a93128c31c67ea Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:52 +1000 Subject: [PATCH 0151/2804] [POWERPC] bootwrapper: Add TARGET_HAS_ETHn tests to ppcboot.h U-boots more recent than when ppcboot.h was forked allow the board config file to enable additional ethernet ports explicitly, rather than using a hardcoded list of targets. This allows bootwrapper platform files to do the same. Fortunately, nothing after the ethernet addresses is of interest to cuboot platforms, so the inevitable mismatches won't be too catastrophic. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/ppcboot.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/boot/ppcboot.h b/arch/powerpc/boot/ppcboot.h index 5290ff2c2b2b..6ae6f9063952 100644 --- a/arch/powerpc/boot/ppcboot.h +++ b/arch/powerpc/boot/ppcboot.h @@ -78,17 +78,18 @@ typedef struct bd_info { hymod_conf_t bi_hymod_conf; /* hymod configuration information */ #endif #if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \ - defined(TARGET_85xx) || defined(TARGET_83xx) + defined(TARGET_85xx) || defined(TARGET_83xx) || defined(TARGET_HAS_ETH1) /* second onboard ethernet port */ unsigned char bi_enet1addr[6]; #define HAVE_ENET1ADDR #endif -#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || defined(TARGET_85xx) +#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || \ + defined(TARGET_85xx) || defined(TARGET_HAS_ETH2) /* third onboard ethernet ports */ unsigned char bi_enet2addr[6]; #define HAVE_ENET2ADDR #endif -#if defined(TARGET_440GX) +#if defined(TARGET_440GX) || defined(TARGET_HAS_ETH3) /* fourth onboard ethernet ports */ unsigned char bi_enet3addr[6]; #define HAVE_ENET3ADDR From dc4f397d6e385c4ea0fe9732df911a86f1a78c9a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:54 +1000 Subject: [PATCH 0152/2804] [POWERPC] bootwrapper: serial_console_init() fixes 1. Search the entire compatible list for serial devices. The serial code previously did a simple strcmp on the compatible node; this fails when the match string is not the first compatible listed. Use dt_is_compatible() instead. 2. Don't call serial_edit_cmdline if getc isn't defined. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/serial.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c index eaa0d3ae3518..3ce7f651ab34 100644 --- a/arch/powerpc/boot/serial.c +++ b/arch/powerpc/boot/serial.c @@ -114,18 +114,14 @@ int serial_console_init(void) { void *devp; int rc = -1; - char compat[MAX_PROP_LEN]; devp = serial_get_stdout_devp(); if (devp == NULL) goto err_out; - if (getprop(devp, "compatible", compat, sizeof(compat)) < 0) - goto err_out; - - if (!strcmp(compat, "ns16550")) + if (dt_is_compatible(devp, "ns16550")) rc = ns16550_console_init(devp, &serial_cd); - else if (!strcmp(compat, "marvell,mpsc")) + else if (dt_is_compatible(devp, "marvell,mpsc")) rc = mpsc_console_init(devp, &serial_cd); /* Add other serial console driver calls here */ @@ -133,10 +129,12 @@ int serial_console_init(void) if (!rc) { console_ops.open = serial_open; console_ops.write = serial_write; - console_ops.edit_cmdline = serial_edit_cmdline; console_ops.close = serial_close; console_ops.data = &serial_cd; + if (serial_cd.getc) + console_ops.edit_cmdline = serial_edit_cmdline; + return 0; } err_out: From 3ee9b7abafc36a9377af6f036f50c3450954884c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:55 +1000 Subject: [PATCH 0153/2804] [POWERPC] bootwrapper: Declare udelay() in ops.h Declarations in various users are removed. Signed-off-by: Scott Wood Signed-off-by: Paul Mackerras --- arch/powerpc/boot/mpsc.c | 1 - arch/powerpc/boot/mv64x60_i2c.c | 2 -- arch/powerpc/boot/ops.h | 1 + arch/powerpc/boot/prpmc2800.c | 2 -- arch/powerpc/boot/serial.c | 2 -- 5 files changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/powerpc/boot/mpsc.c b/arch/powerpc/boot/mpsc.c index f1c0e965e5ce..802ea53790d8 100644 --- a/arch/powerpc/boot/mpsc.c +++ b/arch/powerpc/boot/mpsc.c @@ -17,7 +17,6 @@ #include "io.h" #include "ops.h" -extern void udelay(long delay); #define MPSC_CHR_1 0x000c diff --git a/arch/powerpc/boot/mv64x60_i2c.c b/arch/powerpc/boot/mv64x60_i2c.c index 435fe8528680..d085377be3bc 100644 --- a/arch/powerpc/boot/mv64x60_i2c.c +++ b/arch/powerpc/boot/mv64x60_i2c.c @@ -21,8 +21,6 @@ #include "ops.h" #include "mv64x60.h" -extern void udelay(long); - /* Register defines */ #define MV64x60_I2C_REG_SLAVE_ADDR 0x00 #define MV64x60_I2C_REG_DATA 0x04 diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index a10bf5a153d5..e45b364e7fcf 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -193,5 +193,6 @@ static inline void exit(void) void *_platform_stack_top = _bss_stack + sizeof(_bss_stack); extern unsigned long timebase_period_ns; +void udelay(long delay); #endif /* _PPC_BOOT_OPS_H_ */ diff --git a/arch/powerpc/boot/prpmc2800.c b/arch/powerpc/boot/prpmc2800.c index f428bac10d4a..5c6cd368056e 100644 --- a/arch/powerpc/boot/prpmc2800.c +++ b/arch/powerpc/boot/prpmc2800.c @@ -25,8 +25,6 @@ extern char _end[]; extern char _vmlinux_start[], _vmlinux_end[]; extern char _dtb_start[], _dtb_end[]; -extern void udelay(long delay); - #define KB 1024U #define MB (KB*KB) #define GB (KB*MB) diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c index 3ce7f651ab34..944f0ee5bc0f 100644 --- a/arch/powerpc/boot/serial.c +++ b/arch/powerpc/boot/serial.c @@ -19,8 +19,6 @@ #include "io.h" #include "ops.h" -extern void udelay(long delay); - static int serial_open(void) { struct serial_console_data *scdp = console_ops.data; From d0f53fafc016b3f4f20f63ecf52f6df8774bcb3c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:57 +1000 Subject: [PATCH 0154/2804] [POWERPC] bootwrapper: Add CPM serial driver This serial port is used on all 8xx, many 82xx, and some 85xx chips. The driver requires that the port has already been set up by the firmware and/or platform code. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 3 +- arch/powerpc/boot/cpm-serial.c | 249 +++++++++++++++++++++++++++++++++ arch/powerpc/boot/ops.h | 1 + arch/powerpc/boot/serial.c | 5 + 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/cpm-serial.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 54a72108bcc3..075f961db12f 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -44,7 +44,8 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ - 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c + 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \ + cpm-serial.c src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c diff --git a/arch/powerpc/boot/cpm-serial.c b/arch/powerpc/boot/cpm-serial.c new file mode 100644 index 000000000000..fcb8b5e956bd --- /dev/null +++ b/arch/powerpc/boot/cpm-serial.c @@ -0,0 +1,249 @@ +/* + * CPM serial console support. + * + * Copyright 2007 Freescale Semiconductor, Inc. + * Author: Scott Wood + * + * It is assumed that the firmware (or the platform file) has already set + * up the port. + */ + +#include "types.h" +#include "io.h" +#include "ops.h" + +struct cpm_scc { + u32 gsmrl; + u32 gsmrh; + u16 psmr; + u8 res1[2]; + u16 todr; + u16 dsr; + u16 scce; + u8 res2[2]; + u16 sccm; + u8 res3; + u8 sccs; + u8 res4[8]; +}; + +struct cpm_smc { + u8 res1[2]; + u16 smcmr; + u8 res2[2]; + u8 smce; + u8 res3[3]; + u8 smcm; + u8 res4[5]; +}; + +struct cpm_param { + u16 rbase; + u16 tbase; + u8 rfcr; + u8 tfcr; +}; + +struct cpm_bd { + u16 sc; /* Status and Control */ + u16 len; /* Data length in buffer */ + u8 *addr; /* Buffer address in host memory */ +}; + +static void *cpcr; +static struct cpm_param *param; +static struct cpm_smc *smc; +static struct cpm_scc *scc; +struct cpm_bd *tbdf, *rbdf; +static u32 cpm_cmd; +static u8 *dpram_start; + +static void (*do_cmd)(int op); +static void (*enable_port)(void); +static void (*disable_port)(void); + +#define CPM_CMD_STOP_TX 4 +#define CPM_CMD_RESTART_TX 6 +#define CPM_CMD_INIT_RX_TX 0 + +static void cpm1_cmd(int op) +{ + while (in_be16(cpcr) & 1) + ; + + out_be16(cpcr, (op << 8) | cpm_cmd | 1); + + while (in_be16(cpcr) & 1) + ; +} + +static void cpm2_cmd(int op) +{ + while (in_be32(cpcr) & 0x10000) + ; + + out_be32(cpcr, op | cpm_cmd | 0x10000); + + while (in_be32(cpcr) & 0x10000) + ; +} + +static void smc_disable_port(void) +{ + do_cmd(CPM_CMD_STOP_TX); + out_be16(&smc->smcmr, in_be16(&smc->smcmr) & ~3); +} + +static void scc_disable_port(void) +{ + do_cmd(CPM_CMD_STOP_TX); + out_be32(&scc->gsmrl, in_be32(&scc->gsmrl) & ~0x30); +} + +static void smc_enable_port(void) +{ + out_be16(&smc->smcmr, in_be16(&smc->smcmr) | 3); + do_cmd(CPM_CMD_RESTART_TX); +} + +static void scc_enable_port(void) +{ + out_be32(&scc->gsmrl, in_be32(&scc->gsmrl) | 0x30); + do_cmd(CPM_CMD_RESTART_TX); +} + +static int cpm_serial_open(void) +{ + int dpaddr = 0x800; + disable_port(); + + out_8(¶m->rfcr, 0x10); + out_8(¶m->tfcr, 0x10); + + rbdf = (struct cpm_bd *)(dpram_start + dpaddr); + rbdf->addr = (u8 *)(rbdf + 2); + rbdf->sc = 0xa000; + rbdf->len = 1; + + tbdf = rbdf + 1; + tbdf->addr = (u8 *)(rbdf + 2) + 1; + tbdf->sc = 0x2000; + tbdf->len = 1; + + sync(); + out_be16(¶m->rbase, dpaddr); + out_be16(¶m->tbase, dpaddr + sizeof(struct cpm_bd)); + + do_cmd(CPM_CMD_INIT_RX_TX); + + enable_port(); + return 0; +} + +static void cpm_serial_putc(unsigned char c) +{ + while (tbdf->sc & 0x8000) + barrier(); + + sync(); + + tbdf->addr[0] = c; + eieio(); + tbdf->sc |= 0x8000; +} + +static unsigned char cpm_serial_tstc(void) +{ + barrier(); + return !(rbdf->sc & 0x8000); +} + +static unsigned char cpm_serial_getc(void) +{ + unsigned char c; + + while (!cpm_serial_tstc()) + ; + + sync(); + c = rbdf->addr[0]; + eieio(); + rbdf->sc |= 0x8000; + + return c; +} + +int cpm_console_init(void *devp, struct serial_console_data *scdp) +{ + void *reg_virt[2]; + int is_smc = 0, is_cpm2 = 0, n; + unsigned long reg_phys; + void *parent; + + if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) { + is_smc = 1; + } else if (dt_is_compatible(devp, "fsl,cpm2-scc-uart")) { + is_cpm2 = 1; + } else if (dt_is_compatible(devp, "fsl,cpm2-smc-uart")) { + is_cpm2 = 1; + is_smc = 1; + } + + if (is_smc) { + enable_port = smc_enable_port; + disable_port = smc_disable_port; + } else { + enable_port = scc_enable_port; + disable_port = scc_disable_port; + } + + if (is_cpm2) + do_cmd = cpm2_cmd; + else + do_cmd = cpm1_cmd; + + n = getprop(devp, "fsl,cpm-command", &cpm_cmd, 4); + if (n < 4) + return -1; + + n = getprop(devp, "virtual-reg", reg_virt, sizeof(reg_virt)); + if (n < (int)sizeof(reg_virt)) { + for (n = 0; n < 2; n++) { + if (!dt_xlate_reg(devp, n, ®_phys, NULL)) + return -1; + + reg_virt[n] = (void *)reg_phys; + } + } + + if (is_smc) + smc = reg_virt[0]; + else + scc = reg_virt[0]; + + param = reg_virt[1]; + + parent = get_parent(devp); + if (!parent) + return -1; + + n = getprop(parent, "virtual-reg", reg_virt, sizeof(reg_virt)); + if (n < (int)sizeof(reg_virt)) { + for (n = 0; n < 2; n++) { + if (!dt_xlate_reg(parent, n, ®_phys, NULL)) + return -1; + + reg_virt[n] = (void *)reg_phys; + } + } + + cpcr = reg_virt[0]; + dpram_start = reg_virt[1]; + + scdp->open = cpm_serial_open; + scdp->putc = cpm_serial_putc; + scdp->getc = cpm_serial_getc; + scdp->tstc = cpm_serial_tstc; + + return 0; +} diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index e45b364e7fcf..2bc2f02db741 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -82,6 +82,7 @@ int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device); int serial_console_init(void); int ns16550_console_init(void *devp, struct serial_console_data *scdp); int mpsc_console_init(void *devp, struct serial_console_data *scdp); +int cpm_console_init(void *devp, struct serial_console_data *scdp); void *simple_alloc_init(char *base, unsigned long heap_size, unsigned long granularity, unsigned long max_allocs); extern void flush_cache(void *, unsigned long); diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c index 944f0ee5bc0f..d47f8e0b4b81 100644 --- a/arch/powerpc/boot/serial.c +++ b/arch/powerpc/boot/serial.c @@ -121,6 +121,11 @@ int serial_console_init(void) rc = ns16550_console_init(devp, &serial_cd); else if (dt_is_compatible(devp, "marvell,mpsc")) rc = mpsc_console_init(devp, &serial_cd); + else if (dt_is_compatible(devp, "fsl,cpm1-scc-uart") || + dt_is_compatible(devp, "fsl,cpm1-smc-uart") || + dt_is_compatible(devp, "fsl,cpm2-scc-uart") || + dt_is_compatible(devp, "fsl,cpm2-smc-uart")) + rc = cpm_console_init(devp, &serial_cd); /* Add other serial console driver calls here */ From 2f1d4899321be87bc5f0c4ee0e62c9d9ced05f80 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:39:58 +1000 Subject: [PATCH 0155/2804] [POWERPC] bootwrapper: Move linker symbols into ops.h Most of these were previously used by numerous C files and redeclared in each one. Signed-off-by: Scott Wood Signed-off-by: Paul Mackerras --- arch/powerpc/boot/cuboot-83xx.c | 1 - arch/powerpc/boot/cuboot-85xx.c | 1 - arch/powerpc/boot/cuboot.c | 3 --- arch/powerpc/boot/ebony.c | 3 --- arch/powerpc/boot/holly.c | 5 ----- arch/powerpc/boot/main.c | 10 ---------- arch/powerpc/boot/of.c | 2 -- arch/powerpc/boot/ops.h | 10 ++++++++++ arch/powerpc/boot/prpmc2800.c | 4 ---- arch/powerpc/boot/ps3.c | 4 ---- arch/powerpc/boot/treeboot-ebony.c | 2 -- 11 files changed, 10 insertions(+), 35 deletions(-) diff --git a/arch/powerpc/boot/cuboot-83xx.c b/arch/powerpc/boot/cuboot-83xx.c index 296025d8b295..a0505509abcc 100644 --- a/arch/powerpc/boot/cuboot-83xx.c +++ b/arch/powerpc/boot/cuboot-83xx.c @@ -18,7 +18,6 @@ #include "ppcboot.h" static bd_t bd; -extern char _dtb_start[], _dtb_end[]; static void platform_fixups(void) { diff --git a/arch/powerpc/boot/cuboot-85xx.c b/arch/powerpc/boot/cuboot-85xx.c index 10f0f697c935..345dcbecef0f 100644 --- a/arch/powerpc/boot/cuboot-85xx.c +++ b/arch/powerpc/boot/cuboot-85xx.c @@ -18,7 +18,6 @@ #include "ppcboot.h" static bd_t bd; -extern char _dtb_start[], _dtb_end[]; static void platform_fixups(void) { diff --git a/arch/powerpc/boot/cuboot.c b/arch/powerpc/boot/cuboot.c index 65795468ad6f..7768b2306b7a 100644 --- a/arch/powerpc/boot/cuboot.c +++ b/arch/powerpc/boot/cuboot.c @@ -17,9 +17,6 @@ #include "ppcboot.h" -extern char _end[]; -extern char _dtb_start[], _dtb_end[]; - void cuboot_init(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long end_of_ram) diff --git a/arch/powerpc/boot/ebony.c b/arch/powerpc/boot/ebony.c index 2b9a809bcd74..86c0f5df0a86 100644 --- a/arch/powerpc/boot/ebony.c +++ b/arch/powerpc/boot/ebony.c @@ -29,9 +29,6 @@ #include "4xx.h" #include "44x.h" -extern char _dtb_start[]; -extern char _dtb_end[]; - static u8 *ebony_mac0, *ebony_mac1; /* Calculate 440GP clocks */ diff --git a/arch/powerpc/boot/holly.c b/arch/powerpc/boot/holly.c index 7d6539f5e22c..199e783aea4d 100644 --- a/arch/powerpc/boot/holly.c +++ b/arch/powerpc/boot/holly.c @@ -21,11 +21,6 @@ #include "ops.h" #include "io.h" -extern char _start[]; -extern char _end[]; -extern char _dtb_start[]; -extern char _dtb_end[]; - BSS_STACK(4096); void platform_init(unsigned long r3, unsigned long r4, unsigned long r5) diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c index 416dc3857bfe..1b496b37eca0 100644 --- a/arch/powerpc/boot/main.c +++ b/arch/powerpc/boot/main.c @@ -19,16 +19,6 @@ #include "flatdevtree.h" #include "reg.h" -extern char _start[]; -extern char __bss_start[]; -extern char _end[]; -extern char _vmlinux_start[]; -extern char _vmlinux_end[]; -extern char _initrd_start[]; -extern char _initrd_end[]; -extern char _dtb_start[]; -extern char _dtb_end[]; - static struct gunzip_state gzstate; struct addr_range { diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c index 385e08b83b7e..61d9899aa0d0 100644 --- a/arch/powerpc/boot/of.c +++ b/arch/powerpc/boot/of.c @@ -17,8 +17,6 @@ #include "of.h" -extern char _end[]; - /* Value picked to match that used by yaboot */ #define PROG_START 0x01400000 /* only used on 64-bit systems */ #define RAM_END (512<<20) /* Fixme: use OF */ diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index 2bc2f02db741..e4b6139d2d6e 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -196,4 +196,14 @@ static inline void exit(void) extern unsigned long timebase_period_ns; void udelay(long delay); +extern char _start[]; +extern char __bss_start[]; +extern char _end[]; +extern char _vmlinux_start[]; +extern char _vmlinux_end[]; +extern char _initrd_start[]; +extern char _initrd_end[]; +extern char _dtb_start[]; +extern char _dtb_end[]; + #endif /* _PPC_BOOT_OPS_H_ */ diff --git a/arch/powerpc/boot/prpmc2800.c b/arch/powerpc/boot/prpmc2800.c index 5c6cd368056e..9614e1db9dae 100644 --- a/arch/powerpc/boot/prpmc2800.c +++ b/arch/powerpc/boot/prpmc2800.c @@ -21,10 +21,6 @@ #include "gunzip_util.h" #include "mv64x60.h" -extern char _end[]; -extern char _vmlinux_start[], _vmlinux_end[]; -extern char _dtb_start[], _dtb_end[]; - #define KB 1024U #define MB (KB*KB) #define GB (KB*MB) diff --git a/arch/powerpc/boot/ps3.c b/arch/powerpc/boot/ps3.c index 893d59339c26..d6661151b494 100644 --- a/arch/powerpc/boot/ps3.c +++ b/arch/powerpc/boot/ps3.c @@ -120,10 +120,6 @@ void ps3_copy_vectors(void) void platform_init(void) { - extern char _end[]; - extern char _dtb_start[]; - extern char _initrd_start[]; - extern char _initrd_end[]; const u32 heapsize = 0x1000000 - (u32)_end; /* 16MiB */ void *chosen; unsigned long ft_addr; diff --git a/arch/powerpc/boot/treeboot-ebony.c b/arch/powerpc/boot/treeboot-ebony.c index 8436a9c55192..21cc4834a384 100644 --- a/arch/powerpc/boot/treeboot-ebony.c +++ b/arch/powerpc/boot/treeboot-ebony.c @@ -16,8 +16,6 @@ #include "stdio.h" #include "44x.h" -extern char _end[]; - BSS_STACK(4096); #define OPENBIOS_MAC_BASE 0xfffffe0c From 0b195812dfbccc2ac33e17b35b899dd4fea7611f Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:40:01 +1000 Subject: [PATCH 0156/2804] [POWERPC] bootwrapper: Add 8xx cuboot support This allows booting on legacy, non-device-tree aware versions of U-boot. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 3 +- arch/powerpc/boot/cuboot-8xx.c | 45 ++++++++++++++++++++++++++ arch/powerpc/platforms/Kconfig.cputype | 1 + 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/cuboot-8xx.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 075f961db12f..6b9af78b67d4 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -48,7 +48,7 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ cpm-serial.c src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ - ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c + ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -140,6 +140,7 @@ image-$(CONFIG_PPC_ISERIES) += zImage.iseries image-$(CONFIG_DEFAULT_UIMAGE) += uImage ifneq ($(CONFIG_DEVICE_TREE),"") +image-$(CONFIG_PPC_8xx) += cuImage.8xx image-$(CONFIG_PPC_83xx) += cuImage.83xx image-$(CONFIG_PPC_85xx) += cuImage.85xx image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony diff --git a/arch/powerpc/boot/cuboot-8xx.c b/arch/powerpc/boot/cuboot-8xx.c new file mode 100644 index 000000000000..88ed84015a8b --- /dev/null +++ b/arch/powerpc/boot/cuboot-8xx.c @@ -0,0 +1,45 @@ +/* + * Old U-boot compatibility for 8xx + * + * Author: Scott Wood + * + * Copyright (c) 2007 Freescale Semiconductor, 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 "ops.h" +#include "stdio.h" +#include "cuboot.h" + +#define TARGET_8xx +#define TARGET_HAS_ETH1 +#include "ppcboot.h" + +static bd_t bd; + +static void platform_fixups(void) +{ + void *node; + + dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); + dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr); + dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 16, bd.bi_busfreq); + + node = finddevice("/soc/cpm"); + if (node) { + setprop(node, "clock-frequency", &bd.bi_busfreq, 4); + setprop(node, "fsl,brg-frequency", &bd.bi_busfreq, 4); + } +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + CUBOOT_INIT(); + ft_init(_dtb_start, _dtb_end - _dtb_start, 32); + serial_console_init(); + platform_ops.fixups = platform_fixups; +} diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 643bee223ec5..86eb4cf31f0b 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -36,6 +36,7 @@ config PPC_8xx bool "Freescale 8xx" select FSL_SOC select 8xx + select WANT_DEVICE_TREE config 40x bool "AMCC 40x" From e5d8d54db25790524da34b0143f4e0176fb7677b Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 21 Aug 2007 03:40:02 +1000 Subject: [PATCH 0157/2804] [POWERPC] bootwrapper: Add PowerQUICC II (82xx with CPM) cuboot support This allows booting on legacy, non-device-tree aware versions of U-boot. It also fixes up the hardware to match the PCI and chipselect information in the device tree, as u-boot is inconsistent in setting these up correctly (or at all). Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 3 +- arch/powerpc/boot/cuboot-pq2.c | 283 +++++++++++++++++++++++++++++++++ arch/powerpc/boot/devtree.c | 6 +- arch/powerpc/boot/ops.h | 9 ++ arch/powerpc/platforms/Kconfig | 1 + 5 files changed, 298 insertions(+), 4 deletions(-) create mode 100644 arch/powerpc/boot/cuboot-pq2.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 6b9af78b67d4..cd7c05769e41 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -48,7 +48,7 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ cpm-serial.c src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ - ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c + ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c cuboot-pq2.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -141,6 +141,7 @@ image-$(CONFIG_DEFAULT_UIMAGE) += uImage ifneq ($(CONFIG_DEVICE_TREE),"") image-$(CONFIG_PPC_8xx) += cuImage.8xx +image-$(CONFIG_8260) += cuImage.pq2 image-$(CONFIG_PPC_83xx) += cuImage.83xx image-$(CONFIG_PPC_85xx) += cuImage.85xx image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony diff --git a/arch/powerpc/boot/cuboot-pq2.c b/arch/powerpc/boot/cuboot-pq2.c new file mode 100644 index 000000000000..8021fd4a43bc --- /dev/null +++ b/arch/powerpc/boot/cuboot-pq2.c @@ -0,0 +1,283 @@ +/* + * Old U-boot compatibility for PowerQUICC II + * (a.k.a. 82xx with CPM, not the 8240 family of chips) + * + * Author: Scott Wood + * + * Copyright (c) 2007 Freescale Semiconductor, 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 "ops.h" +#include "stdio.h" +#include "cuboot.h" +#include "io.h" + +#define TARGET_CPM2 +#define TARGET_HAS_ETH1 +#include "ppcboot.h" + +static bd_t bd; + +struct cs_range { + u32 csnum; + u32 base; /* must be zero */ + u32 addr; + u32 size; +}; + +struct pci_range { + u32 flags; + u32 pci_addr[2]; + u32 phys_addr; + u32 size[2]; +}; + +struct cs_range cs_ranges_buf[MAX_PROP_LEN / sizeof(struct cs_range)]; +struct pci_range pci_ranges_buf[MAX_PROP_LEN / sizeof(struct pci_range)]; + +/* Different versions of u-boot put the BCSR in different places, and + * some don't set up the PCI PIC at all, so we assume the device tree is + * sane and update the BRx registers appropriately. + * + * For any node defined as compatible with fsl,pq2-chipselect, + * #address/#size must be 2/1 for chipselect bus, 1/1 for parent bus, + * and ranges must be for whole chip selects. + */ +static void update_cs_ranges(void) +{ + u32 ctrl_ph; + void *ctrl_node, *bus_node, *parent_node; + u32 *ctrl_addr; + unsigned long ctrl_size; + u32 naddr, nsize; + int len; + int i; + + bus_node = finddevice("/chipselect"); + if (!bus_node || !dt_is_compatible(bus_node, "fsl,pq2-chipselect")) + return; + + dt_get_reg_format(bus_node, &naddr, &nsize); + if (naddr != 2 || nsize != 1) + goto err; + + parent_node = get_parent(bus_node); + if (!parent_node) + goto err; + + dt_get_reg_format(parent_node, &naddr, &nsize); + if (naddr != 1 || nsize != 1) + goto err; + + len = getprop(bus_node, "fsl,ctrl", &ctrl_ph, 4); + if (len != 4) + goto err; + + ctrl_node = find_node_by_prop_value(NULL, "linux,phandle", + (char *)&ctrl_ph, 4); + if (!ctrl_node) + goto err; + + if (!dt_is_compatible(ctrl_node, "fsl,pq2-chipselect-ctrl")) + goto err; + + if (!dt_xlate_reg(ctrl_node, 0, (unsigned long *)&ctrl_addr, + &ctrl_size)) + goto err; + + len = getprop(bus_node, "ranges", cs_ranges_buf, sizeof(cs_ranges_buf)); + + for (i = 0; i < len / sizeof(struct cs_range); i++) { + u32 base, option; + int cs = cs_ranges_buf[i].csnum; + if (cs >= ctrl_size / 8) + goto err; + + if (cs_ranges_buf[i].base != 0) + goto err; + + base = in_be32(&ctrl_addr[cs * 2]); + + /* If CS is already valid, use the existing flags. + * Otherwise, guess a sane default. + */ + if (base & 1) { + base &= 0x7fff; + option = in_be32(&ctrl_addr[cs * 2 + 1]) & 0x7fff; + } else { + base = 0x1801; + option = 0x10; + } + + out_be32(&ctrl_addr[cs * 2], 0); + out_be32(&ctrl_addr[cs * 2 + 1], + option | ~(cs_ranges_buf[i].size - 1)); + out_be32(&ctrl_addr[cs * 2], base | cs_ranges_buf[i].addr); + } + + return; + +err: + printf("Bad /chipselect or fsl,pq2-chipselect-ctrl node\r\n"); +} + +/* Older u-boots don't set PCI up properly. Update the hardware to match + * the device tree. The prefetch mem region and non-prefetch mem region + * must be contiguous in the host bus. As required by the PCI binding, + * PCI #addr/#size must be 3/2. The parent bus must be 1/1. Only + * 32-bit PCI is supported. All three region types (prefetchable mem, + * non-prefetchable mem, and I/O) must be present. + */ +static void fixup_pci(void) +{ + struct pci_range *mem = NULL, *mmio = NULL, + *io = NULL, *mem_base = NULL; + u32 *pci_regs[3]; + u8 *soc_regs; + int i, len; + void *ctrl_node, *bus_node, *parent_node, *soc_node; + u32 naddr, nsize, bus_ph, mem_log2; + + ctrl_node = finddevice("/soc/pci"); + if (!ctrl_node || !dt_is_compatible(ctrl_node, "fsl,pq2-pci")) + return; + + soc_node = finddevice("/soc"); + if (!soc_node || !dt_is_compatible(soc_node, "fsl,pq2-soc")) + goto err; + + for (i = 0; i < 3; i++) + if (!dt_xlate_reg(ctrl_node, i, + (unsigned long *)&pci_regs[i], NULL)) + goto err; + + if (!dt_xlate_reg(soc_node, 0, (unsigned long *)&soc_regs, NULL)) + goto err; + + len = getprop(ctrl_node, "fsl,bus", &bus_ph, 4); + if (len != 4) + goto err; + + bus_node = find_node_by_prop_value(NULL, "linux,phandle", + (char *)&bus_ph, 4); + if (!bus_node) + goto err; + + dt_get_reg_format(bus_node, &naddr, &nsize); + if (naddr != 3 || nsize != 2) + goto err; + + parent_node = get_parent(bus_node); + if (!parent_node) + goto err; + + dt_get_reg_format(parent_node, &naddr, &nsize); + if (naddr != 1 || nsize != 1) + goto err; + + len = getprop(bus_node, "ranges", pci_ranges_buf, + sizeof(pci_ranges_buf)); + + for (i = 0; i < len / sizeof(struct pci_range); i++) { + u32 flags = pci_ranges_buf[i].flags & 0x43000000; + + if (flags == 0x42000000) + mem = &pci_ranges_buf[i]; + else if (flags == 0x02000000) + mmio = &pci_ranges_buf[i]; + else if (flags == 0x01000000) + io = &pci_ranges_buf[i]; + } + + if (!mem || !mmio || !io) + goto err; + + if (mem->phys_addr + mem->size[1] == mmio->phys_addr) + mem_base = mem; + else if (mmio->phys_addr + mmio->size[1] == mem->phys_addr) + mem_base = mmio; + else + goto err; + + out_be32(&pci_regs[1][0], mem_base->phys_addr | 1); + out_be32(&pci_regs[2][0], ~(mem->size[1] + mmio->size[1] - 1)); + + out_be32(&pci_regs[1][1], io->phys_addr | 1); + out_be32(&pci_regs[2][1], ~(io->size[1] - 1)); + + out_le32(&pci_regs[0][0], mem->pci_addr[1] >> 12); + out_le32(&pci_regs[0][2], mem->phys_addr >> 12); + out_le32(&pci_regs[0][4], (~(mem->size[1] - 1) >> 12) | 0xa0000000); + + out_le32(&pci_regs[0][6], mmio->pci_addr[1] >> 12); + out_le32(&pci_regs[0][8], mmio->phys_addr >> 12); + out_le32(&pci_regs[0][10], (~(mmio->size[1] - 1) >> 12) | 0x80000000); + + out_le32(&pci_regs[0][12], io->pci_addr[1] >> 12); + out_le32(&pci_regs[0][14], io->phys_addr >> 12); + out_le32(&pci_regs[0][16], (~(io->size[1] - 1) >> 12) | 0xc0000000); + + /* Inbound translation */ + out_le32(&pci_regs[0][58], 0); + out_le32(&pci_regs[0][60], 0); + + mem_log2 = 1 << (__ilog2_u32(bd.bi_memsize - 1) + 1); + out_le32(&pci_regs[0][62], 0xa0000000 | ~((1 << (mem_log2 - 12)) - 1)); + + /* If PCI is disabled, drive RST high to enable. */ + if (!(in_le32(&pci_regs[0][32]) & 1)) { + /* Tpvrh (Power valid to RST# high) 100 ms */ + udelay(100000); + + out_le32(&pci_regs[0][32], 1); + + /* Trhfa (RST# high to first cfg access) 2^25 clocks */ + udelay(1020000); + } + + /* Enable bus master and memory access */ + out_le32(&pci_regs[0][64], 0x80000004); + out_le32(&pci_regs[0][65], in_le32(&pci_regs[0][65]) | 6); + + /* Park the bus on PCI, and elevate PCI's arbitration priority, + * as required by section 9.6 of the user's manual. + */ + out_8(&soc_regs[0x10028], 3); + out_be32((u32 *)&soc_regs[0x1002c], 0x01236745); + + return; + +err: + printf("Bad PCI node\r\n"); +} + +static void pq2_platform_fixups(void) +{ + void *node; + + dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); + dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr); + dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); + + node = finddevice("/soc/cpm"); + if (node) { + setprop(node, "clock-frequency", &bd.bi_cpmfreq, 4); + setprop(node, "fsl,brg-frequency", &bd.bi_brgfreq, 4); + } + + update_cs_ranges(); + fixup_pci(); +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + CUBOOT_INIT(); + ft_init(_dtb_start, _dtb_end - _dtb_start, 32); + serial_console_init(); + platform_ops.fixups = pq2_platform_fixups; +} diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c index 3a18bfe0fdf7..e1b8122b4393 100644 --- a/arch/powerpc/boot/devtree.c +++ b/arch/powerpc/boot/devtree.c @@ -114,7 +114,7 @@ void __dt_fixup_mac_addresses(u32 startindex, ...) #define MAX_ADDR_CELLS 4 -static void get_reg_format(void *node, u32 *naddr, u32 *nsize) +void dt_get_reg_format(void *node, u32 *naddr, u32 *nsize) { if (getprop(node, "#address-cells", naddr, 4) != 4) *naddr = 2; @@ -224,7 +224,7 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, if (!parent) return 0; - get_reg_format(parent, &naddr, &nsize); + dt_get_reg_format(parent, &naddr, &nsize); if (nsize > 2) return 0; @@ -252,7 +252,7 @@ static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, if (!parent) break; - get_reg_format(parent, &naddr, &nsize); + dt_get_reg_format(parent, &naddr, &nsize); buflen = getprop(node, "ranges", prop_buf, sizeof(prop_buf)); diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index e4b6139d2d6e..45c2268d5c56 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -89,6 +89,7 @@ extern void flush_cache(void *, unsigned long); int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size); int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr); int dt_is_compatible(void *node, const char *compat); +void dt_get_reg_format(void *node, u32 *naddr, u32 *nsize); static inline void *finddevice(const char *name) { @@ -206,4 +207,12 @@ extern char _initrd_end[]; extern char _dtb_start[]; extern char _dtb_end[]; +static inline __attribute__((const)) +int __ilog2_u32(u32 n) +{ + int bit; + asm ("cntlzw %0,%1" : "=r" (bit) : "r" (n)); + return 31 - bit; +} + #endif /* _PPC_BOOT_OPS_H_ */ diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 932538a93c2b..2c937fb207fe 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -19,6 +19,7 @@ config EMBEDDED6xx config PPC_82xx bool "Freescale 82xx" depends on 6xx + select WANT_DEVICE_TREE config PPC_83xx bool "Freescale 83xx" From dc559f7cd5d6d11a99b6c29402b31fbb3f3a1db0 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 12:26:43 +1000 Subject: [PATCH 0158/2804] [POWERPC] Rework SMP timebase handoff for pasemi Rework timebase handoff to play nice with configurations with more than 2 cores, as well as with CPU hotplug. Previous scheme just pushed out the current timebase from the giving core to all cores without caring if they wanted it or not, nor checking if they'd taken it. The taking side didn't make sure the giving side had provided a value yet either. In other words, it was completely broken. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/setup.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index ffe6528048b5..05def6282f83 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -50,26 +50,30 @@ static void pas_restart(char *cmd) #ifdef CONFIG_SMP static DEFINE_SPINLOCK(timebase_lock); +static unsigned long timebase; static void __devinit pas_give_timebase(void) { - unsigned long tb; - spin_lock(&timebase_lock); mtspr(SPRN_TBCTL, TBCTL_FREEZE); - tb = mftb(); - mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff)); - mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32)); - mtspr(SPRN_TBCTL, TBCTL_RESTART); + isync(); + timebase = get_tb(); spin_unlock(&timebase_lock); - pr_debug("pas_give_timebase: cpu %d gave tb %lx\n", - smp_processor_id(), tb); + + while (timebase) + barrier(); + mtspr(SPRN_TBCTL, TBCTL_RESTART); } static void __devinit pas_take_timebase(void) { - pr_debug("pas_take_timebase: cpu %d has tb %lx\n", - smp_processor_id(), mftb()); + while (!timebase) + smp_rmb(); + + spin_lock(&timebase_lock); + set_tb(timebase >> 32, timebase & 0xffffffff); + timebase = 0; + spin_unlock(&timebase_lock); } struct smp_ops_t pas_smp_ops = { From fc68e8699f1f987060ef817cff6a13a7cd7d4c8a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 22 Aug 2007 13:44:58 +1000 Subject: [PATCH 0159/2804] [POWERPC] Move iSeries startup code out of head_64.S Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 86 +--------------- arch/powerpc/platforms/iseries/Makefile | 1 + arch/powerpc/platforms/iseries/exception.S | 114 +++++++++++++++++++++ include/asm-powerpc/ppc_asm.h | 14 +++ 4 files changed, 131 insertions(+), 84 deletions(-) create mode 100644 arch/powerpc/platforms/iseries/exception.S diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 1e6d9cc06ca0..97f089b30316 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -802,56 +802,6 @@ system_call_iSeries: STD_EXCEPTION_ISERIES( 0xe00, trap_0e, PACA_EXGEN) STD_EXCEPTION_ISERIES( 0xf00, performance_monitor, PACA_EXGEN) - .globl system_reset_iSeries -system_reset_iSeries: - mfspr r13,SPRN_SPRG3 /* Get paca address */ - mfmsr r24 - ori r24,r24,MSR_RI - mtmsrd r24 /* RI on */ - lhz r24,PACAPACAINDEX(r13) /* Get processor # */ - cmpwi 0,r24,0 /* Are we processor 0? */ - bne 1f - b .__start_initialization_iSeries /* Start up the first processor */ -1: mfspr r4,SPRN_CTRLF - li r5,CTRL_RUNLATCH /* Turn off the run light */ - andc r4,r4,r5 - mtspr SPRN_CTRLT,r4 - -1: - HMT_LOW -#ifdef CONFIG_SMP - lbz r23,PACAPROCSTART(r13) /* Test if this processor - * should start */ - sync - LOAD_REG_IMMEDIATE(r3,current_set) - sldi r28,r24,3 /* get current_set[cpu#] */ - ldx r3,r3,r28 - addi r1,r3,THREAD_SIZE - subi r1,r1,STACK_FRAME_OVERHEAD - - cmpwi 0,r23,0 - beq iSeries_secondary_smp_loop /* Loop until told to go */ - bne __secondary_start /* Loop until told to go */ -iSeries_secondary_smp_loop: - /* Let the Hypervisor know we are alive */ - /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ - lis r3,0x8002 - rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ -#else /* CONFIG_SMP */ - /* Yield the processor. This is required for non-SMP kernels - which are running on multi-threaded machines. */ - lis r3,0x8000 - rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ - addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ - li r4,0 /* "yield timed" */ - li r5,-1 /* "yield forever" */ -#endif /* CONFIG_SMP */ - li r0,-1 /* r0=-1 indicates a Hypervisor call */ - sc /* Invoke the hypervisor via a system call */ - mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */ - b 1b /* If SMP not configured, secondaries - * loop forever */ - decrementer_iSeries_masked: /* We may not have a valid TOC pointer in here. */ li r11,1 @@ -1622,39 +1572,6 @@ _GLOBAL(generic_secondary_smp_init) b __secondary_start #endif -#ifdef CONFIG_PPC_ISERIES -_INIT_STATIC(__start_initialization_iSeries) - /* Clear out the BSS */ - LOAD_REG_IMMEDIATE(r11,__bss_stop) - LOAD_REG_IMMEDIATE(r8,__bss_start) - sub r11,r11,r8 /* bss size */ - addi r11,r11,7 /* round up to an even double word */ - rldicl. r11,r11,61,3 /* shift right by 3 */ - beq 4f - addi r8,r8,-8 - li r0,0 - mtctr r11 /* zero this many doublewords */ -3: stdu r0,8(r8) - bdnz 3b -4: - LOAD_REG_IMMEDIATE(r1,init_thread_union) - addi r1,r1,THREAD_SIZE - li r0,0 - stdu r0,-STACK_FRAME_OVERHEAD(r1) - - LOAD_REG_IMMEDIATE(r2,__toc_start) - addi r2,r2,0x4000 - addi r2,r2,0x4000 - - bl .iSeries_early_setup - bl .early_setup - - /* relocation is on at this point */ - - b .start_here_common -#endif /* CONFIG_PPC_ISERIES */ - - _STATIC(__mmu_off) mfmsr r3 andi. r0,r3,MSR_IR|MSR_DR @@ -1902,6 +1819,7 @@ _GLOBAL(pmac_secondary_start) * r13 = paca virtual address * SPRG3 = paca virtual address */ + .globl __secondary_start __secondary_start: /* Set thread priority to MEDIUM */ HMT_MEDIUM @@ -2032,7 +1950,7 @@ _INIT_STATIC(start_here_multiplatform) b . /* prevent speculative execution */ /* This is where all platforms converge execution */ -_INIT_STATIC(start_here_common) +_INIT_GLOBAL(start_here_common) /* relocation is on at this point */ /* The following code sets up the SP and TOC now that we are */ diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 13ac3015d91c..60db509638f1 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -2,6 +2,7 @@ EXTRA_CFLAGS += -mno-minimal-toc extra-y += dt.o +obj-y += exception.o obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o misc.o irq.o obj-$(CONFIG_PCI) += pci.o vpdinfo.o diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S new file mode 100644 index 000000000000..b6e2f8c0b093 --- /dev/null +++ b/arch/powerpc/platforms/iseries/exception.S @@ -0,0 +1,114 @@ +/* + * Low level routines for legacy iSeries support. + * + * Extracted from head_64.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * 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 + + .text + + .globl system_reset_iSeries +system_reset_iSeries: + mfspr r13,SPRN_SPRG3 /* Get paca address */ + mfmsr r24 + ori r24,r24,MSR_RI + mtmsrd r24 /* RI on */ + lhz r24,PACAPACAINDEX(r13) /* Get processor # */ + cmpwi 0,r24,0 /* Are we processor 0? */ + bne 1f + b .__start_initialization_iSeries /* Start up the first processor */ +1: mfspr r4,SPRN_CTRLF + li r5,CTRL_RUNLATCH /* Turn off the run light */ + andc r4,r4,r5 + mtspr SPRN_CTRLT,r4 + +1: + HMT_LOW +#ifdef CONFIG_SMP + lbz r23,PACAPROCSTART(r13) /* Test if this processor + * should start */ + sync + LOAD_REG_IMMEDIATE(r3,current_set) + sldi r28,r24,3 /* get current_set[cpu#] */ + ldx r3,r3,r28 + addi r1,r3,THREAD_SIZE + subi r1,r1,STACK_FRAME_OVERHEAD + + cmpwi 0,r23,0 + beq iSeries_secondary_smp_loop /* Loop until told to go */ + b __secondary_start /* Loop until told to go */ +iSeries_secondary_smp_loop: + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ +#else /* CONFIG_SMP */ + /* Yield the processor. This is required for non-SMP kernels + which are running on multi-threaded machines. */ + lis r3,0x8000 + rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ + addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ + li r4,0 /* "yield timed" */ + li r5,-1 /* "yield forever" */ +#endif /* CONFIG_SMP */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */ + b 1b /* If SMP not configured, secondaries + * loop forever */ + +_INIT_STATIC(__start_initialization_iSeries) + /* Clear out the BSS */ + LOAD_REG_IMMEDIATE(r11,__bss_stop) + LOAD_REG_IMMEDIATE(r8,__bss_start) + sub r11,r11,r8 /* bss size */ + addi r11,r11,7 /* round up to an even double word */ + rldicl. r11,r11,61,3 /* shift right by 3 */ + beq 4f + addi r8,r8,-8 + li r0,0 + mtctr r11 /* zero this many doublewords */ +3: stdu r0,8(r8) + bdnz 3b +4: + LOAD_REG_IMMEDIATE(r1,init_thread_union) + addi r1,r1,THREAD_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + LOAD_REG_IMMEDIATE(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + bl .iSeries_early_setup + bl .early_setup + + /* relocation is on at this point */ + + b .start_here_common diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index 65325721446d..211fdaeeef84 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -155,6 +155,20 @@ name: \ .type GLUE(.,name),@function; \ GLUE(.,name): +#define _INIT_GLOBAL(name) \ + .section ".text.init.refok"; \ + .align 2 ; \ + .globl name; \ + .globl GLUE(.,name); \ + .section ".opd","aw"; \ +name: \ + .quad GLUE(.,name); \ + .quad .TOC.@tocbase; \ + .quad 0; \ + .previous; \ + .type GLUE(.,name),@function; \ +GLUE(.,name): + #define _KPROBE(name) \ .section ".kprobes.text","a"; \ .align 2 ; \ From f9ff0f304833be9a6a605c84e24d630d5aef2230 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 22 Aug 2007 13:46:44 +1000 Subject: [PATCH 0160/2804] [POWERPC] Move the exception macros into a header file It makes head_64.S a bit more readable and will allow us to move the iSeries exceptions elsewhere. This also removes the last line of the comment: * The following macros define the code that appears as * the prologue to each of the exception handlers. They * are split into two parts to allow a single kernel binary * to be used for pSeries and iSeries. * LOL. One day... - paulus Anything is possible. :-) Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 336 +----------------------------- include/asm-powerpc/exception.h | 356 ++++++++++++++++++++++++++++++++ 2 files changed, 357 insertions(+), 335 deletions(-) create mode 100644 include/asm-powerpc/exception.h diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 97f089b30316..fe6122bfd073 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -35,6 +35,7 @@ #include #include #include +#include #define DO_SOFT_DISABLE @@ -144,344 +145,9 @@ exception_marker: .tc ID_72656773_68657265[TC],0x7265677368657265 .text -/* - * The following macros define the code that appears as - * the prologue to each of the exception handlers. They - * are split into two parts to allow a single kernel binary - * to be used for pSeries and iSeries. - * LOL. One day... - paulus - */ - -/* - * We make as much of the exception code common between native - * exception handlers (including pSeries LPAR) and iSeries LPAR - * implementations as possible. - */ - /* * This is the start of the interrupt handlers for pSeries * This code runs with relocation off. - */ -#define EX_R9 0 -#define EX_R10 8 -#define EX_R11 16 -#define EX_R12 24 -#define EX_R13 32 -#define EX_SRR0 40 -#define EX_DAR 48 -#define EX_DSISR 56 -#define EX_CCR 60 -#define EX_R3 64 -#define EX_LR 72 - -/* - * We're short on space and time in the exception prolog, so we can't - * use the normal SET_REG_IMMEDIATE macro. Normally we just need the - * low halfword of the address, but for Kdump we need the whole low - * word. - */ -#ifdef CONFIG_CRASH_DUMP -#define LOAD_HANDLER(reg, label) \ - oris reg,reg,(label)@h; /* virt addr of handler ... */ \ - ori reg,reg,(label)@l; /* .. and the rest */ -#else -#define LOAD_HANDLER(reg, label) \ - ori reg,reg,(label)@l; /* virt addr of handler ... */ -#endif - -/* - * Equal to EXCEPTION_PROLOG_PSERIES, except that it forces 64bit mode. - * The firmware calls the registered system_reset_fwnmi and - * machine_check_fwnmi handlers in 32bit mode if the cpu happens to run - * a 32bit application at the time of the event. - * This firmware bug is present on POWER4 and JS20. - */ -#define EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(area, label) \ - mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ - std r9,area+EX_R9(r13); /* save r9 - r12 */ \ - std r10,area+EX_R10(r13); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG1; \ - std r9,area+EX_R13(r13); \ - mfcr r9; \ - clrrdi r12,r13,32; /* get high part of &label */ \ - mfmsr r10; \ - /* force 64bit mode */ \ - li r11,5; /* MSR_SF_LG|MSR_ISF_LG */ \ - rldimi r10,r11,61,0; /* insert into top 3 bits */ \ - /* done 64bit mode */ \ - mfspr r11,SPRN_SRR0; /* save SRR0 */ \ - LOAD_HANDLER(r12,label) \ - ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ - mtspr SPRN_SRR0,r12; \ - mfspr r12,SPRN_SRR1; /* and SRR1 */ \ - mtspr SPRN_SRR1,r10; \ - rfid; \ - b . /* prevent speculative execution */ - -#define EXCEPTION_PROLOG_PSERIES(area, label) \ - mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ - std r9,area+EX_R9(r13); /* save r9 - r12 */ \ - std r10,area+EX_R10(r13); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG1; \ - std r9,area+EX_R13(r13); \ - mfcr r9; \ - clrrdi r12,r13,32; /* get high part of &label */ \ - mfmsr r10; \ - mfspr r11,SPRN_SRR0; /* save SRR0 */ \ - LOAD_HANDLER(r12,label) \ - ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ - mtspr SPRN_SRR0,r12; \ - mfspr r12,SPRN_SRR1; /* and SRR1 */ \ - mtspr SPRN_SRR1,r10; \ - rfid; \ - b . /* prevent speculative execution */ - -/* - * This is the start of the interrupt handlers for iSeries - * This code runs with relocation on. - */ -#define EXCEPTION_PROLOG_ISERIES_1(area) \ - mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ - std r9,area+EX_R9(r13); /* save r9 - r12 */ \ - std r10,area+EX_R10(r13); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG1; \ - std r9,area+EX_R13(r13); \ - mfcr r9 - -#define EXCEPTION_PROLOG_ISERIES_2 \ - mfmsr r10; \ - ld r12,PACALPPACAPTR(r13); \ - ld r11,LPPACASRR0(r12); \ - ld r12,LPPACASRR1(r12); \ - ori r10,r10,MSR_RI; \ - mtmsrd r10,1 - -/* - * The common exception prolog is used for all except a few exceptions - * such as a segment miss on a kernel address. We have to be prepared - * to take another exception from the point where we first touch the - * kernel stack onwards. - * - * On entry r13 points to the paca, r9-r13 are saved in the paca, - * r9 contains the saved CR, r11 and r12 contain the saved SRR0 and - * SRR1, and relocation is on. - */ -#define EXCEPTION_PROLOG_COMMON(n, area) \ - andi. r10,r12,MSR_PR; /* See if coming from user */ \ - mr r10,r1; /* Save r1 */ \ - subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \ - beq- 1f; \ - ld r1,PACAKSAVE(r13); /* kernel stack to use */ \ -1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \ - bge- cr1,2f; /* abort if it is */ \ - b 3f; \ -2: li r1,(n); /* will be reloaded later */ \ - sth r1,PACA_TRAP_SAVE(r13); \ - b bad_stack; \ -3: std r9,_CCR(r1); /* save CR in stackframe */ \ - std r11,_NIP(r1); /* save SRR0 in stackframe */ \ - std r12,_MSR(r1); /* save SRR1 in stackframe */ \ - std r10,0(r1); /* make stack chain pointer */ \ - std r0,GPR0(r1); /* save r0 in stackframe */ \ - std r10,GPR1(r1); /* save r1 in stackframe */ \ - ACCOUNT_CPU_USER_ENTRY(r9, r10); \ - std r2,GPR2(r1); /* save r2 in stackframe */ \ - SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ - SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ - ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \ - ld r10,area+EX_R10(r13); \ - std r9,GPR9(r1); \ - std r10,GPR10(r1); \ - ld r9,area+EX_R11(r13); /* move r11 - r13 to stackframe */ \ - ld r10,area+EX_R12(r13); \ - ld r11,area+EX_R13(r13); \ - std r9,GPR11(r1); \ - std r10,GPR12(r1); \ - std r11,GPR13(r1); \ - ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ - mflr r9; /* save LR in stackframe */ \ - std r9,_LINK(r1); \ - mfctr r10; /* save CTR in stackframe */ \ - std r10,_CTR(r1); \ - lbz r10,PACASOFTIRQEN(r13); \ - mfspr r11,SPRN_XER; /* save XER in stackframe */ \ - std r10,SOFTE(r1); \ - std r11,_XER(r1); \ - li r9,(n)+1; \ - std r9,_TRAP(r1); /* set trap number */ \ - li r10,0; \ - ld r11,exception_marker@toc(r2); \ - std r10,RESULT(r1); /* clear regs->result */ \ - std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ - -/* - * Exception vectors. - */ -#define STD_EXCEPTION_PSERIES(n, label) \ - . = n; \ - .globl label##_pSeries; \ -label##_pSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG1,r13; /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) - -#define HSTD_EXCEPTION_PSERIES(n, label) \ - . = n; \ - .globl label##_pSeries; \ -label##_pSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG1,r20; /* save r20 */ \ - mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \ - mtspr SPRN_SRR0,r20; \ - mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \ - mtspr SPRN_SRR1,r20; \ - mfspr r20,SPRN_SPRG1; /* restore r20 */ \ - mtspr SPRN_SPRG1,r13; /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) - - -#define MASKABLE_EXCEPTION_PSERIES(n, label) \ - . = n; \ - .globl label##_pSeries; \ -label##_pSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG1,r13; /* save r13 */ \ - mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ - std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ - std r10,PACA_EXGEN+EX_R10(r13); \ - lbz r10,PACASOFTIRQEN(r13); \ - mfcr r9; \ - cmpwi r10,0; \ - beq masked_interrupt; \ - mfspr r10,SPRN_SPRG1; \ - std r10,PACA_EXGEN+EX_R13(r13); \ - std r11,PACA_EXGEN+EX_R11(r13); \ - std r12,PACA_EXGEN+EX_R12(r13); \ - clrrdi r12,r13,32; /* get high part of &label */ \ - mfmsr r10; \ - mfspr r11,SPRN_SRR0; /* save SRR0 */ \ - LOAD_HANDLER(r12,label##_common) \ - ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ - mtspr SPRN_SRR0,r12; \ - mfspr r12,SPRN_SRR1; /* and SRR1 */ \ - mtspr SPRN_SRR1,r10; \ - rfid; \ - b . /* prevent speculative execution */ - -#define STD_EXCEPTION_ISERIES(n, label, area) \ - .globl label##_iSeries; \ -label##_iSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG1,r13; /* save r13 */ \ - EXCEPTION_PROLOG_ISERIES_1(area); \ - EXCEPTION_PROLOG_ISERIES_2; \ - b label##_common - -#define MASKABLE_EXCEPTION_ISERIES(n, label) \ - .globl label##_iSeries; \ -label##_iSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG1,r13; /* save r13 */ \ - EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ - lbz r10,PACASOFTIRQEN(r13); \ - cmpwi 0,r10,0; \ - beq- label##_iSeries_masked; \ - EXCEPTION_PROLOG_ISERIES_2; \ - b label##_common; \ - -#ifdef CONFIG_PPC_ISERIES -#define DISABLE_INTS \ - li r11,0; \ - stb r11,PACASOFTIRQEN(r13); \ -BEGIN_FW_FTR_SECTION; \ - stb r11,PACAHARDIRQEN(r13); \ -END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ -BEGIN_FW_FTR_SECTION; \ - mfmsr r10; \ - ori r10,r10,MSR_EE; \ - mtmsrd r10,1; \ -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) - -#else -#define DISABLE_INTS \ - li r11,0; \ - stb r11,PACASOFTIRQEN(r13); \ - stb r11,PACAHARDIRQEN(r13) - -#endif /* CONFIG_PPC_ISERIES */ - -#define ENABLE_INTS \ - ld r12,_MSR(r1); \ - mfmsr r11; \ - rlwimi r11,r12,0,MSR_EE; \ - mtmsrd r11,1 - -#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - DISABLE_INTS; \ - bl .save_nvgprs; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b .ret_from_except - -/* - * Like STD_EXCEPTION_COMMON, but for exceptions that can occur - * in the idle task and therefore need the special idle handling. - */ -#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - FINISH_NAP; \ - DISABLE_INTS; \ - bl .save_nvgprs; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b .ret_from_except - -#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - FINISH_NAP; \ - DISABLE_INTS; \ - bl .ppc64_runlatch_on; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b .ret_from_except_lite - -/* - * When the idle code in power4_idle puts the CPU into NAP mode, - * it has to do so in a loop, and relies on the external interrupt - * and decrementer interrupt entry code to get it out of the loop. - * It sets the _TLF_NAPPING bit in current_thread_info()->local_flags - * to signal that it is in the loop and needs help to get out. - */ -#ifdef CONFIG_PPC_970_NAP -#define FINISH_NAP \ -BEGIN_FTR_SECTION \ - clrrdi r11,r1,THREAD_SHIFT; \ - ld r9,TI_LOCAL_FLAGS(r11); \ - andi. r10,r9,_TLF_NAPPING; \ - bnel power4_fixup_nap; \ -END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) -#else -#define FINISH_NAP -#endif - -/* - * Start of pSeries system interrupt routines */ . = 0x100 .globl __start_interrupts diff --git a/include/asm-powerpc/exception.h b/include/asm-powerpc/exception.h new file mode 100644 index 000000000000..1980ed364a9c --- /dev/null +++ b/include/asm-powerpc/exception.h @@ -0,0 +1,356 @@ +#ifndef _ASM_POWERPC_EXCEPTION_H +#define _ASM_POWERPC_EXCEPTION_H +/* + * Extracted from head_64.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * 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. + */ +/* + * The following macros define the code that appears as + * the prologue to each of the exception handlers. They + * are split into two parts to allow a single kernel binary + * to be used for pSeries and iSeries. + * + * We make as much of the exception code common between native + * exception handlers (including pSeries LPAR) and iSeries LPAR + * implementations as possible. + */ + +#define EX_R9 0 +#define EX_R10 8 +#define EX_R11 16 +#define EX_R12 24 +#define EX_R13 32 +#define EX_SRR0 40 +#define EX_DAR 48 +#define EX_DSISR 56 +#define EX_CCR 60 +#define EX_R3 64 +#define EX_LR 72 + +/* + * We're short on space and time in the exception prolog, so we can't + * use the normal SET_REG_IMMEDIATE macro. Normally we just need the + * low halfword of the address, but for Kdump we need the whole low + * word. + */ +#ifdef CONFIG_CRASH_DUMP +#define LOAD_HANDLER(reg, label) \ + oris reg,reg,(label)@h; /* virt addr of handler ... */ \ + ori reg,reg,(label)@l; /* .. and the rest */ +#else +#define LOAD_HANDLER(reg, label) \ + ori reg,reg,(label)@l; /* virt addr of handler ... */ +#endif + +/* + * Equal to EXCEPTION_PROLOG_PSERIES, except that it forces 64bit mode. + * The firmware calls the registered system_reset_fwnmi and + * machine_check_fwnmi handlers in 32bit mode if the cpu happens to run + * a 32bit application at the time of the event. + * This firmware bug is present on POWER4 and JS20. + */ +#define EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(area, label) \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ + std r9,area+EX_R9(r13); /* save r9 - r12 */ \ + std r10,area+EX_R10(r13); \ + std r11,area+EX_R11(r13); \ + std r12,area+EX_R12(r13); \ + mfspr r9,SPRN_SPRG1; \ + std r9,area+EX_R13(r13); \ + mfcr r9; \ + clrrdi r12,r13,32; /* get high part of &label */ \ + mfmsr r10; \ + /* force 64bit mode */ \ + li r11,5; /* MSR_SF_LG|MSR_ISF_LG */ \ + rldimi r10,r11,61,0; /* insert into top 3 bits */ \ + /* done 64bit mode */ \ + mfspr r11,SPRN_SRR0; /* save SRR0 */ \ + LOAD_HANDLER(r12,label) \ + ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ + mtspr SPRN_SRR0,r12; \ + mfspr r12,SPRN_SRR1; /* and SRR1 */ \ + mtspr SPRN_SRR1,r10; \ + rfid; \ + b . /* prevent speculative execution */ + +#define EXCEPTION_PROLOG_PSERIES(area, label) \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ + std r9,area+EX_R9(r13); /* save r9 - r12 */ \ + std r10,area+EX_R10(r13); \ + std r11,area+EX_R11(r13); \ + std r12,area+EX_R12(r13); \ + mfspr r9,SPRN_SPRG1; \ + std r9,area+EX_R13(r13); \ + mfcr r9; \ + clrrdi r12,r13,32; /* get high part of &label */ \ + mfmsr r10; \ + mfspr r11,SPRN_SRR0; /* save SRR0 */ \ + LOAD_HANDLER(r12,label) \ + ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ + mtspr SPRN_SRR0,r12; \ + mfspr r12,SPRN_SRR1; /* and SRR1 */ \ + mtspr SPRN_SRR1,r10; \ + rfid; \ + b . /* prevent speculative execution */ + +/* + * This is the start of the interrupt handlers for iSeries + * This code runs with relocation on. + */ +#define EXCEPTION_PROLOG_ISERIES_1(area) \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ + std r9,area+EX_R9(r13); /* save r9 - r12 */ \ + std r10,area+EX_R10(r13); \ + std r11,area+EX_R11(r13); \ + std r12,area+EX_R12(r13); \ + mfspr r9,SPRN_SPRG1; \ + std r9,area+EX_R13(r13); \ + mfcr r9 + +#define EXCEPTION_PROLOG_ISERIES_2 \ + mfmsr r10; \ + ld r12,PACALPPACAPTR(r13); \ + ld r11,LPPACASRR0(r12); \ + ld r12,LPPACASRR1(r12); \ + ori r10,r10,MSR_RI; \ + mtmsrd r10,1 + +/* + * The common exception prolog is used for all except a few exceptions + * such as a segment miss on a kernel address. We have to be prepared + * to take another exception from the point where we first touch the + * kernel stack onwards. + * + * On entry r13 points to the paca, r9-r13 are saved in the paca, + * r9 contains the saved CR, r11 and r12 contain the saved SRR0 and + * SRR1, and relocation is on. + */ +#define EXCEPTION_PROLOG_COMMON(n, area) \ + andi. r10,r12,MSR_PR; /* See if coming from user */ \ + mr r10,r1; /* Save r1 */ \ + subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \ + beq- 1f; \ + ld r1,PACAKSAVE(r13); /* kernel stack to use */ \ +1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \ + bge- cr1,2f; /* abort if it is */ \ + b 3f; \ +2: li r1,(n); /* will be reloaded later */ \ + sth r1,PACA_TRAP_SAVE(r13); \ + b bad_stack; \ +3: std r9,_CCR(r1); /* save CR in stackframe */ \ + std r11,_NIP(r1); /* save SRR0 in stackframe */ \ + std r12,_MSR(r1); /* save SRR1 in stackframe */ \ + std r10,0(r1); /* make stack chain pointer */ \ + std r0,GPR0(r1); /* save r0 in stackframe */ \ + std r10,GPR1(r1); /* save r1 in stackframe */ \ + ACCOUNT_CPU_USER_ENTRY(r9, r10); \ + std r2,GPR2(r1); /* save r2 in stackframe */ \ + SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ + SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ + ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \ + ld r10,area+EX_R10(r13); \ + std r9,GPR9(r1); \ + std r10,GPR10(r1); \ + ld r9,area+EX_R11(r13); /* move r11 - r13 to stackframe */ \ + ld r10,area+EX_R12(r13); \ + ld r11,area+EX_R13(r13); \ + std r9,GPR11(r1); \ + std r10,GPR12(r1); \ + std r11,GPR13(r1); \ + ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ + mflr r9; /* save LR in stackframe */ \ + std r9,_LINK(r1); \ + mfctr r10; /* save CTR in stackframe */ \ + std r10,_CTR(r1); \ + lbz r10,PACASOFTIRQEN(r13); \ + mfspr r11,SPRN_XER; /* save XER in stackframe */ \ + std r10,SOFTE(r1); \ + std r11,_XER(r1); \ + li r9,(n)+1; \ + std r9,_TRAP(r1); /* set trap number */ \ + li r10,0; \ + ld r11,exception_marker@toc(r2); \ + std r10,RESULT(r1); /* clear regs->result */ \ + std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ + +/* + * Exception vectors. + */ +#define STD_EXCEPTION_PSERIES(n, label) \ + . = n; \ + .globl label##_pSeries; \ +label##_pSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) + +#define HSTD_EXCEPTION_PSERIES(n, label) \ + . = n; \ + .globl label##_pSeries; \ +label##_pSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r20; /* save r20 */ \ + mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \ + mtspr SPRN_SRR0,r20; \ + mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \ + mtspr SPRN_SRR1,r20; \ + mfspr r20,SPRN_SPRG1; /* restore r20 */ \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) + + +#define MASKABLE_EXCEPTION_PSERIES(n, label) \ + . = n; \ + .globl label##_pSeries; \ +label##_pSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ + std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ + std r10,PACA_EXGEN+EX_R10(r13); \ + lbz r10,PACASOFTIRQEN(r13); \ + mfcr r9; \ + cmpwi r10,0; \ + beq masked_interrupt; \ + mfspr r10,SPRN_SPRG1; \ + std r10,PACA_EXGEN+EX_R13(r13); \ + std r11,PACA_EXGEN+EX_R11(r13); \ + std r12,PACA_EXGEN+EX_R12(r13); \ + clrrdi r12,r13,32; /* get high part of &label */ \ + mfmsr r10; \ + mfspr r11,SPRN_SRR0; /* save SRR0 */ \ + LOAD_HANDLER(r12,label##_common) \ + ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ + mtspr SPRN_SRR0,r12; \ + mfspr r12,SPRN_SRR1; /* and SRR1 */ \ + mtspr SPRN_SRR1,r10; \ + rfid; \ + b . /* prevent speculative execution */ + +#define STD_EXCEPTION_ISERIES(n, label, area) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_ISERIES_1(area); \ + EXCEPTION_PROLOG_ISERIES_2; \ + b label##_common + +#define MASKABLE_EXCEPTION_ISERIES(n, label) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ + lbz r10,PACASOFTIRQEN(r13); \ + cmpwi 0,r10,0; \ + beq- label##_iSeries_masked; \ + EXCEPTION_PROLOG_ISERIES_2; \ + b label##_common; \ + +#ifdef CONFIG_PPC_ISERIES +#define DISABLE_INTS \ + li r11,0; \ + stb r11,PACASOFTIRQEN(r13); \ +BEGIN_FW_FTR_SECTION; \ + stb r11,PACAHARDIRQEN(r13); \ +END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ +BEGIN_FW_FTR_SECTION; \ + mfmsr r10; \ + ori r10,r10,MSR_EE; \ + mtmsrd r10,1; \ +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) + +#else +#define DISABLE_INTS \ + li r11,0; \ + stb r11,PACASOFTIRQEN(r13); \ + stb r11,PACAHARDIRQEN(r13) + +#endif /* CONFIG_PPC_ISERIES */ + +#define ENABLE_INTS \ + ld r12,_MSR(r1); \ + mfmsr r11; \ + rlwimi r11,r12,0,MSR_EE; \ + mtmsrd r11,1 + +#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + DISABLE_INTS; \ + bl .save_nvgprs; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except + +/* + * Like STD_EXCEPTION_COMMON, but for exceptions that can occur + * in the idle task and therefore need the special idle handling. + */ +#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + FINISH_NAP; \ + DISABLE_INTS; \ + bl .save_nvgprs; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except + +#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + FINISH_NAP; \ + DISABLE_INTS; \ + bl .ppc64_runlatch_on; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except_lite + +/* + * When the idle code in power4_idle puts the CPU into NAP mode, + * it has to do so in a loop, and relies on the external interrupt + * and decrementer interrupt entry code to get it out of the loop. + * It sets the _TLF_NAPPING bit in current_thread_info()->local_flags + * to signal that it is in the loop and needs help to get out. + */ +#ifdef CONFIG_PPC_970_NAP +#define FINISH_NAP \ +BEGIN_FTR_SECTION \ + clrrdi r11,r1,THREAD_SHIFT; \ + ld r9,TI_LOCAL_FLAGS(r11); \ + andi. r10,r9,_TLF_NAPPING; \ + bnel power4_fixup_nap; \ +END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) +#else +#define FINISH_NAP +#endif + +#endif /* _ASM_POWERPC_EXCEPTION_H */ From dc8f571a26689102f6abe2565a84226edeaacc61 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 22 Aug 2007 13:47:24 +1000 Subject: [PATCH 0161/2804] [POWERPC] Move the iSeries exception vectors out of head_64.S and into platforms/iseries/exception.S Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 136 --------------------- arch/powerpc/platforms/iseries/exception.S | 136 +++++++++++++++++++++ 2 files changed, 136 insertions(+), 136 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index fe6122bfd073..33c4e8cab0ba 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -358,142 +358,6 @@ machine_check_fwnmi: mtspr SPRN_SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXMC, machine_check_common) -#ifdef CONFIG_PPC_ISERIES -/*** ISeries-LPAR interrupt handlers ***/ - - STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC) - - .globl data_access_iSeries -data_access_iSeries: - mtspr SPRN_SPRG1,r13 -BEGIN_FTR_SECTION - mtspr SPRN_SPRG2,r12 - mfspr r13,SPRN_DAR - mfspr r12,SPRN_DSISR - srdi r13,r13,60 - rlwimi r13,r12,16,0x20 - mfcr r12 - cmpwi r13,0x2c - beq .do_stab_bolted_iSeries - mtcrf 0x80,r12 - mfspr r12,SPRN_SPRG2 -END_FTR_SECTION_IFCLR(CPU_FTR_SLB) - EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN) - EXCEPTION_PROLOG_ISERIES_2 - b data_access_common - -.do_stab_bolted_iSeries: - mtcrf 0x80,r12 - mfspr r12,SPRN_SPRG2 - EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - EXCEPTION_PROLOG_ISERIES_2 - b .do_stab_bolted - - .globl data_access_slb_iSeries -data_access_slb_iSeries: - mtspr SPRN_SPRG1,r13 /* save r13 */ - mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ - std r3,PACA_EXSLB+EX_R3(r13) - mfspr r3,SPRN_DAR - std r9,PACA_EXSLB+EX_R9(r13) - mfcr r9 -#ifdef __DISABLED__ - cmpdi r3,0 - bge slb_miss_user_iseries -#endif - std r10,PACA_EXSLB+EX_R10(r13) - std r11,PACA_EXSLB+EX_R11(r13) - std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG1 - std r10,PACA_EXSLB+EX_R13(r13) - ld r12,PACALPPACAPTR(r13) - ld r12,LPPACASRR1(r12) - b .slb_miss_realmode - - STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN) - - .globl instruction_access_slb_iSeries -instruction_access_slb_iSeries: - mtspr SPRN_SPRG1,r13 /* save r13 */ - mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ - std r3,PACA_EXSLB+EX_R3(r13) - ld r3,PACALPPACAPTR(r13) - ld r3,LPPACASRR0(r3) /* get SRR0 value */ - std r9,PACA_EXSLB+EX_R9(r13) - mfcr r9 -#ifdef __DISABLED__ - cmpdi r3,0 - bge .slb_miss_user_iseries -#endif - std r10,PACA_EXSLB+EX_R10(r13) - std r11,PACA_EXSLB+EX_R11(r13) - std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG1 - std r10,PACA_EXSLB+EX_R13(r13) - ld r12,PACALPPACAPTR(r13) - ld r12,LPPACASRR1(r12) - b .slb_miss_realmode - -#ifdef __DISABLED__ -slb_miss_user_iseries: - std r10,PACA_EXGEN+EX_R10(r13) - std r11,PACA_EXGEN+EX_R11(r13) - std r12,PACA_EXGEN+EX_R12(r13) - mfspr r10,SPRG1 - ld r11,PACA_EXSLB+EX_R9(r13) - ld r12,PACA_EXSLB+EX_R3(r13) - std r10,PACA_EXGEN+EX_R13(r13) - std r11,PACA_EXGEN+EX_R9(r13) - std r12,PACA_EXGEN+EX_R3(r13) - EXCEPTION_PROLOG_ISERIES_2 - b slb_miss_user_common -#endif - - MASKABLE_EXCEPTION_ISERIES(0x500, hardware_interrupt) - STD_EXCEPTION_ISERIES(0x600, alignment, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0x700, program_check, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0x800, fp_unavailable, PACA_EXGEN) - MASKABLE_EXCEPTION_ISERIES(0x900, decrementer) - STD_EXCEPTION_ISERIES(0xa00, trap_0a, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0xb00, trap_0b, PACA_EXGEN) - - .globl system_call_iSeries -system_call_iSeries: - mr r9,r13 - mfspr r13,SPRN_SPRG3 - EXCEPTION_PROLOG_ISERIES_2 - b system_call_common - - STD_EXCEPTION_ISERIES( 0xd00, single_step, PACA_EXGEN) - STD_EXCEPTION_ISERIES( 0xe00, trap_0e, PACA_EXGEN) - STD_EXCEPTION_ISERIES( 0xf00, performance_monitor, PACA_EXGEN) - -decrementer_iSeries_masked: - /* We may not have a valid TOC pointer in here. */ - li r11,1 - ld r12,PACALPPACAPTR(r13) - stb r11,LPPACADECRINT(r12) - LOAD_REG_IMMEDIATE(r12, tb_ticks_per_jiffy) - lwz r12,0(r12) - mtspr SPRN_DEC,r12 - /* fall through */ - -hardware_interrupt_iSeries_masked: - mtcrf 0x80,r9 /* Restore regs */ - ld r12,PACALPPACAPTR(r13) - ld r11,LPPACASRR0(r12) - ld r12,LPPACASRR1(r12) - mtspr SPRN_SRR0,r11 - mtspr SPRN_SRR1,r12 - ld r9,PACA_EXGEN+EX_R9(r13) - ld r10,PACA_EXGEN+EX_R10(r13) - ld r11,PACA_EXGEN+EX_R11(r13) - ld r12,PACA_EXGEN+EX_R12(r13) - ld r13,PACA_EXGEN+EX_R13(r13) - rfid - b . /* prevent speculative execution */ -#endif /* CONFIG_PPC_ISERIES */ - /*** Common interrupt handlers ***/ STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index b6e2f8c0b093..b5f600616ade 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -30,6 +30,8 @@ #include #include #include +#include +#include .text @@ -83,6 +85,140 @@ iSeries_secondary_smp_loop: b 1b /* If SMP not configured, secondaries * loop forever */ +/*** ISeries-LPAR interrupt handlers ***/ + + STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC) + + .globl data_access_iSeries +data_access_iSeries: + mtspr SPRN_SPRG1,r13 +BEGIN_FTR_SECTION + mtspr SPRN_SPRG2,r12 + mfspr r13,SPRN_DAR + mfspr r12,SPRN_DSISR + srdi r13,r13,60 + rlwimi r13,r12,16,0x20 + mfcr r12 + cmpwi r13,0x2c + beq .do_stab_bolted_iSeries + mtcrf 0x80,r12 + mfspr r12,SPRN_SPRG2 +END_FTR_SECTION_IFCLR(CPU_FTR_SLB) + EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN) + EXCEPTION_PROLOG_ISERIES_2 + b data_access_common + +.do_stab_bolted_iSeries: + mtcrf 0x80,r12 + mfspr r12,SPRN_SPRG2 + EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) + EXCEPTION_PROLOG_ISERIES_2 + b .do_stab_bolted + + .globl data_access_slb_iSeries +data_access_slb_iSeries: + mtspr SPRN_SPRG1,r13 /* save r13 */ + mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ + std r3,PACA_EXSLB+EX_R3(r13) + mfspr r3,SPRN_DAR + std r9,PACA_EXSLB+EX_R9(r13) + mfcr r9 +#ifdef __DISABLED__ + cmpdi r3,0 + bge slb_miss_user_iseries +#endif + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + mfspr r10,SPRN_SPRG1 + std r10,PACA_EXSLB+EX_R13(r13) + ld r12,PACALPPACAPTR(r13) + ld r12,LPPACASRR1(r12) + b .slb_miss_realmode + + STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN) + + .globl instruction_access_slb_iSeries +instruction_access_slb_iSeries: + mtspr SPRN_SPRG1,r13 /* save r13 */ + mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ + std r3,PACA_EXSLB+EX_R3(r13) + ld r3,PACALPPACAPTR(r13) + ld r3,LPPACASRR0(r3) /* get SRR0 value */ + std r9,PACA_EXSLB+EX_R9(r13) + mfcr r9 +#ifdef __DISABLED__ + cmpdi r3,0 + bge slb_miss_user_iseries +#endif + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + mfspr r10,SPRN_SPRG1 + std r10,PACA_EXSLB+EX_R13(r13) + ld r12,PACALPPACAPTR(r13) + ld r12,LPPACASRR1(r12) + b .slb_miss_realmode + +#ifdef __DISABLED__ +slb_miss_user_iseries: + std r10,PACA_EXGEN+EX_R10(r13) + std r11,PACA_EXGEN+EX_R11(r13) + std r12,PACA_EXGEN+EX_R12(r13) + mfspr r10,SPRG1 + ld r11,PACA_EXSLB+EX_R9(r13) + ld r12,PACA_EXSLB+EX_R3(r13) + std r10,PACA_EXGEN+EX_R13(r13) + std r11,PACA_EXGEN+EX_R9(r13) + std r12,PACA_EXGEN+EX_R3(r13) + EXCEPTION_PROLOG_ISERIES_2 + b slb_miss_user_common +#endif + + MASKABLE_EXCEPTION_ISERIES(0x500, hardware_interrupt) + STD_EXCEPTION_ISERIES(0x600, alignment, PACA_EXGEN) + STD_EXCEPTION_ISERIES(0x700, program_check, PACA_EXGEN) + STD_EXCEPTION_ISERIES(0x800, fp_unavailable, PACA_EXGEN) + MASKABLE_EXCEPTION_ISERIES(0x900, decrementer) + STD_EXCEPTION_ISERIES(0xa00, trap_0a, PACA_EXGEN) + STD_EXCEPTION_ISERIES(0xb00, trap_0b, PACA_EXGEN) + + .globl system_call_iSeries +system_call_iSeries: + mr r9,r13 + mfspr r13,SPRN_SPRG3 + EXCEPTION_PROLOG_ISERIES_2 + b system_call_common + + STD_EXCEPTION_ISERIES( 0xd00, single_step, PACA_EXGEN) + STD_EXCEPTION_ISERIES( 0xe00, trap_0e, PACA_EXGEN) + STD_EXCEPTION_ISERIES( 0xf00, performance_monitor, PACA_EXGEN) + +decrementer_iSeries_masked: + /* We may not have a valid TOC pointer in here. */ + li r11,1 + ld r12,PACALPPACAPTR(r13) + stb r11,LPPACADECRINT(r12) + LOAD_REG_IMMEDIATE(r12, tb_ticks_per_jiffy) + lwz r12,0(r12) + mtspr SPRN_DEC,r12 + /* fall through */ + +hardware_interrupt_iSeries_masked: + mtcrf 0x80,r9 /* Restore regs */ + ld r12,PACALPPACAPTR(r13) + ld r11,LPPACASRR0(r12) + ld r12,LPPACASRR1(r12) + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 + ld r9,PACA_EXGEN+EX_R9(r13) + ld r10,PACA_EXGEN+EX_R10(r13) + ld r11,PACA_EXGEN+EX_R11(r13) + ld r12,PACA_EXGEN+EX_R12(r13) + ld r13,PACA_EXGEN+EX_R13(r13) + rfid + b . /* prevent speculative execution */ + _INIT_STATIC(__start_initialization_iSeries) /* Clear out the BSS */ LOAD_REG_IMMEDIATE(r11,__bss_stop) From 7180e3e636deff82f8810291878a184f21142fa9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 22 Aug 2007 13:48:37 +1000 Subject: [PATCH 0162/2804] [POWERPC] Split out iSeries specific exception macros Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/exception.S | 15 ++--- arch/powerpc/platforms/iseries/exception.h | 58 ++++++++++++++++++ include/asm-powerpc/exception.h | 71 ++++------------------ 3 files changed, 78 insertions(+), 66 deletions(-) create mode 100644 arch/powerpc/platforms/iseries/exception.h diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index b5f600616ade..e9a3435b3c18 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -30,9 +30,10 @@ #include #include #include -#include #include +#include "exception.h" + .text .globl system_reset_iSeries @@ -104,15 +105,15 @@ BEGIN_FTR_SECTION mtcrf 0x80,r12 mfspr r12,SPRN_SPRG2 END_FTR_SECTION_IFCLR(CPU_FTR_SLB) - EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN) - EXCEPTION_PROLOG_ISERIES_2 + EXCEPTION_PROLOG_1(PACA_EXGEN) + EXCEPTION_PROLOG_ISERIES_1 b data_access_common .do_stab_bolted_iSeries: mtcrf 0x80,r12 mfspr r12,SPRN_SPRG2 - EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - EXCEPTION_PROLOG_ISERIES_2 + EXCEPTION_PROLOG_1(PACA_EXSLB) + EXCEPTION_PROLOG_ISERIES_1 b .do_stab_bolted .globl data_access_slb_iSeries @@ -171,7 +172,7 @@ slb_miss_user_iseries: std r10,PACA_EXGEN+EX_R13(r13) std r11,PACA_EXGEN+EX_R9(r13) std r12,PACA_EXGEN+EX_R3(r13) - EXCEPTION_PROLOG_ISERIES_2 + EXCEPTION_PROLOG_ISERIES_1 b slb_miss_user_common #endif @@ -187,7 +188,7 @@ slb_miss_user_iseries: system_call_iSeries: mr r9,r13 mfspr r13,SPRN_SPRG3 - EXCEPTION_PROLOG_ISERIES_2 + EXCEPTION_PROLOG_ISERIES_1 b system_call_common STD_EXCEPTION_ISERIES( 0xd00, single_step, PACA_EXGEN) diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h new file mode 100644 index 000000000000..5b3f285e8168 --- /dev/null +++ b/arch/powerpc/platforms/iseries/exception.h @@ -0,0 +1,58 @@ +#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H +#define _ASM_POWERPC_ISERIES_EXCEPTION_H +/* + * Extracted from head_64.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * 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 EXCEPTION_PROLOG_ISERIES_1 \ + mfmsr r10; \ + ld r12,PACALPPACAPTR(r13); \ + ld r11,LPPACASRR0(r12); \ + ld r12,LPPACASRR1(r12); \ + ori r10,r10,MSR_RI; \ + mtmsrd r10,1 + +#define STD_EXCEPTION_ISERIES(n, label, area) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_1(area); \ + EXCEPTION_PROLOG_ISERIES_1; \ + b label##_common + +#define MASKABLE_EXCEPTION_ISERIES(n, label) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_1(PACA_EXGEN); \ + lbz r10,PACASOFTIRQEN(r13); \ + cmpwi 0,r10,0; \ + beq- label##_iSeries_masked; \ + EXCEPTION_PROLOG_ISERIES_1; \ + b label##_common; \ + +#endif /* _ASM_POWERPC_ISERIES_EXCEPTION_H */ diff --git a/include/asm-powerpc/exception.h b/include/asm-powerpc/exception.h index 1980ed364a9c..d850c8ea5903 100644 --- a/include/asm-powerpc/exception.h +++ b/include/asm-powerpc/exception.h @@ -62,6 +62,16 @@ ori reg,reg,(label)@l; /* virt addr of handler ... */ #endif +#define EXCEPTION_PROLOG_1(area) \ + mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ + std r9,area+EX_R9(r13); /* save r9 - r12 */ \ + std r10,area+EX_R10(r13); \ + std r11,area+EX_R11(r13); \ + std r12,area+EX_R12(r13); \ + mfspr r9,SPRN_SPRG1; \ + std r9,area+EX_R13(r13); \ + mfcr r9 + /* * Equal to EXCEPTION_PROLOG_PSERIES, except that it forces 64bit mode. * The firmware calls the registered system_reset_fwnmi and @@ -70,14 +80,7 @@ * This firmware bug is present on POWER4 and JS20. */ #define EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(area, label) \ - mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ - std r9,area+EX_R9(r13); /* save r9 - r12 */ \ - std r10,area+EX_R10(r13); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG1; \ - std r9,area+EX_R13(r13); \ - mfcr r9; \ + EXCEPTION_PROLOG_1(area); \ clrrdi r12,r13,32; /* get high part of &label */ \ mfmsr r10; \ /* force 64bit mode */ \ @@ -94,14 +97,7 @@ b . /* prevent speculative execution */ #define EXCEPTION_PROLOG_PSERIES(area, label) \ - mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ - std r9,area+EX_R9(r13); /* save r9 - r12 */ \ - std r10,area+EX_R10(r13); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG1; \ - std r9,area+EX_R13(r13); \ - mfcr r9; \ + EXCEPTION_PROLOG_1(area); \ clrrdi r12,r13,32; /* get high part of &label */ \ mfmsr r10; \ mfspr r11,SPRN_SRR0; /* save SRR0 */ \ @@ -113,28 +109,6 @@ rfid; \ b . /* prevent speculative execution */ -/* - * This is the start of the interrupt handlers for iSeries - * This code runs with relocation on. - */ -#define EXCEPTION_PROLOG_ISERIES_1(area) \ - mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ - std r9,area+EX_R9(r13); /* save r9 - r12 */ \ - std r10,area+EX_R10(r13); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG1; \ - std r9,area+EX_R13(r13); \ - mfcr r9 - -#define EXCEPTION_PROLOG_ISERIES_2 \ - mfmsr r10; \ - ld r12,PACALPPACAPTR(r13); \ - ld r11,LPPACASRR0(r12); \ - ld r12,LPPACASRR1(r12); \ - ori r10,r10,MSR_RI; \ - mtmsrd r10,1 - /* * The common exception prolog is used for all except a few exceptions * such as a segment miss on a kernel address. We have to be prepared @@ -247,27 +221,6 @@ label##_pSeries: \ rfid; \ b . /* prevent speculative execution */ -#define STD_EXCEPTION_ISERIES(n, label, area) \ - .globl label##_iSeries; \ -label##_iSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG1,r13; /* save r13 */ \ - EXCEPTION_PROLOG_ISERIES_1(area); \ - EXCEPTION_PROLOG_ISERIES_2; \ - b label##_common - -#define MASKABLE_EXCEPTION_ISERIES(n, label) \ - .globl label##_iSeries; \ -label##_iSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG1,r13; /* save r13 */ \ - EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ - lbz r10,PACASOFTIRQEN(r13); \ - cmpwi 0,r10,0; \ - beq- label##_iSeries_masked; \ - EXCEPTION_PROLOG_ISERIES_2; \ - b label##_common; \ - #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ li r11,0; \ From 5b072ba453078293b8f6de8cdd79d9c26f015238 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 22 Aug 2007 13:49:41 +1000 Subject: [PATCH 0163/2804] [POWERPC] Exception numbers are not relevant to iSeries so remove them from the macros. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/exception.S | 24 +++++++++++----------- arch/powerpc/platforms/iseries/exception.h | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index e9a3435b3c18..5381038f0881 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -88,7 +88,7 @@ iSeries_secondary_smp_loop: /*** ISeries-LPAR interrupt handlers ***/ - STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC) + STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC) .globl data_access_iSeries data_access_iSeries: @@ -137,7 +137,7 @@ data_access_slb_iSeries: ld r12,LPPACASRR1(r12) b .slb_miss_realmode - STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN) + STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN) .globl instruction_access_slb_iSeries instruction_access_slb_iSeries: @@ -176,13 +176,13 @@ slb_miss_user_iseries: b slb_miss_user_common #endif - MASKABLE_EXCEPTION_ISERIES(0x500, hardware_interrupt) - STD_EXCEPTION_ISERIES(0x600, alignment, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0x700, program_check, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0x800, fp_unavailable, PACA_EXGEN) - MASKABLE_EXCEPTION_ISERIES(0x900, decrementer) - STD_EXCEPTION_ISERIES(0xa00, trap_0a, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0xb00, trap_0b, PACA_EXGEN) + MASKABLE_EXCEPTION_ISERIES(hardware_interrupt) + STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN) + STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN) + STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN) + MASKABLE_EXCEPTION_ISERIES(decrementer) + STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN) + STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN) .globl system_call_iSeries system_call_iSeries: @@ -191,9 +191,9 @@ system_call_iSeries: EXCEPTION_PROLOG_ISERIES_1 b system_call_common - STD_EXCEPTION_ISERIES( 0xd00, single_step, PACA_EXGEN) - STD_EXCEPTION_ISERIES( 0xe00, trap_0e, PACA_EXGEN) - STD_EXCEPTION_ISERIES( 0xf00, performance_monitor, PACA_EXGEN) + STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN) + STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN) + STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN) decrementer_iSeries_masked: /* We may not have a valid TOC pointer in here. */ diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h index 5b3f285e8168..ced45a8fa1aa 100644 --- a/arch/powerpc/platforms/iseries/exception.h +++ b/arch/powerpc/platforms/iseries/exception.h @@ -34,7 +34,7 @@ ori r10,r10,MSR_RI; \ mtmsrd r10,1 -#define STD_EXCEPTION_ISERIES(n, label, area) \ +#define STD_EXCEPTION_ISERIES(label, area) \ .globl label##_iSeries; \ label##_iSeries: \ HMT_MEDIUM; \ @@ -43,7 +43,7 @@ label##_iSeries: \ EXCEPTION_PROLOG_ISERIES_1; \ b label##_common -#define MASKABLE_EXCEPTION_ISERIES(n, label) \ +#define MASKABLE_EXCEPTION_ISERIES(label) \ .globl label##_iSeries; \ label##_iSeries: \ HMT_MEDIUM; \ From ed16c20da6f500bc2dfad933078d2987636a7b60 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 17 Aug 2007 01:47:39 -0500 Subject: [PATCH 0164/2804] [POWERPC] Remove old includes from arch/ppc Remove includes of files that existed in arch/ppc that we dont need in arch/powerpc anymore. The following includes were removed: This also caused platforms/embedded6xx/mpc7448_hpc2.h to no longer be needed and thus removed. Signed-off-by: Kumar Gala --- arch/powerpc/kernel/setup_32.c | 2 -- arch/powerpc/platforms/52xx/lite5200.c | 1 - arch/powerpc/platforms/82xx/m82xx_pci.h | 2 -- arch/powerpc/platforms/82xx/mpc82xx.c | 1 - arch/powerpc/platforms/82xx/mpc82xx_ads.c | 1 - arch/powerpc/platforms/82xx/pq2ads.h | 1 - arch/powerpc/platforms/83xx/mpc832x_mds.c | 1 - arch/powerpc/platforms/83xx/mpc834x_itx.c | 1 - arch/powerpc/platforms/83xx/mpc834x_mds.c | 1 - arch/powerpc/platforms/83xx/mpc836x_mds.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_cds.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_mds.c | 1 - arch/powerpc/platforms/8xx/m8xx_setup.c | 4 ++-- arch/powerpc/platforms/8xx/mpc86xads.h | 1 - arch/powerpc/platforms/8xx/mpc86xads_setup.c | 1 - arch/powerpc/platforms/8xx/mpc885ads.h | 1 - arch/powerpc/platforms/8xx/mpc885ads_setup.c | 1 - arch/powerpc/platforms/chrp/smp.c | 1 - arch/powerpc/platforms/embedded6xx/ls_uart.c | 1 - .../platforms/embedded6xx/mpc7448_hpc2.c | 1 - .../platforms/embedded6xx/mpc7448_hpc2.h | 21 ------------------- arch/powerpc/platforms/powermac/bootx_init.c | 1 - drivers/macintosh/adb-iop.c | 1 - 23 files changed, 2 insertions(+), 46 deletions(-) delete mode 100644 arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 7ec6ba56d83d..a288a5f2dbc6 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -18,13 +18,11 @@ #include #include -#include #include #include #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 84bd3da43afd..ce3f6951828e 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/m82xx_pci.h b/arch/powerpc/platforms/82xx/m82xx_pci.h index 9cd8893b5a32..65e38a7ff48f 100644 --- a/arch/powerpc/platforms/82xx/m82xx_pci.h +++ b/arch/powerpc/platforms/82xx/m82xx_pci.h @@ -8,8 +8,6 @@ * 2 of the License, or (at your option) any later version. */ -#include - #define SIU_INT_IRQ1 ((uint)0x13 + CPM_IRQ_OFFSET) #ifndef _IO_BASE diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c index cc9900d2e5ee..c706871aec1a 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx.c +++ b/arch/powerpc/platforms/82xx/mpc82xx.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 2d1b05b9f8ef..c0a0c56ac5b3 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h index 5b5cca6c8c88..6f749b76dd8f 100644 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ b/arch/powerpc/platforms/82xx/pq2ads.h @@ -23,7 +23,6 @@ #define __MACH_ADS8260_DEFS #include -#include /* For our show_cpuinfo hooks. */ #define CPUINFO_VENDOR "Freescale Semiconductor" diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 2c8e641a739b..61e3f1cb0a7e 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 47ba5446f63c..6d06645e5ba8 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 4c9ff9cadfe4..f8aba9a488bc 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 84b58934aafd..69970b910c12 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 6a171e9abf7d..040233472385 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index be25ecd911ba..53830c9a88fd 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 601b389b570b..b2b98dd8be6a 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -36,13 +36,11 @@ #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -55,7 +53,9 @@ struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; #endif void m8xx_calibrate_decr(void); +#ifdef CONFIG_8xx_WDT extern void m8xx_wdt_handler_install(bd_t *bp); +#endif extern int cpm_pic_init(void); extern int cpm_get_irq(void); diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h index 59bad2f9ae51..dd10cd20b6a7 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads.h +++ b/arch/powerpc/platforms/8xx/mpc86xads.h @@ -15,7 +15,6 @@ #ifndef __ASM_MPC86XADS_H__ #define __ASM_MPC86XADS_H__ -#include #include /* U-Boot maps BCSR to 0xff080000 */ diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c index d881647e9923..8f64f48698ab 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h index 7c31aec284c2..14db12417064 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads.h +++ b/arch/powerpc/platforms/8xx/mpc885ads.h @@ -15,7 +15,6 @@ #ifndef __ASM_MPC885ADS_H__ #define __ASM_MPC885ADS_H__ -#include #include /* U-Boot maps BCSR to 0xff080000 */ diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index bd5ff7a892e0..d3da38586b04 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index a137d13008bc..10a4a4d063b6 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index d0bee9f19e4e..f7a4def5eff4 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 25c29bc94988..96737e5608d3 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -40,7 +40,6 @@ #include #include #include -#include "mpc7448_hpc2.h" #include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h deleted file mode 100644 index f7e0e0c7f8d8..000000000000 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * mpc7448_hpc2.h - * - * Definitions for Freescale MPC7448_HPC2 platform - * - * Author: Jacob Pan - * jacob.pan@freescale.com - * Maintainer: Roy Zang - * - * 2006 (c) Freescale 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 warranty of any kind, whether express - * or implied. - */ - -#ifndef __PPC_PLATFORMS_MPC7448_HPC2_H -#define __PPC_PLATFORMS_MPC7448_HPC2_H - -#include - -#endif /* __PPC_PLATFORMS_MPC7448_HPC2_H */ diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index 9d73d0234c5d..cf660916ae0b 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c index 17ef5d3c01b4..444696625171 100644 --- a/drivers/macintosh/adb-iop.c +++ b/drivers/macintosh/adb-iop.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include From 33d71d26ba982f99b8cb76b86b2e1e0a0964a8ac Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 20 Aug 2007 08:50:28 -0500 Subject: [PATCH 0165/2804] [POWERPC] Copy over headers from arch/ppc to arch/powerpc that we need To build arch/powerpc without including asm-ppc/ we need these files in asm-powerpc/ Moved some headers under arch/powerpc/platforms if they were only used by platform or driver files and fixed up the source file includes to match the new locations Signed-off-by: Kumar Gala --- arch/powerpc/platforms/chrp/gg2.h | 61 + arch/powerpc/platforms/chrp/pci.c | 2 +- arch/powerpc/platforms/chrp/setup.c | 2 +- .../platforms/embedded6xx/linkstation.c | 3 +- arch/powerpc/platforms/embedded6xx/ls_uart.c | 3 +- arch/powerpc/platforms/embedded6xx/mpc10x.h | 180 +++ drivers/macintosh/ans-lcd.c | 3 +- .../asm-ppc => drivers/macintosh}/ans-lcd.h | 0 include/asm-powerpc/8xx_immap.h | 564 ++++++++ include/asm-powerpc/commproc.h | 692 +++++++++ include/asm-powerpc/cpm2.h | 1248 +++++++++++++++++ include/asm-powerpc/highmem.h | 135 ++ include/asm-powerpc/hydra.h | 102 ++ include/asm-powerpc/immap_cpm2.h | 648 +++++++++ include/asm-powerpc/kgdb.h | 57 + include/asm-powerpc/mpc52xx_psc.h | 191 +++ 16 files changed, 3886 insertions(+), 5 deletions(-) create mode 100644 arch/powerpc/platforms/chrp/gg2.h create mode 100644 arch/powerpc/platforms/embedded6xx/mpc10x.h rename {include/asm-ppc => drivers/macintosh}/ans-lcd.h (100%) create mode 100644 include/asm-powerpc/8xx_immap.h create mode 100644 include/asm-powerpc/commproc.h create mode 100644 include/asm-powerpc/cpm2.h create mode 100644 include/asm-powerpc/highmem.h create mode 100644 include/asm-powerpc/hydra.h create mode 100644 include/asm-powerpc/immap_cpm2.h create mode 100644 include/asm-powerpc/kgdb.h create mode 100644 include/asm-powerpc/mpc52xx_psc.h diff --git a/arch/powerpc/platforms/chrp/gg2.h b/arch/powerpc/platforms/chrp/gg2.h new file mode 100644 index 000000000000..341ae55b99fb --- /dev/null +++ b/arch/powerpc/platforms/chrp/gg2.h @@ -0,0 +1,61 @@ +/* + * include/asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is based on the following documentation: + * + * The VAS96011/12 Chipset, Data Book, Edition 1.0 + * VLSI Technology, Inc. + * + * 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. + */ + +#ifndef _ASMPPC_GG2_H +#define _ASMPPC_GG2_H + + /* + * Memory Map (CHRP mode) + */ + +#define GG2_PCI_MEM_BASE 0xc0000000 /* Peripheral memory space */ +#define GG2_ISA_MEM_BASE 0xf7000000 /* Peripheral memory alias */ +#define GG2_ISA_IO_BASE 0xf8000000 /* Peripheral I/O space */ +#define GG2_PCI_CONFIG_BASE 0xfec00000 /* PCI configuration space */ +#define GG2_INT_ACK_SPECIAL 0xfec80000 /* Interrupt acknowledge and */ + /* special PCI cycles */ +#define GG2_ROM_BASE0 0xff000000 /* ROM bank 0 */ +#define GG2_ROM_BASE1 0xff800000 /* ROM bank 1 */ + + + /* + * GG2 specific PCI Registers + */ + +extern void __iomem *gg2_pci_config_base; /* kernel virtual address */ + +#define GG2_PCI_BUSNO 0x40 /* Bus number */ +#define GG2_PCI_SUBBUSNO 0x41 /* Subordinate bus number */ +#define GG2_PCI_DISCCTR 0x42 /* Disconnect counter */ +#define GG2_PCI_PPC_CTRL 0x50 /* PowerPC interface control register */ +#define GG2_PCI_ADDR_MAP 0x5c /* Address map */ +#define GG2_PCI_PCI_CTRL 0x60 /* PCI interface control register */ +#define GG2_PCI_ROM_CTRL 0x70 /* ROM interface control register */ +#define GG2_PCI_ROM_TIME 0x74 /* ROM timing */ +#define GG2_PCI_CC_CTRL 0x80 /* Cache controller control register */ +#define GG2_PCI_DRAM_BANK0 0x90 /* Control register for DRAM bank #0 */ +#define GG2_PCI_DRAM_BANK1 0x94 /* Control register for DRAM bank #1 */ +#define GG2_PCI_DRAM_BANK2 0x98 /* Control register for DRAM bank #2 */ +#define GG2_PCI_DRAM_BANK3 0x9c /* Control register for DRAM bank #3 */ +#define GG2_PCI_DRAM_BANK4 0xa0 /* Control register for DRAM bank #4 */ +#define GG2_PCI_DRAM_BANK5 0xa4 /* Control register for DRAM bank #5 */ +#define GG2_PCI_DRAM_TIME0 0xb0 /* Timing parameters set #0 */ +#define GG2_PCI_DRAM_TIME1 0xb4 /* Timing parameters set #1 */ +#define GG2_PCI_DRAM_CTRL 0xc0 /* DRAM control */ +#define GG2_PCI_ERR_CTRL 0xd0 /* Error control register */ +#define GG2_PCI_ERR_STATUS 0xd4 /* Error status register */ + /* Cleared when read */ + +#endif /* _ASMPPC_GG2_H */ diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index 974952ed15cb..e43465d34d29 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -21,6 +20,7 @@ #include #include "chrp.h" +#include "gg2.h" /* LongTrail */ void __iomem *gg2_pci_config_base; diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index dde5ef4dde35..96498ad7b943 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -51,6 +50,7 @@ #include #include "chrp.h" +#include "gg2.h" void rtas_indicator_progress(char *, unsigned short); diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 8c60e0207d02..61ca02c2d644 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -18,9 +18,10 @@ #include #include #include -#include #include +#include "mpc10x.h" + static struct mtd_partition linkstation_physmap_partitions[] = { { .name = "mtd_firmimg", diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index f7a4def5eff4..0d9f1500a671 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -4,10 +4,11 @@ #include #include #include -#include #include #include +#include "mpc10x.h" + static void __iomem *avr_addr; static unsigned long avr_clock; diff --git a/arch/powerpc/platforms/embedded6xx/mpc10x.h b/arch/powerpc/platforms/embedded6xx/mpc10x.h new file mode 100644 index 000000000000..b30a6a3b5bd2 --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/mpc10x.h @@ -0,0 +1,180 @@ +/* + * Common routines for the Motorola SPS MPC106/8240/107 Host bridge/Mem + * ctlr/EPIC/etc. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef __PPC_KERNEL_MPC10X_H +#define __PPC_KERNEL_MPC10X_H + +#include +#include + +/* + * The values here don't completely map everything but should work in most + * cases. + * + * MAP A (PReP Map) + * Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff + * Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff + * PCI MEM: 0x80000000 -> Processor System Memory: 0x00000000 + * EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB) + * + * MAP B (CHRP Map) + * Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff + * Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff + * PCI MEM: 0x00000000 -> Processor System Memory: 0x00000000 + * EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB) + */ + +/* + * Define the vendor/device IDs for the various bridges--should be added to + * + */ +#define MPC10X_BRIDGE_106 ((PCI_DEVICE_ID_MOTOROLA_MPC106 << 16) | \ + PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_8240 ((0x0003 << 16) | PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_107 ((0x0004 << 16) | PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_8245 ((0x0006 << 16) | PCI_VENDOR_ID_MOTOROLA) + +/* Define the type of map to use */ +#define MPC10X_MEM_MAP_A 1 +#define MPC10X_MEM_MAP_B 2 + +/* Map A (PReP Map) Defines */ +#define MPC10X_MAPA_CNFG_ADDR 0x80000cf8 +#define MPC10X_MAPA_CNFG_DATA 0x80000cfc + +#define MPC10X_MAPA_ISA_IO_BASE 0x80000000 +#define MPC10X_MAPA_ISA_MEM_BASE 0xc0000000 +#define MPC10X_MAPA_DRAM_OFFSET 0x80000000 + +#define MPC10X_MAPA_PCI_INTACK_ADDR 0xbffffff0 +#define MPC10X_MAPA_PCI_IO_START 0x00000000 +#define MPC10X_MAPA_PCI_IO_END (0x00800000 - 1) +#define MPC10X_MAPA_PCI_MEM_START 0x00000000 +#define MPC10X_MAPA_PCI_MEM_END (0x20000000 - 1) + +#define MPC10X_MAPA_PCI_MEM_OFFSET (MPC10X_MAPA_ISA_MEM_BASE - \ + MPC10X_MAPA_PCI_MEM_START) + +/* Map B (CHRP Map) Defines */ +#define MPC10X_MAPB_CNFG_ADDR 0xfec00000 +#define MPC10X_MAPB_CNFG_DATA 0xfee00000 + +#define MPC10X_MAPB_ISA_IO_BASE 0xfe000000 +#define MPC10X_MAPB_ISA_MEM_BASE 0x80000000 +#define MPC10X_MAPB_DRAM_OFFSET 0x00000000 + +#define MPC10X_MAPB_PCI_INTACK_ADDR 0xfef00000 +#define MPC10X_MAPB_PCI_IO_START 0x00000000 +#define MPC10X_MAPB_PCI_IO_END (0x00c00000 - 1) +#define MPC10X_MAPB_PCI_MEM_START 0x80000000 +#define MPC10X_MAPB_PCI_MEM_END (0xc0000000 - 1) + +#define MPC10X_MAPB_PCI_MEM_OFFSET (MPC10X_MAPB_ISA_MEM_BASE - \ + MPC10X_MAPB_PCI_MEM_START) + +/* Set hose members to values appropriate for the mem map used */ +#define MPC10X_SETUP_HOSE(hose, map) { \ + (hose)->pci_mem_offset = MPC10X_MAP##map##_PCI_MEM_OFFSET; \ + (hose)->io_space.start = MPC10X_MAP##map##_PCI_IO_START; \ + (hose)->io_space.end = MPC10X_MAP##map##_PCI_IO_END; \ + (hose)->mem_space.start = MPC10X_MAP##map##_PCI_MEM_START; \ + (hose)->mem_space.end = MPC10X_MAP##map##_PCI_MEM_END; \ + (hose)->io_base_virt = (void *)MPC10X_MAP##map##_ISA_IO_BASE; \ +} + + +/* Miscellaneous Configuration register offsets */ +#define MPC10X_CFG_PIR_REG 0x09 +#define MPC10X_CFG_PIR_HOST_BRIDGE 0x00 +#define MPC10X_CFG_PIR_AGENT 0x01 + +#define MPC10X_CFG_EUMBBAR 0x78 + +#define MPC10X_CFG_PICR1_REG 0xa8 +#define MPC10X_CFG_PICR1_ADDR_MAP_MASK 0x00010000 +#define MPC10X_CFG_PICR1_ADDR_MAP_A 0x00010000 +#define MPC10X_CFG_PICR1_ADDR_MAP_B 0x00000000 +#define MPC10X_CFG_PICR1_SPEC_PCI_RD 0x00000004 +#define MPC10X_CFG_PICR1_ST_GATH_EN 0x00000040 + +#define MPC10X_CFG_PICR2_REG 0xac +#define MPC10X_CFG_PICR2_COPYBACK_OPT 0x00000001 + +#define MPC10X_CFG_MAPB_OPTIONS_REG 0xe0 +#define MPC10X_CFG_MAPB_OPTIONS_CFAE 0x80 /* CPU_FD_ALIAS_EN */ +#define MPC10X_CFG_MAPB_OPTIONS_PFAE 0x40 /* PCI_FD_ALIAS_EN */ +#define MPC10X_CFG_MAPB_OPTIONS_DR 0x20 /* DLL_RESET */ +#define MPC10X_CFG_MAPB_OPTIONS_PCICH 0x08 /* PCI_COMPATIBILITY_HOLE */ +#define MPC10X_CFG_MAPB_OPTIONS_PROCCH 0x04 /* PROC_COMPATIBILITY_HOLE */ + +/* Define offsets for the memory controller registers in the config space */ +#define MPC10X_MCTLR_MEM_START_1 0x80 /* Banks 0-3 */ +#define MPC10X_MCTLR_MEM_START_2 0x84 /* Banks 4-7 */ +#define MPC10X_MCTLR_EXT_MEM_START_1 0x88 /* Banks 0-3 */ +#define MPC10X_MCTLR_EXT_MEM_START_2 0x8c /* Banks 4-7 */ + +#define MPC10X_MCTLR_MEM_END_1 0x90 /* Banks 0-3 */ +#define MPC10X_MCTLR_MEM_END_2 0x94 /* Banks 4-7 */ +#define MPC10X_MCTLR_EXT_MEM_END_1 0x98 /* Banks 0-3 */ +#define MPC10X_MCTLR_EXT_MEM_END_2 0x9c /* Banks 4-7 */ + +#define MPC10X_MCTLR_MEM_BANK_ENABLES 0xa0 + +/* Define some offset in the EUMB */ +#define MPC10X_EUMB_SIZE 0x00100000 /* Total EUMB size (1MB) */ + +#define MPC10X_EUMB_MU_OFFSET 0x00000000 /* Msg Unit reg offset */ +#define MPC10X_EUMB_MU_SIZE 0x00001000 /* Msg Unit reg size */ +#define MPC10X_EUMB_DMA_OFFSET 0x00001000 /* DMA Unit reg offset */ +#define MPC10X_EUMB_DMA_SIZE 0x00001000 /* DMA Unit reg size */ +#define MPC10X_EUMB_ATU_OFFSET 0x00002000 /* Addr xlate reg offset */ +#define MPC10X_EUMB_ATU_SIZE 0x00001000 /* Addr xlate reg size */ +#define MPC10X_EUMB_I2C_OFFSET 0x00003000 /* I2C Unit reg offset */ +#define MPC10X_EUMB_I2C_SIZE 0x00001000 /* I2C Unit reg size */ +#define MPC10X_EUMB_DUART_OFFSET 0x00004000 /* DUART Unit reg offset (8245) */ +#define MPC10X_EUMB_DUART_SIZE 0x00001000 /* DUART Unit reg size (8245) */ +#define MPC10X_EUMB_EPIC_OFFSET 0x00040000 /* EPIC offset in EUMB */ +#define MPC10X_EUMB_EPIC_SIZE 0x00030000 /* EPIC size */ +#define MPC10X_EUMB_PM_OFFSET 0x000fe000 /* Performance Monitor reg offset (8245) */ +#define MPC10X_EUMB_PM_SIZE 0x00001000 /* Performance Monitor reg size (8245) */ +#define MPC10X_EUMB_WP_OFFSET 0x000ff000 /* Data path diagnostic, watchpoint reg offset */ +#define MPC10X_EUMB_WP_SIZE 0x00001000 /* Data path diagnostic, watchpoint reg size */ + +/* + * Define some recommended places to put the EUMB regs. + * For both maps, recommend putting the EUMB from 0xeff00000 to 0xefffffff. + */ +extern unsigned long ioremap_base; +#define MPC10X_MAPA_EUMB_BASE (ioremap_base - MPC10X_EUMB_SIZE) +#define MPC10X_MAPB_EUMB_BASE MPC10X_MAPA_EUMB_BASE + +enum ppc_sys_devices { + MPC10X_IIC1, + MPC10X_DMA0, + MPC10X_DMA1, + MPC10X_UART0, + MPC10X_UART1, + NUM_PPC_SYS_DEVS, +}; + +int mpc10x_bridge_init(struct pci_controller *hose, + uint current_map, + uint new_map, + uint phys_eumb_base); +unsigned long mpc10x_get_mem_size(uint mem_map); +int mpc10x_enable_store_gathering(struct pci_controller *hose); +int mpc10x_disable_store_gathering(struct pci_controller *hose); + +/* For MPC107 boards that use the built-in openpic */ +void mpc10x_set_openpic(void); + +#endif /* __PPC_KERNEL_MPC10X_H */ diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c index e54c4d9f6365..73c50bc02095 100644 --- a/drivers/macintosh/ans-lcd.c +++ b/drivers/macintosh/ans-lcd.c @@ -14,9 +14,10 @@ #include #include #include -#include #include +#include "ans-lcd.h" + #define ANSLCD_ADDR 0xf301c000 #define ANSLCD_CTRL_IX 0x00 #define ANSLCD_DATA_IX 0x10 diff --git a/include/asm-ppc/ans-lcd.h b/drivers/macintosh/ans-lcd.h similarity index 100% rename from include/asm-ppc/ans-lcd.h rename to drivers/macintosh/ans-lcd.h diff --git a/include/asm-powerpc/8xx_immap.h b/include/asm-powerpc/8xx_immap.h new file mode 100644 index 000000000000..1311cefdfd30 --- /dev/null +++ b/include/asm-powerpc/8xx_immap.h @@ -0,0 +1,564 @@ +/* + * MPC8xx Internal Memory Map + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * The I/O on the MPC860 is comprised of blocks of special registers + * and the dual port ram for the Communication Processor Module. + * Within this space are functional units such as the SIU, memory + * controller, system timers, and other control functions. It is + * a combination that I found difficult to separate into logical + * functional files.....but anyone else is welcome to try. -- Dan + */ +#ifdef __KERNEL__ +#ifndef __IMMAP_8XX__ +#define __IMMAP_8XX__ + +/* System configuration registers. +*/ +typedef struct sys_conf { + uint sc_siumcr; + uint sc_sypcr; + uint sc_swt; + char res1[2]; + ushort sc_swsr; + uint sc_sipend; + uint sc_simask; + uint sc_siel; + uint sc_sivec; + uint sc_tesr; + char res2[0xc]; + uint sc_sdcr; + char res3[0x4c]; +} sysconf8xx_t; + +/* PCMCIA configuration registers. +*/ +typedef struct pcmcia_conf { + uint pcmc_pbr0; + uint pcmc_por0; + uint pcmc_pbr1; + uint pcmc_por1; + uint pcmc_pbr2; + uint pcmc_por2; + uint pcmc_pbr3; + uint pcmc_por3; + uint pcmc_pbr4; + uint pcmc_por4; + uint pcmc_pbr5; + uint pcmc_por5; + uint pcmc_pbr6; + uint pcmc_por6; + uint pcmc_pbr7; + uint pcmc_por7; + char res1[0x20]; + uint pcmc_pgcra; + uint pcmc_pgcrb; + uint pcmc_pscr; + char res2[4]; + uint pcmc_pipr; + char res3[4]; + uint pcmc_per; + char res4[4]; +} pcmconf8xx_t; + +/* Memory controller registers. +*/ +typedef struct mem_ctlr { + uint memc_br0; + uint memc_or0; + uint memc_br1; + uint memc_or1; + uint memc_br2; + uint memc_or2; + uint memc_br3; + uint memc_or3; + uint memc_br4; + uint memc_or4; + uint memc_br5; + uint memc_or5; + uint memc_br6; + uint memc_or6; + uint memc_br7; + uint memc_or7; + char res1[0x24]; + uint memc_mar; + uint memc_mcr; + char res2[4]; + uint memc_mamr; + uint memc_mbmr; + ushort memc_mstat; + ushort memc_mptpr; + uint memc_mdr; + char res3[0x80]; +} memctl8xx_t; + +/*----------------------------------------------------------------------- + * BR - Memory Controler: Base Register 16-9 + */ +#define BR_BA_MSK 0xffff8000 /* Base Address Mask */ +#define BR_AT_MSK 0x00007000 /* Address Type Mask */ +#define BR_PS_MSK 0x00000c00 /* Port Size Mask */ +#define BR_PS_32 0x00000000 /* 32 bit port size */ +#define BR_PS_16 0x00000800 /* 16 bit port size */ +#define BR_PS_8 0x00000400 /* 8 bit port size */ +#define BR_PARE 0x00000200 /* Parity Enable */ +#define BR_WP 0x00000100 /* Write Protect */ +#define BR_MS_MSK 0x000000c0 /* Machine Select Mask */ +#define BR_MS_GPCM 0x00000000 /* G.P.C.M. Machine Select */ +#define BR_MS_UPMA 0x00000080 /* U.P.M.A Machine Select */ +#define BR_MS_UPMB 0x000000c0 /* U.P.M.B Machine Select */ +#define BR_V 0x00000001 /* Bank Valid */ + +/*----------------------------------------------------------------------- + * OR - Memory Controler: Option Register 16-11 + */ +#define OR_AM_MSK 0xffff8000 /* Address Mask Mask */ +#define OR_ATM_MSK 0x00007000 /* Address Type Mask Mask */ +#define OR_CSNT_SAM 0x00000800 /* Chip Select Negation Time/ Start */ + /* Address Multiplex */ +#define OR_ACS_MSK 0x00000600 /* Address to Chip Select Setup mask */ +#define OR_ACS_DIV1 0x00000000 /* CS is output at the same time */ +#define OR_ACS_DIV4 0x00000400 /* CS is output 1/4 a clock later */ +#define OR_ACS_DIV2 0x00000600 /* CS is output 1/2 a clock later */ +#define OR_G5LA 0x00000400 /* Output #GPL5 on #GPL_A5 */ +#define OR_G5LS 0x00000200 /* Drive #GPL high on falling edge of...*/ +#define OR_BI 0x00000100 /* Burst inhibit */ +#define OR_SCY_MSK 0x000000f0 /* Cycle Lenght in Clocks */ +#define OR_SCY_0_CLK 0x00000000 /* 0 clock cycles wait states */ +#define OR_SCY_1_CLK 0x00000010 /* 1 clock cycles wait states */ +#define OR_SCY_2_CLK 0x00000020 /* 2 clock cycles wait states */ +#define OR_SCY_3_CLK 0x00000030 /* 3 clock cycles wait states */ +#define OR_SCY_4_CLK 0x00000040 /* 4 clock cycles wait states */ +#define OR_SCY_5_CLK 0x00000050 /* 5 clock cycles wait states */ +#define OR_SCY_6_CLK 0x00000060 /* 6 clock cycles wait states */ +#define OR_SCY_7_CLK 0x00000070 /* 7 clock cycles wait states */ +#define OR_SCY_8_CLK 0x00000080 /* 8 clock cycles wait states */ +#define OR_SCY_9_CLK 0x00000090 /* 9 clock cycles wait states */ +#define OR_SCY_10_CLK 0x000000a0 /* 10 clock cycles wait states */ +#define OR_SCY_11_CLK 0x000000b0 /* 11 clock cycles wait states */ +#define OR_SCY_12_CLK 0x000000c0 /* 12 clock cycles wait states */ +#define OR_SCY_13_CLK 0x000000d0 /* 13 clock cycles wait states */ +#define OR_SCY_14_CLK 0x000000e0 /* 14 clock cycles wait states */ +#define OR_SCY_15_CLK 0x000000f0 /* 15 clock cycles wait states */ +#define OR_SETA 0x00000008 /* External Transfer Acknowledge */ +#define OR_TRLX 0x00000004 /* Timing Relaxed */ +#define OR_EHTR 0x00000002 /* Extended Hold Time on Read */ + +/* System Integration Timers. +*/ +typedef struct sys_int_timers { + ushort sit_tbscr; + char res0[0x02]; + uint sit_tbreff0; + uint sit_tbreff1; + char res1[0x14]; + ushort sit_rtcsc; + char res2[0x02]; + uint sit_rtc; + uint sit_rtsec; + uint sit_rtcal; + char res3[0x10]; + ushort sit_piscr; + char res4[2]; + uint sit_pitc; + uint sit_pitr; + char res5[0x34]; +} sit8xx_t; + +#define TBSCR_TBIRQ_MASK ((ushort)0xff00) +#define TBSCR_REFA ((ushort)0x0080) +#define TBSCR_REFB ((ushort)0x0040) +#define TBSCR_REFAE ((ushort)0x0008) +#define TBSCR_REFBE ((ushort)0x0004) +#define TBSCR_TBF ((ushort)0x0002) +#define TBSCR_TBE ((ushort)0x0001) + +#define RTCSC_RTCIRQ_MASK ((ushort)0xff00) +#define RTCSC_SEC ((ushort)0x0080) +#define RTCSC_ALR ((ushort)0x0040) +#define RTCSC_38K ((ushort)0x0010) +#define RTCSC_SIE ((ushort)0x0008) +#define RTCSC_ALE ((ushort)0x0004) +#define RTCSC_RTF ((ushort)0x0002) +#define RTCSC_RTE ((ushort)0x0001) + +#define PISCR_PIRQ_MASK ((ushort)0xff00) +#define PISCR_PS ((ushort)0x0080) +#define PISCR_PIE ((ushort)0x0004) +#define PISCR_PTF ((ushort)0x0002) +#define PISCR_PTE ((ushort)0x0001) + +/* Clocks and Reset. +*/ +typedef struct clk_and_reset { + uint car_sccr; + uint car_plprcr; + uint car_rsr; + char res[0x74]; /* Reserved area */ +} car8xx_t; + +/* System Integration Timers keys. +*/ +typedef struct sitk { + uint sitk_tbscrk; + uint sitk_tbreff0k; + uint sitk_tbreff1k; + uint sitk_tbk; + char res1[0x10]; + uint sitk_rtcsck; + uint sitk_rtck; + uint sitk_rtseck; + uint sitk_rtcalk; + char res2[0x10]; + uint sitk_piscrk; + uint sitk_pitck; + char res3[0x38]; +} sitk8xx_t; + +/* Clocks and reset keys. +*/ +typedef struct cark { + uint cark_sccrk; + uint cark_plprcrk; + uint cark_rsrk; + char res[0x474]; +} cark8xx_t; + +/* The key to unlock registers maintained by keep-alive power. +*/ +#define KAPWR_KEY ((unsigned int)0x55ccaa33) + +/* Video interface. MPC823 Only. +*/ +typedef struct vid823 { + ushort vid_vccr; + ushort res1; + u_char vid_vsr; + u_char res2; + u_char vid_vcmr; + u_char res3; + uint vid_vbcb; + uint res4; + uint vid_vfcr0; + uint vid_vfaa0; + uint vid_vfba0; + uint vid_vfcr1; + uint vid_vfaa1; + uint vid_vfba1; + u_char res5[0x18]; +} vid823_t; + +/* LCD interface. 823 Only. +*/ +typedef struct lcd { + uint lcd_lccr; + uint lcd_lchcr; + uint lcd_lcvcr; + char res1[4]; + uint lcd_lcfaa; + uint lcd_lcfba; + char lcd_lcsr; + char res2[0x7]; +} lcd823_t; + +/* I2C +*/ +typedef struct i2c { + u_char i2c_i2mod; + char res1[3]; + u_char i2c_i2add; + char res2[3]; + u_char i2c_i2brg; + char res3[3]; + u_char i2c_i2com; + char res4[3]; + u_char i2c_i2cer; + char res5[3]; + u_char i2c_i2cmr; + char res6[0x8b]; +} i2c8xx_t; + +/* DMA control/status registers. +*/ +typedef struct sdma_csr { + char res1[4]; + uint sdma_sdar; + u_char sdma_sdsr; + char res3[3]; + u_char sdma_sdmr; + char res4[3]; + u_char sdma_idsr1; + char res5[3]; + u_char sdma_idmr1; + char res6[3]; + u_char sdma_idsr2; + char res7[3]; + u_char sdma_idmr2; + char res8[0x13]; +} sdma8xx_t; + +/* Communication Processor Module Interrupt Controller. +*/ +typedef struct cpm_ic { + ushort cpic_civr; + char res[0xe]; + uint cpic_cicr; + uint cpic_cipr; + uint cpic_cimr; + uint cpic_cisr; +} cpic8xx_t; + +/* Input/Output Port control/status registers. +*/ +typedef struct io_port { + ushort iop_padir; + ushort iop_papar; + ushort iop_paodr; + ushort iop_padat; + char res1[8]; + ushort iop_pcdir; + ushort iop_pcpar; + ushort iop_pcso; + ushort iop_pcdat; + ushort iop_pcint; + char res2[6]; + ushort iop_pddir; + ushort iop_pdpar; + char res3[2]; + ushort iop_pddat; + uint utmode; + char res4[4]; +} iop8xx_t; + +/* Communication Processor Module Timers +*/ +typedef struct cpm_timers { + ushort cpmt_tgcr; + char res1[0xe]; + ushort cpmt_tmr1; + ushort cpmt_tmr2; + ushort cpmt_trr1; + ushort cpmt_trr2; + ushort cpmt_tcr1; + ushort cpmt_tcr2; + ushort cpmt_tcn1; + ushort cpmt_tcn2; + ushort cpmt_tmr3; + ushort cpmt_tmr4; + ushort cpmt_trr3; + ushort cpmt_trr4; + ushort cpmt_tcr3; + ushort cpmt_tcr4; + ushort cpmt_tcn3; + ushort cpmt_tcn4; + ushort cpmt_ter1; + ushort cpmt_ter2; + ushort cpmt_ter3; + ushort cpmt_ter4; + char res2[8]; +} cpmtimer8xx_t; + +/* Finally, the Communication Processor stuff..... +*/ +typedef struct scc { /* Serial communication channels */ + uint scc_gsmrl; + uint scc_gsmrh; + ushort scc_psmr; + char res1[2]; + ushort scc_todr; + ushort scc_dsr; + ushort scc_scce; + char res2[2]; + ushort scc_sccm; + char res3; + u_char scc_sccs; + char res4[8]; +} scc_t; + +typedef struct smc { /* Serial management channels */ + char res1[2]; + ushort smc_smcmr; + char res2[2]; + u_char smc_smce; + char res3[3]; + u_char smc_smcm; + char res4[5]; +} smc_t; + +/* MPC860T Fast Ethernet Controller. It isn't part of the CPM, but + * it fits within the address space. + */ + +typedef struct fec { + uint fec_addr_low; /* lower 32 bits of station address */ + ushort fec_addr_high; /* upper 16 bits of station address */ + ushort res1; /* reserved */ + uint fec_hash_table_high; /* upper 32-bits of hash table */ + uint fec_hash_table_low; /* lower 32-bits of hash table */ + uint fec_r_des_start; /* beginning of Rx descriptor ring */ + uint fec_x_des_start; /* beginning of Tx descriptor ring */ + uint fec_r_buff_size; /* Rx buffer size */ + uint res2[9]; /* reserved */ + uint fec_ecntrl; /* ethernet control register */ + uint fec_ievent; /* interrupt event register */ + uint fec_imask; /* interrupt mask register */ + uint fec_ivec; /* interrupt level and vector status */ + uint fec_r_des_active; /* Rx ring updated flag */ + uint fec_x_des_active; /* Tx ring updated flag */ + uint res3[10]; /* reserved */ + uint fec_mii_data; /* MII data register */ + uint fec_mii_speed; /* MII speed control register */ + uint res4[17]; /* reserved */ + uint fec_r_bound; /* end of RAM (read-only) */ + uint fec_r_fstart; /* Rx FIFO start address */ + uint res5[6]; /* reserved */ + uint fec_x_fstart; /* Tx FIFO start address */ + uint res6[17]; /* reserved */ + uint fec_fun_code; /* fec SDMA function code */ + uint res7[3]; /* reserved */ + uint fec_r_cntrl; /* Rx control register */ + uint fec_r_hash; /* Rx hash register */ + uint res8[14]; /* reserved */ + uint fec_x_cntrl; /* Tx control register */ + uint res9[0x1e]; /* reserved */ +} fec_t; + +/* The FEC and LCD color map share the same address space.... + * I guess we will never see an 823T :-). + */ +union fec_lcd { + fec_t fl_un_fec; + u_char fl_un_cmap[0x200]; +}; + +typedef struct comm_proc { + /* General control and status registers. + */ + ushort cp_cpcr; + u_char res1[2]; + ushort cp_rccr; + u_char res2; + u_char cp_rmds; + u_char res3[4]; + ushort cp_cpmcr1; + ushort cp_cpmcr2; + ushort cp_cpmcr3; + ushort cp_cpmcr4; + u_char res4[2]; + ushort cp_rter; + u_char res5[2]; + ushort cp_rtmr; + u_char res6[0x14]; + + /* Baud rate generators. + */ + uint cp_brgc1; + uint cp_brgc2; + uint cp_brgc3; + uint cp_brgc4; + + /* Serial Communication Channels. + */ + scc_t cp_scc[4]; + + /* Serial Management Channels. + */ + smc_t cp_smc[2]; + + /* Serial Peripheral Interface. + */ + ushort cp_spmode; + u_char res7[4]; + u_char cp_spie; + u_char res8[3]; + u_char cp_spim; + u_char res9[2]; + u_char cp_spcom; + u_char res10[2]; + + /* Parallel Interface Port. + */ + u_char res11[2]; + ushort cp_pipc; + u_char res12[2]; + ushort cp_ptpr; + uint cp_pbdir; + uint cp_pbpar; + u_char res13[2]; + ushort cp_pbodr; + uint cp_pbdat; + + /* Port E - MPC87x/88x only. + */ + uint cp_pedir; + uint cp_pepar; + uint cp_peso; + uint cp_peodr; + uint cp_pedat; + + /* Communications Processor Timing Register - + Contains RMII Timing for the FECs on MPC87x/88x only. + */ + uint cp_cptr; + + /* Serial Interface and Time Slot Assignment. + */ + uint cp_simode; + u_char cp_sigmr; + u_char res15; + u_char cp_sistr; + u_char cp_sicmr; + u_char res16[4]; + uint cp_sicr; + uint cp_sirp; + u_char res17[0xc]; + + /* 256 bytes of MPC823 video controller RAM array. + */ + u_char cp_vcram[0x100]; + u_char cp_siram[0x200]; + + /* The fast ethernet controller is not really part of the CPM, + * but it resides in the address space. + * The LCD color map is also here. + */ + union fec_lcd fl_un; +#define cp_fec fl_un.fl_un_fec +#define lcd_cmap fl_un.fl_un_cmap + char res18[0xE00]; + + /* The DUET family has a second FEC here */ + fec_t cp_fec2; +#define cp_fec1 cp_fec /* consistency macro */ + + /* Dual Ported RAM follows. + * There are many different formats for this memory area + * depending upon the devices used and options chosen. + * Some processors don't have all of it populated. + */ + u_char cp_dpmem[0x1C00]; /* BD / Data / ucode */ + u_char cp_dparam[0x400]; /* Parameter RAM */ +} cpm8xx_t; + +/* Internal memory map. +*/ +typedef struct immap { + sysconf8xx_t im_siu_conf; /* SIU Configuration */ + pcmconf8xx_t im_pcmcia; /* PCMCIA Configuration */ + memctl8xx_t im_memctl; /* Memory Controller */ + sit8xx_t im_sit; /* System integration timers */ + car8xx_t im_clkrst; /* Clocks and reset */ + sitk8xx_t im_sitk; /* Sys int timer keys */ + cark8xx_t im_clkrstk; /* Clocks and reset keys */ + vid823_t im_vid; /* Video (823 only) */ + lcd823_t im_lcd; /* LCD (823 only) */ + i2c8xx_t im_i2c; /* I2C control/status */ + sdma8xx_t im_sdma; /* SDMA control/status */ + cpic8xx_t im_cpic; /* CPM Interrupt Controller */ + iop8xx_t im_ioport; /* IO Port control/status */ + cpmtimer8xx_t im_cpmtimer; /* CPM timers */ + cpm8xx_t im_cpm; /* Communication processor */ +} immap_t; + +#endif /* __IMMAP_8XX__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/commproc.h b/include/asm-powerpc/commproc.h new file mode 100644 index 000000000000..397248705e0e --- /dev/null +++ b/include/asm-powerpc/commproc.h @@ -0,0 +1,692 @@ +/* + * MPC8xx Communication Processor Module. + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * This file contains structures and information for the communication + * processor channels. Some CPM control and status is available + * throught the MPC8xx internal memory map. See immap.h for details. + * This file only contains what I need for the moment, not the total + * CPM capabilities. I (or someone else) will add definitions as they + * are needed. -- Dan + * + * On the MBX board, EPPC-Bug loads CPM microcode into the first 512 + * bytes of the DP RAM and relocates the I2C parameter area to the + * IDMA1 space. The remaining DP RAM is available for buffer descriptors + * or other use. + */ +#ifndef __CPM_8XX__ +#define __CPM_8XX__ + +#include +#include + +/* CPM Command register. +*/ +#define CPM_CR_RST ((ushort)0x8000) +#define CPM_CR_OPCODE ((ushort)0x0f00) +#define CPM_CR_CHAN ((ushort)0x00f0) +#define CPM_CR_FLG ((ushort)0x0001) + +/* Some commands (there are more...later) +*/ +#define CPM_CR_INIT_TRX ((ushort)0x0000) +#define CPM_CR_INIT_RX ((ushort)0x0001) +#define CPM_CR_INIT_TX ((ushort)0x0002) +#define CPM_CR_HUNT_MODE ((ushort)0x0003) +#define CPM_CR_STOP_TX ((ushort)0x0004) +#define CPM_CR_GRA_STOP_TX ((ushort)0x0005) +#define CPM_CR_RESTART_TX ((ushort)0x0006) +#define CPM_CR_CLOSE_RX_BD ((ushort)0x0007) +#define CPM_CR_SET_GADDR ((ushort)0x0008) +#define CPM_CR_SET_TIMER CPM_CR_SET_GADDR + +/* Channel numbers. +*/ +#define CPM_CR_CH_SCC1 ((ushort)0x0000) +#define CPM_CR_CH_I2C ((ushort)0x0001) /* I2C and IDMA1 */ +#define CPM_CR_CH_SCC2 ((ushort)0x0004) +#define CPM_CR_CH_SPI ((ushort)0x0005) /* SPI / IDMA2 / Timers */ +#define CPM_CR_CH_TIMER CPM_CR_CH_SPI +#define CPM_CR_CH_SCC3 ((ushort)0x0008) +#define CPM_CR_CH_SMC1 ((ushort)0x0009) /* SMC1 / DSP1 */ +#define CPM_CR_CH_SCC4 ((ushort)0x000c) +#define CPM_CR_CH_SMC2 ((ushort)0x000d) /* SMC2 / DSP2 */ + +#define mk_cr_cmd(CH, CMD) ((CMD << 8) | (CH << 4)) + +/* The dual ported RAM is multi-functional. Some areas can be (and are + * being) used for microcode. There is an area that can only be used + * as data ram for buffer descriptors, which is all we use right now. + * Currently the first 512 and last 256 bytes are used for microcode. + */ +#define CPM_DATAONLY_BASE ((uint)0x0800) +#define CPM_DATAONLY_SIZE ((uint)0x0700) +#define CPM_DP_NOSPACE ((uint)0x7fffffff) + +/* Export the base address of the communication processor registers + * and dual port ram. + */ +extern cpm8xx_t *cpmp; /* Pointer to comm processor */ +extern unsigned long cpm_dpalloc(uint size, uint align); +extern int cpm_dpfree(unsigned long offset); +extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); +extern void cpm_dpdump(void); +extern void *cpm_dpram_addr(unsigned long offset); +extern uint cpm_dpram_phys(u8* addr); +extern void cpm_setbrg(uint brg, uint rate); + +extern uint m8xx_cpm_hostalloc(uint size); +extern int m8xx_cpm_hostfree(uint start); +extern void m8xx_cpm_hostdump(void); + +extern void cpm_load_patch(volatile immap_t *immr); + +/* Buffer descriptors used by many of the CPM protocols. +*/ +typedef struct cpm_buf_desc { + ushort cbd_sc; /* Status and Control */ + ushort cbd_datlen; /* Data length in buffer */ + uint cbd_bufaddr; /* Buffer address in host memory */ +} cbd_t; + +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ +#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ +#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ +#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame */ +#define BD_SC_TC ((ushort)0x0400) /* Transmit CRC */ +#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ +#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ +#define BD_SC_BR ((ushort)0x0020) /* Break received */ +#define BD_SC_FR ((ushort)0x0010) /* Framing error */ +#define BD_SC_PR ((ushort)0x0008) /* Parity error */ +#define BD_SC_NAK ((ushort)0x0004) /* NAK - did not respond */ +#define BD_SC_OV ((ushort)0x0002) /* Overrun */ +#define BD_SC_UN ((ushort)0x0002) /* Underrun */ +#define BD_SC_CD ((ushort)0x0001) /* ?? */ +#define BD_SC_CL ((ushort)0x0001) /* Collision */ + +/* Parameter RAM offsets. +*/ +#define PROFF_SCC1 ((uint)0x0000) +#define PROFF_IIC ((uint)0x0080) +#define PROFF_SCC2 ((uint)0x0100) +#define PROFF_SPI ((uint)0x0180) +#define PROFF_SCC3 ((uint)0x0200) +#define PROFF_SMC1 ((uint)0x0280) +#define PROFF_SCC4 ((uint)0x0300) +#define PROFF_SMC2 ((uint)0x0380) + +/* Define enough so I can at least use the serial port as a UART. + * The MBX uses SMC1 as the host serial port. + */ +typedef struct smc_uart { + ushort smc_rbase; /* Rx Buffer descriptor base address */ + ushort smc_tbase; /* Tx Buffer descriptor base address */ + u_char smc_rfcr; /* Rx function code */ + u_char smc_tfcr; /* Tx function code */ + ushort smc_mrblr; /* Max receive buffer length */ + uint smc_rstate; /* Internal */ + uint smc_idp; /* Internal */ + ushort smc_rbptr; /* Internal */ + ushort smc_ibc; /* Internal */ + uint smc_rxtmp; /* Internal */ + uint smc_tstate; /* Internal */ + uint smc_tdp; /* Internal */ + ushort smc_tbptr; /* Internal */ + ushort smc_tbc; /* Internal */ + uint smc_txtmp; /* Internal */ + ushort smc_maxidl; /* Maximum idle characters */ + ushort smc_tmpidl; /* Temporary idle counter */ + ushort smc_brklen; /* Last received break length */ + ushort smc_brkec; /* rcv'd break condition counter */ + ushort smc_brkcr; /* xmt break count register */ + ushort smc_rmask; /* Temporary bit mask */ + char res1[8]; /* Reserved */ + ushort smc_rpbase; /* Relocation pointer */ +} smc_uart_t; + +/* Function code bits. +*/ +#define SMC_EB ((u_char)0x10) /* Set big endian byte order */ + +/* SMC uart mode register. +*/ +#define SMCMR_REN ((ushort)0x0001) +#define SMCMR_TEN ((ushort)0x0002) +#define SMCMR_DM ((ushort)0x000c) +#define SMCMR_SM_GCI ((ushort)0x0000) +#define SMCMR_SM_UART ((ushort)0x0020) +#define SMCMR_SM_TRANS ((ushort)0x0030) +#define SMCMR_SM_MASK ((ushort)0x0030) +#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ +#define SMCMR_REVD SMCMR_PM_EVEN +#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ +#define SMCMR_BS SMCMR_PEN +#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ +#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ +#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) + +/* SMC2 as Centronics parallel printer. It is half duplex, in that + * it can only receive or transmit. The parameter ram values for + * each direction are either unique or properly overlap, so we can + * include them in one structure. + */ +typedef struct smc_centronics { + ushort scent_rbase; + ushort scent_tbase; + u_char scent_cfcr; + u_char scent_smask; + ushort scent_mrblr; + uint scent_rstate; + uint scent_r_ptr; + ushort scent_rbptr; + ushort scent_r_cnt; + uint scent_rtemp; + uint scent_tstate; + uint scent_t_ptr; + ushort scent_tbptr; + ushort scent_t_cnt; + uint scent_ttemp; + ushort scent_max_sl; + ushort scent_sl_cnt; + ushort scent_character1; + ushort scent_character2; + ushort scent_character3; + ushort scent_character4; + ushort scent_character5; + ushort scent_character6; + ushort scent_character7; + ushort scent_character8; + ushort scent_rccm; + ushort scent_rccr; +} smc_cent_t; + +/* Centronics Status Mask Register. +*/ +#define SMC_CENT_F ((u_char)0x08) +#define SMC_CENT_PE ((u_char)0x04) +#define SMC_CENT_S ((u_char)0x02) + +/* SMC Event and Mask register. +*/ +#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */ +#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */ +#define SMCM_TXE ((unsigned char)0x10) /* When in Transparent Mode */ +#define SMCM_BSY ((unsigned char)0x04) +#define SMCM_TX ((unsigned char)0x02) +#define SMCM_RX ((unsigned char)0x01) + +/* Baud rate generators. +*/ +#define CPM_BRG_RST ((uint)0x00020000) +#define CPM_BRG_EN ((uint)0x00010000) +#define CPM_BRG_EXTC_INT ((uint)0x00000000) +#define CPM_BRG_EXTC_CLK2 ((uint)0x00004000) +#define CPM_BRG_EXTC_CLK6 ((uint)0x00008000) +#define CPM_BRG_ATB ((uint)0x00002000) +#define CPM_BRG_CD_MASK ((uint)0x00001ffe) +#define CPM_BRG_DIV16 ((uint)0x00000001) + +/* SI Clock Route Register +*/ +#define SICR_RCLK_SCC1_BRG1 ((uint)0x00000000) +#define SICR_TCLK_SCC1_BRG1 ((uint)0x00000000) +#define SICR_RCLK_SCC2_BRG2 ((uint)0x00000800) +#define SICR_TCLK_SCC2_BRG2 ((uint)0x00000100) +#define SICR_RCLK_SCC3_BRG3 ((uint)0x00100000) +#define SICR_TCLK_SCC3_BRG3 ((uint)0x00020000) +#define SICR_RCLK_SCC4_BRG4 ((uint)0x18000000) +#define SICR_TCLK_SCC4_BRG4 ((uint)0x03000000) + +/* SCCs. +*/ +#define SCC_GSMRH_IRP ((uint)0x00040000) +#define SCC_GSMRH_GDE ((uint)0x00010000) +#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000) +#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000) +#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000) +#define SCC_GSMRH_REVD ((uint)0x00002000) +#define SCC_GSMRH_TRX ((uint)0x00001000) +#define SCC_GSMRH_TTX ((uint)0x00000800) +#define SCC_GSMRH_CDP ((uint)0x00000400) +#define SCC_GSMRH_CTSP ((uint)0x00000200) +#define SCC_GSMRH_CDS ((uint)0x00000100) +#define SCC_GSMRH_CTSS ((uint)0x00000080) +#define SCC_GSMRH_TFL ((uint)0x00000040) +#define SCC_GSMRH_RFW ((uint)0x00000020) +#define SCC_GSMRH_TXSY ((uint)0x00000010) +#define SCC_GSMRH_SYNL16 ((uint)0x0000000c) +#define SCC_GSMRH_SYNL8 ((uint)0x00000008) +#define SCC_GSMRH_SYNL4 ((uint)0x00000004) +#define SCC_GSMRH_RTSM ((uint)0x00000002) +#define SCC_GSMRH_RSYN ((uint)0x00000001) + +#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */ +#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000) +#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000) +#define SCC_GSMRL_EDGE_POS ((uint)0x20000000) +#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000) +#define SCC_GSMRL_TCI ((uint)0x10000000) +#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000) +#define SCC_GSMRL_TSNC_4 ((uint)0x08000000) +#define SCC_GSMRL_TSNC_14 ((uint)0x04000000) +#define SCC_GSMRL_TSNC_INF ((uint)0x00000000) +#define SCC_GSMRL_RINV ((uint)0x02000000) +#define SCC_GSMRL_TINV ((uint)0x01000000) +#define SCC_GSMRL_TPL_128 ((uint)0x00c00000) +#define SCC_GSMRL_TPL_64 ((uint)0x00a00000) +#define SCC_GSMRL_TPL_48 ((uint)0x00800000) +#define SCC_GSMRL_TPL_32 ((uint)0x00600000) +#define SCC_GSMRL_TPL_16 ((uint)0x00400000) +#define SCC_GSMRL_TPL_8 ((uint)0x00200000) +#define SCC_GSMRL_TPL_NONE ((uint)0x00000000) +#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000) +#define SCC_GSMRL_TPP_01 ((uint)0x00100000) +#define SCC_GSMRL_TPP_10 ((uint)0x00080000) +#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000) +#define SCC_GSMRL_TEND ((uint)0x00040000) +#define SCC_GSMRL_TDCR_32 ((uint)0x00030000) +#define SCC_GSMRL_TDCR_16 ((uint)0x00020000) +#define SCC_GSMRL_TDCR_8 ((uint)0x00010000) +#define SCC_GSMRL_TDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000) +#define SCC_GSMRL_RDCR_16 ((uint)0x00008000) +#define SCC_GSMRL_RDCR_8 ((uint)0x00004000) +#define SCC_GSMRL_RDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000) +#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000) +#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000) +#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800) +#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600) +#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400) +#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200) +#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100) +#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */ +#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080) +#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040) +#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000) +#define SCC_GSMRL_ENR ((uint)0x00000020) +#define SCC_GSMRL_ENT ((uint)0x00000010) +#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c) +#define SCC_GSMRL_MODE_QMC ((uint)0x0000000a) +#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009) +#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008) +#define SCC_GSMRL_MODE_V14 ((uint)0x00000007) +#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006) +#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005) +#define SCC_GSMRL_MODE_UART ((uint)0x00000004) +#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003) +#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002) +#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000) + +#define SCC_TODR_TOD ((ushort)0x8000) + +/* SCC Event and Mask register. +*/ +#define SCCM_TXE ((unsigned char)0x10) +#define SCCM_BSY ((unsigned char)0x04) +#define SCCM_TX ((unsigned char)0x02) +#define SCCM_RX ((unsigned char)0x01) + +typedef struct scc_param { + ushort scc_rbase; /* Rx Buffer descriptor base address */ + ushort scc_tbase; /* Tx Buffer descriptor base address */ + u_char scc_rfcr; /* Rx function code */ + u_char scc_tfcr; /* Tx function code */ + ushort scc_mrblr; /* Max receive buffer length */ + uint scc_rstate; /* Internal */ + uint scc_idp; /* Internal */ + ushort scc_rbptr; /* Internal */ + ushort scc_ibc; /* Internal */ + uint scc_rxtmp; /* Internal */ + uint scc_tstate; /* Internal */ + uint scc_tdp; /* Internal */ + ushort scc_tbptr; /* Internal */ + ushort scc_tbc; /* Internal */ + uint scc_txtmp; /* Internal */ + uint scc_rcrc; /* Internal */ + uint scc_tcrc; /* Internal */ +} sccp_t; + +/* Function code bits. +*/ +#define SCC_EB ((u_char)0x10) /* Set big endian byte order */ + +/* CPM Ethernet through SCCx. + */ +typedef struct scc_enet { + sccp_t sen_genscc; + uint sen_cpres; /* Preset CRC */ + uint sen_cmask; /* Constant mask for CRC */ + uint sen_crcec; /* CRC Error counter */ + uint sen_alec; /* alignment error counter */ + uint sen_disfc; /* discard frame counter */ + ushort sen_pads; /* Tx short frame pad character */ + ushort sen_retlim; /* Retry limit threshold */ + ushort sen_retcnt; /* Retry limit counter */ + ushort sen_maxflr; /* maximum frame length register */ + ushort sen_minflr; /* minimum frame length register */ + ushort sen_maxd1; /* maximum DMA1 length */ + ushort sen_maxd2; /* maximum DMA2 length */ + ushort sen_maxd; /* Rx max DMA */ + ushort sen_dmacnt; /* Rx DMA counter */ + ushort sen_maxb; /* Max BD byte count */ + ushort sen_gaddr1; /* Group address filter */ + ushort sen_gaddr2; + ushort sen_gaddr3; + ushort sen_gaddr4; + uint sen_tbuf0data0; /* Save area 0 - current frame */ + uint sen_tbuf0data1; /* Save area 1 - current frame */ + uint sen_tbuf0rba; /* Internal */ + uint sen_tbuf0crc; /* Internal */ + ushort sen_tbuf0bcnt; /* Internal */ + ushort sen_paddrh; /* physical address (MSB) */ + ushort sen_paddrm; + ushort sen_paddrl; /* physical address (LSB) */ + ushort sen_pper; /* persistence */ + ushort sen_rfbdptr; /* Rx first BD pointer */ + ushort sen_tfbdptr; /* Tx first BD pointer */ + ushort sen_tlbdptr; /* Tx last BD pointer */ + uint sen_tbuf1data0; /* Save area 0 - current frame */ + uint sen_tbuf1data1; /* Save area 1 - current frame */ + uint sen_tbuf1rba; /* Internal */ + uint sen_tbuf1crc; /* Internal */ + ushort sen_tbuf1bcnt; /* Internal */ + ushort sen_txlen; /* Tx Frame length counter */ + ushort sen_iaddr1; /* Individual address filter */ + ushort sen_iaddr2; + ushort sen_iaddr3; + ushort sen_iaddr4; + ushort sen_boffcnt; /* Backoff counter */ + + /* NOTE: Some versions of the manual have the following items + * incorrectly documented. Below is the proper order. + */ + ushort sen_taddrh; /* temp address (MSB) */ + ushort sen_taddrm; + ushort sen_taddrl; /* temp address (LSB) */ +} scc_enet_t; + +/* SCC Event register as used by Ethernet. +*/ +#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ +#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* SCC Mode Register (PMSR) as used by Ethernet. +*/ +#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ + +/* Buffer descriptor control/status used by Ethernet receive. +*/ +#define BD_ENET_RX_EMPTY ((ushort)0x8000) +#define BD_ENET_RX_WRAP ((ushort)0x2000) +#define BD_ENET_RX_INTR ((ushort)0x1000) +#define BD_ENET_RX_LAST ((ushort)0x0800) +#define BD_ENET_RX_FIRST ((ushort)0x0400) +#define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_LG ((ushort)0x0020) +#define BD_ENET_RX_NO ((ushort)0x0010) +#define BD_ENET_RX_SH ((ushort)0x0008) +#define BD_ENET_RX_CR ((ushort)0x0004) +#define BD_ENET_RX_OV ((ushort)0x0002) +#define BD_ENET_RX_CL ((ushort)0x0001) +#define BD_ENET_RX_BC ((ushort)0x0080) /* DA is Broadcast */ +#define BD_ENET_RX_MC ((ushort)0x0040) /* DA is Multicast */ +#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ + +/* Buffer descriptor control/status used by Ethernet transmit. +*/ +#define BD_ENET_TX_READY ((ushort)0x8000) +#define BD_ENET_TX_PAD ((ushort)0x4000) +#define BD_ENET_TX_WRAP ((ushort)0x2000) +#define BD_ENET_TX_INTR ((ushort)0x1000) +#define BD_ENET_TX_LAST ((ushort)0x0800) +#define BD_ENET_TX_TC ((ushort)0x0400) +#define BD_ENET_TX_DEF ((ushort)0x0200) +#define BD_ENET_TX_HB ((ushort)0x0100) +#define BD_ENET_TX_LC ((ushort)0x0080) +#define BD_ENET_TX_RL ((ushort)0x0040) +#define BD_ENET_TX_RCMASK ((ushort)0x003c) +#define BD_ENET_TX_UN ((ushort)0x0002) +#define BD_ENET_TX_CSL ((ushort)0x0001) +#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ + +/* SCC as UART +*/ +typedef struct scc_uart { + sccp_t scc_genscc; + char res1[8]; /* Reserved */ + ushort scc_maxidl; /* Maximum idle chars */ + ushort scc_idlc; /* temp idle counter */ + ushort scc_brkcr; /* Break count register */ + ushort scc_parec; /* receive parity error counter */ + ushort scc_frmec; /* receive framing error counter */ + ushort scc_nosec; /* receive noise counter */ + ushort scc_brkec; /* receive break condition counter */ + ushort scc_brkln; /* last received break length */ + ushort scc_uaddr1; /* UART address character 1 */ + ushort scc_uaddr2; /* UART address character 2 */ + ushort scc_rtemp; /* Temp storage */ + ushort scc_toseq; /* Transmit out of sequence char */ + ushort scc_char1; /* control character 1 */ + ushort scc_char2; /* control character 2 */ + ushort scc_char3; /* control character 3 */ + ushort scc_char4; /* control character 4 */ + ushort scc_char5; /* control character 5 */ + ushort scc_char6; /* control character 6 */ + ushort scc_char7; /* control character 7 */ + ushort scc_char8; /* control character 8 */ + ushort scc_rccm; /* receive control character mask */ + ushort scc_rccr; /* receive control character register */ + ushort scc_rlbc; /* receive last break character */ +} scc_uart_t; + +/* SCC Event and Mask registers when it is used as a UART. +*/ +#define UART_SCCM_GLR ((ushort)0x1000) +#define UART_SCCM_GLT ((ushort)0x0800) +#define UART_SCCM_AB ((ushort)0x0200) +#define UART_SCCM_IDL ((ushort)0x0100) +#define UART_SCCM_GRA ((ushort)0x0080) +#define UART_SCCM_BRKE ((ushort)0x0040) +#define UART_SCCM_BRKS ((ushort)0x0020) +#define UART_SCCM_CCR ((ushort)0x0008) +#define UART_SCCM_BSY ((ushort)0x0004) +#define UART_SCCM_TX ((ushort)0x0002) +#define UART_SCCM_RX ((ushort)0x0001) + +/* The SCC PMSR when used as a UART. +*/ +#define SCU_PSMR_FLC ((ushort)0x8000) +#define SCU_PSMR_SL ((ushort)0x4000) +#define SCU_PSMR_CL ((ushort)0x3000) +#define SCU_PSMR_UM ((ushort)0x0c00) +#define SCU_PSMR_FRZ ((ushort)0x0200) +#define SCU_PSMR_RZS ((ushort)0x0100) +#define SCU_PSMR_SYN ((ushort)0x0080) +#define SCU_PSMR_DRT ((ushort)0x0040) +#define SCU_PSMR_PEN ((ushort)0x0010) +#define SCU_PSMR_RPM ((ushort)0x000c) +#define SCU_PSMR_REVP ((ushort)0x0008) +#define SCU_PSMR_TPM ((ushort)0x0003) +#define SCU_PSMR_TEVP ((ushort)0x0002) + +/* CPM Transparent mode SCC. + */ +typedef struct scc_trans { + sccp_t st_genscc; + uint st_cpres; /* Preset CRC */ + uint st_cmask; /* Constant mask for CRC */ +} scc_trans_t; + +#define BD_SCC_TX_LAST ((ushort)0x0800) + +/* IIC parameter RAM. +*/ +typedef struct iic { + ushort iic_rbase; /* Rx Buffer descriptor base address */ + ushort iic_tbase; /* Tx Buffer descriptor base address */ + u_char iic_rfcr; /* Rx function code */ + u_char iic_tfcr; /* Tx function code */ + ushort iic_mrblr; /* Max receive buffer length */ + uint iic_rstate; /* Internal */ + uint iic_rdp; /* Internal */ + ushort iic_rbptr; /* Internal */ + ushort iic_rbc; /* Internal */ + uint iic_rxtmp; /* Internal */ + uint iic_tstate; /* Internal */ + uint iic_tdp; /* Internal */ + ushort iic_tbptr; /* Internal */ + ushort iic_tbc; /* Internal */ + uint iic_txtmp; /* Internal */ + char res1[4]; /* Reserved */ + ushort iic_rpbase; /* Relocation pointer */ + char res2[2]; /* Reserved */ +} iic_t; + +#define BD_IIC_START ((ushort)0x0400) + +/* SPI parameter RAM. +*/ +typedef struct spi { + ushort spi_rbase; /* Rx Buffer descriptor base address */ + ushort spi_tbase; /* Tx Buffer descriptor base address */ + u_char spi_rfcr; /* Rx function code */ + u_char spi_tfcr; /* Tx function code */ + ushort spi_mrblr; /* Max receive buffer length */ + uint spi_rstate; /* Internal */ + uint spi_rdp; /* Internal */ + ushort spi_rbptr; /* Internal */ + ushort spi_rbc; /* Internal */ + uint spi_rxtmp; /* Internal */ + uint spi_tstate; /* Internal */ + uint spi_tdp; /* Internal */ + ushort spi_tbptr; /* Internal */ + ushort spi_tbc; /* Internal */ + uint spi_txtmp; /* Internal */ + uint spi_res; + ushort spi_rpbase; /* Relocation pointer */ + ushort spi_res2; +} spi_t; + +/* SPI Mode register. +*/ +#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */ +#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */ +#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */ +#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */ +#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */ +#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */ +#define SPMODE_EN ((ushort)0x0100) /* Enable */ +#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */ +#define SPMODE_LEN4 ((ushort)0x0030) /* 4 bits per char */ +#define SPMODE_LEN8 ((ushort)0x0070) /* 8 bits per char */ +#define SPMODE_LEN16 ((ushort)0x00f0) /* 16 bits per char */ +#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */ + +/* SPIE fields */ +#define SPIE_MME 0x20 +#define SPIE_TXE 0x10 +#define SPIE_BSY 0x04 +#define SPIE_TXB 0x02 +#define SPIE_RXB 0x01 + +/* + * RISC Controller Configuration Register definitons + */ +#define RCCR_TIME 0x8000 /* RISC Timer Enable */ +#define RCCR_TIMEP(t) (((t) & 0x3F)<<8) /* RISC Timer Period */ +#define RCCR_TIME_MASK 0x00FF /* not RISC Timer related bits */ + +/* RISC Timer Parameter RAM offset */ +#define PROFF_RTMR ((uint)0x01B0) + +typedef struct risc_timer_pram { + unsigned short tm_base; /* RISC Timer Table Base Address */ + unsigned short tm_ptr; /* RISC Timer Table Pointer (internal) */ + unsigned short r_tmr; /* RISC Timer Mode Register */ + unsigned short r_tmv; /* RISC Timer Valid Register */ + unsigned long tm_cmd; /* RISC Timer Command Register */ + unsigned long tm_cnt; /* RISC Timer Internal Count */ +} rt_pram_t; + +/* Bits in RISC Timer Command Register */ +#define TM_CMD_VALID 0x80000000 /* Valid - Enables the timer */ +#define TM_CMD_RESTART 0x40000000 /* Restart - for automatic restart */ +#define TM_CMD_PWM 0x20000000 /* Run in Pulse Width Modulation Mode */ +#define TM_CMD_NUM(n) (((n)&0xF)<<16) /* Timer Number */ +#define TM_CMD_PERIOD(p) ((p)&0xFFFF) /* Timer Period */ + +/* CPM interrupts. There are nearly 32 interrupts generated by CPM + * channels or devices. All of these are presented to the PPC core + * as a single interrupt. The CPM interrupt handler dispatches its + * own handlers, in a similar fashion to the PPC core handler. We + * use the table as defined in the manuals (i.e. no special high + * priority and SCC1 == SCCa, etc...). + */ +#define CPMVEC_NR 32 +#define CPMVEC_PIO_PC15 ((ushort)0x1f) +#define CPMVEC_SCC1 ((ushort)0x1e) +#define CPMVEC_SCC2 ((ushort)0x1d) +#define CPMVEC_SCC3 ((ushort)0x1c) +#define CPMVEC_SCC4 ((ushort)0x1b) +#define CPMVEC_PIO_PC14 ((ushort)0x1a) +#define CPMVEC_TIMER1 ((ushort)0x19) +#define CPMVEC_PIO_PC13 ((ushort)0x18) +#define CPMVEC_PIO_PC12 ((ushort)0x17) +#define CPMVEC_SDMA_CB_ERR ((ushort)0x16) +#define CPMVEC_IDMA1 ((ushort)0x15) +#define CPMVEC_IDMA2 ((ushort)0x14) +#define CPMVEC_TIMER2 ((ushort)0x12) +#define CPMVEC_RISCTIMER ((ushort)0x11) +#define CPMVEC_I2C ((ushort)0x10) +#define CPMVEC_PIO_PC11 ((ushort)0x0f) +#define CPMVEC_PIO_PC10 ((ushort)0x0e) +#define CPMVEC_TIMER3 ((ushort)0x0c) +#define CPMVEC_PIO_PC9 ((ushort)0x0b) +#define CPMVEC_PIO_PC8 ((ushort)0x0a) +#define CPMVEC_PIO_PC7 ((ushort)0x09) +#define CPMVEC_TIMER4 ((ushort)0x07) +#define CPMVEC_PIO_PC6 ((ushort)0x06) +#define CPMVEC_SPI ((ushort)0x05) +#define CPMVEC_SMC1 ((ushort)0x04) +#define CPMVEC_SMC2 ((ushort)0x03) +#define CPMVEC_PIO_PC5 ((ushort)0x02) +#define CPMVEC_PIO_PC4 ((ushort)0x01) +#define CPMVEC_ERROR ((ushort)0x00) + +/* CPM interrupt configuration vector. +*/ +#define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */ +#define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */ +#define CICR_SCB_SCC2 ((uint)0x00040000) /* SCC2 @ SCCb */ +#define CICR_SCA_SCC1 ((uint)0x00000000) /* SCC1 @ SCCa */ +#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrrupt */ +#define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */ +#define CICR_IEN ((uint)0x00000080) /* Int. enable */ +#define CICR_SPS ((uint)0x00000001) /* SCC Spread */ + +extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); +extern void cpm_free_handler(int vec); + +#endif /* __CPM_8XX__ */ diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h new file mode 100644 index 000000000000..12a2860f9a9c --- /dev/null +++ b/include/asm-powerpc/cpm2.h @@ -0,0 +1,1248 @@ +/* + * Communication Processor Module v2. + * + * This file contains structures and information for the communication + * processor channels found in the dual port RAM or parameter RAM. + * All CPM control and status is available through the CPM2 internal + * memory map. See immap_cpm2.h for details. + */ +#ifdef __KERNEL__ +#ifndef __CPM2__ +#define __CPM2__ + +#include + +/* CPM Command register. +*/ +#define CPM_CR_RST ((uint)0x80000000) +#define CPM_CR_PAGE ((uint)0x7c000000) +#define CPM_CR_SBLOCK ((uint)0x03e00000) +#define CPM_CR_FLG ((uint)0x00010000) +#define CPM_CR_MCN ((uint)0x00003fc0) +#define CPM_CR_OPCODE ((uint)0x0000000f) + +/* Device sub-block and page codes. +*/ +#define CPM_CR_SCC1_SBLOCK (0x04) +#define CPM_CR_SCC2_SBLOCK (0x05) +#define CPM_CR_SCC3_SBLOCK (0x06) +#define CPM_CR_SCC4_SBLOCK (0x07) +#define CPM_CR_SMC1_SBLOCK (0x08) +#define CPM_CR_SMC2_SBLOCK (0x09) +#define CPM_CR_SPI_SBLOCK (0x0a) +#define CPM_CR_I2C_SBLOCK (0x0b) +#define CPM_CR_TIMER_SBLOCK (0x0f) +#define CPM_CR_RAND_SBLOCK (0x0e) +#define CPM_CR_FCC1_SBLOCK (0x10) +#define CPM_CR_FCC2_SBLOCK (0x11) +#define CPM_CR_FCC3_SBLOCK (0x12) +#define CPM_CR_IDMA1_SBLOCK (0x14) +#define CPM_CR_IDMA2_SBLOCK (0x15) +#define CPM_CR_IDMA3_SBLOCK (0x16) +#define CPM_CR_IDMA4_SBLOCK (0x17) +#define CPM_CR_MCC1_SBLOCK (0x1c) + +#define CPM_CR_FCC_SBLOCK(x) (x + 0x10) + +#define CPM_CR_SCC1_PAGE (0x00) +#define CPM_CR_SCC2_PAGE (0x01) +#define CPM_CR_SCC3_PAGE (0x02) +#define CPM_CR_SCC4_PAGE (0x03) +#define CPM_CR_SMC1_PAGE (0x07) +#define CPM_CR_SMC2_PAGE (0x08) +#define CPM_CR_SPI_PAGE (0x09) +#define CPM_CR_I2C_PAGE (0x0a) +#define CPM_CR_TIMER_PAGE (0x0a) +#define CPM_CR_RAND_PAGE (0x0a) +#define CPM_CR_FCC1_PAGE (0x04) +#define CPM_CR_FCC2_PAGE (0x05) +#define CPM_CR_FCC3_PAGE (0x06) +#define CPM_CR_IDMA1_PAGE (0x07) +#define CPM_CR_IDMA2_PAGE (0x08) +#define CPM_CR_IDMA3_PAGE (0x09) +#define CPM_CR_IDMA4_PAGE (0x0a) +#define CPM_CR_MCC1_PAGE (0x07) +#define CPM_CR_MCC2_PAGE (0x08) + +#define CPM_CR_FCC_PAGE(x) (x + 0x04) + +/* Some opcodes (there are more...later) +*/ +#define CPM_CR_INIT_TRX ((ushort)0x0000) +#define CPM_CR_INIT_RX ((ushort)0x0001) +#define CPM_CR_INIT_TX ((ushort)0x0002) +#define CPM_CR_HUNT_MODE ((ushort)0x0003) +#define CPM_CR_STOP_TX ((ushort)0x0004) +#define CPM_CR_GRA_STOP_TX ((ushort)0x0005) +#define CPM_CR_RESTART_TX ((ushort)0x0006) +#define CPM_CR_SET_GADDR ((ushort)0x0008) +#define CPM_CR_START_IDMA ((ushort)0x0009) +#define CPM_CR_STOP_IDMA ((ushort)0x000b) + +#define mk_cr_cmd(PG, SBC, MCN, OP) \ + ((PG << 26) | (SBC << 21) | (MCN << 6) | OP) + +/* Dual Port RAM addresses. The first 16K is available for almost + * any CPM use, so we put the BDs there. The first 128 bytes are + * used for SMC1 and SMC2 parameter RAM, so we start allocating + * BDs above that. All of this must change when we start + * downloading RAM microcode. + */ +#define CPM_DATAONLY_BASE ((uint)128) +#define CPM_DP_NOSPACE ((uint)0x7fffffff) +#if defined(CONFIG_8272) || defined(CONFIG_MPC8555) +#define CPM_DATAONLY_SIZE ((uint)(8 * 1024) - CPM_DATAONLY_BASE) +#define CPM_FCC_SPECIAL_BASE ((uint)0x00009000) +#else +#define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE) +#define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000) +#endif + +/* The number of pages of host memory we allocate for CPM. This is + * done early in kernel initialization to get physically contiguous + * pages. + */ +#define NUM_CPM_HOST_PAGES 2 + +/* Export the base address of the communication processor registers + * and dual port ram. + */ +extern cpm_cpm2_t *cpmp; /* Pointer to comm processor */ + +extern unsigned long cpm_dpalloc(uint size, uint align); +extern int cpm_dpfree(unsigned long offset); +extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); +extern void cpm_dpdump(void); +extern void *cpm_dpram_addr(unsigned long offset); +extern void cpm_setbrg(uint brg, uint rate); +extern void cpm2_fastbrg(uint brg, uint rate, int div16); +extern void cpm2_reset(void); + + +/* Buffer descriptors used by many of the CPM protocols. +*/ +typedef struct cpm_buf_desc { + ushort cbd_sc; /* Status and Control */ + ushort cbd_datlen; /* Data length in buffer */ + uint cbd_bufaddr; /* Buffer address in host memory */ +} cbd_t; + +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ +#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ +#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ +#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame */ +#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ +#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ +#define BD_SC_BR ((ushort)0x0020) /* Break received */ +#define BD_SC_FR ((ushort)0x0010) /* Framing error */ +#define BD_SC_PR ((ushort)0x0008) /* Parity error */ +#define BD_SC_OV ((ushort)0x0002) /* Overrun */ +#define BD_SC_CD ((ushort)0x0001) /* ?? */ + +/* Function code bits, usually generic to devices. +*/ +#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ +#define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */ +#define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */ +#define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */ +#define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */ + +/* Parameter RAM offsets from the base. +*/ +#define PROFF_SCC1 ((uint)0x8000) +#define PROFF_SCC2 ((uint)0x8100) +#define PROFF_SCC3 ((uint)0x8200) +#define PROFF_SCC4 ((uint)0x8300) +#define PROFF_FCC1 ((uint)0x8400) +#define PROFF_FCC2 ((uint)0x8500) +#define PROFF_FCC3 ((uint)0x8600) +#define PROFF_MCC1 ((uint)0x8700) +#define PROFF_SMC1_BASE ((uint)0x87fc) +#define PROFF_IDMA1_BASE ((uint)0x87fe) +#define PROFF_MCC2 ((uint)0x8800) +#define PROFF_SMC2_BASE ((uint)0x88fc) +#define PROFF_IDMA2_BASE ((uint)0x88fe) +#define PROFF_SPI_BASE ((uint)0x89fc) +#define PROFF_IDMA3_BASE ((uint)0x89fe) +#define PROFF_TIMERS ((uint)0x8ae0) +#define PROFF_REVNUM ((uint)0x8af0) +#define PROFF_RAND ((uint)0x8af8) +#define PROFF_I2C_BASE ((uint)0x8afc) +#define PROFF_IDMA4_BASE ((uint)0x8afe) + +#define PROFF_SCC_SIZE ((uint)0x100) +#define PROFF_FCC_SIZE ((uint)0x100) +#define PROFF_SMC_SIZE ((uint)64) + +/* The SMCs are relocated to any of the first eight DPRAM pages. + * We will fix these at the first locations of DPRAM, until we + * get some microcode patches :-). + * The parameter ram space for the SMCs is fifty-some bytes, and + * they are required to start on a 64 byte boundary. + */ +#define PROFF_SMC1 (0) +#define PROFF_SMC2 (64) + + +/* Define enough so I can at least use the serial port as a UART. + */ +typedef struct smc_uart { + ushort smc_rbase; /* Rx Buffer descriptor base address */ + ushort smc_tbase; /* Tx Buffer descriptor base address */ + u_char smc_rfcr; /* Rx function code */ + u_char smc_tfcr; /* Tx function code */ + ushort smc_mrblr; /* Max receive buffer length */ + uint smc_rstate; /* Internal */ + uint smc_idp; /* Internal */ + ushort smc_rbptr; /* Internal */ + ushort smc_ibc; /* Internal */ + uint smc_rxtmp; /* Internal */ + uint smc_tstate; /* Internal */ + uint smc_tdp; /* Internal */ + ushort smc_tbptr; /* Internal */ + ushort smc_tbc; /* Internal */ + uint smc_txtmp; /* Internal */ + ushort smc_maxidl; /* Maximum idle characters */ + ushort smc_tmpidl; /* Temporary idle counter */ + ushort smc_brklen; /* Last received break length */ + ushort smc_brkec; /* rcv'd break condition counter */ + ushort smc_brkcr; /* xmt break count register */ + ushort smc_rmask; /* Temporary bit mask */ + uint smc_stmp; /* SDMA Temp */ +} smc_uart_t; + +/* SMC uart mode register (Internal memory map). +*/ +#define SMCMR_REN ((ushort)0x0001) +#define SMCMR_TEN ((ushort)0x0002) +#define SMCMR_DM ((ushort)0x000c) +#define SMCMR_SM_GCI ((ushort)0x0000) +#define SMCMR_SM_UART ((ushort)0x0020) +#define SMCMR_SM_TRANS ((ushort)0x0030) +#define SMCMR_SM_MASK ((ushort)0x0030) +#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ +#define SMCMR_REVD SMCMR_PM_EVEN +#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ +#define SMCMR_BS SMCMR_PEN +#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ +#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ +#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) + +/* SMC Event and Mask register. +*/ +#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */ +#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */ +#define SMCM_TXE ((unsigned char)0x10) +#define SMCM_BSY ((unsigned char)0x04) +#define SMCM_TX ((unsigned char)0x02) +#define SMCM_RX ((unsigned char)0x01) + +/* Baud rate generators. +*/ +#define CPM_BRG_RST ((uint)0x00020000) +#define CPM_BRG_EN ((uint)0x00010000) +#define CPM_BRG_EXTC_INT ((uint)0x00000000) +#define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000) +#define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000) +#define CPM_BRG_ATB ((uint)0x00002000) +#define CPM_BRG_CD_MASK ((uint)0x00001ffe) +#define CPM_BRG_DIV16 ((uint)0x00000001) + +/* SCCs. +*/ +#define SCC_GSMRH_IRP ((uint)0x00040000) +#define SCC_GSMRH_GDE ((uint)0x00010000) +#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000) +#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000) +#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000) +#define SCC_GSMRH_REVD ((uint)0x00002000) +#define SCC_GSMRH_TRX ((uint)0x00001000) +#define SCC_GSMRH_TTX ((uint)0x00000800) +#define SCC_GSMRH_CDP ((uint)0x00000400) +#define SCC_GSMRH_CTSP ((uint)0x00000200) +#define SCC_GSMRH_CDS ((uint)0x00000100) +#define SCC_GSMRH_CTSS ((uint)0x00000080) +#define SCC_GSMRH_TFL ((uint)0x00000040) +#define SCC_GSMRH_RFW ((uint)0x00000020) +#define SCC_GSMRH_TXSY ((uint)0x00000010) +#define SCC_GSMRH_SYNL16 ((uint)0x0000000c) +#define SCC_GSMRH_SYNL8 ((uint)0x00000008) +#define SCC_GSMRH_SYNL4 ((uint)0x00000004) +#define SCC_GSMRH_RTSM ((uint)0x00000002) +#define SCC_GSMRH_RSYN ((uint)0x00000001) + +#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */ +#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000) +#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000) +#define SCC_GSMRL_EDGE_POS ((uint)0x20000000) +#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000) +#define SCC_GSMRL_TCI ((uint)0x10000000) +#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000) +#define SCC_GSMRL_TSNC_4 ((uint)0x08000000) +#define SCC_GSMRL_TSNC_14 ((uint)0x04000000) +#define SCC_GSMRL_TSNC_INF ((uint)0x00000000) +#define SCC_GSMRL_RINV ((uint)0x02000000) +#define SCC_GSMRL_TINV ((uint)0x01000000) +#define SCC_GSMRL_TPL_128 ((uint)0x00c00000) +#define SCC_GSMRL_TPL_64 ((uint)0x00a00000) +#define SCC_GSMRL_TPL_48 ((uint)0x00800000) +#define SCC_GSMRL_TPL_32 ((uint)0x00600000) +#define SCC_GSMRL_TPL_16 ((uint)0x00400000) +#define SCC_GSMRL_TPL_8 ((uint)0x00200000) +#define SCC_GSMRL_TPL_NONE ((uint)0x00000000) +#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000) +#define SCC_GSMRL_TPP_01 ((uint)0x00100000) +#define SCC_GSMRL_TPP_10 ((uint)0x00080000) +#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000) +#define SCC_GSMRL_TEND ((uint)0x00040000) +#define SCC_GSMRL_TDCR_32 ((uint)0x00030000) +#define SCC_GSMRL_TDCR_16 ((uint)0x00020000) +#define SCC_GSMRL_TDCR_8 ((uint)0x00010000) +#define SCC_GSMRL_TDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000) +#define SCC_GSMRL_RDCR_16 ((uint)0x00008000) +#define SCC_GSMRL_RDCR_8 ((uint)0x00004000) +#define SCC_GSMRL_RDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000) +#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000) +#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000) +#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800) +#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600) +#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400) +#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200) +#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100) +#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */ +#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080) +#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040) +#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000) +#define SCC_GSMRL_ENR ((uint)0x00000020) +#define SCC_GSMRL_ENT ((uint)0x00000010) +#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c) +#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009) +#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008) +#define SCC_GSMRL_MODE_V14 ((uint)0x00000007) +#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006) +#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005) +#define SCC_GSMRL_MODE_UART ((uint)0x00000004) +#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003) +#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002) +#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000) + +#define SCC_TODR_TOD ((ushort)0x8000) + +/* SCC Event and Mask register. +*/ +#define SCCM_TXE ((unsigned char)0x10) +#define SCCM_BSY ((unsigned char)0x04) +#define SCCM_TX ((unsigned char)0x02) +#define SCCM_RX ((unsigned char)0x01) + +typedef struct scc_param { + ushort scc_rbase; /* Rx Buffer descriptor base address */ + ushort scc_tbase; /* Tx Buffer descriptor base address */ + u_char scc_rfcr; /* Rx function code */ + u_char scc_tfcr; /* Tx function code */ + ushort scc_mrblr; /* Max receive buffer length */ + uint scc_rstate; /* Internal */ + uint scc_idp; /* Internal */ + ushort scc_rbptr; /* Internal */ + ushort scc_ibc; /* Internal */ + uint scc_rxtmp; /* Internal */ + uint scc_tstate; /* Internal */ + uint scc_tdp; /* Internal */ + ushort scc_tbptr; /* Internal */ + ushort scc_tbc; /* Internal */ + uint scc_txtmp; /* Internal */ + uint scc_rcrc; /* Internal */ + uint scc_tcrc; /* Internal */ +} sccp_t; + +/* CPM Ethernet through SCC1. + */ +typedef struct scc_enet { + sccp_t sen_genscc; + uint sen_cpres; /* Preset CRC */ + uint sen_cmask; /* Constant mask for CRC */ + uint sen_crcec; /* CRC Error counter */ + uint sen_alec; /* alignment error counter */ + uint sen_disfc; /* discard frame counter */ + ushort sen_pads; /* Tx short frame pad character */ + ushort sen_retlim; /* Retry limit threshold */ + ushort sen_retcnt; /* Retry limit counter */ + ushort sen_maxflr; /* maximum frame length register */ + ushort sen_minflr; /* minimum frame length register */ + ushort sen_maxd1; /* maximum DMA1 length */ + ushort sen_maxd2; /* maximum DMA2 length */ + ushort sen_maxd; /* Rx max DMA */ + ushort sen_dmacnt; /* Rx DMA counter */ + ushort sen_maxb; /* Max BD byte count */ + ushort sen_gaddr1; /* Group address filter */ + ushort sen_gaddr2; + ushort sen_gaddr3; + ushort sen_gaddr4; + uint sen_tbuf0data0; /* Save area 0 - current frame */ + uint sen_tbuf0data1; /* Save area 1 - current frame */ + uint sen_tbuf0rba; /* Internal */ + uint sen_tbuf0crc; /* Internal */ + ushort sen_tbuf0bcnt; /* Internal */ + ushort sen_paddrh; /* physical address (MSB) */ + ushort sen_paddrm; + ushort sen_paddrl; /* physical address (LSB) */ + ushort sen_pper; /* persistence */ + ushort sen_rfbdptr; /* Rx first BD pointer */ + ushort sen_tfbdptr; /* Tx first BD pointer */ + ushort sen_tlbdptr; /* Tx last BD pointer */ + uint sen_tbuf1data0; /* Save area 0 - current frame */ + uint sen_tbuf1data1; /* Save area 1 - current frame */ + uint sen_tbuf1rba; /* Internal */ + uint sen_tbuf1crc; /* Internal */ + ushort sen_tbuf1bcnt; /* Internal */ + ushort sen_txlen; /* Tx Frame length counter */ + ushort sen_iaddr1; /* Individual address filter */ + ushort sen_iaddr2; + ushort sen_iaddr3; + ushort sen_iaddr4; + ushort sen_boffcnt; /* Backoff counter */ + + /* NOTE: Some versions of the manual have the following items + * incorrectly documented. Below is the proper order. + */ + ushort sen_taddrh; /* temp address (MSB) */ + ushort sen_taddrm; + ushort sen_taddrl; /* temp address (LSB) */ +} scc_enet_t; + + +/* SCC Event register as used by Ethernet. +*/ +#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ +#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* SCC Mode Register (PSMR) as used by Ethernet. +*/ +#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ + +/* Buffer descriptor control/status used by Ethernet receive. + * Common to SCC and FCC. + */ +#define BD_ENET_RX_EMPTY ((ushort)0x8000) +#define BD_ENET_RX_WRAP ((ushort)0x2000) +#define BD_ENET_RX_INTR ((ushort)0x1000) +#define BD_ENET_RX_LAST ((ushort)0x0800) +#define BD_ENET_RX_FIRST ((ushort)0x0400) +#define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_BC ((ushort)0x0080) /* FCC Only */ +#define BD_ENET_RX_MC ((ushort)0x0040) /* FCC Only */ +#define BD_ENET_RX_LG ((ushort)0x0020) +#define BD_ENET_RX_NO ((ushort)0x0010) +#define BD_ENET_RX_SH ((ushort)0x0008) +#define BD_ENET_RX_CR ((ushort)0x0004) +#define BD_ENET_RX_OV ((ushort)0x0002) +#define BD_ENET_RX_CL ((ushort)0x0001) +#define BD_ENET_RX_STATS ((ushort)0x01ff) /* All status bits */ + +/* Buffer descriptor control/status used by Ethernet transmit. + * Common to SCC and FCC. + */ +#define BD_ENET_TX_READY ((ushort)0x8000) +#define BD_ENET_TX_PAD ((ushort)0x4000) +#define BD_ENET_TX_WRAP ((ushort)0x2000) +#define BD_ENET_TX_INTR ((ushort)0x1000) +#define BD_ENET_TX_LAST ((ushort)0x0800) +#define BD_ENET_TX_TC ((ushort)0x0400) +#define BD_ENET_TX_DEF ((ushort)0x0200) +#define BD_ENET_TX_HB ((ushort)0x0100) +#define BD_ENET_TX_LC ((ushort)0x0080) +#define BD_ENET_TX_RL ((ushort)0x0040) +#define BD_ENET_TX_RCMASK ((ushort)0x003c) +#define BD_ENET_TX_UN ((ushort)0x0002) +#define BD_ENET_TX_CSL ((ushort)0x0001) +#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ + +/* SCC as UART +*/ +typedef struct scc_uart { + sccp_t scc_genscc; + uint scc_res1; /* Reserved */ + uint scc_res2; /* Reserved */ + ushort scc_maxidl; /* Maximum idle chars */ + ushort scc_idlc; /* temp idle counter */ + ushort scc_brkcr; /* Break count register */ + ushort scc_parec; /* receive parity error counter */ + ushort scc_frmec; /* receive framing error counter */ + ushort scc_nosec; /* receive noise counter */ + ushort scc_brkec; /* receive break condition counter */ + ushort scc_brkln; /* last received break length */ + ushort scc_uaddr1; /* UART address character 1 */ + ushort scc_uaddr2; /* UART address character 2 */ + ushort scc_rtemp; /* Temp storage */ + ushort scc_toseq; /* Transmit out of sequence char */ + ushort scc_char1; /* control character 1 */ + ushort scc_char2; /* control character 2 */ + ushort scc_char3; /* control character 3 */ + ushort scc_char4; /* control character 4 */ + ushort scc_char5; /* control character 5 */ + ushort scc_char6; /* control character 6 */ + ushort scc_char7; /* control character 7 */ + ushort scc_char8; /* control character 8 */ + ushort scc_rccm; /* receive control character mask */ + ushort scc_rccr; /* receive control character register */ + ushort scc_rlbc; /* receive last break character */ +} scc_uart_t; + +/* SCC Event and Mask registers when it is used as a UART. +*/ +#define UART_SCCM_GLR ((ushort)0x1000) +#define UART_SCCM_GLT ((ushort)0x0800) +#define UART_SCCM_AB ((ushort)0x0200) +#define UART_SCCM_IDL ((ushort)0x0100) +#define UART_SCCM_GRA ((ushort)0x0080) +#define UART_SCCM_BRKE ((ushort)0x0040) +#define UART_SCCM_BRKS ((ushort)0x0020) +#define UART_SCCM_CCR ((ushort)0x0008) +#define UART_SCCM_BSY ((ushort)0x0004) +#define UART_SCCM_TX ((ushort)0x0002) +#define UART_SCCM_RX ((ushort)0x0001) + +/* The SCC PSMR when used as a UART. +*/ +#define SCU_PSMR_FLC ((ushort)0x8000) +#define SCU_PSMR_SL ((ushort)0x4000) +#define SCU_PSMR_CL ((ushort)0x3000) +#define SCU_PSMR_UM ((ushort)0x0c00) +#define SCU_PSMR_FRZ ((ushort)0x0200) +#define SCU_PSMR_RZS ((ushort)0x0100) +#define SCU_PSMR_SYN ((ushort)0x0080) +#define SCU_PSMR_DRT ((ushort)0x0040) +#define SCU_PSMR_PEN ((ushort)0x0010) +#define SCU_PSMR_RPM ((ushort)0x000c) +#define SCU_PSMR_REVP ((ushort)0x0008) +#define SCU_PSMR_TPM ((ushort)0x0003) +#define SCU_PSMR_TEVP ((ushort)0x0002) + +/* CPM Transparent mode SCC. + */ +typedef struct scc_trans { + sccp_t st_genscc; + uint st_cpres; /* Preset CRC */ + uint st_cmask; /* Constant mask for CRC */ +} scc_trans_t; + +#define BD_SCC_TX_LAST ((ushort)0x0800) + +/* How about some FCCs..... +*/ +#define FCC_GFMR_DIAG_NORM ((uint)0x00000000) +#define FCC_GFMR_DIAG_LE ((uint)0x40000000) +#define FCC_GFMR_DIAG_AE ((uint)0x80000000) +#define FCC_GFMR_DIAG_ALE ((uint)0xc0000000) +#define FCC_GFMR_TCI ((uint)0x20000000) +#define FCC_GFMR_TRX ((uint)0x10000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_CDP ((uint)0x04000000) +#define FCC_GFMR_CTSP ((uint)0x02000000) +#define FCC_GFMR_CDS ((uint)0x01000000) +#define FCC_GFMR_CTSS ((uint)0x00800000) +#define FCC_GFMR_SYNL_NONE ((uint)0x00000000) +#define FCC_GFMR_SYNL_AUTO ((uint)0x00004000) +#define FCC_GFMR_SYNL_8 ((uint)0x00008000) +#define FCC_GFMR_SYNL_16 ((uint)0x0000c000) +#define FCC_GFMR_RTSM ((uint)0x00002000) +#define FCC_GFMR_RENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_RENC_NRZI ((uint)0x00000800) +#define FCC_GFMR_REVD ((uint)0x00000400) +#define FCC_GFMR_TENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_TENC_NRZI ((uint)0x00000100) +#define FCC_GFMR_TCRC_16 ((uint)0x00000000) +#define FCC_GFMR_TCRC_32 ((uint)0x00000080) +#define FCC_GFMR_ENR ((uint)0x00000020) +#define FCC_GFMR_ENT ((uint)0x00000010) +#define FCC_GFMR_MODE_ENET ((uint)0x0000000c) +#define FCC_GFMR_MODE_ATM ((uint)0x0000000a) +#define FCC_GFMR_MODE_HDLC ((uint)0x00000000) + +/* Generic FCC parameter ram. +*/ +typedef struct fcc_param { + ushort fcc_riptr; /* Rx Internal temp pointer */ + ushort fcc_tiptr; /* Tx Internal temp pointer */ + ushort fcc_res1; + ushort fcc_mrblr; /* Max receive buffer length, mod 32 bytes */ + uint fcc_rstate; /* Upper byte is Func code, must be set */ + uint fcc_rbase; /* Receive BD base */ + ushort fcc_rbdstat; /* RxBD status */ + ushort fcc_rbdlen; /* RxBD down counter */ + uint fcc_rdptr; /* RxBD internal data pointer */ + uint fcc_tstate; /* Upper byte is Func code, must be set */ + uint fcc_tbase; /* Transmit BD base */ + ushort fcc_tbdstat; /* TxBD status */ + ushort fcc_tbdlen; /* TxBD down counter */ + uint fcc_tdptr; /* TxBD internal data pointer */ + uint fcc_rbptr; /* Rx BD Internal buf pointer */ + uint fcc_tbptr; /* Tx BD Internal buf pointer */ + uint fcc_rcrc; /* Rx temp CRC */ + uint fcc_res2; + uint fcc_tcrc; /* Tx temp CRC */ +} fccp_t; + + +/* Ethernet controller through FCC. +*/ +typedef struct fcc_enet { + fccp_t fen_genfcc; + uint fen_statbuf; /* Internal status buffer */ + uint fen_camptr; /* CAM address */ + uint fen_cmask; /* Constant mask for CRC */ + uint fen_cpres; /* Preset CRC */ + uint fen_crcec; /* CRC Error counter */ + uint fen_alec; /* alignment error counter */ + uint fen_disfc; /* discard frame counter */ + ushort fen_retlim; /* Retry limit */ + ushort fen_retcnt; /* Retry counter */ + ushort fen_pper; /* Persistence */ + ushort fen_boffcnt; /* backoff counter */ + uint fen_gaddrh; /* Group address filter, high 32-bits */ + uint fen_gaddrl; /* Group address filter, low 32-bits */ + ushort fen_tfcstat; /* out of sequence TxBD */ + ushort fen_tfclen; + uint fen_tfcptr; + ushort fen_mflr; /* Maximum frame length (1518) */ + ushort fen_paddrh; /* MAC address */ + ushort fen_paddrm; + ushort fen_paddrl; + ushort fen_ibdcount; /* Internal BD counter */ + ushort fen_ibdstart; /* Internal BD start pointer */ + ushort fen_ibdend; /* Internal BD end pointer */ + ushort fen_txlen; /* Internal Tx frame length counter */ + uint fen_ibdbase[8]; /* Internal use */ + uint fen_iaddrh; /* Individual address filter */ + uint fen_iaddrl; + ushort fen_minflr; /* Minimum frame length (64) */ + ushort fen_taddrh; /* Filter transfer MAC address */ + ushort fen_taddrm; + ushort fen_taddrl; + ushort fen_padptr; /* Pointer to pad byte buffer */ + ushort fen_cftype; /* control frame type */ + ushort fen_cfrange; /* control frame range */ + ushort fen_maxb; /* maximum BD count */ + ushort fen_maxd1; /* Max DMA1 length (1520) */ + ushort fen_maxd2; /* Max DMA2 length (1520) */ + ushort fen_maxd; /* internal max DMA count */ + ushort fen_dmacnt; /* internal DMA counter */ + uint fen_octc; /* Total octect counter */ + uint fen_colc; /* Total collision counter */ + uint fen_broc; /* Total broadcast packet counter */ + uint fen_mulc; /* Total multicast packet count */ + uint fen_uspc; /* Total packets < 64 bytes */ + uint fen_frgc; /* Total packets < 64 bytes with errors */ + uint fen_ospc; /* Total packets > 1518 */ + uint fen_jbrc; /* Total packets > 1518 with errors */ + uint fen_p64c; /* Total packets == 64 bytes */ + uint fen_p65c; /* Total packets 64 < bytes <= 127 */ + uint fen_p128c; /* Total packets 127 < bytes <= 255 */ + uint fen_p256c; /* Total packets 256 < bytes <= 511 */ + uint fen_p512c; /* Total packets 512 < bytes <= 1023 */ + uint fen_p1024c; /* Total packets 1024 < bytes <= 1518 */ + uint fen_cambuf; /* Internal CAM buffer poiner */ + ushort fen_rfthr; /* Received frames threshold */ + ushort fen_rfcnt; /* Received frames count */ +} fcc_enet_t; + +/* FCC Event/Mask register as used by Ethernet. +*/ +#define FCC_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define FCC_ENET_RXC ((ushort)0x0040) /* Control Frame Received */ +#define FCC_ENET_TXC ((ushort)0x0020) /* Out of seq. Tx sent */ +#define FCC_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define FCC_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define FCC_ENET_BSY ((ushort)0x0004) /* Busy. Rx Frame dropped */ +#define FCC_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define FCC_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* FCC Mode Register (FPSMR) as used by Ethernet. +*/ +#define FCC_PSMR_HBC ((uint)0x80000000) /* Enable heartbeat */ +#define FCC_PSMR_FC ((uint)0x40000000) /* Force Collision */ +#define FCC_PSMR_SBT ((uint)0x20000000) /* Stop backoff timer */ +#define FCC_PSMR_LPB ((uint)0x10000000) /* Local protect. 1 = FDX */ +#define FCC_PSMR_LCW ((uint)0x08000000) /* Late collision select */ +#define FCC_PSMR_FDE ((uint)0x04000000) /* Full Duplex Enable */ +#define FCC_PSMR_MON ((uint)0x02000000) /* RMON Enable */ +#define FCC_PSMR_PRO ((uint)0x00400000) /* Promiscuous Enable */ +#define FCC_PSMR_FCE ((uint)0x00200000) /* Flow Control Enable */ +#define FCC_PSMR_RSH ((uint)0x00100000) /* Receive Short Frames */ +#define FCC_PSMR_CAM ((uint)0x00000400) /* CAM enable */ +#define FCC_PSMR_BRO ((uint)0x00000200) /* Broadcast pkt discard */ +#define FCC_PSMR_ENCRC ((uint)0x00000080) /* Use 32-bit CRC */ + +/* IIC parameter RAM. +*/ +typedef struct iic { + ushort iic_rbase; /* Rx Buffer descriptor base address */ + ushort iic_tbase; /* Tx Buffer descriptor base address */ + u_char iic_rfcr; /* Rx function code */ + u_char iic_tfcr; /* Tx function code */ + ushort iic_mrblr; /* Max receive buffer length */ + uint iic_rstate; /* Internal */ + uint iic_rdp; /* Internal */ + ushort iic_rbptr; /* Internal */ + ushort iic_rbc; /* Internal */ + uint iic_rxtmp; /* Internal */ + uint iic_tstate; /* Internal */ + uint iic_tdp; /* Internal */ + ushort iic_tbptr; /* Internal */ + ushort iic_tbc; /* Internal */ + uint iic_txtmp; /* Internal */ +} iic_t; + +/* SPI parameter RAM. +*/ +typedef struct spi { + ushort spi_rbase; /* Rx Buffer descriptor base address */ + ushort spi_tbase; /* Tx Buffer descriptor base address */ + u_char spi_rfcr; /* Rx function code */ + u_char spi_tfcr; /* Tx function code */ + ushort spi_mrblr; /* Max receive buffer length */ + uint spi_rstate; /* Internal */ + uint spi_rdp; /* Internal */ + ushort spi_rbptr; /* Internal */ + ushort spi_rbc; /* Internal */ + uint spi_rxtmp; /* Internal */ + uint spi_tstate; /* Internal */ + uint spi_tdp; /* Internal */ + ushort spi_tbptr; /* Internal */ + ushort spi_tbc; /* Internal */ + uint spi_txtmp; /* Internal */ + uint spi_res; /* Tx temp. */ + uint spi_res1[4]; /* SDMA temp. */ +} spi_t; + +/* SPI Mode register. +*/ +#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */ +#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */ +#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */ +#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */ +#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */ +#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */ +#define SPMODE_EN ((ushort)0x0100) /* Enable */ +#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */ +#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */ + +#define SPMODE_LEN(x) ((((x)-1)&0xF)<<4) +#define SPMODE_PM(x) ((x) &0xF) + +#define SPI_EB ((u_char)0x10) /* big endian byte order */ + +#define BD_IIC_START ((ushort)0x0400) + +/* IDMA parameter RAM +*/ +typedef struct idma { + ushort ibase; /* IDMA buffer descriptor table base address */ + ushort dcm; /* DMA channel mode */ + ushort ibdptr; /* IDMA current buffer descriptor pointer */ + ushort dpr_buf; /* IDMA transfer buffer base address */ + ushort buf_inv; /* internal buffer inventory */ + ushort ss_max; /* steady-state maximum transfer size */ + ushort dpr_in_ptr; /* write pointer inside the internal buffer */ + ushort sts; /* source transfer size */ + ushort dpr_out_ptr; /* read pointer inside the internal buffer */ + ushort seob; /* source end of burst */ + ushort deob; /* destination end of burst */ + ushort dts; /* destination transfer size */ + ushort ret_add; /* return address when working in ERM=1 mode */ + ushort res0; /* reserved */ + uint bd_cnt; /* internal byte count */ + uint s_ptr; /* source internal data pointer */ + uint d_ptr; /* destination internal data pointer */ + uint istate; /* internal state */ + u_char res1[20]; /* pad to 64-byte length */ +} idma_t; + +/* DMA channel mode bit fields +*/ +#define IDMA_DCM_FB ((ushort)0x8000) /* fly-by mode */ +#define IDMA_DCM_LP ((ushort)0x4000) /* low priority */ +#define IDMA_DCM_TC2 ((ushort)0x0400) /* value driven on TC[2] */ +#define IDMA_DCM_DMA_WRAP_MASK ((ushort)0x01c0) /* mask for DMA wrap */ +#define IDMA_DCM_DMA_WRAP_64 ((ushort)0x0000) /* 64-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_128 ((ushort)0x0040) /* 128-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_256 ((ushort)0x0080) /* 256-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_512 ((ushort)0x00c0) /* 512-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_1024 ((ushort)0x0100) /* 1024-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_2048 ((ushort)0x0140) /* 2048-byte DMA xfer buffer */ +#define IDMA_DCM_SINC ((ushort)0x0020) /* source inc addr */ +#define IDMA_DCM_DINC ((ushort)0x0010) /* destination inc addr */ +#define IDMA_DCM_ERM ((ushort)0x0008) /* external request mode */ +#define IDMA_DCM_DT ((ushort)0x0004) /* DONE treatment */ +#define IDMA_DCM_SD_MASK ((ushort)0x0003) /* mask for SD bit field */ +#define IDMA_DCM_SD_MEM2MEM ((ushort)0x0000) /* memory-to-memory xfer */ +#define IDMA_DCM_SD_PER2MEM ((ushort)0x0002) /* peripheral-to-memory xfer */ +#define IDMA_DCM_SD_MEM2PER ((ushort)0x0001) /* memory-to-peripheral xfer */ + +/* IDMA Buffer Descriptors +*/ +typedef struct idma_bd { + uint flags; + uint len; /* data length */ + uint src; /* source data buffer pointer */ + uint dst; /* destination data buffer pointer */ +} idma_bd_t; + +/* IDMA buffer descriptor flag bit fields +*/ +#define IDMA_BD_V ((uint)0x80000000) /* valid */ +#define IDMA_BD_W ((uint)0x20000000) /* wrap */ +#define IDMA_BD_I ((uint)0x10000000) /* interrupt */ +#define IDMA_BD_L ((uint)0x08000000) /* last */ +#define IDMA_BD_CM ((uint)0x02000000) /* continuous mode */ +#define IDMA_BD_SDN ((uint)0x00400000) /* source done */ +#define IDMA_BD_DDN ((uint)0x00200000) /* destination done */ +#define IDMA_BD_DGBL ((uint)0x00100000) /* destination global */ +#define IDMA_BD_DBO_LE ((uint)0x00040000) /* little-end dest byte order */ +#define IDMA_BD_DBO_BE ((uint)0x00080000) /* big-end dest byte order */ +#define IDMA_BD_DDTB ((uint)0x00010000) /* destination data bus */ +#define IDMA_BD_SGBL ((uint)0x00002000) /* source global */ +#define IDMA_BD_SBO_LE ((uint)0x00000800) /* little-end src byte order */ +#define IDMA_BD_SBO_BE ((uint)0x00001000) /* big-end src byte order */ +#define IDMA_BD_SDTB ((uint)0x00000200) /* source data bus */ + +/* per-channel IDMA registers +*/ +typedef struct im_idma { + u_char idsr; /* IDMAn event status register */ + u_char res0[3]; + u_char idmr; /* IDMAn event mask register */ + u_char res1[3]; +} im_idma_t; + +/* IDMA event register bit fields +*/ +#define IDMA_EVENT_SC ((unsigned char)0x08) /* stop completed */ +#define IDMA_EVENT_OB ((unsigned char)0x04) /* out of buffers */ +#define IDMA_EVENT_EDN ((unsigned char)0x02) /* external DONE asserted */ +#define IDMA_EVENT_BC ((unsigned char)0x01) /* buffer descriptor complete */ + +/* RISC Controller Configuration Register (RCCR) bit fields +*/ +#define RCCR_TIME ((uint)0x80000000) /* timer enable */ +#define RCCR_TIMEP_MASK ((uint)0x3f000000) /* mask for timer period bit field */ +#define RCCR_DR0M ((uint)0x00800000) /* IDMA0 request mode */ +#define RCCR_DR1M ((uint)0x00400000) /* IDMA1 request mode */ +#define RCCR_DR2M ((uint)0x00000080) /* IDMA2 request mode */ +#define RCCR_DR3M ((uint)0x00000040) /* IDMA3 request mode */ +#define RCCR_DR0QP_MASK ((uint)0x00300000) /* mask for IDMA0 req priority */ +#define RCCR_DR0QP_HIGH ((uint)0x00000000) /* IDMA0 has high req priority */ +#define RCCR_DR0QP_MED ((uint)0x00100000) /* IDMA0 has medium req priority */ +#define RCCR_DR0QP_LOW ((uint)0x00200000) /* IDMA0 has low req priority */ +#define RCCR_DR1QP_MASK ((uint)0x00030000) /* mask for IDMA1 req priority */ +#define RCCR_DR1QP_HIGH ((uint)0x00000000) /* IDMA1 has high req priority */ +#define RCCR_DR1QP_MED ((uint)0x00010000) /* IDMA1 has medium req priority */ +#define RCCR_DR1QP_LOW ((uint)0x00020000) /* IDMA1 has low req priority */ +#define RCCR_DR2QP_MASK ((uint)0x00000030) /* mask for IDMA2 req priority */ +#define RCCR_DR2QP_HIGH ((uint)0x00000000) /* IDMA2 has high req priority */ +#define RCCR_DR2QP_MED ((uint)0x00000010) /* IDMA2 has medium req priority */ +#define RCCR_DR2QP_LOW ((uint)0x00000020) /* IDMA2 has low req priority */ +#define RCCR_DR3QP_MASK ((uint)0x00000003) /* mask for IDMA3 req priority */ +#define RCCR_DR3QP_HIGH ((uint)0x00000000) /* IDMA3 has high req priority */ +#define RCCR_DR3QP_MED ((uint)0x00000001) /* IDMA3 has medium req priority */ +#define RCCR_DR3QP_LOW ((uint)0x00000002) /* IDMA3 has low req priority */ +#define RCCR_EIE ((uint)0x00080000) /* external interrupt enable */ +#define RCCR_SCD ((uint)0x00040000) /* scheduler configuration */ +#define RCCR_ERAM_MASK ((uint)0x0000e000) /* mask for enable RAM microcode */ +#define RCCR_ERAM_0KB ((uint)0x00000000) /* use 0KB of dpram for microcode */ +#define RCCR_ERAM_2KB ((uint)0x00002000) /* use 2KB of dpram for microcode */ +#define RCCR_ERAM_4KB ((uint)0x00004000) /* use 4KB of dpram for microcode */ +#define RCCR_ERAM_6KB ((uint)0x00006000) /* use 6KB of dpram for microcode */ +#define RCCR_ERAM_8KB ((uint)0x00008000) /* use 8KB of dpram for microcode */ +#define RCCR_ERAM_10KB ((uint)0x0000a000) /* use 10KB of dpram for microcode */ +#define RCCR_ERAM_12KB ((uint)0x0000c000) /* use 12KB of dpram for microcode */ +#define RCCR_EDM0 ((uint)0x00000800) /* DREQ0 edge detect mode */ +#define RCCR_EDM1 ((uint)0x00000400) /* DREQ1 edge detect mode */ +#define RCCR_EDM2 ((uint)0x00000200) /* DREQ2 edge detect mode */ +#define RCCR_EDM3 ((uint)0x00000100) /* DREQ3 edge detect mode */ +#define RCCR_DEM01 ((uint)0x00000008) /* DONE0/DONE1 edge detect mode */ +#define RCCR_DEM23 ((uint)0x00000004) /* DONE2/DONE3 edge detect mode */ + +/*----------------------------------------------------------------------- + * CMXFCR - CMX FCC Clock Route Register + */ +#define CMXFCR_FC1 0x40000000 /* FCC1 connection */ +#define CMXFCR_RF1CS_MSK 0x38000000 /* Receive FCC1 Clock Source Mask */ +#define CMXFCR_TF1CS_MSK 0x07000000 /* Transmit FCC1 Clock Source Mask */ +#define CMXFCR_FC2 0x00400000 /* FCC2 connection */ +#define CMXFCR_RF2CS_MSK 0x00380000 /* Receive FCC2 Clock Source Mask */ +#define CMXFCR_TF2CS_MSK 0x00070000 /* Transmit FCC2 Clock Source Mask */ +#define CMXFCR_FC3 0x00004000 /* FCC3 connection */ +#define CMXFCR_RF3CS_MSK 0x00003800 /* Receive FCC3 Clock Source Mask */ +#define CMXFCR_TF3CS_MSK 0x00000700 /* Transmit FCC3 Clock Source Mask */ + +#define CMXFCR_RF1CS_BRG5 0x00000000 /* Receive FCC1 Clock Source is BRG5 */ +#define CMXFCR_RF1CS_BRG6 0x08000000 /* Receive FCC1 Clock Source is BRG6 */ +#define CMXFCR_RF1CS_BRG7 0x10000000 /* Receive FCC1 Clock Source is BRG7 */ +#define CMXFCR_RF1CS_BRG8 0x18000000 /* Receive FCC1 Clock Source is BRG8 */ +#define CMXFCR_RF1CS_CLK9 0x20000000 /* Receive FCC1 Clock Source is CLK9 */ +#define CMXFCR_RF1CS_CLK10 0x28000000 /* Receive FCC1 Clock Source is CLK10 */ +#define CMXFCR_RF1CS_CLK11 0x30000000 /* Receive FCC1 Clock Source is CLK11 */ +#define CMXFCR_RF1CS_CLK12 0x38000000 /* Receive FCC1 Clock Source is CLK12 */ + +#define CMXFCR_TF1CS_BRG5 0x00000000 /* Transmit FCC1 Clock Source is BRG5 */ +#define CMXFCR_TF1CS_BRG6 0x01000000 /* Transmit FCC1 Clock Source is BRG6 */ +#define CMXFCR_TF1CS_BRG7 0x02000000 /* Transmit FCC1 Clock Source is BRG7 */ +#define CMXFCR_TF1CS_BRG8 0x03000000 /* Transmit FCC1 Clock Source is BRG8 */ +#define CMXFCR_TF1CS_CLK9 0x04000000 /* Transmit FCC1 Clock Source is CLK9 */ +#define CMXFCR_TF1CS_CLK10 0x05000000 /* Transmit FCC1 Clock Source is CLK10 */ +#define CMXFCR_TF1CS_CLK11 0x06000000 /* Transmit FCC1 Clock Source is CLK11 */ +#define CMXFCR_TF1CS_CLK12 0x07000000 /* Transmit FCC1 Clock Source is CLK12 */ + +#define CMXFCR_RF2CS_BRG5 0x00000000 /* Receive FCC2 Clock Source is BRG5 */ +#define CMXFCR_RF2CS_BRG6 0x00080000 /* Receive FCC2 Clock Source is BRG6 */ +#define CMXFCR_RF2CS_BRG7 0x00100000 /* Receive FCC2 Clock Source is BRG7 */ +#define CMXFCR_RF2CS_BRG8 0x00180000 /* Receive FCC2 Clock Source is BRG8 */ +#define CMXFCR_RF2CS_CLK13 0x00200000 /* Receive FCC2 Clock Source is CLK13 */ +#define CMXFCR_RF2CS_CLK14 0x00280000 /* Receive FCC2 Clock Source is CLK14 */ +#define CMXFCR_RF2CS_CLK15 0x00300000 /* Receive FCC2 Clock Source is CLK15 */ +#define CMXFCR_RF2CS_CLK16 0x00380000 /* Receive FCC2 Clock Source is CLK16 */ + +#define CMXFCR_TF2CS_BRG5 0x00000000 /* Transmit FCC2 Clock Source is BRG5 */ +#define CMXFCR_TF2CS_BRG6 0x00010000 /* Transmit FCC2 Clock Source is BRG6 */ +#define CMXFCR_TF2CS_BRG7 0x00020000 /* Transmit FCC2 Clock Source is BRG7 */ +#define CMXFCR_TF2CS_BRG8 0x00030000 /* Transmit FCC2 Clock Source is BRG8 */ +#define CMXFCR_TF2CS_CLK13 0x00040000 /* Transmit FCC2 Clock Source is CLK13 */ +#define CMXFCR_TF2CS_CLK14 0x00050000 /* Transmit FCC2 Clock Source is CLK14 */ +#define CMXFCR_TF2CS_CLK15 0x00060000 /* Transmit FCC2 Clock Source is CLK15 */ +#define CMXFCR_TF2CS_CLK16 0x00070000 /* Transmit FCC2 Clock Source is CLK16 */ + +#define CMXFCR_RF3CS_BRG5 0x00000000 /* Receive FCC3 Clock Source is BRG5 */ +#define CMXFCR_RF3CS_BRG6 0x00000800 /* Receive FCC3 Clock Source is BRG6 */ +#define CMXFCR_RF3CS_BRG7 0x00001000 /* Receive FCC3 Clock Source is BRG7 */ +#define CMXFCR_RF3CS_BRG8 0x00001800 /* Receive FCC3 Clock Source is BRG8 */ +#define CMXFCR_RF3CS_CLK13 0x00002000 /* Receive FCC3 Clock Source is CLK13 */ +#define CMXFCR_RF3CS_CLK14 0x00002800 /* Receive FCC3 Clock Source is CLK14 */ +#define CMXFCR_RF3CS_CLK15 0x00003000 /* Receive FCC3 Clock Source is CLK15 */ +#define CMXFCR_RF3CS_CLK16 0x00003800 /* Receive FCC3 Clock Source is CLK16 */ + +#define CMXFCR_TF3CS_BRG5 0x00000000 /* Transmit FCC3 Clock Source is BRG5 */ +#define CMXFCR_TF3CS_BRG6 0x00000100 /* Transmit FCC3 Clock Source is BRG6 */ +#define CMXFCR_TF3CS_BRG7 0x00000200 /* Transmit FCC3 Clock Source is BRG7 */ +#define CMXFCR_TF3CS_BRG8 0x00000300 /* Transmit FCC3 Clock Source is BRG8 */ +#define CMXFCR_TF3CS_CLK13 0x00000400 /* Transmit FCC3 Clock Source is CLK13 */ +#define CMXFCR_TF3CS_CLK14 0x00000500 /* Transmit FCC3 Clock Source is CLK14 */ +#define CMXFCR_TF3CS_CLK15 0x00000600 /* Transmit FCC3 Clock Source is CLK15 */ +#define CMXFCR_TF3CS_CLK16 0x00000700 /* Transmit FCC3 Clock Source is CLK16 */ + +/*----------------------------------------------------------------------- + * CMXSCR - CMX SCC Clock Route Register + */ +#define CMXSCR_GR1 0x80000000 /* Grant Support of SCC1 */ +#define CMXSCR_SC1 0x40000000 /* SCC1 connection */ +#define CMXSCR_RS1CS_MSK 0x38000000 /* Receive SCC1 Clock Source Mask */ +#define CMXSCR_TS1CS_MSK 0x07000000 /* Transmit SCC1 Clock Source Mask */ +#define CMXSCR_GR2 0x00800000 /* Grant Support of SCC2 */ +#define CMXSCR_SC2 0x00400000 /* SCC2 connection */ +#define CMXSCR_RS2CS_MSK 0x00380000 /* Receive SCC2 Clock Source Mask */ +#define CMXSCR_TS2CS_MSK 0x00070000 /* Transmit SCC2 Clock Source Mask */ +#define CMXSCR_GR3 0x00008000 /* Grant Support of SCC3 */ +#define CMXSCR_SC3 0x00004000 /* SCC3 connection */ +#define CMXSCR_RS3CS_MSK 0x00003800 /* Receive SCC3 Clock Source Mask */ +#define CMXSCR_TS3CS_MSK 0x00000700 /* Transmit SCC3 Clock Source Mask */ +#define CMXSCR_GR4 0x00000080 /* Grant Support of SCC4 */ +#define CMXSCR_SC4 0x00000040 /* SCC4 connection */ +#define CMXSCR_RS4CS_MSK 0x00000038 /* Receive SCC4 Clock Source Mask */ +#define CMXSCR_TS4CS_MSK 0x00000007 /* Transmit SCC4 Clock Source Mask */ + +#define CMXSCR_RS1CS_BRG1 0x00000000 /* SCC1 Rx Clock Source is BRG1 */ +#define CMXSCR_RS1CS_BRG2 0x08000000 /* SCC1 Rx Clock Source is BRG2 */ +#define CMXSCR_RS1CS_BRG3 0x10000000 /* SCC1 Rx Clock Source is BRG3 */ +#define CMXSCR_RS1CS_BRG4 0x18000000 /* SCC1 Rx Clock Source is BRG4 */ +#define CMXSCR_RS1CS_CLK11 0x20000000 /* SCC1 Rx Clock Source is CLK11 */ +#define CMXSCR_RS1CS_CLK12 0x28000000 /* SCC1 Rx Clock Source is CLK12 */ +#define CMXSCR_RS1CS_CLK3 0x30000000 /* SCC1 Rx Clock Source is CLK3 */ +#define CMXSCR_RS1CS_CLK4 0x38000000 /* SCC1 Rx Clock Source is CLK4 */ + +#define CMXSCR_TS1CS_BRG1 0x00000000 /* SCC1 Tx Clock Source is BRG1 */ +#define CMXSCR_TS1CS_BRG2 0x01000000 /* SCC1 Tx Clock Source is BRG2 */ +#define CMXSCR_TS1CS_BRG3 0x02000000 /* SCC1 Tx Clock Source is BRG3 */ +#define CMXSCR_TS1CS_BRG4 0x03000000 /* SCC1 Tx Clock Source is BRG4 */ +#define CMXSCR_TS1CS_CLK11 0x04000000 /* SCC1 Tx Clock Source is CLK11 */ +#define CMXSCR_TS1CS_CLK12 0x05000000 /* SCC1 Tx Clock Source is CLK12 */ +#define CMXSCR_TS1CS_CLK3 0x06000000 /* SCC1 Tx Clock Source is CLK3 */ +#define CMXSCR_TS1CS_CLK4 0x07000000 /* SCC1 Tx Clock Source is CLK4 */ + +#define CMXSCR_RS2CS_BRG1 0x00000000 /* SCC2 Rx Clock Source is BRG1 */ +#define CMXSCR_RS2CS_BRG2 0x00080000 /* SCC2 Rx Clock Source is BRG2 */ +#define CMXSCR_RS2CS_BRG3 0x00100000 /* SCC2 Rx Clock Source is BRG3 */ +#define CMXSCR_RS2CS_BRG4 0x00180000 /* SCC2 Rx Clock Source is BRG4 */ +#define CMXSCR_RS2CS_CLK11 0x00200000 /* SCC2 Rx Clock Source is CLK11 */ +#define CMXSCR_RS2CS_CLK12 0x00280000 /* SCC2 Rx Clock Source is CLK12 */ +#define CMXSCR_RS2CS_CLK3 0x00300000 /* SCC2 Rx Clock Source is CLK3 */ +#define CMXSCR_RS2CS_CLK4 0x00380000 /* SCC2 Rx Clock Source is CLK4 */ + +#define CMXSCR_TS2CS_BRG1 0x00000000 /* SCC2 Tx Clock Source is BRG1 */ +#define CMXSCR_TS2CS_BRG2 0x00010000 /* SCC2 Tx Clock Source is BRG2 */ +#define CMXSCR_TS2CS_BRG3 0x00020000 /* SCC2 Tx Clock Source is BRG3 */ +#define CMXSCR_TS2CS_BRG4 0x00030000 /* SCC2 Tx Clock Source is BRG4 */ +#define CMXSCR_TS2CS_CLK11 0x00040000 /* SCC2 Tx Clock Source is CLK11 */ +#define CMXSCR_TS2CS_CLK12 0x00050000 /* SCC2 Tx Clock Source is CLK12 */ +#define CMXSCR_TS2CS_CLK3 0x00060000 /* SCC2 Tx Clock Source is CLK3 */ +#define CMXSCR_TS2CS_CLK4 0x00070000 /* SCC2 Tx Clock Source is CLK4 */ + +#define CMXSCR_RS3CS_BRG1 0x00000000 /* SCC3 Rx Clock Source is BRG1 */ +#define CMXSCR_RS3CS_BRG2 0x00000800 /* SCC3 Rx Clock Source is BRG2 */ +#define CMXSCR_RS3CS_BRG3 0x00001000 /* SCC3 Rx Clock Source is BRG3 */ +#define CMXSCR_RS3CS_BRG4 0x00001800 /* SCC3 Rx Clock Source is BRG4 */ +#define CMXSCR_RS3CS_CLK5 0x00002000 /* SCC3 Rx Clock Source is CLK5 */ +#define CMXSCR_RS3CS_CLK6 0x00002800 /* SCC3 Rx Clock Source is CLK6 */ +#define CMXSCR_RS3CS_CLK7 0x00003000 /* SCC3 Rx Clock Source is CLK7 */ +#define CMXSCR_RS3CS_CLK8 0x00003800 /* SCC3 Rx Clock Source is CLK8 */ + +#define CMXSCR_TS3CS_BRG1 0x00000000 /* SCC3 Tx Clock Source is BRG1 */ +#define CMXSCR_TS3CS_BRG2 0x00000100 /* SCC3 Tx Clock Source is BRG2 */ +#define CMXSCR_TS3CS_BRG3 0x00000200 /* SCC3 Tx Clock Source is BRG3 */ +#define CMXSCR_TS3CS_BRG4 0x00000300 /* SCC3 Tx Clock Source is BRG4 */ +#define CMXSCR_TS3CS_CLK5 0x00000400 /* SCC3 Tx Clock Source is CLK5 */ +#define CMXSCR_TS3CS_CLK6 0x00000500 /* SCC3 Tx Clock Source is CLK6 */ +#define CMXSCR_TS3CS_CLK7 0x00000600 /* SCC3 Tx Clock Source is CLK7 */ +#define CMXSCR_TS3CS_CLK8 0x00000700 /* SCC3 Tx Clock Source is CLK8 */ + +#define CMXSCR_RS4CS_BRG1 0x00000000 /* SCC4 Rx Clock Source is BRG1 */ +#define CMXSCR_RS4CS_BRG2 0x00000008 /* SCC4 Rx Clock Source is BRG2 */ +#define CMXSCR_RS4CS_BRG3 0x00000010 /* SCC4 Rx Clock Source is BRG3 */ +#define CMXSCR_RS4CS_BRG4 0x00000018 /* SCC4 Rx Clock Source is BRG4 */ +#define CMXSCR_RS4CS_CLK5 0x00000020 /* SCC4 Rx Clock Source is CLK5 */ +#define CMXSCR_RS4CS_CLK6 0x00000028 /* SCC4 Rx Clock Source is CLK6 */ +#define CMXSCR_RS4CS_CLK7 0x00000030 /* SCC4 Rx Clock Source is CLK7 */ +#define CMXSCR_RS4CS_CLK8 0x00000038 /* SCC4 Rx Clock Source is CLK8 */ + +#define CMXSCR_TS4CS_BRG1 0x00000000 /* SCC4 Tx Clock Source is BRG1 */ +#define CMXSCR_TS4CS_BRG2 0x00000001 /* SCC4 Tx Clock Source is BRG2 */ +#define CMXSCR_TS4CS_BRG3 0x00000002 /* SCC4 Tx Clock Source is BRG3 */ +#define CMXSCR_TS4CS_BRG4 0x00000003 /* SCC4 Tx Clock Source is BRG4 */ +#define CMXSCR_TS4CS_CLK5 0x00000004 /* SCC4 Tx Clock Source is CLK5 */ +#define CMXSCR_TS4CS_CLK6 0x00000005 /* SCC4 Tx Clock Source is CLK6 */ +#define CMXSCR_TS4CS_CLK7 0x00000006 /* SCC4 Tx Clock Source is CLK7 */ +#define CMXSCR_TS4CS_CLK8 0x00000007 /* SCC4 Tx Clock Source is CLK8 */ + +/*----------------------------------------------------------------------- + * SIUMCR - SIU Module Configuration Register 4-31 + */ +#define SIUMCR_BBD 0x80000000 /* Bus Busy Disable */ +#define SIUMCR_ESE 0x40000000 /* External Snoop Enable */ +#define SIUMCR_PBSE 0x20000000 /* Parity Byte Select Enable */ +#define SIUMCR_CDIS 0x10000000 /* Core Disable */ +#define SIUMCR_DPPC00 0x00000000 /* Data Parity Pins Configuration*/ +#define SIUMCR_DPPC01 0x04000000 /* - " - */ +#define SIUMCR_DPPC10 0x08000000 /* - " - */ +#define SIUMCR_DPPC11 0x0c000000 /* - " - */ +#define SIUMCR_L2CPC00 0x00000000 /* L2 Cache Pins Configuration */ +#define SIUMCR_L2CPC01 0x01000000 /* - " - */ +#define SIUMCR_L2CPC10 0x02000000 /* - " - */ +#define SIUMCR_L2CPC11 0x03000000 /* - " - */ +#define SIUMCR_LBPC00 0x00000000 /* Local Bus Pins Configuration */ +#define SIUMCR_LBPC01 0x00400000 /* - " - */ +#define SIUMCR_LBPC10 0x00800000 /* - " - */ +#define SIUMCR_LBPC11 0x00c00000 /* - " - */ +#define SIUMCR_APPC00 0x00000000 /* Address Parity Pins Configuration*/ +#define SIUMCR_APPC01 0x00100000 /* - " - */ +#define SIUMCR_APPC10 0x00200000 /* - " - */ +#define SIUMCR_APPC11 0x00300000 /* - " - */ +#define SIUMCR_CS10PC00 0x00000000 /* CS10 Pin Configuration */ +#define SIUMCR_CS10PC01 0x00040000 /* - " - */ +#define SIUMCR_CS10PC10 0x00080000 /* - " - */ +#define SIUMCR_CS10PC11 0x000c0000 /* - " - */ +#define SIUMCR_BCTLC00 0x00000000 /* Buffer Control Configuration */ +#define SIUMCR_BCTLC01 0x00010000 /* - " - */ +#define SIUMCR_BCTLC10 0x00020000 /* - " - */ +#define SIUMCR_BCTLC11 0x00030000 /* - " - */ +#define SIUMCR_MMR00 0x00000000 /* Mask Masters Requests */ +#define SIUMCR_MMR01 0x00004000 /* - " - */ +#define SIUMCR_MMR10 0x00008000 /* - " - */ +#define SIUMCR_MMR11 0x0000c000 /* - " - */ +#define SIUMCR_LPBSE 0x00002000 /* LocalBus Parity Byte Select Enable*/ + +/*----------------------------------------------------------------------- + * SCCR - System Clock Control Register 9-8 +*/ +#define SCCR_PCI_MODE 0x00000100 /* PCI Mode */ +#define SCCR_PCI_MODCK 0x00000080 /* Value of PCI_MODCK pin */ +#define SCCR_PCIDF_MSK 0x00000078 /* PCI division factor */ +#define SCCR_PCIDF_SHIFT 3 + +#ifndef CPM_IMMR_OFFSET +#define CPM_IMMR_OFFSET 0x101a8 +#endif + +#define FCC_PSMR_RMII ((uint)0x00020000) /* Use RMII interface */ + +/* FCC iop & clock configuration. BSP code is responsible to define Fx_RXCLK & Fx_TXCLK + * in order to use clock-computing stuff below for the FCC x + */ + +/* Automatically generates register configurations */ +#define PC_CLK(x) ((uint)(1<<(x-1))) /* FCC CLK I/O ports */ + +#define CMXFCR_RF1CS(x) ((uint)((x-5)<<27)) /* FCC1 Receive Clock Source */ +#define CMXFCR_TF1CS(x) ((uint)((x-5)<<24)) /* FCC1 Transmit Clock Source */ +#define CMXFCR_RF2CS(x) ((uint)((x-9)<<19)) /* FCC2 Receive Clock Source */ +#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16)) /* FCC2 Transmit Clock Source */ +#define CMXFCR_RF3CS(x) ((uint)((x-9)<<11)) /* FCC3 Receive Clock Source */ +#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8)) /* FCC3 Transmit Clock Source */ + +#define PC_F1RXCLK PC_CLK(F1_RXCLK) +#define PC_F1TXCLK PC_CLK(F1_TXCLK) +#define CMX1_CLK_ROUTE (CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK)) +#define CMX1_CLK_MASK ((uint)0xff000000) + +#define PC_F2RXCLK PC_CLK(F2_RXCLK) +#define PC_F2TXCLK PC_CLK(F2_TXCLK) +#define CMX2_CLK_ROUTE (CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK)) +#define CMX2_CLK_MASK ((uint)0x00ff0000) + +#define PC_F3RXCLK PC_CLK(F3_RXCLK) +#define PC_F3TXCLK PC_CLK(F3_TXCLK) +#define CMX3_CLK_ROUTE (CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK)) +#define CMX3_CLK_MASK ((uint)0x0000ff00) + +#define CPMUX_CLK_MASK (CMX3_CLK_MASK | CMX2_CLK_MASK) +#define CPMUX_CLK_ROUTE (CMX3_CLK_ROUTE | CMX2_CLK_ROUTE) + +#define CLK_TRX (PC_F3TXCLK | PC_F3RXCLK | PC_F2TXCLK | PC_F2RXCLK) + +/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PA1_COL 0x00000001U +#define PA1_CRS 0x00000002U +#define PA1_TXER 0x00000004U +#define PA1_TXEN 0x00000008U +#define PA1_RXDV 0x00000010U +#define PA1_RXER 0x00000020U +#define PA1_TXDAT 0x00003c00U +#define PA1_RXDAT 0x0003c000U +#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) +#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ + PA1_RXDV | PA1_RXER) +#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) +#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) + + +/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB2_TXER 0x00000001U +#define PB2_RXDV 0x00000002U +#define PB2_TXEN 0x00000004U +#define PB2_RXER 0x00000008U +#define PB2_COL 0x00000010U +#define PB2_CRS 0x00000020U +#define PB2_TXDAT 0x000003c0U +#define PB2_RXDAT 0x00003c00U +#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ + PB2_RXER | PB2_RXDV | PB2_TXER) +#define PB2_PSORB1 (PB2_TXEN) +#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) +#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) + + +/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB3_RXDV 0x00004000U +#define PB3_RXER 0x00008000U +#define PB3_TXER 0x00010000U +#define PB3_TXEN 0x00020000U +#define PB3_COL 0x00040000U +#define PB3_CRS 0x00080000U +#define PB3_TXDAT 0x0f000000U +#define PC3_TXDAT 0x00000010U +#define PB3_RXDAT 0x00f00000U +#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ + PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) +#define PB3_PSORB1 0 +#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) +#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) +#define PC3_DIRC1 (PC3_TXDAT) + +/* Handy macro to specify mem for FCCs*/ +#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128)) +#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0) +#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1) +#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2) + +/* Clocks and GRG's */ + +enum cpm_clk_dir { + CPM_CLK_RX, + CPM_CLK_TX, + CPM_CLK_RTX +}; + +enum cpm_clk_target { + CPM_CLK_SCC1, + CPM_CLK_SCC2, + CPM_CLK_SCC3, + CPM_CLK_SCC4, + CPM_CLK_FCC1, + CPM_CLK_FCC2, + CPM_CLK_FCC3 +}; + +enum cpm_clk { + CPM_CLK_NONE = 0, + CPM_BRG1, /* Baud Rate Generator 1 */ + CPM_BRG2, /* Baud Rate Generator 2 */ + CPM_BRG3, /* Baud Rate Generator 3 */ + CPM_BRG4, /* Baud Rate Generator 4 */ + CPM_BRG5, /* Baud Rate Generator 5 */ + CPM_BRG6, /* Baud Rate Generator 6 */ + CPM_BRG7, /* Baud Rate Generator 7 */ + CPM_BRG8, /* Baud Rate Generator 8 */ + CPM_CLK1, /* Clock 1 */ + CPM_CLK2, /* Clock 2 */ + CPM_CLK3, /* Clock 3 */ + CPM_CLK4, /* Clock 4 */ + CPM_CLK5, /* Clock 5 */ + CPM_CLK6, /* Clock 6 */ + CPM_CLK7, /* Clock 7 */ + CPM_CLK8, /* Clock 8 */ + CPM_CLK9, /* Clock 9 */ + CPM_CLK10, /* Clock 10 */ + CPM_CLK11, /* Clock 11 */ + CPM_CLK12, /* Clock 12 */ + CPM_CLK13, /* Clock 13 */ + CPM_CLK14, /* Clock 14 */ + CPM_CLK15, /* Clock 15 */ + CPM_CLK16, /* Clock 16 */ + CPM_CLK17, /* Clock 17 */ + CPM_CLK18, /* Clock 18 */ + CPM_CLK19, /* Clock 19 */ + CPM_CLK20, /* Clock 20 */ + CPM_CLK_DUMMY +}; + +extern int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode); + +#endif /* __CPM2__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/highmem.h b/include/asm-powerpc/highmem.h new file mode 100644 index 000000000000..f7b21ee302b4 --- /dev/null +++ b/include/asm-powerpc/highmem.h @@ -0,0 +1,135 @@ +/* + * highmem.h: virtual kernel memory mappings for high memory + * + * PowerPC version, stolen from the i386 version. + * + * Used in CONFIG_HIGHMEM systems for memory pages which + * are not addressable by direct kernel virtual addresses. + * + * Copyright (C) 1999 Gerhard Wichert, Siemens AG + * Gerhard.Wichert@pdb.siemens.de + * + * + * Redesigned the x86 32-bit VM architecture to deal with + * up to 16 Terrabyte physical memory. With current x86 CPUs + * we now support up to 64 Gigabytes physical RAM. + * + * Copyright (C) 1999 Ingo Molnar + */ + +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include + +/* undef for production */ +#define HIGHMEM_DEBUG 1 + +extern pte_t *kmap_pte; +extern pgprot_t kmap_prot; +extern pte_t *pkmap_page_table; + +/* + * Right now we initialize only a single pte table. It can be extended + * easily, subsequent pte tables have to be allocated in one physical + * chunk of RAM. + */ +#define PKMAP_BASE CONFIG_HIGHMEM_START +#define LAST_PKMAP (1 << PTE_SHIFT) +#define LAST_PKMAP_MASK (LAST_PKMAP-1) +#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +#define KMAP_FIX_BEGIN (PKMAP_BASE + 0x00400000UL) + +extern void *kmap_high(struct page *page); +extern void kunmap_high(struct page *page); + +static inline void *kmap(struct page *page) +{ + might_sleep(); + if (!PageHighMem(page)) + return page_address(page); + return kmap_high(page); +} + +static inline void kunmap(struct page *page) +{ + BUG_ON(in_interrupt()); + if (!PageHighMem(page)) + return; + kunmap_high(page); +} + +/* + * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap + * gives a more generic (and caching) interface. But kmap_atomic can + * be used in IRQ contexts, so in some (very limited) cases we need + * it. + */ +static inline void *kmap_atomic(struct page *page, enum km_type type) +{ + unsigned int idx; + unsigned long vaddr; + + /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = KMAP_FIX_BEGIN + idx * PAGE_SIZE; +#ifdef HIGHMEM_DEBUG + BUG_ON(!pte_none(*(kmap_pte+idx))); +#endif + set_pte_at(&init_mm, vaddr, kmap_pte+idx, mk_pte(page, kmap_prot)); + flush_tlb_page(NULL, vaddr); + + return (void*) vaddr; +} + +static inline void kunmap_atomic(void *kvaddr, enum km_type type) +{ +#ifdef HIGHMEM_DEBUG + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + unsigned int idx = type + KM_TYPE_NR*smp_processor_id(); + + if (vaddr < KMAP_FIX_BEGIN) { // FIXME + pagefault_enable(); + return; + } + + BUG_ON(vaddr != KMAP_FIX_BEGIN + idx * PAGE_SIZE); + + /* + * force other mappings to Oops if they'll try to access + * this pte without first remap it + */ + pte_clear(&init_mm, vaddr, kmap_pte+idx); + flush_tlb_page(NULL, vaddr); +#endif + pagefault_enable(); +} + +static inline struct page *kmap_atomic_to_page(void *ptr) +{ + unsigned long idx, vaddr = (unsigned long) ptr; + + if (vaddr < KMAP_FIX_BEGIN) + return virt_to_page(ptr); + + idx = (vaddr - KMAP_FIX_BEGIN) >> PAGE_SHIFT; + return pte_page(kmap_pte[idx]); +} + +#define flush_cache_kmaps() flush_cache_all() + +#endif /* __KERNEL__ */ + +#endif /* _ASM_HIGHMEM_H */ diff --git a/include/asm-powerpc/hydra.h b/include/asm-powerpc/hydra.h new file mode 100644 index 000000000000..1ad4eed07fbe --- /dev/null +++ b/include/asm-powerpc/hydra.h @@ -0,0 +1,102 @@ +/* + * include/asm-ppc/hydra.h -- Mac I/O `Hydra' definitions + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is based on the following documentation: + * + * Macintosh Technology in the Common Hardware Reference Platform + * Apple Computer, Inc. + * + * ยฉ Copyright 1995 Apple Computer, Inc. All rights reserved. + * + * It's available online from http://chrp.apple.com/MacTech.pdf. + * You can obtain paper copies of this book from computer bookstores or by + * writing Morgan Kaufmann Publishers, Inc., 340 Pine Street, Sixth Floor, San + * Francisco, CA 94104. Reference ISBN 1-55860-393-X. + * + * 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. + */ + +#ifndef _ASMPPC_HYDRA_H +#define _ASMPPC_HYDRA_H + +#ifdef __KERNEL__ + +struct Hydra { + /* DBDMA Controller Register Space */ + char Pad1[0x30]; + u_int CachePD; + u_int IDs; + u_int Feature_Control; + char Pad2[0x7fc4]; + /* DBDMA Channel Register Space */ + char SCSI_DMA[0x100]; + char Pad3[0x300]; + char SCCA_Tx_DMA[0x100]; + char SCCA_Rx_DMA[0x100]; + char SCCB_Tx_DMA[0x100]; + char SCCB_Rx_DMA[0x100]; + char Pad4[0x7800]; + /* Device Register Space */ + char SCSI[0x1000]; + char ADB[0x1000]; + char SCC_Legacy[0x1000]; + char SCC[0x1000]; + char Pad9[0x2000]; + char VIA[0x2000]; + char Pad10[0x28000]; + char OpenPIC[0x40000]; +}; + +extern volatile struct Hydra __iomem *Hydra; + + + /* + * Feature Control Register + */ + +#define HYDRA_FC_SCC_CELL_EN 0x00000001 /* Enable SCC Clock */ +#define HYDRA_FC_SCSI_CELL_EN 0x00000002 /* Enable SCSI Clock */ +#define HYDRA_FC_SCCA_ENABLE 0x00000004 /* Enable SCC A Lines */ +#define HYDRA_FC_SCCB_ENABLE 0x00000008 /* Enable SCC B Lines */ +#define HYDRA_FC_ARB_BYPASS 0x00000010 /* Bypass Internal Arbiter */ +#define HYDRA_FC_RESET_SCC 0x00000020 /* Reset SCC */ +#define HYDRA_FC_MPIC_ENABLE 0x00000040 /* Enable OpenPIC */ +#define HYDRA_FC_SLOW_SCC_PCLK 0x00000080 /* 1=15.6672, 0=25 MHz */ +#define HYDRA_FC_MPIC_IS_MASTER 0x00000100 /* OpenPIC Master Mode */ + + + /* + * OpenPIC Interrupt Sources + */ + +#define HYDRA_INT_SIO 0 +#define HYDRA_INT_SCSI_DMA 1 +#define HYDRA_INT_SCCA_TX_DMA 2 +#define HYDRA_INT_SCCA_RX_DMA 3 +#define HYDRA_INT_SCCB_TX_DMA 4 +#define HYDRA_INT_SCCB_RX_DMA 5 +#define HYDRA_INT_SCSI 6 +#define HYDRA_INT_SCCA 7 +#define HYDRA_INT_SCCB 8 +#define HYDRA_INT_VIA 9 +#define HYDRA_INT_ADB 10 +#define HYDRA_INT_ADB_NMI 11 +#define HYDRA_INT_EXT1 12 /* PCI IRQW */ +#define HYDRA_INT_EXT2 13 /* PCI IRQX */ +#define HYDRA_INT_EXT3 14 /* PCI IRQY */ +#define HYDRA_INT_EXT4 15 /* PCI IRQZ */ +#define HYDRA_INT_EXT5 16 /* IDE Primay/Secondary */ +#define HYDRA_INT_EXT6 17 /* IDE Secondary */ +#define HYDRA_INT_EXT7 18 /* Power Off Request */ +#define HYDRA_INT_SPARE 19 + +extern int hydra_init(void); +extern void macio_adb_init(void); + +#endif /* __KERNEL__ */ + +#endif /* _ASMPPC_HYDRA_H */ diff --git a/include/asm-powerpc/immap_cpm2.h b/include/asm-powerpc/immap_cpm2.h new file mode 100644 index 000000000000..f316a91c628a --- /dev/null +++ b/include/asm-powerpc/immap_cpm2.h @@ -0,0 +1,648 @@ +/* + * CPM2 Internal Memory Map + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * + * The Internal Memory Map for devices with CPM2 on them. This + * is the superset of all CPM2 devices (8260, 8266, 8280, 8272, + * 8560). + */ +#ifdef __KERNEL__ +#ifndef __IMMAP_CPM2__ +#define __IMMAP_CPM2__ + +/* System configuration registers. +*/ +typedef struct sys_82xx_conf { + u32 sc_siumcr; + u32 sc_sypcr; + u8 res1[6]; + u16 sc_swsr; + u8 res2[20]; + u32 sc_bcr; + u8 sc_ppc_acr; + u8 res3[3]; + u32 sc_ppc_alrh; + u32 sc_ppc_alrl; + u8 sc_lcl_acr; + u8 res4[3]; + u32 sc_lcl_alrh; + u32 sc_lcl_alrl; + u32 sc_tescr1; + u32 sc_tescr2; + u32 sc_ltescr1; + u32 sc_ltescr2; + u32 sc_pdtea; + u8 sc_pdtem; + u8 res5[3]; + u32 sc_ldtea; + u8 sc_ldtem; + u8 res6[163]; +} sysconf_82xx_cpm2_t; + +typedef struct sys_85xx_conf { + u32 sc_cear; + u16 sc_ceer; + u16 sc_cemr; + u8 res1[70]; + u32 sc_smaer; + u8 res2[4]; + u32 sc_smevr; + u32 sc_smctr; + u32 sc_lmaer; + u8 res3[4]; + u32 sc_lmevr; + u32 sc_lmctr; + u8 res4[144]; +} sysconf_85xx_cpm2_t; + +typedef union sys_conf { + sysconf_82xx_cpm2_t siu_82xx; + sysconf_85xx_cpm2_t siu_85xx; +} sysconf_cpm2_t; + + + +/* Memory controller registers. +*/ +typedef struct mem_ctlr { + u32 memc_br0; + u32 memc_or0; + u32 memc_br1; + u32 memc_or1; + u32 memc_br2; + u32 memc_or2; + u32 memc_br3; + u32 memc_or3; + u32 memc_br4; + u32 memc_or4; + u32 memc_br5; + u32 memc_or5; + u32 memc_br6; + u32 memc_or6; + u32 memc_br7; + u32 memc_or7; + u32 memc_br8; + u32 memc_or8; + u32 memc_br9; + u32 memc_or9; + u32 memc_br10; + u32 memc_or10; + u32 memc_br11; + u32 memc_or11; + u8 res1[8]; + u32 memc_mar; + u8 res2[4]; + u32 memc_mamr; + u32 memc_mbmr; + u32 memc_mcmr; + u8 res3[8]; + u16 memc_mptpr; + u8 res4[2]; + u32 memc_mdr; + u8 res5[4]; + u32 memc_psdmr; + u32 memc_lsdmr; + u8 memc_purt; + u8 res6[3]; + u8 memc_psrt; + u8 res7[3]; + u8 memc_lurt; + u8 res8[3]; + u8 memc_lsrt; + u8 res9[3]; + u32 memc_immr; + u32 memc_pcibr0; + u32 memc_pcibr1; + u8 res10[16]; + u32 memc_pcimsk0; + u32 memc_pcimsk1; + u8 res11[52]; +} memctl_cpm2_t; + +/* System Integration Timers. +*/ +typedef struct sys_int_timers { + u8 res1[32]; + u16 sit_tmcntsc; + u8 res2[2]; + u32 sit_tmcnt; + u8 res3[4]; + u32 sit_tmcntal; + u8 res4[16]; + u16 sit_piscr; + u8 res5[2]; + u32 sit_pitc; + u32 sit_pitr; + u8 res6[94]; + u8 res7[390]; +} sit_cpm2_t; + +#define PISCR_PIRQ_MASK ((u16)0xff00) +#define PISCR_PS ((u16)0x0080) +#define PISCR_PIE ((u16)0x0004) +#define PISCR_PTF ((u16)0x0002) +#define PISCR_PTE ((u16)0x0001) + +/* PCI Controller. +*/ +typedef struct pci_ctlr { + u32 pci_omisr; + u32 pci_omimr; + u8 res1[8]; + u32 pci_ifqpr; + u32 pci_ofqpr; + u8 res2[8]; + u32 pci_imr0; + u32 pci_imr1; + u32 pci_omr0; + u32 pci_omr1; + u32 pci_odr; + u8 res3[4]; + u32 pci_idr; + u8 res4[20]; + u32 pci_imisr; + u32 pci_imimr; + u8 res5[24]; + u32 pci_ifhpr; + u8 res6[4]; + u32 pci_iftpr; + u8 res7[4]; + u32 pci_iphpr; + u8 res8[4]; + u32 pci_iptpr; + u8 res9[4]; + u32 pci_ofhpr; + u8 res10[4]; + u32 pci_oftpr; + u8 res11[4]; + u32 pci_ophpr; + u8 res12[4]; + u32 pci_optpr; + u8 res13[8]; + u32 pci_mucr; + u8 res14[8]; + u32 pci_qbar; + u8 res15[12]; + u32 pci_dmamr0; + u32 pci_dmasr0; + u32 pci_dmacdar0; + u8 res16[4]; + u32 pci_dmasar0; + u8 res17[4]; + u32 pci_dmadar0; + u8 res18[4]; + u32 pci_dmabcr0; + u32 pci_dmandar0; + u8 res19[86]; + u32 pci_dmamr1; + u32 pci_dmasr1; + u32 pci_dmacdar1; + u8 res20[4]; + u32 pci_dmasar1; + u8 res21[4]; + u32 pci_dmadar1; + u8 res22[4]; + u32 pci_dmabcr1; + u32 pci_dmandar1; + u8 res23[88]; + u32 pci_dmamr2; + u32 pci_dmasr2; + u32 pci_dmacdar2; + u8 res24[4]; + u32 pci_dmasar2; + u8 res25[4]; + u32 pci_dmadar2; + u8 res26[4]; + u32 pci_dmabcr2; + u32 pci_dmandar2; + u8 res27[88]; + u32 pci_dmamr3; + u32 pci_dmasr3; + u32 pci_dmacdar3; + u8 res28[4]; + u32 pci_dmasar3; + u8 res29[4]; + u32 pci_dmadar3; + u8 res30[4]; + u32 pci_dmabcr3; + u32 pci_dmandar3; + u8 res31[344]; + u32 pci_potar0; + u8 res32[4]; + u32 pci_pobar0; + u8 res33[4]; + u32 pci_pocmr0; + u8 res34[4]; + u32 pci_potar1; + u8 res35[4]; + u32 pci_pobar1; + u8 res36[4]; + u32 pci_pocmr1; + u8 res37[4]; + u32 pci_potar2; + u8 res38[4]; + u32 pci_pobar2; + u8 res39[4]; + u32 pci_pocmr2; + u8 res40[50]; + u32 pci_ptcr; + u32 pci_gpcr; + u32 pci_gcr; + u32 pci_esr; + u32 pci_emr; + u32 pci_ecr; + u32 pci_eacr; + u8 res41[4]; + u32 pci_edcr; + u8 res42[4]; + u32 pci_eccr; + u8 res43[44]; + u32 pci_pitar1; + u8 res44[4]; + u32 pci_pibar1; + u8 res45[4]; + u32 pci_picmr1; + u8 res46[4]; + u32 pci_pitar0; + u8 res47[4]; + u32 pci_pibar0; + u8 res48[4]; + u32 pci_picmr0; + u8 res49[4]; + u32 pci_cfg_addr; + u32 pci_cfg_data; + u32 pci_int_ack; + u8 res50[756]; +} pci_cpm2_t; + +/* Interrupt Controller. +*/ +typedef struct interrupt_controller { + u16 ic_sicr; + u8 res1[2]; + u32 ic_sivec; + u32 ic_sipnrh; + u32 ic_sipnrl; + u32 ic_siprr; + u32 ic_scprrh; + u32 ic_scprrl; + u32 ic_simrh; + u32 ic_simrl; + u32 ic_siexr; + u8 res2[88]; +} intctl_cpm2_t; + +/* Clocks and Reset. +*/ +typedef struct clk_and_reset { + u32 car_sccr; + u8 res1[4]; + u32 car_scmr; + u8 res2[4]; + u32 car_rsr; + u32 car_rmr; + u8 res[104]; +} car_cpm2_t; + +/* Input/Output Port control/status registers. + * Names consistent with processor manual, although they are different + * from the original 8xx names....... + */ +typedef struct io_port { + u32 iop_pdira; + u32 iop_ppara; + u32 iop_psora; + u32 iop_podra; + u32 iop_pdata; + u8 res1[12]; + u32 iop_pdirb; + u32 iop_pparb; + u32 iop_psorb; + u32 iop_podrb; + u32 iop_pdatb; + u8 res2[12]; + u32 iop_pdirc; + u32 iop_pparc; + u32 iop_psorc; + u32 iop_podrc; + u32 iop_pdatc; + u8 res3[12]; + u32 iop_pdird; + u32 iop_ppard; + u32 iop_psord; + u32 iop_podrd; + u32 iop_pdatd; + u8 res4[12]; +} iop_cpm2_t; + +/* Communication Processor Module Timers +*/ +typedef struct cpm_timers { + u8 cpmt_tgcr1; + u8 res1[3]; + u8 cpmt_tgcr2; + u8 res2[11]; + u16 cpmt_tmr1; + u16 cpmt_tmr2; + u16 cpmt_trr1; + u16 cpmt_trr2; + u16 cpmt_tcr1; + u16 cpmt_tcr2; + u16 cpmt_tcn1; + u16 cpmt_tcn2; + u16 cpmt_tmr3; + u16 cpmt_tmr4; + u16 cpmt_trr3; + u16 cpmt_trr4; + u16 cpmt_tcr3; + u16 cpmt_tcr4; + u16 cpmt_tcn3; + u16 cpmt_tcn4; + u16 cpmt_ter1; + u16 cpmt_ter2; + u16 cpmt_ter3; + u16 cpmt_ter4; + u8 res3[584]; +} cpmtimer_cpm2_t; + +/* DMA control/status registers. +*/ +typedef struct sdma_csr { + u8 res0[24]; + u8 sdma_sdsr; + u8 res1[3]; + u8 sdma_sdmr; + u8 res2[3]; + u8 sdma_idsr1; + u8 res3[3]; + u8 sdma_idmr1; + u8 res4[3]; + u8 sdma_idsr2; + u8 res5[3]; + u8 sdma_idmr2; + u8 res6[3]; + u8 sdma_idsr3; + u8 res7[3]; + u8 sdma_idmr3; + u8 res8[3]; + u8 sdma_idsr4; + u8 res9[3]; + u8 sdma_idmr4; + u8 res10[707]; +} sdma_cpm2_t; + +/* Fast controllers +*/ +typedef struct fcc { + u32 fcc_gfmr; + u32 fcc_fpsmr; + u16 fcc_ftodr; + u8 res1[2]; + u16 fcc_fdsr; + u8 res2[2]; + u16 fcc_fcce; + u8 res3[2]; + u16 fcc_fccm; + u8 res4[2]; + u8 fcc_fccs; + u8 res5[3]; + u8 fcc_ftirr_phy[4]; +} fcc_t; + +/* Fast controllers continued + */ +typedef struct fcc_c { + u32 fcc_firper; + u32 fcc_firer; + u32 fcc_firsr_hi; + u32 fcc_firsr_lo; + u8 fcc_gfemr; + u8 res1[15]; +} fcc_c_t; + +/* TC Layer + */ +typedef struct tclayer { + u16 tc_tcmode; + u16 tc_cdsmr; + u16 tc_tcer; + u16 tc_rcc; + u16 tc_tcmr; + u16 tc_fcc; + u16 tc_ccc; + u16 tc_icc; + u16 tc_tcc; + u16 tc_ecc; + u8 res1[12]; +} tclayer_t; + + +/* I2C +*/ +typedef struct i2c { + u8 i2c_i2mod; + u8 res1[3]; + u8 i2c_i2add; + u8 res2[3]; + u8 i2c_i2brg; + u8 res3[3]; + u8 i2c_i2com; + u8 res4[3]; + u8 i2c_i2cer; + u8 res5[3]; + u8 i2c_i2cmr; + u8 res6[331]; +} i2c_cpm2_t; + +typedef struct scc { /* Serial communication channels */ + u32 scc_gsmrl; + u32 scc_gsmrh; + u16 scc_psmr; + u8 res1[2]; + u16 scc_todr; + u16 scc_dsr; + u16 scc_scce; + u8 res2[2]; + u16 scc_sccm; + u8 res3; + u8 scc_sccs; + u8 res4[8]; +} scc_t; + +typedef struct smc { /* Serial management channels */ + u8 res1[2]; + u16 smc_smcmr; + u8 res2[2]; + u8 smc_smce; + u8 res3[3]; + u8 smc_smcm; + u8 res4[5]; +} smc_t; + +/* Serial Peripheral Interface. +*/ +typedef struct spi_ctrl { + u16 spi_spmode; + u8 res1[4]; + u8 spi_spie; + u8 res2[3]; + u8 spi_spim; + u8 res3[2]; + u8 spi_spcom; + u8 res4[82]; +} spictl_cpm2_t; + +/* CPM Mux. +*/ +typedef struct cpmux { + u8 cmx_si1cr; + u8 res1; + u8 cmx_si2cr; + u8 res2; + u32 cmx_fcr; + u32 cmx_scr; + u8 cmx_smr; + u8 res3; + u16 cmx_uar; + u8 res4[16]; +} cpmux_t; + +/* SIRAM control +*/ +typedef struct siram { + u16 si_amr; + u16 si_bmr; + u16 si_cmr; + u16 si_dmr; + u8 si_gmr; + u8 res1; + u8 si_cmdr; + u8 res2; + u8 si_str; + u8 res3; + u16 si_rsr; +} siramctl_t; + +typedef struct mcc { + u16 mcc_mcce; + u8 res1[2]; + u16 mcc_mccm; + u8 res2[2]; + u8 mcc_mccf; + u8 res3[7]; +} mcc_t; + +typedef struct comm_proc { + u32 cp_cpcr; + u32 cp_rccr; + u8 res1[14]; + u16 cp_rter; + u8 res2[2]; + u16 cp_rtmr; + u16 cp_rtscr; + u8 res3[2]; + u32 cp_rtsr; + u8 res4[12]; +} cpm_cpm2_t; + +/* USB Controller. +*/ +typedef struct usb_ctlr { + u8 usb_usmod; + u8 usb_usadr; + u8 usb_uscom; + u8 res1[1]; + u16 usb_usep1; + u16 usb_usep2; + u16 usb_usep3; + u16 usb_usep4; + u8 res2[4]; + u16 usb_usber; + u8 res3[2]; + u16 usb_usbmr; + u8 usb_usbs; + u8 res4[7]; +} usb_cpm2_t; + +/* ...and the whole thing wrapped up.... +*/ + +typedef struct immap { + /* Some references are into the unique and known dpram spaces, + * others are from the generic base. + */ +#define im_dprambase im_dpram1 + u8 im_dpram1[16*1024]; + u8 res1[16*1024]; + u8 im_dpram2[4*1024]; + u8 res2[8*1024]; + u8 im_dpram3[4*1024]; + u8 res3[16*1024]; + + sysconf_cpm2_t im_siu_conf; /* SIU Configuration */ + memctl_cpm2_t im_memctl; /* Memory Controller */ + sit_cpm2_t im_sit; /* System Integration Timers */ + pci_cpm2_t im_pci; /* PCI Controller */ + intctl_cpm2_t im_intctl; /* Interrupt Controller */ + car_cpm2_t im_clkrst; /* Clocks and reset */ + iop_cpm2_t im_ioport; /* IO Port control/status */ + cpmtimer_cpm2_t im_cpmtimer; /* CPM timers */ + sdma_cpm2_t im_sdma; /* SDMA control/status */ + + fcc_t im_fcc[3]; /* Three FCCs */ + u8 res4z[32]; + fcc_c_t im_fcc_c[3]; /* Continued FCCs */ + + u8 res4[32]; + + tclayer_t im_tclayer[8]; /* Eight TCLayers */ + u16 tc_tcgsr; + u16 tc_tcger; + + /* First set of baud rate generators. + */ + u8 res[236]; + u32 im_brgc5; + u32 im_brgc6; + u32 im_brgc7; + u32 im_brgc8; + + u8 res5[608]; + + i2c_cpm2_t im_i2c; /* I2C control/status */ + cpm_cpm2_t im_cpm; /* Communication processor */ + + /* Second set of baud rate generators. + */ + u32 im_brgc1; + u32 im_brgc2; + u32 im_brgc3; + u32 im_brgc4; + + scc_t im_scc[4]; /* Four SCCs */ + smc_t im_smc[2]; /* Couple of SMCs */ + spictl_cpm2_t im_spi; /* A SPI */ + cpmux_t im_cpmux; /* CPM clock route mux */ + siramctl_t im_siramctl1; /* First SI RAM Control */ + mcc_t im_mcc1; /* First MCC */ + siramctl_t im_siramctl2; /* Second SI RAM Control */ + mcc_t im_mcc2; /* Second MCC */ + usb_cpm2_t im_usb; /* USB Controller */ + + u8 res6[1153]; + + u16 im_si1txram[256]; + u8 res7[512]; + u16 im_si1rxram[256]; + u8 res8[512]; + u16 im_si2txram[256]; + u8 res9[512]; + u16 im_si2rxram[256]; + u8 res10[512]; + u8 res11[4096]; +} cpm2_map_t; + +extern cpm2_map_t *cpm2_immr; + +#endif /* __IMMAP_CPM2__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/kgdb.h b/include/asm-powerpc/kgdb.h new file mode 100644 index 000000000000..b617dac82969 --- /dev/null +++ b/include/asm-powerpc/kgdb.h @@ -0,0 +1,57 @@ +/* + * kgdb.h: Defines and declarations for serial line source level + * remote debugging of the Linux kernel using gdb. + * + * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu) + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ +#ifdef __KERNEL__ +#ifndef _PPC_KGDB_H +#define _PPC_KGDB_H + +#ifndef __ASSEMBLY__ + +/* Things specific to the gen550 backend. */ +struct uart_port; + +extern void gen550_progress(char *, unsigned short); +extern void gen550_kgdb_map_scc(void); +extern void gen550_init(int, struct uart_port *); + +/* Things specific to the pmac backend. */ +extern void zs_kgdb_hook(int tty_num); + +/* To init the kgdb engine. (called by serial hook)*/ +extern void set_debug_traps(void); + +/* To enter the debugger explicitly. */ +extern void breakpoint(void); + +/* For taking exceptions + * these are defined in traps.c + */ +extern int (*debugger)(struct pt_regs *regs); +extern int (*debugger_bpt)(struct pt_regs *regs); +extern int (*debugger_sstep)(struct pt_regs *regs); +extern int (*debugger_iabr_match)(struct pt_regs *regs); +extern int (*debugger_dabr_match)(struct pt_regs *regs); +extern void (*debugger_fault_handler)(struct pt_regs *regs); + +/* What we bring to the party */ +int kgdb_bpt(struct pt_regs *regs); +int kgdb_sstep(struct pt_regs *regs); +void kgdb(struct pt_regs *regs); +int kgdb_iabr_match(struct pt_regs *regs); +int kgdb_dabr_match(struct pt_regs *regs); + +/* + * external low-level support routines (ie macserial.c) + */ +extern void kgdb_interruptible(int); /* control interrupts from serial */ +extern void putDebugChar(char); /* write a single character */ +extern char getDebugChar(void); /* read and return a single char */ + +#endif /* !(__ASSEMBLY__) */ +#endif /* !(_PPC_KGDB_H) */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/mpc52xx_psc.h b/include/asm-powerpc/mpc52xx_psc.h new file mode 100644 index 000000000000..26690d2b32f5 --- /dev/null +++ b/include/asm-powerpc/mpc52xx_psc.h @@ -0,0 +1,191 @@ +/* + * include/asm-ppc/mpc52xx_psc.h + * + * Definitions of consts/structs to drive the Freescale MPC52xx OnChip + * PSCs. Theses are shared between multiple drivers since a PSC can be + * UART, AC97, IR, I2S, ... So this header is in asm-ppc. + * + * + * Maintainer : Sylvain Munaut + * + * Based/Extracted from some header of the 2.4 originally written by + * Dale Farnsworth + * + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __ASM_MPC52xx_PSC_H__ +#define __ASM_MPC52xx_PSC_H__ + +#include + +/* Max number of PSCs */ +#define MPC52xx_PSC_MAXNUM 6 + +/* Programmable Serial Controller (PSC) status register bits */ +#define MPC52xx_PSC_SR_CDE 0x0080 +#define MPC52xx_PSC_SR_RXRDY 0x0100 +#define MPC52xx_PSC_SR_RXFULL 0x0200 +#define MPC52xx_PSC_SR_TXRDY 0x0400 +#define MPC52xx_PSC_SR_TXEMP 0x0800 +#define MPC52xx_PSC_SR_OE 0x1000 +#define MPC52xx_PSC_SR_PE 0x2000 +#define MPC52xx_PSC_SR_FE 0x4000 +#define MPC52xx_PSC_SR_RB 0x8000 + +/* PSC Command values */ +#define MPC52xx_PSC_RX_ENABLE 0x0001 +#define MPC52xx_PSC_RX_DISABLE 0x0002 +#define MPC52xx_PSC_TX_ENABLE 0x0004 +#define MPC52xx_PSC_TX_DISABLE 0x0008 +#define MPC52xx_PSC_SEL_MODE_REG_1 0x0010 +#define MPC52xx_PSC_RST_RX 0x0020 +#define MPC52xx_PSC_RST_TX 0x0030 +#define MPC52xx_PSC_RST_ERR_STAT 0x0040 +#define MPC52xx_PSC_RST_BRK_CHG_INT 0x0050 +#define MPC52xx_PSC_START_BRK 0x0060 +#define MPC52xx_PSC_STOP_BRK 0x0070 + +/* PSC TxRx FIFO status bits */ +#define MPC52xx_PSC_RXTX_FIFO_ERR 0x0040 +#define MPC52xx_PSC_RXTX_FIFO_UF 0x0020 +#define MPC52xx_PSC_RXTX_FIFO_OF 0x0010 +#define MPC52xx_PSC_RXTX_FIFO_FR 0x0008 +#define MPC52xx_PSC_RXTX_FIFO_FULL 0x0004 +#define MPC52xx_PSC_RXTX_FIFO_ALARM 0x0002 +#define MPC52xx_PSC_RXTX_FIFO_EMPTY 0x0001 + +/* PSC interrupt mask bits */ +#define MPC52xx_PSC_IMR_TXRDY 0x0100 +#define MPC52xx_PSC_IMR_RXRDY 0x0200 +#define MPC52xx_PSC_IMR_DB 0x0400 +#define MPC52xx_PSC_IMR_IPC 0x8000 + +/* PSC input port change bit */ +#define MPC52xx_PSC_CTS 0x01 +#define MPC52xx_PSC_DCD 0x02 +#define MPC52xx_PSC_D_CTS 0x10 +#define MPC52xx_PSC_D_DCD 0x20 + +/* PSC mode fields */ +#define MPC52xx_PSC_MODE_5_BITS 0x00 +#define MPC52xx_PSC_MODE_6_BITS 0x01 +#define MPC52xx_PSC_MODE_7_BITS 0x02 +#define MPC52xx_PSC_MODE_8_BITS 0x03 +#define MPC52xx_PSC_MODE_BITS_MASK 0x03 +#define MPC52xx_PSC_MODE_PAREVEN 0x00 +#define MPC52xx_PSC_MODE_PARODD 0x04 +#define MPC52xx_PSC_MODE_PARFORCE 0x08 +#define MPC52xx_PSC_MODE_PARNONE 0x10 +#define MPC52xx_PSC_MODE_ERR 0x20 +#define MPC52xx_PSC_MODE_FFULL 0x40 +#define MPC52xx_PSC_MODE_RXRTS 0x80 + +#define MPC52xx_PSC_MODE_ONE_STOP_5_BITS 0x00 +#define MPC52xx_PSC_MODE_ONE_STOP 0x07 +#define MPC52xx_PSC_MODE_TWO_STOP 0x0f + +#define MPC52xx_PSC_RFNUM_MASK 0x01ff + + +/* Structure of the hardware registers */ +struct mpc52xx_psc { + u8 mode; /* PSC + 0x00 */ + u8 reserved0[3]; + union { /* PSC + 0x04 */ + u16 status; + u16 clock_select; + } sr_csr; +#define mpc52xx_psc_status sr_csr.status +#define mpc52xx_psc_clock_select sr_csr.clock_select + u16 reserved1; + u8 command; /* PSC + 0x08 */ + u8 reserved2[3]; + union { /* PSC + 0x0c */ + u8 buffer_8; + u16 buffer_16; + u32 buffer_32; + } buffer; +#define mpc52xx_psc_buffer_8 buffer.buffer_8 +#define mpc52xx_psc_buffer_16 buffer.buffer_16 +#define mpc52xx_psc_buffer_32 buffer.buffer_32 + union { /* PSC + 0x10 */ + u8 ipcr; + u8 acr; + } ipcr_acr; +#define mpc52xx_psc_ipcr ipcr_acr.ipcr +#define mpc52xx_psc_acr ipcr_acr.acr + u8 reserved3[3]; + union { /* PSC + 0x14 */ + u16 isr; + u16 imr; + } isr_imr; +#define mpc52xx_psc_isr isr_imr.isr +#define mpc52xx_psc_imr isr_imr.imr + u16 reserved4; + u8 ctur; /* PSC + 0x18 */ + u8 reserved5[3]; + u8 ctlr; /* PSC + 0x1c */ + u8 reserved6[3]; + u16 ccr; /* PSC + 0x20 */ + u8 reserved7[14]; + u8 ivr; /* PSC + 0x30 */ + u8 reserved8[3]; + u8 ip; /* PSC + 0x34 */ + u8 reserved9[3]; + u8 op1; /* PSC + 0x38 */ + u8 reserved10[3]; + u8 op0; /* PSC + 0x3c */ + u8 reserved11[3]; + u32 sicr; /* PSC + 0x40 */ + u8 ircr1; /* PSC + 0x44 */ + u8 reserved13[3]; + u8 ircr2; /* PSC + 0x44 */ + u8 reserved14[3]; + u8 irsdr; /* PSC + 0x4c */ + u8 reserved15[3]; + u8 irmdr; /* PSC + 0x50 */ + u8 reserved16[3]; + u8 irfdr; /* PSC + 0x54 */ + u8 reserved17[3]; + u16 rfnum; /* PSC + 0x58 */ + u16 reserved18; + u16 tfnum; /* PSC + 0x5c */ + u16 reserved19; + u32 rfdata; /* PSC + 0x60 */ + u16 rfstat; /* PSC + 0x64 */ + u16 reserved20; + u8 rfcntl; /* PSC + 0x68 */ + u8 reserved21[5]; + u16 rfalarm; /* PSC + 0x6e */ + u16 reserved22; + u16 rfrptr; /* PSC + 0x72 */ + u16 reserved23; + u16 rfwptr; /* PSC + 0x76 */ + u16 reserved24; + u16 rflrfptr; /* PSC + 0x7a */ + u16 reserved25; + u16 rflwfptr; /* PSC + 0x7e */ + u32 tfdata; /* PSC + 0x80 */ + u16 tfstat; /* PSC + 0x84 */ + u16 reserved26; + u8 tfcntl; /* PSC + 0x88 */ + u8 reserved27[5]; + u16 tfalarm; /* PSC + 0x8e */ + u16 reserved28; + u16 tfrptr; /* PSC + 0x92 */ + u16 reserved29; + u16 tfwptr; /* PSC + 0x96 */ + u16 reserved30; + u16 tflrfptr; /* PSC + 0x9a */ + u16 reserved31; + u16 tflwfptr; /* PSC + 0x9e */ +}; + + +#endif /* __ASM_MPC52xx_PSC_H__ */ From 2f6c9d961081dc7b109eb19166244bcb2a5dfc28 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 17 Aug 2007 01:52:39 -0500 Subject: [PATCH 0166/2804] [POWERPC] Stop include asm-ppc when building ARCH=powerpc for ppc32 We no longer have any dependancies on include/asm-ppc so we can get ride of the makefile hacks to include it in the build process. Signed-off-by: Kumar Gala --- arch/powerpc/Makefile | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 8e59c0c405ad..6015a92bc2a0 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -63,8 +63,7 @@ endif LDFLAGS_vmlinux := -Bstatic -# The -Iarch/$(ARCH)/include is temporary while we are merging -CPPFLAGS-$(CONFIG_PPC32) := -Iarch/$(ARCH) -Iarch/$(ARCH)/include +CPPFLAGS-$(CONFIG_PPC32) := -Iarch/$(ARCH) AFLAGS-$(CONFIG_PPC32) := -Iarch/$(ARCH) CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=none -mcall-aixdesc CFLAGS-$(CONFIG_PPC32) := -Iarch/$(ARCH) -ffixed-r2 -mmultiple @@ -72,9 +71,6 @@ CPPFLAGS += $(CPPFLAGS-y) AFLAGS += $(AFLAGS-y) CFLAGS += -msoft-float -pipe $(CFLAGS-y) CPP = $(CC) -E $(CFLAGS) -# Temporary hack until we have migrated to asm-powerpc -LINUXINCLUDE-$(CONFIG_PPC32) := -Iarch/$(ARCH)/include -LINUXINCLUDE += $(LINUXINCLUDE-y) CHECKFLAGS += -m$(SZ) -D__powerpc__ -D__powerpc$(SZ)__ @@ -172,19 +168,8 @@ install: archclean: $(Q)$(MAKE) $(clean)=$(boot) -archmrproper: - $(Q)rm -rf arch/$(ARCH)/include - archprepare: checkbin -ifeq ($(CONFIG_PPC32),y) -# Temporary hack until we have migrated to asm-powerpc -include/asm: arch/$(ARCH)/include/asm -arch/$(ARCH)/include/asm: FORCE - $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi - $(Q)ln -fsn $(srctree)/include/asm-$(OLDARCH) arch/$(ARCH)/include/asm -endif - # Use the file '.tmp_gas_check' for binutils tests, as gas won't output # to stdout and these checks are run even on install targets. TOUT := .tmp_gas_check From d60ff953652f0a2f74ad17ab2d9a0e928c1902d3 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 29 Aug 2007 17:39:42 +0400 Subject: [PATCH 0167/2804] [POWERPC] PowerPC 440EPx: Sequoia device tree AMCC PPC440EPx Sequoia device tree. Signed-off-by: Valentine Barshak Acked-by: David Gibson Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/sequoia.dts | 286 ++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 arch/powerpc/boot/dts/sequoia.dts diff --git a/arch/powerpc/boot/dts/sequoia.dts b/arch/powerpc/boot/dts/sequoia.dts new file mode 100644 index 000000000000..af6a56b4e5b1 --- /dev/null +++ b/arch/powerpc/boot/dts/sequoia.dts @@ -0,0 +1,286 @@ +/* + * Device Tree Source for AMCC Sequoia + * + * Based on Bamboo code by Josh Boyer + * Copyright (c) 2006, 2007 IBM Corp. + * + * FIXME: Draft only! + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + * + */ + +/ { + #address-cells = <2>; + #size-cells = <1>; + model = "amcc,sequoia"; + compatible = "amcc,sequoia"; + dcr-parent = <&/cpus/PowerPC,440EPx@0>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,440EPx@0 { + device_type = "cpu"; + reg = <0>; + clock-frequency = <0>; /* Filled in by zImage */ + timebase-frequency = <0>; /* Filled in by zImage */ + i-cache-line-size = <20>; + d-cache-line-size = <20>; + i-cache-size = <8000>; + d-cache-size = <8000>; + dcr-controller; + dcr-access-method = "native"; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0 0>; /* Filled in by zImage */ + }; + + UIC0: interrupt-controller0 { + compatible = "ibm,uic-440epx","ibm,uic"; + interrupt-controller; + cell-index = <0>; + dcr-reg = <0c0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + }; + + UIC1: interrupt-controller1 { + compatible = "ibm,uic-440epx","ibm,uic"; + interrupt-controller; + cell-index = <1>; + dcr-reg = <0d0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <1e 4 1f 4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + UIC2: interrupt-controller2 { + compatible = "ibm,uic-440epx","ibm,uic"; + interrupt-controller; + cell-index = <2>; + dcr-reg = <0e0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <1c 4 1d 4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + SDR0: sdr { + compatible = "ibm,sdr-440epx", "ibm,sdr-440ep"; + dcr-reg = <00e 002>; + }; + + CPR0: cpr { + compatible = "ibm,cpr-440epx", "ibm,cpr-440ep"; + dcr-reg = <00c 002>; + }; + + plb { + compatible = "ibm,plb-440epx", "ibm,plb4"; + #address-cells = <2>; + #size-cells = <1>; + ranges; + clock-frequency = <0>; /* Filled in by zImage */ + + SDRAM0: sdram { + device_type = "memory-controller"; + compatible = "ibm,sdram-440epx", "ibm,sdram-44x-ddr2denali"; + dcr-reg = <010 2>; + }; + + DMA0: dma { + compatible = "ibm,dma-440epx", "ibm,dma-4xx"; + dcr-reg = <100 027>; + }; + + MAL0: mcmal { + compatible = "ibm,mcmal-440epx", "ibm,mcmal2"; + dcr-reg = <180 62>; + num-tx-chans = <4>; + num-rx-chans = <4>; + interrupt-parent = <&MAL0>; + interrupts = <0 1 2 3 4>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = ; + interrupt-map-mask = ; + }; + + POB0: opb { + compatible = "ibm,opb-440epx", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <00000000 1 00000000 80000000 + 80000000 1 80000000 80000000>; + interrupt-parent = <&UIC1>; + interrupts = <7 4>; + clock-frequency = <0>; /* Filled in by zImage */ + + EBC0: ebc { + compatible = "ibm,ebc-440epx", "ibm,ebc"; + dcr-reg = <012 2>; + #address-cells = <2>; + #size-cells = <1>; + clock-frequency = <0>; /* Filled in by zImage */ + interrupts = <5 1>; + interrupt-parent = <&UIC1>; + + nor_flash@0,0 { + device_type = "rom"; + compatible = "direct-mapped"; + probe-type = "CFI"; + bank-width = <2>; + partitions = < 0 180000 + 180000 200000 + 380000 3aa0000 + 3e20000 140000 + 3f60000 40000 + 3fa0000 60000>; + partition-names = "Kernel", "ramdisk", "file system", + "kozio", "env", "u-boot"; + reg = <0 000000 4000000>; + }; + + }; + + UART0: serial@ef600300 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; /* Filled in by zImage */ + current-speed = <1c200>; + interrupt-parent = <&UIC0>; + interrupts = <0 4>; + }; + + UART1: serial@ef600400 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <1 4>; + }; + + UART2: serial@ef600500 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC1>; + interrupts = <3 4>; + }; + + UART3: serial@ef600600 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC1>; + interrupts = <4 4>; + }; + + IIC0: i2c@ef600700 { + device_type = "i2c"; + compatible = "ibm,iic-440epx", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <2 4>; + }; + + IIC1: i2c@ef600800 { + device_type = "i2c"; + compatible = "ibm,iic-440epx", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <7 4>; + }; + + ZMII0: emac-zmii@ef600d00 { + device_type = "zmii-interface"; + compatible = "ibm,zmii-440epx", "ibm,zmii"; + reg = ; + }; + + EMAC0: ethernet@ef600e00 { + linux,network-index = <0>; + device_type = "network"; + compatible = "ibm,emac-440epx", "ibm,emac4"; + interrupt-parent = <&EMAC0>; + interrupts = <0 1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = ; + reg = ; + local-mac-address = [000000000000]; + mal-device = <&MAL0>; + mal-tx-channel = <0 1>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000000>; + zmii-device = <&ZMII0>; + zmii-channel = <0>; + }; + + EMAC1: ethernet@ef600f00 { + linux,network-index = <1>; + device_type = "network"; + compatible = "ibm,emac-440epx", "ibm,emac4"; + interrupt-parent = <&EMAC1>; + interrupts = <0 1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = ; + reg = ; + local-mac-address = [000000000000]; + mal-device = <&MAL0>; + mal-tx-channel = <2 3>; + mal-rx-channel = <1>; + cell-index = <1>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000000>; + zmii-device = <&ZMII0>; + zmii-channel = <1>; + }; + }; + }; + + chosen { + linux,stdout-path = "/plb/opb/serial@ef600300"; + bootargs = "console=ttyS0,115200"; + }; +}; From 38a5d6c9e79c2dbf3b23fb6fe8c2b51551bc9ee3 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 29 Aug 2007 17:41:28 +0400 Subject: [PATCH 0168/2804] [POWERPC] PowerPC 440EPx: Sequoia defconfig AMCC PPC440EPx Sequoia default config. Signed-off-by: Valentine Barshak Acked-by: David Gibson Signed-off-by: Josh Boyer --- arch/powerpc/configs/sequoia_defconfig | 776 +++++++++++++++++++++++++ 1 file changed, 776 insertions(+) create mode 100644 arch/powerpc/configs/sequoia_defconfig diff --git a/arch/powerpc/configs/sequoia_defconfig b/arch/powerpc/configs/sequoia_defconfig new file mode 100644 index 000000000000..58256625b5b8 --- /dev/null +++ b/arch/powerpc/configs/sequoia_defconfig @@ -0,0 +1,776 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc3 +# Mon Aug 27 20:19:13 2007 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +CONFIG_44x=y +# CONFIG_E200 is not set +CONFIG_PPC_FPU=y +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set +CONFIG_PPC_DCR_NATIVE=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_DCR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +# CONFIG_BAMBOO is not set +# CONFIG_EBONY is not set +CONFIG_SEQUOIA=y +CONFIG_440EPX=y +CONFIG_440A=y +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPM2 is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_PROC_DEVICETREE=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +CONFIG_SECCOMP=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="sequoia.dts" +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x01000000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +# CONFIG_MTD is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=35000 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_XILINX_SYSACE is not set +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +CONFIG_MACINTOSH_DRIVERS=y +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ARCNET is not set +# CONFIG_NET_ETHERNET is not set +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +CONFIG_NETDEV_10000=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_DEBUGGER=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set +# CONFIG_BDI_SWITCH is not set +CONFIG_PPC_EARLY_DEBUG=y +# CONFIG_PPC_EARLY_DEBUG_LPAR is not set +# CONFIG_PPC_EARLY_DEBUG_G5 is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set +# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set +# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set +# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set +# CONFIG_PPC_EARLY_DEBUG_BEAT is not set +CONFIG_PPC_EARLY_DEBUG_44x=y +CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0xef600300 +CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x1 + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_HW=y From 15fc993e31293f9b179eb5f08b18a4a4f2ca648a Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 29 Aug 2007 17:40:30 +0400 Subject: [PATCH 0169/2804] [POWERPC] PowerPC 440EPx: Sequoia board support AMCC PPC440EPx Sequoia board support. Signed-off-by: Valentine Barshak Acked-by: David Gibson Signed-off-by: Josh Boyer --- arch/powerpc/kernel/cputable.c | 18 ++++++++ arch/powerpc/kernel/head_44x.S | 2 +- arch/powerpc/platforms/44x/Kconfig | 17 ++++++- arch/powerpc/platforms/44x/Makefile | 1 + arch/powerpc/platforms/44x/sequoia.c | 66 ++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/platforms/44x/sequoia.c diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index b1f8000952f3..5873073c9045 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1132,6 +1132,24 @@ static struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .platform = "ppc440", }, + { /* 440EPX */ + .pvr_mask = 0xf0000ffb, + .pvr_value = 0x200008D0, + .cpu_name = "440EPX", + .cpu_features = CPU_FTRS_44X, + .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .icache_bsize = 32, + .dcache_bsize = 32, + }, + { /* 440GRX */ + .pvr_mask = 0xf0000ffb, + .pvr_value = 0x200008D8, + .cpu_name = "440GRX", + .cpu_features = CPU_FTRS_44X, + .cpu_user_features = COMMON_USER_BOOKE, + .icache_bsize = 32, + .dcache_bsize = 32, + }, { /* 440GP Rev. B */ .pvr_mask = 0xf0000fff, .pvr_value = 0x40000440, diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 88695963f587..e26d26e31813 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -217,7 +217,7 @@ skpinv: addi r4,r4,1 /* Increment */ lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ mtspr SPRN_IVPR,r4 -#ifdef CONFIG_440EP +#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) /* Clear DAPUIB flag in CCR0 (enable APU between CPU and FPU) */ mfspr r2,SPRN_CCR0 lis r3,0xffef diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index c7cc12a2f269..f28acdcbd6c9 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -14,6 +14,14 @@ config EBONY help This option enables support for the IBM PPC440GP evaluation board. +config SEQUOIA + bool "Sequoia" + depends on 44x + default n + select 440EPX + help + This option enables support for the AMCC PPC440EPX evaluation board. + #config LUAN # bool "Luan" # depends on 44x @@ -37,6 +45,13 @@ config 440EP select IBM440EP_ERR42 # select IBM_NEW_EMAC_ZMII +config 440EPX + bool + select PPC_FPU +# Disabled until the new EMAC Driver is merged. +# select IBM_NEW_EMAC_EMAC4 +# select IBM_NEW_EMAC_ZMII + config 440GP bool # Disabled until the new EMAC Driver is merged. @@ -50,7 +65,7 @@ config 440SP config 440A bool - depends on 440GX + depends on 440GX || 440EPX default y # 44x errata/workaround config symbols, selected by the CPU models above diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index 47ccc3659e34..10ce6740cc7d 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_44x) := misc_44x.o obj-$(CONFIG_EBONY) += ebony.o obj-$(CONFIG_BAMBOO) += bamboo.o +obj-$(CONFIG_SEQUOIA) += sequoia.o diff --git a/arch/powerpc/platforms/44x/sequoia.c b/arch/powerpc/platforms/44x/sequoia.c new file mode 100644 index 000000000000..7d0d9d567d25 --- /dev/null +++ b/arch/powerpc/platforms/44x/sequoia.c @@ -0,0 +1,66 @@ +/* + * Sequoia board specific routines + * + * Valentine Barshak + * Copyright 2007 MontaVista Software Inc. + * + * Based on the Bamboo code by + * Josh Boyer + * Copyright 2007 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 "44x.h" + +static struct of_device_id sequoia_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init sequoia_device_probe(void) +{ + if (!machine_is(sequoia)) + return 0; + + of_platform_bus_probe(NULL, sequoia_of_bus, NULL); + + return 0; +} +device_initcall(sequoia_device_probe); + +static int __init sequoia_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "amcc,sequoia")) + return 0; + + return 1; +} + +static void __init sequoia_setup_arch(void) +{ +} + +define_machine(sequoia) { + .name = "Sequoia", + .probe = sequoia_probe, + .setup_arch = sequoia_setup_arch, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .restart = ppc44x_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; From 606d08bcd674073e0e505cb1eb4ff1516c3b498a Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 29 Aug 2007 17:38:30 +0400 Subject: [PATCH 0170/2804] [POWERPC] PowerPC 440EPx: Sequoia bootwrapper Bootwrapper code for AMCC PPC440EPx Sequoia. Signed-off-by: Valentine Barshak Acked-by: David Gibson Signed-off-by: Josh Boyer --- arch/powerpc/boot/4xx.c | 108 +++++++++++++++++++++++++++++ arch/powerpc/boot/4xx.h | 1 + arch/powerpc/boot/Makefile | 4 +- arch/powerpc/boot/cuboot-sequoia.c | 56 +++++++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/cuboot-sequoia.c diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c index 642d8780bb31..ebf9e217612d 100644 --- a/arch/powerpc/boot/4xx.c +++ b/arch/powerpc/boot/4xx.c @@ -39,6 +39,114 @@ void ibm4xx_fixup_memsize(void) dt_fixup_memory(0, memsize); } +/* 4xx DDR1/2 Denali memory controller support */ +/* DDR0 registers */ +#define DDR0_02 2 +#define DDR0_08 8 +#define DDR0_10 10 +#define DDR0_14 14 +#define DDR0_42 42 +#define DDR0_43 43 + +/* DDR0_02 */ +#define DDR_START 0x1 +#define DDR_START_SHIFT 0 +#define DDR_MAX_CS_REG 0x3 +#define DDR_MAX_CS_REG_SHIFT 24 +#define DDR_MAX_COL_REG 0xf +#define DDR_MAX_COL_REG_SHIFT 16 +#define DDR_MAX_ROW_REG 0xf +#define DDR_MAX_ROW_REG_SHIFT 8 +/* DDR0_08 */ +#define DDR_DDR2_MODE 0x1 +#define DDR_DDR2_MODE_SHIFT 0 +/* DDR0_10 */ +#define DDR_CS_MAP 0x3 +#define DDR_CS_MAP_SHIFT 8 +/* DDR0_14 */ +#define DDR_REDUC 0x1 +#define DDR_REDUC_SHIFT 16 +/* DDR0_42 */ +#define DDR_APIN 0x7 +#define DDR_APIN_SHIFT 24 +/* DDR0_43 */ +#define DDR_COL_SZ 0x7 +#define DDR_COL_SZ_SHIFT 8 +#define DDR_BANK8 0x1 +#define DDR_BANK8_SHIFT 0 + +#define DDR_GET_VAL(val, mask, shift) (((val) >> (shift)) & (mask)) + +static inline u32 mfdcr_sdram0(u32 reg) +{ + mtdcr(DCRN_SDRAM0_CFGADDR, reg); + return mfdcr(DCRN_SDRAM0_CFGDATA); +} + +void ibm4xx_denali_fixup_memsize(void) +{ + u32 val, max_cs, max_col, max_row; + u32 cs, col, row, bank, dpath; + unsigned long memsize; + + val = mfdcr_sdram0(DDR0_02); + if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT)) + fatal("DDR controller is not initialized\n"); + + /* get maximum cs col and row values */ + max_cs = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT); + max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT); + max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT); + + /* get CS value */ + val = mfdcr_sdram0(DDR0_10); + + val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT); + cs = 0; + while (val) { + if (val && 0x1) + cs++; + val = val >> 1; + } + + if (!cs) + fatal("No memory installed\n"); + if (cs > max_cs) + fatal("DDR wrong CS configuration\n"); + + /* get data path bytes */ + val = mfdcr_sdram0(DDR0_14); + + if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT)) + dpath = 8; /* 64 bits */ + else + dpath = 4; /* 32 bits */ + + /* get adress pins (rows) */ + val = mfdcr_sdram0(DDR0_42); + + row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT); + if (row > max_row) + fatal("DDR wrong APIN configuration\n"); + row = max_row - row; + + /* get collomn size and banks */ + val = mfdcr_sdram0(DDR0_43); + + col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT); + if (col > max_col) + fatal("DDR wrong COL configuration\n"); + col = max_col - col; + + if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT)) + bank = 8; /* 8 banks */ + else + bank = 4; /* 4 banks */ + + memsize = cs * (1 << (col+row)) * bank * dpath; + dt_fixup_memory(0, memsize); +} + #define SPRN_DBCR0_40X 0x3F2 #define SPRN_DBCR0_44X 0x134 #define DBCR0_RST_SYSTEM 0x30000000 diff --git a/arch/powerpc/boot/4xx.h b/arch/powerpc/boot/4xx.h index 8f26e480dcd3..adba6a599a93 100644 --- a/arch/powerpc/boot/4xx.h +++ b/arch/powerpc/boot/4xx.h @@ -12,6 +12,7 @@ #define _POWERPC_BOOT_4XX_H_ void ibm4xx_fixup_memsize(void); +void ibm4xx_denali_fixup_memsize(void); void ibm44x_dbcr_reset(void); void ibm40x_dbcr_reset(void); void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1); diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index cd7c05769e41..2766069e6a2b 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -48,7 +48,8 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ cpm-serial.c src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ - ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c cuboot-pq2.c + ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ + cuboot-pq2.c cuboot-sequoia.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -146,6 +147,7 @@ image-$(CONFIG_PPC_83xx) += cuImage.83xx image-$(CONFIG_PPC_85xx) += cuImage.85xx image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony image-$(CONFIG_BAMBOO) += treeImage.bamboo +image-$(CONFIG_SEQUOIA) += cuImage.sequoia endif # For 32-bit powermacs, build the COFF and miboot images diff --git a/arch/powerpc/boot/cuboot-sequoia.c b/arch/powerpc/boot/cuboot-sequoia.c new file mode 100644 index 000000000000..ec635e0bd4ec --- /dev/null +++ b/arch/powerpc/boot/cuboot-sequoia.c @@ -0,0 +1,56 @@ +/* + * Old U-boot compatibility for Sequoia + * + * Valentine Barshak + * Copyright 2007 MontaVista Software, Inc + * + * Based on Ebony code by David Gibson + * Copyright IBM Corporation, 2007 + * + * Based on Bamboo code by Josh Boyer + * Copyright IBM Corporation, 2007 + * + * 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 + */ + +#include +#include +#include "types.h" +#include "elf.h" +#include "string.h" +#include "stdio.h" +#include "page.h" +#include "ops.h" +#include "dcr.h" +#include "4xx.h" +#include "44x.h" +#include "cuboot.h" + +#define TARGET_4xx +#define TARGET_44x +#include "ppcboot.h" + +static bd_t bd; + + +static void sequoia_fixups(void) +{ + unsigned long sysclk = 33333333; + + ibm440ep_fixup_clocks(sysclk, 11059200); + ibm4xx_fixup_ebc_ranges("/plb/opb/ebc"); + ibm4xx_denali_fixup_memsize(); + dt_fixup_mac_addresses(&bd.bi_enetaddr, &bd.bi_enet1addr); +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + CUBOOT_INIT(); + platform_ops.fixups = sequoia_fixups; + platform_ops.exit = ibm44x_dbcr_reset; + ft_init(_dtb_start, 0, 32); + serial_console_init(); +} From c9c6b744d8a2a95ef6d5c8389964df5148e3102a Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 7 Sep 2007 07:49:59 -0500 Subject: [PATCH 0171/2804] [POWERPC] Remove dtc build cruft from DTS files The patch below removes the dtc incantation instructions from the in-kernel DTS files. It's not needed, and is prone to being out-of-date most of the time. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/boot/dts/ebony.dts | 4 ---- arch/powerpc/boot/dts/holly.dts | 4 ---- arch/powerpc/boot/dts/kuroboxHD.dts | 3 --- arch/powerpc/boot/dts/kuroboxHG.dts | 3 --- arch/powerpc/boot/dts/prpmc2800.dts | 4 ---- 5 files changed, 18 deletions(-) diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts index 27a1463b6ab0..37599bda5500 100644 --- a/arch/powerpc/boot/dts/ebony.dts +++ b/arch/powerpc/boot/dts/ebony.dts @@ -9,10 +9,6 @@ * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without * any warranty of any kind, whether express or implied. - * - * To build: - * dtc -I dts -O asm -o ebony.S -b 0 ebony.dts - * dtc -I dts -O dtb -o ebony.dtb -b 0 ebony.dts */ / { diff --git a/arch/powerpc/boot/dts/holly.dts b/arch/powerpc/boot/dts/holly.dts index 80a4fab8ee37..1a4d0beccc99 100644 --- a/arch/powerpc/boot/dts/holly.dts +++ b/arch/powerpc/boot/dts/holly.dts @@ -8,10 +8,6 @@ * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without * any warranty of any kind, whether express or implied. - * - * To build: - * dtc -I dts -O asm -o holly.S -b 0 holly.dts - * dtc -I dts -O dtb -o holly.dtb -b 0 holly.dts */ / { diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts index 122537419d9f..b0eeff036de3 100644 --- a/arch/powerpc/boot/dts/kuroboxHD.dts +++ b/arch/powerpc/boot/dts/kuroboxHD.dts @@ -15,9 +15,6 @@ XXXX add flash parts, rtc, ?? -build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts" - - */ / { diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts index 579aa8b967d9..ccd15a231a10 100644 --- a/arch/powerpc/boot/dts/kuroboxHG.dts +++ b/arch/powerpc/boot/dts/kuroboxHG.dts @@ -15,9 +15,6 @@ XXXX add flash parts, rtc, ?? -build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts" - - */ / { diff --git a/arch/powerpc/boot/dts/prpmc2800.dts b/arch/powerpc/boot/dts/prpmc2800.dts index 5300b50cdc2f..e416ea67be49 100644 --- a/arch/powerpc/boot/dts/prpmc2800.dts +++ b/arch/powerpc/boot/dts/prpmc2800.dts @@ -9,10 +9,6 @@ * * Property values that are labeled as "Default" will be updated by bootwrapper * if it can determine the exact PrPMC type. - * - * To build: - * dtc -I dts -O asm -o prpmc2800.S -b 0 prpmc2800.dts - * dtc -I dts -O dtb -o prpmc2800.dtb -b 0 prpmc2800.dts */ / { From 1f6e57952180cd54e245241b74f4b9cb10c24f98 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 7 Sep 2007 07:50:26 -0500 Subject: [PATCH 0172/2804] [POWERPC] Fix bus probe on Bamboo board Commit 804ace8881d21 changed the behavior of how compatible nodes are found. This highlighted a bug on the Bamboo board where it wasn't probing the bus specified in the DTS file. We fix it by being explicit about which bus to probe. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/platforms/44x/bamboo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c index 5522f1f9642e..9bc45dea078f 100644 --- a/arch/powerpc/platforms/44x/bamboo.c +++ b/arch/powerpc/platforms/44x/bamboo.c @@ -23,7 +23,7 @@ #include "44x.h" static struct of_device_id bamboo_of_bus[] = { - { .compatible = "ibm,plb", }, + { .compatible = "ibm,plb4", }, { .compatible = "ibm,opb", }, { .compatible = "ibm,ebc", }, {}, From 8852ab7afc2397779f9ea926187dbc4e0452ab47 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 7 Sep 2007 07:50:50 -0500 Subject: [PATCH 0173/2804] [POWERPC] Walnut DTS Device tree source file for the PPC405 Walnut evaluation board. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/boot/dts/walnut.dts | 183 +++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 arch/powerpc/boot/dts/walnut.dts diff --git a/arch/powerpc/boot/dts/walnut.dts b/arch/powerpc/boot/dts/walnut.dts new file mode 100644 index 000000000000..27bef06db134 --- /dev/null +++ b/arch/powerpc/boot/dts/walnut.dts @@ -0,0 +1,183 @@ +/* + * Device Tree Source for IBM Walnut + * + * Copyright 2007 IBM Corp. + * Josh Boyer + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/ { + #address-cells = <1>; + #size-cells = <1>; + model = "ibm,walnut"; + compatible = "ibm,walnut"; + dcr-parent = <&/cpus/PowerPC,405GP@0>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,405GP@0 { + device_type = "cpu"; + reg = <0>; + clock-frequency = ; /* Filled in by zImage */ + timebase-frequency = <0>; /* Filled in by zImage */ + i-cache-line-size = <20>; + d-cache-line-size = <20>; + i-cache-size = <4000>; + d-cache-size = <4000>; + dcr-controller; + dcr-access-method = "native"; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0>; /* Filled in by zImage */ + }; + + UIC0: interrupt-controller { + compatible = "ibm,uic"; + interrupt-controller; + cell-index = <0>; + dcr-reg = <0c0 9>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + }; + + plb { + compatible = "ibm,plb3"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + clock-frequency = <0>; /* Filled in by zImage */ + + SDRAM0: memory-controller { + compatible = "ibm,sdram-405gp"; + dcr-reg = <010 2>; + }; + + MAL: mcmal { + compatible = "ibm,mcmal-405gp", "ibm,mcmal"; + dcr-reg = <180 62>; + num-tx-chans = <2>; + num-rx-chans = <1>; + interrupt-parent = <&UIC0>; + interrupts = ; + }; + + POB0: opb { + compatible = "ibm,opb-405gp", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + ranges = ; + dcr-reg = <0a0 5>; + clock-frequency = <0>; /* Filled in by zImage */ + + UART0: serial@ef600300 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; /* Filled in by zImage */ + current-speed = <2580>; + interrupt-parent = <&UIC0>; + interrupts = <0 4>; + }; + + UART1: serial@ef600400 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; /* Filled in by zImage */ + current-speed = <2580>; + interrupt-parent = <&UIC0>; + interrupts = <1 4>; + }; + + IIC: i2c@ef600500 { + compatible = "ibm,iic-405gp", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <2 4>; + }; + + GPIO: gpio@ef600700 { + compatible = "ibm,gpio-405gp"; + reg = ; + }; + + EMAC: ethernet@ef600800 { + linux,network-index = <0>; + device_type = "network"; + compatible = "ibm,emac-405gp", "ibm,emac"; + interrupt-parent = <&UIC0>; + interrupts = <9 4 f 4>; + reg = ; + mal-device = <&MAL>; + mal-tx-channel = <0 1>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000001>; + }; + + }; + + EBC0: ebc { + compatible = "ibm,ebc-405gp", "ibm,ebc"; + dcr-reg = <012 2>; + #address-cells = <2>; + #size-cells = <1>; + clock-frequency = <0>; /* Filled in by zImage */ + + sram@0,0 { + reg = <0 0 80000>; + }; + + flash@0,80000 { + device_type = "rom"; + compatible = "direct-mapped"; + probe-type = "JEDEC"; + bank-width = <1>; + partitions = <0 80000>; + partition-names = "OpenBIOS"; + reg = <0 80000 80000>; + }; + + ds1743@1,0 { + /* NVRAM and RTC */ + compatible = "ds1743"; + reg = <1 0 2000>; + }; + + keyboard@2,0 { + compatible = "intel,82C42PC"; + reg = <2 0 2>; + }; + + ir@3,0 { + compatible = "ti,TIR2000PAG"; + reg = <3 0 10>; + }; + + fpga@7,0 { + compatible = "Walnut-FPGA"; + reg = <7 0 10>; + virtual-reg = ; + }; + }; + }; + + chosen { + linux,stdout-path = "/plb/opb/serial@ef600300"; + }; +}; From 7f2814d229905c35d7c38798891adf00286fdca4 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 7 Sep 2007 07:51:08 -0500 Subject: [PATCH 0174/2804] [POWERPC] Walnut defconfig Walnut board defconfig Signed-off-by: Josh Boyer --- arch/powerpc/configs/walnut_defconfig | 773 ++++++++++++++++++++++++++ 1 file changed, 773 insertions(+) create mode 100644 arch/powerpc/configs/walnut_defconfig diff --git a/arch/powerpc/configs/walnut_defconfig b/arch/powerpc/configs/walnut_defconfig new file mode 100644 index 000000000000..766bf840c18d --- /dev/null +++ b/arch/powerpc/configs/walnut_defconfig @@ -0,0 +1,773 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc4 +# Wed Sep 5 12:06:37 2007 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +CONFIG_40x=y +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_4xx=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set +CONFIG_PPC_DCR_NATIVE=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_DCR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +CONFIG_WALNUT=y +CONFIG_405GP=y +CONFIG_IBM405_ERR77=y +CONFIG_IBM405_ERR51=y +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPM2 is not set +# CONFIG_FSL_ULI1575 is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="walnut.dts" +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x00400000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_WALNUT is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=35000 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_XILINX_SYSACE is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_ETHERNET is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_USB_SUPPORT=y +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_HW=y From 545c069ccd76a0f1f3ceacd8ba5bc8f5208eb727 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 7 Sep 2007 07:51:24 -0500 Subject: [PATCH 0175/2804] [POWERPC] Walnut board support Board support for the PPC405 Walnut evaluation board Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/platforms/40x/Kconfig | 14 +++--- arch/powerpc/platforms/40x/Makefile | 2 +- arch/powerpc/platforms/40x/walnut.c | 68 +++++++++++++++++++++++++++++ arch/powerpc/platforms/Kconfig | 2 +- arch/powerpc/platforms/Makefile | 2 +- 5 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 arch/powerpc/platforms/40x/walnut.c diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index 2cc7343b468c..c3dce3b3d524 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -53,13 +53,13 @@ # help # This option enables support for the IBM PPC405GPr evaluation board. -#config WALNUT -# bool "Walnut" -# depends on 40x -# default y -# select 405GP -# help -# This option enables support for the IBM PPC405GP evaluation board. +config WALNUT + bool "Walnut" + depends on 40x + default y + select 405GP + help + This option enables support for the IBM PPC405GP evaluation board. #config XILINX_ML300 # bool "Xilinx-ML300" diff --git a/arch/powerpc/platforms/40x/Makefile b/arch/powerpc/platforms/40x/Makefile index 79ff6b1e887c..e6c0bbd063a4 100644 --- a/arch/powerpc/platforms/40x/Makefile +++ b/arch/powerpc/platforms/40x/Makefile @@ -1 +1 @@ -# empty makefile so make clean works \ No newline at end of file +obj-$(CONFIG_WALNUT) += walnut.o diff --git a/arch/powerpc/platforms/40x/walnut.c b/arch/powerpc/platforms/40x/walnut.c new file mode 100644 index 000000000000..c17fdf23b492 --- /dev/null +++ b/arch/powerpc/platforms/40x/walnut.c @@ -0,0 +1,68 @@ +/* + * Architecture- / platform-specific boot-time initialization code for + * IBM PowerPC 4xx based boards. Adapted from original + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + * Copyright(c) 1999-2000 Grant Erickson + * + * Rewritten and ported to the merged powerpc tree: + * Copyright 2007 IBM Corporation + * Josh Boyer + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct of_device_id walnut_of_bus[] = { + { .compatible = "ibm,plb3", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init walnut_device_probe(void) +{ + if (!machine_is(walnut)) + return 0; + + /* FIXME: do bus probe here */ + of_platform_bus_probe(NULL, walnut_of_bus, NULL); + + return 0; +} +device_initcall(walnut_device_probe); + +static int __init walnut_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,walnut")) + return 0; + + return 1; +} + +static void __init walnut_setup_arch(void) +{ +} + +define_machine(walnut) { + .name = "Walnut", + .probe = walnut_probe, + .setup_arch = walnut_setup_arch, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 041df77ec117..8eb8d400ecb2 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -59,7 +59,7 @@ source "arch/powerpc/platforms/85xx/Kconfig" source "arch/powerpc/platforms/86xx/Kconfig" source "arch/powerpc/platforms/embedded6xx/Kconfig" source "arch/powerpc/platforms/44x/Kconfig" -#source "arch/powerpc/platforms/4xx/Kconfig +source "arch/powerpc/platforms/40x/Kconfig" config PPC_NATIVE bool diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index d44e832b01f2..6d9079da5f5a 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_PPC_PMAC) += powermac/ endif endif obj-$(CONFIG_PPC_CHRP) += chrp/ -#obj-$(CONFIG_4xx) += 4xx/ +obj-$(CONFIG_40x) += 40x/ obj-$(CONFIG_44x) += 44x/ obj-$(CONFIG_PPC_MPC52xx) += 52xx/ obj-$(CONFIG_PPC_8xx) += 8xx/ From 5326152fa182b0a16e4abf913ce403e3c7ab53b7 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 7 Sep 2007 07:51:44 -0500 Subject: [PATCH 0176/2804] [POWERPC] Walnut zImage wrapper Add zImage wrapper for walnut board Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/boot/Makefile | 3 +- arch/powerpc/boot/dcr.h | 5 ++ arch/powerpc/boot/treeboot-walnut.c | 131 ++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/treeboot-walnut.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 2766069e6a2b..fd16577a40d5 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -49,7 +49,7 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ - cuboot-pq2.c cuboot-sequoia.c + cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -148,6 +148,7 @@ image-$(CONFIG_PPC_85xx) += cuImage.85xx image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony image-$(CONFIG_BAMBOO) += treeImage.bamboo image-$(CONFIG_SEQUOIA) += cuImage.sequoia +image-$(CONFIG_WALNUT) += treeImage.walnut endif # For 32-bit powermacs, build the COFF and miboot images diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h index e158311c501b..83b88aa92888 100644 --- a/arch/powerpc/boot/dcr.h +++ b/arch/powerpc/boot/dcr.h @@ -134,4 +134,9 @@ static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR, SDRAM0_B2C #define CPR0_SCPID 0x120 #define CPR0_PLLC0 0x40 +/* 405GP Clocking/Power Management/Chip Control regs */ +#define DCRN_CPC0_PLLMR 0xb0 +#define DCRN_405_CPC0_CR0 0xb1 +#define DCRN_405_CPC0_CR1 0xb2 + #endif /* _PPC_BOOT_DCR_H_ */ diff --git a/arch/powerpc/boot/treeboot-walnut.c b/arch/powerpc/boot/treeboot-walnut.c new file mode 100644 index 000000000000..3adf2d08a230 --- /dev/null +++ b/arch/powerpc/boot/treeboot-walnut.c @@ -0,0 +1,131 @@ +/* + * Old U-boot compatibility for Walnut + * + * Author: Josh Boyer + * + * Copyright 2007 IBM Corporation + * Based on cuboot-83xx.c, which is: + * Copyright (c) 2007 Freescale Semiconductor, 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 "ops.h" +#include "stdio.h" +#include "dcr.h" +#include "4xx.h" +#include "io.h" + +BSS_STACK(4096); + +void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) +{ + u32 pllmr = mfdcr(DCRN_CPC0_PLLMR); + u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0); + u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1); + u32 cpu, plb, opb, ebc, tb, uart0, uart1, m; + u32 fwdv, fbdv, cbdv, opdv, epdv, udiv; + + fwdv = (8 - ((pllmr & 0xe0000000) >> 29)); + fbdv = (pllmr & 0x1e000000) >> 25; + cbdv = ((pllmr & 0x00060000) >> 17) + 1; + opdv = ((pllmr & 0x00018000) >> 15) + 1; + epdv = ((pllmr & 0x00001800) >> 13) + 2; + udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1; + + m = fwdv * fbdv * cbdv; + + cpu = sysclk * m / fwdv; + plb = cpu / cbdv; + opb = plb / opdv; + ebc = plb / epdv; + + if (cpc0_cr0 & 0x80) { + /* uart0 uses the external clock */ + uart0 = ser_clk; + } else { + uart0 = cpu / udiv; + } + + if (cpc0_cr0 & 0x40) { + /* uart1 uses the external clock */ + uart1 = ser_clk; + } else { + uart1 = cpu / udiv; + } + + /* setup the timebase clock to tick at the cpu frequency */ + cpc0_cr1 = cpc0_cr1 & ~ 0x00800000; + mtdcr(DCRN_CPC0_CR1, cpc0_cr1); + tb = cpu; + + dt_fixup_cpu_clocks(cpu, tb, 0); + dt_fixup_clock("/plb", plb); + dt_fixup_clock("/plb/opb", opb); + dt_fixup_clock("/plb/ebc", ebc); + dt_fixup_clock("/plb/opb/serial@ef600300", uart0); + dt_fixup_clock("/plb/opb/serial@ef600400", uart1); +} + +static void walnut_flashsel_fixup(void) +{ + void *devp, *sram; + u32 reg_flash[3] = {0x0, 0x0, 0x80000}; + u32 reg_sram[3] = {0x0, 0x0, 0x80000}; + u8 *fpga; + u8 fpga_brds1 = 0x0; + + devp = finddevice("/plb/ebc/fpga"); + if (!devp) + fatal("Couldn't locate FPGA node\n\r"); + + if (getprop(devp, "virtual-reg", &fpga, sizeof(fpga)) != sizeof(fpga)) + fatal("no virtual-reg property\n\r"); + + fpga_brds1 = in_8(fpga); + + devp = finddevice("/plb/ebc/flash"); + if (!devp) + fatal("Couldn't locate flash node\n\r"); + + if (getprop(devp, "reg", reg_flash, sizeof(reg_flash)) != sizeof(reg_flash)) + fatal("flash reg property has unexpected size\n\r"); + + sram = finddevice("/plb/ebc/sram"); + if (!sram) + fatal("Couldn't locate sram node\n\r"); + + if (getprop(sram, "reg", reg_sram, sizeof(reg_sram)) != sizeof(reg_sram)) + fatal("sram reg property has unexpected size\n\r"); + + if (fpga_brds1 & 0x1) { + reg_flash[1] ^= 0x80000; + reg_sram[1] ^= 0x80000; + } + + setprop(devp, "reg", reg_flash, sizeof(reg_flash)); + setprop(sram, "reg", reg_sram, sizeof(reg_sram)); +} + +static void walnut_fixups(void) +{ + ibm4xx_fixup_memsize(); + ibm405gp_fixup_clocks(33330000, 0xa8c000); + ibm4xx_quiesce_eth((u32 *)0xef600800, NULL); + ibm4xx_fixup_ebc_ranges("/plb/ebc"); + walnut_flashsel_fixup(); +} + +void platform_init(void) +{ + unsigned long end_of_ram = 0x2000000; + unsigned long avail_ram = end_of_ram - (unsigned long) _end; + + simple_alloc_init(_end, avail_ram, 32, 32); + platform_ops.fixups = walnut_fixups; + platform_ops.exit = ibm40x_dbcr_reset; + ft_init(_dtb_start, _dtb_end - _dtb_start, 32); + serial_console_init(); +} From 768cc2d3b2768ca34f254e8190f1f9e297b09ad4 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Wed, 18 Jul 2007 02:09:35 +1000 Subject: [PATCH 0177/2804] [POWERPC] IOMMU virtual merge is no longer experimental Per conversations with BenH, IOMMU virtual merging should no longer be considered to be an "experimental" feature. In particular, CONFIG_VMERGE has been set to "y" in the defconfigs for quite a while. Signed-off-by: Linas Vepstas Acked-by: Benjamin Herrenschmidt ---- arch/powerpc/Kconfig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 00099efe0e9f..66a329534b5e 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -181,16 +181,17 @@ config MATH_EMULATION instructions to run. config IOMMU_VMERGE - bool "Enable IOMMU virtual merging (EXPERIMENTAL)" - depends on EXPERIMENTAL && PPC64 - default n + bool "Enable IOMMU virtual merging" + depends on PPC64 + default y help Cause IO segments sent to a device for DMA to be merged virtually by the IOMMU when they happen to have been allocated contiguously. This doesn't add pressure to the IOMMU allocator. However, some drivers don't support getting large merged segments coming back - from *_map_sg(). Say Y if you know the drivers you are using are - properly handling this case. + from *_map_sg(). + + Most drivers don't have this problem; it is safe to say Y here. config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" From 0ae0b54565a8dcc2b98de694b998e765de15b713 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 28 Aug 2007 14:52:57 +1000 Subject: [PATCH 0178/2804] [POWERPC] Move bootwrapper's strchr() and strncmp() from .h to string.S Currently the bootwrapper has implementations of strchr() and strncmp(), but they're inlines in flatdevtree_env.h, rather than in string.S with all the rest of the string functions. This moves them to string.S. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/flatdevtree_env.h | 20 -------------------- arch/powerpc/boot/string.S | 24 ++++++++++++++++++++++++ arch/powerpc/boot/string.h | 2 ++ 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/arch/powerpc/boot/flatdevtree_env.h b/arch/powerpc/boot/flatdevtree_env.h index 83bc1c718836..ad0420da8921 100644 --- a/arch/powerpc/boot/flatdevtree_env.h +++ b/arch/powerpc/boot/flatdevtree_env.h @@ -24,24 +24,4 @@ #define be64_to_cpu(x) (x) #define cpu_to_be64(x) (x) -static inline int strncmp(const char *cs, const char *ct, size_t count) -{ - signed char __res = 0; - - while (count) { - if ((__res = *cs - *ct++) != 0 || !*cs++) - break; - count--; - } - return __res; -} - -static inline char *strchr(const char *s, int c) -{ - for (; *s != (char)c; ++s) - if (*s == '\0') - return NULL; - return (char *)s; -} - #endif /* _PPC_BOOT_FLATDEVTREE_ENV_H_ */ diff --git a/arch/powerpc/boot/string.S b/arch/powerpc/boot/string.S index ac3d43b6a324..2627558bcb71 100644 --- a/arch/powerpc/boot/string.S +++ b/arch/powerpc/boot/string.S @@ -49,6 +49,17 @@ strcat: bne 1b blr + .globl strchr +strchr: + addi r3,r3,-1 +1: lbzu r0,1(r3) + cmpw 0,r0,r4 + beqlr + cmpwi 0,r0,0 + bne 1b + li r3,0 + blr + .globl strcmp strcmp: addi r5,r3,-1 @@ -61,6 +72,19 @@ strcmp: beq 1b blr + .globl strncmp +strncmp: + mtctr r5 + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r5) + cmpwi 1,r3,0 + lbzu r0,1(r4) + subf. r3,r0,r3 + beqlr 1 + bdnzt eq,1b + blr + .globl strlen strlen: addi r4,r3,-1 diff --git a/arch/powerpc/boot/string.h b/arch/powerpc/boot/string.h index 9fdff1cc0d70..4650030d1040 100644 --- a/arch/powerpc/boot/string.h +++ b/arch/powerpc/boot/string.h @@ -5,7 +5,9 @@ extern char *strcpy(char *dest, const char *src); extern char *strncpy(char *dest, const char *src, size_t n); extern char *strcat(char *dest, const char *src); +extern char *strchr(const char *s, int c); extern int strcmp(const char *s1, const char *s2); +extern int strncmp(const char *s1, const char *s2, size_t n); extern size_t strlen(const char *s); extern size_t strnlen(const char *s, size_t count); From 52964f87c64e6c6ea671b5bf3030fb1494090a48 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 28 Aug 2007 18:47:54 +1000 Subject: [PATCH 0179/2804] [POWERPC] Add an optional device_node pointer to the irq_host The majority of irq_host implementations (3 out of 4) are associated with a device_node, and need to stash it somewhere. Rather than having it somewhere different for each host, add an optional device_node pointer to the irq_host structure. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/irq.c | 10 ++++++---- arch/powerpc/platforms/52xx/mpc52xx_pic.c | 5 ++--- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 7 ++----- arch/powerpc/platforms/cell/axon_msi.c | 14 +++++--------- arch/powerpc/platforms/cell/interrupt.c | 2 +- arch/powerpc/platforms/cell/spider-pic.c | 18 +++++++----------- arch/powerpc/platforms/celleb/interrupt.c | 2 +- arch/powerpc/platforms/iseries/irq.c | 3 ++- arch/powerpc/platforms/powermac/pic.c | 2 +- arch/powerpc/platforms/ps3/interrupt.c | 2 +- arch/powerpc/platforms/pseries/xics.c | 2 +- arch/powerpc/sysdev/commproc.c | 8 +++----- arch/powerpc/sysdev/cpm2_pic.c | 7 +++---- arch/powerpc/sysdev/i8259.c | 8 +++----- arch/powerpc/sysdev/ipic.c | 7 ++----- arch/powerpc/sysdev/ipic.h | 3 --- arch/powerpc/sysdev/mpc8xx_pic.c | 19 ++++++++++--------- arch/powerpc/sysdev/mpic.c | 11 ++++------- arch/powerpc/sysdev/mpic_msi.c | 7 ++++--- arch/powerpc/sysdev/mv64x60_pic.c | 8 +++----- arch/powerpc/sysdev/qe_lib/qe_ic.c | 7 ++----- arch/powerpc/sysdev/qe_lib/qe_ic.h | 3 --- arch/powerpc/sysdev/tsi108_pci.c | 8 ++++---- arch/powerpc/sysdev/uic.c | 11 +++-------- include/asm-powerpc/irq.h | 8 ++++++-- include/asm-powerpc/mpic.h | 3 --- 26 files changed, 76 insertions(+), 109 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index dfad0e469eec..79b451247b89 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -418,10 +418,11 @@ irq_hw_number_t virq_to_hw(unsigned int virq) } EXPORT_SYMBOL_GPL(virq_to_hw); -__init_refok struct irq_host *irq_alloc_host(unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq) +__init_refok struct irq_host *irq_alloc_host(struct device_node *of_node, + unsigned int revmap_type, + unsigned int revmap_arg, + struct irq_host_ops *ops, + irq_hw_number_t inval_irq) { struct irq_host *host; unsigned int size = sizeof(struct irq_host); @@ -446,6 +447,7 @@ __init_refok struct irq_host *irq_alloc_host(unsigned int revmap_type, host->revmap_type = revmap_type; host->inval_irq = inval_irq; host->ops = ops; + host->of_node = of_node; spin_lock_irqsave(&irq_big_lock, flags); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 8c464c55b5d0..1d793e4b8d56 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -244,7 +244,7 @@ static struct irq_chip mpc52xx_sdma_irqchip = { static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) { pr_debug("%s: node=%p\n", __func__, node); - return mpc52xx_irqhost->host_data == node; + return h->of_node == node; } static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, @@ -419,14 +419,13 @@ void __init mpc52xx_init_irq(void) * hw irq information provided by the ofw to linux virq */ - mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, + mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, MPC52xx_IRQ_HIGHTESTHWIRQ, &mpc52xx_irqhost_ops, -1); if (!mpc52xx_irqhost) panic(__FILE__ ": Cannot allocate the IRQ host\n"); - mpc52xx_irqhost->host_data = picnode; printk(KERN_INFO "MPC52xx PIC is up and running!\n"); } diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index c0a0c56ac5b3..91ddbd2f477d 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -61,7 +61,6 @@ static struct { static unsigned long pci_int_base; static struct irq_host *pci_pic_host; -static struct device_node *pci_pic_node; #endif static void __init mpc82xx_ads_pic_init(void) @@ -401,7 +400,7 @@ m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc) static int pci_pic_host_match(struct irq_host *h, struct device_node *node) { - return node == pci_pic_node; + return h->of_node == node; } static int pci_pic_host_map(struct irq_host *h, unsigned int virq, @@ -478,7 +477,6 @@ void m82xx_pci_init_irq(void) iounmap(immap); return; } - pci_pic_node = of_node_get(np); /* PCI interrupt controller registers: status and mask */ regs = of_get_property(np, "reg", &size); if ((!regs) || (size <= 2)) { @@ -490,7 +488,6 @@ void m82xx_pci_init_irq(void) ioremap(regs[0], sizeof(*pci_regs.pci_int_stat_reg)); pci_regs.pci_int_mask_reg = ioremap(regs[1], sizeof(*pci_regs.pci_int_mask_reg)); - of_node_put(np); /* configure chip select for PCI interrupt controller */ immap->im_memctl.memc_br3 = regs[0] | 0x00001801; immap->im_memctl.memc_or3 = 0xffff8010; @@ -501,7 +498,7 @@ void m82xx_pci_init_irq(void) *pci_regs.pci_int_mask_reg |= 0xfff00000; iounmap(immap); pci_pic_host = - irq_alloc_host(IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1, + irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1, &pci_pic_host_ops, irq_max + 1); return; } diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 4c9ab5b70bae..bdd97bb2446d 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -64,7 +64,6 @@ struct axon_msic { - struct device_node *dn; struct irq_host *irq_host; __le32 *fifo; dcr_host_t dcr_host; @@ -297,9 +296,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq, static int msic_host_match(struct irq_host *host, struct device_node *dn) { - struct axon_msic *msic = host->host_data; - - return msic->dn == dn; + return host->of_node == dn; } static struct irq_host_ops msic_host_ops = { @@ -314,7 +311,8 @@ static int axon_msi_notify_reboot(struct notifier_block *nb, u32 tmp; list_for_each_entry(msic, &axon_msic_list, list) { - pr_debug("axon_msi: disabling %s\n", msic->dn->full_name); + pr_debug("axon_msi: disabling %s\n", + msic->irq_host->of_node->full_name); tmp = msic_dcr_read(msic, MSIC_CTRL_REG); tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; msic_dcr_write(msic, MSIC_CTRL_REG, tmp); @@ -370,8 +368,8 @@ static int axon_msi_setup_one(struct device_node *dn) msic->fifo = page_address(page); - msic->irq_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, NR_IRQS, - &msic_host_ops, 0); + msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP, + NR_IRQS, &msic_host_ops, 0); if (!msic->irq_host) { printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n", dn->full_name); @@ -387,8 +385,6 @@ static int axon_msi_setup_one(struct device_node *dn) goto out_free_host; } - msic->dn = of_node_get(dn); - set_irq_data(virq, msic); set_irq_chained_handler(virq, axon_msi_cascade); pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq); diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 47264e722029..c29e634177fa 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -381,7 +381,7 @@ static int __init setup_iic(void) void __init iic_init_IRQ(void) { /* Setup an irq host data structure */ - iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, + iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, &iic_host_ops, IIC_IRQ_INVALID); BUG_ON(iic_host == NULL); irq_set_default_host(iic_host); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 05f4b3d3d756..4309c2cbbeb9 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -63,7 +63,6 @@ enum { struct spider_pic { struct irq_host *host; - struct device_node *of_node; void __iomem *regs; unsigned int node_id; }; @@ -178,8 +177,7 @@ static struct irq_chip spider_pic = { static int spider_host_match(struct irq_host *h, struct device_node *node) { - struct spider_pic *pic = h->host_data; - return node == pic->of_node; + return h->of_node == node; } static int spider_host_map(struct irq_host *h, unsigned int virq, @@ -247,18 +245,18 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) * tree in case the device-tree is ever fixed */ struct of_irq oirq; - if (of_irq_map_one(pic->of_node, 0, &oirq) == 0) { + if (of_irq_map_one(pic->host->of_node, 0, &oirq) == 0) { virq = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size); return virq; } /* Now do the horrible hacks */ - tmp = of_get_property(pic->of_node, "#interrupt-cells", NULL); + tmp = of_get_property(pic->host->of_node, "#interrupt-cells", NULL); if (tmp == NULL) return NO_IRQ; intsize = *tmp; - imap = of_get_property(pic->of_node, "interrupt-map", &imaplen); + imap = of_get_property(pic->host->of_node, "interrupt-map", &imaplen); if (imap == NULL || imaplen < (intsize + 1)) return NO_IRQ; iic = of_find_node_by_phandle(imap[intsize]); @@ -308,15 +306,13 @@ static void __init spider_init_one(struct device_node *of_node, int chip, panic("spider_pic: can't map registers !"); /* Allocate a host */ - pic->host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, SPIDER_SRC_COUNT, - &spider_host_ops, SPIDER_IRQ_INVALID); + pic->host = irq_alloc_host(of_node_get(of_node), IRQ_HOST_MAP_LINEAR, + SPIDER_SRC_COUNT, &spider_host_ops, + SPIDER_IRQ_INVALID); if (pic->host == NULL) panic("spider_pic: can't allocate irq host !"); pic->host->host_data = pic; - /* Fill out other bits */ - pic->of_node = of_node_get(of_node); - /* Go through all sources and disable them */ for (i = 0; i < SPIDER_SRC_COUNT; i++) { void __iomem *cfg = pic->regs + TIR_CFGA + 8 * i; diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/celleb/interrupt.c index 98e6665681d3..4ecdf06e421b 100644 --- a/arch/powerpc/platforms/celleb/interrupt.c +++ b/arch/powerpc/platforms/celleb/interrupt.c @@ -242,7 +242,7 @@ void __init beatic_init_IRQ(void) ppc_md.get_irq = beatic_get_irq; /* Allocate an irq host */ - beatic_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, + beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &beatic_pic_host_ops, 0); BUG_ON(beatic_host == NULL); diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 63b33675848b..36667460c922 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -369,7 +369,8 @@ void __init iSeries_init_IRQ(void) /* Create irq host. No need for a revmap since HV will give us * back our virtual irq number */ - host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &iseries_irq_host_ops, 0); + host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, + &iseries_irq_host_ops, 0); BUG_ON(host == NULL); irq_set_default_host(host); diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 87cd6805171a..999f5e160897 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -384,7 +384,7 @@ static void __init pmac_pic_probe_oldstyle(void) /* * Allocate an irq host */ - pmac_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, max_irqs, + pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs, &pmac_pic_host_ops, max_irqs); BUG_ON(pmac_pic_host == NULL); diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 67e32ec9b37e..30b9f4c6eb55 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -726,7 +726,7 @@ void __init ps3_init_IRQ(void) unsigned cpu; struct irq_host *host; - host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, + host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, PS3_INVALID_OUTLET); irq_set_default_host(host); irq_set_virq_count(PS3_PLUG_MAX + 1); diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 5bd90a7eb763..5ddb0259b1fb 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -540,7 +540,7 @@ static void __init xics_init_host(void) ops = &xics_host_lpar_ops; else ops = &xics_host_direct_ops; - xics_host = irq_alloc_host(IRQ_HOST_MAP_TREE, 0, ops, + xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, ops, XICS_IRQ_SPURIOUS); BUG_ON(xics_host == NULL); irq_set_default_host(xics_host); diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c index e8e79f83d198..05dc30b80e29 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/commproc.c @@ -50,7 +50,6 @@ static uint host_end; /* end + 1 */ cpm8xx_t *cpmp; /* Pointer to comm processor space */ cpic8xx_t *cpic_reg; -static struct device_node *cpm_pic_node; static struct irq_host *cpm_pic_host; static void cpm_mask_irq(unsigned int irq) @@ -97,7 +96,7 @@ int cpm_get_irq(void) static int cpm_pic_host_match(struct irq_host *h, struct device_node *node) { - return cpm_pic_node == node; + return h->of_node == node; } static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, @@ -165,9 +164,8 @@ unsigned int cpm_pic_init(void) out_be32(&cpic_reg->cpic_cimr, 0); - cpm_pic_node = of_node_get(np); - - cpm_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm_pic_host_ops, 64); + cpm_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR, + 64, &cpm_pic_host_ops, 64); if (cpm_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); sirq = NO_IRQ; diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index eabfe06fe05c..d9ab30c66ebf 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -50,7 +50,6 @@ static intctl_cpm2_t *cpm2_intctl; -static struct device_node *cpm2_pic_node; static struct irq_host *cpm2_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; @@ -208,7 +207,7 @@ unsigned int cpm2_get_irq(void) static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node) { - return cpm2_pic_node == node; + return h->of_node == node; } static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, @@ -273,8 +272,8 @@ void cpm2_pic_init(struct device_node *node) out_be32(&cpm2_intctl->ic_scprrl, 0x05309770); /* create a legacy host */ - cpm2_pic_node = of_node_get(node); - cpm2_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64); + cpm2_pic_host = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR, + 64, &cpm2_pic_host_ops, 64); if (cpm2_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); return; diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index ad87adc975bc..7c1b27ac7d3c 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -25,7 +25,6 @@ static unsigned char cached_8259[2] = { 0xff, 0xff }; static DEFINE_SPINLOCK(i8259_lock); -static struct device_node *i8259_node; static struct irq_host *i8259_host; /* @@ -165,7 +164,7 @@ static struct resource pic_edgectrl_iores = { static int i8259_host_match(struct irq_host *h, struct device_node *node) { - return i8259_node == NULL || i8259_node == node; + return h->of_node == NULL || h->of_node == node; } static int i8259_host_map(struct irq_host *h, unsigned int virq, @@ -276,9 +275,8 @@ void i8259_init(struct device_node *node, unsigned long intack_addr) spin_unlock_irqrestore(&i8259_lock, flags); /* create a legacy host */ - if (node) - i8259_node = of_node_get(node); - i8259_host = irq_alloc_host(IRQ_HOST_MAP_LEGACY, 0, &i8259_host_ops, 0); + i8259_host = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LEGACY, + 0, &i8259_host_ops, 0); if (i8259_host == NULL) { printk(KERN_ERR "i8259: failed to allocate irq host !\n"); return; diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 473c415e9e25..05a56e55804c 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -511,10 +511,8 @@ static struct irq_chip ipic_irq_chip = { static int ipic_host_match(struct irq_host *h, struct device_node *node) { - struct ipic *ipic = h->host_data; - /* Exact match, unless ipic node is NULL */ - return ipic->of_node == NULL || ipic->of_node == node; + return h->of_node == NULL || h->of_node == node; } static int ipic_host_map(struct irq_host *h, unsigned int virq, @@ -568,9 +566,8 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) return NULL; memset(ipic, 0, sizeof(struct ipic)); - ipic->of_node = of_node_get(node); - ipic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, + ipic->irqhost = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR, NR_IPIC_INTS, &ipic_host_ops, 0); if (ipic->irqhost == NULL) { diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h index c28e589877eb..bb309a501b2d 100644 --- a/arch/powerpc/sysdev/ipic.h +++ b/arch/powerpc/sysdev/ipic.h @@ -48,9 +48,6 @@ struct ipic { /* The "linux" controller struct */ struct irq_chip hc_irq; - - /* The device node of the interrupt controller */ - struct device_node *of_node; }; struct ipic_info { diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 2fc2bcd79b5e..f20a4d43d104 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -19,7 +19,6 @@ extern int cpm_get_irq(struct pt_regs *regs); -static struct device_node *mpc8xx_pic_node; static struct irq_host *mpc8xx_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; @@ -122,7 +121,7 @@ unsigned int mpc8xx_get_irq(void) static int mpc8xx_pic_host_match(struct irq_host *h, struct device_node *node) { - return mpc8xx_pic_node == node; + return h->of_node == node; } static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, @@ -176,22 +175,24 @@ int mpc8xx_pic_init(void) return -ENOMEM; } - mpc8xx_pic_node = of_node_get(np); - ret = of_address_to_resource(np, 0, &res); - of_node_put(np); if (ret) - return ret; + goto out; siu_reg = (void *)ioremap(res.start, res.end - res.start + 1); - if (siu_reg == NULL) - return -EINVAL; + if (siu_reg == NULL) { + ret = -EINVAL; + goto out; + } - mpc8xx_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &mpc8xx_pic_host_ops, 64); + mpc8xx_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR, + 64, &mpc8xx_pic_host_ops, 64); if (mpc8xx_pic_host == NULL) { printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); ret = -ENOMEM; } +out: + of_node_put(np); return ret; } diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 74c64c0d3b71..25a81f73cecf 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -271,7 +271,7 @@ static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, { rb->dbase = mpic->dcr_base; rb->doff = offset; - rb->dhost = dcr_map(mpic->of_node, rb->dbase + rb->doff, size); + rb->dhost = dcr_map(mpic->irqhost->of_node, rb->dbase + rb->doff, size); BUG_ON(!DCR_MAP_OK(rb->dhost)); } @@ -861,10 +861,8 @@ static struct irq_chip mpic_irq_ht_chip = { static int mpic_host_match(struct irq_host *h, struct device_node *node) { - struct mpic *mpic = h->host_data; - /* Exact match, unless mpic node is NULL */ - return mpic->of_node == NULL || mpic->of_node == node; + return h->of_node == NULL || h->of_node == node; } static int mpic_host_map(struct irq_host *h, unsigned int virq, @@ -985,10 +983,9 @@ struct mpic * __init mpic_alloc(struct device_node *node, memset(mpic, 0, sizeof(struct mpic)); mpic->name = name; - mpic->of_node = of_node_get(node); - mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, isu_size, - &mpic_host_ops, + mpic->irqhost = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR, + isu_size, &mpic_host_ops, flags & MPIC_LARGE_VECTORS ? 2048 : 256); if (mpic->irqhost == NULL) { of_node_put(node); diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index b076793033c2..9ca4d8f444ff 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c @@ -117,16 +117,17 @@ static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic) int i, len; const u32 *p; - p = of_get_property(mpic->of_node, "msi-available-ranges", &len); + p = of_get_property(mpic->irqhost->of_node, + "msi-available-ranges", &len); if (!p) { pr_debug("mpic: no msi-available-ranges property found on %s\n", - mpic->of_node->full_name); + mpic->irqhost->of_node->full_name); return -ENODEV; } if (len % 8 != 0) { printk(KERN_WARNING "mpic: Malformed msi-available-ranges " - "property on %s\n", mpic->of_node->full_name); + "property on %s\n", mpic->irqhost->of_node->full_name); return -EINVAL; } diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index 01d316287772..a145bfd003c7 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -204,7 +204,7 @@ static struct irq_chip mv64x60_chip_gpp = { static int mv64x60_host_match(struct irq_host *h, struct device_node *np) { - return mv64x60_irq_host->host_data == np; + return h->of_node == np; } static struct irq_chip *mv64x60_chips[] = { @@ -253,14 +253,12 @@ void __init mv64x60_init_irq(void) np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-pic"); reg = of_get_property(np, "reg", &size); paddr = of_translate_address(np, reg); - of_node_put(np); mv64x60_irq_reg_base = ioremap(paddr, reg[1]); - mv64x60_irq_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, MV64x60_NUM_IRQS, + mv64x60_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, + MV64x60_NUM_IRQS, &mv64x60_host_ops, MV64x60_NUM_IRQS); - mv64x60_irq_host->host_data = np; - spin_lock_irqsave(&mv64x60_lock, flags); out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK, mv64x60_cached_gpp_mask); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 4d1dcb45963d..55e6f394af82 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -245,10 +245,8 @@ static struct irq_chip qe_ic_irq_chip = { static int qe_ic_host_match(struct irq_host *h, struct device_node *node) { - struct qe_ic *qe_ic = h->host_data; - /* Exact match, unless qe_ic node is NULL */ - return qe_ic->of_node == NULL || qe_ic->of_node == node; + return h->of_node == NULL || h->of_node == node; } static int qe_ic_host_map(struct irq_host *h, unsigned int virq, @@ -352,9 +350,8 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags) return; memset(qe_ic, 0, sizeof(struct qe_ic)); - qe_ic->of_node = of_node_get(node); - qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, + qe_ic->irqhost = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR, NR_QE_IC_INTS, &qe_ic_host_ops, 0); if (qe_ic->irqhost == NULL) { of_node_put(node); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h index 9a631adb189d..c1361d005a8a 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.h +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h @@ -84,9 +84,6 @@ struct qe_ic { /* The "linux" controller struct */ struct irq_chip hc_irq; - /* The device node of the interrupt controller */ - struct device_node *of_node; - /* VIRQ numbers of QE high/low irqs */ unsigned int virq_high; unsigned int virq_low; diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index cf0bfbd73401..b41492a8d600 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -52,7 +52,6 @@ u32 tsi108_pci_cfg_base; static u32 tsi108_pci_cfg_phys; u32 tsi108_csr_vir_base; -static struct device_node *pci_irq_node; static struct irq_host *pci_irq_host; extern u32 get_vir_csrbase(void); @@ -407,7 +406,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq, static int pci_irq_host_match(struct irq_host *h, struct device_node *node) { - return pci_irq_node == node; + return h->of_node == node; } static struct irq_host_ops pci_irq_host_ops = { @@ -433,10 +432,11 @@ void __init tsi108_pci_int_init(struct device_node *node) { DBG("Tsi108_pci_int_init: initializing PCI interrupts\n"); - pci_irq_node = of_node_get(node); - pci_irq_host = irq_alloc_host(IRQ_HOST_MAP_LEGACY, 0, &pci_irq_host_ops, 0); + pci_irq_host = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LEGACY, + 0, &pci_irq_host_ops, 0); if (pci_irq_host == NULL) { printk(KERN_ERR "pci_irq_host: failed to allocate irq host !\n"); + of_node_put(node); return; } diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 47180b3fca56..bf3766754173 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -56,9 +56,6 @@ struct uic { /* For secondary UICs, the cascade interrupt's irqaction */ struct irqaction cascade; - - /* The device node of the interrupt controller */ - struct device_node *of_node; }; static void uic_unmask_irq(unsigned int virq) @@ -220,8 +217,7 @@ out_unlock: static int uic_host_match(struct irq_host *h, struct device_node *node) { - struct uic *uic = h->host_data; - return uic->of_node == node; + return h->of_node == node; } static int uic_host_map(struct irq_host *h, unsigned int virq, @@ -291,7 +287,6 @@ static struct uic * __init uic_init_one(struct device_node *node) memset(uic, 0, sizeof(*uic)); spin_lock_init(&uic->lock); - uic->of_node = of_node_get(node); indexp = of_get_property(node, "cell-index", &len); if (!indexp || (len != sizeof(u32))) { printk(KERN_ERR "uic: Device node %s has missing or invalid " @@ -308,8 +303,8 @@ static struct uic * __init uic_init_one(struct device_node *node) } uic->dcrbase = *dcrreg; - uic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_UIC_INTS, - &uic_host_ops, -1); + uic->irqhost = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR, + NR_UIC_INTS, &uic_host_ops, -1); if (! uic->irqhost) { of_node_put(node); return NULL; /* FIXME: panic? */ diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index 0485c53db2b5..1392db456523 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h @@ -124,6 +124,9 @@ struct irq_host { struct irq_host_ops *ops; void *host_data; irq_hw_number_t inval_irq; + + /* Optional device node pointer */ + struct device_node *of_node; }; /* The main irq map itself is an array of NR_IRQ entries containing the @@ -142,7 +145,7 @@ extern irq_hw_number_t virq_to_hw(unsigned int virq); /** * irq_alloc_host - Allocate a new irq_host data structure - * @node: device-tree node of the interrupt controller + * @of_node: optional device-tree node of the interrupt controller * @revmap_type: type of reverse mapping to use * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map * @ops: map/unmap host callbacks @@ -156,7 +159,8 @@ extern irq_hw_number_t virq_to_hw(unsigned int virq); * later during boot automatically (the reverse mapping will use the slow path * until that happens). */ -extern struct irq_host *irq_alloc_host(unsigned int revmap_type, +extern struct irq_host *irq_alloc_host(struct device_node *of_node, + unsigned int revmap_type, unsigned int revmap_arg, struct irq_host_ops *ops, irq_hw_number_t inval_irq); diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index 262db6b8da73..0eb3ab9ec2bb 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -240,9 +240,6 @@ struct mpic_irq_save { /* The instance data of a given MPIC */ struct mpic { - /* The device node of the interrupt controller */ - struct device_node *of_node; - /* The remapper for this MPIC */ struct irq_host *irqhost; From 8528ab84ebe7a1eeed9b0acc808df86663d506c0 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 28 Aug 2007 18:47:55 +1000 Subject: [PATCH 0180/2804] [POWERPC] Invert null match behaviour for irq_hosts Currently if you don't specify a match callback for your irq_host it's assumed you match everything. This is a kind of opt-out approach, and turns out to be the exception rather than the rule. So change the semantics to be opt-in, ie. you don't match anything unless you provide a match callback. This in itself isn't very useful, but will allow us to provide a default match implementation in a subsequent patch. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/irq.c | 2 +- arch/powerpc/platforms/celleb/interrupt.c | 7 +++++++ arch/powerpc/platforms/iseries/irq.c | 7 +++++++ arch/powerpc/platforms/ps3/interrupt.c | 7 +++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 79b451247b89..30fb8e2c5c9d 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -523,7 +523,7 @@ struct irq_host *irq_find_host(struct device_node *node) */ spin_lock_irqsave(&irq_big_lock, flags); list_for_each_entry(h, &irq_hosts, link) - if (h->ops->match == NULL || h->ops->match(h, node)) { + if (h->ops->match != NULL && h->ops->match(h, node)) { found = h; break; } diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/celleb/interrupt.c index 4ecdf06e421b..c7c68ca70c82 100644 --- a/arch/powerpc/platforms/celleb/interrupt.c +++ b/arch/powerpc/platforms/celleb/interrupt.c @@ -175,11 +175,18 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } +static int beatic_pic_host_match(struct irq_host *h, struct device_node *np) +{ + /* Match all */ + return 1; +} + static struct irq_host_ops beatic_pic_host_ops = { .map = beatic_pic_host_map, .remap = beatic_pic_host_remap, .unmap = beatic_pic_host_unmap, .xlate = beatic_pic_host_xlate, + .match = beatic_pic_host_match, }; /* diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 36667460c922..701d9297c207 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -346,8 +346,15 @@ static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, return 0; } +static int iseries_irq_host_match(struct irq_host *h, struct device_node *np) +{ + /* Match all */ + return 1; +} + static struct irq_host_ops iseries_irq_host_ops = { .map = iseries_irq_host_map, + .match = iseries_irq_host_match, }; /* diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 30b9f4c6eb55..3a6db04aa940 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -673,9 +673,16 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq, return 0; } +static int ps3_host_match(struct irq_host *h, struct device_node *np) +{ + /* Match all */ + return 1; +} + static struct irq_host_ops ps3_host_ops = { .map = ps3_host_map, .unmap = ps3_host_unmap, + .match = ps3_host_match, }; void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) From 6815800601d3e46b976c868e4e85fb6de32b9133 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 28 Aug 2007 18:47:55 +1000 Subject: [PATCH 0181/2804] [POWERPC] Provide a default irq_host match, which matches on an exact of_node The most common match semantic is an exact match based on the device node. So provide a default implementation that does this, and hook it up if no match routine is specified. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/irq.c | 10 +++++++++- arch/powerpc/platforms/52xx/mpc52xx_pic.c | 7 ------- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 6 ------ arch/powerpc/platforms/cell/axon_msi.c | 6 ------ arch/powerpc/platforms/cell/spider-pic.c | 6 ------ arch/powerpc/sysdev/commproc.c | 6 ------ arch/powerpc/sysdev/cpm2_pic.c | 6 ------ arch/powerpc/sysdev/mpc8xx_pic.c | 6 ------ arch/powerpc/sysdev/mv64x60_pic.c | 6 ------ arch/powerpc/sysdev/tsi108_pci.c | 6 ------ arch/powerpc/sysdev/uic.c | 6 ------ 11 files changed, 9 insertions(+), 62 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 30fb8e2c5c9d..d5c7e4cf2b39 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -418,6 +418,11 @@ irq_hw_number_t virq_to_hw(unsigned int virq) } EXPORT_SYMBOL_GPL(virq_to_hw); +static int default_irq_host_match(struct irq_host *h, struct device_node *np) +{ + return h->of_node != NULL && h->of_node == np; +} + __init_refok struct irq_host *irq_alloc_host(struct device_node *of_node, unsigned int revmap_type, unsigned int revmap_arg, @@ -449,6 +454,9 @@ __init_refok struct irq_host *irq_alloc_host(struct device_node *of_node, host->ops = ops; host->of_node = of_node; + if (host->ops->match == NULL) + host->ops->match = default_irq_host_match; + spin_lock_irqsave(&irq_big_lock, flags); /* If it's a legacy controller, check for duplicates and @@ -523,7 +531,7 @@ struct irq_host *irq_find_host(struct device_node *node) */ spin_lock_irqsave(&irq_big_lock, flags); list_for_each_entry(h, &irq_hosts, link) - if (h->ops->match != NULL && h->ops->match(h, node)) { + if (h->ops->match(h, node)) { found = h; break; } diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 1d793e4b8d56..0f4ca8a2b777 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -241,12 +241,6 @@ static struct irq_chip mpc52xx_sdma_irqchip = { * irq_host */ -static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) -{ - pr_debug("%s: node=%p\n", __func__, node); - return h->of_node == node; -} - static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, u32 * intspec, unsigned int intsize, irq_hw_number_t * out_hwirq, @@ -367,7 +361,6 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, } static struct irq_host_ops mpc52xx_irqhost_ops = { - .match = mpc52xx_irqhost_match, .xlate = mpc52xx_irqhost_xlate, .map = mpc52xx_irqhost_map, }; diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 91ddbd2f477d..40087952935a 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -398,11 +398,6 @@ m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc) } } -static int pci_pic_host_match(struct irq_host *h, struct device_node *node) -{ - return h->of_node == node; -} - static int pci_pic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { @@ -418,7 +413,6 @@ static void pci_host_unmap(struct irq_host *h, unsigned int virq) } static struct irq_host_ops pci_pic_host_ops = { - .match = pci_pic_host_match, .map = pci_pic_host_map, .unmap = pci_host_unmap, }; diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index bdd97bb2446d..74407afddf46 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -294,13 +294,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int msic_host_match(struct irq_host *host, struct device_node *dn) -{ - return host->of_node == dn; -} - static struct irq_host_ops msic_host_ops = { - .match = msic_host_match, .map = msic_host_map, }; diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 4309c2cbbeb9..3f4b4aef756d 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -175,11 +175,6 @@ static struct irq_chip spider_pic = { .set_type = spider_set_irq_type, }; -static int spider_host_match(struct irq_host *h, struct device_node *node) -{ - return h->of_node == node; -} - static int spider_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { @@ -206,7 +201,6 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct, } static struct irq_host_ops spider_host_ops = { - .match = spider_host_match, .map = spider_host_map, .xlate = spider_host_xlate, }; diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c index 05dc30b80e29..b562afc4e50c 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/commproc.c @@ -94,11 +94,6 @@ int cpm_get_irq(void) return irq_linear_revmap(cpm_pic_host, cpm_vec); } -static int cpm_pic_host_match(struct irq_host *h, struct device_node *node) -{ - return h->of_node == node; -} - static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { @@ -126,7 +121,6 @@ static struct irqaction cpm_error_irqaction = { }; static struct irq_host_ops cpm_pic_host_ops = { - .match = cpm_pic_host_match, .map = cpm_pic_host_map, }; diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index d9ab30c66ebf..d5b36e0ecbda 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -205,11 +205,6 @@ unsigned int cpm2_get_irq(void) return irq_linear_revmap(cpm2_pic_host, irq); } -static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node) -{ - return h->of_node == node; -} - static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { @@ -233,7 +228,6 @@ static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, } static struct irq_host_ops cpm2_pic_host_ops = { - .match = cpm2_pic_host_match, .map = cpm2_pic_host_map, .xlate = cpm2_pic_host_xlate, }; diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index f20a4d43d104..565156ae65bc 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -119,11 +119,6 @@ unsigned int mpc8xx_get_irq(void) } -static int mpc8xx_pic_host_match(struct irq_host *h, struct device_node *node) -{ - return h->of_node == node; -} - static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { @@ -157,7 +152,6 @@ static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, static struct irq_host_ops mpc8xx_pic_host_ops = { - .match = mpc8xx_pic_host_match, .map = mpc8xx_pic_host_map, .xlate = mpc8xx_pic_host_xlate, }; diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index a145bfd003c7..19e6ef263797 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -202,11 +202,6 @@ static struct irq_chip mv64x60_chip_gpp = { * mv64x60_host_ops functions */ -static int mv64x60_host_match(struct irq_host *h, struct device_node *np) -{ - return h->of_node == np; -} - static struct irq_chip *mv64x60_chips[] = { [MV64x60_LEVEL1_LOW] = &mv64x60_chip_low, [MV64x60_LEVEL1_HIGH] = &mv64x60_chip_high, @@ -228,7 +223,6 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq, } static struct irq_host_ops mv64x60_host_ops = { - .match = mv64x60_host_match, .map = mv64x60_host_map, }; diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index b41492a8d600..31d3d33d91fc 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -404,13 +404,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int pci_irq_host_match(struct irq_host *h, struct device_node *node) -{ - return h->of_node == node; -} - static struct irq_host_ops pci_irq_host_ops = { - .match = pci_irq_host_match, .map = pci_irq_host_map, .xlate = pci_irq_host_xlate, }; diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index bf3766754173..5149716c734d 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -215,11 +215,6 @@ out_unlock: spin_unlock(&desc->lock); } -static int uic_host_match(struct irq_host *h, struct device_node *node) -{ - return h->of_node == node; -} - static int uic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { @@ -249,7 +244,6 @@ static int uic_host_xlate(struct irq_host *h, struct device_node *ct, } static struct irq_host_ops uic_host_ops = { - .match = uic_host_match, .map = uic_host_map, .xlate = uic_host_xlate, }; From 7866291d4cabf5491d4ecb62787308f8b8958f59 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 28 Aug 2007 18:47:56 +1000 Subject: [PATCH 0182/2804] [POWERPC] Initialise hwirq for legacy irqs Although no one uses the hwirq value for legacy irqs at the moment, we should really setup the correct value in the irq_map. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index d5c7e4cf2b39..1339f32b44b5 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -487,7 +487,7 @@ __init_refok struct irq_host *irq_alloc_host(struct device_node *of_node, host->inval_irq = 0; /* setup us as the host for all legacy interrupts */ for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { - irq_map[i].hwirq = 0; + irq_map[i].hwirq = i; smp_wmb(); irq_map[i].host = host; smp_wmb(); From 60b332e755da7dbf32f1660973ce4f97ebf05d05 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 28 Aug 2007 18:47:57 +1000 Subject: [PATCH 0183/2804] [POWERPC] Export virq mapping via debugfs This adds a debugfs file "powerpc/virq_mapping", which shows the virtual to real mapping of irq numbers. Enable it with CONFIG_VIRQ_DEBUG. Signed-off-by: Zhang Wei Signed-off-by: Chen Gong Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig.debug | 10 ++++++ arch/powerpc/kernel/irq.c | 63 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 22acece95b11..c38bc2237057 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -124,6 +124,16 @@ config IRQSTACKS for handling hard and soft interrupts. This can help avoid overflowing the process kernel stacks. +config VIRQ_DEBUG + bool "Expose hardware/virtual IRQ mapping via debugfs" + depends on DEBUG_FS && PPC_MERGE + help + This option will show the mapping relationship between hardware irq + numbers and virtual irq numbers. The mapping is exposed via debugfs + in the file powerpc/virq_mapping. + + If you don't know what this means you don't need it. + config BDI_SWITCH bool "Include BDI-2000 user context switcher" depends on DEBUG_KERNEL && PPC32 diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 1339f32b44b5..0e47c8cfc979 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -1006,6 +1007,68 @@ static int irq_late_init(void) } arch_initcall(irq_late_init); +#ifdef CONFIG_VIRQ_DEBUG +static int virq_debug_show(struct seq_file *m, void *private) +{ + unsigned long flags; + irq_desc_t *desc; + const char *p; + char none[] = "none"; + int i; + + seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq", + "chip name", "host name"); + + for (i = 1; i < NR_IRQS; i++) { + desc = get_irq_desc(i); + spin_lock_irqsave(&desc->lock, flags); + + if (desc->action && desc->action->handler) { + seq_printf(m, "%5d ", i); + seq_printf(m, "0x%05lx ", virq_to_hw(i)); + + if (desc->chip && desc->chip->typename) + p = desc->chip->typename; + else + p = none; + seq_printf(m, "%-15s ", p); + + if (irq_map[i].host && irq_map[i].host->of_node) + p = irq_map[i].host->of_node->full_name; + else + p = none; + seq_printf(m, "%s\n", p); + } + + spin_unlock_irqrestore(&desc->lock, flags); + } + + return 0; +} + +static int virq_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, virq_debug_show, inode->i_private); +} + +static const struct file_operations virq_debug_fops = { + .open = virq_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init irq_debugfs_init(void) +{ + if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, + NULL, &virq_debug_fops)) + return -ENOMEM; + + return 0; +} +__initcall(irq_debugfs_init); +#endif /* CONFIG_VIRQ_DEBUG */ + #endif /* CONFIG_PPC_MERGE */ #ifdef CONFIG_PPC64 From a302cb9d95978505b18c12be0cd1e41556564f68 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 31 Aug 2007 13:58:51 +1000 Subject: [PATCH 0184/2804] [POWERPC] Export new __io{re,un}map_at() symbols Export new __io{re,un}map_at() symbols so modules can use them. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/mm/pgtable_64.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 3dfd10db931a..60fd52cd270f 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -228,5 +228,7 @@ void iounmap(volatile void __iomem *token) EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(ioremap_flags); EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(__ioremap_at); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(__iounmap); +EXPORT_SYMBOL(__iounmap_at); From 68c8404c742fdda2151b4bf6bd98419bf8118481 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Sep 2007 12:08:30 +1000 Subject: [PATCH 0185/2804] [POWERPC] pasemi: Add pasemi_pci_getcfgaddr() Add pasemi_pci_getcfgaddr(), to get the remapped address of a specific config register for a PCI device. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/pasemi.h | 2 ++ arch/powerpc/platforms/pasemi/pci.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h index be8495497611..6fd2fe75a608 100644 --- a/arch/powerpc/platforms/pasemi/pasemi.h +++ b/arch/powerpc/platforms/pasemi/pasemi.h @@ -6,6 +6,8 @@ extern void pas_pci_init(void); extern void __devinit pas_pci_irq_fixup(struct pci_dev *dev); extern void __devinit pas_pci_dma_dev_setup(struct pci_dev *dev); +extern void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset); + extern void __init alloc_iobmap_l2(void); extern void __init pasemi_idle_init(void); diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index 03d1d07aa2ac..fcfb3df3f1a9 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -175,3 +175,12 @@ void __init pas_pci_init(void) /* Use the common resource allocation mechanism */ pci_probe_only = 1; } + +void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset) +{ + struct pci_controller *hose; + + hose = pci_bus_to_host(bus); + + return pa_pxp_cfg_addr(hose, hose->number, dev->devfn, int offset) +} From 4d442331e57b7bbc28b5a20f7d069bc12e9c503e Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Sep 2007 12:08:50 +1000 Subject: [PATCH 0186/2804] [POWERPC] pasemi: Add workaround for erratum 5945 Erratum 5945 causes some of the registers on the PCIe root ports to not read correctly. Do a small dance to avoid this: Write an unused register, read the value and write it back. Thankfully this is not in a hot code path. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/pci.c | 62 ++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index fcfb3df3f1a9..b6a0ec45c695 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -51,6 +51,61 @@ static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose, return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset); } +static inline int is_root_port(int busno, int devfn) +{ + return ((busno == 0) && (PCI_FUNC(devfn) < 4) && + ((PCI_SLOT(devfn) == 16) || (PCI_SLOT(devfn) == 17))); +} + +static inline int is_5945_reg(int reg) +{ + return (((reg >= 0x18) && (reg < 0x34)) || + ((reg >= 0x158) && (reg < 0x178))); +} + +static int workaround_5945(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose; + void volatile __iomem *addr, *dummy; + int byte; + u32 tmp; + + if (!is_root_port(bus->number, devfn) || !is_5945_reg(offset)) + return 0; + + hose = pci_bus_to_host(bus); + + addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset & ~0x3); + byte = offset & 0x3; + + /* Workaround bug 5945: write 0 to a dummy register before reading, + * and write back what we read. We must read/write the full 32-bit + * contents so we need to shift and mask by hand. + */ + dummy = pa_pxp_cfg_addr(hose, bus->number, devfn, 0x10); + out_le32(dummy, 0); + tmp = in_le32(addr); + out_le32(addr, tmp); + + switch (len) { + case 1: + *val = (tmp >> (8*byte)) & 0xff; + break; + case 2: + if (byte == 0) + *val = tmp & 0xffff; + else + *val = (tmp >> 16) & 0xffff; + break; + default: + *val = tmp; + break; + } + + return 1; +} + static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { @@ -64,6 +119,9 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, if (!pa_pxp_offset_valid(bus->number, devfn, offset)) return PCIBIOS_BAD_REGISTER_NUMBER; + if (workaround_5945(bus, devfn, offset, len, val)) + return PCIBIOS_SUCCESSFUL; + addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset); /* @@ -180,7 +238,7 @@ void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset) { struct pci_controller *hose; - hose = pci_bus_to_host(bus); + hose = pci_bus_to_host(dev->bus); - return pa_pxp_cfg_addr(hose, hose->number, dev->devfn, int offset) + return (void __iomem *)pa_pxp_cfg_addr(hose, dev->bus->number, dev->devfn, offset); } From 2e1957fd47b9d4b7bf35be2ec3d4b5e3eefe5cc0 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Sep 2007 12:09:06 +1000 Subject: [PATCH 0187/2804] [POWERPC] pasemi: Export more SPRs to sysfs when CONFIG_DEBUG_KERNEL=y Export some of the implementation-specific registers via sysfs. Useful when debugging, etc. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/sysfs.c | 60 +++++++++++++++++++++++++++++++++++++ include/asm-powerpc/reg.h | 48 ++++++++++++++++++++++------- 2 files changed, 97 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 55d29ed4b7a0..d7835ba9fb8c 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -197,6 +197,36 @@ SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3); SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4); SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5); +#ifdef CONFIG_DEBUG_KERNEL +SYSFS_PMCSETUP(hid0, SPRN_HID0); +SYSFS_PMCSETUP(hid1, SPRN_HID1); +SYSFS_PMCSETUP(hid4, SPRN_HID4); +SYSFS_PMCSETUP(hid5, SPRN_HID5); +SYSFS_PMCSETUP(ima0, SPRN_PA6T_IMA0); +SYSFS_PMCSETUP(ima1, SPRN_PA6T_IMA1); +SYSFS_PMCSETUP(ima2, SPRN_PA6T_IMA2); +SYSFS_PMCSETUP(ima3, SPRN_PA6T_IMA3); +SYSFS_PMCSETUP(ima4, SPRN_PA6T_IMA4); +SYSFS_PMCSETUP(ima5, SPRN_PA6T_IMA5); +SYSFS_PMCSETUP(ima6, SPRN_PA6T_IMA6); +SYSFS_PMCSETUP(ima7, SPRN_PA6T_IMA7); +SYSFS_PMCSETUP(ima8, SPRN_PA6T_IMA8); +SYSFS_PMCSETUP(ima9, SPRN_PA6T_IMA9); +SYSFS_PMCSETUP(imaat, SPRN_PA6T_IMAAT); +SYSFS_PMCSETUP(btcr, SPRN_PA6T_BTCR); +SYSFS_PMCSETUP(pccr, SPRN_PA6T_PCCR); +SYSFS_PMCSETUP(rpccr, SPRN_PA6T_RPCCR); +SYSFS_PMCSETUP(der, SPRN_PA6T_DER); +SYSFS_PMCSETUP(mer, SPRN_PA6T_MER); +SYSFS_PMCSETUP(ber, SPRN_PA6T_BER); +SYSFS_PMCSETUP(ier, SPRN_PA6T_IER); +SYSFS_PMCSETUP(sier, SPRN_PA6T_SIER); +SYSFS_PMCSETUP(siar, SPRN_PA6T_SIAR); +SYSFS_PMCSETUP(tsr0, SPRN_PA6T_TSR0); +SYSFS_PMCSETUP(tsr1, SPRN_PA6T_TSR1); +SYSFS_PMCSETUP(tsr2, SPRN_PA6T_TSR2); +SYSFS_PMCSETUP(tsr3, SPRN_PA6T_TSR3); +#endif /* CONFIG_DEBUG_KERNEL */ static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL); @@ -228,6 +258,36 @@ static struct sysdev_attribute pa6t_attrs[] = { _SYSDEV_ATTR(pmc3, 0600, show_pa6t_pmc3, store_pa6t_pmc3), _SYSDEV_ATTR(pmc4, 0600, show_pa6t_pmc4, store_pa6t_pmc4), _SYSDEV_ATTR(pmc5, 0600, show_pa6t_pmc5, store_pa6t_pmc5), +#ifdef CONFIG_DEBUG_KERNEL + _SYSDEV_ATTR(hid0, 0600, show_hid0, store_hid0), + _SYSDEV_ATTR(hid1, 0600, show_hid1, store_hid1), + _SYSDEV_ATTR(hid4, 0600, show_hid4, store_hid4), + _SYSDEV_ATTR(hid5, 0600, show_hid5, store_hid5), + _SYSDEV_ATTR(ima0, 0600, show_ima0, store_ima0), + _SYSDEV_ATTR(ima1, 0600, show_ima1, store_ima1), + _SYSDEV_ATTR(ima2, 0600, show_ima2, store_ima2), + _SYSDEV_ATTR(ima3, 0600, show_ima3, store_ima3), + _SYSDEV_ATTR(ima4, 0600, show_ima4, store_ima4), + _SYSDEV_ATTR(ima5, 0600, show_ima5, store_ima5), + _SYSDEV_ATTR(ima6, 0600, show_ima6, store_ima6), + _SYSDEV_ATTR(ima7, 0600, show_ima7, store_ima7), + _SYSDEV_ATTR(ima8, 0600, show_ima8, store_ima8), + _SYSDEV_ATTR(ima9, 0600, show_ima9, store_ima9), + _SYSDEV_ATTR(imaat, 0600, show_imaat, store_imaat), + _SYSDEV_ATTR(btcr, 0600, show_btcr, store_btcr), + _SYSDEV_ATTR(pccr, 0600, show_pccr, store_pccr), + _SYSDEV_ATTR(rpccr, 0600, show_rpccr, store_rpccr), + _SYSDEV_ATTR(der, 0600, show_der, store_der), + _SYSDEV_ATTR(mer, 0600, show_mer, store_mer), + _SYSDEV_ATTR(ber, 0600, show_ber, store_ber), + _SYSDEV_ATTR(ier, 0600, show_ier, store_ier), + _SYSDEV_ATTR(sier, 0600, show_sier, store_sier), + _SYSDEV_ATTR(siar, 0600, show_siar, store_siar), + _SYSDEV_ATTR(tsr0, 0600, show_tsr0, store_tsr0), + _SYSDEV_ATTR(tsr1, 0600, show_tsr1, store_tsr1), + _SYSDEV_ATTR(tsr2, 0600, show_tsr2, store_tsr2), + _SYSDEV_ATTR(tsr3, 0600, show_tsr3, store_tsr3), +#endif /* CONFIG_DEBUG_KERNEL */ }; diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 281011e953ec..347de53e49af 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -518,21 +518,47 @@ #define PA6T_MMCR1_ES4 0x0000000000ff0000UL #define PA6T_MMCR1_ES5 0x00000000ff000000UL -#define SPRN_PA6T_SIAR 780 -#define SPRN_PA6T_UPMC0 771 -#define SPRN_PA6T_UPMC1 772 +#define SPRN_PA6T_UPMC0 771 /* User PerfMon Counter 0 */ +#define SPRN_PA6T_UPMC1 772 /* ... */ #define SPRN_PA6T_UPMC2 773 #define SPRN_PA6T_UPMC3 774 #define SPRN_PA6T_UPMC4 775 #define SPRN_PA6T_UPMC5 776 -#define SPRN_PA6T_UMMCR0 779 -#define SPRN_PA6T_UMMCR1 782 -#define SPRN_PA6T_PMC0 787 -#define SPRN_PA6T_PMC1 788 -#define SPRN_PA6T_PMC2 789 -#define SPRN_PA6T_PMC3 790 -#define SPRN_PA6T_PMC4 791 -#define SPRN_PA6T_PMC5 792 +#define SPRN_PA6T_UMMCR0 779 /* User Monitor Mode Control Register 0 */ +#define SPRN_PA6T_SIAR 780 /* Sampled Instruction Address */ +#define SPRN_PA6T_UMMCR1 782 /* User Monitor Mode Control Register 1 */ +#define SPRN_PA6T_SIER 785 /* Sampled Instruction Event Register */ +#define SPRN_PA6T_PMC0 787 +#define SPRN_PA6T_PMC1 788 +#define SPRN_PA6T_PMC2 789 +#define SPRN_PA6T_PMC3 790 +#define SPRN_PA6T_PMC4 791 +#define SPRN_PA6T_PMC5 792 +#define SPRN_PA6T_TSR0 793 /* Timestamp Register 0 */ +#define SPRN_PA6T_TSR1 794 /* Timestamp Register 1 */ +#define SPRN_PA6T_TSR2 799 /* Timestamp Register 2 */ +#define SPRN_PA6T_TSR3 784 /* Timestamp Register 3 */ + +#define SPRN_PA6T_IER 981 /* Icache Error Register */ +#define SPRN_PA6T_DER 982 /* Dcache Error Register */ +#define SPRN_PA6T_BER 862 /* BIU Error Address Register */ +#define SPRN_PA6T_MER 849 /* MMU Error Register */ + +#define SPRN_PA6T_IMA0 880 /* Instruction Match Array 0 */ +#define SPRN_PA6T_IMA1 881 /* ... */ +#define SPRN_PA6T_IMA2 882 +#define SPRN_PA6T_IMA3 883 +#define SPRN_PA6T_IMA4 884 +#define SPRN_PA6T_IMA5 885 +#define SPRN_PA6T_IMA6 886 +#define SPRN_PA6T_IMA7 887 +#define SPRN_PA6T_IMA8 888 +#define SPRN_PA6T_IMA9 889 +#define SPRN_PA6T_BTCR 978 /* Breakpoint and Tagging Control Register */ +#define SPRN_PA6T_IMAAT 979 /* Instruction Match Array Action Table */ +#define SPRN_PA6T_PCCR 1019 /* Power Counter Control Register */ +#define SPRN_PA6T_RPCCR 1021 /* Retire PC Trace Control Register */ + #else /* 32-bit */ #define SPRN_MMCR0 952 /* Monitor Mode Control Register 0 */ From cd7834167ffb66b470e4d9edb10efb5c1a2dfe7f Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Sep 2007 12:09:23 +1000 Subject: [PATCH 0188/2804] [POWERPC] pasemi: Print more information at machine check Add printout of some SoC error status registers, and dump the SLB contents for those machine check events where it makes sense. Since we can't go about and ioremap registers at machine check time, and we generally want to do as little as possible to print out the information, pre-build a table of the registers to dump and their address in the common PCI config space range. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/setup.c | 110 +++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 05def6282f83..fe9a5d631431 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -39,8 +39,21 @@ #include "pasemi.h" +/* SDC reset register, must be pre-mapped at reset time */ static void __iomem *reset_reg; +/* Various error status registers, must be pre-mapped at MCE time */ + +#define MAX_MCE_REGS 32 +struct mce_regs { + char *name; + void __iomem *addr; +}; + +static struct mce_regs mce_regs[MAX_MCE_REGS]; +static int num_mce_regs; + + static void pas_restart(char *cmd) { printk("Restarting...\n"); @@ -106,6 +119,59 @@ void __init pas_setup_arch(void) pasemi_idle_init(); } +static int __init pas_setup_mce_regs(void) +{ + struct pci_dev *dev; + int reg; + + if (!machine_is(pasemi)) + return -ENODEV; + + /* Remap various SoC status registers for use by the MCE handler */ + + reg = 0; + + dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, NULL); + while (dev && reg < MAX_MCE_REGS) { + mce_regs[reg].name = kasprintf(GFP_KERNEL, + "mc%d_mcdebug_errsta", reg); + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730); + dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev); + reg++; + } + + dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); + if (dev && reg+4 < MAX_MCE_REGS) { + mce_regs[reg].name = "iobdbg_IntStatus1"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x438); + reg++; + mce_regs[reg].name = "iobdbg_IOCTbusIntDbgReg"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x454); + reg++; + mce_regs[reg].name = "iobiom_IntStatus"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc10); + reg++; + mce_regs[reg].name = "iobiom_IntDbgReg"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc1c); + reg++; + } + + dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa009, NULL); + if (dev && reg+2 < MAX_MCE_REGS) { + mce_regs[reg].name = "l2csts_IntStatus"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x200); + reg++; + mce_regs[reg].name = "l2csts_Cnt"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x214); + reg++; + } + + num_mce_regs = reg; + + return 0; +} +device_initcall(pas_setup_mce_regs); + static __init void pas_init_IRQ(void) { struct device_node *np; @@ -166,25 +232,34 @@ static int pas_machine_check_handler(struct pt_regs *regs) { int cpu = smp_processor_id(); unsigned long srr0, srr1, dsisr; + int dump_slb = 0; + int i; srr0 = regs->nip; srr1 = regs->msr; dsisr = mfspr(SPRN_DSISR); printk(KERN_ERR "Machine Check on CPU %d\n", cpu); - printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); - printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); + printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); + printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); + printk(KERN_ERR "BER 0x%016lx MER 0x%016lx\n", mfspr(SPRN_PA6T_BER), + mfspr(SPRN_PA6T_MER)); + printk(KERN_ERR "IER 0x%016lx DER 0x%016lx\n", mfspr(SPRN_PA6T_IER), + mfspr(SPRN_PA6T_DER)); printk(KERN_ERR "Cause:\n"); if (srr1 & 0x200000) printk(KERN_ERR "Signalled by SDC\n"); + if (srr1 & 0x100000) { printk(KERN_ERR "Load/Store detected error:\n"); if (dsisr & 0x8000) printk(KERN_ERR "D-cache ECC double-bit error or bus error\n"); if (dsisr & 0x4000) printk(KERN_ERR "LSU snoop response error\n"); - if (dsisr & 0x2000) + if (dsisr & 0x2000) { printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n"); + dump_slb = 1; + } if (dsisr & 0x1000) printk(KERN_ERR "Recoverable Duptags\n"); if (dsisr & 0x800) @@ -192,13 +267,40 @@ static int pas_machine_check_handler(struct pt_regs *regs) if (dsisr & 0x400) printk(KERN_ERR "TLB parity error count overflow\n"); } + if (srr1 & 0x80000) printk(KERN_ERR "Bus Error\n"); - if (srr1 & 0x40000) + + if (srr1 & 0x40000) { printk(KERN_ERR "I-side SLB multiple hit\n"); + dump_slb = 1; + } + if (srr1 & 0x20000) printk(KERN_ERR "I-cache parity error hit\n"); + if (num_mce_regs == 0) + printk(KERN_ERR "No MCE registers mapped yet, can't dump\n"); + else + printk(KERN_ERR "SoC debug registers:\n"); + + for (i = 0; i < num_mce_regs; i++) + printk(KERN_ERR "%s: 0x%08x\n", mce_regs[i].name, + in_le32(mce_regs[i].addr)); + + if (dump_slb) { + unsigned long e, v; + int i; + + printk(KERN_ERR "slb contents:\n"); + for (i = 0; i < SLB_NUM_ENTRIES; i++) { + asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i)); + asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i)); + printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v); + } + } + + /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ return !!(srr1 & 0x2); } From 3850169dbddcc9e53fd550eb093af7da5dfcefa9 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Sep 2007 12:09:45 +1000 Subject: [PATCH 0189/2804] [POWERPC] pasemi: Move pasemi_idle_init() to late_initcall() Move pasemi_idle_init() to be a late_initcall instead of being called from setup_arch(). This way the cpufreq driver has a chance to initialize and save away the boot time astate before we go to idle for the first time. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/idle.c | 8 +++++++- arch/powerpc/platforms/pasemi/pasemi.h | 2 -- arch/powerpc/platforms/pasemi/setup.c | 2 -- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c index 3c962d5757be..d8e1fcc78513 100644 --- a/arch/powerpc/platforms/pasemi/idle.c +++ b/arch/powerpc/platforms/pasemi/idle.c @@ -72,8 +72,11 @@ static int pasemi_system_reset_exception(struct pt_regs *regs) return 1; } -void __init pasemi_idle_init(void) +static int __init pasemi_idle_init(void) { + if (!machine_is(pasemi)) + return -ENODEV; + #ifndef CONFIG_PPC_PASEMI_CPUFREQ printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); current_mode = 0; @@ -82,7 +85,10 @@ void __init pasemi_idle_init(void) ppc_md.system_reset_exception = pasemi_system_reset_exception; ppc_md.power_save = modes[current_mode].entry; printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); + + return 0; } +late_initcall(pasemi_idle_init); static int __init idle_param(char *p) { diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h index 6fd2fe75a608..516acabb4e96 100644 --- a/arch/powerpc/platforms/pasemi/pasemi.h +++ b/arch/powerpc/platforms/pasemi/pasemi.h @@ -10,8 +10,6 @@ extern void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset); extern void __init alloc_iobmap_l2(void); -extern void __init pasemi_idle_init(void); - /* Power savings modes, implemented in asm */ extern void idle_spin(void); extern void idle_doze(void); diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index fe9a5d631431..5ddf40a66ae8 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -115,8 +115,6 @@ void __init pas_setup_arch(void) /* Remap SDC register for doing reset */ /* XXXOJN This should maybe come out of the device tree */ reset_reg = ioremap(0xfc101100, 4); - - pasemi_idle_init(); } static int __init pas_setup_mce_regs(void) From 01f1c735f57548e6b862e815cc845e452405643d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Sep 2007 12:41:09 +1000 Subject: [PATCH 0190/2804] [POWERPC] Remove unused platform_machine_check() Remove leftover cruft from ARCH=ppc. There are no users of platform_machine_check() in ARCH=powerpc, and none should be added (they should use ppc_md.machine_check_handler instead). Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/traps.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index d8502e377518..ccfc99dad061 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -324,15 +324,6 @@ static inline int check_io_access(struct pt_regs *regs) #define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) #endif -/* - * This is "fall-back" implementation for configurations - * which don't provide platform-specific machine check info - */ -void __attribute__ ((weak)) -platform_machine_check(struct pt_regs *regs) -{ -} - void machine_check_exception(struct pt_regs *regs) { int recover = 0; @@ -480,12 +471,6 @@ void machine_check_exception(struct pt_regs *regs) } #endif /* CONFIG_4xx */ - /* - * Optional platform-provided routine to print out - * additional info, e.g. bus error registers. - */ - platform_machine_check(regs); - if (debugger_fault_handler(regs)) return; die("Machine check", regs, SIGBUS); From a416561bf790d55db68b2980c2a6951981018041 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Sep 2007 12:42:30 +1000 Subject: [PATCH 0191/2804] [POWERPC] Move lowlevel runlatch calls under cpu feature control There's no need to call the runlatch on functions on processors that don't implement them (CPU_FTR_CTRL). Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 2 ++ include/asm-powerpc/exception.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 33c4e8cab0ba..cec59089e48c 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -656,7 +656,9 @@ hardware_interrupt_common: FINISH_NAP hardware_interrupt_entry: DISABLE_INTS +BEGIN_FTR_SECTION bl .ppc64_runlatch_on +END_FTR_SECTION_IFSET(CPU_FTR_CTRL) addi r3,r1,STACK_FRAME_OVERHEAD bl .do_IRQ b .ret_from_except_lite diff --git a/include/asm-powerpc/exception.h b/include/asm-powerpc/exception.h index d850c8ea5903..39abdb02fdef 100644 --- a/include/asm-powerpc/exception.h +++ b/include/asm-powerpc/exception.h @@ -282,7 +282,9 @@ label##_common: \ EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ FINISH_NAP; \ DISABLE_INTS; \ +BEGIN_FTR_SECTION \ bl .ppc64_runlatch_on; \ +END_FTR_SECTION_IFSET(CPU_FTR_CTRL) \ addi r3,r1,STACK_FRAME_OVERHEAD; \ bl hdlr; \ b .ret_from_except_lite From 6bcc4c01755fd2066bc374193cf3b0849cbabe47 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Sep 2007 12:43:17 +1000 Subject: [PATCH 0192/2804] [POWERPC] Remove warning in arch/powerpc/kernel/sysfs.c Fixes: arch/powerpc/kernel/sysfs.c: In function 'cpu_add_sysdev_attr_group': arch/powerpc/kernel/sysfs.c:388: warning: ignoring return value of 'sysfs_create_group', declared with attribute warn_unused_result Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/sysfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index d7835ba9fb8c..25d9a96484dd 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -440,12 +440,14 @@ int cpu_add_sysdev_attr_group(struct attribute_group *attrs) { int cpu; struct sys_device *sysdev; + int ret; mutex_lock(&cpu_mutex); for_each_possible_cpu(cpu) { sysdev = get_cpu_sysdev(cpu); - sysfs_create_group(&sysdev->kobj, attrs); + ret = sysfs_create_group(&sysdev->kobj, attrs); + WARN_ON(ret != 0); } mutex_unlock(&cpu_mutex); From 4674f2f33948432469e52d5bcaeda9904e34fe46 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 6 Sep 2007 05:21:04 +1000 Subject: [PATCH 0193/2804] [POWERPC] bootwrapper: flatdevtree fixes 1. ft_create_node was returning the internal pointer rather than a phandle. 2. ft_find_device_rel was treating a "top" phandle of NULL as an error, rather than as the root of the tree. The old, absolute ft_find_device is removed, and the relative version is renamed to ft_find_device(). Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/flatdevtree.c | 41 +++++++++++++--------------- arch/powerpc/boot/flatdevtree.h | 7 ++--- arch/powerpc/boot/flatdevtree_misc.c | 2 +- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c index 13761bf160c4..0af7291fc67c 100644 --- a/arch/powerpc/boot/flatdevtree.c +++ b/arch/powerpc/boot/flatdevtree.c @@ -354,16 +354,21 @@ static void ft_put_bin(struct ft_cxt *cxt, const void *data, unsigned int sz) cxt->p += sza; } -int ft_begin_node(struct ft_cxt *cxt, const char *name) +char *ft_begin_node(struct ft_cxt *cxt, const char *name) { unsigned long nlen = strlen(name) + 1; unsigned long len = 8 + _ALIGN(nlen, 4); + char *ret; if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, len)) - return -1; + return NULL; + + ret = cxt->p; + ft_put_word(cxt, OF_DT_BEGIN_NODE); ft_put_bin(cxt, name, strlen(name) + 1); - return 0; + + return ret; } void ft_end_node(struct ft_cxt *cxt) @@ -625,25 +630,17 @@ void ft_end_tree(struct ft_cxt *cxt) bph->dt_strings_size = cpu_to_be32(ssize); } -void *ft_find_device(struct ft_cxt *cxt, const char *srch_path) +void *ft_find_device(struct ft_cxt *cxt, const void *top, const char *srch_path) { char *node; - /* require absolute path */ - if (srch_path[0] != '/') - return NULL; - node = ft_find_descendent(cxt, ft_root_node(cxt), srch_path); - return ft_get_phandle(cxt, node); -} - -void *ft_find_device_rel(struct ft_cxt *cxt, const void *top, - const char *srch_path) -{ - char *node; - - node = ft_node_ph2node(cxt, top); - if (node == NULL) - return NULL; + if (top) { + node = ft_node_ph2node(cxt, top); + if (node == NULL) + return NULL; + } else { + node = ft_root_node(cxt); + } node = ft_find_descendent(cxt, node, srch_path); return ft_get_phandle(cxt, node); @@ -945,7 +942,7 @@ int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname) void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name) { struct ft_atom atom; - char *p, *next; + char *p, *next, *ret; int depth = 0; if (parent) { @@ -970,9 +967,9 @@ void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name) break; /* end of node, insert here */ cxt->p = p; - ft_begin_node(cxt, name); + ret = ft_begin_node(cxt, name); ft_end_node(cxt); - return p; + return ft_get_phandle(cxt, ret); } p = next; } diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h index cb26325d72db..2c1c826c4eca 100644 --- a/arch/powerpc/boot/flatdevtree.h +++ b/arch/powerpc/boot/flatdevtree.h @@ -76,7 +76,7 @@ struct ft_cxt { unsigned int nodes_used; }; -int ft_begin_node(struct ft_cxt *cxt, const char *name); +char *ft_begin_node(struct ft_cxt *cxt, const char *name); void ft_end_node(struct ft_cxt *cxt); void ft_begin_tree(struct ft_cxt *cxt); @@ -96,9 +96,8 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size); void ft_dump_blob(const void *bphp); void ft_merge_blob(struct ft_cxt *cxt, void *blob); -void *ft_find_device(struct ft_cxt *cxt, const char *srch_path); -void *ft_find_device_rel(struct ft_cxt *cxt, const void *top, - const char *srch_path); +void *ft_find_device(struct ft_cxt *cxt, const void *top, + const char *srch_path); void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path); int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, void *buf, const unsigned int buflen); diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c index 4341e6558c1a..8d1debe8d941 100644 --- a/arch/powerpc/boot/flatdevtree_misc.c +++ b/arch/powerpc/boot/flatdevtree_misc.c @@ -18,7 +18,7 @@ static struct ft_cxt cxt; static void *fdtm_finddevice(const char *name) { - return ft_find_device(&cxt, name); + return ft_find_device(&cxt, NULL, name); } static int fdtm_getprop(const void *phandle, const char *propname, From 9de782770b84768e1aa2e6454223ef30768de84e Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 6 Sep 2007 05:21:10 +1000 Subject: [PATCH 0194/2804] [POWERPC] bootwrapper: Add strtoull() This will be needed by PlanetCore firmware support. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 2 +- arch/powerpc/boot/stdlib.c | 45 ++++++++++++++++++++++++++++++++++++++ arch/powerpc/boot/stdlib.h | 6 +++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/stdlib.c create mode 100644 arch/powerpc/boot/stdlib.h diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index fd16577a40d5..cffef147e042 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -45,7 +45,7 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \ - cpm-serial.c + cpm-serial.c stdlib.c src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ diff --git a/arch/powerpc/boot/stdlib.c b/arch/powerpc/boot/stdlib.c new file mode 100644 index 000000000000..e00d58c29eea --- /dev/null +++ b/arch/powerpc/boot/stdlib.c @@ -0,0 +1,45 @@ +/* + * stdlib functions + * + * Author: Scott Wood + * + * Copyright (c) 2007 Freescale Semiconductor, 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 "stdlib.h" + +/* Not currently supported: leading whitespace, sign, 0x prefix, zero base */ +unsigned long long int strtoull(const char *ptr, char **end, int base) +{ + unsigned long long ret = 0; + + if (base > 36) + goto out; + + while (*ptr) { + int digit; + + if (*ptr >= '0' && *ptr <= '9' && *ptr < '0' + base) + digit = *ptr - '0'; + else if (*ptr >= 'A' && *ptr < 'A' + base - 10) + digit = *ptr - 'A' + 10; + else if (*ptr >= 'a' && *ptr < 'a' + base - 10) + digit = *ptr - 'a' + 10; + else + break; + + ret *= base; + ret += digit; + ptr++; + } + +out: + if (end) + *end = (char *)ptr; + + return ret; +} diff --git a/arch/powerpc/boot/stdlib.h b/arch/powerpc/boot/stdlib.h new file mode 100644 index 000000000000..1bf01ac73aba --- /dev/null +++ b/arch/powerpc/boot/stdlib.h @@ -0,0 +1,6 @@ +#ifndef _PPC_BOOT_STDLIB_H_ +#define _PPC_BOOT_STDLIB_H_ + +unsigned long long int strtoull(const char *ptr, char **end, int base); + +#endif From 21f3fe2f7ab57832ea1fc7f719ec7e167b7ad80e Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 6 Sep 2007 05:21:12 +1000 Subject: [PATCH 0195/2804] [POWERPC] bootwrapper: Add get_path() This will be used by the PlanetCore firmware support to construct a linux,stdout-path from the serial node that it finds. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/flatdevtree.c | 59 ++++++++++++++++++++++++++++ arch/powerpc/boot/flatdevtree.h | 1 + arch/powerpc/boot/flatdevtree_misc.c | 6 +++ arch/powerpc/boot/ops.h | 9 +++++ 4 files changed, 75 insertions(+) diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c index 0af7291fc67c..cf30675c6116 100644 --- a/arch/powerpc/boot/flatdevtree.c +++ b/arch/powerpc/boot/flatdevtree.c @@ -975,3 +975,62 @@ void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name) } return NULL; } + +/* Returns the start of the path within the provided buffer, or NULL on + * error. + */ +char *ft_get_path(struct ft_cxt *cxt, const void *phandle, + char *buf, int len) +{ + const char *path_comp[FT_MAX_DEPTH]; + struct ft_atom atom; + char *p, *next, *pos; + int depth = 0, i; + void *node; + + node = ft_node_ph2node(cxt, phandle); + if (node == NULL) + return NULL; + + p = ft_root_node(cxt); + + while ((next = ft_next(cxt, p, &atom)) != NULL) { + switch (atom.tag) { + case OF_DT_BEGIN_NODE: + path_comp[depth++] = atom.name; + if (p == node) + goto found; + + break; + + case OF_DT_END_NODE: + if (--depth == 0) + return NULL; + } + + p = next; + } + +found: + pos = buf; + for (i = 1; i < depth; i++) { + int this_len; + + if (len <= 1) + return NULL; + + *pos++ = '/'; + len--; + + strncpy(pos, path_comp[i], len); + + if (pos[len - 1] != 0) + return NULL; + + this_len = strlen(pos); + len -= this_len; + pos += this_len; + } + + return buf; +} diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h index 2c1c826c4eca..b0957a2d967f 100644 --- a/arch/powerpc/boot/flatdevtree.h +++ b/arch/powerpc/boot/flatdevtree.h @@ -108,5 +108,6 @@ void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev, const char *propname, const char *propval, int proplen); void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name); +char *ft_get_path(struct ft_cxt *cxt, const void *phandle, char *buf, int len); #endif /* FLATDEVTREE_H */ diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c index 8d1debe8d941..b3670096fa71 100644 --- a/arch/powerpc/boot/flatdevtree_misc.c +++ b/arch/powerpc/boot/flatdevtree_misc.c @@ -58,6 +58,11 @@ static unsigned long fdtm_finalize(void) return (unsigned long)cxt.bph; } +static char *fdtm_get_path(const void *phandle, char *buf, int len) +{ + return ft_get_path(&cxt, phandle, buf, len); +} + int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device) { dt_ops.finddevice = fdtm_finddevice; @@ -67,6 +72,7 @@ int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device) dt_ops.create_node = fdtm_create_node; dt_ops.find_node_by_prop_value = fdtm_find_node_by_prop_value; dt_ops.finalize = fdtm_finalize; + dt_ops.get_path = fdtm_get_path; return ft_open(&cxt, dt_blob, max_size, max_find_device, platform_ops.realloc); diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index 45c2268d5c56..703255bf0089 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -47,6 +47,7 @@ struct dt_ops { const char *propname, const char *propval, int proplen); unsigned long (*finalize)(void); + char *(*get_path)(const void *phandle, char *buf, int len); }; extern struct dt_ops dt_ops; @@ -170,6 +171,14 @@ static inline void *find_node_by_linuxphandle(const u32 linuxphandle) (char *)&linuxphandle, sizeof(u32)); } +static inline char *get_path(const void *phandle, char *buf, int len) +{ + if (dt_ops.get_path) + return dt_ops.get_path(phandle, buf, len); + + return NULL; +} + static inline void *malloc(unsigned long size) { return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL; From 96ebc3bfb6ddedd5a400d5653b50551d5a3de439 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 6 Sep 2007 05:21:18 +1000 Subject: [PATCH 0196/2804] [POWERPC] bootwrapper: Only print MAC addresses when the node is actually present Some firmwares (such as PlanetCore) only provide a base MAC address, and expect the kernel to set certain bits to generate the addresses for the other ports. As such, MAC addresses are generated that may not correspond to actual hardware. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/devtree.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c index e1b8122b4393..549463bf5eec 100644 --- a/arch/powerpc/boot/devtree.c +++ b/arch/powerpc/boot/devtree.c @@ -100,12 +100,14 @@ void __dt_fixup_mac_addresses(u32 startindex, ...) devp = find_node_by_prop_value(NULL, "linux,network-index", (void*)&index, sizeof(index)); - printf("ENET%d: local-mac-address <-" - " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index, - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + if (devp) { + printf("ENET%d: local-mac-address <-" + " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index, + addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); - if (devp) setprop(devp, "local-mac-address", addr, 6); + } index++; } From bde6c6e16aa489ea76c762fb7ffb0abb48660dd8 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 6 Sep 2007 08:04:38 +1000 Subject: [PATCH 0197/2804] [POWERPC] Check _PAGE_RW and _PAGE_PRESENT on kernel addresses Previously, the TLB miss handlers assumed that pages above KERNELBASE are always present and read/write. This assumption is false in the case of CONFIG_DEBUG_PAGEALLOC. Signed-off-by: Scott Wood Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_32.S | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 7d73a13450b0..0e3df1f55feb 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -475,10 +475,10 @@ InstructionTLBMiss: li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ lwz r2,PGDIR(r2) blt+ 112f + mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ + rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ lis r2,swapper_pg_dir@ha /* if kernel address, use */ addi r2,r2,swapper_pg_dir@l /* kernel page table */ - mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ - rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ 112: tophys(r2,r2) rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ @@ -549,10 +549,10 @@ DataLoadTLBMiss: li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ lwz r2,PGDIR(r2) blt+ 112f + mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ + rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ lis r2,swapper_pg_dir@ha /* if kernel address, use */ addi r2,r2,swapper_pg_dir@l /* kernel page table */ - mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ - rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ 112: tophys(r2,r2) rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ @@ -621,10 +621,10 @@ DataStoreTLBMiss: li r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */ lwz r2,PGDIR(r2) blt+ 112f + mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ + rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ lis r2,swapper_pg_dir@ha /* if kernel address, use */ addi r2,r2,swapper_pg_dir@l /* kernel page table */ - mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ - rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ 112: tophys(r2,r2) rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ From e788ff13be03c2cc4055d5569b7b218dc3f2cb7b Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 7 Sep 2007 03:45:21 +1000 Subject: [PATCH 0198/2804] [POWERPC] prom_init whitespace cleanup, typo fix Whitespace cleanup: badly indented lines. Typo in comment. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 29c2160bcbb5..1db10f70ae69 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1199,7 +1199,7 @@ static void __init prom_initialize_tce_table(void) if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) continue; - /* Keep the old logic in tack to avoid regression. */ + /* Keep the old logic intact to avoid regression. */ if (compatible[0] != 0) { if ((strstr(compatible, RELOC("python")) == NULL) && (strstr(compatible, RELOC("Speedwagon")) == NULL) && @@ -2231,7 +2231,7 @@ static void __init fixup_device_tree(void) static void __init prom_find_boot_cpu(void) { - struct prom_t *_prom = &RELOC(prom); + struct prom_t *_prom = &RELOC(prom); u32 getprop_rval; ihandle prom_cpu; phandle cpu_pkg; @@ -2251,7 +2251,7 @@ static void __init prom_find_boot_cpu(void) static void __init prom_check_initrd(unsigned long r3, unsigned long r4) { #ifdef CONFIG_BLK_DEV_INITRD - struct prom_t *_prom = &RELOC(prom); + struct prom_t *_prom = &RELOC(prom); if (r3 && r4 && r4 != 0xdeadbeef) { unsigned long val; @@ -2284,7 +2284,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp, unsigned long r6, unsigned long r7) { - struct prom_t *_prom; + struct prom_t *_prom; unsigned long hdr; unsigned long offset = reloc_offset(); @@ -2343,8 +2343,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, /* * Copy the CPU hold code */ - if (RELOC(of_platform) != PLATFORM_POWERMAC) - copy_and_flush(0, KERNELBASE + offset, 0x100, 0); + if (RELOC(of_platform) != PLATFORM_POWERMAC) + copy_and_flush(0, KERNELBASE + offset, 0x100, 0); /* * Do early parsing of command line From 70c6cc37db342d9f970884e12744ab5ee290d4ad Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 7 Sep 2007 03:46:15 +1000 Subject: [PATCH 0199/2804] [POWERPC] prom.c whitespace cleanup Whitespace cleanup: badly indented lines. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 0028fe68e09e..b081413c72d4 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -779,13 +779,13 @@ static int __init early_init_dt_scan_chosen(unsigned long node, #endif #ifdef CONFIG_KEXEC - lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL); - if (lprop) - crashk_res.start = *lprop; + lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL); + if (lprop) + crashk_res.start = *lprop; - lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL); - if (lprop) - crashk_res.end = crashk_res.start + *lprop - 1; + lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL); + if (lprop) + crashk_res.end = crashk_res.start + *lprop - 1; #endif early_init_dt_check_for_initrd(node); From 3c607ce2a3213f33b8b6b854b5f7db876021e466 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 7 Sep 2007 03:47:29 +1000 Subject: [PATCH 0200/2804] [POWERPC] setup_64.c and prom.c comment cleanup Grammatical corrections to comments. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 8 +++++--- arch/powerpc/kernel/setup_64.c | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index b081413c72d4..172dcc3849a0 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -430,9 +430,11 @@ static int __init early_parse_mem(char *p) } early_param("mem", early_parse_mem); -/* - * The device tree may be allocated below our memory limit, or inside the - * crash kernel region for kdump. If so, move it out now. +/** + * move_device_tree - move tree to an unused area, if needed. + * + * The device tree may be allocated beyond our memory limit, or inside the + * crash kernel region for kdump. If so, move it out of the way. */ static void move_device_tree(void) { diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 6018178708a5..3089eaed3256 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -181,9 +181,9 @@ void __init early_setup(unsigned long dt_ptr) DBG(" -> early_setup(), dt_ptr: 0x%lx\n", dt_ptr); /* - * Do early initializations using the flattened device - * tree, like retreiving the physical memory map or - * calculating/retreiving the hash table size + * Do early initialization using the flattened device + * tree, such as retrieving the physical memory map or + * calculating/retrieving the hash table size. */ early_init_devtree(__va(dt_ptr)); From 2099172d61abda1b793b499bb8edcaac4de2cdae Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 7 Sep 2007 13:23:53 +1000 Subject: [PATCH 0201/2804] [POWERPC] Document and implement an improved flash device binding for powerpc This replaces the binding for flash chips in booting-without-of.txt with an clarified and improved version. It also makes drivers/mtd/maps/physmap_of.c recognize this new binding. Finally it revises the Ebony device tree source to use the new binding as an example. Signed-off-by: David Gibson Acked-by: Segher Boessenkool Signed-off-by: Paul Mackerras --- Documentation/powerpc/booting-without-of.txt | 86 ++++--- arch/powerpc/boot/dts/ebony.dts | 30 ++- drivers/mtd/maps/physmap_of.c | 239 ++++++++++++++----- 3 files changed, 248 insertions(+), 107 deletions(-) diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 76733a3962f0..20e0e6cb0347 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -50,7 +50,7 @@ Table of Contents g) Freescale SOC SEC Security Engines h) Board Control and Status (BCSR) i) Freescale QUICC Engine module (QE) - j) Flash chip nodes + j) CFI or JEDEC memory-mapped NOR flash k) Global Utilities Block VII - Specifying interrupt information for devices @@ -1757,45 +1757,69 @@ platforms are moved over to use the flattened-device-tree model. }; }; - j) Flash chip nodes + j) CFI or JEDEC memory-mapped NOR flash Flash chips (Memory Technology Devices) are often used for solid state file systems on embedded devices. - Required properties: + - compatible : should contain the specific model of flash chip(s) + used, if known, followed by either "cfi-flash" or "jedec-flash" + - reg : Address range of the flash chip + - bank-width : Width (in bytes) of the flash bank. Equal to the + device width times the number of interleaved chips. + - device-width : (optional) Width of a single flash chip. If + omitted, assumed to be equal to 'bank-width'. + - #address-cells, #size-cells : Must be present if the flash has + sub-nodes representing partitions (see below). In this case + both #address-cells and #size-cells must be equal to 1. - - device_type : has to be "rom" - - compatible : Should specify what this flash device is compatible with. - Currently, this is most likely to be "direct-mapped" (which - corresponds to the MTD physmap mapping driver). - - reg : Offset and length of the register set (or memory mapping) for - the device. - - bank-width : Width of the flash data bus in bytes. Required - for the NOR flashes (compatible == "direct-mapped" and others) ONLY. + For JEDEC compatible devices, the following additional properties + are defined: - Recommended properties : + - vendor-id : Contains the flash chip's vendor id (1 byte). + - device-id : Contains the flash chip's device id (1 byte). - - partitions : Several pairs of 32-bit values where the first value is - partition's offset from the start of the device and the second one is - partition size in bytes with LSB used to signify a read only - partition (so, the partition size should always be an even number). - - partition-names : The list of concatenated zero terminated strings - representing the partition names. - - probe-type : The type of probe which should be done for the chip - (JEDEC vs CFI actually). Valid ONLY for NOR flashes. + In addition to the information on the flash bank itself, the + device tree may optionally contain additional information + describing partitions of the flash address space. This can be + used on platforms which have strong conventions about which + portions of the flash are used for what purposes, but which don't + use an on-flash partition table such as RedBoot. - Example: + Each partition is represented as a sub-node of the flash device. + Each node's name represents the name of the corresponding + partition of the flash device. - flash@ff000000 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "CFI"; - reg = ; - bank-width = <4>; - partitions = <00000000 00f80000 - 00f80000 00080001>; - partition-names = "fs\0firmware"; - }; + Flash partitions + - reg : The partition's offset and size within the flash bank. + - label : (optional) The label / name for this flash partition. + If omitted, the label is taken from the node name (excluding + the unit address). + - read-only : (optional) This parameter, if present, is a hint to + Linux that this flash partition should only be mounted + read-only. This is usually used for flash partitions + containing early-boot firmware images or data which should not + be clobbered. + + Example: + + flash@ff000000 { + compatible = "amd,am29lv128ml", "cfi-flash"; + reg = ; + bank-width = <4>; + device-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + fs@0 { + label = "fs"; + reg = <0 f80000>; + }; + firmware@f80000 { + label ="firmware"; + reg = ; + read-only; + }; + }; k) Global Utilities Block diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts index 37599bda5500..bc259972aaa0 100644 --- a/arch/powerpc/boot/dts/ebony.dts +++ b/arch/powerpc/boot/dts/ebony.dts @@ -138,13 +138,16 @@ interrupt-parent = <&UIC1>; small-flash@0,80000 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "JEDEC"; + compatible = "jedec-flash"; bank-width = <1>; - partitions = <0 80000>; - partition-names = "OpenBIOS"; reg = <0 80000 80000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "OpenBIOS"; + reg = <0 80000>; + read-only; + }; }; ds1743@1,0 { @@ -154,14 +157,19 @@ }; large-flash@2,0 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "JEDEC"; + compatible = "jedec-flash"; bank-width = <1>; - partitions = <0 380000 - 380000 80000>; - partition-names = "fs", "firmware"; reg = <2 0 400000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "fs"; + reg = <0 380000>; + }; + partition@380000 { + label = "firmware"; + reg = <380000 80000>; + }; }; ir@3,0 { diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index bbb42c35b69b..3df001bfee36 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -4,6 +4,9 @@ * Copyright (C) 2006 MontaVista Software Inc. * Author: Vitaly Wool * + * Revised to handle newer style flash binding by: + * Copyright (C) 2007 David Gibson, 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 @@ -30,56 +33,135 @@ struct physmap_flash_info { struct map_info map; struct resource *res; #ifdef CONFIG_MTD_PARTITIONS - int nr_parts; struct mtd_partition *parts; #endif }; -static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL }; #ifdef CONFIG_MTD_PARTITIONS -static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; -#endif - -#ifdef CONFIG_MTD_PARTITIONS -static int parse_flash_partitions(struct device_node *node, - struct mtd_partition **parts) +static int parse_obsolete_partitions(struct of_device *dev, + struct physmap_flash_info *info, + struct device_node *dp) { - int i, plen, retval = -ENOMEM; - const u32 *part; - const char *name; + int i, plen, nr_parts; + const struct { + u32 offset, len; + } *part; + const char *names; - part = of_get_property(node, "partitions", &plen); - if (part == NULL) - goto err; + part = of_get_property(dp, "partitions", &plen); + if (!part) + return -ENOENT; - retval = plen / (2 * sizeof(u32)); - *parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL); - if (*parts == NULL) { + dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); + + nr_parts = plen / sizeof(part[0]); + + info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL); + if (!info->parts) { printk(KERN_ERR "Can't allocate the flash partition data!\n"); - goto err; + return -ENOMEM; } - name = of_get_property(node, "partition-names", &plen); + names = of_get_property(dp, "partition-names", &plen); - for (i = 0; i < retval; i++) { - (*parts)[i].offset = *part++; - (*parts)[i].size = *part & ~1; - if (*part++ & 1) /* bit 0 set signifies read only partition */ - (*parts)[i].mask_flags = MTD_WRITEABLE; + for (i = 0; i < nr_parts; i++) { + info->parts[i].offset = part->offset; + info->parts[i].size = part->len & ~1; + if (part->len & 1) /* bit 0 set signifies read only partition */ + info->parts[i].mask_flags = MTD_WRITEABLE; - if (name != NULL && plen > 0) { - int len = strlen(name) + 1; + if (names && (plen > 0)) { + int len = strlen(names) + 1; - (*parts)[i].name = (char *)name; + info->parts[i].name = (char *)names; plen -= len; - name += len; - } else - (*parts)[i].name = "unnamed"; + names += len; + } else { + info->parts[i].name = "unnamed"; + } + + part++; } -err: - return retval; + + return nr_parts; } -#endif + +static int __devinit process_partitions(struct physmap_flash_info *info, + struct of_device *dev) +{ + const char *partname; + static const char *part_probe_types[] + = { "cmdlinepart", "RedBoot", NULL }; + struct device_node *dp = dev->node, *pp; + int nr_parts, i; + + /* First look for RedBoot table or partitions on the command + * line, these take precedence over device tree information */ + nr_parts = parse_mtd_partitions(info->mtd, part_probe_types, + &info->parts, 0); + if (nr_parts > 0) { + add_mtd_partitions(info->mtd, info->parts, nr_parts); + return 0; + } + + /* First count the subnodes */ + nr_parts = 0; + for (pp = dp->child; pp; pp = pp->sibling) + nr_parts++; + + if (nr_parts) { + info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), + GFP_KERNEL); + if (!info->parts) { + printk(KERN_ERR "Can't allocate the flash partition data!\n"); + return -ENOMEM; + } + + for (pp = dp->child, i = 0 ; pp; pp = pp->sibling, i++) { + const u32 *reg; + int len; + + reg = of_get_property(pp, "reg", &len); + if (!reg || (len != 2*sizeof(u32))) { + dev_err(&dev->dev, "Invalid 'reg' on %s\n", + dp->full_name); + kfree(info->parts); + info->parts = NULL; + return -EINVAL; + } + info->parts[i].offset = reg[0]; + info->parts[i].size = reg[1]; + + partname = of_get_property(pp, "label", &len); + if (!partname) + partname = of_get_property(pp, "name", &len); + info->parts[i].name = (char *)partname; + + if (of_get_property(pp, "read-only", &len)) + info->parts[i].mask_flags = MTD_WRITEABLE; + } + } else { + nr_parts = parse_obsolete_partitions(dev, info, dp); + } + + if (nr_parts < 0) + return nr_parts; + + if (nr_parts > 0) + add_mtd_partitions(info->mtd, info->parts, nr_parts); + else + add_mtd_device(info->mtd); + + return 0; +} +#else /* MTD_PARTITIONS */ +static int __devinit process_partitions(struct physmap_flash_info *info, + struct device_node *dev) +{ + add_mtd_device(info->mtd); + return 0; +} +#endif /* MTD_PARTITIONS */ static int of_physmap_remove(struct of_device *dev) { @@ -92,7 +174,7 @@ static int of_physmap_remove(struct of_device *dev) if (info->mtd != NULL) { #ifdef CONFIG_MTD_PARTITIONS - if (info->nr_parts) { + if (info->parts) { del_mtd_partitions(info->mtd); kfree(info->parts); } else { @@ -115,17 +197,51 @@ static int of_physmap_remove(struct of_device *dev) return 0; } +/* Helper function to handle probing of the obsolete "direct-mapped" + * compatible binding, which has an extra "probe-type" property + * describing the type of flash probe necessary. */ +static struct mtd_info * __devinit obsolete_probe(struct of_device *dev, + struct map_info *map) +{ + struct device_node *dp = dev->node; + const char *of_probe; + struct mtd_info *mtd; + static const char *rom_probe_types[] + = { "cfi_probe", "jedec_probe", "map_rom"}; + int i; + + dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" " + "flash binding\n"); + + of_probe = of_get_property(dp, "probe-type", NULL); + if (!of_probe) { + for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) { + mtd = do_map_probe(rom_probe_types[i], map); + if (mtd) + return mtd; + } + return NULL; + } else if (strcmp(of_probe, "CFI") == 0) { + return do_map_probe("cfi_probe", map); + } else if (strcmp(of_probe, "JEDEC") == 0) { + return do_map_probe("jedec_probe", map); + } else { + if (strcmp(of_probe, "ROM") != 0) + dev_dbg(&dev->dev, "obsolete_probe: don't know probe type " + "'%s', mapping as rom\n", of_probe); + return do_map_probe("mtd_rom", map); + } +} + static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match) { struct device_node *dp = dev->node; struct resource res; struct physmap_flash_info *info; - const char **probe_type; - const char *of_probe; + const char *probe_type = (const char *)match->data; const u32 *width; int err; - if (of_address_to_resource(dp, 0, &res)) { dev_err(&dev->dev, "Can't get the flash mapping!\n"); err = -EINVAL; @@ -174,21 +290,11 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev simple_map_init(&info->map); - of_probe = of_get_property(dp, "probe-type", NULL); - if (of_probe == NULL) { - probe_type = rom_probe_types; - for (; info->mtd == NULL && *probe_type != NULL; probe_type++) - info->mtd = do_map_probe(*probe_type, &info->map); - } else if (!strcmp(of_probe, "CFI")) - info->mtd = do_map_probe("cfi_probe", &info->map); - else if (!strcmp(of_probe, "JEDEC")) - info->mtd = do_map_probe("jedec_probe", &info->map); - else { - if (strcmp(of_probe, "ROM")) - dev_dbg(&dev->dev, "map_probe: don't know probe type " - "'%s', mapping as rom\n", of_probe); - info->mtd = do_map_probe("mtd_rom", &info->map); - } + if (probe_type) + info->mtd = do_map_probe(probe_type, &info->map); + else + info->mtd = obsolete_probe(dev, &info->map); + if (info->mtd == NULL) { dev_err(&dev->dev, "map_probe failed\n"); err = -ENXIO; @@ -196,19 +302,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev } info->mtd->owner = THIS_MODULE; -#ifdef CONFIG_MTD_PARTITIONS - err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0); - if (err > 0) { - add_mtd_partitions(info->mtd, info->parts, err); - } else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) { - dev_info(&dev->dev, "Using OF partition information\n"); - add_mtd_partitions(info->mtd, info->parts, err); - info->nr_parts = err; - } else -#endif - - add_mtd_device(info->mtd); - return 0; + return process_partitions(info, dev); err_out: of_physmap_remove(dev); @@ -220,6 +314,21 @@ err_out: } static struct of_device_id of_physmap_match[] = { + { + .compatible = "cfi-flash", + .data = (void *)"cfi_probe", + }, + { + /* FIXME: JEDEC chips can't be safely and reliably + * probed, although the mtd code gets it right in + * practice most of the time. We should use the + * vendor and device ids specified by the binding to + * bypass the heuristic probe code, but the mtd layer + * provides, at present, no interface for doing so + * :(. */ + .compatible = "jedec-flash", + .data = (void *)"jedec_probe", + }, { .type = "rom", .compatible = "direct-mapped" From 0d72ba930cbc9140a584af7e4e65041b6c7a7d18 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 8 Sep 2007 05:13:19 +1000 Subject: [PATCH 0202/2804] [POWERPC] Add workaround for MPICs with broken register reads Some versions of PWRficient 1682M have an interrupt controller in which the first register in each pair for interrupt sources doesn't always read with the right polarity/sense values. To work around this, keep a software copy of the register instead. Since it's not modified from the mpic itself, it's a feasible solution. Still, keep it under a config option to avoid wasting memory on other platforms. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/Kconfig | 10 ++++++++++ arch/powerpc/platforms/pasemi/Kconfig | 1 + arch/powerpc/sysdev/mpic.c | 14 ++++++++++++-- include/asm-powerpc/mpic.h | 4 ++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 065f3b19d6c7..78a7edac577f 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -137,6 +137,16 @@ config MPIC_U3_HT_IRQS depends on PPC_MAPLE default y +config MPIC_BROKEN_REGREAD + bool + depends on MPIC + help + This option enables a MPIC driver workaround for some chips + that have a bug that causes some interrupt source information + to not read back properly. It is safe to use on other chips as + well, but enabling it uses about 8KB of memory to keep copies + of the register contents in software. + config IBMVIO depends on PPC_PSERIES || PPC_ISERIES bool diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index 95cd90fd81c7..117d90aa5008 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -5,6 +5,7 @@ config PPC_PASEMI select MPIC select PPC_UDBG_16550 select PPC_NATIVE + select MPIC_BROKEN_REGREAD help This option enables support for PA Semi's PWRficient line of SoC processors, including PA6T-1682M diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 25a81f73cecf..8de29f28b4c7 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -228,8 +228,13 @@ static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigne unsigned int isu = src_no >> mpic->isu_shift; unsigned int idx = src_no & mpic->isu_mask; - return _mpic_read(mpic->reg_type, &mpic->isus[isu], - reg + (idx * MPIC_INFO(IRQ_STRIDE))); +#ifdef CONFIG_MPIC_BROKEN_REGREAD + if (reg == 0) + return mpic->isu_reg0_shadow[idx]; + else +#endif + return _mpic_read(mpic->reg_type, &mpic->isus[isu], + reg + (idx * MPIC_INFO(IRQ_STRIDE))); } static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, @@ -240,6 +245,11 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, _mpic_write(mpic->reg_type, &mpic->isus[isu], reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); + +#ifdef CONFIG_MPIC_BROKEN_REGREAD + if (reg == 0) + mpic->isu_reg0_shadow[idx] = value; +#endif } #define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r)) diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index 0eb3ab9ec2bb..edb4a7c84506 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -306,6 +306,10 @@ struct mpic unsigned long *hwirq_bitmap; #endif +#ifdef CONFIG_MPIC_BROKEN_REGREAD + u32 isu_reg0_shadow[MPIC_MAX_IRQ_SOURCES]; +#endif + /* link */ struct mpic *next; From 85d02924a38789be35e83adba32eb6690535cfb0 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 12 Sep 2007 18:43:15 +1000 Subject: [PATCH 0203/2804] [POWERPC] PS3: Fix CONFIG_SMP=n, CONFIG_KEXEC=y build Currently, the ps3 kernel fails to build without smp but with kexec, as ps3_kexec_cpu_down needs ps3_smp_cleanup_cpu, which isn't defined on UP kernels. This change adds an empty ps3_smp_cleanup_cpu for UP kernels. Booted on ps3. Signed-off-by: Jeremy Kerr Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/platform.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 2eb8f92704b4..27c7d099816a 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -47,7 +47,11 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); /* smp */ void smp_init_ps3(void); +#ifdef CONFIG_SMP void ps3_smp_cleanup_cpu(int cpu); +#else +static inline void ps3_smp_cleanup_cpu(int cpu) { } +#endif /* time */ From 06462d9263e168da3ecdff5a3d95ed470a91bbdc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Sep 2007 18:43:16 +1000 Subject: [PATCH 0204/2804] [POWERPC] PS3: Add new LV1 error codes Add new error codes that may be returned by the LV1 hypervisor Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- include/asm-powerpc/ps3.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h index a6f3f5ee7ca7..f577a16c6728 100644 --- a/include/asm-powerpc/ps3.h +++ b/include/asm-powerpc/ps3.h @@ -229,6 +229,9 @@ enum lv1_result { LV1_INVALID_CLASS_ID = -21, LV1_CONSTRAINT_NOT_SATISFIED = -22, LV1_ALIGNMENT_ERROR = -23, + LV1_HARDWARE_ERROR = -24, + LV1_INVALID_DATA_FORMAT = -25, + LV1_INVALID_OPERATION = -26, LV1_INTERNAL_ERROR = -32768, }; @@ -284,6 +287,12 @@ static inline const char* ps3_result(int result) return "LV1_CONSTRAINT_NOT_SATISFIED (-22)"; case LV1_ALIGNMENT_ERROR: return "LV1_ALIGNMENT_ERROR (-23)"; + case LV1_HARDWARE_ERROR: + return "LV1_HARDWARE_ERROR (-24)"; + case LV1_INVALID_DATA_FORMAT: + return "LV1_INVALID_DATA_FORMAT (-25)"; + case LV1_INVALID_OPERATION: + return "LV1_INVALID_OPERATION (-26)"; case LV1_INTERNAL_ERROR: return "LV1_INTERNAL_ERROR (-32768)"; default: From 75cdff9242c4e048cb830d359920719d29b9ee7c Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Wed, 12 Sep 2007 18:43:17 +1000 Subject: [PATCH 0205/2804] [POWERPC] PS3: Enhance storage probe debug output Add some more info to the PS3 storage probe debug output. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/device-init.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index ce15cada88d4..fd063fe0c9b3 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -297,8 +297,8 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) u64 dev_port; } *notify_event; - pr_debug(" -> %s:%u: bus_id %u, dev_id %u, dev_type %u\n", __func__, - __LINE__, repo->bus_id, repo->dev_id, repo->dev_type); + pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id, + repo->dev_id, repo->dev_type); buf = kzalloc(512, GFP_KERNEL); if (!buf) @@ -359,6 +359,11 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) break; } + pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, " + "port %lu\n", __func__, __LINE__, repo->bus_index, + repo->dev_index, repo->dev_type, + notify_event->event_type, notify_event->dev_port); + if (notify_event->event_type != notify_region_probe || notify_event->bus_id != repo->bus_id) { pr_debug("%s:%u: bad notify_event: event %lu, " @@ -370,8 +375,9 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) if (notify_event->dev_id == repo->dev_id && notify_event->dev_type == repo->dev_type) { - pr_debug("%s:%u: device ready: dev_id %u\n", __func__, - __LINE__, repo->dev_id); + pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__, + __LINE__, repo->bus_index, repo->dev_index, + repo->dev_type); error = 0; break; } @@ -412,9 +418,10 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, return -ENODEV; } - pr_debug("%s:%u: index %u:%u: port %lu blk_size %lu num_blocks %lu " + pr_debug("%s:%u: (%u:%u:%u): port %lu blk_size %lu num_blocks %lu " "num_regions %u\n", __func__, __LINE__, repo->bus_index, - repo->dev_index, port, blk_size, num_blocks, num_regions); + repo->dev_index, repo->dev_type, port, blk_size, num_blocks, + num_regions); p = kzalloc(sizeof(struct ps3_storage_device) + num_regions * sizeof(struct ps3_storage_region), @@ -681,8 +688,9 @@ static int ps3_probe_thread(void *data) pr_debug("%s:%u: find device error.\n", __func__, __LINE__); else { - pr_debug("%s:%u: found device\n", __func__, - __LINE__); + pr_debug("%s:%u: found device (%u:%u:%u)\n", + __func__, __LINE__, repo->bus_index, + repo->dev_index, repo->dev_type); ps3_register_repository_device(repo); ps3_repository_bump_device(repo); ms = 250; From 89a300e85b646dd08343264f025f4f412d552bfd Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 22 Aug 2007 21:49:01 -0500 Subject: [PATCH 0206/2804] ucc_geth: kill unused include The ucc_geth_mii code is based on the gianfar_mii code that use to include ocp.h. ucc never need this and it causes issues when we want to kill arch/ppc includes from arch/powerpc. Signed-off-by: Kumar Gala --- drivers/net/ucc_geth_mii.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c index 6c257b88ce51..df884f0ad8e5 100644 --- a/drivers/net/ucc_geth_mii.c +++ b/drivers/net/ucc_geth_mii.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include From 16d24060d1df9e38dd11ffb0a8afcb5e69a08e3c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 17 Aug 2007 09:22:09 -0500 Subject: [PATCH 0207/2804] [POWERPC] 85xx: Renamed mpc8544_ds.c to mpc85xx_ds.c Renamed the mpc8544_ds.c board code to mpc85xx_ds.c to make it more generic in prep for other boards based on the same platform. Signed-off-by: Kumar Gala --- arch/powerpc/configs/mpc8544_ds_defconfig | 2 +- arch/powerpc/platforms/85xx/Kconfig | 8 ++++---- arch/powerpc/platforms/85xx/Makefile | 2 +- .../powerpc/platforms/85xx/{mpc8544_ds.c => mpc85xx_ds.c} | 0 4 files changed, 6 insertions(+), 6 deletions(-) rename arch/powerpc/platforms/85xx/{mpc8544_ds.c => mpc85xx_ds.c} (100%) diff --git a/arch/powerpc/configs/mpc8544_ds_defconfig b/arch/powerpc/configs/mpc8544_ds_defconfig index 86582aefab93..150221f6f723 100644 --- a/arch/powerpc/configs/mpc8544_ds_defconfig +++ b/arch/powerpc/configs/mpc8544_ds_defconfig @@ -136,7 +136,7 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_MPC8560_ADS is not set # CONFIG_MPC85xx_CDS is not set # CONFIG_MPC85xx_MDS is not set -CONFIG_MPC8544_DS=y +CONFIG_MPC85xx_DS=y CONFIG_MPC85xx=y CONFIG_MPIC=y # CONFIG_MPIC_WEIRD is not set diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index f620171ad6b1..b8476b20a424 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -29,13 +29,13 @@ config MPC85xx_MDS help This option enables support for the MPC85xx MDS board -config MPC8544_DS - bool "Freescale MPC8544 DS" +config MPC85xx_DS + bool "Freescale MPC85xx DS" select PPC_I8259 select DEFAULT_UIMAGE select FSL_ULI1575 help - This option enables support for the MPC8544 DS board + This option enables support for the MPC85xx DS (MPC8544 DS) board endchoice @@ -58,4 +58,4 @@ config MPC85xx select FSL_PCI if PCI select SERIAL_8250_SHARE_IRQ if SERIAL_8250 default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \ - || MPC85xx_MDS || MPC8544_DS + || MPC85xx_MDS || MPC85xx_DS diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index d70f2d0f9d36..25bd9e2d4946 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_PPC_85xx) += misc.o obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o -obj-$(CONFIG_MPC8544_DS) += mpc8544_ds.o +obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c similarity index 100% rename from arch/powerpc/platforms/85xx/mpc8544_ds.c rename to arch/powerpc/platforms/85xx/mpc85xx_ds.c From 7f50382dc87988d618f2d47364b22ad5973a968d Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 17 Aug 2007 09:26:40 -0500 Subject: [PATCH 0208/2804] [POWERPC] 85xx: Clean up from 85xx_ds rename Renamed functions in 85xx_ds from 8544 to 85xx. Kept an unique machine def/probe for the MPC8544 DS board to handle some subtle differences between the future board based on the DS platform. Also fixed building w/o CONFIG_PCI and minor whitespace fixes. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc85xx_ds.c | 36 +++++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 48983bc56d46..3a5c3c47653c 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -1,5 +1,5 @@ /* - * MPC8544 DS Board Setup + * MPC85xx DS Board Setup * * Author Xianghua Xiao (x.xiao@freescale.com) * Roy Zang @@ -44,7 +44,7 @@ #endif #ifdef CONFIG_PPC_I8259 -static void mpc8544_8259_cascade(unsigned int irq, struct irq_desc *desc) +static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc) { unsigned int cascade_irq = i8259_irq(); @@ -55,7 +55,7 @@ static void mpc8544_8259_cascade(unsigned int irq, struct irq_desc *desc) } #endif /* CONFIG_PPC_I8259 */ -void __init mpc8544_ds_pic_init(void) +void __init mpc85xx_ds_pic_init(void) { struct mpic *mpic; struct resource r; @@ -104,16 +104,17 @@ void __init mpc8544_ds_pic_init(void) return; } - DBG("mpc8544ds: cascade mapped to irq %d\n", cascade_irq); + DBG("mpc85xxds: cascade mapped to irq %d\n", cascade_irq); i8259_init(cascade_node, 0); of_node_put(cascade_node); - set_irq_chained_handler(cascade_irq, mpc8544_8259_cascade); + set_irq_chained_handler(cascade_irq, mpc85xx_8259_cascade); #endif /* CONFIG_PPC_I8259 */ } #ifdef CONFIG_PCI +static int primary_phb_addr; extern int uses_fsl_uli_m1575; extern int uli_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn); @@ -121,13 +122,13 @@ extern int uli_exclude_device(struct pci_controller *hose, static int mpc85xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { - struct device_node* node; + struct device_node* node; struct resource rsrc; node = (struct device_node *)hose->arch_data; of_address_to_resource(node, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0xb000) { + if ((rsrc.start & 0xfffff) == primary_phb_addr) { return uli_exclude_device(hose, bus, devfn); } @@ -138,20 +139,20 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, /* * Setup the architecture */ -static void __init mpc8544_ds_setup_arch(void) +static void __init mpc85xx_ds_setup_arch(void) { #ifdef CONFIG_PCI struct device_node *np; #endif if (ppc_md.progress) - ppc_md.progress("mpc8544_ds_setup_arch()", 0); + ppc_md.progress("mpc85xx_ds_setup_arch()", 0); #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { struct resource rsrc; of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0xb000) + if ((rsrc.start & 0xfffff) == primary_phb_addr) fsl_add_bridge(np, 1); else fsl_add_bridge(np, 0); @@ -160,7 +161,7 @@ static void __init mpc8544_ds_setup_arch(void) ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif - printk("MPC8544 DS board from Freescale Semiconductor\n"); + printk("MPC85xx DS board from Freescale Semiconductor\n"); } /* @@ -170,14 +171,21 @@ static int __init mpc8544_ds_probe(void) { unsigned long root = of_get_flat_dt_root(); - return of_flat_dt_is_compatible(root, "MPC8544DS"); + if (of_flat_dt_is_compatible(root, "MPC8544DS")) { +#ifdef CONFIG_PCI + primary_phb_addr = 0xb000; +#endif + return 1; + } else { + return 0; + } } define_machine(mpc8544_ds) { .name = "MPC8544 DS", .probe = mpc8544_ds_probe, - .setup_arch = mpc8544_ds_setup_arch, - .init_IRQ = mpc8544_ds_pic_init, + .setup_arch = mpc85xx_ds_setup_arch, + .init_IRQ = mpc85xx_ds_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif From 7f2862c34521ee6006f9c2678d68a02dc57b5444 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 26 Aug 2007 00:08:11 +0200 Subject: [PATCH 0209/2804] [POWERPC] linkstation updates 1. Fix RTC type - it is a rs5c372a, not rs5c372b 2. Configure both UART interrupts edge-triggered 3. Add a license header to ls_uart.c 4. Check for running on linkstation in a late_initcall() function. Needed for multiplatform builds, even though linkstation doesn't support them yet 5. Remove unneeded #include from linkstation.c Signed-off-by: Guennadi Liakhovetski Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/kuroboxHD.dts | 4 ++-- arch/powerpc/boot/dts/kuroboxHG.dts | 4 ++-- arch/powerpc/platforms/embedded6xx/linkstation.c | 1 - arch/powerpc/platforms/embedded6xx/ls_uart.c | 14 ++++++++++++++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts index b0eeff036de3..a7b3714bc029 100644 --- a/arch/powerpc/boot/dts/kuroboxHD.dts +++ b/arch/powerpc/boot/dts/kuroboxHD.dts @@ -69,7 +69,7 @@ XXXX add flash parts, rtc, ?? rtc@32 { device_type = "rtc"; - compatible = "ricoh,rs5c372b"; + compatible = "ricoh,rs5c372a"; reg = <32>; }; }; @@ -80,7 +80,7 @@ XXXX add flash parts, rtc, ?? reg = <80004500 8>; clock-frequency = <5d08d88>; current-speed = <2580>; - interrupts = <9 2>; + interrupts = <9 0>; interrupt-parent = <&mpic>; }; diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts index ccd15a231a10..a0007b9bcc80 100644 --- a/arch/powerpc/boot/dts/kuroboxHG.dts +++ b/arch/powerpc/boot/dts/kuroboxHG.dts @@ -69,7 +69,7 @@ XXXX add flash parts, rtc, ?? rtc@32 { device_type = "rtc"; - compatible = "ricoh,rs5c372b"; + compatible = "ricoh,rs5c372a"; reg = <32>; }; }; @@ -80,7 +80,7 @@ XXXX add flash parts, rtc, ?? reg = <80004500 8>; clock-frequency = <7c044a8>; current-speed = <2580>; - interrupts = <9 2>; + interrupts = <9 0>; interrupt-parent = <&mpic>; }; diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 61ca02c2d644..f392374309b3 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -11,7 +11,6 @@ */ #include -#include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index 0d9f1500a671..c99264cedda5 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -1,3 +1,14 @@ +/* + * AVR power-management chip interface for the Buffalo Linkstation / + * Kurobox Platform. + * + * Author: 2006 (c) G. Liakhovetski + * g.liakhovetski@gmx.de + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of + * any kind, whether express or implied. + */ #include #include #include @@ -106,6 +117,9 @@ static int __init ls_uarts_init(void) phys_addr_t phys_addr; int len; + if (!machine_is(linkstation)) + return 0; + avr = of_find_node_by_path("/soc10x/serial@80004500"); if (!avr) return -EINVAL; From d347b3291b284e42c90b3f675a8332daf890b85a Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Fri, 27 Jul 2007 13:24:36 -0500 Subject: [PATCH 0210/2804] [POWERPC] 86xx: Remove unnecessary loops_per_jiffy initialization code. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 47aafa76c933..3ec9d5a25750 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -132,23 +132,13 @@ static int mpc86xx_exclude_device(struct pci_controller *hose, static void __init mpc86xx_hpcn_setup_arch(void) { +#ifdef CONFIG_PCI struct device_node *np; +#endif if (ppc_md.progress) ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np != 0) { - const unsigned int *fp; - - fp = of_get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } - #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { struct resource rsrc; From 683d00b03eb09a140e25d7f1457d347277bc2619 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Fri, 27 Jul 2007 13:24:45 -0500 Subject: [PATCH 0211/2804] [POWERPC] 85xx: Remove unnecessary loops_per_jiffy initialization code. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 13 ------------- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 13 ------------- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 11 ----------- 3 files changed, 37 deletions(-) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 40a828675c7b..c22bc1c4f591 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -192,7 +192,6 @@ void init_fcc_ioports(struct fs_platform_info *fpi) static void __init mpc85xx_ads_setup_arch(void) { - struct device_node *cpu; #ifdef CONFIG_PCI struct device_node *np; #endif @@ -200,18 +199,6 @@ static void __init mpc85xx_ads_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc85xx_ads_setup_arch()", 0); - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } - #ifdef CONFIG_CPM2 cpm2_reset(); #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index b46c8d50f6d1..665e8df05dc5 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -265,7 +265,6 @@ device_initcall(mpc85xx_cds_8259_attach); */ static void __init mpc85xx_cds_setup_arch(void) { - struct device_node *cpu; #ifdef CONFIG_PCI struct device_node *np; #endif @@ -273,18 +272,6 @@ static void __init mpc85xx_cds_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc85xx_cds_setup_arch()", 0); - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 500000000 / HZ; - of_node_put(cpu); - } - cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 66366a023820..c379286c3730 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -72,17 +72,6 @@ static void __init mpc85xx_mds_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc85xx_mds_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np != NULL) { - const unsigned int *fp = - of_get_property(np, "clock-frequency", NULL); - if (fp != NULL) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } - /* Map BCSR area */ np = of_find_node_by_name(NULL, "bcsr"); if (np != NULL) { From f9234736112bf193e5ab451abbfbdf279cc53137 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 20 Aug 2007 11:38:12 -0500 Subject: [PATCH 0212/2804] [POWERPC] fsl_soc.c cleanup 1. Update the way get_brgfreq() finds things in the device tree. It now uses names that are less namespace polluting. The old names are supported until all boards are converted. 2. "size" is changed from unsigned int to int, to match what of_get_property() expects. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_soc.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index f3abce11bead..7012e51ae5c6 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -52,13 +52,13 @@ phys_addr_t get_immrbase(void) soc = of_find_node_by_type(NULL, "soc"); if (soc) { - unsigned int size; + int size; const void *prop = of_get_property(soc, "reg", &size); if (prop) immrbase = of_translate_address(soc, prop); of_node_put(soc); - }; + } return immrbase; } @@ -76,16 +76,23 @@ u32 get_brgfreq(void) if (brgfreq != -1) return brgfreq; - node = of_find_node_by_type(NULL, "cpm"); + node = of_find_compatible_node(NULL, NULL, "fsl,cpm1"); + if (!node) + node = of_find_compatible_node(NULL, NULL, "fsl,cpm2"); + if (!node) + node = of_find_node_by_type(NULL, "cpm"); if (node) { - unsigned int size; - const unsigned int *prop = of_get_property(node, - "brg-frequency", &size); + int size; + const unsigned int *prop; - if (prop) + prop = of_get_property(node, "fsl,brg-frequency", &size); + if (!prop) + prop = of_get_property(node, "brg-frequency", &size); + if (prop && size == 4) brgfreq = *prop; + of_node_put(node); - }; + } return brgfreq; } @@ -103,14 +110,14 @@ u32 get_baudrate(void) node = of_find_node_by_type(NULL, "serial"); if (node) { - unsigned int size; + int size; const unsigned int *prop = of_get_property(node, "current-speed", &size); if (prop) fs_baudrate = *prop; of_node_put(node); - }; + } return fs_baudrate; } From 26caeb2ee1924d564e8d8190aa783a569532f81a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 24 Aug 2007 16:42:53 -0500 Subject: [PATCH 0213/2804] [POWERPC] Handle alignment faults on SPE load/store instructions This adds code to handle alignment traps generated by the following SPE (signal processing engine) load/store instructions, by emulating the instruction in the kernel (as is done for other instructions that generate alignment traps): evldd[x] Vector Load Double Word into Double Word [Indexed] evldw[x] Vector Load Double into Two Words [Indexed] evldh[x] Vector Load Double into Four Half Words [Indexed] evlhhesplat[x] Vector Load Half Word into Half Words Even and Splat [Indexed] evlhhousplat[x] Vector Load Half Word into Half Word Odd Unsigned and Splat [Indexed] evlhhossplat[x] Vector Load Half Word into Half Word Odd Signed and Splat [Indexed] evlwhe[x] Vector Load Word into Two Half Words Even [Indexed] evlwhou[x] Vector Load Word into Two Half Words Odd Unsigned (zero-extended) [Indexed] evlwhos[x] Vector Load Word into Two Half Words Odd Signed (with sign extension) [Indexed] evlwwsplat[x] Vector Load Word into Word and Splat [Indexed] evlwhsplat[x] Vector Load Word into Two Half Words and Splat [Indexed] evstdd[x] Vector Store Double of Double [Indexed] evstdw[x] Vector Store Double of Two Words [Indexed] evstdh[x] Vector Store Double of Four Half Words [Indexed] evstwhe[x] Vector Store Word of Two Half Words from Even [Indexed] evstwho[x] Vector Store Word of Two Half Words from Odd [Indexed] evstwwe[x] Vector Store Word of Word from Even [Indexed] evstwwo[x] Vector Store Word of Word from Odd [Indexed] Signed-off-by: Kumar Gala --- arch/powerpc/kernel/align.c | 250 ++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index 4c47f9cc0d9a..e06f75daeba3 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -46,6 +46,8 @@ struct aligninfo { #define S 0x40 /* single-precision fp or... */ #define SX 0x40 /* ... byte count in XER */ #define HARD 0x80 /* string, stwcx. */ +#define E4 0x40 /* SPE endianness is word */ +#define E8 0x80 /* SPE endianness is double word */ /* DSISR bits reported for a DCBZ instruction: */ #define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */ @@ -392,6 +394,248 @@ static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr, return 1; /* exception handled and fixed up */ } +#ifdef CONFIG_SPE + +static struct aligninfo spe_aligninfo[32] = { + { 8, LD+E8 }, /* 0 00 00: evldd[x] */ + { 8, LD+E4 }, /* 0 00 01: evldw[x] */ + { 8, LD }, /* 0 00 10: evldh[x] */ + INVALID, /* 0 00 11 */ + { 2, LD }, /* 0 01 00: evlhhesplat[x] */ + INVALID, /* 0 01 01 */ + { 2, LD }, /* 0 01 10: evlhhousplat[x] */ + { 2, LD+SE }, /* 0 01 11: evlhhossplat[x] */ + { 4, LD }, /* 0 10 00: evlwhe[x] */ + INVALID, /* 0 10 01 */ + { 4, LD }, /* 0 10 10: evlwhou[x] */ + { 4, LD+SE }, /* 0 10 11: evlwhos[x] */ + { 4, LD+E4 }, /* 0 11 00: evlwwsplat[x] */ + INVALID, /* 0 11 01 */ + { 4, LD }, /* 0 11 10: evlwhsplat[x] */ + INVALID, /* 0 11 11 */ + + { 8, ST+E8 }, /* 1 00 00: evstdd[x] */ + { 8, ST+E4 }, /* 1 00 01: evstdw[x] */ + { 8, ST }, /* 1 00 10: evstdh[x] */ + INVALID, /* 1 00 11 */ + INVALID, /* 1 01 00 */ + INVALID, /* 1 01 01 */ + INVALID, /* 1 01 10 */ + INVALID, /* 1 01 11 */ + { 4, ST }, /* 1 10 00: evstwhe[x] */ + INVALID, /* 1 10 01 */ + { 4, ST }, /* 1 10 10: evstwho[x] */ + INVALID, /* 1 10 11 */ + { 4, ST+E4 }, /* 1 11 00: evstwwe[x] */ + INVALID, /* 1 11 01 */ + { 4, ST+E4 }, /* 1 11 10: evstwwo[x] */ + INVALID, /* 1 11 11 */ +}; + +#define EVLDD 0x00 +#define EVLDW 0x01 +#define EVLDH 0x02 +#define EVLHHESPLAT 0x04 +#define EVLHHOUSPLAT 0x06 +#define EVLHHOSSPLAT 0x07 +#define EVLWHE 0x08 +#define EVLWHOU 0x0A +#define EVLWHOS 0x0B +#define EVLWWSPLAT 0x0C +#define EVLWHSPLAT 0x0E +#define EVSTDD 0x10 +#define EVSTDW 0x11 +#define EVSTDH 0x12 +#define EVSTWHE 0x18 +#define EVSTWHO 0x1A +#define EVSTWWE 0x1C +#define EVSTWWO 0x1E + +/* + * Emulate SPE loads and stores. + * Only Book-E has these instructions, and it does true little-endian, + * so we don't need the address swizzling. + */ +static int emulate_spe(struct pt_regs *regs, unsigned int reg, + unsigned int instr) +{ + int t, ret; + union { + u64 ll; + u32 w[2]; + u16 h[4]; + u8 v[8]; + } data, temp; + unsigned char __user *p, *addr; + unsigned long *evr = ¤t->thread.evr[reg]; + unsigned int nb, flags; + + instr = (instr >> 1) & 0x1f; + + /* DAR has the operand effective address */ + addr = (unsigned char __user *)regs->dar; + + nb = spe_aligninfo[instr].len; + flags = spe_aligninfo[instr].flags; + + /* Verify the address of the operand */ + if (unlikely(user_mode(regs) && + !access_ok((flags & ST ? VERIFY_WRITE : VERIFY_READ), + addr, nb))) + return -EFAULT; + + /* userland only */ + if (unlikely(!user_mode(regs))) + return 0; + + flush_spe_to_thread(current); + + /* If we are loading, get the data from user space, else + * get it from register values + */ + if (flags & ST) { + data.ll = 0; + switch (instr) { + case EVSTDD: + case EVSTDW: + case EVSTDH: + data.w[0] = *evr; + data.w[1] = regs->gpr[reg]; + break; + case EVSTWHE: + data.h[2] = *evr >> 16; + data.h[3] = regs->gpr[reg] >> 16; + break; + case EVSTWHO: + data.h[2] = *evr & 0xffff; + data.h[3] = regs->gpr[reg] & 0xffff; + break; + case EVSTWWE: + data.w[1] = *evr; + break; + case EVSTWWO: + data.w[1] = regs->gpr[reg]; + break; + default: + return -EINVAL; + } + } else { + temp.ll = data.ll = 0; + ret = 0; + p = addr; + + switch (nb) { + case 8: + ret |= __get_user_inatomic(temp.v[0], p++); + ret |= __get_user_inatomic(temp.v[1], p++); + ret |= __get_user_inatomic(temp.v[2], p++); + ret |= __get_user_inatomic(temp.v[3], p++); + case 4: + ret |= __get_user_inatomic(temp.v[4], p++); + ret |= __get_user_inatomic(temp.v[5], p++); + case 2: + ret |= __get_user_inatomic(temp.v[6], p++); + ret |= __get_user_inatomic(temp.v[7], p++); + if (unlikely(ret)) + return -EFAULT; + } + + switch (instr) { + case EVLDD: + case EVLDW: + case EVLDH: + data.ll = temp.ll; + break; + case EVLHHESPLAT: + data.h[0] = temp.h[3]; + data.h[2] = temp.h[3]; + break; + case EVLHHOUSPLAT: + case EVLHHOSSPLAT: + data.h[1] = temp.h[3]; + data.h[3] = temp.h[3]; + break; + case EVLWHE: + data.h[0] = temp.h[2]; + data.h[2] = temp.h[3]; + break; + case EVLWHOU: + case EVLWHOS: + data.h[1] = temp.h[2]; + data.h[3] = temp.h[3]; + break; + case EVLWWSPLAT: + data.w[0] = temp.w[1]; + data.w[1] = temp.w[1]; + break; + case EVLWHSPLAT: + data.h[0] = temp.h[2]; + data.h[1] = temp.h[2]; + data.h[2] = temp.h[3]; + data.h[3] = temp.h[3]; + break; + default: + return -EINVAL; + } + } + + if (flags & SW) { + switch (flags & 0xf0) { + case E8: + SWAP(data.v[0], data.v[7]); + SWAP(data.v[1], data.v[6]); + SWAP(data.v[2], data.v[5]); + SWAP(data.v[3], data.v[4]); + break; + case E4: + + SWAP(data.v[0], data.v[3]); + SWAP(data.v[1], data.v[2]); + SWAP(data.v[4], data.v[7]); + SWAP(data.v[5], data.v[6]); + break; + /* Its half word endian */ + default: + SWAP(data.v[0], data.v[1]); + SWAP(data.v[2], data.v[3]); + SWAP(data.v[4], data.v[5]); + SWAP(data.v[6], data.v[7]); + break; + } + } + + if (flags & SE) { + data.w[0] = (s16)data.h[1]; + data.w[1] = (s16)data.h[3]; + } + + /* Store result to memory or update registers */ + if (flags & ST) { + ret = 0; + p = addr; + switch (nb) { + case 8: + ret |= __put_user_inatomic(data.v[0], p++); + ret |= __put_user_inatomic(data.v[1], p++); + ret |= __put_user_inatomic(data.v[2], p++); + ret |= __put_user_inatomic(data.v[3], p++); + case 4: + ret |= __put_user_inatomic(data.v[4], p++); + ret |= __put_user_inatomic(data.v[5], p++); + case 2: + ret |= __put_user_inatomic(data.v[6], p++); + ret |= __put_user_inatomic(data.v[7], p++); + } + if (unlikely(ret)) + return -EFAULT; + } else { + *evr = data.w[0]; + regs->gpr[reg] = data.w[1]; + } + + return 1; +} +#endif /* CONFIG_SPE */ /* * Called on alignment exception. Attempts to fixup @@ -450,6 +694,12 @@ int fix_alignment(struct pt_regs *regs) /* extract the operation and registers from the dsisr */ reg = (dsisr >> 5) & 0x1f; /* source/dest register */ areg = dsisr & 0x1f; /* register to update */ + +#ifdef CONFIG_SPE + if ((instr >> 26) == 0x4) + return emulate_spe(regs, reg, instr); +#endif + instr = (dsisr >> 10) & 0x7f; instr |= (dsisr >> 13) & 0x60; From 5d54ddcbcf931bf07cd1ce262bda4674ebd1427f Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 11 Sep 2007 01:25:43 -0500 Subject: [PATCH 0214/2804] [POWERPC] 85xx: Add basic Uniprocessor MPC8572 DS port Added basic board port for MPC8572 DS reference platform that is similiar to the MPC8544/33 DS reference platform in uniprocessor mode. Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8572ds.dts | 404 ++++++ arch/powerpc/configs/mpc8572_ds_defconfig | 1496 +++++++++++++++++++++ arch/powerpc/platforms/85xx/mpc85xx_ds.c | 31 + arch/powerpc/sysdev/fsl_pci.c | 2 + include/linux/pci_ids.h | 2 + 5 files changed, 1935 insertions(+) create mode 100644 arch/powerpc/boot/dts/mpc8572ds.dts create mode 100644 arch/powerpc/configs/mpc8572_ds_defconfig diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts new file mode 100644 index 000000000000..d638deec7652 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8572ds.dts @@ -0,0 +1,404 @@ +/* + * MPC8572 DS Device Tree Source + * + * Copyright 2007 Freescale Semiconductor 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. + */ + +/ { + model = "fsl,MPC8572DS"; + compatible = "fsl,MPC8572DS"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8572@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <8000>; // L1, 32K + i-cache-size = <8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + }; + }; + + memory { + device_type = "memory"; + reg = <00000000 00000000>; // Filled by U-Boot + }; + + soc8572@ffe00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + ranges = <00000000 ffe00000 00100000>; + reg = ; // CCSRBAR & soc regs, remove once parse code for immrbase fixed + bus-frequency = <0>; // Filled out by uboot. + + memory-controller@2000 { + compatible = "fsl,mpc8572-memory-controller"; + reg = <2000 1000>; + interrupt-parent = <&mpic>; + interrupts = <12 2>; + }; + + memory-controller@6000 { + compatible = "fsl,mpc8572-memory-controller"; + reg = <6000 1000>; + interrupt-parent = <&mpic>; + interrupts = <12 2>; + }; + + l2-cache-controller@20000 { + compatible = "fsl,mpc8572-l2-cache-controller"; + reg = <20000 1000>; + cache-line-size = <20>; // 32 bytes + cache-size = <80000>; // L2, 512K + interrupt-parent = <&mpic>; + interrupts = <10 2>; + }; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3000 100>; + interrupts = <2b 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = <2b 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + mdio@24520 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "mdio"; + compatible = "gianfar"; + reg = <24520 20>; + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = ; + reg = <0>; + }; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = ; + reg = <1>; + }; + phy2: ethernet-phy@2 { + interrupt-parent = <&mpic>; + interrupts = ; + reg = <2>; + }; + phy3: ethernet-phy@3 { + interrupt-parent = <&mpic>; + interrupts = ; + reg = <3>; + }; + }; + + ethernet@24000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <24000 1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <1d 2 1e 2 22 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + }; + + ethernet@25000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <25000 1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <23 2 24 2 28 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + + ethernet@26000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <26000 1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <1f 2 20 2 21 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy2>; + phy-connection-type = "rgmii-id"; + }; + + ethernet@27000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <27000 1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <25 2 26 2 27 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy3>; + phy-connection-type = "rgmii-id"; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = <0>; + interrupts = <2a 2>; + interrupt-parent = <&mpic>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = <0>; + interrupts = <2a 2>; + interrupt-parent = <&mpic>; + }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,mpc8572-guts"; + reg = ; + fsl,has-rstcr; + }; + + mpic: pic@40000 { + clock-frequency = <0>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <40000 40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + big-endian; + }; + }; + + pcie@ffe08000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 ff>; + ranges = <02000000 0 80000000 80000000 0 20000000 + 01000000 0 00000000 ffc00000 0 00010000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x11 - PCI slot 1 */ + 8800 0 0 1 &mpic 2 1 + 8800 0 0 2 &mpic 3 1 + 8800 0 0 3 &mpic 4 1 + 8800 0 0 4 &mpic 1 1 + + /* IDSEL 0x12 - PCI slot 2 */ + 9000 0 0 1 &mpic 3 1 + 9000 0 0 2 &mpic 4 1 + 9000 0 0 3 &mpic 1 1 + 9000 0 0 4 &mpic 2 1 + + // IDSEL 0x1c USB + e000 0 0 0 &i8259 c 2 + e100 0 0 0 &i8259 9 2 + e200 0 0 0 &i8259 a 2 + e300 0 0 0 &i8259 b 2 + + // IDSEL 0x1d Audio + e800 0 0 0 &i8259 6 2 + + // IDSEL 0x1e Legacy + f000 0 0 0 &i8259 7 2 + f100 0 0 0 &i8259 7 2 + + // IDSEL 0x1f IDE/SATA + f800 0 0 0 &i8259 e 2 + f900 0 0 0 &i8259 5 2 + + >; + + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 80000000 + 02000000 0 80000000 + 0 20000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + uli1575@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + ranges = <02000000 0 80000000 + 02000000 0 80000000 + 0 20000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + isa@1e { + device_type = "isa"; + #interrupt-cells = <2>; + #size-cells = <1>; + #address-cells = <2>; + reg = ; + ranges = <1 0 01000000 0 0 + 00001000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + reg = <1 20 2 + 1 a0 2 + 1 4d0 2>; + interrupt-controller; + device_type = "interrupt-controller"; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <9 2>; + interrupt-parent = <&mpic>; + }; + + i8042@60 { + #size-cells = <0>; + #address-cells = <1>; + reg = <1 60 1 1 64 1>; + interrupts = <1 3 c 3>; + interrupt-parent = + <&i8259>; + + keyboard@0 { + reg = <0>; + compatible = "pnpPNP,303"; + }; + + mouse@1 { + reg = <1>; + compatible = "pnpPNP,f03"; + }; + }; + + rtc@70 { + compatible = "pnpPNP,b00"; + reg = <1 70 2>; + }; + + gpio@400 { + reg = <1 400 80>; + }; + }; + }; + }; + + }; + + pcie@ffe09000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 ff>; + ranges = <02000000 0 a0000000 a0000000 0 20000000 + 01000000 0 00000000 ffc10000 0 00010000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <1a 2>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 4 1 + 0000 0 0 2 &mpic 5 1 + 0000 0 0 3 &mpic 6 1 + 0000 0 0 4 &mpic 7 1 + >; + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 a0000000 + 02000000 0 a0000000 + 0 20000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + }; + }; + + pcie@ffe0a000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 ff>; + ranges = <02000000 0 c0000000 c0000000 0 20000000 + 01000000 0 00000000 ffc20000 0 00010000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <1b 2>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 0 1 + 0000 0 0 2 &mpic 1 1 + 0000 0 0 3 &mpic 2 1 + 0000 0 0 4 &mpic 3 1 + >; + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 c0000000 + 02000000 0 c0000000 + 0 20000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + }; + }; +}; diff --git a/arch/powerpc/configs/mpc8572_ds_defconfig b/arch/powerpc/configs/mpc8572_ds_defconfig new file mode 100644 index 000000000000..7f1a3e987138 --- /dev/null +++ b/arch/powerpc/configs/mpc8572_ds_defconfig @@ -0,0 +1,1496 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc4 +# Tue Sep 11 01:19:35 2007 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +CONFIG_PPC_85xx=y +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_85xx=y +CONFIG_E500=y +CONFIG_BOOKE=y +CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set +CONFIG_SPE=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# +# Platform support +# +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +# CONFIG_MPC8540_ADS is not set +# CONFIG_MPC8560_ADS is not set +# CONFIG_MPC85xx_CDS is not set +# CONFIG_MPC85xx_MDS is not set +CONFIG_MPC85xx_DS=y +CONFIG_MPC85xx=y +CONFIG_MPIC=y +# CONFIG_MPIC_WEIRD is not set +CONFIG_PPC_I8259=y +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPM2 is not set +CONFIG_FSL_ULI1575=y + +# +# Kernel options +# +CONFIG_HIGHMEM=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_MATH_EMULATION=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="" +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +CONFIG_FSL_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=y +CONFIG_NET_IPGRE=y +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_ARPD=y +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +CONFIG_SCSI_LOGGING=y +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_SATA_AHCI=y +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +CONFIG_PATA_ALI=y +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ARCNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +CONFIG_VITESSE_PHY=y +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +CONFIG_NETDEV_10000=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET_MII is not set +# CONFIG_USB_USBNET is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +CONFIG_NVRAM=y +CONFIG_GEN_RTC=y +CONFIG_GEN_RTC_X=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_DS1682 is not set +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +CONFIG_DVB_CORE=m +# CONFIG_DVB_CORE_ATTACH is not set +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# + +# +# Supported USB Adapters +# +# CONFIG_DVB_USB is not set +# CONFIG_DVB_TTUSB_BUDGET is not set +# CONFIG_DVB_TTUSB_DEC is not set +# CONFIG_DVB_CINERGYT2 is not set + +# +# Supported FlexCopII (B2C2) Adapters +# +# CONFIG_DVB_B2C2_FLEXCOP is not set + +# +# Supported BT878 Adapters +# + +# +# Supported Pluto2 Adapters +# +# CONFIG_DVB_PLUTO2 is not set + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +# CONFIG_DVB_STV0299 is not set +# CONFIG_DVB_CX24110 is not set +# CONFIG_DVB_CX24123 is not set +# CONFIG_DVB_TDA8083 is not set +# CONFIG_DVB_MT312 is not set +# CONFIG_DVB_VES1X93 is not set +# CONFIG_DVB_S5H1420 is not set +# CONFIG_DVB_TDA10086 is not set + +# +# DVB-T (terrestrial) frontends +# +# CONFIG_DVB_SP8870 is not set +# CONFIG_DVB_SP887X is not set +# CONFIG_DVB_CX22700 is not set +# CONFIG_DVB_CX22702 is not set +# CONFIG_DVB_L64781 is not set +# CONFIG_DVB_TDA1004X is not set +# CONFIG_DVB_NXT6000 is not set +# CONFIG_DVB_MT352 is not set +# CONFIG_DVB_ZL10353 is not set +# CONFIG_DVB_DIB3000MB is not set +# CONFIG_DVB_DIB3000MC is not set +# CONFIG_DVB_DIB7000M is not set +# CONFIG_DVB_DIB7000P is not set + +# +# DVB-C (cable) frontends +# +# CONFIG_DVB_VES1820 is not set +# CONFIG_DVB_TDA10021 is not set +# CONFIG_DVB_TDA10023 is not set +# CONFIG_DVB_STV0297 is not set + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +# CONFIG_DVB_NXT200X is not set +# CONFIG_DVB_OR51211 is not set +# CONFIG_DVB_OR51132 is not set +# CONFIG_DVB_BCM3510 is not set +# CONFIG_DVB_LGDT330X is not set + +# +# Tuners/PLL support +# +# CONFIG_DVB_PLL is not set +# CONFIG_DVB_TDA826X is not set +# CONFIG_DVB_TDA827X is not set +# CONFIG_DVB_TUNER_QT1010 is not set +# CONFIG_DVB_TUNER_MT2060 is not set + +# +# Miscellaneous devices +# +# CONFIG_DVB_LNBP21 is not set +# CONFIG_DVB_ISL6421 is not set +# CONFIG_DVB_TUA6100 is not set +CONFIG_DAB=y +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_AC97_CODEC=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# PCI devices +# +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +CONFIG_SND_INTEL8X0=y +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SND_AC97_POWER_SAVE is not set + +# +# ALSA PowerMac devices +# + +# +# ALSA PowerPC devices +# + +# +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set + +# +# System on Chip audio support +# +# CONFIG_SND_SOC is not set + +# +# SoC Audio support for SuperH +# + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set +CONFIG_AC97_BUS=y +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PPC_OF=y +CONFIG_USB_OHCI_HCD_PPC_OF_BE=y +CONFIG_USB_OHCI_HCD_PPC_OF_LE=y +CONFIG_USB_OHCI_HCD_PCI=y +CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y +CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_CRAMFS=y +CONFIG_VXFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +CONFIG_NFSD_TCP=y +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_ECB is not set +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=m +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_HW=y diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 3a5c3c47653c..4d449022ac9b 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -181,6 +181,23 @@ static int __init mpc8544_ds_probe(void) } } +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc8572_ds_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS")) { +#ifdef CONFIG_PCI + primary_phb_addr = 0x8000; +#endif + return 1; + } else { + return 0; + } +} + define_machine(mpc8544_ds) { .name = "MPC8544 DS", .probe = mpc8544_ds_probe, @@ -194,3 +211,17 @@ define_machine(mpc8544_ds) { .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; + +define_machine(mpc8572_ds) { + .name = "MPC8572 DS", + .probe = mpc8572_ds_probe, + .setup_arch = mpc85xx_ds_setup_arch, + .init_IRQ = mpc85xx_ds_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = mpc85xx_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 114c90f8f560..34cad96e0de9 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -255,5 +255,7 @@ DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8533E, quirk_fsl_pcie_transpare DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8533, quirk_fsl_pcie_transparent); DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8544E, quirk_fsl_pcie_transparent); DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8544, quirk_fsl_pcie_transparent); +DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8572E, quirk_fsl_pcie_transparent) +DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8572, quirk_fsl_pcie_transparent); DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_transparent); DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_transparent); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 55f307ffbf96..545f24ce2638 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2100,6 +2100,8 @@ #define PCI_DEVICE_ID_MPC8533 0x0031 #define PCI_DEVICE_ID_MPC8544E 0x0032 #define PCI_DEVICE_ID_MPC8544 0x0033 +#define PCI_DEVICE_ID_MPC8572E 0x0040 +#define PCI_DEVICE_ID_MPC8572 0x0041 #define PCI_DEVICE_ID_MPC8641 0x7010 #define PCI_DEVICE_ID_MPC8641D 0x7011 From f0c8ac8083cbd9347b398bfddcca20f1e2786016 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 12 Sep 2007 11:52:31 -0500 Subject: [PATCH 0215/2804] [POWERPC] DTS cleanup Removed the following cruft from .dts files: * 32-bit in cpu node -- doesn't exist in any spec and not used by kernel * removed built-in (chrp legacy) * Removed #interrupt-cells in places they don't need to be set * Fixed ranges on lite5200* * Removed clock-frequency from i8259 pic node, not sure where this came from * Removed big-endian from i8259 pic nodes, this was just bogus Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/holly.dts | 1 - arch/powerpc/boot/dts/kuroboxHD.dts | 2 -- arch/powerpc/boot/dts/kuroboxHG.dts | 2 -- arch/powerpc/boot/dts/lite5200.dts | 7 ++----- arch/powerpc/boot/dts/lite5200b.dts | 7 ++----- arch/powerpc/boot/dts/mpc7448hpc2.dts | 4 ---- arch/powerpc/boot/dts/mpc8272ads.dts | 5 ----- arch/powerpc/boot/dts/mpc8313erdb.dts | 3 --- arch/powerpc/boot/dts/mpc832x_mds.dts | 4 ---- arch/powerpc/boot/dts/mpc832x_rdb.dts | 4 ---- arch/powerpc/boot/dts/mpc8349emitx.dts | 3 --- arch/powerpc/boot/dts/mpc8349emitxgp.dts | 3 --- arch/powerpc/boot/dts/mpc834x_mds.dts | 3 --- arch/powerpc/boot/dts/mpc836x_mds.dts | 4 ---- arch/powerpc/boot/dts/mpc8540ads.dts | 3 --- arch/powerpc/boot/dts/mpc8541cds.dts | 6 ------ arch/powerpc/boot/dts/mpc8544ds.dts | 5 ----- arch/powerpc/boot/dts/mpc8548cds.dts | 5 ----- arch/powerpc/boot/dts/mpc8555cds.dts | 6 ------ arch/powerpc/boot/dts/mpc8560ads.dts | 5 ----- arch/powerpc/boot/dts/mpc8568mds.dts | 4 ---- arch/powerpc/boot/dts/mpc8641_hpcn.dts | 6 ------ arch/powerpc/boot/dts/mpc866ads.dts | 5 ----- arch/powerpc/boot/dts/mpc885ads.dts | 5 ----- arch/powerpc/boot/dts/prpmc2800.dts | 1 - 25 files changed, 4 insertions(+), 99 deletions(-) diff --git a/arch/powerpc/boot/dts/holly.dts b/arch/powerpc/boot/dts/holly.dts index 1a4d0beccc99..b5d87895fe06 100644 --- a/arch/powerpc/boot/dts/holly.dts +++ b/arch/powerpc/boot/dts/holly.dts @@ -31,7 +31,6 @@ timebase-frequency = <2faf080>; clock-frequency = <23c34600>; bus-frequency = ; - 32-bit; }; }; diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts index a7b3714bc029..ec71ab819fee 100644 --- a/arch/powerpc/boot/dts/kuroboxHD.dts +++ b/arch/powerpc/boot/dts/kuroboxHD.dts @@ -47,7 +47,6 @@ XXXX add flash parts, rtc, ?? soc10x { /* AFAICT need to make soc for 8245's uarts to be defined */ #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; compatible = "mpc10x"; store-gathering = <0>; /* 0 == off, !0 == on */ @@ -101,7 +100,6 @@ XXXX add flash parts, rtc, ?? compatible = "chrp,open-pic"; interrupt-controller; reg = <80040000 40000>; - built-in; }; pci@fec00000 { diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts index a0007b9bcc80..32ecd2319928 100644 --- a/arch/powerpc/boot/dts/kuroboxHG.dts +++ b/arch/powerpc/boot/dts/kuroboxHG.dts @@ -47,7 +47,6 @@ XXXX add flash parts, rtc, ?? soc10x { /* AFAICT need to make soc for 8245's uarts to be defined */ #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; compatible = "mpc10x"; store-gathering = <0>; /* 0 == off, !0 == on */ @@ -101,7 +100,6 @@ XXXX add flash parts, rtc, ?? compatible = "chrp,open-pic"; interrupt-controller; reg = <80040000 40000>; - built-in; }; pci@fec00000 { diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts index d29308fe4c24..d8bcbb870fdc 100644 --- a/arch/powerpc/boot/dts/lite5200.dts +++ b/arch/powerpc/boot/dts/lite5200.dts @@ -37,7 +37,6 @@ timebase-frequency = <0>; // from bootloader bus-frequency = <0>; // from bootloader clock-frequency = <0>; // from bootloader - 32-bit; }; }; @@ -50,10 +49,9 @@ model = "fsl,mpc5200"; compatible = "mpc5200"; revision = ""; // from bootloader - #interrupt-cells = <3>; device_type = "soc"; - ranges = <0 f0000000 f0010000>; - reg = ; + ranges = <0 f0000000 0000c000>; + reg = ; bus-frequency = <0>; // from bootloader system-frequency = <0>; // from bootloader @@ -69,7 +67,6 @@ device_type = "interrupt-controller"; compatible = "mpc5200-pic"; reg = <500 80>; - built-in; }; gpt@600 { // General Purpose Timer diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts index f242531f0451..5fe8998abb7c 100644 --- a/arch/powerpc/boot/dts/lite5200b.dts +++ b/arch/powerpc/boot/dts/lite5200b.dts @@ -37,7 +37,6 @@ timebase-frequency = <0>; // from bootloader bus-frequency = <0>; // from bootloader clock-frequency = <0>; // from bootloader - 32-bit; }; }; @@ -50,10 +49,9 @@ model = "fsl,mpc5200b"; compatible = "mpc5200"; revision = ""; // from bootloader - #interrupt-cells = <3>; device_type = "soc"; - ranges = <0 f0000000 f0010000>; - reg = ; + ranges = <0 f0000000 0000c000>; + reg = ; bus-frequency = <0>; // from bootloader system-frequency = <0>; // from bootloader @@ -69,7 +67,6 @@ device_type = "interrupt-controller"; compatible = "mpc5200b-pic\0mpc5200-pic"; reg = <500 80>; - built-in; }; gpt@600 { // General Purpose Timer diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts index b9158eb2797e..88cd37da13ef 100644 --- a/arch/powerpc/boot/dts/mpc7448hpc2.dts +++ b/arch/powerpc/boot/dts/mpc7448hpc2.dts @@ -31,7 +31,6 @@ timebase-frequency = <0>; // 33 MHz, from uboot clock-frequency = <0>; // From U-Boot bus-frequency = <0>; // From U-Boot - 32-bit; }; }; @@ -44,7 +43,6 @@ tsi108@c0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "tsi-bridge"; ranges = <00000000 c0000000 00010000>; reg = ; @@ -128,7 +126,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <7400 400>; - built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; big-endian; @@ -180,7 +177,6 @@ device_type = "pic-router"; #address-cells = <0>; #interrupt-cells = <2>; - built-in; big-endian; interrupts = <17 2>; interrupt-parent = <&mpic>; diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts index 4d09dcad2537..43130541799a 100644 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -29,7 +29,6 @@ timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; - 32-bit; }; }; @@ -38,7 +37,6 @@ #interrupt-cells = <2>; interrupt-controller; reg = ; - built-in; device_type = "pci-pic"; }; @@ -56,7 +54,6 @@ soc8272@f0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <00000000 f0000000 00053000>; reg = ; @@ -118,7 +115,6 @@ cpm@f0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "cpm"; model = "CPM2"; ranges = <00000000 00000000 20000>; @@ -161,7 +157,6 @@ #interrupt-cells = <2>; interrupt-controller; reg = <10c00 80>; - built-in; device_type = "cpm-pic"; compatible = "CPM2"; }; diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts index c5adbe40364e..abd73a2c5e0c 100644 --- a/arch/powerpc/boot/dts/mpc8313erdb.dts +++ b/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -29,7 +29,6 @@ timebase-frequency = <0>; // from bootloader bus-frequency = <0>; // from bootloader clock-frequency = <0>; // from bootloader - 32-bit; }; }; @@ -41,7 +40,6 @@ soc8313@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -207,7 +205,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <700 100>; - built-in; device_type = "ipic"; }; }; diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts index f158ed781ba8..e88167dc1859 100644 --- a/arch/powerpc/boot/dts/mpc832x_mds.dts +++ b/arch/powerpc/boot/dts/mpc832x_mds.dts @@ -29,7 +29,6 @@ timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; - 32-bit; }; }; @@ -46,7 +45,6 @@ soc8323@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -163,7 +161,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <700 100>; - built-in; device_type = "ipic"; }; @@ -333,7 +330,6 @@ #address-cells = <0>; #interrupt-cells = <1>; reg = <80 80>; - built-in; big-endian; interrupts = <20 8 21 8>; //high:32 low:33 interrupt-parent = < &ipic >; diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts index 7c4beff3e200..01393e6d7da9 100644 --- a/arch/powerpc/boot/dts/mpc832x_rdb.dts +++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts @@ -29,7 +29,6 @@ timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; - 32-bit; }; }; @@ -41,7 +40,6 @@ soc8323@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -132,7 +130,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <700 100>; - built-in; device_type = "ipic"; }; @@ -292,7 +289,6 @@ #address-cells = <0>; #interrupt-cells = <1>; reg = <80 80>; - built-in; big-endian; interrupts = <20 8 21 8>; //high:32 low:33 interrupt-parent = <&pic>; diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index 502f47c01797..f98c785081bf 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -28,7 +28,6 @@ timebase-frequency = <0>; // from bootloader bus-frequency = <0>; // from bootloader clock-frequency = <0>; // from bootloader - 32-bit; }; }; @@ -40,7 +39,6 @@ soc8349@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -244,7 +242,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <700 100>; - built-in; device_type = "ipic"; }; }; diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index 0b8387141d88..7c89ff7f6a37 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -28,7 +28,6 @@ timebase-frequency = <0>; // from bootloader bus-frequency = <0>; // from bootloader clock-frequency = <0>; // from bootloader - 32-bit; }; }; @@ -40,7 +39,6 @@ soc8349@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -176,7 +174,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <700 100>; - built-in; device_type = "ipic"; }; }; diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index 481099756e44..f4ba85775409 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -29,7 +29,6 @@ timebase-frequency = <0>; // from bootloader bus-frequency = <0>; // from bootloader clock-frequency = <0>; // from bootloader - 32-bit; }; }; @@ -46,7 +45,6 @@ soc8349@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -332,7 +330,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <700 100>; - built-in; device_type = "ipic"; }; }; diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index e3f7c1282068..f14e88ee0f1c 100644 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts @@ -34,7 +34,6 @@ timebase-frequency = <3EF1480>; bus-frequency = ; clock-frequency = <1F78A400>; - 32-bit; }; }; @@ -51,7 +50,6 @@ soc8360@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -178,7 +176,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <700 100>; - built-in; device_type = "ipic"; }; @@ -364,7 +361,6 @@ #address-cells = <0>; #interrupt-cells = <1>; reg = <80 80>; - built-in; big-endian; interrupts = <20 8 21 8>; //high:32 low:33 interrupt-parent = < &ipic >; diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index fc8dff9f6201..e038c04b4220 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts @@ -30,7 +30,6 @@ timebase-frequency = <0>; // 33 MHz, from uboot bus-frequency = <0>; // 166 MHz clock-frequency = <0>; // 825 MHz, from uboot - 32-bit; }; }; @@ -42,7 +41,6 @@ soc8540@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; // CCSRBAR 1M @@ -268,7 +266,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <40000 40000>; - built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; big-endian; diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index fb0b647f8c2a..98afd4df27bf 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts @@ -30,7 +30,6 @@ timebase-frequency = <0>; // 33 MHz, from uboot bus-frequency = <0>; // 166 MHz clock-frequency = <0>; // 825 MHz, from uboot - 32-bit; }; }; @@ -42,7 +41,6 @@ soc8541@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; // CCSRBAR 1M @@ -197,15 +195,12 @@ device_type = "pci"; i8259@19000 { - clock-frequency = <0>; interrupt-controller; device_type = "interrupt-controller"; reg = <19000 0 0 0 1>; #address-cells = <0>; #interrupt-cells = <2>; - built-in; compatible = "chrp,iic"; - big-endian; interrupts = <1>; interrupt-parent = <&pci1>; }; @@ -240,7 +235,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <40000 40000>; - built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; big-endian; diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts index 3e79bf0a3159..88082ac6f2cd 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dts +++ b/arch/powerpc/boot/dts/mpc8544ds.dts @@ -30,7 +30,6 @@ timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; - 32-bit; }; }; @@ -42,7 +41,6 @@ soc8544@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; @@ -295,12 +293,10 @@ reg = <1 20 2 1 a0 2 1 4d0 2>; - clock-frequency = <0>; interrupt-controller; device_type = "interrupt-controller"; #address-cells = <0>; #interrupt-cells = <2>; - built-in; compatible = "chrp,iic"; interrupts = <9 2>; interrupt-parent = <&mpic>; @@ -350,7 +346,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <40000 40000>; - built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; big-endian; diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index d215d21fff42..11b823595a08 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts @@ -30,7 +30,6 @@ timebase-frequency = <0>; // 33 MHz, from uboot bus-frequency = <0>; // 166 MHz clock-frequency = <0>; // 825 MHz, from uboot - 32-bit; }; }; @@ -42,7 +41,6 @@ soc8548@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <00001000 e0001000 000ff000 80000000 80000000 10000000 @@ -318,7 +316,6 @@ interrupt-parent = <&i8259>; i8259: interrupt-controller@20 { - clock-frequency = <0>; interrupt-controller; device_type = "interrupt-controller"; reg = <1 20 2 @@ -326,7 +323,6 @@ 1 4d0 2>; #address-cells = <0>; #interrupt-cells = <2>; - built-in; compatible = "chrp,iic"; interrupts = <0 1>; interrupt-parent = <&mpic>; @@ -394,7 +390,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <40000 40000>; - built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; big-endian; diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index c3c888252121..ce11d11293d0 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts @@ -30,7 +30,6 @@ timebase-frequency = <0>; // 33 MHz, from uboot bus-frequency = <0>; // 166 MHz clock-frequency = <0>; // 825 MHz, from uboot - 32-bit; }; }; @@ -42,7 +41,6 @@ soc8555@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; // CCSRBAR 1M @@ -197,15 +195,12 @@ device_type = "pci"; i8259@19000 { - clock-frequency = <0>; interrupt-controller; device_type = "interrupt-controller"; reg = <19000 0 0 0 1>; #address-cells = <0>; #interrupt-cells = <2>; - built-in; compatible = "chrp,iic"; - big-endian; interrupts = <1>; interrupt-parent = <&pci1>; }; @@ -240,7 +235,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <40000 40000>; - built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; big-endian; diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index 16dbe848cecf..cf87c30cf6a8 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -30,7 +30,6 @@ timebase-frequency = <04ead9a0>; bus-frequency = <13ab6680>; clock-frequency = <312c8040>; - 32-bit; }; }; @@ -42,7 +41,6 @@ soc8560@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -227,14 +225,12 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <40000 40000>; - built-in; device_type = "open-pic"; }; cpm@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "cpm"; model = "CPM2"; ranges = <0 0 c0000>; @@ -249,7 +245,6 @@ interrupts = <2e 2>; interrupt-parent = <&mpic>; reg = <90c00 80>; - built-in; device_type = "cpm-pic"; }; diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index b1dcfbe8c1f8..c472a4b488e9 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -34,7 +34,6 @@ timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; - 32-bit; }; }; @@ -51,7 +50,6 @@ soc8568@e0000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 e0000000 00100000>; reg = ; @@ -258,7 +256,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <40000 40000>; - built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; big-endian; @@ -449,7 +446,6 @@ #address-cells = <0>; #interrupt-cells = <1>; reg = <80 80>; - built-in; big-endian; interrupts = <2e 2 2e 2>; //high:30 low:30 interrupt-parent = <&mpic>; diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts index b0166e5c177e..4d53d9bc3a9d 100644 --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts @@ -30,7 +30,6 @@ timebase-frequency = <0>; // 33 MHz, from uboot bus-frequency = <0>; // From uboot clock-frequency = <0>; // From uboot - 32-bit; }; PowerPC,8641@1 { device_type = "cpu"; @@ -42,7 +41,6 @@ timebase-frequency = <0>; // 33 MHz, from uboot bus-frequency = <0>; // From uboot clock-frequency = <0>; // From uboot - 32-bit; }; }; @@ -54,7 +52,6 @@ soc8641@f8000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <00001000 f8001000 000ff000 80000000 80000000 20000000 @@ -291,12 +288,10 @@ reg = <1 20 2 1 a0 2 1 4d0 2>; - clock-frequency = <0>; interrupt-controller; device_type = "interrupt-controller"; #address-cells = <0>; #interrupt-cells = <2>; - built-in; compatible = "chrp,iic"; interrupts = <9 2>; interrupt-parent = @@ -366,7 +361,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <40000 40000>; - built-in; compatible = "chrp,open-pic"; device_type = "open-pic"; big-endian; diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts index e5e7726ddb03..90f2293ed3cd 100644 --- a/arch/powerpc/boot/dts/mpc866ads.dts +++ b/arch/powerpc/boot/dts/mpc866ads.dts @@ -30,7 +30,6 @@ timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; - 32-bit; interrupts = ; // decrementer interrupt interrupt-parent = <&Mpc8xx_pic>; }; @@ -44,7 +43,6 @@ soc866@ff000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 ff000000 00100000>; reg = ; @@ -78,7 +76,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <0 24>; - built-in; device_type = "mpc8xx-pic"; compatible = "CPM"; }; @@ -86,7 +83,6 @@ cpm@ff000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "cpm"; model = "CPM"; ranges = <0 0 4000>; @@ -103,7 +99,6 @@ interrupts = <5 2 0 2>; interrupt-parent = <&Mpc8xx_pic>; reg = <930 20>; - built-in; device_type = "cpm-pic"; compatible = "CPM"; }; diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts index dc7ab9c80611..e9aa9d00da24 100644 --- a/arch/powerpc/boot/dts/mpc885ads.dts +++ b/arch/powerpc/boot/dts/mpc885ads.dts @@ -30,7 +30,6 @@ timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; - 32-bit; interrupts = ; // decrementer interrupt interrupt-parent = <&Mpc8xx_pic>; }; @@ -44,7 +43,6 @@ soc885@ff000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "soc"; ranges = <0 ff000000 00100000>; reg = ; @@ -98,7 +96,6 @@ #address-cells = <0>; #interrupt-cells = <2>; reg = <0 24>; - built-in; device_type = "mpc8xx-pic"; compatible = "CPM"; }; @@ -117,7 +114,6 @@ cpm@ff000000 { #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <2>; device_type = "cpm"; model = "CPM"; ranges = <0 0 4000>; @@ -134,7 +130,6 @@ interrupts = <5 2 0 2>; interrupt-parent = <&Mpc8xx_pic>; reg = <930 20>; - built-in; device_type = "cpm-pic"; compatible = "CPM"; }; diff --git a/arch/powerpc/boot/dts/prpmc2800.dts b/arch/powerpc/boot/dts/prpmc2800.dts index e416ea67be49..297dfa53fe9e 100644 --- a/arch/powerpc/boot/dts/prpmc2800.dts +++ b/arch/powerpc/boot/dts/prpmc2800.dts @@ -43,7 +43,6 @@ mv64x60@f1000000 { /* Marvell Discovery */ #address-cells = <1>; #size-cells = <1>; - #interrupt-cells = <1>; model = "mv64360"; /* Default */ compatible = "marvell,mv64x60"; clock-frequency = <7f28155>; /* 133.333333 MHz */ From 1b3c5cdab49a605f0e048e1ccbf4cc61a2626485 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 12 Sep 2007 18:23:46 -0500 Subject: [PATCH 0216/2804] [POWERPC] Move PCI nodes to be sibilings with SOC nodes Updated the device trees to have the PCI nodes be at the same level as the SOC node. This is to make it so that the SOC nodes children address space is just on chip registers and not other bus memory as well. Also, for PCIe nodes added a P2P bridge to handle the virtual P2P bridge that exists in the PHB. Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/lite5200.dts | 42 +-- arch/powerpc/boot/dts/lite5200b.dts | 52 +-- arch/powerpc/boot/dts/mpc8313erdb.dts | 60 ++-- arch/powerpc/boot/dts/mpc832x_mds.dts | 118 +++---- arch/powerpc/boot/dts/mpc832x_rdb.dts | 66 ++-- arch/powerpc/boot/dts/mpc8349emitx.dts | 95 +++--- arch/powerpc/boot/dts/mpc8349emitxgp.dts | 44 +-- arch/powerpc/boot/dts/mpc834x_mds.dts | 240 ++++++------- arch/powerpc/boot/dts/mpc836x_mds.dts | 119 ++++--- arch/powerpc/boot/dts/mpc8540ads.dts | 178 +++++----- arch/powerpc/boot/dts/mpc8541cds.dts | 190 +++++------ arch/powerpc/boot/dts/mpc8544ds.dts | 414 +++++++++++----------- arch/powerpc/boot/dts/mpc8548cds.dts | 415 ++++++++++++----------- arch/powerpc/boot/dts/mpc8555cds.dts | 190 +++++------ arch/powerpc/boot/dts/mpc8560ads.dts | 180 +++++----- arch/powerpc/boot/dts/mpc8641_hpcn.dts | 313 ++++++++--------- 16 files changed, 1377 insertions(+), 1339 deletions(-) diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts index d8bcbb870fdc..324e1bd2aa60 100644 --- a/arch/powerpc/boot/dts/lite5200.dts +++ b/arch/powerpc/boot/dts/lite5200.dts @@ -182,27 +182,6 @@ interrupt-parent = <&mpc5200_pic>; }; - pci@0d00 { - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - device_type = "pci"; - compatible = "mpc5200-pci"; - reg = ; - interrupt-map-mask = ; - interrupt-map = ; - clock-frequency = <0>; // From boot loader - interrupts = <2 8 0 2 9 0 2 a 0>; - interrupt-parent = <&mpc5200_pic>; - bus-range = <0 0>; - ranges = <42000000 0 80000000 80000000 0 20000000 - 02000000 0 a0000000 a0000000 0 10000000 - 01000000 0 00000000 b0000000 0 01000000>; - }; - spi@f00 { device_type = "spi"; compatible = "mpc5200-spi"; @@ -337,4 +316,25 @@ reg = <8000 4000>; }; }; + + pci@f0000d00 { + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + compatible = "mpc5200-pci"; + reg = ; + interrupt-map-mask = ; + interrupt-map = ; + clock-frequency = <0>; // From boot loader + interrupts = <2 8 0 2 9 0 2 a 0>; + interrupt-parent = <&mpc5200_pic>; + bus-range = <0 0>; + ranges = <42000000 0 80000000 80000000 0 20000000 + 02000000 0 a0000000 a0000000 0 10000000 + 01000000 0 00000000 b0000000 0 01000000>; + }; }; diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts index 5fe8998abb7c..3f74f73f70ad 100644 --- a/arch/powerpc/boot/dts/lite5200b.dts +++ b/arch/powerpc/boot/dts/lite5200b.dts @@ -182,32 +182,6 @@ interrupt-parent = <&mpc5200_pic>; }; - pci@0d00 { - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - device_type = "pci"; - compatible = "mpc5200b-pci\0mpc5200-pci"; - reg = ; - interrupt-map-mask = ; - interrupt-map = ; - clock-frequency = <0>; // From boot loader - interrupts = <2 8 0 2 9 0 2 a 0>; - interrupt-parent = <&mpc5200_pic>; - bus-range = <0 0>; - ranges = <42000000 0 80000000 80000000 0 20000000 - 02000000 0 a0000000 a0000000 0 10000000 - 01000000 0 00000000 b0000000 0 01000000>; - }; - spi@f00 { device_type = "spi"; compatible = "mpc5200b-spi\0mpc5200-spi"; @@ -342,4 +316,30 @@ reg = <8000 4000>; }; }; + + pci@f0000d00 { + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + compatible = "mpc5200b-pci\0mpc5200-pci"; + reg = ; + interrupt-map-mask = ; + interrupt-map = ; + clock-frequency = <0>; // From boot loader + interrupts = <2 8 0 2 9 0 2 a 0>; + interrupt-parent = <&mpc5200_pic>; + bus-range = <0 0>; + ranges = <42000000 0 80000000 80000000 0 20000000 + 02000000 0 a0000000 a0000000 0 10000000 + 01000000 0 00000000 b0000000 0 01000000>; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts index abd73a2c5e0c..a8eadc8c4497 100644 --- a/arch/powerpc/boot/dts/mpc8313erdb.dts +++ b/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -150,36 +150,6 @@ interrupt-parent = < &ipic >; }; - pci@8500 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x0E -mini PCI */ - 7000 0 0 1 &ipic 12 8 - 7000 0 0 2 &ipic 12 8 - 7000 0 0 3 &ipic 12 8 - 7000 0 0 4 &ipic 12 8 - - /* IDSEL 0x0F - PCI slot */ - 7800 0 0 1 &ipic 11 8 - 7800 0 0 2 &ipic 12 8 - 7800 0 0 3 &ipic 11 8 - 7800 0 0 4 &ipic 12 8>; - interrupt-parent = < &ipic >; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <02000000 0 90000000 90000000 0 10000000 - 42000000 0 80000000 80000000 0 10000000 - 01000000 0 00000000 e2000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8500 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - crypto@30000 { device_type = "crypto"; model = "SEC2"; @@ -208,4 +178,34 @@ device_type = "ipic"; }; }; + + pci@e0008500 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x0E -mini PCI */ + 7000 0 0 1 &ipic 12 8 + 7000 0 0 2 &ipic 12 8 + 7000 0 0 3 &ipic 12 8 + 7000 0 0 4 &ipic 12 8 + + /* IDSEL 0x0F - PCI slot */ + 7800 0 0 1 &ipic 11 8 + 7800 0 0 2 &ipic 12 8 + 7800 0 0 3 &ipic 11 8 + 7800 0 0 4 &ipic 12 8>; + interrupt-parent = < &ipic >; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 90000000 90000000 0 10000000 + 42000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; }; diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts index e88167dc1859..fcd333c391ec 100644 --- a/arch/powerpc/boot/dts/mpc832x_mds.dts +++ b/arch/powerpc/boot/dts/mpc832x_mds.dts @@ -97,65 +97,6 @@ descriptor-types-mask = <0122003f>; }; - pci@8500 { - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x11 AD17 */ - 8800 0 0 1 &ipic 14 8 - 8800 0 0 2 &ipic 15 8 - 8800 0 0 3 &ipic 16 8 - 8800 0 0 4 &ipic 17 8 - - /* IDSEL 0x12 AD18 */ - 9000 0 0 1 &ipic 16 8 - 9000 0 0 2 &ipic 17 8 - 9000 0 0 3 &ipic 14 8 - 9000 0 0 4 &ipic 15 8 - - /* IDSEL 0x13 AD19 */ - 9800 0 0 1 &ipic 17 8 - 9800 0 0 2 &ipic 14 8 - 9800 0 0 3 &ipic 15 8 - 9800 0 0 4 &ipic 16 8 - - /* IDSEL 0x15 AD21*/ - a800 0 0 1 &ipic 14 8 - a800 0 0 2 &ipic 15 8 - a800 0 0 3 &ipic 16 8 - a800 0 0 4 &ipic 17 8 - - /* IDSEL 0x16 AD22*/ - b000 0 0 1 &ipic 17 8 - b000 0 0 2 &ipic 14 8 - b000 0 0 3 &ipic 15 8 - b000 0 0 4 &ipic 16 8 - - /* IDSEL 0x17 AD23*/ - b800 0 0 1 &ipic 16 8 - b800 0 0 2 &ipic 17 8 - b800 0 0 3 &ipic 14 8 - b800 0 0 4 &ipic 15 8 - - /* IDSEL 0x18 AD24*/ - c000 0 0 1 &ipic 15 8 - c000 0 0 2 &ipic 16 8 - c000 0 0 3 &ipic 17 8 - c000 0 0 4 &ipic 14 8>; - interrupt-parent = < &ipic >; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <02000000 0 90000000 90000000 0 10000000 - 42000000 0 80000000 80000000 0 10000000 - 01000000 0 00000000 d0000000 0 00100000>; - clock-frequency = <0>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8500 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - ipic: pic@700 { interrupt-controller; #address-cells = <0>; @@ -335,4 +276,63 @@ interrupt-parent = < &ipic >; }; }; + + pci@e0008500 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x11 AD17 */ + 8800 0 0 1 &ipic 14 8 + 8800 0 0 2 &ipic 15 8 + 8800 0 0 3 &ipic 16 8 + 8800 0 0 4 &ipic 17 8 + + /* IDSEL 0x12 AD18 */ + 9000 0 0 1 &ipic 16 8 + 9000 0 0 2 &ipic 17 8 + 9000 0 0 3 &ipic 14 8 + 9000 0 0 4 &ipic 15 8 + + /* IDSEL 0x13 AD19 */ + 9800 0 0 1 &ipic 17 8 + 9800 0 0 2 &ipic 14 8 + 9800 0 0 3 &ipic 15 8 + 9800 0 0 4 &ipic 16 8 + + /* IDSEL 0x15 AD21*/ + a800 0 0 1 &ipic 14 8 + a800 0 0 2 &ipic 15 8 + a800 0 0 3 &ipic 16 8 + a800 0 0 4 &ipic 17 8 + + /* IDSEL 0x16 AD22*/ + b000 0 0 1 &ipic 17 8 + b000 0 0 2 &ipic 14 8 + b000 0 0 3 &ipic 15 8 + b000 0 0 4 &ipic 16 8 + + /* IDSEL 0x17 AD23*/ + b800 0 0 1 &ipic 16 8 + b800 0 0 2 &ipic 17 8 + b800 0 0 3 &ipic 14 8 + b800 0 0 4 &ipic 15 8 + + /* IDSEL 0x18 AD24*/ + c000 0 0 1 &ipic 15 8 + c000 0 0 2 &ipic 16 8 + c000 0 0 3 &ipic 17 8 + c000 0 0 4 &ipic 14 8>; + interrupt-parent = < &ipic >; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 90000000 90000000 0 10000000 + 42000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 d0000000 0 00100000>; + clock-frequency = <0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; }; diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts index 01393e6d7da9..cdc4a94e9c28 100644 --- a/arch/powerpc/boot/dts/mpc832x_rdb.dts +++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts @@ -92,39 +92,6 @@ descriptor-types-mask = <0122003f>; }; - pci@8500 { - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x10 AD16 (USB) */ - 8000 0 0 1 &pic 11 8 - - /* IDSEL 0x11 AD17 (Mini1)*/ - 8800 0 0 1 &pic 12 8 - 8800 0 0 2 &pic 13 8 - 8800 0 0 3 &pic 14 8 - 8800 0 0 4 &pic 30 8 - - /* IDSEL 0x12 AD18 (PCI/Mini2) */ - 9000 0 0 1 &pic 13 8 - 9000 0 0 2 &pic 14 8 - 9000 0 0 3 &pic 30 8 - 9000 0 0 4 &pic 11 8>; - - interrupt-parent = <&pic>; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <42000000 0 80000000 80000000 0 10000000 - 02000000 0 90000000 90000000 0 10000000 - 01000000 0 d0000000 d0000000 0 04000000>; - clock-frequency = <0>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8500 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - pic:pic@700 { interrupt-controller; #address-cells = <0>; @@ -294,4 +261,37 @@ interrupt-parent = <&pic>; }; }; + + pci@e0008500 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x10 AD16 (USB) */ + 8000 0 0 1 &pic 11 8 + + /* IDSEL 0x11 AD17 (Mini1)*/ + 8800 0 0 1 &pic 12 8 + 8800 0 0 2 &pic 13 8 + 8800 0 0 3 &pic 14 8 + 8800 0 0 4 &pic 30 8 + + /* IDSEL 0x12 AD18 (PCI/Mini2) */ + 9000 0 0 1 &pic 13 8 + 9000 0 0 2 &pic 14 8 + 9000 0 0 3 &pic 30 8 + 9000 0 0 4 &pic 11 8>; + + interrupt-parent = <&pic>; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <42000000 0 80000000 80000000 0 10000000 + 02000000 0 90000000 90000000 0 10000000 + 01000000 0 d0000000 d0000000 0 04000000>; + clock-frequency = <0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index f98c785081bf..67781601b6b3 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -178,52 +178,6 @@ interrupt-parent = < &ipic >; }; - pci@8500 { - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x10 - SATA */ - 8000 0 0 1 &ipic 16 8 /* SATA_INTA */ - >; - interrupt-parent = < &ipic >; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <42000000 0 80000000 80000000 0 10000000 - 02000000 0 90000000 90000000 0 10000000 - 01000000 0 00000000 e2000000 0 01000000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8500 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - - pci@8600 { - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x0E - MiniPCI Slot */ - 7000 0 0 1 &ipic 15 8 /* PCI_INTA */ - - /* IDSEL 0x0F - PCI Slot */ - 7800 0 0 1 &ipic 14 8 /* PCI_INTA */ - 7800 0 0 2 &ipic 15 8 /* PCI_INTB */ - >; - interrupt-parent = < &ipic >; - interrupts = <43 8>; - bus-range = <1 1>; - ranges = <42000000 0 a0000000 a0000000 0 10000000 - 02000000 0 b0000000 b0000000 0 10000000 - 01000000 0 00000000 e3000000 0 01000000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8600 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - crypto@30000 { device_type = "crypto"; model = "SEC2"; @@ -245,4 +199,53 @@ device_type = "ipic"; }; }; + + pci@e0008500 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x10 - SATA */ + 8000 0 0 1 &ipic 16 8 /* SATA_INTA */ + >; + interrupt-parent = < &ipic >; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <42000000 0 80000000 80000000 0 10000000 + 02000000 0 90000000 90000000 0 10000000 + 01000000 0 00000000 e2000000 0 01000000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; + + pci@e0008600 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x0E - MiniPCI Slot */ + 7000 0 0 1 &ipic 15 8 /* PCI_INTA */ + + /* IDSEL 0x0F - PCI Slot */ + 7800 0 0 1 &ipic 14 8 /* PCI_INTA */ + 7800 0 0 2 &ipic 15 8 /* PCI_INTB */ + >; + interrupt-parent = < &ipic >; + interrupts = <43 8>; + bus-range = <0 0>; + ranges = <42000000 0 a0000000 a0000000 0 10000000 + 02000000 0 b0000000 b0000000 0 10000000 + 01000000 0 00000000 e3000000 0 01000000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; + + + }; diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index 7c89ff7f6a37..fa852ba1b6ba 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -134,28 +134,6 @@ interrupt-parent = < &ipic >; }; - pci@8600 { - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x0F - PCI Slot */ - 7800 0 0 1 &ipic 14 8 /* PCI_INTA */ - 7800 0 0 2 &ipic 15 8 /* PCI_INTB */ - >; - interrupt-parent = < &ipic >; - interrupts = <43 8>; - bus-range = <1 1>; - ranges = <42000000 0 a0000000 a0000000 0 10000000 - 02000000 0 b0000000 b0000000 0 10000000 - 01000000 0 00000000 e3000000 0 01000000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8600 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - crypto@30000 { device_type = "crypto"; model = "SEC2"; @@ -177,4 +155,26 @@ device_type = "ipic"; }; }; + + pci@e0008600 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x0F - PCI Slot */ + 7800 0 0 1 &ipic 14 8 /* PCI_INTA */ + 7800 0 0 2 &ipic 15 8 /* PCI_INTB */ + >; + interrupt-parent = < &ipic >; + interrupts = <43 8>; + bus-range = <1 1>; + ranges = <42000000 0 a0000000 a0000000 0 10000000 + 02000000 0 b0000000 b0000000 0 10000000 + 01000000 0 00000000 e3000000 0 01000000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; }; diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index f4ba85775409..1b8882e20040 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -183,126 +183,6 @@ interrupt-parent = < &ipic >; }; - pci@8500 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x11 */ - 8800 0 0 1 &ipic 14 8 - 8800 0 0 2 &ipic 15 8 - 8800 0 0 3 &ipic 16 8 - 8800 0 0 4 &ipic 17 8 - - /* IDSEL 0x12 */ - 9000 0 0 1 &ipic 16 8 - 9000 0 0 2 &ipic 17 8 - 9000 0 0 3 &ipic 14 8 - 9000 0 0 4 &ipic 15 8 - - /* IDSEL 0x13 */ - 9800 0 0 1 &ipic 17 8 - 9800 0 0 2 &ipic 14 8 - 9800 0 0 3 &ipic 15 8 - 9800 0 0 4 &ipic 16 8 - - /* IDSEL 0x15 */ - a800 0 0 1 &ipic 14 8 - a800 0 0 2 &ipic 15 8 - a800 0 0 3 &ipic 16 8 - a800 0 0 4 &ipic 17 8 - - /* IDSEL 0x16 */ - b000 0 0 1 &ipic 17 8 - b000 0 0 2 &ipic 14 8 - b000 0 0 3 &ipic 15 8 - b000 0 0 4 &ipic 16 8 - - /* IDSEL 0x17 */ - b800 0 0 1 &ipic 16 8 - b800 0 0 2 &ipic 17 8 - b800 0 0 3 &ipic 14 8 - b800 0 0 4 &ipic 15 8 - - /* IDSEL 0x18 */ - c000 0 0 1 &ipic 15 8 - c000 0 0 2 &ipic 16 8 - c000 0 0 3 &ipic 17 8 - c000 0 0 4 &ipic 14 8>; - interrupt-parent = < &ipic >; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <02000000 0 90000000 90000000 0 10000000 - 42000000 0 80000000 80000000 0 10000000 - 01000000 0 00000000 e2000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8500 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - - pci@8600 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x11 */ - 8800 0 0 1 &ipic 14 8 - 8800 0 0 2 &ipic 15 8 - 8800 0 0 3 &ipic 16 8 - 8800 0 0 4 &ipic 17 8 - - /* IDSEL 0x12 */ - 9000 0 0 1 &ipic 16 8 - 9000 0 0 2 &ipic 17 8 - 9000 0 0 3 &ipic 14 8 - 9000 0 0 4 &ipic 15 8 - - /* IDSEL 0x13 */ - 9800 0 0 1 &ipic 17 8 - 9800 0 0 2 &ipic 14 8 - 9800 0 0 3 &ipic 15 8 - 9800 0 0 4 &ipic 16 8 - - /* IDSEL 0x15 */ - a800 0 0 1 &ipic 14 8 - a800 0 0 2 &ipic 15 8 - a800 0 0 3 &ipic 16 8 - a800 0 0 4 &ipic 17 8 - - /* IDSEL 0x16 */ - b000 0 0 1 &ipic 17 8 - b000 0 0 2 &ipic 14 8 - b000 0 0 3 &ipic 15 8 - b000 0 0 4 &ipic 16 8 - - /* IDSEL 0x17 */ - b800 0 0 1 &ipic 16 8 - b800 0 0 2 &ipic 17 8 - b800 0 0 3 &ipic 14 8 - b800 0 0 4 &ipic 15 8 - - /* IDSEL 0x18 */ - c000 0 0 1 &ipic 15 8 - c000 0 0 2 &ipic 16 8 - c000 0 0 3 &ipic 17 8 - c000 0 0 4 &ipic 14 8>; - interrupt-parent = < &ipic >; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <02000000 0 b0000000 b0000000 0 10000000 - 42000000 0 a0000000 a0000000 0 10000000 - 01000000 0 00000000 e2100000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8600 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - /* May need to remove if on a part without crypto engine */ crypto@30000 { device_type = "crypto"; @@ -333,4 +213,124 @@ device_type = "ipic"; }; }; + + pci@e0008500 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x11 */ + 8800 0 0 1 &ipic 14 8 + 8800 0 0 2 &ipic 15 8 + 8800 0 0 3 &ipic 16 8 + 8800 0 0 4 &ipic 17 8 + + /* IDSEL 0x12 */ + 9000 0 0 1 &ipic 16 8 + 9000 0 0 2 &ipic 17 8 + 9000 0 0 3 &ipic 14 8 + 9000 0 0 4 &ipic 15 8 + + /* IDSEL 0x13 */ + 9800 0 0 1 &ipic 17 8 + 9800 0 0 2 &ipic 14 8 + 9800 0 0 3 &ipic 15 8 + 9800 0 0 4 &ipic 16 8 + + /* IDSEL 0x15 */ + a800 0 0 1 &ipic 14 8 + a800 0 0 2 &ipic 15 8 + a800 0 0 3 &ipic 16 8 + a800 0 0 4 &ipic 17 8 + + /* IDSEL 0x16 */ + b000 0 0 1 &ipic 17 8 + b000 0 0 2 &ipic 14 8 + b000 0 0 3 &ipic 15 8 + b000 0 0 4 &ipic 16 8 + + /* IDSEL 0x17 */ + b800 0 0 1 &ipic 16 8 + b800 0 0 2 &ipic 17 8 + b800 0 0 3 &ipic 14 8 + b800 0 0 4 &ipic 15 8 + + /* IDSEL 0x18 */ + c000 0 0 1 &ipic 15 8 + c000 0 0 2 &ipic 16 8 + c000 0 0 3 &ipic 17 8 + c000 0 0 4 &ipic 14 8>; + interrupt-parent = < &ipic >; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 90000000 90000000 0 10000000 + 42000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; + + pci@e0008600 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x11 */ + 8800 0 0 1 &ipic 14 8 + 8800 0 0 2 &ipic 15 8 + 8800 0 0 3 &ipic 16 8 + 8800 0 0 4 &ipic 17 8 + + /* IDSEL 0x12 */ + 9000 0 0 1 &ipic 16 8 + 9000 0 0 2 &ipic 17 8 + 9000 0 0 3 &ipic 14 8 + 9000 0 0 4 &ipic 15 8 + + /* IDSEL 0x13 */ + 9800 0 0 1 &ipic 17 8 + 9800 0 0 2 &ipic 14 8 + 9800 0 0 3 &ipic 15 8 + 9800 0 0 4 &ipic 16 8 + + /* IDSEL 0x15 */ + a800 0 0 1 &ipic 14 8 + a800 0 0 2 &ipic 15 8 + a800 0 0 3 &ipic 16 8 + a800 0 0 4 &ipic 17 8 + + /* IDSEL 0x16 */ + b000 0 0 1 &ipic 17 8 + b000 0 0 2 &ipic 14 8 + b000 0 0 3 &ipic 15 8 + b000 0 0 4 &ipic 16 8 + + /* IDSEL 0x17 */ + b800 0 0 1 &ipic 16 8 + b800 0 0 2 &ipic 17 8 + b800 0 0 3 &ipic 14 8 + b800 0 0 4 &ipic 15 8 + + /* IDSEL 0x18 */ + c000 0 0 1 &ipic 15 8 + c000 0 0 2 &ipic 16 8 + c000 0 0 3 &ipic 17 8 + c000 0 0 4 &ipic 14 8>; + interrupt-parent = < &ipic >; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 b0000000 b0000000 0 10000000 + 42000000 0 a0000000 a0000000 0 10000000 + 01000000 0 00000000 e2100000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; }; diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index f14e88ee0f1c..fbd1573c348b 100644 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts @@ -111,66 +111,6 @@ descriptor-types-mask = <01010ebf>; }; - pci@8500 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x11 AD17 */ - 8800 0 0 1 &ipic 14 8 - 8800 0 0 2 &ipic 15 8 - 8800 0 0 3 &ipic 16 8 - 8800 0 0 4 &ipic 17 8 - - /* IDSEL 0x12 AD18 */ - 9000 0 0 1 &ipic 16 8 - 9000 0 0 2 &ipic 17 8 - 9000 0 0 3 &ipic 14 8 - 9000 0 0 4 &ipic 15 8 - - /* IDSEL 0x13 AD19 */ - 9800 0 0 1 &ipic 17 8 - 9800 0 0 2 &ipic 14 8 - 9800 0 0 3 &ipic 15 8 - 9800 0 0 4 &ipic 16 8 - - /* IDSEL 0x15 AD21*/ - a800 0 0 1 &ipic 14 8 - a800 0 0 2 &ipic 15 8 - a800 0 0 3 &ipic 16 8 - a800 0 0 4 &ipic 17 8 - - /* IDSEL 0x16 AD22*/ - b000 0 0 1 &ipic 17 8 - b000 0 0 2 &ipic 14 8 - b000 0 0 3 &ipic 15 8 - b000 0 0 4 &ipic 16 8 - - /* IDSEL 0x17 AD23*/ - b800 0 0 1 &ipic 16 8 - b800 0 0 2 &ipic 17 8 - b800 0 0 3 &ipic 14 8 - b800 0 0 4 &ipic 15 8 - - /* IDSEL 0x18 AD24*/ - c000 0 0 1 &ipic 15 8 - c000 0 0 2 &ipic 16 8 - c000 0 0 3 &ipic 17 8 - c000 0 0 4 &ipic 14 8>; - interrupt-parent = < &ipic >; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <02000000 0 a0000000 a0000000 0 10000000 - 42000000 0 80000000 80000000 0 10000000 - 01000000 0 00000000 e2000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8500 100>; - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - ipic: pic@700 { interrupt-controller; #address-cells = <0>; @@ -365,6 +305,65 @@ interrupts = <20 8 21 8>; //high:32 low:33 interrupt-parent = < &ipic >; }; + }; + pci@e0008500 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x11 AD17 */ + 8800 0 0 1 &ipic 14 8 + 8800 0 0 2 &ipic 15 8 + 8800 0 0 3 &ipic 16 8 + 8800 0 0 4 &ipic 17 8 + + /* IDSEL 0x12 AD18 */ + 9000 0 0 1 &ipic 16 8 + 9000 0 0 2 &ipic 17 8 + 9000 0 0 3 &ipic 14 8 + 9000 0 0 4 &ipic 15 8 + + /* IDSEL 0x13 AD19 */ + 9800 0 0 1 &ipic 17 8 + 9800 0 0 2 &ipic 14 8 + 9800 0 0 3 &ipic 15 8 + 9800 0 0 4 &ipic 16 8 + + /* IDSEL 0x15 AD21*/ + a800 0 0 1 &ipic 14 8 + a800 0 0 2 &ipic 15 8 + a800 0 0 3 &ipic 16 8 + a800 0 0 4 &ipic 17 8 + + /* IDSEL 0x16 AD22*/ + b000 0 0 1 &ipic 17 8 + b000 0 0 2 &ipic 14 8 + b000 0 0 3 &ipic 15 8 + b000 0 0 4 &ipic 16 8 + + /* IDSEL 0x17 AD23*/ + b800 0 0 1 &ipic 16 8 + b800 0 0 2 &ipic 17 8 + b800 0 0 3 &ipic 14 8 + b800 0 0 4 &ipic 15 8 + + /* IDSEL 0x18 AD24*/ + c000 0 0 1 &ipic 15 8 + c000 0 0 2 &ipic 16 8 + c000 0 0 3 &ipic 17 8 + c000 0 0 4 &ipic 14 8>; + interrupt-parent = < &ipic >; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 a0000000 a0000000 0 10000000 + 42000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; }; }; diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index e038c04b4220..6442a717ec3b 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts @@ -171,95 +171,6 @@ interrupts = <2a 2>; interrupt-parent = <&mpic>; }; - pci@8000 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x02 */ - 1000 0 0 1 &mpic 1 1 - 1000 0 0 2 &mpic 2 1 - 1000 0 0 3 &mpic 3 1 - 1000 0 0 4 &mpic 4 1 - - /* IDSEL 0x03 */ - 1800 0 0 1 &mpic 4 1 - 1800 0 0 2 &mpic 1 1 - 1800 0 0 3 &mpic 2 1 - 1800 0 0 4 &mpic 3 1 - - /* IDSEL 0x04 */ - 2000 0 0 1 &mpic 3 1 - 2000 0 0 2 &mpic 4 1 - 2000 0 0 3 &mpic 1 1 - 2000 0 0 4 &mpic 2 1 - - /* IDSEL 0x05 */ - 2800 0 0 1 &mpic 2 1 - 2800 0 0 2 &mpic 3 1 - 2800 0 0 3 &mpic 4 1 - 2800 0 0 4 &mpic 1 1 - - /* IDSEL 0x0c */ - 6000 0 0 1 &mpic 1 1 - 6000 0 0 2 &mpic 2 1 - 6000 0 0 3 &mpic 3 1 - 6000 0 0 4 &mpic 4 1 - - /* IDSEL 0x0d */ - 6800 0 0 1 &mpic 4 1 - 6800 0 0 2 &mpic 1 1 - 6800 0 0 3 &mpic 2 1 - 6800 0 0 4 &mpic 3 1 - - /* IDSEL 0x0e */ - 7000 0 0 1 &mpic 3 1 - 7000 0 0 2 &mpic 4 1 - 7000 0 0 3 &mpic 1 1 - 7000 0 0 4 &mpic 2 1 - - /* IDSEL 0x0f */ - 7800 0 0 1 &mpic 2 1 - 7800 0 0 2 &mpic 3 1 - 7800 0 0 3 &mpic 4 1 - 7800 0 0 4 &mpic 1 1 - - /* IDSEL 0x12 */ - 9000 0 0 1 &mpic 1 1 - 9000 0 0 2 &mpic 2 1 - 9000 0 0 3 &mpic 3 1 - 9000 0 0 4 &mpic 4 1 - - /* IDSEL 0x13 */ - 9800 0 0 1 &mpic 4 1 - 9800 0 0 2 &mpic 1 1 - 9800 0 0 3 &mpic 2 1 - 9800 0 0 4 &mpic 3 1 - - /* IDSEL 0x14 */ - a000 0 0 1 &mpic 3 1 - a000 0 0 2 &mpic 4 1 - a000 0 0 3 &mpic 1 1 - a000 0 0 4 &mpic 2 1 - - /* IDSEL 0x15 */ - a800 0 0 1 &mpic 2 1 - a800 0 0 2 &mpic 3 1 - a800 0 0 3 &mpic 4 1 - a800 0 0 4 &mpic 1 1>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - bus-range = <0 0>; - ranges = <02000000 0 80000000 80000000 0 20000000 - 01000000 0 00000000 e2000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8000 1000>; - compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci"; - device_type = "pci"; - }; - mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; @@ -271,4 +182,93 @@ big-endian; }; }; + + pci@e0008000 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x02 */ + 1000 0 0 1 &mpic 1 1 + 1000 0 0 2 &mpic 2 1 + 1000 0 0 3 &mpic 3 1 + 1000 0 0 4 &mpic 4 1 + + /* IDSEL 0x03 */ + 1800 0 0 1 &mpic 4 1 + 1800 0 0 2 &mpic 1 1 + 1800 0 0 3 &mpic 2 1 + 1800 0 0 4 &mpic 3 1 + + /* IDSEL 0x04 */ + 2000 0 0 1 &mpic 3 1 + 2000 0 0 2 &mpic 4 1 + 2000 0 0 3 &mpic 1 1 + 2000 0 0 4 &mpic 2 1 + + /* IDSEL 0x05 */ + 2800 0 0 1 &mpic 2 1 + 2800 0 0 2 &mpic 3 1 + 2800 0 0 3 &mpic 4 1 + 2800 0 0 4 &mpic 1 1 + + /* IDSEL 0x0c */ + 6000 0 0 1 &mpic 1 1 + 6000 0 0 2 &mpic 2 1 + 6000 0 0 3 &mpic 3 1 + 6000 0 0 4 &mpic 4 1 + + /* IDSEL 0x0d */ + 6800 0 0 1 &mpic 4 1 + 6800 0 0 2 &mpic 1 1 + 6800 0 0 3 &mpic 2 1 + 6800 0 0 4 &mpic 3 1 + + /* IDSEL 0x0e */ + 7000 0 0 1 &mpic 3 1 + 7000 0 0 2 &mpic 4 1 + 7000 0 0 3 &mpic 1 1 + 7000 0 0 4 &mpic 2 1 + + /* IDSEL 0x0f */ + 7800 0 0 1 &mpic 2 1 + 7800 0 0 2 &mpic 3 1 + 7800 0 0 3 &mpic 4 1 + 7800 0 0 4 &mpic 1 1 + + /* IDSEL 0x12 */ + 9000 0 0 1 &mpic 1 1 + 9000 0 0 2 &mpic 2 1 + 9000 0 0 3 &mpic 3 1 + 9000 0 0 4 &mpic 4 1 + + /* IDSEL 0x13 */ + 9800 0 0 1 &mpic 4 1 + 9800 0 0 2 &mpic 1 1 + 9800 0 0 3 &mpic 2 1 + 9800 0 0 4 &mpic 3 1 + + /* IDSEL 0x14 */ + a000 0 0 1 &mpic 3 1 + a000 0 0 2 &mpic 4 1 + a000 0 0 3 &mpic 1 1 + a000 0 0 4 &mpic 2 1 + + /* IDSEL 0x15 */ + a800 0 0 1 &mpic 2 1 + a800 0 0 2 &mpic 3 1 + a800 0 0 3 &mpic 4 1 + a800 0 0 4 &mpic 1 1>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + bus-range = <0 0>; + ranges = <02000000 0 80000000 80000000 0 20000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci"; + device_type = "pci"; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index 98afd4df27bf..6633e07d9f4d 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts @@ -43,7 +43,7 @@ #size-cells = <1>; device_type = "soc"; ranges = <0 e0000000 00100000>; - reg = ; // CCSRBAR 1M + reg = ; // CCSRBAR 1M bus-frequency = <0>; memory-controller@2000 { @@ -135,100 +135,6 @@ interrupt-parent = <&mpic>; }; - pci1: pci@8000 { - interrupt-map-mask = <1f800 0 0 7>; - interrupt-map = < - - /* IDSEL 0x10 */ - 08000 0 0 1 &mpic 0 1 - 08000 0 0 2 &mpic 1 1 - 08000 0 0 3 &mpic 2 1 - 08000 0 0 4 &mpic 3 1 - - /* IDSEL 0x11 */ - 08800 0 0 1 &mpic 0 1 - 08800 0 0 2 &mpic 1 1 - 08800 0 0 3 &mpic 2 1 - 08800 0 0 4 &mpic 3 1 - - /* IDSEL 0x12 (Slot 1) */ - 09000 0 0 1 &mpic 0 1 - 09000 0 0 2 &mpic 1 1 - 09000 0 0 3 &mpic 2 1 - 09000 0 0 4 &mpic 3 1 - - /* IDSEL 0x13 (Slot 2) */ - 09800 0 0 1 &mpic 1 1 - 09800 0 0 2 &mpic 2 1 - 09800 0 0 3 &mpic 3 1 - 09800 0 0 4 &mpic 0 1 - - /* IDSEL 0x14 (Slot 3) */ - 0a000 0 0 1 &mpic 2 1 - 0a000 0 0 2 &mpic 3 1 - 0a000 0 0 3 &mpic 0 1 - 0a000 0 0 4 &mpic 1 1 - - /* IDSEL 0x15 (Slot 4) */ - 0a800 0 0 1 &mpic 3 1 - 0a800 0 0 2 &mpic 0 1 - 0a800 0 0 3 &mpic 1 1 - 0a800 0 0 4 &mpic 2 1 - - /* Bus 1 (Tundra Bridge) */ - /* IDSEL 0x12 (ISA bridge) */ - 19000 0 0 1 &mpic 0 1 - 19000 0 0 2 &mpic 1 1 - 19000 0 0 3 &mpic 2 1 - 19000 0 0 4 &mpic 3 1>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - bus-range = <0 0>; - ranges = <02000000 0 80000000 80000000 0 20000000 - 01000000 0 00000000 e2000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8000 1000>; - compatible = "fsl,mpc8540-pci"; - device_type = "pci"; - - i8259@19000 { - interrupt-controller; - device_type = "interrupt-controller"; - reg = <19000 0 0 0 1>; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <1>; - interrupt-parent = <&pci1>; - }; - }; - - pci@9000 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x15 */ - a800 0 0 1 &mpic b 1 - a800 0 0 2 &mpic b 1 - a800 0 0 3 &mpic b 1 - a800 0 0 4 &mpic b 1>; - interrupt-parent = <&mpic>; - interrupts = <19 2>; - bus-range = <0 0>; - ranges = <02000000 0 a0000000 a0000000 0 20000000 - 01000000 0 00000000 e3000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <9000 1000>; - compatible = "fsl,mpc8540-pci"; - device_type = "pci"; - }; - mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; @@ -240,4 +146,98 @@ big-endian; }; }; + + pci1: pci@e0008000 { + interrupt-map-mask = <1f800 0 0 7>; + interrupt-map = < + + /* IDSEL 0x10 */ + 08000 0 0 1 &mpic 0 1 + 08000 0 0 2 &mpic 1 1 + 08000 0 0 3 &mpic 2 1 + 08000 0 0 4 &mpic 3 1 + + /* IDSEL 0x11 */ + 08800 0 0 1 &mpic 0 1 + 08800 0 0 2 &mpic 1 1 + 08800 0 0 3 &mpic 2 1 + 08800 0 0 4 &mpic 3 1 + + /* IDSEL 0x12 (Slot 1) */ + 09000 0 0 1 &mpic 0 1 + 09000 0 0 2 &mpic 1 1 + 09000 0 0 3 &mpic 2 1 + 09000 0 0 4 &mpic 3 1 + + /* IDSEL 0x13 (Slot 2) */ + 09800 0 0 1 &mpic 1 1 + 09800 0 0 2 &mpic 2 1 + 09800 0 0 3 &mpic 3 1 + 09800 0 0 4 &mpic 0 1 + + /* IDSEL 0x14 (Slot 3) */ + 0a000 0 0 1 &mpic 2 1 + 0a000 0 0 2 &mpic 3 1 + 0a000 0 0 3 &mpic 0 1 + 0a000 0 0 4 &mpic 1 1 + + /* IDSEL 0x15 (Slot 4) */ + 0a800 0 0 1 &mpic 3 1 + 0a800 0 0 2 &mpic 0 1 + 0a800 0 0 3 &mpic 1 1 + 0a800 0 0 4 &mpic 2 1 + + /* Bus 1 (Tundra Bridge) */ + /* IDSEL 0x12 (ISA bridge) */ + 19000 0 0 1 &mpic 0 1 + 19000 0 0 2 &mpic 1 1 + 19000 0 0 3 &mpic 2 1 + 19000 0 0 4 &mpic 3 1>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + bus-range = <0 0>; + ranges = <02000000 0 80000000 80000000 0 20000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + + i8259@19000 { + interrupt-controller; + device_type = "interrupt-controller"; + reg = <19000 0 0 0 1>; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <1>; + interrupt-parent = <&pci1>; + }; + }; + + pci@e0009000 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x15 */ + a800 0 0 1 &mpic b 1 + a800 0 0 2 &mpic b 1 + a800 0 0 3 &mpic b 1 + a800 0 0 4 &mpic b 1>; + interrupt-parent = <&mpic>; + interrupts = <19 2>; + bus-range = <0 0>; + ranges = <02000000 0 a0000000 a0000000 0 20000000 + 01000000 0 00000000 e3000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts index 88082ac6f2cd..3f9d15cf13e0 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dts +++ b/arch/powerpc/boot/dts/mpc8544ds.dts @@ -43,16 +43,7 @@ #size-cells = <1>; device_type = "soc"; - - ranges = <00001000 e0001000 000ff000 - 80000000 80000000 20000000 - a0000000 a0000000 10000000 - b0000000 b0000000 00100000 - c0000000 c0000000 20000000 - b0100000 b0100000 00100000 - e1000000 e1000000 00010000 - e1010000 e1010000 00010000 - e1020000 e1020000 00010000>; + ranges = <00000000 e0000000 00100000>; reg = ; // CCSRBAR 1M bus-frequency = <0>; // Filled out by uboot. @@ -147,193 +138,6 @@ interrupt-parent = <&mpic>; }; - pci@8000 { - compatible = "fsl,mpc8540-pci"; - device_type = "pci"; - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x11 J17 Slot 1 */ - 8800 0 0 1 &mpic 2 1 - 8800 0 0 2 &mpic 3 1 - 8800 0 0 3 &mpic 4 1 - 8800 0 0 4 &mpic 1 1 - - /* IDSEL 0x12 J16 Slot 2 */ - - 9000 0 0 1 &mpic 3 1 - 9000 0 0 2 &mpic 4 1 - 9000 0 0 3 &mpic 2 1 - 9000 0 0 4 &mpic 1 1>; - - interrupt-parent = <&mpic>; - interrupts = <18 2>; - bus-range = <0 ff>; - ranges = <02000000 0 c0000000 c0000000 0 20000000 - 01000000 0 00000000 e1000000 0 00010000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8000 1000>; - }; - - pcie@9000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <9000 1000>; - bus-range = <0 ff>; - ranges = <02000000 0 80000000 80000000 0 20000000 - 01000000 0 00000000 e1010000 0 00010000>; - clock-frequency = <1fca055>; - interrupt-parent = <&mpic>; - interrupts = <1a 2>; - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x0 */ - 0000 0 0 1 &mpic 4 1 - 0000 0 0 2 &mpic 5 1 - 0000 0 0 3 &mpic 6 1 - 0000 0 0 4 &mpic 7 1 - >; - }; - - pcie@a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = ; - bus-range = <0 ff>; - ranges = <02000000 0 a0000000 a0000000 0 10000000 - 01000000 0 00000000 e1020000 0 00010000>; - clock-frequency = <1fca055>; - interrupt-parent = <&mpic>; - interrupts = <19 2>; - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x0 */ - 0000 0 0 1 &mpic 0 1 - 0000 0 0 2 &mpic 1 1 - 0000 0 0 3 &mpic 2 1 - 0000 0 0 4 &mpic 3 1 - >; - }; - - pcie@b000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = ; - bus-range = <0 ff>; - ranges = <02000000 0 b0000000 b0000000 0 00100000 - 01000000 0 00000000 b0100000 0 00100000>; - clock-frequency = <1fca055>; - interrupt-parent = <&mpic>; - interrupts = <1b 2>; - interrupt-map-mask = ; - interrupt-map = < - // IDSEL 0x1c USB - e000 0 0 0 &i8259 c 2 - e100 0 0 0 &i8259 9 2 - e200 0 0 0 &i8259 a 2 - e300 0 0 0 &i8259 b 2 - - // IDSEL 0x1d Audio - e800 0 0 0 &i8259 6 2 - - // IDSEL 0x1e Legacy - f000 0 0 0 &i8259 7 2 - f100 0 0 0 &i8259 7 2 - - // IDSEL 0x1f IDE/SATA - f800 0 0 0 &i8259 e 2 - f900 0 0 0 &i8259 5 2 - >; - uli1575@0 { - reg = <0 0 0 0 0>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <02000000 0 b0000000 - 02000000 0 b0000000 - 0 00100000 - 01000000 0 00000000 - 01000000 0 00000000 - 0 00100000>; - - pci_bridge@0 { - reg = <0 0 0 0 0>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <02000000 0 b0000000 - 02000000 0 b0000000 - 0 00100000 - 01000000 0 00000000 - 01000000 0 00000000 - 0 00100000>; - - isa@1e { - device_type = "isa"; - #interrupt-cells = <2>; - #size-cells = <1>; - #address-cells = <2>; - reg = ; - ranges = <1 0 - 01000000 0 0 - 00001000>; - interrupt-parent = <&i8259>; - - i8259: interrupt-controller@20 { - reg = <1 20 2 - 1 a0 2 - 1 4d0 2>; - interrupt-controller; - device_type = "interrupt-controller"; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <9 2>; - interrupt-parent = <&mpic>; - }; - - i8042@60 { - #size-cells = <0>; - #address-cells = <1>; - reg = <1 60 1 1 64 1>; - interrupts = <1 3 c 3>; - interrupt-parent = <&i8259>; - - keyboard@0 { - reg = <0>; - compatible = "pnpPNP,303"; - }; - - mouse@1 { - reg = <1>; - compatible = "pnpPNP,f03"; - }; - }; - - rtc@70 { - compatible = "pnpPNP,b00"; - reg = <1 70 2>; - }; - - gpio@400 { - reg = <1 400 80>; - }; - }; - }; - }; - - }; - global-utilities@e0000 { //global utilities block compatible = "fsl,mpc8548-guts"; reg = ; @@ -351,4 +155,220 @@ big-endian; }; }; + + pci@e0008000 { + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x11 J17 Slot 1 */ + 8800 0 0 1 &mpic 2 1 + 8800 0 0 2 &mpic 3 1 + 8800 0 0 3 &mpic 4 1 + 8800 0 0 4 &mpic 1 1 + + /* IDSEL 0x12 J16 Slot 2 */ + + 9000 0 0 1 &mpic 3 1 + 9000 0 0 2 &mpic 4 1 + 9000 0 0 3 &mpic 2 1 + 9000 0 0 4 &mpic 1 1>; + + interrupt-parent = <&mpic>; + interrupts = <18 2>; + bus-range = <0 ff>; + ranges = <02000000 0 c0000000 c0000000 0 20000000 + 01000000 0 00000000 e1000000 0 00010000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + }; + + pcie@e0009000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 ff>; + ranges = <02000000 0 80000000 80000000 0 20000000 + 01000000 0 00000000 e1010000 0 00010000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <1a 2>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 4 1 + 0000 0 0 2 &mpic 5 1 + 0000 0 0 3 &mpic 6 1 + 0000 0 0 4 &mpic 7 1 + >; + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 80000000 + 02000000 0 80000000 + 0 20000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00010000>; + }; + }; + + pcie@e000a000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 ff>; + ranges = <02000000 0 a0000000 a0000000 0 10000000 + 01000000 0 00000000 e1020000 0 00010000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <19 2>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 0 1 + 0000 0 0 2 &mpic 1 1 + 0000 0 0 3 &mpic 2 1 + 0000 0 0 4 &mpic 3 1 + >; + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 a0000000 + 02000000 0 a0000000 + 0 10000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00010000>; + }; + }; + + pcie@e000b000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 ff>; + ranges = <02000000 0 b0000000 b0000000 0 00100000 + 01000000 0 00000000 b0100000 0 00100000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <1b 2>; + interrupt-map-mask = ; + interrupt-map = < + // IDSEL 0x1c USB + e000 0 0 0 &i8259 c 2 + e100 0 0 0 &i8259 9 2 + e200 0 0 0 &i8259 a 2 + e300 0 0 0 &i8259 b 2 + + // IDSEL 0x1d Audio + e800 0 0 0 &i8259 6 2 + + // IDSEL 0x1e Legacy + f000 0 0 0 &i8259 7 2 + f100 0 0 0 &i8259 7 2 + + // IDSEL 0x1f IDE/SATA + f800 0 0 0 &i8259 e 2 + f900 0 0 0 &i8259 5 2 + >; + + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 b0000000 + 02000000 0 b0000000 + 0 00100000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + + uli1575@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + ranges = <02000000 0 b0000000 + 02000000 0 b0000000 + 0 00100000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + isa@1e { + device_type = "isa"; + #interrupt-cells = <2>; + #size-cells = <1>; + #address-cells = <2>; + reg = ; + ranges = <1 0 + 01000000 0 0 + 00001000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + reg = <1 20 2 + 1 a0 2 + 1 4d0 2>; + interrupt-controller; + device_type = "interrupt-controller"; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <9 2>; + interrupt-parent = <&mpic>; + }; + + i8042@60 { + #size-cells = <0>; + #address-cells = <1>; + reg = <1 60 1 1 64 1>; + interrupts = <1 3 c 3>; + interrupt-parent = <&i8259>; + + keyboard@0 { + reg = <0>; + compatible = "pnpPNP,303"; + }; + + mouse@1 { + reg = <1>; + compatible = "pnpPNP,f03"; + }; + }; + + rtc@70 { + compatible = "pnpPNP,b00"; + reg = <1 70 2>; + }; + + gpio@400 { + reg = <1 400 80>; + }; + }; + }; + }; + + }; }; diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index 11b823595a08..69ca5025d972 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts @@ -42,13 +42,7 @@ #address-cells = <1>; #size-cells = <1>; device_type = "soc"; - ranges = <00001000 e0001000 000ff000 - 80000000 80000000 10000000 - e2000000 e2000000 00800000 - 90000000 90000000 10000000 - e2800000 e2800000 00800000 - a0000000 a0000000 20000000 - e3000000 e3000000 01000000>; + ranges = <00000000 e0000000 00100000>; reg = ; // CCSRBAR bus-frequency = <0>; @@ -187,203 +181,6 @@ fsl,has-rstcr; }; - pci@8000 { - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x4 (PCIX Slot 2) */ - 02000 0 0 1 &mpic 0 1 - 02000 0 0 2 &mpic 1 1 - 02000 0 0 3 &mpic 2 1 - 02000 0 0 4 &mpic 3 1 - - /* IDSEL 0x5 (PCIX Slot 3) */ - 02800 0 0 1 &mpic 1 1 - 02800 0 0 2 &mpic 2 1 - 02800 0 0 3 &mpic 3 1 - 02800 0 0 4 &mpic 0 1 - - /* IDSEL 0x6 (PCIX Slot 4) */ - 03000 0 0 1 &mpic 2 1 - 03000 0 0 2 &mpic 3 1 - 03000 0 0 3 &mpic 0 1 - 03000 0 0 4 &mpic 1 1 - - /* IDSEL 0x8 (PCIX Slot 5) */ - 04000 0 0 1 &mpic 0 1 - 04000 0 0 2 &mpic 1 1 - 04000 0 0 3 &mpic 2 1 - 04000 0 0 4 &mpic 3 1 - - /* IDSEL 0xC (Tsi310 bridge) */ - 06000 0 0 1 &mpic 0 1 - 06000 0 0 2 &mpic 1 1 - 06000 0 0 3 &mpic 2 1 - 06000 0 0 4 &mpic 3 1 - - /* IDSEL 0x14 (Slot 2) */ - 0a000 0 0 1 &mpic 0 1 - 0a000 0 0 2 &mpic 1 1 - 0a000 0 0 3 &mpic 2 1 - 0a000 0 0 4 &mpic 3 1 - - /* IDSEL 0x15 (Slot 3) */ - 0a800 0 0 1 &mpic 1 1 - 0a800 0 0 2 &mpic 2 1 - 0a800 0 0 3 &mpic 3 1 - 0a800 0 0 4 &mpic 0 1 - - /* IDSEL 0x16 (Slot 4) */ - 0b000 0 0 1 &mpic 2 1 - 0b000 0 0 2 &mpic 3 1 - 0b000 0 0 3 &mpic 0 1 - 0b000 0 0 4 &mpic 1 1 - - /* IDSEL 0x18 (Slot 5) */ - 0c000 0 0 1 &mpic 0 1 - 0c000 0 0 2 &mpic 1 1 - 0c000 0 0 3 &mpic 2 1 - 0c000 0 0 4 &mpic 3 1 - - /* IDSEL 0x1C (Tsi310 bridge PCI primary) */ - 0E000 0 0 1 &mpic 0 1 - 0E000 0 0 2 &mpic 1 1 - 0E000 0 0 3 &mpic 2 1 - 0E000 0 0 4 &mpic 3 1>; - - interrupt-parent = <&mpic>; - interrupts = <18 2>; - bus-range = <0 0>; - ranges = <02000000 0 80000000 80000000 0 10000000 - 01000000 0 00000000 e2000000 0 00800000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8000 1000>; - compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci"; - device_type = "pci"; - - pci_bridge@1c { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x00 (PrPMC Site) */ - 0000 0 0 1 &mpic 0 1 - 0000 0 0 2 &mpic 1 1 - 0000 0 0 3 &mpic 2 1 - 0000 0 0 4 &mpic 3 1 - - /* IDSEL 0x04 (VIA chip) */ - 2000 0 0 1 &mpic 0 1 - 2000 0 0 2 &mpic 1 1 - 2000 0 0 3 &mpic 2 1 - 2000 0 0 4 &mpic 3 1 - - /* IDSEL 0x05 (8139) */ - 2800 0 0 1 &mpic 1 1 - - /* IDSEL 0x06 (Slot 6) */ - 3000 0 0 1 &mpic 2 1 - 3000 0 0 2 &mpic 3 1 - 3000 0 0 3 &mpic 0 1 - 3000 0 0 4 &mpic 1 1 - - /* IDESL 0x07 (Slot 7) */ - 3800 0 0 1 &mpic 3 1 - 3800 0 0 2 &mpic 0 1 - 3800 0 0 3 &mpic 1 1 - 3800 0 0 4 &mpic 2 1>; - - reg = ; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <02000000 0 80000000 - 02000000 0 80000000 - 0 20000000 - 01000000 0 00000000 - 01000000 0 00000000 - 0 00080000>; - clock-frequency = <1fca055>; - - isa@4 { - device_type = "isa"; - #interrupt-cells = <2>; - #size-cells = <1>; - #address-cells = <2>; - reg = <2000 0 0 0 0>; - ranges = <1 0 01000000 0 0 00001000>; - interrupt-parent = <&i8259>; - - i8259: interrupt-controller@20 { - interrupt-controller; - device_type = "interrupt-controller"; - reg = <1 20 2 - 1 a0 2 - 1 4d0 2>; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <0 1>; - interrupt-parent = <&mpic>; - }; - - rtc@70 { - compatible = "pnpPNP,b00"; - reg = <1 70 2>; - }; - }; - }; - }; - - pci@9000 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x15 */ - a800 0 0 1 &mpic b 1 - a800 0 0 2 &mpic 1 1 - a800 0 0 3 &mpic 2 1 - a800 0 0 4 &mpic 3 1>; - - interrupt-parent = <&mpic>; - interrupts = <19 2>; - bus-range = <0 0>; - ranges = <02000000 0 90000000 90000000 0 10000000 - 01000000 0 00000000 e2800000 0 00800000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <9000 1000>; - compatible = "fsl,mpc8540-pci"; - device_type = "pci"; - }; - /* PCI Express */ - pcie@a000 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x0 (PEX) */ - 00000 0 0 1 &mpic 0 1 - 00000 0 0 2 &mpic 1 1 - 00000 0 0 3 &mpic 2 1 - 00000 0 0 4 &mpic 3 1>; - - interrupt-parent = <&mpic>; - interrupts = <1a 2>; - bus-range = <0 ff>; - ranges = <02000000 0 a0000000 a0000000 0 20000000 - 01000000 0 00000000 e3000000 0 08000000>; - clock-frequency = <1fca055>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = ; - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - }; - mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; @@ -395,4 +192,214 @@ big-endian; }; }; + + pci@e0008000 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x4 (PCIX Slot 2) */ + 02000 0 0 1 &mpic 0 1 + 02000 0 0 2 &mpic 1 1 + 02000 0 0 3 &mpic 2 1 + 02000 0 0 4 &mpic 3 1 + + /* IDSEL 0x5 (PCIX Slot 3) */ + 02800 0 0 1 &mpic 1 1 + 02800 0 0 2 &mpic 2 1 + 02800 0 0 3 &mpic 3 1 + 02800 0 0 4 &mpic 0 1 + + /* IDSEL 0x6 (PCIX Slot 4) */ + 03000 0 0 1 &mpic 2 1 + 03000 0 0 2 &mpic 3 1 + 03000 0 0 3 &mpic 0 1 + 03000 0 0 4 &mpic 1 1 + + /* IDSEL 0x8 (PCIX Slot 5) */ + 04000 0 0 1 &mpic 0 1 + 04000 0 0 2 &mpic 1 1 + 04000 0 0 3 &mpic 2 1 + 04000 0 0 4 &mpic 3 1 + + /* IDSEL 0xC (Tsi310 bridge) */ + 06000 0 0 1 &mpic 0 1 + 06000 0 0 2 &mpic 1 1 + 06000 0 0 3 &mpic 2 1 + 06000 0 0 4 &mpic 3 1 + + /* IDSEL 0x14 (Slot 2) */ + 0a000 0 0 1 &mpic 0 1 + 0a000 0 0 2 &mpic 1 1 + 0a000 0 0 3 &mpic 2 1 + 0a000 0 0 4 &mpic 3 1 + + /* IDSEL 0x15 (Slot 3) */ + 0a800 0 0 1 &mpic 1 1 + 0a800 0 0 2 &mpic 2 1 + 0a800 0 0 3 &mpic 3 1 + 0a800 0 0 4 &mpic 0 1 + + /* IDSEL 0x16 (Slot 4) */ + 0b000 0 0 1 &mpic 2 1 + 0b000 0 0 2 &mpic 3 1 + 0b000 0 0 3 &mpic 0 1 + 0b000 0 0 4 &mpic 1 1 + + /* IDSEL 0x18 (Slot 5) */ + 0c000 0 0 1 &mpic 0 1 + 0c000 0 0 2 &mpic 1 1 + 0c000 0 0 3 &mpic 2 1 + 0c000 0 0 4 &mpic 3 1 + + /* IDSEL 0x1C (Tsi310 bridge PCI primary) */ + 0E000 0 0 1 &mpic 0 1 + 0E000 0 0 2 &mpic 1 1 + 0E000 0 0 3 &mpic 2 1 + 0E000 0 0 4 &mpic 3 1>; + + interrupt-parent = <&mpic>; + interrupts = <18 2>; + bus-range = <0 0>; + ranges = <02000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 e2000000 0 00800000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci"; + device_type = "pci"; + + pci_bridge@1c { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x00 (PrPMC Site) */ + 0000 0 0 1 &mpic 0 1 + 0000 0 0 2 &mpic 1 1 + 0000 0 0 3 &mpic 2 1 + 0000 0 0 4 &mpic 3 1 + + /* IDSEL 0x04 (VIA chip) */ + 2000 0 0 1 &mpic 0 1 + 2000 0 0 2 &mpic 1 1 + 2000 0 0 3 &mpic 2 1 + 2000 0 0 4 &mpic 3 1 + + /* IDSEL 0x05 (8139) */ + 2800 0 0 1 &mpic 1 1 + + /* IDSEL 0x06 (Slot 6) */ + 3000 0 0 1 &mpic 2 1 + 3000 0 0 2 &mpic 3 1 + 3000 0 0 3 &mpic 0 1 + 3000 0 0 4 &mpic 1 1 + + /* IDESL 0x07 (Slot 7) */ + 3800 0 0 1 &mpic 3 1 + 3800 0 0 2 &mpic 0 1 + 3800 0 0 3 &mpic 1 1 + 3800 0 0 4 &mpic 2 1>; + + reg = ; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + ranges = <02000000 0 80000000 + 02000000 0 80000000 + 0 20000000 + 01000000 0 00000000 + 01000000 0 00000000 + 0 00080000>; + clock-frequency = <1fca055>; + + isa@4 { + device_type = "isa"; + #interrupt-cells = <2>; + #size-cells = <1>; + #address-cells = <2>; + reg = <2000 0 0 0 0>; + ranges = <1 0 01000000 0 0 00001000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + interrupt-controller; + device_type = "interrupt-controller"; + reg = <1 20 2 + 1 a0 2 + 1 4d0 2>; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <0 1>; + interrupt-parent = <&mpic>; + }; + + rtc@70 { + compatible = "pnpPNP,b00"; + reg = <1 70 2>; + }; + }; + }; + }; + + pci@e0009000 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x15 */ + a800 0 0 1 &mpic b 1 + a800 0 0 2 &mpic 1 1 + a800 0 0 3 &mpic 2 1 + a800 0 0 4 &mpic 3 1>; + + interrupt-parent = <&mpic>; + interrupts = <19 2>; + bus-range = <0 0>; + ranges = <02000000 0 90000000 90000000 0 10000000 + 01000000 0 00000000 e2800000 0 00800000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + }; + + pcie@e000a000 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x0 (PEX) */ + 00000 0 0 1 &mpic 0 1 + 00000 0 0 2 &mpic 1 1 + 00000 0 0 3 &mpic 2 1 + 00000 0 0 4 &mpic 3 1>; + + interrupt-parent = <&mpic>; + interrupts = <1a 2>; + bus-range = <0 ff>; + ranges = <02000000 0 a0000000 a0000000 0 20000000 + 01000000 0 00000000 e3000000 0 08000000>; + clock-frequency = <1fca055>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 a0000000 + 02000000 0 a0000000 + 0 20000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 08000000>; + }; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index ce11d11293d0..99199295147e 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts @@ -43,7 +43,7 @@ #size-cells = <1>; device_type = "soc"; ranges = <0 e0000000 00100000>; - reg = ; // CCSRBAR 1M + reg = ; // CCSRBAR 1M bus-frequency = <0>; memory-controller@2000 { @@ -135,100 +135,6 @@ interrupt-parent = <&mpic>; }; - pci1: pci@8000 { - interrupt-map-mask = <1f800 0 0 7>; - interrupt-map = < - - /* IDSEL 0x10 */ - 08000 0 0 1 &mpic 0 1 - 08000 0 0 2 &mpic 1 1 - 08000 0 0 3 &mpic 2 1 - 08000 0 0 4 &mpic 3 1 - - /* IDSEL 0x11 */ - 08800 0 0 1 &mpic 0 1 - 08800 0 0 2 &mpic 1 1 - 08800 0 0 3 &mpic 2 1 - 08800 0 0 4 &mpic 3 1 - - /* IDSEL 0x12 (Slot 1) */ - 09000 0 0 1 &mpic 0 1 - 09000 0 0 2 &mpic 1 1 - 09000 0 0 3 &mpic 2 1 - 09000 0 0 4 &mpic 3 1 - - /* IDSEL 0x13 (Slot 2) */ - 09800 0 0 1 &mpic 1 1 - 09800 0 0 2 &mpic 2 1 - 09800 0 0 3 &mpic 3 1 - 09800 0 0 4 &mpic 0 1 - - /* IDSEL 0x14 (Slot 3) */ - 0a000 0 0 1 &mpic 2 1 - 0a000 0 0 2 &mpic 3 1 - 0a000 0 0 3 &mpic 0 1 - 0a000 0 0 4 &mpic 1 1 - - /* IDSEL 0x15 (Slot 4) */ - 0a800 0 0 1 &mpic 3 1 - 0a800 0 0 2 &mpic 0 1 - 0a800 0 0 3 &mpic 1 1 - 0a800 0 0 4 &mpic 2 1 - - /* Bus 1 (Tundra Bridge) */ - /* IDSEL 0x12 (ISA bridge) */ - 19000 0 0 1 &mpic 0 1 - 19000 0 0 2 &mpic 1 1 - 19000 0 0 3 &mpic 2 1 - 19000 0 0 4 &mpic 3 1>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - bus-range = <0 0>; - ranges = <02000000 0 80000000 80000000 0 20000000 - 01000000 0 00000000 e2000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8000 1000>; - compatible = "fsl,mpc8540-pci"; - device_type = "pci"; - - i8259@19000 { - interrupt-controller; - device_type = "interrupt-controller"; - reg = <19000 0 0 0 1>; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <1>; - interrupt-parent = <&pci1>; - }; - }; - - pci@9000 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x15 */ - a800 0 0 1 &mpic b 1 - a800 0 0 2 &mpic b 1 - a800 0 0 3 &mpic b 1 - a800 0 0 4 &mpic b 1>; - interrupt-parent = <&mpic>; - interrupts = <19 2>; - bus-range = <0 0>; - ranges = <02000000 0 a0000000 a0000000 0 20000000 - 01000000 0 00000000 e3000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <9000 1000>; - compatible = "fsl,mpc8540-pci"; - device_type = "pci"; - }; - mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; @@ -240,4 +146,98 @@ big-endian; }; }; + + pci1: pci@e0008000 { + interrupt-map-mask = <1f800 0 0 7>; + interrupt-map = < + + /* IDSEL 0x10 */ + 08000 0 0 1 &mpic 0 1 + 08000 0 0 2 &mpic 1 1 + 08000 0 0 3 &mpic 2 1 + 08000 0 0 4 &mpic 3 1 + + /* IDSEL 0x11 */ + 08800 0 0 1 &mpic 0 1 + 08800 0 0 2 &mpic 1 1 + 08800 0 0 3 &mpic 2 1 + 08800 0 0 4 &mpic 3 1 + + /* IDSEL 0x12 (Slot 1) */ + 09000 0 0 1 &mpic 0 1 + 09000 0 0 2 &mpic 1 1 + 09000 0 0 3 &mpic 2 1 + 09000 0 0 4 &mpic 3 1 + + /* IDSEL 0x13 (Slot 2) */ + 09800 0 0 1 &mpic 1 1 + 09800 0 0 2 &mpic 2 1 + 09800 0 0 3 &mpic 3 1 + 09800 0 0 4 &mpic 0 1 + + /* IDSEL 0x14 (Slot 3) */ + 0a000 0 0 1 &mpic 2 1 + 0a000 0 0 2 &mpic 3 1 + 0a000 0 0 3 &mpic 0 1 + 0a000 0 0 4 &mpic 1 1 + + /* IDSEL 0x15 (Slot 4) */ + 0a800 0 0 1 &mpic 3 1 + 0a800 0 0 2 &mpic 0 1 + 0a800 0 0 3 &mpic 1 1 + 0a800 0 0 4 &mpic 2 1 + + /* Bus 1 (Tundra Bridge) */ + /* IDSEL 0x12 (ISA bridge) */ + 19000 0 0 1 &mpic 0 1 + 19000 0 0 2 &mpic 1 1 + 19000 0 0 3 &mpic 2 1 + 19000 0 0 4 &mpic 3 1>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + bus-range = <0 0>; + ranges = <02000000 0 80000000 80000000 0 20000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + + i8259@19000 { + interrupt-controller; + device_type = "interrupt-controller"; + reg = <19000 0 0 0 1>; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <1>; + interrupt-parent = <&pci1>; + }; + }; + + pci@e0009000 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x15 */ + a800 0 0 1 &mpic b 1 + a800 0 0 2 &mpic b 1 + a800 0 0 3 &mpic b 1 + a800 0 0 4 &mpic b 1>; + interrupt-parent = <&mpic>; + interrupts = <19 2>; + bus-range = <0 0>; + ranges = <02000000 0 a0000000 a0000000 0 20000000 + 01000000 0 00000000 e3000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index cf87c30cf6a8..5577ec1f312b 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -130,96 +130,6 @@ phy-handle = <&phy1>; }; - pci@8000 { - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci"; - device_type = "pci"; - reg = <8000 1000>; - clock-frequency = <3f940aa>; - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x2 */ - 1000 0 0 1 &mpic 1 1 - 1000 0 0 2 &mpic 2 1 - 1000 0 0 3 &mpic 3 1 - 1000 0 0 4 &mpic 4 1 - - /* IDSEL 0x3 */ - 1800 0 0 1 &mpic 4 1 - 1800 0 0 2 &mpic 1 1 - 1800 0 0 3 &mpic 2 1 - 1800 0 0 4 &mpic 3 1 - - /* IDSEL 0x4 */ - 2000 0 0 1 &mpic 3 1 - 2000 0 0 2 &mpic 4 1 - 2000 0 0 3 &mpic 1 1 - 2000 0 0 4 &mpic 2 1 - - /* IDSEL 0x5 */ - 2800 0 0 1 &mpic 2 1 - 2800 0 0 2 &mpic 3 1 - 2800 0 0 3 &mpic 4 1 - 2800 0 0 4 &mpic 1 1 - - /* IDSEL 12 */ - 6000 0 0 1 &mpic 1 1 - 6000 0 0 2 &mpic 2 1 - 6000 0 0 3 &mpic 3 1 - 6000 0 0 4 &mpic 4 1 - - /* IDSEL 13 */ - 6800 0 0 1 &mpic 4 1 - 6800 0 0 2 &mpic 1 1 - 6800 0 0 3 &mpic 2 1 - 6800 0 0 4 &mpic 3 1 - - /* IDSEL 14*/ - 7000 0 0 1 &mpic 3 1 - 7000 0 0 2 &mpic 4 1 - 7000 0 0 3 &mpic 1 1 - 7000 0 0 4 &mpic 2 1 - - /* IDSEL 15 */ - 7800 0 0 1 &mpic 2 1 - 7800 0 0 2 &mpic 3 1 - 7800 0 0 3 &mpic 4 1 - 7800 0 0 4 &mpic 1 1 - - /* IDSEL 18 */ - 9000 0 0 1 &mpic 1 1 - 9000 0 0 2 &mpic 2 1 - 9000 0 0 3 &mpic 3 1 - 9000 0 0 4 &mpic 4 1 - - /* IDSEL 19 */ - 9800 0 0 1 &mpic 4 1 - 9800 0 0 2 &mpic 1 1 - 9800 0 0 3 &mpic 2 1 - 9800 0 0 4 &mpic 3 1 - - /* IDSEL 20 */ - a000 0 0 1 &mpic 3 1 - a000 0 0 2 &mpic 4 1 - a000 0 0 3 &mpic 1 1 - a000 0 0 4 &mpic 2 1 - - /* IDSEL 21 */ - a800 0 0 1 &mpic 2 1 - a800 0 0 2 &mpic 3 1 - a800 0 0 3 &mpic 4 1 - a800 0 0 4 &mpic 1 1>; - - interrupt-parent = <&mpic>; - interrupts = <18 2>; - bus-range = <0 0>; - ranges = <02000000 0 80000000 80000000 0 20000000 - 01000000 0 00000000 e2000000 0 01000000>; - }; - mpic: pic@40000 { interrupt-controller; #address-cells = <0>; @@ -319,4 +229,94 @@ }; }; }; + + pci@e0008000 { + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci"; + device_type = "pci"; + reg = ; + clock-frequency = <3f940aa>; + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x2 */ + 1000 0 0 1 &mpic 1 1 + 1000 0 0 2 &mpic 2 1 + 1000 0 0 3 &mpic 3 1 + 1000 0 0 4 &mpic 4 1 + + /* IDSEL 0x3 */ + 1800 0 0 1 &mpic 4 1 + 1800 0 0 2 &mpic 1 1 + 1800 0 0 3 &mpic 2 1 + 1800 0 0 4 &mpic 3 1 + + /* IDSEL 0x4 */ + 2000 0 0 1 &mpic 3 1 + 2000 0 0 2 &mpic 4 1 + 2000 0 0 3 &mpic 1 1 + 2000 0 0 4 &mpic 2 1 + + /* IDSEL 0x5 */ + 2800 0 0 1 &mpic 2 1 + 2800 0 0 2 &mpic 3 1 + 2800 0 0 3 &mpic 4 1 + 2800 0 0 4 &mpic 1 1 + + /* IDSEL 12 */ + 6000 0 0 1 &mpic 1 1 + 6000 0 0 2 &mpic 2 1 + 6000 0 0 3 &mpic 3 1 + 6000 0 0 4 &mpic 4 1 + + /* IDSEL 13 */ + 6800 0 0 1 &mpic 4 1 + 6800 0 0 2 &mpic 1 1 + 6800 0 0 3 &mpic 2 1 + 6800 0 0 4 &mpic 3 1 + + /* IDSEL 14*/ + 7000 0 0 1 &mpic 3 1 + 7000 0 0 2 &mpic 4 1 + 7000 0 0 3 &mpic 1 1 + 7000 0 0 4 &mpic 2 1 + + /* IDSEL 15 */ + 7800 0 0 1 &mpic 2 1 + 7800 0 0 2 &mpic 3 1 + 7800 0 0 3 &mpic 4 1 + 7800 0 0 4 &mpic 1 1 + + /* IDSEL 18 */ + 9000 0 0 1 &mpic 1 1 + 9000 0 0 2 &mpic 2 1 + 9000 0 0 3 &mpic 3 1 + 9000 0 0 4 &mpic 4 1 + + /* IDSEL 19 */ + 9800 0 0 1 &mpic 4 1 + 9800 0 0 2 &mpic 1 1 + 9800 0 0 3 &mpic 2 1 + 9800 0 0 4 &mpic 3 1 + + /* IDSEL 20 */ + a000 0 0 1 &mpic 3 1 + a000 0 0 2 &mpic 4 1 + a000 0 0 3 &mpic 1 1 + a000 0 0 4 &mpic 2 1 + + /* IDSEL 21 */ + a800 0 0 1 &mpic 2 1 + a800 0 0 2 &mpic 3 1 + a800 0 0 3 &mpic 4 1 + a800 0 0 4 &mpic 1 1>; + + interrupt-parent = <&mpic>; + interrupts = <18 2>; + bus-range = <0 0>; + ranges = <02000000 0 80000000 80000000 0 20000000 + 01000000 0 00000000 e2000000 0 01000000>; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts index 4d53d9bc3a9d..f797662212ba 100644 --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts @@ -53,11 +53,7 @@ #address-cells = <1>; #size-cells = <1>; device_type = "soc"; - ranges = <00001000 f8001000 000ff000 - 80000000 80000000 20000000 - e2000000 e2000000 00100000 - a0000000 a0000000 20000000 - e3000000 e3000000 00100000>; + ranges = <00000000 f8000000 00100000>; reg = ; // CCSRBAR bus-frequency = <0>; @@ -208,153 +204,6 @@ interrupt-parent = <&mpic>; }; - pcie@8000 { - compatible = "fsl,mpc8641-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8000 1000>; - bus-range = <0 ff>; - ranges = <02000000 0 80000000 80000000 0 20000000 - 01000000 0 00000000 e2000000 0 00100000>; - clock-frequency = <1fca055>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x11 */ - 8800 0 0 1 &i8259 9 2 - 8800 0 0 2 &i8259 a 2 - 8800 0 0 3 &i8259 b 2 - 8800 0 0 4 &i8259 c 2 - - /* IDSEL 0x12 */ - 9000 0 0 1 &i8259 a 2 - 9000 0 0 2 &i8259 b 2 - 9000 0 0 3 &i8259 c 2 - 9000 0 0 4 &i8259 9 2 - - // IDSEL 0x1c USB - e000 0 0 0 &i8259 c 2 - e100 0 0 0 &i8259 9 2 - e200 0 0 0 &i8259 a 2 - e300 0 0 0 &i8259 b 2 - - // IDSEL 0x1d Audio - e800 0 0 0 &i8259 6 2 - - // IDSEL 0x1e Legacy - f000 0 0 0 &i8259 7 2 - f100 0 0 0 &i8259 7 2 - - // IDSEL 0x1f IDE/SATA - f800 0 0 0 &i8259 e 2 - f900 0 0 0 &i8259 5 2 - >; - uli1575@0 { - reg = <0 0 0 0 0>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <02000000 0 80000000 - 02000000 0 80000000 - 0 20000000 - 01000000 0 00000000 - 01000000 0 00000000 - 0 00100000>; - - pci_bridge@0 { - reg = <0 0 0 0 0>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <02000000 0 80000000 - 02000000 0 80000000 - 0 20000000 - 01000000 0 00000000 - 01000000 0 00000000 - 0 00100000>; - - isa@1e { - device_type = "isa"; - #interrupt-cells = <2>; - #size-cells = <1>; - #address-cells = <2>; - reg = ; - ranges = <1 0 01000000 0 0 - 00001000>; - interrupt-parent = <&i8259>; - - i8259: interrupt-controller@20 { - reg = <1 20 2 - 1 a0 2 - 1 4d0 2>; - interrupt-controller; - device_type = "interrupt-controller"; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <9 2>; - interrupt-parent = - <&mpic>; - }; - - i8042@60 { - #size-cells = <0>; - #address-cells = <1>; - reg = <1 60 1 1 64 1>; - interrupts = <1 3 c 3>; - interrupt-parent = - <&i8259>; - - keyboard@0 { - reg = <0>; - compatible = "pnpPNP,303"; - }; - - mouse@1 { - reg = <1>; - compatible = "pnpPNP,f03"; - }; - }; - - rtc@70 { - compatible = - "pnpPNP,b00"; - reg = <1 70 2>; - }; - - gpio@400 { - reg = <1 400 80>; - }; - }; - }; - }; - - }; - - pcie@9000 { - compatible = "fsl,mpc8641-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <9000 1000>; - bus-range = <0 ff>; - ranges = <02000000 0 a0000000 a0000000 0 20000000 - 01000000 0 00000000 e3000000 0 00100000>; - clock-frequency = <1fca055>; - interrupt-parent = <&mpic>; - interrupts = <19 2>; - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x0 */ - 0000 0 0 1 &mpic 4 1 - 0000 0 0 2 &mpic 5 1 - 0000 0 0 3 &mpic 6 1 - 0000 0 0 4 &mpic 7 1 - >; - }; - mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; @@ -366,4 +215,164 @@ big-endian; }; }; + + pcie@f8008000 { + compatible = "fsl,mpc8641-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 ff>; + ranges = <02000000 0 80000000 80000000 0 20000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x11 */ + 8800 0 0 1 &i8259 9 2 + 8800 0 0 2 &i8259 a 2 + 8800 0 0 3 &i8259 b 2 + 8800 0 0 4 &i8259 c 2 + + /* IDSEL 0x12 */ + 9000 0 0 1 &i8259 a 2 + 9000 0 0 2 &i8259 b 2 + 9000 0 0 3 &i8259 c 2 + 9000 0 0 4 &i8259 9 2 + + // IDSEL 0x1c USB + e000 0 0 0 &i8259 c 2 + e100 0 0 0 &i8259 9 2 + e200 0 0 0 &i8259 a 2 + e300 0 0 0 &i8259 b 2 + + // IDSEL 0x1d Audio + e800 0 0 0 &i8259 6 2 + + // IDSEL 0x1e Legacy + f000 0 0 0 &i8259 7 2 + f100 0 0 0 &i8259 7 2 + + // IDSEL 0x1f IDE/SATA + f800 0 0 0 &i8259 e 2 + f900 0 0 0 &i8259 5 2 + >; + + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 80000000 + 02000000 0 80000000 + 0 20000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + uli1575@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + ranges = <02000000 0 80000000 + 02000000 0 80000000 + 0 20000000 + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + isa@1e { + device_type = "isa"; + #interrupt-cells = <2>; + #size-cells = <1>; + #address-cells = <2>; + reg = ; + ranges = <1 0 01000000 0 0 + 00001000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + reg = <1 20 2 + 1 a0 2 + 1 4d0 2>; + interrupt-controller; + device_type = "interrupt-controller"; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <9 2>; + interrupt-parent = <&mpic>; + }; + + i8042@60 { + #size-cells = <0>; + #address-cells = <1>; + reg = <1 60 1 1 64 1>; + interrupts = <1 3 c 3>; + interrupt-parent = + <&i8259>; + + keyboard@0 { + reg = <0>; + compatible = "pnpPNP,303"; + }; + + mouse@1 { + reg = <1>; + compatible = "pnpPNP,f03"; + }; + }; + + rtc@70 { + compatible = + "pnpPNP,b00"; + reg = <1 70 2>; + }; + + gpio@400 { + reg = <1 400 80>; + }; + }; + }; + }; + + }; + + pcie@f8009000 { + compatible = "fsl,mpc8641-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 ff>; + ranges = <02000000 0 a0000000 a0000000 0 20000000 + 01000000 0 00000000 e3000000 0 00100000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <19 2>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 4 1 + 0000 0 0 2 &mpic 5 1 + 0000 0 0 3 &mpic 6 1 + 0000 0 0 4 &mpic 7 1 + >; + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 a0000000 + 02000000 0 a0000000 + 0 20000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + }; + }; }; From d8f1324a5063c833862328ceafabc53ac3cc4f71 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 12 Sep 2007 22:14:10 -0500 Subject: [PATCH 0217/2804] [POWERPC] 83xx: Removed PCI exclude of PHB Now that the generic code doesn't assign resources for Freescale PHBs we dont have to explicitly exclude it. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/mpc8313_rdb.c | 2 -- arch/powerpc/platforms/83xx/mpc832x_mds.c | 1 - arch/powerpc/platforms/83xx/mpc832x_rdb.c | 2 -- arch/powerpc/platforms/83xx/mpc834x_itx.c | 2 -- arch/powerpc/platforms/83xx/mpc834x_mds.c | 2 -- arch/powerpc/platforms/83xx/mpc836x_mds.c | 1 - arch/powerpc/platforms/83xx/mpc83xx.h | 2 -- arch/powerpc/platforms/83xx/pci.c | 7 ------- 8 files changed, 19 deletions(-) diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c index 3edfe170a03b..140b46ffdb19 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c @@ -45,8 +45,6 @@ static void __init mpc8313_rdb_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc83xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif mpc831x_usb_cfg(); } diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 61e3f1cb0a7e..d494bc456458 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -75,7 +75,6 @@ static void __init mpc832x_sys_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc83xx_add_bridge(np); - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif #ifdef CONFIG_QUICC_ENGINE diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 090906170a41..e6c1760f36ef 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -49,8 +49,6 @@ static void __init mpc832x_rdb_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc83xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif #ifdef CONFIG_QUICC_ENGINE diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 6d06645e5ba8..870fd20461ce 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -54,8 +54,6 @@ static void __init mpc834x_itx_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc83xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif mpc834x_usb_cfg(); diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index f8aba9a488bc..a9140b64b98a 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -85,8 +85,6 @@ static void __init mpc834x_mds_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc83xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif mpc834xemds_usb_cfg(); diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 69970b910c12..db6957611585 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -81,7 +81,6 @@ static void __init mpc836x_mds_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc83xx_add_bridge(np); - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif #ifdef CONFIG_QUICC_ENGINE diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 589ee55730f3..b778cb4f3fb5 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -49,8 +49,6 @@ */ extern int mpc83xx_add_bridge(struct device_node *dev); -extern int mpc83xx_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn); extern void mpc83xx_restart(char *cmd); extern long mpc83xx_time_init(void); extern int mpc834x_usb_cfg(void); diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 92069469de20..80425d7b14f8 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -33,13 +33,6 @@ #define DBG(x...) #endif -int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) -{ - if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - return PCIBIOS_SUCCESSFUL; -} - int __init mpc83xx_add_bridge(struct device_node *dev) { int len; From 5e14d21e3f28a4181dacff0336040e30942f4921 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 13 Sep 2007 01:44:20 -0500 Subject: [PATCH 0218/2804] [POWERPC] Add cpu feature for SPE handling Make it so that SPE support can be determined at runtime. This is similiar to how we handle AltiVec. This allows us to have SPE support built in and work on processors with and without SPE. Signed-off-by: Kumar Gala --- arch/powerpc/kernel/cputable.c | 23 +++++++---------------- arch/powerpc/kernel/entry_32.S | 4 ++++ arch/powerpc/kernel/process.c | 15 +++++++++++---- arch/powerpc/kernel/ptrace.c | 6 ++---- include/asm-powerpc/cputable.h | 26 ++++++++++++++++++++++---- 5 files changed, 46 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 5873073c9045..8eb8087383eb 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -68,15 +68,6 @@ extern void __restore_cpu_ppc970(void); #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ PPC_FEATURE_BOOKE) -/* We only set the spe features if the kernel was compiled with - * spe support - */ -#ifdef CONFIG_SPE -#define PPC_FEATURE_SPE_COMP PPC_FEATURE_HAS_SPE -#else -#define PPC_FEATURE_SPE_COMP 0 -#endif - static struct cpu_spec cpu_specs[] = { #ifdef CONFIG_PPC64 { /* Power3 */ @@ -1261,8 +1252,8 @@ static struct cpu_spec cpu_specs[] = { /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ .cpu_features = CPU_FTRS_E200, .cpu_user_features = COMMON_USER_BOOKE | - PPC_FEATURE_SPE_COMP | - PPC_FEATURE_HAS_EFP_SINGLE | + PPC_FEATURE_HAS_SPE_COMP | + PPC_FEATURE_HAS_EFP_SINGLE_COMP | PPC_FEATURE_UNIFIED_CACHE, .dcache_bsize = 32, .platform = "ppc5554", @@ -1274,8 +1265,8 @@ static struct cpu_spec cpu_specs[] = { /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ .cpu_features = CPU_FTRS_E500, .cpu_user_features = COMMON_USER_BOOKE | - PPC_FEATURE_SPE_COMP | - PPC_FEATURE_HAS_EFP_SINGLE, + PPC_FEATURE_HAS_SPE_COMP | + PPC_FEATURE_HAS_EFP_SINGLE_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -1290,9 +1281,9 @@ static struct cpu_spec cpu_specs[] = { /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ .cpu_features = CPU_FTRS_E500_2, .cpu_user_features = COMMON_USER_BOOKE | - PPC_FEATURE_SPE_COMP | - PPC_FEATURE_HAS_EFP_SINGLE | - PPC_FEATURE_HAS_EFP_DOUBLE, + PPC_FEATURE_HAS_SPE_COMP | + PPC_FEATURE_HAS_EFP_SINGLE_COMP | + PPC_FEATURE_HAS_EFP_DOUBLE_COMP, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 4074c0b31453..21d889e63e87 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -504,9 +504,11 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE +BEGIN_FTR_SECTION oris r0,r0,MSR_SPE@h /* Disable SPE */ mfspr r12,SPRN_SPEFSCR /* save spefscr register value */ stw r12,THREAD+THREAD_SPEFSCR(r2) +END_FTR_SECTION_IFSET(CPU_FTR_SPE) #endif /* CONFIG_SPE */ and. r0,r0,r11 /* FP or altivec or SPE enabled? */ beq+ 1f @@ -542,8 +544,10 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE +BEGIN_FTR_SECTION lwz r0,THREAD+THREAD_SPEFSCR(r2) mtspr SPRN_SPEFSCR,r0 /* restore SPEFSCR reg */ +END_FTR_SECTION_IFSET(CPU_FTR_SPE) #endif /* CONFIG_SPE */ lwz r0,_CCR(r1) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e477c9d0498b..57c589c34147 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -669,9 +669,13 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val) * mode (asyn, precise, disabled) for 'Classic' FP. */ if (val & PR_FP_EXC_SW_ENABLE) { #ifdef CONFIG_SPE - tsk->thread.fpexc_mode = val & - (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT); - return 0; + if (cpu_has_feature(CPU_FTR_SPE)) { + tsk->thread.fpexc_mode = val & + (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT); + return 0; + } else { + return -EINVAL; + } #else return -EINVAL; #endif @@ -697,7 +701,10 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) #ifdef CONFIG_SPE - val = tsk->thread.fpexc_mode; + if (cpu_has_feature(CPU_FTR_SPE)) + val = tsk->thread.fpexc_mode; + else + return -EINVAL; #else return -EINVAL; #endif diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 8a177bd9eab4..fb8866e0e35d 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -576,8 +576,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef CONFIG_SPE case PTRACE_GETEVRREGS: /* Get the child spe register state. */ - if (child->thread.regs->msr & MSR_SPE) - giveup_spe(child); + flush_spe_to_thread(child); ret = get_evrregs((unsigned long __user *)data, child); break; @@ -585,8 +584,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* Set the child spe register state. */ /* this is to clear the MSR_SPE bit to force a reload * of register state from memory */ - if (child->thread.regs->msr & MSR_SPE) - giveup_spe(child); + flush_spe_to_thread(child); ret = set_evrregs(child, (unsigned long __user *)data); break; #endif diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 3dc8e2dfca84..f62cffd56c0c 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -136,6 +136,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, #define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000) #define CPU_FTR_FPU_UNAVAILABLE ASM_CONST(0x0000000000800000) #define CPU_FTR_UNIFIED_ID_CACHE ASM_CONST(0x0000000001000000) +#define CPU_FTR_SPE ASM_CONST(0x0000000002000000) /* * Add the 64-bit processor unique features in the top half of the word; @@ -180,6 +181,21 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, #define PPC_FEATURE_HAS_ALTIVEC_COMP 0 #endif +/* We only set the spe features if the kernel was compiled with spe + * support + */ +#ifdef CONFIG_SPE +#define CPU_FTR_SPE_COMP CPU_FTR_SPE +#define PPC_FEATURE_HAS_SPE_COMP PPC_FEATURE_HAS_SPE +#define PPC_FEATURE_HAS_EFP_SINGLE_COMP PPC_FEATURE_HAS_EFP_SINGLE +#define PPC_FEATURE_HAS_EFP_DOUBLE_COMP PPC_FEATURE_HAS_EFP_DOUBLE +#else +#define CPU_FTR_SPE_COMP 0 +#define PPC_FEATURE_HAS_SPE_COMP 0 +#define PPC_FEATURE_HAS_EFP_SINGLE_COMP 0 +#define PPC_FEATURE_HAS_EFP_DOUBLE_COMP 0 +#endif + /* We need to mark all pages as being coherent if we're SMP or we * have a 74[45]x and an MPC107 host bridge. Also 83xx requires * it for PCI "streaming/prefetch" to work properly. @@ -310,10 +326,12 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, #define CPU_FTRS_8XX (CPU_FTR_USE_TB) #define CPU_FTRS_40X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN) #define CPU_FTRS_44X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN) -#define CPU_FTRS_E200 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ - CPU_FTR_COHERENT_ICACHE | CPU_FTR_UNIFIED_ID_CACHE) -#define CPU_FTRS_E500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN) -#define CPU_FTRS_E500_2 (CPU_FTR_USE_TB | \ +#define CPU_FTRS_E200 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \ + CPU_FTR_NODSISRALIGN | CPU_FTR_COHERENT_ICACHE | \ + CPU_FTR_UNIFIED_ID_CACHE) +#define CPU_FTRS_E500 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \ + CPU_FTR_NODSISRALIGN) +#define CPU_FTRS_E500_2 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \ CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN) #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) From 748a768384e05c021ea6be221b80c62a83d7b520 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 13 Sep 2007 15:42:35 -0500 Subject: [PATCH 0219/2804] [POWERPC] Fix modpost warnings from head*.S on ppc32 We get warnings like the following from the various ppc32 head*.S files: WARNING: vmlinux.o(.text+0x358): Section mismatch: reference to .init.text:early_init (between 'skpinv' and 'interrupt_base') WARNING: vmlinux.o(.text+0x380): Section mismatch: reference to .init.text:machine_init (between 'skpinv' and 'interrupt_base') WARNING: vmlinux.o(.text+0x384): Section mismatch: reference to .init.text:MMU_init (between 'skpinv' and 'interrupt_base') WARNING: vmlinux.o(.text+0x3aa): Section mismatch: reference to .init.text:start_kernel (between 'skpinv' and 'interrupt_base') WARNING: vmlinux.o(.text+0x3ae): Section mismatch: reference to .init.text:start_kernel (between 'skpinv' and 'interrupt_base') Added a .text.head section simliar to what other architectures do since modpost already excludes this from its warnings. Signed-off-by: Kumar Gala --- arch/powerpc/kernel/head_32.S | 17 +++++++---------- arch/powerpc/kernel/head_40x.S | 12 ++++++------ arch/powerpc/kernel/head_44x.S | 6 +++--- arch/powerpc/kernel/head_8xx.S | 9 +++------ arch/powerpc/kernel/head_fsl_booke.S | 6 +++--- arch/powerpc/kernel/vmlinux.lds.S | 2 ++ include/asm-powerpc/ppc_asm.h | 4 ++++ 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 0e3df1f55feb..12febfe43de6 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -48,20 +48,17 @@ mtspr SPRN_DBAT##n##L,RB; \ 1: - .text + .section .text.head, "ax" .stabs "arch/powerpc/kernel/",N_SO,0,0,0f .stabs "head_32.S",N_SO,0,0,0f 0: - .globl _stext -_stext: +_ENTRY(_stext); /* * _start is defined this way because the XCOFF loader in the OpenFirmware * on the powermac expects the entry point to be a procedure descriptor. */ - .text - .globl _start -_start: +_ENTRY(_start); /* * These are here for legacy reasons, the kernel used to * need to look like a coff function entry for the pmac @@ -841,7 +838,7 @@ relocate_kernel: * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. */ -_GLOBAL(copy_and_flush) +_ENTRY(copy_and_flush) addi r5,r5,-4 addi r6,r6,-4 4: li r0,L1_CACHE_BYTES/4 @@ -954,9 +951,9 @@ __secondary_start: * included in CONFIG_6xx */ #if !defined(CONFIG_6xx) -_GLOBAL(__save_cpu_setup) +_ENTRY(__save_cpu_setup) blr -_GLOBAL(__restore_cpu_setup) +_ENTRY(__restore_cpu_setup) blr #endif /* !defined(CONFIG_6xx) */ @@ -1080,7 +1077,7 @@ start_here: /* * Set up the segment registers for a new context. */ -_GLOBAL(set_context) +_ENTRY(set_context) mulli r3,r3,897 /* multiply context by skew factor */ rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */ addis r3,r3,0x6000 /* Set Ks, Ku bits */ diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index a8e045773a92..00bdb6d1c724 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -52,9 +52,9 @@ * * This is all going to change RSN when we add bi_recs....... -- Dan */ - .text -_GLOBAL(_stext) -_GLOBAL(_start) + .section .text.head, "ax" +_ENTRY(_stext); +_ENTRY(_start); /* Save parameters we are passed. */ @@ -89,9 +89,9 @@ turn_on_mmu: */ . = 0xc0 crit_save: -_GLOBAL(crit_r10) +_ENTRY(crit_r10) .space 4 -_GLOBAL(crit_r11) +_ENTRY(crit_r11) .space 4 /* @@ -814,7 +814,7 @@ finish_tlb_load: * The PowerPC 4xx family of processors do not have an FPU, so this just * returns. */ -_GLOBAL(giveup_fpu) +_ENTRY(giveup_fpu) blr /* This is where the main kernel code starts. diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index e26d26e31813..a3dc0e4d0456 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -50,9 +50,9 @@ * r7 - End of kernel command line string * */ - .text -_GLOBAL(_stext) -_GLOBAL(_start) + .section .text.head, "ax" +_ENTRY(_stext); +_ENTRY(_start); /* * Reserve a word at a fixed location to store the address * of abatron_pteptrs diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 901be47a02a9..a6ecdd643167 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -38,12 +38,9 @@ #else #define DO_8xx_CPU6(val, reg) #endif - .text - .globl _stext -_stext: - .text - .globl _start -_start: + .section .text.head, "ax" +_ENTRY(_stext); +_ENTRY(_start); /* MPC8xx * This port was done on an MBX board with an 860. Right now I only diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 1f155d399d57..d83cbbb264e2 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -52,9 +52,9 @@ * r7 - End of kernel command line string * */ - .text -_GLOBAL(_stext) -_GLOBAL(_start) + .section .text.head, "ax" +_ENTRY(_stext); +_ENTRY(_start); /* * Reserve a word at a fixed location to store the address * of abatron_pteptrs diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 0c458556399f..823a8cbd60b5 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -34,6 +34,8 @@ SECTIONS /* Text and gots */ .text : { + ALIGN_FUNCTION(); + *(.text.head) _text = .; TEXT_TEXT SCHED_TEXT diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index 211fdaeeef84..2dbd4e7884fa 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -209,6 +209,10 @@ GLUE(.,name): #else /* 32-bit */ +#define _ENTRY(n) \ + .globl n; \ +n: + #define _GLOBAL(n) \ .text; \ .stabs __stringify(n:F-1),N_FUN,0,0,n;\ From 5a24e1a1773f284d19859d27f2ba7e50a533aaaf Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 28 Aug 2007 15:16:49 -0500 Subject: [PATCH 0220/2804] [PPC] Add clrbits8 and setbits8. These I/O accessors will be used in code under drivers/, which is expected to still work in arch/ppc. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- include/asm-ppc/io.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index 95d590423cf2..f776c49f5579 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -553,4 +553,7 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *); #define setbits16(_addr, _v) out_be16((_addr), in_be16(_addr) | (_v)) #define clrbits16(_addr, _v) out_be16((_addr), in_be16(_addr) & ~(_v)) +#define setbits8(_addr, _v) out_8((_addr), in_8(_addr) | (_v)) +#define clrbits8(_addr, _v) out_8((_addr), in_8(_addr) & ~(_v)) + #endif /* __KERNEL__ */ From 364f8ffc182ac5431b156ca1915dd81ddd4a592b Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 23 Aug 2007 15:35:53 +0400 Subject: [PATCH 0221/2804] [POWERPC] QE: extern par_io_config_pin and par_io_data_set funcs This is needed to configure and control QE pario pins from the kernel. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- include/asm-powerpc/qe.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h index 9d304b1f1608..ad23c580631c 100644 --- a/include/asm-powerpc/qe.h +++ b/include/asm-powerpc/qe.h @@ -32,6 +32,9 @@ extern void qe_reset(void); extern int par_io_init(struct device_node *np); extern int par_io_of_config(struct device_node *np); +extern int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, + int assignment, int has_irq); +extern int par_io_data_set(u8 port, u8 pin, u8 val); /* QE internal API */ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); From dc967d7f5e5d2c9d01c8ea172a1e231908dba9de Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 22 Aug 2007 20:07:28 -0500 Subject: [PATCH 0222/2804] [POWERPC] add clrsetbits macros This patch adds the clrsetbits_xxx() macros, which are used to set and clear multiple bits in a single read-modify-write operation. Specify the bits to clear in the 'clear' parameter and the bits to set in the 'set' parameter. These macros can also be used to set a multiple-bit bit pattern using a mask, by specifying the mask in the 'clear' parameter and the new bit pattern in the 'set' parameter. There are big-endian and little-endian versions for 8, 16, 32, and 64 bits. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala --- include/asm-powerpc/io.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h index 4c0b55087dc7..6805efb2cb6d 100644 --- a/include/asm-powerpc/io.h +++ b/include/asm-powerpc/io.h @@ -737,6 +737,29 @@ static inline void * bus_to_virt(unsigned long address) #define setbits8(_addr, _v) out_8((_addr), in_8(_addr) | (_v)) #define clrbits8(_addr, _v) out_8((_addr), in_8(_addr) & ~(_v)) +/* Clear and set bits in one shot. These macros can be used to clear and + * set multiple bits in a register using a single read-modify-write. These + * macros can also be used to set a multiple-bit bit pattern using a mask, + * by specifying the mask in the 'clear' parameter and the new bit pattern + * in the 'set' parameter. + */ + +#define clrsetbits(type, addr, clear, set) \ + out_##type((addr), (in_##type(addr) & ~(clear)) | (set)) + +#ifdef __powerpc64__ +#define clrsetbits_be64(addr, clear, set) clrsetbits(be64, addr, clear, set) +#define clrsetbits_le64(addr, clear, set) clrsetbits(le64, addr, clear, set) +#endif + +#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set) +#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set) + +#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set) +#define clrsetbits_le16(addr, clear, set) clrsetbits(le32, addr, clear, set) + +#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set) + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_IO_H */ From 82925e76db19112cad62066828c1db0bbb3f77e3 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 25 Jul 2007 12:30:33 -0500 Subject: [PATCH 0223/2804] [POWERPC] 86xx: Fix definition of global-utilites structure The current definition of struct ccsr_guts in immap_86xx.h was for 85xx. This patch fixes that and replaces the vague integer types with sized types of the correct endianness. The unused struct ccsr_pci is also deleted. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala --- include/asm-powerpc/immap_86xx.h | 151 ++++++++++--------------------- 1 file changed, 46 insertions(+), 105 deletions(-) diff --git a/include/asm-powerpc/immap_86xx.h b/include/asm-powerpc/immap_86xx.h index 59b9e07b8e99..c83d7ad16606 100644 --- a/include/asm-powerpc/immap_86xx.h +++ b/include/asm-powerpc/immap_86xx.h @@ -1,124 +1,65 @@ -/* +/** * MPC86xx Internal Memory Map * - * Author: Jeff Brown + * Authors: Jeff Brown + * Timur Tabi * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright 2004,2007 Freescale Semiconductor, 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. * + * This header file defines structures for various 86xx SOC devices that are + * used by multiple source files. */ #ifndef __ASM_POWERPC_IMMAP_86XX_H__ #define __ASM_POWERPC_IMMAP_86XX_H__ #ifdef __KERNEL__ -/* Eventually this should define all the IO block registers in 86xx */ - -/* PCI Registers */ -typedef struct ccsr_pci { - uint cfg_addr; /* 0x.000 - PCI Configuration Address Register */ - uint cfg_data; /* 0x.004 - PCI Configuration Data Register */ - uint int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */ - char res1[3060]; - uint potar0; /* 0x.c00 - PCI Outbound Transaction Address Register 0 */ - uint potear0; /* 0x.c04 - PCI Outbound Translation Extended Address Register 0 */ - uint powbar0; /* 0x.c08 - PCI Outbound Window Base Address Register 0 */ - char res2[4]; - uint powar0; /* 0x.c10 - PCI Outbound Window Attributes Register 0 */ - char res3[12]; - uint potar1; /* 0x.c20 - PCI Outbound Transaction Address Register 1 */ - uint potear1; /* 0x.c24 - PCI Outbound Translation Extended Address Register 1 */ - uint powbar1; /* 0x.c28 - PCI Outbound Window Base Address Register 1 */ - char res4[4]; - uint powar1; /* 0x.c30 - PCI Outbound Window Attributes Register 1 */ - char res5[12]; - uint potar2; /* 0x.c40 - PCI Outbound Transaction Address Register 2 */ - uint potear2; /* 0x.c44 - PCI Outbound Translation Extended Address Register 2 */ - uint powbar2; /* 0x.c48 - PCI Outbound Window Base Address Register 2 */ - char res6[4]; - uint powar2; /* 0x.c50 - PCI Outbound Window Attributes Register 2 */ - char res7[12]; - uint potar3; /* 0x.c60 - PCI Outbound Transaction Address Register 3 */ - uint potear3; /* 0x.c64 - PCI Outbound Translation Extended Address Register 3 */ - uint powbar3; /* 0x.c68 - PCI Outbound Window Base Address Register 3 */ - char res8[4]; - uint powar3; /* 0x.c70 - PCI Outbound Window Attributes Register 3 */ - char res9[12]; - uint potar4; /* 0x.c80 - PCI Outbound Transaction Address Register 4 */ - uint potear4; /* 0x.c84 - PCI Outbound Translation Extended Address Register 4 */ - uint powbar4; /* 0x.c88 - PCI Outbound Window Base Address Register 4 */ - char res10[4]; - uint powar4; /* 0x.c90 - PCI Outbound Window Attributes Register 4 */ - char res11[268]; - uint pitar3; /* 0x.da0 - PCI Inbound Translation Address Register 3 */ - char res12[4]; - uint piwbar3; /* 0x.da8 - PCI Inbound Window Base Address Register 3 */ - uint piwbear3; /* 0x.dac - PCI Inbound Window Base Extended Address Register 3 */ - uint piwar3; /* 0x.db0 - PCI Inbound Window Attributes Register 3 */ - char res13[12]; - uint pitar2; /* 0x.dc0 - PCI Inbound Translation Address Register 2 */ - char res14[4]; - uint piwbar2; /* 0x.dc8 - PCI Inbound Window Base Address Register 2 */ - uint piwbear2; /* 0x.dcc - PCI Inbound Window Base Extended Address Register 2 */ - uint piwar2; /* 0x.dd0 - PCI Inbound Window Attributes Register 2 */ - char res15[12]; - uint pitar1; /* 0x.de0 - PCI Inbound Translation Address Register 1 */ - char res16[4]; - uint piwbar1; /* 0x.de8 - PCI Inbound Window Base Address Register 1 */ - char res17[4]; - uint piwar1; /* 0x.df0 - PCI Inbound Window Attributes Register 1 */ - char res18[12]; - uint err_dr; /* 0x.e00 - PCI Error Detect Register */ - uint err_cap_dr; /* 0x.e04 - PCI Error Capture Disable Register */ - uint err_en; /* 0x.e08 - PCI Error Enable Register */ - uint err_attrib; /* 0x.e0c - PCI Error Attributes Capture Register */ - uint err_addr; /* 0x.e10 - PCI Error Address Capture Register */ - uint err_ext_addr; /* 0x.e14 - PCI Error Extended Address Capture Register */ - uint err_dl; /* 0x.e18 - PCI Error Data Low Capture Register */ - uint err_dh; /* 0x.e1c - PCI Error Data High Capture Register */ - uint gas_timr; /* 0x.e20 - PCI Gasket Timer Register */ - uint pci_timr; /* 0x.e24 - PCI Timer Register */ - char res19[472]; -} ccsr_pci_t; - /* Global Utility Registers */ -typedef struct ccsr_guts { - uint porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */ - uint porbmsr; /* 0x.0004 - POR Boot Mode Status Register */ - uint porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */ - uint pordevsr; /* 0x.000c - POR I/O Device Status Register */ - uint pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */ - char res1[12]; - uint gpporcr; /* 0x.0020 - General-Purpose POR Configuration Register */ - char res2[12]; - uint gpiocr; /* 0x.0030 - GPIO Control Register */ - char res3[12]; - uint gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */ - char res4[12]; - uint gpindr; /* 0x.0050 - General-Purpose Input Data Register */ - char res5[12]; - uint pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */ - char res6[12]; - uint devdisr; /* 0x.0070 - Device Disable Control */ - char res7[12]; - uint powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */ - char res8[12]; - uint mcpsumr; /* 0x.0090 - Machine Check Summary Register */ - char res9[12]; - uint pvr; /* 0x.00a0 - Processor Version Register */ - uint svr; /* 0x.00a4 - System Version Register */ - char res10[3416]; - uint clkocr; /* 0x.0e00 - Clock Out Select Register */ - char res11[12]; - uint ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */ - char res12[12]; - uint lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */ - char res13[61916]; -} ccsr_guts_t; +struct ccsr_guts { + __be32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */ + __be32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */ + __be32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */ + __be32 pordevsr; /* 0x.000c - POR I/O Device Status Register */ + __be32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */ + u8 res1[0x20 - 0x14]; + __be32 porcir; /* 0x.0020 - POR Configuration Information Register */ + u8 res2[0x30 - 0x24]; + __be32 gpiocr; /* 0x.0030 - GPIO Control Register */ + u8 res3[0x40 - 0x34]; + __be32 gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */ + u8 res4[0x50 - 0x44]; + __be32 gpindr; /* 0x.0050 - General-Purpose Input Data Register */ + u8 res5[0x60 - 0x54]; + __be32 pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */ + u8 res6[0x70 - 0x64]; + __be32 devdisr; /* 0x.0070 - Device Disable Control */ + u8 res7[0x80 - 0x74]; + __be32 powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */ + u8 res8[0x90 - 0x84]; + __be32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */ + __be32 rstrscr; /* 0x.0094 - Reset Request Status and Control Register */ + u8 res9[0xA0 - 0x98]; + __be32 pvr; /* 0x.00a0 - Processor Version Register */ + __be32 svr; /* 0x.00a4 - System Version Register */ + u8 res10[0xB0 - 0xA8]; + __be32 rstcr; /* 0x.00b0 - Reset Control Register */ + u8 res11[0xB20 - 0xB4]; + __be32 ddr1clkdr; /* 0x.0b20 - DDRC1 Clock Disable Register */ + __be32 ddr2clkdr; /* 0x.0b24 - DDRC2 Clock Disable Register */ + u8 res12[0xE00 - 0xB28]; + __be32 clkocr; /* 0x.0e00 - Clock Out Select Register */ + u8 res13[0xF04 - 0xE04]; + __be32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */ + __be32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */ + u8 res14[0xF40 - 0xF0C]; + __be32 srds2cr0; /* 0x.0f40 - SerDes1 Control Register 0 */ + __be32 srds2cr1; /* 0x.0f44 - SerDes1 Control Register 0 */ +}; #endif /* __ASM_POWERPC_IMMAP_86XX_H__ */ #endif /* __KERNEL__ */ From af6a9aabc106b70ab03d6665c713bca3dd3cb195 Mon Sep 17 00:00:00 2001 From: John Rigby Date: Wed, 23 May 2007 11:30:55 -0600 Subject: [PATCH 0224/2804] [POWERPC] 52xx: Fix mpc52xx_uart_of_assign to use correct index Use idx as index into mpc52xx_uart_nodes instead of i Signed-off-by: John Rigby Signed-off-by: Kumar Gala --- drivers/serial/mpc52xx_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 35f8b86cc78f..035cca028199 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -1051,7 +1051,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx) /* If the slot is already occupied, then swap slots */ if (mpc52xx_uart_nodes[idx] && (free_idx != -1)) mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx]; - mpc52xx_uart_nodes[i] = np; + mpc52xx_uart_nodes[idx] = np; } static void From 26f6cb999366a71b8e318bceaf8fafc1ffecae40 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 23 Aug 2007 15:35:56 +0400 Subject: [PATCH 0225/2804] [POWERPC] fsl_soc: add support for fsl_spi Add helper function to setup SPI bus/device information Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_soc.c | 87 +++++++++++++++++++++++++++++++++++ arch/powerpc/sysdev/fsl_soc.h | 7 +++ 2 files changed, 94 insertions(+) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 7012e51ae5c6..d028e8da027b 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1199,3 +1200,89 @@ err: arch_initcall(cpm_smc_uart_of_init); #endif /* CONFIG_8xx */ + +int __init fsl_spi_init(struct spi_board_info *board_infos, + unsigned int num_board_infos, + void (*activate_cs)(u8 cs, u8 polarity), + void (*deactivate_cs)(u8 cs, u8 polarity)) +{ + struct device_node *np; + unsigned int i; + const u32 *sysclk; + + np = of_find_node_by_type(NULL, "qe"); + if (!np) + return -ENODEV; + + sysclk = of_get_property(np, "bus-frequency", NULL); + if (!sysclk) + return -ENODEV; + + for (np = NULL, i = 1; + (np = of_find_compatible_node(np, "spi", "fsl_spi")) != NULL; + i++) { + int ret = 0; + unsigned int j; + const void *prop; + struct resource res[2]; + struct platform_device *pdev; + struct fsl_spi_platform_data pdata = { + .activate_cs = activate_cs, + .deactivate_cs = deactivate_cs, + }; + + memset(res, 0, sizeof(res)); + + pdata.sysclk = *sysclk; + + prop = of_get_property(np, "reg", NULL); + if (!prop) + goto err; + pdata.bus_num = *(u32 *)prop; + + prop = of_get_property(np, "mode", NULL); + if (prop && !strcmp(prop, "cpu-qe")) + pdata.qe_mode = 1; + + for (j = 0; j < num_board_infos; j++) { + if (board_infos[j].bus_num == pdata.bus_num) + pdata.max_chipselect++; + } + + if (!pdata.max_chipselect) + goto err; + + ret = of_address_to_resource(np, 0, &res[0]); + if (ret) + goto err; + + ret = of_irq_to_resource(np, 0, &res[1]); + if (ret == NO_IRQ) + goto err; + + pdev = platform_device_alloc("mpc83xx_spi", i); + if (!pdev) + goto err; + + ret = platform_device_add_data(pdev, &pdata, sizeof(pdata)); + if (ret) + goto unreg; + + ret = platform_device_add_resources(pdev, res, + ARRAY_SIZE(res)); + if (ret) + goto unreg; + + ret = platform_device_register(pdev); + if (ret) + goto unreg; + + continue; +unreg: + platform_device_del(pdev); +err: + continue; + } + + return spi_register_board_info(board_infos, num_board_infos); +} diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 04e145b5fc32..618d91d1e103 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -8,5 +8,12 @@ extern phys_addr_t get_immrbase(void); extern u32 get_brgfreq(void); extern u32 get_baudrate(void); +struct spi_board_info; + +extern int fsl_spi_init(struct spi_board_info *board_infos, + unsigned int num_board_infos, + void (*activate_cs)(u8 cs, u8 polarity), + void (*deactivate_cs)(u8 cs, u8 polarity)); + #endif #endif From 8237bf080e9ef6adc3f2adce26060722685bbb15 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 23 Aug 2007 15:36:00 +0400 Subject: [PATCH 0226/2804] [POWERPC] MPC832x_RDB: Update dts to use SPI1 in QE, register mmc_spi stub Enabled using SPI controller on the MPC832x RDB board. We currently use a modalias of "spidev" as a place holder (replace with "mmc_spie") until the mmc_spi driver support is merged in. This gets us the ability to test SPI until then. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc832x_rdb.dts | 2 +- arch/powerpc/platforms/83xx/mpc832x_rdb.c | 46 +++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts index cdc4a94e9c28..388c8a7012e1 100644 --- a/arch/powerpc/boot/dts/mpc832x_rdb.dts +++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts @@ -175,7 +175,7 @@ reg = <4c0 40>; interrupts = <2>; interrupt-parent = <&qeic>; - mode = "cpu"; + mode = "cpu-qe"; }; spi@500 { diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index e6c1760f36ef..24a790c79ec0 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include "mpc83xx.h" @@ -32,6 +34,50 @@ #define DBG(fmt...) #endif +static void mpc83xx_spi_activate_cs(u8 cs, u8 polarity) +{ + pr_debug("%s %d %d\n", __func__, cs, polarity); + par_io_data_set(3, 13, polarity); +} + +static void mpc83xx_spi_deactivate_cs(u8 cs, u8 polarity) +{ + pr_debug("%s %d %d\n", __func__, cs, polarity); + par_io_data_set(3, 13, !polarity); +} + +static struct spi_board_info mpc832x_spi_boardinfo = { + .bus_num = 0x4c0, + .chip_select = 0, + .max_speed_hz = 50000000, + /* + * XXX: This is spidev (spi in userspace) stub, should + * be replaced by "mmc_spi" when mmc_spi will hit mainline. + */ + .modalias = "spidev", +}; + +static int __init mpc832x_spi_init(void) +{ + if (!machine_is(mpc832x_rdb)) + return 0; + + par_io_config_pin(3, 0, 3, 0, 1, 0); /* SPI1 MOSI, I/O */ + par_io_config_pin(3, 1, 3, 0, 1, 0); /* SPI1 MISO, I/O */ + par_io_config_pin(3, 2, 3, 0, 1, 0); /* SPI1 CLK, I/O */ + par_io_config_pin(3, 3, 2, 0, 1, 0); /* SPI1 SEL, I */ + + par_io_config_pin(3, 13, 1, 0, 0, 0); /* !SD_CS, O */ + par_io_config_pin(3, 14, 2, 0, 0, 0); /* SD_INSERT, I */ + par_io_config_pin(3, 15, 2, 0, 0, 0); /* SD_PROTECT,I */ + + return fsl_spi_init(&mpc832x_spi_boardinfo, 1, + mpc83xx_spi_activate_cs, + mpc83xx_spi_deactivate_cs); +} + +device_initcall(mpc832x_spi_init); + /* ************************************************************************ * * Setup the architecture From e6b6e3ffb9ee8926f9f2f7dc9147df73e27d5828 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 27 Aug 2007 23:29:53 +0200 Subject: [PATCH 0227/2804] [POWERPC] Remove APUS support from arch/ppc Current status of APUS: - arch/powerpc/: removed in 2.6.23 - arch/ppc/: marked BROKEN since 2 years This therefore removes the remaining parts of APUS support from arch/ppc, include/asm-ppc, arch/powerpc and include/asm-powerpc. Signed-off-by: Adrian Bunk Signed-off-by: Paul Mackerras --- arch/ppc/Kconfig | 148 +---- arch/ppc/Makefile | 1 - arch/ppc/amiga/Makefile | 8 - arch/ppc/amiga/amiga_ksyms.c | 1 - arch/ppc/amiga/amiints.c | 322 ----------- arch/ppc/amiga/amisound.c | 1 - arch/ppc/amiga/bootinfo.c | 78 --- arch/ppc/amiga/chipram.c | 1 - arch/ppc/amiga/cia.c | 176 ------ arch/ppc/amiga/config.c | 953 -------------------------------- arch/ppc/amiga/ints.c | 158 ------ arch/ppc/amiga/pcmcia.c | 1 - arch/ppc/amiga/time.c | 57 -- arch/ppc/configs/apus_defconfig | 920 ------------------------------ arch/ppc/kernel/head.S | 117 +--- arch/ppc/kernel/ppc_ksyms.c | 3 - arch/ppc/kernel/setup.c | 1 - arch/ppc/mm/pgtable.c | 38 -- arch/ppc/platforms/Makefile | 4 - arch/ppc/platforms/apus_pci.c | 207 ------- arch/ppc/platforms/apus_pci.h | 34 -- arch/ppc/platforms/apus_setup.c | 798 -------------------------- include/asm-powerpc/ide.h | 2 +- include/asm-powerpc/reg.h | 4 - include/asm-ppc/amigahw.h | 16 - include/asm-ppc/amigaints.h | 133 ----- include/asm-ppc/amigappc.h | 85 --- include/asm-ppc/bootinfo.h | 5 - include/asm-ppc/io.h | 48 +- include/asm-ppc/machdep.h | 4 - include/asm-ppc/page.h | 44 +- include/asm-ppc/pgtable.h | 8 - 32 files changed, 12 insertions(+), 4364 deletions(-) delete mode 100644 arch/ppc/amiga/Makefile delete mode 100644 arch/ppc/amiga/amiga_ksyms.c delete mode 100644 arch/ppc/amiga/amiints.c delete mode 100644 arch/ppc/amiga/amisound.c delete mode 100644 arch/ppc/amiga/bootinfo.c delete mode 100644 arch/ppc/amiga/chipram.c delete mode 100644 arch/ppc/amiga/cia.c delete mode 100644 arch/ppc/amiga/config.c delete mode 100644 arch/ppc/amiga/ints.c delete mode 100644 arch/ppc/amiga/pcmcia.c delete mode 100644 arch/ppc/amiga/time.c delete mode 100644 arch/ppc/configs/apus_defconfig delete mode 100644 arch/ppc/platforms/apus_pci.c delete mode 100644 arch/ppc/platforms/apus_pci.h delete mode 100644 arch/ppc/platforms/apus_setup.c delete mode 100644 include/asm-ppc/amigahw.h delete mode 100644 include/asm-ppc/amigaints.h delete mode 100644 include/asm-ppc/amigappc.h diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 6bdeeb70b157..c1b34eb383cf 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -573,24 +573,9 @@ choice Select PReP if configuring for a PReP machine. - Select Gemini if configuring for a Synergy Microsystems' Gemini - series Single Board Computer. More information is available at: - . - - Select APUS if configuring for a PowerUP Amiga. More information is - available at: . - config PPC_PREP bool "PReP" -config APUS - bool "Amiga-APUS" - depends on BROKEN - help - Select APUS if configuring for a PowerUP Amiga. - More information is available at: - . - config KATANA bool "Artesyn-Katana" help @@ -1027,132 +1012,6 @@ config CMDLINE some command-line options at build time by entering them here. In most cases you will need to specify the root device here. -config AMIGA - bool - depends on APUS - default y - help - This option enables support for the Amiga series of computers. - -config ZORRO - bool - depends on APUS - default y - help - This enables support for the Zorro bus in the Amiga. If you have - expansion cards in your Amiga that conform to the Amiga - AutoConfig(tm) specification, say Y, otherwise N. Note that even - expansion cards that do not fit in the Zorro slots but fit in e.g. - the CPU slot may fall in this category, so you have to say Y to let - Linux use these. - -config ABSTRACT_CONSOLE - bool - depends on APUS - default y - -config APUS_FAST_EXCEPT - bool - depends on APUS - default y - -config AMIGA_PCMCIA - bool "Amiga 1200/600 PCMCIA support" - depends on APUS && EXPERIMENTAL - help - Include support in the kernel for pcmcia on Amiga 1200 and Amiga - 600. If you intend to use pcmcia cards say Y; otherwise say N. - -config AMIGA_BUILTIN_SERIAL - tristate "Amiga builtin serial support" - depends on APUS - help - If you want to use your Amiga's built-in serial port in Linux, - answer Y. - - To compile this driver as a module, choose M here. - -config GVPIOEXT - tristate "GVP IO-Extender support" - depends on APUS - help - If you want to use a GVP IO-Extender serial card in Linux, say Y. - Otherwise, say N. - -config GVPIOEXT_LP - tristate "GVP IO-Extender parallel printer support" - depends on GVPIOEXT - help - Say Y to enable driving a printer from the parallel port on your - GVP IO-Extender card, N otherwise. - -config GVPIOEXT_PLIP - tristate "GVP IO-Extender PLIP support" - depends on GVPIOEXT - help - Say Y to enable doing IP over the parallel port on your GVP - IO-Extender card, N otherwise. - -config MULTIFACE_III_TTY - tristate "Multiface Card III serial support" - depends on APUS - help - If you want to use a Multiface III card's serial port in Linux, - answer Y. - - To compile this driver as a module, choose M here. - -config A2232 - tristate "Commodore A2232 serial support (EXPERIMENTAL)" - depends on EXPERIMENTAL && APUS - ---help--- - This option supports the 2232 7-port serial card shipped with the - Amiga 2000 and other Zorro-bus machines, dating from 1989. At - a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip - each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The - ports were connected with 8 pin DIN connectors on the card bracket, - for which 8 pin to DB25 adapters were supplied. The card also had - jumpers internally to toggle various pinning configurations. - - This driver can be built as a module; but then "generic_serial" - will also be built as a module. This has to be loaded before - "ser_a2232". If you want to do this, answer M here. - -config WHIPPET_SERIAL - tristate "Hisoft Whippet PCMCIA serial support" - depends on AMIGA_PCMCIA - help - HiSoft has a web page at , but there - is no listing for the Whippet in their Amiga section. - -config APNE - tristate "PCMCIA NE2000 support" - depends on AMIGA_PCMCIA - help - If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise, - say N. - - To compile this driver as a module, choose M here: the - module will be called apne. - -config SERIAL_CONSOLE - bool "Support for serial port console" - depends on APUS && (AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y) - -config HEARTBEAT - bool "Use power LED as a heartbeat" - depends on APUS - help - Use the power-on LED on your machine as a load meter. The exact - behavior is platform-dependent, but normally the flash frequency is - a hyperbolic function of the 5-minute load average. - -config PROC_HARDWARE - bool "/proc/hardware support" - depends on APUS - -source "drivers/zorro/Kconfig" - if !44x || BROKEN source kernel/power/Kconfig endif @@ -1227,8 +1086,7 @@ config MCA config PCI bool "PCI support" if 40x || CPM2 || 83xx || 85xx || PPC_MPC52xx - default y if !40x && !CPM2 && !8xx && !APUS && !83xx && !85xx - default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS + default y if !40x && !CPM2 && !8xx && !83xx && !85xx default PCI_QSPAN if !4xx && !CPM2 && 8xx help Find out whether your system includes a PCI bus. PCI is the name of @@ -1284,10 +1142,6 @@ config 8260_PCI9_IDMA4 endchoice -config PCI_PERMEDIA - bool "PCI for Permedia2" - depends on !4xx && !8xx && APUS - source "drivers/pci/Kconfig" source "drivers/pcmcia/Kconfig" diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 0db66dcf0723..eee6264e8a04 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -69,7 +69,6 @@ core-$(CONFIG_83xx) += arch/ppc/platforms/83xx/ core-$(CONFIG_85xx) += arch/ppc/platforms/85xx/ core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/ core-$(CONFIG_XMON) += arch/ppc/xmon/ -core-$(CONFIG_APUS) += arch/ppc/amiga/ drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ drivers-$(CONFIG_CPM2) += arch/ppc/8260_io/ diff --git a/arch/ppc/amiga/Makefile b/arch/ppc/amiga/Makefile deleted file mode 100644 index 59fec0a3ac8e..000000000000 --- a/arch/ppc/amiga/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for Linux arch/m68k/amiga source directory -# - -obj-y := config.o amiints.o cia.o time.o bootinfo.o amisound.o \ - chipram.o amiga_ksyms.o - -obj-$(CONFIG_AMIGA_PCMCIA) += pcmcia.o diff --git a/arch/ppc/amiga/amiga_ksyms.c b/arch/ppc/amiga/amiga_ksyms.c deleted file mode 100644 index ec74e5b7a1ce..000000000000 --- a/arch/ppc/amiga/amiga_ksyms.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../m68k/amiga/amiga_ksyms.c" diff --git a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c deleted file mode 100644 index 265fcd3c6ab2..000000000000 --- a/arch/ppc/amiga/amiints.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Amiga Linux interrupt handling code - * - * 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. - * - * 11/07/96: rewritten interrupt handling, irq lists are exists now only for - * this sources where it makes sense (VERTB/PORTS/EXTER) and you must - * be careful that dev_id for this sources is unique since this the - * only possibility to distinguish between different handlers for - * free_irq. irq lists also have different irq flags: - * - IRQ_FLG_FAST: handler is inserted at top of list (after other - * fast handlers) - * - IRQ_FLG_SLOW: handler is inserted at bottom of list and before - * they're executed irq level is set to the previous - * one, but handlers don't need to be reentrant, if - * reentrance occurred, slow handlers will be just - * called again. - * The whole interrupt handling for CIAs is moved to cia.c - * /Roman Zippel - * - * 07/08/99: rewamp of the interrupt handling - we now have two types of - * interrupts, normal and fast handlers, fast handlers being - * marked with SA_INTERRUPT and runs with all other interrupts - * disabled. Normal interrupts disable their own source but - * run with all other interrupt sources enabled. - * PORTS and EXTER interrupts are always shared even if the - * drivers do not explicitly mark this when calling - * request_irq which they really should do. - * This is similar to the way interrupts are handled on all - * other architectures and makes a ton of sense besides - * having the advantage of making it easier to share - * drivers. - * /Jes - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_APUS -#include -#endif - -extern void cia_init_IRQ(struct ciabase *base); - -unsigned short ami_intena_vals[AMI_STD_IRQS] = { - IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT, - IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER -}; -static const unsigned char ami_servers[AMI_STD_IRQS] = { - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 -}; - -static short ami_ablecount[AMI_IRQS]; - -static void ami_badint(int irq, void *dev_id, struct pt_regs *fp) -{ -/* num_spurious += 1;*/ -} - -/* - * void amiga_init_IRQ(void) - * - * Parameters: None - * - * Returns: Nothing - * - * This function should be called during kernel startup to initialize - * the amiga IRQ handling routines. - */ - -__init -void amiga_init_IRQ(void) -{ - int i; - - for (i = 0; i < AMI_IRQS; i++) - ami_ablecount[i] = 0; - - /* turn off PCMCIA interrupts */ - if (AMIGAHW_PRESENT(PCMCIA)) - gayle.inten = GAYLE_IRQ_IDE; - - /* turn off all interrupts... */ - amiga_custom.intena = 0x7fff; - amiga_custom.intreq = 0x7fff; - -#ifdef CONFIG_APUS - /* Clear any inter-CPU interrupt requests. Circumvents bug in - Blizzard IPL emulation HW (or so it appears). */ - APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); - - /* Init IPL emulation. */ - APUS_WRITE(APUS_REG_INT, REGINT_INTMASTER | REGINT_ENABLEIPL); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK); -#endif - /* ... and enable the master interrupt bit */ - amiga_custom.intena = IF_SETCLR | IF_INTEN; - - cia_init_IRQ(&ciaa_base); - cia_init_IRQ(&ciab_base); -} - -/* - * Enable/disable a particular machine specific interrupt source. - * Note that this may affect other interrupts in case of a shared interrupt. - * This function should only be called for a _very_ short time to change some - * internal data, that may not be changed by the interrupt at the same time. - * ami_(enable|disable)_irq calls may also be nested. - */ - -void amiga_enable_irq(unsigned int irq) -{ - if (irq >= AMI_IRQS) { - printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); - return; - } - - ami_ablecount[irq]--; - if (ami_ablecount[irq]<0) - ami_ablecount[irq]=0; - else if (ami_ablecount[irq]) - return; - - /* No action for auto-vector interrupts */ - if (irq >= IRQ_AMIGA_AUTO){ - printk("%s: Trying to enable auto-vector IRQ %i\n", - __FUNCTION__, irq - IRQ_AMIGA_AUTO); - return; - } - - if (irq >= IRQ_AMIGA_CIAA) { - cia_set_irq(irq, 0); - cia_able_irq(irq, 1); - return; - } - - /* enable the interrupt */ - amiga_custom.intena = IF_SETCLR | ami_intena_vals[irq]; -} - -void amiga_disable_irq(unsigned int irq) -{ - if (irq >= AMI_IRQS) { - printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); - return; - } - - if (ami_ablecount[irq]++) - return; - - /* No action for auto-vector interrupts */ - if (irq >= IRQ_AMIGA_AUTO) { - printk("%s: Trying to disable auto-vector IRQ %i\n", - __FUNCTION__, irq - IRQ_AMIGA_AUTO); - return; - } - - if (irq >= IRQ_AMIGA_CIAA) { - cia_able_irq(irq, 0); - return; - } - - /* disable the interrupt */ - amiga_custom.intena = ami_intena_vals[irq]; -} - -inline void amiga_do_irq(int irq, struct pt_regs *fp) -{ - irq_desc_t *desc = irq_desc + irq; - struct irqaction *action = desc->action; - - kstat_cpu(0).irqs[irq]++; - action->handler(irq, action->dev_id, fp); -} - -void amiga_do_irq_list(int irq, struct pt_regs *fp) -{ - irq_desc_t *desc = irq_desc + irq; - struct irqaction *action; - - kstat_cpu(0).irqs[irq]++; - - amiga_custom.intreq = ami_intena_vals[irq]; - - for (action = desc->action; action; action = action->next) - action->handler(irq, action->dev_id, fp); -} - -/* - * The builtin Amiga hardware interrupt handlers. - */ - -static void ami_int1(int irq, void *dev_id, struct pt_regs *fp) -{ - unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; - - /* if serial transmit buffer empty, interrupt */ - if (ints & IF_TBE) { - amiga_custom.intreq = IF_TBE; - amiga_do_irq(IRQ_AMIGA_TBE, fp); - } - - /* if floppy disk transfer complete, interrupt */ - if (ints & IF_DSKBLK) { - amiga_custom.intreq = IF_DSKBLK; - amiga_do_irq(IRQ_AMIGA_DSKBLK, fp); - } - - /* if software interrupt set, interrupt */ - if (ints & IF_SOFT) { - amiga_custom.intreq = IF_SOFT; - amiga_do_irq(IRQ_AMIGA_SOFT, fp); - } -} - -static void ami_int3(int irq, void *dev_id, struct pt_regs *fp) -{ - unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; - - /* if a blitter interrupt */ - if (ints & IF_BLIT) { - amiga_custom.intreq = IF_BLIT; - amiga_do_irq(IRQ_AMIGA_BLIT, fp); - } - - /* if a copper interrupt */ - if (ints & IF_COPER) { - amiga_custom.intreq = IF_COPER; - amiga_do_irq(IRQ_AMIGA_COPPER, fp); - } - - /* if a vertical blank interrupt */ - if (ints & IF_VERTB) - amiga_do_irq_list(IRQ_AMIGA_VERTB, fp); -} - -static void ami_int4(int irq, void *dev_id, struct pt_regs *fp) -{ - unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; - - /* if audio 0 interrupt */ - if (ints & IF_AUD0) { - amiga_custom.intreq = IF_AUD0; - amiga_do_irq(IRQ_AMIGA_AUD0, fp); - } - - /* if audio 1 interrupt */ - if (ints & IF_AUD1) { - amiga_custom.intreq = IF_AUD1; - amiga_do_irq(IRQ_AMIGA_AUD1, fp); - } - - /* if audio 2 interrupt */ - if (ints & IF_AUD2) { - amiga_custom.intreq = IF_AUD2; - amiga_do_irq(IRQ_AMIGA_AUD2, fp); - } - - /* if audio 3 interrupt */ - if (ints & IF_AUD3) { - amiga_custom.intreq = IF_AUD3; - amiga_do_irq(IRQ_AMIGA_AUD3, fp); - } -} - -static void ami_int5(int irq, void *dev_id, struct pt_regs *fp) -{ - unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; - - /* if serial receive buffer full interrupt */ - if (ints & IF_RBF) { - /* acknowledge of IF_RBF must be done by the serial interrupt */ - amiga_do_irq(IRQ_AMIGA_RBF, fp); - } - - /* if a disk sync interrupt */ - if (ints & IF_DSKSYN) { - amiga_custom.intreq = IF_DSKSYN; - amiga_do_irq(IRQ_AMIGA_DSKSYN, fp); - } -} - -static void ami_int7(int irq, void *dev_id, struct pt_regs *fp) -{ - panic ("level 7 interrupt received\n"); -} - -#ifdef CONFIG_APUS -/* The PPC irq handling links all handlers requested on the same vector - and executes them in a loop. Having ami_badint at the end of the chain - is a bad idea. */ -struct irqaction amiga_sys_irqaction[AUTO_IRQS] = { - { .handler = ami_badint, .name = "spurious int" }, - { .handler = ami_int1, .name = "int1 handler" }, - { 0, /* CIAA */ }, - { .handler = ami_int3, .name = "int3 handler" }, - { .handler = ami_int4, .name = "int4 handler" }, - { .handler = ami_int5, .name = "int5 handler" }, - { 0, /* CIAB */ }, - { .handler = ami_int7, .name = "int7 handler" }, -}; -#else -void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { - ami_badint, ami_int1, ami_badint, ami_int3, - ami_int4, ami_int5, ami_badint, ami_int7 -}; -#endif diff --git a/arch/ppc/amiga/amisound.c b/arch/ppc/amiga/amisound.c deleted file mode 100644 index 2b86cbef79f6..000000000000 --- a/arch/ppc/amiga/amisound.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../m68k/amiga/amisound.c" diff --git a/arch/ppc/amiga/bootinfo.c b/arch/ppc/amiga/bootinfo.c deleted file mode 100644 index efd869a3ed9b..000000000000 --- a/arch/ppc/amiga/bootinfo.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Extracted from arch/m68k/kernel/setup.c. - * Should be properly generalized and put somewhere else. - * Jesper - */ - -#include -#include -#include -#include - -#include -#include - -extern char cmd_line[CL_SIZE]; - -extern int num_memory; -extern int m68k_realnum_memory; -extern struct mem_info memory[NUM_MEMINFO]; -extern struct mem_info m68k_memory[NUM_MEMINFO]; -extern struct mem_info ramdisk; - -extern int amiga_parse_bootinfo(const struct bi_record *); -extern int atari_parse_bootinfo(const struct bi_record *); -extern int mac_parse_bootinfo(const struct bi_record *); - -void __init parse_bootinfo(const struct bi_record *record) -{ - while (record->tag != BI_LAST) { - int unknown = 0; - const u_long *data = record->data; - switch (record->tag) { - case BI_MACHTYPE: - case BI_CPUTYPE: - case BI_FPUTYPE: - case BI_MMUTYPE: - /* Already set up by head.S */ - break; - - case BI_MEMCHUNK: - if (num_memory < NUM_MEMINFO) { - memory[num_memory].addr = data[0]; - memory[num_memory].size = data[1]; - num_memory++; - - /* FIXME: duplicate for m68k drivers. */ - m68k_memory[m68k_realnum_memory].addr = data[0]; - m68k_memory[m68k_realnum_memory].size = data[1]; - m68k_realnum_memory++; - } else - printk("parse_bootinfo: too many memory chunks\n"); - break; - - case BI_RAMDISK: - ramdisk.addr = data[0]; - ramdisk.size = data[1]; - break; - - case BI_COMMAND_LINE: - strlcpy(cmd_line, (const char *)data, sizeof(cmd_line)); - break; - - default: - if (MACH_IS_AMIGA) - unknown = amiga_parse_bootinfo(record); - else if (MACH_IS_ATARI) - unknown = atari_parse_bootinfo(record); - else if (MACH_IS_MAC) - unknown = mac_parse_bootinfo(record); - else - unknown = 1; - } - if (unknown) - printk("parse_bootinfo: unknown tag 0x%04x ignored\n", - record->tag); - record = (struct bi_record *)((u_long)record+record->size); - } -} diff --git a/arch/ppc/amiga/chipram.c b/arch/ppc/amiga/chipram.c deleted file mode 100644 index e6ab3c6b223c..000000000000 --- a/arch/ppc/amiga/chipram.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../m68k/amiga/chipram.c" diff --git a/arch/ppc/amiga/cia.c b/arch/ppc/amiga/cia.c deleted file mode 100644 index 9558f2f40e64..000000000000 --- a/arch/ppc/amiga/cia.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 1996 Roman Zippel - * - * The concept of some functions bases on the original Amiga OS function - * - * 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 - -struct ciabase { - volatile struct CIA *cia; - u_char icr_mask, icr_data; - u_short int_mask; - int handler_irq, cia_irq, server_irq; - char *name; -} ciaa_base = { - &ciaa, 0, 0, IF_PORTS, - IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA, - IRQ_AMIGA_PORTS, - "CIAA handler" -}, ciab_base = { - &ciab, 0, 0, IF_EXTER, - IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB, - IRQ_AMIGA_EXTER, - "CIAB handler" -}; - -#define CIA_SET_BASE_ADJUST_IRQ(base, irq) \ -do { \ - if (irq >= IRQ_AMIGA_CIAB) { \ - base = &ciab_base; \ - irq -= IRQ_AMIGA_CIAB; \ - } else { \ - base = &ciaa_base; \ - irq -= IRQ_AMIGA_CIAA; \ - } \ -} while (0) - -/* - * Cause or clear CIA interrupts, return old interrupt status. - */ - -static unsigned char cia_set_irq_private(struct ciabase *base, - unsigned char mask) -{ - u_char old; - - old = (base->icr_data |= base->cia->icr); - if (mask & CIA_ICR_SETCLR) - base->icr_data |= mask; - else - base->icr_data &= ~mask; - if (base->icr_data & base->icr_mask) - amiga_custom.intreq = IF_SETCLR | base->int_mask; - return old & base->icr_mask; -} - -unsigned char cia_set_irq(unsigned int irq, int set) -{ - struct ciabase *base; - unsigned char mask; - - if (irq >= IRQ_AMIGA_CIAB) - mask = (1 << (irq - IRQ_AMIGA_CIAB)); - else - mask = (1 << (irq - IRQ_AMIGA_CIAA)); - mask |= (set) ? CIA_ICR_SETCLR : 0; - - CIA_SET_BASE_ADJUST_IRQ(base, irq); - - return cia_set_irq_private(base, mask); -} - -unsigned char cia_get_irq_mask(unsigned int irq) -{ - struct ciabase *base; - - CIA_SET_BASE_ADJUST_IRQ(base, irq); - - return base->cia->icr; -} - -/* - * Enable or disable CIA interrupts, return old interrupt mask. - */ - -static unsigned char cia_able_irq_private(struct ciabase *base, - unsigned char mask) -{ - u_char old; - - old = base->icr_mask; - base->icr_data |= base->cia->icr; - base->cia->icr = mask; - if (mask & CIA_ICR_SETCLR) - base->icr_mask |= mask; - else - base->icr_mask &= ~mask; - base->icr_mask &= CIA_ICR_ALL; - - if (base->icr_data & base->icr_mask) - amiga_custom.intreq = IF_SETCLR | base->int_mask; - return old; -} - -unsigned char cia_able_irq(unsigned int irq, int enable) -{ - struct ciabase *base; - unsigned char mask; - - if (irq >= IRQ_AMIGA_CIAB) - mask = (1 << (irq - IRQ_AMIGA_CIAB)); - else - mask = (1 << (irq - IRQ_AMIGA_CIAA)); - mask |= (enable) ? CIA_ICR_SETCLR : 0; - - CIA_SET_BASE_ADJUST_IRQ(base, irq); - - return cia_able_irq_private(base, mask); -} - -static void cia_handler(int irq, void *dev_id, struct pt_regs *fp) -{ - struct ciabase *base = (struct ciabase *)dev_id; - irq_desc_t *desc; - struct irqaction *action; - int i; - unsigned char ints; - - irq = base->cia_irq; - desc = irq_desc + irq; - ints = cia_set_irq_private(base, CIA_ICR_ALL); - amiga_custom.intreq = base->int_mask; - for (i = 0; i < CIA_IRQS; i++, irq++) { - if (ints & 1) { - kstat_cpu(0).irqs[irq]++; - action = desc->action; - action->handler(irq, action->dev_id, fp); - } - ints >>= 1; - desc++; - } - amiga_do_irq_list(base->server_irq, fp); -} - -void __init cia_init_IRQ(struct ciabase *base) -{ - extern struct irqaction amiga_sys_irqaction[AUTO_IRQS]; - struct irqaction *action; - - /* clear any pending interrupt and turn off all interrupts */ - cia_set_irq_private(base, CIA_ICR_ALL); - cia_able_irq_private(base, CIA_ICR_ALL); - - /* install CIA handler */ - action = &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO]; - action->handler = cia_handler; - action->dev_id = base; - action->name = base->name; - setup_irq(base->handler_irq, &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO]); - - amiga_custom.intena = IF_SETCLR | base->int_mask; -} diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c deleted file mode 100644 index bc50ed11957d..000000000000 --- a/arch/ppc/amiga/config.c +++ /dev/null @@ -1,953 +0,0 @@ -#define m68k_debug_device debug_device - -/* - * Copyright (C) 1993 Hamish Macdonald - * - * 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. - */ - -/* - * Miscellaneous Amiga stuff - */ - -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_ZORRO -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -unsigned long powerup_PCI_present; -unsigned long powerup_BPPCPLUS_present; -unsigned long amiga_model; -unsigned long amiga_eclock; -unsigned long amiga_masterclock; -unsigned long amiga_colorclock; -unsigned long amiga_chipset; -unsigned char amiga_vblank; -unsigned char amiga_psfreq; -struct amiga_hw_present amiga_hw_present; - -static char s_a500[] __initdata = "A500"; -static char s_a500p[] __initdata = "A500+"; -static char s_a600[] __initdata = "A600"; -static char s_a1000[] __initdata = "A1000"; -static char s_a1200[] __initdata = "A1200"; -static char s_a2000[] __initdata = "A2000"; -static char s_a2500[] __initdata = "A2500"; -static char s_a3000[] __initdata = "A3000"; -static char s_a3000t[] __initdata = "A3000T"; -static char s_a3000p[] __initdata = "A3000+"; -static char s_a4000[] __initdata = "A4000"; -static char s_a4000t[] __initdata = "A4000T"; -static char s_cdtv[] __initdata = "CDTV"; -static char s_cd32[] __initdata = "CD32"; -static char s_draco[] __initdata = "Draco"; -static char *amiga_models[] __initdata = { - s_a500, s_a500p, s_a600, s_a1000, s_a1200, s_a2000, s_a2500, s_a3000, - s_a3000t, s_a3000p, s_a4000, s_a4000t, s_cdtv, s_cd32, s_draco, -}; - -static char amiga_model_name[13] = "Amiga "; - -extern char m68k_debug_device[]; - -static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); -/* amiga specific irq functions */ -extern void amiga_init_IRQ (void); -extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); -extern int amiga_request_irq (unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, - void *dev_id); -extern void amiga_free_irq (unsigned int irq, void *dev_id); -extern void amiga_enable_irq (unsigned int); -extern void amiga_disable_irq (unsigned int); -static void amiga_get_model(char *model); -static int amiga_get_hardware_list(char *buffer); -/* amiga specific timer functions */ -static unsigned long amiga_gettimeoffset (void); -static void a3000_gettod (int *, int *, int *, int *, int *, int *); -static void a2000_gettod (int *, int *, int *, int *, int *, int *); -static int amiga_hwclk (int, struct hwclk_time *); -static int amiga_set_clock_mmss (unsigned long); -static void amiga_reset (void); -extern void amiga_init_sound(void); -static void amiga_savekmsg_init(void); -static void amiga_mem_console_write(struct console *co, const char *b, - unsigned int count); -void amiga_serial_console_write(struct console *co, const char *s, - unsigned int count); -static void amiga_debug_init(void); -#ifdef CONFIG_HEARTBEAT -static void amiga_heartbeat(int on); -#endif - -static struct console amiga_console_driver = { - .name = "debug", - .flags = CON_PRINTBUFFER, - .index = -1, -}; - - - /* - * Motherboard Resources present in all Amiga models - */ - -static struct { - struct resource _ciab, _ciaa, _custom, _kickstart; -} mb_resources = { -// { "Ranger Memory", 0x00c00000, 0x00c7ffff }, - ._ciab = { "CIA B", 0x00bfd000, 0x00bfdfff }, - ._ciaa = { "CIA A", 0x00bfe000, 0x00bfefff }, - ._custom = { "Custom I/O", 0x00dff000, 0x00dfffff }, - ._kickstart = { "Kickstart ROM", 0x00f80000, 0x00ffffff } -}; - -static struct resource rtc_resource = { - NULL, 0x00dc0000, 0x00dcffff -}; - -static struct resource ram_resource[NUM_MEMINFO]; - - - /* - * Parse an Amiga-specific record in the bootinfo - */ - -int amiga_parse_bootinfo(const struct bi_record *record) -{ - int unknown = 0; - const unsigned long *data = record->data; - - switch (record->tag) { - case BI_AMIGA_MODEL: - { - unsigned long d = *data; - - powerup_PCI_present = d & 0x100; - amiga_model = d & 0xff; - } - break; - - case BI_AMIGA_ECLOCK: - amiga_eclock = *data; - break; - - case BI_AMIGA_CHIPSET: - amiga_chipset = *data; - break; - - case BI_AMIGA_CHIP_SIZE: - amiga_chip_size = *(const int *)data; - break; - - case BI_AMIGA_VBLANK: - amiga_vblank = *(const unsigned char *)data; - break; - - case BI_AMIGA_PSFREQ: - amiga_psfreq = *(const unsigned char *)data; - break; - - case BI_AMIGA_AUTOCON: -#ifdef CONFIG_ZORRO - if (zorro_num_autocon < ZORRO_NUM_AUTO) { - const struct ConfigDev *cd = (struct ConfigDev *)data; - struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; - dev->rom = cd->cd_Rom; - dev->slotaddr = cd->cd_SlotAddr; - dev->slotsize = cd->cd_SlotSize; - dev->resource.start = (unsigned long)cd->cd_BoardAddr; - dev->resource.end = dev->resource.start+cd->cd_BoardSize-1; - } else - printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); -#endif /* CONFIG_ZORRO */ - break; - - case BI_AMIGA_SERPER: - /* serial port period: ignored here */ - break; - - case BI_AMIGA_PUP_BRIDGE: - powerup_PCI_present = *(const unsigned short *)data; - break; - - case BI_AMIGA_BPPC_SCSI: - powerup_BPPCPLUS_present = *(const unsigned short *)data; - break; - - default: - unknown = 1; - } - return(unknown); -} - - /* - * Identify builtin hardware - */ - -static void __init amiga_identify(void) -{ - /* Fill in some default values, if necessary */ - if (amiga_eclock == 0) - amiga_eclock = 709379; - - memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); - - printk("Amiga hardware found: "); - if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { - printk("[%s] ", amiga_models[amiga_model-AMI_500]); - strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); - } - - switch(amiga_model) { - case AMI_UNKNOWN: - goto Generic; - - case AMI_600: - case AMI_1200: - AMIGAHW_SET(A1200_IDE); - AMIGAHW_SET(PCMCIA); - case AMI_500: - case AMI_500PLUS: - case AMI_1000: - case AMI_2000: - case AMI_2500: - AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ - goto Generic; - - case AMI_3000: - case AMI_3000T: - AMIGAHW_SET(AMBER_FF); - AMIGAHW_SET(MAGIC_REKICK); - /* fall through */ - case AMI_3000PLUS: - AMIGAHW_SET(A3000_SCSI); - AMIGAHW_SET(A3000_CLK); - AMIGAHW_SET(ZORRO3); - goto Generic; - - case AMI_4000T: - AMIGAHW_SET(A4000_SCSI); - /* fall through */ - case AMI_4000: - AMIGAHW_SET(A4000_IDE); - AMIGAHW_SET(A3000_CLK); - AMIGAHW_SET(ZORRO3); - goto Generic; - - case AMI_CDTV: - case AMI_CD32: - AMIGAHW_SET(CD_ROM); - AMIGAHW_SET(A2000_CLK); /* Is this correct? */ - goto Generic; - - Generic: - AMIGAHW_SET(AMI_VIDEO); - AMIGAHW_SET(AMI_BLITTER); - AMIGAHW_SET(AMI_AUDIO); - AMIGAHW_SET(AMI_FLOPPY); - AMIGAHW_SET(AMI_KEYBOARD); - AMIGAHW_SET(AMI_MOUSE); - AMIGAHW_SET(AMI_SERIAL); - AMIGAHW_SET(AMI_PARALLEL); - AMIGAHW_SET(CHIP_RAM); - AMIGAHW_SET(PAULA); - - switch(amiga_chipset) { - case CS_OCS: - case CS_ECS: - case CS_AGA: - switch (amiga_custom.deniseid & 0xf) { - case 0x0c: - AMIGAHW_SET(DENISE_HR); - break; - case 0x08: - AMIGAHW_SET(LISA); - break; - } - break; - default: - AMIGAHW_SET(DENISE); - break; - } - switch ((amiga_custom.vposr>>8) & 0x7f) { - case 0x00: - AMIGAHW_SET(AGNUS_PAL); - break; - case 0x10: - AMIGAHW_SET(AGNUS_NTSC); - break; - case 0x20: - case 0x21: - AMIGAHW_SET(AGNUS_HR_PAL); - break; - case 0x30: - case 0x31: - AMIGAHW_SET(AGNUS_HR_NTSC); - break; - case 0x22: - case 0x23: - AMIGAHW_SET(ALICE_PAL); - break; - case 0x32: - case 0x33: - AMIGAHW_SET(ALICE_NTSC); - break; - } - AMIGAHW_SET(ZORRO); - break; - - case AMI_DRACO: - panic("No support for Draco yet"); - - default: - panic("Unknown Amiga Model"); - } - -#define AMIGAHW_ANNOUNCE(name, str) \ - if (AMIGAHW_PRESENT(name)) \ - printk(str) - - AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); - AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); - AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); - AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); - AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); - AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); - AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); - AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); - AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); - AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); - AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); - AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); - AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); - AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); - AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); - AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); - AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); - AMIGAHW_ANNOUNCE(PAULA, "PAULA "); - AMIGAHW_ANNOUNCE(DENISE, "DENISE "); - AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); - AMIGAHW_ANNOUNCE(LISA, "LISA "); - AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); - AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); - AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); - AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); - AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); - AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); - AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); - AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); - if (AMIGAHW_PRESENT(ZORRO)) - printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); - printk("\n"); - -#undef AMIGAHW_ANNOUNCE -} - - /* - * Setup the Amiga configuration info - */ - -void __init config_amiga(void) -{ - int i; - - amiga_debug_init(); - amiga_identify(); - - /* Some APUS boxes may have PCI memory, but ... */ - iomem_resource.name = "Memory"; - for (i = 0; i < 4; i++) - request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); - - mach_sched_init = amiga_sched_init; - mach_init_IRQ = amiga_init_IRQ; -#ifndef CONFIG_APUS - mach_default_handler = &amiga_default_handler; - mach_request_irq = amiga_request_irq; - mach_free_irq = amiga_free_irq; - enable_irq = amiga_enable_irq; - disable_irq = amiga_disable_irq; -#endif - mach_get_model = amiga_get_model; - mach_get_hardware_list = amiga_get_hardware_list; - mach_gettimeoffset = amiga_gettimeoffset; - if (AMIGAHW_PRESENT(A3000_CLK)){ - mach_gettod = a3000_gettod; - rtc_resource.name = "A3000 RTC"; - request_resource(&iomem_resource, &rtc_resource); - } - else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */ - mach_gettod = a2000_gettod; - rtc_resource.name = "A2000 RTC"; - request_resource(&iomem_resource, &rtc_resource); - } - - mach_max_dma_address = 0xffffffff; /* - * default MAX_DMA=0xffffffff - * on all machines. If we don't - * do so, the SCSI code will not - * be able to allocate any mem - * for transfers, unless we are - * dealing with a Z2 mem only - * system. /Jes - */ - - mach_hwclk = amiga_hwclk; - mach_set_clock_mmss = amiga_set_clock_mmss; - mach_reset = amiga_reset; -#ifdef CONFIG_HEARTBEAT - mach_heartbeat = amiga_heartbeat; -#endif - - /* Fill in the clock values (based on the 700 kHz E-Clock) */ - amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ - amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ - - /* clear all DMA bits */ - amiga_custom.dmacon = DMAF_ALL; - /* ensure that the DMA master bit is set */ - amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER; - - /* request all RAM */ - for (i = 0; i < m68k_num_memory; i++) { - ram_resource[i].name = - (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : - (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : - "16-bit Slow RAM"; - ram_resource[i].start = m68k_memory[i].addr; - ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; - request_resource(&iomem_resource, &ram_resource[i]); - } - - /* initialize chipram allocator */ - amiga_chip_init (); - - /* debugging using chipram */ - if (!strcmp( m68k_debug_device, "mem" )){ - if (!AMIGAHW_PRESENT(CHIP_RAM)) - printk("Warning: no chipram present for debugging\n"); - else { - amiga_savekmsg_init(); - amiga_console_driver.write = amiga_mem_console_write; - register_console(&amiga_console_driver); - } - } - - /* our beloved beeper */ - if (AMIGAHW_PRESENT(AMI_AUDIO)) - amiga_init_sound(); - - /* - * if it is an A3000, set the magic bit that forces - * a hard rekick - */ - if (AMIGAHW_PRESENT(MAGIC_REKICK)) - *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; -} - -static unsigned short jiffy_ticks; - -static void __init amiga_sched_init(irqreturn_t (*timer_routine)(int, void *, - struct pt_regs *)) -{ - static struct resource sched_res = { - "timer", 0x00bfd400, 0x00bfd5ff, - }; - jiffy_ticks = (amiga_eclock+HZ/2)/HZ; - - if (request_resource(&mb_resources._ciab, &sched_res)) - printk("Cannot allocate ciab.ta{lo,hi}\n"); - ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ - ciab.talo = jiffy_ticks % 256; - ciab.tahi = jiffy_ticks / 256; - - /* install interrupt service routine for CIAB Timer A - * - * Please don't change this to use ciaa, as it interferes with the - * SCSI code. We'll have to take a look at this later - */ - request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, 0, "timer", NULL); - /* start timer */ - ciab.cra |= 0x11; -} - -#define TICK_SIZE 10000 - -extern unsigned char cia_get_irq_mask(unsigned int irq); - -/* This is always executed with interrupts disabled. */ -static unsigned long amiga_gettimeoffset (void) -{ - unsigned short hi, lo, hi2; - unsigned long ticks, offset = 0; - - /* read CIA B timer A current value */ - hi = ciab.tahi; - lo = ciab.talo; - hi2 = ciab.tahi; - - if (hi != hi2) { - lo = ciab.talo; - hi = hi2; - } - - ticks = hi << 8 | lo; - - if (ticks > jiffy_ticks / 2) - /* check for pending interrupt */ - if (cia_get_irq_mask(IRQ_AMIGA_CIAB) & CIA_ICR_TA) - offset = 10000; - - ticks = jiffy_ticks - ticks; - ticks = (10000 * ticks) / jiffy_ticks; - - return ticks + offset; -} - -static void a3000_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - volatile struct tod3000 *tod = TOD_3000; - - tod->cntrl1 = TOD3000_CNTRL1_HOLD; - - *secp = tod->second1 * 10 + tod->second2; - *minp = tod->minute1 * 10 + tod->minute2; - *hourp = tod->hour1 * 10 + tod->hour2; - *dayp = tod->day1 * 10 + tod->day2; - *monp = tod->month1 * 10 + tod->month2; - *yearp = tod->year1 * 10 + tod->year2; - - tod->cntrl1 = TOD3000_CNTRL1_FREE; -} - -static void a2000_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - volatile struct tod2000 *tod = TOD_2000; - - tod->cntrl1 = TOD2000_CNTRL1_HOLD; - - while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) - ; - - *secp = tod->second1 * 10 + tod->second2; - *minp = tod->minute1 * 10 + tod->minute2; - *hourp = (tod->hour1 & 3) * 10 + tod->hour2; - *dayp = tod->day1 * 10 + tod->day2; - *monp = tod->month1 * 10 + tod->month2; - *yearp = tod->year1 * 10 + tod->year2; - - if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ - if (!(tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12) - *hourp = 0; - else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12) - *hourp += 12; - } - - tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; -} - -static int amiga_hwclk(int op, struct hwclk_time *t) -{ - if (AMIGAHW_PRESENT(A3000_CLK)) { - volatile struct tod3000 *tod = TOD_3000; - - tod->cntrl1 = TOD3000_CNTRL1_HOLD; - - if (!op) { /* read */ - t->sec = tod->second1 * 10 + tod->second2; - t->min = tod->minute1 * 10 + tod->minute2; - t->hour = tod->hour1 * 10 + tod->hour2; - t->day = tod->day1 * 10 + tod->day2; - t->wday = tod->weekday; - t->mon = tod->month1 * 10 + tod->month2 - 1; - t->year = tod->year1 * 10 + tod->year2; - if (t->year <= 69) - t->year += 100; - } else { - tod->second1 = t->sec / 10; - tod->second2 = t->sec % 10; - tod->minute1 = t->min / 10; - tod->minute2 = t->min % 10; - tod->hour1 = t->hour / 10; - tod->hour2 = t->hour % 10; - tod->day1 = t->day / 10; - tod->day2 = t->day % 10; - if (t->wday != -1) - tod->weekday = t->wday; - tod->month1 = (t->mon + 1) / 10; - tod->month2 = (t->mon + 1) % 10; - if (t->year >= 100) - t->year -= 100; - tod->year1 = t->year / 10; - tod->year2 = t->year % 10; - } - - tod->cntrl1 = TOD3000_CNTRL1_FREE; - } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { - volatile struct tod2000 *tod = TOD_2000; - - tod->cntrl1 = TOD2000_CNTRL1_HOLD; - - while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) - ; - - if (!op) { /* read */ - t->sec = tod->second1 * 10 + tod->second2; - t->min = tod->minute1 * 10 + tod->minute2; - t->hour = (tod->hour1 & 3) * 10 + tod->hour2; - t->day = tod->day1 * 10 + tod->day2; - t->wday = tod->weekday; - t->mon = tod->month1 * 10 + tod->month2 - 1; - t->year = tod->year1 * 10 + tod->year2; - if (t->year <= 69) - t->year += 100; - - if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ - if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12) - t->hour = 0; - else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->hour != 12) - t->hour += 12; - } - } else { - tod->second1 = t->sec / 10; - tod->second2 = t->sec % 10; - tod->minute1 = t->min / 10; - tod->minute2 = t->min % 10; - if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE) - tod->hour1 = t->hour / 10; - else if (t->hour >= 12) - tod->hour1 = TOD2000_HOUR1_PM + - (t->hour - 12) / 10; - else - tod->hour1 = t->hour / 10; - tod->hour2 = t->hour % 10; - tod->day1 = t->day / 10; - tod->day2 = t->day % 10; - if (t->wday != -1) - tod->weekday = t->wday; - tod->month1 = (t->mon + 1) / 10; - tod->month2 = (t->mon + 1) % 10; - if (t->year >= 100) - t->year -= 100; - tod->year1 = t->year / 10; - tod->year2 = t->year % 10; - } - - tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; - } - - return 0; -} - -static int amiga_set_clock_mmss (unsigned long nowtime) -{ - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; - - if (AMIGAHW_PRESENT(A3000_CLK)) { - volatile struct tod3000 *tod = TOD_3000; - - tod->cntrl1 = TOD3000_CNTRL1_HOLD; - - tod->second1 = real_seconds / 10; - tod->second2 = real_seconds % 10; - tod->minute1 = real_minutes / 10; - tod->minute2 = real_minutes % 10; - - tod->cntrl1 = TOD3000_CNTRL1_FREE; - } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { - volatile struct tod2000 *tod = TOD_2000; - - tod->cntrl1 = TOD2000_CNTRL1_HOLD; - - while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) - ; - - tod->second1 = real_seconds / 10; - tod->second2 = real_seconds % 10; - tod->minute1 = real_minutes / 10; - tod->minute2 = real_minutes % 10; - - tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; - } - - return 0; -} - -static NORET_TYPE void amiga_reset( void ) - ATTRIB_NORET; - -static void amiga_reset (void) -{ - for (;;); -} - - - /* - * Debugging - */ - -#define SAVEKMSG_MAXMEM 128*1024 - -#define SAVEKMSG_MAGIC1 0x53415645 /* 'SAVE' */ -#define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ - -struct savekmsg { - unsigned long magic1; /* SAVEKMSG_MAGIC1 */ - unsigned long magic2; /* SAVEKMSG_MAGIC2 */ - unsigned long magicptr; /* address of magic1 */ - unsigned long size; - char data[0]; -}; - -static struct savekmsg *savekmsg = NULL; - -static void amiga_mem_console_write(struct console *co, const char *s, - unsigned int count) -{ - if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { - memcpy(savekmsg->data+savekmsg->size, s, count); - savekmsg->size += count; - } -} - -static void amiga_savekmsg_init(void) -{ - static struct resource debug_res = { "Debug" }; - - savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); - savekmsg->magic1 = SAVEKMSG_MAGIC1; - savekmsg->magic2 = SAVEKMSG_MAGIC2; - savekmsg->magicptr = virt_to_phys(savekmsg); - savekmsg->size = 0; -} - -static void amiga_serial_putc(char c) -{ - amiga_custom.serdat = (unsigned char)c | 0x100; - mb(); - while (!(amiga_custom.serdatr & 0x2000)) - ; -} - -void amiga_serial_console_write(struct console *co, const char *s, - unsigned int count) -{ -#if 0 /* def CONFIG_KGDB */ - /* FIXME:APUS GDB doesn't seem to like O-packages before it is - properly connected with the target. */ - __gdb_output_string (s, count); -#else - while (count--) { - if (*s == '\n') - amiga_serial_putc('\r'); - amiga_serial_putc(*s++); - } -#endif -} - -#ifdef CONFIG_SERIAL_CONSOLE -void amiga_serial_puts(const char *s) -{ - amiga_serial_console_write(NULL, s, strlen(s)); -} - -int amiga_serial_console_wait_key(struct console *co) -{ - int ch; - - while (!(amiga_custom.intreqr & IF_RBF)) - barrier(); - ch = amiga_custom.serdatr & 0xff; - /* clear the interrupt, so that another character can be read */ - amiga_custom.intreq = IF_RBF; - return ch; -} - -void amiga_serial_gets(struct console *co, char *s, int len) -{ - int ch, cnt = 0; - - while (1) { - ch = amiga_serial_console_wait_key(co); - - /* Check for backspace. */ - if (ch == 8 || ch == 127) { - if (cnt == 0) { - amiga_serial_putc('\007'); - continue; - } - cnt--; - amiga_serial_puts("\010 \010"); - continue; - } - - /* Check for enter. */ - if (ch == 10 || ch == 13) - break; - - /* See if line is too long. */ - if (cnt >= len + 1) { - amiga_serial_putc(7); - cnt--; - continue; - } - - /* Store and echo character. */ - s[cnt++] = ch; - amiga_serial_putc(ch); - } - /* Print enter. */ - amiga_serial_puts("\r\n"); - s[cnt] = 0; -} -#endif - -static void __init amiga_debug_init(void) -{ - if (!strcmp( m68k_debug_device, "ser" )) { - /* no initialization required (?) */ - amiga_console_driver.write = amiga_serial_console_write; - register_console(&amiga_console_driver); - } -} - -#ifdef CONFIG_HEARTBEAT -static void amiga_heartbeat(int on) -{ - if (on) - ciaa.pra &= ~2; - else - ciaa.pra |= 2; -} -#endif - - /* - * Amiga specific parts of /proc - */ - -static void amiga_get_model(char *model) -{ - strcpy(model, amiga_model_name); -} - - -static int amiga_get_hardware_list(char *buffer) -{ - int len = 0; - - if (AMIGAHW_PRESENT(CHIP_RAM)) - len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); - len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", - amiga_psfreq, amiga_eclock); - if (AMIGAHW_PRESENT(AMI_VIDEO)) { - char *type; - switch(amiga_chipset) { - case CS_OCS: - type = "OCS"; - break; - case CS_ECS: - type = "ECS"; - break; - case CS_AGA: - type = "AGA"; - break; - default: - type = "Old or Unknown"; - break; - } - len += sprintf(buffer+len, "Graphics:\t%s\n", type); - } - -#define AMIGAHW_ANNOUNCE(name, str) \ - if (AMIGAHW_PRESENT(name)) \ - len += sprintf (buffer+len, "\t%s\n", str) - - len += sprintf (buffer + len, "Detected hardware:\n"); - - AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); - AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); - AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); - AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); - AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); - AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); - AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); - AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); - AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); - AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); - AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); - AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); - AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); - AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); - AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); - AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); - AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); - AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); - AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); - AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); - AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); - AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); - AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); - AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); - AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); - AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); - AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); - AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); - AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); - if (AMIGAHW_PRESENT(ZORRO)) - len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion " - "Device%s\n", - AMIGAHW_PRESENT(ZORRO3) ? "I" : "", - zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); - -#undef AMIGAHW_ANNOUNCE - - return(len); -} - -#ifdef CONFIG_APUS -int get_hardware_list(char *buffer) -{ - extern int get_cpuinfo(char *buffer); - int len = 0; - char model[80]; - u_long mem; - int i; - - if (mach_get_model) - mach_get_model(model); - else - strcpy(model, "Unknown PowerPC"); - - len += sprintf(buffer+len, "Model:\t\t%s\n", model); - len += get_cpuinfo(buffer+len); - for (mem = 0, i = 0; i < m68k_realnum_memory; i++) - mem += m68k_memory[i].size; - len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); - - if (mach_get_hardware_list) - len += mach_get_hardware_list(buffer+len); - - return(len); -} -#endif diff --git a/arch/ppc/amiga/ints.c b/arch/ppc/amiga/ints.c deleted file mode 100644 index 083a17462190..000000000000 --- a/arch/ppc/amiga/ints.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Linux/m68k general interrupt handling code from arch/m68k/kernel/ints.c - * Needed to drive the m68k emulating IRQ hardware on the PowerUp boards. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* table for system interrupt handlers */ -static irq_handler_t irq_list[SYS_IRQS]; - -static const char *default_names[SYS_IRQS] = { - "spurious int", "int1 handler", "int2 handler", "int3 handler", - "int4 handler", "int5 handler", "int6 handler", "int7 handler" -}; - -/* The number of spurious interrupts */ -volatile unsigned int num_spurious; - -#define NUM_IRQ_NODES 100 -static irq_node_t nodes[NUM_IRQ_NODES]; - - -/* - * void init_IRQ(void) - * - * Parameters: None - * - * Returns: Nothing - * - * This function should be called during kernel startup to initialize - * the IRQ handling routines. - */ - -__init -void m68k_init_IRQ(void) -{ - int i; - - for (i = 0; i < SYS_IRQS; i++) { - if (mach_default_handler) - irq_list[i].handler = (*mach_default_handler)[i]; - irq_list[i].flags = 0; - irq_list[i].dev_id = NULL; - irq_list[i].devname = default_names[i]; - } - - for (i = 0; i < NUM_IRQ_NODES; i++) - nodes[i].handler = NULL; - - mach_init_IRQ (); -} - -irq_node_t *new_irq_node(void) -{ - irq_node_t *node; - short i; - - for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) - if (!node->handler) - return node; - - printk ("new_irq_node: out of nodes\n"); - return NULL; -} - -int sys_request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) -{ - if (irq < IRQ1 || irq > IRQ7) { - printk("%s: Incorrect IRQ %d from %s\n", - __FUNCTION__, irq, devname); - return -ENXIO; - } - -#if 0 - if (!(irq_list[irq].flags & IRQ_FLG_STD)) { - if (irq_list[irq].flags & IRQ_FLG_LOCK) { - printk("%s: IRQ %d from %s is not replaceable\n", - __FUNCTION__, irq, irq_list[irq].devname); - return -EBUSY; - } - if (!(flags & IRQ_FLG_REPLACE)) { - printk("%s: %s can't replace IRQ %d from %s\n", - __FUNCTION__, devname, irq, irq_list[irq].devname); - return -EBUSY; - } - } -#endif - - irq_list[irq].handler = handler; - irq_list[irq].flags = flags; - irq_list[irq].dev_id = dev_id; - irq_list[irq].devname = devname; - return 0; -} - -void sys_free_irq(unsigned int irq, void *dev_id) -{ - if (irq < IRQ1 || irq > IRQ7) { - printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); - return; - } - - if (irq_list[irq].dev_id != dev_id) - printk("%s: Removing probably wrong IRQ %d from %s\n", - __FUNCTION__, irq, irq_list[irq].devname); - - irq_list[irq].handler = (*mach_default_handler)[irq]; - irq_list[irq].flags = 0; - irq_list[irq].dev_id = NULL; - irq_list[irq].devname = default_names[irq]; -} - -asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) -{ - if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) { - vec -= VEC_SPUR; - kstat_cpu(0).irqs[vec]++; - irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); - } else { - if (mach_process_int) - mach_process_int(vec, fp); - else - panic("Can't process interrupt vector %ld\n", vec); - return; - } -} - -int m68k_get_irq_list(struct seq_file *p, void *v) -{ - int i; - - /* autovector interrupts */ - if (mach_default_handler) { - for (i = 0; i < SYS_IRQS; i++) { - seq_printf(p, "auto %2d: %10u ", i, - i ? kstat_cpu(0).irqs[i] : num_spurious); - seq_puts(p, " "); - seq_printf(p, "%s\n", irq_list[i].devname); - } - } - - mach_get_irq_list(p, v); - return 0; -} diff --git a/arch/ppc/amiga/pcmcia.c b/arch/ppc/amiga/pcmcia.c deleted file mode 100644 index 5d29dc65093c..000000000000 --- a/arch/ppc/amiga/pcmcia.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../m68k/amiga/pcmcia.c" diff --git a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c deleted file mode 100644 index 8c880c0ca380..000000000000 --- a/arch/ppc/amiga/time.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -unsigned long m68k_get_rtc_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - - extern void arch_gettod(int *year, int *mon, int *day, int *hour, - int *min, int *sec); - - arch_gettod (&year, &mon, &day, &hour, &min, &sec); - - if ((year += 1900) < 1970) - year += 100; - - return mktime(year, mon, day, hour, min, sec); -} - -int m68k_set_rtc_time(unsigned long nowtime) -{ - if (mach_set_clock_mmss) - return mach_set_clock_mmss (nowtime); - return -1; -} - -void apus_heartbeat (void) -{ -#ifdef CONFIG_HEARTBEAT - static unsigned cnt = 0, period = 0, dist = 0; - - if (cnt == 0 || cnt == dist) - mach_heartbeat( 1 ); - else if (cnt == 7 || cnt == dist+7) - mach_heartbeat( 0 ); - - if (++cnt > period) { - cnt = 0; - /* The hyperbolic function below modifies the heartbeat period - * length in dependency of the current (5min) load. It goes - * through the points f(0)=126, f(1)=86, f(5)=51, - * f(inf)->30. */ - period = ((672< #include -#ifdef CONFIG_APUS -#include -#endif - /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, reg, RA, RB) \ /* see the comment for clear_bats() -- Cort */ \ @@ -128,14 +124,6 @@ __start: */ bl early_init -#ifdef CONFIG_APUS -/* On APUS the __va/__pa constants need to be set to the correct - * values before continuing. - */ - mr r4,r30 - bl fix_mem_constants -#endif /* CONFIG_APUS */ - /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by early_init() */ @@ -145,7 +133,7 @@ __after_mmu_off: bl flush_tlbs bl initial_bats -#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) +#ifdef CONFIG_BOOTX_TEXT bl setup_disp_bat #endif @@ -161,7 +149,6 @@ __after_mmu_off: #endif /* CONFIG_6xx */ -#ifndef CONFIG_APUS /* * We need to run with _start at physical address 0. * If the MMU is already turned on, we copy stuff to KERNELBASE, @@ -172,7 +159,7 @@ __after_mmu_off: addis r4,r3,KERNELBASE@h /* current address of _start */ cmpwi 0,r4,0 /* are we already running at 0? */ bne relocate_kernel -#endif /* CONFIG_APUS */ + /* * we now have the 1st 16M of ram mapped with the bats. * prep needs the mmu to be turned on here, but pmac already has it on. @@ -812,85 +799,6 @@ copy_and_flush: addi r6,r6,4 blr -#ifdef CONFIG_APUS -/* - * On APUS the physical base address of the kernel is not known at compile - * time, which means the __pa/__va constants used are incorrect. In the - * __init section is recorded the virtual addresses of instructions using - * these constants, so all that has to be done is fix these before - * continuing the kernel boot. - * - * r4 = The physical address of the kernel base. - */ -fix_mem_constants: - mr r10,r4 - addis r10,r10,-KERNELBASE@h /* virt_to_phys constant */ - neg r11,r10 /* phys_to_virt constant */ - - lis r12,__vtop_table_begin@h - ori r12,r12,__vtop_table_begin@l - add r12,r12,r10 /* table begin phys address */ - lis r13,__vtop_table_end@h - ori r13,r13,__vtop_table_end@l - add r13,r13,r10 /* table end phys address */ - subi r12,r12,4 - subi r13,r13,4 -1: lwzu r14,4(r12) /* virt address of instruction */ - add r14,r14,r10 /* phys address of instruction */ - lwz r15,0(r14) /* instruction, now insert top */ - rlwimi r15,r10,16,16,31 /* half of vp const in low half */ - stw r15,0(r14) /* of instruction and restore. */ - dcbst r0,r14 /* write it to memory */ - sync - icbi r0,r14 /* flush the icache line */ - cmpw r12,r13 - bne 1b - sync /* additional sync needed on g4 */ - isync - -/* - * Map the memory where the exception handlers will - * be copied to when hash constants have been patched. - */ -#ifdef CONFIG_APUS_FAST_EXCEPT - lis r8,0xfff0 -#else - lis r8,0 -#endif - ori r8,r8,0x2 /* 128KB, supervisor */ - mtspr SPRN_DBAT3U,r8 - mtspr SPRN_DBAT3L,r8 - - lis r12,__ptov_table_begin@h - ori r12,r12,__ptov_table_begin@l - add r12,r12,r10 /* table begin phys address */ - lis r13,__ptov_table_end@h - ori r13,r13,__ptov_table_end@l - add r13,r13,r10 /* table end phys address */ - subi r12,r12,4 - subi r13,r13,4 -1: lwzu r14,4(r12) /* virt address of instruction */ - add r14,r14,r10 /* phys address of instruction */ - lwz r15,0(r14) /* instruction, now insert top */ - rlwimi r15,r11,16,16,31 /* half of pv const in low half*/ - stw r15,0(r14) /* of instruction and restore. */ - dcbst r0,r14 /* write it to memory */ - sync - icbi r0,r14 /* flush the icache line */ - cmpw r12,r13 - bne 1b - - sync /* additional sync needed on g4 */ - isync /* No speculative loading until now */ - blr - -/*********************************************************************** - * Please note that on APUS the exception handlers are located at the - * physical address 0xfff0000. For this reason, the exception handlers - * cannot use relative branches to access the code below. - ***********************************************************************/ -#endif /* CONFIG_APUS */ - #ifdef CONFIG_SMP .globl __secondary_start_pmac_0 __secondary_start_pmac_0: @@ -1043,19 +951,6 @@ start_here: bl machine_init bl MMU_init -#ifdef CONFIG_APUS - /* Copy exception code to exception vector base on APUS. */ - lis r4,KERNELBASE@h -#ifdef CONFIG_APUS_FAST_EXCEPT - lis r3,0xfff0 /* Copy to 0xfff00000 */ -#else - lis r3,0 /* Copy to 0x00000000 */ -#endif - li r5,0x4000 /* # bytes of memory to copy */ - li r6,0 - bl copy_and_flush /* copy the first 0x4000 bytes */ -#endif /* CONFIG_APUS */ - /* * Go back to running unmapped so we can load up new values * for SDR1 (hash table pointer) and the segment registers @@ -1232,11 +1127,7 @@ initial_bats: #else ori r8,r8,2 /* R/W access */ #endif /* CONFIG_SMP */ -#ifdef CONFIG_APUS - ori r11,r11,BL_8M<<2|0x2 /* set up 8MB BAT registers for 604 */ -#else ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ -#endif /* CONFIG_APUS */ mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */ @@ -1245,7 +1136,7 @@ initial_bats: isync blr -#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) +#ifdef CONFIG_BOOTX_TEXT setup_disp_bat: /* * setup the display bat prepared for us in prom.c @@ -1268,7 +1159,7 @@ setup_disp_bat: mtspr SPRN_IBAT3U,r11 blr -#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ +#endif /* defined(CONFIG_BOOTX_TEXT) */ #ifdef CONFIG_8260 /* Jump into the system reset for the rom. diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 63f0a987139b..22494ec123ea 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -60,8 +60,6 @@ long long __ashrdi3(long long, int); long long __ashldi3(long long, int); long long __lshrdi3(long long, int); -extern unsigned long mm_ptov (unsigned long paddr); - EXPORT_SYMBOL(clear_pages); EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(transfer_to_handler); @@ -118,7 +116,6 @@ EXPORT_SYMBOL(_outsw_ns); EXPORT_SYMBOL(_insl_ns); EXPORT_SYMBOL(_outsl_ns); EXPORT_SYMBOL(iopa); -EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(ioremap); #ifdef CONFIG_44x EXPORT_SYMBOL(ioremap64); diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 967c1ef59a6b..aac88c2f3db9 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index 35ebb6395ae3..1f51e6c94507 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -426,41 +426,3 @@ unsigned long iopa(unsigned long addr) return(pa); } -/* This is will find the virtual address for a physical one.... - * Swiped from APUS, could be dangerous :-). - * This is only a placeholder until I really find a way to make this - * work. -- Dan - */ -unsigned long -mm_ptov (unsigned long paddr) -{ - unsigned long ret; -#if 0 - if (paddr < 16*1024*1024) - ret = ZTWO_VADDR(paddr); - else { - int i; - - for (i = 0; i < kmap_chunk_count;){ - unsigned long phys = kmap_chunks[i++]; - unsigned long size = kmap_chunks[i++]; - unsigned long virt = kmap_chunks[i++]; - if (paddr >= phys - && paddr < (phys + size)){ - ret = virt + paddr - phys; - goto exit; - } - } - - ret = (unsigned long) __va(paddr); - } -exit: -#ifdef DEBUGPV - printk ("PTOV(%lx)=%lx\n", paddr, ret); -#endif -#else - ret = (unsigned long)paddr + KERNELBASE; -#endif - return ret; -} - diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile index e17fad470621..40f53fbe6d35 100644 --- a/arch/ppc/platforms/Makefile +++ b/arch/ppc/platforms/Makefile @@ -2,10 +2,6 @@ # Makefile for the linux kernel. # -obj-$(CONFIG_APUS) += apus_setup.o -ifeq ($(CONFIG_APUS),y) -obj-$(CONFIG_PCI) += apus_pci.o -endif obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_setup.o obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_PQ2ADS) += pq2ads.o diff --git a/arch/ppc/platforms/apus_pci.c b/arch/ppc/platforms/apus_pci.c deleted file mode 100644 index dc165f0c8908..000000000000 --- a/arch/ppc/platforms/apus_pci.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) Michel Dไnzer - * - * APUS PCI routines. - * - * Currently, only B/CVisionPPC cards (Permedia2) are supported. - * - * Thanks to Geert Uytterhoeven for the idea: - * Read values from given config space(s) for the first devices, -1 otherwise - * - */ - -#ifdef CONFIG_AMIGA - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "apus_pci.h" - - -/* These definitions are mostly adapted from pm2fb.c */ - -#undef APUS_PCI_MASTER_DEBUG -#ifdef APUS_PCI_MASTER_DEBUG -#define DPRINTK(a,b...) printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b) -#else -#define DPRINTK(a,b...) -#endif - -/* - * The _DEFINITIVE_ memory mapping/unmapping functions. - * This is due to the fact that they're changing soooo often... - */ -#define DEFW() wmb() -#define DEFR() rmb() -#define DEFRW() mb() - -#define DEVNO(d) ((d)>>3) -#define FNNO(d) ((d)&7) - - -extern unsigned long powerup_PCI_present; - -static struct pci_controller *apus_hose; - - -void *pci_io_base(unsigned int bus) -{ - return 0; -} - - -int -apus_pcibios_read_config(struct pci_bus *bus, int devfn, int offset, - int len, u32 *val) -{ - int fnno = FNNO(devfn); - int devno = DEVNO(devfn); - volatile unsigned char *cfg_data; - - if (bus->number > 0 || devno != 1) { - *val = ~0; - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* base address + function offset + offset ^ endianness conversion */ - /* XXX the fnno<<5 bit seems wacky -- paulus */ - cfg_data = apus_hose->cfg_data + (fnno<<5) + (offset ^ (len - 1)); - switch (len) { - case 1: - *val = readb(cfg_data); - break; - case 2: - *val = readw(cfg_data); - break; - default: - *val = readl(cfg_data); - break; - } - - DPRINTK("read b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, l: %d, v: 0x%x\n", - bus->number, devfn>>3, devfn&7, offset, len, *val); - return PCIBIOS_SUCCESSFUL; -} - -int -apus_pcibios_write_config(struct pci_bus *bus, int devfn, int offset, - int len, u32 *val) -{ - int fnno = FNNO(devfn); - int devno = DEVNO(devfn); - volatile unsigned char *cfg_data; - - if (bus->number > 0 || devno != 1) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* base address + function offset + offset ^ endianness conversion */ - /* XXX the fnno<<5 bit seems wacky -- paulus */ - cfg_data = apus_hose->cfg_data + (fnno<<5) + (offset ^ (len - 1)); - switch (len) { - case 1: - writeb(val, cfg_data); DEFW(); - break; - case 2: - writew(val, cfg_data); DEFW(); - break; - default: - writel(val, cfg_data); DEFW(); - break; - } - - DPRINTK("write b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, l: %d, v: 0x%x\n", - bus->number, devfn>>3, devfn&7, offset, len, val); - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops apus_pci_ops = { - apus_pcibios_read_config, - apus_pcibios_write_config -}; - -static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM }; - -void __init -apus_pcibios_fixup(void) -{ -/* struct pci_dev *dev = pci_find_slot(0, 1<<3); - unsigned int reg, val, offset;*/ - - /* FIXME: interrupt? */ - /*dev->interrupt = xxx;*/ - - request_resource(&iomem_resource, &pci_mem); - printk("%s: PCI mem resource requested\n", __FUNCTION__); -} - -static void __init apus_pcibios_fixup_bus(struct pci_bus *bus) -{ - bus->resource[1] = &pci_mem; -} - - -/* - * This is from pm2fb.c again - * - * Check if PCI (B/CVisionPPC) is available, initialize it and set up - * the pcibios_* pointers - */ - - -void __init -apus_setup_pci_ptrs(void) -{ - if (!powerup_PCI_present) { - DPRINTK("no PCI bridge detected\n"); - return; - } - DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n"); - - apus_hose = pcibios_alloc_controller(); - if (!apus_hose) { - printk("apus_pci: Can't allocate PCI controller structure\n"); - return; - } - - if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) { - printk("apus_pci: unable to map PCI config region\n"); - return; - } - - if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) { - printk("apus_pci: unable to map PCI bridge\n"); - return; - } - - writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN); - DEFW(); - - writel(CVPPC_REGS_REGION, apus_hose->cfg_data+ PCI_BASE_ADDRESS_0); - DEFW(); - writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1); - DEFW(); - writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2); - DEFW(); - writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS); - DEFW(); - - writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND); - DEFW(); - - apus_hose->first_busno = 0; - apus_hose->last_busno = 0; - apus_hose->ops = &apus_pci_ops; - ppc_md.pcibios_fixup = apus_pcibios_fixup; - ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus; - - return; -} - -#endif /* CONFIG_AMIGA */ diff --git a/arch/ppc/platforms/apus_pci.h b/arch/ppc/platforms/apus_pci.h deleted file mode 100644 index f15974ae0189..000000000000 --- a/arch/ppc/platforms/apus_pci.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer - * driver. - * - * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) - * -------------------------------------------------------------------------- - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file README.legal in the main directory of this archive - * for more details. - */ - -#ifndef APUS_PCI_H -#define APUS_PCI_H - - -#define CSPPC_PCI_BRIDGE 0xfffe0000 -#define CSPPC_BRIDGE_ENDIAN 0x0000 -#define CSPPC_BRIDGE_INT 0x0010 - -#define CVPPC_PCI_CONFIG 0xfffc0000 -#define CVPPC_ROM_ADDRESS 0xe2000001 -#define CVPPC_REGS_REGION 0xef000000 -#define CVPPC_FB_APERTURE_ONE 0xe0000000 -#define CVPPC_FB_APERTURE_TWO 0xe1000000 -#define CVPPC_FB_SIZE 0x00800000 - -/* CVPPC_BRIDGE_ENDIAN */ -#define CSPPCF_BRIDGE_BIG_ENDIAN 0x02 - -/* CVPPC_BRIDGE_INT */ -#define CSPPCF_BRIDGE_ACTIVE_INT2 0x01 - - -#endif /* APUS_PCI_H */ diff --git a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c deleted file mode 100644 index 063274d2c503..000000000000 --- a/arch/ppc/platforms/apus_setup.c +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Copyright (C) 1998, 1999 Jesper Skov - * - * Basically what is needed to replace functionality found in - * arch/m68k allowing Amiga drivers to work under APUS. - * Bits of code and/or ideas from arch/m68k and arch/ppc files. - * - * TODO: - * This file needs a *really* good cleanup. Restructure and optimize. - * Make sure it can be compiled for non-APUS configs. Begin to move - * Amiga specific stuff into mach/amiga. - */ - -#include -#include -#include -#include -#include - -/* Needs INITSERIAL call in head.S! */ -#undef APUS_DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -unsigned long m68k_machtype; -char debug_device[6] = ""; - -extern void amiga_init_IRQ(void); - -extern void apus_setup_pci_ptrs(void); - -void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL; -/* machine dependent irq functions */ -void (*mach_init_IRQ) (void) __initdata = NULL; -void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; -void (*mach_get_model) (char *model) = NULL; -int (*mach_get_hardware_list) (char *buffer) = NULL; -int (*mach_get_irq_list) (struct seq_file *, void *) = NULL; -void (*mach_process_int) (int, struct pt_regs *) = NULL; -/* machine dependent timer functions */ -unsigned long (*mach_gettimeoffset) (void); -void (*mach_gettod) (int*, int*, int*, int*, int*, int*); -int (*mach_hwclk) (int, struct hwclk_time*) = NULL; -int (*mach_set_clock_mmss) (unsigned long) = NULL; -void (*mach_reset)( void ); -long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -#ifdef CONFIG_HEARTBEAT -void (*mach_heartbeat) (int) = NULL; -extern void apus_heartbeat (void); -#endif - -extern unsigned long amiga_model; -extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */ -extern unsigned count_period_num; /* 1 decrementer count equals */ -extern unsigned count_period_den; /* count_period_num / count_period_den us */ - -int num_memory = 0; -struct mem_info memory[NUM_MEMINFO];/* memory description */ -/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */ -int m68k_realnum_memory = 0; -struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */ - -struct mem_info ramdisk; - -extern void config_amiga(void); - -static int __60nsram = 0; - -/* for cpuinfo */ -static int __bus_speed = 0; -static int __speed_test_failed = 0; - -/********************************************** COMPILE PROTECTION */ -/* Provide some stubs that links to Amiga specific functions. - * This allows CONFIG_APUS to be removed from generic PPC files while - * preventing link errors for other PPC targets. - */ -unsigned long apus_get_rtc_time(void) -{ -#ifdef CONFIG_APUS - extern unsigned long m68k_get_rtc_time(void); - - return m68k_get_rtc_time (); -#else - return 0; -#endif -} - -int apus_set_rtc_time(unsigned long nowtime) -{ -#ifdef CONFIG_APUS - extern int m68k_set_rtc_time(unsigned long nowtime); - - return m68k_set_rtc_time (nowtime); -#else - return 0; -#endif -} - -/*********************************************************** SETUP */ -/* From arch/m68k/kernel/setup.c. */ -void __init apus_setup_arch(void) -{ -#ifdef CONFIG_APUS - extern char cmd_line[]; - int i; - char *p, *q; - - /* Let m68k-shared code know it should do the Amiga thing. */ - m68k_machtype = MACH_AMIGA; - - /* Parse the command line for arch-specific options. - * For the m68k, this is currently only "debug=xxx" to enable printing - * certain kernel messages to some machine-specific device. */ - for( p = cmd_line; p && *p; ) { - i = 0; - if (!strncmp( p, "debug=", 6 )) { - strlcpy( debug_device, p+6, sizeof(debug_device) ); - if ((q = strchr( debug_device, ' ' ))) *q = 0; - i = 1; - } else if (!strncmp( p, "60nsram", 7 )) { - APUS_WRITE (APUS_REG_WAITSTATE, - REGWAITSTATE_SETRESET - |REGWAITSTATE_PPCR - |REGWAITSTATE_PPCW); - __60nsram = 1; - i = 1; - } - - if (i) { - /* option processed, delete it */ - if ((q = strchr( p, ' ' ))) - strcpy( p, q+1 ); - else - *p = 0; - } else { - if ((p = strchr( p, ' ' ))) ++p; - } - } - - config_amiga(); - -#if 0 /* Enable for logging - also include logging.o in Makefile rule */ - { -#define LOG_SIZE 4096 - void* base; - - /* Throw away some memory - the P5 firmare stomps on top - * of CHIP memory during bootup. - */ - amiga_chip_alloc(0x1000); - - base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t)); - LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE); - } -#endif -#endif -} - -int -apus_show_cpuinfo(struct seq_file *m) -{ - extern int __map_without_bats; - extern unsigned long powerup_PCI_present; - - seq_printf(m, "machine\t\t: Amiga\n"); - seq_printf(m, "bus speed\t: %d%s", __bus_speed, - (__speed_test_failed) ? " [failed]\n" : "\n"); - seq_printf(m, "using BATs\t: %s\n", - (__map_without_bats) ? "No" : "Yes"); - seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70); - seq_printf(m, "PCI bridge\t: %s\n", - (powerup_PCI_present) ? "Yes" : "No"); - return 0; -} - -static void get_current_tb(unsigned long long *time) -{ - __asm __volatile ("1:mftbu 4 \n\t" - " mftb 5 \n\t" - " mftbu 6 \n\t" - " cmpw 4,6 \n\t" - " bne 1b \n\t" - " stw 4,0(%0)\n\t" - " stw 5,4(%0)\n\t" - : - : "r" (time) - : "r4", "r5", "r6"); -} - - -void apus_calibrate_decr(void) -{ -#ifdef CONFIG_APUS - unsigned long freq; - - /* This algorithm for determining the bus speed was - contributed by Ralph Schmidt. */ - unsigned long long start, stop; - int bus_speed; - int speed_test_failed = 0; - - { - unsigned long loop = amiga_eclock / 10; - - get_current_tb (&start); - while (loop--) { - unsigned char tmp; - - tmp = ciaa.pra; - } - get_current_tb (&stop); - } - - bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000; - if (AMI_1200 == amiga_model) - bus_speed /= 2; - - if ((bus_speed >= 47) && (bus_speed < 53)) { - bus_speed = 50; - freq = 12500000; - } else if ((bus_speed >= 57) && (bus_speed < 63)) { - bus_speed = 60; - freq = 15000000; - } else if ((bus_speed >= 63) && (bus_speed < 69)) { - bus_speed = 67; - freq = 16666667; - } else { - printk ("APUS: Unable to determine bus speed (%d). " - "Defaulting to 50MHz", bus_speed); - bus_speed = 50; - freq = 12500000; - speed_test_failed = 1; - } - - /* Ease diagnostics... */ - { - extern int __map_without_bats; - extern unsigned long powerup_PCI_present; - - printk ("APUS: BATs=%d, BUS=%dMHz", - (__map_without_bats) ? 0 : 1, - bus_speed); - if (speed_test_failed) - printk ("[FAILED - please report]"); - - printk (", RAM=%dns, PCI bridge=%d\n", - (__60nsram) ? 60 : 70, - (powerup_PCI_present) ? 1 : 0); - - /* print a bit more if asked politely... */ - if (!(ciaa.pra & 0x40)){ - extern unsigned int bat_addrs[4][3]; - int b; - for (b = 0; b < 4; ++b) { - printk ("APUS: BAT%d ", b); - printk ("%08x-%08x -> %08x\n", - bat_addrs[b][0], - bat_addrs[b][1], - bat_addrs[b][2]); - } - } - - } - - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - - __bus_speed = bus_speed; - __speed_test_failed = speed_test_failed; -#endif -} - -void arch_gettod(int *year, int *mon, int *day, int *hour, - int *min, int *sec) -{ -#ifdef CONFIG_APUS - if (mach_gettod) - mach_gettod(year, mon, day, hour, min, sec); - else - *year = *mon = *day = *hour = *min = *sec = 0; -#endif -} - -/* for "kbd-reset" cmdline param */ -__init -void kbd_reset_setup(char *str, int *ints) -{ -} - -/*********************************************************** MEMORY */ -#define KMAP_MAX 32 -unsigned long kmap_chunks[KMAP_MAX*3]; -int kmap_chunk_count = 0; - -/* From pgtable.h */ -static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va) -{ - pgd_t *dir = 0; - pmd_t *pmd = 0; - pte_t *pte = 0; - - va &= PAGE_MASK; - - dir = pgd_offset( mm, va ); - if (dir) - { - pmd = pmd_offset(dir, va & PAGE_MASK); - if (pmd && pmd_present(*pmd)) - { - pte = pte_offset(pmd, va); - } - } - return pte; -} - - -/* Again simulating an m68k/mm/kmap.c function. */ -void kernel_set_cachemode( unsigned long address, unsigned long size, - unsigned int cmode ) -{ - unsigned long mask, flags; - - switch (cmode) - { - case IOMAP_FULL_CACHING: - mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED); - flags = 0; - break; - case IOMAP_NOCACHE_SER: - mask = ~0; - flags = (_PAGE_NO_CACHE | _PAGE_GUARDED); - break; - default: - panic ("kernel_set_cachemode() doesn't support mode %d\n", - cmode); - break; - } - - size /= PAGE_SIZE; - address &= PAGE_MASK; - while (size--) - { - pte_t *pte; - - pte = my_find_pte(&init_mm, address); - if ( !pte ) - { - printk("pte NULL in kernel_set_cachemode()\n"); - return; - } - - pte_val (*pte) &= mask; - pte_val (*pte) |= flags; - flush_tlb_page(find_vma(&init_mm,address),address); - - address += PAGE_SIZE; - } -} - -unsigned long mm_ptov (unsigned long paddr) -{ - unsigned long ret; - if (paddr < 16*1024*1024) - ret = ZTWO_VADDR(paddr); - else { - int i; - - for (i = 0; i < kmap_chunk_count;){ - unsigned long phys = kmap_chunks[i++]; - unsigned long size = kmap_chunks[i++]; - unsigned long virt = kmap_chunks[i++]; - if (paddr >= phys - && paddr < (phys + size)){ - ret = virt + paddr - phys; - goto exit; - } - } - - ret = (unsigned long) __va(paddr); - } -exit: -#ifdef DEBUGPV - printk ("PTOV(%lx)=%lx\n", paddr, ret); -#endif - return ret; -} - -int mm_end_of_chunk (unsigned long addr, int len) -{ - if (memory[0].addr + memory[0].size == addr + len) - return 1; - return 0; -} - -/*********************************************************** CACHE */ - -#define L1_CACHE_BYTES 32 -#define MAX_CACHE_SIZE 8192 -void cache_push(__u32 addr, int length) -{ - addr = mm_ptov(addr); - - if (MAX_CACHE_SIZE < length) - length = MAX_CACHE_SIZE; - - while(length > 0){ - __asm ("dcbf 0,%0\n\t" - : : "r" (addr)); - addr += L1_CACHE_BYTES; - length -= L1_CACHE_BYTES; - } - /* Also flush trailing block */ - __asm ("dcbf 0,%0\n\t" - "sync \n\t" - : : "r" (addr)); -} - -void cache_clear(__u32 addr, int length) -{ - if (MAX_CACHE_SIZE < length) - length = MAX_CACHE_SIZE; - - addr = mm_ptov(addr); - - __asm ("dcbf 0,%0\n\t" - "sync \n\t" - "icbi 0,%0 \n\t" - "isync \n\t" - : : "r" (addr)); - - addr += L1_CACHE_BYTES; - length -= L1_CACHE_BYTES; - - while(length > 0){ - __asm ("dcbf 0,%0\n\t" - "sync \n\t" - "icbi 0,%0 \n\t" - "isync \n\t" - : : "r" (addr)); - addr += L1_CACHE_BYTES; - length -= L1_CACHE_BYTES; - } - - __asm ("dcbf 0,%0\n\t" - "sync \n\t" - "icbi 0,%0 \n\t" - "isync \n\t" - : : "r" (addr)); -} - -/****************************************************** from setup.c */ -void -apus_restart(char *cmd) -{ - local_irq_disable(); - - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2); - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3); - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3); - APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET); - APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET); - for(;;); -} - -void -apus_power_off(void) -{ - for (;;); -} - -void -apus_halt(void) -{ - apus_restart(NULL); -} - -/****************************************************** IRQ stuff */ - -static unsigned char last_ipl[8]; - -int apus_get_irq(void) -{ - unsigned char ipl_emu, mask; - unsigned int level; - - APUS_READ(APUS_IPL_EMU, ipl_emu); - level = (ipl_emu >> 3) & IPLEMU_IPLMASK; - mask = IPLEMU_SETRESET|IPLEMU_DISABLEINT|level; - level ^= 7; - - /* Save previous IPL value */ - if (last_ipl[level]) - return -2; - last_ipl[level] = ipl_emu; - - /* Set to current IPL value */ - APUS_WRITE(APUS_IPL_EMU, mask); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|level); - - -#ifdef __INTERRUPT_DEBUG - printk("<%d:%d>", level, ~ipl_emu & IPLEMU_IPLMASK); -#endif - return level + IRQ_AMIGA_AUTO; -} - -void apus_end_irq(unsigned int irq) -{ - unsigned char ipl_emu; - unsigned int level = irq - IRQ_AMIGA_AUTO; -#ifdef __INTERRUPT_DEBUG - printk("{%d}", ~last_ipl[level] & IPLEMU_IPLMASK); -#endif - /* Restore IPL to the previous value */ - ipl_emu = last_ipl[level] & IPLEMU_IPLMASK; - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET|IPLEMU_DISABLEINT|ipl_emu); - last_ipl[level] = 0; - ipl_emu ^= 7; - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|ipl_emu); -} - -/****************************************************** debugging */ - -/* some serial hardware definitions */ -#define SDR_OVRUN (1<<15) -#define SDR_RBF (1<<14) -#define SDR_TBE (1<<13) -#define SDR_TSRE (1<<12) - -#define AC_SETCLR (1<<15) -#define AC_UARTBRK (1<<11) - -#define SER_DTR (1<<7) -#define SER_RTS (1<<6) -#define SER_DCD (1<<5) -#define SER_CTS (1<<4) -#define SER_DSR (1<<3) - -static __inline__ void ser_RTSon(void) -{ - ciab.pra &= ~SER_RTS; /* active low */ -} - -int __debug_ser_out( unsigned char c ) -{ - amiga_custom.serdat = c | 0x100; - mb(); - while (!(amiga_custom.serdatr & 0x2000)) - barrier(); - return 1; -} - -unsigned char __debug_ser_in( void ) -{ - unsigned char c; - - /* XXX: is that ok?? derived from amiga_ser.c... */ - while( !(amiga_custom.intreqr & IF_RBF) ) - barrier(); - c = amiga_custom.serdatr; - /* clear the interrupt, so that another character can be read */ - amiga_custom.intreq = IF_RBF; - return c; -} - -int __debug_serinit( void ) -{ - unsigned long flags; - - local_irq_save(flags); - - /* turn off Rx and Tx interrupts */ - amiga_custom.intena = IF_RBF | IF_TBE; - - /* clear any pending interrupt */ - amiga_custom.intreq = IF_RBF | IF_TBE; - - local_irq_restore(flags); - - /* - * set the appropriate directions for the modem control flags, - * and clear RTS and DTR - */ - ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ - ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ - -#ifdef CONFIG_KGDB - /* turn Rx interrupts on for GDB */ - amiga_custom.intena = IF_SETCLR | IF_RBF; - ser_RTSon(); -#endif - - return 0; -} - -void __debug_print_hex(unsigned long x) -{ - int i; - char hexchars[] = "0123456789ABCDEF"; - - for (i = 0; i < 8; i++) { - __debug_ser_out(hexchars[(x >> 28) & 15]); - x <<= 4; - } - __debug_ser_out('\n'); - __debug_ser_out('\r'); -} - -void __debug_print_string(char* s) -{ - unsigned char c; - while((c = *s++)) - __debug_ser_out(c); - __debug_ser_out('\n'); - __debug_ser_out('\r'); -} - -static void apus_progress(char *s, unsigned short value) -{ - __debug_print_string(s); -} - -/****************************************************** init */ - -/* The number of spurious interrupts */ -volatile unsigned int num_spurious; - -extern struct irqaction amiga_sys_irqaction[AUTO_IRQS]; - - -extern void amiga_enable_irq(unsigned int irq); -extern void amiga_disable_irq(unsigned int irq); - -struct hw_interrupt_type amiga_sys_irqctrl = { - .typename = "Amiga IPL", - .end = apus_end_irq, -}; - -struct hw_interrupt_type amiga_irqctrl = { - .typename = "Amiga ", - .enable = amiga_enable_irq, - .disable = amiga_disable_irq, -}; - -#define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init apus_find_end_of_memory(void) -{ - int shadow = 0; - unsigned long total; - - /* The memory size reported by ADOS excludes the 512KB - reserved for PPC exception registers and possibly 512KB - containing a shadow of the ADOS ROM. */ - { - unsigned long size = memory[0].size; - - /* If 2MB aligned, size was probably user - specified. We can't tell anything about shadowing - in this case so skip shadow assignment. */ - if (0 != (size & 0x1fffff)){ - /* Align to 512KB to ensure correct handling - of both memfile and system specified - sizes. */ - size = ((size+0x0007ffff) & 0xfff80000); - /* If memory is 1MB aligned, assume - shadowing. */ - shadow = !(size & 0x80000); - } - - /* Add the chunk that ADOS does not see. by aligning - the size to the nearest 2MB limit upwards. */ - memory[0].size = ((size+0x001fffff) & 0xffe00000); - } - - ppc_memstart = memory[0].addr; - ppc_memoffset = PAGE_OFFSET - PPC_MEMSTART; - total = memory[0].size; - - /* Remove the memory chunks that are controlled by special - Phase5 hardware. */ - - /* Remove the upper 512KB if it contains a shadow of - the ADOS ROM. FIXME: It might be possible to - disable this shadow HW. Check the booter - (ppc_boot.c) */ - if (shadow) - total -= HARDWARE_MAPPED_SIZE; - - /* Remove the upper 512KB where the PPC exception - vectors are mapped. */ - total -= HARDWARE_MAPPED_SIZE; - - /* Linux/APUS only handles one block of memory -- the one on - the PowerUP board. Other system memory is horrible slow in - comparison. The user can use other memory for swapping - using the z2ram device. */ - return total; -} - -static void __init -apus_map_io(void) -{ - /* Map PPC exception vectors. */ - io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL); - /* Map chip and ZorroII memory */ - io_block_mapping(zTwoBase, 0x00000000, 0x01000000, _PAGE_IO); -} - -__init -void apus_init_IRQ(void) -{ - struct irqaction *action; - int i; - -#ifdef CONFIG_PCI - apus_setup_pci_ptrs(); -#endif - - for ( i = 0 ; i < AMI_IRQS; i++ ) { - irq_desc[i].status = IRQ_LEVEL; - if (i < IRQ_AMIGA_AUTO) { - irq_desc[i].chip = &amiga_irqctrl; - } else { - irq_desc[i].chip = &amiga_sys_irqctrl; - action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO]; - if (action->name) - setup_irq(i, action); - } - } - - amiga_init_IRQ(); - -} - -__init -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - extern int parse_bootinfo(const struct bi_record *); - extern char _end[]; - - /* Parse bootinfo. The bootinfo is located right after - the kernel bss */ - parse_bootinfo((const struct bi_record *)&_end); -#ifdef CONFIG_BLK_DEV_INITRD - /* Take care of initrd if we have one. Use data from - bootinfo to avoid the need to initialize PPC - registers when kernel is booted via a PPC reset. */ - if ( ramdisk.addr ) { - initrd_start = (unsigned long) __va(ramdisk.addr); - initrd_end = (unsigned long) - __va(ramdisk.size + ramdisk.addr); - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - ISA_DMA_THRESHOLD = 0x00ffffff; - - ppc_md.setup_arch = apus_setup_arch; - ppc_md.show_cpuinfo = apus_show_cpuinfo; - ppc_md.init_IRQ = apus_init_IRQ; - ppc_md.get_irq = apus_get_irq; - -#ifdef CONFIG_HEARTBEAT - ppc_md.heartbeat = apus_heartbeat; - ppc_md.heartbeat_count = 1; -#endif -#ifdef APUS_DEBUG - __debug_serinit(); - ppc_md.progress = apus_progress; -#endif - ppc_md.init = NULL; - - ppc_md.restart = apus_restart; - ppc_md.power_off = apus_power_off; - ppc_md.halt = apus_halt; - - ppc_md.time_init = NULL; - ppc_md.set_rtc_time = apus_set_rtc_time; - ppc_md.get_rtc_time = apus_get_rtc_time; - ppc_md.calibrate_decr = apus_calibrate_decr; - - ppc_md.find_end_of_memory = apus_find_end_of_memory; - ppc_md.setup_io_mappings = apus_map_io; -} diff --git a/include/asm-powerpc/ide.h b/include/asm-powerpc/ide.h index 0f66f0f82c32..1644e44c8757 100644 --- a/include/asm-powerpc/ide.h +++ b/include/asm-powerpc/ide.h @@ -67,7 +67,7 @@ static __inline__ unsigned long ide_default_io_base(int index) #define ide_init_default_irq(base) ide_default_irq(base) #endif -#if (defined CONFIG_APUS || defined CONFIG_BLK_DEV_MPC8xx_IDE ) +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE #define IDE_ARCH_ACK_INTR 1 #define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1) #endif diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 347de53e49af..e775ff1ca413 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -102,12 +102,8 @@ #else /* 32-bit */ /* Default MSR for kernel mode. */ #ifndef MSR_KERNEL /* reg_booke.h also defines this */ -#ifdef CONFIG_APUS_FAST_EXCEPT -#define MSR_KERNEL (MSR_ME|MSR_IP|MSR_RI|MSR_IR|MSR_DR) -#else #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR) #endif -#endif #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) #endif diff --git a/include/asm-ppc/amigahw.h b/include/asm-ppc/amigahw.h deleted file mode 100644 index 90fd1274d727..000000000000 --- a/include/asm-ppc/amigahw.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifdef __KERNEL__ -#ifndef __ASMPPC_AMIGAHW_H -#define __ASMPPC_AMIGAHW_H - -#include - -#undef CHIP_PHYSADDR -#ifdef CONFIG_APUS_FAST_EXCEPT -#define CHIP_PHYSADDR (0x000000) -#else -#define CHIP_PHYSADDR (0x004000) -#endif - - -#endif /* __ASMPPC_AMIGAHW_H */ -#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/amigaints.h b/include/asm-ppc/amigaints.h deleted file mode 100644 index aa3ff6349e81..000000000000 --- a/include/asm-ppc/amigaints.h +++ /dev/null @@ -1,133 +0,0 @@ -/* -** amigaints.h -- Amiga Linux interrupt handling structs and prototypes -** -** Copyright 1992 by Greg Harp -** -** 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. -** -** Created 10/2/92 by Greg Harp -*/ - -#ifdef __KERNEL__ -#ifndef _ASMm68k_AMIGAINTS_H_ -#define _ASMm68k_AMIGAINTS_H_ - -/* -** Amiga Interrupt sources. -** -*/ - -#define AUTO_IRQS (8) -#define AMI_STD_IRQS (14) -#define CIA_IRQS (5) -#define AMI_IRQS (32) /* AUTO_IRQS+AMI_STD_IRQS+2*CIA_IRQS */ - -/* vertical blanking interrupt */ -#define IRQ_AMIGA_VERTB 0 - -/* copper interrupt */ -#define IRQ_AMIGA_COPPER 1 - -/* Audio interrupts */ -#define IRQ_AMIGA_AUD0 2 -#define IRQ_AMIGA_AUD1 3 -#define IRQ_AMIGA_AUD2 4 -#define IRQ_AMIGA_AUD3 5 - -/* Blitter done interrupt */ -#define IRQ_AMIGA_BLIT 6 - -/* floppy disk interrupts */ -#define IRQ_AMIGA_DSKSYN 7 -#define IRQ_AMIGA_DSKBLK 8 - -/* builtin serial port interrupts */ -#define IRQ_AMIGA_RBF 9 -#define IRQ_AMIGA_TBE 10 - -/* software interrupts */ -#define IRQ_AMIGA_SOFT 11 - -/* interrupts from external hardware */ -#define IRQ_AMIGA_PORTS 12 -#define IRQ_AMIGA_EXTER 13 - -/* CIA interrupt sources */ -#define IRQ_AMIGA_CIAA 14 -#define IRQ_AMIGA_CIAA_TA 14 -#define IRQ_AMIGA_CIAA_TB 15 -#define IRQ_AMIGA_CIAA_ALRM 16 -#define IRQ_AMIGA_CIAA_SP 17 -#define IRQ_AMIGA_CIAA_FLG 18 -#define IRQ_AMIGA_CIAB 19 -#define IRQ_AMIGA_CIAB_TA 19 -#define IRQ_AMIGA_CIAB_TB 20 -#define IRQ_AMIGA_CIAB_ALRM 21 -#define IRQ_AMIGA_CIAB_SP 22 -#define IRQ_AMIGA_CIAB_FLG 23 - -/* auto-vector interrupts */ -#define IRQ_AMIGA_AUTO 24 -#define IRQ_AMIGA_AUTO_0 24 /* This is just a dummy */ -#define IRQ_AMIGA_AUTO_1 25 -#define IRQ_AMIGA_AUTO_2 26 -#define IRQ_AMIGA_AUTO_3 27 -#define IRQ_AMIGA_AUTO_4 28 -#define IRQ_AMIGA_AUTO_5 29 -#define IRQ_AMIGA_AUTO_6 30 -#define IRQ_AMIGA_AUTO_7 31 - -#define IRQ_FLOPPY IRQ_AMIGA_DSKBLK - -/* INTREQR masks */ -#define IRQ1_MASK 0x0007 /* INTREQR mask for IRQ 1 */ -#define IRQ2_MASK 0x0008 /* INTREQR mask for IRQ 2 */ -#define IRQ3_MASK 0x0070 /* INTREQR mask for IRQ 3 */ -#define IRQ4_MASK 0x0780 /* INTREQR mask for IRQ 4 */ -#define IRQ5_MASK 0x1800 /* INTREQR mask for IRQ 5 */ -#define IRQ6_MASK 0x2000 /* INTREQR mask for IRQ 6 */ -#define IRQ7_MASK 0x4000 /* INTREQR mask for IRQ 7 */ - -#define IF_SETCLR 0x8000 /* set/clr bit */ -#define IF_INTEN 0x4000 /* master interrupt bit in INT* registers */ -#define IF_EXTER 0x2000 /* external level 6 and CIA B interrupt */ -#define IF_DSKSYN 0x1000 /* disk sync interrupt */ -#define IF_RBF 0x0800 /* serial receive buffer full interrupt */ -#define IF_AUD3 0x0400 /* audio channel 3 done interrupt */ -#define IF_AUD2 0x0200 /* audio channel 2 done interrupt */ -#define IF_AUD1 0x0100 /* audio channel 1 done interrupt */ -#define IF_AUD0 0x0080 /* audio channel 0 done interrupt */ -#define IF_BLIT 0x0040 /* blitter done interrupt */ -#define IF_VERTB 0x0020 /* vertical blanking interrupt */ -#define IF_COPER 0x0010 /* copper interrupt */ -#define IF_PORTS 0x0008 /* external level 2 and CIA A interrupt */ -#define IF_SOFT 0x0004 /* software initiated interrupt */ -#define IF_DSKBLK 0x0002 /* diskblock DMA finished */ -#define IF_TBE 0x0001 /* serial transmit buffer empty interrupt */ - -extern void amiga_do_irq(int irq, struct pt_regs *fp); -extern void amiga_do_irq_list(int irq, struct pt_regs *fp); - -/* CIA interrupt control register bits */ - -#define CIA_ICR_TA 0x01 -#define CIA_ICR_TB 0x02 -#define CIA_ICR_ALRM 0x04 -#define CIA_ICR_SP 0x08 -#define CIA_ICR_FLG 0x10 -#define CIA_ICR_ALL 0x1f -#define CIA_ICR_SETCLR 0x80 - -/* to access the interrupt control registers of CIA's use only -** these functions, they behave exactly like the amiga os routines -*/ - -extern struct ciabase ciaa_base, ciab_base; - -extern unsigned char cia_set_irq(unsigned int irq, int set); -extern unsigned char cia_able_irq(unsigned int irq, int enable); - -#endif /* asm-m68k/amigaints.h */ -#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/amigappc.h b/include/asm-ppc/amigappc.h deleted file mode 100644 index 35114ce5135f..000000000000 --- a/include/asm-ppc/amigappc.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -** asm-ppc/amigappc.h -- This header defines some values and pointers for -** the Phase 5 PowerUp card. -** -** Copyright 1997, 1998 by Phase5, Germany. -** -** 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. -** -** Created: 7/22/97 by Jesper Skov -*/ - -#ifdef __KERNEL__ -#ifndef _M68K_AMIGAPPC_H -#define _M68K_AMIGAPPC_H - -#ifndef __ASSEMBLY__ - -/* #include */ -#define mb() __asm__ __volatile__ ("sync" : : : "memory") - -#define APUS_WRITE(_a_, _v_) \ -do { \ - (*((volatile unsigned char *)(_a_)) = (_v_)); \ - mb(); \ -} while (0) - -#define APUS_READ(_a_, _v_) \ -do { \ - (_v_) = (*((volatile unsigned char *)(_a_))); \ - mb(); \ -} while (0) -#endif /* ndef __ASSEMBLY__ */ - -/* Maybe add a [#ifdef WANT_ZTWOBASE] condition to amigahw.h? */ -#define zTwoBase (0x80000000) - -#define APUS_IPL_BASE (zTwoBase + 0x00f60000) -#define APUS_REG_RESET (APUS_IPL_BASE + 0x00) -#define APUS_REG_WAITSTATE (APUS_IPL_BASE + 0x10) -#define APUS_REG_SHADOW (APUS_IPL_BASE + 0x18) -#define APUS_REG_LOCK (APUS_IPL_BASE + 0x20) -#define APUS_REG_INT (APUS_IPL_BASE + 0x28) -#define APUS_IPL_EMU (APUS_IPL_BASE + 0x30) -#define APUS_INT_LVL (APUS_IPL_BASE + 0x38) - -#define REGSHADOW_SETRESET (0x80) -#define REGSHADOW_SELFRESET (0x40) - -#define REGLOCK_SETRESET (0x80) -#define REGLOCK_BLACKMAGICK1 (0x40) -#define REGLOCK_BLACKMAGICK2 (0x20) -#define REGLOCK_BLACKMAGICK3 (0x10) - -#define REGWAITSTATE_SETRESET (0x80) -#define REGWAITSTATE_PPCW (0x08) -#define REGWAITSTATE_PPCR (0x04) - -#define REGRESET_SETRESET (0x80) -#define REGRESET_PPCRESET (0x10) -#define REGRESET_M68KRESET (0x08) -#define REGRESET_AMIGARESET (0x04) -#define REGRESET_AUXRESET (0x02) -#define REGRESET_SCSIRESET (0x01) - -#define REGINT_SETRESET (0x80) -#define REGINT_ENABLEIPL (0x02) -#define REGINT_INTMASTER (0x01) - -#define IPLEMU_SETRESET (0x80) -#define IPLEMU_DISABLEINT (0x40) -#define IPLEMU_IPL2 (0x20) -#define IPLEMU_IPL1 (0x10) -#define IPLEMU_IPL0 (0x08) -#define IPLEMU_PPCIPL2 (0x04) -#define IPLEMU_PPCIPL1 (0x02) -#define IPLEMU_PPCIPL0 (0x01) -#define IPLEMU_IPLMASK (IPLEMU_PPCIPL2|IPLEMU_PPCIPL1|IPLEMU_PPCIPL0) - -#define INTLVL_SETRESET (0x80) -#define INTLVL_MASK (0x7f) - -#endif /* _M68k_AMIGAPPC_H */ -#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/bootinfo.h b/include/asm-ppc/bootinfo.h index 2ace4a74f263..f6ed77aee328 100644 --- a/include/asm-ppc/bootinfo.h +++ b/include/asm-ppc/bootinfo.h @@ -11,10 +11,6 @@ #include -#if defined(CONFIG_APUS) && !defined(__BOOTER__) -#include -#else - struct bi_record { unsigned long tag; /* tag ID */ unsigned long size; /* size of record (in bytes) */ @@ -44,7 +40,6 @@ bootinfo_addr(unsigned long offset) return (struct bi_record *)_ALIGN((offset) + (1 << 20) - 1, (1 << 20)); } -#endif /* CONFIG_APUS */ #endif /* _PPC_BOOTINFO_H */ diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index f776c49f5579..8f58231a8bc6 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -30,7 +30,7 @@ #include #elif defined(CONFIG_8260) #include -#elif defined(CONFIG_APUS) || !defined(CONFIG_PCI) +#elif !defined(CONFIG_PCI) #define _IO_BASE 0 #define _ISA_MEM_BASE 0 #define PCI_DRAM_OFFSET 0 @@ -145,24 +145,7 @@ static inline void writeb(__u8 b, volatile void __iomem *addr) } #endif -#if defined(CONFIG_APUS) -static inline __u16 readw(const volatile void __iomem *addr) -{ - return *(__force volatile __u16 *)(addr); -} -static inline __u32 readl(const volatile void __iomem *addr) -{ - return *(__force volatile __u32 *)(addr); -} -static inline void writew(__u16 b, volatile void __iomem *addr) -{ - *(__force volatile __u16 *)(addr) = b; -} -static inline void writel(__u32 b, volatile void __iomem *addr) -{ - *(__force volatile __u32 *)(addr) = b; -} -#elif defined (CONFIG_8260_PCI9) +#if defined (CONFIG_8260_PCI9) /* Use macros if PCI9 workaround enabled */ #define readw(addr) in_le16((volatile u16 *)(addr)) #define readl(addr) in_le32((volatile u32 *)(addr)) @@ -185,7 +168,7 @@ static inline void writel(__u32 b, volatile void __iomem *addr) { out_le32(addr, b); } -#endif /* CONFIG_APUS */ +#endif /* CONFIG_8260_PCI9 */ #define readb_relaxed(addr) readb(addr) #define readw_relaxed(addr) readw(addr) @@ -300,13 +283,7 @@ extern __inline__ void name(unsigned int val, unsigned int port) \ } __do_out_asm(outb, "stbx") -#ifdef CONFIG_APUS -__do_in_asm(inb, "lbzx") -__do_in_asm(inw, "lhz%U1%X1") -__do_in_asm(inl, "lwz%U1%X1") -__do_out_asm(outl,"stw%U0%X0") -__do_out_asm(outw, "sth%U0%X0") -#elif defined (CONFIG_8260_PCI9) +#if defined (CONFIG_8260_PCI9) /* in asm cannot be defined if PCI9 workaround is used */ #define inb(port) in_8((port)+___IO_BASE) #define inw(port) in_le16((port)+___IO_BASE) @@ -371,7 +348,6 @@ extern void __iomem *ioremap64(unsigned long long address, unsigned long size); #define ioremap_nocache(addr, size) ioremap((addr), (size)) extern void iounmap(volatile void __iomem *addr); extern unsigned long iopa(unsigned long addr); -extern unsigned long mm_ptov(unsigned long addr) __attribute_const__; extern void io_block_mapping(unsigned long virt, phys_addr_t phys, unsigned int size, int flags); @@ -384,24 +360,16 @@ extern void io_block_mapping(unsigned long virt, phys_addr_t phys, */ extern inline unsigned long virt_to_bus(volatile void * address) { -#ifndef CONFIG_APUS if (address == (void *)0) return 0; return (unsigned long)address - KERNELBASE + PCI_DRAM_OFFSET; -#else - return iopa ((unsigned long) address); -#endif } extern inline void * bus_to_virt(unsigned long address) { -#ifndef CONFIG_APUS if (address == 0) return NULL; return (void *)(address - PCI_DRAM_OFFSET + KERNELBASE); -#else - return (void*) mm_ptov (address); -#endif } /* @@ -410,20 +378,12 @@ extern inline void * bus_to_virt(unsigned long address) */ extern inline unsigned long virt_to_phys(volatile void * address) { -#ifndef CONFIG_APUS return (unsigned long) address - KERNELBASE; -#else - return iopa ((unsigned long) address); -#endif } extern inline void * phys_to_virt(unsigned long address) { -#ifndef CONFIG_APUS return (void *) (address + KERNELBASE); -#else - return (void*) mm_ptov (address); -#endif } /* diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index 293a444a1d77..a20b499b0186 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -8,10 +8,6 @@ #include #include -#ifdef CONFIG_APUS -#include -#endif - struct pt_regs; struct pci_bus; struct pci_dev; diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index fe95c8258cf9..ad4c5a1bc9d6 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -97,62 +97,22 @@ extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg); extern void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *pg); -#ifndef CONFIG_APUS #define PPC_MEMSTART 0 -#define PPC_PGSTART 0 #define PPC_MEMOFFSET PAGE_OFFSET -#else -extern unsigned long ppc_memstart; -extern unsigned long ppc_pgstart; -extern unsigned long ppc_memoffset; -#define PPC_MEMSTART ppc_memstart -#define PPC_PGSTART ppc_pgstart -#define PPC_MEMOFFSET ppc_memoffset -#endif -#if defined(CONFIG_APUS) && !defined(MODULE) -/* map phys->virtual and virtual->phys for RAM pages */ -static inline unsigned long ___pa(unsigned long v) -{ - unsigned long p; - asm volatile ("1: addis %0, %1, %2;" - ".section \".vtop_fixup\",\"aw\";" - ".align 1;" - ".long 1b;" - ".previous;" - : "=r" (p) - : "b" (v), "K" (((-PAGE_OFFSET) >> 16) & 0xffff)); - - return p; -} -static inline void* ___va(unsigned long p) -{ - unsigned long v; - asm volatile ("1: addis %0, %1, %2;" - ".section \".ptov_fixup\",\"aw\";" - ".align 1;" - ".long 1b;" - ".previous;" - : "=r" (v) - : "b" (p), "K" (((PAGE_OFFSET) >> 16) & 0xffff)); - - return (void*) v; -} -#else #define ___pa(vaddr) ((vaddr)-PPC_MEMOFFSET) #define ___va(paddr) ((paddr)+PPC_MEMOFFSET) -#endif extern int page_is_ram(unsigned long pfn); #define __pa(x) ___pa((unsigned long)(x)) #define __va(x) ((void *)(___va((unsigned long)(x)))) -#define ARCH_PFN_OFFSET (PPC_PGSTART) +#define ARCH_PFN_OFFSET 0 #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) -#define pfn_valid(pfn) (((pfn) - PPC_PGSTART) < max_mapnr) +#define pfn_valid(pfn) ((pfn) < max_mapnr) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) /* Pure 2^n version of get_order */ diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index c159315d2c8f..063ad91cbbcc 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -765,14 +765,6 @@ extern void paging_init(void); #define pte_to_pgoff(pte) (pte_val(pte) >> 3) #define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE }) -/* CONFIG_APUS */ -/* For virtual address to physical address conversion */ -extern void cache_clear(__u32 addr, int length); -extern void cache_push(__u32 addr, int length); -extern int mm_end_of_chunk (unsigned long addr, int len); -extern unsigned long iopa(unsigned long addr); -extern unsigned long mm_ptov(unsigned long addr) __attribute_const__; - /* Values for nocacheflag and cmode */ /* These are not used by the APUS kernel_map, but prevents compilation errors. */ From 61a564fd2e7ab13ab11a6ce8305433baacf344ef Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 09:45:08 +1000 Subject: [PATCH 0228/2804] [POWERPC] Don't cast kmalloc return value in ibmebus.c kmalloc() returns a void pointer so there is absolutely no need to cast it in ibmebus_chomp(). Signed-off-by: Jesper Juhl Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ibmebus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index d6a38cd5018e..7697d5b8296e 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -371,7 +371,8 @@ static int ibmebus_match_path(struct device *dev, void *data) static char *ibmebus_chomp(const char *in, size_t count) { - char *out = (char*)kmalloc(count + 1, GFP_KERNEL); + char *out = kmalloc(count + 1, GFP_KERNEL); + if (!out) return NULL; From 00efee7d5d0d7888aafbf0d2de76943ee8aca47a Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 24 Aug 2007 16:58:37 +1000 Subject: [PATCH 0229/2804] [POWERPC] Remove barriers from the SLB shadow buffer update After talking to an IBM POWER hypervisor (PHYP) design and development guy, there seems to be no need for memory barriers when updating the SLB shadow buffer provided we only update it from the current CPU, which we do. Also, these guys see no need in the future for these barriers. Signed-off-by: Michael Neuling Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/entry_64.S | 8 ++++---- arch/powerpc/mm/slb.c | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 952eba6701f4..fbbd3f6f0064 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -385,15 +385,15 @@ BEGIN_FTR_SECTION oris r0,r6,(SLB_ESID_V)@h ori r0,r0,(SLB_NUM_BOLTED-1)@l - /* Update the last bolted SLB */ + /* Update the last bolted SLB. No write barriers are needed + * here, provided we only update the current CPU's SLB shadow + * buffer. + */ ld r9,PACA_SLBSHADOWPTR(r13) li r12,0 std r12,SLBSHADOW_STACKESID(r9) /* Clear ESID */ - eieio std r7,SLBSHADOW_STACKVSID(r9) /* Save VSID */ - eieio std r0,SLBSHADOW_STACKESID(r9) /* Save ESID */ - eieio slbie r6 slbie r6 /* Workaround POWER5 < DD2.1 issue */ diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index ff1811ac6c81..4bee1cfa9dea 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -59,14 +59,12 @@ static inline void slb_shadow_update(unsigned long ea, { /* * Clear the ESID first so the entry is not valid while we are - * updating it. + * updating it. No write barriers are needed here, provided + * we only update the current CPU's SLB shadow buffer. */ get_slb_shadow()->save_area[entry].esid = 0; - smp_wmb(); get_slb_shadow()->save_area[entry].vsid = mk_vsid_data(ea, flags); - smp_wmb(); get_slb_shadow()->save_area[entry].esid = mk_esid_data(ea, entry); - smp_wmb(); } static inline void slb_shadow_clear(unsigned long entry) From aa0154290fc05948560ac43afcccf8259e10bcd0 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sun, 26 Aug 2007 19:10:59 +1000 Subject: [PATCH 0230/2804] [POWERPC] Fix pmac_zilog debug arg drivers/serial/pmac_zilog.c:1590: warning: format '%d' expects type 'int', but argument 3 has type 'pm_message_t' Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras --- drivers/serial/pmac_zilog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 0fa9f6761763..f793ac212672 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -1587,7 +1587,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) if (pm_state.event == mdev->ofdev.dev.power.power_state.event) return 0; - pmz_debug("suspend, switching to state %d\n", pm_state); + pmz_debug("suspend, switching to state %d\n", pm_state.event); state = pmz_uart_reg.state + uap->port.line; From 1238819a41b6e38e1560afe8f33bbc815671b4f7 Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0231/2804] [POWERPC] spufs: Make file-internal functions & variables static There are a few symbols used only in one file within spufs; this change makes them static where suitable. Signed-off-by: Sebastian Siewior Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 2 +- arch/powerpc/platforms/cell/spu_callbacks.c | 2 +- arch/powerpc/platforms/cell/spufs/file.c | 6 +++--- arch/powerpc/platforms/cell/spufs/run.c | 4 ++-- arch/powerpc/platforms/cell/spufs/syscalls.c | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 106d2921e2d9..b5a21177bb32 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -458,7 +458,7 @@ static int spu_shutdown(struct sys_device *sysdev) return 0; } -struct sysdev_class spu_sysdev_class = { +static struct sysdev_class spu_sysdev_class = { set_kset_name("spu"), .shutdown = spu_shutdown, }; diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index 47ec3be3edcd..ab39e223d44d 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -33,7 +33,7 @@ * mbind, mq_open, ipc, ... */ -void *spu_syscall_table[] = { +static void *spu_syscall_table[] = { #define SYSCALL(func) sys_ni_syscall, #define COMPAT_SYS(func) sys_ni_syscall, #define PPC_SYS(func) sys_ni_syscall, diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 4100ddc52f02..a4a8770623d4 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -199,9 +199,9 @@ static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) } #ifdef CONFIG_SPU_FS_64K_LS -unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, - unsigned long flags) +static unsigned long spufs_get_unmapped_area(struct file *file, + unsigned long addr, unsigned long len, unsigned long pgoff, + unsigned long flags) { struct spu_context *ctx = file->private_data; struct spu_state *csa = &ctx->csa; diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 958f10e90fdd..1ce5e22ea5f4 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -205,7 +205,7 @@ static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, * This means we can only do a very rough approximation of POSIX * signal semantics. */ -int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, +static int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, unsigned int *npc) { int ret; @@ -241,7 +241,7 @@ int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, return ret; } -int spu_process_callback(struct spu_context *ctx) +static int spu_process_callback(struct spu_context *ctx) { struct spu_syscall_block s; u32 ls_pointer, npc; diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 43f0fb88abbc..3d8c3281c768 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -76,8 +76,8 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) } #endif -asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags, - mode_t mode, struct file *neighbor) +static asmlinkage long do_spu_create(const char __user *pathname, + unsigned int flags, mode_t mode, struct file *neighbor) { char *tmp; int ret; From 1e8b0f6d1b4dd5fafe732a24dfcb9ac9fd27cf08 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0232/2804] [POWERPC] spufs: Remove asmlinkage from do_spu_create do_spu_create doesn't need the asmlinkage qualifier; remove it. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/syscalls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 3d8c3281c768..936e0a8af3a9 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -76,8 +76,8 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) } #endif -static asmlinkage long do_spu_create(const char __user *pathname, - unsigned int flags, mode_t mode, struct file *neighbor) +static long do_spu_create(const char __user *pathname, unsigned int flags, + mode_t mode, struct file *neighbor) { char *tmp; int ret; From 6232a74f25f45a98d8cf64c5d4208f4795eb693d Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0233/2804] [POWERPC] spufs: Remove spu_harvest Based on an initial patch from Sebastian Siewior spu_harvest isn't used, remove it. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/switch.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 27ffdae98e5a..250661991503 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -2146,19 +2146,6 @@ int spu_restore(struct spu_state *new, struct spu *spu) } EXPORT_SYMBOL_GPL(spu_restore); -/** - * spu_harvest - SPU harvest (reset) operation - * @spu: pointer to SPU iomem structure. - * - * Perform SPU harvest (reset) operation. - */ -void spu_harvest(struct spu *spu) -{ - acquire_spu_lock(spu); - harvest(NULL, spu); - release_spu_lock(spu); -} - static void init_prob(struct spu_state *csa) { csa->spu_chnlcnt_RW[9] = 1; From 8b0d3121a0b2cf91768ecef635e241b6abc3f1da Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0234/2804] [POWERPC] spufs: Make isolated loader properly aligned According to the comment in spufs_init_isolated_loader(), the isolated loader should be aligned on a 16 byte boundary. ARCH_{KMALLOC,SLAB}_MINALIGN is not defined so only 8 byte alignment is guaranteed. This enforces alignment via __get_free_pages. Signed-off-by: Sebastian Siewior Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index b3d0dd118dd0..e210a4b259fb 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -43,6 +43,7 @@ static struct kmem_cache *spufs_inode_cache; char *isolated_loader; +static int isolated_loader_size; static struct inode * spufs_alloc_inode(struct super_block *sb) @@ -667,7 +668,8 @@ spufs_parse_options(char *options, struct inode *root) static void spufs_exit_isolated_loader(void) { - kfree(isolated_loader); + free_pages((unsigned long) isolated_loader, + get_order(isolated_loader_size)); } static void @@ -685,11 +687,12 @@ spufs_init_isolated_loader(void) if (!loader) return; - /* kmalloc should align on a 16 byte boundary..* */ - isolated_loader = kmalloc(size, GFP_KERNEL); + /* the loader must be align on a 16 byte boundary */ + isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size)); if (!isolated_loader) return; + isolated_loader_size = size; memcpy(isolated_loader, loader, size); printk(KERN_INFO "spufs: SPU isolation mode enabled\n"); } From 36ddbb1380f282b4280c57efdb646dd8647a789f Mon Sep 17 00:00:00 2001 From: Andre Detsch Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0235/2804] [POWERPC] spufs: Fix race condition on gang->aff_ref_spu Affinity reference point location (gang->aff_ref_spu) is reset when the whole gang is descheduled. However, the last member of a gang can be descheduled while we are trying to schedule another member of the gang. This was leading to a race condition, and the code was using gang->aff_ref_spu in an unsafe manner. By holding the gang->aff_mutex a little bit longer, and increment gang->aff_sched_count (which controls when gang->aff_ref_spu should be reset) a little bit earlier, the problem is fixed. Signed-off-by: Andre Detsch Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 49 +++++++++++++++-------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index c784edd40ea7..17806e001e50 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -230,8 +230,6 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) if (ctx->flags & SPU_CREATE_NOSCHED) atomic_inc(&cbe_spu_info[spu->node].reserved_spus); - if (!list_empty(&ctx->aff_list)) - atomic_inc(&ctx->gang->aff_sched_count); ctx->stats.slb_flt_base = spu->stats.slb_flt; ctx->stats.class2_intr_base = spu->stats.class2_intr; @@ -392,7 +390,6 @@ static int has_affinity(struct spu_context *ctx) if (list_empty(&ctx->aff_list)) return 0; - mutex_lock(&gang->aff_mutex); if (!gang->aff_ref_spu) { if (!(gang->aff_flags & AFF_MERGED)) aff_merge_remaining_ctxs(gang); @@ -400,7 +397,6 @@ static int has_affinity(struct spu_context *ctx) aff_set_offsets(gang); aff_set_ref_point_location(gang); } - mutex_unlock(&gang->aff_mutex); return gang->aff_ref_spu != NULL; } @@ -418,9 +414,16 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) if (spu->ctx->flags & SPU_CREATE_NOSCHED) atomic_dec(&cbe_spu_info[spu->node].reserved_spus); - if (!list_empty(&ctx->aff_list)) - if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) - ctx->gang->aff_ref_spu = NULL; + + if (ctx->gang){ + mutex_lock(&ctx->gang->aff_mutex); + if (has_affinity(ctx)) { + if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) + ctx->gang->aff_ref_spu = NULL; + } + mutex_unlock(&ctx->gang->aff_mutex); + } + spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); @@ -511,20 +514,32 @@ static void spu_prio_wait(struct spu_context *ctx) static struct spu *spu_get_idle(struct spu_context *ctx) { - struct spu *spu; + struct spu *spu, *aff_ref_spu; int node, n; - if (has_affinity(ctx)) { - node = ctx->gang->aff_ref_spu->node; + if (ctx->gang) { + mutex_lock(&ctx->gang->aff_mutex); + if (has_affinity(ctx)) { + aff_ref_spu = ctx->gang->aff_ref_spu; + atomic_inc(&ctx->gang->aff_sched_count); + mutex_unlock(&ctx->gang->aff_mutex); + node = aff_ref_spu->node; - mutex_lock(&cbe_spu_info[node].list_mutex); - spu = ctx_location(ctx->gang->aff_ref_spu, ctx->aff_offset, node); - if (spu && spu->alloc_state == SPU_FREE) - goto found; - mutex_unlock(&cbe_spu_info[node].list_mutex); - return NULL; + mutex_lock(&cbe_spu_info[node].list_mutex); + spu = ctx_location(aff_ref_spu, ctx->aff_offset, node); + if (spu && spu->alloc_state == SPU_FREE) + goto found; + mutex_unlock(&cbe_spu_info[node].list_mutex); + + mutex_lock(&ctx->gang->aff_mutex); + if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) + ctx->gang->aff_ref_spu = NULL; + mutex_unlock(&ctx->gang->aff_mutex); + + return NULL; + } + mutex_unlock(&ctx->gang->aff_mutex); } - node = cpu_to_node(raw_smp_processor_id()); for (n = 0; n < MAX_NUMNODES; n++, node++) { node = (node < MAX_NUMNODES) ? node : 0; From 98f06978ffebbec16abdea58489f217229580859 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0236/2804] [POWERPC] cell: Unify spufs syscall path At present, a built-in spufs will not use the spufs_calls callbacks, but directly call sys_spu_create. This saves us an indirect branch, but means we have duplicated functions - one for CONFIG_SPU_FS=y and one for =m. This change unifies the spufs syscall path, and provides access to the spufs_calls structure through a get/put pair. At present, the only user of the spufs_calls structure is spu_syscalls.c, but this will facilitate adding the coredump calls later. Everyone likes numbers, right? Here's a before/after comparison with CONFIG_SPU_FS=y, doing spu_create(); close(); 64k times. Before: [jk@cell ~]$ time ./spu_create performing 65536 spu_create calls real 0m24.075s user 0m0.146s sys 0m23.925s After: [jk@cell ~]$ time ./spu_create performing 65536 spu_create calls real 0m24.777s user 0m0.141s sys 0m24.631s So, we're adding around 11us per syscall, at the benefit of having only one syscall path. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/Makefile | 4 +- arch/powerpc/platforms/cell/spu_syscalls.c | 108 ++++++++++++------- arch/powerpc/platforms/cell/spufs/spufs.h | 1 + arch/powerpc/platforms/cell/spufs/syscalls.c | 42 -------- include/asm-powerpc/spu.h | 14 +-- 5 files changed, 72 insertions(+), 97 deletions(-) diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index f88a7c76f296..40f78e908953 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -13,15 +13,13 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o endif # needed only when building loadable spufs.ko -spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ - spu_coredump.o \ - $(spufs-modular-m) \ + spu_coredump.o spu_syscalls.o \ $(spu-priv1-y) \ $(spu-manage-y) \ spufs/ diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index 027ac32cc636..c0238dd9ff27 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -22,42 +22,70 @@ #include #include #include +#include #include -struct spufs_calls spufs_calls = { - .owner = NULL, -}; +/* protected by rcu */ +static struct spufs_calls *spufs_calls; -/* These stub syscalls are needed to have the actual implementation - * within a loadable module. When spufs is built into the kernel, - * this file is not used and the syscalls directly enter the fs code */ +#ifdef CONFIG_SPU_FS_MODULE + +static inline struct spufs_calls *spufs_calls_get(void) +{ + struct spufs_calls *calls = NULL; + + rcu_read_lock(); + calls = rcu_dereference(spufs_calls); + if (calls && !try_module_get(calls->owner)) + calls = NULL; + rcu_read_unlock(); + + return calls; +} + +static inline void spufs_calls_put(struct spufs_calls *calls) +{ + BUG_ON(calls != spufs_calls); + + /* we don't need to rcu this, as we hold a reference to the module */ + module_put(spufs_calls->owner); +} + +#else /* !defined CONFIG_SPU_FS_MODULE */ + +static inline struct spufs_calls *spufs_calls_get(void) +{ + return spufs_calls; +} + +static inline void spufs_calls_put(struct spufs_calls *calls) { } + +#endif /* CONFIG_SPU_FS_MODULE */ asmlinkage long sys_spu_create(const char __user *name, unsigned int flags, mode_t mode, int neighbor_fd) { long ret; - struct module *owner = spufs_calls.owner; struct file *neighbor; int fput_needed; + struct spufs_calls *calls; - ret = -ENOSYS; - if (owner && try_module_get(owner)) { - if (flags & SPU_CREATE_AFFINITY_SPU) { - neighbor = fget_light(neighbor_fd, &fput_needed); - ret = -EBADF; - if (neighbor) { - ret = spufs_calls.create_thread(name, flags, - mode, neighbor); - fput_light(neighbor, fput_needed); - } + calls = spufs_calls_get(); + if (!calls) + return -ENOSYS; + + if (flags & SPU_CREATE_AFFINITY_SPU) { + ret = -EBADF; + neighbor = fget_light(neighbor_fd, &fput_needed); + if (neighbor) { + ret = calls->create_thread(name, flags, mode, neighbor); + fput_light(neighbor, fput_needed); } - else { - ret = spufs_calls.create_thread(name, flags, - mode, NULL); - } - module_put(owner); - } + } else + ret = calls->create_thread(name, flags, mode, NULL); + + spufs_calls_put(calls); return ret; } @@ -66,37 +94,37 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) long ret; struct file *filp; int fput_needed; - struct module *owner = spufs_calls.owner; + struct spufs_calls *calls; - ret = -ENOSYS; - if (owner && try_module_get(owner)) { - ret = -EBADF; - filp = fget_light(fd, &fput_needed); - if (filp) { - ret = spufs_calls.spu_run(filp, unpc, ustatus); - fput_light(filp, fput_needed); - } - module_put(owner); + calls = spufs_calls_get(); + if (!calls) + return -ENOSYS; + + ret = -EBADF; + filp = fget_light(fd, &fput_needed); + if (filp) { + ret = calls->spu_run(filp, unpc, ustatus); + fput_light(filp, fput_needed); } + + spufs_calls_put(calls); return ret; } int register_spu_syscalls(struct spufs_calls *calls) { - if (spufs_calls.owner) + if (spufs_calls) return -EBUSY; - spufs_calls.create_thread = calls->create_thread; - spufs_calls.spu_run = calls->spu_run; - smp_mb(); - spufs_calls.owner = calls->owner; + rcu_assign_pointer(spufs_calls, calls); return 0; } EXPORT_SYMBOL_GPL(register_spu_syscalls); void unregister_spu_syscalls(struct spufs_calls *calls) { - BUG_ON(spufs_calls.owner != calls->owner); - spufs_calls.owner = NULL; + BUG_ON(spufs_calls->owner != calls->owner); + rcu_assign_pointer(spufs_calls, NULL); + synchronize_rcu(); } EXPORT_SYMBOL_GPL(unregister_spu_syscalls); diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 2bfdeb8ea8bd..3dbffebb3cef 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -200,6 +200,7 @@ extern struct tree_descr spufs_dir_contents[]; extern struct tree_descr spufs_dir_nosched_contents[]; /* system call implementation */ +extern struct spufs_calls spufs_calls; long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, struct file *filp); diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 936e0a8af3a9..22b138dc335c 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -58,24 +58,6 @@ out: return ret; } -#ifndef MODULE -asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) -{ - int fput_needed; - struct file *filp; - long ret; - - ret = -EBADF; - filp = fget_light(fd, &fput_needed); - if (filp) { - ret = do_spu_run(filp, unpc, ustatus); - fput_light(filp, fput_needed); - } - - return ret; -} -#endif - static long do_spu_create(const char __user *pathname, unsigned int flags, mode_t mode, struct file *neighbor) { @@ -99,30 +81,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags, return ret; } -#ifndef MODULE -asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags, - mode_t mode, int neighbor_fd) -{ - int fput_needed; - struct file *neighbor; - long ret; - - if (flags & SPU_CREATE_AFFINITY_SPU) { - ret = -EBADF; - neighbor = fget_light(neighbor_fd, &fput_needed); - if (neighbor) { - ret = do_spu_create(pathname, flags, mode, neighbor); - fput_light(neighbor, fput_needed); - } - } - else { - ret = do_spu_create(pathname, flags, mode, NULL); - } - - return ret; -} -#endif - struct spufs_calls spufs_calls = { .create_thread = do_spu_create, .spu_run = do_spu_run, diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 5bde3980bf49..383ecfdf7eb0 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -238,14 +238,14 @@ extern long spu_sys_callback(struct spu_syscall_block *s); /* syscalls implemented in spufs */ struct file; -extern struct spufs_calls { +struct spufs_calls { asmlinkage long (*create_thread)(const char __user *name, unsigned int flags, mode_t mode, struct file *neighbor); asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus); struct module *owner; -} spufs_calls; +}; /* coredump calls implemented in spufs */ struct spu_coredump_calls { @@ -274,18 +274,8 @@ struct spu_coredump_calls { #define SPU_CREATE_FLAG_ALL 0x003f /* mask of all valid flags */ -#ifdef CONFIG_SPU_FS_MODULE int register_spu_syscalls(struct spufs_calls *calls); void unregister_spu_syscalls(struct spufs_calls *calls); -#else -static inline int register_spu_syscalls(struct spufs_calls *calls) -{ - return 0; -} -static inline void unregister_spu_syscalls(struct spufs_calls *calls) -{ -} -#endif /* MODULE */ int register_arch_coredump_calls(struct spu_coredump_calls *calls); void unregister_arch_coredump_calls(struct spu_coredump_calls *calls); From 4ec3c3d08d4de744b7a1d885529d1e040ec747a4 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0237/2804] [POWERPC] spufs: Remove asmlinkage from spufs_calls spu_create and spu_run are wrapped by the cell syscall layer, so we don't need the asmlinkage. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- include/asm-powerpc/spu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 383ecfdf7eb0..eb1159cdb8ac 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -239,10 +239,10 @@ extern long spu_sys_callback(struct spu_syscall_block *s); /* syscalls implemented in spufs */ struct file; struct spufs_calls { - asmlinkage long (*create_thread)(const char __user *name, + long (*create_thread)(const char __user *name, unsigned int flags, mode_t mode, struct file *neighbor); - asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, + long (*spu_run)(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus); struct module *owner; }; From 05a059f3296c07a7455290dd8188b23ecb380fc7 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0238/2804] [POWERPC] spufs: Fix restore_decr_wrapped() to match CBE Handbook Based on an original patch from Masato Noguchi . We're currently not restoring the SPE decrementer as specified by the CBE handbook. This change fixes our implementation to match, and makes the function read more like the docs. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/switch.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 250661991503..de7e5ee451d2 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -1559,15 +1559,15 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu) * "wrapped" flag is set, OR in a '1' to * CSA.SPU_Event_Status[Tm]. */ - if (csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) { - csa->spu_chnldata_RW[0] |= 0x20; - } - if ((csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) && - (csa->spu_chnlcnt_RW[0] == 0 && - ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) && - ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) { + if (!(csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED)) + return; + + if ((csa->spu_chnlcnt_RW[0] == 0) && + (csa->spu_chnldata_RW[1] & 0x20) && + !(csa->spu_chnldata_RW[0] & 0x20)) csa->spu_chnlcnt_RW[0] = 1; - } + + csa->spu_chnldata_RW[0] |= 0x20; } static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu) From c70d4ca52b1390dd2603535600c948cbdb0b9ec9 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0239/2804] [POWERPC] cell: Remove DEBUG for SPU callbacks We don't want SPE programs to be able to flood the kernel log by invoking the SPE callback handler, so don't enable DEBUG for spu_callbacks.c by default. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_callbacks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index ab39e223d44d..dceb8b6a9382 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -2,7 +2,7 @@ * System call callback functions for SPUs */ -#define DEBUG +#undef DEBUG #include #include From a595ed662c96dcd920415bea3135ff1af60e9a00 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0240/2804] [POWERPC] spufs: Extract the file descriptor search logic in SPU coredump code Extract the logic for searching through the file descriptors for spu contexts into a separate routine, coredump_next_context(), so we can use it elsewhere in future. In the process we flatten the for loop, and move the NOSCHED test into coredump_next_context(). Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/coredump.c | 54 +++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 5e31799b1e3f..99f8e0b00897 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -109,16 +109,11 @@ static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) return total; } -static int spufs_add_one_context(struct file *file, int dfd) +static int spufs_add_one_context(struct spu_context *ctx, int dfd) { - struct spu_context *ctx; struct spufs_ctx_info *ctx_info; int size; - ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx; - if (ctx->flags & SPU_CREATE_NOSCHED) - return 0; - ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL); if (unlikely(!ctx_info)) return -ENOMEM; @@ -142,22 +137,45 @@ static int spufs_add_one_context(struct file *file, int dfd) * internal functionality to dump them without needing to actually * open the files. */ -static int spufs_arch_notes_size(void) +static struct spu_context *coredump_next_context(int *fd) { struct fdtable *fdt = files_fdtable(current->files); - int size = 0, fd; + struct file *file; + struct spu_context *ctx = NULL; - for (fd = 0; fd < fdt->max_fds; fd++) { - if (FD_ISSET(fd, fdt->open_fds)) { - struct file *file = fcheck(fd); + for (; *fd < fdt->max_fds; (*fd)++) { + if (!FD_ISSET(*fd, fdt->open_fds)) + continue; - if (file && file->f_op == &spufs_context_fops) { - int rval = spufs_add_one_context(file, fd); - if (rval < 0) - break; - size += rval; - } - } + file = fcheck(*fd); + + if (!file || file->f_op != &spufs_context_fops) + continue; + + ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx; + if (ctx->flags & SPU_CREATE_NOSCHED) + continue; + + /* start searching the next fd next time we're called */ + (*fd)++; + break; + } + + return ctx; +} + +static int spufs_arch_notes_size(void) +{ + struct spu_context *ctx; + int size = 0, rc, fd; + + fd = 0; + while ((ctx = coredump_next_context(&fd)) != NULL) { + rc = spufs_add_one_context(ctx, fd); + if (rc < 0) + break; + + size += rc; } return size; From f9b7bbe7a803c6f10e7b3a354c5d97f632060320 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0241/2804] [POWERPC] spufs: Remove ctx_info and ctx_info_list Remove the ctx_info struct entirely, and also the ctx_info_list. This fixes a race where two processes can clobber each other's ctx_info structs. Instead of using the list, we just repeat the search through the file descriptor table. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/coredump.c | 79 +++++--------------- 1 file changed, 19 insertions(+), 60 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 99f8e0b00897..66636693c9d6 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -31,15 +31,6 @@ #include "spufs.h" -struct spufs_ctx_info { - struct list_head list; - int dfd; - int memsize; /* in bytes */ - struct spu_context *ctx; -}; - -static LIST_HEAD(ctx_info_list); - static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer, size_t size, loff_t *off) { @@ -73,25 +64,17 @@ static int spufs_dump_seek(struct file *file, loff_t off) return 1; } -static void spufs_fill_memsize(struct spufs_ctx_info *ctx_info) +static u64 ctx_ls_size(struct spu_context *ctx) { - struct spu_context *ctx; - unsigned long long lslr; - - ctx = ctx_info->ctx; - lslr = ctx->csa.priv2.spu_lslr_RW; - ctx_info->memsize = lslr + 1; + return ctx->csa.priv2.spu_lslr_RW + 1; } -static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) +static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) { - int dfd, memsize, i, sz, total = 0; + int i, sz, total = 0; char *name; char fullname[80]; - dfd = ctx_info->dfd; - memsize = ctx_info->memsize; - for (i = 0; spufs_coredump_read[i].name; i++) { name = spufs_coredump_read[i].name; sz = spufs_coredump_read[i].size; @@ -101,7 +84,7 @@ static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) total += sizeof(struct elf_note); total += roundup(strlen(fullname) + 1, 4); if (!strcmp(name, "mem")) - total += roundup(memsize, 4); + total += roundup(ctx_ls_size(ctx), 4); else total += roundup(sz, 4); } @@ -109,25 +92,6 @@ static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) return total; } -static int spufs_add_one_context(struct spu_context *ctx, int dfd) -{ - struct spufs_ctx_info *ctx_info; - int size; - - ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL); - if (unlikely(!ctx_info)) - return -ENOMEM; - - ctx_info->dfd = dfd; - ctx_info->ctx = ctx; - - spufs_fill_memsize(ctx_info); - - size = spufs_ctx_note_size(ctx_info); - list_add(&ctx_info->list, &ctx_info_list); - return size; -} - /* * The additional architecture-specific notes for Cell are various * context files in the spu context. @@ -171,7 +135,7 @@ static int spufs_arch_notes_size(void) fd = 0; while ((ctx = coredump_next_context(&fd)) != NULL) { - rc = spufs_add_one_context(ctx, fd); + rc = spufs_ctx_note_size(ctx, fd); if (rc < 0) break; @@ -181,12 +145,11 @@ static int spufs_arch_notes_size(void) return size; } -static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, - struct file *file) +static void spufs_arch_write_note(struct spu_context *ctx, int i, + struct file *file, int dfd) { - struct spu_context *ctx; loff_t pos = 0; - int sz, dfd, rc, total = 0; + int sz, rc, total = 0; const int bufsz = PAGE_SIZE; char *name; char fullname[80], *buf; @@ -196,18 +159,13 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, if (!buf) return; - dfd = ctx_info->dfd; name = spufs_coredump_read[i].name; if (!strcmp(name, "mem")) - sz = ctx_info->memsize; + sz = ctx_ls_size(ctx); else sz = spufs_coredump_read[i].size; - ctx = ctx_info->ctx; - if (!ctx) - goto out; - sprintf(fullname, "SPU/%d/%s", dfd, name); en.n_namesz = strlen(fullname) + 1; en.n_descsz = sz; @@ -237,16 +195,17 @@ out: static void spufs_arch_write_notes(struct file *file) { - int j; - struct spufs_ctx_info *ctx_info, *next; + struct spu_context *ctx; + int fd, j; + + fd = 0; + while ((ctx = coredump_next_context(&fd)) != NULL) { + spu_acquire_saved(ctx); - list_for_each_entry_safe(ctx_info, next, &ctx_info_list, list) { - spu_acquire_saved(ctx_info->ctx); for (j = 0; j < spufs_coredump_num_notes; j++) - spufs_arch_write_note(ctx_info, j, file); - spu_release_saved(ctx_info->ctx); - list_del(&ctx_info->list); - kfree(ctx_info); + spufs_arch_write_note(ctx, j, file, fd); + + spu_release_saved(ctx); } } From 9a5080f11d67972d7972d824f1b1827fafbce126 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0242/2804] [POWERPC] spufs: Call spu_acquire_saved() before calculating the SPU note sizes It makes sense to stop the SPU processes as soon as possible. Also if we dont acquire_saved() I think there's a possibility that the value in csa.priv2.spu_lslr_RW won't be accurate. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/coredump.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 66636693c9d6..21283f682889 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -135,7 +135,9 @@ static int spufs_arch_notes_size(void) fd = 0; while ((ctx = coredump_next_context(&fd)) != NULL) { + spu_acquire_saved(ctx); rc = spufs_ctx_note_size(ctx, fd); + spu_release_saved(ctx); if (rc < 0) break; From 4fca9c425009c01d41db6c6ebf0189843ee90f0b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0243/2804] [POWERPC] spufs: Use computed sizes/#defines rather than literals in SPU coredump code The spufs_coredump_reader array contains the size of the data that will be returned by the read routine. Currently these are specified as literals, and though some are obvious, sizeof(u32) == 4, others are not, 69 * 8 == ??? Instead, use sizeof() whatever type is returned by each routine, or in the case of spufs_mem_read() the #define LS_SIZE. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index a4a8770623d4..18ddde8ba197 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -2231,23 +2231,24 @@ struct tree_descr spufs_dir_nosched_contents[] = { }; struct spufs_coredump_reader spufs_coredump_read[] = { - { "regs", __spufs_regs_read, NULL, 128 * 16 }, - { "fpcr", __spufs_fpcr_read, NULL, 16 }, + { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, + { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, { "lslr", NULL, __spufs_lslr_get, 11 }, { "decr", NULL, __spufs_decr_get, 11 }, { "decr_status", NULL, __spufs_decr_status_get, 11 }, - { "mem", __spufs_mem_read, NULL, 256 * 1024, }, - { "signal1", __spufs_signal1_read, NULL, 4 }, + { "mem", __spufs_mem_read, NULL, LS_SIZE, }, + { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, { "signal1_type", NULL, __spufs_signal1_type_get, 2 }, - { "signal2", __spufs_signal2_read, NULL, 4 }, + { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, { "signal2_type", NULL, __spufs_signal2_type_get, 2 }, { "event_mask", NULL, __spufs_event_mask_get, 8 }, { "event_status", NULL, __spufs_event_status_get, 8 }, - { "mbox_info", __spufs_mbox_info_read, NULL, 4 }, - { "ibox_info", __spufs_ibox_info_read, NULL, 4 }, - { "wbox_info", __spufs_wbox_info_read, NULL, 16 }, - { "dma_info", __spufs_dma_info_read, NULL, 69 * 8 }, - { "proxydma_info", __spufs_proxydma_info_read, NULL, 35 * 8 }, + { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, + { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, + { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, + { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, + { "proxydma_info", __spufs_proxydma_info_read, + NULL, sizeof(struct spu_proxydma_info)}, { "object-id", NULL, __spufs_object_id_get, 19 }, { }, }; From d464fb441071a3d65bde2264c5f97f9ca47ce5c3 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0244/2804] [POWERPC] spufs: Write some SPU coredump values as ASCII Unfortunately GDB expects some of the SPU coredump values to be identical in format to what is found in spufs. This means we need to dump some of the values as ASCII strings, not the actual values. Because we don't know what the values will be, we always print the values with the format "0x%.16lx", that way we know the result will be 19 bytes. do_coredump_read() doesn't take a __user buffer, so remove the annotation, and because we know that it's safe to just snprintf() directly to it. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/coredump.c | 8 +++++--- arch/powerpc/platforms/cell/spufs/file.c | 14 +++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 21283f682889..c65b7178e77b 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -31,7 +31,7 @@ #include "spufs.h" -static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer, +static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer, size_t size, loff_t *off) { u64 data; @@ -41,8 +41,10 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *b return spufs_coredump_read[num].read(ctx, buffer, size, off); data = spufs_coredump_read[num].get(ctx); - ret = copy_to_user(buffer, &data, 8); - return ret ? -EFAULT : 8; + ret = snprintf(buffer, size, "0x%.16lx", data); + if (ret >= size) + return size; + return ++ret; /* count trailing NULL */ } /* diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 18ddde8ba197..85edbecf5062 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -2233,16 +2233,16 @@ struct tree_descr spufs_dir_nosched_contents[] = { struct spufs_coredump_reader spufs_coredump_read[] = { { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, - { "lslr", NULL, __spufs_lslr_get, 11 }, - { "decr", NULL, __spufs_decr_get, 11 }, - { "decr_status", NULL, __spufs_decr_status_get, 11 }, + { "lslr", NULL, __spufs_lslr_get, 19 }, + { "decr", NULL, __spufs_decr_get, 19 }, + { "decr_status", NULL, __spufs_decr_status_get, 19 }, { "mem", __spufs_mem_read, NULL, LS_SIZE, }, { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, - { "signal1_type", NULL, __spufs_signal1_type_get, 2 }, + { "signal1_type", NULL, __spufs_signal1_type_get, 19 }, { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, - { "signal2_type", NULL, __spufs_signal2_type_get, 2 }, - { "event_mask", NULL, __spufs_event_mask_get, 8 }, - { "event_status", NULL, __spufs_event_status_get, 8 }, + { "signal2_type", NULL, __spufs_signal2_type_get, 19 }, + { "event_mask", NULL, __spufs_event_mask_get, 19 }, + { "event_status", NULL, __spufs_event_status_get, 19 }, { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, From 59000b53c7ea07531018b6cf1f5fcd21e881867a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0245/2804] [POWERPC] spufs: Correctly calculate the size of the local-store to dump The routine to dump the local store, __spufs_mem_read(), does not take the spu_lslr_RW value into account - so we shouldn't check it when we're calculating the size either. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/coredump.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index c65b7178e77b..52d62193fd83 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -66,11 +66,6 @@ static int spufs_dump_seek(struct file *file, loff_t off) return 1; } -static u64 ctx_ls_size(struct spu_context *ctx) -{ - return ctx->csa.priv2.spu_lslr_RW + 1; -} - static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) { int i, sz, total = 0; @@ -85,10 +80,7 @@ static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) total += sizeof(struct elf_note); total += roundup(strlen(fullname) + 1, 4); - if (!strcmp(name, "mem")) - total += roundup(ctx_ls_size(ctx), 4); - else - total += roundup(sz, 4); + total += roundup(sz, 4); } return total; @@ -164,11 +156,7 @@ static void spufs_arch_write_note(struct spu_context *ctx, int i, return; name = spufs_coredump_read[i].name; - - if (!strcmp(name, "mem")) - sz = ctx_ls_size(ctx); - else - sz = spufs_coredump_read[i].size; + sz = spufs_coredump_read[i].size; sprintf(fullname, "SPU/%d/%s", dfd, name); en.n_namesz = strlen(fullname) + 1; From c1a72173ab156306666cb531f891f32e4e21d592 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0246/2804] [POWERPC] spufs: Don't return -ENOSYS as extra notes size if spufs is not loaded Because the SPU coredump code might be built as part of a module (spufs), we have a stub which is called by the coredump code, this routine then calls into spufs if it's loaded. Unfortunately the stub returns -ENOSYS if spufs is not loaded, which is interpreted by the coredump code as an extra note size of -38 bytes. This leads to a corrupt core dump. If spufs is not loaded there will be no SPU ELF notes to write, and so the extra notes size will be == 0. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_coredump.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c index 4fd37ff1e210..656a8c52cd38 100644 --- a/arch/powerpc/platforms/cell/spu_coredump.c +++ b/arch/powerpc/platforms/cell/spu_coredump.c @@ -31,15 +31,19 @@ static DEFINE_MUTEX(spu_coredump_mutex); int arch_notes_size(void) { - long ret; + int ret; - ret = -ENOSYS; mutex_lock(&spu_coredump_mutex); + if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { ret = spu_coredump_calls->arch_notes_size(); module_put(spu_coredump_calls->owner); + } else { + ret = 0; } + mutex_unlock(&spu_coredump_mutex); + return ret; } From 936d5bf1d7dc69c56bf79ad68819e597307a1884 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0247/2804] [POWERPC] spufs: Get rid of spufs_coredump_num_notes, it's not needed if we NULL terminate The spufs_coredump_read array is NULL terminated, and we also store the size. We only need one or the other, and the other arrays in file.c are NULL terminated, so do that. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/coredump.c | 4 ++-- arch/powerpc/platforms/cell/spufs/file.c | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 52d62193fd83..fc988fd1ffb6 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -72,7 +72,7 @@ static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) char *name; char fullname[80]; - for (i = 0; spufs_coredump_read[i].name; i++) { + for (i = 0; spufs_coredump_read[i].name != NULL; i++) { name = spufs_coredump_read[i].name; sz = spufs_coredump_read[i].size; @@ -194,7 +194,7 @@ static void spufs_arch_write_notes(struct file *file) while ((ctx = coredump_next_context(&fd)) != NULL) { spu_acquire_saved(ctx); - for (j = 0; j < spufs_coredump_num_notes; j++) + for (j = 0; spufs_coredump_read[j].name != NULL; j++) spufs_arch_write_note(ctx, j, file, fd); spu_release_saved(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 85edbecf5062..6095fb18dbb5 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -2250,7 +2250,5 @@ struct spufs_coredump_reader spufs_coredump_read[] = { { "proxydma_info", __spufs_proxydma_info_read, NULL, sizeof(struct spu_proxydma_info)}, { "object-id", NULL, __spufs_object_id_get, 19 }, - { }, + { NULL }, }; -int spufs_coredump_num_notes = ARRAY_SIZE(spufs_coredump_read) - 1; - From 74de08bc10dd4d67870cf5b6c5aaf6875cd869c5 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0248/2804] [POWERPC] spufs: Internal __spufs_get_foo() routines should take a spu_context * The SPUFS attribute get routines take a void * because the generic attribute code doesn't know what sort of data it's passing around. However our internal __spufs_get_foo() routines can take a spu_context * directly, which saves plonking it in and out of a void * again. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 40 +++++++++-------------- arch/powerpc/platforms/cell/spufs/spufs.h | 2 +- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 6095fb18dbb5..4cd34e53acaa 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -1085,9 +1085,8 @@ static void spufs_signal1_type_set(void *data, u64 val) spu_release(ctx); } -static u64 __spufs_signal1_type_get(void *data) +static u64 __spufs_signal1_type_get(struct spu_context *ctx) { - struct spu_context *ctx = data; return ctx->ops->signal1_type_get(ctx); } @@ -1097,7 +1096,7 @@ static u64 spufs_signal1_type_get(void *data) u64 ret; spu_acquire(ctx); - ret = __spufs_signal1_type_get(data); + ret = __spufs_signal1_type_get(ctx); spu_release(ctx); return ret; @@ -1114,9 +1113,8 @@ static void spufs_signal2_type_set(void *data, u64 val) spu_release(ctx); } -static u64 __spufs_signal2_type_get(void *data) +static u64 __spufs_signal2_type_get(struct spu_context *ctx) { - struct spu_context *ctx = data; return ctx->ops->signal2_type_get(ctx); } @@ -1126,7 +1124,7 @@ static u64 spufs_signal2_type_get(void *data) u64 ret; spu_acquire(ctx); - ret = __spufs_signal2_type_get(data); + ret = __spufs_signal2_type_get(ctx); spu_release(ctx); return ret; @@ -1629,9 +1627,8 @@ static void spufs_decr_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_decr_get(void *data) +static u64 __spufs_decr_get(struct spu_context *ctx) { - struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; return lscsa->decr.slot[0]; } @@ -1641,7 +1638,7 @@ static u64 spufs_decr_get(void *data) struct spu_context *ctx = data; u64 ret; spu_acquire_saved(ctx); - ret = __spufs_decr_get(data); + ret = __spufs_decr_get(ctx); spu_release_saved(ctx); return ret; } @@ -1659,9 +1656,8 @@ static void spufs_decr_status_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_decr_status_get(void *data) +static u64 __spufs_decr_status_get(struct spu_context *ctx) { - struct spu_context *ctx = data; if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) return SPU_DECR_STATUS_RUNNING; else @@ -1673,7 +1669,7 @@ static u64 spufs_decr_status_get(void *data) struct spu_context *ctx = data; u64 ret; spu_acquire_saved(ctx); - ret = __spufs_decr_status_get(data); + ret = __spufs_decr_status_get(ctx); spu_release_saved(ctx); return ret; } @@ -1689,9 +1685,8 @@ static void spufs_event_mask_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_event_mask_get(void *data) +static u64 __spufs_event_mask_get(struct spu_context *ctx) { - struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; return lscsa->event_mask.slot[0]; } @@ -1701,16 +1696,15 @@ static u64 spufs_event_mask_get(void *data) struct spu_context *ctx = data; u64 ret; spu_acquire_saved(ctx); - ret = __spufs_event_mask_get(data); + ret = __spufs_event_mask_get(ctx); spu_release_saved(ctx); return ret; } DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, spufs_event_mask_set, "0x%llx\n") -static u64 __spufs_event_status_get(void *data) +static u64 __spufs_event_status_get(struct spu_context *ctx) { - struct spu_context *ctx = data; struct spu_state *state = &ctx->csa; u64 stat; stat = state->spu_chnlcnt_RW[0]; @@ -1725,7 +1719,7 @@ static u64 spufs_event_status_get(void *data) u64 ret = 0; spu_acquire_saved(ctx); - ret = __spufs_event_status_get(data); + ret = __spufs_event_status_get(ctx); spu_release_saved(ctx); return ret; } @@ -1770,16 +1764,15 @@ static u64 spufs_id_get(void *data) } DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") -static u64 __spufs_object_id_get(void *data) +static u64 __spufs_object_id_get(struct spu_context *ctx) { - struct spu_context *ctx = data; return ctx->object_id; } static u64 spufs_object_id_get(void *data) { /* FIXME: Should there really be no locking here? */ - return __spufs_object_id_get(data); + return __spufs_object_id_get((struct spu_context *)data); } static void spufs_object_id_set(void *data, u64 id) @@ -1791,9 +1784,8 @@ static void spufs_object_id_set(void *data, u64 id) DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, spufs_object_id_set, "0x%llx\n"); -static u64 __spufs_lslr_get(void *data) +static u64 __spufs_lslr_get(struct spu_context *ctx) { - struct spu_context *ctx = data; return ctx->csa.priv2.spu_lslr_RW; } @@ -1803,7 +1795,7 @@ static u64 spufs_lslr_get(void *data) u64 ret; spu_acquire_saved(ctx); - ret = __spufs_lslr_get(data); + ret = __spufs_lslr_get(ctx); spu_release_saved(ctx); return ret; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 3dbffebb3cef..f869a4b488b0 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -296,7 +296,7 @@ struct spufs_coredump_reader { char *name; ssize_t (*read)(struct spu_context *ctx, char __user *buffer, size_t size, loff_t *pos); - u64 (*get)(void *data); + u64 (*get)(struct spu_context *ctx); size_t size; }; extern struct spufs_coredump_reader spufs_coredump_read[]; From 78810ff6723f20015373b1ba8dd981f24c62f680 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0249/2804] [POWERPC] spufs: Add contents of npc file to SPU coredumps Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 4cd34e53acaa..985c86bb16d0 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -1606,12 +1606,17 @@ static void spufs_npc_set(void *data, u64 val) spu_release(ctx); } +static u64 __spufs_npc_get(struct spu_context *ctx) +{ + return ctx->ops->npc_read(ctx); +} + static u64 spufs_npc_get(void *data) { struct spu_context *ctx = data; u64 ret; spu_acquire(ctx); - ret = ctx->ops->npc_read(ctx); + ret = __spufs_npc_get(ctx); spu_release(ctx); return ret; } @@ -2242,5 +2247,6 @@ struct spufs_coredump_reader spufs_coredump_read[] = { { "proxydma_info", __spufs_proxydma_info_read, NULL, sizeof(struct spu_proxydma_info)}, { "object-id", NULL, __spufs_object_id_get, 19 }, + { "npc", NULL, __spufs_npc_get, 19 }, { NULL }, }; From 48cad41f7ee7b8a9a8317a4abbdaf09bc68b4773 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0250/2804] [POWERPC] spufs: Combine spufs_coredump_calls with spufs_calls Because spufs might be built as a module, we can't have other parts of the kernel calling directly into it, we need stub routines that check first if the module is loaded. Currently we have two structures which hold callbacks for these stubs, the syscalls are in spufs_calls and the coredump calls are in spufs_coredump_calls. In both cases the logic for registering/unregistering is essentially the same, so we can simplify things by combining the two. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/Makefile | 2 +- arch/powerpc/platforms/cell/spu_coredump.c | 83 -------------------- arch/powerpc/platforms/cell/spu_syscalls.c | 30 +++++++ arch/powerpc/platforms/cell/spufs/coredump.c | 10 +-- arch/powerpc/platforms/cell/spufs/inode.c | 6 -- arch/powerpc/platforms/cell/spufs/spufs.h | 4 + arch/powerpc/platforms/cell/spufs/syscalls.c | 2 + include/asm-powerpc/spu.h | 12 +-- 8 files changed, 41 insertions(+), 108 deletions(-) delete mode 100644 arch/powerpc/platforms/cell/spu_coredump.c diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 40f78e908953..61d12f183036 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -19,7 +19,7 @@ spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ - spu_coredump.o spu_syscalls.o \ + spu_syscalls.o \ $(spu-priv1-y) \ $(spu-manage-y) \ spufs/ diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c deleted file mode 100644 index 656a8c52cd38..000000000000 --- a/arch/powerpc/platforms/cell/spu_coredump.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SPU core dump code - * - * (C) Copyright 2006 IBM Corp. - * - * Author: Dwayne Grant McConnell - * - * 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; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include - -#include - -static struct spu_coredump_calls *spu_coredump_calls; -static DEFINE_MUTEX(spu_coredump_mutex); - -int arch_notes_size(void) -{ - int ret; - - mutex_lock(&spu_coredump_mutex); - - if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { - ret = spu_coredump_calls->arch_notes_size(); - module_put(spu_coredump_calls->owner); - } else { - ret = 0; - } - - mutex_unlock(&spu_coredump_mutex); - - return ret; -} - -void arch_write_notes(struct file *file) -{ - mutex_lock(&spu_coredump_mutex); - if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { - spu_coredump_calls->arch_write_notes(file); - module_put(spu_coredump_calls->owner); - } - mutex_unlock(&spu_coredump_mutex); -} - -int register_arch_coredump_calls(struct spu_coredump_calls *calls) -{ - int ret = 0; - - - mutex_lock(&spu_coredump_mutex); - if (spu_coredump_calls) - ret = -EBUSY; - else - spu_coredump_calls = calls; - mutex_unlock(&spu_coredump_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(register_arch_coredump_calls); - -void unregister_arch_coredump_calls(struct spu_coredump_calls *calls) -{ - BUG_ON(spu_coredump_calls != calls); - - mutex_lock(&spu_coredump_mutex); - spu_coredump_calls = NULL; - mutex_unlock(&spu_coredump_mutex); -} -EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls); diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index c0238dd9ff27..05841cdef4e1 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -2,6 +2,7 @@ * SPU file system -- system call stubs * * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * (C) Copyright 2006-2007, IBM Corporation * * Author: Arnd Bergmann * @@ -111,6 +112,35 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) return ret; } +int arch_notes_size(void) +{ + struct spufs_calls *calls; + int ret; + + calls = spufs_calls_get(); + if (!calls) + return 0; + + ret = calls->coredump_extra_notes_size(); + + spufs_calls_put(calls); + + return ret; +} + +void arch_write_notes(struct file *file) +{ + struct spufs_calls *calls; + + calls = spufs_calls_get(); + if (!calls) + return; + + calls->coredump_extra_notes_write(file); + + spufs_calls_put(calls); +} + int register_spu_syscalls(struct spufs_calls *calls) { if (spufs_calls) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index fc988fd1ffb6..6c20e44dba63 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -122,7 +122,7 @@ static struct spu_context *coredump_next_context(int *fd) return ctx; } -static int spufs_arch_notes_size(void) +int spufs_coredump_extra_notes_size(void) { struct spu_context *ctx; int size = 0, rc, fd; @@ -185,7 +185,7 @@ out: free_page((unsigned long)buf); } -static void spufs_arch_write_notes(struct file *file) +void spufs_coredump_extra_notes_write(struct file *file) { struct spu_context *ctx; int fd, j; @@ -200,9 +200,3 @@ static void spufs_arch_write_notes(struct file *file) spu_release_saved(ctx); } } - -struct spu_coredump_calls spufs_coredump_calls = { - .arch_notes_size = spufs_arch_notes_size, - .arch_write_notes = spufs_arch_write_notes, - .owner = THIS_MODULE, -}; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index e210a4b259fb..11098747d09b 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -790,16 +790,11 @@ static int __init spufs_init(void) ret = register_spu_syscalls(&spufs_calls); if (ret) goto out_fs; - ret = register_arch_coredump_calls(&spufs_coredump_calls); - if (ret) - goto out_syscalls; spufs_init_isolated_loader(); return 0; -out_syscalls: - unregister_spu_syscalls(&spufs_calls); out_fs: unregister_filesystem(&spufs_type); out_sched: @@ -815,7 +810,6 @@ static void __exit spufs_exit(void) { spu_sched_exit(); spufs_exit_isolated_loader(); - unregister_arch_coredump_calls(&spufs_coredump_calls); unregister_spu_syscalls(&spufs_calls); unregister_filesystem(&spufs_type); kmem_cache_destroy(spufs_inode_cache); diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index f869a4b488b0..c7b4e035de48 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -204,6 +204,10 @@ extern struct spufs_calls spufs_calls; long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, struct file *filp); +/* ELF coredump callbacks for writing SPU ELF notes */ +extern int spufs_coredump_extra_notes_size(void); +extern void spufs_coredump_extra_notes_write(struct file *file); + extern const struct file_operations spufs_context_fops; /* gang management */ diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 22b138dc335c..2c34f7170190 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -84,5 +84,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags, struct spufs_calls spufs_calls = { .create_thread = do_spu_create, .spu_run = do_spu_run, + .coredump_extra_notes_size = spufs_coredump_extra_notes_size, + .coredump_extra_notes_write = spufs_coredump_extra_notes_write, .owner = THIS_MODULE, }; diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index eb1159cdb8ac..f1b10a187987 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -244,13 +244,8 @@ struct spufs_calls { struct file *neighbor); long (*spu_run)(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus); - struct module *owner; -}; - -/* coredump calls implemented in spufs */ -struct spu_coredump_calls { - asmlinkage int (*arch_notes_size)(void); - asmlinkage void (*arch_write_notes)(struct file *file); + int (*coredump_extra_notes_size)(void); + void (*coredump_extra_notes_write)(struct file *file); struct module *owner; }; @@ -277,9 +272,6 @@ struct spu_coredump_calls { int register_spu_syscalls(struct spufs_calls *calls); void unregister_spu_syscalls(struct spufs_calls *calls); -int register_arch_coredump_calls(struct spu_coredump_calls *calls); -void unregister_arch_coredump_calls(struct spu_coredump_calls *calls); - int spu_add_sysdev_attr(struct sysdev_attribute *attr); void spu_remove_sysdev_attr(struct sysdev_attribute *attr); From e55014923e65e4ee8e477a1212381cca0125f3aa Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0251/2804] [POWERPC] spufs: Cleanup ELF coredump extra notes logic To start with, arch_notes_size() etc. is a little too ambiguous a name for my liking, so change the function names to be more explicit. Calling through macros is ugly, especially with hidden parameters, so don't do that, call the routines directly. Use ARCH_HAVE_EXTRA_ELF_NOTES as the only flag, and based on it decide whether we want the extern declarations or the empty versions. Since we have empty routines, actually use them in the coredump code to save a few #ifdefs. We want to change the handling of foffset so that the write routine updates foffset as it goes, instead of using file->f_pos (so that writing to a pipe works). So pass foffset to the write routine, and for now just set it to file->f_pos at the end of writing. It should also be possible for the write routine to fail, so change it to return int and treat a non-zero return as failure. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_syscalls.c | 12 +++++++++--- fs/binfmt_elf.c | 14 +++----------- include/asm-powerpc/elf.h | 9 ++------- include/linux/elf.h | 14 ++++++++------ 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index 05841cdef4e1..b0117a7c6100 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -21,6 +21,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include +#include #include #include #include @@ -112,7 +113,7 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) return ret; } -int arch_notes_size(void) +int elf_coredump_extra_notes_size(void) { struct spufs_calls *calls; int ret; @@ -128,17 +129,22 @@ int arch_notes_size(void) return ret; } -void arch_write_notes(struct file *file) +int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset) { struct spufs_calls *calls; calls = spufs_calls_get(); if (!calls) - return; + return 0; calls->coredump_extra_notes_write(file); spufs_calls_put(calls); + + /* Fudge foffset for now */ + *foffset = file->f_pos; + + return 0; } int register_spu_syscalls(struct spufs_calls *calls) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 4482a0673b15..b1013f34085d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1514,9 +1514,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) int thread_status_size = 0; elf_addr_t *auxv; unsigned long mm_flags; -#ifdef ELF_CORE_WRITE_EXTRA_NOTES - int extra_notes_size; -#endif /* * We no longer stop all VM operations. @@ -1645,10 +1642,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) sz += thread_status_size; -#ifdef ELF_CORE_WRITE_EXTRA_NOTES - extra_notes_size = ELF_CORE_EXTRA_NOTES_SIZE; - sz += extra_notes_size; -#endif + sz += elf_coredump_extra_notes_size(); fill_elf_note_phdr(&phdr, sz, offset); offset += sz; @@ -1698,10 +1692,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) if (!writenote(notes + i, file, &foffset)) goto end_coredump; -#ifdef ELF_CORE_WRITE_EXTRA_NOTES - ELF_CORE_WRITE_EXTRA_NOTES; - foffset += extra_notes_size; -#endif + if (elf_coredump_extra_notes_write(file, &foffset)) + goto end_coredump; /* write out the thread status notes section */ list_for_each(t, &thread_list) { diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index de507995c7b1..e42820d6d25b 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h @@ -413,13 +413,8 @@ do { \ /* Notes used in ET_CORE. Note name is "SPU//". */ #define NT_SPU 1 -extern int arch_notes_size(void); -extern void arch_write_notes(struct file *file); - -#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size() -#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file) - #define ARCH_HAVE_EXTRA_ELF_NOTES -#endif /* CONFIG_PPC_CELL */ + +#endif /* CONFIG_SPU_BASE */ #endif /* _ASM_POWERPC_ELF_H */ diff --git a/include/linux/elf.h b/include/linux/elf.h index 8b17ffe222c4..d2da84acf45d 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -389,12 +389,14 @@ extern Elf64_Dyn _DYNAMIC []; #endif +/* Optional callbacks to write extra ELF notes. */ #ifndef ARCH_HAVE_EXTRA_ELF_NOTES -static inline int arch_notes_size(void) { return 0; } -static inline void arch_write_notes(struct file *file) { } - -#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size() -#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file) -#endif /* ARCH_HAVE_EXTRA_ELF_NOTES */ +static inline int elf_coredump_extra_notes_size(void) { return 0; } +static inline int elf_coredump_extra_notes_write(struct file *file, + loff_t *foffset) { return 0; } +#else +extern int elf_coredump_extra_notes_size(void); +extern int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset); +#endif #endif /* _LINUX_ELF_H */ From 7af1443a9d319132087e1e9a3984b94c6998835c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0252/2804] [POWERPC] spufs: Handle errors in SPU coredump code, and support coredump to a pipe Rework spufs_coredump_extra_notes_write() to check for and return errors. If we're coredumping to a pipe we can't trust file->f_pos, we need to maintain the foffset value passed to us. The cleanest way to do this is to have the low level write routine increment foffset when we've successfully written. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_syscalls.c | 8 +- arch/powerpc/platforms/cell/spufs/coredump.c | 89 ++++++++++++++------ arch/powerpc/platforms/cell/spufs/spufs.h | 2 +- include/asm-powerpc/spu.h | 2 +- 4 files changed, 67 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index b0117a7c6100..a9438b719fe8 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -132,19 +132,17 @@ int elf_coredump_extra_notes_size(void) int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset) { struct spufs_calls *calls; + int ret; calls = spufs_calls_get(); if (!calls) return 0; - calls->coredump_extra_notes_write(file); + ret = calls->coredump_extra_notes_write(file, foffset); spufs_calls_put(calls); - /* Fudge foffset for now */ - *foffset = file->f_pos; - - return 0; + return ret; } int register_spu_syscalls(struct spufs_calls *calls) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 6c20e44dba63..6b8aef6d7e68 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -51,19 +51,34 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer, * These are the only things you should do on a core-file: use only these * functions to write out all the necessary info. */ -static int spufs_dump_write(struct file *file, const void *addr, int nr) +static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset) { - return file->f_op->write(file, addr, nr, &file->f_pos) == nr; + ssize_t written; + + written = file->f_op->write(file, addr, nr, &file->f_pos); + *foffset += written; + + if (written != nr) + return -EIO; + + return 0; } -static int spufs_dump_seek(struct file *file, loff_t off) +static int spufs_dump_align(struct file *file, char *buf, loff_t new_off, + loff_t *foffset) { - if (file->f_op->llseek) { - if (file->f_op->llseek(file, off, 0) != off) - return 0; - } else - file->f_pos = off; - return 1; + int rc, size; + + size = min((loff_t)PAGE_SIZE, new_off - *foffset); + memset(buf, 0, size); + + rc = 0; + while (rc == 0 && new_off > *foffset) { + size = min((loff_t)PAGE_SIZE, new_off - *foffset); + rc = spufs_dump_write(file, buf, size, foffset); + } + + return rc; } static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) @@ -141,11 +156,11 @@ int spufs_coredump_extra_notes_size(void) return size; } -static void spufs_arch_write_note(struct spu_context *ctx, int i, - struct file *file, int dfd) +static int spufs_arch_write_note(struct spu_context *ctx, int i, + struct file *file, int dfd, loff_t *foffset) { loff_t pos = 0; - int sz, rc, total = 0; + int sz, rc, nread, total = 0; const int bufsz = PAGE_SIZE; char *name; char fullname[80], *buf; @@ -153,7 +168,7 @@ static void spufs_arch_write_note(struct spu_context *ctx, int i, buf = (void *)get_zeroed_page(GFP_KERNEL); if (!buf) - return; + return -ENOMEM; name = spufs_coredump_read[i].name; sz = spufs_coredump_read[i].size; @@ -163,40 +178,60 @@ static void spufs_arch_write_note(struct spu_context *ctx, int i, en.n_descsz = sz; en.n_type = NT_SPU; - if (!spufs_dump_write(file, &en, sizeof(en))) + rc = spufs_dump_write(file, &en, sizeof(en), foffset); + if (rc) goto out; - if (!spufs_dump_write(file, fullname, en.n_namesz)) + + rc = spufs_dump_write(file, fullname, en.n_namesz, foffset); + if (rc) goto out; - if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) + + rc = spufs_dump_align(file, buf, roundup(*foffset, 4), foffset); + if (rc) goto out; do { - rc = do_coredump_read(i, ctx, buf, bufsz, &pos); - if (rc > 0) { - if (!spufs_dump_write(file, buf, rc)) + nread = do_coredump_read(i, ctx, buf, bufsz, &pos); + if (nread > 0) { + rc = spufs_dump_write(file, buf, nread, foffset); + if (rc) goto out; - total += rc; + total += nread; } - } while (rc == bufsz && total < sz); + } while (nread == bufsz && total < sz); + + if (nread < 0) { + rc = nread; + goto out; + } + + rc = spufs_dump_align(file, buf, roundup(*foffset - total + sz, 4), + foffset); - spufs_dump_seek(file, roundup((unsigned long)file->f_pos - - total + sz, 4)); out: free_page((unsigned long)buf); + return rc; } -void spufs_coredump_extra_notes_write(struct file *file) +int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset) { struct spu_context *ctx; - int fd, j; + int fd, j, rc; fd = 0; while ((ctx = coredump_next_context(&fd)) != NULL) { spu_acquire_saved(ctx); - for (j = 0; spufs_coredump_read[j].name != NULL; j++) - spufs_arch_write_note(ctx, j, file, fd); + for (j = 0; spufs_coredump_read[j].name != NULL; j++) { + rc = spufs_arch_write_note(ctx, j, file, fd, foffset); + if (rc) { + spu_release_saved(ctx); + return rc; + } + } spu_release_saved(ctx); } + + return 0; } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index c7b4e035de48..ca47b991bda5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -206,7 +206,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, struct file *filp); /* ELF coredump callbacks for writing SPU ELF notes */ extern int spufs_coredump_extra_notes_size(void); -extern void spufs_coredump_extra_notes_write(struct file *file); +extern int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset); extern const struct file_operations spufs_context_fops; diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index f1b10a187987..b1accce77bb5 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -245,7 +245,7 @@ struct spufs_calls { long (*spu_run)(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus); int (*coredump_extra_notes_size)(void); - void (*coredump_extra_notes_write)(struct file *file); + int (*coredump_extra_notes_write)(struct file *file, loff_t *foffset); struct module *owner; }; From 9e25ae6d91e7fb058c8957c2a64dc3ca0377dd5b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0253/2804] [POWERPC] spufs: Respect RLIMIT_CORE in spu coredump code Currently the spu coredump code doesn't respect the ulimit, it should. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/coredump.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 6b8aef6d7e68..80f62363e1ce 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -53,8 +53,12 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer, */ static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset) { + unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; ssize_t written; + if (*foffset + nr > limit) + return -EIO; + written = file->f_op->write(file, addr, nr, &file->f_pos); *foffset += written; From 104f0cc2dcf7ce0ca7da041177233747d6aa0136 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 Sep 2007 14:38:12 +1000 Subject: [PATCH 0254/2804] [POWERPC] spufs: Add DEFINE_SPUFS_ATTRIBUTE() This patch adds DEFINE_SPUFS_ATTRIBUTE(), a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the specified locking for the get routine for us. Unfortunately we need two get routines (a locked and unlocked version) to support the coredump code. This hides one of those (the locked version) inside the macro foo. Signed-off-by: Michael Ellerman Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 216 ++++++++--------------- 1 file changed, 76 insertions(+), 140 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 985c86bb16d0..b93a0275a217 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -1076,6 +1076,36 @@ static const struct file_operations spufs_signal2_nosched_fops = { .mmap = spufs_signal2_mmap, }; +/* + * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the + * work of acquiring (or not) the SPU context before calling through + * to the actual get routine. The set routine is called directly. + */ +#define SPU_ATTR_NOACQUIRE 0 +#define SPU_ATTR_ACQUIRE 1 +#define SPU_ATTR_ACQUIRE_SAVED 2 + +#define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ +static u64 __##__get(void *data) \ +{ \ + struct spu_context *ctx = data; \ + u64 ret; \ + \ + if (__acquire == SPU_ATTR_ACQUIRE) { \ + spu_acquire(ctx); \ + ret = __get(ctx); \ + spu_release(ctx); \ + } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ + spu_acquire_saved(ctx); \ + ret = __get(ctx); \ + spu_release_saved(ctx); \ + } else \ + ret = __get(ctx); \ + \ + return ret; \ +} \ +DEFINE_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); + static void spufs_signal1_type_set(void *data, u64 val) { struct spu_context *ctx = data; @@ -1085,24 +1115,13 @@ static void spufs_signal1_type_set(void *data, u64 val) spu_release(ctx); } -static u64 __spufs_signal1_type_get(struct spu_context *ctx) +static u64 spufs_signal1_type_get(struct spu_context *ctx) { return ctx->ops->signal1_type_get(ctx); } +DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, + spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); -static u64 spufs_signal1_type_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - - spu_acquire(ctx); - ret = __spufs_signal1_type_get(ctx); - spu_release(ctx); - - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, - spufs_signal1_type_set, "%llu"); static void spufs_signal2_type_set(void *data, u64 val) { @@ -1113,24 +1132,12 @@ static void spufs_signal2_type_set(void *data, u64 val) spu_release(ctx); } -static u64 __spufs_signal2_type_get(struct spu_context *ctx) +static u64 spufs_signal2_type_get(struct spu_context *ctx) { return ctx->ops->signal2_type_get(ctx); } - -static u64 spufs_signal2_type_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - - spu_acquire(ctx); - ret = __spufs_signal2_type_get(ctx); - spu_release(ctx); - - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, - spufs_signal2_type_set, "%llu"); +DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, + spufs_signal2_type_set, "%llu", SPU_ATTR_ACQUIRE); #if SPUFS_MMAP_4K static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, @@ -1606,22 +1613,12 @@ static void spufs_npc_set(void *data, u64 val) spu_release(ctx); } -static u64 __spufs_npc_get(struct spu_context *ctx) +static u64 spufs_npc_get(struct spu_context *ctx) { return ctx->ops->npc_read(ctx); } - -static u64 spufs_npc_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - spu_acquire(ctx); - ret = __spufs_npc_get(ctx); - spu_release(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, - "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, + "0x%llx\n", SPU_ATTR_ACQUIRE); static void spufs_decr_set(void *data, u64 val) { @@ -1632,23 +1629,13 @@ static void spufs_decr_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_decr_get(struct spu_context *ctx) +static u64 spufs_decr_get(struct spu_context *ctx) { struct spu_lscsa *lscsa = ctx->csa.lscsa; return lscsa->decr.slot[0]; } - -static u64 spufs_decr_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - spu_acquire_saved(ctx); - ret = __spufs_decr_get(ctx); - spu_release_saved(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, - "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, + "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); static void spufs_decr_status_set(void *data, u64 val) { @@ -1661,25 +1648,16 @@ static void spufs_decr_status_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_decr_status_get(struct spu_context *ctx) +static u64 spufs_decr_status_get(struct spu_context *ctx) { if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) return SPU_DECR_STATUS_RUNNING; else return 0; } - -static u64 spufs_decr_status_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - spu_acquire_saved(ctx); - ret = __spufs_decr_status_get(ctx); - spu_release_saved(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, - spufs_decr_status_set, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, + spufs_decr_status_set, "0x%llx\n", + SPU_ATTR_ACQUIRE_SAVED); static void spufs_event_mask_set(void *data, u64 val) { @@ -1690,25 +1668,17 @@ static void spufs_event_mask_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_event_mask_get(struct spu_context *ctx) +static u64 spufs_event_mask_get(struct spu_context *ctx) { struct spu_lscsa *lscsa = ctx->csa.lscsa; return lscsa->event_mask.slot[0]; } -static u64 spufs_event_mask_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - spu_acquire_saved(ctx); - ret = __spufs_event_mask_get(ctx); - spu_release_saved(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, - spufs_event_mask_set, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, + spufs_event_mask_set, "0x%llx\n", + SPU_ATTR_ACQUIRE_SAVED); -static u64 __spufs_event_status_get(struct spu_context *ctx) +static u64 spufs_event_status_get(struct spu_context *ctx) { struct spu_state *state = &ctx->csa; u64 stat; @@ -1717,19 +1687,8 @@ static u64 __spufs_event_status_get(struct spu_context *ctx) return state->spu_chnldata_RW[0]; return 0; } - -static u64 spufs_event_status_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret = 0; - - spu_acquire_saved(ctx); - ret = __spufs_event_status_get(ctx); - spu_release_saved(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, - NULL, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, + NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) static void spufs_srr0_set(void *data, u64 val) { @@ -1740,44 +1699,32 @@ static void spufs_srr0_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 spufs_srr0_get(void *data) +static u64 spufs_srr0_get(struct spu_context *ctx) { - struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; - u64 ret; - spu_acquire_saved(ctx); - ret = lscsa->srr0.slot[0]; - spu_release_saved(ctx); - return ret; + return lscsa->srr0.slot[0]; } -DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, - "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, + "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) -static u64 spufs_id_get(void *data) +static u64 spufs_id_get(struct spu_context *ctx) { - struct spu_context *ctx = data; u64 num; - spu_acquire(ctx); if (ctx->state == SPU_STATE_RUNNABLE) num = ctx->spu->number; else num = (unsigned int)-1; - spu_release(ctx); return num; } -DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", + SPU_ATTR_ACQUIRE) -static u64 __spufs_object_id_get(struct spu_context *ctx) -{ - return ctx->object_id; -} - -static u64 spufs_object_id_get(void *data) +static u64 spufs_object_id_get(struct spu_context *ctx) { /* FIXME: Should there really be no locking here? */ - return __spufs_object_id_get((struct spu_context *)data); + return ctx->object_id; } static void spufs_object_id_set(void *data, u64 id) @@ -1786,26 +1733,15 @@ static void spufs_object_id_set(void *data, u64 id) ctx->object_id = id; } -DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, - spufs_object_id_set, "0x%llx\n"); +DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, + spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); -static u64 __spufs_lslr_get(struct spu_context *ctx) +static u64 spufs_lslr_get(struct spu_context *ctx) { return ctx->csa.priv2.spu_lslr_RW; } - -static u64 spufs_lslr_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - - spu_acquire_saved(ctx); - ret = __spufs_lslr_get(ctx); - spu_release_saved(ctx); - - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", + SPU_ATTR_ACQUIRE_SAVED); static int spufs_info_open(struct inode *inode, struct file *file) { @@ -2230,23 +2166,23 @@ struct tree_descr spufs_dir_nosched_contents[] = { struct spufs_coredump_reader spufs_coredump_read[] = { { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, - { "lslr", NULL, __spufs_lslr_get, 19 }, - { "decr", NULL, __spufs_decr_get, 19 }, - { "decr_status", NULL, __spufs_decr_status_get, 19 }, + { "lslr", NULL, spufs_lslr_get, 19 }, + { "decr", NULL, spufs_decr_get, 19 }, + { "decr_status", NULL, spufs_decr_status_get, 19 }, { "mem", __spufs_mem_read, NULL, LS_SIZE, }, { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, - { "signal1_type", NULL, __spufs_signal1_type_get, 19 }, + { "signal1_type", NULL, spufs_signal1_type_get, 19 }, { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, - { "signal2_type", NULL, __spufs_signal2_type_get, 19 }, - { "event_mask", NULL, __spufs_event_mask_get, 19 }, - { "event_status", NULL, __spufs_event_status_get, 19 }, + { "signal2_type", NULL, spufs_signal2_type_get, 19 }, + { "event_mask", NULL, spufs_event_mask_get, 19 }, + { "event_status", NULL, spufs_event_status_get, 19 }, { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, { "proxydma_info", __spufs_proxydma_info_read, NULL, sizeof(struct spu_proxydma_info)}, - { "object-id", NULL, __spufs_object_id_get, 19 }, - { "npc", NULL, __spufs_npc_get, 19 }, + { "object-id", NULL, spufs_object_id_get, 19 }, + { "npc", NULL, spufs_npc_get, 19 }, { NULL }, }; From ee983079ce04641523b23b8ed02cc3503632351e Mon Sep 17 00:00:00 2001 From: Domen Puncer Date: Wed, 18 Jul 2007 06:32:31 +1000 Subject: [PATCH 0255/2804] [POWERPC] MPC5200 low power mode Low-power mode implementation for Lite5200b. Some I/O registers are also saved here. A recent U-Boot that supports this (lite5200b_PM_config) is needed. Signed-off-by: Domen Puncer Signed-off-by: Sylvain Munaut Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/52xx/Makefile | 3 + arch/powerpc/platforms/52xx/lite5200.c | 14 +- arch/powerpc/platforms/52xx/lite5200_pm.c | 213 ++++++++++ arch/powerpc/platforms/52xx/lite5200_sleep.S | 412 +++++++++++++++++++ include/asm-powerpc/mpc52xx.h | 10 + 5 files changed, 647 insertions(+), 5 deletions(-) create mode 100644 arch/powerpc/platforms/52xx/lite5200_pm.c create mode 100644 arch/powerpc/platforms/52xx/lite5200_sleep.S diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index b91e39c84d46..307dbc178091 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile @@ -10,3 +10,6 @@ obj-$(CONFIG_PPC_EFIKA) += efika.o obj-$(CONFIG_PPC_LITE5200) += lite5200.o obj-$(CONFIG_PM) += mpc52xx_sleep.o mpc52xx_pm.o +ifeq ($(CONFIG_PPC_LITE5200),y) + obj-$(CONFIG_PM) += lite5200_sleep.o lite5200_pm.o +endif diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index ce3f6951828e..e11d27f9c4f0 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -85,7 +85,6 @@ error: } #ifdef CONFIG_PM -static u32 descr_a; static void lite5200_suspend_prepare(void __iomem *mbar) { u8 pin = 1; /* GPIO_WKUP_1 (GPIO_PSC2_4) */ @@ -96,13 +95,18 @@ static void lite5200_suspend_prepare(void __iomem *mbar) * power down usb port * this needs to be called before of-ohci suspend code */ - descr_a = in_be32(mbar + 0x1048); - out_be32(mbar + 0x1048, (descr_a & ~0x200) | 0x100); + + /* set ports to "power switched" and "powered at the same time" + * USB Rh descriptor A: NPS = 0, PSM = 0 */ + out_be32(mbar + 0x1048, in_be32(mbar + 0x1048) & ~0x300); + /* USB Rh status: LPS = 1 - turn off power */ + out_be32(mbar + 0x1050, 0x00000001); } static void lite5200_resume_finish(void __iomem *mbar) { - out_be32(mbar + 0x1048, descr_a); + /* USB Rh status: LPSC = 1 - turn on power */ + out_be32(mbar + 0x1050, 0x00010000); } #endif @@ -122,7 +126,7 @@ static void __init lite5200_setup_arch(void) #ifdef CONFIG_PM mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; mpc52xx_suspend.board_resume_finish = lite5200_resume_finish; - mpc52xx_pm_init(); + lite5200_pm_init(); #endif #ifdef CONFIG_PCI diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c new file mode 100644 index 000000000000..f26afcd41757 --- /dev/null +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include +#include "mpc52xx_pic.h" + +/* defined in lite5200_sleep.S and only used here */ +extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar); + +static struct mpc52xx_cdm __iomem *cdm; +static struct mpc52xx_intr __iomem *pic; +static struct mpc52xx_sdma __iomem *bes; +static struct mpc52xx_xlb __iomem *xlb; +static struct mpc52xx_gpio __iomem *gps; +static struct mpc52xx_gpio_wkup __iomem *gpw; +static void __iomem *sram; +static const int sram_size = 0x4000; /* 16 kBytes */ +static void __iomem *mbar; + +static int lite5200_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + return 1; + default: + return 0; + } +} + +static int lite5200_pm_prepare(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) + return mpc52xx_pm_prepare(state); + + if (state != PM_SUSPEND_MEM) + return -EINVAL; + + /* map registers */ + mbar = mpc52xx_find_and_map("mpc5200"); + if (!mbar) { + printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); + return -ENOSYS; + } + + cdm = mbar + 0x200; + pic = mbar + 0x500; + gps = mbar + 0xb00; + gpw = mbar + 0xc00; + bes = mbar + 0x1200; + xlb = mbar + 0x1f00; + sram = mbar + 0x8000; + + return 0; +} + +/* save and restore registers not bound to any real devices */ +static struct mpc52xx_cdm scdm; +static struct mpc52xx_intr spic; +static struct mpc52xx_sdma sbes; +static struct mpc52xx_xlb sxlb; +static struct mpc52xx_gpio sgps; +static struct mpc52xx_gpio_wkup sgpw; + +static void lite5200_save_regs(void) +{ + _memcpy_fromio(&spic, pic, sizeof(*pic)); + _memcpy_fromio(&sbes, bes, sizeof(*bes)); + _memcpy_fromio(&scdm, cdm, sizeof(*cdm)); + _memcpy_fromio(&sxlb, xlb, sizeof(*xlb)); + _memcpy_fromio(&sgps, gps, sizeof(*gps)); + _memcpy_fromio(&sgpw, gpw, sizeof(*gpw)); + + _memcpy_fromio(saved_sram, sram, sram_size); +} + +static void lite5200_restore_regs(void) +{ + int i; + _memcpy_toio(sram, saved_sram, sram_size); + + + /* + * GPIOs. Interrupt Master Enable has higher address then other + * registers, so just memcpy is ok. + */ + _memcpy_toio(gpw, &sgpw, sizeof(*gpw)); + _memcpy_toio(gps, &sgps, sizeof(*gps)); + + + /* XLB Arbitrer */ + out_be32(&xlb->snoop_window, sxlb.snoop_window); + out_be32(&xlb->master_priority, sxlb.master_priority); + out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable); + + /* enable */ + out_be32(&xlb->int_enable, sxlb.int_enable); + out_be32(&xlb->config, sxlb.config); + + + /* CDM - Clock Distribution Module */ + out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel); + out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel); + + out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en); + out_8(&cdm->fd_enable, scdm.fd_enable); + out_be16(&cdm->fd_counters, scdm.fd_counters); + + out_be32(&cdm->clk_enables, scdm.clk_enables); + + out_8(&cdm->osc_disable, scdm.osc_disable); + + out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1); + out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2); + out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3); + out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6); + + + /* BESTCOMM */ + out_be32(&bes->taskBar, sbes.taskBar); + out_be32(&bes->currentPointer, sbes.currentPointer); + out_be32(&bes->endPointer, sbes.endPointer); + out_be32(&bes->variablePointer, sbes.variablePointer); + + out_8(&bes->IntVect1, sbes.IntVect1); + out_8(&bes->IntVect2, sbes.IntVect2); + out_be16(&bes->PtdCntrl, sbes.PtdCntrl); + + for (i=0; i<32; i++) + out_8(&bes->ipr[i], sbes.ipr[i]); + + out_be32(&bes->cReqSelect, sbes.cReqSelect); + out_be32(&bes->task_size0, sbes.task_size0); + out_be32(&bes->task_size1, sbes.task_size1); + out_be32(&bes->MDEDebug, sbes.MDEDebug); + out_be32(&bes->ADSDebug, sbes.ADSDebug); + out_be32(&bes->Value1, sbes.Value1); + out_be32(&bes->Value2, sbes.Value2); + out_be32(&bes->Control, sbes.Control); + out_be32(&bes->Status, sbes.Status); + out_be32(&bes->PTDDebug, sbes.PTDDebug); + + /* restore tasks */ + for (i=0; i<16; i++) + out_be16(&bes->tcr[i], sbes.tcr[i]); + + /* enable interrupts */ + out_be32(&bes->IntPend, sbes.IntPend); + out_be32(&bes->IntMask, sbes.IntMask); + + + /* PIC */ + out_be32(&pic->per_pri1, spic.per_pri1); + out_be32(&pic->per_pri2, spic.per_pri2); + out_be32(&pic->per_pri3, spic.per_pri3); + + out_be32(&pic->main_pri1, spic.main_pri1); + out_be32(&pic->main_pri2, spic.main_pri2); + + out_be32(&pic->enc_status, spic.enc_status); + + /* unmask and enable interrupts */ + out_be32(&pic->per_mask, spic.per_mask); + out_be32(&pic->main_mask, spic.main_mask); + out_be32(&pic->ctrl, spic.ctrl); +} + +static int lite5200_pm_enter(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) { + return mpc52xx_pm_enter(state); + } + + lite5200_save_regs(); + + /* effectively save FP regs */ + enable_kernel_fp(); + + lite5200_low_power(sram, mbar); + + lite5200_restore_regs(); + + /* restart jiffies */ + wakeup_decrementer(); + + iounmap(mbar); + return 0; +} + +static int lite5200_pm_finish(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) { + return mpc52xx_pm_finish(state); + } + return 0; +} + +static struct pm_ops lite5200_pm_ops = { + .valid = lite5200_pm_valid, + .prepare = lite5200_pm_prepare, + .enter = lite5200_pm_enter, + .finish = lite5200_pm_finish, +}; + +int __init lite5200_pm_init(void) +{ + pm_set_ops(&lite5200_pm_ops); + return 0; +} diff --git a/arch/powerpc/platforms/52xx/lite5200_sleep.S b/arch/powerpc/platforms/52xx/lite5200_sleep.S new file mode 100644 index 000000000000..08ab6fefcf7a --- /dev/null +++ b/arch/powerpc/platforms/52xx/lite5200_sleep.S @@ -0,0 +1,412 @@ +#include +#include +#include +#include + + +#define SDRAM_CTRL 0x104 +#define SC_MODE_EN (1<<31) +#define SC_CKE (1<<30) +#define SC_REF_EN (1<<28) +#define SC_SOFT_PRE (1<<1) + +#define GPIOW_GPIOE 0xc00 +#define GPIOW_DDR 0xc08 +#define GPIOW_DVO 0xc0c + +#define CDM_CE 0x214 +#define CDM_SDRAM (1<<3) + + +/* helpers... beware: r10 and r4 are overwritten */ +#define SAVE_SPRN(reg, addr) \ + mfspr r10, SPRN_##reg; \ + stw r10, ((addr)*4)(r4); + +#define LOAD_SPRN(reg, addr) \ + lwz r10, ((addr)*4)(r4); \ + mtspr SPRN_##reg, r10; \ + sync; \ + isync; + + + .data +registers: + .space 0x5c*4 + .text + +/* ---------------------------------------------------------------------- */ +/* low-power mode with help of M68HLC908QT1 */ + + .globl lite5200_low_power +lite5200_low_power: + + mr r7, r3 /* save SRAM va */ + mr r8, r4 /* save MBAR va */ + + /* setup wakeup address for u-boot at physical location 0x0 */ + lis r3, CONFIG_KERNEL_START@h + lis r4, lite5200_wakeup@h + ori r4, r4, lite5200_wakeup@l + sub r4, r4, r3 + stw r4, 0(r3) + + + /* + * save stuff BDI overwrites + * 0xf0 (0xe0->0x100 gets overwritten when BDI connected; + * even when CONFIG_BDI* is disabled and MMU XLAT commented; heisenbug?)) + * WARNING: self-refresh doesn't seem to work when BDI2000 is connected, + * possibly because BDI sets SDRAM registers before wakeup code does + */ + lis r4, registers@h + ori r4, r4, registers@l + lwz r10, 0xf0(r3) + stw r10, (0x1d*4)(r4) + + /* save registers to r4 [destroys r10] */ + SAVE_SPRN(LR, 0x1c) + bl save_regs + + /* flush caches [destroys r3, r4] */ + bl flush_data_cache + + + /* copy code to sram */ + mr r4, r7 + li r3, (sram_code_end - sram_code)/4 + mtctr r3 + lis r3, sram_code@h + ori r3, r3, sram_code@l +1: + lwz r5, 0(r3) + stw r5, 0(r4) + addi r3, r3, 4 + addi r4, r4, 4 + bdnz 1b + + /* get tb_ticks_per_usec */ + lis r3, tb_ticks_per_usec@h + lwz r11, tb_ticks_per_usec@l(r3) + + /* disable I and D caches */ + mfspr r3, SPRN_HID0 + ori r3, r3, HID0_ICE | HID0_DCE + xori r3, r3, HID0_ICE | HID0_DCE + sync; isync; + mtspr SPRN_HID0, r3 + sync; isync; + + /* jump to sram */ + mtlr r7 + blrl + /* doesn't return */ + + +sram_code: + /* self refresh */ + lwz r4, SDRAM_CTRL(r8) + + /* send NOP (precharge) */ + oris r4, r4, SC_MODE_EN@h /* mode_en */ + stw r4, SDRAM_CTRL(r8) + sync + + ori r4, r4, SC_SOFT_PRE /* soft_pre */ + stw r4, SDRAM_CTRL(r8) + sync + xori r4, r4, SC_SOFT_PRE + + xoris r4, r4, SC_MODE_EN@h /* !mode_en */ + stw r4, SDRAM_CTRL(r8) + sync + + /* delay (for NOP to finish) */ + li r12, 1 + bl udelay + + /* + * mode_en must not be set when enabling self-refresh + * send AR with CKE low (self-refresh) + */ + oris r4, r4, (SC_REF_EN | SC_CKE)@h + xoris r4, r4, (SC_CKE)@h /* ref_en !cke */ + stw r4, SDRAM_CTRL(r8) + sync + + /* delay (after !CKE there should be two cycles) */ + li r12, 1 + bl udelay + + /* disable clock */ + lwz r4, CDM_CE(r8) + ori r4, r4, CDM_SDRAM + xori r4, r4, CDM_SDRAM + stw r4, CDM_CE(r8) + sync + + /* delay a bit */ + li r12, 1 + bl udelay + + + /* turn off with QT chip */ + li r4, 0x02 + stb r4, GPIOW_GPIOE(r8) /* enable gpio_wkup1 */ + sync + + stb r4, GPIOW_DVO(r8) /* "output" high */ + sync + stb r4, GPIOW_DDR(r8) /* output */ + sync + stb r4, GPIOW_DVO(r8) /* output high */ + sync + + /* 10uS delay */ + li r12, 10 + bl udelay + + /* turn off */ + li r4, 0 + stb r4, GPIOW_DVO(r8) /* output low */ + sync + + /* wait until we're offline */ + 1: + b 1b + + + /* local udelay in sram is needed */ + udelay: /* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */ + mullw r12, r12, r11 + mftb r13 /* start */ + addi r12, r13, r12 /* end */ + 1: + mftb r13 /* current */ + cmp cr0, r13, r12 + blt 1b + blr + +sram_code_end: + + + +/* uboot jumps here on resume */ +lite5200_wakeup: + bl restore_regs + + + /* HIDs, MSR */ + LOAD_SPRN(HID1, 0x19) + LOAD_SPRN(HID2, 0x1a) + + + /* address translation is tricky (see turn_on_mmu) */ + mfmsr r10 + ori r10, r10, MSR_DR | MSR_IR + + + mtspr SPRN_SRR1, r10 + lis r10, mmu_on@h + ori r10, r10, mmu_on@l + mtspr SPRN_SRR0, r10 + sync + rfi +mmu_on: + /* kernel offset (r4 is still set from restore_registers) */ + addis r4, r4, CONFIG_KERNEL_START@h + + + /* restore MSR */ + lwz r10, (4*0x1b)(r4) + mtmsr r10 + sync; isync; + + /* invalidate caches */ + mfspr r10, SPRN_HID0 + ori r5, r10, HID0_ICFI | HID0_DCI + mtspr SPRN_HID0, r5 /* invalidate caches */ + sync; isync; + mtspr SPRN_HID0, r10 + sync; isync; + + /* enable caches */ + lwz r10, (4*0x18)(r4) + mtspr SPRN_HID0, r10 /* restore (enable caches, DPM) */ + /* ^ this has to be after address translation set in MSR */ + sync + isync + + + /* restore 0xf0 (BDI2000) */ + lis r3, CONFIG_KERNEL_START@h + lwz r10, (0x1d*4)(r4) + stw r10, 0xf0(r3) + + LOAD_SPRN(LR, 0x1c) + + + blr + + +/* ---------------------------------------------------------------------- */ +/* boring code: helpers */ + +/* save registers */ +#define SAVE_BAT(n, addr) \ + SAVE_SPRN(DBAT##n##L, addr); \ + SAVE_SPRN(DBAT##n##U, addr+1); \ + SAVE_SPRN(IBAT##n##L, addr+2); \ + SAVE_SPRN(IBAT##n##U, addr+3); + +#define SAVE_SR(n, addr) \ + mfsr r10, n; \ + stw r10, ((addr)*4)(r4); + +#define SAVE_4SR(n, addr) \ + SAVE_SR(n, addr); \ + SAVE_SR(n+1, addr+1); \ + SAVE_SR(n+2, addr+2); \ + SAVE_SR(n+3, addr+3); + +save_regs: + stw r0, 0(r4) + stw r1, 0x4(r4) + stw r2, 0x8(r4) + stmw r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */ + + SAVE_SPRN(HID0, 0x18) + SAVE_SPRN(HID1, 0x19) + SAVE_SPRN(HID2, 0x1a) + mfmsr r10 + stw r10, (4*0x1b)(r4) + /*SAVE_SPRN(LR, 0x1c) have to save it before the call */ + /* 0x1d reserved by 0xf0 */ + SAVE_SPRN(RPA, 0x1e) + SAVE_SPRN(SDR1, 0x1f) + + /* save MMU regs */ + SAVE_BAT(0, 0x20) + SAVE_BAT(1, 0x24) + SAVE_BAT(2, 0x28) + SAVE_BAT(3, 0x2c) + SAVE_BAT(4, 0x30) + SAVE_BAT(5, 0x34) + SAVE_BAT(6, 0x38) + SAVE_BAT(7, 0x3c) + + SAVE_4SR(0, 0x40) + SAVE_4SR(4, 0x44) + SAVE_4SR(8, 0x48) + SAVE_4SR(12, 0x4c) + + SAVE_SPRN(SPRG0, 0x50) + SAVE_SPRN(SPRG1, 0x51) + SAVE_SPRN(SPRG2, 0x52) + SAVE_SPRN(SPRG3, 0x53) + SAVE_SPRN(SPRG4, 0x54) + SAVE_SPRN(SPRG5, 0x55) + SAVE_SPRN(SPRG6, 0x56) + SAVE_SPRN(SPRG7, 0x57) + + SAVE_SPRN(IABR, 0x58) + SAVE_SPRN(DABR, 0x59) + SAVE_SPRN(TBRL, 0x5a) + SAVE_SPRN(TBRU, 0x5b) + + blr + + +/* restore registers */ +#define LOAD_BAT(n, addr) \ + LOAD_SPRN(DBAT##n##L, addr); \ + LOAD_SPRN(DBAT##n##U, addr+1); \ + LOAD_SPRN(IBAT##n##L, addr+2); \ + LOAD_SPRN(IBAT##n##U, addr+3); + +#define LOAD_SR(n, addr) \ + lwz r10, ((addr)*4)(r4); \ + mtsr n, r10; + +#define LOAD_4SR(n, addr) \ + LOAD_SR(n, addr); \ + LOAD_SR(n+1, addr+1); \ + LOAD_SR(n+2, addr+2); \ + LOAD_SR(n+3, addr+3); + +restore_regs: + lis r4, registers@h + ori r4, r4, registers@l + + /* MMU is not up yet */ + subis r4, r4, CONFIG_KERNEL_START@h + + lwz r0, 0(r4) + lwz r1, 0x4(r4) + lwz r2, 0x8(r4) + lmw r11, 0xc(r4) + + /* + * these are a bit tricky + * + * 0x18 - HID0 + * 0x19 - HID1 + * 0x1a - HID2 + * 0x1b - MSR + * 0x1c - LR + * 0x1d - reserved by 0xf0 (BDI2000) + */ + LOAD_SPRN(RPA, 0x1e); + LOAD_SPRN(SDR1, 0x1f); + + /* restore MMU regs */ + LOAD_BAT(0, 0x20) + LOAD_BAT(1, 0x24) + LOAD_BAT(2, 0x28) + LOAD_BAT(3, 0x2c) + LOAD_BAT(4, 0x30) + LOAD_BAT(5, 0x34) + LOAD_BAT(6, 0x38) + LOAD_BAT(7, 0x3c) + + LOAD_4SR(0, 0x40) + LOAD_4SR(4, 0x44) + LOAD_4SR(8, 0x48) + LOAD_4SR(12, 0x4c) + + /* rest of regs */ + LOAD_SPRN(SPRG0, 0x50); + LOAD_SPRN(SPRG1, 0x51); + LOAD_SPRN(SPRG2, 0x52); + LOAD_SPRN(SPRG3, 0x53); + LOAD_SPRN(SPRG4, 0x54); + LOAD_SPRN(SPRG5, 0x55); + LOAD_SPRN(SPRG6, 0x56); + LOAD_SPRN(SPRG7, 0x57); + + LOAD_SPRN(IABR, 0x58); + LOAD_SPRN(DABR, 0x59); + LOAD_SPRN(TBWL, 0x5a); /* these two have separate R/W regs */ + LOAD_SPRN(TBWU, 0x5b); + + blr + + + +/* cache flushing code. copied from arch/ppc/boot/util.S */ +#define NUM_CACHE_LINES (128*8) + +/* + * Flush data cache + * Do this by just reading lots of stuff into the cache. + */ +flush_data_cache: + lis r3,CONFIG_KERNEL_START@h + ori r3,r3,CONFIG_KERNEL_START@l + li r4,NUM_CACHE_LINES + mtctr r4 +1: + lwz r4,0(r3) + addi r3,r3,L1_CACHE_BYTES /* Next line, please */ + bdnz 1b + blr diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h index c4631f6dd4f9..1a3dbb743a3f 100644 --- a/include/asm-powerpc/mpc52xx.h +++ b/include/asm-powerpc/mpc52xx.h @@ -262,6 +262,16 @@ struct mpc52xx_suspend { extern struct mpc52xx_suspend mpc52xx_suspend; extern int __init mpc52xx_pm_init(void); extern int mpc52xx_set_wakeup_gpio(u8 pin, u8 level); + +#ifdef CONFIG_PPC_LITE5200 +extern int __init lite5200_pm_init(void); + +/* lite5200 calls mpc5200 suspend functions, so here they are */ +extern int mpc52xx_pm_prepare(suspend_state_t); +extern int mpc52xx_pm_enter(suspend_state_t); +extern int mpc52xx_pm_finish(suspend_state_t); +extern char saved_sram[0x4000]; /* reuse buffer from mpc52xx suspend */ +#endif #endif /* CONFIG_PM */ #endif /* __ASM_POWERPC_MPC52xx_H__ */ From 7b2c3c5b1d6dd77d7bb5a7d57ab7280e051c59bc Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 17 Sep 2007 14:08:06 +1000 Subject: [PATCH 0256/2804] [POWERPC] Fix section mismatch in PCI code Create a helper function (alloc_maybe_bootmem) that is marked __init_refok to limit the chances of mistakenly referring to other __init routines. WARNING: vmlinux.o(.text+0x2a9c4): Section mismatch: reference to .init.text:.__alloc_bootmem (between '.update_dn_pci_info' and '.pci_dn_reconfig_notifier') WARNING: vmlinux.o(.text+0x36430): Section mismatch: reference to .init.text:.__alloc_bootmem (between '.mpic_msi_init_allocator' and '.find_ht_magic_addr') WARNING: vmlinux.o(.text+0x5e804): Section mismatch: reference to .init.text:.__alloc_bootmem (between '.celleb_setup_phb' and '.celleb_fake_pci_write_config') WARNING: vmlinux.o(.text+0x5e8e8): Section mismatch: reference to .init.text:.__alloc_bootmem (between '.celleb_setup_phb' and '.celleb_fake_pci_write_config') WARNING: vmlinux.o(.text+0x5e968): Section mismatch: reference to .init.text:.__alloc_bootmem (between '.celleb_setup_phb' and '.celleb_fake_pci_write_config') Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_dn.c | 7 +------ arch/powerpc/lib/Makefile | 2 +- arch/powerpc/lib/alloc.c | 14 ++++++++++++++ arch/powerpc/platforms/celleb/pci.c | 19 +++++-------------- arch/powerpc/sysdev/mpic_msi.c | 6 +----- include/asm-powerpc/system.h | 2 ++ 6 files changed, 24 insertions(+), 26 deletions(-) create mode 100644 arch/powerpc/lib/alloc.c diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c index d7d36df9c053..b4839038613d 100644 --- a/arch/powerpc/kernel/pci_dn.c +++ b/arch/powerpc/kernel/pci_dn.c @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include #include @@ -45,10 +43,7 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data) const u32 *regs; struct pci_dn *pdn; - if (mem_init_done) - pdn = kmalloc(sizeof(*pdn), GFP_KERNEL); - else - pdn = alloc_bootmem(sizeof(*pdn)); + pdn = alloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL); if (pdn == NULL) return NULL; memset(pdn, 0, sizeof(*pdn)); diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 0a486d4b2547..23bbb1ea7f9f 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -7,7 +7,7 @@ EXTRA_CFLAGS += -mno-minimal-toc endif ifeq ($(CONFIG_PPC_MERGE),y) -obj-y := string.o +obj-y := string.o alloc.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o endif diff --git a/arch/powerpc/lib/alloc.c b/arch/powerpc/lib/alloc.c new file mode 100644 index 000000000000..e58c80590ebc --- /dev/null +++ b/arch/powerpc/lib/alloc.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +#include + +void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask) +{ + if (mem_init_done) + return kmalloc(size, mask); + else + return alloc_bootmem(size); +} diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c index 11336b40feca..1348b23cbbc9 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/celleb/pci.c @@ -327,10 +327,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, size = 256; config = &private->fake_config[devno][fn]; - if (mem_init_done) - *config = kzalloc(size, GFP_KERNEL); - else - *config = alloc_bootmem(size); + *config = alloc_maybe_bootmem(size, GFP_KERNEL); if (*config == NULL) { printk(KERN_ERR "PCI: " "not enough memory for fake configuration space\n"); @@ -341,10 +338,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, size = sizeof(struct celleb_pci_resource); res = &private->res[devno][fn]; - if (mem_init_done) - *res = kzalloc(size, GFP_KERNEL); - else - *res = alloc_bootmem(size); + *res = alloc_maybe_bootmem(size, GFP_KERNEL); if (*res == NULL) { printk(KERN_ERR "PCI: not enough memory for resource data space\n"); @@ -436,12 +430,9 @@ static int __init phb_set_bus_ranges(struct device_node *dev, static void __init celleb_alloc_private_mem(struct pci_controller *hose) { - if (mem_init_done) - hose->private_data = - kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL); - else - hose->private_data = - alloc_bootmem(sizeof(struct celleb_pci_private)); + hose->private_data = + alloc_maybe_bootmem(sizeof(struct celleb_pci_private), + GFP_KERNEL); } int __init celleb_setup_phb(struct pci_controller *phb) diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 9ca4d8f444ff..d272a52ecd24 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -152,10 +151,7 @@ int mpic_msi_init_allocator(struct mpic *mpic) size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long); pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size); - if (mem_init_done) - mpic->hwirq_bitmap = kmalloc(size, GFP_KERNEL); - else - mpic->hwirq_bitmap = alloc_bootmem(size); + mpic->hwirq_bitmap = alloc_maybe_bootmem(size, GFP_KERNEL); if (!mpic->hwirq_bitmap) { pr_debug("mpic: ENOMEM allocating allocator bitmap!\n"); diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 41520b7a7b76..f7879fc530f1 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -189,6 +189,8 @@ extern int mem_init_done; /* set on boot once kmalloc can be called */ extern unsigned long memory_limit; extern unsigned long klimit; +extern void *alloc_maybe_bootmem(size_t size, gfp_t mask); + extern int powersave_nap; /* set if nap mode can be used in idle loop */ /* From 19a8d97d89442e2bda6245b8a3de2c1fec69a7ad Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 17 Sep 2007 14:41:38 +1000 Subject: [PATCH 0257/2804] [POWERPC] Remove cmd_line from head*.S It is just a C char array, so declare it thusly. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_32.S | 8 -------- arch/powerpc/kernel/head_40x.S | 7 ------- arch/powerpc/kernel/head_44x.S | 8 -------- arch/powerpc/kernel/head_64.S | 8 -------- arch/powerpc/kernel/head_8xx.S | 8 -------- arch/powerpc/kernel/head_fsl_booke.S | 8 -------- arch/powerpc/kernel/setup-common.c | 2 ++ 7 files changed, 2 insertions(+), 47 deletions(-) diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 12febfe43de6..c86c626cf156 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -1297,14 +1297,6 @@ empty_zero_page: swapper_pg_dir: .space 4096 -/* - * This space gets a copy of optional info passed to us by the bootstrap - * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - .globl intercept_table intercept_table: .long 0, 0, i0x200, i0x300, i0x400, 0, i0x600, i0x700 diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index 00bdb6d1c724..e312824bdd98 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -1006,13 +1006,6 @@ critical_stack_top: .globl exception_stack_top exception_stack_top: -/* This space gets a copy of optional info passed to us by the bootstrap - * which is used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - /* Room for two PTE pointers, usually the kernel and current user pointers * to their respective root page table. */ diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index a3dc0e4d0456..c6a510bdefd4 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -743,14 +743,6 @@ exception_stack_bottom: .globl exception_stack_top exception_stack_top: -/* - * This space gets a copy of optional info passed to us by the bootstrap - * which is used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - /* * Room for two PTE pointers, usually the kernel and current user pointers * to their respective root page table. diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index cec59089e48c..f4ae82e9c92d 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -1540,11 +1540,3 @@ empty_zero_page: .globl swapper_pg_dir swapper_pg_dir: .space PAGE_SIZE - -/* - * This space gets a copy of optional info passed to us by the bootstrap - * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space COMMAND_LINE_SIZE diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index a6ecdd643167..96cea8e753c4 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -832,14 +832,6 @@ empty_zero_page: swapper_pg_dir: .space 4096 -/* - * This space gets a copy of optional info passed to us by the bootstrap - * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - /* Room for two PTE table poiners, usually the kernel and current user * pointer to their respective root page table (pgdir). */ diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index d83cbbb264e2..bfc38703a8ac 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -1049,14 +1049,6 @@ exception_stack_bottom: .globl exception_stack_top exception_stack_top: -/* - * This space gets a copy of optional info passed to us by the bootstrap - * which is used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - /* * Room for two PTE pointers, usually the kernel and current user pointers * to their respective root page table. diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 50ef38cffdbf..36c90ba2d312 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -76,6 +76,8 @@ EXPORT_SYMBOL(machine_id); unsigned long klimit = (unsigned long) _end; +char cmd_line[COMMAND_LINE_SIZE]; + /* * This still seems to be needed... -- paulus */ From ee7a76da1ef5e3e5e0e54e84319e435ea25c267c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 18 Sep 2007 17:22:59 +1000 Subject: [PATCH 0258/2804] [POWERPC] Size swapper_pg_dir correctly David Gibson pointed out that swapper_pg_dir actually need to be PGD_TABLE_SIZE bytes long not PAGE_SIZE. This actually saves 64k in the bss for a kernel ppc64_defconfig built with CONFIG_PPC_64K_PAGES. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 4 ++++ arch/powerpc/kernel/head_64.S | 2 +- include/asm-powerpc/pgtable-4k.h | 2 ++ include/asm-powerpc/pgtable-64k.h | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index a40805328f9b..0ae5d57b9368 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -320,5 +320,9 @@ int main(void) DEFINE(VMALLOC_START_ESID, GET_ESID(VMALLOC_START)); DEFINE(VMALLOC_START_VSID, KERNEL_VSID(VMALLOC_START)); #endif + +#ifdef CONFIG_PPC64 + DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE); +#endif return 0; } diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index f4ae82e9c92d..384cc75f1cd4 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -1539,4 +1539,4 @@ empty_zero_page: .globl swapper_pg_dir swapper_pg_dir: - .space PAGE_SIZE + .space PGD_TABLE_SIZE diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h index add5481fd7c7..818e2abc81e2 100644 --- a/include/asm-powerpc/pgtable-4k.h +++ b/include/asm-powerpc/pgtable-4k.h @@ -10,10 +10,12 @@ #define PUD_INDEX_SIZE 7 #define PGD_INDEX_SIZE 9 +#ifndef __ASSEMBLY__ #define PTE_TABLE_SIZE (sizeof(pte_t) << PTE_INDEX_SIZE) #define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE) #define PUD_TABLE_SIZE (sizeof(pud_t) << PUD_INDEX_SIZE) #define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE) +#endif /* __ASSEMBLY__ */ #define PTRS_PER_PTE (1 << PTE_INDEX_SIZE) #define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h index 33ae9018fe72..bd54b772fbc6 100644 --- a/include/asm-powerpc/pgtable-64k.h +++ b/include/asm-powerpc/pgtable-64k.h @@ -9,9 +9,11 @@ #define PUD_INDEX_SIZE 0 #define PGD_INDEX_SIZE 4 +#ifndef __ASSEMBLY__ #define PTE_TABLE_SIZE (sizeof(real_pte_t) << PTE_INDEX_SIZE) #define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE) #define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE) +#endif /* __ASSEMBLY__ */ #define PTRS_PER_PTE (1 << PTE_INDEX_SIZE) #define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) From 9e4859ef5462193643fd2b3c8ffb298e5a4a4319 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 18 Sep 2007 17:25:12 +1000 Subject: [PATCH 0259/2804] [POWERPC] FWNMI is only used on pSeries This saves 4k on non pSeries builds (except for iSeries where it saves almost 4k). Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/crash_dump.c | 2 ++ arch/powerpc/kernel/head_64.S | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index ffa91d673ec8..29ff77c468ac 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -54,8 +54,10 @@ void __init setup_kdump_trampoline(void) create_trampoline(i); } +#ifdef CONFIG_PPC_PSERIES create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START); create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START); +#endif /* CONFIG_PPC_PSERIES */ DBG(" <- setup_kdump_trampoline()\n"); } diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 384cc75f1cd4..22ac245bd59a 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -341,6 +341,7 @@ slb_miss_user_pseries: b . /* prevent spec. execution */ #endif /* __DISABLED__ */ +#ifdef CONFIG_PPC_PSERIES /* * Vectors for the FWNMI option. Share common code. */ @@ -358,6 +359,8 @@ machine_check_fwnmi: mtspr SPRN_SPRG1,r13 /* save r13 */ EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXMC, machine_check_common) +#endif /* CONFIG_PPC_PSERIES */ + /*** Common interrupt handlers ***/ STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) @@ -1012,6 +1015,7 @@ _GLOBAL(do_stab_bolted) initial_stab: .space 4096 +#ifdef CONFIG_PPC_PSERIES /* * Data area reserved for FWNMI option. * This address (0x7000) is fixed by the RPA. @@ -1019,6 +1023,7 @@ initial_stab: .= 0x7000 .globl fwnmi_data_area fwnmi_data_area: +#endif /* CONFIG_PPC_PSERIES */ /* iSeries does not use the FWNMI stuff, so it is safe to put * this here, even if we later allow kernels that will boot on @@ -1043,7 +1048,9 @@ xLparMap: #endif /* CONFIG_PPC_ISERIES */ +#ifdef CONFIG_PPC_PSERIES . = 0x8000 +#endif /* CONFIG_PPC_PSERIES */ /* * On pSeries and most other platforms, secondary processors spin From 658e81701970a82d33f46241f20be416ebd5e930 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Sat, 15 Sep 2007 04:54:11 +1000 Subject: [PATCH 0260/2804] [POWERPC] cuimage for Bamboo board Add a cuboot wrapper for the Bamboo board. Additionally, we enable MAC address fixups for both cuboot and treeboot. This also removes some obsoleted linker declarations that have been moved into ops.h Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/boot/44x.h | 2 +- arch/powerpc/boot/Makefile | 4 ++-- arch/powerpc/boot/bamboo.c | 8 +++++--- arch/powerpc/boot/cuboot-bamboo.c | 30 +++++++++++++++++++++++++++++ arch/powerpc/boot/treeboot-bamboo.c | 22 ++++++++++++++++++--- 5 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 arch/powerpc/boot/cuboot-bamboo.c diff --git a/arch/powerpc/boot/44x.h b/arch/powerpc/boot/44x.h index ad33dcc95ae5..02563443788a 100644 --- a/arch/powerpc/boot/44x.h +++ b/arch/powerpc/boot/44x.h @@ -11,6 +11,6 @@ #define _PPC_BOOT_44X_H_ void ebony_init(void *mac0, void *mac1); -void bamboo_init(void); +void bamboo_init(void *mac0, void *mac1); #endif /* _PPC_BOOT_44X_H_ */ diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index cffef147e042..c1582b62911c 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -49,7 +49,7 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ - cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c + cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -146,7 +146,7 @@ image-$(CONFIG_8260) += cuImage.pq2 image-$(CONFIG_PPC_83xx) += cuImage.83xx image-$(CONFIG_PPC_85xx) += cuImage.85xx image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony -image-$(CONFIG_BAMBOO) += treeImage.bamboo +image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo image-$(CONFIG_SEQUOIA) += cuImage.sequoia image-$(CONFIG_WALNUT) += treeImage.walnut endif diff --git a/arch/powerpc/boot/bamboo.c b/arch/powerpc/boot/bamboo.c index bc097694b445..f61fcdab1c7c 100644 --- a/arch/powerpc/boot/bamboo.c +++ b/arch/powerpc/boot/bamboo.c @@ -24,8 +24,7 @@ #include "4xx.h" #include "44x.h" -extern char _dtb_start[]; -extern char _dtb_end[]; +static u8 *bamboo_mac0, *bamboo_mac1; static void bamboo_fixups(void) { @@ -34,12 +33,15 @@ static void bamboo_fixups(void) ibm440ep_fixup_clocks(sysclk, 11059200); ibm4xx_fixup_memsize(); ibm4xx_quiesce_eth((u32 *)0xef600e00, (u32 *)0xef600f00); + dt_fixup_mac_addresses(bamboo_mac0, bamboo_mac1); } -void bamboo_init(void) +void bamboo_init(void *mac0, void *mac1) { platform_ops.fixups = bamboo_fixups; platform_ops.exit = ibm44x_dbcr_reset; + bamboo_mac0 = mac0; + bamboo_mac1 = mac1; ft_init(_dtb_start, 0, 32); serial_console_init(); } diff --git a/arch/powerpc/boot/cuboot-bamboo.c b/arch/powerpc/boot/cuboot-bamboo.c new file mode 100644 index 000000000000..900c7ff2b7e9 --- /dev/null +++ b/arch/powerpc/boot/cuboot-bamboo.c @@ -0,0 +1,30 @@ +/* + * Old U-boot compatibility for Bamboo + * + * Author: Josh Boyer + * + * Copyright 2007 IBM Corporation + * + * Based on cuboot-ebony.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 "ops.h" +#include "stdio.h" +#include "44x.h" +#include "cuboot.h" + +#define TARGET_44x +#include "ppcboot.h" + +static bd_t bd; + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + CUBOOT_INIT(); + bamboo_init(&bd.bi_enetaddr, &bd.bi_enet1addr); +} diff --git a/arch/powerpc/boot/treeboot-bamboo.c b/arch/powerpc/boot/treeboot-bamboo.c index 1f1fe5aaac12..9eee48fc7114 100644 --- a/arch/powerpc/boot/treeboot-bamboo.c +++ b/arch/powerpc/boot/treeboot-bamboo.c @@ -12,16 +12,32 @@ #include "ops.h" #include "stdio.h" #include "44x.h" - -extern char _end[]; +#include "stdlib.h" BSS_STACK(4096); +#define PIBS_MAC0 0xfffc0400 +#define PIBS_MAC1 0xfffc0500 +char pibs_mac0[6]; +char pibs_mac1[6]; + +static void read_pibs_mac(void) +{ + unsigned long long mac64; + + mac64 = strtoull((char *)PIBS_MAC0, 0, 16); + memcpy(&pibs_mac0, (char *)&mac64+2, 6); + + mac64 = strtoull((char *)PIBS_MAC1, 0, 16); + memcpy(&pibs_mac1, (char *)&mac64+2, 6); +} + void platform_init(void) { unsigned long end_of_ram = 0x8000000; unsigned long avail_ram = end_of_ram - (unsigned long)_end; simple_alloc_init(_end, avail_ram, 32, 64); - bamboo_init(); + read_pibs_mac(); + bamboo_init((u8 *)&pibs_mac0, (u8 *)&pibs_mac1); } From 8d9ae994d8fce807fc90fb8e3b6ac8df1cc7dce6 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Sat, 15 Sep 2007 04:54:12 +1000 Subject: [PATCH 0261/2804] [POWERPC] Make partitions optional in physmap_of The latest physmap_of driver has a small error where it will fail the probe with: physmap-flash: probe of fff00000.small-flas failed with error -2 if there are no partition subnodes in the device tree and the old style binding is not used. Since partition definitions are optional, the probe should still succeed. Signed-off-by: Josh Boyer Acked-by: David Gibson --- drivers/mtd/maps/physmap_of.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 3df001bfee36..096dd47b5d5d 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -142,6 +142,8 @@ static int __devinit process_partitions(struct physmap_flash_info *info, } } else { nr_parts = parse_obsolete_partitions(dev, info, dp); + if (nr_parts == -ENOENT) + nr_parts = 0; } if (nr_parts < 0) From bf07f32d4332be50f5d4ef06307fb328257fcd1b Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Sat, 15 Sep 2007 04:54:13 +1000 Subject: [PATCH 0262/2804] [POWERPC] 4xx: Convert Walnut flash mappings to new binding A new binding for flash devices was recently introduced. This updates the Walnut DTS to use the new binding. Signed-off-by: Josh Boyer Acked-by: David Gibson --- arch/powerpc/boot/dts/walnut.dts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/boot/dts/walnut.dts b/arch/powerpc/boot/dts/walnut.dts index 27bef06db134..ec54f4e04ad6 100644 --- a/arch/powerpc/boot/dts/walnut.dts +++ b/arch/powerpc/boot/dts/walnut.dts @@ -137,6 +137,10 @@ dcr-reg = <012 2>; #address-cells = <2>; #size-cells = <1>; + /* The ranges property is supplied by the bootwrapper + * and is based on the firmware's configuration of the + * EBC bridge + */ clock-frequency = <0>; /* Filled in by zImage */ sram@0,0 { @@ -144,13 +148,16 @@ }; flash@0,80000 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "JEDEC"; + compatible = "jedec-flash"; bank-width = <1>; - partitions = <0 80000>; - partition-names = "OpenBIOS"; reg = <0 80000 80000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "OpenBIOS"; + reg = <0 80000>; + read-only; + }; }; ds1743@1,0 { From 504ca43e5e681b8ed3837f11ea458eb145a82e4e Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Sat, 15 Sep 2007 04:54:14 +1000 Subject: [PATCH 0263/2804] [POWERPC] 4xx: Convert Seqouia flash mappings to new binding A new binding for flash devices was recently introduced. This updates the Sequoia DTS to use the new binding and enabled MTD in the defconfig. Signed-off-by: Josh Boyer Acked-by: David Gibson Acked-by: Stefan Roese --- arch/powerpc/boot/dts/sequoia.dts | 38 +++++++---- arch/powerpc/configs/sequoia_defconfig | 91 +++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/boot/dts/sequoia.dts b/arch/powerpc/boot/dts/sequoia.dts index af6a56b4e5b1..b236798ce812 100644 --- a/arch/powerpc/boot/dts/sequoia.dts +++ b/arch/powerpc/boot/dts/sequoia.dts @@ -142,19 +142,35 @@ interrupt-parent = <&UIC1>; nor_flash@0,0 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "CFI"; + compatible = "amd,s29gl256n", "cfi-flash"; bank-width = <2>; - partitions = < 0 180000 - 180000 200000 - 380000 3aa0000 - 3e20000 140000 - 3f60000 40000 - 3fa0000 60000>; - partition-names = "Kernel", "ramdisk", "file system", - "kozio", "env", "u-boot"; reg = <0 000000 4000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "Kernel"; + reg = <0 180000>; + }; + partition@180000 { + label = "ramdisk"; + reg = <180000 200000>; + }; + partition@380000 { + label = "file system"; + reg = <380000 3aa0000>; + }; + partition@3e20000 { + label = "kozio"; + reg = <3e20000 140000>; + }; + partition@3f60000 { + label = "env"; + reg = <3f60000 40000>; + }; + partition@3fa0000 { + label = "u-boot"; + reg = <3fa0000 60000>; + }; }; }; diff --git a/arch/powerpc/configs/sequoia_defconfig b/arch/powerpc/configs/sequoia_defconfig index 58256625b5b8..bc7f5089a894 100644 --- a/arch/powerpc/configs/sequoia_defconfig +++ b/arch/powerpc/configs/sequoia_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.23-rc3 -# Mon Aug 27 20:19:13 2007 +# Linux kernel version: 2.6.23-rc6 +# Fri Sep 14 13:20:06 2007 # # CONFIG_PPC64 is not set @@ -146,6 +146,7 @@ CONFIG_440A=y # CONFIG_GENERIC_IOMAP is not set # CONFIG_CPU_FREQ is not set # CONFIG_CPM2 is not set +# CONFIG_FSL_ULI1575 is not set # # Kernel options @@ -317,7 +318,81 @@ CONFIG_FW_LOADER=y # CONFIG_SYS_HYPERVISOR is not set CONFIG_CONNECTOR=y CONFIG_PROC_EVENTS=y -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLKDEVS is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set CONFIG_OF_DEVICE=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y @@ -613,6 +688,15 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -671,6 +755,7 @@ CONFIG_CRC32=y # CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y From 70dea47da12932cc512e09124a836ddd3499ab39 Mon Sep 17 00:00:00 2001 From: Hollis Blanchard Date: Mon, 17 Sep 2007 05:56:47 -0500 Subject: [PATCH 0264/2804] [POWERPC] 4xx: Implement udbg_getc() for 440 Implement udbg_getc() for 440, which fixes xmon input. Signed-off-by: Hollis Blanchard Acked-by: David Gibson Signed-off-by: Josh Boyer --- arch/powerpc/kernel/udbg_16550.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 7afab5bcd61a..833a3d0bcfa7 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -206,11 +206,22 @@ static void udbg_44x_as1_putc(char c) } } +static int udbg_44x_as1_getc(void) +{ + if (udbg_comport) { + while ((as1_readb(&udbg_comport->lsr) & LSR_DR) == 0) + ; /* wait for char */ + return as1_readb(&udbg_comport->rbr); + } + return -1; +} + void __init udbg_init_44x_as1(void) { udbg_comport = (volatile struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR; udbg_putc = udbg_44x_as1_putc; + udbg_getc = udbg_44x_as1_getc; } #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ From 9a474fff4f6a5fc14ac493c48f56a14e65912cc7 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Wed, 19 Sep 2007 21:19:07 -0500 Subject: [PATCH 0265/2804] [POWERPC] Update PowerPC 4xx entry in MAINTAINERS Add myself as PowerPC 4xx maintainer and list the git tree Signed-off-by: Josh Boyer --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9c54a5ef0ba7..8f800680384d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2295,10 +2295,13 @@ L: linuxppc-embedded@ozlabs.org S: Maintained LINUX FOR POWERPC EMBEDDED PPC4XX +P: Josh Boyer +M: jwboyer@linux.vnet.ibm.com P: Matt Porter M: mporter@kernel.crashing.org W: http://www.penguinppc.org/ L: linuxppc-embedded@ozlabs.org +T: git kernel.org:/pub/scm/linux/kernel/git/jwboyer/powerpc.git S: Maintained LINUX FOR POWERPC BOOT CODE From 472b5b43bec45e7e79f86094ca9091bd9eb474ed Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Thu, 6 Sep 2007 03:30:16 +1000 Subject: [PATCH 0266/2804] [POWERPC] Add 64-bit resources support to pci_iomap The patch adds support for the 64-bit resources to the PCI iomap code. Signed-off-by: Valentine Barshak Acked-by: David Gibson Signed-off-by: Josh Boyer --- arch/powerpc/kernel/iomap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c index 2a5cf8680370..1577434f4088 100644 --- a/arch/powerpc/kernel/iomap.c +++ b/arch/powerpc/kernel/iomap.c @@ -119,8 +119,8 @@ EXPORT_SYMBOL(ioport_unmap); void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) { - unsigned long start = pci_resource_start(dev, bar); - unsigned long len = pci_resource_len(dev, bar); + resource_size_t start = pci_resource_start(dev, bar); + resource_size_t len = pci_resource_len(dev, bar); unsigned long flags = pci_resource_flags(dev, bar); if (!len) From e52f5677bf6954dbd128a2d659d77a85ced55d30 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 19 Sep 2007 03:27:52 +1000 Subject: [PATCH 0267/2804] [POWERPC] 4xx: Fix Bamboo MAL0 dts entry. According to PowerPC 440EP documentation, MAL0 consists of 6 channels (4 transmit channels and 2 receive channels) This patch fixes Bamboo DTS MAL0 "num-rx-chans" entry. Signed-off-by: Valentine Barshak Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/bamboo.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/boot/dts/bamboo.dts b/arch/powerpc/boot/dts/bamboo.dts index bdd56b0e9460..a88ae3d218a5 100644 --- a/arch/powerpc/boot/dts/bamboo.dts +++ b/arch/powerpc/boot/dts/bamboo.dts @@ -94,7 +94,7 @@ compatible = "ibm,mcmal-440ep", "ibm,mcmal-440gp", "ibm,mcmal"; dcr-reg = <180 62>; num-tx-chans = <4>; - num-rx-chans = <4>; + num-rx-chans = <2>; interrupt-parent = <&MAL0>; interrupts = <0 1 2 3 4>; #interrupt-cells = <1>; From bd0076cc330f303905018a17d9dcfbabde497572 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 19 Sep 2007 03:29:13 +1000 Subject: [PATCH 0268/2804] [POWERPC] 4xx: Fix Sequoia MAL0 and EMAC dts entries. According to PowerPC 440EPx documentation, MAL0 is comprised of four channels (two transmit and two receive). Each channel is dedicated to one of two EMAC cores. This patch fixes Sequoia DTS MAL0 entry and EMAC entries, assigning correct channel numbers to EMACs. Signed-off-by: Valentine Barshak Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/sequoia.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/boot/dts/sequoia.dts b/arch/powerpc/boot/dts/sequoia.dts index b236798ce812..36be75b04de1 100644 --- a/arch/powerpc/boot/dts/sequoia.dts +++ b/arch/powerpc/boot/dts/sequoia.dts @@ -107,8 +107,8 @@ MAL0: mcmal { compatible = "ibm,mcmal-440epx", "ibm,mcmal2"; dcr-reg = <180 62>; - num-tx-chans = <4>; - num-rx-chans = <4>; + num-tx-chans = <2>; + num-rx-chans = <2>; interrupt-parent = <&MAL0>; interrupts = <0 1 2 3 4>; #interrupt-cells = <1>; @@ -255,7 +255,7 @@ reg = ; local-mac-address = [000000000000]; mal-device = <&MAL0>; - mal-tx-channel = <0 1>; + mal-tx-channel = <0>; mal-rx-channel = <0>; cell-index = <0>; max-frame-size = <5dc>; @@ -281,7 +281,7 @@ reg = ; local-mac-address = [000000000000]; mal-device = <&MAL0>; - mal-tx-channel = <2 3>; + mal-tx-channel = <1>; mal-rx-channel = <1>; cell-index = <1>; max-frame-size = <5dc>; From c4d5e375470862fd741f93bf0686d7ac2f7fdce4 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 20 Sep 2007 11:22:25 +1000 Subject: [PATCH 0269/2804] [POWERPC] Cleanups for physmap_of.c (v2) This patch includes a whole batch of smallish cleanups for drivers/mtd/physmap_of.c. - A bunch of uneeded #includes are removed - We switch to the modern linux/of.h etc. in place of asm/prom.h - Use some helper macros to avoid some ugly inline #ifdefs - A few lines of unreachable code are removed - A number of indentation / line-wrapping fixes - More consistent use of kernel idioms such as if (!p) instead of if (p == NULL) - Clarify some printk()s and other informative strings. - parse_obsolete_partitions() now returns 0 if no partition information is found, instead of returning -ENOENT which the caller had to handle specially. - (the big one) Despite the name, this driver really has nothing to do with drivers/mtd/physmap.c. The fact that the flash chips must be physically direct mapped is a constrant, but doesn't really say anything about the actual purpose of this driver, which is to instantiate MTD devices based on information from the device tree. Therefore the physmap name is replaced everywhere within the file with "of_flash". The file itself and the Kconfig option is not renamed for now (so that the diff is actually a diff). That can come later. Signed-off-by: David Gibson Signed-off-by: Josh Boyer --- drivers/mtd/maps/physmap_of.c | 224 +++++++++++++++------------------- 1 file changed, 99 insertions(+), 125 deletions(-) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 096dd47b5d5d..cf75a566442e 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -1,5 +1,5 @@ /* - * Normal mappings of chips in physical memory for OF devices + * Flash mappings described by the OF (or flattened) device tree * * Copyright (C) 2006 MontaVista Software Inc. * Author: Vitaly Wool @@ -15,20 +15,15 @@ #include #include -#include #include -#include #include #include #include #include -#include -#include -#include -#include -#include +#include +#include -struct physmap_flash_info { +struct of_flash { struct mtd_info *mtd; struct map_info map; struct resource *res; @@ -38,8 +33,10 @@ struct physmap_flash_info { }; #ifdef CONFIG_MTD_PARTITIONS +#define OF_FLASH_PARTS(info) ((info)->parts) + static int parse_obsolete_partitions(struct of_device *dev, - struct physmap_flash_info *info, + struct of_flash *info, struct device_node *dp) { int i, plen, nr_parts; @@ -50,17 +47,15 @@ static int parse_obsolete_partitions(struct of_device *dev, part = of_get_property(dp, "partitions", &plen); if (!part) - return -ENOENT; + return 0; /* No partitions found */ dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); nr_parts = plen / sizeof(part[0]); - info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL); - if (!info->parts) { - printk(KERN_ERR "Can't allocate the flash partition data!\n"); + info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL); + if (!info->parts) return -ENOMEM; - } names = of_get_property(dp, "partition-names", &plen); @@ -86,8 +81,8 @@ static int parse_obsolete_partitions(struct of_device *dev, return nr_parts; } -static int __devinit process_partitions(struct physmap_flash_info *info, - struct of_device *dev) +static int __devinit parse_partitions(struct of_flash *info, + struct of_device *dev) { const char *partname; static const char *part_probe_types[] @@ -109,89 +104,68 @@ static int __devinit process_partitions(struct physmap_flash_info *info, for (pp = dp->child; pp; pp = pp->sibling) nr_parts++; - if (nr_parts) { - info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), - GFP_KERNEL); - if (!info->parts) { - printk(KERN_ERR "Can't allocate the flash partition data!\n"); - return -ENOMEM; + if (nr_parts == 0) + return parse_obsolete_partitions(dev, info, dp); + + info->parts = kzalloc(nr_parts * sizeof(*info->parts), + GFP_KERNEL); + if (!info->parts) + return -ENOMEM; + + for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) { + const u32 *reg; + int len; + + reg = of_get_property(pp, "reg", &len); + if (!reg || (len != 2*sizeof(u32))) { + dev_err(&dev->dev, "Invalid 'reg' on %s\n", + dp->full_name); + kfree(info->parts); + info->parts = NULL; + return -EINVAL; } + info->parts[i].offset = reg[0]; + info->parts[i].size = reg[1]; - for (pp = dp->child, i = 0 ; pp; pp = pp->sibling, i++) { - const u32 *reg; - int len; + partname = of_get_property(pp, "label", &len); + if (!partname) + partname = of_get_property(pp, "name", &len); + info->parts[i].name = (char *)partname; - reg = of_get_property(pp, "reg", &len); - if (!reg || (len != 2*sizeof(u32))) { - dev_err(&dev->dev, "Invalid 'reg' on %s\n", - dp->full_name); - kfree(info->parts); - info->parts = NULL; - return -EINVAL; - } - info->parts[i].offset = reg[0]; - info->parts[i].size = reg[1]; - - partname = of_get_property(pp, "label", &len); - if (!partname) - partname = of_get_property(pp, "name", &len); - info->parts[i].name = (char *)partname; - - if (of_get_property(pp, "read-only", &len)) - info->parts[i].mask_flags = MTD_WRITEABLE; - } - } else { - nr_parts = parse_obsolete_partitions(dev, info, dp); - if (nr_parts == -ENOENT) - nr_parts = 0; + if (of_get_property(pp, "read-only", &len)) + info->parts[i].mask_flags = MTD_WRITEABLE; } - if (nr_parts < 0) - return nr_parts; - - if (nr_parts > 0) - add_mtd_partitions(info->mtd, info->parts, nr_parts); - else - add_mtd_device(info->mtd); - - return 0; + return nr_parts; } #else /* MTD_PARTITIONS */ -static int __devinit process_partitions(struct physmap_flash_info *info, - struct device_node *dev) -{ - add_mtd_device(info->mtd); - return 0; -} +#define OF_FLASH_PARTS(info) (0) +#define parse_partitions(info, dev) (0) #endif /* MTD_PARTITIONS */ -static int of_physmap_remove(struct of_device *dev) +static int of_flash_remove(struct of_device *dev) { - struct physmap_flash_info *info; + struct of_flash *info; info = dev_get_drvdata(&dev->dev); - if (info == NULL) + if (!info) return 0; dev_set_drvdata(&dev->dev, NULL); - if (info->mtd != NULL) { -#ifdef CONFIG_MTD_PARTITIONS - if (info->parts) { + if (info->mtd) { + if (OF_FLASH_PARTS(info)) { del_mtd_partitions(info->mtd); - kfree(info->parts); + kfree(OF_FLASH_PARTS(info)); } else { del_mtd_device(info->mtd); } -#else - del_mtd_device(info->mtd); -#endif map_destroy(info->mtd); } - if (info->map.virt != NULL) + if (info->map.virt) iounmap(info->map.virt); - if (info->res != NULL) { + if (info->res) { release_resource(info->res); kfree(info->res); } @@ -229,52 +203,49 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev, return do_map_probe("jedec_probe", map); } else { if (strcmp(of_probe, "ROM") != 0) - dev_dbg(&dev->dev, "obsolete_probe: don't know probe type " - "'%s', mapping as rom\n", of_probe); + dev_warn(&dev->dev, "obsolete_probe: don't know probe " + "type '%s', mapping as rom\n", of_probe); return do_map_probe("mtd_rom", map); } } -static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit of_flash_probe(struct of_device *dev, + const struct of_device_id *match) { struct device_node *dp = dev->node; struct resource res; - struct physmap_flash_info *info; - const char *probe_type = (const char *)match->data; + struct of_flash *info; + const char *probe_type = match->data; const u32 *width; int err; + err = -ENXIO; if (of_address_to_resource(dp, 0, &res)) { - dev_err(&dev->dev, "Can't get the flash mapping!\n"); - err = -EINVAL; + dev_err(&dev->dev, "Can't get IO address from device tree\n"); goto err_out; } - dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n", - (unsigned long long)res.end - res.start + 1, - (unsigned long long)res.start); + dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", + (unsigned long long)res.start, (unsigned long long)res.end); - info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); - if (info == NULL) { - err = -ENOMEM; + err = -ENOMEM; + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) goto err_out; - } memset(info, 0, sizeof(*info)); dev_set_drvdata(&dev->dev, info); + err = -EBUSY; info->res = request_mem_region(res.start, res.end - res.start + 1, - dev->dev.bus_id); - if (info->res == NULL) { - dev_err(&dev->dev, "Could not reserve memory region\n"); - err = -ENOMEM; + dev->dev.bus_id); + if (!info->res) goto err_out; - } + err = -ENXIO; width = of_get_property(dp, "bank-width", NULL); - if (width == NULL) { - dev_err(&dev->dev, "Can't get the flash bank width!\n"); - err = -EINVAL; + if (!width) { + dev_err(&dev->dev, "Can't get bank width from device tree\n"); goto err_out; } @@ -283,10 +254,10 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev info->map.size = res.end - res.start + 1; info->map.bankwidth = *width; + err = -ENOMEM; info->map.virt = ioremap(info->map.phys, info->map.size); - if (info->map.virt == NULL) { - dev_err(&dev->dev, "Failed to ioremap flash region\n"); - err = EIO; + if (!info->map.virt) { + dev_err(&dev->dev, "Failed to ioremap() flash region\n"); goto err_out; } @@ -297,25 +268,30 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev else info->mtd = obsolete_probe(dev, &info->map); - if (info->mtd == NULL) { - dev_err(&dev->dev, "map_probe failed\n"); - err = -ENXIO; + err = -ENXIO; + if (!info->mtd) { + dev_err(&dev->dev, "do_map_probe() failed\n"); goto err_out; } info->mtd->owner = THIS_MODULE; - return process_partitions(info, dev); + err = parse_partitions(info, dev); + if (err < 0) + goto err_out; -err_out: - of_physmap_remove(dev); - return err; + if (err > 0) + add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err); + else + add_mtd_device(info->mtd); return 0; - +err_out: + of_flash_remove(dev); + return err; } -static struct of_device_id of_physmap_match[] = { +static struct of_device_id of_flash_match[] = { { .compatible = "cfi-flash", .data = (void *)"cfi_probe", @@ -337,30 +313,28 @@ static struct of_device_id of_physmap_match[] = { }, { }, }; +MODULE_DEVICE_TABLE(of, of_flash_match); -MODULE_DEVICE_TABLE(of, of_physmap_match); - - -static struct of_platform_driver of_physmap_flash_driver = { - .name = "physmap-flash", - .match_table = of_physmap_match, - .probe = of_physmap_probe, - .remove = of_physmap_remove, +static struct of_platform_driver of_flash_driver = { + .name = "of-flash", + .match_table = of_flash_match, + .probe = of_flash_probe, + .remove = of_flash_remove, }; -static int __init of_physmap_init(void) +static int __init of_flash_init(void) { - return of_register_platform_driver(&of_physmap_flash_driver); + return of_register_platform_driver(&of_flash_driver); } -static void __exit of_physmap_exit(void) +static void __exit of_flash_exit(void) { - of_unregister_platform_driver(&of_physmap_flash_driver); + of_unregister_platform_driver(&of_flash_driver); } -module_init(of_physmap_init); -module_exit(of_physmap_exit); +module_init(of_flash_init); +module_exit(of_flash_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Vitaly Wool "); -MODULE_DESCRIPTION("Configurable MTD map driver for OF"); +MODULE_DESCRIPTION("Device tree based MTD map driver"); From e4533b243e5e0c3a26287a902a1ed0f8f5b1cec0 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 5 Apr 2007 00:19:43 +1000 Subject: [PATCH 0270/2804] [POWERPC] Optionally use new device number for pmac_zilog This adds the option for the pmac_zilog driver to use the major/minor numbers recently allocated specifically for it (/dev/ttyPZn) instead of the /dev/ttySn numbers. The advantage of doing this is that it allows the pmac_zilog and 8250 drivers to coexist. The disadvantage of doing this is that it is a user-visible ABI change and it will break existing working setups on powermacs, and could be confusing to users. Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras --- drivers/serial/Kconfig | 25 +++++++++++++++++++++++++ drivers/serial/pmac_zilog.c | 20 +++++++++++++++----- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 81b52b7cca21..d6ae38e55d01 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -986,6 +986,31 @@ config SERIAL_PMACZILOG PowerMac machines. Say Y or M if you want to be able to these serial ports. +config SERIAL_PMACZILOG_TTYS + bool "Use ttySn device nodes for Zilog z85c30" + depends on SERIAL_PMACZILOG + help + The pmac_zilog driver for the z85C30 chip on many powermacs + historically used the device numbers for /dev/ttySn. The + 8250 serial port driver also uses these numbers, which means + the two drivers being unable to coexist; you could not use + both z85C30 and 8250 type ports at the same time. + + If this option is not selected, the pmac_zilog driver will + use the device numbers allocated for /dev/ttyPZn. This allows + the pmac_zilog and 8250 drivers to co-exist, but may cause + existing userspace setups to break. Programs that need to + access the built-in serial ports on powermacs will need to + be reconfigured to use /dev/ttyPZn instead of /dev/ttySn. + + If you enable this option, any z85c30 ports in the system will + be registered as ttyS0 onwards as in the past, and you will be + unable to use the 8250 module for PCMCIA or other 16C550-style + UARTs. + + Say N unless you need the z85c30 ports on your powermac + to appear as /dev/ttySn. + config SERIAL_PMACZILOG_CONSOLE bool "Console on PowerMac z85c30 serial port" depends on SERIAL_PMACZILOG=y diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index f793ac212672..794bd0f50d73 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -88,6 +88,16 @@ MODULE_LICENSE("GPL"); #define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg) +#ifdef CONFIG_SERIAL_PMACZILOG_TTYS +#define PMACZILOG_MAJOR TTY_MAJOR +#define PMACZILOG_MINOR 64 +#define PMACZILOG_NAME "ttyS" +#else +#define PMACZILOG_MAJOR 204 +#define PMACZILOG_MINOR 192 +#define PMACZILOG_NAME "ttyPZ" +#endif + /* * For the sake of early serial console, we can do a pre-probe @@ -99,9 +109,10 @@ static DEFINE_MUTEX(pmz_irq_mutex); static struct uart_driver pmz_uart_reg = { .owner = THIS_MODULE, - .driver_name = "ttyS", - .dev_name = "ttyS", - .major = TTY_MAJOR, + .driver_name = PMACZILOG_NAME, + .dev_name = PMACZILOG_NAME, + .major = PMACZILOG_MAJOR, + .minor = PMACZILOG_MINOR, }; @@ -1778,7 +1789,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c static int __init pmz_console_setup(struct console *co, char *options); static struct console pmz_console = { - .name = "ttyS", + .name = PMACZILOG_NAME, .write = pmz_console_write, .device = uart_console_device, .setup = pmz_console_setup, @@ -1802,7 +1813,6 @@ static int __init pmz_register(void) pmz_uart_reg.nr = pmz_ports_count; pmz_uart_reg.cons = PMACZILOG_CONSOLE; - pmz_uart_reg.minor = 64; /* * Register this driver with the serial core From 9b41fcb0eb890009f9de3df76fcdb2ba77314a4b Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Tue, 15 May 2007 05:52:22 +1000 Subject: [PATCH 0271/2804] [POWERPC] Add Marvell mv64x60 udbg putc/getc functions Commit 69331af, "Fixes and cleanups for earlyprintk aka boot console", resulted in printk output prior to the initialization of the mpsc console driver not being printed. That commit causes the mpsc's CON_PRINTBUFFER flag to be cleared since udbg should have printed the previous output. I guess we can no longer ignore udbg. :) This patch provides udbg_putc() and udbg_getc() functions for the Marvell mv64x60 chips. These functions are enabled if an mv64x60 port is to be used as the console as determined from the device tree. Signed-off-by: Dale Farnsworth Acked-by: Mark A. Greer Signed-off-by: Paul Mackerras --- .../powerpc/platforms/embedded6xx/prpmc2800.c | 1 + arch/powerpc/sysdev/Makefile | 3 +- arch/powerpc/sysdev/mv64x60.h | 1 + arch/powerpc/sysdev/mv64x60_udbg.c | 152 ++++++++++++++++++ 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/sysdev/mv64x60_udbg.c diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c index 54675648d6de..e484cac75095 100644 --- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c +++ b/arch/powerpc/platforms/embedded6xx/prpmc2800.c @@ -151,6 +151,7 @@ define_machine(prpmc2800){ .name = prpmc2800_platform_name, .probe = prpmc2800_probe, .setup_arch = prpmc2800_setup_arch, + .init_early = mv64x60_init_early, .show_cpuinfo = prpmc2800_show_cpuinfo, .init_IRQ = mv64x60_init_irq, .get_irq = mv64x60_get_irq, diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 08ce31e612c2..ed41dc0a310f 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -16,7 +16,8 @@ obj-$(CONFIG_FSL_PCI) += fsl_pci.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ mv64x60-$(CONFIG_PCI) += mv64x60_pci.o -obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o +obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \ + mv64x60_udbg.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o obj-$(CONFIG_AXON_RAM) += axonram.o diff --git a/arch/powerpc/sysdev/mv64x60.h b/arch/powerpc/sysdev/mv64x60.h index 2ff0b4ef2681..4f618fa465c0 100644 --- a/arch/powerpc/sysdev/mv64x60.h +++ b/arch/powerpc/sysdev/mv64x60.h @@ -7,5 +7,6 @@ extern void __init mv64x60_init_irq(void); extern unsigned int mv64x60_get_irq(void); extern void __init mv64x60_pci_init(void); +extern void __init mv64x60_init_early(void); #endif /* __MV64X60_H__ */ diff --git a/arch/powerpc/sysdev/mv64x60_udbg.c b/arch/powerpc/sysdev/mv64x60_udbg.c new file mode 100644 index 000000000000..367e7b13ec00 --- /dev/null +++ b/arch/powerpc/sysdev/mv64x60_udbg.c @@ -0,0 +1,152 @@ +/* + * udbg serial input/output routines for the Marvell MV64x60 (Discovery). + * + * Author: Dale Farnsworth + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include + +#include + +#define MPSC_0_CR1_OFFSET 0x000c + +#define MPSC_0_CR2_OFFSET 0x0010 +#define MPSC_CHR_2_TCS (1 << 9) + +#define MPSC_0_CHR_10_OFFSET 0x0030 + +#define MPSC_INTR_CAUSE_OFF_0 0x0004 +#define MPSC_INTR_CAUSE_OFF_1 0x000c +#define MPSC_INTR_CAUSE_RCC (1<<6) + +static void __iomem *mpsc_base; +static void __iomem *mpsc_intr_cause; + +static void mv64x60_udbg_putc(char c) +{ + if (c == '\n') + mv64x60_udbg_putc('\r'); + + while(in_le32(mpsc_base + MPSC_0_CR2_OFFSET) & MPSC_CHR_2_TCS) + ; + out_le32(mpsc_base + MPSC_0_CR1_OFFSET, c); + out_le32(mpsc_base + MPSC_0_CR2_OFFSET, MPSC_CHR_2_TCS); +} + +static int mv64x60_udbg_testc(void) +{ + return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0; +} + +static int mv64x60_udbg_getc(void) +{ + int cause = 0; + int c; + + while (!mv64x60_udbg_testc()) + ; + + c = in_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2); + out_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2, c); + out_le32(mpsc_intr_cause, cause & ~MPSC_INTR_CAUSE_RCC); + return c; +} + +static int mv64x60_udbg_getc_poll(void) +{ + if (!mv64x60_udbg_testc()) + return -1; + + return mv64x60_udbg_getc(); +} + +static void mv64x60_udbg_init(void) +{ + struct device_node *np, *mpscintr, *stdout = NULL; + const char *path; + const phandle *ph; + struct resource r[2]; + const int *block_index; + int intr_cause_offset; + int err; + + path = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (!path) + return; + + stdout = of_find_node_by_path(path); + if (!stdout) + return; + + for (np = NULL; + (np = of_find_compatible_node(np, "serial", "marvell,mpsc")); ) + if (np == stdout) + break; + + of_node_put(stdout); + if (!np) + return; + + block_index = of_get_property(np, "block-index", NULL); + if (!block_index) + goto error; + + switch (*block_index) { + case 0: + intr_cause_offset = MPSC_INTR_CAUSE_OFF_0; + break; + case 1: + intr_cause_offset = MPSC_INTR_CAUSE_OFF_1; + break; + default: + goto error; + } + + err = of_address_to_resource(np, 0, &r[0]); + if (err) + goto error; + + ph = of_get_property(np, "mpscintr", NULL); + mpscintr = of_find_node_by_phandle(*ph); + if (!mpscintr) + goto error; + + err = of_address_to_resource(mpscintr, 0, &r[1]); + of_node_put(mpscintr); + if (err) + goto error; + + of_node_put(np); + + mpsc_base = ioremap(r[0].start, r[0].end - r[0].start + 1); + if (!mpsc_base) + return; + + mpsc_intr_cause = ioremap(r[1].start, r[1].end - r[1].start + 1); + if (!mpsc_intr_cause) { + iounmap(mpsc_base); + return; + } + mpsc_intr_cause += intr_cause_offset; + + udbg_putc = mv64x60_udbg_putc; + udbg_getc = mv64x60_udbg_getc; + udbg_getc_poll = mv64x60_udbg_getc_poll; + + return; + +error: + of_node_put(np); +} + +void mv64x60_init_early(void) +{ + mv64x60_udbg_init(); +} From fc624eae3278330f484669dd8fe85535def7eb78 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 15 Jul 2007 13:36:09 +1000 Subject: [PATCH 0272/2804] [POWERPC] Use __attribute__ in asm-powerpc Pretty much everyone uses "__attribute__" or "attribute", no one uses "__attribute". This tweaks the three places in asm-powerpc where this comes up. While only asm-powerpc/types.h is interesting (for userspace), I did asm-powerpc/processor.h as well for consistency. Signed-off-by: Mike Frysinger Signed-off-by: Paul Mackerras --- include/asm-powerpc/processor.h | 4 ++-- include/asm-powerpc/types.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index e28b10805159..dba7c948189d 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h @@ -145,9 +145,9 @@ struct thread_struct { unsigned long dabr; /* Data address breakpoint register */ #ifdef CONFIG_ALTIVEC /* Complete AltiVec register set */ - vector128 vr[32] __attribute((aligned(16))); + vector128 vr[32] __attribute__((aligned(16))); /* AltiVec status */ - vector128 vscr __attribute((aligned(16))); + vector128 vscr __attribute__((aligned(16))); unsigned long vrsave; int used_vr; /* set if process has used altivec */ #endif /* CONFIG_ALTIVEC */ diff --git a/include/asm-powerpc/types.h b/include/asm-powerpc/types.h index 3b363757a2bb..a584341c87e3 100644 --- a/include/asm-powerpc/types.h +++ b/include/asm-powerpc/types.h @@ -48,7 +48,7 @@ typedef unsigned long long __u64; typedef struct { __u32 u[4]; -} __attribute((aligned(16))) __vector128; +} __attribute__((aligned(16))) __vector128; #endif /* __ASSEMBLY__ */ From 555ddbb4e2191c8823df2d61525218ac39481385 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Tue, 17 Jul 2007 06:53:09 +1000 Subject: [PATCH 0273/2804] [POWERPC] adbhid: Enable KEY_FN key reporting When a Fn key is used in combination with another key in ADB keyboards it will generate a Fn event and then a second event that can be a different key than pressed (Fn + F1 for instance can generate Fn + brightness down if it's configured like that). This enables the reporting of the Fn key to the input system. As Fn is a dead key for most purposes, it's useful to report it so applications can make use of it. One example is apple_mouse (https://jake.ruivo.org/uinputd/trunk/apple_mouse/) that emulates the second and third keys using a combination of keyboard keys and the mouse button. Other applications may use the KEY_FN as a modifier as well. I've been updating and using this patch for months without problems. Signed-off-by: Aristeu Rozanski Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/macintosh/adbhid.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index b46817f699f1..48d17bf6c927 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -70,7 +70,7 @@ static struct notifier_block adbhid_adb_notifier = { #define ADB_KEY_POWER_OLD 0x7e #define ADB_KEY_POWER 0x7f -u8 adb_to_linux_keycodes[128] = { +u16 adb_to_linux_keycodes[128] = { /* 0x00 */ KEY_A, /* 30 */ /* 0x01 */ KEY_S, /* 31 */ /* 0x02 */ KEY_D, /* 32 */ @@ -134,7 +134,7 @@ u8 adb_to_linux_keycodes[128] = { /* 0x3c */ KEY_RIGHT, /* 106 */ /* 0x3d */ KEY_DOWN, /* 108 */ /* 0x3e */ KEY_UP, /* 103 */ - /* 0x3f */ 0, + /* 0x3f */ KEY_FN, /* 0x1d0 */ /* 0x40 */ 0, /* 0x41 */ KEY_KPDOT, /* 83 */ /* 0x42 */ 0, @@ -208,7 +208,7 @@ struct adbhid { int original_handler_id; int current_handler_id; int mouse_kind; - unsigned char *keycode; + u16 *keycode; char name[64]; char phys[32]; int flags; @@ -275,7 +275,7 @@ static void adbhid_input_keycode(int id, int keycode, int repeat) { struct adbhid *ahid = adbhid[id]; - int up_flag; + int up_flag, key; up_flag = (keycode & 0x80); keycode &= 0x7f; @@ -321,8 +321,7 @@ adbhid_input_keycode(int id, int keycode, int repeat) } } else ahid->flags |= FLAG_FN_KEY_PRESSED; - /* Swallow the key press */ - return; + break; case ADB_KEY_DEL: /* Emulate Fn+delete = forward delete */ if (ahid->flags & FLAG_FN_KEY_PRESSED) { @@ -336,9 +335,9 @@ adbhid_input_keycode(int id, int keycode, int repeat) #endif /* CONFIG_PPC_PMAC */ } - if (adbhid[id]->keycode[keycode]) { - input_report_key(adbhid[id]->input, - adbhid[id]->keycode[keycode], !up_flag); + key = adbhid[id]->keycode[keycode]; + if (key) { + input_report_key(adbhid[id]->input, key, !up_flag); input_sync(adbhid[id]->input); } else printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, @@ -757,8 +756,8 @@ adbhid_input_register(int id, int default_id, int original_handler_id, input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); input_dev->event = adbhid_kbd_event; - input_dev->keycodemax = 127; - input_dev->keycodesize = 1; + input_dev->keycodemax = KEY_FN; + input_dev->keycodesize = sizeof(hid->keycode[0]); break; case ADB_MOUSE: From 20b31b53ea87e598ea8159f109b4217ad185fce5 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 18 Jul 2007 23:36:36 +1000 Subject: [PATCH 0274/2804] [POWERPC] Prevent direct inclusion of . Signed-off-by: Robert P. J. Day Signed-off-by: Paul Mackerras --- arch/ppc/syslib/ocp.c | 2 +- include/asm-powerpc/rwsem.h | 4 ++++ include/asm-ppc/ocp.h | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/ppc/syslib/ocp.c b/arch/ppc/syslib/ocp.c index 491fe9a57229..3f5be2c5ce99 100644 --- a/arch/ppc/syslib/ocp.c +++ b/arch/ppc/syslib/ocp.c @@ -44,11 +44,11 @@ #include #include #include +#include #include #include #include -#include #include //#define DBG(x) printk x diff --git a/include/asm-powerpc/rwsem.h b/include/asm-powerpc/rwsem.h index e929145e1e46..cefc14728cc5 100644 --- a/include/asm-powerpc/rwsem.h +++ b/include/asm-powerpc/rwsem.h @@ -1,6 +1,10 @@ #ifndef _ASM_POWERPC_RWSEM_H #define _ASM_POWERPC_RWSEM_H +#ifndef _LINUX_RWSEM_H +#error "Please don't include directly, use instead." +#endif + #ifdef __KERNEL__ /* diff --git a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h index 16dbc7d17450..1379a4f76de3 100644 --- a/include/asm-ppc/ocp.h +++ b/include/asm-ppc/ocp.h @@ -27,10 +27,10 @@ #include #include #include +#include #include #include -#include #include #ifdef CONFIG_PPC_OCP From 3e61576b2ac930b9d1fa2c8d077552f7e7709b3c Mon Sep 17 00:00:00 2001 From: Meelis Roos Date: Wed, 25 Jul 2007 22:17:43 +1000 Subject: [PATCH 0275/2804] [POWERPC] Fix ppc kernels after build-id addition This patch fixes arch/ppc kernels, at least for prep subarch, after build-id addition. Without this, kernels were 3 times the size and bootloader refused to load them. Now they are back to normal again. Tested only with Roland McGrath's "Use LDFLAGS_MODULE only for .ko links" patch applied - boots and works fine. Signed-off-by: Meelis Roos Signed-off-by: Paul Mackerras --- arch/ppc/kernel/vmlinux.lds.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S index c0aac3ff9e91..98c1212674f6 100644 --- a/arch/ppc/kernel/vmlinux.lds.S +++ b/arch/ppc/kernel/vmlinux.lds.S @@ -91,6 +91,8 @@ SECTIONS . = ALIGN(8192); .data.init_task : { *(.data.init_task) } + NOTES + . = ALIGN(4096); __init_begin = .; .init.text : { From ad25a4cca7f21b53e3af8303d922a87c910677d7 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 31 Aug 2007 06:26:24 +1000 Subject: [PATCH 0276/2804] [POWERPC] mpc8349: Add linux,network-index to ethernet nodes in device tree cuImage needs to know the logical index of the ethernet devices in order to assign mac addresses. This adds the needed properties. Signed-off-by: Grant Likely Acked-by: David Gibson CC: Scott Wood CC: Kumar Gala CC: Timur Tabi Signed-off-by: Paul Mackerras --- arch/powerpc/boot/dts/mpc8349emitx.dts | 2 ++ arch/powerpc/boot/dts/mpc8349emitxgp.dts | 1 + arch/powerpc/boot/dts/mpc834x_mds.dts | 2 ++ 3 files changed, 5 insertions(+) diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index 67781601b6b3..f5c3086bcb5d 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -139,6 +139,7 @@ interrupts = <20 8 21 8 22 8>; interrupt-parent = < &ipic >; phy-handle = < &phy1c >; + linux,network-index = <0>; }; ethernet@25000 { @@ -158,6 +159,7 @@ interrupts = <23 8 24 8 25 8>; interrupt-parent = < &ipic >; phy-handle = < &phy1f >; + linux,network-index = <1>; }; serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index fa852ba1b6ba..36a27607f766 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -114,6 +114,7 @@ interrupts = <20 8 21 8 22 8>; interrupt-parent = < &ipic >; phy-handle = < &phy1c >; + linux,network-index = <0>; }; serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index 1b8882e20040..c27e2fff5d58 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -144,6 +144,7 @@ interrupts = <20 8 21 8 22 8>; interrupt-parent = < &ipic >; phy-handle = < &phy0 >; + linux,network-index = <0>; }; ethernet@25000 { @@ -163,6 +164,7 @@ interrupts = <23 8 24 8 25 8>; interrupt-parent = < &ipic >; phy-handle = < &phy1 >; + linux,network-index = <1>; }; serial@4500 { From 85498ae87c7d789de613b7e21bd539577142c3cb Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 1 Sep 2007 03:34:37 +1000 Subject: [PATCH 0277/2804] [POWERPC] mpc5200: Add cuimage support for mpc5200 boards Signed-off-by: Grant Likely Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 5 ++- arch/powerpc/boot/cuboot-52xx.c | 59 ++++++++++++++++++++++++ arch/powerpc/boot/mpc52xx-psc.c | 69 +++++++++++++++++++++++++++++ arch/powerpc/boot/ops.h | 1 + arch/powerpc/boot/serial.c | 2 + arch/powerpc/platforms/52xx/Kconfig | 1 + 6 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/boot/cuboot-52xx.c create mode 100644 arch/powerpc/boot/mpc52xx-psc.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index c1582b62911c..b63e423428c7 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -45,8 +45,8 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \ - cpm-serial.c stdlib.c -src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ + cpm-serial.c stdlib.c mpc52xx-psc.c +src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c @@ -143,6 +143,7 @@ image-$(CONFIG_DEFAULT_UIMAGE) += uImage ifneq ($(CONFIG_DEVICE_TREE),"") image-$(CONFIG_PPC_8xx) += cuImage.8xx image-$(CONFIG_8260) += cuImage.pq2 +image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx image-$(CONFIG_PPC_83xx) += cuImage.83xx image-$(CONFIG_PPC_85xx) += cuImage.85xx image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony diff --git a/arch/powerpc/boot/cuboot-52xx.c b/arch/powerpc/boot/cuboot-52xx.c new file mode 100644 index 000000000000..9256a26d40e4 --- /dev/null +++ b/arch/powerpc/boot/cuboot-52xx.c @@ -0,0 +1,59 @@ +/* + * Old U-boot compatibility for MPC5200 + * + * Author: Grant Likely + * + * Copyright (c) 2007 Secret Lab Technologies Ltd. + * Copyright (c) 2007 Freescale Semiconductor, 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 "ops.h" +#include "stdio.h" +#include "io.h" +#include "cuboot.h" + +#define TARGET_PPC_MPC52xx +#include "ppcboot.h" + +static bd_t bd; + +static void platform_fixups(void) +{ + void *soc, *reg; + int div; + u32 sysfreq; + + + dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); + dt_fixup_mac_addresses(bd.bi_enetaddr); + dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); + + /* Unfortunately, the specific model number is encoded in the + * soc node name in existing dts files -- once that is fixed, + * this can do a simple path lookup. + */ + soc = find_node_by_devtype(NULL, "soc"); + if (soc) { + setprop(soc, "bus-frequency", &bd.bi_ipbfreq, + sizeof(bd.bi_ipbfreq)); + + if (!dt_xlate_reg(soc, 0, (void*)®, NULL)) + return; + div = in_8(reg + 0x204) & 0x0020 ? 8 : 4; + sysfreq = bd.bi_busfreq * div; + setprop(soc, "system-frequency", &sysfreq, sizeof(sysfreq)); + } +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + CUBOOT_INIT(); + ft_init(_dtb_start, _dtb_end - _dtb_start, 32); + serial_console_init(); + platform_ops.fixups = platform_fixups; +} diff --git a/arch/powerpc/boot/mpc52xx-psc.c b/arch/powerpc/boot/mpc52xx-psc.c new file mode 100644 index 000000000000..1074626e6a37 --- /dev/null +++ b/arch/powerpc/boot/mpc52xx-psc.c @@ -0,0 +1,69 @@ +/* + * MPC5200 PSC serial console support. + * + * Author: Grant Likely + * + * Copyright (c) 2007 Secret Lab Technologies Ltd. + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * + * It is assumed that the firmware (or the platform file) has already set + * up the port. + */ + +#include "types.h" +#include "io.h" +#include "ops.h" + +/* Programmable Serial Controller (PSC) status register bits */ +#define MPC52xx_PSC_SR 0x04 +#define MPC52xx_PSC_SR_RXRDY 0x0100 +#define MPC52xx_PSC_SR_RXFULL 0x0200 +#define MPC52xx_PSC_SR_TXRDY 0x0400 +#define MPC52xx_PSC_SR_TXEMP 0x0800 + +#define MPC52xx_PSC_BUFFER 0x0C + +static void *psc; + +static int psc_open(void) +{ + /* Assume the firmware has already configured the PSC into + * uart mode */ + return 0; +} + +static void psc_putc(unsigned char c) +{ + while (!(in_be16(psc + MPC52xx_PSC_SR) & MPC52xx_PSC_SR_TXRDY)) ; + out_8(psc + MPC52xx_PSC_BUFFER, c); +} + +static unsigned char psc_tstc(void) +{ + return (in_be16(psc + MPC52xx_PSC_SR) & MPC52xx_PSC_SR_RXRDY) != 0; +} + +static unsigned char psc_getc(void) +{ + while (!(in_be16(psc + MPC52xx_PSC_SR) & MPC52xx_PSC_SR_RXRDY)) ; + return in_8(psc + MPC52xx_PSC_BUFFER); +} + +int mpc5200_psc_console_init(void *devp, struct serial_console_data *scdp) +{ + int n; + + /* Get the base address of the psc registers */ + n = getprop(devp, "virtual-reg", &psc, sizeof(psc)); + if (n != sizeof(psc)) { + if (!dt_xlate_reg(devp, 0, (void *)&psc, NULL)) + return -1; + } + + scdp->open = psc_open; + scdp->putc = psc_putc; + scdp->getc = psc_getc; + scdp->tstc = psc_tstc; + + return 0; +} diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index 703255bf0089..f639fcab2c44 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -84,6 +84,7 @@ int serial_console_init(void); int ns16550_console_init(void *devp, struct serial_console_data *scdp); int mpsc_console_init(void *devp, struct serial_console_data *scdp); int cpm_console_init(void *devp, struct serial_console_data *scdp); +int mpc5200_psc_console_init(void *devp, struct serial_console_data *scdp); void *simple_alloc_init(char *base, unsigned long heap_size, unsigned long granularity, unsigned long max_allocs); extern void flush_cache(void *, unsigned long); diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c index d47f8e0b4b81..95e08e4ddcd2 100644 --- a/arch/powerpc/boot/serial.c +++ b/arch/powerpc/boot/serial.c @@ -126,6 +126,8 @@ int serial_console_init(void) dt_is_compatible(devp, "fsl,cpm2-scc-uart") || dt_is_compatible(devp, "fsl,cpm2-smc-uart")) rc = cpm_console_init(devp, &serial_cd); + else if (dt_is_compatible(devp, "mpc5200-psc-uart")) + rc = mpc5200_psc_console_init(devp, &serial_cd); /* Add other serial console driver calls here */ diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index 3ffaa066c2c8..9ddf251b192b 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig @@ -30,6 +30,7 @@ config PPC_EFIKA config PPC_LITE5200 bool "Freescale Lite5200 Eval Board" depends on PPC_MULTIPLATFORM && PPC32 + select WANT_DEVICE_TREE select PPC_MPC5200 default n From 408e83a682bbca54c579519098d63f3f5d8856e1 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Wed, 12 Sep 2007 13:58:54 +1000 Subject: [PATCH 0278/2804] [POWERPC] Convert define_machine(mpc885_ads) to C99 initializer syntax Make the define_machine() block for mpc885_ads more greppable and consistent with other examples in tree. Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/8xx/mpc885ads_setup.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index d3da38586b04..a1dab4cfd3de 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -426,9 +426,14 @@ static int __init mpc885ads_probe(void) define_machine(mpc885_ads) { -.name = "MPC885 ADS",.probe = mpc885ads_probe,.setup_arch = - mpc885ads_setup_arch,.init_IRQ = - m8xx_pic_init,.show_cpuinfo = mpc8xx_show_cpuinfo,.get_irq = - mpc8xx_get_irq,.restart = mpc8xx_restart,.calibrate_decr = - mpc8xx_calibrate_decr,.set_rtc_time = - mpc8xx_set_rtc_time,.get_rtc_time = mpc8xx_get_rtc_time,}; + .name = "MPC885 ADS", + .probe = mpc885ads_probe, + .setup_arch = mpc885ads_setup_arch, + .init_IRQ = m8xx_pic_init, + .show_cpuinfo = mpc8xx_show_cpuinfo, + .get_irq = mpc8xx_get_irq, + .restart = mpc8xx_restart, + .calibrate_decr = mpc8xx_calibrate_decr, + .set_rtc_time = mpc8xx_set_rtc_time, + .get_rtc_time = mpc8xx_get_rtc_time, +}; From fb8299ed31d474248c2028ab8393462841cc9b0b Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 14 Sep 2007 15:46:40 +1000 Subject: [PATCH 0279/2804] [POWERPC] cell: Don't cast the result of of_get_property() The cast to u32 * isn't required, of_get_property returns a void *. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_manage.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index 0e14f532500e..1b010707488d 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -377,10 +377,10 @@ static int qs20_reg_memory[QS20_SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 }; static struct spu *spu_lookup_reg(int node, u32 reg) { struct spu *spu; - u32 *spu_reg; + const u32 *spu_reg; list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { - spu_reg = (u32*)of_get_property(spu_devnode(spu), "reg", NULL); + spu_reg = of_get_property(spu_devnode(spu), "reg", NULL); if (*spu_reg == reg) return spu; } From 3164cccdc0e6e16eb9797586aaa8d1f759799c01 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 15 Sep 2007 10:21:57 +1000 Subject: [PATCH 0280/2804] [POWERPC] add Kconfig option for optimizing for cell Since the PPE on cell is an in-order core, it suffers significantly from wrong instruction scheduling. This adds a Kconfig option that enables passing -mtune=cell to gcc in order to generate object code that runs well on cell. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 4 ++++ arch/powerpc/platforms/Kconfig.cputype | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 6015a92bc2a0..87aff5372d6e 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -92,6 +92,10 @@ else endif endif +ifeq ($(CONFIG_TUNE_CELL),y) + CFLAGS += $(call cc-option,-mtune=cell) +endif + # No AltiVec instruction when building kernel CFLAGS += $(call cc-option,-mno-altivec) diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 86eb4cf31f0b..4c315be25015 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -71,6 +71,18 @@ config POWER4 depends on PPC64 def_bool y +config TUNE_CELL + bool "Optimize for Cell Broadband Engine" + depends on PPC64 + help + Cause the compiler to optimize for the PPE of the Cell Broadband + Engine. This will make the code run considerably faster on Cell + but somewhat slower on other machines. This option only changes + the scheduling of instructions, not the selection of instructions + itself, so the resulting kernel will keep running on all other + machines. When building a kernel that is supposed to run only + on Cell, you should also select the POWER4_ONLY option. + config 6xx bool From 17b5ee04c09a158129eb538933eae7be956190e9 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 18 Sep 2007 06:12:29 +1000 Subject: [PATCH 0281/2804] [POWERPC] Support setting affinity for U3/U4 MSI sources Hook up affinity-setting for U3/U4 MSI interrupt sources. Tested on Quad G5 with myri10ge. Signed-off-by: Olof Johansson Acked-by: Benjamin Herrenschmidt Acked-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic.c | 2 +- arch/powerpc/sysdev/mpic.h | 1 + arch/powerpc/sysdev/mpic_u3msi.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 8de29f28b4c7..22600fd23958 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -768,7 +768,7 @@ static void mpic_end_ipi(unsigned int irq) #endif /* CONFIG_SMP */ -static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) +void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) { struct mpic *mpic = mpic_from_irq(irq); unsigned int src = mpic_irq_to_hw(irq); diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index 3a1c3d2c594d..1cb6bd841027 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h @@ -34,5 +34,6 @@ extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); extern void mpic_end_irq(unsigned int irq); extern void mpic_mask_irq(unsigned int irq); extern void mpic_unmask_irq(unsigned int irq); +extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask); #endif /* _POWERPC_SYSDEV_MPIC_H */ diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 305b864c25d9..0fc4e961d451 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -40,6 +40,7 @@ static struct irq_chip mpic_u3msi_chip = { .unmask = mpic_u3msi_unmask_irq, .eoi = mpic_end_irq, .set_type = mpic_set_irq_type, + .set_affinity = mpic_set_affinity, .typename = "MPIC-U3MSI", }; From 8fd7675c092f79f240246c76728477ec4e7f7f09 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Tue, 18 Sep 2007 09:43:40 +1000 Subject: [PATCH 0282/2804] [POWERPC] Avoid pointless WARN_ON(irqs_disabled()) from panic codepath > ------------[ cut here ]------------ > Badness at arch/powerpc/kernel/smp.c:202 comes when smp_call_function_map() has been called with irqs disabled, which is illegal. However, there is a special case, the panic() codepath, when we do not want to warn about this -- warning at that time is pointless anyway, and only serves to scroll away the *real* cause of the panic and distracts from the real bug. * So let's extract the WARN_ON() from smp_call_function_map() into all its callers -- smp_call_function() and smp_call_function_single() * Also, introduce another caller of smp_call_function_map(), namely __smp_call_function() (and make smp_call_function() a wrapper over this) which does *not* warn about disabled irqs * Use this __smp_call_function() from the panic codepath's smp_send_stop() We also end having to move code of smp_send_stop() below the definition of __smp_call_function(). Signed-off-by: Satyam Sharma Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/smp.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 1ea43160f543..b24dcbaeecaa 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -152,11 +152,6 @@ static void stop_this_cpu(void *dummy) ; } -void smp_send_stop(void) -{ - smp_call_function(stop_this_cpu, NULL, 1, 0); -} - /* * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. @@ -198,9 +193,6 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, int cpu; u64 timeout; - /* Can deadlock when called with interrupts disabled */ - WARN_ON(irqs_disabled()); - if (unlikely(smp_ops == NULL)) return ret; @@ -270,10 +262,19 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, return ret; } +static int __smp_call_function(void (*func)(void *info), void *info, + int nonatomic, int wait) +{ + return smp_call_function_map(func,info,nonatomic,wait,cpu_online_map); +} + int smp_call_function(void (*func) (void *info), void *info, int nonatomic, int wait) { - return smp_call_function_map(func,info,nonatomic,wait,cpu_online_map); + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + + return __smp_call_function(func, info, nonatomic, wait); } EXPORT_SYMBOL(smp_call_function); @@ -283,6 +284,9 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int cpumask_t map = CPU_MASK_NONE; int ret = 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + if (!cpu_online(cpu)) return -EINVAL; @@ -299,6 +303,11 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int } EXPORT_SYMBOL(smp_call_function_single); +void smp_send_stop(void) +{ + __smp_call_function(stop_this_cpu, NULL, 1, 0); +} + void smp_call_function_interrupt(void) { void (*func) (void *info); From 4c2a54b09ba35a409afc34bd331a57a994921664 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 19 Sep 2007 14:50:22 +1000 Subject: [PATCH 0283/2804] [POWERPC] Fix platinumfb framebuffer Current kernels have a non-working platinumfb due to some resource management issues. This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/video/platinumfb.c | 48 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 8503e733a172..cbe71a5338d0 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -17,6 +17,8 @@ * more details. */ +#undef DEBUG + #include #include #include @@ -535,33 +537,35 @@ static int __devinit platinumfb_probe(struct of_device* odev, volatile __u8 *fbuffer; int bank0, bank1, bank2, bank3, rc; - printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n"); + dev_info(&odev->dev, "Found Apple Platinum video hardware\n"); info = framebuffer_alloc(sizeof(*pinfo), &odev->dev); - if (info == NULL) + if (info == NULL) { + dev_err(&odev->dev, "Failed to allocate fbdev !\n"); return -ENOMEM; + } pinfo = info->par; if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) || of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) { - printk(KERN_ERR "platinumfb: Can't get resources\n"); - framebuffer_release(info); - return -ENXIO; - } - if (!request_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.start - - pinfo->rsrc_reg.end + 1, - "platinumfb registers")) { + dev_err(&odev->dev, "Can't get resources\n"); framebuffer_release(info); return -ENXIO; } + dev_dbg(&odev->dev, " registers : 0x%llx...0x%llx\n", + (unsigned long long)pinfo->rsrc_reg.start, + (unsigned long long)pinfo->rsrc_reg.end); + dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n", + (unsigned long long)pinfo->rsrc_fb.start, + (unsigned long long)pinfo->rsrc_fb.end); + + /* Do not try to request register space, they overlap with the + * northbridge and that can fail. Only request framebuffer + */ if (!request_mem_region(pinfo->rsrc_fb.start, - pinfo->rsrc_fb.start - - pinfo->rsrc_fb.end + 1, + pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1, "platinumfb framebuffer")) { - release_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.end - - pinfo->rsrc_reg.start + 1); + printk(KERN_ERR "platinumfb: Can't request framebuffer !\n"); framebuffer_release(info); return -ENXIO; } @@ -600,7 +604,8 @@ static int __devinit platinumfb_probe(struct of_device* odev, bank2 = fbuffer[0x200000] == 0x56; bank3 = fbuffer[0x300000] == 0x78; pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000; - printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (int) (pinfo->total_vram / 1024 / 1024), + printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", + (unsigned int) (pinfo->total_vram / 1024 / 1024), bank3, bank2, bank1, bank0); /* @@ -644,16 +649,15 @@ static int __devexit platinumfb_remove(struct of_device* odev) unregister_framebuffer (info); /* Unmap frame buffer and registers */ + iounmap(pinfo->frame_buffer); + iounmap(pinfo->platinum_regs); + iounmap(pinfo->cmap_regs); + release_mem_region(pinfo->rsrc_fb.start, pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1); - release_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.end - - pinfo->rsrc_reg.start + 1); - iounmap(pinfo->frame_buffer); - iounmap(pinfo->platinum_regs); + release_mem_region(pinfo->cmap_regs_phys, 0x1000); - iounmap(pinfo->cmap_regs); framebuffer_release(info); From 576e393e74e58bd4c949d551a3340accc8dbab0f Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Thu, 20 Sep 2007 12:25:17 +1000 Subject: [PATCH 0284/2804] [POWERPC] Fix build errors when BLOCK=n These are the symptom error messages: CC arch/powerpc/kernel/setup_32.o In file included from include/linux/blkdev.h:17, from include/linux/ide.h:13, from arch/powerpc/kernel/setup_32.c:13: include/linux/bsg.h:67: warning: 'struct request_queue' declared inside parameter list include/linux/bsg.h:67: warning: its scope is only this definition or declaration, which is probably not what you want include/linux/bsg.h:71: warning: 'struct request_queue' declared inside parameter list In file included from arch/powerpc/kernel/setup_32.c:13: include/linux/ide.h:857: error: field 'wrq' has incomplete type CC arch/powerpc/kernel/ppc_ksyms.o In file included from include/linux/blkdev.h:17, from include/linux/ide.h:13, from arch/powerpc/kernel/ppc_ksyms.c:15: include/linux/bsg.h:67: warning: 'struct request_queue' declared inside parameter list include/linux/bsg.h:67: warning: its scope is only this definition or declaration, which is probably not what you want include/linux/bsg.h:71: warning: 'struct request_queue' declared inside parameter list In file included from arch/powerpc/kernel/ppc_ksyms.c:15: include/linux/ide.h:857: error: field 'wrq' has incomplete type The fix tries to use the smallest scope CONFIG_* symbols that will fix the build problem. In this case needs to be included only if IDE=y or IDE=m were selected. Also, ppc_ide_md is needed only if BLK_DEV_IDE=y or BLK_DEV_IDE=m Moved the EXPORT_SYMBOL(ppc_ide_md) from ppc_ksysms.c next to its declaration in setup_32.c which made not needed. With gone from ppc_ksyms.c, is needed to address the following warnings and errors: CC arch/powerpc/kernel/ppc_ksyms.o arch/powerpc/kernel/ppc_ksyms.c:122: error: '__flush_icache_range' undeclared here (not in a function) arch/powerpc/kernel/ppc_ksyms.c:122: warning: type defaults to 'int' in declaration of '__flush_icache_range' arch/powerpc/kernel/ppc_ksyms.c:123: error: 'flush_dcache_range' undeclared here (not in a function) arch/powerpc/kernel/ppc_ksyms.c:123: warning: type defaults to 'int' in declaration of 'flush_dcache_range' Signed-off-by: Emil Medve Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ppc_ksyms.c | 6 +----- arch/powerpc/kernel/setup_32.c | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 430c502179c3..c6b1aa3efbb9 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -12,12 +12,12 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -95,10 +95,6 @@ EXPORT_SYMBOL(__strnlen_user); EXPORT_SYMBOL(copy_4K_page); #endif -#if defined(CONFIG_PPC32) && (defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)) -EXPORT_SYMBOL(ppc_ide_md); -#endif - #if defined(CONFIG_PCI) && defined(CONFIG_PPC32) EXPORT_SYMBOL(isa_io_base); EXPORT_SYMBOL(isa_mem_base); diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index a288a5f2dbc6..7474502dace5 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -10,7 +10,9 @@ #include #include #include +#if defined(CONFIG_IDE) || defined(CONFIG_IDE_MODULE) #include +#endif #include #include #include @@ -49,7 +51,10 @@ extern void bootx_init(unsigned long r4, unsigned long phys); +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) struct ide_machdep_calls ppc_ide_md; +EXPORT_SYMBOL(ppc_ide_md); +#endif int boot_cpuid; EXPORT_SYMBOL_GPL(boot_cpuid); From 17b0429dde9ab60f9cee8e07ab28c7dc6cfe6efd Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 22 Jul 2007 22:18:46 +0200 Subject: [PATCH 0285/2804] mmc: remove custom error codes Convert the MMC layer to use standard error codes and not its own, incompatible values. Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 4 +-- drivers/mmc/core/core.c | 4 +-- drivers/mmc/core/mmc.c | 36 ++++++++++++------------ drivers/mmc/core/mmc_ops.c | 34 +++++++++++----------- drivers/mmc/core/sd.c | 56 ++++++++++++++++++------------------- drivers/mmc/core/sd_ops.c | 46 +++++++++++++++--------------- drivers/mmc/host/at91_mci.c | 12 ++++---- drivers/mmc/host/au1xmmc.c | 32 ++++++++++----------- drivers/mmc/host/imxmmc.c | 14 +++++----- drivers/mmc/host/mmci.c | 12 ++++---- drivers/mmc/host/omap.c | 12 ++++---- drivers/mmc/host/pxamci.c | 12 ++++---- drivers/mmc/host/sdhci.c | 51 ++++++++++++++++----------------- drivers/mmc/host/tifm_sd.c | 20 ++++++------- drivers/mmc/host/wbsd.c | 41 +++++++++++++-------------- include/linux/mmc/core.h | 19 +++++++++---- 16 files changed, 203 insertions(+), 202 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 93fe2e5dd616..0da341acf32b 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -154,7 +154,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); - if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) + if (err || !(cmd.resp[0] & R1_APP_CMD)) return (u32)-1; memset(&cmd, 0, sizeof(struct mmc_command)); @@ -192,7 +192,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) mmc_wait_for_req(card->host, &mrq); - if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) + if (cmd.error || data.error) return (u32)-1; blocks = ntohl(blocks); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bfd2ae5bd669..63b67296e92d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -598,7 +598,7 @@ void mmc_rescan(struct work_struct *work) mmc_send_if_cond(host, host->ocr_avail); err = mmc_send_app_op_cond(host, 0, &ocr); - if (err == MMC_ERR_NONE) { + if (!err) { if (mmc_attach_sd(host, ocr)) mmc_power_off(host); } else { @@ -607,7 +607,7 @@ void mmc_rescan(struct work_struct *work) * searching for MMC cards. */ err = mmc_send_op_cond(host, 0, &ocr); - if (err == MMC_ERR_NONE) { + if (!err) { if (mmc_attach_mmc(host, ocr)) mmc_power_off(host); } else { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 21d7f48e1d4e..fe483d5af744 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -164,10 +164,10 @@ static int mmc_read_ext_csd(struct mmc_card *card) BUG_ON(!card); - err = MMC_ERR_FAILED; + err = -EIO; if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return MMC_ERR_NONE; + return 0; /* * As the ext_csd is so large and mostly unused, we don't store the @@ -178,11 +178,11 @@ static int mmc_read_ext_csd(struct mmc_card *card) printk(KERN_ERR "%s: could not allocate a buffer to " "receive the ext_csd. mmc v4 cards will be " "treated as v3.\n", mmc_hostname(card->host)); - return MMC_ERR_FAILED; + return -ENOMEM; } err = mmc_send_ext_csd(card, ext_csd); - if (err != MMC_ERR_NONE) { + if (err) { /* * High capacity cards should have this "magic" size * stored in their CSD. @@ -197,7 +197,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) "EXT_CSD, performance might " "suffer.\n", mmc_hostname(card->host)); - err = MMC_ERR_NONE; + err = 0; } goto out; } @@ -258,14 +258,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* The extra bit indicates that we support high capacity */ err = mmc_send_op_cond(host, ocr | (1 << 30), NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; /* * Fetch CID from card. */ err = mmc_all_send_cid(host, cid); - if (err != MMC_ERR_NONE) + if (err) goto err; if (oldcard) { @@ -290,7 +290,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Set card RCA. */ err = mmc_set_relative_addr(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); @@ -300,7 +300,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Fetch CSD from card. */ err = mmc_send_csd(card, card->raw_csd); - if (err != MMC_ERR_NONE) + if (err) goto free_card; err = mmc_decode_csd(card); @@ -315,7 +315,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Select card, as all following commands rely on that. */ err = mmc_select_card(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; if (!oldcard) { @@ -323,7 +323,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Fetch and process extened CSD. */ err = mmc_read_ext_csd(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; } @@ -334,7 +334,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, (host->caps & MMC_CAP_MMC_HIGHSPEED)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_card_set_highspeed(card); @@ -363,7 +363,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, (host->caps & MMC_CAP_4_BIT_DATA)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); @@ -372,14 +372,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - return MMC_ERR_NONE; + return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - return MMC_ERR_FAILED; + return -EIO; } /* @@ -413,7 +413,7 @@ static void mmc_detect(struct mmc_host *host) mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_remove(host); mmc_claim_host(host); @@ -502,7 +502,7 @@ static void mmc_resume(struct mmc_host *host) err = mmc_init_card(host, host->ocr, host->card); mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_remove(host); mmc_claim_host(host); @@ -565,7 +565,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) * Detect and init the card. */ err = mmc_init_card(host, host->ocr, NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; mmc_release_host(host); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 913e75f00843..15cd575effaa 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -40,10 +40,10 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) } err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; - return MMC_ERR_NONE; + return 0; } int mmc_select_card(struct mmc_card *card) @@ -99,13 +99,13 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) + if (err) break; if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; - err = MMC_ERR_TIMEOUT; + err = -ETIMEDOUT; mmc_delay(10); } @@ -131,12 +131,12 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid) cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; memcpy(cid, cmd.resp, sizeof(u32) * 4); - return MMC_ERR_NONE; + return 0; } int mmc_set_relative_addr(struct mmc_card *card) @@ -154,10 +154,10 @@ int mmc_set_relative_addr(struct mmc_card *card) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; - return MMC_ERR_NONE; + return 0; } int mmc_send_csd(struct mmc_card *card, u32 *csd) @@ -176,12 +176,12 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd) cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; memcpy(csd, cmd.resp, sizeof(u32) * 4); - return MMC_ERR_NONE; + return 0; } int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) @@ -218,12 +218,12 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_wait_for_req(card->host, &mrq); - if (cmd.error != MMC_ERR_NONE) + if (cmd.error) return cmd.error; - if (data.error != MMC_ERR_NONE) + if (data.error) return data.error; - return MMC_ERR_NONE; + return 0; } int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) @@ -244,10 +244,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; - return MMC_ERR_NONE; + return 0; } int mmc_send_status(struct mmc_card *card, u32 *status) @@ -265,12 +265,12 @@ int mmc_send_status(struct mmc_card *card, u32 *status) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; if (status) *status = cmd.resp[0]; - return MMC_ERR_NONE; + return 0; } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 1edc62b1e5c6..00895c99d9bb 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -193,30 +193,30 @@ static int mmc_read_switch(struct mmc_card *card) u8 *status; if (card->scr.sda_vsn < SCR_SPEC_VER_1) - return MMC_ERR_NONE; + return 0; if (!(card->csd.cmdclass & CCC_SWITCH)) { printk(KERN_WARNING "%s: card lacks mandatory switch " "function, performance might suffer.\n", mmc_hostname(card->host)); - return MMC_ERR_NONE; + return 0; } - err = MMC_ERR_FAILED; + err = -EIO; status = kmalloc(64, GFP_KERNEL); if (!status) { printk(KERN_ERR "%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); - return err; + return -ENOMEM; } err = mmc_sd_switch(card, 0, 0, 1, status); - if (err != MMC_ERR_NONE) { + if (err) { printk(KERN_WARNING "%s: problem reading switch " "capabilities, performance might suffer.\n", mmc_hostname(card->host)); - err = MMC_ERR_NONE; + err = 0; goto out; } @@ -238,28 +238,28 @@ static int mmc_switch_hs(struct mmc_card *card) u8 *status; if (card->scr.sda_vsn < SCR_SPEC_VER_1) - return MMC_ERR_NONE; + return 0; if (!(card->csd.cmdclass & CCC_SWITCH)) - return MMC_ERR_NONE; + return 0; if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED)) - return MMC_ERR_NONE; + return 0; if (card->sw_caps.hs_max_dtr == 0) - return MMC_ERR_NONE; + return 0; - err = MMC_ERR_FAILED; + err = -EIO; status = kmalloc(64, GFP_KERNEL); if (!status) { printk(KERN_ERR "%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); - return err; + return -ENOMEM; } err = mmc_sd_switch(card, 1, 0, 1, status); - if (err != MMC_ERR_NONE) + if (err) goto out; if ((status[16] & 0xF) != 1) { @@ -309,18 +309,18 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * block-addressed SDHC cards. */ err = mmc_send_if_cond(host, ocr); - if (err == MMC_ERR_NONE) + if (!err) ocr |= 1 << 30; err = mmc_send_app_op_cond(host, ocr, NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; /* * Fetch CID from card. */ err = mmc_all_send_cid(host, cid); - if (err != MMC_ERR_NONE) + if (err) goto err; if (oldcard) { @@ -344,7 +344,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Set card RCA. */ err = mmc_send_relative_addr(host, &card->rca); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); @@ -354,7 +354,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Fetch CSD from card. */ err = mmc_send_csd(card, card->raw_csd); - if (err != MMC_ERR_NONE) + if (err) goto free_card; err = mmc_decode_csd(card); @@ -368,7 +368,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Select card, as all following commands rely on that. */ err = mmc_select_card(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; if (!oldcard) { @@ -376,7 +376,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Fetch SCR from card. */ err = mmc_app_send_scr(card, card->raw_scr); - if (err != MMC_ERR_NONE) + if (err) goto free_card; err = mmc_decode_scr(card); @@ -387,7 +387,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Fetch switch information from card. */ err = mmc_read_switch(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; } @@ -395,7 +395,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Attempt to change to high-speed (if supported) */ err = mmc_switch_hs(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; /* @@ -418,7 +418,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if ((host->caps & MMC_CAP_4_BIT_DATA) && (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_width(host, MMC_BUS_WIDTH_4); @@ -442,14 +442,14 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - return MMC_ERR_NONE; + return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - return MMC_ERR_FAILED; + return -EIO; } /* @@ -483,7 +483,7 @@ static void mmc_sd_detect(struct mmc_host *host) mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_sd_remove(host); mmc_claim_host(host); @@ -574,7 +574,7 @@ static void mmc_sd_resume(struct mmc_host *host) err = mmc_sd_init_card(host, host->ocr, host->card); mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_sd_remove(host); mmc_claim_host(host); @@ -644,7 +644,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) * Detect and init the card. */ err = mmc_sd_init_card(host, host->ocr, NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; mmc_release_host(host); diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 342f340ebc25..b4d43bd0fedd 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -40,14 +40,14 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) } err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) + if (err) return err; /* Check that card supported application commands */ if (!(cmd.resp[0] & R1_APP_CMD)) - return MMC_ERR_FAILED; + return -EOPNOTSUPP; - return MMC_ERR_NONE; + return 0; } /** @@ -73,7 +73,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, BUG_ON(!cmd); BUG_ON(retries < 0); - err = MMC_ERR_INVALID; + err = -EIO; /* * We have to resend MMC_APP_CMD for each attempt so @@ -83,7 +83,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, memset(&mrq, 0, sizeof(struct mmc_request)); err = mmc_app_cmd(host, card); - if (err != MMC_ERR_NONE) + if (err) continue; memset(&mrq, 0, sizeof(struct mmc_request)); @@ -97,7 +97,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, mmc_wait_for_req(host, &mrq); err = cmd->error; - if (cmd->error == MMC_ERR_NONE) + if (!cmd->error) break; } @@ -127,14 +127,14 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) cmd.arg = SD_BUS_WIDTH_4; break; default: - return MMC_ERR_INVALID; + return -EINVAL; } err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; - return MMC_ERR_NONE; + return 0; } int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) @@ -152,13 +152,13 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) break; if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; - err = MMC_ERR_TIMEOUT; + err = -ETIMEDOUT; mmc_delay(10); } @@ -185,13 +185,13 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) + if (err) return err; if ((cmd.resp[0] & 0xFF) != test_pattern) - return MMC_ERR_FAILED; + return -EIO; - return MMC_ERR_NONE; + return 0; } int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) @@ -209,12 +209,12 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; *rca = cmd.resp[0] >> 16; - return MMC_ERR_NONE; + return 0; } int mmc_app_send_scr(struct mmc_card *card, u32 *scr) @@ -230,7 +230,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) BUG_ON(!scr); err = mmc_app_cmd(card->host, card); - if (err != MMC_ERR_NONE) + if (err) return err; memset(&mrq, 0, sizeof(struct mmc_request)); @@ -256,15 +256,15 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) mmc_wait_for_req(card->host, &mrq); - if (cmd.error != MMC_ERR_NONE) + if (cmd.error) return cmd.error; - if (data.error != MMC_ERR_NONE) + if (data.error) return data.error; scr[0] = ntohl(scr[0]); scr[1] = ntohl(scr[1]); - return MMC_ERR_NONE; + return 0; } int mmc_sd_switch(struct mmc_card *card, int mode, int group, @@ -306,11 +306,11 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, mmc_wait_for_req(card->host, &mrq); - if (cmd.error != MMC_ERR_NONE) + if (cmd.error) return cmd.error; - if (data.error != MMC_ERR_NONE) + if (data.error) return data.error; - return MMC_ERR_NONE; + return 0; } diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 955ea60583b5..810a433ce532 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -577,24 +577,22 @@ static void at91_mci_completed_command(struct at91mci_host *host) AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) { if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { - cmd->error = MMC_ERR_NONE; + cmd->error = 0; } else { if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE)) - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE)) - cmd->error = MMC_ERR_BADCRC; - else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE)) - cmd->error = MMC_ERR_FIFO; + cmd->error = -EILSEQ; else - cmd->error = MMC_ERR_FAILED; + cmd->error = -EIO; pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n", cmd->error, cmd->opcode, cmd->retries); } } else - cmd->error = MMC_ERR_NONE; + cmd->error = 0; at91_mci_process_next(host); } diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 34c99d4ea041..49b0367e57c8 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -208,7 +208,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, default: printk(KERN_INFO "au1xmmc: unhandled response type %02x\n", mmc_resp_type(cmd)); - return MMC_ERR_INVALID; + return -EINVAL; } if (flags & MMC_DATA_READ) { @@ -253,7 +253,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, IRQ_ON(host, SD_CONFIG_CR); } - return MMC_ERR_NONE; + return 0; } static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) @@ -278,7 +278,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB)) status = au_readl(HOST_STATUS(host)); - data->error = MMC_ERR_NONE; + data->error = 0; dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir); /* Process any errors */ @@ -288,14 +288,14 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) crc |= ((status & 0x07) == 0x02) ? 0 : 1; if (crc) - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; /* Clear the CRC bits */ au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host)); data->bytes_xfered = 0; - if (data->error == MMC_ERR_NONE) { + if (!data->error) { if (host->flags & HOST_F_DMA) { u32 chan = DMA_CHANNEL(host); @@ -475,7 +475,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) return; cmd = mrq->cmd; - cmd->error = MMC_ERR_NONE; + cmd->error = 0; if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { @@ -512,11 +512,11 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) /* Figure out errors */ if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC)) - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; trans = host->flags & (HOST_F_XMIT | HOST_F_RECV); - if (!trans || cmd->error != MMC_ERR_NONE) { + if (!trans || cmd->error) { IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF); tasklet_schedule(&host->finish_task); @@ -589,7 +589,7 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) data->sg_len, host->dma.dir); if (host->dma.len == 0) - return MMC_ERR_TIMEOUT; + return -ETIMEDOUT; au_writel(data->blksz - 1, HOST_BLKSIZE(host)); @@ -640,11 +640,11 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF); } - return MMC_ERR_NONE; + return 0; dataerr: dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir); - return MMC_ERR_TIMEOUT; + return -ETIMEDOUT; } /* static void au1xmmc_request @@ -656,7 +656,7 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) struct au1xmmc_host *host = mmc_priv(mmc); unsigned int flags = 0; - int ret = MMC_ERR_NONE; + int ret = 0; WARN_ON(irqs_disabled()); WARN_ON(host->status != HOST_S_IDLE); @@ -672,10 +672,10 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) ret = au1xmmc_prepare_data(host, mrq->data); } - if (ret == MMC_ERR_NONE) + if (!ret) ret = au1xmmc_send_command(host, 0, mrq->cmd, flags); - if (ret != MMC_ERR_NONE) { + if (ret) { mrq->cmd->error = ret; au1xmmc_finish_request(host); } @@ -764,10 +764,10 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id) if (host->mrq && (status & STATUS_TIMEOUT)) { if (status & SD_STATUS_RAT) - host->mrq->cmd->error = MMC_ERR_TIMEOUT; + host->mrq->cmd->error = -ETIMEDOUT; else if (status & SD_STATUS_DT) - host->mrq->data->error = MMC_ERR_TIMEOUT; + host->mrq->data->error = -ETIMEDOUT; /* In PIO mode, interrupts might still be enabled */ IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH); diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 54bfc9f25596..04458c342812 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -428,11 +428,11 @@ static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat) if ( stat & STATUS_ERR_MASK ) { dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat); if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR)) - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; else if(stat & STATUS_TIME_OUT_READ) - data->error = MMC_ERR_TIMEOUT; + data->error = -ETIMEDOUT; else - data->error = MMC_ERR_FAILED; + data->error = -EIO; } else { data->bytes_xfered = host->dma_size; } @@ -458,10 +458,10 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) if (stat & STATUS_TIME_OUT_RESP) { dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n"); - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) { dev_dbg(mmc_dev(host->mmc), "cmd crc error\n"); - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; } if(cmd->flags & MMC_RSP_PRESENT) { @@ -482,7 +482,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); - if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) { + if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) { if (host->req->data->flags & MMC_DATA_WRITE) { /* Wait for FIFO to be empty before starting DMA write */ @@ -491,7 +491,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) if(imxmci_busy_wait_for_status(host, &stat, STATUS_APPL_BUFF_FE, 40, "imxmci_cmd_done DMA WR") < 0) { - cmd->error = MMC_ERR_FIFO; + cmd->error = -EIO; imxmci_finish_data(host, stat); if(host->req) imxmci_finish_request(host, host->req); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index be730c0a0352..d53e9a8bdaa2 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -154,11 +154,11 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, } if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { if (status & MCI_DATACRCFAIL) - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; else if (status & MCI_DATATIMEOUT) - data->error = MMC_ERR_TIMEOUT; + data->error = -ETIMEDOUT; else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) - data->error = MMC_ERR_FIFO; + data->error = -EIO; status |= MCI_DATAEND; /* @@ -193,12 +193,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, cmd->resp[3] = readl(base + MMCIRESPONSE3); if (status & MCI_CMDTIMEOUT) { - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; } - if (!cmd->data || cmd->error != MMC_ERR_NONE) { + if (!cmd->data || cmd->error) { if (host->data) mmci_stop_data(host); mmci_request_end(host, cmd->mrq); diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 0cf97edc5f58..60a67dfcda6a 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -263,7 +263,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) enum dma_data_direction dma_data_dir; BUG_ON(host->dma_ch < 0); - if (data->error != MMC_ERR_NONE) + if (data->error) omap_stop_dma(host->dma_ch); /* Release DMA channel lazily */ mod_timer(&host->dma_timer, jiffies + HZ); @@ -368,7 +368,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) } } - if (host->data == NULL || cmd->error != MMC_ERR_NONE) { + if (host->data == NULL || cmd->error) { host->mrq = NULL; clk_disable(host->fclk); mmc_request_done(host->mmc, cmd->mrq); @@ -475,14 +475,14 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) if (status & OMAP_MMC_STAT_DATA_TOUT) { dev_dbg(mmc_dev(host->mmc), "data timeout\n"); if (host->data) { - host->data->error |= MMC_ERR_TIMEOUT; + host->data->error = -ETIMEDOUT; transfer_error = 1; } } if (status & OMAP_MMC_STAT_DATA_CRC) { if (host->data) { - host->data->error |= MMC_ERR_BADCRC; + host->data->error = -EILSEQ; dev_dbg(mmc_dev(host->mmc), "data CRC error, bytes left %d\n", host->total_bytes_left); @@ -504,7 +504,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) dev_err(mmc_dev(host->mmc), "command timeout, CMD %d\n", host->cmd->opcode); - host->cmd->error = MMC_ERR_TIMEOUT; + host->cmd->error = -ETIMEDOUT; end_command = 1; } } @@ -514,7 +514,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) dev_err(mmc_dev(host->mmc), "command CRC error (CMD%d, arg 0x%08x)\n", host->cmd->opcode, host->cmd->arg); - host->cmd->error = MMC_ERR_BADCRC; + host->cmd->error = -EILSEQ; end_command = 1; } else dev_err(mmc_dev(host->mmc), diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index ff960334b337..b89e32d1e9b5 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -226,7 +226,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) } if (stat & STAT_TIME_OUT_RESPONSE) { - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { #ifdef CONFIG_PXA27x /* @@ -239,11 +239,11 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); } else #endif - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; } pxamci_disable_irq(host, END_CMD_RES); - if (host->data && cmd->error == MMC_ERR_NONE) { + if (host->data && !cmd->error) { pxamci_enable_irq(host, DATA_TRAN_DONE); } else { pxamci_finish_request(host, host->mrq); @@ -264,9 +264,9 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) host->dma_dir); if (stat & STAT_READ_TIME_OUT) - data->error = MMC_ERR_TIMEOUT; + data->error = -ETIMEDOUT; else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; /* * There appears to be a hardware design bug here. There seems to @@ -274,7 +274,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) * This means that if there was an error on any block, we mark all * data blocks as being in error. */ - if (data->error == MMC_ERR_NONE) + if (!data->error) data->bytes_xfered = data->blocks * data->blksz; else data->bytes_xfered = 0; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 20a7d89e01ba..479d6a265dd1 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -481,16 +481,16 @@ static void sdhci_finish_data(struct sdhci_host *host) * Controller doesn't count down when in single block mode. */ if (data->blocks == 1) - blocks = (data->error == MMC_ERR_NONE) ? 0 : 1; + blocks = (data->error == 0) ? 0 : 1; else blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT); data->bytes_xfered = data->blksz * (data->blocks - blocks); - if ((data->error == MMC_ERR_NONE) && blocks) { + if (!data->error && blocks) { printk(KERN_ERR "%s: Controller signalled completion even " "though there were blocks left.\n", mmc_hostname(host->mmc)); - data->error = MMC_ERR_FAILED; + data->error = -EIO; } if (data->stop) { @@ -498,7 +498,7 @@ static void sdhci_finish_data(struct sdhci_host *host) * The controller needs a reset of internal state machines * upon error conditions. */ - if (data->error != MMC_ERR_NONE) { + if (data->error) { sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); } @@ -533,7 +533,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) printk(KERN_ERR "%s: Controller never released " "inhibit bit(s).\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); - cmd->error = MMC_ERR_FAILED; + cmd->error = -EIO; tasklet_schedule(&host->finish_tasklet); return; } @@ -554,7 +554,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { printk(KERN_ERR "%s: Unsupported response type!\n", mmc_hostname(host->mmc)); - cmd->error = MMC_ERR_INVALID; + cmd->error = -EINVAL; tasklet_schedule(&host->finish_tasklet); return; } @@ -601,7 +601,7 @@ static void sdhci_finish_command(struct sdhci_host *host) } } - host->cmd->error = MMC_ERR_NONE; + host->cmd->error = 0; if (host->data && host->data_early) sdhci_finish_data(host); @@ -722,7 +722,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - host->mrq->cmd->error = MMC_ERR_TIMEOUT; + host->mrq->cmd->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); } else sdhci_send_command(host, mrq->cmd); @@ -831,7 +831,7 @@ static void sdhci_tasklet_card(unsigned long param) sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); - host->mrq->cmd->error = MMC_ERR_FAILED; + host->mrq->cmd->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); } } @@ -859,9 +859,9 @@ static void sdhci_tasklet_finish(unsigned long param) * The controller needs a reset of internal state machines * upon error conditions. */ - if ((mrq->cmd->error != MMC_ERR_NONE) || - (mrq->data && ((mrq->data->error != MMC_ERR_NONE) || - (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) { + if (mrq->cmd->error || + (mrq->data && (mrq->data->error || + (mrq->data->stop && mrq->data->stop->error)))) { /* Some controllers need this kick or reset won't work here */ if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { @@ -906,13 +906,13 @@ static void sdhci_timeout_timer(unsigned long data) sdhci_dumpregs(host); if (host->data) { - host->data->error = MMC_ERR_TIMEOUT; + host->data->error = -ETIMEDOUT; sdhci_finish_data(host); } else { if (host->cmd) - host->cmd->error = MMC_ERR_TIMEOUT; + host->cmd->error = -ETIMEDOUT; else - host->mrq->cmd->error = MMC_ERR_TIMEOUT; + host->mrq->cmd->error = -ETIMEDOUT; tasklet_schedule(&host->finish_tasklet); } @@ -941,13 +941,12 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) } if (intmask & SDHCI_INT_TIMEOUT) - host->cmd->error = MMC_ERR_TIMEOUT; - else if (intmask & SDHCI_INT_CRC) - host->cmd->error = MMC_ERR_BADCRC; - else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) - host->cmd->error = MMC_ERR_FAILED; + host->cmd->error = -ETIMEDOUT; + else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | + SDHCI_INT_INDEX)) + host->cmd->error = -EILSEQ; - if (host->cmd->error != MMC_ERR_NONE) + if (host->cmd->error) tasklet_schedule(&host->finish_tasklet); else if (intmask & SDHCI_INT_RESPONSE) sdhci_finish_command(host); @@ -974,13 +973,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } if (intmask & SDHCI_INT_DATA_TIMEOUT) - host->data->error = MMC_ERR_TIMEOUT; - else if (intmask & SDHCI_INT_DATA_CRC) - host->data->error = MMC_ERR_BADCRC; - else if (intmask & SDHCI_INT_DATA_END_BIT) - host->data->error = MMC_ERR_FAILED; + host->data->error = -ETIMEDOUT; + else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) + host->data->error = -EILSEQ; - if (host->data->error != MMC_ERR_NONE) + if (host->data->error) sdhci_finish_data(host); else { if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 8b736e968447..b4a56e5e5132 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -404,14 +404,14 @@ static void tifm_sd_check_status(struct tifm_sd *host) struct tifm_dev *sock = host->dev; struct mmc_command *cmd = host->req->cmd; - if (cmd->error != MMC_ERR_NONE) + if (cmd->error) goto finish_request; if (!(host->cmd_flags & CMD_READY)) return; if (cmd->data) { - if (cmd->data->error != MMC_ERR_NONE) { + if (cmd->data->error) { if ((host->cmd_flags & SCMD_ACTIVE) && !(host->cmd_flags & SCMD_READY)) return; @@ -504,7 +504,7 @@ static void tifm_sd_card_event(struct tifm_dev *sock) { struct tifm_sd *host; unsigned int host_status = 0; - int cmd_error = MMC_ERR_NONE; + int cmd_error = 0; struct mmc_command *cmd = NULL; unsigned long flags; @@ -521,15 +521,15 @@ static void tifm_sd_card_event(struct tifm_dev *sock) writel(host_status & TIFM_MMCSD_ERRMASK, sock->addr + SOCK_MMCSD_STATUS); if (host_status & TIFM_MMCSD_CTO) - cmd_error = MMC_ERR_TIMEOUT; + cmd_error = -ETIMEDOUT; else if (host_status & TIFM_MMCSD_CCRC) - cmd_error = MMC_ERR_BADCRC; + cmd_error = -EILSEQ; if (cmd->data) { if (host_status & TIFM_MMCSD_DTO) - cmd->data->error = MMC_ERR_TIMEOUT; + cmd->data->error = -ETIMEDOUT; else if (host_status & TIFM_MMCSD_DCRC) - cmd->data->error = MMC_ERR_BADCRC; + cmd->data->error = -EILSEQ; } writel(TIFM_FIFO_INT_SETALL, @@ -722,7 +722,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) return; err_out: - mrq->cmd->error = MMC_ERR_TIMEOUT; + mrq->cmd->error = -ETIMEDOUT; mmc_request_done(mmc, mrq); } @@ -1012,9 +1012,9 @@ static void tifm_sd_remove(struct tifm_dev *sock) writel(TIFM_FIFO_INT_SETALL, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - host->req->cmd->error = MMC_ERR_TIMEOUT; + host->req->cmd->error = -ENOMEDIUM; if (host->req->stop) - host->req->stop->error = MMC_ERR_TIMEOUT; + host->req->stop->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); } spin_unlock_irqrestore(&sock->lock, flags); diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 9bf2a877113b..44968c2279e1 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -317,7 +317,7 @@ static inline void wbsd_get_short_reply(struct wbsd_host *host, * Correct response type? */ if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) { - cmd->error = MMC_ERR_INVALID; + cmd->error = -EILSEQ; return; } @@ -337,7 +337,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host *host, * Correct response type? */ if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) { - cmd->error = MMC_ERR_INVALID; + cmd->error = -EILSEQ; return; } @@ -372,7 +372,7 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) for (i = 3; i >= 0; i--) outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR); - cmd->error = MMC_ERR_NONE; + cmd->error = 0; /* * Wait for the request to complete. @@ -392,13 +392,13 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) /* Card removed? */ if (isr & WBSD_INT_CARD) - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ENOMEDIUM; /* Timeout? */ else if (isr & WBSD_INT_TIMEOUT) - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; /* CRC? */ else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC)) - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; /* All ok */ else { if (cmd->flags & MMC_RSP_136) @@ -585,7 +585,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); } else { - data->error = MMC_ERR_INVALID; + data->error = -EINVAL; return; } @@ -607,7 +607,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) */ BUG_ON(size > 0x10000); if (size > 0x10000) { - data->error = MMC_ERR_INVALID; + data->error = -EINVAL; return; } @@ -669,7 +669,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) } } - data->error = MMC_ERR_NONE; + data->error = 0; } static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) @@ -724,8 +724,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) "%d bytes left.\n", mmc_hostname(host->mmc), count); - if (data->error == MMC_ERR_NONE) - data->error = MMC_ERR_FAILED; + if (!data->error) + data->error = -EIO; } else { /* * Transfer data from DMA buffer to @@ -735,7 +735,7 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) wbsd_dma_to_sg(host, data); } - if (data->error != MMC_ERR_NONE) { + if (data->error) { if (data->bytes_xfered) data->bytes_xfered -= data->blksz; } @@ -767,11 +767,10 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; /* - * If there is no card in the slot then - * timeout immediatly. + * Check that there is actually a card in the slot. */ if (!(host->flags & WBSD_FCARD_PRESENT)) { - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ENOMEDIUM; goto done; } @@ -807,7 +806,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) "supported by this controller.\n", mmc_hostname(host->mmc), cmd->opcode); #endif - cmd->error = MMC_ERR_INVALID; + cmd->error = -EINVAL; goto done; }; @@ -819,7 +818,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) if (cmd->data) { wbsd_prepare_data(host, cmd->data); - if (cmd->data->error != MMC_ERR_NONE) + if (cmd->data->error) goto done; } @@ -830,7 +829,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) * will be finished after the data has * transfered. */ - if (cmd->data && (cmd->error == MMC_ERR_NONE)) { + if (cmd->data && !cmd->error) { /* * Dirty fix for hardware bug. */ @@ -1033,7 +1032,7 @@ static void wbsd_tasklet_card(unsigned long param) mmc_hostname(host->mmc)); wbsd_reset(host); - host->mrq->cmd->error = MMC_ERR_FAILED; + host->mrq->cmd->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); } @@ -1097,7 +1096,7 @@ static void wbsd_tasklet_crc(unsigned long param) DBGF("CRC error\n"); - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; tasklet_schedule(&host->finish_tasklet); @@ -1121,7 +1120,7 @@ static void wbsd_tasklet_timeout(unsigned long param) DBGF("Timeout\n"); - data->error = MMC_ERR_TIMEOUT; + data->error = -ETIMEDOUT; tasklet_schedule(&host->finish_tasklet); diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 63a80ea61124..a2b79518f051 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -54,12 +54,19 @@ struct mmc_command { unsigned int retries; /* max number of retries */ unsigned int error; /* command error */ -#define MMC_ERR_NONE 0 -#define MMC_ERR_TIMEOUT 1 -#define MMC_ERR_BADCRC 2 -#define MMC_ERR_FIFO 3 -#define MMC_ERR_FAILED 4 -#define MMC_ERR_INVALID 5 +/* + * Standard errno values are used for errors, but some have specific + * meaning in the MMC layer: + * + * ETIMEDOUT Card took too long to respond + * EILSEQ Basic format problem with the received or sent data + * (e.g. CRC check failed, incorrect opcode in response + * or bad end bit) + * EINVAL Request cannot be performed because of restrictions + * in hardware and/or the driver + * ENOMEDIUM Host can determine that the slot is empty and is + * actively failing requests + */ struct mmc_data *data; /* data segment associated with cmd */ struct mmc_request *mrq; /* associated request */ From adf66a0dc5e8be8d4e64f3c2114f9b175558235b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 22 Jul 2007 23:08:30 +0200 Subject: [PATCH 0286/2804] mmc: improve error code feedback Now that we use "normal" error codes, improve the reporting and response to error codes in the core. Signed-off-by: Pierre Ossman --- drivers/mmc/core/mmc.c | 27 +++++++++++++++++++-------- drivers/mmc/core/sd.c | 22 +++++++++++++++++----- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index fe483d5af744..258fe73eeaa7 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -176,13 +176,19 @@ static int mmc_read_ext_csd(struct mmc_card *card) ext_csd = kmalloc(512, GFP_KERNEL); if (!ext_csd) { printk(KERN_ERR "%s: could not allocate a buffer to " - "receive the ext_csd. mmc v4 cards will be " - "treated as v3.\n", mmc_hostname(card->host)); + "receive the ext_csd.\n", mmc_hostname(card->host)); return -ENOMEM; } err = mmc_send_ext_csd(card, ext_csd); if (err) { + /* + * We all hosts that cannot perform the command + * to fail more gracefully + */ + if (err != -EINVAL) + goto out; + /* * High capacity cards should have this "magic" size * stored in their CSD. @@ -199,6 +205,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) mmc_hostname(card->host)); err = 0; } + goto out; } @@ -269,8 +276,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto err; if (oldcard) { - if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) + if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) { + err = -ENOENT; goto err; + } card = oldcard; } else { @@ -278,8 +287,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Allocate card structure. */ card = mmc_alloc_card(host); - if (IS_ERR(card)) + if (IS_ERR(card)) { + err = PTR_ERR(card); goto err; + } card->type = MMC_TYPE_MMC; card->rca = 1; @@ -304,10 +315,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto free_card; err = mmc_decode_csd(card); - if (err < 0) + if (err) goto free_card; err = mmc_decode_cid(card); - if (err < 0) + if (err) goto free_card; } @@ -379,7 +390,7 @@ free_card: mmc_remove_card(card); err: - return -EIO; + return err; } /* @@ -587,6 +598,6 @@ err: printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", mmc_hostname(host), err); - return 0; + return err; } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 00895c99d9bb..0a04a6e86ca1 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -213,10 +213,18 @@ static int mmc_read_switch(struct mmc_card *card) err = mmc_sd_switch(card, 0, 0, 1, status); if (err) { + /* + * We all hosts that cannot perform the command + * to fail more gracefully + */ + if (err != -EINVAL) + goto out; + printk(KERN_WARNING "%s: problem reading switch " "capabilities, performance might suffer.\n", mmc_hostname(card->host)); err = 0; + goto out; } @@ -324,8 +332,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto err; if (oldcard) { - if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) + if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) { + err = -ENOENT; goto err; + } card = oldcard; } else { @@ -333,8 +343,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Allocate card structure. */ card = mmc_alloc_card(host); - if (IS_ERR(card)) + if (IS_ERR(card)) { + err = PTR_ERR(card); goto err; + } card->type = MMC_TYPE_SD; memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); @@ -358,7 +370,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto free_card; err = mmc_decode_csd(card); - if (err < 0) + if (err) goto free_card; mmc_decode_cid(card); @@ -449,7 +461,7 @@ free_card: mmc_remove_card(card); err: - return -EIO; + return err; } /* @@ -666,6 +678,6 @@ err: printk(KERN_ERR "%s: error %d whilst initialising SD card\n", mmc_hostname(host), err); - return 0; + return err; } From d7604d76351f7745d0e62d9f2bbcbb917c9013f3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 23 Jul 2007 00:34:07 +0200 Subject: [PATCH 0287/2804] mmc: read ext_csd version number Make sure we do not try to parse a structure we do not understand. Signed-off-by: Pierre Ossman --- drivers/mmc/core/mmc.c | 24 +++++++++++++++++------- include/linux/mmc/mmc.h | 1 + 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 258fe73eeaa7..cdc38b43b799 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -161,6 +161,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) { int err; u8 *ext_csd; + unsigned int ext_csd_struct; BUG_ON(!card); @@ -209,13 +210,22 @@ static int mmc_read_ext_csd(struct mmc_card *card) goto out; } - card->ext_csd.sectors = - ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | - ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | - ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | - ext_csd[EXT_CSD_SEC_CNT + 3] << 24; - if (card->ext_csd.sectors) - mmc_card_set_blockaddr(card); + ext_csd_struct = ext_csd[EXT_CSD_REV]; + if (ext_csd_struct > 2) { + printk("%s: unrecognised EXT_CSD structure version %d\n", + mmc_hostname(card->host), ext_csd_struct); + return -EINVAL; + } + + if (ext_csd_struct >= 2) { + card->ext_csd.sectors = + ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | + ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | + ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | + ext_csd[EXT_CSD_SEC_CNT + 3] << 24; + if (card->ext_csd.sectors) + mmc_card_set_blockaddr(card); + } switch (ext_csd[EXT_CSD_CARD_TYPE]) { case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index e3ed9b95040e..d1d6cbcc1514 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -227,6 +227,7 @@ struct _mmc_csd { #define EXT_CSD_BUS_WIDTH 183 /* R/W */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ /* From b146d26a61e0feab2f12a98ae83fd352830899c0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 24 Jul 2007 19:16:54 +0200 Subject: [PATCH 0288/2804] mmc: mmc_set_data_timeout() parameter write is redundant The write parameter in mmc_set_data_timeout() is redundant as the data structure contains information about the direction of the transfer. Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 4 ++-- drivers/mmc/core/core.c | 8 +++----- drivers/mmc/core/mmc_ops.c | 2 +- drivers/mmc/core/sd_ops.c | 4 ++-- include/linux/mmc/core.h | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 0da341acf32b..9abf29f8435b 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -229,8 +229,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) if (brq.data.blocks > card->host->max_blk_count) brq.data.blocks = card->host->max_blk_count; - mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); - /* * If the host doesn't support multiple block writes, force * block writes to single block. SD cards are excepted from @@ -261,6 +259,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.data.flags |= MMC_DATA_WRITE; } + mmc_set_data_timeout(&brq.data, card); + brq.data.sg = mq->sg; brq.data.sg_len = mmc_queue_map_sg(mq); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 63b67296e92d..51e611f2f33d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -220,13 +220,11 @@ EXPORT_SYMBOL(mmc_wait_for_cmd); * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer - * @write: flag to differentiate reads from writes * * Computes the data timeout parameters according to the * correct algorithm given the card type. */ -void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, - int write) +void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) { unsigned int mult; @@ -239,7 +237,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, * Scale up the multiplier (and therefore the timeout) by * the r2w factor for writes. */ - if (write) + if (data->flags & MMC_DATA_WRITE) mult <<= card->csd.r2w_factor; data->timeout_ns = card->csd.tacc_ns * mult; @@ -255,7 +253,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, timeout_us += data->timeout_clks * 1000 / (card->host->ios.clock / 1000); - if (write) + if (data->flags & MMC_DATA_WRITE) limit_us = 250000; else limit_us = 100000; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 15cd575effaa..39567f91a4b8 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -214,7 +214,7 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) sg_init_one(&sg, ext_csd, 512); - mmc_set_data_timeout(&data, card, 0); + mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index b4d43bd0fedd..491e0306b1b4 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -252,7 +252,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) sg_init_one(&sg, scr, 8); - mmc_set_data_timeout(&data, card, 0); + mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); @@ -302,7 +302,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, sg_init_one(&sg, resp, 64); - mmc_set_data_timeout(&data, card, 0); + mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index a2b79518f051..2a03f8b9cdfb 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -111,7 +111,7 @@ extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, struct mmc_command *, int); -extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *, int); +extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); extern void mmc_claim_host(struct mmc_host *host); extern void mmc_release_host(struct mmc_host *host); From 255d01af9a990fd5166f04ed0cc0b30b7b67e81e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 24 Jul 2007 20:38:53 +0200 Subject: [PATCH 0289/2804] mmc: remove BYTEBLOCK capability Remove the BYTEBLOCK capability and let the broken hosts fail the requests with -EINVAL instead. Signed-off-by: Pierre Ossman --- drivers/mmc/host/at91_mci.c | 1 - drivers/mmc/host/imxmmc.c | 2 +- drivers/mmc/host/mmci.c | 8 ++++++++ drivers/mmc/host/sdhci.c | 2 +- drivers/mmc/host/tifm_sd.c | 13 ++++++++++--- drivers/mmc/host/wbsd.c | 2 +- include/linux/mmc/host.h | 5 ++--- 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 810a433ce532..576d7cb0b3ec 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -834,7 +834,6 @@ static int __init at91_mci_probe(struct platform_device *pdev) mmc->f_min = 375000; mmc->f_max = 25000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_BYTEBLOCK; mmc->max_blk_size = 4095; mmc->max_blk_count = mmc->max_req_size; diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 04458c342812..e33c123c7027 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -963,7 +963,7 @@ static int imxmci_probe(struct platform_device *pdev) mmc->f_min = 150000; mmc->f_max = CLK_RATE/2; mmc->ocr_avail = MMC_VDD_32_33; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK; + mmc->caps = MMC_CAP_4_BIT_DATA; /* MMC core transfer sizes tunable parameters */ mmc->max_hw_segs = 64; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index d53e9a8bdaa2..4a72772f4fe4 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -391,6 +391,14 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); + if (mrq->data && (hweight32(mrq->data->blksz) > 1)) { + printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", + mmc_hostname(mmc), mrq->data->blksz); + mrq->cmd->error = -EINVAL; + mmc_request_done(mmc, mrq); + return; + } + spin_lock_irq(&host->lock); host->mrq = mrq; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 479d6a265dd1..c63edc5c17e4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1309,7 +1309,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED; diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index b4a56e5e5132..951392d2ce37 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -626,14 +626,21 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_lock_irqsave(&sock->lock, flags); if (host->eject) { - spin_unlock_irqrestore(&sock->lock, flags); + mrq->cmd->error = -ENOMEDIUM; goto err_out; } if (host->req) { printk(KERN_ERR "%s : unfinished request detected\n", sock->dev.bus_id); - spin_unlock_irqrestore(&sock->lock, flags); + mrq->cmd->error = -ETIMEDOUT; + goto err_out; + } + + if (mrq->data && (hweight32(mrq->data->blksz) > 1)) { + printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", + sock->dev.bus_id, mrq->data->blksz); + mrq->cmd->error = -EINVAL; goto err_out; } @@ -722,7 +729,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) return; err_out: - mrq->cmd->error = -ETIMEDOUT; + spin_unlock_irqrestore(&sock->lock, flags); mmc_request_done(mmc, mrq); } diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 44968c2279e1..80db11c05f2a 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1219,7 +1219,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) mmc->f_min = 375000; mmc->f_max = 24000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; spin_lock_init(&host->lock); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index b1350dfd3e91..8e2642ebf02f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -87,9 +87,8 @@ struct mmc_host { #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ #define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */ -#define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */ -#define MMC_CAP_MMC_HIGHSPEED (1 << 3) /* Can do MMC high-speed timing */ -#define MMC_CAP_SD_HIGHSPEED (1 << 4) /* Can do SD high-speed timing */ +#define MMC_CAP_MMC_HIGHSPEED (1 << 2) /* Can do MMC high-speed timing */ +#define MMC_CAP_SD_HIGHSPEED (1 << 3) /* Can do SD high-speed timing */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ From be0192aae1aed3fbf172e3f9a22ec75392c1b175 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 24 Jul 2007 21:11:47 +0200 Subject: [PATCH 0290/2804] mmc: remove confusing flag The MMC_DATA_MULTI flag never had a proper definition of what it means, so remove it and let the drivers check the block count in the request. Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 1 - drivers/mmc/host/at91_mci.c | 4 ++-- drivers/mmc/host/au1xmmc.c | 26 ++++++++++++++------------ include/linux/mmc/core.h | 1 - 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 9abf29f8435b..ab510689ecde 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -241,7 +241,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.data.blocks = 1; if (brq.data.blocks > 1) { - brq.data.flags |= MMC_DATA_MULTI; brq.mrq.stop = &brq.stop; readcmd = MMC_READ_MULTIPLE_BLOCK; writecmd = MMC_WRITE_MULTIPLE_BLOCK; diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 576d7cb0b3ec..8ec317802347 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -328,7 +328,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) data = cmd->data; if (!data) return; - if (cmd->data->flags & MMC_DATA_MULTI) { + if (cmd->data->blocks > 1) { pr_debug("multiple write : wait for BLKE...\n"); at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); } else @@ -439,7 +439,7 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command if (data->flags & MMC_DATA_STREAM) cmdr |= AT91_MCI_TRTYP_STREAM; - if (data->flags & MMC_DATA_MULTI) + if (data->blocks > 1) cmdr |= AT91_MCI_TRTYP_MULTIPLE; } else { diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 49b0367e57c8..92c4d0dfee43 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -186,7 +186,7 @@ static void au1xmmc_tasklet_finish(unsigned long param) } static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, - struct mmc_command *cmd, unsigned int flags) + struct mmc_command *cmd, struct mmc_data *data) { u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); @@ -211,16 +211,18 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, return -EINVAL; } - if (flags & MMC_DATA_READ) { - if (flags & MMC_DATA_MULTI) - mmccmd |= SD_CMD_CT_4; - else - mmccmd |= SD_CMD_CT_2; - } else if (flags & MMC_DATA_WRITE) { - if (flags & MMC_DATA_MULTI) - mmccmd |= SD_CMD_CT_3; - else - mmccmd |= SD_CMD_CT_1; + if (data) { + if (flags & MMC_DATA_READ) { + if (data->blocks > 1) + mmccmd |= SD_CMD_CT_4; + else + mmccmd |= SD_CMD_CT_2; + } else if (flags & MMC_DATA_WRITE) { + if (data->blocks > 1) + mmccmd |= SD_CMD_CT_3; + else + mmccmd |= SD_CMD_CT_1; + } } au_writel(cmd->arg, HOST_CMDARG(host)); @@ -673,7 +675,7 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) } if (!ret) - ret = au1xmmc_send_command(host, 0, mrq->cmd, flags); + ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data); if (ret) { mrq->cmd->error = ret; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 2a03f8b9cdfb..29c98ae10aff 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -83,7 +83,6 @@ struct mmc_data { #define MMC_DATA_WRITE (1 << 8) #define MMC_DATA_READ (1 << 9) #define MMC_DATA_STREAM (1 << 10) -#define MMC_DATA_MULTI (1 << 11) unsigned int bytes_xfered; From 8fdd8521dcc9d89072f3ca5dca444560bcea39c6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 24 Jul 2007 21:53:43 +0200 Subject: [PATCH 0291/2804] mmc: add missing printk levels Some printk:s were missing an explicit level. Signed-off-by: Pierre Ossman --- drivers/mmc/core/mmc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index cdc38b43b799..ba7a847cfd08 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -212,8 +212,9 @@ static int mmc_read_ext_csd(struct mmc_card *card) ext_csd_struct = ext_csd[EXT_CSD_REV]; if (ext_csd_struct > 2) { - printk("%s: unrecognised EXT_CSD structure version %d\n", - mmc_hostname(card->host), ext_csd_struct); + printk(KERN_ERR "%s: unrecognised EXT_CSD structure " + "version %d\n", mmc_hostname(card->host), + ext_csd_struct); return -EINVAL; } From 1d4de9edd6c9ad676b20729ab15c04b78e9a50c5 Mon Sep 17 00:00:00 2001 From: Marc Pignat Date: Thu, 9 Aug 2007 13:56:29 +0200 Subject: [PATCH 0292/2804] mmc: at91_mci: disable handling of blocks with size not multiple of 4 bytes This kind of transfer is not supported, so don't advertise it and make it fail early. Signed-off-by: Marc Pignat Signed-off-by: Pierre Ossman --- drivers/mmc/host/at91_mci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 8ec317802347..6ba98a49612d 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -428,6 +428,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command } if (data) { + + if ( data->blksz & 0x3 ) { + pr_debug("Unsupported block size\n"); + cmd->error = -EINVAL; + mmc_request_done(host->mmc, host->request); + return; + } + block_length = data->blksz; blocks = data->blocks; From 5c4e6f1301649d5b29dd0f70e6da83e728ab5ca5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 May 2007 20:23:20 +0200 Subject: [PATCH 0293/2804] mmc: detect SDIO cards Really basic init sequence for SDIO cards. Signed-off-by: Pierre Ossman --- MAINTAINERS | 2 +- drivers/mmc/core/Makefile | 3 +- drivers/mmc/core/bus.c | 8 ++ drivers/mmc/core/core.c | 42 ++++++--- drivers/mmc/core/sdio.c | 176 ++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_ops.c | 49 ++++++++++ drivers/mmc/core/sdio_ops.h | 18 ++++ include/linux/mmc/card.h | 2 + include/linux/mmc/core.h | 1 + include/linux/mmc/sdio.h | 19 ++++ 10 files changed, 305 insertions(+), 15 deletions(-) create mode 100644 drivers/mmc/core/sdio.c create mode 100644 drivers/mmc/core/sdio_ops.c create mode 100644 drivers/mmc/core/sdio_ops.h create mode 100644 include/linux/mmc/sdio.h diff --git a/MAINTAINERS b/MAINTAINERS index 9a91d9e3f1f2..c22d34b11f64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2561,7 +2561,7 @@ L: linux-kernel@vger.kernel.org W: http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html S: Maintained -MULTIMEDIA CARD (MMC) AND SECURE DIGITAL (SD) SUBSYSTEM +MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM P: Pierre Ossman M: drzeus-mmc@drzeus.cx L: linux-kernel@vger.kernel.org diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 3fdd08c7f143..2fa5ebbc170d 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -8,5 +8,6 @@ endif obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ - mmc.o mmc_ops.o sd.o sd_ops.o + mmc.o mmc_ops.o sd.o sd_ops.o \ + sdio.o sdio_ops.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 817a79462b3d..87a6070522f8 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -34,6 +34,8 @@ static ssize_t mmc_type_show(struct device *dev, return sprintf(buf, "MMC\n"); case MMC_TYPE_SD: return sprintf(buf, "SD\n"); + case MMC_TYPE_SDIO: + return sprintf(buf, "SDIO\n"); default: return -EFAULT; } @@ -76,6 +78,9 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, case MMC_TYPE_SD: add_env("MMC_TYPE=%s", "SD"); break; + case MMC_TYPE_SDIO: + add_env("MMC_TYPE=%s", "SDIO"); + break; } add_env("MMC_NAME=%s", mmc_card_name(card)); @@ -221,6 +226,9 @@ int mmc_add_card(struct mmc_card *card) if (mmc_card_blockaddr(card)) type = "SDHC"; break; + case MMC_TYPE_SDIO: + type = "SDIO"; + break; default: type = "?"; break; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 51e611f2f33d..092fa906ab86 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -32,9 +32,11 @@ #include "mmc_ops.h" #include "sd_ops.h" +#include "sdio_ops.h" extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr); extern int mmc_attach_sd(struct mmc_host *host, u32 ocr); +extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); static struct workqueue_struct *workqueue; @@ -595,24 +597,38 @@ void mmc_rescan(struct work_struct *work) mmc_send_if_cond(host, host->ocr_avail); + /* + * First we search for SDIO... + */ + err = mmc_send_io_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_sdio(host, ocr)) + mmc_power_off(host); + return; + } + + /* + * ...then normal SD... + */ err = mmc_send_app_op_cond(host, 0, &ocr); if (!err) { if (mmc_attach_sd(host, ocr)) mmc_power_off(host); - } else { - /* - * If we fail to detect any SD cards then try - * searching for MMC cards. - */ - err = mmc_send_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_mmc(host, ocr)) - mmc_power_off(host); - } else { - mmc_power_off(host); - mmc_release_host(host); - } + return; } + + /* + * ...and finally MMC. + */ + err = mmc_send_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_mmc(host, ocr)) + mmc_power_off(host); + return; + } + + mmc_release_host(host); + mmc_power_off(host); } else { if (host->bus_ops->detect && !host->bus_dead) host->bus_ops->detect(host); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c new file mode 100644 index 000000000000..ac0dd68df8e7 --- /dev/null +++ b/drivers/mmc/core/sdio.c @@ -0,0 +1,176 @@ +/* + * linux/drivers/mmc/sdio.c + * + * Copyright 2006-2007 Pierre Ossman + * + * 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 "core.h" +#include "bus.h" +#include "mmc_ops.h" +#include "sd_ops.h" +#include "sdio_ops.h" + +/* + * Host is being removed. Free up the current card. + */ +static void mmc_sdio_remove(struct mmc_host *host) +{ + BUG_ON(!host); + BUG_ON(!host->card); + + mmc_remove_card(host->card); + host->card = NULL; +} + +/* + * Card detection callback from host. + */ +static void mmc_sdio_detect(struct mmc_host *host) +{ + int err; + + BUG_ON(!host); + BUG_ON(!host->card); + + mmc_claim_host(host); + + /* + * Just check if our card has been removed. + */ + err = mmc_select_card(host->card); + + mmc_release_host(host); + + if (err) { + mmc_sdio_remove(host); + + mmc_claim_host(host); + mmc_detach_bus(host); + mmc_release_host(host); + } +} + + +static const struct mmc_bus_ops mmc_sdio_ops = { + .remove = mmc_sdio_remove, + .detect = mmc_sdio_detect, +}; + + +/* + * Starting point for SDIO card init. + */ +int mmc_attach_sdio(struct mmc_host *host, u32 ocr) +{ + int err; + int funcs; + struct mmc_card *card; + + BUG_ON(!host); + BUG_ON(!host->claimed); + + mmc_attach_bus(host, &mmc_sdio_ops); + + /* + * Sanity check the voltages that the card claims to + * support. + */ + if (ocr & 0x7F) { + printk(KERN_WARNING "%s: card claims to support voltages " + "below the defined range. These will be ignored.\n", + mmc_hostname(host)); + ocr &= ~0x7F; + } + + if (ocr & MMC_VDD_165_195) { + printk(KERN_WARNING "%s: SDIO card claims to support the " + "incompletely defined 'low voltage range'. This " + "will be ignored.\n", mmc_hostname(host)); + ocr &= ~MMC_VDD_165_195; + } + + host->ocr = mmc_select_voltage(host, ocr); + + /* + * Can we support the voltage(s) of the card(s)? + */ + if (!host->ocr) { + err = -EINVAL; + goto err; + } + + /* + * Inform the card of the voltage + */ + err = mmc_send_io_op_cond(host, host->ocr, &ocr); + if (err) + goto err; + + /* + * The number of functions on the card is encoded inside + * the ocr. + */ + funcs = (ocr & 0x70000000) >> 28; + + /* + * Allocate card structure. + */ + card = mmc_alloc_card(host); + if (IS_ERR(card)) { + err = PTR_ERR(card); + goto err; + } + + card->type = MMC_TYPE_SDIO; + + /* + * Set card RCA. + */ + err = mmc_send_relative_addr(host, &card->rca); + if (err) + goto free_card; + + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + + /* + * Select card, as all following commands rely on that. + */ + err = mmc_select_card(card); + if (err) + goto free_card; + + host->card = card; + + mmc_release_host(host); + + err = mmc_add_card(host->card); + if (err) + goto reclaim_host; + + return 0; + +reclaim_host: + mmc_claim_host(host); +free_card: + mmc_remove_card(card); + host->card = NULL; +err: + mmc_detach_bus(host); + mmc_release_host(host); + + printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", + mmc_hostname(host), err); + + return err; +} + diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c new file mode 100644 index 000000000000..d6f9f9d85178 --- /dev/null +++ b/drivers/mmc/core/sdio_ops.c @@ -0,0 +1,49 @@ +/* + * linux/drivers/mmc/sdio_ops.c + * + * Copyright 2006-2007 Pierre Ossman + * + * 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 "core.h" + +int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ + struct mmc_command cmd; + int i, err = 0; + + BUG_ON(!host); + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_IO_SEND_OP_COND; + cmd.arg = ocr; + cmd.flags = MMC_RSP_R4 | MMC_CMD_BCR; + + for (i = 100; i; i--) { + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); + if (err) + break; + + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + break; + + err = -ETIMEDOUT; + + mmc_delay(10); + } + + if (rocr) + *rocr = cmd.resp[0]; + + return err; +} + diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h new file mode 100644 index 000000000000..d8c982976f19 --- /dev/null +++ b/drivers/mmc/core/sdio_ops.h @@ -0,0 +1,18 @@ +/* + * linux/drivers/mmc/sdio_ops.c + * + * Copyright 2006-2007 Pierre Ossman + * + * 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 _MMC_SDIO_OPS_H +#define _MMC_SDIO_OPS_H + +int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); + +#endif + diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index badf702fcff4..43480ebebf9a 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -67,6 +67,7 @@ struct mmc_card { unsigned int type; /* card type */ #define MMC_TYPE_MMC 0 /* MMC card */ #define MMC_TYPE_SD 1 /* SD card */ +#define MMC_TYPE_SDIO 2 /* SDIO card */ unsigned int state; /* (our) card state */ #define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ #define MMC_STATE_READONLY (1<<1) /* card is read-only */ @@ -84,6 +85,7 @@ struct mmc_card { #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) #define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD) +#define mmc_card_sdio(c) ((c)->type == MMC_TYPE_SDIO) #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 29c98ae10aff..8faa436c5571 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -41,6 +41,7 @@ struct mmc_command { #define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R4 (MMC_RSP_PRESENT) #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h new file mode 100644 index 000000000000..d1a0b15cdfdf --- /dev/null +++ b/include/linux/mmc/sdio.h @@ -0,0 +1,19 @@ +/* + * include/linux/mmc/sdio.h + * + * Copyright 2006-2007 Pierre Ossman + * + * 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 MMC_SDIO_H +#define MMC_SDIO_H + +/* SDIO commands type argument response */ +#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ + +#endif + From b2bcc798bbb482b2909801280f3c4aff8cbbf5be Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 May 2007 20:25:21 +0200 Subject: [PATCH 0294/2804] mmc: implement SDIO IO_RW_DIRECT operation Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_ops.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_ops.h | 2 ++ include/linux/mmc/core.h | 1 + include/linux/mmc/sdio.h | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index d6f9f9d85178..31233f7b55cd 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -47,3 +48,39 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) return err; } +int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8* out) +{ + struct mmc_command cmd; + int err; + + BUG_ON(!card); + BUG_ON(fn > 7); + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_IO_RW_DIRECT; + cmd.arg = write ? 0x80000000 : 0x00000000; + cmd.arg |= fn << 28; + cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; + cmd.arg |= addr << 9; + cmd.arg |= in; + cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if (err) + return err; + + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + + if (out) + *out = cmd.resp[0] & 0xFF; + + return 0; +} + diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index d8c982976f19..f0e9d69e5ce8 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -13,6 +13,8 @@ #define _MMC_SDIO_OPS_H int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); +int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8* out); #endif diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 8faa436c5571..43a92736be63 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -42,6 +42,7 @@ struct mmc_command { #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) #define MMC_RSP_R4 (MMC_RSP_PRESENT) +#define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index d1a0b15cdfdf..e5f06de7d527 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -14,6 +14,40 @@ /* SDIO commands type argument response */ #define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ +#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */ + +/* + * SD_IO_RW_DIRECT argument format: + * + * [31] R/W flag + * [30:28] Function number + * [27] RAW flag + * [25:9] Register address + * [7:0] Data + */ + +/* + SDIO status in R5 + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R5_COM_CRC_ERROR (1 << 15) /* er, b */ +#define R5_ILLEGAL_COMMAND (1 << 14) /* er, b */ +#define R5_ERROR (1 << 11) /* erx, c */ +#define R5_FUNCTION_NUMBER (1 << 9) /* er, c */ +#define R5_OUT_OF_RANGE (1 << 8) /* er, c */ +#define R5_STATUS(x) (x & 0xCB00) +#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12) /* s, b */ #endif From e29a7d73f4277eb92aa64e17017dea33460828ef Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 26 May 2007 13:48:18 +0200 Subject: [PATCH 0295/2804] mmc: basic SDIO device model Add the sdio bus type and basic device handling. Signed-off-by: Pierre Ossman --- drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/core.c | 27 +++++-- drivers/mmc/core/sdio.c | 72 ++++++++++++++++--- drivers/mmc/core/sdio_bus.c | 129 ++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_bus.h | 22 ++++++ include/linux/mmc/card.h | 7 ++ include/linux/mmc/sdio_func.h | 35 +++++++++ 7 files changed, 279 insertions(+), 15 deletions(-) create mode 100644 drivers/mmc/core/sdio_bus.c create mode 100644 drivers/mmc/core/sdio_bus.h create mode 100644 include/linux/mmc/sdio_func.h diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 2fa5ebbc170d..71ab3d1e1eb2 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -9,5 +9,5 @@ endif obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ - sdio.o sdio_ops.o + sdio.o sdio_ops.o sdio_bus.o diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 092fa906ab86..9747455928da 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -29,6 +29,7 @@ #include "core.h" #include "bus.h" #include "host.h" +#include "sdio_bus.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -739,16 +740,32 @@ static int __init mmc_init(void) return -ENOMEM; ret = mmc_register_bus(); - if (ret == 0) { - ret = mmc_register_host_class(); - if (ret) - mmc_unregister_bus(); - } + if (ret) + goto destroy_workqueue; + + ret = mmc_register_host_class(); + if (ret) + goto unregister_bus; + + ret = sdio_register_bus(); + if (ret) + goto unregister_host_class; + + return 0; + +unregister_host_class: + mmc_unregister_host_class(); +unregister_bus: + mmc_unregister_bus(); +destroy_workqueue: + destroy_workqueue(workqueue); + return ret; } static void __exit mmc_exit(void) { + sdio_unregister_bus(); mmc_unregister_host_class(); mmc_unregister_bus(); destroy_workqueue(workqueue); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ac0dd68df8e7..444328581cec 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -13,21 +13,49 @@ #include #include +#include #include "core.h" #include "bus.h" +#include "sdio_bus.h" #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" +static int sdio_init_func(struct mmc_card *card, unsigned int fn) +{ + struct sdio_func *func; + + BUG_ON(fn > SDIO_MAX_FUNCS); + + func = sdio_alloc_func(card); + if (IS_ERR(func)) + return PTR_ERR(func); + + func->num = fn; + + card->sdio_func[fn - 1] = func; + + return 0; +} + /* * Host is being removed. Free up the current card. */ static void mmc_sdio_remove(struct mmc_host *host) { + int i; + BUG_ON(!host); BUG_ON(!host->card); + for (i = 0;i < host->card->sdio_funcs;i++) { + if (host->card->sdio_func[i]) { + sdio_remove_func(host->card->sdio_func[i]); + host->card->sdio_func[i] = NULL; + } + } + mmc_remove_card(host->card); host->card = NULL; } @@ -73,7 +101,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { int mmc_attach_sdio(struct mmc_host *host, u32 ocr) { int err; - int funcs; + int i, funcs; struct mmc_card *card; BUG_ON(!host); @@ -132,13 +160,16 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) } card->type = MMC_TYPE_SDIO; + card->sdio_funcs = funcs; + + host->card = card; /* * Set card RCA. */ err = mmc_send_relative_addr(host, &card->rca); if (err) - goto free_card; + goto remove; mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); @@ -147,23 +178,46 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) */ err = mmc_select_card(card); if (err) - goto free_card; + goto remove; - host->card = card; + /* + * Initialize (but don't add) all present functions. + */ + for (i = 0;i < funcs;i++) { + err = sdio_init_func(host->card, i + 1); + if (err) + goto remove; + } mmc_release_host(host); + /* + * First add the card to the driver model... + */ err = mmc_add_card(host->card); if (err) - goto reclaim_host; + goto remove_added; + + /* + * ...then the SDIO functions. + */ + for (i = 0;i < funcs;i++) { + err = sdio_add_func(host->card->sdio_func[i]); + if (err) + goto remove_added; + } return 0; -reclaim_host: + +remove_added: + /* Remove without lock if the device has been added. */ + mmc_sdio_remove(host); mmc_claim_host(host); -free_card: - mmc_remove_card(card); - host->card = NULL; +remove: + /* And with lock if it hasn't been added. */ + if (host->card) + mmc_sdio_remove(host); err: mmc_detach_bus(host); mmc_release_host(host); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c new file mode 100644 index 000000000000..59c909e1c7c6 --- /dev/null +++ b/drivers/mmc/core/sdio_bus.c @@ -0,0 +1,129 @@ +/* + * linux/drivers/mmc/core/sdio_bus.c + * + * Copyright 2007 Pierre Ossman + * + * 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. + * + * SDIO function driver model + */ + +#include +#include + +#include +#include + +#include "sdio_bus.h" + +#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) + +/* + * This currently matches any SDIO function to any driver in order + * to help initial development and testing. + */ +static int sdio_bus_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static int +sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, + int buf_size) +{ + envp[0] = NULL; + + return 0; +} + +static int sdio_bus_probe(struct device *dev) +{ + return -ENODEV; +} + +static int sdio_bus_remove(struct device *dev) +{ + return 0; +} + +static struct bus_type sdio_bus_type = { + .name = "sdio", + .match = sdio_bus_match, + .uevent = sdio_bus_uevent, + .probe = sdio_bus_probe, + .remove = sdio_bus_remove, +}; + +int sdio_register_bus(void) +{ + return bus_register(&sdio_bus_type); +} + +void sdio_unregister_bus(void) +{ + bus_unregister(&sdio_bus_type); +} + +static void sdio_release_func(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + + kfree(func); +} + +/* + * Allocate and initialise a new SDIO function structure. + */ +struct sdio_func *sdio_alloc_func(struct mmc_card *card) +{ + struct sdio_func *func; + + func = kmalloc(sizeof(struct sdio_func), GFP_KERNEL); + if (!func) + return ERR_PTR(-ENOMEM); + + memset(func, 0, sizeof(struct sdio_func)); + + func->card = card; + + device_initialize(&func->dev); + + func->dev.parent = &card->dev; + func->dev.bus = &sdio_bus_type; + func->dev.release = sdio_release_func; + + return func; +} + +/* + * Register a new SDIO function with the driver model. + */ +int sdio_add_func(struct sdio_func *func) +{ + int ret; + + snprintf(func->dev.bus_id, sizeof(func->dev.bus_id), + "%s:%d", mmc_card_id(func->card), func->num); + + ret = device_add(&func->dev); + if (ret == 0) + sdio_func_set_present(func); + + return ret; +} + +/* + * Unregister a SDIO function with the driver model, and + * (eventually) free it. + */ +void sdio_remove_func(struct sdio_func *func) +{ + if (sdio_func_present(func)) + device_del(&func->dev); + + put_device(&func->dev); +} + diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h new file mode 100644 index 000000000000..567a76821ba7 --- /dev/null +++ b/drivers/mmc/core/sdio_bus.h @@ -0,0 +1,22 @@ +/* + * linux/drivers/mmc/core/sdio_bus.h + * + * Copyright 2007 Pierre Ossman + * + * 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 _MMC_CORE_SDIO_BUS_H +#define _MMC_CORE_SDIO_BUS_H + +struct sdio_func *sdio_alloc_func(struct mmc_card *card); +int sdio_add_func(struct sdio_func *func); +void sdio_remove_func(struct sdio_func *func); + +int sdio_register_bus(void); +void sdio_unregister_bus(void); + +#endif + diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 43480ebebf9a..9f5f74482d98 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -56,6 +56,9 @@ struct sd_switch_caps { }; struct mmc_host; +struct sdio_func; + +#define SDIO_MAX_FUNCS 7 /* * MMC device @@ -73,6 +76,7 @@ struct mmc_card { #define MMC_STATE_READONLY (1<<1) /* card is read-only */ #define MMC_STATE_HIGHSPEED (1<<2) /* card is in high speed mode */ #define MMC_STATE_BLOCKADDR (1<<3) /* card uses block-addressing */ + u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ u32 raw_scr[2]; /* raw card SCR */ @@ -81,6 +85,9 @@ struct mmc_card { struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ struct sd_scr scr; /* extra SD information */ struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ + + unsigned int sdio_funcs; /* number of SDIO functions */ + struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ }; #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h new file mode 100644 index 000000000000..50c78db420e6 --- /dev/null +++ b/include/linux/mmc/sdio_func.h @@ -0,0 +1,35 @@ +/* + * include/linux/mmc/sdio_func.h + * + * Copyright 2007 Pierre Ossman + * + * 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 MMC_SDIO_FUNC_H +#define MMC_SDIO_FUNC_H + +struct mmc_card; + +/* + * SDIO function devices + */ +struct sdio_func { + struct mmc_card *card; /* the card this device belongs to */ + struct device dev; /* the device */ + unsigned int num; /* function number */ + unsigned int state; /* function state */ +#define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ +}; + +#define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT) + +#define sdio_func_set_present(f) ((f)->state |= SDIO_STATE_PRESENT) + +#define sdio_func_id(f) ((f)->dev.bus_id) + +#endif + From f76c85154d320497bf1a939a98d6c432edcbd4a9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 27 May 2007 12:00:02 +0200 Subject: [PATCH 0296/2804] mmc: add SDIO driver handling Add basic driver handling to the SDIO device model. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 23 +++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 18 ++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 59c909e1c7c6..fa488cea8594 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -67,6 +67,29 @@ void sdio_unregister_bus(void) bus_unregister(&sdio_bus_type); } +/** + * sdio_register_driver - register a function driver + * @drv: SDIO function driver + */ +int sdio_register_driver(struct sdio_driver *drv) +{ + drv->drv.name = drv->name; + drv->drv.bus = &sdio_bus_type; + return driver_register(&drv->drv); +} +EXPORT_SYMBOL_GPL(sdio_register_driver); + +/** + * sdio_unregister_driver - unregister a function driver + * @drv: SDIO function driver + */ +void sdio_unregister_driver(struct sdio_driver *drv) +{ + drv->drv.bus = &sdio_bus_type; + driver_unregister(&drv->drv); +} +EXPORT_SYMBOL_GPL(sdio_unregister_driver); + static void sdio_release_func(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 50c78db420e6..13a1a9ca4b66 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -31,5 +31,23 @@ struct sdio_func { #define sdio_func_id(f) ((f)->dev.bus_id) +#define sdio_get_drvdata(f) dev_get_drvdata(&(f)->dev) +#define sdio_set_drvdata(f,d) dev_set_drvdata(&(f)->dev, d) + +/* + * SDIO function device driver + */ +struct sdio_driver { + char *name; + + int (*probe)(struct sdio_func *); + void (*remove)(struct sdio_func *); + + struct device_driver drv; +}; + +extern int sdio_register_driver(struct sdio_driver *); +extern void sdio_unregister_driver(struct sdio_driver *); + #endif From 46f555f2731a14545a09ec06d27bd18e8e07069f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 27 May 2007 12:57:15 +0200 Subject: [PATCH 0297/2804] mmc: add basic SDIO I/O operations Add command wrappers that simplify register access from SDIO function drivers. Signed-off-by: Pierre Ossman --- drivers/mmc/core/Makefile | 3 +- drivers/mmc/core/sdio_io.c | 105 ++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 12 ++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 drivers/mmc/core/sdio_io.c diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 71ab3d1e1eb2..bf7a00248039 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -9,5 +9,6 @@ endif obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ - sdio.o sdio_ops.o sdio_bus.o + sdio.o sdio_ops.o sdio_bus.o \ + sdio_io.o diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c new file mode 100644 index 000000000000..4ad06e575634 --- /dev/null +++ b/drivers/mmc/core/sdio_io.c @@ -0,0 +1,105 @@ +/* + * linux/drivers/mmc/core/sdio_io.c + * + * Copyright 2007 Pierre Ossman + * + * 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 "sdio_ops.h" + +/** + * sdio_claim_host - exclusively claim a bus for a certain SDIO function + * @func: SDIO function that will be accessed + * + * Claim a bus for a set of operations. The SDIO function given + * is used to figure out which bus is relevant. + */ +void sdio_claim_host(struct sdio_func *func) +{ + BUG_ON(!func); + BUG_ON(!func->card); + + mmc_claim_host(func->card->host); +} +EXPORT_SYMBOL_GPL(sdio_claim_host); + +/** + * sdio_release_host - release a bus for a certain SDIO function + * @func: SDIO function that was accessed + * + * Release a bus, allowing others to claim the bus for their + * operations. + */ +void sdio_release_host(struct sdio_func *func) +{ + BUG_ON(!func); + BUG_ON(!func->card); + + mmc_release_host(func->card->host); +} +EXPORT_SYMBOL_GPL(sdio_release_host); + +/** + * sdio_readb - read a single byte from a SDIO function + * @func: SDIO function to access + * @addr: address to read + * @err_ret: optional status value from transfer + * + * Reads a single byte from the address space of a given SDIO + * function. If there is a problem reading the address, 0xff + * is returned and @err_ret will contain the error code. + */ +unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, + int *err_ret) +{ + int ret; + unsigned char val; + + BUG_ON(!func); + + if (err_ret) + *err_ret = 0; + + ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFF; + } + + return val; +} +EXPORT_SYMBOL_GPL(sdio_readb); + +/** + * sdio_writeb - write a single byte to a SDIO function + * @func: SDIO function to access + * @b: byte to write + * @addr: address to write to + * @err_ret: optional status value from transfer + * + * Writes a single byte to the address space of a given SDIO + * function. @err_ret will contain the status of the actual + * transfer. + */ +void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, + int *err_ret) +{ + int ret; + + BUG_ON(!func); + + ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL); + if (err_ret) + *err_ret = ret; +} +EXPORT_SYMBOL_GPL(sdio_writeb); + diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 13a1a9ca4b66..5c56df196287 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -49,5 +49,17 @@ struct sdio_driver { extern int sdio_register_driver(struct sdio_driver *); extern void sdio_unregister_driver(struct sdio_driver *); +/* + * SDIO I/O operations + */ +extern void sdio_claim_host(struct sdio_func *func); +extern void sdio_release_host(struct sdio_func *func); + +extern unsigned char sdio_readb(struct sdio_func *func, + unsigned int addr, int *err_ret); + +extern void sdio_writeb(struct sdio_func *func, unsigned char b, + unsigned int addr, int *err_ret); + #endif From fa64efa1f2a0672767ad0753a6e4bfa4bcc77b87 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 27 May 2007 14:22:37 +0200 Subject: [PATCH 0298/2804] mmc: enable/disable functions for SDIO Like many other buses, the devices (functions) on the SDIO bus must be enabled before they can be used. Add functions that allow drivers to do so. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_io.c | 93 +++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio.h | 92 ++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 3 ++ 3 files changed, 188 insertions(+) diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 4ad06e575634..eb6c20935cef 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -11,6 +11,7 @@ #include #include +#include #include #include "sdio_ops.h" @@ -47,6 +48,98 @@ void sdio_release_host(struct sdio_func *func) } EXPORT_SYMBOL_GPL(sdio_release_host); +/** + * sdio_enable_func - enables a SDIO function for usage + * @func: SDIO function to enable + * + * Powers up and activates a SDIO function so that register + * access is possible. + */ +int sdio_enable_func(struct sdio_func *func) +{ + int ret; + unsigned char reg; + unsigned long timeout; + + BUG_ON(!func); + BUG_ON(!func->card); + + pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func)); + + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, ®); + if (ret) + goto err; + + reg |= 1 << func->num; + + ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL); + if (ret) + goto err; + + /* + * FIXME: This should timeout based on information in the CIS, + * but we don't have card to parse that yet. + */ + timeout = jiffies + HZ; + + while (1) { + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, ®); + if (ret) + goto err; + if (reg & (1 << func->num)) + break; + ret = -ETIME; + if (time_after(jiffies, timeout)) + goto err; + } + + pr_debug("SDIO: Enabled device %s\n", sdio_func_id(func)); + + return 0; + +err: + pr_debug("SDIO: Failed to enable device %s\n", sdio_func_id(func)); + return ret; +} +EXPORT_SYMBOL_GPL(sdio_enable_func); + +/** + * sdio_disable_func - disable a SDIO function + * @func: SDIO function to disable + * + * Powers down and deactivates a SDIO function. Register access + * to this function will fail until the function is reenabled. + */ +int sdio_disable_func(struct sdio_func *func) +{ + int ret; + unsigned char reg; + + BUG_ON(!func); + BUG_ON(!func->card); + + pr_debug("SDIO: Disabling device %s...\n", sdio_func_id(func)); + + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, ®); + if (ret) + goto err; + + reg &= ~(1 << func->num); + + ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL); + if (ret) + goto err; + + pr_debug("SDIO: Disabled device %s\n", sdio_func_id(func)); + + return 0; + +err: + pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func)); + return -EIO; +} +EXPORT_SYMBOL_GPL(sdio_disable_func); + /** * sdio_readb - read a single byte from a SDIO function * @func: SDIO function to access diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index e5f06de7d527..56239f4aab04 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -49,5 +49,97 @@ #define R5_STATUS(x) (x & 0xCB00) #define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12) /* s, b */ +/* + * Card Common Control Registers (CCCR) + */ + +#define SDIO_CCCR_CCCR 0x00 + +#define SDIO_CCCR_REV_1_00 0 /* CCCR/FBR Version 1.00 */ +#define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */ +#define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */ + +#define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */ +#define SDIO_SDIO_REV_1_10 1 /* SDIO Spec Version 1.10 */ +#define SDIO_SDIO_REV_1_20 2 /* SDIO Spec Version 1.20 */ +#define SDIO_SDIO_REV_2_00 3 /* SDIO Spec Version 2.00 */ + +#define SDIO_CCCR_SD 0x01 + +#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */ +#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */ +#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */ + +#define SDIO_CCCR_IOEx 0x02 +#define SDIO_CCCR_IORx 0x03 + +#define SDIO_CCCR_IENx 0x04 /* Function/Master Interrupt Enable */ +#define SDIO_CCCR_INTx 0x05 /* Function Interrupt Pending */ + +#define SDIO_CCCR_ABORT 0x06 /* function abort/card reset */ + +#define SDIO_CCCR_IF 0x07 /* bus interface controls */ + +#define SDIO_BUS_WIDTH_1BIT 0x00 +#define SDIO_BUS_WIDTH_4BIT 0x02 + +#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */ + +#define SDIO_CCCR_CAPS 0x08 + +#define SDIO_CCCR_CAP_SDC 0x01 /* can do CMD52 while data transfer */ +#define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */ +#define SDIO_CCCR_CAP_SRW 0x04 /* supports read-wait protocol */ +#define SDIO_CCCR_CAP_SBS 0x08 /* supports suspend/resume */ +#define SDIO_CCCR_CAP_S4MI 0x10 /* interrupt during 4-bit CMD53 */ +#define SDIO_CCCR_CAP_E4MI 0x20 /* enable ints during 4-bit CMD53 */ +#define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */ +#define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */ + +#define SDIO_CCCR_CIS 0x09 /* common CIS pointer (3 bytes) */ + +/* Following 4 regs are valid only if SBS is set */ +#define SDIO_CCCR_SUSPEND 0x0c +#define SDIO_CCCR_SELx 0x0d +#define SDIO_CCCR_EXECx 0x0e +#define SDIO_CCCR_READYx 0x0f + +#define SDIO_CCCR_BLKSIZE 0x10 + +#define SDIO_CCCR_POWER 0x12 + +#define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */ +#define SDIO_POWER_EMPC 0x02 /* Enable Master Power Control */ + +#define SDIO_CCCR_SPEED 0x13 + +#define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */ +#define SDIO_SPEED_EHS 0x02 /* Enable High-Speed mode */ + +/* + * Function Basic Registers (FBR) + */ + +#define SDIO_FBR_STD_IF 0x00 + +#define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */ +#define SDIO_FBR_ENABLE_CSA 0x80 /* enable Code Storage Area */ + +#define SDIO_FBR_STD_IF_EXT 0x01 + +#define SDIO_FBR_POWER 0x02 + +#define SDIO_FBR_POWER_SPS 0x01 /* Supports Power Selection */ +#define SDIO_FBR_POWER_EPS 0x02 /* Enable (low) Power Selection */ + +#define SDIO_FBR_CIS 0x09 /* CIS pointer (3 bytes) */ + + +#define SDIO_FBR_CSA 0x0C /* CSA pointer (3 bytes) */ + +#define SDIO_FBR_CSA_DATA 0x0F + +#define SDIO_FBR_BLKSIZE 0x10 /* block size (2 bytes) */ + #endif diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 5c56df196287..3365fef5f713 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -55,6 +55,9 @@ extern void sdio_unregister_driver(struct sdio_driver *); extern void sdio_claim_host(struct sdio_func *func); extern void sdio_release_host(struct sdio_func *func); +extern int sdio_enable_func(struct sdio_func *func); +extern int sdio_disable_func(struct sdio_func *func); + extern unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret); From 35c66c19088bddb11110c124bad8abd4441a8421 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Jun 2007 20:25:43 +0200 Subject: [PATCH 0299/2804] sdio: read and decode interesting parts of the CCCR Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 63 ++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/card.h | 11 +++++++ 2 files changed, 74 insertions(+) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 444328581cec..7ce3e3104d21 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -13,6 +13,7 @@ #include #include +#include #include #include "core.h" @@ -39,6 +40,61 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) return 0; } +static int sdio_read_cccr(struct mmc_card *card) +{ + int ret; + int cccr_vsn; + unsigned char data; + + memset(&card->cccr, 0, sizeof(struct sdio_cccr)); + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); + if (ret) + goto out; + + cccr_vsn = data & 0x0f; + + if (cccr_vsn > SDIO_CCCR_REV_1_20) { + printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", + mmc_hostname(card->host), cccr_vsn); + return -EINVAL; + } + + card->cccr.sdio_vsn = (data & 0xf0) >> 4; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); + if (ret) + goto out; + + if (data & SDIO_CCCR_CAP_SMB) + card->cccr.multi_block = 1; + if (data & SDIO_CCCR_CAP_LSC) + card->cccr.low_speed = 1; + if (data & SDIO_CCCR_CAP_4BLS) + card->cccr.wide_bus = 1; + + if (cccr_vsn >= SDIO_CCCR_REV_1_10) { + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data); + if (ret) + goto out; + + if (data & SDIO_POWER_SMPC) + card->cccr.high_power = 1; + } + + if (cccr_vsn >= SDIO_CCCR_REV_1_20) { + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); + if (ret) + goto out; + + if (data & SDIO_SPEED_SHS) + card->cccr.high_speed = 1; + } + +out: + return ret; +} + /* * Host is being removed. Free up the current card. */ @@ -180,6 +236,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto remove; + /* + * Read the common registers. + */ + err = sdio_read_cccr(card); + if (err) + goto remove; + /* * Initialize (but don't add) all present functions. */ diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 9f5f74482d98..520d9d29b3b2 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -55,6 +55,16 @@ struct sd_switch_caps { unsigned int hs_max_dtr; }; +struct sdio_cccr { + unsigned int sdio_vsn; + unsigned int sd_vsn; + unsigned int multi_block:1, + low_speed:1, + wide_bus:1, + high_power:1, + high_speed:1; +}; + struct mmc_host; struct sdio_func; @@ -87,6 +97,7 @@ struct mmc_card { struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ unsigned int sdio_funcs; /* number of SDIO functions */ + struct sdio_cccr cccr; /* common card info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ }; From 0597007f1b22bbb5d4234ca09c045f9bb2711270 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Jun 2007 21:01:00 +0200 Subject: [PATCH 0300/2804] sdio: basic parsing of FBR Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 38 +++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 5 +++++ 2 files changed, 43 insertions(+) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 7ce3e3104d21..be623856f288 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -23,8 +23,34 @@ #include "sd_ops.h" #include "sdio_ops.h" +static int sdio_read_fbr(struct sdio_func *func) +{ + int ret; + unsigned char data; + + ret = mmc_io_rw_direct(func->card, 0, 0, + func->num * 0x100 + SDIO_FBR_STD_IF, 0, &data); + if (ret) + goto out; + + data &= 0x0f; + + if (data == 0x0f) { + ret = mmc_io_rw_direct(func->card, 0, 0, + func->num * 0x100 + SDIO_FBR_STD_IF_EXT, 0, &data); + if (ret) + goto out; + } + + func->class = data; + +out: + return ret; +} + static int sdio_init_func(struct mmc_card *card, unsigned int fn) { + int ret; struct sdio_func *func; BUG_ON(fn > SDIO_MAX_FUNCS); @@ -35,9 +61,21 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) func->num = fn; + ret = sdio_read_fbr(func); + if (ret) + goto fail; + card->sdio_func[fn - 1] = func; return 0; + +fail: + /* + * It is okay to remove the function here even though we hold + * the host lock as we haven't registered the device yet. + */ + sdio_remove_func(func); + return ret; } static int sdio_read_cccr(struct mmc_card *card) diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 3365fef5f713..4164809a8e63 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -21,6 +21,11 @@ struct sdio_func { struct mmc_card *card; /* the card this device belongs to */ struct device dev; /* the device */ unsigned int num; /* function number */ + + unsigned char class; /* standard interface class */ + unsigned short vendor; /* vendor id */ + unsigned short device; /* device id */ + unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ }; From b726126196d54cbbba0924191e5c4dd5ba747fa2 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 16 Jun 2007 02:04:16 -0400 Subject: [PATCH 0301/2804] sdio: initial CIS parsing code Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/sdio.c | 5 ++ drivers/mmc/core/sdio_cis.c | 119 ++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_cis.h | 19 ++++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 drivers/mmc/core/sdio_cis.c create mode 100644 drivers/mmc/core/sdio_cis.h diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index bf7a00248039..05d69fc72c18 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,5 +10,5 @@ obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ - sdio_io.o + sdio_cis.o sdio_io.o diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index be623856f288..c5baf76146b2 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -22,6 +22,7 @@ #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" +#include "sdio_cis.h" static int sdio_read_fbr(struct sdio_func *func) { @@ -65,6 +66,10 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) if (ret) goto fail; + ret = sdio_read_cis(func); + if (ret) + goto fail; + card->sdio_func[fn - 1] = func; return 0; diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c new file mode 100644 index 000000000000..114b600cd788 --- /dev/null +++ b/drivers/mmc/core/sdio_cis.c @@ -0,0 +1,119 @@ +/* + * linux/drivers/mmc/core/sdio_cis.c + * + * Author: Nicolas Pitre + * Created: June 11, 2007 + * Copyright: MontaVista Software 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 "sdio_cis.h" +#include "sdio_ops.h" + +static int cistpl_manfid(struct sdio_func *func, + const unsigned char *buf, + unsigned size) +{ + /* TPLMID_MANF */ + func->vendor = buf[0] | (buf[1] << 8); + + /* TPLMID_CARD */ + func->device = buf[2] | (buf[3] << 8); + + return 0; +} + +struct cis_tpl { + unsigned char code; + unsigned char min_size; + int (*parse)(struct sdio_func *, const unsigned char *buf, unsigned size); +}; + +static const struct cis_tpl cis_tpl_list[] = { + { 0x15, 3, /* cistpl_vers_1 */ }, + { 0x20, 4, cistpl_manfid }, + { 0x21, 2, /* cistpl_funcid */ }, + { 0x22, 0, /* cistpl_funce */ }, +}; + +int sdio_read_cis(struct sdio_func *func) +{ + int ret; + unsigned char *buf; + unsigned i, ptr = 0; + + for (i = 0; i < 3; i++) { + unsigned char x; + ret = mmc_io_rw_direct(func->card, 0, 0, + func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); + if (ret) + return ret; + ptr |= x << (i * 8); + } + + buf = kmalloc(256, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + do { + unsigned char tpl_code, tpl_link; + const struct cis_tpl *tpl; + + ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); + if (ret) + break; + + /* 0xff means we're done */ + if (tpl_code == 0xff) + break; + + ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); + if (ret) + break; + + for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) + if (cis_tpl_list[i].code == tpl_code) + break; + if (i >= ARRAY_SIZE(cis_tpl_list)) { + printk(KERN_WARNING + "%s: unknown CIS tuple 0x%02x of length %u\n", + sdio_func_id(func), tpl_code, tpl_link); + ptr += tpl_link; + continue; + } + tpl = cis_tpl_list + i; + + if (tpl_link < tpl->min_size) { + printk(KERN_ERR + "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u\n", + sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); + ret = -EINVAL; + break; + } + + for (i = 0; i < tpl_link; i++) { + ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]); + if (ret) + break; + } + if (ret) + break; + ptr += tpl_link; + + if (tpl->parse) + ret = tpl->parse(func, buf, tpl_link); + } while (!ret); + + kfree(buf); + return ret; +} diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h new file mode 100644 index 000000000000..df21c495d133 --- /dev/null +++ b/drivers/mmc/core/sdio_cis.h @@ -0,0 +1,19 @@ +/* + * linux/drivers/mmc/core/sdio_cis.h + * + * Author: Nicolas Pitre + * Created: June 11, 2007 + * Copyright: MontaVista Software 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. + */ + +#ifndef _MMC_SDIO_CIS_H +#define _MMC_SDIO_CIS_H + +int sdio_read_cis(struct sdio_func *func); + +#endif From b1538bcf75e2e11459947ec4d4329ed04fbe2b2c Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 16 Jun 2007 02:06:47 -0400 Subject: [PATCH 0302/2804] sdio: link unknown CIS tuples to the sdio_func structure This way those tuples that the core cares about are consumed by the core code, and tuples that only function drivers might make sense of are available to drivers. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 3 ++ drivers/mmc/core/sdio_cis.c | 83 +++++++++++++++++++++++------------ drivers/mmc/core/sdio_cis.h | 1 + include/linux/mmc/sdio_func.h | 12 +++++ 4 files changed, 70 insertions(+), 29 deletions(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index fa488cea8594..78e0381f55ac 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -17,6 +17,7 @@ #include #include +#include "sdio_cis.h" #include "sdio_bus.h" #define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) @@ -94,6 +95,8 @@ static void sdio_release_func(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); + sdio_free_cis(func); + kfree(func); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 114b600cd788..b6c7342572c1 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -5,6 +5,8 @@ * Created: June 11, 2007 * Copyright: MontaVista Software Inc. * + * Copyright 2007 Pierre Ossman + * * 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 @@ -49,7 +51,7 @@ static const struct cis_tpl cis_tpl_list[] = { int sdio_read_cis(struct sdio_func *func) { int ret; - unsigned char *buf; + struct sdio_func_tuple *this, **prev; unsigned i, ptr = 0; for (i = 0; i < 3; i++) { @@ -61,13 +63,11 @@ int sdio_read_cis(struct sdio_func *func) ptr |= x << (i * 8); } - buf = kmalloc(256, GFP_KERNEL); - if (!buf) - return -ENOMEM; + /* find the list tail */ + for (prev = &func->tuples; *prev; prev = &(*prev)->next); do { unsigned char tpl_code, tpl_link; - const struct cis_tpl *tpl; ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); if (ret) @@ -81,39 +81,64 @@ int sdio_read_cis(struct sdio_func *func) if (ret) break; + this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL); + if (!this) + return -ENOMEM; + + for (i = 0; i < tpl_link; i++) { + ret = mmc_io_rw_direct(func->card, 0, 0, + ptr + i, 0, &this->data[i]); + if (ret) + break; + } + if (ret) { + kfree(this); + break; + } + for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) if (cis_tpl_list[i].code == tpl_code) break; if (i >= ARRAY_SIZE(cis_tpl_list)) { - printk(KERN_WARNING - "%s: unknown CIS tuple 0x%02x of length %u\n", + /* this tuple is unknown to the core */ + this->next = NULL; + this->code = tpl_code; + this->size = tpl_link; + *prev = this; + prev = &this->next; + printk(KERN_DEBUG + "%s: queuing CIS tuple 0x%02x length %u\n", sdio_func_id(func), tpl_code, tpl_link); - ptr += tpl_link; - continue; - } - tpl = cis_tpl_list + i; - - if (tpl_link < tpl->min_size) { - printk(KERN_ERR - "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u\n", - sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); - ret = -EINVAL; - break; + } else { + const struct cis_tpl *tpl = cis_tpl_list + i; + if (tpl_link < tpl->min_size) { + printk(KERN_ERR + "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", + sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); + ret = -EINVAL; + } else if (tpl->parse) + ret = tpl->parse(func, this->data, tpl_link); + kfree(this); } - for (i = 0; i < tpl_link; i++) { - ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]); - if (ret) - break; - } - if (ret) - break; ptr += tpl_link; - - if (tpl->parse) - ret = tpl->parse(func, buf, tpl_link); } while (!ret); - kfree(buf); return ret; } + +void sdio_free_cis(struct sdio_func *func) +{ + struct sdio_func_tuple *tuple, *victim; + + tuple = func->tuples; + + while (tuple) { + victim = tuple; + tuple = tuple->next; + kfree(victim); + } + + func->tuples = NULL; +} + diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h index df21c495d133..863d3d516371 100644 --- a/drivers/mmc/core/sdio_cis.h +++ b/drivers/mmc/core/sdio_cis.h @@ -15,5 +15,6 @@ #define _MMC_SDIO_CIS_H int sdio_read_cis(struct sdio_func *func); +void sdio_free_cis(struct sdio_func *func); #endif diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 4164809a8e63..269067663c8d 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -14,6 +14,16 @@ struct mmc_card; +/* + * SDIO function CIS tuple (unknown to the core) + */ +struct sdio_func_tuple { + struct sdio_func_tuple *next; + unsigned char code; + unsigned char size; + unsigned char data[0]; +}; + /* * SDIO function devices */ @@ -28,6 +38,8 @@ struct sdio_func { unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ + + struct sdio_func_tuple *tuples; }; #define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT) From 1a632f8cdc33e7f8edca352164f0c96a75d08f08 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jul 2007 15:15:30 +0200 Subject: [PATCH 0303/2804] sdio: split up common and function CIS parsing Add a more clean separation between global, common CIS information and the function specific one as we need the common information in places where no specific function is specified. Signed-off-by: Pierre Ossman --- drivers/mmc/core/bus.c | 3 + drivers/mmc/core/sdio.c | 9 +- drivers/mmc/core/sdio_bus.c | 2 +- drivers/mmc/core/sdio_cis.c | 200 ++++++++++++++++++++++++++++++---- drivers/mmc/core/sdio_cis.h | 7 +- include/linux/mmc/card.h | 10 ++ include/linux/mmc/sdio_func.h | 2 + 7 files changed, 206 insertions(+), 27 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 87a6070522f8..9be11ec05d86 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -19,6 +19,7 @@ #include "sysfs.h" #include "core.h" +#include "sdio_cis.h" #include "bus.h" #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) @@ -181,6 +182,8 @@ static void mmc_release_card(struct device *dev) { struct mmc_card *card = dev_to_mmc_card(dev); + sdio_free_common_cis(card); + kfree(card); } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c5baf76146b2..1fb36a340468 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -66,7 +66,7 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) if (ret) goto fail; - ret = sdio_read_cis(func); + ret = sdio_read_func_cis(func); if (ret) goto fail; @@ -286,6 +286,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto remove; + /* + * Read the common CIS tuples. + */ + err = sdio_read_common_cis(card); + if (err) + goto remove; + /* * Initialize (but don't add) all present functions. */ diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 78e0381f55ac..461fe4837a9f 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -95,7 +95,7 @@ static void sdio_release_func(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); - sdio_free_cis(func); + sdio_free_func_cis(func); kfree(func); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index b6c7342572c1..ec806a1229b6 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -16,60 +16,152 @@ #include #include +#include #include #include #include "sdio_cis.h" #include "sdio_ops.h" -static int cistpl_manfid(struct sdio_func *func, - const unsigned char *buf, - unsigned size) +static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func, + const unsigned char *buf, unsigned size) { + unsigned int vendor, device; + /* TPLMID_MANF */ - func->vendor = buf[0] | (buf[1] << 8); + vendor = buf[0] | (buf[1] << 8); /* TPLMID_CARD */ - func->device = buf[2] | (buf[3] << 8); + device = buf[2] | (buf[3] << 8); + + if (func) { + func->vendor = vendor; + func->device = device; + } else { + card->cis.vendor = vendor; + card->cis.device = device; + } return 0; } +static const unsigned char speed_val[16] = + { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; +static const unsigned int speed_unit[8] = + { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; + +static int cistpl_funce_common(struct mmc_card *card, + const unsigned char *buf, unsigned size) +{ + if (size < 0x04 || buf[0] != 0) + return -EINVAL; + + /* TPLFE_FN0_BLK_SIZE */ + card->cis.blksize = buf[1] | (buf[2] << 8); + + /* TPLFE_MAX_TRAN_SPEED */ + card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] * + speed_unit[buf[3] & 7]; + + return 0; +} + +static int cistpl_funce_func(struct sdio_func *func, + const unsigned char *buf, unsigned size) +{ + unsigned vsn; + unsigned min_size; + + vsn = func->card->cccr.sdio_vsn; + min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; + + if (size < min_size || buf[0] != 1) + return -EINVAL; + + /* TPLFE_MAX_BLK_SIZE */ + func->blksize = buf[12] | (buf[13] << 8); + + return 0; +} + +static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, + const unsigned char *buf, unsigned size) +{ + int ret; + + /* + * There should be two versions of the CISTPL_FUNCE tuple, + * one for the common CIS (function 0) and a version used by + * the individual function's CIS (1-7). Yet, the later has a + * different length depending on the SDIO spec version. + */ + if (func) + ret = cistpl_funce_func(func, buf, size); + else + ret = cistpl_funce_common(card, buf, size); + + if (ret) { + printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " + "type %u\n", mmc_hostname(card->host), size, buf[0]); + return ret; + } + + return 0; +} + +typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *, + const unsigned char *, unsigned); + struct cis_tpl { unsigned char code; unsigned char min_size; - int (*parse)(struct sdio_func *, const unsigned char *buf, unsigned size); + tpl_parse_t *parse; }; static const struct cis_tpl cis_tpl_list[] = { { 0x15, 3, /* cistpl_vers_1 */ }, { 0x20, 4, cistpl_manfid }, { 0x21, 2, /* cistpl_funcid */ }, - { 0x22, 0, /* cistpl_funce */ }, + { 0x22, 0, cistpl_funce }, }; -int sdio_read_cis(struct sdio_func *func) +static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) { int ret; struct sdio_func_tuple *this, **prev; unsigned i, ptr = 0; + /* + * Note that this works for the common CIS (function number 0) as + * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS + * have the same offset. + */ for (i = 0; i < 3; i++) { - unsigned char x; - ret = mmc_io_rw_direct(func->card, 0, 0, - func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); + unsigned char x, fn; + + if (func) + fn = func->num; + else + fn = 0; + + ret = mmc_io_rw_direct(card, 0, 0, + fn * 0x100 + SDIO_FBR_CIS + i, 0, &x); if (ret) return ret; ptr |= x << (i * 8); } - /* find the list tail */ - for (prev = &func->tuples; *prev; prev = &(*prev)->next); + if (func) + prev = &func->tuples; + else + prev = &card->tuples; + + BUG_ON(*prev); do { unsigned char tpl_code, tpl_link; - ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); + ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code); if (ret) break; @@ -77,7 +169,7 @@ int sdio_read_cis(struct sdio_func *func) if (tpl_code == 0xff) break; - ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); + ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); if (ret) break; @@ -86,7 +178,7 @@ int sdio_read_cis(struct sdio_func *func) return -ENOMEM; for (i = 0; i < tpl_link; i++) { - ret = mmc_io_rw_direct(func->card, 0, 0, + ret = mmc_io_rw_direct(card, 0, 0, ptr + i, 0, &this->data[i]); if (ret) break; @@ -108,30 +200,45 @@ int sdio_read_cis(struct sdio_func *func) prev = &this->next; printk(KERN_DEBUG "%s: queuing CIS tuple 0x%02x length %u\n", - sdio_func_id(func), tpl_code, tpl_link); + mmc_hostname(card->host), tpl_code, tpl_link); } else { const struct cis_tpl *tpl = cis_tpl_list + i; if (tpl_link < tpl->min_size) { printk(KERN_ERR "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", - sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); + mmc_hostname(card->host), + tpl_code, tpl_link, tpl->min_size); ret = -EINVAL; - } else if (tpl->parse) - ret = tpl->parse(func, this->data, tpl_link); + } else if (tpl->parse) { + ret = tpl->parse(card, func, + this->data, tpl_link); + } kfree(this); } ptr += tpl_link; } while (!ret); + /* + * Link in all unknown tuples found in the common CIS so that + * drivers don't have to go digging in two places. + */ + if (func) + *prev = card->tuples; + return ret; } -void sdio_free_cis(struct sdio_func *func) +int sdio_read_common_cis(struct mmc_card *card) +{ + return sdio_read_cis(card, NULL); +} + +void sdio_free_common_cis(struct mmc_card *card) { struct sdio_func_tuple *tuple, *victim; - tuple = func->tuples; + tuple = card->tuples; while (tuple) { victim = tuple; @@ -139,6 +246,53 @@ void sdio_free_cis(struct sdio_func *func) kfree(victim); } - func->tuples = NULL; + card->tuples = NULL; +} + +int sdio_read_func_cis(struct sdio_func *func) +{ + int ret; + + ret = sdio_read_cis(func->card, func); + if (ret) + return ret; + + /* + * Since we've linked to tuples in the card structure, + * we must make sure we have a reference to it. + */ + get_device(&func->card->dev); + + /* + * Vendor/device id is optional for function CIS, so + * copy it from the card structure as needed. + */ + if (func->vendor == 0) { + func->vendor = func->card->cis.vendor; + func->device = func->card->cis.device; + } + + return 0; +} + +void sdio_free_func_cis(struct sdio_func *func) +{ + struct sdio_func_tuple *tuple, *victim; + + tuple = func->tuples; + + while (tuple && tuple != func->card->tuples) { + victim = tuple; + tuple = tuple->next; + kfree(victim); + } + + func->tuples = NULL; + + /* + * We have now removed the link to the tuples in the + * card structure, so remove the reference. + */ + put_device(&func->card->dev); } diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h index 863d3d516371..4d903c2e425e 100644 --- a/drivers/mmc/core/sdio_cis.h +++ b/drivers/mmc/core/sdio_cis.h @@ -14,7 +14,10 @@ #ifndef _MMC_SDIO_CIS_H #define _MMC_SDIO_CIS_H -int sdio_read_cis(struct sdio_func *func); -void sdio_free_cis(struct sdio_func *func); +int sdio_read_common_cis(struct mmc_card *card); +void sdio_free_common_cis(struct mmc_card *card); + +int sdio_read_func_cis(struct sdio_func *func); +void sdio_free_func_cis(struct sdio_func *func); #endif diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 520d9d29b3b2..a444431e28bd 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -65,8 +65,16 @@ struct sdio_cccr { high_speed:1; }; +struct sdio_cis { + unsigned short vendor; + unsigned short device; + unsigned short blksize; + unsigned int max_dtr; +}; + struct mmc_host; struct sdio_func; +struct sdio_func_tuple; #define SDIO_MAX_FUNCS 7 @@ -98,7 +106,9 @@ struct mmc_card { unsigned int sdio_funcs; /* number of SDIO functions */ struct sdio_cccr cccr; /* common card info */ + struct sdio_cis cis; /* common tuple info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ + struct sdio_func_tuple *tuples; /* unknown common tuples */ }; #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 269067663c8d..2f2b3c854415 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -36,6 +36,8 @@ struct sdio_func { unsigned short vendor; /* vendor id */ unsigned short device; /* device id */ + unsigned short blksize; /* maximum block size */ + unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ From 26074962e8f547b96614dbe248748ba2a1996ca3 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 16 Jun 2007 02:07:53 -0400 Subject: [PATCH 0304/2804] mmc: initialize mmc subsystem with subsys_initcall() The problem is that the sdio_bus must be registered before any SDIO drivers are registered against it otherwise the kernel sulks. Because the sdio_bus registration happens through module_init (equivalent to device_initcall), then any SDIO drivers linked before the SDIO core code in the kernel will be initialized first. Upcoming SDIO function drivers are likely to be located outside the drivers/mmc directory as it is common practice to group drivers according to their function rather than the bus they use. SDIO drivers are therefore likely to appear at random location in the kernel link. To make sure the sdio_bus is always initialized before any SDIO drivers, let's move the MMC init to the subsys_initcall level. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9747455928da..b8f27e5ade97 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -771,7 +771,7 @@ static void __exit mmc_exit(void) destroy_workqueue(workqueue); } -module_init(mmc_init); +subsys_initcall(mmc_init); module_exit(mmc_exit); MODULE_LICENSE("GPL"); From 3b38bea0d976513970f947806b08b9faca418e7a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 16 Jun 2007 15:54:55 +0200 Subject: [PATCH 0305/2804] sdio: add device id table and matching Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 58 +++++++++++++++++++++++++++++---- include/linux/mmc/sdio_func.h | 30 ++++++++++++++++- include/linux/mod_devicetable.h | 11 +++++++ 3 files changed, 92 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 461fe4837a9f..a3a89e973d94 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -21,14 +21,47 @@ #include "sdio_bus.h" #define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) +#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) + +static const struct sdio_device_id *sdio_match_one(struct sdio_func *func, + const struct sdio_device_id *id) +{ + if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class) + return NULL; + if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor) + return NULL; + if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device) + return NULL; + return id; +} + +static const struct sdio_device_id *sdio_match_device(struct sdio_func *func, + struct sdio_driver *sdrv) +{ + const struct sdio_device_id *ids; + + ids = sdrv->id_table; + + if (ids) { + while (ids->class || ids->vendor || ids->device) { + if (sdio_match_one(func, ids)) + return ids; + ids++; + } + } + + return NULL; +} -/* - * This currently matches any SDIO function to any driver in order - * to help initial development and testing. - */ static int sdio_bus_match(struct device *dev, struct device_driver *drv) { - return 1; + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_driver *sdrv = to_sdio_driver(drv); + + if (sdio_match_device(func, sdrv)) + return 1; + + return 0; } static int @@ -42,11 +75,24 @@ sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, static int sdio_bus_probe(struct device *dev) { - return -ENODEV; + struct sdio_driver *drv = to_sdio_driver(dev->driver); + struct sdio_func *func = dev_to_sdio_func(dev); + const struct sdio_device_id *id; + + id = sdio_match_device(func, drv); + if (!id) + return -ENODEV; + + return drv->probe(func, id); } static int sdio_bus_remove(struct device *dev) { + struct sdio_driver *drv = to_sdio_driver(dev->driver); + struct sdio_func *func = dev_to_sdio_func(dev); + + drv->remove(func); + return 0; } diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 2f2b3c854415..8106d399c414 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -12,6 +12,9 @@ #ifndef MMC_SDIO_FUNC_H #define MMC_SDIO_FUNC_H +#include +#include + struct mmc_card; /* @@ -58,13 +61,38 @@ struct sdio_func { */ struct sdio_driver { char *name; + const struct sdio_device_id *id_table; - int (*probe)(struct sdio_func *); + int (*probe)(struct sdio_func *, const struct sdio_device_id *); void (*remove)(struct sdio_func *); struct device_driver drv; }; +/** + * SDIO_DEVICE - macro used to describe a specific SDIO device + * @vend: the 16 bit manufacturer code + * @dev: the 16 bit function id + * + * This macro is used to create a struct sdio_device_id that matches a + * specific device. The class field will be set to SDIO_ANY_ID. + */ +#define SDIO_DEVICE(vend,dev) \ + .class = SDIO_ANY_ID, \ + .vendor = (vend), .device = (dev) + +/** + * SDIO_DEVICE_CLASS - macro used to describe a specific SDIO device class + * @dev_class: the 8 bit standard interface code + * + * This macro is used to create a struct sdio_device_id that matches a + * specific standard SDIO function type. The vendor and device fields will + * be set to SDIO_ANY_ID. + */ +#define SDIO_DEVICE_CLASS(dev_class) \ + .class = (dev_class), \ + .vendor = SDIO_ANY_ID, .device = SDIO_ANY_ID + extern int sdio_register_driver(struct sdio_driver *); extern void sdio_unregister_driver(struct sdio_driver *); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 4dc5fa8be781..e47e5951058b 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -340,4 +340,15 @@ struct parisc_device_id { #define PA_HVERSION_ANY_ID 0xffff #define PA_SVERSION_ANY_ID 0xffffffff +/* SDIO */ + +#define SDIO_ANY_ID (~0) + +struct sdio_device_id { + __u8 class; /* Standard interface or SDIO_ANY_ID */ + __u16 vendor; /* Vendor or SDIO_ANY_ID */ + __u16 device; /* Device ID or SDIO_ANY_ID */ + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ From 9eb3a94d022e6c233c0b22ec54516d35d2e87eb9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 17 Jun 2007 11:18:46 +0200 Subject: [PATCH 0306/2804] mmc: whip bus uevent handler into shape Make the mmc bus uevent callback look like all other subsystems. Signed-off-by: Pierre Ossman --- drivers/mmc/core/bus.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 9be11ec05d86..1cc11714916f 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -62,31 +62,34 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, int buf_size) { struct mmc_card *card = dev_to_mmc_card(dev); - int retval = 0, i = 0, length = 0; - -#define add_env(fmt,val) do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buf, buf_size, &length, \ - fmt, val); \ - if (retval) \ - return retval; \ -} while (0); + const char *type; + int i = 0, length = 0; switch (card->type) { case MMC_TYPE_MMC: - add_env("MMC_TYPE=%s", "MMC"); + type = "MMC"; break; case MMC_TYPE_SD: - add_env("MMC_TYPE=%s", "SD"); + type = "SD"; break; case MMC_TYPE_SDIO: - add_env("MMC_TYPE=%s", "SDIO"); + type = "SDIO"; break; + default: + type = NULL; } - add_env("MMC_NAME=%s", mmc_card_name(card)); + if (type) { + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "MMC_TYPE=%s", type)) + return -ENOMEM; + } -#undef add_env + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "MMC_NAME=%s", mmc_card_name(card))) + return -ENOMEM; envp[i] = NULL; From d59b66c7a575cfa8e01f483875d131e42b539bbc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 17 Jun 2007 11:34:23 +0200 Subject: [PATCH 0307/2804] sdio: add modalias support Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 21 ++++++++++++++++++++- scripts/mod/file2alias.c | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index a3a89e973d94..c834f5150888 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -68,7 +68,26 @@ static int sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, int buf_size) { - envp[0] = NULL; + struct sdio_func *func = dev_to_sdio_func(dev); + int i = 0, length = 0; + + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "SDIO_CLASS=%02X", func->class)) + return -ENOMEM; + + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "SDIO_ID=%04X:%04X", func->vendor, func->device)) + return -ENOMEM; + + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "MODALIAS=sdio:c%02Xv%04Xd%04X", + func->class, func->vendor, func->device)) + return -ENOMEM; + + envp[i] = NULL; return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 8a09021d8c59..1e5d4d693195 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -484,6 +484,22 @@ static int do_parisc_entry(const char *filename, struct parisc_device_id *id, return 1; } +/* Looks like: sdio:cNvNdN. */ +static int do_sdio_entry(const char *filename, + struct sdio_device_id *id, char *alias) +{ + id->class = TO_NATIVE(id->class); + id->vendor = TO_NATIVE(id->vendor); + id->device = TO_NATIVE(id->device); + + strcpy(alias, "sdio:"); + ADD(alias, "c", id->class != (__u8)SDIO_ANY_ID, id->class); + ADD(alias, "v", id->vendor != (__u16)SDIO_ANY_ID, id->vendor); + ADD(alias, "d", id->device != (__u16)SDIO_ANY_ID, id->device); + + return 1; +} + /* Ignore any prefix, eg. v850 prepends _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -599,6 +615,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct parisc_device_id), "parisc", do_parisc_entry, mod); + else if (sym_is(symname, "__mod_sdio_device_table")) + do_table(symval, sym->st_size, + sizeof(struct sdio_device_id), "sdio", + do_sdio_entry, mod); } /* Now add out buffered information to the generated C source */ From bcfe66e21ef78a078bb0de0bab532701996695d3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 17 Jun 2007 11:42:21 +0200 Subject: [PATCH 0308/2804] sdio: add basic sysfs attributes Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index c834f5150888..129f0719c391 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -23,6 +23,37 @@ #define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) #define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) +/* show configuration fields */ +#define sdio_config_attr(field, format_string) \ +static ssize_t \ +field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct sdio_func *func; \ + \ + func = dev_to_sdio_func (dev); \ + return sprintf (buf, format_string, func->field); \ +} + +sdio_config_attr(class, "0x%02x\n"); +sdio_config_attr(vendor, "0x%04x\n"); +sdio_config_attr(device, "0x%04x\n"); + +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sdio_func *func = dev_to_sdio_func (dev); + + return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n", + func->class, func->vendor, func->device); +} + +struct device_attribute sdio_dev_attrs[] = { + __ATTR_RO(class), + __ATTR_RO(vendor), + __ATTR_RO(device), + __ATTR_RO(modalias), + __ATTR_NULL, +}; + static const struct sdio_device_id *sdio_match_one(struct sdio_func *func, const struct sdio_device_id *id) { @@ -117,6 +148,7 @@ static int sdio_bus_remove(struct device *dev) static struct bus_type sdio_bus_type = { .name = "sdio", + .dev_attrs = sdio_dev_attrs, .match = sdio_bus_match, .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, From 55fe77a0a24e05c9aaf1a13550dde5efad8b49f2 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 16 Jun 2007 21:40:07 -0400 Subject: [PATCH 0309/2804] sdio: defines for some standard interface types Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- include/linux/mmc/sdio_ids.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 include/linux/mmc/sdio_ids.h diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h new file mode 100644 index 000000000000..09306d47ff5e --- /dev/null +++ b/include/linux/mmc/sdio_ids.h @@ -0,0 +1,23 @@ +/* + * SDIO Classes, Interface Types, Manufacturer IDs, etc. + */ + +#ifndef MMC_SDIO_IDS_H +#define MMC_SDIO_IDS_H + +/* + * Standard SDIO Function Interfaces + */ + +#define SDIO_CLASS_NONE 0x00 /* Not a SDIO standard interface */ +#define SDIO_CLASS_UART 0x01 /* standard UART interface */ +#define SDIO_CLASS_BT_A 0x02 /* Type-A BlueTooth std interface */ +#define SDIO_CLASS_BT_B 0x03 /* Type-B BlueTooth std interface */ +#define SDIO_CLASS_GPS 0x04 /* GPS standard interface */ +#define SDIO_CLASS_CAMERA 0x05 /* Camera standard interface */ +#define SDIO_CLASS_PHS 0x06 /* PHS standard interface */ +#define SDIO_CLASS_WLAN 0x07 /* WLAN interface */ +#define SDIO_CLASS_ATA 0x08 /* Embedded SDIO-ATA std interface */ + + +#endif From 2342f3323c9a76367a1d7f9a35525ee3cb3911df Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 30 Jun 2007 16:21:52 +0200 Subject: [PATCH 0310/2804] sdio: allow for mmc_claim_host to be aborted It is sometimes necessary to give up on trying to claim the host lock, especially if that happens in a thread that has to be stopped. While at it, fix the description for mmc_claim_host() which was wrong. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 22 ++++++++++++++++------ include/linux/mmc/core.h | 13 ++++++++++++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index b8f27e5ade97..d1e4b0849e39 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -273,15 +273,20 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) EXPORT_SYMBOL(mmc_set_data_timeout); /** - * mmc_claim_host - exclusively claim a host + * __mmc_claim_host - exclusively claim a host * @host: mmc host to claim + * @abort: whether or not the operation should be aborted * - * Claim a host for a set of operations. + * Claim a host for a set of operations. If @abort is non null and + * dereference a non-zero value then this will return prematurely with + * that non-zero value without acquiring the lock. Returns zero + * with the lock held otherwise. */ -void mmc_claim_host(struct mmc_host *host) +int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) { DECLARE_WAITQUEUE(wait, current); unsigned long flags; + int stop; might_sleep(); @@ -289,19 +294,24 @@ void mmc_claim_host(struct mmc_host *host) spin_lock_irqsave(&host->lock, flags); while (1) { set_current_state(TASK_UNINTERRUPTIBLE); - if (!host->claimed) + stop = abort ? atomic_read(abort) : 0; + if (stop || !host->claimed) break; spin_unlock_irqrestore(&host->lock, flags); schedule(); spin_lock_irqsave(&host->lock, flags); } set_current_state(TASK_RUNNING); - host->claimed = 1; + if (!stop) + host->claimed = 1; + else + wake_up(&host->wq); spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); + return stop; } -EXPORT_SYMBOL(mmc_claim_host); +EXPORT_SYMBOL(__mmc_claim_host); /** * mmc_release_host - release a host diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 43a92736be63..8945da9b54fa 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -114,7 +114,18 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); -extern void mmc_claim_host(struct mmc_host *host); +extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); extern void mmc_release_host(struct mmc_host *host); +/** + * mmc_claim_host - exclusively claim a host + * @host: mmc host to claim + * + * Claim a host for a set of operations. + */ +static inline void mmc_claim_host(struct mmc_host *host) +{ + __mmc_claim_host(host, NULL); +} + #endif From d1496c39e500857b8949cdb91af24e0eb8aae4d0 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 30 Jun 2007 16:29:41 +0200 Subject: [PATCH 0311/2804] sdio: core support for SDIO function interrupt Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/sdio_bus.c | 8 ++ drivers/mmc/core/sdio_irq.c | 237 ++++++++++++++++++++++++++++++++++ include/linux/mmc/host.h | 4 + include/linux/mmc/sdio_func.h | 7 + 5 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/mmc/core/sdio_irq.c diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 05d69fc72c18..4985807257a8 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,5 +10,5 @@ obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ - sdio_cis.o sdio_io.o + sdio_cis.o sdio_io.o sdio_irq.o diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 129f0719c391..240724454914 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -143,6 +143,14 @@ static int sdio_bus_remove(struct device *dev) drv->remove(func); + if (func->irq_handler) { + printk(KERN_WARNING "WARNING: driver %s did not remove " + "its interrupt handler!\n", drv->name); + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); + } + return 0; } diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c new file mode 100644 index 000000000000..01922d29241d --- /dev/null +++ b/drivers/mmc/core/sdio_irq.c @@ -0,0 +1,237 @@ +/* + * linux/drivers/mmc/core/sdio_irq.c + * + * Author: Nicolas Pitre + * Created: June 18, 2007 + * Copyright: MontaVista Software 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 +#include + +#include "sdio_ops.h" + +static int process_sdio_pending_irqs(struct mmc_card *card) +{ + int i, ret; + unsigned char pending; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending); + if (ret) { + printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n", + mmc_card_id(card), ret); + return ret; + } + + for (i = 1; i <= 7; i++) { + if (pending & (1 << i)) { + struct sdio_func *func = card->sdio_func[i - 1]; + if (!func) { + printk(KERN_WARNING "%s: pending IRQ for " + "non-existant function\n", + sdio_func_id(func)); + } else if (func->irq_handler) { + func->irq_handler(func); + } else + printk(KERN_WARNING "%s: pending IRQ with no handler\n", + sdio_func_id(func)); + } + } + + return 0; +} + +static int sdio_irq_thread(void *_host) +{ + struct mmc_host *host = _host; + struct sched_param param = { .sched_priority = 1 }; + unsigned long period; + int ret; + + sched_setscheduler(current, SCHED_FIFO, ¶m); + + /* + * We want to allow for SDIO cards to work even on non SDIO + * aware hosts. One thing that non SDIO host cannot do is + * asynchronous notification of pending SDIO card interrupts + * hence we poll for them in that case. + */ + period = msecs_to_jiffies(10); + + pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n", + mmc_hostname(host), period); + + do { + /* + * We claim the host here on drivers behalf for a couple + * reasons: + * + * 1) it is already needed to retrieve the CCCR_INTx; + * 2) we want the driver(s) to clear the IRQ condition ASAP; + * 3) we need to control the abort condition locally. + * + * Just like traditional hard IRQ handlers, we expect SDIO + * IRQ handlers to be quick and to the point, so that the + * holding of the host lock does not cover too much work + * that doesn't require that lock to be held. + */ + ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort); + if (ret) + break; + ret = process_sdio_pending_irqs(host->card); + mmc_release_host(host); + + /* + * Give other threads a chance to run in the presence of + * errors. FIXME: determine if due to card removal and + * possibly exit this thread if so. + */ + if (ret) + ssleep(1); + + set_task_state(current, TASK_INTERRUPTIBLE); + if (!kthread_should_stop()) + schedule_timeout(period); + set_task_state(current, TASK_RUNNING); + } while (!kthread_should_stop()); + + pr_debug("%s: IRQ thread exiting with code %d\n", + mmc_hostname(host), ret); + + return ret; +} + +static int sdio_card_irq_get(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + + BUG_ON(!host->claimed); + + if (!host->sdio_irqs++) { + atomic_set(&host->sdio_irq_thread_abort, 0); + host->sdio_irq_thread = + kthread_run(sdio_irq_thread, host, "ksdiorqd"); + if (IS_ERR(host->sdio_irq_thread)) { + int err = PTR_ERR(host->sdio_irq_thread); + host->sdio_irqs--; + return err; + } + } + + return 0; +} + +static int sdio_card_irq_put(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + + BUG_ON(!host->claimed); + BUG_ON(host->sdio_irqs < 1); + + if (!--host->sdio_irqs) { + atomic_set(&host->sdio_irq_thread_abort, 1); + kthread_stop(host->sdio_irq_thread); + } + + return 0; +} + +/** + * sdio_claim_irq - claim the IRQ for a SDIO function + * @func: SDIO function + * @handler: IRQ handler callback + * + * Claim and activate the IRQ for the given SDIO function. The provided + * handler will be called when that IRQ is asserted. The host is always + * claimed already when the handler is called so the handler must not + * call sdio_claim_host() nor sdio_release_host(). + */ +int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler) +{ + int ret; + unsigned char reg; + + BUG_ON(!func); + BUG_ON(!func->card); + + pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func)); + + if (func->irq_handler) { + pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func)); + return -EBUSY; + } + + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®); + if (ret) + return ret; + + reg |= 1 << func->num; + + reg |= 1; /* Master interrupt enable */ + + ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL); + if (ret) + return ret; + + func->irq_handler = handler; + ret = sdio_card_irq_get(func->card); + if (ret) + func->irq_handler = NULL; + + return ret; +} +EXPORT_SYMBOL_GPL(sdio_claim_irq); + +/** + * sdio_release_irq - release the IRQ for a SDIO function + * @func: SDIO function + * + * Disable and release the IRQ for the given SDIO function. + */ +int sdio_release_irq(struct sdio_func *func) +{ + int ret; + unsigned char reg; + + BUG_ON(!func); + BUG_ON(!func->card); + + pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func)); + + if (func->irq_handler) { + func->irq_handler = NULL; + sdio_card_irq_put(func->card); + } + + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®); + if (ret) + return ret; + + reg &= ~(1 << func->num); + + /* Disable master interrupt with the last function interrupt */ + if (!(reg & 0xFE)) + reg = 0; + + ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(sdio_release_irq); + diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 8e2642ebf02f..00dc1809494c 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -123,6 +123,10 @@ struct mmc_host { unsigned int bus_refs; /* reference counter */ unsigned int bus_dead:1; /* bus has been released */ + unsigned int sdio_irqs; + struct task_struct *sdio_irq_thread; + atomic_t sdio_irq_thread_abort; + unsigned long private[0] ____cacheline_aligned; }; diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 8106d399c414..a8d268c9c276 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -16,6 +16,9 @@ #include struct mmc_card; +struct sdio_func; + +typedef void (sdio_irq_handler_t)(struct sdio_func *); /* * SDIO function CIS tuple (unknown to the core) @@ -33,6 +36,7 @@ struct sdio_func_tuple { struct sdio_func { struct mmc_card *card; /* the card this device belongs to */ struct device dev; /* the device */ + sdio_irq_handler_t *irq_handler; /* IRQ callback */ unsigned int num; /* function number */ unsigned char class; /* standard interface class */ @@ -105,6 +109,9 @@ extern void sdio_release_host(struct sdio_func *func); extern int sdio_enable_func(struct sdio_func *func); extern int sdio_disable_func(struct sdio_func *func); +extern int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler); +extern int sdio_release_irq(struct sdio_func *func); + extern unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret); From 6e418a9d26ab4fd44b3e07dc1158027cbdf0a919 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 30 Jun 2007 02:04:21 -0400 Subject: [PATCH 0312/2804] sdio: UART/GPS driver This currently only accepts the GPS class since that's all I have for testing. Tested with a Matsushita GPS and gpsd version 2.34. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/card/Kconfig | 7 + drivers/mmc/card/Makefile | 2 + drivers/mmc/card/sdio_uart.c | 1077 ++++++++++++++++++++++++++++++++++ 3 files changed, 1086 insertions(+) create mode 100644 drivers/mmc/card/sdio_uart.c diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig index a49cb9737cd8..aa8a4e461942 100644 --- a/drivers/mmc/card/Kconfig +++ b/drivers/mmc/card/Kconfig @@ -32,3 +32,10 @@ config MMC_BLOCK_BOUNCE If unsure, say Y here. +config SDIO_UART + tristate "SDIO UART/GPS class support" + depends on MMC + help + SDIO function driver for SDIO cards that implements the UART + class, as well as the GPS class which appears like a UART. + diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile index cf8c939867f5..fc5a784cfa1a 100644 --- a/drivers/mmc/card/Makefile +++ b/drivers/mmc/card/Makefile @@ -9,3 +9,5 @@ endif obj-$(CONFIG_MMC_BLOCK) += mmc_block.o mmc_block-objs := block.o queue.o +obj-$(CONFIG_SDIO_UART) += sdio_uart.o + diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c new file mode 100644 index 000000000000..e4d9e85ff584 --- /dev/null +++ b/drivers/mmc/card/sdio_uart.c @@ -0,0 +1,1077 @@ +/* + * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver + * + * Based on drivers/serial/8250.c and drivers/serial/serial_core.c + * by Russell King. + * + * Author: Nicolas Pitre + * Created: June 15, 2007 + * Copyright: MontaVista Software, 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. + */ + +/* + * Note: Although this driver assumes a 16550A-like UART implementation, + * it is not possible to leverage the common 8250/16550 driver, nor the + * core UART infrastructure, as they assumes direct access to the hardware + * registers, often under a spinlock. This is not possible in the SDIO + * context as SDIO access functions must be able to sleep. + * + * Because we need to lock the SDIO host to ensure an exclusive access to + * the card, we simply rely on that lock to also prevent and serialize + * concurrent access to the same port. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#define UART_NR 8 /* Number of UARTs this driver can handle */ + + +#define UART_XMIT_SIZE PAGE_SIZE +#define WAKEUP_CHARS 256 + +#define circ_empty(circ) ((circ)->head == (circ)->tail) +#define circ_clear(circ) ((circ)->head = (circ)->tail = 0) + +#define circ_chars_pending(circ) \ + (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) + +#define circ_chars_free(circ) \ + (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) + + +struct uart_icount { + __u32 cts; + __u32 dsr; + __u32 rng; + __u32 dcd; + __u32 rx; + __u32 tx; + __u32 frame; + __u32 overrun; + __u32 parity; + __u32 brk; +}; + +struct sdio_uart_port { + struct kref kref; + struct tty_struct *tty; + unsigned int index; + unsigned int opened; + struct mutex open_lock; + struct sdio_func *func; + struct mutex func_lock; + unsigned int regs_offset; + struct circ_buf xmit; + spinlock_t write_lock; + struct uart_icount icount; + unsigned int uartclk; + unsigned int mctrl; + unsigned int read_status_mask; + unsigned int ignore_status_mask; + unsigned char x_char; + unsigned char ier; + unsigned char lcr; +}; + +static struct sdio_uart_port *sdio_uart_table[UART_NR]; +static DEFINE_SPINLOCK(sdio_uart_table_lock); + +static int sdio_uart_add_port(struct sdio_uart_port *port) +{ + int index, ret = -EBUSY; + + kref_init(&port->kref); + mutex_init(&port->open_lock); + mutex_init(&port->func_lock); + spin_lock_init(&port->write_lock); + + spin_lock(&sdio_uart_table_lock); + for (index = 0; index < UART_NR; index++) { + if (!sdio_uart_table[index]) { + port->index = index; + sdio_uart_table[index] = port; + ret = 0; + break; + } + } + spin_unlock(&sdio_uart_table_lock); + + return ret; +} + +static struct sdio_uart_port *sdio_uart_port_get(unsigned index) +{ + struct sdio_uart_port *port; + + if (index >= UART_NR) + return NULL; + + spin_lock(&sdio_uart_table_lock); + port = sdio_uart_table[index]; + if (port) + kref_get(&port->kref); + spin_unlock(&sdio_uart_table_lock); + + return port; +} + +static void sdio_uart_port_destroy(struct kref *kref) +{ + struct sdio_uart_port *port = + container_of(kref, struct sdio_uart_port, kref); + kfree(port); +} + +static void sdio_uart_port_put(struct sdio_uart_port *port) +{ + kref_put(&port->kref, sdio_uart_port_destroy); +} + +static void sdio_uart_port_remove(struct sdio_uart_port *port) +{ + struct sdio_func *func; + + BUG_ON(sdio_uart_table[port->index] != port); + + spin_lock(&sdio_uart_table_lock); + sdio_uart_table[port->index] = NULL; + spin_unlock(&sdio_uart_table_lock); + + /* + * We're killing a port that potentially still is in use by + * the tty layer. Be careful to prevent any further access + * to the SDIO function and arrange for the tty layer to + * give up on that port ASAP. + * Beware: the lock ordering is critical. + */ + mutex_lock(&port->open_lock); + mutex_lock(&port->func_lock); + func = port->func; + sdio_claim_host(func); + port->func = NULL; + mutex_unlock(&port->func_lock); + if (port->opened) + tty_hangup(port->tty); + mutex_unlock(&port->open_lock); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + + sdio_uart_port_put(port); +} + +static int sdio_uart_claim_func(struct sdio_uart_port *port) +{ + mutex_lock(&port->func_lock); + if (unlikely(!port->func)) { + mutex_unlock(&port->func_lock); + return -ENODEV; + } + sdio_claim_host(port->func); + mutex_unlock(&port->func_lock); + return 0; +} + +static inline void sdio_uart_release_func(struct sdio_uart_port *port) +{ + sdio_release_host(port->func); +} + +static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset) +{ + unsigned char c; + c = sdio_readb(port->func, port->regs_offset + offset, NULL); + return c; +} + +static inline void sdio_out(struct sdio_uart_port *port, int offset, int value) +{ + sdio_writeb(port->func, value, port->regs_offset + offset, NULL); +} + +static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port) +{ + unsigned char status; + unsigned int ret; + + status = sdio_in(port, UART_MSR); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void sdio_uart_write_mctrl(struct sdio_uart_port *port, unsigned int mctrl) +{ + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + sdio_out(port, UART_MCR, mcr); +} + +static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port, + unsigned int set, unsigned int clear) +{ + unsigned int old; + + old = port->mctrl; + port->mctrl = (old & ~clear) | set; + if (old != port->mctrl) + sdio_uart_write_mctrl(port, port->mctrl); +} + +#define sdio_uart_set_mctrl(port, x) sdio_uart_update_mctrl(port, x, 0) +#define sdio_uart_clear_mctrl(port, x) sdio_uart_update_mctrl(port, 0, x) + +static void sdio_uart_change_speed(struct sdio_uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned char cval, fcr = 0; + unsigned int baud, quot; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; + + for (;;) { + baud = tty_termios_baud_rate(termios); + if (baud == 0) + baud = 9600; /* Special case: B0 rate. */ + if (baud <= port->uartclk) + break; + /* + * Oops, the quotient was zero. Try again with the old + * baud rate if possible, otherwise default to 9600. + */ + termios->c_cflag &= ~CBAUD; + if (old) { + termios->c_cflag |= old->c_cflag & CBAUD; + old = NULL; + } else + termios->c_cflag |= B9600; + } + quot = (2 * port->uartclk + baud) / (2 * baud); + + if (baud < 2400) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; + + port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + port->ier &= ~UART_IER_MSI; + if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL)) + port->ier |= UART_IER_MSI; + + port->lcr = cval; + + sdio_out(port, UART_IER, port->ier); + sdio_out(port, UART_LCR, cval | UART_LCR_DLAB); + sdio_out(port, UART_DLL, quot & 0xff); + sdio_out(port, UART_DLM, quot >> 8); + sdio_out(port, UART_LCR, cval); + sdio_out(port, UART_FCR, fcr); + + sdio_uart_write_mctrl(port, port->mctrl); +} + +static void sdio_uart_start_tx(struct sdio_uart_port *port) +{ + if (!(port->ier & UART_IER_THRI)) { + port->ier |= UART_IER_THRI; + sdio_out(port, UART_IER, port->ier); + } +} + +static void sdio_uart_stop_tx(struct sdio_uart_port *port) +{ + if (port->ier & UART_IER_THRI) { + port->ier &= ~UART_IER_THRI; + sdio_out(port, UART_IER, port->ier); + } +} + +static void sdio_uart_stop_rx(struct sdio_uart_port *port) +{ + port->ier &= ~UART_IER_RLSI; + port->read_status_mask &= ~UART_LSR_DR; + sdio_out(port, UART_IER, port->ier); +} + +static void sdio_uart_receive_chars(struct sdio_uart_port *port, int *status) +{ + struct tty_struct *tty = port->tty; + unsigned int ch, flag; + int max_count = 256; + + do { + ch = sdio_in(port, UART_RX); + flag = TTY_NORMAL; + port->icount.rx++; + + if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE))) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(UART_LSR_FE | UART_LSR_PE); + port->icount.brk++; + } else if (*status & UART_LSR_PE) + port->icount.parity++; + else if (*status & UART_LSR_FE) + port->icount.frame++; + if (*status & UART_LSR_OE) + port->icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ + *status &= port->read_status_mask; + if (*status & UART_LSR_BI) { + flag = TTY_BREAK; + } else if (*status & UART_LSR_PE) + flag = TTY_PARITY; + else if (*status & UART_LSR_FE) + flag = TTY_FRAME; + } + + if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) + tty_insert_flip_char(tty, ch, flag); + + /* + * Overrun is special. Since it's reported immediately, + * it doesn't affect the current character. + */ + if (*status & ~port->ignore_status_mask & UART_LSR_OE) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + *status = sdio_in(port, UART_LSR); + } while ((*status & UART_LSR_DR) && (max_count-- > 0)); + tty_flip_buffer_push(tty); +} + +static void sdio_uart_transmit_chars(struct sdio_uart_port *port) +{ + struct circ_buf *xmit = &port->xmit; + int count; + + if (port->x_char) { + sdio_out(port, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) { + sdio_uart_stop_tx(port); + return; + } + + count = 16; + do { + sdio_out(port, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (circ_empty(xmit)) + break; + } while (--count > 0); + + if (circ_chars_pending(xmit) < WAKEUP_CHARS) + tty_wakeup(port->tty); + + if (circ_empty(xmit)) + sdio_uart_stop_tx(port); +} + +static void sdio_uart_check_modem_status(struct sdio_uart_port *port) +{ + int status; + + status = sdio_in(port, UART_MSR); + + if ((status & UART_MSR_ANY_DELTA) == 0) + return; + + if (status & UART_MSR_TERI) + port->icount.rng++; + if (status & UART_MSR_DDSR) + port->icount.dsr++; + if (status & UART_MSR_DDCD) + port->icount.dcd++; + if (status & UART_MSR_DCTS) { + port->icount.cts++; + if (port->tty->termios->c_cflag & CRTSCTS) { + int cts = (status & UART_MSR_CTS); + if (port->tty->hw_stopped) { + if (cts) { + port->tty->hw_stopped = 0; + sdio_uart_start_tx(port); + tty_wakeup(port->tty); + } + } else { + if (!cts) { + port->tty->hw_stopped = 1; + sdio_uart_stop_tx(port); + } + } + } + } +} + +/* + * This handles the interrupt from one port. + */ +static void sdio_uart_irq(struct sdio_func *func) +{ + struct sdio_uart_port *port = sdio_get_drvdata(func); + unsigned int iir, lsr; + + iir = sdio_in(port, UART_IIR); + if (iir & UART_IIR_NO_INT) + return; + lsr = sdio_in(port, UART_LSR); + if (lsr & UART_LSR_DR) + sdio_uart_receive_chars(port, &lsr); + sdio_uart_check_modem_status(port); + if (lsr & UART_LSR_THRE) + sdio_uart_transmit_chars(port); +} + +static int sdio_uart_startup(struct sdio_uart_port *port) +{ + unsigned long page; + int ret; + + /* + * Set the TTY IO error marker - we will only clear this + * once we have successfully opened the port. + */ + set_bit(TTY_IO_ERROR, &port->tty->flags); + + /* Initialise and allocate the transmit buffer. */ + page = __get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + port->xmit.buf = (unsigned char *)page; + circ_clear(&port->xmit); + + ret = sdio_uart_claim_func(port); + if (ret) + goto err1; + ret = sdio_enable_func(port->func); + if (ret) + goto err2; + ret = sdio_claim_irq(port->func, sdio_uart_irq); + if (ret) + goto err3; + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in sdio_change_speed()) + */ + sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); + sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + sdio_out(port, UART_FCR, 0); + + /* + * Clear the interrupt registers. + */ + (void) sdio_in(port, UART_LSR); + (void) sdio_in(port, UART_RX); + (void) sdio_in(port, UART_IIR); + (void) sdio_in(port, UART_MSR); + + /* + * Now, initialize the UART + */ + sdio_out(port, UART_LCR, UART_LCR_WLEN8); + + port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE; + port->mctrl = TIOCM_OUT2; + + sdio_uart_change_speed(port, port->tty->termios, NULL); + + if (port->tty->termios->c_cflag & CBAUD) + sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); + + if (port->tty->termios->c_cflag & CRTSCTS) + if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) + port->tty->hw_stopped = 1; + + clear_bit(TTY_IO_ERROR, &port->tty->flags); + + /* Kick the IRQ handler once while we're still holding the host lock */ + sdio_uart_irq(port->func); + + sdio_uart_release_func(port); + return 0; + +err3: + sdio_disable_func(port->func); +err2: + sdio_uart_release_func(port); +err1: + free_page((unsigned long)port->xmit.buf); + return ret; +} + +static void sdio_uart_shutdown(struct sdio_uart_port *port) +{ + int ret; + + ret = sdio_uart_claim_func(port); + if (ret) + goto skip; + + sdio_uart_stop_rx(port); + + /* TODO: wait here for TX FIFO to drain */ + + /* Turn off DTR and RTS early. */ + if (port->tty->termios->c_cflag & HUPCL) + sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); + + /* Disable interrupts from this port */ + sdio_release_irq(port->func); + port->ier = 0; + sdio_out(port, UART_IER, 0); + + sdio_uart_clear_mctrl(port, TIOCM_OUT2); + + /* Disable break condition and FIFOs. */ + port->lcr &= ~UART_LCR_SBC; + sdio_out(port, UART_LCR, port->lcr); + sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + sdio_out(port, UART_FCR, 0); + + sdio_disable_func(port->func); + + sdio_uart_release_func(port); + +skip: + /* Free the transmit buffer page. */ + free_page((unsigned long)port->xmit.buf); +} + +static int sdio_uart_open (struct tty_struct *tty, struct file * filp) +{ + struct sdio_uart_port *port; + int ret; + + port = sdio_uart_port_get(tty->index); + if (!port) + return -ENODEV; + + mutex_lock(&port->open_lock); + + /* + * Make sure not to mess up with a dead port + * which has not been closed yet. + */ + if (tty->driver_data && tty->driver_data != port) { + mutex_unlock(&port->open_lock); + sdio_uart_port_put(port); + return -EBUSY; + } + + if (!port->opened) { + tty->driver_data = port; + port->tty = tty; + ret = sdio_uart_startup(port); + if (ret) { + tty->driver_data = NULL; + port->tty = NULL; + mutex_unlock(&port->open_lock); + sdio_uart_port_put(port); + return ret; + } + } + port->opened++; + mutex_unlock(&port->open_lock); + return 0; +} + +static void sdio_uart_close(struct tty_struct *tty, struct file * filp) +{ + struct sdio_uart_port *port = tty->driver_data; + + if (!port) + return; + + mutex_lock(&port->open_lock); + BUG_ON(!port->opened); + + /* + * This is messy. The tty layer calls us even when open() + * returned an error. Ignore this close request if tty->count + * is larger than port->count. + */ + if (tty->count > port->opened) { + mutex_unlock(&port->open_lock); + return; + } + + if (--port->opened == 0) { + tty->closing = 1; + sdio_uart_shutdown(port); + tty_ldisc_flush(tty); + port->tty = NULL; + tty->driver_data = NULL; + tty->closing = 0; + } + mutex_unlock(&port->open_lock); + sdio_uart_port_put(port); +} + +static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf, + int count) +{ + struct sdio_uart_port *port = tty->driver_data; + struct circ_buf *circ = &port->xmit; + int c, ret = 0; + + if (!port->func) + return -ENODEV; + + spin_lock(&port->write_lock); + while (1) { + c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + memcpy(circ->buf + circ->head, buf, c); + circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); + buf += c; + count -= c; + ret += c; + } + spin_unlock(&port->write_lock); + + if ( !(port->ier & UART_IER_THRI)) { + int err = sdio_uart_claim_func(port); + if (!err) { + sdio_uart_start_tx(port); + sdio_uart_irq(port->func); + sdio_uart_release_func(port); + } else + ret = err; + } + + return ret; +} + +static int sdio_uart_write_room(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + return port ? circ_chars_free(&port->xmit) : 0; +} + +static int sdio_uart_chars_in_buffer(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + return port ? circ_chars_pending(&port->xmit) : 0; +} + +static void sdio_uart_send_xchar(struct tty_struct *tty, char ch) +{ + struct sdio_uart_port *port = tty->driver_data; + + port->x_char = ch; + if (ch && !(port->ier & UART_IER_THRI)) { + if (sdio_uart_claim_func(port) != 0) + return; + sdio_uart_start_tx(port); + sdio_uart_irq(port->func); + sdio_uart_release_func(port); + } +} + +static void sdio_uart_throttle(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + + if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + return; + + if (sdio_uart_claim_func(port) != 0) + return; + + if (I_IXOFF(tty)) { + port->x_char = STOP_CHAR(tty); + sdio_uart_start_tx(port); + } + + if (tty->termios->c_cflag & CRTSCTS) + sdio_uart_clear_mctrl(port, TIOCM_RTS); + + sdio_uart_irq(port->func); + sdio_uart_release_func(port); +} + +static void sdio_uart_unthrottle(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + + if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + return; + + if (sdio_uart_claim_func(port) != 0) + return; + + if (I_IXOFF(tty)) { + if (port->x_char) { + port->x_char = 0; + } else { + port->x_char = START_CHAR(tty); + sdio_uart_start_tx(port); + } + } + + if (tty->termios->c_cflag & CRTSCTS) + sdio_uart_set_mctrl(port, TIOCM_RTS); + + sdio_uart_irq(port->func); + sdio_uart_release_func(port); +} + +static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +{ + struct sdio_uart_port *port = tty->driver_data; + unsigned int cflag = tty->termios->c_cflag; + +#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + if ((cflag ^ old_termios->c_cflag) == 0 && + RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) + return; + + if (sdio_uart_claim_func(port) != 0) + return; + + sdio_uart_change_speed(port, tty->termios, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) + sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR); + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { + unsigned int mask = TIOCM_DTR; + if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) + mask |= TIOCM_RTS; + sdio_uart_set_mctrl(port, mask); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { + tty->hw_stopped = 0; + sdio_uart_start_tx(port); + } + + /* Handle turning on CRTSCTS */ + if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { + if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) { + tty->hw_stopped = 1; + sdio_uart_stop_tx(port); + } + } + + sdio_uart_release_func(port); +} + +static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state) +{ + struct sdio_uart_port *port = tty->driver_data; + + if (sdio_uart_claim_func(port) != 0) + return; + + if (break_state == -1) + port->lcr |= UART_LCR_SBC; + else + port->lcr &= ~UART_LCR_SBC; + sdio_out(port, UART_LCR, port->lcr); + + sdio_uart_release_func(port); +} + +static int sdio_uart_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct sdio_uart_port *port = tty->driver_data; + int result; + + result = sdio_uart_claim_func(port); + if (!result) { + result = port->mctrl | sdio_uart_get_mctrl(port); + sdio_uart_release_func(port); + } + + return result; +} + +static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct sdio_uart_port *port = tty->driver_data; + int result; + + result =sdio_uart_claim_func(port); + if(!result) { + sdio_uart_update_mctrl(port, set, clear); + sdio_uart_release_func(port); + } + + return result; +} + +static const struct tty_operations sdio_uart_ops = { + .open = sdio_uart_open, + .close = sdio_uart_close, + .write = sdio_uart_write, + .write_room = sdio_uart_write_room, + .chars_in_buffer = sdio_uart_chars_in_buffer, + .send_xchar = sdio_uart_send_xchar, + .throttle = sdio_uart_throttle, + .unthrottle = sdio_uart_unthrottle, + .set_termios = sdio_uart_set_termios, + .break_ctl = sdio_uart_break_ctl, + .tiocmget = sdio_uart_tiocmget, + .tiocmset = sdio_uart_tiocmset, +}; + +static struct tty_driver *sdio_uart_tty_driver; + +static int sdio_uart_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct sdio_uart_port *port; + int ret; + + port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + if (func->class == SDIO_CLASS_UART) { + printk(KERN_WARNING "%s: need info on UART class basic setup\n", + sdio_func_id(func)); + kfree(port); + return -ENOSYS; + } else if (func->class == SDIO_CLASS_GPS) { + /* + * We need tuple 0x91. It contains SUBTPL_SIOREG + * and SUBTPL_RCVCAPS. + */ + struct sdio_func_tuple *tpl; + for (tpl = func->tuples; tpl; tpl = tpl->next) { + if (tpl->code != 0x91) + continue; + if (tpl->size < 10) + continue; + if (tpl->data[1] == 0) /* SUBTPL_SIOREG */ + break; + } + if (!tpl) { + printk(KERN_WARNING + "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", + sdio_func_id(func)); + kfree(port); + return -EINVAL; + } + printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", + sdio_func_id(func), tpl->data[2], tpl->data[3]); + port->regs_offset = (tpl->data[4] << 0) | + (tpl->data[5] << 8) | + (tpl->data[6] << 16); + printk(KERN_DEBUG "%s: regs offset = 0x%x\n", + sdio_func_id(func), port->regs_offset); + port->uartclk = tpl->data[7] * 115200; + if (port->uartclk == 0) + port->uartclk = 115200; + printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n", + sdio_func_id(func), port->uartclk, + tpl->data[7], tpl->data[8] | (tpl->data[9] << 8)); + } else { + kfree(port); + return -EINVAL; + } + + port->func = func; + sdio_set_drvdata(func, port); + + ret = sdio_uart_add_port(port); + if (ret) { + kfree(port); + } else { + struct device *dev; + dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev); + if (IS_ERR(dev)) { + sdio_uart_port_remove(port); + ret = PTR_ERR(dev); + } + } + + return ret; +} + +static void sdio_uart_remove(struct sdio_func *func) +{ + struct sdio_uart_port *port = sdio_get_drvdata(func); + + tty_unregister_device(sdio_uart_tty_driver, port->index); + sdio_uart_port_remove(port); +} + +static const struct sdio_device_id sdio_uart_ids[] = { + { SDIO_DEVICE_CLASS(SDIO_CLASS_UART) }, + { SDIO_DEVICE_CLASS(SDIO_CLASS_GPS) }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, sdio_uart_ids); + +static struct sdio_driver sdio_uart_driver = { + .probe = sdio_uart_probe, + .remove = sdio_uart_remove, + .name = "sdio_uart", + .id_table = sdio_uart_ids, +}; + +static int __init sdio_uart_init(void) +{ + int ret; + struct tty_driver *tty_drv; + + sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR); + if (!tty_drv) + return -ENOMEM; + + tty_drv->owner = THIS_MODULE; + tty_drv->driver_name = "sdio_uart"; + tty_drv->name = "ttySDIO"; + tty_drv->major = 0; /* dynamically allocated */ + tty_drv->minor_start = 0; + tty_drv->type = TTY_DRIVER_TYPE_SERIAL; + tty_drv->subtype = SERIAL_TYPE_NORMAL; + tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_drv->init_termios = tty_std_termios; + tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; + tty_set_operations(tty_drv, &sdio_uart_ops); + + ret = tty_register_driver(tty_drv); + if (ret) + goto err1; + + ret = sdio_register_driver(&sdio_uart_driver); + if (ret) + goto err2; + + return 0; + +err2: + tty_unregister_driver(tty_drv); +err1: + put_tty_driver(tty_drv); + return ret; +} + +static void __exit sdio_uart_exit(void) +{ + sdio_unregister_driver(&sdio_uart_driver); + tty_unregister_driver(sdio_uart_tty_driver); + put_tty_driver(sdio_uart_tty_driver); +} + +module_init(sdio_uart_init); +module_exit(sdio_uart_exit); + +MODULE_AUTHOR("Nicolas Pitre"); +MODULE_LICENSE("GPL"); From 5ed334a1f8caaae98806d572f78c5802975ea20f Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 4 Jul 2007 23:40:34 -0400 Subject: [PATCH 0313/2804] sdio: add /proc interface to sdio_uart driver This mimics what the serial_core does. Useful for diagnostics. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/card/sdio_uart.c | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index e4d9e85ff584..190120d1449a 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -913,6 +913,67 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file, return result; } +static int sdio_uart_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int i, len = 0; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", + "", "", ""); + for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) { + struct sdio_uart_port *port = sdio_uart_port_get(i); + if (port) { + len += sprintf(page+len, "%d: uart:SDIO", i); + if(capable(CAP_SYS_ADMIN)) { + len += sprintf(page + len, " tx:%d rx:%d", + port->icount.tx, port->icount.rx); + if (port->icount.frame) + len += sprintf(page + len, " fe:%d", + port->icount.frame); + if (port->icount.parity) + len += sprintf(page + len, " pe:%d", + port->icount.parity); + if (port->icount.brk) + len += sprintf(page + len, " brk:%d", + port->icount.brk); + if (port->icount.overrun) + len += sprintf(page + len, " oe:%d", + port->icount.overrun); + if (port->icount.cts) + len += sprintf(page + len, " cts:%d", + port->icount.cts); + if (port->icount.dsr) + len += sprintf(page + len, " dsr:%d", + port->icount.dsr); + if (port->icount.rng) + len += sprintf(page + len, " rng:%d", + port->icount.rng); + if (port->icount.dcd) + len += sprintf(page + len, " dcd:%d", + port->icount.dcd); + } + strcat(page, "\n"); + len++; + sdio_uart_port_put(port); + } + + if (len + begin > off + count) + goto done; + if (len + begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; + +done: + if (off >= len + begin) + return 0; + *start = page + (off - begin); + return (count < begin + len - off) ? count : (begin + len - off); +} + static const struct tty_operations sdio_uart_ops = { .open = sdio_uart_open, .close = sdio_uart_close, @@ -926,6 +987,7 @@ static const struct tty_operations sdio_uart_ops = { .break_ctl = sdio_uart_break_ctl, .tiocmget = sdio_uart_tiocmget, .tiocmset = sdio_uart_tiocmset, + .read_proc = sdio_uart_read_proc, }; static struct tty_driver *sdio_uart_tty_driver; From 112c9db91ee6bf19eca7cbb6854be3127381c229 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 6 Jul 2007 13:35:01 +0200 Subject: [PATCH 0314/2804] sdio: support IO_RW_EXTENDED Support the multi-byte transfer operation, including handlers for common operations like writel()/readl(). Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_io.c | 184 ++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_ops.c | 57 +++++++++++ drivers/mmc/core/sdio_ops.h | 2 + include/linux/mmc/sdio.h | 12 +++ include/linux/mmc/sdio_func.h | 20 ++++ 5 files changed, 275 insertions(+) diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index eb6c20935cef..ecdb77242e98 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -196,3 +196,187 @@ void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, } EXPORT_SYMBOL_GPL(sdio_writeb); +/** + * sdio_memcpy_fromio - read a chunk of memory from a SDIO function + * @func: SDIO function to access + * @dst: buffer to store the data + * @addr: address to begin reading from + * @count: number of bytes to read + * + * Reads up to 512 bytes from the address space of a given SDIO + * function. Return value indicates if the transfer succeeded or + * not. + */ +int sdio_memcpy_fromio(struct sdio_func *func, void *dst, + unsigned int addr, int count) +{ + return mmc_io_rw_extended(func->card, 0, func->num, addr, 0, dst, + count); +} +EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); + +/** + * sdio_memcpy_toio - write a chunk of memory to a SDIO function + * @func: SDIO function to access + * @addr: address to start writing to + * @src: buffer that contains the data to write + * @count: number of bytes to write + * + * Writes up to 512 bytes to the address space of a given SDIO + * function. Return value indicates if the transfer succeeded or + * not. + */ +int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, + void *src, int count) +{ + return mmc_io_rw_extended(func->card, 1, func->num, addr, 0, src, + count); +} +EXPORT_SYMBOL_GPL(sdio_memcpy_toio); + +/** + * sdio_readsb - read from a FIFO on a SDIO function + * @func: SDIO function to access + * @dst: buffer to store the data + * @addr: address of (single byte) FIFO + * @count: number of bytes to read + * + * Reads up to 512 bytes from the specified FIFO of a given SDIO + * function. Return value indicates if the transfer succeeded or + * not. + */ +int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, + int count) +{ + return mmc_io_rw_extended(func->card, 0, func->num, addr, 1, dst, + count); +} + +EXPORT_SYMBOL_GPL(sdio_readsb); + +/** + * sdio_writesb - write to a FIFO of a SDIO function + * @func: SDIO function to access + * @addr: address of (single byte) FIFO + * @src: buffer that contains the data to write + * @count: number of bytes to write + * + * Writes up to 512 bytes to the specified FIFO of a given SDIO + * function. Return value indicates if the transfer succeeded or + * not. + */ +int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, + int count) +{ + return mmc_io_rw_extended(func->card, 1, func->num, addr, 1, src, + count); +} +EXPORT_SYMBOL_GPL(sdio_writesb); + +/** + * sdio_readw - read a 16 bit integer from a SDIO function + * @func: SDIO function to access + * @addr: address to read + * @err_ret: optional status value from transfer + * + * Reads a 16 bit integer from the address space of a given SDIO + * function. If there is a problem reading the address, 0xffff + * is returned and @err_ret will contain the error code. + */ +unsigned short sdio_readw(struct sdio_func *func, unsigned int addr, + int *err_ret) +{ + int ret; + + if (err_ret) + *err_ret = 0; + + ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFFFF; + } + + return le16_to_cpu(*(u16*)func->tmpbuf); +} +EXPORT_SYMBOL_GPL(sdio_readw); + +/** + * sdio_writew - write a 16 bit integer to a SDIO function + * @func: SDIO function to access + * @b: integer to write + * @addr: address to write to + * @err_ret: optional status value from transfer + * + * Writes a 16 bit integer to the address space of a given SDIO + * function. @err_ret will contain the status of the actual + * transfer. + */ +void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr, + int *err_ret) +{ + int ret; + + *(u16*)func->tmpbuf = cpu_to_le16(b); + + ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2); + if (err_ret) + *err_ret = ret; +} +EXPORT_SYMBOL_GPL(sdio_writew); + +/** + * sdio_readl - read a 32 bit integer from a SDIO function + * @func: SDIO function to access + * @addr: address to read + * @err_ret: optional status value from transfer + * + * Reads a 32 bit integer from the address space of a given SDIO + * function. If there is a problem reading the address, + * 0xffffffff is returned and @err_ret will contain the error + * code. + */ +unsigned long sdio_readl(struct sdio_func *func, unsigned int addr, + int *err_ret) +{ + int ret; + + if (err_ret) + *err_ret = 0; + + ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFFFFFFFF; + } + + return le32_to_cpu(*(u32*)func->tmpbuf); +} +EXPORT_SYMBOL_GPL(sdio_readl); + +/** + * sdio_writel - write a 32 bit integer to a SDIO function + * @func: SDIO function to access + * @b: integer to write + * @addr: address to write to + * @err_ret: optional status value from transfer + * + * Writes a 32 bit integer to the address space of a given SDIO + * function. @err_ret will contain the status of the actual + * transfer. + */ +void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr, + int *err_ret) +{ + int ret; + + *(u32*)func->tmpbuf = cpu_to_le32(b); + + ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4); + if (err_ret) + *err_ret = ret; +} +EXPORT_SYMBOL_GPL(sdio_writel); + diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 31233f7b55cd..4f2c77139477 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -9,6 +9,9 @@ * your option) any later version. */ +#include +#include + #include #include #include @@ -84,3 +87,57 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, return 0; } +int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, + unsigned addr, int bang, u8 *buf, unsigned size) +{ + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + struct scatterlist sg; + + BUG_ON(!card); + BUG_ON(fn > 7); + BUG_ON(size > 512); + + memset(&mrq, 0, sizeof(struct mmc_request)); + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + mrq.cmd = &cmd; + mrq.data = &data; + + cmd.opcode = SD_IO_RW_EXTENDED; + cmd.arg = write ? 0x80000000 : 0x00000000; + cmd.arg |= fn << 28; + cmd.arg |= bang ? 0x00000000 : 0x04000000; + cmd.arg |= addr << 9; + cmd.arg |= (size == 512) ? 0 : size; + cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; + + data.blksz = size; + data.blocks = 1; + data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + sg_init_one(&sg, buf, size); + + mmc_set_data_timeout(&data, card); + + mmc_wait_for_req(card->host, &mrq); + + if (cmd.error) + return cmd.error; + if (data.error) + return data.error; + + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + + return 0; +} + diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index f0e9d69e5ce8..1d42e4f366aa 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -15,6 +15,8 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out); +int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, + unsigned addr, int bang, u8 *data, unsigned size); #endif diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index 56239f4aab04..9b1ec76cac37 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -15,6 +15,7 @@ /* SDIO commands type argument response */ #define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ #define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */ +#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */ /* * SD_IO_RW_DIRECT argument format: @@ -26,6 +27,17 @@ * [7:0] Data */ +/* + * SD_IO_RW_EXTENDED argument format: + * + * [31] R/W flag + * [30:28] Function number + * [27] Block mode + * [26] Increment address + * [25:9] Register address + * [8:0] Byte/block count + */ + /* SDIO status in R5 Type diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index a8d268c9c276..af813fffc4ac 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -48,6 +48,8 @@ struct sdio_func { unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ + u8 tmpbuf[4]; /* DMA:able scratch buffer */ + struct sdio_func_tuple *tuples; }; @@ -114,9 +116,27 @@ extern int sdio_release_irq(struct sdio_func *func); extern unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret); +extern unsigned short sdio_readw(struct sdio_func *func, + unsigned int addr, int *err_ret); +extern unsigned long sdio_readl(struct sdio_func *func, + unsigned int addr, int *err_ret); + +extern int sdio_memcpy_fromio(struct sdio_func *func, void *dst, + unsigned int addr, int count); +extern int sdio_readsb(struct sdio_func *func, void *dst, + unsigned int addr, int count); extern void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, int *err_ret); +extern void sdio_writew(struct sdio_func *func, unsigned short b, + unsigned int addr, int *err_ret); +extern void sdio_writel(struct sdio_func *func, unsigned long b, + unsigned int addr, int *err_ret); + +extern int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, + void *src, int count); +extern int sdio_writesb(struct sdio_func *func, unsigned int addr, + void *src, int count); #endif From 17b759aff916b4d02721e75ce5ed82b1903e5bd6 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 24 Jul 2007 02:09:39 -0400 Subject: [PATCH 0315/2804] sdio: add interface for host side SDIO interrupt reporting Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/host.c | 3 +++ drivers/mmc/core/sdio_irq.c | 8 +++++++- include/linux/mmc/host.h | 8 ++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 2c7ce8f43a9a..37b761891d67 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -100,6 +100,9 @@ int mmc_add_host(struct mmc_host *host) { int err; + WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && + !host->ops->enable_sdio_irq); + if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) return -ENOMEM; diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 01922d29241d..01daee934d16 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -70,7 +70,8 @@ static int sdio_irq_thread(void *_host) * asynchronous notification of pending SDIO card interrupts * hence we poll for them in that case. */ - period = msecs_to_jiffies(10); + period = (host->caps & MMC_CAP_SDIO_IRQ) ? + MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(10); pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n", mmc_hostname(host), period); @@ -104,11 +105,16 @@ static int sdio_irq_thread(void *_host) ssleep(1); set_task_state(current, TASK_INTERRUPTIBLE); + if (host->caps & MMC_CAP_SDIO_IRQ) + host->ops->enable_sdio_irq(host, 1); if (!kthread_should_stop()) schedule_timeout(period); set_task_state(current, TASK_RUNNING); } while (!kthread_should_stop()); + if (host->caps & MMC_CAP_SDIO_IRQ) + host->ops->enable_sdio_irq(host, 0); + pr_debug("%s: IRQ thread exiting with code %d\n", mmc_hostname(host), ret); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 00dc1809494c..3fd197962f73 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -51,6 +51,7 @@ struct mmc_host_ops { void (*request)(struct mmc_host *host, struct mmc_request *req); void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); int (*get_ro)(struct mmc_host *host); + void (*enable_sdio_irq)(struct mmc_host *host, int enable); }; struct mmc_card; @@ -89,6 +90,7 @@ struct mmc_host { #define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */ #define MMC_CAP_MMC_HIGHSPEED (1 << 2) /* Can do MMC high-speed timing */ #define MMC_CAP_SD_HIGHSPEED (1 << 3) /* Can do SD high-speed timing */ +#define MMC_CAP_SDIO_IRQ (1 << 4) /* Can signal pending SDIO IRQs */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ @@ -150,5 +152,11 @@ extern int mmc_resume_host(struct mmc_host *); extern void mmc_detect_change(struct mmc_host *, unsigned long delay); extern void mmc_request_done(struct mmc_host *, struct mmc_request *); +static inline void mmc_signal_sdio_irq(struct mmc_host *host) +{ + host->ops->enable_sdio_irq(host, 0); + wake_up_process(host->sdio_irq_thread); +} + #endif From 22bfc979d38f57d5b10d141990175d8fc47f6775 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 29 Jul 2007 16:58:09 +0200 Subject: [PATCH 0316/2804] make struct sdio_dev_attrs[] static On Wed, Jul 25, 2007 at 04:03:04AM -0700, Andrew Morton wrote: >... > Changes since 2.6.22-rc6-mm1: >... > git-mmc.patch >... > git trees >... sdio_dev_attrs[] can become static. Signed-off-by: Adrian Bunk Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 240724454914..d229020db4a2 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -46,7 +46,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, func->class, func->vendor, func->device); } -struct device_attribute sdio_dev_attrs[] = { +static struct device_attribute sdio_dev_attrs[] = { __ATTR_RO(class), __ATTR_RO(vendor), __ATTR_RO(device), From 6db5020e7386ddf17378f91eb8c445433e5b07cd Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jul 2007 17:15:07 +0200 Subject: [PATCH 0317/2804] sdio: change clock speed Change clock speed to the highest supported by the card. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 1fb36a340468..62df8e177585 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -293,6 +293,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto remove; + /* + * No support for high-speed yet, so just set + * the card's maximum speed. + */ + mmc_set_clock(host, card->cis.max_dtr); + /* * Initialize (but don't add) all present functions. */ From 4ff6471c028a9885e8f09a000d87694f81190ab9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jul 2007 18:23:53 +0200 Subject: [PATCH 0318/2804] sdio: enable wide bus mode Enable 4-bit data bus mode, according to host and card capabilities. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 62df8e177585..48c465a8e34e 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -138,6 +138,32 @@ out: return ret; } +static int sdio_enable_wide(struct mmc_card *card) +{ + int ret; + u8 ctrl; + + if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) + return 0; + + if (card->cccr.low_speed && !card->cccr.wide_bus) + return 0; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl); + if (ret) + return ret; + + ctrl |= SDIO_BUS_WIDTH_4BIT; + + ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); + if (ret) + return ret; + + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); + + return 0; +} + /* * Host is being removed. Free up the current card. */ @@ -299,6 +325,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) */ mmc_set_clock(host, card->cis.max_dtr); + /* + * Switch to wider bus (if supported). + */ + err = sdio_enable_wide(card); + if (err) + goto remove; + /* * Initialize (but don't add) all present functions. */ From ce252edd869ba1fee6a9a6f83e20f349d4c4d669 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 7 Aug 2007 14:06:18 +0200 Subject: [PATCH 0319/2804] mmc: fix incorrect divisor in debug output Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d1e4b0849e39..07c03cb677b6 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -121,7 +121,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) "tsac %d ms nsac %d\n", mmc_hostname(host), mrq->data->blksz, mrq->data->blocks, mrq->data->flags, - mrq->data->timeout_ns / 10000000, + mrq->data->timeout_ns / 1000000, mrq->data->timeout_clks); } From e6f918bf39773d712ab5b457bff54ade3bda0cb1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 7 Aug 2007 14:11:55 +0200 Subject: [PATCH 0320/2804] mmc: fix sdio timeout calculation SDIO doesn't have a CSD so it uses different timeout values than SD memory. Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 07c03cb677b6..9d29bed820a1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -231,6 +231,15 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) { unsigned int mult; + /* + * SDIO cards only define an upper 1 s limit on access. + */ + if (mmc_card_sdio(card)) { + data->timeout_ns = 1000000000; + data->timeout_clks = 0; + return; + } + /* * SD cards use a 100 multiplier rather than 10 */ From 7616ee95f27a04fd5a6434e9ef4a82cec4b2807c Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 8 Aug 2007 14:23:05 +0100 Subject: [PATCH 0321/2804] sdio: add SDIO_FBR_BASE(f) macro Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 4 ++-- drivers/mmc/core/sdio_cis.c | 2 +- include/linux/mmc/sdio.h | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 48c465a8e34e..58cf36e44678 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -30,7 +30,7 @@ static int sdio_read_fbr(struct sdio_func *func) unsigned char data; ret = mmc_io_rw_direct(func->card, 0, 0, - func->num * 0x100 + SDIO_FBR_STD_IF, 0, &data); + SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data); if (ret) goto out; @@ -38,7 +38,7 @@ static int sdio_read_fbr(struct sdio_func *func) if (data == 0x0f) { ret = mmc_io_rw_direct(func->card, 0, 0, - func->num * 0x100 + SDIO_FBR_STD_IF_EXT, 0, &data); + SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data); if (ret) goto out; } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index ec806a1229b6..d050c40cf046 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -145,7 +145,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) fn = 0; ret = mmc_io_rw_direct(card, 0, 0, - fn * 0x100 + SDIO_FBR_CIS + i, 0, &x); + SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x); if (ret) return ret; ptr |= x << (i * 8); diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index 9b1ec76cac37..47ba464f5170 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -132,6 +132,8 @@ * Function Basic Registers (FBR) */ +#define SDIO_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */ + #define SDIO_FBR_STD_IF 0x00 #define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */ From 9a08f82b3cc522f727ace580a2aaee5402435bc8 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 8 Aug 2007 14:23:48 +0100 Subject: [PATCH 0322/2804] sdio: set the functions' block size Before a driver is probed, set the function's block size to the default so the driver is sure the block size is something sensible and it needn't explicitly set it. The default block size is the largest that's supported by both the card and the host, with a maximum of 512 to ensure aribitrarily sized transfer use the optimal (least) number of commands. See http://lkml.org/lkml/2007/8/7/150 for reasons for the block size choice. Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 9 +++++++ drivers/mmc/core/sdio_cis.c | 2 +- drivers/mmc/core/sdio_io.c | 49 +++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 5 +++- 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index d229020db4a2..fcb13fb0daad 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -128,11 +128,20 @@ static int sdio_bus_probe(struct device *dev) struct sdio_driver *drv = to_sdio_driver(dev->driver); struct sdio_func *func = dev_to_sdio_func(dev); const struct sdio_device_id *id; + int ret; id = sdio_match_device(func, drv); if (!id) return -ENODEV; + /* Set the default block size so the driver is sure it's something + * sensible. */ + sdio_claim_host(func); + ret = sdio_set_block_size(func, 0); + sdio_release_host(func); + if (ret) + return ret; + return drv->probe(func, id); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index d050c40cf046..1d03f12bbb38 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -79,7 +79,7 @@ static int cistpl_funce_func(struct sdio_func *func, return -EINVAL; /* TPLFE_MAX_BLK_SIZE */ - func->blksize = buf[12] | (buf[13] << 8); + func->max_blksize = buf[12] | (buf[13] << 8); return 0; } diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index ecdb77242e98..c2bad1195e3b 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -140,6 +140,55 @@ err: } EXPORT_SYMBOL_GPL(sdio_disable_func); +/** + * sdio_set_block_size - set the block size of an SDIO function + * @func: SDIO function to change + * @blksz: new block size or 0 to use the default. + * + * The default block size is the largest supported by both the function + * and the host, with a maximum of 512 to ensure that arbitrarily sized + * data transfer use the optimal (least) number of commands. + * + * A driver may call this to override the default block size set by the + * core. This can be used to set a block size greater than the maximum + * that reported by the card; it is the driver's responsibility to ensure + * it uses a value that the card supports. + * + * Returns 0 on success, -EINVAL if the host does not support the + * requested block size, or -EIO (etc.) if one of the resultant FBR block + * size register writes failed. + * + */ +int sdio_set_block_size(struct sdio_func *func, unsigned blksz) +{ + int ret; + + if (blksz > func->card->host->max_blk_size) + return -EINVAL; + + if (blksz == 0) { + blksz = min(min( + func->max_blksize, + func->card->host->max_blk_size), + 512u); + } + + ret = mmc_io_rw_direct(func->card, 1, 0, + SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE, + blksz & 0xff, NULL); + if (ret) + return ret; + ret = mmc_io_rw_direct(func->card, 1, 0, + SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1, + (blksz >> 8) & 0xff, NULL); + if (ret) + return ret; + func->cur_blksize = blksz; + return 0; +} + +EXPORT_SYMBOL_GPL(sdio_set_block_size); + /** * sdio_readb - read a single byte from a SDIO function * @func: SDIO function to access diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index af813fffc4ac..f05757984e8d 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -43,7 +43,8 @@ struct sdio_func { unsigned short vendor; /* vendor id */ unsigned short device; /* device id */ - unsigned short blksize; /* maximum block size */ + unsigned max_blksize; /* maximum block size */ + unsigned cur_blksize; /* current block size */ unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ @@ -111,6 +112,8 @@ extern void sdio_release_host(struct sdio_func *func); extern int sdio_enable_func(struct sdio_func *func); extern int sdio_disable_func(struct sdio_func *func); +extern int sdio_set_block_size(struct sdio_func *func, unsigned blksz); + extern int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler); extern int sdio_release_irq(struct sdio_func *func); From eb6594689226663968ef0a9fd71ec5e1e4e04f9c Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 8 Aug 2007 14:24:21 +0100 Subject: [PATCH 0323/2804] sdio: extend sdio_readsb() and friends to handle any length of buffer Extend sdio_readsb(), sdio_writesb(), sdio_memcpy_fromio(), and sdio_memcpy_toio() to handle any length of buffer by splitting the transfer into several IO_RW_EXTENDED commands. Typically, a transfer would be split into a single block mode transfer followed by a byte mode transfer for the remainder but we also handle lack of block mode support and the block size being greater than 512 (the maximum byte mode transfer size). host->max_seg_size <= host->max_req_size so there's no need to check both when determining the maximum data size for a single command. Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_io.c | 93 +++++++++++++++++++++++++++++-------- drivers/mmc/core/sdio_ops.c | 19 +++++--- drivers/mmc/core/sdio_ops.h | 2 +- 3 files changed, 86 insertions(+), 28 deletions(-) diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index c2bad1195e3b..34b085d4024a 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -189,6 +189,67 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz) EXPORT_SYMBOL_GPL(sdio_set_block_size); +/* Split an arbitrarily sized data transfer into several + * IO_RW_EXTENDED commands. */ +static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, + unsigned addr, int incr_addr, u8 *buf, unsigned size) +{ + unsigned remainder = size; + unsigned max_blocks; + int ret; + + /* Do the bulk of the transfer using block mode (if supported). */ + if (func->card->cccr.multi_block) { + /* Blocks per command is limited by host count, host transfer + * size (we only use a single sg entry) and the maximum for + * IO_RW_EXTENDED of 511 blocks. */ + max_blocks = min(min( + func->card->host->max_blk_count, + func->card->host->max_seg_size / func->cur_blksize), + 511u); + + while (remainder > func->cur_blksize) { + unsigned blocks; + + blocks = remainder / func->cur_blksize; + if (blocks > max_blocks) + blocks = max_blocks; + size = blocks * func->cur_blksize; + + ret = mmc_io_rw_extended(func->card, write, + func->num, addr, incr_addr, buf, + blocks, func->cur_blksize); + if (ret) + return ret; + + remainder -= size; + buf += size; + if (incr_addr) + addr += size; + } + } + + /* Write the remainder using byte mode. */ + while (remainder > 0) { + size = remainder; + if (size > func->cur_blksize) + size = func->cur_blksize; + if (size > 512) + size = 512; /* maximum size for byte mode */ + + ret = mmc_io_rw_extended(func->card, write, func->num, addr, + incr_addr, buf, 1, size); + if (ret) + return ret; + + remainder -= size; + buf += size; + if (incr_addr) + addr += size; + } + return 0; +} + /** * sdio_readb - read a single byte from a SDIO function * @func: SDIO function to access @@ -252,15 +313,13 @@ EXPORT_SYMBOL_GPL(sdio_writeb); * @addr: address to begin reading from * @count: number of bytes to read * - * Reads up to 512 bytes from the address space of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Reads from the address space of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_memcpy_fromio(struct sdio_func *func, void *dst, unsigned int addr, int count) { - return mmc_io_rw_extended(func->card, 0, func->num, addr, 0, dst, - count); + return sdio_io_rw_ext_helper(func, 0, addr, 1, dst, count); } EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); @@ -271,15 +330,13 @@ EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); * @src: buffer that contains the data to write * @count: number of bytes to write * - * Writes up to 512 bytes to the address space of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Writes to the address space of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, void *src, int count) { - return mmc_io_rw_extended(func->card, 1, func->num, addr, 0, src, - count); + return sdio_io_rw_ext_helper(func, 1, addr, 1, src, count); } EXPORT_SYMBOL_GPL(sdio_memcpy_toio); @@ -290,15 +347,13 @@ EXPORT_SYMBOL_GPL(sdio_memcpy_toio); * @addr: address of (single byte) FIFO * @count: number of bytes to read * - * Reads up to 512 bytes from the specified FIFO of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Reads from the specified FIFO of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, int count) { - return mmc_io_rw_extended(func->card, 0, func->num, addr, 1, dst, - count); + return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count); } EXPORT_SYMBOL_GPL(sdio_readsb); @@ -310,15 +365,13 @@ EXPORT_SYMBOL_GPL(sdio_readsb); * @src: buffer that contains the data to write * @count: number of bytes to write * - * Writes up to 512 bytes to the specified FIFO of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Writes to the specified FIFO of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, int count) { - return mmc_io_rw_extended(func->card, 1, func->num, addr, 1, src, - count); + return sdio_io_rw_ext_helper(func, 1, addr, 0, src, count); } EXPORT_SYMBOL_GPL(sdio_writesb); diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 4f2c77139477..98e20532452a 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -88,7 +88,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, } int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, - unsigned addr, int bang, u8 *buf, unsigned size) + unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { struct mmc_request mrq; struct mmc_command cmd; @@ -97,7 +97,9 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, BUG_ON(!card); BUG_ON(fn > 7); - BUG_ON(size > 512); + BUG_ON(blocks == 1 && blksz > 512); + WARN_ON(blocks == 0); + WARN_ON(blksz == 0); memset(&mrq, 0, sizeof(struct mmc_request)); memset(&cmd, 0, sizeof(struct mmc_command)); @@ -109,18 +111,21 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.opcode = SD_IO_RW_EXTENDED; cmd.arg = write ? 0x80000000 : 0x00000000; cmd.arg |= fn << 28; - cmd.arg |= bang ? 0x00000000 : 0x04000000; + cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; cmd.arg |= addr << 9; - cmd.arg |= (size == 512) ? 0 : size; + if (blocks == 1 && blksz <= 512) + cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ + else + cmd.arg |= 0x08000000 | blocks; /* block mode */ cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; - data.blksz = size; - data.blocks = 1; + data.blksz = blksz; + data.blocks = blocks; data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, buf, size); + sg_init_one(&sg, buf, blksz * blocks); mmc_set_data_timeout(&data, card); diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index 1d42e4f366aa..e2e74b0d17d8 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -16,7 +16,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out); int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, - unsigned addr, int bang, u8 *data, unsigned size); + unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); #endif From 9f2fcf99394b34769e3243a7f42a0ba8d21fc774 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 1 Aug 2007 00:05:24 +0200 Subject: [PATCH 0324/2804] sdio: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index fcb13fb0daad..683d91740109 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -221,12 +221,10 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) { struct sdio_func *func; - func = kmalloc(sizeof(struct sdio_func), GFP_KERNEL); + func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL); if (!func) return ERR_PTR(-ENOMEM); - memset(func, 0, sizeof(struct sdio_func)); - func->card = card; device_initialize(&func->dev); From d84075c8aed771d47d7ac6e96b098559da361c25 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 9 Aug 2007 13:23:56 +0200 Subject: [PATCH 0325/2804] mmc: replace BUG_ON with WARN_ON Replace all cases of BUG_ON with WARN_ON where there is a chance (with varying degrees of slim) that the kernel can continue without incidence. Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 12 ++++++------ drivers/mmc/core/mmc.c | 4 ++-- drivers/mmc/core/sd.c | 6 ++---- drivers/mmc/core/sdio.c | 2 +- drivers/mmc/core/sdio_irq.c | 4 ++-- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9d29bed820a1..3bebd3b55dc5 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -202,7 +202,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries { struct mmc_request mrq; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); memset(&mrq, 0, sizeof(struct mmc_request)); @@ -333,7 +333,7 @@ void mmc_release_host(struct mmc_host *host) { unsigned long flags; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); spin_lock_irqsave(&host->lock, flags); host->claimed = 0; @@ -531,7 +531,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) BUG_ON(!host); BUG_ON(!ops); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); spin_lock_irqsave(&host->lock, flags); @@ -555,8 +555,8 @@ void mmc_detach_bus(struct mmc_host *host) BUG_ON(!host); - BUG_ON(!host->claimed); - BUG_ON(!host->bus_ops); + WARN_ON(!host->claimed); + WARN_ON(!host->bus_ops); spin_lock_irqsave(&host->lock, flags); @@ -584,7 +584,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) #ifdef CONFIG_MMC_DEBUG unsigned long flags; spin_lock_irqsave(&host->lock, flags); - BUG_ON(host->removed); + WARN_ON(host->removed); spin_unlock_irqrestore(&host->lock, flags); #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index ba7a847cfd08..6ba458951d24 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -264,7 +264,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, unsigned int max_dtr; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); /* * Since we're changing the OCR value, we seem to @@ -558,7 +558,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) int err; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); mmc_attach_bus(host, &mmc_ops); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 0a04a6e86ca1..c86588fdaae5 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -166,8 +166,6 @@ static int mmc_decode_scr(struct mmc_card *card) unsigned int scr_struct; u32 resp[4]; - BUG_ON(!mmc_card_sd(card)); - resp[3] = card->raw_scr[1]; resp[2] = card->raw_scr[0]; @@ -300,7 +298,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, unsigned int max_dtr; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); /* * Since we're changing the OCR value, we seem to @@ -620,7 +618,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) int err; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); mmc_attach_bus(host, &mmc_sd_ops); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 58cf36e44678..2f3fb994c383 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -230,7 +230,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) struct mmc_card *card; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); mmc_attach_bus(host, &mmc_sdio_ops); diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 01daee934d16..8843a4c2fe91 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -125,7 +125,7 @@ static int sdio_card_irq_get(struct mmc_card *card) { struct mmc_host *host = card->host; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); if (!host->sdio_irqs++) { atomic_set(&host->sdio_irq_thread_abort, 0); @@ -145,7 +145,7 @@ static int sdio_card_irq_put(struct mmc_card *card) { struct mmc_host *host = card->host; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); BUG_ON(host->sdio_irqs < 1); if (!--host->sdio_irqs) { From 7806cdb40fd562e5dcc07321579b62a5dc7cd95c Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Fri, 10 Aug 2007 13:29:46 +0100 Subject: [PATCH 0326/2804] sdio: add sdio_f0_readb() and sdio_f0_writeb() Add sdio_f0_readb() and sdio_f0_writeb() functions to reading and writing function 0 registers. Writes outside the vendor specific CCCR registers (0xF0 - 0xFF) are not permitted. Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_io.c | 64 +++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 5 +++ 2 files changed, 69 insertions(+) diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 34b085d4024a..625b92ce9cef 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -482,3 +482,67 @@ void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr, } EXPORT_SYMBOL_GPL(sdio_writel); +/** + * sdio_f0_readb - read a single byte from SDIO function 0 + * @func: an SDIO function of the card + * @addr: address to read + * @err_ret: optional status value from transfer + * + * Reads a single byte from the address space of SDIO function 0. + * If there is a problem reading the address, 0xff is returned + * and @err_ret will contain the error code. + */ +unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr, + int *err_ret) +{ + int ret; + unsigned char val; + + BUG_ON(!func); + + if (err_ret) + *err_ret = 0; + + ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFF; + } + + return val; +} +EXPORT_SYMBOL_GPL(sdio_f0_readb); + +/** + * sdio_f0_writeb - write a single byte to SDIO function 0 + * @func: an SDIO function of the card + * @b: byte to write + * @addr: address to write to + * @err_ret: optional status value from transfer + * + * Writes a single byte to the address space of SDIO function 0. + * @err_ret will contain the status of the actual transfer. + * + * Only writes to the vendor specific CCCR registers (0xF0 - + * 0xFF) are permiited; @err_ret will be set to -EINVAL for * + * writes outside this range. + */ +void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, + int *err_ret) +{ + int ret; + + BUG_ON(!func); + + if (addr < 0xF0 || addr > 0xFF) { + if (err_ret) + *err_ret = -EINVAL; + return; + } + + ret = mmc_io_rw_direct(func->card, 1, 0, addr, b, NULL); + if (err_ret) + *err_ret = ret; +} +EXPORT_SYMBOL_GPL(sdio_f0_writeb); diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index f05757984e8d..da6a96c39776 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -141,5 +141,10 @@ extern int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, extern int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, int count); +extern unsigned char sdio_f0_readb(struct sdio_func *func, + unsigned int addr, int *err_ret); +extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b, + unsigned int addr, int *err_ret); + #endif From 2ba30eedec37e2f65babf4ea54233f98afbe0871 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 15 Aug 2007 13:27:29 -0400 Subject: [PATCH 0327/2804] sdio: add default c_ispeed/c_ospeed values to sdio_uart driver Note that the default baudrate is 4800 instead of 9600 as a convenience because that's what GPS devices want which is still the main use for this driver. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/card/sdio_uart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 190120d1449a..606100212afa 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -1106,6 +1106,8 @@ static int __init sdio_uart_init(void) tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_drv->init_termios = tty_std_termios; tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; + tty_drv->init_termios.c_ispeed = 4800; + tty_drv->init_termios.c_ospeed = 4800; tty_set_operations(tty_drv, &sdio_uart_ops); ret = tty_register_driver(tty_drv); From 15b82b46de358a574c2a6a6dea4c8076bef7ac43 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 20 Aug 2007 17:17:37 -0400 Subject: [PATCH 0328/2804] sdio: fix recursion issues between sdio-uart driver and tty layer In a few places, sdio_uart_irq() is called directly instead of waiting for the actual interrupt to be raised and the SDIO IRQ thread scheduled in order to reduce latency. However, some interaction with the tty core may end up calling us back (serial echo, flow control, etc.) creating two issues: - the host lock gets claimed twice from the same thread causing a deadlock; - the same direct calls to sdio_uart_irq() may be performed causing unexpected reentrancy into the IRQ handler. This patch handles both of those issues. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/card/sdio_uart.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 606100212afa..d552de683110 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -79,6 +79,7 @@ struct sdio_uart_port { struct mutex open_lock; struct sdio_func *func; struct mutex func_lock; + struct task_struct *in_sdio_uart_irq; unsigned int regs_offset; struct circ_buf xmit; spinlock_t write_lock; @@ -186,14 +187,16 @@ static int sdio_uart_claim_func(struct sdio_uart_port *port) mutex_unlock(&port->func_lock); return -ENODEV; } - sdio_claim_host(port->func); + if (likely(port->in_sdio_uart_irq != current)) + sdio_claim_host(port->func); mutex_unlock(&port->func_lock); return 0; } static inline void sdio_uart_release_func(struct sdio_uart_port *port) { - sdio_release_host(port->func); + if (likely(port->in_sdio_uart_irq != current)) + sdio_release_host(port->func); } static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset) @@ -511,15 +514,29 @@ static void sdio_uart_irq(struct sdio_func *func) struct sdio_uart_port *port = sdio_get_drvdata(func); unsigned int iir, lsr; + /* + * In a few places sdio_uart_irq() is called directly instead of + * waiting for the actual interrupt to be raised and the SDIO IRQ + * thread scheduled in order to reduce latency. However, some + * interaction with the tty core may end up calling us back + * (serial echo, flow control, etc.) through those same places + * causing undesirable effects. Let's stop the recursion here. + */ + if (unlikely(port->in_sdio_uart_irq == current)) + return; + iir = sdio_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) return; + + port->in_sdio_uart_irq = current; lsr = sdio_in(port, UART_LSR); if (lsr & UART_LSR_DR) sdio_uart_receive_chars(port, &lsr); sdio_uart_check_modem_status(port); if (lsr & UART_LSR_THRE) sdio_uart_transmit_chars(port); + port->in_sdio_uart_irq = NULL; } static int sdio_uart_startup(struct sdio_uart_port *port) From f75979b77fb20b01522d8fab96dfc76cc9f42420 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 4 Sep 2007 07:59:18 +0200 Subject: [PATCH 0329/2804] sdhci: sdio interrupt support Add support for relaying the sdio interrupt signal from the card. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c63edc5c17e4..228ce42371dc 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -800,10 +800,35 @@ static int sdhci_get_ro(struct mmc_host *mmc) return !(present & SDHCI_WRITE_PROTECT); } +static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct sdhci_host *host; + unsigned long flags; + u32 ier; + + host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + + ier = readl(host->ioaddr + SDHCI_INT_ENABLE); + + ier &= ~SDHCI_INT_CARD_INT; + if (enable) + ier |= SDHCI_INT_CARD_INT; + + writel(ier, host->ioaddr + SDHCI_INT_ENABLE); + writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); + + mmiowb(); + + spin_unlock_irqrestore(&host->lock, flags); +} + static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, .get_ro = sdhci_get_ro, + .enable_sdio_irq = sdhci_enable_sdio_irq, }; /*****************************************************************************\ @@ -1012,6 +1037,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) irqreturn_t result; struct sdhci_host* host = dev_id; u32 intmask; + int cardint = 0; spin_lock(&host->lock); @@ -1056,6 +1082,11 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~SDHCI_INT_BUS_POWER; + if (intmask & SDHCI_INT_CARD_INT) + cardint = 1; + + intmask &= ~SDHCI_INT_CARD_INT; + if (intmask) { printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), intmask); @@ -1070,6 +1101,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) out: spin_unlock(&host->lock); + /* + * We have to delay this as it calls back into the driver. + */ + if (cardint) + mmc_signal_sdio_irq(host->mmc); + return result; } @@ -1309,7 +1346,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED; From f9996aee36921e8f1d499de1b2ea380855cf6d97 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Sep 2007 18:38:50 +0200 Subject: [PATCH 0330/2804] mmc: increase power up delay Increase delay for power up in order to support some slower boards. Also add some comments about why the delays are there. Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3bebd3b55dc5..bffcaf8df352 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -460,12 +460,20 @@ static void mmc_power_up(struct mmc_host *host) host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); - mmc_delay(1); + /* + * This delay should be sufficient to allow the power supply + * to reach the minimum voltage. + */ + mmc_delay(2); host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; mmc_set_ios(host); + /* + * This delay must be at least 74 clock sizes, or 1 ms, or the + * time required to reach a stable voltage. + */ mmc_delay(2); } From 759bdc7af450404382e937c76722ae8736daef92 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Sep 2007 18:42:16 +0200 Subject: [PATCH 0331/2804] sdio: store vendor strings Store vendor strings found in CISTPL_VERS_1 so that function drivers can access them. Signed-off-by: Pierre Ossman --- drivers/mmc/core/bus.c | 3 +++ drivers/mmc/core/sdio_bus.c | 3 +++ drivers/mmc/core/sdio_cis.c | 50 ++++++++++++++++++++++++++++++++++- include/linux/mmc/card.h | 2 ++ include/linux/mmc/sdio_func.h | 3 +++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 1cc11714916f..733ac95331c7 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -187,6 +187,9 @@ static void mmc_release_card(struct device *dev) sdio_free_common_cis(card); + if (card->info) + kfree(card->info); + kfree(card); } diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 683d91740109..0713a8c71e54 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -211,6 +211,9 @@ static void sdio_release_func(struct device *dev) sdio_free_func_cis(func); + if (func->info) + kfree(func->info); + kfree(func); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 1d03f12bbb38..d5e51b1c7b3f 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -23,6 +23,54 @@ #include "sdio_cis.h" #include "sdio_ops.h" +static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func, + const unsigned char *buf, unsigned size) +{ + unsigned i, nr_strings; + char **buffer, *string; + + buf += 2; + size -= 2; + + nr_strings = 0; + for (i = 0; i < size; i++) { + if (buf[i] == 0xff) + break; + if (buf[i] == 0) + nr_strings++; + } + + if (buf[i-1] != '\0') { + printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n"); + return 0; + } + + size = i; + + buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + string = (char*)(buffer + nr_strings); + + for (i = 0; i < nr_strings; i++) { + buffer[i] = string; + strcpy(string, buf); + string += strlen(string) + 1; + buf += strlen(buf) + 1; + } + + if (func) { + func->num_info = nr_strings; + func->info = (const char**)buffer; + } else { + card->num_info = nr_strings; + card->info = (const char**)buffer; + } + + return 0; +} + static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func, const unsigned char *buf, unsigned size) { @@ -119,7 +167,7 @@ struct cis_tpl { }; static const struct cis_tpl cis_tpl_list[] = { - { 0x15, 3, /* cistpl_vers_1 */ }, + { 0x15, 3, cistpl_vers_1 }, { 0x20, 4, cistpl_manfid }, { 0x21, 2, /* cistpl_funcid */ }, { 0x22, 0, cistpl_funce }, diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index a444431e28bd..0d508ac17d64 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -108,6 +108,8 @@ struct mmc_card { struct sdio_cccr cccr; /* common card info */ struct sdio_cis cis; /* common tuple info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ + unsigned num_info; /* number of info strings */ + const char **info; /* info strings */ struct sdio_func_tuple *tuples; /* unknown common tuples */ }; diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index da6a96c39776..b050f4d7b41f 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -51,6 +51,9 @@ struct sdio_func { u8 tmpbuf[4]; /* DMA:able scratch buffer */ + unsigned num_info; /* number of info strings */ + const char **info; /* info strings */ + struct sdio_func_tuple *tuples; }; From 97018580c40c8a31dd7ae744da3378c787a2066d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 8 Aug 2007 09:09:01 -0700 Subject: [PATCH 0332/2804] MMC headers learn about SPI Teach the MMC/SD/SDIO system headers that some hosts use SPI mode - New host capabilities and status bits * MMC_CAP_SPI, with mmc_host_is_spi() test * mmc_host.use_spi_crc flag - SPI-specific declarations: * Response types, MMC_RSP_SPI_R* * Two SPI-only commands * Status bits used native to SPI: R1_SPI_*, R2_SPI_* - Fix a few (unrelated) whitespace bugs in the headers. - Reorder a few mmc_host fields, removing several bytes of padding None of these changes affect current code. Signed-off-by: David Brownell Signed-off-by: Pierre Ossman --- include/linux/mmc/core.h | 26 ++++++++++++++++++++++++-- include/linux/mmc/host.h | 16 +++++++++++----- include/linux/mmc/mmc.h | 38 ++++++++++++++++++++++++++++++++------ 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 8945da9b54fa..d0c3abed74c2 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -25,14 +25,20 @@ struct mmc_command { #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ #define MMC_RSP_BUSY (1 << 3) /* card may send busy */ #define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ -#define MMC_CMD_MASK (3 << 5) /* command type */ + +#define MMC_CMD_MASK (3 << 5) /* non-SPI command type */ #define MMC_CMD_AC (0 << 5) #define MMC_CMD_ADTC (1 << 5) #define MMC_CMD_BC (2 << 5) #define MMC_CMD_BCR (3 << 5) +#define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ +#define MMC_RSP_SPI_S2 (1 << 8) /* second byte */ +#define MMC_RSP_SPI_B4 (1 << 9) /* four data bytes */ +#define MMC_RSP_SPI_BUSY (1 << 10) /* card may send busy */ + /* - * These are the response types, and correspond to valid bit + * These are the native response types, and correspond to valid bit * patterns of the above flags. One additional valid pattern * is all zeros, which means we don't expect a response. */ @@ -48,6 +54,22 @@ struct mmc_command { #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) +/* + * These are the SPI response types for MMC, SD, and SDIO cards. + * Commands return R1, with maybe more info. Zero is an error type; + * callers must always provide the appropriate MMC_RSP_SPI_Rx flags. + */ +#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) +#define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY) +#define MMC_RSP_SPI_R2 (MMC_RSP_SPI_S1|MMC_RSP_SPI_S2) +#define MMC_RSP_SPI_R3 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) +#define MMC_RSP_SPI_R4 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) +#define MMC_RSP_SPI_R5 (MMC_RSP_SPI_S1|MMC_RSP_SPI_S2) +#define MMC_RSP_SPI_R7 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) + +#define mmc_spi_resp_type(cmd) ((cmd)->flags & \ + (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY|MMC_RSP_SPI_S2|MMC_RSP_SPI_B4)) + /* * These are the command types. */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 3fd197962f73..76eef94782f8 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -91,6 +91,7 @@ struct mmc_host { #define MMC_CAP_MMC_HIGHSPEED (1 << 2) /* Can do MMC high-speed timing */ #define MMC_CAP_SD_HIGHSPEED (1 << 3) /* Can do SD high-speed timing */ #define MMC_CAP_SDIO_IRQ (1 << 4) /* Can signal pending SDIO IRQs */ +#define MMC_CAP_SPI (1 << 5) /* Talks only SPI protocols */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ @@ -107,6 +108,14 @@ struct mmc_host { struct mmc_ios ios; /* current io bus settings */ u32 ocr; /* the current OCR setting */ + /* group bitfields together to minimize padding */ + unsigned int use_spi_crc:1; + unsigned int claimed:1; /* host exclusively claimed */ + unsigned int bus_dead:1; /* bus has been released */ +#ifdef CONFIG_MMC_DEBUG + unsigned int removed:1; /* host is being removed */ +#endif + unsigned int mode; /* current card mode of host */ #define MMC_MODE_MMC 0 #define MMC_MODE_SD 1 @@ -114,16 +123,11 @@ struct mmc_host { struct mmc_card *card; /* device attached to this host */ wait_queue_head_t wq; - unsigned int claimed:1; /* host exclusively claimed */ struct delayed_work detect; -#ifdef CONFIG_MMC_DEBUG - unsigned int removed:1; /* host is being removed */ -#endif const struct mmc_bus_ops *bus_ops; /* current bus driver */ unsigned int bus_refs; /* reference counter */ - unsigned int bus_dead:1; /* bus has been released */ unsigned int sdio_irqs; struct task_struct *sdio_irq_thread; @@ -142,6 +146,8 @@ static inline void *mmc_priv(struct mmc_host *host) return (void *)host->private; } +#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI) + #define mmc_dev(x) ((x)->parent) #define mmc_classdev(x) (&(x)->class_dev) #define mmc_hostname(x) ((x)->class_dev.bus_id) diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index d1d6cbcc1514..4236fbf0b6fb 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -27,7 +27,7 @@ /* Standard MMC commands (4.1) type argument response */ /* class 1 */ -#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ @@ -39,8 +39,10 @@ #define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ #define MMC_STOP_TRANSMISSION 12 /* ac R1b */ -#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ #define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ +#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ /* class 2 */ #define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ @@ -90,15 +92,15 @@ */ /* - MMC status in R1 + MMC status in R1, for native mode (SPI bits are different) Type - e : error bit + e : error bit s : status bit r : detected and set for the actual command response x : detected and set during command execution. the host must poll the card by sending status command in order to read these bits. Clear condition - a : according to the card state + a : according to the card state b : always related to the previous command. Reception of a valid command will clear it (with a delay of one command) c : clear by read @@ -124,10 +126,33 @@ #define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ #define R1_ERASE_RESET (1 << 13) /* sr, c */ #define R1_STATUS(x) (x & 0xFFFFE000) -#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ #define R1_APP_CMD (1 << 5) /* sr, c */ +/* + * MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS + * R1 is the low order byte; R2 is the next highest byte, when present. + */ +#define R1_SPI_IDLE (1 << 0) +#define R1_SPI_ERASE_RESET (1 << 1) +#define R1_SPI_ILLEGAL_COMMAND (1 << 2) +#define R1_SPI_COM_CRC (1 << 3) +#define R1_SPI_ERASE_SEQ (1 << 4) +#define R1_SPI_ADDRESS (1 << 5) +#define R1_SPI_PARAMETER (1 << 6) +/* R1 bit 7 is always zero */ +#define R2_SPI_CARD_LOCKED (1 << 8) +#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */ +#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP +#define R2_SPI_ERROR (1 << 10) +#define R2_SPI_CC_ERROR (1 << 11) +#define R2_SPI_CARD_ECC_ERROR (1 << 12) +#define R2_SPI_WP_VIOLATION (1 << 13) +#define R2_SPI_ERASE_PARAM (1 << 14) +#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */ +#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE + /* These are unpacked versions of the actual responses */ struct _mmc_csd { @@ -182,6 +207,7 @@ struct _mmc_csd { */ #define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ /* (CMD0,1,2,3,4,7,9,10,12,13,15) */ + /* (and for SPI, CMD58,59) */ #define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */ /* (CMD11) */ #define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */ From 7213d175e3b6f6db60f843b72e88857a350e146a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 8 Aug 2007 09:10:23 -0700 Subject: [PATCH 0333/2804] MMC/SD card driver learns SPI Teaching the MMC/SD block card driver about SPI. - Provide the SPI response type flags with each request issued. - Understand that multiblock SPI writes don't use STOP_TRANSMISSION. - Correct check for APP_CMD failure. Signed-off-by: David Brownell Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index ab510689ecde..e38d5a3b2a89 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -151,17 +151,19 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) cmd.opcode = MMC_APP_CMD; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); - if (err || !(cmd.resp[0] & R1_APP_CMD)) + if (err) + return (u32)-1; + if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD)) return (u32)-1; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = SD_APP_SEND_NUM_WR_BLKS; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; memset(&data, 0, sizeof(struct mmc_data)); @@ -220,11 +222,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.cmd.arg = req->sector; if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; - brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.blksz = 1 << md->block_bits; brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; - brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); if (brq.data.blocks > card->host->max_blk_count) brq.data.blocks = card->host->max_blk_count; @@ -241,7 +243,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.data.blocks = 1; if (brq.data.blocks > 1) { - brq.mrq.stop = &brq.stop; + /* SPI multiblock writes terminate using a special + * token, not a STOP_TRANSMISSION request. + */ + if (!mmc_host_is_spi(card->host) + || rq_data_dir(req) == READ) + brq.mrq.stop = &brq.stop; readcmd = MMC_READ_MULTIPLE_BLOCK; writecmd = MMC_WRITE_MULTIPLE_BLOCK; } else { @@ -301,7 +308,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) goto cmd_err; } - if (rq_data_dir(req) != READ) { + if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { do { int err; @@ -509,7 +516,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) mmc_claim_host(card->host); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); mmc_release_host(card->host); From af51715079e7fb6b290e1881d63d815dc4de5011 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 8 Aug 2007 09:11:32 -0700 Subject: [PATCH 0334/2804] MMC core learns about SPI Teach the MMC/SD/SDIO core about using SPI mode. - Use mmc_host_is_spi() so enumeration works through SPI signaling and protocols, not just the native versions. - Provide the SPI response type flags with each request issued, including requests from the new lock/unlock code. - Understand that cmd->resp[0] and mmc_get_status() results for SPI return different values than for "native" MMC/SD protocol; this affects resetting, checking card lock status, and some others. - Understand that some commands act a bit differently ... notably: * OP_COND command doesn't return the OCR * APP_CMD status doesn't have an R1_APP_CMD analogue Those changes required some new and updated primitives: - Provide utilities to access two SPI-only requests, and one request that wasn't previously needed: * mmc_spi_read_ocr() ... SPI only * mmc_spi_set_crc() ... SPI only (override by module parm) * mmc_send_cid() ... for use without broadcast mode - Updated internal routines: * Previous mmc_send_csd() modified into mmc_send_cxd_native(); it uses native "R2" responses, which include 16 bytes of data. * Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data() helper for command-and-data access * Bugfix to that mmc_send_cxd_data() code: dma-to-stack is unsafe/nonportable, so kmalloc a bounce buffer instead. - Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper - Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use those helper routines based on whether they're native or SPI The newest categories of cards supported by the MMC stack aren't expected to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO. All those cards support SPI mode, so eventually they should work too. Signed-off-by: David Brownell Signed-off-by: Pierre Ossman --- drivers/mmc/core/bus.c | 24 ++++-- drivers/mmc/core/core.c | 28 +++++- drivers/mmc/core/core.h | 2 + drivers/mmc/core/mmc.c | 50 ++++++++--- drivers/mmc/core/mmc_ops.c | 166 +++++++++++++++++++++++++++++------- drivers/mmc/core/mmc_ops.h | 3 + drivers/mmc/core/sd.c | 48 ++++++++--- drivers/mmc/core/sd_ops.c | 59 ++++++++++--- drivers/mmc/core/sdio.c | 29 +++++-- drivers/mmc/core/sdio_ops.c | 66 +++++++++----- 10 files changed, 372 insertions(+), 103 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 733ac95331c7..8d6f6014870f 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -243,10 +243,17 @@ int mmc_add_card(struct mmc_card *card) break; } - printk(KERN_INFO "%s: new %s%s card at address %04x\n", - mmc_hostname(card->host), - mmc_card_highspeed(card) ? "high speed " : "", - type, card->rca); + if (mmc_host_is_spi(card->host)) { + printk(KERN_INFO "%s: new %s%s card on SPI\n", + mmc_hostname(card->host), + mmc_card_highspeed(card) ? "high speed " : "", + type); + } else { + printk(KERN_INFO "%s: new %s%s card at address %04x\n", + mmc_hostname(card->host), + mmc_card_highspeed(card) ? "high speed " : "", + type, card->rca); + } card->dev.uevent_suppress = 1; @@ -278,8 +285,13 @@ int mmc_add_card(struct mmc_card *card) void mmc_remove_card(struct mmc_card *card) { if (mmc_card_present(card)) { - printk(KERN_INFO "%s: card %04x removed\n", - mmc_hostname(card->host), card->rca); + if (mmc_host_is_spi(card->host)) { + printk(KERN_INFO "%s: SPI card removed\n", + mmc_hostname(card->host)); + } else { + printk(KERN_INFO "%s: card %04x removed\n", + mmc_hostname(card->host), card->rca); + } if (card->host->bus_ops->sysfs_remove) card->host->bus_ops->sysfs_remove(card->host, card); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bffcaf8df352..bad39442f8fe 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -41,6 +41,14 @@ extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); static struct workqueue_struct *workqueue; +/* + * Enabling software CRCs on the data blocks can be a significant (30%) + * performance cost, and for other reasons may not always be desired. + * So we allow it it to be disabled. + */ +int use_spi_crc = 1; +module_param(use_spi_crc, bool, 0); + /* * Internal function. Schedule delayed work in the MMC work queue. */ @@ -71,6 +79,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) struct mmc_command *cmd = mrq->cmd; int err = cmd->error; + if (err && cmd->retries && mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + cmd->retries = 0; + } + if (err && cmd->retries) { pr_debug("%s: req failed (CMD%u): %d, retrying...\n", mmc_hostname(host), cmd->opcode, err); @@ -453,8 +466,13 @@ static void mmc_power_up(struct mmc_host *host) int bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (mmc_host_is_spi(host)) { + host->ios.chip_select = MMC_CS_HIGH; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + } else { + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + } host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -481,8 +499,10 @@ static void mmc_power_off(struct mmc_host *host) { host->ios.clock = 0; host->ios.vdd = 0; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (!mmc_host_is_spi(host)) { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.chip_select = MMC_CS_DONTCARE; + } host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index bb2774af9ea9..39daf2fb5dc4 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -48,5 +48,7 @@ void mmc_rescan(struct work_struct *work); void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); +extern int use_spi_crc; + #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6ba458951d24..65fe28860f54 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -165,8 +165,6 @@ static int mmc_read_ext_csd(struct mmc_card *card) BUG_ON(!card); - err = -EIO; - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) return 0; @@ -279,10 +277,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (err) goto err; + /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); if (err) goto err; @@ -309,13 +319,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } /* - * Set card RCA. + * For native busses: set card RCA and quit open drain mode. */ - err = mmc_set_relative_addr(card); - if (err) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_set_relative_addr(card); + if (err) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -336,13 +348,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto free_card; + } if (!oldcard) { /* - * Fetch and process extened CSD. + * Fetch and process extended CSD. */ err = mmc_read_ext_csd(card); if (err) @@ -502,7 +516,8 @@ static void mmc_suspend(struct mmc_host *host) BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } @@ -562,6 +577,15 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) mmc_attach_bus(host, &mmc_ops); + /* + * We need to get OCR a different way for SPI. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_read_ocr(host, 1, &ocr); + if (err) + goto err; + } + /* * Sanity check the voltages that the card claims to * support. diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 39567f91a4b8..bf4bc6adcfef 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -63,23 +63,36 @@ int mmc_go_idle(struct mmc_host *host) int err; struct mmc_command cmd; - mmc_set_chip_select(host, MMC_CS_HIGH); - - mmc_delay(1); + /* + * Non-SPI hosts need to prevent chipselect going active during + * GO_IDLE; that would put chips into SPI mode. Remind them of + * that in case of hardware that won't pull up DAT3/nCS otherwise. + * + * SPI hosts ignore ios.chip_select; it's managed according to + * rules that must accomodate non-MMC slaves which this layer + * won't even know about. + */ + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_HIGH); + mmc_delay(1); + } memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; - cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; err = mmc_wait_for_cmd(host, &cmd, 0); mmc_delay(1); - mmc_set_chip_select(host, MMC_CS_DONTCARE); + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_DONTCARE); + mmc_delay(1); + } - mmc_delay(1); + host->use_spi_crc = 0; return err; } @@ -94,23 +107,33 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_OP_COND; - cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, 0); if (err) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + /* if we're just probing, do a single pass */ + if (ocr == 0) break; + /* otherwise wait until reset completes */ + if (mmc_host_is_spi(host)) { + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else { + if (cmd.resp[0] & MMC_CARD_BUSY) + break; + } + err = -ETIMEDOUT; mmc_delay(10); } - if (rocr) + if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; return err; @@ -160,40 +183,46 @@ int mmc_set_relative_addr(struct mmc_card *card) return 0; } -int mmc_send_csd(struct mmc_card *card, u32 *csd) +static int +mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) { int err; struct mmc_command cmd; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!csd); + BUG_ON(!host); + BUG_ON(!cxd); memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SEND_CSD; - cmd.arg = card->rca << 16; + cmd.opcode = opcode; + cmd.arg = arg; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err) return err; - memcpy(csd, cmd.resp, sizeof(u32) * 4); + memcpy(cxd, cmd.resp, sizeof(u32) * 4); return 0; } -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +static int +mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, + u32 opcode, void *buf, unsigned len) { struct mmc_request mrq; struct mmc_command cmd; struct mmc_data data; struct scatterlist sg; + void *data_buf; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!ext_csd); + /* dma onto stack is unsafe/nonportable, but callers to this + * routine normally provide temporary on-stack buffers ... + */ + data_buf = kmalloc(len, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; memset(&mrq, 0, sizeof(struct mmc_request)); memset(&cmd, 0, sizeof(struct mmc_command)); @@ -202,21 +231,31 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) mrq.cmd = &cmd; mrq.data = &data; - cmd.opcode = MMC_SEND_EXT_CSD; + cmd.opcode = opcode; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - data.blksz = 512; + /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we + * rely on callers to never use this with "native" calls for reading + * CSD or CID. Native versions of those commands use the R2 type, + * not R1 plus a data block. + */ + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = len; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, ext_csd, 512); + sg_init_one(&sg, data_buf, len); - mmc_set_data_timeout(&data, card); + if (card) + mmc_set_data_timeout(&data, card); - mmc_wait_for_req(card->host, &mrq); + mmc_wait_for_req(host, &mrq); + + memcpy(buf, data_buf, len); + kfree(data_buf); if (cmd.error) return cmd.error; @@ -226,6 +265,67 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) return 0; } +int mmc_send_csd(struct mmc_card *card, u32 *csd) +{ + if (!mmc_host_is_spi(card->host)) + return mmc_send_cxd_native(card->host, card->rca << 16, + csd, MMC_SEND_CSD); + + return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16); +} + +int mmc_send_cid(struct mmc_host *host, u32 *cid) +{ + if (!mmc_host_is_spi(host)) { + if (!host->card) + return -EINVAL; + return mmc_send_cxd_native(host, host->card->rca << 16, + cid, MMC_SEND_CID); + } + + return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16); +} + +int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +{ + return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, + ext_csd, 512); +} + +int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_READ_OCR; + cmd.arg = highcap ? (1 << 30) : 0; + cmd.flags = MMC_RSP_SPI_R3; + + err = mmc_wait_for_cmd(host, &cmd, 0); + + *ocrp = cmd.resp[1]; + return err; +} + +int mmc_spi_set_crc(struct mmc_host *host, int use_crc) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_CRC_ON_OFF; + cmd.flags = MMC_RSP_SPI_R1; + cmd.arg = use_crc; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (!err) + host->use_spi_crc = use_crc; + return err; +} + int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) { int err; @@ -241,7 +341,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) (index << 16) | (value << 8) | set; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) @@ -261,13 +361,17 @@ int mmc_send_status(struct mmc_card *card, u32 *status) memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + if (!mmc_host_is_spi(card->host)) + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; + /* NOTE: callers are required to understand the difference + * between "native" and SPI format status words! + */ if (status) *status = cmd.resp[0]; diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 76d09a93c5d6..17854bf7cf0d 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -22,6 +22,9 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd); int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); int mmc_send_status(struct mmc_card *card, u32 *status); +int mmc_send_cid(struct mmc_host *host, u32 *cid); +int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); +int mmc_spi_set_crc(struct mmc_host *host, int use_crc); #endif diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index c86588fdaae5..d1c1e0f592f1 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -322,10 +322,22 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if (err) goto err; + /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); if (err) goto err; @@ -351,13 +363,15 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, } /* - * Set card RCA. + * For native busses: get card RCA and quit open drain mode. */ - err = mmc_send_relative_addr(host, &card->rca); - if (err) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -377,9 +391,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto free_card; + } if (!oldcard) { /* @@ -562,7 +578,8 @@ static void mmc_sd_suspend(struct mmc_host *host) BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } @@ -622,6 +639,17 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) mmc_attach_bus(host, &mmc_sd_ops); + /* + * We need to get OCR a different way for SPI. + */ + if (mmc_host_is_spi(host)) { + mmc_go_idle(host); + + err = mmc_spi_read_ocr(host, 0, &ocr); + if (err) + goto err; + } + /* * Sanity check the voltages that the card claims to * support. diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 491e0306b1b4..ee4029a24efd 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -33,10 +33,10 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) if (card) { cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; } else { cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; } err = mmc_wait_for_cmd(host, &cmd, 0); @@ -44,7 +44,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) return err; /* Check that card supported application commands */ - if (!(cmd.resp[0] & R1_APP_CMD)) + if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) return -EOPNOTSUPP; return 0; @@ -83,8 +83,14 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, memset(&mrq, 0, sizeof(struct mmc_request)); err = mmc_app_cmd(host, card); - if (err) + if (err) { + /* no point in retrying; no APP commands allowed */ + if (mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + break; + } continue; + } memset(&mrq, 0, sizeof(struct mmc_request)); @@ -99,6 +105,12 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, err = cmd->error; if (!cmd->error) break; + + /* no point in retrying illegal APP commands */ + if (mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + break; + } } return err; @@ -147,23 +159,36 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = SD_APP_OP_COND; - cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + if (mmc_host_is_spi(host)) + cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */ + else + cmd.arg = ocr; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); if (err) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + /* if we're just probing, do a single pass */ + if (ocr == 0) break; + /* otherwise wait until reset completes */ + if (mmc_host_is_spi(host)) { + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else { + if (cmd.resp[0] & MMC_CARD_BUSY) + break; + } + err = -ETIMEDOUT; mmc_delay(10); } - if (rocr) + if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; return err; @@ -174,6 +199,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) struct mmc_command cmd; int err; static const u8 test_pattern = 0xAA; + u8 result_pattern; /* * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND @@ -182,13 +208,18 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) */ cmd.opcode = SD_SEND_IF_COND; cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; - cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, 0); if (err) return err; - if ((cmd.resp[0] & 0xFF) != test_pattern) + if (mmc_host_is_spi(host)) + result_pattern = cmd.resp[1] & 0xFF; + else + result_pattern = cmd.resp[0] & 0xFF; + + if (result_pattern != test_pattern) return -EIO; return 0; @@ -229,6 +260,8 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) BUG_ON(!card->host); BUG_ON(!scr); + /* NOTE: caller guarantees scr is heap-allocated */ + err = mmc_app_cmd(card->host, card); if (err) return err; @@ -242,7 +275,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) cmd.opcode = SD_APP_SEND_SCR; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 8; data.blocks = 1; @@ -278,6 +311,8 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, BUG_ON(!card); BUG_ON(!card->host); + /* NOTE: caller guarantees resp is heap-allocated */ + mode = !!mode; value &= 0xF; @@ -292,7 +327,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, cmd.arg = mode << 31 | 0x00FFFFFF; cmd.arg &= ~(0xF << (group * 4)); cmd.arg |= value << (group * 4); - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 64; data.blocks = 1; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2f3fb994c383..87a50f456efc 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -269,6 +269,15 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto err; + /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + /* * The number of functions on the card is encoded inside * the ocr. @@ -290,20 +299,24 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) host->card = card; /* - * Set card RCA. + * For native busses: set card RCA and quit open drain mode. */ - err = mmc_send_relative_addr(host, &card->rca); - if (err) - goto remove; + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err) + goto remove; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err) - goto remove; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto remove; + } /* * Read the common registers. diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 98e20532452a..4d289b275031 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -30,23 +30,39 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) cmd.opcode = SD_IO_SEND_OP_COND; cmd.arg = ocr; - cmd.flags = MMC_RSP_R4 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + /* if we're just probing, do a single pass */ + if (ocr == 0) break; + /* otherwise wait until reset completes */ + if (mmc_host_is_spi(host)) { + /* + * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate + * an initialized card under SPI, but some cards + * (Marvell's) only behave when looking at this + * one. + */ + if (cmd.resp[1] & MMC_CARD_BUSY) + break; + } else { + if (cmd.resp[0] & MMC_CARD_BUSY) + break; + } + err = -ETIMEDOUT; mmc_delay(10); } if (rocr) - *rocr = cmd.resp[0]; + *rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0]; return err; } @@ -68,21 +84,29 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; cmd.arg |= addr << 9; cmd.arg |= in; - cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) return err; - if (cmd.resp[0] & R5_ERROR) - return -EIO; - if (cmd.resp[0] & R5_FUNCTION_NUMBER) - return -EINVAL; - if (cmd.resp[0] & R5_OUT_OF_RANGE) - return -ERANGE; + if (mmc_host_is_spi(card->host)) { + /* host driver already reported errors */ + } else { + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + } - if (out) - *out = cmd.resp[0] & 0xFF; + if (out) { + if (mmc_host_is_spi(card->host)) + *out = (cmd.resp[0] >> 8) & 0xFF; + else + *out = cmd.resp[0] & 0xFF; + } return 0; } @@ -117,7 +141,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ else cmd.arg |= 0x08000000 | blocks; /* block mode */ - cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; data.blksz = blksz; data.blocks = blocks; @@ -136,12 +160,16 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, if (data.error) return data.error; - if (cmd.resp[0] & R5_ERROR) - return -EIO; - if (cmd.resp[0] & R5_FUNCTION_NUMBER) - return -EINVAL; - if (cmd.resp[0] & R5_OUT_OF_RANGE) - return -ERANGE; + if (mmc_host_is_spi(card->host)) { + /* host driver already reported errors */ + } else { + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + } return 0; } From 15a0580ced081a0f7dc2deea8a4812bdc5e9a109 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 8 Aug 2007 09:12:54 -0700 Subject: [PATCH 0335/2804] mmc_spi host driver This is the latest version of the MMC-over-SPI support. It works on 2.6.23-rc2 plus git-mmc (from rc1-mm2), along with the preceding patches which teach the rest of the MMC stack about SPI. The main issue of note is that sometimes cards need to be power cycled to recover after certain faults. Also, it may sometimes be necessary to disable CRCs. ("modprobe mmc_core use_spi_crc=n") Signed-off-by: David Brownell Cc: mikael.starvik@axis.com, Cc: Hans-Peter Nilsson Cc: Jan Nikitenko Cc: Mike Lavender Signed-off-by: Pierre Ossman --- MAINTAINERS | 6 + drivers/mmc/host/Kconfig | 13 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/mmc_spi.c | 1408 +++++++++++++++++++++++++++++++++++ include/linux/spi/mmc_spi.h | 33 + 5 files changed, 1461 insertions(+) create mode 100644 drivers/mmc/host/mmc_spi.c create mode 100644 include/linux/spi/mmc_spi.h diff --git a/MAINTAINERS b/MAINTAINERS index c22d34b11f64..0df29ce05e5a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2567,6 +2567,12 @@ M: drzeus-mmc@drzeus.cx L: linux-kernel@vger.kernel.org S: Maintained +MULTIMEDIA CARD (MMC) ETC. OVER SPI +P: David Brownell +M: dbrownell@users.sourceforge.net +L: linux-kernel@vger.kernel.org +S: Odd fixes + MULTISOUND SOUND DRIVER P: Andrew Veliath M: andrewtv@usa.net diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index e23082fe88d0..68fb052afd3e 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -100,3 +100,16 @@ config MMC_TIFM_SD To compile this driver as a module, choose M here: the module will be called tifm_sd. +config MMC_SPI + tristate "MMC/SD over SPI (EXPERIMENTAL)" + depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL + select CRC7 + select CRC_ITU_T + help + Some systems accss MMC/SD cards using a SPI controller instead of + using a "native" MMC/SD controller. This has a disadvantage of + being relatively high overhead, but a compensating advantage of + working on many systems without dedicated MMC/SD controllers. + + If unsure, or if your system has no SPI master driver, say N. + diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 6685f64345b4..8dc82ce647b7 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -15,4 +15,5 @@ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_AT91) += at91_mci.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o +obj-$(CONFIG_MMC_SPI) += mmc_spi.o diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c new file mode 100644 index 000000000000..f30327bba6f6 --- /dev/null +++ b/drivers/mmc/host/mmc_spi.c @@ -0,0 +1,1408 @@ +/* + * mmc_spi.c - Access SD/MMC cards through SPI master controllers + * + * (C) Copyright 2005, Intec Automation, + * Mike Lavender (mike@steroidmicros) + * (C) Copyright 2006-2007, David Brownell + * (C) Copyright 2007, Axis Communications, + * Hans-Peter Nilsson (hp@axis.com) + * (C) Copyright 2007, ATRON electronic GmbH, + * Jan Nikitenko + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include + +#include +#include /* for R1_SPI_* bit values */ + +#include +#include + +#include + + +/* NOTES: + * + * - For now, we won't try to interoperate with a real mmc/sd/sdio + * controller, although some of them do have hardware support for + * SPI protocol. The main reason for such configs would be mmc-ish + * cards like DataFlash, which don't support that "native" protocol. + * + * We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to + * switch between driver stacks, and in any case if "native" mode + * is available, it will be faster and hence preferable. + * + * - MMC depends on a different chipselect management policy than the + * SPI interface currently supports for shared bus segments: it needs + * to issue multiple spi_message requests with the chipselect active, + * using the results of one message to decide the next one to issue. + * + * Pending updates to the programming interface, this driver expects + * that it not share the bus with other drivers (precluding conflicts). + * + * - We tell the controller to keep the chipselect active from the + * beginning of an mmc_host_ops.request until the end. So beware + * of SPI controller drivers that mis-handle the cs_change flag! + * + * However, many cards seem OK with chipselect flapping up/down + * during that time ... at least on unshared bus segments. + */ + + +/* + * Local protocol constants, internal to data block protocols. + */ + +/* Response tokens used to ack each block written: */ +#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f) +#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1) +#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1) +#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1) + +/* Read and write blocks start with these tokens and end with crc; + * on error, read tokens act like a subset of R2_SPI_* values. + */ +#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */ +#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */ +#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */ + +#define MMC_SPI_BLOCKSIZE 512 + + +/* These fixed timeouts come from the latest SD specs, which say to ignore + * the CSD values. The R1B value is for card erase (e.g. the "I forgot the + * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after + * reads which takes nowhere near that long. Older cards may be able to use + * shorter timeouts ... but why bother? + */ +#define readblock_timeout ktime_set(0, 100 * 1000 * 1000) +#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000) +#define r1b_timeout ktime_set(3, 0) + + +/****************************************************************************/ + +/* + * Local Data Structures + */ + +/* "scratch" is per-{command,block} data exchanged with the card */ +struct scratch { + u8 status[29]; + u8 data_token; + __be16 crc_val; +}; + +struct mmc_spi_host { + struct mmc_host *mmc; + struct spi_device *spi; + + unsigned char power_mode; + u16 powerup_msecs; + + struct mmc_spi_platform_data *pdata; + + /* for bulk data transfers */ + struct spi_transfer token, t, crc, early_status; + struct spi_message m; + + /* for status readback */ + struct spi_transfer status; + struct spi_message readback; + + /* underlying DMA-aware controller, or null */ + struct device *dma_dev; + + /* buffer used for commands and for message "overhead" */ + struct scratch *data; + dma_addr_t data_dma; + + /* Specs say to write ones most of the time, even when the card + * has no need to read its input data; and many cards won't care. + * This is our source of those ones. + */ + void *ones; + dma_addr_t ones_dma; +}; + + +/****************************************************************************/ + +/* + * MMC-over-SPI protocol glue, used by the MMC stack interface + */ + +static inline int mmc_cs_off(struct mmc_spi_host *host) +{ + /* chipselect will always be inactive after setup() */ + return spi_setup(host->spi); +} + +static int +mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) +{ + int status; + + if (len > sizeof(*host->data)) { + WARN_ON(1); + return -EIO; + } + + host->status.len = len; + + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_FROM_DEVICE); + + status = spi_sync(host->spi, &host->readback); + if (status == 0) + status = host->readback.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_FROM_DEVICE); + + return status; +} + +static int +mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) +{ + u8 *cp = host->data->status; + + timeout = ktime_add(timeout, ktime_get()); + + while (1) { + int status; + unsigned i; + + status = mmc_spi_readbytes(host, n); + if (status < 0) + return status; + + for (i = 0; i < n; i++) { + if (cp[i] != byte) + return cp[i]; + } + + /* REVISIT investigate msleep() to avoid busy-wait I/O + * in at least some cases. + */ + if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0) + break; + } + return -ETIMEDOUT; +} + +static inline int +mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout) +{ + return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0); +} + +static int mmc_spi_readtoken(struct mmc_spi_host *host) +{ + return mmc_spi_skip(host, readblock_timeout, 1, 0xff); +} + + +/* + * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol + * hosts return! The low byte holds R1_SPI bits. The next byte may hold + * R2_SPI bits ... for SEND_STATUS, or after data read errors. + * + * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on + * newer cards R7 (IF_COND). + */ + +static char *maptype(struct mmc_command *cmd) +{ + switch (mmc_spi_resp_type(cmd)) { + case MMC_RSP_SPI_R1: return "R1"; + case MMC_RSP_SPI_R1B: return "R1B"; + case MMC_RSP_SPI_R2: return "R2/R5"; + case MMC_RSP_SPI_R3: return "R3/R4/R7"; + default: return "?"; + } +} + +/* return zero, else negative errno after setting cmd->error */ +static int mmc_spi_response_get(struct mmc_spi_host *host, + struct mmc_command *cmd, int cs_on) +{ + u8 *cp = host->data->status; + u8 *end = cp + host->t.len; + int value = 0; + char tag[32]; + + snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s", + cmd->opcode, maptype(cmd)); + + /* Except for data block reads, the whole response will already + * be stored in the scratch buffer. It's somewhere after the + * command and the first byte we read after it. We ignore that + * first byte. After STOP_TRANSMISSION command it may include + * two data bits, but otherwise it's all ones. + */ + cp += 8; + while (cp < end && *cp == 0xff) + cp++; + + /* Data block reads (R1 response types) may need more data... */ + if (cp == end) { + unsigned i; + + cp = host->data->status; + + /* Card sends N(CR) (== 1..8) bytes of all-ones then one + * status byte ... and we already scanned 2 bytes. + * + * REVISIT block read paths use nasty byte-at-a-time I/O + * so it can always DMA directly into the target buffer. + * It'd probably be better to memcpy() the first chunk and + * avoid extra i/o calls... + */ + for (i = 2; i < 9; i++) { + value = mmc_spi_readbytes(host, 1); + if (value < 0) + goto done; + if (*cp != 0xff) + goto checkstatus; + } + value = -ETIMEDOUT; + goto done; + } + +checkstatus: + if (*cp & 0x80) { + dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n", + tag, *cp); + value = -EBADR; + goto done; + } + + cmd->resp[0] = *cp++; + cmd->error = 0; + + /* Status byte: the entire seven-bit R1 response. */ + if (cmd->resp[0] != 0) { + if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS + | R1_SPI_ILLEGAL_COMMAND) + & cmd->resp[0]) + value = -EINVAL; + else if (R1_SPI_COM_CRC & cmd->resp[0]) + value = -EILSEQ; + else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET) + & cmd->resp[0]) + value = -EIO; + /* else R1_SPI_IDLE, "it's resetting" */ + } + + switch (mmc_spi_resp_type(cmd)) { + + /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads) + * and less-common stuff like various erase operations. + */ + case MMC_RSP_SPI_R1B: + /* maybe we read all the busy tokens already */ + while (cp < end && *cp == 0) + cp++; + if (cp == end) + mmc_spi_wait_unbusy(host, r1b_timeout); + break; + + /* SPI R2 == R1 + second status byte; SEND_STATUS + * SPI R5 == R1 + data byte; IO_RW_DIRECT + */ + case MMC_RSP_SPI_R2: + cmd->resp[0] |= *cp << 8; + break; + + /* SPI R3, R4, or R7 == R1 + 4 bytes */ + case MMC_RSP_SPI_R3: + cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp)); + break; + + /* SPI R1 == just one status byte */ + case MMC_RSP_SPI_R1: + break; + + default: + dev_dbg(&host->spi->dev, "bad response type %04x\n", + mmc_spi_resp_type(cmd)); + if (value >= 0) + value = -EINVAL; + goto done; + } + + if (value < 0) + dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n", + tag, cmd->resp[0], cmd->resp[1]); + + /* disable chipselect on errors and some success cases */ + if (value >= 0 && cs_on) + return value; +done: + if (value < 0) + cmd->error = value; + mmc_cs_off(host); + return value; +} + +/* Issue command and read its response. + * Returns zero on success, negative for error. + * + * On error, caller must cope with mmc core retry mechanism. That + * means immediate low-level resubmit, which affects the bus lock... + */ +static int +mmc_spi_command_send(struct mmc_spi_host *host, + struct mmc_request *mrq, + struct mmc_command *cmd, int cs_on) +{ + struct scratch *data = host->data; + u8 *cp = data->status; + u32 arg = cmd->arg; + int status; + struct spi_transfer *t; + + /* We can handle most commands (except block reads) in one full + * duplex I/O operation before either starting the next transfer + * (data block or command) or else deselecting the card. + * + * First, write 7 bytes: + * - an all-ones byte to ensure the card is ready + * - opcode byte (plus start and transmission bits) + * - four bytes of big-endian argument + * - crc7 (plus end bit) ... always computed, it's cheap + * + * We init the whole buffer to all-ones, which is what we need + * to write while we're reading (later) response data. + */ + memset(cp++, 0xff, sizeof(data->status)); + + *cp++ = 0x40 | cmd->opcode; + *cp++ = (u8)(arg >> 24); + *cp++ = (u8)(arg >> 16); + *cp++ = (u8)(arg >> 8); + *cp++ = (u8)arg; + *cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01; + + /* Then, read up to 13 bytes (while writing all-ones): + * - N(CR) (== 1..8) bytes of all-ones + * - status byte (for all response types) + * - the rest of the response, either: + * + nothing, for R1 or R1B responses + * + second status byte, for R2 responses + * + four data bytes, for R3 and R7 responses + * + * Finally, read some more bytes ... in the nice cases we know in + * advance how many, and reading 1 more is always OK: + * - N(EC) (== 0..N) bytes of all-ones, before deselect/finish + * - N(RC) (== 1..N) bytes of all-ones, before next command + * - N(WR) (== 1..N) bytes of all-ones, before data write + * + * So in those cases one full duplex I/O of at most 21 bytes will + * handle the whole command, leaving the card ready to receive a + * data block or new command. We do that whenever we can, shaving + * CPU and IRQ costs (especially when using DMA or FIFOs). + * + * There are two other cases, where it's not generally practical + * to rely on a single I/O: + * + * - R1B responses need at least N(EC) bytes of all-zeroes. + * + * In this case we can *try* to fit it into one I/O, then + * maybe read more data later. + * + * - Data block reads are more troublesome, since a variable + * number of padding bytes precede the token and data. + * + N(CX) (== 0..8) bytes of all-ones, before CSD or CID + * + N(AC) (== 1..many) bytes of all-ones + * + * In this case we currently only have minimal speedups here: + * when N(CR) == 1 we can avoid I/O in response_get(). + */ + if (cs_on && (mrq->data->flags & MMC_DATA_READ)) { + cp += 2; /* min(N(CR)) + status */ + /* R1 */ + } else { + cp += 10; /* max(N(CR)) + status + min(N(RC),N(WR)) */ + if (cmd->flags & MMC_RSP_SPI_S2) /* R2/R5 */ + cp++; + else if (cmd->flags & MMC_RSP_SPI_B4) /* R3/R4/R7 */ + cp += 4; + else if (cmd->flags & MMC_RSP_BUSY) /* R1B */ + cp = data->status + sizeof(data->status); + /* else: R1 (most commands) */ + } + + dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, resp %s\n", + cmd->opcode, maptype(cmd)); + + /* send command, leaving chipselect active */ + spi_message_init(&host->m); + + t = &host->t; + memset(t, 0, sizeof(*t)); + t->tx_buf = t->rx_buf = data->status; + t->tx_dma = t->rx_dma = host->data_dma; + t->len = cp - data->status; + t->cs_change = 1; + spi_message_add_tail(t, &host->m); + + if (host->dma_dev) { + host->m.is_dma_mapped = 1; + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + } + status = spi_sync(host->spi, &host->m); + if (status == 0) + status = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + if (status < 0) { + dev_dbg(&host->spi->dev, " ... write returned %d\n", status); + cmd->error = status; + return status; + } + + /* after no-data commands and STOP_TRANSMISSION, chipselect off */ + return mmc_spi_response_get(host, cmd, cs_on); +} + +/* Build data message with up to four separate transfers. For TX, we + * start by writing the data token. And in most cases, we finish with + * a status transfer. + * + * We always provide TX data for data and CRC. The MMC/SD protocol + * requires us to write ones; but Linux defaults to writing zeroes; + * so we explicitly initialize it to all ones on RX paths. + * + * We also handle DMA mapping, so the underlying SPI controller does + * not need to (re)do it for each message. + */ +static void +mmc_spi_setup_data_message( + struct mmc_spi_host *host, + int multiple, + enum dma_data_direction direction) +{ + struct spi_transfer *t; + struct scratch *scratch = host->data; + dma_addr_t dma = host->data_dma; + + spi_message_init(&host->m); + if (dma) + host->m.is_dma_mapped = 1; + + /* for reads, readblock() skips 0xff bytes before finding + * the token; for writes, this transfer issues that token. + */ + if (direction == DMA_TO_DEVICE) { + t = &host->token; + memset(t, 0, sizeof(*t)); + t->len = 1; + if (multiple) + scratch->data_token = SPI_TOKEN_MULTI_WRITE; + else + scratch->data_token = SPI_TOKEN_SINGLE; + t->tx_buf = &scratch->data_token; + if (dma) + t->tx_dma = dma + offsetof(struct scratch, data_token); + spi_message_add_tail(t, &host->m); + } + + /* Body of transfer is buffer, then CRC ... + * either TX-only, or RX with TX-ones. + */ + t = &host->t; + memset(t, 0, sizeof(*t)); + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + /* length and actual buffer info are written later */ + spi_message_add_tail(t, &host->m); + + t = &host->crc; + memset(t, 0, sizeof(*t)); + t->len = 2; + if (direction == DMA_TO_DEVICE) { + /* the actual CRC may get written later */ + t->tx_buf = &scratch->crc_val; + if (dma) + t->tx_dma = dma + offsetof(struct scratch, crc_val); + } else { + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + t->rx_buf = &scratch->crc_val; + if (dma) + t->rx_dma = dma + offsetof(struct scratch, crc_val); + } + spi_message_add_tail(t, &host->m); + + /* + * A single block read is followed by N(EC) [0+] all-ones bytes + * before deselect ... don't bother. + * + * Multiblock reads are followed by N(AC) [1+] all-ones bytes before + * the next block is read, or a STOP_TRANSMISSION is issued. We'll + * collect that single byte, so readblock() doesn't need to. + * + * For a write, the one-byte data response follows immediately, then + * come zero or more busy bytes, then N(WR) [1+] all-ones bytes. + * Then single block reads may deselect, and multiblock ones issue + * the next token (next data block, or STOP_TRAN). We can try to + * minimize I/O ops by using a single read to collect end-of-busy. + */ + if (multiple || direction == DMA_TO_DEVICE) { + t = &host->early_status; + memset(t, 0, sizeof(*t)); + t->len = (direction == DMA_TO_DEVICE) + ? sizeof(scratch->status) + : 1; + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + t->rx_buf = scratch->status; + if (dma) + t->rx_dma = dma + offsetof(struct scratch, status); + t->cs_change = 1; + spi_message_add_tail(t, &host->m); + } +} + +/* + * Write one block: + * - caller handled preceding N(WR) [1+] all-ones bytes + * - data block + * + token + * + data bytes + * + crc16 + * - an all-ones byte ... card writes a data-response byte + * - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy' + * + * Return negative errno, else success. + */ +static int +mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t) +{ + struct spi_device *spi = host->spi; + int status, i; + struct scratch *scratch = host->data; + + if (host->mmc->use_spi_crc) + scratch->crc_val = cpu_to_be16( + crc_itu_t(0, t->tx_buf, t->len)); + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + status = spi_sync(spi, &host->m); + if (status == 0) + status = host->m.status; + + if (status != 0) { + dev_dbg(&spi->dev, "write error (%d)\n", status); + return status; + } + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + /* + * Get the transmission data-response reply. It must follow + * immediately after the data block we transferred. This reply + * doesn't necessarily tell whether the write operation succeeded; + * it just says if the transmission was ok and whether *earlier* + * writes succeeded; see the standard. + */ + switch (SPI_MMC_RESPONSE_CODE(scratch->status[0])) { + case SPI_RESPONSE_ACCEPTED: + status = 0; + break; + case SPI_RESPONSE_CRC_ERR: + /* host shall then issue MMC_STOP_TRANSMISSION */ + status = -EILSEQ; + break; + case SPI_RESPONSE_WRITE_ERR: + /* host shall then issue MMC_STOP_TRANSMISSION, + * and should MMC_SEND_STATUS to sort it out + */ + status = -EIO; + break; + default: + status = -EPROTO; + break; + } + if (status != 0) { + dev_dbg(&spi->dev, "write error %02x (%d)\n", + scratch->status[0], status); + return status; + } + + t->tx_buf += t->len; + if (host->dma_dev) + t->tx_dma += t->len; + + /* Return when not busy. If we didn't collect that status yet, + * we'll need some more I/O. + */ + for (i = 1; i < sizeof(scratch->status); i++) { + if (scratch->status[i] != 0) + return 0; + } + return mmc_spi_wait_unbusy(host, writeblock_timeout); +} + +/* + * Read one block: + * - skip leading all-ones bytes ... either + * + N(AC) [1..f(clock,CSD)] usually, else + * + N(CX) [0..8] when reading CSD or CID + * - data block + * + token ... if error token, no data or crc + * + data bytes + * + crc16 + * + * After single block reads, we're done; N(EC) [0+] all-ones bytes follow + * before dropping chipselect. + * + * For multiblock reads, caller either reads the next block or issues a + * STOP_TRANSMISSION command. + */ +static int +mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t) +{ + struct spi_device *spi = host->spi; + int status; + struct scratch *scratch = host->data; + + /* At least one SD card sends an all-zeroes byte when N(CX) + * applies, before the all-ones bytes ... just cope with that. + */ + status = mmc_spi_readbytes(host, 1); + if (status < 0) + return status; + status = scratch->status[0]; + if (status == 0xff || status == 0) + status = mmc_spi_readtoken(host); + + if (status == SPI_TOKEN_SINGLE) { + if (host->dma_dev) { + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + dma_sync_single_for_device(host->dma_dev, + t->rx_dma, t->len, + DMA_FROM_DEVICE); + } + + status = spi_sync(spi, &host->m); + if (status == 0) + status = host->m.status; + + if (host->dma_dev) { + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + dma_sync_single_for_cpu(host->dma_dev, + t->rx_dma, t->len, + DMA_FROM_DEVICE); + } + + } else { + dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); + + /* we've read extra garbage, timed out, etc */ + if (status < 0) + return status; + + /* low four bits are an R2 subset, fifth seems to be + * vendor specific ... map them all to generic error.. + */ + return -EIO; + } + + if (host->mmc->use_spi_crc) { + u16 crc = crc_itu_t(0, t->rx_buf, t->len); + + be16_to_cpus(&scratch->crc_val); + if (scratch->crc_val != crc) { + dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, " + "computed=0x%04x len=%d\n", + scratch->crc_val, crc, t->len); + return -EILSEQ; + } + } + + t->rx_buf += t->len; + if (host->dma_dev) + t->rx_dma += t->len; + + return 0; +} + +/* + * An MMC/SD data stage includes one or more blocks, optional CRCs, + * and inline handshaking. That handhaking makes it unlike most + * other SPI protocol stacks. + */ +static void +mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, + struct mmc_data *data, u32 blk_size) +{ + struct spi_device *spi = host->spi; + struct device *dma_dev = host->dma_dev; + struct spi_transfer *t; + enum dma_data_direction direction; + struct scatterlist *sg; + unsigned n_sg; + int multiple = (data->blocks > 1); + + if (data->flags & MMC_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + mmc_spi_setup_data_message(host, multiple, direction); + t = &host->t; + + /* Handle scatterlist segments one at a time, with synch for + * each 512-byte block + */ + for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) { + int status = 0; + dma_addr_t dma_addr = 0; + void *kmap_addr; + unsigned length = sg->length; + enum dma_data_direction dir = direction; + + /* set up dma mapping for controller drivers that might + * use DMA ... though they may fall back to PIO + */ + if (dma_dev) { + /* never invalidate whole *shared* pages ... */ + if ((sg->offset != 0 || length != PAGE_SIZE) + && dir == DMA_FROM_DEVICE) + dir = DMA_BIDIRECTIONAL; + + dma_addr = dma_map_page(dma_dev, sg->page, 0, + PAGE_SIZE, dir); + if (direction == DMA_TO_DEVICE) + t->tx_dma = dma_addr + sg->offset; + else + t->rx_dma = dma_addr + sg->offset; + } + + /* allow pio too; we don't allow highmem */ + kmap_addr = kmap(sg->page); + if (direction == DMA_TO_DEVICE) + t->tx_buf = kmap_addr + sg->offset; + else + t->rx_buf = kmap_addr + sg->offset; + + /* transfer each block, and update request status */ + while (length) { + t->len = min(length, blk_size); + + dev_dbg(&host->spi->dev, + " mmc_spi: %s block, %d bytes\n", + (direction == DMA_TO_DEVICE) + ? "write" + : "read", + t->len); + + if (direction == DMA_TO_DEVICE) + status = mmc_spi_writeblock(host, t); + else + status = mmc_spi_readblock(host, t); + if (status < 0) + break; + + data->bytes_xfered += t->len; + length -= t->len; + + if (!multiple) + break; + } + + /* discard mappings */ + if (direction == DMA_FROM_DEVICE) + flush_kernel_dcache_page(sg->page); + kunmap(sg->page); + if (dma_dev) + dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir); + + if (status < 0) { + data->error = status; + dev_dbg(&spi->dev, "%s status %d\n", + (direction == DMA_TO_DEVICE) + ? "write" : "read", + status); + break; + } + } + + /* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that + * can be issued before multiblock writes. Unlike its more widely + * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23), + * that can affect the STOP_TRAN logic. Complete (and current) + * MMC specs should sort that out before Linux starts using CMD23. + */ + if (direction == DMA_TO_DEVICE && multiple) { + struct scratch *scratch = host->data; + int tmp; + const unsigned statlen = sizeof(scratch->status); + + dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n"); + + /* Tweak the per-block message we set up earlier by morphing + * it to hold single buffer with the token followed by some + * all-ones bytes ... skip N(BR) (0..1), scan the rest for + * "not busy any longer" status, and leave chip selected. + */ + INIT_LIST_HEAD(&host->m.transfers); + list_add(&host->early_status.transfer_list, + &host->m.transfers); + + memset(scratch->status, 0xff, statlen); + scratch->status[0] = SPI_TOKEN_STOP_TRAN; + + host->early_status.tx_buf = host->early_status.rx_buf; + host->early_status.tx_dma = host->early_status.rx_dma; + host->early_status.len = statlen; + + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + tmp = spi_sync(spi, &host->m); + if (tmp == 0) + tmp = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + if (tmp < 0) { + if (!data->error) + data->error = tmp; + return; + } + + /* Ideally we collected "not busy" status with one I/O, + * avoiding wasteful byte-at-a-time scanning... but more + * I/O is often needed. + */ + for (tmp = 2; tmp < statlen; tmp++) { + if (scratch->status[tmp] != 0) + return; + } + tmp = mmc_spi_wait_unbusy(host, writeblock_timeout); + if (tmp < 0 && !data->error) + data->error = tmp; + } +} + +/****************************************************************************/ + +/* + * MMC driver implementation -- the interface to the MMC stack + */ + +static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + int status = -EINVAL; + +#ifdef DEBUG + /* MMC core and layered drivers *MUST* issue SPI-aware commands */ + { + struct mmc_command *cmd; + int invalid = 0; + + cmd = mrq->cmd; + if (!mmc_spi_resp_type(cmd)) { + dev_dbg(&host->spi->dev, "bogus command\n"); + cmd->error = -EINVAL; + invalid = 1; + } + + cmd = mrq->stop; + if (cmd && !mmc_spi_resp_type(cmd)) { + dev_dbg(&host->spi->dev, "bogus STOP command\n"); + cmd->error = -EINVAL; + invalid = 1; + } + + if (invalid) { + dump_stack(); + mmc_request_done(host->mmc, mrq); + return; + } + } +#endif + + /* issue command; then optionally data and stop */ + status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL); + if (status == 0 && mrq->data) { + mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz); + if (mrq->stop) + status = mmc_spi_command_send(host, mrq, mrq->stop, 0); + else + mmc_cs_off(host); + } + + mmc_request_done(host->mmc, mrq); +} + +/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0" + * + * NOTE that here we can't know that the card has just been powered up; + * not all MMC/SD sockets support power switching. + * + * FIXME when the card is still in SPI mode, e.g. from a previous kernel, + * this doesn't seem to do the right thing at all... + */ +static void mmc_spi_initsequence(struct mmc_spi_host *host) +{ + /* Try to be very sure any previous command has completed; + * wait till not-busy, skip debris from any old commands. + */ + mmc_spi_wait_unbusy(host, r1b_timeout); + mmc_spi_readbytes(host, 10); + + /* + * Do a burst with chipselect active-high. We need to do this to + * meet the requirement of 74 clock cycles with both chipselect + * and CMD (MOSI) high before CMD0 ... after the card has been + * powered up to Vdd(min), and so is ready to take commands. + * + * Some cards are particularly needy of this (e.g. Viking "SD256") + * while most others don't seem to care. + * + * Note that this is one of the places MMC/SD plays games with the + * SPI protocol. Another is that when chipselect is released while + * the card returns BUSY status, the clock must issue several cycles + * with chipselect high before the card will stop driving its output. + */ + host->spi->mode |= SPI_CS_HIGH; + if (spi_setup(host->spi) != 0) { + /* Just warn; most cards work without it. */ + dev_warn(&host->spi->dev, + "can't change chip-select polarity\n"); + host->spi->mode &= ~SPI_CS_HIGH; + } else { + mmc_spi_readbytes(host, 18); + + host->spi->mode &= ~SPI_CS_HIGH; + if (spi_setup(host->spi) != 0) { + /* Wot, we can't get the same setup we had before? */ + dev_err(&host->spi->dev, + "can't restore chip-select polarity\n"); + } + } +} + +static char *mmc_powerstring(u8 power_mode) +{ + switch (power_mode) { + case MMC_POWER_OFF: return "off"; + case MMC_POWER_UP: return "up"; + case MMC_POWER_ON: return "on"; + } + return "?"; +} + +static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + + if (host->power_mode != ios->power_mode) { + int canpower; + + canpower = host->pdata && host->pdata->setpower; + + dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n", + mmc_powerstring(ios->power_mode), + ios->vdd, + canpower ? ", can switch" : ""); + + /* switch power on/off if possible, accounting for + * max 250msec powerup time if needed. + */ + if (canpower) { + switch (ios->power_mode) { + case MMC_POWER_OFF: + case MMC_POWER_UP: + host->pdata->setpower(&host->spi->dev, + ios->vdd); + if (ios->power_mode == MMC_POWER_UP) + msleep(host->powerup_msecs); + } + } + + /* See 6.4.1 in the simplified SD card physical spec 2.0 */ + if (ios->power_mode == MMC_POWER_ON) + mmc_spi_initsequence(host); + + /* If powering down, ground all card inputs to avoid power + * delivery from data lines! On a shared SPI bus, this + * will probably be temporary; 6.4.2 of the simplified SD + * spec says this must last at least 1msec. + * + * - Clock low means CPOL 0, e.g. mode 0 + * - MOSI low comes from writing zero + * - Chipselect is usually active low... + */ + if (canpower && ios->power_mode == MMC_POWER_OFF) { + int mres; + + host->spi->mode &= ~(SPI_CPOL|SPI_CPHA); + mres = spi_setup(host->spi); + if (mres < 0) + dev_dbg(&host->spi->dev, + "switch to SPI mode 0 failed\n"); + + if (spi_w8r8(host->spi, 0x00) < 0) + dev_dbg(&host->spi->dev, + "put spi signals to low failed\n"); + + /* + * Now clock should be low due to spi mode 0; + * MOSI should be low because of written 0x00; + * chipselect should be low (it is active low) + * power supply is off, so now MMC is off too! + * + * FIXME no, chipselect can be high since the + * device is inactive and SPI_CS_HIGH is clear... + */ + msleep(10); + if (mres == 0) { + host->spi->mode |= (SPI_CPOL|SPI_CPHA); + mres = spi_setup(host->spi); + if (mres < 0) + dev_dbg(&host->spi->dev, + "switch back to SPI mode 3" + " failed\n"); + } + } + + host->power_mode = ios->power_mode; + } + + if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) { + int status; + + host->spi->max_speed_hz = ios->clock; + status = spi_setup(host->spi); + dev_dbg(&host->spi->dev, + "mmc_spi: clock to %d Hz, %d\n", + host->spi->max_speed_hz, status); + } +} + +static int mmc_spi_get_ro(struct mmc_host *mmc) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return host->pdata->get_ro(mmc->parent); + /* board doesn't support read only detection; assume writeable */ + return 0; +} + + +static const struct mmc_host_ops mmc_spi_ops = { + .request = mmc_spi_request, + .set_ios = mmc_spi_set_ios, + .get_ro = mmc_spi_get_ro, +}; + + +/****************************************************************************/ + +/* + * SPI driver implementation + */ + +static irqreturn_t +mmc_spi_detect_irq(int irq, void *mmc) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + u16 delay_msec = max(host->pdata->detect_delay, (u16)100); + + mmc_detect_change(mmc, msecs_to_jiffies(delay_msec)); + return IRQ_HANDLED; +} + +static int mmc_spi_probe(struct spi_device *spi) +{ + void *ones; + struct mmc_host *mmc; + struct mmc_spi_host *host; + int status; + + /* MMC and SD specs only seem to care that sampling is on the + * rising edge ... meaning SPI modes 0 or 3. So either SPI mode + * should be legit. We'll use mode 0 since it seems to be a + * bit less troublesome on some hardware ... unclear why. + */ + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + + status = spi_setup(spi); + if (status < 0) { + dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n", + spi->mode, spi->max_speed_hz / 1000, + status); + return status; + } + + /* We can use the bus safely iff nobody else will interfere with + * us. That is, either we have the experimental exclusive access + * primitives ... or else there's nobody to share it with. + */ + if (spi->master->num_chipselect > 1) { + struct device *parent = spi->dev.parent; + + /* If there are multiple devices on this bus, we + * can't proceed. + */ + spin_lock(&parent->klist_children.k_lock); + if (parent->klist_children.k_list.next + != parent->klist_children.k_list.prev) + status = -EMLINK; + else + status = 0; + spin_unlock(&parent->klist_children.k_lock); + if (status < 0) { + dev_err(&spi->dev, "can't share SPI bus\n"); + return status; + } + + /* REVISIT we can't guarantee another device won't + * be added later. It's uncommon though ... for now, + * work as if this is safe. + */ + dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n"); + } + + /* We need a supply of ones to transmit. This is the only time + * the CPU touches these, so cache coherency isn't a concern. + * + * NOTE if many systems use more than one MMC-over-SPI connector + * it'd save some memory to share this. That's evidently rare. + */ + status = -ENOMEM; + ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL); + if (!ones) + goto nomem; + memset(ones, 0xff, MMC_SPI_BLOCKSIZE); + + mmc = mmc_alloc_host(sizeof(*host), &spi->dev); + if (!mmc) + goto nomem; + + mmc->ops = &mmc_spi_ops; + mmc->max_blk_size = MMC_SPI_BLOCKSIZE; + + /* As long as we keep track of the number of successfully + * transmitted blocks, we're good for multiwrite. + */ + mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE; + + /* SPI doesn't need the lowspeed device identification thing for + * MMC or SD cards, since it never comes up in open drain mode. + * That's good; some SPI masters can't handle very low speeds! + * + * However, low speed SDIO cards need not handle over 400 KHz; + * that's the only reason not to use a few MHz for f_min (until + * the upper layer reads the target frequency from the CSD). + */ + mmc->f_min = 400000; + mmc->f_max = spi->max_speed_hz; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->spi = spi; + + host->ones = ones; + + /* Platform data is used to hook up things like card sensing + * and power switching gpios. + */ + host->pdata = spi->dev.platform_data; + if (host->pdata) + mmc->ocr_avail = host->pdata->ocr_mask; + if (!mmc->ocr_avail) { + dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n"); + mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + } + if (host->pdata && host->pdata->setpower) { + host->powerup_msecs = host->pdata->powerup_msecs; + if (!host->powerup_msecs || host->powerup_msecs > 250) + host->powerup_msecs = 250; + } + + dev_set_drvdata(&spi->dev, mmc); + + /* preallocate dma buffers */ + host->data = kmalloc(sizeof(*host->data), GFP_KERNEL); + if (!host->data) + goto fail_nobuf1; + + if (spi->master->cdev.dev->dma_mask) { + struct device *dev = spi->master->cdev.dev; + + host->dma_dev = dev; + host->ones_dma = dma_map_single(dev, ones, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + host->data_dma = dma_map_single(dev, host->data, + sizeof(*host->data), DMA_BIDIRECTIONAL); + + /* REVISIT in theory those map operations can fail... */ + + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + } + + /* setup message for status/busy readback */ + spi_message_init(&host->readback); + host->readback.is_dma_mapped = (host->dma_dev != NULL); + + spi_message_add_tail(&host->status, &host->readback); + host->status.tx_buf = host->ones; + host->status.tx_dma = host->ones_dma; + host->status.rx_buf = &host->data->status; + host->status.rx_dma = host->data_dma + offsetof(struct scratch, status); + host->status.cs_change = 1; + + /* register card detect irq */ + if (host->pdata && host->pdata->init) { + status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc); + if (status != 0) + goto fail_glue_init; + } + + status = mmc_add_host(mmc); + if (status != 0) + goto fail_add_host; + + dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n", + mmc->class_dev.bus_id, + host->dma_dev ? "" : ", no DMA", + (host->pdata && host->pdata->get_ro) + ? "" : ", no WP", + (host->pdata && host->pdata->setpower) + ? "" : ", no poweroff"); + return 0; + +fail_add_host: + mmc_remove_host (mmc); +fail_glue_init: + if (host->dma_dev) + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof(*host->data), DMA_BIDIRECTIONAL); + kfree(host->data); + +fail_nobuf1: + mmc_free_host(mmc); + dev_set_drvdata(&spi->dev, NULL); + +nomem: + kfree(ones); + return status; +} + + +static int __devexit mmc_spi_remove(struct spi_device *spi) +{ + struct mmc_host *mmc = dev_get_drvdata(&spi->dev); + struct mmc_spi_host *host; + + if (mmc) { + host = mmc_priv(mmc); + + /* prevent new mmc_detect_change() calls */ + if (host->pdata && host->pdata->exit) + host->pdata->exit(&spi->dev, mmc); + + mmc_remove_host(mmc); + + if (host->dma_dev) { + dma_unmap_single(host->dma_dev, host->ones_dma, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof(*host->data), DMA_BIDIRECTIONAL); + } + + kfree(host->data); + kfree(host->ones); + + spi->max_speed_hz = mmc->f_max; + mmc_free_host(mmc); + dev_set_drvdata(&spi->dev, NULL); + } + return 0; +} + + +static struct spi_driver mmc_spi_driver = { + .driver = { + .name = "mmc_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = mmc_spi_probe, + .remove = __devexit_p(mmc_spi_remove), +}; + + +static int __init mmc_spi_init(void) +{ + return spi_register_driver(&mmc_spi_driver); +} +module_init(mmc_spi_init); + + +static void __exit mmc_spi_exit(void) +{ + spi_unregister_driver(&mmc_spi_driver); +} +module_exit(mmc_spi_exit); + + +MODULE_AUTHOR("Mike Lavender, David Brownell, " + "Hans-Peter Nilsson, Jan Nikitenko"); +MODULE_DESCRIPTION("SPI SD/MMC host driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/spi/mmc_spi.h b/include/linux/spi/mmc_spi.h new file mode 100644 index 000000000000..e9bbe3ebd721 --- /dev/null +++ b/include/linux/spi/mmc_spi.h @@ -0,0 +1,33 @@ +#ifndef __LINUX_SPI_MMC_SPI_H +#define __LINUX_SPI_MMC_SPI_H + +struct device; +struct mmc_host; + +/* Put this in platform_data of a device being used to manage an MMC/SD + * card slot. (Modeled after PXA mmc glue; see that for usage examples.) + * + * REVISIT This is not a spi-specific notion. Any card slot should be + * able to handle it. If the MMC core doesn't adopt this kind of notion, + * switch the "struct device *" parameters over to "struct spi_device *". + */ +struct mmc_spi_platform_data { + /* driver activation and (optional) card detect irq hookup */ + int (*init)(struct device *, + irqreturn_t (*)(int, void *), + void *); + void (*exit)(struct device *, void *); + + /* sense switch on sd cards */ + int (*get_ro)(struct device *); + + /* how long to debounce card detect, in msecs */ + u16 detect_delay; + + /* power management */ + u16 powerup_msecs; /* delay of up to 250 msec */ + u32 ocr_mask; /* available voltages */ + void (*setpower)(struct device *, unsigned int maskval); +}; + +#endif /* __LINUX_SPI_MMC_SPI_H */ From af8350c756cb48a738474738f7bf8c0e572fa057 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 24 Sep 2007 07:15:48 +0200 Subject: [PATCH 0336/2804] mmc: add led trigger Add a led trigger for each host controller that indicates if there is a request active on the controller. Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 5 +++++ drivers/mmc/core/host.c | 5 +++++ include/linux/mmc/host.h | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bad39442f8fe..09435e0ec680 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -92,6 +93,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) cmd->error = 0; host->ops->request(host, mrq); } else { + led_trigger_event(host->led, LED_OFF); + pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), cmd->opcode, err, cmd->resp[0], cmd->resp[1], @@ -146,6 +149,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) WARN_ON(!host->claimed); + led_trigger_event(host->led, LED_FULL); + mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 37b761891d67..64fbc9759a30 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -115,6 +116,8 @@ int mmc_add_host(struct mmc_host *host) snprintf(host->class_dev.bus_id, BUS_ID_SIZE, "mmc%d", host->index); + led_trigger_register_simple(host->class_dev.bus_id, &host->led); + err = device_add(&host->class_dev); if (err) return err; @@ -140,6 +143,8 @@ void mmc_remove_host(struct mmc_host *host) device_del(&host->class_dev); + led_trigger_unregister(host->led); + spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); spin_unlock(&mmc_host_lock); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 76eef94782f8..125eee1407ff 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -10,6 +10,8 @@ #ifndef LINUX_MMC_HOST_H #define LINUX_MMC_HOST_H +#include + #include struct mmc_ios { @@ -133,6 +135,10 @@ struct mmc_host { struct task_struct *sdio_irq_thread; atomic_t sdio_irq_thread_abort; +#ifdef CONFIG_LEDS_TRIGGERS + struct led_trigger *led; /* activity led */ +#endif + unsigned long private[0] ____cacheline_aligned; }; From faf39ede5e6325d3e91b6e4e0017d27fbecb6022 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Sun, 23 Sep 2007 22:59:01 +0200 Subject: [PATCH 0337/2804] arm: i.MX/MX1 SDHC implements SD cards read-only switch read-back The patch enables to define MMC host get_ro() method through platform data. Signed-off-by: Pavel Pisa Signed-off-by: Pierre Ossman --- arch/arm/mach-imx/mx1ads.c | 2 +- drivers/mmc/host/imxmmc.c | 16 ++++++++++++++-- include/asm-arm/arch-imx/mmc.h | 5 ++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index da893c80d471..a9778c1587ab 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -116,7 +116,7 @@ static struct platform_device *devices[] __initdata = { }; #ifdef CONFIG_MMC_IMX -static int mx1ads_mmc_card_present(void) +static int mx1ads_mmc_card_present(struct device *dev) { /* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */ return (SSR(1) & (1 << 20) ? 0 : 1); diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index e33c123c7027..6ebc41e7592c 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -884,9 +884,21 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } +static int imxmci_get_ro(struct mmc_host *mmc) +{ + struct imxmci_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return host->pdata->get_ro(mmc_dev(mmc)); + /* Host doesn't support read only detection so assume writeable */ + return 0; +} + + static const struct mmc_host_ops imxmci_ops = { .request = imxmci_request, .set_ios = imxmci_set_ios, + .get_ro = imxmci_get_ro, }; static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr) @@ -913,7 +925,7 @@ static void imxmci_check_status(unsigned long data) { struct imxmci_host *host = (struct imxmci_host *)data; - if( host->pdata->card_present() != host->present ) { + if( host->pdata->card_present(mmc_dev(host->mmc)) != host->present ) { host->present ^= 1; dev_info(mmc_dev(host->mmc), "card %s\n", host->present ? "inserted" : "removed"); @@ -1022,7 +1034,7 @@ static int imxmci_probe(struct platform_device *pdev) if (ret) goto out; - host->present = host->pdata->card_present(); + host->present = host->pdata->card_present(mmc_dev(mmc)); init_timer(&host->timer); host->timer.data = (unsigned long)host; host->timer.function = imxmci_check_status; diff --git a/include/asm-arm/arch-imx/mmc.h b/include/asm-arm/arch-imx/mmc.h index 84c726934ace..4712f354dcca 100644 --- a/include/asm-arm/arch-imx/mmc.h +++ b/include/asm-arm/arch-imx/mmc.h @@ -3,8 +3,11 @@ #include +struct device; + struct imxmmc_platform_data { - int (*card_present)(void); + int (*card_present)(struct device *); + int (*get_ro)(struct device *); }; extern void imx_set_mmc_info(struct imxmmc_platform_data *info); From 81ab570f65395f09962f4bca0d89403f8911c071 Mon Sep 17 00:00:00 2001 From: Bridge Wu Date: Tue, 25 Sep 2007 18:59:07 +0200 Subject: [PATCH 0338/2804] mmc: pxamci: better pending IRQ determination Pending interrupts should be determined from both I_REG and I_MASK registers. Signed-off-by: Bridge Wu Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index b89e32d1e9b5..03d162881159 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -298,7 +298,7 @@ static irqreturn_t pxamci_irq(int irq, void *devid) unsigned int ireg; int handled = 0; - ireg = readl(host->base + MMC_I_REG); + ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); if (ireg) { unsigned stat = readl(host->base + MMC_STAT); From fe2dc44eac1223a0e92859242f58fd2a58a6f8fa Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 24 Sep 2007 15:47:18 -0400 Subject: [PATCH 0339/2804] mmc: pxamci: set proper block capabilities according to PXA flavor From PXA27x, it is possible to do 2048-byte block transfers. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 03d162881159..67acc6a00895 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -444,9 +444,9 @@ static int pxamci_probe(struct platform_device *pdev) mmc->max_seg_size = PAGE_SIZE; /* - * Block length register is 10 bits. + * Block length register is only 10 bits before PXA27x. */ - mmc->max_blk_size = 1023; + mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048; /* * Block count register is 16 bits. From df456f479aa6fdc812df51627c6f2c21d8a1aed8 Mon Sep 17 00:00:00 2001 From: Bridge Wu Date: Tue, 25 Sep 2007 19:09:19 +0200 Subject: [PATCH 0340/2804] mmc: pxamci: set proper buswidth capabilities according to PXA flavor From PXA27x, it is possible to do 4-bit data transfers. Signed-off-by: Bridge Wu Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 10 +++++++++- drivers/mmc/host/pxamci.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 67acc6a00895..6549f546df55 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -284,7 +284,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) host->data = NULL; if (host->mrq->stop) { pxamci_stop_clock(host); - pxamci_start_cmd(host, host->mrq->stop, 0); + pxamci_start_cmd(host, host->mrq->stop, host->cmdat); } else { pxamci_finish_request(host, host->mrq); } @@ -382,6 +382,11 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->cmdat |= CMDAT_INIT; } + if (ios->bus_width == MMC_BUS_WIDTH_4) + host->cmdat |= CMDAT_SD_4DAT; + else + host->cmdat &= ~CMDAT_SD_4DAT; + pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", host->clkrt, host->cmdat); } @@ -460,6 +465,9 @@ static int pxamci_probe(struct platform_device *pdev) mmc->ocr_avail = host->pdata ? host->pdata->ocr_mask : MMC_VDD_32_33|MMC_VDD_33_34; + mmc->caps = 0; + if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) + mmc->caps |= MMC_CAP_4_BIT_DATA; host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); if (!host->sg_cpu) { diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h index df17c281278a..5655be823a00 100644 --- a/drivers/mmc/host/pxamci.h +++ b/drivers/mmc/host/pxamci.h @@ -25,6 +25,7 @@ #define SPI_EN (1 << 0) #define MMC_CMDAT 0x0010 +#define CMDAT_SD_4DAT (1 << 8) #define CMDAT_DMAEN (1 << 7) #define CMDAT_INIT (1 << 6) #define CMDAT_BUSY (1 << 5) From 5d3ad4e8a12e538eead0a37d22b1ba6aec0f2127 Mon Sep 17 00:00:00 2001 From: Bridge Wu Date: Tue, 25 Sep 2007 19:11:00 +0200 Subject: [PATCH 0341/2804] mmc: pxamci: add SDIO card interrupt reporting capability Again, only available from PXA27x. Signed-off-by: Bridge Wu Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 28 +++++++++++++++++++++++----- drivers/mmc/host/pxamci.h | 1 + 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 6549f546df55..91e25683b397 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -309,6 +309,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid) handled |= pxamci_cmd_done(host, stat); if (ireg & DATA_TRAN_DONE) handled |= pxamci_data_done(host, stat); + if (ireg & SDIO_INT) { + mmc_signal_sdio_irq(host->mmc); + handled = 1; + } } return IRQ_RETVAL(handled); @@ -391,10 +395,21 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->clkrt, host->cmdat); } +static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) +{ + struct pxamci_host *pxa_host = mmc_priv(host); + + if (enable) + pxamci_enable_irq(pxa_host, SDIO_INT); + else + pxamci_disable_irq(pxa_host, SDIO_INT); +} + static const struct mmc_host_ops pxamci_ops = { - .request = pxamci_request, - .get_ro = pxamci_get_ro, - .set_ios = pxamci_set_ios, + .request = pxamci_request, + .get_ro = pxamci_get_ro, + .set_ios = pxamci_set_ios, + .enable_sdio_irq = pxamci_enable_sdio_irq, }; static void pxamci_dma_irq(int dma, void *devid) @@ -466,8 +481,11 @@ static int pxamci_probe(struct platform_device *pdev) host->pdata->ocr_mask : MMC_VDD_32_33|MMC_VDD_33_34; mmc->caps = 0; - if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) - mmc->caps |= MMC_CAP_4_BIT_DATA; + host->cmdat = 0; + if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + host->cmdat |= CMDAT_SDIO_INT_EN; + } host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); if (!host->sg_cpu) { diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h index 5655be823a00..3153e779d46a 100644 --- a/drivers/mmc/host/pxamci.h +++ b/drivers/mmc/host/pxamci.h @@ -25,6 +25,7 @@ #define SPI_EN (1 << 0) #define MMC_CMDAT 0x0010 +#define CMDAT_SDIO_INT_EN (1 << 11) #define CMDAT_SD_4DAT (1 << 8) #define CMDAT_DMAEN (1 << 7) #define CMDAT_INIT (1 << 6) From c5552ca48b312880ba9111411c98abfe72d88ea9 Mon Sep 17 00:00:00 2001 From: Jochen Friedrich Date: Fri, 21 Sep 2007 12:57:13 +0200 Subject: [PATCH 0342/2804] [POWERPC] Fix copy'n'paste typo in commproc.c The powerpc version of commproc.c exports cpm_dpram_addr twice and cpm_dpram_phys not at all due to a typo. This patch fixes this problem. CC arch/powerpc/sysdev/commproc.o arch/powerpc/sysdev/commproc.c:398: error: redefinition of '__kcrctab_cpm_dpram_addr' arch/powerpc/sysdev/commproc.c:392: error: previous definition of '__kcrctab_cpm_dpram_addr' was here arch/powerpc/sysdev/commproc.c:398: error: redefinition of '__kstrtab_cpm_dpram_addr' arch/powerpc/sysdev/commproc.c:392: error: previous definition of '__kstrtab_cpm_dpram_addr' was here arch/powerpc/sysdev/commproc.c:398: error: redefinition of '__ksymtab_cpm_dpram_addr' arch/powerpc/sysdev/commproc.c:392: error: previous definition of '__ksymtab_cpm_dpram_addr' was here make[1]: *** [arch/powerpc/sysdev/commproc.o] Error 1 make: *** [arch/powerpc/sysdev] Error 2 Signed-off-by: Jochen Friedrich --- arch/powerpc/sysdev/commproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c index 4f67b89ba1d0..dd5417aec1b4 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/commproc.c @@ -395,4 +395,4 @@ uint cpm_dpram_phys(u8* addr) { return (dpram_pbase + (uint)(addr - dpram_vbase)); } -EXPORT_SYMBOL(cpm_dpram_addr); +EXPORT_SYMBOL(cpm_dpram_phys); From 1d7a8ee0ebcc26c98f21889fd900546ef2a02fa1 Mon Sep 17 00:00:00 2001 From: Jochen Friedrich Date: Fri, 21 Sep 2007 13:15:07 +0200 Subject: [PATCH 0343/2804] [PPC] Fix cpm_dpram_addr returning phys mem instead of virt mem cpm_dpram_addr returns physical memory of the DP RAM instead of iomapped virtual memory. As there usually is a 1:1 MMU map of the IMMR area, this is often not noticed. However, cpm_dpram_phys assumes this iomapped virtual memory and returns garbage on the 1:1 mapped memory causing CPM1 uart console to fail. This patch fixes the problem (copied from the powerpc tree). Signed-off-by: Jochen Friedrich --- arch/ppc/8xx_io/commproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index 7088428e1fe2..9da880be4dc0 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -459,7 +459,7 @@ EXPORT_SYMBOL(cpm_dpdump); void *cpm_dpram_addr(unsigned long offset) { - return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset; + return (void *)(dpram_vbase + offset); } EXPORT_SYMBOL(cpm_dpram_addr); From 7a6d44f79f60f2b106e2a820503fa7c1814a13d0 Mon Sep 17 00:00:00 2001 From: Jochen Friedrich Date: Thu, 13 Sep 2007 16:00:48 +0200 Subject: [PATCH 0344/2804] [PPC] Compile fix for 8xx CPM Ehernet driver Add #include for flush_dcache_range to make the driver compile again. CC arch/ppc/8xx_io/enet.o arch/ppc/8xx_io/enet.c: In function 'scc_enet_start_xmit': arch/ppc/8xx_io/enet.c:240: error: implicit declaration of function 'flush_dcache_range' make[1]: *** [arch/ppc/8xx_io/enet.o] Error 1 make: *** [arch/ppc/8xx_io] Error 2 Signed-off-by: Jochen Friedrich --- arch/ppc/8xx_io/enet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c index 703d47eee436..eace3bc118d2 100644 --- a/arch/ppc/8xx_io/enet.c +++ b/arch/ppc/8xx_io/enet.c @@ -44,6 +44,7 @@ #include #include #include +#include /* * Theory of Operation From b15773a06e5feee192f83c578222b45d81d1edc9 Mon Sep 17 00:00:00 2001 From: Jochen Friedrich Date: Mon, 24 Sep 2007 18:54:41 +0200 Subject: [PATCH 0345/2804] [POWERPC] Fix cpm_uart driver in cpm_uart_cpm1.h, DPRAM_BASE is assigned an address derived from cpmp. On ARC=ppc, this is a physical address with 1:1 DMA mapping which can't be used for arithmetric compare operations with virtual addresses returned by cpm_dpram_addr. This patch changes the assignment to use cpm_dpram_addr as well, like in cpm_uart_cpm2.h. Signed-off-by: Jochen Friedrich --- drivers/serial/cpm_uart/cpm_uart_cpm1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index a99e45e2b6d8..2a6477834c3e 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -37,6 +37,6 @@ static inline void cpm_set_smc_fcr(volatile smc_uart_t * up) up->smc_tfcr = SMC_EB; } -#define DPRAM_BASE ((unsigned char *)&cpmp->cp_dpmem[0]) +#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0)) #endif From 6f4285d13300f1c8cd675a41ab390cea06173cd1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 27 Sep 2007 10:48:29 +0200 Subject: [PATCH 0346/2804] sdio: adaptive interrupt polling The interrupt polling frequency is a compromise between power usage and interrupt latency. Unfortunately, it affects throughput rather severely for devices which require an interrupt for every chunk of data. By making the polling frequency adaptive, we get better throughput with those devices without sacficing too much power. Polling will quickly increase when there is an actual interrupt, and slowly fall back to the idle frequency when the interrupts stop coming. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_irq.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 8843a4c2fe91..f78ffeefed52 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -27,7 +27,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) { - int i, ret; + int i, ret, count; unsigned char pending; ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending); @@ -37,6 +37,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) return ret; } + count = 0; for (i = 1; i <= 7; i++) { if (pending & (1 << i)) { struct sdio_func *func = card->sdio_func[i - 1]; @@ -46,20 +47,21 @@ static int process_sdio_pending_irqs(struct mmc_card *card) sdio_func_id(func)); } else if (func->irq_handler) { func->irq_handler(func); + count++; } else printk(KERN_WARNING "%s: pending IRQ with no handler\n", sdio_func_id(func)); } } - return 0; + return count; } static int sdio_irq_thread(void *_host) { struct mmc_host *host = _host; struct sched_param param = { .sched_priority = 1 }; - unsigned long period; + unsigned long period, idle_period; int ret; sched_setscheduler(current, SCHED_FIFO, ¶m); @@ -70,8 +72,9 @@ static int sdio_irq_thread(void *_host) * asynchronous notification of pending SDIO card interrupts * hence we poll for them in that case. */ + idle_period = msecs_to_jiffies(10); period = (host->caps & MMC_CAP_SDIO_IRQ) ? - MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(10); + MAX_SCHEDULE_TIMEOUT : idle_period; pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n", mmc_hostname(host), period); @@ -101,9 +104,24 @@ static int sdio_irq_thread(void *_host) * errors. FIXME: determine if due to card removal and * possibly exit this thread if so. */ - if (ret) + if (ret < 0) ssleep(1); + /* + * Adaptive polling frequency based on the assumption + * that an interrupt will be closely followed by more. + * This has a substantial benefit for network devices. + */ + if (!(host->caps & MMC_CAP_SDIO_IRQ)) { + if (ret > 0) + period /= 2; + else { + period++; + if (period > idle_period) + period = idle_period; + } + } + set_task_state(current, TASK_INTERRUPTIBLE); if (host->caps & MMC_CAP_SDIO_IRQ) host->ops->enable_sdio_irq(host, 1); From a7fb7ea76e20740c641a9b5401ef45b3b022cb69 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 10 Aug 2007 09:27:00 +1000 Subject: [PATCH 0347/2804] [POWERPC] pseries: device node status can be "ok" or "okay" It seems that some versions of firmware will report a device node status as the string "okay". As we are not expecting this string, the device node will be ignored by the EEH subsystem. Which means EEH will not be enabled. When EEH is not enabled, PCI errors will be converted into Machine Check exceptions, and we'll have a very unhappy system. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index b242c6c34f81..22322b35a0ff 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -955,7 +955,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) pdn->eeh_freeze_count = 0; pdn->eeh_false_positives = 0; - if (status && strcmp(status, "ok") != 0) + if (status && strncmp(status, "ok", 2) != 0) return NULL; /* ignore devices with bad status */ /* Ignore bad nodes. */ From a35e370cfd2ddfb5d2f0ceae376ffeda273b357c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 30 Aug 2007 09:11:24 +1000 Subject: [PATCH 0348/2804] [POWERPC] Move embedded6xx into multiplatform The various embedded 6xx systems can easily coexist in one kernel together with the other 6xx based systems, so there is no strict reason to keep them separate. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/Kconfig | 4 ---- arch/powerpc/platforms/embedded6xx/Kconfig | 11 +++++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 78a7edac577f..92fcd6e35b51 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -12,10 +12,6 @@ config PPC_MULTIPLATFORM RS/6000 machine, an Apple machine, or a PReP, CHRP, Maple or Cell-based machine. -config EMBEDDED6xx - bool "Embedded 6xx/7xx/7xxx-based board" - depends on PPC32 && (BROKEN||BROKEN_ON_SMP) - config PPC_82xx bool "Freescale 82xx" depends on 6xx diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 2d12f77e46bc..da66103009c6 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -1,9 +1,10 @@ -choice - prompt "Machine Type" - depends on EMBEDDED6xx +config EMBEDDED6xx + bool "Embedded 6xx/7xx/7xxx-based boards" + depends on PPC32 && BROKEN_ON_SMP && PPC_MULTIPLATFORM config LINKSTATION bool "Linkstation / Kurobox(HG) from Buffalo" + depends on EMBEDDED6xx select MPIC select FSL_SOC select PPC_UDBG_16550 if SERIAL_8250 @@ -17,6 +18,7 @@ config LINKSTATION config MPC7448HPC2 bool "Freescale MPC7448HPC2(Taiga)" + depends on EMBEDDED6xx select TSI108_BRIDGE select DEFAULT_UIMAGE select PPC_UDBG_16550 @@ -26,6 +28,7 @@ config MPC7448HPC2 config PPC_HOLLY bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)" + depends on EMBEDDED6xx select TSI108_BRIDGE select PPC_UDBG_16550 select WANT_DEVICE_TREE @@ -35,12 +38,12 @@ config PPC_HOLLY config PPC_PRPMC2800 bool "Motorola-PrPMC2800" + depends on EMBEDDED6xx select MV64X60 select NOT_COHERENT_CACHE select WANT_DEVICE_TREE help This option enables support for the Motorola PrPMC2800 board -endchoice config TSI108_BRIDGE bool From db220b234da9f183b127b9c3077c253b94756e35 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 17 Sep 2007 16:03:45 +1000 Subject: [PATCH 0349/2804] [POWERPC] Make sure to of_node_get() the result of pci_device_to_OF_node() pci_device_to_OF_node() returns the device node attached to a PCI device, but doesn't actually grab a reference - we need to do it ourselves. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/axon_msi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 74407afddf46..4bde8da11f44 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -125,7 +125,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) const phandle *ph; struct axon_msic *msic = NULL; - dn = pci_device_to_OF_node(dev); + dn = of_node_get(pci_device_to_OF_node(dev)); if (!dn) { dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n"); return NULL; @@ -182,7 +182,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) int len; const u32 *prop; - dn = pci_device_to_OF_node(dev); + dn = of_node_get(pci_device_to_OF_node(dev)); if (!dn) { dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n"); return -ENODEV; From d9303d662fa3fca8a6d27dee82b961a5f5524f20 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 20 Sep 2007 16:36:47 +1000 Subject: [PATCH 0350/2804] [POWERPC] Simplify error logic in u3msi_setup_msi_irqs() u3msi_setup_msi_irqs() doesn't need to call teardown() itself, the generic code will do this for us as long as we return a non zero value. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic_u3msi.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 0fc4e961d451..255b2f53beda 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -125,7 +125,6 @@ static void u3msi_compose_msi_msg(struct pci_dev *pdev, int virq, static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { irq_hw_number_t hwirq; - int rc; unsigned int virq; struct msi_desc *entry; struct msi_msg msg; @@ -133,17 +132,15 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) list_for_each_entry(entry, &pdev->msi_list, list) { hwirq = mpic_msi_alloc_hwirqs(msi_mpic, 1); if (hwirq < 0) { - rc = hwirq; pr_debug("u3msi: failed allocating hwirq\n"); - goto out_free; + return hwirq; } virq = irq_create_mapping(msi_mpic->irqhost, hwirq); if (virq == NO_IRQ) { pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq); mpic_msi_free_hwirqs(msi_mpic, hwirq, 1); - rc = -ENOSPC; - goto out_free; + return -ENOSPC; } set_irq_msi(virq, entry); @@ -157,10 +154,6 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) } return 0; - - out_free: - u3msi_teardown_msi_irqs(pdev); - return rc; } int mpic_u3msi_init(struct mpic *mpic) From fcbe8090a001522f98ad6f3146f0a1d9fa473821 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 20 Sep 2007 16:36:48 +1000 Subject: [PATCH 0351/2804] [POWERPC] Simplify error logic in rtas_setup_msi_irqs() rtas_setup_msi_irqs() doesn't need to call teardown() itself, the generic code will do this for us as long as we return a non-zero value. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/msi.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 6063ea2f67ad..9c3bcfe3fe6a 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -189,29 +189,22 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) if (rc != nvec) { pr_debug("rtas_msi: rtas_change_msi() failed\n"); - - /* - * In case of an error it's not clear whether the device is - * left with MSI enabled or not, so we explicitly disable. - */ - goto out_free; + return rc; } i = 0; list_for_each_entry(entry, &pdev->msi_list, list) { hwirq = rtas_query_irq_number(pdn, i); if (hwirq < 0) { - rc = hwirq; pr_debug("rtas_msi: error (%d) getting hwirq\n", rc); - goto out_free; + return hwirq; } virq = irq_create_mapping(NULL, hwirq); if (virq == NO_IRQ) { pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq); - rc = -ENOSPC; - goto out_free; + return -ENOSPC; } dev_dbg(&pdev->dev, "rtas_msi: allocated virq %d\n", virq); @@ -220,10 +213,6 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) } return 0; - - out_free: - rtas_teardown_msi_irqs(pdev); - return rc; } static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev) From d385366a9b96fc3f4705f8513adccceaa0515f97 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 20 Sep 2007 16:36:50 +1000 Subject: [PATCH 0352/2804] [POWERPC] Simplify rtas_change_msi() error semantics Currently rtas_change_msi() returns either the error code from RTAS, or if the RTAS call succeeded the number of irqs that were configured by RTAS. This makes checking the return value more complicated than it needs to be. Instead, have rtas_change_msi() check that the number of irqs configured by RTAS is equal to what we requested - and return an error otherwise. This makes the return semantics match the usual 0 for success, something else for error. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/msi.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 9c3bcfe3fe6a..2793a1b100e6 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -70,11 +70,15 @@ static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs) seq_num = rtas_ret[1]; } while (rtas_busy_delay(rc)); - if (rc == 0) /* Success */ - rc = rtas_ret[0]; + /* + * If the RTAS call succeeded, check the number of irqs is actually + * what we asked for. If not, return an error. + */ + if (rc == 0 && rtas_ret[0] != num_irqs) + rc = -ENOSPC; - pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d) = (%d)\n", - func, num_irqs, rc); + pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d), got %d rc = %d\n", + func, num_irqs, rtas_ret[0], rc); return rc; } @@ -87,7 +91,7 @@ static void rtas_disable_msi(struct pci_dev *pdev) if (!pdn) return; - if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0) + if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0)) pr_debug("rtas_msi: Setting MSIs to 0 failed!\n"); } @@ -180,14 +184,14 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) if (type == PCI_CAP_ID_MSI) { rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); - if (rc != nvec) { + if (rc) { pr_debug("rtas_msi: trying the old firmware call.\n"); rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); } } else rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); - if (rc != nvec) { + if (rc) { pr_debug("rtas_msi: rtas_change_msi() failed\n"); return rc; } From 21ccdd31e9c70f42b00d9ea152f6c4e0ff3f536e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 20 Sep 2007 16:36:51 +1000 Subject: [PATCH 0353/2804] [POWERPC] Inline u3msi_compose_msi_msg() In the MPIC U3 MSI code, we call u3msi_compose_msi_msg() once for each MSI. This is overkill, as the address is per pci device, not per MSI. So setup the address once, and just set the data per MSI. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic_u3msi.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 255b2f53beda..1d5a40899b74 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -108,26 +108,17 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) return; } -static void u3msi_compose_msi_msg(struct pci_dev *pdev, int virq, - struct msi_msg *msg) -{ - u64 addr; - - addr = find_ht_magic_addr(pdev); - msg->address_lo = addr & 0xFFFFFFFF; - msg->address_hi = addr >> 32; - msg->data = virq_to_hw(virq); - - pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) at address 0x%lx\n", - virq, virq_to_hw(virq), addr); -} - static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { irq_hw_number_t hwirq; unsigned int virq; struct msi_desc *entry; struct msi_msg msg; + u64 addr; + + addr = find_ht_magic_addr(pdev); + msg.address_lo = addr & 0xFFFFFFFF; + msg.address_hi = addr >> 32; list_for_each_entry(entry, &pdev->msi_list, list) { hwirq = mpic_msi_alloc_hwirqs(msi_mpic, 1); @@ -147,7 +138,10 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) set_irq_chip(virq, &mpic_u3msi_chip); set_irq_type(virq, IRQ_TYPE_EDGE_RISING); - u3msi_compose_msi_msg(pdev, virq, &msg); + pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n", + virq, hwirq, addr); + + msg.data = hwirq; write_msi_msg(virq, &msg); hwirq++; From 6f6682809b994fd9a61081fa0410df31481d5f7f Mon Sep 17 00:00:00 2001 From: Domen Puncer Date: Fri, 21 Sep 2007 00:00:11 +1000 Subject: [PATCH 0354/2804] [POWERPC] clk.h interface for platforms This provides an implementation of the interface for arch/powerpc using a set of function pointers in clk_functions. Platforms that want to support this interface should fill clk_functions and select CONFIG_PPC_CLOCK in Kconfig. Signed-off-by: Domen Puncer Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 4 ++ arch/powerpc/kernel/Makefile | 1 + arch/powerpc/kernel/clock.c | 82 +++++++++++++++++++++++++++++ arch/powerpc/platforms/52xx/Kconfig | 1 + include/asm-powerpc/clk_interface.h | 20 +++++++ 5 files changed, 108 insertions(+) create mode 100644 arch/powerpc/kernel/clock.c create mode 100644 include/asm-powerpc/clk_interface.h diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 66a329534b5e..26126d27d756 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -663,3 +663,7 @@ config KEYS_COMPAT default y source "crypto/Kconfig" + +config PPC_CLOCK + bool + default n diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 967afc517d8f..b37165effb65 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_PPC_970_NAP) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o +obj-$(CONFIG_PPC_CLOCK) += clock.o procfs-$(CONFIG_PPC64) := proc_ppc64.o obj-$(CONFIG_PROC_FS) += $(procfs-y) rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o diff --git a/arch/powerpc/kernel/clock.c b/arch/powerpc/kernel/clock.c new file mode 100644 index 000000000000..ce668f545758 --- /dev/null +++ b/arch/powerpc/kernel/clock.c @@ -0,0 +1,82 @@ +/* + * Dummy clk implementations for powerpc. + * These need to be overridden in platform code. + */ + +#include +#include +#include +#include +#include + +struct clk_interface clk_functions; + +struct clk *clk_get(struct device *dev, const char *id) +{ + if (clk_functions.clk_get) + return clk_functions.clk_get(dev, id); + return ERR_PTR(-ENOSYS); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + if (clk_functions.clk_put) + clk_functions.clk_put(clk); +} +EXPORT_SYMBOL(clk_put); + +int clk_enable(struct clk *clk) +{ + if (clk_functions.clk_enable) + return clk_functions.clk_enable(clk); + return -ENOSYS; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + if (clk_functions.clk_disable) + clk_functions.clk_disable(clk); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk_functions.clk_get_rate) + return clk_functions.clk_get_rate(clk); + return 0; +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (clk_functions.clk_round_rate) + return clk_functions.clk_round_rate(clk, rate); + return -ENOSYS; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + if (clk_functions.clk_set_rate) + return clk_functions.clk_set_rate(clk, rate); + return -ENOSYS; +} +EXPORT_SYMBOL(clk_set_rate); + +struct clk *clk_get_parent(struct clk *clk) +{ + if (clk_functions.clk_get_parent) + return clk_functions.clk_get_parent(clk); + return ERR_PTR(-ENOSYS); +} +EXPORT_SYMBOL(clk_get_parent); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + if (clk_functions.clk_set_parent) + return clk_functions.clk_set_parent(clk, parent); + return -ENOSYS; +} +EXPORT_SYMBOL(clk_set_parent); diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index 9ddf251b192b..2938d4927b83 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig @@ -1,6 +1,7 @@ config PPC_MPC52xx bool select FSL_SOC + select PPC_CLOCK default n config PPC_MPC5200 diff --git a/include/asm-powerpc/clk_interface.h b/include/asm-powerpc/clk_interface.h new file mode 100644 index 000000000000..ab1882c1e176 --- /dev/null +++ b/include/asm-powerpc/clk_interface.h @@ -0,0 +1,20 @@ +#ifndef __ASM_POWERPC_CLK_INTERFACE_H +#define __ASM_POWERPC_CLK_INTERFACE_H + +#include + +struct clk_interface { + struct clk* (*clk_get) (struct device *dev, const char *id); + int (*clk_enable) (struct clk *clk); + void (*clk_disable) (struct clk *clk); + unsigned long (*clk_get_rate) (struct clk *clk); + void (*clk_put) (struct clk *clk); + long (*clk_round_rate) (struct clk *clk, unsigned long rate); + int (*clk_set_rate) (struct clk *clk, unsigned long rate); + int (*clk_set_parent) (struct clk *clk, struct clk *parent); + struct clk* (*clk_get_parent) (struct clk *clk); +}; + +extern struct clk_interface clk_functions; + +#endif /* __ASM_POWERPC_CLK_INTERFACE_H */ From 75918a4b5998c93ee1ab131fbe64b97b5d0d2315 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 21 Sep 2007 05:11:20 +1000 Subject: [PATCH 0355/2804] [POWERPC] Separate out legacy machine check exception parsers Move out the old-style exception parsers to a separate function, and don't call it on platforms that have a platform-specific handler. It would make sense to move out the generic versions into their platforms instead, but that can be done gradually down the road. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/traps.c | 66 +++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index ccfc99dad061..5a49eabd492e 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -324,38 +324,10 @@ static inline int check_io_access(struct pt_regs *regs) #define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) #endif -void machine_check_exception(struct pt_regs *regs) +static int generic_machine_check_exception(struct pt_regs *regs) { - int recover = 0; unsigned long reason = get_mc_reason(regs); - /* See if any machine dependent calls */ - if (ppc_md.machine_check_exception) - recover = ppc_md.machine_check_exception(regs); - - if (recover) - return; - - if (user_mode(regs)) { - regs->msr |= MSR_RI; - _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); - return; - } - -#if defined(CONFIG_8xx) && defined(CONFIG_PCI) - /* the qspan pci read routines can cause machine checks -- Cort */ - bad_page_fault(regs, regs->dar, SIGBUS); - return; -#endif - - if (debugger_fault_handler(regs)) { - regs->msr |= MSR_RI; - return; - } - - if (check_io_access(regs)) - return; - #if defined(CONFIG_4xx) && !defined(CONFIG_440A) if (reason & ESR_IMCP) { printk("Instruction"); @@ -471,6 +443,42 @@ void machine_check_exception(struct pt_regs *regs) } #endif /* CONFIG_4xx */ + return 0; +} + +void machine_check_exception(struct pt_regs *regs) +{ + int recover = 0; + + /* See if any machine dependent calls */ + if (ppc_md.machine_check_exception) + recover = ppc_md.machine_check_exception(regs); + else + recover = generic_machine_check_exception(regs); + + if (recover) + return; + + if (user_mode(regs)) { + regs->msr |= MSR_RI; + _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); + return; + } + +#if defined(CONFIG_8xx) && defined(CONFIG_PCI) + /* the qspan pci read routines can cause machine checks -- Cort */ + bad_page_fault(regs, regs->dar, SIGBUS); + return; +#endif + + if (debugger_fault_handler(regs)) { + regs->msr |= MSR_RI; + return; + } + + if (check_io_access(regs)) + return; + if (debugger_fault_handler(regs)) return; die("Machine check", regs, SIGBUS); From 2578bfae84a78bd46fdbc0d2f9d39e9fbc9c8a3f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 21 Sep 2007 10:16:20 +1000 Subject: [PATCH 0356/2804] [POWERPC] Create and use CONFIG_WORD_SIZE Linus made this suggestion for the x86 merge and this starts the process for powerpc. We assume that CONFIG_PPC64 implies CONFIG_PPC_MERGE and CONFIG_PPC_STD_MMU_32 implies CONFIG_PPC_STD_MMU. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 5 +++++ arch/powerpc/Makefile | 21 ++++++++++++--------- arch/powerpc/kernel/Makefile | 30 +++++++++++++----------------- arch/powerpc/lib/Makefile | 7 ++++--- arch/powerpc/mm/Makefile | 13 ++++++++----- arch/ppc/Kconfig | 4 ++++ 6 files changed, 46 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 26126d27d756..45e86c751f11 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -14,6 +14,11 @@ config 64BIT bool default y if PPC64 +config WORD_SIZE + int + default 64 if PPC64 + default 32 if !PPC64 + config PPC_MERGE def_bool y diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 87aff5372d6e..71632b20b81d 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -39,7 +39,6 @@ KBUILD_DEFCONFIG := $(shell uname -m)_defconfig ifeq ($(CONFIG_PPC64),y) OLDARCH := ppc64 -SZ := 64 new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi) @@ -49,16 +48,21 @@ endif else OLDARCH := ppc -SZ := 32 +endif + +# It seems there are times we use this Makefile without +# including the config file, but this replicates the old behaviour +ifeq ($(CONFIG_WORD_SIZE),) +CONFIG_WORD_SIZE := 32 endif UTS_MACHINE := $(OLDARCH) ifeq ($(HAS_BIARCH),y) -override AS += -a$(SZ) -override LD += -m elf$(SZ)ppc -override CC += -m$(SZ) -override AR := GNUTARGET=elf$(SZ)-powerpc $(AR) +override AS += -a$(CONFIG_WORD_SIZE) +override LD += -m elf$(CONFIG_WORD_SIZE)ppc +override CC += -m$(CONFIG_WORD_SIZE) +override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR) endif LDFLAGS_vmlinux := -Bstatic @@ -72,7 +76,7 @@ AFLAGS += $(AFLAGS-y) CFLAGS += -msoft-float -pipe $(CFLAGS-y) CPP = $(CC) -E $(CFLAGS) -CHECKFLAGS += -m$(SZ) -D__powerpc__ -D__powerpc$(SZ)__ +CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__ ifeq ($(CONFIG_PPC64),y) GCC_BROKEN_VEC := $(shell if [ $(call cc-version) -lt 0400 ] ; then echo "y"; fi) @@ -120,8 +124,7 @@ cpu-as-$(CONFIG_E200) += -Wa,-me200 AFLAGS += $(cpu-as-y) CFLAGS += $(cpu-as-y) -head-y := arch/powerpc/kernel/head_32.o -head-$(CONFIG_PPC64) := arch/powerpc/kernel/head_64.o +head-y := arch/powerpc/kernel/head_$(CONFIG_WORD_SIZE).o head-$(CONFIG_8xx) := arch/powerpc/kernel/head_8xx.o head-$(CONFIG_40x) := arch/powerpc/kernel/head_40x.o head-$(CONFIG_44x) := arch/powerpc/kernel/head_44x.o diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b37165effb65..fb33a7e71941 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -38,10 +38,10 @@ obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o obj-$(CONFIG_TAU) += tau_6xx.o -obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o -obj32-$(CONFIG_HIBERNATION) += swsusp_32.o -obj64-$(CONFIG_HIBERNATION) += swsusp_64.o swsusp_asm64.o -obj32-$(CONFIG_MODULES) += module_32.o +obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \ + swsusp_$(CONFIG_WORD_SIZE).o +obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o +obj-$(CONFIG_MODULES) += module_$(CONFIG_WORD_SIZE).o ifeq ($(CONFIG_PPC_MERGE),y) @@ -54,9 +54,10 @@ extra-$(CONFIG_8xx) := head_8xx.o extra-y += vmlinux.lds obj-y += time.o prom.o traps.o setup-common.o \ - udbg.o misc.o io.o -obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o -obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o + udbg.o misc.o io.o \ + misc_$(CONFIG_WORD_SIZE).o +obj-$(CONFIG_PPC32) += entry_32.o setup_32.o +obj-$(CONFIG_PPC64) += dma_64.o iommu.o obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o @@ -64,16 +65,12 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o -module-$(CONFIG_PPC64) += module_64.o -obj-$(CONFIG_MODULES) += $(module-y) - -pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o isa-bridge.o -pci32-$(CONFIG_PPC32) := pci_32.o -obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) pci-common.o +pci64-$(CONFIG_PPC64) += pci_dn.o isa-bridge.o +obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \ + pci-common.o obj-$(CONFIG_PCI_MSI) += msi.o -kexec-$(CONFIG_PPC64) := machine_kexec_64.o -kexec-$(CONFIG_PPC32) := machine_kexec_32.o -obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y) +obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \ + machine_kexec_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_AUDIT) += audit.o obj64-$(CONFIG_AUDIT) += compat_audit.o @@ -87,7 +84,6 @@ smpobj-$(CONFIG_SMP) += smp.o endif -obj-$(CONFIG_PPC32) += $(obj32-y) obj-$(CONFIG_PPC64) += $(obj64-y) extra-$(CONFIG_PPC_FPU) += fpu.o diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 23bbb1ea7f9f..65d492e316a6 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -7,11 +7,12 @@ EXTRA_CFLAGS += -mno-minimal-toc endif ifeq ($(CONFIG_PPC_MERGE),y) -obj-y := string.o alloc.o -obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o +obj-y := string.o alloc.o \ + checksum_$(CONFIG_WORD_SIZE).o +obj-$(CONFIG_PPC32) += div64.o copy_32.o endif -obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ +obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ memcpy_64.o usercopy_64.o mem_64.o string.o obj-$(CONFIG_QUICC_ENGINE) += rheap.o obj-$(CONFIG_XMON) += sstep.o diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index bf20fa688809..20629ae95c50 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -6,13 +6,16 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif -obj-y := fault.o mem.o lmb.o -obj-$(CONFIG_PPC32) += init_32.o pgtable_32.o mmu_context_32.o +obj-y := fault.o mem.o lmb.o \ + init_$(CONFIG_WORD_SIZE).o \ + pgtable_$(CONFIG_WORD_SIZE).o \ + mmu_context_$(CONFIG_WORD_SIZE).o hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o -obj-$(CONFIG_PPC64) += init_64.o pgtable_64.o mmu_context_64.o \ - hash_utils_64.o hash_low_64.o tlb_64.o \ +obj-$(CONFIG_PPC64) += hash_utils_64.o \ slb_low.o slb.o stab.o mmap.o $(hash-y) -obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o tlb_32.o +obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o +obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ + tlb_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_40x) += 40x_mmu.o obj-$(CONFIG_44x) += 44x_mmu.o obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index c1b34eb383cf..c2087f645ad3 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -4,6 +4,10 @@ mainmenu "Linux/PowerPC Kernel Configuration" +config WORD_SIZE + int + default 32 + config MMU bool default y From 94987aff23bcdd7cee92edf02c2f4ef259d1cbf6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 21 Sep 2007 11:52:36 +1000 Subject: [PATCH 0357/2804] [POWERPC] Disable power management for arch/ppc Currently the prep_defconfig in arch/ppc won't build due to swsusp being broken. This patch avoids the problem by essentially disabling all power management on those platforms left in arch/ppc. Signed-off-by: Paul Mackerras --- arch/ppc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index c2087f645ad3..20dce4681259 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -1016,7 +1016,7 @@ config CMDLINE some command-line options at build time by entering them here. In most cases you will need to specify the root device here. -if !44x || BROKEN +if BROKEN source kernel/power/Kconfig endif From df174e3be88d4352bfcfe20d11adc671d2961c79 Mon Sep 17 00:00:00 2001 From: Ed Swarthout Date: Fri, 21 Sep 2007 12:53:02 +1000 Subject: [PATCH 0358/2804] [POWERPC] Add memory regions to the kcore list for 32-bit machines The entries are only 32-bit, so restrict the virtual address to stay below 0xffff_ffff. With KERNELBASE set to 0xc000_0000, this in effect restricts access to the first 1GB of real memory. Make setup_kcore conditional on CONFIG_PROC_KCORE for both 32/64. Signed-off-by: Ed Swarthout Signed-off-by: Paul Mackerras --- arch/powerpc/mm/init_32.c | 37 +++++++++++++++++++++++++++++++++++++ arch/powerpc/mm/init_64.c | 2 ++ 2 files changed, 39 insertions(+) diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index d65995ae8273..27c234fb5118 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -255,3 +255,40 @@ void free_initrd_mem(unsigned long start, unsigned long end) } } #endif + +#ifdef CONFIG_PROC_KCORE +static struct kcore_list kcore_vmem; + +static int __init setup_kcore(void) +{ + int i; + + for (i = 0; i < lmb.memory.cnt; i++) { + unsigned long base; + unsigned long size; + struct kcore_list *kcore_mem; + + base = lmb.memory.region[i].base; + size = lmb.memory.region[i].size; + + kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC); + if (!kcore_mem) + panic("%s: kmalloc failed\n", __FUNCTION__); + + /* must stay under 32 bits */ + if ( 0xfffffffful - (unsigned long)__va(base) < size) { + size = 0xfffffffful - (unsigned long)(__va(base)); + printk(KERN_DEBUG "setup_kcore: restrict size=%lx\n", + size); + } + + kclist_add(kcore_mem, __va(base), size); + } + + kclist_add(&kcore_vmem, (void *)VMALLOC_START, + VMALLOC_END-VMALLOC_START); + + return 0; +} +module_init(setup_kcore); +#endif diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index 9f27bb56a61d..fa90f6561b9f 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -113,6 +113,7 @@ void free_initrd_mem(unsigned long start, unsigned long end) } #endif +#ifdef CONFIG_PROC_KCORE static struct kcore_list kcore_vmem; static int __init setup_kcore(void) @@ -139,6 +140,7 @@ static int __init setup_kcore(void) return 0; } module_init(setup_kcore); +#endif static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags) { From aa3be5f32db137bc4404f32a24b36fb47d48d260 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Fri, 21 Sep 2007 13:26:02 +1000 Subject: [PATCH 0359/2804] [POWERPC] Implement {read,update}_persistent_clock With these functions implemented we cooperate better with the generic timekeeping code. This obsoletes the need for the timer sysdev as a bonus. Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 3 ++ arch/powerpc/kernel/time.c | 85 +++++++++++------------------------- arch/powerpc/sysdev/Makefile | 5 --- arch/powerpc/sysdev/timer.c | 81 ---------------------------------- 4 files changed, 29 insertions(+), 145 deletions(-) delete mode 100644 arch/powerpc/sysdev/timer.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 45e86c751f11..6468cd9d72e4 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -26,6 +26,9 @@ config MMU bool default y +config GENERIC_CMOS_UPDATE + def_bool y + config GENERIC_HARDIRQS bool default y diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index d95e68c0a6b3..b94e4dffba19 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -73,16 +73,11 @@ #include #endif -/* keep track of when we need to update the rtc */ -time_t last_rtc_update; #ifdef CONFIG_PPC_ISERIES static unsigned long __initdata iSeries_recal_titan; static signed long __initdata iSeries_recal_tb; #endif -/* The decrementer counts down by 128 every 128ns on a 601. */ -#define DECREMENTER_COUNT_601 (1000000000 / HZ) - #define XSEC_PER_SEC (1024*1024) #ifdef CONFIG_PPC64 @@ -348,39 +343,6 @@ void udelay(unsigned long usecs) } EXPORT_SYMBOL(udelay); -static __inline__ void timer_check_rtc(void) -{ - /* - * update the rtc when needed, this should be performed on the - * right fraction of a second. Half or full second ? - * Full second works on mk48t59 clocks, others need testing. - * Note that this update is basically only used through - * the adjtimex system calls. Setting the HW clock in - * any other way is a /dev/rtc and userland business. - * This is still wrong by -0.5/+1.5 jiffies because of the - * timer interrupt resolution and possible delay, but here we - * hit a quantization limit which can only be solved by higher - * resolution timers and decoupling time management from timer - * interrupts. This is also wrong on the clocks - * which require being written at the half second boundary. - * We should have an rtc call that only sets the minutes and - * seconds like on Intel to avoid problems with non UTC clocks. - */ - if (ppc_md.set_rtc_time && ntp_synced() && - xtime.tv_sec - last_rtc_update >= 659 && - abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ) { - struct rtc_time tm; - to_tm(xtime.tv_sec + 1 + timezone_offset, &tm); - tm.tm_year -= 1900; - tm.tm_mon -= 1; - if (ppc_md.set_rtc_time(&tm) == 0) - last_rtc_update = xtime.tv_sec + 1; - else - /* Try again one minute later */ - last_rtc_update += 60; - } -} - /* * This version of gettimeofday has microsecond resolution. */ @@ -689,7 +651,6 @@ void timer_interrupt(struct pt_regs * regs) tb_last_jiffy = tb_next_jiffy; do_timer(1); timer_recalc_offset(tb_last_jiffy); - timer_check_rtc(); } write_sequnlock(&xtime_lock); } @@ -801,11 +762,6 @@ int do_settimeofday(struct timespec *tv) set_normalized_timespec(&xtime, new_sec, new_nsec); set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - /* In case of a large backwards jump in time with NTP, we want the - * clock to be updated as soon as the PLL is again in lock. - */ - last_rtc_update = new_sec - 658; - ntp_clear(); new_xsec = xtime.tv_nsec; @@ -881,12 +837,35 @@ void __init generic_calibrate_decr(void) #endif } -unsigned long get_boot_time(void) +int update_persistent_clock(struct timespec now) { struct rtc_time tm; - if (ppc_md.get_boot_time) - return ppc_md.get_boot_time(); + if (!ppc_md.set_rtc_time) + return 0; + + to_tm(now.tv_sec + 1 + timezone_offset, &tm); + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + return ppc_md.set_rtc_time(&tm); +} + +unsigned long read_persistent_clock(void) +{ + struct rtc_time tm; + static int first = 1; + + /* XXX this is a litle fragile but will work okay in the short term */ + if (first) { + first = 0; + if (ppc_md.time_init) + timezone_offset = ppc_md.time_init(); + + /* get_boot_time() isn't guaranteed to be safe to call late */ + if (ppc_md.get_boot_time) + return ppc_md.get_boot_time() -timezone_offset; + } if (!ppc_md.get_rtc_time) return 0; ppc_md.get_rtc_time(&tm); @@ -898,14 +877,10 @@ unsigned long get_boot_time(void) void __init time_init(void) { unsigned long flags; - unsigned long tm = 0; struct div_result res; u64 scale, x; unsigned shift; - if (ppc_md.time_init != NULL) - timezone_offset = ppc_md.time_init(); - if (__USE_RTC()) { /* 601 processor: dec counts down by 128 every 128ns */ ppc_tb_freq = 1000000000; @@ -980,19 +955,14 @@ void __init time_init(void) /* Save the current timebase to pretty up CONFIG_PRINTK_TIME */ boot_tb = get_tb_or_rtc(); - tm = get_boot_time(); - write_seqlock_irqsave(&xtime_lock, flags); /* If platform provided a timezone (pmac), we correct the time */ if (timezone_offset) { sys_tz.tz_minuteswest = -timezone_offset / 60; sys_tz.tz_dsttime = 0; - tm -= timezone_offset; } - xtime.tv_sec = tm; - xtime.tv_nsec = 0; do_gtod.varp = &do_gtod.vars[0]; do_gtod.var_idx = 0; do_gtod.varp->tb_orig_stamp = tb_last_jiffy; @@ -1010,9 +980,6 @@ void __init time_init(void) time_freq = 0; - last_rtc_update = xtime.tv_sec; - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); write_sequnlock_irqrestore(&xtime_lock, flags); /* Not exact, but the timer interrupt takes care of this */ diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index ed41dc0a310f..b0ea8e9495e8 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -21,11 +21,6 @@ obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \ obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o obj-$(CONFIG_AXON_RAM) += axonram.o -# contains only the suspend handler for time -ifeq ($(CONFIG_RTC_CLASS),) -obj-$(CONFIG_PM) += timer.o -endif - ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_I8259) += i8259.o diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c deleted file mode 100644 index e81e7ec2e799..000000000000 --- a/arch/powerpc/sysdev/timer.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Common code to keep time when machine suspends. - * - * Copyright 2007 Johannes Berg - * - * GPLv2 - */ - -#include -#include -#include - -static unsigned long suspend_rtc_time; - -/* - * Reset the time after a sleep. - */ -static int timer_resume(struct sys_device *dev) -{ - struct timeval tv; - struct timespec ts; - struct rtc_time cur_rtc_tm; - unsigned long cur_rtc_time, diff; - - /* get current RTC time and convert to seconds */ - get_rtc_time(&cur_rtc_tm); - cur_rtc_time = mktime(cur_rtc_tm.tm_year + 1900, - cur_rtc_tm.tm_mon + 1, - cur_rtc_tm.tm_mday, - cur_rtc_tm.tm_hour, - cur_rtc_tm.tm_min, - cur_rtc_tm.tm_sec); - - diff = cur_rtc_time - suspend_rtc_time; - - /* adjust time of day by seconds that elapsed while - * we were suspended */ - do_gettimeofday(&tv); - ts.tv_sec = tv.tv_sec + diff; - ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC; - do_settimeofday(&ts); - - return 0; -} - -static int timer_suspend(struct sys_device *dev, pm_message_t state) -{ - struct rtc_time suspend_rtc_tm; - WARN_ON(!ppc_md.get_rtc_time); - - get_rtc_time(&suspend_rtc_tm); - suspend_rtc_time = mktime(suspend_rtc_tm.tm_year + 1900, - suspend_rtc_tm.tm_mon + 1, - suspend_rtc_tm.tm_mday, - suspend_rtc_tm.tm_hour, - suspend_rtc_tm.tm_min, - suspend_rtc_tm.tm_sec); - - return 0; -} - -static struct sysdev_class timer_sysclass = { - .resume = timer_resume, - .suspend = timer_suspend, - set_kset_name("timer"), -}; - -static struct sys_device device_timer = { - .id = 0, - .cls = &timer_sysclass, -}; - -static int time_init_device(void) -{ - int error = sysdev_class_register(&timer_sysclass); - if (!error) - error = sysdev_register(&device_timer); - return error; -} - -device_initcall(time_init_device); From 4a4cfe3836916e12282ceb5c4bdd799dc71af567 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Sat, 22 Sep 2007 07:35:52 +1000 Subject: [PATCH 0360/2804] [POWERPC] Implement generic time of day clocksource for powerpc Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 6 + arch/powerpc/kernel/time.c | 270 ++++++++++++++----------------------- 2 files changed, 104 insertions(+), 172 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 6468cd9d72e4..6819a94f2cac 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -29,6 +29,12 @@ config MMU config GENERIC_CMOS_UPDATE def_bool y +config GENERIC_TIME + def_bool y + +config GENERIC_TIME_VSYSCALL + def_bool y + config GENERIC_HARDIRQS bool default y diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index b94e4dffba19..e71a0d8c597a 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -65,17 +65,44 @@ #include #include #include -#ifdef CONFIG_PPC64 #include -#endif #ifdef CONFIG_PPC_ISERIES #include #include #endif +/* powerpc clocksource/clockevent code */ + +#include + +static cycle_t rtc_read(void); +static struct clocksource clocksource_rtc = { + .name = "rtc", + .rating = 400, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .mask = CLOCKSOURCE_MASK(64), + .shift = 22, + .mult = 0, /* To be filled in */ + .read = rtc_read, +}; + +static cycle_t timebase_read(void); +static struct clocksource clocksource_timebase = { + .name = "timebase", + .rating = 400, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .mask = CLOCKSOURCE_MASK(64), + .shift = 22, + .mult = 0, /* To be filled in */ + .read = timebase_read, +}; + #ifdef CONFIG_PPC_ISERIES static unsigned long __initdata iSeries_recal_titan; static signed long __initdata iSeries_recal_tb; + +/* Forward declaration is only needed for iSereis compiles */ +void __init clocksource_init(void); #endif #define XSEC_PER_SEC (1024*1024) @@ -343,65 +370,6 @@ void udelay(unsigned long usecs) } EXPORT_SYMBOL(udelay); -/* - * This version of gettimeofday has microsecond resolution. - */ -static inline void __do_gettimeofday(struct timeval *tv) -{ - unsigned long sec, usec; - u64 tb_ticks, xsec; - struct gettimeofday_vars *temp_varp; - u64 temp_tb_to_xs, temp_stamp_xsec; - - /* - * These calculations are faster (gets rid of divides) - * if done in units of 1/2^20 rather than microseconds. - * The conversion to microseconds at the end is done - * without a divide (and in fact, without a multiply) - */ - temp_varp = do_gtod.varp; - - /* Sampling the time base must be done after loading - * do_gtod.varp in order to avoid racing with update_gtod. - */ - data_barrier(temp_varp); - tb_ticks = get_tb() - temp_varp->tb_orig_stamp; - temp_tb_to_xs = temp_varp->tb_to_xs; - temp_stamp_xsec = temp_varp->stamp_xsec; - xsec = temp_stamp_xsec + mulhdu(tb_ticks, temp_tb_to_xs); - sec = xsec / XSEC_PER_SEC; - usec = (unsigned long)xsec & (XSEC_PER_SEC - 1); - usec = SCALE_XSEC(usec, 1000000); - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -void do_gettimeofday(struct timeval *tv) -{ - if (__USE_RTC()) { - /* do this the old way */ - unsigned long flags, seq; - unsigned int sec, nsec, usec; - - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - sec = xtime.tv_sec; - nsec = xtime.tv_nsec + tb_ticks_since(tb_last_jiffy); - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - usec = nsec / 1000; - while (usec >= 1000000) { - usec -= 1000000; - ++sec; - } - tv->tv_sec = sec; - tv->tv_usec = usec; - return; - } - __do_gettimeofday(tv); -} - -EXPORT_SYMBOL(do_gettimeofday); /* * There are two copies of tb_to_xs and stamp_xsec so that no @@ -447,56 +415,6 @@ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, ++(vdso_data->tb_update_count); } -/* - * When the timebase - tb_orig_stamp gets too big, we do a manipulation - * between tb_orig_stamp and stamp_xsec. The goal here is to keep the - * difference tb - tb_orig_stamp small enough to always fit inside a - * 32 bits number. This is a requirement of our fast 32 bits userland - * implementation in the vdso. If we "miss" a call to this function - * (interrupt latency, CPU locked in a spinlock, ...) and we end up - * with a too big difference, then the vdso will fallback to calling - * the syscall - */ -static __inline__ void timer_recalc_offset(u64 cur_tb) -{ - unsigned long offset; - u64 new_stamp_xsec; - u64 tlen, t2x; - u64 tb, xsec_old, xsec_new; - struct gettimeofday_vars *varp; - - if (__USE_RTC()) - return; - tlen = current_tick_length(); - offset = cur_tb - do_gtod.varp->tb_orig_stamp; - if (tlen == last_tick_len && offset < 0x80000000u) - return; - if (tlen != last_tick_len) { - t2x = mulhdu(tlen << TICKLEN_SHIFT, ticklen_to_xs); - last_tick_len = tlen; - } else - t2x = do_gtod.varp->tb_to_xs; - new_stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC; - do_div(new_stamp_xsec, 1000000000); - new_stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC; - - ++vdso_data->tb_update_count; - smp_mb(); - - /* - * Make sure time doesn't go backwards for userspace gettimeofday. - */ - tb = get_tb(); - varp = do_gtod.varp; - xsec_old = mulhdu(tb - varp->tb_orig_stamp, varp->tb_to_xs) - + varp->stamp_xsec; - xsec_new = mulhdu(tb - cur_tb, t2x) + new_stamp_xsec; - if (xsec_new < xsec_old) - new_stamp_xsec += xsec_old - xsec_new; - - update_gtod(cur_tb, new_stamp_xsec, t2x); -} - #ifdef CONFIG_SMP unsigned long profile_pc(struct pt_regs *regs) { @@ -568,6 +486,8 @@ static int __init iSeries_tb_recal(void) iSeries_recal_titan = titan; iSeries_recal_tb = tb; + /* Called here as now we know accurate values for the timebase */ + clocksource_init(); return 0; } late_initcall(iSeries_tb_recal); @@ -650,7 +570,6 @@ void timer_interrupt(struct pt_regs * regs) if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) { tb_last_jiffy = tb_next_jiffy; do_timer(1); - timer_recalc_offset(tb_last_jiffy); } write_sequnlock(&xtime_lock); } @@ -722,66 +641,6 @@ unsigned long long sched_clock(void) return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift; } -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, new_sec = tv->tv_sec; - long wtm_nsec, new_nsec = tv->tv_nsec; - unsigned long flags; - u64 new_xsec; - unsigned long tb_delta; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irqsave(&xtime_lock, flags); - - /* - * Updating the RTC is not the job of this code. If the time is - * stepped under NTP, the RTC will be updated after STA_UNSYNC - * is cleared. Tools like clock/hwclock either copy the RTC - * to the system time, in which case there is no point in writing - * to the RTC again, or write to the RTC but then they don't call - * settimeofday to perform this operation. - */ - - /* Make userspace gettimeofday spin until we're done. */ - ++vdso_data->tb_update_count; - smp_mb(); - - /* - * Subtract off the number of nanoseconds since the - * beginning of the last tick. - */ - tb_delta = tb_ticks_since(tb_last_jiffy); - tb_delta = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); /* in xsec */ - new_nsec -= SCALE_XSEC(tb_delta, 1000000000); - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); - - set_normalized_timespec(&xtime, new_sec, new_nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - - new_xsec = xtime.tv_nsec; - if (new_xsec != 0) { - new_xsec *= XSEC_PER_SEC; - do_div(new_xsec, NSEC_PER_SEC); - } - new_xsec += (u64)xtime.tv_sec * XSEC_PER_SEC; - update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); - - vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; - vdso_data->tz_dsttime = sys_tz.tz_dsttime; - - write_sequnlock_irqrestore(&xtime_lock, flags); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - static int __init get_freq(char *name, int cells, unsigned long *val) { struct device_node *cpu; @@ -873,6 +732,69 @@ unsigned long read_persistent_clock(void) tm.tm_hour, tm.tm_min, tm.tm_sec); } +/* clocksource code */ +static cycle_t rtc_read(void) +{ + return (cycle_t)get_rtc(); +} + +static cycle_t timebase_read(void) +{ + return (cycle_t)get_tb(); +} + +void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) +{ + u64 t2x, stamp_xsec; + + if (clock != &clocksource_timebase) + return; + + /* Make userspace gettimeofday spin until we're done. */ + ++vdso_data->tb_update_count; + smp_mb(); + + /* XXX this assumes clock->shift == 22 */ + /* 4611686018 ~= 2^(20+64-22) / 1e9 */ + t2x = (u64) clock->mult * 4611686018ULL; + stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC; + do_div(stamp_xsec, 1000000000); + stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC; + update_gtod(clock->cycle_last, stamp_xsec, t2x); +} + +void update_vsyscall_tz(void) +{ + /* Make userspace gettimeofday spin until we're done. */ + ++vdso_data->tb_update_count; + smp_mb(); + vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; + vdso_data->tz_dsttime = sys_tz.tz_dsttime; + smp_mb(); + ++vdso_data->tb_update_count; +} + +void __init clocksource_init(void) +{ + struct clocksource *clock; + + if (__USE_RTC()) + clock = &clocksource_rtc; + else + clock = &clocksource_timebase; + + clock->mult = clocksource_hz2mult(tb_ticks_per_sec, clock->shift); + + if (clocksource_register(clock)) { + printk(KERN_ERR "clocksource: %s is already registered\n", + clock->name); + return; + } + + printk(KERN_INFO "clocksource: %s mult[%x] shift[%d] registered\n", + clock->name, clock->mult, clock->shift); +} + /* This function is only called on the boot processor */ void __init time_init(void) { @@ -982,6 +904,10 @@ void __init time_init(void) write_sequnlock_irqrestore(&xtime_lock, flags); + /* Register the clocksource, if we're not running on iSeries */ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + clocksource_init(); + /* Not exact, but the timer interrupt takes care of this */ set_dec(tb_ticks_per_jiffy); } From c546726293912c932f3c14d06b0f68e175d70781 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 21 Sep 2007 14:29:28 +1000 Subject: [PATCH 0361/2804] [POWERPC] Remove debug printk from vio_bus_init As it just adds noise to the boot messages. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 62c1bc12ea39..54645baab652 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -317,11 +317,8 @@ static int __init vio_bus_init(void) * the device tree. Drivers will associate with them later. */ for (of_node = node_vroot->child; of_node != NULL; - of_node = of_node->sibling) { - printk(KERN_DEBUG "%s: processing %p\n", - __FUNCTION__, of_node); + of_node = of_node->sibling) vio_register_device_node(of_node); - } of_node_put(node_vroot); } From c868078ed82e3651b16f68a420ae7568de2102db Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 21 Sep 2007 14:31:02 +1000 Subject: [PATCH 0362/2804] [POWERPC] Simplify vio_bus_init a little for legacy iSeries iSeries_vio_dev was already statically initialised and we can remove one set of #ifdef CONFIG_PPC_ISERIES guards. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 54645baab652..ee15c2280aea 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -64,6 +64,12 @@ static void __init iommu_vio_init(void) printk("Virtual Bus VETH TCE table failed.\n"); if (!iommu_init_table(&vio_iommu_table, -1)) printk("Virtual Bus VIO TCE table failed.\n"); + vio_bus_device.dev.archdata.dma_ops = &dma_iommu_ops; + vio_bus_device.dev.archdata.dma_data = &vio_iommu_table; +} +#else +static void __init iommu_vio_init(void) +{ } #endif @@ -282,14 +288,8 @@ static int __init vio_bus_init(void) int err; struct device_node *node_vroot; -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES)) { + if (firmware_has_feature(FW_FEATURE_ISERIES)) iommu_vio_init(); - vio_bus_device.dev.archdata.dma_ops = &dma_iommu_ops; - vio_bus_device.dev.archdata.dma_data = &vio_iommu_table; - iSeries_vio_dev = &vio_bus_device.dev; - } -#endif /* CONFIG_PPC_ISERIES */ err = bus_register(&vio_bus_type); if (err) { From 6fccab26df4f59815d7ec912e4111a92807780de Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 21 Sep 2007 14:32:05 +1000 Subject: [PATCH 0363/2804] [POWERPC] Make vio_bus_type static Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 4 +++- include/asm-powerpc/vio.h | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index ee15c2280aea..1d7b272b3737 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -39,6 +39,8 @@ extern struct kset devices_subsys; /* needed for vio_find_name() */ +static struct bus_type vio_bus_type; + static struct vio_dev vio_bus_device = { /* fake "parent" device */ .name = vio_bus_device.dev.bus_id, .type = "", @@ -388,7 +390,7 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp, return 0; } -struct bus_type vio_bus_type = { +static struct bus_type vio_bus_type = { .name = "vio", .dev_attrs = vio_dev_attrs, .uevent = vio_hotplug, diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h index 3a0975e2adad..598d111e8098 100644 --- a/include/asm-powerpc/vio.h +++ b/include/asm-powerpc/vio.h @@ -63,7 +63,6 @@ struct vio_driver { }; extern struct dma_mapping_ops vio_dma_ops; -extern struct bus_type vio_bus_type; extern int vio_register_driver(struct vio_driver *drv); extern void vio_unregister_driver(struct vio_driver *drv); From e47654d016c68a02f654ac16951577804f7789c7 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Sat, 22 Sep 2007 09:03:34 +1000 Subject: [PATCH 0364/2804] [POWERPC] boot: Record header bytes in gunzip_start Record the number of header bytes skipped in the total bytes read field. This is needed for the initramfs parsing code to find the end of the zip file. Signed-off-by: Milton Miller Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/gunzip_util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/boot/gunzip_util.c b/arch/powerpc/boot/gunzip_util.c index df8ab07e9ff4..e1e215e16983 100644 --- a/arch/powerpc/boot/gunzip_util.c +++ b/arch/powerpc/boot/gunzip_util.c @@ -78,6 +78,7 @@ void gunzip_start(struct gunzip_state *state, void *src, int srclen) fatal("inflateInit2 returned %d\n\r", r); } + state->s.total_in = hdrlen; state->s.next_in = src + hdrlen; state->s.avail_in = srclen - hdrlen; } From 51a505d73bfed863135861fdc0496a09766b69d5 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Sat, 22 Sep 2007 09:03:52 +1000 Subject: [PATCH 0365/2804] [POWERPC] boot: Simplify gunzip_finish Call gunzip_partial to calculate the remaining length and copy the data to the user buffer. This makes it shorter and reduces duplication. Signed-off-by: Milton Miller Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/gunzip_util.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/boot/gunzip_util.c b/arch/powerpc/boot/gunzip_util.c index e1e215e16983..ef2aed0f63ca 100644 --- a/arch/powerpc/boot/gunzip_util.c +++ b/arch/powerpc/boot/gunzip_util.c @@ -194,13 +194,10 @@ int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen) { int len; + len = gunzip_partial(state, dst, dstlen); + if (state->s.workspace) { - len = gunzip_partial(state, dst, dstlen); zlib_inflateEnd(&state->s); - } else { - /* uncompressed image */ - len = min(state->s.avail_in, (unsigned)dstlen); - memcpy(dst, state->s.next_in, len); } return len; From 27ff35d9026b5d41d66ed95b65d7819db4cf5fb1 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 25 Sep 2007 06:09:11 +1000 Subject: [PATCH 0366/2804] [POWERPC] bootwrapper: Factor out dt_set_mac_address() This allows callers to set addresses one at a time when that would be more convenient. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/devtree.c | 31 +++++++++++++++++-------------- arch/powerpc/boot/ops.h | 1 + 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c index 549463bf5eec..e5dfe4497313 100644 --- a/arch/powerpc/boot/devtree.c +++ b/arch/powerpc/boot/devtree.c @@ -88,29 +88,32 @@ void dt_fixup_clock(const char *path, u32 freq) } } +void dt_fixup_mac_address(u32 index, const u8 *addr) +{ + void *devp = find_node_by_prop_value(NULL, "linux,network-index", + (void*)&index, sizeof(index)); + + if (devp) { + printf("ENET%d: local-mac-address <-" + " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index, + addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + + setprop(devp, "local-mac-address", addr, 6); + } +} + void __dt_fixup_mac_addresses(u32 startindex, ...) { va_list ap; u32 index = startindex; - void *devp; const u8 *addr; va_start(ap, startindex); - while ((addr = va_arg(ap, const u8 *))) { - devp = find_node_by_prop_value(NULL, "linux,network-index", - (void*)&index, sizeof(index)); - if (devp) { - printf("ENET%d: local-mac-address <-" - " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index, - addr[0], addr[1], addr[2], - addr[3], addr[4], addr[5]); + while ((addr = va_arg(ap, const u8 *))) + dt_fixup_mac_address(index++, addr); - setprop(devp, "local-mac-address", addr, 6); - } - - index++; - } va_end(ap); } diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index f639fcab2c44..e948e57abef8 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -161,6 +161,7 @@ static inline void *find_node_by_devtype(const void *prev, void dt_fixup_memory(u64 start, u64 size); void dt_fixup_cpu_clocks(u32 cpufreq, u32 tbfreq, u32 busfreq); void dt_fixup_clock(const char *path, u32 freq); +void dt_fixup_mac_address(u32 index, const u8 *addr); void __dt_fixup_mac_addresses(u32 startindex, ...); #define dt_fixup_mac_addresses(...) \ __dt_fixup_mac_addresses(0, __VA_ARGS__, NULL) From fec6047047fda307e47b9e87697144a89528c752 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 25 Sep 2007 06:09:49 +1000 Subject: [PATCH 0367/2804] [POWERPC] bootwrapper: Add PlanetCore firmware support This is a library that board code can use to extract information from the PlanetCore configuration keys. PlanetCore is used on various boards from Embedded Planet. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 2 +- arch/powerpc/boot/planetcore.c | 166 +++++++++++++++++++++++++++++++++ arch/powerpc/boot/planetcore.h | 49 ++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/planetcore.c create mode 100644 arch/powerpc/boot/planetcore.h diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index b63e423428c7..a6bba9a69e66 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -45,7 +45,7 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \ - cpm-serial.c stdlib.c mpc52xx-psc.c + cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ diff --git a/arch/powerpc/boot/planetcore.c b/arch/powerpc/boot/planetcore.c new file mode 100644 index 000000000000..0d8558a475bb --- /dev/null +++ b/arch/powerpc/boot/planetcore.c @@ -0,0 +1,166 @@ +/* + * PlanetCore configuration data support functions + * + * Author: Scott Wood + * + * Copyright (c) 2007 Freescale Semiconductor, 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 "stdio.h" +#include "stdlib.h" +#include "ops.h" +#include "planetcore.h" +#include "io.h" + +/* PlanetCore passes information to the OS in the form of + * a table of key=value strings, separated by newlines. + * + * The list is terminated by an empty string (i.e. two + * consecutive newlines). + * + * To make it easier to parse, we first convert all the + * newlines into null bytes. + */ + +void planetcore_prepare_table(char *table) +{ + do { + if (*table == '\n') + *table = 0; + + table++; + } while (*(table - 1) || *table != '\n'); + + *table = 0; +} + +const char *planetcore_get_key(const char *table, const char *key) +{ + int keylen = strlen(key); + + do { + if (!strncmp(table, key, keylen) && table[keylen] == '=') + return table + keylen + 1; + + table += strlen(table) + 1; + } while (strlen(table) != 0); + + return NULL; +} + +int planetcore_get_decimal(const char *table, const char *key, u64 *val) +{ + const char *str = planetcore_get_key(table, key); + if (!str) + return 0; + + *val = strtoull(str, NULL, 10); + return 1; +} + +int planetcore_get_hex(const char *table, const char *key, u64 *val) +{ + const char *str = planetcore_get_key(table, key); + if (!str) + return 0; + + *val = strtoull(str, NULL, 16); + return 1; +} + +static u64 mac_table[4] = { + 0x000000000000, + 0x000000800000, + 0x000000400000, + 0x000000c00000, +}; + +void planetcore_set_mac_addrs(const char *table) +{ + u8 addr[4][6]; + u64 int_addr; + u32 i; + int j; + + if (!planetcore_get_hex(table, PLANETCORE_KEY_MAC_ADDR, &int_addr)) + return; + + for (i = 0; i < 4; i++) { + u64 this_dev_addr = (int_addr & ~0x000000c00000) | + mac_table[i]; + + for (j = 5; j >= 0; j--) { + addr[i][j] = this_dev_addr & 0xff; + this_dev_addr >>= 8; + } + + dt_fixup_mac_address(i, addr[i]); + } +} + +static char prop_buf[MAX_PROP_LEN]; + +void planetcore_set_stdout_path(const char *table) +{ + char *path; + const char *label; + void *node, *chosen; + + label = planetcore_get_key(table, PLANETCORE_KEY_SERIAL_PORT); + if (!label) + return; + + node = find_node_by_prop_value_str(NULL, "linux,planetcore-label", + label); + if (!node) + return; + + path = get_path(node, prop_buf, MAX_PROP_LEN); + if (!path) + return; + + chosen = finddevice("/chosen"); + if (!chosen) + chosen = create_node(NULL, "chosen"); + if (!chosen) + return; + + setprop_str(chosen, "linux,stdout-path", path); +} + +void planetcore_set_serial_speed(const char *table) +{ + void *chosen, *stdout; + u64 baud; + u32 baud32; + int len; + + chosen = finddevice("/chosen"); + if (!chosen) + return; + + len = getprop(chosen, "linux,stdout-path", prop_buf, MAX_PROP_LEN); + if (len <= 0) + return; + + stdout = finddevice(prop_buf); + if (!stdout) { + printf("planetcore_set_serial_speed: " + "Bad /chosen/linux,stdout-path.\r\n"); + + return; + } + + if (!planetcore_get_decimal(table, PLANETCORE_KEY_SERIAL_BAUD, + &baud)) { + printf("planetcore_set_serial_speed: No SB tag.\r\n"); + return; + } + + baud32 = baud; + setprop(stdout, "current-speed", &baud32, 4); +} diff --git a/arch/powerpc/boot/planetcore.h b/arch/powerpc/boot/planetcore.h new file mode 100644 index 000000000000..0d4094f1771c --- /dev/null +++ b/arch/powerpc/boot/planetcore.h @@ -0,0 +1,49 @@ +#ifndef _PPC_BOOT_PLANETCORE_H_ +#define _PPC_BOOT_PLANETCORE_H_ + +#include "types.h" + +#define PLANETCORE_KEY_BOARD_TYPE "BO" +#define PLANETCORE_KEY_BOARD_REV "BR" +#define PLANETCORE_KEY_MB_RAM "D1" +#define PLANETCORE_KEY_MAC_ADDR "EA" +#define PLANETCORE_KEY_FLASH_SPEED "FS" +#define PLANETCORE_KEY_IP_ADDR "IP" +#define PLANETCORE_KEY_KB_NVRAM "NV" +#define PLANETCORE_KEY_PROCESSOR "PR" +#define PLANETCORE_KEY_PROC_VARIANT "PV" +#define PLANETCORE_KEY_SERIAL_BAUD "SB" +#define PLANETCORE_KEY_SERIAL_PORT "SP" +#define PLANETCORE_KEY_SWITCH "SW" +#define PLANETCORE_KEY_TEMP_OFFSET "TC" +#define PLANETCORE_KEY_TARGET_IP "TIP" +#define PLANETCORE_KEY_CRYSTAL_HZ "XT" + +/* Prepare the table for processing, by turning all newlines + * into NULL bytes. + */ +void planetcore_prepare_table(char *table); + +/* Return the value associated with a given key in text, + * decimal, or hex format. + * + * Returns zero/NULL on failure, non-zero on success. + */ +const char *planetcore_get_key(const char *table, const char *key); +int planetcore_get_decimal(const char *table, const char *key, u64 *val); +int planetcore_get_hex(const char *table, const char *key, u64 *val); + +/* Updates the device tree local-mac-address properties based + * on the EA tag. + */ +void planetcore_set_mac_addrs(const char *table); + +/* Sets the linux,stdout-path in the /chosen node. This requires the + * linux,planetcore-label property in each serial node. + */ +void planetcore_set_stdout_path(const char *table); + +/* Sets the current-speed property in the serial node. */ +void planetcore_set_serial_speed(const char *table); + +#endif From fabca2c0a461bd82a35194e3a4bb1e98f3ffa789 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 25 Sep 2007 09:50:52 +1000 Subject: [PATCH 0368/2804] [POWERPC] Add CHECK_FULL_REGS in several places in ptrace code This restores the CHECK_FULL_REGS sanity check to every place that can access the nonvolatile GPRs for ptrace. This is already done for native-bitwidth PTRACE_PEEKUSR, but was omitted for many other cases (32-bit ptrace, PTRACE_GETREGS, etc.); I think there may have been more uniform checks before that were lost in the recent cleanup of GETREGS et al. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 4 ++++ arch/powerpc/kernel/ptrace32.c | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index fb8866e0e35d..cf7732cdd6c7 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -331,6 +331,7 @@ static long arch_ptrace_old(struct task_struct *child, long request, long addr, unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; unsigned long __user *tmp = (unsigned long __user *)addr; + CHECK_FULL_REGS(child->thread.regs); for (i = 0; i < 32; i++) { ret = put_user(*reg, tmp); if (ret) @@ -346,6 +347,7 @@ static long arch_ptrace_old(struct task_struct *child, long request, long addr, unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; unsigned long __user *tmp = (unsigned long __user *)addr; + CHECK_FULL_REGS(child->thread.regs); for (i = 0; i < 32; i++) { ret = get_user(*reg, tmp); if (ret) @@ -517,6 +519,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = -EIO; break; } + CHECK_FULL_REGS(child->thread.regs); ret = 0; for (ui = 0; ui < PT_REGS_COUNT; ui ++) { ret |= __put_user(ptrace_get_reg(child, ui), @@ -537,6 +540,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = -EIO; break; } + CHECK_FULL_REGS(child->thread.regs); ret = 0; for (ui = 0; ui < PT_REGS_COUNT; ui ++) { ret = __get_user(tmp, (unsigned long __user *) data); diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 9e6baeac0fb1..fea6206ff90f 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -53,6 +53,7 @@ static long compat_ptrace_old(struct task_struct *child, long request, unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; unsigned int __user *tmp = (unsigned int __user *)addr; + CHECK_FULL_REGS(child->thread.regs); for (i = 0; i < 32; i++) { ret = put_user(*reg, tmp); if (ret) @@ -68,6 +69,7 @@ static long compat_ptrace_old(struct task_struct *child, long request, unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; unsigned int __user *tmp = (unsigned int __user *)addr; + CHECK_FULL_REGS(child->thread.regs); for (i = 0; i < 32; i++) { ret = get_user(*reg, tmp); if (ret) @@ -164,6 +166,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, if ((addr & 3) || (index > PT_FPSCR32)) break; + CHECK_FULL_REGS(child->thread.regs); if (index < PT_FPR0) { tmp = ptrace_get_reg(child, index); } else { @@ -210,6 +213,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, if ((addr & 3) || numReg > PT_FPSCR) break; + CHECK_FULL_REGS(child->thread.regs); if (numReg >= PT_FPR0) { flush_fp_to_thread(child); tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0]; @@ -270,6 +274,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, if ((addr & 3) || (index > PT_FPSCR32)) break; + CHECK_FULL_REGS(child->thread.regs); if (index < PT_FPR0) { ret = ptrace_put_reg(child, index, data); } else { @@ -307,6 +312,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, */ if ((addr & 3) || (numReg > PT_FPSCR)) break; + CHECK_FULL_REGS(child->thread.regs); if (numReg < PT_FPR0) { unsigned long freg = ptrace_get_reg(child, numReg); if (index % 2) @@ -342,6 +348,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, ret = -EIO; break; } + CHECK_FULL_REGS(child->thread.regs); ret = 0; for (ui = 0; ui < PT_REGS_COUNT; ui ++) { ret |= __put_user(ptrace_get_reg(child, ui), @@ -359,6 +366,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, ret = -EIO; break; } + CHECK_FULL_REGS(child->thread.regs); ret = 0; for (ui = 0; ui < PT_REGS_COUNT; ui ++) { ret = __get_user(tmp, (unsigned int __user *) data); From 3eb523b939d59fd90518188750c26df5d357478f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 27 Sep 2007 00:02:05 +1000 Subject: [PATCH 0369/2804] [POWERPC] Fix pci domain detection The /proc/bus/pci/* files list PCI domain numbers only for devices that claim to be on a multi-domain system. The check for this is broken on powerpc, because the buid value is truncated to 32 bits. There is at least one machine (IBM QS21) that only uses the high-order bits of the buid, so the return value of pci_proc_domain() ends up being always zero, which makes /proc/bus/pci useless. Change the logic to always return '1' for a nonzero buid value. Signed-off-by: Arnd Bergmann Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 291ffbc360c9..9f63bdcb0bdf 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -588,7 +588,7 @@ int pci_proc_domain(struct pci_bus *bus) return 0; else { struct pci_controller *hose = pci_bus_to_host(bus); - return hose->buid; + return hose->buid != 0; } } From 0de2d820067e03ca93f6bf5320d362d5262fb7a3 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 28 Sep 2007 04:38:55 +1000 Subject: [PATCH 0370/2804] [POWERPC] Make instruction dumping work in real mode On non-book-E, exceptions execute in real mode. If a fault happens that leads to a register dump, the kernel currently prints XXXXXXXX because it doesn't realize that PC is a physical address. This patch checks whether instruction address translation is turned on, and if not converts PC into a virtual address. Signed-off-by: Scott Wood Acked-by: Kumar Gala Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/process.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 57c589c34147..588c0cb8115e 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -354,6 +354,14 @@ static void show_instructions(struct pt_regs *regs) if (!(i % 8)) printk("\n"); +#if !defined(CONFIG_BOOKE) + /* If executing with the IMMU off, adjust pc rather + * than print XXXXXXXX. + */ + if (!(regs->msr & MSR_IR)) + pc = (unsigned long)phys_to_virt(pc); +#endif + /* We use __get_user here *only* to avoid an OOPS on a * bad address because the pc *should* only be a * kernel address. From 88de3cab98ff6c794b840969427e61605d0cc1ea Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Tue, 2 Oct 2007 10:24:08 +1000 Subject: [PATCH 0371/2804] [POWERPC] MAINTAINERS shouldn't reference linuxppc-embedded Powerpc patches should be posted to linuxppc-dev@ozlabs.org, so modify MAINTAINERS to no longer reference linuxppc-embedded@ozlabs.org. Signed-off-by: Mark A. Greer Signed-off-by: Paul Mackerras --- MAINTAINERS | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 8f800680384d..06259b494e6f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1543,7 +1543,7 @@ P: Pantelis Antoniou M: pantelis.antoniou@gmail.com P: Vitaly Bordug M: vbordug@ru.mvista.com -L: linuxppc-embedded@ozlabs.org +L: linuxppc-dev@ozlabs.org L: netdev@vger.kernel.org S: Maintained @@ -1551,14 +1551,14 @@ FREESCALE HIGHSPEED USB DEVICE DRIVER P: Li Yang M: leoli@freescale.com L: linux-usb-devel@lists.sourceforge.net -L: linuxppc-embedded@ozlabs.org +L: linuxppc-dev@ozlabs.org S: Maintained FREESCALE QUICC ENGINE UCC ETHERNET DRIVER P: Li Yang M: leoli@freescale.com L: netdev@vger.kernel.org -L: linuxppc-embedded@ozlabs.org +L: linuxppc-dev@ozlabs.org S: Maintained FILE LOCKING (flock() and fcntl()/lockf()) @@ -2291,7 +2291,6 @@ M: tnt@246tNt.com W: http://www.246tNt.com/mpc52xx/ W: http://www.penguinppc.org/ L: linuxppc-dev@ozlabs.org -L: linuxppc-embedded@ozlabs.org S: Maintained LINUX FOR POWERPC EMBEDDED PPC4XX @@ -2300,7 +2299,7 @@ M: jwboyer@linux.vnet.ibm.com P: Matt Porter M: mporter@kernel.crashing.org W: http://www.penguinppc.org/ -L: linuxppc-embedded@ozlabs.org +L: linuxppc-dev@ozlabs.org T: git kernel.org:/pub/scm/linux/kernel/git/jwboyer/powerpc.git S: Maintained @@ -2308,21 +2307,21 @@ LINUX FOR POWERPC BOOT CODE P: Tom Rini M: trini@kernel.crashing.org W: http://www.penguinppc.org/ -L: linuxppc-embedded@ozlabs.org +L: linuxppc-dev@ozlabs.org S: Maintained LINUX FOR POWERPC EMBEDDED PPC8XX P: Marcelo Tosatti M: marcelo@kvack.org W: http://www.penguinppc.org/ -L: linuxppc-embedded@ozlabs.org +L: linuxppc-dev@ozlabs.org S: Maintained LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX P: Kumar Gala M: galak@kernel.crashing.org W: http://www.penguinppc.org/ -L: linuxppc-embedded@ozlabs.org +L: linuxppc-dev@ozlabs.org S: Maintained LINUX FOR POWERPC PA SEMI PWRFICIENT @@ -2978,7 +2977,7 @@ POWERPC 4xx EMAC DRIVER P: Eugene Surovegin M: ebs@ebshome.net W: http://kernel.ebshome.net/emac/ -L: linuxppc-embedded@ozlabs.org +L: linuxppc-dev@ozlabs.org L: netdev@vger.kernel.org S: Maintained From 5669c3cf19fbadaa9120b59914beec8431277efe Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 2 Oct 2007 13:37:53 +1000 Subject: [PATCH 0372/2804] [POWERPC] Limit range of __init_ref_ok somewhat This patch introduces zalloc_maybe_bootmem and uses it so that we don't have to mark a whole (largish) routine as __init_ref_ok. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/irq.c | 10 ++-------- arch/powerpc/lib/alloc.c | 15 +++++++++++++++ include/asm-powerpc/system.h | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 0e47c8cfc979..151b13119208 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -424,7 +424,7 @@ static int default_irq_host_match(struct irq_host *h, struct device_node *np) return h->of_node != NULL && h->of_node == np; } -__init_refok struct irq_host *irq_alloc_host(struct device_node *of_node, +struct irq_host *irq_alloc_host(struct device_node *of_node, unsigned int revmap_type, unsigned int revmap_arg, struct irq_host_ops *ops, @@ -439,13 +439,7 @@ __init_refok struct irq_host *irq_alloc_host(struct device_node *of_node, /* Allocate structure and revmap table if using linear mapping */ if (revmap_type == IRQ_HOST_MAP_LINEAR) size += revmap_arg * sizeof(unsigned int); - if (mem_init_done) - host = kzalloc(size, GFP_KERNEL); - else { - host = alloc_bootmem(size); - if (host) - memset(host, 0, size); - } + host = zalloc_maybe_bootmem(size, GFP_KERNEL); if (host == NULL) return NULL; diff --git a/arch/powerpc/lib/alloc.c b/arch/powerpc/lib/alloc.c index e58c80590ebc..f53e09c7dac7 100644 --- a/arch/powerpc/lib/alloc.c +++ b/arch/powerpc/lib/alloc.c @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -12,3 +13,17 @@ void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask) else return alloc_bootmem(size); } + +void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask) +{ + void *p; + + if (mem_init_done) + p = kzalloc(size, mask); + else { + p = alloc_bootmem(size); + if (p) + memset(p, 0, size); + } + return p; +} diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index f7879fc530f1..d10e99bf5001 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -190,6 +190,7 @@ extern unsigned long memory_limit; extern unsigned long klimit; extern void *alloc_maybe_bootmem(size_t size, gfp_t mask); +extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); extern int powersave_nap; /* set if nap mode can be used in idle loop */ From 048c8bc90e53bf1f5feec020a7d482da94894e93 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 1 Nov 2006 05:44:54 +1100 Subject: [PATCH 0373/2804] [POWERPC] ppc64: support CONFIG_DEBUG_PREEMPT Add CONFIG_DEBUG_PREEMPT support to ppc64: it was useful for testing get_paca() preemption. Cheat a little, just use debug_smp_processor_id() in the debug version of get_paca(): it contains all the right checks and reporting, though get_paca() doesn't really use smp_processor_id(). Use local_paca for what might have been called __raw_get_paca(). Silence harmless warnings from io.h and lparcfg.c with local_paca - it is okay for iseries_lparcfg_data to be referencing shared_proc with preemption enabled: all cpus should show the same value for shared_proc. Why do other architectures need TRACE_IRQFLAGS_SUPPORT for DEBUG_PREEMPT? I don't know, ppc64 appears to get along fine without it. Signed-off-by: Hugh Dickins Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/lparcfg.c | 2 +- include/asm-powerpc/io.h | 2 +- include/asm-powerpc/paca.h | 11 +++++++++++ include/asm-powerpc/percpu.h | 2 +- include/asm-powerpc/smp.h | 2 +- lib/Kconfig.debug | 2 +- 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 6444eaa30a2f..ff781b2eddec 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -77,7 +77,7 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v) int processors, max_processors; unsigned long purr = get_purr(); - shared = (int)(get_lppaca()->shared_proc); + shared = (int)(local_paca->lppaca_ptr->shared_proc); seq_printf(m, "system_active_processors=%d\n", (int)HvLpConfig_getSystemPhysicalProcessors()); diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h index 6805efb2cb6d..affba7052fb6 100644 --- a/include/asm-powerpc/io.h +++ b/include/asm-powerpc/io.h @@ -86,7 +86,7 @@ extern unsigned long pci_dram_offset; */ #ifdef CONFIG_PPC64 -#define IO_SET_SYNC_FLAG() do { get_paca()->io_sync = 1; } while(0) +#define IO_SET_SYNC_FLAG() do { local_paca->io_sync = 1; } while(0) #else #define IO_SET_SYNC_FLAG() #endif diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index c6a5b1735666..fcd7b428ed0b 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -21,7 +21,18 @@ #include register struct paca_struct *local_paca asm("r13"); + +#if defined(CONFIG_DEBUG_PREEMPT) && defined(CONFIG_SMP) +extern unsigned int debug_smp_processor_id(void); /* from linux/smp.h */ +/* + * Add standard checks that preemption cannot occur when using get_paca(): + * otherwise the paca_struct it points to may be the wrong one just after. + */ +#define get_paca() ((void) debug_smp_processor_id(), local_paca) +#else #define get_paca() local_paca +#endif + #define get_lppaca() (get_paca()->lppaca_ptr) #define get_slb_shadow() (get_paca()->slb_shadow_ptr) diff --git a/include/asm-powerpc/percpu.h b/include/asm-powerpc/percpu.h index 73dc8ba4010d..6b229626d3ff 100644 --- a/include/asm-powerpc/percpu.h +++ b/include/asm-powerpc/percpu.h @@ -28,7 +28,7 @@ /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu))) #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset())) -#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset())) +#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, local_paca->data_offset)) /* A macro to avoid #include hell... */ #define percpu_modcopy(pcpudst, src, size) \ diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h index d037f50580e2..19102bfc14ca 100644 --- a/include/asm-powerpc/smp.h +++ b/include/asm-powerpc/smp.h @@ -45,7 +45,7 @@ void generic_mach_cpu_die(void); #endif #ifdef CONFIG_PPC64 -#define raw_smp_processor_id() (get_paca()->paca_index) +#define raw_smp_processor_id() (local_paca->paca_index) #define hard_smp_processor_id() (get_paca()->hw_cpu_id) #else /* 32-bit */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 50a94eee4d92..51e2fd0d851c 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -167,7 +167,7 @@ config SLUB_DEBUG_ON config DEBUG_PREEMPT bool "Debug preemptible kernel" - depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT + depends on DEBUG_KERNEL && PREEMPT && (TRACE_IRQFLAGS_SUPPORT || PPC64) default y help If you say Y here then the kernel will use a debug variant of the From d4243c175f127b377c881f512e7fb8ddaf2ed5e2 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 2 Oct 2007 13:30:04 -0700 Subject: [PATCH 0374/2804] [POWERPC] Include pagemap.h in asm/powerpc/tlb.h Fixes this powerpc build error in 2.6.22-rc6-mm1 for powerpc 64 with CONFIG_SWAP=n : In file included from include2/asm/tlb.h:60, from /home/compudj/git/linux-2.6-lttng/arch/powerpc/mm/init_64. c:56: /home/compudj/git/linux-2.6-lttng/include/asm-generic/tlb.h: In function 'tlb_flush_mmu': /home/compudj/git/linux-2.6-lttng/include/asm-generic/tlb.h:76: error: implicit declaration of function 'release_pages' /home/compudj/git/linux-2.6-lttng/include/asm-generic/tlb.h: In function 'tlb_remove_page': /home/compudj/git/linux-2.6-lttng/include/asm-generic/tlb.h:105: error: implicit declaration of function 'page_cache_release' make[2]: *** [arch/powerpc/mm/init_64.o] Error 1 release_pages is declared in linux/pagemap.h, but cannot be included in linux/swap.h because of a sparc related comment: /* only sparc can not include linux/pagemap.h in this file * so leave page_cache_release and release_pages undeclared... */ #define free_page_and_swap_cache(page) \ page_cache_release(page) #define free_pages_and_swap_cache(pages, nr) \ release_pages((pages), (nr), 0); Signed-off-by: Mathieu Desnoyers Cc: Benjamin Herrenschmidt Cc: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- include/asm-powerpc/tlb.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-powerpc/tlb.h b/include/asm-powerpc/tlb.h index 66714042e438..e20ff7541f36 100644 --- a/include/asm-powerpc/tlb.h +++ b/include/asm-powerpc/tlb.h @@ -23,6 +23,8 @@ #include #endif +#include + struct mmu_gather; #define tlb_start_vma(tlb, vma) do { } while (0) From 8150caad02266623b5b9f58088d589f130fccd97 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 2 Oct 2007 13:30:04 -0700 Subject: [PATCH 0375/2804] [POWERPC] powerpc vDSO: install unstripped copies on disk This keeps an unstripped copy of the vDSO images built before they are stripped and embedded in the kernel. The unstripped copies get installed in $(MODLIB)/vdso/ by "make install". These files can be useful when they contain source-level debugging information. Signed-off-by: Roland McGrath Cc: Sam Ravnborg Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 8 +++++++- arch/powerpc/kernel/vdso32/Makefile | 20 +++++++++++++++++--- arch/powerpc/kernel/vdso64/Makefile | 19 ++++++++++++++++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 71632b20b81d..dc2d18e93002 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -169,9 +169,15 @@ define archhelp @echo ' *_defconfig - Select default config from arch/$(ARCH)/configs' endef -install: +install: vdso_install $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install +vdso_install: +ifeq ($(CONFIG_PPC64),y) + $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@ +endif + $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso32 $@ + archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/powerpc/kernel/vdso32/Makefile b/arch/powerpc/kernel/vdso32/Makefile index 3726358faae8..c3d57bd01a88 100644 --- a/arch/powerpc/kernel/vdso32/Makefile +++ b/arch/powerpc/kernel/vdso32/Makefile @@ -9,11 +9,11 @@ ifeq ($(CONFIG_PPC32),y) CROSS32CC := $(CC) endif -targets := $(obj-vdso32) vdso32.so +targets := $(obj-vdso32) vdso32.so vdso32.so.dbg obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32)) -EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin +EXTRA_CFLAGS := -shared -fno-common -fno-builtin EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 \ $(call ld-option, -Wl$(comma)--hash-style=sysv) EXTRA_AFLAGS := -D__VDSO32__ -s @@ -26,9 +26,14 @@ CPPFLAGS_vdso32.lds += -P -C -Upowerpc $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so # link rule for the .so file, .lds has to be first -$(obj)/vdso32.so: $(src)/vdso32.lds $(obj-vdso32) +$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) $(call if_changed,vdso32ld) +# strip rule for the .so file +$(obj)/%.so: OBJCOPYFLAGS := -S +$(obj)/%.so: $(obj)/%.so.dbg FORCE + $(call if_changed,objcopy) + # assembly rules for the .S files $(obj-vdso32): %.o: %.S $(call if_changed_dep,vdso32as) @@ -39,3 +44,12 @@ quiet_cmd_vdso32ld = VDSO32L $@ quiet_cmd_vdso32as = VDSO32A $@ cmd_vdso32as = $(CROSS32CC) $(a_flags) -c -o $@ $< +# install commands for the unstripped file +quiet_cmd_vdso_install = INSTALL $@ + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ + +vdso32.so: $(obj)/vdso32.so.dbg + @mkdir -p $(MODLIB)/vdso + $(call cmd,vdso_install) + +vdso_install: vdso32.so diff --git a/arch/powerpc/kernel/vdso64/Makefile b/arch/powerpc/kernel/vdso64/Makefile index 43af9b2a6f3b..fa7f1b8f3e50 100644 --- a/arch/powerpc/kernel/vdso64/Makefile +++ b/arch/powerpc/kernel/vdso64/Makefile @@ -4,10 +4,10 @@ obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o # Build rules -targets := $(obj-vdso64) vdso64.so +targets := $(obj-vdso64) vdso64.so vdso64.so.dbg obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64)) -EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin +EXTRA_CFLAGS := -shared -fno-common -fno-builtin EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 \ $(call ld-option, -Wl$(comma)--hash-style=sysv) EXTRA_AFLAGS := -D__VDSO64__ -s @@ -20,9 +20,14 @@ CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so # link rule for the .so file, .lds has to be first -$(obj)/vdso64.so: $(src)/vdso64.lds $(obj-vdso64) +$(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64) $(call if_changed,vdso64ld) +# strip rule for the .so file +$(obj)/%.so: OBJCOPYFLAGS := -S +$(obj)/%.so: $(obj)/%.so.dbg FORCE + $(call if_changed,objcopy) + # assembly rules for the .S files $(obj-vdso64): %.o: %.S $(call if_changed_dep,vdso64as) @@ -33,4 +38,12 @@ quiet_cmd_vdso64ld = VDSO64L $@ quiet_cmd_vdso64as = VDSO64A $@ cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $< +# install commands for the unstripped file +quiet_cmd_vdso_install = INSTALL $@ + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +vdso64.so: $(obj)/vdso64.so.dbg + @mkdir -p $(MODLIB)/vdso + $(call cmd,vdso_install) + +vdso_install: vdso64.so From a4e32b5f0ac60e6bca7c6896f47e1c624ae45df1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:05 -0700 Subject: [PATCH 0376/2804] [POWERPC] Sky Cpu and Nexus: code style improvement Remove useless spaces and adds some empty lines to make code more readable. Also marker for printk is added. Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 38 ++++++++++++--------------- drivers/misc/hdpuftrs/hdpu_nexus.c | 24 ++++++++++------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 276ba3c5143f..1874b0740f2b 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -169,22 +169,21 @@ static struct platform_driver hdpu_cpustate_driver = { * The various file operations we support. */ static const struct file_operations cpustate_fops = { - owner:THIS_MODULE, - open:cpustate_open, - release:cpustate_release, - read:cpustate_read, - write:cpustate_write, - fasync:NULL, - poll:NULL, - ioctl:NULL, - llseek:no_llseek, - + owner: THIS_MODULE, + open: cpustate_open, + release: cpustate_release, + read: cpustate_read, + write: cpustate_write, + fasync: NULL, + poll: NULL, + ioctl: NULL, + llseek: no_llseek, }; static struct miscdevice cpustate_dev = { MISC_DYNAMIC_MINOR, "sky_cpustate", - &cpustate_fops + &cpustate_fops, }; static int hdpu_cpustate_probe(struct platform_device *pdev) @@ -199,18 +198,18 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) ret = misc_register(&cpustate_dev); if (ret) { - printk(KERN_WARNING "sky_cpustate: Unable to register misc " - "device.\n"); + printk(KERN_WARNING "sky_cpustate: " + "Unable to register misc device.\n"); cpustate.set_addr = NULL; cpustate.clr_addr = NULL; return ret; } proc_de = create_proc_read_entry("sky_cpustate", 0, 0, - cpustate_read_proc, NULL); + cpustate_read_proc, NULL); if (proc_de == NULL) - printk(KERN_WARNING "sky_cpustate: Unable to create proc " - "dir entry\n"); + printk(KERN_WARNING "sky_cpustate: " + "Unable to create proc dir entry\n"); printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); return 0; @@ -218,21 +217,18 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) static int hdpu_cpustate_remove(struct platform_device *pdev) { - cpustate.set_addr = NULL; cpustate.clr_addr = NULL; remove_proc_entry("sky_cpustate", NULL); misc_deregister(&cpustate_dev); - return 0; + return 0; } static int __init cpustate_init(void) { - int rc; - rc = platform_driver_register(&hdpu_cpustate_driver); - return rc; + return platform_driver_register(&hdpu_cpustate_driver); } static void __exit cpustate_exit(void) diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index 60c8b26f0678..fd3f3c22115f 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -40,40 +40,43 @@ static struct platform_driver hdpu_nexus_driver = { int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *zero, void *ptr) { - if (offset > 0) return 0; + return sprintf(buffer, "%d\n", slot_id); } int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *zero, void *ptr) { - if (offset > 0) return 0; + return sprintf(buffer, "%d\n", chassis_id); } static int hdpu_nexus_probe(struct platform_device *pdev) { struct resource *res; + int *nexus_id_addr; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - int *nexus_id_addr; - nexus_id_addr = - ioremap(res->start, (unsigned long)(res->end - res->start)); + nexus_id_addr = ioremap(res->start, + (unsigned long)(res->end - res->start)); if (nexus_id_addr) { slot_id = (*nexus_id_addr >> 8) & 0x1f; chassis_id = *nexus_id_addr & 0xff; iounmap(nexus_id_addr); - } else - printk("Could not map slot id\n"); + } else { + printk(KERN_ERR "Could not map slot id\n"); + } + hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); hdpu_slot_id->read_proc = hdpu_slot_id_read; hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + return 0; } @@ -81,18 +84,19 @@ static int hdpu_nexus_remove(struct platform_device *pdev) { slot_id = -1; chassis_id = -1; + remove_proc_entry("sky_slot_id", &proc_root); remove_proc_entry("sky_chassis_id", &proc_root); + hdpu_slot_id = 0; hdpu_chassis_id = 0; + return 0; } static int __init nexus_init(void) { - int rc; - rc = platform_driver_register(&hdpu_nexus_driver); - return rc; + return platform_driver_register(&hdpu_nexus_driver); } static void __exit nexus_exit(void) From d2ceb47a7cbcc50b45832c6b24c47515838d169a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:06 -0700 Subject: [PATCH 0377/2804] [POWERPC] Sky Cpu and Nexus: include io.h Add #include directive to properly declare ioremap() and writel(). Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 1 + drivers/misc/hdpuftrs/hdpu_nexus.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 1874b0740f2b..b5c6f21dcb69 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -22,6 +22,7 @@ #include #include #include +#include #define SKY_CPUSTATE_VERSION "1.1" diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index fd3f3c22115f..fda9998f45ca 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -20,6 +20,7 @@ #include #include +#include static int hdpu_nexus_probe(struct platform_device *pdev); static int hdpu_nexus_remove(struct platform_device *pdev); From 7472fd36a87e84c2819066543224285a6ab79ffc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:06 -0700 Subject: [PATCH 0378/2804] [POWERPC] Sky Cpu and Nexus: check for platform_get_resource retcode Add adds checking for platform_get_resource() return code to prevent possible NULL pointer usage. Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 5 +++++ drivers/misc/hdpuftrs/hdpu_nexus.c | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index b5c6f21dcb69..b16742c7c69d 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -194,6 +194,11 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + printk(KERN_ERR "sky_cpustate: " + "Invalid memory resource.\n"); + return -EINVAL; + } cpustate.set_addr = (unsigned long *)res->start; cpustate.clr_addr = (unsigned long *)res->end - 1; diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index fda9998f45ca..01bc9179603b 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -62,6 +62,11 @@ static int hdpu_nexus_probe(struct platform_device *pdev) int *nexus_id_addr; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + printk(KERN_ERR "sky_nexus: " + "Invalid memory resource.\n"); + return -EINVAL; + } nexus_id_addr = ioremap(res->start, (unsigned long)(res->end - res->start)); if (nexus_id_addr) { @@ -69,7 +74,7 @@ static int hdpu_nexus_probe(struct platform_device *pdev) chassis_id = *nexus_id_addr & 0xff; iounmap(nexus_id_addr); } else { - printk(KERN_ERR "Could not map slot id\n"); + printk(KERN_ERR "sky_nexus: Could not map slot id\n"); } hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); From 5f725fe92cc2e75892b237e863d5f695fb634bb2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:07 -0700 Subject: [PATCH 0379/2804] [POWERPC] Sky Cpu and Nexus: check for create_proc_entry ret code Adds checking of create_proc_entry call to prevent possible NULL pointer usage. Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_nexus.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index 01bc9179603b..cc818532c7ec 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -78,10 +78,20 @@ static int hdpu_nexus_probe(struct platform_device *pdev) } hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); - hdpu_slot_id->read_proc = hdpu_slot_id_read; + if (!hdpu_slot_id) { + printk(KERN_WARNING "sky_nexus: " + "Unable to create proc dir entry: sky_slot_id\n"); + } else { + hdpu_slot_id->read_proc = hdpu_slot_id_read; + } hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); - hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + if (!hdpu_chassis_id) { + printk(KERN_WARNING "sky_nexus: " + "Unable to create proc dir entry: sky_chassis_id\n"); + } else { + hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + } return 0; } From 8b70da1a094fb781d49a811fd2368907adc92b8d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:08 -0700 Subject: [PATCH 0380/2804] [POWERPC] Sky Cpu: use C99 style for struct init This changes structure item init format to C99, and removes useless structure items init. Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index b16742c7c69d..32f65a3e07ce 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -170,21 +170,18 @@ static struct platform_driver hdpu_cpustate_driver = { * The various file operations we support. */ static const struct file_operations cpustate_fops = { - owner: THIS_MODULE, - open: cpustate_open, - release: cpustate_release, - read: cpustate_read, - write: cpustate_write, - fasync: NULL, - poll: NULL, - ioctl: NULL, - llseek: no_llseek, + .owner = THIS_MODULE, + .open = cpustate_open, + .release = cpustate_release, + .read = cpustate_read, + .write = cpustate_write, + .llseek = no_llseek, }; static struct miscdevice cpustate_dev = { - MISC_DYNAMIC_MINOR, - "sky_cpustate", - &cpustate_fops, + .minor = MISC_DYNAMIC_MINOR, + .name = "sky_cpustate", + .fops = &cpustate_fops, }; static int hdpu_cpustate_probe(struct platform_device *pdev) From 3049ea7e04408abf35dc295014cb6f1eabcf9b8c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:09 -0700 Subject: [PATCH 0381/2804] [POWERPC] Sky Cpu and Nexus: use seq_file/single_open on proc interface This patch changes proc interface to be used with single_file/seq_open calls. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 66 ++++++++++++++------------- drivers/misc/hdpuftrs/hdpu_nexus.c | 54 ++++++++++++++++------ 2 files changed, 75 insertions(+), 45 deletions(-) diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 32f65a3e07ce..aa8ce7abe922 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -19,9 +19,10 @@ #include #include #include +#include #include #include -#include +#include #include #define SKY_CPUSTATE_VERSION "1.1" @@ -29,7 +30,30 @@ static int hdpu_cpustate_probe(struct platform_device *pdev); static int hdpu_cpustate_remove(struct platform_device *pdev); -struct cpustate_t cpustate; +static unsigned char cpustate_get_state(void); +static int cpustate_proc_open(struct inode *inode, struct file *file); +static int cpustate_proc_read(struct seq_file *seq, void *offset); + +static struct cpustate_t cpustate; + +static const struct file_operations proc_cpustate = { + .open = cpustate_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int cpustate_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, cpustate_proc_read, NULL); +} + +static int cpustate_proc_read(struct seq_file *seq, void *offset) +{ + seq_printf(seq, "CPU State: %04x\n", cpustate_get_state()); + return 0; +} static int cpustate_get_ref(int excl) { @@ -67,13 +91,13 @@ static int cpustate_free_ref(void) return 0; } -unsigned char cpustate_get_state(void) +static unsigned char cpustate_get_state(void) { return cpustate.cached_val; } -void cpustate_set_state(unsigned char new_state) +static void cpustate_set_state(unsigned char new_state) { unsigned int state = (new_state << 21); @@ -135,29 +159,6 @@ static int cpustate_release(struct inode *inode, struct file *file) return cpustate_free_ref(); } -/* - * Info exported via "/proc/sky_cpustate". - */ -static int cpustate_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - char *p = page; - int len = 0; - - p += sprintf(p, "CPU State: %04x\n", cpustate_get_state()); - len = p - page; - - if (len <= off + count) - *eof = 1; - *start = page + off; - len -= off; - if (len > count) - len = count; - if (len < 0) - len = 0; - return len; -} - static struct platform_driver hdpu_cpustate_driver = { .probe = hdpu_cpustate_probe, .remove = hdpu_cpustate_remove, @@ -208,11 +209,14 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) return ret; } - proc_de = create_proc_read_entry("sky_cpustate", 0, 0, - cpustate_read_proc, NULL); - if (proc_de == NULL) + proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root); + if (!proc_de) { printk(KERN_WARNING "sky_cpustate: " - "Unable to create proc dir entry\n"); + "Unable to create proc entry\n"); + } else { + proc_de->proc_fops = &proc_cpustate; + proc_de->owner = THIS_MODULE; + } printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); return 0; diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index cc818532c7ec..2887b2147980 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -18,18 +18,38 @@ #include #include #include - #include +#include #include static int hdpu_nexus_probe(struct platform_device *pdev); static int hdpu_nexus_remove(struct platform_device *pdev); +static int hdpu_slot_id_open(struct inode *inode, struct file *file); +static int hdpu_slot_id_read(struct seq_file *seq, void *offset); +static int hdpu_chassis_id_open(struct inode *inode, struct file *file); +static int hdpu_chassis_id_read(struct seq_file *seq, void *offset); static struct proc_dir_entry *hdpu_slot_id; static struct proc_dir_entry *hdpu_chassis_id; static int slot_id = -1; static int chassis_id = -1; +static const struct file_operations proc_slot_id = { + .open = hdpu_slot_id_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations proc_chassis_id = { + .open = hdpu_chassis_id_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static struct platform_driver hdpu_nexus_driver = { .probe = hdpu_nexus_probe, .remove = hdpu_nexus_remove, @@ -38,22 +58,26 @@ static struct platform_driver hdpu_nexus_driver = { }, }; -int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset, - int buffer_length, int *zero, void *ptr) +static int hdpu_slot_id_open(struct inode *inode, struct file *file) { - if (offset > 0) - return 0; - - return sprintf(buffer, "%d\n", slot_id); + return single_open(file, hdpu_slot_id_read, NULL); } -int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset, - int buffer_length, int *zero, void *ptr) +static int hdpu_slot_id_read(struct seq_file *seq, void *offset) { - if (offset > 0) - return 0; + seq_printf(seq, "%d\n", slot_id); + return 0; +} - return sprintf(buffer, "%d\n", chassis_id); +static int hdpu_chassis_id_open(struct inode *inode, struct file *file) +{ + return single_open(file, hdpu_chassis_id_read, NULL); +} + +static int hdpu_chassis_id_read(struct seq_file *seq, void *offset) +{ + seq_printf(seq, "%d\n", chassis_id); + return 0; } static int hdpu_nexus_probe(struct platform_device *pdev) @@ -82,7 +106,8 @@ static int hdpu_nexus_probe(struct platform_device *pdev) printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_slot_id\n"); } else { - hdpu_slot_id->read_proc = hdpu_slot_id_read; + hdpu_slot_id->proc_fops = &proc_slot_id; + hdpu_slot_id->owner = THIS_MODULE; } hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); @@ -90,7 +115,8 @@ static int hdpu_nexus_probe(struct platform_device *pdev) printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_chassis_id\n"); } else { - hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + hdpu_chassis_id->proc_fops = &proc_chassis_id; + hdpu_chassis_id->owner = THIS_MODULE; } return 0; From ca786f83a97d7897b013b1e9b290c9010b69af9b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 2 Oct 2007 13:30:09 -0700 Subject: [PATCH 0382/2804] [POWERPC] Select proper defconfig for crosscompiles The trick for finding the right defconfig is neat, but you forgot to provide an i686_defconfig. ;-) More seriously, cross compiling the defconfig is often useful, e.g. for testing the compilation of patches that touch multiple architectures, and this patch therefore chooses g5_defconfig if $(CROSS_COMPILE) is non-empty. Signed-off-by: Adrian Bunk Acked-by: Sam Ravnborg Cc: Benjamin Herrenschmidt Cc: Olof Johansson Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index dc2d18e93002..643839a3f5d8 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -35,7 +35,11 @@ endif export CROSS32CC CROSS32AS CROSS32LD CROSS32AR CROSS32OBJCOPY +ifeq ($(CROSS_COMPILE),) KBUILD_DEFCONFIG := $(shell uname -m)_defconfig +else +KBUILD_DEFCONFIG := ppc64_defconfig +endif ifeq ($(CONFIG_PPC64),y) OLDARCH := ppc64 From 0b94a1eeeeb3542d046b928ca01fcd4bf0ea7587 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 17 Sep 2007 16:05:00 +1000 Subject: [PATCH 0383/2804] [POWERPC] Store the base address in dcr_host_t In its current form, dcr_map() doesn't remember the base address you passed it, which means you need to store it somewhere else. Rather than adding the base to another struct it seems simpler to store it in the dcr_host_t. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/dcr.c | 2 +- include/asm-powerpc/dcr-mmio.h | 6 +++++- include/asm-powerpc/dcr-native.h | 6 ++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c index e82d54de8a8d..ab11c0b29024 100644 --- a/arch/powerpc/sysdev/dcr.c +++ b/arch/powerpc/sysdev/dcr.c @@ -104,7 +104,7 @@ u64 of_translate_dcr_address(struct device_node *dev, dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n, unsigned int dcr_c) { - dcr_host_t ret = { .token = NULL, .stride = 0 }; + dcr_host_t ret = { .token = NULL, .stride = 0, .base = dcr_n }; u64 addr; pr_debug("dcr_map(%s, 0x%x, 0x%x)\n", diff --git a/include/asm-powerpc/dcr-mmio.h b/include/asm-powerpc/dcr-mmio.h index 5dbfca8dde36..6b82c3ba495a 100644 --- a/include/asm-powerpc/dcr-mmio.h +++ b/include/asm-powerpc/dcr-mmio.h @@ -23,7 +23,11 @@ #include -typedef struct { void __iomem *token; unsigned int stride; } dcr_host_t; +typedef struct { + void __iomem *token; + unsigned int stride; + unsigned int base; +} dcr_host_t; #define DCR_MAP_OK(host) ((host).token != NULL) diff --git a/include/asm-powerpc/dcr-native.h b/include/asm-powerpc/dcr-native.h index 05af081222f6..f41058c0f6cb 100644 --- a/include/asm-powerpc/dcr-native.h +++ b/include/asm-powerpc/dcr-native.h @@ -22,11 +22,13 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -typedef struct {} dcr_host_t; +typedef struct { + unsigned int base; +} dcr_host_t; #define DCR_MAP_OK(host) (1) -#define dcr_map(dev, dcr_n, dcr_c) ((dcr_host_t){}) +#define dcr_map(dev, dcr_n, dcr_c) ((dcr_host_t){ .base = (dcr_n) }) #define dcr_unmap(host, dcr_n, dcr_c) do {} while (0) #define dcr_read(host, dcr_n) mfdcr(dcr_n) #define dcr_write(host, dcr_n, value) mtdcr(dcr_n, value) From 0411a5e233db0f5196cff46a34bff15c005bbe6a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 17 Sep 2007 16:05:01 +1000 Subject: [PATCH 0384/2804] [POWERPC] Update mpic to use dcr_host_t.base Now that dcr_host_t contains the base address, we can use that in the mpic code, rather than storing it separately. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic.c | 28 +++++++++++----------------- include/asm-powerpc/mpic.h | 6 ------ 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 22600fd23958..893e65439e85 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -156,8 +156,7 @@ static inline u32 _mpic_read(enum mpic_reg_type type, switch(type) { #ifdef CONFIG_PPC_DCR case mpic_access_dcr: - return dcr_read(rb->dhost, - rb->dbase + reg + rb->doff); + return dcr_read(rb->dhost, rb->dhost.base + reg); #endif case mpic_access_mmio_be: return in_be32(rb->base + (reg >> 2)); @@ -174,8 +173,7 @@ static inline void _mpic_write(enum mpic_reg_type type, switch(type) { #ifdef CONFIG_PPC_DCR case mpic_access_dcr: - return dcr_write(rb->dhost, - rb->dbase + reg + rb->doff, value); + return dcr_write(rb->dhost, rb->dhost.base + reg, value); #endif case mpic_access_mmio_be: return out_be32(rb->base + (reg >> 2), value); @@ -279,9 +277,11 @@ static void _mpic_map_mmio(struct mpic *mpic, unsigned long phys_addr, static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, unsigned int offset, unsigned int size) { - rb->dbase = mpic->dcr_base; - rb->doff = offset; - rb->dhost = dcr_map(mpic->irqhost->of_node, rb->dbase + rb->doff, size); + const u32 *dbasep; + + dbasep = of_get_property(mpic->irqhost->of_node, "dcr-reg", NULL); + + rb->dhost = dcr_map(mpic->irqhost->of_node, *dbasep + offset, size); BUG_ON(!DCR_MAP_OK(rb->dhost)); } @@ -1075,20 +1075,14 @@ struct mpic * __init mpic_alloc(struct device_node *node, BUG_ON(paddr == 0 && node == NULL); /* If no physical address passed in, check if it's dcr based */ - if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL) - mpic->flags |= MPIC_USES_DCR; - + if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL) { #ifdef CONFIG_PPC_DCR - if (mpic->flags & MPIC_USES_DCR) { - const u32 *dbasep; - dbasep = of_get_property(node, "dcr-reg", NULL); - BUG_ON(dbasep == NULL); - mpic->dcr_base = *dbasep; + mpic->flags |= MPIC_USES_DCR; mpic->reg_type = mpic_access_dcr; - } #else - BUG_ON (mpic->flags & MPIC_USES_DCR); + BUG(); #endif /* CONFIG_PPC_DCR */ + } /* If the MPIC is not DCR based, and no physical address was passed * in, try to obtain one diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index edb4a7c84506..ae84dde3bc7f 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -224,8 +224,6 @@ struct mpic_reg_bank { u32 __iomem *base; #ifdef CONFIG_PPC_DCR dcr_host_t dhost; - unsigned int dbase; - unsigned int doff; #endif /* CONFIG_PPC_DCR */ }; @@ -289,10 +287,6 @@ struct mpic struct mpic_reg_bank cpuregs[MPIC_MAX_CPUS]; struct mpic_reg_bank isus[MPIC_MAX_ISU]; -#ifdef CONFIG_PPC_DCR - unsigned int dcr_base; -#endif - /* Protected sources */ unsigned long *protected; From 4acb889627412cbab6b4b44593efe232f5028eb2 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 17 Sep 2007 16:05:02 +1000 Subject: [PATCH 0385/2804] [POWERPC] Update axon_msi to use dcr_host_t.base Now that dcr_host_t contains the base address, we can use that in the axon_msi code, rather than storing it separately. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/axon_msi.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 4bde8da11f44..1245b2f517bb 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -69,7 +69,6 @@ struct axon_msic { dcr_host_t dcr_host; struct list_head list; u32 read_offset; - u32 dcr_base; }; static LIST_HEAD(axon_msic_list); @@ -78,12 +77,12 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val) { pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n); - dcr_write(msic->dcr_host, msic->dcr_base + dcr_n, val); + dcr_write(msic->dcr_host, msic->dcr_host.base + dcr_n, val); } static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n) { - return dcr_read(msic->dcr_host, msic->dcr_base + dcr_n); + return dcr_read(msic->dcr_host, msic->dcr_host.base + dcr_n); } static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) @@ -324,7 +323,7 @@ static int axon_msi_setup_one(struct device_node *dn) struct page *page; struct axon_msic *msic; unsigned int virq; - int dcr_len; + int dcr_base, dcr_len; pr_debug("axon_msi: setting up dn %s\n", dn->full_name); @@ -335,17 +334,17 @@ static int axon_msi_setup_one(struct device_node *dn) goto out; } - msic->dcr_base = dcr_resource_start(dn, 0); + dcr_base = dcr_resource_start(dn, 0); dcr_len = dcr_resource_len(dn, 0); - if (msic->dcr_base == 0 || dcr_len == 0) { + if (dcr_base == 0 || dcr_len == 0) { printk(KERN_ERR "axon_msi: couldn't parse dcr properties on %s\n", dn->full_name); goto out; } - msic->dcr_host = dcr_map(dn, msic->dcr_base, dcr_len); + msic->dcr_host = dcr_map(dn, dcr_base, dcr_len); if (!DCR_MAP_OK(msic->dcr_host)) { printk(KERN_ERR "axon_msi: dcr_map failed for %s\n", dn->full_name); From 74c9b99d4dcadd144fab7326c99d0ffb1de19245 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Wed, 26 Sep 2007 19:46:34 +1000 Subject: [PATCH 0386/2804] [POWERPC] ibmebus: More descriptive error return code in ibmebus_store_probe() Signed-off-by: Joachim Fenkes Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ibmebus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 7697d5b8296e..53bf64623bd8 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -397,10 +397,10 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus, return -ENOMEM; if (bus_find_device(&ibmebus_bus_type, NULL, path, - ibmebus_match_path)) { + ibmebus_match_path)) { printk(KERN_WARNING "%s: %s has already been probed\n", __FUNCTION__, path); - rc = -EINVAL; + rc = -EEXIST; goto out; } From 80755b4144b303882437ac301034f0c7330199a8 Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Tue, 2 Oct 2007 18:18:46 +1000 Subject: [PATCH 0387/2804] [POWERPC] Celleb: Move pause, kexec_cpu_down to beat.c This is an update for "Beat on Celleb" - Move beat_pause(), beat_kexec_cpu_down() from setup.c to beat.c Signed-off-by: Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/beat.c | 12 ++++++++++++ arch/powerpc/platforms/celleb/beat.h | 2 ++ arch/powerpc/platforms/celleb/setup.c | 14 +------------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c index 99341ce8a697..ced6f68c7b0b 100644 --- a/arch/powerpc/platforms/celleb/beat.c +++ b/arch/powerpc/platforms/celleb/beat.c @@ -158,6 +158,18 @@ int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2) return beat_put_characters_to_console(vterm, len, (u8*)db); } +void beat_power_save(void) +{ + beat_pause(0); +} + +#ifdef CONFIG_KEXEC +void beat_kexec_cpu_down(int crash, int secondary) +{ + beatic_deinit_IRQ(); +} +#endif + EXPORT_SYMBOL(beat_get_term_char); EXPORT_SYMBOL(beat_put_term_char); EXPORT_SYMBOL(beat_halt_code); diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/celleb/beat.h index 2b16bf3bee89..b2e292df13ca 100644 --- a/arch/powerpc/platforms/celleb/beat.h +++ b/arch/powerpc/platforms/celleb/beat.h @@ -36,5 +36,7 @@ ssize_t beat_nvram_get_size(void); ssize_t beat_nvram_read(char *, size_t, loff_t *); ssize_t beat_nvram_write(char *, size_t, loff_t *); int beat_set_xdabr(unsigned long); +void beat_power_save(void); +void beat_kexec_cpu_down(int, int); #endif /* _CELLEB_BEAT_H */ diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c index 1fca3f23533b..a2180aa509d9 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/celleb/setup.c @@ -111,11 +111,6 @@ static void __init celleb_setup_arch(void) #endif } -static void beat_power_save(void) -{ - beat_pause(0); -} - static int __init celleb_probe(void) { unsigned long root = of_get_flat_dt_root(); @@ -128,13 +123,6 @@ static int __init celleb_probe(void) return 1; } -#ifdef CONFIG_KEXEC -static void celleb_kexec_cpu_down(int crash, int secondary) -{ - beatic_deinit_IRQ(); -} -#endif - static struct of_device_id celleb_bus_ids[] __initdata = { { .type = "scc", }, { .type = "ioif", }, /* old style */ @@ -175,7 +163,7 @@ define_machine(celleb) { .pci_probe_mode = celleb_pci_probe_mode, .pci_setup_phb = celleb_setup_phb, #ifdef CONFIG_KEXEC - .kexec_cpu_down = celleb_kexec_cpu_down, + .kexec_cpu_down = beat_kexec_cpu_down, .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, .machine_crash_shutdown = default_machine_crash_shutdown, From b41848031ac16aee8d045e86f0b7ad3ba97e961e Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Tue, 2 Oct 2007 18:21:21 +1000 Subject: [PATCH 0388/2804] [POWERPC] Celleb: Support for Power/Reset buttons This supports Power/Reset buttons on Beat on Celleb. On Beat, we have an event from Beat if Power button or Reset button is pressed. This patch catches the event and convert it to a signal to INIT process by calling ctrl_alt_del() function. /sbin/inittab have no entry to turn the machine power off so we have to detect if power button is pressed or not internally in our driver. This idea is taken from PS3's event handling subsystem. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/beat.c | 94 +++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c index ced6f68c7b0b..93ebb7d85120 100644 --- a/arch/powerpc/platforms/celleb/beat.c +++ b/arch/powerpc/platforms/celleb/beat.c @@ -22,16 +22,24 @@ #include #include #include +#include +#include +#include #include #include +#include +#include #include "beat_wrapper.h" #include "beat.h" +#include "interrupt.h" + +static int beat_pm_poweroff_flag; void beat_restart(char *cmd) { - beat_shutdown_logical_partition(1); + beat_shutdown_logical_partition(!beat_pm_poweroff_flag); } void beat_power_off(void) @@ -170,6 +178,90 @@ void beat_kexec_cpu_down(int crash, int secondary) } #endif +static irqreturn_t beat_power_event(int virq, void *arg) +{ + printk(KERN_DEBUG "Beat: power button pressed\n"); + beat_pm_poweroff_flag = 1; + ctrl_alt_del(); + return IRQ_HANDLED; +} + +static irqreturn_t beat_reset_event(int virq, void *arg) +{ + printk(KERN_DEBUG "Beat: reset button pressed\n"); + beat_pm_poweroff_flag = 0; + ctrl_alt_del(); + return IRQ_HANDLED; +} + +static struct beat_event_list { + const char *typecode; + irq_handler_t handler; + unsigned int virq; +} beat_event_list[] = { + { "power", beat_power_event, 0 }, + { "reset", beat_reset_event, 0 }, +}; + +static int __init beat_register_event(void) +{ + u64 path[4], data[2]; + int rc, i; + unsigned int virq; + + for (i = 0; i < ARRAY_SIZE(beat_event_list); i++) { + struct beat_event_list *ev = &beat_event_list[i]; + + if (beat_construct_event_receive_port(data) != 0) { + printk(KERN_ERR "Beat: " + "cannot construct event receive port for %s\n", + ev->typecode); + return -EINVAL; + } + + virq = irq_create_mapping(NULL, data[0]); + if (virq == NO_IRQ) { + printk(KERN_ERR "Beat: failed to get virtual IRQ" + " for event receive port for %s\n", + ev->typecode); + beat_destruct_event_receive_port(data[0]); + return -EIO; + } + ev->virq = virq; + + rc = request_irq(virq, ev->handler, IRQF_DISABLED, + ev->typecode, NULL); + if (rc != 0) { + printk(KERN_ERR "Beat: failed to request virtual IRQ" + " for event receive port for %s\n", + ev->typecode); + beat_destruct_event_receive_port(data[0]); + return rc; + } + + path[0] = 0x1000000065780000ul; /* 1,ex */ + path[1] = 0x627574746f6e0000ul; /* button */ + path[2] = 0; + strncpy((char *)&path[2], ev->typecode, 8); + path[3] = 0; + data[1] = 0; + + beat_create_repository_node(path, data); + } + return 0; +} + +static int __init beat_event_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_BEAT)) + return -EINVAL; + + beat_pm_poweroff_flag = 0; + return beat_register_event(); +} + +device_initcall(beat_event_init); + EXPORT_SYMBOL(beat_get_term_char); EXPORT_SYMBOL(beat_put_term_char); EXPORT_SYMBOL(beat_halt_code); From 7f2c85777db26c120821bc1c9b8273a30a705a09 Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Tue, 2 Oct 2007 18:23:46 +1000 Subject: [PATCH 0389/2804] [POWERPC] Celleb: New HTAB Guest OS Interface on Beat This changes the Celleb code to work with new Guest OS Interface to tweak HTAB on Beat. It detects old and new Guest OS Interfaces automatically. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/beat_syscall.h | 4 + arch/powerpc/platforms/celleb/beat_wrapper.h | 68 ++++++++++ arch/powerpc/platforms/celleb/htab.c | 130 +++++++++++++++++++ arch/powerpc/platforms/celleb/setup.c | 2 +- include/asm-powerpc/mmu-hash64.h | 1 + 5 files changed, 204 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/celleb/beat_syscall.h index 14e16974773f..8580dc7e1798 100644 --- a/arch/powerpc/platforms/celleb/beat_syscall.h +++ b/arch/powerpc/platforms/celleb/beat_syscall.h @@ -157,4 +157,8 @@ #define HV_rtc_write __BEAT_ADD_VENDOR_ID(0x191, 1) #define HV_eeprom_read __BEAT_ADD_VENDOR_ID(0x192, 1) #define HV_eeprom_write __BEAT_ADD_VENDOR_ID(0x193, 1) +#define HV_insert_htab_entry3 __BEAT_ADD_VENDOR_ID(0x104, 1) +#define HV_invalidate_htab_entry3 __BEAT_ADD_VENDOR_ID(0x105, 1) +#define HV_update_htab_permission3 __BEAT_ADD_VENDOR_ID(0x106, 1) +#define HV_clear_htab3 __BEAT_ADD_VENDOR_ID(0x107, 1) #endif diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/celleb/beat_wrapper.h index 76ea0a6a9011..cbc1487df7de 100644 --- a/arch/powerpc/platforms/celleb/beat_wrapper.h +++ b/arch/powerpc/platforms/celleb/beat_wrapper.h @@ -98,6 +98,37 @@ static inline s64 beat_write_htab_entry(u64 htab_id, u64 slot, return ret; } +static inline s64 beat_insert_htab_entry3(u64 htab_id, u64 group, + u64 hpte_v, u64 hpte_r, u64 mask_v, u64 value_v, u64 *slot) +{ + u64 dummy[1]; + s64 ret; + + ret = beat_hcall1(HV_insert_htab_entry3, dummy, htab_id, group, + hpte_v, hpte_r, mask_v, value_v); + *slot = dummy[0]; + return ret; +} + +static inline s64 beat_invalidate_htab_entry3(u64 htab_id, u64 group, + u64 va, u64 pss) +{ + return beat_hcall_norets(HV_invalidate_htab_entry3, + htab_id, group, va, pss); +} + +static inline s64 beat_update_htab_permission3(u64 htab_id, u64 group, + u64 va, u64 pss, u64 ptel_mask, u64 ptel_value) +{ + return beat_hcall_norets(HV_update_htab_permission3, + htab_id, group, va, pss, ptel_mask, ptel_value); +} + +static inline s64 beat_clear_htab3(u64 htab_id) +{ + return beat_hcall_norets(HV_clear_htab3, htab_id); +} + static inline void beat_shutdown_logical_partition(u64 code) { (void)beat_hcall_norets(HV_shutdown_logical_partition, code); @@ -217,4 +248,41 @@ static inline s64 beat_put_iopte(u64 ioas_id, u64 io_addr, u64 real_addr, ioid, flags); } +static inline s64 beat_construct_event_receive_port(u64 *port) +{ + u64 dummy[1]; + s64 ret; + + ret = beat_hcall1(HV_construct_event_receive_port, dummy); + *port = dummy[0]; + return ret; +} + +static inline s64 beat_destruct_event_receive_port(u64 port) +{ + s64 ret; + + ret = beat_hcall_norets(HV_destruct_event_receive_port, port); + return ret; +} + +static inline s64 beat_create_repository_node(u64 path[4], u64 data[2]) +{ + s64 ret; + + ret = beat_hcall_norets(HV_create_repository_node2, + path[0], path[1], path[2], path[3], data[0], data[1]); + return ret; +} + +static inline s64 beat_get_repository_node_value(u64 lpid, u64 path[4], + u64 data[2]) +{ + s64 ret; + + ret = beat_hcall2(HV_get_repository_node_value2, data, + lpid, path[0], path[1], path[2], path[3]); + return ret; +} + #endif diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/celleb/htab.c index 279d7339e170..5e75c77ea8f3 100644 --- a/arch/powerpc/platforms/celleb/htab.c +++ b/arch/powerpc/platforms/celleb/htab.c @@ -306,3 +306,133 @@ void __init hpte_init_beat(void) ppc_md.hpte_remove = beat_lpar_hpte_remove; ppc_md.hpte_clear_all = beat_lpar_hptab_clear; } + +static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, + unsigned long va, unsigned long pa, + unsigned long rflags, unsigned long vflags, + int psize) +{ + unsigned long lpar_rc; + unsigned long slot; + unsigned long hpte_v, hpte_r; + + /* same as iseries */ + if (vflags & HPTE_V_SECONDARY) + return -1; + + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " + "rflags=%lx, vflags=%lx, psize=%d)\n", + hpte_group, va, pa, rflags, vflags, psize); + + hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + hpte_r = hpte_encode_r(pa, psize) | rflags; + + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); + + if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) + hpte_r &= ~_PAGE_COHERENT; + + /* insert into not-volted entry */ + lpar_rc = beat_insert_htab_entry3(0, hpte_group, hpte_v, hpte_r, + HPTE_V_BOLTED, 0, &slot); + /* + * Since we try and ioremap PHBs we don't own, the pte insert + * will fail. However we must catch the failure in hash_page + * or we will loop forever, so return -2 in this case. + */ + if (unlikely(lpar_rc != 0)) { + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" lpar err %lx\n", lpar_rc); + return -2; + } + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" -> slot: %lx\n", slot); + + /* We have to pass down the secondary bucket bit here as well */ + return (slot ^ hpte_group) & 15; +} + +/* + * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and + * the low 3 bits of flags happen to line up. So no transform is needed. + * We can probably optimize here and assume the high bits of newpp are + * already zero. For now I am paranoid. + */ +static long beat_lpar_hpte_updatepp_v3(unsigned long slot, + unsigned long newpp, + unsigned long va, + int psize, int local) +{ + unsigned long lpar_rc; + unsigned long want_v; + unsigned long pss; + + want_v = hpte_encode_v(va, psize); + pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc; + + DBG_LOW(" update: " + "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", + want_v & HPTE_V_AVPN, slot, psize, newpp); + + lpar_rc = beat_update_htab_permission3(0, slot, want_v, pss, 7, newpp); + + if (lpar_rc == 0xfffffff7) { + DBG_LOW("not found !\n"); + return -1; + } + + DBG_LOW("ok\n"); + + BUG_ON(lpar_rc != 0); + + return 0; +} + +static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long va, + int psize, int local) +{ + unsigned long want_v; + unsigned long lpar_rc; + unsigned long pss; + + DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", + slot, va, psize, local); + want_v = hpte_encode_v(va, psize); + pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc; + + lpar_rc = beat_invalidate_htab_entry3(0, slot, want_v, pss); + + /* E_busy can be valid output: page may be already replaced */ + BUG_ON(lpar_rc != 0 && lpar_rc != 0xfffffff7); +} + +static int64_t _beat_lpar_hptab_clear_v3(void) +{ + return beat_clear_htab3(0); +} + +static void beat_lpar_hptab_clear_v3(void) +{ + _beat_lpar_hptab_clear_v3(); +} + +void __init hpte_init_beat_v3(void) +{ + if (_beat_lpar_hptab_clear_v3() == 0) { + ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate_v3; + ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp_v3; + ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp; + ppc_md.hpte_insert = beat_lpar_hpte_insert_v3; + ppc_md.hpte_remove = beat_lpar_hpte_remove; + ppc_md.hpte_clear_all = beat_lpar_hptab_clear_v3; + } else { + ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate; + ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp; + ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp; + ppc_md.hpte_insert = beat_lpar_hpte_insert; + ppc_md.hpte_remove = beat_lpar_hpte_remove; + ppc_md.hpte_clear_all = beat_lpar_hptab_clear; + } +} diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c index a2180aa509d9..59731e836e28 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/celleb/setup.c @@ -119,7 +119,7 @@ static int __init celleb_probe(void) return 0; powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE; - hpte_init_beat(); + hpte_init_beat_v3(); return 1; } diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h index 3112ad14ad95..b22b0d20e157 100644 --- a/include/asm-powerpc/mmu-hash64.h +++ b/include/asm-powerpc/mmu-hash64.h @@ -256,6 +256,7 @@ extern void hpte_init_native(void); extern void hpte_init_lpar(void); extern void hpte_init_iSeries(void); extern void hpte_init_beat(void); +extern void hpte_init_beat_v3(void); extern void stabs_alloc(void); extern void slb_initialize(void); From 86de9f5f5e663123a5a49c6fe39750bea3dba24c Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Tue, 2 Oct 2007 18:25:16 +1000 Subject: [PATCH 0390/2804] [POWERPC] Celleb: Serial I/O update This is an update for Serial I/O on Celleb. - Detection algorithm has been changed Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/scc_sio.c | 48 ++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c index bb98735ac46f..610008211ca1 100644 --- a/arch/powerpc/platforms/celleb/scc_sio.c +++ b/arch/powerpc/platforms/celleb/scc_sio.c @@ -1,7 +1,7 @@ /* * setup serial port in SCC * - * (C) Copyright 2006 TOSHIBA CORPORATION + * (C) Copyright 2006-2007 TOSHIBA 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 @@ -42,40 +42,40 @@ static struct { static int __init txx9_serial_init(void) { extern int early_serial_txx9_setup(struct uart_port *port); - struct device_node *node; + struct device_node *node = NULL; int i; struct uart_port req; struct of_irq irq; struct resource res; - node = of_find_node_by_path("/ioif1/sio"); - if (!node) - return 0; + while ((node = of_find_compatible_node(node, + "serial", "toshiba,sio-scc")) != NULL) { + for (i = 0; i < ARRAY_SIZE(txx9_scc_tab); i++) { + if (!(txx9_serial_bitmap & (1< Date: Tue, 2 Oct 2007 18:26:53 +1000 Subject: [PATCH 0391/2804] [POWERPC] Celleb: update for PCI This adds support for the PCI bus on Celleb with new "I/O routines for PowerPC." External PCI on Celleb must do explicit synchronization with devices (Bus has no automatic synchronization feature). Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/Kconfig | 1 + arch/powerpc/platforms/celleb/Makefile | 5 +- .../powerpc/platforms/celleb/io-workarounds.c | 279 ++++++++++++++++++ arch/powerpc/platforms/celleb/pci.c | 65 ++-- arch/powerpc/platforms/celleb/pci.h | 9 +- arch/powerpc/platforms/celleb/scc.h | 2 +- arch/powerpc/platforms/celleb/scc_epci.c | 80 +++-- arch/powerpc/platforms/celleb/setup.c | 2 + 8 files changed, 396 insertions(+), 47 deletions(-) create mode 100644 arch/powerpc/platforms/celleb/io-workarounds.c diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig index 2db1e293433e..04748d410fc9 100644 --- a/arch/powerpc/platforms/celleb/Kconfig +++ b/arch/powerpc/platforms/celleb/Kconfig @@ -2,6 +2,7 @@ config PPC_CELLEB bool "Toshiba's Cell Reference Set 'Celleb' Architecture" depends on PPC_MULTIPLATFORM && PPC64 select PPC_CELL + select PPC_INDIRECT_IO select PPC_OF_PLATFORM_PCI select HAS_TXX9_SERIAL select PPC_UDBG_BEAT diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile index 5240046d8671..889d43f715ea 100644 --- a/arch/powerpc/platforms/celleb/Makefile +++ b/arch/powerpc/platforms/celleb/Makefile @@ -1,6 +1,7 @@ obj-y += interrupt.o iommu.o setup.o \ - htab.o beat.o pci.o \ - scc_epci.o scc_uhc.o hvCall.o + htab.o beat.o hvCall.o pci.o \ + scc_epci.o scc_uhc.o \ + io-workarounds.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o diff --git a/arch/powerpc/platforms/celleb/io-workarounds.c b/arch/powerpc/platforms/celleb/io-workarounds.c new file mode 100644 index 000000000000..2b912140bcbb --- /dev/null +++ b/arch/powerpc/platforms/celleb/io-workarounds.c @@ -0,0 +1,279 @@ +/* + * Support for Celleb io workarounds + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This file is based to arch/powerpc/platform/cell/io-workarounds.c + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include +#include + +#include +#include +#include +#include +#include + +#include "pci.h" + +#define MAX_CELLEB_PCI_BUS 4 + +void *celleb_dummy_page_va; + +static struct celleb_pci_bus { + struct pci_controller *phb; + void (*dummy_read)(struct pci_controller *); +} celleb_pci_busses[MAX_CELLEB_PCI_BUS]; + +static int celleb_pci_count = 0; + +static struct celleb_pci_bus *celleb_pci_find(unsigned long vaddr, + unsigned long paddr) +{ + int i, j; + struct resource *res; + + for (i = 0; i < celleb_pci_count; i++) { + struct celleb_pci_bus *bus = &celleb_pci_busses[i]; + struct pci_controller *phb = bus->phb; + if (paddr) + for (j = 0; j < 3; j++) { + res = &phb->mem_resources[j]; + if (paddr >= res->start && paddr <= res->end) + return bus; + } + res = &phb->io_resource; + if (vaddr && vaddr >= res->start && vaddr <= res->end) + return bus; + } + return NULL; +} + +static void celleb_io_flush(const PCI_IO_ADDR addr) +{ + struct celleb_pci_bus *bus; + int token; + + token = PCI_GET_ADDR_TOKEN(addr); + + if (token && token <= celleb_pci_count) + bus = &celleb_pci_busses[token - 1]; + else { + unsigned long vaddr, paddr; + pte_t *ptep; + + vaddr = (unsigned long)PCI_FIX_ADDR(addr); + if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) + return; + + ptep = find_linux_pte(init_mm.pgd, vaddr); + if (ptep == NULL) + paddr = 0; + else + paddr = pte_pfn(*ptep) << PAGE_SHIFT; + bus = celleb_pci_find(vaddr, paddr); + + if (bus == NULL) + return; + } + + if (bus->dummy_read) + bus->dummy_read(bus->phb); +} + +static u8 celleb_readb(const PCI_IO_ADDR addr) +{ + u8 val; + val = __do_readb(addr); + celleb_io_flush(addr); + return val; +} + +static u16 celleb_readw(const PCI_IO_ADDR addr) +{ + u16 val; + val = __do_readw(addr); + celleb_io_flush(addr); + return val; +} + +static u32 celleb_readl(const PCI_IO_ADDR addr) +{ + u32 val; + val = __do_readl(addr); + celleb_io_flush(addr); + return val; +} + +static u64 celleb_readq(const PCI_IO_ADDR addr) +{ + u64 val; + val = __do_readq(addr); + celleb_io_flush(addr); + return val; +} + +static u16 celleb_readw_be(const PCI_IO_ADDR addr) +{ + u16 val; + val = __do_readw_be(addr); + celleb_io_flush(addr); + return val; +} + +static u32 celleb_readl_be(const PCI_IO_ADDR addr) +{ + u32 val; + val = __do_readl_be(addr); + celleb_io_flush(addr); + return val; +} + +static u64 celleb_readq_be(const PCI_IO_ADDR addr) +{ + u64 val; + val = __do_readq_be(addr); + celleb_io_flush(addr); + return val; +} + +static void celleb_readsb(const PCI_IO_ADDR addr, + void *buf, unsigned long count) +{ + __do_readsb(addr, buf, count); + celleb_io_flush(addr); +} + +static void celleb_readsw(const PCI_IO_ADDR addr, + void *buf, unsigned long count) +{ + __do_readsw(addr, buf, count); + celleb_io_flush(addr); +} + +static void celleb_readsl(const PCI_IO_ADDR addr, + void *buf, unsigned long count) +{ + __do_readsl(addr, buf, count); + celleb_io_flush(addr); +} + +static void celleb_memcpy_fromio(void *dest, + const PCI_IO_ADDR src, + unsigned long n) +{ + __do_memcpy_fromio(dest, src, n); + celleb_io_flush(src); +} + +static void __iomem *celleb_ioremap(unsigned long addr, + unsigned long size, + unsigned long flags) +{ + struct celleb_pci_bus *bus; + void __iomem *res = __ioremap(addr, size, flags); + int busno; + + bus = celleb_pci_find(0, addr); + if (bus != NULL) { + busno = bus - celleb_pci_busses; + PCI_SET_ADDR_TOKEN(res, busno + 1); + } + return res; +} + +static void celleb_iounmap(volatile void __iomem *addr) +{ + return __iounmap(PCI_FIX_ADDR(addr)); +} + +static struct ppc_pci_io celleb_pci_io __initdata = { + .readb = celleb_readb, + .readw = celleb_readw, + .readl = celleb_readl, + .readq = celleb_readq, + .readw_be = celleb_readw_be, + .readl_be = celleb_readl_be, + .readq_be = celleb_readq_be, + .readsb = celleb_readsb, + .readsw = celleb_readsw, + .readsl = celleb_readsl, + .memcpy_fromio = celleb_memcpy_fromio, +}; + +void __init celleb_pci_add_one(struct pci_controller *phb, + void (*dummy_read)(struct pci_controller *)) +{ + struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count]; + struct device_node *np = phb->arch_data; + + if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) { + printk(KERN_ERR "Too many pci bridges, workarounds" + " disabled for %s\n", np->full_name); + return; + } + + celleb_pci_count++; + + bus->phb = phb; + bus->dummy_read = dummy_read; +} + +static struct of_device_id celleb_pci_workaround_match[] __initdata = { + { + .name = "pci-pseudo", + .data = fake_pci_workaround_init, + }, { + .name = "epci", + .data = epci_workaround_init, + }, { + }, +}; + +int __init celleb_pci_workaround_init(void) +{ + struct pci_controller *phb; + struct device_node *node; + const struct of_device_id *match; + void (*init_func)(struct pci_controller *); + + celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!celleb_dummy_page_va) { + printk(KERN_ERR "Celleb: dummy read disabled." + "Alloc celleb_dummy_page_va failed\n"); + return 1; + } + + list_for_each_entry(phb, &hose_list, list_node) { + node = phb->arch_data; + match = of_match_node(celleb_pci_workaround_match, node); + + if (match) { + init_func = match->data; + (*init_func)(phb); + } + } + + ppc_pci_io = celleb_pci_io; + ppc_md.ioremap = celleb_ioremap; + ppc_md.iounmap = celleb_iounmap; + + return 0; +} diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c index 1348b23cbbc9..6bc32fda7a6b 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/celleb/pci.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -435,36 +436,58 @@ static void __init celleb_alloc_private_mem(struct pci_controller *hose) GFP_KERNEL); } +static int __init celleb_setup_fake_pci(struct device_node *dev, + struct pci_controller *phb) +{ + struct device_node *node; + + phb->ops = &celleb_fake_pci_ops; + celleb_alloc_private_mem(phb); + + for (node = of_get_next_child(dev, NULL); + node != NULL; node = of_get_next_child(dev, node)) + celleb_setup_fake_pci_device(node, phb); + + return 0; +} + +void __init fake_pci_workaround_init(struct pci_controller *phb) +{ + /** + * We will add fake pci bus to scc_pci_bus for the purpose to improve + * I/O Macro performance. But device-tree and device drivers + * are not ready to use address with a token. + */ + + /* celleb_pci_add_one(phb, NULL); */ +} + +static struct of_device_id celleb_phb_match[] __initdata = { + { + .name = "pci-pseudo", + .data = celleb_setup_fake_pci, + }, { + .name = "epci", + .data = celleb_setup_epci, + }, { + }, +}; + int __init celleb_setup_phb(struct pci_controller *phb) { - const char *name; struct device_node *dev = phb->arch_data; - struct device_node *node; - unsigned int rlen; + const struct of_device_id *match; + int (*setup_func)(struct device_node *, struct pci_controller *); - name = of_get_property(dev, "name", &rlen); - if (!name) + match = of_match_node(celleb_phb_match, dev); + if (!match) return 1; - pr_debug("PCI: celleb_setup_phb() %s\n", name); phb_set_bus_ranges(dev, phb); phb->buid = 1; - if (strcmp(name, "epci") == 0) { - phb->ops = &celleb_epci_ops; - return celleb_setup_epci(dev, phb); - - } else if (strcmp(name, "pci-pseudo") == 0) { - phb->ops = &celleb_fake_pci_ops; - celleb_alloc_private_mem(phb); - for (node = of_get_next_child(dev, NULL); - node != NULL; node = of_get_next_child(dev, node)) - celleb_setup_fake_pci_device(node, phb); - - } else - return 1; - - return 0; + setup_func = match->data; + return (*setup_func)(dev, phb); } int celleb_pci_probe_mode(struct pci_bus *bus) diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/celleb/pci.h index 5340e348e297..5d5544ffeddb 100644 --- a/arch/powerpc/platforms/celleb/pci.h +++ b/arch/powerpc/platforms/celleb/pci.h @@ -25,11 +25,18 @@ #include #include +#include extern int celleb_setup_phb(struct pci_controller *); extern int celleb_pci_probe_mode(struct pci_bus *); -extern struct pci_ops celleb_epci_ops; extern int celleb_setup_epci(struct device_node *, struct pci_controller *); +extern void *celleb_dummy_page_va; +extern int __init celleb_pci_workaround_init(void); +extern void __init celleb_pci_add_one(struct pci_controller *, + void (*)(struct pci_controller *)); +extern void fake_pci_workaround_init(struct pci_controller *); +extern void epci_workaround_init(struct pci_controller *); + #endif /* _CELLEB_PCI_H */ diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/celleb/scc.h index e9ce8a7c1882..6be1542a6e66 100644 --- a/arch/powerpc/platforms/celleb/scc.h +++ b/arch/powerpc/platforms/celleb/scc.h @@ -53,7 +53,7 @@ #define SCC_EPCI_STATUS 0x808 #define SCC_EPCI_ABTSET 0x80c #define SCC_EPCI_WATRP 0x810 -#define SCC_EPCI_DUMMYRADR 0x814 +#define SCC_EPCI_DUMYRADR 0x814 #define SCC_EPCI_SWRESP 0x818 #define SCC_EPCI_CNTOPT 0x81c #define SCC_EPCI_ECMODE 0xf00 diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c index 506fc8447554..9d076426676c 100644 --- a/arch/powerpc/platforms/celleb/scc_epci.c +++ b/arch/powerpc/platforms/celleb/scc_epci.c @@ -43,7 +43,11 @@ #define iob() __asm__ __volatile__("eieio; sync":::"memory") -static inline volatile void __iomem *celleb_epci_get_epci_base( +struct epci_private { + dma_addr_t dummy_page_da; +}; + +static inline PCI_IO_ADDR celleb_epci_get_epci_base( struct pci_controller *hose) { /* @@ -55,7 +59,7 @@ static inline volatile void __iomem *celleb_epci_get_epci_base( return hose->cfg_addr; } -static inline volatile void __iomem *celleb_epci_get_epci_cfg( +static inline PCI_IO_ADDR celleb_epci_get_epci_cfg( struct pci_controller *hose) { /* @@ -67,20 +71,11 @@ static inline volatile void __iomem *celleb_epci_get_epci_cfg( return hose->cfg_data; } -#if 0 /* test code for epci dummy read */ -static void celleb_epci_dummy_read(struct pci_dev *dev) +static void scc_epci_dummy_read(struct pci_controller *hose) { - volatile void __iomem *epci_base; - struct device_node *node; - struct pci_controller *hose; + PCI_IO_ADDR epci_base; u32 val; - node = (struct device_node *)dev->bus->sysdata; - hose = pci_find_hose_for_OF_device(node); - - if (!hose) - return; - epci_base = celleb_epci_get_epci_base(hose); val = in_be32(epci_base + SCC_EPCI_WATRP); @@ -88,21 +83,45 @@ static void celleb_epci_dummy_read(struct pci_dev *dev) return; } -#endif + +void __init epci_workaround_init(struct pci_controller *hose) +{ + PCI_IO_ADDR epci_base; + PCI_IO_ADDR reg; + struct epci_private *private = hose->private_data; + + BUG_ON(!private); + + private->dummy_page_da = dma_map_single(hose->parent, + celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE); + if (private->dummy_page_da == DMA_ERROR_CODE) { + printk(KERN_ERR "EPCI: dummy read disabled." + "Map dummy page failed.\n"); + return; + } + + celleb_pci_add_one(hose, scc_epci_dummy_read); + epci_base = celleb_epci_get_epci_base(hose); + + reg = epci_base + SCC_EPCI_DUMYRADR; + out_be32(reg, private->dummy_page_da); +} static inline void clear_and_disable_master_abort_interrupt( struct pci_controller *hose) { - volatile void __iomem *epci_base, *reg; + PCI_IO_ADDR epci_base; + PCI_IO_ADDR reg; epci_base = celleb_epci_get_epci_base(hose); reg = epci_base + PCI_COMMAND; out_be32(reg, in_be32(reg) | (PCI_STATUS_REC_MASTER_ABORT << 16)); } static int celleb_epci_check_abort(struct pci_controller *hose, - volatile void __iomem *addr) + PCI_IO_ADDR addr) { - volatile void __iomem *reg, *epci_base; + PCI_IO_ADDR reg; + PCI_IO_ADDR epci_base; u32 val; iob(); @@ -132,12 +151,12 @@ static int celleb_epci_check_abort(struct pci_controller *hose, return PCIBIOS_SUCCESSFUL; } -static volatile void __iomem *celleb_epci_make_config_addr( +static PCI_IO_ADDR celleb_epci_make_config_addr( struct pci_bus *bus, struct pci_controller *hose, unsigned int devfn, int where) { - volatile void __iomem *addr; + PCI_IO_ADDR addr; if (bus != hose->bus) addr = celleb_epci_get_epci_cfg(hose) + @@ -157,7 +176,8 @@ static volatile void __iomem *celleb_epci_make_config_addr( static int celleb_epci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) { - volatile void __iomem *epci_base, *addr; + PCI_IO_ADDR epci_base; + PCI_IO_ADDR addr; struct device_node *node; struct pci_controller *hose; @@ -220,7 +240,8 @@ static int celleb_epci_read_config(struct pci_bus *bus, static int celleb_epci_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - volatile void __iomem *epci_base, *addr; + PCI_IO_ADDR epci_base; + PCI_IO_ADDR addr; struct device_node *node; struct pci_controller *hose; @@ -286,7 +307,8 @@ struct pci_ops celleb_epci_ops = { static int __init celleb_epci_init(struct pci_controller *hose) { u32 val; - volatile void __iomem *reg, *epci_base; + PCI_IO_ADDR reg; + PCI_IO_ADDR epci_base; int hwres = 0; epci_base = celleb_epci_get_epci_base(hose); @@ -440,10 +462,24 @@ int __init celleb_setup_epci(struct device_node *node, r.start, (unsigned long)hose->cfg_data, (r.end - r.start + 1)); + hose->private_data = kzalloc(sizeof(struct epci_private), GFP_KERNEL); + if (hose->private_data == NULL) { + printk(KERN_ERR "EPCI: no memory for private data.\n"); + goto error; + } + + hose->ops = &celleb_epci_ops; celleb_epci_init(hose); return 0; error: + kfree(hose->private_data); + + if (hose->cfg_addr) + iounmap(hose->cfg_addr); + + if (hose->cfg_data) + iounmap(hose->cfg_data); return 1; } diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c index 59731e836e28..0f1dddb81cd2 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/celleb/setup.c @@ -137,6 +137,8 @@ static int __init celleb_publish_devices(void) /* Publish OF platform devices for southbridge IOs */ of_platform_bus_probe(NULL, celleb_bus_ids, NULL); + celleb_pci_workaround_init(); + return 0; } device_initcall(celleb_publish_devices); From 2d5f5659649924b86d527a2af2552bab741d1d6f Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Wed, 3 Oct 2007 07:40:12 +1000 Subject: [PATCH 0392/2804] [POWERPC] Use alloc_maybe_bootmem() in pcibios_alloc_controller Use alloc_maybe_bootmem() which wraps the if (mem_init_done) malloc clause. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci-common.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 083cfbdbe0b2..2ae3b6f778a3 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -65,14 +65,11 @@ static void __devinit pci_setup_pci_controller(struct pci_controller *hose) spin_unlock(&hose_spinlock); } -__init_refok struct pci_controller * pcibios_alloc_controller(struct device_node *dev) +struct pci_controller * pcibios_alloc_controller(struct device_node *dev) { struct pci_controller *phb; - if (mem_init_done) - phb = kmalloc(sizeof(struct pci_controller), GFP_KERNEL); - else - phb = alloc_bootmem(sizeof (struct pci_controller)); + phb = alloc_maybe_bootmem(sizeof(struct pci_controller), GFP_KERNEL); if (phb == NULL) return NULL; pci_setup_pci_controller(phb); From a0c7ce9c877ceef8428798ac91fb794f83609aed Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Wed, 3 Oct 2007 11:19:09 +1000 Subject: [PATCH 0393/2804] [POWERPC] Fix panic in RTAS code Some older pSeries machines were panicking in pSeries_log_error because it was getting called before it was ready. This is a result of commit "[POWERPC] pseries: Fix jumbled no_logging flag." (79c0108d1b9db4864ab77b2a95dfa04f2dcf264c). This fixes it by explicitly enabling RTAS error logging when it has been initialized, and also makes the code clearer by renaming the "no_more_logging" variable to "logging_enabled". Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/rtasd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 30925d29bcea..73401c820110 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -54,8 +54,9 @@ static unsigned int rtas_event_scan_rate; static int full_rtas_msgs = 0; /* Stop logging to nvram after first fatal error */ -static int no_more_logging; - +static int logging_enabled; /* Until we initialize everything, + * make sure we don't try logging + * anything */ static int error_log_cnt; /* @@ -217,7 +218,7 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) } /* Write error to NVRAM */ - if (!no_more_logging && !(err_type & ERR_FLAG_BOOT)) + if (logging_enabled && !(err_type & ERR_FLAG_BOOT)) nvram_write_error_log(buf, len, err_type, error_log_cnt); /* @@ -229,8 +230,8 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) printk_log_rtas(buf, len); /* Check to see if we need to or have stopped logging */ - if (fatal || no_more_logging) { - no_more_logging = 1; + if (fatal || !logging_enabled) { + logging_enabled = 0; spin_unlock_irqrestore(&rtasd_log_lock, s); return; } @@ -302,7 +303,7 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf, spin_lock_irqsave(&rtasd_log_lock, s); /* if it's 0, then we know we got the last one (the one in NVRAM) */ - if (rtas_log_size == 0 && !no_more_logging) + if (rtas_log_size == 0 && logging_enabled) nvram_clear_error_log(); spin_unlock_irqrestore(&rtasd_log_lock, s); @@ -414,6 +415,8 @@ static int rtasd(void *unused) memset(logdata, 0, rtas_error_log_max); rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type, &error_log_cnt); + /* We can use rtas_log_buf now */ + logging_enabled = 1; if (!rc) { if (err_type != ERR_FLAG_ALREADY_LOGGED) { From d831d0b83f205888f4be4dee0a074ad67ef809b3 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Fri, 21 Sep 2007 13:26:03 +1000 Subject: [PATCH 0394/2804] [POWERPC] Implement clockevents driver for powerpc This registers a clock event structure for the decrementer and turns on CONFIG_GENERIC_CLOCKEVENTS, which means that we now don't need most of timer_interrupt(), since the work is done in generic code. For secondary CPUs, their decrementer clockevent is registered when the CPU comes up (the generic code automatically removes the clockevent when the CPU goes down). Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 3 + arch/powerpc/kernel/smp.c | 2 + arch/powerpc/kernel/time.c | 131 +++++++++++++++++++++++++------------ include/asm-powerpc/time.h | 1 + 4 files changed, 94 insertions(+), 43 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 6819a94f2cac..a46f8116f476 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -35,6 +35,9 @@ config GENERIC_TIME config GENERIC_TIME_VSYSCALL def_bool y +config GENERIC_CLOCKEVENTS + def_bool y + config GENERIC_HARDIRQS bool default y diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index b24dcbaeecaa..d30f08fa0297 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -569,6 +569,8 @@ int __devinit start_secondary(void *unused) if (system_state > SYSTEM_BOOTING) snapshot_timebase(); + secondary_cpu_time_init(); + spin_lock(&call_lock); cpu_set(cpu, cpu_online_map); spin_unlock(&call_lock); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index e71a0d8c597a..d20947cf1735 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -73,6 +73,7 @@ /* powerpc clocksource/clockevent code */ +#include #include static cycle_t rtc_read(void); @@ -97,6 +98,27 @@ static struct clocksource clocksource_timebase = { .read = timebase_read, }; +#define DECREMENTER_MAX 0x7fffffff + +static int decrementer_set_next_event(unsigned long evt, + struct clock_event_device *dev); +static void decrementer_set_mode(enum clock_event_mode mode, + struct clock_event_device *dev); + +static struct clock_event_device decrementer_clockevent = { + .name = "decrementer", + .rating = 200, + .shift = 32, + .mult = 0, /* To be filled in */ + .irq = 0, + .set_next_event = decrementer_set_next_event, + .set_mode = decrementer_set_mode, + .features = CLOCK_EVT_FEAT_ONESHOT, +}; + +static DEFINE_PER_CPU(struct clock_event_device, decrementers); +void init_decrementer_clockevent(void); + #ifdef CONFIG_PPC_ISERIES static unsigned long __initdata iSeries_recal_titan; static signed long __initdata iSeries_recal_tb; @@ -517,10 +539,12 @@ void __init iSeries_time_init_early(void) void timer_interrupt(struct pt_regs * regs) { struct pt_regs *old_regs; - int next_dec; int cpu = smp_processor_id(); - unsigned long ticks; - u64 tb_next_jiffy; + struct clock_event_device *evt = &per_cpu(decrementers, cpu); + + /* Ensure a positive value is written to the decrementer, or else + * some CPUs will continuue to take decrementer exceptions */ + set_dec(DECREMENTER_MAX); #ifdef CONFIG_PPC32 if (atomic_read(&ppc_n_lost_interrupts) != 0) @@ -530,7 +554,6 @@ void timer_interrupt(struct pt_regs * regs) old_regs = set_irq_regs(regs); irq_enter(); - profile_tick(CPU_PROFILING); calculate_steal_time(); #ifdef CONFIG_PPC_ISERIES @@ -538,44 +561,20 @@ void timer_interrupt(struct pt_regs * regs) get_lppaca()->int_dword.fields.decr_int = 0; #endif - while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu))) - >= tb_ticks_per_jiffy) { - /* Update last_jiffy */ - per_cpu(last_jiffy, cpu) += tb_ticks_per_jiffy; - /* Handle RTCL overflow on 601 */ - if (__USE_RTC() && per_cpu(last_jiffy, cpu) >= 1000000000) - per_cpu(last_jiffy, cpu) -= 1000000000; + /* + * We cannot disable the decrementer, so in the period + * between this cpu's being marked offline in cpu_online_map + * and calling stop-self, it is taking timer interrupts. + * Avoid calling into the scheduler rebalancing code if this + * is the case. + */ + if (!cpu_is_offline(cpu)) + account_process_time(regs); - /* - * We cannot disable the decrementer, so in the period - * between this cpu's being marked offline in cpu_online_map - * and calling stop-self, it is taking timer interrupts. - * Avoid calling into the scheduler rebalancing code if this - * is the case. - */ - if (!cpu_is_offline(cpu)) - account_process_time(regs); - - /* - * No need to check whether cpu is offline here; boot_cpuid - * should have been fixed up by now. - */ - if (cpu != boot_cpuid) - continue; - - write_seqlock(&xtime_lock); - tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy; - if (__USE_RTC() && tb_next_jiffy >= 1000000000) - tb_next_jiffy -= 1000000000; - if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) { - tb_last_jiffy = tb_next_jiffy; - do_timer(1); - } - write_sequnlock(&xtime_lock); - } - - next_dec = tb_ticks_per_jiffy - ticks; - set_dec(next_dec); + if (evt->event_handler) + evt->event_handler(evt); + else + evt->set_next_event(DECREMENTER_MAX, evt); #ifdef CONFIG_PPC_ISERIES if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) @@ -795,6 +794,53 @@ void __init clocksource_init(void) clock->name, clock->mult, clock->shift); } +static int decrementer_set_next_event(unsigned long evt, + struct clock_event_device *dev) +{ + set_dec(evt); + return 0; +} + +static void decrementer_set_mode(enum clock_event_mode mode, + struct clock_event_device *dev) +{ + if (mode != CLOCK_EVT_MODE_ONESHOT) + decrementer_set_next_event(DECREMENTER_MAX, dev); +} + +static void register_decrementer_clockevent(int cpu) +{ + struct clock_event_device *dec = &per_cpu(decrementers, cpu); + + *dec = decrementer_clockevent; + dec->cpumask = cpumask_of_cpu(cpu); + + printk(KERN_ERR "clockevent: %s mult[%lx] shift[%d] cpu[%d]\n", + dec->name, dec->mult, dec->shift, cpu); + + clockevents_register_device(dec); +} + +void init_decrementer_clockevent(void) +{ + int cpu = smp_processor_id(); + + decrementer_clockevent.mult = div_sc(ppc_tb_freq, NSEC_PER_SEC, + decrementer_clockevent.shift); + decrementer_clockevent.max_delta_ns = + clockevent_delta2ns(DECREMENTER_MAX, &decrementer_clockevent); + decrementer_clockevent.min_delta_ns = 1000; + + register_decrementer_clockevent(cpu); +} + +void secondary_cpu_time_init(void) +{ + /* FIME: Should make unrelatred change to move snapshot_timebase + * call here ! */ + register_decrementer_clockevent(smp_processor_id()); +} + /* This function is only called on the boot processor */ void __init time_init(void) { @@ -908,8 +954,7 @@ void __init time_init(void) if (!firmware_has_feature(FW_FEATURE_ISERIES)) clocksource_init(); - /* Not exact, but the timer interrupt takes care of this */ - set_dec(tb_ticks_per_jiffy); + init_decrementer_clockevent(); } diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h index fa331dad97cb..f05895522f7f 100644 --- a/include/asm-powerpc/time.h +++ b/include/asm-powerpc/time.h @@ -245,6 +245,7 @@ extern void snapshot_timebases(void); #define snapshot_timebases() do { } while (0) #endif +extern void secondary_cpu_time_init(void); extern void iSeries_time_init_early(void); #endif /* __KERNEL__ */ From 1ad749980a5fda46f7ec920d8409ddcc89b38714 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Fri, 21 Sep 2007 13:26:03 +1000 Subject: [PATCH 0395/2804] [POWERPC] Enable tickless idle and high res timers for powerpc Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/idle.c | 3 +++ arch/powerpc/platforms/iseries/setup.c | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a46f8116f476..b387e1ed5177 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -173,6 +173,7 @@ config HIGHMEM bool "High memory support" depends on PPC32 +source kernel/time/Kconfig source kernel/Kconfig.hz source kernel/Kconfig.preempt source "fs/Kconfig.binfmt" diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index a9e9cbd32975..abd2957fe537 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,7 @@ void cpu_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); while (1) { + tick_nohz_stop_sched_tick(); while (!need_resched() && !cpu_should_die()) { ppc64_runlatch_off(); @@ -90,6 +92,7 @@ void cpu_idle(void) HMT_medium(); ppc64_runlatch_on(); + tick_nohz_restart_sched_tick(); if (cpu_should_die()) cpu_die(); preempt_enable_no_resched(); diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index fad493e29d37..37ae07ee54a9 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -561,6 +563,7 @@ static void yield_shared_processor(void) static void iseries_shared_idle(void) { while (1) { + tick_nohz_stop_sched_tick(); while (!need_resched() && !hvlpevent_is_pending()) { local_irq_disable(); ppc64_runlatch_off(); @@ -574,6 +577,7 @@ static void iseries_shared_idle(void) } ppc64_runlatch_on(); + tick_nohz_restart_sched_tick(); if (hvlpevent_is_pending()) process_iSeries_events(); @@ -589,6 +593,7 @@ static void iseries_dedicated_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); while (1) { + tick_nohz_stop_sched_tick(); if (!need_resched()) { while (!need_resched()) { ppc64_runlatch_off(); @@ -605,6 +610,7 @@ static void iseries_dedicated_idle(void) } ppc64_runlatch_on(); + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); From 2e71cc0d51d8f0dd4532d88c8fffccc08ba7ecdb Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 24 Sep 2007 07:32:15 -0500 Subject: [PATCH 0396/2804] [POWERPC] 4xx: Fix Walnut wrapper compile errors Pass the appropriate -mcpu flag to the treeboot-walnut.o object to prevent some toolchains from erroring out with unknown opcodes Signed-off-by: Josh Boyer --- arch/powerpc/boot/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index a6bba9a69e66..53fd8e6a4e3b 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -33,6 +33,7 @@ BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj) $(obj)/4xx.o: BOOTCFLAGS += -mcpu=440 $(obj)/ebony.o: BOOTCFLAGS += -mcpu=440 +$(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405 zlib := inffast.c inflate.c inftrees.c zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h From 84e3ad5b91ed51db7513a54ad7ed652ab0ca4ba1 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Sat, 22 Sep 2007 00:44:38 +1000 Subject: [PATCH 0397/2804] [POWERPC] 4xx: Introduce cpu_setup functionality to 44x platform This adds cpu_setup functionality for ppc44x platform. Low level cpu-spefic initialization routines should be placed in cpu_setup_44x.S and a callback should be added to cputable. The cpu_setup is invoked by identify_cpu() function at early init. Signed-off-by: Valentine Barshak Signed-off-by: Josh Boyer --- arch/powerpc/kernel/Makefile | 1 + arch/powerpc/kernel/cpu_setup_44x.S | 19 +++++++++++++++++++ arch/powerpc/kernel/cputable.c | 13 +++++++------ 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 arch/powerpc/kernel/cpu_setup_44x.S diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index fb33a7e71941..f1dd90439efc 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -58,6 +58,7 @@ obj-y += time.o prom.o traps.o setup-common.o \ misc_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o obj-$(CONFIG_PPC64) += dma_64.o iommu.o +obj-$(CONFIG_44x) += cpu_setup_44x.o obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o diff --git a/arch/powerpc/kernel/cpu_setup_44x.S b/arch/powerpc/kernel/cpu_setup_44x.S new file mode 100644 index 000000000000..6a6e6c71ad6f --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_44x.S @@ -0,0 +1,19 @@ +/* + * This file contains low level CPU setup functions. + * Valentine Barshak + * MontaVista Software, Inc (c) 2007 + * + * Based on cpu_setup_6xx code by + * Benjamin Herrenschmidt + * + * 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 + diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 8eb8087383eb..8711499f5a02 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1319,17 +1319,18 @@ struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr) for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) if ((pvr & s->pvr_mask) == s->pvr_value) { *cur = cpu_specs + i; -#ifdef CONFIG_PPC64 - /* ppc64 expects identify_cpu to also call setup_cpu - * for that processor. I will consolidate that at a - * later time, for now, just use our friend #ifdef. +#if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE) + /* ppc64 and booke expect identify_cpu to also call + * setup_cpu for that processor. I will consolidate + * that at a later time, for now, just use #ifdef. * we also don't need to PTRRELOC the function pointer - * on ppc64 as we are running at 0 in real mode. + * on ppc64 and booke as we are running at 0 in real + * mode on ppc64 and reloc_offset is always 0 on booke. */ if (s->cpu_setup) { s->cpu_setup(offset, s); } -#endif /* CONFIG_PPC64 */ +#endif /* CONFIG_PPC64 || CONFIG_BOOKE */ return s; } BUG(); From 8112753bb2c0045398c89d0647792b39805f6d40 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Sat, 22 Sep 2007 00:46:57 +1000 Subject: [PATCH 0398/2804] [POWERPC] 4xx: Move 440EP(x) FPU setup from head_44x to cpu_setup_4xx The PowerPC 440EP(x) FPU init is currently done in head_44x under ifdefs. Since we should support more then one board in the same kernel, we move FPU initialization code from head_44x to cpu_setup_44x and add cpu_setup callbacks for 440EP(x). Signed-off-by: Valentine Barshak Signed-off-by: Josh Boyer --- arch/powerpc/kernel/cpu_setup_44x.S | 14 ++++++++++++++ arch/powerpc/kernel/cputable.c | 6 ++++++ arch/powerpc/kernel/head_44x.S | 10 ---------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/kernel/cpu_setup_44x.S b/arch/powerpc/kernel/cpu_setup_44x.S index 6a6e6c71ad6f..c790634d946b 100644 --- a/arch/powerpc/kernel/cpu_setup_44x.S +++ b/arch/powerpc/kernel/cpu_setup_44x.S @@ -17,3 +17,17 @@ #include #include +_GLOBAL(__setup_cpu_440ep) + b __init_fpu_44x +_GLOBAL(__setup_cpu_440epx) + b __init_fpu_44x + +/* enable APU between CPU and FPU */ +_GLOBAL(__init_fpu_44x) + mfspr r3,SPRN_CCR0 + /* Clear DAPUIB flag in CCR0 */ + rlwinm r3,r3,0,12,10 + mtspr SPRN_CCR0,r3 + isync + blr + diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 8711499f5a02..94d98190e19a 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -31,6 +31,8 @@ EXPORT_SYMBOL(cur_cpu_spec); * and ppc64 */ #ifdef CONFIG_PPC32 +extern void __setup_cpu_440ep(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_440epx(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec); @@ -1111,6 +1113,7 @@ static struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, .icache_bsize = 32, .dcache_bsize = 32, + .cpu_setup = __setup_cpu_440ep, .platform = "ppc440", }, { @@ -1121,6 +1124,7 @@ static struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, .icache_bsize = 32, .dcache_bsize = 32, + .cpu_setup = __setup_cpu_440ep, .platform = "ppc440", }, { /* 440EPX */ @@ -1131,6 +1135,8 @@ static struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, .icache_bsize = 32, .dcache_bsize = 32, + .cpu_setup = __setup_cpu_440epx, + .platform = "ppc440", }, { /* 440GRX */ .pvr_mask = 0xf0000ffb, diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index c6a510bdefd4..864d63fbb204 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -217,16 +217,6 @@ skpinv: addi r4,r4,1 /* Increment */ lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ mtspr SPRN_IVPR,r4 -#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) - /* Clear DAPUIB flag in CCR0 (enable APU between CPU and FPU) */ - mfspr r2,SPRN_CCR0 - lis r3,0xffef - ori r3,r3,0xffff - and r2,r2,r3 - mtspr SPRN_CCR0,r2 - isync -#endif - /* * This is where the main kernel code starts. */ From 340ffd267c85fc28da7cfd681b177c816af800cf Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Sat, 22 Sep 2007 00:50:09 +1000 Subject: [PATCH 0399/2804] [POWERPC] 4xx: 440EPx/GRx incorrect write to DDR SDRAM errata workaround Add a workaround for PowerPC 440EPx/GRx incorrect write to DDR SDRAM errata. Data can be written to wrong address in SDRAM when write pipelining enabled on plb0. We disable it in the cpu_setup for these processors at early init. Signed-off-by: Valentine Barshak Signed-off-by: Josh Boyer --- arch/powerpc/kernel/cpu_setup_44x.S | 25 ++++++++++++++++++++++++- arch/powerpc/kernel/cputable.c | 3 +++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/cpu_setup_44x.S b/arch/powerpc/kernel/cpu_setup_44x.S index c790634d946b..8e1812e2f3ee 100644 --- a/arch/powerpc/kernel/cpu_setup_44x.S +++ b/arch/powerpc/kernel/cpu_setup_44x.S @@ -20,7 +20,14 @@ _GLOBAL(__setup_cpu_440ep) b __init_fpu_44x _GLOBAL(__setup_cpu_440epx) - b __init_fpu_44x + mflr r4 + bl __init_fpu_44x + bl __plb_disable_wrp + mtlr r4 + blr +_GLOBAL(__setup_cpu_440grx) + b __plb_disable_wrp + /* enable APU between CPU and FPU */ _GLOBAL(__init_fpu_44x) @@ -31,3 +38,19 @@ _GLOBAL(__init_fpu_44x) isync blr +/* + * Workaround for the incorrect write to DDR SDRAM errata. + * The write address can be corrupted during writes to + * DDR SDRAM when write pipelining is enabled on PLB0. + * Disable write pipelining here. + */ +#define DCRN_PLB4A0_ACR 0x81 + +_GLOBAL(__plb_disable_wrp) + mfdcr r3,DCRN_PLB4A0_ACR + /* clear WRP bit in PLB4A0_ACR */ + rlwinm r3,r3,0,8,6 + mtdcr DCRN_PLB4A0_ACR,r3 + isync + blr + diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 94d98190e19a..b03a442b7888 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -33,6 +33,7 @@ EXPORT_SYMBOL(cur_cpu_spec); #ifdef CONFIG_PPC32 extern void __setup_cpu_440ep(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_440epx(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_440grx(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec); @@ -1146,6 +1147,8 @@ static struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_BOOKE, .icache_bsize = 32, .dcache_bsize = 32, + .cpu_setup = __setup_cpu_440grx, + .platform = "ppc440", }, { /* 440GP Rev. B */ .pvr_mask = 0xf0000fff, From 7ddc5f978b16c024b6c1fcecbda6815d3d3222ef Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:13 +1000 Subject: [PATCH 0400/2804] [POWERPC] Virtex: Add uartlite bootwrapper driver Allows the bootwrapper to use the uartlite device for console output. Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/powerpc/boot/Makefile | 2 +- arch/powerpc/boot/ops.h | 1 + arch/powerpc/boot/serial.c | 2 ++ arch/powerpc/boot/uartlite.c | 64 ++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/uartlite.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 53fd8e6a4e3b..cf80db3ef78c 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -46,7 +46,7 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \ - cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c + cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index e948e57abef8..a180b6505f47 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h @@ -85,6 +85,7 @@ int ns16550_console_init(void *devp, struct serial_console_data *scdp); int mpsc_console_init(void *devp, struct serial_console_data *scdp); int cpm_console_init(void *devp, struct serial_console_data *scdp); int mpc5200_psc_console_init(void *devp, struct serial_console_data *scdp); +int uartlite_console_init(void *devp, struct serial_console_data *scdp); void *simple_alloc_init(char *base, unsigned long heap_size, unsigned long granularity, unsigned long max_allocs); extern void flush_cache(void *, unsigned long); diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c index 95e08e4ddcd2..cafeece20ac7 100644 --- a/arch/powerpc/boot/serial.c +++ b/arch/powerpc/boot/serial.c @@ -128,6 +128,8 @@ int serial_console_init(void) rc = cpm_console_init(devp, &serial_cd); else if (dt_is_compatible(devp, "mpc5200-psc-uart")) rc = mpc5200_psc_console_init(devp, &serial_cd); + else if (dt_is_compatible(devp, "xilinx,uartlite")) + rc = uartlite_console_init(devp, &serial_cd); /* Add other serial console driver calls here */ diff --git a/arch/powerpc/boot/uartlite.c b/arch/powerpc/boot/uartlite.c new file mode 100644 index 000000000000..f4249a74c367 --- /dev/null +++ b/arch/powerpc/boot/uartlite.c @@ -0,0 +1,64 @@ +/* + * Xilinx UARTLITE bootloader driver + * + * Copyright (C) 2007 Secret Lab Technologies Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include "types.h" +#include "string.h" +#include "stdio.h" +#include "io.h" +#include "ops.h" + +static void * reg_base; + +static int uartlite_open(void) +{ + /* Clear the RX FIFO */ + out_be32(reg_base + 0x0C, 0x2); + return 0; +} + +static void uartlite_putc(unsigned char c) +{ + while ((in_be32(reg_base + 0x8) & 0x08) != 0); /* spin */ + out_be32(reg_base + 0x4, c); +} + +static unsigned char uartlite_getc(void) +{ + while ((in_be32(reg_base + 0x8) & 0x01) == 0); /* spin */ + return in_be32(reg_base); +} + +static u8 uartlite_tstc(void) +{ + return ((in_be32(reg_base + 0x8) & 0x01) != 0); +} + +int uartlite_console_init(void *devp, struct serial_console_data *scdp) +{ + int n; + unsigned long reg_phys; + + n = getprop(devp, "virtual-reg", ®_base, sizeof(reg_base)); + if (n != sizeof(reg_base)) { + if (!dt_xlate_reg(devp, 0, ®_phys, NULL)) + return -1; + + reg_base = (void *)reg_phys; + } + + scdp->open = uartlite_open; + scdp->putc = uartlite_putc; + scdp->getc = uartlite_getc; + scdp->tstc = uartlite_tstc; + scdp->close = NULL; + return 0; +} From 36660cef734e3c80c4379443781ed0b2fe3e1ffe Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:18 +1000 Subject: [PATCH 0401/2804] [POWERPC] Virtex: Add Kconfig macros for Xilinx Virtex board support Add the needed kconfig macros to enable Xilinx Virtex board support Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/powerpc/platforms/40x/Kconfig | 38 ++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index c3dce3b3d524..a0a50b16b8a9 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -61,13 +61,22 @@ config WALNUT help This option enables support for the IBM PPC405GP evaluation board. -#config XILINX_ML300 -# bool "Xilinx-ML300" -# depends on 40x -# default y -# select VIRTEX_II_PRO -# help -# This option enables support for the Xilinx ML300 evaluation board. +config XILINX_VIRTEX_GENERIC_BOARD + bool "Generic Xilinx Virtex board" + depends on 40x + default n + select XILINX_VIRTEX_II_PRO + select XILINX_VIRTEX_4_FX + help + This option enables generic support for Xilinx Virtex based boards. + + The generic virtex board support matches any device tree which + specifies 'xilinx,virtex' in its compatible field. This includes + the Xilinx ML3xx and ML4xx reference designs using the powerpc + core. + + Most Virtex designs should use this unless it needs to do some + special configuration at board probe time. # 40x specific CPU modules, selected based on the board above. config NP405H @@ -91,11 +100,19 @@ config 405EP config 405GPR bool -config VIRTEX_II_PRO +config XILINX_VIRTEX bool + +config XILINX_VIRTEX_II_PRO + bool + select XILINX_VIRTEX select IBM405_ERR77 select IBM405_ERR51 +config XILINX_VIRTEX_4_FX + bool + select XILINX_VIRTEX + config STB03xxx bool select IBM405_ERR77 @@ -111,11 +128,6 @@ config IBM405_ERR77 config IBM405_ERR51 bool -#config XILINX_OCP -# bool -# depends on XILINX_ML300 -# default y - #config BIOS_FIXUP # bool # depends on BUBINGA || EP405 || SYCAMORE || WALNUT From 4dc9783ea9e4d6f97e40b808991b324a4719a837 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:23 +1000 Subject: [PATCH 0402/2804] [POWERPC] Virtex: add xilinx interrupt controller driver Adds support for the Xilinx opb-intc interrupt controller Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/xilinx_intc.c | 151 ++++++++++++++++++++++++++++++ include/asm-powerpc/xilinx_intc.h | 20 ++++ 3 files changed, 172 insertions(+) create mode 100644 arch/powerpc/sysdev/xilinx_intc.c create mode 100644 include/asm-powerpc/xilinx_intc.h diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index b0ea8e9495e8..592c17ea713d 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_I8259) += i8259.o obj-$(CONFIG_PPC_83xx) += ipic.o obj-$(CONFIG_4xx) += uic.o +obj-$(CONFIG_XILINX_VIRTEX) += xilinx_intc.o endif # Temporary hack until we have migrated to asm-powerpc diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c new file mode 100644 index 000000000000..c2f17cc43dfa --- /dev/null +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -0,0 +1,151 @@ +/* + * Interrupt controller driver for Xilinx Virtex FPGAs + * + * Copyright (C) 2007 Secret Lab Technologies Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + */ + +/* + * This is a driver for the interrupt controller typically found in + * Xilinx Virtex FPGA designs. + * + * The interrupt sense levels are hard coded into the FPGA design with + * typically a 1:1 relationship between irq lines and devices (no shared + * irq lines). Therefore, this driver does not attempt to handle edge + * and level interrupts differently. + */ +#undef DEBUG + +#include +#include +#include +#include +#include +#include + +/* + * INTC Registers + */ +#define XINTC_ISR 0 /* Interrupt Status */ +#define XINTC_IPR 4 /* Interrupt Pending */ +#define XINTC_IER 8 /* Interrupt Enable */ +#define XINTC_IAR 12 /* Interrupt Acknowledge */ +#define XINTC_SIE 16 /* Set Interrupt Enable bits */ +#define XINTC_CIE 20 /* Clear Interrupt Enable bits */ +#define XINTC_IVR 24 /* Interrupt Vector */ +#define XINTC_MER 28 /* Master Enable */ + +static struct irq_host *master_irqhost; + +/* + * IRQ Chip operations + */ +static void xilinx_intc_mask(unsigned int virq) +{ + int irq = virq_to_hw(virq); + void * regs = get_irq_chip_data(virq); + pr_debug("mask: %d\n", irq); + out_be32(regs + XINTC_CIE, 1 << irq); +} + +static void xilinx_intc_unmask(unsigned int virq) +{ + int irq = virq_to_hw(virq); + void * regs = get_irq_chip_data(virq); + pr_debug("unmask: %d\n", irq); + out_be32(regs + XINTC_SIE, 1 << irq); +} + +static void xilinx_intc_ack(unsigned int virq) +{ + int irq = virq_to_hw(virq); + void * regs = get_irq_chip_data(virq); + pr_debug("ack: %d\n", irq); + out_be32(regs + XINTC_IAR, 1 << irq); +} + +static struct irq_chip xilinx_intc_irqchip = { + .typename = "Xilinx INTC", + .mask = xilinx_intc_mask, + .unmask = xilinx_intc_unmask, + .ack = xilinx_intc_ack, +}; + +/* + * IRQ Host operations + */ +static int xilinx_intc_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t irq) +{ + set_irq_chip_data(virq, h->host_data); + set_irq_chip_and_handler(virq, &xilinx_intc_irqchip, handle_level_irq); + set_irq_type(virq, IRQ_TYPE_NONE); + return 0; +} + +static struct irq_host_ops xilinx_intc_ops = { + .map = xilinx_intc_map, +}; + +struct irq_host * __init +xilinx_intc_init(struct device_node *np) +{ + struct irq_host * irq; + struct resource res; + void * regs; + int rc; + + /* Find and map the intc registers */ + rc = of_address_to_resource(np, 0, &res); + if (rc) { + printk(KERN_ERR __FILE__ ": of_address_to_resource() failed\n"); + return NULL; + } + regs = ioremap(res.start, 32); + + printk(KERN_INFO "Xilinx intc at 0x%08X mapped to 0x%p\n", + res.start, regs); + + /* Setup interrupt controller */ + out_be32(regs + XINTC_IER, 0); /* disable all irqs */ + out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */ + out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ + + /* Allocate and initialize an irq_host structure. */ + irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 32, &xilinx_intc_ops, -1); + if (!irq) + panic(__FILE__ ": Cannot allocate IRQ host\n"); + irq->host_data = regs; + return irq; +} + +int xilinx_intc_get_irq(void) +{ + void * regs = master_irqhost->host_data; + pr_debug("get_irq:\n"); + return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR)); +} + +void __init xilinx_intc_init_tree(void) +{ + struct device_node *np; + + /* find top level interrupt controller */ + for_each_compatible_node(np, NULL, "xilinx,intc") { + if (!of_get_property(np, "interrupts", NULL)) + break; + } + + /* xilinx interrupt controller needs to be top level */ + BUG_ON(!np); + + master_irqhost = xilinx_intc_init(np); + BUG_ON(!master_irqhost); + + irq_set_default_host(master_irqhost); + of_node_put(np); +} diff --git a/include/asm-powerpc/xilinx_intc.h b/include/asm-powerpc/xilinx_intc.h new file mode 100644 index 000000000000..343612f8fece --- /dev/null +++ b/include/asm-powerpc/xilinx_intc.h @@ -0,0 +1,20 @@ +/* + * Xilinx intc external definitions + * + * Copyright 2007 Secret Lab Technologies Ltd. + * + * 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 _ASM_POWERPC_XILINX_INTC_H +#define _ASM_POWERPC_XILINX_INTC_H + +#ifdef __KERNEL__ + +extern void __init xilinx_intc_init_tree(void); +extern unsigned int xilinx_intc_get_irq(void); + +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_XILINX_INTC_H */ From 486ba7e6418b69143701f6772e8864d9299178b8 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:29 +1000 Subject: [PATCH 0403/2804] [POWERPC] Virtex: Add generic Xilinx Virtex board support Adds support for generic Xilinx Virtex boards. Any board which specifies "xilinx,virtex" in the compatible property will make use of this board support. Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/powerpc/platforms/40x/Makefile | 1 + arch/powerpc/platforms/40x/virtex.c | 50 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 arch/powerpc/platforms/40x/virtex.c diff --git a/arch/powerpc/platforms/40x/Makefile b/arch/powerpc/platforms/40x/Makefile index e6c0bbd063a4..0a3cfe99a7ed 100644 --- a/arch/powerpc/platforms/40x/Makefile +++ b/arch/powerpc/platforms/40x/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_WALNUT) += walnut.o +obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c new file mode 100644 index 000000000000..b52aa94abd78 --- /dev/null +++ b/arch/powerpc/platforms/40x/virtex.c @@ -0,0 +1,50 @@ +/* + * Xilinx Virtex (IIpro & 4FX) based board support + * + * Copyright 2007 Secret Lab Technologies Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +static int __init virtex_device_probe(void) +{ + if (!machine_is(virtex)) + return 0; + + of_platform_bus_probe(NULL, NULL, NULL); + + return 0; +} +device_initcall(virtex_device_probe); + +static int __init virtex_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "xilinx,virtex")) + return 0; + + return 1; +} + +static void __init virtex_setup_arch(void) +{ +} + +define_machine(virtex) { + .name = "Xilinx Virtex", + .probe = virtex_probe, + .setup_arch = virtex_setup_arch, + .init_IRQ = xilinx_intc_init_tree, + .get_irq = xilinx_intc_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; From 260c02a9beddf4186a8c7549b2eec2f6c67f1151 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:34 +1000 Subject: [PATCH 0404/2804] [POWERPC] Add PowerPC Xilinx Virtex entry to maintainers Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2ef086214135..d47367f68406 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2303,6 +2303,13 @@ L: linuxppc-dev@ozlabs.org T: git kernel.org:/pub/scm/linux/kernel/git/jwboyer/powerpc.git S: Maintained +LINUX FOR POWERPC EMBEDDED XILINX VIRTEX +P: Grant Likely +M: grant.likely@secretlab.ca +W: http://www.secretlab.ca/ +L: linuxppc-dev@ozlabs.org +S: Maintained + LINUX FOR POWERPC BOOT CODE P: Tom Rini M: trini@kernel.crashing.org From a15da8eff3627b8368db7f5dd260e5643213d918 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:39 +1000 Subject: [PATCH 0405/2804] [POWERPC] Uartlite: Fix reg io to access documented register size The Uartlite data sheet defines the registers as 32 bit wide. This patch changes the register access to use 32 bit transfers and eliminates the magic +3 offset which is currently required to make the device work. Signed-off-by: Grant Likely Acked-by: John Williams Signed-off-by: Josh Boyer --- arch/ppc/syslib/virtex_devices.c | 2 +- drivers/serial/uartlite.c | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/ppc/syslib/virtex_devices.c b/arch/ppc/syslib/virtex_devices.c index ace4ec08de51..270ad3acfb59 100644 --- a/arch/ppc/syslib/virtex_devices.c +++ b/arch/ppc/syslib/virtex_devices.c @@ -28,7 +28,7 @@ .num_resources = 2, \ .resource = (struct resource[]) { \ { \ - .start = XPAR_UARTLITE_##num##_BASEADDR + 3, \ + .start = XPAR_UARTLITE_##num##_BASEADDR, \ .end = XPAR_UARTLITE_##num##_HIGHADDR, \ .flags = IORESOURCE_MEM, \ }, \ diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index f5051cf1a0c8..59b674aa2c01 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -61,7 +61,7 @@ static int ulite_receive(struct uart_port *port, int stat) /* stats */ if (stat & ULITE_STATUS_RXVALID) { port->icount.rx++; - ch = readb(port->membase + ULITE_RX); + ch = in_be32((void*)port->membase + ULITE_RX); if (stat & ULITE_STATUS_PARITY) port->icount.parity++; @@ -106,7 +106,7 @@ static int ulite_transmit(struct uart_port *port, int stat) return 0; if (port->x_char) { - writeb(port->x_char, port->membase + ULITE_TX); + out_be32((void*)port->membase + ULITE_TX, port->x_char); port->x_char = 0; port->icount.tx++; return 1; @@ -115,7 +115,7 @@ static int ulite_transmit(struct uart_port *port, int stat) if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return 0; - writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX); + out_be32((void*)port->membase + ULITE_TX, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); port->icount.tx++; @@ -132,7 +132,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) int busy; do { - int stat = readb(port->membase + ULITE_STATUS); + int stat = in_be32((void*)port->membase + ULITE_STATUS); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); } while (busy); @@ -148,7 +148,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port) unsigned int ret; spin_lock_irqsave(&port->lock, flags); - ret = readb(port->membase + ULITE_STATUS); + ret = in_be32((void*)port->membase + ULITE_STATUS); spin_unlock_irqrestore(&port->lock, flags); return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; @@ -171,7 +171,7 @@ static void ulite_stop_tx(struct uart_port *port) static void ulite_start_tx(struct uart_port *port) { - ulite_transmit(port, readb(port->membase + ULITE_STATUS)); + ulite_transmit(port, in_be32((void*)port->membase + ULITE_STATUS)); } static void ulite_stop_rx(struct uart_port *port) @@ -200,17 +200,17 @@ static int ulite_startup(struct uart_port *port) if (ret) return ret; - writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, - port->membase + ULITE_CONTROL); - writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + out_be32((void*)port->membase + ULITE_CONTROL, + ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); + out_be32((void*)port->membase + ULITE_CONTROL, ULITE_CONTROL_IE); return 0; } static void ulite_shutdown(struct uart_port *port) { - writeb(0, port->membase + ULITE_CONTROL); - readb(port->membase + ULITE_CONTROL); /* dummy */ + out_be32((void*)port->membase + ULITE_CONTROL, 0); + in_be32((void*)port->membase + ULITE_CONTROL); /* dummy */ free_irq(port->irq, port); } @@ -314,7 +314,7 @@ static void ulite_console_wait_tx(struct uart_port *port) /* wait up to 10ms for the character(s) to be sent */ for (i = 0; i < 10000; i++) { - if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) + if (in_be32((void*)port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) break; udelay(1); } @@ -323,7 +323,7 @@ static void ulite_console_wait_tx(struct uart_port *port) static void ulite_console_putchar(struct uart_port *port, int ch) { ulite_console_wait_tx(port); - writeb(ch, port->membase + ULITE_TX); + out_be32((void*)port->membase + ULITE_TX, ch); } static void ulite_console_write(struct console *co, const char *s, @@ -340,8 +340,8 @@ static void ulite_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; - writeb(0, port->membase + ULITE_CONTROL); + ier = in_be32((void*)port->membase + ULITE_STATUS) & ULITE_STATUS_IE; + out_be32((void*)port->membase + ULITE_CONTROL, 0); uart_console_write(port, s, count, ulite_console_putchar); @@ -349,7 +349,7 @@ static void ulite_console_write(struct console *co, const char *s, /* restore interrupt state */ if (ier) - writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + out_be32((void*)port->membase + ULITE_CONTROL, ULITE_CONTROL_IE); if (locked) spin_unlock_irqrestore(&port->lock, flags); From 483c79db95b56a9650bd6f0638e7366eb20ffc01 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:44 +1000 Subject: [PATCH 0406/2804] [POWERPC] Uartlite: change name of ports to ulite_ports Changed to match naming convention used in the rest of the module Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 59b674aa2c01..ae05a67d9dbe 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -46,7 +46,7 @@ #define ULITE_CONTROL_IE 0x10 -static struct uart_port ports[ULITE_NR_UARTS]; +static struct uart_port ulite_ports[ULITE_NR_UARTS]; static int ulite_receive(struct uart_port *port, int stat) { @@ -329,7 +329,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch) static void ulite_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &ports[co->index]; + struct uart_port *port = &ulite_ports[co->index]; unsigned long flags; unsigned int ier; int locked = 1; @@ -366,7 +366,7 @@ static int __init ulite_console_setup(struct console *co, char *options) if (co->index < 0 || co->index >= ULITE_NR_UARTS) return -EINVAL; - port = &ports[co->index]; + port = &ulite_ports[co->index]; /* not initialized yet? */ if (!port->membase) @@ -420,7 +420,7 @@ static int __devinit ulite_probe(struct platform_device *pdev) if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS) return -EINVAL; - if (ports[pdev->id].membase) + if (ulite_ports[pdev->id].membase) return -EBUSY; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -431,7 +431,7 @@ static int __devinit ulite_probe(struct platform_device *pdev) if (!res2) return -ENODEV; - port = &ports[pdev->id]; + port = &ulite_ports[pdev->id]; port->fifosize = 16; port->regshift = 2; From 00775828e66124b4af54fafc393e5e89248802c9 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:49 +1000 Subject: [PATCH 0407/2804] [POWERPC] Uartlite: Add macro for uartlite device name Changed to make the following OF_platform bus binding patch a wee bit cleaner Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index ae05a67d9dbe..10e0da97811e 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -18,6 +18,7 @@ #include #include +#define ULITE_NAME "ttyUL" #define ULITE_MAJOR 204 #define ULITE_MINOR 187 #define ULITE_NR_UARTS 4 @@ -381,7 +382,7 @@ static int __init ulite_console_setup(struct console *co, char *options) static struct uart_driver ulite_uart_driver; static struct console ulite_console = { - .name = "ttyUL", + .name = ULITE_NAME, .write = ulite_console_write, .device = uart_console_device, .setup = ulite_console_setup, @@ -403,7 +404,7 @@ console_initcall(ulite_console_init); static struct uart_driver ulite_uart_driver = { .owner = THIS_MODULE, .driver_name = "uartlite", - .dev_name = "ttyUL", + .dev_name = ULITE_NAME, .major = ULITE_MAJOR, .minor = ULITE_MINOR, .nr = ULITE_NR_UARTS, From 8fa7b6100693e0b648ffd34564f6f41226502a19 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:54 +1000 Subject: [PATCH 0408/2804] [POWERPC] Uartlite: Separate the bus binding from the driver proper Separate the bus binding code from the driver structure allocation code in preparation for adding the of_platform_bus bindings needed by arch/powerpc Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 105 ++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 37 deletions(-) diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 10e0da97811e..c00a627ef89e 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -413,16 +413,75 @@ static struct uart_driver ulite_uart_driver = { #endif }; +static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) +{ + struct uart_port *port; + int rc; + + /* if id = -1; then scan for a free id and use that */ + if (id < 0) { + for (id = 0; id < ULITE_NR_UARTS; id++) + if (ulite_ports[id].mapbase == 0) + break; + } + if (id < 0 || id >= ULITE_NR_UARTS) { + dev_err(dev, "%s%i too large\n", ULITE_NAME, id); + return -EINVAL; + } + + if (ulite_ports[id].mapbase) { + dev_err(dev, "cannot assign to %s%i; it is already in use\n", + ULITE_NAME, id); + return -EBUSY; + } + + port = &ulite_ports[id]; + + spin_lock_init(&port->lock); + port->fifosize = 16; + port->regshift = 2; + port->iotype = UPIO_MEM; + port->iobase = 1; /* mark port in use */ + port->mapbase = base; + port->membase = NULL; + port->ops = &ulite_ops; + port->irq = irq; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = dev; + port->type = PORT_UNKNOWN; + port->line = id; + + dev_set_drvdata(dev, port); + + /* Register the port */ + rc = uart_add_one_port(&ulite_uart_driver, port); + if (rc) { + dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc); + port->mapbase = 0; + dev_set_drvdata(dev, NULL); + return rc; + } + + return 0; +} + +static int __devinit ulite_release(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + int rc = 0; + + if (port) { + rc = uart_remove_one_port(&ulite_uart_driver, port); + dev_set_drvdata(dev, NULL); + port->mapbase = 0; + } + + return rc; +} + static int __devinit ulite_probe(struct platform_device *pdev) { struct resource *res, *res2; - struct uart_port *port; - - if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS) - return -EINVAL; - - if (ulite_ports[pdev->id].membase) - return -EBUSY; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -432,40 +491,12 @@ static int __devinit ulite_probe(struct platform_device *pdev) if (!res2) return -ENODEV; - port = &ulite_ports[pdev->id]; - - port->fifosize = 16; - port->regshift = 2; - port->iotype = UPIO_MEM; - port->iobase = 1; /* mark port in use */ - port->mapbase = res->start; - port->membase = NULL; - port->ops = &ulite_ops; - port->irq = res2->start; - port->flags = UPF_BOOT_AUTOCONF; - port->dev = &pdev->dev; - port->type = PORT_UNKNOWN; - port->line = pdev->id; - - uart_add_one_port(&ulite_uart_driver, port); - platform_set_drvdata(pdev, port); - - return 0; + return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); } static int ulite_remove(struct platform_device *pdev) { - struct uart_port *port = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (port) - uart_remove_one_port(&ulite_uart_driver, port); - - /* mark port as free */ - port->membase = NULL; - - return 0; + return ulite_release(&pdev->dev); } static struct platform_driver ulite_platform_driver = { From 435706b385d1f5422e44ee86b5dec0a2150eca02 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:59 +1000 Subject: [PATCH 0409/2804] [POWERPC] Uartlite: Comment block tidy Tidy the comments to split the driver into logical section; the main driver, the console driver, the platform bus binding, and module initialization and teardown. Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 43 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index c00a627ef89e..ed13b9fac1af 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -23,9 +23,13 @@ #define ULITE_MINOR 187 #define ULITE_NR_UARTS 4 -/* For register details see datasheet: - http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf -*/ +/* --------------------------------------------------------------------- + * Register definitions + * + * For register details see datasheet: + * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf + */ + #define ULITE_RX 0x00 #define ULITE_TX 0x04 #define ULITE_STATUS 0x08 @@ -49,6 +53,10 @@ static struct uart_port ulite_ports[ULITE_NR_UARTS]; +/* --------------------------------------------------------------------- + * Core UART driver operations + */ + static int ulite_receive(struct uart_port *port, int stat) { struct tty_struct *tty = port->info->tty; @@ -308,6 +316,10 @@ static struct uart_ops ulite_ops = { .verify_port = ulite_verify_port }; +/* --------------------------------------------------------------------- + * Console driver operations + */ + #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE static void ulite_console_wait_tx(struct uart_port *port) { @@ -413,6 +425,19 @@ static struct uart_driver ulite_uart_driver = { #endif }; +/* --------------------------------------------------------------------- + * Port assignment functions (mapping devices to uart_port structures) + */ + +/** ulite_assign: register a uartlite device with the driver + * + * @dev: pointer to device structure + * @id: requested id number. Pass -1 for automatic port assignment + * @base: base address of uartlite registers + * @irq: irq number for uartlite + * + * Returns: 0 on success, <0 otherwise + */ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) { struct uart_port *port; @@ -465,6 +490,10 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) return 0; } +/** ulite_release: register a uartlite device with the driver + * + * @dev: pointer to device structure + */ static int __devinit ulite_release(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); @@ -479,6 +508,10 @@ static int __devinit ulite_release(struct device *dev) return rc; } +/* --------------------------------------------------------------------- + * Platform bus binding + */ + static int __devinit ulite_probe(struct platform_device *pdev) { struct resource *res, *res2; @@ -508,6 +541,10 @@ static struct platform_driver ulite_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * Module setup/teardown + */ + int __init ulite_init(void) { int ret; From 852e1ea748e83eba7fdb1cc198f271837b16137b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:16:04 +1000 Subject: [PATCH 0410/2804] [POWERPC] Uartlite: Add of-platform-bus binding Add of_platform bus binding so this driver can be used with arch/powerpc Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 96 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index ed13b9fac1af..0904c2a62fc4 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -1,7 +1,8 @@ /* * uartlite.c: Serial driver for Xilinx uartlite serial controller * - * Peter Korsgaard + * Copyright (C) 2006 Peter Korsgaard + * Copyright (C) 2007 Secret Lab Technologies Ltd. * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any @@ -17,6 +18,10 @@ #include #include #include +#if defined(CONFIG_OF) +#include +#include +#endif #define ULITE_NAME "ttyUL" #define ULITE_MAJOR 204 @@ -382,8 +387,10 @@ static int __init ulite_console_setup(struct console *co, char *options) port = &ulite_ports[co->index]; /* not initialized yet? */ - if (!port->membase) + if (!port->membase) { + pr_debug("console on ttyUL%i not initialized\n", co->index); return -ENODEV; + } if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -541,6 +548,72 @@ static struct platform_driver ulite_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * OF bus bindings + */ +#if defined(CONFIG_OF) +static int __devinit +ulite_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct resource res; + const unsigned int *id; + int irq, rc; + + dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match); + + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalide address\n"); + return rc; + } + + irq = irq_of_parse_and_map(op->node, 0); + + id = of_get_property(op->node, "port-number", NULL); + + return ulite_assign(&op->dev, id ? *id : -1, res.start, irq); +} + +static int __devexit ulite_of_remove(struct of_device *op) +{ + return ulite_release(&op->dev); +} + +/* Match table for of_platform binding */ +static struct of_device_id __devinit ulite_of_match[] = { + { .type = "serial", .compatible = "xilinx,uartlite", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ulite_of_match); + +static struct of_platform_driver ulite_of_driver = { + .owner = THIS_MODULE, + .name = "uartlite", + .match_table = ulite_of_match, + .probe = ulite_of_probe, + .remove = __devexit_p(ulite_of_remove), + .driver = { + .name = "uartlite", + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init ulite_of_register(void) +{ + pr_debug("uartlite: calling of_register_platform_driver()\n"); + return of_register_platform_driver(&ulite_of_driver); +} + +static inline void __exit ulite_of_unregister(void) +{ + of_unregister_platform_driver(&ulite_of_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init ulite_of_register(void) { return 0; } +static inline void __exit ulite_of_unregister(void) { } +#endif /* CONFIG_OF */ + /* --------------------------------------------------------------------- * Module setup/teardown */ @@ -549,20 +622,35 @@ int __init ulite_init(void) { int ret; + pr_debug("uartlite: calling uart_register_driver()\n"); ret = uart_register_driver(&ulite_uart_driver); if (ret) - return ret; + goto err_uart; + ret = ulite_of_register(); + if (ret) + goto err_of; + + pr_debug("uartlite: calling platform_driver_register()\n"); ret = platform_driver_register(&ulite_platform_driver); if (ret) - uart_unregister_driver(&ulite_uart_driver); + goto err_plat; + return 0; + +err_plat: + ulite_of_unregister(); +err_of: + uart_unregister_driver(&ulite_uart_driver); +err_uart: + printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); return ret; } void __exit ulite_exit(void) { platform_driver_unregister(&ulite_platform_driver); + ulite_of_unregister(); uart_unregister_driver(&ulite_uart_driver); } From fb4e6e663b404ecdfac2e3f6e643d204488b28e9 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:16:09 +1000 Subject: [PATCH 0411/2804] [POWERPC] Uartlite: Let the console be initialized earlier By configuring it earlier we get console output sooner which is helpful for debugging when the kernel crashes before the serial drivers are initialized. Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 41 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 0904c2a62fc4..2b8404c81164 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -373,6 +373,31 @@ static void ulite_console_write(struct console *co, const char *s, spin_unlock_irqrestore(&port->lock, flags); } +#if defined(CONFIG_OF) +static inline void __init ulite_console_of_find_device(int id) +{ + struct device_node *np; + struct resource res; + const unsigned int *of_id; + int rc; + + for_each_compatible_node(np, NULL, "xilinx,uartlite") { + of_id = of_get_property(np, "port-number", NULL); + if ((!of_id) || (*of_id != id)) + continue; + + rc = of_address_to_resource(np, 0, &res); + if (rc) + continue; + + ulite_ports[id].mapbase = res.start; + return; + } +} +#else /* CONFIG_OF */ +static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ } +#endif /* CONFIG_OF */ + static int __init ulite_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -386,10 +411,20 @@ static int __init ulite_console_setup(struct console *co, char *options) port = &ulite_ports[co->index]; + /* Check if it is an OF device */ + if (!port->mapbase) + ulite_console_of_find_device(co->index); + + /* Do we have a device now? */ + if (!port->mapbase) { + pr_debug("console on ttyUL%i not present\n", co->index); + return -ENODEV; + } + /* not initialized yet? */ if (!port->membase) { - pr_debug("console on ttyUL%i not initialized\n", co->index); - return -ENODEV; + if (ulite_request_port(port)) + return -ENODEV; } if (options) @@ -461,7 +496,7 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) return -EINVAL; } - if (ulite_ports[id].mapbase) { + if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) { dev_err(dev, "cannot assign to %s%i; it is already in use\n", ULITE_NAME, id); return -EBUSY; From 267b49a96e30f129600bdb4f3fa6d80d6dd42523 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 2 Oct 2007 07:33:22 -0500 Subject: [PATCH 0412/2804] [POWERPC] Add treeImage to .gitignore Tell git to ignore the generated treeImage.* files in arch/powerpc/boot Signed-off-by: Josh Boyer --- arch/powerpc/boot/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore index 2c187ca05982..65f4118cbe78 100644 --- a/arch/powerpc/boot/.gitignore +++ b/arch/powerpc/boot/.gitignore @@ -19,6 +19,7 @@ kernel-vmlinux.strip.gz mktree uImage cuImage.* +treeImage.* zImage zImage.bin.* zImage.chrp From bedfc8a040378cb51f46155c980d295c2c397203 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 07:46:55 +1000 Subject: [PATCH 0413/2804] [POWERPC] Uartlite: Flush RX fifo in bootwrapper Flush the uartlite RX fifo so that characters typed before entry into the zImage wrapper do not muck up the kernel command line. Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/ppc/boot/simple/misc-embedded.c | 4 +++- arch/ppc/boot/simple/uartlite_tty.c | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/ppc/boot/simple/misc-embedded.c b/arch/ppc/boot/simple/misc-embedded.c index 8a08ad397ed5..d5a00eb0e4eb 100644 --- a/arch/ppc/boot/simple/misc-embedded.c +++ b/arch/ppc/boot/simple/misc-embedded.c @@ -89,7 +89,9 @@ load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *b * initialize the serial console port. */ embed_config(&bp); -#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) +#if defined(CONFIG_SERIAL_CPM_CONSOLE) || \ + defined(CONFIG_SERIAL_8250_CONSOLE) || \ + defined(CONFIG_SERIAL_UARTLITE_CONSOLE) com_port = serial_init(0, bp); #endif diff --git a/arch/ppc/boot/simple/uartlite_tty.c b/arch/ppc/boot/simple/uartlite_tty.c index 0eae1eab38d4..ca1743e3e912 100644 --- a/arch/ppc/boot/simple/uartlite_tty.c +++ b/arch/ppc/boot/simple/uartlite_tty.c @@ -16,6 +16,14 @@ #define UARTLITE_BASEADDR ((void*)(XPAR_UARTLITE_0_BASEADDR)) +unsigned long +serial_init(int chan, void *ignored) +{ + /* Clear the RX FIFO */ + out_be32(UARTLITE_BASEADDR + 0x0C, 0x2); + return 0; +} + void serial_putc(unsigned long com_port, unsigned char c) { From dc8afdc7ada82562231cbae867fe6dcdb7b677f5 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 07:47:00 +1000 Subject: [PATCH 0414/2804] [POWERPC] XilinxFB: Move xilinxfb_platform_data definition to a shared header file XilnixFB can be used by more than just arch/ppc. Move the data structure definition into include/linux/xilinxfb.h so it can be used by microblaze and arch/powerpc Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/ppc/syslib/virtex_devices.h | 8 +------- drivers/video/xilinxfb.c | 2 +- include/linux/xilinxfb.h | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 include/linux/xilinxfb.h diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h index 9f38d92ae536..6ebd9b4b8f1c 100644 --- a/arch/ppc/syslib/virtex_devices.h +++ b/arch/ppc/syslib/virtex_devices.h @@ -12,13 +12,7 @@ #define __ASM_VIRTEX_DEVICES_H__ #include - -/* ML300/403 reference design framebuffer driver platform data struct */ -struct xilinxfb_platform_data { - u32 rotate_screen; - u32 screen_height_mm; - u32 screen_width_mm; -}; +#include void __init virtex_early_serial_map(void); diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 6ef9733a18d4..4bc67ab56afa 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -30,7 +30,7 @@ #include #include -#include +#include #define DRIVER_NAME "xilinxfb" #define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver" diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h new file mode 100644 index 000000000000..9ad984d22c38 --- /dev/null +++ b/include/linux/xilinxfb.h @@ -0,0 +1,23 @@ +/* + * Platform device data for Xilinx Framebuffer device + * + * Copyright 2007 Secret Lab Technologies Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __XILINXFB_H__ +#define __XILINXFB_H__ + +#include + +/* ML300/403 reference design framebuffer driver platform data struct */ +struct xilinxfb_platform_data { + u32 rotate_screen; + u32 screen_height_mm; + u32 screen_width_mm; +}; + +#endif /* __XILINXFB_H__ */ From 69c9c94303e309c02cf4b3e671a46a34fd0c4b0b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 07:47:05 +1000 Subject: [PATCH 0415/2804] [POWERPC] Setup default eth addr in embed_config for Xilinx Virtex platforms This simply adds the boilerplate default Ethernet address to embed_config for the Xilinx platform (bug fix). Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/ppc/boot/simple/embed_config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c index 840bff2a45fb..3b46792d7b8b 100644 --- a/arch/ppc/boot/simple/embed_config.c +++ b/arch/ppc/boot/simple/embed_config.c @@ -752,7 +752,9 @@ embed_config(bd_t ** bdp) static const unsigned long congruence_classes = 256; unsigned long addr; unsigned long dccr; + uint8_t* cp; bd_t *bd; + int i; /* * Invalidate the data cache if the data cache is turned off. @@ -778,6 +780,12 @@ embed_config(bd_t ** bdp) bd->bi_intfreq = XPAR_CORE_CLOCK_FREQ_HZ; bd->bi_busfreq = XPAR_PLB_CLOCK_FREQ_HZ; bd->bi_pci_busfreq = XPAR_PCI_0_CLOCK_FREQ_HZ; + + /* Copy the default ethernet address */ + cp = (u_char *)def_enet_addr; + for (i=0; i<6; i++) + bd->bi_enetaddr[i] = *cp++; + timebase_period_ns = 1000000000 / bd->bi_tbfreq; /* see bi_tbfreq definition in arch/ppc/platforms/4xx/xilinx_ml300.h */ } From be1b4d34e3a379d20d50e75a95aa5c3f0c7cf612 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 3 Oct 2007 02:44:15 +1000 Subject: [PATCH 0416/2804] [POWERPC] Uartlite: Add macros for register names Add macros to define register names to improve readability. Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/powerpc/boot/uartlite.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/boot/uartlite.c b/arch/powerpc/boot/uartlite.c index f4249a74c367..38a470b329e3 100644 --- a/arch/powerpc/boot/uartlite.c +++ b/arch/powerpc/boot/uartlite.c @@ -16,30 +16,45 @@ #include "io.h" #include "ops.h" +#define ULITE_RX 0x00 +#define ULITE_TX 0x04 +#define ULITE_STATUS 0x08 +#define ULITE_CONTROL 0x0c + +#define ULITE_STATUS_RXVALID 0x01 +#define ULITE_STATUS_TXFULL 0x08 + +#define ULITE_CONTROL_RST_RX 0x02 + static void * reg_base; static int uartlite_open(void) { /* Clear the RX FIFO */ - out_be32(reg_base + 0x0C, 0x2); + out_be32(reg_base + ULITE_CONTROL, ULITE_CONTROL_RST_RX); return 0; } static void uartlite_putc(unsigned char c) { - while ((in_be32(reg_base + 0x8) & 0x08) != 0); /* spin */ - out_be32(reg_base + 0x4, c); + u32 reg = ULITE_STATUS_TXFULL; + while (reg & ULITE_STATUS_TXFULL) /* spin on TXFULL bit */ + reg = in_be32(reg_base + ULITE_STATUS); + out_be32(reg_base + ULITE_TX, c); } static unsigned char uartlite_getc(void) { - while ((in_be32(reg_base + 0x8) & 0x01) == 0); /* spin */ - return in_be32(reg_base); + u32 reg = ULITE_STATUS_RXVALID; + while (reg & ULITE_STATUS_RXVALID) /* spin on RXVALID bit */ + reg = in_be32(reg_base + ULITE_STATUS); + return in_be32(reg_base + ULITE_RX); } static u8 uartlite_tstc(void) { - return ((in_be32(reg_base + 0x8) & 0x01) != 0); + u32 reg = in_be32(reg_base + ULITE_STATUS); + return reg & ULITE_STATUS_RXVALID; } int uartlite_console_init(void *devp, struct serial_console_data *scdp) From e077b50c29a7e8be5812d1156934ea837b712ca6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 3 Oct 2007 02:47:02 +1000 Subject: [PATCH 0417/2804] [POWERPC] Uartlite: Revert register io access changes Reverts commit a15da8eff3627b8368db7f5dd260e5643213d918 This driver is used by devices other than the xilinx opb-uartlite which depend on bytewise access to the registers. The change to 32 bit access does not work on these devices. Signed-off-by: Grant Likely Acked-by: Peter Korsgaard Signed-off-by: Josh Boyer --- arch/ppc/syslib/virtex_devices.c | 2 +- drivers/serial/uartlite.c | 36 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/ppc/syslib/virtex_devices.c b/arch/ppc/syslib/virtex_devices.c index 270ad3acfb59..ace4ec08de51 100644 --- a/arch/ppc/syslib/virtex_devices.c +++ b/arch/ppc/syslib/virtex_devices.c @@ -28,7 +28,7 @@ .num_resources = 2, \ .resource = (struct resource[]) { \ { \ - .start = XPAR_UARTLITE_##num##_BASEADDR, \ + .start = XPAR_UARTLITE_##num##_BASEADDR + 3, \ .end = XPAR_UARTLITE_##num##_HIGHADDR, \ .flags = IORESOURCE_MEM, \ }, \ diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 2b8404c81164..dfef83f14960 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -75,7 +75,7 @@ static int ulite_receive(struct uart_port *port, int stat) /* stats */ if (stat & ULITE_STATUS_RXVALID) { port->icount.rx++; - ch = in_be32((void*)port->membase + ULITE_RX); + ch = readb(port->membase + ULITE_RX); if (stat & ULITE_STATUS_PARITY) port->icount.parity++; @@ -120,7 +120,7 @@ static int ulite_transmit(struct uart_port *port, int stat) return 0; if (port->x_char) { - out_be32((void*)port->membase + ULITE_TX, port->x_char); + writeb(port->x_char, port->membase + ULITE_TX); port->x_char = 0; port->icount.tx++; return 1; @@ -129,7 +129,7 @@ static int ulite_transmit(struct uart_port *port, int stat) if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return 0; - out_be32((void*)port->membase + ULITE_TX, xmit->buf[xmit->tail]); + writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); port->icount.tx++; @@ -146,7 +146,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) int busy; do { - int stat = in_be32((void*)port->membase + ULITE_STATUS); + int stat = readb(port->membase + ULITE_STATUS); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); } while (busy); @@ -162,7 +162,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port) unsigned int ret; spin_lock_irqsave(&port->lock, flags); - ret = in_be32((void*)port->membase + ULITE_STATUS); + ret = readb(port->membase + ULITE_STATUS); spin_unlock_irqrestore(&port->lock, flags); return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; @@ -185,7 +185,7 @@ static void ulite_stop_tx(struct uart_port *port) static void ulite_start_tx(struct uart_port *port) { - ulite_transmit(port, in_be32((void*)port->membase + ULITE_STATUS)); + ulite_transmit(port, readb(port->membase + ULITE_STATUS)); } static void ulite_stop_rx(struct uart_port *port) @@ -214,17 +214,17 @@ static int ulite_startup(struct uart_port *port) if (ret) return ret; - out_be32((void*)port->membase + ULITE_CONTROL, - ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); - out_be32((void*)port->membase + ULITE_CONTROL, ULITE_CONTROL_IE); + writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, + port->membase + ULITE_CONTROL); + writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); return 0; } static void ulite_shutdown(struct uart_port *port) { - out_be32((void*)port->membase + ULITE_CONTROL, 0); - in_be32((void*)port->membase + ULITE_CONTROL); /* dummy */ + writeb(0, port->membase + ULITE_CONTROL); + readb(port->membase + ULITE_CONTROL); /* dummy */ free_irq(port->irq, port); } @@ -332,7 +332,7 @@ static void ulite_console_wait_tx(struct uart_port *port) /* wait up to 10ms for the character(s) to be sent */ for (i = 0; i < 10000; i++) { - if (in_be32((void*)port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) + if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) break; udelay(1); } @@ -341,7 +341,7 @@ static void ulite_console_wait_tx(struct uart_port *port) static void ulite_console_putchar(struct uart_port *port, int ch) { ulite_console_wait_tx(port); - out_be32((void*)port->membase + ULITE_TX, ch); + writeb(ch, port->membase + ULITE_TX); } static void ulite_console_write(struct console *co, const char *s, @@ -358,8 +358,8 @@ static void ulite_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - ier = in_be32((void*)port->membase + ULITE_STATUS) & ULITE_STATUS_IE; - out_be32((void*)port->membase + ULITE_CONTROL, 0); + ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; + writeb(0, port->membase + ULITE_CONTROL); uart_console_write(port, s, count, ulite_console_putchar); @@ -367,7 +367,7 @@ static void ulite_console_write(struct console *co, const char *s, /* restore interrupt state */ if (ier) - out_be32((void*)port->membase + ULITE_CONTROL, ULITE_CONTROL_IE); + writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); if (locked) spin_unlock_irqrestore(&port->lock, flags); @@ -598,7 +598,7 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match) rc = of_address_to_resource(op->node, 0, &res); if (rc) { - dev_err(&op->dev, "invalide address\n"); + dev_err(&op->dev, "invalid address\n"); return rc; } @@ -606,7 +606,7 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match) id = of_get_property(op->node, "port-number", NULL); - return ulite_assign(&op->dev, id ? *id : -1, res.start, irq); + return ulite_assign(&op->dev, id ? *id : -1, res.start+3, irq); } static int __devexit ulite_of_remove(struct of_device *op) From 5ae70296c85f96a9969891d9de3410ebdf210b71 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sat, 15 Sep 2007 12:54:08 -0700 Subject: [PATCH 0418/2804] mmc: Disabler for Ricoh MMC controller Thanks to Matt Domsch and Rezwanul Kabir at Dell, we know how to disable the MMC controller on the multi-function Ricoh R5C832. The MMC controller needs to be disabled or it will steal MMC cards from the SD controller where they would otherwise be supported by the Linux SDHCI driver. Signed-off-by: Philipl Langdale Signed-off-by: Pierre Ossman --- drivers/mmc/host/Kconfig | 17 ++++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/ricoh_mmc.c | 151 +++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 2 + 4 files changed, 171 insertions(+) create mode 100644 drivers/mmc/host/ricoh_mmc.c diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 68fb052afd3e..5fef6783c716 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -35,6 +35,23 @@ config MMC_SDHCI If unsure, say N. +config MMC_RICOH_MMC + tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL && MMC_SDHCI + help + This selects the disabler for the Ricoh MMC Controller. This + proprietary controller is unnecessary because the SDHCI driver + supports MMC cards on the SD controller, but if it is not + disabled, it will steal the MMC cards away - rendering them + useless. It is safe to select this driver even if you don't + have a Ricoh based card reader. + + + To compile this driver as a module, choose M here: + the module will be called ricoh_mmc. + + If unsure, say Y. + config MMC_OMAP tristate "TI OMAP Multimedia Card Interface support" depends on ARCH_OMAP diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 8dc82ce647b7..3877c87e6da2 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o +obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c new file mode 100644 index 000000000000..1e8704533bc5 --- /dev/null +++ b/drivers/mmc/host/ricoh_mmc.c @@ -0,0 +1,151 @@ +/* + * ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller. + * + * Copyright (C) 2007 Philip Langdale, 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 is a conceptually ridiculous driver, but it is required by the way + * the Ricoh multi-function R5C832 works. This chip implements firewire + * and four different memory card controllers. Two of those controllers are + * an SDHCI controller and a proprietary MMC controller. The linux SDHCI + * driver supports MMC cards but the chip detects MMC cards in hardware + * and directs them to the MMC controller - so the SDHCI driver never sees + * them. To get around this, we must disable the useless MMC controller. + * At that point, the SDHCI controller will start seeing them. As a bonus, + * a detection event occurs immediately, even if the MMC card is already + * in the reader. + * + * The relevant registers live on the firewire function, so this is unavoidably + * ugly. Such is life. + */ + +#include + +#define DRIVER_NAME "ricoh-mmc" + +static const struct pci_device_id pci_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_RICOH, + .device = PCI_DEVICE_ID_RICOH_R5C843, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(pci, pci_ids); + +static int __devinit ricoh_mmc_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + u8 rev; + + struct pci_dev *fw_dev = NULL; + + BUG_ON(pdev == NULL); + BUG_ON(ent == NULL); + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev); + + printk(KERN_INFO DRIVER_NAME + ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n", + pci_name(pdev), (int)pdev->vendor, (int)pdev->device, + (int)rev); + + while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) { + if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && + pdev->bus == fw_dev->bus) { + u8 write_enable; + u8 disable; + + pci_read_config_byte(fw_dev, 0xCB, &disable); + if (disable & 0x02) { + printk(KERN_INFO DRIVER_NAME + ": Controller already disabled. Nothing to do.\n"); + return -ENODEV; + } + + pci_read_config_byte(fw_dev, 0xCA, &write_enable); + pci_write_config_byte(fw_dev, 0xCA, 0x57); + pci_write_config_byte(fw_dev, 0xCB, disable | 0x02); + pci_write_config_byte(fw_dev, 0xCA, write_enable); + + pci_set_drvdata(pdev, fw_dev); + + printk(KERN_INFO DRIVER_NAME + ": Controller is now disabled.\n"); + + break; + } + } + + if (pci_get_drvdata(pdev) == NULL) { + printk(KERN_WARNING DRIVER_NAME + ": Main firewire function not found. Cannot disable controller.\n"); + return -ENODEV; + } + + return 0; +} + +static void __devexit ricoh_mmc_remove(struct pci_dev *pdev) +{ + u8 write_enable; + u8 disable; + struct pci_dev *fw_dev = NULL; + + fw_dev = pci_get_drvdata(pdev); + BUG_ON(fw_dev == NULL); + + pci_read_config_byte(fw_dev, 0xCA, &write_enable); + pci_read_config_byte(fw_dev, 0xCB, &disable); + pci_write_config_byte(fw_dev, 0xCA, 0x57); + pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02); + pci_write_config_byte(fw_dev, 0xCA, write_enable); + + printk(KERN_INFO DRIVER_NAME + ": Controller is now re-enabled.\n"); + + pci_set_drvdata(pdev, NULL); +} + +static struct pci_driver ricoh_mmc_driver = { + .name = DRIVER_NAME, + .id_table = pci_ids, + .probe = ricoh_mmc_probe, + .remove = __devexit_p(ricoh_mmc_remove), +}; + +/*****************************************************************************\ + * * + * Driver init/exit * + * * +\*****************************************************************************/ + +static int __init ricoh_mmc_drv_init(void) +{ + printk(KERN_INFO DRIVER_NAME + ": Ricoh MMC Controller disabling driver\n"); + printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n"); + + return pci_register_driver(&ricoh_mmc_driver); +} + +static void __exit ricoh_mmc_drv_exit(void) +{ + pci_unregister_driver(&ricoh_mmc_driver); +} + +module_init(ricoh_mmc_drv_init); +module_exit(ricoh_mmc_drv_exit); + +MODULE_AUTHOR("Philip Langdale "); +MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver"); +MODULE_LICENSE("GPL"); + diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 55f307ffbf96..c8636bb3e3a7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1471,6 +1471,8 @@ #define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 #define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 #define PCI_DEVICE_ID_RICOH_R5C822 0x0822 +#define PCI_DEVICE_ID_RICOH_R5C832 0x0832 +#define PCI_DEVICE_ID_RICOH_R5C843 0x0843 #define PCI_VENDOR_ID_DLINK 0x1186 #define PCI_DEVICE_ID_DLINK_DGE510T 0x4c00 From 2df3b71b2746469b5b344cf7da5facecd4110cc9 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 29 Sep 2007 10:46:20 -0400 Subject: [PATCH 0419/2804] sdhci: fix a typo Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 2 +- drivers/mmc/host/sdhci.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 228ce42371dc..317578d68538 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -132,7 +132,7 @@ static void sdhci_dumpregs(struct sdhci_host *host) readb(host->ioaddr + SDHCI_POWER_CONTROL), readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL)); printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", - readb(host->ioaddr + SDHCI_WALK_UP_CONTROL), + readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL), readw(host->ioaddr + SDHCI_CLOCK_CONTROL)); printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL), diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e28987d6d2eb..05195ea900f4 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -81,7 +81,7 @@ #define SDHCI_BLOCK_GAP_CONTROL 0x2A -#define SDHCI_WALK_UP_CONTROL 0x2B +#define SDHCI_WAKE_UP_CONTROL 0x2B #define SDHCI_CLOCK_CONTROL 0x2C #define SDHCI_DIVIDER_SHIFT 8 From 56e71efe44eb06ae1761f43cca70a5f3cc54c0fb Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Sat, 29 Sep 2007 14:15:05 +0800 Subject: [PATCH 0420/2804] sdhci: remove DMA capability check from controller's PCI Class reg Many host controllers don't fully follow the PCI spec to claim whether they support DMA in PCI class register. Leave the driver to judge it from the Capability register, quirks and module parameter Signed-off-by: Feng Tang Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 317578d68538..866528c4ac10 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1299,13 +1299,18 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) host->flags |= SDHCI_USE_DMA; } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_DMA; - else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) - DBG("Controller doesn't have DMA interface\n"); else if (!(caps & SDHCI_CAN_DO_DMA)) DBG("Controller doesn't have DMA capability\n"); else host->flags |= SDHCI_USE_DMA; + if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && + (host->flags & SDHCI_USE_DMA)) { + printk(KERN_WARNING "%s: Will use DMA " + "mode even though HW doesn't fully " + "claim to support it.\n", host->slot_descr); + } + if (host->flags & SDHCI_USE_DMA) { if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "%s: No suitable DMA available. " From 7c168e3db7d900008ee304574057e0dc1a8505af Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Sun, 30 Sep 2007 12:44:18 +0200 Subject: [PATCH 0421/2804] sdhci: add SDHCI_QUIRK_BROKEN_DMA quirk Some controllers like ENE712 can't work properly with DMA mode, add this quirk to force these kinds of HW work with PIO mode Signed-off-by: Feng Tang Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 866528c4ac10..2b4a86c55a94 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -35,6 +35,7 @@ static unsigned int debug_quirks = 0; #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) +#define SDHCI_QUIRK_BROKEN_DMA (1<<5) static const struct pci_device_id pci_ids[] __devinitdata = { { @@ -68,7 +69,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .device = PCI_DEVICE_ID_ENE_CB712_SD, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, + .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_BROKEN_DMA, }, { @@ -76,7 +78,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .device = PCI_DEVICE_ID_ENE_CB712_SD_2, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, + .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_BROKEN_DMA, }, { @@ -1304,6 +1307,12 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) else host->flags |= SDHCI_USE_DMA; + if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) && + (host->flags & SDHCI_USE_DMA)) { + DBG("Disabling DMA as it is marked broken"); + host->flags &= ~SDHCI_USE_DMA; + } + if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && (host->flags & SDHCI_USE_DMA)) { printk(KERN_WARNING "%s: Will use DMA " From d6f8deecefc133cac044f6029bdb349a1cb8753a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 30 Sep 2007 12:47:05 +0200 Subject: [PATCH 0422/2804] sdhci: remove old dma module params The forcedma and nodma module parameters can be replaced with the quirks parameter, so remove the redundancy. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2b4a86c55a94..b397121b947d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -25,8 +25,6 @@ #define DBG(f, x...) \ pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) -static unsigned int debug_nodma = 0; -static unsigned int debug_forcedma = 0; static unsigned int debug_quirks = 0; #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) @@ -1295,12 +1293,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) caps = readl(host->ioaddr + SDHCI_CAPABILITIES); - if (debug_nodma) - DBG("DMA forced off\n"); - else if (debug_forcedma) { - DBG("DMA forced on\n"); - host->flags |= SDHCI_USE_DMA; - } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) + if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_DMA; else if (!(caps & SDHCI_CAN_DO_DMA)) DBG("Controller doesn't have DMA capability\n"); @@ -1613,14 +1606,10 @@ static void __exit sdhci_drv_exit(void) module_init(sdhci_drv_init); module_exit(sdhci_drv_exit); -module_param(debug_nodma, uint, 0444); -module_param(debug_forcedma, uint, 0444); module_param(debug_quirks, uint, 0444); MODULE_AUTHOR("Pierre Ossman "); MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver"); MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)"); -MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)"); MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); From 26f571d7c968dbd30656fc1421eeb0d9088aaad9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 4 Oct 2007 11:02:09 +1000 Subject: [PATCH 0423/2804] [PPC] Use cpu setup routines from cpu_setup_44x.S for ARCH=ppc Commit 8112753bb2c0045398c89d0647792b39805f6d40 made 44x in ARCH=powerpc builds use cpu setup routines in cpu_setup_44x.S, but didn't make a similar change for ARCH=ppc, and consequently the ARCH=ppc builds fail with undefined symbols (since both use the same cputable.c). This fixes it by including cpu_setup_44x.S in the ARCH=ppc builds, and by taking out the now-redundant FPU initialization in arch/ppc/kernel/head_44x.S. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/ppc/kernel/head_44x.S | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f1dd90439efc..8327d92eeca8 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \ swsusp_$(CONFIG_WORD_SIZE).o obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o obj-$(CONFIG_MODULES) += module_$(CONFIG_WORD_SIZE).o +obj-$(CONFIG_44x) += cpu_setup_44x.o ifeq ($(CONFIG_PPC_MERGE),y) @@ -58,7 +59,6 @@ obj-y += time.o prom.o traps.o setup-common.o \ misc_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o obj-$(CONFIG_PPC64) += dma_64.o iommu.o -obj-$(CONFIG_44x) += cpu_setup_44x.o obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index 7e44de5a26db..75bbc937ed73 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -227,16 +227,6 @@ skpinv: addi r4,r4,1 /* Increment */ lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ mtspr SPRN_IVPR,r4 -#ifdef CONFIG_440EP - /* Clear DAPUIB flag in CCR0 (enable APU between CPU and FPU) */ - mfspr r2,SPRN_CCR0 - lis r3,0xffef - ori r3,r3,0xffff - and r2,r2,r3 - mtspr SPRN_CCR0,r2 - isync -#endif - /* * This is where the main kernel code starts. */ From 6d817aa71fddea859ba02d1a0b326da930ce6b50 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 29 Aug 2007 15:08:40 -0500 Subject: [PATCH 0424/2804] [POWERPC] CPM: Change from fsl,brg-frequency to brg/clock-frequency As suggested by David Gibson, now that we have a separate node for the baud rate generators, it's better to use the standard clock-frequency property than a cpm-node-level fsl,brg-frequency property. This patch updates existing places where fsl,brg-frequency is used. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/boot/cuboot-8xx.c | 8 +++++--- arch/powerpc/boot/cuboot-pq2.c | 8 +++++--- arch/powerpc/sysdev/fsl_soc.c | 24 ++++++++++++++---------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/arch/powerpc/boot/cuboot-8xx.c b/arch/powerpc/boot/cuboot-8xx.c index 88ed84015a8b..0e82015a5f95 100644 --- a/arch/powerpc/boot/cuboot-8xx.c +++ b/arch/powerpc/boot/cuboot-8xx.c @@ -29,10 +29,12 @@ static void platform_fixups(void) dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 16, bd.bi_busfreq); node = finddevice("/soc/cpm"); - if (node) { + if (node) setprop(node, "clock-frequency", &bd.bi_busfreq, 4); - setprop(node, "fsl,brg-frequency", &bd.bi_busfreq, 4); - } + + node = finddevice("/soc/cpm/brg"); + if (node) + setprop(node, "clock-frequency", &bd.bi_busfreq, 4); } void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, diff --git a/arch/powerpc/boot/cuboot-pq2.c b/arch/powerpc/boot/cuboot-pq2.c index 8021fd4a43bc..b150bd4f1b73 100644 --- a/arch/powerpc/boot/cuboot-pq2.c +++ b/arch/powerpc/boot/cuboot-pq2.c @@ -264,10 +264,12 @@ static void pq2_platform_fixups(void) dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); node = finddevice("/soc/cpm"); - if (node) { + if (node) setprop(node, "clock-frequency", &bd.bi_cpmfreq, 4); - setprop(node, "fsl,brg-frequency", &bd.bi_brgfreq, 4); - } + + node = finddevice("/soc/cpm/brg"); + if (node) + setprop(node, "clock-frequency", &bd.bi_brgfreq, 4); update_cs_ranges(); fixup_pci(); diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index d028e8da027b..30523667df4e 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -73,22 +73,26 @@ static u32 brgfreq = -1; u32 get_brgfreq(void) { struct device_node *node; + const unsigned int *prop; + int size; if (brgfreq != -1) return brgfreq; - node = of_find_compatible_node(NULL, NULL, "fsl,cpm1"); - if (!node) - node = of_find_compatible_node(NULL, NULL, "fsl,cpm2"); - if (!node) - node = of_find_node_by_type(NULL, "cpm"); + node = of_find_compatible_node(NULL, NULL, "fsl,cpm-brg"); if (node) { - int size; - const unsigned int *prop; + prop = of_get_property(node, "clock-frequency", &size); + if (prop && size == 4) + brgfreq = *prop; - prop = of_get_property(node, "fsl,brg-frequency", &size); - if (!prop) - prop = of_get_property(node, "brg-frequency", &size); + of_node_put(node); + return brgfreq; + } + + /* Legacy device binding -- will go away when no users are left. */ + node = of_find_node_by_type(NULL, "cpm"); + if (node) { + prop = of_get_property(node, "brg-frequency", &size); if (prop && size == 4) brgfreq = *prop; From e631ae3b164158fbf486fbed5adb597696c4f0e5 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 14 Sep 2007 13:04:54 -0500 Subject: [PATCH 0425/2804] [POWERPC] Introduce new CPM device bindings. This introduces a new device binding for the CPM and other devices on these boards. Some of the changes include: 1. Proper namespace scoping for Freescale compatibles and properties. 2. Use compatible rather than things like device_type and model to determine which particular variant of a device is present. 3. Give the drivers the relevant CPM command word directly, rather than requiring it to have a lookup table based on device-id, SCC v. SMC, and CPM version. 4. Specify the CPCR and the usable DPRAM region in the CPM's reg property. Boards that do not require the legacy bindings should select CONFIG_PPC_CPM_NEW_BINDING to enable the of_platform CPM devices. Once all existing boards are converted and tested, the config option can become default y to prevent new boards from using the old model. Once arch/ppc is gone, the config option can be removed altogether. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Kumar Gala --- Documentation/powerpc/booting-without-of.txt | 171 ++++++++++++++++++- arch/powerpc/platforms/Kconfig | 11 ++ arch/powerpc/sysdev/fsl_soc.c | 2 + 3 files changed, 183 insertions(+), 1 deletion(-) diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 20e0e6cb0347..a599f1a8a145 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1510,7 +1510,10 @@ platforms are moved over to use the flattened-device-tree model. i) Freescale QUICC Engine module (QE) This represents qe module that is installed on PowerQUICC II Pro. - Hopefully it will merge backward compatibility with CPM/CPM2. + + NOTE: This is an interim binding; it should be updated to fit + in with the CPM binding later in this document. + Basically, it is a bus of devices, that could act more or less as a complete entity (UCC, USB etc ). All of them should be siblings on the "root" qe node, using the common properties from there. @@ -1848,6 +1851,172 @@ platforms are moved over to use the flattened-device-tree model. fsl,has-rstcr; }; + l) Freescale Communications Processor Module + + NOTE: This is an interim binding, and will likely change slightly, + as more devices are supported. The QE bindings especially are + incomplete. + + i) Root CPM node + + Properties: + - compatible : "fsl,cpm1", "fsl,cpm2", or "fsl,qe". + - reg : The first resource is a 48-byte region beginning with + CPCR. The second is the available general-purpose + DPRAM. + + Example: + cpm@119c0 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + compatible = "fsl,mpc8272-cpm", "fsl,cpm2"; + reg = <119c0 30 0 2000>; + } + + ii) Properties common to mulitple CPM/QE devices + + - fsl,cpm-command : This value is ORed with the opcode and command flag + to specify the device on which a CPM command operates. + + - fsl,cpm-brg : Indicates which baud rate generator the device + is associated with. If absent, an unused BRG + should be dynamically allocated. If zero, the + device uses an external clock rather than a BRG. + + - reg : Unless otherwise specified, the first resource represents the + scc/fcc/ucc registers, and the second represents the device's + parameter RAM region (if it has one). + + iii) Serial + + Currently defined compatibles: + - fsl,cpm1-smc-uart + - fsl,cpm2-smc-uart + - fsl,cpm1-scc-uart + - fsl,cpm2-scc-uart + - fsl,qe-uart + + Example: + + serial@11a00 { + device_type = "serial"; + compatible = "fsl,mpc8272-scc-uart", + "fsl,cpm2-scc-uart"; + reg = <11a00 20 8000 100>; + interrupts = <28 8>; + interrupt-parent = <&PIC>; + fsl,cpm-brg = <1>; + fsl,cpm-command = <00800000>; + }; + + iii) Network + + Currently defined compatibles: + - fsl,cpm1-scc-enet + - fsl,cpm2-scc-enet + - fsl,cpm1-fec-enet + - fsl,cpm2-fcc-enet (third resource is GFEMR) + - fsl,qe-enet + + Example: + + ethernet@11300 { + device_type = "network"; + compatible = "fsl,mpc8272-fcc-enet", + "fsl,cpm2-fcc-enet"; + reg = <11300 20 8400 100 11390 1>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <20 8>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY0>; + linux,network-index = <0>; + fsl,cpm-command = <12000300>; + }; + + iv) MDIO + + Currently defined compatibles: + fsl,pq1-fec-mdio (reg is same as first resource of FEC device) + fsl,cpm2-mdio-bitbang (reg is port C registers) + + Properties for fsl,cpm2-mdio-bitbang: + fsl,mdio-pin : pin of port C controlling mdio data + fsl,mdc-pin : pin of port C controlling mdio clock + + Example: + + mdio@10d40 { + device_type = "mdio"; + compatible = "fsl,mpc8272ads-mdio-bitbang", + "fsl,mpc8272-mdio-bitbang", + "fsl,cpm2-mdio-bitbang"; + reg = <10d40 14>; + #address-cells = <1>; + #size-cells = <0>; + fsl,mdio-pin = <12>; + fsl,mdc-pin = <13>; + }; + + v) Baud Rate Generators + + Currently defined compatibles: + fsl,cpm-brg + fsl,cpm1-brg + fsl,cpm2-brg + + Properties: + - reg : There may be an arbitrary number of reg resources; BRG + numbers are assigned to these in order. + - clock-frequency : Specifies the base frequency driving + the BRG. + + Example: + + brg@119f0 { + compatible = "fsl,mpc8272-brg", + "fsl,cpm2-brg", + "fsl,cpm-brg"; + reg = <119f0 10 115f0 10>; + clock-frequency = ; + }; + + vi) Interrupt Controllers + + Currently defined compatibles: + - fsl,cpm1-pic + - only one interrupt cell + - fsl,pq1-pic + - fsl,cpm2-pic + - second interrupt cell is level/sense: + - 2 is falling edge + - 8 is active low + + Example: + + interrupt-controller@10c00 { + #interrupt-cells = <2>; + interrupt-controller; + reg = <10c00 80>; + compatible = "mpc8272-pic", "fsl,cpm2-pic"; + }; + + vii) USB (Universal Serial Bus Controller) + + Properties: + - compatible : "fsl,cpm1-usb", "fsl,cpm2-usb", "fsl,qe-usb" + + Example: + usb@11bc0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,cpm2-usb"; + reg = <11b60 18 8b00 100>; + interrupts = ; + interrupt-parent = <&PIC>; + fsl,cpm-command = <2e600000>; + }; + More devices will be defined as this spec matures. VII - Specifying interrupt information for devices diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 92fcd6e35b51..8a62ca533b30 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -279,6 +279,17 @@ config CPM2 you wish to build a kernel for a machine with a CPM2 coprocessor on it (826x, 827x, 8560). +config PPC_CPM_NEW_BINDING + bool + depends on CPM1 || CPM2 + help + Select this if your board has been converted to use the new + device tree bindings for CPM, and no longer needs the + ioport callbacks or the platform device glue code. + + The fs_enet and cpm_uart drivers will be built as + of_platform devices. + config AXON_RAM tristate "Axon DDR2 memory device driver" depends on PPC_IBM_CELL_BLADE diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 30523667df4e..b465b30c9547 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -665,6 +665,7 @@ err: arch_initcall(fsl_usb_of_init); +#ifndef CONFIG_PPC_CPM_NEW_BINDING #ifdef CONFIG_CPM2 extern void init_scc_ioports(struct fs_uart_platform_info*); @@ -1204,6 +1205,7 @@ err: arch_initcall(cpm_smc_uart_of_init); #endif /* CONFIG_8xx */ +#endif /* CONFIG_PPC_CPM_NEW_BINDING */ int __init fsl_spi_init(struct spi_board_info *board_infos, unsigned int num_board_infos, From c374e00e17f1c10768d5af922a1ff33e43df2eb0 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 16 Jul 2007 11:43:43 -0500 Subject: [PATCH 0426/2804] [POWERPC] Add early debug console for CPM serial ports. This code assumes that the ports have been previously set up, with buffers in DPRAM. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Kumar Gala --- arch/powerpc/Kconfig.debug | 21 ++++++++++++++ arch/powerpc/kernel/head_32.S | 16 +++++++++++ arch/powerpc/kernel/udbg.c | 2 ++ arch/powerpc/platforms/8xx/Kconfig | 1 + arch/powerpc/platforms/Kconfig | 4 +++ arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/cpm_common.c | 46 ++++++++++++++++++++++++++++++ include/asm-powerpc/udbg.h | 1 + 8 files changed, 92 insertions(+) create mode 100644 arch/powerpc/sysdev/cpm_common.c diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index c38bc2237057..f4e5d22312a0 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -221,6 +221,15 @@ config PPC_EARLY_DEBUG_44x Select this to enable early debugging for IBM 44x chips via the inbuilt serial port. +config PPC_EARLY_DEBUG_CPM + bool "Early serial debugging for Freescale CPM-based serial ports" + depends on SERIAL_CPM + select PIN_TLB if PPC_8xx + help + Select this to enable early debugging for Freescale chips + using a CPM-based serial port. This assumes that the bootwrapper + has run, and set up the CPM in a particular way. + endchoice config PPC_EARLY_DEBUG_44x_PHYSLOW @@ -233,4 +242,16 @@ config PPC_EARLY_DEBUG_44x_PHYSHIGH depends PPC_EARLY_DEBUG_44x default "0x1" +config PPC_EARLY_DEBUG_CPM_ADDR + hex "CPM UART early debug transmit descriptor address" + depends on PPC_EARLY_DEBUG_CPM + default "0xfa202808" if PPC_EP88XC + default "0xf0000808" if CPM2 + default "0xff002808" if CPM1 + help + This specifies the address of the transmit descriptor + used for early debug output. Because it is needed before + platform probing is done, all platforms selected must + share the same address. + endmenu diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index c86c626cf156..d83f04e5a599 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -149,6 +149,9 @@ __after_mmu_off: #if defined(CONFIG_BOOTX_TEXT) bl setup_disp_bat #endif +#ifdef CONFIG_PPC_EARLY_DEBUG_CPM + bl setup_cpm_bat +#endif /* * Call setup_cpu for CPU 0 and initialize 6xx Idle @@ -1245,6 +1248,19 @@ setup_disp_bat: blr #endif /* CONFIG_BOOTX_TEXT */ +#ifdef CONFIG_PPC_EARLY_DEBUG_CPM +setup_cpm_bat: + lis r8, 0xf000 + ori r8, r8, 0x002a + mtspr SPRN_DBAT1L, r8 + + lis r11, 0xf000 + ori r11, r11, (BL_1M << 2) | 2 + mtspr SPRN_DBAT1U, r11 + + blr +#endif + #ifdef CONFIG_8260 /* Jump into the system reset for the rom. * We first disable the MMU, and then jump to the ROM reset address. diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 0f9b4eadfbcb..d723070c9a33 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -54,6 +54,8 @@ void __init udbg_early_init(void) #elif defined(CONFIG_PPC_EARLY_DEBUG_44x) /* PPC44x debug */ udbg_init_44x_as1(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_CPM) + udbg_init_cpm(); #endif } diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 39bb8c5ebe70..8ecd01ad0de8 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -3,6 +3,7 @@ config FADS config CPM1 bool + select CPM choice prompt "8xx Machine Type" diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 8a62ca533b30..cc6013ffc29a 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -273,6 +273,7 @@ config QUICC_ENGINE config CPM2 bool default n + select CPM help The CPM2 (Communications Processor Module) is a coprocessor on embedded CPUs made by Freescale. Selecting this option means that @@ -309,4 +310,7 @@ config FSL_ULI1575 Freescale reference boards. The boards all use the ULI in pretty much the same way. +config CPM + bool + endmenu diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 592c17ea713d..52e93bca10ca 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -31,6 +31,7 @@ endif # Temporary hack until we have migrated to asm-powerpc ifeq ($(ARCH),powerpc) +obj-$(CONFIG_CPM) += cpm_common.o obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o obj-$(CONFIG_8xx) += mpc8xx_pic.o commproc.o obj-$(CONFIG_UCODE_PATCH) += micropatch.o diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c new file mode 100644 index 000000000000..9daa6ac67676 --- /dev/null +++ b/arch/powerpc/sysdev/cpm_common.c @@ -0,0 +1,46 @@ +/* + * Common CPM code + * + * Author: Scott Wood + * + * Copyright 2007 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PPC_EARLY_DEBUG_CPM +static u32 __iomem *cpm_udbg_txdesc = + (u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR; + +static void udbg_putc_cpm(char c) +{ + u8 __iomem *txbuf = (u8 __iomem __force *)in_be32(&cpm_udbg_txdesc[1]); + + if (c == '\n') + udbg_putc('\r'); + + while (in_be32(&cpm_udbg_txdesc[0]) & 0x80000000) + ; + + out_8(txbuf, c); + out_be32(&cpm_udbg_txdesc[0], 0xa0000001); +} + +void __init udbg_init_cpm(void) +{ + if (cpm_udbg_txdesc) { +#ifdef CONFIG_CPM2 + setbat(1, 0xf0000000, 0xf0000000, 1024*1024, _PAGE_IO); +#endif + udbg_putc = udbg_putc_cpm; + } +} +#endif diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h index ce9d82fb7b68..a9e0b0ebcb0f 100644 --- a/include/asm-powerpc/udbg.h +++ b/include/asm-powerpc/udbg.h @@ -48,6 +48,7 @@ extern void __init udbg_init_rtas_console(void); extern void __init udbg_init_debug_beat(void); extern void __init udbg_init_btext(void); extern void __init udbg_init_44x_as1(void); +extern void __init udbg_init_cpm(void); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_UDBG_H */ From 568091512d464b06f17b88bfd2bdc1ec98a697bd Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 30 Aug 2007 12:06:21 -0500 Subject: [PATCH 0427/2804] [POWERPC] bootwrapper: Support all-in-one PCI nodes in cuboot-pq2. Consensus was reached to put PCI nodes at the root of the tree (and not under /soc), but the phandle to a control node was rejected in favor of simply not worrying about /pci/reg overlapping /soc/ranges. This updates cuboot-82xx to not look for the phandle. Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Kumar Gala --- arch/powerpc/boot/cuboot-pq2.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/boot/cuboot-pq2.c b/arch/powerpc/boot/cuboot-pq2.c index b150bd4f1b73..d3d3388d552f 100644 --- a/arch/powerpc/boot/cuboot-pq2.c +++ b/arch/powerpc/boot/cuboot-pq2.c @@ -139,11 +139,11 @@ static void fixup_pci(void) u32 *pci_regs[3]; u8 *soc_regs; int i, len; - void *ctrl_node, *bus_node, *parent_node, *soc_node; - u32 naddr, nsize, bus_ph, mem_log2; + void *node, *parent_node, *soc_node; + u32 naddr, nsize, mem_log2; - ctrl_node = finddevice("/soc/pci"); - if (!ctrl_node || !dt_is_compatible(ctrl_node, "fsl,pq2-pci")) + node = finddevice("/pci"); + if (!node || !dt_is_compatible(node, "fsl,pq2-pci")) return; soc_node = finddevice("/soc"); @@ -151,27 +151,18 @@ static void fixup_pci(void) goto err; for (i = 0; i < 3; i++) - if (!dt_xlate_reg(ctrl_node, i, + if (!dt_xlate_reg(node, i, (unsigned long *)&pci_regs[i], NULL)) goto err; if (!dt_xlate_reg(soc_node, 0, (unsigned long *)&soc_regs, NULL)) goto err; - len = getprop(ctrl_node, "fsl,bus", &bus_ph, 4); - if (len != 4) - goto err; - - bus_node = find_node_by_prop_value(NULL, "linux,phandle", - (char *)&bus_ph, 4); - if (!bus_node) - goto err; - - dt_get_reg_format(bus_node, &naddr, &nsize); + dt_get_reg_format(node, &naddr, &nsize); if (naddr != 3 || nsize != 2) goto err; - parent_node = get_parent(bus_node); + parent_node = get_parent(node); if (!parent_node) goto err; @@ -179,7 +170,7 @@ static void fixup_pci(void) if (naddr != 1 || nsize != 1) goto err; - len = getprop(bus_node, "ranges", pci_ranges_buf, + len = getprop(node, "ranges", pci_ranges_buf, sizeof(pci_ranges_buf)); for (i = 0; i < len / sizeof(struct pci_range); i++) { From bbc6fac387f09e46a372e4aadbc935cba5a6b463 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 27 Aug 2007 13:46:38 -0500 Subject: [PATCH 0428/2804] [POWERPC] bootwrapper: Add fsl_get_immr() and 8xx/pq2 clock functions. fsl_get_immr() uses /soc/ranges to determine the immr. mpc885_get_clock() transforms a crystal frequency into a system frequency according to the PLL register settings. pq2_get_clocks() does the same as the above for the PowerQUICC II, except that it produces several different clocks. The mpc8xx/pq2 set_clocks() functions modify common properties in the device tree based on the given clock data. The mpc885/pq2 fixup_clocks() functions call get_clocks(), and pass the results to set_clocks(). Signed-off-by: Scott Wood Acked-by: David Gibson Signed-off-by: Kumar Gala --- arch/powerpc/boot/Makefile | 3 +- arch/powerpc/boot/fsl-soc.c | 57 ++++++++++++++++++++ arch/powerpc/boot/fsl-soc.h | 8 +++ arch/powerpc/boot/mpc8xx.c | 82 +++++++++++++++++++++++++++++ arch/powerpc/boot/mpc8xx.h | 11 ++++ arch/powerpc/boot/pq2.c | 102 ++++++++++++++++++++++++++++++++++++ arch/powerpc/boot/pq2.h | 11 ++++ 7 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/fsl-soc.c create mode 100644 arch/powerpc/boot/fsl-soc.h create mode 100644 arch/powerpc/boot/mpc8xx.c create mode 100644 arch/powerpc/boot/mpc8xx.h create mode 100644 arch/powerpc/boot/pq2.c create mode 100644 arch/powerpc/boot/pq2.h diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index cf80db3ef78c..6d1935a06ee1 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -46,7 +46,8 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \ - cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c + cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c \ + fsl-soc.c mpc8xx.c pq2.c src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ diff --git a/arch/powerpc/boot/fsl-soc.c b/arch/powerpc/boot/fsl-soc.c new file mode 100644 index 000000000000..b835ed69e1a1 --- /dev/null +++ b/arch/powerpc/boot/fsl-soc.c @@ -0,0 +1,57 @@ +/* + * Freescale SOC support functions + * + * Author: Scott Wood + * + * Copyright (c) 2007 Freescale Semiconductor, 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 "ops.h" +#include "types.h" +#include "fsl-soc.h" +#include "stdio.h" + +static u32 prop_buf[MAX_PROP_LEN / 4]; + +u32 *fsl_get_immr(void) +{ + void *soc; + unsigned long ret = 0; + + soc = find_node_by_devtype(NULL, "soc"); + if (soc) { + int size; + u32 naddr; + + size = getprop(soc, "#address-cells", prop_buf, MAX_PROP_LEN); + if (size == 4) + naddr = prop_buf[0]; + else + naddr = 2; + + if (naddr != 1 && naddr != 2) + goto err; + + size = getprop(soc, "ranges", prop_buf, MAX_PROP_LEN); + + if (size < 12) + goto err; + if (prop_buf[0] != 0) + goto err; + if (naddr == 2 && prop_buf[1] != 0) + goto err; + + if (!dt_xlate_addr(soc, prop_buf + naddr, 8, &ret)) + ret = 0; + } + +err: + if (!ret) + printf("fsl_get_immr: Failed to find immr base\r\n"); + + return (u32 *)ret; +} diff --git a/arch/powerpc/boot/fsl-soc.h b/arch/powerpc/boot/fsl-soc.h new file mode 100644 index 000000000000..5da26fc6e3cf --- /dev/null +++ b/arch/powerpc/boot/fsl-soc.h @@ -0,0 +1,8 @@ +#ifndef _PPC_BOOT_FSL_SOC_H_ +#define _PPC_BOOT_FSL_SOC_H_ + +#include "types.h" + +u32 *fsl_get_immr(void); + +#endif diff --git a/arch/powerpc/boot/mpc8xx.c b/arch/powerpc/boot/mpc8xx.c new file mode 100644 index 000000000000..add55a7f184f --- /dev/null +++ b/arch/powerpc/boot/mpc8xx.c @@ -0,0 +1,82 @@ +/* + * MPC8xx support functions + * + * Author: Scott Wood + * + * Copyright (c) 2007 Freescale Semiconductor, 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 "ops.h" +#include "types.h" +#include "fsl-soc.h" +#include "mpc8xx.h" +#include "stdio.h" +#include "io.h" + +#define MPC8XX_PLPRCR (0x284/4) /* PLL and Reset Control Register */ + +/* Return system clock from crystal frequency */ +u32 mpc885_get_clock(u32 crystal) +{ + u32 *immr; + u32 plprcr; + int mfi, mfn, mfd, pdf, div; + u32 ret; + + immr = fsl_get_immr(); + if (!immr) { + printf("mpc885_get_clock: Couldn't get IMMR base.\r\n"); + return 0; + } + + plprcr = in_be32(&immr[MPC8XX_PLPRCR]); + + mfi = (plprcr >> 16) & 15; + if (mfi < 5) { + printf("Warning: PLPRCR[MFI] value of %d out-of-bounds\r\n", + mfi); + mfi = 5; + } + + pdf = (plprcr >> 1) & 0xf; + div = (plprcr >> 20) & 3; + mfd = (plprcr >> 22) & 0x1f; + mfn = (plprcr >> 27) & 0x1f; + + ret = crystal * mfi; + + if (mfn != 0) + ret += crystal * mfn / (mfd + 1); + + return ret / (pdf + 1); +} + +/* Set common device tree fields based on the given clock frequencies. */ +void mpc8xx_set_clocks(u32 sysclk) +{ + void *node; + + dt_fixup_cpu_clocks(sysclk, sysclk / 16, sysclk); + + node = finddevice("/soc/cpm"); + if (node) + setprop(node, "clock-frequency", &sysclk, 4); + + node = finddevice("/soc/cpm/brg"); + if (node) + setprop(node, "clock-frequency", &sysclk, 4); +} + +int mpc885_fixup_clocks(u32 crystal) +{ + u32 sysclk = mpc885_get_clock(crystal); + if (!sysclk) + return 0; + + mpc8xx_set_clocks(sysclk); + return 1; +} diff --git a/arch/powerpc/boot/mpc8xx.h b/arch/powerpc/boot/mpc8xx.h new file mode 100644 index 000000000000..3f59901ab1c0 --- /dev/null +++ b/arch/powerpc/boot/mpc8xx.h @@ -0,0 +1,11 @@ +#ifndef _PPC_BOOT_MPC8xx_H_ +#define _PPC_BOOT_MPC8xx_H_ + +#include "types.h" + +void mpc8xx_set_clocks(u32 sysclk); + +u32 mpc885_get_clock(u32 crystal); +int mpc885_fixup_clocks(u32 crystal); + +#endif diff --git a/arch/powerpc/boot/pq2.c b/arch/powerpc/boot/pq2.c new file mode 100644 index 000000000000..f6d118558f1d --- /dev/null +++ b/arch/powerpc/boot/pq2.c @@ -0,0 +1,102 @@ +/* + * PowerQUICC II support functions + * + * Author: Scott Wood + * + * Copyright (c) 2007 Freescale Semiconductor, 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 "ops.h" +#include "types.h" +#include "fsl-soc.h" +#include "pq2.h" +#include "stdio.h" +#include "io.h" + +#define PQ2_SCCR (0x10c80/4) /* System Clock Configuration Register */ +#define PQ2_SCMR (0x10c88/4) /* System Clock Mode Register */ + +static int pq2_corecnf_map[] = { + 3, 2, 2, 2, 4, 4, 5, 9, 6, 11, 8, 10, 3, 12, 7, -1, + 6, 5, 13, 2, 14, 4, 15, 9, 0, 11, 8, 10, 16, 12, 7, -1 +}; + +/* Get various clocks from crystal frequency. + * Returns zero on failure and non-zero on success. + */ +int pq2_get_clocks(u32 crystal, u32 *sysfreq, u32 *corefreq, + u32 *timebase, u32 *brgfreq) +{ + u32 *immr; + u32 sccr, scmr, mainclk, busclk; + int corecnf, busdf, plldf, pllmf, dfbrg; + + immr = fsl_get_immr(); + if (!immr) { + printf("pq2_get_clocks: Couldn't get IMMR base.\r\n"); + return 0; + } + + sccr = in_be32(&immr[PQ2_SCCR]); + scmr = in_be32(&immr[PQ2_SCMR]); + + dfbrg = sccr & 3; + corecnf = (scmr >> 24) & 0x1f; + busdf = (scmr >> 20) & 0xf; + plldf = (scmr >> 12) & 1; + pllmf = scmr & 0xfff; + + mainclk = crystal * (pllmf + 1) / (plldf + 1); + busclk = mainclk / (busdf + 1); + + if (sysfreq) + *sysfreq = mainclk / 2; + if (timebase) + *timebase = busclk / 4; + if (brgfreq) + *brgfreq = mainclk / (1 << ((dfbrg + 1) * 2)); + + if (corefreq) { + int coremult = pq2_corecnf_map[corecnf]; + + if (coremult < 0) + *corefreq = mainclk / 2; + else if (coremult == 0) + return 0; + else + *corefreq = busclk * coremult / 2; + } + + return 1; +} + +/* Set common device tree fields based on the given clock frequencies. */ +void pq2_set_clocks(u32 sysfreq, u32 corefreq, u32 timebase, u32 brgfreq) +{ + void *node; + + dt_fixup_cpu_clocks(corefreq, timebase, sysfreq); + + node = finddevice("/soc/cpm"); + if (node) + setprop(node, "clock-frequency", &sysfreq, 4); + + node = finddevice("/soc/cpm/brg"); + if (node) + setprop(node, "clock-frequency", &brgfreq, 4); +} + +int pq2_fixup_clocks(u32 crystal) +{ + u32 sysfreq, corefreq, timebase, brgfreq; + + if (!pq2_get_clocks(crystal, &sysfreq, &corefreq, &timebase, &brgfreq)) + return 0; + + pq2_set_clocks(sysfreq, corefreq, timebase, brgfreq); + return 1; +} diff --git a/arch/powerpc/boot/pq2.h b/arch/powerpc/boot/pq2.h new file mode 100644 index 000000000000..481698c7a51a --- /dev/null +++ b/arch/powerpc/boot/pq2.h @@ -0,0 +1,11 @@ +#ifndef _PPC_BOOT_PQ2_H_ +#define _PPC_BOOT_PQ2_H_ + +#include "types.h" + +int pq2_get_clocks(u32 crystal, u32 *sysfreq, u32 *corefreq, + u32 *timebase, u32 *brgfreq); +void pq2_set_clocks(u32 sysfreq, u32 corefreq, u32 timebase, u32 brgfreq); +int pq2_fixup_clocks(u32 crystal); + +#endif From a94b89a4813bddf85c052f8d04021688c5dfe0d7 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 31 Aug 2007 17:18:28 -0500 Subject: [PATCH 0429/2804] [POWERPC] bootwrapper: Use fsl_get_immr() in cuboot-pq2.c. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/boot/cuboot-pq2.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/boot/cuboot-pq2.c b/arch/powerpc/boot/cuboot-pq2.c index d3d3388d552f..470ffacb8373 100644 --- a/arch/powerpc/boot/cuboot-pq2.c +++ b/arch/powerpc/boot/cuboot-pq2.c @@ -15,6 +15,7 @@ #include "stdio.h" #include "cuboot.h" #include "io.h" +#include "fsl-soc.h" #define TARGET_CPM2 #define TARGET_HAS_ETH1 @@ -139,23 +140,20 @@ static void fixup_pci(void) u32 *pci_regs[3]; u8 *soc_regs; int i, len; - void *node, *parent_node, *soc_node; + void *node, *parent_node; u32 naddr, nsize, mem_log2; node = finddevice("/pci"); if (!node || !dt_is_compatible(node, "fsl,pq2-pci")) return; - soc_node = finddevice("/soc"); - if (!soc_node || !dt_is_compatible(soc_node, "fsl,pq2-soc")) - goto err; - for (i = 0; i < 3; i++) if (!dt_xlate_reg(node, i, (unsigned long *)&pci_regs[i], NULL)) goto err; - if (!dt_xlate_reg(soc_node, 0, (unsigned long *)&soc_regs, NULL)) + soc_regs = (u8 *)fsl_get_immr(); + if (!soc_regs) goto err; dt_get_reg_format(node, &naddr, &nsize); From 7ae870368d198affa249ed3382a8a288167ce885 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 17 Jul 2007 17:59:06 -0500 Subject: [PATCH 0430/2804] [POWERPC] cpm_uart: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set. The existing OF glue code was crufty and broken. Rather than fix it, it has been removed, and the serial driver now talks to the device tree directly. The non-CONFIG_PPC_CPM_NEW_BINDING code can go away once CPM platforms are dropped from arch/ppc (which will hopefully be soon), and existing arch/powerpc boards that I wasn't able to test on for this patchset get converted (which should be even sooner). Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart.h | 6 +- drivers/serial/cpm_uart/cpm_uart_core.c | 241 +++++++++++++++++++++--- drivers/serial/cpm_uart/cpm_uart_cpm1.c | 16 +- drivers/serial/cpm_uart/cpm_uart_cpm1.h | 2 + drivers/serial/cpm_uart/cpm_uart_cpm2.c | 18 +- drivers/serial/cpm_uart/cpm_uart_cpm2.h | 2 + 6 files changed, 260 insertions(+), 25 deletions(-) diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index a8f894c78194..4e1987adc23b 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -80,14 +80,18 @@ struct uart_cpm_port { int is_portb; /* wait on close if needed */ int wait_closing; + /* value to combine with opcode to form cpm command */ + u32 command; }; +#ifndef CONFIG_PPC_CPM_NEW_BINDING extern int cpm_uart_port_map[UART_NR]; +#endif extern int cpm_uart_nr; extern struct uart_cpm_port cpm_uart_ports[UART_NR]; /* these are located in their respective files */ -void cpm_line_cr_cmd(int line, int cmd); +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd); int cpm_uart_init_portdesc(void); int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con); void cpm_uart_freebuf(struct uart_cpm_port *pinfo); diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index cefde58dbad2..8564ba2f3ec2 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -10,7 +10,7 @@ * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) * Pantelis Antoniou (panto@intracom.gr) (CPM1) * - * Copyright (C) 2004 Freescale Semiconductor, Inc. + * Copyright (C) 2004, 2007 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. * (C) 2005-2006 MontaVista Software, Inc. * Vitaly Bordug @@ -47,6 +47,11 @@ #include #include #include +#include + +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif #if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -57,12 +62,6 @@ #include "cpm_uart.h" -/***********************************************************************/ - -/* Track which ports are configured as uarts */ -int cpm_uart_port_map[UART_NR]; -/* How many ports did we config as uarts */ -int cpm_uart_nr = 0; /**************************************************************/ @@ -73,6 +72,11 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo); /**************************************************************/ +#ifndef CONFIG_PPC_CPM_NEW_BINDING +/* Track which ports are configured as uarts */ +int cpm_uart_port_map[UART_NR]; +/* How many ports did we config as uarts */ +int cpm_uart_nr; /* Place-holder for board-specific stuff */ struct platform_device* __attribute__ ((weak)) __init @@ -119,6 +123,7 @@ static int cpm_uart_id2nr(int id) /* not found or invalid argument */ return -1; } +#endif /* * Check, if transmit buffers are processed @@ -232,15 +237,14 @@ static void cpm_uart_enable_ms(struct uart_port *port) static void cpm_uart_break_ctl(struct uart_port *port, int break_state) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - int line = pinfo - cpm_uart_ports; pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line, break_state); if (break_state) - cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); else - cpm_line_cr_cmd(line, CPM_CR_RESTART_TX); + cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); } /* @@ -407,7 +411,6 @@ static int cpm_uart_startup(struct uart_port *port) { int retval; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - int line = pinfo - cpm_uart_ports; pr_debug("CPM uart[%d]:startup\n", port->line); @@ -426,7 +429,7 @@ static int cpm_uart_startup(struct uart_port *port) } if (!(pinfo->flags & FLAG_CONSOLE)) - cpm_line_cr_cmd(line,CPM_CR_INIT_TRX); + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); return 0; } @@ -442,7 +445,6 @@ inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo) static void cpm_uart_shutdown(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - int line = pinfo - cpm_uart_ports; pr_debug("CPM uart[%d]:shutdown\n", port->line); @@ -473,9 +475,9 @@ static void cpm_uart_shutdown(struct uart_port *port) /* Shut them really down and reinit buffer descriptors */ if (IS_SMC(pinfo)) - cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); else - cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX); + cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX); cpm_uart_initbd(pinfo); } @@ -595,7 +597,6 @@ static void cpm_uart_set_termios(struct uart_port *port, cpm_set_brg(pinfo->brg - 1, baud); spin_unlock_irqrestore(&port->lock, flags); - } static const char *cpm_uart_type(struct uart_port *port) @@ -742,7 +743,6 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) { - int line = pinfo - cpm_uart_ports; volatile scc_t *scp; volatile scc_uart_t *sup; @@ -783,7 +783,7 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) /* Send the CPM an initialize command. */ - cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. @@ -803,7 +803,6 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) { - int line = pinfo - cpm_uart_ports; volatile smc_t *sp; volatile smc_uart_t *up; @@ -840,7 +839,7 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) up->smc_brkec = 0; up->smc_brkcr = 1; - cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. @@ -929,6 +928,85 @@ static struct uart_ops cpm_uart_pops = { .verify_port = cpm_uart_verify_port, }; +#ifdef CONFIG_PPC_CPM_NEW_BINDING +struct uart_cpm_port cpm_uart_ports[UART_NR]; + +int cpm_uart_init_port(struct device_node *np, struct uart_cpm_port *pinfo) +{ + const u32 *data; + void __iomem *mem, __iomem *pram; + int len; + int ret; + + data = of_get_property(np, "fsl,cpm-brg", &len); + if (!data || len != 4) { + printk(KERN_ERR "CPM UART %s has no/invalid " + "fsl,cpm-brg property.\n", np->name); + return -EINVAL; + } + pinfo->brg = *data; + + data = of_get_property(np, "fsl,cpm-command", &len); + if (!data || len != 4) { + printk(KERN_ERR "CPM UART %s has no/invalid " + "fsl,cpm-command property.\n", np->name); + return -EINVAL; + } + pinfo->command = *data; + + mem = of_iomap(np, 0); + if (!mem) + return -ENOMEM; + + pram = of_iomap(np, 1); + if (!pram) { + ret = -ENOMEM; + goto out_mem; + } + + if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") || + of_device_is_compatible(np, "fsl,cpm2-scc-uart")) { + pinfo->sccp = mem; + pinfo->sccup = pram; + } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") || + of_device_is_compatible(np, "fsl,cpm2-smc-uart")) { + pinfo->flags |= FLAG_SMC; + pinfo->smcp = mem; + pinfo->smcup = pram; + } else { + ret = -ENODEV; + goto out_pram; + } + + pinfo->tx_nrfifos = TX_NUM_FIFO; + pinfo->tx_fifosize = TX_BUF_SIZE; + pinfo->rx_nrfifos = RX_NUM_FIFO; + pinfo->rx_fifosize = RX_BUF_SIZE; + + pinfo->port.uartclk = ppc_proc_freq; + pinfo->port.mapbase = (unsigned long)mem; + pinfo->port.type = PORT_CPM; + pinfo->port.ops = &cpm_uart_pops, + pinfo->port.iotype = UPIO_MEM; + spin_lock_init(&pinfo->port.lock); + + pinfo->port.irq = of_irq_to_resource(np, 0, NULL); + if (pinfo->port.irq == NO_IRQ) { + ret = -EINVAL; + goto out_pram; + } + + return cpm_uart_request_port(&pinfo->port); + +out_pram: + iounmap(pram); +out_mem: + iounmap(mem); + return ret; +} + +#else + struct uart_cpm_port cpm_uart_ports[UART_NR] = { [UART_SMC1] = { .port = { @@ -1072,6 +1150,7 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) return 0; } +#endif #ifdef CONFIG_SERIAL_CPM_CONSOLE /* @@ -1083,8 +1162,12 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) static void cpm_uart_console_write(struct console *co, const char *s, u_int count) { +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index]; +#else struct uart_cpm_port *pinfo = &cpm_uart_ports[cpm_uart_port_map[co->index]]; +#endif unsigned int i; volatile cbd_t *bdp, *bdbase; volatile unsigned char *cp; @@ -1155,13 +1238,47 @@ static void cpm_uart_console_write(struct console *co, const char *s, static int __init cpm_uart_console_setup(struct console *co, char *options) { - struct uart_port *port; - struct uart_cpm_port *pinfo; int baud = 38400; int bits = 8; int parity = 'n'; int flow = 'n'; int ret; + struct uart_cpm_port *pinfo; + struct uart_port *port; + +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct device_node *np = NULL; + int i = 0; + + if (co->index >= UART_NR) { + printk(KERN_ERR "cpm_uart: console index %d too high\n", + co->index); + return -ENODEV; + } + + do { + np = of_find_node_by_type(np, "serial"); + if (!np) + return -ENODEV; + + if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") && + !of_device_is_compatible(np, "fsl,cpm1-scc-uart") && + !of_device_is_compatible(np, "fsl,cpm2-smc-uart") && + !of_device_is_compatible(np, "fsl,cpm2-scc-uart")) + i--; + } while (i++ != co->index); + + pinfo = &cpm_uart_ports[co->index]; + + pinfo->flags |= FLAG_CONSOLE; + port = &pinfo->port; + + ret = cpm_uart_init_port(np, pinfo); + of_node_put(np); + if (ret) + return ret; + +#else struct fs_uart_platform_info *pdata; struct platform_device* pdev = early_uart_get_pdev(co->index); @@ -1188,6 +1305,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) } pinfo->flags |= FLAG_CONSOLE; +#endif if (options) { uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1196,6 +1314,10 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) baud = 9600; } +#ifdef CONFIG_PPC_EARLY_DEBUG_CPM + udbg_putc = NULL; +#endif + if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); @@ -1252,7 +1374,81 @@ static struct uart_driver cpm_reg = { .major = SERIAL_CPM_MAJOR, .minor = SERIAL_CPM_MINOR, .cons = CPM_UART_CONSOLE, + .nr = UART_NR, }; + +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static int probe_index; + +static int __devinit cpm_uart_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + int index = probe_index++; + struct uart_cpm_port *pinfo = &cpm_uart_ports[index]; + int ret; + + pinfo->port.line = index; + + if (index >= UART_NR) + return -ENODEV; + + dev_set_drvdata(&ofdev->dev, pinfo); + + ret = cpm_uart_init_port(ofdev->node, pinfo); + if (ret) + return ret; + + return uart_add_one_port(&cpm_reg, &pinfo->port); +} + +static int __devexit cpm_uart_remove(struct of_device *ofdev) +{ + struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev); + return uart_remove_one_port(&cpm_reg, &pinfo->port); +} + +static struct of_device_id cpm_uart_match[] = { + { + .compatible = "fsl,cpm1-smc-uart", + }, + { + .compatible = "fsl,cpm1-scc-uart", + }, + { + .compatible = "fsl,cpm2-smc-uart", + }, + { + .compatible = "fsl,cpm2-scc-uart", + }, + {} +}; + +static struct of_platform_driver cpm_uart_driver = { + .name = "cpm_uart", + .match_table = cpm_uart_match, + .probe = cpm_uart_probe, + .remove = cpm_uart_remove, + }; + +static int __init cpm_uart_init(void) +{ + int ret = uart_register_driver(&cpm_reg); + if (ret) + return ret; + + ret = of_register_platform_driver(&cpm_uart_driver); + if (ret) + uart_unregister_driver(&cpm_reg); + + return ret; +} + +static void __exit cpm_uart_exit(void) +{ + of_unregister_platform_driver(&cpm_uart_driver); + uart_unregister_driver(&cpm_reg); +} +#else static int cpm_uart_drv_probe(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1380,6 +1576,7 @@ static void __exit cpm_uart_exit(void) driver_unregister(&cpm_smc_uart_driver); uart_unregister_driver(&cpm_reg); } +#endif module_init(cpm_uart_init); module_exit(cpm_uart_exit); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 8c6324ed0202..4647f55e19f1 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -49,9 +49,20 @@ /**************************************************************/ -void cpm_line_cr_cmd(int line, int cmd) +#ifdef CONFIG_PPC_CPM_NEW_BINDING +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) +{ + u16 __iomem *cpcr = &cpmp->cp_cpcr; + + out_be16(cpcr, port->command | (cmd << 8) | CPM_CR_FLG); + while (in_be16(cpcr) & CPM_CR_FLG) + ; +} +#else +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { ushort val; + int line = port - cpm_uart_ports; volatile cpm8xx_t *cp = cpmp; switch (line) { @@ -114,6 +125,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo) /* XXX SCC4: insert port configuration here */ pinfo->brg = 4; } +#endif /* * Allocate DP-Ram and memory buffers. We need to allocate a transmit and @@ -184,6 +196,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) cpm_dpfree(pinfo->dp_addr); } +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* Setup any dynamic params in the uart desc */ int cpm_uart_init_portdesc(void) { @@ -279,3 +292,4 @@ int cpm_uart_init_portdesc(void) #endif return 0; } +#endif diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index 2a6477834c3e..69f523a442e0 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -13,12 +13,14 @@ #include /* defines for IRQs */ +#ifndef CONFIG_PPC_CPM_NEW_BINDING #define SMC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC1) #define SMC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC2) #define SCC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC1) #define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC2) #define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3) #define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4) +#endif static inline void cpm_set_brg(int brg, int baud) { diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 7b61d805ebe9..7ebce263ad40 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -49,9 +49,22 @@ /**************************************************************/ -void cpm_line_cr_cmd(int line, int cmd) +#ifdef CONFIG_PPC_CPM_NEW_BINDING +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) +{ + cpm_cpm2_t __iomem *cp = cpm2_map(im_cpm); + + out_be32(&cp->cp_cpcr, port->command | cmd | CPM_CR_FLG); + while (in_be32(&cp->cp_cpcr) & CPM_CR_FLG) + ; + + cpm2_unmap(cp); +} +#else +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { ulong val; + int line = port - cpm_uart_ports; volatile cpm_cpm2_t *cp = cpm2_map(im_cpm); @@ -211,6 +224,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo) cpm2_unmap(cpmux); cpm2_unmap(io); } +#endif /* * Allocate DP-Ram and memory buffers. We need to allocate a transmit and @@ -281,6 +295,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) cpm_dpfree(pinfo->dp_addr); } +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* Setup any dynamic params in the uart desc */ int cpm_uart_init_portdesc(void) { @@ -386,3 +401,4 @@ int cpm_uart_init_portdesc(void) return 0; } +#endif diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h index 1b3219f56c81..e7717ece0831 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h @@ -13,12 +13,14 @@ #include /* defines for IRQs */ +#ifndef CONFIG_PPC_CPM_NEW_BINDING #define SMC1_IRQ SIU_INT_SMC1 #define SMC2_IRQ SIU_INT_SMC2 #define SCC1_IRQ SIU_INT_SCC1 #define SCC2_IRQ SIU_INT_SCC2 #define SCC3_IRQ SIU_INT_SCC3 #define SCC4_IRQ SIU_INT_SCC4 +#endif static inline void cpm_set_brg(int brg, int baud) { From c1dcfd9d199043ff0e8805484a736ad36d9dd04a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 24 Jul 2007 15:53:07 -0500 Subject: [PATCH 0431/2804] [POWERPC] cpm_uart: sparse fixes Mostly a bunch of direct access to in/out conversions, plus a few cast removals, __iomem annotations, and miscellaneous cleanup. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart.h | 42 ++-- drivers/serial/cpm_uart/cpm_uart_core.c | 299 ++++++++++++------------ drivers/serial/cpm_uart/cpm_uart_cpm1.c | 2 +- drivers/serial/cpm_uart/cpm_uart_cpm1.h | 14 +- drivers/serial/cpm_uart/cpm_uart_cpm2.c | 4 +- drivers/serial/cpm_uart/cpm_uart_cpm2.h | 14 +- 6 files changed, 192 insertions(+), 183 deletions(-) diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 4e1987adc23b..32b9737759c4 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -56,21 +56,21 @@ struct uart_cpm_port { u16 rx_fifosize; u16 tx_nrfifos; u16 tx_fifosize; - smc_t *smcp; - smc_uart_t *smcup; - scc_t *sccp; - scc_uart_t *sccup; - volatile cbd_t *rx_bd_base; - volatile cbd_t *rx_cur; - volatile cbd_t *tx_bd_base; - volatile cbd_t *tx_cur; + smc_t __iomem *smcp; + smc_uart_t __iomem *smcup; + scc_t __iomem *sccp; + scc_uart_t __iomem *sccup; + cbd_t __iomem *rx_bd_base; + cbd_t __iomem *rx_cur; + cbd_t __iomem *tx_bd_base; + cbd_t __iomem *tx_cur; unsigned char *tx_buf; unsigned char *rx_buf; u32 flags; void (*set_lineif)(struct uart_cpm_port *); u8 brg; uint dp_addr; - void *mem_addr; + void *mem_addr; dma_addr_t dma_addr; u32 mem_size; /* helpers */ @@ -106,34 +106,36 @@ void scc4_lineif(struct uart_cpm_port *pinfo); /* virtual to phys transtalion */ -static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo) +static inline unsigned long cpu2cpm_addr(void *addr, + struct uart_cpm_port *pinfo) { int offset; u32 val = (u32)addr; + u32 mem = (u32)pinfo->mem_addr; /* sane check */ - if (likely((val >= (u32)pinfo->mem_addr)) && - (val<((u32)pinfo->mem_addr + pinfo->mem_size))) { - offset = val - (u32)pinfo->mem_addr; - return pinfo->dma_addr+offset; + if (likely(val >= mem && val < mem + pinfo->mem_size)) { + offset = val - mem; + return pinfo->dma_addr + offset; } /* something nasty happened */ BUG(); return 0; } -static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo) +static inline void *cpm2cpu_addr(unsigned long addr, + struct uart_cpm_port *pinfo) { int offset; u32 val = addr; + u32 dma = (u32)pinfo->dma_addr; /* sane check */ - if (likely((val >= pinfo->dma_addr) && - (val<(pinfo->dma_addr + pinfo->mem_size)))) { - offset = val - (u32)pinfo->dma_addr; - return (void*)(pinfo->mem_addr+offset); + if (likely(val >= dma && val < dma + pinfo->mem_size)) { + offset = val - dma; + return pinfo->mem_addr + offset; } /* something nasty happened */ BUG(); - return 0; + return NULL; } diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 8564ba2f3ec2..afaf195b6e04 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -131,14 +131,14 @@ static int cpm_uart_id2nr(int id) static unsigned int cpm_uart_tx_empty(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile cbd_t *bdp = pinfo->tx_bd_base; + cbd_t __iomem *bdp = pinfo->tx_bd_base; int ret = 0; while (1) { - if (bdp->cbd_sc & BD_SC_READY) + if (in_be16(&bdp->cbd_sc) & BD_SC_READY) break; - if (bdp->cbd_sc & BD_SC_WRAP) { + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) { ret = TIOCSER_TEMT; break; } @@ -167,15 +167,15 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port) static void cpm_uart_stop_tx(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:stop tx\n", port->line); if (IS_SMC(pinfo)) - smcp->smc_smcm &= ~SMCM_TX; + clrbits8(&smcp->smc_smcm, SMCM_TX); else - sccp->scc_sccm &= ~UART_SCCM_TX; + clrbits16(&sccp->scc_sccm, UART_SCCM_TX); } /* @@ -184,24 +184,24 @@ static void cpm_uart_stop_tx(struct uart_port *port) static void cpm_uart_start_tx(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:start tx\n", port->line); if (IS_SMC(pinfo)) { - if (smcp->smc_smcm & SMCM_TX) + if (in_8(&smcp->smc_smcm) & SMCM_TX) return; } else { - if (sccp->scc_sccm & UART_SCCM_TX) + if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX) return; } if (cpm_uart_tx_pump(port) != 0) { if (IS_SMC(pinfo)) { - smcp->smc_smcm |= SMCM_TX; + setbits8(&smcp->smc_smcm, SMCM_TX); } else { - sccp->scc_sccm |= UART_SCCM_TX; + setbits16(&sccp->scc_sccm, UART_SCCM_TX); } } } @@ -212,15 +212,15 @@ static void cpm_uart_start_tx(struct uart_port *port) static void cpm_uart_stop_rx(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:stop rx\n", port->line); if (IS_SMC(pinfo)) - smcp->smc_smcm &= ~SMCM_RX; + clrbits8(&smcp->smc_smcm, SMCM_RX); else - sccp->scc_sccm &= ~UART_SCCM_RX; + clrbits16(&sccp->scc_sccm, UART_SCCM_RX); } /* @@ -263,10 +263,11 @@ static void cpm_uart_int_tx(struct uart_port *port) static void cpm_uart_int_rx(struct uart_port *port) { int i; - unsigned char ch, *cp; + unsigned char ch; + u8 *cp; struct tty_struct *tty = port->info->tty; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile cbd_t *bdp; + cbd_t __iomem *bdp; u16 status; unsigned int flg; @@ -278,13 +279,13 @@ static void cpm_uart_int_rx(struct uart_port *port) bdp = pinfo->rx_cur; for (;;) { /* get status */ - status = bdp->cbd_sc; + status = in_be16(&bdp->cbd_sc); /* If this one is empty, return happy */ if (status & BD_SC_EMPTY) break; /* get number of characters, and check spce in flip-buffer */ - i = bdp->cbd_datlen; + i = in_be16(&bdp->cbd_datlen); /* If we have not enough room in tty flip buffer, then we try * later, which will be the next rx-interrupt or a timeout @@ -295,7 +296,7 @@ static void cpm_uart_int_rx(struct uart_port *port) } /* get pointer */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); + cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); /* loop through the buffer */ while (i-- > 0) { @@ -315,10 +316,11 @@ static void cpm_uart_int_rx(struct uart_port *port) } /* End while (i--) */ /* This BD is ready to be used again. Clear status. get next */ - bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); - bdp->cbd_sc |= BD_SC_EMPTY; + clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR | + BD_SC_OV | BD_SC_ID); + setbits16(&bdp->cbd_sc, BD_SC_EMPTY); - if (bdp->cbd_sc & BD_SC_WRAP) + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->rx_bd_base; else bdp++; @@ -326,7 +328,7 @@ static void cpm_uart_int_rx(struct uart_port *port) } /* End for (;;) */ /* Write back buffer pointer */ - pinfo->rx_cur = (volatile cbd_t *) bdp; + pinfo->rx_cur = bdp; /* activate BH processing */ tty_flip_buffer_push(tty); @@ -380,14 +382,14 @@ static irqreturn_t cpm_uart_int(int irq, void *data) u8 events; struct uart_port *port = (struct uart_port *)data; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:IRQ\n", port->line); if (IS_SMC(pinfo)) { - events = smcp->smc_smce; - smcp->smc_smce = events; + events = in_8(&smcp->smc_smce); + out_8(&smcp->smc_smce, events); if (events & SMCM_BRKE) uart_handle_break(port); if (events & SMCM_RX) @@ -395,8 +397,8 @@ static irqreturn_t cpm_uart_int(int irq, void *data) if (events & SMCM_TX) cpm_uart_int_tx(port); } else { - events = sccp->scc_scce; - sccp->scc_scce = events; + events = in_be16(&sccp->scc_scce); + out_be16(&sccp->scc_scce, events); if (events & UART_SCCM_BRKE) uart_handle_break(port); if (events & UART_SCCM_RX) @@ -421,11 +423,11 @@ static int cpm_uart_startup(struct uart_port *port) /* Startup rx-int */ if (IS_SMC(pinfo)) { - pinfo->smcp->smc_smcm |= SMCM_RX; - pinfo->smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); + setbits8(&pinfo->smcp->smc_smcm, SMCM_RX); + setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN)); } else { - pinfo->sccp->scc_sccm |= UART_SCCM_RX; - pinfo->sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX); + setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT)); } if (!(pinfo->flags & FLAG_CONSOLE)) @@ -464,13 +466,13 @@ static void cpm_uart_shutdown(struct uart_port *port) /* Stop uarts */ if (IS_SMC(pinfo)) { - volatile smc_t *smcp = pinfo->smcp; - smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); + smc_t __iomem *smcp = pinfo->smcp; + clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); + clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX); } else { - volatile scc_t *sccp = pinfo->sccp; - sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); + scc_t __iomem *sccp = pinfo->sccp; + clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); } /* Shut them really down and reinit buffer descriptors */ @@ -492,8 +494,8 @@ static void cpm_uart_set_termios(struct uart_port *port, u16 cval, scval, prev_mode; int bits, sbits; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:set_termios\n", port->line); @@ -588,11 +590,11 @@ static void cpm_uart_set_termios(struct uart_port *port, * enables, because we want to put them back if they were * present. */ - prev_mode = smcp->smc_smcmr; - smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; - smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); + prev_mode = in_be16(&smcp->smc_smcmr); + out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | SMCMR_SM_UART); + setbits16(&smcp->smc_smcmr, (prev_mode & (SMCMR_REN | SMCMR_TEN))); } else { - sccp->scc_psmr = (sbits << 12) | scval; + out_be16(&sccp->scc_psmr, (sbits << 12) | scval); } cpm_set_brg(pinfo->brg - 1, baud); @@ -630,8 +632,8 @@ static int cpm_uart_verify_port(struct uart_port *port, */ static int cpm_uart_tx_pump(struct uart_port *port) { - volatile cbd_t *bdp; - unsigned char *p; + cbd_t __iomem *bdp; + u8 *p; int count; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; struct circ_buf *xmit = &port->info->xmit; @@ -641,13 +643,14 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); + p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *p++ = port->x_char; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; + + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); /* Get next BD. */ - if (bdp->cbd_sc & BD_SC_WRAP) + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; @@ -666,9 +669,10 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { + while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && + xmit->tail != xmit->head) { count = 0; - p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); + p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -677,11 +681,10 @@ static int cpm_uart_tx_pump(struct uart_port *port) if (xmit->head == xmit->tail) break; } - bdp->cbd_datlen = count; - bdp->cbd_sc |= BD_SC_READY; - eieio(); + out_be16(&bdp->cbd_datlen, count); + setbits16(&bdp->cbd_sc, BD_SC_READY); /* Get next BD. */ - if (bdp->cbd_sc & BD_SC_WRAP) + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; @@ -706,7 +709,7 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) { int i; u8 *mem_addr; - volatile cbd_t *bdp; + cbd_t __iomem *bdp; pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line); @@ -717,13 +720,13 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr; bdp = pinfo->rx_cur = pinfo->rx_bd_base; for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); - bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT); mem_addr += pinfo->rx_fifosize; } - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); - bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -732,19 +735,19 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); bdp = pinfo->tx_cur = pinfo->tx_bd_base; for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); - bdp->cbd_sc = BD_SC_INTRPT; + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_INTRPT); mem_addr += pinfo->tx_fifosize; } - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); - bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT; + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT); } static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) { - volatile scc_t *scp; - volatile scc_uart_t *sup; + scc_t __iomem *scp; + scc_uart_t __iomem *sup; pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line); @@ -752,8 +755,10 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) sup = pinfo->sccup; /* Store address */ - pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE; - pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE; + out_be16(&pinfo->sccup->scc_genscc.scc_rbase, + (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE); + out_be16(&pinfo->sccup->scc_genscc.scc_tbase, + (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE); /* Set up the uart parameters in the * parameter ram. @@ -761,25 +766,25 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) cpm_set_scc_fcr(sup); - sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize; - sup->scc_maxidl = pinfo->rx_fifosize; - sup->scc_brkcr = 1; - sup->scc_parec = 0; - sup->scc_frmec = 0; - sup->scc_nosec = 0; - sup->scc_brkec = 0; - sup->scc_uaddr1 = 0; - sup->scc_uaddr2 = 0; - sup->scc_toseq = 0; - sup->scc_char1 = 0x8000; - sup->scc_char2 = 0x8000; - sup->scc_char3 = 0x8000; - sup->scc_char4 = 0x8000; - sup->scc_char5 = 0x8000; - sup->scc_char6 = 0x8000; - sup->scc_char7 = 0x8000; - sup->scc_char8 = 0x8000; - sup->scc_rccm = 0xc0ff; + out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); + out_be16(&sup->scc_maxidl, pinfo->rx_fifosize); + out_be16(&sup->scc_brkcr, 1); + out_be16(&sup->scc_parec, 0); + out_be16(&sup->scc_frmec, 0); + out_be16(&sup->scc_nosec, 0); + out_be16(&sup->scc_brkec, 0); + out_be16(&sup->scc_uaddr1, 0); + out_be16(&sup->scc_uaddr2, 0); + out_be16(&sup->scc_toseq, 0); + out_be16(&sup->scc_char1, 0x8000); + out_be16(&sup->scc_char2, 0x8000); + out_be16(&sup->scc_char3, 0x8000); + out_be16(&sup->scc_char4, 0x8000); + out_be16(&sup->scc_char5, 0x8000); + out_be16(&sup->scc_char6, 0x8000); + out_be16(&sup->scc_char7, 0x8000); + out_be16(&sup->scc_char8, 0x8000); + out_be16(&sup->scc_rccm, 0xc0ff); /* Send the CPM an initialize command. */ @@ -788,23 +793,23 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. */ - scp->scc_gsmrh = 0; - scp->scc_gsmrl = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + out_be32(&scp->scc_gsmrh, 0); + out_be32(&scp->scc_gsmrl, + SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); /* Enable rx interrupts and clear all pending events. */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_psmr = 0x3000; + out_be16(&scp->scc_sccm, 0); + out_be16(&scp->scc_scce, 0xffff); + out_be16(&scp->scc_dsr, 0x7e7e); + out_be16(&scp->scc_psmr, 0x3000); - scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) { - volatile smc_t *sp; - volatile smc_uart_t *up; + smc_t __iomem *sp; + smc_uart_t __iomem *up; pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line); @@ -812,19 +817,21 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) up = pinfo->smcup; /* Store address */ - pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE; - pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE; + out_be16(&pinfo->smcup->smc_rbase, + (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE); + out_be16(&pinfo->smcup->smc_tbase, + (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE); /* * In case SMC1 is being relocated... */ #if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH) - up->smc_rbptr = pinfo->smcup->smc_rbase; - up->smc_tbptr = pinfo->smcup->smc_tbase; - up->smc_rstate = 0; - up->smc_tstate = 0; - up->smc_brkcr = 1; /* number of break chars */ - up->smc_brkec = 0; + out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase)); + out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase)); + out_be32(&up->smc_rstate, 0); + out_be32(&up->smc_tstate, 0); + out_be16(&up->smc_brkcr, 1); /* number of break chars */ + out_be16(&up->smc_brkec, 0); #endif /* Set up the uart parameters in the @@ -833,24 +840,24 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) cpm_set_smc_fcr(up); /* Using idle charater time requires some additional tuning. */ - up->smc_mrblr = pinfo->rx_fifosize; - up->smc_maxidl = pinfo->rx_fifosize; - up->smc_brklen = 0; - up->smc_brkec = 0; - up->smc_brkcr = 1; + out_be16(&up->smc_mrblr, pinfo->rx_fifosize); + out_be16(&up->smc_maxidl, pinfo->rx_fifosize); + out_be16(&up->smc_brklen, 0); + out_be16(&up->smc_brkec, 0); + out_be16(&up->smc_brkcr, 1); cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART); /* Enable only rx interrupts clear all pending events. */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; + out_8(&sp->smc_smcm, 0); + out_8(&sp->smc_smce, 0xff); - sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); + setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN); } /* @@ -868,11 +875,11 @@ static int cpm_uart_request_port(struct uart_port *port) return 0; if (IS_SMC(pinfo)) { - pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); - pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); + clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); } else { - pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } ret = cpm_uart_allocbuf(pinfo, 0); @@ -931,10 +938,11 @@ static struct uart_ops cpm_uart_pops = { #ifdef CONFIG_PPC_CPM_NEW_BINDING struct uart_cpm_port cpm_uart_ports[UART_NR]; -int cpm_uart_init_port(struct device_node *np, struct uart_cpm_port *pinfo) +static int cpm_uart_init_port(struct device_node *np, + struct uart_cpm_port *pinfo) { const u32 *data; - void __iomem *mem, __iomem *pram; + void __iomem *mem, *pram; int len; int ret; @@ -1169,8 +1177,8 @@ static void cpm_uart_console_write(struct console *co, const char *s, &cpm_uart_ports[cpm_uart_port_map[co->index]]; #endif unsigned int i; - volatile cbd_t *bdp, *bdbase; - volatile unsigned char *cp; + cbd_t __iomem *bdp, *bdbase; + unsigned char *cp; /* Get the address of the host memory buffer. */ @@ -1188,37 +1196,36 @@ static void cpm_uart_console_write(struct console *co, const char *s, * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ - while ((bdp->cbd_sc & BD_SC_READY) != 0) + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; /* Send the character out. * If the buffer address is in the CPM DPRAM, don't * convert it. */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); - + cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cp = *s; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); - if (bdp->cbd_sc & BD_SC_WRAP) + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { - while ((bdp->cbd_sc & BD_SC_READY) != 0) + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; - cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); - + cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cp = 13; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; - if (bdp->cbd_sc & BD_SC_WRAP) + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); + + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; @@ -1229,10 +1236,10 @@ static void cpm_uart_console_write(struct console *co, const char *s, * Finally, Wait for transmitter & holding register to empty * and restore the IER */ - while ((bdp->cbd_sc & BD_SC_READY) != 0) + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; - pinfo->tx_cur = (volatile cbd_t *) bdp; + pinfo->tx_cur = bdp; } @@ -1319,11 +1326,11 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) #endif if (IS_SMC(pinfo)) { - pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); - pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); + clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); } else { - pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } ret = cpm_uart_allocbuf(pinfo, 1); @@ -1354,7 +1361,7 @@ static struct console cpm_scc_uart_console = { .data = &cpm_reg, }; -int __init cpm_uart_console_init(void) +static int __init cpm_uart_console_init(void) { register_console(&cpm_scc_uart_console); return 0; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 4647f55e19f1..52fb044bb79a 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -179,7 +179,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); - pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; + pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index 69f523a442e0..9b5465fb0bbb 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -27,18 +27,18 @@ static inline void cpm_set_brg(int brg, int baud) cpm_setbrg(brg, baud); } -static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup) +static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup) { - sup->scc_genscc.scc_rfcr = SMC_EB; - sup->scc_genscc.scc_tfcr = SMC_EB; + out_8(&sup->scc_genscc.scc_rfcr, SMC_EB); + out_8(&sup->scc_genscc.scc_tfcr, SMC_EB); } -static inline void cpm_set_smc_fcr(volatile smc_uart_t * up) +static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up) { - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; + out_8(&up->smc_rfcr, SMC_EB); + out_8(&up->smc_tfcr, SMC_EB); } -#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0)) +#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) #endif diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 7ebce263ad40..5bd4508ce3c1 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -278,7 +278,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); - pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; + pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; @@ -289,7 +289,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * - pinfo->tx_fifosize), pinfo->mem_addr, + pinfo->tx_fifosize), (void __force *)pinfo->mem_addr, pinfo->dma_addr); cpm_dpfree(pinfo->dp_addr); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h index e7717ece0831..40006a7dce46 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h @@ -27,18 +27,18 @@ static inline void cpm_set_brg(int brg, int baud) cpm_setbrg(brg, baud); } -static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup) +static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup) { - sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; - sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; + out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB); + out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB); } -static inline void cpm_set_smc_fcr(volatile smc_uart_t * up) +static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up) { - up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; - up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; + out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB); + out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB); } -#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0)) +#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) #endif From d948a29ea7a9514f588dafb61d5a6da68131c3ba Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 17 Jul 2007 18:09:33 -0500 Subject: [PATCH 0432/2804] [POWERPC] cpm_uart: Issue STOP_TX command before initializing console. This prevents some bootloader/bootwrapper characters from being lost. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index afaf195b6e04..b5e4478de0e3 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -1325,6 +1325,8 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) udbg_putc = NULL; #endif + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); + if (IS_SMC(pinfo)) { clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); @@ -1346,6 +1348,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) cpm_uart_init_scc(pinfo); uart_set_options(port, co, baud, parity, bits, flow); + cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); return 0; } From ccf0d68e835003f19d5a9463d5a8c1e092d3a31a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 16 Jul 2007 11:28:18 -0500 Subject: [PATCH 0433/2804] [POWERPC] 8xx: Fix CONFIG_PIN_TLB. 1. Move CONSISTENT_START on 8xx so that it doesn't overlap the IMMR mapping. 2. The wrong register was being loaded into SPRN_MD_RPN. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/head_8xx.S | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b387e1ed5177..37ff383393bd 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -600,6 +600,7 @@ config CONSISTENT_START_BOOL config CONSISTENT_START hex "Base virtual address of consistent memory pool" if CONSISTENT_START_BOOL + default "0xfd000000" if (NOT_COHERENT_CACHE && 8xx) default "0xff100000" if NOT_COHERENT_CACHE config CONSISTENT_SIZE_BOOL diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 96cea8e753c4..9c30938aad52 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -727,13 +727,13 @@ initial_mmu: mtspr SPRN_MD_TWC, r9 li r11, MI_BOOTINIT /* Create RPN for address 0 */ addis r11, r11, 0x0080 /* Add 8M */ - mtspr SPRN_MD_RPN, r8 + mtspr SPRN_MD_RPN, r11 addis r8, r8, 0x0080 /* Add 8M */ mtspr SPRN_MD_EPN, r8 mtspr SPRN_MD_TWC, r9 addis r11, r11, 0x0080 /* Add 8M */ - mtspr SPRN_MD_RPN, r8 + mtspr SPRN_MD_RPN, r11 #endif /* Since the cache is enabled according to the information we From fb533d0c5a9783ecafa9a177bace6384c47282a9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 14 Sep 2007 14:22:36 -0500 Subject: [PATCH 0434/2804] [POWERPC] 8xx: Infrastructure code cleanup. 1. Keep a global mpc8xx_immr mapping, rather than constantly creating temporary mappings. 2. Look for new fsl,cpm1 and fsl,cpm1-pic names. 3. Always reset the CPM when not using the udbg console; this is required in case the firmware initialized a device that is incompatible with one that the kernel is about to use. 4. Remove some superfluous casts and header includes. 5. Change a usage of IMAP_ADDR to get_immrbase(). 6. Use phys_addr_t, not uint, for dpram_pbase. 7. Various sparse-related fixes, such as __iomem annotations. 8. Remove mpc8xx_show_cpuinfo, which doesn't provide anything useful beyond the generic cpuinfo handler. 9. Move prototypes for 8xx support functions from board files to sysdev/commproc.h. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/platforms/8xx/m8xx_setup.c | 90 +++++--------------- arch/powerpc/platforms/8xx/mpc86xads.h | 3 - arch/powerpc/platforms/8xx/mpc86xads_setup.c | 10 +-- arch/powerpc/platforms/8xx/mpc885ads.h | 3 - arch/powerpc/platforms/8xx/mpc885ads_setup.c | 10 +-- arch/powerpc/sysdev/commproc.c | 67 ++++++++------- arch/powerpc/sysdev/commproc.h | 12 +++ arch/powerpc/sysdev/mpc8xx_pic.c | 19 ++--- include/asm-powerpc/commproc.h | 4 +- include/asm-powerpc/fs_pd.h | 19 +---- 10 files changed, 88 insertions(+), 149 deletions(-) create mode 100644 arch/powerpc/sysdev/commproc.h diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index b2b98dd8be6a..d35eda80e9e6 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -10,57 +10,33 @@ * bootup setup stuff.. */ -#include -#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -#include #include -#include -#include -#include -#include -#include #include #include -#include -#include -#include #include -#include #include #include -#include -#include #include #include #include -#include "sysdev/mpc8xx_pic.h" +#include +#include #ifdef CONFIG_PCMCIA_M8XX struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; #endif void m8xx_calibrate_decr(void); -#ifdef CONFIG_8xx_WDT -extern void m8xx_wdt_handler_install(bd_t *bp); -#endif extern int cpm_pic_init(void); extern int cpm_get_irq(void); /* A place holder for time base interrupts, if they are ever enabled. */ -irqreturn_t timebase_interrupt(int irq, void * dev) +static irqreturn_t timebase_interrupt(int irq, void *dev) { printk ("timebase_interrupt()\n"); @@ -77,7 +53,7 @@ static struct irqaction tbint_irqaction = { void __init __attribute__ ((weak)) init_internal_rtc(void) { - sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit); + sit8xx_t __iomem *sys_tmr = immr_map(im_sit); /* Disable the RTC one second and alarm interrupts. */ clrbits16(&sys_tmr->sit_rtcsc, (RTCSC_SIE | RTCSC_ALE)); @@ -116,13 +92,13 @@ static int __init get_freq(char *name, unsigned long *val) void __init mpc8xx_calibrate_decr(void) { struct device_node *cpu; - cark8xx_t *clk_r1; - car8xx_t *clk_r2; - sitk8xx_t *sys_tmr1; - sit8xx_t *sys_tmr2; + cark8xx_t __iomem *clk_r1; + car8xx_t __iomem *clk_r2; + sitk8xx_t __iomem *sys_tmr1; + sit8xx_t __iomem *sys_tmr2; int irq, virq; - clk_r1 = (cark8xx_t *) immr_map(im_clkrstk); + clk_r1 = immr_map(im_clkrstk); /* Unlock the SCCR. */ out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY); @@ -130,7 +106,7 @@ void __init mpc8xx_calibrate_decr(void) immr_unmap(clk_r1); /* Force all 8xx processors to use divide by 16 processor clock. */ - clk_r2 = (car8xx_t *) immr_map(im_clkrst); + clk_r2 = immr_map(im_clkrst); setbits32(&clk_r2->car_sccr, 0x02000000); immr_unmap(clk_r2); @@ -164,7 +140,7 @@ void __init mpc8xx_calibrate_decr(void) * we guarantee the registers are locked, then we unlock them * for our use. */ - sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); + sys_tmr1 = immr_map(im_sitk); out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY); out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY); out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY); @@ -184,20 +160,13 @@ void __init mpc8xx_calibrate_decr(void) virq= irq_of_parse_and_map(cpu, 0); irq = irq_map[virq].hwirq; - sys_tmr2 = (sit8xx_t *) immr_map(im_sit); + sys_tmr2 = immr_map(im_sit); out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) | (TBSCR_TBF | TBSCR_TBE)); immr_unmap(sys_tmr2); if (setup_irq(virq, &tbint_irqaction)) panic("Could not allocate timer IRQ!"); - -#ifdef CONFIG_8xx_WDT - /* Install watchdog timer handler early because it might be - * already enabled by the bootloader - */ - m8xx_wdt_handler_install(binfo); -#endif } /* The RTC on the MPC8xx is an internal register. @@ -207,12 +176,12 @@ void __init mpc8xx_calibrate_decr(void) int mpc8xx_set_rtc_time(struct rtc_time *tm) { - sitk8xx_t *sys_tmr1; - sit8xx_t *sys_tmr2; + sitk8xx_t __iomem *sys_tmr1; + sit8xx_t __iomem *sys_tmr2; int time; - sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); - sys_tmr2 = (sit8xx_t *) immr_map(im_sit); + sys_tmr1 = immr_map(im_sitk); + sys_tmr2 = immr_map(im_sit); time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -228,7 +197,7 @@ int mpc8xx_set_rtc_time(struct rtc_time *tm) void mpc8xx_get_rtc_time(struct rtc_time *tm) { unsigned long data; - sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit); + sit8xx_t __iomem *sys_tmr = immr_map(im_sit); /* Get time from the RTC. */ data = in_be32(&sys_tmr->sit_rtc); @@ -241,8 +210,7 @@ void mpc8xx_get_rtc_time(struct rtc_time *tm) void mpc8xx_restart(char *cmd) { - __volatile__ unsigned char dummy; - car8xx_t * clk_r = (car8xx_t *) immr_map(im_clkrst); + car8xx_t __iomem *clk_r = immr_map(im_clkrst); local_irq_disable(); @@ -252,26 +220,8 @@ void mpc8xx_restart(char *cmd) */ mtmsr(mfmsr() & ~0x1000); - dummy = in_8(&clk_r->res[0]); - printk("Restart failed\n"); - while(1); -} - -void mpc8xx_show_cpuinfo(struct seq_file *m) -{ - struct device_node *root; - uint memsize = total_memory; - const char *model = ""; - - seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - - root = of_find_node_by_path("/"); - if (root) - model = of_get_property(root, "model", NULL); - seq_printf(m, "Machine\t\t: %s\n", model); - of_node_put(root); - - seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + in_8(&clk_r->res[0]); + panic("Restart failed\n"); } static void cpm_cascade(unsigned int irq, struct irq_desc *desc) diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h index dd10cd20b6a7..cffa194ccf1f 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads.h +++ b/arch/powerpc/platforms/8xx/mpc86xads.h @@ -29,9 +29,6 @@ #define CFG_PHYDEV_ADDR ((uint)0xff0a0000) #define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) -#define IMAP_ADDR (get_immrbase()) -#define IMAP_SIZE ((uint)(64 * 1024)) - #define MPC8xx_CPM_OFFSET (0x9c0) #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c index 8f64f48698ab..49012835f453 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -37,14 +37,7 @@ #include #include -extern void cpm_reset(void); -extern void mpc8xx_show_cpuinfo(struct seq_file*); -extern void mpc8xx_restart(char *cmd); -extern void mpc8xx_calibrate_decr(void); -extern int mpc8xx_set_rtc_time(struct rtc_time *tm); -extern void mpc8xx_get_rtc_time(struct rtc_time *tm); -extern void m8xx_pic_init(void); -extern unsigned int mpc8xx_get_irq(void); +#include static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); @@ -277,7 +270,6 @@ define_machine(mpc86x_ads) { .probe = mpc86xads_probe, .setup_arch = mpc86xads_setup_arch, .init_IRQ = m8xx_pic_init, - .show_cpuinfo = mpc8xx_show_cpuinfo, .get_irq = mpc8xx_get_irq, .restart = mpc8xx_restart, .calibrate_decr = mpc8xx_calibrate_decr, diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h index 14db12417064..a21e528f26c6 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads.h +++ b/arch/powerpc/platforms/8xx/mpc885ads.h @@ -29,9 +29,6 @@ #define CFG_PHYDEV_ADDR ((uint)0xff0a0000) #define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) -#define IMAP_ADDR (get_immrbase()) -#define IMAP_SIZE ((uint)(64 * 1024)) - #define MPC8xx_CPM_OFFSET (0x9c0) #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index a1dab4cfd3de..bad08683f7ae 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -38,14 +38,7 @@ #include #include -extern void cpm_reset(void); -extern void mpc8xx_show_cpuinfo(struct seq_file *); -extern void mpc8xx_restart(char *cmd); -extern void mpc8xx_calibrate_decr(void); -extern int mpc8xx_set_rtc_time(struct rtc_time *tm); -extern void mpc8xx_get_rtc_time(struct rtc_time *tm); -extern void m8xx_pic_init(void); -extern unsigned int mpc8xx_get_irq(void); +#include static void init_smc1_uart_ioports(struct fs_uart_platform_info *fpi); static void init_smc2_uart_ioports(struct fs_uart_platform_info *fpi); @@ -430,7 +423,6 @@ define_machine(mpc885_ads) .probe = mpc885ads_probe, .setup_arch = mpc885ads_setup_arch, .init_IRQ = m8xx_pic_init, - .show_cpuinfo = mpc8xx_show_cpuinfo, .get_irq = mpc8xx_get_irq, .restart = mpc8xx_restart, .calibrate_decr = mpc8xx_calibrate_decr, diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c index 160a8b49bdea..f8f3741acd87 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/commproc.c @@ -47,8 +47,9 @@ static void m8xx_cpm_dpinit(void); static uint host_buffer; /* One page of host buffer */ static uint host_end; /* end + 1 */ -cpm8xx_t *cpmp; /* Pointer to comm processor space */ -cpic8xx_t *cpic_reg; +cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ +immap_t __iomem *mpc8xx_immr; +static cpic8xx_t __iomem *cpic_reg; static struct irq_host *cpm_pic_host; @@ -133,16 +134,19 @@ unsigned int cpm_pic_init(void) pr_debug("cpm_pic_init\n"); - np = of_find_compatible_node(NULL, "cpm-pic", "CPM"); + np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic"); + if (np == NULL) + np = of_find_compatible_node(NULL, "cpm-pic", "CPM"); if (np == NULL) { printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n"); return sirq; } + ret = of_address_to_resource(np, 0, &res); if (ret) goto end; - cpic_reg = (void *)ioremap(res.start, res.end - res.start + 1); + cpic_reg = ioremap(res.start, res.end - res.start + 1); if (cpic_reg == NULL) goto end; @@ -165,14 +169,16 @@ unsigned int cpm_pic_init(void) sirq = NO_IRQ; goto end; } - of_node_put(np); /* Install our own error handler. */ - np = of_find_node_by_type(NULL, "cpm"); + np = of_find_compatible_node(NULL, NULL, "fsl,cpm1"); + if (np == NULL) + np = of_find_node_by_type(NULL, "cpm"); if (np == NULL) { printk(KERN_ERR "CPM PIC init: can not find cpm node\n"); goto end; } + eirq = irq_of_parse_and_map(np, 0); if (eirq == NO_IRQ) goto end; @@ -189,21 +195,28 @@ end: void cpm_reset(void) { - cpm8xx_t *commproc; - sysconf8xx_t *siu_conf; + sysconf8xx_t __iomem *siu_conf; - commproc = (cpm8xx_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE); + mpc8xx_immr = ioremap(get_immrbase(), 0x4000); + if (!mpc8xx_immr) { + printk(KERN_CRIT "Could not map IMMR\n"); + return; + } -#ifdef CONFIG_UCODE_PATCH + cpmp = &mpc8xx_immr->im_cpm; + +#ifndef CONFIG_PPC_EARLY_DEBUG_CPM /* Perform a reset. */ - out_be16(&commproc->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); + out_be16(&cpmp->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); /* Wait for it. */ - while (in_be16(&commproc->cp_cpcr) & CPM_CR_FLG); + while (in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG); +#endif - cpm_load_patch(commproc); +#ifdef CONFIG_UCODE_PATCH + cpm_load_patch(cpmp); #endif /* Set SDMA Bus Request priority 5. @@ -212,16 +225,12 @@ void cpm_reset(void) * manual recommends it. * Bit 25, FAM can also be set to use FEC aggressive mode (860T). */ - siu_conf = (sysconf8xx_t*)immr_map(im_siu_conf); + siu_conf = immr_map(im_siu_conf); out_be32(&siu_conf->sc_sdcr, 1); immr_unmap(siu_conf); /* Reclaim the DP memory for our use. */ m8xx_cpm_dpinit(); - - /* Tell everyone where the comm processor resides. - */ - cpmp = commproc; } /* We used to do this earlier, but have to postpone as long as possible @@ -271,20 +280,20 @@ m8xx_cpm_hostalloc(uint size) void cpm_setbrg(uint brg, uint rate) { - volatile uint *bp; + u32 __iomem *bp; /* This is good enough to get SMCs running..... */ - bp = (uint *)&cpmp->cp_brgc1; + bp = &cpmp->cp_brgc1; bp += brg; /* The BRG has a 12-bit counter. For really slow baud rates (or * really fast processors), we may have to further divide by 16. */ if (((BRG_UART_CLK / rate) - 1) < 4096) - *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN; + out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); else - *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | - CPM_BRG_EN | CPM_BRG_DIV16; + out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | + CPM_BRG_EN | CPM_BRG_DIV16); } /* @@ -299,15 +308,15 @@ static rh_block_t cpm_boot_dpmem_rh_block[16]; static rh_info_t cpm_dpmem_info; #define CPM_DPMEM_ALIGNMENT 8 -static u8 *dpram_vbase; -static uint dpram_pbase; +static u8 __iomem *dpram_vbase; +static phys_addr_t dpram_pbase; -void m8xx_cpm_dpinit(void) +static void m8xx_cpm_dpinit(void) { spin_lock_init(&cpm_dpmem_lock); - dpram_vbase = immr_map_size(im_cpm.cp_dpmem, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE); - dpram_pbase = (uint)&((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem; + dpram_vbase = cpmp->cp_dpmem; + dpram_pbase = get_immrbase() + offsetof(immap_t, im_cpm.cp_dpmem); /* Initialize the info header */ rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT, @@ -383,7 +392,7 @@ void *cpm_dpram_addr(unsigned long offset) } EXPORT_SYMBOL(cpm_dpram_addr); -uint cpm_dpram_phys(u8* addr) +uint cpm_dpram_phys(u8 *addr) { return (dpram_pbase + (uint)(addr - dpram_vbase)); } diff --git a/arch/powerpc/sysdev/commproc.h b/arch/powerpc/sysdev/commproc.h new file mode 100644 index 000000000000..9155ba467274 --- /dev/null +++ b/arch/powerpc/sysdev/commproc.h @@ -0,0 +1,12 @@ +#ifndef _POWERPC_SYSDEV_COMMPROC_H +#define _POWERPC_SYSDEV_COMMPROC_H + +extern void cpm_reset(void); +extern void mpc8xx_restart(char *cmd); +extern void mpc8xx_calibrate_decr(void); +extern int mpc8xx_set_rtc_time(struct rtc_time *tm); +extern void mpc8xx_get_rtc_time(struct rtc_time *tm); +extern void m8xx_pic_init(void); +extern unsigned int mpc8xx_get_irq(void); + +#endif diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 565156ae65bc..7aa4ff5f5ec8 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -22,7 +22,7 @@ extern int cpm_get_irq(struct pt_regs *regs); static struct irq_host *mpc8xx_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; -static sysconf8xx_t *siu_reg; +static sysconf8xx_t __iomem *siu_reg; int cpm_get_irq(struct pt_regs *regs); @@ -159,13 +159,14 @@ static struct irq_host_ops mpc8xx_pic_host_ops = { int mpc8xx_pic_init(void) { struct resource res; - struct device_node *np = NULL; + struct device_node *np; int ret; - np = of_find_node_by_type(np, "mpc8xx-pic"); - + np = of_find_compatible_node(NULL, NULL, "fsl,pq1-pic"); + if (np == NULL) + np = of_find_node_by_type(NULL, "mpc8xx-pic"); if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); + printk(KERN_ERR "Could not find fsl,pq1-pic node\n"); return -ENOMEM; } @@ -173,11 +174,9 @@ int mpc8xx_pic_init(void) if (ret) goto out; - siu_reg = (void *)ioremap(res.start, res.end - res.start + 1); - if (siu_reg == NULL) { - ret = -EINVAL; - goto out; - } + siu_reg = ioremap(res.start, res.end - res.start + 1); + if (siu_reg == NULL) + return -EINVAL; mpc8xx_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR, 64, &mpc8xx_pic_host_ops, 64); diff --git a/include/asm-powerpc/commproc.h b/include/asm-powerpc/commproc.h index 397248705e0e..86fcf265c54a 100644 --- a/include/asm-powerpc/commproc.h +++ b/include/asm-powerpc/commproc.h @@ -66,7 +66,7 @@ /* Export the base address of the communication processor registers * and dual port ram. */ -extern cpm8xx_t *cpmp; /* Pointer to comm processor */ +extern cpm8xx_t __iomem *cpmp; /* Pointer to comm processor */ extern unsigned long cpm_dpalloc(uint size, uint align); extern int cpm_dpfree(unsigned long offset); extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); @@ -689,4 +689,6 @@ typedef struct risc_timer_pram { extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); extern void cpm_free_handler(int vec); +#define IMAP_ADDR (get_immrbase()) + #endif /* __CPM_8XX__ */ diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h index c624915b757e..77e04d01749c 100644 --- a/include/asm-powerpc/fs_pd.h +++ b/include/asm-powerpc/fs_pd.h @@ -45,22 +45,11 @@ #include #include -#define immr_map(member) \ -({ \ - u32 offset = offsetof(immap_t, member); \ - void *addr = ioremap (IMAP_ADDR + offset, \ - sizeof( ((immap_t*)0)->member)); \ - addr; \ -}) +extern immap_t __iomem *mpc8xx_immr; -#define immr_map_size(member, size) \ -({ \ - u32 offset = offsetof(immap_t, member); \ - void *addr = ioremap (IMAP_ADDR + offset, size); \ - addr; \ -}) - -#define immr_unmap(addr) iounmap(addr) +#define immr_map(member) (&mpc8xx_immr->member) +#define immr_map_size(member, size) (&mpc8xx_immr->member) +#define immr_unmap(addr) do {} while (0) #endif static inline int uart_baudrate(void) From 663edbd2640447dc43840568cd5701e6c9878d63 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 16 Jul 2007 17:22:01 -0500 Subject: [PATCH 0435/2804] [POWERPC] 8xx: Add pin and clock setting functions. These let board code set up pins and clocks without having to put magic numbers directly into the registers. The clock function is mostly duplicated from the cpm2 version; hopefully this stuff can be merged at some point. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/commproc.c | 201 +++++++++++++++++++++++++++++++++ include/asm-powerpc/commproc.h | 49 ++++++++ 2 files changed, 250 insertions(+) diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c index f8f3741acd87..428eb8c151b9 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/commproc.c @@ -397,3 +397,204 @@ uint cpm_dpram_phys(u8 *addr) return (dpram_pbase + (uint)(addr - dpram_vbase)); } EXPORT_SYMBOL(cpm_dpram_phys); + +struct cpm_ioport16 { + __be16 dir, par, sor, dat, intr; + __be16 res[3]; +}; + +struct cpm_ioport32 { + __be32 dir, par, sor; +}; + +static void cpm1_set_pin32(int port, int pin, int flags) +{ + struct cpm_ioport32 __iomem *iop; + pin = 1 << (31 - pin); + + if (port == CPM_PORTB) + iop = (struct cpm_ioport32 __iomem *) + &mpc8xx_immr->im_cpm.cp_pbdir; + else + iop = (struct cpm_ioport32 __iomem *) + &mpc8xx_immr->im_cpm.cp_pedir; + + if (flags & CPM_PIN_OUTPUT) + setbits32(&iop->dir, pin); + else + clrbits32(&iop->dir, pin); + + if (!(flags & CPM_PIN_GPIO)) + setbits32(&iop->par, pin); + else + clrbits32(&iop->par, pin); + + if (port == CPM_PORTE) { + if (flags & CPM_PIN_SECONDARY) + setbits32(&iop->sor, pin); + else + clrbits32(&iop->sor, pin); + + if (flags & CPM_PIN_OPENDRAIN) + setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); + else + clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin); + } +} + +static void cpm1_set_pin16(int port, int pin, int flags) +{ + struct cpm_ioport16 __iomem *iop = + (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport; + + pin = 1 << (15 - pin); + + if (port != 0) + iop += port - 1; + + if (flags & CPM_PIN_OUTPUT) + setbits16(&iop->dir, pin); + else + clrbits16(&iop->dir, pin); + + if (!(flags & CPM_PIN_GPIO)) + setbits16(&iop->par, pin); + else + clrbits16(&iop->par, pin); + + if (port == CPM_PORTC) { + if (flags & CPM_PIN_SECONDARY) + setbits16(&iop->sor, pin); + else + clrbits16(&iop->sor, pin); + } +} + +void cpm1_set_pin(enum cpm_port port, int pin, int flags) +{ + if (port == CPM_PORTB || port == CPM_PORTE) + cpm1_set_pin32(port, pin, flags); + else + cpm1_set_pin16(port, pin, flags); +} + +int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) +{ + int shift; + int i, bits = 0; + u32 __iomem *reg; + u32 mask = 7; + + u8 clk_map[][3] = { + {CPM_CLK_SCC1, CPM_BRG1, 0}, + {CPM_CLK_SCC1, CPM_BRG2, 1}, + {CPM_CLK_SCC1, CPM_BRG3, 2}, + {CPM_CLK_SCC1, CPM_BRG4, 3}, + {CPM_CLK_SCC1, CPM_CLK1, 4}, + {CPM_CLK_SCC1, CPM_CLK2, 5}, + {CPM_CLK_SCC1, CPM_CLK3, 6}, + {CPM_CLK_SCC1, CPM_CLK4, 7}, + + {CPM_CLK_SCC2, CPM_BRG1, 0}, + {CPM_CLK_SCC2, CPM_BRG2, 1}, + {CPM_CLK_SCC2, CPM_BRG3, 2}, + {CPM_CLK_SCC2, CPM_BRG4, 3}, + {CPM_CLK_SCC2, CPM_CLK1, 4}, + {CPM_CLK_SCC2, CPM_CLK2, 5}, + {CPM_CLK_SCC2, CPM_CLK3, 6}, + {CPM_CLK_SCC2, CPM_CLK4, 7}, + + {CPM_CLK_SCC3, CPM_BRG1, 0}, + {CPM_CLK_SCC3, CPM_BRG2, 1}, + {CPM_CLK_SCC3, CPM_BRG3, 2}, + {CPM_CLK_SCC3, CPM_BRG4, 3}, + {CPM_CLK_SCC3, CPM_CLK5, 4}, + {CPM_CLK_SCC3, CPM_CLK6, 5}, + {CPM_CLK_SCC3, CPM_CLK7, 6}, + {CPM_CLK_SCC3, CPM_CLK8, 7}, + + {CPM_CLK_SCC4, CPM_BRG1, 0}, + {CPM_CLK_SCC4, CPM_BRG2, 1}, + {CPM_CLK_SCC4, CPM_BRG3, 2}, + {CPM_CLK_SCC4, CPM_BRG4, 3}, + {CPM_CLK_SCC4, CPM_CLK5, 4}, + {CPM_CLK_SCC4, CPM_CLK6, 5}, + {CPM_CLK_SCC4, CPM_CLK7, 6}, + {CPM_CLK_SCC4, CPM_CLK8, 7}, + + {CPM_CLK_SMC1, CPM_BRG1, 0}, + {CPM_CLK_SMC1, CPM_BRG2, 1}, + {CPM_CLK_SMC1, CPM_BRG3, 2}, + {CPM_CLK_SMC1, CPM_BRG4, 3}, + {CPM_CLK_SMC1, CPM_CLK1, 4}, + {CPM_CLK_SMC1, CPM_CLK2, 5}, + {CPM_CLK_SMC1, CPM_CLK3, 6}, + {CPM_CLK_SMC1, CPM_CLK4, 7}, + + {CPM_CLK_SMC2, CPM_BRG1, 0}, + {CPM_CLK_SMC2, CPM_BRG2, 1}, + {CPM_CLK_SMC2, CPM_BRG3, 2}, + {CPM_CLK_SMC2, CPM_BRG4, 3}, + {CPM_CLK_SMC2, CPM_CLK5, 4}, + {CPM_CLK_SMC2, CPM_CLK6, 5}, + {CPM_CLK_SMC2, CPM_CLK7, 6}, + {CPM_CLK_SMC2, CPM_CLK8, 7}, + }; + + switch (target) { + case CPM_CLK_SCC1: + reg = &mpc8xx_immr->im_cpm.cp_sicr; + shift = 0; + break; + + case CPM_CLK_SCC2: + reg = &mpc8xx_immr->im_cpm.cp_sicr; + shift = 8; + break; + + case CPM_CLK_SCC3: + reg = &mpc8xx_immr->im_cpm.cp_sicr; + shift = 16; + break; + + case CPM_CLK_SCC4: + reg = &mpc8xx_immr->im_cpm.cp_sicr; + shift = 24; + break; + + case CPM_CLK_SMC1: + reg = &mpc8xx_immr->im_cpm.cp_simode; + shift = 12; + break; + + case CPM_CLK_SMC2: + reg = &mpc8xx_immr->im_cpm.cp_simode; + shift = 28; + break; + + default: + printk(KERN_ERR "cpm1_clock_setup: invalid clock target\n"); + return -EINVAL; + } + + if (reg == &mpc8xx_immr->im_cpm.cp_sicr && mode == CPM_CLK_RX) + shift += 3; + + for (i = 0; i < ARRAY_SIZE(clk_map); i++) { + if (clk_map[i][0] == target && clk_map[i][1] == clock) { + bits = clk_map[i][2]; + break; + } + } + + if (i == ARRAY_SIZE(clk_map)) { + printk(KERN_ERR "cpm1_clock_setup: invalid clock combination\n"); + return -EINVAL; + } + + bits <<= shift; + mask <<= shift; + out_be32(reg, (in_be32(reg) & ~mask) | bits); + + return 0; +} diff --git a/include/asm-powerpc/commproc.h b/include/asm-powerpc/commproc.h index 86fcf265c54a..5dec32404fa2 100644 --- a/include/asm-powerpc/commproc.h +++ b/include/asm-powerpc/commproc.h @@ -691,4 +691,53 @@ extern void cpm_free_handler(int vec); #define IMAP_ADDR (get_immrbase()) +#define CPM_PIN_INPUT 0 +#define CPM_PIN_OUTPUT 1 +#define CPM_PIN_PRIMARY 0 +#define CPM_PIN_SECONDARY 2 +#define CPM_PIN_GPIO 4 +#define CPM_PIN_OPENDRAIN 8 + +enum cpm_port { + CPM_PORTA, + CPM_PORTB, + CPM_PORTC, + CPM_PORTD, + CPM_PORTE, +}; + +void cpm1_set_pin(enum cpm_port port, int pin, int flags); + +enum cpm_clk_dir { + CPM_CLK_RX, + CPM_CLK_TX, + CPM_CLK_RTX +}; + +enum cpm_clk_target { + CPM_CLK_SCC1, + CPM_CLK_SCC2, + CPM_CLK_SCC3, + CPM_CLK_SCC4, + CPM_CLK_SMC1, + CPM_CLK_SMC2, +}; + +enum cpm_clk { + CPM_BRG1, /* Baud Rate Generator 1 */ + CPM_BRG2, /* Baud Rate Generator 2 */ + CPM_BRG3, /* Baud Rate Generator 3 */ + CPM_BRG4, /* Baud Rate Generator 4 */ + CPM_CLK1, /* Clock 1 */ + CPM_CLK2, /* Clock 2 */ + CPM_CLK3, /* Clock 3 */ + CPM_CLK4, /* Clock 4 */ + CPM_CLK5, /* Clock 5 */ + CPM_CLK6, /* Clock 6 */ + CPM_CLK7, /* Clock 7 */ + CPM_CLK8, /* Clock 8 */ +}; + +int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode); + #endif /* __CPM_8XX__ */ From 7401685242fbcbf4b0660726372c77a88c4af17d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 25 Jun 2007 14:50:41 -0500 Subject: [PATCH 0436/2804] [POWERPC] 8xx: Work around CPU15 erratum. The CPU15 erratum on MPC8xx chips can cause incorrect code execution under certain circumstances, where there is a conditional or indirect branch in the last word of a page, with a target in the last cache line of the next page. This patch implements one of the suggested workarounds, by forcing a TLB miss whenever execution crosses a page boundary. This is done by invalidating the pages before and after the one being loaded into the TLB in the ITLB miss handler. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/kernel/head_8xx.S | 6 ++++++ arch/powerpc/platforms/8xx/Kconfig | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 9c30938aad52..f7458396cd7c 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -298,6 +298,12 @@ InstructionTLBMiss: stw r10, 0(r0) stw r11, 4(r0) mfspr r10, SPRN_SRR0 /* Get effective address of fault */ +#ifdef CONFIG_8xx_CPU15 + addi r11, r10, 0x1000 + tlbie r11 + addi r11, r10, -0x1000 + tlbie r11 +#endif DO_8xx_CPU6(0x3780, r3) mtspr SPRN_MD_EPN, r10 /* Have to use MD_EPN for walk, MI_EPN can't */ mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 8ecd01ad0de8..322b155f24ec 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -100,6 +100,22 @@ config 8xx_CPU6 If in doubt, say N here. +config 8xx_CPU15 + bool "CPU15 Silicon Errata" + default y + help + This enables a workaround for erratum CPU15 on MPC8xx chips. + This bug can cause incorrect code execution under certain + circumstances. This workaround adds some overhead (a TLB miss + every time execution crosses a page boundary), and you may wish + to disable it if you have worked around the bug in the compiler + (by not placing conditional branches or branches to LR or CTR + in the last word of a page, with a target of the last cache + line in the next page), or if you have used some other + workaround. + + If in doubt, say Y here. + choice prompt "Microcode patch selection" default NO_UCODE_PATCH From 544cdabe642e5508e784de709530a74d0775d070 Mon Sep 17 00:00:00 2001 From: John Traill Date: Tue, 17 Jul 2007 05:17:23 +0400 Subject: [PATCH 0437/2804] [POWERPC] 8xx: Set initial memory limit. The 8xx can only support a max of 8M during early boot (it seems a lot of 8xx boards only have 8M so the bug was never triggered), but the early allocator isn't aware of this. The following change makes it able to run with larger memory. Signed-off-by: John Traill Signed-off-by: Vitaly Bordug Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/mm/init_32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 27c234fb5118..977cb1ee5e72 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -132,6 +132,9 @@ void __init MMU_init(void) /* 601 can only access 16MB at the moment */ if (PVR_VER(mfspr(SPRN_PVR)) == 1) __initial_memory_limit = 0x01000000; + /* 8xx can only access 8MB at the moment */ + if (PVR_VER(mfspr(SPRN_PVR)) == 0x50) + __initial_memory_limit = 0x00800000; /* parse args from command line */ MMU_setup(); From 449012daa92a60e42f0d55478641cfa796d51528 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 14 Sep 2007 15:30:44 -0500 Subject: [PATCH 0438/2804] [POWERPC] cpm2: Infrastructure code cleanup. Mostly sparse fixes (__iomem annotations, etc); also, cpm2_immr is used rather than creating many temporary mappings. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/cpm2_common.c | 56 ++++++++++++++++++++++--------- arch/powerpc/sysdev/cpm2_pic.c | 2 +- include/asm-powerpc/cpm2.h | 2 +- include/asm-powerpc/fs_pd.h | 19 ++--------- include/asm-powerpc/immap_cpm2.h | 4 ++- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c index 3bf89b324760..0330ca490928 100644 --- a/arch/powerpc/sysdev/cpm2_common.c +++ b/arch/powerpc/sysdev/cpm2_common.c @@ -33,6 +33,8 @@ #include #include #include +#include + #include #include #include @@ -45,13 +47,12 @@ #include static void cpm2_dpinit(void); -cpm_cpm2_t *cpmp; /* Pointer to comm processor space */ +cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */ /* We allocate this here because it is used almost exclusively for * the communication processor devices. */ -cpm2_map_t *cpm2_immr; -intctl_cpm2_t *cpm2_intctl; +cpm2_map_t __iomem *cpm2_immr; #define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount of space for CPM as it is larger @@ -60,8 +61,11 @@ intctl_cpm2_t *cpm2_intctl; void cpm2_reset(void) { - cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE); - cpm2_intctl = cpm2_map(im_intctl); +#ifdef CONFIG_PPC_85xx + cpm2_immr = ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE); +#else + cpm2_immr = ioremap(get_immrbase(), CPM_MAP_SIZE); +#endif /* Reclaim the DP memory for our use. */ @@ -91,7 +95,7 @@ cpm2_reset(void) void cpm_setbrg(uint brg, uint rate) { - volatile uint *bp; + u32 __iomem *bp; /* This is good enough to get SMCs running..... */ @@ -113,7 +117,8 @@ cpm_setbrg(uint brg, uint rate) void cpm2_fastbrg(uint brg, uint rate, int div16) { - volatile uint *bp; + u32 __iomem *bp; + u32 val; if (brg < 4) { bp = cpm2_map_size(im_brgc1, 16); @@ -123,10 +128,11 @@ cpm2_fastbrg(uint brg, uint rate, int div16) brg -= 4; } bp += brg; - *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN; + val = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN; if (div16) - *bp |= CPM_BRG_DIV16; + val |= CPM_BRG_DIV16; + out_be32(bp, val); cpm2_unmap(bp); } @@ -135,8 +141,8 @@ int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) int ret = 0; int shift; int i, bits = 0; - cpmux_t *im_cpmux; - u32 *reg; + cpmux_t __iomem *im_cpmux; + u32 __iomem *reg; u32 mask = 7; u8 clk_map [24][3] = { {CPM_CLK_FCC1, CPM_BRG5, 0}, @@ -228,13 +234,33 @@ static spinlock_t cpm_dpmem_lock; * until the memory subsystem goes up... */ static rh_block_t cpm_boot_dpmem_rh_block[16]; static rh_info_t cpm_dpmem_info; -static u8* im_dprambase; +static u8 __iomem *im_dprambase; static void cpm2_dpinit(void) { - spin_lock_init(&cpm_dpmem_lock); + struct resource r; - im_dprambase = ioremap(CPM_MAP_ADDR, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE); +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,cpm2"); + if (!np) + panic("Cannot find CPM2 node"); + + if (of_address_to_resource(np, 1, &r)) + panic("Cannot get CPM2 resource 1"); + + of_node_put(np); +#else + r.start = CPM_MAP_ADDR; + r.end = r.start + CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE - 1; +#endif + + im_dprambase = ioremap(r.start, r.end - r.start + 1); + if (!im_dprambase) + panic("Cannot map DPRAM"); + + spin_lock_init(&cpm_dpmem_lock); /* initialize the info header */ rh_init(&cpm_dpmem_info, 1, @@ -248,7 +274,7 @@ static void cpm2_dpinit(void) * varies with the processor and the microcode patches activated. * But the following should be at least safe. */ - rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE); + rh_attach_region(&cpm_dpmem_info, 0, r.end - r.start + 1); } /* This function returns an index into the DPRAM area. diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index d5b36e0ecbda..5fe65b2f8f3a 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -48,7 +48,7 @@ #define CPM2_IRQ_PORTC15 48 #define CPM2_IRQ_PORTC0 63 -static intctl_cpm2_t *cpm2_intctl; +static intctl_cpm2_t __iomem *cpm2_intctl; static struct irq_host *cpm2_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h index 12a2860f9a9c..c03650609792 100644 --- a/include/asm-powerpc/cpm2.h +++ b/include/asm-powerpc/cpm2.h @@ -107,7 +107,7 @@ /* Export the base address of the communication processor registers * and dual port ram. */ -extern cpm_cpm2_t *cpmp; /* Pointer to comm processor */ +extern cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor */ extern unsigned long cpm_dpalloc(uint size, uint align); extern int cpm_dpfree(unsigned long offset); diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h index 77e04d01749c..64706a0532d3 100644 --- a/include/asm-powerpc/fs_pd.h +++ b/include/asm-powerpc/fs_pd.h @@ -23,22 +23,9 @@ #include #endif -#define cpm2_map(member) \ -({ \ - u32 offset = offsetof(cpm2_map_t, member); \ - void *addr = ioremap (CPM_MAP_ADDR + offset, \ - sizeof( ((cpm2_map_t*)0)->member)); \ - addr; \ -}) - -#define cpm2_map_size(member, size) \ -({ \ - u32 offset = offsetof(cpm2_map_t, member); \ - void *addr = ioremap (CPM_MAP_ADDR + offset, size); \ - addr; \ -}) - -#define cpm2_unmap(addr) iounmap(addr) +#define cpm2_map(member) (&cpm2_immr->member) +#define cpm2_map_size(member, size) (&cpm2_immr->member) +#define cpm2_unmap(addr) do {} while(0) #endif #ifdef CONFIG_8xx diff --git a/include/asm-powerpc/immap_cpm2.h b/include/asm-powerpc/immap_cpm2.h index f316a91c628a..4080bab0468c 100644 --- a/include/asm-powerpc/immap_cpm2.h +++ b/include/asm-powerpc/immap_cpm2.h @@ -10,6 +10,8 @@ #ifndef __IMMAP_CPM2__ #define __IMMAP_CPM2__ +#include + /* System configuration registers. */ typedef struct sys_82xx_conf { @@ -642,7 +644,7 @@ typedef struct immap { u8 res11[4096]; } cpm2_map_t; -extern cpm2_map_t *cpm2_immr; +extern cpm2_map_t __iomem *cpm2_immr; #endif /* __IMMAP_CPM2__ */ #endif /* __KERNEL__ */ From 2652d4ec4a363487d0106a8bf51f1b081dd7e397 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 16 Jul 2007 13:26:35 -0500 Subject: [PATCH 0439/2804] [POWERPC] cpm2: Add SCCs to cpm2_clk_setup(), and cpm2_smc_clk_setup(). Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/cpm2_common.c | 100 ++++++++++++++++++++++++++++-- include/asm-powerpc/cpm2.h | 5 +- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c index 0330ca490928..c6dc0bf614b3 100644 --- a/arch/powerpc/sysdev/cpm2_common.c +++ b/arch/powerpc/sysdev/cpm2_common.c @@ -144,7 +144,8 @@ int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) cpmux_t __iomem *im_cpmux; u32 __iomem *reg; u32 mask = 7; - u8 clk_map [24][3] = { + + u8 clk_map[][3] = { {CPM_CLK_FCC1, CPM_BRG5, 0}, {CPM_CLK_FCC1, CPM_BRG6, 1}, {CPM_CLK_FCC1, CPM_BRG7, 2}, @@ -168,8 +169,40 @@ int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) {CPM_CLK_FCC3, CPM_CLK13, 4}, {CPM_CLK_FCC3, CPM_CLK14, 5}, {CPM_CLK_FCC3, CPM_CLK15, 6}, - {CPM_CLK_FCC3, CPM_CLK16, 7} - }; + {CPM_CLK_FCC3, CPM_CLK16, 7}, + {CPM_CLK_SCC1, CPM_BRG1, 0}, + {CPM_CLK_SCC1, CPM_BRG2, 1}, + {CPM_CLK_SCC1, CPM_BRG3, 2}, + {CPM_CLK_SCC1, CPM_BRG4, 3}, + {CPM_CLK_SCC1, CPM_CLK11, 4}, + {CPM_CLK_SCC1, CPM_CLK12, 5}, + {CPM_CLK_SCC1, CPM_CLK3, 6}, + {CPM_CLK_SCC1, CPM_CLK4, 7}, + {CPM_CLK_SCC2, CPM_BRG1, 0}, + {CPM_CLK_SCC2, CPM_BRG2, 1}, + {CPM_CLK_SCC2, CPM_BRG3, 2}, + {CPM_CLK_SCC2, CPM_BRG4, 3}, + {CPM_CLK_SCC2, CPM_CLK11, 4}, + {CPM_CLK_SCC2, CPM_CLK12, 5}, + {CPM_CLK_SCC2, CPM_CLK3, 6}, + {CPM_CLK_SCC2, CPM_CLK4, 7}, + {CPM_CLK_SCC3, CPM_BRG1, 0}, + {CPM_CLK_SCC3, CPM_BRG2, 1}, + {CPM_CLK_SCC3, CPM_BRG3, 2}, + {CPM_CLK_SCC3, CPM_BRG4, 3}, + {CPM_CLK_SCC3, CPM_CLK5, 4}, + {CPM_CLK_SCC3, CPM_CLK6, 5}, + {CPM_CLK_SCC3, CPM_CLK7, 6}, + {CPM_CLK_SCC3, CPM_CLK8, 7}, + {CPM_CLK_SCC4, CPM_BRG1, 0}, + {CPM_CLK_SCC4, CPM_BRG2, 1}, + {CPM_CLK_SCC4, CPM_BRG3, 2}, + {CPM_CLK_SCC4, CPM_BRG4, 3}, + {CPM_CLK_SCC4, CPM_CLK5, 4}, + {CPM_CLK_SCC4, CPM_CLK6, 5}, + {CPM_CLK_SCC4, CPM_CLK7, 6}, + {CPM_CLK_SCC4, CPM_CLK8, 7}, + }; im_cpmux = cpm2_map(im_cpmux); @@ -209,23 +242,80 @@ int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) if (mode == CPM_CLK_RX) shift += 3; - for (i=0; i<24; i++) { + for (i = 0; i < ARRAY_SIZE(clk_map); i++) { if (clk_map[i][0] == target && clk_map[i][1] == clock) { bits = clk_map[i][2]; break; } } - if (i == sizeof(clk_map)/3) + if (i == ARRAY_SIZE(clk_map)) ret = -EINVAL; bits <<= shift; mask <<= shift; + out_be32(reg, (in_be32(reg) & ~mask) | bits); cpm2_unmap(im_cpmux); return ret; } +int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock) +{ + int ret = 0; + int shift; + int i, bits = 0; + cpmux_t __iomem *im_cpmux; + u8 __iomem *reg; + u8 mask = 3; + + u8 clk_map[][3] = { + {CPM_CLK_SMC1, CPM_BRG1, 0}, + {CPM_CLK_SMC1, CPM_BRG7, 1}, + {CPM_CLK_SMC1, CPM_CLK7, 2}, + {CPM_CLK_SMC1, CPM_CLK9, 3}, + {CPM_CLK_SMC2, CPM_BRG2, 0}, + {CPM_CLK_SMC2, CPM_BRG8, 1}, + {CPM_CLK_SMC2, CPM_CLK4, 2}, + {CPM_CLK_SMC2, CPM_CLK15, 3}, + }; + + im_cpmux = cpm2_map(im_cpmux); + + switch (target) { + case CPM_CLK_SMC1: + reg = &im_cpmux->cmx_smr; + mask = 3; + shift = 4; + break; + case CPM_CLK_SMC2: + reg = &im_cpmux->cmx_smr; + mask = 3; + shift = 0; + break; + default: + printk(KERN_ERR "cpm2_smc_clock_setup: invalid clock target\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(clk_map); i++) { + if (clk_map[i][0] == target && clk_map[i][1] == clock) { + bits = clk_map[i][2]; + break; + } + } + if (i == ARRAY_SIZE(clk_map)) + ret = -EINVAL; + + bits <<= shift; + mask <<= shift; + + out_8(reg, (in_8(reg) & ~mask) | bits); + + cpm2_unmap(im_cpmux); + return ret; +} + /* * dpalloc / dpfree bits. */ diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h index c03650609792..41a45db0c8b1 100644 --- a/include/asm-powerpc/cpm2.h +++ b/include/asm-powerpc/cpm2.h @@ -1206,7 +1206,9 @@ enum cpm_clk_target { CPM_CLK_SCC4, CPM_CLK_FCC1, CPM_CLK_FCC2, - CPM_CLK_FCC3 + CPM_CLK_FCC3, + CPM_CLK_SMC1, + CPM_CLK_SMC2, }; enum cpm_clk { @@ -1243,6 +1245,7 @@ enum cpm_clk { }; extern int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode); +extern int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock); #endif /* __CPM2__ */ #endif /* __KERNEL__ */ From 7f21f52940212c25b4387c2450018e161043549a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 16 Jul 2007 13:32:24 -0500 Subject: [PATCH 0440/2804] [POWERPC] cpm2: Add cpm2_set_pin(). This provides a generic way for board code to set up CPM pins, rather than directly poking magic values into registers. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/cpm2_common.c | 33 +++++++++++++++++++++++++++++++ include/asm-powerpc/cpm2.h | 9 +++++++++ 2 files changed, 42 insertions(+) diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c index c6dc0bf614b3..fc4c99565381 100644 --- a/arch/powerpc/sysdev/cpm2_common.c +++ b/arch/powerpc/sysdev/cpm2_common.c @@ -422,3 +422,36 @@ void *cpm_dpram_addr(unsigned long offset) return (void *)(im_dprambase + offset); } EXPORT_SYMBOL(cpm_dpram_addr); + +struct cpm2_ioports { + u32 dir, par, sor, odr, dat; + u32 res[3]; +}; + +void cpm2_set_pin(int port, int pin, int flags) +{ + struct cpm2_ioports __iomem *iop = + (struct cpm2_ioports __iomem *)&cpm2_immr->im_ioport; + + pin = 1 << (31 - pin); + + if (flags & CPM_PIN_OUTPUT) + setbits32(&iop[port].dir, pin); + else + clrbits32(&iop[port].dir, pin); + + if (!(flags & CPM_PIN_GPIO)) + setbits32(&iop[port].par, pin); + else + clrbits32(&iop[port].par, pin); + + if (flags & CPM_PIN_SECONDARY) + setbits32(&iop[port].sor, pin); + else + clrbits32(&iop[port].sor, pin); + + if (flags & CPM_PIN_OPENDRAIN) + setbits32(&iop[port].odr, pin); + else + clrbits32(&iop[port].odr, pin); +} diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h index 41a45db0c8b1..d7b57ac55892 100644 --- a/include/asm-powerpc/cpm2.h +++ b/include/asm-powerpc/cpm2.h @@ -1247,5 +1247,14 @@ enum cpm_clk { extern int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode); extern int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock); +#define CPM_PIN_INPUT 0 +#define CPM_PIN_OUTPUT 1 +#define CPM_PIN_PRIMARY 0 +#define CPM_PIN_SECONDARY 2 +#define CPM_PIN_GPIO 4 +#define CPM_PIN_OPENDRAIN 8 + +void cpm2_set_pin(int port, int pin, int flags); + #endif /* __CPM2__ */ #endif /* __KERNEL__ */ From 11af1192b75307e4099dd962b3b97b255d5ab023 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 14 Sep 2007 15:32:14 -0500 Subject: [PATCH 0441/2804] [POWERPC] mpc82xx: Define CPU_FTR_NEED_COHERENT The 8272 (and presumably other PCI PQ2 chips) appear to have the same issue as the 83xx regarding PCI streaming DMA. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- include/asm-powerpc/cputable.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index f62cffd56c0c..c9b8f64bbb45 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -196,12 +196,12 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, #define PPC_FEATURE_HAS_EFP_DOUBLE_COMP 0 #endif -/* We need to mark all pages as being coherent if we're SMP or we - * have a 74[45]x and an MPC107 host bridge. Also 83xx requires - * it for PCI "streaming/prefetch" to work properly. +/* We need to mark all pages as being coherent if we're SMP or we have a + * 74[45]x and an MPC107 host bridge. Also 83xx and PowerQUICC II + * require it for PCI "streaming/prefetch" to work properly. */ #if defined(CONFIG_SMP) || defined(CONFIG_MPC10X_BRIDGE) \ - || defined(CONFIG_PPC_83xx) + || defined(CONFIG_PPC_83xx) || defined(CONFIG_8260) #define CPU_FTR_COMMON CPU_FTR_NEED_COHERENT #else #define CPU_FTR_COMMON 0 @@ -313,7 +313,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, CPU_FTR_PPC_LE) #define CPU_FTRS_82XX (CPU_FTR_COMMON | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB) -#define CPU_FTRS_G2_LE (CPU_FTR_MAYBE_CAN_DOZE | \ +#define CPU_FTRS_G2_LE (CPU_FTR_COMMON | CPU_FTR_MAYBE_CAN_DOZE | \ CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS) #define CPU_FTRS_E300 (CPU_FTR_MAYBE_CAN_DOZE | \ CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \ From 4ff62e1c7f5263427e742069235d94ba1336960d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 27 Aug 2007 16:56:43 -0500 Subject: [PATCH 0442/2804] [POWERPC] mpc82xx: Remove a bunch of cruft that duplicates generic functionality. m82xx_calibrate_decr(), mpc82xx_ads_show_cpuinfo(), and mpc82xx_halt() do anything useful beyond what the generic code does. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/platforms/82xx/Makefile | 1 - arch/powerpc/platforms/82xx/mpc82xx.c | 109 ---------------------- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 11 +-- arch/powerpc/platforms/82xx/pq2ads.h | 6 -- 4 files changed, 2 insertions(+), 125 deletions(-) delete mode 100644 arch/powerpc/platforms/82xx/mpc82xx.c diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile index d9fd4c84d2e0..534c35375b73 100644 --- a/arch/powerpc/platforms/82xx/Makefile +++ b/arch/powerpc/platforms/82xx/Makefile @@ -1,5 +1,4 @@ # # Makefile for the PowerPC 82xx linux kernel. # -obj-$(CONFIG_PPC_82xx) += mpc82xx.o obj-$(CONFIG_MPC82xx_ADS) += mpc82xx_ads.o diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c deleted file mode 100644 index c706871aec1a..000000000000 --- a/arch/powerpc/platforms/82xx/mpc82xx.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * MPC82xx setup and early boot code plus other random bits. - * - * Author: Vitaly Bordug - * - * Copyright (c) 2006 MontaVista Software, 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "pq2ads.h" - -static int __init get_freq(char *name, unsigned long *val) -{ - struct device_node *cpu; - const unsigned int *fp; - int found = 0; - - /* The cpu node should have timebase and clock frequency properties */ - cpu = of_find_node_by_type(NULL, "cpu"); - - if (cpu) { - fp = of_get_property(cpu, name, NULL); - if (fp) { - found = 1; - *val = *fp; - } - - of_node_put(cpu); - } - - return found; -} - -void __init m82xx_calibrate_decr(void) -{ - ppc_tb_freq = 125000000; - if (!get_freq("bus-frequency", &ppc_tb_freq)) { - printk(KERN_ERR "WARNING: Estimating decrementer frequency " - "(not found)\n"); - } - ppc_tb_freq /= 4; - ppc_proc_freq = 1000000000; - if (!get_freq("clock-frequency", &ppc_proc_freq)) - printk(KERN_ERR "WARNING: Estimating processor frequency" - "(not found)\n"); -} - -void mpc82xx_ads_show_cpuinfo(struct seq_file *m) -{ - uint pvid, svid, phid1; - uint memsize = total_memory; - - pvid = mfspr(SPRN_PVR); - svid = mfspr(SPRN_SVR); - - seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - seq_printf(m, "Machine\t\t: %s\n", CPUINFO_MACHINE); - seq_printf(m, "PVR\t\t: 0x%x\n", pvid); - seq_printf(m, "SVR\t\t: 0x%x\n", svid); - - /* Display cpu Pll setting */ - phid1 = mfspr(SPRN_HID1); - seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); - - /* Display the amount of memory */ - seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); -} diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 40087952935a..5f538d5e7fdb 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -612,20 +612,13 @@ static void m82xx_restart(char *cmd) while (1) ; } -static void m82xx_halt(void) -{ - local_irq_disable(); - while (1) ; -} - define_machine(mpc82xx_ads) { .name = "MPC82xx ADS", .probe = mpc82xx_ads_probe, .setup_arch = mpc82xx_ads_setup_arch, .init_IRQ = mpc82xx_ads_pic_init, - .show_cpuinfo = mpc82xx_ads_show_cpuinfo, .get_irq = cpm2_get_irq, - .calibrate_decr = m82xx_calibrate_decr, - .restart = m82xx_restart,.halt = m82xx_halt, + .calibrate_decr = generic_calibrate_decr, + .restart = m82xx_restart, }; diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h index 6f749b76dd8f..8b67048e6f22 100644 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ b/arch/powerpc/platforms/82xx/pq2ads.h @@ -24,10 +24,6 @@ #include -/* For our show_cpuinfo hooks. */ -#define CPUINFO_VENDOR "Freescale Semiconductor" -#define CPUINFO_MACHINE "PQ2 ADS PowerPC" - /* Backword-compatibility stuff for the drivers */ #define CPM_MAP_ADDR ((uint)0xf0000000) #define CPM_IRQ_OFFSET 0 @@ -58,8 +54,6 @@ #define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET) void m82xx_pci_init_irq(void); -void mpc82xx_ads_show_cpuinfo(struct seq_file*); -void m82xx_calibrate_decr(void); #endif /* __MACH_ADS8260_DEFS */ #endif /* __KERNEL__ */ From d1df447197b11e70d451786be8aebf2f8606754e Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 26 Jul 2007 13:51:42 -0500 Subject: [PATCH 0443/2804] [POWERPC] mpc82xx: Rename mpc82xx_ads to mpc8272_ads. This is just a rename patch; internal references to mpc82xx_ads will be changed in the next one. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/platforms/82xx/Kconfig | 8 ++++---- arch/powerpc/platforms/82xx/Makefile | 2 +- .../platforms/82xx/{mpc82xx_ads.c => mpc8272_ads.c} | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename arch/powerpc/platforms/82xx/{mpc82xx_ads.c => mpc8272_ads.c} (100%) diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 89fde43895c5..f260c014ff2a 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -1,17 +1,17 @@ choice prompt "82xx Board Type" depends on PPC_82xx - default MPC82xx_ADS + default MPC8272_ADS -config MPC82xx_ADS - bool "Freescale MPC82xx ADS" +config MPC8272_ADS + bool "Freescale MPC8272 ADS" select DEFAULT_UIMAGE select PQ2ADS select 8272 select 8260 select FSL_SOC help - This option enables support for the MPC8272 ADS board + This option enables support for the MPC8272 ADS board endchoice diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile index 534c35375b73..9b7c851ce6f1 100644 --- a/arch/powerpc/platforms/82xx/Makefile +++ b/arch/powerpc/platforms/82xx/Makefile @@ -1,4 +1,4 @@ # # Makefile for the PowerPC 82xx linux kernel. # -obj-$(CONFIG_MPC82xx_ADS) += mpc82xx_ads.o +obj-$(CONFIG_MPC8272_ADS) += mpc8272_ads.o diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c similarity index 100% rename from arch/powerpc/platforms/82xx/mpc82xx_ads.c rename to arch/powerpc/platforms/82xx/mpc8272_ads.c From 2d2294ae12827a97c9daa253f1ce99e7ae3195d7 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 26 Jul 2007 13:52:28 -0500 Subject: [PATCH 0444/2804] [POWERPC] mpc8272ads: Change references from 82xx_ADS to 8272_ADS. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/platforms/82xx/mpc8272_ads.c | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c index 5f538d5e7fdb..4de76dad31b2 100644 --- a/arch/powerpc/platforms/82xx/mpc8272_ads.c +++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c @@ -1,5 +1,5 @@ /* - * MPC82xx_ads setup and early boot code plus other random bits. + * MPC8272_ads setup and early boot code plus other random bits. * * Author: Vitaly Bordug * m82xx_restart fix by Wade Farnsworth @@ -63,7 +63,7 @@ static unsigned long pci_int_base; static struct irq_host *pci_pic_host; #endif -static void __init mpc82xx_ads_pic_init(void) +static void __init mpc8272_ads_pic_init(void) { struct device_node *np = of_find_compatible_node(NULL, "cpm-pic", "CPM2"); struct resource r; @@ -553,14 +553,14 @@ static void __init mpc82xx_add_bridge(struct device_node *np) /* * Setup the architecture */ -static void __init mpc82xx_ads_setup_arch(void) +static void __init mpc8272_ads_setup_arch(void) { #ifdef CONFIG_PCI struct device_node *np; #endif if (ppc_md.progress) - ppc_md.progress("mpc82xx_ads_setup_arch()", 0); + ppc_md.progress("mpc8272_ads_setup_arch()", 0); cpm2_reset(); /* Map I/O region to a 256MB BAT */ @@ -582,13 +582,13 @@ static void __init mpc82xx_ads_setup_arch(void) #endif if (ppc_md.progress) - ppc_md.progress("mpc82xx_ads_setup_arch(), finish", 0); + ppc_md.progress("mpc8272_ads_setup_arch(), finish", 0); } /* * Called very early, device-tree isn't unflattened */ -static int __init mpc82xx_ads_probe(void) +static int __init mpc8272_ads_probe(void) { /* We always match for now, eventually we should look at * the flat dev tree to ensure this is the board we are @@ -612,13 +612,13 @@ static void m82xx_restart(char *cmd) while (1) ; } -define_machine(mpc82xx_ads) +define_machine(mpc8272_ads) { - .name = "MPC82xx ADS", - .probe = mpc82xx_ads_probe, - .setup_arch = mpc82xx_ads_setup_arch, - .init_IRQ = mpc82xx_ads_pic_init, - .get_irq = cpm2_get_irq, + .name = "MPC8272 ADS", + .probe = mpc8272_ads_probe, + .setup_arch = mpc8272_ads_setup_arch, + .init_IRQ = mpc8272_ads_pic_init, + .get_irq = cpm2_get_irq, .calibrate_decr = generic_calibrate_decr, .restart = m82xx_restart, }; From 96fca1dea8f32e96668d55727d66416fdd67360b Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 14 Sep 2007 13:24:02 -0500 Subject: [PATCH 0445/2804] [POWERPC] Document local bus nodes in the device tree, and update cuboot-pq2. The localbus node is used to describe devices that are connected via a chip select or similar mechanism. The advantages over placing the devices under the root node are that it can be probed without probing other random things under the root, and that the description of which chip select a given device uses can be used to set up mappings if the firmware failed to do so in a useful manner. cuboot-pq2 is updated to match the binding; previously, it called itself chipselect rather than localbus, and used phandle linkage between the actual bus node and the control node (the current agreement is to simply use the fully-qualified address of the control registers, and ignore the overlap with the IMMR node). Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- Documentation/powerpc/booting-without-of.txt | 38 ++++++++++++++++++++ arch/powerpc/boot/cuboot-pq2.c | 29 +++++---------- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index a599f1a8a145..c36dcd2fbdc4 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -2017,6 +2017,44 @@ platforms are moved over to use the flattened-device-tree model. fsl,cpm-command = <2e600000>; }; + m) Chipselect/Local Bus + + Properties: + - name : Should be localbus + - #address-cells : Should be either two or three. The first cell is the + chipselect number, and the remaining cells are the + offset into the chipselect. + - #size-cells : Either one or two, depending on how large each chipselect + can be. + - ranges : Each range corresponds to a single chipselect, and cover + the entire access window as configured. + + Example: + localbus@f0010100 { + compatible = "fsl,mpc8272ads-localbus", + "fsl,mpc8272-localbus", + "fsl,pq2-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = ; + + ranges = <0 0 fe000000 02000000 + 1 0 f4500000 00008000>; + + flash@0,0 { + compatible = "jedec-flash"; + reg = <0 0 2000000>; + bank-width = <4>; + device-width = <1>; + }; + + board-control@1,0 { + reg = <1 0 20>; + compatible = "fsl,mpc8272ads-bcsr"; + }; + }; + + More devices will be defined as this spec matures. VII - Specifying interrupt information for devices diff --git a/arch/powerpc/boot/cuboot-pq2.c b/arch/powerpc/boot/cuboot-pq2.c index 470ffacb8373..61574f3272dd 100644 --- a/arch/powerpc/boot/cuboot-pq2.c +++ b/arch/powerpc/boot/cuboot-pq2.c @@ -44,22 +44,21 @@ struct pci_range pci_ranges_buf[MAX_PROP_LEN / sizeof(struct pci_range)]; * some don't set up the PCI PIC at all, so we assume the device tree is * sane and update the BRx registers appropriately. * - * For any node defined as compatible with fsl,pq2-chipselect, - * #address/#size must be 2/1 for chipselect bus, 1/1 for parent bus, - * and ranges must be for whole chip selects. + * For any node defined as compatible with fsl,pq2-localbus, + * #address/#size must be 2/1 for the localbus, and 1/1 for the parent bus. + * Ranges must be for whole chip selects. */ static void update_cs_ranges(void) { - u32 ctrl_ph; - void *ctrl_node, *bus_node, *parent_node; + void *bus_node, *parent_node; u32 *ctrl_addr; unsigned long ctrl_size; u32 naddr, nsize; int len; int i; - bus_node = finddevice("/chipselect"); - if (!bus_node || !dt_is_compatible(bus_node, "fsl,pq2-chipselect")) + bus_node = finddevice("/localbus"); + if (!bus_node || !dt_is_compatible(bus_node, "fsl,pq2-localbus")) return; dt_get_reg_format(bus_node, &naddr, &nsize); @@ -74,19 +73,7 @@ static void update_cs_ranges(void) if (naddr != 1 || nsize != 1) goto err; - len = getprop(bus_node, "fsl,ctrl", &ctrl_ph, 4); - if (len != 4) - goto err; - - ctrl_node = find_node_by_prop_value(NULL, "linux,phandle", - (char *)&ctrl_ph, 4); - if (!ctrl_node) - goto err; - - if (!dt_is_compatible(ctrl_node, "fsl,pq2-chipselect-ctrl")) - goto err; - - if (!dt_xlate_reg(ctrl_node, 0, (unsigned long *)&ctrl_addr, + if (!dt_xlate_reg(bus_node, 0, (unsigned long *)&ctrl_addr, &ctrl_size)) goto err; @@ -123,7 +110,7 @@ static void update_cs_ranges(void) return; err: - printf("Bad /chipselect or fsl,pq2-chipselect-ctrl node\r\n"); + printf("Bad /localbus node\r\n"); } /* Older u-boots don't set PCI up properly. Update the hardware to match From 20906ecea2004c0667c8b229ac6461d16ea6bde3 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 14 Sep 2007 14:38:16 -0500 Subject: [PATCH 0446/2804] [POWERPC] 8xx: mpc885ads cleanup It now uses the new CPM binding and the generic pin/clock functions, and has assorted fixes and cleanup. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc885ads.dts | 195 ++++---- arch/powerpc/configs/mpc885_ads_defconfig | 297 ++++++------ arch/powerpc/platforms/8xx/Kconfig | 1 + arch/powerpc/platforms/8xx/mpc885ads.h | 38 -- arch/powerpc/platforms/8xx/mpc885ads_setup.c | 468 +++++++------------ 5 files changed, 429 insertions(+), 570 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts index e9aa9d00da24..cbcd16f74c45 100644 --- a/arch/powerpc/boot/dts/mpc885ads.dts +++ b/arch/powerpc/boot/dts/mpc885ads.dts @@ -2,6 +2,7 @@ * MPC885 ADS Device Tree Source * * Copyright 2006 MontaVista Software, Inc. + * Copyright 2007 Freescale Semiconductor, 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 @@ -12,7 +13,7 @@ / { model = "MPC885ADS"; - compatible = "mpc8xx"; + compatible = "fsl,mpc885ads"; #address-cells = <1>; #size-cells = <1>; @@ -23,156 +24,188 @@ PowerPC,885@0 { device_type = "cpu"; reg = <0>; - d-cache-line-size = <20>; // 32 bytes - i-cache-line-size = <20>; // 32 bytes - d-cache-size = <2000>; // L1, 8K - i-cache-size = <2000>; // L1, 8K + d-cache-line-size = ; + i-cache-line-size = ; + d-cache-size = ; + i-cache-size = ; timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; interrupts = ; // decrementer interrupt - interrupt-parent = <&Mpc8xx_pic>; + interrupt-parent = <&PIC>; }; }; memory { device_type = "memory"; - reg = <00000000 800000>; + reg = <0 0>; }; - soc885@ff000000 { + localbus@ff000100 { + compatible = "fsl,mpc885-localbus", "fsl,pq1-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = ; + + ranges = < + 0 0 fe000000 00800000 + 1 0 ff080000 00008000 + 5 0 ff0a0000 00008000 + >; + + flash@0,0 { + compatible = "jedec-flash"; + reg = <0 0 800000>; + bank-width = <4>; + device-width = <1>; + }; + + board-control@1,0 { + reg = <1 0 20 5 300 4>; + compatible = "fsl,mpc885ads-bcsr"; + }; + }; + + soc@ff000000 { + compatible = "fsl,mpc885", "fsl,pq1-soc"; #address-cells = <1>; #size-cells = <1>; device_type = "soc"; - ranges = <0 ff000000 00100000>; - reg = ; + ranges = <0 ff000000 00004000>; bus-frequency = <0>; - mdio@e80 { - device_type = "mdio"; - compatible = "fs_enet"; - reg = ; + + // Temporary -- will go away once kernel uses ranges for get_immrbase(). + reg = ; + + mdio@e00 { + compatible = "fsl,mpc885-fec-mdio", "fsl,pq1-fec-mdio"; + reg = ; #address-cells = <1>; #size-cells = <0>; - Phy0: ethernet-phy@0 { + + PHY0: ethernet-phy@0 { reg = <0>; device_type = "ethernet-phy"; }; - Phy1: ethernet-phy@1 { + + PHY1: ethernet-phy@1 { reg = <1>; device_type = "ethernet-phy"; }; - Phy2: ethernet-phy@2 { + + PHY2: ethernet-phy@2 { reg = <2>; device_type = "ethernet-phy"; }; }; - fec@e00 { + ethernet@e00 { device_type = "network"; - compatible = "fs_enet"; - model = "FEC"; - device-id = <1>; + compatible = "fsl,mpc885-fec-enet", + "fsl,pq1-fec-enet"; reg = ; - mac-address = [ 00 00 0C 00 01 FD ]; + local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <3 1>; - interrupt-parent = <&Mpc8xx_pic>; - phy-handle = <&Phy1>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY0>; + linux,network-index = <0>; }; - fec@1e00 { + ethernet@1e00 { device_type = "network"; - compatible = "fs_enet"; - model = "FEC"; - device-id = <2>; + compatible = "fsl,mpc885-fec-enet", + "fsl,pq1-fec-enet"; reg = <1e00 188>; - mac-address = [ 00 00 0C 00 02 FD ]; + local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <7 1>; - interrupt-parent = <&Mpc8xx_pic>; - phy-handle = <&Phy2>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY1>; + linux,network-index = <1>; }; - Mpc8xx_pic: pic@ff000000 { + PIC: interrupt-controller@0 { interrupt-controller; - #address-cells = <0>; #interrupt-cells = <2>; reg = <0 24>; - device_type = "mpc8xx-pic"; - compatible = "CPM"; + compatible = "fsl,mpc885-pic", "fsl,pq1-pic"; }; - pcmcia@0080 { + pcmcia@80 { #address-cells = <3>; #interrupt-cells = <1>; #size-cells = <2>; compatible = "fsl,pq-pcmcia"; device_type = "pcmcia"; reg = <80 80>; - interrupt-parent = <&Mpc8xx_pic>; + interrupt-parent = <&PIC>; interrupts = ; }; - cpm@ff000000 { + cpm@9c0 { #address-cells = <1>; #size-cells = <1>; - device_type = "cpm"; - model = "CPM"; - ranges = <0 0 4000>; - reg = <860 f0>; + compatible = "fsl,mpc885-cpm", "fsl,cpm1"; command-proc = <9c0>; - brg-frequency = <0>; - interrupts = <0 2>; // cpm error interrupt - interrupt-parent = <&Cpm_pic>; + interrupts = <0>; // cpm error interrupt + interrupt-parent = <&CPM_PIC>; + reg = <9c0 40 2000 1c00>; + ranges; - Cpm_pic: pic@930 { + brg@9f0 { + compatible = "fsl,mpc885-brg", + "fsl,cpm1-brg", + "fsl,cpm-brg"; + reg = <9f0 10>; + }; + + CPM_PIC: interrupt-controller@930 { interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; + #interrupt-cells = <1>; interrupts = <5 2 0 2>; - interrupt-parent = <&Mpc8xx_pic>; + interrupt-parent = <&PIC>; reg = <930 20>; - device_type = "cpm-pic"; - compatible = "CPM"; + compatible = "fsl,mpc885-cpm-pic", + "fsl,cpm1-pic"; }; - smc@a80 { + serial@a80 { device_type = "serial"; - compatible = "cpm_uart"; - model = "SMC"; - device-id = <1>; + compatible = "fsl,mpc885-smc-uart", + "fsl,cpm1-smc-uart"; reg = ; - clock-setup = <00ffffff 0>; - rx-clock = <1>; - tx-clock = <1>; - current-speed = <0>; - interrupts = <4 3>; - interrupt-parent = <&Cpm_pic>; + interrupts = <4>; + interrupt-parent = <&CPM_PIC>; + fsl,cpm-brg = <1>; + fsl,cpm-command = <0090>; }; - smc@a90 { + serial@a90 { device_type = "serial"; - compatible = "cpm_uart"; - model = "SMC"; - device-id = <2>; - reg = ; - clock-setup = ; - rx-clock = <2>; - tx-clock = <2>; - current-speed = <0>; - interrupts = <3 3>; - interrupt-parent = <&Cpm_pic>; + compatible = "fsl,mpc885-smc-uart", + "fsl,cpm1-smc-uart"; + reg = ; + interrupts = <3>; + interrupt-parent = <&CPM_PIC>; + fsl,cpm-brg = <2>; + fsl,cpm-command = <00d0>; }; - scc@a40 { + ethernet@a40 { device_type = "network"; - compatible = "fs_enet"; - model = "SCC"; - device-id = <3>; - reg = ; - mac-address = [ 00 00 0C 00 03 FD ]; - interrupts = <1c 3>; - interrupt-parent = <&Cpm_pic>; - phy-handle = <&Phy2>; + compatible = "fsl,mpc885-scc-enet", + "fsl,cpm1-scc-enet"; + reg = ; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <1c>; + interrupt-parent = <&CPM_PIC>; + phy-handle = <&PHY2>; + fsl,cpm-command = <0080>; + linux,network-index = <2>; }; }; }; + + chosen { + linux,stdout-path = "/soc/cpm/serial@a80"; + }; }; diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig index d27e1f8c38fa..482d99db6870 100644 --- a/arch/powerpc/configs/mpc885_ads_defconfig +++ b/arch/powerpc/configs/mpc885_ads_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.23-rc4 -# Tue Aug 28 21:24:45 2007 +# Linux kernel version: 2.6.23-rc3 +# Mon Aug 27 15:23:16 2007 # # CONFIG_PPC64 is not set @@ -38,6 +38,7 @@ CONFIG_OF=y # CONFIG_PPC_UDBG_16550 is not set # CONFIG_GENERIC_TBSYNC is not set CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y # CONFIG_DEFAULT_UIMAGE is not set # CONFIG_PPC_DCR_NATIVE is not set # CONFIG_PPC_DCR_MMIO is not set @@ -69,24 +70,25 @@ CONFIG_SYSCTL=y CONFIG_EMBEDDED=y # CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set -# CONFIG_HOTPLUG is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y -# CONFIG_BUG is not set -CONFIG_ELF_CORE=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set -CONFIG_FUTEX=y +# CONFIG_FUTEX is not set CONFIG_ANON_INODES=y -# CONFIG_EPOLL is not set +CONFIG_EPOLL=y CONFIG_SIGNALFD=y CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y # CONFIG_VM_EVENT_COUNTERS is not set -CONFIG_SLAB=y -# CONFIG_SLUB is not set +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y # CONFIG_SLOB is not set -CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=1 # CONFIG_MODULES is not set @@ -100,14 +102,14 @@ CONFIG_BLOCK=y # IO Schedulers # CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y +# CONFIG_IOSCHED_AS is not set CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_AS=y -# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +CONFIG_DEFAULT_DEADLINE=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_DEFAULT_IOSCHED="deadline" # # Platform support @@ -120,6 +122,7 @@ CONFIG_CPM1=y # CONFIG_MPC8XXFADS is not set # CONFIG_MPC86XADS is not set CONFIG_MPC885ADS=y +# CONFIG_PPC_EP88XC is not set # # Freescale Ethernet driver platform-specific options @@ -137,6 +140,7 @@ CONFIG_MPC8xx_SECOND_ETH_FEC2=y # CONFIG_8xx_COPYBACK=y # CONFIG_8xx_CPU6 is not set +CONFIG_8xx_CPU15=y CONFIG_NO_UCODE_PATCH=y # CONFIG_USB_SOF_UCODE_PATCH is not set # CONFIG_I2C_SPI_UCODE_PATCH is not set @@ -153,23 +157,23 @@ CONFIG_NO_UCODE_PATCH=y # CONFIG_GENERIC_IOMAP is not set # CONFIG_CPU_FREQ is not set # CONFIG_CPM2 is not set -# CONFIG_FSL_ULI1575 is not set +CONFIG_PPC_CPM_NEW_BINDING=y # # Kernel options # # CONFIG_HIGHMEM is not set -# CONFIG_HZ_100 is not set +CONFIG_HZ_100=y # CONFIG_HZ_250 is not set # CONFIG_HZ_300 is not set -CONFIG_HZ_1000=y -CONFIG_HZ=1000 +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -CONFIG_MATH_EMULATION=y +# CONFIG_MATH_EMULATION is not set CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_POPULATES_NODE_MAP=y @@ -185,11 +189,12 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y -# CONFIG_PROC_DEVICETREE is not set +CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set # CONFIG_PM is not set # CONFIG_SECCOMP is not set -# CONFIG_WANT_DEVICE_TREE is not set +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="mpc885ads.dts" CONFIG_ISA_DMA_API=y # @@ -206,6 +211,7 @@ CONFIG_FSL_SOC=y # # PCCARD (PCMCIA/CardBus) support # +# CONFIG_PCCARD is not set # # Advanced setup @@ -234,10 +240,6 @@ CONFIG_NET=y CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y -CONFIG_XFRM=y -# CONFIG_XFRM_USER is not set -# CONFIG_XFRM_SUB_POLICY is not set -# CONFIG_XFRM_MIGRATE is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -257,9 +259,9 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_IPCOMP is not set # CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set -CONFIG_INET_XFRM_MODE_TRANSPORT=y -CONFIG_INET_XFRM_MODE_TUNNEL=y -CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set @@ -319,22 +321,91 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # CONFIG_CONNECTOR is not set -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_PARTITIONS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +# CONFIG_MTD_CFI_I1 is not set +# CONFIG_MTD_CFI_I2 is not set +CONFIG_MTD_CFI_I4=y +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set CONFIG_OF_DEVICE=y # CONFIG_PARPORT is not set -CONFIG_BLK_DEV=y -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set -CONFIG_MISC_DEVICES=y -# CONFIG_EEPROM_93CX6 is not set +# CONFIG_BLK_DEV is not set +# CONFIG_MISC_DEVICES is not set # CONFIG_IDE is not set # @@ -368,16 +439,15 @@ CONFIG_DAVICOM_PHY=y # CONFIG_SMSC_PHY is not set # CONFIG_BROADCOM_PHY is not set # CONFIG_ICPLUS_PHY is not set -CONFIG_FIXED_PHY=y -CONFIG_FIXED_MII_10_FDX=y -# CONFIG_FIXED_MII_100_FDX is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_FS_ENET=y -CONFIG_FS_ENET_HAS_SCC=y +# CONFIG_FS_ENET_HAS_SCC is not set CONFIG_FS_ENET_HAS_FEC=y -CONFIG_NETDEV_1000=y -CONFIG_NETDEV_10000=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set # # Wireless LAN @@ -397,55 +467,12 @@ CONFIG_NETDEV_10000=y # # Input device support # -CONFIG_INPUT=y -# CONFIG_INPUT_FF_MEMLESS is not set -# CONFIG_INPUT_POLLDEV is not set - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -CONFIG_KEYBOARD_ATKBD=y -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -# CONFIG_KEYBOARD_NEWTON is not set -# CONFIG_KEYBOARD_STOWAWAY is not set -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=y -CONFIG_MOUSE_PS2_ALPS=y -CONFIG_MOUSE_PS2_LOGIPS2PP=y -CONFIG_MOUSE_PS2_SYNAPTICS=y -CONFIG_MOUSE_PS2_LIFEBOOK=y -CONFIG_MOUSE_PS2_TRACKPOINT=y -# CONFIG_MOUSE_PS2_TOUCHKIT is not set -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TABLET is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set +# CONFIG_INPUT is not set # # Hardware I/O ports # -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set # @@ -493,20 +520,7 @@ CONFIG_GEN_RTC=y # CONFIG_SPI_MASTER is not set # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set -CONFIG_HWMON=y -# CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ABITUGURU is not set -# CONFIG_SENSORS_ABITUGURU3 is not set -# CONFIG_SENSORS_F71805F is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_PC87427 is not set -# CONFIG_SENSORS_SMSC47M1 is not set -# CONFIG_SENSORS_SMSC47B397 is not set -# CONFIG_SENSORS_VT1211 is not set -# CONFIG_SENSORS_W83627HF is not set -# CONFIG_SENSORS_W83627EHF is not set -# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON is not set # # Multifunction device drivers @@ -530,7 +544,7 @@ CONFIG_DAB=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y +# CONFIG_VIDEO_OUTPUT_CONTROL is not set # CONFIG_FB is not set # CONFIG_FB_IBM_GXT4500 is not set @@ -538,22 +552,7 @@ CONFIG_VIDEO_OUTPUT_CONTROL=y # Sound # # CONFIG_SOUND is not set -CONFIG_HID_SUPPORT=y -CONFIG_HID=y -# CONFIG_HID_DEBUG is not set -CONFIG_USB_SUPPORT=y -# CONFIG_USB_ARCH_HAS_HCD is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set +# CONFIG_USB_SUPPORT is not set # CONFIG_MMC is not set # CONFIG_NEW_LEDS is not set # CONFIG_EDAC is not set @@ -580,19 +579,9 @@ CONFIG_USB_SUPPORT=y # # File systems # -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -# CONFIG_EXT2_FS_POSIX_ACL is not set -# CONFIG_EXT2_FS_SECURITY is not set -# CONFIG_EXT2_FS_XIP is not set -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_XATTR=y -# CONFIG_EXT3_FS_POSIX_ACL is not set -# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set # CONFIG_EXT4DEV_FS is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set @@ -601,10 +590,9 @@ CONFIG_FS_MBCACHE=y # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y +# CONFIG_INOTIFY is not set # CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y +# CONFIG_DNOTIFY is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set # CONFIG_FUSE_FS is not set @@ -645,6 +633,7 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -711,15 +700,13 @@ CONFIG_MSDOS_PARTITION=y # # Library routines # -CONFIG_BITREVERSE=y -CONFIG_CRC_CCITT=y +# CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set # CONFIG_CRC_ITU_T is not set -CONFIG_CRC32=y +# CONFIG_CRC32 is not set # CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y -CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y @@ -734,11 +721,33 @@ CONFIG_HAS_DMA=y # # CONFIG_PRINTK_TIME is not set CONFIG_ENABLE_MUST_CHECK=y -# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set -# CONFIG_DEBUG_KERNEL is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set # CONFIG_PPC_EARLY_DEBUG is not set # diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 322b155f24ec..0d4ff0ae0746 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -26,6 +26,7 @@ config MPC86XADS config MPC885ADS bool "MPC885ADS" select CPM1 + select PPC_CPM_NEW_BINDING help Freescale Semiconductor MPC885 Application Development System (ADS). Also known as DUET. diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h index a21e528f26c6..a5076668bad6 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads.h +++ b/arch/powerpc/platforms/8xx/mpc885ads.h @@ -17,25 +17,10 @@ #include -/* U-Boot maps BCSR to 0xff080000 */ -#define BCSR_ADDR ((uint)0xff080000) -#define BCSR_SIZE ((uint)32) -#define BCSR0 ((uint)(BCSR_ADDR + 0x00)) -#define BCSR1 ((uint)(BCSR_ADDR + 0x04)) -#define BCSR2 ((uint)(BCSR_ADDR + 0x08)) -#define BCSR3 ((uint)(BCSR_ADDR + 0x0c)) -#define BCSR4 ((uint)(BCSR_ADDR + 0x10)) - -#define CFG_PHYDEV_ADDR ((uint)0xff0a0000) -#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) - #define MPC8xx_CPM_OFFSET (0x9c0) #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver -#define PCMCIA_MEM_ADDR ((uint)0xff020000) -#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) - /* Bits of interest in the BCSRs. */ #define BCSR1_ETHEN ((uint)0x20000000) @@ -64,28 +49,5 @@ #define BCSR5_MII1_EN 0x02 #define BCSR5_MII1_RST 0x01 -/* Interrupt level assignments */ -#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */ -#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */ -#define SIU_INT_FEC2 SIU_LEVEL3 /* FEC2 interrupt */ -#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */ - -/* We don't use the 8259 */ -#define NR_8259_INTS 0 - -/* CPM Ethernet through SCC3 */ -#define PA_ENET_RXD ((ushort)0x0040) -#define PA_ENET_TXD ((ushort)0x0080) -#define PE_ENET_TCLK ((uint)0x00004000) -#define PE_ENET_RCLK ((uint)0x00008000) -#define PE_ENET_TENA ((uint)0x00000010) -#define PC_ENET_CLSN ((ushort)0x0400) -#define PC_ENET_RENA ((ushort)0x0800) - -/* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to - * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */ -#define SICR_ENET_MASK ((uint)0x00ff0000) -#define SICR_ENET_CLKRT ((uint)0x002c0000) - #endif /* __ASM_MPC885ADS_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index bad08683f7ae..2cf1b6a75173 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -1,11 +1,13 @@ -/*arch/powerpc/platforms/8xx/mpc885ads_setup.c - * +/* * Platform setup for the Freescale mpc885ads board * * Vitaly Bordug * * Copyright 2005 MontaVista Software Inc. * + * Heavily modified by Scott Wood + * Copyright 2007 Freescale 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 warranty of any * kind, whether express or implied. @@ -18,12 +20,12 @@ #include #include #include -#include #include #include #include #include +#include #include #include @@ -36,34 +38,24 @@ #include #include #include -#include +#include #include -static void init_smc1_uart_ioports(struct fs_uart_platform_info *fpi); -static void init_smc2_uart_ioports(struct fs_uart_platform_info *fpi); -static void init_scc3_ioports(struct fs_platform_info *ptr); +static u32 __iomem *bcsr, *bcsr5; #ifdef CONFIG_PCMCIA_M8XX static void pcmcia_hw_setup(int slot, int enable) { - unsigned *bcsr_io; - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); if (enable) - clrbits32(bcsr_io, BCSR1_PCCEN); + clrbits32(&bcsr[1], BCSR1_PCCEN); else - setbits32(bcsr_io, BCSR1_PCCEN); - - iounmap(bcsr_io); + setbits32(&bcsr[1], BCSR1_PCCEN); } static int pcmcia_set_voltage(int slot, int vcc, int vpp) { u32 reg = 0; - unsigned *bcsr_io; - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); switch (vcc) { case 0: @@ -98,334 +90,196 @@ static int pcmcia_set_voltage(int slot, int vcc, int vpp) } /* first, turn off all power */ - clrbits32(bcsr_io, 0x00610000); + clrbits32(&bcsr[1], 0x00610000); /* enable new powersettings */ - setbits32(bcsr_io, reg); + setbits32(&bcsr[1], reg); - iounmap(bcsr_io); return 0; } #endif -void __init mpc885ads_board_setup(void) -{ - cpm8xx_t *cp; - unsigned int *bcsr_io; - u8 tmpval8; +struct cpm_pin { + int port, pin, flags; +}; -#ifdef CONFIG_FS_ENET - iop8xx_t *io_port; +static struct cpm_pin mpc885ads_pins[] = { + /* SMC1 */ + {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */ + {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ + + /* SMC2 */ +#ifndef CONFIG_MPC8xx_SECOND_ETH_FEC2 + {CPM_PORTE, 21, CPM_PIN_INPUT}, /* RX */ + {CPM_PORTE, 20, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ #endif - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - cp = (cpm8xx_t *) immr_map(im_cpm); + /* SCC3 */ + {CPM_PORTA, 9, CPM_PIN_INPUT}, /* RX */ + {CPM_PORTA, 8, CPM_PIN_INPUT}, /* TX */ + {CPM_PORTC, 4, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* RENA */ + {CPM_PORTC, 5, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CLSN */ + {CPM_PORTE, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TENA */ + {CPM_PORTE, 17, CPM_PIN_INPUT}, /* CLK5 */ + {CPM_PORTE, 16, CPM_PIN_INPUT}, /* CLK6 */ - if (bcsr_io == NULL) { + /* MII1 */ + {CPM_PORTA, 0, CPM_PIN_INPUT}, + {CPM_PORTA, 1, CPM_PIN_INPUT}, + {CPM_PORTA, 2, CPM_PIN_INPUT}, + {CPM_PORTA, 3, CPM_PIN_INPUT}, + {CPM_PORTA, 4, CPM_PIN_OUTPUT}, + {CPM_PORTA, 10, CPM_PIN_OUTPUT}, + {CPM_PORTA, 11, CPM_PIN_OUTPUT}, + {CPM_PORTB, 19, CPM_PIN_INPUT}, + {CPM_PORTB, 31, CPM_PIN_INPUT}, + {CPM_PORTC, 12, CPM_PIN_INPUT}, + {CPM_PORTC, 13, CPM_PIN_INPUT}, + {CPM_PORTE, 30, CPM_PIN_OUTPUT}, + {CPM_PORTE, 31, CPM_PIN_OUTPUT}, + + /* MII2 */ +#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2 + {CPM_PORTE, 14, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 15, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 16, CPM_PIN_OUTPUT}, + {CPM_PORTE, 17, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 18, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 19, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 20, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 21, CPM_PIN_OUTPUT}, + {CPM_PORTE, 22, CPM_PIN_OUTPUT}, + {CPM_PORTE, 23, CPM_PIN_OUTPUT}, + {CPM_PORTE, 24, CPM_PIN_OUTPUT}, + {CPM_PORTE, 25, CPM_PIN_OUTPUT}, + {CPM_PORTE, 26, CPM_PIN_OUTPUT}, + {CPM_PORTE, 27, CPM_PIN_OUTPUT}, + {CPM_PORTE, 28, CPM_PIN_OUTPUT}, + {CPM_PORTE, 29, CPM_PIN_OUTPUT}, +#endif +}; + +static void __init init_ioports(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mpc885ads_pins); i++) { + struct cpm_pin *pin = &mpc885ads_pins[i]; + cpm1_set_pin(pin->port, pin->pin, pin->flags); + } + + cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX); + cpm1_clk_setup(CPM_CLK_SMC2, CPM_BRG2, CPM_CLK_RTX); + cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_TX); + cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK6, CPM_CLK_RX); + + /* Set FEC1 and FEC2 to MII mode */ + clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180); +} + +static void __init mpc885ads_setup_arch(void) +{ + struct device_node *np; + + cpm_reset(); + init_ioports(); + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc885ads-bcsr"); + if (!np) { + printk(KERN_CRIT "Could not find fsl,mpc885ads-bcsr node\n"); + return; + } + + bcsr = of_iomap(np, 0); + bcsr5 = of_iomap(np, 1); + of_node_put(np); + + if (!bcsr || !bcsr5) { printk(KERN_CRIT "Could not remap BCSR\n"); return; } -#ifdef CONFIG_SERIAL_CPM_SMC1 - clrbits32(bcsr_io, BCSR1_RS232EN_1); - clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */ - tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX); - out_8(&(cp->cp_smc[0].smc_smcm), tmpval8); - clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); /* brg1 */ + + clrbits32(&bcsr[1], BCSR1_RS232EN_1); +#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2 + setbits32(&bcsr[1], BCSR1_RS232EN_2); #else - setbits32(bcsr_io, BCSR1_RS232EN_1); - out_be16(&cp->cp_smc[0].smc_smcmr, 0); - out_8(&cp->cp_smc[0].smc_smce, 0); + clrbits32(&bcsr[1], BCSR1_RS232EN_2); #endif -#ifdef CONFIG_SERIAL_CPM_SMC2 - clrbits32(bcsr_io, BCSR1_RS232EN_2); - clrbits32(&cp->cp_simode, 0xe0000000 >> 1); - setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */ - tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX); - out_8(&(cp->cp_smc[1].smc_smcm), tmpval8); - clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN); + clrbits32(bcsr5, BCSR5_MII1_EN); + setbits32(bcsr5, BCSR5_MII1_RST); + udelay(1000); + clrbits32(bcsr5, BCSR5_MII1_RST); - init_smc2_uart_ioports(0); +#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2 + clrbits32(bcsr5, BCSR5_MII2_EN); + setbits32(bcsr5, BCSR5_MII2_RST); + udelay(1000); + clrbits32(bcsr5, BCSR5_MII2_RST); #else - setbits32(bcsr_io, BCSR1_RS232EN_2); - out_be16(&cp->cp_smc[1].smc_smcmr, 0); - out_8(&cp->cp_smc[1].smc_smce, 0); + setbits32(bcsr5, BCSR5_MII2_EN); #endif - immr_unmap(cp); - iounmap(bcsr_io); -#ifdef CONFIG_FS_ENET - /* use MDC for MII (common) */ - io_port = (iop8xx_t *) immr_map(im_ioport); - setbits16(&io_port->iop_pdpar, 0x0080); - clrbits16(&io_port->iop_pddir, 0x0080); +#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3 + clrbits32(&bcsr[4], BCSR4_ETH10_RST); + udelay(1000); + setbits32(&bcsr[4], BCSR4_ETH10_RST); - bcsr_io = ioremap(BCSR5, sizeof(unsigned long)); - clrbits32(bcsr_io, BCSR5_MII1_EN); - clrbits32(bcsr_io, BCSR5_MII1_RST); -#ifndef CONFIG_FC_ENET_HAS_SCC - clrbits32(bcsr_io, BCSR5_MII2_EN); - clrbits32(bcsr_io, BCSR5_MII2_RST); + setbits32(&bcsr[1], BCSR1_ETHEN); + np = of_find_node_by_path("/soc@ff000000/cpm@9c0/serial@a80"); +#else + np = of_find_node_by_path("/soc@ff000000/cpm@9c0/ethernet@a40"); #endif - iounmap(bcsr_io); - immr_unmap(io_port); -#endif + /* The SCC3 enet registers overlap the SMC1 registers, so + * one of the two must be removed from the device tree. + */ + + if (np) { + of_detach_node(np); + of_node_put(np); + } #ifdef CONFIG_PCMCIA_M8XX - /*Set up board specific hook-ups */ + /* Set up board specific hook-ups.*/ m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup; m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage; #endif } -static void init_fec1_ioports(struct fs_platform_info *ptr) +static int __init mpc885ads_probe(void) { - cpm8xx_t *cp = (cpm8xx_t *) immr_map(im_cpm); - iop8xx_t *io_port = (iop8xx_t *) immr_map(im_ioport); - - /* configure FEC1 pins */ - setbits16(&io_port->iop_papar, 0xf830); - setbits16(&io_port->iop_padir, 0x0830); - clrbits16(&io_port->iop_padir, 0xf000); - - setbits32(&cp->cp_pbpar, 0x00001001); - clrbits32(&cp->cp_pbdir, 0x00001001); - - setbits16(&io_port->iop_pcpar, 0x000c); - clrbits16(&io_port->iop_pcdir, 0x000c); - - setbits32(&cp->cp_pepar, 0x00000003); - setbits32(&cp->cp_pedir, 0x00000003); - clrbits32(&cp->cp_peso, 0x00000003); - clrbits32(&cp->cp_cptr, 0x00000100); - - immr_unmap(io_port); - immr_unmap(cp); + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "fsl,mpc885ads"); } -static void init_fec2_ioports(struct fs_platform_info *ptr) +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) { - cpm8xx_t *cp = (cpm8xx_t *) immr_map(im_cpm); - iop8xx_t *io_port = (iop8xx_t *) immr_map(im_ioport); - - /* configure FEC2 pins */ - setbits32(&cp->cp_pepar, 0x0003fffc); - setbits32(&cp->cp_pedir, 0x0003fffc); - clrbits32(&cp->cp_peso, 0x000087fc); - setbits32(&cp->cp_peso, 0x00037800); - clrbits32(&cp->cp_cptr, 0x00000080); - - immr_unmap(io_port); - immr_unmap(cp); -} - -void init_fec_ioports(struct fs_platform_info *fpi) -{ - int fec_no = fs_get_fec_index(fpi->fs_no); - - switch (fec_no) { - case 0: - init_fec1_ioports(fpi); - break; - case 1: - init_fec2_ioports(fpi); - break; - default: - printk(KERN_ERR "init_fec_ioports: invalid FEC number\n"); - return; - } -} - -static void init_scc3_ioports(struct fs_platform_info *fpi) -{ - unsigned *bcsr_io; - iop8xx_t *io_port; - cpm8xx_t *cp; - - bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE); - io_port = (iop8xx_t *) immr_map(im_ioport); - cp = (cpm8xx_t *) immr_map(im_cpm); - - if (bcsr_io == NULL) { - printk(KERN_CRIT "Could not remap BCSR\n"); - return; - } - - /* Enable the PHY. - */ - clrbits32(bcsr_io + 4, BCSR4_ETH10_RST); - udelay(1000); - setbits32(bcsr_io + 4, BCSR4_ETH10_RST); - /* Configure port A pins for Txd and Rxd. - */ - setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD); - clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD); - - /* Configure port C pins to enable CLSN and RENA. - */ - clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA); - clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA); - setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA); - - /* Configure port E for TCLK and RCLK. - */ - setbits32(&cp->cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK); - clrbits32(&cp->cp_pepar, PE_ENET_TENA); - clrbits32(&cp->cp_pedir, PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA); - clrbits32(&cp->cp_peso, PE_ENET_TCLK | PE_ENET_RCLK); - setbits32(&cp->cp_peso, PE_ENET_TENA); - - /* Configure Serial Interface clock routing. - * First, clear all SCC bits to zero, then set the ones we want. - */ - clrbits32(&cp->cp_sicr, SICR_ENET_MASK); - setbits32(&cp->cp_sicr, SICR_ENET_CLKRT); - - /* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used. - */ - clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); - /* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode - * by H/W setting after reset. SCC ethernet controller support only half duplex. - * This discrepancy of modes causes a lot of carrier lost errors. - */ - - /* In the original SCC enet driver the following code is placed at - the end of the initialization */ - setbits32(&cp->cp_pepar, PE_ENET_TENA); - clrbits32(&cp->cp_pedir, PE_ENET_TENA); - setbits32(&cp->cp_peso, PE_ENET_TENA); - - setbits32(bcsr_io + 4, BCSR1_ETHEN); - iounmap(bcsr_io); - immr_unmap(io_port); - immr_unmap(cp); -} - -void init_scc_ioports(struct fs_platform_info *fpi) -{ - int scc_no = fs_get_scc_index(fpi->fs_no); - - switch (scc_no) { - case 2: - init_scc3_ioports(fpi); - break; - default: - printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); - return; - } -} - -static void init_smc1_uart_ioports(struct fs_uart_platform_info *ptr) -{ - unsigned *bcsr_io; - cpm8xx_t *cp; - - cp = (cpm8xx_t *) immr_map(im_cpm); - setbits32(&cp->cp_pepar, 0x000000c0); - clrbits32(&cp->cp_pedir, 0x000000c0); - clrbits32(&cp->cp_peso, 0x00000040); - setbits32(&cp->cp_peso, 0x00000080); - immr_unmap(cp); - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - - if (bcsr_io == NULL) { - printk(KERN_CRIT "Could not remap BCSR1\n"); - return; - } - clrbits32(bcsr_io, BCSR1_RS232EN_1); - iounmap(bcsr_io); -} - -static void init_smc2_uart_ioports(struct fs_uart_platform_info *fpi) -{ - unsigned *bcsr_io; - cpm8xx_t *cp; - - cp = (cpm8xx_t *) immr_map(im_cpm); - setbits32(&cp->cp_pepar, 0x00000c00); - clrbits32(&cp->cp_pedir, 0x00000c00); - clrbits32(&cp->cp_peso, 0x00000400); - setbits32(&cp->cp_peso, 0x00000800); - immr_unmap(cp); - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - - if (bcsr_io == NULL) { - printk(KERN_CRIT "Could not remap BCSR1\n"); - return; - } - clrbits32(bcsr_io, BCSR1_RS232EN_2); - iounmap(bcsr_io); -} - -void init_smc_ioports(struct fs_uart_platform_info *data) -{ - int smc_no = fs_uart_id_fsid2smc(data->fs_no); - - switch (smc_no) { - case 0: - init_smc1_uart_ioports(data); - data->brg = data->clk_rx; - break; - case 1: - init_smc2_uart_ioports(data); - data->brg = data->clk_rx; - break; - default: - printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); - return; - } -} - -int platform_device_skip(const char *model, int id) -{ -#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3 - const char *dev = "FEC"; - int n = 2; -#else - const char *dev = "SCC"; - int n = 3; -#endif - - if (!strcmp(model, dev) && n == id) - return 1; + /* Publish the QE devices */ + if (machine_is(mpc885_ads)) + of_platform_bus_probe(NULL, of_bus_ids, NULL); return 0; } +device_initcall(declare_of_platform_devices); -static void __init mpc885ads_setup_arch(void) -{ - cpm_reset(); - - mpc885ads_board_setup(); - - ROOT_DEV = Root_NFS; -} - -static int __init mpc885ads_probe(void) -{ - char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), - "model", NULL); - if (model == NULL) - return 0; - if (strcmp(model, "MPC885ADS")) - return 0; - - return 1; -} - -define_machine(mpc885_ads) -{ - .name = "MPC885 ADS", - .probe = mpc885ads_probe, - .setup_arch = mpc885ads_setup_arch, - .init_IRQ = m8xx_pic_init, - .get_irq = mpc8xx_get_irq, - .restart = mpc8xx_restart, - .calibrate_decr = mpc8xx_calibrate_decr, - .set_rtc_time = mpc8xx_set_rtc_time, - .get_rtc_time = mpc8xx_get_rtc_time, +define_machine(mpc885_ads) { + .name = "Freescale MPC885 ADS", + .probe = mpc885ads_probe, + .setup_arch = mpc885ads_setup_arch, + .init_IRQ = m8xx_pic_init, + .get_irq = mpc8xx_get_irq, + .restart = mpc8xx_restart, + .calibrate_decr = mpc8xx_calibrate_decr, + .set_rtc_time = mpc8xx_set_rtc_time, + .get_rtc_time = mpc8xx_get_rtc_time, + .progress = udbg_progress, }; From 11c146cc19df337f4af42dade9e4fca33c5a54ee Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 14 Sep 2007 14:58:25 -0500 Subject: [PATCH 0447/2804] [POWERPC] 8xx/wrapper: Embedded Planet EP88xC support This board is also resold by Freescale under the names "QUICCStart MPC885 Evaluation System" and "CWH-PPC-885XN-VE". Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/boot/Makefile | 4 +- arch/powerpc/boot/dts/ep88xc.dts | 203 +++++++ arch/powerpc/boot/ep88xc.c | 54 ++ arch/powerpc/boot/fixed-head.S | 4 + arch/powerpc/boot/wrapper | 20 +- arch/powerpc/configs/ep88xc_defconfig | 751 ++++++++++++++++++++++++++ arch/powerpc/platforms/8xx/Kconfig | 10 + arch/powerpc/platforms/8xx/Makefile | 1 + arch/powerpc/platforms/8xx/ep88xc.c | 176 ++++++ 9 files changed, 1216 insertions(+), 7 deletions(-) create mode 100644 arch/powerpc/boot/dts/ep88xc.dts create mode 100644 arch/powerpc/boot/ep88xc.c create mode 100644 arch/powerpc/boot/fixed-head.S create mode 100644 arch/powerpc/configs/ep88xc_defconfig create mode 100644 arch/powerpc/platforms/8xx/ep88xc.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 6d1935a06ee1..a90baa3aff23 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -51,7 +51,8 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ - cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c + cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \ + fixed-head.S ep88xc.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -144,6 +145,7 @@ image-$(CONFIG_DEFAULT_UIMAGE) += uImage ifneq ($(CONFIG_DEVICE_TREE),"") image-$(CONFIG_PPC_8xx) += cuImage.8xx +image-$(CONFIG_PPC_EP88XC) += zImage.ep88xc image-$(CONFIG_8260) += cuImage.pq2 image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx image-$(CONFIG_PPC_83xx) += cuImage.83xx diff --git a/arch/powerpc/boot/dts/ep88xc.dts b/arch/powerpc/boot/dts/ep88xc.dts new file mode 100644 index 000000000000..0406fc50b2af --- /dev/null +++ b/arch/powerpc/boot/dts/ep88xc.dts @@ -0,0 +1,203 @@ +/* + * EP88xC Device Tree Source + * + * Copyright 2006 MontaVista Software, Inc. + * Copyright 2007 Freescale Semiconductor, 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. + */ + + +/ { + model = "EP88xC"; + compatible = "fsl,ep88xc"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,885@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = ; + i-cache-line-size = ; + d-cache-size = ; + i-cache-size = ; + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + interrupts = ; // decrementer interrupt + interrupt-parent = <&PIC>; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0>; + }; + + localbus@fa200100 { + compatible = "fsl,mpc885-localbus", "fsl,pq1-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = ; + + ranges = < + 0 0 fc000000 04000000 + 3 0 fa000000 01000000 + >; + + flash@0,2000000 { + compatible = "cfi-flash"; + reg = <0 2000000 2000000>; + bank-width = <4>; + device-width = <2>; + }; + + board-control@3,400000 { + reg = <3 400000 10>; + compatible = "fsl,ep88xc-bcsr"; + }; + }; + + soc@fa200000 { + compatible = "fsl,mpc885", "fsl,pq1-soc"; + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + ranges = <0 fa200000 00004000>; + bus-frequency = <0>; + + // Temporary -- will go away once kernel uses ranges for get_immrbase(). + reg = ; + + mdio@e00 { + compatible = "fsl,mpc885-fec-mdio", "fsl,pq1-fec-mdio"; + reg = ; + #address-cells = <1>; + #size-cells = <0>; + + PHY0: ethernet-phy@0 { + reg = <0>; + device_type = "ethernet-phy"; + }; + + PHY1: ethernet-phy@1 { + reg = <1>; + device_type = "ethernet-phy"; + }; + }; + + ethernet@e00 { + device_type = "network"; + compatible = "fsl,mpc885-fec-enet", + "fsl,pq1-fec-enet"; + reg = ; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <3 1>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY0>; + linux,network-index = <0>; + }; + + ethernet@1e00 { + device_type = "network"; + compatible = "fsl,mpc885-fec-enet", + "fsl,pq1-fec-enet"; + reg = <1e00 188>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <7 1>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY1>; + linux,network-index = <1>; + }; + + PIC: interrupt-controller@0 { + interrupt-controller; + #interrupt-cells = <2>; + reg = <0 24>; + compatible = "fsl,mpc885-pic", "fsl,pq1-pic"; + }; + + pcmcia@80 { + #address-cells = <3>; + #interrupt-cells = <1>; + #size-cells = <2>; + compatible = "fsl,pq-pcmcia"; + device_type = "pcmcia"; + reg = <80 80>; + interrupt-parent = <&PIC>; + interrupts = ; + }; + + cpm@9c0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc885-cpm", "fsl,cpm1"; + command-proc = <9c0>; + interrupts = <0>; // cpm error interrupt + interrupt-parent = <&CPM_PIC>; + reg = <9c0 40 2000 1c00>; + ranges; + + brg@9f0 { + compatible = "fsl,mpc885-brg", + "fsl,cpm1-brg", + "fsl,cpm-brg"; + reg = <9f0 10>; + }; + + CPM_PIC: interrupt-controller@930 { + interrupt-controller; + #interrupt-cells = <1>; + interrupts = <5 2 0 2>; + interrupt-parent = <&PIC>; + reg = <930 20>; + compatible = "fsl,mpc885-cpm-pic", + "fsl,cpm1-pic"; + }; + + // MON-1 + serial@a80 { + device_type = "serial"; + compatible = "fsl,mpc885-smc-uart", + "fsl,cpm1-smc-uart"; + reg = ; + interrupts = <4>; + interrupt-parent = <&CPM_PIC>; + fsl,cpm-brg = <1>; + fsl,cpm-command = <0090>; + linux,planetcore-label = "SMC1"; + }; + + // SER-1 + serial@a20 { + device_type = "serial"; + compatible = "fsl,mpc885-scc-uart", + "fsl,cpm1-scc-uart"; + reg = ; + interrupts = <1d>; + interrupt-parent = <&CPM_PIC>; + fsl,cpm-brg = <2>; + fsl,cpm-command = <0040>; + linux,planetcore-label = "SCC2"; + }; + + usb@a00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc885-usb", + "fsl,cpm1-usb"; + reg = ; + interrupt-parent = <&CPM_PIC>; + interrupts = <1e>; + fsl,cpm-command = <0000>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/ep88xc.c b/arch/powerpc/boot/ep88xc.c new file mode 100644 index 000000000000..6b87cdce3fe7 --- /dev/null +++ b/arch/powerpc/boot/ep88xc.c @@ -0,0 +1,54 @@ +/* + * Embedded Planet EP88xC with PlanetCore firmware + * + * Author: Scott Wood + * + * Copyright (c) 2007 Freescale Semiconductor, 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 "ops.h" +#include "stdio.h" +#include "planetcore.h" +#include "mpc8xx.h" + +static char *table; +static u64 mem_size; + +static void platform_fixups(void) +{ + u64 val; + + dt_fixup_memory(0, mem_size); + planetcore_set_mac_addrs(table); + + if (!planetcore_get_decimal(table, PLANETCORE_KEY_CRYSTAL_HZ, &val)) { + printf("No PlanetCore crystal frequency key.\r\n"); + return; + } + + mpc885_fixup_clocks(val); +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + table = (char *)r3; + planetcore_prepare_table(table); + + if (!planetcore_get_decimal(table, PLANETCORE_KEY_MB_RAM, &mem_size)) + return; + + mem_size *= 1024 * 1024; + simple_alloc_init(_end, mem_size - (unsigned long)_end, 32, 64); + + ft_init(_dtb_start, _dtb_end - _dtb_start, 32); + + planetcore_set_stdout_path(table); + + serial_console_init(); + platform_ops.fixups = platform_fixups; +} diff --git a/arch/powerpc/boot/fixed-head.S b/arch/powerpc/boot/fixed-head.S new file mode 100644 index 000000000000..8e14cd9e1a54 --- /dev/null +++ b/arch/powerpc/boot/fixed-head.S @@ -0,0 +1,4 @@ + .text + .global _zimage_start +_zimage_start: + b _zimage_start_lib diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 65f685479175..39b27e5ef6c1 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -29,6 +29,7 @@ initrd= dtb= dts= cacheit= +binary= gzip=.gz # cross-compilation prefix @@ -142,17 +143,23 @@ miboot|uboot) isection=initrd ;; cuboot*) + binary=y gzip= ;; ps3) platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o" lds=$object/zImage.ps3.lds + binary=y gzip= ext=bin objflags="-O binary --set-section-flags=.bss=contents,alloc,load,data" ksection=.kernel:vmlinux.bin isection=.kernel:initrd ;; +ep88xc) + platformo="$object/fixed-head.o $object/$platform.o" + binary=y + ;; esac vmz="$tmpdir/`basename \"$kernel\"`.$ext" @@ -224,6 +231,11 @@ fi base=0x`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1` entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | cut -d' ' -f3` +if [ -n "$binary" ]; then + mv "$ofile" "$ofile".elf + ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin +fi + # post-processing needed for some platforms case "$platform" in pseries|chrp) @@ -234,8 +246,6 @@ coff) $object/hack-coff "$ofile" ;; cuboot*) - mv "$ofile" "$ofile".elf - ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin gzip -f -9 "$ofile".bin mkimage -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \ $uboot_version -d "$ofile".bin.gz "$ofile" @@ -259,11 +269,11 @@ ps3) # then copied to offset 0x100. At runtime the bootwrapper program # copies the 0x100 bytes at __system_reset_kernel to addr 0x100. - system_reset_overlay=0x`${CROSS}nm "$ofile" \ + system_reset_overlay=0x`${CROSS}nm "$ofile".elf \ | grep ' __system_reset_overlay$' \ | cut -d' ' -f1` system_reset_overlay=`printf "%d" $system_reset_overlay` - system_reset_kernel=0x`${CROSS}nm "$ofile" \ + system_reset_kernel=0x`${CROSS}nm "$ofile".elf \ | grep ' __system_reset_kernel$' \ | cut -d' ' -f1` system_reset_kernel=`printf "%d" $system_reset_kernel` @@ -272,8 +282,6 @@ ps3) rm -f "$object/otheros.bld" - ${CROSS}objcopy -O binary "$ofile" "$ofile.bin" - msg=$(dd if="$ofile.bin" of="$ofile.bin" conv=notrunc \ skip=$overlay_dest seek=$system_reset_kernel \ count=$overlay_size bs=1 2>&1) diff --git a/arch/powerpc/configs/ep88xc_defconfig b/arch/powerpc/configs/ep88xc_defconfig new file mode 100644 index 000000000000..d8ee3c0dcadf --- /dev/null +++ b/arch/powerpc/configs/ep88xc_defconfig @@ -0,0 +1,751 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc6 +# Fri Sep 14 14:59:56 2007 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +# CONFIG_PPC_85xx is not set +CONFIG_PPC_8xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_8xx=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +# CONFIG_BASE_FULL is not set +# CONFIG_FUTEX is not set +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=1 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" + +# +# Platform support +# +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +CONFIG_CPM1=y +# CONFIG_MPC8XXFADS is not set +# CONFIG_MPC86XADS is not set +# CONFIG_MPC885ADS is not set +CONFIG_PPC_EP88XC=y + +# +# MPC8xx CPM Options +# + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set +CONFIG_8xx_CPU15=y +CONFIG_NO_UCODE_PATCH=y +# CONFIG_USB_SOF_UCODE_PATCH is not set +# CONFIG_I2C_SPI_UCODE_PATCH is not set +# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set +# CONFIG_PQ2ADS is not set +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPM2 is not set +CONFIG_PPC_CPM_NEW_BINDING=y +# CONFIG_FSL_ULI1575 is not set +CONFIG_CPM=y + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SUSPEND_UP_POSSIBLE=y +CONFIG_HIBERNATION_UP_POSSIBLE=y +# CONFIG_SECCOMP is not set +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="ep88xc.dts" +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_FSL_SOC=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCI_QSPAN is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xfd000000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x00400000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_PARTITIONS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_CFI_FLAGADM is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +# CONFIG_BLK_DEV is not set +# CONFIG_MISC_DEVICES is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +CONFIG_LXT_PHY=y +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_FS_ENET=y +# CONFIG_FS_ENET_HAS_SCC is not set +CONFIG_FS_ENET_HAS_FEC=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_CPM=y +CONFIG_SERIAL_CPM_CONSOLE=y +# CONFIG_SERIAL_CPM_SCC1 is not set +# CONFIG_SERIAL_CPM_SCC2 is not set +# CONFIG_SERIAL_CPM_SCC3 is not set +# CONFIG_SERIAL_CPM_SCC4 is not set +CONFIG_SERIAL_CPM_SMC1=y +CONFIG_SERIAL_CPM_SMC2=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC32 is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_CRYPTO is not set diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 0d4ff0ae0746..bd28655043a0 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -33,6 +33,16 @@ config MPC885ADS The MPC885ADS is meant to serve as a platform for s/w and h/w development around the MPC885 processor family. +config PPC_EP88XC + bool "Embedded Planet EP88xC (a.k.a. CWH-PPC-885XN-VE)" + select CPM1 + select PPC_CPM_NEW_BINDING + help + This enables support for the Embedded Planet EP88xC board. + + This board is also resold by Freescale as the QUICCStart + MPC885 Evaluation System and/or the CWH-PPC-885XN-VE. + endchoice menu "Freescale Ethernet driver platform-specific options" diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile index 5e2dae3afd2f..8b7098018b59 100644 --- a/arch/powerpc/platforms/8xx/Makefile +++ b/arch/powerpc/platforms/8xx/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PPC_8xx) += m8xx_setup.o obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o +obj-$(CONFIG_PPC_EP88XC) += ep88xc.o diff --git a/arch/powerpc/platforms/8xx/ep88xc.c b/arch/powerpc/platforms/8xx/ep88xc.c new file mode 100644 index 000000000000..c518b6cc5fab --- /dev/null +++ b/arch/powerpc/platforms/8xx/ep88xc.c @@ -0,0 +1,176 @@ +/* + * Platform setup for the Embedded Planet EP88xC board + * + * Author: Scott Wood + * Copyright 2007 Freescale 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 warranty of any + * kind, whether express or implied. + */ + +#include +#include + +#include +#include +#include +#include + +#include + +struct cpm_pin { + int port, pin, flags; +}; + +static struct cpm_pin ep88xc_pins[] = { + /* SMC1 */ + {1, 24, CPM_PIN_INPUT}, /* RX */ + {1, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ + + /* SCC2 */ + {0, 12, CPM_PIN_INPUT}, /* TX */ + {0, 13, CPM_PIN_INPUT}, /* RX */ + {2, 8, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CD */ + {2, 9, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CTS */ + {2, 14, CPM_PIN_INPUT}, /* RTS */ + + /* MII1 */ + {0, 0, CPM_PIN_INPUT}, + {0, 1, CPM_PIN_INPUT}, + {0, 2, CPM_PIN_INPUT}, + {0, 3, CPM_PIN_INPUT}, + {0, 4, CPM_PIN_OUTPUT}, + {0, 10, CPM_PIN_OUTPUT}, + {0, 11, CPM_PIN_OUTPUT}, + {1, 19, CPM_PIN_INPUT}, + {1, 31, CPM_PIN_INPUT}, + {2, 12, CPM_PIN_INPUT}, + {2, 13, CPM_PIN_INPUT}, + {3, 8, CPM_PIN_INPUT}, + {4, 30, CPM_PIN_OUTPUT}, + {4, 31, CPM_PIN_OUTPUT}, + + /* MII2 */ + {4, 14, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 15, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 16, CPM_PIN_OUTPUT}, + {4, 17, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 18, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 19, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 20, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 21, CPM_PIN_OUTPUT}, + {4, 22, CPM_PIN_OUTPUT}, + {4, 23, CPM_PIN_OUTPUT}, + {4, 24, CPM_PIN_OUTPUT}, + {4, 25, CPM_PIN_OUTPUT}, + {4, 26, CPM_PIN_OUTPUT}, + {4, 27, CPM_PIN_OUTPUT}, + {4, 28, CPM_PIN_OUTPUT}, + {4, 29, CPM_PIN_OUTPUT}, + + /* USB */ + {0, 6, CPM_PIN_INPUT}, /* CLK2 */ + {0, 14, CPM_PIN_INPUT}, /* USBOE */ + {0, 15, CPM_PIN_INPUT}, /* USBRXD */ + {2, 6, CPM_PIN_OUTPUT}, /* USBTXN */ + {2, 7, CPM_PIN_OUTPUT}, /* USBTXP */ + {2, 10, CPM_PIN_INPUT}, /* USBRXN */ + {2, 11, CPM_PIN_INPUT}, /* USBRXP */ + + /* Misc */ + {1, 26, CPM_PIN_INPUT}, /* BRGO2 */ + {1, 27, CPM_PIN_INPUT}, /* BRGO1 */ +}; + +static void __init init_ioports(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ep88xc_pins); i++) { + struct cpm_pin *pin = &ep88xc_pins[i]; + cpm1_set_pin(pin->port, pin->pin, pin->flags); + } + + cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX); + cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK2, CPM_CLK_TX); /* USB */ + cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK2, CPM_CLK_RX); + cpm1_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); + cpm1_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); +} + +static u8 __iomem *ep88xc_bcsr; + +#define BCSR7_SCC2_ENABLE 0x10 + +#define BCSR8_PHY1_ENABLE 0x80 +#define BCSR8_PHY1_POWER 0x40 +#define BCSR8_PHY2_ENABLE 0x20 +#define BCSR8_PHY2_POWER 0x10 + +#define BCSR9_USB_ENABLE 0x80 +#define BCSR9_USB_POWER 0x40 +#define BCSR9_USB_HOST 0x20 +#define BCSR9_USB_FULL_SPEED_TARGET 0x10 + +static void __init ep88xc_setup_arch(void) +{ + struct device_node *np; + + cpm_reset(); + init_ioports(); + + np = of_find_compatible_node(NULL, NULL, "fsl,ep88xc-bcsr"); + if (!np) { + printk(KERN_CRIT "Could not find fsl,ep88xc-bcsr node\n"); + return; + } + + ep88xc_bcsr = of_iomap(np, 0); + of_node_put(np); + + if (!ep88xc_bcsr) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } + + setbits8(&ep88xc_bcsr[7], BCSR7_SCC2_ENABLE); + setbits8(&ep88xc_bcsr[8], BCSR8_PHY1_ENABLE | BCSR8_PHY1_POWER | + BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER); +} + +static int __init ep88xc_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "fsl,ep88xc"); +} + +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + /* Publish the QE devices */ + if (machine_is(ep88xc)) + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +device_initcall(declare_of_platform_devices); + +define_machine(ep88xc) { + .name = "Embedded Planet EP88xC", + .probe = ep88xc_probe, + .setup_arch = ep88xc_setup_arch, + .init_IRQ = m8xx_pic_init, + .get_irq = mpc8xx_get_irq, + .restart = mpc8xx_restart, + .calibrate_decr = mpc8xx_calibrate_decr, + .set_rtc_time = mpc8xx_set_rtc_time, + .get_rtc_time = mpc8xx_get_rtc_time, + .progress = udbg_progress, +}; From e00c5498a2a614931cbb7d88a53979d5d47594e1 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 14 Sep 2007 15:41:56 -0500 Subject: [PATCH 0448/2804] [POWERPC] mpc82xx: Update mpc8272ads, and factor out PCI and reset. 1. PCI and reset are factored out into pq2.c. I renamed them from m82xx to pq2 because they won't work on the Integrated Host Processor line of 82xx chips (i.e. 8240, 8245, and such). 2. The PCI PIC, which is nominally board-specific, is used on multiple boards, and thus is used into pq2ads-pci-pic.c. 3. The new CPM binding is used. 4. General cleanup. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/Kconfig | 2 +- arch/powerpc/boot/dts/mpc8272ads.dts | 313 +++++---- arch/powerpc/configs/mpc8272_ads_defconfig | 248 ++++--- arch/powerpc/platforms/82xx/Kconfig | 5 + arch/powerpc/platforms/82xx/Makefile | 2 + arch/powerpc/platforms/82xx/mpc8272_ads.c | 672 ++++--------------- arch/powerpc/platforms/82xx/pq2.c | 82 +++ arch/powerpc/platforms/82xx/pq2.h | 20 + arch/powerpc/platforms/82xx/pq2ads-pci-pic.c | 195 ++++++ arch/powerpc/platforms/82xx/pq2ads.h | 2 - 10 files changed, 761 insertions(+), 780 deletions(-) create mode 100644 arch/powerpc/platforms/82xx/pq2.c create mode 100644 arch/powerpc/platforms/82xx/pq2.h create mode 100644 arch/powerpc/platforms/82xx/pq2ads-pci-pic.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 37ff383393bd..6f5155d8c324 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -484,7 +484,7 @@ config PCI_8260 config 8260_PCI9 bool "Enable workaround for MPC826x erratum PCI 9" - depends on PCI_8260 && !ADS8272 + depends on PCI_8260 && !8272 default y choice diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts index 43130541799a..3fe991d4cb03 100644 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -11,7 +11,7 @@ / { model = "MPC8272ADS"; - compatible = "MPC8260ADS"; + compatible = "fsl,mpc8272ads"; #address-cells = <1>; #size-cells = <1>; @@ -22,187 +22,208 @@ PowerPC,8272@0 { device_type = "cpu"; reg = <0>; - d-cache-line-size = <20>; // 32 bytes - i-cache-line-size = <20>; // 32 bytes - d-cache-size = <4000>; // L1, 16K - i-cache-size = <4000>; // L1, 16K + d-cache-line-size = ; + i-cache-line-size = ; + d-cache-size = ; + i-cache-size = ; timebase-frequency = <0>; bus-frequency = <0>; clock-frequency = <0>; }; }; - pci_pic: interrupt-controller@f8200000 { - #address-cells = <0>; - #interrupt-cells = <2>; - interrupt-controller; - reg = ; - device_type = "pci-pic"; - }; - memory { device_type = "memory"; - reg = <00000000 4000000 f4500000 00000020>; + reg = <0 0>; }; - chosen { - name = "chosen"; - linux,platform = <0>; - interrupt-controller = <&Cpm_pic>; + localbus@f0010100 { + compatible = "fsl,mpc8272-localbus", + "fsl,pq2-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = ; + + ranges = <0 0 fe000000 02000000 + 1 0 f4500000 00008000 + 3 0 f8200000 00008000>; + + flash@0,0 { + compatible = "jedec-flash"; + reg = <0 0 2000000>; + bank-width = <4>; + device-width = <1>; + }; + + board-control@1,0 { + reg = <1 0 20>; + compatible = "fsl,mpc8272ads-bcsr"; + }; + + PCI_PIC: interrupt-controller@3,0 { + compatible = "fsl,mpc8272ads-pci-pic", + "fsl,pq2ads-pci-pic"; + #interrupt-cells = <1>; + interrupt-controller; + reg = <3 0 8>; + interrupt-parent = <&PIC>; + interrupts = <14 8>; + }; }; - soc8272@f0000000 { + + pci@f0010800 { + device_type = "pci"; + reg = ; + compatible = "fsl,mpc8272-pci", "fsl,pq2-pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + clock-frequency = ; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x16 */ + b000 0 0 1 &PCI_PIC 0 + b000 0 0 2 &PCI_PIC 1 + b000 0 0 3 &PCI_PIC 2 + b000 0 0 4 &PCI_PIC 3 + + /* IDSEL 0x17 */ + b800 0 0 1 &PCI_PIC 4 + b800 0 0 2 &PCI_PIC 5 + b800 0 0 3 &PCI_PIC 6 + b800 0 0 4 &PCI_PIC 7 + + /* IDSEL 0x18 */ + c000 0 0 1 &PCI_PIC 8 + c000 0 0 2 &PCI_PIC 9 + c000 0 0 3 &PCI_PIC a + c000 0 0 4 &PCI_PIC b>; + + interrupt-parent = <&PIC>; + interrupts = <12 8>; + ranges = <42000000 0 80000000 80000000 0 20000000 + 02000000 0 a0000000 a0000000 0 20000000 + 01000000 0 00000000 f6000000 0 02000000>; + }; + + soc@f0000000 { #address-cells = <1>; #size-cells = <1>; device_type = "soc"; + compatible = "fsl,mpc8272", "fsl,pq2-soc"; ranges = <00000000 f0000000 00053000>; - reg = ; - mdio@0 { - device_type = "mdio"; - compatible = "fs_enet"; - reg = <0 0>; - #address-cells = <1>; - #size-cells = <0>; + // Temporary -- will go away once kernel uses ranges for get_immrbase(). + reg = ; - phy0:ethernet-phy@0 { - interrupt-parent = <&Cpm_pic>; - interrupts = <17 4>; - reg = <0>; - bitbang = [ 12 12 13 02 02 01 ]; - device_type = "ethernet-phy"; - }; - - phy1:ethernet-phy@1 { - interrupt-parent = <&Cpm_pic>; - interrupts = <17 4>; - bitbang = [ 12 12 13 02 02 01 ]; - reg = <3>; - device_type = "ethernet-phy"; - }; - }; - - ethernet@24000 { - #address-cells = <1>; - #size-cells = <0>; - device_type = "network"; - device-id = <1>; - compatible = "fs_enet"; - model = "FCC"; - reg = <11300 20 8400 100 11380 30>; - mac-address = [ 00 11 2F 99 43 54 ]; - interrupts = <20 2>; - interrupt-parent = <&Cpm_pic>; - phy-handle = <&Phy0>; - rx-clock = <13>; - tx-clock = <12>; - }; - - ethernet@25000 { - device_type = "network"; - device-id = <2>; - compatible = "fs_enet"; - model = "FCC"; - reg = <11320 20 8500 100 113b0 30>; - mac-address = [ 00 11 2F 99 44 54 ]; - interrupts = <21 2>; - interrupt-parent = <&Cpm_pic>; - phy-handle = <&Phy1>; - rx-clock = <17>; - tx-clock = <18>; - }; - - cpm@f0000000 { + cpm@119c0 { #address-cells = <1>; #size-cells = <1>; - device_type = "cpm"; - model = "CPM2"; - ranges = <00000000 00000000 20000>; - reg = <0 20000>; - command-proc = <119c0>; - brg-frequency = <17D7840>; - cpm_clk = ; + compatible = "fsl,mpc8272-cpm", "fsl,cpm2"; + reg = <119c0 30 0 2000>; + ranges; - scc@11a00 { - device_type = "serial"; - compatible = "cpm_uart"; - model = "SCC"; - device-id = <1>; - reg = <11a00 20 8000 100>; - current-speed = <1c200>; - interrupts = <28 2>; - interrupt-parent = <&Cpm_pic>; - clock-setup = <0 00ffffff>; - rx-clock = <1>; - tx-clock = <1>; + brg@119f0 { + compatible = "fsl,mpc8272-brg", + "fsl,cpm2-brg", + "fsl,cpm-brg"; + reg = <119f0 10 115f0 10>; }; - scc@11a60 { + serial@11a00 { device_type = "serial"; - compatible = "cpm_uart"; - model = "SCC"; - device-id = <4>; + compatible = "fsl,mpc8272-scc-uart", + "fsl,cpm2-scc-uart"; + reg = <11a00 20 8000 100>; + interrupts = <28 8>; + interrupt-parent = <&PIC>; + fsl,cpm-brg = <1>; + fsl,cpm-command = <00800000>; + }; + + serial@11a60 { + device_type = "serial"; + compatible = "fsl,mpc8272-scc-uart", + "fsl,cpm2-scc-uart"; reg = <11a60 20 8300 100>; - current-speed = <1c200>; - interrupts = <2b 2>; - interrupt-parent = <&Cpm_pic>; - clock-setup = <1b ffffff00>; - rx-clock = <4>; - tx-clock = <4>; + interrupts = <2b 8>; + interrupt-parent = <&PIC>; + fsl,cpm-brg = <4>; + fsl,cpm-command = <0ce00000>; + }; + + mdio@10d40 { + device_type = "mdio"; + compatible = "fsl,mpc8272ads-mdio-bitbang", + "fsl,mpc8272-mdio-bitbang", + "fsl,cpm2-mdio-bitbang"; + reg = <10d40 14>; + #address-cells = <1>; + #size-cells = <0>; + fsl,mdio-pin = <12>; + fsl,mdc-pin = <13>; + + PHY0: ethernet-phy@0 { + interrupt-parent = <&PIC>; + interrupts = <17 8>; + reg = <0>; + device_type = "ethernet-phy"; + }; + + PHY1: ethernet-phy@1 { + interrupt-parent = <&PIC>; + interrupts = <17 8>; + reg = <3>; + device_type = "ethernet-phy"; + }; + }; + + ethernet@11300 { + device_type = "network"; + compatible = "fsl,mpc8272-fcc-enet", + "fsl,cpm2-fcc-enet"; + reg = <11300 20 8400 100 11390 1>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <20 8>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY0>; + linux,network-index = <0>; + fsl,cpm-command = <12000300>; + }; + + ethernet@11320 { + device_type = "network"; + compatible = "fsl,mpc8272-fcc-enet", + "fsl,cpm2-fcc-enet"; + reg = <11320 20 8500 100 113b0 1>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <21 8>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY1>; + linux,network-index = <1>; + fsl,cpm-command = <16200300>; }; }; - cpm_pic:interrupt-controller@10c00 { - #address-cells = <0>; + PIC: interrupt-controller@10c00 { #interrupt-cells = <2>; interrupt-controller; reg = <10c00 80>; - device_type = "cpm-pic"; - compatible = "CPM2"; - }; - - pci@0500 { - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "8272"; - device_type = "pci"; - reg = <10430 4dc>; - clock-frequency = <3f940aa>; - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x16 */ - b000 0 0 1 f8200000 40 8 - b000 0 0 2 f8200000 41 8 - b000 0 0 3 f8200000 42 8 - b000 0 0 4 f8200000 43 8 - - /* IDSEL 0x17 */ - b800 0 0 1 f8200000 43 8 - b800 0 0 2 f8200000 40 8 - b800 0 0 3 f8200000 41 8 - b800 0 0 4 f8200000 42 8 - - /* IDSEL 0x18 */ - c000 0 0 1 f8200000 42 8 - c000 0 0 2 f8200000 43 8 - c000 0 0 3 f8200000 40 8 - c000 0 0 4 f8200000 41 8>; - interrupt-parent = <&Cpm_pic>; - interrupts = <14 8>; - bus-range = <0 0>; - ranges = <02000000 0 80000000 80000000 0 40000000 - 01000000 0 00000000 f6000000 0 02000000>; + compatible = "fsl,mpc8272-pic", "fsl,cpm2-pic"; }; /* May need to remove if on a part without crypto engine */ crypto@30000 { device_type = "crypto"; model = "SEC2"; - compatible = "talitos"; + compatible = "fsl,mpc8272-talitos-sec2", + "fsl,talitos-sec2", + "fsl,talitos", + "talitos"; reg = <30000 10000>; - interrupts = ; - interrupt-parent = <&Cpm_pic>; + interrupts = ; + interrupt-parent = <&PIC>; num-channels = <4>; channel-fifo-len = <18>; exec-units-mask = <0000007e>; @@ -210,4 +231,8 @@ descriptor-types-mask = <01010ebf>; }; }; + + chosen { + linux,stdout-path = "/soc/cpm/serial@11a00"; + }; }; diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig index 4b68032588ff..6b7951ec941a 100644 --- a/arch/powerpc/configs/mpc8272_ads_defconfig +++ b/arch/powerpc/configs/mpc8272_ads_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.23-rc4 -# Tue Aug 28 21:24:39 2007 +# Wed Sep 5 12:43:23 2007 # # CONFIG_PPC64 is not set @@ -52,7 +52,7 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # CONFIG_EXPERIMENTAL is not set CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 -CONFIG_LOCALVERSION="powerpc8272" +CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y @@ -71,7 +71,7 @@ CONFIG_EMBEDDED=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y @@ -122,10 +122,11 @@ CONFIG_PPC_82xx=y # CONFIG_PPC_MPC5200 is not set # CONFIG_PPC_CELL is not set # CONFIG_PPC_CELL_NATIVE is not set -CONFIG_MPC82xx_ADS=y +CONFIG_MPC8272_ADS=y CONFIG_PQ2ADS=y CONFIG_8260=y CONFIG_8272=y +CONFIG_PQ2_ADS_PCI_PIC=y # CONFIG_MPIC is not set # CONFIG_MPIC_WEIRD is not set # CONFIG_PPC_I8259 is not set @@ -137,7 +138,9 @@ CONFIG_8272=y # CONFIG_GENERIC_IOMAP is not set # CONFIG_CPU_FREQ is not set CONFIG_CPM2=y +CONFIG_PPC_CPM_NEW_BINDING=y # CONFIG_FSL_ULI1575 is not set +CONFIG_CPM=y # # Kernel options @@ -168,18 +171,25 @@ CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set # CONFIG_PM is not set CONFIG_SECCOMP=y -# CONFIG_WANT_DEVICE_TREE is not set +CONFIG_WANT_DEVICE_TREE=y +# CONFIG_BUILD_RAW_IMAGE is not set +CONFIG_DEVICE_TREE="mpc8272ads.dts" CONFIG_ISA_DMA_API=y # # Bus options # CONFIG_ZONE_DMA=y +CONFIG_PPC_INDIRECT_PCI=y CONFIG_FSL_SOC=y -# CONFIG_PCI is not set -# CONFIG_PCI_DOMAINS is not set -# CONFIG_PCI_SYSCALL is not set -# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCI_8260=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support @@ -313,43 +323,101 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # CONFIG_CONNECTOR is not set -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_PARTITIONS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +# CONFIG_MTD_CFI_I1 is not set +# CONFIG_MTD_CFI_I2 is not set +CONFIG_MTD_CFI_I4=y +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_SBC8240 is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set CONFIG_OF_DEVICE=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set -CONFIG_MISC_DEVICES=y -# CONFIG_EEPROM_93CX6 is not set -CONFIG_IDE=y -CONFIG_IDE_MAX_HWIFS=4 -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_IDE_SATA is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_IDE_TASK_IOCTL is not set -CONFIG_IDE_PROC_FS=y - -# -# IDE chipset support/bugfixes -# -# CONFIG_IDE_GENERIC is not set -# CONFIG_IDEPCI_PCIBUS_ORDER is not set -# CONFIG_IDE_ARM is not set -# CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_BLK_DEV_HD is not set +# CONFIG_MISC_DEVICES is not set +# CONFIG_IDE is not set # # SCSI device support @@ -360,6 +428,21 @@ CONFIG_IDE_PROC_FS=y # CONFIG_SCSI_NETLINK is not set # CONFIG_ATA is not set # CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# An alternative FireWire stack is available with EXPERIMENTAL=y +# +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set # CONFIG_MACINTOSH_DRIVERS is not set CONFIG_NETDEVICES=y # CONFIG_NETDEVICES_MULTIQUEUE is not set @@ -367,6 +450,7 @@ CONFIG_NETDEVICES=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set CONFIG_TUN=y +# CONFIG_ARCNET is not set CONFIG_PHYLIB=y # @@ -382,13 +466,42 @@ CONFIG_DAVICOM_PHY=y # CONFIG_BROADCOM_PHY is not set # CONFIG_ICPLUS_PHY is not set # CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y CONFIG_NET_ETHERNET=y CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set CONFIG_FS_ENET_HAS_FCC=y CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set CONFIG_NETDEV_10000=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_TR is not set # # Wireless LAN @@ -396,6 +509,7 @@ CONFIG_NETDEV_10000=y # CONFIG_WLAN_PRE80211 is not set # CONFIG_WLAN_80211 is not set # CONFIG_WAN is not set +# CONFIG_FDDI is not set CONFIG_PPP=y # CONFIG_PPP_FILTER is not set CONFIG_PPP_ASYNC=y @@ -459,6 +573,7 @@ CONFIG_MOUSE_PS2_TRACKPOINT=y CONFIG_SERIO=y # CONFIG_SERIO_I8042 is not set CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set @@ -488,6 +603,7 @@ CONFIG_SERIAL_CPM_SCC1=y CONFIG_SERIAL_CPM_SCC4=y # CONFIG_SERIAL_CPM_SMC1 is not set # CONFIG_SERIAL_CPM_SMC2 is not set +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -497,7 +613,11 @@ CONFIG_HW_RANDOM=y # CONFIG_NVRAM is not set # CONFIG_GEN_RTC is not set # CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y # CONFIG_I2C is not set # @@ -531,7 +651,7 @@ CONFIG_DAB=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y +# CONFIG_VIDEO_OUTPUT_CONTROL is not set # CONFIG_FB is not set # CONFIG_FB_IBM_GXT4500 is not set @@ -539,45 +659,11 @@ CONFIG_VIDEO_OUTPUT_CONTROL=y # Sound # # CONFIG_SOUND is not set -CONFIG_HID_SUPPORT=y -CONFIG_HID=y -# CONFIG_HID_DEBUG is not set -CONFIG_USB_SUPPORT=y -# CONFIG_USB_ARCH_HAS_HCD is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -CONFIG_USB_GADGET=y -# CONFIG_USB_GADGET_DEBUG_FILES is not set -CONFIG_USB_GADGET_SELECTED=y -# CONFIG_USB_GADGET_AMD5536UDC is not set -# CONFIG_USB_GADGET_FSL_USB2 is not set -# CONFIG_USB_GADGET_NET2280 is not set -# CONFIG_USB_GADGET_PXA2XX is not set -CONFIG_USB_GADGET_M66592=y -CONFIG_USB_M66592=y -# CONFIG_USB_GADGET_GOKU is not set -# CONFIG_USB_GADGET_LH7A40X is not set -# CONFIG_USB_GADGET_OMAP is not set -# CONFIG_USB_GADGET_S3C2410 is not set -# CONFIG_USB_GADGET_AT91 is not set -# CONFIG_USB_GADGET_DUMMY_HCD is not set -CONFIG_USB_GADGET_DUALSPEED=y -# CONFIG_USB_ZERO is not set -CONFIG_USB_ETH=y -# CONFIG_USB_GADGETFS is not set -# CONFIG_USB_FILE_STORAGE is not set -# CONFIG_USB_G_SERIAL is not set -# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set # CONFIG_MMC is not set # CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set # CONFIG_RTC_CLASS is not set # @@ -614,11 +700,7 @@ CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y -CONFIG_XFS_FS=y -# CONFIG_XFS_QUOTA is not set -# CONFIG_XFS_SECURITY is not set -# CONFIG_XFS_POSIX_ACL is not set -# CONFIG_XFS_RT is not set +# CONFIG_XFS_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -659,6 +741,7 @@ CONFIG_RAMFS=y # Miscellaneous filesystems # # CONFIG_HFSPLUS_FS is not set +# CONFIG_JFFS2_FS is not set CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -680,8 +763,7 @@ CONFIG_LOCKD_V4=y CONFIG_NFS_ACL_SUPPORT=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y -CONFIG_SMB_FS=y -# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_SMB_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set @@ -775,7 +857,7 @@ CONFIG_HAS_DMA=y # # CONFIG_PRINTK_TIME is not set CONFIG_ENABLE_MUST_CHECK=y -# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set @@ -793,7 +875,7 @@ CONFIG_SCHED_DEBUG=y # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_LIST is not set @@ -845,4 +927,4 @@ CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_CAMELLIA is not set -CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index f260c014ff2a..03f5aeb5fa40 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -10,6 +10,8 @@ config MPC8272_ADS select 8272 select 8260 select FSL_SOC + select PQ2_ADS_PCI_PIC if PCI + select PPC_CPM_NEW_BINDING help This option enables support for the MPC8272 ADS board @@ -34,3 +36,6 @@ config 8272 help The MPC8272 CPM has a different internal dpram setup than other CPM2 devices + +config PQ2_ADS_PCI_PIC + bool diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile index 9b7c851ce6f1..bfcb64cdbd83 100644 --- a/arch/powerpc/platforms/82xx/Makefile +++ b/arch/powerpc/platforms/82xx/Makefile @@ -2,3 +2,5 @@ # Makefile for the PowerPC 82xx linux kernel. # obj-$(CONFIG_MPC8272_ADS) += mpc8272_ads.o +obj-$(CONFIG_CPM2) += pq2.o +obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c index 4de76dad31b2..fd83440eb287 100644 --- a/arch/powerpc/platforms/82xx/mpc8272_ads.c +++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c @@ -1,9 +1,10 @@ /* - * MPC8272_ads setup and early boot code plus other random bits. + * MPC8272 ADS board support * - * Author: Vitaly Bordug - * m82xx_restart fix by Wade Farnsworth + * Copyright 2007 Freescale Semiconductor, Inc. + * Author: Scott Wood * + * Based on code by Vitaly Bordug * Copyright (c) 2006 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify it @@ -12,613 +13,184 @@ * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include +#include +#include + +#include #include #include #include "pq2ads.h" - -#ifdef CONFIG_PCI -static uint pci_clk_frq; -static struct { - unsigned long *pci_int_stat_reg; - unsigned long *pci_int_mask_reg; -} pci_regs; - -static unsigned long pci_int_base; -static struct irq_host *pci_pic_host; -#endif +#include "pq2.h" static void __init mpc8272_ads_pic_init(void) { - struct device_node *np = of_find_compatible_node(NULL, "cpm-pic", "CPM2"); - struct resource r; - cpm2_map_t *cpm_reg; + struct device_node *np = of_find_compatible_node(NULL, NULL, + "fsl,cpm2-pic"); + if (!np) { + printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); + return; + } - if (np == NULL) { - printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); - return; - } - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "PIC init: invalid resource\n"); - of_node_put(np); - return; - } cpm2_pic_init(np); of_node_put(np); - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - cpm_reg = (cpm2_map_t *) ioremap(get_immrbase(), sizeof(cpm2_map_t)); - cpm_reg->im_intctl.ic_siprr = 0x05309770; - iounmap(cpm_reg); -#ifdef CONFIG_PCI /* Initialize stuff for the 82xx CPLD IC and install demux */ - m82xx_pci_init_irq(); -#endif + pq2ads_pci_init_irq(); } -static void init_fcc1_ioports(struct fs_platform_info *fpi) -{ - struct io_port *io; - u32 tempval; - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - struct device_node *np; - struct resource r; - u32 *bcsr; - - np = of_find_node_by_type(NULL, "memory"); - if (!np) { - printk(KERN_INFO "No memory node in device tree\n"); - return; - } - if (of_address_to_resource(np, 1, &r)) { - printk(KERN_INFO "No memory reg property [1] in devicetree\n"); - return; - } - of_node_put(np); - bcsr = ioremap(r.start + 4, sizeof(u32)); - io = &immap->im_ioport; - - /* Enable the PHY */ - clrbits32(bcsr, BCSR1_FETHIEN); - setbits32(bcsr, BCSR1_FETH_RST); - - /* FCC1 pins are on port A/C. */ - /* Configure port A and C pins for FCC1 Ethernet. */ - - tempval = in_be32(&io->iop_pdira); - tempval &= ~PA1_DIRA0; - tempval |= PA1_DIRA1; - out_be32(&io->iop_pdira, tempval); - - tempval = in_be32(&io->iop_psora); - tempval &= ~PA1_PSORA0; - tempval |= PA1_PSORA1; - out_be32(&io->iop_psora, tempval); - - setbits32(&io->iop_ppara, PA1_DIRA0 | PA1_DIRA1); - - /* Alter clocks */ - tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8); - - clrbits32(&io->iop_psorc, tempval); - clrbits32(&io->iop_pdirc, tempval); - setbits32(&io->iop_pparc, tempval); - - cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_rx, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_tx, CPM_CLK_TX); - - iounmap(bcsr); - iounmap(immap); -} - -static void init_fcc2_ioports(struct fs_platform_info *fpi) -{ - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - struct device_node *np; - struct resource r; - u32 *bcsr; - - struct io_port *io; - u32 tempval; - - np = of_find_node_by_type(NULL, "memory"); - if (!np) { - printk(KERN_INFO "No memory node in device tree\n"); - return; - } - if (of_address_to_resource(np, 1, &r)) { - printk(KERN_INFO "No memory reg property [1] in devicetree\n"); - return; - } - of_node_put(np); - io = &immap->im_ioport; - bcsr = ioremap(r.start + 12, sizeof(u32)); - - /* Enable the PHY */ - clrbits32(bcsr, BCSR3_FETHIEN2); - setbits32(bcsr, BCSR3_FETH2_RST); - - /* FCC2 are port B/C. */ - /* Configure port A and C pins for FCC2 Ethernet. */ - - tempval = in_be32(&io->iop_pdirb); - tempval &= ~PB2_DIRB0; - tempval |= PB2_DIRB1; - out_be32(&io->iop_pdirb, tempval); - - tempval = in_be32(&io->iop_psorb); - tempval &= ~PB2_PSORB0; - tempval |= PB2_PSORB1; - out_be32(&io->iop_psorb, tempval); - - setbits32(&io->iop_pparb, PB2_DIRB0 | PB2_DIRB1); - - tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8); - - /* Alter clocks */ - clrbits32(&io->iop_psorc, tempval); - clrbits32(&io->iop_pdirc, tempval); - setbits32(&io->iop_pparc, tempval); - - cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_rx, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_tx, CPM_CLK_TX); - - iounmap(bcsr); - iounmap(immap); -} - -void init_fcc_ioports(struct fs_platform_info *fpi) -{ - int fcc_no = fs_get_fcc_index(fpi->fs_no); - - switch (fcc_no) { - case 0: - init_fcc1_ioports(fpi); - break; - case 1: - init_fcc2_ioports(fpi); - break; - default: - printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n"); - return; - } -} - -static void init_scc1_uart_ioports(struct fs_uart_platform_info *data) -{ - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - - /* SCC1 is only on port D */ - setbits32(&immap->im_ioport.iop_ppard, 0x00000003); - clrbits32(&immap->im_ioport.iop_psord, 0x00000001); - setbits32(&immap->im_ioport.iop_psord, 0x00000002); - clrbits32(&immap->im_ioport.iop_pdird, 0x00000001); - setbits32(&immap->im_ioport.iop_pdird, 0x00000002); - - clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx))); - clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx))); - setbits32(&immap->im_cpmux.cmx_scr, - ((data->clk_tx - 1) << (4 - data->clk_tx))); - setbits32(&immap->im_cpmux.cmx_scr, - ((data->clk_rx - 1) << (4 - data->clk_rx))); - - iounmap(immap); -} - -static void init_scc4_uart_ioports(struct fs_uart_platform_info *data) -{ - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - - setbits32(&immap->im_ioport.iop_ppard, 0x00000600); - clrbits32(&immap->im_ioport.iop_psord, 0x00000600); - clrbits32(&immap->im_ioport.iop_pdird, 0x00000200); - setbits32(&immap->im_ioport.iop_pdird, 0x00000400); - - clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx))); - clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx))); - setbits32(&immap->im_cpmux.cmx_scr, - ((data->clk_tx - 1) << (4 - data->clk_tx))); - setbits32(&immap->im_cpmux.cmx_scr, - ((data->clk_rx - 1) << (4 - data->clk_rx))); - - iounmap(immap); -} - -void init_scc_ioports(struct fs_uart_platform_info *data) -{ - int scc_no = fs_get_scc_index(data->fs_no); - - switch (scc_no) { - case 0: - init_scc1_uart_ioports(data); - data->brg = data->clk_rx; - break; - case 3: - init_scc4_uart_ioports(data); - data->brg = data->clk_rx; - break; - default: - printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); - return; - } -} - -void __init m82xx_board_setup(void) -{ - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - struct device_node *np; - struct resource r; - u32 *bcsr; - - np = of_find_node_by_type(NULL, "memory"); - if (!np) { - printk(KERN_INFO "No memory node in device tree\n"); - return; - } - if (of_address_to_resource(np, 1, &r)) { - printk(KERN_INFO "No memory reg property [1] in devicetree\n"); - return; - } - of_node_put(np); - bcsr = ioremap(r.start + 4, sizeof(u32)); - /* Enable the 2nd UART port */ - clrbits32(bcsr, BCSR1_RS232_EN2); - -#ifdef CONFIG_SERIAL_CPM_SCC1 - clrbits32((u32 *) & immap->im_scc[0].scc_sccm, - UART_SCCM_TX | UART_SCCM_RX); - clrbits32((u32 *) & immap->im_scc[0].scc_gsmrl, - SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - -#ifdef CONFIG_SERIAL_CPM_SCC2 - clrbits32((u32 *) & immap->im_scc[1].scc_sccm, - UART_SCCM_TX | UART_SCCM_RX); - clrbits32((u32 *) & immap->im_scc[1].scc_gsmrl, - SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - -#ifdef CONFIG_SERIAL_CPM_SCC3 - clrbits32((u32 *) & immap->im_scc[2].scc_sccm, - UART_SCCM_TX | UART_SCCM_RX); - clrbits32((u32 *) & immap->im_scc[2].scc_gsmrl, - SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - -#ifdef CONFIG_SERIAL_CPM_SCC4 - clrbits32((u32 *) & immap->im_scc[3].scc_sccm, - UART_SCCM_TX | UART_SCCM_RX); - clrbits32((u32 *) & immap->im_scc[3].scc_gsmrl, - SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - - iounmap(bcsr); - iounmap(immap); -} - -#ifdef CONFIG_PCI -static void m82xx_pci_mask_irq(unsigned int irq) -{ - int bit = irq - pci_int_base; - - *pci_regs.pci_int_mask_reg |= (1 << (31 - bit)); - return; -} - -static void m82xx_pci_unmask_irq(unsigned int irq) -{ - int bit = irq - pci_int_base; - - *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit)); - return; -} - -static void m82xx_pci_mask_and_ack(unsigned int irq) -{ - int bit = irq - pci_int_base; - - *pci_regs.pci_int_mask_reg |= (1 << (31 - bit)); - return; -} - -static void m82xx_pci_end_irq(unsigned int irq) -{ - int bit = irq - pci_int_base; - - *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit)); - return; -} - -struct hw_interrupt_type m82xx_pci_ic = { - .typename = "MPC82xx ADS PCI", - .name = "MPC82xx ADS PCI", - .enable = m82xx_pci_unmask_irq, - .disable = m82xx_pci_mask_irq, - .ack = m82xx_pci_mask_and_ack, - .end = m82xx_pci_end_irq, - .mask = m82xx_pci_mask_irq, - .mask_ack = m82xx_pci_mask_and_ack, - .unmask = m82xx_pci_unmask_irq, - .eoi = m82xx_pci_end_irq, +struct cpm_pin { + int port, pin, flags; }; -static void -m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc) -{ - unsigned long stat, mask, pend; - int bit; +static struct cpm_pin mpc8272_ads_pins[] = { + /* SCC1 */ + {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - for (;;) { - stat = *pci_regs.pci_int_stat_reg; - mask = *pci_regs.pci_int_mask_reg; - pend = stat & ~mask & 0xf0000000; - if (!pend) - break; - for (bit = 0; pend != 0; ++bit, pend <<= 1) { - if (pend & 0x80000000) - __do_IRQ(pci_int_base + bit); - } - } -} + /* SCC4 */ + {3, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, -static int pci_pic_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - get_irq_desc(virq)->status |= IRQ_LEVEL; - set_irq_chip(virq, &m82xx_pci_ic); - return 0; -} + /* FCC1 */ + {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, -static void pci_host_unmap(struct irq_host *h, unsigned int virq) -{ - /* remove chip and handler */ - set_irq_chip(virq, NULL); -} - -static struct irq_host_ops pci_pic_host_ops = { - .map = pci_pic_host_map, - .unmap = pci_host_unmap, + /* FCC2 */ + {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, }; -void m82xx_pci_init_irq(void) +static void __init init_ioports(void) { - int irq; - cpm2_map_t *immap; - struct device_node *np; - struct resource r; - const u32 *regs; - unsigned int size; - const u32 *irq_map; int i; - unsigned int irq_max, irq_min; - if ((np = of_find_node_by_type(NULL, "soc")) == NULL) { - printk(KERN_INFO "No SOC node in device tree\n"); - return; + for (i = 0; i < ARRAY_SIZE(mpc8272_ads_pins); i++) { + struct cpm_pin *pin = &mpc8272_ads_pins[i]; + cpm2_set_pin(pin->port, pin->pin, pin->flags); } - memset(&r, 0, sizeof(r)); - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_INFO "No SOC reg property in device tree\n"); - return; - } - immap = ioremap(r.start, sizeof(*immap)); - of_node_put(np); - /* install the demultiplexer for the PCI cascade interrupt */ - np = of_find_node_by_type(NULL, "pci"); - if (!np) { - printk(KERN_INFO "No pci node on device tree\n"); - iounmap(immap); - return; - } - irq_map = of_get_property(np, "interrupt-map", &size); - if ((!irq_map) || (size <= 7)) { - printk(KERN_INFO "No interrupt-map property of pci node\n"); - iounmap(immap); - return; - } - size /= sizeof(irq_map[0]); - for (i = 0, irq_max = 0, irq_min = 512; i < size; i += 7, irq_map += 7) { - if (irq_map[5] < irq_min) - irq_min = irq_map[5]; - if (irq_map[5] > irq_max) - irq_max = irq_map[5]; - } - pci_int_base = irq_min; - irq = irq_of_parse_and_map(np, 0); - set_irq_chained_handler(irq, m82xx_pci_irq_demux); - of_node_put(np); - np = of_find_node_by_type(NULL, "pci-pic"); - if (!np) { - printk(KERN_INFO "No pci pic node on device tree\n"); - iounmap(immap); - return; - } - /* PCI interrupt controller registers: status and mask */ - regs = of_get_property(np, "reg", &size); - if ((!regs) || (size <= 2)) { - printk(KERN_INFO "No reg property in pci pic node\n"); - iounmap(immap); - return; - } - pci_regs.pci_int_stat_reg = - ioremap(regs[0], sizeof(*pci_regs.pci_int_stat_reg)); - pci_regs.pci_int_mask_reg = - ioremap(regs[1], sizeof(*pci_regs.pci_int_mask_reg)); - /* configure chip select for PCI interrupt controller */ - immap->im_memctl.memc_br3 = regs[0] | 0x00001801; - immap->im_memctl.memc_or3 = 0xffff8010; - /* make PCI IRQ level sensitive */ - immap->im_intctl.ic_siexr &= ~(1 << (14 - (irq - SIU_INT_IRQ1))); - - /* mask all PCI interrupts */ - *pci_regs.pci_int_mask_reg |= 0xfff00000; - iounmap(immap); - pci_pic_host = - irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1, - &pci_pic_host_ops, irq_max + 1); - return; + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK15, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK16, CPM_CLK_TX); } -static int m82xx_pci_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn) -{ - if (bus == 0 && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - else - return PCIBIOS_SUCCESSFUL; -} - -static void __init mpc82xx_add_bridge(struct device_node *np) -{ - int len; - struct pci_controller *hose; - struct resource r; - const int *bus_range; - const uint *ptr; - - memset(&r, 0, sizeof(r)); - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_INFO "No PCI reg property in device tree\n"); - return; - } - if (!(ptr = of_get_property(np, "clock-frequency", NULL))) { - printk(KERN_INFO "No clock-frequency property in PCI node"); - return; - } - pci_clk_frq = *ptr; - of_node_put(np); - bus_range = of_get_property(np, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume" - " bus 0\n", np->full_name); - } - - pci_assign_all_buses = 1; - - hose = pcibios_alloc_controller(np); - - if (!hose) - return; - - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; - - setup_indirect_pci(hose, - r.start + offsetof(pci_cpm2_t, pci_cfg_addr), - r.start + offsetof(pci_cpm2_t, pci_cfg_data), - 0); - - pci_process_bridge_OF_ranges(hose, np, 1); -} -#endif - -/* - * Setup the architecture - */ static void __init mpc8272_ads_setup_arch(void) { -#ifdef CONFIG_PCI struct device_node *np; -#endif + __be32 __iomem *bcsr; if (ppc_md.progress) ppc_md.progress("mpc8272_ads_setup_arch()", 0); + cpm2_reset(); - /* Map I/O region to a 256MB BAT */ + np = of_find_compatible_node(NULL, NULL, "fsl,mpc8272ads-bcsr"); + if (!np) { + printk(KERN_ERR "No bcsr in device tree\n"); + return; + } - m82xx_board_setup(); - -#ifdef CONFIG_PCI - ppc_md.pci_exclude_device = m82xx_pci_exclude_device; - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - mpc82xx_add_bridge(np); + bcsr = of_iomap(np, 0); + if (!bcsr) { + printk(KERN_ERR "Cannot map BCSR registers\n"); + return; + } of_node_put(np); -#endif -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif + clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); + setbits32(&bcsr[1], BCSR1_FETH_RST); + + clrbits32(&bcsr[3], BCSR3_FETHIEN2); + setbits32(&bcsr[3], BCSR3_FETH2_RST); + + iounmap(bcsr); + + init_ioports(); + pq2_init_pci(); if (ppc_md.progress) ppc_md.progress("mpc8272_ads_setup_arch(), finish", 0); } +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + if (!machine_is(mpc8272_ads)) + return 0; + + /* Publish the QE devices */ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} +device_initcall(declare_of_platform_devices); + /* * Called very early, device-tree isn't unflattened */ static int __init mpc8272_ads_probe(void) { - /* We always match for now, eventually we should look at - * the flat dev tree to ensure this is the board we are - * supposed to run on - */ - return 1; -} - -#define RMR_CSRE 0x00000001 -static void m82xx_restart(char *cmd) -{ - __volatile__ unsigned char dummy; - - local_irq_disable(); - ((cpm2_map_t *) cpm2_immr)->im_clkrst.car_rmr |= RMR_CSRE; - - /* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */ - mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR)); - dummy = ((cpm2_map_t *) cpm2_immr)->im_clkrst.res[0]; - printk("Restart failed\n"); - while (1) ; + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "fsl,mpc8272ads"); } define_machine(mpc8272_ads) { - .name = "MPC8272 ADS", - .probe = mpc8272_ads_probe, - .setup_arch = mpc8272_ads_setup_arch, - .init_IRQ = mpc8272_ads_pic_init, - .get_irq = cpm2_get_irq, + .name = "Freescale MPC8272 ADS", + .probe = mpc8272_ads_probe, + .setup_arch = mpc8272_ads_setup_arch, + .init_IRQ = mpc8272_ads_pic_init, + .get_irq = cpm2_get_irq, .calibrate_decr = generic_calibrate_decr, - .restart = m82xx_restart, + .restart = pq2_restart, + .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/82xx/pq2.c b/arch/powerpc/platforms/82xx/pq2.c new file mode 100644 index 000000000000..a497cbaa1ac5 --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2.c @@ -0,0 +1,82 @@ +/* + * Common PowerQUICC II code. + * + * Author: Scott Wood + * Copyright (c) 2007 Freescale Semiconductor + * + * Based on code by Vitaly Bordug + * pq2_restart fix by Wade Farnsworth + * Copyright (c) 2006 MontaVista Software, 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 + +#define RMR_CSRE 0x00000001 + +void pq2_restart(char *cmd) +{ + local_irq_disable(); + setbits32(&cpm2_immr->im_clkrst.car_rmr, RMR_CSRE); + + /* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */ + mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR)); + in_8(&cpm2_immr->im_clkrst.res[0]); + + panic("Restart failed\n"); +} + +#ifdef CONFIG_PCI +static int pq2_pci_exclude_device(struct pci_controller *hose, + u_char bus, u8 devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +static void __init pq2_pci_add_bridge(struct device_node *np) +{ + struct pci_controller *hose; + struct resource r; + + if (of_address_to_resource(np, 0, &r) || r.end - r.start < 0x10b) + goto err; + + pci_assign_all_buses = 1; + + hose = pcibios_alloc_controller(np); + if (!hose) + return; + + hose->arch_data = np; + + setup_indirect_pci(hose, r.start + 0x100, r.start + 0x104, 0); + pci_process_bridge_OF_ranges(hose, np, 1); + + return; + +err: + printk(KERN_ERR "No valid PCI reg property in device tree\n"); +} + +void __init pq2_init_pci(void) +{ + struct device_node *np = NULL; + + ppc_md.pci_exclude_device = pq2_pci_exclude_device; + + while ((np = of_find_compatible_node(np, NULL, "fsl,pq2-pci"))) + pq2_pci_add_bridge(np); +} +#endif diff --git a/arch/powerpc/platforms/82xx/pq2.h b/arch/powerpc/platforms/82xx/pq2.h new file mode 100644 index 000000000000..a41f84ae2325 --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2.h @@ -0,0 +1,20 @@ +#ifndef _PQ2_H +#define _PQ2_H + +void pq2_restart(char *cmd); + +#ifdef CONFIG_PCI +int pq2ads_pci_init_irq(void); +void pq2_init_pci(void); +#else +static inline int pq2ads_pci_init_irq(void) +{ + return 0; +} + +static inline void pq2_init_pci(void) +{ +} +#endif + +#endif diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c new file mode 100644 index 000000000000..a8013816125c --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -0,0 +1,195 @@ +/* + * PQ2 ADS-style PCI interrupt controller + * + * Copyright 2007 Freescale Semiconductor, Inc. + * Author: Scott Wood + * + * Loosely based on mpc82xx ADS support by Vitaly Bordug + * Copyright (c) 2006 MontaVista 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 "pq2.h" + +static DEFINE_SPINLOCK(pci_pic_lock); + +struct pq2ads_pci_pic { + struct device_node *node; + struct irq_host *host; + + struct { + u32 stat; + u32 mask; + } __iomem *regs; +}; + +#define NUM_IRQS 32 + +static void pq2ads_pci_mask_irq(unsigned int virq) +{ + struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); + int irq = NUM_IRQS - virq_to_hw(virq) - 1; + + if (irq != -1) { + unsigned long flags; + spin_lock_irqsave(&pci_pic_lock, flags); + + setbits32(&priv->regs->mask, 1 << irq); + mb(); + + spin_unlock_irqrestore(&pci_pic_lock, flags); + } +} + +static void pq2ads_pci_unmask_irq(unsigned int virq) +{ + struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); + int irq = NUM_IRQS - virq_to_hw(virq) - 1; + + if (irq != -1) { + unsigned long flags; + + spin_lock_irqsave(&pci_pic_lock, flags); + clrbits32(&priv->regs->mask, 1 << irq); + spin_unlock_irqrestore(&pci_pic_lock, flags); + } +} + +static struct irq_chip pq2ads_pci_ic = { + .typename = "PQ2 ADS PCI", + .name = "PQ2 ADS PCI", + .end = pq2ads_pci_unmask_irq, + .mask = pq2ads_pci_mask_irq, + .mask_ack = pq2ads_pci_mask_irq, + .ack = pq2ads_pci_mask_irq, + .unmask = pq2ads_pci_unmask_irq, + .enable = pq2ads_pci_unmask_irq, + .disable = pq2ads_pci_mask_irq +}; + +static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc) +{ + struct pq2ads_pci_pic *priv = desc->handler_data; + u32 stat, mask, pend; + int bit; + + for (;;) { + stat = in_be32(&priv->regs->stat); + mask = in_be32(&priv->regs->mask); + + pend = stat & ~mask; + + if (!pend) + break; + + for (bit = 0; pend != 0; ++bit, pend <<= 1) { + if (pend & 0x80000000) { + int virq = irq_linear_revmap(priv->host, bit); + generic_handle_irq(virq); + } + } + } +} + +static int pci_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + get_irq_desc(virq)->status |= IRQ_LEVEL; + set_irq_chip_data(virq, h->host_data); + set_irq_chip(virq, &pq2ads_pci_ic); + return 0; +} + +static void pci_host_unmap(struct irq_host *h, unsigned int virq) +{ + /* remove chip and handler */ + set_irq_chip_data(virq, NULL); + set_irq_chip(virq, NULL); +} + +static struct irq_host_ops pci_pic_host_ops = { + .map = pci_pic_host_map, + .unmap = pci_host_unmap, +}; + +int __init pq2ads_pci_init_irq(void) +{ + struct pq2ads_pci_pic *priv; + struct irq_host *host; + struct device_node *np; + int ret = -ENODEV; + int irq; + + np = of_find_compatible_node(NULL, NULL, "fsl,pq2ads-pci-pic"); + if (!np) { + printk(KERN_ERR "No pci pic node in device tree.\n"); + of_node_put(np); + goto out; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR "No interrupt in pci pic node.\n"); + of_node_put(np); + goto out; + } + + priv = alloc_bootmem(sizeof(struct pq2ads_pci_pic)); + if (!priv) { + of_node_put(np); + ret = -ENOMEM; + goto out_unmap_irq; + } + + /* PCI interrupt controller registers: status and mask */ + priv->regs = of_iomap(np, 0); + if (!priv->regs) { + printk(KERN_ERR "Cannot map PCI PIC registers.\n"); + goto out_free_bootmem; + } + + /* mask all PCI interrupts */ + out_be32(&priv->regs->mask, ~0); + mb(); + + host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS, + &pci_pic_host_ops, NUM_IRQS); + if (!host) { + ret = -ENOMEM; + goto out_unmap_regs; + } + + host->host_data = priv; + + priv->host = host; + host->host_data = priv; + set_irq_data(irq, priv); + set_irq_chained_handler(irq, pq2ads_pci_irq_demux); + + of_node_put(np); + return 0; + +out_unmap_regs: + iounmap(priv->regs); +out_free_bootmem: + free_bootmem((unsigned long)priv, + sizeof(sizeof(struct pq2ads_pci_pic))); + of_node_put(np); +out_unmap_irq: + irq_dispose_mapping(irq); +out: + return ret; +} diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h index 8b67048e6f22..984db42cc8e7 100644 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ b/arch/powerpc/platforms/82xx/pq2ads.h @@ -53,7 +53,5 @@ #define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) #define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET) -void m82xx_pci_init_irq(void); - #endif /* __MACH_ADS8260_DEFS */ #endif /* __KERNEL__ */ From 3611f2ad424094655d381f099613a6f43239824d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 5 Sep 2007 14:00:54 -0500 Subject: [PATCH 0449/2804] [POWERPC] mpc82xx: Add pq2fads board support. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/pq2fads.dts | 229 ++++++ arch/powerpc/configs/pq2fads_defconfig | 1003 ++++++++++++++++++++++++ arch/powerpc/platforms/82xx/Kconfig | 11 + arch/powerpc/platforms/82xx/Makefile | 1 + arch/powerpc/platforms/82xx/pq2fads.c | 198 +++++ 5 files changed, 1442 insertions(+) create mode 100644 arch/powerpc/boot/dts/pq2fads.dts create mode 100644 arch/powerpc/configs/pq2fads_defconfig create mode 100644 arch/powerpc/platforms/82xx/pq2fads.c diff --git a/arch/powerpc/boot/dts/pq2fads.dts b/arch/powerpc/boot/dts/pq2fads.dts new file mode 100644 index 000000000000..54e8bd1ae22f --- /dev/null +++ b/arch/powerpc/boot/dts/pq2fads.dts @@ -0,0 +1,229 @@ +/* + * Device Tree for the PQ2FADS-ZU board with an MPC8280 chip. + * + * Copyright 2007 Freescale Semiconductor 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. + */ + +/ { + model = "pq2fads"; + compatible = "fsl,pq2fads"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = ; + i-cache-line-size = ; + d-cache-size = ; + i-cache-size = ; + timebase-frequency = <0>; + clock-frequency = <0>; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0>; + }; + + localbus@f0010100 { + compatible = "fsl,mpc8280-localbus", + "fsl,pq2-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = ; + + ranges = <0 0 fe000000 00800000 + 1 0 f4500000 00008000 + 8 0 f8200000 00008000>; + + flash@0,0 { + compatible = "jedec-flash"; + reg = <0 0 800000>; + bank-width = <4>; + device-width = <1>; + }; + + bcsr@1,0 { + reg = <1 0 20>; + compatible = "fsl,pq2fads-bcsr"; + }; + + PCI_PIC: pic@8,0 { + #interrupt-cells = <1>; + interrupt-controller; + reg = <8 0 8>; + compatible = "fsl,pq2ads-pci-pic"; + interrupt-parent = <&PIC>; + interrupts = <18 8>; + }; + }; + + pci@f0010800 { + device_type = "pci"; + reg = ; + compatible = "fsl,mpc8280-pci", "fsl,pq2-pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + clock-frequency = ; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x16 */ + b000 0 0 1 &PCI_PIC 0 + b000 0 0 2 &PCI_PIC 1 + b000 0 0 3 &PCI_PIC 2 + b000 0 0 4 &PCI_PIC 3 + + /* IDSEL 0x17 */ + b800 0 0 1 &PCI_PIC 4 + b800 0 0 2 &PCI_PIC 5 + b800 0 0 3 &PCI_PIC 6 + b800 0 0 4 &PCI_PIC 7 + + /* IDSEL 0x18 */ + c000 0 0 1 &PCI_PIC 8 + c000 0 0 2 &PCI_PIC 9 + c000 0 0 3 &PCI_PIC a + c000 0 0 4 &PCI_PIC b>; + + interrupt-parent = <&PIC>; + interrupts = <12 8>; + ranges = <42000000 0 80000000 80000000 0 20000000 + 02000000 0 a0000000 a0000000 0 20000000 + 01000000 0 00000000 f6000000 0 02000000>; + }; + + soc@f0000000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "fsl,mpc8280", "fsl,pq2-soc"; + ranges = <00000000 f0000000 00053000>; + + // Temporary -- will go away once kernel uses ranges for get_immrbase(). + reg = ; + + cpm@119c0 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + compatible = "fsl,mpc8280-cpm", "fsl,cpm2"; + reg = <119c0 30 0 2000>; + ranges; + + brg@119f0 { + compatible = "fsl,mpc8280-brg", + "fsl,cpm2-brg", + "fsl,cpm-brg"; + reg = <119f0 10 115f0 10>; + }; + + serial@11a00 { + device_type = "serial"; + compatible = "fsl,mpc8280-scc-uart", + "fsl,cpm2-scc-uart"; + reg = <11a00 20 8000 100>; + interrupts = <28 8>; + interrupt-parent = <&PIC>; + fsl,cpm-brg = <1>; + fsl,cpm-command = <00800000>; + }; + + serial@11a20 { + device_type = "serial"; + compatible = "fsl,mpc8280-scc-uart", + "fsl,cpm2-scc-uart"; + reg = <11a20 20 8100 100>; + interrupts = <29 8>; + interrupt-parent = <&PIC>; + fsl,cpm-brg = <2>; + fsl,cpm-command = <04a00000>; + }; + + ethernet@11320 { + device_type = "network"; + compatible = "fsl,mpc8280-fcc-enet", + "fsl,cpm2-fcc-enet"; + reg = <11320 20 8500 100 113b0 1>; + interrupts = <21 8>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY0>; + linux,network-index = <0>; + fsl,cpm-command = <16200300>; + }; + + ethernet@11340 { + device_type = "network"; + compatible = "fsl,mpc8280-fcc-enet", + "fsl,cpm2-fcc-enet"; + reg = <11340 20 8600 100 113d0 1>; + interrupts = <22 8>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY1>; + linux,network-index = <1>; + fsl,cpm-command = <1a400300>; + local-mac-address = [00 e0 0c 00 79 01]; + }; + + mdio@10d40 { + device_type = "mdio"; + compatible = "fsl,pq2fads-mdio-bitbang", + "fsl,mpc8280-mdio-bitbang", + "fsl,cpm2-mdio-bitbang"; + #address-cells = <1>; + #size-cells = <0>; + reg = <10d40 14>; + fsl,mdio-pin = <9>; + fsl,mdc-pin = ; + + PHY0: ethernet-phy@0 { + interrupt-parent = <&PIC>; + interrupts = <19 2>; + reg = <0>; + device_type = "ethernet-phy"; + }; + + PHY1: ethernet-phy@1 { + interrupt-parent = <&PIC>; + interrupts = <19 2>; + reg = <3>; + device_type = "ethernet-phy"; + }; + }; + + usb@11b60 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc8280-usb", + "fsl,cpm2-usb"; + reg = <11b60 18 8b00 100>; + interrupt-parent = <&PIC>; + interrupts = ; + fsl,cpm-command = <2e600000>; + }; + }; + + PIC: interrupt-controller@10c00 { + #interrupt-cells = <2>; + interrupt-controller; + reg = <10c00 80>; + compatible = "fsl,mpc8280-pic", "fsl,cpm2-pic"; + }; + + }; + + chosen { + linux,stdout-path = "/soc/cpm/serial@11a00"; + }; +}; diff --git a/arch/powerpc/configs/pq2fads_defconfig b/arch/powerpc/configs/pq2fads_defconfig new file mode 100644 index 000000000000..a51fc39dea4e --- /dev/null +++ b/arch/powerpc/configs/pq2fads_defconfig @@ -0,0 +1,1003 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc4 +# Thu Aug 30 11:58:17 2007 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +CONFIG_6xx=y +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_PPC_FPU=y +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_PPC_MM_SLICES is not set +# CONFIG_SMP is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +# CONFIG_EXPERIMENTAL is not set +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +# CONFIG_PPC_MULTIPLATFORM is not set +# CONFIG_EMBEDDED6xx is not set +CONFIG_PPC_82xx=y +# CONFIG_PPC_83xx is not set +# CONFIG_PPC_86xx is not set +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_MPC8272_ADS is not set +CONFIG_PQ2FADS=y +# CONFIG_EP8248E is not set +CONFIG_PQ2ADS=y +CONFIG_8260=y +CONFIG_PQ2_ADS_PCI_PIC=y +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +CONFIG_CPM2=y +CONFIG_PPC_CPM_NEW_BINDING=y +# CONFIG_FSL_ULI1575 is not set +CONFIG_CPM=y + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="pq2fads.dts" +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCI_8260=y +# CONFIG_8260_PCI9 is not set +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00400000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_IP_VS is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NF_CONNTRACK_ENABLED is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_PARTITIONS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +# CONFIG_MTD_CFI_I1 is not set +# CONFIG_MTD_CFI_I2 is not set +CONFIG_MTD_CFI_I4=y +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_SBC8240 is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +# CONFIG_IDE_GENERIC is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# An alternative FireWire stack is available with EXPERIMENTAL=y +# +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=y +# CONFIG_ARCNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +CONFIG_DAVICOM_PHY=y +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_MDIO_BITBANG=y +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set +CONFIG_FS_ENET=y +# CONFIG_FS_ENET_HAS_SCC is not set +CONFIG_FS_ENET_HAS_FCC=y +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +CONFIG_NETDEV_10000=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +CONFIG_PPP=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_CPM=y +CONFIG_SERIAL_CPM_CONSOLE=y +CONFIG_SERIAL_CPM_SCC1=y +# CONFIG_SERIAL_CPM_SCC2 is not set +# CONFIG_SERIAL_CPM_SCC3 is not set +CONFIG_SERIAL_CPM_SCC4=y +# CONFIG_SERIAL_CPM_SMC1 is not set +# CONFIG_SERIAL_CPM_SMC2 is not set +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +CONFIG_USB_GADGET_M66592=y +CONFIG_USB_M66592=y +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +CONFIG_USB_ETH=y +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_HFSPLUS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y +# CONFIG_UCC_SLOW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUGGER is not set +# CONFIG_KGDB_CONSOLE is not set +CONFIG_BDI_SWITCH=y +# CONFIG_PPC_EARLY_DEBUG is not set +# CONFIG_PPC_EARLY_DEBUG_LPAR is not set +# CONFIG_PPC_EARLY_DEBUG_G5 is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set +# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set +# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set +# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set +# CONFIG_PPC_EARLY_DEBUG_BEAT is not set +# CONFIG_PPC_EARLY_DEBUG_44x is not set +# CONFIG_PPC_EARLY_DEBUG_CPM is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +CONFIG_CRYPTO_HW=y diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 03f5aeb5fa40..541fbb815631 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -15,6 +15,17 @@ config MPC8272_ADS help This option enables support for the MPC8272 ADS board +config PQ2FADS + bool "Freescale PQ2FADS" + select DEFAULT_UIMAGE + select PQ2ADS + select 8260 + select FSL_SOC + select PQ2_ADS_PCI_PIC if PCI + select PPC_CPM_NEW_BINDING + help + This option enables support for the PQ2FADS board + endchoice config PQ2ADS diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile index bfcb64cdbd83..68c8b0c9772b 100644 --- a/arch/powerpc/platforms/82xx/Makefile +++ b/arch/powerpc/platforms/82xx/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_MPC8272_ADS) += mpc8272_ads.o obj-$(CONFIG_CPM2) += pq2.o obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o +obj-$(CONFIG_PQ2FADS) += pq2fads.o diff --git a/arch/powerpc/platforms/82xx/pq2fads.c b/arch/powerpc/platforms/82xx/pq2fads.c new file mode 100644 index 000000000000..4f457a9c79ae --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2fads.c @@ -0,0 +1,198 @@ +/* + * PQ2FADS board support + * + * Copyright 2007 Freescale Semiconductor, Inc. + * Author: Scott Wood + * + * Loosely based on mp82xx ADS support by Vitaly Bordug + * Copyright (c) 2006 MontaVista 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 "pq2ads.h" +#include "pq2.h" + +static void __init pq2fads_pic_init(void) +{ + struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); + if (!np) { + printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); + return; + } + + cpm2_pic_init(np); + of_node_put(np); + + /* Initialize stuff for the 82xx CPLD IC and install demux */ + pq2ads_pci_init_irq(); +} + +struct cpm_pin { + int port, pin, flags; +}; + +static struct cpm_pin pq2fads_pins[] = { + /* SCC1 */ + {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* SCC2 */ + {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC2 */ + {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC3 */ + {1, 4, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 6, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 7, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 12, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 13, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 14, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 15, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, +}; + +static void __init init_ioports(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pq2fads_pins); i++) { + struct cpm_pin *pin = &pq2fads_pins[i]; + cpm2_set_pin(pin->port, pin->pin, pin->flags); + } + + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK15, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK16, CPM_CLK_TX); +} + +static void __init pq2fads_setup_arch(void) +{ + struct device_node *np; + __be32 __iomem *bcsr; + + if (ppc_md.progress) + ppc_md.progress("pq2fads_setup_arch()", 0); + + cpm2_reset(); + + np = of_find_compatible_node(NULL, NULL, "fsl,pq2fads-bcsr"); + if (!np) { + printk(KERN_ERR "No fsl,pq2fads-bcsr in device tree\n"); + return; + } + + bcsr = of_iomap(np, 0); + if (!bcsr) { + printk(KERN_ERR "Cannot map BCSR registers\n"); + return; + } + + of_node_put(np); + + /* Enable the serial and ethernet ports */ + + clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); + setbits32(&bcsr[1], BCSR1_FETH_RST); + + clrbits32(&bcsr[3], BCSR3_FETHIEN2); + setbits32(&bcsr[3], BCSR3_FETH2_RST); + + iounmap(bcsr); + + init_ioports(); + + /* Enable external IRQs */ + clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_siumcr, 0x0c000000); + + pq2_init_pci(); + + if (ppc_md.progress) + ppc_md.progress("pq2fads_setup_arch(), finish", 0); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init pq2fads_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "fsl,pq2fads"); +} + +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + if (!machine_is(pq2fads)) + return 0; + + /* Publish the QE devices */ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} +device_initcall(declare_of_platform_devices); + +define_machine(pq2fads) +{ + .name = "Freescale PQ2FADS", + .probe = pq2fads_probe, + .setup_arch = pq2fads_setup_arch, + .init_IRQ = pq2fads_pic_init, + .get_irq = cpm2_get_irq, + .calibrate_decr = generic_calibrate_decr, + .restart = pq2_restart, + .progress = udbg_progress, +}; From c4e05bc57dd14294683cdea7fe36ce3c01f5c6ae Mon Sep 17 00:00:00 2001 From: Roy Zang Date: Mon, 24 Sep 2007 18:31:55 +0800 Subject: [PATCH 0450/2804] [POWERPC] bootwrapper: adds cuboot for MPC7448HPC2 platform This patch adds cuboot support for MPC7448HPC2 platform. The cuImage can be used with legacy u-boot without FDT support. Signed-off-by: Roy Zang Acked-by: David Gibson Signed-off-by: Kumar Gala --- arch/powerpc/boot/Makefile | 3 +- arch/powerpc/boot/cuboot-hpc2.c | 48 ++++++++++++++++++++++ arch/powerpc/boot/dts/mpc7448hpc2.dts | 5 +++ arch/powerpc/platforms/embedded6xx/Kconfig | 1 + 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/cuboot-hpc2.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index a90baa3aff23..f3f7ce3d79a5 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -52,7 +52,7 @@ src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \ - fixed-head.S ep88xc.c + fixed-head.S ep88xc.c cuboot-hpc2.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -150,6 +150,7 @@ image-$(CONFIG_8260) += cuImage.pq2 image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx image-$(CONFIG_PPC_83xx) += cuImage.83xx image-$(CONFIG_PPC_85xx) += cuImage.85xx +image-$(CONFIG_MPC7448HPC2) += cuImage.hpc2 image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo image-$(CONFIG_SEQUOIA) += cuImage.sequoia diff --git a/arch/powerpc/boot/cuboot-hpc2.c b/arch/powerpc/boot/cuboot-hpc2.c new file mode 100644 index 000000000000..d333898bca30 --- /dev/null +++ b/arch/powerpc/boot/cuboot-hpc2.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Roy Zang + * + * Description: + * Old U-boot compatibility for mpc7448hpc2 board + * Based on the code of Scott Wood + * for 83xx and 85xx. + * + * This 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 "ops.h" +#include "stdio.h" +#include "cuboot.h" + +#define TARGET_HAS_ETH1 +#include "ppcboot.h" + +static bd_t bd; +extern char _dtb_start[], _dtb_end[]; + +static void platform_fixups(void) +{ + void *tsi; + + dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); + dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr); + dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); + tsi = find_node_by_devtype(NULL, "tsi-bridge"); + if (tsi) + setprop(tsi, "bus-frequency", &bd.bi_busfreq, + sizeof(bd.bi_busfreq)); +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + CUBOOT_INIT(); + ft_init(_dtb_start, _dtb_end - _dtb_start, 32); + serial_console_init(); + platform_ops.fixups = platform_fixups; +} diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts index 88cd37da13ef..8fb542387436 100644 --- a/arch/powerpc/boot/dts/mpc7448hpc2.dts +++ b/arch/powerpc/boot/dts/mpc7448hpc2.dts @@ -78,6 +78,7 @@ }; ethernet@6200 { + linux,network-index = <0>; #size-cells = <0>; device_type = "network"; compatible = "tsi108-ethernet"; @@ -90,6 +91,7 @@ }; ethernet@6600 { + linux,network-index = <1>; #address-cells = <1>; #size-cells = <0>; device_type = "network"; @@ -183,5 +185,8 @@ }; }; }; + chosen { + linux,stdout-path = "/tsi108@c0000000/serial@7808"; + }; }; diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index da66103009c6..8924095a7928 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -22,6 +22,7 @@ config MPC7448HPC2 select TSI108_BRIDGE select DEFAULT_UIMAGE select PPC_UDBG_16550 + select WANT_DEVICE_TREE help Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) platform From 5dd57a1308a7e40e04fb6ecbff170df7a0b92cd8 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 18 Sep 2007 15:29:35 -0500 Subject: [PATCH 0451/2804] [POWERPC] 8xx: Move softemu8xx.c from arch/ppc Previously, Soft_emulate_8xx was called with no implementation, resulting in build failures whenever building 8xx without math emulation. The implementation is copied from arch/ppc to resolve this issue. However, this sort of minimal emulation is not a very good idea other than for compatibility with existing userspaces, as it's less efficient than soft-float and can mislead users into believing they have soft-float. Thus, it is made a configurable option, off by default. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/Kconfig | 11 ++ arch/powerpc/kernel/Makefile | 2 + arch/powerpc/kernel/softemu8xx.c | 202 +++++++++++++++++++++++++++++++ arch/powerpc/kernel/traps.c | 6 +- 4 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/kernel/softemu8xx.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 6f5155d8c324..31804575dd5e 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -198,6 +198,17 @@ config MATH_EMULATION unit, which will allow programs that use floating-point instructions to run. +config 8XX_MINIMAL_FPEMU + bool "Minimal math emulation for 8xx" + depends on 8xx && !MATH_EMULATION + help + Older arch/ppc kernels still emulated a few floating point + instructions such as load and store, even when full math + emulation is disabled. Say "Y" here if you want to preserve + this behavior. + + It is recommended that you build a soft-float userspace instead. + config IOMMU_VMERGE bool "Enable IOMMU virtual merging" depends on PPC64 diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 8327d92eeca8..ca51f0cf27ab 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -75,6 +75,8 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \ obj-$(CONFIG_AUDIT) += audit.o obj64-$(CONFIG_AUDIT) += compat_audit.o +obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o + ifneq ($(CONFIG_PPC_INDIRECT_IO),y) obj-y += iomap.o endif diff --git a/arch/powerpc/kernel/softemu8xx.c b/arch/powerpc/kernel/softemu8xx.c new file mode 100644 index 000000000000..67d6f6890edc --- /dev/null +++ b/arch/powerpc/kernel/softemu8xx.c @@ -0,0 +1,202 @@ +/* + * Software emulation of some PPC instructions for the 8xx core. + * + * Copyright (C) 1998 Dan Malek (dmalek@jlc.net) + * + * Software floating emuation for the MPC8xx processor. I did this mostly + * because it was easier than trying to get the libraries compiled for + * software floating point. The goal is still to get the libraries done, + * but I lost patience and needed some hacks to at least get init and + * shells running. The first problem is the setjmp/longjmp that save + * and restore the floating point registers. + * + * For this emulation, our working registers are found on the register + * save area. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Eventually we may need a look-up table, but this works for now. +*/ +#define LFS 48 +#define LFD 50 +#define LFDU 51 +#define STFD 54 +#define STFDU 55 +#define FMR 63 + +void print_8xx_pte(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + printk(" pte @ 0x%8lx: ", addr); + pgd = pgd_offset(mm, addr & PAGE_MASK); + if (pgd) { + pmd = pmd_offset(pud_offset(pgd, addr & PAGE_MASK), + addr & PAGE_MASK); + if (pmd && pmd_present(*pmd)) { + pte = pte_offset_kernel(pmd, addr & PAGE_MASK); + if (pte) { + printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n", + (long)pgd, (long)pte, (long)pte_val(*pte)); +#define pp ((long)pte_val(*pte)) + printk(" RPN: %05lx PP: %lx SPS: %lx SH: %lx " + "CI: %lx v: %lx\n", + pp>>12, /* rpn */ + (pp>>10)&3, /* pp */ + (pp>>3)&1, /* small */ + (pp>>2)&1, /* shared */ + (pp>>1)&1, /* cache inhibit */ + pp&1 /* valid */ + ); +#undef pp + } + else { + printk("no pte\n"); + } + } + else { + printk("no pmd\n"); + } + } + else { + printk("no pgd\n"); + } +} + +int get_8xx_pte(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int retval = 0; + + pgd = pgd_offset(mm, addr & PAGE_MASK); + if (pgd) { + pmd = pmd_offset(pud_offset(pgd, addr & PAGE_MASK), + addr & PAGE_MASK); + if (pmd && pmd_present(*pmd)) { + pte = pte_offset_kernel(pmd, addr & PAGE_MASK); + if (pte) { + retval = (int)pte_val(*pte); + } + } + } + return retval; +} + +/* + * We return 0 on success, 1 on unimplemented instruction, and EFAULT + * if a load/store faulted. + */ +int Soft_emulate_8xx(struct pt_regs *regs) +{ + u32 inst, instword; + u32 flreg, idxreg, disp; + int retval; + s16 sdisp; + u32 *ea, *ip; + + retval = 0; + + instword = *((u32 *)regs->nip); + inst = instword >> 26; + + flreg = (instword >> 21) & 0x1f; + idxreg = (instword >> 16) & 0x1f; + disp = instword & 0xffff; + + ea = (u32 *)(regs->gpr[idxreg] + disp); + ip = (u32 *)¤t->thread.fpr[flreg]; + + switch ( inst ) + { + case LFD: + /* this is a 16 bit quantity that is sign extended + * so use a signed short here -- Cort + */ + sdisp = (instword & 0xffff); + ea = (u32 *)(regs->gpr[idxreg] + sdisp); + if (copy_from_user(ip, ea, sizeof(double))) + retval = -EFAULT; + break; + + case LFDU: + if (copy_from_user(ip, ea, sizeof(double))) + retval = -EFAULT; + else + regs->gpr[idxreg] = (u32)ea; + break; + case LFS: + sdisp = (instword & 0xffff); + ea = (u32 *)(regs->gpr[idxreg] + sdisp); + if (copy_from_user(ip, ea, sizeof(float))) + retval = -EFAULT; + break; + case STFD: + /* this is a 16 bit quantity that is sign extended + * so use a signed short here -- Cort + */ + sdisp = (instword & 0xffff); + ea = (u32 *)(regs->gpr[idxreg] + sdisp); + if (copy_to_user(ea, ip, sizeof(double))) + retval = -EFAULT; + break; + + case STFDU: + if (copy_to_user(ea, ip, sizeof(double))) + retval = -EFAULT; + else + regs->gpr[idxreg] = (u32)ea; + break; + case FMR: + /* assume this is a fp move -- Cort */ + memcpy(ip, ¤t->thread.fpr[(instword>>11)&0x1f], + sizeof(double)); + break; + default: + retval = 1; + printk("Bad emulation %s/%d\n" + " NIP: %08lx instruction: %08x opcode: %x " + "A: %x B: %x C: %x code: %x rc: %x\n", + current->comm,current->pid, + regs->nip, + instword,inst, + (instword>>16)&0x1f, + (instword>>11)&0x1f, + (instword>>6)&0x1f, + (instword>>1)&0x3ff, + instword&1); + { + int pa; + print_8xx_pte(current->mm,regs->nip); + pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK; + pa |= (regs->nip & ~PAGE_MASK); + pa = (unsigned long)__va(pa); + printk("Kernel VA for NIP %x ", pa); + print_8xx_pte(current->mm,pa); + } + } + + if (retval == 0) + regs->nip += 4; + + return retval; +} diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5a49eabd492e..2f1857c9819f 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -906,7 +906,9 @@ void SoftwareEmulation(struct pt_regs *regs) { extern int do_mathemu(struct pt_regs *); extern int Soft_emulate_8xx(struct pt_regs *); +#if defined(CONFIG_MATH_EMULATION) || defined(CONFIG_8XX_MINIMAL_FPEMU) int errcode; +#endif CHECK_FULL_REGS(regs); @@ -936,7 +938,7 @@ void SoftwareEmulation(struct pt_regs *regs) return; } -#else +#elif defined(CONFIG_8XX_MINIMAL_FPEMU) errcode = Soft_emulate_8xx(regs); switch (errcode) { case 0: @@ -949,6 +951,8 @@ void SoftwareEmulation(struct pt_regs *regs) _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); return; } +#else + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); #endif } #endif /* CONFIG_8xx */ From 210805e219f781d0a0efbdbe41d59f6fccef529c Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 20 Sep 2007 12:42:12 +0200 Subject: [PATCH 0452/2804] [POWERPC] fsl_soc: Fix trivial printk typo. Fix a trivial printk typo in fsl_soc. Cc: G. Liakhovetski Signed-off-by: Peter Korsgaard Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index b465b30c9547..ef880cb54c1d 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -363,7 +363,7 @@ static void __init of_register_i2c_devices(struct device_node *adap_node, addr = of_get_property(node, "reg", &len); if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) { - printk(KERN_WARNING "fsl_ioc.c: invalid i2c device entry\n"); + printk(KERN_WARNING "fsl_soc.c: invalid i2c device entry\n"); continue; } From 0438c28fa40c1145e8322f91feb9e6fed3301d94 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 20 Sep 2007 12:42:13 +0200 Subject: [PATCH 0453/2804] [POWERPC] fsl_soc: rtc-ds1307 support Add support for the I2C devices handled by the rtc-ds1307 driver to of_register_i2c_devices. Cc: G. Liakhovetski Signed-off-by: Peter Korsgaard Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_soc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index ef880cb54c1d..4a1645691fb1 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -331,6 +331,12 @@ static struct i2c_driver_device i2c_devices[] __initdata = { {"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",}, {"ricoh,rv5c386", "rtc-rs5c372", "rv5c386",}, {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",}, + {"dallas,ds1307", "rtc-ds1307", "ds1307",}, + {"dallas,ds1337", "rtc-ds1307", "ds1337",}, + {"dallas,ds1338", "rtc-ds1307", "ds1338",}, + {"dallas,ds1339", "rtc-ds1307", "ds1339",}, + {"dallas,ds1340", "rtc-ds1307", "ds1340",}, + {"stm,m41t00", "rtc-ds1307", "m41t00"}, }; static int __init of_find_i2c_driver(struct device_node *node, From b6927bca245f83879bcb319aa108a1a347e36d8f Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Wed, 26 Sep 2007 12:03:40 -0500 Subject: [PATCH 0454/2804] [POWERPC] QE: Added missing CEURNR register According to the publicly available MPC8360E RM (rev. 1 from 09/2006 and rev. 2 from 05/2007) and MPC8323E RM (rev. 1 from 09/2006), CEURNR is the QE microcode revision number register and is located at offset 0x1b8 within the QE internal register space Signed-off-by: Emil Medve Signed-off-by: Kumar Gala --- include/asm-powerpc/immap_qe.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h index 1020b7fc0129..02548f74ccb7 100644 --- a/include/asm-powerpc/immap_qe.h +++ b/include/asm-powerpc/immap_qe.h @@ -86,8 +86,9 @@ struct cp_qe { __be16 ceexe4; /* QE external request 4 event register */ u8 res11[0x2]; __be16 ceexm4; /* QE external request 4 mask register */ - u8 res12[0x2]; - u8 res13[0x280]; + u8 res12[0x3A]; + __be32 ceurnr; /* QE microcode revision number register */ + u8 res13[0x244]; } __attribute__ ((packed)); /* QE Multiplexer */ From 3c5df5c26ed17828760945d59653a2e22e3fb63f Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 27 Sep 2007 08:43:35 -0500 Subject: [PATCH 0455/2804] [POWERPC] Cleaned up whitespace in head_fsl_booke.S Signed-off-by: Kumar Gala --- arch/powerpc/kernel/head_fsl_booke.S | 76 ++++++++++++++-------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index bfc38703a8ac..ee33ddd97ef3 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -2,27 +2,27 @@ * Kernel execution entry point code. * * Copyright (c) 1995-1996 Gary Thomas - * Initial PowerPC version. + * Initial PowerPC version. * Copyright (c) 1996 Cort Dougan - * Rewritten for PReP + * Rewritten for PReP * Copyright (c) 1996 Paul Mackerras - * Low-level exception handers, MMU support, and rewrite. + * Low-level exception handers, MMU support, and rewrite. * Copyright (c) 1997 Dan Malek - * PowerPC 8xx modifications. + * PowerPC 8xx modifications. * Copyright (c) 1998-1999 TiVo, Inc. - * PowerPC 403GCX modifications. + * PowerPC 403GCX modifications. * Copyright (c) 1999 Grant Erickson - * PowerPC 403GCX/405GP modifications. + * PowerPC 403GCX/405GP modifications. * Copyright 2000 MontaVista Software Inc. * PPC405 modifications - * PowerPC 403GCX/405GP modifications. - * Author: MontaVista Software, Inc. - * frank_rowand@mvista.com or source@mvista.com - * debbie_chu@mvista.com + * PowerPC 403GCX/405GP modifications. + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com * Copyright 2002-2004 MontaVista Software, Inc. - * PowerPC 44x support, Matt Porter + * PowerPC 44x support, Matt Porter * Copyright 2004 Freescale Semiconductor, Inc - * PowerPC e500 modifications, Kumar Gala + * PowerPC e500 modifications, Kumar Gala * * 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 @@ -146,13 +146,13 @@ skpinv: addi r6,r6,1 /* Increment */ bne 1b /* If not, repeat */ /* Invalidate TLB0 */ - li r6,0x04 + li r6,0x04 tlbivax 0,r6 #ifdef CONFIG_SMP tlbsync #endif /* Invalidate TLB1 */ - li r6,0x0c + li r6,0x0c tlbivax 0,r6 #ifdef CONFIG_SMP tlbsync @@ -211,7 +211,7 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_MAS1,r6 tlbwe /* Invalidate TLB1 */ - li r9,0x0c + li r9,0x0c tlbivax 0,r9 #ifdef CONFIG_SMP tlbsync @@ -254,7 +254,7 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_MAS1,r8 tlbwe /* Invalidate TLB1 */ - li r9,0x0c + li r9,0x0c tlbivax 0,r9 #ifdef CONFIG_SMP tlbsync @@ -294,7 +294,7 @@ skpinv: addi r6,r6,1 /* Increment */ #ifdef CONFIG_E200 oris r2,r2,MAS4_TLBSELD(1)@h #endif - mtspr SPRN_MAS4, r2 + mtspr SPRN_MAS4, r2 #if 0 /* Enable DOZE */ @@ -305,7 +305,7 @@ skpinv: addi r6,r6,1 /* Increment */ #ifdef CONFIG_E200 /* enable dedicated debug exception handling resources (Debug APU) */ mfspr r2,SPRN_HID0 - ori r2,r2,HID0_DAPUEN@l + ori r2,r2,HID0_DAPUEN@l mtspr SPRN_HID0,r2 #endif @@ -391,7 +391,7 @@ skpinv: addi r6,r6,1 /* Increment */ #ifdef CONFIG_PTE_64BIT #define PTE_FLAGS_OFFSET 4 #define FIND_PTE \ - rlwinm r12, r10, 13, 19, 29; /* Compute pgdir/pmd offset */ \ + rlwinm r12, r10, 13, 19, 29; /* Compute pgdir/pmd offset */ \ lwzx r11, r12, r11; /* Get pgd/pmd entry */ \ rlwinm. r12, r11, 0, 0, 20; /* Extract pt base address */ \ beq 2f; /* Bail if no table */ \ @@ -487,7 +487,7 @@ interrupt_base: */ andi. r11, r11, _PAGE_HWEXEC rlwimi r11, r11, 31, 27, 27 /* SX <- _PAGE_HWEXEC */ - ori r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */ + ori r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */ /* update search PID in MAS6, AS = 0 */ mfspr r12, SPRN_PID0 @@ -694,7 +694,7 @@ interrupt_base: START_EXCEPTION(SPEUnavailable) NORMAL_EXCEPTION_PROLOG bne load_up_spe - addi r3,r1,STACK_FRAME_OVERHEAD + addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE_LITE(0x2010, KernelSPE) #else EXCEPTION(0x2020, SPEUnavailable, unknown_exception, EXC_XFER_EE) @@ -741,10 +741,10 @@ data_access: * Both the instruction and data TLB miss get to this * point to load the TLB. - * r10 - EA of fault - * r11 - TLB (info from Linux PTE) - * r12, r13 - available to use - * CR5 - results of addr < TASK_SIZE + * r10 - EA of fault + * r11 - TLB (info from Linux PTE) + * r12, r13 - available to use + * CR5 - results of addr < TASK_SIZE * MAS0, MAS1 - loaded with proper value when we get here * MAS2, MAS3 - will need additional info from Linux PTE * Upon exit, we reload everything and RFI. @@ -813,7 +813,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS) lwz r13, tlbcam_index@l(r13) rlwimi r12, r13, 0, 20, 31 7: - mtspr SPRN_MAS0,r12 + mtspr SPRN_MAS0,r12 #endif /* CONFIG_E200 */ tlbwe @@ -855,17 +855,17 @@ load_up_spe: beq 1f addi r4,r4,THREAD /* want THREAD of last_task_used_spe */ SAVE_32EVRS(0,r10,r4) - evxor evr10, evr10, evr10 /* clear out evr10 */ + evxor evr10, evr10, evr10 /* clear out evr10 */ evmwumiaa evr10, evr10, evr10 /* evr10 <- ACC = 0 * 0 + ACC */ li r5,THREAD_ACC - evstddx evr10, r4, r5 /* save off accumulator */ + evstddx evr10, r4, r5 /* save off accumulator */ lwz r5,PT_REGS(r4) lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) lis r10,MSR_SPE@h andc r4,r4,r10 /* disable SPE for previous task */ stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1: -#endif /* CONFIG_SMP */ +#endif /* !CONFIG_SMP */ /* enable use of SPE after return */ oris r9,r9,MSR_SPE@h mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ @@ -878,7 +878,7 @@ load_up_spe: #ifndef CONFIG_SMP subi r4,r5,THREAD stw r4,last_task_used_spe@l(r3) -#endif /* CONFIG_SMP */ +#endif /* !CONFIG_SMP */ /* restore registers and return */ 2: REST_4GPRS(3, r11) lwz r10,_CCR(r11) @@ -963,10 +963,10 @@ _GLOBAL(giveup_spe) lwz r5,PT_REGS(r3) cmpi 0,r5,0 SAVE_32EVRS(0, r4, r3) - evxor evr6, evr6, evr6 /* clear out evr6 */ + evxor evr6, evr6, evr6 /* clear out evr6 */ evmwumiaa evr6, evr6, evr6 /* evr6 <- ACC = 0 * 0 + ACC */ li r4,THREAD_ACC - evstddx evr6, r4, r3 /* save off accumulator */ + evstddx evr6, r4, r3 /* save off accumulator */ mfspr r6,SPRN_SPEFSCR stw r6,THREAD_SPEFSCR(r3) /* save spefscr register value */ beq 1f @@ -979,7 +979,7 @@ _GLOBAL(giveup_spe) li r5,0 lis r4,last_task_used_spe@ha stw r5,last_task_used_spe@l(r4) -#endif /* CONFIG_SMP */ +#endif /* !CONFIG_SMP */ blr #endif /* CONFIG_SPE */ @@ -1000,15 +1000,15 @@ _GLOBAL(giveup_fpu) */ _GLOBAL(abort) li r13,0 - mtspr SPRN_DBCR0,r13 /* disable all debug events */ + mtspr SPRN_DBCR0,r13 /* disable all debug events */ isync mfmsr r13 ori r13,r13,MSR_DE@l /* Enable Debug Events */ mtmsr r13 isync - mfspr r13,SPRN_DBCR0 - lis r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h - mtspr SPRN_DBCR0,r13 + mfspr r13,SPRN_DBCR0 + lis r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h + mtspr SPRN_DBCR0,r13 isync _GLOBAL(set_context) @@ -1043,7 +1043,7 @@ swapper_pg_dir: /* Reserved 4k for the critical exception stack & 4k for the machine * check stack per CPU for kernel mode exceptions */ .section .bss - .align 12 + .align 12 exception_stack_bottom: .space BOOKE_EXCEPTION_STACK_SIZE * NR_CPUS .globl exception_stack_top From 15f8c604a79c4840ed76eecf3af5d88b7c1dee9e Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 28 Sep 2007 14:06:16 -0500 Subject: [PATCH 0456/2804] [POWERPC] cpm: Describe multi-user ram in its own device node. The way the current CPM binding describes available multi-user (a.k.a. dual-ported) RAM doesn't work well when there are multiple free regions, and it doesn't work at all if the region doesn't begin at the start of the muram area (as the hardware needs to be programmed with offsets into this area). The latter situation can happen with SMC UARTs on CPM2, as its parameter RAM is relocatable, u-boot puts it at zero, and the kernel doesn't support moving it. It is now described with a muram node, similar to QE. The current CPM binding is sufficiently recent (i.e. never appeared in an official release) that compatibility with existing device trees is not an issue. The code supporting the new binding is shared between cpm1 and cpm2, rather than remain separated. QE should be able to use this code as well, once minor fixes are made to its device trees. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- Documentation/powerpc/booting-without-of.txt | 40 ++++- arch/powerpc/Kconfig.debug | 6 +- arch/powerpc/boot/cpm-serial.c | 44 +++-- arch/powerpc/boot/dts/ep88xc.dts | 13 +- arch/powerpc/boot/dts/mpc8272ads.dts | 11 ++ arch/powerpc/boot/dts/mpc885ads.dts | 13 +- arch/powerpc/boot/dts/pq2fads.dts | 13 +- arch/powerpc/sysdev/commproc.c | 11 +- arch/powerpc/sysdev/cpm2_common.c | 35 ++-- arch/powerpc/sysdev/cpm_common.c | 159 +++++++++++++++++++ drivers/serial/cpm_uart/cpm_uart_cpm2.c | 4 +- include/asm-powerpc/commproc.h | 12 ++ include/asm-powerpc/cpm.h | 14 ++ include/asm-powerpc/cpm2.h | 10 ++ 14 files changed, 337 insertions(+), 48 deletions(-) create mode 100644 include/asm-powerpc/cpm.h diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index c36dcd2fbdc4..ce5d67f5cb5c 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1861,9 +1861,7 @@ platforms are moved over to use the flattened-device-tree model. Properties: - compatible : "fsl,cpm1", "fsl,cpm2", or "fsl,qe". - - reg : The first resource is a 48-byte region beginning with - CPCR. The second is the available general-purpose - DPRAM. + - reg : A 48-byte region beginning with CPCR. Example: cpm@119c0 { @@ -1871,7 +1869,7 @@ platforms are moved over to use the flattened-device-tree model. #size-cells = <1>; #interrupt-cells = <2>; compatible = "fsl,mpc8272-cpm", "fsl,cpm2"; - reg = <119c0 30 0 2000>; + reg = <119c0 30>; } ii) Properties common to mulitple CPM/QE devices @@ -2017,6 +2015,40 @@ platforms are moved over to use the flattened-device-tree model. fsl,cpm-command = <2e600000>; }; + viii) Multi-User RAM (MURAM) + + The multi-user/dual-ported RAM is expressed as a bus under the CPM node. + + Ranges must be set up subject to the following restrictions: + + - Children's reg nodes must be offsets from the start of all muram, even + if the user-data area does not begin at zero. + - If multiple range entries are used, the difference between the parent + address and the child address must be the same in all, so that a single + mapping can cover them all while maintaining the ability to determine + CPM-side offsets with pointer subtraction. It is recommended that + multiple range entries not be used. + - A child address of zero must be translatable, even if no reg resources + contain it. + + A child "data" node must exist, compatible with "fsl,cpm-muram-data", to + indicate the portion of muram that is usable by the OS for arbitrary + purposes. The data node may have an arbitrary number of reg resources, + all of which contribute to the allocatable muram pool. + + Example, based on mpc8272: + + muram@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9800 800>; + }; + }; + m) Chipselect/Local Bus Properties: diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index f4e5d22312a0..464f9b4b3169 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -245,9 +245,9 @@ config PPC_EARLY_DEBUG_44x_PHYSHIGH config PPC_EARLY_DEBUG_CPM_ADDR hex "CPM UART early debug transmit descriptor address" depends on PPC_EARLY_DEBUG_CPM - default "0xfa202808" if PPC_EP88XC - default "0xf0000808" if CPM2 - default "0xff002808" if CPM1 + default "0xfa202008" if PPC_EP88XC + default "0xf0000008" if CPM2 + default "0xff002008" if CPM1 help This specifies the address of the transmit descriptor used for early debug output. Because it is needed before diff --git a/arch/powerpc/boot/cpm-serial.c b/arch/powerpc/boot/cpm-serial.c index fcb8b5e956bd..28296facb2ae 100644 --- a/arch/powerpc/boot/cpm-serial.c +++ b/arch/powerpc/boot/cpm-serial.c @@ -56,7 +56,8 @@ static struct cpm_smc *smc; static struct cpm_scc *scc; struct cpm_bd *tbdf, *rbdf; static u32 cpm_cmd; -static u8 *dpram_start; +static u8 *muram_start; +static u32 muram_offset; static void (*do_cmd)(int op); static void (*enable_port)(void); @@ -114,13 +115,12 @@ static void scc_enable_port(void) static int cpm_serial_open(void) { - int dpaddr = 0x800; disable_port(); out_8(¶m->rfcr, 0x10); out_8(¶m->tfcr, 0x10); - rbdf = (struct cpm_bd *)(dpram_start + dpaddr); + rbdf = (struct cpm_bd *)muram_start; rbdf->addr = (u8 *)(rbdf + 2); rbdf->sc = 0xa000; rbdf->len = 1; @@ -131,8 +131,8 @@ static int cpm_serial_open(void) tbdf->len = 1; sync(); - out_be16(¶m->rbase, dpaddr); - out_be16(¶m->tbase, dpaddr + sizeof(struct cpm_bd)); + out_be16(¶m->rbase, muram_offset); + out_be16(¶m->tbase, muram_offset + sizeof(struct cpm_bd)); do_cmd(CPM_CMD_INIT_RX_TX); @@ -178,7 +178,7 @@ int cpm_console_init(void *devp, struct serial_console_data *scdp) void *reg_virt[2]; int is_smc = 0, is_cpm2 = 0, n; unsigned long reg_phys; - void *parent; + void *parent, *muram; if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) { is_smc = 1; @@ -229,16 +229,36 @@ int cpm_console_init(void *devp, struct serial_console_data *scdp) n = getprop(parent, "virtual-reg", reg_virt, sizeof(reg_virt)); if (n < (int)sizeof(reg_virt)) { - for (n = 0; n < 2; n++) { - if (!dt_xlate_reg(parent, n, ®_phys, NULL)) - return -1; + if (!dt_xlate_reg(parent, 0, ®_phys, NULL)) + return -1; - reg_virt[n] = (void *)reg_phys; - } + reg_virt[0] = (void *)reg_phys; } cpcr = reg_virt[0]; - dpram_start = reg_virt[1]; + + muram = finddevice("/soc/cpm/muram/data"); + if (!muram) + return -1; + + /* For bootwrapper-compatible device trees, we assume that the first + * entry has at least 18 bytes, and that #address-cells/#data-cells + * is one for both parent and child. + */ + + n = getprop(muram, "virtual-reg", reg_virt, sizeof(reg_virt)); + if (n < (int)sizeof(reg_virt)) { + if (!dt_xlate_reg(muram, 0, ®_phys, NULL)) + return -1; + + reg_virt[0] = (void *)reg_phys; + } + + muram_start = reg_virt[0]; + + n = getprop(muram, "reg", &muram_offset, 4); + if (n < 4) + return -1; scdp->open = cpm_serial_open; scdp->putc = cpm_serial_putc; diff --git a/arch/powerpc/boot/dts/ep88xc.dts b/arch/powerpc/boot/dts/ep88xc.dts index 0406fc50b2af..02705f299790 100644 --- a/arch/powerpc/boot/dts/ep88xc.dts +++ b/arch/powerpc/boot/dts/ep88xc.dts @@ -142,9 +142,20 @@ command-proc = <9c0>; interrupts = <0>; // cpm error interrupt interrupt-parent = <&CPM_PIC>; - reg = <9c0 40 2000 1c00>; + reg = <9c0 40>; ranges; + muram@2000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 2000 2000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 1c00>; + }; + }; + brg@9f0 { compatible = "fsl,mpc885-brg", "fsl,cpm1-brg", diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts index 3fe991d4cb03..188179df0845 100644 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -124,6 +124,17 @@ reg = <119c0 30 0 2000>; ranges; + muram@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9800 800>; + }; + }; + brg@119f0 { compatible = "fsl,mpc8272-brg", "fsl,cpm2-brg", diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts index cbcd16f74c45..8848e637293e 100644 --- a/arch/powerpc/boot/dts/mpc885ads.dts +++ b/arch/powerpc/boot/dts/mpc885ads.dts @@ -148,9 +148,20 @@ command-proc = <9c0>; interrupts = <0>; // cpm error interrupt interrupt-parent = <&CPM_PIC>; - reg = <9c0 40 2000 1c00>; + reg = <9c0 40>; ranges; + muram@2000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 2000 2000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 1c00>; + }; + }; + brg@9f0 { compatible = "fsl,mpc885-brg", "fsl,cpm1-brg", diff --git a/arch/powerpc/boot/dts/pq2fads.dts b/arch/powerpc/boot/dts/pq2fads.dts index 54e8bd1ae22f..2d564921897a 100644 --- a/arch/powerpc/boot/dts/pq2fads.dts +++ b/arch/powerpc/boot/dts/pq2fads.dts @@ -119,9 +119,20 @@ #size-cells = <1>; #interrupt-cells = <2>; compatible = "fsl,mpc8280-cpm", "fsl,cpm2"; - reg = <119c0 30 0 2000>; + reg = <119c0 30>; ranges; + muram@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9800 800>; + }; + }; + brg@119f0 { compatible = "fsl,mpc8280-brg", "fsl,cpm2-brg", diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c index 428eb8c151b9..f6a63780bbde 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/commproc.c @@ -39,12 +39,15 @@ #include #include #include +#include #include #define CPM_MAP_SIZE (0x4000) +#ifndef CONFIG_PPC_CPM_NEW_BINDING static void m8xx_cpm_dpinit(void); +#endif static uint host_buffer; /* One page of host buffer */ static uint host_end; /* end + 1 */ cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ @@ -193,7 +196,7 @@ end: return sirq; } -void cpm_reset(void) +void __init cpm_reset(void) { sysconf8xx_t __iomem *siu_conf; @@ -229,8 +232,12 @@ void cpm_reset(void) out_be32(&siu_conf->sc_sdcr, 1); immr_unmap(siu_conf); +#ifdef CONFIG_PPC_CPM_NEW_BINDING + cpm_muram_init(); +#else /* Reclaim the DP memory for our use. */ m8xx_cpm_dpinit(); +#endif } /* We used to do this earlier, but have to postpone as long as possible @@ -296,6 +303,7 @@ cpm_setbrg(uint brg, uint rate) CPM_BRG_EN | CPM_BRG_DIV16); } +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* * dpalloc / dpfree bits. */ @@ -397,6 +405,7 @@ uint cpm_dpram_phys(u8 *addr) return (dpram_pbase + (uint)(addr - dpram_vbase)); } EXPORT_SYMBOL(cpm_dpram_phys); +#endif /* !CONFIG_PPC_CPM_NEW_BINDING */ struct cpm_ioport16 { __be16 dir, par, sor, dat, intr; diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c index fc4c99565381..859362fecb7c 100644 --- a/arch/powerpc/sysdev/cpm2_common.c +++ b/arch/powerpc/sysdev/cpm2_common.c @@ -46,7 +46,10 @@ #include +#ifndef CONFIG_PPC_CPM_NEW_BINDING static void cpm2_dpinit(void); +#endif + cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */ /* We allocate this here because it is used almost exclusively for @@ -69,7 +72,11 @@ cpm2_reset(void) /* Reclaim the DP memory for our use. */ +#ifdef CONFIG_PPC_CPM_NEW_BINDING + cpm_muram_init(); +#else cpm2_dpinit(); +#endif /* Tell everyone where the comm processor resides. */ @@ -316,6 +323,7 @@ int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock) return ret; } +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* * dpalloc / dpfree bits. */ @@ -328,28 +336,6 @@ static u8 __iomem *im_dprambase; static void cpm2_dpinit(void) { - struct resource r; - -#ifdef CONFIG_PPC_CPM_NEW_BINDING - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,cpm2"); - if (!np) - panic("Cannot find CPM2 node"); - - if (of_address_to_resource(np, 1, &r)) - panic("Cannot get CPM2 resource 1"); - - of_node_put(np); -#else - r.start = CPM_MAP_ADDR; - r.end = r.start + CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE - 1; -#endif - - im_dprambase = ioremap(r.start, r.end - r.start + 1); - if (!im_dprambase) - panic("Cannot map DPRAM"); - spin_lock_init(&cpm_dpmem_lock); /* initialize the info header */ @@ -358,13 +344,15 @@ static void cpm2_dpinit(void) sizeof(cpm_boot_dpmem_rh_block[0]), cpm_boot_dpmem_rh_block); + im_dprambase = cpm2_immr; + /* Attach the usable dpmem area */ /* XXX: This is actually crap. CPM_DATAONLY_BASE and * CPM_DATAONLY_SIZE is only a subset of the available dpram. It * varies with the processor and the microcode patches activated. * But the following should be at least safe. */ - rh_attach_region(&cpm_dpmem_info, 0, r.end - r.start + 1); + rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE); } /* This function returns an index into the DPRAM area. @@ -422,6 +410,7 @@ void *cpm_dpram_addr(unsigned long offset) return (void *)(im_dprambase + offset); } EXPORT_SYMBOL(cpm_dpram_addr); +#endif /* !CONFIG_PPC_CPM_NEW_BINDING */ struct cpm2_ioports { u32 dir, par, sor, odr, dat; diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index 9daa6ac67676..66c8ad4cfce6 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -5,15 +5,27 @@ * * Copyright 2007 Freescale Semiconductor, Inc. * + * Some parts derived from commproc.c/cpm2_common.c, which is: + * Copyright (c) 1997 Dan error_act (dmalek@jlc.net) + * Copyright (c) 1999-2001 Dan Malek + * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com) + * 2006 (c) MontaVista Software, Inc. + * Vitaly Bordug + * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. */ #include +#include + #include #include #include +#include +#include + #include #ifdef CONFIG_PPC_EARLY_DEBUG_CPM @@ -41,6 +53,153 @@ void __init udbg_init_cpm(void) setbat(1, 0xf0000000, 0xf0000000, 1024*1024, _PAGE_IO); #endif udbg_putc = udbg_putc_cpm; + udbg_putc('X'); } } #endif + +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static spinlock_t cpm_muram_lock; +static rh_block_t cpm_boot_muram_rh_block[16]; +static rh_info_t cpm_muram_info; +static u8 __iomem *muram_vbase; +static phys_addr_t muram_pbase; + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 + +int __init cpm_muram_init(void) +{ + struct device_node *np; + struct resource r; + u32 zero[OF_MAX_ADDR_CELLS] = {}; + resource_size_t max = 0; + int i = 0; + int ret = 0; + + printk("cpm_muram_init\n"); + + spin_lock_init(&cpm_muram_lock); + /* initialize the info header */ + rh_init(&cpm_muram_info, 1, + sizeof(cpm_boot_muram_rh_block) / + sizeof(cpm_boot_muram_rh_block[0]), + cpm_boot_muram_rh_block); + + np = of_find_compatible_node(NULL, NULL, "fsl,cpm-muram-data"); + if (!np) { + printk(KERN_ERR "Cannot find CPM muram data node"); + ret = -ENODEV; + goto out; + } + + muram_pbase = of_translate_address(np, zero); + if (muram_pbase == (phys_addr_t)OF_BAD_ADDR) { + printk(KERN_ERR "Cannot translate zero through CPM muram node"); + ret = -ENODEV; + goto out; + } + + while (of_address_to_resource(np, i++, &r) == 0) { + if (r.end > max) + max = r.end; + + rh_attach_region(&cpm_muram_info, r.start - muram_pbase, + r.end - r.start + 1); + } + + muram_vbase = ioremap(muram_pbase, max - muram_pbase + 1); + if (!muram_vbase) { + printk(KERN_ERR "Cannot map CPM muram"); + ret = -ENOMEM; + } + +out: + of_node_put(np); + return ret; +} + +/** + * cpm_muram_alloc - allocate the requested size worth of multi-user ram + * @size: number of bytes to allocate + * @align: requested alignment, in bytes + * + * This function returns an offset into the muram area. + * Use cpm_dpram_addr() to get the virtual address of the area. + * Use cpm_muram_free() to free the allocation. + */ +unsigned long cpm_muram_alloc(unsigned long size, unsigned long align) +{ + unsigned long start; + unsigned long flags; + + spin_lock_irqsave(&cpm_muram_lock, flags); + cpm_muram_info.alignment = align; + start = rh_alloc(&cpm_muram_info, size, "commproc"); + spin_unlock_irqrestore(&cpm_muram_lock, flags); + + return start; +} +EXPORT_SYMBOL(cpm_muram_alloc); + +/** + * cpm_muram_free - free a chunk of multi-user ram + * @offset: The beginning of the chunk as returned by cpm_muram_alloc(). + */ +int cpm_muram_free(unsigned long offset) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&cpm_muram_lock, flags); + ret = rh_free(&cpm_muram_info, offset); + spin_unlock_irqrestore(&cpm_muram_lock, flags); + + return ret; +} +EXPORT_SYMBOL(cpm_muram_free); + +/** + * cpm_muram_alloc_fixed - reserve a specific region of multi-user ram + * @offset: the offset into the muram area to reserve + * @size: the number of bytes to reserve + * + * This function returns "start" on success, -ENOMEM on failure. + * Use cpm_dpram_addr() to get the virtual address of the area. + * Use cpm_muram_free() to free the allocation. + */ +unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size) +{ + unsigned long start; + unsigned long flags; + + spin_lock_irqsave(&cpm_muram_lock, flags); + cpm_muram_info.alignment = 1; + start = rh_alloc_fixed(&cpm_muram_info, offset, size, "commproc"); + spin_unlock_irqrestore(&cpm_muram_lock, flags); + + return start; +} +EXPORT_SYMBOL(cpm_muram_alloc_fixed); + +/** + * cpm_muram_addr - turn a muram offset into a virtual address + * @offset: muram offset to convert + */ +void __iomem *cpm_muram_addr(unsigned long offset) +{ + return muram_vbase + offset; +} +EXPORT_SYMBOL(cpm_muram_addr); + +/** + * cpm_muram_phys - turn a muram virtual address into a DMA address + * @offset: virtual address from cpm_muram_addr() to convert + */ +dma_addr_t cpm_muram_dma(void __iomem *addr) +{ + return muram_pbase + ((u8 __iomem *)addr - muram_vbase); +} +EXPORT_SYMBOL(cpm_muram_dma); + +#endif /* CONFIG_PPC_CPM_NEW_BINDING */ diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 5bd4508ce3c1..882dbc17d590 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -235,7 +235,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo) int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) { int dpmemsz, memsz; - u8 *dp_mem; + u8 __iomem *dp_mem; unsigned long dp_offset; u8 *mem_addr; dma_addr_t dma_addr = 0; @@ -278,7 +278,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); - pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; + pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; diff --git a/include/asm-powerpc/commproc.h b/include/asm-powerpc/commproc.h index 5dec32404fa2..0307c84a5c1d 100644 --- a/include/asm-powerpc/commproc.h +++ b/include/asm-powerpc/commproc.h @@ -19,6 +19,7 @@ #include #include +#include /* CPM Command register. */ @@ -54,6 +55,7 @@ #define mk_cr_cmd(CH, CMD) ((CMD << 8) | (CH << 4)) +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* The dual ported RAM is multi-functional. Some areas can be (and are * being) used for microcode. There is an area that can only be used * as data ram for buffer descriptors, which is all we use right now. @@ -62,17 +64,27 @@ #define CPM_DATAONLY_BASE ((uint)0x0800) #define CPM_DATAONLY_SIZE ((uint)0x0700) #define CPM_DP_NOSPACE ((uint)0x7fffffff) +#endif /* Export the base address of the communication processor registers * and dual port ram. */ extern cpm8xx_t __iomem *cpmp; /* Pointer to comm processor */ + +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#define cpm_dpalloc cpm_muram_alloc +#define cpm_dpfree cpm_muram_free +#define cpm_dpram_addr cpm_muram_addr +#define cpm_dpram_phys cpm_muram_dma +#else extern unsigned long cpm_dpalloc(uint size, uint align); extern int cpm_dpfree(unsigned long offset); extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); extern void cpm_dpdump(void); extern void *cpm_dpram_addr(unsigned long offset); extern uint cpm_dpram_phys(u8* addr); +#endif + extern void cpm_setbrg(uint brg, uint rate); extern uint m8xx_cpm_hostalloc(uint size); diff --git a/include/asm-powerpc/cpm.h b/include/asm-powerpc/cpm.h new file mode 100644 index 000000000000..48df9f330e76 --- /dev/null +++ b/include/asm-powerpc/cpm.h @@ -0,0 +1,14 @@ +#ifndef __CPM_H +#define __CPM_H + +#include +#include + +int cpm_muram_init(void); +unsigned long cpm_muram_alloc(unsigned long size, unsigned long align); +int cpm_muram_free(unsigned long offset); +unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size); +void __iomem *cpm_muram_addr(unsigned long offset); +dma_addr_t cpm_muram_dma(void __iomem *addr); + +#endif diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h index d7b57ac55892..e698b1d09dcf 100644 --- a/include/asm-powerpc/cpm2.h +++ b/include/asm-powerpc/cpm2.h @@ -11,6 +11,7 @@ #define __CPM2__ #include +#include /* CPM Command register. */ @@ -82,6 +83,7 @@ #define mk_cr_cmd(PG, SBC, MCN, OP) \ ((PG << 26) | (SBC << 21) | (MCN << 6) | OP) +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* Dual Port RAM addresses. The first 16K is available for almost * any CPM use, so we put the BDs there. The first 128 bytes are * used for SMC1 and SMC2 parameter RAM, so we start allocating @@ -97,6 +99,7 @@ #define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE) #define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000) #endif +#endif /* The number of pages of host memory we allocate for CPM. This is * done early in kernel initialization to get physically contiguous @@ -109,11 +112,18 @@ */ extern cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor */ +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#define cpm_dpalloc cpm_muram_alloc +#define cpm_dpfree cpm_muram_free +#define cpm_dpram_addr cpm_muram_addr +#else extern unsigned long cpm_dpalloc(uint size, uint align); extern int cpm_dpfree(unsigned long offset); extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); extern void cpm_dpdump(void); extern void *cpm_dpram_addr(unsigned long offset); +#endif + extern void cpm_setbrg(uint brg, uint rate); extern void cpm2_fastbrg(uint brg, uint rate, int div16); extern void cpm2_reset(void); From da1bb3a0e1f7f9cabe70fb2c41b47fa57c42fdfd Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 2 Oct 2007 17:47:40 +0400 Subject: [PATCH 0457/2804] [POWERPC] fsl_soc: fix uninitialized i2c_board_info structure i2c_board_info used semi-initialized, causing garbage in the info->flags, and that, in turn, causes various symptoms of i2c malfunctioning, like PEC mismatches. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_soc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 4a1645691fb1..91987e000d25 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -363,7 +363,7 @@ static void __init of_register_i2c_devices(struct device_node *adap_node, struct device_node *node = NULL; while ((node = of_get_next_child(adap_node, node))) { - struct i2c_board_info info; + struct i2c_board_info info = {}; const u32 *addr; int len; @@ -380,7 +380,6 @@ static void __init of_register_i2c_devices(struct device_node *adap_node, if (of_find_i2c_driver(node, &info) < 0) continue; - info.platform_data = NULL; info.addr = *addr; i2c_register_board_info(bus_num, &info, 1); From c0e4eb2d8a8a094db5295a42d84aef08dea8aea4 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 2 Oct 2007 17:47:43 +0400 Subject: [PATCH 0458/2804] [POWERPC] MPC8568E-MDS: add support for ds1374 rtc MPC8568E-MDS have DS1374 chip on the I2C bus, thus let's use it. This patch also adds #address-cells and #size-cells to the I2C controllers nodes. p.s. DS1374 rtc class driver is in the -mm tree, its name is rtc-rtc-class-driver-for-the-ds1374.patch. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8568mds.dts | 9 +++++++++ arch/powerpc/sysdev/fsl_soc.c | 1 + 2 files changed, 10 insertions(+) diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index c472a4b488e9..76d23ee643d0 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -72,15 +72,24 @@ }; i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; device_type = "i2c"; compatible = "fsl-i2c"; reg = <3000 100>; interrupts = <2b 2>; interrupt-parent = <&mpic>; dfsrr; + + rtc@68 { + compatible = "dallas,ds1374"; + reg = <68>; + }; }; i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; device_type = "i2c"; compatible = "fsl-i2c"; reg = <3100 100>; diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 91987e000d25..c765d7a5217b 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -337,6 +337,7 @@ static struct i2c_driver_device i2c_devices[] __initdata = { {"dallas,ds1339", "rtc-ds1307", "ds1339",}, {"dallas,ds1340", "rtc-ds1307", "ds1340",}, {"stm,m41t00", "rtc-ds1307", "m41t00"}, + {"dallas,ds1374", "rtc-ds1374", "rtc-ds1374",}, }; static int __init of_find_i2c_driver(struct device_node *node, From 6b9c67681b8d08301cdc31b0503023e0208cc1d8 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 2 Oct 2007 17:48:07 +0400 Subject: [PATCH 0459/2804] [POWERPC] mpc8568mds.dts: fix PCIe I/O address space location and size According to u-boot/board/mpc8568mds/init.S: LAW(Local Access Window) configuration: 2) 0xa000_0000 0xbfff_ffff PCIe MEM 512MB 4) 0xe280_0000 0xe2ff_ffff PCIe I/O 8M Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8568mds.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index 76d23ee643d0..6923e42af4fd 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -226,8 +226,8 @@ interrupt-parent = <&mpic>; interrupts = <1a 2>; bus-range = <0 ff>; - ranges = <02000000 0 a0000000 a0000000 0 20000000 - 01000000 0 00000000 e3000000 0 08000000>; + ranges = <02000000 0 a0000000 a0000000 0 10000000 + 01000000 0 00000000 e2800000 0 00800000>; clock-frequency = <1fca055>; #interrupt-cells = <1>; #size-cells = <2>; From c925401b6dc2229adbb15b2f3c9f0f2d9253a5d5 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 22 Aug 2007 18:44:20 -0700 Subject: [PATCH 0460/2804] [CPUFREQ] x86: use num_online_nodes to get physical cpus numbers for powernow_k8 [PATCH] x86: use num_online_nodes to get physical cpus numbers for powernow_k8 For opteron based system, don't assume all physical cpus have the same booted cpus even same cores. esp for downcore case. Signed-off-by: Yinghai Lu Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 34ed53a06730..372df6e67e89 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -1325,21 +1325,16 @@ static struct cpufreq_driver cpufreq_amd64_driver = { static int __cpuinit powernowk8_init(void) { unsigned int i, supported_cpus = 0; - unsigned int booted_cores = 1; for_each_online_cpu(i) { if (check_supported_cpu(i)) supported_cpus++; } -#ifdef CONFIG_SMP - booted_cores = cpu_data[0].booted_cores; -#endif - if (supported_cpus == num_online_cpus()) { printk(KERN_INFO PFX "Found %d %s " "processors (%d cpu cores) (" VERSION ")\n", - supported_cpus/booted_cores, + num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus); return cpufreq_register_driver(&cpufreq_amd64_driver); } From a09d60a622ea4a3592dc6836e709d4a7a4ed4025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Bilski?= Date: Wed, 26 Sep 2007 17:08:14 +0200 Subject: [PATCH 0461/2804] [CPUFREQ] Longhaul - Add support for PM133 northbridge Add support for PM133 northbridge. Tested by Sylvain Ferrand. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/longhaul.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index ef8f0bc3fc71..58816facc435 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -665,6 +665,10 @@ static int enable_arbiter_disable(void) reg = 0x78; dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL); + /* Find PM133/VT8605 host bridge */ + if (dev == NULL) + dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8605_0, NULL); /* Find CLE266 host bridge */ if (dev == NULL) { reg = 0x76; From 8122c6cea033e8034e99d3b10a4e3f377ce23994 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 2 Oct 2007 13:28:09 -0700 Subject: [PATCH 0462/2804] [CPUFREQ] move policy's governor initialisation out of low-level drivers into cpufreq core Signed-off-by: Thomas Renninger Signed-off-by: Venkatesh Pallipadi Cc: Russell King Cc: Bryan Wu Cc: Andi Kleen Cc: "Luck, Tony" Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Paul Mundt Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- arch/arm/mach-imx/cpufreq.c | 1 - arch/arm/mach-sa1100/cpu-sa1110.c | 1 - arch/arm/plat-omap/cpu-omap.c | 1 - arch/blackfin/mach-bf533/cpu.c | 2 -- arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 1 - arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c | 1 - arch/i386/kernel/cpu/cpufreq/e_powersaver.c | 1 - arch/i386/kernel/cpu/cpufreq/elanfreq.c | 1 - arch/i386/kernel/cpu/cpufreq/gx-suspmod.c | 1 - arch/i386/kernel/cpu/cpufreq/longhaul.c | 1 - arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 1 - arch/i386/kernel/cpu/cpufreq/powernow-k6.c | 1 - arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 2 -- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 1 - arch/i386/kernel/cpu/cpufreq/sc520_freq.c | 1 - arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | 1 - arch/i386/kernel/cpu/cpufreq/speedstep-ich.c | 1 - arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 1 - arch/ia64/kernel/cpufreq/acpi-cpufreq.c | 2 -- arch/powerpc/platforms/cell/cbe_cpufreq.c | 2 -- arch/powerpc/platforms/pasemi/cpufreq.c | 2 -- arch/powerpc/platforms/powermac/cpufreq_32.c | 1 - arch/powerpc/platforms/powermac/cpufreq_64.c | 1 - arch/sh/kernel/cpufreq.c | 1 - arch/sparc64/kernel/us2e_cpufreq.c | 1 - drivers/cpufreq/cpufreq.c | 2 ++ 26 files changed, 2 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c index 467d899fbe75..e548ba74a4d2 100644 --- a/arch/arm/mach-imx/cpufreq.c +++ b/arch/arm/mach-imx/cpufreq.c @@ -269,7 +269,6 @@ static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy) return -EINVAL; policy->cur = policy->min = policy->max = imx_get_speed(0); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = 8000; policy->cpuinfo.max_freq = 200000; /* Manual states, that PLL stabilizes in two CLK32 periods */ diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c index 78f4c1346044..36b47ff5af11 100644 --- a/arch/arm/mach-sa1100/cpu-sa1110.c +++ b/arch/arm/mach-sa1100/cpu-sa1110.c @@ -331,7 +331,6 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -EINVAL; policy->cur = policy->min = policy->max = sa11x0_getspeed(0); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = 59000; policy->cpuinfo.max_freq = 287000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c index a0c71dca2373..c0d63b0c61c9 100644 --- a/arch/arm/plat-omap/cpu-omap.c +++ b/arch/arm/plat-omap/cpu-omap.c @@ -108,7 +108,6 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -EINVAL; policy->cur = policy->min = policy->max = omap_getspeed(0); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/arch/blackfin/mach-bf533/cpu.c b/arch/blackfin/mach-bf533/cpu.c index 6fd9cfd0a31b..b7a0e0fbd9af 100644 --- a/arch/blackfin/mach-bf533/cpu.c +++ b/arch/blackfin/mach-bf533/cpu.c @@ -118,8 +118,6 @@ static int __init __bf533_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -EINVAL; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; /*Now ,only support one cpu */ policy->cur = bf533_getfreq(0); diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 705e13a30781..42115b609f63 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -646,7 +646,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000; } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; data->max_freq = perf->states[0].core_frequency * 1000; /* table init */ diff --git a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c index 66acd5039918..32f0bda3fc95 100644 --- a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c +++ b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c @@ -363,7 +363,6 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) policy->cur = nforce2_get(policy->cpu); policy->min = policy->cpuinfo.min_freq; policy->max = policy->cpuinfo.max_freq; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; return 0; } diff --git a/arch/i386/kernel/cpu/cpufreq/e_powersaver.c b/arch/i386/kernel/cpu/cpufreq/e_powersaver.c index f43d98e11cc7..c11baaf9f2b4 100644 --- a/arch/i386/kernel/cpu/cpufreq/e_powersaver.c +++ b/arch/i386/kernel/cpu/cpufreq/e_powersaver.c @@ -253,7 +253,6 @@ static int eps_cpu_init(struct cpufreq_policy *policy) f_table[k].frequency = CPUFREQ_TABLE_END; } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */ policy->cur = fsb * current_multiplier; diff --git a/arch/i386/kernel/cpu/cpufreq/elanfreq.c b/arch/i386/kernel/cpu/cpufreq/elanfreq.c index f317276afa7a..1e7ae7dafcf6 100644 --- a/arch/i386/kernel/cpu/cpufreq/elanfreq.c +++ b/arch/i386/kernel/cpu/cpufreq/elanfreq.c @@ -219,7 +219,6 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) } /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = elanfreq_get_cpu_frequency(0); diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c index 461dabc4e495..ed2bda127c44 100644 --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c @@ -420,7 +420,6 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) policy->min = maxfreq / POLICY_MIN_DIV; policy->max = maxfreq; policy->cur = curfreq; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = maxfreq / max_duration; policy->cpuinfo.max_freq = maxfreq; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 58816facc435..a2fbfd912a08 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -877,7 +877,6 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0)) longhaul_setup_voltagescaling(); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 200000; /* nsec */ policy->cur = calc_speed(longhaul_get_cpu_mult()); diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index 4c76b511e194..8eb414b906d2 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -229,7 +229,6 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu); /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 1000000; /* assumed */ policy->cur = stock_freq; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c index f89524051e4a..6d0285339317 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c @@ -160,7 +160,6 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) } /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = busfreq * max_multiplier; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index ca3e1d341889..7decd6a50ffa 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -637,8 +637,6 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", minimum_speed/1000, maximum_speed/1000); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency); policy->cur = powernow_get(0); diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 372df6e67e89..f2a65a9609f1 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -1208,7 +1208,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) /* run on any CPU again */ set_cpus_allowed(current, oldmask); - pol->governor = CPUFREQ_DEFAULT_GOVERNOR; if (cpu_family == CPU_HW_PSTATE) pol->cpus = cpumask_of_cpu(pol->cpu); else diff --git a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c index b8fb4b521c62..d9f3e90a7ae0 100644 --- a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c +++ b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c @@ -111,7 +111,6 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy) return -ENODEV; /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 1000000; /* 1ms */ policy->cur = sc520_freq_get_cpu_frequency(0); diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index 6c5dc2c85aeb..811d47438546 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -393,7 +393,6 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) freq = get_cur_freq(policy->cpu); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */ policy->cur = freq; diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c index a5b2346faf1f..36685e8f7be1 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c @@ -348,7 +348,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) (speed / 1000)); /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cur = speed; result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c index e1c509aa3054..f2b5a621d27b 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c @@ -290,7 +290,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) (speed / 1000)); /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = speed; diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c index 8c6ec7070844..b8498ea62068 100644 --- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c +++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c @@ -321,8 +321,6 @@ acpi_cpufreq_cpu_init ( data->acpi_data.states[i].transition_latency * 1000; } } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cur = processor_get_freq(data, policy->cpu); /* table init */ diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index 0b6e8ee85ab1..c50ad22bf73e 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -107,8 +107,6 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("%d: %d\n", i, cbe_freqs[i].frequency); } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - /* if DEBUG is enabled set_pmode() measures the latency * of a transition */ policy->cpuinfo.transition_latency = 25000; diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index 3ae083851b01..1cfb8b0c8fec 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c @@ -195,8 +195,6 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("%d: %d\n", i, pas_freqs[i].frequency); } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = get_gizmo_latency(); cur_astate = get_cur_astate(policy->cpu); diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 1fe35dab0e9e..c04abcc28a7a 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -410,7 +410,6 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -ENODEV; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = cur_freq; diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c index 00f50298c342..4dfb4bc242b5 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_64.c +++ b/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -357,7 +357,6 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu) static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy) { - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = g5_cpu_freqs[g5_query_freq()].frequency; /* secondary CPUs are tied to the primary one by the diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c index e61890217c50..71d1c427b907 100644 --- a/arch/sh/kernel/cpufreq.c +++ b/arch/sh/kernel/cpufreq.c @@ -93,7 +93,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cur = sh_cpufreq_get(policy->cpu); policy->min = policy->cpuinfo.min_freq; policy->max = policy->cpuinfo.max_freq; diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c index 1f83fe6a82d6..791c15138f3a 100644 --- a/arch/sparc64/kernel/us2e_cpufreq.c +++ b/arch/sparc64/kernel/us2e_cpufreq.c @@ -326,7 +326,6 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) table[2].index = 5; table[3].frequency = CPUFREQ_TABLE_END; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 0; policy->cur = clock_tick; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2f6a73c01b71..9528bd577365 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); + /* Set governor before ->init, so that driver could check it */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU */ From 1c2562459faedc35927546cfa5273ec6c2884cce Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 2 Oct 2007 13:28:12 -0700 Subject: [PATCH 0463/2804] [CPUFREQ] allow ondemand and conservative cpufreq governors to be used as default Depending on the transition latency of the HW for cpufreq switches, the ondemand or conservative governor cannot be used with certain cpufreq drivers. Still the ondemand should be the default governor on a wide range of systems. This patch allows this and lets the governor fallback to the performance governor at cpufreq driver load time, if the driver does not support fast enough frequency switching. Main benefit is that on e.g. installation or other systems without userspace support a working dynamic cpufreq support can be achieved on most systems by simply loading the cpufreq driver. This is especially essential for recent x86(_64) laptop hardware which may rely on working dynamic cpufreq OS support. Signed-off-by: Thomas Renninger Signed-off-by: Venkatesh Pallipadi Cc: Russell King Cc: Bryan Wu Cc: Andi Kleen Cc: "Luck, Tony" Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Paul Mundt Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/Kconfig | 27 ++++++++++++++++++++++---- drivers/cpufreq/cpufreq.c | 12 ++++++++++++ drivers/cpufreq/cpufreq_conservative.c | 19 +++++++++--------- drivers/cpufreq/cpufreq_ondemand.c | 22 +++++++++------------ include/linux/cpufreq.h | 20 ++++++++++++++++--- 5 files changed, 70 insertions(+), 30 deletions(-) diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 993fa7b89253..721f86f4f008 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS If in doubt, say N. -# Note that it is not currently possible to set the other governors (such as ondemand) -# as the default, since if they fail to initialise, cpufreq will be -# left in an undefined state. - choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 @@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE program shall be able to set the CPU dynamically without having to enable the userspace governor manually. +config CPU_FREQ_DEFAULT_GOV_ONDEMAND + bool "ondemand" + select CPU_FREQ_GOV_ONDEMAND + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'ondemand' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the ondemand + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. + +config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE + bool "conservative" + select CPU_FREQ_GOV_CONSERVATIVE + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'conservative' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the conservative + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. endchoice config CPU_FREQ_GOV_PERFORMANCE diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9528bd577365..418522f88f73 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1484,6 +1484,18 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) { int ret; + struct cpufreq_governor *gov = CPUFREQ_PERFORMANCE_GOVERNOR; + + if (policy->governor->max_transition_latency && + policy->cpuinfo.transition_latency > + policy->governor->max_transition_latency) { + printk(KERN_WARNING "%s governor failed, too long" + " transition latency of HW, fallback" + " to %s governor\n", + policy->governor->name, + gov->name); + policy->governor = gov; + } if (!try_module_get(policy->governor->owner)) return -EINVAL; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 26f440ccc3fb..4bd33ce8a6f3 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -58,7 +58,7 @@ static unsigned int def_sampling_rate; #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (10) -#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -466,9 +466,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, (!policy->cur)) return -EINVAL; - if (policy->cpuinfo.transition_latency > - (TRANSITION_LATENCY_LIMIT * 1000)) - return -EINVAL; if (this_dbs_info->enable) /* Already enabled */ break; @@ -551,15 +548,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_dbs = { - .name = "conservative", - .governor = cpufreq_governor_dbs, - .owner = THIS_MODULE, +struct cpufreq_governor cpufreq_gov_conservative = { + .name = "conservative", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, }; +EXPORT_SYMBOL(cpufreq_gov_conservative); static int __init cpufreq_gov_dbs_init(void) { - return cpufreq_register_governor(&cpufreq_gov_dbs); + return cpufreq_register_governor(&cpufreq_gov_conservative); } static void __exit cpufreq_gov_dbs_exit(void) @@ -567,7 +566,7 @@ static void __exit cpufreq_gov_dbs_exit(void) /* Make sure that the scheduled work is indeed not running */ flush_scheduled_work(); - cpufreq_unregister_governor(&cpufreq_gov_dbs); + cpufreq_unregister_governor(&cpufreq_gov_conservative); } diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index e794527e4925..369f44595150 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -47,7 +47,7 @@ static unsigned int def_sampling_rate; (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) -#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, if ((!cpu_online(cpu)) || (!policy->cur)) return -EINVAL; - if (policy->cpuinfo.transition_latency > - (TRANSITION_LATENCY_LIMIT * 1000)) { - printk(KERN_WARNING "ondemand governor failed to load " - "due to too long transition latency\n"); - return -EINVAL; - } if (this_dbs_info->enable) /* Already enabled */ break; @@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_dbs = { - .name = "ondemand", - .governor = cpufreq_governor_dbs, - .owner = THIS_MODULE, +struct cpufreq_governor cpufreq_gov_ondemand = { + .name = "ondemand", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, }; +EXPORT_SYMBOL(cpufreq_gov_ondemand); static int __init cpufreq_gov_dbs_init(void) { @@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void) printk(KERN_ERR "Creation of kondemand failed\n"); return -EFAULT; } - return cpufreq_register_governor(&cpufreq_gov_dbs); + return cpufreq_register_governor(&cpufreq_gov_ondemand); } static void __exit cpufreq_gov_dbs_exit(void) { - cpufreq_unregister_governor(&cpufreq_gov_dbs); + cpufreq_unregister_governor(&cpufreq_gov_ondemand); destroy_workqueue(kondemand_wq); } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 3ec6e7ff5fbd..9e5f5d0c87f3 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -155,6 +155,9 @@ struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; int (*governor) (struct cpufreq_policy *policy, unsigned int event); + unsigned int max_transition_latency; /* HW must be able to switch to + next freq faster than this value in nano secs or we + will fallback to performance governor */ struct list_head governor_list; struct module *owner; }; @@ -279,12 +282,23 @@ static inline unsigned int cpufreq_quick_get(unsigned int cpu) *********************************************************************/ -#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE +/* + Performance governor is fallback governor if any other gov failed to + auto load due latency restrictions +*/ extern struct cpufreq_governor cpufreq_gov_performance; -#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_performance +#define CPUFREQ_PERFORMANCE_GOVERNOR (&cpufreq_gov_performance) +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_performance) #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE) extern struct cpufreq_governor cpufreq_gov_userspace; -#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_userspace +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_userspace) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND) +extern struct cpufreq_governor cpufreq_gov_ondemand; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_ondemand) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE) +extern struct cpufreq_governor cpufreq_gov_conservative; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative) #endif From 6afde10c3f58cc3ac593f5b4505b8b1cf719f5d6 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 2 Oct 2007 13:28:13 -0700 Subject: [PATCH 0464/2804] [CPUFREQ] Only check for transition latency on problematic governors (kconfig fix) Cc: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 27 ++++++++++++++++++++------- include/linux/cpufreq.h | 3 ++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 418522f88f73..65ac58511228 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1484,17 +1484,30 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) { int ret; - struct cpufreq_governor *gov = CPUFREQ_PERFORMANCE_GOVERNOR; + + /* Only must be defined when default governor is known to have latency + restrictions, like e.g. conservative or ondemand. + That this is the case is already ensured in Kconfig + */ +#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE + struct cpufreq_governor *gov = &cpufreq_gov_performance; +#else + struct cpufreq_governor *gov = NULL; +#endif if (policy->governor->max_transition_latency && policy->cpuinfo.transition_latency > policy->governor->max_transition_latency) { - printk(KERN_WARNING "%s governor failed, too long" - " transition latency of HW, fallback" - " to %s governor\n", - policy->governor->name, - gov->name); - policy->governor = gov; + if (!gov) + return -EINVAL; + else { + printk(KERN_WARNING "%s governor failed, too long" + " transition latency of HW, fallback" + " to %s governor\n", + policy->governor->name, + gov->name); + policy->governor = gov; + } } if (!try_module_get(policy->governor->owner)) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 9e5f5d0c87f3..450a841b5892 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -286,8 +286,9 @@ static inline unsigned int cpufreq_quick_get(unsigned int cpu) Performance governor is fallback governor if any other gov failed to auto load due latency restrictions */ +#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE extern struct cpufreq_governor cpufreq_gov_performance; -#define CPUFREQ_PERFORMANCE_GOVERNOR (&cpufreq_gov_performance) +#endif #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE #define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_performance) #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE) From dd184a01b8ece6bac2f7a63de99a4a4d29552746 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Tue, 2 Oct 2007 13:28:14 -0700 Subject: [PATCH 0465/2804] [CPUFREQ] mark hotplug notifier callback as __cpuinit The notifier_block is already __cpuinitdata, thereby allowing us to safely mark the callback function as __cpuinit also, thereby saving space when HOTPLUG_CPU=n. Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 65ac58511228..e027052a6604 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1730,7 +1730,7 @@ int cpufreq_update_policy(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_update_policy); -static int cpufreq_cpu_callback(struct notifier_block *nfb, +static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; From 6070b5de50ab5e3f810628a9cbb04deecf30a85f Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Tue, 2 Oct 2007 13:28:15 -0700 Subject: [PATCH 0466/2804] [CPUFREQ] implement !CONFIG_CPU_FREQ stub for cpufreq_unregister_notifier() Callsites such as arch/powerpc/oprofile/op_model_cell.c are having to open-code #ifdef CONFIG_CPU_FREQ only to be able to get at the full definition of cpufreq_unregister_notifier(), because no empty stub is available for the !CONFIG_CPU_FREQ case. Let's provide one, to be able to remove such #ifdef's from the rest of the kernel tree -- those will come in a subsequent patch. Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- include/linux/cpufreq.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 450a841b5892..23932d7741a9 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -32,12 +32,24 @@ * CPUFREQ NOTIFIER INTERFACE * *********************************************************************/ -int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); -int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); - #define CPUFREQ_TRANSITION_NOTIFIER (0) #define CPUFREQ_POLICY_NOTIFIER (1) +#ifdef CONFIG_CPU_FREQ +int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); +int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); +#else /* CONFIG_CPU_FREQ */ +static inline int cpufreq_register_notifier(struct notifier_block *nb, + unsigned int list) +{ + return 0; +} +static inline int cpufreq_unregister_notifier(struct notifier_block *nb, + unsigned int list) +{ + return 0; +} +#endif /* CONFIG_CPU_FREQ */ /* if (cpufreq_driver->target) exists, the ->governor decides what frequency * within the limits is used. If (cpufreq_driver->setpolicy> exists, these From 55395ae72b6e5ae614d28df74158c47454652583 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Tue, 2 Oct 2007 13:28:15 -0700 Subject: [PATCH 0467/2804] [CPUFREQ] cpufreq_stats: misc cpuinit section annotations * Stop referencing the callback directly from the __init and __exit functions of this driver, and instead explicitly call cpufreq_update_policy() et al. This enables the callback function to be marked as __cpuinit (and the notifier_block __cpuinitdata), thereby saving space when HOTPLUG_CPU=n. This also enables us to use other tricks to replace __cpuinit{data} in future. * cpufreq_stats_free_table() is only called from __cpuinit or __exit marked functions, making it an ideal candidate for __cpuexit. * Fix missing space in the module description Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_stats.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 917b9bab9ccb..8a45d0f93e26 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) return -1; } -static void -cpufreq_stats_free_table (unsigned int cpu) +static void __cpuexit cpufreq_stats_free_table(unsigned int cpu) { struct cpufreq_stats *stat = cpufreq_stats_table[cpu]; struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); @@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, return 0; } -static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) +static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { unsigned int cpu = (unsigned long)hcpu; @@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block cpufreq_stat_cpu_notifier = +static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata = { .notifier_call = cpufreq_stat_cpu_callback, }; @@ -356,8 +356,7 @@ __init cpufreq_stats_init(void) register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_ONLINE, (void *)(long)cpu); + cpufreq_update_policy(cpu); } return 0; } @@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void) CPUFREQ_TRANSITION_NOTIFIER); unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_DEAD, (void *)(long)cpu); + cpufreq_stats_free_table(cpu); } } MODULE_AUTHOR ("Zou Nan hai "); -MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats" +MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats " "through sysfs filesystem"); MODULE_LICENSE ("GPL"); From 562d94d98f7032bdc4a99d9124a78a543dbea225 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Fri, 3 Aug 2007 14:09:05 -0500 Subject: [PATCH 0468/2804] [CPUFREQ] Support different families in fid/did to frequency conversion The equation to find the frequency given the fid and did is family dependant. Acked-by: Mark Langsdorf Signed-off-by: Joachim Deguara Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index f2a65a9609f1..b273b69cfddf 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -76,7 +76,10 @@ static u32 find_khz_freq_from_fid(u32 fid) /* Return a frequency in MHz, given an input fid and did */ static u32 find_freq_from_fiddid(u32 fid, u32 did) { - return 100 * (fid + 0x10) >> did; + if (current_cpu_data.x86 == 0x10) + return 100 * (fid + 0x10) >> did; + else + return 100 * (fid + 0x8) >> did; } static u32 find_khz_freq_from_fiddid(u32 fid, u32 did) From 3e01e4bcdd56209e70c39293e0c4c355d09364b8 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 3 Oct 2007 15:32:10 -0400 Subject: [PATCH 0469/2804] sdio: fix IRQ diagnostic message If func is actually null we won't get much from sdio_func_id(func). Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index f78ffeefed52..e7865059e126 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -44,7 +44,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) if (!func) { printk(KERN_WARNING "%s: pending IRQ for " "non-existant function\n", - sdio_func_id(func)); + mmc_card_id(card)); } else if (func->irq_handler) { func->irq_handler(func); count++; From 599473cf15a3fae78cbc3192cfb38ca04d5abc72 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 3 Oct 2007 15:32:57 -0400 Subject: [PATCH 0470/2804] sdio: make the IRQ thread more resilient in the presence of bad states Currently we print a message about some bad states wrt function IRQ handlers but return 0 from process_sdio_pending_irqs() nevertheless. This can lead to an infinite loop as nothing might have cleared the condition for the pending card interrupt from the host controller by the time host->ops->enable_sdio_irq(host, 1) is called. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_irq.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index e7865059e126..3bd3021f5e80 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -45,16 +45,22 @@ static int process_sdio_pending_irqs(struct mmc_card *card) printk(KERN_WARNING "%s: pending IRQ for " "non-existant function\n", mmc_card_id(card)); + ret = -EINVAL; } else if (func->irq_handler) { func->irq_handler(func); count++; - } else + } else { printk(KERN_WARNING "%s: pending IRQ with no handler\n", sdio_func_id(func)); + ret = -EINVAL; + } } } - return count; + if (count) + return count; + + return ret; } static int sdio_irq_thread(void *_host) From 86a04d9c850787040ba63261cfa5eb9a48b58e5a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 2 Oct 2007 09:51:32 -0500 Subject: [PATCH 0471/2804] [POWERPC] Fixup MPC8568 dts The PCI nodes on the MPC8568 dts didn't get moved up to be sibilings of the SOC node when we did that clean up for some reason. Fix that up and some minor whitespace and adjusting the size of the soc reg property. Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8568mds.dts | 125 +++++++++++++++------------ 1 file changed, 70 insertions(+), 55 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index 6923e42af4fd..b064a2ff2306 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -52,7 +52,7 @@ #size-cells = <1>; device_type = "soc"; ranges = <0 e0000000 00100000>; - reg = ; + reg = ; bus-frequency = <0>; memory-controller@2000 { @@ -183,60 +183,6 @@ fsl,has-rstcr; }; - pci@8000 { - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x12 AD18 */ - 9000 0 0 1 &mpic 5 1 - 9000 0 0 2 &mpic 6 1 - 9000 0 0 3 &mpic 7 1 - 9000 0 0 4 &mpic 4 1 - - /* IDSEL 0x13 AD19 */ - 9800 0 0 1 &mpic 6 1 - 9800 0 0 2 &mpic 7 1 - 9800 0 0 3 &mpic 4 1 - 9800 0 0 4 &mpic 5 1>; - - interrupt-parent = <&mpic>; - interrupts = <18 2>; - bus-range = <0 ff>; - ranges = <02000000 0 80000000 80000000 0 20000000 - 01000000 0 00000000 e2000000 0 00800000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8000 1000>; - compatible = "fsl,mpc8540-pci"; - device_type = "pci"; - }; - - /* PCI Express */ - pcie@a000 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x0 (PEX) */ - 00000 0 0 1 &mpic 0 1 - 00000 0 0 2 &mpic 1 1 - 00000 0 0 3 &mpic 2 1 - 00000 0 0 4 &mpic 3 1>; - - interrupt-parent = <&mpic>; - interrupts = <1a 2>; - bus-range = <0 ff>; - ranges = <02000000 0 a0000000 a0000000 0 10000000 - 01000000 0 00000000 e2800000 0 00800000>; - clock-frequency = <1fca055>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = ; - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - }; - serial@4600 { device_type = "serial"; compatible = "ns16550"; @@ -269,6 +215,7 @@ device_type = "open-pic"; big-endian; }; + par_io@e0100 { reg = ; device_type = "par_io"; @@ -301,6 +248,7 @@ 4 13 1 0 2 0 /* GTX_CLK */ 1 1f 2 0 3 0>; /* GTX125 */ }; + pio2: ucc_pin@02 { pio-map = < /* port pin dir open_drain assignment has_irq */ @@ -461,4 +409,71 @@ }; }; + + pci@e0008000 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x12 AD18 */ + 9000 0 0 1 &mpic 5 1 + 9000 0 0 2 &mpic 6 1 + 9000 0 0 3 &mpic 7 1 + 9000 0 0 4 &mpic 4 1 + + /* IDSEL 0x13 AD19 */ + 9800 0 0 1 &mpic 6 1 + 9800 0 0 2 &mpic 7 1 + 9800 0 0 3 &mpic 4 1 + 9800 0 0 4 &mpic 5 1>; + + interrupt-parent = <&mpic>; + interrupts = <18 2>; + bus-range = <0 ff>; + ranges = <02000000 0 80000000 80000000 0 20000000 + 01000000 0 00000000 e2000000 0 00800000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8540-pci"; + device_type = "pci"; + }; + + /* PCI Express */ + pcie@e000a000 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x0 (PEX) */ + 00000 0 0 1 &mpic 0 1 + 00000 0 0 2 &mpic 1 1 + 00000 0 0 3 &mpic 2 1 + 00000 0 0 4 &mpic 3 1>; + + interrupt-parent = <&mpic>; + interrupts = <1a 2>; + bus-range = <0 ff>; + ranges = <02000000 0 a0000000 a0000000 0 10000000 + 01000000 0 00000000 e2800000 0 00800000>; + clock-frequency = <1fca055>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 a0000000 + 02000000 0 a0000000 + 0 10000000 + + 01000000 0 00000000 + 01000000 0 00000000 + 0 00800000>; + }; + }; }; From 6039680705906f270411435c05c869ac4f59ef10 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 3 Oct 2007 10:43:10 -0500 Subject: [PATCH 0472/2804] [POWERPC] Update .gitignore for new vdso generated files We now generate vdso[32,64].so.dbg as part of the build so add them to .gitignore Signed-off-by: Kumar Gala --- arch/powerpc/kernel/vdso32/.gitignore | 1 + arch/powerpc/kernel/vdso64/.gitignore | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/powerpc/kernel/vdso32/.gitignore b/arch/powerpc/kernel/vdso32/.gitignore index e45fba9d0ced..fea5809857a5 100644 --- a/arch/powerpc/kernel/vdso32/.gitignore +++ b/arch/powerpc/kernel/vdso32/.gitignore @@ -1 +1,2 @@ vdso32.lds +vdso32.so.dbg diff --git a/arch/powerpc/kernel/vdso64/.gitignore b/arch/powerpc/kernel/vdso64/.gitignore index 3fd18cf9fec2..77a0b423642c 100644 --- a/arch/powerpc/kernel/vdso64/.gitignore +++ b/arch/powerpc/kernel/vdso64/.gitignore @@ -1 +1,2 @@ vdso64.lds +vdso64.so.dbg From 6b0b594bb81f86dbc7b0829ee5102abaab242913 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 3 Oct 2007 11:34:59 -0500 Subject: [PATCH 0473/2804] [POWERPC] qe: miscellaneous code improvements and fixes to the QE library This patch makes numerous miscellaneous code improvements to the QE library. 1. Remove struct ucc_common and merge ucc_init_guemr() into ucc_set_type() (every caller of ucc_init_guemr() also calls ucc_set_type()). Modify all callers of ucc_set_type() accordingly. 2. Remove the unused enum ucc_pram_initial_offset. 3. Refactor qe_setbrg(), also implement work-around for errata QE_General4. 4. Several printk() calls were missing the terminating \n. 5. Add __iomem where needed, and change u16 to __be16 and u32 to __be32 where appropriate. 6. In ucc_slow_init() the RBASE and TBASE registers in the PRAM were programmed with the wrong value. 7. Add the protocol type to struct us_info and updated ucc_slow_init() to use it, instead of always programming QE_CR_PROTOCOL_UNSPECIFIED. 8. Rename ucc_slow_restart_x() to ucc_slow_restart_tx() 9. Add several macros in qe.h (mostly for slow UCC support, but also to standardize some naming convention) and remove several unused macros. 10. Update ucc_geth.c to use the new macros. 11. Add ucc_slow_info.protocol to specify which QE_CR_PROTOCOL_xxx protcol to use when initializing the UCC in ucc_slow_init(). 12. Rename ucc_slow_pram.rfcr to rbmr and ucc_slow_pram.tfcr to tbmr, since these are the real names of the registers. 13. Use the setbits, clrbits, and clrsetbits where appropriate. 14. Refactor ucc_set_qe_mux_rxtx(). 15. Remove all instances of 'volatile'. 16. Simplify get_cmxucr_reg(); 17. Replace qe_mux.cmxucrX with qe_mux.cmxucr[]. 18. Updated struct ucc_geth because struct ucc_fast is not padded any more. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/qe_lib/qe.c | 36 ++-- arch/powerpc/sysdev/qe_lib/qe_ic.c | 2 - arch/powerpc/sysdev/qe_lib/qe_io.c | 35 ++-- arch/powerpc/sysdev/qe_lib/ucc.c | 270 +++++++++++--------------- arch/powerpc/sysdev/qe_lib/ucc_fast.c | 125 ++++++------ arch/powerpc/sysdev/qe_lib/ucc_slow.c | 48 +++-- drivers/net/ucc_geth.c | 2 +- drivers/net/ucc_geth.h | 1 + include/asm-powerpc/immap_qe.h | 30 +-- include/asm-powerpc/qe.h | 237 +++++++++++++++------- include/asm-powerpc/ucc.h | 40 +--- include/asm-powerpc/ucc_slow.h | 9 +- 12 files changed, 427 insertions(+), 408 deletions(-) diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 90f87408b5d5..3d57d3835b04 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -141,7 +141,7 @@ EXPORT_SYMBOL(qe_issue_cmd); * 16 BRGs, which can be connected to the QE channels or output * as clocks. The BRGs are in two different block of internal * memory mapped space. - * The baud rate clock is the system clock divided by something. + * The BRG clock is the QE clock divided by 2. * It was set up long ago during the initial boot phase and is * is given to us. * Baud rate clocks are zero-based in the driver code (as that maps @@ -165,28 +165,38 @@ unsigned int get_brg_clk(void) return brg_clk; } -/* This function is used by UARTS, or anything else that uses a 16x - * oversampled clock. +/* Program the BRG to the given sampling rate and multiplier + * + * @brg: the BRG, 1-16 + * @rate: the desired sampling rate + * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or + * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01, + * then 'multiplier' should be 8. + * + * Also note that the value programmed into the BRGC register must be even. */ -void qe_setbrg(u32 brg, u32 rate) +void qe_setbrg(unsigned int brg, unsigned int rate, unsigned int multiplier) { - volatile u32 *bp; u32 divisor, tempval; - int div16 = 0; + u32 div16 = 0; - bp = &qe_immr->brg.brgc[brg]; + divisor = get_brg_clk() / (rate * multiplier); - divisor = (get_brg_clk() / rate); if (divisor > QE_BRGC_DIVISOR_MAX + 1) { - div16 = 1; + div16 = QE_BRGC_DIV16; divisor /= 16; } - tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; - if (div16) - tempval |= QE_BRGC_DIV16; + /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says + that the BRG divisor must be even if you're not using divide-by-16 + mode. */ + if (!div16 && (divisor & 1)) + divisor++; - out_be32(bp, tempval); + tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | + QE_BRGC_ENABLE | div16; + + out_be32(&qe_immr->brg.brgc[brg - 1], tempval); } /* Initialize SNUMs (thread serial numbers) according to diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 55e6f394af82..9a2d1edd050e 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -405,8 +405,6 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags) set_irq_data(qe_ic->virq_high, qe_ic); set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high); } - - printk("QEIC (%d IRQ sources) at %p\n", NR_QE_IC_INTS, qe_ic->regs); } void qe_ic_set_highest_priority(unsigned int virq, int high) diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index e32b45bf9ff5..a114cb0c572f 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -195,29 +195,22 @@ EXPORT_SYMBOL(par_io_of_config); #ifdef DEBUG static void dump_par_io(void) { - int i; + unsigned int i; - printk(KERN_INFO "PAR IO registars:\n"); - printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io); + printk(KERN_INFO "%s: par_io=%p\n", __FUNCTION__, par_io); for (i = 0; i < num_par_io_ports; i++) { - printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cpodr, - in_be32(&par_io[i].cpodr)); - printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cpdata, - in_be32(&par_io[i].cpdata)); - printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cpdir1, - in_be32(&par_io[i].cpdir1)); - printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cpdir2, - in_be32(&par_io[i].cpdir2)); - printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cppar1, - in_be32(&par_io[i].cppar1)); - printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cppar2, - in_be32(&par_io[i].cppar2)); + printk(KERN_INFO " cpodr[%u]=%08x\n", i, + in_be32(&par_io[i].cpodr)); + printk(KERN_INFO " cpdata[%u]=%08x\n", i, + in_be32(&par_io[i].cpdata)); + printk(KERN_INFO " cpdir1[%u]=%08x\n", i, + in_be32(&par_io[i].cpdir1)); + printk(KERN_INFO " cpdir2[%u]=%08x\n", i, + in_be32(&par_io[i].cpdir2)); + printk(KERN_INFO " cppar1[%u]=%08x\n", i, + in_be32(&par_io[i].cppar1)); + printk(KERN_INFO " cppar2[%u]=%08x\n", i, + in_be32(&par_io[i].cppar2)); } } diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index f970e5415ac0..0e348d9af8a6 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -28,228 +28,188 @@ static DEFINE_SPINLOCK(ucc_lock); -int ucc_set_qe_mux_mii_mng(int ucc_num) +int ucc_set_qe_mux_mii_mng(unsigned int ucc_num) { unsigned long flags; + if (ucc_num > UCC_MAX_NUM - 1) + return -EINVAL; + spin_lock_irqsave(&ucc_lock, flags); - out_be32(&qe_immr->qmx.cmxgcr, - ((in_be32(&qe_immr->qmx.cmxgcr) & - ~QE_CMXGCR_MII_ENET_MNG) | - (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT))); + clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG, + ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT); spin_unlock_irqrestore(&ucc_lock, flags); return 0; } EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng); -int ucc_set_type(int ucc_num, struct ucc_common *regs, - enum ucc_speed_type speed) +/* Configure the UCC to either Slow or Fast. + * + * A given UCC can be figured to support either "slow" devices (e.g. UART) + * or "fast" devices (e.g. Ethernet). + * + * 'ucc_num' is the UCC number, from 0 - 7. + * + * This function also sets the UCC_GUEMR_SET_RESERVED3 bit because that bit + * must always be set to 1. + */ +int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed) { - u8 guemr = 0; + u8 __iomem *guemr; - /* check if the UCC number is in range. */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) - return -EINVAL; - - guemr = regs->guemr; - guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX); - switch (speed) { - case UCC_SPEED_TYPE_SLOW: - guemr |= (UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX); - break; - case UCC_SPEED_TYPE_FAST: - guemr |= (UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX); - break; - default: - return -EINVAL; - } - regs->guemr = guemr; - - return 0; -} - -int ucc_init_guemr(struct ucc_common *regs) -{ - u8 guemr = 0; - - if (!regs) - return -EINVAL; - - /* Set bit 3 (which is reserved in the GUEMR register) to 1 */ - guemr = UCC_GUEMR_SET_RESERVED3; - - regs->guemr = guemr; - - return 0; -} - -static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 * reg_num, - u8 * shift) -{ + /* The GUEMR register is at the same location for both slow and fast + devices, so we just use uccX.slow.guemr. */ switch (ucc_num) { - case 0: *p_cmxucr = &(qe_immr->qmx.cmxucr1); - *reg_num = 1; - *shift = 16; + case 0: guemr = &qe_immr->ucc1.slow.guemr; break; - case 2: *p_cmxucr = &(qe_immr->qmx.cmxucr1); - *reg_num = 1; - *shift = 0; + case 1: guemr = &qe_immr->ucc2.slow.guemr; break; - case 4: *p_cmxucr = &(qe_immr->qmx.cmxucr2); - *reg_num = 2; - *shift = 16; + case 2: guemr = &qe_immr->ucc3.slow.guemr; break; - case 6: *p_cmxucr = &(qe_immr->qmx.cmxucr2); - *reg_num = 2; - *shift = 0; + case 3: guemr = &qe_immr->ucc4.slow.guemr; break; - case 1: *p_cmxucr = &(qe_immr->qmx.cmxucr3); - *reg_num = 3; - *shift = 16; + case 4: guemr = &qe_immr->ucc5.slow.guemr; break; - case 3: *p_cmxucr = &(qe_immr->qmx.cmxucr3); - *reg_num = 3; - *shift = 0; + case 5: guemr = &qe_immr->ucc6.slow.guemr; break; - case 5: *p_cmxucr = &(qe_immr->qmx.cmxucr4); - *reg_num = 4; - *shift = 16; + case 6: guemr = &qe_immr->ucc7.slow.guemr; break; - case 7: *p_cmxucr = &(qe_immr->qmx.cmxucr4); - *reg_num = 4; - *shift = 0; + case 7: guemr = &qe_immr->ucc8.slow.guemr; break; default: - break; + return -EINVAL; } + + clrsetbits_8(guemr, UCC_GUEMR_MODE_MASK, + UCC_GUEMR_SET_RESERVED3 | speed); + + return 0; } -int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask) +static void get_cmxucr_reg(unsigned int ucc_num, __be32 **cmxucr, + unsigned int *reg_num, unsigned int *shift) { - volatile u32 *p_cmxucr; - u8 reg_num; - u8 shift; + unsigned int cmx = ((ucc_num & 1) << 1) + (ucc_num > 3); + + *reg_num = cmx + 1; + *cmxucr = &qe_immr->qmx.cmxucr[cmx]; + *shift = 16 - 8 * (ucc_num & 2); +} + +int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask) +{ + __be32 *cmxucr; + unsigned int reg_num; + unsigned int shift; /* check if the UCC number is in range. */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) + if (ucc_num > UCC_MAX_NUM - 1) return -EINVAL; - get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); + get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift); if (set) - out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift)); + setbits32(cmxucr, mask << shift); else - out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask << shift)); + clrbits32(cmxucr, mask << shift); return 0; } -int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode) +int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock, + enum comm_dir mode) { - volatile u32 *p_cmxucr; - u8 reg_num; - u8 shift; - u32 clock_bits; - u32 clock_mask; - int source = -1; + __be32 *cmxucr; + unsigned int reg_num; + unsigned int shift; + u32 clock_bits = 0; /* check if the UCC number is in range. */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) + if (ucc_num > UCC_MAX_NUM - 1) return -EINVAL; - if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) { - printk(KERN_ERR - "ucc_set_qe_mux_rxtx: bad comm mode type passed."); + /* The communications direction must be RX or TX */ + if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) return -EINVAL; - } - get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); + get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift); switch (reg_num) { case 1: switch (clock) { - case QE_BRG1: source = 1; break; - case QE_BRG2: source = 2; break; - case QE_BRG7: source = 3; break; - case QE_BRG8: source = 4; break; - case QE_CLK9: source = 5; break; - case QE_CLK10: source = 6; break; - case QE_CLK11: source = 7; break; - case QE_CLK12: source = 8; break; - case QE_CLK15: source = 9; break; - case QE_CLK16: source = 10; break; - default: source = -1; break; + case QE_BRG1: clock_bits = 1; break; + case QE_BRG2: clock_bits = 2; break; + case QE_BRG7: clock_bits = 3; break; + case QE_BRG8: clock_bits = 4; break; + case QE_CLK9: clock_bits = 5; break; + case QE_CLK10: clock_bits = 6; break; + case QE_CLK11: clock_bits = 7; break; + case QE_CLK12: clock_bits = 8; break; + case QE_CLK15: clock_bits = 9; break; + case QE_CLK16: clock_bits = 10; break; + default: break; } break; case 2: switch (clock) { - case QE_BRG5: source = 1; break; - case QE_BRG6: source = 2; break; - case QE_BRG7: source = 3; break; - case QE_BRG8: source = 4; break; - case QE_CLK13: source = 5; break; - case QE_CLK14: source = 6; break; - case QE_CLK19: source = 7; break; - case QE_CLK20: source = 8; break; - case QE_CLK15: source = 9; break; - case QE_CLK16: source = 10; break; - default: source = -1; break; + case QE_BRG5: clock_bits = 1; break; + case QE_BRG6: clock_bits = 2; break; + case QE_BRG7: clock_bits = 3; break; + case QE_BRG8: clock_bits = 4; break; + case QE_CLK13: clock_bits = 5; break; + case QE_CLK14: clock_bits = 6; break; + case QE_CLK19: clock_bits = 7; break; + case QE_CLK20: clock_bits = 8; break; + case QE_CLK15: clock_bits = 9; break; + case QE_CLK16: clock_bits = 10; break; + default: break; } break; case 3: switch (clock) { - case QE_BRG9: source = 1; break; - case QE_BRG10: source = 2; break; - case QE_BRG15: source = 3; break; - case QE_BRG16: source = 4; break; - case QE_CLK3: source = 5; break; - case QE_CLK4: source = 6; break; - case QE_CLK17: source = 7; break; - case QE_CLK18: source = 8; break; - case QE_CLK7: source = 9; break; - case QE_CLK8: source = 10; break; - case QE_CLK16: source = 11; break; - default: source = -1; break; + case QE_BRG9: clock_bits = 1; break; + case QE_BRG10: clock_bits = 2; break; + case QE_BRG15: clock_bits = 3; break; + case QE_BRG16: clock_bits = 4; break; + case QE_CLK3: clock_bits = 5; break; + case QE_CLK4: clock_bits = 6; break; + case QE_CLK17: clock_bits = 7; break; + case QE_CLK18: clock_bits = 8; break; + case QE_CLK7: clock_bits = 9; break; + case QE_CLK8: clock_bits = 10; break; + case QE_CLK16: clock_bits = 11; break; + default: break; } break; case 4: switch (clock) { - case QE_BRG13: source = 1; break; - case QE_BRG14: source = 2; break; - case QE_BRG15: source = 3; break; - case QE_BRG16: source = 4; break; - case QE_CLK5: source = 5; break; - case QE_CLK6: source = 6; break; - case QE_CLK21: source = 7; break; - case QE_CLK22: source = 8; break; - case QE_CLK7: source = 9; break; - case QE_CLK8: source = 10; break; - case QE_CLK16: source = 11; break; - default: source = -1; break; + case QE_BRG13: clock_bits = 1; break; + case QE_BRG14: clock_bits = 2; break; + case QE_BRG15: clock_bits = 3; break; + case QE_BRG16: clock_bits = 4; break; + case QE_CLK5: clock_bits = 5; break; + case QE_CLK6: clock_bits = 6; break; + case QE_CLK21: clock_bits = 7; break; + case QE_CLK22: clock_bits = 8; break; + case QE_CLK7: clock_bits = 9; break; + case QE_CLK8: clock_bits = 10; break; + case QE_CLK16: clock_bits = 11; break; + default: break; } break; - default: - source = -1; - break; + default: break; } - if (source == -1) { - printk(KERN_ERR - "ucc_set_qe_mux_rxtx: Bad combination of clock and UCC."); + /* Check for invalid combination of clock and UCC number */ + if (!clock_bits) return -ENOENT; - } - clock_bits = (u32) source; - clock_mask = QE_CMXUCR_TX_CLK_SRC_MASK; - if (mode == COMM_DIR_RX) { - clock_bits <<= 4; /* Rx field is 4 bits to left of Tx field */ - clock_mask <<= 4; /* Rx field is 4 bits to left of Tx field */ - } - clock_bits <<= shift; - clock_mask <<= shift; + if (mode == COMM_DIR_RX) + shift += 4; - out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clock_mask) | clock_bits); + clrsetbits_be32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift, + clock_bits << shift); return 0; } diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c index 3df202e8d332..3223acbc39e5 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -30,46 +30,45 @@ void ucc_fast_dump_regs(struct ucc_fast_private * uccf) { - printk(KERN_INFO "UCC%d Fast registers:", uccf->uf_info->ucc_num); - printk(KERN_INFO "Base address: 0x%08x", (u32) uccf->uf_regs); + printk(KERN_INFO "UCC%u Fast registers:\n", uccf->uf_info->ucc_num); + printk(KERN_INFO "Base address: 0x%p\n", uccf->uf_regs); - printk(KERN_INFO "gumr : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr)); - printk(KERN_INFO "upsmr : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr)); - printk(KERN_INFO "utodr : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr)); - printk(KERN_INFO "udsr : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr)); - printk(KERN_INFO "ucce : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce)); - printk(KERN_INFO "uccm : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm)); - printk(KERN_INFO "uccs : addr - 0x%08x, val - 0x%02x", - (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs); - printk(KERN_INFO "urfb : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb)); - printk(KERN_INFO "urfs : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs)); - printk(KERN_INFO "urfet : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet)); - printk(KERN_INFO "urfset: addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->urfset, - in_be16(&uccf->uf_regs->urfset)); - printk(KERN_INFO "utfb : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb)); - printk(KERN_INFO "utfs : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs)); - printk(KERN_INFO "utfet : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet)); - printk(KERN_INFO "utftt : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt)); - printk(KERN_INFO "utpt : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt)); - printk(KERN_INFO "urtry : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry)); - printk(KERN_INFO "guemr : addr - 0x%08x, val - 0x%02x", - (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr); + printk(KERN_INFO "gumr : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr)); + printk(KERN_INFO "upsmr : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr)); + printk(KERN_INFO "utodr : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr)); + printk(KERN_INFO "udsr : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr)); + printk(KERN_INFO "ucce : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce)); + printk(KERN_INFO "uccm : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm)); + printk(KERN_INFO "uccs : addr=0x%p, val=0x%02x\n", + &uccf->uf_regs->uccs, uccf->uf_regs->uccs); + printk(KERN_INFO "urfb : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb)); + printk(KERN_INFO "urfs : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs)); + printk(KERN_INFO "urfet : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet)); + printk(KERN_INFO "urfset: addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->urfset, in_be16(&uccf->uf_regs->urfset)); + printk(KERN_INFO "utfb : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb)); + printk(KERN_INFO "utfs : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs)); + printk(KERN_INFO "utfet : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet)); + printk(KERN_INFO "utftt : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt)); + printk(KERN_INFO "utpt : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt)); + printk(KERN_INFO "urtry : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry)); + printk(KERN_INFO "guemr : addr=0x%p, val=0x%02x\n", + &uccf->uf_regs->guemr, uccf->uf_regs->guemr); } EXPORT_SYMBOL(ucc_fast_dump_regs); @@ -149,55 +148,57 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* check if the UCC port number is in range. */ if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { - printk(KERN_ERR "%s: illegal UCC number", __FUNCTION__); + printk(KERN_ERR "%s: illegal UCC number\n", __FUNCTION__); return -EINVAL; } /* Check that 'max_rx_buf_length' is properly aligned (4). */ if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: max_rx_buf_length not aligned", __FUNCTION__); + printk(KERN_ERR "%s: max_rx_buf_length not aligned\n", + __FUNCTION__); return -EINVAL; } /* Validate Virtual Fifo register values */ if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) { - printk(KERN_ERR "%s: urfs is too small", __FUNCTION__); + printk(KERN_ERR "%s: urfs is too small\n", __FUNCTION__); return -EINVAL; } if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: urfs is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: urfs is not aligned\n", __FUNCTION__); return -EINVAL; } if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: urfet is not aligned.", __FUNCTION__); + printk(KERN_ERR "%s: urfet is not aligned.\n", __FUNCTION__); return -EINVAL; } if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: urfset is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: urfset is not aligned\n", __FUNCTION__); return -EINVAL; } if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: utfs is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: utfs is not aligned\n", __FUNCTION__); return -EINVAL; } if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: utfet is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: utfet is not aligned\n", __FUNCTION__); return -EINVAL; } if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: utftt is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: utftt is not aligned\n", __FUNCTION__); return -EINVAL; } uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL); if (!uccf) { - printk(KERN_ERR "%s: Cannot allocate private data", __FUNCTION__); + printk(KERN_ERR "%s: Cannot allocate private data\n", + __FUNCTION__); return -ENOMEM; } @@ -206,7 +207,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* Set the PHY base address */ uccf->uf_regs = ioremap(uf_info->regs, sizeof(struct ucc_fast)); if (uccf->uf_regs == NULL) { - printk(KERN_ERR "%s: Cannot map UCC registers", __FUNCTION__); + printk(KERN_ERR "%s: Cannot map UCC registers\n", __FUNCTION__); return -ENOMEM; } @@ -226,18 +227,10 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc uccf->rx_discarded = 0; #endif /* STATISTICS */ - /* Init Guemr register */ - if ((ret = ucc_init_guemr((struct ucc_common *) (uf_regs)))) { - printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__); - ucc_fast_free(uccf); - return ret; - } - /* Set UCC to fast type */ - if ((ret = ucc_set_type(uf_info->ucc_num, - (struct ucc_common *) (uf_regs), - UCC_SPEED_TYPE_FAST))) { - printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__); + ret = ucc_set_type(uf_info->ucc_num, UCC_SPEED_TYPE_FAST); + if (ret) { + printk(KERN_ERR "%s: cannot set UCC type\n", __FUNCTION__); ucc_fast_free(uccf); return ret; } @@ -276,7 +269,8 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc uccf->ucc_fast_tx_virtual_fifo_base_offset = qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); if (IS_ERR_VALUE(uccf->ucc_fast_tx_virtual_fifo_base_offset)) { - printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO", __FUNCTION__); + printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO\n", + __FUNCTION__); uccf->ucc_fast_tx_virtual_fifo_base_offset = 0; ucc_fast_free(uccf); return -ENOMEM; @@ -288,7 +282,8 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); if (IS_ERR_VALUE(uccf->ucc_fast_rx_virtual_fifo_base_offset)) { - printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO", __FUNCTION__); + printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO\n", + __FUNCTION__); uccf->ucc_fast_rx_virtual_fifo_base_offset = 0; ucc_fast_free(uccf); return -ENOMEM; @@ -318,7 +313,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc if ((uf_info->rx_clock != QE_CLK_NONE) && ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->rx_clock, COMM_DIR_RX)) { - printk(KERN_ERR "%s: illegal value for RX clock", + printk(KERN_ERR "%s: illegal value for RX clock\n", __FUNCTION__); ucc_fast_free(uccf); return -EINVAL; @@ -327,7 +322,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc if ((uf_info->tx_clock != QE_CLK_NONE) && ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->tx_clock, COMM_DIR_TX)) { - printk(KERN_ERR "%s: illegal value for TX clock", + printk(KERN_ERR "%s: illegal value for TX clock\n", __FUNCTION__); ucc_fast_free(uccf); return -EINVAL; diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index 1f65c26ce63f..0174b3aeef8f 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -115,11 +115,15 @@ void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) out_be32(&us_regs->gumr_l, gumr_l); } +/* Initialize the UCC for Slow operations + * + * The caller should initialize the following us_info + */ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret) { struct ucc_slow_private *uccs; u32 i; - struct ucc_slow *us_regs; + struct ucc_slow __iomem *us_regs; u32 gumr; struct qe_bd *bd; u32 id; @@ -131,7 +135,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* check if the UCC port number is in range. */ if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) { - printk(KERN_ERR "%s: illegal UCC number", __FUNCTION__); + printk(KERN_ERR "%s: illegal UCC number\n", __FUNCTION__); return -EINVAL; } @@ -143,13 +147,14 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc */ if ((!us_info->rfw) && (us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) { - printk(KERN_ERR "max_rx_buf_length not aligned."); + printk(KERN_ERR "max_rx_buf_length not aligned.\n"); return -EINVAL; } uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL); if (!uccs) { - printk(KERN_ERR "%s: Cannot allocate private data", __FUNCTION__); + printk(KERN_ERR "%s: Cannot allocate private data\n", + __FUNCTION__); return -ENOMEM; } @@ -158,7 +163,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* Set the PHY base address */ uccs->us_regs = ioremap(us_info->regs, sizeof(struct ucc_slow)); if (uccs->us_regs == NULL) { - printk(KERN_ERR "%s: Cannot map UCC registers", __FUNCTION__); + printk(KERN_ERR "%s: Cannot map UCC registers\n", __FUNCTION__); return -ENOMEM; } @@ -182,22 +187,14 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc return -ENOMEM; } id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); - qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, QE_CR_PROTOCOL_UNSPECIFIED, + qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, us_info->protocol, uccs->us_pram_offset); uccs->us_pram = qe_muram_addr(uccs->us_pram_offset); - /* Init Guemr register */ - if ((ret = ucc_init_guemr((struct ucc_common *) us_regs))) { - printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__); - ucc_slow_free(uccs); - return ret; - } - /* Set UCC to slow type */ - if ((ret = ucc_set_type(us_info->ucc_num, - (struct ucc_common *) us_regs, - UCC_SPEED_TYPE_SLOW))) { + ret = ucc_set_type(us_info->ucc_num, UCC_SPEED_TYPE_SLOW); + if (ret) { printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__); ucc_slow_free(uccs); return ret; @@ -212,7 +209,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd), QE_ALIGNMENT_OF_BD); if (IS_ERR_VALUE(uccs->rx_base_offset)) { - printk(KERN_ERR "%s: cannot allocate RX BDs", __FUNCTION__); + printk(KERN_ERR "%s: cannot allocate %u RX BDs\n", __FUNCTION__, + us_info->rx_bd_ring_len); uccs->rx_base_offset = 0; ucc_slow_free(uccs); return -ENOMEM; @@ -292,12 +290,12 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* if the data is in cachable memory, the 'global' */ /* in the function code should be set. */ - uccs->us_pram->tfcr = uccs->us_pram->rfcr = - us_info->data_mem_part | QE_BMR_BYTE_ORDER_BO_MOT; + uccs->us_pram->tbmr = UCC_BMR_BO_BE; + uccs->us_pram->rbmr = UCC_BMR_BO_BE; /* rbase, tbase are offsets from MURAM base */ - out_be16(&uccs->us_pram->rbase, uccs->us_pram_offset); - out_be16(&uccs->us_pram->tbase, uccs->us_pram_offset); + out_be16(&uccs->us_pram->rbase, uccs->rx_base_offset); + out_be16(&uccs->us_pram->tbase, uccs->tx_base_offset); /* Mux clocking */ /* Grant Support */ @@ -311,7 +309,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* Rx clock routing */ if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->rx_clock, COMM_DIR_RX)) { - printk(KERN_ERR "%s: illegal value for RX clock", + printk(KERN_ERR "%s: illegal value for RX clock\n", __FUNCTION__); ucc_slow_free(uccs); return -EINVAL; @@ -319,7 +317,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* Tx clock routing */ if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->tx_clock, COMM_DIR_TX)) { - printk(KERN_ERR "%s: illegal value for TX clock", + printk(KERN_ERR "%s: illegal value for TX clock\n", __FUNCTION__); ucc_slow_free(uccs); return -EINVAL; @@ -343,8 +341,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc command = QE_INIT_TX; else command = QE_INIT_RX; /* We know at least one is TRUE */ - id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); - qe_issue_cmd(command, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); + + qe_issue_cmd(command, id, us_info->protocol, 0); *uccs_ret = uccs; return 0; diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 9a38dfe45f8f..7dedc9609603 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2919,7 +2919,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) test = in_be16(&ugeth->p_tx_glbl_pram->temoder); /* Function code register value to be used later */ - function_code = QE_BMR_BYTE_ORDER_BO_MOT | UCC_FAST_FUNCTION_CODE_GBL; + function_code = UCC_BMR_BO_BE | UCC_BMR_GBL; /* Required for QE */ /* function code register */ diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index bb4dac8c0c65..1aa69023cde1 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -44,6 +44,7 @@ struct ucc_geth { struct ucc_fast uccf; + u8 res0[0x100 - sizeof(struct ucc_fast)]; u32 maccfg1; /* mac configuration reg. 1 */ u32 maccfg2; /* mac configuration reg. 2 */ diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h index 02548f74ccb7..aba9806b31c9 100644 --- a/include/asm-powerpc/immap_qe.h +++ b/include/asm-powerpc/immap_qe.h @@ -97,10 +97,7 @@ struct qe_mux { __be32 cmxsi1cr_l; /* CMX SI1 clock route low register */ __be32 cmxsi1cr_h; /* CMX SI1 clock route high register */ __be32 cmxsi1syr; /* CMX SI1 SYNC route register */ - __be32 cmxucr1; /* CMX UCC1, UCC3 clock route register */ - __be32 cmxucr2; /* CMX UCC5, UCC7 clock route register */ - __be32 cmxucr3; /* CMX UCC2, UCC4 clock route register */ - __be32 cmxucr4; /* CMX UCC6, UCC8 clock route register */ + __be32 cmxucr[4]; /* CMX UCCx clock route registers */ __be32 cmxupcr; /* CMX UPC clock route register */ u8 res0[0x1C]; } __attribute__ ((packed)); @@ -261,7 +258,6 @@ struct ucc_slow { __be16 utpt; u8 res4[0x52]; u8 guemr; /* UCC general extended mode register */ - u8 res5[0x200 - 0x091]; } __attribute__ ((packed)); /* QE UCC Fast */ @@ -294,21 +290,13 @@ struct ucc_fast { __be32 urtry; /* UCC retry counter register */ u8 res8[0x4C]; u8 guemr; /* UCC general extended mode register */ - u8 res9[0x100 - 0x091]; -} __attribute__ ((packed)); - -/* QE UCC */ -struct ucc_common { - u8 res1[0x90]; - u8 guemr; - u8 res2[0x200 - 0x091]; } __attribute__ ((packed)); struct ucc { union { struct ucc_slow slow; struct ucc_fast fast; - struct ucc_common common; + u8 res[0x200]; /* UCC blocks are 512 bytes each */ }; } __attribute__ ((packed)); @@ -407,7 +395,7 @@ struct dbg { /* RISC Special Registers (Trap and Breakpoint) */ struct rsp { - u8 fixme[0x100]; + u32 reg[0x40]; /* 64 32-bit registers */ } __attribute__ ((packed)); struct qe_immap { @@ -436,11 +424,13 @@ struct qe_immap { u8 res13[0x600]; struct upc upc2; /* MultiPHY UTOPIA POS Ctrlr 2*/ struct sdma sdma; /* SDMA */ - struct dbg dbg; /* Debug Space */ - struct rsp rsp[0x2]; /* RISC Special Registers + struct dbg dbg; /* 0x104080 - 0x1040FF + Debug Space */ + struct rsp rsp[0x2]; /* 0x104100 - 0x1042FF + RISC Special Registers (Trap and Breakpoint) */ - u8 res14[0x300]; - u8 res15[0x3A00]; + u8 res14[0x300]; /* 0x104300 - 0x1045FF */ + u8 res15[0x3A00]; /* 0x104600 - 0x107FFF */ u8 res16[0x8000]; /* 0x108000 - 0x110000 */ u8 muram[0xC000]; /* 0x110000 - 0x11C000 Multi-user RAM */ @@ -451,7 +441,7 @@ struct qe_immap { extern struct qe_immap *qe_immr; extern phys_addr_t get_qe_base(void); -static inline unsigned long immrbar_virt_to_phys(volatile void * address) +static inline unsigned long immrbar_virt_to_phys(void *address) { if ( ((u32)address >= (u32)qe_immr) && ((u32)address < ((u32)qe_immr + QE_IMMAP_SIZE)) ) diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h index ad23c580631c..0dabe46a29d2 100644 --- a/include/asm-powerpc/qe.h +++ b/include/asm-powerpc/qe.h @@ -38,7 +38,7 @@ extern int par_io_data_set(u8 port, u8 pin, u8 val); /* QE internal API */ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); -void qe_setbrg(u32 brg, u32 rate); +void qe_setbrg(unsigned int brg, unsigned int rate, unsigned int multiplier); int qe_get_snum(void); void qe_put_snum(u8 snum); unsigned long qe_muram_alloc(int size, int align); @@ -49,14 +49,28 @@ void *qe_muram_addr(unsigned long offset); /* Buffer descriptors */ struct qe_bd { - u16 status; - u16 length; - u32 buf; + __be16 status; + __be16 length; + __be32 buf; } __attribute__ ((packed)); #define BD_STATUS_MASK 0xffff0000 #define BD_LENGTH_MASK 0x0000ffff +#define BD_SC_EMPTY 0x8000 /* Receive is empty */ +#define BD_SC_READY 0x8000 /* Transmit is ready */ +#define BD_SC_WRAP 0x2000 /* Last buffer descriptor */ +#define BD_SC_INTRPT 0x1000 /* Interrupt on change */ +#define BD_SC_LAST 0x0800 /* Last buffer in frame */ +#define BD_SC_CM 0x0200 /* Continous mode */ +#define BD_SC_ID 0x0100 /* Rec'd too many idles */ +#define BD_SC_P 0x0100 /* xmt preamble */ +#define BD_SC_BR 0x0020 /* Break received */ +#define BD_SC_FR 0x0010 /* Framing error */ +#define BD_SC_PR 0x0008 /* Parity error */ +#define BD_SC_OV 0x0002 /* Overrun */ +#define BD_SC_CD 0x0001 /* ?? */ + /* Alignment */ #define QE_INTR_TABLE_ALIGN 16 /* ??? */ #define QE_ALIGNMENT_OF_BD 8 @@ -269,15 +283,12 @@ enum qe_clock { /* QE CECR Protocol - For non-MCC, specifies mode for QE CECR command */ #define QE_CR_PROTOCOL_UNSPECIFIED 0x00 /* For all other protocols */ #define QE_CR_PROTOCOL_HDLC_TRANSPARENT 0x00 +#define QE_CR_PROTOCOL_QMC 0x02 +#define QE_CR_PROTOCOL_UART 0x04 #define QE_CR_PROTOCOL_ATM_POS 0x0A #define QE_CR_PROTOCOL_ETHERNET 0x0C #define QE_CR_PROTOCOL_L2_SWITCH 0x0D -/* BMR byte order */ -#define QE_BMR_BYTE_ORDER_BO_PPC 0x08 /* powerpc little endian */ -#define QE_BMR_BYTE_ORDER_BO_MOT 0x10 /* motorola big endian */ -#define QE_BMR_BYTE_ORDER_BO_MAX 0x18 - /* BRG configuration register */ #define QE_BRGC_ENABLE 0x00010000 #define QE_BRGC_DIVISOR_SHIFT 1 @@ -324,41 +335,41 @@ enum qe_clock { #define UPGCR_ADDR 0x10000000 /* Master MPHY Addr multiplexing */ #define UPGCR_DIAG 0x01000000 /* Diagnostic mode */ -/* UCC */ +/* UCC GUEMR register */ #define UCC_GUEMR_MODE_MASK_RX 0x02 -#define UCC_GUEMR_MODE_MASK_TX 0x01 #define UCC_GUEMR_MODE_FAST_RX 0x02 -#define UCC_GUEMR_MODE_FAST_TX 0x01 #define UCC_GUEMR_MODE_SLOW_RX 0x00 +#define UCC_GUEMR_MODE_MASK_TX 0x01 +#define UCC_GUEMR_MODE_FAST_TX 0x01 #define UCC_GUEMR_MODE_SLOW_TX 0x00 +#define UCC_GUEMR_MODE_MASK (UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX) #define UCC_GUEMR_SET_RESERVED3 0x10 /* Bit 3 in the guemr is reserved but must be set 1 */ /* structure representing UCC SLOW parameter RAM */ struct ucc_slow_pram { - u16 rbase; /* RX BD base address */ - u16 tbase; /* TX BD base address */ - u8 rfcr; /* Rx function code */ - u8 tfcr; /* Tx function code */ - u16 mrblr; /* Rx buffer length */ - u32 rstate; /* Rx internal state */ - u32 rptr; /* Rx internal data pointer */ - u16 rbptr; /* rb BD Pointer */ - u16 rcount; /* Rx internal byte count */ - u32 rtemp; /* Rx temp */ - u32 tstate; /* Tx internal state */ - u32 tptr; /* Tx internal data pointer */ - u16 tbptr; /* Tx BD pointer */ - u16 tcount; /* Tx byte count */ - u32 ttemp; /* Tx temp */ - u32 rcrc; /* temp receive CRC */ - u32 tcrc; /* temp transmit CRC */ + __be16 rbase; /* RX BD base address */ + __be16 tbase; /* TX BD base address */ + u8 rbmr; /* RX bus mode register (same as CPM's RFCR) */ + u8 tbmr; /* TX bus mode register (same as CPM's TFCR) */ + __be16 mrblr; /* Rx buffer length */ + __be32 rstate; /* Rx internal state */ + __be32 rptr; /* Rx internal data pointer */ + __be16 rbptr; /* rb BD Pointer */ + __be16 rcount; /* Rx internal byte count */ + __be32 rtemp; /* Rx temp */ + __be32 tstate; /* Tx internal state */ + __be32 tptr; /* Tx internal data pointer */ + __be16 tbptr; /* Tx BD pointer */ + __be16 tcount; /* Tx byte count */ + __be32 ttemp; /* Tx temp */ + __be32 rcrc; /* temp receive CRC */ + __be32 tcrc; /* temp transmit CRC */ } __attribute__ ((packed)); /* General UCC SLOW Mode Register (GUMRH & GUMRL) */ -#define UCC_SLOW_GUMR_H_CRC16 0x00004000 -#define UCC_SLOW_GUMR_H_CRC16CCITT 0x00000000 -#define UCC_SLOW_GUMR_H_CRC32CCITT 0x00008000 +#define UCC_SLOW_GUMR_H_SAM_QMC 0x00000000 +#define UCC_SLOW_GUMR_H_SAM_SATM 0x00008000 #define UCC_SLOW_GUMR_H_REVD 0x00002000 #define UCC_SLOW_GUMR_H_TRX 0x00001000 #define UCC_SLOW_GUMR_H_TTX 0x00000800 @@ -378,9 +389,33 @@ struct ucc_slow_pram { #define UCC_SLOW_GUMR_L_TCI 0x10000000 #define UCC_SLOW_GUMR_L_RINV 0x02000000 #define UCC_SLOW_GUMR_L_TINV 0x01000000 -#define UCC_SLOW_GUMR_L_TEND 0x00020000 +#define UCC_SLOW_GUMR_L_TEND 0x00040000 +#define UCC_SLOW_GUMR_L_TDCR_MASK 0x00030000 +#define UCC_SLOW_GUMR_L_TDCR_32 0x00030000 +#define UCC_SLOW_GUMR_L_TDCR_16 0x00020000 +#define UCC_SLOW_GUMR_L_TDCR_8 0x00010000 +#define UCC_SLOW_GUMR_L_TDCR_1 0x00000000 +#define UCC_SLOW_GUMR_L_RDCR_MASK 0x0000c000 +#define UCC_SLOW_GUMR_L_RDCR_32 0x0000c000 +#define UCC_SLOW_GUMR_L_RDCR_16 0x00008000 +#define UCC_SLOW_GUMR_L_RDCR_8 0x00004000 +#define UCC_SLOW_GUMR_L_RDCR_1 0x00000000 +#define UCC_SLOW_GUMR_L_RENC_NRZI 0x00000800 +#define UCC_SLOW_GUMR_L_RENC_NRZ 0x00000000 +#define UCC_SLOW_GUMR_L_TENC_NRZI 0x00000100 +#define UCC_SLOW_GUMR_L_TENC_NRZ 0x00000000 +#define UCC_SLOW_GUMR_L_DIAG_MASK 0x000000c0 +#define UCC_SLOW_GUMR_L_DIAG_LE 0x000000c0 +#define UCC_SLOW_GUMR_L_DIAG_ECHO 0x00000080 +#define UCC_SLOW_GUMR_L_DIAG_LOOP 0x00000040 +#define UCC_SLOW_GUMR_L_DIAG_NORM 0x00000000 #define UCC_SLOW_GUMR_L_ENR 0x00000020 #define UCC_SLOW_GUMR_L_ENT 0x00000010 +#define UCC_SLOW_GUMR_L_MODE_MASK 0x0000000F +#define UCC_SLOW_GUMR_L_MODE_BISYNC 0x00000008 +#define UCC_SLOW_GUMR_L_MODE_AHDLC 0x00000006 +#define UCC_SLOW_GUMR_L_MODE_UART 0x00000004 +#define UCC_SLOW_GUMR_L_MODE_QMC 0x00000002 /* General UCC FAST Mode Register */ #define UCC_FAST_GUMR_TCI 0x20000000 @@ -397,53 +432,111 @@ struct ucc_slow_pram { #define UCC_FAST_GUMR_ENR 0x00000020 #define UCC_FAST_GUMR_ENT 0x00000010 -/* Slow UCC Event Register (UCCE) */ -#define UCC_SLOW_UCCE_GLR 0x1000 -#define UCC_SLOW_UCCE_GLT 0x0800 -#define UCC_SLOW_UCCE_DCC 0x0400 -#define UCC_SLOW_UCCE_FLG 0x0200 -#define UCC_SLOW_UCCE_AB 0x0200 -#define UCC_SLOW_UCCE_IDLE 0x0100 -#define UCC_SLOW_UCCE_GRA 0x0080 -#define UCC_SLOW_UCCE_TXE 0x0010 -#define UCC_SLOW_UCCE_RXF 0x0008 -#define UCC_SLOW_UCCE_CCR 0x0008 -#define UCC_SLOW_UCCE_RCH 0x0008 -#define UCC_SLOW_UCCE_BSY 0x0004 -#define UCC_SLOW_UCCE_TXB 0x0002 -#define UCC_SLOW_UCCE_TX 0x0002 -#define UCC_SLOW_UCCE_RX 0x0001 -#define UCC_SLOW_UCCE_GOV 0x0001 -#define UCC_SLOW_UCCE_GUN 0x0002 -#define UCC_SLOW_UCCE_GINT 0x0004 -#define UCC_SLOW_UCCE_IQOV 0x0008 +/* UART Slow UCC Event Register (UCCE) */ +#define UCC_UART_UCCE_AB 0x0200 +#define UCC_UART_UCCE_IDLE 0x0100 +#define UCC_UART_UCCE_GRA 0x0080 +#define UCC_UART_UCCE_BRKE 0x0040 +#define UCC_UART_UCCE_BRKS 0x0020 +#define UCC_UART_UCCE_CCR 0x0008 +#define UCC_UART_UCCE_BSY 0x0004 +#define UCC_UART_UCCE_TX 0x0002 +#define UCC_UART_UCCE_RX 0x0001 -#define UCC_SLOW_UCCE_HDLC_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ - UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF | \ - UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) -#define UCC_SLOW_UCCE_ENET_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ - UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF) -#define UCC_SLOW_UCCE_TRANS_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ - UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \ - UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) -#define UCC_SLOW_UCCE_UART_SET (UCC_SLOW_UCCE_BSY | UCC_SLOW_UCCE_GRA | \ - UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \ - UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) -#define UCC_SLOW_UCCE_QMC_SET (UCC_SLOW_UCCE_IQOV | UCC_SLOW_UCCE_GINT | \ - UCC_SLOW_UCCE_GUN | UCC_SLOW_UCCE_GOV) +/* HDLC Slow UCC Event Register (UCCE) */ +#define UCC_HDLC_UCCE_GLR 0x1000 +#define UCC_HDLC_UCCE_GLT 0x0800 +#define UCC_HDLC_UCCE_IDLE 0x0100 +#define UCC_HDLC_UCCE_BRKE 0x0040 +#define UCC_HDLC_UCCE_BRKS 0x0020 +#define UCC_HDLC_UCCE_TXE 0x0010 +#define UCC_HDLC_UCCE_RXF 0x0008 +#define UCC_HDLC_UCCE_BSY 0x0004 +#define UCC_HDLC_UCCE_TXB 0x0002 +#define UCC_HDLC_UCCE_RXB 0x0001 -#define UCC_SLOW_UCCE_OTHER (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ - UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | \ - UCC_SLOW_UCCE_GLR) +/* BISYNC Slow UCC Event Register (UCCE) */ +#define UCC_BISYNC_UCCE_GRA 0x0080 +#define UCC_BISYNC_UCCE_TXE 0x0010 +#define UCC_BISYNC_UCCE_RCH 0x0008 +#define UCC_BISYNC_UCCE_BSY 0x0004 +#define UCC_BISYNC_UCCE_TXB 0x0002 +#define UCC_BISYNC_UCCE_RXB 0x0001 -#define UCC_SLOW_INTR_TX UCC_SLOW_UCCE_TXB -#define UCC_SLOW_INTR_RX (UCC_SLOW_UCCE_RXF | UCC_SLOW_UCCE_RX) -#define UCC_SLOW_INTR (UCC_SLOW_INTR_TX | UCC_SLOW_INTR_RX) +/* Gigabit Ethernet Fast UCC Event Register (UCCE) */ +#define UCC_GETH_UCCE_MPD 0x80000000 +#define UCC_GETH_UCCE_SCAR 0x40000000 +#define UCC_GETH_UCCE_GRA 0x20000000 +#define UCC_GETH_UCCE_CBPR 0x10000000 +#define UCC_GETH_UCCE_BSY 0x08000000 +#define UCC_GETH_UCCE_RXC 0x04000000 +#define UCC_GETH_UCCE_TXC 0x02000000 +#define UCC_GETH_UCCE_TXE 0x01000000 +#define UCC_GETH_UCCE_TXB7 0x00800000 +#define UCC_GETH_UCCE_TXB6 0x00400000 +#define UCC_GETH_UCCE_TXB5 0x00200000 +#define UCC_GETH_UCCE_TXB4 0x00100000 +#define UCC_GETH_UCCE_TXB3 0x00080000 +#define UCC_GETH_UCCE_TXB2 0x00040000 +#define UCC_GETH_UCCE_TXB1 0x00020000 +#define UCC_GETH_UCCE_TXB0 0x00010000 +#define UCC_GETH_UCCE_RXB7 0x00008000 +#define UCC_GETH_UCCE_RXB6 0x00004000 +#define UCC_GETH_UCCE_RXB5 0x00002000 +#define UCC_GETH_UCCE_RXB4 0x00001000 +#define UCC_GETH_UCCE_RXB3 0x00000800 +#define UCC_GETH_UCCE_RXB2 0x00000400 +#define UCC_GETH_UCCE_RXB1 0x00000200 +#define UCC_GETH_UCCE_RXB0 0x00000100 +#define UCC_GETH_UCCE_RXF7 0x00000080 +#define UCC_GETH_UCCE_RXF6 0x00000040 +#define UCC_GETH_UCCE_RXF5 0x00000020 +#define UCC_GETH_UCCE_RXF4 0x00000010 +#define UCC_GETH_UCCE_RXF3 0x00000008 +#define UCC_GETH_UCCE_RXF2 0x00000004 +#define UCC_GETH_UCCE_RXF1 0x00000002 +#define UCC_GETH_UCCE_RXF0 0x00000001 + +/* UPSMR, when used as a UART */ +#define UCC_UART_UPSMR_FLC 0x8000 +#define UCC_UART_UPSMR_SL 0x4000 +#define UCC_UART_UPSMR_CL_MASK 0x3000 +#define UCC_UART_UPSMR_CL_8 0x3000 +#define UCC_UART_UPSMR_CL_7 0x2000 +#define UCC_UART_UPSMR_CL_6 0x1000 +#define UCC_UART_UPSMR_CL_5 0x0000 +#define UCC_UART_UPSMR_UM_MASK 0x0c00 +#define UCC_UART_UPSMR_UM_NORMAL 0x0000 +#define UCC_UART_UPSMR_UM_MAN_MULTI 0x0400 +#define UCC_UART_UPSMR_UM_AUTO_MULTI 0x0c00 +#define UCC_UART_UPSMR_FRZ 0x0200 +#define UCC_UART_UPSMR_RZS 0x0100 +#define UCC_UART_UPSMR_SYN 0x0080 +#define UCC_UART_UPSMR_DRT 0x0040 +#define UCC_UART_UPSMR_PEN 0x0010 +#define UCC_UART_UPSMR_RPM_MASK 0x000c +#define UCC_UART_UPSMR_RPM_ODD 0x0000 +#define UCC_UART_UPSMR_RPM_LOW 0x0004 +#define UCC_UART_UPSMR_RPM_EVEN 0x0008 +#define UCC_UART_UPSMR_RPM_HIGH 0x000C +#define UCC_UART_UPSMR_TPM_MASK 0x0003 +#define UCC_UART_UPSMR_TPM_ODD 0x0000 +#define UCC_UART_UPSMR_TPM_LOW 0x0001 +#define UCC_UART_UPSMR_TPM_EVEN 0x0002 +#define UCC_UART_UPSMR_TPM_HIGH 0x0003 /* UCC Transmit On Demand Register (UTODR) */ #define UCC_SLOW_TOD 0x8000 #define UCC_FAST_TOD 0x8000 +/* UCC Bus Mode Register masks */ +/* Not to be confused with the Bundle Mode Register */ +#define UCC_BMR_GBL 0x20 +#define UCC_BMR_BO_BE 0x10 +#define UCC_BMR_CETM 0x04 +#define UCC_BMR_DTB 0x02 +#define UCC_BMR_BDB 0x01 + /* Function code masks */ #define FC_GBL 0x20 #define FC_DTB_LCL 0x02 diff --git a/include/asm-powerpc/ucc.h b/include/asm-powerpc/ucc.h index afe3076bdc03..46b09ba6bead 100644 --- a/include/asm-powerpc/ucc.h +++ b/include/asm-powerpc/ucc.h @@ -25,58 +25,38 @@ /* Slow or fast type for UCCs. */ enum ucc_speed_type { - UCC_SPEED_TYPE_FAST, UCC_SPEED_TYPE_SLOW -}; - -/* Initial UCCs Parameter RAM address relative to: MEM_MAP_BASE (IMMR). -*/ -enum ucc_pram_initial_offset { - UCC_PRAM_OFFSET_UCC1 = 0x8400, - UCC_PRAM_OFFSET_UCC2 = 0x8500, - UCC_PRAM_OFFSET_UCC3 = 0x8600, - UCC_PRAM_OFFSET_UCC4 = 0x9000, - UCC_PRAM_OFFSET_UCC5 = 0x8000, - UCC_PRAM_OFFSET_UCC6 = 0x8100, - UCC_PRAM_OFFSET_UCC7 = 0x8200, - UCC_PRAM_OFFSET_UCC8 = 0x8300 + UCC_SPEED_TYPE_FAST = UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX, + UCC_SPEED_TYPE_SLOW = UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX }; /* ucc_set_type * Sets UCC to slow or fast mode. * * ucc_num - (In) number of UCC (0-7). - * regs - (In) pointer to registers base for the UCC. * speed - (In) slow or fast mode for UCC. */ -int ucc_set_type(int ucc_num, struct ucc_common *regs, - enum ucc_speed_type speed); +int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed); -/* ucc_init_guemr - * Init the Guemr register. - * - * regs - (In) pointer to registers base for the UCC. - */ -int ucc_init_guemr(struct ucc_common *regs); +int ucc_set_qe_mux_mii_mng(unsigned int ucc_num); -int ucc_set_qe_mux_mii_mng(int ucc_num); +int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock, + enum comm_dir mode); -int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode); - -int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask); +int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask); /* QE MUX clock routing for UCC */ -static inline int ucc_set_qe_mux_grant(int ucc_num, int set) +static inline int ucc_set_qe_mux_grant(unsigned int ucc_num, int set) { return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_GRANT); } -static inline int ucc_set_qe_mux_tsa(int ucc_num, int set) +static inline int ucc_set_qe_mux_tsa(unsigned int ucc_num, int set) { return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_TSA); } -static inline int ucc_set_qe_mux_bkpt(int ucc_num, int set) +static inline int ucc_set_qe_mux_bkpt(unsigned int ucc_num, int set) { return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_BKPT); } diff --git a/include/asm-powerpc/ucc_slow.h b/include/asm-powerpc/ucc_slow.h index fdaac9d762bb..0980e6ad335b 100644 --- a/include/asm-powerpc/ucc_slow.h +++ b/include/asm-powerpc/ucc_slow.h @@ -148,9 +148,10 @@ enum ucc_slow_diag_mode { struct ucc_slow_info { int ucc_num; + int protocol; /* QE_CR_PROTOCOL_xxx */ enum qe_clock rx_clock; enum qe_clock tx_clock; - u32 regs; + phys_addr_t regs; int irq; u16 uccm_mask; int data_mem_part; @@ -186,7 +187,7 @@ struct ucc_slow_info { struct ucc_slow_private { struct ucc_slow_info *us_info; - struct ucc_slow *us_regs; /* a pointer to memory map of UCC regs */ + struct ucc_slow __iomem *us_regs; /* Ptr to memory map of UCC regs */ struct ucc_slow_pram *us_pram; /* a pointer to the parameter RAM */ u32 us_pram_offset; int enabled_tx; /* Whether channel is enabled for Tx (ENT) */ @@ -277,12 +278,12 @@ void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs); */ void ucc_slow_stop_tx(struct ucc_slow_private * uccs); -/* ucc_slow_restart_x +/* ucc_slow_restart_tx * Restarts transmitting on a specified slow UCC. * * uccs - (In) pointer to the slow UCC structure. */ -void ucc_slow_restart_x(struct ucc_slow_private * uccs); +void ucc_slow_restart_tx(struct ucc_slow_private *uccs); u32 ucc_slow_get_qe_cr_subblock(int uccs_num); From 33799e337997284a4b845743fc43af52f66babd7 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 3 Oct 2007 17:44:58 +0200 Subject: [PATCH 0474/2804] [POWERPC] spi: Use fsl_spi instead of mpc83xx_spi According to booting-without-of.txt, compatible should be "fsl_spi" and mode "cpu" or "qe" for the fsl SPI controllers. Signed-off-by: Peter Korsgaard Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8313erdb.dts | 4 ++-- arch/powerpc/boot/dts/mpc8349emitx.dts | 4 ++-- arch/powerpc/boot/dts/mpc8349emitxgp.dts | 4 ++-- arch/powerpc/boot/dts/mpc834x_mds.dts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts index a8eadc8c4497..9e7eba973262 100644 --- a/arch/powerpc/boot/dts/mpc8313erdb.dts +++ b/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -71,11 +71,11 @@ spi@7000 { device_type = "spi"; - compatible = "mpc83xx_spi"; + compatible = "fsl_spi"; reg = <7000 1000>; interrupts = <10 8>; interrupt-parent = < &ipic >; - mode = <0>; + mode = "cpu"; }; /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */ diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index 3bc32029ca5b..5072f6d0a46d 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -70,11 +70,11 @@ spi@7000 { device_type = "spi"; - compatible = "mpc83xx_spi"; + compatible = "fsl_spi"; reg = <7000 1000>; interrupts = <10 8>; interrupt-parent = < &ipic >; - mode = <0>; + mode = "cpu"; }; usb@22000 { diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index 36a27607f766..074f7a2ab7e4 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -70,11 +70,11 @@ spi@7000 { device_type = "spi"; - compatible = "mpc83xx_spi"; + compatible = "fsl_spi"; reg = <7000 1000>; interrupts = <10 8>; interrupt-parent = < &ipic >; - mode = <0>; + mode = "cpu"; }; usb@23000 { diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index c27e2fff5d58..e5a84ef9f4b0 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -76,11 +76,11 @@ spi@7000 { device_type = "spi"; - compatible = "mpc83xx_spi"; + compatible = "fsl_spi"; reg = <7000 1000>; interrupts = <10 8>; interrupt-parent = < &ipic >; - mode = <0>; + mode = "cpu"; }; /* phy type (ULPI or SERIAL) are only types supportted for MPH */ From f023dc769c47b9158d897ee8a0278bdfe39b0115 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 3 Oct 2007 18:29:09 +0200 Subject: [PATCH 0475/2804] [POWERPC] spi: mode should be "cpu-qe" instead of "qe" Mode should be "cpu-qe" for QE in CPU mode. "qe" should be reserved for native QE mode. Signed-off-by: Peter Korsgaard Signed-off-by: Kumar Gala --- Documentation/powerpc/booting-without-of.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index ce5d67f5cb5c..7a6c5f2f3b00 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1551,7 +1551,7 @@ platforms are moved over to use the flattened-device-tree model. Required properties: - device_type : should be "spi". - compatible : should be "fsl_spi". - - mode : the SPI operation mode, it can be "cpu" or "qe". + - mode : the SPI operation mode, it can be "cpu" or "cpu-qe". - reg : Offset and length of the register set for the device - interrupts : where a is the interrupt number and b is a field that represents an encoding of the sense and level From 53f3945a160af9a2282b9fad0f6ccde25e4ed805 Mon Sep 17 00:00:00 2001 From: Xianghua Xiao Date: Wed, 3 Oct 2007 15:09:15 -0500 Subject: [PATCH 0476/2804] [POWERPC] Add initial MPC8610 HPCD Device Tree Source file. Signed-off-by: Xianghua Xiao Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8610_hpcd.dts | 191 +++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 arch/powerpc/boot/dts/mpc8610_hpcd.dts diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts new file mode 100644 index 000000000000..966edf1161a6 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts @@ -0,0 +1,191 @@ +/* + * MPC8610 HPCD Device Tree Source + * + * Copyright 2007 Freescale Semiconductor 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. + */ + + +/ { + model = "MPC8610HPCD"; + compatible = "fsl,MPC8610HPCD"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8610@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = ; // bytes + i-cache-line-size = ; // bytes + d-cache-size = <8000>; // L1, 32K + i-cache-size = <8000>; // L1, 32K + timebase-frequency = <0>; // 33 MHz, from uboot + bus-frequency = <0>; // From uboot + clock-frequency = <0>; // From uboot + }; + }; + + memory { + device_type = "memory"; + reg = <00000000 20000000>; // 512M at 0x0 + }; + + soc@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = ; + bus-frequency = <0>; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <3000 100>; + interrupts = <2b 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <3100 100>; + interrupts = <2b 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = <0>; + interrupts = <2a 2>; + interrupt-parent = <&mpic>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = <0>; + interrupts = <1c 2>; + interrupt-parent = <&mpic>; + }; + + + mpic: interrupt-controller@40000 { + clock-frequency = <0>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <40000 40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + big-endian; + }; + + global-utilities@e0000 { + compatible = "fsl,mpc8610-guts"; + reg = ; + fsl,has-rstcr; + }; + }; + + pci@e0008000 { + compatible = "fsl,mpc8610-pci"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <0 0>; + ranges = <02000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 e1000000 0 00100000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x11 */ + 8800 0 0 1 &mpic 4 1 + 8800 0 0 2 &mpic 5 1 + 8800 0 0 3 &mpic 6 1 + 8800 0 0 4 &mpic 7 1 + + /* IDSEL 0x12 */ + 9000 0 0 1 &mpic 5 1 + 9000 0 0 2 &mpic 6 1 + 9000 0 0 3 &mpic 7 1 + 9000 0 0 4 &mpic 4 1 + >; + }; + + pcie@e000a000 { + compatible = "fsl,mpc8641-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = ; + bus-range = <1 3>; + ranges = <02000000 0 a0000000 a0000000 0 10000000 + 01000000 0 00000000 e3000000 0 00100000>; + clock-frequency = <1fca055>; + interrupt-parent = <&mpic>; + interrupts = <1a 2>; + interrupt-map-mask = ; + + interrupt-map = < + /* IDSEL 0x1b */ + d800 0 0 1 &mpic 2 1 + + /* IDSEL 0x1c*/ + e000 0 0 1 &mpic 1 1 + e000 0 0 2 &mpic 1 1 + e000 0 0 3 &mpic 1 1 + e000 0 0 4 &mpic 1 1 + + /* IDSEL 0x1f */ + f800 0 0 1 &mpic 3 0 + f800 0 0 2 &mpic 0 1 + >; + + pcie@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <02000000 0 a0000000 + 02000000 0 a0000000 + 0 10000000 + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + uli1575@0 { + reg = <0 0 0 0 0>; + #size-cells = <2>; + #address-cells = <3>; + ranges = <02000000 0 a0000000 + 02000000 0 a0000000 + 0 10000000 + 01000000 0 00000000 + 01000000 0 00000000 + 0 00100000>; + }; + }; + }; +}; From 61c5d3cde10689867b86c8352aa0295637e941cb Mon Sep 17 00:00:00 2001 From: Jason Jin Date: Wed, 3 Oct 2007 15:09:50 -0500 Subject: [PATCH 0477/2804] [POWERPC] Treat 8610 PCIe host bridge as transparent Signed-off-by: Jason Jin Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 1 + include/linux/pci_ids.h | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 34cad96e0de9..98290f4ef3df 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -259,3 +259,4 @@ DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8572E, quirk_fsl_pcie_transpare DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8572, quirk_fsl_pcie_transparent); DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_transparent); DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_transparent); +DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_transparent); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 545f24ce2638..bb244a42f7a1 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2104,6 +2104,7 @@ #define PCI_DEVICE_ID_MPC8572 0x0041 #define PCI_DEVICE_ID_MPC8641 0x7010 #define PCI_DEVICE_ID_MPC8641D 0x7011 +#define PCI_DEVICE_ID_MPC8610 0x7018 #define PCI_VENDOR_ID_PASEMI 0x1959 From 0e65bfe34c1000581746b9889d095241c4cf4a5c Mon Sep 17 00:00:00 2001 From: Xianghua Xiao Date: Wed, 3 Oct 2007 15:09:33 -0500 Subject: [PATCH 0478/2804] [POWERPC] Add initial MPC8610 HPCD Platform files. Add basic board support for the MPC8610 HPCD. This does not include any support the SoC Display or Audio controllers. Signed-off-by: Xianghua Xiao Signed-off-by: Jason Jin Signed-off-by: Jon Loelier Signed-off-by: Kumar Gala --- arch/powerpc/configs/mpc8610_hpcd_defconfig | 1023 +++++++++++++++++++ arch/powerpc/platforms/86xx/Kconfig | 13 + arch/powerpc/platforms/86xx/Makefile | 1 + arch/powerpc/platforms/86xx/mpc8610_hpcd.c | 233 +++++ 4 files changed, 1270 insertions(+) create mode 100644 arch/powerpc/configs/mpc8610_hpcd_defconfig create mode 100644 arch/powerpc/platforms/86xx/mpc8610_hpcd.c diff --git a/arch/powerpc/configs/mpc8610_hpcd_defconfig b/arch/powerpc/configs/mpc8610_hpcd_defconfig new file mode 100644 index 000000000000..de19b781937f --- /dev/null +++ b/arch/powerpc/configs/mpc8610_hpcd_defconfig @@ -0,0 +1,1023 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc6 +# Tue Oct 2 11:42:56 2007 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +CONFIG_6xx=y +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_PPC_FPU=y +CONFIG_ALTIVEC=y +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_PPC_MM_SLICES is not set +# CONFIG_SMP is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +# CONFIG_SYSVIPC is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" + +# +# Platform support +# +# CONFIG_PPC_MULTIPLATFORM is not set +# CONFIG_EMBEDDED6xx is not set +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +CONFIG_PPC_86xx=y +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +# CONFIG_MPC8641_HPCN is not set +CONFIG_MPC8610_HPCD=y +CONFIG_MPC8610=y +CONFIG_MPIC=y +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPM2 is not set +# CONFIG_FSL_ULI1575 is not set + +# +# Kernel options +# +CONFIG_HIGHMEM=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SUSPEND_UP_POSSIBLE=y +CONFIG_HIBERNATION_UP_POSSIBLE=y +# CONFIG_SECCOMP is not set +# CONFIG_WANT_DEVICE_TREE is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +CONFIG_FSL_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +CONFIG_PCI_DEBUG=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +# CONFIG_BLK_DEV_IDE is not set +# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_SATA_AHCI=y +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +CONFIG_PATA_ALI=y +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ARCNET is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_FIXED_PHY is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set +CONFIG_NETDEV_1000=y +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_GIANFAR is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +CONFIG_NETDEV_10000=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +CONFIG_NFSD_TCP=y +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_CRYPTO is not set diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 685b2fbbbe00..21d113536b86 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -11,6 +11,12 @@ config MPC8641_HPCN help This option enables support for the MPC8641 HPCN board. +config MPC8610_HPCD + bool "Freescale MPC8610 HPCD" + select DEFAULT_UIMAGE + help + This option enables support for the MPC8610 HPCD board. + endchoice config MPC8641 @@ -19,3 +25,10 @@ config MPC8641 select PPC_UDBG_16550 select MPIC default y if MPC8641_HPCN + +config MPC8610 + bool + select FSL_PCI if PCI + select PPC_UDBG_16550 + select MPIC + default y if MPC8610_HPCD diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 3376c7767f2d..c96706327eaa 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o +obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c new file mode 100644 index 000000000000..c794d88fa55f --- /dev/null +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -0,0 +1,233 @@ +/* + * MPC8610 HPCD board specific routines + * + * Initial author: Xianghua Xiao + * Recode: Jason Jin + * + * Rewrite the interrupt routing. remove the 8259PIC support, + * All the integrated device in ULI use sideband interrupt. + * + * Copyright 2007 Freescale Semiconductor 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 +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define MPC86XX_RSTCR_OFFSET (0xe00b0) /* Reset Control Register */ + +void __init +mpc86xx_hpcd_init_irq(void) +{ + struct mpic *mpic1; + struct device_node *np; + struct resource res; + + /* Determine PIC address. */ + np = of_find_node_by_type(NULL, "open-pic"); + if (np == NULL) + return; + of_address_to_resource(np, 0, &res); + + /* Alloc mpic structure and per isu has 16 INT entries. */ + mpic1 = mpic_alloc(np, res.start, + MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + 0, 256, " MPIC "); + BUG_ON(mpic1 == NULL); + + mpic_init(mpic1); +} + +#ifdef CONFIG_PCI +static void __devinit quirk_uli1575(struct pci_dev *dev) +{ + u32 temp32; + + /* Disable INTx */ + pci_read_config_dword(dev, 0x48, &temp32); + pci_write_config_dword(dev, 0x48, (temp32 | 1<<26)); + + /* Enable sideband interrupt */ + pci_read_config_dword(dev, 0x90, &temp32); + pci_write_config_dword(dev, 0x90, (temp32 | 1<<22)); +} + +static void __devinit quirk_uli5288(struct pci_dev *dev) +{ + unsigned char c; + unsigned short temp; + + /* Interrupt Disable, Needed when SATA disabled */ + pci_read_config_word(dev, PCI_COMMAND, &temp); + temp |= 1<<10; + pci_write_config_word(dev, PCI_COMMAND, temp); + + pci_read_config_byte(dev, 0x83, &c); + c |= 0x80; + pci_write_config_byte(dev, 0x83, c); + + pci_write_config_byte(dev, PCI_CLASS_PROG, 0x01); + pci_write_config_byte(dev, PCI_CLASS_DEVICE, 0x06); + + pci_read_config_byte(dev, 0x83, &c); + c &= 0x7f; + pci_write_config_byte(dev, 0x83, c); +} + +/* + * Since 8259PIC was disabled on the board, the IDE device can not + * use the legacy IRQ, we need to let the IDE device work under + * native mode and use the interrupt line like other PCI devices. + * IRQ14 is a sideband interrupt from IDE device to CPU and we use this + * as the interrupt for IDE device. + */ +static void __devinit quirk_uli5229(struct pci_dev *dev) +{ + unsigned char c; + + pci_read_config_byte(dev, 0x4b, &c); + c |= 0x10; + pci_write_config_byte(dev, 0x4b, c); +} + +/* + * SATA interrupt pin bug fix + * There's a chip bug for 5288, The interrupt pin should be 2, + * not the read only value 1, So it use INTB#, not INTA# which + * actually used by the IDE device 5229. + * As of this bug, during the PCI initialization, 5288 read the + * irq of IDE device from the device tree, this function fix this + * bug by re-assigning a correct irq to 5288. + * + */ +static void __devinit final_uli5288(struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct device_node *hosenode = hose ? hose->arch_data : NULL; + struct of_irq oirq; + int virq, pin = 2; + u32 laddr[3]; + + if (!hosenode) + return; + + laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8); + laddr[1] = laddr[2] = 0; + of_irq_map_raw(hosenode, &pin, 1, laddr, &oirq); + virq = irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); + dev->irq = virq; +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_uli1575); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, final_uli5288); +#endif /* CONFIG_PCI */ + +static void __init +mpc86xx_hpcd_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; +#endif + if (ppc_md.progress) + ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8610-pci") + || of_device_is_compatible(np, "fsl,mpc8641-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == 0xa000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } + } +#endif + + printk("MPC86xx HPCD board from Freescale Semiconductor\n"); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc86xx_hpcd_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "fsl,MPC8610HPCD")) + return 1; /* Looks good */ + + return 0; +} + +void +mpc86xx_restart(char *cmd) +{ + void __iomem *rstcr; + + rstcr = ioremap(get_immrbase() + MPC86XX_RSTCR_OFFSET, 0x100); + + local_irq_disable(); + + /* Assert reset request to Reset Control Register */ + out_be32(rstcr, 0x2); + + /* not reached */ +} + +long __init +mpc86xx_time_init(void) +{ + unsigned int temp; + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + temp = mfspr(SPRN_HID0); + temp |= HID0_TBEN; + mtspr(SPRN_HID0, temp); + asm volatile("isync"); + + return 0; +} + +define_machine(mpc86xx_hpcd) { + .name = "MPC86xx HPCD", + .probe = mpc86xx_hpcd_probe, + .setup_arch = mpc86xx_hpcd_setup_arch, + .init_IRQ = mpc86xx_hpcd_init_irq, + .get_irq = mpic_get_irq, + .restart = mpc86xx_restart, + .time_init = mpc86xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +}; From 873553b3d6b3b19f187a5630300ece20bbf74afd Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Wed, 3 Oct 2007 12:01:40 -0700 Subject: [PATCH 0479/2804] [POWERPC] 85xx: Failure with odd memory sizes and CONFIG_HIGHMEM The CONFIG_FSL_BOOKE mmu setup code fails when CONFIG_HIGHMEM=y and the 3 fixed TLB entries cannot exactly map the lowmem size. Each TLB entry can map 4MB, 16MB, 64MB or 256MB, so the failure is observed when the kernel lowmem size is not equal to the sum of up to 3 of those values. Normally, memory is sized in nice numbers, but I observed this problem while testing a crash dump kernel. The failure can also be observed by artificially reducing the kernel's main memory via the mem= kernel command line parameter. This commit fixes the problem by setting __initial_memory_limit in adjust_total_lowmem(). Signed-off-by: Dale Farnsworth Signed-off-by: Kumar Gala --- arch/powerpc/mm/fsl_booke_mmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index afab247d472f..17139daeaff4 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -59,6 +59,7 @@ unsigned int num_tlbcam_entries; static unsigned long __cam0, __cam1, __cam2; extern unsigned long total_lowmem; extern unsigned long __max_low_memory; +extern unsigned long __initial_memory_limit; #define MAX_LOW_MEM CONFIG_LOWMEM_SIZE #define NUM_TLBCAMS (16) @@ -232,4 +233,5 @@ adjust_total_lowmem(void) __cam0 >> 20, __cam1 >> 20, __cam2 >> 20, (total_lowmem - __cam0 - __cam1 - __cam2) >> 20); __max_low_memory = max_low_mem = __cam0 + __cam1 + __cam2; + __initial_memory_limit = __max_low_memory; } From 2fce1225af6f2d3bb9ffb4e6253400db61278594 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 3 Oct 2007 23:37:33 -0500 Subject: [PATCH 0480/2804] [POWERPC] FSL: Access PCIe LTSSM register with correct size The LTSSM register is actual 32-bits wide so we should be doing a dword access. Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 98290f4ef3df..af090c93be10 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -160,8 +160,8 @@ static void __init quirk_fsl_pcie_transparent(struct pci_dev *dev) int __init fsl_pcie_check_link(struct pci_controller *hose) { - u16 val; - early_read_config_word(hose, 0, 0, PCIE_LTSSM, &val); + u32 val; + early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val); if (val < PCIE_LTSSM_L0) return 1; return 0; From c9438affcb7ac0dda4c6c6961637fb272f7c32d4 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 4 Oct 2007 00:28:43 -0500 Subject: [PATCH 0481/2804] [POWERPC] Use for_each_ matching routinues for pci PHBs On the Freescale embedded (83xx, 85xx, 86xx) and a few of the discrete bridges (mpc10x, tsi108) use the new for_each_compatible_node() or for_each_node_by_type() to provide more exact matching when looking for PHBs in the device tree. With the previous code it was possible to match on pci bridges since we were only matching on device_type. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/mpc8313_rdb.c | 2 +- arch/powerpc/platforms/83xx/mpc832x_mds.c | 2 +- arch/powerpc/platforms/83xx/mpc832x_rdb.c | 2 +- arch/powerpc/platforms/83xx/mpc834x_itx.c | 2 +- arch/powerpc/platforms/83xx/mpc834x_mds.c | 2 +- arch/powerpc/platforms/83xx/mpc836x_mds.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 3 ++- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 18 +++++++++++------- arch/powerpc/platforms/85xx/mpc85xx_ds.c | 18 +++++++++++------- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 14 +++++++++++--- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 3 ++- .../platforms/embedded6xx/linkstation.c | 2 +- .../platforms/embedded6xx/mpc7448_hpc2.c | 2 +- 13 files changed, 45 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c index 140b46ffdb19..33766b8f2594 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c @@ -43,7 +43,7 @@ static void __init mpc8313_rdb_setup_arch(void) ppc_md.progress("mpc8313_rdb_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); #endif mpc831x_usb_cfg(); diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index d494bc456458..b8d8c914569b 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -73,7 +73,7 @@ static void __init mpc832x_sys_setup_arch(void) } #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); #endif diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 24a790c79ec0..4da0698487c0 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -93,7 +93,7 @@ static void __init mpc832x_rdb_setup_arch(void) ppc_md.progress("mpc832x_rdb_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); #endif diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 870fd20461ce..aa768199432d 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -52,7 +52,7 @@ static void __init mpc834x_itx_setup_arch(void) ppc_md.progress("mpc834x_itx_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); #endif diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index a9140b64b98a..00aed7c2269e 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -83,7 +83,7 @@ static void __init mpc834x_mds_setup_arch(void) ppc_md.progress("mpc834x_mds_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); #endif diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index db6957611585..0b18a75e9200 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -79,7 +79,7 @@ static void __init mpc836x_mds_setup_arch(void) } #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index c22bc1c4f591..acb1ef932240 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -204,8 +204,9 @@ static void __init mpc85xx_ads_setup_arch(void) #endif #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") fsl_add_bridge(np, 1); + ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 665e8df05dc5..abc85b8d9f8a 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -283,14 +283,18 @@ static void __init mpc85xx_cds_setup_arch(void) } #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == 0x8000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } } + ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup; ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 4d449022ac9b..d60bb2beeb55 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -149,14 +149,18 @@ static void __init mpc85xx_ds_setup_arch(void) ppc_md.progress("mpc85xx_ds_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == primary_phb_addr) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == primary_phb_addr) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } } + uses_fsl_uli_m1575 = 1; ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index c379286c3730..f8b6b08af848 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -83,9 +83,17 @@ static void __init mpc85xx_mds_setup_arch(void) } #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - fsl_add_bridge(np, 1); - of_node_put(np); + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == 0x8000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } + } #endif #ifdef CONFIG_QUICC_ENGINE diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 3ec9d5a25750..6879b83ef95a 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -140,7 +140,7 @@ mpc86xx_hpcn_setup_arch(void) ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { + for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") { struct resource rsrc; of_address_to_resource(np, 0, &rsrc); if ((rsrc.start & 0xfffff) == 0x8000) @@ -148,6 +148,7 @@ mpc86xx_hpcn_setup_arch(void) else fsl_add_bridge(np, 0); } + uses_fsl_uli_m1575 = 1; ppc_md.pci_exclude_device = mpc86xx_exclude_device; diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index f392374309b3..eb5d74e26fe9 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -91,7 +91,7 @@ static void __init linkstation_setup_arch(void) #endif /* Lookup PCI host bridges */ - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "mpc10x-pci") linkstation_add_bridge(np); printk(KERN_INFO "BUFFALO Network Attached Storage Series\n"); diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 96737e5608d3..a2c04b9d42b1 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -74,7 +74,7 @@ static void __init mpc7448_hpc2_setup_arch(void) /* setup PCI host bridge */ #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "tsi108-pci") tsi108_setup_pci(np, MPC7448HPC2_PCI_CFG_PHYS, 0); ppc_md.pci_exclude_device = mpc7448_hpc2_exclude_device; From e1c1575f831ab2165732037e6d664010a0149730 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 4 Oct 2007 01:04:57 -0500 Subject: [PATCH 0482/2804] [POWERPC] 85xx/86xx: refactor RSTCR reset code On the majority of 85xx & 86xx we have a register that's ability to assert HRESET_REQ to reset the board. We refactored that code so it can be shared between both platforms into fsl_soc.c and removed all the duplication in each platform directory. Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8641_hpcn.dts | 6 +++ arch/powerpc/platforms/85xx/Makefile | 1 - arch/powerpc/platforms/85xx/misc.c | 55 ---------------------- arch/powerpc/platforms/85xx/mpc85xx.h | 17 ------- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 3 +- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 5 +- arch/powerpc/platforms/85xx/mpc85xx_ds.c | 5 +- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 4 +- arch/powerpc/platforms/86xx/mpc8610_hpcd.c | 19 +------- arch/powerpc/platforms/86xx/mpc8641_hpcn.h | 21 --------- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 20 +------- arch/powerpc/sysdev/fsl_soc.c | 38 +++++++++++++++ arch/powerpc/sysdev/fsl_soc.h | 1 + 13 files changed, 53 insertions(+), 142 deletions(-) delete mode 100644 arch/powerpc/platforms/85xx/misc.c delete mode 100644 arch/powerpc/platforms/85xx/mpc85xx.h delete mode 100644 arch/powerpc/platforms/86xx/mpc8641_hpcn.h diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts index f797662212ba..367765937a06 100644 --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts @@ -214,6 +214,12 @@ device_type = "open-pic"; big-endian; }; + + global-utilities@e0000 { + compatible = "fsl,mpc8641-guts"; + reg = ; + fsl,has-rstcr; + }; }; pcie@f8008000 { diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 25bd9e2d4946..5eca92023ec8 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -1,7 +1,6 @@ # # Makefile for the PowerPC 85xx linux kernel. # -obj-$(CONFIG_PPC_85xx) += misc.o obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o diff --git a/arch/powerpc/platforms/85xx/misc.c b/arch/powerpc/platforms/85xx/misc.c deleted file mode 100644 index 4fe376e9c3b6..000000000000 --- a/arch/powerpc/platforms/85xx/misc.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MPC85xx generic code. - * - * Maintained by Kumar Gala (see MAINTAINERS for contact information) - * - * Copyright 2005 Freescale Semiconductor 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 - -static __be32 __iomem *rstcr; - -extern void abort(void); - -static int __init mpc85xx_rstcr(void) -{ - struct device_node *np; - np = of_find_node_by_name(NULL, "global-utilities"); - if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) { - const u32 *prop = of_get_property(np, "reg", NULL); - if (prop) { - /* map reset control register - * 0xE00B0 is offset of reset control register - */ - rstcr = ioremap(get_immrbase() + *prop + 0xB0, 0xff); - if (!rstcr) - printk (KERN_EMERG "Error: reset control " - "register not mapped!\n"); - } - } else - printk (KERN_INFO "rstcr compatible register does not exist!\n"); - if (np) - of_node_put(np); - return 0; -} - -arch_initcall(mpc85xx_rstcr); - -void mpc85xx_restart(char *cmd) -{ - local_irq_disable(); - if (rstcr) - /* set reset control register */ - out_be32(rstcr, 0x2); /* HRESET_REQ */ - abort(); -} diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h deleted file mode 100644 index 5b34deef12b5..000000000000 --- a/arch/powerpc/platforms/85xx/mpc85xx.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * arch/powerpc/platforms/85xx/mpc85xx.h - * - * MPC85xx soc definitions/function decls - * - * Maintainer: Kumar Gala - * - * Copyright 2005 Freescale Semiconductor 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. - * - */ - -extern void mpc85xx_restart(char *); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index acb1ef932240..378a244b3bac 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -30,7 +30,6 @@ #include #include -#include "mpc85xx.h" #ifdef CONFIG_CPM2 #include @@ -249,7 +248,7 @@ define_machine(mpc85xx_ads) { .init_IRQ = mpc85xx_ads_pic_init, .show_cpuinfo = mpc85xx_ads_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index abc85b8d9f8a..afe5868cd975 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -46,7 +46,6 @@ #include #include -#include "mpc85xx.h" static int cds_pci_slot = 2; static volatile u8 *cadmus; @@ -96,7 +95,7 @@ static void mpc85xx_cds_restart(char *cmd) * If we can't find the VIA chip (maybe the P2P bridge is disabled) * or the VIA chip reset didn't work, just use the default reset. */ - mpc85xx_restart(NULL); + fsl_rstcr_restart(NULL); } static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev) @@ -343,7 +342,7 @@ define_machine(mpc85xx_cds) { .restart = mpc85xx_cds_restart, .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #else - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, #endif .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index d60bb2beeb55..772e8de9310e 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -33,7 +33,6 @@ #include #include -#include "mpc85xx.h" #undef DEBUG @@ -211,7 +210,7 @@ define_machine(mpc8544_ds) { .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif .get_irq = mpic_get_irq, - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; @@ -225,7 +224,7 @@ define_machine(mpc8572_ds) { .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif .get_irq = mpic_get_irq, - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index f8b6b08af848..00f4c3aef78b 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -50,8 +50,6 @@ #include #include -#include "mpc85xx.h" - #undef DEBUG #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -200,7 +198,7 @@ define_machine(mpc85xx_mds) { .setup_arch = mpc85xx_mds_setup_arch, .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index c794d88fa55f..6390895e5e92 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -37,8 +37,6 @@ #include #include -#define MPC86XX_RSTCR_OFFSET (0xe00b0) /* Reset Control Register */ - void __init mpc86xx_hpcd_init_irq(void) { @@ -187,21 +185,6 @@ static int __init mpc86xx_hpcd_probe(void) return 0; } -void -mpc86xx_restart(char *cmd) -{ - void __iomem *rstcr; - - rstcr = ioremap(get_immrbase() + MPC86XX_RSTCR_OFFSET, 0x100); - - local_irq_disable(); - - /* Assert reset request to Reset Control Register */ - out_be32(rstcr, 0x2); - - /* not reached */ -} - long __init mpc86xx_time_init(void) { @@ -225,7 +208,7 @@ define_machine(mpc86xx_hpcd) { .setup_arch = mpc86xx_hpcd_setup_arch, .init_IRQ = mpc86xx_hpcd_init_irq, .get_irq = mpic_get_irq, - .restart = mpc86xx_restart, + .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h deleted file mode 100644 index 41e554c4af94..000000000000 --- a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * MPC8641 HPCN board definitions - * - * Copyright 2006 Freescale Semiconductor 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. - * - * Author: Xianghua Xiao - */ - -#ifndef __MPC8641_HPCN_H__ -#define __MPC8641_HPCN_H__ - -#include - -#define MPC86XX_RSTCR_OFFSET (0xe00b0) /* Reset Control Register */ - -#endif /* __MPC8641_HPCN_H__ */ diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 6879b83ef95a..32a531aebcb7 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -35,7 +35,6 @@ #include #include "mpc86xx.h" -#include "mpc8641_hpcn.h" #undef DEBUG @@ -196,23 +195,6 @@ static int __init mpc86xx_hpcn_probe(void) return 0; } - -void -mpc86xx_restart(char *cmd) -{ - void __iomem *rstcr; - - rstcr = ioremap(get_immrbase() + MPC86XX_RSTCR_OFFSET, 0x100); - - local_irq_disable(); - - /* Assert reset request to Reset Control Register */ - out_be32(rstcr, 0x2); - - /* not reached */ -} - - long __init mpc86xx_time_init(void) { @@ -237,7 +219,7 @@ define_machine(mpc86xx_hpcn) { .init_IRQ = mpc86xx_hpcn_init_irq, .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = mpc86xx_restart, + .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index c765d7a5217b..be5e0bda2318 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -1298,3 +1298,41 @@ err: return spi_register_board_info(board_infos, num_board_infos); } + +#if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx) +static __be32 __iomem *rstcr; + +static int __init setup_rstcr(void) +{ + struct device_node *np; + np = of_find_node_by_name(NULL, "global-utilities"); + if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) { + const u32 *prop = of_get_property(np, "reg", NULL); + if (prop) { + /* map reset control register + * 0xE00B0 is offset of reset control register + */ + rstcr = ioremap(get_immrbase() + *prop + 0xB0, 0xff); + if (!rstcr) + printk (KERN_EMERG "Error: reset control " + "register not mapped!\n"); + } + } else + printk (KERN_INFO "rstcr compatible register does not exist!\n"); + if (np) + of_node_put(np); + return 0; +} + +arch_initcall(setup_rstcr); + +void fsl_rstcr_restart(char *cmd) +{ + local_irq_disable(); + if (rstcr) + /* set reset control register */ + out_be32(rstcr, 0x2); /* HRESET_REQ */ + + while (1) ; +} +#endif diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 618d91d1e103..63e7db30a4cd 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -15,5 +15,6 @@ extern int fsl_spi_init(struct spi_board_info *board_infos, void (*activate_cs)(u8 cs, u8 polarity), void (*deactivate_cs)(u8 cs, u8 polarity)); +extern void fsl_rstcr_restart(char *cmd); #endif #endif From 090fe850f9520eaedf6de50877e0c5b95349f225 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 2 Oct 2007 16:27:13 -0500 Subject: [PATCH 0483/2804] [POWERPC] 86xx: update immap_86xx.h for the 8610 Update the definition of the global utilities structure (ccsr_guts) in immap_86xx.h and add some related macros for the Freescale 8610 SOC. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala --- include/asm-powerpc/immap_86xx.h | 86 +++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/include/asm-powerpc/immap_86xx.h b/include/asm-powerpc/immap_86xx.h index c83d7ad16606..0ad4e653d464 100644 --- a/include/asm-powerpc/immap_86xx.h +++ b/include/asm-powerpc/immap_86xx.h @@ -38,7 +38,8 @@ struct ccsr_guts { __be32 pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */ u8 res6[0x70 - 0x64]; __be32 devdisr; /* 0x.0070 - Device Disable Control */ - u8 res7[0x80 - 0x74]; + __be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */ + u8 res7[0x80 - 0x78]; __be32 powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */ u8 res8[0x90 - 0x84]; __be32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */ @@ -48,18 +49,87 @@ struct ccsr_guts { __be32 svr; /* 0x.00a4 - System Version Register */ u8 res10[0xB0 - 0xA8]; __be32 rstcr; /* 0x.00b0 - Reset Control Register */ - u8 res11[0xB20 - 0xB4]; - __be32 ddr1clkdr; /* 0x.0b20 - DDRC1 Clock Disable Register */ - __be32 ddr2clkdr; /* 0x.0b24 - DDRC2 Clock Disable Register */ - u8 res12[0xE00 - 0xB28]; + u8 res11[0xC0 - 0xB4]; + __be32 elbcvselcr; /* 0x.00c0 - eLBC Voltage Select Ctrl Reg */ + u8 res12[0x800 - 0xC4]; + __be32 clkdvdr; /* 0x.0800 - Clock Divide Register */ + u8 res13[0x900 - 0x804]; + __be32 ircr; /* 0x.0900 - Infrared Control Register */ + u8 res14[0x908 - 0x904]; + __be32 dmacr; /* 0x.0908 - DMA Control Register */ + u8 res15[0x914 - 0x90C]; + __be32 elbccr; /* 0x.0914 - eLBC Control Register */ + u8 res16[0xB20 - 0x918]; + __be32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */ + __be32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */ + __be32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */ + u8 res17[0xE00 - 0xB2C]; __be32 clkocr; /* 0x.0e00 - Clock Out Select Register */ - u8 res13[0xF04 - 0xE04]; + u8 res18[0xE10 - 0xE04]; + __be32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */ + u8 res19[0xE20 - 0xE14]; + __be32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */ + u8 res20[0xF04 - 0xE24]; __be32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */ __be32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */ - u8 res14[0xF40 - 0xF0C]; + u8 res21[0xF40 - 0xF0C]; __be32 srds2cr0; /* 0x.0f40 - SerDes1 Control Register 0 */ __be32 srds2cr1; /* 0x.0f44 - SerDes1 Control Register 0 */ -}; +} __attribute__ ((packed)); + +#define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */ +#define CCSR_GUTS_DMACR_DEV_IR 1 /* DMA controller/channel set to IR */ + +/* + * Set the DMACR register in the GUTS + * + * The DMACR register determines the source of initiated transfers for each + * channel on each DMA controller. Rather than have a bunch of repetitive + * macros for the bit patterns, we just have a function that calculates + * them. + * + * guts: Pointer to GUTS structure + * co: The DMA controller (1 or 2) + * ch: The channel on the DMA controller (0, 1, 2, or 3) + * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx) + */ +static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts, + unsigned int co, unsigned int ch, unsigned int device) +{ + unsigned int shift = 16 + (8 * (2 - co) + 2 * (3 - ch)); + + clrsetbits_be32(&guts->dmacr, 3 << shift, device << shift); +} + +#define CCSR_GUTS_PMUXCR_LDPSEL 0x00010000 +#define CCSR_GUTS_PMUXCR_SSI1_MASK 0x0000C000 /* Bitmask for SSI1 */ +#define CCSR_GUTS_PMUXCR_SSI1_LA 0x00000000 /* Latched address */ +#define CCSR_GUTS_PMUXCR_SSI1_HI 0x00004000 /* High impedance */ +#define CCSR_GUTS_PMUXCR_SSI1_SSI 0x00008000 /* Used for SSI1 */ +#define CCSR_GUTS_PMUXCR_SSI2_MASK 0x00003000 /* Bitmask for SSI2 */ +#define CCSR_GUTS_PMUXCR_SSI2_LA 0x00000000 /* Latched address */ +#define CCSR_GUTS_PMUXCR_SSI2_HI 0x00001000 /* High impedance */ +#define CCSR_GUTS_PMUXCR_SSI2_SSI 0x00002000 /* Used for SSI2 */ +#define CCSR_GUTS_PMUXCR_LA_22_25_LA 0x00000000 /* Latched Address */ +#define CCSR_GUTS_PMUXCR_LA_22_25_HI 0x00000400 /* High impedance */ +#define CCSR_GUTS_PMUXCR_DBGDRV 0x00000200 /* Signals not driven */ +#define CCSR_GUTS_PMUXCR_DMA2_0 0x00000008 +#define CCSR_GUTS_PMUXCR_DMA2_3 0x00000004 +#define CCSR_GUTS_PMUXCR_DMA1_0 0x00000002 +#define CCSR_GUTS_PMUXCR_DMA1_3 0x00000001 + +#define CCSR_GUTS_CLKDVDR_PXCKEN 0x80000000 +#define CCSR_GUTS_CLKDVDR_SSICKEN 0x20000000 +#define CCSR_GUTS_CLKDVDR_PXCKINV 0x10000000 +#define CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT 25 +#define CCSR_GUTS_CLKDVDR_PXCKDLY_MASK 0x06000000 +#define CCSR_GUTS_CLKDVDR_PXCKDLY(x) \ + (((x) & 3) << CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT) +#define CCSR_GUTS_CLKDVDR_PXCLK_SHIFT 16 +#define CCSR_GUTS_CLKDVDR_PXCLK_MASK 0x001F0000 +#define CCSR_GUTS_CLKDVDR_PXCLK(x) (((x) & 31) << CCSR_GUTS_CLKDVDR_PXCLK_SHIFT) +#define CCSR_GUTS_CLKDVDR_SSICLK_MASK 0x000000FF +#define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK) #endif /* __ASM_POWERPC_IMMAP_86XX_H__ */ #endif /* __KERNEL__ */ From 55f9ed0f6a3af19b5b5cc633eced658723bd3395 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 5 Oct 2007 21:47:38 +0400 Subject: [PATCH 0484/2804] [POWERPC] mpc85xx_mds: select QUICC_ENGINE Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index b8476b20a424..cf815b22b9fb 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -25,7 +25,7 @@ config MPC85xx_CDS config MPC85xx_MDS bool "Freescale MPC85xx MDS" select DEFAULT_UIMAGE -# select QUICC_ENGINE + select QUICC_ENGINE help This option enables support for the MPC85xx MDS board From cccd21027c17c27ad275093c22475354b4495814 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 5 Oct 2007 21:47:29 +0400 Subject: [PATCH 0485/2804] [POWERPC] QEIC: Implement pluggable handlers, fix MPIC cascading set_irq_chained_handler overwrites MPIC's handle_irq function (handle_fasteoi_irq) thus MPIC never gets eoi event from the cascaded IRQ. This situation hangs MPIC on MPC8568E. To solve this problem efficiently, QEIC needs pluggable handlers, specific to the underlaying interrupt controller. Patch extends qe_ic_init() function to accept low and high interrupt handlers. To avoid #ifdefs, stack of interrupt handlers specified in the header file and functions are marked 'static inline', thus handlers are compiled-in only if actually used (in the board file). Another option would be to lookup for parent controller and automatically detect handlers (will waste text size because of never used handlers, so this option abolished). qe_ic_init() also changed in regard to support multiplexed high/low lines as found in MPC8568E-MDS, plus qe_ic_cascade_muxed_mpic() handler implemented appropriately. Signed-off-by: Anton Vorontsov Acked-by: Benjamin Herrenschmidt Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/mpc832x_mds.c | 2 +- arch/powerpc/platforms/83xx/mpc832x_rdb.c | 2 +- arch/powerpc/platforms/83xx/mpc836x_mds.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 2 +- arch/powerpc/sysdev/qe_lib/qe_ic.c | 29 +++------- include/asm-powerpc/qe_ic.h | 68 ++++++++++++++++++++++- 6 files changed, 78 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index b8d8c914569b..972fa8528a8c 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -140,7 +140,7 @@ static void __init mpc832x_sys_init_IRQ(void) if (!np) return; - qe_ic_init(np, 0); + qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 4da0698487c0..fbca336aa0ae 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -151,7 +151,7 @@ void __init mpc832x_rdb_init_IRQ(void) if (!np) return; - qe_ic_init(np, 0); + qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 0b18a75e9200..0f3855c95ff5 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -147,7 +147,7 @@ static void __init mpc836x_mds_init_IRQ(void) if (!np) return; - qe_ic_init(np, 0); + qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 00f4c3aef78b..57e840a1c027 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -180,7 +180,7 @@ static void __init mpc85xx_mds_pic_init(void) if (!np) return; - qe_ic_init(np, 0); + qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 9a2d1edd050e..e1c0fd6dbc1a 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -321,25 +321,9 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic) return irq_linear_revmap(qe_ic->irqhost, irq); } -void qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc) -{ - struct qe_ic *qe_ic = desc->handler_data; - unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); - - if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq); -} - -void qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc) -{ - struct qe_ic *qe_ic = desc->handler_data; - unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); - - if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq); -} - -void __init qe_ic_init(struct device_node *node, unsigned int flags) +void __init qe_ic_init(struct device_node *node, unsigned int flags, + void (*low_handler)(unsigned int irq, struct irq_desc *desc), + void (*high_handler)(unsigned int irq, struct irq_desc *desc)) { struct qe_ic *qe_ic; struct resource res; @@ -399,11 +383,12 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags) qe_ic_write(qe_ic->regs, QEIC_CICR, temp); set_irq_data(qe_ic->virq_low, qe_ic); - set_irq_chained_handler(qe_ic->virq_low, qe_ic_cascade_low); + set_irq_chained_handler(qe_ic->virq_low, low_handler); - if (qe_ic->virq_high != NO_IRQ) { + if (qe_ic->virq_high != NO_IRQ && + qe_ic->virq_high != qe_ic->virq_low) { set_irq_data(qe_ic->virq_high, qe_ic); - set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high); + set_irq_chained_handler(qe_ic->virq_high, high_handler); } } diff --git a/include/asm-powerpc/qe_ic.h b/include/asm-powerpc/qe_ic.h index e386fb7e44b0..a779b2c9eaf1 100644 --- a/include/asm-powerpc/qe_ic.h +++ b/include/asm-powerpc/qe_ic.h @@ -56,9 +56,75 @@ enum qe_ic_grp_id { QE_IC_GRP_RISCB /* QE interrupt controller RISC group B */ }; -void qe_ic_init(struct device_node *node, unsigned int flags); +void qe_ic_init(struct device_node *node, unsigned int flags, + void (*low_handler)(unsigned int irq, struct irq_desc *desc), + void (*high_handler)(unsigned int irq, struct irq_desc *desc)); void qe_ic_set_highest_priority(unsigned int virq, int high); int qe_ic_set_priority(unsigned int virq, unsigned int priority); int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high); +struct qe_ic; +unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic); +unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic); + +static inline void qe_ic_cascade_low_ipic(unsigned int irq, + struct irq_desc *desc) +{ + struct qe_ic *qe_ic = desc->handler_data; + unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); +} + +static inline void qe_ic_cascade_high_ipic(unsigned int irq, + struct irq_desc *desc) +{ + struct qe_ic *qe_ic = desc->handler_data; + unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); +} + +static inline void qe_ic_cascade_low_mpic(unsigned int irq, + struct irq_desc *desc) +{ + struct qe_ic *qe_ic = desc->handler_data; + unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + + desc->chip->eoi(irq); +} + +static inline void qe_ic_cascade_high_mpic(unsigned int irq, + struct irq_desc *desc) +{ + struct qe_ic *qe_ic = desc->handler_data; + unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + + desc->chip->eoi(irq); +} + +static inline void qe_ic_cascade_muxed_mpic(unsigned int irq, + struct irq_desc *desc) +{ + struct qe_ic *qe_ic = desc->handler_data; + unsigned int cascade_irq; + + cascade_irq = qe_ic_get_high_irq(qe_ic); + if (cascade_irq == NO_IRQ) + cascade_irq = qe_ic_get_low_irq(qe_ic); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + + desc->chip->eoi(irq); +} + #endif /* _ASM_POWERPC_QE_IC_H */ From 321872dcc07f83f9b60af1be41c6bafbaddf9bf6 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 5 Oct 2007 21:47:09 +0400 Subject: [PATCH 0486/2804] [POWERPC] QE: pario - support for MPC85xx layout 8 bytes padding required to match MPC85xx registers layout. Signed-off-by: Anton Vorontsov Reviewed-by: Kim Phillips Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/qe_lib/qe_io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index a114cb0c572f..e53ea4d374a0 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -36,6 +36,9 @@ struct port_regs { __be32 cpdir2; /* Direction register */ __be32 cppar1; /* Pin assignment register */ __be32 cppar2; /* Pin assignment register */ +#ifdef CONFIG_PPC_85xx + u8 pad[8]; +#endif }; static struct port_regs *par_io = NULL; From af6521ea8af210fea094b183a9ad29ab73945ee1 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 5 Oct 2007 21:46:53 +0400 Subject: [PATCH 0487/2804] [POWERPC] 85xx: mpc8568mds - update dts to be able to use UCCs 1. UCC1's RX_DV pin is 16, not 15; 2. UCC1's phy is at 0x7, not 0x1. Schematics says 0x7, and recent u-boot also using 0x7. 3. Use gianfar's (eTSEC) mdio bus. This is hardware default setup. 4. tx-clock should be CLK16 (GE125, PB31); 5. phy-connection-type is RGMII-ID; Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8568mds.dts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index b064a2ff2306..54394372b12a 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -104,10 +104,10 @@ device_type = "mdio"; compatible = "gianfar"; reg = <24520 20>; - phy0: ethernet-phy@0 { + phy0: ethernet-phy@7 { interrupt-parent = <&mpic>; interrupts = <1 1>; - reg = <0>; + reg = <7>; device_type = "ethernet-phy"; }; phy1: ethernet-phy@1 { @@ -242,7 +242,7 @@ 4 1a 2 0 2 0 /* RxD7 */ 4 0b 1 0 2 0 /* TX_EN */ 4 18 1 0 2 0 /* TX_ER */ - 4 0f 2 0 2 0 /* RX_DV */ + 4 10 2 0 2 0 /* RX_DV */ 4 1e 2 0 2 0 /* RX_ER */ 4 11 2 0 2 0 /* RX_CLK */ 4 13 1 0 2 0 /* GTX_CLK */ @@ -334,10 +334,10 @@ mac-address = [ 00 00 00 00 00 00 ]; local-mac-address = [ 00 00 00 00 00 00 ]; rx-clock = <0>; - tx-clock = <19>; - phy-handle = <&qe_phy0>; - phy-connection-type = "gmii"; + tx-clock = <20>; pio-handle = <&pio1>; + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; }; ucc@3000 { @@ -356,10 +356,10 @@ mac-address = [ 00 00 00 00 00 00 ]; local-mac-address = [ 00 00 00 00 00 00 ]; rx-clock = <0>; - tx-clock = <14>; - phy-handle = <&qe_phy1>; - phy-connection-type = "gmii"; + tx-clock = <20>; pio-handle = <&pio2>; + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; }; mdio@2120 { @@ -371,10 +371,10 @@ /* These are the same PHYs as on * gianfar's MDIO bus */ - qe_phy0: ethernet-phy@00 { + qe_phy0: ethernet-phy@07 { interrupt-parent = <&mpic>; interrupts = <1 1>; - reg = <0>; + reg = <7>; device_type = "ethernet-phy"; }; qe_phy1: ethernet-phy@01 { From 803dedb60849a8e4ec38e66ca41f51188c18a87d Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 5 Oct 2007 21:46:47 +0400 Subject: [PATCH 0488/2804] [POWERPC] 85xx: mpc85xx_mds - reset UCC ethernet properly Apart from that the current code doesn't compile it's also meaningless with regard to the MPC8568E-MDS' BCSR. This patch used to reset UCCs properly. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 57e840a1c027..6913e99c1279 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -113,18 +113,22 @@ static void __init mpc85xx_mds_setup_arch(void) } if (bcsr_regs) { - u8 bcsr_phy; +#define BCSR_UCC1_GETH_EN (0x1 << 7) +#define BCSR_UCC2_GETH_EN (0x1 << 7) +#define BCSR_UCC1_MODE_MSK (0x3 << 4) +#define BCSR_UCC2_MODE_MSK (0x3 << 0) - /* Reset the Ethernet PHY */ - bcsr_phy = in_be8(&bcsr_regs[9]); - bcsr_phy &= ~0x20; - out_be8(&bcsr_regs[9], bcsr_phy); + /* Turn off UCC1 & UCC2 */ + clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); + clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); - udelay(1000); + /* Mode is RGMII, all bits clear */ + clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK | + BCSR_UCC2_MODE_MSK); - bcsr_phy = in_be8(&bcsr_regs[9]); - bcsr_phy |= 0x20; - out_be8(&bcsr_regs[9], bcsr_phy); + /* Turn UCC1 & UCC2 on */ + setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); + setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); iounmap(bcsr_regs); } From 082ea86fce463f8c2f1ce059cc959f21dc1ef24a Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Sat, 6 Oct 2007 22:06:40 +0200 Subject: [PATCH 0489/2804] [POWERPC] spi: Support non-QE processors On non-QE processors (mpc831x/mpc834x) the SPI clock is the SoC clock. Signed-off-by: Peter Korsgaard Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_soc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index be5e0bda2318..3ace7474809e 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -1222,7 +1222,11 @@ int __init fsl_spi_init(struct spi_board_info *board_infos, unsigned int i; const u32 *sysclk; + /* SPI controller is either clocked from QE or SoC clock */ np = of_find_node_by_type(NULL, "qe"); + if (!np) + np = of_find_node_by_type(NULL, "soc"); + if (!np) return -ENODEV; From dcccb37e98e0444b0c6a03b303855771aa463c96 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 8 Oct 2007 01:24:22 -0600 Subject: [PATCH 0490/2804] [POWERPC] Lite5200: Use comma delimiter format for lists in device tree DTC now supports "foo","bar" format for lists of strings; use the new format on the lite5200 device trees. Signed-off-by: Grant Likely Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/lite5200.dts | 10 ++--- arch/powerpc/boot/dts/lite5200b.dts | 62 ++++++++++++++--------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts index 324e1bd2aa60..bc45f5fbb060 100644 --- a/arch/powerpc/boot/dts/lite5200.dts +++ b/arch/powerpc/boot/dts/lite5200.dts @@ -19,7 +19,7 @@ / { model = "fsl,lite5200"; // revision = "1.0"; - compatible = "fsl,lite5200\0generic-mpc5200"; + compatible = "fsl,lite5200","generic-mpc5200"; #address-cells = <1>; #size-cells = <1>; @@ -192,7 +192,7 @@ usb@1000 { device_type = "usb-ohci-be"; - compatible = "mpc5200-ohci\0ohci-be"; + compatible = "mpc5200-ohci","ohci-be"; reg = <1000 ff>; interrupts = <2 6 0>; interrupt-parent = <&mpc5200_pic>; @@ -293,7 +293,7 @@ i2c@3d00 { device_type = "i2c"; - compatible = "mpc5200-i2c\0fsl-i2c"; + compatible = "mpc5200-i2c","fsl-i2c"; cell-index = <0>; reg = <3d00 40>; interrupts = <2 f 0>; @@ -303,7 +303,7 @@ i2c@3d40 { device_type = "i2c"; - compatible = "mpc5200-i2c\0fsl-i2c"; + compatible = "mpc5200-i2c","fsl-i2c"; cell-index = <1>; reg = <3d40 40>; interrupts = <2 10 0>; @@ -312,7 +312,7 @@ }; sram@8000 { device_type = "sram"; - compatible = "mpc5200-sram\0sram"; + compatible = "mpc5200-sram","sram"; reg = <8000 4000>; }; }; diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts index 3f74f73f70ad..a6bb1d0558ef 100644 --- a/arch/powerpc/boot/dts/lite5200b.dts +++ b/arch/powerpc/boot/dts/lite5200b.dts @@ -19,7 +19,7 @@ / { model = "fsl,lite5200b"; // revision = "1.0"; - compatible = "fsl,lite5200b\0generic-mpc5200"; + compatible = "fsl,lite5200b","generic-mpc5200"; #address-cells = <1>; #size-cells = <1>; @@ -56,7 +56,7 @@ system-frequency = <0>; // from bootloader cdm@200 { - compatible = "mpc5200b-cdm\0mpc5200-cdm"; + compatible = "mpc5200b-cdm","mpc5200-cdm"; reg = <200 38>; }; @@ -65,12 +65,12 @@ interrupt-controller; #interrupt-cells = <3>; device_type = "interrupt-controller"; - compatible = "mpc5200b-pic\0mpc5200-pic"; + compatible = "mpc5200b-pic","mpc5200-pic"; reg = <500 80>; }; gpt@600 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc5200-gpt"; + compatible = "mpc5200b-gpt","mpc5200-gpt"; device_type = "gpt"; cell-index = <0>; reg = <600 10>; @@ -80,7 +80,7 @@ }; gpt@610 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc5200-gpt"; + compatible = "mpc5200b-gpt","mpc5200-gpt"; device_type = "gpt"; cell-index = <1>; reg = <610 10>; @@ -89,7 +89,7 @@ }; gpt@620 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc5200-gpt"; + compatible = "mpc5200b-gpt","mpc5200-gpt"; device_type = "gpt"; cell-index = <2>; reg = <620 10>; @@ -98,7 +98,7 @@ }; gpt@630 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc5200-gpt"; + compatible = "mpc5200b-gpt","mpc5200-gpt"; device_type = "gpt"; cell-index = <3>; reg = <630 10>; @@ -107,7 +107,7 @@ }; gpt@640 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc5200-gpt"; + compatible = "mpc5200b-gpt","mpc5200-gpt"; device_type = "gpt"; cell-index = <4>; reg = <640 10>; @@ -116,7 +116,7 @@ }; gpt@650 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc5200-gpt"; + compatible = "mpc5200b-gpt","mpc5200-gpt"; device_type = "gpt"; cell-index = <5>; reg = <650 10>; @@ -125,7 +125,7 @@ }; gpt@660 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc5200-gpt"; + compatible = "mpc5200b-gpt","mpc5200-gpt"; device_type = "gpt"; cell-index = <6>; reg = <660 10>; @@ -134,7 +134,7 @@ }; gpt@670 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc5200-gpt"; + compatible = "mpc5200b-gpt","mpc5200-gpt"; device_type = "gpt"; cell-index = <7>; reg = <670 10>; @@ -143,7 +143,7 @@ }; rtc@800 { // Real time clock - compatible = "mpc5200b-rtc\0mpc5200-rtc"; + compatible = "mpc5200b-rtc","mpc5200-rtc"; device_type = "rtc"; reg = <800 100>; interrupts = <1 5 0 1 6 0>; @@ -152,7 +152,7 @@ mscan@900 { device_type = "mscan"; - compatible = "mpc5200b-mscan\0mpc5200-mscan"; + compatible = "mpc5200b-mscan","mpc5200-mscan"; cell-index = <0>; interrupts = <2 11 0>; interrupt-parent = <&mpc5200_pic>; @@ -161,7 +161,7 @@ mscan@980 { device_type = "mscan"; - compatible = "mpc5200b-mscan\0mpc5200-mscan"; + compatible = "mpc5200b-mscan","mpc5200-mscan"; cell-index = <1>; interrupts = <2 12 0>; interrupt-parent = <&mpc5200_pic>; @@ -169,14 +169,14 @@ }; gpio@b00 { - compatible = "mpc5200b-gpio\0mpc5200-gpio"; + compatible = "mpc5200b-gpio","mpc5200-gpio"; reg = ; interrupts = <1 7 0>; interrupt-parent = <&mpc5200_pic>; }; gpio-wkup@c00 { - compatible = "mpc5200b-gpio-wkup\0mpc5200-gpio-wkup"; + compatible = "mpc5200b-gpio-wkup","mpc5200-gpio-wkup"; reg = ; interrupts = <1 8 0 0 3 0>; interrupt-parent = <&mpc5200_pic>; @@ -184,7 +184,7 @@ spi@f00 { device_type = "spi"; - compatible = "mpc5200b-spi\0mpc5200-spi"; + compatible = "mpc5200b-spi","mpc5200-spi"; reg = ; interrupts = <2 d 0 2 e 0>; interrupt-parent = <&mpc5200_pic>; @@ -192,7 +192,7 @@ usb@1000 { device_type = "usb-ohci-be"; - compatible = "mpc5200b-ohci\0mpc5200-ohci\0ohci-be"; + compatible = "mpc5200b-ohci","mpc5200-ohci","ohci-be"; reg = <1000 ff>; interrupts = <2 6 0>; interrupt-parent = <&mpc5200_pic>; @@ -200,7 +200,7 @@ bestcomm@1200 { device_type = "dma-controller"; - compatible = "mpc5200b-bestcomm\0mpc5200-bestcomm"; + compatible = "mpc5200b-bestcomm","mpc5200-bestcomm"; reg = <1200 80>; interrupts = <3 0 0 3 1 0 3 2 0 3 3 0 3 4 0 3 5 0 3 6 0 3 7 0 @@ -210,13 +210,13 @@ }; xlb@1f00 { - compatible = "mpc5200b-xlb\0mpc5200-xlb"; + compatible = "mpc5200b-xlb","mpc5200-xlb"; reg = <1f00 100>; }; serial@2000 { // PSC1 device_type = "serial"; - compatible = "mpc5200b-psc-uart\0mpc5200-psc-uart"; + compatible = "mpc5200b-psc-uart","mpc5200-psc-uart"; port-number = <0>; // Logical port assignment cell-index = <0>; reg = <2000 100>; @@ -227,7 +227,7 @@ // PSC2 in ac97 mode example //ac97@2200 { // PSC2 // device_type = "sound"; - // compatible = "mpc5200b-psc-ac97\0mpc5200-psc-ac97"; + // compatible = "mpc5200b-psc-ac97","mpc5200-psc-ac97"; // cell-index = <1>; // reg = <2200 100>; // interrupts = <2 2 0>; @@ -247,7 +247,7 @@ // PSC4 in uart mode example //serial@2600 { // PSC4 // device_type = "serial"; - // compatible = "mpc5200b-psc-uart\0mpc5200-psc-uart"; + // compatible = "mpc5200b-psc-uart","mpc5200-psc-uart"; // cell-index = <3>; // reg = <2600 100>; // interrupts = <2 b 0>; @@ -257,7 +257,7 @@ // PSC5 in uart mode example //serial@2800 { // PSC5 // device_type = "serial"; - // compatible = "mpc5200b-psc-uart\0mpc5200-psc-uart"; + // compatible = "mpc5200b-psc-uart","mpc5200-psc-uart"; // cell-index = <4>; // reg = <2800 100>; // interrupts = <2 c 0>; @@ -267,7 +267,7 @@ // PSC6 in spi mode example //spi@2c00 { // PSC6 // device_type = "spi"; - // compatible = "mpc5200b-psc-spi\0mpc5200-psc-spi"; + // compatible = "mpc5200b-psc-spi","mpc5200-psc-spi"; // cell-index = <5>; // reg = <2c00 100>; // interrupts = <2 4 0>; @@ -276,7 +276,7 @@ ethernet@3000 { device_type = "network"; - compatible = "mpc5200b-fec\0mpc5200-fec"; + compatible = "mpc5200b-fec","mpc5200-fec"; reg = <3000 800>; mac-address = [ 02 03 04 05 06 07 ]; // Bad! interrupts = <2 5 0>; @@ -285,7 +285,7 @@ ata@3a00 { device_type = "ata"; - compatible = "mpc5200b-ata\0mpc5200-ata"; + compatible = "mpc5200b-ata","mpc5200-ata"; reg = <3a00 100>; interrupts = <2 7 0>; interrupt-parent = <&mpc5200_pic>; @@ -293,7 +293,7 @@ i2c@3d00 { device_type = "i2c"; - compatible = "mpc5200b-i2c\0mpc5200-i2c\0fsl-i2c"; + compatible = "mpc5200b-i2c","mpc5200-i2c","fsl-i2c"; cell-index = <0>; reg = <3d00 40>; interrupts = <2 f 0>; @@ -303,7 +303,7 @@ i2c@3d40 { device_type = "i2c"; - compatible = "mpc5200b-i2c\0mpc5200-i2c\0fsl-i2c"; + compatible = "mpc5200b-i2c","mpc5200-i2c","fsl-i2c"; cell-index = <1>; reg = <3d40 40>; interrupts = <2 10 0>; @@ -312,7 +312,7 @@ }; sram@8000 { device_type = "sram"; - compatible = "mpc5200b-sram\0mpc5200-sram\0sram"; + compatible = "mpc5200b-sram","mpc5200-sram","sram"; reg = <8000 4000>; }; }; @@ -322,7 +322,7 @@ #size-cells = <2>; #address-cells = <3>; device_type = "pci"; - compatible = "mpc5200b-pci\0mpc5200-pci"; + compatible = "mpc5200b-pci","mpc5200-pci"; reg = ; interrupt-map-mask = ; interrupt-map = Date: Fri, 21 Sep 2007 14:36:47 +1000 Subject: [PATCH 0491/2804] [POWERPC] iSeries: Correct missing newline in printk Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/viopath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index 6a0060a5f2ec..45f2fe39c87e 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c @@ -596,7 +596,7 @@ int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) numOpen += viopathStatus[remoteLp].users[i]; if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { - printk(VIOPATH_KERN_INFO "closing connection to partition %d", + printk(VIOPATH_KERN_INFO "closing connection to partition %d\n", remoteLp); HvCallEvent_closeLpEventPath(remoteLp, From cd6eed3718b1b32c60a6ee5658ae6341de3177d9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 21 Sep 2007 18:08:17 +1000 Subject: [PATCH 0492/2804] [POWERPC] Prepare to remove of_platform_driver name The name field of of_platform_driver is just copied into the included device_driver. By not overriding an already initialised device_driver name, we can convert the drivers over time to stop using the of_platform_driver name. Also we were not copying the owner field from of_platform_driver, so do the same with it. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/of_platform.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index f70e787d556f..eca8ccc3fa12 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -19,11 +19,11 @@ #include #include #include +#include +#include #include #include -#include -#include #include #include #include @@ -70,7 +70,10 @@ postcore_initcall(of_bus_driver_init); int of_register_platform_driver(struct of_platform_driver *drv) { /* initialize common driver fields */ - drv->driver.name = drv->name; + if (!drv->driver.name) + drv->driver.name = drv->name; + if (!drv->driver.owner) + drv->driver.owner = drv->owner; drv->driver.bus = &of_platform_bus_type; /* register with core */ @@ -385,9 +388,11 @@ static struct of_device_id of_pci_phb_ids[] = { }; static struct of_platform_driver of_pci_phb_driver = { - .name = "of-pci", - .match_table = of_pci_phb_ids, - .probe = of_pci_phb_probe, + .match_table = of_pci_phb_ids, + .probe = of_pci_phb_probe, + .driver = { + .name = "of-pci", + }, }; static __init int of_pci_phb_init(void) From 84fdde5af1eca5ff170d1dff7e2681b0a50a9ecb Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 3 Oct 2007 14:41:15 +1000 Subject: [PATCH 0493/2804] [POWERPC] Use cache-inhibited large page bit from firmware Discussions with firmware architects have confirmed that the bit in the ibm,pa-features property that indicates support for cache-inhibited large (>= 64kB) page mappings does in fact mean that the hypervisor allows 64kB mappings to I/O devices. Thus we can now enable the code that tests that bit and sets our CPU_FTR_CI_LARGE_PAGE feature bit. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 172dcc3849a0..9f329a8928ea 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -531,10 +531,7 @@ static struct ibm_pa_feature { {CPU_FTR_CTRL, 0, 0, 3, 0}, {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, -#if 0 - /* put this back once we know how to test if firmware does 64k IO */ {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, -#endif {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, }; From d7418031cf10fe82e16aa2057a702a2d1dab6f4a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 4 Oct 2007 12:00:28 +1000 Subject: [PATCH 0494/2804] [POWERPC] Remove some more section mismatch warnings WARNING: vmlinux.o(.text+0x2ff5c): Section mismatch: reference to .init.text:.pmac_find_ide_boot (between '.note_bootable_part' and '.note_scsi_host') >From holly_defconfig: WARNING: vmlinux.o(.text+0x164fe): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'find_via_pmu') WARNING: vmlinux.o(.text+0x16506): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'find_via_pmu') >From linkstation_defconfig: WARNING: vmlinux.o(.text+0x158fe): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'find_via_pmu') WARNING: vmlinux.o(.text+0x15906): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'find_via_pmu') >From mpc7448_hpc2_defconfig: WARNING: vmlinux.o(.text+0x1583e): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'find_via_pmu') WARNING: vmlinux.o(.text+0x15846): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'find_via_pmu') >From pmac32_defconfig: WARNING: vmlinux.o(.text+0x154ca): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'note_scsi_host') WARNING: vmlinux.o(.text+0x154d2): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'note_scsi_host') WARNING: vmlinux.o(.text+0x1553c): Section mismatch: reference to .init.text:pmac_find_ide_boot (between 'note_bootable_part' and 'note_scsi_host') >From ppc64_defconfig: WARNING: vmlinux.o(.text+0x3acdc): Section mismatch: reference to .init.text:.pmac_find_ide_boot (between '.note_bootable_part' and '.note_scsi_host') >From prpmc2800_defconfig: WARNING: vmlinux.o(.text+0x1611e): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'find_via_pmu') WARNING: vmlinux.o(.text+0x16126): Section mismatch: reference to .init.data:boot_command_line (between 'note_bootable_part' and 'find_via_pmu') Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/setup.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 7ccb9236e8b4..840f5b45384d 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -466,8 +466,13 @@ static int pmac_late_init(void) late_initcall(pmac_late_init); -/* can't be __init - can be called whenever a disk is first accessed */ -void note_bootable_part(dev_t dev, int part, int goodness) +/* + * This is __init_refok because we check for "initializing" before + * touching any of the __init sensitive things and "initializing" + * will be false after __init time. This can't be __init because it + * can be called whenever a disk is first accessed. + */ +void __init_refok note_bootable_part(dev_t dev, int part, int goodness) { static int found_boot = 0; char *p; From 6ee0d9f744d4417f20aabd9a4e40fac93f2c9d76 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 4 Oct 2007 13:47:06 +1000 Subject: [PATCH 0495/2804] [POWERPC] Remove unused old code from powermac setup code Since bootdevice never gets initialized, it's always NULL, and hence a whole pile of code in arch/powerpc/platforms/setup.c never gets used. (This was the code that originally was there so that the automatic root partition selection mechanism would prefer a rootish-looking partition on the device that OF loaded the kernel from over a similar partition on other devices.) This removes the unused code. Signed-off-by: Paul Mackerras Acked-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powermac/setup.c | 68 +------------------------ 1 file changed, 2 insertions(+), 66 deletions(-) diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 840f5b45384d..02c533096627 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -387,69 +387,13 @@ static void __init pmac_setup_arch(void) #endif /* CONFIG_ADB */ } -char *bootpath; -char *bootdevice; -void *boot_host; -int boot_target; -int boot_part; -static dev_t boot_dev; - #ifdef CONFIG_SCSI void note_scsi_host(struct device_node *node, void *host) { - int l; - char *p; - - l = strlen(node->full_name); - if (bootpath != NULL && bootdevice != NULL - && strncmp(node->full_name, bootdevice, l) == 0 - && (bootdevice[l] == '/' || bootdevice[l] == 0)) { - boot_host = host; - /* - * There's a bug in OF 1.0.5. (Why am I not surprised.) - * If you pass a path like scsi/sd@1:0 to canon, it returns - * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 - * That is, the scsi target number doesn't get preserved. - * So we pick the target number out of bootpath and use that. - */ - p = strstr(bootpath, "/sd@"); - if (p != NULL) { - p += 4; - boot_target = simple_strtoul(p, NULL, 10); - p = strchr(p, ':'); - if (p != NULL) - boot_part = simple_strtoul(p + 1, NULL, 10); - } - } } EXPORT_SYMBOL(note_scsi_host); #endif -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) -static dev_t __init find_ide_boot(void) -{ - char *p; - int n; - dev_t __init pmac_find_ide_boot(char *bootdevice, int n); - - if (bootdevice == NULL) - return 0; - p = strrchr(bootdevice, '/'); - if (p == NULL) - return 0; - n = p - bootdevice; - - return pmac_find_ide_boot(bootdevice, n); -} -#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ - -static void __init find_boot_device(void) -{ -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) - boot_dev = find_ide_boot(); -#endif -} - static int initializing = 1; static int pmac_late_init(void) @@ -474,7 +418,6 @@ late_initcall(pmac_late_init); */ void __init_refok note_bootable_part(dev_t dev, int part, int goodness) { - static int found_boot = 0; char *p; if (!initializing) @@ -486,15 +429,8 @@ void __init_refok note_bootable_part(dev_t dev, int part, int goodness) if (p != NULL && (p == boot_command_line || p[-1] == ' ')) return; - if (!found_boot) { - find_boot_device(); - found_boot = 1; - } - if (!boot_dev || dev == boot_dev) { - ROOT_DEV = dev + part; - boot_dev = 0; - current_root_goodness = goodness; - } + ROOT_DEV = dev + part; + current_root_goodness = goodness; } #ifdef CONFIG_ADB_CUDA From 105c13dd7a29fe2d18643b851d7f1c1cbc4315ed Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 14:05:01 +1000 Subject: [PATCH 0496/2804] [POWERPC] Enable debug info on boot wrapper Add '-g' to BOOTCFLAGS if CONFIG_DEBUG_INFO is set. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index f3f7ce3d79a5..18e32719d0ed 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -25,6 +25,10 @@ BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -isystem $(shell $(CROSS32CC) -print-file-name=include) BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc +ifdef CONFIG_DEBUG_INFO +BOOTCFLAGS += -g +endif + ifeq ($(call cc-option-yn, -fstack-protector),y) BOOTCFLAGS += -fno-stack-protector endif From eef686a0095430bdd6c1942f86dd2b543e66679f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 4 Oct 2007 15:40:42 +1000 Subject: [PATCH 0497/2804] [POWERPC] cell: Move cbe_regs.h to include/asm-powerpc/cell-regs.h The new Cell EDAC driver needs that file, oprofile also does ugly path tricks to get to it, it's time to move it to asm-powerpc. While at it, rename it to be consistent with cell-pmu.h (and dashes look nicer than underscores anyway). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/oprofile/cell/pr_util.h | 3 +-- arch/powerpc/oprofile/op_model_cell.c | 2 +- arch/powerpc/platforms/cell/cbe_cpufreq.c | 2 +- arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c | 2 +- arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c | 2 +- arch/powerpc/platforms/cell/cbe_regs.c | 3 +-- arch/powerpc/platforms/cell/cbe_thermal.c | 2 +- arch/powerpc/platforms/cell/interrupt.c | 2 +- arch/powerpc/platforms/cell/iommu.c | 2 +- arch/powerpc/platforms/cell/pervasive.c | 2 +- arch/powerpc/platforms/cell/pmu.c | 2 +- arch/powerpc/platforms/cell/ras.c | 2 +- arch/powerpc/platforms/cell/setup.c | 2 +- .../cell/cbe_regs.h => include/asm-powerpc/cell-regs.h | 0 14 files changed, 13 insertions(+), 15 deletions(-) rename arch/powerpc/platforms/cell/cbe_regs.h => include/asm-powerpc/cell-regs.h (100%) diff --git a/arch/powerpc/oprofile/cell/pr_util.h b/arch/powerpc/oprofile/cell/pr_util.h index e5704f00c8b4..22e4e8d4eb2c 100644 --- a/arch/powerpc/oprofile/cell/pr_util.h +++ b/arch/powerpc/oprofile/cell/pr_util.h @@ -17,10 +17,9 @@ #include #include #include +#include #include -#include "../../platforms/cell/cbe_regs.h" - /* Defines used for sync_start */ #define SKIP_GENERIC_SYNC 0 #define SYNC_START_ERROR -1 diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c index d928b54f3a0f..bb6bff51ce48 100644 --- a/arch/powerpc/oprofile/op_model_cell.c +++ b/arch/powerpc/oprofile/op_model_cell.c @@ -35,9 +35,9 @@ #include #include #include +#include #include "../platforms/cell/interrupt.h" -#include "../platforms/cell/cbe_regs.h" #include "cell/pr_util.h" static void cell_global_stop_spu(void); diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index 0b6e8ee85ab1..901236fa0f07 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -24,7 +24,7 @@ #include #include #include -#include "cbe_regs.h" +#include #include "cbe_cpufreq.h" static DEFINE_MUTEX(cbe_switch_mutex); diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c index 163263b3e1cd..70fa7aef5edd 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c @@ -28,8 +28,8 @@ #include #include #include +#include -#include "cbe_regs.h" #include "cbe_cpufreq.h" /* to write to MIC register */ diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c index fc6f38982ff4..6a2c1b0a9a94 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c @@ -27,12 +27,12 @@ #include #include #include +#include #ifdef DEBUG #include #endif -#include "cbe_regs.h" #include "cbe_cpufreq.h" static u8 pmi_slow_mode_limit[MAX_CBE]; diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c index c8f7f0007422..16a9b07e7b0c 100644 --- a/arch/powerpc/platforms/cell/cbe_regs.c +++ b/arch/powerpc/platforms/cell/cbe_regs.c @@ -16,8 +16,7 @@ #include #include #include - -#include "cbe_regs.h" +#include /* * Current implementation uses "cpu" nodes. We build our own mapping diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c index fb5eda48467d..4852bf312d83 100644 --- a/arch/powerpc/platforms/cell/cbe_thermal.c +++ b/arch/powerpc/platforms/cell/cbe_thermal.c @@ -52,8 +52,8 @@ #include #include #include +#include -#include "cbe_regs.h" #include "spu_priv1_mmio.h" #define TEMP_MIN 65 diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index c29e634177fa..151fd8b82d63 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -41,9 +41,9 @@ #include #include #include +#include #include "interrupt.h" -#include "cbe_regs.h" struct iic { struct cbe_iic_thread_regs __iomem *regs; diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 760caa76841a..faabc3fdc130 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -34,8 +34,8 @@ #include #include #include +#include -#include "cbe_regs.h" #include "interrupt.h" /* Define CELL_IOMMU_REAL_UNMAP to actually unmap non-used pages diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 4ede22d363fa..0304589c0a80 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -34,9 +34,9 @@ #include #include #include +#include #include "pervasive.h" -#include "cbe_regs.h" static int sysreset_hack; diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c index 66ca4b5a1dbc..1ed303678887 100644 --- a/arch/powerpc/platforms/cell/pmu.c +++ b/arch/powerpc/platforms/cell/pmu.c @@ -30,8 +30,8 @@ #include #include #include +#include -#include "cbe_regs.h" #include "interrupt.h" /* diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index 3961a085b432..b2494ebcdbe9 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -10,9 +10,9 @@ #include #include #include +#include #include "ras.h" -#include "cbe_regs.h" static void dump_fir(int cpu) diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index db6654272e13..b8d95ad736e8 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -52,9 +52,9 @@ #include #include #include +#include #include "interrupt.h" -#include "cbe_regs.h" #include "pervasive.h" #include "ras.h" diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/include/asm-powerpc/cell-regs.h similarity index 100% rename from arch/powerpc/platforms/cell/cbe_regs.h rename to include/asm-powerpc/cell-regs.h From d767efe30f42c9e827ac1f452762f55b2d8fbdb3 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 4 Oct 2007 15:40:43 +1000 Subject: [PATCH 0498/2804] [POWERPC] cell: Add Cell memory controller register defs and expose it This adds definitions for the Cell memory controller registers (at least some of them) for use by the EDAC driver for ECC error reporting. It also expose the said MIC as a platform device that can be used by the EDAC driver to match on. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/setup.c | 10 ++++++ include/asm-powerpc/cell-regs.h | 48 +++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index b8d95ad736e8..5343e3844e2a 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -83,12 +83,22 @@ static void cell_progress(char *s, unsigned short hex) static int __init cell_publish_devices(void) { + int node; + if (!machine_is(cell)) return 0; /* Publish OF platform devices for southbridge IOs */ of_platform_bus_probe(NULL, NULL, NULL); + /* There is no device for the MIC memory controller, thus we create + * a platform device for it to attach the EDAC driver to. + */ + for_each_online_node(node) { + if (cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(node)) == NULL) + continue; + platform_device_register_simple("cbe-mic", node, NULL, 0); + } return 0; } device_initcall(cell_publish_devices); diff --git a/include/asm-powerpc/cell-regs.h b/include/asm-powerpc/cell-regs.h index b24025f2ac7a..fd6fd00434ef 100644 --- a/include/asm-powerpc/cell-regs.h +++ b/include/asm-powerpc/cell-regs.h @@ -244,16 +244,60 @@ struct cbe_mic_tm_regs { u64 slow_fast_timer_0; /* 0x0090 */ u64 slow_next_timer_0; /* 0x0098 */ - u8 pad_0x00a0_0x01c0[0x01c0 - 0x0a0]; /* 0x00a0 */ + u8 pad_0x00a0_0x00f8[0x00f8 - 0x00a0]; /* 0x00a0 */ + u64 mic_df_ecc_address_0; /* 0x00f8 */ + + u8 pad_0x0100_0x01b8[0x01b8 - 0x0100]; /* 0x0100 */ + u64 mic_df_ecc_address_1; /* 0x01b8 */ u64 mic_ctl_cnfg_1; /* 0x01c0 */ #define CBE_MIC_DISABLE_PWR_SAV_1 0x8000000000000000LL + u64 pad_0x01c8; /* 0x01c8 */ u64 slow_fast_timer_1; /* 0x01d0 */ u64 slow_next_timer_1; /* 0x01d8 */ - u8 pad_0x01e0_0x1000[0x1000 - 0x01e0]; /* 0x01e0 */ + u8 pad_0x01e0_0x0208[0x0208 - 0x01e0]; /* 0x01e0 */ + u64 mic_exc; /* 0x0208 */ +#define CBE_MIC_EXC_BLOCK_SCRUB 0x0800000000000000ULL +#define CBE_MIC_EXC_FAST_SCRUB 0x0100000000000000ULL + + u64 mic_mnt_cfg; /* 0x0210 */ +#define CBE_MIC_MNT_CFG_CHAN_0_POP 0x0002000000000000ULL +#define CBE_MIC_MNT_CFG_CHAN_1_POP 0x0004000000000000ULL + + u64 mic_df_config; /* 0x0218 */ +#define CBE_MIC_ECC_DISABLE_0 0x4000000000000000ULL +#define CBE_MIC_ECC_REP_SINGLE_0 0x2000000000000000ULL +#define CBE_MIC_ECC_DISABLE_1 0x0080000000000000ULL +#define CBE_MIC_ECC_REP_SINGLE_1 0x0040000000000000ULL + + u8 pad_0x0220_0x0230[0x0230 - 0x0220]; /* 0x0220 */ + u64 mic_fir; /* 0x0230 */ +#define CBE_MIC_FIR_ECC_SINGLE_0_ERR 0x0200000000000000ULL +#define CBE_MIC_FIR_ECC_MULTI_0_ERR 0x0100000000000000ULL +#define CBE_MIC_FIR_ECC_SINGLE_1_ERR 0x0080000000000000ULL +#define CBE_MIC_FIR_ECC_MULTI_1_ERR 0x0040000000000000ULL +#define CBE_MIC_FIR_ECC_ERR_MASK 0xffff000000000000ULL +#define CBE_MIC_FIR_ECC_SINGLE_0_CTE 0x0000020000000000ULL +#define CBE_MIC_FIR_ECC_MULTI_0_CTE 0x0000010000000000ULL +#define CBE_MIC_FIR_ECC_SINGLE_1_CTE 0x0000008000000000ULL +#define CBE_MIC_FIR_ECC_MULTI_1_CTE 0x0000004000000000ULL +#define CBE_MIC_FIR_ECC_CTE_MASK 0x0000ffff00000000ULL +#define CBE_MIC_FIR_ECC_SINGLE_0_RESET 0x0000000002000000ULL +#define CBE_MIC_FIR_ECC_MULTI_0_RESET 0x0000000001000000ULL +#define CBE_MIC_FIR_ECC_SINGLE_1_RESET 0x0000000000800000ULL +#define CBE_MIC_FIR_ECC_MULTI_1_RESET 0x0000000000400000ULL +#define CBE_MIC_FIR_ECC_RESET_MASK 0x00000000ffff0000ULL +#define CBE_MIC_FIR_ECC_SINGLE_0_SET 0x0000000000000200ULL +#define CBE_MIC_FIR_ECC_MULTI_0_SET 0x0000000000000100ULL +#define CBE_MIC_FIR_ECC_SINGLE_1_SET 0x0000000000000080ULL +#define CBE_MIC_FIR_ECC_MULTI_1_SET 0x0000000000000040ULL +#define CBE_MIC_FIR_ECC_SET_MASK 0x000000000000ffffULL + u64 mic_fir_debug; /* 0x0238 */ + + u8 pad_0x0240_0x1000[0x1000 - 0x0240]; /* 0x0240 */ }; extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np); From ca94297f0c169710848a095a2fd986195e546cb3 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sun, 7 Oct 2007 07:35:43 +1000 Subject: [PATCH 0499/2804] [POWERPC] PS3: Cleanup of os-area.c Minor cleanup of the PS3 file os-area.c: o Correct file text header. o Add type names enum os_area_ldr_format, enum os_area_boot_flag, enum os_area_ctrl_button. o Change struct os_area_header.magic_num type to u8. o Add preprocessor macro SECONDS_FROM_1970_TO_2000. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/os-area.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index b70e474014f0..ee463d0f87ad 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -1,5 +1,5 @@ /* - * PS3 'Other OS' area data. + * PS3 flash memory os area. * * Copyright (C) 2006 Sony Computer Entertainment Inc. * Copyright 2006 Sony Corp. @@ -29,7 +29,7 @@ enum { OS_AREA_SEGMENT_SIZE = 0X200, }; -enum { +enum os_area_ldr_format { HEADER_LDR_FORMAT_RAW = 0, HEADER_LDR_FORMAT_GZIP = 1, }; @@ -50,7 +50,7 @@ enum { */ struct os_area_header { - s8 magic_num[16]; + u8 magic_num[16]; u32 hdr_version; u32 os_area_offset; u32 ldr_area_offset; @@ -60,12 +60,12 @@ struct os_area_header { u32 _reserved_2[6]; }; -enum { +enum os_area_boot_flag { PARAM_BOOT_FLAG_GAME_OS = 0, PARAM_BOOT_FLAG_OTHER_OS = 1, }; -enum { +enum os_area_ctrl_button { PARAM_CTRL_BUTTON_O_IS_YES = 0, PARAM_CTRL_BUTTON_X_IS_YES = 1, }; @@ -84,6 +84,9 @@ enum { * @dns_primary: User preference of static primary dns server. * @dns_secondary: User preference of static secondary dns server. * + * The ps3 rtc maintains a read-only value that approximates seconds since + * 2000-01-01 00:00:00 UTC. + * * User preference of zero for static_ip_addr means use dhcp. */ @@ -108,6 +111,8 @@ struct os_area_params { u8 _reserved_5[8]; }; +#define SECONDS_FROM_1970_TO_2000 946684800LL + /** * struct saved_params - Static working copies of data from the 'Other OS' area. * @@ -213,7 +218,8 @@ int __init ps3_os_area_init(void) } header = (struct os_area_header *)__va(lpar_addr); - params = (struct os_area_params *)__va(lpar_addr + OS_AREA_SEGMENT_SIZE); + params = (struct os_area_params *)__va(lpar_addr + + OS_AREA_SEGMENT_SIZE); result = verify_header(header); @@ -238,16 +244,13 @@ int __init ps3_os_area_init(void) } /** - * ps3_os_area_rtc_diff - Returns the ps3 rtc diff value. - * - * The ps3 rtc maintains a value that approximates seconds since - * 2000-01-01 00:00:00 UTC. Returns the exact number of seconds from 1970 to - * 2000 when saved_params.rtc_diff has not been properly set up. + * ps3_os_area_rtc_diff - Returns the rtc diff value. */ u64 ps3_os_area_rtc_diff(void) { - return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL; + return saved_params.rtc_diff ? saved_params.rtc_diff + : SECONDS_FROM_1970_TO_2000; } /** From 01263e88c3b8c4ec9621062a40b42814e0859e92 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sun, 7 Oct 2007 07:35:44 +1000 Subject: [PATCH 0500/2804] [POWERPC] PS3: Remove unused os-area params Updates for PS3 os-area startup params o Remove some unused PS3 os-area startup params from struct saved_params. o Rename ps3_os_area_init() to ps3_os_area_save_params(). o Zero mirrored header after saving params. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/os-area.c | 44 ++++++++++++--------------- arch/powerpc/platforms/ps3/platform.h | 2 +- arch/powerpc/platforms/ps3/setup.c | 2 +- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index ee463d0f87ad..f5112248802b 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -114,27 +114,12 @@ struct os_area_params { #define SECONDS_FROM_1970_TO_2000 946684800LL /** - * struct saved_params - Static working copies of data from the 'Other OS' area. - * - * For the convinience of the guest, the HV makes a copy of the 'Other OS' area - * in flash to a high address in the boot memory region and then puts that RAM - * address and the byte count into the repository for retreval by the guest. - * We copy the data we want into a static variable and allow the memory setup - * by the HV to be claimed by the lmb manager. + * struct saved_params - Static working copies of data from the PS3 'os area'. */ struct saved_params { - /* param 0 */ s64 rtc_diff; unsigned int av_multi_out; - unsigned int ctrl_button; - /* param 1 */ - u8 static_ip_addr[4]; - u8 network_mask[4]; - u8 default_gateway[4]; - /* param 2 */ - u8 dns_primary[4]; - u8 dns_secondary[4]; } static saved_params; #define dump_header(_a) _dump_header(_a, __func__, __LINE__) @@ -201,7 +186,17 @@ static int __init verify_header(const struct os_area_header *header) return 0; } -int __init ps3_os_area_init(void) +/** + * ps3_os_area_save_params - Copy data from os area mirror to @saved_params. + * + * For the convenience of the guest, the HV makes a copy of the os area in + * flash to a high address in the boot memory region and then puts that RAM + * address and the byte count into the repository for retreval by the guest. + * We copy the data we want into a static variable and allow the memory setup + * by the HV to be claimed by the lmb manager. + */ + +void __init ps3_os_area_save_params(void) { int result; u64 lpar_addr; @@ -209,12 +204,14 @@ int __init ps3_os_area_init(void) struct os_area_header *header; struct os_area_params *params; + pr_debug(" -> %s:%d\n", __func__, __LINE__); + result = ps3_repository_read_boot_dat_info(&lpar_addr, &size); if (result) { pr_debug("%s:%d ps3_repository_read_boot_dat_info failed\n", __func__, __LINE__); - return result; + return; } header = (struct os_area_header *)__va(lpar_addr); @@ -226,7 +223,7 @@ int __init ps3_os_area_init(void) if (result) { pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); dump_header(header); - return -EIO; + return; } dump_header(header); @@ -234,13 +231,10 @@ int __init ps3_os_area_init(void) saved_params.rtc_diff = params->rtc_diff; saved_params.av_multi_out = params->av_multi_out; - saved_params.ctrl_button = params->ctrl_button; - memcpy(saved_params.static_ip_addr, params->static_ip_addr, 4); - memcpy(saved_params.network_mask, params->network_mask, 4); - memcpy(saved_params.default_gateway, params->default_gateway, 4); - memcpy(saved_params.dns_secondary, params->dns_secondary, 4); - return result; + memset(header, 0, sizeof(*header)); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); } /** diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 27c7d099816a..9109c313e492 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -62,7 +62,7 @@ int ps3_set_rtc_time(struct rtc_time *time); /* os area */ -int __init ps3_os_area_init(void); +void __init ps3_os_area_save_params(void); u64 ps3_os_area_rtc_diff(void); /* spu */ diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 609945dbe394..f0d5ec51ef17 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -228,7 +228,7 @@ static int __init ps3_probe(void) powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE; - ps3_os_area_init(); + ps3_os_area_save_params(); ps3_mm_init(); ps3_mm_vas_create(&htab_size); ps3_hpte_init(htab_size); From 418ef2094eb8b0916d6cbda10e2ab857b9f64d97 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sun, 7 Oct 2007 07:35:45 +1000 Subject: [PATCH 0501/2804] [POWERPC] PS3: os-area workqueue processing Add a workqueue to the PS3 os-area support. This is needed to support writing updates to flash memory and to update the /proc device tree entries from the timer tick interrupt context. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/os-area.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index f5112248802b..db311a147c28 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -20,6 +20,7 @@ #include #include +#include #include @@ -186,6 +187,28 @@ static int __init verify_header(const struct os_area_header *header) return 0; } +/** + * os_area_queue_work_handler - Asynchronous write handler. + * + * An asynchronous write for flash memory and the device tree. Do not + * call directly, use os_area_queue_work(). + */ + +static void os_area_queue_work_handler(struct work_struct *work) +{ + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); +} + +static void os_area_queue_work(void) +{ + static DECLARE_WORK(q, os_area_queue_work_handler); + + wmb(); + schedule_work(&q); +} + /** * ps3_os_area_save_params - Copy data from os area mirror to @saved_params. * From d7b98e3dd87b4512462f6cdfe646a8e59673e62e Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sun, 7 Oct 2007 07:35:46 +1000 Subject: [PATCH 0502/2804] [POWERPC] PS3: Add os-area rtc_diff set/get routines Updates for PS3 os-area rtc_diff set/get routines o Add a new routine ps3_os_area_set_rtc_diff(). o Rename ps3_os_area_rtc_diff() to ps3_os_area_get_rtc_diff(). o Remove static variable rtc_shift with calls to ps3_os_area_get_rtc_diff(). Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/os-area.c | 19 +++++++++++++++++-- arch/powerpc/platforms/ps3/platform.h | 3 ++- arch/powerpc/platforms/ps3/time.c | 14 +++----------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index db311a147c28..473aee8580ce 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -261,15 +261,30 @@ void __init ps3_os_area_save_params(void) } /** - * ps3_os_area_rtc_diff - Returns the rtc diff value. + * ps3_os_area_get_rtc_diff - Returns the rtc diff value. */ -u64 ps3_os_area_rtc_diff(void) +u64 ps3_os_area_get_rtc_diff(void) { return saved_params.rtc_diff ? saved_params.rtc_diff : SECONDS_FROM_1970_TO_2000; } +/** + * ps3_os_area_set_rtc_diff - Set the rtc diff value. + * + * An asynchronous write is needed to support writing updates from + * the timer interrupt context. + */ + +void ps3_os_area_set_rtc_diff(u64 rtc_diff) +{ + if (saved_params.rtc_diff != rtc_diff) { + saved_params.rtc_diff = rtc_diff; + os_area_queue_work(); + } +} + /** * ps3_os_area_get_av_multi_out - Returns the default video mode. */ diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 9109c313e492..6b4f4dd2d15a 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -63,7 +63,8 @@ int ps3_set_rtc_time(struct rtc_time *time); /* os area */ void __init ps3_os_area_save_params(void); -u64 ps3_os_area_rtc_diff(void); +u64 ps3_os_area_get_rtc_diff(void); +void ps3_os_area_set_rtc_diff(u64 rtc_diff); /* spu */ diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c index 802a9ccacb5e..d0daf7d6d3b2 100644 --- a/arch/powerpc/platforms/ps3/time.c +++ b/arch/powerpc/platforms/ps3/time.c @@ -50,12 +50,6 @@ static void __maybe_unused _dump_time(int time, const char *func, _dump_tm(&tm, func, line); } -/** - * rtc_shift - Difference in seconds between 1970 and the ps3 rtc value. - */ - -static s64 rtc_shift; - void __init ps3_calibrate_decr(void) { int result; @@ -66,8 +60,6 @@ void __init ps3_calibrate_decr(void) ppc_tb_freq = tmp; ppc_proc_freq = ppc_tb_freq * 40; - - rtc_shift = ps3_os_area_rtc_diff(); } static u64 read_rtc(void) @@ -87,18 +79,18 @@ int ps3_set_rtc_time(struct rtc_time *tm) u64 now = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - rtc_shift = now - read_rtc(); + ps3_os_area_set_rtc_diff(now - read_rtc()); return 0; } void ps3_get_rtc_time(struct rtc_time *tm) { - to_tm(read_rtc() + rtc_shift, tm); + to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm); tm->tm_year -= 1900; tm->tm_mon -= 1; } unsigned long __init ps3_get_boot_time(void) { - return read_rtc() + rtc_shift; + return read_rtc() + ps3_os_area_get_rtc_diff(); } From 7db19421a9b116a196845a1118729cf5988f1b57 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sun, 7 Oct 2007 07:35:47 +1000 Subject: [PATCH 0503/2804] [POWERPC] PS3: Save os-area params to device tree Add the PS3 os-area startup params to the device tree. This allows a second stage kernel loaded with kexec to use these values. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/os-area.c | 104 +++++++++++++++++++++++++- arch/powerpc/platforms/ps3/platform.h | 1 + arch/powerpc/platforms/ps3/setup.c | 1 + 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 473aee8580ce..e50a276fcf67 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -119,10 +119,65 @@ struct os_area_params { */ struct saved_params { + unsigned int valid; s64 rtc_diff; unsigned int av_multi_out; } static saved_params; +static struct property property_rtc_diff = { + .name = "linux,rtc_diff", + .length = sizeof(saved_params.rtc_diff), + .value = &saved_params.rtc_diff, +}; + +static struct property property_av_multi_out = { + .name = "linux,av_multi_out", + .length = sizeof(saved_params.av_multi_out), + .value = &saved_params.av_multi_out, +}; + +/** + * os_area_set_property - Add or overwrite a saved_params value to the device tree. + * + * Overwrites an existing property. + */ + +static void os_area_set_property(struct device_node *node, + struct property *prop) +{ + int result; + struct property *tmp = of_find_property(node, prop->name, NULL); + + if (tmp) { + pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name); + prom_remove_property(node, tmp); + } + + result = prom_add_property(node, prop); + + if (result) + pr_debug("%s:%d prom_set_property failed\n", __func__, + __LINE__); +} + +/** + * os_area_get_property - Get a saved_params value from the device tree. + * + */ + +static void __init os_area_get_property(struct device_node *node, + struct property *prop) +{ + const struct property *tmp = of_find_property(node, prop->name, NULL); + + if (tmp) { + BUG_ON(prop->length != tmp->length); + memcpy(prop->value, tmp->value, prop->length); + } else + pr_debug("%s:%d not found %s\n", __func__, __LINE__, + prop->name); +} + #define dump_header(_a) _dump_header(_a, __func__, __LINE__) static void _dump_header(const struct os_area_header *h, const char *func, int line) @@ -196,8 +251,19 @@ static int __init verify_header(const struct os_area_header *header) static void os_area_queue_work_handler(struct work_struct *work) { + struct device_node *node; + pr_debug(" -> %s:%d\n", __func__, __LINE__); + node = of_find_node_by_path("/"); + + if (node) { + os_area_set_property(node, &property_rtc_diff); + of_node_put(node); + } else + pr_debug("%s:%d of_find_node_by_path failed\n", + __func__, __LINE__); + pr_debug(" <- %s:%d\n", __func__, __LINE__); } @@ -244,6 +310,8 @@ void __init ps3_os_area_save_params(void) result = verify_header(header); if (result) { + /* Second stage kernels exit here. */ + pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); dump_header(header); return; @@ -254,20 +322,52 @@ void __init ps3_os_area_save_params(void) saved_params.rtc_diff = params->rtc_diff; saved_params.av_multi_out = params->av_multi_out; + saved_params.valid = 1; memset(header, 0, sizeof(*header)); pr_debug(" <- %s:%d\n", __func__, __LINE__); } +/** + * ps3_os_area_init - Setup os area device tree properties as needed. + */ + +void __init ps3_os_area_init(void) +{ + struct device_node *node; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + node = of_find_node_by_path("/"); + + if (!saved_params.valid && node) { + /* Second stage kernels should have a dt entry. */ + os_area_get_property(node, &property_rtc_diff); + os_area_get_property(node, &property_av_multi_out); + } + + if(!saved_params.rtc_diff) + saved_params.rtc_diff = SECONDS_FROM_1970_TO_2000; + + if (node) { + os_area_set_property(node, &property_rtc_diff); + os_area_set_property(node, &property_av_multi_out); + of_node_put(node); + } else + pr_debug("%s:%d of_find_node_by_path failed\n", + __func__, __LINE__); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); +} + /** * ps3_os_area_get_rtc_diff - Returns the rtc diff value. */ u64 ps3_os_area_get_rtc_diff(void) { - return saved_params.rtc_diff ? saved_params.rtc_diff - : SECONDS_FROM_1970_TO_2000; + return saved_params.rtc_diff; } /** diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 6b4f4dd2d15a..01f0c9506e11 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -63,6 +63,7 @@ int ps3_set_rtc_time(struct rtc_time *time); /* os area */ void __init ps3_os_area_save_params(void); +void __init ps3_os_area_init(void); u64 ps3_os_area_get_rtc_diff(void); void ps3_os_area_set_rtc_diff(u64 rtc_diff); diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index f0d5ec51ef17..5c2cbb08eb52 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -206,6 +206,7 @@ static void __init ps3_setup_arch(void) prealloc_ps3flash_bounce_buffer(); ppc_md.power_save = ps3_power_save; + ps3_os_area_init(); DBG(" <- %s:%d\n", __func__, __LINE__); } From ef2ac63aef91f2a93da23476cc6b32a346b00c41 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Tue, 9 Oct 2007 11:07:24 +1000 Subject: [PATCH 0504/2804] [POWERPC] PS3: Add os-area database routines Add support for a simple tagged database in the PS3 flash rom os-area. The database allows the flash rom os-area to be shared between a bootloader and installed operating systems. The application ps3-flash-util or the library libps3-utils from the ps3-utils package can be used for userspace database operations. The latest ps3-utils package is available here: git://git.kernel.org/pub/scm/linux/kernel/git/geoff/ps3-utils.git Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/os-area.c | 445 ++++++++++++++++++++++++++- 1 file changed, 431 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index e50a276fcf67..766685ab26f8 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include @@ -39,7 +41,7 @@ enum os_area_ldr_format { * struct os_area_header - os area header segment. * @magic_num: Always 'cell_ext_os_area'. * @hdr_version: Header format version number. - * @os_area_offset: Starting segment number of os image area. + * @db_area_offset: Starting segment number of other os database area. * @ldr_area_offset: Starting segment number of bootloader image area. * @ldr_format: HEADER_LDR_FORMAT flag. * @ldr_size: Size of bootloader image in bytes. @@ -53,7 +55,7 @@ enum os_area_ldr_format { struct os_area_header { u8 magic_num[16]; u32 hdr_version; - u32 os_area_offset; + u32 db_area_offset; u32 ldr_area_offset; u32 _reserved_1; u32 ldr_format; @@ -112,10 +114,95 @@ struct os_area_params { u8 _reserved_5[8]; }; +enum { + OS_AREA_DB_MAGIC_NUM = 0x2d64622dU, +}; + +/** + * struct os_area_db - Shared flash memory database. + * @magic_num: Always '-db-' = 0x2d64622d. + * @version: os_area_db format version number. + * @index_64: byte offset of the database id index for 64 bit variables. + * @count_64: number of usable 64 bit index entries + * @index_32: byte offset of the database id index for 32 bit variables. + * @count_32: number of usable 32 bit index entries + * @index_16: byte offset of the database id index for 16 bit variables. + * @count_16: number of usable 16 bit index entries + * + * Flash rom storage for exclusive use by guests running in the other os lpar. + * The current system configuration allocates 1K (two segments) for other os + * use. + */ + +struct os_area_db { + u32 magic_num; + u16 version; + u16 _reserved_1; + u16 index_64; + u16 count_64; + u16 index_32; + u16 count_32; + u16 index_16; + u16 count_16; + u32 _reserved_2; + u8 _db_data[1000]; +}; + +/** + * enum os_area_db_owner - Data owners. + */ + +enum os_area_db_owner { + OS_AREA_DB_OWNER_ANY = -1, + OS_AREA_DB_OWNER_NONE = 0, + OS_AREA_DB_OWNER_PROTOTYPE = 1, + OS_AREA_DB_OWNER_LINUX = 2, + OS_AREA_DB_OWNER_PETITBOOT = 3, + OS_AREA_DB_OWNER_MAX = 32, +}; + +enum os_area_db_key { + OS_AREA_DB_KEY_ANY = -1, + OS_AREA_DB_KEY_NONE = 0, + OS_AREA_DB_KEY_RTC_DIFF = 1, + OS_AREA_DB_KEY_VIDEO_MODE = 2, + OS_AREA_DB_KEY_MAX = 8, +}; + +struct os_area_db_id { + int owner; + int key; +}; + +static const struct os_area_db_id os_area_db_id_empty = { + .owner = OS_AREA_DB_OWNER_NONE, + .key = OS_AREA_DB_KEY_NONE +}; + +static const struct os_area_db_id os_area_db_id_any = { + .owner = OS_AREA_DB_OWNER_ANY, + .key = OS_AREA_DB_KEY_ANY +}; + +static const struct os_area_db_id os_area_db_id_rtc_diff = { + .owner = OS_AREA_DB_OWNER_LINUX, + .key = OS_AREA_DB_KEY_RTC_DIFF +}; + +static const struct os_area_db_id os_area_db_id_video_mode = { + .owner = OS_AREA_DB_OWNER_LINUX, + .key = OS_AREA_DB_KEY_VIDEO_MODE +}; + #define SECONDS_FROM_1970_TO_2000 946684800LL /** * struct saved_params - Static working copies of data from the PS3 'os area'. + * + * The order of preference we use for the rtc_diff source: + * 1) The database value. + * 2) The game os value. + * 3) The number of seconds from 1970 to 2000. */ struct saved_params { @@ -182,17 +269,17 @@ static void __init os_area_get_property(struct device_node *node, static void _dump_header(const struct os_area_header *h, const char *func, int line) { - pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, + pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, h->magic_num); - pr_debug("%s:%d: h.hdr_version: %u\n", func, line, + pr_debug("%s:%d: h.hdr_version: %u\n", func, line, h->hdr_version); - pr_debug("%s:%d: h.os_area_offset: %u\n", func, line, - h->os_area_offset); + pr_debug("%s:%d: h.db_area_offset: %u\n", func, line, + h->db_area_offset); pr_debug("%s:%d: h.ldr_area_offset: %u\n", func, line, h->ldr_area_offset); - pr_debug("%s:%d: h.ldr_format: %u\n", func, line, + pr_debug("%s:%d: h.ldr_format: %u\n", func, line, h->ldr_format); - pr_debug("%s:%d: h.ldr_size: %xh\n", func, line, + pr_debug("%s:%d: h.ldr_size: %xh\n", func, line, h->ldr_size); } @@ -222,7 +309,7 @@ static void _dump_params(const struct os_area_params *p, const char *func, p->dns_secondary[2], p->dns_secondary[3]); } -static int __init verify_header(const struct os_area_header *header) +static int verify_header(const struct os_area_header *header) { if (memcmp(header->magic_num, "cell_ext_os_area", 16)) { pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); @@ -234,7 +321,7 @@ static int __init verify_header(const struct os_area_header *header) return -1; } - if (header->os_area_offset > header->ldr_area_offset) { + if (header->db_area_offset > header->ldr_area_offset) { pr_debug("%s:%d offsets failed\n", __func__, __LINE__); return -1; } @@ -242,6 +329,319 @@ static int __init verify_header(const struct os_area_header *header) return 0; } +static int db_verify(const struct os_area_db *db) +{ + if (db->magic_num != OS_AREA_DB_MAGIC_NUM) { + pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); + return -1; + } + + if (db->version != 1) { + pr_debug("%s:%d version failed\n", __func__, __LINE__); + return -1; + } + + return 0; +} + +struct db_index { + uint8_t owner:5; + uint8_t key:3; +}; + +struct db_iterator { + const struct os_area_db *db; + struct os_area_db_id match_id; + struct db_index *idx; + struct db_index *last_idx; + union { + uint64_t *value_64; + uint32_t *value_32; + uint16_t *value_16; + }; +}; + +static unsigned int db_align_up(unsigned int val, unsigned int size) +{ + return (val + (size - 1)) & (~(size - 1)); +} + +/** + * db_for_each_64 - Iterator for 64 bit entries. + * + * A NULL value for id can be used to match all entries. + * OS_AREA_DB_OWNER_ANY and OS_AREA_DB_KEY_ANY can be used to match all. + */ + +static int db_for_each_64(const struct os_area_db *db, + const struct os_area_db_id *match_id, struct db_iterator *i) +{ +next: + if (!i->db) { + i->db = db; + i->match_id = match_id ? *match_id : os_area_db_id_any; + i->idx = (void *)db + db->index_64; + i->last_idx = i->idx + db->count_64; + i->value_64 = (void *)db + db->index_64 + + db_align_up(db->count_64, 8); + } else { + i->idx++; + i->value_64++; + } + + if (i->idx >= i->last_idx) { + pr_debug("%s:%d: reached end\n", __func__, __LINE__); + return 0; + } + + if (i->match_id.owner != OS_AREA_DB_OWNER_ANY + && i->match_id.owner != (int)i->idx->owner) + goto next; + if (i->match_id.key != OS_AREA_DB_KEY_ANY + && i->match_id.key != (int)i->idx->key) + goto next; + + return 1; +} + +static int db_delete_64(struct os_area_db *db, const struct os_area_db_id *id) +{ + struct db_iterator i; + + for (i.db = NULL; db_for_each_64(db, id, &i); ) { + + pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__, + i.idx->owner, i.idx->key, + (unsigned long long)*i.value_64); + + i.idx->owner = 0; + i.idx->key = 0; + *i.value_64 = 0; + } + return 0; +} + +static int db_set_64(struct os_area_db *db, const struct os_area_db_id *id, + uint64_t value) +{ + struct db_iterator i; + + pr_debug("%s:%d: (%d:%d) <= %llxh\n", __func__, __LINE__, + id->owner, id->key, (unsigned long long)value); + + if (!id->owner || id->owner == OS_AREA_DB_OWNER_ANY + || id->key == OS_AREA_DB_KEY_ANY) { + pr_debug("%s:%d: bad id: (%d:%d)\n", __func__, + __LINE__, id->owner, id->key); + return -1; + } + + db_delete_64(db, id); + + i.db = NULL; + if (db_for_each_64(db, &os_area_db_id_empty, &i)) { + + pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__, + i.idx->owner, i.idx->key, + (unsigned long long)*i.value_64); + + i.idx->owner = id->owner; + i.idx->key = id->key; + *i.value_64 = value; + + pr_debug("%s:%d: set (%d:%d) <= %llxh\n", __func__, __LINE__, + i.idx->owner, i.idx->key, + (unsigned long long)*i.value_64); + return 0; + } + pr_debug("%s:%d: database full.\n", + __func__, __LINE__); + return -1; +} + +static int db_get_64(const struct os_area_db *db, + const struct os_area_db_id *id, uint64_t *value) +{ + struct db_iterator i; + + i.db = NULL; + if (db_for_each_64(db, id, &i)) { + *value = *i.value_64; + pr_debug("%s:%d: found %lld\n", __func__, __LINE__, + (long long int)*i.value_64); + return 0; + } + pr_debug("%s:%d: not found\n", __func__, __LINE__); + return -1; +} + +static int db_get_rtc_diff(const struct os_area_db *db, int64_t *rtc_diff) +{ + return db_get_64(db, &os_area_db_id_rtc_diff, (uint64_t*)rtc_diff); +} + +#define dump_db(a) _dump_db(a, __func__, __LINE__) +static void _dump_db(const struct os_area_db *db, const char *func, + int line) +{ + pr_debug("%s:%d: db.magic_num: '%s'\n", func, line, + (const char*)&db->magic_num); + pr_debug("%s:%d: db.version: %u\n", func, line, + db->version); + pr_debug("%s:%d: db.index_64: %u\n", func, line, + db->index_64); + pr_debug("%s:%d: db.count_64: %u\n", func, line, + db->count_64); + pr_debug("%s:%d: db.index_32: %u\n", func, line, + db->index_32); + pr_debug("%s:%d: db.count_32: %u\n", func, line, + db->count_32); + pr_debug("%s:%d: db.index_16: %u\n", func, line, + db->index_16); + pr_debug("%s:%d: db.count_16: %u\n", func, line, + db->count_16); +} + +static void os_area_db_init(struct os_area_db *db) +{ + enum { + HEADER_SIZE = offsetof(struct os_area_db, _db_data), + INDEX_64_COUNT = 64, + VALUES_64_COUNT = 57, + INDEX_32_COUNT = 64, + VALUES_32_COUNT = 57, + INDEX_16_COUNT = 64, + VALUES_16_COUNT = 57, + }; + + memset(db, 0, sizeof(struct os_area_db)); + + db->magic_num = OS_AREA_DB_MAGIC_NUM; + db->version = 1; + db->index_64 = HEADER_SIZE; + db->count_64 = VALUES_64_COUNT; + db->index_32 = HEADER_SIZE + + INDEX_64_COUNT * sizeof(struct db_index) + + VALUES_64_COUNT * sizeof(u64); + db->count_32 = VALUES_32_COUNT; + db->index_16 = HEADER_SIZE + + INDEX_64_COUNT * sizeof(struct db_index) + + VALUES_64_COUNT * sizeof(u64) + + INDEX_32_COUNT * sizeof(struct db_index) + + VALUES_32_COUNT * sizeof(u32); + db->count_16 = VALUES_16_COUNT; + + /* Rules to check db layout. */ + + BUILD_BUG_ON(sizeof(struct db_index) != 1); + BUILD_BUG_ON(sizeof(struct os_area_db) != 2 * OS_AREA_SEGMENT_SIZE); + BUILD_BUG_ON(INDEX_64_COUNT & 0x7); + BUILD_BUG_ON(VALUES_64_COUNT > INDEX_64_COUNT); + BUILD_BUG_ON(INDEX_32_COUNT & 0x7); + BUILD_BUG_ON(VALUES_32_COUNT > INDEX_32_COUNT); + BUILD_BUG_ON(INDEX_16_COUNT & 0x7); + BUILD_BUG_ON(VALUES_16_COUNT > INDEX_16_COUNT); + BUILD_BUG_ON(HEADER_SIZE + + INDEX_64_COUNT * sizeof(struct db_index) + + VALUES_64_COUNT * sizeof(u64) + + INDEX_32_COUNT * sizeof(struct db_index) + + VALUES_32_COUNT * sizeof(u32) + + INDEX_16_COUNT * sizeof(struct db_index) + + VALUES_16_COUNT * sizeof(u16) + > sizeof(struct os_area_db)); +} + +/** + * update_flash_db - Helper for os_area_queue_work_handler. + * + */ + +static void update_flash_db(void) +{ + int result; + int file; + off_t offset; + ssize_t count; + static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; + const struct os_area_header *header; + struct os_area_db* db; + + /* Read in header and db from flash. */ + + file = sys_open("/dev/ps3flash", O_RDWR, 0); + + if (file < 0) { + pr_debug("%s:%d sys_open failed\n", __func__, __LINE__); + goto fail_open; + } + + header = kmalloc(buf_len, GFP_KERNEL); + + if (!header) { + pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__); + goto fail_malloc; + } + + offset = sys_lseek(file, 0, SEEK_SET); + + if (offset != 0) { + pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); + goto fail_header_seek; + } + + count = sys_read(file, (char __user *)header, buf_len); + + result = count < OS_AREA_SEGMENT_SIZE || verify_header(header) + || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE; + + if (result) { + pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); + dump_header(header); + goto fail_header; + } + + /* Now got a good db offset and some maybe good db data. */ + + db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE; + + result = db_verify(db); + + if (result) { + printk(KERN_NOTICE "%s:%d: Verify of flash database failed, " + "formatting.\n", __func__, __LINE__); + dump_db(db); + os_area_db_init(db); + } + + /* Now got good db data. */ + + db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff); + + offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE, + SEEK_SET); + + if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) { + pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); + goto fail_db_seek; + } + + count = sys_write(file, (const char __user *)db, + sizeof(struct os_area_db)); + + if (count < sizeof(struct os_area_db)) { + pr_debug("%s:%d sys_write failed\n", __func__, __LINE__); + } + +fail_db_seek: +fail_header: +fail_header_seek: + kfree(header); +fail_malloc: + sys_close(file); +fail_open: + return; +} + /** * os_area_queue_work_handler - Asynchronous write handler. * @@ -264,6 +664,12 @@ static void os_area_queue_work_handler(struct work_struct *work) pr_debug("%s:%d of_find_node_by_path failed\n", __func__, __LINE__); +#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) + update_flash_db(); +#else + printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n", + __func__, __LINE__); +#endif pr_debug(" <- %s:%d\n", __func__, __LINE__); } @@ -278,11 +684,15 @@ static void os_area_queue_work(void) /** * ps3_os_area_save_params - Copy data from os area mirror to @saved_params. * - * For the convenience of the guest, the HV makes a copy of the os area in + * For the convenience of the guest the HV makes a copy of the os area in * flash to a high address in the boot memory region and then puts that RAM - * address and the byte count into the repository for retreval by the guest. + * address and the byte count into the repository for retrieval by the guest. * We copy the data we want into a static variable and allow the memory setup * by the HV to be claimed by the lmb manager. + * + * The os area mirror will not be available to a second stage kernel, and + * the header verify will fail. In this case, the saved_params values will + * be set from flash memory or the passed in device tree in ps3_os_area_init(). */ void __init ps3_os_area_save_params(void) @@ -292,6 +702,7 @@ void __init ps3_os_area_save_params(void) unsigned int size; struct os_area_header *header; struct os_area_params *params; + struct os_area_db *db; pr_debug(" -> %s:%d\n", __func__, __LINE__); @@ -311,16 +722,22 @@ void __init ps3_os_area_save_params(void) if (result) { /* Second stage kernels exit here. */ - pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); dump_header(header); return; } + db = (struct os_area_db *)__va(lpar_addr + + header->db_area_offset * OS_AREA_SEGMENT_SIZE); + dump_header(header); dump_params(params); + dump_db(db); - saved_params.rtc_diff = params->rtc_diff; + result = db_verify(db) || db_get_rtc_diff(db, &saved_params.rtc_diff); + if (result) + saved_params.rtc_diff = params->rtc_diff ? params->rtc_diff + : SECONDS_FROM_1970_TO_2000; saved_params.av_multi_out = params->av_multi_out; saved_params.valid = 1; From 38b08e48355641f843c1a5eb4ee252b6db9934aa Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Sun, 7 Oct 2007 21:34:57 +1000 Subject: [PATCH 0505/2804] [POWERPC] Remove redundant reference to non-existent CONFIG_BOOTIMG There is no BOOTIMG Kconfig variable, not to mention that there is no include/linux/bootimg.h header file. Signed-off-by: Robert P. J. Day Signed-off-by: Paul Mackerras --- arch/ppc/platforms/ev64360.c | 3 --- arch/ppc/platforms/katana.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/arch/ppc/platforms/ev64360.c b/arch/ppc/platforms/ev64360.c index f8baf05f16ce..6765676a5c6b 100644 --- a/arch/ppc/platforms/ev64360.c +++ b/arch/ppc/platforms/ev64360.c @@ -23,9 +23,6 @@ #include #include #include -#ifdef CONFIG_BOOTIMG -#include -#endif #include #include #include diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c index c289e9f1b251..52f63e6f0856 100644 --- a/arch/ppc/platforms/katana.c +++ b/arch/ppc/platforms/katana.c @@ -27,9 +27,6 @@ #include #include #include -#ifdef CONFIG_BOOTIMG -#include -#endif #include #include #include From 258de4badd5b7b5d168307638f755bd4df16c18e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:36 -0600 Subject: [PATCH 0506/2804] [POWERPC] XilinxFB: add banner output to probe routine when DEBUG is defined Debug support: when DEBUG is defined, output relevant details to the log about the framebuffer registration. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 4bc67ab56afa..1a5f1e429c4d 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -287,6 +287,11 @@ xilinxfb_drv_probe(struct device *dev) goto failed4; } + /* Put a banner in the log (for DEBUG) */ + dev_dbg(dev, "regs: phys=%x, virt=%p\n", + drvdata->regs_phys, drvdata->regs); + dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", + (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ failed4: From 3cb3ec2c26473d8123a468abfaca1e926344b1c2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:36 -0600 Subject: [PATCH 0507/2804] [POWERPC] XilinxFB: Replace calls to printk with dev_dbg, dev_err, etc. The dev_dbg, dev_err, etc functions provide more context that plain vanilla printk which is useful for debugging. Where appropriate, change printk calls to the appropriate dev_*() call. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 1a5f1e429c4d..e63cbd1acfd2 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -18,6 +18,7 @@ * Geert Uytterhoeven. */ +#include #include #include #include @@ -214,7 +215,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { - printk(KERN_ERR "Couldn't allocate device private record\n"); + dev_err(dev, "Couldn't allocate device private record\n"); return -ENOMEM; } dev_set_drvdata(dev, drvdata); @@ -222,14 +223,13 @@ xilinxfb_drv_probe(struct device *dev) /* Map the control registers in */ regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { - printk(KERN_ERR "Couldn't get registers resource\n"); + dev_err(dev, "Couldn't get registers resource\n"); retval = -EFAULT; goto failed1; } if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { - printk(KERN_ERR - "Couldn't lock memory region at 0x%08X\n", + dev_err(dev, "Couldn't lock memory region at 0x%08X\n", regs_res->start); retval = -EBUSY; goto failed1; @@ -241,7 +241,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { - printk(KERN_ERR "Could not allocate frame buffer memory\n"); + dev_err(dev, "Could not allocate frame buffer memory\n"); retval = -ENOMEM; goto failed2; } @@ -267,7 +267,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata->info.pseudo_palette = drvdata->pseudo_palette; if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) { - printk(KERN_ERR "Fail to allocate colormap (%d entries)\n", + dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); retval = -EFAULT; goto failed3; @@ -282,7 +282,7 @@ xilinxfb_drv_probe(struct device *dev) /* Register new frame buffer */ if (register_framebuffer(&drvdata->info) < 0) { - printk(KERN_ERR "Could not register frame buffer\n"); + dev_err(dev, "Could not register frame buffer\n"); retval = -EINVAL; goto failed4; } From 3fb99ce4e2748dafe3f10dba2932f0d13f577623 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [PATCH 0508/2804] [POWERPC] XilinxFB: rename failout labels to reflect failure Labels and gotos are used in xilinxfb_assign to unwind allocations on device registration failures. Rename the labels to reflect the error which occured. This change is being made to make it easier to add new failout paths (which occurs in a subsuquent patch) and to make reviewing the failout path easier. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e63cbd1acfd2..9aa754a25218 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -225,14 +225,14 @@ xilinxfb_drv_probe(struct device *dev) if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { dev_err(dev, "Couldn't get registers resource\n"); retval = -EFAULT; - goto failed1; + goto err_region; } if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { dev_err(dev, "Couldn't lock memory region at 0x%08X\n", regs_res->start); retval = -EBUSY; - goto failed1; + goto err_region; } drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8); drvdata->regs_phys = regs_res->start; @@ -243,7 +243,7 @@ xilinxfb_drv_probe(struct device *dev) if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); retval = -ENOMEM; - goto failed2; + goto err_fbmem; } /* Clear (turn to black) the framebuffer */ @@ -270,7 +270,7 @@ xilinxfb_drv_probe(struct device *dev) dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); retval = -EFAULT; - goto failed3; + goto err_cmap; } drvdata->info.flags = FBINFO_DEFAULT; @@ -284,7 +284,7 @@ xilinxfb_drv_probe(struct device *dev) if (register_framebuffer(&drvdata->info) < 0) { dev_err(dev, "Could not register frame buffer\n"); retval = -EINVAL; - goto failed4; + goto err_regfb; } /* Put a banner in the log (for DEBUG) */ @@ -294,10 +294,10 @@ xilinxfb_drv_probe(struct device *dev) (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ -failed4: +err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); -failed3: +err_cmap: dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, drvdata->fb_phys); @@ -305,10 +305,10 @@ failed3: xilinx_fb_out_be32(drvdata, REG_CTRL, 0); iounmap(drvdata->regs); -failed2: +err_fbmem: release_mem_region(regs_res->start, 8); -failed1: +err_region: kfree(drvdata); dev_set_drvdata(dev, NULL); From 264776224d3bb0cd80bc0ec11a769e05a58f8c6b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [PATCH 0509/2804] [POWERPC] XilinxFB: Split device setup from bus binding Split the device setup code away from the platform bus binding. This is in preparation for adding the of_platform bus binding to this driver and most of the setup code is common between the two busses. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 133 +++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 53 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 9aa754a25218..12d91279996d 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -196,23 +196,17 @@ static struct fb_ops xilinxfb_ops = .fb_imageblit = cfb_imageblit, }; -/* === The device driver === */ +/* --------------------------------------------------------------------- + * Bus independent setup/teardown + */ -static int -xilinxfb_drv_probe(struct device *dev) +static int xilinxfb_assign(struct device *dev, unsigned long physaddr, + int width_mm, int height_mm, int rotate) { - struct platform_device *pdev; - struct xilinxfb_platform_data *pdata; struct xilinxfb_drvdata *drvdata; - struct resource *regs_res; - int retval; - - if (!dev) - return -EINVAL; - - pdev = to_platform_device(dev); - pdata = pdev->dev.platform_data; + int rc; + /* Allocate the driver data region */ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { dev_err(dev, "Couldn't allocate device private record\n"); @@ -221,40 +215,39 @@ xilinxfb_drv_probe(struct device *dev) dev_set_drvdata(dev, drvdata); /* Map the control registers in */ - regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { - dev_err(dev, "Couldn't get registers resource\n"); - retval = -EFAULT; + if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { + dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", + physaddr); + rc = -ENODEV; goto err_region; } - - if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { - dev_err(dev, "Couldn't lock memory region at 0x%08X\n", - regs_res->start); - retval = -EBUSY; - goto err_region; + drvdata->regs_phys = physaddr; + drvdata->regs = ioremap(physaddr, 8); + if (!drvdata->regs) { + dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", + physaddr); + rc = -ENODEV; + goto err_map; } - drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8); - drvdata->regs_phys = regs_res->start; /* Allocate the framebuffer memory */ drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); - retval = -ENOMEM; + rc = -ENOMEM; goto err_fbmem; } /* Clear (turn to black) the framebuffer */ - memset_io((void *) drvdata->fb_virt, 0, FB_SIZE); + memset_io(drvdata->fb_virt, 0, FB_SIZE); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); /* Turn on the display */ drvdata->reg_ctrl_default = REG_CTRL_ENABLE; - if (pdata && pdata->rotate_screen) + if (rotate) drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); @@ -265,31 +258,29 @@ xilinxfb_drv_probe(struct device *dev) drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; drvdata->info.pseudo_palette = drvdata->pseudo_palette; + drvdata->info.flags = FBINFO_DEFAULT; + drvdata->info.var = xilinx_fb_var; - if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) { + xilinx_fb_var.height = height_mm; + xilinx_fb_var.width = width_mm; + + /* Allocate a colour map */ + rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); + if (rc) { dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); - retval = -EFAULT; goto err_cmap; } - drvdata->info.flags = FBINFO_DEFAULT; - if (pdata) { - xilinx_fb_var.height = pdata->screen_height_mm; - xilinx_fb_var.width = pdata->screen_width_mm; - } - drvdata->info.var = xilinx_fb_var; - /* Register new frame buffer */ - if (register_framebuffer(&drvdata->info) < 0) { + rc = register_framebuffer(&drvdata->info); + if (rc) { dev_err(dev, "Could not register frame buffer\n"); - retval = -EINVAL; goto err_regfb; } /* Put a banner in the log (for DEBUG) */ - dev_dbg(dev, "regs: phys=%x, virt=%p\n", - drvdata->regs_phys, drvdata->regs); + dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ @@ -300,30 +291,25 @@ err_regfb: err_cmap: dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, drvdata->fb_phys); - /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); - iounmap(drvdata->regs); err_fbmem: - release_mem_region(regs_res->start, 8); + iounmap(drvdata->regs); + +err_map: + release_mem_region(physaddr, 8); err_region: kfree(drvdata); dev_set_drvdata(dev, NULL); - return retval; + return rc; } -static int -xilinxfb_drv_remove(struct device *dev) +static int xilinxfb_release(struct device *dev) { - struct xilinxfb_drvdata *drvdata; - - if (!dev) - return -ENODEV; - - drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev); + struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev); #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); @@ -348,6 +334,47 @@ xilinxfb_drv_remove(struct device *dev) return 0; } +/* --------------------------------------------------------------------- + * Platform bus binding + */ + +static int +xilinxfb_drv_probe(struct device *dev) +{ + struct platform_device *pdev; + struct xilinxfb_platform_data *pdata; + struct resource *res; + int width_mm; + int height_mm; + int rotate; + + pdev = to_platform_device(dev); + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(dev, "Missing pdata structure\n"); + return -ENODEV; + } + + /* Find the registers address */ + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(dev, "Couldn't get registers resource\n"); + return -ENODEV; + } + + height_mm = pdata->screen_height_mm; + width_mm = pdata->screen_width_mm; + rotate = pdata->rotate_screen ? 1 : 0; + + return xilinxfb_assign(dev, res->start, width_mm, height_mm, rotate); +} + +static int +xilinxfb_drv_remove(struct device *dev) +{ + return xilinxfb_release(dev); +} + static struct device_driver xilinxfb_driver = { .name = DRIVER_NAME, From 47473e31585032e5c048eeec50e0f9165890230a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [PATCH 0510/2804] [POWERPC] XilinxFB: cleanup platform_bus binding to use platform bus API. Change the platform bus binding to make use of the established platform_bus API. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 12d91279996d..e482bb519635 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -339,26 +339,24 @@ static int xilinxfb_release(struct device *dev) */ static int -xilinxfb_drv_probe(struct device *dev) +xilinxfb_platform_probe(struct platform_device *pdev) { - struct platform_device *pdev; struct xilinxfb_platform_data *pdata; struct resource *res; int width_mm; int height_mm; int rotate; - pdev = to_platform_device(dev); pdata = pdev->dev.platform_data; if (!pdata) { - dev_err(dev, "Missing pdata structure\n"); + dev_err(&pdev->dev, "Missing pdata structure\n"); return -ENODEV; } /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) { - dev_err(dev, "Couldn't get registers resource\n"); + dev_err(&pdev->dev, "Couldn't get registers resource\n"); return -ENODEV; } @@ -366,22 +364,24 @@ xilinxfb_drv_probe(struct device *dev) width_mm = pdata->screen_width_mm; rotate = pdata->rotate_screen ? 1 : 0; - return xilinxfb_assign(dev, res->start, width_mm, height_mm, rotate); + return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, + rotate); } static int -xilinxfb_drv_remove(struct device *dev) +xilinxfb_platform_remove(struct platform_device *pdev) { - return xilinxfb_release(dev); + return xilinxfb_release(&pdev->dev); } -static struct device_driver xilinxfb_driver = { - .name = DRIVER_NAME, - .bus = &platform_bus_type, - - .probe = xilinxfb_drv_probe, - .remove = xilinxfb_drv_remove +static struct platform_driver xilinxfb_platform_driver = { + .probe = xilinxfb_platform_probe, + .remove = xilinxfb_platform_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, }; static int __init @@ -391,13 +391,13 @@ xilinxfb_init(void) * No kernel boot options used, * so we just need to register the driver */ - return driver_register(&xilinxfb_driver); + return platform_driver_register(&xilinxfb_platform_driver); } static void __exit xilinxfb_cleanup(void) { - driver_unregister(&xilinxfb_driver); + platform_driver_unregister(&xilinxfb_platform_driver); } module_init(xilinxfb_init); From 31e8d4603ecaeb02424c9669e252ab835354a36e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [PATCH 0511/2804] [POWERPC] XilinxFB: add of_platform bus binding Adds the of_platform bus binding to the xilinxfb driver. Needed to use framebuffer devices described in the OF device tree (used by arch/powerpc). Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 107 +++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 9 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e482bb519635..dbb23a9fef7b 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -6,9 +6,12 @@ * Author: MontaVista Software, Inc. * source@mvista.com * - * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the - * terms of the GNU General Public License version 2. This program is licensed - * "as is" without any warranty of any kind, whether express or implied. + * 2002-2007 (c) MontaVista Software, Inc. + * 2007 (c) Secret Lab Technologies, Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. */ /* @@ -29,7 +32,10 @@ #include #include #include - +#if defined(CONFIG_OF) +#include +#include +#endif #include #include @@ -384,20 +390,103 @@ static struct platform_driver xilinxfb_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * OF bus binding + */ + +#if defined(CONFIG_OF) +static int __devinit +xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct resource res; + const u32 *prop; + int width = 0, height = 0, rotate = 0; + int size, rc; + + dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); + + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalid address\n"); + return rc; + } + + prop = of_get_property(op->node, "display-number", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + width = prop[0]; + height = prop[1]; + } + + if (of_find_property(op->node, "rotate-display", NULL)) + rotate = 1; + + return xilinxfb_assign(&op->dev, res.start, width, height, rotate); +} + +static int __devexit xilinxfb_of_remove(struct of_device *op) +{ + return xilinxfb_release(&op->dev); +} + +/* Match table for of_platform binding */ +static struct of_device_id __devinit xilinxfb_of_match[] = { + { .compatible = "xilinx,ml300-fb", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xilinxfb_of_match); + +static struct of_platform_driver xilinxfb_of_driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .match_table = xilinxfb_of_match, + .probe = xilinxfb_of_probe, + .remove = __devexit_p(xilinxfb_of_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init xilinxfb_of_register(void) +{ + pr_debug("xilinxfb: calling of_register_platform_driver()\n"); + return of_register_platform_driver(&xilinxfb_of_driver); +} + +static inline void __exit xilinxfb_of_unregister(void) +{ + of_unregister_platform_driver(&xilinxfb_of_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init xilinxfb_of_register(void) { return 0; } +static inline void __exit xilinxfb_of_unregister(void) { } +#endif /* CONFIG_OF */ + +/* --------------------------------------------------------------------- + * Module setup and teardown + */ + static int __init xilinxfb_init(void) { - /* - * No kernel boot options used, - * so we just need to register the driver - */ - return platform_driver_register(&xilinxfb_platform_driver); + int rc; + rc = xilinxfb_of_register(); + if (rc) + return rc; + + rc = platform_driver_register(&xilinxfb_platform_driver); + if (rc) + xilinxfb_of_unregister(); + + return rc; } static void __exit xilinxfb_cleanup(void) { platform_driver_unregister(&xilinxfb_platform_driver); + xilinxfb_of_unregister(); } module_init(xilinxfb_init); From e3cec00366e9d60ff65c6f6f8fffdfcadea01056 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 15:44:52 -0600 Subject: [PATCH 0512/2804] [POWERPC] XilinxFB: Make missing pdata structure non-fatal Missing pdata structure is not a fatal error. The device can still be initialized without it. Signed-off-by: Grant Likely --- drivers/video/xilinxfb.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index dbb23a9fef7b..e6e12be845a9 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -349,15 +349,9 @@ xilinxfb_platform_probe(struct platform_device *pdev) { struct xilinxfb_platform_data *pdata; struct resource *res; - int width_mm; - int height_mm; - int rotate; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing pdata structure\n"); - return -ENODEV; - } + int width_mm = 0; + int height_mm = 0; + int rotate = 0; /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -366,9 +360,13 @@ xilinxfb_platform_probe(struct platform_device *pdev) return -ENODEV; } - height_mm = pdata->screen_height_mm; - width_mm = pdata->screen_width_mm; - rotate = pdata->rotate_screen ? 1 : 0; + /* If a pdata structure is provided, then extract the parameters */ + pdata = pdev->dev.platform_data; + if (pdata) { + height_mm = pdata->screen_height_mm; + width_mm = pdata->screen_width_mm; + rotate = pdata->rotate_screen ? 1 : 0; + } return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, rotate); From 1855256c497ecfefc730df6032243f26855ce52c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:15:40 -0400 Subject: [PATCH 0513/2804] drivers/firmware: const-ify DMI API and internals Three main sets of changes: 1) dmi_get_system_info() return value should have been marked const, since callers should not be changing that data. 2) const-ify DMI internals, since DMI firmware tables should, whenever possible, be marked const to ensure we never ever write to that data area. 3) const-ify DMI API, to enable marking tables const where possible in low-level drivers. And if we're really lucky, this might enable some additional optimizations on the part of the compiler. The bulk of the changes are #2 and #3, which are interrelated. #1 could have been a separate patch, but it was so small compared to the others, it was easier to roll it into this changeset. Signed-off-by: Jeff Garzik --- arch/i386/kernel/acpi/boot.c | 8 +-- arch/i386/kernel/acpi/sleep.c | 2 +- arch/i386/kernel/apm.c | 18 +++---- arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 4 +- arch/i386/kernel/reboot.c | 2 +- arch/i386/kernel/tsc.c | 2 +- arch/i386/mach-generic/bigsmp.c | 4 +- arch/i386/pci/common.c | 4 +- arch/i386/pci/irq.c | 4 +- drivers/acpi/osl.c | 2 +- drivers/acpi/processor_idle.c | 2 +- drivers/acpi/sleep/main.c | 2 +- drivers/acpi/thermal.c | 8 +-- drivers/ata/ata_piix.c | 4 +- drivers/ata/pata_ali.c | 2 +- drivers/ata/pata_cs5530.c | 2 +- drivers/ata/pata_via.c | 2 +- drivers/char/i8k.c | 4 +- drivers/char/ipmi/ipmi_si_intf.c | 9 ++-- drivers/firmware/dmi_scan.c | 57 +++++++++++---------- drivers/hwmon/abituguru.c | 2 +- drivers/hwmon/applesmc.c | 2 +- drivers/hwmon/hdaps.c | 4 +- drivers/ide/pci/alim15x3.c | 2 +- drivers/ide/pci/via82cxxx.c | 2 +- drivers/input/misc/wistron_btns.c | 2 +- drivers/input/mouse/lifebook.c | 6 +-- drivers/input/mouse/synaptics.c | 2 +- drivers/misc/msi-laptop.c | 2 +- drivers/misc/sony-laptop.c | 4 +- drivers/misc/thinkpad_acpi.c | 2 +- drivers/pnp/pnpbios/core.c | 2 +- drivers/usb/host/uhci-hcd.c | 2 +- drivers/video/imacfb.c | 2 +- include/linux/dmi.h | 22 ++++---- 35 files changed, 103 insertions(+), 97 deletions(-) diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index cacdd883bf2b..afd2afe9102d 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -907,7 +907,7 @@ static void __init acpi_process_madt(void) #ifdef __i386__ -static int __init disable_acpi_irq(struct dmi_system_id *d) +static int __init disable_acpi_irq(const struct dmi_system_id *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n", @@ -917,7 +917,7 @@ static int __init disable_acpi_irq(struct dmi_system_id *d) return 0; } -static int __init disable_acpi_pci(struct dmi_system_id *d) +static int __init disable_acpi_pci(const struct dmi_system_id *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n", @@ -927,7 +927,7 @@ static int __init disable_acpi_pci(struct dmi_system_id *d) return 0; } -static int __init dmi_disable_acpi(struct dmi_system_id *d) +static int __init dmi_disable_acpi(const struct dmi_system_id *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: acpi off\n", d->ident); @@ -942,7 +942,7 @@ static int __init dmi_disable_acpi(struct dmi_system_id *d) /* * Limit ACPI to CPU enumeration for HT */ -static int __init force_acpi_ht(struct dmi_system_id *d) +static int __init force_acpi_ht(const struct dmi_system_id *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c index c42b5ab49deb..10699489cfe7 100644 --- a/arch/i386/kernel/acpi/sleep.c +++ b/arch/i386/kernel/acpi/sleep.c @@ -84,7 +84,7 @@ __setup("acpi_sleep=", acpi_sleep_setup); /* Ouch, we want to delete this. We already have better version in userspace, in s2ram from suspend.sf.net project */ -static __init int reset_videomode_after_s3(struct dmi_system_id *d) +static __init int reset_videomode_after_s3(const struct dmi_system_id *d) { acpi_realmode_flags |= 2; return 0; diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index f02a8aca826b..32f2365c26ed 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -1869,7 +1869,7 @@ static struct miscdevice apm_device = { /* Simple "print if true" callback */ -static int __init print_if_true(struct dmi_system_id *d) +static int __init print_if_true(const struct dmi_system_id *d) { printk("%s\n", d->ident); return 0; @@ -1879,14 +1879,14 @@ static int __init print_if_true(struct dmi_system_id *d) * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it was * disabled before the suspend. Linux used to get terribly confused by that. */ -static int __init broken_ps2_resume(struct dmi_system_id *d) +static int __init broken_ps2_resume(const struct dmi_system_id *d) { printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround hopefully not needed.\n", d->ident); return 0; } /* Some bioses have a broken protected mode poweroff and need to use realmode */ -static int __init set_realmode_power_off(struct dmi_system_id *d) +static int __init set_realmode_power_off(const struct dmi_system_id *d) { if (apm_info.realmode_power_off == 0) { apm_info.realmode_power_off = 1; @@ -1896,7 +1896,7 @@ static int __init set_realmode_power_off(struct dmi_system_id *d) } /* Some laptops require interrupts to be enabled during APM calls */ -static int __init set_apm_ints(struct dmi_system_id *d) +static int __init set_apm_ints(const struct dmi_system_id *d) { if (apm_info.allow_ints == 0) { apm_info.allow_ints = 1; @@ -1906,7 +1906,7 @@ static int __init set_apm_ints(struct dmi_system_id *d) } /* Some APM bioses corrupt memory or just plain do not work */ -static int __init apm_is_horked(struct dmi_system_id *d) +static int __init apm_is_horked(const struct dmi_system_id *d) { if (apm_info.disabled == 0) { apm_info.disabled = 1; @@ -1915,7 +1915,7 @@ static int __init apm_is_horked(struct dmi_system_id *d) return 0; } -static int __init apm_is_horked_d850md(struct dmi_system_id *d) +static int __init apm_is_horked_d850md(const struct dmi_system_id *d) { if (apm_info.disabled == 0) { apm_info.disabled = 1; @@ -1927,7 +1927,7 @@ static int __init apm_is_horked_d850md(struct dmi_system_id *d) } /* Some APM bioses hang on APM idle calls */ -static int __init apm_likes_to_melt(struct dmi_system_id *d) +static int __init apm_likes_to_melt(const struct dmi_system_id *d) { if (apm_info.forbid_idle == 0) { apm_info.forbid_idle = 1; @@ -1951,7 +1951,7 @@ static int __init apm_likes_to_melt(struct dmi_system_id *d) * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) */ -static int __init broken_apm_power(struct dmi_system_id *d) +static int __init broken_apm_power(const struct dmi_system_id *d) { apm_info.get_power_status_broken = 1; printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); @@ -1962,7 +1962,7 @@ static int __init broken_apm_power(struct dmi_system_id *d) * This bios swaps the APM minute reporting bytes over (Many sony laptops * have this problem). */ -static int __init swab_apm_power_in_minutes(struct dmi_system_id *d) +static int __init swab_apm_power_in_minutes(const struct dmi_system_id *d) { apm_info.get_power_status_swabinminutes = 1; printk(KERN_WARNING "BIOS strings suggest APM reports battery life in minutes and wrong byte order.\n"); diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 705e13a30781..b6434a7ef8b2 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -533,13 +533,13 @@ static int __init acpi_cpufreq_early_init(void) */ static int bios_with_sw_any_bug; -static int sw_any_bug_found(struct dmi_system_id *d) +static int sw_any_bug_found(const struct dmi_system_id *d) { bios_with_sw_any_bug = 1; return 0; } -static struct dmi_system_id sw_any_bug_dmi_table[] = { +static const struct dmi_system_id sw_any_bug_dmi_table[] = { { .callback = sw_any_bug_found, .ident = "Supermicro Server X6DLP", diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index 0d796248866c..b37ed226830a 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c @@ -79,7 +79,7 @@ __setup("reboot=", reboot_setup); /* * Some machines require the "reboot=b" commandline option, this quirk makes that automatic. */ -static int __init set_bios_reboot(struct dmi_system_id *d) +static int __init set_bios_reboot(const struct dmi_system_id *d) { if (!reboot_thru_bios) { reboot_thru_bios = 1; diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index a39280b4dd3a..3ed0ae8c918d 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -305,7 +305,7 @@ void mark_tsc_unstable(char *reason) } EXPORT_SYMBOL_GPL(mark_tsc_unstable); -static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d) +static int __init dmi_mark_tsc_unstable(const struct dmi_system_id *d) { printk(KERN_NOTICE "%s detected: marking TSC unstable.\n", d->ident); diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c index 58a477baec30..292a225edabe 100644 --- a/arch/i386/mach-generic/bigsmp.c +++ b/arch/i386/mach-generic/bigsmp.c @@ -21,7 +21,7 @@ static int dmi_bigsmp; /* can be set by dmi scanners */ -static int hp_ht_bigsmp(struct dmi_system_id *d) +static int hp_ht_bigsmp(const struct dmi_system_id *d) { #ifdef CONFIG_X86_GENERICARCH printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident); @@ -31,7 +31,7 @@ static int hp_ht_bigsmp(struct dmi_system_id *d) } -static struct dmi_system_id bigsmp_dmi_table[] = { +static const struct dmi_system_id bigsmp_dmi_table[] = { { hp_ht_bigsmp, "HP ProLiant DL760 G2", { DMI_MATCH(DMI_BIOS_VENDOR, "HP"), DMI_MATCH(DMI_BIOS_VERSION, "P44-"), diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index ebc6f3c66340..07d5223442bf 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -123,7 +123,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b) * on the kernel command line (which was parsed earlier). */ -static int __devinit set_bf_sort(struct dmi_system_id *d) +static int __devinit set_bf_sort(const struct dmi_system_id *d) { if (pci_bf_sort == pci_bf_sort_default) { pci_bf_sort = pci_dmi_bf; @@ -136,7 +136,7 @@ static int __devinit set_bf_sort(struct dmi_system_id *d) * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) */ #ifdef __i386__ -static int __devinit assign_all_busses(struct dmi_system_id *d) +static int __devinit assign_all_busses(const struct dmi_system_id *d) { pci_probe |= PCI_ASSIGN_ALL_BUSSES; printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 8434f2323b87..d98c6b096f8e 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -1010,7 +1010,7 @@ static void __init pcibios_fixup_irqs(void) * Work around broken HP Pavilion Notebooks which assign USB to * IRQ 9 even though it is actually wired to IRQ 11 */ -static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) +static int __init fix_broken_hp_bios_irq9(const struct dmi_system_id *d) { if (!broken_hp_bios_irq9) { broken_hp_bios_irq9 = 1; @@ -1023,7 +1023,7 @@ static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) * Work around broken Acer TravelMate 360 Notebooks which assign * Cardbus to IRQ 11 even though it is actually wired to IRQ 10 */ -static int __init fix_acer_tm360_irqrouting(struct dmi_system_id *d) +static int __init fix_acer_tm360_irqrouting(const struct dmi_system_id *d) { if (!acer_tm360_irqrouting) { acer_tm360_irqrouting = 1; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 12c09fafce9a..352cf81af581 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1214,7 +1214,7 @@ acpi_os_validate_address ( } #ifdef CONFIG_DMI -static int dmi_osi_linux(struct dmi_system_id *d) +static int dmi_osi_linux(const struct dmi_system_id *d) { printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident); enable_osi_linux(1); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f18261368e76..1e8287b4f40c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -92,7 +92,7 @@ module_param(bm_history, uint, 0644); * * To skip this limit, boot/load with a large max_cstate limit. */ -static int set_max_cstate(struct dmi_system_id *id) +static int set_max_cstate(const struct dmi_system_id *id) { if (max_cstate > ACPI_PROCESSOR_MAX_POWER) return 0; diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 2cbb9aabd00e..5055acf2163c 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -215,7 +215,7 @@ static struct pm_ops acpi_pm_ops = { * Toshiba fails to preserve interrupts over S1, reinitialization * of 8259 is needed after S1 resume. */ -static int __init init_ints_after_s1(struct dmi_system_id *d) +static int __init init_ints_after_s1(const struct dmi_system_id *d) { printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident); init_8259A_after_S1 = 1; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index bc6d5866ef98..ad898e10c1a9 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -1360,7 +1360,7 @@ static int acpi_thermal_resume(struct acpi_device *device) } #ifdef CONFIG_DMI -static int thermal_act(struct dmi_system_id *d) { +static int thermal_act(const struct dmi_system_id *d) { if (act == 0) { printk(KERN_NOTICE "ACPI: %s detected: " @@ -1369,14 +1369,14 @@ static int thermal_act(struct dmi_system_id *d) { } return 0; } -static int thermal_nocrt(struct dmi_system_id *d) { +static int thermal_nocrt(const struct dmi_system_id *d) { printk(KERN_NOTICE "ACPI: %s detected: " "disabling all critical thermal trip point actions.\n", d->ident); nocrt = 1; return 0; } -static int thermal_tzp(struct dmi_system_id *d) { +static int thermal_tzp(const struct dmi_system_id *d) { if (tzp == 0) { printk(KERN_NOTICE "ACPI: %s detected: " @@ -1385,7 +1385,7 @@ static int thermal_tzp(struct dmi_system_id *d) { } return 0; } -static int thermal_psv(struct dmi_system_id *d) { +static int thermal_psv(const struct dmi_system_id *d) { if (psv == 0) { printk(KERN_NOTICE "ACPI: %s detected: " diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 6996eb5b7506..92c2d5082bef 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -919,7 +919,7 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev) #ifdef CONFIG_PM static int piix_broken_suspend(void) { - static struct dmi_system_id sysids[] = { + static const struct dmi_system_id sysids[] = { { .ident = "TECRA M3", .matches = { @@ -1183,7 +1183,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) { - static struct dmi_system_id sysids[] = { + static const struct dmi_system_id sysids[] = { { /* Clevo M570U sets IOCFG bit 18 if the cdrom * isn't used to boot the system which diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 71bdc3b3189c..32a10c99c06f 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -40,7 +40,7 @@ * Cable special cases */ -static struct dmi_system_id cable_dmi_table[] = { +static const struct dmi_system_id cable_dmi_table[] = { { .ident = "HP Pavilion N5430", .matches = { diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index c6066aa43ec8..eaaea848b649 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -214,7 +214,7 @@ static struct ata_port_operations cs5530_port_ops = { .port_start = ata_port_start, }; -static struct dmi_system_id palmax_dmi_table[] = { +static const struct dmi_system_id palmax_dmi_table[] = { { .ident = "Palmax PD1100", .matches = { diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 636c4f1a0b24..f143db4559e0 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -129,7 +129,7 @@ static const struct via_isa_bridge { * Cable special cases */ -static struct dmi_system_id cable_dmi_table[] = { +static const struct dmi_system_id cable_dmi_table[] = { { .ident = "Acer Ferrari 3400", .matches = { diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 0289705967de..cd406416effd 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -98,9 +98,9 @@ struct smm_regs { unsigned int edi __attribute__ ((packed)); }; -static inline char *i8k_get_dmi_data(int field) +static inline const char *i8k_get_dmi_data(int field) { - char *dmi_data = dmi_get_system_info(field); + const char *dmi_data = dmi_get_system_info(field); return dmi_data && *dmi_data ? dmi_data : "?"; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index dd441ff4af56..7901d5f218ec 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1965,10 +1965,10 @@ struct dmi_ipmi_data u8 slave_addr; }; -static int __devinit decode_dmi(struct dmi_header *dm, +static int __devinit decode_dmi(const struct dmi_header *dm, struct dmi_ipmi_data *dmi) { - u8 *data = (u8 *)dm; + const u8 *data = (const u8 *)dm; unsigned long base_addr; u8 reg_spacing; u8 len = dm->length; @@ -2091,13 +2091,14 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) static void __devinit dmi_find_bmc(void) { - struct dmi_device *dev = NULL; + const struct dmi_device *dev = NULL; struct dmi_ipmi_data data; int rv; while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) { memset(&data, 0, sizeof(data)); - rv = decode_dmi((struct dmi_header *) dev->device_data, &data); + rv = decode_dmi((const struct dmi_header *) dev->device_data, + &data); if (!rv) try_init_dmi(&data); } diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index f7318b3b51f2..0cdadea7a40e 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -8,9 +8,9 @@ #include #include -static char * __init dmi_string(struct dmi_header *dm, u8 s) +static char * __init dmi_string(const struct dmi_header *dm, u8 s) { - u8 *bp = ((u8 *) dm) + dm->length; + const u8 *bp = ((u8 *) dm) + dm->length; char *str = ""; if (s) { @@ -37,7 +37,7 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s) * pointing to completely the wrong place for example */ static int __init dmi_table(u32 base, int len, int num, - void (*decode)(struct dmi_header *)) + void (*decode)(const struct dmi_header *)) { u8 *buf, *data; int i = 0; @@ -53,7 +53,8 @@ static int __init dmi_table(u32 base, int len, int num, * OR we run off the end of the table (also happens) */ while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { - struct dmi_header *dm = (struct dmi_header *)data; + const struct dmi_header *dm = (const struct dmi_header *)data; + /* * We want to know the total length (formated area and strings) * before decoding to make sure we won't run off the table in @@ -71,7 +72,7 @@ static int __init dmi_table(u32 base, int len, int num, return 0; } -static int __init dmi_checksum(u8 *buf) +static int __init dmi_checksum(const u8 *buf) { u8 sum = 0; int a; @@ -89,9 +90,10 @@ int dmi_available; /* * Save a DMI string */ -static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) +static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string) { - char *p, *d = (char*) dm; + const char *d = (const char*) dm; + char *p; if (dmi_ident[slot]) return; @@ -103,9 +105,9 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) dmi_ident[slot] = p; } -static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index) +static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index) { - u8 *d = (u8*) dm + index; + const u8 *d = (u8*) dm + index; char *s; int is_ff = 1, is_00 = 1, i; @@ -132,9 +134,9 @@ static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index) dmi_ident[slot] = s; } -static void __init dmi_save_type(struct dmi_header *dm, int slot, int index) +static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index) { - u8 *d = (u8*) dm + index; + const u8 *d = (u8*) dm + index; char *s; if (dmi_ident[slot]) @@ -148,13 +150,13 @@ static void __init dmi_save_type(struct dmi_header *dm, int slot, int index) dmi_ident[slot] = s; } -static void __init dmi_save_devices(struct dmi_header *dm) +static void __init dmi_save_devices(const struct dmi_header *dm) { int i, count = (dm->length - sizeof(struct dmi_header)) / 2; struct dmi_device *dev; for (i = 0; i < count; i++) { - char *d = (char *)(dm + 1) + (i * 2); + const char *d = (char *)(dm + 1) + (i * 2); /* Skip disabled device */ if ((*d & 0x80) == 0) @@ -173,7 +175,7 @@ static void __init dmi_save_devices(struct dmi_header *dm) } } -static void __init dmi_save_oem_strings_devices(struct dmi_header *dm) +static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) { int i, count = *(u8 *)(dm + 1); struct dmi_device *dev; @@ -194,7 +196,7 @@ static void __init dmi_save_oem_strings_devices(struct dmi_header *dm) } } -static void __init dmi_save_ipmi_device(struct dmi_header *dm) +static void __init dmi_save_ipmi_device(const struct dmi_header *dm) { struct dmi_device *dev; void * data; @@ -225,7 +227,7 @@ static void __init dmi_save_ipmi_device(struct dmi_header *dm) * and machine entries. For 2.5 we should pull the smbus controller info * out of here. */ -static void __init dmi_decode(struct dmi_header *dm) +static void __init dmi_decode(const struct dmi_header *dm) { switch(dm->type) { case 0: /* BIOS Information */ @@ -265,9 +267,10 @@ static void __init dmi_decode(struct dmi_header *dm) } } -static int __init dmi_present(char __iomem *p) +static int __init dmi_present(const char __iomem *p) { u8 buf[15]; + memcpy_fromio(buf, p, 15); if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { u16 num = (buf[13] << 8) | buf[12]; @@ -348,10 +351,10 @@ void __init dmi_scan_machine(void) * returns non zero or we hit the end. Callback function is called for * each successful match. Returns the number of matches. */ -int dmi_check_system(struct dmi_system_id *list) +int dmi_check_system(const struct dmi_system_id *list) { int i, count = 0; - struct dmi_system_id *d = list; + const struct dmi_system_id *d = list; while (d->ident) { for (i = 0; i < ARRAY_SIZE(d->matches); i++) { @@ -380,7 +383,7 @@ EXPORT_SYMBOL(dmi_check_system); * Returns one DMI data value, can be used to perform * complex DMI data checks. */ -char *dmi_get_system_info(int field) +const char *dmi_get_system_info(int field) { return dmi_ident[field]; } @@ -391,7 +394,7 @@ EXPORT_SYMBOL(dmi_get_system_info); * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. * @str: Case sensitive Name */ -int dmi_name_in_vendors(char *str) +int dmi_name_in_vendors(const char *str) { static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, @@ -418,13 +421,15 @@ EXPORT_SYMBOL(dmi_name_in_vendors); * A new search is initiated by passing %NULL as the @from argument. * If @from is not %NULL, searches continue from next device. */ -struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from) +const struct dmi_device * dmi_find_device(int type, const char *name, + const struct dmi_device *from) { - struct list_head *d, *head = from ? &from->list : &dmi_devices; + const struct list_head *head = from ? &from->list : &dmi_devices; + struct list_head *d; for(d = head->next; d != &dmi_devices; d = d->next) { - struct dmi_device *dev = list_entry(d, struct dmi_device, list); + const struct dmi_device *dev = + list_entry(d, struct dmi_device, list); if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) && ((name == NULL) || (strcmp(dev->name, name) == 0))) @@ -444,7 +449,7 @@ EXPORT_SYMBOL(dmi_find_device); int dmi_get_year(int field) { int year; - char *s = dmi_get_system_info(field); + const char *s = dmi_get_system_info(field); if (!s) return -1; diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index d575ee958de5..2317f4bb9c92 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1449,7 +1449,7 @@ static int __init abituguru_init(void) struct resource res = { .flags = IORESOURCE_IO }; #ifdef CONFIG_DMI - char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); /* safety check, refuse to load on non Abit motherboards */ if (!force && (!board_vendor || diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 941729a131f5..56213b7f8188 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -1071,7 +1071,7 @@ static const struct attribute_group temperature_attributes_group = /* * applesmc_dmi_match - found a match. return one, short-circuiting the hunt. */ -static int applesmc_dmi_match(struct dmi_system_id *id) +static int applesmc_dmi_match(const struct dmi_system_id *id) { int i = 0; struct dmi_match_data* dmi_data = id->driver_data; diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index e0cf5e6fe5bc..a7c6d407572b 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -480,14 +480,14 @@ static struct attribute_group hdaps_attribute_group = { /* Module stuff */ /* hdaps_dmi_match - found a match. return one, short-circuiting the hunt. */ -static int __init hdaps_dmi_match(struct dmi_system_id *id) +static int __init hdaps_dmi_match(const struct dmi_system_id *id) { printk(KERN_INFO "hdaps: %s detected.\n", id->ident); return 1; } /* hdaps_dmi_match_invert - found an inverted match. */ -static int __init hdaps_dmi_match_invert(struct dmi_system_id *id) +static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id) { hdaps_invert = 1; printk(KERN_INFO "hdaps: inverting axis readings.\n"); diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 11ecb618007c..20ebe3b7049c 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -588,7 +588,7 @@ out: * Cable special cases */ -static struct dmi_system_id cable_dmi_table[] = { +static const struct dmi_system_id cable_dmi_table[] = { { .ident = "HP Pavilion N5430", .matches = { diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index a7be7795e6af..c10203a32159 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -419,7 +419,7 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const * Cable special cases */ -static struct dmi_system_id cable_dmi_table[] = { +static const struct dmi_system_id cable_dmi_table[] = { { .ident = "Acer Ferrari 3400", .matches = { diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 60121f10f8d9..b438d998625c 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -247,7 +247,7 @@ static int have_wifi; static int have_bluetooth; static int have_leds; -static int __init dmi_matched(struct dmi_system_id *dmi) +static int __init dmi_matched(const struct dmi_system_id *dmi) { const struct key_entry *key; diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 91109b49fde1..608674d0be8b 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -27,7 +27,7 @@ struct lifebook_data { static const char *desired_serio_phys; -static int lifebook_set_serio_phys(struct dmi_system_id *d) +static int lifebook_set_serio_phys(const struct dmi_system_id *d) { desired_serio_phys = d->driver_data; return 0; @@ -35,13 +35,13 @@ static int lifebook_set_serio_phys(struct dmi_system_id *d) static unsigned char lifebook_use_6byte_proto; -static int lifebook_set_6byte_proto(struct dmi_system_id *d) +static int lifebook_set_6byte_proto(const struct dmi_system_id *d) { lifebook_use_6byte_proto = 1; return 0; } -static struct dmi_system_id lifebook_dmi_table[] = { +static const struct dmi_system_id lifebook_dmi_table[] = { { .ident = "FLORA-ie 55mi", .matches = { diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 666ad3a53fdb..d349c4a5e3e8 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -602,7 +602,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) #if defined(__i386__) #include -static struct dmi_system_id toshiba_dmi_table[] = { +static const struct dmi_system_id toshiba_dmi_table[] = { { .ident = "Toshiba Satellite", .matches = { diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index 349be934db7c..83679c762925 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c @@ -283,7 +283,7 @@ static struct platform_device *msipf_device; /* Initialization */ -static int dmi_check_cb(struct dmi_system_id *id) +static int dmi_check_cb(const struct dmi_system_id *id) { printk("msi-laptop: Identified laptop model '%s'.\n", id->ident); return 0; diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index d38ddce592c0..e73a71f04bb4 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -807,7 +807,7 @@ static struct sony_nc_event *sony_nc_events; /* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence * for Fn keys */ -static int sony_nc_C_enable(struct dmi_system_id *id) +static int sony_nc_C_enable(const struct dmi_system_id *id) { int result = 0; @@ -845,7 +845,7 @@ static struct sony_nc_event sony_C_events[] = { }; /* SNC-only model map */ -static struct dmi_system_id sony_nc_ids[] = { +static const struct dmi_system_id sony_nc_ids[] = { { .ident = "Sony Vaio FE Series", .callback = sony_nc_C_enable, diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 0222bbaf7b76..6c0b2f0a51ab 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -4448,7 +4448,7 @@ static void ibm_exit(struct ibm_struct *ibm) static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) { - struct dmi_device *dev = NULL; + const struct dmi_device *dev = NULL; char ec_fw_string[18]; if (!tp) diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 0691f473e9d4..4e9fd37cff35 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -500,7 +500,7 @@ static int __init pnpbios_probe_system(void) return 0; } -static int __init exploding_pnp_bios(struct dmi_system_id *d) +static int __init exploding_pnp_bios(const struct dmi_system_id *d) { printk(KERN_WARNING "%s detected. Disabling PnPBIOS\n", d->ident); return 0; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 805e5fc5f5db..4db17f75f4f1 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -237,7 +237,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) static int remote_wakeup_is_broken(struct uhci_hcd *uhci) { int port; - char *sys_info; + const char *sys_info; static char bad_Asus_board[] = "A7V8X"; /* One of Asus's motherboards has a bug which causes it to diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c index 18ea4a549105..6455fd2a39f2 100644 --- a/drivers/video/imacfb.c +++ b/drivers/video/imacfb.c @@ -58,7 +58,7 @@ static int model = M_UNKNOWN; static int manual_height; static int manual_width; -static int set_system(struct dmi_system_id *id) +static int set_system(const struct dmi_system_id *id) { printk(KERN_INFO "imacfb: %s detected - set system to %ld\n", id->ident, (long)id->driver_data); diff --git a/include/linux/dmi.h b/include/linux/dmi.h index b8ac7b01c45e..00fc7a9c35ec 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -54,7 +54,7 @@ struct dmi_strmatch { }; struct dmi_system_id { - int (*callback)(struct dmi_system_id *); + int (*callback)(const struct dmi_system_id *); const char *ident; struct dmi_strmatch matches[4]; void *driver_data; @@ -71,22 +71,22 @@ struct dmi_device { #ifdef CONFIG_DMI -extern int dmi_check_system(struct dmi_system_id *list); -extern char * dmi_get_system_info(int field); -extern struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from); +extern int dmi_check_system(const struct dmi_system_id *list); +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 int dmi_name_in_vendors(char *str); +extern int dmi_name_in_vendors(const char *str); #else -static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } -static inline char * dmi_get_system_info(int field) { return NULL; } -static inline struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from) { return NULL; } +static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; } +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 int dmi_get_year(int year) { return 0; } -static inline int dmi_name_in_vendors(char *s) { return 0; } +static inline int dmi_name_in_vendors(const char *s) { return 0; } #endif From 9b5d0f1e6dd6b4a67d0851a1c5a4bcf9b0c2f258 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 18 Jul 2007 17:59:15 -0300 Subject: [PATCH 0514/2804] V4L/DVB (5862): V4L: Add internal ioctl-like interface. This patch adds an internal ioctl-like interface which can be used in situations where a single Video4Linux device is implemented by multiple device drivers. One master device controls one or more slave devices. The slaves provide Video4Linux ioctl-like interface for the use of the master. Only a handful of ioctls are implemented at the moment. More can (and should) be added as more functionality is required. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 3 +- drivers/media/video/v4l2-int-device.c | 154 +++++++++++++++++++ include/media/v4l2-int-device.h | 210 ++++++++++++++++++++++++++ 3 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 drivers/media/video/v4l2-int-device.c create mode 100644 include/media/v4l2-int-device.h diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 10b4d4469016..d35306daac2f 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -11,7 +11,8 @@ tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o -obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o +obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ + v4l2-int-device.o ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y) obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c new file mode 100644 index 000000000000..7885d9b38c92 --- /dev/null +++ b/drivers/media/video/v4l2-int-device.c @@ -0,0 +1,154 @@ +/* + * drivers/media/video/v4l2-int-device.c + * + * V4L2 internal ioctl interface. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * 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 + +static DEFINE_MUTEX(mutex); +static LIST_HEAD(int_list); + +static void v4l2_int_device_try_attach_all(void) +{ + struct list_head *head_master; + + list_for_each(head_master, &int_list) { + struct list_head *head_slave; + struct v4l2_int_device *m = + list_entry(head_master, struct v4l2_int_device, head); + + if (m->type != v4l2_int_type_master) + continue; + + list_for_each(head_slave, &int_list) { + struct v4l2_int_device *s = + list_entry(head_slave, + struct v4l2_int_device, head); + + if (s->type != v4l2_int_type_slave) + continue; + + /* Slave is connected? */ + if (s->u.slave->master) + continue; + + /* Slave wants to attach to master? */ + if (s->u.slave->attach_to[0] != 0 + && strncmp(m->name, s->u.slave->attach_to, + V4L2NAMESIZE)) + continue; + + if (!try_module_get(m->module)) + continue; + + if (m->u.master->attach(m, s)) { + module_put(m->module); + continue; + } + + s->u.slave->master = m; + } + } +} + +static int ioctl_sort_cmp(const void *a, const void *b) +{ + const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b; + + if (d1->num > d2->num) + return 1; + + if (d1->num < d2->num) + return -1; + + return 0; +} + +int v4l2_int_device_register(struct v4l2_int_device *d) +{ + if (d->type == v4l2_int_type_slave) + sort(d->u.slave->ioctls, d->u.slave->num_ioctls, + sizeof(struct v4l2_int_ioctl_desc), + &ioctl_sort_cmp, NULL); + mutex_lock(&mutex); + list_add(&d->head, &int_list); + v4l2_int_device_try_attach_all(); + mutex_unlock(&mutex); + + return 0; +} + +void v4l2_int_device_unregister(struct v4l2_int_device *d) +{ + mutex_lock(&mutex); + list_del(&d->head); + if (d->type == v4l2_int_type_slave + && d->u.slave->master != NULL) { + d->u.slave->master->u.master->detach(d); + module_put(d->u.slave->master->module); + d->u.slave->master = NULL; + } + mutex_unlock(&mutex); +} + +static int no_such_ioctl(struct v4l2_int_device *d) +{ + return -EINVAL; +} + +/* Adapted from search_extable in extable.c. */ +static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) +{ + const struct v4l2_int_ioctl_desc *first = slave->ioctls; + const struct v4l2_int_ioctl_desc *last = + first + slave->num_ioctls - 1; + + while (first <= last) { + const struct v4l2_int_ioctl_desc *mid; + + mid = (last - first) / 2 + first; + + if (mid->num < cmd) + first = mid + 1; + else if (mid->num > cmd) + last = mid - 1; + else + return mid->func; + } + + return &no_such_ioctl; +} + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) +{ + return ((v4l2_int_ioctl_func_0 *)find_ioctl(d->u.slave, cmd))(d); +} + +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) +{ + return ((v4l2_int_ioctl_func_1 *)find_ioctl(d->u.slave, cmd))(d, arg); +} diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h new file mode 100644 index 000000000000..2b6fc1122f6c --- /dev/null +++ b/include/media/v4l2-int-device.h @@ -0,0 +1,210 @@ +/* + * include/media/v4l2-int-device.h + * + * V4L2 internal ioctl interface. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * 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 V4L2_INT_DEVICE_H +#define V4L2_INT_DEVICE_H + +#include +#include + +#define V4L2NAMESIZE 32 + +enum v4l2_int_type { + v4l2_int_type_master = 1, + v4l2_int_type_slave +}; + +enum v4l2_int_ioctl_num { + /* + * + * "Proper" V4L ioctls, as in struct video_device. + * + */ + vidioc_int_enum_fmt_cap_num = 1, + vidioc_int_g_fmt_cap_num, + vidioc_int_s_fmt_cap_num, + vidioc_int_try_fmt_cap_num, + vidioc_int_queryctrl_num, + vidioc_int_g_ctrl_num, + vidioc_int_s_ctrl_num, + vidioc_int_g_parm_num, + vidioc_int_s_parm_num, + + /* + * + * Strictly internal ioctls. + * + */ + /* Initialise the device when slave attaches to the master. */ + vidioc_int_dev_init_num = 1000, + /* Delinitialise the device at slave detach. */ + vidioc_int_dev_exit_num, + /* Set device power state: 0 is off, non-zero is on. */ + vidioc_int_s_power_num, + /* Get parallel interface clock speed for current settings. */ + vidioc_int_g_ext_clk_num, + /* + * Tell what the parallel interface clock speed actually is. + */ + vidioc_int_s_ext_clk_num, + /* Does the slave need to be reset after VIDIOC_DQBUF? */ + vidioc_int_g_needs_reset_num, + + /* + * + * VIDIOC_INT_* ioctls. + * + */ + /* VIDIOC_INT_RESET */ + vidioc_int_reset_num, + /* VIDIOC_INT_INIT */ + vidioc_int_init_num, + /* VIDIOC_INT_G_CHIP_IDENT */ + vidioc_int_g_chip_ident_num, + + /* + * + * Start of private ioctls. + * + */ + vidioc_int_priv_start_num = 2000, +}; + +struct v4l2_int_device; + +struct v4l2_int_master { + int (*attach)(struct v4l2_int_device *master, + struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *master); +}; + +typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); + +struct v4l2_int_ioctl_desc { + int num; + v4l2_int_ioctl_func *func; +}; + +struct v4l2_int_slave { + /* Don't touch master. */ + struct v4l2_int_device *master; + + char attach_to[V4L2NAMESIZE]; + + int num_ioctls; + struct v4l2_int_ioctl_desc *ioctls; +}; + +struct v4l2_int_device { + /* Don't touch head. */ + struct list_head head; + + struct module *module; + + char name[V4L2NAMESIZE]; + + enum v4l2_int_type type; + union { + struct v4l2_int_master *master; + struct v4l2_int_slave *slave; + } u; + + void *priv; +}; + +int v4l2_int_device_register(struct v4l2_int_device *d); +void v4l2_int_device_unregister(struct v4l2_int_device *d); + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); + +/* + * + * IOCTL wrapper functions for better type checking. + * + */ + +#define V4L2_INT_WRAPPER_0(name) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d) \ + { \ + return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d, \ + arg_type asterisk arg) \ + { \ + return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ + (void *)arg); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *, \ + arg_type asterisk)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *); +V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *); +V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *); +V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); + +V4L2_INT_WRAPPER_0(dev_init); +V4L2_INT_WRAPPER_0(dev_exit); +V4L2_INT_WRAPPER_1(s_power, int, ); +V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); +V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); +V4L2_INT_WRAPPER_1(g_needs_reset, void, *); + +V4L2_INT_WRAPPER_0(reset); +V4L2_INT_WRAPPER_0(init); +V4L2_INT_WRAPPER_1(g_chip_ident, int, *); + +#endif From a5e90862114124d79e1a3f34641b00fec51d1806 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 18 Jul 2007 18:04:17 -0300 Subject: [PATCH 0515/2804] V4L/DVB (5863): TCM825x: Add driver. Add a driver for Toshiba TCM825x VGA camera sensor. This sensor is used e.g. in Nokia N800 internet tablet. This driver uses the new V4L2 internal ioctl interface. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 7 + drivers/media/video/Makefile | 2 + drivers/media/video/tcm825x.c | 942 ++++++++++++++++++++++++++++++++++ drivers/media/video/tcm825x.h | 195 +++++++ 4 files changed, 1146 insertions(+) create mode 100644 drivers/media/video/tcm825x.c create mode 100644 drivers/media/video/tcm825x.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index e204e7b4028a..675c8574403e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -197,6 +197,13 @@ config VIDEO_OV7670 OV7670 VGA camera. It currently only works with the M88ALP01 controller. +config VIDEO_TCM825X + tristate "TCM825x camera sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a driver for the Toshiba TCM825x VGA camera sensor. + It is used for example in Nokia N800. + config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index d35306daac2f..8f7205b558f6 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -98,6 +98,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o + obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c new file mode 100644 index 000000000000..4b973b099e59 --- /dev/null +++ b/drivers/media/video/tcm825x.c @@ -0,0 +1,942 @@ +/* + * drivers/media/video/tcm825x.c + * + * TCM825X camera sensor driver. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * Based on code from David Cohen + * + * This driver was based on ov9640 sensor driver from MontaVista + * + * 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 "tcm825x.h" + +/* + * The sensor has two fps modes: the lower one just gives half the fps + * at the same xclk than the high one. + */ +#define MAX_FPS 30 +#define MIN_FPS 8 +#define MAX_HALF_FPS (MAX_FPS / 2) +#define HIGH_FPS_MODE_LOWER_LIMIT 14 +#define DEFAULT_FPS MAX_HALF_FPS + +struct tcm825x_sensor { + const struct tcm825x_platform_data *platform_data; + struct v4l2_int_device *v4l2_int_device; + struct i2c_client *i2c_client; + struct v4l2_pix_format pix; + struct v4l2_fract timeperframe; +}; + +/* list of image formats supported by TCM825X sensor */ +const static struct v4l2_fmtdesc tcm825x_formats[] = { + { + .description = "YUYV (YUV 4:2:2), packed", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, { + /* Note: V4L2 defines RGB565 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 + * + * We interpret RGB565 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 + */ + .description = "RGB565, le", + .pixelformat = V4L2_PIX_FMT_RGB565, + }, +}; + +#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats) + +/* + * TCM825X register configuration for all combinations of pixel format and + * image size + */ +const static struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ }; +const static struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ }; +const static struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ }; +const static struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ }; +const static struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ }; +const static struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ }; + +const static struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT }; +const static struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT }; + +/* Our own specific controls */ +#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE +#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1 +#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2 +#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3 +#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4 +#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME + +/* Video controls */ +static struct vcontrol { + struct v4l2_queryctrl qc; + u16 reg; + u16 start_bit; +} video_control[] = { + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 63, + .step = 1, + }, + .reg = TCM825X_AG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0, + .maximum = 255, + .step = 1, + }, + .reg = TCM825X_MRG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0, + .maximum = 255, + .step = 1, + }, + .reg = TCM825X_MBG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto White Balance", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_AWBSW, + .start_bit = 7, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Time", + .minimum = 0, + .maximum = 0x1fff, + .step = 1, + }, + .reg = TCM825X_ESRSPD_U, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Image", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_H_INV, + .start_bit = 6, + }, + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_V_INV, + .start_bit = 7, + }, + /* Private controls */ + { + { + .id = V4L2_CID_ALC, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Luminance Control", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_ALCSW, + .start_bit = 7, + }, + { + { + .id = V4L2_CID_H_EDGE_EN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Horizontal Edge Enhancement", + .minimum = 0, + .maximum = 0xff, + .step = 1, + }, + .reg = TCM825X_HDTG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_V_EDGE_EN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Vertical Edge Enhancement", + .minimum = 0, + .maximum = 0xff, + .step = 1, + }, + .reg = TCM825X_VDTG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_LENS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Lens Shading Compensation", + .minimum = 0, + .maximum = 0x3f, + .step = 1, + }, + .reg = TCM825X_LENS, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_MAX_EXPOSURE_TIME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Maximum Exposure Time", + .minimum = 0, + .maximum = 0x3, + .step = 1, + }, + .reg = TCM825X_ESRLIM, + .start_bit = 5, + }, +}; + + +const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] = +{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga }; + +const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] = +{ &yuv422, &rgb565 }; + +/* + * Read a value from a register in an TCM825X sensor device. The value is + * returned in 'val'. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_read_reg(struct i2c_client *client, int reg) +{ + int err; + struct i2c_msg msg[2]; + u8 reg_buf, data_buf = 0; + + if (!client->adapter) + return -ENODEV; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ®_buf; + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = &data_buf; + + reg_buf = reg; + + err = i2c_transfer(client->adapter, msg, 2); + if (err < 0) + return err; + return data_buf; +} + +/* + * Write a value to a register in an TCM825X sensor device. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val) +{ + int err; + struct i2c_msg msg[1]; + unsigned char data[2]; + + if (!client->adapter) + return -ENODEV; + + msg->addr = client->addr; + msg->flags = 0; + msg->len = 2; + msg->buf = data; + data[0] = reg; + data[1] = val; + err = i2c_transfer(client->adapter, msg, 1); + if (err >= 0) + return 0; + return err; +} + +static int __tcm825x_write_reg_mask(struct i2c_client *client, + u8 reg, u8 val, u8 mask) +{ + int rc; + + /* need to do read - modify - write */ + rc = tcm825x_read_reg(client, reg); + if (rc < 0) + return rc; + + rc &= (~mask); /* Clear the masked bits */ + val &= mask; /* Enforce mask on value */ + val |= rc; + + /* write the new value to the register */ + rc = tcm825x_write_reg(client, reg, val); + if (rc) + return rc; + + return 0; +} + +#define tcm825x_write_reg_mask(client, regmask, val) \ + __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \ + TCM825X_MASK((regmask))) + + +/* + * Initialize a list of TCM825X registers. + * The list of registers is terminated by the pair of values + * { TCM825X_REG_TERM, TCM825X_VAL_TERM }. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_write_default_regs(struct i2c_client *client, + const struct tcm825x_reg *reglist) +{ + int err; + const struct tcm825x_reg *next = reglist; + + while (!((next->reg == TCM825X_REG_TERM) + && (next->val == TCM825X_VAL_TERM))) { + err = tcm825x_write_reg(client, next->reg, next->val); + if (err) { + dev_err(&client->dev, "register writing failed\n"); + return err; + } + next++; + } + + return 0; +} + +static struct vcontrol *find_vctrl(int id) +{ + int i; + + if (id < V4L2_CID_BASE) + return NULL; + + for (i = 0; i < ARRAY_SIZE(video_control); i++) + if (video_control[i].qc.id == id) + return &video_control[i]; + + return NULL; +} + +/* + * Find the best match for a requested image capture size. The best match + * is chosen as the nearest match that has the same number or fewer pixels + * as the requested size, or the smallest image size if the requested size + * has fewer pixels than the smallest image. + */ +static enum image_size tcm825x_find_size(struct v4l2_int_device *s, + unsigned int width, + unsigned int height) +{ + enum image_size isize; + unsigned long pixels = width * height; + struct tcm825x_sensor *sensor = s->priv; + + for (isize = subQCIF; isize < VGA; isize++) { + if (tcm825x_sizes[isize + 1].height + * tcm825x_sizes[isize + 1].width > pixels) { + dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize); + + return isize; + } + } + + dev_dbg(&sensor->i2c_client->dev, "format default VGA\n"); + + return VGA; +} + +/* + * Configure the TCM825X for current image size, pixel format, and + * frame period. fper is the frame period (in seconds) expressed as a + * fraction. Returns zero if successful, or non-zero otherwise. The + * actual frame period is returned in fper. + */ +static int tcm825x_configure(struct v4l2_int_device *s) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_pix_format *pix = &sensor->pix; + enum image_size isize = tcm825x_find_size(s, pix->width, pix->height); + struct v4l2_fract *fper = &sensor->timeperframe; + enum pixel_format pfmt; + int err; + u32 tgt_fps; + u8 val; + + /* common register initialization */ + err = tcm825x_write_default_regs( + sensor->i2c_client, sensor->platform_data->default_regs()); + if (err) + return err; + + /* configure image size */ + val = tcm825x_siz_reg[isize]->val; + dev_dbg(&sensor->i2c_client->dev, + "configuring image size %d\n", isize); + err = tcm825x_write_reg_mask(sensor->i2c_client, + tcm825x_siz_reg[isize]->reg, val); + if (err) + return err; + + /* configure pixel format */ + switch (pix->pixelformat) { + default: + case V4L2_PIX_FMT_RGB565: + pfmt = RGB565; + break; + case V4L2_PIX_FMT_UYVY: + pfmt = YUV422; + break; + } + + dev_dbg(&sensor->i2c_client->dev, + "configuring pixel format %d\n", pfmt); + val = tcm825x_fmt_reg[pfmt]->val; + + err = tcm825x_write_reg_mask(sensor->i2c_client, + tcm825x_fmt_reg[pfmt]->reg, val); + if (err) + return err; + + /* + * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be + * set. Frame rate will be halved from the normal. + */ + tgt_fps = fper->denominator / fper->numerator; + if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) { + val = tcm825x_read_reg(sensor->i2c_client, 0x02); + val |= 0x80; + tcm825x_write_reg(sensor->i2c_client, 0x02, val); + } + + return 0; +} + +/* + * Given the image capture format in pix, the nominal frame period in + * timeperframe, calculate the required xclk frequency. + * + * TCM825X input frequency characteristics are: + * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz + */ +#define XCLK_MIN 11900000 +#define XCLK_MAX 25000000 + +static int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &sensor->timeperframe; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? + (2457 * tgt_fps) / MAX_HALF_FPS : + (2457 * tgt_fps) / MAX_FPS; + tgt_xclk *= 10000; + + tgt_xclk = min(tgt_xclk, (u32)XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)XCLK_MIN); + + *xclk = tgt_xclk; + + return 0; +} + +static int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk) +{ + if (xclk > XCLK_MAX || xclk < XCLK_MIN) + return -EINVAL; + + return 0; +} + +static int ioctl_queryctrl(struct v4l2_int_device *s, + struct v4l2_queryctrl *qc) +{ + struct vcontrol *control; + + control = find_vctrl(qc->id); + + if (control == NULL) + return -EINVAL; + + *qc = control->qc; + + return 0; +} + +static int ioctl_g_ctrl(struct v4l2_int_device *s, + struct v4l2_control *vc) +{ + struct tcm825x_sensor *sensor = s->priv; + struct i2c_client *client = sensor->i2c_client; + int val, r; + struct vcontrol *lvc; + + /* exposure time is special, spread accross 2 registers */ + if (vc->id == V4L2_CID_EXPOSURE) { + int val_lower, val_upper; + + val_upper = tcm825x_read_reg(client, + TCM825X_ADDR(TCM825X_ESRSPD_U)); + if (val_upper < 0) + return val_upper; + val_lower = tcm825x_read_reg(client, + TCM825X_ADDR(TCM825X_ESRSPD_L)); + if (val_lower < 0) + return val_lower; + + vc->value = ((val_upper & 0x1f) << 8) | (val_lower); + return 0; + } + + lvc = find_vctrl(vc->id); + if (lvc == NULL) + return -EINVAL; + + r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg)); + if (r < 0) + return r; + val = r & TCM825X_MASK(lvc->reg); + val >>= lvc->start_bit; + + if (val < 0) + return val; + + vc->value = val; + return 0; +} + +static int ioctl_s_ctrl(struct v4l2_int_device *s, + struct v4l2_control *vc) +{ + struct tcm825x_sensor *sensor = s->priv; + struct i2c_client *client = sensor->i2c_client; + struct vcontrol *lvc; + int val = vc->value; + + /* exposure time is special, spread accross 2 registers */ + if (vc->id == V4L2_CID_EXPOSURE) { + int val_lower, val_upper; + val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L); + val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U); + + if (tcm825x_write_reg_mask(client, + TCM825X_ESRSPD_U, val_upper)) + return -EIO; + + if (tcm825x_write_reg_mask(client, + TCM825X_ESRSPD_L, val_lower)) + return -EIO; + + return 0; + } + + lvc = find_vctrl(vc->id); + if (lvc == NULL) + return -EINVAL; + + val = val << lvc->start_bit; + if (tcm825x_write_reg_mask(client, lvc->reg, val)) + return -EIO; + + return 0; +} + +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + int index = fmt->index; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (index >= TCM825X_NUM_CAPTURE_FORMATS) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + fmt->flags = tcm825x_formats[index].flags; + strlcpy(fmt->description, tcm825x_formats[index].description, + sizeof(fmt->description)); + fmt->pixelformat = tcm825x_formats[index].pixelformat; + + return 0; +} + +static int ioctl_try_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + enum image_size isize; + int ifmt; + struct v4l2_pix_format *pix = &f->fmt.pix; + + isize = tcm825x_find_size(s, pix->width, pix->height); + dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %d\n", + isize, TCM825X_NUM_CAPTURE_FORMATS); + + pix->width = tcm825x_sizes[isize].width; + pix->height = tcm825x_sizes[isize].height; + + for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++) + if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat) + break; + + if (ifmt == TCM825X_NUM_CAPTURE_FORMATS) + ifmt = 0; /* Default = YUV 4:2:2 */ + + pix->pixelformat = tcm825x_formats[ifmt].pixelformat; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL; + pix->sizeimage = pix->bytesperline * pix->height; + pix->priv = 0; + dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n", + pix->pixelformat); + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_UYVY: + default: + pix->colorspace = V4L2_COLORSPACE_JPEG; + break; + case V4L2_PIX_FMT_RGB565: + pix->colorspace = V4L2_COLORSPACE_SRGB; + break; + } + + return 0; +} + +static int ioctl_s_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_pix_format *pix = &f->fmt.pix; + int rval; + + rval = ioctl_try_fmt_cap(s, f); + if (rval) + return rval; + + rval = tcm825x_configure(s); + + sensor->pix = *pix; + + return rval; +} + +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + + f->fmt.pix = sensor->pix; + + return 0; +} + +static int ioctl_g_parm(struct v4l2_int_device *s, + struct v4l2_streamparm *a) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + cparm->capability = V4L2_CAP_TIMEPERFRAME; + cparm->timeperframe = sensor->timeperframe; + + return 0; +} + +static int ioctl_s_parm(struct v4l2_int_device *s, + struct v4l2_streamparm *a) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + int rval; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if ((timeperframe->numerator == 0) + || (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + sensor->timeperframe = *timeperframe; + + rval = tcm825x_configure(s); + + return rval; +} + +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct tcm825x_sensor *sensor = s->priv; + + return sensor->platform_data->power_set(on); +} + +static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) +{ + struct tcm825x_sensor *sensor = s->priv; + + return sensor->platform_data->needs_reset(s, buf, &sensor->pix); +} + +static int ioctl_reset(struct v4l2_int_device *s) +{ + return -EBUSY; +} + +static int ioctl_init(struct v4l2_int_device *s) +{ + return tcm825x_configure(s); +} + +static int ioctl_dev_exit(struct v4l2_int_device *s) +{ + return 0; +} + +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + struct tcm825x_sensor *sensor = s->priv; + int r; + + r = tcm825x_read_reg(sensor->i2c_client, 0x01); + if (r < 0) + return r; + if (r == 0) { + dev_err(&sensor->i2c_client->dev, "device not detected\n"); + return -EIO; + } + return 0; +} + +#define NUM_IOCTLS 17 + +static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[NUM_IOCTLS] = { + { vidioc_int_dev_init_num, + (v4l2_int_ioctl_func *)&ioctl_dev_init }, + { vidioc_int_dev_exit_num, + (v4l2_int_ioctl_func *)&ioctl_dev_exit }, + { vidioc_int_s_power_num, + (v4l2_int_ioctl_func *)&ioctl_s_power }, + { vidioc_int_g_ext_clk_num, + (v4l2_int_ioctl_func *)&ioctl_g_ext_clk }, + { vidioc_int_s_ext_clk_num, + (v4l2_int_ioctl_func *)&ioctl_s_ext_clk }, + { vidioc_int_g_needs_reset_num, + (v4l2_int_ioctl_func *)&ioctl_g_needs_reset }, + { vidioc_int_reset_num, + (v4l2_int_ioctl_func *)&ioctl_reset }, + { vidioc_int_init_num, + (v4l2_int_ioctl_func *)&ioctl_init }, + { vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap }, + { vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap }, + { vidioc_int_g_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap }, + { vidioc_int_s_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap }, + { vidioc_int_g_parm_num, + (v4l2_int_ioctl_func *)&ioctl_g_parm }, + { vidioc_int_s_parm_num, + (v4l2_int_ioctl_func *)&ioctl_s_parm }, + { vidioc_int_queryctrl_num, + (v4l2_int_ioctl_func *)&ioctl_queryctrl }, + { vidioc_int_g_ctrl_num, + (v4l2_int_ioctl_func *)&ioctl_g_ctrl }, + { vidioc_int_s_ctrl_num, + (v4l2_int_ioctl_func *)&ioctl_s_ctrl }, +}; + +static struct v4l2_int_slave tcm825x_slave = { + .ioctls = tcm825x_ioctl_desc, + .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc), +}; + +static struct tcm825x_sensor tcm825x; + +static struct v4l2_int_device tcm825x_int_device = { + .module = THIS_MODULE, + .name = TCM825X_NAME, + .priv = &tcm825x, + .type = v4l2_int_type_slave, + .u = { + .slave = &tcm825x_slave, + }, +}; + +static int tcm825x_probe(struct i2c_client *client) +{ + struct tcm825x_sensor *sensor = &tcm825x; + int rval; + + if (i2c_get_clientdata(client)) + return -EBUSY; + + sensor->platform_data = client->dev.platform_data; + + if (sensor->platform_data == NULL + && !sensor->platform_data->is_okay()) + return -ENODEV; + + sensor->v4l2_int_device = &tcm825x_int_device; + + sensor->i2c_client = client; + i2c_set_clientdata(client, sensor); + + /* Make the default capture format QVGA RGB565 */ + sensor->pix.width = tcm825x_sizes[QVGA].width; + sensor->pix.height = tcm825x_sizes[QVGA].height; + sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565; + + rval = v4l2_int_device_register(sensor->v4l2_int_device); + if (rval) + i2c_set_clientdata(client, NULL); + + return rval; +} + +static int __exit tcm825x_remove(struct i2c_client *client) +{ + struct tcm825x_sensor *sensor = i2c_get_clientdata(client); + + if (!client->adapter) + return -ENODEV; /* our client isn't attached */ + + v4l2_int_device_unregister(sensor->v4l2_int_device); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static struct i2c_driver tcm825x_i2c_driver = { + .driver = { + .name = TCM825X_NAME, + }, + .probe = &tcm825x_probe, + .remove = __exit_p(&tcm825x_remove), +}; + +static struct tcm825x_sensor tcm825x = { + .timeperframe = { + .numerator = 1, + .denominator = DEFAULT_FPS, + }, +}; + +static int __init tcm825x_init(void) +{ + int rval; + int i = 0; + + /* Just an experiment --- don't use *_cb functions yet. */ + tcm825x_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init); + BUG_ON(i >= NUM_IOCTLS); + + rval = i2c_add_driver(&tcm825x_i2c_driver); + if (rval) + printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n", + __FUNCTION__); + + return rval; +} + +static void __exit tcm825x_exit(void) +{ + i2c_del_driver(&tcm825x_i2c_driver); +} + +/* + * FIXME: Menelaus isn't ready (?) at module_init stage, so use + * late_initcall for now. + */ +late_initcall(tcm825x_init); +module_exit(tcm825x_exit); + +MODULE_AUTHOR("Sakari Ailus "); +MODULE_DESCRIPTION("TCM825x camera sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h new file mode 100644 index 000000000000..d6471ec40bc5 --- /dev/null +++ b/drivers/media/video/tcm825x.h @@ -0,0 +1,195 @@ +/* + * drivers/media/video/tcm825x.h + * + * Register definitions for the TCM825X CameraChip. + * + * Author: David Cohen (david.cohen@indt.org.br) + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * This file was based on ov9640.h from MontaVista + */ + +#ifndef TCM825X_H +#define TCM825X_H + +#include + +#include + +#define TCM825X_NAME "tcm825x" + +#define TCM825X_MASK(x) x & 0x00ff +#define TCM825X_ADDR(x) (x & 0xff00) >> 8 + +/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */ +#define TCM825X_I2C_ADDR 0x3d + +/* + * define register offsets for the TCM825X sensor chip + * OFFSET(8 bits) + MASK(8 bits) + * MASK bit 4 and 3 are used when the register uses more than one address + */ +#define TCM825X_FPS 0x0280 +#define TCM825X_ACF 0x0240 +#define TCM825X_DOUTBUF 0x020C +#define TCM825X_DCLKP 0x0202 +#define TCM825X_ACFDET 0x0201 +#define TCM825X_DOUTSW 0x0380 +#define TCM825X_DATAHZ 0x0340 +#define TCM825X_PICSIZ 0x033c +#define TCM825X_PICFMT 0x0302 +#define TCM825X_V_INV 0x0480 +#define TCM825X_H_INV 0x0440 +#define TCM825X_ESRLSW 0x0430 +#define TCM825X_V_LENGTH 0x040F +#define TCM825X_ALCSW 0x0580 +#define TCM825X_ESRLIM 0x0560 +#define TCM825X_ESRSPD_U 0x051F +#define TCM825X_ESRSPD_L 0x06FF +#define TCM825X_AG 0x07FF +#define TCM825X_ESRSPD2 0x06FF +#define TCM825X_ALCMODE 0x0830 +#define TCM825X_ALCH 0x080F +#define TCM825X_ALCL 0x09FF +#define TCM825X_AWBSW 0x0A80 +#define TCM825X_MRG 0x0BFF +#define TCM825X_MBG 0x0CFF +#define TCM825X_GAMSW 0x0D80 +#define TCM825X_HDTG 0x0EFF +#define TCM825X_VDTG 0x0FFF +#define TCM825X_HDTCORE 0x10F0 +#define TCM825X_VDTCORE 0x100F +#define TCM825X_CONT 0x11FF +#define TCM825X_BRIGHT 0x12FF +#define TCM825X_VHUE 0x137F +#define TCM825X_UHUE 0x147F +#define TCM825X_VGAIN 0x153F +#define TCM825X_UGAIN 0x163F +#define TCM825X_UVCORE 0x170F +#define TCM825X_SATU 0x187F +#define TCM825X_MHMODE 0x1980 +#define TCM825X_MHLPFSEL 0x1940 +#define TCM825X_YMODE 0x1930 +#define TCM825X_MIXHG 0x1907 +#define TCM825X_LENS 0x1A3F +#define TCM825X_AGLIM 0x1BE0 +#define TCM825X_LENSRPOL 0x1B10 +#define TCM825X_LENSRGAIN 0x1B0F +#define TCM825X_ES100S 0x1CFF +#define TCM825X_ES120S 0x1DFF +#define TCM825X_DMASK 0x1EC0 +#define TCM825X_CODESW 0x1E20 +#define TCM825X_CODESEL 0x1E10 +#define TCM825X_TESPIC 0x1E04 +#define TCM825X_PICSEL 0x1E03 +#define TCM825X_HNUM 0x20FF +#define TCM825X_VOUTPH 0x287F +#define TCM825X_ESROUT 0x327F +#define TCM825X_ESROUT2 0x33FF +#define TCM825X_AGOUT 0x34FF +#define TCM825X_DGOUT 0x353F +#define TCM825X_AGSLOW1 0x39C0 +#define TCM825X_FLLSMODE 0x3930 +#define TCM825X_FLLSLIM 0x390F +#define TCM825X_DETSEL 0x3AF0 +#define TCM825X_ACDETNC 0x3A0F +#define TCM825X_AGSLOW2 0x3BC0 +#define TCM825X_DG 0x3B3F +#define TCM825X_REJHLEV 0x3CFF +#define TCM825X_ALCLOCK 0x3D80 +#define TCM825X_FPSLNKSW 0x3D40 +#define TCM825X_ALCSPD 0x3D30 +#define TCM825X_REJH 0x3D03 +#define TCM825X_SHESRSW 0x3E80 +#define TCM825X_ESLIMSEL 0x3E40 +#define TCM825X_SHESRSPD 0x3E30 +#define TCM825X_ELSTEP 0x3E0C +#define TCM825X_ELSTART 0x3E03 +#define TCM825X_AGMIN 0x3FFF +#define TCM825X_PREGRG 0x423F +#define TCM825X_PREGBG 0x433F +#define TCM825X_PRERG 0x443F +#define TCM825X_PREBG 0x453F +#define TCM825X_MSKBR 0x477F +#define TCM825X_MSKGR 0x487F +#define TCM825X_MSKRB 0x497F +#define TCM825X_MSKGB 0x4A7F +#define TCM825X_MSKRG 0x4B7F +#define TCM825X_MSKBG 0x4C7F +#define TCM825X_HDTCSW 0x4D80 +#define TCM825X_VDTCSW 0x4D40 +#define TCM825X_DTCYL 0x4D3F +#define TCM825X_HDTPSW 0x4E80 +#define TCM825X_VDTPSW 0x4E40 +#define TCM825X_DTCGAIN 0x4E3F +#define TCM825X_DTLLIMSW 0x4F10 +#define TCM825X_DTLYLIM 0x4F0F +#define TCM825X_YLCUTLMSK 0x5080 +#define TCM825X_YLCUTL 0x503F +#define TCM825X_YLCUTHMSK 0x5180 +#define TCM825X_YLCUTH 0x513F +#define TCM825X_UVSKNC 0x527F +#define TCM825X_UVLJ 0x537F +#define TCM825X_WBGMIN 0x54FF +#define TCM825X_WBGMAX 0x55FF +#define TCM825X_WBSPDUP 0x5603 +#define TCM825X_ALLAREA 0x5820 +#define TCM825X_WBLOCK 0x5810 +#define TCM825X_WB2SP 0x580F +#define TCM825X_KIZUSW 0x5920 +#define TCM825X_PBRSW 0x5910 +#define TCM825X_ABCSW 0x5903 +#define TCM825X_PBDLV 0x5AFF +#define TCM825X_PBC1LV 0x5BFF + +#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1) + +#define TCM825X_BYTES_PER_PIXEL 2 + +#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */ +#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */ + +/* define a structure for tcm825x register initialization values */ +struct tcm825x_reg { + u8 val; + u16 reg; +}; + +enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA }; +enum pixel_format { YUV422 = 0, RGB565 }; +#define NUM_IMAGE_SIZES 6 +#define NUM_PIXEL_FORMATS 2 + +struct capture_size { + unsigned long width; + unsigned long height; +}; + +struct tcm825x_platform_data { + /* Is the sensor usable? Doesn't yet mean it's there, but you + * can try! */ + int (*is_okay)(void); + /* Set power state, zero is off, non-zero is on. */ + int (*power_set)(int power); + /* Default registers written after power-on or reset. */ + const struct tcm825x_reg *(*default_regs)(void); + int (*needs_reset)(struct v4l2_int_device *s, void *buf, + struct v4l2_pix_format *fmt); +}; + +/* Array of image sizes supported by TCM825X. These must be ordered from + * smallest image size to largest. + */ +const static struct capture_size tcm825x_sizes[] = { + { 128, 96 }, /* subQCIF */ + { 160, 120 }, /* QQVGA */ + { 176, 144 }, /* QCIF */ + { 320, 240 }, /* QVGA */ + { 352, 288 }, /* CIF */ + { 640, 480 }, /* VGA */ +}; + +#endif /* ifndef TCM825X_H */ From baa05e4b454fa7d87f9a41a4bbc1f749c113ff3a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:26:34 -0300 Subject: [PATCH 0516/2804] V4L/DVB (5881): ivtv: init channel for NTSC_M_JP standard. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index d73d433a4ff6..622af634104e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1154,8 +1154,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev, vf.tuner = 0; vf.type = V4L2_TUNER_ANALOG_TV; vf.frequency = 6400; /* the tuner 'baseline' frequency */ - if (itv->std & V4L2_STD_NTSC_M) { - /* Why on earth? */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (itv->std == V4L2_STD_NTSC_M_JP) { + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + } + else if (itv->std & V4L2_STD_NTSC_M) { vf.frequency = 1076; /* ch. 4 67250*16/1000 */ } From 63116febb9233743279a05be510ab8524f5f6242 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 20 Jul 2007 13:12:51 -0300 Subject: [PATCH 0517/2804] V4L/DVB (5883): V4L: Fix a compile warning on non-32-bit machines. Fix a compile warning on non-32-bit machines in v4l2-int-device.h. Add internal ioctl interface fallback function for ioctls with one argument. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 28 ++++++++++++++++++--------- include/media/v4l2-int-device.h | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 7885d9b38c92..aa2a8156338d 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -115,13 +115,9 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d) mutex_unlock(&mutex); } -static int no_such_ioctl(struct v4l2_int_device *d) -{ - return -EINVAL; -} - /* Adapted from search_extable in extable.c. */ -static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) +static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, + v4l2_int_ioctl_func *no_such_ioctl) { const struct v4l2_int_ioctl_desc *first = slave->ioctls; const struct v4l2_int_ioctl_desc *last = @@ -140,15 +136,29 @@ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) return mid->func; } - return &no_such_ioctl; + return no_such_ioctl; +} + +static int no_such_ioctl_0(struct v4l2_int_device *d) +{ + return -EINVAL; } int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) { - return ((v4l2_int_ioctl_func_0 *)find_ioctl(d->u.slave, cmd))(d); + return ((v4l2_int_ioctl_func_0 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)&no_such_ioctl_0))(d); +} + +static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) +{ + return -EINVAL; } int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) { - return ((v4l2_int_ioctl_func_1 *)find_ioctl(d->u.slave, cmd))(d, arg); + return ((v4l2_int_ioctl_func_1 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)&no_such_ioctl_1))(d, arg); } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 2b6fc1122f6c..deb28ce6685d 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -170,7 +170,7 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); arg_type asterisk arg) \ { \ return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ - (void *)arg); \ + (void *)(unsigned long)arg); \ } \ \ static inline struct v4l2_int_ioctl_desc \ From 18b548ca580838a2cc5813a941e6dab28660bb22 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 17 Jul 2007 18:29:41 -0300 Subject: [PATCH 0518/2804] V4L/DVB (5884): zr36067: clean up debug function Debugging cleanups to the zr36067 driver: * Use module_param_named() to declare the debug parameter, so we can use a single global variable to handle the debug level. This makes the driver a bit smaller (by 648 bytes on x86_64), thanks to one less level of indirection on every use. * Change the debug parameter sysfs permissions, so that the debug level can be adjusted at runtime, as is done in many other media/video drivers. * The debug level is between 0 and 5, not 0 and 4. * Move the zr_debug export and dprintk macro definition to a header file so that we don't have to define them in each source file. * Simplify a duplicate test on zr_debug. Note that zr_debug was subsequently renamed to debug_zr36067 to avoid possible conflicts with other Zoran device drivers, on a suggestion by Trent Piepho. Signed-off-by: Jean Delvare Signed-off-by: Trent Piepho Acked-by: Ronald S. Bultje Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 19 ++++++------------- drivers/media/video/zoran_card.h | 8 ++++++++ drivers/media/video/zoran_device.c | 17 +++++------------ drivers/media/video/zoran_driver.c | 20 +++++--------------- drivers/media/video/zoran_procfs.c | 9 +-------- 5 files changed, 25 insertions(+), 48 deletions(-) diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 73162a3a61dd..8e12ff80550d 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -145,10 +145,9 @@ module_param(pass_through, int, 0); MODULE_PARM_DESC(pass_through, "Pass TV signal through to TV-out when idling"); -static int debug = 1; -int *zr_debug = &debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); +int zr36067_debug = 1; +module_param_named(debug, zr36067_debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-5)"); MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); MODULE_AUTHOR("Serguei Miridonov"); @@ -161,12 +160,6 @@ static struct pci_device_id zr36067_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - int zoran_num; /* number of Buzs in use */ struct zoran zoran[BUZ_MAX]; @@ -1075,7 +1068,7 @@ test_interrupts (struct zoran *zr) if (timeout) { dprintk(1, ": time spent: %d\n", 1 * HZ - timeout); } - if (*zr_debug > 1) + if (zr36067_debug > 1) print_interrupts(zr); btwrite(icr, ZR36057_ICR); } @@ -1158,7 +1151,7 @@ zr36057_init (struct zoran *zr) goto exit_unregister; zoran_init_hardware(zr); - if (*zr_debug > 2) + if (zr36067_debug > 2) detect_guest_activity(zr); test_interrupts(zr); if (!pass_through) { @@ -1620,7 +1613,7 @@ init_dc10_cards (void) } /* random nonsense */ - dprintk(5, KERN_DEBUG "Jotti is een held!\n"); + dprintk(6, KERN_DEBUG "Jotti is een held!\n"); /* some mainboards might not do PCI-PCI data transfer well */ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) { diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h index ad997c30bee5..8444ca0a5f3f 100644 --- a/drivers/media/video/zoran_card.h +++ b/drivers/media/video/zoran_card.h @@ -30,6 +30,14 @@ #ifndef __ZORAN_CARD_H__ #define __ZORAN_CARD_H__ +extern int zr36067_debug; + +#define dprintk(num, format, args...) \ + do { \ + if (zr36067_debug >= num) \ + printk(format, ##args); \ + } while (0) + /* Anybody who uses more than four? */ #define BUZ_MAX 4 extern int zoran_num; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index ba2f4ed29483..dc1ec20fb266 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -52,6 +52,7 @@ #include "videocodec.h" #include "zoran.h" #include "zoran_device.h" +#include "zoran_card.h" #define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \ ZR36057_ISR_GIRQ1 | \ @@ -59,14 +60,6 @@ extern const struct zoran_format zoran_formats[]; -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - static int lml33dpath = 0; /* 1 will use digital path in capture * mode instead of analog. It can be * used for picture adjustments using @@ -174,7 +167,7 @@ post_office_read (struct zoran *zr, static void dump_guests (struct zoran *zr) { - if (*zr_debug > 2) { + if (zr36067_debug > 2) { int i, guest[8]; for (i = 1; i < 8; i++) { // Don't read jpeg codec here @@ -1271,7 +1264,7 @@ error_handler (struct zoran *zr, zr->num_errors++; /* Report error */ - if (*zr_debug > 1 && zr->num_errors <= 8) { + if (zr36067_debug > 1 && zr->num_errors <= 8) { long frame; frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; @@ -1531,7 +1524,7 @@ zoran_irq (int irq, if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - if (*zr_debug > 1 && + if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) { printk(KERN_INFO "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n", @@ -1568,7 +1561,7 @@ zoran_irq (int irq, zr->JPEG_missed; } - if (*zr_debug > 2 && zr->frame_num < 6) { + if (zr36067_debug > 2 && zr->frame_num < 6) { int i; printk("%s: seq=%ld stat_com:", ZR_DEVNAME(zr), zr->jpg_seq_num); diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 72a037b75d63..377bb2d11ffd 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -200,14 +200,6 @@ const struct zoran_format zoran_formats[] = { // RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - extern int v4l_nbufs; extern int v4l_bufsize; extern int jpg_nbufs; @@ -1106,12 +1098,10 @@ jpg_sync (struct file *file, frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; /* buffer should now be in BUZ_STATE_DONE */ - if (*zr_debug > 0) - if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) - dprintk(2, - KERN_ERR - "%s: jpg_sync() - internal state error\n", - ZR_DEVNAME(zr)); + if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) + dprintk(2, + KERN_ERR "%s: jpg_sync() - internal state error\n", + ZR_DEVNAME(zr)); *bs = zr->jpg_buffers.buffer[frame].bs; bs->frame = frame; @@ -1389,7 +1379,7 @@ zoran_close (struct inode *inode, /* disable interrupts */ btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - if (*zr_debug > 1) + if (zr36067_debug > 1) print_interrupts(zr); /* Overlay off */ diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c index 446ae8d5c3df..328ed6e7ac6a 100644 --- a/drivers/media/video/zoran_procfs.c +++ b/drivers/media/video/zoran_procfs.c @@ -48,14 +48,7 @@ #include "videocodec.h" #include "zoran.h" #include "zoran_procfs.h" - -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) +#include "zoran_card.h" #ifdef CONFIG_PROC_FS struct procfs_params_zr36067 { From 60e3cac47a442fae74d3429f706350229623bcce Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 17 Jul 2007 18:29:42 -0300 Subject: [PATCH 0519/2804] V4L/DVB (5885): zr36067: Fix problems with module parameters Add permissions to all the module parameters so they can be queried and set (when possible) via sysfs. Add description for the vidmem parameter. Change the video_nr parameter to an array, so that the video number can be specified when a user has more than one card. The driver would try to give all cards the same number otherwise, which will fail for all cards after the first. The default_input option would only allow values of 0 or 1, contrary to the description. Allow values up to the number of inputs defined for the card. Add description of lock_norm's different behavior for 1 and >1. Signed-off-by: Trent Piepho Acked-by: Ronald S. Bultje Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 45 ++++++++++++++++++------------ drivers/media/video/zoran_device.c | 2 +- drivers/media/video/zoran_driver.c | 4 +-- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 8e12ff80550d..48da36a15fca 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -64,15 +64,15 @@ extern const struct zoran_format zoran_formats[]; static int card[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(card, int, NULL, 0); +module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "The type of card"); static int encoder[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(encoder, int, NULL, 0); +module_param_array(encoder, int, NULL, 0444); MODULE_PARM_DESC(encoder, "i2c TV encoder"); static int decoder[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(decoder, int, NULL, 0); +module_param_array(decoder, int, NULL, 0444); MODULE_PARM_DESC(decoder, "i2c TV decoder"); /* @@ -84,29 +84,31 @@ MODULE_PARM_DESC(decoder, "i2c TV decoder"); */ static unsigned long vidmem = 0; /* Video memory base address */ -module_param(vidmem, ulong, 0); +module_param(vidmem, ulong, 0444); +MODULE_PARM_DESC(vidmem, "Default video memory base address"); /* Default input and video norm at startup of the driver. */ -static int default_input = 0; /* 0=Composite, 1=S-Video */ -module_param(default_input, int, 0); +static unsigned int default_input = 0; /* 0=Composite, 1=S-Video */ +module_param(default_input, uint, 0444); MODULE_PARM_DESC(default_input, "Default input (0=Composite, 1=S-Video, 2=Internal)"); static int default_mux = 1; /* 6 Eyes input selection */ -module_param(default_mux, int, 0); +module_param(default_mux, int, 0644); MODULE_PARM_DESC(default_mux, "Default 6 Eyes mux setting (Input selection)"); static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */ -module_param(default_norm, int, 0); +module_param(default_norm, int, 0444); MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)"); -static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, "video device number"); +/* /dev/videoN, -1 for autodetect */ +static int video_nr[BUZ_MAX] = {-1, -1, -1, -1}; +module_param_array(video_nr, int, NULL, 0444); +MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)"); /* Number and size of grab buffers for Video 4 Linux @@ -127,21 +129,21 @@ MODULE_PARM_DESC(video_nr, "video device number"); int v4l_nbufs = 2; int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ -module_param(v4l_nbufs, int, 0); +module_param(v4l_nbufs, int, 0644); MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use"); -module_param(v4l_bufsize, int, 0); +module_param(v4l_bufsize, int, 0644); MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)"); int jpg_nbufs = 32; int jpg_bufsize = 512; /* max size for 100% quality full-PAL frame */ -module_param(jpg_nbufs, int, 0); +module_param(jpg_nbufs, int, 0644); MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use"); -module_param(jpg_bufsize, int, 0); +module_param(jpg_bufsize, int, 0644); MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)"); int pass_through = 0; /* 1=Pass through TV signal when device is not used */ /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ -module_param(pass_through, int, 0); +module_param(pass_through, int, 0644); MODULE_PARM_DESC(pass_through, "Pass TV signal through to TV-out when idling"); @@ -1114,7 +1116,14 @@ zr36057_init (struct zoran *zr) zr->timing = zr->card.tvn[zr->norm]; } - zr->input = default_input = (default_input ? 1 : 0); + if (default_input > zr->card.inputs-1) { + dprintk(1, + KERN_WARNING + "%s: default_input value %d out of range (0-%d)\n", + ZR_DEVNAME(zr), default_input, zr->card.inputs-1); + default_input = 0; + } + zr->input = default_input; /* Should the following be reset at every open ? */ zr->hue = 32768; @@ -1146,7 +1155,7 @@ zr36057_init (struct zoran *zr) */ memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template)); strcpy(zr->video_dev->name, ZR_DEVNAME(zr)); - err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr); + err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]); if (err < 0) goto exit_unregister; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index dc1ec20fb266..68c7c505587e 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -69,7 +69,7 @@ static int lml33dpath = 0; /* 1 will use digital path in capture * load on Bt819 input, there will be * some image imperfections */ -module_param(lml33dpath, bool, 0); +module_param(lml33dpath, bool, 0644); MODULE_PARM_DESC(lml33dpath, "Use digital path capture mode (on LML33 cards)"); diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 377bb2d11ffd..4dbe2d449b50 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -207,8 +207,8 @@ extern int jpg_bufsize; extern int pass_through; static int lock_norm = 0; /* 1=Don't change TV standard (norm) */ -module_param(lock_norm, int, 0); -MODULE_PARM_DESC(lock_norm, "Users can't change norm"); +module_param(lock_norm, int, 0644); +MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)"); #ifdef CONFIG_VIDEO_V4L2 /* small helper function for calculating buffersizes for v4l2 From d3c35acf2455fe354bdd00085511bef6bd6d52f1 Mon Sep 17 00:00:00 2001 From: Rasmus Rohde Date: Sat, 21 Jul 2007 15:37:35 -0300 Subject: [PATCH 0520/2804] V4L/DVB (5897): dtt200u: add support for the Miglia TVMini USB DVB-T adapter add code for autodetection and firmware download to the Miglia TVMini USB DVB-T adapter. After firmware download, the device re-registers using the WT220U_ZL0353_WARM usb id. Signed-off-by: Rasmus Rohde Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dtt200u.c | 28 ++++++++++++++++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 7dbe14321019..d86cf9bee91c 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -1,5 +1,5 @@ /* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan DVB-T USB2.0 receiver. + * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * @@ -96,6 +96,7 @@ static struct dvb_usb_device_properties dtt200u_properties; static struct dvb_usb_device_properties wt220u_fc_properties; static struct dvb_usb_device_properties wt220u_properties; static struct dvb_usb_device_properties wt220u_zl0353_properties; +static struct dvb_usb_device_properties wt220u_miglia_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -103,7 +104,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf, if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0) + dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0) return 0; return -ENODEV; @@ -119,6 +121,7 @@ static struct usb_device_id dtt200u_usb_table [] = { { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, + { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -303,6 +306,25 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { } }; +static struct dvb_usb_device_properties wt220u_miglia_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-miglia-01.fw", + + .num_adapters = 1, + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Miglia)", + .cold_ids = { &dtt200u_usb_table[9], NULL }, + /* This device turns into WT220U_ZL0353_WARM when fw + has been uploaded */ + .warm_ids = { NULL }, + }, + { NULL }, + } +}; + /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { .name = "dvb_usb_dtt200u", @@ -333,6 +355,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4dfab02a8a0d..78ea3b566ffc 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -34,6 +34,7 @@ #define USB_VID_LEADTEK 0x0413 #define USB_VID_LITEON 0x04ca #define USB_VID_MEDION 0x1660 +#define USB_VID_MIGLIA 0x18f3 #define USB_VID_MSI 0x0db0 #define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 From 32db775452818656d5fd8fd8b0f54425f5cfc177 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 09:29:43 -0300 Subject: [PATCH 0521/2804] V4L/DVB (5902): Add ivtv-fb framebuffer driver. Add the ivtv-fb framebuffer driver for cx23415 devices (currently only the Hauppauge PVR-350 cards). This makes it possible to use the On-Screen Display functionality of these cards, either for menus during MPEG playback, or as a console or X display. Signed-off-by: Kevin Thayer Signed-off-by: Chris Kennedy Signed-off-by: Hans Verkuil Signed-off-by: John P Harvey Signed-off-by: Ian Armstrong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 16 + drivers/media/video/ivtv/Makefile | 1 + drivers/media/video/ivtv/ivtv-driver.c | 15 +- drivers/media/video/ivtv/ivtv-driver.h | 26 +- drivers/media/video/ivtv/ivtv-fb.c | 1215 ++++++++++++++++++++++++ include/media/ivtv-fb.h | 35 + 6 files changed, 1283 insertions(+), 25 deletions(-) create mode 100644 drivers/media/video/ivtv/ivtv-fb.c create mode 100644 include/media/ivtv-fb.h diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index e43beb2c9cbf..399f231abb96 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -25,3 +25,19 @@ config VIDEO_IVTV To compile this driver as a module, choose M here: the module will be called ivtv. + +config VIDEO_IVTV_FB + tristate "Conexant cx23415 framebuffer support" + depends on VIDEO_IVTV && FB && EXPERIMENTAL + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This is a framebuffer driver for the Conexant cx23415 MPEG + encoder/decoder. + + This is used in the Hauppauge PVR-350 card. There is a driver + homepage at . + + To compile this driver as a module, choose M here: the + module will be called ivtv-fb. diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 7e95148fbf4f..90e2d1270561 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -5,3 +5,4 @@ ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ ivtv-vbi.o ivtv-video.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o +obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 622af634104e..81cbaf7dd51c 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -95,8 +95,14 @@ const u32 yuv_offset[4] = { /* Parameter declarations */ static int cardtype[IVTV_MAX_CARDS]; -static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; static int cardtype_c = 1; static int tuner_c = 1; @@ -1242,8 +1248,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, retval = -ENODEV; IVTV_ERR("Error %d on initialization\n", retval); + spin_lock(&ivtv_cards_lock); kfree(ivtv_cards[ivtv_cards_active]); ivtv_cards[ivtv_cards_active] = NULL; + spin_unlock(&ivtv_cards_lock); return retval; } @@ -1346,6 +1354,7 @@ static void module_cleanup(void) pci_unregister_driver(&ivtv_pci_driver); + spin_lock(&ivtv_cards_lock); for (i = 0; i < ivtv_cards_active; i++) { if (ivtv_cards[i] == NULL) continue; @@ -1354,6 +1363,7 @@ static void module_cleanup(void) } kfree(ivtv_cards[i]); } + spin_unlock(&ivtv_cards_lock); } /* Note: These symbols are exported because they are used by the ivtv-fb @@ -1361,6 +1371,7 @@ static void module_cleanup(void) EXPORT_SYMBOL(ivtv_set_irq_mask); EXPORT_SYMBOL(ivtv_cards_active); EXPORT_SYMBOL(ivtv_cards); +EXPORT_SYMBOL(ivtv_cards_lock); EXPORT_SYMBOL(ivtv_api); EXPORT_SYMBOL(ivtv_vapi); EXPORT_SYMBOL(ivtv_vapi_result); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8abb34a35816..8fe9d9c7a18e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -89,11 +89,9 @@ extern const u32 yuv_offset[4]; -/* Maximum ivtv driver instances. - Based on 6 PVR500s each with two PVR15s... - TODO: make this dynamic. I believe it is only a global in order to support - ivtv-fb. There must be a better way to do that. */ -#define IVTV_MAX_CARDS 12 +/* Maximum ivtv driver instances. Some people have a huge number of + capture cards, so set this to a high value. */ +#define IVTV_MAX_CARDS 32 /* Supported cards */ #define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ @@ -303,28 +301,10 @@ extern const u32 yuv_offset[4]; #define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) #define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_debug) \ - printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \ - } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) -#define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) -#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) - /* Standard kernel messages */ #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args) /* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ #define MPEG_FRAME_TYPE_IFRAME 1 diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c new file mode 100644 index 000000000000..8e9bd75fc2bf --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -0,0 +1,1215 @@ +/* + On Screen Display cx23415 Framebuffer driver + + This module presents the cx23415 OSD (onscreen display) framebuffer memory + as a standard Linux /dev/fb style framebuffer device. The framebuffer has + support for 8,16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + mode, there is a choice of a three color depths (12, 15 or 16 bits), but no + local alpha. The colorspace is selectable between rgb & yuv. + Depending on the TV standard configured in the ivtv module at load time, + the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. + Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) + or 59.94 (NTSC) + + Copyright (c) 2003 Matt T. Yourst + + Derived from drivers/video/vesafb.c + Portions (c) 1998 Gerd Knorr + + 2.6 kernel port: + Copyright (C) 2004 Matthias Badaire + + Copyright (C) 2004 Chris Kennedy + + Copyright (C) 2006 Ian Armstrong + + 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif + +#include "ivtv-driver.h" +#include "ivtv-queue.h" +#include "ivtv-udma.h" +#include "ivtv-irq.h" +#include "ivtv-fileops.h" +#include "ivtv-mailbox.h" +#include "ivtv-cards.h" +#include + +/* card parameters */ +static int ivtv_fb_card_id = -1; +static int ivtv_fb_debug = 0; +static int osd_laced; +static int osd_compat; +static int osd_depth; +static int osd_upper; +static int osd_left; +static int osd_yres; +static int osd_xres; + +module_param(ivtv_fb_card_id, int, 0444); +module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(osd_laced, bool, 0444); +module_param(osd_compat, bool, 0444); +module_param(osd_depth, int, 0444); +module_param(osd_upper, int, 0444); +module_param(osd_left, int, 0444); +module_param(osd_yres, int, 0444); +module_param(osd_xres, int, 0444); + +MODULE_PARM_DESC(ivtv_fb_card_id, + "Only use framebuffer of the specified ivtv card (0-31)\n" + "\t\t\tdefault -1: initialize all available framebuffers"); + +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: errors only\n" + "\t\t\t(debug = 3 gives full debugging)"); + +MODULE_PARM_DESC(osd_compat, + "Compatibility mode - Display size is locked (use for old X drivers)\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +/* Why upper, left, xres, yres, depth, laced ? To match terminology used + by fbset. + Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ + +MODULE_PARM_DESC(osd_laced, + "Interlaced mode\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +MODULE_PARM_DESC(osd_depth, + "Bits per pixel - 8,16,32\n" + "\t\t\tdefault 8"); + +MODULE_PARM_DESC(osd_upper, + "Vertical start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_left, + "Horizontal start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_yres, + "Display height\n" + "\t\t\tdefault 480 (PAL)\n" + "\t\t\t 400 (NTSC)"); + +MODULE_PARM_DESC(osd_xres, + "Display width\n" + "\t\t\tdefault 640"); + +MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); +MODULE_LICENSE("GPL"); + +/* --------------------------------------------------------------------- */ + +#define IVTV_FB_DBGFLG_WARN (1 << 0) +#define IVTV_FB_DBGFLG_INFO (1 << 1) + +#define IVTV_FB_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & ivtv_fb_debug) \ + printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + } while (0) +#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) + +/* Standard kernel messages */ +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) + +/* --------------------------------------------------------------------- */ + +#define IVTV_OSD_MAX_WIDTH 720 +#define IVTV_OSD_MAX_HEIGHT 576 + +#define IVTV_OSD_BPP_8 0x00 +#define IVTV_OSD_BPP_16_444 0x03 +#define IVTV_OSD_BPP_16_555 0x02 +#define IVTV_OSD_BPP_16_565 0x01 +#define IVTV_OSD_BPP_32 0x04 + +struct osd_info { + /* Timing info for modes */ + u32 pixclock; + u32 hlimit; + u32 vlimit; + + /* Physical base address */ + unsigned long video_pbase; + /* Relative base address (relative to start of decoder memory) */ + u32 video_rbase; + /* Mapped base address */ + volatile char __iomem *video_vbase; + /* Buffer size */ + u32 video_buffer_size; + +#ifdef CONFIG_MTRR + /* video_base rounded down as required by hardware MTRRs */ + unsigned long fb_start_aligned_physaddr; + /* video_base rounded up as required by hardware MTRRs */ + unsigned long fb_end_aligned_physaddr; +#endif + + /* Store the buffer offset */ + int set_osd_coords_x; + int set_osd_coords_y; + + /* Current dimensions (NOT VISIBLE SIZE!) */ + int display_width; + int display_height; + int display_byte_stride; + + /* Current bits per pixel */ + int bits_per_pixel; + int bytes_per_pixel; + + /* Frame buffer stuff */ + struct fb_info ivtvfb_info; + struct fb_var_screeninfo ivtvfb_defined; + struct fb_fix_screeninfo ivtvfb_fix; +}; + +struct ivtv_osd_coords { + unsigned long offset; + unsigned long max_offset; + int pixel_stride; + int lines; + int x; + int y; +}; + +/* --------------------------------------------------------------------- */ + +/* ivtv API calls for framebuffer related support */ + +static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, + u32 *fblength) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + int rc; + + rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); + *fbbase = data[0]; + *fblength = data[1]; + return rc; +} + +static int ivtv_fb_get_osd_coords(struct ivtv *itv, + struct ivtv_osd_coords *osd) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); + + osd->offset = data[0] - itv->osd_info->video_rbase; + osd->max_offset = itv->osd_info->display_width * itv->osd_info->display_height * 4; + osd->pixel_stride = data[1]; + osd->lines = data[2]; + osd->x = data[3]; + osd->y = data[4]; + return 0; +} + +static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +{ + itv->osd_info->display_width = osd->pixel_stride; + itv->osd_info->display_byte_stride = osd->pixel_stride * itv->osd_info->bytes_per_pixel; + itv->osd_info->set_osd_coords_x += osd->x; + itv->osd_info->set_osd_coords_y = osd->y; + + return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, + osd->offset + itv->osd_info->video_rbase, + osd->pixel_stride, + osd->lines, osd->x, osd->y); +} + +static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +{ + + int osd_height_limit = itv->is_50hz ? 576 : 480; + + /* Only fail if resolution too high, otherwise fudge the start coords. */ + if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) + return -EINVAL; + + /* Ensure we don't exceed display limits */ + if (ivtv_window->top + ivtv_window->height > osd_height_limit) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d,%d)\n", + ivtv_window->top, ivtv_window->height); + ivtv_window->top = osd_height_limit - ivtv_window->height; + } + + if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d,%d)\n", + ivtv_window->left, ivtv_window->width); + ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; + } + + /* Set the OSD origin */ + write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); + + /* How much to display */ + write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_vis_w = ivtv_window->width; + itv->yuv_info.osd_vis_h = ivtv_window->height; + itv->yuv_info.osd_x_offset = ivtv_window->left; + itv->yuv_info.osd_y_offset = ivtv_window->top; + + return 0; +} + +static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, + unsigned long ivtv_dest_addr, void __user *userbuf, + int size_in_bytes) +{ + DEFINE_WAIT(wait); + int ret = 0; + int got_sig = 0; + + mutex_lock(&itv->udma.lock); + /* Map User DMA */ + if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { + mutex_unlock(&itv->udma.lock); + IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + "Error with get_user_pages: %d bytes, %d pages returned\n", + size_in_bytes, itv->udma.page_count); + + /* get_user_pages must have failed completely */ + return -EIO; + } + + IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + size_in_bytes, itv->udma.page_count); + + ivtv_udma_prepare(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + /* if no UDMA is pending and no UDMA is in progress, then the DMA + is finished */ + while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { + /* don't interrupt if the DMA is in progress but break off + a still pending DMA. */ + got_sig = signal_pending(current); + if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + + /* Unmap Last DMA Xfer */ + ivtv_udma_unmap(itv); + mutex_unlock(&itv->udma.lock); + if (got_sig) { + IVTV_DEBUG_INFO("User stopped OSD\n"); + return -EINTR; + } + + return ret; +} + +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) +{ + DEFINE_WAIT(wait); + + /* Nothing to do */ + if (count == 0) { + IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + return -EINVAL; + } + + /* Check Total FB Size */ + if ((dest_offset + count) > itv->osd_info->video_buffer_size) { + IVTV_FB_WARN( + "ivtv_fb_prep_frame: Overflowing the framebuffer %ld, " + "only %d available\n", + (dest_offset + count), itv->osd_info->video_buffer_size); + return -E2BIG; + } + + /* Not fatal, but will have undesirable results */ + if ((unsigned long)source & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",(unsigned long)source); + + if (dest_offset & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n",dest_offset); + + if (count & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n",count); + + /* Check Source */ + if (!access_ok(VERIFY_READ, source + dest_offset, count)) { + IVTV_FB_WARN( + "Invalid userspace pointer!!! 0x%08lx\n", + (unsigned long)source); + + IVTV_FB_DEBUG_WARN( + "access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + dest_offset, (unsigned long)source, + count); + return -EINVAL; + } + + /* OSD Address to send DMA to */ + dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase; + + /* Fill Buffers */ + return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); +} + +static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + DEFINE_WAIT(wait); + struct ivtv *itv = (struct ivtv *)info->par; + int rc=0; + + switch (cmd) { + + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + u32 trace; + + vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + trace = read_reg (0x028c0) >> 16; + if (itv->is_50hz && trace > 312) trace -= 312; + else if (itv->is_60hz && trace > 262) trace -= 262; + if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; + vblank.count = itv->lastVsyncFrame; + vblank.vcount = trace; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + case FBIO_WAITFORVSYNC: { + prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); + if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; + finish_wait (&itv->vsync_waitq, &wait); + return rc; + } + + case IVTVFB_IOCTL_PREP_FRAME: { + struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + + IVTV_FB_DEBUG_INFO("IVTVFB_IOCTL_PREP_FRAME\n"); + if (copy_from_user(&args, (void __user *)arg, sizeof(args))) + return -EFAULT; + + return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + } + + default: + IVTV_FB_ERR("Unknown IOCTL %d\n",cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) +{ + + struct ivtv_osd_coords ivtv_osd; + struct v4l2_rect ivtv_window; + + IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + + /* Select color space */ + if (var->nonstd) /* YUV */ + write_reg (read_reg(0x02a00) | 0x0002000,0x02a00); + else /* RGB */ + write_reg (read_reg(0x02a00) & ~0x0002000,0x02a00); + + /* Set the color mode + Although rare, occasionally things go wrong. The extra mode + change seems to help... */ + + switch (var->bits_per_pixel) { + case 8: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8); + break; + case 32: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32); + break; + case 16: + switch (var->green.length) { + case 4: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444); + break; + case 5: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555); + break; + case 6: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + + itv->osd_info->bits_per_pixel = var->bits_per_pixel; + itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8; + + /* Set the flicker filter */ + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: /* Filter on */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); + break; + case FB_VMODE_INTERLACED: /* Filter off */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + } + + /* Read the current osd info */ + ivtv_fb_get_osd_coords(itv, &ivtv_osd); + + /* Now set the OSD to the size we want */ + ivtv_osd.pixel_stride = var->xres_virtual; + ivtv_osd.lines = var->yres_virtual; + ivtv_osd.x = 0; + ivtv_osd.y = 0; + ivtv_fb_set_osd_coords(itv, &ivtv_osd); + + /* Can't seem to find the right API combo for this. + Use another function which does what we need through direct register access. */ + ivtv_window.width = var->xres; + ivtv_window.height = var->yres; + + /* Minimum margin cannot be 0, as X won't allow such a mode */ + if (!var->upper_margin) var->upper_margin ++; + if (!var->left_margin) var->left_margin ++; + ivtv_window.top = var->upper_margin - 1; + ivtv_window.left = var->left_margin - 1; + + ivtv_fb_set_display_window(itv, &ivtv_window); + + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + + IVTV_FB_INFO("=== Display mode change ===\n"); + IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", + var->xres, + var->yres, + var->xres_virtual, + var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_INFO("Display position %d,%d\n", + var->left_margin, + var->upper_margin); + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + IVTV_FB_INFO("Display filter : on\n"); + } + else { + IVTV_FB_INFO("Display filter : off\n"); + } + + if (var->nonstd) { + IVTV_FB_INFO("Color space : YUV\n"); + } + else { + IVTV_FB_INFO("Color space : RGB\n"); + } + + return 0; +} + +static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) +{ + IVTV_FB_DEBUG_INFO ("ivtvfb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "cx23415 TV out"); + fix->smem_start = itv->osd_info->video_pbase; + fix->smem_len = itv->osd_info->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = (itv->osd_info->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = itv->osd_info->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) +{ + int osd_height_limit = itv->is_50hz ? 576 : 480; + + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + + /* Check the bits per pixel */ + if (osd_compat) { + if (var->bits_per_pixel != 32) { + IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + return -EINVAL; + } + } + + if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + } + else if (var->bits_per_pixel == 16) { + /* To find out the true mode, check green length */ + switch (var->green.length) { + case 4: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + break; + case 5: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + default: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + } + } + else { + IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + return -EINVAL; + } + + /* Check the resolution */ + if (osd_compat) { + if (var->xres != itv->osd_info->ivtvfb_defined.xres || var->yres != itv->osd_info->ivtvfb_defined.yres || + var->xres_virtual != itv->osd_info->ivtvfb_defined.xres_virtual || var->yres_virtual != + itv->osd_info->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d (%d x %d Virtual)\n", + var->xres,var->yres, var->xres_virtual,var->yres_virtual); + return -EINVAL; + } + } + else { + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit ) { + IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d\n", + var->xres,var->yres); + return -EINVAL; + } + + /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ + if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel/8) > itv->osd_info->video_buffer_size || + var->xres_virtual < var->xres || + var->yres_virtual < var->yres) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution: %d x %d\n", + var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + } + + /* Some extra checks if in 8 bit mode */ + if (var->bits_per_pixel == 8) { + /* Width must be a multiple of 4 */ + if (var->xres & 3) { + IVTV_FB_DEBUG_WARN ("Invalid resolution for 8bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 3) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + else if (var->bits_per_pixel == 16) { + /* Width must be a multiple of 2 */ + if (var->xres & 1) { + IVTV_FB_DEBUG_WARN ("Invalid resolution for 16bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 1) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + + /* Now check the offsets */ + if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { + IVTV_FB_DEBUG_WARN ("Invalid offset: %d (%d) %d (%d)\n",var->xoffset,var->xres_virtual, + var->yoffset,var->yres_virtual); + return -EINVAL; + } + + /* Check pixel format */ + if (var->nonstd > 1) { + IVTV_FB_DEBUG_WARN ("Invalid nonstd % d\n",var->nonstd); + return -EINVAL; + } + + /* Check video mode */ + if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && + ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { + IVTV_FB_DEBUG_WARN ("Invalid video mode: %d\n",var->vmode & FB_VMODE_MASK); + return -EINVAL; + } + + /* Check the left & upper margins + If the margins are too large, just center the screen + (enforcing margins causes too many problems) */ + + if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { + var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); + } + if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { + var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); + } + + /* Maintain overall 'size' for a constant refresh rate */ + var->right_margin = itv->osd_info->hlimit - var->left_margin - var->xres; + var->lower_margin = itv->osd_info->vlimit - var->upper_margin - var->yres; + + /* Fixed sync times */ + var->hsync_len = 24; + var->vsync_len = 2; + + /* Non-interlaced / interlaced mode is used to switch the OSD filter + on or off. Adjust the clock timings to maintain a constant + vertical refresh rate. */ + var->pixclock = itv->osd_info->pixclock; + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + var->pixclock /= 2; + + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var - Parameters validated\n"); + + IVTV_FB_INFO("=== Validated display mode ===\n"); + IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", + var->xres, + var->yres, + var->xres_virtual, + var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_INFO("Display position %d,%d\n", + var->left_margin, + var->upper_margin); + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + IVTV_FB_INFO("Display filter : on\n"); + } + else { + IVTV_FB_INFO("Display filter : off\n"); + } + + if (var->nonstd) { + IVTV_FB_INFO("Color space : YUV\n"); + } + else { + IVTV_FB_INFO("Color space : RGB\n"); + } + return 0; +} + +static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *) info->par; + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + return _ivtvfb_check_var (var,itv); +} + +static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 osd_pan_index; + struct ivtv *itv = (struct ivtv *) info->par; + + osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; + write_reg (osd_pan_index,0x02A0C); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_x_pan = var->xoffset; + itv->yuv_info.osd_y_pan = var->yoffset; + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + return 0; +} + +static int ivtvfb_set_par(struct fb_info *info) +{ + int rc = 0; + struct ivtv *itv = (struct ivtv *) info->par; + + IVTV_FB_DEBUG_INFO ("ivtvfb_set_par\n"); + + rc = ivtvfb_set_var(itv, &info->var); + ivtvfb_pan_display(&info->var, info); + ivtvfb_get_fix (itv, &info->fix); + return rc; +} + +static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + struct ivtv *itv = (struct ivtv *) info->par; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (info->var.bits_per_pixel <= 8) { + write_reg(regno, 0x02a30); + write_reg(color, 0x02a34); + } + else { + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + } + } + palette[regno] = color; + } + + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int ivtvfb_blank(int blank_mode, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *)info->par; + + IVTV_FB_DEBUG_INFO ("Set blanking mode : %d\n",blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + break; + } + return 0; +} + +static struct fb_ops ivtvfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = ivtvfb_check_var, + .fb_set_par = ivtvfb_set_par, + .fb_setcolreg = ivtvfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = ivtvfb_ioctl, + .fb_pan_display = ivtvfb_pan_display, + .fb_blank = ivtvfb_blank, +}; + +/* Initialization */ + + +/* Setup our initial video mode */ +static int ivtvfb_init_vidmode(struct ivtv *itv) +{ + int max_height; + struct v4l2_rect start_window; + + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + itv->osd_info->pixclock = 84316; + itv->osd_info->hlimit = 776; + itv->osd_info->vlimit = 591; + } + else { + itv->osd_info->pixclock = 83926; + itv->osd_info->hlimit = 776; + itv->osd_info->vlimit = 495; + } + + /* Color mode */ + + if (osd_compat) osd_depth = 32; + if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; + itv->osd_info->bits_per_pixel = osd_depth; + itv->osd_info->bytes_per_pixel = itv->osd_info->bits_per_pixel / 8; + + /* Horizontal size & position */ + + if (osd_xres > 720) osd_xres = 720; + + /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ + if (osd_depth == 8) + osd_xres &= ~3; + else if (osd_depth == 16) + osd_xres &= ~1; + + if (osd_xres) + start_window.width = osd_xres; + else + start_window.width = osd_compat ? 720: 640; + + /* Check horizontal start (osd_left). */ + if (osd_left && osd_left + start_window.width > 721) { + IVTV_FB_ERR ("Invalid osd_left - assuming default\n"); + osd_left = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_left --; + + start_window.left = + osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + + itv->osd_info->display_byte_stride = + start_window.width * itv->osd_info->bytes_per_pixel; + + /* Vertical size & position */ + + max_height = itv->is_50hz ? 576 : 480; + + if ( osd_yres > max_height) osd_yres = max_height; + + if (osd_yres) + start_window.height = osd_yres; + else { + if (itv->is_50hz) + start_window.height = osd_compat ? max_height : 480; + else + start_window.height = osd_compat ? max_height : 400; + } + + /* Check vertical start (osd_upper). */ + if (osd_upper + start_window.height > max_height + 1) { + IVTV_FB_ERR ("Invalid osd_upper - assuming default\n"); + osd_upper = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_upper --; + + start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); + + itv->osd_info->display_width = start_window.width; + itv->osd_info->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + itv->osd_info->ivtvfb_defined.xres = itv->osd_info->display_width; + itv->osd_info->ivtvfb_defined.yres = itv->osd_info->display_height; + itv->osd_info->ivtvfb_defined.xres_virtual = itv->osd_info->display_width; + itv->osd_info->ivtvfb_defined.yres_virtual = itv->osd_info->display_height; + itv->osd_info->ivtvfb_defined.bits_per_pixel = itv->osd_info->bits_per_pixel; + itv->osd_info->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + itv->osd_info->ivtvfb_defined.left_margin = start_window.left + 1; + itv->osd_info->ivtvfb_defined.upper_margin = start_window.top + 1; + itv->osd_info->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + itv->osd_info->ivtvfb_defined.nonstd = 0; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _ivtvfb_check_var (&itv->osd_info->ivtvfb_defined,itv); + + /* Generate valid fb_fix_screeninfo */ + + ivtvfb_get_fix(itv,&itv->osd_info->ivtvfb_fix); + + /* Generate valid fb_info */ + + itv->osd_info->ivtvfb_info.node = -1; + itv->osd_info->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + itv->osd_info->ivtvfb_info.par = itv; + itv->osd_info->ivtvfb_info.var = itv->osd_info->ivtvfb_defined; + itv->osd_info->ivtvfb_info.fix = itv->osd_info->ivtvfb_fix; + itv->osd_info->ivtvfb_info.screen_base = (u8 __iomem *)itv->osd_info->video_vbase; + itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + itv->osd_info->ivtvfb_info.monspecs.hfmin = 8000; + itv->osd_info->ivtvfb_info.monspecs.hfmax = 70000; + itv->osd_info->ivtvfb_info.monspecs.vfmin = 10; + itv->osd_info->ivtvfb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&itv->osd_info->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR ("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + itv->osd_info->ivtvfb_info.pseudo_palette = kmalloc(sizeof (u32) * 16, GFP_KERNEL); + + if (!itv->osd_info->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR ("abort, unable to alloc pseudo pallete\n"); + return -ENOMEM; + } + + return 0; +} + +/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ + +static int ivtvfb_init_io(struct ivtv *itv) +{ + ivtv_fb_get_framebuffer(itv, &itv->osd_info->video_rbase, &itv->osd_info->video_buffer_size); + + /* The osd buffer size depends on the number of video buffers allocated + on the PVR350 itself. For now we'll hardcode the smallest osd buffer + size to prevent any overlap. */ + itv->osd_info->video_buffer_size = 1704960; + + itv->osd_info->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; + itv->osd_info->video_vbase = itv->dec_mem + itv->osd_info->video_rbase; + + if (!itv->osd_info->video_vbase) { + IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + itv->osd_info->video_buffer_size, itv->osd_info->video_pbase); + return -EIO; + } + + IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + itv->osd_info->video_pbase, itv->osd_info->video_vbase, + itv->osd_info->video_buffer_size / 1024); + +#ifdef CONFIG_MTRR + { + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; + + while (!(itv->osd_info->video_buffer_size & (1 << size_shift))) { + size_shift--; + } + size_shift++; + itv->osd_info->fb_start_aligned_physaddr = itv->osd_info->video_pbase & ~((1 << size_shift) - 1); + itv->osd_info->fb_end_aligned_physaddr = itv->osd_info->video_pbase + itv->osd_info->video_buffer_size; + itv->osd_info->fb_end_aligned_physaddr += (1 << size_shift) - 1; + itv->osd_info->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(itv->osd_info->fb_start_aligned_physaddr, + itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr, + MTRR_TYPE_WRCOMB, 1) < 0) { + IVTV_FB_ERR("warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n", + (unsigned int)itv->osd_info->fb_start_aligned_physaddr, + (unsigned int)itv->osd_info->fb_end_aligned_physaddr); + } + } +#endif /* CONFIG_MTRR */ + + /* Blank the entire osd. */ + memset_io(itv->osd_info->video_vbase, 0, itv->osd_info->video_buffer_size); + + return 0; +} + +/* Release any memory we've grabbed & remove mtrr entry */ +static void ivtvfb_release_buffers (struct ivtv *itv) +{ + /* Release cmap */ + if (itv->osd_info->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&itv->osd_info->ivtvfb_info.cmap); + + /* Release pseudo palette */ + if (itv->osd_info->ivtvfb_info.pseudo_palette) + kfree(itv->osd_info->ivtvfb_info.pseudo_palette); + +#ifdef CONFIG_MTRR + mtrr_del(-1, itv->osd_info->fb_start_aligned_physaddr, + (itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr)); +#endif /* CONFIG_MTRR */ + + kfree(itv->osd_info); + itv->osd_info = NULL; +} + +/* Initialize the specified card */ + +static int ivtvfb_init_card (struct ivtv *itv) +{ + int rc; + + if (itv->osd_info) { + IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + return -EBUSY; + } + + itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); + if (itv->osd_info == 0) { + IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + return -ENOMEM; + } + + /* Find & setup the OSD buffer */ + if ((rc = ivtvfb_init_io (itv))) + return rc; + + /* Set the startup video mode information */ + if ((rc = ivtvfb_init_vidmode (itv))) { + ivtvfb_release_buffers(itv); + return rc; + } + + /* Register the framebuffer */ + if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { + ivtvfb_release_buffers(itv); + return -EINVAL; + } + + itv->osd_video_pbase = itv->osd_info->video_pbase; + + /* Set the card to the requested mode */ + ivtvfb_set_par(&itv->osd_info->ivtvfb_info); + + /* Set color 0 to black */ + write_reg(0, 0x02a30); + write_reg(0, 0x02a34); + + /* Enable the osd */ + ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); + + /* Note if we're running in compatibility mode */ + if (osd_compat) + IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + + /* Allocate DMA */ + ivtv_udma_alloc(itv); + return 0; + +} + +static int __init ivtvfb_init(void) +{ + struct ivtv *itv; + int i, registered = 0; + + if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + IVTV_MAX_CARDS - 1); + return -EINVAL; + } + + /* Locate & initialise all cards supporting an OSD. */ + for (i = 0; i < ivtv_cards_active; i++) { + if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + continue; + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (ivtvfb_init_card(itv) == 0) { + IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + registered++; + } + } + } + if (!registered) { + printk(KERN_ERR "ivtv-fb: no cards found"); + return -ENODEV; + } + return 0; +} + +static void ivtvfb_cleanup(void) +{ + struct ivtv *itv; + int i; + + printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + + for (i = 0; i < ivtv_cards_active; i++) { + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { + IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); + unregister_framebuffer(&itv->osd_info->ivtvfb_info); + ivtvfb_release_buffers(itv); + itv->osd_video_pbase = 0; + } + } +} + +module_init(ivtvfb_init); +module_exit(ivtvfb_cleanup); diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h new file mode 100644 index 000000000000..902b2f3d3cb6 --- /dev/null +++ b/include/media/ivtv-fb.h @@ -0,0 +1,35 @@ +/* + On Screen Display cx23415 Framebuffer driver + + Copyright (C) 2006 Ian Armstrong + + 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 + */ + +#ifndef _LINUX_IVTV_FB_H +#define _LINUX_IVTV_FB_H + +/* Framebuffer external API */ + +struct ivtvfb_ioctl_dma_host_to_ivtv_args { + void __user *source; + unsigned long dest_offset; + int count; +}; + +/* Framebuffer ioctls should use the range 1 - 28 */ +#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) + +#endif From be383bd312c4defab8bd4bde8c06fea5bfe0996b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 10:16:03 -0300 Subject: [PATCH 0522/2804] V4L/DVB (5904): ivtv-fb: cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 439 ++++++++++++++--------------- 1 file changed, 204 insertions(+), 235 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 8e9bd75fc2bf..01cd65328e8a 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -3,7 +3,7 @@ This module presents the cx23415 OSD (onscreen display) framebuffer memory as a standard Linux /dev/fb style framebuffer device. The framebuffer has - support for 8,16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp mode, there is a choice of a three color depths (12, 15 or 16 bits), but no local alpha. The colorspace is selectable between rgb & yuv. Depending on the TV standard configured in the ivtv module at load time, @@ -111,7 +111,7 @@ MODULE_PARM_DESC(osd_laced, "\t\t\tdefault off"); MODULE_PARM_DESC(osd_depth, - "Bits per pixel - 8,16,32\n" + "Bits per pixel - 8, 16, 32\n" "\t\t\tdefault 8"); MODULE_PARM_DESC(osd_upper, @@ -232,12 +232,13 @@ static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, static int ivtv_fb_get_osd_coords(struct ivtv *itv, struct ivtv_osd_coords *osd) { + struct osd_info *oi = itv->osd_info; u32 data[CX2341X_MBOX_MAX_DATA]; ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); - osd->offset = data[0] - itv->osd_info->video_rbase; - osd->max_offset = itv->osd_info->display_width * itv->osd_info->display_height * 4; + osd->offset = data[0] - oi->video_rbase; + osd->max_offset = oi->display_width * oi->display_height * 4; osd->pixel_stride = data[1]; osd->lines = data[2]; osd->x = data[3]; @@ -247,20 +248,21 @@ static int ivtv_fb_get_osd_coords(struct ivtv *itv, static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) { - itv->osd_info->display_width = osd->pixel_stride; - itv->osd_info->display_byte_stride = osd->pixel_stride * itv->osd_info->bytes_per_pixel; - itv->osd_info->set_osd_coords_x += osd->x; - itv->osd_info->set_osd_coords_y = osd->y; + struct osd_info *oi = itv->osd_info; + + oi->display_width = osd->pixel_stride; + oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; + oi->set_osd_coords_x += osd->x; + oi->set_osd_coords_y = osd->y; return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, - osd->offset + itv->osd_info->video_rbase, + osd->offset + oi->video_rbase, osd->pixel_stride, osd->lines, osd->x, osd->y); } static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) { - int osd_height_limit = itv->is_50hz ? 576 : 480; /* Only fail if resolution too high, otherwise fudge the start coords. */ @@ -269,13 +271,13 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w /* Ensure we don't exceed display limits */ if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d,%d)\n", + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", ivtv_window->top, ivtv_window->height); ivtv_window->top = osd_height_limit - ivtv_window->height; } if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d,%d)\n", + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", ivtv_window->left, ivtv_window->width); ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; } @@ -344,7 +346,8 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return ret; } -static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, + unsigned long dest_offset, int count) { DEFINE_WAIT(wait); @@ -356,31 +359,28 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, un /* Check Total FB Size */ if ((dest_offset + count) > itv->osd_info->video_buffer_size) { - IVTV_FB_WARN( - "ivtv_fb_prep_frame: Overflowing the framebuffer %ld, " - "only %d available\n", - (dest_offset + count), itv->osd_info->video_buffer_size); + IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + dest_offset + count, itv->osd_info->video_buffer_size); return -E2BIG; } /* Not fatal, but will have undesirable results */ if ((unsigned long)source & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",(unsigned long)source); + IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + (unsigned long)source); if (dest_offset & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n",dest_offset); + IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); if (count & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n",count); + IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); /* Check Source */ if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTV_FB_WARN( - "Invalid userspace pointer!!! 0x%08lx\n", + IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", (unsigned long)source); - IVTV_FB_DEBUG_WARN( - "access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", dest_offset, (unsigned long)source, count); return -EINVAL; @@ -397,17 +397,16 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar { DEFINE_WAIT(wait); struct ivtv *itv = (struct ivtv *)info->par; - int rc=0; + int rc = 0; switch (cmd) { - case FBIOGET_VBLANK: { struct fb_vblank vblank; u32 trace; vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC; - trace = read_reg (0x028c0) >> 16; + trace = read_reg(0x028c0) >> 16; if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; @@ -419,12 +418,11 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar return 0; } - case FBIO_WAITFORVSYNC: { + case FBIO_WAITFORVSYNC: prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; - finish_wait (&itv->vsync_waitq, &wait); + finish_wait(&itv->vsync_waitq, &wait); return rc; - } case IVTVFB_IOCTL_PREP_FRAME: { struct ivtvfb_ioctl_dma_host_to_ivtv_args args; @@ -437,7 +435,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar } default: - IVTV_FB_ERR("Unknown IOCTL %d\n",cmd); + IVTV_FB_ERR("Unknown IOCTL %d\n", cmd); return -EINVAL; } return 0; @@ -447,7 +445,6 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) { - struct ivtv_osd_coords ivtv_osd; struct v4l2_rect ivtv_window; @@ -455,9 +452,9 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) /* Select color space */ if (var->nonstd) /* YUV */ - write_reg (read_reg(0x02a00) | 0x0002000,0x02a00); + write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); else /* RGB */ - write_reg (read_reg(0x02a00) & ~0x0002000,0x02a00); + write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); /* Set the color mode Although rare, occasionally things go wrong. The extra mode @@ -525,8 +522,8 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_window.height = var->yres; /* Minimum margin cannot be 0, as X won't allow such a mode */ - if (!var->upper_margin) var->upper_margin ++; - if (!var->left_margin) var->left_margin ++; + if (!var->upper_margin) var->upper_margin++; + if (!var->left_margin) var->left_margin++; ivtv_window.top = var->upper_margin - 1; ivtv_window.left = var->left_margin - 1; @@ -535,48 +532,36 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; - IVTV_FB_INFO("=== Display mode change ===\n"); - IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", - var->xres, - var->yres, - var->xres_virtual, - var->yres_virtual, - var->bits_per_pixel); + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); - IVTV_FB_INFO("Display position %d,%d\n", - var->left_margin, - var->upper_margin); + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { - IVTV_FB_INFO("Display filter : on\n"); - } - else { - IVTV_FB_INFO("Display filter : off\n"); - } - - if (var->nonstd) { - IVTV_FB_INFO("Color space : YUV\n"); - } - else { - IVTV_FB_INFO("Color space : RGB\n"); - } + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) { - IVTV_FB_DEBUG_INFO ("ivtvfb_get_fix\n"); + struct osd_info *oi = itv->osd_info; + + IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "cx23415 TV out"); - fix->smem_start = itv->osd_info->video_pbase; - fix->smem_len = itv->osd_info->video_buffer_size; + fix->smem_start = oi->video_pbase; + fix->smem_len = oi->video_buffer_size; fix->type = FB_TYPE_PACKED_PIXELS; - fix->visual = (itv->osd_info->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; fix->xpanstep = 1; fix->ypanstep = 1; fix->ywrapstep = 0; - fix->line_length = itv->osd_info->display_byte_stride; + fix->line_length = oi->display_byte_stride; fix->accel = FB_ACCEL_NONE; return 0; } @@ -586,14 +571,15 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) { + struct osd_info *oi = itv->osd_info; int osd_height_limit = itv->is_50hz ? 576 : 480; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { - IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } } @@ -609,11 +595,12 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 8; } else if (var->bits_per_pixel == 16) { + var->transp.offset = 0; + var->transp.length = 0; + /* To find out the true mode, check green length */ switch (var->green.length) { case 4: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 8; var->red.length = 4; var->green.offset = 4; @@ -622,8 +609,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 4; break; case 5: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 10; var->red.length = 5; var->green.offset = 5; @@ -632,8 +617,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 5; break; default: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; @@ -644,33 +627,34 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } } else { - IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } /* Check the resolution */ if (osd_compat) { - if (var->xres != itv->osd_info->ivtvfb_defined.xres || var->yres != itv->osd_info->ivtvfb_defined.yres || - var->xres_virtual != itv->osd_info->ivtvfb_defined.xres_virtual || var->yres_virtual != - itv->osd_info->ivtvfb_defined.yres_virtual) { - IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d (%d x %d Virtual)\n", - var->xres,var->yres, var->xres_virtual,var->yres_virtual); + if (var->xres != oi->ivtvfb_defined.xres || + var->yres != oi->ivtvfb_defined.yres || + var->xres_virtual != oi->ivtvfb_defined.xres_virtual || + var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", + var->xres, var->yres, var->xres_virtual, var->yres_virtual); return -EINVAL; } } else { - if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit ) { - IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d\n", - var->xres,var->yres); + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", + var->xres, var->yres); return -EINVAL; } /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || - var->xres_virtual * var->yres_virtual * (var->bits_per_pixel/8) > itv->osd_info->video_buffer_size || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || var->xres_virtual < var->xres || var->yres_virtual < var->yres) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution: %d x %d\n", + IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", var->xres_virtual, var->yres_virtual); return -EINVAL; } @@ -680,43 +664,43 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) if (var->bits_per_pixel == 8) { /* Width must be a multiple of 4 */ if (var->xres & 3) { - IVTV_FB_DEBUG_WARN ("Invalid resolution for 8bpp: %d\n", var->xres); + IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 3) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); return -EINVAL; } } else if (var->bits_per_pixel == 16) { /* Width must be a multiple of 2 */ if (var->xres & 1) { - IVTV_FB_DEBUG_WARN ("Invalid resolution for 16bpp: %d\n", var->xres); + IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 1) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); return -EINVAL; } } /* Now check the offsets */ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTV_FB_DEBUG_WARN ("Invalid offset: %d (%d) %d (%d)\n",var->xoffset,var->xres_virtual, - var->yoffset,var->yres_virtual); + IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); return -EINVAL; } /* Check pixel format */ if (var->nonstd > 1) { - IVTV_FB_DEBUG_WARN ("Invalid nonstd % d\n",var->nonstd); + IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); return -EINVAL; } /* Check video mode */ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTV_FB_DEBUG_WARN ("Invalid video mode: %d\n",var->vmode & FB_VMODE_MASK); + IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); return -EINVAL; } @@ -732,8 +716,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = itv->osd_info->hlimit - var->left_margin - var->xres; - var->lower_margin = itv->osd_info->vlimit - var->upper_margin - var->yres; + var->right_margin = oi->hlimit - var->left_margin - var->xres; + var->lower_margin = oi->vlimit - var->upper_margin - var->yres; /* Fixed sync times */ var->hsync_len = 24; @@ -742,45 +726,29 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Non-interlaced / interlaced mode is used to switch the OSD filter on or off. Adjust the clock timings to maintain a constant vertical refresh rate. */ - var->pixclock = itv->osd_info->pixclock; + var->pixclock = oi->pixclock; if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) var->pixclock /= 2; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var - Parameters validated\n"); - - IVTV_FB_INFO("=== Validated display mode ===\n"); - IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", - var->xres, - var->yres, - var->xres_virtual, - var->yres_virtual, + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_INFO("Display position %d,%d\n", - var->left_margin, - var->upper_margin); + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { - IVTV_FB_INFO("Display filter : on\n"); - } - else { - IVTV_FB_INFO("Display filter : off\n"); - } - - if (var->nonstd) { - IVTV_FB_INFO("Color space : YUV\n"); - } - else { - IVTV_FB_INFO("Color space : RGB\n"); - } + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); - return _ivtvfb_check_var (var,itv); + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + return _ivtvfb_check_var(var, itv); } static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) @@ -789,7 +757,7 @@ static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *inf struct ivtv *itv = (struct ivtv *) info->par; osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; - write_reg (osd_pan_index,0x02A0C); + write_reg(osd_pan_index, 0x02A0C); /* Pass this info back the yuv handler */ itv->yuv_info.osd_x_pan = var->xoffset; @@ -804,11 +772,11 @@ static int ivtvfb_set_par(struct fb_info *info) int rc = 0; struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO ("ivtvfb_set_par\n"); + IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); rc = ivtvfb_set_var(itv, &info->var); ivtvfb_pan_display(&info->var, info); - ivtvfb_get_fix (itv, &info->fix); + ivtvfb_get_fix(itv, &info->fix); return rc; } @@ -817,7 +785,7 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { u32 color, *palette; - struct ivtv *itv = (struct ivtv *) info->par; + struct ivtv *itv = (struct ivtv *)info->par; if (regno >= info->cmap.len) return -EINVAL; @@ -826,34 +794,32 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (info->var.bits_per_pixel <= 8) { write_reg(regno, 0x02a30); write_reg(color, 0x02a34); + return 0; } - else { - if (regno >= 16) - return -EINVAL; + if (regno >= 16) + return -EINVAL; - palette = info->pseudo_palette; - if (info->var.bits_per_pixel == 16) { - switch (info->var.green.length) { - case 4: - color = ((red & 0xf000) >> 4) | - ((green & 0xf000) >> 8) | - ((blue & 0xf000) >> 12); - break; - case 5: - color = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 6: - color = (red & 0xf800 ) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - } + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; } - palette[regno] = color; } - + palette[regno] = color; return 0; } @@ -863,7 +829,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) { struct ivtv *itv = (struct ivtv *)info->par; - IVTV_FB_DEBUG_INFO ("Set blanking mode : %d\n",blank_mode); + IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); switch (blank_mode) { case FB_BLANK_UNBLANK: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); @@ -898,27 +864,28 @@ static struct fb_ops ivtvfb_ops = { /* Setup our initial video mode */ static int ivtvfb_init_vidmode(struct ivtv *itv) { - int max_height; + struct osd_info *oi = itv->osd_info; struct v4l2_rect start_window; + int max_height; /* Set base references for mode calcs. */ if (itv->is_50hz) { - itv->osd_info->pixclock = 84316; - itv->osd_info->hlimit = 776; - itv->osd_info->vlimit = 591; + oi->pixclock = 84316; + oi->hlimit = 776; + oi->vlimit = 591; } else { - itv->osd_info->pixclock = 83926; - itv->osd_info->hlimit = 776; - itv->osd_info->vlimit = 495; + oi->pixclock = 83926; + oi->hlimit = 776; + oi->vlimit = 495; } /* Color mode */ if (osd_compat) osd_depth = 32; if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; - itv->osd_info->bits_per_pixel = osd_depth; - itv->osd_info->bytes_per_pixel = itv->osd_info->bits_per_pixel / 8; + oi->bits_per_pixel = osd_depth; + oi->bytes_per_pixel = oi->bits_per_pixel / 8; /* Horizontal size & position */ @@ -937,97 +904,93 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check horizontal start (osd_left). */ if (osd_left && osd_left + start_window.width > 721) { - IVTV_FB_ERR ("Invalid osd_left - assuming default\n"); + IVTV_FB_ERR("Invalid osd_left - assuming default\n"); osd_left = 0; } /* Hardware coords start at 0, user coords start at 1. */ - osd_left --; + osd_left--; - start_window.left = - osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); - itv->osd_info->display_byte_stride = - start_window.width * itv->osd_info->bytes_per_pixel; + oi->display_byte_stride = + start_window.width * oi->bytes_per_pixel; /* Vertical size & position */ max_height = itv->is_50hz ? 576 : 480; - if ( osd_yres > max_height) osd_yres = max_height; + if (osd_yres > max_height) + osd_yres = max_height; if (osd_yres) start_window.height = osd_yres; - else { - if (itv->is_50hz) - start_window.height = osd_compat ? max_height : 480; - else - start_window.height = osd_compat ? max_height : 400; - } + else + start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400); /* Check vertical start (osd_upper). */ if (osd_upper + start_window.height > max_height + 1) { - IVTV_FB_ERR ("Invalid osd_upper - assuming default\n"); + IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); osd_upper = 0; } /* Hardware coords start at 0, user coords start at 1. */ - osd_upper --; + osd_upper--; start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); - itv->osd_info->display_width = start_window.width; - itv->osd_info->display_height = start_window.height; + oi->display_width = start_window.width; + oi->display_height = start_window.height; /* Generate a valid fb_var_screeninfo */ - itv->osd_info->ivtvfb_defined.xres = itv->osd_info->display_width; - itv->osd_info->ivtvfb_defined.yres = itv->osd_info->display_height; - itv->osd_info->ivtvfb_defined.xres_virtual = itv->osd_info->display_width; - itv->osd_info->ivtvfb_defined.yres_virtual = itv->osd_info->display_height; - itv->osd_info->ivtvfb_defined.bits_per_pixel = itv->osd_info->bits_per_pixel; - itv->osd_info->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); - itv->osd_info->ivtvfb_defined.left_margin = start_window.left + 1; - itv->osd_info->ivtvfb_defined.upper_margin = start_window.top + 1; - itv->osd_info->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; - itv->osd_info->ivtvfb_defined.nonstd = 0; + oi->ivtvfb_defined.xres = oi->display_width; + oi->ivtvfb_defined.yres = oi->display_height; + oi->ivtvfb_defined.xres_virtual = oi->display_width; + oi->ivtvfb_defined.yres_virtual = oi->display_height; + oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; + oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + oi->ivtvfb_defined.left_margin = start_window.left + 1; + oi->ivtvfb_defined.upper_margin = start_window.top + 1; + oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + oi->ivtvfb_defined.nonstd = 0; /* We've filled in the most data, let the usual mode check routine fill in the rest. */ - _ivtvfb_check_var (&itv->osd_info->ivtvfb_defined,itv); + _ivtvfb_check_var(&oi->ivtvfb_defined, itv); /* Generate valid fb_fix_screeninfo */ - ivtvfb_get_fix(itv,&itv->osd_info->ivtvfb_fix); + ivtvfb_get_fix(itv, &oi->ivtvfb_fix); /* Generate valid fb_info */ - itv->osd_info->ivtvfb_info.node = -1; - itv->osd_info->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; - itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; - itv->osd_info->ivtvfb_info.par = itv; - itv->osd_info->ivtvfb_info.var = itv->osd_info->ivtvfb_defined; - itv->osd_info->ivtvfb_info.fix = itv->osd_info->ivtvfb_fix; - itv->osd_info->ivtvfb_info.screen_base = (u8 __iomem *)itv->osd_info->video_vbase; - itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.node = -1; + oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.par = itv; + oi->ivtvfb_info.var = oi->ivtvfb_defined; + oi->ivtvfb_info.fix = oi->ivtvfb_fix; + oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; + oi->ivtvfb_info.fbops = &ivtvfb_ops; /* Supply some monitor specs. Bogus values will do for now */ - itv->osd_info->ivtvfb_info.monspecs.hfmin = 8000; - itv->osd_info->ivtvfb_info.monspecs.hfmax = 70000; - itv->osd_info->ivtvfb_info.monspecs.vfmin = 10; - itv->osd_info->ivtvfb_info.monspecs.vfmax = 100; + oi->ivtvfb_info.monspecs.hfmin = 8000; + oi->ivtvfb_info.monspecs.hfmax = 70000; + oi->ivtvfb_info.monspecs.vfmin = 10; + oi->ivtvfb_info.monspecs.vfmax = 100; /* Allocate color map */ - if (fb_alloc_cmap(&itv->osd_info->ivtvfb_info.cmap, 256, 1)) { - IVTV_FB_ERR ("abort, unable to alloc cmap\n"); + if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR("abort, unable to alloc cmap\n"); return -ENOMEM; } /* Allocate the pseudo palette */ - itv->osd_info->ivtvfb_info.pseudo_palette = kmalloc(sizeof (u32) * 16, GFP_KERNEL); + oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); - if (!itv->osd_info->ivtvfb_info.pseudo_palette) { - IVTV_FB_ERR ("abort, unable to alloc pseudo pallete\n"); + if (!oi->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); return -ENOMEM; } @@ -1038,51 +1001,53 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) static int ivtvfb_init_io(struct ivtv *itv) { - ivtv_fb_get_framebuffer(itv, &itv->osd_info->video_rbase, &itv->osd_info->video_buffer_size); + struct osd_info *oi = itv->osd_info; + + ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer size to prevent any overlap. */ - itv->osd_info->video_buffer_size = 1704960; + oi->video_buffer_size = 1704960; - itv->osd_info->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; - itv->osd_info->video_vbase = itv->dec_mem + itv->osd_info->video_rbase; + oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; + oi->video_vbase = itv->dec_mem + oi->video_rbase; - if (!itv->osd_info->video_vbase) { + if (!oi->video_vbase) { IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", - itv->osd_info->video_buffer_size, itv->osd_info->video_pbase); + oi->video_buffer_size, oi->video_pbase); return -EIO; } IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - itv->osd_info->video_pbase, itv->osd_info->video_vbase, - itv->osd_info->video_buffer_size / 1024); + oi->video_pbase, oi->video_vbase, + oi->video_buffer_size / 1024); #ifdef CONFIG_MTRR { /* Find the largest power of two that maps the whole buffer */ int size_shift = 31; - while (!(itv->osd_info->video_buffer_size & (1 << size_shift))) { + while (!(oi->video_buffer_size & (1 << size_shift))) { size_shift--; } size_shift++; - itv->osd_info->fb_start_aligned_physaddr = itv->osd_info->video_pbase & ~((1 << size_shift) - 1); - itv->osd_info->fb_end_aligned_physaddr = itv->osd_info->video_pbase + itv->osd_info->video_buffer_size; - itv->osd_info->fb_end_aligned_physaddr += (1 << size_shift) - 1; - itv->osd_info->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); - if (mtrr_add(itv->osd_info->fb_start_aligned_physaddr, - itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr, + oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); + oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; + oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; + oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, MTRR_TYPE_WRCOMB, 1) < 0) { - IVTV_FB_ERR("warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n", - (unsigned int)itv->osd_info->fb_start_aligned_physaddr, - (unsigned int)itv->osd_info->fb_end_aligned_physaddr); + IVTV_FB_WARN("cannot use mttr\n"); + oi->fb_start_aligned_physaddr = 0; + oi->fb_end_aligned_physaddr = 0; } } -#endif /* CONFIG_MTRR */ +#endif /* Blank the entire osd. */ - memset_io(itv->osd_info->video_vbase, 0, itv->osd_info->video_buffer_size); + memset_io(oi->video_vbase, 0, oi->video_buffer_size); return 0; } @@ -1090,26 +1055,30 @@ static int ivtvfb_init_io(struct ivtv *itv) /* Release any memory we've grabbed & remove mtrr entry */ static void ivtvfb_release_buffers (struct ivtv *itv) { + struct osd_info *oi = itv->osd_info; + /* Release cmap */ - if (itv->osd_info->ivtvfb_info.cmap.len); - fb_dealloc_cmap(&itv->osd_info->ivtvfb_info.cmap); + if (oi->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); /* Release pseudo palette */ - if (itv->osd_info->ivtvfb_info.pseudo_palette) - kfree(itv->osd_info->ivtvfb_info.pseudo_palette); + if (oi->ivtvfb_info.pseudo_palette) + kfree(oi->ivtvfb_info.pseudo_palette); #ifdef CONFIG_MTRR - mtrr_del(-1, itv->osd_info->fb_start_aligned_physaddr, - (itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr)); -#endif /* CONFIG_MTRR */ + if (oi->fb_end_aligned_physaddr) { + mtrr_del(-1, oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); + } +#endif - kfree(itv->osd_info); + kfree(oi); itv->osd_info = NULL; } /* Initialize the specified card */ -static int ivtvfb_init_card (struct ivtv *itv) +static int ivtvfb_init_card(struct ivtv *itv) { int rc; @@ -1125,11 +1094,11 @@ static int ivtvfb_init_card (struct ivtv *itv) } /* Find & setup the OSD buffer */ - if ((rc = ivtvfb_init_io (itv))) + if ((rc = ivtvfb_init_io(itv))) return rc; /* Set the startup video mode information */ - if ((rc = ivtvfb_init_vidmode (itv))) { + if ((rc = ivtvfb_init_vidmode(itv))) { ivtvfb_release_buffers(itv); return rc; } From d715e766ddf4786a06abe6a841e956ad8a875963 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 10:30:32 -0300 Subject: [PATCH 0523/2804] V4L/DVB (5905): ivtv-fb: Use proper ioctl value Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 6 +++--- include/media/ivtv-fb.h | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 01cd65328e8a..55265bd5c250 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -424,10 +424,10 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar finish_wait(&itv->vsync_waitq, &wait); return rc; - case IVTVFB_IOCTL_PREP_FRAME: { - struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + case IVTVFB_IOC_DMA_FRAME: { + struct ivtvfb_dma_frame args; - IVTV_FB_DEBUG_INFO("IVTVFB_IOCTL_PREP_FRAME\n"); + IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); if (copy_from_user(&args, (void __user *)arg, sizeof(args))) return -EFAULT; diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h index 902b2f3d3cb6..3b746f5e3c9e 100644 --- a/include/media/ivtv-fb.h +++ b/include/media/ivtv-fb.h @@ -23,13 +23,12 @@ /* Framebuffer external API */ -struct ivtvfb_ioctl_dma_host_to_ivtv_args { +struct ivtvfb_dma_frame { void __user *source; unsigned long dest_offset; int count; }; -/* Framebuffer ioctls should use the range 1 - 28 */ -#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) +#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) #endif From 84149a0f70a73385ee7fbb77024544cbed4fe16d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 18:17:18 -0300 Subject: [PATCH 0524/2804] V4L/DVB (5906): ivtv-fb: replace HZ with msecs_to_jiffies Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 55265bd5c250..6f5da57299a1 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -420,7 +420,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar case FBIO_WAITFORVSYNC: prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); - if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; + if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT; finish_wait(&itv->vsync_waitq, &wait); return rc; From aaf9fa21b684509973dd593e30423fc0a6a5e7a3 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sat, 21 Jul 2007 16:43:36 -0300 Subject: [PATCH 0525/2804] V4L/DVB (5908): ivtv-fb: cleanups, prevent fw calls in some cases Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 48 ++++++++++++++++++------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 6f5da57299a1..56ce5c08bbb3 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -185,6 +185,9 @@ struct osd_info { unsigned long fb_end_aligned_physaddr; #endif + /* Current osd mode */ + int osd_mode; + /* Store the buffer offset */ int set_osd_coords_x; int set_osd_coords_y; @@ -350,6 +353,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) { DEFINE_WAIT(wait); + struct osd_info *oi = itv->osd_info; /* Nothing to do */ if (count == 0) { @@ -358,9 +362,9 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* Check Total FB Size */ - if ((dest_offset + count) > itv->osd_info->video_buffer_size) { + if ((dest_offset + count) > oi->video_buffer_size) { IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", - dest_offset + count, itv->osd_info->video_buffer_size); + dest_offset + count, oi->video_buffer_size); return -E2BIG; } @@ -387,7 +391,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* OSD Address to send DMA to */ - dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase; + dest_offset += IVTV_DEC_MEM_START + oi->video_rbase; /* Fill Buffers */ return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); @@ -445,8 +449,10 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) { + struct osd_info *oi = itv->osd_info; struct ivtv_osd_coords ivtv_osd; struct v4l2_rect ivtv_window; + int osd_mode = -1; IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); @@ -456,32 +462,24 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) else /* RGB */ write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); - /* Set the color mode - Although rare, occasionally things go wrong. The extra mode - change seems to help... */ - + /* Set the color mode */ switch (var->bits_per_pixel) { case 8: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8); + osd_mode = IVTV_OSD_BPP_8; break; case 32: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32); + osd_mode = IVTV_OSD_BPP_32; break; case 16: switch (var->green.length) { case 4: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444); + osd_mode = IVTV_OSD_BPP_16_444; break; case 5: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555); + osd_mode = IVTV_OSD_BPP_16_555; break; case 6: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565); + osd_mode = IVTV_OSD_BPP_16_565; break; default: IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); @@ -491,8 +489,17 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } - itv->osd_info->bits_per_pixel = var->bits_per_pixel; - itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8; + /* Change osd mode if needed. + Although rare, things can go wrong. The extra mode + change seems to help... */ + if (osd_mode != -1 && osd_mode != oi->osd_mode) { + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); + oi->osd_mode = osd_mode; + } + + oi->bits_per_pixel = var->bits_per_pixel; + oi->bytes_per_pixel = var->bits_per_pixel / 8; /* Set the flicker filter */ switch (var->vmode & FB_VMODE_MASK) { @@ -887,6 +894,9 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) oi->bits_per_pixel = osd_depth; oi->bytes_per_pixel = oi->bits_per_pixel / 8; + /* Invalidate current osd mode to force a mode switch later */ + oi->osd_mode = -1; + /* Horizontal size & position */ if (osd_xres > 720) osd_xres = 720; From f38a7982ad4c38dc592f7f0ac8ee155a2df19fb5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 08:39:43 -0300 Subject: [PATCH 0526/2804] V4L/DVB (5909): ivtv: update version to 1.1 to mark ivtv-fb support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 85530a3cd369..122d56105969 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -19,7 +19,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 0 +#define IVTV_DRIVER_VERSION_MINOR 1 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) From c6f95d16e0da4d909afc787a3a3dfc504be12177 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 15:44:41 -0300 Subject: [PATCH 0527/2804] V4L/DVB (5910): ivtv-fb: improve debug message Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 56ce5c08bbb3..b8ad249a0b17 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -439,7 +439,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar } default: - IVTV_FB_ERR("Unknown IOCTL %d\n", cmd); + IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); return -EINVAL; } return 0; From 915366da0c591f60cb670d89b5ff376f2ef9d8fe Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 23 Jul 2007 11:33:26 -0300 Subject: [PATCH 0528/2804] V4L/DVB (5912): Clean up duplicate includes in drivers/media/ This patch cleans up duplicate includes in drivers/media/ Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/arv.c | 1 - drivers/media/video/cx88/cx88-mpeg.c | 1 - drivers/media/video/cx88/cx88-video.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 649f52f9ad27..2666d3b76630 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index da7a6b591a67..c34158d9dcc1 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "cx88.h" diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 06b233a7b20b..41b5cb63fd2d 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "cx88.h" From 59a00adbd30ed5d3a97ac41ad9e4b040a111eea8 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 23 Jul 2007 11:34:34 -0300 Subject: [PATCH 0529/2804] V4L/DVB (5913): Clean up duplicate includes in include/media/ This patch cleans up duplicate includes in include/media/ Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-dev.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 17f8f3a2f0a3..8b79e2cf77fa 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -23,8 +23,6 @@ #include #endif -#include - #define VIDEO_MAJOR 81 /* Minor device allocation */ #define MINOR_VFL_TYPE_GRABBER_MIN 0 From 54d75ebaa02809f24a16624e32706af3bf97588e Mon Sep 17 00:00:00 2001 From: Olivier DANET Date: Wed, 25 Jul 2007 14:42:54 -0300 Subject: [PATCH 0530/2804] V4L/DVB (5914): Add initial support for Dual-DVB-T stick Add initial support for Dual-DVB-T stick based on DiB7700 and MT2266 - Microtune MT2266 driver. - Preliminary support for these dual tuner devices : - Pinnacle Dual DVB-T diversity - Terratec Cinergy DT USB XS diversity - Hauppauge Nova TD USB Signed-off-by: Olivier DANET Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + drivers/media/dvb/dvb-usb/dib0700.h | 4 +- drivers/media/dvb/dvb-usb/dib0700_core.c | 2 +- drivers/media/dvb/dvb-usb/dib0700_devices.c | 262 ++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 5 +- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dib7000p.c | 5 + drivers/media/dvb/frontends/dib7000p.h | 2 +- drivers/media/dvb/frontends/mt2266.c | 288 ++++++++++++++++++++ drivers/media/dvb/frontends/mt2266.h | 37 +++ 11 files changed, 609 insertions(+), 5 deletions(-) create mode 100644 drivers/media/dvb/frontends/mt2266.c create mode 100644 drivers/media/dvb/frontends/mt2266.h diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 40e41f2f5afe..dec03ee32e1a 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -74,6 +74,7 @@ config DVB_USB_DIB0700 select DVB_DIB7000M select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index cda3adea24fb..74ae6c24087e 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -35,12 +35,13 @@ extern int dvb_usb_dib0700_debug; struct dib0700_state { u8 channel_state; u16 mt2060_if1[2]; - + u8 rc_toggle; u8 is_dib7000pc; }; extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); +extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); extern struct i2c_algorithm dib0700_i2c_algo; @@ -50,5 +51,4 @@ extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device extern int dib0700_device_count; extern struct dvb_usb_device_properties dib0700_devices[]; extern struct usb_device_id dib0700_usb_id_table[]; - #endif diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index dddf164f269a..8a1ea114deb0 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -32,7 +32,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) } /* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ -static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) { u16 index, value; int status; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 2208757d9017..122d9d4b4baa 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -12,6 +12,7 @@ #include "dib7000m.h" #include "dib7000p.h" #include "mt2060.h" +#include "mt2266.h" static int force_lna_activation; module_param(force_lna_activation, int, 0644); @@ -96,6 +97,228 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; } +/* STK7700D: Pinnacle Dual DVB-T Diversity */ + +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config = { + BAND_UHF/* | BAND_VHF*/, + 0xE64, // setup + 2372, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 0, // wbd_ref + 0, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + 0, // agc1_pt1 + 128, // agc1_pt2 + 128, // agc1_pt3 + 128, // agc1_slope1 + 0, // agc1_slope2 + 128, // agc2_pt1 + 253, // agc2_pt2 + 81, // agc2_slope1 + 0, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + + 23, // beta_mant + 51, // beta_exp + + 0, // perform_agc_softsplit : 1 en vrai! +}; + +static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { + 60000, 30000, // internal, sampling + 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + 0, // ifreq + 20452225, // timf +}; + +static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc = &stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + }, + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc = &stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + } +}; + +static struct mt2266_config stk7700d_mt2266_config[2] = { + { .i2c_address = 0x60 + }, + { .i2c_address = 0x60 + } +}; + +static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config); + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe, tun_i2c, + &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;; +} + +#define DEFAULT_RC_INTERVAL 150 + +static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; + +int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[4]; + int i; + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + struct dib0700_state *st = d->priv; + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + i=dib0700_ctrl_rd(d,rc_request,2,key,4); + if (i<=0) { + err("stk7700d:RC Query Failed\n"); + return 0; + } + if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; + if (key[1]!=st->rc_toggle) { + for (i=0;iprops.rc_key_map_size; i++) { + if (keymap[i].custom == key[2] && keymap[i].data == key[3]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + st->rc_toggle=key[1]; + return 0; + } + } + err("stk7700d:Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + } + return 0; +} + +#define KEY_MAP_SIZE (25+48) + +struct dvb_usb_rc_key stk7700d_rc_keys[] = { + /* Key codes for the tiny Pinnacle remote*/ + { 0x07, 0x00, KEY_MUTE }, + { 0x07, 0x01, KEY_MENU }, // Pinnacle logo + { 0x07, 0x39, KEY_POWER }, + { 0x07, 0x03, KEY_VOLUMEUP }, + { 0x07, 0x09, KEY_VOLUMEDOWN }, + { 0x07, 0x06, KEY_CHANNELUP }, + { 0x07, 0x0c, KEY_CHANNELDOWN }, + { 0x07, 0x0f, KEY_1 }, + { 0x07, 0x15, KEY_2 }, + { 0x07, 0x10, KEY_3 }, + { 0x07, 0x18, KEY_4 }, + { 0x07, 0x1b, KEY_5 }, + { 0x07, 0x1e, KEY_6 }, + { 0x07, 0x11, KEY_7 }, + { 0x07, 0x21, KEY_8 }, + { 0x07, 0x12, KEY_9 }, + { 0x07, 0x27, KEY_0 }, + { 0x07, 0x24, KEY_SCREEN }, // 'Square' key + { 0x07, 0x2a, KEY_TEXT }, // 'T' key + { 0x07, 0x2d, KEY_REWIND }, + { 0x07, 0x30, KEY_PLAY }, + { 0x07, 0x33, KEY_FASTFORWARD }, + { 0x07, 0x36, KEY_RECORD }, + { 0x07, 0x3c, KEY_STOP }, + { 0x07, 0x3f, KEY_CANCEL }, // '?' key + /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ + { 0xeb, 0x01, KEY_POWER }, + { 0xeb, 0x02, KEY_1 }, + { 0xeb, 0x03, KEY_2 }, + { 0xeb, 0x04, KEY_3 }, + { 0xeb, 0x05, KEY_4 }, + { 0xeb, 0x06, KEY_5 }, + { 0xeb, 0x07, KEY_6 }, + { 0xeb, 0x08, KEY_7 }, + { 0xeb, 0x09, KEY_8 }, + { 0xeb, 0x0a, KEY_9 }, + { 0xeb, 0x0b, KEY_VIDEO }, + { 0xeb, 0x0c, KEY_0 }, + { 0xeb, 0x0d, KEY_REFRESH }, + { 0xeb, 0x0f, KEY_EPG }, + { 0xeb, 0x10, KEY_UP }, + { 0xeb, 0x11, KEY_LEFT }, + { 0xeb, 0x12, KEY_OK }, + { 0xeb, 0x13, KEY_RIGHT }, + { 0xeb, 0x14, KEY_DOWN }, + { 0xeb, 0x16, KEY_INFO }, + { 0xeb, 0x17, KEY_RED }, + { 0xeb, 0x18, KEY_GREEN }, + { 0xeb, 0x19, KEY_YELLOW }, + { 0xeb, 0x1a, KEY_BLUE }, + { 0xeb, 0x1b, KEY_CHANNELUP }, + { 0xeb, 0x1c, KEY_VOLUMEUP }, + { 0xeb, 0x1d, KEY_MUTE }, + { 0xeb, 0x1e, KEY_VOLUMEDOWN }, + { 0xeb, 0x1f, KEY_CHANNELDOWN }, + { 0xeb, 0x40, KEY_PAUSE }, + { 0xeb, 0x41, KEY_HOME }, + { 0xeb, 0x42, KEY_MENU }, /* DVD Menu */ + { 0xeb, 0x43, KEY_SUBTITLE }, + { 0xeb, 0x44, KEY_TEXT }, /* Teletext */ + { 0xeb, 0x45, KEY_DELETE }, + { 0xeb, 0x46, KEY_TV }, + { 0xeb, 0x47, KEY_DVD }, + { 0xeb, 0x48, KEY_STOP }, + { 0xeb, 0x49, KEY_VIDEO }, + { 0xeb, 0x4a, KEY_AUDIO }, /* Music */ + { 0xeb, 0x4b, KEY_SCREEN }, /* Pic */ + { 0xeb, 0x4c, KEY_PLAY }, + { 0xeb, 0x4d, KEY_BACK }, + { 0xeb, 0x4e, KEY_REWIND }, + { 0xeb, 0x4f, KEY_FASTFORWARD }, + { 0xeb, 0x54, KEY_PREVIOUS }, + { 0xeb, 0x58, KEY_RECORD }, + { 0xeb, 0x5c, KEY_NEXT } + }; + /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { BAND_UHF | BAND_VHF, // band_caps @@ -280,6 +503,9 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -372,6 +598,42 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, { + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } + }, + + .num_device_descs = 3, + .devices = { + { "Pinnacle PCTV 2000e", + { &dib0700_usb_id_table[11], NULL }, + { NULL }, + }, + { "Terratec Cinergy DT XS Diversity", + { &dib0700_usb_id_table[12], NULL }, + { NULL }, + }, + { "Haupauge Nova-TD Stick", + { &dib0700_usb_id_table[13], NULL }, + { NULL }, + }, + }, + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = stk7700d_rc_keys, + .rc_key_map_size = KEY_MAP_SIZE, + .rc_query = stk7700d_rc_query } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 78ea3b566ffc..2e38be3aa45b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -12,7 +12,7 @@ /* Vendor IDs */ #define USB_VID_ADSTECH 0x06e1 #define USB_VID_AFATECH 0x15a4 -#define USB_VID_ALCOR_MICRO 0x058f +#define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd @@ -116,8 +116,11 @@ #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 #define USB_PID_AVERMEDIA_VOLAR 0xa807 #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 +#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a +#define USB_PID_PINNACLE_PCTV2000E 0x022c #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ff448761dcef..ba70ad0c3f05 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -322,6 +322,13 @@ config DVB_TUNER_MT2060 help A driver for the silicon IF tuner MT2060 from Microtune. +config DVB_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 156b062e02c4..217265ca2849 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -40,5 +40,6 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index aece458cfe12..c24189fcbc89 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -112,6 +112,11 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) break; } + if (state->cfg.hostbus_diversity) { + ret |= dib7000p_write_word(state, 204, 1); // Diversity ? + ret |= dib7000p_write_word(state, 205, 0); // Diversity ? + } + if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5) ; diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 79465cf1aced..94829c1ed054 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -35,7 +35,7 @@ struct dib7000p_config { extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); - +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); /* TODO extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c new file mode 100644 index 000000000000..145135778bce --- /dev/null +++ b/drivers/media/dvb/frontends/mt2266.c @@ -0,0 +1,288 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mt2266.h" + +#define I2C_ADDRESS 0x60 + +#define REG_PART_REV 0 +#define REG_TUNE 1 +#define REG_BAND 6 +#define REG_BANDWIDTH 8 +#define REG_LOCK 0x12 + +#define PART_REV 0x85 + +struct mt2266_priv { + struct mt2266_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) + +// Reads a single register +static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "MT2266 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a single register +static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a set of consecutive registers +static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +// Initialisation sequences +static u8 mt2266_init1[] = { + REG_TUNE, + 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f }; + +static u8 mt2266_init2[] = { + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, + 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d }; + +static u8 mt2266_init_8mhz[] = { + REG_BANDWIDTH, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; + +static u8 mt2266_init_7mhz[] = { + REG_BANDWIDTH, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; + +static u8 mt2266_init_6mhz[] = { + REG_BANDWIDTH, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 }; + +#define FREF 30000 // Quartz oscillator 30 MHz + +static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2266_priv *priv; + int ret=0; + u32 freq; + u32 tune; + u8 lnaband; + u8 b[10]; + int i; + + priv = fe->tuner_priv; + + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + + freq = params->frequency / 1000; // Hz -> kHz + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = freq * 1000; + tune=2 * freq * (8192/16) / (FREF/16); + + if (freq <= 495000) lnaband = 0xEE; else + if (freq <= 525000) lnaband = 0xDD; else + if (freq <= 550000) lnaband = 0xCC; else + if (freq <= 580000) lnaband = 0xBB; else + if (freq <= 605000) lnaband = 0xAA; else + if (freq <= 630000) lnaband = 0x99; else + if (freq <= 655000) lnaband = 0x88; else + if (freq <= 685000) lnaband = 0x77; else + if (freq <= 710000) lnaband = 0x66; else + if (freq <= 735000) lnaband = 0x55; else + if (freq <= 765000) lnaband = 0x44; else + if (freq <= 802000) lnaband = 0x33; else + if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11; + + msleep(100); + mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz: + (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz: + mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + b[0] = REG_TUNE; + b[1] = (tune >> 8) & 0x1F; + b[2] = tune & 0xFF; + b[3] = tune >> 13; + mt2266_writeregs(priv,b,4); + + dprintk("set_parms: tune=%d band=%d\n",(int)tune,(int)lnaband); + dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); + + b[0] = 0x05; + b[1] = 0x62; + b[2] = lnaband; + mt2266_writeregs(priv,b,3); + + //Waits for pll lock or timeout + i = 0; + do { + mt2266_readreg(priv,REG_LOCK,b); + if ((b[0] & 0x40)==0x40) + break; + msleep(10); + i++; + } while (i<10); + dprintk("Lock when i=%i\n",(int)i); + return ret; +} + +static void mt2266_calibrate(struct mt2266_priv *priv) +{ + mt2266_writereg(priv,0x11,0x03); + mt2266_writereg(priv,0x11,0x01); + + mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1)); + mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2)); + + mt2266_writereg(priv,0x33,0x5e); + mt2266_writereg(priv,0x10,0x10); + mt2266_writereg(priv,0x10,0x00); + + mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + msleep(25); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); + msleep(75); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); +} + +static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2266_init(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + return 0; +} + +static int mt2266_sleep(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); + return 0; +} + +static int mt2266_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2266_tuner_ops = { + .info = { + .name = "Microtune MT2266", + .frequency_min = 470000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + .release = mt2266_release, + .init = mt2266_init, + .sleep = mt2266_sleep, + .set_params = mt2266_set_params, + .get_frequency = mt2266_get_frequency, + .get_bandwidth = mt2266_get_bandwidth +}; + +struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + struct mt2266_priv *priv = NULL; + u8 id = 0; + + priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + + if (mt2266_readreg(priv,0,&id) != 0) { + kfree(priv); + return NULL; + } + if (id != PART_REV) { + kfree(priv); + return NULL; + } + printk(KERN_INFO "MT2266: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + mt2266_calibrate(priv); + return fe; +} +EXPORT_SYMBOL(mt2266_attach); + +MODULE_AUTHOR("Olivier DANET"); +MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/dvb/frontends/mt2266.h new file mode 100644 index 000000000000..f31dd613ad37 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2266.h @@ -0,0 +1,37 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * 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. + */ + +#ifndef MT2266_H +#define MT2266_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2266_config { + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE)) +extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); +#else +static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_MT2266 + +#endif From 7bb293849489b6cc5d6919b8c7f94cb273303e1f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 09:42:09 -0300 Subject: [PATCH 0531/2804] V4L/DVB (5919): ivtv: remove dead code Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-streams.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 51df3f855031..405e2e3fcb49 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -314,15 +314,6 @@ static void ivtv_vbi_setup(struct ivtv *itv) int lines; int i; - /* If Embed then streamtype must be Program */ - /* TODO: should we really do this? */ - if (0 && !raw && itv->vbi.insert_mpeg) { - itv->params.stream_type = 0; - - /* assign stream type */ - ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type); - } - /* Reset VBI */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); From fa8a7529ba8c3c2f87dec78ad32c388695f4c1b7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 12:13:08 -0300 Subject: [PATCH 0532/2804] V4L/DVB (5921): ivtv: add missing composite input line for ivtv_pci_pg600v2 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index 8eab02083887..baab14b40e87 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -845,6 +845,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, }, .audio_inputs = { { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, From c976bc82339437e840f7dbf0b8c89c09d3fcd75e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 12:52:40 -0300 Subject: [PATCH 0533/2804] V4L/DVB (5922): ivtv, cx25840: postpone fw load until first use The firmware is now loaded when the driver is actually used for the first time. This allows the driver to be compiled in-kernel instead of as a module. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 3 +- drivers/media/video/cx25840/cx25840-core.c | 21 ++- drivers/media/video/cx25840/cx25840-core.h | 1 + drivers/media/video/ivtv/ivtv-driver.c | 189 ++++++++++----------- drivers/media/video/ivtv/ivtv-driver.h | 5 + drivers/media/video/ivtv/ivtv-fileops.c | 9 + 6 files changed, 127 insertions(+), 101 deletions(-) diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 8f7205b558f6..c5286bfba447 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -64,7 +64,6 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ -obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o @@ -117,6 +116,8 @@ obj-$(CONFIG_USB_KONICAWC) += usbvideo/ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ +obj-$(CONFIG_VIDEO_IVTV) += ivtv/ + obj-$(CONFIG_VIDEO_VIVI) += vivi.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 67bda9f9a44b..9c12bd39cfb5 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -625,6 +625,22 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, struct v4l2_tuner *vt = arg; struct v4l2_routing *route = arg; + /* ignore these commands */ + switch (cmd) { + case TUNER_SET_TYPE_ADDR: + return 0; + } + + if (!state->is_initialized) { + v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd); + /* initialize on first use */ + state->is_initialized = 1; + if (state->is_cx25836) + cx25836_initialize(client); + else + cx25840_initialize(client, 1); + } + switch (cmd) { #ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct access to the @@ -906,11 +922,6 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, i2c_attach_client(client); - if (state->is_cx25836) - cx25836_initialize(client); - else - cx25840_initialize(client, 1); - return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index f4b56d2fd6b6..8c1fbd9b87c1 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -46,6 +46,7 @@ struct cx25840_state { u32 id; u32 rev; int is_cx25836; + int is_initialized; }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 81cbaf7dd51c..00bdcc2e8f53 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -814,7 +814,6 @@ static void ivtv_request_module(struct ivtv *itv, const char *name) static void ivtv_load_and_init_modules(struct ivtv *itv) { - struct v4l2_control ctrl; u32 hw = itv->card->hw_all; int i; @@ -896,11 +895,6 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) } if (hw & IVTV_HW_CX25840) { - /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ - ctrl.id = V4L2_CID_PRIVATE_BASE; - ctrl.value = itv->pvr150_workaround; - itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); - itv->vbi.raw_decoder_line_size = 1444; itv->vbi.raw_decoder_sav_odd_field = 0x20; itv->vbi.raw_decoder_sav_even_field = 0x60; @@ -946,12 +940,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; - int video_input; int yuv_buf_size; int vbi_buf_size; - int fw_retry_count = 3; struct ivtv *itv; - struct v4l2_frequency vf; spin_lock(&ivtv_cards_lock); @@ -1038,22 +1029,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, goto free_io; } - while (--fw_retry_count > 0) { - /* load firmware */ - if (ivtv_firmware_init(itv) == 0) - break; - if (fw_retry_count > 1) - IVTV_WARN("Retry loading firmware\n"); - } - if (fw_retry_count == 0) { - IVTV_ERR("Error initializing firmware\n"); - goto free_i2c; - } - - /* Try and get firmware versions */ - IVTV_DEBUG_INFO("Getting firmware version..\n"); - ivtv_firmware_versions(itv); - /* Check yuv output filter table */ if (itv->has_cx23415) ivtv_yuv_filter_check(itv); @@ -1157,44 +1132,16 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); } - vf.tuner = 0; - vf.type = V4L2_TUNER_ANALOG_TV; - vf.frequency = 6400; /* the tuner 'baseline' frequency */ - - /* Set initial frequency. For PAL/SECAM broadcasts no - 'default' channel exists AFAIK. */ - if (itv->std == V4L2_STD_NTSC_M_JP) { - vf.frequency = 1460; /* ch. 1 91250*16/1000 */ - } - else if (itv->std & V4L2_STD_NTSC_M) { - vf.frequency = 1076; /* ch. 4 67250*16/1000 */ - } - /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) are not. */ itv->tuner_std = itv->std; - video_input = itv->active_input; - itv->active_input++; /* Force update of input */ - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); - - /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code - in one place. */ - itv->std++; /* Force full standard initialization */ - itv->std_out = itv->std; - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); - retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); goto free_i2c; } - if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { - ivtv_init_mpeg_decoder(itv); - } - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); - IVTV_DEBUG_IRQ("Masking interrupts\n"); /* clear interrupt mask, effectively disabling interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); @@ -1206,26 +1153,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ERR("Failed to register irq %d\n", retval); goto free_streams; } - - /* On a cx23416 this seems to be able to enable DMA to the chip? */ - if (!itv->has_cx23415) - write_reg_sync(0x03, IVTV_REG_DMACONTROL); - - /* Default interrupts enabled. For the PVR350 this includes the - decoder VSYNC interrupt, which is always on. It is not only used - during decoding but also by the OSD. - Some old PVR250 cards had a cx23415, so testing for that is too - general. Instead test if the card has video output capability. */ - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); - else - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); - - if (itv->has_cx23415) - ivtv_set_osd_alpha(itv); - IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); - return 0; free_irq: @@ -1255,55 +1183,126 @@ static int __devinit ivtv_probe(struct pci_dev *dev, return retval; } +int ivtv_init_on_first_open(struct ivtv *itv) +{ + struct v4l2_frequency vf; + int fw_retry_count = 3; + int video_input; + + while (--fw_retry_count > 0) { + /* load firmware */ + if (ivtv_firmware_init(itv) == 0) + break; + if (fw_retry_count > 1) + IVTV_WARN("Retry loading firmware\n"); + } + if (fw_retry_count == 0) { + IVTV_ERR("Error initializing firmware\n"); + return -1; + } + + /* Try and get firmware versions */ + IVTV_DEBUG_INFO("Getting firmware version..\n"); + ivtv_firmware_versions(itv); + + if (itv->card->hw_all & IVTV_HW_CX25840) { + struct v4l2_control ctrl; + + /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ + ctrl.id = V4L2_CID_PRIVATE_BASE; + ctrl.value = itv->pvr150_workaround; + itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); + } + + vf.tuner = 0; + vf.type = V4L2_TUNER_ANALOG_TV; + vf.frequency = 6400; /* the tuner 'baseline' frequency */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (itv->std == V4L2_STD_NTSC_M_JP) { + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + } + else if (itv->std & V4L2_STD_NTSC_M) { + vf.frequency = 1076; /* ch. 4 67250*16/1000 */ + } + + video_input = itv->active_input; + itv->active_input++; /* Force update of input */ + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); + + /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code + in one place. */ + itv->std++; /* Force full standard initialization */ + itv->std_out = itv->std; + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); + + if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_init_mpeg_decoder(itv); + } + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); + + /* On a cx23416 this seems to be able to enable DMA to the chip? */ + if (!itv->has_cx23415) + write_reg_sync(0x03, IVTV_REG_DMACONTROL); + + /* Default interrupts enabled. For the PVR350 this includes the + decoder VSYNC interrupt, which is always on. It is not only used + during decoding but also by the OSD. + Some old PVR250 cards had a cx23415, so testing for that is too + general. Instead test if the card has video output capability. */ + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); + ivtv_set_osd_alpha(itv); + } + else + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); + return 0; +} + static void ivtv_remove(struct pci_dev *pci_dev) { struct ivtv *itv = pci_get_drvdata(pci_dev); IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num); - /* Stop all captures */ - IVTV_DEBUG_INFO("Stopping all streams\n"); - if (atomic_read(&itv->capturing) > 0) - ivtv_stop_all_captures(itv); + if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) { + /* Stop all captures */ + IVTV_DEBUG_INFO("Stopping all streams\n"); + if (atomic_read(&itv->capturing) > 0) + ivtv_stop_all_captures(itv); - /* Stop all decoding */ - IVTV_DEBUG_INFO("Stopping decoding\n"); - if (atomic_read(&itv->decoding) > 0) { - int type; + /* Stop all decoding */ + IVTV_DEBUG_INFO("Stopping decoding\n"); + if (atomic_read(&itv->decoding) > 0) { + int type; - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - type = IVTV_DEC_STREAM_TYPE_YUV; - else - type = IVTV_DEC_STREAM_TYPE_MPG; - ivtv_stop_v4l2_decode_stream(&itv->streams[type], - VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + type = IVTV_DEC_STREAM_TYPE_YUV; + else + type = IVTV_DEC_STREAM_TYPE_MPG; + ivtv_stop_v4l2_decode_stream(&itv->streams[type], + VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); + } + ivtv_halt_firmware(itv); } /* Interrupts */ - IVTV_DEBUG_INFO("Disabling interrupts\n"); ivtv_set_irq_mask(itv, 0xffffffff); del_timer_sync(&itv->dma_timer); /* Stop all Work Queues */ - IVTV_DEBUG_INFO("Stop Work Queues\n"); flush_workqueue(itv->irq_work_queues); destroy_workqueue(itv->irq_work_queues); - IVTV_DEBUG_INFO("Stopping Firmware\n"); - ivtv_halt_firmware(itv); - - IVTV_DEBUG_INFO("Unregistering v4l devices\n"); ivtv_streams_cleanup(itv); - IVTV_DEBUG_INFO("Freeing dma resources\n"); ivtv_udma_free(itv); exit_ivtv_i2c(itv); - IVTV_DEBUG_INFO(" Releasing irq\n"); free_irq(itv->dev->irq, (void *)itv); ivtv_iounmap(itv); - IVTV_DEBUG_INFO(" Releasing mem\n"); release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (itv->has_cx23415) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8fe9d9c7a18e..6e53a1f04f7e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -398,6 +398,8 @@ struct ivtv_mailbox_data { #define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ #define IVTV_F_I_PIO 19 /* PIO in progress */ #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ +#define IVTV_F_I_INITED 21 /* set after first open */ +#define IVTV_F_I_FAILED 22 /* set if first open failed */ /* Event notifications */ #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ @@ -838,6 +840,9 @@ int ivtv_waitq(wait_queue_head_t *waitq); struct tveeprom; /* forward reference */ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); +/* First-open initialization: load firmware, init cx25840, etc. */ +int ivtv_init_on_first_open(struct ivtv *itv); + /* This is a PCI post thing, where if the pci register is not read, then the write doesn't always take effect right away. By reading back the register any pending PCI writes will be performed (in order), and so diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 66ea3cbc369c..498860841644 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -850,6 +850,15 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -ENXIO; } + if (!test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) + if (ivtv_init_on_first_open(itv)) + set_bit(IVTV_F_I_FAILED, &itv->i_flags); + + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) { + printk(KERN_WARNING "ivtv: failed to initialize on minor %d\n", minor); + return -ENXIO; + } + if (y == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) return -EBUSY; From 6e5eb59102aa6007d3ea2b382a1d3ca4112c272a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 25 Jul 2007 12:55:52 -0300 Subject: [PATCH 0534/2804] V4L/DVB (5924): ivtv-fb: initializing the fb should trigger ivtv firmware load ivtv-fb: initializing the framebuffer should trigger ivtv firmware load Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 12 ++++++++++-- drivers/media/video/ivtv/ivtv-fb.c | 5 +++++ drivers/media/video/ivtv/ivtv-fileops.c | 10 +++------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 00bdcc2e8f53..55ed0305fd64 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1189,6 +1189,12 @@ int ivtv_init_on_first_open(struct ivtv *itv) int fw_retry_count = 3; int video_input; + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) + return -ENXIO; + + if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) + return 0; + while (--fw_retry_count > 0) { /* load firmware */ if (ivtv_firmware_init(itv) == 0) @@ -1196,9 +1202,10 @@ int ivtv_init_on_first_open(struct ivtv *itv) if (fw_retry_count > 1) IVTV_WARN("Retry loading firmware\n"); } + if (fw_retry_count == 0) { - IVTV_ERR("Error initializing firmware\n"); - return -1; + set_bit(IVTV_F_I_FAILED, &itv->i_flags); + return -ENXIO; } /* Try and get firmware versions */ @@ -1381,6 +1388,7 @@ EXPORT_SYMBOL(ivtv_udma_setup); EXPORT_SYMBOL(ivtv_udma_unmap); EXPORT_SYMBOL(ivtv_udma_alloc); EXPORT_SYMBOL(ivtv_udma_prepare); +EXPORT_SYMBOL(ivtv_init_on_first_open); module_init(module_start); module_exit(module_cleanup); diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index b8ad249a0b17..00765da8a6a0 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -1013,6 +1013,11 @@ static int ivtvfb_init_io(struct ivtv *itv) { struct osd_info *oi = itv->osd_info; + if (ivtv_init_on_first_open(itv)) { + IVTV_FB_ERR("Failed to initialize ivtv\n"); + return -ENXIO; + } + ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 498860841644..fedddecf661e 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -846,16 +846,12 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) if (itv == NULL) { /* Couldn't find a device registered on that minor, shouldn't happen! */ - printk(KERN_WARNING "ivtv: No ivtv device found on minor %d\n", minor); + IVTV_WARN("No ivtv device found on minor %d\n", minor); return -ENXIO; } - if (!test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) - if (ivtv_init_on_first_open(itv)) - set_bit(IVTV_F_I_FAILED, &itv->i_flags); - - if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) { - printk(KERN_WARNING "ivtv: failed to initialize on minor %d\n", minor); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on minor %d\n", minor); return -ENXIO; } From 469ba047c08669f364c2616967e8494b1f3ef21c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:51:58 -0300 Subject: [PATCH 0535/2804] V4L/DVB (5927): ivtv: set correct crystal frequency of the GVMVPRX cards Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 55ed0305fd64..cf52111a2dcc 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -57,6 +57,7 @@ #include "ivtv-yuv.h" #include +#include #include /* var to keep track of the number of array elements in use */ @@ -893,6 +894,15 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) else if ((hw & IVTV_HW_UPD64031A) == 0) itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR); } + else if (itv->card->type == IVTV_CARD_GV_MVPRX || + itv->card->type == IVTV_CARD_GV_MVPRX2E) { + struct v4l2_crystal_freq crystal_freq; + + /* The crystal frequency of GVMVPRX is 24.576MHz */ + crystal_freq.freq = SAA7115_FREQ_24_576_MHZ; + crystal_freq.flags = SAA7115_FREQ_FL_UCGC; + itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq); + } if (hw & IVTV_HW_CX25840) { itv->vbi.raw_decoder_line_size = 1444; From b4c85248afcc5265ce8c36b9c15e40e6a92b5ae7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:53:23 -0300 Subject: [PATCH 0536/2804] V4L/DVB (5928): tuner: fix TOP values for the Panasonic VP27 tuner. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-types.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 417f642b4359..53a99b39387f 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -670,6 +670,9 @@ static struct tuner_params tuner_panasonic_vp27_params[] = { .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), .has_tda9887 = 1, .intercarrier_mode = 1, + .default_top_low = -3, + .default_top_mid = -3, + .default_top_high = -3, }, }; From ac247433fe205acf460f05de64a30ee71ea307f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 27 Jul 2007 06:56:50 -0300 Subject: [PATCH 0537/2804] V4L/DVB (5929): Add vp27smpx driver This device is internal to the Panasonic VP27S tuner and is used to set the mono/stereo/bilingual setting of the tuner. It is used by two Japanese cx23416-based cards. Signed-off-by: Takahiro Adachi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 ++ drivers/media/video/Makefile | 1 + drivers/media/video/ivtv/Kconfig | 1 + drivers/media/video/ivtv/ivtv-cards.c | 4 +- drivers/media/video/ivtv/ivtv-cards.h | 3 +- drivers/media/video/ivtv/ivtv-driver.c | 4 + drivers/media/video/ivtv/ivtv-i2c.c | 2 + drivers/media/video/vp27smpx.c | 211 +++++++++++++++++++++++++ include/linux/i2c-id.h | 1 + include/media/v4l2-chip-ident.h | 3 + 10 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 drivers/media/video/vp27smpx.c diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 675c8574403e..0e1d2ccc4e81 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -148,6 +148,15 @@ config VIDEO_WM8739 To compile this driver as a module, choose M here: the module will be called wm8739. +config VIDEO_VP27SMPX + tristate "Panasonic VP27s internal MPX" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the internal MPX of the Panasonic VP27s tuner. + + To compile this driver as a module, choose M here: the + module will be called vp27smpx. + comment "Video decoders" config VIDEO_BT819 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c5286bfba447..113e525f6dab 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o +obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_MXB) += mxb.o diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 399f231abb96..5efacb332114 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -14,6 +14,7 @@ config VIDEO_IVTV select VIDEO_CS53L32A select VIDEO_WM8775 select VIDEO_WM8739 + select VIDEO_VP27SMPX select VIDEO_UPD64031A select VIDEO_UPD64083 ---help--- diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index baab14b40e87..e51d7cc35b1c 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -616,7 +616,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, .hw_audio = IVTV_HW_GPIO, .hw_audio_ctrl = IVTV_HW_WM8739, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO | + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX | IVTV_HW_TUNER | IVTV_HW_WM8739 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, .video_inputs = { @@ -654,7 +654,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { .hw_audio = IVTV_HW_GPIO, .hw_audio_ctrl = IVTV_HW_WM8739, .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_TVAUDIO | IVTV_HW_WM8739, + IVTV_HW_VP27SMPX | IVTV_HW_WM8739, .video_inputs = { { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 91e9e90c14a5..3191920f4c6b 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -33,7 +33,8 @@ #define IVTV_HW_UPD6408X (1 << 11) #define IVTV_HW_SAA717X (1 << 12) #define IVTV_HW_WM8739 (1 << 13) -#define IVTV_HW_GPIO (1 << 14) +#define IVTV_HW_VP27SMPX (1 << 14) +#define IVTV_HW_GPIO (1 << 15) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index cf52111a2dcc..f8ef267e56b2 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -853,6 +853,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) #ifndef CONFIG_VIDEO_MSP3400 if (hw & IVTV_HW_MSP34XX) ivtv_request_module(itv, "msp3400"); +#endif +#ifndef CONFIG_VIDEO_VP27SMPX + if (hw & IVTV_HW_VP27SMPX) + ivtv_request_module(itv, "vp27smpx"); #endif if (hw & IVTV_HW_TVAUDIO) ivtv_request_module(itv, "tvaudio"); diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index b3557435456d..5e12ebc2a9de 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -109,6 +109,7 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_UPD64083, I2C_DRIVERID_SAA717X, I2C_DRIVERID_WM8739, + I2C_DRIVERID_VP27SMPX, 0 /* IVTV_HW_GPIO dummy driver ID */ }; @@ -128,6 +129,7 @@ static const char * const hw_drivernames[] = { "upd64083", "saa717x", "wm8739", + "vp27smpx", "gpio", }; diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c new file mode 100644 index 000000000000..9aa526bd2c84 --- /dev/null +++ b/drivers/media/video/vp27smpx.c @@ -0,0 +1,211 @@ +/* + * vp27smpx - driver version 0.0.1 + * + * Copyright (C) 2007 Hans Verkuil + * + * Special thanks to Kazz for the i2c data. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("vp27smpx driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; + +/* ----------------------------------------------------------------------- */ + +struct vp27smpx_state { + int radio; + u32 audmode; +}; + +static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + u8 data[3] = { 0x00, 0x00, 0x04 }; + + switch (audmode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + data[1] = 0x01; + break; + case V4L2_TUNER_MODE_LANG2: + data[1] = 0x02; + break; + } + + if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) { + v4l_err(client, "%s: I/O error setting audmode\n", client->name); + } + else { + state->audmode = audmode; + } +} + +static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + struct v4l2_tuner *vt = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + state->radio = 1; + break; + + case VIDIOC_S_STD: + state->radio = 0; + break; + + case VIDIOC_S_TUNER: + if (!state->radio) + vp27smpx_set_audmode(client, vt->audmode); + break; + + case VIDIOC_G_TUNER: + if (state->radio) + break; + vt->audmode = state->audmode; + vt->capability = V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0); + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Audio Mode: %u%s\n", state->audmode, + state->radio ? " (Radio)" : ""); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static struct i2c_driver i2c_driver; + +static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct vp27smpx_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + + state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + state->audmode = V4L2_TUNER_MODE_STEREO; + i2c_set_clientdata(client, state); + + /* initialize vp27smpx */ + vp27smpx_set_audmode(client, state->audmode); + i2c_attach_client(client); + + return 0; +} + +static int vp27smpx_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, vp27smpx_attach); + return 0; +} + +static int vp27smpx_detach(struct i2c_client *client) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(state); + kfree(client); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "vp27smpx", + }, + .id = I2C_DRIVERID_VP27SMPX, + .attach_adapter = vp27smpx_probe, + .detach_client = vp27smpx_detach, + .command = vp27smpx_command, +}; + + +static int __init vp27smpx_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit vp27smpx_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(vp27smpx_init_module); +module_exit(vp27smpx_cleanup_module); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index b69014865714..4891e03ad23a 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -119,6 +119,7 @@ #define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ #define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */ #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */ +#define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 09d16c4f00f7..8ae42c41dd08 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -65,6 +65,9 @@ enum { V4L2_IDENT_CX23415 = 415, V4L2_IDENT_CX23416 = 416, + /* module vp27smpx: just ident 2700 */ + V4L2_IDENT_VP27SMPX = 2700, + /* module wm8739: just ident 8739 */ V4L2_IDENT_WM8739 = 8739, From 36c15f8ee41fbc3d8eaf88bba95be3d50268d5d2 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 13:59:55 -0300 Subject: [PATCH 0538/2804] V4L/DVB (5934): dvb-ttpci/saa7146: Replace saa7146_i2c_transfer by generic i2c_transfer Convert av7110_v4l.c to use i2c_transfer() instead of saa7146_i2c_transfer(). Make saa7146_i2c_transfer() static. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_core.c | 1 - drivers/media/common/saa7146_i2c.c | 2 +- drivers/media/dvb/ttpci/av7110_v4l.c | 6 ++++-- include/media/saa7146.h | 1 - 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index ba6701e97671..12cda9eebd12 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -548,7 +548,6 @@ EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); EXPORT_SYMBOL_GPL(saa7146_setgpio); -EXPORT_SYMBOL_GPL(saa7146_i2c_transfer); EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); EXPORT_SYMBOL_GPL(saa7146_debug); diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 8c85efc26527..f823286341eb 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -277,7 +277,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d return 0; } -int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) +static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) { int i = 0, count = 0; u32* buffer = dev->d_i2c.cpu_addr; diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 87afaebc0703..76cca003252f 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -129,23 +129,25 @@ static struct v4l2_input inputs[4] = { static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) { + struct av7110 *av7110 = dev->ext_priv; u8 buf[] = { 0x00, reg, data }; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) { + struct av7110 *av7110 = dev->ext_priv; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 67703249b245..cd3ff2c29d5e 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -146,7 +146,6 @@ struct saa7146_dev /* from saa7146_i2c.c */ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); -int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg *msgs, int num, int retries); /* from saa7146_core.c */ extern struct list_head saa7146_devices; From 1fab46f0decd226fcbae73b23d7f8ed478416fbb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 21:00:36 -0300 Subject: [PATCH 0539/2804] V4L/DVB (5935): dvb_frontend: Range check of frequency and symbol rate Add range check of frequency and symbol rate to the FE_SET_FRONTEND ioctl. This will also avoid a divide-by zero exception in the stv0297 driver, if symbol rate is set to 0. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index b6c7f6610ec5..384b5b8959c1 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -697,6 +697,47 @@ static int dvb_frontend_start(struct dvb_frontend *fe) return 0; } +static int dvb_frontend_check_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *parms) +{ + /* range check: frequency */ + if ((fe->ops.info.frequency_min && + parms->frequency < fe->ops.info.frequency_min) || + (fe->ops.info.frequency_max && + parms->frequency > fe->ops.info.frequency_max)) { + printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n", + fe->dvb->num, parms->frequency, + fe->ops.info.frequency_min, fe->ops.info.frequency_max); + return -EINVAL; + } + + /* range check: symbol rate */ + if (fe->ops.info.type == FE_QPSK) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, parms->u.qpsk.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + + } else if (fe->ops.info.type == FE_QAM) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, parms->u.qam.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + } + + return 0; +} + static int dvb_frontend_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { @@ -883,6 +924,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; + if (dvb_frontend_check_parameters(fe, parg) < 0) { + err = -EINVAL; + break; + } + memcpy (&fepriv->parameters, parg, sizeof (struct dvb_frontend_parameters)); From 92b3c1ec128695e606fc435d0b68902105d585bb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 21:14:10 -0300 Subject: [PATCH 0540/2804] V4L/DVB (5936): tda10023: Remove range check of symbol rate Remove incorrect range check of symbol rate, spotted by the coverity checker and reported by Adrian Bunk. These range checks are performed by dvb_core now. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda10023.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index 4bb06f97938b..a00cf0f54efc 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -215,12 +215,6 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) s16 SFIL=0; u16 NDEC = 0; - if (sr > (SYSCLK/(2*4))) - sr=SYSCLK/(2*4); - - if (sr<870000) - sr=870000; - if (sr < (u32)(SYSCLK/98.40)) { NDEC=3; SFIL=1; From 261efd12fc291e6b3b42011201bfd011484ad90b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 30 Jul 2007 11:43:55 -0300 Subject: [PATCH 0541/2804] V4L/DVB (5940): Export v4l2_int_device_{, un}register This patch fixes the following build error: <-- snip --> ... MODPOST 2135 modules make[2]: *** [__modpost] Error 1 <-- snip --> Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index aa2a8156338d..a643730fa3b2 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -101,6 +101,7 @@ int v4l2_int_device_register(struct v4l2_int_device *d) return 0; } +EXPORT_SYMBOL_GPL(v4l2_int_device_register); void v4l2_int_device_unregister(struct v4l2_int_device *d) { @@ -114,6 +115,7 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d) } mutex_unlock(&mutex); } +EXPORT_SYMBOL_GPL(v4l2_int_device_unregister); /* Adapted from search_extable in extable.c. */ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, From af520a3478b59476ed61eddee73948807398e358 Mon Sep 17 00:00:00 2001 From: Andi Drebes Date: Mon, 30 Jul 2007 11:48:10 -0300 Subject: [PATCH 0542/2804] V4L/DVB (5941): Ttpci/budget-av.c: ARRAY_SIZE() This patch replaces an array size calculation done using sizeof with an invocation of the ARRAY_SIZE macro. Tested by compilation on an i386 box using "allyesconfig". Diffed against Linus' git-tree. Signed-off-by: Andi Drebes Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-av.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 0aee7a13a070..3439c9864f67 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1232,7 +1232,7 @@ static struct saa7146_ext_vv vv_data = { .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 .flags = 0, .stds = &standard[0], - .num_stds = sizeof(standard) / sizeof(struct saa7146_standard), + .num_stds = ARRAY_SIZE(standard), .ioctls = &ioctls[0], .ioctl = av_ioctl, }; From 667c7bc0aff18288186f1223784b57f77be7d81b Mon Sep 17 00:00:00 2001 From: Andi Drebes Date: Mon, 30 Jul 2007 11:49:51 -0300 Subject: [PATCH 0543/2804] V4L/DVB (5942): Usb/vp7045.c: ARRAY_SIZE() This patch replaces an array size calculation done using sizeof with an invocation of the ARRAY_SIZE macro. Tested by compilation on an i386 box using "allyesconfig". Diffed against Linus' git-tree. Signed-off-by: Andi Drebes Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/vp7045.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 69a46b3607a2..5bbd2d5192f0 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -159,7 +159,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } - for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++) + for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++) if (vp7045_rc_keys[i].data == key) { *state = REMOTE_KEY_PRESSED; *event = vp7045_rc_keys[i].event; From 03b7612336560c6799852acaaaeac70e1f00e483 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 30 Jul 2007 14:58:10 -0300 Subject: [PATCH 0544/2804] V4L/DVB (5946): Use mutex instead of semaphore in the DVB frontend tuning interface The DVB frontend tuning interface uses a semaphore as mutex. Use the mutex API instead of the (binary) semaphore. Signed-off-by: Matthias Kaehlcke Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 10 +++++----- drivers/media/dvb/dvb-core/dvb_frontend.h | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 384b5b8959c1..afe797b75de4 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -138,7 +138,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) dprintk ("%s\n", __FUNCTION__); - if (down_interruptible (&events->sem)) + if (mutex_lock_interruptible (&events->mtx)) return; wp = (events->eventw + 1) % MAX_EVENT; @@ -159,7 +159,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) events->eventw = wp; - up (&events->sem); + mutex_unlock(&events->mtx); e->status = status; @@ -197,7 +197,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, return ret; } - if (down_interruptible (&events->sem)) + if (mutex_lock_interruptible (&events->mtx)) return -ERESTARTSYS; memcpy (event, &events->events[events->eventr], @@ -205,7 +205,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, events->eventr = (events->eventr + 1) % MAX_EVENT; - up (&events->sem); + mutex_unlock(&events->mtx); return 0; } @@ -1126,7 +1126,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, init_MUTEX (&fepriv->sem); init_waitqueue_head (&fepriv->wait_queue); init_waitqueue_head (&fepriv->events.wait_queue); - init_MUTEX (&fepriv->events.sem); + mutex_init(&fepriv->events.mtx); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index a770a87b9a93..f95de63d0e24 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -142,7 +143,7 @@ struct dvb_fe_events { int eventr; int overflow; wait_queue_head_t wait_queue; - struct semaphore sem; + struct mutex mtx; }; struct dvb_frontend { From f47623a04dab402fb2c18fe516a174bc02005629 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jul 2007 19:17:39 -0300 Subject: [PATCH 0545/2804] V4L/DVB (5947): Adding support for the MT2131 tuner. This adds support for the Microtune MT2131 tuner. 8VSB mode has been tested but QAM support will likely require more register work. Hauppauge have not announced any QAM devices using the MT2131 so QAM remains undone. For legal reasons, Microtune allowed us to write a GPL driver providing we did not document in significant detail any of the registers. This explains the lack of comments or defined on register names. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/mt2131.c | 308 ++++++++++++++++++++++ drivers/media/dvb/frontends/mt2131.h | 49 ++++ drivers/media/dvb/frontends/mt2131_priv.h | 44 ++++ 5 files changed, 409 insertions(+) create mode 100644 drivers/media/dvb/frontends/mt2131.c create mode 100644 drivers/media/dvb/frontends/mt2131.h create mode 100644 drivers/media/dvb/frontends/mt2131_priv.h diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ba70ad0c3f05..c3c8af771f80 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -329,6 +329,13 @@ config DVB_TUNER_MT2266 help A driver for the silicon baseband tuner MT2266 from Microtune. +config DVB_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 217265ca2849..a8cfa03b273c 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o +obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c new file mode 100644 index 000000000000..4fe1e62c9f06 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131.c @@ -0,0 +1,308 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mt2131.h" +#include "mt2131_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) + +static u8 mt2131_config1[] = { + 0x01, + 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, + 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, + 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, + 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 +}; + +static u8 mt2131_config2[] = { + 0x10, + 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 +}; + +static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "mt2131 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 v; + + mt2131_readreg(priv, 0x07, &v); + mt2131_writereg(priv, 0x07, (v & 0xfe) | (val & 0x01)); + + return 0; +} + +static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2131_priv *priv; + int ret=0, i; + u32 freq; + u8 if_band_center; + u32 f_lo1,f_lo2; + u32 div1,num1,div2,num2; + u8 b[8]; + u8 lockval = 0; + + priv = fe->tuner_priv; + if (fe->ops.info.type == FE_OFDM) + priv->bandwidth = params->u.ofdm.bandwidth; + else + priv->bandwidth = 0; + + freq = params->frequency / 1000; // Hz -> kHz + dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq); + + f_lo1 = freq + MT2131_IF1 * 1000; + f_lo1 = (f_lo1 / 250) * 250; + f_lo2 = f_lo1 - freq - MT2131_IF2; + + priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000, + + /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ + num1 = f_lo1 * 64 / (MT2131_FREF / 128); + div1 = num1 / 8192; + num1 &= 0x1fff; + + /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ + num2 = f_lo2 * 64 / (MT2131_FREF / 128); + div2 = num2 / 8192; + num2 &= 0x1fff; + + if (freq <= 82500) if_band_center = 0x00; else + if (freq <= 137500) if_band_center = 0x01; else + if (freq <= 192500) if_band_center = 0x02; else + if (freq <= 247500) if_band_center = 0x03; else + if (freq <= 302500) if_band_center = 0x04; else + if (freq <= 357500) if_band_center = 0x05; else + if (freq <= 412500) if_band_center = 0x06; else + if (freq <= 467500) if_band_center = 0x07; else + if (freq <= 522500) if_band_center = 0x08; else + if (freq <= 577500) if_band_center = 0x09; else + if (freq <= 632500) if_band_center = 0x0A; else + if (freq <= 687500) if_band_center = 0x0B; else + if (freq <= 742500) if_band_center = 0x0C; else + if (freq <= 797500) if_band_center = 0x0D; else + if (freq <= 852500) if_band_center = 0x0E; else + if (freq <= 907500) if_band_center = 0x0F; else + if (freq <= 962500) if_band_center = 0x10; else + if (freq <= 1017500) if_band_center = 0x11; else + if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; + + b[0] = 1; + b[1] = (num1 >> 5) & 0xFF; + b[2] = (num1 & 0x1F); + b[3] = div1; + b[4] = (num2 >> 5) & 0xFF; + b[5] = num2 & 0x1F; + b[6] = div2; + + dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); + dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); + dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); + dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", + (int)div1, (int)num1, (int)div2, (int)num2); + dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", + (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], + (int)b[6]); + + ret = mt2131_writeregs(priv,b,7); + if (ret < 0) + return ret; + + mt2131_writereg(priv, 0x0b, if_band_center); + + /* Wait for lock */ + i = 0; + do { + mt2131_readreg(priv, 0x08, &lockval); + if ((lockval & 0x88) == 0x88) + break; + msleep(4); + i++; + } while (i < 10); + + return ret; +} + +static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *frequency = priv->frequency; + return 0; +} + +static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 lock_status = 0; + u8 afc_status = 0; + + *status = 0; + + mt2131_readreg(priv, 0x08, &lock_status); + if ((lock_status & 0x88) == 0x88) + *status = TUNER_STATUS_LOCKED; + + mt2131_readreg(priv, 0x09, &afc_status); + dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", + __FUNCTION__, lock_status, afc_status); + + return 0; +} + +static int mt2131_init(struct dvb_frontend *fe) +{ + struct mt2131_priv *priv = fe->tuner_priv; + int ret; + dprintk(1, "%s()\n", __FUNCTION__); + + if ((ret = mt2131_writeregs(priv, mt2131_config1, sizeof(mt2131_config1))) < 0) + return ret; + + mt2131_writereg(priv, 0x0b, 0x09); + mt2131_writereg(priv, 0x15, 0x47); + mt2131_writereg(priv, 0x07, 0xf2); + mt2131_writereg(priv, 0x0b, 0x01); + + if ((ret = mt2131_writeregs(priv, mt2131_config2, sizeof(mt2131_config2))) < 0) + return ret; + + return ret; +} + +static int mt2131_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __FUNCTION__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2131_tuner_ops = { + .info = { + .name = "Microtune MT2131", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mt2131_release, + .init = mt2131_init, + + .set_params = mt2131_set_params, + .get_frequency = mt2131_get_frequency, + .get_bandwidth = mt2131_get_bandwidth, + .get_status = mt2131_get_status +}; + +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, u16 if1) +{ + struct mt2131_priv *priv = NULL; + u8 id = 0; + + dprintk(1, "%s()\n", __FUNCTION__); + + priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->bandwidth = 6000000; /* 6MHz */ + priv->i2c = i2c; + + if (mt2131_readreg(priv, 0, &id) != 0) { + kfree(priv); + return NULL; + } + if ( (id != 0x3E) && (id != 0x3F) ) { + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", cfg->i2c_address); + kfree(priv); + return NULL; + } + + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(mt2131_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h new file mode 100644 index 000000000000..5d1f281d87b2 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131.h @@ -0,0 +1,49 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * 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 __MT2131_H__ +#define __MT2131_H__ + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2131_config { + u8 i2c_address; + u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ +}; + +#if defined(CONFIG_DVB_TUNER_MT2131) || defined(CONFIG_DVB_TUNER_MT2131_MODULE) +extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1); +#else +static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_MT2131 + +#endif // __MT2131_H__ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h new file mode 100644 index 000000000000..fe6333b49c93 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131_priv.h @@ -0,0 +1,44 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * 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 MT2131_PRIV_H +#define MT2131_PRIV_H + +/* Regs */ +#define MT2131_PWR 0x07 +#define MT2131_UPC_1 0x0b +#define MT2131_AGC_RL 0x10 +#define MT2131_MISC_2 0x15 + +/* frequency values in KHz */ +#define MT2131_IF1 1220 +#define MT2131_IF2 44000 +#define MT2131_FREF 16000 + +struct mt2131_priv { + struct mt2131_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +#endif From 89885558ada9e076b48f4b6887e252e13e7eaf74 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jul 2007 19:34:52 -0300 Subject: [PATCH 0546/2804] V4L/DVB (5948): Adding support for the S5H1409/CX24227 8VSB/QAM demodulator. This patch adds support for the Samsung S5H1409 demodulator, also known as the Conexant CX24227 demodulator. 8VSB mode has been tested and QAM has been implemented based on the spec, although it's untested. The S5H1409 / CX24227 appears on various Hauppauge boards. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 8 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/s5h1409.c | 715 ++++++++++++++++++++++++++ drivers/media/dvb/frontends/s5h1409.h | 68 +++ 4 files changed, 792 insertions(+) create mode 100644 drivers/media/dvb/frontends/s5h1409.c create mode 100644 drivers/media/dvb/frontends/s5h1409.h diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index c3c8af771f80..faf9fe3c9cce 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -283,6 +283,14 @@ config DVB_LGDT330X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_S5H1409 + tristate "Samsung S5H1409 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + comment "Tuners/PLL support" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a8cfa03b273c..c46b9d8e9313 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o +obj-$(CONFIG_DVB_S5H1409) += s5h1409.o diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c new file mode 100644 index 000000000000..4b77390f5d4b --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -0,0 +1,715 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "s5h1409.h" + +struct s5h1409_state { + + struct i2c_adapter* i2c; + + /* configuration settings */ + const struct s5h1409_config* config; + + struct dvb_frontend frontend; + + /* previous uncorrected block counter */ + fe_modulation_t current_modulation; + + u32 current_frequency; +}; + +static int debug = 0; +#define dprintk if (debug) printk + +/* Register values to initialise the demod, this will set VSB by default */ +static struct init_tab { + u8 reg; + u16 data; +} init_tab[] = { + { 0x00, 0x0071, }, + { 0x01, 0x3213, }, + { 0x09, 0x0025, }, + { 0x1c, 0x001d, }, + { 0x1f, 0x002d, }, + { 0x20, 0x001d, }, + { 0x22, 0x0022, }, + { 0x23, 0x0020, }, + { 0x29, 0x110f, }, + { 0x2a, 0x10b4, }, + { 0x2b, 0x10ae, }, + { 0x2c, 0x0031, }, + { 0x31, 0x010d, }, + { 0x32, 0x0100, }, + { 0x44, 0x0510, }, + { 0x54, 0x0104, }, + { 0x58, 0x2222, }, + { 0x59, 0x1162, }, + { 0x5a, 0x3211, }, + { 0x5d, 0x0370, }, + { 0x5e, 0x0296, }, + { 0x61, 0x0010, }, + { 0x63, 0x4a00, }, + { 0x65, 0x0800, }, + { 0x71, 0x0003, }, + { 0x72, 0x0470, }, + { 0x81, 0x0002, }, + { 0x82, 0x0600, }, + { 0x86, 0x0002, }, + { 0x8a, 0x2c38, }, + { 0x8b, 0x2a37, }, + { 0x92, 0x302f, }, + { 0x93, 0x3332, }, + { 0x96, 0x000c, }, + { 0x99, 0x0101, }, + { 0x9c, 0x2e37, }, + { 0x9d, 0x2c37, }, + { 0x9e, 0x2c37, }, + { 0xab, 0x0100, }, + { 0xac, 0x1003, }, + { 0xad, 0x103f, }, + { 0xe2, 0x0100, }, + { 0x28, 0x1010, }, + { 0xb1, 0x000e, }, +}; + +/* VSB SNR lookup table */ +static struct vsb_snr_tab { + u16 val; + u16 data; +} vsb_snr_tab[] = { + { 1023, 770, }, + { 923, 300, }, + { 918, 295, }, + { 915, 290, }, + { 911, 285, }, + { 906, 280, }, + { 901, 275, }, + { 896, 270, }, + { 891, 265, }, + { 885, 260, }, + { 879, 255, }, + { 873, 250, }, + { 864, 245, }, + { 858, 240, }, + { 850, 235, }, + { 841, 230, }, + { 832, 225, }, + { 823, 220, }, + { 812, 215, }, + { 802, 210, }, + { 788, 205, }, + { 778, 200, }, + { 767, 195, }, + { 753, 190, }, + { 740, 185, }, + { 725, 180, }, + { 707, 175, }, + { 689, 170, }, + { 671, 165, }, + { 656, 160, }, + { 637, 155, }, + { 616, 150, }, + { 542, 145, }, + { 519, 140, }, + { 507, 135, }, + { 497, 130, }, + { 492, 125, }, + { 474, 120, }, + { 300, 111, }, + { 0, 0, }, +}; + +/* QAM64 SNR lookup table */ +static struct qam64_snr_tab { + u16 val; + u16 data; +} qam64_snr_tab[] = { + { 12, 300, }, + { 15, 290, }, + { 18, 280, }, + { 22, 270, }, + { 23, 268, }, + { 24, 266, }, + { 25, 264, }, + { 27, 262, }, + { 28, 260, }, + { 29, 258, }, + { 30, 256, }, + { 32, 254, }, + { 33, 252, }, + { 34, 250, }, + { 35, 249, }, + { 36, 248, }, + { 37, 247, }, + { 38, 246, }, + { 39, 245, }, + { 40, 244, }, + { 41, 243, }, + { 42, 241, }, + { 43, 240, }, + { 44, 239, }, + { 45, 238, }, + { 46, 237, }, + { 47, 236, }, + { 48, 235, }, + { 49, 234, }, + { 50, 233, }, + { 51, 232, }, + { 52, 231, }, + { 53, 230, }, + { 55, 229, }, + { 56, 228, }, + { 57, 227, }, + { 58, 226, }, + { 59, 225, }, + { 60, 224, }, + { 62, 223, }, + { 63, 222, }, + { 65, 221, }, + { 66, 220, }, + { 68, 219, }, + { 69, 218, }, + { 70, 217, }, + { 72, 216, }, + { 73, 215, }, + { 75, 214, }, + { 76, 213, }, + { 78, 212, }, + { 80, 211, }, + { 81, 210, }, + { 83, 209, }, + { 84, 208, }, + { 85, 207, }, + { 87, 206, }, + { 89, 205, }, + { 91, 204, }, + { 93, 203, }, + { 95, 202, }, + { 96, 201, }, + { 104, 200, }, +}; + +/* QAM256 SNR lookup table */ +static struct qam256_snr_tab { + u16 val; + u16 data; +} qam256_snr_tab[] = { + { 12, 400, }, + { 13, 390, }, + { 15, 380, }, + { 17, 360, }, + { 19, 350, }, + { 22, 348, }, + { 23, 346, }, + { 24, 344, }, + { 25, 342, }, + { 26, 340, }, + { 27, 336, }, + { 28, 334, }, + { 29, 332, }, + { 30, 330, }, + { 31, 328, }, + { 32, 326, }, + { 33, 325, }, + { 34, 322, }, + { 35, 320, }, + { 37, 318, }, + { 39, 316, }, + { 40, 314, }, + { 41, 312, }, + { 42, 310, }, + { 43, 308, }, + { 46, 306, }, + { 47, 304, }, + { 49, 302, }, + { 51, 300, }, + { 53, 298, }, + { 54, 297, }, + { 55, 296, }, + { 56, 295, }, + { 57, 294, }, + { 59, 293, }, + { 60, 292, }, + { 61, 291, }, + { 63, 290, }, + { 64, 289, }, + { 65, 288, }, + { 66, 287, }, + { 68, 286, }, + { 69, 285, }, + { 71, 284, }, + { 72, 283, }, + { 74, 282, }, + { 75, 281, }, + { 76, 280, }, + { 77, 279, }, + { 78, 278, }, + { 81, 277, }, + { 83, 276, }, + { 84, 275, }, + { 86, 274, }, + { 87, 273, }, + { 89, 272, }, + { 90, 271, }, + { 92, 270, }, + { 93, 269, }, + { 95, 268, }, + { 96, 267, }, + { 98, 266, }, + { 100, 265, }, + { 102, 264, }, + { 104, 263, }, + { 105, 262, }, + { 106, 261, }, + { 110, 260, }, +}; + +/* 8 bit registers, 16 bit values */ +static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) +{ + int ret; + u8 buf [] = { reg, data >> 8, data & 0xff }; + + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, ret == %i)\n", + __FUNCTION__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0, 0 }; + + struct i2c_msg msg [] = { + { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret) + ; + return (b1[0] << 8) | b1[1]; +} + +static int s5h1409_softreset(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + s5h1409_writereg(state, 0xf5, 0); + s5h1409_writereg(state, 0xf5, 1); + return 0; +} + +static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) +{ + struct s5h1409_state* state = fe->demodulator_priv; + int ret = 0; + + dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); + + if( (KHz == 44000) || (KHz == 5380) ) + { + s5h1409_writereg(state, 0x87, 0x01be); + s5h1409_writereg(state, 0x88, 0x0436); + s5h1409_writereg(state, 0x89, 0x054d); + } else { + printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); + ret = -1; + } + + return ret; +} + +static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + if(inverted == 1) + return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ + else + return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ +} + +static int s5h1409_enable_modulation(struct dvb_frontend* fe, fe_modulation_t m) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(0x%08x)\n", __FUNCTION__, m); + + switch(m) { + case VSB_8: + dprintk("%s() VSB_8\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 0); + break; + case QAM_64: + dprintk("%s() QAM_64\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x100); + break; + case QAM_256: + dprintk("%s() QAM_256\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x101); + break; + default: + dprintk("%s() Invalid modulation\n", __FUNCTION__); + return -EINVAL; + } + + state->current_modulation = m; + s5h1409_softreset(fe); + + return 0; +} + +static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + if (enable) + return s5h1409_writereg(state, 0xf3, 1); + else + return s5h1409_writereg(state, 0xf3, 0); +} + +static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + if (enable) + return s5h1409_writereg(state, 0xe3, 0x1100); + else + return s5h1409_writereg(state, 0xe3, 0); +} + +static int s5h1409_sleep(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + return s5h1409_writereg(state, 0xf2, enable); +} + +static int s5h1409_register_reset(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + return s5h1409_writereg(state, 0xfa, 0); +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int s5h1409_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency); + + s5h1409_softreset(fe); + + state->current_frequency = p->frequency; + + s5h1409_enable_modulation(fe, p->u.vsb.modulation); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + return 0; +} + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +static int s5h1409_init (struct dvb_frontend* fe) +{ + int i; + + struct s5h1409_state* state = fe->demodulator_priv; + dprintk("%s()\n", __FUNCTION__); + + s5h1409_sleep(fe, 0); + s5h1409_register_reset(fe); + + for (i=0; icurrent_modulation = VSB_8; + + if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) + s5h1409_writereg(state, 0xab, 0x100); /* Serial */ + else + s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ + + s5h1409_set_spectralinversion(fe, state->config->inversion); + s5h1409_set_if_freq(fe, state->config->if_freq); + s5h1409_set_gpio(fe, state->config->gpio); + s5h1409_softreset(fe); + + /* Note: Leaving the I2C gate open here. */ + s5h1409_i2c_gate_ctrl(fe, 1); + + return 0; +} + +static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct s5h1409_state* state = fe->demodulator_priv; + u16 reg; + u32 tuner_status = 0; + + *status = 0; + + /* Get the demodulator status */ + reg = s5h1409_readreg(state, 0xf1); + if(reg & 0x1000) + *status |= FE_HAS_VITERBI; + if(reg & 0x8000) + *status |= FE_HAS_LOCK | FE_HAS_SYNC; + + switch(state->config->status_mode) { + case S5H1409_DEMODLOCKING: + if (*status & FE_HAS_VITERBI) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + case S5H1409_TUNERLOCKING: + /* Get the tuner status */ + if (fe->ops.tuner_ops.get_status) { + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.get_status(fe, &tuner_status); + + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + if (tuner_status) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + } + + dprintk("%s() status 0x%08x\n", __FUNCTION__, *status); + + return 0; +} + +static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __FUNCTION__); + + for (i=0; i vsb_snr_tab[i].val) { + *snr = vsb_snr_tab[i].data; + ret = 0; + break; + } + } + dprintk("%s() snr=%d\n", __FUNCTION__, *snr); + return ret; +} + +static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct s5h1409_state* state = fe->demodulator_priv; + u16 reg; + dprintk("%s()\n", __FUNCTION__); + + reg = s5h1409_readreg(state, 0xf1) & 0x1ff; + + switch(state->current_modulation) { + case QAM_64: + return s5h1409_qam64_lookup_snr(fe, snr, reg); + case QAM_256: + return s5h1409_qam256_lookup_snr(fe, snr, reg); + case VSB_8: + return s5h1409_vsb_lookup_snr(fe, snr, reg); + default: + break; + } + + return -EINVAL; +} + +static int s5h1409_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + return s5h1409_read_snr(fe, signal_strength); +} + +static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + *ucblocks = s5h1409_readreg(state, 0xb5); + + return 0; +} + +static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber) +{ + return s5h1409_read_ucblocks(fe, ber); +} + +static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + p->frequency = state->current_frequency; + p->u.vsb.modulation = state->current_modulation; + + return 0; +} + +static int s5h1409_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void s5h1409_release(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1409_ops; + +struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c) +{ + struct s5h1409_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->current_modulation = 0; + + /* check if the demod exists */ + if (s5h1409_readreg(state, 0x04) != 0x0066) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s5h1409_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* Note: Leaving the I2C gate open here. */ + s5h1409_writereg(state, 0xf3, 1); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops s5h1409_ops = { + + .info = { + .name = "Samsung S5H1409 QAM/8VSB Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .init = s5h1409_init, + .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl, + .set_frontend = s5h1409_set_frontend, + .get_frontend = s5h1409_get_frontend, + .get_tune_settings = s5h1409_get_tune_settings, + .read_status = s5h1409_read_status, + .read_ber = s5h1409_read_ber, + .read_signal_strength = s5h1409_read_signal_strength, + .read_snr = s5h1409_read_snr, + .read_ucblocks = s5h1409_read_ucblocks, + .release = s5h1409_release, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(s5h1409_attach); diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h new file mode 100644 index 000000000000..6e9b9f24b60c --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -0,0 +1,68 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth + + 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 S5H1409_H +#define S5H1409_H + +#include + +struct s5h1409_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* serial/parallel output */ +#define S5H1409_PARALLEL_OUTPUT 0 +#define S5H1409_SERIAL_OUTPUT 1 + u8 output_mode; + + /* GPIO Setting */ +#define S5H1409_GPIO_OFF 0 +#define S5H1409_GPIO_ON 1 + u8 gpio; + + /* IF Freq in KHz */ + u16 if_freq; + + /* Spectral Inversion */ +#define S5H1409_INVERSION_OFF 0 +#define S5H1409_INVERSION_ON 1 + u8 inversion; + + /* Return lock status based on tuner lock, or demod lock */ +#define S5H1409_TUNERLOCKING 0 +#define S5H1409_DEMODLOCKING 1 + u8 status_mode; +}; + +#if defined(CONFIG_DVB_S5H1409) || defined(CONFIG_DVB_S5H1409_MODULE) +extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_S5H1409 + +#endif // S5H1409_H From a45c92756ed60bc89528701ac512e954acd23b9e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 21 Mar 2007 12:03:23 -0300 Subject: [PATCH 0547/2804] V4L/DVB (5949): s5h1409: use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1409.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 4b77390f5d4b..25cf78142d94 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -476,7 +476,7 @@ static int s5h1409_init (struct dvb_frontend* fe) s5h1409_sleep(fe, 0); s5h1409_register_reset(fe); - for (i=0; i vsb_snr_tab[i].val) { *snr = vsb_snr_tab[i].data; ret = 0; From 3873dd041465799cfdeb642531c0ade4fb6614e5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 28 Jul 2007 20:02:55 -0300 Subject: [PATCH 0548/2804] V4L/DVB (5950): whitespace cleanup for mt2131 and s5h1409 - trivial whitespace cleanups - add "c-basic-offset: 8" to enforce tabbing style in emacs Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.c | 46 +++++++++++++++------- drivers/media/dvb/frontends/mt2131.h | 9 ++++- drivers/media/dvb/frontends/mt2131_priv.h | 11 ++++-- drivers/media/dvb/frontends/s5h1409.c | 48 +++++++++++++++-------- drivers/media/dvb/frontends/s5h1409.h | 15 ++++--- 5 files changed, 88 insertions(+), 41 deletions(-) diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 4fe1e62c9f06..375dfa166817 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -53,8 +53,10 @@ static u8 mt2131_config2[] = { static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) { struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, + .buf = val, .len = 1 }, }; if (i2c_transfer(priv->i2c, msg, 2) != 2) { @@ -67,7 +69,8 @@ static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) { u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = buf, .len = 2 }; if (i2c_transfer(priv->i2c, &msg, 1) != 1) { printk(KERN_WARNING "mt2131 I2C write failed\n"); @@ -78,10 +81,12 @@ static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) { - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = len }; if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",(int)len); + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", + (int)len); return -EREMOTEIO; } return 0; @@ -98,14 +103,15 @@ static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) return 0; } -static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int mt2131_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { struct mt2131_priv *priv; int ret=0, i; u32 freq; u8 if_band_center; - u32 f_lo1,f_lo2; - u32 div1,num1,div2,num2; + u32 f_lo1, f_lo2; + u32 div1, num1, div2, num2; u8 b[8]; u8 lockval = 0; @@ -231,7 +237,8 @@ static int mt2131_init(struct dvb_frontend *fe) int ret; dprintk(1, "%s()\n", __FUNCTION__); - if ((ret = mt2131_writeregs(priv, mt2131_config1, sizeof(mt2131_config1))) < 0) + if ((ret = mt2131_writeregs(priv, mt2131_config1, + sizeof(mt2131_config1))) < 0) return ret; mt2131_writereg(priv, 0x0b, 0x09); @@ -239,7 +246,8 @@ static int mt2131_init(struct dvb_frontend *fe) mt2131_writereg(priv, 0x07, 0xf2); mt2131_writereg(priv, 0x0b, 0x01); - if ((ret = mt2131_writeregs(priv, mt2131_config2, sizeof(mt2131_config2))) < 0) + if ((ret = mt2131_writeregs(priv, mt2131_config2, + sizeof(mt2131_config2))) < 0) return ret; return ret; @@ -270,7 +278,9 @@ static const struct dvb_tuner_ops mt2131_tuner_ops = { .get_status = mt2131_get_status }; -struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, u16 if1) +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, u16 if1) { struct mt2131_priv *priv = NULL; u8 id = 0; @@ -290,13 +300,16 @@ struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter return NULL; } if ( (id != 0x3E) && (id != 0x3F) ) { - printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", cfg->i2c_address); + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", + cfg->i2c_address); kfree(priv); return NULL; } - printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", cfg->i2c_address); - memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, sizeof(struct dvb_tuner_ops)); + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", + cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, + sizeof(struct dvb_tuner_ops)); fe->tuner_priv = priv; return fe; @@ -306,3 +319,8 @@ EXPORT_SYMBOL(mt2131_attach); MODULE_AUTHOR("Steven Toth"); MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h index 5d1f281d87b2..608f1f66c9e7 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/dvb/frontends/mt2131.h @@ -44,6 +44,11 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2131 +#endif /* CONFIG_DVB_TUNER_MT2131 */ -#endif // __MT2131_H__ +#endif /* __MT2131_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h index fe6333b49c93..e930759c2c00 100644 --- a/drivers/media/dvb/frontends/mt2131_priv.h +++ b/drivers/media/dvb/frontends/mt2131_priv.h @@ -19,8 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef MT2131_PRIV_H -#define MT2131_PRIV_H +#ifndef __MT2131_PRIV_H__ +#define __MT2131_PRIV_H__ /* Regs */ #define MT2131_PWR 0x07 @@ -41,4 +41,9 @@ struct mt2131_priv { u32 bandwidth; }; -#endif +#endif /* __MT2131_PRIV_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 25cf78142d94..30e8a705fad4 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -296,13 +296,14 @@ static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) int ret; u8 buf [] = { reg, data >> 8, data & 0xff }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 3 }; ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, ret == %i)\n", - __FUNCTION__, reg, data, ret); + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " + "ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -1 : 0; } @@ -314,14 +315,15 @@ static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) u8 b1 [] = { 0, 0 }; struct i2c_msg msg [] = { - { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 2 } }; ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret) - ; + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); return (b1[0] << 8) | b1[1]; } @@ -343,8 +345,7 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); - if( (KHz == 44000) || (KHz == 5380) ) - { + if( (KHz == 44000) || (KHz == 5380) ) { s5h1409_writereg(state, 0x87, 0x01be); s5h1409_writereg(state, 0x88, 0x0436); s5h1409_writereg(state, 0x89, 0x054d); @@ -368,7 +369,8 @@ static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ } -static int s5h1409_enable_modulation(struct dvb_frontend* fe, fe_modulation_t m) +static int s5h1409_enable_modulation(struct dvb_frontend* fe, + fe_modulation_t m) { struct s5h1409_state* state = fe->demodulator_priv; @@ -443,7 +445,8 @@ static int s5h1409_register_reset(struct dvb_frontend* fe) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1409_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1409_set_frontend (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1409_state* state = fe->demodulator_priv; @@ -521,11 +524,13 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) case S5H1409_TUNERLOCKING: /* Get the tuner status */ if (fe->ops.tuner_ops.get_status) { - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.get_status(fe, &tuner_status); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); } if (tuner_status) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; @@ -605,7 +610,8 @@ static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) return -EINVAL; } -static int s5h1409_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +static int s5h1409_read_signal_strength(struct dvb_frontend* fe, + u16* signal_strength) { return s5h1409_read_snr(fe, signal_strength); } @@ -624,7 +630,8 @@ static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber) return s5h1409_read_ucblocks(fe, ber); } -static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1409_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1409_state* state = fe->demodulator_priv; @@ -634,7 +641,8 @@ static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int s5h1409_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +static int s5h1409_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 1000; return 0; @@ -668,7 +676,8 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, goto error; /* create dvb_frontend */ - memcpy(&state->frontend.ops, &s5h1409_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &s5h1409_ops, + sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; /* Note: Leaving the I2C gate open here. */ @@ -713,3 +722,8 @@ MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(s5h1409_attach); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index 6e9b9f24b60c..bccfd8a6fbd4 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -19,8 +19,8 @@ */ -#ifndef S5H1409_H -#define S5H1409_H +#ifndef __S5H1409_H__ +#define __S5H1409_H__ #include @@ -58,11 +58,16 @@ extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c); #else static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, - struct i2c_adapter* i2c) + struct i2c_adapter* i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_S5H1409 +#endif /* CONFIG_DVB_S5H1409 */ -#endif // S5H1409_H +#endif /* __S5H1409_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ From b2a657603e7285bf05b86ad198111b5403c57b41 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 16:35:32 -0300 Subject: [PATCH 0549/2804] V4L/DVB (5953): msp3400-driver.c: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400-driver.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 11cfcf18ec34..e9d400e19a5d 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -813,8 +813,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) int msp_rom; client = kzalloc(sizeof(*client), GFP_KERNEL); - if (client == NULL) + if (!client) return -ENOMEM; + client->addr = address; client->adapter = adapter; client->driver = &i2c_driver; @@ -826,14 +827,14 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) return 0; } - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) { + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) { kfree(client); return -ENOMEM; } + i2c_set_clientdata(client, state); - memset(state, 0, sizeof(*state)); state->v4l2_std = V4L2_STD_NTSC; state->audmode = V4L2_TUNER_MODE_STEREO; state->volume = 58880; /* 0db gain */ From b6884a17fc70e979ef34e4b5560988b522bb50a0 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 27 Jul 2007 10:08:51 -0300 Subject: [PATCH 0550/2804] V4L/DVB (5954): Sync with DiBcom Driver Release 2.1.3 + some improvements This changesets syncs the OpenSource driver for DiBcom demodulators with version 2.1.3 of DiBcom reference driver. There were some improvements since the last release for linux-dvb, e.g.: - stepped AGC startup - less space for initialization - diversity synchronization Furthermore this changeset contains the following things: - latest AGC settings for MT2266-based devices (namely Nova-TD and other) will improve the sensitivity - support for STK7700D reference design in dib0700-devices - remove some line-breaks when debugging is enabled - getting rid of layer between frontend_parameters and ofdm_channel used in dib*-drivers Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 136 ++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/frontends/dib3000mc.c | 170 ++-- drivers/media/dvb/frontends/dib7000m.c | 719 +++++++++------ drivers/media/dvb/frontends/dib7000p.c | 886 +++++++++++++------ drivers/media/dvb/frontends/dib7000p.h | 7 +- drivers/media/dvb/frontends/dibx000_common.h | 57 +- drivers/media/dvb/frontends/mt2266.c | 4 +- 8 files changed, 1282 insertions(+), 698 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 122d9d4b4baa..04b66f6e659f 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -4,7 +4,7 @@ * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 2. * - * Copyright (C) 2005-6 DiBcom, SA + * Copyright (C) 2005-7 DiBcom, SA */ #include "dib0700.h" @@ -99,41 +99,87 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) /* STK7700D: Pinnacle Dual DVB-T Diversity */ -static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config = { - BAND_UHF/* | BAND_VHF*/, - 0xE64, // setup - 2372, // inv_gain - 21, // time_stabiliz +/* MT226x */ +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { + { + BAND_UHF, // band_caps - 0, // alpha_level - 118, // thlock + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup - 0, // wbd_inv - 0, // wbd_ref - 0, // wbd_sel - 0, // wbd_alpha + 1130, // inv_gain + 21, // time_stabiliz - 65535, // agc1_max - 0, // agc1_min - 65535, // agc2_max - 23592, // agc2_min - 0, // agc1_pt1 - 128, // agc1_pt2 - 128, // agc1_pt3 - 128, // agc1_slope1 - 0, // agc1_slope2 - 128, // agc2_pt1 - 253, // agc2_pt2 - 81, // agc2_slope1 - 0, // agc2_slope2 + 0, // alpha_level + 118, // thlock - 17, // alpha_mant - 27, // alpha_exp + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha - 23, // beta_mant - 51, // beta_exp + 65535, // agc1_max + 33770, // agc1_min + 65535, // agc2_max + 23592, // agc2_min - 0, // perform_agc_softsplit : 1 en vrai! + 0, // agc1_pt1 + 62, // agc1_pt2 + 255, // agc1_pt3 + 64, // agc1_slope1 + 64, // agc1_slope2 + 132, // agc2_pt1 + 192, // agc2_pt2 + 80, // agc2_slope1 + 80, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + }, { + BAND_VHF | BAND_LBAND, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + + 2372, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + + 0, // agc1_pt1 + 128, // agc1_pt2 + 128, // agc1_pt3 + 128, // agc1_slope1 + 0, // agc1_slope2 + 128, // agc2_pt1 + 253, // agc2_pt2 + 81, // agc2_slope1 + 0, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + } }; static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { @@ -150,23 +196,25 @@ static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { .hostbus_diversity = 1, .tuner_is_baseband = 1, - .agc = &stk7700d_7000p_mt2266_agc_config, + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, .bw = &stk7700d_mt2266_pll_config, - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, }, { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, - .agc = &stk7700d_7000p_mt2266_agc_config, + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, .bw = &stk7700d_mt2266_pll_config, - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, } }; @@ -211,7 +259,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; -int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[4]; int i; @@ -241,7 +289,7 @@ int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) #define KEY_MAP_SIZE (25+48) -struct dvb_usb_rc_key stk7700d_rc_keys[] = { +static struct dvb_usb_rc_key stk7700d_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, { 0x07, 0x01, KEY_MENU }, // Pinnacle logo @@ -436,6 +484,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = { static struct dib7000p_config stk7700p_dib7000p_config = { .output_mpeg2_in_188_bytes = 1, + .agc_config_count = 1, .agc = &stk7700p_7000p_mt2060_agc_config, .bw = &stk7700p_pll_config, @@ -506,6 +555,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -615,7 +665,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "Pinnacle PCTV 2000e", { &dib0700_usb_id_table[11], NULL }, @@ -629,6 +679,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[13], NULL }, { NULL }, }, + { "DiBcom STK7700D", + { &dib0700_usb_id_table[14], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = stk7700d_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2e38be3aa45b..5657ad8beaac 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -67,6 +67,7 @@ #define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 +#define USB_PID_DIBCOM_STK7700D 0x1ef0 #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 054d7e6d9662..cbbe2c2f05dc 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -1,7 +1,7 @@ /* * Driver for DiBcom DiB3000MC/P-demodulator. * - * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * This code is partially based on the previous dib3000mc.c . @@ -26,7 +26,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) struct dib3000mc_state { struct dvb_frontend demod; @@ -71,7 +71,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val) return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } - static int dib3000mc_identify(struct dib3000mc_state *state) { u16 value; @@ -92,7 +91,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state) return 0; } -static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset) +static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) { u32 timf; @@ -103,7 +102,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, } else timf = state->timf; - timf *= (BW_INDEX_TO_KHZ(bw) / 1000); + timf *= (bw / 1000); if (update_offset) { s16 tim_offs = dib3000mc_read_word(state, 416); @@ -111,17 +110,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, if (tim_offs & 0x2000) tim_offs -= 0x4000; - if (nfft == 0) + if (nfft == TRANSMISSION_MODE_2K) tim_offs *= 4; timf += tim_offs; - state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000); + state->timf = timf / (bw / 1000); } dprintk("timf: %d\n", timf); - dib3000mc_write_word(state, 23, timf >> 16); - dib3000mc_write_word(state, 24, timf & 0xffff); + dib3000mc_write_word(state, 23, (u16) (timf >> 16)); + dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); return 0; } @@ -209,31 +208,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) return ret; } -static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) +static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) { - struct dib3000mc_state *state = demod->demodulator_priv; u16 bw_cfg[6] = { 0 }; u16 imp_bw_cfg[3] = { 0 }; u16 reg; /* settings here are for 27.7MHz */ switch (bw) { - case BANDWIDTH_8_MHZ: + case 8000: bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; break; - case BANDWIDTH_7_MHZ: + case 7000: bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; break; - case BANDWIDTH_6_MHZ: + case 6000: bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; break; - case 255 /* BANDWIDTH_5_MHZ */: + case 5000: bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; break; @@ -257,7 +255,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); // Timing configuration - dib3000mc_set_timing(state, 0, bw, 0); + dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); return 0; } @@ -276,7 +274,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, for (i = 58; i < 87; i++) dib3000mc_write_word(state, i, impulse_noise_val[i-58]); - if (nfft == 1) { + if (nfft == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 58, 0x3b); dib3000mc_write_word(state, 84, 0x00); dib3000mc_write_word(state, 85, 0x8200); @@ -376,7 +374,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) // P_search_maxtrial=1 dib3000mc_write_word(state, 5, 1); - dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib3000mc_set_bandwidth(state, 8000); // div_lock_mask dib3000mc_write_word(state, 4, 0x814); @@ -397,7 +395,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) dib3000mc_write_word(state, 180, 0x2FF0); // Impulse noise configuration - dib3000mc_set_impulse_noise(state, 0, 1); + dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); // output mode set-up dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); @@ -423,13 +421,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) { u16 cfg[4] = { 0 },reg; switch (qam) { - case 0: + case QPSK: cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; break; - case 1: + case QAM_16: cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; break; - case 2: + case QAM_64: cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; break; } @@ -437,11 +435,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) dib3000mc_write_word(state, reg, cfg[reg - 129]); } -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq) +static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) { - u16 tmp; - - dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0); + u16 value; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); // if (boost) // dib3000mc_write_word(state, 100, (11 << 6) + 6); @@ -455,7 +453,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 26, 0x6680); dib3000mc_write_word(state, 29, 0x1273); dib3000mc_write_word(state, 33, 5); - dib3000mc_set_adp_cfg(state, 1); + dib3000mc_set_adp_cfg(state, QAM_16); dib3000mc_write_word(state, 133, 15564); dib3000mc_write_word(state, 12 , 0x0); @@ -470,52 +468,98 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 97,0); dib3000mc_write_word(state, 98,0); - dib3000mc_set_impulse_noise(state, 0, chan->nfft); - - tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha; - dib3000mc_write_word(state, 0, tmp); + dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib3000mc_write_word(state, 0, value); dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); - tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp); - if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp)) - tmp |= chan->vit_code_rate_hp << 1; - else - tmp |= chan->vit_code_rate_lp << 1; - dib3000mc_write_word(state, 181, tmp); + value = 0; + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib3000mc_write_word(state, 181, value); - // diversity synchro delay - tmp = dib3000mc_read_word(state, 180) & 0x000f; - tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin - dib3000mc_write_word(state, 180, tmp); + // diversity synchro delay add 50% SFN margin + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + value <<= 4; + value |= dib3000mc_read_word(state, 180) & 0x000f; + dib3000mc_write_word(state, 180, value); // restart demod - tmp = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, tmp | (1 << 9)); - dib3000mc_write_word(state, 0, tmp); + value = dib3000mc_read_word(state, 0); + dib3000mc_write_word(state, 0, value | (1 << 9)); + dib3000mc_write_word(state, 0, value); msleep(30); - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft); + dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); } -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan) +static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) { struct dib3000mc_state *state = demod->demodulator_priv; u16 reg; // u32 val; - struct dibx000_ofdm_channel fchan; + struct dvb_frontend_parameters schan; - INIT_OFDM_CHANNEL(&fchan); - fchan = *chan; + schan = *chan; + /* TODO what is that ? */ /* a channel for autosearch */ - fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2; - fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2; - fchan.vit_hrch = 0; fchan.vit_select_hp = 1; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_2_3; + schan.u.ofdm.hierarchy_information = 0; - dib3000mc_set_channel_cfg(state, &fchan, 11); + dib3000mc_set_channel_cfg(state, &schan, 11); reg = dib3000mc_read_word(state, 0); dib3000mc_write_word(state, 0, reg | (1 << 8)); @@ -539,7 +583,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib3000mc_state *state = demod->demodulator_priv; @@ -549,9 +593,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe // activates isi dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_set_adp_cfg(state, (u8)ch->nqam); - - if (ch->nfft == 1) { + dib3000mc_set_adp_cfg(state, (uint8_t)ch->u.ofdm.constellation); + if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); } else { @@ -560,7 +603,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe } if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); return 0; } @@ -632,13 +675,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib3000mc_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); @@ -651,7 +690,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 100, found; - dib3000mc_autosearch_start(fe, &ch); + dib3000mc_autosearch_start(fe, fep); do { msleep(1); found = dib3000mc_autosearch_is_irq(fe); @@ -662,13 +701,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, return 0; // no channel found dib3000mc_get_frontend(fe, fep); - FEP2DIB(fep,&ch); } /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib3000mc_tune(fe, &ch); + return dib3000mc_tune(fe, fep); } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index f64546c6aeb5..608156a691de 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -2,7 +2,7 @@ * Linux-DVB Driver for DiBcom's DiB7000M and * first generation DiB7000P-demodulator-family. * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,7 +19,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0) struct dib7000m_state { struct dvb_frontend demod; @@ -39,8 +39,16 @@ struct dib7000m_state { fe_bandwidth_t current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; + u32 timf_default; + u32 internal_clk; + + uint8_t div_force_off : 1; + uint8_t div_state : 1; + uint16_t div_sync_wait; u16 revision; + + u8 agc_state; }; enum dib7000m_power_mode { @@ -63,7 +71,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -79,6 +87,25 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC + r++; + + do { + dib7000m_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) { int ret = 0; @@ -89,8 +116,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", - &state->demod, mode); + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock @@ -117,7 +143,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } @@ -129,13 +155,20 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) ret |= dib7000m_write_word(state, 1795, outreg); ret |= dib7000m_write_word(state, 1805, sram); + if (state->revision == 0x4003) { + u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; + if (mode == OUTMODE_DIVERSITY) + clk_cfg1 |= (1 << 1); // P_O_CLK_en + dib7000m_write_word(state, 909, clk_cfg1); + } return ret; } -static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) +static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) { /* by default everything is going to be powered off */ u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; + u8 offset = 0; /* now, depending on the requested mode, we power on */ switch (mode) { @@ -170,16 +203,17 @@ static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_p if (!state->cfg.mobile_mode) reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); - /* P_sdio_select_clk = 0 on MC */ + /* P_sdio_select_clk = 0 on MC and after*/ if (state->revision != 0x4000) reg_906 <<= 1; - dib7000m_write_word(state, 903, reg_903); - dib7000m_write_word(state, 904, reg_904); - dib7000m_write_word(state, 905, reg_905); - dib7000m_write_word(state, 906, reg_906); + if (state->revision == 0x4003) + offset = 1; - return 0; + dib7000m_write_word(state, 903 + offset, reg_903); + dib7000m_write_word(state, 904 + offset, reg_904); + dib7000m_write_word(state, 905 + offset, reg_905); + dib7000m_write_word(state, 906 + offset, reg_906); } static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no) @@ -230,34 +264,55 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc break; } -// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914); - +// dprintk( "913: %x, 914: %x", reg_913, reg_914); ret |= dib7000m_write_word(state, 913, reg_913); ret |= dib7000m_write_word(state, 914, reg_914); return ret; } -static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx) +static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) { - struct dib7000m_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = bw_idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); - timf = state->cfg.bw->timf; + dprintk( "using default timf"); + timf = state->timf_default; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dib7000m_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000m_write_word(state, 24, (timf ) & 0xffff); + dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); + + return 0; +} + +static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000m_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (uint8_t)onoff; + + if (onoff) { + dib7000m_write_word(state, 263 + state->reg_offs, 6); + dib7000m_write_word(state, 264 + state->reg_offs, 6); + dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000m_write_word(state, 263 + state->reg_offs, 1); + dib7000m_write_word(state, 264 + state->reg_offs, 0); + dib7000m_write_word(state, 266 + state->reg_offs, 0); + } return 0; } @@ -266,7 +321,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) { /* internal */ -// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 @@ -281,10 +336,10 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw) { - dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff); - dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000m_write_word(state, 22, bw->ifreq & 0xffff); + dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); + dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); dib7000m_write_word(state, 928, bw->sad_cfg); } @@ -325,15 +380,19 @@ static void dib7000m_reset_pll(struct dib7000m_state *state) static void dib7000mc_reset_pll(struct dib7000m_state *state) { const struct dibx000_bandwidth_config *bw = state->cfg.bw; + u16 clk_cfg1; // clk_cfg0 dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); // clk_cfg1 //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | - dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) | + clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | - (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0)); + (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); + dib7000m_write_word(state, 908, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); + dib7000m_write_word(state, 908, clk_cfg1); // smpl_cfg dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); @@ -344,9 +403,6 @@ static void dib7000mc_reset_pll(struct dib7000m_state *state) static int dib7000m_reset_gpio(struct dib7000m_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n", - st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos); - dib7000m_write_word(st, 773, st->cfg.gpio_dir); dib7000m_write_word(st, 774, st->cfg.gpio_val); @@ -358,6 +414,107 @@ static int dib7000m_reset_gpio(struct dib7000m_state *st) return 0; } +static u16 dib7000m_defaults_common[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_corm_thres Lock algorithms configuration + + 1, 170, + 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on + + 8, 173, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 182, + 8192, // P_fft_nb_to_cut + + 2, 195, + 0x0ccd, // P_pha3_thres + 0, // P_cti_use_cpe, P_cti_use_prog + + 1, 205, + 0x200f, // P_cspu_regul, P_cspu_win_cut + + 5, 214, + 0x023d, // P_adp_regul_cnt + 0x00a4, // P_adp_noise_cnt + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 226, + 0, // P_2d_byp_ti_num + + 1, 255, + 0x800, // P_equal_thres_wgn + + 1, 263, + 0x0001, + + 1, 281, + 0x0010, // P_fec_* + + 1, 294, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 0 +}; + +static u16 dib7000m_defaults[] = + +{ + /* set ADC level to -16 */ + 11, 76, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + // Tuner IO bank: max drive (14mA) + 1, 912, + 0x2c8a, + + 1, 1817, + 1, + + 0, +}; + static int dib7000m_demod_reset(struct dib7000m_state *state) { dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); @@ -382,22 +539,47 @@ static int dib7000m_demod_reset(struct dib7000m_state *state) dib7000mc_reset_pll(state); if (dib7000m_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); - dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib7000m_set_bandwidth(state, 8000); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON); dib7000m_sad_calib(state); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + if (state->cfg.dvbt_mode) + dib7000m_write_word(state, 1796, 0x0); // select DVB-T output + + if (state->cfg.mobile_mode) + dib7000m_write_word(state, 261 + state->reg_offs, 2); + else + dib7000m_write_word(state, 224 + state->reg_offs, 1); + + // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000m_write_word(state, 36, 0x0755); + else + dib7000m_write_word(state, 36, 0x1f55); + + // P_divclksel=3 P_divbitsel=1 + if (state->revision == 0x4000) + dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); + else + dib7000m_write_word(state, 909, (3 << 4) | 1); + + dib7000m_write_tab(state, dib7000m_defaults_common); + dib7000m_write_tab(state, dib7000m_defaults); + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY); + state->internal_clk = state->cfg.bw->internal; + return 0; } @@ -427,7 +609,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - dprintk("AGC split_offset: %d\n",split_offset); + dprintk( "AGC split_offset: %d",split_offset); // P_agc_force_split and P_agc_split_offset return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); @@ -435,35 +617,26 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) static int dib7000m_update_lna(struct dib7000m_state *state) { - int i; u16 dyn_gain; - // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return 0; - - msleep(60); - for (i = 0; i < 20; i++) { + if (state->cfg.update_lna) { // read dyn_gain here (because it is demod-dependent and not tuner) dyn_gain = dib7000m_read_word(state, 390); - dprintk("agc global: %d\n", dyn_gain); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000m_restart_agc(state); - msleep(60); - } else - break; + return 1; + } } return 0; } -static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) +static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) { struct dibx000_agc_config *agc = NULL; int i; - if (state->current_band == band) - return; + if (state->current_band == band && state->current_agc != NULL) + return 0; state->current_band = band; for (i = 0; i < state->cfg.agc_config_count; i++) @@ -473,8 +646,8 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) } if (agc == NULL) { - dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band); - return; + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; } state->current_agc = agc; @@ -489,7 +662,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); /* AGC continued */ @@ -510,7 +683,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) if (state->revision > 0x4000) { // settings for the MC dib7000m_write_word(state, 71, agc->agc1_pt3); -// dprintk("-D- 929: %x %d %d\n", +// dprintk( "929: %x %d %d", // (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); } else { @@ -519,33 +692,160 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) for (i = 0; i < 9; i++) dib7000m_write_word(state, 88 + i, b[i]); } + return 0; } -static void dib7000m_update_timf_freq(struct dib7000m_state *state) +static void dib7000m_update_timf(struct dib7000m_state *state) { u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); + state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000m_write_word(state, 23, (u16) (timf >> 16)); dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); } -static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000m_state *state = demod->demodulator_priv; + u16 cfg_72 = dib7000m_read_word(state, 72); + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); + dib7000m_set_adc_state(state, DIBX000_ADC_ON); + + if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; /* ADC power up */ + (*agc_state)++; + break; + + case 1: + /* AGC initialization */ + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000m_write_word(state, 75, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */ + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000m_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */ + dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (uint8_t)dib7000m_read_word(state, 392); /* store the split value for the next time */ + dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ + + dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ + dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000m_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + /* wait AGC accurate lock time */ + ret = 7; + + if (dib7000m_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else + (*agc_state)++; + break; + + case 5: + dib7000m_agc_soft_split(state); + + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + + (*agc_state)++; + break; + + default: + break; + } + return ret; +} + +static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) { u16 value, est[4]; - dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000m_write_word(state, 0, value); dib7000m_write_word(state, 5, (seq << 4)); - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - value |= (ch->vit_code_rate_hp << 1); - else - value |= (ch->vit_code_rate_lp << 1); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } dib7000m_write_word(state, 267 + state->reg_offs, value); /* offset loop parameters */ @@ -563,32 +863,38 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of dib7000m_write_word(state, 33, (0 << 4) | 0x5); /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: value = 256; break; - case 2: value = 128; break; - case 0: + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: default: value = 64; break; } - value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - value <<= 4; + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || state->revision > 0x4000) - value |= (1 << 2) | (2 << 0); + if (1 == 1 || state->revision > 0x4000) + state->div_force_off = 0; else - value |= 0; - dib7000m_write_word(state, 266 + state->reg_offs, value); + state->div_force_off = 1; + dib7000m_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -604,70 +910,48 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of for (value = 0; value < 4; value++) dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]); - // set power-up level: interf+analog+AGC - dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); - dib7000m_set_adc_state(state, DIBX000_ADC_ON); - - msleep(7); - - //AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000m_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000m_update_lna(state); - dib7000m_agc_soft_split(state); - - // wait AGC accurate lock time - msleep(7); - - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); - // set power-up level: autosearch dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); } -static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; + struct dvb_frontend_parameters schan; int ret = 0; - u32 value; + u32 value, factor; - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; + schan = *ch; - dib7000m_set_channel(state, &auto_ch, 7); + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000m_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time // start search value = dib7000m_read_word(state, 0); - ret |= dib7000m_write_word(state, 0, value | (1 << 9)); + ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); /* clear n_irq_pending */ if (state->revision == 0x4000) @@ -685,12 +969,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) u16 irq_pending = dib7000m_read_word(state, reg); if (irq_pending & 0x1) { // failed - dprintk("#\n"); + dprintk( "autosearch failed"); return 1; } if (irq_pending & 0x2) { // succeeded - dprintk("!\n"); + dprintk( "autosearch succeeded"); return 2; } return 0; // still pending @@ -705,7 +989,7 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) return dib7000m_autosearch_irq(state, 537); } -static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; int ret = 0; @@ -722,182 +1006,103 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel ret |= dib7000m_write_word(state, 898, 0x0000); msleep(45); - ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); + dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); - // never achieved a lock with that bandwidth so far - wait for timfreq to update + // never achieved a lock before - wait for timfreq to update if (state->timf == 0) msleep(200); //dump_reg(state); /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ value = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: value |= (7 << 12); break; - case 1: value |= (9 << 12); break; - case 2: value |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (7 << 12); break; + case /* 4K MODE */ 255: value |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: value |= (9 << 12); break; } ret |= dib7000m_write_word(state, 26, value); /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 32, value); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 33, value); - // we achieved a lock - it's time to update the osc freq + // we achieved a lock - it's time to update the timf freq if ((dib7000m_read_word(state, 535) >> 6) & 0x1) - dib7000m_update_timf_freq(state); + dib7000m_update_timf(state); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return ret; } -static int dib7000m_init(struct dvb_frontend *demod) +static int dib7000m_wakeup(struct dvb_frontend *demod) { struct dib7000m_state *state = demod->demodulator_priv; - int ret = 0; - u8 o = state->reg_offs; dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk("-E- could not start Slow ADC\n"); + dprintk( "could not start Slow ADC"); - if (state->cfg.dvbt_mode) - dib7000m_write_word(state, 1796, 0x0); // select DVB-T output - - if (state->cfg.mobile_mode) - ret |= dib7000m_write_word(state, 261 + o, 2); - else - ret |= dib7000m_write_word(state, 224 + o, 1); - - ret |= dib7000m_write_word(state, 173 + o, 0); - ret |= dib7000m_write_word(state, 174 + o, 0); - ret |= dib7000m_write_word(state, 175 + o, 0); - ret |= dib7000m_write_word(state, 176 + o, 0); - ret |= dib7000m_write_word(state, 177 + o, 0); - ret |= dib7000m_write_word(state, 178 + o, 0); - ret |= dib7000m_write_word(state, 179 + o, 0); - ret |= dib7000m_write_word(state, 180 + o, 0); - - // P_corm_thres Lock algorithms configuration - ret |= dib7000m_write_word(state, 26, 0x6680); - - // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on - ret |= dib7000m_write_word(state, 170 + o, 0x0410); - // P_fft_nb_to_cut - ret |= dib7000m_write_word(state, 182 + o, 8192); - // P_pha3_thres - ret |= dib7000m_write_word(state, 195 + o, 0x0ccd); - // P_cti_use_cpe, P_cti_use_prog - ret |= dib7000m_write_word(state, 196 + o, 0); - // P_cspu_regul, P_cspu_win_cut - ret |= dib7000m_write_word(state, 205 + o, 0x200f); - // P_adp_regul_cnt - ret |= dib7000m_write_word(state, 214 + o, 0x023d); - // P_adp_noise_cnt - ret |= dib7000m_write_word(state, 215 + o, 0x00a4); - // P_adp_regul_ext - ret |= dib7000m_write_word(state, 216 + o, 0x00a4); - // P_adp_noise_ext - ret |= dib7000m_write_word(state, 217 + o, 0x7ff0); - // P_adp_fil - ret |= dib7000m_write_word(state, 218 + o, 0x3ccc); - - // P_2d_byp_ti_num - ret |= dib7000m_write_word(state, 226 + o, 0); - - // P_fec_* - ret |= dib7000m_write_word(state, 281 + o, 0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000m_write_word(state, 294 + o,0x0062); - - // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000m_write_word(state, 36, 0x0755); - else - ret |= dib7000m_write_word(state, 36, 0x1f55); - - // auto search configuration - ret |= dib7000m_write_word(state, 2, 0x0004); - ret |= dib7000m_write_word(state, 3, 0x1000); - ret |= dib7000m_write_word(state, 4, 0x0814); - ret |= dib7000m_write_word(state, 6, 0x001b); - ret |= dib7000m_write_word(state, 7, 0x7740); - ret |= dib7000m_write_word(state, 8, 0x005b); - ret |= dib7000m_write_word(state, 9, 0x8d80); - ret |= dib7000m_write_word(state, 10, 0x01c9); - ret |= dib7000m_write_word(state, 11, 0xc380); - ret |= dib7000m_write_word(state, 12, 0x0000); - ret |= dib7000m_write_word(state, 13, 0x0080); - ret |= dib7000m_write_word(state, 14, 0x0000); - ret |= dib7000m_write_word(state, 15, 0x0090); - ret |= dib7000m_write_word(state, 16, 0x0001); - ret |= dib7000m_write_word(state, 17, 0xd4c0); - ret |= dib7000m_write_word(state, 263 + o,0x0001); - - // P_divclksel=3 P_divbitsel=1 - if (state->revision == 0x4000) - dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); - else - dib7000m_write_word(state, 909, (3 << 4) | 1); - - // Tuner IO bank: max drive (14mA) - ret |= dib7000m_write_word(state, 912 ,0x2c8a); - - ret |= dib7000m_write_word(state, 1817, 1); - - return ret; + return 0; } static int dib7000m_sleep(struct dvb_frontend *demod) { struct dib7000m_state *st = demod->demodulator_priv; dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); - return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) | - dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | + dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); + return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib7000m_set_adc_state(st, DIBX000_ADC_OFF); } static int dib7000m_identify(struct dib7000m_state *state) { u16 value; + if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { - dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (0x%x)",value); return -EREMOTEIO; } state->revision = dib7000m_read_word(state, 897); if (state->revision != 0x4000 && state->revision != 0x4001 && - state->revision != 0x4002) { - dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value); + state->revision != 0x4002 && + state->revision != 0x4003) { + dprintk( "wrong Device ID (0x%x)",value); return -EREMOTEIO; } /* protect this driver to be used with 7000PC */ if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { - dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n"); + dprintk( "this driver does not work with DiB7000PC"); return -EREMOTEIO; } switch (state->revision) { - case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break; - case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break; - case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break; + case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; + case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; + case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; + case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; } return 0; @@ -966,41 +1171,45 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000m_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000m_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000m_autosearch_start(fe, &ch); + dib7000m_autosearch_start(fe, fep); do { msleep(1); found = dib7000m_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000m_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000m_tune(fe, &ch); + return dib7000m_tune(fe, fep); } static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -1087,7 +1296,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau if (dib7000m_identify(&st) != 0) { st.i2c_addr = default_addr; if (dib7000m_identify(&st) != 0) { - dprintk("DiB7000M #%d: not identified\n", k); + dprintk("DiB7000M #%d: not identified", k); return -EIO; } } @@ -1100,7 +1309,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1172,7 +1381,7 @@ static struct dvb_frontend_ops dib7000m_ops = { .release = dib7000m_release, - .init = dib7000m_init, + .init = dib7000m_wakeup, .sleep = dib7000m_sleep, .set_frontend = dib7000m_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index c24189fcbc89..156c53ab56db 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1,7 +1,7 @@ /* * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,7 +18,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) struct dib7000p_state { struct dvb_frontend demod; @@ -36,12 +36,19 @@ struct dib7000p_state { struct dibx000_agc_config *current_agc; u32 timf; + uint8_t div_force_off : 1; + uint8_t div_state : 1; + uint16_t div_sync_wait; + + u8 agc_state; + u16 gpio_dir; u16 gpio_val; }; enum dib7000p_power_mode { DIB7000P_POWER_ALL = 0, + DIB7000P_POWER_ANALOG_ADC, DIB7000P_POWER_INTERFACE_ONLY, }; @@ -55,7 +62,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -71,6 +78,22 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + do { + dib7000p_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) { int ret = 0; @@ -80,7 +103,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { @@ -104,19 +127,17 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 512; outreg = (1 << 10) | (5 << 6); break; + case OUTMODE_ANALOG_ADC: + outreg = (1 << 10) | (3 << 6); + break; case OUTMODE_HIGH_Z: // disable outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } - if (state->cfg.hostbus_diversity) { - ret |= dib7000p_write_word(state, 204, 1); // Diversity ? - ret |= dib7000p_write_word(state, 205, 0); // Diversity ? - } - if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5) ; @@ -127,6 +148,30 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) return ret; } +static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000p_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (uint8_t)onoff; + + if (onoff) { + dib7000p_write_word(state, 204, 6); + dib7000p_write_word(state, 205, 16); + /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ + dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000p_write_word(state, 204, 1); + dib7000p_write_word(state, 205, 0); + dib7000p_write_word(state, 207, 0); + } + + return 0; +} + static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) { /* by default everything is powered off */ @@ -139,10 +184,21 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p case DIB7000P_POWER_ALL: reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff; break; + + case DIB7000P_POWER_ANALOG_ADC: + /* dem, cfg, iqc, sad, agc */ + reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); + /* nud */ + reg_776 &= ~((1 << 0)); + /* Dout */ + reg_1280 &= ~((1 << 11)); + /* fall through wanted to enable the interfaces */ + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); break; + /* TODO following stuff is just converted from the dib7000-driver - check when is used what */ } @@ -193,34 +249,31 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad break; } -// dprintk("908: %x, 909: %x\n", reg_908, reg_909); +// dprintk( "908: %x, 909: %x\n", reg_908, reg_909); dib7000p_write_word(state, 908, reg_908); dib7000p_write_word(state, 909, reg_909); } -static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) +static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) { - struct dib7000p_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = BW_Idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); + dprintk( "using default timf"); timf = state->cfg.bw->timf; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dprintk("timf: %d\n",timf); - - dib7000p_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000p_write_word(state, 24, (timf ) & 0xffff); + dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff)); return 0; } @@ -228,7 +281,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) static int dib7000p_sad_calib(struct dib7000p_state *state) { /* internal */ -// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096 @@ -244,15 +297,24 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; + u16 clk_cfg0; + /* force PLL bypass */ + clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | + (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | + (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); + + dib7000p_write_word(state, 900, clk_cfg0); + + /* P_pll_cfg */ dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); - dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) | - (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0)); + clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); + dib7000p_write_word(state, 900, clk_cfg0); - dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff); - dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff); + dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff)); + dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff)); dib7000p_write_word(state, 72, bw->sad_cfg); } @@ -260,7 +322,7 @@ static void dib7000p_reset_pll(struct dib7000p_state *state) static int dib7000p_reset_gpio(struct dib7000p_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); + dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1029, st->gpio_dir); dib7000p_write_word(st, 1030, st->gpio_val); @@ -273,6 +335,98 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) return 0; } +static u16 dib7000p_defaults[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, /* Equal Lock */ + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 + + /* set ADC level to -16 */ + 11, 79, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + 1, 142, + 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 + + /* disable power smoothing */ + 8, 145, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 154, + 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 + + 1, 168, + 0x0ccd, // P_pha3_thres, default 0x3000 + +// 1, 169, +// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 + + 1, 183, + 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 + + 5, 187, + 0x023d, // P_adp_regul_cnt=573, default: 410 + 0x00a4, // P_adp_noise_cnt= + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 198, + 0x800, // P_equal_thres_wgn + + 1, 222, + 0x0010, // P_fec_ber_rs_len=2 + + 1, 235, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 2, 901, + 0x0006, // P_clk_cfg1 + (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1 + + 1, 905, + 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive + + 0, +}; + static int dib7000p_demod_reset(struct dib7000p_state *state) { dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); @@ -297,47 +451,34 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_reset_pll(state); if (dib7000p_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) ); + dib7000p_set_bandwidth(state, 8000); + + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); + dib7000p_sad_calib(state); + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + + // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000p_write_word(state, 36,0x0755); + else + dib7000p_write_word(state, 36,0x1f55); + + dib7000p_write_tab(state, dib7000p_defaults); + dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + return 0; } -static void dib7000p_restart_agc(struct dib7000p_state *state) -{ - // P_restart_iqc & P_restart_agc - dib7000p_write_word(state, 770, 0x0c00); - dib7000p_write_word(state, 770, 0x0000); -} - -static void dib7000p_update_lna(struct dib7000p_state *state) -{ - int i; - u16 dyn_gain; - - // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return; - - for (i = 0; i < 5; i++) { - // read dyn_gain here (because it is demod-dependent and not tuner) - dyn_gain = dib7000p_read_word(state, 394); - - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed - dib7000p_restart_agc(state); - msleep(5); - } else - break; - } -} - static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) { u16 tmp = 0; @@ -347,61 +488,270 @@ static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock } -static void dib7000p_update_timf_freq(struct dib7000p_state *state) +static void dib7000p_restart_agc(struct dib7000p_state *state) { - u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); - dib7000p_write_word(state, 23, (u16) (timf >> 16)); - dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + // P_restart_iqc & P_restart_agc + dib7000p_write_word(state, 770, (1 << 11) | (1 << 9)); + dib7000p_write_word(state, 770, 0x0000); } -static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static int dib7000p_update_lna(struct dib7000p_state *state) { - u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208; + u16 dyn_gain; + + // when there is no LNA to program return immediatly + if (state->cfg.update_lna) { + // read dyn_gain here (because it is demod-dependent and not tuner) + dyn_gain = dib7000p_read_word(state, 394); + if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed + dib7000p_restart_agc(state); + return 1; + } + } + + return 0; +} + +static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) +{ + struct dibx000_agc_config *agc = NULL; + int i; + if (state->current_band == band && state->current_agc != NULL) + return 0; + state->current_band = band; + + for (i = 0; i < state->cfg.agc_config_count; i++) + if (state->cfg.agc[i].band_caps & band) { + agc = &state->cfg.agc[i]; + break; + } + + if (agc == NULL) { + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; + } + + state->current_agc = agc; + + /* AGC */ + dib7000p_write_word(state, 75 , agc->setup ); + dib7000p_write_word(state, 76 , agc->inv_gain ); + dib7000p_write_word(state, 77 , agc->time_stabiliz ); + dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); + + // Demod AGC loop configuration + dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); + dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); + + /* AGC continued */ + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", + state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); + + if (state->wbd_ref != 0) + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); + else + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); + + dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); + + dib7000p_write_word(state, 107, agc->agc1_max); + dib7000p_write_word(state, 108, agc->agc1_min); + dib7000p_write_word(state, 109, agc->agc2_max); + dib7000p_write_word(state, 110, agc->agc2_min); + dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib7000p_write_word(state, 112, agc->agc1_pt3); + dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + return 0; +} + +static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000p_state *state = demod->demodulator_priv; + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + dib7000p_set_adc_state(state, DIBX000_ADC_ON); + dib7000p_pll_clk_cfg(state); + + if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; + (*agc_state)++; + break; + + case 1: + // AGC initialization + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000p_write_word(state, 78, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + /* force 0 split on WBD and restart AGC */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000p_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (uint8_t)dib7000p_read_word(state, 396); /* store the split value for the next time */ + dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ + + dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000p_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + // wait AGC accurate lock time + ret = 7; + + if (dib7000p_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else // nothing was done, go to the next state + (*agc_state)++; + break; + + case 5: + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + (*agc_state)++; + break; + default: + break; + } + return ret; +} + +static void dib7000p_update_timf(struct dib7000p_state *state) +{ + u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); + state->timf = timf * 160 / (state->current_bandwidth / 50); + dib7000p_write_word(state, 23, (u16) (timf >> 16)); + dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf); + +} + +static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) +{ + u16 value, est[4]; + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000p_write_word(state, 0, value); dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - tmp |= (ch->vit_code_rate_hp << 1); - else - tmp |= (ch->vit_code_rate_lp << 1); - dib7000p_write_word(state, 208, tmp); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib7000p_write_word(state, 208, value); + + /* offset loop parameters */ + dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) + dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 + dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: tmp = 256; break; - case 2: tmp = 128; break; - case 0: - default: tmp = 64; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; } - tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - tmp <<= 4; + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO - /* deactive the possibility of diversity reception if extended interleave */ - /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || ch->nfft == 1) - tmp |= (1 << 2) | (2 << 0); - dib7000p_write_word(state, 207, tmp); - - dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 - dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) - dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) + /* deactive the possibility of diversity reception if extended interleaver */ + state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; + dib7000p_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -414,66 +764,45 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_of est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ break; } - for (tmp = 0; tmp < 4; tmp++) - dib7000p_write_word(state, 187 + tmp, est[tmp]); - - // set power-up level: interf+analog+AGC - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); - dib7000p_set_adc_state(state, DIBX000_ADC_ON); - dib7000p_pll_clk_cfg(state); - msleep(7); - - // AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000p_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000p_update_lna(state); - - // wait AGC accurate lock time - msleep(7); - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); + for (value = 0; value < 4; value++) + dib7000p_write_word(state, 187 + value, est[value]); } -static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; - u32 value; + struct dvb_frontend_parameters schan; + u32 value, factor; - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; + schan = *ch; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; - dib7000p_set_channel(state, &auto_ch, 7); + dib7000p_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time value = dib7000p_read_word(state, 0); - dib7000p_write_word(state, 0, (1 << 9) | value); + dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); dib7000p_read_word(state, 1284); dib7000p_write_word(state, 0, (u16) value); @@ -494,7 +823,95 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) +{ + static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392}; + static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, + 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, + 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, + 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, + 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, + 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, + 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, + 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, + 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, + 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, + 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, + 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255}; + + u32 xtal = state->cfg.bw->xtal_hz / 1000; + int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz; + int k; + int coef_re[8],coef_im[8]; + int bw_khz = bw; + u32 pha; + + dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); + + + if (f_rel < -bw_khz/2 || f_rel > bw_khz/2) + return; + + bw_khz /= 100; + + dib7000p_write_word(state, 142 ,0x0610); + + for (k = 0; k < 8; k++) { + pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff; + + if (pha==0) { + coef_re[k] = 256; + coef_im[k] = 0; + } else if(pha < 256) { + coef_re[k] = sine[256-(pha&0xff)]; + coef_im[k] = sine[pha&0xff]; + } else if (pha == 256) { + coef_re[k] = 0; + coef_im[k] = 256; + } else if (pha < 512) { + coef_re[k] = -sine[pha&0xff]; + coef_im[k] = sine[256 - (pha&0xff)]; + } else if (pha == 512) { + coef_re[k] = -256; + coef_im[k] = 0; + } else if (pha < 768) { + coef_re[k] = -sine[256-(pha&0xff)]; + coef_im[k] = -sine[pha&0xff]; + } else if (pha == 768) { + coef_re[k] = 0; + coef_im[k] = -256; + } else { + coef_re[k] = sine[pha&0xff]; + coef_im[k] = -sine[256 - (pha&0xff)]; + } + + coef_re[k] *= notch[k]; + coef_re[k] += (1<<14); + if (coef_re[k] >= (1<<24)) + coef_re[k] = (1<<24) - 1; + coef_re[k] /= (1<<15); + + coef_im[k] *= notch[k]; + coef_im[k] += (1<<14); + if (coef_im[k] >= (1<<24)) + coef_im[k] = (1<<24)-1; + coef_im[k] /= (1<<15); + + dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); + + dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); + dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + } + dib7000p_write_word(state,143 ,0); +} + +static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; u16 tmp = 0; @@ -520,28 +937,31 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ tmp = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: tmp |= (7 << 12); break; - case 1: tmp |= (9 << 12); break; - case 2: tmp |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break; + case /* 4K MODE */ 255: tmp |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break; } dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 32, tmp); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 33, tmp); @@ -557,131 +977,21 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel // we achieved a lock - it's time to update the osc freq if ((tmp >> 6) & 0x1) - dib7000p_update_timf_freq(state); + dib7000p_update_timf(state); + if (state->cfg.spur_protect) + dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return 0; } -static int dib7000p_init(struct dvb_frontend *demod) +static int dib7000p_wakeup(struct dvb_frontend *demod) { - struct dibx000_agc_config *agc; struct dib7000p_state *state = demod->demodulator_priv; - int ret = 0; - - // Demodulator default configuration - agc = state->cfg.agc; - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); - - /* AGC */ - ret |= dib7000p_write_word(state, 75 , agc->setup ); - ret |= dib7000p_write_word(state, 76 , agc->inv_gain ); - ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz ); - ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); - - // Demod AGC loop configuration - ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); - ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); - - /* AGC continued */ - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", - state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); - - if (state->wbd_ref != 0) - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); - else - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); - - ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) ); - - ret |= dib7000p_write_word(state, 107, agc->agc1_max); - ret |= dib7000p_write_word(state, 108, agc->agc1_min); - ret |= dib7000p_write_word(state, 109, agc->agc2_max); - ret |= dib7000p_write_word(state, 110, agc->agc2_min); - ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 ); - ret |= dib7000p_write_word(state, 112, agc->agc1_pt3); - ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - - /* disable power smoothing */ - ret |= dib7000p_write_word(state, 145, 0); - ret |= dib7000p_write_word(state, 146, 0); - ret |= dib7000p_write_word(state, 147, 0); - ret |= dib7000p_write_word(state, 148, 0); - ret |= dib7000p_write_word(state, 149, 0); - ret |= dib7000p_write_word(state, 150, 0); - ret |= dib7000p_write_word(state, 151, 0); - ret |= dib7000p_write_word(state, 152, 0); - - // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 - ret |= dib7000p_write_word(state, 26 ,0x6680); - - // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 - ret |= dib7000p_write_word(state, 142,0x0410); - // P_fft_freq_dir=1, P_fft_nb_to_cut=0 - ret |= dib7000p_write_word(state, 154,1 << 13); - // P_pha3_thres, default 0x3000 - ret |= dib7000p_write_word(state, 168,0x0ccd); - // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 - //ret |= dib7000p_write_word(state, 169,0x0010); - // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 - ret |= dib7000p_write_word(state, 183,0x200f); - // P_adp_regul_cnt=573, default: 410 - ret |= dib7000p_write_word(state, 187,0x023d); - // P_adp_noise_cnt= - ret |= dib7000p_write_word(state, 188,0x00a4); - // P_adp_regul_ext - ret |= dib7000p_write_word(state, 189,0x00a4); - // P_adp_noise_ext - ret |= dib7000p_write_word(state, 190,0x7ff0); - // P_adp_fil - ret |= dib7000p_write_word(state, 191,0x3ccc); - - ret |= dib7000p_write_word(state, 222,0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000p_write_word(state, 235,0x0062); - - // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000p_write_word(state, 36,0x0755); - else - ret |= dib7000p_write_word(state, 36,0x1f55); - - // auto search configuration - ret |= dib7000p_write_word(state, 2 ,0x0004); - ret |= dib7000p_write_word(state, 3 ,0x1000); - - /* Equal Lock */ - ret |= dib7000p_write_word(state, 4 ,0x0814); - - ret |= dib7000p_write_word(state, 6 ,0x001b); - ret |= dib7000p_write_word(state, 7 ,0x7740); - ret |= dib7000p_write_word(state, 8 ,0x005b); - ret |= dib7000p_write_word(state, 9 ,0x8d80); - ret |= dib7000p_write_word(state, 10 ,0x01c9); - ret |= dib7000p_write_word(state, 11 ,0xc380); - ret |= dib7000p_write_word(state, 12 ,0x0000); - ret |= dib7000p_write_word(state, 13 ,0x0080); - ret |= dib7000p_write_word(state, 14 ,0x0000); - ret |= dib7000p_write_word(state, 15 ,0x0090); - ret |= dib7000p_write_word(state, 16 ,0x0001); - ret |= dib7000p_write_word(state, 17 ,0xd4c0); - - // P_clk_cfg1 - ret |= dib7000p_write_word(state, 901, 0x0006); - - // P_divclksel=3 P_divbitsel=1 - ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6)); - - // Tuner IO bank: max drive (14mA) + divout pads max drive - ret |= dib7000p_write_word(state, 905, 0x2c8e); - - ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); - dib7000p_sad_calib(state); - - return ret; + return 0; } static int dib7000p_sleep(struct dvb_frontend *demod) @@ -693,16 +1003,16 @@ static int dib7000p_sleep(struct dvb_frontend *demod) static int dib7000p_identify(struct dib7000p_state *st) { u16 value; - dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n", + dprintk( "checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { - dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (read=0x%x)",value); return -EREMOTEIO; } if ((value = dib7000p_read_word(st, 769)) != 0x4000) { - dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value); + dprintk( "wrong Device ID (%x)",value); return -EREMOTEIO; } @@ -772,41 +1082,45 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000p_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000p_autosearch_start(fe, &ch); + dib7000p_autosearch_start(fe, fep); do { msleep(1); found = dib7000p_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000p_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000p_tune(fe, &ch); + return dib7000p_tune(fe, fep); } static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -884,7 +1198,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } @@ -892,11 +1206,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } - dprintk("-D- DiB7000PC not detected\n"); + dprintk("-D- DiB7000PC not detected"); return 0; } EXPORT_SYMBOL(dib7000pc_detection); @@ -934,7 +1248,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1005,7 +1319,7 @@ static struct dvb_frontend_ops dib7000p_ops = { .release = dib7000p_release, - .init = dib7000p_init, + .init = dib7000p_wakeup, .sleep = dib7000p_sleep, .set_frontend = dib7000p_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 94829c1ed054..e7769e7cd92a 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -9,6 +9,7 @@ struct dib7000p_config { u8 tuner_is_baseband; int (*update_lna) (struct dvb_frontend *, u16 agc_global); + u8 agc_config_count; struct dibx000_agc_config *agc; struct dibx000_bandwidth_config *bw; @@ -27,15 +28,19 @@ struct dib7000p_config { u8 quartz_direct; + u8 spur_protect; + int (*agc_control) (struct dvb_frontend *, u8 before); }; #define DEFAULT_DIB7000P_I2C_ADDRESS 18 extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + /* TODO extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index a1df604366c3..5e17275afd25 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -111,6 +111,8 @@ struct dibx000_bandwidth_config { u32 ifreq; u32 timf; + + u32 xtal_hz; }; enum dibx000_adc_states { @@ -122,56 +124,17 @@ enum dibx000_adc_states { DIBX000_VBG_DISABLE, }; -#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ +#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ (v) == BANDWIDTH_7_MHZ ? 7000 : \ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) /* Chip output mode. */ -#define OUTMODE_HIGH_Z 0 -#define OUTMODE_MPEG2_PAR_GATED_CLK 1 -#define OUTMODE_MPEG2_PAR_CONT_CLK 2 -#define OUTMODE_MPEG2_SERIAL 7 -#define OUTMODE_DIVERSITY 4 -#define OUTMODE_MPEG2_FIFO 5 - -/* I hope I can get rid of the following kludge in the near future */ -struct dibx000_ofdm_channel { - u32 RF_kHz; - u8 Bw; - s16 nfft; - s16 guard; - s16 nqam; - s16 vit_hrch; - s16 vit_select_hp; - s16 vit_alpha; - s16 vit_code_rate_hp; - s16 vit_code_rate_lp; - u8 intlv_native; -}; - -#define FEP2DIB(fep,ch) \ - (ch)->RF_kHz = (fep)->frequency / 1000; \ - (ch)->Bw = (fep)->u.ofdm.bandwidth; \ - (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \ - (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \ - (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \ - (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \ - (ch)->vit_select_hp = 1; \ - (ch)->vit_alpha = 1; \ - (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \ - (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \ - (ch)->intlv_native = 1; - -#define INIT_OFDM_CHANNEL(ch) do {\ - (ch)->Bw = 0; \ - (ch)->nfft = -1; \ - (ch)->guard = -1; \ - (ch)->nqam = -1; \ - (ch)->vit_hrch = -1; \ - (ch)->vit_select_hp = -1; \ - (ch)->vit_alpha = -1; \ - (ch)->vit_code_rate_hp = -1; \ - (ch)->vit_code_rate_lp = -1; \ -} while (0) +#define OUTMODE_HIGH_Z 0 +#define OUTMODE_MPEG2_PAR_GATED_CLK 1 +#define OUTMODE_MPEG2_PAR_CONT_CLK 2 +#define OUTMODE_MPEG2_SERIAL 7 +#define OUTMODE_DIVERSITY 4 +#define OUTMODE_MPEG2_FIFO 5 +#define OUTMODE_ANALOG_ADC 6 #endif diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 145135778bce..33b388e8f7b8 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -159,7 +159,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame b[3] = tune >> 13; mt2266_writeregs(priv,b,4); - dprintk("set_parms: tune=%d band=%d\n",(int)tune,(int)lnaband); + dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); b[0] = 0x05; @@ -176,7 +176,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame msleep(10); i++; } while (i<10); - dprintk("Lock when i=%i\n",(int)i); + dprintk("Lock when i=%i",(int)i); return ret; } From 01373a5c97ced83d4cb520f7e56c80454a198bfb Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 12:49:04 -0300 Subject: [PATCH 0551/2804] V4L/DVB (5955): Add support for DiB7070-based devices This changeset adds support for DiB7070P-based devices by adding the dib0070-driver and putting the appropriate layouts into dib0700_devices.c It also includes a new firmware for the dib0700 which is necessary to make the DiB7070-boards work and it also should fix the i2c-problems on some boards. Signed-off-by: Jean-Philippe Sibers Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + drivers/media/dvb/dvb-usb/dib0700_devices.c | 295 +++++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 10 +- drivers/media/dvb/frontends/Kconfig | 9 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dib0070.c | 580 ++++++++++++++++++++ drivers/media/dvb/frontends/dib0070.h | 44 ++ drivers/media/dvb/frontends/dib3000mc.c | 2 +- drivers/media/dvb/frontends/dib7000m.c | 12 +- drivers/media/dvb/frontends/dib7000p.c | 44 +- drivers/media/dvb/frontends/dib7000p.h | 9 +- 11 files changed, 974 insertions(+), 33 deletions(-) create mode 100644 drivers/media/dvb/frontends/dib0070.c create mode 100644 drivers/media/dvb/frontends/dib0070.h diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index dec03ee32e1a..d73934dd4c57 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -75,6 +75,7 @@ config DVB_USB_DIB0700 select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 04b66f6e659f..558ab3bd6889 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -13,13 +13,18 @@ #include "dib7000p.h" #include "mt2060.h" #include "mt2266.h" +#include "dib0070.h" static int force_lna_activation; module_param(force_lna_activation, int, 0644); MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " "if applicable for the device (default: 0=automatic/off)."); -/* Hauppauge Nova-T 500 +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); +}; + +/* Hauppauge Nova-T 500 (aka Bristol) * has a LNA on GPIO0 which is enabled by setting 1 */ static struct mt2060_config bristol_mt2060_config[2] = { { @@ -97,7 +102,7 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; } -/* STK7700D: Pinnacle Dual DVB-T Diversity */ +/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ /* MT226x */ static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { @@ -539,31 +544,243 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[0]) == NULL ? -ENODEV : 0; } +/* DIB7070 generic */ +static struct dibx000_agc_config dib7070_agc_config = { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + 600, // inv_gain + 10, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 5, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + + 65535, // agc2_max + 0, // agc2_min + + 0, // agc1_pt1 + 40, // agc1_pt2 + 183, // agc1_pt3 + 206, // agc1_slope1 + 255, // agc1_slope2 + 72, // agc2_pt1 + 152, // agc2_pt2 + 88, // agc2_slope1 + 90, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 0, // perform_agc_softsplit +}; + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 9, 0, onoff); +} + +static struct dib0070_config dib7070p_dib0070_config[2] = { + { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 4 + }, { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + + } +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe, fep); +} + +static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (adap->id == 0) { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + return -ENODEV; + } else { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + return -ENODEV; + } + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + 60000, 15000, // internal, sampling + 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + (0 << 25) | 0, // ifreq = 0.000000 MHz + 20452225, // timf + 12000000, // xtal_hz +}; + +static struct dib7000p_config dib7070p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +/* STK7070P */ +static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* STK7070PD */ +static struct dib7000p_config stk7070pd_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + } +}; + +static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* DVB-USB and USB stuff follows */ struct usb_device_id dib0700_usb_id_table[] = { - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, +/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, +/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, +/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, - { } /* Terminating entry */ +/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ .usb_ctrl = DEVICE_SPECIFIC, \ - .firmware = "dvb-usb-dib0700-01.fw", \ + .firmware = "dvb-usb-dib0700-03-pre1.fw", \ .download_firmware = dib0700_download_firmware, \ .no_reconnect = 1, \ .size_of_priv = sizeof(struct dib0700_state), \ @@ -675,11 +892,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[12], NULL }, { NULL }, }, - { "Haupauge Nova-TD Stick", + { "Haupauge Nova-TD Stick/Elgato Eye-TV Diversity", { &dib0700_usb_id_table[13], NULL }, { NULL }, }, - { "DiBcom STK7700D", + { "DiBcom STK7700D reference design", { &dib0700_usb_id_table[14], NULL }, { NULL }, }, @@ -688,7 +905,65 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map = stk7700d_rc_keys, .rc_key_map_size = KEY_MAP_SIZE, .rc_query = stk7700d_rc_query - } + + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = stk7070p_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "DiBcom STK7070P reference design", + { &dib0700_usb_id_table[15], NULL }, + { NULL }, + }, + { "Pinnacle PCTV DVB-T Flash Stick", + { &dib0700_usb_id_table[16], NULL }, + { NULL }, + }, + } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = stk7070pd_frontend_attach0, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .frontend_attach = stk7070pd_frontend_attach1, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 2, + .devices = { + { "DiBcom STK7070PD reference design", + { &dib0700_usb_id_table[17], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Dual DVB-T Diversity Stick", + { &dib0700_usb_id_table[18], NULL }, + { NULL }, + }, + } + }, }; int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 5657ad8beaac..dae605bbd0f9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -68,6 +68,8 @@ #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 #define USB_PID_DIBCOM_STK7700D 0x1ef0 +#define USB_PID_DIBCOM_STK7070P 0x1ebc +#define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 @@ -122,6 +124,11 @@ #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_PINNACLE_PCTV2000E 0x022c +#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 +#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 +#define USB_PID_PCTV_200E 0x020e +#define USB_PID_PCTV_400E 0x020f +#define USB_PID_PCTV_450E 0x0222 #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 @@ -141,9 +148,6 @@ #define USB_PID_MSI_MEGASKY580_55801 0x5581 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f -#define USB_PID_PCTV_200E 0x020e -#define USB_PID_PCTV_400E 0x020f -#define USB_PID_PCTV_450E 0x0222 #define USB_PID_LITEON_DVB_T_COLD 0xf000 #define USB_PID_LITEON_DVB_T_WARM 0xf001 #define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index faf9fe3c9cce..53e775539649 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -344,6 +344,15 @@ config DVB_TUNER_MT2131 help A driver for the silicon baseband tuner MT2131 from Microtune. +config DVB_TUNER_DIB0070 + tristate "DiBcom DiB0070 silicon base-band tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner DiB0070 from DiBcom. + This device is only used inside a SiP called togther with a + demodulator for now. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index c46b9d8e9313..4b8ad1f132aa 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c new file mode 100644 index 000000000000..481eaa684157 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.c @@ -0,0 +1,580 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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. + */ +#include +#include + +#include "dvb_frontend.h" + +#include "dib0070.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0) + +#define DIB0070_P1D 0x00 +#define DIB0070_P1F 0x01 +#define DIB0070_P1G 0x03 +#define DIB0070S_P1A 0x02 + +struct dib0070_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + const struct dib0070_config *cfg; + u16 wbd_ff_offset; + u8 revision; +}; + +static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) +{ + u8 b[2]; + struct i2c_msg msg[2] = { + { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, + }; + if (i2c_transfer(state->i2c, msg, 2) != 2) { + printk(KERN_WARNING "DiB0070 I2C read failed\n"); + return 0; + } + return (b[0] << 8) | b[1]; +} + +static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) +{ + u8 b[3] = { reg, val >> 8, val & 0xff }; + struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "DiB0070 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0) + +static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *st = fe->tuner_priv; + u16 tmp = 0; + tmp = dib0070_read_reg(st, 0x02) & 0x3fff; + + switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) { + case 8000: + tmp |= (0 << 14); + break; + case 7000: + tmp |= (1 << 14); + break; + case 6000: + tmp |= (2 << 14); + break; + case 5000: + default: + tmp |= (3 << 14); + break; + } + dib0070_write_reg(st, 0x02, tmp); + return 0; +} + +static void dib0070_captrim(struct dib0070_state *st, u16 LO4) +{ + int8_t captrim, fcaptrim, step_sign, step; + u16 adc, adc_diff = 3000; + + + + dib0070_write_reg(st, 0x0f, 0xed10); + dib0070_write_reg(st, 0x17, 0x0034); + + dib0070_write_reg(st, 0x18, 0x0032); + msleep(2); + + step = captrim = fcaptrim = 64; + + do { + step /= 2; + dib0070_write_reg(st, 0x14, LO4 | captrim); + msleep(1); + adc = dib0070_read_reg(st, 0x19); + + dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024); + + if (adc >= 400) { + adc -= 400; + step_sign = -1; + } else { + adc = 400 - adc; + step_sign = 1; + } + + if (adc < adc_diff) { + dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff); + adc_diff = adc; + fcaptrim = captrim; + + + + } + captrim += (step_sign * step); + } while (step >= 1); + + dib0070_write_reg(st, 0x14, LO4 | fcaptrim); + dib0070_write_reg(st, 0x18, 0x07ff); +} + +#define LPF 100 // define for the loop filter 100kHz by default 16-07-06 +#define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7) +#define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12) +#define LO4_SET_CTRIM(l, c) l |= (c) << 10 +static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *st = fe->tuner_priv; + u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf); + + u8 band = BAND_OF_FREQUENCY(freq), c; + + /*******************VCO***********************************/ + u16 lo4 = 0; + + u8 REFDIV, PRESC = 2; + u32 FBDiv, Rest, FREF, VCOF_kHz; + u16 Num, Den; + /*******************FrontEnd******************************/ + u16 value = 0; + + dprintk( "Tuning for Band: %hd (%d kHz)", band, freq); + + + dib0070_write_reg(st, 0x17, 0x30); + + dib0070_set_bandwidth(fe, ch); /* c is used as HF */ + switch (st->revision) { + case DIB0070S_P1A: + switch (band) { + case BAND_LBAND: + LO4_SET_VCO_HFDIV(lo4, 1, 1); + c = 2; + break; + case BAND_SBAND: + LO4_SET_VCO_HFDIV(lo4, 0, 0); + LO4_SET_CTRIM(lo4, 1);; + c = 1; + break; + case BAND_UHF: + default: + if (freq < 570000) { + LO4_SET_VCO_HFDIV(lo4, 1, 3); + PRESC = 6; c = 6; + } else if (freq < 680000) { + LO4_SET_VCO_HFDIV(lo4, 0, 2); + c = 4; + } else { + LO4_SET_VCO_HFDIV(lo4, 1, 2); + c = 4; + } + break; + } break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + switch (band) { + case BAND_FM: + LO4_SET_VCO_HFDIV(lo4, 0, 7); + c = 24; + break; + case BAND_LBAND: + LO4_SET_VCO_HFDIV(lo4, 1, 0); + c = 2; + break; + case BAND_VHF: + if (freq < 180000) { + LO4_SET_VCO_HFDIV(lo4, 0, 3); + c = 16; + } else if (freq < 190000) { + LO4_SET_VCO_HFDIV(lo4, 1, 3); + c = 16; + } else { + LO4_SET_VCO_HFDIV(lo4, 0, 6); + c = 12; + } + break; + + case BAND_UHF: + default: + if (freq < 570000) { + LO4_SET_VCO_HFDIV(lo4, 1, 5); + c = 6; + } else if (freq < 700000) { + LO4_SET_VCO_HFDIV(lo4, 0, 1); + c = 4; + } else { + LO4_SET_VCO_HFDIV(lo4, 1, 1); + c = 4; + } + break; + } + break; + } + + dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf); + dprintk( "VCO = %hd", (lo4 >> 11) & 0x3); + + + VCOF_kHz = (c * freq) * 2; + dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq); + + switch (band) { + case BAND_VHF: + REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000); + break; + case BAND_FM: + REFDIV = (u8) ((st->cfg->clock_khz) / 1000); + break; + default: + REFDIV = (u8) ( st->cfg->clock_khz / 10000); + break; + } + FREF = st->cfg->clock_khz / REFDIV; + + dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF); + + + + switch (st->revision) { + case DIB0070S_P1A: + FBDiv = (VCOF_kHz / PRESC / FREF); + Rest = (VCOF_kHz / PRESC) - FBDiv * FREF; + break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + FBDiv = (freq / (FREF / 2)); + Rest = 2 * freq - FBDiv * FREF; + break; + } + + + if (Rest < LPF) Rest = 0; + else if (Rest < 2 * LPF) Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; } + else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest); + + Num = 0; + Den = 1; + + if (Rest > 0) { + LO4_SET_SD(lo4, 1); + Den = 255; + Num = (u16)Rest; + } + dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1); + + + + dib0070_write_reg(st, 0x11, (u16)FBDiv); + + + dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV); + + + dib0070_write_reg(st, 0x13, Num); + + + value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001; + + switch (band) { + case BAND_UHF: value |= 0x4000 | 0x0800; break; + case BAND_LBAND: value |= 0x2000 | 0x0400; break; + default: value |= 0x8000 | 0x1000; break; + } + dib0070_write_reg(st, 0x20, value); + + dib0070_captrim(st, lo4); + if (st->revision == DIB0070S_P1A) { + if (band == BAND_SBAND) + dib0070_write_reg(st, 0x15, 0x16e2); + else + dib0070_write_reg(st, 0x15, 0x56e5); + } + + + + switch (band) { + case BAND_UHF: value = 0x7c82; break; + case BAND_LBAND: value = 0x7c84; break; + default: value = 0x7c81; break; + } + dib0070_write_reg(st, 0x0f, value); + dib0070_write_reg(st, 0x06, 0x3fff); + + /* Front End */ + /* c == TUNE, value = SWITCH */ + c = 0; + value = 0; + switch (band) { + case BAND_FM: + c = 0; value = 1; + break; + + case BAND_VHF: + if (freq <= 180000) c = 0; + else if (freq <= 188200) c = 1; + else if (freq <= 196400) c = 2; + else c = 3; + value = 1; + break; + + case BAND_LBAND: + if (freq <= 1500000) c = 0; + else if (freq <= 1600000) c = 1; + else c = 3; + break; + + case BAND_SBAND: + c = 7; + dib0070_write_reg(st, 0x1d,0xFFFF); + break; + + case BAND_UHF: + default: + if (st->cfg->flip_chip) { + if (freq <= 550000) c = 0; + else if (freq <= 590000) c = 1; + else if (freq <= 666000) c = 3; + else c = 5; + } else { + if (freq <= 550000) c = 2; + else if (freq <= 650000) c = 3; + else if (freq <= 750000) c = 5; + else if (freq <= 850000) c = 6; + else c = 7; + } + value = 2; + break; + } + + /* default: LNA_MATCH=7, BIAS=3 */ + dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0)); + dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127)); + dib0070_write_reg(st, 0x0d, 0x0d80); + + + dib0070_write_reg(st, 0x18, 0x07ff); + dib0070_write_reg(st, 0x17, 0x0033); + + return 0; +} + +static int dib0070_wakeup(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + if (st->cfg->sleep) + st->cfg->sleep(fe, 0); + return 0; +} + +static int dib0070_sleep(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + if (st->cfg->sleep) + st->cfg->sleep(fe, 1); + return 0; +} + +static u16 dib0070_p1f_defaults[] = + +{ + 7, 0x02, + 0x0008, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0002, + 0x0100, + + 3, 0x0d, + 0x0d80, + 0x0001, + 0x0000, + + 4, 0x11, + 0x0000, + 0x0103, + 0x0000, + 0x0000, + + 3, 0x16, + 0x0004 | 0x0040, + 0x0030, + 0x07ff, + + 6, 0x1b, + 0x4112, + 0xff00, + 0xc07f, + 0x0000, + 0x0180, + 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, + + 0, +}; + +static void dib0070_wbd_calibration(struct dib0070_state *state) +{ + u16 wbd_offs; + dib0070_write_reg(state, 0x0f, 0x6d81); + dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); + msleep(9); + wbd_offs = dib0070_read_reg(state, 0x19); + dib0070_write_reg(state, 0x20, 0); + state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); + dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); +} + +u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + return st->wbd_ff_offset; +} + +EXPORT_SYMBOL(dib0070_wbd_offset); +static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + dprintk( "CTRL_LO5: 0x%x", lo5); + return dib0070_write_reg(state, 0x15, lo5); +} + +#define pgm_read_word(w) (*w) +static int dib0070_reset(struct dib0070_state *state) +{ + u16 l, r, *n; + + HARD_RESET(state); + + +#ifndef FORCE_SBAND_TUNER + if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) + state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; + else +#endif + state->revision = DIB0070S_P1A; + + /* P1F or not */ + dprintk( "Revision: %x", state->revision); + + if (state->revision == DIB0070_P1D) { + dprintk( "Error: this driver is not to be used meant for P1D or earlier"); + return -EINVAL; + } + + n = (u16 *) dib0070_p1f_defaults; + l = pgm_read_word(n++); + while (l) { + r = pgm_read_word(n++); + do { + dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); + r++; + } while (--l); + l = pgm_read_word(n++); + } + + if (state->cfg->force_crystal_mode != 0) + r = state->cfg->force_crystal_mode; + else if (state->cfg->clock_khz >= 24000) + r = 1; + else + r = 2; + + r |= state->cfg->osc_buffer_state << 3; + + dib0070_write_reg(state, 0x10, r); + dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4)); + + if (state->cfg->invert_iq) { + r = dib0070_read_reg(state, 0x02) & 0xffdf; + dib0070_write_reg(state, 0x02, r | (1 << 5)); + } + + + if (state->revision == DIB0070S_P1A) + dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1); + else + dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0); + + dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); + return 0; +} + + +static int dib0070_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static struct dvb_tuner_ops dib0070_ops = { + .info = { + .name = "DiBcom DiB0070", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0070_release, + + .init = dib0070_wakeup, + .sleep = dib0070_sleep, + .set_params = dib0070_tune_digital, +// .get_frequency = dib0070_get_frequency, +// .get_bandwidth = dib0070_get_bandwidth +}; + +struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) +{ + struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->cfg = cfg; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + + if (dib0070_reset(state) != 0) + goto free_mem; + + dib0070_wbd_calibration(state); + + printk(KERN_INFO "DiB0070: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; + +free_mem: + kfree(state); + fe->tuner_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(dib0070_attach); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h new file mode 100644 index 000000000000..786e37d33889 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.h @@ -0,0 +1,44 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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. + */ +#ifndef DIB0070_H +#define DIB0070_H + +struct dvb_frontend; +struct i2c_adapter; + +#define DEFAULT_DIB0070_I2C_ADDRESS 0x60 + +struct dib0070_config { + u8 i2c_address; + + /* tuner pins controlled externally */ + int (*reset) (struct dvb_frontend *, int); + int (*sleep) (struct dvb_frontend *, int); + + /* offset in kHz */ + int freq_offset_khz_uhf; + int freq_offset_khz_vhf; + + u8 osc_buffer_state; /* 0= normal, 1= tri-state */ + u32 clock_khz; + u8 clock_pad_drive; /* (Drive + 1) * 2mA */ + + u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */ + + u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */ + + u8 flip_chip; +}; + +extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); +extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); +extern u16 dib0070_wbd_offset(struct dvb_frontend *); + +#endif diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index cbbe2c2f05dc..38d2322cbaf6 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -593,7 +593,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame // activates isi dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_set_adp_cfg(state, (uint8_t)ch->u.ofdm.constellation); + dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 608156a691de..0ad9f3eb20a6 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -42,9 +42,9 @@ struct dib7000m_state { u32 timf_default; u32 internal_clk; - uint8_t div_force_off : 1; - uint8_t div_state : 1; - uint16_t div_sync_wait; + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; u16 revision; @@ -302,7 +302,7 @@ static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) dprintk( "diversity combination deactivated - forced by COFDM parameters"); onoff = 0; } - state->div_state = (uint8_t)onoff; + state->div_state = (u8)onoff; if (onoff) { dib7000m_write_word(state, 263 + state->reg_offs, 6); @@ -620,7 +620,7 @@ static int dib7000m_update_lna(struct dib7000m_state *state) u16 dyn_gain; if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not tuner) + // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000m_read_word(state, 390); if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed @@ -754,7 +754,7 @@ static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ break; case 3: /* split search ended */ - agc_split = (uint8_t)dib7000m_read_word(state, 392); /* store the split value for the next time */ + agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */ dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 156c53ab56db..1175ab9a4532 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -36,9 +36,9 @@ struct dib7000p_state { struct dibx000_agc_config *current_agc; u32 timf; - uint8_t div_force_off : 1; - uint8_t div_state : 1; - uint16_t div_sync_wait; + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; u8 agc_state; @@ -156,7 +156,7 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) dprintk( "diversity combination deactivated - forced by COFDM parameters"); onoff = 0; } - state->div_state = (uint8_t)onoff; + state->div_state = (u8)onoff; if (onoff) { dib7000p_write_word(state, 204, 6); @@ -294,6 +294,16 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) return 0; } +int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) +{ + struct dib7000p_state *state = demod->demodulator_priv; + if (value > 4095) + value = 4095; + state->wbd_ref = value; + return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value); +} + +EXPORT_SYMBOL(dib7000p_set_wbd_ref); static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; @@ -335,6 +345,28 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) return 0; } +static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val) +{ + st->gpio_dir = dib7000p_read_word(st, 1029); + st->gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + dib7000p_write_word(st, 1029, st->gpio_dir); + + st->gpio_val = dib7000p_read_word(st, 1030); + st->gpio_val &= ~(1 << num); /* reset the direction bit */ + st->gpio_val |= (val & 0x01) << num; /* set the new value */ + dib7000p_write_word(st, 1030, st->gpio_val); + + return 0; +} + +int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val) +{ + struct dib7000p_state *state = demod->demodulator_priv; + return dib7000p_cfg_gpio(state, num, dir, val); +} + +EXPORT_SYMBOL(dib7000p_set_gpio); static u16 dib7000p_defaults[] = { @@ -501,7 +533,7 @@ static int dib7000p_update_lna(struct dib7000p_state *state) // when there is no LNA to program return immediatly if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not tuner) + // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000p_read_word(state, 394); if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000p_restart_agc(state); @@ -617,7 +649,7 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ break; case 3: /* split search ended */ - agc_split = (uint8_t)dib7000p_read_word(state, 396); /* store the split value for the next time */ + agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */ dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index e7769e7cd92a..eefcac8b5244 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -40,12 +40,7 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); - -/* TODO -extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); -extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); -extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff); -extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod); -*/ +extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #endif From 82f3d5594240adcd8d6764cf31dffc473a6cc1d0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Jul 2007 13:50:28 -0300 Subject: [PATCH 0552/2804] V4L/DVB (5956): Add remote control support for the Hauppauge Nova-T 500 This patch adds remote control support for the Hauppauge Nova-T 500 using the same keys as for STK7700PD. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 26 ++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 558ab3bd6889..994e5b8d44a2 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -264,7 +264,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; -static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[4]; int i; @@ -274,7 +274,7 @@ static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) *state = REMOTE_NO_KEY_PRESSED; i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { - err("stk7700d:RC Query Failed\n"); + err("RC Query Failed\n"); return 0; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; @@ -287,14 +287,12 @@ static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } } - err("stk7700d:Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); } return 0; } -#define KEY_MAP_SIZE (25+48) - -static struct dvb_usb_rc_key stk7700d_rc_keys[] = { +static struct dvb_usb_rc_key dib0700_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, { 0x07, 0x01, KEY_MENU }, // Pinnacle logo @@ -370,7 +368,7 @@ static struct dvb_usb_rc_key stk7700d_rc_keys[] = { { 0xeb, 0x54, KEY_PREVIOUS }, { 0xeb, 0x58, KEY_RECORD }, { 0xeb, 0x5c, KEY_NEXT } - }; +}; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { @@ -864,7 +862,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, { NULL }, }, - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, @@ -901,10 +904,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, }, + .rc_interval = DEFAULT_RC_INTERVAL, - .rc_key_map = stk7700d_rc_keys, - .rc_key_map_size = KEY_MAP_SIZE, - .rc_query = stk7700d_rc_query + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, From 7161f27f2e61b44352a9dcf3927813380d5e710b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Jul 2007 13:54:55 -0300 Subject: [PATCH 0553/2804] V4L/DVB (5957): Add remote keymap for the Hauppauge Nova-TD Stick Copied from drivers/media/dvb/dvb-usb/nova-t-usb2.c Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 51 ++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 994e5b8d44a2..fb1a9bf7e591 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -346,7 +346,7 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0xeb, 0x1a, KEY_BLUE }, { 0xeb, 0x1b, KEY_CHANNELUP }, { 0xeb, 0x1c, KEY_VOLUMEUP }, - { 0xeb, 0x1d, KEY_MUTE }, + { 0xeb, 0x1d, KEY_MUTE }, { 0xeb, 0x1e, KEY_VOLUMEDOWN }, { 0xeb, 0x1f, KEY_CHANNELDOWN }, { 0xeb, 0x40, KEY_PAUSE }, @@ -367,7 +367,54 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0xeb, 0x4f, KEY_FASTFORWARD }, { 0xeb, 0x54, KEY_PREVIOUS }, { 0xeb, 0x58, KEY_RECORD }, - { 0xeb, 0x5c, KEY_NEXT } + { 0xeb, 0x5c, KEY_NEXT }, + + /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ + { 0x1e, 0x00, KEY_0 }, + { 0x1e, 0x01, KEY_1 }, + { 0x1e, 0x02, KEY_2 }, + { 0x1e, 0x03, KEY_3 }, + { 0x1e, 0x04, KEY_4 }, + { 0x1e, 0x05, KEY_5 }, + { 0x1e, 0x06, KEY_6 }, + { 0x1e, 0x07, KEY_7 }, + { 0x1e, 0x08, KEY_8 }, + { 0x1e, 0x09, KEY_9 }, + { 0x1e, 0x0a, KEY_KPASTERISK }, + { 0x1e, 0x0b, KEY_RED }, + { 0x1e, 0x0c, KEY_RADIO }, + { 0x1e, 0x0d, KEY_MENU }, + { 0x1e, 0x0e, KEY_GRAVE }, /* # */ + { 0x1e, 0x0f, KEY_MUTE }, + { 0x1e, 0x10, KEY_VOLUMEUP }, + { 0x1e, 0x11, KEY_VOLUMEDOWN }, + { 0x1e, 0x12, KEY_CHANNEL }, + { 0x1e, 0x14, KEY_UP }, + { 0x1e, 0x15, KEY_DOWN }, + { 0x1e, 0x16, KEY_LEFT }, + { 0x1e, 0x17, KEY_RIGHT }, + { 0x1e, 0x18, KEY_VIDEO }, + { 0x1e, 0x19, KEY_AUDIO }, + { 0x1e, 0x1a, KEY_MEDIA }, + { 0x1e, 0x1b, KEY_EPG }, + { 0x1e, 0x1c, KEY_TV }, + { 0x1e, 0x1e, KEY_NEXT }, + { 0x1e, 0x1f, KEY_BACK }, + { 0x1e, 0x20, KEY_CHANNELUP }, + { 0x1e, 0x21, KEY_CHANNELDOWN }, + { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */ + { 0x1e, 0x25, KEY_OK }, + { 0x1e, 0x29, KEY_BLUE}, + { 0x1e, 0x2e, KEY_GREEN }, + { 0x1e, 0x30, KEY_PAUSE }, + { 0x1e, 0x32, KEY_REWIND }, + { 0x1e, 0x34, KEY_FASTFORWARD }, + { 0x1e, 0x35, KEY_PLAY }, + { 0x1e, 0x36, KEY_STOP }, + { 0x1e, 0x37, KEY_RECORD }, + { 0x1e, 0x38, KEY_YELLOW }, + { 0x1e, 0x3b, KEY_GOTO }, + { 0x1e, 0x3d, KEY_POWER }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ From 1f8ca4b37355cc56a4d25d5698a894ec46964f83 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 14:24:37 -0300 Subject: [PATCH 0554/2804] V4L/DVB (5958): Add support Compro VideoMate 500 with DiB7000PC Add support Compro VideoMate 500 with DiB7000PC. Another design of Compro uses the DiB7000PC and it has new USB ids. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 3 ++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index fb1a9bf7e591..b0ae5b731296 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -818,6 +818,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -874,7 +875,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, { "Compro Videomate U500", - { &dib0700_usb_id_table[6], NULL }, + { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, { NULL }, }, { "Uniwill STK7700P based (Hama and others)", diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index dae605bbd0f9..a16be605c630 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -59,6 +59,7 @@ #define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 +#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 From 8779737b8e01b95fe6f1e33dc90ea621281c7b67 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 17:02:17 -0300 Subject: [PATCH 0555/2804] V4L/DVB (5959): Fix for size of remote keys in DiB0700 Fix for size of remote control keys in DiB0700. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index b0ae5b731296..a2b2830f978a 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -914,7 +914,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, - .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -955,7 +955,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, - .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, From 8f6956c7f9fa72c502bde47df4122bd32d0b86d5 Mon Sep 17 00:00:00 2001 From: Matt Doran Date: Tue, 31 Jul 2007 07:09:30 -0300 Subject: [PATCH 0556/2804] V4L/DVB (5960): Add module parameter to enable SFN workaround In some areas in the world the broadcasters are not using the same cellid for each transmitter in a SFN. The DiBcom has problems with that setup. The module parameter buggy_sfn_workaround makes it re-usable. Signed-off-by: Matt Doran Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib3000mc.c | 22 +++++++++++++++++----- drivers/media/dvb/frontends/dib7000p.c | 21 +++++++++++++++++++-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 38d2322cbaf6..f0096de2279e 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -13,10 +13,6 @@ #include #include -//#include -//#include -//#include -//#include #include "dvb_frontend.h" @@ -26,6 +22,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); + #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) struct dib3000mc_state { @@ -42,6 +42,8 @@ struct dib3000mc_state { fe_bandwidth_t current_bandwidth; u16 dev_id; + + u8 sfn_workaround_active :1; }; static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg) @@ -591,7 +593,14 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame dib3000mc_set_channel_cfg(state, ch, 0); // activates isi - dib3000mc_write_word(state, 29, 0x1073); + if (state->sfn_workaround_active) { + dprintk("SFN workaround is active\n"); + dib3000mc_write_word(state, 29, 0x1273); + dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift + } else { + dib3000mc_write_word(state, 29, 0x1073); + dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift + } dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { @@ -679,6 +688,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, state->current_bandwidth = fep->u.ofdm.bandwidth; dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; + if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); msleep(100); diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 1175ab9a4532..aa7dc4503323 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -18,6 +18,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); + #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) struct dib7000p_state { @@ -44,6 +48,8 @@ struct dib7000p_state { u16 gpio_dir; u16 gpio_val; + + u8 sfn_workaround_active :1; }; enum dib7000p_power_mode { @@ -751,8 +757,8 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte /* offset loop parameters */ dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 29, 0x1273); // isi dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ @@ -959,7 +965,15 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet msleep(45); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ - dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); + tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); + if (state->sfn_workaround_active) { + dprintk( "SFN workaround is active"); + tmp |= (1 << 9); + dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift + } else { + dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift + } + dib7000p_write_word(state, 29, tmp); // never achieved a lock with that bandwidth so far - wait for osc-freq to update if (state->timf == 0) @@ -1119,6 +1133,9 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, state->current_bandwidth = fep->u.ofdm.bandwidth; dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; + if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); From 3db78e59500a45e05cbe271c8e1ba5a2b7ce0ef8 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 31 Jul 2007 08:19:28 -0300 Subject: [PATCH 0557/2804] V4L/DVB (5961): Fix support for DiB7000M-devices Forgot to initialize the timf_default field. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 1 + drivers/media/dvb/frontends/dib7000m.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index a2b2830f978a..a70fe75bcb27 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -515,6 +515,7 @@ static struct dibx000_bandwidth_config stk7700p_pll_config = { (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k 60258167, // ifreq 20452225, // timf + 30000000, // xtal }; static struct dib7000m_config stk7700p_dib7000m_config = { diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 0ad9f3eb20a6..fb18441a8c57 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -1344,6 +1344,8 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); + st->timf_default = cfg->bw->timf; + if (dib7000m_identify(st) != 0) goto error; From 034d65ed209f8525b1989dc3e6beca92fad57a7d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Jul 2007 08:48:40 -0300 Subject: [PATCH 0558/2804] V4L/DVB (5962): Fix line-break in err output line-breaks in dib0700-remote-query function fixed. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index a70fe75bcb27..0eca0fc75327 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -274,7 +274,7 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) *state = REMOTE_NO_KEY_PRESSED; i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { - err("RC Query Failed\n"); + err("RC Query Failed"); return 0; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; @@ -287,7 +287,7 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } } - err("Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X",(int)key[2],(int)key[3]); } return 0; } From 8d99996b0942ff566c62602d83ac2c13521bbe40 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 31 Jul 2007 10:36:06 -0300 Subject: [PATCH 0559/2804] V4L/DVB (5963): Module parameter description for SFN workaround Thanks to Matt Doran I found that there the module parameter description was not OK. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib3000mc.c | 2 +- drivers/media/dvb/frontends/dib7000p.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index f0096de2279e..edae0be063f5 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -24,7 +24,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int buggy_sfn_workaround; module_param(buggy_sfn_workaround, int, 0644); -MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index aa7dc4503323..f45bcfc51cf8 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -20,7 +20,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int buggy_sfn_workaround; module_param(buggy_sfn_workaround, int, 0644); -MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) From 89f4267d6fa96cb3db053d5183558c94ad5f46e5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Jul 2007 19:45:13 -0300 Subject: [PATCH 0560/2804] V4L/DVB (5964): Fixed remote control for dib0700 with new firmware The new firmware returns the data of the REQUEST_POLL_RC request in reversed order. The default is RC5, but it can be adjusted using a module parameter. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700.h | 1 + drivers/media/dvb/dvb-usb/dib0700_core.c | 21 ++++++++++++++++++++- drivers/media/dvb/dvb-usb/dib0700_devices.c | 10 +++++----- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 74ae6c24087e..4a903ea95896 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -30,6 +30,7 @@ extern int dvb_usb_dib0700_debug; // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) +#define REQUEST_SET_RC 0x11 #define REQUEST_GET_VERSION 0x15 struct dib0700_state { diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 8a1ea114deb0..3ea294eb96bd 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -13,6 +13,10 @@ int dvb_usb_dib0700_debug; module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); +static int dvb_usb_dib0700_ir_proto = 1; +module_param(dvb_usb_dib0700_ir_proto, int, 0644); +MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6)."); + /* expecting rx buffer: request data[0] data[1] ... data[2] */ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) { @@ -260,14 +264,29 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return dib0700_ctrl_wr(adap->dev, b, 4); } +static int dib0700_rc_setup(struct dvb_usb_device *d) +{ + u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0}; + int i = dib0700_ctrl_wr(d, rc_setup, 3); + if (i<0) { + err("ir protocol setup failed"); + return -1; + } + return 0; +} + static int dib0700_probe(struct usb_interface *intf, const struct usb_device_id *id) { int i; + struct dvb_usb_device *dev; for (i = 0; i < dib0700_device_count; i++) - if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0) + if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0) + { + dib0700_rc_setup(dev); return 0; + } return -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0eca0fc75327..4a3c5467d7e0 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -275,19 +275,19 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { err("RC Query Failed"); - return 0; + return -1; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; - if (key[1]!=st->rc_toggle) { + if (key[3-1]!=st->rc_toggle) { for (i=0;iprops.rc_key_map_size; i++) { - if (keymap[i].custom == key[2] && keymap[i].data == key[3]) { + if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) { *event = keymap[i].event; *state = REMOTE_KEY_PRESSED; - st->rc_toggle=key[1]; + st->rc_toggle=key[3-1]; return 0; } } - err("Unknown remote controller key : %2X %2X",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]); } return 0; } From 813ce47cee33964ff710d2c91063548773cb4cd5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 1 Aug 2007 10:13:36 -0300 Subject: [PATCH 0561/2804] V4L/DVB (5965): Frontend_ioctl(): fix check-after-use The Coverity checker spotted that we have already oops'ed if "fe" was NULL. Since "fe" being NULL seems impossible at this point this patch removes the NULL check. Signed-off-by: Adrian Bunk Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index afe797b75de4..fd9bac5eb25e 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -748,7 +748,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, dprintk ("%s\n", __FUNCTION__); - if (!fe || fepriv->exit) + if (fepriv->exit) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY && From b4b38bd63c07c8927b43c6c378eca1db10fdaf2e Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:44:13 -0300 Subject: [PATCH 0562/2804] V4L/DVB (5970): ivtv: prevent vertical overflow of yuv output When the video standard is changed, there's no guarantee the framebuffer dimensions are still legal. The yuv output code uses these dimensions to calculate the size & position for the video overlay. If the framebuffer dimensions are now illegal, the output may exceed the vertical limit of the display, causing distortion. This patch adds an additional check to ensure the output doesn't exceed the limits for the current video standard, cropping if required. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index bcea09542e5a..70ddf4060d37 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -898,8 +898,21 @@ static void ivtv_yuv_init (struct ivtv *itv) itv->yuv_info.decode_height = 480; /* If no visible size set, assume full size */ - if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; - if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + if (!itv->yuv_info.osd_vis_w) + itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; + + if (!itv->yuv_info.osd_vis_h) { + itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + } else { + /* If output video standard has changed, requested height may + not be legal */ + if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) { + IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", + itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset, + itv->yuv_info.decode_height); + itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + } + } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL); From 68a341a53ab5a3c5b7dad4b226124414c62c124d Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:51:58 -0300 Subject: [PATCH 0563/2804] V4L/DVB (5971): ivtv-fb: framebuffer timings no longer locked on module load Framebuffer timings are currently locked to the video format in use when the module is loaded. If the video format is then changed, the timings returned by the framebuffer will be for the original format. This patch ensures that the timings returned reflect the current video format. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 43 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 00765da8a6a0..d2cc03172749 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -164,11 +164,6 @@ MODULE_LICENSE("GPL"); #define IVTV_OSD_BPP_32 0x04 struct osd_info { - /* Timing info for modes */ - u32 pixclock; - u32 hlimit; - u32 vlimit; - /* Physical base address */ unsigned long video_pbase; /* Relative base address (relative to start of decoder memory) */ @@ -579,10 +574,25 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) { struct osd_info *oi = itv->osd_info; - int osd_height_limit = itv->is_50hz ? 576 : 480; + int osd_height_limit; + u32 pixclock, hlimit, vlimit; IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + pixclock = 84316; + hlimit = 776; + vlimit = 591; + osd_height_limit = 576; + } + else { + pixclock = 83926; + hlimit = 776; + vlimit = 495; + osd_height_limit = 480; + } + /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { @@ -723,8 +733,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = oi->hlimit - var->left_margin - var->xres; - var->lower_margin = oi->vlimit - var->upper_margin - var->yres; + var->right_margin = hlimit - var->left_margin - var->xres; + var->lower_margin = vlimit - var->upper_margin - var->yres; /* Fixed sync times */ var->hsync_len = 24; @@ -733,9 +743,10 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Non-interlaced / interlaced mode is used to switch the OSD filter on or off. Adjust the clock timings to maintain a constant vertical refresh rate. */ - var->pixclock = oi->pixclock; if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) - var->pixclock /= 2; + var->pixclock = pixclock / 2; + else + var->pixclock = pixclock; IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, @@ -875,18 +886,6 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) struct v4l2_rect start_window; int max_height; - /* Set base references for mode calcs. */ - if (itv->is_50hz) { - oi->pixclock = 84316; - oi->hlimit = 776; - oi->vlimit = 591; - } - else { - oi->pixclock = 83926; - oi->hlimit = 776; - oi->vlimit = 495; - } - /* Color mode */ if (osd_compat) osd_depth = 32; From 943e8910db31e36d945f2bf7d4c273ca5fa01f6e Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:58:29 -0300 Subject: [PATCH 0564/2804] V4L/DVB (5972): ivtv: prevent yuv register updates from being missed The yuv output code always compares the new frame position & size with those of the previous frame. If they are different, a flag is set to request the yuv output registers be updated when the new frame is displayed. If the incoming frames are delivered too fast, exhausting the buffers, the most recent frame already buffered will be discarded. Unfortunately, any update request will also be discarded. If the new frame matches the size & position of the now discarded frame, the yuv registers are not flagged for update & will remain in their old state. This patch preserves the register update flag in the event that a frame is dropped. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 70ddf4060d37..5c94d3282c82 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -940,6 +940,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) int rc = 0; int got_sig = 0; int frame, next_fill_frame, last_fill_frame; + int register_update = 0; IVTV_DEBUG_INFO("yuv_prep_frame\n"); @@ -953,6 +954,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) /* Buffers are full - Overwrite the last frame */ next_fill_frame = frame; frame = (frame - 1) & 3; + register_update = itv->yuv_info.new_frame_info[frame].update; } /* Take a snapshot of the yuv coordinate information */ @@ -991,6 +993,8 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) /* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ } + itv->yuv_info.new_frame_info[frame].update |= register_update; + /* DMA the frame */ mutex_lock(&itv->udma.lock); From bfd7beacff2b5c811badb587a74c3dfbf7f98721 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 10:01:39 -0300 Subject: [PATCH 0565/2804] V4L/DVB (5973): ivtv: attach yuv field order to each frame In the current driver, the field order is global. As soon as it's changed it takes immediate effect. This is a problem when the video changes order mid stream. Although it mostly works okay, the video may judder / flicker. This patch attaches the field order to the frame, so that any buffered frames will not be displayed until the correct field. In the event that the field order is changed mid stream, the driver will ensure that the previous frame is displayed for a minimum of 3 fields. These are the two original fields the frame should have occupied, plus the one extra since the new frame still has to wait for the correct field. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 7 ++++++- drivers/media/video/ivtv/ivtv-irq.c | 22 ++++++++++++++-------- drivers/media/video/ivtv/ivtv-yuv.c | 12 +++++++++++- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 6e53a1f04f7e..6c7c9a57a1ab 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -531,6 +531,7 @@ struct yuv_frame_info u32 tru_w; u32 tru_h; u32 offset_y; + int lace_mode; }; #define IVTV_YUV_MODE_INTERLACED 0x00 @@ -603,7 +604,6 @@ struct yuv_playback_info int decode_height; int frame_interlaced; - int frame_interlaced_last; int lace_mode; int lace_threshold; @@ -614,6 +614,11 @@ struct yuv_playback_info u32 yuv_forced_update; int update_frame; + + int sync_field[4]; /* Field to sync on */ + int field_delay[4]; /* Flag to extend duration of previous frame */ + u8 fields_lapsed; /* Counter used when delaying a frame */ + struct yuv_frame_info new_frame_info[4]; struct yuv_frame_info old_frame_info; struct yuv_frame_info old_frame_info_args; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index fcd6e7f5f121..88c6f4ff5c6d 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -698,17 +698,21 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) || + if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && + ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { - write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) & 0x3; - atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { + if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { + write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); + write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); + next_dma_frame = (next_dma_frame + 1) & 0x3; + atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + itv->yuv_info.fields_lapsed = -1; + } } } if (frame != (itv->lastVsyncFrame & 1)) { @@ -749,6 +753,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } } + + itv->yuv_info.fields_lapsed ++; } } diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 5c94d3282c82..fa8c76f3d359 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -612,7 +612,6 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi itv->yuv_info.v_filter_2 = v_filter_2; } - itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced; } /* Modify the supplied coordinate information to fit the visible osd area */ @@ -799,6 +798,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo (itv->yuv_info.old_frame_info.src_y != window->src_y) || (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || + (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) || (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; @@ -970,6 +970,9 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; + /* Snapshot field order */ + itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; + /* Are we going to offset the Y plane */ if (args->src.height + args->src.top < 512-16) itv->yuv_info.new_frame_info[frame].offset_y = 1; @@ -985,6 +988,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].update = 0; itv->yuv_info.new_frame_info[frame].interlaced_y = 0; itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; + itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.new_frame_info[frame]))) { @@ -995,6 +999,12 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].update |= register_update; + /* Should this frame be delayed ? */ + if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) + itv->yuv_info.field_delay[frame] = 1; + else + itv->yuv_info.field_delay[frame] = 0; + /* DMA the frame */ mutex_lock(&itv->udma.lock); From 19dc74b7c5f02ada19840a85582f42f4dddcdb3e Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 31 Jul 2007 23:06:50 -0300 Subject: [PATCH 0566/2804] V4L/DVB (5975): cx88: Wrong values used for HD-3000 radio mode After some tedious work with a logic probe and a magnifying glass, I've determined that GPIO 7 is used to switch between the DTT7612's Sound 4.5 MHz IF output on pin 12 and the FM 10.7MHz If output on pin 11. GPIO 2 is used to switch the card's analog sound output from from the analog input connector to the CX23883's audio DACs. So, in radio mode GPIO2 = 1 and GPIO7 = 0. Add some comments about how the HD-3000's GPIOs are connected. Delete the vmux setting for the radio, as vmux doesn't apply to radio mode. Also delete the lines setting unused gpio words to zero; it's not necessary as 0 is the default value for uninitialized fields. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6a136ddbccf8..1fc71a78b926 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -575,35 +575,34 @@ struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, + /* GPIO[2] = audio source for analog audio out connector + * 0 = analog audio input connector + * 1 = CX88 audio DACs + * + * GPIO[7] = input to CX88's audio/chroma ADC + * 0 = FM 10.7 MHz IF + * 1 = Sound 4.5 MHz IF + * + * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively + * + * GPIO[16] = Remote control input + */ .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00008484, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, }}, .radio = { .type = CX88_RADIO, - .vmux = 2, - .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, + .gpio0 = 0x00008404, }, .mpeg = CX88_MPEG_DVB, }, From b97762ba18b57c7057b58ed4f7140a19d0166b01 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 31 Jul 2007 18:51:30 -0300 Subject: [PATCH 0567/2804] V4L/DVB (5976): mt2131 s5h1409: correct frontend selection logic If a card driver is compiled into the kernel and mt2131 or s5h1409 are compiled as modules, the kernel won't link. A compiled in driver can't use a module, so in this case the mt2131 or s5h1409 are effectively disabled w.r.t the compiled in driver and the stub attach function should be used. Signed-off-by: Trent Piepho Acked-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.h | 2 +- drivers/media/dvb/frontends/s5h1409.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h index 608f1f66c9e7..1e4ffe7dc8c8 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/dvb/frontends/mt2131.h @@ -30,7 +30,7 @@ struct mt2131_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2131) || defined(CONFIG_DVB_TUNER_MT2131_MODULE) +#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE)) extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index bccfd8a6fbd4..20f9af1af445 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -53,7 +53,7 @@ struct s5h1409_config u8 status_mode; }; -#if defined(CONFIG_DVB_S5H1409) || defined(CONFIG_DVB_S5H1409_MODULE) +#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c); #else From a75d204860b5051ebd5635278c097bafb4ea53f9 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 1 Aug 2007 00:13:28 -0300 Subject: [PATCH 0568/2804] V4L/DVB (5977): cx8800: Add register debug functions to radio device too Add the advanced debug functions to the radio videodev template. One could already use them from the video and vbi devices. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 41b5cb63fd2d..58ec76be436c 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1716,6 +1716,10 @@ static struct video_device cx8800_radio_template = .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif }; /* ----------------------------------------------------------- */ From 5e082f1521598a91c9194b2356b157cade9b6e87 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 3 Aug 2007 18:32:38 -0300 Subject: [PATCH 0569/2804] V4L/DVB (5978): tuner: Better tuner radio support Add radio support for the Thomson DTT7612 tuner. This tuner uses a different 1st intermediate frequency than the other radio tuners supported (a lot of NTSC radio tuners probably need this change too). Add a new tuner-simple parameter, radio_if. It selects the 1st IF used for radio reception. The radio frequency setting code in tuner-simple now uses this field, instead of a special case select() block for each tuner with radio support. The tuner parameters for tuners that used a 33.3 MHz RIF now set radio_if to 1 in tuner-types.c. The Thomson DTT7612 gets radio_if = 2, also add has_tda9887 = 1 and fm_gain_normal = 1. Add some defines for tda9887 bits that control IF setting in radio mode. Add a new tda9887 config option, TDA9887_RIF_41_3, that selects a 41.3 MHz radio IF. Fix the way tda9887 radio options work. The driver was modifying the default radio mode config templates based on the TDA9887_XXXX flags. This means that _all_ tuners would get the same settings. If you had a one tuner than used TDA9887_GAIN_NORMAL and one that didn't, both would get the setting. Now the tda9987 driver just checks if tuner mode is radio and then applies the config settings directly to the data being sent, just like how all the TV mode settings already work. The PLL setting math is made a little more accurate. And a grammar error in a printk is fixed. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 19 ++++++++-- drivers/media/video/tuner-simple.c | 57 +++++++++++++++++++----------- drivers/media/video/tuner-types.c | 5 +++ include/media/tuner-types.h | 4 +++ include/media/tuner.h | 1 + 5 files changed, 63 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index a8f773274fe3..aa311e4f1f61 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -97,6 +97,8 @@ struct tvnorm { #define cAudioIF_6_5 0x03 // bit e0:1 +#define cVideoIFMask 0x1c // bit e2:4 +/* Video IF selection in TV Mode (bit B3=0) */ #define cVideoIF_58_75 0x00 // bit e2:4 #define cVideoIF_45_75 0x04 // bit e2:4 #define cVideoIF_38_90 0x08 // bit e2:4 @@ -106,6 +108,13 @@ struct tvnorm { #define cRadioIF_45_75 0x18 // bit e2:4 #define cRadioIF_38_90 0x1C // bit e2:4 +/* IF1 selection in Radio Mode (bit B3=1) */ +#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) +#define cRadioIF_41_30 0x04 // bit e2,4 + +/* Output of AFC pin in radio mode when bit E7=1 */ +#define cRadioAGC_SIF 0x00 // bit e3 +#define cRadioAGC_FM 0x08 // bit e3 #define cTunerGainNormal 0x00 // bit e5 #define cTunerGainLow 0x20 // bit e5 @@ -487,9 +496,13 @@ static int tda9887_set_config(struct tuner *t, char *buf) if (t->tda9887_config & TDA9887_GATING_18) buf[3] &= ~cGating_36; - if (t->tda9887_config & TDA9887_GAIN_NORMAL) { - radio_stereo.e &= ~cTunerGainLow; - radio_mono.e &= ~cTunerGainLow; + if (t->mode == V4L2_TUNER_RADIO) { + if (t->tda9887_config & TDA9887_RIF_41_3) { + buf[3] &= ~cVideoIFMask; + buf[3] |= cRadioIF_41_30; + } + if (t->tda9887_config & TDA9887_GAIN_NORMAL) + buf[3] &= ~cTunerGainLow; } return 0; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 2d57e8bc0db3..10a7d36a2646 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -402,53 +402,68 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) u8 buffer[4]; u16 div; int rc, j; - enum param_type desired_type = TUNER_PARAM_TYPE_RADIO; struct tuner_params *params; tun = &tuners[t->type]; - for (j = 0; j < tun->count-1; j++) { - if (desired_type != tun->params[j].type) - continue; - break; - } - /* use default tuner_params if desired_type not available */ - if (desired_type != tun->params[j].type) - j = 0; - - div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */ + for (j = tun->count-1; j > 0; j--) + if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) + break; + /* default params (j=0) will be used if desired type wasn't found */ params = &tun->params[j]; - buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ + /* Select Radio 1st IF used */ + switch (params->radio_if) { + case 0: /* 10.7 MHz */ + freq += (unsigned int)(10.7*16000); + break; + case 1: /* 33.3 MHz */ + freq += (unsigned int)(33.3*16000); + break; + case 2: /* 41.3 MHz */ + freq += (unsigned int)(41.3*16000); + break; + default: + tuner_warn("Unsupported radio_if value %d\n", params->radio_if); + return; + } + + /* Bandswitch byte */ switch (t->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n"); + tuner_dbg ("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); return; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: case TUNER_LG_NTSC_TAPE: + case TUNER_PHILIPS_FM1256_IH3: buffer[3] = 0x19; break; case TUNER_TNF_5335MF: buffer[3] = 0x11; break; - case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ - buffer[3] = 0x19; - break; case TUNER_LG_PAL_FM: buffer[3] = 0xa5; break; - case TUNER_MICROTUNE_4049FM5: - div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ - buffer[3] = 0xa4; + case TUNER_THOMSON_DTT761X: + buffer[3] = 0x39; break; + case TUNER_MICROTUNE_4049FM5: default: buffer[3] = 0xa4; break; } + + buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | + TUNER_RATIO_SELECT_50; /* 50 kHz step */ + + /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps + freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = + freq * (1/800) */ + div = (freq + 400) / 800; + if (params->cb_first_if_lower_freq && div < t->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; @@ -475,6 +490,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) config &= ~TDA9887_PORT1_ACTIVE;*/ if (params->fm_gain_normal) config |= TDA9887_GAIN_NORMAL; + if (params->radio_if == 2) + config |= TDA9887_RIF_41_3; i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); } if (4 != (rc = i2c_master_send(c,buffer,4))) diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 53a99b39387f..c6a7934bd5a6 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -652,6 +652,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = { .port1_invert_for_secam_lc = 1, .default_pll_gating_18 = 1, .fm_gain_normal=1, + .radio_if = 1, /* 33.3 MHz */ }, }; @@ -733,6 +734,7 @@ static struct tuner_params tuner_philips_fm1256_ih3_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_fm1236_mk3_ntsc_ranges, .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .radio_if = 1, /* 33.3 MHz */ }, }; @@ -859,6 +861,9 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_thomson_dtt761x_ntsc_ranges, .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), + .has_tda9887 = 1, + .fm_gain_normal = 1, + .radio_if = 2, /* 41.3 MHz */ }, }; diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h index e5ad3fcfe984..b201371416a0 100644 --- a/include/media/tuner-types.h +++ b/include/media/tuner-types.h @@ -79,6 +79,10 @@ struct tuner_params { /* Select 18% (or according to datasheet 0%) L standard PLL gating, vs the driver default of 36%. */ unsigned int default_pll_gating_18:1; + /* IF to use in radio mode. Tuners with a separate radio IF filter + seem to use 10.7, while those without use 33.3 for PAL/SECAM tuners + and 41.3 for NTSC tuners. 0 = 10.7, 1 = 33.3, 2 = 41.3 */ + unsigned int radio_if:2; /* Default tda9887 TOP value in dB for the low band. Default is 0. Range: -16:+15 */ signed int default_top_low:5; diff --git a/include/media/tuner.h b/include/media/tuner.h index 160381c72e4b..c03dceb92605 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -146,6 +146,7 @@ extern int tuner_debug; #define TDA9887_AUTOMUTE (1<<18) #define TDA9887_GATING_18 (1<<19) #define TDA9887_GAIN_NORMAL (1<<20) +#define TDA9887_RIF_41_3 (1<<21) /* radio IF1 41.3 vs 33.3 */ #ifdef __KERNEL__ From 4f76b672c4f9ceb9e7e0aa6224293da0ae7430da Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 6 Aug 2007 13:59:19 -0300 Subject: [PATCH 0570/2804] V4L/DVB (5980): tda8083: fix frequency and symbolrate info The TDA8083 supports a symbol rate from 12..30 MSym/s. The Grundig 29504-451 tuner uses the TDA8060 down-converter, which has a frequency range from 920..2200MHz. Thanks-to: Lars Buerding Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda8083.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 67415c9db6f7..0f041e873781 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -443,12 +443,12 @@ static struct dvb_frontend_ops tda8083_ops = { .info = { .name = "Philips TDA8083 DVB-S", .type = FE_QPSK, - .frequency_min = 950000, /* FIXME: guessed! */ - .frequency_max = 1400000, /* FIXME: guessed! */ + .frequency_min = 920000, /* TDA8060 */ + .frequency_max = 2200000, /* TDA8060 */ .frequency_stepsize = 125, /* kHz for QPSK frontends */ /* .frequency_tolerance = ???,*/ - .symbol_rate_min = 1000000, /* FIXME: guessed! */ - .symbol_rate_max = 45000000, /* FIXME: guessed! */ + .symbol_rate_min = 12000000, + .symbol_rate_max = 30000000, /* .symbol_rate_tolerance = ???,*/ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | From 5e76a1cb2ce0918ff2429fcfa2d5655dbd273c54 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:27 -0300 Subject: [PATCH 0571/2804] V4L/DVB (5981): Zoran_driver.c: fix memset in ioctl Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 4dbe2d449b50..d831ca16d9e9 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -3196,7 +3196,7 @@ zoran_do_ioctl (struct inode *inode, "%s: VIDIOC_QUERYBUF - index=%d, type=%d\n", ZR_DEVNAME(zr), buf->index, buf->type); - memset(buf, 0, sizeof(buf)); + memset(buf, 0, sizeof(*buf)); buf->type = type; buf->index = index; From 473c653fff8dc6a63cad279a8e83395ead12119d Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:35 -0300 Subject: [PATCH 0572/2804] V4L/DVB (5982): Dev.c: memset fix Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index b876aca69c73..0334b9aaf12a 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -448,7 +448,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (cmd == VIDIOCGMBUF) { struct video_mbuf *p=arg; - memset(p,0,sizeof(p)); + memset(p, 0, sizeof(*p)); if (!vfd->vidiocgmbuf) return ret; From 8509a29ec6050a03d88f2da59fc2e361f6c16534 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:45 -0300 Subject: [PATCH 0573/2804] V4L/DVB (5983): Arv.c: fix memset in ioctl Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/arv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 2666d3b76630..19e9929ffa0f 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -441,7 +441,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file, { struct video_window *w = arg; DEBUG(1, "VIDIOCGWIN:\n"); - memset(w, 0, sizeof(w)); + memset(w, 0, sizeof(*w)); w->width = ar->width; w->height = ar->height; return 0; From a18255bef2a62632ed442fdb90b091193cbabca5 Mon Sep 17 00:00:00 2001 From: Hartmut Birr Date: Thu, 9 Aug 2007 00:01:51 -0300 Subject: [PATCH 0574/2804] V4L/DVB (5985): Fix the min/max frequencies of some DVB-C frontends The min frequencies of the DVB-C frontends are wrong. In Europe, the center frequency of the lowest channel is 50.5MHz and not 51MHz. All known cards with the stv0297/tda0002x/ves1820 frontend are able to tune to this frequency. I've changed the range to the lowest channel - 1/2 bandwidth and the highest channel + 1/2 bandwidth. For the design of the dvb driver, the frequency ranges must be part of the tuner and not of the frontend itself. The same frontend may be used for different tuners. The attached patch does only fix the ranges and not the design. Signed-off-by: Hartmut Birr Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0297.c | 4 ++-- drivers/media/dvb/frontends/tda10021.c | 4 ++-- drivers/media/dvb/frontends/tda10023.c | 4 ++-- drivers/media/dvb/frontends/ves1820.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 9a343972ff50..17e5cb561cd8 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -680,8 +680,8 @@ static struct dvb_frontend_ops stv0297_ops = { .info = { .name = "ST STV0297 DVB-C", .type = FE_QAM, - .frequency_min = 64000000, - .frequency_max = 1300000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .frequency_stepsize = 62500, .symbol_rate_min = 870000, .symbol_rate_max = 11700000, diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index e725f612a6b7..4cd9e82c4669 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -439,8 +439,8 @@ static struct dvb_frontend_ops tda10021_ops = { .name = "Philips TDA10021 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ #if 0 diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index a00cf0f54efc..364bc01971a0 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -500,8 +500,8 @@ static struct dvb_frontend_ops tda10023_ops = { .name = "Philips TDA10023 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ .caps = 0x400 | //FE_CAN_QAM_4 diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 9b57576bfeb4..066b73b75698 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -410,8 +410,8 @@ static struct dvb_frontend_ops ves1820_ops = { .name = "VLSI VES1820 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | From c471b331dda9fdfaf67832998d0b2c848777ab4a Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 9 Aug 2007 01:03:42 -0300 Subject: [PATCH 0575/2804] V4L/DVB (5986): dvb_frontend: Fixed GET_INFO ioctl and check of frequency limits The calculation of frequency limits ignored tuner-specific frequency limits. Range checks and GET_INFO ioctl updated accordingly. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 31 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index fd9bac5eb25e..1a1b2405b0f4 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -697,17 +697,35 @@ static int dvb_frontend_start(struct dvb_frontend *fe) return 0; } +static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe, + u32 *freq_min, u32 *freq_max) +{ + *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); + + if (fe->ops.info.frequency_max == 0) + *freq_max = fe->ops.tuner_ops.info.frequency_max; + else if (fe->ops.tuner_ops.info.frequency_max == 0) + *freq_max = fe->ops.info.frequency_max; + else + *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); + + if (*freq_min == 0 || *freq_max == 0) + printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n", + fe->dvb->num); +} + static int dvb_frontend_check_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *parms) { + u32 freq_min; + u32 freq_max; + /* range check: frequency */ - if ((fe->ops.info.frequency_min && - parms->frequency < fe->ops.info.frequency_min) || - (fe->ops.info.frequency_max && - parms->frequency > fe->ops.info.frequency_max)) { + dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max); + if ((freq_min && parms->frequency < freq_min) || + (freq_max && parms->frequency > freq_max)) { printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n", - fe->dvb->num, parms->frequency, - fe->ops.info.frequency_min, fe->ops.info.frequency_max); + fe->dvb->num, parms->frequency, freq_min, freq_max); return -EINVAL; } @@ -763,6 +781,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_GET_INFO: { struct dvb_frontend_info* info = parg; memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); + dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max); /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't * do it, it is done for it. */ From 276e49a01a7e6c4a7bfb78618cf2f5befbf9f5de Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 9 Aug 2007 02:41:16 -0300 Subject: [PATCH 0576/2804] V4L/DVB (5987): saa7146: clean-up irq processing Interrupt processing fixed: First handle interrupt, then acknowledge it. Otherwise the same interrupt might occur twice. Cleaned-up i2c interrupt handler and i2c error messages. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_core.c | 31 ++++++++++++----------------- drivers/media/common/saa7146_i2c.c | 19 ++++++++++++++---- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 12cda9eebd12..1c962a2b44df 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -248,10 +248,11 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt static irqreturn_t interrupt_hw(int irq, void *dev_id) { struct saa7146_dev *dev = dev_id; - u32 isr = 0; + u32 isr; + u32 ack_isr; /* read out the interrupt status register */ - isr = saa7146_read(dev, ISR); + ack_isr = isr = saa7146_read(dev, ISR); /* is this our interrupt? */ if ( 0 == isr ) { @@ -259,8 +260,6 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) return IRQ_NONE; } - saa7146_write(dev, ISR, isr); - if( 0 != (dev->ext)) { if( 0 != (dev->ext->irq_mask & isr )) { if( 0 != dev->ext->irq_func ) { @@ -283,21 +282,16 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) isr &= ~MASK_28; } if (0 != (isr & (MASK_16|MASK_17))) { - u32 status = saa7146_read(dev, I2C_STATUS); - if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) { - SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); - /* only wake up if we expect something */ - if( 0 != dev->i2c_op ) { - u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2; - u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f; - DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr)); - dev->i2c_op = 0; - wake_up(&dev->i2c_wq); - } else { - DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr)); - } + SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); + /* only wake up if we expect something */ + if (0 != dev->i2c_op) { + dev->i2c_op = 0; + wake_up(&dev->i2c_wq); } else { - DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr)); + u32 psr = saa7146_read(dev, PSR); + u32 ssr = saa7146_read(dev, SSR); + printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", + dev->name, isr, psr, ssr); } isr &= ~(MASK_16|MASK_17); } @@ -306,6 +300,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) ERR(("disabling interrupt source(s)!\n")); SAA7146_IER_DISABLE(dev,isr); } + saa7146_write(dev, ISR, ack_isr); return IRQ_HANDLED; } diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index f823286341eb..7e7689afae62 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -202,7 +202,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d /* a signal arrived */ return -ERESTARTSYS; - printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n"); + printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n", + dev->name, __FUNCTION__); return -EIO; } status = saa7146_read(dev, I2C_STATUS); @@ -219,7 +220,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d break; } if (time_after(jiffies,timeout)) { - printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for MC2\n"); + printk(KERN_WARNING "%s %s: timed out waiting for MC2\n", + dev->name, __FUNCTION__); return -EIO; } } @@ -235,7 +237,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d /* this is normal when probing the bus * (no answer from nonexisistant device...) */ - DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n")); + printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n", + dev->name, __FUNCTION__); return -EIO; } if (++trial < 50 && short_delay) @@ -246,8 +249,16 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d } /* give a detailed status report */ - if ( 0 != (status & SAA7146_I2C_ERR)) { + if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR | + SAA7146_I2C_DTERR | SAA7146_I2C_DRERR | + SAA7146_I2C_AL | SAA7146_I2C_ERR | + SAA7146_I2C_BUSY)) ) { + if ( 0 == (status & SAA7146_I2C_ERR) || + 0 == (status & SAA7146_I2C_BUSY) ) { + /* it may take some time until ERR goes high - ignore */ + DEB_I2C(("unexpected i2c status %04x\n", status)); + } if( 0 != (status & SAA7146_I2C_SPERR) ) { DEB_I2C(("error due to invalid start/stop condition.\n")); } From 4ebcb48da1eace49ef5f2d83a91984085c6d702d Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Thu, 9 Aug 2007 11:29:33 -0300 Subject: [PATCH 0577/2804] V4L/DVB (5988): Fix OOP on videobuf-dvb when hibernating Since videobuf_waiton is called with intr=1, it can return -EINTR and therefore err may be non-zero. This happens when the system goes into the standby state. Without the BUG() occurring, there's no problem with standby mode while DVB is being used. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/video-buf-dvb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index e617925ba31e..d2af82dc8faf 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -56,7 +56,6 @@ static int videobuf_dvb_thread(void *data) struct videobuf_buffer, stream); list_del(&buf->stream); err = videobuf_waiton(buf,0,1); - BUG_ON(0 != err); /* no more feeds left or stop_feed() asked us to quit */ if (0 == dvb->nfeeds) From 7963fa48dafd07a8c6b6007fb038095553ad6a0f Mon Sep 17 00:00:00 2001 From: Steven Walter Date: Thu, 9 Aug 2007 11:36:35 -0300 Subject: [PATCH 0578/2804] V4L/DVB (5989): V4L: Add additional ioctls to compat_ioctl32 With the addition of these ioctls, I'm able to watch TV with a 32-bit version of tvtime on x86_64. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index f065ad12cc61..cefd1381e8de 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -848,6 +848,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOCSFREQ32: case VIDIOCGAUDIO: case VIDIOCSAUDIO: + case VIDIOCGVBIFMT: + case VIDIOCSVBIFMT: #endif case VIDIOC_QUERYCAP: case VIDIOC_ENUM_FMT: @@ -874,7 +876,10 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_ENUMINPUT: case VIDIOC_ENUMINPUT32: case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: case VIDIOC_S_CTRL32: + case VIDIOC_S_FREQUENCY: + case VIDIOC_G_FREQUENCY: case VIDIOC_QUERYCTRL: case VIDIOC_G_INPUT32: case VIDIOC_S_INPUT32: From 1597f1f676d2c425028b6a20f21a987f489dbdd2 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 9 Aug 2007 12:02:30 -0300 Subject: [PATCH 0579/2804] V4L/DVB (5990): cinergyt2_suspend: don't forget to unlock cinergyt2->wq_sem Restore unlock of cinergyt2->wq_sem, was deleted by accident. Signed-off-by: Oleg Nesterov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/cinergyT2/cinergyT2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 28929b618e20..b910fa0baa07 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -1008,6 +1008,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) cinergyt2_sleep(cinergyt2, 1); mutex_unlock(&cinergyt2->sem); + mutex_unlock(&cinergyt2->wq_sem); + return 0; } From 94104aa2a88ac2433f7cbde3dbec629263724271 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 04:56:00 -0300 Subject: [PATCH 0580/2804] V4L/DVB (5992): ivtv: show card name as well in the LOG_STATUS output. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index dfe0aedc60fd..85e6a34d5e90 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1209,6 +1209,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void int i; IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); + IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); if (itv->hw_flags & IVTV_HW_TVEEPROM) { struct tveeprom tv; @@ -1242,7 +1243,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Version: %s Status flags: 0x%08lx\n", IVTV_VERSION, itv->i_flags); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); for (i = 0; i < IVTV_MAX_STREAMS; i++) { struct ivtv_stream *s = &itv->streams[i]; From 89fc4eb924fc8da769083e1680e24c182589d789 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 05:00:07 -0300 Subject: [PATCH 0581/2804] V4L/DVB (5993): cx25840: resetting also requires reloading the firmware Resetting without reloading the firmware is not enough. Sometimes the firmware is 'stuck' and needs to be reloaded. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 9c12bd39cfb5..9f99007d389b 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -179,7 +179,7 @@ static void cx25836_initialize(struct i2c_client *client) cx25840_and_or(client, 0x15b, ~0x1e, 0x10); } -static void cx25840_initialize(struct i2c_client *client, int loadfw) +static void cx25840_initialize(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); @@ -197,8 +197,7 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw) cx25840_write(client, 0x13c, 0x01); cx25840_write(client, 0x13c, 0x00); /* 5. */ - if (loadfw) - cx25840_loadfw(client); + cx25840_loadfw(client); /* 6. */ cx25840_write(client, 0x115, 0x8c); cx25840_write(client, 0x116, 0x07); @@ -638,7 +637,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, if (state->is_cx25836) cx25836_initialize(client); else - cx25840_initialize(client, 1); + cx25840_initialize(client); } switch (cmd) { @@ -841,7 +840,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, if (state->is_cx25836) cx25836_initialize(client); else - cx25840_initialize(client, 0); + cx25840_initialize(client); break; case VIDIOC_G_CHIP_IDENT: From 2cc720957a743ef59f9925ecfef5f71f08387d8b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 05:06:23 -0300 Subject: [PATCH 0582/2804] V4L/DVB (5994): ivtv: make VIDIOC_INT_RESET support smarter. Add support to optionally reset the IR and/or the video digitizer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 85e6a34d5e90..cee6c558c69c 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -681,9 +681,17 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) break; } - case VIDIOC_INT_RESET: - ivtv_reset_ir_gpio(itv); + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; + + if ((val == 0 && itv->options.newi2c) || (val & 0x01)) { + ivtv_reset_ir_gpio(itv); + } + if (val & 0x02) { + itv->video_dec_func(itv, cmd, 0); + } break; + } default: return -EINVAL; From 372978055dd564d97ca1b4099c99296eaff1fe19 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 11 Sep 2007 11:59:15 -0300 Subject: [PATCH 0583/2804] V4L/DVB (5995): ivtv: add AverMedia M116 - Split Club3D card from Yuan PG600-2, GotView PCI DVD Lite (different composite input) - Add AVerTV MCE 116 Plus (M116) card - Allow Xceive cards to be used without Xceive support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 81 +++++++++++++++++++++----- drivers/media/video/ivtv/ivtv-driver.c | 27 ++++----- drivers/media/video/ivtv/ivtv-driver.h | 14 ++--- drivers/media/video/ivtv/ivtv-gpio.c | 24 -------- drivers/media/video/ivtv/ivtv-gpio.h | 2 +- 5 files changed, 86 insertions(+), 62 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index e51d7cc35b1c..b6a8be622d3c 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -823,9 +823,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { /* ------------------------------------------------------------------------- */ -#ifdef HAVE_XC3028 - -/* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */ +/* Yuan PG600-2/GotView PCI DVD Lite cards */ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, @@ -835,30 +833,87 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { static const struct ivtv_card ivtv_card_pg600v2 = { .type = IVTV_CARD_PG600V2, - .name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01", + .name = "Yuan PG600-2, GotView PCI DVD Lite", .v4l2_capabilities = IVTV_CAP_ENCODER, .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, }, .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, }, - .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ .pci_list = ivtv_pci_pg600v2, }; -#endif + +/* ------------------------------------------------------------------------- */ + +/* Club3D ZAP-TV1x01 cards */ + +static const struct ivtv_card_pci_info ivtv_pci_club3d[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_club3d = { + .type = IVTV_CARD_CLUB3D, + .name = "Club3D ZAP-TV1x01", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + }, + .pci_list = ivtv_pci_club3d, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerTV MCE 116 Plus (M116) card */ + +static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_avertv_mce116 = { + .type = IVTV_CARD_AVERTV_MCE116, + .name = "AVerTV MCE 116 Plus", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + }, + .pci_list = ivtv_pci_avertv_mce116, +}; static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, @@ -879,9 +934,9 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_gotview_pci_dvd2, &ivtv_card_yuan_mpc622, &ivtv_card_dctmvtvp1, -#ifdef HAVE_XC3028 &ivtv_card_pg600v2, -#endif + &ivtv_card_club3d, + &ivtv_card_avertv_mce116, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index f8ef267e56b2..198e443e8a5e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -177,9 +177,9 @@ MODULE_PARM_DESC(cardtype, "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n" "\t\t\t17 = Yuan MPC622\n" "\t\t\t18 = Digital Cowboy DCT-MTVP1\n" -#ifdef HAVE_XC3028 - "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n" -#endif + "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" + "\t\t\t20 = Club3D ZAP-TV1x01\n" + "\t\t\t21 = AverTV MCE 116 Plus\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -821,11 +821,13 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) /* load modules */ #ifndef CONFIG_VIDEO_TUNER if (hw & IVTV_HW_TUNER) { - ivtv_request_module(itv, "tuner"); -#ifdef HAVE_XC3028 - if (itv->options.tuner == TUNER_XCEIVE_XC3028) - ivtv_request_module(itv, "xc3028-tuner"); -#endif + if (itv->options.tuner == TUNER_XCEIVE_XC3028) { + IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n"); + itv->tunerid = 1; + } + else { + ivtv_request_module(itv, "tuner"); + } } #endif #ifndef CONFIG_VIDEO_CX25840 @@ -1130,19 +1132,12 @@ static int __devinit ivtv_probe(struct pci_dev *dev, if (itv->options.radio > 0) itv->v4l2_cap |= V4L2_CAP_RADIO; - if (itv->options.tuner > -1) { + if (itv->options.tuner > -1 && itv->tunerid == 0) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ -#ifdef HAVE_XC3028 - setup.initmode = V4L2_TUNER_ANALOG_TV; - if (itv->options.tuner == TUNER_XCEIVE_XC3028) { - setup.gpio_write = ivtv_reset_tuner_gpio; - setup.gpio_priv = itv; - } -#endif ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); } diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 6c7c9a57a1ab..4a7b23b9f22a 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -63,10 +63,9 @@ #include #include -/* #define HAVE_XC3028 1 */ - #include + #define IVTV_ENCODER_OFFSET 0x00000000 #define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ @@ -114,12 +113,10 @@ extern const u32 yuv_offset[4]; #define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ #define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ #define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ -#ifdef HAVE_XC3028 -#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */ -#define IVTV_CARD_LAST 18 -#else -#define IVTV_CARD_LAST 17 -#endif +#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ +#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ +#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ +#define IVTV_CARD_LAST 20 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -705,6 +702,7 @@ struct ivtv { u8 nof_audio_inputs; /* number of audio inputs */ u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* Hardware description of the board */ + int tunerid; /* Userspace tuner ID for experimental Xceive tuner support */ /* controlling Video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 6a5a7aa66976..132fb5f71366 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -122,30 +122,6 @@ void ivtv_reset_ir_gpio(struct ivtv *itv) write_reg(curdir, IVTV_REG_GPIO_DIR); } -#ifdef HAVE_XC3028 -int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr) -{ - int curdir, curout; - struct ivtv *itv = (struct ivtv *) priv; - - if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028) - return -EINVAL; - IVTV_INFO("Resetting tuner\n"); - curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= (1 << 12); /* GPIO bit 12 */ - - curout &= ~(1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - - curout |= (1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - - return 0; -} -#endif void ivtv_gpio_init(struct ivtv *itv) { diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h index c301d2a39346..b31c679bbd8e 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.h +++ b/drivers/media/video/ivtv/ivtv-gpio.h @@ -21,5 +21,5 @@ /* GPIO stuff */ void ivtv_gpio_init(struct ivtv *itv); void ivtv_reset_ir_gpio(struct ivtv *itv); -int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr); +int ivtv_reset_tuner_gpio(void *dev, int cmd, int value); int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); From 87410dab1238623e082e9a78a62f1bbeb6c475e3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 08:00:36 -0300 Subject: [PATCH 0584/2804] V4L/DVB (5997): cx25840: fix audio mute handling and reporting Audio muting for the tuner input was implemented by stopping the audio microcontroller and restarting it on unmute. However, it appears that this method can actually crash the audio firmware. It's rare and seems to happen with NTSC only. It has been reimplemented by setting to volume to 0. In addition, the reporting of the mute state has been improved as well: it used to be impossible to detect whether the audio was muted by the user or if it was muted due to the microcontroller trying to detect the audio standard. This is now clearly stated. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 53 +++++++++++++-------- drivers/media/video/cx25840/cx25840-core.c | 6 ++- drivers/media/video/cx25840/cx25840-core.h | 1 + 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index f897c1ebd5f3..f93b5160bb4f 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -194,19 +194,34 @@ void cx25840_audio_set_path(struct i2c_client *client) static int get_volume(struct i2c_client *client) { + struct cx25840_state *state = i2c_get_clientdata(client); + int vol; + + if (state->unmute_volume >= 0) + return state->unmute_volume; + /* Volume runs +18dB to -96dB in 1/2dB steps * change to fit the msp3400 -114dB to +12dB range */ /* check PATH1_VOLUME */ - int vol = 228 - cx25840_read(client, 0x8d4); + vol = 228 - cx25840_read(client, 0x8d4); vol = (vol / 2) + 23; return vol << 9; } static void set_volume(struct i2c_client *client, int volume) { - /* First convert the volume to msp3400 values (0-127) */ - int vol = volume >> 9; + struct cx25840_state *state = i2c_get_clientdata(client); + int vol; + + if (state->unmute_volume >= 0) { + state->unmute_volume = volume; + return; + } + + /* Convert the volume to msp3400 values (0-127) */ + vol = volume >> 9; + /* now scale it up to cx25840 values * -114dB to -96dB maps to 0 * this should be 19, but in my testing that was 4dB too loud */ @@ -284,30 +299,26 @@ static void set_balance(struct i2c_client *client, int balance) static int get_mute(struct i2c_client *client) { - /* check SRC1_MUTE_EN */ - return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; + struct cx25840_state *state = i2c_get_clientdata(client); + + return state->unmute_volume >= 0; } static void set_mute(struct i2c_client *client, int mute) { struct cx25840_state *state = i2c_get_clientdata(client); - if (state->aud_input != CX25840_AUDIO_SERIAL) { - /* Must turn off microcontroller in order to mute sound. - * Not sure if this is the best method, but it does work. - * If the microcontroller is running, then it will undo any - * changes to the mute register. */ - if (mute) { - /* disable microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - cx25840_write(client, 0x8d3, 0x1f); - } else { - /* enable microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } - } else { - /* SRC1_MUTE_EN */ - cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + if (mute && state->unmute_volume == -1) { + int vol = get_volume(client); + + set_volume(client, 0); + state->unmute_volume = vol; + } + else if (!mute && state->unmute_volume != -1) { + int vol = state->unmute_volume; + + state->unmute_volume = -1; + set_volume(client, vol); } } diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 9f99007d389b..65ad7943dd9a 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -915,6 +915,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->audclk_freq = 48000; state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; + state->unmute_volume = -1; state->vbi_line_offset = 8; state->id = id; state->rev = device_id; @@ -1066,9 +1067,10 @@ static void log_audio_status(struct i2c_client *client) } v4l_info(client, "Detected audio standard: %s\n", p); v4l_info(client, "Audio muted: %s\n", - (mute_ctl & 0x2) ? "yes" : "no"); + (state->unmute_volume >= 0) ? "yes" : "no"); v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? "running" : "stopped"); + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); switch (audio_config >> 4) { case 0x00: p = "undefined"; break; diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 8c1fbd9b87c1..86e2edfc4941 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -42,6 +42,7 @@ struct cx25840_state { enum cx25840_audio_input aud_input; u32 audclk_freq; int audmode; + int unmute_volume; /* -1 if not muted */ int vbi_line_offset; u32 id; u32 rev; From 9085009683dd46d95105eda14efa8bda403b459f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 08:02:45 -0300 Subject: [PATCH 0585/2804] V4L/DVB (5998): ivtv: no need to mute the audio input When changing channels the audio has to be muted. This is done by calling CX2341X_ENC_MUTE_AUDIO and by muted the audio input. The latter is not necessary and is now removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index fedddecf661e..9e867b5229d1 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -924,21 +924,13 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) void ivtv_mute(struct ivtv *itv) { - struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 }; - - /* Mute sound to avoid pop */ - ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); - if (atomic_read(&itv->capturing)) ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); - IVTV_DEBUG_INFO("Mute\n"); } void ivtv_unmute(struct ivtv *itv) { - struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 }; - /* initialize or refresh input */ if (atomic_read(&itv->capturing) == 0) ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); @@ -949,8 +941,5 @@ void ivtv_unmute(struct ivtv *itv) ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); } - - /* Unmute */ - ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); IVTV_DEBUG_INFO("Unmute\n"); } From 39c4ad6ab364354bf76cdcc0081fa5c4422db907 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 14:24:17 -0300 Subject: [PATCH 0586/2804] V4L/DVB (5999): cx25840: add radio support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 65ad7943dd9a..8f9c32613b45 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -251,7 +251,11 @@ static void input_change(struct i2c_client *client) cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); - if (std & V4L2_STD_525_60) { + if (state->radio) { + cx25840_write(client, 0x808, 0xf9); + cx25840_write(client, 0x80b, 0x00); + } + else if (std & V4L2_STD_525_60) { /* Certain Hauppauge PVR150 models have a hardware bug that causes audio to drop out. For these models the audio standard must be set explicitly. From 6af5a0394ae9ce7ac8eea233a8c430d743a377c3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Aug 2007 07:19:33 -0300 Subject: [PATCH 0587/2804] V4L/DVB (6002): ivtv: remove unused struct field. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 4a7b23b9f22a..0a1c16ad10bb 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -651,7 +651,6 @@ struct vbi_info { struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; - u32 service_set_in; int insert_mpeg; /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. From be848fe39a656fd57429263f5ac8c656ccdff362 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2007 17:13:22 -0300 Subject: [PATCH 0588/2804] V4L/DVB (6003): vp27smpx: correctly attribute the origin of the driver Correctly attribute the origin of the driver to Kazuhiko Kawakami. It took some time to get the S-O-B line from the original tvaudio patch author, but here it is. Signed-off-by: Kazuhiko Kawakami Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vp27smpx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 9aa526bd2c84..8a81fcd13ae9 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -3,7 +3,7 @@ * * Copyright (C) 2007 Hans Verkuil * - * Special thanks to Kazz for the i2c data. + * Based on a tvaudio patch from Kazuhiko Kawakami * * 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 From afa76b392e10d37c9e717198b5c2686de26c629d Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 13 Aug 2007 08:08:21 -0300 Subject: [PATCH 0589/2804] V4L/DVB (6005): Initialize filp->private_data only once in em28xx_v4l2_open Some lines later filp->private_data is initialized to dev again. Since there are some checks that might fail in the mean time keep the later version. Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 40307f3f6fe3..e4fba9068336 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -268,8 +268,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) if (NULL == dev) return -ENODEV; - filp->private_data=dev; - em28xx_videodbg("open minor=%d type=%s users=%d\n", minor,v4l2_type_names[dev->type],dev->users); From 6b1dde90de7f612805fbe8212a39264d7b868efc Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 11 Aug 2007 15:42:12 -0300 Subject: [PATCH 0590/2804] V4L/DVB (6006): tuner: move last_div to tuner-simple private data tuner-simple is the only sub-driver that uses last_div, so we can free up two bytes of memory for all other tuners, by moving this into tuner-simple's private data area. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 1 - drivers/media/video/tuner-simple.c | 29 +++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 0334a9125077..fa51b7cec691 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -49,7 +49,6 @@ struct tuner { unsigned int tv_freq; /* keep track of the current settings */ unsigned int radio_freq; - u16 last_div; unsigned int audmode; v4l2_std_id std; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 10a7d36a2646..572f22423b98 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -82,6 +82,10 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); #define TUNER_PLL_LOCKED 0x40 #define TUNER_STEREO_MK3 0x04 +struct tuner_simple_priv { + u16 last_div; +}; + /* ---------------------------------------------------------------------- */ static int tuner_getstatus(struct i2c_client *c) @@ -126,6 +130,7 @@ static int tuner_stereo(struct i2c_client *c) static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = t->priv; u8 config, cb, tuneraddr; u16 div; struct tunertype *tun; @@ -291,7 +296,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) break; } - if (params->cb_first_if_lower_freq && div < t->last_div) { + if (params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = config; buffer[1] = cb; buffer[2] = (div>>8) & 0x7f; @@ -302,7 +307,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[2] = config; buffer[3] = cb; } - t->last_div = div; + priv->last_div = div; if (params->has_tda9887) { int config = 0; int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && @@ -399,6 +404,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tunertype *tun; struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = t->priv; u8 buffer[4]; u16 div; int rc, j; @@ -464,7 +470,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) freq * (1/800) */ div = (freq + 400) / 800; - if (params->cb_first_if_lower_freq && div < t->last_div) { + if (params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; buffer[2] = (div>>8) & 0x7f; @@ -476,7 +482,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - t->last_div = div; + priv->last_div = div; if (params->has_tda9887) { int config = 0; @@ -498,16 +504,31 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); } +static void tuner_release(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations simple_tuner_ops = { .set_tv_freq = default_set_tv_freq, .set_radio_freq = default_set_radio_freq, .has_signal = tuner_signal, .is_stereo = tuner_stereo, + .release = tuner_release, }; int default_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; tuner_info("type set to %d (%s)\n", t->type, tuners[t->type].name); From fbd8af07063f7379e71654013e7915315cd869f8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 15 Aug 2007 10:43:08 -0300 Subject: [PATCH 0591/2804] V4L/DVB (6009): Bt8xx: "extern inline" -> "static inline" "extern inline" will have different semantics with gcc 4.3. Signed-off-by: Adrian Bunk Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/bt878.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index f685bc129609..1c8e3366000f 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -149,7 +149,7 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, void bt878_stop(struct bt878 *bt); #if defined(__powerpc__) /* big-endian */ -extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val) +static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) { __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val), "r"(addr)); From e9f668dd12d3ed293af0d466bcaa393b78a7d0ee Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 15 Aug 2007 10:43:19 -0300 Subject: [PATCH 0592/2804] V4L/DVB (6010): Use inline functions instead of inline asm for powerpc Change io_st_le32() to use inline functions rather than direct inline assembly code. Signed-off-by: Kumar Gala Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/bt878.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index 1c8e3366000f..d593bc145628 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -151,9 +151,8 @@ void bt878_stop(struct bt878 *bt); #if defined(__powerpc__) /* big-endian */ static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) { - __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val), - "r"(addr)); - __asm__ __volatile__("eieio":::"memory"); + st_le32(addr, val); + eieio(); } #define bmtwrite(dat,adr) io_st_le32((adr),(dat)) From acb09af4e333dc92cdd32ae75ee7e5f3d7aaf60b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 29 Jul 2007 22:56:11 -0300 Subject: [PATCH 0593/2804] V4L/DVB (6014): vivi: use videobuf_read_stream() videobuf_read_stream is more efficient than videobuf_read_one Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index f6d3a9460ccc..c10169e35753 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1123,7 +1123,7 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (res_locked(fh->dev)) return -EBUSY; - return videobuf_read_one(&fh->vb_vidq, data, count, ppos, + return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } return 0; From 5f553388b06532b495681f5d6c8e8fbff64ea86a Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 14:00:09 -0300 Subject: [PATCH 0594/2804] V4L/DVB (6015): DVB: convert struct class_device to struct device The currently used "struct class_device" will be removed from the kernel. Here is a trivial patch that converts DVB to use struct device. Signed-off-by: Kay Sievers Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvbdev.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 9ef0c00605ee..0f18ce8a9397 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -200,7 +200,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, { struct dvb_device *dvbdev; struct file_operations *dvbdevfops; - struct class_device *clsdev; + struct device *clsdev; int id; mutex_lock(&dvbdev_register_lock); @@ -242,10 +242,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, mutex_unlock(&dvbdev_register_lock); - clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, - nums2minor(adap->num, type, id)), - adap->device, "dvb%d.%s%d", adap->num, - dnames[type], id); + clsdev = device_create(dvb_class, adap->device, + MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", __FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev)); @@ -266,8 +265,8 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); + device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, + dvbdev->type, dvbdev->id))); list_del (&dvbdev->list_head); kfree (dvbdev->fops); From c252b0511596f76a32c7c64bcc6cc60b3bc1ec3a Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 13 Aug 2007 12:21:57 -0300 Subject: [PATCH 0595/2804] V4L/DVB (6019): cx88: Make card database more memory efficient The vmux setting is only two bits, but was taking up a whole 32 in the input description struct. By changing it to a two-bit bitfield, it can fit in what was padding space before and drop the input size by 4 bytes, from 28 to 24. This drops the board description struct, which has 9 inputs, from 280 to 244 bytes. Total driver size decreases by 2108 bytes. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 809126866a3e..78486f90327a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -226,8 +226,8 @@ enum cx88_itype { struct cx88_input { enum cx88_itype type; - unsigned int vmux; u32 gpio0, gpio1, gpio2, gpio3; + unsigned int vmux:2; unsigned int extadc:1; }; From b09a79f5848f2143a8ffc724910743027d5a70e0 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 13 Aug 2007 12:21:58 -0300 Subject: [PATCH 0596/2804] V4L/DVB (6020): cx88: Fix use of uninitialized variable An error message for PCI resource allocation failure used the board type before it was set. Just get rid of the error message, as get_ressources() [sic] already prints one. Format that error message better, and add the pci function and subsystem information to better associate the error with what caused it. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index f31ec96924b9..055264b9cd61 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1077,8 +1077,11 @@ static int get_ressources(struct cx88_core *core, struct pci_dev *pci) pci_resource_len(pci,0), core->name)) return 0; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", - core->name,(unsigned long long)pci_resource_start(pci,0)); + printk(KERN_ERR + "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", + core->name, PCI_FUNC(pci->devfn), + (unsigned long long)pci_resource_start(pci, 0), + pci->subsystem_vendor, pci->subsystem_device); return -EBUSY; } @@ -1115,12 +1118,6 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); if (0 != get_ressources(core,pci)) { - printk(KERN_ERR "CORE %s No more PCI ressources for " - "subsystem: %04x:%04x, board: %s\n", - core->name,pci->subsystem_vendor, - pci->subsystem_device, - cx88_boards[core->board].name); - cx88_devcount--; goto fail_free; } From 6a59d64c5cc302e0139ddb1f5e57afceecb14368 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:57 -0300 Subject: [PATCH 0597/2804] V4L/DVB (6021): cx88: Copy board information into card state The cx88 driver state stored the ID of the board type in core->board. Every time the driver need to get some information about the board configuration, it uses the board number as an index into board configuration array. This patch changes it so that the board number is in core->boardnr, and core->board is a copy of the board configuration information. This allows access to board information without the extra indirection. e.g. cx88_boards[core->board].mpeg becomes core->board.mpeg. This has a number of advantages: - The code is simpler to write. - It compiles to be smaller and faster, without needing the extra array lookup to get at the board information. - The cx88_boards array no longer needs to be exported to all cx88 modules. - The boards array can be made const - It should be possible to avoid keeping the (large) cx88_boards array around after the module is loaded. - If module parameters or eeprom info override some board configuration setting, it's not necessary to modify the boards array, which would affect all boards of the same type. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 18 +++---- drivers/media/video/cx88/cx88-cards.c | 27 +++++----- drivers/media/video/cx88/cx88-core.c | 45 +++++++--------- drivers/media/video/cx88/cx88-dvb.c | 10 ++-- drivers/media/video/cx88/cx88-i2c.c | 24 ++++----- drivers/media/video/cx88/cx88-input.c | 11 ++-- drivers/media/video/cx88/cx88-mpeg.c | 22 ++++---- drivers/media/video/cx88/cx88-tvaudio.c | 4 +- drivers/media/video/cx88/cx88-video.c | 63 +++++++++++----------- drivers/media/video/cx88/cx88-vp3054-i2c.c | 4 +- drivers/media/video/cx88/cx88.h | 13 ++--- 11 files changed, 112 insertions(+), 129 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index f2fcdb92ecce..74e3eb945751 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -734,14 +734,14 @@ static int vidioc_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx88_blackbird"); - strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (UNSET != core->tuner_type) + if (UNSET != core->board.tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -990,7 +990,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, struct cx8802_fh *fh = priv; struct cx88_core *core = fh->dev->core; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; f->type = V4L2_TUNER_ANALOG_TV; @@ -1028,7 +1028,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; u32 reg; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1049,7 +1049,7 @@ static int vidioc_s_tuner (struct file *file, void *priv, { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - if (UNSET == core->tuner_type) + if (UNSET == core->board.tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1246,7 +1246,7 @@ static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) struct cx88_core *core = drv->core; int err = 0; - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* By default, core setup will leave the cx22702 out of reset, on the bus. * We left the hardware on power up with the cx22702 active. @@ -1268,7 +1268,7 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) struct cx88_core *core = drv->core; int err = 0; - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Exit leaving the cx23416 on the bus */ break; @@ -1316,13 +1316,13 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) dprintk( 1, "%s\n", __FUNCTION__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - core->board, + core->boardnr, core->name, core->pci_bus, core->pci_slot); err = -ENODEV; - if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD)) + if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD)) goto fail_core; dev->width = 720; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 1fc71a78b926..8be90ad4e910 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -30,7 +30,7 @@ /* ------------------------------------------------------------------ */ /* board config info */ -struct cx88_board cx88_boards[] = { +const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", .tuner_type = UNSET, @@ -1687,12 +1687,12 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) return; } - core->has_radio = 1; - core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38; + core->board.tuner_type = (eeprom_data[6] == 0x13) ? + TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3; printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: " "tuner=%d, eeprom[0]=0x%02x\n", - core->name, core->tuner_type, eeprom_data[0]); + core->name, core->board.tuner_type, eeprom_data[0]); } static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) @@ -1700,9 +1700,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) struct tveeprom tv; tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); - core->tuner_type = tv.tuner_type; + core->board.tuner_type = tv.tuner_type; core->tuner_formats = tv.tuner_formats; - core->has_radio = tv.has_radio; + core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; /* Make sure we support the board model */ switch (tv.model) @@ -1792,8 +1792,9 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) name ? name : "unknown"); if (NULL == name) return; - core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id; - core->has_radio = gdi_tuner[eeprom_data[0x0d]].fm; + core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; + core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ? + CX88_RADIO : 0; } /* ----------------------------------------------------------------------- */ @@ -1860,7 +1861,7 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) void cx88_card_setup_pre_i2c(struct cx88_core *core) { - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */ /* We leave here with the 702 on the bus */ @@ -1883,7 +1884,7 @@ void cx88_card_setup(struct cx88_core *core) tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); } - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_ROSLYN: if (0 == core->i2c_rc) @@ -1927,7 +1928,7 @@ void cx88_card_setup(struct cx88_core *core) msleep(1); cx_set(MO_GP0_IO, 0x00000101); if (0 == core->i2c_rc && - core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) + core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) dvico_fusionhdtv_hybrid_init(core); break; case CX88_BOARD_KWORLD_DVB_T: @@ -1965,14 +1966,10 @@ void cx88_card_setup(struct cx88_core *core) } break; } - if (cx88_boards[core->board].radio.type == CX88_RADIO) - core->has_radio = 1; } /* ------------------------------------------------------------------ */ -EXPORT_SYMBOL(cx88_boards); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 055264b9cd61..ece788bd3d55 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -738,7 +738,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig value |= (1 << 15); value |= (1 << 16); } - if (INPUT(core->input)->type == CX88_VMUX_SVIDEO) + if (INPUT(core->input).type == CX88_VMUX_SVIDEO) value |= (1 << 13) | (1 << 5); if (V4L2_FIELD_INTERLACED == field) value |= (1 << 3); // VINT (interlaced vertical scaling) @@ -833,7 +833,7 @@ static int set_tvaudio(struct cx88_core *core) { v4l2_std_id norm = core->tvnorm; - if (CX88_VMUX_TELEVISION != INPUT(core->input)->type) + if (CX88_VMUX_TELEVISION != INPUT(core->input).type) return 0; if (V4L2_STD_PAL_BG & norm) { @@ -1067,7 +1067,7 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, vfd->dev = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - core->name, type, cx88_boards[core->board].name); + core->name, type, core->board.name); return vfd; } @@ -1130,39 +1130,34 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->bmmio = (u8 __iomem *)core->lmmio; /* board config */ - core->board = UNSET; + core->boardnr = UNSET; if (card[core->nr] < cx88_bcount) - core->board = card[core->nr]; - for (i = 0; UNSET == core->board && i < cx88_idcount; i++) + core->boardnr = card[core->nr]; + for (i = 0; UNSET == core->boardnr && i < cx88_idcount; i++) if (pci->subsystem_vendor == cx88_subids[i].subvendor && pci->subsystem_device == cx88_subids[i].subdevice) - core->board = cx88_subids[i].card; - if (UNSET == core->board) { - core->board = CX88_BOARD_UNKNOWN; + core->boardnr = cx88_subids[i].card; + if (UNSET == core->boardnr) { + core->boardnr = CX88_BOARD_UNKNOWN; cx88_card_list(core,pci); } + + memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", core->name,pci->subsystem_vendor, - pci->subsystem_device,cx88_boards[core->board].name, - core->board, card[core->nr] == core->board ? + pci->subsystem_device, core->board.name, + core->boardnr, card[core->nr] == core->boardnr ? "insmod option" : "autodetected"); - core->tuner_type = tuner[core->nr]; - core->radio_type = radio[core->nr]; - if (UNSET == core->tuner_type) - core->tuner_type = cx88_boards[core->board].tuner_type; - if (UNSET == core->radio_type) - core->radio_type = cx88_boards[core->board].radio_type; - if (!core->tuner_addr) - core->tuner_addr = cx88_boards[core->board].tuner_addr; - if (!core->radio_addr) - core->radio_addr = cx88_boards[core->board].radio_addr; + if (tuner[core->nr] != UNSET) + core->board.tuner_type = tuner[core->nr]; + if (radio[core->nr] != UNSET) + core->board.radio_type = radio[core->nr]; printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->tuner_type, core->tuner_addr<<1, - core->radio_type, core->radio_addr<<1); - - core->tda9887_conf = cx88_boards[core->board].tda9887_conf; + core->board.tuner_type, core->board.tuner_addr<<1, + core->board.radio_type, core->board.radio_addr<<1); /* init hardware */ cx88_reset(core); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 1773b40467dc..d98b90721019 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -378,7 +378,7 @@ static int dvb_register(struct cx8802_dev *dev) dev->ts_gen_cntrl = 0x0c; /* init frontend */ - switch (dev->core->board) { + switch (dev->core->boardnr) { case CX88_BOARD_HAUPPAUGE_DVB_T1: dev->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, @@ -653,7 +653,7 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) int err = 0; dprintk( 1, "%s\n", __FUNCTION__); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* We arrive here with either the cx23416 or the cx22702 * on the bus. Take the bus from the cx23416 and enable the @@ -676,7 +676,7 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv) int err = 0; dprintk( 1, "%s\n", __FUNCTION__); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Do Nothing, leave the cx22702 on the bus. */ break; @@ -694,13 +694,13 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) dprintk( 1, "%s\n", __FUNCTION__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - core->board, + core->boardnr, core->name, core->pci_bus, core->pci_slot); err = -ENODEV; - if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB)) + if (!(core->board.mpeg & CX88_MPEG_DVB)) goto fail_core; /* If vp3054 isn't enabled, a stub will just return 0 */ diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 78bbcfab9670..6b42dea860fd 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -108,28 +108,28 @@ static int attach_inform(struct i2c_client *client) if (!client->driver->command) return 0; - if (core->radio_type != UNSET) { - if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) { + if (core->board.radio_type != UNSET) { + if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->radio_type; - tun_setup.addr = core->radio_addr; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); } } - if (core->tuner_type != UNSET) { - if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) { + if (core->board.tuner_type != UNSET) { + if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->tuner_type; - tun_setup.addr = core->tuner_addr; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); } } - if (core->tda9887_conf) - client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf); + if (core->board.tda9887_conf) + client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf); return 0; } @@ -204,9 +204,9 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, sizeof(core->i2c_algo)); - if (core->tuner_type != TUNER_ABSENT) + if (core->board.tuner_type != TUNER_ABSENT) core->i2c_adap.class |= I2C_CLASS_TV_ANALOG; - if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) + if (core->board.mpeg & CX88_MPEG_DVB) core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL; core->i2c_adap.dev.parent = &pci->dev; diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index f5d4a565346e..120f56857f0e 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -74,7 +74,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) /* read gpio value */ gpio = cx_read(ir->gpio_addr); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_NPGTECH_REALTV_TOP10FM: /* This board apparently uses a combination of 2 GPIO to represent the keys. Additionally, the second GPIO @@ -113,7 +113,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) (gpio & ir->mask_keydown) ? " down" : "", (gpio & ir->mask_keyup) ? " up" : ""); - if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) { + if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) { u32 gpio_key = cx_read(MO_GP0_IO); data = (data << 4) | ((gpio_key & 0xf0) >> 4); @@ -204,7 +204,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->input = input_dev; /* detect & configure */ - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_DNTV_LIVE_DVB_T: case CX88_BOARD_KWORLD_DVB_T: case CX88_BOARD_KWORLD_DVB_T_CX22702: @@ -314,8 +314,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) } /* init input device */ - snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", - cx88_boards[core->board].name); + snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); @@ -406,7 +405,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_dump_samples(ir->samples, ir->scount); /* decode it */ - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index c34158d9dcc1..1df245ace2d0 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -55,9 +55,9 @@ static void request_module_async(struct work_struct *work) { struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); - if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB) + if (dev->core->board.mpeg & CX88_MPEG_DVB) request_module("cx88-dvb"); - if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD) + if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD) request_module("cx88-blackbird"); } @@ -95,7 +95,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); if ( (core->active_type_id == CX88_MPEG_DVB) && - (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) { + (core->board.mpeg & CX88_MPEG_DVB) ) { dprintk( 1, "cx8802_start_dma doing .dvb\n"); /* negedge driven & software reset */ @@ -103,7 +103,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); cx_write(MO_PINMUX_IO, 0x00); cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: @@ -124,7 +124,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && - (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) { + (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) { dprintk( 1, "cx8802_start_dma doing .blackbird\n"); cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ @@ -138,7 +138,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); } else { printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__, - cx88_boards[core->board].mpeg ); + core->board.mpeg ); return -EINVAL; } @@ -689,8 +689,8 @@ int cx8802_register_driver(struct cx8802_driver *drv) printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,cx88_boards[h->core->board].name, - h->core->board); + h->pci->subsystem_device,h->core->board.name, + h->core->boardnr); /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv),GFP_KERNEL); @@ -741,8 +741,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,cx88_boards[h->core->board].name, - h->core->board); + h->pci->subsystem_device,h->core->board.name, + h->core->boardnr); list_for_each_safe(list2, q, &h->drvlist.devlist) { d = list_entry(list2, struct cx8802_driver, devlist); @@ -782,7 +782,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); err = -ENODEV; - if (!cx88_boards[core->board].mpeg) + if (!core->board.mpeg) goto fail_core; err = -ENOMEM; diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 1cc2d286a1cb..99e120483ecd 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -140,7 +140,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) cx_write(AUD_RATE_THRES_DMD, 0x000000C0); cx88_start_audio_dma(core); - if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { cx_write(AUD_I2SINPUTCNTL, 4); cx_write(AUD_BAUDRATE, 1); /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ @@ -149,7 +149,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) cx_write(AUD_I2SCNTL, 0); /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */ } - if ((always_analog) || (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))) { + if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) { ctl |= EN_DAC_ENABLE; cx_write(AUD_CTL, ctl); } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 58ec76be436c..b0dd4313a841 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -368,17 +368,17 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) /* struct cx88_core *core = dev->core; */ dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", - input, INPUT(input)->vmux, - INPUT(input)->gpio0,INPUT(input)->gpio1, - INPUT(input)->gpio2,INPUT(input)->gpio3); + input, INPUT(input).vmux, + INPUT(input).gpio0,INPUT(input).gpio1, + INPUT(input).gpio2,INPUT(input).gpio3); core->input = input; - cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14); - cx_write(MO_GP3_IO, INPUT(input)->gpio3); - cx_write(MO_GP0_IO, INPUT(input)->gpio0); - cx_write(MO_GP1_IO, INPUT(input)->gpio1); - cx_write(MO_GP2_IO, INPUT(input)->gpio2); + cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); + cx_write(MO_GP3_IO, INPUT(input).gpio3); + cx_write(MO_GP0_IO, INPUT(input).gpio0); + cx_write(MO_GP1_IO, INPUT(input).gpio1); + cx_write(MO_GP2_IO, INPUT(input).gpio2); - switch (INPUT(input)->type) { + switch (INPUT(input).type) { case CX88_VMUX_SVIDEO: cx_set(MO_AFECFG_IO, 0x00000001); cx_set(MO_INPUT_FORMAT, 0x00010010); @@ -393,9 +393,9 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) break; } - if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { /* sets sound input from external adc */ - if (INPUT(input)->extadc) + if (INPUT(input).extadc) cx_set(AUD_CTL, EN_I2SIN_ENABLE); else cx_clear(AUD_CTL, EN_I2SIN_ENABLE); @@ -767,12 +767,11 @@ static int video_open(struct inode *inode, struct file *file) fh); if (fh->radio) { - int board = core->board; dprintk(1,"video_open: setting radio device\n"); - cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3); - cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0); - cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1); - cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2); + cx_write(MO_GP3_IO, core->board.radio.gpio3); + cx_write(MO_GP0_IO, core->board.radio.gpio0); + cx_write(MO_GP1_IO, core->board.radio.gpio1); + cx_write(MO_GP2_IO, core->board.radio.gpio2); core->tvaudio = WW_FM; cx88_set_tvaudio(core); cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); @@ -1078,8 +1077,7 @@ static int vidioc_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, cx88_boards[core->board].name, - sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = @@ -1087,7 +1085,7 @@ static int vidioc_querycap (struct file *file, void *priv, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE; - if (UNSET != core->tuner_type) + if (UNSET != core->board.tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1221,14 +1219,14 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) n = i->index; if (n >= 4) return -EINVAL; - if (0 == INPUT(n)->type) + if (0 == INPUT(n).type) return -EINVAL; memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,iname[INPUT(n)->type]); - if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || - (CX88_VMUX_CABLE == INPUT(n)->type)) + strcpy(i->name,iname[INPUT(n).type]); + if ((CX88_VMUX_TELEVISION == INPUT(n).type) || + (CX88_VMUX_CABLE == INPUT(n).type)) i->type = V4L2_INPUT_TYPE_TUNER; i->std = CX88_NORMS; return 0; @@ -1297,7 +1295,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; u32 reg; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1318,7 +1316,7 @@ static int vidioc_s_tuner (struct file *file, void *priv, { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - if (UNSET == core->tuner_type) + if (UNSET == core->board.tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1333,7 +1331,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, struct cx8800_fh *fh = priv; struct cx88_core *core = fh->dev->core; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ @@ -1348,7 +1346,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, int cx88_set_freq (struct cx88_core *core, struct v4l2_frequency *f) { - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; @@ -1419,8 +1417,7 @@ static int radio_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, cx88_boards[core->board].name, - sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; @@ -1828,10 +1825,10 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* load and configure helper modules */ - if (TUNER_ABSENT != core->tuner_type) + if (TUNER_ABSENT != core->board.tuner_type) request_module("tuner"); - if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775) + if (core->board.audio_chip == AUDIO_CHIP_WM8775) request_module("wm8775"); /* register v4l devices */ @@ -1858,7 +1855,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, printk(KERN_INFO "%s/0: registered device vbi%d\n", core->name,dev->vbi_dev->minor & 0x1f); - if (core->has_radio) { + if (core->board.radio.type == CX88_RADIO) { dev->radio_dev = cx88_vdev_init(core,dev->pci, &cx8800_radio_template,"radio"); err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, @@ -1884,7 +1881,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, mutex_unlock(&core->lock); /* start tvaudio thread */ - if (core->tuner_type != TUNER_ABSENT) { + if (core->board.tuner_type != TUNER_ABSENT) { core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); if (IS_ERR(core->kthread)) { err = PTR_ERR(core->kthread); diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index cd0877636a32..f76ca9e2eebf 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -111,7 +111,7 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) struct vp3054_i2c_state *vp3054_i2c; int rc; - if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return 0; dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL); @@ -152,7 +152,7 @@ void vp3054_i2c_remove(struct cx8802_dev *dev) struct vp3054_i2c_state *vp3054_i2c = dev->card_priv; if (vp3054_i2c == NULL || - dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return; i2c_del_adapter(&vp3054_i2c->adap); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 78486f90327a..3636ec26de59 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -250,7 +250,7 @@ struct cx88_subid { u32 card; }; -#define INPUT(nr) (&cx88_boards[core->board].input[nr]) +#define INPUT(nr) (core->board.input[nr]) /* ----------------------------------------------------------- */ /* device / file handle status */ @@ -304,13 +304,8 @@ struct cx88_core { u32 i2c_state, i2c_rc; /* config info -- analog */ - unsigned int board; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - unsigned int tda9887_conf; - unsigned int has_radio; + unsigned int boardnr; + struct cx88_board board; /* Supported V4L _STD_ tuner formats */ unsigned int tuner_formats; @@ -585,7 +580,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern struct cx88_board cx88_boards[]; +extern const struct cx88_board cx88_boards[]; extern const unsigned int cx88_bcount; extern struct cx88_subid cx88_subids[]; From bbc83597dfe3093b161014e6ebb351279eabaa7c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:58 -0300 Subject: [PATCH 0598/2804] V4L/DVB (6022): cx88: Move card core creation from cx88-core.c to cx88-cards.c A lot of code in cx88-cards.c was only used by cx88-core.c when the core state is first allocated and initialized. Moving that task to cx88-cards makes the driver simpler and the files more self contained. - Module parameters tuner, radio, card, and latency move to cx88-cards.c - cx88_boards is made static - cx88_subids is made static and const - cx88_bcount is eliminated - cx88_idcount is eliminated - cx88_card_list() is made static - cx88_card_setup_pre_i2c() is made static - cx88_card_setup() is made static - cx88_pci_quirks() is moved from cx88-core to cx88-cards The function argument "char *name" is made const too - get_ressources() is moved from cx88-core to cx88-cards, and renamed to cx88_get_resources() - The code to allocate and initialize the core state struct and the chip is moved out of cx88-core.c:cx88_get_core() and into a new function in cx88-cards.c, cx88_core_create(). This makes both functions simpler. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 168 ++++++++++++++++++++++++-- drivers/media/video/cx88/cx88-core.c | 161 ++---------------------- drivers/media/video/cx88/cx88.h | 12 +- 3 files changed, 171 insertions(+), 170 deletions(-) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 8be90ad4e910..6204a453c11e 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -27,10 +27,26 @@ #include "cx88.h" +static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; + +module_param_array(tuner, int, NULL, 0444); +module_param_array(radio, int, NULL, 0444); +module_param_array(card, int, NULL, 0444); + +MODULE_PARM_DESC(tuner,"tuner type"); +MODULE_PARM_DESC(radio,"radio tuner type"); +MODULE_PARM_DESC(card,"card type"); + +static unsigned int latency = UNSET; +module_param(latency,int,0444); +MODULE_PARM_DESC(latency,"pci latency timer"); + /* ------------------------------------------------------------------ */ /* board config info */ -const struct cx88_board cx88_boards[] = { +static const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", .tuner_type = UNSET, @@ -1355,12 +1371,11 @@ const struct cx88_board cx88_boards[] = { }}, }, }; -const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); /* ------------------------------------------------------------------ */ /* PCI subsystem IDs */ -struct cx88_subid cx88_subids[] = { +static const struct cx88_subid cx88_subids[] = { { .subvendor = 0x0070, .subdevice = 0x3400, @@ -1666,7 +1681,6 @@ struct cx88_subid cx88_subids[] = { .card = CX88_BOARD_ADSTECH_PTV_390, }, }; -const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); /* ----------------------------------------------------------------------- */ /* some leadtek specific stuff */ @@ -1833,7 +1847,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) /* ----------------------------------------------------------------------- */ -void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) +static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) { int i; @@ -1854,12 +1868,12 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) } printk("%s: Here is a list of valid choices for the card= insmod option:\n", core->name); - for (i = 0; i < cx88_bcount; i++) + for (i = 0; i < ARRAY_SIZE(cx88_boards); i++) printk("%s: card=%d -> %s\n", core->name, i, cx88_boards[i].name); } -void cx88_card_setup_pre_i2c(struct cx88_core *core) +static void cx88_card_setup_pre_i2c(struct cx88_core *core) { switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: @@ -1875,7 +1889,7 @@ void cx88_card_setup_pre_i2c(struct cx88_core *core) } } -void cx88_card_setup(struct cx88_core *core) +static void cx88_card_setup(struct cx88_core *core) { static u8 eeprom[256]; @@ -1970,6 +1984,144 @@ void cx88_card_setup(struct cx88_core *core) /* ------------------------------------------------------------------ */ +static int cx88_pci_quirks(const char *name, struct pci_dev *pci) +{ + unsigned int lat = UNSET; + u8 ctrl = 0; + u8 value; + + /* check pci quirks */ + if (pci_pci_problems & PCIPCI_TRITON) { + printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_NATOMA) { + printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_VIAETBF) { + printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_VSFX) { + printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", + name); + ctrl |= CX88X_EN_VSFX; + } +#ifdef PCIPCI_ALIMAGIK + if (pci_pci_problems & PCIPCI_ALIMAGIK) { + printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", + name); + lat = 0x0A; + } +#endif + + /* check insmod options */ + if (UNSET != latency) + lat = latency; + + /* apply stuff */ + if (ctrl) { + pci_read_config_byte(pci, CX88X_DEVCTRL, &value); + value |= ctrl; + pci_write_config_byte(pci, CX88X_DEVCTRL, value); + } + if (UNSET != lat) { + printk(KERN_INFO "%s: setting pci latency timer to %d\n", + name, latency); + pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); + } + return 0; +} + +int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) +{ + if (request_mem_region(pci_resource_start(pci,0), + pci_resource_len(pci,0), + core->name)) + return 0; + printk(KERN_ERR + "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", + core->name, PCI_FUNC(pci->devfn), + (unsigned long long)pci_resource_start(pci, 0), + pci->subsystem_vendor, pci->subsystem_device); + return -EBUSY; +} + +/* Allocate and initialize the cx88 core struct. One should hold the + * devlist mutex before calling this. */ +struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) +{ + struct cx88_core *core; + int i; + + core = kzalloc(sizeof(*core), GFP_KERNEL); + + atomic_inc(&core->refcount); + core->pci_bus = pci->bus->number; + core->pci_slot = PCI_SLOT(pci->devfn); + core->pci_irqmask = 0x00fc00; + mutex_init(&core->lock); + + core->nr = nr; + sprintf(core->name, "cx88[%d]", core->nr); + if (0 != cx88_get_resources(core, pci)) { + kfree(core); + return NULL; + } + + /* PCI stuff */ + cx88_pci_quirks(core->name, pci); + core->lmmio = ioremap(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + core->bmmio = (u8 __iomem *)core->lmmio; + + /* board config */ + core->boardnr = UNSET; + if (card[core->nr] < ARRAY_SIZE(cx88_boards)) + core->boardnr = card[core->nr]; + for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++) + if (pci->subsystem_vendor == cx88_subids[i].subvendor && + pci->subsystem_device == cx88_subids[i].subdevice) + core->boardnr = cx88_subids[i].card; + if (UNSET == core->boardnr) { + core->boardnr = CX88_BOARD_UNKNOWN; + cx88_card_list(core, pci); + } + + memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); + + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + core->name,pci->subsystem_vendor, + pci->subsystem_device, core->board.name, + core->boardnr, card[core->nr] == core->boardnr ? + "insmod option" : "autodetected"); + + if (tuner[core->nr] != UNSET) + core->board.tuner_type = tuner[core->nr]; + if (radio[core->nr] != UNSET) + core->board.radio_type = radio[core->nr]; + + printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", + core->board.tuner_type, core->board.tuner_addr<<1, + core->board.radio_type, core->board.radio_addr<<1); + + /* init hardware */ + cx88_reset(core); + cx88_card_setup_pre_i2c(core); + cx88_i2c_init(core, pci); + cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); + cx88_card_setup(core); + cx88_ir_init(core, pci); + + return core; +} + +/* ------------------------------------------------------------------ */ + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index ece788bd3d55..0765e9db5339 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -52,22 +52,6 @@ static unsigned int core_debug = 0; module_param(core_debug,int,0644); MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); -static unsigned int latency = UNSET; -module_param(latency,int,0444); -MODULE_PARM_DESC(latency,"pci latency timer"); - -static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; - -module_param_array(tuner, int, NULL, 0444); -module_param_array(radio, int, NULL, 0444); -module_param_array(card, int, NULL, 0444); - -MODULE_PARM_DESC(tuner,"tuner type"); -MODULE_PARM_DESC(radio,"radio tuner type"); -MODULE_PARM_DESC(card,"card type"); - static unsigned int nicam = 0; module_param(nicam,int,0644); MODULE_PARM_DESC(nicam,"tv audio is nicam"); @@ -997,61 +981,6 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) /* ------------------------------------------------------------------ */ -static int cx88_pci_quirks(char *name, struct pci_dev *pci) -{ - unsigned int lat = UNSET; - u8 ctrl = 0; - u8 value; - - /* check pci quirks */ - if (pci_pci_problems & PCIPCI_TRITON) { - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_NATOMA) { - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_VIAETBF) { - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_VSFX) { - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", - name); - ctrl |= CX88X_EN_VSFX; - } -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", - name); - lat = 0x0A; - } -#endif - - /* check insmod options */ - if (UNSET != latency) - lat = latency; - - /* apply stuff */ - if (ctrl) { - pci_read_config_byte(pci, CX88X_DEVCTRL, &value); - value |= ctrl; - pci_write_config_byte(pci, CX88X_DEVCTRL, value); - } - if (UNSET != lat) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", - name, latency); - pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); - } - return 0; -} - -/* ------------------------------------------------------------------ */ - struct video_device *cx88_vdev_init(struct cx88_core *core, struct pci_dev *pci, struct video_device *template, @@ -1071,25 +1000,10 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, return vfd; } -static int get_ressources(struct cx88_core *core, struct pci_dev *pci) -{ - if (request_mem_region(pci_resource_start(pci,0), - pci_resource_len(pci,0), - core->name)) - return 0; - printk(KERN_ERR - "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", - core->name, PCI_FUNC(pci->devfn), - (unsigned long long)pci_resource_start(pci, 0), - pci->subsystem_vendor, pci->subsystem_device); - return -EBUSY; -} - struct cx88_core* cx88_core_get(struct pci_dev *pci) { struct cx88_core *core; struct list_head *item; - int i; mutex_lock(&devlist); list_for_each(item,&cx88_devlist) { @@ -1099,82 +1013,23 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) if (PCI_SLOT(pci->devfn) != core->pci_slot) continue; - if (0 != get_ressources(core,pci)) - goto fail_unlock; + if (0 != cx88_get_resources(core, pci)) { + mutex_unlock(&devlist); + return NULL; + } atomic_inc(&core->refcount); mutex_unlock(&devlist); return core; } - core = kzalloc(sizeof(*core),GFP_KERNEL); - if (NULL == core) - goto fail_unlock; - atomic_inc(&core->refcount); - core->pci_bus = pci->bus->number; - core->pci_slot = PCI_SLOT(pci->devfn); - core->pci_irqmask = 0x00fc00; - mutex_init(&core->lock); - - core->nr = cx88_devcount++; - sprintf(core->name,"cx88[%d]",core->nr); - if (0 != get_ressources(core,pci)) { - cx88_devcount--; - goto fail_free; + core = cx88_core_create(pci, cx88_devcount); + if (NULL != core) { + cx88_devcount++; + list_add_tail(&core->devlist, &cx88_devlist); } - list_add_tail(&core->devlist,&cx88_devlist); - - /* PCI stuff */ - cx88_pci_quirks(core->name, pci); - core->lmmio = ioremap(pci_resource_start(pci,0), - pci_resource_len(pci,0)); - core->bmmio = (u8 __iomem *)core->lmmio; - - /* board config */ - core->boardnr = UNSET; - if (card[core->nr] < cx88_bcount) - core->boardnr = card[core->nr]; - for (i = 0; UNSET == core->boardnr && i < cx88_idcount; i++) - if (pci->subsystem_vendor == cx88_subids[i].subvendor && - pci->subsystem_device == cx88_subids[i].subdevice) - core->boardnr = cx88_subids[i].card; - if (UNSET == core->boardnr) { - core->boardnr = CX88_BOARD_UNKNOWN; - cx88_card_list(core,pci); - } - - memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - core->name,pci->subsystem_vendor, - pci->subsystem_device, core->board.name, - core->boardnr, card[core->nr] == core->boardnr ? - "insmod option" : "autodetected"); - - if (tuner[core->nr] != UNSET) - core->board.tuner_type = tuner[core->nr]; - if (radio[core->nr] != UNSET) - core->board.radio_type = radio[core->nr]; - - printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->board.tuner_type, core->board.tuner_addr<<1, - core->board.radio_type, core->board.radio_addr<<1); - - /* init hardware */ - cx88_reset(core); - cx88_card_setup_pre_i2c(core); - cx88_i2c_init(core,pci); - cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); - cx88_card_setup(core); - cx88_ir_init(core,pci); mutex_unlock(&devlist); return core; - -fail_free: - kfree(core); -fail_unlock: - mutex_unlock(&devlist); - return NULL; } void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 3636ec26de59..80e49f986fbb 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -580,15 +580,9 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern const struct cx88_board cx88_boards[]; -extern const unsigned int cx88_bcount; - -extern struct cx88_subid cx88_subids[]; -extern const unsigned int cx88_idcount; - -extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci); -extern void cx88_card_setup(struct cx88_core *core); -extern void cx88_card_setup_pre_i2c(struct cx88_core *core); +extern int cx88_get_resources(const struct cx88_core *core, + struct pci_dev *pci); +extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); /* ----------------------------------------------------------- */ /* cx88-tvaudio.c */ From 5772f81326904f2bfbb2bf2f365b3fb36ee3b7d8 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:59 -0300 Subject: [PATCH 0599/2804] V4L/DVB (6023): cx88: Clean up some ugly and inconsistent printk()s Get rid of the "CORE" prefix from cx88 printks. It was only used a few times, and it makes it look like they're coming from the kernel core or something. Fix the message, "TV tuner 60 at 0x1fe, Radio tuner -1 at 0x1fe", by adding a "cx88[0]" prefix to be consistent, and to keep people who grep their dmesg output for cx88 from missing it. Get rid of the addresses, which are always wrong. The addresses are always set to -1, but because it's an unsigned 8-bit value, the left shift converts it to the nonsense address 0x1fe. In the cx8802 driver, some cut and pasted code prefixed lines with "CORE cx88[0]:", which has been changed to "cx88[0]/2:" like the other printks from the cx8802 driver. Also fix some ugly printks in the cx8802 driver that used __FUNCTION__ for KERN_INFO and KERN_ERR messages. The changed printks in cx88-mpeg.c also needed lots of whitespace and 80-column fixes. A bunch of misc changes in cx88-dvb.c and cx88-video.c to add message levels or a consistent "cx88[?]/2" or "cx88[?]/0" prefix. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 7 ++--- drivers/media/video/cx88/cx88-dvb.c | 13 +++++---- drivers/media/video/cx88/cx88-mpeg.c | 42 ++++++++++++++++----------- drivers/media/video/cx88/cx88-video.c | 30 +++++++++---------- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6204a453c11e..e73e8c96d5b9 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -2094,7 +2094,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", core->name,pci->subsystem_vendor, pci->subsystem_device, core->board.name, core->boardnr, card[core->nr] == core->boardnr ? @@ -2105,9 +2105,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (radio[core->nr] != UNSET) core->board.radio_type = radio[core->nr]; - printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->board.tuner_type, core->board.tuner_addr<<1, - core->board.radio_type, core->board.radio_addr<<1); + printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n", + core->name, core->board.tuner_type, core->board.radio_type); /* init hardware */ cx88_reset(core); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index d98b90721019..00d0e43785a0 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -482,7 +482,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap, DVB_PLL_FMD1216ME); } #else - printk("%s: built without vp3054 support\n", dev->core->name); + printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name); #endif break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: @@ -625,12 +625,12 @@ static int dvb_register(struct cx8802_dev *dev) } break; default: - printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); break; } if (NULL == dev->dvb.frontend) { - printk("%s: frontend initialization failed\n",dev->core->name); + printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name); return -1; } @@ -709,7 +709,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) goto fail_core; /* dvb stuff */ - printk("%s/2: cx2388x based dvb card\n", core->name); + printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -718,7 +718,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) dev); err = dvb_register(dev); if (err != 0) - printk("%s dvb_register failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n", + core->name, err); fail_core: return err; @@ -747,7 +748,7 @@ static struct cx8802_driver cx8802_dvb_driver = { static int dvb_init(void) { - printk(KERN_INFO "cx2388x dvb driver version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 1df245ace2d0..5da47e251e66 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -675,22 +675,24 @@ int cx8802_register_driver(struct cx8802_driver *drv) struct list_head *list; int err = 0, i = 0; - printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ , - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + printk(KERN_INFO + "cx88/2: registering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); if ((err = cx8802_check_driver(drv)) != 0) { - printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ ); + printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n"); return err; } list_for_each(list,&cx8802_devlist) { h = list_entry(list, struct cx8802_dev, devlist); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", - h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,h->core->board.name, - h->core->boardnr); + printk(KERN_INFO + "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name, h->pci->subsystem_vendor, + h->pci->subsystem_device, h->core->board.name, + h->core->boardnr); /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv),GFP_KERNEL); @@ -712,7 +714,9 @@ int cx8802_register_driver(struct cx8802_driver *drv) list_add_tail(&driver->devlist,&h->drvlist.devlist); mutex_unlock(&drv->core->lock); } else { - printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR + "%s/2: cx8802 probe failed, err = %d\n", + h->core->name, err); } } @@ -732,17 +736,20 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) struct list_head *list2, *q; int err = 0, i = 0; - printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ , - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird"); + printk(KERN_INFO + "cx88/2: unregistering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); list_for_each(list,&cx8802_devlist) { i++; h = list_entry(list, struct cx8802_dev, devlist); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", - h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,h->core->board.name, - h->core->boardnr); + printk(KERN_INFO + "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name, h->pci->subsystem_vendor, + h->pci->subsystem_device, h->core->board.name, + h->core->boardnr); list_for_each_safe(list2, q, &h->drvlist.devlist) { d = list_entry(list2, struct cx8802_driver, devlist); @@ -757,7 +764,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) list_del(list2); mutex_unlock(&drv->core->lock); } else - printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR "%s/2: cx8802 driver remove " + "failed (%d)\n", h->core->name, err); } @@ -865,7 +873,7 @@ static struct pci_driver cx8802_pci_driver = { static int cx8802_init(void) { - printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index b0dd4313a841..e158ea2454af 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1818,7 +1818,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = request_irq(pci_dev->irq, cx8800_irq, IRQF_SHARED | IRQF_DISABLED, core->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + printk(KERN_ERR "%s/0: can't get IRQ %d\n", core->name,pci_dev->irq); goto fail_core; } @@ -1837,7 +1837,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + printk(KERN_ERR "%s/0: can't register video device\n", core->name); goto fail_unreg; } @@ -1848,7 +1848,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s/0: can't register vbi device\n", + printk(KERN_ERR "%s/0: can't register vbi device\n", core->name); goto fail_unreg; } @@ -1861,7 +1861,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s/0: can't register radio device\n", + printk(KERN_ERR "%s/0: can't register radio device\n", core->name); goto fail_unreg; } @@ -1885,8 +1885,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); if (IS_ERR(core->kthread)) { err = PTR_ERR(core->kthread); - printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n", - err); + printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", + core->name, err); } } return 0; @@ -1937,12 +1937,12 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) /* stop video+vbi capture */ spin_lock(&dev->slock); if (!list_empty(&dev->vidq.active)) { - printk("%s: suspend video\n", core->name); + printk("%s/0: suspend video\n", core->name); stop_video_dma(dev); del_timer(&dev->vidq.timeout); } if (!list_empty(&dev->vbiq.active)) { - printk("%s: suspend vbi\n", core->name); + printk("%s/0: suspend vbi\n", core->name); cx8800_stop_vbi_dma(dev); del_timer(&dev->vbiq.timeout); } @@ -1968,8 +1968,8 @@ static int cx8800_resume(struct pci_dev *pci_dev) if (dev->state.disabled) { err=pci_enable_device(pci_dev); if (err) { - printk(KERN_ERR "%s: can't enable device\n", - core->name); + printk(KERN_ERR "%s/0: can't enable device\n", + core->name); return err; } @@ -1977,9 +1977,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) } err= pci_set_power_state(pci_dev, PCI_D0); if (err) { - printk(KERN_ERR "%s: can't enable device\n", - core->name); - + printk(KERN_ERR "%s/0: can't set power state\n", core->name); pci_disable_device(pci_dev); dev->state.disabled = 1; @@ -1993,11 +1991,11 @@ static int cx8800_resume(struct pci_dev *pci_dev) /* restart video+vbi capture */ spin_lock(&dev->slock); if (!list_empty(&dev->vidq.active)) { - printk("%s: resume video\n", core->name); + printk("%s/0: resume video\n", core->name); restart_video_queue(dev,&dev->vidq); } if (!list_empty(&dev->vbiq.active)) { - printk("%s: resume vbi\n", core->name); + printk("%s/0: resume vbi\n", core->name); cx8800_restart_vbi_queue(dev,&dev->vbiq); } spin_unlock(&dev->slock); @@ -2033,7 +2031,7 @@ static struct pci_driver cx8800_pci_driver = { static int cx8800_init(void) { - printk(KERN_INFO "cx2388x v4l2 driver version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); From 89d969a39da8e9ee5db1c1fb49f55f4206a445ac Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 16 Aug 2007 10:03:18 -0300 Subject: [PATCH 0600/2804] V4L/DVB (6025): Net_ule(): fix check-after-use The Coverity checker spotted that we'd have already oops'ed if "dev" was NULL. Signed-off-by: Adrian Bunk Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index bdd797071cb0..b9c78d03a7fe 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -357,11 +357,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) static unsigned char *ule_where = ule_hist, ule_dump = 0; #endif - if (dev == NULL) { - printk( KERN_ERR "NO netdev struct!\n" ); - return; - } - /* For all TS cells in current buffer. * Appearently, we are called for every single TS cell. */ From 82e67246cd2a860637ee9d27776ad48d32734f6c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 17 Aug 2007 17:49:41 -0300 Subject: [PATCH 0601/2804] V4L/DVB (6031): Fix for bug 7819: fixed hotplugging for dvbnet The first part of dvb_net_close() is just a cut&paste from dvb_generic_release(), so maybe it would be better to just call dvb_generic_release() instead? Signed-off-by: Trent Piepho Acked-by: Markus Rechberger Acked-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index b9c78d03a7fe..13e2998a4043 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1441,18 +1441,9 @@ static int dvb_net_close(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dvb_net *dvbnet = dvbdev->priv; - if (!dvbdev) - return -ENODEV; + dvb_generic_release(inode, file); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - dvbdev->readers++; - } else { - dvbdev->writers++; - } - - dvbdev->users++; - - if(dvbdev->users == 1 && dvbnet->exit==1) { + if(dvbdev->users == 1 && dvbnet->exit == 1) { fops_put(file->f_op); file->f_op = NULL; wake_up(&dvbdev->wait_queue); From fa40b2237ab6ed239967f76432438080232b88fe Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 17 Aug 2007 05:50:22 -0300 Subject: [PATCH 0602/2804] V4L/DVB (6034): cx88: Add parameter to control radio deemphasis time constant FM radio transmission use a preemphasis/deemphasis scheme to reduce high-frequency noise. The cx88 audio decoder is supposedly set to no deemphasis by the current driver. However, the "no deemphasis" setting doesn't work. On my chip, cx23883, it produces the same result as the 75 us time constant. Maybe the default settings on the cx23881 are for 50 us? Since the deemphasis time constant varies by country, allow setting it via a module parameter. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-tvaudio.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 99e120483ecd..9aee8c51ee27 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -62,6 +62,10 @@ static unsigned int always_analog = 0; module_param(always_analog,int,0644); MODULE_PARM_DESC(always_analog,"force analog audio out"); +static unsigned int radio_deemphasis = 0; +module_param(radio_deemphasis,int,0644); +MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, " + "0=None, 1=50us (elsewhere), 2=75us (USA)"); #define dprintk(fmt, arg...) if (audio_debug) \ printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) @@ -678,6 +682,10 @@ static void set_audio_standard_FM(struct cx88_core *core, }; /* It is enough to leave default values? */ + /* No, it's not! The deemphasis registers are reset to the 75us + * values by default. Analyzing the spectrum of the decoded audio + * reveals that "no deemphasis" is the same as 75 us, while the 50 us + * setting results in less deemphasis. */ static const struct rlist fm_no_deemph[] = { {AUD_POLYPH80SCALEFAC, 0x0003}, @@ -688,6 +696,7 @@ static void set_audio_standard_FM(struct cx88_core *core, set_audio_start(core, SEL_FMRADIO); switch (deemph) { + default: case FM_NO_DEEMPH: set_audio_registers(core, fm_no_deemph); break; @@ -757,7 +766,7 @@ void cx88_set_tvaudio(struct cx88_core *core) set_audio_standard_EIAJ(core); break; case WW_FM: - set_audio_standard_FM(core, FM_NO_DEEMPH); + set_audio_standard_FM(core, radio_deemphasis); break; case WW_NONE: default: From 458b634cd86968032171a4d6db5c89a772ff0348 Mon Sep 17 00:00:00 2001 From: Alan Nisota Date: Sat, 18 Aug 2007 17:52:35 -0300 Subject: [PATCH 0603/2804] V4L/DVB (6037): Updated GenPix USB driver There are now 4 different versions of the GENPIX USB adapter. The newest 'Skywalker' models are fully self-contained, and need no additional hardware to be used. A very reliable DVB-S card even without using any of the alternate modulatations (which this kernel module does not currently support) The following patch adds support for all 4 versions of the genpix adapter (www.genpix-electronics.com). Signed-off-by: Alan Nisota alannisota@gmail.com Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 7 +- drivers/media/dvb/dvb-usb/gp8psk-fe.c | 84 +++++++++++++--------- drivers/media/dvb/dvb-usb/gp8psk.c | 93 +++++++++++++++++++------ drivers/media/dvb/dvb-usb/gp8psk.h | 32 +++++++-- 4 files changed, 152 insertions(+), 64 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index a16be605c630..43bfe50a2227 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -158,8 +158,11 @@ #define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 -#define USB_PID_GENPIX_8PSK_COLD 0x0200 -#define USB_PID_GENPIX_8PSK_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 +#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_2 0x0202 +#define USB_PID_GENPIX_SKYWALKER_1 0x0203 +#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 #define USB_PID_SIGMATEK_DVB_110 0x6610 #define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 #define USB_PID_OPERA1_COLD 0x2830 diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 6ccbdc9cd772..e37142d9271a 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -17,27 +18,39 @@ struct gp8psk_fe_state { struct dvb_frontend fe; - struct dvb_usb_device *d; - + u8 lock; u16 snr; - - unsigned long next_snr_check; + unsigned long next_status_check; + unsigned long status_check_interval; }; +static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) +{ + u8 buf[6]; + if (time_after(jiffies,st->next_status_check)) { + gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); + gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); + st->snr = (buf[1]) << 8 | buf[0]; + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) { struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 lock; + gp8psk_fe_update_status(st); - if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1)) - return -EINVAL; - - if (lock) + if (st->lock) *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; else *status = 0; + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 100; return 0; } @@ -60,33 +73,29 @@ static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) { struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 buf[2]; - - if (time_after(jiffies,st->next_snr_check)) { - gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2); - *snr = (int)(buf[1]) << 8 | buf[0]; - /* snr is reported in dBu*256 */ - /* snr / 38.4 ~= 100% strength */ - /* snr * 17 returns 100% strength as 65535 */ - if (*snr <= 3855) - *snr = (*snr<<4) + *snr; // snr * 17 - else - *snr = 65535; - st->next_snr_check = jiffies + (10*HZ)/1000; - } else { - *snr = st->snr; - } + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + *snr = st->snr; return 0; } static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { - return gp8psk_fe_read_snr(fe, strength); + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + /* snr / 38.4 ~= 100% strength */ + /* snr * 17 returns 100% strength as 65535 */ + if (st->snr > 0xf00) + *strength = 0xffff; + else + *strength = (st->snr << 4) + st->snr; /* snr*17 */ + return 0; } static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) { - tune->min_delay_ms = 800; + tune->min_delay_ms = 200; return 0; } @@ -124,7 +133,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10); - state->next_snr_check = jiffies; + state->lock = 0; + state->next_status_check = jiffies; + state->status_check_interval = 200; return 0; } @@ -190,6 +201,12 @@ static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t volt return 0; } +static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); +} + static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) { struct gp8psk_fe_state* state = fe->demodulator_priv; @@ -235,10 +252,10 @@ success: static struct dvb_frontend_ops gp8psk_fe_ops = { .info = { - .name = "Genpix 8psk-USB DVB-S", + .name = "Genpix 8psk-to-USB2 DVB-S", .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, + .frequency_min = 800000, + .frequency_max = 2250000, .frequency_stepsize = 100, .symbol_rate_min = 1000000, .symbol_rate_max = 45000000, @@ -269,4 +286,5 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .set_tone = gp8psk_fe_set_tone, .set_voltage = gp8psk_fe_set_voltage, .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, + .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage }; diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 518d67fca5e8..92147ee3e14f 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -40,7 +41,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 } if (ret < 0 || ret != blen) { - warn("usb in operation failed."); + warn("usb in %d operation failed.", req); ret = -EIO; } else ret = 0; @@ -97,10 +98,10 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) goto out_rel_fw; - info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware); + info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); ptr = fw->data; - buf = kmalloc(512, GFP_KERNEL | GFP_DMA); + buf = kmalloc(64, GFP_KERNEL | GFP_DMA); while (ptr[0] != 0xff) { u16 buflen = ptr[0] + 4; @@ -129,25 +130,34 @@ out_rel_fw: static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 status, buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + if (onoff) { gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); - if (! (status & 0x01)) /* started */ + if (! (status & bm8pskStarted)) { /* started */ + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) return -EINVAL; + } - if (! (status & 0x02)) /* BCM4500 firmware loaded */ - if(gp8psk_load_bcm4500fw(d)) - return EINVAL; + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ + if(gp8psk_load_bcm4500fw(d)) + return EINVAL; - if (! (status & 0x04)) /* LNB Power */ + if (! (status & bmIntersilOn)) /* LNB Power */ if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, &buf, 1)) return EINVAL; - /* Set DVB mode */ - if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) - return -EINVAL; - gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); + /* Set DVB mode to 1 */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) + return EINVAL; + /* Abort possible TS (if previous tune crashed) */ + if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) + return EINVAL; } else { /* Turn off LNB power */ if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) @@ -155,11 +165,28 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) /* Turn off 8psk power */ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) return -EINVAL; - + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); } return 0; } +int gp8psk_bcm4500_reload(struct dvb_usb_device *d) +{ + u8 buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn On 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + /* load BCM4500 firmware */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_load_bcm4500fw(d)) + return EINVAL; + return 0; +} static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { @@ -177,12 +204,22 @@ static struct dvb_usb_device_properties gp8psk_properties; static int gp8psk_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); + int ret; + struct usb_device *udev = interface_to_usbdev(intf); + ret = dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); + if (ret == 0) { + info("found Genpix USB device pID = %x (hex)", + le16_to_cpu(udev->descriptor.idProduct)); + } + return ret; } static struct usb_device_id gp8psk_usb_table [] = { - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); @@ -213,12 +250,24 @@ static struct dvb_usb_device_properties gp8psk_properties = { .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 1, + .num_device_descs = 4, .devices = { - { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver", + { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", .cold_ids = { &gp8psk_usb_table[0], NULL }, .warm_ids = { &gp8psk_usb_table[1], NULL }, }, + { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[2], NULL }, + }, + { .name = "Genpix SkyWalker-1 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[3], NULL }, + }, + { .name = "Genpix SkyWalker-CW3K DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[4], NULL }, + }, { NULL }, } }; @@ -253,6 +302,6 @@ module_init(gp8psk_usb_module_init); module_exit(gp8psk_usb_module_exit); MODULE_AUTHOR("Alan Nisota "); -MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0"); -MODULE_VERSION("1.0"); +MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S"); +MODULE_VERSION("1.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index 3eba7061011c..e83a57506cfa 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -30,21 +31,37 @@ extern int dvb_usb_gp8psk_debug; #define TH_COMMAND_IN 0xC0 #define TH_COMMAND_OUT 0xC1 -/* command bytes */ -#define GET_8PSK_CONFIG 0x80 +/* gp8psk commands */ + +#define GET_8PSK_CONFIG 0x80 /* in */ #define SET_8PSK_CONFIG 0x81 +#define I2C_WRITE 0x83 +#define I2C_READ 0x84 #define ARM_TRANSFER 0x85 #define TUNE_8PSK 0x86 -#define GET_SIGNAL_STRENGTH 0x87 +#define GET_SIGNAL_STRENGTH 0x87 /* in */ #define LOAD_BCM4500 0x88 -#define BOOT_8PSK 0x89 -#define START_INTERSIL 0x8A +#define BOOT_8PSK 0x89 /* in */ +#define START_INTERSIL 0x8A /* in */ #define SET_LNB_VOLTAGE 0x8B #define SET_22KHZ_TONE 0x8C #define SEND_DISEQC_COMMAND 0x8D #define SET_DVB_MODE 0x8E #define SET_DN_SWITCH 0x8F -#define GET_SIGNAL_LOCK 0x90 +#define GET_SIGNAL_LOCK 0x90 /* in */ +#define GET_SERIAL_NUMBER 0x93 /* in */ +#define USE_EXTRA_VOLT 0x94 +#define CW3K_INIT 0x9d + +/* PSK_configuration bits */ +#define bm8pskStarted 0x01 +#define bm8pskFW_Loaded 0x02 +#define bmIntersilOn 0x04 +#define bmDVBmode 0x08 +#define bm22kHz 0x10 +#define bmSEL18V 0x20 +#define bmDCtuned 0x40 +#define bmArmed 0x80 /* Satellite modulation modes */ #define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ @@ -75,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); #endif From e927b3fa595117c9f4c6dfa241fe7c3a3c596f17 Mon Sep 17 00:00:00 2001 From: Michael Mauch Date: Sat, 18 Aug 2007 18:02:31 -0300 Subject: [PATCH 0604/2804] V4L/DVB (6038): Trivial: repair mixed parm descs in dvb-usb-init.c Repair modinfo parameter descriptions for force_pid_filter_usage and disable_rc_polling. Signed-off-by: Michael Mauch Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index ffdde83d1e77..cdd717c3fe45 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -24,7 +24,7 @@ MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0 static int dvb_usb_force_pid_filter_usage; module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); static int dvb_usb_adapter_init(struct dvb_usb_device *d) { From faebb914399ecf8ecfd0e24b96ac90d7381f7e07 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 18 Aug 2007 18:04:00 -0300 Subject: [PATCH 0605/2804] V4L/DVB (6039): Typo fix in Nova-TD description Typo fix in Nova-TD description Signed-off-by: Darren Salt Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 4a3c5467d7e0..0227e7fac3cf 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -944,7 +944,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[12], NULL }, { NULL }, }, - { "Haupauge Nova-TD Stick/Elgato Eye-TV Diversity", + { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", { &dib0700_usb_id_table[13], NULL }, { NULL }, }, From b1139e353c7fc636bfe413f3296ba0284eb60c2e Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 18 Aug 2007 18:05:31 -0300 Subject: [PATCH 0606/2804] V4L/DVB (6040): Add IR support for Nova-T Stick Working with Nova-T Stick (70001) with remote control model A415. Untested with other dib0700m/dib0700p devices. Signed-off-by: Darren Salt Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0227e7fac3cf..063fb5095bda 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -887,7 +887,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[8], NULL }, { NULL }, } - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, From 33bc4dea0ece371ccadbac8bf90fd0b8e2803f06 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 11:36:09 -0300 Subject: [PATCH 0607/2804] V4L/DVB (6043): ivtv: fix incorrect round-robin implementation Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 88c6f4ff5c6d..a97d55fd2277 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -859,8 +859,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { + itv->irq_rr_idx++; for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; struct ivtv_stream *s = &itv->streams[idx]; if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) @@ -877,8 +878,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) { + itv->irq_rr_idx++; for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; struct ivtv_stream *s = &itv->streams[idx]; if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags)) From da80be21362376443c6ee9918dfff408e83e0c39 Mon Sep 17 00:00:00 2001 From: Kazuhiko Kawakami Date: Sat, 18 Aug 2007 11:39:28 -0300 Subject: [PATCH 0608/2804] V4L/DVB (6044): vp27smpx: clarify history of this source. Signed-off-by: Kazuhiko Kawakami Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vp27smpx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 8a81fcd13ae9..63002e0ac764 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -3,7 +3,8 @@ * * Copyright (C) 2007 Hans Verkuil * - * Based on a tvaudio patch from Kazuhiko Kawakami + * Based on a tvaudio patch from Takahiro Adachi + * and Kazuhiko Kawakami * * 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 From 3562c43be8cfd6e300508d7c33acebf3369eacd3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 11:46:05 -0300 Subject: [PATCH 0609/2804] V4L/DVB (6045): ivtv: fix handling of INITIALIZE_INPUT fw call The CX2341X_ENC_INITIALIZE_INPUT firmware call requires careful handling, otherwise the computer can freeze or the top-third of the screen can start flickering. This patch ensures that CX2341X_ENC_INITIALIZE_INPUT is called at the right time and in the right way. In addition the stop capture handling was improved so that the last pending DMA transfer is also processed. Otherwise this would be the first data that arrived when a new capture was started which is not what you want. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 19 ++++++++++------- drivers/media/video/ivtv/ivtv-ioctl.c | 3 +++ drivers/media/video/ivtv/ivtv-streams.c | 28 +++++-------------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 9e867b5229d1..908e640c274d 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -892,12 +892,20 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -EBUSY; } + if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + if (atomic_read(&itv->capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + kfree(item); + return -EBUSY; + } + } + /* Mark that the radio is being used. */ + set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); /* We have the radio */ ivtv_mute(itv); /* Switch tuner to radio */ ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL); - /* Mark that the radio is being used. */ - set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); /* Select the correct audio input (i.e. radio tuner) */ ivtv_audio_set_io(itv); if (itv->hw_flags & IVTV_HW_SAA711X) @@ -931,13 +939,8 @@ void ivtv_mute(struct ivtv *itv) void ivtv_unmute(struct ivtv *itv) { - /* initialize or refresh input */ - if (atomic_read(&itv->capturing) == 0) - ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_msleep_timeout(100, 0); - if (atomic_read(&itv->capturing)) { + ivtv_msleep_timeout(100, 0); ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); } diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index cee6c558c69c..734f2d2ffa62 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -906,6 +906,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void IVTV_DEBUG_INFO("Input unchanged\n"); break; } + if (atomic_read(&itv->capturing) > 0) { + return -EBUSY; + } IVTV_DEBUG_INFO("Changing input from %d to %d\n", itv->active_input, inp); diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 405e2e3fcb49..0582b9d57c55 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -554,9 +554,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_I_EOS, &itv->i_flags); /* Initialize Digitizer for Capture */ + itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0); + ivtv_msleep_timeout(300, 1); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_msleep_timeout(100, 0); + itv->video_dec_func(itv, VIDIOC_STREAMON, 0); } /* begin_capture */ @@ -713,7 +714,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) int cap_type; unsigned long then; int stopmode; - u32 data[CX2341X_MBOX_MAX_DATA]; if (s->v4l2dev == NULL) return -EINVAL; @@ -793,27 +793,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } then = jiffies; - /* Make sure DMA is complete */ - add_wait_queue(&s->waitq, &wait); - do { - /* check if DMA is pending */ - if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */ - (read_reg(IVTV_REG_DMASTATUS) & 0x02)) { - /* Check for last DMA */ - ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0); - if (data[0] == 1) { - IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]); - break; - } - } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) { - break; - } - } while (!ivtv_msleep_timeout(10, 1) && - then + msecs_to_jiffies(2000) > jiffies); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&s->waitq, &wait); + /* Handle any pending interrupts */ + ivtv_msleep_timeout(100, 1); } atomic_dec(&itv->capturing); From f4071b85ea0ca3bd06f63c330562b4cfdffa8473 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Jul 2007 12:07:12 -0300 Subject: [PATCH 0610/2804] V4L/DVB (6046): ivtv: always steal full frames if out of buffers. When there are no more free buffers, then buffers are stolen from the predma queue. Buffers should be stolen from the head of that queue (which is where the most recently added buffers are) and all buffers belonging to a frame should be stolen. Otherwise 'half-frames' would remain in the queue, which leads to ugly playback and complete sync failure for YUV buffers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 9 ++++- drivers/media/video/ivtv/ivtv-fileops.c | 3 +- drivers/media/video/ivtv/ivtv-irq.c | 5 ++- drivers/media/video/ivtv/ivtv-queue.c | 54 +++++++++++++++---------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 0a1c16ad10bb..f5de2fd01b1a 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -356,7 +356,7 @@ struct ivtv_mailbox_data { }; /* per-buffer bit flags */ -#define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ +#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */ /* per-stream, s_flags */ #define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ @@ -437,7 +437,8 @@ struct ivtv_dma_page_info { struct ivtv_buffer { struct list_head list; dma_addr_t dma_handle; - unsigned long b_flags; + unsigned short b_flags; + unsigned short dma_xfer_cnt; char *buf; u32 bytesused; @@ -487,6 +488,10 @@ struct ivtv_stream { struct ivtv_queue q_dma; /* waiting for DMA */ struct ivtv_queue q_predma; /* waiting for DMA */ + /* DMA xfer counter, buffers belonging to the same DMA + xfer will have the same dma_xfer_cnt. */ + u16 dma_xfer_cnt; + /* Base Dev SG Array for cx23415/6 */ struct ivtv_SG_element *SGarray; struct ivtv_SG_element *PIOarray; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 908e640c274d..076b0089a2b0 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -247,8 +247,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, /* do we have new data? */ buf = ivtv_dequeue(s, &s->q_full); if (buf) { - if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags)) + if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0) return buf; + buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP; if (s->type == IVTV_ENC_STREAM_TYPE_MPG) /* byteswap MPG data */ ivtv_buf_swap(buf); diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index a97d55fd2277..8644f3dda31e 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -214,6 +214,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA s->SGarray[idx].src = cpu_to_le32(offset); s->SGarray[idx].size = cpu_to_le32(s->buf_size); buf->bytesused = (size < s->buf_size) ? size : s->buf_size; + buf->dma_xfer_cnt = s->dma_xfer_cnt; s->q_predma.bytesused += buf->bytesused; size -= buf->bytesused; @@ -286,7 +287,7 @@ static void dma_post(struct ivtv_stream *s) /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ if (s->type == IVTV_ENC_STREAM_TYPE_MPG || s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags); + buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP; } if (buf) buf->bytesused += s->dma_last_offset; @@ -396,12 +397,14 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) } itv->vbi.dma_offset = s_vbi->dma_offset; s_vbi->SG_length = 0; + s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } /* Mark last buffer size for Interrupt flag */ s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); + s->dma_xfer_cnt++; if (s->type == IVTV_ENC_STREAM_TYPE_VBI) set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index a04f9387f63d..bff75aeee0a0 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -60,6 +60,7 @@ void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_qu buf->bytesused = 0; buf->readpos = 0; buf->b_flags = 0; + buf->dma_xfer_cnt = 0; } spin_lock_irqsave(&s->qlock, flags); list_add_tail(&buf->list, &q->list); @@ -87,7 +88,7 @@ struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) } static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, - struct ivtv_queue *to, int clear, int full) + struct ivtv_queue *to, int clear) { struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); @@ -97,13 +98,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, from->bytesused -= buf->bytesused - buf->readpos; /* special handling for q_free */ if (clear) - buf->bytesused = buf->readpos = buf->b_flags = 0; - else if (full) { - /* special handling for stolen buffers, assume - all bytes are used. */ - buf->bytesused = s->buf_size; - buf->readpos = buf->b_flags = 0; - } + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; to->buffers++; to->length += s->buf_size; to->bytesused += buf->bytesused - buf->readpos; @@ -112,7 +107,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. If 'steal' != NULL, then buffers may also taken from that queue if - needed. + needed, but only if 'from' is the free queue. The buffer is automatically cleared if it goes to the free queue. It is also cleared if buffers need to be taken from the 'steal' queue and @@ -133,7 +128,7 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_ int rc = 0; int from_free = from == &s->q_free; int to_free = to == &s->q_free; - int bytes_available; + int bytes_available, bytes_steal; spin_lock_irqsave(&s->qlock, flags); if (needed_bytes == 0) { @@ -142,32 +137,47 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_ } bytes_available = from_free ? from->length : from->bytesused; - bytes_available += steal ? steal->length : 0; + bytes_steal = (from_free && steal) ? steal->length : 0; - if (bytes_available < needed_bytes) { + if (bytes_available + bytes_steal < needed_bytes) { spin_unlock_irqrestore(&s->qlock, flags); return -ENOMEM; } + while (bytes_available < needed_bytes) { + struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + u16 dma_xfer_cnt = buf->dma_xfer_cnt; + + /* move buffers from the tail of the 'steal' queue to the tail of the + 'from' queue. Always copy all the buffers with the same dma_xfer_cnt + value, this ensures that you do not end up with partial frame data + if one frame is stored in multiple buffers. */ + while (dma_xfer_cnt == buf->dma_xfer_cnt) { + list_move_tail(steal->list.prev, &from->list); + rc++; + steal->buffers--; + steal->length -= s->buf_size; + steal->bytesused -= buf->bytesused - buf->readpos; + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; + from->buffers++; + from->length += s->buf_size; + bytes_available += s->buf_size; + if (list_empty(&steal->list)) + break; + buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + } + } if (from_free) { u32 old_length = to->length; while (to->length - old_length < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - ivtv_queue_move_buf(s, from, to, 1, 0); + ivtv_queue_move_buf(s, from, to, 1); } } else { u32 old_bytesused = to->bytesused; while (to->bytesused - old_bytesused < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - ivtv_queue_move_buf(s, from, to, to_free, rc); + ivtv_queue_move_buf(s, from, to, to_free); } } spin_unlock_irqrestore(&s->qlock, flags); From 37093b1ea600d84fbf7252baf12eedec85ae40f1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Jul 2007 19:45:50 -0300 Subject: [PATCH 0611/2804] V4L/DVB (6047): ivtv: Fix scatter/gather DMA timeouts It turns out that the cx23415/6 DMA engine cannot do scatter/gather DMA reliably. Every so often depending on the phase of the moon and your hardware configuration the cx2341x DMA engine simply chokes on it and you have to reboot to get it working again. This change replaced the scatter/gather DMA by single transfers at a time, where the driver is now responsible for DMA-ing each buffer. UDMA is still done using scatter/gather DMA, that will be fixed soon. Many thanks to Mark Bryars for discovering the link between scatter/gather and the DMA timeouts. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 22 ++- drivers/media/video/ivtv/ivtv-irq.c | 242 ++++++++++++++---------- drivers/media/video/ivtv/ivtv-queue.c | 67 ++++--- drivers/media/video/ivtv/ivtv-queue.h | 8 +- drivers/media/video/ivtv/ivtv-streams.c | 2 +- 5 files changed, 202 insertions(+), 139 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index f5de2fd01b1a..e80f9f65a905 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -382,7 +382,6 @@ struct ivtv_mailbox_data { #define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ #define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ -#define IVTV_F_I_ENC_VBI 8 /* VBI DMA */ #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ #define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ @@ -405,7 +404,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ /* Scatter-Gather array element, used in DMA transfers */ -struct ivtv_SG_element { +struct ivtv_sg_element { u32 src; u32 dst; u32 size; @@ -417,7 +416,7 @@ struct ivtv_user_dma { struct page *map[IVTV_DMA_SG_OSD_ENT]; /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT]; + struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; dma_addr_t SG_handle; int SG_length; @@ -468,6 +467,10 @@ struct ivtv_stream { int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ + u32 pending_offset; + u32 pending_backup; + u64 pending_pts; + u32 dma_offset; u32 dma_backup; u64 dma_pts; @@ -493,10 +496,13 @@ struct ivtv_stream { u16 dma_xfer_cnt; /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element *SGarray; - struct ivtv_SG_element *PIOarray; - dma_addr_t SG_handle; - int SG_length; + struct ivtv_sg_element *sg_pending; + struct ivtv_sg_element *sg_processing; + struct ivtv_sg_element *sg_dma; + dma_addr_t sg_handle; + int sg_pending_size; + int sg_processing_size; + int sg_processed; /* SG List of Buffers */ struct scatterlist *SGlist; @@ -637,7 +643,6 @@ struct vbi_info { u32 enc_start, enc_size; int fpi; u32 frame; - u32 dma_offset; u8 cc_data_odd[256]; u8 cc_data_even[256]; int cc_pos; @@ -724,6 +729,7 @@ struct ivtv { int cur_pio_stream; /* index of stream doing PIO */ u32 dma_data_req_offset; u32 dma_data_req_size; + int dma_retries; int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ spinlock_t lock; /* lock access to this struct */ int search_pack_header; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 8644f3dda31e..9695e5356163 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -60,18 +60,18 @@ static void ivtv_pio_work_handler(struct ivtv *itv) buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list); list_for_each(p, &s->q_dma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - u32 size = s->PIOarray[i].size & 0x3ffff; + u32 size = s->sg_processing[i].size & 0x3ffff; /* Copy the data from the card to the buffer */ if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - memcpy_fromio(buf->buf, itv->dec_mem + s->PIOarray[i].src - IVTV_DECODER_OFFSET, size); + memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size); } else { - memcpy_fromio(buf->buf, itv->enc_mem + s->PIOarray[i].src, size); + memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size); } - if (s->PIOarray[i].size & 0x80000000) - break; i++; + if (i == s->sg_processing_size) + break; } write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); } @@ -105,7 +105,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA u32 offset, size; u32 UVoffset = 0, UVsize = 0; int skip_bufs = s->q_predma.buffers; - int idx = s->SG_length; + int idx = s->sg_pending_size; int rc; /* sanity checks */ @@ -123,7 +123,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA case IVTV_ENC_STREAM_TYPE_MPG: offset = data[1]; size = data[2]; - s->dma_pts = 0; + s->pending_pts = 0; break; case IVTV_ENC_STREAM_TYPE_YUV: @@ -131,13 +131,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA size = data[2]; UVoffset = data[3]; UVsize = data[4]; - s->dma_pts = ((u64) data[5] << 32) | data[6]; + s->pending_pts = ((u64) data[5] << 32) | data[6]; break; case IVTV_ENC_STREAM_TYPE_PCM: offset = data[1] + 12; size = data[2] - 12; - s->dma_pts = read_dec(offset - 8) | + s->pending_pts = read_dec(offset - 8) | ((u64)(read_dec(offset - 12)) << 32); if (itv->has_cx23415) offset += IVTV_DECODER_OFFSET; @@ -150,13 +150,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA IVTV_DEBUG_INFO("VBI offset == 0\n"); return -1; } - s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); + s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); break; case IVTV_DEC_STREAM_TYPE_VBI: size = read_dec(itv->vbi.dec_start + 4) + 8; offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; - s->dma_pts = 0; + s->pending_pts = 0; offset += IVTV_DECODER_OFFSET; break; default: @@ -165,17 +165,17 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } /* if this is the start of the DMA then fill in the magic cookie */ - if (s->SG_length == 0) { + if (s->sg_pending_size == 0) { if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET); + s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); } else { - s->dma_backup = read_enc(offset); + s->pending_backup = read_enc(offset); write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); } - s->dma_offset = offset; + s->pending_offset = offset; } bytes_needed = size; @@ -202,7 +202,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } s->buffers_stolen = rc; - /* got the buffers, now fill in SGarray (DMA) */ + /* got the buffers, now fill in sg_pending */ buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); memset(buf->buf, 0, 128); list_for_each(p, &s->q_predma.list) { @@ -210,9 +210,9 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA if (skip_bufs-- > 0) continue; - s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].src = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(s->buf_size); + s->sg_pending[idx].dst = buf->dma_handle; + s->sg_pending[idx].src = offset; + s->sg_pending[idx].size = s->buf_size; buf->bytesused = (size < s->buf_size) ? size : s->buf_size; buf->dma_xfer_cnt = s->dma_xfer_cnt; @@ -230,7 +230,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } idx++; } - s->SG_length = idx; + s->sg_pending_size = idx; return 0; } @@ -332,9 +332,9 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) offset = uv_offset; y_done = 1; } - s->SGarray[idx].src = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].dst = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(buf->bytesused); + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = buf->bytesused; offset += buf->bytesused; bytes_written += buf->bytesused; @@ -343,10 +343,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) ivtv_buf_sync_for_device(s, buf); idx++; } - s->SG_length = idx; - - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); + s->sg_pending_size = idx; /* Sync Hardware SG List of buffers */ ivtv_stream_sync_for_device(s); @@ -362,6 +359,34 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) spin_unlock_irqrestore(&itv->dma_reg_lock, flags); } +static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); +} + +static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); +} + /* start the encoder DMA */ static void ivtv_dma_enc_start(struct ivtv_stream *s) { @@ -375,8 +400,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); if (ivtv_use_dma(s)) - s->SGarray[s->SG_length - 1].size = - cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256); + s->sg_pending[s->sg_pending_size - 1].size += 256; /* If this is an MPEG stream, and VBI data is also pending, then append the VBI DMA to the MPEG DMA and transfer both sets of data at once. @@ -387,45 +411,39 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) sure we only use the MPEG DMA to transfer the VBI DMA if both are in use. This way no conflicts occur. */ clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length && - s->SG_length + s_vbi->SG_length <= s->buffers) { + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size && + s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) { ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); if (ivtv_use_dma(s_vbi)) - s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256); - for (i = 0; i < s_vbi->SG_length; i++) { - s->SGarray[s->SG_length++] = s_vbi->SGarray[i]; + s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256; + for (i = 0; i < s_vbi->sg_pending_size; i++) { + s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i]; } - itv->vbi.dma_offset = s_vbi->dma_offset; - s_vbi->SG_length = 0; + s_vbi->dma_offset = s_vbi->pending_offset; + s_vbi->sg_pending_size = 0; s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); s->dma_xfer_cnt++; - - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); - else - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + s->dma_offset = s->pending_offset; + s->dma_backup = s->pending_backup; + s->dma_pts = s->pending_pts; if (ivtv_use_pio(s)) { - for (i = 0; i < s->SG_length; i++) { - s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src); - s->PIOarray[i].size = le32_to_cpu(s->SGarray[i].size); - } set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); set_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = s->type; } else { - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); + itv->dma_retries = 0; + ivtv_dma_enc_start_xfer(s); set_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = s->type; itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); @@ -439,10 +457,15 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s) if (s->q_predma.bytesused) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); + s->dma_xfer_cnt++; + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name); - /* put SG Handle into register 0x0c */ - write_reg(s->SG_handle, IVTV_REG_DECDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); + itv->dma_retries = 0; + ivtv_dma_dec_start_xfer(s); set_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = s->type; itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); @@ -453,27 +476,42 @@ static void ivtv_irq_dma_read(struct ivtv *itv) { struct ivtv_stream *s = NULL; struct ivtv_buffer *buf; - int hw_stream_type; + int hw_stream_type = 0; IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); - del_timer(&itv->dma_timer); - if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { - IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS)); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) { + del_timer(&itv->dma_timer); + return; } - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - hw_stream_type = 2; - } - else { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - hw_stream_type = 0; - } - IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + s = &itv->streams[itv->cur_dma_stream]; ivtv_stream_sync_for_cpu(s); + if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { + IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n", + read_reg(IVTV_REG_DMASTATUS), + s->sg_processed, s->sg_processing_size, itv->dma_retries); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (itv->dma_retries == 3) { + itv->dma_retries = 0; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } + } + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_dec_start_xfer(s); + return; + } + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) + hw_stream_type = 2; + IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); + /* For some reason must kick the firmware, like PIO mode, I think this tells the firmware we are done and the size of the xfer so it can calculate what we need next. @@ -490,6 +528,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv) } wake_up(&s->waitq); } + del_timer(&itv->dma_timer); clear_bit(IVTV_F_I_UDMA, &itv->i_flags); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; @@ -501,33 +540,44 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; - del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); - IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); - if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags)) - data[1] = 3; - else if (data[1] > 2) + IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream); + if (itv->cur_dma_stream < 0) { + del_timer(&itv->dma_timer); return; - s = &itv->streams[ivtv_stream_map[data[1]]]; - if (data[0] & 0x18) { - IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]); } - s->SG_length = 0; + s = &itv->streams[itv->cur_dma_stream]; + ivtv_stream_sync_for_cpu(s); + + if (data[0] & 0x18) { + IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0], + s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (itv->dma_retries == 3) { + itv->dma_retries = 0; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } + } + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_enc_start_xfer(s); + return; + } + del_timer(&itv->dma_timer); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; dma_post(s); - ivtv_stream_sync_for_cpu(s); if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; dma_post(s); - s->dma_offset = tmp; } + s->sg_processing_size = 0; + s->sg_processed = 0; wake_up(&itv->dma_waitq); } @@ -541,8 +591,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) } s = &itv->streams[itv->cur_pio_stream]; IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - s->SG_length = 0; - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); + s->sg_pending_size = 0; clear_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = -1; dma_post(s); @@ -554,13 +603,8 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2); clear_bit(IVTV_F_I_PIO, &itv->i_flags); if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; dma_post(s); - s->dma_offset = tmp; } wake_up(&itv->dma_waitq); } @@ -572,19 +616,23 @@ static void ivtv_irq_dma_err(struct ivtv *itv) del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], - read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; /* retry */ - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) ivtv_dma_dec_start(s); else ivtv_dma_enc_start(s); return; } + if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + ivtv_udma_start(itv); + return; + } clear_bit(IVTV_F_I_UDMA, &itv->i_flags); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; @@ -628,14 +676,14 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) DMA the data. Since at most four VBI DMA buffers are available, we just drop the old requests when there are already three requests queued. */ - if (s->SG_length > 2) { + if (s->sg_pending_size > 2) { struct list_head *p; list_for_each(p, &s->q_predma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); ivtv_buf_sync_for_cpu(s, buf); } ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); - s->SG_length = 0; + s->sg_pending_size = 0; } /* if we can append the data, and the MPEG stream isn't capturing, then start a DMA request for just the VBI data. */ diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index bff75aeee0a0..d9a1478ca1f7 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -195,7 +195,7 @@ void ivtv_flush_queues(struct ivtv_stream *s) int ivtv_stream_alloc(struct ivtv_stream *s) { struct ivtv *itv = s->itv; - int SGsize = sizeof(struct ivtv_SG_element) * s->buffers; + int SGsize = sizeof(struct ivtv_sg_element) * s->buffers; int i; if (s->buffers == 0) @@ -205,27 +205,33 @@ int ivtv_stream_alloc(struct ivtv_stream *s) s->dma != PCI_DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - if (ivtv_might_use_pio(s)) { - s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->PIOarray == NULL) { - IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name); - return -ENOMEM; - } - } - - /* Allocate DMA SG Arrays */ - s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->SGarray == NULL) { - IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name); - if (ivtv_might_use_pio(s)) { - kfree(s->PIOarray); - s->PIOarray = NULL; - } + s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + if (s->sg_pending == NULL) { + IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); + return -ENOMEM; + } + s->sg_pending_size = 0; + + s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + if (s->sg_processing == NULL) { + IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + return -ENOMEM; + } + s->sg_processing_size = 0; + + s->sg_dma = (struct ivtv_sg_element *)kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); + if (s->sg_dma == NULL) { + IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + kfree(s->sg_processing); + s->sg_processing = NULL; return -ENOMEM; } - s->SG_length = 0; if (ivtv_might_use_dma(s)) { - s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma); + s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma); ivtv_stream_sync_for_cpu(s); } @@ -272,16 +278,19 @@ void ivtv_stream_free(struct ivtv_stream *s) } /* Free SG Array/Lists */ - if (s->SGarray != NULL) { - if (s->SG_handle != IVTV_DMA_UNMAPPED) { - pci_unmap_single(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); - s->SG_handle = IVTV_DMA_UNMAPPED; + if (s->sg_dma != NULL) { + if (s->sg_handle != IVTV_DMA_UNMAPPED) { + pci_unmap_single(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); + s->sg_handle = IVTV_DMA_UNMAPPED; } - kfree(s->SGarray); - kfree(s->PIOarray); - s->PIOarray = NULL; - s->SGarray = NULL; - s->SG_length = 0; + kfree(s->sg_pending); + kfree(s->sg_processing); + kfree(s->sg_dma); + s->sg_pending = NULL; + s->sg_processing = NULL; + s->sg_dma = NULL; + s->sg_pending_size = 0; + s->sg_processing_size = 0; } } diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h index 2ed8d548255d..14a9f7fe50aa 100644 --- a/drivers/media/video/ivtv/ivtv-queue.h +++ b/drivers/media/video/ivtv/ivtv-queue.h @@ -79,13 +79,13 @@ void ivtv_stream_free(struct ivtv_stream *s); static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) { if (ivtv_use_dma(s)) - pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) { if (ivtv_use_dma(s)) - pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 0582b9d57c55..d1cc366c2a35 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -154,7 +154,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; - s->SG_handle = IVTV_DMA_UNMAPPED; + s->sg_handle = IVTV_DMA_UNMAPPED; ivtv_queue_init(&s->q_free); ivtv_queue_init(&s->q_full); ivtv_queue_init(&s->q_dma); From de870b52be9d52c3dad76c9ea7399cb94abcaa1a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 29 Jul 2007 15:22:05 -0300 Subject: [PATCH 0612/2804] V4L/DVB (6048): ivtv: fix stop stream locking Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-streams.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index d1cc366c2a35..4272fbc0bc8b 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -751,6 +751,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) stopmode = 1; } + /* ensure these actions are done only once */ + mutex_lock(&itv->serialize_lock); + /* end_capture */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); @@ -803,9 +806,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Clear capture and no-read bits */ clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - /* ensure these global cleanup actions are done only once */ - mutex_lock(&itv->serialize_lock); - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); From 51a99c0428cc6d3a442eef1c9046099c9383d72b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 15:16:00 -0300 Subject: [PATCH 0613/2804] V4L/DVB (6049): ivtv: fix VBI reinsertion decoding - Invalid VBI packets should result in an empty VBI frame, not in an zero-sized frame that causes the reader to incorrectly return a 0 (EOF) value. - PIO completion should not reset the sg_pending_size field. - The DMA offset detection code should be ignored for PIO transfers: it somehow messes up the data on the card and is not needed anyway for PIO. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 5 ++--- drivers/media/video/ivtv/ivtv-vbi.c | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 9695e5356163..7272f1a71dd9 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -165,7 +165,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } /* if this is the start of the DMA then fill in the magic cookie */ - if (s->sg_pending_size == 0) { + if (s->sg_pending_size == 0 && ivtv_use_dma(s)) { if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); @@ -252,7 +252,7 @@ static void dma_post(struct ivtv_stream *s) /* Sync Buffer */ ivtv_buf_sync_for_cpu(s, buf); - if (x == 0) { + if (x == 0 && ivtv_use_dma(s)) { offset = s->dma_last_offset; if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) { @@ -591,7 +591,6 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) } s = &itv->streams[itv->cur_pio_stream]; IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - s->sg_pending_size = 0; clear_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = -1; dma_post(s); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index a7282a91bd97..a58c833c2b04 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -163,8 +163,8 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) linemask[1] = 0xf; p += 4; } else { - /* unknown VBI data stream */ - return 0; + /* unknown VBI data, convert to empty VBI frame */ + linemask[0] = linemask[1] = 0; } for (i = 0; i < 36; i++) { int err = 0; From e17a06badaedba89fad989eed409661c89a22e04 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 15:48:42 -0300 Subject: [PATCH 0614/2804] V4L/DVB (6050): ivtv: retry/timer improvements - Give up frame after three retries. - When the last capture/decode ends, make sure to delete the dma_timer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 4 ++++ drivers/media/video/ivtv/ivtv-streams.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 7272f1a71dd9..d68853fd60a3 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -494,7 +494,9 @@ static void ivtv_irq_dma_read(struct ivtv *itv) s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; } else { /* Retry, starting with the first xfer segment. @@ -554,7 +556,9 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; } else { /* Retry, starting with the first xfer segment. diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 4272fbc0bc8b..2e632014c90d 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -816,6 +816,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Set the following Interrupt mask bits for capture */ ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + del_timer(&itv->dma_timer); /* event notification (off) */ if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { @@ -873,6 +874,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); + del_timer(&itv->dma_timer); clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); clear_bit(IVTV_F_S_STREAMING, &s->s_flags); From 8267761881d6bb91c168ba4d629b778cf106c485 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Aug 2007 07:16:07 -0300 Subject: [PATCH 0615/2804] V4L/DVB (6051): cx25840: make proper use of SOFT_RESET Whenever the 0x80b register is used the microcontroller should be reset. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 22 ++++++++++----------- drivers/media/video/cx25840/cx25840-core.c | 7 ++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index f93b5160bb4f..3d46a776df36 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -157,13 +157,12 @@ void cx25840_audio_set_path(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); + /* assert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x01); + /* stop microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0); - /* assert soft reset */ - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0x01); - /* Mute everything to prevent the PFFT! */ cx25840_write(client, 0x8d3, 0x1f); @@ -181,15 +180,14 @@ void cx25840_audio_set_path(struct i2c_client *client) set_audclk_freq(client, state->audclk_freq); - /* deassert soft reset */ - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0x00); - if (state->aud_input != CX25840_AUDIO_SERIAL) { /* When the microcontroller detects the * audio format, it will unmute the lines */ cx25840_and_or(client, 0x803, ~0x10, 0x10); } + + /* deassert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x00); } static int get_volume(struct i2c_client *client) @@ -330,18 +328,18 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: + if (!state->is_cx25836) + cx25840_and_or(client, 0x810, ~0x1, 1); if (state->aud_input != CX25840_AUDIO_SERIAL) { cx25840_and_or(client, 0x803, ~0x10, 0); cx25840_write(client, 0x8d3, 0x1f); } - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 1); retval = set_audclk_freq(client, *(u32 *)arg); - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0); if (state->aud_input != CX25840_AUDIO_SERIAL) { cx25840_and_or(client, 0x803, ~0x10, 0x10); } + if (!state->is_cx25836) + cx25840_and_or(client, 0x810, ~0x1, 0); return retval; case VIDIOC_G_CTRL: diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 8f9c32613b45..ae90d1c3d12b 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -250,6 +250,7 @@ static void input_change(struct i2c_client *client) } cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); + cx25840_and_or(client, 0x810, ~0x01, 1); if (state->radio) { cx25840_write(client, 0x808, 0xf9); @@ -284,11 +285,7 @@ static void input_change(struct i2c_client *client) cx25840_write(client, 0x80b, 0x10); } - if (cx25840_read(client, 0x803) & 0x10) { - /* restart audio decoder microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } + cx25840_and_or(client, 0x810, ~0x01, 0); } static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, From 2ce55b606b29c6ab0c8583772f6807b49cc89372 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 05:09:37 -0300 Subject: [PATCH 0616/2804] V4L/DVB (6053): ivtv: setup TV output standard on init to prevent flicker The TV output standard was set only on first use, which meant that the saa7127 was set to NTSC until then, leading to flickering on PAL systems. Since the saa7127 has no firmware it is OK to initialize it immediately. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 198e443e8a5e..8086c62e7545 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1145,6 +1145,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, are not. */ itv->tuner_std = itv->std; + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); + } + retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); From 313e91e824c0c595dec3740c0c87f55eea6bdb3f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 05:32:33 -0300 Subject: [PATCH 0617/2804] V4L/DVB (6054): ivtv: specify some stream sizes in kB instead of MB Some streams (PCM, VBI decoding) do not need that much memory, so specify the allocated memory in kB instead of MB to limit memory usage. E.g. 1 MB is overkill for the VBI decoding stream, 64 kB is enough. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 18 +++++++++--------- drivers/media/video/ivtv/ivtv-driver.h | 8 +++++--- drivers/media/video/ivtv/ivtv-streams.c | 14 +++++++------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 8086c62e7545..3591518ed358 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -208,7 +208,7 @@ MODULE_PARM_DESC(enc_vbi_buffers, "Encoder VBI Buffers (in MB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffers (in MB)\n" + "Encoder PCM buffers (in kB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); MODULE_PARM_DESC(dec_mpg_buffers, "Decoder MPG buffers (in MB)\n" @@ -217,7 +217,7 @@ MODULE_PARM_DESC(dec_yuv_buffers, "Decoder YUV buffers (in MB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); MODULE_PARM_DESC(dec_vbi_buffers, - "Decoder VBI buffers (in MB)\n" + "Decoder VBI buffers (in kB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); MODULE_PARM_DESC(newi2c, "Use new I2C implementation\n" @@ -547,13 +547,13 @@ static void ivtv_process_options(struct ivtv *itv) const char *chipname; int i, j; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; itv->options.cardtype = cardtype[itv->num]; itv->options.tuner = tuner[itv->num]; itv->options.radio = radio[itv->num]; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index e80f9f65a905..783fb4449b0e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -186,10 +186,12 @@ extern const u32 yuv_offset[4]; #define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 #define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 #define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1 +/* Exception: size in kB for this stream (MB is overkill) */ +#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 #define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 #define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1 +/* Exception: size in kB for this stream (MB is way overkill) */ +#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 /* ======================================================================== */ /* ========================== END USER SETTABLE DMA VARIABLES ============= */ @@ -321,7 +323,7 @@ extern int ivtv_debug; struct ivtv_options { - int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */ + int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ int cardtype; /* force card type on load */ int tuner; /* set tuner on load */ int radio; /* enable/disable radio */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 2e632014c90d..fab5c51b1519 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -150,7 +150,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->dma = ivtv_stream_info[type].dma; s->buf_size = itv->stream_buf_size[type]; if (s->buf_size) - s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size; + s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size; spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; @@ -192,7 +192,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) /* User explicitly selected 0 buffers for these streams, so don't create them. */ if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE && - itv->options.megabytes[type] == 0) { + itv->options.kilobytes[type] == 0) { IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); return 0; } @@ -238,18 +238,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) switch (vfl_type) { case VFL_TYPE_GRABBER: - IVTV_INFO("Registered device video%d for %s (%d MB)\n", - s->v4l2dev->minor, s->name, itv->options.megabytes[type]); + IVTV_INFO("Registered device video%d for %s (%d kB)\n", + s->v4l2dev->minor, s->name, itv->options.kilobytes[type]); break; case VFL_TYPE_RADIO: IVTV_INFO("Registered device radio%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); break; case VFL_TYPE_VBI: - if (itv->options.megabytes[type]) - IVTV_INFO("Registered device vbi%d for %s (%d MB)\n", + if (itv->options.kilobytes[type]) + IVTV_INFO("Registered device vbi%d for %s (%d kB)\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, - s->name, itv->options.megabytes[type]); + s->name, itv->options.kilobytes[type]); else IVTV_INFO("Registered device vbi%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); From 1aa32c2ffd146dddd76babf842e998502f1b993a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 06:08:58 -0300 Subject: [PATCH 0618/2804] V4L/DVB (6055): ivtv: improve debug messages - add FILE debug flag for open/close/read/write/poll. - show cmd for encoder/decoder command ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 18 ++++++-- drivers/media/video/ivtv/ivtv-driver.h | 55 +++++++++++++------------ drivers/media/video/ivtv/ivtv-fileops.c | 18 ++++---- drivers/media/video/ivtv/ivtv-ioctl.c | 9 +++- drivers/media/video/ivtv/ivtv-mailbox.c | 6 +-- 5 files changed, 64 insertions(+), 42 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 3591518ed358..93ddea49f0ed 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -186,8 +186,18 @@ MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 1023 gives full debugging)"); + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: ioctl\n" + "\t\t\t 16/0x0010: file\n" + "\t\t\t 32/0x0020: dma\n" + "\t\t\t 64/0x0040: irq\n" + "\t\t\t 128/0x0080: decoder\n" + "\t\t\t 256/0x0100: yuv\n" + "\t\t\t 512/0x0200: i2c\n" + "\t\t\t1024/0x0400: high volume\n"); MODULE_PARM_DESC(ivtv_pci_latency, "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" "\t\t\tDefault: Yes"); @@ -1354,9 +1364,9 @@ static int module_start(void) return -1; } - if (ivtv_debug < 0 || ivtv_debug > 1023) { + if (ivtv_debug < 0 || ivtv_debug > 2047) { ivtv_debug = 0; - printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 1023\n"); + printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n"); } if (pci_register_driver(&ivtv_pci_driver)) { diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 783fb4449b0e..93a008409f49 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -256,17 +256,18 @@ extern const u32 yuv_offset[4]; /* debugging */ -#define IVTV_DBGFLG_WARN (1 << 0) -#define IVTV_DBGFLG_INFO (1 << 1) -#define IVTV_DBGFLG_API (1 << 2) -#define IVTV_DBGFLG_DMA (1 << 3) -#define IVTV_DBGFLG_IOCTL (1 << 4) -#define IVTV_DBGFLG_I2C (1 << 5) -#define IVTV_DBGFLG_IRQ (1 << 6) -#define IVTV_DBGFLG_DEC (1 << 7) -#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_WARN (1 << 0) +#define IVTV_DBGFLG_INFO (1 << 1) +#define IVTV_DBGFLG_MB (1 << 2) +#define IVTV_DBGFLG_IOCTL (1 << 3) +#define IVTV_DBGFLG_FILE (1 << 4) +#define IVTV_DBGFLG_DMA (1 << 5) +#define IVTV_DBGFLG_IRQ (1 << 6) +#define IVTV_DBGFLG_DEC (1 << 7) +#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_I2C (1 << 9) /* Flag to turn on high volume debugging */ -#define IVTV_DBGFLG_HIGHVOL (1 << 9) +#define IVTV_DBGFLG_HIGHVOL (1 << 10) /* NOTE: extra space before comma in 'itv->num , ## args' is required for gcc-2.95, otherwise it won't compile. */ @@ -275,30 +276,32 @@ extern const u32 yuv_offset[4]; if ((x) & ivtv_debug) \ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_MB(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) #define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_FILE(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) #define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \ do { \ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_HI_API(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_HI_MB(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) #define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_HI_FILE(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) /* Standard kernel messages */ #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 076b0089a2b0..846e9bfa41f0 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -409,7 +409,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; struct ivtv *itv = s->itv; - IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc); + IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) pos += rc; return rc; @@ -500,7 +500,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ struct ivtv_stream *s = &itv->streams[id->type]; int rc; - IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name); + IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); rc = ivtv_start_capture(id); if (rc) @@ -538,7 +538,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c int rc; DEFINE_WAIT(wait); - IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name); + IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); if (s->type != IVTV_DEC_STREAM_TYPE_MPG && s->type != IVTV_DEC_STREAM_TYPE_YUV && @@ -646,7 +646,7 @@ retry: to transfer the rest. */ if (count && !(filp->f_flags & O_NONBLOCK)) goto retry; - IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); return bytes_written; } @@ -658,6 +658,7 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) int res = 0; /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Decoder poll\n"); poll_wait(filp, &s->waitq, wait); set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); @@ -687,9 +688,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) s->name, rc); return POLLERR; } + IVTV_DEBUG_FILE("Encoder poll started capture\n"); } /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); if (eof || s->q_full.length) @@ -702,7 +705,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close() of %s\n", s->name); /* 'Unclaim' this stream */ @@ -740,7 +743,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close() of %s\n", s->name); /* Stop decoding */ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { @@ -772,7 +775,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close %s\n", s->name); v4l2_prio_close(&itv->prio, &id->prio); @@ -855,6 +858,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) IVTV_ERR("Failed to initialize on minor %d\n", minor); return -ENXIO; } + IVTV_DEBUG_FILE("open %s\n", s->name); if (y == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 734f2d2ffa62..2c0f27241332 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1138,12 +1138,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void memset(&enc->raw, 0, sizeof(enc->raw)); switch (enc->cmd) { case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); enc->flags = 0; if (try) return 0; return ivtv_start_capture(id); case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; if (try) return 0; @@ -1151,6 +1153,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void return 0; case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); enc->flags = 0; if (try) return 0; @@ -1163,6 +1166,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void break; case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); enc->flags = 0; if (try) return 0; @@ -1174,6 +1178,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_unmute(itv); break; default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); return -EINVAL; } break; @@ -1408,9 +1413,9 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) int try = (cmd == VIDEO_TRY_COMMAND); if (try) - IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n"); + IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); else - IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n"); + IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); return ivtv_video_command(itv, id, vc, try); } diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c index 5e3b679202ae..b05436da7136 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.c +++ b/drivers/media/video/ivtv/ivtv-mailbox.c @@ -225,15 +225,15 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) } if (args < 0 || args > CX2341X_MBOX_MAX_DATA || cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { - IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args); + IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args); return -EINVAL; } if (api_info[cmd].flags & API_HIGH_VOL) { - IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name); + IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name); } else { - IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name); + IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name); } /* clear possibly uninitialized part of data array */ From baa4072d84e7a2e9954121c826d7bb8f1fb66b38 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 07:10:55 -0300 Subject: [PATCH 0619/2804] V4L/DVB (6056): ivtv: move serialization to the fileops level Serialization is now done on the open/close/ioctl level and also when the read/write/poll start an encoder/decoder stream. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 95 +++++++++++++++---------- drivers/media/video/ivtv/ivtv-ioctl.c | 26 +++++-- drivers/media/video/ivtv/ivtv-streams.c | 11 --- 3 files changed, 76 insertions(+), 56 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 846e9bfa41f0..1f3c8d0310f5 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -502,7 +502,9 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + mutex_lock(&itv->serialize_lock); rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); if (rc) return rc; return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); @@ -613,7 +615,9 @@ retry: } /* Start decoder (returns 0 if already started) */ + mutex_lock(&itv->serialize_lock); rc = ivtv_start_decoding(id, itv->speed); + mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); @@ -681,8 +685,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) /* Start a capture if there is none */ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - int rc = ivtv_start_capture(id); + int rc; + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", s->name, rc); @@ -788,6 +795,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) /* 'Unclaim' this stream */ /* Stop radio */ + mutex_lock(&itv->serialize_lock); if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { /* Closing radio device, return to TV mode */ ivtv_mute(itv); @@ -822,53 +830,26 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) ivtv_stop_capture(id, 0); } kfree(id); + mutex_unlock(&itv->serialize_lock); return 0; } -int ivtv_v4l2_open(struct inode *inode, struct file *filp) +static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) { - int x, y = 0; + struct ivtv *itv = s->itv; struct ivtv_open_id *item; - struct ivtv *itv = NULL; - struct ivtv_stream *s = NULL; - int minor = iminor(inode); - /* Find which card this open was on */ - spin_lock(&ivtv_cards_lock); - for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { - /* find out which stream this open was on */ - for (y = 0; y < IVTV_MAX_STREAMS; y++) { - s = &ivtv_cards[x]->streams[y]; - if (s->v4l2dev && s->v4l2dev->minor == minor) { - itv = ivtv_cards[x]; - break; - } - } - } - spin_unlock(&ivtv_cards_lock); - - if (itv == NULL) { - /* Couldn't find a device registered - on that minor, shouldn't happen! */ - IVTV_WARN("No ivtv device found on minor %d\n", minor); - return -ENXIO; - } - - if (ivtv_init_on_first_open(itv)) { - IVTV_ERR("Failed to initialize on minor %d\n", minor); - return -ENXIO; - } IVTV_DEBUG_FILE("open %s\n", s->name); - if (y == IVTV_DEC_STREAM_TYPE_MPG && + if (s->type == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) return -EBUSY; - if (y == IVTV_DEC_STREAM_TYPE_YUV && + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) return -EBUSY; - if (y == IVTV_DEC_STREAM_TYPE_YUV) { + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { if (read_reg(0x82c) == 0) { IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); /* return -ENODEV; */ @@ -883,7 +864,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -ENOMEM; } item->itv = itv; - item->type = y; + item->type = s->type; v4l2_prio_open(&itv->prio, &item->prio); item->open_id = itv->open_id++; @@ -925,14 +906,50 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) } /* YUV or MPG Decoding Mode? */ - if (y == IVTV_DEC_STREAM_TYPE_MPG) + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - else if (y == IVTV_DEC_STREAM_TYPE_YUV) - { + else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); + return 0; +} + +int ivtv_v4l2_open(struct inode *inode, struct file *filp) +{ + int res, x, y = 0; + struct ivtv *itv = NULL; + struct ivtv_stream *s = NULL; + int minor = iminor(inode); + + /* Find which card this open was on */ + spin_lock(&ivtv_cards_lock); + for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { + /* find out which stream this open was on */ + for (y = 0; y < IVTV_MAX_STREAMS; y++) { + s = &ivtv_cards[x]->streams[y]; + if (s->v4l2dev && s->v4l2dev->minor == minor) { + itv = ivtv_cards[x]; + break; + } + } + } + spin_unlock(&ivtv_cards_lock); + + if (itv == NULL) { + /* Couldn't find a device registered + on that minor, shouldn't happen! */ + IVTV_WARN("No ivtv device found on minor %d\n", minor); + return -ENXIO; } - return 0; + mutex_lock(&itv->serialize_lock); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on minor %d\n", minor); + mutex_unlock(&itv->serialize_lock); + return -ENXIO; + } + res = ivtv_serialized_open(s, filp); + mutex_unlock(&itv->serialize_lock); + return res; } void ivtv_mute(struct ivtv *itv) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2c0f27241332..2061d82653fc 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1446,11 +1446,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return 0; if (nonblocking) return -EAGAIN; - /* wait for event */ + /* Wait for event. Note that serialize_lock is locked, + so to allow other processes to access the driver while + we are waiting unlock first and later lock again. */ + mutex_unlock(&itv->serialize_lock); prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0) schedule(); finish_wait(&itv->event_waitq, &wait); + mutex_lock(&itv->serialize_lock); if (signal_pending(current)) { /* return if a signal was received */ IVTV_DEBUG_INFO("User stopped wait for event\n"); @@ -1580,12 +1584,9 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, return 0; } -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - /* Filter dvb ioctls that cannot be handled by video_usercopy */ switch (cmd) { case VIDEO_SELECT_SOURCE: @@ -1620,3 +1621,16 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, } return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); } + +int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + struct ivtv *itv = id->itv; + int res; + + mutex_lock(&itv->serialize_lock); + res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg); + mutex_unlock(&itv->serialize_lock); + return res; +} diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index fab5c51b1519..65fa247e33c5 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -437,9 +437,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (s->v4l2dev == NULL) return -EINVAL; - /* Big serialization lock to ensure no two streams are started - simultaneously: that can give all sorts of weird results. */ - mutex_lock(&itv->serialize_lock); IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { @@ -481,7 +478,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) 0, sizeof(itv->vbi.sliced_mpeg_size)); break; default: - mutex_unlock(&itv->serialize_lock); return -EINVAL; } s->subtype = subtype; @@ -564,7 +560,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) { IVTV_DEBUG_WARN( "Error starting capture!\n"); - mutex_unlock(&itv->serialize_lock); return -EINVAL; } @@ -580,7 +575,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) /* you're live! sit back and await interrupts :) */ atomic_inc(&itv->capturing); - mutex_unlock(&itv->serialize_lock); return 0; } @@ -751,9 +745,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) stopmode = 1; } - /* ensure these actions are done only once */ - mutex_lock(&itv->serialize_lock); - /* end_capture */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); @@ -810,7 +801,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); if (atomic_read(&itv->capturing) > 0) { - mutex_unlock(&itv->serialize_lock); return 0; } @@ -827,7 +817,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } wake_up(&s->waitq); - mutex_unlock(&itv->serialize_lock); return 0; } From 3869c6a088c2eb165abe476c3372c6a3653649b3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 07:11:44 -0300 Subject: [PATCH 0620/2804] V4L/DVB (6057): ivtv-fb: remove unused header includes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index d2cc03172749..008076543aca 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -57,12 +57,8 @@ #endif #include "ivtv-driver.h" -#include "ivtv-queue.h" #include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-fileops.h" #include "ivtv-mailbox.h" -#include "ivtv-cards.h" #include /* card parameters */ From 0989fd2c88a11aa5014b2b348ed51872d14d536d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 12:25:39 -0300 Subject: [PATCH 0621/2804] V4L/DVB (6058): ivtv: add support for highmem udma When trying to DMA userspace buffers to the cx23415 you need to check whether the page is in highmem. If this is the case, then bounce buffers have to be used to allow DMA. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 2 ++ drivers/media/video/ivtv/ivtv-udma.c | 45 +++++++++++++++++++++----- drivers/media/video/ivtv/ivtv-yuv.c | 9 +++++- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 93a008409f49..784098d4bf04 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -419,6 +419,8 @@ struct ivtv_user_dma { struct mutex lock; int page_count; struct page *map[IVTV_DMA_SG_OSD_ENT]; + /* Needed when dealing with highmem userspace buffers */ + struct page *bouncemap[IVTV_DMA_SG_OSD_ENT]; /* Base Dev SG Array for cx23415/6 */ struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index bd642e1aafc3..5592abbe14e6 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -38,23 +38,38 @@ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) { int i, offset; + unsigned long flags; offset = dma_page->offset; /* Fill SG Array with new values */ for (i = 0; i < dma_page->page_count; i++) { - if (i == dma_page->page_count - 1) { - dma->SGlist[map_offset].length = dma_page->tail; + unsigned int len = (i == dma_page->page_count - 1) ? + dma_page->tail : PAGE_SIZE - offset; + + dma->SGlist[map_offset].length = len; + dma->SGlist[map_offset].offset = offset; + if (PageHighMem(dma->map[map_offset])) { + void *src; + + if (dma->bouncemap[map_offset] == NULL) + dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); + if (dma->bouncemap[map_offset] == NULL) + return -ENOMEM; + local_irq_save(flags); + src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; + memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); + kunmap_atomic(src, KM_BOUNCE_READ); + local_irq_restore(flags); + dma->SGlist[map_offset].page = dma->bouncemap[map_offset]; } else { - dma->SGlist[map_offset].length = PAGE_SIZE - offset; + dma->SGlist[map_offset].page = dma->map[map_offset]; } - dma->SGlist[map_offset].offset = offset; - dma->SGlist[map_offset].page = dma->map[map_offset]; offset = 0; map_offset++; } - return map_offset; + return 0; } void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { @@ -89,7 +104,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, { struct ivtv_dma_page_info user_dma; struct ivtv_user_dma *dma = &itv->udma; - int err; + int i, err; IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); @@ -123,7 +138,14 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, dma->page_count = user_dma.page_count; /* Fill SG List with new values */ - ivtv_udma_fill_sg_list(dma, &user_dma, 0); + err = ivtv_udma_fill_sg_list(dma, &user_dma, 0); + if (err) { + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return err; + } /* Map SG List */ dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); @@ -166,6 +188,8 @@ void ivtv_udma_unmap(struct ivtv *itv) void ivtv_udma_free(struct ivtv *itv) { + int i; + /* Unmap SG Array */ if (itv->udma.SG_handle) { pci_unmap_single(itv->dev, itv->udma.SG_handle, @@ -176,6 +200,11 @@ void ivtv_udma_free(struct ivtv *itv) if (itv->udma.SG_length) { pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); } + + for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) { + if (itv->udma.bouncemap[i]) + __free_page(itv->udma.bouncemap[i]); + } } void ivtv_udma_start(struct ivtv *itv) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index fa8c76f3d359..2ae7556f5e68 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -83,7 +83,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } /* Fill & map SG List */ - ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)); + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) { + IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return -ENOMEM; + } dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); /* Fill SG Array with new values */ From 25e3f8f40ecf61b87a4b6476ea6d00cb5b74628c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 15:03:05 -0300 Subject: [PATCH 0622/2804] V4L/DVB (6059): ivtv: log stereo/bilingual audio modes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2061d82653fc..de866d450ecd 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1235,7 +1235,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s\n", audin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, + (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; struct v4l2_audioout audout; @@ -1247,11 +1248,20 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "YUV Frames", "Passthrough", }; + static const char * const audio_modes[] = { + "Stereo", + "Left", + "Right", + "Mono", + "Swapped" + }; ivtv_get_output(itv, itv->active_output, &vidout); ivtv_get_audio_output(itv, 0, &audout); IVTV_INFO("Video Output: %s\n", vidout.name); - IVTV_INFO("Audio Output: %s\n", audout.name); + IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, + audio_modes[itv->audio_stereo_mode], + audio_modes[itv->audio_bilingual_mode]); if (mode < 0 || mode > OUT_PASSTHROUGH) mode = OUT_NONE; IVTV_INFO("Output Mode: %s\n", output_modes[mode]); From 8beb058f1ecde7bc0554d18ce1baa18b5dfb02d3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 17:56:41 -0300 Subject: [PATCH 0623/2804] V4L/DVB (6060): ivtv: fix IVTV_IOC_DMA_FRAME bug introduced by highmem bugfix The return value of ivtv_udma_fill_sg_list() was changed by the highmem bugfix, but that return value was still used in ivtv-yuv.c. Revert to the old return value, but in addition return -1 in case of a memory allocation error. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-udma.c | 12 +++++++----- drivers/media/video/ivtv/ivtv-yuv.c | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index 5592abbe14e6..7e503adacea0 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -40,6 +40,9 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info int i, offset; unsigned long flags; + if (map_offset < 0) + return map_offset; + offset = dma_page->offset; /* Fill SG Array with new values */ @@ -55,7 +58,7 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info if (dma->bouncemap[map_offset] == NULL) dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); if (dma->bouncemap[map_offset] == NULL) - return -ENOMEM; + return -1; local_irq_save(flags); src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); @@ -69,7 +72,7 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info offset = 0; map_offset++; } - return 0; + return map_offset; } void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { @@ -138,13 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, dma->page_count = user_dma.page_count; /* Fill SG List with new values */ - err = ivtv_udma_fill_sg_list(dma, &user_dma, 0); - if (err) { + if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) { for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); } dma->page_count = 0; - return err; + return -ENOMEM; } /* Map SG List */ diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 2ae7556f5e68..1922c1da20d3 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -83,7 +83,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } /* Fill & map SG List */ - if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) { + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) { IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); From 7c03a4488bf6d28078488c70c82357d4286cacc5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 18:59:42 -0300 Subject: [PATCH 0624/2804] V4L/DVB (6061): ivtv: add VIDIOC_OVERLAY Add VIDIOC_OVERLAY to enable/disable the OSD. Also add the OSD state to the log status report. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 45 +++++++++++++++++++++---- drivers/media/video/ivtv/ivtv-streams.c | 6 ++-- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index de866d450ecd..ed5707660e0e 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1217,9 +1217,19 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void break; } + case VIDIOC_OVERLAY: { + int *on = arg; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0); + break; + } + case VIDIOC_LOG_STATUS: { int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; + u32 data[CX2341X_MBOX_MAX_DATA]; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -1234,8 +1244,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); - IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s%s\n", audin.name, + IVTV_INFO("Video Input: %s\n", vidin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; @@ -1255,6 +1265,22 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "Mono", "Swapped" }; + static const char * const alpha_mode[] = { + "None", + "Global", + "Local", + "Global and Local" + }; + static const char * const pixel_format[] = { + "Indexed", + "RGB 5:6:5", + "ARGB 1:5:5:5", + "ARGB 1:4:4:4", + "ARGB 8:8:8:8", + "5", + "6", + "7", + }; ivtv_get_output(itv, itv->active_output, &vidout); ivtv_get_audio_output(itv, 0, &audout); @@ -1264,12 +1290,17 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void audio_modes[itv->audio_bilingual_mode]); if (mode < 0 || mode > OUT_PASSTHROUGH) mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", + data[0] & 1 ? "On" : "Off", + alpha_mode[(data[0] >> 1) & 0x3], + pixel_format[(data[0] >> 3) & 0x7]); } - IVTV_INFO("Tuner: %s\n", + IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); for (i = 0; i < IVTV_MAX_STREAMS; i++) { struct ivtv_stream *s = &itv->streams[i]; @@ -1279,7 +1310,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void (s->buffers - s->q_free.buffers) * 100 / s->buffers, (s->buffers * s->buf_size) / 1024, s->buffers); } - IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); + IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); break; } @@ -1501,6 +1532,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_S_AUDOUT: case VIDIOC_S_EXT_CTRLS: case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: ret = v4l2_prio_check(&itv->prio, &id->prio); if (ret) return ret; @@ -1554,6 +1586,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_TRY_ENCODER_CMD: case VIDIOC_G_FBUF: case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: if (ivtv_debug & IVTV_DBGFLG_IOCTL) { printk(KERN_INFO "ivtv%d ioctl: ", itv->num); v4l_printk_ioctl(cmd); diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 65fa247e33c5..ebf925c549fd 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -75,7 +75,7 @@ static struct { struct file_operations *fops; } ivtv_stream_info[] = { { /* IVTV_ENC_STREAM_TYPE_MPG */ - "encoder MPEG", + "encoder MPG", VFL_TYPE_GRABBER, 0, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, &ivtv_v4l2_enc_fops @@ -93,7 +93,7 @@ static struct { &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_PCM */ - "encoder PCM audio", + "encoder PCM", VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, &ivtv_v4l2_enc_fops @@ -105,7 +105,7 @@ static struct { &ivtv_v4l2_enc_fops }, { /* IVTV_DEC_STREAM_TYPE_MPG */ - "decoder MPEG", + "decoder MPG", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, &ivtv_v4l2_dec_fops From 8ddac9ee4b6f08d7cacf79202ab882eefc55b0c0 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 06:57:55 -0300 Subject: [PATCH 0625/2804] V4L/DVB (6064): cx88: Add symbolic names for the PCI interrupt bits Used for the PCI_INTMSK and PCI_INT_STAT registers. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 16 +++++++++------- drivers/media/video/cx88/cx88-cards.c | 4 +++- drivers/media/video/cx88/cx88-core.c | 2 +- drivers/media/video/cx88/cx88-input.c | 4 ++-- drivers/media/video/cx88/cx88-mpeg.c | 9 +++++---- drivers/media/video/cx88/cx88-reg.h | 22 ++++++++++++++++++++++ drivers/media/video/cx88/cx88-vbi.c | 4 ++-- drivers/media/video/cx88/cx88-video.c | 9 +++++---- 8 files changed, 49 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 2d666b56020c..a529c0a87d1a 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -149,9 +149,11 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) /* reset counter */ cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); - dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02)); + dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", + chip->core->pci_irqmask, + chip->core->pci_irqmask | PCI_INT_AUDINT); /* enable irqs */ - cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02); + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); /* Enables corresponding bits at AUD_INT_STAT */ @@ -184,7 +186,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) cx_clear(MO_AUD_DMACNTRL, 0x11); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x02); + cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); cx_clear(MO_AUD_INTMSK, (1<<16)| (1<<12)| @@ -273,7 +275,8 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_AUDINT); if (0 == status) goto out; dprintk( 3, "cx8801_irq\n" ); @@ -282,8 +285,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) handled = 1; cx_write(MO_PCI_INTSTAT, status); - if (status & 0x02) - { + if (status & PCI_INT_AUDINT) { dprintk( 2, " ALSA IRQ handling\n" ); cx8801_aud_irq(chip); } @@ -293,7 +295,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) dprintk( 0, "clearing mask\n" ); dprintk(1,"%s/0: irq loop -- clearing mask\n", core->name); - cx_clear(MO_PCI_INTMSK,0x02); + cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); } out: diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index e73e8c96d5b9..a4eb6a87a761 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -2063,7 +2063,9 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) atomic_inc(&core->refcount); core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); - core->pci_irqmask = 0x00fc00; + core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT | + PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT | + PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT; mutex_init(&core->lock); core->nr = nr; diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 0765e9db5339..970926b97ee4 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -498,7 +498,7 @@ int cx88_core_irq(struct cx88_core *core, u32 status) { int handled = 0; - if (status & (1<<18)) { + if (status & PCI_INT_IR_SMPINT) { cx88_ir_irq(core); handled++; } diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 120f56857f0e..c78a95ef7581 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -167,7 +167,7 @@ static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) schedule_work(&ir->work); } if (ir->sampling) { - core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */ + core->pci_irqmask |= PCI_INT_IR_SMPINT; cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */ cx_write(MO_DDSCFG_IO, 0x5); /* enable */ } @@ -177,7 +177,7 @@ static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) { if (ir->sampling) { cx_write(MO_DDSCFG_IO, 0x0); - core->pci_irqmask &= ~(1 << 18); + core->pci_irqmask &= ~PCI_INT_IR_SMPINT; } if (ir->polling) { diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 5da47e251e66..d46114685ed1 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -148,7 +148,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, /* enable irqs */ dprintk( 1, "setting the interrupt mask\n" ); - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); cx_set(MO_TS_INTMSK, 0x1f0011); /* start dma */ @@ -166,7 +166,7 @@ static int cx8802_stop_dma(struct cx8802_dev *dev) cx_clear(MO_TS_DMACNTRL, 0x11); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000004); + cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT); cx_clear(MO_TS_INTMSK, 0x1f0011); /* Reset the controller */ @@ -413,7 +413,8 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_TSINT); if (0 == status) goto out; dprintk( 1, "cx8802_irq\n" ); @@ -424,7 +425,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) if (status & core->pci_irqmask) cx88_core_irq(core,status); - if (status & 0x04) + if (status & PCI_INT_TSINT) cx8802_mpeg_irq(dev); }; if (MAX_IRQ_LOOP == loop) { diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index d3bf5b17b1d4..2b1d102cd220 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -582,6 +582,28 @@ /* ---------------------------------------------------------------------- */ /* various constants */ +// DMA +/* Interrupt mask/status */ +#define PCI_INT_VIDINT (1 << 0) +#define PCI_INT_AUDINT (1 << 1) +#define PCI_INT_TSINT (1 << 2) +#define PCI_INT_VIPINT (1 << 3) +#define PCI_INT_HSTINT (1 << 4) +#define PCI_INT_TM1INT (1 << 5) +#define PCI_INT_SRCDMAINT (1 << 6) +#define PCI_INT_DSTDMAINT (1 << 7) +#define PCI_INT_RISC_RD_BERRINT (1 << 10) +#define PCI_INT_RISC_WR_BERRINT (1 << 11) +#define PCI_INT_BRDG_BERRINT (1 << 12) +#define PCI_INT_SRC_DMA_BERRINT (1 << 13) +#define PCI_INT_DST_DMA_BERRINT (1 << 14) +#define PCI_INT_IPB_DMA_BERRINT (1 << 15) +#define PCI_INT_I2CDONE (1 << 16) +#define PCI_INT_I2CRACK (1 << 17) +#define PCI_INT_IR_SMPINT (1 << 18) +#define PCI_INT_GPIO_INT0 (1 << 19) +#define PCI_INT_GPIO_INT1 (1 << 20) + #define SEL_BTSC 0x01 #define SEL_EIAJ 0x02 #define SEL_A2 0x04 diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 86c1cf8334bc..16c0d36bb6b2 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -67,7 +67,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); cx_set(MO_VID_INTMSK, 0x0f0088); /* enable capture */ @@ -91,7 +91,7 @@ int cx8800_stop_vbi_dma(struct cx8800_dev *dev) cx_clear(VID_CAPTURE_CONTROL,0x18); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000001); + cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); cx_clear(MO_VID_INTMSK, 0x0f0088); return 0; } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index e158ea2454af..e96c688cba9f 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -423,7 +423,7 @@ static int start_video_dma(struct cx8800_dev *dev, q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); /* Enables corresponding bits at PCI_INT_STAT: bits 0 to 4: video, audio, transport stream, VIP, Host @@ -456,7 +456,7 @@ static int stop_video_dma(struct cx8800_dev *dev) cx_clear(VID_CAPTURE_CONTROL,0x06); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000001); + cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); cx_clear(MO_VID_INTMSK, 0x0f0011); return 0; } @@ -1604,7 +1604,8 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_VIDINT); if (0 == status) goto out; cx_write(MO_PCI_INTSTAT, status); @@ -1612,7 +1613,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) if (status & core->pci_irqmask) cx88_core_irq(core,status); - if (status & 0x01) + if (status & PCI_INT_VIDINT) cx8800_vid_irq(dev); }; if (10 == loop) { From 5ba862b77e2d7f9e6e2cb133c43be32ac612aea5 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 07:02:26 -0300 Subject: [PATCH 0626/2804] V4L/DVB (6065): cx88-alsa: Call core irq handler when needed When an irq handled by the cx88 core driver (currently IR and errors) occurs and the cx88-alsa irq handler is the first called, it will claim to have handled the irq but it doesn't call cx88_core_irq() to handle it. The means loading cx88-alsa can disable the IR remote. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index a529c0a87d1a..76a8c01208c1 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -285,6 +285,8 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) handled = 1; cx_write(MO_PCI_INTSTAT, status); + if (status & core->pci_irqmask) + cx88_core_irq(core, status); if (status & PCI_INT_AUDINT) { dprintk( 2, " ALSA IRQ handling\n" ); cx8801_aud_irq(chip); From 59fd8f8d8ee9f7539758419965381bcccfa6f798 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 22:09:42 -0300 Subject: [PATCH 0627/2804] V4L/DVB (6066): cx88-alsa: Change order of interrupt enabling, fix spurious IRQs Currently the driver turns on audio interrupts, then sets the audio interrupt mask to select which interrupts to get. One could received unwanted interrupts since the mask is set _after_ interrupts have already been turned on. Change the order of the operations, and clear any audio interrupt status bits that are already set for good measure. Before changing the SRAM FIFO parameters, make sure the FIFO isn't being used. This shouldn't happen with just the ALSA driver, as it should never try to turn on FIFO/RISC/DMA while they are already on. However, the V4L driver needs to turn the audio FIFO on for analog audio output to work (undocumented cx88 bug). The FIFO parameters are in an inconsistent state while they are updated, and this results in many FIFO sync error IRQs if the FIFO is in use while it's in this inconsistent state. Also create and use a bunch of symbolic constants for audio interrupt mask bits. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 42 +++++++++++++--------------- drivers/media/video/cx88/cx88-reg.h | 13 +++++++++ 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 76a8c01208c1..ecb9a74ae03d 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -136,12 +136,11 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) struct cx88_core *core=chip->core; struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25]; - - dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start); + /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ + cx_clear(MO_AUD_DMACNTRL, 0x11); /* setup fifo + format - out channel */ - cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25], - buf->bpl, buf->risc.dma); + cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma); /* sets bpl size */ cx_write(MO_AUDD_LNGTH, buf->bpl); @@ -149,27 +148,30 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) /* reset counter */ cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d lines/irq, " + "%d B/irq\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + chip->num_periods, buf->bpl * chip->num_periods); + dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", chip->core->pci_irqmask, chip->core->pci_irqmask | PCI_INT_AUDINT); - /* enable irqs */ - cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); - /* Enables corresponding bits at AUD_INT_STAT */ - cx_write(MO_AUD_INTMSK, - (1<<16)| - (1<<12)| - (1<<4)| - (1<<0) - ); + cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); + + /* Clean any pending interrupt bits already set */ + cx_write(MO_AUD_INTSTAT, ~0); + + /* enable audio irqs */ + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */ if (debug) - cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); + cx88_sram_channel_dump(chip->core, audio_ch); return 0; } @@ -187,12 +189,8 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) /* disable irqs */ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); - cx_clear(MO_AUD_INTMSK, - (1<<16)| - (1<<12)| - (1<<4)| - (1<<0) - ); + cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); if (debug) cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); @@ -239,14 +237,14 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), status, mask); /* risc op code error */ - if (status & (1 << 16)) { + if (status & AUD_INT_OPC_ERR) { printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); cx_clear(MO_AUD_DMACNTRL, 0x11); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); } /* risc1 downstream */ - if (status & 0x01) { + if (status & AUD_INT_DN_RISCI1) { spin_lock(&chip->reg_lock); count = cx_read(MO_AUDD_GPCNT); spin_unlock(&chip->reg_lock); diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index 2b1d102cd220..2ec52d1cdea0 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -612,6 +612,19 @@ #define SEL_FMRADIO 0x20 // AUD_CTL +#define AUD_INT_DN_RISCI1 (1 << 0) +#define AUD_INT_UP_RISCI1 (1 << 1) +#define AUD_INT_RDS_DN_RISCI1 (1 << 2) +#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ +#define AUD_INT_UP_RISCI2 (1 << 5) +#define AUD_INT_RDS_DN_RISCI2 (1 << 6) +#define AUD_INT_DN_SYNC (1 << 12) +#define AUD_INT_UP_SYNC (1 << 13) +#define AUD_INT_RDS_DN_SYNC (1 << 14) +#define AUD_INT_OPC_ERR (1 << 16) +#define AUD_INT_BER_IRQ (1 << 20) +#define AUD_INT_MCHG_IRQ (1 << 21) + #define EN_BTSC_FORCE_MONO 0 #define EN_BTSC_FORCE_STEREO 1 #define EN_BTSC_FORCE_SAP 2 From 5a5b3b5d4fe3acdd9fb73162023422a9ee0e56f3 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 21:01:40 -0300 Subject: [PATCH 0628/2804] V4L/DVB (6067): cx88-alsa: Hardware doesn't support mono audio channels_min should be 2, not 1. The hardware only supports stereo. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index ecb9a74ae03d..3e293da0f70b 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -335,7 +335,7 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = { .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (2*2048), .period_bytes_min = 2048, From 19453bc18848e842a9743fcc40707e6fb19ae92b Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 22:54:49 -0300 Subject: [PATCH 0629/2804] V4L/DVB (6068): cx88-alsa: Use pci_dev->revision The revision is part of the pci_dev struct, so there is no need to read it in. Stop storing the revision and latency in the chip struct, since they're never used after being printed out when the driver loads. linux/pci.h wasn't included. It was getting picked up something else, probably cx88.h, but this file uses struct pci_dev so it should include pci.h. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 3e293da0f70b..8d19d33c8b32 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -60,7 +61,6 @@ struct cx88_audio_dev { /* pci i/o */ struct pci_dev *pci; - unsigned char pci_rev,pci_lat; /* audio controls */ int irq; @@ -667,6 +667,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, snd_cx88_card_t *chip; struct cx88_core *core; int err; + unsigned char pci_lat; *rchip = NULL; @@ -711,13 +712,12 @@ static int __devinit snd_cx88_create(struct snd_card *card, } /* print pci info */ - pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev); - pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat); + pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat); dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, " "latency: %d, mmio: 0x%llx\n", core->name, devno, - pci_name(pci), chip->pci_rev, pci->irq, - chip->pci_lat,(unsigned long long)pci_resource_start(pci,0)); + pci_name(pci), pci->revision, pci->irq, + pci_lat, (unsigned long long)pci_resource_start(pci,0)); chip->irq = pci->irq; synchronize_irq(chip->irq); From 261f5081a4dbcd148be0a0e744fb454a4f688441 Mon Sep 17 00:00:00 2001 From: Edgar Simo Date: Mon, 20 Aug 2007 14:06:00 -0300 Subject: [PATCH 0630/2804] V4L/DVB (6071): saa7134-dvb: add missing newline This is a simple whitespace cleanup. Signed-off-by: Edgar Simo Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-dvb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 1f6bd3300715..a0ce67ecb018 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -567,6 +567,7 @@ static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config } /* ------------------------------------------------------------------ */ + static struct tda1004x_config tda827x_lifeview_config = { .demod_address = 0x08, .invert = 1, @@ -746,6 +747,7 @@ static struct tda1004x_config asus_p7131_hybrid_lna_config = { .antenna_switch= 2, .request_firmware = philips_tda1004x_request_firmware }; + static struct tda1004x_config kworld_dvb_t_210_config = { .demod_address = 0x08, .invert = 1, @@ -760,6 +762,7 @@ static struct tda1004x_config kworld_dvb_t_210_config = { .antenna_switch= 1, .request_firmware = philips_tda1004x_request_firmware }; + /* ------------------------------------------------------------------ * special case: this card uses saa713x GPIO22 for the mode switch */ From d90d9f5a0ae9eb80bb3a33472074a114af7e548d Mon Sep 17 00:00:00 2001 From: Edgar Simo Date: Mon, 20 Aug 2007 14:14:50 -0300 Subject: [PATCH 0631/2804] V4L/DVB (6072): saa7134: add DVB-T support for Avermedia Super 007 Add DVB-T support for Avermedia Super 007 Analog television is untested. The device lacks input adapters for radio, svideo & composite -- seems to be a DVB-T ONLY device. Signed-off-by: Edgar Simo Acked-by: Hermann Pitton Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 23 +++++++++++++++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 18 ++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 1 + 4 files changed, 43 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 3f8aeab50a10..831b4da48b80 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -115,3 +115,4 @@ 114 -> KWorld DVB-T 210 [17de:7250] 115 -> Sabrent PCMCIA TV-PCB05 [0919:2003] 116 -> 10MOONS TM300 TV Card [1131:2304] +117 -> Avermedia Super 007 [1461:f01d] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 25ec16810818..5c3174a62e58 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3534,6 +3534,22 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x3000, }, }, + [SAA7134_BOARD_AVERMEDIA_SUPER_007] = { + .name = "Avermedia Super 007", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 0, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, /* FIXME: analog tv untested */ + .vmux = 1, + .amux = TV, + .tv = 1, + }}, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4256,6 +4272,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0x2304, .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ + .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4564,6 +4586,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: + case SAA7134_BOARD_AVERMEDIA_SUPER_007: { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index a0ce67ecb018..bbab252cbeee 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -763,6 +763,21 @@ static struct tda1004x_config kworld_dvb_t_210_config = { .request_firmware = philips_tda1004x_request_firmware }; +static struct tda1004x_config avermedia_super_007_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .gpio_config = TDA10046_GP01_I, + .if_freq = TDA10046_FREQ_045, + .i2c_gate = 0x4b, + .tuner_address = 0x60, + .tuner_config = 0, + .antenna_switch= 1, + .request_firmware = philips_tda1004x_request_firmware +}; + /* ------------------------------------------------------------------ * special case: this card uses saa713x GPIO22 for the mode switch */ @@ -1025,6 +1040,9 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config); break; + case SAA7134_BOARD_AVERMEDIA_SUPER_007: + configure_tda827x_fe(dev, &avermedia_super_007_config); + break; default: wprintk("Huh? unknown DVB card?\n"); break; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 346255468dad..fd12942b3a10 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -239,6 +239,7 @@ struct saa7134_format { #define SAA7134_BOARD_KWORLD_DVBT_210 114 #define SAA7134_BOARD_SABRENT_TV_PCB05 115 #define SAA7134_BOARD_10MOONSTVMASTER3 116 +#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 From c996899d0bc2414c7ff4682500344eb912d5ee1d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 20 Aug 2007 21:04:44 -0300 Subject: [PATCH 0632/2804] V4L/DVB (6074): tuner: fix ifdef tags to match actual file name The file, tuner-driver.h was originally named tuner-hw.h, but we decided to rename it. At the time, I had forgotten to change the #ifdef __TUNER_HW_H__ to #ifdef __TUNER_DRIVER_H__ . This patch corrects that. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index fa51b7cec691..145045561a51 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -19,8 +19,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __TUNER_HW_H__ -#define __TUNER_HW_H__ +#ifndef __TUNER_DRIVER_H__ +#define __TUNER_DRIVER_H__ #include #include @@ -95,7 +95,7 @@ extern int tea5767_tuner_init(struct i2c_client *c); printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#endif /* __TUNER_HW_H__ */ +#endif /* __TUNER_DRIVER_H__ */ /* * Overrides for Emacs so that we follow Linus's tabbing style. From ffbb807c1362a2b64b473c0e093c496a4c7de4bb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:14:12 -0300 Subject: [PATCH 0633/2804] V4L/DVB (6075): tuner: kernel headers go above subsystem headers Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 2 +- drivers/media/video/tda8290.c | 2 +- drivers/media/video/tda9887.c | 3 +-- drivers/media/video/tea5761.c | 2 +- drivers/media/video/tea5767.c | 2 +- drivers/media/video/tuner-core.c | 3 +-- drivers/media/video/tuner-simple.c | 1 + 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 7549114aaaca..210a84d8b971 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -5,8 +5,8 @@ */ #include #include -#include #include +#include #include "tuner-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 59cff5a3c59e..760d22f65da2 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -19,8 +19,8 @@ */ #include -#include #include +#include #include "tuner-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index aa311e4f1f61..e8597c10aa4c 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -3,12 +3,11 @@ #include #include #include -#include #include #include #include #include - +#include #include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index ae105c2cd0ac..43bdc374927e 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -8,8 +8,8 @@ */ #include -#include #include +#include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 4985d47a508f..4c9c4e01331a 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -11,8 +11,8 @@ */ #include -#include #include +#include #include "tuner-driver.h" #define PREFIX "TEA5767 " diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index e646465464a1..5f378265d8c5 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -15,9 +15,8 @@ #include #include #include -#include #include - +#include #include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 572f22423b98..f1ee60a4aa76 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include From 5634f2ec809818983f58880e381ee929187e4ddf Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:34:36 -0300 Subject: [PATCH 0634/2804] V4L/DVB (6076): Coding style fix drivers/media/video/zr36060.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36060.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c index 97c8f9b9dc12..1ef14fef08e6 100644 --- a/drivers/media/video/zr36060.c +++ b/drivers/media/video/zr36060.c @@ -38,14 +38,14 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* headerfile of this module */ -#include"zr36060.h" +#include "zr36060.h" /* codec io API */ -#include"videocodec.h" +#include "videocodec.h" /* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */ From b9758dfe0a2065f6fe3a484cc26886960aa847c1 Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:34:48 -0300 Subject: [PATCH 0635/2804] V4L/DVB (6077): Coding style fix drivers/media/video/zr36050.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36050.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c index a6bbd125631c..9f622e00c479 100644 --- a/drivers/media/video/zr36050.c +++ b/drivers/media/video/zr36050.c @@ -38,14 +38,14 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* headerfile of this module */ -#include"zr36050.h" +#include "zr36050.h" /* codec io API */ -#include"videocodec.h" +#include "videocodec.h" /* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */ From f518b43c452fb2dbe98ee211abfc63cf421927ab Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:36:51 -0300 Subject: [PATCH 0636/2804] V4L/DVB (6078): Coding style fix drivers/media/video/zr36016.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36016.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c index 62f77584fb85..dd084555da8f 100644 --- a/drivers/media/video/zr36016.c +++ b/drivers/media/video/zr36016.c @@ -38,11 +38,11 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* v4l API */ -#include +#include /* headerfile of this module */ #include"zr36016.h" From 9c12224a607a4b22ab86784e3394b52810b9507c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 21 Aug 2007 12:38:39 -0300 Subject: [PATCH 0637/2804] V4L/DVB (6079): Cleanup: remove linux/moduleparam.h from drivers/media files Since at least kernel 2.6.12-rc2, module.h includes moduleparm.h. This patch removes all occurences of moduleparm.h from drivers/media files. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-functions.c | 1 - drivers/media/common/ir-keymaps.c | 1 - drivers/media/dvb/bt8xx/bt878.c | 1 - drivers/media/dvb/bt8xx/dvb-bt8xx.c | 1 - drivers/media/dvb/dvb-core/dmxdev.c | 1 - drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 1 - drivers/media/dvb/dvb-core/dvb_frontend.c | 1 - drivers/media/dvb/dvb-core/dvbdev.c | 1 - drivers/media/dvb/frontends/bcm3510.c | 1 - drivers/media/dvb/frontends/cx22700.c | 1 - drivers/media/dvb/frontends/cx24110.c | 1 - drivers/media/dvb/frontends/cx24123.c | 1 - drivers/media/dvb/frontends/dib3000mb.c | 1 - drivers/media/dvb/frontends/dvb_dummy_fe.c | 1 - drivers/media/dvb/frontends/isl6421.c | 1 - drivers/media/dvb/frontends/l64781.c | 1 - drivers/media/dvb/frontends/lgdt330x.c | 1 - drivers/media/dvb/frontends/lnbp21.c | 1 - drivers/media/dvb/frontends/mt2060.c | 1 - drivers/media/dvb/frontends/mt2131.c | 1 - drivers/media/dvb/frontends/mt2266.c | 1 - drivers/media/dvb/frontends/mt312.c | 1 - drivers/media/dvb/frontends/mt352.c | 1 - drivers/media/dvb/frontends/nxt200x.c | 1 - drivers/media/dvb/frontends/or51132.c | 1 - drivers/media/dvb/frontends/or51211.c | 1 - drivers/media/dvb/frontends/sp8870.c | 1 - drivers/media/dvb/frontends/sp887x.c | 1 - drivers/media/dvb/frontends/stv0299.c | 1 - drivers/media/dvb/frontends/tda1004x.c | 1 - drivers/media/dvb/frontends/tda10086.c | 1 - drivers/media/dvb/frontends/tda8083.c | 1 - drivers/media/dvb/frontends/zl10353.c | 1 - drivers/media/dvb/ttpci/av7110.c | 1 - drivers/media/dvb/ttpci/av7110_ir.c | 1 - drivers/media/dvb/ttpci/budget-core.c | 1 - drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 1 - drivers/media/dvb/ttusb-dec/ttusb_dec.c | 1 - drivers/media/video/bt8xx/bttv-cards.c | 1 - drivers/media/video/bt8xx/bttv-driver.c | 1 - drivers/media/video/bt8xx/bttv-i2c.c | 1 - drivers/media/video/bt8xx/bttv-input.c | 1 - drivers/media/video/bt8xx/bttv-vbi.c | 1 - drivers/media/video/btcx-risc.c | 1 - drivers/media/video/cafe_ccic.c | 1 - drivers/media/video/cpia.c | 1 - drivers/media/video/cpia2/cpia2_v4l.c | 1 - drivers/media/video/cx2341x.c | 1 - drivers/media/video/cx88/cx88-blackbird.c | 1 - drivers/media/video/cx88/cx88-core.c | 1 - drivers/media/video/cx88/cx88-i2c.c | 1 - drivers/media/video/cx88/cx88-input.c | 1 - drivers/media/video/cx88/cx88-mpeg.c | 1 - drivers/media/video/cx88/cx88-tvaudio.c | 1 - drivers/media/video/cx88/cx88-vbi.c | 1 - drivers/media/video/cx88/cx88-video.c | 1 - drivers/media/video/cx88/cx88-vp3054-i2c.c | 1 - drivers/media/video/em28xx/em28xx-core.c | 1 - drivers/media/video/em28xx/em28xx-input.c | 1 - drivers/media/video/et61x251/et61x251_core.c | 1 - drivers/media/video/ir-kbd-i2c.c | 1 - drivers/media/video/ivtv/ivtv-driver.h | 1 - drivers/media/video/mt20xx.c | 1 - drivers/media/video/ov7670.c | 1 - drivers/media/video/ovcamchip/ovcamchip_core.c | 1 - drivers/media/video/pvrusb2/pvrusb2-main.c | 1 - drivers/media/video/pwc/pwc-if.c | 1 - drivers/media/video/saa7134/saa7134-alsa.c | 1 - drivers/media/video/saa7134/saa7134-core.c | 1 - drivers/media/video/saa7134/saa7134-empress.c | 1 - drivers/media/video/saa7134/saa7134-i2c.c | 1 - drivers/media/video/saa7134/saa7134-input.c | 1 - drivers/media/video/saa7134/saa7134-oss.c | 1 - drivers/media/video/saa7134/saa7134-ts.c | 1 - drivers/media/video/saa7134/saa7134-tvaudio.c | 1 - drivers/media/video/saa7134/saa7134-vbi.c | 1 - drivers/media/video/saa7134/saa7134-video.c | 1 - drivers/media/video/sn9c102/sn9c102_core.c | 1 - drivers/media/video/tda9887.c | 1 - drivers/media/video/tuner-core.c | 1 - drivers/media/video/tuner-simple.c | 1 - drivers/media/video/tvaudio.c | 1 - drivers/media/video/tveeprom.c | 1 - drivers/media/video/tvmixer.c | 1 - drivers/media/video/usbvision/usbvision-core.c | 1 - drivers/media/video/usbvision/usbvision-video.c | 1 - drivers/media/video/v4l1-compat.c | 1 - drivers/media/video/video-buf.c | 1 - drivers/media/video/vino.c | 1 - drivers/media/video/w9968cf.c | 1 - drivers/media/video/zc0301/zc0301_core.c | 1 - 91 files changed, 91 deletions(-) diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index a3292e955aaa..e7c3ab951a44 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -21,7 +21,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index cbd1184b5219..137f68bee39f 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -20,7 +20,6 @@ */ #include -#include #include #include diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index df72b4b8ee10..eca602d9b3de 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 67613eb6fa3d..dedd30a8356b 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 5394de2e4ce0..f94bc31e3b33 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 4fadddb264d6..b0bf21958ede 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 1a1b2405b0f4..880d499cd36a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 0f18ce8a9397..6b7954daeb4a 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index baeb311de893..a913f49c062b 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index 13ad1bfae663..11a4968f18cb 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 10fc0c8316dd..b03d8283c37d 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 0834c0677fef..d74fdbd63361 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index b6adea5ffeb8..136b9d2164d7 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index 6271b1e7f6ab..fed09dfb2b7c 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c index c967148a5945..684c8ec166cb 100644 --- a/drivers/media/dvb/frontends/isl6421.c +++ b/drivers/media/dvb/frontends/isl6421.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 1aeacb1c4af7..443d9045d4c9 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index e25286e2d431..bdc9fa88b86a 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c index 2d2f58c26226..76f935d9755a 100644 --- a/drivers/media/dvb/frontends/lnbp21.c +++ b/drivers/media/dvb/frontends/lnbp21.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c index 450fad8d9b65..1305b0e63ce5 100644 --- a/drivers/media/dvb/frontends/mt2060.c +++ b/drivers/media/dvb/frontends/mt2060.c @@ -22,7 +22,6 @@ /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 375dfa166817..6bcc4ccc9911 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 33b388e8f7b8..03fe8265745f 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 1ef821825641..0606b9a5b616 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 87e31ca7e108..5dd9b731f6f2 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index ddc84899cf86..fcf964fe1d6b 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 3cc8b444b8f2..b314a1f2deed 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -36,7 +36,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index f46d5a46683a..f02bd9445955 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index d98fd5c2e13e..da876f7bfe32 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 5c2f8f4e0ae5..1aa2539f5099 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 6c607302c1b6..035dd7ba6519 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 33a84372c9e6..8415a8a5247a 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index 0f2d4b415560..9a8ddc537f8f 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 0f041e873781..011b74f798a0 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 245f9b7dddfa..a97a7fd2c891 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8178832d14a8..aecfdeb8ec43 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 6322800ee12b..e8f553719bc5 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index b611f2b1f8bc..0252081f013c 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -34,7 +34,6 @@ * the project's page is at http://www.linuxtv.org/dvb/ */ -#include #include "budget.h" #include "ttpci-eeprom.h" diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index b60cdc93d6db..288e79f2cb0f 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 78c98b089975..5e691fd79904 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index f6715007d409..1f4f2625395e 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index cb555f2c40f9..0711c9507843 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 0dfa49b66418..844f1762c45a 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 4201552bc3c0..e7c521b8444a 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 93e35de5a181..007485aa4f01 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c index b4aca7249276..ce0840ccd594 100644 --- a/drivers/media/video/btcx-risc.c +++ b/drivers/media/video/btcx-risc.c @@ -23,7 +23,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index ef5361824f87..0fae0e000f1a 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 78c9699eafbb..a1d02e5ce0fd 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -28,7 +28,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 92778cd1d735..e3aaba1e0e0a 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "cpia2.h" #include "cpia2dev.h" diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index d73c86aeeaac..904bba0dbc4d 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -20,7 +20,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 74e3eb945751..206af419aea7 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -27,7 +27,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 970926b97ee4..cea3212d28b4 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 6b42dea860fd..6ae21750b2c1 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index c78a95ef7581..78adf4d1cf63 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "cx88.h" #include diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index d46114685ed1..6ece35b5fc83 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -23,7 +23,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 9aee8c51ee27..82364fb07025 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -36,7 +36,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 16c0d36bb6b2..72c1d19fa79f 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -2,7 +2,6 @@ */ #include #include -#include #include #include diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index e96c688cba9f..a16fc157a67d 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index f76ca9e2eebf..77c37889232b 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -23,7 +23,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 255a47dfb84f..d3282ec62c5b 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 55d45b0032cf..e3894b68c4ee 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -22,7 +22,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 585bd1fe0765..31062a981e36 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 2d709e064679..b3939a0bada0 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 784098d4bf04..03d31860851b 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 210a84d8b971..bd495c12d29f 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include "tuner-driver.h" diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index c4c5bd67f795..2bc6bdc9c1f2 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -12,7 +12,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c index 3fe9fa04cd84..8063e33f1c85 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_core.c +++ b/drivers/media/video/ovcamchip/ovcamchip_core.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include "ovcamchip_priv.h" diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 9ea41c6699bb..1ea0939096ae 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 931b274bffca..d3ac70a0d9ca 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -64,7 +64,6 @@ #include #include #include -#include #include "pwc.h" #include "pwc-kiara.h" diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 3c0fc9027ad0..eb5e77dd0d18 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 25f84701a8e8..80108ddf4834 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index fc260ec8fdc2..7ed4eaf05e13 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 1cb8c709ca90..cc87f5855a21 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 1b6dfd801cc1..80d2644f765a 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 72444f039e3d..1a737b647366 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 60a90a2617ae..7780b2cce80d 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 18b4817b4aac..43501b5dc05b 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index f38366a470fa..0044079f5da2 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9985ded20950..9c317ed6b210 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 36d8a455e0ec..e0accf1b8713 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index e8597c10aa4c..d162bc67d445 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 5f378265d8c5..baeae28f2836 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index f1ee60a4aa76..572f22423b98 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index cffb011590e3..a19cdcc17ef7 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index fdc3def437b1..4b2c4034f5b3 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -30,7 +30,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 3ae5a9cd2e28..544a4ae7d2ed 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -2,7 +2,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 5b1e346df206..c7d5f9ed22d7 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -45,7 +45,6 @@ #include #include -#include #include #ifdef CONFIG_KMOD diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 0cb006f2943d..2f9b2b9e3b09 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -68,7 +68,6 @@ #include #include -#include #include #ifdef CONFIG_KMOD diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index ede8543818bf..9eac65f34bff 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index a32dfbe0585a..f6f31e1773d1 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index a0c1647a2ba4..9a03dc82c6ca 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 8f31613b9903..77599f228b61 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -42,7 +42,6 @@ #include #include #include -#include #include "w9968cf.h" #include "w9968cf_decoder.h" diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 703b741e46df..35138c594be1 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include From aeb292d1342c649ac0b35ae9205b761fd14adb57 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Aug 2007 15:45:41 -0300 Subject: [PATCH 0638/2804] V4L/DVB (6081): ivtv: Fix static structure initialization Convert the initialization of ivtv_i2c_algo_template to C99-style. Otherwise a future change to struct i2c_algo_bit_data would break this code. Also declared that structure const - it's a template after all. Signed-off-by: Jean Delvare Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-i2c.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 5e12ebc2a9de..085dc3938da7 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -536,14 +536,13 @@ static struct i2c_adapter ivtv_i2c_adap_template = { #endif }; -static struct i2c_algo_bit_data ivtv_i2c_algo_template = { - NULL, /* ?? */ - ivtv_setsda_old, /* setsda function */ - ivtv_setscl_old, /* " */ - ivtv_getsda_old, /* " */ - ivtv_getscl_old, /* " */ - 10, /* udelay */ - 200 /* timeout */ +static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { + .setsda = ivtv_setsda_old, + .setscl = ivtv_setscl_old, + .getsda = ivtv_getsda_old, + .getscl = ivtv_getscl_old, + .udelay = 10, + .timeout = 200, }; static struct i2c_client ivtv_i2c_client_template = { From 16cf1d0c5d7b8970aca2ca426166833642ce0544 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 21 Aug 2007 08:19:16 -0300 Subject: [PATCH 0639/2804] V4L/DVB (6082): cx88: Improve risc instruction printing in sram channel dump When the risc instrunctions from the CMDS were printed, instruction arguments weren't taken into account. This changes output like: cx88[0]: risc0: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc1: 0x0cac2800 [ INVALID sol eol 23 21 19 18 13 count=2048 ] cx88[0]: risc2: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc3: 0x0cac2c00 [ INVALID sol eol 23 21 19 18 13 count=3072 ] cx88[0]: risc0: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc1: 0x0cac2800 [ arg #1 ] cx88[0]: risc2: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc3: 0x0cac2c00 [ arg #1 ] Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index cea3212d28b4..ce7f1f0ae054 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -434,10 +434,13 @@ void cx88_sram_channel_dump(struct cx88_core *core, printk("%s: cmds: %-12s: 0x%08x\n", core->name,name[i], cx_read(ch->cmds_start + 4*i)); - for (i = 0; i < 4; i++) { + for (n = 1, i = 0; i < 4; i++) { risc = cx_read(ch->cmds_start + 4 * (i+11)); printk("%s: risc%d: ", core->name, i); - cx88_risc_decode(risc); + if (--n) + printk("0x%08x [ arg #%d ]\n", risc, n); + else + n = cx88_risc_decode(risc); } for (i = 0; i < 16; i += n) { risc = cx_read(ch->ctrl_start + 4 * i); From 05b2723387cb4086535e935ee07cca19086308fc Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:34 -0300 Subject: [PATCH 0640/2804] V4L/DVB (6083): cx88-alsa: Rework buffer handling Rework the way the DMA buffer is handled and IRQs are generated. ALSA uses a ring-buffer of multiple periods. Each period is supposed to corrispond to one IRQ. The existing driver was generating one interrupt per ring-buffer, as opposed to per period. This meant that as soon as the IRQ was generated, the hardware was already starting to re-write the beginning of the buffer. Since the DMA happens on a per-line basis, there was only a narrow window to copy the data out before the buffer was overwritten. The cx88 core RISC program generator is modified so that it can set the IRQ and counter flags to count every X lines of DMA transfer. This way we can generate an interrupt every period instead of every full ring-buffer. Right now only period of one line are supported, but it should be possible to support longer periods. Note that a WRITE instruction generates an IRQ when it starts, not when the transfer is finished. Thus to generate an IRQ when line X is done, one must set the IRQ flag on the instruction that starts line X+1, not the one that ends line X. Change the line size so that there are four lines in the SRAM FIFO. If there are not four lines, the analog output from the cx88's internal DACs is full of clicks and pops. Try to handle FIFO sync errors. Sometimes the chip generates many of these errors before audio data starts. Up to 50 sync errors will be ignored and the counter reset. Have the IRQ handler save the RISC counter to the chip struct, and then have the pointer callback use this to calculate the pointer position. We could read the counter from the pointer callback, but sometimes the sync errors on start up cause the counter to go crazy. ALSA sees this and thinks there has been an overrun. The IRQ hander can avoid saving the counter position on sync errors. The chip "opened" flag wasn't necessary. ALSA won't try to open the same substream multiple times. Probably this code was cut&pasted from the bt87x driver, which has multiple sub-streams for one chip. Do error checking for the videobuf mapping functions. snd_card_cx88_runtime_free() is useless and can be deleted. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 168 ++++++++++++--------------- drivers/media/video/cx88/cx88-core.c | 22 ++-- drivers/media/video/cx88/cx88-mpeg.c | 2 +- drivers/media/video/cx88/cx88.h | 2 +- 4 files changed, 89 insertions(+), 105 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 8d19d33c8b32..33dd4cb5e877 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -3,6 +3,7 @@ * Support for audio capture * PCI function #1 of the cx2388x. * + * (c) 2007 Trent Piepho * (c) 2005,2006 Ricardo Cerqueira * (c) 2005 Mauro Carvalho Chehab * Based on a dummy cx88 module by Gerd Knorr @@ -47,7 +48,6 @@ #define dprintk_core(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg) - /**************************************************************************** Data type declarations - Can be moded to a header file later ****************************************************************************/ @@ -58,6 +58,7 @@ struct cx88_audio_dev { struct cx88_core *core; struct cx88_dmaqueue q; + u64 starttime; /* pci i/o */ struct pci_dev *pci; @@ -68,24 +69,20 @@ struct cx88_audio_dev { struct snd_card *card; spinlock_t reg_lock; + atomic_t count; unsigned int dma_size; unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf dma_risc; + struct videobuf_dmabuf dma_risc; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; - long int read_count; - long int read_offset; - - struct cx88_buffer *buf; - - long opened; - struct snd_pcm_substream *substream; + struct cx88_buffer *buf; + struct snd_pcm_substream *substream; }; typedef struct cx88_audio_dev snd_cx88_card_t; @@ -146,16 +143,13 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) cx_write(MO_AUDD_LNGTH, buf->bpl); /* reset counter */ - cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); + cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); + atomic_set(&chip->count, 0); - dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d lines/irq, " - "%d B/irq\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " + "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, chip->num_periods, buf->bpl * chip->num_periods); - dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", - chip->core->pci_irqmask, - chip->core->pci_irqmask | PCI_INT_AUDINT); - /* Enables corresponding bits at AUD_INT_STAT */ cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); @@ -198,7 +192,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) return 0; } -#define MAX_IRQ_LOOP 10 +#define MAX_IRQ_LOOP 50 /* * BOARD Specific: IRQ dma bits @@ -223,14 +217,11 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) { struct cx88_core *core = chip->core; u32 status, mask; - u32 count; status = cx_read(MO_AUD_INTSTAT); mask = cx_read(MO_AUD_INTMSK); - if (0 == (status & mask)) { - spin_unlock(&chip->reg_lock); + if (0 == (status & mask)) return; - } cx_write(MO_AUD_INTSTAT, status); if (debug > 1 || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq aud", @@ -238,27 +229,20 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) status, mask); /* risc op code error */ if (status & AUD_INT_OPC_ERR) { - printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); + printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name); cx_clear(MO_AUD_DMACNTRL, 0x11); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); } - + if (status & AUD_INT_DN_SYNC) { + dprintk(1, "Downstream sync error\n"); + cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); + return; + } /* risc1 downstream */ if (status & AUD_INT_DN_RISCI1) { - spin_lock(&chip->reg_lock); - count = cx_read(MO_AUDD_GPCNT); - spin_unlock(&chip->reg_lock); - if (chip->read_count == 0) - chip->read_count += chip->dma_size; - } - - if (chip->read_count >= chip->period_size) { - dprintk(2, "Elapsing period\n"); + atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT)); snd_pcm_period_elapsed(chip->substream); } - - dprintk(3,"Leaving audio IRQ handler...\n"); - /* FIXME: Any other status should deserve a special handling? */ } @@ -277,23 +261,20 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) (core->pci_irqmask | PCI_INT_AUDINT); if (0 == status) goto out; - dprintk( 3, "cx8801_irq\n" ); - dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP ); - dprintk( 3, " status: %d\n", status ); + dprintk(3, "cx8801_irq loop %d/%d, status %x\n", + loop, MAX_IRQ_LOOP, status); handled = 1; cx_write(MO_PCI_INTSTAT, status); if (status & core->pci_irqmask) cx88_core_irq(core, status); - if (status & PCI_INT_AUDINT) { - dprintk( 2, " ALSA IRQ handling\n" ); + if (status & PCI_INT_AUDINT) cx8801_aud_irq(chip); - } - }; + } if (MAX_IRQ_LOOP == loop) { - dprintk( 0, "clearing mask\n" ); - dprintk(1,"%s/0: irq loop -- clearing mask\n", + printk(KERN_ERR + "%s/1: IRQ loop detected, disabling interrupts\n", core->name); cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); } @@ -315,7 +296,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) chip->dma_size = 0; - return 0; + return 0; } /**************************************************************************** @@ -325,6 +306,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) /* * Digital hardware definition */ +#define DEFAULT_FIFO_SIZE 4096 static struct snd_pcm_hardware snd_cx88_digital_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -337,19 +319,15 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = { .rate_max = 48000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = (2*2048), - .period_bytes_min = 2048, - .period_bytes_max = 2048, - .periods_min = 2, - .periods_max = 2, + /* Analog audio output will be full of clicks and pops if there + are not exactly four lines in the SRAM FIFO buffer. */ + .period_bytes_min = DEFAULT_FIFO_SIZE/4, + .period_bytes_max = DEFAULT_FIFO_SIZE/4, + .periods_min = 1, + .periods_max = 1024, + .buffer_bytes_max = (1024*1024), }; -/* - * audio pcm capture runtime free - */ -static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime) -{ -} /* * audio pcm capture open callback */ @@ -359,26 +337,24 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if (test_and_set_bit(0, &chip->opened)) - return -EBUSY; - - err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) goto _error; chip->substream = substream; - chip->read_count = 0; - chip->read_offset = 0; - - runtime->private_free = snd_card_cx88_runtime_free; runtime->hw = snd_cx88_digital_hw; + if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) { + unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4; + bpl &= ~7; /* must be multiple of 8 */ + runtime->hw.period_bytes_min = bpl; + runtime->hw.period_bytes_max = bpl; + } + return 0; _error: dprintk(1,"Error opening PCM!\n"); - clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); return err; } @@ -387,11 +363,6 @@ _error: */ static int snd_cx88_close(struct snd_pcm_substream *substream) { - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); - - clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); - return 0; } @@ -403,54 +374,61 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); struct cx88_buffer *buf; + int ret; if (substream->runtime->dma_area) { dsp_buffer_free(chip); substream->runtime->dma_area = NULL; } - chip->period_size = params_period_bytes(hw_params); chip->num_periods = params_periods(hw_params); chip->dma_size = chip->period_size * params_periods(hw_params); BUG_ON(!chip->dma_size); + BUG_ON(chip->num_periods & (chip->num_periods-1)); - dprintk(1,"Setting buffer\n"); - - buf = kzalloc(sizeof(*buf),GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (NULL == buf) return -ENOMEM; buf->vb.memory = V4L2_MEMORY_MMAP; + buf->vb.field = V4L2_FIELD_NONE; buf->vb.width = chip->period_size; + buf->bpl = chip->period_size; buf->vb.height = chip->num_periods; buf->vb.size = chip->dma_size; - buf->vb.field = V4L2_FIELD_NONE; videobuf_dma_init(&buf->vb.dma); - videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE, + ret = videobuf_dma_init_kernel(&buf->vb.dma, PCI_DMA_FROMDEVICE, (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT)); + if (ret < 0) + goto error; - videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + ret = videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + if (ret < 0) + goto error; + ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->vb.dma.sglist, + buf->vb.width, buf->vb.height, 1); + if (ret < 0) + goto error; - cx88_risc_databuffer(chip->pci, &buf->risc, - buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); - - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + /* Loop back to start of program */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); buf->vb.state = STATE_PREPARED; - buf->bpl = chip->period_size; chip->buf = buf; chip->dma_risc = buf->vb.dma; - dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages); substream->runtime->dma_area = chip->dma_risc.vmalloc; return 0; + +error: + kfree(buf); + return ret; } /* @@ -477,7 +455,6 @@ static int snd_cx88_prepare(struct snd_pcm_substream *substream) return 0; } - /* * trigger callback */ @@ -486,6 +463,7 @@ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd) snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); int err; + /* Local interrupts are already disabled by ALSA */ spin_lock(&chip->reg_lock); switch (cmd) { @@ -512,17 +490,14 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + u16 count; - if (chip->read_count) { - chip->read_count -= snd_pcm_lib_period_bytes(substream); - chip->read_offset += snd_pcm_lib_period_bytes(substream); - if (chip->read_offset == chip->dma_size) - chip->read_offset = 0; - } - - dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count); - return bytes_to_frames(runtime, chip->read_offset); + count = atomic_read(&chip->count); +// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__, +// count, new, count & (runtime->periods-1), +// runtime->period_size * (count & (runtime->periods-1))); + return runtime->period_size * (count & (runtime->periods-1)); } /* @@ -592,10 +567,13 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol, int v; u32 old_control; + /* Do we really know this will always be called with IRQs on? */ spin_lock_irq(&chip->reg_lock); + old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); v = 0x3f - (value->value.integer.value[0] & 0x3f); cx_andor(AUD_VOL_CTL, 0x3f, v); + spin_unlock_irq(&chip->reg_lock); return v != old_control; diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index ce7f1f0ae054..41f7f374c183 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -68,13 +68,15 @@ static DEFINE_MUTEX(devlist); #define NO_SYNC_LINE (-1U) +/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be + generated _after_ lpi lines are transferred. */ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int lines, unsigned int lpi) { struct scatterlist *sg; - unsigned int line,todo; + unsigned int line,todo,sol; /* sync instruction */ if (sync_line != NO_SYNC_LINE) @@ -87,15 +89,19 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist, offset -= sg_dma_len(sg); sg++; } + if (lpi && line>0 && !(line % lpi)) + sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; + else + sol = RISC_SOL; if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); offset+=bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL| + *(rp++)=cpu_to_le32(RISC_WRITE|sol| (sg_dma_len(sg)-offset)); *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); todo -= (sg_dma_len(sg)-offset); @@ -146,10 +152,10 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx88_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); + bpl, padding, lines, 0); if (UNSET != bottom_offset) rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); + bpl, padding, lines, 0); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -159,7 +165,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) + unsigned int lines, unsigned int lpi) { u32 instructions; u32 *rp; @@ -176,7 +182,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write risc instructions */ rp = risc->cpu; - rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi); /* save pointer to jmp instruction address */ risc->jmp = rp; diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 6ece35b5fc83..4e6a84f15d17 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -253,7 +253,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, goto fail; cx88_risc_databuffer(dev->pci, &buf->risc, buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); + buf->vb.width, buf->vb.height, 0); } buf->vb.state = STATE_PREPARED; return 0; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 80e49f986fbb..e436a37b4404 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -519,7 +519,7 @@ cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, extern int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, - unsigned int lines); + unsigned int lines, unsigned int lpi); extern int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value); From ffb7394d51cf6f60a3753a5cc40613fc9d5c5c96 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:35 -0300 Subject: [PATCH 0641/2804] V4L/DVB (6084): cx88-alsa: Eliminate snd_cx88_cards The driver kepts a static global array of snd_card pointers for each card probed, which was never used. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 33dd4cb5e877..ac317fb856e4 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -95,7 +95,6 @@ typedef struct cx88_audio_dev snd_cx88_card_t; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; -static struct snd_card *snd_cx88_cards[SNDRV_CARDS]; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); @@ -759,8 +758,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, snd_card_free(card); return (err); } - snd_cx88_cards[devno] = card; - pci_set_drvdata(pci,card); devno++; From f6210c9160dff82ceaaf5e59cf5f8fcd6bdefa38 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:36 -0300 Subject: [PATCH 0642/2804] V4L/DVB (6085): cx88-alsa: Fix mmap support The driver has long claimed to support mmap, but it didn't work at all. Some of the dma buffer parameters weren't set, and since video_buf uses vmalloc to allocate the buffer, a page callback is needed too. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index ac317fb856e4..85d632224f3a 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -423,6 +424,8 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, chip->dma_risc = buf->vb.dma; substream->runtime->dma_area = chip->dma_risc.vmalloc; + substream->runtime->dma_bytes = chip->dma_size; + substream->runtime->dma_addr = 0; return 0; error: @@ -499,6 +502,16 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) return runtime->period_size * (count & (runtime->periods-1)); } +/* + * page callback (needed for mmap) + */ +static struct page *snd_cx88_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + void *pageptr = substream->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + /* * operators */ @@ -511,6 +524,7 @@ static struct snd_pcm_ops snd_cx88_pcm_ops = { .prepare = snd_cx88_prepare, .trigger = snd_cx88_card_trigger, .pointer = snd_cx88_pointer, + .page = snd_cx88_page, }; /* From ad8ff0f10b489562012e433acdac92498fe8bdc9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Aug 2007 16:01:58 -0300 Subject: [PATCH 0643/2804] V4L/DVB (6086): ivtv: fix output mode processing: UDMA_YUV wasn't cleared - Always clear when stopping the decoder - Clear if the filehandle that is being close was used for UDMA_YUV output. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 + drivers/media/video/ivtv/ivtv-fileops.c | 7 ++----- drivers/media/video/ivtv/ivtv-ioctl.c | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 03d31860851b..3ed4703956d3 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -517,6 +517,7 @@ struct ivtv_stream { struct ivtv_open_id { u32 open_id; int type; + int yuv_frames; enum v4l2_priority prio; struct ivtv *itv; }; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 1f3c8d0310f5..62ee41c5220b 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -757,6 +757,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) IVTV_DEBUG_INFO("close stopping decode\n"); ivtv_stop_v4l2_decode_stream(s, flags, pts); + itv->output_mode = OUT_NONE; } clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); @@ -764,11 +765,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) /* Restore registers we've changed & clean up any mess we've made */ ivtv_yuv_close(itv); } - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV) - itv->output_mode = OUT_NONE; - else if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_UDMA_YUV) - itv->output_mode = OUT_NONE; - else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG) + if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames) itv->output_mode = OUT_NONE; itv->speed = 0; diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index ed5707660e0e..2bb1e324785b 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1346,6 +1346,8 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) ivtv_release_stream(s); return -EBUSY; } + /* Mark that this file handle started the UDMA_YUV mode */ + id->yuv_frames = 1; if (args->y_source == NULL) return 0; return ivtv_yuv_prep_frame(itv, args); From ea115d54bc963eb2eb0dc223795f3bd6c689ff99 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Aug 2007 16:26:40 -0300 Subject: [PATCH 0644/2804] V4L/DVB (6087): ivtv: prevent changing VBI format while capture is in progress Changing the VBI format requires a CX2341X_ENC_INITIALIZE_INPUT firmware call. This can only be done if no capture is in progress. So return -EBUSY if the encoder is busy. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2bb1e324785b..0dde82f67e26 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -584,9 +584,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, /* set raw VBI format */ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI && - itv->vbi.sliced_in->service_set && - atomic_read(&itv->capturing) > 0) { + if (set_fmt && atomic_read(&itv->capturing) > 0) { return -EBUSY; } if (set_fmt) { @@ -624,7 +622,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, return 0; if (set == 0) return -EINVAL; - if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) { + if (atomic_read(&itv->capturing) > 0) { return -EBUSY; } itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); From 01f1e44fe8455b6c6c557a62119b8622fb99f5f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 21 Aug 2007 18:32:42 -0300 Subject: [PATCH 0645/2804] V4L/DVB (6088): cx2341x: some controls can't be changed while the device is busy The driver should now pass the 'busy' state of the device to the cx2341x module whenever controls are set or tried. -EBUSY will be returned if the device is busy and the user attempts to modify certain 'dangerous' controls. It concerns controls that change the audio or video compression mode and bitrates. The cx88-blackbird and pvrusb2 drivers currently always pass '0' (not busy) to the cx2341x, effectively keeping the old behavior for now. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx2341x.c | 18 +++++++++++++++--- drivers/media/video/cx88/cx88-blackbird.c | 6 +++--- drivers/media/video/ivtv/ivtv-controls.c | 6 +++--- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 6 +++--- drivers/media/video/v4l2-common.c | 1 + include/media/cx2341x.h | 2 +- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 904bba0dbc4d..62304255dcae 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -190,17 +190,21 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, /* Map the control ID to the correct field in the cx2341x_mpeg_params struct. Return -EINVAL if the ID is unknown, else return 0. */ -static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, +static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_control *ctrl) { switch (ctrl->id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + if (busy) + return -EBUSY; params->audio_sampling_freq = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_ENCODING: params->audio_encoding = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + if (busy) + return -EBUSY; params->audio_l2_bitrate = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_MODE: @@ -245,6 +249,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_gop_closure = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (busy) + return -EBUSY; /* MPEG-1 only allows CBR */ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 && ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) @@ -252,9 +258,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_bitrate_mode = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE: + if (busy) + return -EBUSY; params->video_bitrate = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + if (busy) + return -EBUSY; params->video_bitrate_peak = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: @@ -267,6 +277,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_mute_yuv = ctrl->value; break; case V4L2_CID_MPEG_STREAM_TYPE: + if (busy) + return -EBUSY; params->stream_type = ctrl->value; params->video_encoding = (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || @@ -631,7 +643,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) (params->audio_crc << 14); } -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd) { int err = 0; @@ -663,7 +675,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); if (err) break; - err = cx2341x_set_ctrl(params, ctrl); + err = cx2341x_set_ctrl(params, busy, ctrl); if (err) break; } diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 206af419aea7..47007380a98a 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -876,7 +876,7 @@ static int vidioc_g_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS); + return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS); } static int vidioc_s_ext_ctrls (struct file *file, void *priv, @@ -889,7 +889,7 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; p = dev->params; - err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS); + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); if (!err) { err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); dev->params = p; @@ -907,7 +907,7 @@ static int vidioc_try_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; p = dev->params; - err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS); + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); return err; } diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 7a876c3e5b19..0005ea46f208 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -232,7 +232,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { struct cx2341x_mpeg_params p = itv->params; - int err = cx2341x_ext_ctrls(&p, arg, cmd); + int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); if (err) return err; @@ -282,7 +282,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); + return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd); return -EINVAL; } @@ -292,7 +292,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); + return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd); return -EINVAL; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 1311891e7ee3..2d5be5cfbccf 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -492,7 +492,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) cs.controls = &c1; cs.count = 1; c1.id = cptr->info->v4l_id; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_G_EXT_CTRLS); if (ret) return ret; *vp = c1.value; @@ -510,7 +510,7 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) cs.count = 1; c1.id = cptr->info->v4l_id; c1.value = v; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_S_EXT_CTRLS); if (ret) return ret; cptr->hdw->enc_stale = !0; @@ -2478,7 +2478,7 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) cs.count = 1; c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; c1.value = hdw->srate_val; - cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS); + cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS); } /* Scan i2c core at this point - before we clear all the dirty diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index d2915d3530ea..0689a041d777 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -716,6 +716,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_LOUDNESS: case V4L2_CID_MPEG_AUDIO_MUTE: + case V4L2_CID_MPEG_VIDEO_MUTE: case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: case V4L2_CID_MPEG_VIDEO_PULLDOWN: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h index 38c12fed7535..af8071d7620d 100644 --- a/include/media/cx2341x.h +++ b/include/media/cx2341x.h @@ -91,7 +91,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl); const char **cx2341x_ctrl_get_menu(u32 id); -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p); void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix); From d2a35fb172845fe75c40a3ee9c95656c7c115e48 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 22 Aug 2007 08:43:34 -0300 Subject: [PATCH 0646/2804] V4L/DVB (6089): ivtv: log in status if framebuffer uses YUV instead of RGB Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 0dde82f67e26..bb59634419cc 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1270,7 +1270,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "Global and Local" }; static const char * const pixel_format[] = { - "Indexed", + "RGB Indexed", "RGB 5:6:5", "ARGB 1:5:5:5", "ARGB 1:4:4:4", @@ -1278,6 +1278,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "5", "6", "7", + "YUV Indexed", + "YUV 5:6:5", + "AYUV 1:5:5:5", + "AYUV 1:4:4:4", + "AYUV 8:8:8:8", + "13", + "14", + "15", }; ivtv_get_output(itv, itv->active_output, &vidout); @@ -1290,10 +1298,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void mode = OUT_NONE; IVTV_INFO("Output Mode: %s\n", output_modes[mode]); ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", data[0] & 1 ? "On" : "Off", alpha_mode[(data[0] >> 1) & 0x3], - pixel_format[(data[0] >> 3) & 0x7]); + pixel_format[(data[0] >> 3) & 0xf]); } IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); From 459a52fab2c42cd5fadfd51fdcfc6dea8107fabf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 22 Aug 2007 08:58:47 -0300 Subject: [PATCH 0647/2804] V4L/DVB (6090): ivtv-fb: correct transparency bit reporting Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 008076543aca..7618cd47a35d 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -608,9 +608,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 8; } else if (var->bits_per_pixel == 16) { - var->transp.offset = 0; - var->transp.length = 0; - /* To find out the true mode, check green length */ switch (var->green.length) { case 4: @@ -620,6 +617,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 4; var->blue.offset = 0; var->blue.length = 4; + var->transp.offset = 12; + var->transp.length = 1; break; case 5: var->red.offset = 10; @@ -628,6 +627,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; break; default: var->red.offset = 11; @@ -636,6 +637,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; break; } } From 612570f2c4794bbf4e5bfa8648b61fbfc9cd8501 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 05:42:59 -0300 Subject: [PATCH 0648/2804] V4L/DVB (6091): ivtv: header cleanup - add guards - remove unused header includes - move card-specific stuff from ivtv-driver.h to ivtv-cards.h - move YUV-specific stuff from ivtv-driver.h to ivtv-yuv.h Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-audio.c | 3 - drivers/media/video/ivtv/ivtv-audio.h | 5 ++ drivers/media/video/ivtv/ivtv-cards.h | 64 ++++++++++++++++++++ drivers/media/video/ivtv/ivtv-controls.h | 5 ++ drivers/media/video/ivtv/ivtv-driver.c | 7 --- drivers/media/video/ivtv/ivtv-driver.h | 74 +----------------------- drivers/media/video/ivtv/ivtv-fileops.c | 1 - drivers/media/video/ivtv/ivtv-fileops.h | 5 ++ drivers/media/video/ivtv/ivtv-firmware.h | 5 ++ drivers/media/video/ivtv/ivtv-gpio.h | 5 ++ drivers/media/video/ivtv/ivtv-i2c.h | 5 ++ drivers/media/video/ivtv/ivtv-ioctl.h | 5 ++ drivers/media/video/ivtv/ivtv-irq.c | 3 - drivers/media/video/ivtv/ivtv-irq.h | 5 ++ drivers/media/video/ivtv/ivtv-mailbox.h | 5 ++ drivers/media/video/ivtv/ivtv-queue.c | 2 - drivers/media/video/ivtv/ivtv-queue.h | 5 ++ drivers/media/video/ivtv/ivtv-streams.c | 8 +-- drivers/media/video/ivtv/ivtv-streams.h | 5 ++ drivers/media/video/ivtv/ivtv-udma.c | 1 - drivers/media/video/ivtv/ivtv-udma.h | 5 ++ drivers/media/video/ivtv/ivtv-vbi.h | 5 ++ drivers/media/video/ivtv/ivtv-version.h | 5 ++ drivers/media/video/ivtv/ivtv-video.h | 5 ++ drivers/media/video/ivtv/ivtv-yuv.c | 9 ++- drivers/media/video/ivtv/ivtv-yuv.h | 18 ++++++ 26 files changed, 167 insertions(+), 98 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c index d702b8b539a1..6cb65d69c986 100644 --- a/drivers/media/video/ivtv/ivtv-audio.c +++ b/drivers/media/video/ivtv/ivtv-audio.c @@ -19,13 +19,10 @@ */ #include "ivtv-driver.h" -#include "ivtv-mailbox.h" #include "ivtv-i2c.h" -#include "ivtv-gpio.h" #include "ivtv-cards.h" #include "ivtv-audio.h" #include -#include /* Selects the audio input and output according to the current settings. */ diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-audio.h index 9c42846d8124..ebb90cc8f861 100644 --- a/drivers/media/video/ivtv/ivtv-audio.h +++ b/drivers/media/video/ivtv/ivtv-audio.h @@ -18,6 +18,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_AUDIO_H +#define IVTV_AUDIO_H + int ivtv_audio_set_io(struct ivtv *itv); void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 3191920f4c6b..ff46e5ae8653 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -18,6 +18,68 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_CARDS_H +#define IVTV_CARDS_H + +/* Supported cards */ +#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ +#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ +#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two + PVR150s on one PCI board) */ +#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ +#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ +#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 + cx23415 based, but does not have tv-out */ +#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ +#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ +#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ +#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ +#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ +#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ +#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ +#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ +#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ +#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ +#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ +#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ +#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ +#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ +#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ +#define IVTV_CARD_LAST 20 + +/* Variants of existing cards but with the same PCI IDs. The driver + detects these based on other device information. + These cards must always come last. + New cards must be inserted above, and the indices of the cards below + must be adjusted accordingly. */ + +/* PVR-350 V1 (uses saa7114) */ +#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) +/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ +#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) +#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) + +/* system vendor and device IDs */ +#define PCI_VENDOR_ID_ICOMP 0x4444 +#define PCI_DEVICE_ID_IVTV15 0x0803 +#define PCI_DEVICE_ID_IVTV16 0x0016 + +/* subsystem vendor ID */ +#define IVTV_PCI_ID_HAUPPAUGE 0x0070 +#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 +#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 +#define IVTV_PCI_ID_ADAPTEC 0x9005 +#define IVTV_PCI_ID_AVERMEDIA 0x1461 +#define IVTV_PCI_ID_YUAN1 0x12ab +#define IVTV_PCI_ID_YUAN2 0xff01 +#define IVTV_PCI_ID_YUAN3 0xffab +#define IVTV_PCI_ID_YUAN4 0xfbab +#define IVTV_PCI_ID_DIAMONDMM 0xff92 +#define IVTV_PCI_ID_IODATA 0x10fc +#define IVTV_PCI_ID_MELCO 0x1154 +#define IVTV_PCI_ID_GOTVIEW1 0xffac +#define IVTV_PCI_ID_GOTVIEW2 0xffad + /* hardware flags */ #define IVTV_HW_CX25840 (1 << 0) #define IVTV_HW_SAA7115 (1 << 1) @@ -206,3 +268,5 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output); int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input); int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output); const struct ivtv_card *ivtv_get_card(u16 index); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h index 5a11149725ad..bb8a6a5ed2bc 100644 --- a/drivers/media/video/ivtv/ivtv-controls.h +++ b/drivers/media/video/ivtv/ivtv-controls.h @@ -18,4 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_CONTROLS_H +#define IVTV_CONTROLS_H + int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 93ddea49f0ed..2ed9894672f4 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -87,13 +87,6 @@ static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); -const u32 yuv_offset[4] = { - IVTV_YUV_BUFFER_OFFSET, - IVTV_YUV_BUFFER_OFFSET_1, - IVTV_YUV_BUFFER_OFFSET_2, - IVTV_YUV_BUFFER_OFFSET_3 -}; - /* Parameter declarations */ static int cardtype[IVTV_MAX_CARDS]; static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 3ed4703956d3..f7849f852e9d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -74,61 +74,10 @@ #define IVTV_REG_OFFSET 0x02000000 #define IVTV_REG_SIZE 0x00010000 -/* Buffers on hardware offsets */ -#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ -#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ - -/* Offset to filter table in firmware */ -#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 -#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 - -extern const u32 yuv_offset[4]; - /* Maximum ivtv driver instances. Some people have a huge number of capture cards, so set this to a high value. */ #define IVTV_MAX_CARDS 32 -/* Supported cards */ -#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ -#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ -#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two - PVR150s on one PCI board) */ -#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ -#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ -#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 - cx23415 based, but does not have tv-out */ -#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ -#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ -#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ -#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ -#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ -#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ -#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ -#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ -#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ -#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ -#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ -#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ -#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ -#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ -#define IVTV_CARD_LAST 20 - -/* Variants of existing cards but with the same PCI IDs. The driver - detects these based on other device information. - These cards must always come last. - New cards must be inserted above, and the indices of the cards below - must be adjusted accordingly. */ - -/* PVR-350 V1 (uses saa7114) */ -#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) -/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) -#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) - #define IVTV_ENC_STREAM_TYPE_MPG 0 #define IVTV_ENC_STREAM_TYPE_YUV 1 #define IVTV_ENC_STREAM_TYPE_VBI 2 @@ -150,27 +99,6 @@ extern const u32 yuv_offset[4]; #define IVTV_ENC_MEM_START 0x00000000 #define IVTV_DEC_MEM_START 0x01000000 -/* system vendor and device IDs */ -#define PCI_VENDOR_ID_ICOMP 0x4444 -#define PCI_DEVICE_ID_IVTV15 0x0803 -#define PCI_DEVICE_ID_IVTV16 0x0016 - -/* subsystem vendor ID */ -#define IVTV_PCI_ID_HAUPPAUGE 0x0070 -#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 -#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 -#define IVTV_PCI_ID_ADAPTEC 0x9005 -#define IVTV_PCI_ID_AVERMEDIA 0x1461 -#define IVTV_PCI_ID_YUAN1 0x12ab -#define IVTV_PCI_ID_YUAN2 0xff01 -#define IVTV_PCI_ID_YUAN3 0xffab -#define IVTV_PCI_ID_YUAN4 0xfbab -#define IVTV_PCI_ID_DIAMONDMM 0xff92 -#define IVTV_PCI_ID_IODATA 0x10fc -#define IVTV_PCI_ID_MELCO 0x1154 -#define IVTV_PCI_ID_GOTVIEW1 0xffac -#define IVTV_PCI_ID_GOTVIEW2 0xffad - /* Decoder Buffer hardware size on Chip */ #define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ #define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ @@ -890,4 +818,4 @@ int ivtv_init_on_first_open(struct ivtv *itv); #define write_dec_sync(val, addr) \ do { write_dec(val, addr); read_dec(addr); } while (0) -#endif /* IVTV_DRIVER_H */ +#endif diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 62ee41c5220b..6449f5831e66 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -30,7 +30,6 @@ #include "ivtv-audio.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" -#include "ivtv-controls.h" #include "ivtv-ioctl.h" #include "ivtv-cards.h" #include diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h index 74a1745fabbc..2c8d5186c9c3 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.h +++ b/drivers/media/video/ivtv/ivtv-fileops.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_FILEOPS_H +#define IVTV_FILEOPS_H + /* Testing/Debugging */ int ivtv_v4l2_open(struct inode *inode, struct file *filp); ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count, @@ -42,3 +45,5 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type); /* Release a previously claimed stream. */ void ivtv_release_stream(struct ivtv_stream *s); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h index 8b2ffe658905..041ba94e65bc 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.h +++ b/drivers/media/video/ivtv/ivtv-firmware.h @@ -19,7 +19,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_FIRMWARE_H +#define IVTV_FIRMWARE_H + int ivtv_firmware_init(struct ivtv *itv); void ivtv_firmware_versions(struct ivtv *itv); void ivtv_halt_firmware(struct ivtv *itv); void ivtv_init_mpeg_decoder(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h index b31c679bbd8e..964a265d91a9 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.h +++ b/drivers/media/video/ivtv/ivtv-gpio.h @@ -18,8 +18,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_GPIO_H +#define IVTV_GPIO_H + /* GPIO stuff */ void ivtv_gpio_init(struct ivtv *itv); void ivtv_reset_ir_gpio(struct ivtv *itv); int ivtv_reset_tuner_gpio(void *dev, int cmd, int value); int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h index 5d210adb5c52..677c3292855e 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.h +++ b/drivers/media/video/ivtv/ivtv-i2c.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_I2C_H +#define IVTV_I2C_H + int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg); int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg); int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg); @@ -34,3 +37,5 @@ void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); /* init + register i2c algo-bit adapter */ int __devinit init_ivtv_i2c(struct ivtv *itv); void __devexit exit_ivtv_i2c(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h index cbccf7a9f65c..a03351b6853d 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.h +++ b/drivers/media/video/ivtv/ivtv-ioctl.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_IOCTL_H +#define IVTV_IOCTL_H + u16 service2vbi(int type); void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 get_service_set(struct v4l2_sliced_vbi_format *fmt); @@ -26,3 +29,5 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); void ivtv_set_osd_alpha(struct ivtv *itv); int ivtv_set_speed(struct ivtv *itv, int speed); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index d68853fd60a3..b6a94a1ad19b 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -19,12 +19,9 @@ */ #include "ivtv-driver.h" -#include "ivtv-firmware.h" -#include "ivtv-fileops.h" #include "ivtv-queue.h" #include "ivtv-udma.h" #include "ivtv-irq.h" -#include "ivtv-ioctl.h" #include "ivtv-mailbox.h" #include "ivtv-vbi.h" #include "ivtv-yuv.h" diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h index a43348a30309..e180bd348989 100644 --- a/drivers/media/video/ivtv/ivtv-irq.h +++ b/drivers/media/video/ivtv/ivtv-irq.h @@ -19,8 +19,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_IRQ_H +#define IVTV_IRQ_H + irqreturn_t ivtv_irq_handler(int irq, void *dev_id); void ivtv_irq_work_handler(struct work_struct *work); void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); void ivtv_unfinished_dma(unsigned long arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h index 79b8aec14370..90c871b8e23b 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/drivers/media/video/ivtv/ivtv-mailbox.h @@ -18,8 +18,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_MAILBOX_H +#define IVTV_MAILBOX_H + void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index d9a1478ca1f7..437f134796e3 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -20,9 +20,7 @@ */ #include "ivtv-driver.h" -#include "ivtv-streams.h" #include "ivtv-queue.h" -#include "ivtv-mailbox.h" int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) { diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h index 14a9f7fe50aa..7cfc0c9ab050 100644 --- a/drivers/media/video/ivtv/ivtv-queue.h +++ b/drivers/media/video/ivtv/ivtv-queue.h @@ -19,6 +19,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_QUEUE_H +#define IVTV_QUEUE_H + #define IVTV_DMA_UNMAPPED ((u32) -1) #define SLICED_VBI_PIO 1 @@ -89,3 +92,5 @@ static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle, sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } + +#endif diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index ebf925c549fd..fae151a31e85 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -35,16 +35,12 @@ #include "ivtv-driver.h" #include "ivtv-fileops.h" -#include "ivtv-i2c.h" #include "ivtv-queue.h" #include "ivtv-mailbox.h" -#include "ivtv-audio.h" -#include "ivtv-video.h" -#include "ivtv-vbi.h" #include "ivtv-ioctl.h" -#include "ivtv-irq.h" -#include "ivtv-streams.h" +#include "ivtv-yuv.h" #include "ivtv-cards.h" +#include "ivtv-streams.h" static struct file_operations ivtv_v4l2_enc_fops = { .owner = THIS_MODULE, diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h index 8597b75384a7..8f5f5b1c7c89 100644 --- a/drivers/media/video/ivtv/ivtv-streams.h +++ b/drivers/media/video/ivtv/ivtv-streams.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_STREAMS_H +#define IVTV_STREAMS_H + int ivtv_streams_setup(struct ivtv *itv); void ivtv_streams_cleanup(struct ivtv *itv); @@ -29,3 +32,5 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts); void ivtv_stop_all_captures(struct ivtv *itv); int ivtv_passthrough_mode(struct ivtv *itv, int enable); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index 7e503adacea0..c4626d1cdf41 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -21,7 +21,6 @@ */ #include "ivtv-driver.h" -#include "ivtv-streams.h" #include "ivtv-udma.h" void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size) diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h index e131bccedec0..df727e23be0a 100644 --- a/drivers/media/video/ivtv/ivtv-udma.h +++ b/drivers/media/video/ivtv/ivtv-udma.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_UDMA_H +#define IVTV_UDMA_H + /* User DMA functions */ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size); int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset); @@ -41,3 +44,5 @@ static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv) pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle, sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); } + +#endif diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h index ec211b49702c..d5740493a690 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.h +++ b/drivers/media/video/ivtv/ivtv-vbi.h @@ -17,6 +17,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VBI_H +#define IVTV_VBI_H + ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, u64 pts_stamp, int streamtype); @@ -24,3 +27,5 @@ int ivtv_used_line(struct ivtv *itv, int line, int field); void ivtv_disable_vbi(struct ivtv *itv); void ivtv_set_vbi(unsigned long arg); void ivtv_vbi_work_handler(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 122d56105969..d050de2a7229 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -17,6 +17,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VERSION_H +#define IVTV_VERSION_H + #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 #define IVTV_DRIVER_VERSION_MINOR 1 @@ -24,3 +27,5 @@ #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) + +#endif diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h index c8ade5d3c413..498e9b61c227 100644 --- a/drivers/media/video/ivtv/ivtv-video.h +++ b/drivers/media/video/ivtv/ivtv-video.h @@ -17,8 +17,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VIDEO_H +#define IVTV_VIDEO_H + void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, u8 vps4, u8 vps5); void ivtv_video_set_io(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 1922c1da20d3..bb2cbb206c14 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -19,11 +19,16 @@ */ #include "ivtv-driver.h" -#include "ivtv-queue.h" #include "ivtv-udma.h" -#include "ivtv-irq.h" #include "ivtv-yuv.h" +const u32 yuv_offset[4] = { + IVTV_YUV_BUFFER_OFFSET, + IVTV_YUV_BUFFER_OFFSET_1, + IVTV_YUV_BUFFER_OFFSET_2, + IVTV_YUV_BUFFER_OFFSET_3 +}; + static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, struct ivtv_dma_frame *args) { diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 88972d3f77c4..0824048ce3a2 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -18,7 +18,25 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_YUV_H +#define IVTV_YUV_H + +/* Buffers on hardware offsets */ +#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ +#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ + +/* Offset to filter table in firmware */ +#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 +#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 + +extern const u32 yuv_offset[4]; + int ivtv_yuv_filter_check(struct ivtv *itv); int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); void ivtv_yuv_close(struct ivtv *itv); void ivtv_yuv_work_handler (struct ivtv *itv); + +#endif From 33c0fcad2160bc211272295e862c6f708118d006 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 06:32:46 -0300 Subject: [PATCH 0649/2804] V4L/DVB (6092): ivtv: more cleanups, merged ivtv-audio.c and ivtv-video.c into ivtv-routing.c Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Makefile | 4 +- drivers/media/video/ivtv/ivtv-audio.c | 71 ----------- drivers/media/video/ivtv/ivtv-controls.c | 10 +- drivers/media/video/ivtv/ivtv-driver.c | 14 ++- drivers/media/video/ivtv/ivtv-driver.h | 113 +++--------------- drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-fileops.c | 2 +- drivers/media/video/ivtv/ivtv-ioctl.c | 5 +- drivers/media/video/ivtv/ivtv-irq.h | 22 ++++ drivers/media/video/ivtv/ivtv-mailbox.h | 3 + .../ivtv/{ivtv-video.c => ivtv-routing.c} | 92 +++++--------- .../ivtv/{ivtv-audio.h => ivtv-routing.h} | 11 +- drivers/media/video/ivtv/ivtv-streams.c | 16 ++- drivers/media/video/ivtv/ivtv-vbi.c | 64 +++++++++- drivers/media/video/ivtv/ivtv-video.h | 29 ----- drivers/media/video/ivtv/ivtv-yuv.c | 4 +- drivers/media/video/ivtv/ivtv-yuv.h | 3 + 17 files changed, 185 insertions(+), 280 deletions(-) delete mode 100644 drivers/media/video/ivtv/ivtv-audio.c rename drivers/media/video/ivtv/{ivtv-video.c => ivtv-routing.c} (59%) rename drivers/media/video/ivtv/{ivtv-audio.h => ivtv-routing.h} (77%) delete mode 100644 drivers/media/video/ivtv/ivtv-video.h diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 90e2d1270561..6998781e2b11 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -1,8 +1,8 @@ -ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ +ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \ ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \ ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \ - ivtv-vbi.o ivtv-video.o ivtv-yuv.o + ivtv-vbi.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c deleted file mode 100644 index 6cb65d69c986..000000000000 --- a/drivers/media/video/ivtv/ivtv-audio.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - Audio-related ivtv functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -#include "ivtv-driver.h" -#include "ivtv-i2c.h" -#include "ivtv-cards.h" -#include "ivtv-audio.h" -#include - -/* Selects the audio input and output according to the current - settings. */ -int ivtv_audio_set_io(struct ivtv *itv) -{ - struct v4l2_routing route; - u32 audio_input; - int mux_input; - - /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - audio_input = itv->card->radio_input.audio_input; - mux_input = itv->card->radio_input.muxer_input; - } else { - audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; - mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; - } - - /* handle muxer chips */ - route.input = mux_input; - route.output = 0; - ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); - - route.input = audio_input; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) { - route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - } - return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); -} - -void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route) -{ - ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); -} - -void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq) -{ - static u32 freqs[3] = { 44100, 48000, 32000 }; - - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (freq > 2) - return; - ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); -} - diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 0005ea46f208..8c02fa661591 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -21,7 +21,7 @@ #include "ivtv-driver.h" #include "ivtv-cards.h" #include "ivtv-ioctl.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-i2c.h" #include "ivtv-mailbox.h" #include "ivtv-controls.h" @@ -231,8 +231,10 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + static u32 freqs[3] = { 44100, 48000, 32000 }; struct cx2341x_mpeg_params p = itv->params; int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); + unsigned idx; if (err) return err; @@ -254,7 +256,11 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } itv->params = p; itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; - ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03); + idx = p.audio_properties & 0x03; + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < sizeof(freqs)) + ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]); return err; } return -EINVAL; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 2ed9894672f4..6a74e509c87d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -52,7 +52,7 @@ #include "ivtv-ioctl.h" #include "ivtv-cards.h" #include "ivtv-vbi.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-gpio.h" #include "ivtv-yuv.h" @@ -106,6 +106,18 @@ static char secam[] = "--"; static char ntsc[] = "-"; /* Buffers */ + +/* DMA Buffers, Default size in MB allocated */ +#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 +#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 +#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 +/* Exception: size in kB for this stream (MB is overkill) */ +#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 +#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 +#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 +/* Exception: size in kB for this stream (MB is way overkill) */ +#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 + static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS; static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS; static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index f7849f852e9d..b9dfdab66362 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -65,12 +65,11 @@ #include +/* Memory layout */ #define IVTV_ENCODER_OFFSET 0x00000000 -#define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ - +#define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ #define IVTV_DECODER_OFFSET 0x01000000 -#define IVTV_DECODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ - +#define IVTV_DECODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ #define IVTV_REG_OFFSET 0x02000000 #define IVTV_REG_SIZE 0x00010000 @@ -89,51 +88,8 @@ #define IVTV_DEC_STREAM_TYPE_YUV 8 #define IVTV_MAX_STREAMS 9 -#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ -#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ -#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ -#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ - -#define IVTV_ENC_MEM_START 0x00000000 -#define IVTV_DEC_MEM_START 0x01000000 - -/* Decoder Buffer hardware size on Chip */ -#define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ -#define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ - -/* ======================================================================== */ -/* ========================== START USER SETTABLE DMA VARIABLES =========== */ -/* ======================================================================== */ - #define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */ -/* DMA Buffers, Default size in MB allocated */ -#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 -#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 -#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -/* Exception: size in kB for this stream (MB is overkill) */ -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 -#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 -#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -/* Exception: size in kB for this stream (MB is way overkill) */ -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 - -/* ======================================================================== */ -/* ========================== END USER SETTABLE DMA VARIABLES ============= */ -/* ======================================================================== */ - -/* Decoder Status Register */ -#define IVTV_DMA_ERR_LIST 0x00000010 -#define IVTV_DMA_ERR_WRITE 0x00000008 -#define IVTV_DMA_ERR_READ 0x00000004 -#define IVTV_DMA_SUCCESS_WRITE 0x00000002 -#define IVTV_DMA_SUCCESS_READ 0x00000001 -#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ) -#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE) -#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ) - /* DMA Registers */ #define IVTV_REG_DMAXFER (0x0000) #define IVTV_REG_DMASTATUS (0x0004) @@ -156,32 +112,11 @@ #define IVTV_REG_VPU (0x9058) #define IVTV_REG_APU (0xA064) -#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) -#define IVTV_IRQ_ENC_EOS (0x1 << 30) -#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) -#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) -#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) -#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) -#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) -#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) -#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) -#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) -#define IVTV_IRQ_DMA_ERR (0x1 << 18) -#define IVTV_IRQ_DMA_WRITE (0x1 << 17) -#define IVTV_IRQ_DMA_READ (0x1 << 16) -#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) - -/* IRQ Masks */ -#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ - IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE) - -#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) -#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) - /* i2c stuff */ #define I2C_CLIENTS_MAX 16 /* debugging */ +extern int ivtv_debug; #define IVTV_DBGFLG_WARN (1 << 0) #define IVTV_DBGFLG_INFO (1 << 1) @@ -235,11 +170,6 @@ #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) -/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ -#define MPEG_FRAME_TYPE_IFRAME 1 -#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 -#define MPEG_FRAME_TYPE_ALL 7 - /* output modes (cx23415 only) */ #define OUT_NONE 0 #define OUT_MPG 1 @@ -249,9 +179,6 @@ #define IVTV_MAX_PGM_INDEX (400) -extern int ivtv_debug; - - struct ivtv_options { int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ int cardtype; /* force card type on load */ @@ -260,11 +187,6 @@ struct ivtv_options { int newi2c; /* New I2C algorithm */ }; -#define IVTV_MBOX_DMA_START 6 -#define IVTV_MBOX_DMA_END 8 -#define IVTV_MBOX_DMA 9 -#define IVTV_MBOX_FIELD_DISPLAYED 8 - /* ivtv-specific mailbox template */ struct ivtv_mailbox { u32 flags; @@ -450,31 +372,28 @@ struct ivtv_open_id { struct ivtv *itv; }; -#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 -#define IVTV_YUV_UPDATE_VERTICAL 0x02 - struct yuv_frame_info { u32 update; - int src_x; - int src_y; - unsigned int src_w; - unsigned int src_h; - int dst_x; - int dst_y; - unsigned int dst_w; - unsigned int dst_h; - int pan_x; - int pan_y; + s32 src_x; + s32 src_y; + u32 src_w; + u32 src_h; + s32 dst_x; + s32 dst_y; + u32 dst_w; + u32 dst_h; + s32 pan_x; + s32 pan_y; u32 vis_w; u32 vis_h; u32 interlaced_y; u32 interlaced_uv; - int tru_x; + s32 tru_x; u32 tru_w; u32 tru_h; u32 offset_y; - int lace_mode; + s32 lace_mode; }; #define IVTV_YUV_MODE_INTERLACED 0x00 diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 7618cd47a35d..2c521d1bb057 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -382,7 +382,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* OSD Address to send DMA to */ - dest_offset += IVTV_DEC_MEM_START + oi->video_rbase; + dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; /* Fill Buffers */ return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 6449f5831e66..170bef61aa62 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -27,7 +27,7 @@ #include "ivtv-irq.h" #include "ivtv-vbi.h" #include "ivtv-mailbox.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" #include "ivtv-ioctl.h" diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index bb59634419cc..f4f56a6e1f81 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -25,8 +25,7 @@ #include "ivtv-queue.h" #include "ivtv-fileops.h" #include "ivtv-vbi.h" -#include "ivtv-audio.h" -#include "ivtv-video.h" +#include "ivtv-routing.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" #include "ivtv-ioctl.h" @@ -675,7 +674,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) case VIDIOC_INT_S_AUDIO_ROUTING: { struct v4l2_routing *route = arg; - ivtv_audio_set_route(itv, route); + ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h index e180bd348989..f879a5822e71 100644 --- a/drivers/media/video/ivtv/ivtv-irq.h +++ b/drivers/media/video/ivtv/ivtv-irq.h @@ -22,6 +22,28 @@ #ifndef IVTV_IRQ_H #define IVTV_IRQ_H +#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) +#define IVTV_IRQ_ENC_EOS (0x1 << 30) +#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) +#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) +#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) +#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) +#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) +#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) +#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) +#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) +#define IVTV_IRQ_DMA_ERR (0x1 << 18) +#define IVTV_IRQ_DMA_WRITE (0x1 << 17) +#define IVTV_IRQ_DMA_READ (0x1 << 16) +#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) + +/* IRQ Masks */ +#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ + IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE) + +#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) +#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) + irqreturn_t ivtv_irq_handler(int irq, void *dev_id); void ivtv_irq_work_handler(struct work_struct *work); diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h index 90c871b8e23b..71a54eef8fc7 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/drivers/media/video/ivtv/ivtv-mailbox.h @@ -21,6 +21,9 @@ #ifndef IVTV_MAILBOX_H #define IVTV_MAILBOX_H +#define IVTV_MBOX_DMA_END 8 +#define IVTV_MBOX_DMA 9 + void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-routing.c similarity index 59% rename from drivers/media/video/ivtv/ivtv-video.c rename to drivers/media/video/ivtv/ivtv-routing.c index 5858b197d510..398bd33033ed 100644 --- a/drivers/media/video/ivtv/ivtv-video.c +++ b/drivers/media/video/ivtv/ivtv-routing.c @@ -1,6 +1,7 @@ /* - saa7127 interface functions - Copyright (C) 2004-2007 Hans Verkuil + Audio/video-routing-related ivtv functions. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil 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 @@ -18,73 +19,46 @@ */ #include "ivtv-driver.h" -#include "ivtv-video.h" #include "ivtv-i2c.h" -#include "ivtv-gpio.h" #include "ivtv-cards.h" +#include "ivtv-gpio.h" +#include "ivtv-routing.h" + +#include #include #include -void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5) +/* Selects the audio input and output according to the current + settings. */ +void ivtv_audio_set_io(struct ivtv *itv) { - struct v4l2_sliced_vbi_data data; + struct v4l2_routing route; + u32 audio_input; + int mux_input; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_VPS; - data.field = 0; - data.line = enabled ? 16 : 0; - data.data[4] = vps1; - data.data[10] = vps2; - data.data[11] = vps3; - data.data[12] = vps4; - data.data[13] = vps5; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_CAPTION_525; - data.field = 0; - data.line = (mode & 1) ? 21 : 0; - data.data[0] = cc1; - data.data[1] = cc2; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); - data.field = 1; - data.line = (mode & 2) ? 21 : 0; - data.data[0] = cc3; - data.data[1] = cc4; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - /* When using a 50 Hz system, always turn on the - wide screen signal with 4x3 ratio as the default. - Turning this signal on and off can confuse certain - TVs. As far as I can tell there is no reason not to - transmit this signal. */ - if ((itv->std & V4L2_STD_625_50) && !enabled) { - enabled = 1; - mode = 0x08; /* 4x3 full format */ + /* Determine which input to use */ + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + audio_input = itv->card->radio_input.audio_input; + mux_input = itv->card->radio_input.muxer_input; + } else { + audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; + mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; } - data.id = V4L2_SLICED_WSS_625; - data.field = 0; - data.line = enabled ? 23 : 0; - data.data[0] = mode & 0xff; - data.data[1] = (mode >> 8) & 0xff; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); + + /* handle muxer chips */ + route.input = mux_input; + route.output = 0; + ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); + + route.input = audio_input; + if (itv->card->hw_audio & IVTV_HW_MSP34XX) { + route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); + } + ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); } +/* Selects the video input and output according to the current + settings. */ void ivtv_video_set_io(struct ivtv *itv) { struct v4l2_routing route; diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-routing.h similarity index 77% rename from drivers/media/video/ivtv/ivtv-audio.h rename to drivers/media/video/ivtv/ivtv-routing.h index ebb90cc8f861..c72a9731ca01 100644 --- a/drivers/media/video/ivtv/ivtv-audio.h +++ b/drivers/media/video/ivtv/ivtv-routing.h @@ -1,5 +1,5 @@ /* - Audio-related ivtv functions. + Audio/video-routing-related ivtv functions. Copyright (C) 2003-2004 Kevin Thayer Copyright (C) 2005-2007 Hans Verkuil @@ -18,11 +18,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef IVTV_AUDIO_H -#define IVTV_AUDIO_H +#ifndef IVTV_ROUTING_H +#define IVTV_ROUTING_H -int ivtv_audio_set_io(struct ivtv *itv); -void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); -void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); +void ivtv_audio_set_io(struct ivtv *itv); +void ivtv_video_set_io(struct ivtv *itv); #endif diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index fae151a31e85..3939a804f043 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -38,6 +38,7 @@ #include "ivtv-queue.h" #include "ivtv-mailbox.h" #include "ivtv-ioctl.h" +#include "ivtv-irq.h" #include "ivtv-yuv.h" #include "ivtv-cards.h" #include "ivtv-streams.h" @@ -62,6 +63,13 @@ static struct file_operations ivtv_v4l2_dec_fops = { .poll = ivtv_v4l2_dec_poll, }; +#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ +#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ +#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ +#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ +#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ +#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ + static struct { const char *name; int vfl_type; @@ -658,10 +666,10 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); /* Zero out decoder counters */ - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index a58c833c2b04..5d8a40f3d2b6 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -18,10 +18,70 @@ */ #include "ivtv-driver.h" -#include "ivtv-video.h" -#include "ivtv-vbi.h" +#include "ivtv-i2c.h" #include "ivtv-ioctl.h" #include "ivtv-queue.h" +#include "ivtv-vbi.h" + +static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, + u8 vps4, u8 vps5) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + data.id = V4L2_SLICED_VPS; + data.field = 0; + data.line = enabled ? 16 : 0; + data.data[4] = vps1; + data.data[10] = vps2; + data.data[11] = vps3; + data.data[12] = vps4; + data.data[13] = vps5; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} + +static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + data.id = V4L2_SLICED_CAPTION_525; + data.field = 0; + data.line = (mode & 1) ? 21 : 0; + data.data[0] = cc1; + data.data[1] = cc2; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); + data.field = 1; + data.line = (mode & 2) ? 21 : 0; + data.data[0] = cc3; + data.data[1] = cc4; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} + +static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + /* When using a 50 Hz system, always turn on the + wide screen signal with 4x3 ratio as the default. + Turning this signal on and off can confuse certain + TVs. As far as I can tell there is no reason not to + transmit this signal. */ + if ((itv->std & V4L2_STD_625_50) && !enabled) { + enabled = 1; + mode = 0x08; /* 4x3 full format */ + } + data.id = V4L2_SLICED_WSS_625; + data.field = 0; + data.line = enabled ? 23 : 0; + data.data[0] = mode & 0xff; + data.data[1] = (mode >> 8) & 0xff; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} static int odd_parity(u8 c) { diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h deleted file mode 100644 index 498e9b61c227..000000000000 --- a/drivers/media/video/ivtv/ivtv-video.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - saa7127 interface functions - Copyright (C) 2004-2007 Hans Verkuil - - 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 - */ - -#ifndef IVTV_VIDEO_H -#define IVTV_VIDEO_H - -void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); -void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); -void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5); -void ivtv_video_set_io(struct ivtv *itv); - -#endif diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index bb2cbb206c14..e2288f224ab6 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -42,7 +42,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, int y_decode_height, uv_decode_height, y_size; int frame = atomic_read(&itv->yuv_info.next_fill_frame); - y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame]; + y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; y_decode_height = uv_decode_height = args->src.height + args->src.top; @@ -106,7 +106,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, if (itv->yuv_info.blanking_dmaptr) { dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); - dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]); + dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); dma->SG_length++; } } diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 0824048ce3a2..f7215eeca018 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -32,6 +32,9 @@ #define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 #define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 +#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 +#define IVTV_YUV_UPDATE_VERTICAL 0x02 + extern const u32 yuv_offset[4]; int ivtv_yuv_filter_check(struct ivtv *itv); From fd8b281a2809d2bd9119df1fbd717ab2371297cd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 10:13:15 -0300 Subject: [PATCH 0650/2804] V4L/DVB (6093): ivtv: reorganized and cleanup ivtv struct Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 15 +- drivers/media/video/ivtv/ivtv-driver.h | 209 ++++++++++++------------ drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-ioctl.c | 10 +- drivers/media/video/ivtv/ivtv-irq.c | 12 +- drivers/media/video/ivtv/ivtv-streams.c | 19 ++- 6 files changed, 135 insertions(+), 132 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 6a74e509c87d..855697c1c968 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -667,7 +667,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) cx2341x_fill_defaults(&itv->params); itv->params.port = CX2341X_PORT_MEMORY; itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; - init_waitqueue_head(&itv->cap_w); + init_waitqueue_head(&itv->eos_waitq); init_waitqueue_head(&itv->event_waitq); init_waitqueue_head(&itv->vsync_waitq); init_waitqueue_head(&itv->dma_waitq); @@ -713,14 +713,6 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv) break; itv->nof_audio_inputs = i; - /* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */ - if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) - itv->digitizer = 0xF1; - else if (itv->card->hw_all & IVTV_HW_SAA7114) - itv->digitizer = 0xEF; - else /* cx25840 */ - itv->digitizer = 0x140; - if (itv->card->hw_all & IVTV_HW_CX25840) { itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */ } else { @@ -749,6 +741,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, const struct pci_device_id *pci_id) { u16 cmd; + u8 card_rev; unsigned char pci_latency; IVTV_DEBUG_INFO("Enabling pci device\n"); @@ -795,7 +788,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, } IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); - pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev); + pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev); pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 64 && ivtv_pci_latency) { @@ -812,7 +805,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " "irq: %d, latency: %d, memory: 0x%lx\n", - itv->dev->device, itv->card_rev, dev->bus->number, + itv->dev->device, card_rev, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), itv->dev->irq, pci_latency, (unsigned long)itv->base_addr); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index b9dfdab66362..2c27515d8731 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -550,133 +550,134 @@ struct ivtv_card; /* Struct to hold info about ivtv cards */ struct ivtv { - int num; /* board number, -1 during init! */ - char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ - struct pci_dev *dev; /* PCI device */ + /* General fixed card data */ + int num; /* board number, -1 during init! */ + char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ + struct pci_dev *dev; /* PCI device */ const struct ivtv_card *card; /* card information */ - const char *card_name; /* full name of the card */ - u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ - u8 is_50hz; - u8 is_60hz; - u8 is_out_50hz; - u8 is_out_60hz; - u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ - u8 nof_inputs; /* number of video inputs */ - u8 nof_audio_inputs; /* number of audio inputs */ - u32 v4l2_cap; /* V4L2 capabilities of card */ - u32 hw_flags; /* Hardware description of the board */ - int tunerid; /* Userspace tuner ID for experimental Xceive tuner support */ - - /* controlling Video decoder function */ + const char *card_name; /* full name of the card */ + u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ + u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ + u8 nof_inputs; /* number of video inputs */ + u8 nof_audio_inputs; /* number of audio inputs */ + u32 v4l2_cap; /* V4L2 capabilities of card */ + u32 hw_flags; /* hardware description of the board */ + int tunerid; /* userspace tuner ID for experimental Xceive tuner support */ + v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ + /* controlling video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); + u32 base_addr; /* PCI resource base address */ + volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */ + volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */ + volatile void __iomem *reg_mem; /* pointer to mapped registers */ + struct ivtv_options options; /* user options */ - struct ivtv_options options; /* User options */ - int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */ - struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* Stream data */ - int speed; - u8 speed_mute_audio; - unsigned long i_flags; /* global ivtv flags */ - atomic_t capturing; /* count number of active capture streams */ - atomic_t decoding; /* count number of active decoding streams */ - u32 irq_rr_idx; /* Round-robin stream index */ - int cur_dma_stream; /* index of stream doing DMA */ - int cur_pio_stream; /* index of stream doing PIO */ - u32 dma_data_req_offset; - u32 dma_data_req_size; - int dma_retries; - int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ - spinlock_t lock; /* lock access to this struct */ - int search_pack_header; - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - struct mutex serialize_lock; /* lock used to serialize starting streams */ + /* High-level state info */ + unsigned long i_flags; /* global ivtv flags */ + u8 is_50hz; /* 1 if the current capture standard is 50 Hz */ + u8 is_60hz /* 1 if the current capture standard is 60 Hz */; + u8 is_out_50hz /* 1 if the current TV output standard is 50 Hz */; + u8 is_out_60hz /* 1 if the current TV output standard is 60 Hz */; + int output_mode; /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */ + u32 audio_input; /* current audio input */ + u32 active_input; /* current video input */ + u32 active_output; /* current video output */ + v4l2_std_id std; /* current capture TV standard */ + v4l2_std_id std_out; /* current TV output standard */ + u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ + u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ + struct cx2341x_mpeg_params params; /* current encoder parameters */ - /* User based DMA for OSD */ - struct ivtv_user_dma udma; - int open_id; /* incremented each time an open occurs, used as unique ID. - starts at 1, so 0 can be used as uninitialized value - in the stream->id. */ + /* Locking */ + spinlock_t lock; /* lock access to this struct */ + /* mutex used to serialize open/close/start/stop/ioctl operations */ + struct mutex serialize_lock; - u32 base_addr; - u32 irqmask; - struct v4l2_prio_state prio; - struct workqueue_struct *irq_work_queues; - struct work_struct irq_work_queue; - struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */ + /* Streams */ + int stream_buf_size[IVTV_MAX_STREAMS]; /* stream buffer size */ + struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* stream data */ + atomic_t capturing; /* count number of active capture streams */ + atomic_t decoding; /* count number of active decoding streams */ - struct vbi_info vbi; - struct ivtv_mailbox_data enc_mbox; - struct ivtv_mailbox_data dec_mbox; - struct ivtv_api_cache api_cache[256]; /* Cached API Commands */ + /* Interrupts & DMA */ + u32 irqmask; /* active interrupts */ + u32 irq_rr_idx; /* round-robin stream index */ + struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */ + struct work_struct irq_work_queue; /* work entry */ + spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */ + int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */ + u32 dma_data_req_offset; /* store offset in decoder memory of current DMA request */ + u32 dma_data_req_size; /* store size of current DMA request */ + int dma_retries; /* current DMA retry attempt */ + struct ivtv_user_dma udma; /* user based DMA for OSD */ + struct timer_list dma_timer; /* timer used to catch unfinished DMAs */ + u32 last_vsync_frame; /* last seen vsync field */ + wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */ + wait_queue_head_t eos_waitq; /* wake up when EOS arrives */ + wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */ + wait_queue_head_t vsync_waitq; /* wake up when the next decoder vsync arrives */ - u8 card_rev; - volatile void __iomem *enc_mem, *dec_mem, *reg_mem; - u32 pgm_info_offset; - u32 pgm_info_num; - u32 pgm_info_write_idx; - u32 pgm_info_read_idx; - struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; + /* Mailbox */ + struct ivtv_mailbox_data enc_mbox; /* encoder mailboxes */ + struct ivtv_mailbox_data dec_mbox; /* decoder mailboxes */ + struct ivtv_api_cache api_cache[256]; /* cached API commands */ - u64 mpg_data_received; - u64 vbi_data_inserted; - wait_queue_head_t cap_w; - /* when the next decoder event arrives this queue is woken up */ - wait_queue_head_t event_waitq; - /* when the next decoder vsync arrives this queue is woken up */ - wait_queue_head_t vsync_waitq; - /* when the current DMA is finished this queue is woken up */ - wait_queue_head_t dma_waitq; - - /* OSD support */ - unsigned long osd_video_pbase; - int osd_global_alpha_state; /* 0=off : 1=on */ - int osd_local_alpha_state; /* 0=off : 1=on */ - int osd_color_key_state; /* 0=off : 1=on */ - u8 osd_global_alpha; /* Current global alpha */ - u32 osd_color_key; /* Current color key */ - u32 osd_pixelformat; /* Current pixel format */ - struct v4l2_rect osd_rect; /* Current OSD position and size */ - struct v4l2_rect main_rect; /* Current Main window position and size */ - - u32 last_dec_timing[3]; /* Store last retrieved pts/scr/frame values */ - - /* i2c */ + /* I2C */ struct i2c_adapter i2c_adap; struct i2c_algo_bit_data i2c_algo; struct i2c_client i2c_client; - struct mutex i2c_bus_lock; - int i2c_state; - struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */ + int i2c_state; /* i2c bit state */ + struct mutex i2c_bus_lock; /* lock i2c bus */ - /* v4l2 and User settings */ - /* codec settings */ - struct cx2341x_mpeg_params params; - u32 audio_input; - u32 active_input; - u32 active_output; - v4l2_std_id std; - v4l2_std_id std_out; - v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ - u8 audio_stereo_mode; - u8 audio_bilingual_mode; + /* Program Index information */ + u32 pgm_info_offset; /* start of pgm info in encoder memory */ + u32 pgm_info_num; /* number of elements in the pgm cyclic buffer in encoder memory */ + u32 pgm_info_write_idx; /* last index written by the card that was transferred to pgm_info[] */ + u32 pgm_info_read_idx; /* last index in pgm_info read by the application */ + struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */ - /* dualwatch */ - unsigned long dualwatch_jiffies; - u16 dualwatch_stereo_mode; - /* Digitizer type */ - int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ + /* Miscellaneous */ + u32 open_id; /* incremented each time an open occurs, is >= 1 */ + struct v4l2_prio_state prio; /* priority state */ + int search_pack_header; /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */ + int speed; /* current playback speed setting */ + u8 speed_mute_audio; /* 1 if audio should be muted when fast forward */ + u64 mpg_data_received; /* number of bytes received from the MPEG stream */ + u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */ + u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */ + unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */ + u16 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ - u32 lastVsyncFrame; - struct yuv_playback_info yuv_info; - struct osd_info *osd_info; + /* VBI state info */ + struct vbi_info vbi; /* VBI-specific data */ + + + /* YUV playback */ + struct yuv_playback_info yuv_info; /* YUV playback data */ + + + /* OSD support */ + unsigned long osd_video_pbase; + int osd_global_alpha_state; /* 1 = global alpha is on */ + int osd_local_alpha_state; /* 1 = local alpha is on */ + int osd_chroma_key_state; /* 1 = chroma-keying is on */ + u8 osd_global_alpha; /* current global alpha */ + u32 osd_chroma_key; /* current chroma key */ + u32 osd_pixelformat; /* current pixel format */ + struct v4l2_rect osd_rect; /* current OSD position and size */ + struct v4l2_rect main_rect; /* current Main window position and size */ + struct osd_info *osd_info; /* ivtv-fb private OSD info */ }; /* Globals */ diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 2c521d1bb057..f5ed2cf1cd87 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -405,7 +405,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->lastVsyncFrame; + vblank.count = itv->last_vsync_frame; vblank.vcount = trace; vblank.hcount = 0; if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index f4f56a6e1f81..01215a1c4b82 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -163,7 +163,7 @@ void ivtv_set_osd_alpha(struct ivtv *itv) { ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); - ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key); + ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key); } int ivtv_set_speed(struct ivtv *itv, int speed) @@ -426,7 +426,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; - fmt->fmt.win.chromakey = itv->osd_color_key; + fmt->fmt.win.chromakey = itv->osd_chroma_key; fmt->fmt.win.global_alpha = itv->osd_global_alpha; break; @@ -546,7 +546,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; if (set_fmt) { - itv->osd_color_key = fmt->fmt.win.chromakey; + itv->osd_chroma_key = fmt->fmt.win.chromakey; itv->osd_global_alpha = fmt->fmt.win.global_alpha; ivtv_set_osd_alpha(itv); } @@ -1197,7 +1197,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; if (itv->osd_local_alpha_state) fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - if (itv->osd_color_key_state) + if (itv->osd_chroma_key_state) fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; break; } @@ -1209,7 +1209,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void return -EINVAL; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; - itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; + itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ivtv_set_osd_alpha(itv); break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index b6a94a1ad19b..4ec3df58e247 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -750,8 +750,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && - ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || - (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { + ((itv->last_vsync_frame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || + (frame != (itv->last_vsync_frame & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { @@ -766,10 +766,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } } - if (frame != (itv->lastVsyncFrame & 1)) { + if (frame != (itv->last_vsync_frame & 1)) { struct ivtv_stream *s = ivtv_get_output_stream(itv); - itv->lastVsyncFrame += 1; + itv->last_vsync_frame += 1; if (frame == 0) { clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); @@ -834,7 +834,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) */ if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { /* vsync is enabled, see if we're in a new field */ - if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) { + if ((itv->last_vsync_frame & 1) != (read_reg(0x28c0) & 1)) { /* New field, looks like we missed it */ IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); vsync_force = 1; @@ -888,7 +888,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) if (combo & IVTV_IRQ_ENC_EOS) { IVTV_DEBUG_IRQ("ENC EOS\n"); set_bit(IVTV_F_I_EOS, &itv->i_flags); - wake_up(&itv->cap_w); + wake_up(&itv->eos_waitq); } if (combo & IVTV_IRQ_DEC_DATA_REQ) { diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 3939a804f043..e05af62a8cd5 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -404,8 +404,8 @@ static void ivtv_vbi_setup(struct ivtv *itv) if (!itv->vbi.fpi) itv->vbi.fpi = 1; - IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n", - itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer); + IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n", + itv->vbi.enc_start, data[1], itv->vbi.fpi); /* select VBI lines. Note that the sliced argument seems to have no effect. */ @@ -494,6 +494,8 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); if (atomic_read(&itv->capturing) == 0) { + int digitizer; + /* Always use frame based mode. Experiments have demonstrated that byte stream based mode results in dropped frames and corruption. Not often, but occasionally. Many thanks go to Leonard Orb who spent a lot of @@ -519,7 +521,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer); + if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) + digitizer = 0xF1; + else if (itv->card->hw_all & IVTV_HW_SAA7114) + digitizer = 0xEF; + else /* cx25840 */ + digitizer = 0x140; + + ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer); /* Setup VBI */ if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) { @@ -761,7 +770,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) unsigned long duration; then = jiffies; - add_wait_queue(&itv->cap_w, &wait); + add_wait_queue(&itv->eos_waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -787,7 +796,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); } set_current_state(TASK_RUNNING); - remove_wait_queue(&itv->cap_w, &wait); + remove_wait_queue(&itv->eos_waitq, &wait); } then = jiffies; From a158f3559334c6314c7876390caffe88c9fdb64d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 11:31:57 -0300 Subject: [PATCH 0651/2804] V4L/DVB (6094): ivtv: more ivtv-driver.h cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 66 +++++++++++++------------- drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-irq.c | 10 ++-- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 2c27515d8731..332d16415ebf 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -180,11 +180,11 @@ extern int ivtv_debug; #define IVTV_MAX_PGM_INDEX (400) struct ivtv_options { - int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ - int cardtype; /* force card type on load */ - int tuner; /* set tuner on load */ - int radio; /* enable/disable radio */ - int newi2c; /* New I2C algorithm */ + int kilobytes[IVTV_MAX_STREAMS]; /* size in kilobytes of each stream */ + int cardtype; /* force card type on load */ + int tuner; /* set tuner on load */ + int radio; /* enable/disable radio */ + int newi2c; /* new I2C algorithm */ }; /* ivtv-specific mailbox template */ @@ -231,10 +231,10 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DMA 0 /* DMA in progress */ #define IVTV_F_I_UDMA 1 /* UDMA in progress */ #define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */ -#define IVTV_F_I_SPEED_CHANGE 3 /* A speed change is in progress */ -#define IVTV_F_I_EOS 4 /* End of encoder stream reached */ -#define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ -#define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ +#define IVTV_F_I_SPEED_CHANGE 3 /* a speed change is in progress */ +#define IVTV_F_I_EOS 4 /* end of encoder stream reached */ +#define IVTV_F_I_RADIO_USER 5 /* the radio tuner is selected */ +#define IVTV_F_I_DIG_RST 6 /* reset digitizer */ #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ @@ -242,7 +242,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */ #define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */ #define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */ -#define IVTV_F_I_HAVE_WORK 15 /* Used in the interrupt handler: there is work to be done */ +#define IVTV_F_I_HAVE_WORK 15 /* used in the interrupt handler: there is work to be done */ #define IVTV_F_I_WORK_HANDLER_VBI 16 /* there is work to be done for VBI */ #define IVTV_F_I_WORK_HANDLER_YUV 17 /* there is work to be done for YUV */ #define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ @@ -295,19 +295,18 @@ struct ivtv_buffer { unsigned short b_flags; unsigned short dma_xfer_cnt; char *buf; - u32 bytesused; u32 readpos; }; struct ivtv_queue { - struct list_head list; - u32 buffers; - u32 length; - u32 bytesused; + struct list_head list; /* the list of buffers in this queue */ + u32 buffers; /* number of buffers in this queue */ + u32 length; /* total number of bytes of available buffer space */ + u32 bytesused; /* total number of bytes used in this queue */ }; -struct ivtv; /* forward reference */ +struct ivtv; /* forward reference */ struct ivtv_stream { /* These first four fields are always set, even if the stream @@ -318,11 +317,9 @@ struct ivtv_stream { int type; /* stream type */ u32 id; - spinlock_t qlock; /* locks access to the queues */ - unsigned long s_flags; /* status flags, see above */ - int dma; /* can be PCI_DMA_TODEVICE, - PCI_DMA_FROMDEVICE or - PCI_DMA_NONE */ + spinlock_t qlock; /* locks access to the queues */ + unsigned long s_flags; /* status flags, see above */ + int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ u32 pending_offset; u32 pending_backup; u64 pending_pts; @@ -365,10 +362,10 @@ struct ivtv_stream { }; struct ivtv_open_id { - u32 open_id; - int type; - int yuv_frames; - enum v4l2_priority prio; + u32 open_id; /* unique ID for this file descriptor */ + int type; /* stream type */ + int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */ + enum v4l2_priority prio; /* priority */ struct ivtv *itv; }; @@ -493,6 +490,14 @@ struct yuv_playback_info /* VBI data */ struct vbi_info { + /* VBI general fixed card data */ + u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ + u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */ + u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */ + u32 sliced_decoder_line_size; /* sliced VBI line size from digitizer */ + u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */ + u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */ + u32 dec_start; u32 enc_start, enc_size; int fpi; @@ -506,12 +511,6 @@ struct vbi_info { int wss; u8 wss_found; u8 wss_no_update; - u32 raw_decoder_line_size; - u8 raw_decoder_sav_odd_field; - u8 raw_decoder_sav_even_field; - u32 sliced_decoder_line_size; - u8 sliced_decoder_sav_odd_field; - u8 sliced_decoder_sav_even_field; struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; @@ -592,8 +591,7 @@ struct ivtv { /* Locking */ spinlock_t lock; /* lock access to this struct */ - /* mutex used to serialize open/close/start/stop/ioctl operations */ - struct mutex serialize_lock; + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ /* Streams */ @@ -616,7 +614,7 @@ struct ivtv { int dma_retries; /* current DMA retry attempt */ struct ivtv_user_dma udma; /* user based DMA for OSD */ struct timer_list dma_timer; /* timer used to catch unfinished DMAs */ - u32 last_vsync_frame; /* last seen vsync field */ + u32 last_vsync_field; /* last seen vsync field */ wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */ wait_queue_head_t eos_waitq; /* wake up when EOS arrives */ wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */ diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index f5ed2cf1cd87..e80564aed632 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -405,7 +405,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->last_vsync_frame; + vblank.count = itv->last_vsync_field; vblank.vcount = trace; vblank.hcount = 0; if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 4ec3df58e247..66d0da22389f 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -750,8 +750,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && - ((itv->last_vsync_frame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || - (frame != (itv->last_vsync_frame & 1) && !itv->yuv_info.frame_interlaced)) { + ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || + (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { @@ -766,10 +766,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } } - if (frame != (itv->last_vsync_frame & 1)) { + if (frame != (itv->last_vsync_field & 1)) { struct ivtv_stream *s = ivtv_get_output_stream(itv); - itv->last_vsync_frame += 1; + itv->last_vsync_field += 1; if (frame == 0) { clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); @@ -834,7 +834,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) */ if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { /* vsync is enabled, see if we're in a new field */ - if ((itv->last_vsync_frame & 1) != (read_reg(0x28c0) & 1)) { + if ((itv->last_vsync_field & 1) != (read_reg(0x28c0) & 1)) { /* New field, looks like we missed it */ IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); vsync_force = 1; From 559e196a56a5d518181efc1d2fefe0892f4689b4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 17:51:07 -0300 Subject: [PATCH 0652/2804] V4L/DVB (6096): ivtv: fix V4L2_ENC_CMD_STOP_AT_GOP_END support Support for V4L2_ENC_CMD_STOP_AT_GOP_END was broken. While the driver correctly waited for the card to capture until the GOP was complete, afterwards the driver buffers were just flushed instead of waiting for the application to read all the pending data. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 37 ++++++++++++++++--------- drivers/media/video/ivtv/ivtv-streams.c | 8 ++---- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 170bef61aa62..5b5d6666fa16 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -258,19 +258,19 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, } return buf; } - /* return if file was opened with O_NONBLOCK */ - if (non_block) { - *err = -EAGAIN; - return NULL; - } /* return if end of stream */ if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); IVTV_DEBUG_INFO("EOS %s\n", s->name); return NULL; } + /* return if file was opened with O_NONBLOCK */ + if (non_block) { + *err = -EAGAIN; + return NULL; + } + /* wait for more data to arrive */ prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); /* New buffers might have become available before we were added to the waitqueue */ @@ -378,10 +378,20 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co int rc; buf = ivtv_get_buffer(s, non_block, &rc); - if (buf == NULL && rc == -EAGAIN && tot_written) - break; - if (buf == NULL) + /* if there is no data available... */ + if (buf == NULL) { + /* if we got data, then return that regardless */ + if (tot_written) + break; + /* EOS condition */ + if (rc == 0) { + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + ivtv_release_stream(s); + } + /* set errno */ return rc; + } rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); if (buf != &itv->vbi.sliced_mpeg_buf) { ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); @@ -738,10 +748,11 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) ivtv_stop_v4l2_encode_stream(s, gop_end); } } - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - ivtv_release_stream(s); + if (!gop_end) { + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + ivtv_release_stream(s); + } } static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index e05af62a8cd5..a3296224f821 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -719,7 +719,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) struct ivtv *itv = s->itv; DECLARE_WAITQUEUE(wait, current); int cap_type; - unsigned long then; int stopmode; if (s->v4l2dev == NULL) @@ -762,14 +761,12 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); - then = jiffies; - if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { /* only run these if we're shutting down the last cap */ unsigned long duration; + unsigned long then = jiffies; - then = jiffies; add_wait_queue(&itv->eos_waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -797,10 +794,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } set_current_state(TASK_RUNNING); remove_wait_queue(&itv->eos_waitq, &wait); + set_bit(IVTV_F_S_STREAMOFF, &s->s_flags); } - then = jiffies; - /* Handle any pending interrupts */ ivtv_msleep_timeout(100, 1); } From 2d4d5f11ecf6df6974579c70461866932f0bd722 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 21:15:24 -0300 Subject: [PATCH 0653/2804] V4L/DVB (6097): ivtv: set correct pixel format and alpha properties ivtv: set correct pixel format and alpha properties in VIDIOC_G_FBUF Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 - drivers/media/video/ivtv/ivtv-ioctl.c | 66 ++++++++++++++++++++------ 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 332d16415ebf..41f753c125da 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -672,7 +672,6 @@ struct ivtv { int osd_chroma_key_state; /* 1 = chroma-keying is on */ u8 osd_global_alpha; /* current global alpha */ u32 osd_chroma_key; /* current chroma key */ - u32 osd_pixelformat; /* current pixel format */ struct v4l2_rect osd_rect; /* current OSD position and size */ struct v4l2_rect main_rect; /* current Main window position and size */ struct osd_info *osd_info; /* ivtv-fb private OSD info */ diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 01215a1c4b82..6d24c6b9a45b 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -699,6 +699,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg) { struct ivtv_open_id *id = NULL; + u32 data[CX2341X_MBOX_MAX_DATA]; if (filp) id = (struct ivtv_open_id *)filp->private_data; @@ -1183,22 +1184,59 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_G_FBUF: { struct v4l2_framebuffer *fb = arg; + int pixfmt; + static u32 pixel_format[16] = { + V4L2_PIX_FMT_RGB332, /* Really RGB Indexed */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + /* Really YUV variants */ + V4L2_PIX_FMT_RGB332, /* Really YUV Indexed */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + }; memset(fb, 0, sizeof(*fb)); if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | - V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA; - fb->fmt.pixelformat = itv->osd_pixelformat; + V4L2_FBUF_CAP_GLOBAL_ALPHA; + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + pixfmt = (data[0] >> 3) & 0xf; + fb->fmt.pixelformat = pixel_format[pixfmt]; fb->fmt.width = itv->osd_rect.width; fb->fmt.height = itv->osd_rect.height; fb->base = (void *)itv->osd_video_pbase; - if (itv->osd_global_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; - if (itv->osd_local_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; if (itv->osd_chroma_key_state) fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; + if (itv->osd_global_alpha_state) + fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + pixfmt &= 7; + /* no local alpha for RGB565 or unknown formats */ + if (pixfmt == 1 || pixfmt > 4) + break; + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + else + fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; + if (itv->osd_local_alpha_state) { + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; + else + fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; + } break; } @@ -1208,7 +1246,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; - itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; + itv->osd_local_alpha_state = + (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ivtv_set_osd_alpha(itv); break; @@ -1226,7 +1265,6 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_LOG_STATUS: { int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; - u32 data[CX2341X_MBOX_MAX_DATA]; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -1248,28 +1286,28 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_output vidout; struct v4l2_audioout audout; int mode = itv->output_mode; - static const char * const output_modes[] = { + static const char * const output_modes[5] = { "None", "MPEG Streaming", "YUV Streaming", "YUV Frames", "Passthrough", }; - static const char * const audio_modes[] = { + static const char * const audio_modes[5] = { "Stereo", "Left", "Right", "Mono", "Swapped" }; - static const char * const alpha_mode[] = { + static const char * const alpha_mode[4] = { "None", "Global", "Local", "Global and Local" }; - static const char * const pixel_format[] = { - "RGB Indexed", + static const char * const pixel_format[16] = { + "ARGB Indexed", "RGB 5:6:5", "ARGB 1:5:5:5", "ARGB 1:4:4:4", @@ -1277,7 +1315,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "5", "6", "7", - "YUV Indexed", + "AYUV Indexed", "YUV 5:6:5", "AYUV 1:5:5:5", "AYUV 1:4:4:4", From 6327e952cd3ef5e5a49c84f794dbba72ff3c0e9c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 05:28:54 -0300 Subject: [PATCH 0654/2804] V4L/DVB (6098): ivtv: kzalloc() returns void pointer, no need to cast Since kzalloc() returns a void pointer, we don't need to cast the return value in drivers/media/video/ivtv/ivtv-queue.c Signed-off-by: Jesper Juhl Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-queue.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index 437f134796e3..39a216713244 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -203,14 +203,14 @@ int ivtv_stream_alloc(struct ivtv_stream *s) s->dma != PCI_DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + s->sg_pending = kzalloc(SGsize, GFP_KERNEL); if (s->sg_pending == NULL) { IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); return -ENOMEM; } s->sg_pending_size = 0; - s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + s->sg_processing = kzalloc(SGsize, GFP_KERNEL); if (s->sg_processing == NULL) { IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); kfree(s->sg_pending); @@ -219,7 +219,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s) } s->sg_processing_size = 0; - s->sg_dma = (struct ivtv_sg_element *)kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); + s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); if (s->sg_dma == NULL) { IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); kfree(s->sg_pending); From 71be258bd9bf41ca3060021f2ed50ad8c672a01e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 23 Aug 2007 22:33:28 -0300 Subject: [PATCH 0655/2804] V4L/DVB (6100): dvb_net: whitespace cleanup Clean whitespace brain-damage caused by previous patch, "Fix a warning at dvb_net" Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 13e2998a4043..2117377c141d 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -795,8 +795,8 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, } -static void dvb_net_sec(struct net_device *dev, const u8 *pkt, int -pkt_len) +static void dvb_net_sec(struct net_device *dev, + const u8 *pkt, int pkt_len) { u8 *eth; struct sk_buff *skb; From d9bf2c037754f1493323829048d6210602712a43 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 25 Aug 2007 11:23:54 -0300 Subject: [PATCH 0656/2804] V4L/DVB (6102): dvb: remove some unneeded vmalloc() return value casts from av7110 vmalloc() returns void * - no need to cast it. Signed-off-by: Jesper Juhl Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 2 +- drivers/media/dvb/ttpci/av7110_ir.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index aecfdeb8ec43..8b8144f77a73 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1542,7 +1542,7 @@ static int get_firmware(struct av7110* av7110) } /* check if the firmware is available */ - av7110->bin_fw = (unsigned char *) vmalloc(fw->size); + av7110->bin_fw = vmalloc(fw->size); if (NULL == av7110->bin_fw) { dprintk(1, "out of memory\n"); release_firmware(fw); diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index e8f553719bc5..5d19c402dad1 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -279,7 +279,7 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, if (count < size) return -EINVAL; - page = (char *) vmalloc(size); + page = vmalloc(size); if (!page) return -ENOMEM; From 0c12c1bfc432477e38ba76f680be4b3f55112a8e Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Sat, 25 Aug 2007 11:36:39 -0300 Subject: [PATCH 0657/2804] V4L/DVB (6103): dvb_ca_en50221: return correct error code value return correct error code value Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index b0bf21958ede..3f7479557919 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1569,7 +1569,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_ca_private *ca = dvbdev->priv; - int err = 0; + int err; dprintk("%s\n", __FUNCTION__); @@ -1581,7 +1581,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) module_put(ca->pub->owner); - return 0; + return err; } From 226835d7e0a1136bce2a0b923e0832ab47450a30 Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Sat, 25 Aug 2007 11:46:07 -0300 Subject: [PATCH 0658/2804] V4L/DVB (6104): dvb_ca_en50221: decrement module use count on error decrement module use count on error Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 3f7479557919..5c7bcb8393d2 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1535,8 +1535,10 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) return -EIO; err = dvb_generic_open(inode, file); - if (err < 0) + if (err < 0) { + module_put(ca->pub->owner); return err; + } for (i = 0; i < ca->slot_count; i++) { From 48136e1e93195b56dc3d9b0730917241b3365633 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 12:00:23 -0300 Subject: [PATCH 0659/2804] V4L/DVB (6105): dvb_frontend: ts_bus_ctrl() handling fixed ts_bus_ctrl() should only be called by - the first open - the last release call. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 38 +++++++++++++---------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 880d499cd36a..07c0db2abfbc 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1056,18 +1056,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) dprintk ("%s\n", __FUNCTION__); - if ((ret = dvb_generic_open (inode, file)) < 0) - return ret; - - if (fe->ops.ts_bus_ctrl) { - if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) { - dvb_generic_release (inode, file); + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { + if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) return ret; - } } - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if ((ret = dvb_generic_open (inode, file)) < 0) + goto err1; + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { /* normal tune mode when opened R/W */ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; fepriv->tone = -1; @@ -1075,13 +1072,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ret = dvb_frontend_start (fe); if (ret) - dvb_generic_release (inode, file); + goto err2; /* empty event queue */ fepriv->events.eventr = fepriv->events.eventw = 0; } return ret; + +err2: + dvb_generic_release(inode, file); +err1: + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); + return ret; } static int dvb_frontend_release(struct inode *inode, struct file *file) @@ -1096,16 +1100,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) if ((file->f_flags & O_ACCMODE) != O_RDONLY) fepriv->release_jiffies = jiffies; - if (fe->ops.ts_bus_ctrl) - fe->ops.ts_bus_ctrl (fe, 0); - ret = dvb_generic_release (inode, file); - if (dvbdev->users==-1 && fepriv->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - wake_up(&dvbdev->wait_queue); + if (dvbdev->users == -1) { + if (fepriv->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; + wake_up(&dvbdev->wait_queue); + } + if (fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); } + return ret; } From 849be2cdf11eef830ec2a3f916c8e7d1e51bc9fb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 12:22:16 -0300 Subject: [PATCH 0660/2804] V4L/DVB (6106): dvb_frontend: Default for dvb_shutdown_timeout set to 0 Default for dvb_shutdown_timeout set to 0. dvb_shutdown_timeout > 0 is used for debugging only. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 07c0db2abfbc..32017f62a82f 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -42,7 +42,7 @@ #include "dvbdev.h" static int dvb_frontend_debug; -static int dvb_shutdown_timeout = 5; +static int dvb_shutdown_timeout; static int dvb_force_auto_inversion; static int dvb_override_tune_delay; static int dvb_powerdown_on_sleep = 1; From 608f62d6ffbc21067e8b9a09f887a5d6cbfe7617 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 13:17:53 -0300 Subject: [PATCH 0661/2804] V4L/DVB (6107): dvb_frontend: clean-up shutdown handling Now dvb_powerdown_on_sleep controls whether - whether LNB power is turned off - whether the tuner/frontend enters sleep mode Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 32017f62a82f..b203640ef1c5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -573,10 +573,9 @@ restart: dvb_frontend_swzigzag(fe); } - if (dvb_shutdown_timeout) { - if (dvb_powerdown_on_sleep) - if (fe->ops.set_voltage) - fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); + if (dvb_powerdown_on_sleep) { + if (fe->ops.set_voltage) + fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops.tuner_ops.sleep) { fe->ops.tuner_ops.sleep(fe); if (fe->ops.i2c_gate_ctrl) From 5d05704cbe7f9c4708e0f35be13839f593441215 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:16:37 -0300 Subject: [PATCH 0662/2804] V4L/DVB (6108): videodev2.h: add new pixel formats for the cx23415 OSD The Conexant cx23415 MPEG encoder/decoder supports some unusual pixelformats for the On-Screen Display. Add new defines to videodev2.h for these formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index ae9b24c12f6a..1f503e94eff1 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -271,6 +271,7 @@ struct v4l2_pix_format /* Pixel format FOURCC depth Description */ #define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */ #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ @@ -280,6 +281,7 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ #define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P','A','L','8') /* 8 8-bit palette */ #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ @@ -287,6 +289,10 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ +#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y','4','4','4') /* 16 xxxxyyyy uuuuvvvv */ +#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y','U','V','O') /* 16 YUV-5-5-5 */ +#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y','U','V','P') /* 16 YUV-5-6-5 */ +#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y','U','V','4') /* 32 YUV-8-8-8-8 */ /* two planes -- one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ @@ -298,7 +304,6 @@ struct v4l2_pix_format #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:2:0 16x16 macroblocks */ -#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */ /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ From 3eaeef57423b5f9571e7524373ec079f583b2113 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:19:18 -0300 Subject: [PATCH 0663/2804] V4L/DVB (6109): ivtv: use new videodev2.h pixel formats Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 6d24c6b9a45b..206eee7542db 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1186,7 +1186,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_framebuffer *fb = arg; int pixfmt; static u32 pixel_format[16] = { - V4L2_PIX_FMT_RGB332, /* Really RGB Indexed */ + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_RGB555, V4L2_PIX_FMT_RGB444, @@ -1194,12 +1194,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void 0, 0, 0, - /* Really YUV variants */ - V4L2_PIX_FMT_RGB332, /* Really YUV Indexed */ - V4L2_PIX_FMT_RGB565, - V4L2_PIX_FMT_RGB555, - V4L2_PIX_FMT_RGB444, - V4L2_PIX_FMT_RGB32, + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ + V4L2_PIX_FMT_YUV565, + V4L2_PIX_FMT_YUV555, + V4L2_PIX_FMT_YUV444, + V4L2_PIX_FMT_YUV32, 0, 0, 0, From f58db9590fc56fe519d6919abae7a70ec17b4d0e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Aug 2007 12:05:18 -0300 Subject: [PATCH 0664/2804] V4L/DVB (6111): Fix a warning when compiling on x86_64 tcm825x.c: In function 'ioctl_try_fmt_cap': tcm825x.c:639: warning: format '%d' expects type 'int', but argument 4 has type 'long unsigned int' Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tcm825x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 4b973b099e59..3a139f288a9d 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -635,8 +635,8 @@ static int ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_pix_format *pix = &f->fmt.pix; isize = tcm825x_find_size(s, pix->width, pix->height); - dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %d\n", - isize, TCM825X_NUM_CAPTURE_FORMATS); + dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n", + isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS); pix->width = tcm825x_sizes[isize].width; pix->height = tcm825x_sizes[isize].height; From 21340ae03a61bded62acb582264660e61c0636b9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 10:53:16 -0300 Subject: [PATCH 0665/2804] V4L/DVB (6112): cx25840: use a workqueue to load the firmware Loading the firmware using the i2c bit-banging code blocks the kernel. Move the firmware load code into a workqueue so that it plays well with other processes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 45 +++++++++++++++++----- drivers/media/video/cx25840/cx25840-core.h | 4 +- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index ae90d1c3d12b..d6f8b3b6af40 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -179,9 +179,18 @@ static void cx25836_initialize(struct i2c_client *client) cx25840_and_or(client, 0x15b, ~0x1e, 0x10); } +static void cx25840_work_handler(struct work_struct *work) +{ + struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); + cx25840_loadfw(state->c); + wake_up(&state->fw_wait); +} + static void cx25840_initialize(struct i2c_client *client) { + DEFINE_WAIT(wait); struct cx25840_state *state = i2c_get_clientdata(client); + struct workqueue_struct *q; /* datasheet startup in numbered steps, refer to page 3-77 */ /* 2. */ @@ -197,7 +206,19 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_write(client, 0x13c, 0x01); cx25840_write(client, 0x13c, 0x00); /* 5. */ - cx25840_loadfw(client); + /* Do the firmware load in a work handler to prevent. + Otherwise the kernel is blocked waiting for the + bit-banging i2c interface to finish uploading the + firmware. */ + INIT_WORK(&state->fw_work, cx25840_work_handler); + init_waitqueue_head(&state->fw_wait); + q = create_singlethread_workqueue("cx25840_fw"); + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + /* 6. */ cx25840_write(client, 0x115, 0x8c); cx25840_write(client, 0x116, 0x07); @@ -872,17 +893,16 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return 0; - state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); - if (state == 0) + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) return -ENOMEM; - client = &state->c; client->addr = address; client->adapter = adapter; client->driver = &i2c_driver_cx25840; snprintf(client->name, sizeof(client->name) - 1, "cx25840"); - v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", address << 1); + v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); @@ -891,26 +911,32 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, * 0x83 for the cx2583x and 0x84 for the cx2584x */ if ((device_id & 0xff00) == 0x8300) { id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; - state->is_cx25836 = 1; } else if ((device_id & 0xff00) == 0x8400) { id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); - state->is_cx25836 = 0; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - kfree(state); + kfree(client); return 0; } + state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + /* Note: revision '(device_id & 0x0f) == 2' was never built. The marking skips from 0x1 == 22 to 0x3 == 23. */ v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", (device_id & 0xfff0) >> 4, (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f), - address << 1, adapter->name); + client->addr << 1, client->adapter->name); i2c_set_clientdata(client, state); + state->c = client; + state->is_cx25836 = ((device_id & 0xff00) == 0x8300); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; @@ -944,6 +970,7 @@ static int cx25840_detach_client(struct i2c_client *client) } kfree(state); + kfree(client); return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 86e2edfc4941..ea669b1f084d 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -35,7 +35,7 @@ extern int cx25840_debug; #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) struct cx25840_state { - struct i2c_client c; + struct i2c_client *c; int pvr150_workaround; int radio; enum cx25840_video_input vid_input; @@ -48,6 +48,8 @@ struct cx25840_state { u32 rev; int is_cx25836; int is_initialized; + wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ + struct work_struct fw_work; /* work entry for fw load */ }; /* ----------------------------------------------------------------------- */ From 49ebf14e249734a5f64d5bdd9aaa2ddf4bcedc51 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 10:54:14 -0300 Subject: [PATCH 0666/2804] V4L/DVB (6113): ivtv: udelay for the i2c bus was set too high An udelay of 5 is sufficient for standard speed i2c busses, 10 make it too slow. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 085dc3938da7..285fca676a69 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -541,7 +541,7 @@ static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { .setscl = ivtv_setscl_old, .getsda = ivtv_getsda_old, .getscl = ivtv_getscl_old, - .udelay = 10, + .udelay = 5, .timeout = 200, }; From 26e9d599561e9a964bd4d7c2be0029db8aaff852 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 05:41:52 -0300 Subject: [PATCH 0667/2804] V4L/DVB (6115): ivtv/ivtv-fb: improve locking to avoid initialization problems ivtv/ivtv-fb: improve locking to prevent ivtv/ivtv-fb initialization problems Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 4 ++++ drivers/media/video/ivtv/ivtv-fb.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 855697c1c968..2a5e0facca7d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1003,6 +1003,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); + mutex_lock(&itv->serialize_lock); + /* PCI Device Setup */ if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) { if (retval == -EIO) @@ -1174,6 +1176,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ERR("Failed to register irq %d\n", retval); goto free_streams; } + mutex_unlock(&itv->serialize_lock); IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); return 0; @@ -1192,6 +1195,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); free_workqueue: destroy_workqueue(itv->irq_work_queues); + mutex_unlock(&itv->serialize_lock); err: if (retval == 0) retval = -ENODEV; diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index e80564aed632..ffe6478682ae 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -1011,10 +1011,13 @@ static int ivtvfb_init_io(struct ivtv *itv) { struct osd_info *oi = itv->osd_info; + mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { + mutex_unlock(&itv->serialize_lock); IVTV_FB_ERR("Failed to initialize ivtv\n"); return -ENXIO; } + mutex_unlock(&itv->serialize_lock); ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); From 2f3a98931f51be6093df7c6cc2633bf238778b7d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 14:11:23 -0300 Subject: [PATCH 0668/2804] V4L/DVB (6116): ivtv: VBI cleanups and fixes Besides some VBI cleanups this patch also fixes a subtle problem with the VBI re-insertion stream where the PIO work handler wasn't called quickly enough, resulting in occasional corrupt data. Furthermore the CC output didn't disable CC correctly and at the right time, causing duplicates to be sent. An saa7127 fix for VPS output was also added: the wrong data was sent. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 26 ++- drivers/media/video/ivtv/ivtv-fileops.c | 11 +- drivers/media/video/ivtv/ivtv-irq.c | 10 +- drivers/media/video/ivtv/ivtv-vbi.c | 237 ++++++++---------------- drivers/media/video/ivtv/ivtv-vbi.h | 4 +- drivers/media/video/saa7127.c | 10 +- 6 files changed, 112 insertions(+), 186 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 41f753c125da..748ef66bd945 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -489,6 +489,15 @@ struct yuv_playback_info #define IVTV_VBI_FRAMES 32 /* VBI data */ +struct vbi_cc { + u8 odd[2]; /* two-byte payload of odd field */ + u8 even[2]; /* two-byte payload of even field */; +}; + +struct vbi_vps { + u8 data[5]; /* five-byte VPS payload */ +}; + struct vbi_info { /* VBI general fixed card data */ u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ @@ -502,15 +511,14 @@ struct vbi_info { u32 enc_start, enc_size; int fpi; u32 frame; - u8 cc_data_odd[256]; - u8 cc_data_even[256]; - int cc_pos; - u8 cc_no_update; - u8 vps[5]; - u8 vps_found; - int wss; - u8 wss_found; - u8 wss_no_update; + struct vbi_cc cc_payload[256]; /* Sliced VBI CC payload array. It is an array to + prevent dropping CC data if they couldn't be + processed fast enough. */ + int cc_payload_idx; /* Index in cc_payload */ + u8 cc_missing_cnt; /* Counts number of frames without CC for passthrough mode */ + int wss_payload; /* Sliced VBI WSS payload */ + u8 wss_missing_cnt; /* Counts number of frames without WSS for passthrough mode */ + struct vbi_vps vps_payload; /* Sliced VBI VPS payload */ struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 5b5d6666fa16..da50fa4a72a5 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -563,8 +563,11 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c /* This stream does not need to start any decoding */ if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { + int elems = count / sizeof(struct v4l2_sliced_vbi_data); + set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return ivtv_write_vbi(itv, user_buf, count); + ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems); + return elems * sizeof(struct v4l2_sliced_vbi_data); } mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; @@ -828,10 +831,10 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); /* If all output streams are closed, and if the user doesn't have - IVTV_DEC_STREAM_TYPE_VOUT open, then disable VBI on TV-out. */ + IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) { - /* disable VBI on TV-out */ - ivtv_disable_vbi(itv); + /* disable CC on TV-out */ + ivtv_disable_cc(itv); } } else { ivtv_stop_capture(id, 0); diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 66d0da22389f..bf7d99c6ffaf 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -786,7 +786,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) wake_up(&s->waitq); /* Send VBI to saa7127 */ - if (frame) { + if (frame && (itv->output_mode == OUT_PASSTHROUGH || + test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) || + test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) || + test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) { set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } @@ -809,7 +812,7 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } -#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ) +#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT) irqreturn_t ivtv_irq_handler(int irq, void *dev_id) { @@ -942,8 +945,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } } - if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) + if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { queue_work(itv->irq_work_queues, &itv->irq_work_queue); + } spin_unlock(&itv->dma_reg_lock); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index 5d8a40f3d2b6..c151bcf5519a 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -23,8 +23,7 @@ #include "ivtv-queue.h" #include "ivtv-vbi.h" -static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5) +static void ivtv_set_vps(struct ivtv *itv, int enabled) { struct v4l2_sliced_vbi_data data; @@ -33,15 +32,15 @@ static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps data.id = V4L2_SLICED_VPS; data.field = 0; data.line = enabled ? 16 : 0; - data.data[4] = vps1; - data.data[10] = vps2; - data.data[11] = vps3; - data.data[12] = vps4; - data.data[13] = vps5; + data.data[2] = itv->vbi.vps_payload.data[0]; + data.data[8] = itv->vbi.vps_payload.data[1]; + data.data[9] = itv->vbi.vps_payload.data[2]; + data.data[10] = itv->vbi.vps_payload.data[3]; + data.data[11] = itv->vbi.vps_payload.data[4]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); } -static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) +static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc) { struct v4l2_sliced_vbi_data data; @@ -50,13 +49,13 @@ static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 c data.id = V4L2_SLICED_CAPTION_525; data.field = 0; data.line = (mode & 1) ? 21 : 0; - data.data[0] = cc1; - data.data[1] = cc2; + data.data[0] = cc->odd[0]; + data.data[1] = cc->odd[1]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); data.field = 1; data.line = (mode & 2) ? 21 : 0; - data.data[0] = cc3; - data.data[1] = cc4; + data.data[0] = cc->even[0]; + data.data[1] = cc->even[1]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); } @@ -92,62 +91,50 @@ static int odd_parity(u8 c) return c & 1; } -static void passthrough_vbi_data(struct ivtv *itv, int cnt) +void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt) { - int wss = 0; - u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; - u8 vps[13]; + struct vbi_info *vi = &itv->vbi; + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; int found_cc = 0; - int found_wss = 0; - int found_vps = 0; - int cc_pos = itv->vbi.cc_pos; - int i; + size_t i; for (i = 0; i < cnt; i++) { - struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; + const struct v4l2_sliced_vbi_data *d = sliced + i; if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { - found_cc = 1; if (d->field) { - cc[2] = d->data[0]; - cc[3] = d->data[1]; + cc.even[0] = d->data[0]; + cc.even[1] = d->data[1]; } else { - cc[0] = d->data[0]; - cc[1] = d->data[1]; + cc.odd[0] = d->data[0]; + cc.odd[1] = d->data[1]; } + found_cc = 1; } else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { - memcpy(vps, d->data, sizeof(vps)); - found_vps = 1; + struct vbi_vps vps; + + vps.data[0] = d->data[2]; + vps.data[1] = d->data[8]; + vps.data[2] = d->data[9]; + vps.data[3] = d->data[10]; + vps.data[4] = d->data[11]; + if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) { + vi->vps_payload = vps; + set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); + } } else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) { - wss = d->data[0] | d->data[1] << 8; - found_wss = 1; + int wss = d->data[0] | d->data[1] << 8; + + if (vi->wss_payload != wss) { + vi->wss_payload = wss; + set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); + } } } - - if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) { - itv->vbi.wss = wss; - itv->vbi.wss_found = found_wss; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - - if (found_vps || itv->vbi.vps_found) { - itv->vbi.vps[0] = vps[2]; - itv->vbi.vps[1] = vps[8]; - itv->vbi.vps[2] = vps[9]; - itv->vbi.vps[3] = vps[10]; - itv->vbi.vps[4] = vps[11]; - itv->vbi.vps_found = found_vps; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - } - - if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { - itv->vbi.cc_data_odd[cc_pos] = cc[0]; - itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; - itv->vbi.cc_data_even[cc_pos] = cc[2]; - itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; - itv->vbi.cc_pos = cc_pos + 2; + if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) { + vi->cc_payload[vi->cc_payload_idx++] = cc; set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); } } @@ -271,69 +258,6 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) return line * sizeof(itv->vbi.sliced_dec_data[0]); } -ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count) -{ - /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */ - const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf; - u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; - int found_cc = 0; - int cc_pos = itv->vbi.cc_pos; - - while (count >= sizeof(struct v4l2_sliced_vbi_data)) { - switch (p->id) { - case V4L2_SLICED_CAPTION_525: - if (p->line == 21) { - found_cc = 1; - if (p->field) { - cc[2] = p->data[0]; - cc[3] = p->data[1]; - } else { - cc[0] = p->data[0]; - cc[1] = p->data[1]; - } - } - break; - - case V4L2_SLICED_VPS: - if (p->line == 16 && p->field == 0) { - itv->vbi.vps[0] = p->data[2]; - itv->vbi.vps[1] = p->data[8]; - itv->vbi.vps[2] = p->data[9]; - itv->vbi.vps[3] = p->data[10]; - itv->vbi.vps[4] = p->data[11]; - itv->vbi.vps_found = 1; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - } - break; - - case V4L2_SLICED_WSS_625: - if (p->line == 23 && p->field == 0) { - /* No lock needed for WSS */ - itv->vbi.wss = p->data[0] | (p->data[1] << 8); - itv->vbi.wss_found = 1; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - break; - - default: - break; - } - count -= sizeof(*p); - p++; - } - - if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { - itv->vbi.cc_data_odd[cc_pos] = cc[0]; - itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; - itv->vbi.cc_data_even[cc_pos] = cc[2]; - itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; - itv->vbi.cc_pos = cc_pos + 2; - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - } - - return (const char __user *)p - ubuf; -} - /* Compress raw VBI format, removes leading SAV codes and surplus space after the field. Returns new compressed size. */ @@ -482,108 +406,95 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); buf->bytesused = cnt; - passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0])); + ivtv_write_vbi(itv, itv->vbi.sliced_dec_data, + cnt / sizeof(itv->vbi.sliced_dec_data[0])); return; } } -void ivtv_disable_vbi(struct ivtv *itv) +void ivtv_disable_cc(struct ivtv *itv) { - clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; + clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - ivtv_set_wss(itv, 0, 0); - ivtv_set_cc(itv, 0, 0, 0, 0, 0); - ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0); - itv->vbi.vps_found = itv->vbi.wss_found = 0; - itv->vbi.wss = 0; - itv->vbi.cc_pos = 0; + ivtv_set_cc(itv, 0, &cc); + itv->vbi.cc_payload_idx = 0; } void ivtv_vbi_work_handler(struct ivtv *itv) { + struct vbi_info *vi = &itv->vbi; struct v4l2_sliced_vbi_data data; + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; /* Lock */ if (itv->output_mode == OUT_PASSTHROUGH) { - /* Note: currently only the saa7115 is used in a PVR350, - so these commands are for now saa7115 specific. */ if (itv->is_50hz) { data.id = V4L2_SLICED_WSS_625; data.field = 0; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { ivtv_set_wss(itv, 1, data.data[0] & 0xf); - itv->vbi.wss_no_update = 0; - } else if (itv->vbi.wss_no_update == 4) { + vi->wss_missing_cnt = 0; + } else if (vi->wss_missing_cnt == 4) { ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ } else { - itv->vbi.wss_no_update++; + vi->wss_missing_cnt++; } } else { - u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0; int mode = 0; data.id = V4L2_SLICED_CAPTION_525; data.field = 0; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { mode |= 1; - c1 = data.data[0]; - c2 = data.data[1]; + cc.odd[0] = data.data[0]; + cc.odd[1] = data.data[1]; } data.field = 1; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { mode |= 2; - c3 = data.data[0]; - c4 = data.data[1]; + cc.even[0] = data.data[0]; + cc.even[1] = data.data[1]; } if (mode) { - itv->vbi.cc_no_update = 0; - ivtv_set_cc(itv, mode, c1, c2, c3, c4); - } else if (itv->vbi.cc_no_update == 4) { - ivtv_set_cc(itv, 0, 0, 0, 0, 0); + vi->cc_missing_cnt = 0; + ivtv_set_cc(itv, mode, &cc); + } else if (vi->cc_missing_cnt == 4) { + ivtv_set_cc(itv, 0, &cc); } else { - itv->vbi.cc_no_update++; + vi->cc_missing_cnt++; } } return; } if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { - /* Lock */ - ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf); + ivtv_set_wss(itv, 1, vi->wss_payload & 0xf); } - if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { - if (itv->vbi.cc_pos == 0) { - ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80); + if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { + if (vi->cc_payload_idx == 0) { + clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + ivtv_set_cc(itv, 3, &cc); } - while (itv->vbi.cc_pos) { - u8 cc_odd0 = itv->vbi.cc_data_odd[0]; - u8 cc_odd1 = itv->vbi.cc_data_odd[1]; - u8 cc_even0 = itv->vbi.cc_data_even[0]; - u8 cc_even1 = itv->vbi.cc_data_even[1]; + while (vi->cc_payload_idx) { + cc = vi->cc_payload[0]; - memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2); - memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2); - itv->vbi.cc_pos -= 2; - if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80) + memcpy(vi->cc_payload, vi->cc_payload + 1, + sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0])); + vi->cc_payload_idx--; + if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80) continue; - /* Send to Saa7127 */ - ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1); - if (itv->vbi.cc_pos == 0) - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + ivtv_set_cc(itv, 3, &cc); break; } } if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { - /* Lock */ - ivtv_set_vps(itv, itv->vbi.vps_found, - itv->vbi.vps[0], itv->vbi.vps[1], - itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]); + ivtv_set_vps(itv, 1); } } diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h index d5740493a690..970567b9194d 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.h +++ b/drivers/media/video/ivtv/ivtv-vbi.h @@ -20,11 +20,11 @@ #ifndef IVTV_VBI_H #define IVTV_VBI_H -ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); +void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t count); void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, u64 pts_stamp, int streamtype); int ivtv_used_line(struct ivtv *itv, int line, int field); -void ivtv_disable_vbi(struct ivtv *itv); +void ivtv_disable_cc(struct ivtv *itv); void ivtv_set_vbi(unsigned long arg); void ivtv_vbi_work_handler(struct ivtv *itv); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 9f986930490f..e35ef321ec71 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -332,11 +332,11 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat if (!enable) return 0; - state->vps_data[0] = data->data[4]; - state->vps_data[1] = data->data[10]; - state->vps_data[2] = data->data[11]; - state->vps_data[3] = data->data[12]; - state->vps_data[4] = data->data[13]; + state->vps_data[0] = data->data[2]; + state->vps_data[1] = data->data[8]; + state->vps_data[2] = data->data[9]; + state->vps_data[3] = data->data[10]; + state->vps_data[4] = data->data[11]; v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n", state->vps_data[0], state->vps_data[1], state->vps_data[2], state->vps_data[3], From effa0b08633122cc63d2b7f098434d359d5767ef Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:09:52 -0300 Subject: [PATCH 0669/2804] V4L/DVB (6117): ivtv: finish VBI related cleanup Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 67 +++++++++++++++---------- drivers/media/video/ivtv/ivtv-streams.c | 10 ---- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 748ef66bd945..5400ccef4dfb 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -499,7 +499,8 @@ struct vbi_vps { }; struct vbi_info { - /* VBI general fixed card data */ + /* VBI general data, does not change during streaming */ + u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */ u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */ @@ -507,27 +508,42 @@ struct vbi_info { u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */ u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */ - u32 dec_start; - u32 enc_start, enc_size; - int fpi; - u32 frame; - struct vbi_cc cc_payload[256]; /* Sliced VBI CC payload array. It is an array to - prevent dropping CC data if they couldn't be - processed fast enough. */ - int cc_payload_idx; /* Index in cc_payload */ - u8 cc_missing_cnt; /* Counts number of frames without CC for passthrough mode */ - int wss_payload; /* Sliced VBI WSS payload */ - u8 wss_missing_cnt; /* Counts number of frames without WSS for passthrough mode */ - struct vbi_vps vps_payload; /* Sliced VBI VPS payload */ - struct v4l2_format in; - /* convenience pointer to sliced struct in vbi_in union */ - struct v4l2_sliced_vbi_format *sliced_in; - int insert_mpeg; + u32 start[2]; /* start of first VBI line in the odd/even fields */ + u32 count; /* number of VBI lines per field */ + u32 raw_size; /* size of raw VBI line from the digitizer */ + u32 sliced_size; /* size of sliced VBI line from the digitizer */ - /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. - One for /dev/vbi0 and one for /dev/vbi8 */ - struct v4l2_sliced_vbi_data sliced_data[36]; - struct v4l2_sliced_vbi_data sliced_dec_data[36]; + u32 dec_start; /* start in decoder memory of VBI re-insertion buffers */ + u32 enc_start; /* start in encoder memory of VBI capture buffers */ + u32 enc_size; /* size of VBI capture area */ + int fpi; /* number of VBI frames per interrupt */ + + struct v4l2_format in; /* current VBI capture format */ + struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */ + int insert_mpeg; /* if non-zero, then embed VBI data in MPEG stream */ + + /* Raw VBI compatibility hack */ + + u32 frame; /* frame counter hack needed for backwards compatibility + of old VBI software */ + + /* Sliced VBI output data */ + + struct vbi_cc cc_payload[256]; /* sliced VBI CC payload array: it is an array to + prevent dropping CC data if they couldn't be + processed fast enough */ + int cc_payload_idx; /* index in cc_payload */ + u8 cc_missing_cnt; /* counts number of frames without CC for passthrough mode */ + int wss_payload; /* sliced VBI WSS payload */ + u8 wss_missing_cnt; /* counts number of frames without WSS for passthrough mode */ + struct vbi_vps vps_payload; /* sliced VBI VPS payload */ + + /* Sliced VBI capture data */ + + struct v4l2_sliced_vbi_data sliced_data[36]; /* sliced VBI storage for VBI encoder stream */ + struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */ + + /* VBI Embedding data */ /* Buffer for VBI data inserted into MPEG stream. The first byte is a dummy byte that's never used. @@ -544,12 +560,9 @@ struct vbi_info { This pointer array will allocate 2049 bytes to store each VBI frame. */ u8 *sliced_mpeg_data[IVTV_VBI_FRAMES]; u32 sliced_mpeg_size[IVTV_VBI_FRAMES]; - struct ivtv_buffer sliced_mpeg_buf; - u32 inserted_frame; - - u32 start[2], count; - u32 raw_size; - u32 sliced_size; + struct ivtv_buffer sliced_mpeg_buf; /* temporary buffer holding data from sliced_mpeg_data */ + u32 inserted_frame; /* index in sliced_mpeg_size of next sliced data + to be inserted in the MPEG stream */ }; /* forward declaration of struct defined in ivtv-cards.h */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index a3296224f821..fd135985e70f 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -321,16 +321,6 @@ static void ivtv_vbi_setup(struct ivtv *itv) /* Reset VBI */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); - if (itv->is_60hz) { - itv->vbi.count = 12; - itv->vbi.start[0] = 10; - itv->vbi.start[1] = 273; - } else { /* PAL/SECAM */ - itv->vbi.count = 18; - itv->vbi.start[0] = 6; - itv->vbi.start[1] = 318; - } - /* setup VBI registers */ itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); From 66cfaeff95d20d1377b4fa3d2c6aa7c29d832941 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 05:45:48 -0300 Subject: [PATCH 0670/2804] V4L/DVB (6118): ivtv-fb: add missing FBIO_WAITFORVSYNC ioctl define Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 3 +-- include/media/ivtv-fb.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index ffe6478682ae..d2b1f5d5c8b2 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include @@ -59,7 +59,6 @@ #include "ivtv-driver.h" #include "ivtv-udma.h" #include "ivtv-mailbox.h" -#include /* card parameters */ static int ivtv_fb_card_id = -1; diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h index 3b746f5e3c9e..d3a797b17280 100644 --- a/include/media/ivtv-fb.h +++ b/include/media/ivtv-fb.h @@ -29,6 +29,7 @@ struct ivtvfb_dma_frame { int count; }; -#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif From 0f45b8c57e40cca1778b0b75daab65ca139e5bb9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:04:10 -0300 Subject: [PATCH 0671/2804] V4L/DVB (6119): ivtvfb: renamed ivtv-fb to ivtvfb, move header to include/linux The convention for framebuffer devices is to call them xxxfb, not xxx-fb. Conform to this. Also move the ivtvfb.h header to include/linux: it is a public header. The FBIO_WAITFORVSYNC ioctl is now also defined in the ivtvfb.h header, no more need to include matroxfb.h for just this ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 2 +- drivers/media/video/ivtv/Makefile | 2 +- drivers/media/video/ivtv/{ivtv-fb.c => ivtvfb.c} | 11 +---------- include/{media/ivtv-fb.h => linux/ivtvfb.h} | 15 +++++++++++---- 4 files changed, 14 insertions(+), 16 deletions(-) rename drivers/media/video/ivtv/{ivtv-fb.c => ivtvfb.c} (99%) rename include/{media/ivtv-fb.h => linux/ivtvfb.h} (74%) diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 5efacb332114..7f20c166d59f 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -27,7 +27,7 @@ config VIDEO_IVTV To compile this driver as a module, choose M here: the module will be called ivtv. -config VIDEO_IVTV_FB +config VIDEO_FB_IVTV tristate "Conexant cx23415 framebuffer support" depends on VIDEO_IVTV && FB && EXPERIMENTAL select FB_CFB_FILLRECT diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 6998781e2b11..e8eefd96d897 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -5,4 +5,4 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ ivtv-vbi.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o -obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o +obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtvfb.c similarity index 99% rename from drivers/media/video/ivtv/ivtv-fb.c rename to drivers/media/video/ivtv/ivtvfb.c index d2b1f5d5c8b2..ff721c088479 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -40,17 +40,8 @@ #include #include -#include -#include -#include #include -#include -#include -#include -#include - -#include -#include +#include #ifdef CONFIG_MTRR #include diff --git a/include/media/ivtv-fb.h b/include/linux/ivtvfb.h similarity index 74% rename from include/media/ivtv-fb.h rename to include/linux/ivtvfb.h index d3a797b17280..e980ba62ddcc 100644 --- a/include/media/ivtv-fb.h +++ b/include/linux/ivtvfb.h @@ -1,7 +1,7 @@ /* On Screen Display cx23415 Framebuffer driver - Copyright (C) 2006 Ian Armstrong + Copyright (C) 2006, 2007 Ian Armstrong 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 @@ -18,8 +18,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _LINUX_IVTV_FB_H -#define _LINUX_IVTV_FB_H +#ifndef __LINUX_IVTVFB_H__ +#define __LINUX_IVTVFB_H__ + +#ifdef __KERNEL__ +#include /* need __user */ +#else +#define __user +#endif +#include /* Framebuffer external API */ @@ -29,7 +36,7 @@ struct ivtvfb_dma_frame { int count; }; -#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define IVTVFB_IOC_DMA_FRAME _IOW('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) #define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif From 7b3a0d49e3e929b810ade38926342faca53e867d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:11:07 -0300 Subject: [PATCH 0672/2804] V4L/DVB (6120): ivtvfb: rename some missed ivtv-fb references to ivtvfb Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 2 +- drivers/media/video/ivtv/ivtv-driver.c | 2 +- drivers/media/video/ivtv/ivtv-driver.h | 2 +- drivers/media/video/ivtv/ivtvfb.c | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 7f20c166d59f..854cc9c30ca9 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -41,4 +41,4 @@ config VIDEO_FB_IVTV homepage at . To compile this driver as a module, choose M here: the - module will be called ivtv-fb. + module will be called ivtvfb. diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 2a5e0facca7d..511a66252413 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1397,7 +1397,7 @@ static void module_cleanup(void) spin_unlock(&ivtv_cards_lock); } -/* Note: These symbols are exported because they are used by the ivtv-fb +/* Note: These symbols are exported because they are used by the ivtvfb framebuffer module and an infrared module for the IR-blaster. */ EXPORT_SYMBOL(ivtv_set_irq_mask); EXPORT_SYMBOL(ivtv_cards_active); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 5400ccef4dfb..32dfc7a859fa 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -695,7 +695,7 @@ struct ivtv { u32 osd_chroma_key; /* current chroma key */ struct v4l2_rect osd_rect; /* current OSD position and size */ struct v4l2_rect main_rect; /* current Main window position and size */ - struct osd_info *osd_info; /* ivtv-fb private OSD info */ + struct osd_info *osd_info; /* ivtvfb private OSD info */ }; /* Globals */ diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index ff721c088479..c8ca7cbbe38b 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -128,15 +128,15 @@ MODULE_LICENSE("GPL"); #define IVTV_FB_DEBUG(x, type, fmt, args...) \ do { \ if ((x) & ivtv_fb_debug) \ - printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \ } while (0) #define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) #define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) /* Standard kernel messages */ -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) /* --------------------------------------------------------------------- */ @@ -1143,7 +1143,7 @@ static int __init ivtvfb_init(void) int i, registered = 0; if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + printk(KERN_ERR "ivtvfb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", IVTV_MAX_CARDS - 1); return -EINVAL; } @@ -1161,7 +1161,7 @@ static int __init ivtvfb_init(void) } } if (!registered) { - printk(KERN_ERR "ivtv-fb: no cards found"); + printk(KERN_ERR "ivtvfb: no cards found"); return -ENODEV; } return 0; @@ -1172,7 +1172,7 @@ static void ivtvfb_cleanup(void) struct ivtv *itv; int i; - printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n"); for (i = 0; i < ivtv_cards_active; i++) { itv = ivtv_cards[i]; From 641ed49db6ecf6c539a5eab50a7540542377add1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 28 Aug 2007 03:24:31 -0300 Subject: [PATCH 0673/2804] V4L/DVB (6121): ivtvfb: replace ivtv_fb prefix to ivtvfb ivtvfb: replace ivtv_fb prefix to ivtvfb, change warning to info message Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtvfb.c | 168 +++++++++++++++--------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index c8ca7cbbe38b..73e46f94b45a 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -52,8 +52,8 @@ #include "ivtv-mailbox.h" /* card parameters */ -static int ivtv_fb_card_id = -1; -static int ivtv_fb_debug = 0; +static int ivtvfb_card_id = -1; +static int ivtvfb_debug = 0; static int osd_laced; static int osd_compat; static int osd_depth; @@ -62,8 +62,8 @@ static int osd_left; static int osd_yres; static int osd_xres; -module_param(ivtv_fb_card_id, int, 0444); -module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(ivtvfb_card_id, int, 0444); +module_param_named(debug,ivtvfb_debug, int, 0644); module_param(osd_laced, bool, 0444); module_param(osd_compat, bool, 0444); module_param(osd_depth, int, 0444); @@ -72,7 +72,7 @@ module_param(osd_left, int, 0444); module_param(osd_yres, int, 0444); module_param(osd_xres, int, 0444); -MODULE_PARM_DESC(ivtv_fb_card_id, +MODULE_PARM_DESC(ivtvfb_card_id, "Only use framebuffer of the specified ivtv card (0-31)\n" "\t\t\tdefault -1: initialize all available framebuffers"); @@ -122,21 +122,21 @@ MODULE_LICENSE("GPL"); /* --------------------------------------------------------------------- */ -#define IVTV_FB_DBGFLG_WARN (1 << 0) -#define IVTV_FB_DBGFLG_INFO (1 << 1) +#define IVTVFB_DBGFLG_WARN (1 << 0) +#define IVTVFB_DBGFLG_INFO (1 << 1) -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ +#define IVTVFB_DEBUG(x, type, fmt, args...) \ do { \ - if ((x) & ivtv_fb_debug) \ + if ((x) & ivtvfb_debug) \ printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) +#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args) /* Standard kernel messages */ -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) /* --------------------------------------------------------------------- */ @@ -201,7 +201,7 @@ struct ivtv_osd_coords { /* ivtv API calls for framebuffer related support */ -static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, +static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase, u32 *fblength) { u32 data[CX2341X_MBOX_MAX_DATA]; @@ -213,7 +213,7 @@ static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, return rc; } -static int ivtv_fb_get_osd_coords(struct ivtv *itv, +static int ivtvfb_get_osd_coords(struct ivtv *itv, struct ivtv_osd_coords *osd) { struct osd_info *oi = itv->osd_info; @@ -230,7 +230,7 @@ static int ivtv_fb_get_osd_coords(struct ivtv *itv, return 0; } -static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) { struct osd_info *oi = itv->osd_info; @@ -245,7 +245,7 @@ static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords osd->lines, osd->x, osd->y); } -static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) { int osd_height_limit = itv->is_50hz ? 576 : 480; @@ -255,13 +255,13 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w /* Ensure we don't exceed display limits */ if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", + IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", ivtv_window->top, ivtv_window->height); ivtv_window->top = osd_height_limit - ivtv_window->height; } if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", + IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", ivtv_window->left, ivtv_window->width); ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; } @@ -281,7 +281,7 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w return 0; } -static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, +static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv, unsigned long ivtv_dest_addr, void __user *userbuf, int size_in_bytes) { @@ -293,7 +293,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, /* Map User DMA */ if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { mutex_unlock(&itv->udma.lock); - IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, " "Error with get_user_pages: %d bytes, %d pages returned\n", size_in_bytes, itv->udma.page_count); @@ -301,7 +301,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return -EIO; } - IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", size_in_bytes, itv->udma.page_count); ivtv_udma_prepare(itv); @@ -330,7 +330,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return ret; } -static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, +static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) { DEFINE_WAIT(wait); @@ -338,34 +338,34 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, /* Nothing to do */ if (count == 0) { - IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n"); return -EINVAL; } /* Check Total FB Size */ if ((dest_offset + count) > oi->video_buffer_size) { - IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", dest_offset + count, oi->video_buffer_size); return -E2BIG; } /* Not fatal, but will have undesirable results */ if ((unsigned long)source & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", (unsigned long)source); if (dest_offset & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); + IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); if (count & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); + IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count); /* Check Source */ if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", + IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", (unsigned long)source); - IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", dest_offset, (unsigned long)source, count); return -EINVAL; @@ -375,7 +375,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; /* Fill Buffers */ - return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); + return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count); } static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) @@ -412,15 +412,15 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar case IVTVFB_IOC_DMA_FRAME: { struct ivtvfb_dma_frame args; - IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); + IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); if (copy_from_user(&args, (void __user *)arg, sizeof(args))) return -EFAULT; - return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); } default: - IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); + IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); return -EINVAL; } return 0; @@ -435,7 +435,7 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) struct v4l2_rect ivtv_window; int osd_mode = -1; - IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_set_var\n"); /* Select color space */ if (var->nonstd) /* YUV */ @@ -463,11 +463,11 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) osd_mode = IVTV_OSD_BPP_16_565; break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } /* Change osd mode if needed. @@ -491,18 +491,18 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); } /* Read the current osd info */ - ivtv_fb_get_osd_coords(itv, &ivtv_osd); + ivtvfb_get_osd_coords(itv, &ivtv_osd); /* Now set the OSD to the size we want */ ivtv_osd.pixel_stride = var->xres_virtual; ivtv_osd.lines = var->yres_virtual; ivtv_osd.x = 0; ivtv_osd.y = 0; - ivtv_fb_set_osd_coords(itv, &ivtv_osd); + ivtvfb_set_osd_coords(itv, &ivtv_osd); /* Can't seem to find the right API combo for this. Use another function which does what we need through direct register access. */ @@ -515,22 +515,22 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_window.top = var->upper_margin - 1; ivtv_window.left = var->left_margin - 1; - ivtv_fb_set_display_window(itv, &ivtv_window); + ivtvfb_set_display_window(itv, &ivtv_window); /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + IVTVFB_DEBUG_INFO("Display position: %d, %d\n", var->left_margin, var->upper_margin); - IVTV_FB_DEBUG_INFO("Display filter: %s\n", + IVTVFB_DEBUG_INFO("Display filter: %s\n", (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } @@ -539,7 +539,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) { struct osd_info *oi = itv->osd_info; - IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); + IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "cx23415 TV out"); fix->smem_start = oi->video_pbase; @@ -563,7 +563,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) int osd_height_limit; u32 pixclock, hlimit, vlimit; - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); /* Set base references for mode calcs. */ if (itv->is_50hz) { @@ -582,7 +582,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } } @@ -633,7 +633,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } } else { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } @@ -643,14 +643,14 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->yres != oi->ivtvfb_defined.yres || var->xres_virtual != oi->ivtvfb_defined.xres_virtual || var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", + IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual); return -EINVAL; } } else { if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", + IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n", var->xres, var->yres); return -EINVAL; } @@ -660,7 +660,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || var->xres_virtual < var->xres || var->yres_virtual < var->yres) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", + IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", var->xres_virtual, var->yres_virtual); return -EINVAL; } @@ -670,43 +670,43 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) if (var->bits_per_pixel == 8) { /* Width must be a multiple of 4 */ if (var->xres & 3) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); + IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 3) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); return -EINVAL; } } else if (var->bits_per_pixel == 16) { /* Width must be a multiple of 2 */ if (var->xres & 1) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); + IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 1) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); return -EINVAL; } } /* Now check the offsets */ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); return -EINVAL; } /* Check pixel format */ if (var->nonstd > 1) { - IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); + IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); return -EINVAL; } /* Check video mode */ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); + IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); return -EINVAL; } @@ -737,24 +737,24 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) else var->pixclock = pixclock; - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + IVTVFB_DEBUG_INFO("Display position: %d, %d\n", var->left_margin, var->upper_margin); - IVTV_FB_DEBUG_INFO("Display filter: %s\n", + IVTVFB_DEBUG_INFO("Display filter: %s\n", (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); return _ivtvfb_check_var(var, itv); } @@ -779,7 +779,7 @@ static int ivtvfb_set_par(struct fb_info *info) int rc = 0; struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); + IVTVFB_DEBUG_INFO("ivtvfb_set_par\n"); rc = ivtvfb_set_var(itv, &info->var); ivtvfb_pan_display(&info->var, info); @@ -836,7 +836,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) { struct ivtv *itv = (struct ivtv *)info->par; - IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); + IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); switch (blank_mode) { case FB_BLANK_UNBLANK: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); @@ -902,7 +902,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check horizontal start (osd_left). */ if (osd_left && osd_left + start_window.width > 721) { - IVTV_FB_ERR("Invalid osd_left - assuming default\n"); + IVTVFB_ERR("Invalid osd_left - assuming default\n"); osd_left = 0; } @@ -928,7 +928,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check vertical start (osd_upper). */ if (osd_upper + start_window.height > max_height + 1) { - IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); + IVTVFB_ERR("Invalid osd_upper - assuming default\n"); osd_upper = 0; } @@ -980,7 +980,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Allocate color map */ if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { - IVTV_FB_ERR("abort, unable to alloc cmap\n"); + IVTVFB_ERR("abort, unable to alloc cmap\n"); return -ENOMEM; } @@ -988,7 +988,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); if (!oi->ivtvfb_info.pseudo_palette) { - IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); + IVTVFB_ERR("abort, unable to alloc pseudo pallete\n"); return -ENOMEM; } @@ -1004,12 +1004,12 @@ static int ivtvfb_init_io(struct ivtv *itv) mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { mutex_unlock(&itv->serialize_lock); - IVTV_FB_ERR("Failed to initialize ivtv\n"); + IVTVFB_ERR("Failed to initialize ivtv\n"); return -ENXIO; } mutex_unlock(&itv->serialize_lock); - ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); + ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer @@ -1020,12 +1020,12 @@ static int ivtvfb_init_io(struct ivtv *itv) oi->video_vbase = itv->dec_mem + oi->video_rbase; if (!oi->video_vbase) { - IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", oi->video_buffer_size, oi->video_pbase); return -EIO; } - IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", oi->video_pbase, oi->video_vbase, oi->video_buffer_size / 1024); @@ -1045,7 +1045,7 @@ static int ivtvfb_init_io(struct ivtv *itv) if (mtrr_add(oi->fb_start_aligned_physaddr, oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, MTRR_TYPE_WRCOMB, 1) < 0) { - IVTV_FB_WARN("cannot use mttr\n"); + IVTVFB_INFO("disabled mttr\n"); oi->fb_start_aligned_physaddr = 0; oi->fb_end_aligned_physaddr = 0; } @@ -1089,13 +1089,13 @@ static int ivtvfb_init_card(struct ivtv *itv) int rc; if (itv->osd_info) { - IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id); return -EBUSY; } itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); if (itv->osd_info == 0) { - IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + IVTVFB_ERR("Failed to allocate memory for osd_info\n"); return -ENOMEM; } @@ -1129,7 +1129,7 @@ static int ivtvfb_init_card(struct ivtv *itv) /* Note if we're running in compatibility mode */ if (osd_compat) - IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + IVTVFB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); /* Allocate DMA */ ivtv_udma_alloc(itv); @@ -1142,20 +1142,20 @@ static int __init ivtvfb_init(void) struct ivtv *itv; int i, registered = 0; - if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtvfb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n", IVTV_MAX_CARDS - 1); return -EINVAL; } /* Locate & initialise all cards supporting an OSD. */ for (i = 0; i < ivtv_cards_active; i++) { - if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + if (ivtvfb_card_id != -1 && i != ivtvfb_card_id) continue; itv = ivtv_cards[i]; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { if (ivtvfb_init_card(itv) == 0) { - IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i); registered++; } } @@ -1177,7 +1177,7 @@ static void ivtvfb_cleanup(void) for (i = 0; i < ivtv_cards_active; i++) { itv = ivtv_cards[i]; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { - IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i); ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); unregister_framebuffer(&itv->osd_info->ivtvfb_info); ivtvfb_release_buffers(itv); From 136280322d894e6ec07187f2427b00c3d64ad066 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 28 Aug 2007 03:28:04 -0300 Subject: [PATCH 0674/2804] V4L/DVB (6122): ivtvfb: fix an obvious bug in ivtvfb_release_buffers() Signed-off-by: Adrian Bunk Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtvfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 73e46f94b45a..9684048fe56c 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -1064,8 +1064,8 @@ static void ivtvfb_release_buffers (struct ivtv *itv) struct osd_info *oi = itv->osd_info; /* Release cmap */ - if (oi->ivtvfb_info.cmap.len); - fb_dealloc_cmap(&oi->ivtvfb_info.cmap); + if (oi->ivtvfb_info.cmap.len) + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); /* Release pseudo palette */ if (oi->ivtvfb_info.pseudo_palette) From 51b39dfa5477fdb2459e3c46f855f01b8b03102d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:13:04 -0300 Subject: [PATCH 0675/2804] V4L/DVB (6123): ivtv: move ivtv.h public header to include/linux Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 2 +- include/{media => linux}/ivtv.h | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) rename include/{media => linux}/ivtv.h (93%) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 32dfc7a859fa..3bda1df63cb6 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -62,7 +62,7 @@ #include #include -#include +#include /* Memory layout */ diff --git a/include/media/ivtv.h b/include/linux/ivtv.h similarity index 93% rename from include/media/ivtv.h rename to include/linux/ivtv.h index 412b48ea8eda..794b8daa9378 100644 --- a/include/media/ivtv.h +++ b/include/linux/ivtv.h @@ -18,8 +18,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _LINUX_IVTV_H -#define _LINUX_IVTV_H +#ifndef __LINUX_IVTV_H__ +#define __LINUX_IVTV_H__ + +#ifdef __KERNEL__ +#include /* need __user */ +#else +#define __user +#endif +#include /* ivtv knows several distinct output modes: MPEG streaming, YUV streaming, YUV updates through user DMA and the passthrough From 38051450b378ef2cb51dff76a6b8299f59129172 Mon Sep 17 00:00:00 2001 From: Tyler Trafford Date: Tue, 28 Aug 2007 17:56:47 -0300 Subject: [PATCH 0676/2804] V4L/DVB (6124): cx25840: add a few 10 microsecond delays There were a couple of places in the cx25840 initialization where the datasheet called for a 10 microsecond delay, which we ignored because of the 10 usec I2C delay. Put them in anyway now that the I2C delay was decreased to 5 usec. Signed-off-by: Tyler Trafford Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index d6f8b3b6af40..90f7859bb48e 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -133,7 +133,9 @@ static void init_dll1(struct i2c_client *client) cx25840_write(client, 0x159, 0x23); cx25840_write(client, 0x15a, 0x87); cx25840_write(client, 0x15b, 0x06); + udelay(10); cx25840_write(client, 0x159, 0xe1); + udelay(10); cx25840_write(client, 0x15a, 0x86); cx25840_write(client, 0x159, 0xe0); cx25840_write(client, 0x159, 0xe1); @@ -147,6 +149,7 @@ static void init_dll2(struct i2c_client *client) cx25840_write(client, 0x15d, 0xe3); cx25840_write(client, 0x15e, 0x86); cx25840_write(client, 0x15f, 0x06); + udelay(10); cx25840_write(client, 0x15d, 0xe1); cx25840_write(client, 0x15d, 0xe0); cx25840_write(client, 0x15d, 0xe1); @@ -165,9 +168,7 @@ static void cx25836_initialize(struct i2c_client *client) /* 3c. */ cx25840_and_or(client, 0x159, ~0x02, 0x02); /* 3d. */ - /* There should be a 10-us delay here, but since the - i2c bus already has a 10-us delay we don't need to do - anything */ + udelay(10); /* 3e. */ cx25840_and_or(client, 0x159, ~0x02, 0x00); /* 3f. */ From b930e1d851c3ffbf82127bd0e4d72ffe94d4b7f2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 18:16:54 -0300 Subject: [PATCH 0677/2804] V4L/DVB (6125): whitespace cleanup: replace leading spaces with tabs There were many instances of 7-space indents spread throughout the v4l-dvb tree. This patch replaces the 7-space indents with tabs. The whitespace cleaner script doesn't catch these, because it assumes that all indents are 8-space. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/cinergyT2/cinergyT2.c | 6 +- drivers/media/dvb/ttpci/av7110_hw.c | 28 +++++----- drivers/media/radio/radio-terratec.c | 2 +- drivers/media/video/bt8xx/bttv-cards.c | 20 +++---- drivers/media/video/cx88/cx88-blackbird.c | 4 +- drivers/media/video/cx88/cx88-mpeg.c | 64 +++++++++++----------- drivers/media/video/cx88/cx88-tvaudio.c | 6 +- drivers/media/video/msp3400-driver.c | 10 ++-- drivers/media/video/planb.c | 30 +++++----- drivers/media/video/pwc/pwc-ctrl.c | 2 +- drivers/media/video/pwc/pwc-if.c | 4 +- drivers/media/video/saa7134/saa7134-alsa.c | 2 +- 12 files changed, 89 insertions(+), 89 deletions(-) diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index b910fa0baa07..5a12b5679556 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -548,19 +548,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; - unsigned int mask = 0; + unsigned int mask = 0; if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; poll_wait(file, &cinergyt2->poll_wq, wait); - if (cinergyt2->pending_fe_events != 0) + if (cinergyt2->pending_fe_events != 0) mask |= (POLLIN | POLLRDNORM | POLLPRI); mutex_unlock(&cinergyt2->sem); - return mask; + return mask; } diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 515e8232e020..a468aa2e4854 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -978,24 +978,24 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) { - int i; - int length = last - first + 1; + int i; + int length = last - first + 1; - if (length * 4 > DATA_BUFF3_SIZE) - return -EINVAL; + if (length * 4 > DATA_BUFF3_SIZE) + return -EINVAL; - for (i = 0; i < length; i++) { - u32 color, blend, yuv; + for (i = 0; i < length; i++) { + u32 color, blend, yuv; - if (get_user(color, colors + i)) - return -EFAULT; - blend = (color & 0xF0000000) >> 4; - yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, + if (get_user(color, colors + i)) + return -EFAULT; + blend = (color & 0xF0000000) >> 4; + yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF) | blend : 0; - yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); - wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); - } - return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, + yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); + wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); + } + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], first, last); diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 7e1911c3d54e..535ffe8c8102 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -173,7 +173,7 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1) i--; p--; temp = temp/2; - } + } spin_lock(&lock); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 1f4f2625395e..900d18e14060 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -3275,15 +3275,15 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input) btaor((2)<<5, ~(3<<5), BT848_IFORM); gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]); - /* composite */ - /* set chroma ADC to sleep */ - btor(BT848_ADC_C_SLEEP, BT848_ADC); - /* set to composite video */ - btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); - btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); + /* composite */ + /* set chroma ADC to sleep */ + btor(BT848_ADC_C_SLEEP, BT848_ADC); + /* set to composite video */ + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); - /* switch sync drive off */ - gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); + /* switch sync drive off */ + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); } static void gvc1100_muxsel(struct bttv *btv, unsigned int input) @@ -3452,7 +3452,7 @@ void __devinit bttv_init_card2(struct bttv *btv) printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr); } break; - case BTTV_BOARD_STB2: + case BTTV_BOARD_STB2: if (btv->cardid == 0x3060121a) { /* Fix up entry for 3DFX VoodooTV 100, which is an OEM STB card variant. */ @@ -3783,7 +3783,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) for (i = 12; i < 21; i++) serial *= 10, serial += ee[i] - '0'; } - } else { + } else { unsigned short type; for (i = 4*16; i < 8*16; i += 16) { diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 47007380a98a..fcaf4f51293f 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1077,7 +1077,7 @@ static int mpeg_open(struct inode *inode, struct file *file) struct cx8802_driver *drv = NULL; int err; - dev = cx8802_get_device(inode); + dev = cx8802_get_device(inode); dprintk( 1, "%s\n", __FUNCTION__); @@ -1234,7 +1234,7 @@ static struct video_device cx8802_mpeg_template = .vidioc_s_tuner = vidioc_s_tuner, .vidioc_s_std = vidioc_s_std, .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 4e6a84f15d17..d302793fcfb9 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -179,43 +179,43 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, struct cx88_buffer *buf; struct list_head *item; - dprintk( 1, "cx8802_restart_queue\n" ); + dprintk( 1, "cx8802_restart_queue\n" ); if (list_empty(&q->active)) { - struct cx88_buffer *prev; - prev = NULL; + struct cx88_buffer *prev; + prev = NULL; - dprintk(1, "cx8802_restart_queue: queue is empty\n" ); + dprintk(1, "cx8802_restart_queue: queue is empty\n" ); - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); - if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - cx8802_start_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(1,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + cx8802_start_dma(dev, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(1,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); - } else { - return 0; - } - prev = buf; - } + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(1,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } return 0; } diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 82364fb07025..76e5c78d8ae4 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -798,9 +798,9 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) core->astat = reg; /* TODO - Reading from AUD_STATUS is not enough - for auto-detecting sap/dual-fm/nicam. - Add some code here later. + Reading from AUD_STATUS is not enough + for auto-detecting sap/dual-fm/nicam. + Add some code here later. */ return; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index e9d400e19a5d..c0c87e06259b 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -244,17 +244,17 @@ int msp_write_dsp(struct i2c_client *client, int addr, int val) * ----------------------------------------------------------------------- */ static int scarts[3][9] = { - /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ + /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ /* SCART DSP Input select */ - { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, + { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, /* SCART1 Output select */ - { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, + { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, /* SCART2 Output select */ - { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, + { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, }; static char *scart_names[] = { - "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" + "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" }; void msp_set_scart(struct i2c_client *client, int in, int out) diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index 4ab1af74a970..0ef73d9d5848 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c @@ -844,21 +844,21 @@ cmd_tab_mask_end: /*********************************/ static int palette2fmt[] = { - 0, - PLANB_GRAY, - 0, - 0, - 0, - PLANB_COLOUR32, - PLANB_COLOUR15, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + 0, + PLANB_GRAY, + 0, + 0, + 0, + PLANB_COLOUR32, + PLANB_COLOUR15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, }; #define PLANB_PALETTE_MAX 15 diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 338ced7188f2..ea53316d2111 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -1648,7 +1648,7 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) ARG_OUT(cmd) break; } - /* + /* case VIDIOCPWCGVIDTABLE: { ARG_DEF(struct pwc_table_init_buffer, table); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index d3ac70a0d9ca..1088ebf5744f 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -126,9 +126,9 @@ static struct usb_driver pwc_driver = { static int default_size = PSZ_QCIF; static int default_fps = 10; static int default_fbufs = 3; /* Default number of frame buffers */ - int pwc_mbufs = 2; /* Default number of mmap() buffers */ + int pwc_mbufs = 2; /* Default number of mmap() buffers */ #ifdef CONFIG_USB_PWC_DEBUG - int pwc_trace = PWC_DEBUG_LEVEL; + int pwc_trace = PWC_DEBUG_LEVEL; #endif static int power_save = 0; static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index eb5e77dd0d18..c6f7279669c1 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -312,7 +312,7 @@ static int dsp_buffer_free(struct saa7134_dev *dev) dev->dmasound.blksize = 0; dev->dmasound.bufsize = 0; - return 0; + return 0; } From 293197cd0f34eb6bfb5492a63a878575b69e9df4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 28 Aug 2007 17:20:42 -0300 Subject: [PATCH 0678/2804] V4L/DVB (6126): tuner: add warning for obsolete i2c address range 0x64 thru 0x6f The tuner module has a rather aggressive range of possible i2c addresses. As per the specs available, it appears as if there are no 4-byte tuners that actually use i2c addresses in the range 0x64 thru 0x6f, yet, tuner-core claims the address range 0x60 thru 0x6f. Allowing tuner.ko to probe these addresses can cause potential damage to certain IR receivers, RTC chips or any other IC's that might otherwise reside on the i2c bus using one of these addresses. The plan is to remove these i2c addresses from the i2c address range of the tuner module. If any devices are discovered that actually do have tuners at one of these addresses, the newer i2c probing methods will be used to handle those cases. In order to collect this information and avoid any potential regressions, the following warning has been added upon successful detection of a tuner using an i2c address in the range 0x64 thru 0x6f: ====================== WARNING! ====================== Support for tuners in i2c address range 0x64 thru 0x6f will soon be dropped. This message indicates that your hardware has a {tuner name} tuner at i2c address {addr}. To ensure continued support for your device, please send a copy of this message, along with full dmesg output to v4l-dvb-maintainer@linuxtv.org Please use subject line: "obsolete tuner i2c address." ====================== WARNING! ====================== Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index baeae28f2836..f505f43bb126 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -145,6 +145,27 @@ static void set_freq(struct i2c_client *c, unsigned long freq) } } +static void tuner_i2c_address_check(struct tuner *t) +{ + if ((t->type == UNSET || t->type == TUNER_ABSENT) || + ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) + return; + + tuner_warn("====================== WARNING! ======================\n"); + tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); + tuner_warn("will soon be dropped. This message indicates that your\n"); + tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", + t->i2c.name, t->i2c.addr); + tuner_warn("To ensure continued support for your device, please\n"); + tuner_warn("send a copy of this message, along with full dmesg\n"); + tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); + tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); + tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", + t->i2c.adapter->name, t->i2c.addr, t->type, + tuners[t->type].name); + tuner_warn("====================== WARNING! ======================\n"); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -244,6 +265,7 @@ static void set_type(struct i2c_client *c, unsigned int type, tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", c->adapter->name, c->driver->driver.name, c->addr << 1, type, t->mode_mask); + tuner_i2c_address_check(t); } /* From db8a695658cda21eacfa2a5e3b15e8964bfb93ef Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:24:42 -0300 Subject: [PATCH 0679/2804] V4L/DVB (6127): tuner: kill i2c_client interface to tuner sub-drivers To ease the conversion of the analog tuner sub-drivers into dvb_frontend style tuner modules, we must remove the i2c_client interface. dvb_frontend style tuner modules use i2c_transfer directly on the i2c_adapter. This change only alters the interface between tuner.ko and the tuner sub-drivers. The v4l2 / i2c_client interface to tuner.ko remains intact. This patch adds inline functions tuner_i2c_xfer_send, and tuner_i2c_xfer_recv, to replace i2c_master_send and i2c_master_recv inside the tuner sub-drivers. Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 138 ++++++++-------- drivers/media/video/tda8290.c | 247 +++++++++++++++-------------- drivers/media/video/tda9887.c | 39 ++--- drivers/media/video/tea5761.c | 55 ++++--- drivers/media/video/tea5767.c | 61 ++++--- drivers/media/video/tuner-core.c | 55 ++++--- drivers/media/video/tuner-driver.h | 37 +++-- drivers/media/video/tuner-i2c.h | 70 ++++++++ drivers/media/video/tuner-simple.c | 57 ++++--- 9 files changed, 430 insertions(+), 329 deletions(-) create mode 100644 drivers/media/video/tuner-i2c.h diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index bd495c12d29f..41bc91817a16 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -37,23 +37,22 @@ static char *microtune_part[] = { }; struct microtune_priv { + struct tuner_i2c_props i2c_props; + unsigned int xogc; unsigned int radio_if2; }; -static void microtune_release(struct i2c_client *c) +static void microtune_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } // IsSpurInBand()? -static int mt2032_spurcheck(struct i2c_client *c, +static int mt2032_spurcheck(struct tuner *t, int f1, int f2, int spectrum_from,int spectrum_to) { - struct tuner *t = i2c_get_clientdata(c); int n1=1,n2,f; f1=f1/1000; //scale to kHz to avoid 32bit overflows @@ -81,7 +80,7 @@ static int mt2032_spurcheck(struct i2c_client *c, return 1; } -static int mt2032_compute_freq(struct i2c_client *c, +static int mt2032_compute_freq(struct tuner *t, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int spectrum_from, @@ -90,7 +89,6 @@ static int mt2032_compute_freq(struct i2c_client *c, int *ret_sel, unsigned int xogc) //all in Hz { - struct tuner *t = i2c_get_clientdata(c); unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; @@ -140,7 +138,7 @@ static int mt2032_compute_freq(struct i2c_client *c, return(-1); } - mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to); + mt2032_spurcheck(t, lo1freq, desired_lo2, spectrum_from, spectrum_to); // should recalculate lo1 (one step up/down) // set up MT2032 register map for transfer over i2c @@ -164,16 +162,16 @@ static int mt2032_compute_freq(struct i2c_client *c, return 0; } -static int mt2032_check_lo_lock(struct i2c_client *c) +static int mt2032_check_lo_lock(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; int try,lock=0; unsigned char buf[2]; for(try=0;try<10;try++) { buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); lock=buf[0] &0x06; @@ -186,15 +184,15 @@ static int mt2032_check_lo_lock(struct i2c_client *c) return lock; } -static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) +static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int tad1; buf[0]=0x0f; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); tad1=buf[0]&0x07; @@ -217,58 +215,57 @@ static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) buf[0]=0x0f; buf[1]=sel; - i2c_master_send(c,buf,2); - lock=mt2032_check_lo_lock(c); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + lock=mt2032_check_lo_lock(t); return lock; } -static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, +static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int from, unsigned int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", rfin,if1,if2,from,to); buf[0]=0; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); buf[0]=0; - ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); + ret=mt2032_compute_freq(t,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); if (ret<0) return; // send only the relevant registers per Rev. 1.2 buf[0]=0; - ret=i2c_master_send(c,buf,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); buf[5]=5; - ret=i2c_master_send(c,buf+5,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); buf[11]=11; - ret=i2c_master_send(c,buf+11,3); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); if(ret!=3) tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); // wait for PLLs to lock (per manual), retry LINT if not. for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(c); + lock=mt2032_check_lo_lock(t); if(optimize_vco) - lock=mt2032_optimize_vco(c,sel,lock); + lock=mt2032_optimize_vco(t,sel,lock); if(lock==6) break; tuner_dbg("mt2032: re-init PLLs by LINT\n"); buf[0]=7; buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs - i2c_master_send(c,buf,2); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); mdelay(10); buf[1]=8+priv->xogc; - i2c_master_send(c,buf,2); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); } if (lock!=6) @@ -276,15 +273,14 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, buf[0]=2; buf[1]=0x20; // LOGC for optimal phase noise - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } -static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); int if2,from,to; // signal bandwidth and picture carrier @@ -300,18 +296,17 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) if2 = 38900*1000; } - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, + mt2032_set_if_freq(t, freq*62500 /* freq*1000*1000/16 */, 1090*1000*1000, if2, from, to); } -static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void mt2032_set_radio_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; int if2 = priv->radio_if2; // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(c, freq * 1000 / 16, + mt2032_set_if_freq(t, freq * 1000 / 16, 1085*1000*1000,if2,if2,if2); } @@ -322,9 +317,8 @@ static struct tuner_operations mt2032_tuner_ops = { }; // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct i2c_client *c) +static int mt2032_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; unsigned char buf[21]; int ret,xogc,xok=0; @@ -334,7 +328,7 @@ static int mt2032_init(struct i2c_client *c) buf[2]=0xff; buf[3]=0x0f; buf[4]=0x1f; - ret=i2c_master_send(c,buf+1,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); buf[5]=6; // Index register 6 buf[6]=0xe4; @@ -342,11 +336,11 @@ static int mt2032_init(struct i2c_client *c) buf[8]=0xc3; buf[9]=0x4e; buf[10]=0xec; - ret=i2c_master_send(c,buf+5,6); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); buf[12]=13; // Index register 13 buf[13]=0x32; - ret=i2c_master_send(c,buf+12,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); // Adjust XOGC (register 7), wait for XOK xogc=7; @@ -354,8 +348,8 @@ static int mt2032_init(struct i2c_client *c) tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); mdelay(10); buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); xok=buf[0]&0x01; tuner_dbg("mt2032: xok = 0x%02x\n",xok); if (xok == 1) break; @@ -368,7 +362,7 @@ static int mt2032_init(struct i2c_client *c) } buf[0]=0x07; buf[1]=0x88 + xogc; - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } while (xok != 1 ); @@ -379,21 +373,21 @@ static int mt2032_init(struct i2c_client *c) return(1); } -static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) +static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int ret; buf[0] = 6; buf[1] = antenna ? 0x11 : 0x10; - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); } -static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) +static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int if2) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned int if1=1218*1000*1000; unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; int ret; @@ -449,14 +443,13 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned printk("\n"); } - ret=i2c_master_send(c,buf,6); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); if (ret!=6) tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); } -static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void mt2050_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); unsigned int if2; if (t->std & V4L2_STD_525_60) { @@ -470,18 +463,17 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) // DVB (pinnacle 300i) if2 = 36150*1000; } - mt2050_set_if_freq(c, freq*62500, if2); - mt2050_set_antenna(c, tv_antenna); + mt2050_set_if_freq(t, freq*62500, if2); + mt2050_set_antenna(t, tv_antenna); } -static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void mt2050_set_radio_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; int if2 = priv->radio_if2; - mt2050_set_if_freq(c, freq * 1000 / 16, if2); - mt2050_set_antenna(c, radio_antenna); + mt2050_set_if_freq(t, freq * 1000 / 16, if2); + mt2050_set_antenna(t, radio_antenna); } static struct tuner_operations mt2050_tuner_ops = { @@ -490,23 +482,23 @@ static struct tuner_operations mt2050_tuner_ops = { .release = microtune_release, }; -static int mt2050_init(struct i2c_client *c) +static int mt2050_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int ret; buf[0]=6; buf[1]=0x10; - ret=i2c_master_send(c,buf,2); // power + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power buf[0]=0x0f; buf[1]=0x0f; - ret=i2c_master_send(c,buf,2); // m1lo + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo buf[0]=0x0d; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2050: sro is %x\n",buf[0]); @@ -515,10 +507,9 @@ static int mt2050_init(struct i2c_client *c) return 0; } -int microtune_init(struct i2c_client *c) +int microtune_init(struct tuner *t) { struct microtune_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); char *name; unsigned char buf[21]; int company_code; @@ -528,6 +519,9 @@ int microtune_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ memset(buf,0,sizeof(buf)); @@ -541,8 +535,8 @@ int microtune_init(struct i2c_client *c) } name = "unknown"; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); if (tuner_debug) { int i; tuner_dbg("MT20xx hexdump:"); @@ -562,10 +556,10 @@ int microtune_init(struct i2c_client *c) name = microtune_part[buf[0x13]]; switch (buf[0x13]) { case MT2032: - mt2032_init(c); + mt2032_init(t); break; case MT2050: - mt2050_init(c); + mt2050_init(t); break; default: tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", @@ -573,7 +567,7 @@ int microtune_init(struct i2c_client *c) return 0; } - strlcpy(c->name, name, sizeof(c->name)); + strlcpy(t->i2c.name, name, sizeof(t->i2c.name)); tuner_info("microtune %s found, OK\n",name); return 0; } diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 760d22f65da2..beb4a7e1d286 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -26,6 +26,8 @@ /* ---------------------------------------------------------------------- */ struct tda8290_priv { + struct tuner_i2c_props i2c_props; + unsigned char tda8290_easy_mode; unsigned char tda827x_lpsel; unsigned char tda827x_addr; @@ -79,13 +81,12 @@ static struct tda827x_data tda827x_analog[] = { { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ }; -static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) { unsigned char tuner_reg[8]; unsigned char reg2[2]; u32 N; int i; - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; @@ -114,54 +115,53 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) msg.buf = tuner_reg; msg.len = 8; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.buf= reg2; msg.len = 2; reg2[0] = 0x80; reg2[1] = 0; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x60; reg2[1] = 0xbf; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x30; reg2[1] = tuner_reg[4] + 0x80; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(1); reg2[0] = 0x30; reg2[1] = tuner_reg[4] + 4; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(1); reg2[0] = 0x30; reg2[1] = tuner_reg[4]; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(550); reg2[0] = 0x30; reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x60; reg2[1] = 0x3f; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x80; reg2[1] = 0x08; // Vsync en - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827x_agcf(struct i2c_client *c) +static void tda827x_agcf(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char data[] = {0x80, 0x0c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } /* ---------------------------------------------------------------------- */ @@ -204,12 +204,12 @@ static struct tda827xa_data tda827xa_analog[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ }; -static void tda827xa_lna_gain(struct i2c_client *c, int high) +static void tda827xa_lna_gain(struct tuner *t, int high) { - struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; unsigned char buf[] = {0x22, 0x01}; int arg; - struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; + struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; if (t->config) { if (high) tuner_dbg("setting LNA to high gain\n"); @@ -227,29 +227,28 @@ static void tda827xa_lna_gain(struct i2c_client *c, int high) else arg = 0; if (t->tuner_callback) - t->tuner_callback(c->adapter->algo_data, 1, arg); + t->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); buf[1] = high ? 0 : 1; if (t->config == 2) buf[1] = high ? 1 : 0; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); break; case 3: /* switch with GPIO of saa713x */ if (t->tuner_callback) - t->tuner_callback(c->adapter->algo_data, 0, high); + t->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); break; } } -static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) { unsigned char tuner_reg[11]; u32 N; int i; - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; - tda827xa_lna_gain( c, 1); + tda827xa_lna_gain(t, 1); msleep(10); if (t->mode == V4L2_TUNER_RADIO) @@ -278,7 +277,7 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[9] = 0x20; tuner_reg[10] = 0x00; msg.len = 11; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x90; tuner_reg[1] = 0xff; @@ -286,81 +285,81 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[3] = 0; tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1); msg.len = 5; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xa0; tuner_reg[1] = 0xc0; msg.len = 2; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x30; tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.flags = I2C_M_RD; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.flags = 0; tuner_reg[1] >>= 4; tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); if (tuner_reg[1] < 1) - tda827xa_lna_gain( c, 0); + tda827xa_lna_gain(t, 0); msleep(100); tuner_reg[0] = 0x60; tuner_reg[1] = 0x3c; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(163); tuner_reg[0] = 0x50; tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x80; tuner_reg[1] = 0x28; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xb0; tuner_reg[1] = 0x01; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xc0; tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1); - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827xa_agcf(struct i2c_client *c) +static void tda827xa_agcf(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char data[] = {0x80, 0x2c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct i2c_client *c, int close) +static void tda8290_i2c_bridge(struct tuner *t, int close) { + struct tda8290_priv *priv = t->priv; + unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; unsigned char *msg; if(close) { msg = enable; - i2c_master_send(c, msg, 2); + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); /* let the bridge stabilize */ msleep(20); } else { msg = disable; - i2c_master_send(c, msg, 2); + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } } /*---------------------------------------------------------------------*/ -static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; @@ -385,34 +384,34 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) int i; tuner_dbg("tda827xa config is 0x%02x\n", t->config); - i2c_master_send(c, easy_mode, 2); - i2c_master_send(c, agc_out_on, 2); - i2c_master_send(c, soft_reset, 2); + tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); + tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); msleep(1); expert_mode[1] = priv->tda8290_easy_mode + 0x80; - i2c_master_send(c, expert_mode, 2); - i2c_master_send(c, gainset_off, 2); - i2c_master_send(c, if_agc_spd, 2); + tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); if (priv->tda8290_easy_mode & 0x60) - i2c_master_send(c, adc_head_9, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); else - i2c_master_send(c, adc_head_6, 2); - i2c_master_send(c, pll_bw_nom, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - tda8290_i2c_bridge(c, 1); + tda8290_i2c_bridge(t, 1); if (priv->tda827x_ver != 0) - tda827xa_tune(c, ifc, freq); + tda827xa_tune(t, ifc, freq); else - tda827x_tune(c, ifc, freq); + tda827x_tune(t, ifc, freq); for (i = 0; i < 3; i++) { - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if (pll_stat & 0x80) { - i2c_master_send(c, &addr_adc_sat, 1); - i2c_master_recv(c, &adc_sat, 1); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); break; } else { @@ -424,28 +423,28 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", agc_stat, adc_sat, pll_stat & 0x80); - i2c_master_send(c, gainset_2, 2); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); msleep(100); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); if (priv->tda827x_ver != 0) - tda827xa_agcf(c); + tda827xa_agcf(t); else - tda827x_agcf(c); + tda827x_agcf(t); msleep(100); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); - i2c_master_send(c, adc_head_12, 2); - i2c_master_send(c, pll_bw_low, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); msleep(100); } } @@ -453,20 +452,20 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) /* l/ l' deadlock? */ if(priv->tda8290_easy_mode & 0x60) { - i2c_master_send(c, &addr_adc_sat, 1); - i2c_master_recv(c, &adc_sat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if ((adc_sat > 20) || !(pll_stat & 0x80)) { tuner_dbg("trying to resolve SECAM L deadlock\n"); - i2c_master_send(c, agc_rst_on, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); msleep(40); - i2c_master_send(c, agc_rst_off, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); } } - tda8290_i2c_bridge(c, 0); - i2c_master_send(c, if_agc_set, 2); + tda8290_i2c_bridge(t, 0); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); return 0; } @@ -515,69 +514,69 @@ static void set_audio(struct tuner *t) tuner_dbg("setting tda8290 to system %s\n", mode); } -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; set_audio(t); - tda8290_tune(c, priv->sgIF, freq); + tda8290_tune(t, priv->sgIF, freq); } -static void set_radio_freq(struct i2c_client *c, unsigned int freq) +static void set_radio_freq(struct tuner *t, unsigned int freq) { /* if frequency is 5.5 MHz */ - tda8290_tune(c, 88, freq); + tda8290_tune(t, 88, freq); } -static int has_signal(struct i2c_client *c) +static int has_signal(struct tuner *t) { + struct tda8290_priv *priv = t->priv; + unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; - i2c_master_send(c, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); - i2c_master_recv(c, &afc, 1); + tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); + tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); return (afc & 0x80)? 65535:0; } /*---------------------------------------------------------------------*/ -static void standby(struct i2c_client *c) +static void standby(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(c, 1); + tda8290_i2c_bridge(t, 1); if (priv->tda827x_ver != 0) cb1[1] = 0x90; - i2c_transfer(c->adapter, &msg, 1); - tda8290_i2c_bridge(c, 0); - i2c_master_send(c, tda8290_agc_tri, 2); - i2c_master_send(c, tda8290_standby, 2); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(t, 0); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); } -static void tda8290_init_if(struct i2c_client *c) +static void tda8290_init_if(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; + unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; if ((t->config == 1) || (t->config == 2)) - i2c_master_send(c, set_GP00_CF, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else - i2c_master_send(c, set_GP01_CF, 2); - i2c_master_send(c, set_VS, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8290_init_tuner(struct i2c_client *c) +static void tda8290_init_tuner(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; @@ -588,17 +587,15 @@ static void tda8290_init_tuner(struct i2c_client *c) if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; - tda8290_i2c_bridge(c, 1); - i2c_transfer(c->adapter, &msg, 1); - tda8290_i2c_bridge(c, 0); + tda8290_i2c_bridge(t, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(t, 0); } /*---------------------------------------------------------------------*/ -static void tda8290_release(struct i2c_client *c) +static void tda8290_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -611,10 +608,9 @@ static struct tuner_operations tda8290_tuner_ops = { .release = tda8290_release, }; -int tda8290_init(struct i2c_client *c) +int tda8290_init(struct tuner *t) { struct tda8290_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); u8 data; int i, ret, tuners_found; u32 tuner_addrs; @@ -625,13 +621,16 @@ int tda8290_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; - tda8290_i2c_bridge(c, 1); + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + + tda8290_i2c_bridge(t, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; for (i=0x60; i<= 0x63; i++) { msg.addr = i; - ret = i2c_transfer(c->adapter, &msg, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) { tuners_found++; tuner_addrs = (tuner_addrs << 8) + i; @@ -641,11 +640,11 @@ int tda8290_init(struct i2c_client *c) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(c, 0); + tda8290_i2c_bridge(t, 0); if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; - ret = i2c_transfer(c->adapter, &msg, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if(ret == 1) tuner_addrs = tuner_addrs >> 8; else @@ -662,31 +661,33 @@ int tda8290_init(struct i2c_client *c) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(c, 1); - ret = i2c_transfer(c->adapter, &msg, 1); + tda8290_i2c_bridge(t, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if( ret != 1) tuner_warn ("TDA827x access failed!\n"); if ((data & 0x3c) == 0) { - strlcpy(c->name, "tda8290+75", sizeof(c->name)); + strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); priv->tda827x_ver = 0; } else { - strlcpy(c->name, "tda8290+75a", sizeof(c->name)); + strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); priv->tda827x_ver = 2; } - tuner_info("type set to %s\n", c->name); + tuner_info("type set to %s\n", t->i2c.name); memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); priv->tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; - tda8290_init_tuner(c); - tda8290_init_if(c); + tda8290_init_tuner(t); + tda8290_init_if(t); return 0; } -int tda8290_probe(struct i2c_client *c) +int tda8290_probe(struct tuner *t) { + struct i2c_client *c = &t->i2c; + unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode_b[] = { 0x01, 0x02 }; unsigned char easy_mode_g[] = { 0x01, 0x04 }; diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index d162bc67d445..be5387f11afb 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -29,6 +29,8 @@ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) struct tda9887_priv { + struct tuner_i2c_props i2c_props; + unsigned char data[4]; }; @@ -510,19 +512,19 @@ static int tda9887_set_config(struct tuner *t, char *buf) static int tda9887_status(struct tuner *t) { + struct tda9887_priv *priv = t->priv; unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); - if (1 != (rc = i2c_master_recv(&t->i2c,buf,1))) + if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); dump_read_message(t, buf); return 0; } -static void tda9887_configure(struct i2c_client *client) +static void tda9887_configure(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); struct tda9887_priv *priv = t->priv; int rc; @@ -557,7 +559,7 @@ static void tda9887_configure(struct i2c_client *client) if (tuner_debug > 1) dump_write_message(t, priv->data); - if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); if (tuner_debug > 2) { @@ -568,16 +570,15 @@ static void tda9887_configure(struct i2c_client *client) /* ---------------------------------------------------------------------- */ -static void tda9887_tuner_status(struct i2c_client *client) +static void tda9887_tuner_status(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); struct tda9887_priv *priv = t->priv; tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct i2c_client *client) +static int tda9887_get_afc(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); + struct tda9887_priv *priv = t->priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -587,26 +588,24 @@ static int tda9887_get_afc(struct i2c_client *client) int afc=0; __u8 reg = 0; - if (1 == i2c_master_recv(&t->i2c,®,1)) + if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; return afc; } -static void tda9887_standby(struct i2c_client *client) +static void tda9887_standby(struct tuner *t) { - tda9887_configure(client); + tda9887_configure(t); } -static void tda9887_set_freq(struct i2c_client *client, unsigned int freq) +static void tda9887_set_freq(struct tuner *t, unsigned int freq) { - tda9887_configure(client); + tda9887_configure(t); } -static void tda9887_release(struct i2c_client *c) +static void tda9887_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -620,17 +619,19 @@ static struct tuner_operations tda9887_tuner_ops = { .release = tda9887_release, }; -int tda9887_tuner_init(struct i2c_client *c) +int tda9887_tuner_init(struct tuner *t) { struct tda9887_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; t->priv = priv; - strlcpy(c->name, "tda9887", sizeof(c->name)); + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + + strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, t->i2c.driver->driver.name); diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 43bdc374927e..9965ba48cffa 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -18,6 +18,10 @@ /* from tuner-core.c */ extern int tuner_debug; +struct tea5761_priv { + struct tuner_i2c_props i2c_props; +}; + /*****************************************************************************/ /*************************** @@ -114,10 +118,8 @@ extern int tuner_debug; /*****************************************************************************/ -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); - tuner_warn("This tuner doesn't support TV freq.\n"); } @@ -135,9 +137,9 @@ static void tea5761_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct i2c_client *c, unsigned int frq) +static void set_radio_freq(struct tuner *t, unsigned int frq) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; unsigned div; int rc; @@ -167,31 +169,31 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) if (tuner_debug) tea5761_status_dump(buffer); - if (7 != (rc = i2c_master_send(c, buffer, 7))) + if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); } -static int tea5761_signal(struct i2c_client *c) +static int tea5761_signal(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = i2c_master_recv(c, buffer, 16))) + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); } -static int tea5761_stereo(struct i2c_client *c) +static int tea5761_stereo(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = i2c_master_recv(c, buffer, 16))) + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); rc = buffer[9] & TEA5761_TUNCHECK_STEREO; @@ -201,13 +203,13 @@ static int tea5761_stereo(struct i2c_client *c) return (rc ? V4L2_TUNER_SUB_STEREO : 0); } -int tea5761_autodetection(struct i2c_client *c) +int tea5761_autodetection(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; - if (16 != (rc = i2c_master_recv(c, buffer, 16))) { + if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { tuner_warn("it is not a TEA5761. Received %i chars.\n", rc); return EINVAL; } @@ -220,22 +222,37 @@ int tea5761_autodetection(struct i2c_client *c) return 0; } +static void tea5761_release(struct tuner *t) +{ + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations tea5761_tuner_ops = { .set_tv_freq = set_tv_freq, .set_radio_freq = set_radio_freq, .has_signal = tea5761_signal, .is_stereo = tea5761_stereo, + .release = tea5761_release, }; -int tea5761_tuner_init(struct i2c_client *c) +int tea5761_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = NULL; - if (tea5761_autodetection(c) == EINVAL) + if (tea5761_autodetection(t) == EINVAL) return EINVAL; + priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio"); - strlcpy(c->name, "tea5761", sizeof(c->name)); + strlcpy(t->i2c.name, "tea5761", sizeof(t->i2c.name)); memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations)); diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 4c9c4e01331a..5a08ec2f99fb 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -20,6 +20,10 @@ /* from tuner-core.c */ extern int tuner_debug; +struct tea5767_priv { + struct tuner_i2c_props i2c_props; +}; + /*****************************************************************************/ /****************************** @@ -129,10 +133,8 @@ enum tea5767_xtal_freq { /*****************************************************************************/ -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); - tuner_warn("This tuner doesn't support TV freq.\n"); } @@ -190,9 +192,9 @@ static void tea5767_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct i2c_client *c, unsigned int frq) +static void set_radio_freq(struct tuner *t, unsigned int frq) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; unsigned char buffer[5]; unsigned div; int rc; @@ -246,38 +248,38 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) buffer[0] = (div >> 8) & 0x3f; buffer[1] = div & 0xff; - if (5 != (rc = i2c_master_send(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); if (tuner_debug) { - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else tea5767_status_dump(buffer); } } -static int tea5767_signal(struct i2c_client *c) +static int tea5767_signal(struct tuner *t) { unsigned char buffer[5]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); } -static int tea5767_stereo(struct i2c_client *c) +static int tea5767_stereo(struct tuner *t) { unsigned char buffer[5]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); rc = buffer[2] & TEA5767_STEREO_MASK; @@ -287,10 +289,10 @@ static int tea5767_stereo(struct i2c_client *c) return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } -static void tea5767_standby(struct i2c_client *c) +static void tea5767_standby(struct tuner *t) { unsigned char buffer[5]; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; unsigned div, rc; div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ @@ -301,17 +303,17 @@ static void tea5767_standby(struct i2c_client *c) TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; buffer[4] = 0; - if (5 != (rc = i2c_master_send(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); } -int tea5767_autodetection(struct i2c_client *c) +int tea5767_autodetection(struct tuner *t) { + struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; - struct tuner *t = i2c_get_clientdata(c); - if ((rc = i2c_master_recv(c, buffer, 7))< 5) { + if ((rc = tuner_i2c_xfer_send(&i2c, buffer, 7))< 5) { tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc); return EINVAL; } @@ -343,20 +345,35 @@ int tea5767_autodetection(struct i2c_client *c) return 0; } +static void tea5767_release(struct tuner *t) +{ + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations tea5767_tuner_ops = { .set_tv_freq = set_tv_freq, .set_radio_freq = set_radio_freq, .has_signal = tea5767_signal, .is_stereo = tea5767_stereo, .standby = tea5767_standby, + .release = tea5767_release, }; -int tea5767_tuner_init(struct i2c_client *c) +int tea5767_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); - strlcpy(c->name, "tea5767", sizeof(c->name)); + strlcpy(t->i2c.name, "tea5767", sizeof(t->i2c.name)); memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f505f43bb126..0363eae800e7 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -94,7 +94,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->ops.set_tv_freq(c, freq); + t->ops.set_tv_freq(t, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -121,7 +121,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - t->ops.set_radio_freq(c, freq); + t->ops.set_radio_freq(t, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -199,7 +199,7 @@ static void set_type(struct i2c_client *c, unsigned int type, /* discard private data, in case set_type() was previously called */ if (t->ops.release) - t->ops.release(c); + t->ops.release(t); else { kfree(t->priv); t->priv = NULL; @@ -207,13 +207,13 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - microtune_init(c); + microtune_init(t); break; case TUNER_PHILIPS_TDA8290: - tda8290_init(c); + tda8290_init(t); break; case TUNER_TEA5767: - if (tea5767_tuner_init(c) == EINVAL) { + if (tea5767_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -222,7 +222,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; #ifdef CONFIG_TUNER_TEA5761 case TUNER_TEA5761: - if (tea5761_tuner_init(c) == EINVAL) { + if (tea5761_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -240,7 +240,7 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - default_tuner_init(c); + default_tuner_init(t); break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; @@ -248,13 +248,13 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0xa4; i2c_master_send(c,buffer,4); - default_tuner_init(c); + default_tuner_init(t); break; case TUNER_TDA9887: - tda9887_tuner_init(c); + tda9887_tuner_init(t); break; default: - default_tuner_init(c); + default_tuner_init(t); break; } @@ -426,9 +426,8 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct i2c_client *client) +static void tuner_status(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); unsigned long freq, freq_fraction; const char *p; @@ -451,10 +450,10 @@ static void tuner_status(struct i2c_client *client) if (t->mode != V4L2_TUNER_RADIO) return; if (t->ops.has_signal) { - tuner_info("Signal strength: %d\n", t->ops.has_signal(client)); + tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); } if (t->ops.is_stereo) { - tuner_info("Stereo: %s\n", t->ops.is_stereo(client) ? "yes" : "no"); + tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); } } @@ -503,7 +502,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) switch (addr) { #ifdef CONFIG_TUNER_TEA5761 case 0x10: - if (tea5761_autodetection(&t->i2c) != EINVAL) { + if (tea5761_autodetection(t) != EINVAL) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -520,7 +519,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(&t->i2c) == 0) { + if (tda8290_probe(t) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ @@ -531,7 +530,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) } break; case 0x60: - if (tea5767_autodetection(&t->i2c) != EINVAL) { + if (tea5767_autodetection(t) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -588,7 +587,7 @@ static int tuner_detach(struct i2c_client *client) } if (t->ops.release) - t->ops.release(client); + t->ops.release(t); else { kfree(t->priv); } @@ -613,7 +612,7 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; if (t->ops.standby) - t->ops.standby (client); + t->ops.standby(t); return EINVAL; } return 0; @@ -662,7 +661,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; t->mode = T_STANDBY; if (t->ops.standby) - t->ops.standby (client); + t->ops.standby(t); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -722,9 +721,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (V4L2_TUNER_RADIO == t->mode) { if (t->ops.has_signal) - vt->signal = t->ops.has_signal(client); + vt->signal = t->ops.has_signal(t); if (t->ops.is_stereo) { - if (t->ops.is_stereo(client)) + if (t->ops.is_stereo(t)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -753,7 +752,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo) - va->mode = t->ops.is_stereo(client) + va->mode = t->ops.is_stereo(t) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; return 0; } @@ -819,7 +818,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) tuner->type = t->mode; if (t->ops.get_afc) - tuner->afc=t->ops.get_afc(client); + tuner->afc=t->ops.get_afc(t); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -830,12 +829,12 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) /* radio mode */ if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(client); + tuner->signal = t->ops.has_signal(t); tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(client) ? + tuner->rxsubchans = t->ops.is_stereo(t) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } @@ -864,7 +863,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_LOG_STATUS: if (t->ops.tuner_status) - t->ops.tuner_status(client); + t->ops.tuner_status(t); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 145045561a51..3cd1d446f2f3 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -24,18 +24,21 @@ #include #include +#include "tuner-i2c.h" extern unsigned const int tuner_count; +struct tuner; + struct tuner_operations { - void (*set_tv_freq)(struct i2c_client *c, unsigned int freq); - void (*set_radio_freq)(struct i2c_client *c, unsigned int freq); - int (*has_signal)(struct i2c_client *c); - int (*is_stereo)(struct i2c_client *c); - int (*get_afc)(struct i2c_client *c); - void (*tuner_status)(struct i2c_client *c); - void (*standby)(struct i2c_client *c); - void (*release)(struct i2c_client *c); + void (*set_tv_freq)(struct tuner *t, unsigned int freq); + void (*set_radio_freq)(struct tuner *t, unsigned int freq); + int (*has_signal)(struct tuner *t); + int (*is_stereo)(struct tuner *t); + int (*get_afc)(struct tuner *t); + void (*tuner_status)(struct tuner *t); + void (*standby)(struct tuner *t); + void (*release)(struct tuner *t); }; struct tuner { @@ -66,20 +69,20 @@ struct tuner { /* ------------------------------------------------------------------------ */ -extern int default_tuner_init(struct i2c_client *c); +extern int default_tuner_init(struct tuner *t); -extern int tda9887_tuner_init(struct i2c_client *c); +extern int tda9887_tuner_init(struct tuner *t); -extern int microtune_init(struct i2c_client *c); +extern int microtune_init(struct tuner *t); -extern int tda8290_init(struct i2c_client *c); -extern int tda8290_probe(struct i2c_client *c); +extern int tda8290_init(struct tuner *t); +extern int tda8290_probe(struct tuner *t); -extern int tea5761_tuner_init(struct i2c_client *c); -extern int tea5761_autodetection(struct i2c_client *c); +extern int tea5761_tuner_init(struct tuner *t); +extern int tea5761_autodetection(struct tuner *t); -extern int tea5767_autodetection(struct i2c_client *c); -extern int tea5767_tuner_init(struct i2c_client *c); +extern int tea5767_autodetection(struct tuner *t); +extern int tea5767_tuner_init(struct tuner *t); /* ------------------------------------------------------------------------ */ diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h new file mode 100644 index 000000000000..159019ec3373 --- /dev/null +++ b/drivers/media/video/tuner-i2c.h @@ -0,0 +1,70 @@ +/* + tuner-i2c.h - i2c interface for different tuners + + Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TUNER_I2C_H__ +#define __TUNER_I2C_H__ + +#include + +struct tuner_i2c_props { + u8 addr; + struct i2c_adapter *adap; +}; + +static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = 0, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +#ifndef __TUNER_DRIVER_H__ +#define tuner_warn(fmt, arg...) do {\ + printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_info(fmt, arg...) do {\ + printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_dbg(fmt, arg...) do {\ + if ((debug)) \ + printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#endif /* __TUNER_DRIVER_H__ */ + +#endif /* __TUNER_I2C_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 572f22423b98..eca2ff249a36 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -84,31 +84,32 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); struct tuner_simple_priv { u16 last_div; + struct tuner_i2c_props i2c_props; }; /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct i2c_client *c) +static int tuner_getstatus(struct tuner *t) { + struct tuner_simple_priv *priv = t->priv; unsigned char byte; - if (1 != i2c_master_recv(c,&byte,1)) + if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1)) return 0; return byte; } -static int tuner_signal(struct i2c_client *c) +static int tuner_signal(struct tuner *t) { - return (tuner_getstatus(c) & TUNER_SIGNAL) << 13; + return (tuner_getstatus(t) & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct i2c_client *c) +static int tuner_stereo(struct tuner *t) { int stereo, status; - struct tuner *t = i2c_get_clientdata(c); - status = tuner_getstatus (c); + status = tuner_getstatus(t); switch (t->type) { case TUNER_PHILIPS_FM1216ME_MK3: @@ -127,9 +128,8 @@ static int tuner_stereo(struct i2c_client *c) /* ---------------------------------------------------------------------- */ -static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void default_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = t->priv; u8 config, cb, tuneraddr; u16 div; @@ -285,13 +285,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[1] = 0x04; } /* set to the correct mode (analog or digital) */ - tuneraddr = c->addr; - c->addr = 0x0a; - if (2 != (rc = i2c_master_send(c,&buffer[0],2))) + tuneraddr = priv->i2c_props.addr; + priv->i2c_props.addr = 0x0a; + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); - if (2 != (rc = i2c_master_send(c,&buffer[2],2))) + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); - c->addr = tuneraddr; + priv->i2c_props.addr = tuneraddr; /* FIXME: input */ break; } @@ -345,12 +345,12 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) } if (params->default_pll_gating_18) config |= TDA9887_GATING_18; - i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); switch (t->type) { @@ -362,7 +362,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[1] = 0x20; tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]); - if (2 != (rc = i2c_master_send(c,buffer,2))) + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); break; case TUNER_MICROTUNE_4042FI5: @@ -375,7 +375,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) for (;;) { if (time_after(jiffies,timeout)) return; - if (1 != (rc = i2c_master_recv(c,&status_byte,1))) { + if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) { tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); break; } @@ -393,17 +393,16 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); break; } } } -static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void default_set_radio_freq(struct tuner *t, unsigned int freq) { struct tunertype *tun; - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = t->priv; u8 buffer[4]; u16 div; @@ -498,16 +497,14 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) config |= TDA9887_GAIN_NORMAL; if (params->radio_if == 2) config |= TDA9887_RIF_41_3; - i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); } -static void tuner_release(struct i2c_client *c) +static void tuner_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -520,9 +517,8 @@ static struct tuner_operations simple_tuner_ops = { .release = tuner_release, }; -int default_tuner_init(struct i2c_client *c) +int default_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = NULL; priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); @@ -530,9 +526,12 @@ int default_tuner_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + tuner_info("type set to %d (%s)\n", t->type, tuners[t->type].name); - strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); + strlcpy(t->i2c.name, tuners[t->type].name, sizeof(t->i2c.name)); memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations)); From e18f9444bda60a67e6feef00c354f8de0cdaeba7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:25:48 -0300 Subject: [PATCH 0680/2804] V4L/DVB (6128): hybrid tuner refactoring core changes, phase 1 Prepare tuner-core for conversion of tuner sub-drivers into dvb_frontend modules Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Oliver Endriss Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 9 ++ drivers/media/video/tuner-core.c | 131 ++++++++++++++++++---- drivers/media/video/tuner-driver.h | 3 + 3 files changed, 124 insertions(+), 19 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index f95de63d0e24..ffb83b0f68c3 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -62,6 +62,13 @@ struct dvb_tuner_info { u32 bandwidth_step; }; +struct analog_parameters { + unsigned int frequency; + unsigned int mode; + unsigned int audmode; + u64 std; +}; + struct dvb_tuner_ops { struct dvb_tuner_info info; @@ -72,6 +79,7 @@ struct dvb_tuner_ops { /** This is for simple PLLs - set all parameters in one go. */ int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); @@ -80,6 +88,7 @@ struct dvb_tuner_ops { int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); #define TUNER_STATUS_LOCKED 1 +#define TUNER_STATUS_STEREO 2 int (*get_status)(struct dvb_frontend *fe, u32 *status); /** These are provided seperately from set_params in order to facilitate silicon diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 0363eae800e7..183bbb9ba6ab 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -70,6 +70,40 @@ static struct i2c_client client_template; /* ---------------------------------------------------------------------- */ +static void fe_set_freq(struct tuner *t, unsigned int freq) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + if (NULL == fe_tuner_ops->set_analog_params) { + tuner_warn("Tuner frontend module has no way to set freq\n"); + return; + } + fe_tuner_ops->set_analog_params(&t->fe, ¶ms); +} + +static void fe_release(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->release) + fe_tuner_ops->release(&t->fe); +} + +static void fe_standby(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->sleep) + fe_tuner_ops->sleep(&t->fe); +} + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { @@ -171,6 +205,7 @@ static void set_type(struct i2c_client *c, unsigned int type, int (*tuner_callback) (void *dev, int command,int arg)) { struct tuner *t = i2c_get_clientdata(c); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -258,6 +293,17 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } + if (fe_tuner_ops->set_analog_params) { + strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); + + t->ops.set_tv_freq = fe_set_freq; + t->ops.set_radio_freq = fe_set_freq; + t->ops.standby = fe_standby; + t->ops.release = fe_release; + } + + tuner_info("type set to %s\n", t->i2c.name); + if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -429,6 +475,7 @@ static int tuner_fixup_std(struct tuner *t) static void tuner_status(struct tuner *t) { unsigned long freq, freq_fraction; + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; const char *p; switch (t->mode) { @@ -449,6 +496,15 @@ static void tuner_status(struct tuner *t) tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) return; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_LOCKED) + tuner_info("Tuner is locked.\n"); + if (tuner_status & TUNER_STATUS_STEREO) + tuner_info("Stereo: yes\n"); + } if (t->ops.has_signal) { tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); } @@ -634,6 +690,7 @@ static inline int check_v4l2(struct tuner *t) static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; if (tuner_debug>1) v4l_i2c_print_ioctl(&(t->i2c),cmd); @@ -720,15 +777,27 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode) { - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); - if (t->ops.is_stereo) { - if (t->ops.is_stereo(t)) - vt->flags |= - VIDEO_TUNER_STEREO_ON; - else - vt->flags &= - ~VIDEO_TUNER_STEREO_ON; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_STEREO) + vt->flags |= VIDEO_TUNER_STEREO_ON; + else + vt->flags &= ~VIDEO_TUNER_STEREO_ON; + vt->signal = tuner_status & TUNER_STATUS_LOCKED + ? 65535 : 0; + } else { + if (t->ops.is_stereo) { + if (t->ops.is_stereo(t)) + vt->flags |= + VIDEO_TUNER_STEREO_ON; + else + vt->flags &= + ~VIDEO_TUNER_STEREO_ON; + } + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); } vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -751,9 +820,17 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_v4l2(t) == EINVAL) return 0; - if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo) - va->mode = t->ops.is_stereo(t) - ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + if (V4L2_TUNER_RADIO == t->mode) { + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + va->mode = (tuner_status & TUNER_STATUS_STEREO) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } else if (t->ops.is_stereo) + va->mode = t->ops.is_stereo(t) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } return 0; } #endif @@ -804,6 +881,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; switch_v4l2(); f->type = t->mode; + if (fe_tuner_ops->get_frequency) { + u32 abs_freq; + + fe_tuner_ops->get_frequency(&t->fe, &abs_freq); + f->frequency = (V4L2_TUNER_RADIO == t->mode) ? + (abs_freq * 2 + 125/2) / 125 : + (abs_freq + 62500/2) / 62500; + break; + } f->frequency = (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq; break; @@ -828,16 +914,23 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } /* radio mode */ - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(t) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - } + if (fe_tuner_ops->get_status) { + u32 tuner_status; + fe_tuner_ops->get_status(&t->fe, &tuner_status); + tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + tuner->signal = tuner_status & TUNER_STATUS_LOCKED ? 65535 : 0; + } else { + if (t->ops.is_stereo) { + tuner->rxsubchans = t->ops.is_stereo(t) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); + } tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 3cd1d446f2f3..d4c02b4abe71 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -25,6 +25,7 @@ #include #include #include "tuner-i2c.h" +#include "dvb_frontend.h" extern unsigned const int tuner_count; @@ -58,6 +59,8 @@ struct tuner { int using_v4l2; void *priv; + struct dvb_frontend fe; + /* used by tda9887 */ unsigned int tda9887_config; From 910bb3e3c5a5d8ed5028846728efc6a375d200eb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:22:20 -0300 Subject: [PATCH 0681/2804] V4L/DVB (6129): tda8290: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 367 +++++++++++++++++------------ drivers/media/video/tda8290.h | 35 +++ drivers/media/video/tuner-core.c | 16 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 270 insertions(+), 151 deletions(-) create mode 100644 drivers/media/video/tda8290.h diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index beb4a7e1d286..ec731d6fbfb8 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -16,12 +16,21 @@ 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. + + This "tda8290" module was split apart from the original "tuner" module. */ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tda8290.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tda8290 " /* ---------------------------------------------------------------------- */ @@ -33,6 +42,11 @@ struct tda8290_priv { unsigned char tda827x_addr; unsigned char tda827x_ver; unsigned int sgIF; + + u32 frequency; + + unsigned int *lna_cfg; + int (*tuner_callback) (void *dev, int command,int arg); }; /* ---------------------------------------------------------------------- */ @@ -81,19 +95,21 @@ static struct tda827x_data tda827x_analog[] = { { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ }; -static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void tda827x_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned char tuner_reg[8]; unsigned char reg2[2]; u32 N; int i; - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; + unsigned int freq = params->frequency; - if (t->mode == V4L2_TUNER_RADIO) + if (params->mode == V4L2_TUNER_RADIO) freq = freq / 1000; - N = freq + ifc; + N = freq + priv->sgIF; i = 0; while (tda827x_analog[i].lomax < N) { if(tda827x_analog[i + 1].lomax == 0) @@ -155,9 +171,9 @@ static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827x_agcf(struct tuner *t) +static void tda827x_agcf(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char data[] = {0x80, 0x0c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; @@ -204,57 +220,64 @@ static struct tda827xa_data tda827xa_analog[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ }; -static void tda827xa_lna_gain(struct tuner *t, int high) +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char buf[] = {0x22, 0x01}; int arg; struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; - if (t->config) { + + if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL)) + return; + + if (*priv->lna_cfg) { if (high) tuner_dbg("setting LNA to high gain\n"); else tuner_dbg("setting LNA to low gain\n"); } - switch (t->config) { + switch (*priv->lna_cfg) { case 0: /* no LNA */ break; case 1: /* switch is GPIO 0 of tda8290 */ case 2: /* turn Vsync on */ - if (t->std & V4L2_STD_MN) + if (params->std & V4L2_STD_MN) arg = 1; else arg = 0; - if (t->tuner_callback) - t->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); + if (priv->tuner_callback) + priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); buf[1] = high ? 0 : 1; - if (t->config == 2) + if (*priv->lna_cfg == 2) buf[1] = high ? 1 : 0; i2c_transfer(priv->i2c_props.adap, &msg, 1); break; case 3: /* switch with GPIO of saa713x */ - if (t->tuner_callback) - t->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); + if (priv->tuner_callback) + priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); break; } } -static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned char tuner_reg[11]; u32 N; int i; - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; + unsigned int freq = params->frequency; - tda827xa_lna_gain(t, 1); + tda827xa_lna_gain(fe, 1, params); msleep(10); - if (t->mode == V4L2_TUNER_RADIO) + if (params->mode == V4L2_TUNER_RADIO) freq = freq / 1000; - N = freq + ifc; + N = freq + priv->sgIF; i = 0; while (tda827xa_analog[i].lomax < N) { if(tda827xa_analog[i + 1].lomax == 0) @@ -302,7 +325,7 @@ static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_reg[1] >>= 4; tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); if (tuner_reg[1] < 1) - tda827xa_lna_gain(t, 0); + tda827xa_lna_gain(fe, 0, params); msleep(100); tuner_reg[0] = 0x60; @@ -327,9 +350,9 @@ static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827xa_agcf(struct tuner *t) +static void tda827xa_agcf(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char data[] = {0x80, 0x2c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; @@ -338,9 +361,9 @@ static void tda827xa_agcf(struct tuner *t) /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct tuner *t, int close) +static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; @@ -358,9 +381,58 @@ static void tda8290_i2c_bridge(struct tuner *t, int close) /*---------------------------------------------------------------------*/ -static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void set_audio(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; + char* mode; + + priv->tda827x_lpsel = 0; + if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; + priv->tda8290_easy_mode = 0x01; + priv->tda827x_lpsel = 1; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; + priv->tda8290_easy_mode = 0x02; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x04; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x08; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x10; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x20; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; + priv->tda8290_easy_mode = 0x40; + mode = "LC"; + } else { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x10; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + + tuner_dbg("setting tda8290 to system %s\n", mode); +} + +static int tda8290_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->tuner_priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -383,7 +455,10 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) pll_stat; int i; - tuner_dbg("tda827xa config is 0x%02x\n", t->config); + set_audio(fe, params); + + if (priv->lna_cfg) + tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); @@ -399,11 +474,11 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); if (priv->tda827x_ver != 0) - tda827xa_tune(t, ifc, freq); + tda827xa_set_analog_params(fe, params); else - tda827x_tune(t, ifc, freq); + tda827x_set_analog_params(fe, params); for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); @@ -433,9 +508,9 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); if (priv->tda827x_ver != 0) - tda827xa_agcf(t); + tda827xa_agcf(fe); else - tda827x_agcf(t); + tda827x_agcf(fe); msleep(100); tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); @@ -464,73 +539,20 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) } } - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); + + priv->frequency = (V4L2_TUNER_RADIO == params->mode) ? + params->frequency * 125 / 2 : params->frequency * 62500; + return 0; } /*---------------------------------------------------------------------*/ -static void set_audio(struct tuner *t) +static int tda8290_has_signal(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; - char* mode; - - priv->tda827x_lpsel = 0; - if (t->std & V4L2_STD_MN) { - priv->sgIF = 92; - priv->tda8290_easy_mode = 0x01; - priv->tda827x_lpsel = 1; - mode = "MN"; - } else if (t->std & V4L2_STD_B) { - priv->sgIF = 108; - priv->tda8290_easy_mode = 0x02; - mode = "B"; - } else if (t->std & V4L2_STD_GH) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x04; - mode = "GH"; - } else if (t->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x08; - mode = "I"; - } else if (t->std & V4L2_STD_DK) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x10; - mode = "DK"; - } else if (t->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x20; - mode = "L"; - } else if (t->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; - priv->tda8290_easy_mode = 0x40; - mode = "LC"; - } else { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x10; - mode = "xx"; - } - tuner_dbg("setting tda8290 to system %s\n", mode); -} - -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - struct tda8290_priv *priv = t->priv; - - set_audio(t); - tda8290_tune(t, priv->sgIF, freq); -} - -static void set_radio_freq(struct tuner *t, unsigned int freq) -{ - /* if frequency is 5.5 MHz */ - tda8290_tune(t, 88, freq); -} - -static int has_signal(struct tuner *t) -{ - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; @@ -540,44 +562,63 @@ static int has_signal(struct tuner *t) return (afc & 0x80)? 65535:0; } +static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tda8290_priv *priv = fe->tuner_priv; + + int signal = tda8290_has_signal(fe); + *status = 0; + + /* for now, report based on afc status */ + if (signal) + *status = TUNER_STATUS_LOCKED; + + tuner_dbg("tda8290: AFC status: %d\n", signal); + + return 0; +} + /*---------------------------------------------------------------------*/ -static void standby(struct tuner *t) +static int tda8290_standby(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); if (priv->tda827x_ver != 0) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); + + return 0; } -static void tda8290_init_if(struct tuner *t) +static void tda8290_init_if(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((t->config == 1) || (t->config == 2)) + if ((priv->lna_cfg) && + ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2))) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8290_init_tuner(struct tuner *t) +static void tda8290_init_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, @@ -587,28 +628,40 @@ static void tda8290_init_tuner(struct tuner *t) if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); } /*---------------------------------------------------------------------*/ -static void tda8290_release(struct tuner *t) +static int tda8290_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; } -static struct tuner_operations tda8290_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = has_signal, - .standby = standby, - .release = tda8290_release, +static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda8290_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tda8290_tuner_ops = { + .sleep = tda8290_standby, + .set_analog_params = tda8290_set_params, + .release = tda8290_release, + .get_frequency = tda8290_get_frequency, + .get_status = tda8290_get_status, }; -int tda8290_init(struct tuner *t) +struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg) { struct tda8290_priv *priv = NULL; u8 data; @@ -618,13 +671,17 @@ int tda8290_init(struct tuner *t) priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + if (cfg) { + priv->lna_cfg = cfg->lna_cfg; + priv->tuner_callback = cfg->tuner_callback; + } - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; @@ -640,7 +697,7 @@ int tda8290_init(struct tuner *t) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; @@ -652,41 +709,52 @@ int tda8290_init(struct tuner *t) } if (tuner_addrs == 0) { tuner_addrs = 0x61; - tuner_info ("could not clearly identify tuner address, defaulting to %x\n", + tuner_info("could not clearly identify tuner address, defaulting to %x\n", tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; - tuner_info ("setting tuner address to %x\n", tuner_addrs); + tuner_info("setting tuner address to %x\n", tuner_addrs); } priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if( ret != 1) - tuner_warn ("TDA827x access failed!\n"); + tuner_warn("TDA827x access failed!\n"); + + memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops, + sizeof(struct dvb_tuner_ops)); + if ((data & 0x3c) == 0) { - strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75", + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = 55000000; + fe->ops.tuner_ops.info.frequency_max = 860000000; + fe->ops.tuner_ops.info.frequency_step = 250000; priv->tda827x_ver = 0; } else { - strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a", + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = 44000000; + fe->ops.tuner_ops.info.frequency_max = 906000000; + fe->ops.tuner_ops.info.frequency_step = 62500; priv->tda827x_ver = 2; } - tuner_info("type set to %s\n", t->i2c.name); - - memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); priv->tda827x_lpsel = 0; - t->mode = V4L2_TUNER_ANALOG_TV; - tda8290_init_tuner(t); - tda8290_init_if(t); - return 0; + tda8290_init_tuner(fe); + tda8290_init_if(fe); + return fe; } -int tda8290_probe(struct tuner *t) +int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) { - struct i2c_client *c = &t->i2c; + struct tuner_i2c_props i2c_props = { + .adap = i2c_adap, + .addr = i2c_addr + }; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode_b[] = { 0x01, 0x02 }; @@ -695,23 +763,30 @@ int tda8290_probe(struct tuner *t) unsigned char addr_dto_lsb = 0x07; unsigned char data; - i2c_master_send(c, easy_mode_b, 2); - i2c_master_send(c, soft_reset, 2); - i2c_master_send(c, &addr_dto_lsb, 1); - i2c_master_recv(c, &data, 1); + tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); + tuner_i2c_xfer_recv(&i2c_props, &data, 1); if (data == 0) { - i2c_master_send(c, easy_mode_g, 2); - i2c_master_send(c, soft_reset, 2); - i2c_master_send(c, &addr_dto_lsb, 1); - i2c_master_recv(c, &data, 1); + tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); + tuner_i2c_xfer_recv(&i2c_props, &data, 1); if (data == 0x7b) { return 0; } } - i2c_master_send(c, restore_9886, 3); + tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); return -1; } +EXPORT_SYMBOL_GPL(tda8290_probe); +EXPORT_SYMBOL_GPL(tda8290_attach); + +MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h new file mode 100644 index 000000000000..815ca1c78f80 --- /dev/null +++ b/drivers/media/video/tda8290.h @@ -0,0 +1,35 @@ +/* + 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 __TDA8290_H__ +#define __TDA8290_H__ + +#include +#include "dvb_frontend.h" + +struct tda8290_config +{ + unsigned int *lna_cfg; + int (*tuner_callback) (void *dev, int command,int arg); +}; + +extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg); + +#endif /* __TDA8290_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 183bbb9ba6ab..f37fe83b1995 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,6 +19,7 @@ #include #include #include "tuner-driver.h" +#include "tda8290.h" #define UNSET (-1U) @@ -200,6 +201,15 @@ static void tuner_i2c_address_check(struct tuner *t) tuner_warn("====================== WARNING! ======================\n"); } +static void attach_tda8290(struct tuner *t) +{ + struct tda8290_config cfg = { + .lna_cfg = &t->config, + .tuner_callback = t->tuner_callback + }; + tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -245,8 +255,10 @@ static void set_type(struct i2c_client *c, unsigned int type, microtune_init(t); break; case TUNER_PHILIPS_TDA8290: - tda8290_init(t); + { + attach_tda8290(t); break; + } case TUNER_TEA5767: if (tea5767_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; @@ -575,7 +587,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(t) == 0) { + if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index d4c02b4abe71..05d5f8575673 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -78,9 +78,6 @@ extern int tda9887_tuner_init(struct tuner *t); extern int microtune_init(struct tuner *t); -extern int tda8290_init(struct tuner *t); -extern int tda8290_probe(struct tuner *t); - extern int tea5761_tuner_init(struct tuner *t); extern int tea5761_autodetection(struct tuner *t); From 96c0b7cfa5de1d6be0a6f6d202a6a078f5577d8f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:23:08 -0300 Subject: [PATCH 0682/2804] V4L/DVB (6130): mt20xx: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 246 ++++++++++++++++++++--------- drivers/media/video/mt20xx.h | 27 ++++ drivers/media/video/tuner-core.c | 3 +- drivers/media/video/tuner-driver.h | 2 - 4 files changed, 197 insertions(+), 81 deletions(-) create mode 100644 drivers/media/video/mt20xx.h diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 41bc91817a16..f49d1f4c40db 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -1,12 +1,20 @@ /* - * * i2c tv tuner chip device driver * controls microtune tuners, mt2032 + mt2050 at the moment. + * + * This "mt20xx" module was split apart from the original "tuner" module. */ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "mt20xx.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "mt20xx " /* ---------------------------------------------------------------------- */ @@ -19,9 +27,6 @@ module_param(tv_antenna, int, 0644); static unsigned int radio_antenna = 0; module_param(radio_antenna, int, 0644); -/* from tuner-core.c */ -extern int tuner_debug; - /* ---------------------------------------------------------------------- */ #define MT2032 0x04 @@ -40,19 +45,31 @@ struct microtune_priv { struct tuner_i2c_props i2c_props; unsigned int xogc; - unsigned int radio_if2; + //unsigned int radio_if2; + + u32 frequency; }; -static void microtune_release(struct tuner *t) +static int microtune_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct microtune_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; } // IsSpurInBand()? -static int mt2032_spurcheck(struct tuner *t, +static int mt2032_spurcheck(struct dvb_frontend *fe, int f1, int f2, int spectrum_from,int spectrum_to) { + struct microtune_priv *priv = fe->tuner_priv; int n1=1,n2,f; f1=f1/1000; //scale to kHz to avoid 32bit overflows @@ -80,7 +97,7 @@ static int mt2032_spurcheck(struct tuner *t, return 1; } -static int mt2032_compute_freq(struct tuner *t, +static int mt2032_compute_freq(struct dvb_frontend *fe, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int spectrum_from, @@ -89,6 +106,7 @@ static int mt2032_compute_freq(struct tuner *t, int *ret_sel, unsigned int xogc) //all in Hz { + struct microtune_priv *priv = fe->tuner_priv; unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; @@ -138,7 +156,7 @@ static int mt2032_compute_freq(struct tuner *t, return(-1); } - mt2032_spurcheck(t, lo1freq, desired_lo2, spectrum_from, spectrum_to); + mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); // should recalculate lo1 (one step up/down) // set up MT2032 register map for transfer over i2c @@ -162,9 +180,9 @@ static int mt2032_compute_freq(struct tuner *t, return 0; } -static int mt2032_check_lo_lock(struct tuner *t) +static int mt2032_check_lo_lock(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; int try,lock=0; unsigned char buf[2]; @@ -184,9 +202,9 @@ static int mt2032_check_lo_lock(struct tuner *t) return lock; } -static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) +static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int tad1; @@ -216,18 +234,18 @@ static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) buf[0]=0x0f; buf[1]=sel; tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - lock=mt2032_check_lo_lock(t); + lock=mt2032_check_lo_lock(fe); return lock; } -static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, +static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int from, unsigned int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", rfin,if1,if2,from,to); @@ -237,7 +255,7 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); buf[0]=0; - ret=mt2032_compute_freq(t,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); + ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); if (ret<0) return; @@ -253,10 +271,10 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, // wait for PLLs to lock (per manual), retry LINT if not. for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(t); + lock=mt2032_check_lo_lock(fe); if(optimize_vco) - lock=mt2032_optimize_vco(t,sel,lock); + lock=mt2032_optimize_vco(fe,sel,lock); if(lock==6) break; tuner_dbg("mt2032: re-init PLLs by LINT\n"); @@ -279,12 +297,13 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, } -static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) +static int mt2032_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { int if2,from,to; // signal bandwidth and picture carrier - if (t->std & V4L2_STD_525_60) { + if (params->std & V4L2_STD_525_60) { // NTSC from = 40750*1000; to = 46750*1000; @@ -296,30 +315,64 @@ static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) if2 = 38900*1000; } - mt2032_set_if_freq(t, freq*62500 /* freq*1000*1000/16 */, + mt2032_set_if_freq(fe, params->frequency*62500, 1090*1000*1000, if2, from, to); + + return 0; } -static void mt2032_set_radio_freq(struct tuner *t, unsigned int freq) +static int mt2032_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct microtune_priv *priv = t->priv; - int if2 = priv->radio_if2; + struct microtune_priv *priv = fe->tuner_priv; + int if2; + + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(t, freq * 1000 / 16, - 1085*1000*1000,if2,if2,if2); + mt2032_set_if_freq(fe, params->frequency * 125 / 2, + 1085*1000*1000,if2,if2,if2); + + return 0; } -static struct tuner_operations mt2032_tuner_ops = { - .set_tv_freq = mt2032_set_tv_freq, - .set_radio_freq = mt2032_set_radio_freq, - .release = microtune_release, +static int mt2032_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2032_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2032_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2032_tuner_ops = { + .set_analog_params = mt2032_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, }; // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct tuner *t) +static int mt2032_init(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[21]; int ret,xogc,xok=0; @@ -368,14 +421,14 @@ static int mt2032_init(struct tuner *t) } while (xok != 1 ); priv->xogc=xogc; - memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations)); + memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); return(1); } -static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) +static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int ret; @@ -385,9 +438,9 @@ static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); } -static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int if2) +static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned int if1=1218*1000*1000; unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; int ret; @@ -419,7 +472,7 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i div2a=(lo2/8)-1; div2b=lo2-(div2a+1)*8; - if (tuner_debug > 1) { + if (debug > 1) { tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", num1,num2,div1a,div1b,div2a,div2b); @@ -435,7 +488,7 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i buf[5]=div2a; if(num2!=0) buf[5]=buf[5]|0x40; - if (tuner_debug > 1) { + if (debug > 1) { int i; tuner_dbg("bufs is: "); for(i=0;i<6;i++) @@ -448,43 +501,78 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); } -static void mt2050_set_tv_freq(struct tuner *t, unsigned int freq) +static int mt2050_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned int if2; - if (t->std & V4L2_STD_525_60) { + if (params->std & V4L2_STD_525_60) { // NTSC if2 = 45750*1000; } else { // PAL if2 = 38900*1000; } - if (V4L2_TUNER_DIGITAL_TV == t->mode) { + if (V4L2_TUNER_DIGITAL_TV == params->mode) { // DVB (pinnacle 300i) if2 = 36150*1000; } - mt2050_set_if_freq(t, freq*62500, if2); - mt2050_set_antenna(t, tv_antenna); + mt2050_set_if_freq(fe, params->frequency*62500, if2); + mt2050_set_antenna(fe, tv_antenna); + + return 0; } -static void mt2050_set_radio_freq(struct tuner *t, unsigned int freq) +static int mt2050_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct microtune_priv *priv = t->priv; - int if2 = priv->radio_if2; + struct microtune_priv *priv = fe->tuner_priv; + int if2; - mt2050_set_if_freq(t, freq * 1000 / 16, if2); - mt2050_set_antenna(t, radio_antenna); + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } + + mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); + mt2050_set_antenna(fe, radio_antenna); + + return 0; } -static struct tuner_operations mt2050_tuner_ops = { - .set_tv_freq = mt2050_set_tv_freq, - .set_radio_freq = mt2050_set_radio_freq, - .release = microtune_release, +static int mt2050_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2050_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2050_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2050_tuner_ops = { + .set_analog_params = mt2050_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, }; -static int mt2050_init(struct tuner *t) +static int mt2050_init(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int ret; @@ -502,12 +590,14 @@ static int mt2050_init(struct tuner *t) tuner_dbg("mt2050: sro is %x\n",buf[0]); - memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations)); + memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); return 0; } -int microtune_init(struct tuner *t) +struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct microtune_priv *priv = NULL; char *name; @@ -516,28 +606,21 @@ int microtune_init(struct tuner *t) priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ + //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ memset(buf,0,sizeof(buf)); - if (t->std & V4L2_STD_525_60) { - tuner_dbg("pinnacle ntsc\n"); - priv->radio_if2 = 41300 * 1000; - } else { - tuner_dbg("pinnacle pal\n"); - priv->radio_if2 = 33300 * 1000; - } name = "unknown"; tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); - if (tuner_debug) { + if (debug) { int i; tuner_dbg("MT20xx hexdump:"); for(i=0;i<21;i++) { @@ -556,10 +639,10 @@ int microtune_init(struct tuner *t) name = microtune_part[buf[0x13]]; switch (buf[0x13]) { case MT2032: - mt2032_init(t); + mt2032_init(fe); break; case MT2050: - mt2050_init(t); + mt2050_init(fe); break; default: tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", @@ -567,11 +650,18 @@ int microtune_init(struct tuner *t) return 0; } - strlcpy(t->i2c.name, name, sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, name, + sizeof(fe->ops.tuner_ops.info.name)); tuner_info("microtune %s found, OK\n",name); - return 0; + return fe; } +EXPORT_SYMBOL_GPL(microtune_attach); + +MODULE_DESCRIPTION("Microtune tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h new file mode 100644 index 000000000000..877dbef891ea --- /dev/null +++ b/drivers/media/video/mt20xx.h @@ -0,0 +1,27 @@ +/* + 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 __MT20XX_H__ +#define __MT20XX_H__ + +#include +#include "dvb_frontend.h" + +extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __MT20XX_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f37fe83b1995..f24ec1a18b45 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,6 +19,7 @@ #include #include #include "tuner-driver.h" +#include "mt20xx.h" #include "tda8290.h" #define UNSET (-1U) @@ -252,7 +253,7 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - microtune_init(t); + microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); break; case TUNER_PHILIPS_TDA8290: { diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 05d5f8575673..87d937f2f740 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,8 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int microtune_init(struct tuner *t); - extern int tea5761_tuner_init(struct tuner *t); extern int tea5761_autodetection(struct tuner *t); From 7ab10bf72add23f0badf98ead92f58e34e14d35a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:23:40 -0300 Subject: [PATCH 0683/2804] V4L/DVB (6131): tea5761: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5761.c | 132 +++++++++++++++++++---------- drivers/media/video/tea5761.h | 28 ++++++ drivers/media/video/tuner-core.c | 5 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 118 insertions(+), 50 deletions(-) create mode 100644 drivers/media/video/tea5761.h diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 9965ba48cffa..8cdaf474ffdd 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -11,15 +11,19 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tea5761.h" -#define PREFIX "TEA5761 " +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); -/* from tuner-core.c */ -extern int tuner_debug; +#define PREFIX "tea5761 " struct tea5761_priv { struct tuner_i2c_props i2c_props; + + u32 frequency; }; /*****************************************************************************/ @@ -118,11 +122,6 @@ struct tea5761_priv { /*****************************************************************************/ -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - tuner_warn("This tuner doesn't support TV freq.\n"); -} - #define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ static void tea5761_status_dump(unsigned char *buffer) { @@ -137,16 +136,18 @@ static void tea5761_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct tuner *t, unsigned int frq) +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; + unsigned int frq = params->frequency; unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; unsigned div; int rc; - tuner_dbg (PREFIX "radio freq counter %d\n", frq); + tuner_dbg("radio freq counter %d\n", frq); - if (t->mode == T_STANDBY) { + if (params->mode == T_STANDBY) { tuner_dbg("TEA5761 set to standby mode\n"); buffer[5] |= TEA5761_TNCTRL_MU; } else { @@ -154,10 +155,9 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) } - if (t->audmode == V4L2_TUNER_MODE_MONO) { + if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5761 set to mono\n"); buffer[5] |= TEA5761_TNCTRL_MST; -; } else { tuner_dbg("TEA5761 set to stereo\n"); } @@ -166,18 +166,22 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) buffer[1] = (div >> 8) & 0x3f; buffer[2] = div & 0xff; - if (tuner_debug) + if (debug) tea5761_status_dump(buffer); if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + priv->frequency = frq * 125 / 2; + + return 0; } -static int tea5761_signal(struct tuner *t) +static int tea5761_signal(struct dvb_frontend *fe) { unsigned char buffer[16]; int rc; - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) @@ -186,11 +190,11 @@ static int tea5761_signal(struct tuner *t) return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); } -static int tea5761_stereo(struct tuner *t) +static int tea5761_stereo(struct dvb_frontend *fe) { unsigned char buffer[16]; int rc; - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) @@ -203,58 +207,96 @@ static int tea5761_stereo(struct tuner *t) return (rc ? V4L2_TUNER_SUB_STEREO : 0); } -int tea5761_autodetection(struct tuner *t) +static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tea5761_priv *priv = fe->tuner_priv; + int signal = tea5761_signal(fe); + + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tea5761_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tea5761: Signal strength: %d\n", signal); + + return 0; +} + +int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) { unsigned char buffer[16]; int rc; - struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { - tuner_warn("it is not a TEA5761. Received %i chars.\n", rc); + printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); return EINVAL; } if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) { - tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); + printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); return EINVAL; } - tuner_warn("TEA5761 detected.\n"); + printk(KERN_WARNING "TEA5761 detected.\n"); return 0; } -static void tea5761_release(struct tuner *t) +static int tea5761_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; } -static struct tuner_operations tea5761_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = tea5761_signal, - .is_stereo = tea5761_stereo, - .release = tea5761_release, +static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5761_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tea5761_tuner_ops = { + .info = { + .name = "tea5761", // Philips TEA5761HN FM Radio + }, + .set_analog_params = set_radio_freq, + .release = tea5761_release, + .get_frequency = tea5761_get_frequency, + .get_status = tea5761_get_status, }; -int tea5761_tuner_init(struct tuner *t) +struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct tea5761_priv *priv = NULL; - if (tea5761_autodetection(t) == EINVAL) - return EINVAL; + if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL) + return NULL; priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio"); - strlcpy(t->i2c.name, "tea5761", sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, + sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); - return (0); + return fe; } + + +EXPORT_SYMBOL_GPL(tea5761_attach); +EXPORT_SYMBOL_GPL(tea5761_autodetection); + +MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h new file mode 100644 index 000000000000..f287c0291bff --- /dev/null +++ b/drivers/media/video/tea5761.h @@ -0,0 +1,28 @@ +/* + 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 __TEA5761_H__ +#define __TEA5761_H__ + +#include +#include "dvb_frontend.h" + +extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __TEA5761_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f24ec1a18b45..848ee6420c5c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -21,6 +21,7 @@ #include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" +#include "tea5761.h" #define UNSET (-1U) @@ -270,7 +271,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; #ifdef CONFIG_TUNER_TEA5761 case TUNER_TEA5761: - if (tea5761_tuner_init(t) == EINVAL) { + if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -571,7 +572,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) switch (addr) { #ifdef CONFIG_TUNER_TEA5761 case 0x10: - if (tea5761_autodetection(t) != EINVAL) { + if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 87d937f2f740..bcb6a61c2086 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,9 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int tea5761_tuner_init(struct tuner *t); -extern int tea5761_autodetection(struct tuner *t); - extern int tea5767_autodetection(struct tuner *t); extern int tea5767_tuner_init(struct tuner *t); From 8d0936ed15f509c32e8f81849be3a1cee80e2225 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:24:27 -0300 Subject: [PATCH 0684/2804] V4L/DVB (6132): tea5767: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 149 +++++++++++++++++++---------- drivers/media/video/tea5767.h | 29 ++++++ drivers/media/video/tuner-core.c | 5 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 129 insertions(+), 57 deletions(-) create mode 100644 drivers/media/video/tea5767.h diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 5a08ec2f99fb..cf908d853195 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -13,15 +13,19 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tea5767.h" -#define PREFIX "TEA5767 " +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); -/* from tuner-core.c */ -extern int tuner_debug; +#define PREFIX "tea5767 " struct tea5767_priv { struct tuner_i2c_props i2c_props; + + u32 frequency; }; /*****************************************************************************/ @@ -133,11 +137,6 @@ enum tea5767_xtal_freq { /*****************************************************************************/ -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - tuner_warn("This tuner doesn't support TV freq.\n"); -} - static void tea5767_status_dump(unsigned char *buffer) { unsigned int div, frq; @@ -192,14 +191,16 @@ static void tea5767_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct tuner *t, unsigned int frq) +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; + unsigned int frq = params->frequency; unsigned char buffer[5]; unsigned div; int rc; - tuner_dbg (PREFIX "radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); + tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); /* Rounds freq to next decimal value - for 62.5 KHz step */ /* frq = 20*(frq/16)+radio_frq[frq%16]; */ @@ -209,7 +210,7 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; buffer[4] = 0; - if (t->audmode == V4L2_TUNER_MODE_MONO) { + if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); buffer[2] |= TEA5767_MONO; } else { @@ -219,26 +220,26 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) /* Should be replaced */ switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: - tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); + tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_13MHz: - tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); + tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_32768: - tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); + tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); buffer[3] |= TEA5767_XTAL_32768; /* const 700=4000*175 Khz - to adjust freq to right value */ div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; break; case TEA5767_HIGH_LO_32768: default: - tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); + tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[3] |= TEA5767_XTAL_32768; @@ -251,19 +252,23 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - if (tuner_debug) { + if (debug) { if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else tea5767_status_dump(buffer); } + + priv->frequency = frq * 125 / 2; + + return 0; } -static int tea5767_signal(struct tuner *t) +static int tea5767_signal(struct dvb_frontend *fe) { unsigned char buffer[5]; int rc; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) @@ -272,11 +277,11 @@ static int tea5767_signal(struct tuner *t) return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); } -static int tea5767_stereo(struct tuner *t) +static int tea5767_stereo(struct dvb_frontend *fe) { unsigned char buffer[5]; int rc; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) @@ -284,15 +289,31 @@ static int tea5767_stereo(struct tuner *t) rc = buffer[2] & TEA5767_STEREO_MASK; - tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); + tuner_dbg("radio ST GET = %02x\n", rc); return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } -static void tea5767_standby(struct tuner *t) +static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tea5767_priv *priv = fe->tuner_priv; + int signal = tea5767_signal(fe); + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tea5767_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tea5767: Signal strength: %d\n", signal); + + return 0; +} + +static int tea5767_standby(struct dvb_frontend *fe) { unsigned char buffer[5]; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; unsigned div, rc; div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ @@ -305,23 +326,25 @@ static void tea5767_standby(struct tuner *t) if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + return 0; } -int tea5767_autodetection(struct tuner *t) +int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) { - struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; - if ((rc = tuner_i2c_xfer_send(&i2c, buffer, 7))< 5) { - tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc); + if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { + printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); return EINVAL; } /* If all bytes are the same then it's a TV tuner and not a tea5767 */ if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && buffer[0] == buffer[3] && buffer[0] == buffer[4]) { - tuner_warn("All bytes are equal. It is not a TEA5767\n"); + printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); return EINVAL; } @@ -331,51 +354,73 @@ int tea5767_autodetection(struct tuner *t) * Byte 5: bit 7:0 : == 0 */ if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { - tuner_warn("Chip ID is not zero. It is not a TEA5767\n"); + printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); return EINVAL; } /* It seems that tea5767 returns 0xff after the 5th byte */ if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) { - tuner_warn("Returned more than 5 bytes. It is not a TEA5767\n"); + printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n"); return EINVAL; } - tuner_warn("TEA5767 detected.\n"); + printk(KERN_WARNING "TEA5767 detected.\n"); return 0; } -static void tea5767_release(struct tuner *t) +static int tea5767_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; } -static struct tuner_operations tea5767_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = tea5767_signal, - .is_stereo = tea5767_stereo, - .standby = tea5767_standby, - .release = tea5767_release, +static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5767_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tea5767_tuner_ops = { + .info = { + .name = "tea5767", // Philips TEA5767HN FM Radio + }, + + .set_analog_params = set_radio_freq, + .sleep = tea5767_standby, + .release = tea5767_release, + .get_frequency = tea5767_get_frequency, + .get_status = tea5767_get_status, }; -int tea5767_tuner_init(struct tuner *t) +struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct tea5767_priv *priv = NULL; priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); - strlcpy(t->i2c.name, "tea5767", sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, + sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); - return (0); + return fe; } + + +EXPORT_SYMBOL_GPL(tea5767_attach); +EXPORT_SYMBOL_GPL(tea5767_autodetection); + +MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h new file mode 100644 index 000000000000..68e9263badfd --- /dev/null +++ b/drivers/media/video/tea5767.h @@ -0,0 +1,29 @@ +/* + 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 __TEA5767_H__ +#define __TEA5767_H__ + +#include +#include "dvb_frontend.h" + +extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __TEA5767_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 848ee6420c5c..9598a3da85f4 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -22,6 +22,7 @@ #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" +#include "tea5767.h" #define UNSET (-1U) @@ -262,7 +263,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TEA5767: - if (tea5767_tuner_init(t) == EINVAL) { + if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -600,7 +601,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) } break; case 0x60: - if (tea5767_autodetection(t) != EINVAL) { + if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index bcb6a61c2086..664f3467ee4f 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,9 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int tea5767_autodetection(struct tuner *t); -extern int tea5767_tuner_init(struct tuner *t); - /* ------------------------------------------------------------------------ */ #define tuner_warn(fmt, arg...) do {\ From 4adad287de82703fd504fdab7aebe760196bb786 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:59:08 -0300 Subject: [PATCH 0685/2804] V4L/DVB (6133): tuner-simple: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 17 +- drivers/media/video/tuner-driver.h | 2 - drivers/media/video/tuner-simple.c | 294 ++++++++++++++++++----------- drivers/media/video/tuner-simple.h | 35 ++++ 4 files changed, 236 insertions(+), 112 deletions(-) create mode 100644 drivers/media/video/tuner-simple.h diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9598a3da85f4..8ee0be261076 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -17,12 +17,14 @@ #include #include #include +#include #include #include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" #include "tea5767.h" +#include "tuner-simple.h" #define UNSET (-1U) @@ -213,6 +215,15 @@ static void attach_tda8290(struct tuner *t) tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); } +static void attach_simple_tuner(struct tuner *t) +{ + struct simple_tuner_config cfg = { + .type = t->type, + .tun = &tuners[t->type] + }; + simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -290,7 +301,7 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - default_tuner_init(t); + attach_simple_tuner(t); break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; @@ -298,13 +309,13 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0xa4; i2c_master_send(c,buffer,4); - default_tuner_init(t); + attach_simple_tuner(t); break; case TUNER_TDA9887: tda9887_tuner_init(t); break; default: - default_tuner_init(t); + attach_simple_tuner(t); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 664f3467ee4f..28a10da76d12 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -72,8 +72,6 @@ struct tuner { /* ------------------------------------------------------------------------ */ -extern int default_tuner_init(struct tuner *t); - extern int tda9887_tuner_init(struct tuner *t); /* ------------------------------------------------------------------------ */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index eca2ff249a36..2dbd91c8cb64 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,7 +1,8 @@ /* - * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. + * + * This "tuner-simple" module was split apart from the original "tuner" module. */ #include #include @@ -9,7 +10,14 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tuner-simple.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tuner-simple " static int offset = 0; module_param(offset, int, 0664); @@ -85,13 +93,18 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); struct tuner_simple_priv { u16 last_div; struct tuner_i2c_props i2c_props; + + unsigned int type; + struct tunertype *tun; + + u32 frequency; }; /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct tuner *t) +static int tuner_getstatus(struct dvb_frontend *fe) { - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; unsigned char byte; if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1)) @@ -100,18 +113,20 @@ static int tuner_getstatus(struct tuner *t) return byte; } -static int tuner_signal(struct tuner *t) +static int tuner_signal(struct dvb_frontend *fe) { - return (tuner_getstatus(t) & TUNER_SIGNAL) << 13; + return (tuner_getstatus(fe) & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct tuner *t) +static int tuner_stereo(struct dvb_frontend *fe) { + struct tuner_simple_priv *priv = fe->tuner_priv; + int stereo, status; - status = tuner_getstatus(t); + status = tuner_getstatus(fe); - switch (t->type) { + switch (priv->type) { case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: @@ -126,20 +141,38 @@ static int tuner_stereo(struct tuner *t) } +static int simple_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int signal = tuner_signal(fe); + + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tuner_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tuner-simple: Signal strength: %d\n", signal); + + return 0; +} + /* ---------------------------------------------------------------------- */ -static void default_set_tv_freq(struct tuner *t, unsigned int freq) +static int simple_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; u8 config, cb, tuneraddr; u16 div; struct tunertype *tun; u8 buffer[4]; int rc, IFPCoff, i, j; enum param_type desired_type; - struct tuner_params *params; + struct tuner_params *t_params; - tun = &tuners[t->type]; + tun = priv->tun; /* IFPCoff = Video Intermediate Frequency - Vif: 940 =16*58.75 NTSC/J (Japan) @@ -153,14 +186,14 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) 171.2=16*10.70 FM Radio (at set_radio_freq) */ - if (t->std == V4L2_STD_NTSC_M_JP) { + if (params->std == V4L2_STD_NTSC_M_JP) { IFPCoff = 940; desired_type = TUNER_PARAM_TYPE_NTSC; - } else if ((t->std & V4L2_STD_MN) && - !(t->std & ~V4L2_STD_MN)) { + } else if ((params->std & V4L2_STD_MN) && + !(params->std & ~V4L2_STD_MN)) { IFPCoff = 732; desired_type = TUNER_PARAM_TYPE_NTSC; - } else if (t->std == V4L2_STD_SECAM_LC) { + } else if (params->std == V4L2_STD_SECAM_LC) { IFPCoff = 543; desired_type = TUNER_PARAM_TYPE_SECAM; } else { @@ -173,49 +206,49 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) continue; break; } - /* use default tuner_params if desired_type not available */ + /* use default tuner_t_params if desired_type not available */ if (desired_type != tun->params[j].type) { - tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n", - IFPCoff,t->type); + tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n", + IFPCoff, priv->type); j = 0; } - params = &tun->params[j]; + t_params = &tun->params[j]; - for (i = 0; i < params->count; i++) { - if (freq > params->ranges[i].limit) + for (i = 0; i < t_params->count; i++) { + if (params->frequency > t_params->ranges[i].limit) continue; break; } - if (i == params->count) { + if (i == t_params->count) { tuner_dbg("TV frequency out of range (%d > %d)", - freq, params->ranges[i - 1].limit); - freq = params->ranges[--i].limit; + params->frequency, t_params->ranges[i - 1].limit); + params->frequency = t_params->ranges[--i].limit; } - config = params->ranges[i].config; - cb = params->ranges[i].cb; + config = t_params->ranges[i].config; + cb = t_params->ranges[i].cb; /* i == 0 -> VHF_LO * i == 1 -> VHF_HI * i == 2 -> UHF */ tuner_dbg("tv: param %d, range %d\n",j,i); - div=freq + IFPCoff + offset; + div=params->frequency + IFPCoff + offset; tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n", - freq / 16, freq % 16 * 100 / 16, + params->frequency / 16, params->frequency % 16 * 100 / 16, IFPCoff / 16, IFPCoff % 16 * 100 / 16, offset / 16, offset % 16 * 100 / 16, div); /* tv norm specific stuff for multi-norm tuners */ - switch (t->type) { + switch (priv->type) { case TUNER_PHILIPS_SECAM: // FI1216MF /* 0x01 -> ??? no change ??? */ /* 0x02 -> PAL BDGHI / SECAM L */ /* 0x04 -> ??? PAL others / SECAM others ??? */ cb &= ~0x03; - if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM + if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM cb |= PHILIPS_MF_SET_STD_L; - else if (t->std & V4L2_STD_SECAM_LC) + else if (params->std & V4L2_STD_SECAM_LC) cb |= PHILIPS_MF_SET_STD_LC; else /* V4L2_STD_B|V4L2_STD_GH */ cb |= PHILIPS_MF_SET_STD_BG; @@ -224,16 +257,16 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) case TUNER_TEMIC_4046FM5: cb &= ~0x0f; - if (t->std & V4L2_STD_PAL_BG) { + if (params->std & V4L2_STD_PAL_BG) { cb |= TEMIC_SET_PAL_BG; - } else if (t->std & V4L2_STD_PAL_I) { + } else if (params->std & V4L2_STD_PAL_I) { cb |= TEMIC_SET_PAL_I; - } else if (t->std & V4L2_STD_PAL_DK) { + } else if (params->std & V4L2_STD_PAL_DK) { cb |= TEMIC_SET_PAL_DK; - } else if (t->std & V4L2_STD_SECAM_L) { + } else if (params->std & V4L2_STD_SECAM_L) { cb |= TEMIC_SET_PAL_L; } @@ -242,13 +275,13 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) case TUNER_PHILIPS_FQ1216ME: cb &= ~0x0f; - if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { + if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { cb |= PHILIPS_SET_PAL_BGDK; - } else if (t->std & V4L2_STD_PAL_I) { + } else if (params->std & V4L2_STD_PAL_I) { cb |= PHILIPS_SET_PAL_I; - } else if (t->std & V4L2_STD_SECAM_L) { + } else if (params->std & V4L2_STD_SECAM_L) { cb |= PHILIPS_SET_PAL_L; } @@ -260,7 +293,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) /* 0x02 -> NTSC antenna input 1 */ /* 0x03 -> NTSC antenna input 2 */ cb &= ~0x03; - if (!(t->std & V4L2_STD_ATSC)) + if (!(params->std & V4L2_STD_ATSC)) cb |= 2; /* FIXME: input */ break; @@ -280,7 +313,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) buffer[2] = 0x17; buffer[3] = 0x00; cb &= ~0x40; - if (t->std & V4L2_STD_ATSC) { + if (params->std & V4L2_STD_ATSC) { cb |= 0x40; buffer[1] = 0x04; } @@ -296,7 +329,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) break; } - if (params->cb_first_if_lower_freq && div < priv->last_div) { + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = config; buffer[1] = cb; buffer[2] = (div>>8) & 0x7f; @@ -308,42 +341,42 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) buffer[3] = cb; } priv->last_div = div; - if (params->has_tda9887) { + if (t_params->has_tda9887) { int config = 0; - int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && - !(t->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); + int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && + !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); - if (t->std == V4L2_STD_SECAM_LC) { - if (params->port1_active ^ params->port1_invert_for_secam_lc) + if (params->std == V4L2_STD_SECAM_LC) { + if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active ^ params->port2_invert_for_secam_lc) + if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) config |= TDA9887_PORT2_ACTIVE; } else { - if (params->port1_active) + if (t_params->port1_active) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active) + if (t_params->port2_active) config |= TDA9887_PORT2_ACTIVE; } - if (params->intercarrier_mode) + if (t_params->intercarrier_mode) config |= TDA9887_INTERCARRIER; if (is_secam_l) { - if (i == 0 && params->default_top_secam_low) - config |= TDA9887_TOP(params->default_top_secam_low); - else if (i == 1 && params->default_top_secam_mid) - config |= TDA9887_TOP(params->default_top_secam_mid); - else if (params->default_top_secam_high) - config |= TDA9887_TOP(params->default_top_secam_high); + if (i == 0 && t_params->default_top_secam_low) + config |= TDA9887_TOP(t_params->default_top_secam_low); + else if (i == 1 && t_params->default_top_secam_mid) + config |= TDA9887_TOP(t_params->default_top_secam_mid); + else if (t_params->default_top_secam_high) + config |= TDA9887_TOP(t_params->default_top_secam_high); } else { - if (i == 0 && params->default_top_low) - config |= TDA9887_TOP(params->default_top_low); - else if (i == 1 && params->default_top_mid) - config |= TDA9887_TOP(params->default_top_mid); - else if (params->default_top_high) - config |= TDA9887_TOP(params->default_top_high); + if (i == 0 && t_params->default_top_low) + config |= TDA9887_TOP(t_params->default_top_low); + else if (i == 1 && t_params->default_top_mid) + config |= TDA9887_TOP(t_params->default_top_mid); + else if (t_params->default_top_high) + config |= TDA9887_TOP(t_params->default_top_high); } - if (params->default_pll_gating_18) + if (t_params->default_pll_gating_18) config |= TDA9887_GATING_18; i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } @@ -353,7 +386,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); - switch (t->type) { + switch (priv->type) { case TUNER_LG_TDVS_H06XF: /* Set the Auxiliary Byte. */ buffer[0] = buffer[2]; @@ -374,7 +407,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) /* Wait until the PLL locks */ for (;;) { if (time_after(jiffies,timeout)) - return; + return 0; if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) { tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); break; @@ -398,27 +431,30 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) break; } } + return 0; } -static void default_set_radio_freq(struct tuner *t, unsigned int freq) +static int simple_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { struct tunertype *tun; - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; u8 buffer[4]; u16 div; int rc, j; - struct tuner_params *params; + struct tuner_params *t_params; + unsigned int freq = params->frequency; - tun = &tuners[t->type]; + tun = priv->tun; for (j = tun->count-1; j > 0; j--) if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) break; - /* default params (j=0) will be used if desired type wasn't found */ - params = &tun->params[j]; + /* default t_params (j=0) will be used if desired type wasn't found */ + t_params = &tun->params[j]; /* Select Radio 1st IF used */ - switch (params->radio_if) { + switch (t_params->radio_if) { case 0: /* 10.7 MHz */ freq += (unsigned int)(10.7*16000); break; @@ -429,16 +465,16 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) freq += (unsigned int)(41.3*16000); break; default: - tuner_warn("Unsupported radio_if value %d\n", params->radio_if); - return; + tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if); + return 0; } /* Bandswitch byte */ - switch (t->type) { + switch (priv->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - tuner_dbg ("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); - return; + tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); + return 0; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: @@ -461,7 +497,7 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) break; } - buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | + buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps @@ -469,7 +505,7 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) freq * (1/800) */ div = (freq + 400) / 800; - if (params->cb_first_if_lower_freq && div < priv->last_div) { + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; buffer[2] = (div>>8) & 0x7f; @@ -483,61 +519,105 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) buffer[0],buffer[1],buffer[2],buffer[3]); priv->last_div = div; - if (params->has_tda9887) { + if (t_params->has_tda9887) { int config = 0; - if (params->port1_active && !params->port1_fm_high_sensitivity) + if (t_params->port1_active && !t_params->port1_fm_high_sensitivity) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active && !params->port2_fm_high_sensitivity) + if (t_params->port2_active && !t_params->port2_fm_high_sensitivity) config |= TDA9887_PORT2_ACTIVE; - if (params->intercarrier_mode) + if (t_params->intercarrier_mode) config |= TDA9887_INTERCARRIER; -/* if (params->port1_set_for_fm_mono) +/* if (t_params->port1_set_for_fm_mono) config &= ~TDA9887_PORT1_ACTIVE;*/ - if (params->fm_gain_normal) + if (t_params->fm_gain_normal) config |= TDA9887_GAIN_NORMAL; - if (params->radio_if == 2) + if (t_params->radio_if == 2) config |= TDA9887_RIF_41_3; i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); + + return 0; } -static void tuner_release(struct tuner *t) +static int simple_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - kfree(t->priv); - t->priv = NULL; + struct tuner_simple_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = simple_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = simple_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; } -static struct tuner_operations simple_tuner_ops = { - .set_tv_freq = default_set_tv_freq, - .set_radio_freq = default_set_radio_freq, - .has_signal = tuner_signal, - .is_stereo = tuner_stereo, - .release = tuner_release, + +static int simple_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops simple_tuner_ops = { + .set_analog_params = simple_set_params, + .release = simple_release, + .get_frequency = simple_get_frequency, + .get_status = simple_get_status, }; -int default_tuner_init(struct tuner *t) +struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg) { struct tuner_simple_priv *priv = NULL; priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->type = cfg->type; + priv->tun = cfg->tun; - tuner_info("type set to %d (%s)\n", - t->type, tuners[t->type].name); - strlcpy(t->i2c.name, tuners[t->type].name, sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name); - return 0; + strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name)); + + return fe; } + +EXPORT_SYMBOL_GPL(simple_tuner_attach); + +MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h new file mode 100644 index 000000000000..75cd45b7145d --- /dev/null +++ b/drivers/media/video/tuner-simple.h @@ -0,0 +1,35 @@ +/* + 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 __TUNER_SIMPLE_H__ +#define __TUNER_SIMPLE_H__ + +#include +#include "dvb_frontend.h" + +struct simple_tuner_config +{ + /* chip type */ + unsigned int type; + struct tunertype *tun; +}; + +extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg); + +#endif /* __TUNER_SIMPLE_H__ */ From ca805d57cf5ea7482ed3da28653f30621249ee45 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:59:35 -0300 Subject: [PATCH 0686/2804] V4L/DVB (6134): tuner: alter build to produce separate modules Break tuner.ko into separate modules. This was a quick change - Tuner sub-drivers are still static-linked to tuner.ko, this will change after using dvb_attach and removing the probing functions. After this change, one can deselect undesired tuner sub-drivers via Kconfig. Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 56 ++++++++++++++++++++++++++++++ drivers/media/video/Kconfig | 9 ----- drivers/media/video/Makefile | 12 ++++--- drivers/media/video/mt20xx.h | 10 ++++++ drivers/media/video/tda8290.h | 19 ++++++++++ drivers/media/video/tea5761.h | 19 ++++++++++ drivers/media/video/tea5767.h | 18 ++++++++++ drivers/media/video/tuner-simple.h | 11 ++++++ 8 files changed, 141 insertions(+), 13 deletions(-) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index d9d033e07e19..3f8cfa873de5 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -69,6 +69,62 @@ source "drivers/media/common/Kconfig" config VIDEO_TUNER tristate depends on I2C + select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE + +menuconfig VIDEO_TUNER_CUSTOMIZE + bool "Customize analog tuner modules to build" + depends on VIDEO_TUNER + help + This allows the user to deselect tuner drivers unnecessary + for their hardware from the build. Use this option with care + as deselecting tuner drivers which are in fact necessary will + result in V4L devices which cannot be tuned due to lack of + driver support + + If unsure say N. + +if VIDEO_TUNER_CUSTOMIZE + +config TUNER_MT20XX + tristate "Microtune 2032 / 2050 tuners" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the MT2032 / MT2050 tuner. + +config TUNER_TDA8290 + tristate "TDA 8290+8275(a) tuner combo" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA8290+8275(a) tuner. + +config TUNER_TEA5761 + tristate "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on I2C && EXPERIMENTAL + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5761 radio tuner. + +config TUNER_TEA5767 + tristate "TEA 5767 radio tuner" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5767 radio tuner. + +config TUNER_SIMPLE + tristate "Simple tuner support" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for various simple tuners. + +endif # VIDEO_TUNER_CUSTOMIZE config VIDEO_BUF depends on PCI diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 0e1d2ccc4e81..04756c342cba 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -505,15 +505,6 @@ config TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. If in doubt, say N. -config TUNER_TEA5761 - bool "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on I2C - select VIDEO_TUNER - help - Say Y here to include support for Philips TEA5761 radio tuner. - If in doubt, say N. - config VIDEO_VINO tristate "SGI Vino Video For Linux (EXPERIMENTAL)" depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 113e525f6dab..00699c36ec1a 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -4,10 +4,7 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \ - mt20xx.o tda8290.o tea5767.o tda9887.o - -tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o +tuner-objs := tuner-core.o tuner-types.o tda9887.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o @@ -83,6 +80,13 @@ obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o + +obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o +obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o +obj-$(CONFIG_TUNER_TDA8290) += tda8290.o +obj-$(CONFIG_TUNER_TEA5767) += tea5767.o +obj-$(CONFIG_TUNER_TEA5761) += tea5761.o + obj-$(CONFIG_VIDEO_BUF) += video-buf.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h index 877dbef891ea..5e9c825d2e91 100644 --- a/drivers/media/video/mt20xx.h +++ b/drivers/media/video/mt20xx.h @@ -20,8 +20,18 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE)) extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __MT20XX_H__ */ diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 815ca1c78f80..107b24b05aa1 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -26,10 +26,29 @@ struct tda8290_config int (*tuner_callback) (void *dev, int command,int arg); }; +#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); + extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr, struct tda8290_config *cfg); +#else +static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TDA8290_H__ */ diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h index f287c0291bff..73a03b427843 100644 --- a/drivers/media/video/tea5761.h +++ b/drivers/media/video/tea5761.h @@ -20,9 +20,28 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TEA5761_H__ */ diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h index 68e9263badfd..5d78281adcc2 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/video/tea5767.h @@ -20,10 +20,28 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TEA5767_H__ */ diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h index 75cd45b7145d..9089939a8c02 100644 --- a/drivers/media/video/tuner-simple.h +++ b/drivers/media/video/tuner-simple.h @@ -27,9 +27,20 @@ struct simple_tuner_config struct tunertype *tun; }; +#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE)) extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, struct simple_tuner_config *cfg); +#else +static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TUNER_SIMPLE_H__ */ From 8fb3b9f7a9e0420150bf6cb8a3c20f45d372cce4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 30 Aug 2007 23:00:43 -0300 Subject: [PATCH 0687/2804] V4L/DVB (6136): dvb_frontend: add get_rf_strength function pointer to dvb_tuner_ops Add get_rf_strength function pointer to dvb_tuner_ops, so that rf signal strength can be read directly from the tuner driver by the dvb demodulator driver and / or the analog tuning system. This is an internal api addition -- userspace is not affected. Signed-off-by: Michael Krufky Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index ffb83b0f68c3..a5262e852c82 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -90,6 +90,7 @@ struct dvb_tuner_ops { #define TUNER_STATUS_LOCKED 1 #define TUNER_STATUS_STEREO 2 int (*get_status)(struct dvb_frontend *fe, u32 *status); + int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); /** These are provided seperately from set_params in order to facilitate silicon * tuners which require sophisticated tuning loops, controlling each parameter seperately. */ From 735f0b9af1748602bb7f3a8009c31cf5f133eec8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:39:39 -0300 Subject: [PATCH 0688/2804] V4L/DVB (6137): tuner-simple: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 58 ++++++++++++++++++------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 2dbd91c8cb64..7b93d3b1f4c6 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -102,7 +102,7 @@ struct tuner_simple_priv { /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct dvb_frontend *fe) +static int tuner_read_status(struct dvb_frontend *fe) { struct tuner_simple_priv *priv = fe->tuner_priv; unsigned char byte; @@ -113,47 +113,60 @@ static int tuner_getstatus(struct dvb_frontend *fe) return byte; } -static int tuner_signal(struct dvb_frontend *fe) +static inline int tuner_signal(const int status) { - return (tuner_getstatus(fe) & TUNER_SIGNAL) << 13; + return (status & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct dvb_frontend *fe) +static inline int tuner_stereo(const int type, const int status) { - struct tuner_simple_priv *priv = fe->tuner_priv; - - int stereo, status; - - status = tuner_getstatus(fe); - - switch (priv->type) { + switch (type) { case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: case TUNER_LG_NTSC_TAPE: - stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); - break; + return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); default: - stereo = status & TUNER_STEREO; + return status & TUNER_STEREO; } +} - return stereo; +static inline int tuner_islocked(const int status) +{ + return (status & TUNER_FL); +} + +static inline int tuner_afcstatus(const int status) +{ + return (status & TUNER_AFC) - 2; } static int simple_get_status(struct dvb_frontend *fe, u32 *status) { struct tuner_simple_priv *priv = fe->tuner_priv; - int signal = tuner_signal(fe); + int tuner_status = tuner_read_status(fe); *status = 0; - if (signal) + if (tuner_islocked(tuner_status)) *status = TUNER_STATUS_LOCKED; - if (tuner_stereo(fe)) + if (tuner_stereo(priv->type, tuner_status)) *status |= TUNER_STATUS_STEREO; - tuner_dbg("tuner-simple: Signal strength: %d\n", signal); + tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); + + return 0; +} + +static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int signal = tuner_signal(tuner_read_status(fe)); + + *strength = signal; + + tuner_dbg("Signal strength: %d\n", signal); return 0; } @@ -580,9 +593,10 @@ static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) static struct dvb_tuner_ops simple_tuner_ops = { .set_analog_params = simple_set_params, - .release = simple_release, - .get_frequency = simple_get_frequency, - .get_status = simple_get_status, + .release = simple_release, + .get_frequency = simple_get_frequency, + .get_status = simple_get_status, + .get_rf_strength = simple_get_rf_strength, }; struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, From fd443f7444180c1cd9cbcb816ebf65c8b8e35301 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:39:57 -0300 Subject: [PATCH 0689/2804] V4L/DVB (6138): tea5761: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5761.c | 64 ++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 8cdaf474ffdd..2150222a3860 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -177,49 +177,66 @@ static int set_radio_freq(struct dvb_frontend *fe, return 0; } -static int tea5761_signal(struct dvb_frontend *fe) +static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) { - unsigned char buffer[16]; - int rc; struct tea5761_priv *priv = fe->tuner_priv; + int rc; - memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + memset(buffer, 0, 16); + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { + tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); + return -EREMOTEIO; + } - return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); + return 0; } -static int tea5761_stereo(struct dvb_frontend *fe) +static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) { - unsigned char buffer[16]; - int rc; struct tea5761_priv *priv = fe->tuner_priv; - memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); - rc = buffer[9] & TEA5761_TUNCHECK_STEREO; + tuner_dbg("Signal strength: %d\n", signal); - tuner_dbg("TEA5761 radio ST GET = %02x\n", rc); + return signal; +} - return (rc ? V4L2_TUNER_SUB_STEREO : 0); +static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; + + int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); } static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) { - struct tea5761_priv *priv = fe->tuner_priv; - int signal = tea5761_signal(fe); + unsigned char buffer[16]; *status = 0; - if (signal) - *status = TUNER_STATUS_LOCKED; - if (tea5761_stereo(fe)) - *status |= TUNER_STATUS_STEREO; + if (0 == tea5761_read_status(fe, buffer)) { + if (tea5761_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5761_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } - tuner_dbg("tea5761: Signal strength: %d\n", signal); + return 0; +} + +static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[16]; + + *strength = 0; + + if (0 == tea5761_read_status(fe, buffer)) + *strength = tea5761_signal(fe, buffer); return 0; } @@ -266,6 +283,7 @@ static struct dvb_tuner_ops tea5761_tuner_ops = { .release = tea5761_release, .get_frequency = tea5761_get_frequency, .get_status = tea5761_get_status, + .get_rf_strength = tea5761_get_rf_strength, }; struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, From 6b897f2c3982af51134ba83f4b6de71d28d35944 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:40:14 -0300 Subject: [PATCH 0690/2804] V4L/DVB (6139): tea5767: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 63 +++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index cf908d853195..71df419df7bc 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -264,48 +264,66 @@ static int set_radio_freq(struct dvb_frontend *fe, return 0; } -static int tea5767_signal(struct dvb_frontend *fe) +static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) { - unsigned char buffer[5]; - int rc; struct tea5767_priv *priv = fe->tuner_priv; + int rc; - memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) + memset(buffer, 0, 5); + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + return -EREMOTEIO; + } - return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); + return 0; } -static int tea5767_stereo(struct dvb_frontend *fe) +static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) { - unsigned char buffer[5]; - int rc; struct tea5767_priv *priv = fe->tuner_priv; - memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); - rc = buffer[2] & TEA5767_STEREO_MASK; + tuner_dbg("Signal strength: %d\n", signal); - tuner_dbg("radio ST GET = %02x\n", rc); + return signal; +} - return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); +static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + int stereo = buffer[2] & TEA5767_STEREO_MASK; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); } static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) { - struct tea5767_priv *priv = fe->tuner_priv; - int signal = tea5767_signal(fe); + unsigned char buffer[5]; + *status = 0; - if (signal) - *status = TUNER_STATUS_LOCKED; - if (tea5767_stereo(fe)) - *status |= TUNER_STATUS_STEREO; + if (0 == tea5767_read_status(fe, buffer)) { + if (tea5767_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5767_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } - tuner_dbg("tea5767: Signal strength: %d\n", signal); + return 0; +} + +static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[5]; + + *strength = 0; + + if (0 == tea5767_read_status(fe, buffer)) + *strength = tea5767_signal(fe, buffer); return 0; } @@ -393,6 +411,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = { .release = tea5767_release, .get_frequency = tea5767_get_frequency, .get_status = tea5767_get_status, + .get_rf_strength = tea5767_get_rf_strength, }; struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, From 3782e050f8860fb701d4cb14df16cd4ed9cce2d2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 17:53:00 -0300 Subject: [PATCH 0691/2804] V4L/DVB (6140): tda8290: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index ec731d6fbfb8..0e5cf459d3ed 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -553,27 +553,35 @@ static int tda8290_set_params(struct dvb_frontend *fe, static int tda8290_has_signal(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->tuner_priv; + int ret; unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; + /* for now, report based on afc status */ tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); - return (afc & 0x80)? 65535:0; + + ret = (afc & 0x80) ? 65535 : 0; + + tuner_dbg("AFC status: %d\n", ret); + + return ret; } static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) { - struct tda8290_priv *priv = fe->tuner_priv; - - int signal = tda8290_has_signal(fe); *status = 0; - /* for now, report based on afc status */ - if (signal) + if (tda8290_has_signal(fe)) *status = TUNER_STATUS_LOCKED; - tuner_dbg("tda8290: AFC status: %d\n", signal); + return 0; +} + +static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + *strength = tda8290_has_signal(fe); return 0; } @@ -656,6 +664,7 @@ static struct dvb_tuner_ops tda8290_tuner_ops = { .release = tda8290_release, .get_frequency = tda8290_get_frequency, .get_status = tda8290_get_status, + .get_rf_strength = tda8290_get_rf_strength, }; struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, From 1f5ef19779df2c2f75870332b37dd3004c08a515 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 17:38:02 -0300 Subject: [PATCH 0692/2804] V4L/DVB (6141): tuner: use get_rf_strength instead of get_status to determine signal strength Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 8ee0be261076..2f74379f4e4b 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -110,6 +110,17 @@ static void fe_standby(struct tuner *t) fe_tuner_ops->sleep(&t->fe); } +static int fe_has_signal(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + u16 strength; + + if (fe_tuner_ops->get_rf_strength) + fe_tuner_ops->get_rf_strength(&t->fe, &strength); + + return strength; +} + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { @@ -326,6 +337,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->ops.set_radio_freq = fe_set_freq; t->ops.standby = fe_standby; t->ops.release = fe_release; + t->ops.has_signal = fe_has_signal; } tuner_info("type set to %s\n", t->i2c.name); @@ -807,12 +819,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); - if (tuner_status & TUNER_STATUS_STEREO) - vt->flags |= VIDEO_TUNER_STEREO_ON; - else - vt->flags &= ~VIDEO_TUNER_STEREO_ON; - vt->signal = tuner_status & TUNER_STATUS_LOCKED - ? 65535 : 0; + if (tuner_status & TUNER_STATUS_STEREO) + vt->flags |= VIDEO_TUNER_STEREO_ON; + else + vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { if (t->ops.is_stereo) { if (t->ops.is_stereo(t)) @@ -822,9 +832,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) vt->flags &= ~VIDEO_TUNER_STEREO_ON; } - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); } + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); + vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ vt->rangelow = radio_range[0] * 16000; @@ -948,15 +959,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - tuner->signal = tuner_status & TUNER_STATUS_LOCKED ? 65535 : 0; } else { if (t->ops.is_stereo) { tuner->rxsubchans = t->ops.is_stereo(t) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); } + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; From f61b48f7a838bb3d089b12fc9d03fd53c9ef5022 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 1 Sep 2007 02:02:51 -0300 Subject: [PATCH 0693/2804] V4L/DVB (6142): cx25840: fix build warning Fix the following build warning: CC [M] cx25840-core.o cx25840-core.c: In function 'init_dll1': cx25840-core.c:147: warning: implicit declaration of function 'udelay' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 90f7859bb48e..15f191e170d2 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include From 275511a0aca8483c03df1c6e3a33a27cee334709 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sun, 11 Mar 2007 20:44:05 -0300 Subject: [PATCH 0694/2804] V4L/DVB (6149): Add I2C_HW_B_CX23885 for Conexant 23885/23887 PCIe bridge Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- include/linux/i2c-id.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 4891e03ad23a..a271b67a8e2d 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -197,6 +197,7 @@ #define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */ #define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */ #define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */ +#define I2C_HW_B_CX23885 0x010022 /* conexant 23885 based tv cards (bus1) */ /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x020000 /* Parallel port interface */ From d19770e5178a4bc49641711246360c25781d20a4 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sun, 11 Mar 2007 20:44:05 -0300 Subject: [PATCH 0695/2804] V4L/DVB (6150): Add CX23885/CX23887 PCIe bridge driver This is a new framework to support boards based on the CX23885/7 PCIe bridge. The framework supports digital (no analog yet) Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 1 + drivers/media/video/cx23885/Kconfig | 17 + drivers/media/video/cx23885/Makefile | 9 + drivers/media/video/cx23885/cx23885-cards.c | 198 +++ drivers/media/video/cx23885/cx23885-core.c | 1601 +++++++++++++++++++ drivers/media/video/cx23885/cx23885-dvb.c | 199 +++ drivers/media/video/cx23885/cx23885-i2c.c | 375 +++++ drivers/media/video/cx23885/cx23885-reg.h | 429 +++++ drivers/media/video/cx23885/cx23885.h | 295 ++++ 9 files changed, 3124 insertions(+) create mode 100644 drivers/media/video/cx23885/Kconfig create mode 100644 drivers/media/video/cx23885/Makefile create mode 100644 drivers/media/video/cx23885/cx23885-cards.c create mode 100644 drivers/media/video/cx23885/cx23885-core.c create mode 100644 drivers/media/video/cx23885/cx23885-dvb.c create mode 100644 drivers/media/video/cx23885/cx23885-i2c.c create mode 100644 drivers/media/video/cx23885/cx23885-reg.h create mode 100644 drivers/media/video/cx23885/cx23885.h diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 00699c36ec1a..9e99d2e1c1bd 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -124,5 +124,6 @@ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o +obj-$(CONFIG_VIDEO_CX23885) += cx23885/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig new file mode 100644 index 000000000000..ea53466dacbe --- /dev/null +++ b/drivers/media/video/cx23885/Kconfig @@ -0,0 +1,17 @@ +config VIDEO_CX23885 + tristate "Conexant cx23885 (2388x successor) support" + depends on VIDEO_DEV && PCI && I2C + select I2C_ALGOBIT + select FW_LOADER + select VIDEO_BTCX + select VIDEO_BUF + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_IR + ---help--- + This is a video4linux driver for Conexant 23885 based + TV cards. + + To compile this driver as a module, choose M here: the + module will be called cx23885 + diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile new file mode 100644 index 000000000000..665067022d2a --- /dev/null +++ b/drivers/media/video/cx23885/Makefile @@ -0,0 +1,9 @@ +cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o + +obj-$(CONFIG_VIDEO_CX23885) += cx23885.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c new file mode 100644 index 000000000000..9344fb5d95f6 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -0,0 +1,198 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "cx23885.h" + +/* ------------------------------------------------------------------ */ +/* board config info */ + +struct cx23885_board cx23885_boards[] = { + [CX23885_BOARD_UNKNOWN] = { + .name = "UNKNOWN/GENERIC", + .bridge = CX23885_BRIDGE_UNDEFINED, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 0, + },{ + .type = CX23885_VMUX_COMPOSITE2, + .vmux = 1, + },{ + .type = CX23885_VMUX_COMPOSITE3, + .vmux = 2, + },{ + .type = CX23885_VMUX_COMPOSITE4, + .vmux = 3, + }}, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { + .name = "Hauppauge WinTV-HVR1800lp", + .bridge = CX23885_BRIDGE_885, + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1800] = { + .name = "Hauppauge WinTV-HVR1800", + .bridge = CX23885_BRIDGE_887, + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, +}; +const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); + +/* ------------------------------------------------------------------ */ +/* PCI subsystem IDs */ + +struct cx23885_subid cx23885_subids[] = { + { + .subvendor = 0x0070, + .subdevice = 0x3400, + .card = CX23885_BOARD_UNKNOWN, + },{ + .subvendor = 0x0070, + .subdevice = 0x7600, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp, + },{ + .subvendor = 0x0070, + .subdevice = 0x7800, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + },{ + .subvendor = 0x0070, + .subdevice = 0x7801, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + }, +}; +const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); + +void cx23885_card_list(struct cx23885_dev *dev) +{ + int i; + + if (0 == dev->pci->subsystem_vendor && + 0 == dev->pci->subsystem_device) { + printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n" + "%s: be autodetected. Please pass card= insmod option to\n" + "%s: workaround that. Redirect complaints to the vendor of\n" + "%s: the TV card. Best regards,\n" + "%s: -- tux\n", + dev->name, dev->name, dev->name, dev->name, dev->name); + } else { + printk("%s: Your board isn't known (yet) to the driver. You can\n" + "%s: try to pick one of the existing card configs via\n" + "%s: card= insmod option. Updating to the latest\n" + "%s: version might help as well.\n", + dev->name, dev->name, dev->name, dev->name); + } + printk("%s: Here is a list of valid choices for the card= insmod option:\n", + dev->name); + for (i = 0; i < cx23885_bcount; i++) + printk("%s: card=%d -> %s\n", + dev->name, i, cx23885_boards[i].name); +} + +static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data); + + + /* Make sure we support the board model */ + switch (tv.model) + { + case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ + case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + break; + default: + printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + dev->name, tv.model); +} + +void cx23885_card_setup(struct cx23885_dev *dev) +{ + static u8 eeprom[256]; + + if (dev->i2c_bus[0].i2c_rc == 0) { + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); + } + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + if (dev->i2c_bus[0].i2c_rc == 0) + hauppauge_eeprom(dev, eeprom+0x80); + break; + } +} + +/* ------------------------------------------------------------------ */ + +EXPORT_SYMBOL(cx23885_boards); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c new file mode 100644 index 000000000000..876d396fb7a3 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -0,0 +1,1601 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" + +MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); +MODULE_AUTHOR("Steven Toth "); +MODULE_LICENSE("GPL"); + +static unsigned int debug = 0; +module_param(debug,int,0644); +MODULE_PARM_DESC(debug,"enable debug messages"); + +static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card,"card type"); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) + +static unsigned int cx23885_devcount; + +static DEFINE_MUTEX(devlist); +static LIST_HEAD(cx23885_devlist); + +#define NO_SYNC_LINE (-1U) + +/* + * CX23885 Assumptions + * 1 line = 16 bytes of CDT + * cmds size = 80 + * cdt size = 16 * linesize + * iqsize = 64 + * maxlines = 6 + * + * Address Space: + * 0x00000000 0x00008fff FIFO clusters + * 0x00010000 0x000104af Channel Management Data Structures + * 0x000104b0 0x000104ff Free + * 0x00010500 0x000108bf 15 channels * iqsize + * 0x000108c0 0x000108ff Free + * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables + * 15 channels * (iqsize + (maxlines * linesize)) + * 0x00010ea0 0x00010xxx Free + */ + +struct sram_channel cx23885_sram_channels[] = { + [SRAM_CH01] = { + .name = "test ch1", + .cmds_start = 0x10000, + .ctrl_start = 0x10500, + .cdt = 0x10900, + .fifo_start = 0x3000, + .fifo_size = 0x1000, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + .jumponly = 1, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "ch3", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10680, + .cdt = 0x10480, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + +/* FIXME, these allocations will change when + * analog arrives. The be reviewed. + * CX23887 Assumptions + * 1 line = 16 bytes of CDT + * cmds size = 80 + * cdt size = 16 * linesize + * iqsize = 64 + * maxlines = 6 + * + * Address Space: + * 0x00000000 0x00008fff FIFO clusters + * 0x00010000 0x000104af Channel Management Data Structures + * 0x000104b0 0x000104ff Free + * 0x00010500 0x000108bf 15 channels * iqsize + * 0x000108c0 0x000108ff Free + * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables + * 15 channels * (iqsize + (maxlines * linesize)) + * 0x00010ea0 0x00010xxx Free + */ + +struct sram_channel cx23887_sram_channels[] = { + [SRAM_CH01] = { + .name = "test ch1", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "ch3", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10680, + .cdt = 0x10480, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + +static int cx23885_risc_decode(u32 risc) +{ + static char *instr[16] = { + [ RISC_SYNC >> 28 ] = "sync", + [ RISC_WRITE >> 28 ] = "write", + [ RISC_WRITEC >> 28 ] = "writec", + [ RISC_READ >> 28 ] = "read", + [ RISC_READC >> 28 ] = "readc", + [ RISC_JUMP >> 28 ] = "jump", + [ RISC_SKIP >> 28 ] = "skip", + [ RISC_WRITERM >> 28 ] = "writerm", + [ RISC_WRITECM >> 28 ] = "writecm", + [ RISC_WRITECR >> 28 ] = "writecr", + }; + static int incr[16] = { + [ RISC_WRITE >> 28 ] = 3, // 2 + [ RISC_JUMP >> 28 ] = 3, // 2 + [ RISC_SKIP >> 28 ] = 1, + [ RISC_SYNC >> 28 ] = 1, + [ RISC_WRITERM >> 28 ] = 3, + [ RISC_WRITECM >> 28 ] = 3, + [ RISC_WRITECR >> 28 ] = 4, + }; + static char *bits[] = { + "12", "13", "14", "resync", + "cnt0", "cnt1", "18", "19", + "20", "21", "22", "23", + "irq1", "irq2", "eol", "sol", + }; + int i; + + printk("0x%08x [ %s", risc, + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + if (risc & (1 << (i + 12))) + printk(" %s",bits[i]); + printk(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + +void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) + break; + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + do_gettimeofday(&buf->vb.ts); + dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, + count, buf->count); + buf->vb.state = STATE_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + if (list_empty(&q->active)) { + del_timer(&q->timeout); + } else { + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + } + if (bc != 1) + printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); +} +void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch); + +int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i,lines; + u32 cdt; + + if (ch->cmds_start == 0) + { + dprintk(1, "%s() Erasing channel [%s]\n",__FUNCTION__, ch->name); + cx_write(ch->ptr1_reg, 0); + cx_write(ch->ptr2_reg, 0); + cx_write(ch->cnt2_reg, 0); + cx_write(ch->cnt1_reg, 0); + return 0; + } else { + dprintk(1, "%s() Configuring channel [%s]\n",__FUNCTION__, ch->name); + } + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + if (lines > 6) + lines = 6; + BUG_ON(lines < 2); + + cx_write(8+0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); + cx_write(8+4, cpu_to_le32(8) ); + cx_write(8+8, cpu_to_le32(0) ); + + /* write CDT */ + for (i = 0; i < lines; i++) { + dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, ch->fifo_start + bpl*i); + cx_write(cdt + 16*i, ch->fifo_start + bpl*i); + cx_write(cdt + 16*i + 4, 0); + cx_write(cdt + 16*i + 8, 0); + cx_write(cdt + 16*i + 12, 0); + } + + /* write CMDS */ + if (ch->jumponly) + cx_write(ch->cmds_start + 0, 8); + else + cx_write(ch->cmds_start + 0, risc); + cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ + cx_write(ch->cmds_start + 8, cdt); + cx_write(ch->cmds_start + 12, (lines*16) >> 3); + cx_write(ch->cmds_start + 16, ch->ctrl_start); + if (ch->jumponly) + cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) ); + else + cx_write(ch->cmds_start + 20, 64 >> 2); + for (i = 24; i < 80; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt2_reg, (lines*16) >> 3); + cx_write(ch->cnt1_reg, (bpl >> 3) -1); + + dprintk(2,"[bridged %d] sram setup %s: bpl=%d lines=%d\n", + cx23885_boards[dev->board].bridge, + ch->name, + bpl, + lines); + + return 0; +} + +void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch) +{ + static char *name[] = { + "init risc lo", + "init risc hi", + "cdt base", + "cdt size", + "iq base", + "iq size", + "risc pc lo", + "risc pc hi", + "iq wr ptr", + "iq rd ptr", + "cdt current", + "pci target lo", + "pci target hi", + "line / byte", + }; + u32 risc; + unsigned int i,j,n; + + printk("%s: %s - dma channel status dump\n", + dev->name, ch->name); + for (i = 0; i < ARRAY_SIZE(name); i++) + printk("%s: cmds: %-15s: 0x%08x\n", + dev->name, name[i], + cx_read(ch->cmds_start + 4*i)); + + for (i = 0; i < 4; i++) { + risc = cx_read(ch->cmds_start + 4 * (i+14)); + printk("%s: risc%d: ", dev->name, i); + cx23885_risc_decode(risc); + } + for (i = 0; i < (64 >> 2); i += n) { + risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */ + printk("%s: (0x%08x) iq %x: ", dev->name, ch->ctrl_start + 4 * i, i); + n = cx23885_risc_decode(risc); + for (j = 1; j < n; j++) { + risc = cx_read(ch->ctrl_start + 4 * (i+j)); + printk("%s: iq %x: 0x%08x [ arg #%d ]\n", + dev->name, i+j, risc, j); + } + } + + printk("%s: fifo: 0x%08x -> 0x%x\n", + dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); + printk("%s: ctrl: 0x%08x -> 0x%x\n", + dev->name, ch->ctrl_start, ch->ctrl_start+6*16); + printk("%s: ptr1_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr1_reg)); + printk("%s: ptr2_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr2_reg)); + printk("%s: cnt1_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt1_reg)); + printk("%s: cnt2_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt2_reg)); +} + +void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) +{ + struct cx23885_dev *dev = port->dev; + unsigned int i,j,n; + + printk("%s: risc disasm: %p [dma=0x%08lx]\n", + dev->name, risc->cpu, (unsigned long)risc->dma); + for (i = 0; i < (risc->size >> 2); i += n) { + printk("%s: %04d: ", dev->name, i); + n = cx23885_risc_decode(risc->cpu[i]); + for (j = 1; j < n; j++) + printk("%s: %04d: 0x%08x [ arg #%d ]\n", + dev->name, i+j, risc->cpu[i+j], j); + if (risc->cpu[i] == RISC_JUMP) + break; + } +} + +void cx23885_shutdown(struct cx23885_dev *dev) +{ + /* disable RISC controller */ + cx_write(DEV_CNTRL2, 0); + + /* Disable all IR activity */ + cx_write(IR_CNTRL_REG, 0); + + /* Disable Video A/B activity */ + cx_write(VID_A_DMA_CTL, 0); + cx_write(VID_B_DMA_CTL, 0); + cx_write(VID_C_DMA_CTL, 0); + + /* Disable Audio activity */ + cx_write(AUD_INT_DMA_CTL, 0); + cx_write(AUD_EXT_DMA_CTL, 0); + + /* Disable Serial port */ + cx_write(UART_CTL, 0); + + /* Disable Interrupts */ + cx_write(PCI_INT_MSK, 0); + cx_write(VID_A_INT_MSK, 0); + cx_write(VID_B_INT_MSK, 0); + cx_write(VID_C_INT_MSK, 0); + cx_write(AUDIO_INT_INT_MSK, 0); + cx_write(AUDIO_EXT_INT_MSK, 0); + +} + +void cx23885_reset(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + cx23885_shutdown(dev); + + cx_write(PCI_INT_STAT, 0xffffffff); + cx_write(VID_A_INT_STAT, 0xffffffff); + cx_write(VID_B_INT_STAT, 0xffffffff); + cx_write(VID_C_INT_STAT, 0xffffffff); + cx_write(AUDIO_INT_INT_STAT, 0xffffffff); + cx_write(AUDIO_EXT_INT_STAT, 0xffffffff); + cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); + + mdelay(100); + +#if SRAM + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); + +#else + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH09 ], 128, 0); + break; + case CX23885_BRIDGE_887: + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH09 ], 128, 0); + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } +#endif + + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + dprintk( 1, "%s() Configuring HVR1800 GPIO's\n", __FUNCTION__); + // FIXME: Analog requires the tuner is brought out of reset + break; + } +} + + +static int cx23885_pci_quirks(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + cx_clear(RDR_TLCTL0, 1 << 4); + break; + } + return 0; +} + +static int get_resources(struct cx23885_dev *dev) +{ + if (request_mem_region(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0), + dev->name)) + return 0; + + printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + dev->name, (unsigned long long)pci_resource_start(dev->pci,0)); + + return -EBUSY; +} + +static void cx23885_timeout(unsigned long data); +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); + +static int cx23885_ir_init(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); + break; + } + + return 0; +} + +static int cx23885_dev_setup(struct cx23885_dev *dev) +{ + int i; + + mutex_init(&dev->lock); + + atomic_inc(&dev->refcount); + + dev->nr = cx23885_devcount++; + dev->pci_bus = dev->pci->bus->number; + dev->pci_slot = PCI_SLOT(dev->pci->devfn); + dev->pci_irqmask = 0x001f00; + + /* External Master 1 Bus */ + dev->i2c_bus[0].nr = 0; + dev->i2c_bus[0].dev = dev; + dev->i2c_bus[0].reg_stat = I2C1_STAT; + dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; + dev->i2c_bus[0].reg_addr = I2C1_ADDR; + dev->i2c_bus[0].reg_rdata = I2C1_RDATA; + dev->i2c_bus[0].reg_wdata = I2C1_WDATA; + dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */ + + /* External Master 2 Bus */ + dev->i2c_bus[1].nr = 1; + dev->i2c_bus[1].dev = dev; + dev->i2c_bus[1].reg_stat = I2C2_STAT; + dev->i2c_bus[1].reg_ctrl = I2C2_CTRL; + dev->i2c_bus[1].reg_addr = I2C2_ADDR; + dev->i2c_bus[1].reg_rdata = I2C2_RDATA; + dev->i2c_bus[1].reg_wdata = I2C2_WDATA; + dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */ + + /* Internal Master 3 Bus */ + dev->i2c_bus[2].nr = 2; + dev->i2c_bus[2].dev = dev; + dev->i2c_bus[2].reg_stat = I2C3_STAT; + dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; + dev->i2c_bus[2].reg_addr = I2C2_ADDR; + dev->i2c_bus[2].reg_rdata = I2C3_RDATA; + dev->i2c_bus[2].reg_wdata = I2C3_WDATA; + dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ + + /* Transport bus init dma queue */ + spin_lock_init(&dev->ts2.slock); + dev->ts2.dev = dev; + dev->ts2.nr = 2; + dev->ts2.sram_chno = SRAM_CH06; + INIT_LIST_HEAD(&dev->ts2.mpegq.active); + INIT_LIST_HEAD(&dev->ts2.mpegq.queued); + dev->ts2.mpegq.timeout.function = cx23885_timeout; + dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; + init_timer(&dev->ts2.mpegq.timeout); + + dev->ts2.reg_gpcnt = VID_C_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; + dev->ts2.reg_lngth = VID_C_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_C_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_C_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + + sprintf(dev->name,"cx23885[%d]", dev->nr); + + if (get_resources(dev) < 0) { + printk(KERN_ERR "CORE %s No more PCIe resources for " + "subsystem: %04x:%04x\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device); + + cx23885_devcount--; + goto fail_free; + } + + mutex_lock(&devlist); + list_add_tail(&dev->devlist, &cx23885_devlist); + mutex_unlock(&devlist); + + /* PCIe stuff */ + dev->lmmio = ioremap(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0)); + + dev->bmmio = (u8 __iomem *)dev->lmmio; + + cx23885_pci_quirks(dev); + + /* board config */ + dev->board = UNSET; + if (card[dev->nr] < cx23885_bcount) + dev->board = card[dev->nr]; + for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) + if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && + dev->pci->subsystem_device == cx23885_subids[i].subdevice) + dev->board = cx23885_subids[i].card; + if (UNSET == dev->board) { + dev->board = CX23885_BOARD_UNKNOWN; + cx23885_card_list(dev); + } + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx23885_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); + + /* Configure the hardware internal memory for fifos */ + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_UNDEFINED: + case CX23885_BRIDGE_885: + dev->sram_channels = cx23885_sram_channels; + break; + case CX23885_BRIDGE_887: + dev->sram_channels = cx23887_sram_channels; + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + /* init hardware */ + cx23885_reset(dev); + + cx23885_i2c_register(&dev->i2c_bus[0]); + cx23885_i2c_register(&dev->i2c_bus[1]); + cx23885_i2c_register(&dev->i2c_bus[2]); + cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + + cx23885_card_setup(dev); + cx23885_ir_init(dev); + + if (cx23885_dvb_register(&dev->ts2) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); + } + + return 0; + +fail_free: + kfree(dev); + return -ENODEV; +} + +void cx23885_dev_unregister(struct cx23885_dev *dev) +{ + release_mem_region(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0)); + + if (!atomic_dec_and_test(&dev->refcount)) + return; + + cx23885_dvb_unregister(&dev->ts2); + cx23885_i2c_unregister(&dev->i2c_bus[2]); + cx23885_i2c_unregister(&dev->i2c_bus[1]); + cx23885_i2c_unregister(&dev->i2c_bus[0]); + + iounmap(dev->lmmio); +} + +static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines) +{ + struct scatterlist *sg; + unsigned int line,todo; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (bpl <= sg_dma_len(sg)-offset) { + /* fits into current chunk */ + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + offset+=bpl; + } else { + /* scanline needs to be split */ + todo = bpl; + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL| + (sg_dma_len(sg)-offset)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + todo -= (sg_dma_len(sg)-offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++)=cpu_to_le32(RISC_WRITE| + sg_dma_len(sg)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + todo -= sg_dma_len(sg); + sg++; + } + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + offset += todo; + } + offset += padding; + } + + return rp; +} + +int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines) +{ + u32 instructions,fields; + u32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + /* write and jump need and extra dword */ + instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); + instructions += 2; + //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + if (UNSET != top_offset) + rp = cx23885_risc_field(rp, sglist, top_offset, 0, + bpl, padding, lines); + if (UNSET != bottom_offset) + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, + bpl, padding, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} + +int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines) +{ + u32 instructions; + u32 *rp; + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Here + there is no padding and no sync. First DMA region may be smaller + than PAGE_SIZE */ + /* Jump and write need an extra dword */ + instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; + instructions += 1; + + //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} + +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value) +{ + u32 *rp; + int rc; + + if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + //*(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM); + *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); + *(rp++) = cpu_to_le32(reg); + *(rp++) = cpu_to_le32(value); + *(rp++) = cpu_to_le32(mask); + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc->dma); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + return 0; +} + +void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) +{ + BUG_ON(in_interrupt()); + videobuf_waiton(&buf->vb,0,0); + videobuf_dma_unmap(q, &buf->vb.dma); + videobuf_dma_free(&buf->vb.dma); + btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); + buf->vb.state = STATE_NEEDS_INIT; +} + +static int cx23885_start_dma(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, + buf->vb.width, buf->vb.height, buf->vb.field); + +#if SRAM + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, + &dev->sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); +#else + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + cx23885_sram_channel_setup(dev, + &cx23885_sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ] ); + break; + case CX23885_BRIDGE_887: + cx23885_sram_channel_setup(dev, + &cx23887_sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ] ); + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } +#endif + + if(debug > 5) + cx23885_risc_disasm(port, &buf->risc); + + /* write TS length to chip */ + cx_write(port->reg_lngth, buf->vb.width); + + if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { + printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", __FUNCTION__, + cx23885_boards[dev->board].portc ); + return -EINVAL; + } + + // FIXME: review the need for these two lines + dprintk( 1, "%s() doing .dvb\n", __FUNCTION__); + udelay(100); + + cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); + cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); + + // FIXME: review the need for this + cx_write(GPIO2, 0x00); + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + cx_write(port->reg_vld_misc, 0x00); + dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", __FUNCTION__); + break; + default: + // FIXME + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); + udelay(100); + + /* reset counter to zero */ + cx_write(port->reg_gpcnt_ctl, 3); + q->count = 1; + + /* A bug in the current 887 implementation, causes an NMI assert during + * starting or stopping interrupts or dma. Avoid the bug for the time being, + * enabling the developer to work on the demod/tuner locking work. + */ + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + /* enable irqs */ + dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ ); + cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); + cx_set(port->reg_dma_ctl, port->dma_ctl_val); + cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); + break; + case CX23885_BRIDGE_887: + // FIXME + dprintk(1, "%s() NOT enabling TS int's and DMA, NMI bug\n", __FUNCTION__ ); + break; + default: + // FIXME: generate a sensible switch-default message + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + dprintk(1, "%s() Register Dump\n", __FUNCTION__); + dprintk(1, "%s() set port ts_int_msk, now %x\n", __FUNCTION__, cx_read(port->reg_ts_int_msk) ); + dprintk(1, "%s() DEV_CNTRL2 0x%08x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); + dprintk(1, "%s() PCI_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(PCI_INT_MSK) ); + dprintk(1, "%s() VID_A_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_A_INT_MSK) ); + dprintk(1, "%s() VID_B_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_B_INT_MSK) ); + dprintk(1, "%s() VID_C_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSK) ); + dprintk(1, "%s() VID_A_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_A_DMA_CTL) ); + dprintk(1, "%s() VID_B_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_B_DMA_CTL) ); + dprintk(1, "%s() VID_C_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); + dprintk(1, "%s() AUD_INT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_INT_INT_MSK) ); + dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_INT_DMA_CTL) ); + dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_EXT_INT_MSK) ); + dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_EXT_DMA_CTL) ); + + cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ + + dprintk(1, "%s() set dev_cntrl2, now %x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); + dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_dma_ctl) ); + dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); + dprintk(1, "%s() PAD_CTRL %x\n", __FUNCTION__, cx_read(PAD_CTRL) ); + dprintk(1, "%s() GPIO2 %x\n", __FUNCTION__, cx_read(GPIO2) ); + dprintk(1, "%s() VID_C_LN_LNGTH , now %x\n", __FUNCTION__, cx_read(port->reg_lngth) ); + dprintk(1, "%s() VID_C_HW_SOP_CTL, now %x\n", __FUNCTION__, cx_read(port->reg_hw_sop_ctrl) ); + dprintk(1, "%s() VID_C_GEN_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_gen_ctrl) ); + dprintk(1, "%s() VID_C_SOP_STATUS, now %x\n", __FUNCTION__, cx_read(VID_C_SOP_STATUS) ); + dprintk(1, "%s() VID_C_TS_CLK_EN , now %x\n", __FUNCTION__, cx_read(VID_C_TS_CLK_EN) ); + dprintk(1, "%s() VID_C_FIFO_OVLST, now %x\n", __FUNCTION__, cx_read(VID_C_FIFO_OVFL_STAT) ); + dprintk(1, "%s() VID_C_INT_MSTAT , now 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSTAT) ); + return 0; +} + +static int cx23885_stop_dma(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + dprintk(1, "%s()\n", __FUNCTION__); + + /* Stop interrupts and DMA */ + cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + + return 0; +} + +static int cx23885_restart_queue(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf; + struct list_head *item; + + dprintk(5, "%s()\n", __FUNCTION__); + if (list_empty(&q->active)) + { + struct cx23885_buffer *prev; + prev = NULL; + + dprintk(5, "%s() queue is empty\n", __FUNCTION__); + + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + cx23885_start_dma(port, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(5,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk(5,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } + return 0; + } + + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + dprintk(2,"restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_dma(port, q, buf); + list_for_each(item,&q->active) { + buf = list_entry(item, struct cx23885_buffer, vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +/* ------------------------------------------------------------------ */ + +int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, + struct cx23885_buffer *buf, enum v4l2_field field) +{ + struct cx23885_dev *dev = port->dev; + int size = port->ts_packet_size * port->ts_packet_count; + int rc; + + dprintk(1, "%s: %p\n", __FUNCTION__, buf); + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (STATE_NEEDS_INIT == buf->vb.state) { + buf->vb.width = port->ts_packet_size; + buf->vb.height = port->ts_packet_count; + buf->vb.size = size; + buf->vb.field = field /*V4L2_FIELD_TOP*/; + + if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + goto fail; + cx23885_risc_databuffer(dev->pci, &buf->risc, + buf->vb.dma.sglist, + buf->vb.width, buf->vb.height); + } + buf->vb.state = STATE_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q,buf); + return rc; +} + +void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) +{ + struct cx23885_buffer *prev; + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *cx88q = &port->mpegq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (list_empty(&cx88q->active)) { + dprintk( 1, "queue is empty - first active\n" ); + list_add_tail(&buf->vb.queue,&cx88q->active); + cx23885_start_dma(port, cx88q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = cx88q->count++; + mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] %s - first active\n", + buf, buf->vb.i, __FUNCTION__); + + } else { + dprintk( 1, "queue is not empty - append to active\n" ); + prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); + list_add_tail(&buf->vb.queue,&cx88q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = cx88q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk( 1, "[%p/%d] %s - append to active\n", + buf, buf->vb.i, __FUNCTION__); + } +} + +/* ----------------------------------------------------------- */ + +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, int restart) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + struct cx23885_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&port->slock,flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = STATE_ERROR; + wake_up(&buf->vb.done); + dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", + buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); + } + if (restart) + { + dprintk(1, "restarting queue\n" ); + cx23885_restart_queue(port, q); + } + spin_unlock_irqrestore(&port->slock,flags); +} + +void cx23885_cancel_buffers(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + + dprintk(1, "%s()\n", __FUNCTION__ ); + del_timer_sync(&q->timeout); + cx23885_stop_dma(port); + do_cancel_buffers(port, "cancel", 0); +} + +static void cx23885_timeout(unsigned long data) +{ + struct cx23885_tsport *port = (struct cx23885_tsport *)data; + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s()\n",__FUNCTION__); + + if (debug > 5) +#if SRAM + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); +#else + { + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_885) + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); + if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_887) + cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ]); + } +#endif + cx23885_stop_dma(port); + do_cancel_buffers(port, "timeout", 1); +} + +#define PCI_MSK_APB_DMA (1 << 12) +#define PCI_MSK_AL_WR (1 << 11) +#define PCI_MSK_AL_RD (1 << 10) +#define PCI_MSK_RISC_WR (1 << 9) +#define PCI_MSK_RISC_RD (1 << 8) + +#define PCI_MSK_AUD_EXT (1 << 4) +#define PCI_MSK_AUD_INT (1 << 3) +#define PCI_MSK_VID_C (1 << 2) +#define PCI_MSK_VID_B (1 << 1) +#define PCI_MSK_VID_A 1 + +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 + +static irqreturn_t cx23885_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cx23885_dev *dev = dev_id; + struct cx23885_tsport *port = &dev->ts2; + u32 pci_status, pci_mask; + u32 ts2_status, ts2_mask; + int count = 0, handled = 0; + + pci_status = cx_read(PCI_INT_STAT); + pci_mask = cx_read(PCI_INT_MSK); + + ts2_status = cx_read(VID_C_INT_STAT); + ts2_mask = cx_read(VID_C_INT_MSK); + + if ( (pci_status == 0) && (ts2_status == 0) ) + goto out; + + count = cx_read(port->reg_gpcnt); + dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); + + if ( (pci_status & PCI_MSK_RISC_RD) || + (pci_status & PCI_MSK_RISC_WR) || + (pci_status & PCI_MSK_AL_RD) || + (pci_status & PCI_MSK_AL_WR) || + (pci_status & PCI_MSK_APB_DMA) || + (pci_status & PCI_MSK_VID_C) || + (pci_status & PCI_MSK_VID_B) || + (pci_status & PCI_MSK_VID_A) || + (pci_status & PCI_MSK_AUD_INT) || + (pci_status & PCI_MSK_AUD_EXT) ) + { + + if (pci_status & PCI_MSK_RISC_RD) + dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", PCI_MSK_RISC_RD); + if (pci_status & PCI_MSK_RISC_WR) + dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", PCI_MSK_RISC_WR); + if (pci_status & PCI_MSK_AL_RD) + dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", PCI_MSK_AL_RD); + if (pci_status & PCI_MSK_AL_WR) + dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", PCI_MSK_AL_WR); + if (pci_status & PCI_MSK_APB_DMA) + dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", PCI_MSK_APB_DMA); + if (pci_status & PCI_MSK_VID_C) + dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", PCI_MSK_VID_C); + if (pci_status & PCI_MSK_VID_B) + dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", PCI_MSK_VID_B); + if (pci_status & PCI_MSK_VID_A) + dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", PCI_MSK_VID_A); + if (pci_status & PCI_MSK_AUD_INT) + dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", PCI_MSK_AUD_INT); + if (pci_status & PCI_MSK_AUD_EXT) + dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", PCI_MSK_AUD_EXT); + + } + + if ( (ts2_status & VID_C_MSK_OPC_ERR) || + (ts2_status & VID_C_MSK_BAD_PKT) || + (ts2_status & VID_C_MSK_SYNC) || + (ts2_status & VID_C_MSK_OF)) + { + if (ts2_status & VID_C_MSK_OPC_ERR) + dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); + if (ts2_status & VID_C_MSK_BAD_PKT) + dprintk(7, " (VID_C_MSK_BAD_PKT 0x%08x)\n", VID_C_MSK_BAD_PKT); + if (ts2_status & VID_C_MSK_SYNC) + dprintk(7, " (VID_C_MSK_SYNC 0x%08x)\n", VID_C_MSK_SYNC); + if (ts2_status & VID_C_MSK_OF) + dprintk(7, " (VID_C_MSK_OF 0x%08x)\n", VID_C_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); +#if SRAM + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); +#else + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); +#endif + + + } else if (ts2_status & VID_C_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_C_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (ts2_status & VID_C_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_C_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + + cx_write(VID_C_INT_STAT, ts2_status); + cx_write(PCI_INT_STAT, pci_status); + handled = 1; +out: + return IRQ_RETVAL(handled); +} + +static int __devinit cx23885_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx23885_dev *dev; + int err; + + dev = kzalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + + /* pci init */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + goto fail_free; + } + + if (cx23885_dev_setup(dev) < 0) { + err = -EINVAL; + goto fail_free; + } + + /* print pci info */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", dev->name, + pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0)); + + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev, 0xffffffff)) { + printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); + err = -EIO; + goto fail_irq; + } + + err = request_irq(pci_dev->irq, cx23885_irq + , IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->name, pci_dev->irq); + goto fail_irq; + } + + pci_set_drvdata(pci_dev, dev); + return 0; + +fail_irq: + cx23885_dev_unregister(dev); +fail_free: + kfree(dev); + return err; +} + +static void __devexit cx23885_finidev(struct pci_dev *pci_dev) +{ + struct cx23885_dev *dev = pci_get_drvdata(pci_dev); + + cx23885_shutdown(dev); + + pci_disable_device(pci_dev); + + /* unregister stuff */ + free_irq(pci_dev->irq, dev); + pci_set_drvdata(pci_dev, NULL); + + mutex_lock(&devlist); + list_del(&dev->devlist); + mutex_unlock(&devlist); + + cx23885_dev_unregister(dev); + kfree(dev); +} + +static struct pci_device_id cx23885_pci_tbl[] = { + { + /* CX23885 */ + .vendor = 0x14f1, + .device = 0x8852, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* CX23887 Rev 2 */ + .vendor = 0x14f1, + .device = 0x8880, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl); + +static struct pci_driver cx23885_pci_driver = { + .name = "cx23885", + .id_table = cx23885_pci_tbl, + .probe = cx23885_initdev, + .remove = __devexit_p(cx23885_finidev), + /* TODO */ + .suspend = NULL, + .resume = NULL, +}; + +static int cx23885_init(void) +{ + printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx23885_pci_driver); +} + +static void cx23885_fini(void) +{ + pci_unregister_driver(&cx23885_pci_driver); +} + +module_init(cx23885_init); +module_exit(cx23885_fini); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c new file mode 100644 index 000000000000..4ff85f75f9f7 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -0,0 +1,199 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include "dvb-pll.h" +#include + +#include "s5h1409.h" +#include "mt2131.h" + +static unsigned int debug = 2; + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------ */ + +static int dvb_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx23885_tsport *port = q->priv_data; + + port->ts_packet_size = 188 * 4; + port->ts_packet_count = 32; + + *size = port->ts_packet_size * port->ts_packet_count; + *count = 32; + return 0; +} + +static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_tsport *port = q->priv_data; + return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb,field); +} + +static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx23885_tsport *port = q->priv_data; + cx23885_buf_queue(port, (struct cx23885_buffer*)vb); +} + +static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + cx23885_free_buffer(q, (struct cx23885_buffer*)vb); +} + +static struct videobuf_queue_ops dvb_qops = { + .buf_setup = dvb_buf_setup, + .buf_prepare = dvb_buf_prepare, + .buf_queue = dvb_buf_queue, + .buf_release = dvb_buf_release, +}; + +static struct s5h1409_config hauppauge_hvr1800lp_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF +}; + +static struct s5h1409_config hauppauge_hvr1800_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF +}; + + +static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { + 0x61 +}; + +static struct mt2131_config hauppauge_hvr1800_tunerconfig = { + 0x61 +}; + +static int dvb_register(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + + /* init struct videobuf_dvb */ + port->dvb.name = dev->name; + + /* init frontend */ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, + port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800lp_rev2_tunerconfig, + 0); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, + port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800_tunerconfig, + 0); + } + break; + default: + printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + dev->name); + break; + } + if (NULL == port->dvb.frontend) { + printk("%s: frontend initialization failed\n", dev->name); + return -1; + } + + /* Put the analog decoder in standby to keep it quiet */ + cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + + /* register everything */ + return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); +} + +int cx23885_dvb_register(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + int err; + + dprintk( 1, "%s\n", __FUNCTION__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dev->board, + dev->name, + dev->pci_bus, + dev->pci_slot); + + err = -ENODEV; + if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) + goto fail_core; + + /* dvb stuff */ + printk("%s: cx23885 based dvb card\n", dev->name); + videobuf_queue_init( + &port->dvb.dvbq, + &dvb_qops, + dev->pci, + &port->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_TOP, + sizeof(struct cx23885_buffer), + port); + err = dvb_register(port); + if (err != 0) + printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); + + fail_core: + return err; +} + +int cx23885_dvb_unregister(struct cx23885_tsport *port) +{ + /* dvb */ + if(port->dvb.frontend) + videobuf_dvb_unregister(&port->dvb); + + return 0; +} diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c new file mode 100644 index 000000000000..6f5e207c11a6 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -0,0 +1,375 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "cx23885.h" + +#include + +static unsigned int i2c_debug = 2; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); + +static unsigned int i2c_scan = 0; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); + +#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) + +#define I2C_WAIT_DELAY 32 +#define I2C_WAIT_RETRY 64 + +#define I2C_EXTEND (1 << 3) +#define I2C_NOSTOP (1 << 4) + +static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x01; +} + +static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; +} + +static int i2c_wait_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_is_busy(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + u32 wdata, addr, ctrl; + int retval, cnt; + + dprintk(1, "%s()\n", __FUNCTION__); + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -EIO; + + dprintk(1, "%s() returns 0\n", __FUNCTION__); + return 0; + } + + + /* dev, reg + first byte */ + addr = (msg->addr << 25) | msg->buf[0]; + wdata = msg->buf[0]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (msg->len > 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" addr << 1, msg->buf[0]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + + for (cnt = 1; cnt < msg->len; cnt++ ) { + /* following bytes */ + wdata = msg->buf[cnt]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (cnt < msg->len-1 || !last) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + //printk("addr = 0x%08x wdata = 0x%08x ctrl = 0x%08x\n", addr, wdata, ctrl); + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" %02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + printk(" ERR: %d\n",retval); + return retval; +} + +static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + u32 ctrl, cnt; + int retval; + + dprintk(1, "%s()\n", __FUNCTION__); + + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -EIO; + + + dprintk(1, "%s() returns 0\n", __FUNCTION__); + return 0; + } + + for(cnt = 0; cnt < msg->len; cnt++) { + + ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; + + if (cnt < msg->len-1 || !last) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; + if (i2c_debug) { + if (!(ctrl & I2C_NOSTOP)) + printk(" addr << 1) +1); + printk(" =%02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + printk(" ERR: %d\n",retval); + return retval; +} + +static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + int i, retval = 0; + + dprintk(1, "%s(num = %d)\n", __FUNCTION__, num); + + for (i = 0 ; i < num; i++) { + dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n" + , __FUNCTION__, num, msgs[i].addr, msgs[i].len); + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } else { + /* write */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } + } + return num; + + err: + return retval; +} + +static int attach_inform(struct i2c_client *client) +{ + struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); + + dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, client->addr, client->name); + + if (!client->driver->command) + return 0; + + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); + + dprintk(1, "i2c detach [client=%s]\n", client->name); + + return 0; +} + +void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) +{ +// struct cx23885_dev *dev = bus->dev; + + if (bus->i2c_rc != 0) + return; + + i2c_clients_command(&bus->i2c_adap, cmd, arg); +} + +static int cx23885_algo_control(struct i2c_adapter *adap, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static u32 cx23885_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm cx23885_i2c_algo_template = { + .master_xfer = i2c_xfer, + .algo_control = cx23885_algo_control, + .functionality = cx23885_functionality, +}; + +/* ----------------------------------------------------------------------- */ + +static struct i2c_adapter cx23885_i2c_adap_template = { + .name = "cx23885", + .owner = THIS_MODULE, + .id = I2C_HW_B_CX23885, + .algo = &cx23885_i2c_algo_template, +// .class = I2C_CLASS_TV_ANALOG, + .client_register = attach_inform, + .client_unregister = detach_inform, +}; + +static struct i2c_client cx23885_i2c_client_template = { + .name = "cx23885 internal", +}; + +static char *i2c_devs[128] = { + [ 0x32 >> 1 ] = "cx24227", + [ 0x88 >> 1 ] = "cx25837", + [ 0x84 >> 1 ] = "tda8295", + [ 0xa0 >> 1 ] = "eeprom", + [ 0xc0 >> 1 ] = "mt2131/tda8275", + [ 0xc2 >> 1 ] = "mt2131/tda8275", +}; + +static void do_i2c_scan(char *name, struct i2c_client *c) +{ + unsigned char buf; + int i,rc; + + for (i = 0; i < 128; i++) { + c->addr = i; + rc = i2c_master_recv(c,&buf,0); + if (rc < 0) + continue; + printk("%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } +} + +/* init + register i2c algo-bit adapter */ +int cx23885_i2c_register(struct cx23885_i2c *bus) +{ + struct cx23885_dev *dev = bus->dev; + + dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr); + + memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, sizeof(bus->i2c_adap)); + memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, sizeof(bus->i2c_algo)); + memcpy(&bus->i2c_client, &cx23885_i2c_client_template, sizeof(bus->i2c_client)); + + bus->i2c_adap.dev.parent = &dev->pci->dev; + + strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + bus->i2c_algo.data = bus; + bus->i2c_adap.algo_data = bus; + i2c_add_adapter(&bus->i2c_adap); + + bus->i2c_client.adapter = &bus->i2c_adap; + + if (0 == bus->i2c_rc) { + printk("%s: i2c bus %d registered\n", dev->name, bus->nr); + if (i2c_scan) + do_i2c_scan(dev->name, &bus->i2c_client); + } else + printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr); + + return bus->i2c_rc; +} + +int cx23885_i2c_unregister(struct cx23885_i2c *bus) +{ + i2c_del_adapter(&bus->i2c_adap); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +EXPORT_SYMBOL(cx23885_call_i2c_clients); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h new file mode 100644 index 000000000000..5cb692f20d28 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -0,0 +1,429 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * 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 _CX23885_REG_H_ +#define _CX23885_REG_H_ + + +/* +Address Map +0x00000000 -> 0x00009000 TX SRAM (Fifos) +0x00010000 -> 0x00013c00 RX SRAM CMDS + CDT + +EACH CMDS struct is 0x80 bytes long + +DMAx_PTR1 = 0x03040 address of first cluster +DMAx_PTR2 = 0x10600 address of the CDT +DMAx_CNT1 = cluster size in (bytes >> 4) -1 +DMAx_CNT2 = total cdt size for all entries >> 3 + +Cluster Descriptor entry = 4 DWORDS + DWORD 0 -> ptr to cluster + DWORD 1 Reserved + DWORD 2 Reserved + DWORD 3 Reserved + +Channel manager Data Structure entry = 20 DWORD + 0 IntialProgramCounterLow + 1 IntialProgramCounterHigh + 2 ClusterDescriptorTableBase + 3 ClusterDescriptorTableSize + 4 InstructionQueueBase + 5 InstructionQueueSize +... Reserved + 19 Reserved + + +*/ + +/* Risc Instructions */ +#define RISC_CNT_INC 0x00010000 +#define RISC_CNT_RESET 0x00030000 +#define RISC_IRQ1 0x01000000 +#define RISC_IRQ2 0x02000000 +#define RISC_EOL 0x04000000 +#define RISC_SOL 0x08000000 +#define RISC_WRITE 0x10000000 +#define RISC_SKIP 0x20000000 +#define RISC_JUMP 0x70000000 +#define RISC_SYNC 0x80000000 +#define RISC_RESYNC 0x80008000 +#define RISC_READ 0x90000000 +#define RISC_WRITERM 0xB0000000 +#define RISC_WRITECM 0xC0000000 +#define RISC_WRITECR 0xD0000000 + +//#define RISC_SYNC_ODD 0x80000000 +//#define RISC_SYNC_EVEN 0x80000200 +//#define RISC_RESYNC_ODD 0x80008000 +//#define RISC_RESYNC_EVEN 0x80008200 + +// Do we need these? +#define RISC_WRITEC 0x50000000 +#define RISC_READC 0xA0000000 + +// Is this used? +#define RISC_IMM 0x00000001 + +//#define RISC_CNT_NONE 0x00000000 +//#define RISC_CNT_RSVR 0x00020000 +//#define RISC_JMP_SRP 0x01 + +/* Audio and Video Core */ +#define HOST_REG1 0x00000000 +#define HOST_REG2 0x00000001 +#define HOST_REG3 0x00000002 + +/* Chip Configuration Registers */ +#define CHIP_CTRL 0x00000100 +#define AFE_CTRL 0x00000104 +#define VID_PLL_INT_POST 0x00000108 +#define VID_PLL_FRAC 0x0000010C +#define AUX_PLL_INT_POST 0x00000110 +#define AUX_PLL_FRAC 0x00000114 +#define SYS_PLL_INT_POST 0x00000118 +#define SYS_PLL_FRAC 0x0000011C +#define PIN_CTRL 0x00000120 +#define AUD_IO_CTRL 0x00000124 +#define AUD_LOCK1 0x00000128 +#define AUD_LOCK2 0x0000012C +#define POWER_CTRL 0x00000130 +#define AFE_DIAG_CTRL1 0x00000134 +#define AFE_DIAG_CTRL3 0x0000013C +#define PLL_DIAG_CTRL 0x00000140 +#define AFE_CLK_OUT_CTRL 0x00000144 +#define DLL1_DIAG_CTRL 0x0000015C + +/* GPIO[23:19] Output Enable */ +#define GPIO2_OUT_EN_REG 0x00000160 +/* GPIO[23:19] Data Registers */ +#define GPIO2 0x00000164 + +#define IFADC_CTRL 0x00000180 + +/* Infrared Remote Registers */ +#define IR_CNTRL_REG 0x00000200 +#define IR_TXCLK_REG 0x00000204 +#define IR_RXCLK_REG 0x00000208 +#define IR_CDUTY_REG 0x0000020C +#define IR_STAT_REG 0x00000210 +#define IR_IRQEN_REG 0x00000214 +#define IR_FILTR_REG 0x00000218 +#define IR_FIFO_REG 0x0000023C + +/* Video Decoder Registers */ +#define MODE_CTRL 0x00000400 +#define OUT_CTRL1 0x00000404 +#define OUT_CTRL2 0x00000408 +#define GEN_STAT 0x0000040C +#define INT_STAT_MASK 0x00000410 +#define LUMA_CTRL 0x00000414 +#define HSCALE_CTRL 0x00000418 +#define VSCALE_CTRL 0x0000041C +#define CHROMA_CTRL 0x00000420 +#define VBI_LINE_CTRL1 0x00000424 +#define VBI_LINE_CTRL2 0x00000428 +#define VBI_LINE_CTRL3 0x0000042C +#define VBI_LINE_CTRL4 0x00000430 +#define VBI_LINE_CTRL5 0x00000434 +#define VBI_FC_CFG 0x00000438 +#define VBI_MISC_CFG1 0x0000043C +#define VBI_MISC_CFG2 0x00000440 +#define VBI_PAY1 0x00000444 +#define VBI_PAY2 0x00000448 +#define VBI_CUST1_CFG1 0x0000044C +#define VBI_CUST1_CFG2 0x00000450 +#define VBI_CUST1_CFG3 0x00000454 +#define VBI_CUST2_CFG1 0x00000458 +#define VBI_CUST2_CFG2 0x0000045C +#define VBI_CUST2_CFG3 0x00000460 +#define VBI_CUST3_CFG1 0x00000464 +#define VBI_CUST3_CFG2 0x00000468 +#define VBI_CUST3_CFG3 0x0000046C +#define HORIZ_TIM_CTRL 0x00000470 +#define VERT_TIM_CTRL 0x00000474 +#define SRC_COMB_CFG 0x00000478 +#define CHROMA_VBIOFF_CFG 0x0000047C +#define FIELD_COUNT 0x00000480 +#define MISC_TIM_CTRL 0x00000484 +#define DFE_CTRL1 0x00000488 +#define DFE_CTRL2 0x0000048C +#define DFE_CTRL3 0x00000490 +#define PLL_CTRL 0x00000494 +#define HTL_CTRL 0x00000498 +#define COMB_CTRL 0x0000049C +#define CRUSH_CTRL 0x000004A0 +#define SOFT_RST_CTRL 0x000004A4 +#define CX885_VERSION 0x000004B4 +#define VBI_PASS_CTRL 0x000004BC + +/* Audio Decoder Registers */ +/* 8051 Configuration */ +#define DL_CTL 0x00000800 +#define STD_DET_STATUS 0x00000804 +#define STD_DET_CTL 0x00000808 +#define DW8051_INT 0x0000080C +#define GENERAL_CTL 0x00000810 +#define AAGC_CTL 0x00000814 +#define DEMATRIX_CTL 0x000008CC +#define PATH1_CTL1 0x000008D0 +#define PATH1_VOL_CTL 0x000008D4 +#define PATH1_EQ_CTL 0x000008D8 +#define PATH1_SC_CTL 0x000008DC +#define PATH2_CTL1 0x000008E0 +#define PATH2_VOL_CTL 0x000008E4 +#define PATH2_EQ_CTL 0x000008E8 +#define PATH2_SC_CTL 0x000008EC + +/* Sample Rate Converter */ +#define SRC_CTL 0x000008F0 +#define SRC_LF_COEF 0x000008F4 +#define SRC1_CTL 0x000008F8 +#define SRC2_CTL 0x000008FC +#define SRC3_CTL 0x00000900 +#define SRC4_CTL 0x00000904 +#define SRC5_CTL 0x00000908 +#define SRC6_CTL 0x0000090C +#define BAND_OUT_SEL 0x00000910 +#define I2S_N_CTL 0x00000914 +#define I2S_OUT_CTL 0x00000918 +#define AUTOCONFIG_REG 0x000009C4 + +/* Audio ADC Registers */ +#define DSM_CTRL1 0x00000000 +#define DSM_CTRL2 0x00000001 +#define CHP_EN_CTRL 0x00000002 +#define CHP_CLK_CTRL1 0x00000004 +#define CHP_CLK_CTRL2 0x00000005 +#define BG_REF_CTRL 0x00000006 +#define SD2_SW_CTRL1 0x00000008 +#define SD2_SW_CTRL2 0x00000009 +#define SD2_BIAS_CTRL 0x0000000A +#define AMP_BIAS_CTRL 0x0000000C +#define CH_PWR_CTRL1 0x0000000E +#define CH_PWR_CTRL2 0x0000000F +#define DSM_STATUS1 0x00000010 +#define DSM_STATUS2 0x00000011 +#define DIG_CTL1 0x00000012 +#define DIG_CTL2 0x00000013 +#define I2S_TX_CFG 0x0000001A + +#define DEV_CNTRL2 0x00040000 +#define PCI_INT_MSK 0x00040010 +#define PCI_MSK_APB_DMA (1 << 12) +#define PCI_MSK_AL_WR (1 << 11) +#define PCI_MSK_AL_RD (1 << 10) +#define PCI_MSK_RISC_WR (1 << 9) +#define PCI_MSK_RISC_RD (1 << 8) +#define PCI_MSK_AUD_EXT (1 << 4) +#define PCI_MSK_AUD_INT (1 << 3) +#define PCI_MSK_VID_C (1 << 2) +#define PCI_MSK_VID_B (1 << 1) +#define PCI_MSK_VID_A 1 +#define PCI_INT_STAT 0x00040014 +#define PCI_INT_MSTAT 0x00040018 + +#define VID_A_INT_MSK 0x00040020 +#define VID_A_INT_STAT 0x00040024 +#define VID_A_INT_MSTAT 0x00040028 +#define VID_A_INT_SSTAT 0x0004002C + +#define VID_B_INT_MSK 0x00040030 +#define VID_B_INT_STAT 0x00040034 +#define VID_B_INT_MSTAT 0x00040038 +#define VID_B_INT_SSTAT 0x0004003C + +#define VID_C_INT_MSK 0x00040040 +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 +#define VID_C_INT_STAT 0x00040044 +#define VID_C_INT_MSTAT 0x00040048 +#define VID_C_INT_SSTAT 0x0004004C + +#define AUDIO_INT_INT_MSK 0x00040050 +#define AUDIO_INT_INT_STAT 0x00040054 +#define AUDIO_INT_INT_MSTAT 0x00040058 +#define AUDIO_INT_INT_SSTAT 0x0004005C + +#define AUDIO_EXT_INT_MSK 0x00040060 +#define AUDIO_EXT_INT_STAT 0x00040064 +#define AUDIO_EXT_INT_MSTAT 0x00040068 +#define AUDIO_EXT_INT_SSTAT 0x0004006C + +#define RDR_CFG0 0x00050000 +#define RDR_CFG1 0x00050004 +#define RDR_TLCTL0 0x00050318 + +/* APB DMAC Current Buffer Pointer */ +#define DMA1_PTR1 0x00100000 +#define DMA2_PTR1 0x00100004 +#define DMA3_PTR1 0x00100008 +#define DMA4_PTR1 0x0010000C +#define DMA5_PTR1 0x00100010 +#define DMA6_PTR1 0x00100014 +#define DMA7_PTR1 0x00100018 +#define DMA8_PTR1 0x0010001C + +/* APB DMAC Current Table Pointer */ +#define DMA1_PTR2 0x00100040 +#define DMA2_PTR2 0x00100044 +#define DMA3_PTR2 0x00100048 +#define DMA4_PTR2 0x0010004C +#define DMA5_PTR2 0x00100050 +#define DMA6_PTR2 0x00100054 +#define DMA7_PTR2 0x00100058 +#define DMA8_PTR2 0x0010005C + +/* APB DMAC Buffer Limit */ +#define DMA1_CNT1 0x00100080 +#define DMA2_CNT1 0x00100084 +#define DMA3_CNT1 0x00100088 +#define DMA4_CNT1 0x0010008C +#define DMA5_CNT1 0x00100090 +#define DMA6_CNT1 0x00100094 +#define DMA7_CNT1 0x00100098 +#define DMA8_CNT1 0x0010009C + +/* APB DMAC Table Size */ +#define DMA1_CNT2 0x001000C0 +#define DMA2_CNT2 0x001000C4 +#define DMA3_CNT2 0x001000C8 +#define DMA4_CNT2 0x001000CC +#define DMA5_CNT2 0x001000D0 +#define DMA6_CNT2 0x001000D4 +#define DMA7_CNT2 0x001000D8 +#define DMA8_CNT2 0x001000DC + +/* Timer Counters */ +#define TM_CNT_LDW 0x00110000 +#define TM_CNT_UW 0x00110004 +#define TM_LMT_LDW 0x00110008 +#define TM_LMT_UW 0x0011000C + +/* GPIO */ +#define GP0_IO 0x00110010 +#define GPIO_ISM 0x00110014 +#define SOFT_RESET 0x0011001C + +/* GPIO (417 Microsoftcontroller) RW Data */ +#define MC417_RWD 0x00110020 + +/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ +#define MC417_OEN 0x00110024 +#define MC417_CTL 0x00110028 +#define CLK_DELAY 0x00110048 +#define PAD_CTRL 0x0011004C + +/* Video A Interface */ +#define VID_A_GPCNT 0x00130020 +#define VBI_A_GPCNT 0x00130024 +#define VID_A_GPCNT_CTL 0x00130030 +#define VBI_A_GPCNT_CTL 0x00130034 +#define VID_A_DMA_CTL 0x00130040 +#define VID_A_VIP_CTRL 0x00130080 +#define VID_A_PIXEL_FRMT 0x00130084 +#define VID_A_VBI_CTRL 0x00130088 + +/* Video B Interface */ +#define VID_B_DMA 0x00130100 +#define VBI_B_DMA 0x00130108 +#define VID_B_GPCNT 0x00130120 +#define VBI_B_GPCNT 0x00130124 +#define VID_B_GPCNT_CTL 0x00130130 +#define VBI_B_GPCNT_CTL 0x00130134 +#define VID_B_DMA_CTL 0x00130140 +#define VID_B_SRC_SEL 0x00130144 +#define VID_B_LNGTH 0x00130150 +#define VID_B_HW_SOP_CTL 0x00130154 +#define VID_B_GEN_CTL 0x00130158 +#define VID_B_BD_PKT_STATUS 0x0013015C +#define VID_B_SOP_STATUS 0x00130160 +#define VID_B_FIFO_OVFL_STAT 0x00130164 +#define VID_B_VLD_MISC 0x00130168 +#define VID_B_TS_CLK_EN 0x0013016C +#define VID_B_VIP_CTRL 0x00130180 +#define VID_B_PIXEL_FRMT 0x00130184 + +/* Video C Interface */ +#define VID_C_GPCNT 0x00130220 +#define VID_C_GPCNT_CTL 0x00130230 +#define VBI_C_GPCNT_CTL 0x00130234 +#define VID_C_DMA_CTL 0x00130240 +#define VID_C_LNGTH 0x00130250 +#define VID_C_HW_SOP_CTL 0x00130254 +#define VID_C_GEN_CTL 0x00130258 +#define VID_C_BD_PKT_STATUS 0x0013025C +#define VID_C_SOP_STATUS 0x00130260 +#define VID_C_FIFO_OVFL_STAT 0x00130264 +#define VID_C_VLD_MISC 0x00130268 +#define VID_C_TS_CLK_EN 0x0013026C + +/* Internal Audio Interface */ +#define AUD_INT_A_GPCNT 0x00140020 +#define AUD_INT_B_GPCNT 0x00140024 +#define AUD_INT_A_GPCNT_CTL 0x00140030 +#define AUD_INT_B_GPCNT_CTL 0x00140034 +#define AUD_INT_DMA_CTL 0x00140040 +#define AUD_INT_A_LNGTH 0x00140050 +#define AUD_INT_B_LNGTH 0x00140054 +#define AUD_INT_A_MODE 0x00140058 +#define AUD_INT_B_MODE 0x0014005C + +/* External Audio Interface */ +#define AUD_EXT_DMA 0x00140100 +#define AUD_EXT_GPCNT 0x00140120 +#define AUD_EXT_GPCNT_CTL 0x00140130 +#define AUD_EXT_DMA_CTL 0x00140140 +#define AUD_EXT_LNGTH 0x00140150 +#define AUD_EXT_A_MODE 0x00140158 + +/* I2C Bus 1 */ +#define I2C1_ADDR 0x00180000 +#define I2C1_WDATA 0x00180004 +#define I2C1_CTRL 0x00180008 +#define I2C1_RDATA 0x0018000C +#define I2C1_STAT 0x00180010 + +/* I2C Bus 2 */ +#define I2C2_ADDR 0x00190000 +#define I2C2_WDATA 0x00190004 +#define I2C2_CTRL 0x00190008 +#define I2C2_RDATA 0x0019000C +#define I2C2_STAT 0x00190010 + +/* I2C Bus 3 */ +#define I2C3_ADDR 0x001A0000 +#define I2C3_WDATA 0x001A0004 +#define I2C3_CTRL 0x001A0008 +#define I2C3_RDATA 0x001A000C +#define I2C3_STAT 0x001A0010 + +/* UART */ +#define UART_CTL 0x001B0000 +#define UART_BRD 0x001B0004 +#define UART_ISR 0x001B000C +#define UART_CNT 0x001B0010 + +#endif /* _CX23885_REG_H_ */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h new file mode 100644 index 000000000000..f58ab86bd532 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885.h @@ -0,0 +1,295 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "btcx-risc.h" +#include "cx23885-reg.h" + +#include +#include + +#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6) + +#define UNSET (-1U) + +#define CX23885_MAXBOARDS 8 + +#define SRAM 0 + +/* Max number of inputs by card */ +#define MAX_CX23885_INPUT 8 + +//#define SHADOW_MAX 3 + +#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ + +#define CX23885_BOARD_NOAUTO UNSET +#define CX23885_BOARD_UNKNOWN 0 +#define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 +#define CX23885_BOARD_HAUPPAUGE_HVR1800 2 + +enum cx23885_itype { + CX23885_VMUX_COMPOSITE1 = 1, + CX23885_VMUX_COMPOSITE2, + CX23885_VMUX_COMPOSITE3, + CX23885_VMUX_COMPOSITE4, + CX23885_VMUX_SVIDEO, + CX23885_VMUX_TELEVISION, + CX23885_VMUX_CABLE, + CX23885_VMUX_DVB, + CX23885_VMUX_DEBUG, + CX23885_RADIO, +}; + +struct cx23885_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; + +/* buffer for one video frame */ +struct cx23885_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* cx23885 specific */ + unsigned int bpl; + struct btcx_riscmem risc; + struct cx23885_fmt *fmt; + u32 count; +}; + +struct cx23885_input { + enum cx23885_itype type; + unsigned int vmux; + u32 gpio0, gpio1, gpio2, gpio3; +}; + +struct cx23885_board { + char *name; + enum { + CX23885_MPEG_UNDEFINED = 0, + CX23885_MPEG_DVB + } portc; + enum { + CX23885_BRIDGE_UNDEFINED = 0, + CX23885_BRIDGE_885 = 885, + CX23885_BRIDGE_887 = 887, + } bridge; + struct cx23885_input input[MAX_CX23885_INPUT]; +}; + +struct cx23885_subid { + u16 subvendor; + u16 subdevice; + u32 card; +}; + +struct cx23885_i2c { + struct cx23885_dev *dev; + + int nr; + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + u32 i2c_rc; + + /* 885 registers used for raw addess */ + u32 i2c_period; + u32 reg_ctrl; + u32 reg_stat; + u32 reg_addr; + u32 reg_rdata; + u32 reg_wdata; +}; + +struct cx23885_dmaqueue { + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + u32 count; +}; + +struct cx23885_tsport { + struct cx23885_dev *dev; + + int nr; + int sram_chno; + + struct videobuf_dvb dvb; + + /* dma queues */ + struct cx23885_dmaqueue mpegq; + u32 ts_packet_size; + u32 ts_packet_count; + + int width; + int height; + + spinlock_t slock; + + /* registers */ + u32 reg_gpcnt; + u32 reg_gpcnt_ctl; + u32 reg_dma_ctl; + u32 reg_lngth; + u32 reg_hw_sop_ctrl; + u32 reg_gen_ctrl; + u32 reg_bd_pkt_status; + u32 reg_sop_status; + u32 reg_fifo_ovfl_stat; + u32 reg_vld_misc; + u32 reg_ts_clk_en; + u32 reg_ts_int_msk; + + /* Default register vals */ + int pci_irqmask; + u32 dma_ctl_val; + u32 ts_int_msk_val; + u32 gen_ctrl_val; + u32 ts_clk_en_val; +}; + +struct cx23885_dev { + struct list_head devlist; + atomic_t refcount; + + /* pci stuff */ + struct pci_dev *pci; + unsigned char pci_rev, pci_lat; + int pci_bus, pci_slot; + u32 __iomem *lmmio; + u8 __iomem *bmmio; + //u32 shadow[SHADOW_MAX]; + int pci_irqmask; + + /* I2C adapters: Master 1 and 2 (External) and Master 3 (Internal only) */ + struct cx23885_i2c i2c_bus[3]; + + int nr; + struct mutex lock; + + /* board details */ + unsigned int board; + char name[32]; + + struct cx23885_tsport ts2; + + /* sram configuration */ + struct sram_channel *sram_channels; +}; + +#define SRAM_CH01 0 /* Video A */ +#define SRAM_CH02 1 /* VBI A */ +#define SRAM_CH03 2 /* Video B */ +#define SRAM_CH04 3 /* Transport via B */ +#define SRAM_CH05 4 /* VBI B */ +#define SRAM_CH06 5 /* Video C */ +#define SRAM_CH07 6 /* Transport via C */ +#define SRAM_CH08 7 /* Audio Internal A */ +#define SRAM_CH09 8 /* Audio Internal B */ +#define SRAM_CH10 9 /* Audio External */ +#define SRAM_CH11 10 /* COMB_3D_N */ +#define SRAM_CH12 11 /* Comb 3D N1 */ +#define SRAM_CH13 12 /* Comb 3D N2 */ +#define SRAM_CH14 13 /* MOE Vid */ +#define SRAM_CH15 14 /* MOE RSLT */ + +struct sram_channel { + char *name; + u32 cmds_start; + u32 ctrl_start; + u32 cdt; + u32 fifo_start;; + u32 fifo_size; + u32 ptr1_reg; + u32 ptr2_reg; + u32 cnt1_reg; + u32 cnt2_reg; + u32 jumponly; +}; + +/* ----------------------------------------------------------- */ + +#define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) +#define cx_write(reg,value) writel((value), dev->lmmio + ((reg)>>2)) + +#define cx_andor(reg,mask,value) \ + writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ + ((value) & (mask)), dev->lmmio+((reg)>>2)) + +#define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) +#define cx_clear(reg,bit) cx_andor((reg),(bit),0) + + +extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc); + +/* ----------------------------------------------------------- */ +/* cx23885-cards.c */ + +extern struct cx23885_board cx23885_boards[]; +extern const unsigned int cx23885_bcount; + +extern struct cx23885_subid cx23885_subids[]; +extern const unsigned int cx23885_idcount; + +extern void cx23885_card_list(struct cx23885_dev *dev); +extern void cx23885_card_setup(struct cx23885_dev *dev); +extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); + +extern int cx23885_dvb_register(struct cx23885_tsport *port); +extern int cx23885_dvb_unregister(struct cx23885_tsport *port); + +extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, + struct cx23885_buffer *buf, enum v4l2_field field); + +extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); +extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); + +/* ----------------------------------------------------------- */ +/* cx23885-i2c.c */ +extern int cx23885_i2c_register(struct cx23885_i2c *bus); +extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); +extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ From 2f52cdb20955b024e6b48f4e3d797504c8568a6d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 11 Mar 2007 20:55:18 -0300 Subject: [PATCH 0696/2804] V4L/DVB (6151): include drivers/media/video/cx23885/Kconfig Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 04756c342cba..5d74925748c0 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -668,6 +668,8 @@ config VIDEO_HEXIUM_GEMINI source "drivers/media/video/cx88/Kconfig" +source "drivers/media/video/cx23885/Kconfig" + source "drivers/media/video/ivtv/Kconfig" config VIDEO_M32R_AR From 03121f05f98cf9bba8f0fe77ef381c17681e1386 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 11 Mar 2007 20:57:52 -0300 Subject: [PATCH 0697/2804] V4L/DVB (6152): cx23885: forward compatibility fixes for recent kernels - fix #include for - fix cx23885_irq declaration for 2.6.19 and later Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 2 +- drivers/media/video/cx23885/cx23885.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 876d396fb7a3..4e6e8737e38e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1361,7 +1361,7 @@ static void cx23885_timeout(unsigned long data) #define VID_C_MSK_RISCI2 (1 << 4) #define VID_C_MSK_RISCI1 1 -static irqreturn_t cx23885_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; struct cx23885_tsport *port = &dev->ts2; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index f58ab86bd532..769a0e7541c0 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -28,7 +28,9 @@ #include #include #include +#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) #include +#endif #include "btcx-risc.h" #include "cx23885-reg.h" From a2129af5b65e28dc3a10402603aa714e493b2169 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 16 Mar 2007 11:48:33 -0300 Subject: [PATCH 0698/2804] V4L/DVB (6153): I2C bus 3 register was incorrect I2C bus 3 was being initialised with the incorrect address register. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 4e6e8737e38e..fda0c1631dbd 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -722,7 +722,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->i2c_bus[2].dev = dev; dev->i2c_bus[2].reg_stat = I2C3_STAT; dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; - dev->i2c_bus[2].reg_addr = I2C2_ADDR; + dev->i2c_bus[2].reg_addr = I2C3_ADDR; dev->i2c_bus[2].reg_rdata = I2C3_RDATA; dev->i2c_bus[2].reg_wdata = I2C3_WDATA; dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ From 3bd4065961aa03d030cd58feec03d60479fc4348 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 17:46:03 -0300 Subject: [PATCH 0699/2804] V4L/DVB (6154): NMI hang and corrupt transport packet fixes The sram allocations for the cx23887 differ slightly from the cx23885. This patch modifies the cx23887 specific sram memory map to reflect this. As a result, interrupts and DMA handling have also been enabled in cx23885_start_dma() for 887 specific boards. ATSC streaming is now available on cx23885 and cx23887 bridges. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index fda0c1631dbd..5769db47529c 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -270,7 +270,7 @@ struct sram_channel cx23887_sram_channels[] = { .name = "TS2 C", .cmds_start = 0x10140, .ctrl_start = 0x10680, - .cdt = 0x10480, + .cdt = 0x108d0, .fifo_start = 0x6000, .fifo_size = 0x1000, .ptr1_reg = DMA5_PTR1, @@ -1095,16 +1095,13 @@ static int cx23885_start_dma(struct cx23885_tsport *port, */ switch(cx23885_boards[dev->board].bridge) { case CX23885_BRIDGE_885: + case CX23885_BRIDGE_887: /* enable irqs */ dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ ); cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); cx_set(port->reg_dma_ctl, port->dma_ctl_val); cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; - case CX23885_BRIDGE_887: - // FIXME - dprintk(1, "%s() NOT enabling TS int's and DMA, NMI bug\n", __FUNCTION__ ); - break; default: // FIXME: generate a sensible switch-default message printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); From 3328e4fbf10a2c2513d4de662ab251e0f4cb7c3e Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 18:01:07 -0300 Subject: [PATCH 0700/2804] V4L/DVB (6155): Cleanup/remove code to access the sram memory maps The cx23885 and cx23887 family use two different memory maps which govern how the internal SRAM is configured. This patch streamlines the access to those structures. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 77 +--------------------- drivers/media/video/cx23885/cx23885.h | 2 - 2 files changed, 3 insertions(+), 76 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 5769db47529c..b1f75350e83d 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -584,7 +584,6 @@ void cx23885_reset(struct cx23885_dev *dev) mdelay(100); -#if SRAM cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); @@ -595,37 +594,6 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); -#else - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_885: - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH01 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH03 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH04 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH05 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH06 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH07 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH08 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH09 ], 128, 0); - break; - case CX23885_BRIDGE_887: - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH01 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH03 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH04 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH05 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH06 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH07 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH08 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH09 ], 128, 0); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } -#endif - switch(dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ @@ -1019,38 +987,14 @@ static int cx23885_start_dma(struct cx23885_tsport *port, dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, buf->vb.width, buf->vb.height, buf->vb.field); -#if SRAM /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[ port->sram_chno ], port->ts_packet_size, buf->risc.dma); - if(debug > 5) + if(debug > 5) { cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); -#else - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_885: - cx23885_sram_channel_setup(dev, - &cx23885_sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); - if(debug > 5) - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ] ); - break; - case CX23885_BRIDGE_887: - cx23885_sram_channel_setup(dev, - &cx23887_sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); - if(debug > 5) - cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ] ); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } -#endif - - if(debug > 5) cx23885_risc_disasm(port, &buf->risc); + } /* write TS length to chip */ cx_write(port->reg_lngth, buf->vb.width); @@ -1323,18 +1267,8 @@ static void cx23885_timeout(unsigned long data) dprintk(1, "%s()\n",__FUNCTION__); if (debug > 5) -#if SRAM cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); -#else - { - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_885) - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); - if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_887) - cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ]); - } -#endif + cx23885_stop_dma(port); do_cancel_buffers(port, "timeout", 1); } @@ -1431,12 +1365,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); cx_clear(port->reg_dma_ctl, port->dma_ctl_val); -#if SRAM cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); -#else - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); -#endif - } else if (ts2_status & VID_C_MSK_RISCI1) { diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 769a0e7541c0..04105bcf53f3 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -44,8 +44,6 @@ #define CX23885_MAXBOARDS 8 -#define SRAM 0 - /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 From 0fc0739ba940c07e97599a7ee04c24faae9808ed Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 18:03:03 -0300 Subject: [PATCH 0701/2804] V4L/DVB (6156): Added the I2C_FUNC_I2C support to the cx23885 i2c algo definition This is required to support the cx258xx family of audio and video decoders. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 6f5e207c11a6..dbd048d08dda 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -279,7 +279,7 @@ static int cx23885_algo_control(struct i2c_adapter *adap, static u32 cx23885_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } static struct i2c_algorithm cx23885_i2c_algo_template = { From e133be0f587996f112d7984c03606af418a7ca05 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 19:22:41 -0300 Subject: [PATCH 0702/2804] V4L/DVB (6157): Removed the need to manually define .bridge for each card Moved the field from cx23885_board to cx23885_dev and added code to iautomatically set the bridge type based on the pci device id. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 3 --- drivers/media/video/cx23885/cx23885-core.c | 24 ++++++++++----------- drivers/media/video/cx23885/cx23885.h | 11 +++++----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 9344fb5d95f6..decf602ab164 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -32,7 +32,6 @@ struct cx23885_board cx23885_boards[] = { [CX23885_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", - .bridge = CX23885_BRIDGE_UNDEFINED, .input = {{ .type = CX23885_VMUX_COMPOSITE1, .vmux = 0, @@ -49,7 +48,6 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { .name = "Hauppauge WinTV-HVR1800lp", - .bridge = CX23885_BRIDGE_885, .portc = CX23885_MPEG_DVB, .input = {{ .type = CX23885_VMUX_TELEVISION, @@ -71,7 +69,6 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800] = { .name = "Hauppauge WinTV-HVR1800", - .bridge = CX23885_BRIDGE_887, .portc = CX23885_MPEG_DVB, .input = {{ .type = CX23885_VMUX_TELEVISION, diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index b1f75350e83d..d8e376dee68b 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -452,8 +452,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, cx_write(ch->cnt2_reg, (lines*16) >> 3); cx_write(ch->cnt1_reg, (bpl >> 3) -1); - dprintk(2,"[bridged %d] sram setup %s: bpl=%d lines=%d\n", - cx23885_boards[dev->board].bridge, + dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n", + dev->bridge, ch->name, bpl, lines); @@ -770,18 +770,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - /* Configure the hardware internal memory for fifos */ - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_UNDEFINED: - case CX23885_BRIDGE_885: - dev->sram_channels = cx23885_sram_channels; - break; - case CX23885_BRIDGE_887: + /* Configure the internal memory */ + if(dev->pci->device == 0x8880) { + dev->bridge = CX23885_BRIDGE_887; dev->sram_channels = cx23887_sram_channels; - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } else + if(dev->pci->device == 0x8852) { + dev->bridge = CX23885_BRIDGE_885; + dev->sram_channels = cx23885_sram_channels; } + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); /* init hardware */ cx23885_reset(dev); @@ -1037,7 +1035,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, * starting or stopping interrupts or dma. Avoid the bug for the time being, * enabling the developer to work on the demod/tuner locking work. */ - switch(cx23885_boards[dev->board].bridge) { + switch(dev->bridge) { case CX23885_BRIDGE_885: case CX23885_BRIDGE_887: /* enable irqs */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 04105bcf53f3..4e1fc68d4206 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -101,11 +101,6 @@ struct cx23885_board { CX23885_MPEG_UNDEFINED = 0, CX23885_MPEG_DVB } portc; - enum { - CX23885_BRIDGE_UNDEFINED = 0, - CX23885_BRIDGE_885 = 885, - CX23885_BRIDGE_887 = 887, - } bridge; struct cx23885_input input[MAX_CX23885_INPUT]; }; @@ -210,6 +205,12 @@ struct cx23885_dev { /* sram configuration */ struct sram_channel *sram_channels; + + enum { + CX23885_BRIDGE_UNDEFINED = 0, + CX23885_BRIDGE_885 = 885, + CX23885_BRIDGE_887 = 887, + } bridge; }; #define SRAM_CH01 0 /* Video A */ From fe475163ff9680495af3b1b5b7633ea7a42e4185 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 20 Mar 2007 15:27:53 -0300 Subject: [PATCH 0703/2804] V4L/DVB (6158): Fix MT2131 tuner lock status problem The mt2131 tuner reports lock even when the hardware should not lock. This patch allows the s5h1409 demodulator to be configured to query either the tuner driver for status, or the demodulator status when the application requests lock status. This avoids returning false CARRIER and/or SIGNAL lock status. S5H1409 and MT2131 drivers. This is the remainder of the changeset, which only touches cx23885-dvb.c Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 4ff85f75f9f7..188a5a7819cb 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -84,7 +84,8 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING }; static struct s5h1409_config hauppauge_hvr1800_config = { @@ -92,7 +93,8 @@ static struct s5h1409_config hauppauge_hvr1800_config = { .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_ON, .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING }; From 047646bfbbe5ec961d2430514ae29fa0b87ab651 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 20 Mar 2007 15:33:53 -0300 Subject: [PATCH 0704/2804] V4L/DVB (6159): General code cleanup Removed if 0'd code, removed cx88 references. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 6 +++--- drivers/media/video/cx23885/cx23885.h | 10 +--------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d8e376dee68b..804ba7ff9770 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1498,9 +1498,9 @@ static struct pci_driver cx23885_pci_driver = { static int cx23885_init(void) { printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); + (CX23885_VERSION_CODE >> 16) & 0xff, + (CX23885_VERSION_CODE >> 8) & 0xff, + CX23885_VERSION_CODE & 0xff); #ifdef SNAPSHOT printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4e1fc68d4206..b60de21c2387 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -38,7 +38,7 @@ #include #include -#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6) +#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1) #define UNSET (-1U) @@ -69,14 +69,6 @@ enum cx23885_itype { CX23885_RADIO, }; -struct cx23885_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int flags; - u32 cxformat; -}; - /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ From 70ebd70573a58a2c0405ef038f1acf74c795eaa5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 21:32:12 -0300 Subject: [PATCH 0705/2804] V4L/DVB (6161): cx23885-dvb.c doesnt need to include dvb-pll.h The dvb-pll module is not being used by this driver. Remove the unneeded #include. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 188a5a7819cb..79948553901d 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -28,7 +28,6 @@ #include #include "cx23885.h" -#include "dvb-pll.h" #include #include "s5h1409.h" From 44a6481dcd9ec835bbd608b1b2ee47ee62c7e1d8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:00:18 -0300 Subject: [PATCH 0706/2804] V4L/DVB (6162): cx23885: whitespace cleanups Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 3 +- drivers/media/video/cx23885/cx23885-core.c | 273 +++++++++++--------- drivers/media/video/cx23885/cx23885-dvb.c | 59 +++-- drivers/media/video/cx23885/cx23885-i2c.c | 40 +-- drivers/media/video/cx23885/cx23885.h | 17 +- 5 files changed, 210 insertions(+), 182 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index decf602ab164..8bb3fe4a876c 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -171,7 +171,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) if (dev->i2c_bus[0].i2c_rc == 0) { dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); + tveeprom_read(&dev->i2c_bus[0].i2c_client, + eeprom, sizeof(eeprom)); } switch (dev->board) { diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 804ba7ff9770..6f0a8dbc6b3b 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -349,15 +349,15 @@ static int cx23885_risc_decode(u32 risc) printk("0x%08x [ %s", risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(" %s",bits[i]); + printk(" %s", bits[i]); printk(" count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count) + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; @@ -374,7 +374,7 @@ void cx23885_wakeup(struct cx23885_tsport *port, if ((s16) (count - buf->count) < 0) break; do_gettimeofday(&buf->vb.ts); - dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); buf->vb.state = STATE_DONE; list_del(&buf->vb.queue); @@ -383,31 +383,34 @@ void cx23885_wakeup(struct cx23885_tsport *port, if (list_empty(&q->active)) { del_timer(&q->timeout); } else { - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); } if (bc != 1) - printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); + printk("%s: %d buffers handled (should be 1)\n", + __FUNCTION__, bc); } void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch); + struct sram_channel *ch); int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) + struct sram_channel *ch, + unsigned int bpl, u32 risc) { - unsigned int i,lines; + unsigned int i, lines; u32 cdt; if (ch->cmds_start == 0) { - dprintk(1, "%s() Erasing channel [%s]\n",__FUNCTION__, ch->name); + dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__, + ch->name); cx_write(ch->ptr1_reg, 0); cx_write(ch->ptr2_reg, 0); cx_write(ch->cnt2_reg, 0); cx_write(ch->cnt1_reg, 0); return 0; } else { - dprintk(1, "%s() Configuring channel [%s]\n",__FUNCTION__, ch->name); + dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__, + ch->name); } bpl = (bpl + 7) & ~7; /* alignment */ @@ -417,13 +420,14 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, lines = 6; BUG_ON(lines < 2); - cx_write(8+0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); - cx_write(8+4, cpu_to_le32(8) ); - cx_write(8+8, cpu_to_le32(0) ); + cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); + cx_write(8 + 4, cpu_to_le32(8) ); + cx_write(8 + 8, cpu_to_le32(0) ); /* write CDT */ for (i = 0; i < lines; i++) { - dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, ch->fifo_start + bpl*i); + dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, + ch->fifo_start + bpl*i); cx_write(cdt + 16*i, ch->fifo_start + bpl*i); cx_write(cdt + 16*i + 4, 0); cx_write(cdt + 16*i + 8, 0); @@ -462,7 +466,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, } void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch) + struct sram_channel *ch) { static char *name[] = { "init risc lo", @@ -481,7 +485,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, "line / byte", }; u32 risc; - unsigned int i,j,n; + unsigned int i, j, n; printk("%s: %s - dma channel status dump\n", dev->name, ch->name); @@ -491,16 +495,19 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, cx_read(ch->cmds_start + 4*i)); for (i = 0; i < 4; i++) { - risc = cx_read(ch->cmds_start + 4 * (i+14)); + risc = cx_read(ch->cmds_start + 4 * (i + 14)); printk("%s: risc%d: ", dev->name, i); cx23885_risc_decode(risc); } for (i = 0; i < (64 >> 2); i += n) { - risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */ - printk("%s: (0x%08x) iq %x: ", dev->name, ch->ctrl_start + 4 * i, i); + risc = cx_read(ch->ctrl_start + 4 * i); + /* No consideration for bits 63-32 */ + + printk("%s: (0x%08x) iq %x: ", dev->name, + ch->ctrl_start + 4 * i, i); n = cx23885_risc_decode(risc); for (j = 1; j < n; j++) { - risc = cx_read(ch->ctrl_start + 4 * (i+j)); + risc = cx_read(ch->ctrl_start + 4 * (i + j)); printk("%s: iq %x: 0x%08x [ arg #%d ]\n", dev->name, i+j, risc, j); } @@ -509,7 +516,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, printk("%s: fifo: 0x%08x -> 0x%x\n", dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); printk("%s: ctrl: 0x%08x -> 0x%x\n", - dev->name, ch->ctrl_start, ch->ctrl_start+6*16); + dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); printk("%s: ptr1_reg: 0x%08x\n", dev->name, cx_read(ch->ptr1_reg)); printk("%s: ptr2_reg: 0x%08x\n", @@ -520,10 +527,11 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, dev->name, cx_read(ch->cnt2_reg)); } -void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) +void cx23885_risc_disasm(struct cx23885_tsport *port, + struct btcx_riscmem *risc) { struct cx23885_dev *dev = port->dev; - unsigned int i,j,n; + unsigned int i, j, n; printk("%s: risc disasm: %p [dma=0x%08lx]\n", dev->name, risc->cpu, (unsigned long)risc->dma); @@ -532,7 +540,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) n = cx23885_risc_decode(risc->cpu[i]); for (j = 1; j < n; j++) printk("%s: %04d: 0x%08x [ arg #%d ]\n", - dev->name, i+j, risc->cpu[i+j], j); + dev->name, i + j, risc->cpu[i + j], j); if (risc->cpu[i] == RISC_JUMP) break; } @@ -625,8 +633,8 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) static int get_resources(struct cx23885_dev *dev) { if (request_mem_region(pci_resource_start(dev->pci,0), - pci_resource_len(dev->pci,0), - dev->name)) + pci_resource_len(dev->pci,0), + dev->name)) return 0; printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", @@ -637,7 +645,7 @@ static int get_resources(struct cx23885_dev *dev) static void cx23885_timeout(unsigned long data); int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); + u32 reg, u32 mask, u32 value); static int cx23885_ir_init(struct cx23885_dev *dev) { @@ -726,15 +734,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, + dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - sprintf(dev->name,"cx23885[%d]", dev->nr); + sprintf(dev->name, "cx23885[%d]", dev->nr); if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " - "subsystem: %04x:%04x\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device); + "subsystem: %04x:%04x\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device); cx23885_devcount--; goto fail_free; @@ -746,7 +755,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) /* PCIe stuff */ dev->lmmio = ioremap(pci_resource_start(dev->pci,0), - pci_resource_len(dev->pci,0)); + pci_resource_len(dev->pci,0)); dev->bmmio = (u8 __iomem *)dev->lmmio; @@ -765,10 +774,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_list(dev); } printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, cx23885_boards[dev->board].name, - dev->board, card[dev->nr] == dev->board ? - "insmod option" : "autodetected"); + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx23885_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); /* Configure the internal memory */ if(dev->pci->device == 0x8880) { @@ -779,7 +788,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bridge = CX23885_BRIDGE_885; dev->sram_channels = cx23885_sram_channels; } - dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", + __FUNCTION__, dev->bridge); /* init hardware */ cx23885_reset(dev); @@ -793,7 +803,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_ir_init(dev); if (cx23885_dvb_register(&dev->ts2) < 0) { - printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); + printk(KERN_ERR "%s() Failed to register dvb adapters\n", + __FUNCTION__); } return 0; @@ -820,12 +831,12 @@ void cx23885_dev_unregister(struct cx23885_dev *dev) } static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines) { struct scatterlist *sg; - unsigned int line,todo; + unsigned int line, todo; /* sync instruction */ if (sync_line != NO_SYNC_LINE) @@ -874,11 +885,11 @@ static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, } int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int top_offset, unsigned int bottom_offset, - unsigned int bpl, unsigned int padding, unsigned int lines) + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines) { - u32 instructions,fields; + u32 instructions, fields; u32 *rp; int rc; @@ -903,10 +914,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); + bpl, padding, lines); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); + bpl, padding, lines); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -915,8 +926,8 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines) { u32 instructions; u32 *rp; @@ -945,7 +956,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) + u32 reg, u32 mask, u32 value) { u32 *rp; int rc; @@ -969,7 +980,7 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) { BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(&buf->vb, 0, 0); videobuf_dma_unmap(q, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); @@ -977,18 +988,18 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) } static int cx23885_start_dma(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, - struct cx23885_buffer *buf) + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) { struct cx23885_dev *dev = port->dev; dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, - buf->vb.width, buf->vb.height, buf->vb.field); + buf->vb.width, buf->vb.height, buf->vb.field); /* setup fifo + format */ cx23885_sram_channel_setup(dev, - &dev->sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); + &dev->sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); if(debug > 5) { cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); cx23885_risc_disasm(port, &buf->risc); @@ -998,8 +1009,8 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_lngth, buf->vb.width); if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { - printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", __FUNCTION__, - cx23885_boards[dev->board].portc ); + printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", + __FUNCTION__, cx23885_boards[dev->board].portc ); return -EINVAL; } @@ -1017,7 +1028,8 @@ static int cx23885_start_dma(struct cx23885_tsport *port, case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1800: cx_write(port->reg_vld_misc, 0x00); - dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", __FUNCTION__); + dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", + __FUNCTION__); break; default: // FIXME @@ -1103,53 +1115,54 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, dprintk(5, "%s()\n", __FUNCTION__); if (list_empty(&q->active)) { - struct cx23885_buffer *prev; - prev = NULL; + struct cx23885_buffer *prev; + prev = NULL; dprintk(5, "%s() queue is empty\n", __FUNCTION__); - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, vb.queue); - if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - cx23885_start_dma(port, q, buf); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(5,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, + vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_dma(port, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(5, "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ - dprintk(5,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); - } else { - return 0; - } - prev = buf; - } + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk(5,"[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); + } else { + return 0; + } + prev = buf; + } return 0; } buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", + dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx23885_start_dma(port, q, buf); - list_for_each(item,&q->active) { + list_for_each(item, &q->active) { buf = list_entry(item, struct cx23885_buffer, vb.queue); buf->count = q->count++; } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); return 0; } @@ -1172,7 +1185,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, buf->vb.size = size; buf->vb.field = field /*V4L2_FIELD_TOP*/; - if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, buf->vb.dma.sglist, @@ -1182,7 +1195,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, return 0; fail: - cx23885_free_buffer(q,buf); + cx23885_free_buffer(q, buf); return rc; } @@ -1199,51 +1212,53 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) if (list_empty(&cx88q->active)) { dprintk( 1, "queue is empty - first active\n" ); - list_add_tail(&buf->vb.queue,&cx88q->active); + list_add_tail(&buf->vb.queue, &cx88q->active); cx23885_start_dma(port, cx88q, buf); buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; - mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(1,"[%p/%d] %s - first active\n", + mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); + dprintk(1, "[%p/%d] %s - first active\n", buf, buf->vb.i, __FUNCTION__); } else { dprintk( 1, "queue is not empty - append to active\n" ); - prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); - list_add_tail(&buf->vb.queue,&cx88q->active); + prev = list_entry(cx88q->active.prev, struct cx23885_buffer, + vb.queue); + list_add_tail(&buf->vb.queue, &cx88q->active); buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ dprintk( 1, "[%p/%d] %s - append to active\n", - buf, buf->vb.i, __FUNCTION__); + buf, buf->vb.i, __FUNCTION__); } } /* ----------------------------------------------------------- */ -static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, int restart) +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, + int restart) { struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; struct cx23885_buffer *buf; unsigned long flags; - spin_lock_irqsave(&port->slock,flags); + spin_lock_irqsave(&port->slock, flags); while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); list_del(&buf->vb.queue); buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); - dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", + dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); } - if (restart) - { + if (restart) { dprintk(1, "restarting queue\n" ); cx23885_restart_queue(port, q); } - spin_unlock_irqrestore(&port->slock,flags); + spin_unlock_irqrestore(&port->slock, flags); } void cx23885_cancel_buffers(struct cx23885_tsport *port) @@ -1251,7 +1266,7 @@ void cx23885_cancel_buffers(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; - dprintk(1, "%s()\n", __FUNCTION__ ); + dprintk(1, "%s()\n", __FUNCTION__); del_timer_sync(&q->timeout); cx23885_stop_dma(port); do_cancel_buffers(port, "cancel", 0); @@ -1312,15 +1327,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); if ( (pci_status & PCI_MSK_RISC_RD) || - (pci_status & PCI_MSK_RISC_WR) || - (pci_status & PCI_MSK_AL_RD) || - (pci_status & PCI_MSK_AL_WR) || - (pci_status & PCI_MSK_APB_DMA) || - (pci_status & PCI_MSK_VID_C) || - (pci_status & PCI_MSK_VID_B) || - (pci_status & PCI_MSK_VID_A) || - (pci_status & PCI_MSK_AUD_INT) || - (pci_status & PCI_MSK_AUD_EXT) ) + (pci_status & PCI_MSK_RISC_WR) || + (pci_status & PCI_MSK_AL_RD) || + (pci_status & PCI_MSK_AL_WR) || + (pci_status & PCI_MSK_APB_DMA) || + (pci_status & PCI_MSK_VID_C) || + (pci_status & PCI_MSK_VID_B) || + (pci_status & PCI_MSK_VID_A) || + (pci_status & PCI_MSK_AUD_INT) || + (pci_status & PCI_MSK_AUD_EXT) ) { if (pci_status & PCI_MSK_RISC_RD) @@ -1347,9 +1362,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } if ( (ts2_status & VID_C_MSK_OPC_ERR) || - (ts2_status & VID_C_MSK_BAD_PKT) || - (ts2_status & VID_C_MSK_SYNC) || - (ts2_status & VID_C_MSK_OF)) + (ts2_status & VID_C_MSK_BAD_PKT) || + (ts2_status & VID_C_MSK_SYNC) || + (ts2_status & VID_C_MSK_OF)) { if (ts2_status & VID_C_MSK_OPC_ERR) dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); @@ -1392,12 +1407,12 @@ out: } static int __devinit cx23885_initdev(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) + const struct pci_device_id *pci_id) { struct cx23885_dev *dev; int err; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (NULL == dev) return -ENOMEM; @@ -1428,8 +1443,8 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, goto fail_irq; } - err = request_irq(pci_dev->irq, cx23885_irq - , IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + err = request_irq(pci_dev->irq, cx23885_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, pci_dev->irq); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 79948553901d..bd0afc2a0447 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -53,11 +53,11 @@ static int dvb_buf_setup(struct videobuf_queue *q, return 0; } -static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int dvb_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_tsport *port = q->priv_data; - return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb,field); + return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field); } static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) @@ -66,7 +66,8 @@ static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) cx23885_buf_queue(port, (struct cx23885_buffer*)vb); } -static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void dvb_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) { cx23885_free_buffer(q, (struct cx23885_buffer*)vb); } @@ -116,26 +117,22 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800lp_config, - &dev->i2c_bus[0].i2c_adap); + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, - port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800lp_rev2_tunerconfig, - 0); + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800lp_rev2_tunerconfig, 0); } break; case CX23885_BOARD_HAUPPAUGE_HVR1800: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800_config, - &dev->i2c_bus[0].i2c_adap); + &hauppauge_hvr1800_config, + &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, - port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800_tunerconfig, - 0); + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800_tunerconfig, 0); } break; default: @@ -152,7 +149,8 @@ static int dvb_register(struct cx23885_tsport *port) cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); /* register everything */ - return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); + return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, + &dev->pci->dev); } int cx23885_dvb_register(struct cx23885_tsport *port) @@ -160,8 +158,8 @@ int cx23885_dvb_register(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; int err; - dprintk( 1, "%s\n", __FUNCTION__); - dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dprintk(1, "%s\n", __FUNCTION__); + dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", dev->board, dev->name, dev->pci_bus, @@ -173,15 +171,9 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_init( - &port->dvb.dvbq, - &dvb_qops, - dev->pci, - &port->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_TOP, - sizeof(struct cx23885_buffer), - port); + videobuf_queue_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, + sizeof(struct cx23885_buffer), port); err = dvb_register(port); if (err != 0) printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); @@ -198,3 +190,10 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) return 0; } + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off +*/ diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index dbd048d08dda..155ab928cd60 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -31,11 +31,11 @@ static unsigned int i2c_debug = 2; module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); static unsigned int i2c_scan = 0; module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); #define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) @@ -76,7 +76,8 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap) return 1; } -static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int last) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -150,11 +151,12 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg eio: retval = -EIO; err: - printk(" ERR: %d\n",retval); + printk(" ERR: %d\n", retval); return retval; } -static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +static int i2c_readbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int last) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -206,11 +208,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg eio: retval = -EIO; err: - printk(" ERR: %d\n",retval); + printk(" ERR: %d\n", retval); return retval; } -static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +static int i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -219,8 +222,8 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) dprintk(1, "%s(num = %d)\n", __FUNCTION__, num); for (i = 0 ; i < num; i++) { - dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n" - , __FUNCTION__, num, msgs[i].addr, msgs[i].len); + dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", + __FUNCTION__, num, msgs[i].addr, msgs[i].len); if (msgs[i].flags & I2C_M_RD) { /* read */ retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); @@ -261,7 +264,8 @@ static int detach_inform(struct i2c_client *client) return 0; } -void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) +void cx23885_call_i2c_clients(struct cx23885_i2c *bus, + unsigned int cmd, void *arg) { // struct cx23885_dev *dev = bus->dev; @@ -316,11 +320,11 @@ static char *i2c_devs[128] = { static void do_i2c_scan(char *name, struct i2c_client *c) { unsigned char buf; - int i,rc; + int i, rc; for (i = 0; i < 128; i++) { c->addr = i; - rc = i2c_master_recv(c,&buf,0); + rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; printk("%s: i2c scan: found device @ 0x%x [%s]\n", @@ -335,13 +339,17 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr); - memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx23885_i2c_client_template, sizeof(bus->i2c_client)); + memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, + sizeof(bus->i2c_adap)); + memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, + sizeof(bus->i2c_algo)); + memcpy(&bus->i2c_client, &cx23885_i2c_client_template, + sizeof(bus->i2c_client)); bus->i2c_adap.dev.parent = &dev->pci->dev; - strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + strlcpy(bus->i2c_adap.name, bus->dev->name, + sizeof(bus->i2c_adap.name)); bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index b60de21c2387..4312c3fcc1ec 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -183,7 +183,7 @@ struct cx23885_dev { //u32 shadow[SHADOW_MAX]; int pci_irqmask; - /* I2C adapters: Master 1 and 2 (External) and Master 3 (Internal only) */ + /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ struct cx23885_i2c i2c_bus[3]; int nr; @@ -268,17 +268,22 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); extern int cx23885_dvb_register(struct cx23885_tsport *port); extern int cx23885_dvb_unregister(struct cx23885_tsport *port); -extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, - struct cx23885_buffer *buf, enum v4l2_field field); +extern int cx23885_buf_prepare(struct videobuf_queue *q, + struct cx23885_tsport *port, + struct cx23885_buffer *buf, + enum v4l2_field field); -extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); -extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); +extern void cx23885_buf_queue(struct cx23885_tsport *port, + struct cx23885_buffer *buf); +extern void cx23885_free_buffer(struct videobuf_queue *q, + struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ /* cx23885-i2c.c */ extern int cx23885_i2c_register(struct cx23885_i2c *bus); extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); -extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); +extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, + void *arg); /* * Local variables: From 60a41d3b61a714d98a36cddbe182cc6ff0794274 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:03:52 -0300 Subject: [PATCH 0707/2804] V4L/DVB (6163): cx23885: remove old comments Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 4 ---- drivers/media/video/cx23885/cx23885-i2c.c | 4 +--- drivers/media/video/cx23885/cx23885-reg.h | 11 ++--------- drivers/media/video/cx23885/cx23885.h | 3 --- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 6f0a8dbc6b3b..3e1b62a2d50d 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1043,10 +1043,6 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; - /* A bug in the current 887 implementation, causes an NMI assert during - * starting or stopping interrupts or dma. Avoid the bug for the time being, - * enabling the developer to work on the demod/tuner locking work. - */ switch(dev->bridge) { case CX23885_BRIDGE_885: case CX23885_BRIDGE_887: diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 155ab928cd60..c40c37f2d139 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -267,12 +267,10 @@ static int detach_inform(struct i2c_client *client) void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) { -// struct cx23885_dev *dev = bus->dev; - if (bus->i2c_rc != 0) return; - i2c_clients_command(&bus->i2c_adap, cmd, arg); + i2c_clients_command(&bus->i2c_adap, cmd, arg); } static int cx23885_algo_control(struct i2c_adapter *adap, diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 5cb692f20d28..771b22ac2153 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -71,21 +71,14 @@ Channel manager Data Structure entry = 20 DWORD #define RISC_WRITECM 0xC0000000 #define RISC_WRITECR 0xD0000000 -//#define RISC_SYNC_ODD 0x80000000 -//#define RISC_SYNC_EVEN 0x80000200 -//#define RISC_RESYNC_ODD 0x80008000 -//#define RISC_RESYNC_EVEN 0x80008200 -// Do we need these? +/* Do we need these? */ #define RISC_WRITEC 0x50000000 #define RISC_READC 0xA0000000 -// Is this used? +/* Is this used? */ #define RISC_IMM 0x00000001 -//#define RISC_CNT_NONE 0x00000000 -//#define RISC_CNT_RSVR 0x00020000 -//#define RISC_JMP_SRP 0x01 /* Audio and Video Core */ #define HOST_REG1 0x00000000 diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4312c3fcc1ec..929235440e23 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -47,8 +47,6 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 -//#define SHADOW_MAX 3 - #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ #define CX23885_BOARD_NOAUTO UNSET @@ -180,7 +178,6 @@ struct cx23885_dev { int pci_bus, pci_slot; u32 __iomem *lmmio; u8 __iomem *bmmio; - //u32 shadow[SHADOW_MAX]; int pci_irqmask; /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ From 3c5666aee31decafdca14f6f83d33ec27b27f982 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:18:04 -0300 Subject: [PATCH 0708/2804] V4L/DVB (6164): cx23885: turn off i2c_debug by default Turn off i2c_debug by default, to make the driver less verbose. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index c40c37f2d139..6b49b414aebf 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -29,7 +29,7 @@ #include -static unsigned int i2c_debug = 2; +static unsigned int i2c_debug = 0; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); From b86b580244511f9b2fb2043d813e9c4c7d294a62 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 22 Mar 2007 01:01:53 -0300 Subject: [PATCH 0709/2804] V4L/DVB (6165): cx23885: fix Kconfig dependencies Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ea53466dacbe..333dd29d44b4 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -8,6 +8,9 @@ config VIDEO_CX23885 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR + select VIDEO_BUF_DVB + select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE + select DVB_S5H1409 if !DVB_FE_CUSTOMISE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. From 426d523664e01c778f6455e9b3bbd40dda76c66a Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 14 Aug 2007 23:35:16 -0300 Subject: [PATCH 0710/2804] V4L/DVB (6166): cx23885: Ensure pci_quirks is called after board identification The pci_quirks function was being called too early during initialisation, it needs to be called after the board has been identified. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 3e1b62a2d50d..691672947084 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -759,8 +759,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bmmio = (u8 __iomem *)dev->lmmio; - cx23885_pci_quirks(dev); - /* board config */ dev->board = UNSET; if (card[dev->nr] < cx23885_bcount) @@ -779,6 +777,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); + cx23885_pci_quirks(dev); + /* Configure the internal memory */ if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; From 4823e9ee9f45c78777d040742b5e46336a42c8b3 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Wed, 22 Aug 2007 20:52:21 -0300 Subject: [PATCH 0711/2804] V4L/DVB (6167): cx23885: Changed PCI quirks to after bridge detech Changed the pci_quirks function to detech the bridge type before setting the NMI clear bit, rather than detecting based on unique board id. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 691672947084..d2bc3e586623 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -622,11 +622,9 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); - switch(dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + if(dev->bridge == CX23885_BRIDGE_885) cx_clear(RDR_TLCTL0, 1 << 4); - break; - } + return 0; } @@ -777,8 +775,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - cx23885_pci_quirks(dev); - /* Configure the internal memory */ if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; @@ -791,6 +787,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); + cx23885_pci_quirks(dev); + /* init hardware */ cx23885_reset(dev); From a77743bc2d29197d48a6f4ae9f8f9e0f0b0ba5d7 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Wed, 22 Aug 2007 21:01:20 -0300 Subject: [PATCH 0712/2804] V4L/DVB (6168): cx23885: Added HVR1250 ATSC support Adding support for the Hauppauge HVR1250 PCIe ATSC board. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 26 +++++++++++++++++++++ drivers/media/video/cx23885/cx23885-core.c | 7 ++++++ drivers/media/video/cx23885/cx23885-dvb.c | 24 +++++++++++++++++++ drivers/media/video/cx23885/cx23885.h | 1 + 4 files changed, 58 insertions(+) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 8bb3fe4a876c..e6d34fb5b943 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -88,6 +88,27 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0xff02, }}, }, + [CX23885_BOARD_HAUPPAUGE_HVR1250] = { + .name = "Hauppauge WinTV-HVR1250", + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -111,6 +132,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7801, .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + },{ + .subvendor = 0x0070, + .subdevice = 0x7911, + .card = CX23885_BOARD_HAUPPAUGE_HVR1250, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -176,6 +201,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) } switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: if (dev->i2c_bus[0].i2c_rc == 0) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d2bc3e586623..1148d684188a 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -603,6 +603,11 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* GPIO-0 cx24227 demodulator reset */ + dprintk( 1, "%s() Configuring HVR1250 GPIO's\n", __FUNCTION__); + cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ + break; case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ /* GPIO-1 656_D0 */ @@ -650,6 +655,7 @@ static int cx23885_ir_init(struct cx23885_dev *dev) dprintk(1, "%s()\n", __FUNCTION__); switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); break; @@ -1023,6 +1029,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(GPIO2, 0x00); switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1800: cx_write(port->reg_vld_misc, 0x00); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index bd0afc2a0447..63a1dde0d17a 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -97,6 +97,16 @@ static struct s5h1409_config hauppauge_hvr1800_config = { .status_mode = S5H1409_DEMODLOCKING }; +static struct s5h1409_config hauppauge_hvr1250_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING +}; + + static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { 0x61 @@ -106,6 +116,10 @@ static struct mt2131_config hauppauge_hvr1800_tunerconfig = { 0x61 }; +static struct mt2131_config hauppauge_hvr1250_tunerconfig = { + 0x61 +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -115,6 +129,16 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1250_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1250_tunerconfig, 0); + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_hvr1800lp_config, diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 929235440e23..300a97980acb 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -53,6 +53,7 @@ #define CX23885_BOARD_UNKNOWN 0 #define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 +#define CX23885_BOARD_HAUPPAUGE_HVR1250 3 enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, From f29379c3619d85e0bdc0ee30c8199f7f66866fcf Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:15:46 -0300 Subject: [PATCH 0713/2804] V4L/DVB (6169): Removed unused function mt2131_set_gpo() Unused code is removed. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 6bcc4ccc9911..4b93931de4e1 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -91,17 +91,6 @@ static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) return 0; } -static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) -{ - struct mt2131_priv *priv = fe->tuner_priv; - u8 v; - - mt2131_readreg(priv, 0x07, &v); - mt2131_writereg(priv, 0x07, (v & 0xfe) | (val & 0x01)); - - return 0; -} - static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { From 2e52f215be1b3a0337788c8d3345bdf5e3894e19 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:32:41 -0300 Subject: [PATCH 0714/2804] V4L/DVB (6170): cx23885: General cleanup of old code Removed unused code. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 1 - drivers/media/video/cx23885/cx23885-core.c | 40 ++------------------- drivers/media/video/cx23885/cx23885-dvb.c | 4 +-- drivers/media/video/cx23885/cx23885-i2c.c | 3 +- drivers/media/video/cx23885/cx23885-reg.h | 9 ----- drivers/media/video/cx23885/cx23885.h | 1 - 6 files changed, 4 insertions(+), 54 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index e6d34fb5b943..09d4376c2e05 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -172,7 +172,6 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data); - /* Make sure we support the board model */ switch (tv.model) { diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 1148d684188a..7a1c4672041d 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -368,11 +368,13 @@ void cx23885_wakeup(struct cx23885_tsport *port, break; buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- * this trick handles wrap-arounds correctly for * up to 32767 buffers in flight... */ if ((s16) (count - buf->count) < 0) break; + do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); @@ -910,7 +912,6 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 2; - //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) return rc; @@ -945,7 +946,6 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 1; - //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) return rc; @@ -970,7 +970,6 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, /* write risc instructions */ rp = risc->cpu; - //*(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM); *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); *(rp++) = cpu_to_le32(reg); *(rp++) = cpu_to_le32(value); @@ -1018,16 +1017,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port, return -EINVAL; } - // FIXME: review the need for these two lines - dprintk( 1, "%s() doing .dvb\n", __FUNCTION__); udelay(100); cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); - // FIXME: review the need for this - cx_write(GPIO2, 0x00); - switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: @@ -1037,7 +1031,6 @@ static int cx23885_start_dma(struct cx23885_tsport *port, __FUNCTION__); break; default: - // FIXME printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); } @@ -1058,39 +1051,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; default: - // FIXME: generate a sensible switch-default message printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); } - dprintk(1, "%s() Register Dump\n", __FUNCTION__); - dprintk(1, "%s() set port ts_int_msk, now %x\n", __FUNCTION__, cx_read(port->reg_ts_int_msk) ); - dprintk(1, "%s() DEV_CNTRL2 0x%08x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); - dprintk(1, "%s() PCI_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(PCI_INT_MSK) ); - dprintk(1, "%s() VID_A_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_A_INT_MSK) ); - dprintk(1, "%s() VID_B_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_B_INT_MSK) ); - dprintk(1, "%s() VID_C_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSK) ); - dprintk(1, "%s() VID_A_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_A_DMA_CTL) ); - dprintk(1, "%s() VID_B_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_B_DMA_CTL) ); - dprintk(1, "%s() VID_C_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); - dprintk(1, "%s() AUD_INT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_INT_INT_MSK) ); - dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_INT_DMA_CTL) ); - dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_EXT_INT_MSK) ); - dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_EXT_DMA_CTL) ); - cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ - dprintk(1, "%s() set dev_cntrl2, now %x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); - dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_dma_ctl) ); - dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); - dprintk(1, "%s() PAD_CTRL %x\n", __FUNCTION__, cx_read(PAD_CTRL) ); - dprintk(1, "%s() GPIO2 %x\n", __FUNCTION__, cx_read(GPIO2) ); - dprintk(1, "%s() VID_C_LN_LNGTH , now %x\n", __FUNCTION__, cx_read(port->reg_lngth) ); - dprintk(1, "%s() VID_C_HW_SOP_CTL, now %x\n", __FUNCTION__, cx_read(port->reg_hw_sop_ctrl) ); - dprintk(1, "%s() VID_C_GEN_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_gen_ctrl) ); - dprintk(1, "%s() VID_C_SOP_STATUS, now %x\n", __FUNCTION__, cx_read(VID_C_SOP_STATUS) ); - dprintk(1, "%s() VID_C_TS_CLK_EN , now %x\n", __FUNCTION__, cx_read(VID_C_TS_CLK_EN) ); - dprintk(1, "%s() VID_C_FIFO_OVLST, now %x\n", __FUNCTION__, cx_read(VID_C_FIFO_OVFL_STAT) ); - dprintk(1, "%s() VID_C_INT_MSTAT , now 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSTAT) ); return 0; } @@ -1220,7 +1185,6 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); dprintk(1, "[%p/%d] %s - first active\n", buf, buf->vb.i, __FUNCTION__); - } else { dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx23885_buffer, diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 63a1dde0d17a..58ae15a99e9c 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -33,7 +33,7 @@ #include "s5h1409.h" #include "mt2131.h" -static unsigned int debug = 2; +static unsigned int debug = 0; #define dprintk(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) @@ -106,8 +106,6 @@ static struct s5h1409_config hauppauge_hvr1250_config = { .status_mode = S5H1409_DEMODLOCKING }; - - static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { 0x61 }; diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 6b49b414aebf..5572fbbbb5ae 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -130,7 +130,6 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (cnt < msg->len-1 || !last) ctrl |= I2C_NOSTOP | I2C_EXTEND; - //printk("addr = 0x%08x wdata = 0x%08x ctrl = 0x%08x\n", addr, wdata, ctrl); cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); cx_write(bus->reg_ctrl, ctrl); @@ -297,7 +296,6 @@ static struct i2c_adapter cx23885_i2c_adap_template = { .owner = THIS_MODULE, .id = I2C_HW_B_CX23885, .algo = &cx23885_i2c_algo_template, -// .class = I2C_CLASS_TV_ANALOG, .client_register = attach_inform, .client_unregister = detach_inform, }; @@ -348,6 +346,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 771b22ac2153..6527bd3b4d77 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -22,7 +22,6 @@ #ifndef _CX23885_REG_H_ #define _CX23885_REG_H_ - /* Address Map 0x00000000 -> 0x00009000 TX SRAM (Fifos) @@ -50,8 +49,6 @@ Channel manager Data Structure entry = 20 DWORD 5 InstructionQueueSize ... Reserved 19 Reserved - - */ /* Risc Instructions */ @@ -70,15 +67,9 @@ Channel manager Data Structure entry = 20 DWORD #define RISC_WRITERM 0xB0000000 #define RISC_WRITECM 0xC0000000 #define RISC_WRITECR 0xD0000000 - - -/* Do we need these? */ #define RISC_WRITEC 0x50000000 #define RISC_READC 0xA0000000 -/* Is this used? */ -#define RISC_IMM 0x00000001 - /* Audio and Video Core */ #define HOST_REG1 0x00000000 diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 300a97980acb..c0f4e4337351 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -245,7 +245,6 @@ struct sram_channel { #define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) #define cx_clear(reg,bit) cx_andor((reg),(bit),0) - extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, struct sram_channel *ch, unsigned int bpl, u32 risc); From 31bae4a62036a1d85aa9ee5864115dad2727336d Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:36:32 -0300 Subject: [PATCH 0715/2804] V4L/DVB (6171): cx23885: Cleaning up defines Moving some defines into the correct header file. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 19 ------------------- drivers/media/video/cx23885/cx23885-reg.h | 11 ++++++++++- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 7a1c4672041d..fa5f6488b994 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1251,25 +1251,6 @@ static void cx23885_timeout(unsigned long data) do_cancel_buffers(port, "timeout", 1); } -#define PCI_MSK_APB_DMA (1 << 12) -#define PCI_MSK_AL_WR (1 << 11) -#define PCI_MSK_AL_RD (1 << 10) -#define PCI_MSK_RISC_WR (1 << 9) -#define PCI_MSK_RISC_RD (1 << 8) - -#define PCI_MSK_AUD_EXT (1 << 4) -#define PCI_MSK_AUD_INT (1 << 3) -#define PCI_MSK_VID_C (1 << 2) -#define PCI_MSK_VID_B (1 << 1) -#define PCI_MSK_VID_A 1 - -#define VID_C_MSK_BAD_PKT (1 << 20) -#define VID_C_MSK_OPC_ERR (1 << 16) -#define VID_C_MSK_SYNC (1 << 12) -#define VID_C_MSK_OF (1 << 8) -#define VID_C_MSK_RISCI2 (1 << 4) -#define VID_C_MSK_RISCI1 1 - static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 6527bd3b4d77..63ab0fb26acb 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -211,7 +211,7 @@ Channel manager Data Structure entry = 20 DWORD #define I2S_TX_CFG 0x0000001A #define DEV_CNTRL2 0x00040000 -#define PCI_INT_MSK 0x00040010 + #define PCI_MSK_APB_DMA (1 << 12) #define PCI_MSK_AL_WR (1 << 11) #define PCI_MSK_AL_RD (1 << 10) @@ -222,6 +222,8 @@ Channel manager Data Structure entry = 20 DWORD #define PCI_MSK_VID_C (1 << 2) #define PCI_MSK_VID_B (1 << 1) #define PCI_MSK_VID_A 1 +#define PCI_INT_MSK 0x00040010 + #define PCI_INT_STAT 0x00040014 #define PCI_INT_MSTAT 0x00040018 @@ -235,7 +237,14 @@ Channel manager Data Structure entry = 20 DWORD #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 #define VID_C_INT_MSK 0x00040040 + #define VID_C_MSK_BAD_PKT (1 << 20) #define VID_C_MSK_OPC_ERR (1 << 16) #define VID_C_MSK_SYNC (1 << 12) From 86184e06da4b71fc24ae9505ec60ce95c098d0de Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:40:47 -0300 Subject: [PATCH 0716/2804] V4L/DVB (6172): cx23885: Removing duplicate tuner and demod definitions A number of Hauppauge boards share the same tuner and demod configurations. This patch removes duplicate structures. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 54 +++-------------------- 1 file changed, 5 insertions(+), 49 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 58ae15a99e9c..291cc0556222 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -79,7 +79,7 @@ static struct videobuf_queue_ops dvb_qops = { .buf_release = dvb_buf_release, }; -static struct s5h1409_config hauppauge_hvr1800lp_config = { +static struct s5h1409_config hauppauge_generic_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, @@ -88,33 +88,7 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .status_mode = S5H1409_DEMODLOCKING }; -static struct s5h1409_config hauppauge_hvr1800_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING -}; - -static struct s5h1409_config hauppauge_hvr1250_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING -}; - -static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { - 0x61 -}; - -static struct mt2131_config hauppauge_hvr1800_tunerconfig = { - 0x61 -}; - -static struct mt2131_config hauppauge_hvr1250_tunerconfig = { +static struct mt2131_config hauppauge_generic_tunerconfig = { 0x61 }; @@ -128,33 +102,15 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: - port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1250_config, - &dev->i2c_bus[0].i2c_adap); - if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1250_tunerconfig, 0); - } - break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800lp_config, + &hauppauge_generic_config, &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800lp_rev2_tunerconfig, 0); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800_config, - &dev->i2c_bus[0].i2c_adap); - if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800_tunerconfig, 0); + &hauppauge_generic_tunerconfig, 0); } break; default: From 2df9a4c2d81ed255c9e027ee5df676a65f4ab578 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:50:49 -0300 Subject: [PATCH 0717/2804] V4L/DVB (6173): cx23885: Minor cleanup and important NMI comment placed in code I wanted to document the NMI assert issue inside the code, even though it's already documented in the patch history. If/when the next cx23887 revision appears, is may need to be enabled on that also. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index fa5f6488b994..13dc7c8642ca 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -331,8 +331,8 @@ static int cx23885_risc_decode(u32 risc) [ RISC_WRITECR >> 28 ] = "writecr", }; static int incr[16] = { - [ RISC_WRITE >> 28 ] = 3, // 2 - [ RISC_JUMP >> 28 ] = 3, // 2 + [ RISC_WRITE >> 28 ] = 3, + [ RISC_JUMP >> 28 ] = 3, [ RISC_SKIP >> 28 ] = 1, [ RISC_SYNC >> 28 ] = 1, [ RISC_WRITERM >> 28 ] = 3, @@ -629,6 +629,10 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); + /* The cx23885 bridge has a weird bug which causes NMI to be asserted + * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not + * occur on the cx23887 bridge. + */ if(dev->bridge == CX23885_BRIDGE_885) cx_clear(RDR_TLCTL0, 1 << 4); From d54d6980916d5521ad47fa61e5b6ff8733221714 Mon Sep 17 00:00:00 2001 From: Chaogui Zhang Date: Fri, 24 Aug 2007 01:02:32 -0300 Subject: [PATCH 0718/2804] V4L/DVB (6178): add IR remote support for FusionHDTV 5 RT Gold This patch adds support for the built-in IR receiver of the DViCO Fusion HDTV5 RT GOLD PCI card, using FusionHDTV MCE remote controller. Signed-off-by: Chaogui Zhang Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 69 +++++++++++++++++++++++++++++++ drivers/media/video/ir-kbd-i2c.c | 36 +++++++++++++++- include/media/ir-common.h | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 137f68bee39f..1879c304ae6d 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1782,3 +1782,72 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_tt_1500); + +/* DViCO FUSION HDTV 5 RT GOLD remote */ +IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { + + [ 0x0b ] = KEY_1, + [ 0x17 ] = KEY_2, + [ 0x1b ] = KEY_3, + [ 0x07 ] = KEY_4, + [ 0x50 ] = KEY_5, + [ 0x54 ] = KEY_6, + [ 0x48 ] = KEY_7, + [ 0x4c ] = KEY_8, + [ 0x58 ] = KEY_9, + [ 0x03 ] = KEY_0, + + [ 0x5e ] = KEY_OK, + [ 0x51 ] = KEY_UP, + [ 0x53 ] = KEY_DOWN, + [ 0x5b ] = KEY_LEFT, + [ 0x5f ] = KEY_RIGHT, + + [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */ + [ 0x0e ] = KEY_MP3, + [ 0x1a ] = KEY_DVD, + [ 0x1e ] = KEY_RESERVED, /* Labeled CPF on remote */ + [ 0x16 ] = KEY_SETUP, + [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */ + [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */ + + [ 0x49 ] = KEY_BACK, + [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */ + [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */ + [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */ + [ 0x0f ] = KEY_REDO, /* Labeled |<< REPLAY on remote */ + [ 0x12 ] = KEY_END, /* Labeled >>| SKIP on remote */ + [ 0x42 ] = KEY_GREEN, /* Labeled START with a green + * MS windows logo on remote */ + + [ 0x15 ] = KEY_VOLUMEUP, + [ 0x05 ] = KEY_VOLUMEDOWN, + [ 0x11 ] = KEY_CHANNELUP, + [ 0x09 ] = KEY_CHANNELDOWN, + + /* The following are not defined in kernel 2.6 and + * I cannot find suitable substitute key definitions. + + [ 0x52 ] = KEY_PHOTO, + [ 0x5a ] = KEY_LIVE, + [ 0x19 ] = KEY_FOLDER, + + */ + + [ 0x52 ] = KEY_RESERVED, + [ 0x5a ] = KEY_RESERVED, + [ 0x19 ] = KEY_RESERVED, + + [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */ + [ 0x1f ] = KEY_ZOOM, + + [ 0x43 ] = KEY_REWIND, + [ 0x47 ] = KEY_PLAYPAUSE, + [ 0x4f ] = KEY_FORWARD, + [ 0x57 ] = KEY_MUTE, + [ 0x0d ] = KEY_STOP, + [ 0x01 ] = KEY_RECORD, + [ 0x4e ] = KEY_POWER, +}; + +EXPORT_SYMBOL_GPL(ir_codes_fusion_gold); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index b3939a0bada0..3d5a28c2c929 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -10,6 +10,8 @@ * Ulrich Mueller * modified for em2820 based USB TV tuners by * Markus Rechberger + * modified for DViCO Fusion HDTV 5 RT GOLD by + * Chaogui Zhang * * 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 @@ -141,6 +143,32 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } +static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char buf[4]; + + /* poll IR chip */ + if (4 != i2c_master_recv(&ir->c,buf,4)) { + dprintk(1,"read error\n"); + return -EIO; + } + + if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) + dprintk(2, "ir fusion gold: 0x%2x 0x%2x 0x%2x 0x%2x\n", + buf[0], buf[1], buf[2], buf[3]); + + /* no key pressed or signal from other ir remote */ + if(buf[0] != 0x1 || buf[1] != 0xfe) + return 0; + + *ir_key = buf[2]; + *ir_raw = (buf[2] << 8) | buf[3]; + + return 1; + +} + + static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -363,6 +391,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_type = IR_TYPE_OTHER; ir_codes = ir_codes_empty; break; + case 0x6b: + name = "FusionGold"; + ir->get_key = get_key_fusion_gold; + ir_type = IR_TYPE_RC5; + ir_codes = ir_codes_fusion_gold; + break; case 0x7a: case 0x47: case 0x71: @@ -474,7 +508,7 @@ static int ir_probe(struct i2c_adapter *adap) static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; - static const int probe_cx88[] = { 0x18, 0x71, -1 }; + static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; const int *probe = NULL; struct i2c_client c; unsigned char buf; diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 9807a7c15830..dfae84038e2d 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,6 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE]; #endif From 3c44358c49ee4142d0f868509b5b3b02759fa16a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:07:12 -0300 Subject: [PATCH 0719/2804] V4L/DVB (6179): Clean up FusionHDTV ir code - fixed missing buttons in keymap. - make function names & descriptions more generic, since this same ir receiver and remote is used in many FusionHDTV products. - miscellaneous cleanups. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 32 ++++++++++++------------------- drivers/media/video/ir-kbd-i2c.c | 12 +++++------- include/media/ir-common.h | 2 +- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 1879c304ae6d..aefcf28da1ca 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1783,8 +1783,8 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { EXPORT_SYMBOL_GPL(ir_codes_tt_1500); -/* DViCO FUSION HDTV 5 RT GOLD remote */ -IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { +/* DViCO FUSION HDTV MCE remote */ +IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = { [ 0x0b ] = KEY_1, [ 0x17 ] = KEY_2, @@ -1806,7 +1806,7 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */ [ 0x0e ] = KEY_MP3, [ 0x1a ] = KEY_DVD, - [ 0x1e ] = KEY_RESERVED, /* Labeled CPF on remote */ + [ 0x1e ] = KEY_FAVORITES, /* Labeled CPF on remote */ [ 0x16 ] = KEY_SETUP, [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */ [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */ @@ -1815,9 +1815,10 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */ [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */ [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */ - [ 0x0f ] = KEY_REDO, /* Labeled |<< REPLAY on remote */ - [ 0x12 ] = KEY_END, /* Labeled >>| SKIP on remote */ - [ 0x42 ] = KEY_GREEN, /* Labeled START with a green + + [ 0x0f ] = KEY_PREVIOUSSONG, /* Labeled |<< REPLAY on remote */ + [ 0x12 ] = KEY_NEXTSONG, /* Labeled >>| SKIP on remote */ + [ 0x42 ] = KEY_ENTER, /* Labeled START with a green * MS windows logo on remote */ [ 0x15 ] = KEY_VOLUMEUP, @@ -1825,29 +1826,20 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x11 ] = KEY_CHANNELUP, [ 0x09 ] = KEY_CHANNELDOWN, - /* The following are not defined in kernel 2.6 and - * I cannot find suitable substitute key definitions. - - [ 0x52 ] = KEY_PHOTO, - [ 0x5a ] = KEY_LIVE, - [ 0x19 ] = KEY_FOLDER, - - */ - - [ 0x52 ] = KEY_RESERVED, - [ 0x5a ] = KEY_RESERVED, - [ 0x19 ] = KEY_RESERVED, + [ 0x52 ] = KEY_CAMERA, + [ 0x5a ] = KEY_TUNER, + [ 0x19 ] = KEY_OPEN, [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */ [ 0x1f ] = KEY_ZOOM, [ 0x43 ] = KEY_REWIND, [ 0x47 ] = KEY_PLAYPAUSE, - [ 0x4f ] = KEY_FORWARD, + [ 0x4f ] = KEY_FASTFORWARD, [ 0x57 ] = KEY_MUTE, [ 0x0d ] = KEY_STOP, [ 0x01 ] = KEY_RECORD, [ 0x4e ] = KEY_POWER, }; -EXPORT_SYMBOL_GPL(ir_codes_fusion_gold); +EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 3d5a28c2c929..04f6eb5ea292 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -143,7 +143,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } -static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[4]; @@ -154,7 +154,7 @@ static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) } if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) - dprintk(2, "ir fusion gold: 0x%2x 0x%2x 0x%2x 0x%2x\n", + dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); /* no key pressed or signal from other ir remote */ @@ -165,10 +165,8 @@ static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) *ir_raw = (buf[2] << 8) | buf[3]; return 1; - } - static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -392,10 +390,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_codes = ir_codes_empty; break; case 0x6b: - name = "FusionGold"; - ir->get_key = get_key_fusion_gold; + name = "FusionHDTV"; + ir->get_key = get_key_fusionhdtv; ir_type = IR_TYPE_RC5; - ir_codes = ir_codes_fusion_gold; + ir_codes = ir_codes_fusionhdtv_mce; break; case 0x7a: case 0x47: diff --git a/include/media/ir-common.h b/include/media/ir-common.h index dfae84038e2d..7a785fa77212 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,7 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; -extern IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE]; #endif From a1dec5160d6e536b409761c1914500f4a7cf08c2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:13:07 -0300 Subject: [PATCH 0720/2804] V4L/DVB (6180): tuner: don't probe 0x6b or 0x6f on cx88 boards Ignore 0x6b and 0x6f on cx88 boards. Some FusionHDTV cards have an ir receiver at 0x6b and an RTC at 0x6f which can get corrupted if probed. Signed-off-by: Michael Krufky Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2f74379f4e4b..2d4a3e38f278 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -661,6 +661,27 @@ static int tuner_probe(struct i2c_adapter *adap) normal_i2c[1] = I2C_CLIENT_END; } + /* HACK: Ignore 0x6b and 0x6f on cx88 boards. + * FusionHDTV5 RT Gold has an ir receiver at 0x6b + * and an RTC at 0x6f which can get corrupted if probed. + */ + if (adap->id == I2C_HW_B_CX2388x) { + unsigned int i = 0; + + while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) + i += 2; + if (i + 4 < I2C_CLIENT_MAX_OPTS) { + ignore[i+0] = adap->nr; + ignore[i+1] = 0x6b; + ignore[i+2] = adap->nr; + ignore[i+3] = 0x6f; + ignore[i+4] = I2C_CLIENT_END; + } else + printk(KERN_WARNING "tuner: " + "too many options specified " + "in i2c probe ignore list!\n"); + } + default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; if (adap->class & I2C_CLASS_TV_ANALOG) From 6fcecce7e1a5223be450031fa446323b08d1ec41 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:32:31 -0300 Subject: [PATCH 0721/2804] V4L/DVB (6181): cx88: auto-load rtc and ir receiver i2c modules for FusionHDTV5 RT Gold Auto-load ir-kbd-i2c for ir receiver support, and rtc-isl1208 for rtc support for the FusionHDTV5 RT Gold. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index a16fc157a67d..f94a3b41782a 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1831,6 +1831,12 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, if (core->board.audio_chip == AUDIO_CHIP_WM8775) request_module("wm8775"); + switch (core->boardnr) { + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: + request_module("ir-kbd-i2c"); + request_module("rtc-isl1208"); + } + /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); From 82896f29d47d945e331873c7295da9e3a47d709d Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 6 Sep 2007 23:02:23 -0300 Subject: [PATCH 0722/2804] V4L/DVB (6184): cx88-alsa: Make volume control stereo Use the balance control to make the mono volume control stereo. Note that full range isn't supported. The balance control attenuates one channel by 0 to -63 dB, and the volume control provides additional attenuation to both channels by another 0 to -63 dB. So the channel with the most attenuation has a range of 0 to -126 dB, while the other channel only has a range of 0 to -63 dB. ALSA volume controls don't appear to support this concept. I just limited the range to 0 to -63 total. Once you get to -63 dB, you're already at silence, so additional attenuation is pretty much pointless anyway. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 59 +++++++++++++++++----------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 85d632224f3a..25de25fb8052 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -552,7 +552,7 @@ static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) { info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 1; + info->count = 2; info->value.integer.min = 0; info->value.integer.max = 0x3f; @@ -565,8 +565,12 @@ static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core=chip->core; + int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), + bal = cx_read(AUD_BAL_CTL); - value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); + value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol; + vol -= (bal & 0x3f); + value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol; return 0; } @@ -577,19 +581,31 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core=chip->core; - int v; - u32 old_control; + int v, b; + int changed = 0; + u32 old; + b = value->value.integer.value[1] - value->value.integer.value[0]; + if (b < 0) { + v = 0x3f - value->value.integer.value[0]; + b = (-b) | 0x40; + } else { + v = 0x3f - value->value.integer.value[1]; + } /* Do we really know this will always be called with IRQs on? */ spin_lock_irq(&chip->reg_lock); - - old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); - v = 0x3f - (value->value.integer.value[0] & 0x3f); - cx_andor(AUD_VOL_CTL, 0x3f, v); - + old = cx_read(AUD_VOL_CTL); + if (v != (old & 0x3f)) { + cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); + changed = 1; + } + if (cx_read(AUD_BAL_CTL) != b) { + cx_write(AUD_BAL_CTL, b); + changed = 1; + } spin_unlock_irq(&chip->reg_lock); - return v != old_control; + return changed; } static struct snd_kcontrol_new snd_cx88_capture_volume = { @@ -746,17 +762,12 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, return (err); err = snd_cx88_pcm(chip, 0, "CX88 Digital"); - - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip)); - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; strcpy (card->driver, "CX88x"); sprintf(card->shortname, "Conexant CX%x", pci->device); @@ -768,14 +779,16 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->driver,devno); err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; pci_set_drvdata(pci,card); devno++; return 0; + +error: + snd_card_free(card); + return err; } /* * ALSA destructor From 415927dcd118ee9e5f24c78976509b9a9c747545 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 6 Sep 2007 23:02:24 -0300 Subject: [PATCH 0723/2804] V4L/DVB (6186): cx88-alsa: Remove some unused fields in card state struct Not sure why they are there, but they don't do anything now. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 25de25fb8052..f4abed454fd4 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -53,13 +53,9 @@ Data type declarations - Can be moded to a header file later ****************************************************************************/ -/* These can be replaced after done */ -#define MIXER_ADDR_LAST MAX_CX88_INPUT - struct cx88_audio_dev { struct cx88_core *core; struct cx88_dmaqueue q; - u64 starttime; /* pci i/o */ struct pci_dev *pci; @@ -78,9 +74,6 @@ struct cx88_audio_dev { struct videobuf_dmabuf dma_risc; - int mixer_volume[MIXER_ADDR_LAST+1][2]; - int capture_source[MIXER_ADDR_LAST+1][2]; - struct cx88_buffer *buf; struct snd_pcm_substream *substream; From fc959befe0f0e4647bb4e326e3ae55875401888a Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 19:08:17 -0300 Subject: [PATCH 0724/2804] V4L/DVB (6190): cx23885: GPIO fix for non HVR1800lp boards The HVR1250 and HVR1800 boards need the s5h1409 demod GPIO enabled. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 291cc0556222..ffa4c49d6916 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -80,6 +80,15 @@ static struct videobuf_queue_ops dvb_qops = { }; static struct s5h1409_config hauppauge_generic_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING +}; + +static struct s5h1409_config hauppauge_hvr1800lp_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, @@ -103,7 +112,6 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, &dev->i2c_bus[0].i2c_adap); @@ -113,6 +121,16 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_generic_tunerconfig, 0); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); From bfde287c2f8f0fe4e50e0eb136e4dca6b0ed84dc Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 6 Sep 2007 15:50:31 -0300 Subject: [PATCH 0725/2804] V4L/DVB (6191): Removed a redundant switch() The switch() statement is no longer required. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 13dc7c8642ca..f5b73c4b625e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1025,18 +1025,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: - case CX23885_BOARD_HAUPPAUGE_HVR1800: - cx_write(port->reg_vld_misc, 0x00); - dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", - __FUNCTION__); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } + cx_write(port->reg_vld_misc, 0x00); cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); udelay(100); From 661c7e44c5cc2828c7acb00cb71d985e129e3641 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 6 Sep 2007 16:07:49 -0300 Subject: [PATCH 0726/2804] V4L/DVB (6192): Ensure start_dma() is capable of starting dma on port VIDB start_dma() would fail to start dma if a device used VIDB (portb). Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 9 ++++++--- drivers/media/video/cx23885/cx23885.h | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index f5b73c4b625e..907ea4c2ea38 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1015,9 +1015,12 @@ static int cx23885_start_dma(struct cx23885_tsport *port, /* write TS length to chip */ cx_write(port->reg_lngth, buf->vb.width); - if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { - printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", - __FUNCTION__, cx23885_boards[dev->board].portc ); + if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && + (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) { + printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n", + __FUNCTION__, + cx23885_boards[dev->board].portb, + cx23885_boards[dev->board].portc ); return -EINVAL; } diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index c0f4e4337351..e44698a6bede 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -86,12 +86,14 @@ struct cx23885_input { u32 gpio0, gpio1, gpio2, gpio3; }; +typedef enum { + CX23885_MPEG_UNDEFINED = 0, + CX23885_MPEG_DVB +} port_t; + struct cx23885_board { char *name; - enum { - CX23885_MPEG_UNDEFINED = 0, - CX23885_MPEG_DVB - } portc; + port_t portb, portc; struct cx23885_input input[MAX_CX23885_INPUT]; }; From ccbe64c664f2e3a86430ef63c974e38ac1cd5b93 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Sep 2007 11:25:37 -0300 Subject: [PATCH 0727/2804] V4L/DVB (6193): cx23885: define Video B Interrupt Status register bit values - define missing register bit values for VID_B - corrected VID/VBI_B_GPCNT_CTL register addresses Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-reg.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 63ab0fb26acb..3f1afbeea778 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -237,6 +237,13 @@ Channel manager Data Structure entry = 20 DWORD #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C +#define VID_B_MSK_BAD_PKT (1 << 20) +#define VID_B_MSK_OPC_ERR (1 << 16) +#define VID_B_MSK_SYNC (1 << 12) +#define VID_B_MSK_OF (1 << 8) +#define VID_B_MSK_RISCI2 (1 << 4) +#define VID_B_MSK_RISCI1 1 + #define VID_C_MSK_BAD_PKT (1 << 20) #define VID_C_MSK_OPC_ERR (1 << 16) #define VID_C_MSK_SYNC (1 << 12) @@ -344,8 +351,8 @@ Channel manager Data Structure entry = 20 DWORD #define VBI_B_DMA 0x00130108 #define VID_B_GPCNT 0x00130120 #define VBI_B_GPCNT 0x00130124 -#define VID_B_GPCNT_CTL 0x00130130 -#define VBI_B_GPCNT_CTL 0x00130134 +#define VID_B_GPCNT_CTL 0x00130134 +#define VBI_B_GPCNT_CTL 0x00130138 #define VID_B_DMA_CTL 0x00130140 #define VID_B_SRC_SEL 0x00130144 #define VID_B_LNGTH 0x00130150 From 6f074abb624aced31339a0f8fac778b344adac4c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 14:21:03 -0300 Subject: [PATCH 0728/2804] V4L/DVB (6194): Changes to support interrupts on VIDB Changes to support interrupts on VIDB Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 59 ++++++++++++++++++++-- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 907ea4c2ea38..d155f5fb133c 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1252,20 +1252,23 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) struct cx23885_dev *dev = dev_id; struct cx23885_tsport *port = &dev->ts2; u32 pci_status, pci_mask; + u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; int count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); - + ts1_status = cx_read(VID_B_INT_STAT); + ts1_mask = cx_read(VID_B_INT_MSK); ts2_status = cx_read(VID_C_INT_STAT); ts2_mask = cx_read(VID_C_INT_MSK); - if ( (pci_status == 0) && (ts2_status == 0) ) + if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; count = cx_read(port->reg_gpcnt); dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, count ); dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); if ( (pci_status & PCI_MSK_RISC_RD) || @@ -1303,6 +1306,48 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } + if ( (ts1_status & VID_B_MSK_OPC_ERR) || + (ts1_status & VID_B_MSK_BAD_PKT) || + (ts1_status & VID_B_MSK_SYNC) || + (ts1_status & VID_B_MSK_OF)) + { + if (ts1_status & VID_B_MSK_OPC_ERR) + dprintk(7, " (VID_B_MSK_OPC_ERR 0x%08x)\n", VID_B_MSK_OPC_ERR); + if (ts1_status & VID_B_MSK_BAD_PKT) + dprintk(7, " (VID_B_MSK_BAD_PKT 0x%08x)\n", VID_B_MSK_BAD_PKT); + if (ts1_status & VID_B_MSK_SYNC) + dprintk(7, " (VID_B_MSK_SYNC 0x%08x)\n", VID_B_MSK_SYNC); + if (ts1_status & VID_B_MSK_OF) + dprintk(7, " (VID_B_MSK_OF 0x%08x)\n", VID_B_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); + + } else if (ts1_status & VID_B_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_B_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (ts1_status & VID_B_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_B_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + if (ts1_status) { + cx_write(VID_B_INT_STAT, ts1_status); + handled = 1; + } + if ( (ts2_status & VID_C_MSK_OPC_ERR) || (ts2_status & VID_C_MSK_BAD_PKT) || (ts2_status & VID_C_MSK_SYNC) || @@ -1341,9 +1386,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - cx_write(VID_C_INT_STAT, ts2_status); - cx_write(PCI_INT_STAT, pci_status); - handled = 1; + if (ts2_status) { + cx_write(VID_C_INT_STAT, ts2_status); + handled = 1; + } + + if (handled) + cx_write(PCI_INT_STAT, pci_status); out: return IRQ_RETVAL(handled); } From 579f1163cd5b2a3fd96ec5b84b18a071e7da3b6b Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 15:07:02 -0300 Subject: [PATCH 0729/2804] V4L/DVB (6195): Changes to support MPEG TS on VIDB Changes to support MPEG TS on VIDB Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 142 ++++++++++++--------- drivers/media/video/cx23885/cx23885.h | 7 + 2 files changed, 86 insertions(+), 63 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d155f5fb133c..553a72ae163a 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -100,12 +100,12 @@ struct sram_channel cx23885_sram_channels[] = { .cnt2_reg = DMA2_CNT2, }, [SRAM_CH03] = { - .name = "ch3", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10780, + .cdt = 0x10400, + .fifo_start = 0x5000, + .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, .ptr2_reg = DMA3_PTR2, .cnt1_reg = DMA3_CNT1, @@ -596,7 +596,7 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); @@ -679,6 +679,39 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) atomic_inc(&dev->refcount); dev->nr = cx23885_devcount++; + sprintf(dev->name, "cx23885[%d]", dev->nr); + + mutex_lock(&devlist); + list_add_tail(&dev->devlist, &cx23885_devlist); + mutex_unlock(&devlist); + + /* Configure the internal memory */ + if(dev->pci->device == 0x8880) { + dev->bridge = CX23885_BRIDGE_887; + dev->sram_channels = cx23887_sram_channels; + } else + if(dev->pci->device == 0x8852) { + dev->bridge = CX23885_BRIDGE_885; + dev->sram_channels = cx23885_sram_channels; + } else + BUG(); + + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", + __FUNCTION__, dev->bridge); + + /* board config */ + dev->board = UNSET; + if (card[dev->nr] < cx23885_bcount) + dev->board = card[dev->nr]; + for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) + if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && + dev->pci->subsystem_device == cx23885_subids[i].subdevice) + dev->board = cx23885_subids[i].card; + if (UNSET == dev->board) { + dev->board = CX23885_BOARD_UNKNOWN; + cx23885_card_list(dev); + } + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); dev->pci_irqmask = 0x001f00; @@ -717,38 +750,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) spin_lock_init(&dev->ts2.slock); dev->ts2.dev = dev; dev->ts2.nr = 2; - dev->ts2.sram_chno = SRAM_CH06; + INIT_LIST_HEAD(&dev->ts2.mpegq.active); INIT_LIST_HEAD(&dev->ts2.mpegq.queued); dev->ts2.mpegq.timeout.function = cx23885_timeout; dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; init_timer(&dev->ts2.mpegq.timeout); - dev->ts2.reg_gpcnt = VID_C_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; - dev->ts2.reg_lngth = VID_C_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_C_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_C_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, - dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - - sprintf(dev->name, "cx23885[%d]", dev->nr); - if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " "subsystem: %04x:%04x\n", @@ -759,46 +767,18 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) goto fail_free; } - mutex_lock(&devlist); - list_add_tail(&dev->devlist, &cx23885_devlist); - mutex_unlock(&devlist); - /* PCIe stuff */ dev->lmmio = ioremap(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); dev->bmmio = (u8 __iomem *)dev->lmmio; - /* board config */ - dev->board = UNSET; - if (card[dev->nr] < cx23885_bcount) - dev->board = card[dev->nr]; - for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) - if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && - dev->pci->subsystem_device == cx23885_subids[i].subdevice) - dev->board = cx23885_subids[i].card; - if (UNSET == dev->board) { - dev->board = CX23885_BOARD_UNKNOWN; - cx23885_card_list(dev); - } printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device, cx23885_boards[dev->board].name, dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - /* Configure the internal memory */ - if(dev->pci->device == 0x8880) { - dev->bridge = CX23885_BRIDGE_887; - dev->sram_channels = cx23887_sram_channels; - } else - if(dev->pci->device == 0x8852) { - dev->bridge = CX23885_BRIDGE_885; - dev->sram_channels = cx23885_sram_channels; - } - dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", - __FUNCTION__, dev->bridge); - cx23885_pci_quirks(dev); /* init hardware */ @@ -812,6 +792,38 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_setup(dev); cx23885_ir_init(dev); + switch (dev->board) { + default: + dev->ts2.reg_gpcnt = VID_C_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; + dev->ts2.reg_lngth = VID_C_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_C_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_C_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; + dev->ts2.reg_src_sel = 0; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + + // Drive this from cards.c (portb/c) and move it outside of this switch + dev->ts2.sram_chno = SRAM_CH06; + } + + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, + dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + + // FIXME: This should only be called if ts2 is being used, driven by cards.c if (cx23885_dvb_register(&dev->ts2) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); @@ -1026,13 +1038,17 @@ static int cx23885_start_dma(struct cx23885_tsport *port, udelay(100); + /* If the port supports SRC SELECT, configure it */ + if(port->reg_src_sel) + cx_write(port->reg_src_sel, port->src_sel_val); + cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); cx_write(port->reg_vld_misc, 0x00); - cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); udelay(100); + // NOTE: this is 2 (reserved) for portb, does it matter? /* reset counter to zero */ cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; @@ -1047,7 +1063,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + BUG(); } cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index e44698a6bede..62b44f6d749f 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -68,6 +68,11 @@ enum cx23885_itype { CX23885_RADIO, }; +enum cx23885_src_sel_type { + CX23885_SRC_SEL_EXT_656_VIDEO = 0, + CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO +}; + /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ @@ -162,6 +167,7 @@ struct cx23885_tsport { u32 reg_vld_misc; u32 reg_ts_clk_en; u32 reg_ts_int_msk; + u32 reg_src_sel; /* Default register vals */ int pci_irqmask; @@ -169,6 +175,7 @@ struct cx23885_tsport { u32 ts_int_msk_val; u32 gen_ctrl_val; u32 ts_clk_en_val; + u32 src_sel_val; }; struct cx23885_dev { From 9bc37caadffe8327683980b2323371691fa182e3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Sep 2007 15:17:13 -0300 Subject: [PATCH 0730/2804] V4L/DVB (6196): cx23885: add support for DViCO FusionHDTV 5 Express This patch adds digital ATSC / QAM support for the DViCO FusionHDTV5 Express. Remote control is supported by ir-kbd-i2c, RTC is supported by rtc-isl1208. Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 8 +++++++ drivers/media/video/cx23885/cx23885-core.c | 26 +++++++++++++++++++++ drivers/media/video/cx23885/cx23885-dvb.c | 18 ++++++++++++++ drivers/media/video/cx23885/cx23885-i2c.c | 6 +++-- drivers/media/video/cx23885/cx23885.h | 1 + drivers/media/video/ir-kbd-i2c.c | 3 +++ drivers/media/video/tuner-core.c | 3 ++- 7 files changed, 62 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 09d4376c2e05..cdda11ddf145 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -109,6 +109,10 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0xff02, }}, }, + [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { + .name = "DViCO FusionHDTV5 Express", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -136,6 +140,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7911, .card = CX23885_BOARD_HAUPPAUGE_HVR1250, + },{ + .subvendor = 0x18ac, + .subdevice = 0xd500, + .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 553a72ae163a..bcba19263476 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -793,6 +793,32 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_ir_init(dev); switch (dev->board) { + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + dev->ts2.reg_gpcnt = VID_B_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_B_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_B_DMA_CTL; + dev->ts2.reg_lngth = VID_B_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_B_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_B_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_B_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_B_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_B_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_B_INT_MSK; + dev->ts2.reg_src_sel = VID_B_SRC_SEL; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x02; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + + // Drive this from cards.c (portb/c) and move it outside of this switch + dev->ts2.sram_chno = SRAM_CH03; + break; default: dev->ts2.reg_gpcnt = VID_C_GPCNT; dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index ffa4c49d6916..0ace919195df 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -32,6 +32,8 @@ #include "s5h1409.h" #include "mt2131.h" +#include "lgdt330x.h" +#include "dvb-pll.h" static unsigned int debug = 0; @@ -101,6 +103,12 @@ static struct mt2131_config hauppauge_generic_tunerconfig = { 0x61 }; +static struct lgdt330x_config fusionhdtv_5_express = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -131,6 +139,16 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + port->dvb.frontend = dvb_attach(lgdt330x_attach, + &fusionhdtv_5_express, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, port->dvb.frontend, + 0x61, &dev->i2c_bus[0].i2c_adap, + DVB_PLL_LG_TDVS_H06XF); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 5572fbbbb5ae..b517c8b5a566 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -305,12 +305,14 @@ static struct i2c_client cx23885_i2c_client_template = { }; static char *i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt3303", + [ 0x86 >> 1 ] = "tda9887", [ 0x32 >> 1 ] = "cx24227", [ 0x88 >> 1 ] = "cx25837", [ 0x84 >> 1 ] = "tda8295", [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "mt2131/tda8275", - [ 0xc2 >> 1 ] = "mt2131/tda8275", + [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275", + [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 62b44f6d749f..4933274b1e39 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -54,6 +54,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 +#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 04f6eb5ea292..d98dd0d1e373 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -507,6 +507,7 @@ static int ir_probe(struct i2c_adapter *adap) static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; + static const int probe_cx23885[] = { 0x6b, -1 }; const int *probe = NULL; struct i2c_client c; unsigned char buf; @@ -527,6 +528,8 @@ static int ir_probe(struct i2c_adapter *adap) break; case I2C_HW_B_CX2388x: probe = probe_cx88; + case I2C_HW_B_CX23885: + probe = probe_cx23885; break; } if (NULL == probe) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2d4a3e38f278..94843086cda9 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -665,7 +665,8 @@ static int tuner_probe(struct i2c_adapter *adap) * FusionHDTV5 RT Gold has an ir receiver at 0x6b * and an RTC at 0x6f which can get corrupted if probed. */ - if (adap->id == I2C_HW_B_CX2388x) { + if ((adap->id == I2C_HW_B_CX2388x) || + (adap->id == I2C_HW_B_CX23885)) { unsigned int i = 0; while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) From 15e90839512a2c7d2b7f801af8f9057279e3f813 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Sep 2007 15:58:45 -0300 Subject: [PATCH 0731/2804] V4L/DVB (6198): add CARDLIST.cx23885 to Documentation/ Cardlist generated by cx23885.pl Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Documentation/video4linux/CARDLIST.cx23885 diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 new file mode 100644 index 000000000000..00cb646a4bde --- /dev/null +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -0,0 +1,5 @@ + 0 -> UNKNOWN/GENERIC [0070:3400] + 1 -> Hauppauge WinTV-HVR1800lp [0070:7600] + 2 -> Hauppauge WinTV-HVR1800 [0070:7800,0070:7801] + 3 -> Hauppauge WinTV-HVR1250 [0070:7911] + 4 -> DViCO FusionHDTV5 Express [18ac:d500] From a6a3f14035fe94c0925fea62f3d3a7a1ab44c1f1 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 21:31:56 -0300 Subject: [PATCH 0732/2804] V4L/DVB (6199): cx23885: Changes to allow demodulators on each transport bus cx23885: Changes to allow demodulators on each transport bus. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 53 +++- drivers/media/video/cx23885/cx23885-core.c | 322 +++++++++----------- drivers/media/video/cx23885/cx23885-dvb.c | 4 +- drivers/media/video/cx23885/cx23885-reg.h | 16 +- drivers/media/video/cx23885/cx23885.h | 5 +- 5 files changed, 206 insertions(+), 194 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index cdda11ddf145..b9012acabb2f 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -111,7 +111,7 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { .name = "DViCO FusionHDTV5 Express", - .portc = CX23885_MPEG_DVB, + .portb = CX23885_MPEG_DVB, }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -197,8 +197,43 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } +void cx23885_gpio_setup(struct cx23885_dev *dev) +{ + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* GPIO-0 cx24227 demodulator reset */ + cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + // FIXME: Analog requires the tuner is brought out of reset + break; + } +} + +int cx23885_ir_init(struct cx23885_dev *dev) +{ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* FIXME: Implement me */ + break; + } + + return 0; +} + void cx23885_card_setup(struct cx23885_dev *dev) { + struct cx23885_tsport *ts1 = &dev->ts1; + struct cx23885_tsport *ts2 = &dev->ts2; + static u8 eeprom[256]; if (dev->i2c_bus[0].i2c_rc == 0) { @@ -215,6 +250,22 @@ void cx23885_card_setup(struct cx23885_dev *dev) hauppauge_eeprom(dev, eeprom+0x80); break; } + + switch (dev->board) { + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + default: + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + } + } /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index bcba19263476..51879961e3ea 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -604,24 +604,7 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); - switch(dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - /* GPIO-0 cx24227 demodulator reset */ - dprintk( 1, "%s() Configuring HVR1250 GPIO's\n", __FUNCTION__); - cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - /* GPIO-0 656_CLK */ - /* GPIO-1 656_D0 */ - /* GPIO-2 8295A Reset */ - /* GPIO-3-10 cx23417 data0-7 */ - /* GPIO-11-14 cx23417 addr0-3 */ - /* GPIO-15-18 cx23417 READY, CS, RD, WR */ - /* GPIO-19 IR_RX */ - dprintk( 1, "%s() Configuring HVR1800 GPIO's\n", __FUNCTION__); - // FIXME: Analog requires the tuner is brought out of reset - break; - } + cx23885_gpio_setup(dev); } @@ -656,17 +639,68 @@ static void cx23885_timeout(unsigned long data); int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value); -static int cx23885_ir_init(struct cx23885_dev *dev) +static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { - dprintk(1, "%s()\n", __FUNCTION__); + dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno); - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1800: - dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); + /* Transport bus init dma queue - Common settings */ + port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + + spin_lock_init(&port->slock); + port->dev = dev; + port->nr = portno; + + INIT_LIST_HEAD(&port->mpegq.active); + INIT_LIST_HEAD(&port->mpegq.queued); + port->mpegq.timeout.function = cx23885_timeout; + port->mpegq.timeout.data = (unsigned long)port; + init_timer(&port->mpegq.timeout); + + switch(portno) { + case 1: + port->reg_gpcnt = VID_B_GPCNT; + port->reg_gpcnt_ctl = VID_B_GPCNT_CTL; + port->reg_dma_ctl = VID_B_DMA_CTL; + port->reg_lngth = VID_B_LNGTH; + port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; + port->reg_gen_ctrl = VID_B_GEN_CTL; + port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS; + port->reg_sop_status = VID_B_SOP_STATUS; + port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; + port->reg_vld_misc = VID_B_VLD_MISC; + port->reg_ts_clk_en = VID_B_TS_CLK_EN; + port->reg_src_sel = VID_B_SRC_SEL; + port->reg_ts_int_msk = VID_B_INT_MSK; + port->reg_ts_int_stat = VID_B_INT_STAT; + port->sram_chno = SRAM_CH03; /* VID_B */ + port->pci_irqmask = 0x02; /* VID_B bit1 */ break; + case 2: + port->reg_gpcnt = VID_C_GPCNT; + port->reg_gpcnt_ctl = VID_C_GPCNT_CTL; + port->reg_dma_ctl = VID_C_DMA_CTL; + port->reg_lngth = VID_C_LNGTH; + port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + port->reg_gen_ctrl = VID_C_GEN_CTL; + port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + port->reg_sop_status = VID_C_SOP_STATUS; + port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + port->reg_vld_misc = VID_C_VLD_MISC; + port->reg_ts_clk_en = VID_C_TS_CLK_EN; + port->reg_src_sel = 0; + port->reg_ts_int_msk = VID_C_INT_MSK; + port->reg_ts_int_stat = VID_C_INT_STAT; + port->sram_chno = SRAM_CH06; /* VID_C */ + port->pci_irqmask = 0x04; /* VID_C bit2 */ + break; + default: + BUG(); } + cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, + port->reg_dma_ctl, port->dma_ctl_val, 0x00); + return 0; } @@ -746,16 +780,11 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->i2c_bus[2].reg_wdata = I2C3_WDATA; dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ - /* Transport bus init dma queue */ - spin_lock_init(&dev->ts2.slock); - dev->ts2.dev = dev; - dev->ts2.nr = 2; + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + cx23885_init_tsport(dev, &dev->ts1, 1); - INIT_LIST_HEAD(&dev->ts2.mpegq.active); - INIT_LIST_HEAD(&dev->ts2.mpegq.queued); - dev->ts2.mpegq.timeout.function = cx23885_timeout; - dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; - init_timer(&dev->ts2.mpegq.timeout); + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + cx23885_init_tsport(dev, &dev->ts2, 2); if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " @@ -788,71 +817,21 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_i2c_register(&dev->i2c_bus[1]); cx23885_i2c_register(&dev->i2c_bus[2]); cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); - cx23885_card_setup(dev); cx23885_ir_init(dev); - switch (dev->board) { - case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: - dev->ts2.reg_gpcnt = VID_B_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_B_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_B_DMA_CTL; - dev->ts2.reg_lngth = VID_B_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_B_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_B_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_B_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_B_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_B_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_B_INT_MSK; - dev->ts2.reg_src_sel = VID_B_SRC_SEL; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x02; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - - // Drive this from cards.c (portb/c) and move it outside of this switch - dev->ts2.sram_chno = SRAM_CH03; - break; - default: - dev->ts2.reg_gpcnt = VID_C_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; - dev->ts2.reg_lngth = VID_C_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_C_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_C_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; - dev->ts2.reg_src_sel = 0; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - - // Drive this from cards.c (portb/c) and move it outside of this switch - dev->ts2.sram_chno = SRAM_CH06; + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + if (cx23885_dvb_register(&dev->ts1) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", + __FUNCTION__); + } } - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, - dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - - // FIXME: This should only be called if ts2 is being used, driven by cards.c - if (cx23885_dvb_register(&dev->ts2) < 0) { - printk(KERN_ERR "%s() Failed to register dvb adapters\n", - __FUNCTION__); + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + if (cx23885_dvb_register(&dev->ts2) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n", + __FUNCTION__); + } } return 0; @@ -870,7 +849,12 @@ void cx23885_dev_unregister(struct cx23885_dev *dev) if (!atomic_dec_and_test(&dev->refcount)) return; - cx23885_dvb_unregister(&dev->ts2); + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + cx23885_dvb_unregister(&dev->ts1); + + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + cx23885_dvb_unregister(&dev->ts2); + cx23885_i2c_unregister(&dev->i2c_bus[2]); cx23885_i2c_unregister(&dev->i2c_bus[1]); cx23885_i2c_unregister(&dev->i2c_bus[0]); @@ -1289,14 +1273,66 @@ static void cx23885_timeout(unsigned long data) do_cancel_buffers(port, "timeout", 1); } +static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) +{ + struct cx23885_dev *dev = port->dev; + int handled = 0; + u32 count; + + if ( (status & VID_BC_MSK_OPC_ERR) || + (status & VID_BC_MSK_BAD_PKT) || + (status & VID_BC_MSK_SYNC) || + (status & VID_BC_MSK_OF)) + { + if (status & VID_BC_MSK_OPC_ERR) + dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR); + if (status & VID_BC_MSK_BAD_PKT) + dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT); + if (status & VID_BC_MSK_SYNC) + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", VID_BC_MSK_SYNC); + if (status & VID_BC_MSK_OF) + dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", VID_BC_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); + + } else if (status & VID_BC_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (status & VID_BC_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + if (status) { + cx_write(port->reg_ts_int_stat, status); + handled = 1; + } + + return handled; +} + static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; - struct cx23885_tsport *port = &dev->ts2; + struct cx23885_tsport *ts1 = &dev->ts1; + struct cx23885_tsport *ts2 = &dev->ts2; u32 pci_status, pci_mask; u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; - int count = 0, handled = 0; + int ts1_count = 0, ts2_count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); @@ -1308,10 +1344,11 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; - count = cx_read(port->reg_gpcnt); + ts1_count = cx_read(ts1->reg_gpcnt); + ts2_count = cx_read(ts2->reg_gpcnt); dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); - dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, count ); - dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count ); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count ); if ( (pci_status & PCI_MSK_RISC_RD) || (pci_status & PCI_MSK_RISC_WR) || @@ -1348,90 +1385,11 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - if ( (ts1_status & VID_B_MSK_OPC_ERR) || - (ts1_status & VID_B_MSK_BAD_PKT) || - (ts1_status & VID_B_MSK_SYNC) || - (ts1_status & VID_B_MSK_OF)) - { - if (ts1_status & VID_B_MSK_OPC_ERR) - dprintk(7, " (VID_B_MSK_OPC_ERR 0x%08x)\n", VID_B_MSK_OPC_ERR); - if (ts1_status & VID_B_MSK_BAD_PKT) - dprintk(7, " (VID_B_MSK_BAD_PKT 0x%08x)\n", VID_B_MSK_BAD_PKT); - if (ts1_status & VID_B_MSK_SYNC) - dprintk(7, " (VID_B_MSK_SYNC 0x%08x)\n", VID_B_MSK_SYNC); - if (ts1_status & VID_B_MSK_OF) - dprintk(7, " (VID_B_MSK_OF 0x%08x)\n", VID_B_MSK_OF); + if (ts1_status) + handled += cx23885_irq_ts(ts1, ts1_status); - printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); - - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); - - } else if (ts1_status & VID_B_MSK_RISCI1) { - - dprintk(7, " (RISCI1 0x%08x)\n", VID_B_MSK_RISCI1); - - spin_lock(&port->slock); - count = cx_read(port->reg_gpcnt); - cx23885_wakeup(port, &port->mpegq, count); - spin_unlock(&port->slock); - - } else if (ts1_status & VID_B_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_B_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - - } - if (ts1_status) { - cx_write(VID_B_INT_STAT, ts1_status); - handled = 1; - } - - if ( (ts2_status & VID_C_MSK_OPC_ERR) || - (ts2_status & VID_C_MSK_BAD_PKT) || - (ts2_status & VID_C_MSK_SYNC) || - (ts2_status & VID_C_MSK_OF)) - { - if (ts2_status & VID_C_MSK_OPC_ERR) - dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); - if (ts2_status & VID_C_MSK_BAD_PKT) - dprintk(7, " (VID_C_MSK_BAD_PKT 0x%08x)\n", VID_C_MSK_BAD_PKT); - if (ts2_status & VID_C_MSK_SYNC) - dprintk(7, " (VID_C_MSK_SYNC 0x%08x)\n", VID_C_MSK_SYNC); - if (ts2_status & VID_C_MSK_OF) - dprintk(7, " (VID_C_MSK_OF 0x%08x)\n", VID_C_MSK_OF); - - printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); - - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); - - } else if (ts2_status & VID_C_MSK_RISCI1) { - - dprintk(7, " (RISCI1 0x%08x)\n", VID_C_MSK_RISCI1); - - spin_lock(&port->slock); - count = cx_read(port->reg_gpcnt); - cx23885_wakeup(port, &port->mpegq, count); - spin_unlock(&port->slock); - - } else if (ts2_status & VID_C_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_C_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - - } - - if (ts2_status) { - cx_write(VID_C_INT_STAT, ts2_status); - handled = 1; - } + if (ts2_status) + handled += cx23885_irq_ts(ts2, ts2_status); if (handled) cx_write(PCI_INT_STAT, pci_status); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 0ace919195df..e0dc1495b8cd 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -160,6 +160,7 @@ static int dvb_register(struct cx23885_tsport *port) } /* Put the analog decoder in standby to keep it quiet */ + /* Assumption here: analog decoder is only on i2c bus 0 */ cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); /* register everything */ @@ -180,8 +181,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port) dev->pci_slot); err = -ENODEV; - if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) - goto fail_core; /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); @@ -192,7 +191,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port) if (err != 0) printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); - fail_core: return err; } diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 3f1afbeea778..162169f9091b 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -250,14 +250,16 @@ Channel manager Data Structure entry = 20 DWORD #define VID_C_MSK_OF (1 << 8) #define VID_C_MSK_RISCI2 (1 << 4) #define VID_C_MSK_RISCI1 1 -#define VID_C_INT_MSK 0x00040040 -#define VID_C_MSK_BAD_PKT (1 << 20) -#define VID_C_MSK_OPC_ERR (1 << 16) -#define VID_C_MSK_SYNC (1 << 12) -#define VID_C_MSK_OF (1 << 8) -#define VID_C_MSK_RISCI2 (1 << 4) -#define VID_C_MSK_RISCI1 1 +/* A superset for testing purposes */ +#define VID_BC_MSK_BAD_PKT (1 << 20) +#define VID_BC_MSK_OPC_ERR (1 << 16) +#define VID_BC_MSK_SYNC (1 << 12) +#define VID_BC_MSK_OF (1 << 8) +#define VID_BC_MSK_RISCI2 (1 << 4) +#define VID_BC_MSK_RISCI1 1 + +#define VID_C_INT_MSK 0x00040040 #define VID_C_INT_STAT 0x00040044 #define VID_C_INT_MSTAT 0x00040048 #define VID_C_INT_SSTAT 0x0004004C diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4933274b1e39..45c47cd60703 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -168,6 +168,7 @@ struct cx23885_tsport { u32 reg_vld_misc; u32 reg_ts_clk_en; u32 reg_ts_int_msk; + u32 reg_ts_int_stat; u32 reg_src_sel; /* Default register vals */ @@ -201,7 +202,7 @@ struct cx23885_dev { unsigned int board; char name[32]; - struct cx23885_tsport ts2; + struct cx23885_tsport ts1, ts2; /* sram configuration */ struct sram_channel *sram_channels; @@ -269,6 +270,8 @@ extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; extern void cx23885_card_list(struct cx23885_dev *dev); +extern int cx23885_ir_init(struct cx23885_dev *dev); +extern void cx23885_gpio_setup(struct cx23885_dev *dev); extern void cx23885_card_setup(struct cx23885_dev *dev); extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); From f139fa71c03d80c1d1ee60aa4b0a3ec7a14d45f9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 03:55:34 -0300 Subject: [PATCH 0733/2804] V4L/DVB (6200): cx23885: use a pointer to the required i2c bus in dvb_register function Store a pointer to the required i2c_bus so that we do not put the wrong analog demod into standby. Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index e0dc1495b8cd..d952f3a67532 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -112,6 +112,7 @@ static struct lgdt330x_config fusionhdtv_5_express = { static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; + struct cx23885_i2c *i2c_bus = NULL; /* init struct videobuf_dvb */ port->dvb.name = dev->name; @@ -120,33 +121,35 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, + &i2c_bus->i2c_adap, &hauppauge_generic_tunerconfig, 0); } break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_hvr1800lp_config, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, + &i2c_bus->i2c_adap, &hauppauge_generic_tunerconfig, 0); } break; case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_5_express, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, port->dvb.frontend, - 0x61, &dev->i2c_bus[0].i2c_adap, - DVB_PLL_LG_TDVS_H06XF); + dvb_attach(dvb_pll_attach, port->dvb.frontend, 0x61, + &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF); } break; default: @@ -160,8 +163,7 @@ static int dvb_register(struct cx23885_tsport *port) } /* Put the analog decoder in standby to keep it quiet */ - /* Assumption here: analog decoder is only on i2c bus 0 */ - cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL); /* register everything */ return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, From 289ea1f03353104c4f288f6c70c5c7e1568ea257 Mon Sep 17 00:00:00 2001 From: Simon Farnsworth Date: Mon, 10 Sep 2007 13:37:26 -0300 Subject: [PATCH 0734/2804] V4L/DVB (6203): Fix SVideo input on KWorld DVB-T 220 boards Fix SVideo input on KWorld DVB-T 220 boards. Without this patch, the luma pin on the SVideo input is treated as a composite in, and the chroma pin is ignored. Also, fix the radio, and provide a second composite input for people who are used to the existing composite on SVideo connector behaviour. Signed-off-by: Simon Farnsworth Reviewed-by: Hermann Pitton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 5c3174a62e58..c4dc9868c48b 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2771,6 +2771,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 1 << 21, .inputs = {{ .name = name_tv, .vmux = 1, @@ -2781,13 +2782,18 @@ struct saa7134_board saa7134_boards[] = { .vmux = 3, .amux = LINE1, },{ - .name = name_svideo, + .name = name_comp2, .vmux = 0, .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, }}, .radio = { .name = name_radio, - .amux = LINE1, + .amux = TV, + .gpio = 0x0200000, }, }, [SAA7134_BOARD_KWORLD_DVBT_210] = { From 747f07961e9450058522840129cd7bb994f05fb9 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:10:11 -0300 Subject: [PATCH 0735/2804] V4L/DVB (6205): pvrusb2: Fix oops in error leg cleanup Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-context.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index 6bbed88d7867..22719ba861ac 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -33,8 +33,10 @@ static void pvr2_context_destroy(struct pvr2_context *mp) { if (mp->hdw) pvr2_hdw_destroy(mp->hdw); pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); - flush_workqueue(mp->workqueue); - destroy_workqueue(mp->workqueue); + if (mp->workqueue) { + flush_workqueue(mp->workqueue); + destroy_workqueue(mp->workqueue); + } kfree(mp); } From 401c27ce96382b3bdbc7a9c7e7303fd1b3af9ef0 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:11:46 -0300 Subject: [PATCH 0736/2804] V4L/DVB (6207): pvrusb2: Fix a potential oops in an error leg cleanup Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 2d5be5cfbccf..5d9045268cf5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2172,6 +2172,7 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) /* Destroy hardware interaction structure */ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) { + if (!hdw) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); if (hdw->fw_buffer) { kfree(hdw->fw_buffer); From 4db666cc3d199a8b837174bb0ad00d6b8f6115d6 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:16:27 -0300 Subject: [PATCH 0737/2804] V4L/DVB (6208): pvrusb2: Implement programmatic means to extract prom contents The pvrusb2 driver already has a method for extracting the FX2's program memory back out to a user application; this ability is used to facilitate manual firmware extraction as per the procedure documented on the pvrusb2 web site. This change follows that pattern and implements a corresponding method to grab the binary contents of the PVR USB2 prom (which for PVR USB2 devices can contain information in addition to the usual Hauppauge metadata). Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- .../media/video/pvrusb2/pvrusb2-debugifc.c | 16 +- .../video/pvrusb2/pvrusb2-hdw-internal.h | 1 + drivers/media/video/pvrusb2/pvrusb2-hdw.c | 156 ++++++++++++++---- drivers/media/video/pvrusb2/pvrusb2-hdw.h | 12 +- 4 files changed, 150 insertions(+), 35 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c index e9da9bb8f8de..6f135f4a2497 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c @@ -397,10 +397,22 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, count -= scnt; buf += scnt; if (!wptr) return -EINVAL; if (debugifc_match_keyword(wptr,wlen,"fetch")) { - pvr2_hdw_cpufw_set_enabled(hdw,!0); + scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); + if (scnt && wptr) { + count -= scnt; buf += scnt; + if (debugifc_match_keyword(wptr,wlen,"prom")) { + pvr2_hdw_cpufw_set_enabled(hdw,!0,!0); + } else if (debugifc_match_keyword(wptr,wlen, + "ram")) { + pvr2_hdw_cpufw_set_enabled(hdw,0,!0); + } else { + return -EINVAL; + } + } + pvr2_hdw_cpufw_set_enabled(hdw,0,!0); return 0; } else if (debugifc_match_keyword(wptr,wlen,"done")) { - pvr2_hdw_cpufw_set_enabled(hdw,0); + pvr2_hdw_cpufw_set_enabled(hdw,0,0); return 0; } else { return -EINVAL; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index ce66ab8ff2d8..985d9ae7f5ee 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -238,6 +238,7 @@ struct pvr2_hdw { // CPU firmware info (used to help find / save firmware data) char *fw_buffer; unsigned int fw_size; + int fw_cpu_flag; /* True if we are dealing with the CPU */ // Which subsystem pieces have been enabled / configured unsigned long subsys_enabled_mask; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 5d9045268cf5..7172f66a6a28 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2605,7 +2605,85 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) } while (0); LOCK_GIVE(hdw->big_lock); } -void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) + +/* Grab EEPROM contents, needed for direct method. */ +#define EEPROM_SIZE 8192 +#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__) +static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) +{ + struct i2c_msg msg[2]; + u8 *eeprom; + u8 iadd[2]; + u8 addr; + u16 eepromSize; + unsigned int offs; + int ret; + int mode16 = 0; + unsigned pcnt,tcnt; + eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); + if (!eeprom) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Failed to allocate memory" + " required to read eeprom"); + return NULL; + } + + trace_eeprom("Value for eeprom addr from controller was 0x%x", + hdw->eeprom_addr); + addr = hdw->eeprom_addr; + /* Seems that if the high bit is set, then the *real* eeprom + address is shifted right now bit position (noticed this in + newer PVR USB2 hardware) */ + if (addr & 0x80) addr >>= 1; + + /* FX2 documentation states that a 16bit-addressed eeprom is + expected if the I2C address is an odd number (yeah, this is + strange but it's what they do) */ + mode16 = (addr & 1); + eepromSize = (mode16 ? EEPROM_SIZE : 256); + trace_eeprom("Examining %d byte eeprom at location 0x%x" + " using %d bit addressing",eepromSize,addr, + mode16 ? 16 : 8); + + msg[0].addr = addr; + msg[0].flags = 0; + msg[0].len = mode16 ? 2 : 1; + msg[0].buf = iadd; + msg[1].addr = addr; + msg[1].flags = I2C_M_RD; + + /* We have to do the actual eeprom data fetch ourselves, because + (1) we're only fetching part of the eeprom, and (2) if we were + getting the whole thing our I2C driver can't grab it in one + pass - which is what tveeprom is otherwise going to attempt */ + memset(eeprom,0,EEPROM_SIZE); + for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { + pcnt = 16; + if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; + offs = tcnt + (eepromSize - EEPROM_SIZE); + if (mode16) { + iadd[0] = offs >> 8; + iadd[1] = offs; + } else { + iadd[0] = offs; + } + msg[1].len = pcnt; + msg[1].buf = eeprom+tcnt; + if ((ret = i2c_transfer(&hdw->i2c_adap, + msg,ARRAY_SIZE(msg))) != 2) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "eeprom fetch set offs err=%d",ret); + kfree(eeprom); + return NULL; + } + } + return eeprom; +} + + +void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, + int prom_flag, + int enable_flag) { int ret; u16 address; @@ -2619,38 +2697,60 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) kfree(hdw->fw_buffer); hdw->fw_buffer = NULL; hdw->fw_size = 0; - /* Now release the CPU. It will disconnect and - reconnect later. */ - pvr2_hdw_cpureset_assert(hdw,0); + if (hdw->fw_cpu_flag) { + /* Now release the CPU. It will disconnect + and reconnect later. */ + pvr2_hdw_cpureset_assert(hdw,0); + } break; } - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Preparing to suck out CPU firmware"); - hdw->fw_size = 0x2000; - hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); - if (!hdw->fw_buffer) { - hdw->fw_size = 0; - break; + hdw->fw_cpu_flag = (prom_flag == 0); + if (hdw->fw_cpu_flag) { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Preparing to suck out CPU firmware"); + hdw->fw_size = 0x2000; + hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); + if (!hdw->fw_buffer) { + hdw->fw_size = 0; + break; + } + + /* We have to hold the CPU during firmware upload. */ + pvr2_hdw_cpureset_assert(hdw,1); + + /* download the firmware from address 0000-1fff in 2048 + (=0x800) bytes chunk. */ + + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Grabbing CPU firmware"); + pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); + for(address = 0; address < hdw->fw_size; + address += 0x800) { + ret = usb_control_msg(hdw->usb_dev,pipe, + 0xa0,0xc0, + address,0, + hdw->fw_buffer+address, + 0x800,HZ); + if (ret < 0) break; + } + + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Done grabbing CPU firmware"); + } else { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Sucking down EEPROM contents"); + hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw); + if (!hdw->fw_buffer) { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "EEPROM content suck failed."); + break; + } + hdw->fw_size = EEPROM_SIZE; + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Done sucking down EEPROM contents"); } - /* We have to hold the CPU during firmware upload. */ - pvr2_hdw_cpureset_assert(hdw,1); - - /* download the firmware from address 0000-1fff in 2048 - (=0x800) bytes chunk. */ - - pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware"); - pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); - for(address = 0; address < hdw->fw_size; address += 0x800) { - ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0, - address,0, - hdw->fw_buffer+address,0x800,HZ); - if (ret < 0) break; - } - - pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware"); - } while (0); LOCK_GIVE(hdw->big_lock); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 4dba8d006324..e2f9d5e4cb65 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -197,11 +197,13 @@ void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); -/* Enable / disable retrieval of CPU firmware. This must be enabled before - pvr2_hdw_cpufw_get() will function. Note that doing this may prevent - the device from running (and leaving this mode may imply a device - reset). */ -void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag); +/* Enable / disable retrieval of CPU firmware or prom contents. This must + be enabled before pvr2_hdw_cpufw_get() will function. Note that doing + this may prevent the device from running (and leaving this mode may + imply a device reset). */ +void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, + int prom_flag, + int enable_flag); /* Return true if we're in a mode for retrieval CPU firmware */ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); From 1d643a372259749ce2029e386ed5760d5d7f8b89 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:18:50 -0300 Subject: [PATCH 0738/2804] V4L/DVB (6209): pvrusb2: Better discriminate among device types This is a bunch of cleanup in various places to improve behavior based on actual device type being driven. While this doesn't actually affect operation with existing devices, it cleans things up so that it will be easier / more deterministic when other devices are added. Ideally we should make stuff like this table-driven, but for now this is just a series of small incremental (read: safe) improvements. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 84 +++++++++++++++-------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 7172f66a6a28..c8ee379159e2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1143,6 +1143,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx) }, }; + + if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) || + (!fw_file_defs[hdw->hdw_type].lst)) { + hdw->fw1_state = FW1_STATE_OK; + return 0; + } + hdw->fw1_state = FW1_STATE_FAILED; // default result trace_firmware("pvr2_upload_firmware1"); @@ -1224,6 +1231,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) CX2341X_FIRM_ENC_FILENAME, }; + if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) && + (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) { + return 0; + } + trace_firmware("pvr2_upload_firmware2"); ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder", @@ -1742,30 +1754,36 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) unsigned int idx; struct pvr2_ctrl *cptr; int reloadFl = 0; - if (!reloadFl) { - reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints - == 0); + if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || + (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + if (!reloadFl) { + reloadFl = + (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints + == 0); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "USB endpoint config looks strange" + "; possibly firmware needs to be" + " loaded"); + } + } + if (!reloadFl) { + reloadFl = !pvr2_hdw_check_firmware(hdw); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "Check for FX2 firmware failed" + "; possibly firmware needs to be" + " loaded"); + } + } if (reloadFl) { - pvr2_trace(PVR2_TRACE_INIT, - "USB endpoint config looks strange" - "; possibly firmware needs to be loaded"); + if (pvr2_upload_firmware1(hdw) != 0) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Failure uploading firmware1"); + } + return; } } - if (!reloadFl) { - reloadFl = !pvr2_hdw_check_firmware(hdw); - if (reloadFl) { - pvr2_trace(PVR2_TRACE_INIT, - "Check for FX2 firmware failed" - "; possibly firmware needs to be loaded"); - } - } - if (reloadFl) { - if (pvr2_upload_firmware1(hdw) != 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failure uploading firmware1"); - } - return; - } hdw->fw1_state = FW1_STATE_OK; if (initusbreset) { @@ -1773,17 +1791,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } if (!pvr2_hdw_dev_ok(hdw)) return; - for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) { - request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]); + if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) { + for (idx = 0; + idx < pvr2_client_lists[hdw->hdw_type].cnt; + idx++) { + request_module( + pvr2_client_lists[hdw->hdw_type].lst[idx]); + } } - pvr2_hdw_cmd_powerup(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; + if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || + (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + pvr2_hdw_cmd_powerup(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; - if (pvr2_upload_firmware2(hdw)){ - pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); - pvr2_hdw_render_useless(hdw); - return; + if (pvr2_upload_firmware2(hdw)){ + pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); + pvr2_hdw_render_useless(hdw); + return; + } } // This step MUST happen after the earlier powerup step. From 9f66d4eac6be2428901ab6e0cbb6747d5b6794ef Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:28:51 -0300 Subject: [PATCH 0739/2804] V4L/DVB (6210): pvrusb2: Do a far better job at setting the default initial video standard The v4l tveeprom logic tells us what video standards are supported by the hardware, however it doesn't directly tell us what should be the preferred initial standard. For example "NTSC/NTSC-J" devices are reported by tveeprom as support NTSC-M and PAL-M, and while that might be true, in the vast majority of cases NTSC-M is really what the user is going to want. However the driver previously just arbitrarily picked the "lowest numbered" standard as the initial default, which in that case would have been PAL-M. (And making matters more confusing - this only caused real problems on 24xxx devices because the saa7115 on 29xxx seems to autodetect the right answer anyway.) This change implements an algorithm that uses the set of "supported" standards as a hint to decide on the initial standard. This algorithm ONLY comes into play if the driver isn't specifically told what to do; said another way - the user can always still change the standard via the sysfs interface, via the usual V4L methods, or even specified as a module parameter. The idea here is only to pick a better starting point if the user (or app) doesn't otherwise do something to set the standard; otherwise this change has no real impact. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 59 +++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index c8ee379159e2..20dc573bc150 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1694,6 +1694,44 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) return result == 0; } +struct pvr2_std_hack { + v4l2_std_id pat; /* Pattern to match */ + v4l2_std_id msk; /* Which bits we care about */ + v4l2_std_id std; /* What additional standards or default to set */ +}; + +/* This data structure labels specific combinations of standards from + tveeprom that we'll try to recognize. If we recognize one, then assume + a specified default standard to use. This is here because tveeprom only + tells us about available standards not the intended default standard (if + any) for the device in question. We guess the default based on what has + been reported as available. Note that this is only for guessing a + default - which can always be overridden explicitly - and if the user + has otherwise named a default then that default will always be used in + place of this table. */ +const static struct pvr2_std_hack std_eeprom_maps[] = { + { /* PAL(B/G) */ + .pat = V4L2_STD_B|V4L2_STD_GH, + .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G, + }, + { /* NTSC(M) */ + .pat = V4L2_STD_MN, + .std = V4L2_STD_NTSC_M, + }, + { /* PAL(I) */ + .pat = V4L2_STD_PAL_I, + .std = V4L2_STD_PAL_I, + }, + { /* SECAM(L/L') */ + .pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, + .std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, + }, + { /* PAL(D/D1/K) */ + .pat = V4L2_STD_DK, + .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K, + }, +}; + static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) { char buf[40]; @@ -1732,6 +1770,27 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) return; } + { + unsigned int idx; + for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) { + if (std_eeprom_maps[idx].msk ? + ((std_eeprom_maps[idx].pat ^ + hdw->std_mask_eeprom) & + std_eeprom_maps[idx].msk) : + (std_eeprom_maps[idx].pat != + hdw->std_mask_eeprom)) continue; + bcnt = pvr2_std_id_to_str(buf,sizeof(buf), + std_eeprom_maps[idx].std); + pvr2_trace(PVR2_TRACE_INIT, + "Initial video standard guessed as %.*s", + bcnt,buf); + hdw->std_mask_cur = std_eeprom_maps[idx].std; + hdw->std_dirty = !0; + pvr2_hdw_internal_find_stdenum(hdw); + return; + } + } + if (hdw->std_enum_cnt > 1) { // Autoselect the first listed standard hdw->std_enum_cur = 1; From 56585386e297c54a65feef55810c13b4313bdf1e Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:32:12 -0300 Subject: [PATCH 0740/2804] V4L/DVB (6211): pvrusb2: Allocate a debug mask bit for reporting video standard things It's useful to see specific details for how the pvrusb2 driver is figuring out things related to the video standard, independent of other initialization activities. So let's set up a separate debug mask bit for this and turn it on. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-debug.h | 53 +++++++++++---------- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 10 ++-- drivers/media/video/pvrusb2/pvrusb2-main.c | 1 + drivers/media/video/pvrusb2/pvrusb2-std.c | 8 ++-- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index d95a8588e4f8..da6441b88f31 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -26,32 +26,33 @@ extern int pvrusb2_debug; /* These are listed in *rough* order of decreasing usefulness and increasing noise level. */ -#define PVR2_TRACE_INFO (1 << 0) // Normal messages -#define PVR2_TRACE_ERROR_LEGS (1 << 1) // error messages -#define PVR2_TRACE_TOLERANCE (1 << 2) // track tolerance-affected errors -#define PVR2_TRACE_TRAP (1 << 3) // Trap & report misbehavior from app -#define PVR2_TRACE_INIT (1 << 4) // misc initialization steps -#define PVR2_TRACE_START_STOP (1 << 5) // Streaming start / stop -#define PVR2_TRACE_CTL (1 << 6) // commit of control changes -#define PVR2_TRACE_DEBUG (1 << 7) // Temporary debug code -#define PVR2_TRACE_EEPROM (1 << 8) // eeprom parsing / report -#define PVR2_TRACE_STRUCT (1 << 9) // internal struct creation -#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close -#define PVR2_TRACE_CREG (1 << 11) // Main critical region entry / exit -#define PVR2_TRACE_SYSFS (1 << 12) // Sysfs driven I/O -#define PVR2_TRACE_FIRMWARE (1 << 13) // firmware upload actions -#define PVR2_TRACE_CHIPS (1 << 14) // chip broadcast operation -#define PVR2_TRACE_I2C (1 << 15) // I2C related stuff -#define PVR2_TRACE_I2C_CMD (1 << 16) // Software commands to I2C modules -#define PVR2_TRACE_I2C_CORE (1 << 17) // I2C core debugging -#define PVR2_TRACE_I2C_TRAF (1 << 18) // I2C traffic through the adapter -#define PVR2_TRACE_V4LIOCTL (1 << 19) // v4l ioctl details -#define PVR2_TRACE_ENCODER (1 << 20) // mpeg2 encoder operation -#define PVR2_TRACE_BUF_POOL (1 << 21) // Track buffer pool management -#define PVR2_TRACE_BUF_FLOW (1 << 22) // Track buffer flow in system -#define PVR2_TRACE_DATA_FLOW (1 << 23) // Track data flow -#define PVR2_TRACE_DEBUGIFC (1 << 24) // Debug interface actions -#define PVR2_TRACE_GPIO (1 << 25) // GPIO state bit changes +#define PVR2_TRACE_INFO (1 << 0) /* Normal messages */ +#define PVR2_TRACE_ERROR_LEGS (1 << 1) /* error messages */ +#define PVR2_TRACE_TOLERANCE (1 << 2) /* track tolerance-affected errors */ +#define PVR2_TRACE_TRAP (1 << 3) /* Trap & report app misbehavior */ +#define PVR2_TRACE_STD (1 << 4) /* Log video standard stuff */ +#define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */ +#define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */ +#define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */ +#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */ +#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */ +#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */ +#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */ +#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */ +#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */ +#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */ +#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */ +#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */ +#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */ +#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */ +#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */ +#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */ +#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */ +#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */ +#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */ +#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */ +#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */ +#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 20dc573bc150..eec83d6ae788 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1741,7 +1741,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) std1 = get_default_standard(hdw); bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Supported video standard(s) reported by eeprom: %.*s", bcnt,buf); @@ -1750,7 +1750,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) std2 = std1 & ~hdw->std_mask_avail; if (std2) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Expanding supported video standards" " to include: %.*s", bcnt,buf); @@ -1761,7 +1761,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) if (std1) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard forced to %.*s", bcnt,buf); hdw->std_mask_cur = std1; @@ -1781,7 +1781,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) hdw->std_mask_eeprom)) continue; bcnt = pvr2_std_id_to_str(buf,sizeof(buf), std_eeprom_maps[idx].std); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard guessed as %.*s", bcnt,buf); hdw->std_mask_cur = std_eeprom_maps[idx].std; @@ -1796,7 +1796,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) hdw->std_enum_cur = 1; hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id; hdw->std_dirty = !0; - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard auto-selected to %s", hdw->std_defs[hdw->std_enum_cur-1].name); return; diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 1ea0939096ae..ca9e2789c8ca 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -41,6 +41,7 @@ #define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \ PVR2_TRACE_INFO| \ + PVR2_TRACE_STD| \ PVR2_TRACE_TOLERANCE| \ PVR2_TRACE_TRAP| \ 0) diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c index 81de26ba41d9..63e55bb59fcb 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c @@ -298,7 +298,7 @@ static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id) std->id = id; bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id); std->name[bcnt] = 0; - pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s", + pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s", std->index,std->name); return !0; } @@ -320,11 +320,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, v4l2_std_id idmsk,cmsk,fmsk; struct v4l2_standard *stddefs; - if (pvrusb2_debug & PVR2_TRACE_INIT) { + if (pvrusb2_debug & PVR2_TRACE_STD) { char buf[50]; bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id); pvr2_trace( - PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)", + PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)", (int)id,bcnt,buf); } @@ -355,7 +355,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, bcnt,buf); } - pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)", + pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)", std_cnt); if (!std_cnt) return NULL; // paranoia From 7fb0dfc853735ccf4e580b0d71510bad96d37c4f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Sep 2007 23:19:32 -0300 Subject: [PATCH 0741/2804] V4L/DVB (6212): pvrusb2: I2C adapter tweaks from Jean Delvare * I2C adapters aren't expected to handle I2C_M_NOSTART unless they really have to. As the pvrusb2 driver doesn't support it, I take it that it doesn't need it so it shouldn't mention it at all. * I2C_FUNC_SMBUS_EMUL includes I2C_FUNC_SMBUS_BYTE_DATA so listing both is redundant. Signed-off-by: Jean Delvare Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 6786d3c0c98b..7697f391e8bb 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -389,10 +389,6 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, ret = -EINVAL; goto done; } - if ((msgs[0].flags & I2C_M_NOSTART)) { - trace_i2c("i2c refusing I2C_M_NOSTART"); - goto done; - } if (msgs[0].addr < PVR2_I2C_FUNC_CNT) { funcp = hdw->i2c_func[msgs[0].addr]; } @@ -494,14 +490,12 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, cnt = msgs[idx].len; printk(KERN_INFO "pvrusb2 i2c xfer %u/%u:" - " addr=0x%x len=%d %s%s", + " addr=0x%x len=%d %s", idx+1,num, msgs[idx].addr, cnt, (msgs[idx].flags & I2C_M_RD ? - "read" : "write"), - (msgs[idx].flags & I2C_M_NOSTART ? - " nostart" : "")); + "read" : "write")); if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) { if (cnt > 8) cnt = 8; printk(" ["); @@ -534,7 +528,7 @@ static int pvr2_i2c_control(struct i2c_adapter *adapter, static u32 pvr2_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } static int pvr2_i2c_core_singleton(struct i2c_client *cp, From 39f46adef8e83653b4716369683c134e1413ad30 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 9 Sep 2007 06:17:44 -0300 Subject: [PATCH 0742/2804] V4L/DVB (6214): usbvision: Don't support I2C_M_REV_DIR_ADDR I2C adapters should only support I2C_M_REV_DIR_ADDR if they really have to (i.e. if they are connected to a broken I2C device which needs this deviation from the standard I2C protocol.) As no media chip driver uses I2C_M_REV_DIR_ADDR, I don't think that the usbvision driver needs to support it. Signed-off-by: Jean Delvare Acked-by: Thierry Merle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-i2c.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 025be555194f..c66aef63916f 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -134,8 +134,6 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, addr = (msg->addr << 1); if (flags & I2C_M_RD) addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR) - addr ^= 1; add[0] = addr; if (flags & I2C_M_RD) @@ -192,7 +190,7 @@ static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned static u32 functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; } From 588005e1008f2cea61b7a1ae2a86c531e99b8c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans-J=C3=BCrgen=20Koch?= Date: Wed, 12 Sep 2007 16:20:43 -0300 Subject: [PATCH 0743/2804] V4L/DVB (6215): Bugfix for saa6588.c, add forgotten spin_lock_init() There's a serious bug in saa6588.c, it uses a non-initialized spin_lock. Funny thing is that it works fine with bttv, but completly freezes the machine if e.g. saa7134 is loaded. Thanks to Derek Philip for reporting this bug on the rdsd-devel list. This patch adds the missing spin_lock_init(). Signed-off-by: Hans J. Koch Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa6588.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index 92eabf88a09b..72e344a12c79 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -406,6 +406,7 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) kfree(s); return -ENOMEM; } + spin_lock_init(&s->lock); s->client = client_template; s->block_count = 0; s->wr_index = 0; From 098c645e39e10dc580763b5ea4bd4fb390013474 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:38 -0300 Subject: [PATCH 0744/2804] V4L/DVB (6216): V4L: Int if: add vidioc_int_g_ifparm, other updates vidioc_int_g_ifparm can be used to obtain hardware-specific information about the interface used by the slave. Rearrange v4l2-int-device.h as well. Also remove useless & characters. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 4 +- include/media/v4l2-int-device.h | 138 +++++++++++++++----------- 2 files changed, 84 insertions(+), 58 deletions(-) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index a643730fa3b2..7ad8700ebdea 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -150,7 +150,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) { return ((v4l2_int_ioctl_func_0 *) find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)&no_such_ioctl_0))(d); + (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); } static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) @@ -162,5 +162,5 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) { return ((v4l2_int_ioctl_func_1 *) find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)&no_such_ioctl_1))(d, arg); + (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index deb28ce6685d..861978deb3bf 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -30,67 +30,17 @@ #define V4L2NAMESIZE 32 +/* + * + * The internal V4L2 device interface core. + * + */ + enum v4l2_int_type { v4l2_int_type_master = 1, v4l2_int_type_slave }; -enum v4l2_int_ioctl_num { - /* - * - * "Proper" V4L ioctls, as in struct video_device. - * - */ - vidioc_int_enum_fmt_cap_num = 1, - vidioc_int_g_fmt_cap_num, - vidioc_int_s_fmt_cap_num, - vidioc_int_try_fmt_cap_num, - vidioc_int_queryctrl_num, - vidioc_int_g_ctrl_num, - vidioc_int_s_ctrl_num, - vidioc_int_g_parm_num, - vidioc_int_s_parm_num, - - /* - * - * Strictly internal ioctls. - * - */ - /* Initialise the device when slave attaches to the master. */ - vidioc_int_dev_init_num = 1000, - /* Delinitialise the device at slave detach. */ - vidioc_int_dev_exit_num, - /* Set device power state: 0 is off, non-zero is on. */ - vidioc_int_s_power_num, - /* Get parallel interface clock speed for current settings. */ - vidioc_int_g_ext_clk_num, - /* - * Tell what the parallel interface clock speed actually is. - */ - vidioc_int_s_ext_clk_num, - /* Does the slave need to be reset after VIDIOC_DQBUF? */ - vidioc_int_g_needs_reset_num, - - /* - * - * VIDIOC_INT_* ioctls. - * - */ - /* VIDIOC_INT_RESET */ - vidioc_int_reset_num, - /* VIDIOC_INT_INIT */ - vidioc_int_init_num, - /* VIDIOC_INT_G_CHIP_IDENT */ - vidioc_int_g_chip_ident_num, - - /* - * - * Start of private ioctls. - * - */ - vidioc_int_priv_start_num = 2000, -}; - struct v4l2_int_device; struct v4l2_int_master { @@ -141,6 +91,81 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d); int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); +/* + * + * Types and definitions for IOCTL commands. + * + */ + +/* Slave interface type. */ +enum v4l2_if_type { +}; + +struct v4l2_ifparm { + enum v4l2_if_type if_type; + union { + } u; +}; + +/* IOCTL command numbers. */ +enum v4l2_int_ioctl_num { + /* + * + * "Proper" V4L ioctls, as in struct video_device. + * + */ + vidioc_int_enum_fmt_cap_num = 1, + vidioc_int_g_fmt_cap_num, + vidioc_int_s_fmt_cap_num, + vidioc_int_try_fmt_cap_num, + vidioc_int_queryctrl_num, + vidioc_int_g_ctrl_num, + vidioc_int_s_ctrl_num, + vidioc_int_g_parm_num, + vidioc_int_s_parm_num, + + /* + * + * Strictly internal ioctls. + * + */ + /* Initialise the device when slave attaches to the master. */ + vidioc_int_dev_init_num = 1000, + /* Delinitialise the device at slave detach. */ + vidioc_int_dev_exit_num, + /* Set device power state: 0 is off, non-zero is on. */ + vidioc_int_s_power_num, + /* Get slave interface parameters. */ + vidioc_int_g_ifparm_num, + /* Get external clock speed for current slave settings. */ + vidioc_int_g_ext_clk_num, + /* + * Tell what the generated interface clock speed actually is. + */ + vidioc_int_s_ext_clk_num, + /* Does the slave need to be reset after VIDIOC_DQBUF? */ + vidioc_int_g_needs_reset_num, + + /* + * + * VIDIOC_INT_* ioctls. + * + */ + /* VIDIOC_INT_RESET */ + vidioc_int_reset_num, + /* VIDIOC_INT_INIT */ + vidioc_int_init_num, + /* VIDIOC_INT_G_CHIP_IDENT */ + vidioc_int_g_chip_ident_num, + + /* + * + * Start of private ioctls. + * + */ + vidioc_int_priv_start_num = 2000, +}; + /* * * IOCTL wrapper functions for better type checking. @@ -199,6 +224,7 @@ V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); V4L2_INT_WRAPPER_0(dev_init); V4L2_INT_WRAPPER_0(dev_exit); V4L2_INT_WRAPPER_1(s_power, int, ); +V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); V4L2_INT_WRAPPER_1(g_needs_reset, void, *); From 08256ea0da18db20f2edc2e8c935cf74c33ad564 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:39 -0300 Subject: [PATCH 0745/2804] V4L/DVB (6217): V4L: Int if: Add BT.656 interface support This patch adds BT.656 interface settings for [gs]_ifparm. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-int-device.h | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 861978deb3bf..4e07707bd5ea 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -99,11 +99,61 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); /* Slave interface type. */ enum v4l2_if_type { + /* + * Parallel 8-, 10- or 12-bit interface, used by for example + * on certain image sensors. + */ + V4L2_IF_TYPE_BT656, +}; + +enum v4l2_if_type_bt656_mode { + /* + * Modes without Bt synchronisation codes. Separate + * synchronisation signal lines are used. + */ + V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT, + V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT, + V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT, + /* + * Use Bt synchronisation codes. The vertical and horizontal + * synchronisation is done based on synchronisation codes. + */ + V4L2_IF_TYPE_BT656_MODE_BT_8BIT, + V4L2_IF_TYPE_BT656_MODE_BT_10BIT, +}; + +struct v4l2_if_type_bt656 { + /* + * 0: Frame begins when vsync is high. + * 1: Frame begins when vsync changes from low to high. + */ + unsigned frame_start_on_rising_vs:1; + /* Use Bt synchronisation codes for sync correction. */ + unsigned bt_sync_correct:1; + /* Swap every two adjacent image data elements. */ + unsigned swap:1; + /* Inverted latch clock polarity from slave. */ + unsigned latch_clk_inv:1; + /* Hs polarity. 0 is active high, 1 active low. */ + unsigned nobt_hs_inv:1; + /* Vs polarity. 0 is active high, 1 active low. */ + unsigned nobt_vs_inv:1; + enum v4l2_if_type_bt656_mode mode; + /* Minimum accepted bus clock for slave (in Hz). */ + u32 clock_min; + /* Maximum accepted bus clock for slave. */ + u32 clock_max; + /* + * Current wish of the slave. May only change in response to + * ioctls that affect image capture. + */ + u32 clock_curr; }; struct v4l2_ifparm { enum v4l2_if_type if_type; union { + struct v4l2_if_type_bt656 bt656; } u; }; From 61c310dc1e2a34bced25b4fa7609316d6755ccc2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:40 -0300 Subject: [PATCH 0746/2804] V4L/DVB (6218): V4L: Int if: Use -ENOIOCTLCMD for nonexistent ioctls Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 7ad8700ebdea..f497c9458344 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -143,7 +143,7 @@ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, static int no_such_ioctl_0(struct v4l2_int_device *d) { - return -EINVAL; + return -ENOIOCTLCMD; } int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) @@ -155,7 +155,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) { - return -EINVAL; + return -ENOIOCTLCMD; } int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) From 768f4bd3d6a88c13a4099451aa85ae75c9061316 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:41 -0300 Subject: [PATCH 0747/2804] V4L/DVB (6219): V4L: Int if: Remove [gs]_ext_clk Remove support for g_ext_clk and s_ext_clk. The same functionality is now handled by g_ifparm. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-int-device.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 4e07707bd5ea..066ebfc4f983 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -187,12 +187,6 @@ enum v4l2_int_ioctl_num { vidioc_int_s_power_num, /* Get slave interface parameters. */ vidioc_int_g_ifparm_num, - /* Get external clock speed for current slave settings. */ - vidioc_int_g_ext_clk_num, - /* - * Tell what the generated interface clock speed actually is. - */ - vidioc_int_s_ext_clk_num, /* Does the slave need to be reset after VIDIOC_DQBUF? */ vidioc_int_g_needs_reset_num, @@ -275,8 +269,6 @@ V4L2_INT_WRAPPER_0(dev_init); V4L2_INT_WRAPPER_0(dev_exit); V4L2_INT_WRAPPER_1(s_power, int, ); V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); -V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); -V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); V4L2_INT_WRAPPER_1(g_needs_reset, void, *); V4L2_INT_WRAPPER_0(reset); From 2060955748dff6280cd211b68c92d9a99d1c78f9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:42 -0300 Subject: [PATCH 0748/2804] V4L/DVB (6220): TCM825x: Add support for vidioc_int_g_ifparm call, small cleanups vidioc_int_g_ifparm returns platform-specific information about the interface settings used by the sensor. Support for [gs]_ext_clk has been removed. Fix indentation and remove useless & characters. Remove experiment for typechecking slave callback function arguments. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tcm825x.c | 128 +++++++++++++++------------------- drivers/media/video/tcm825x.h | 4 ++ 2 files changed, 61 insertions(+), 71 deletions(-) diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 3a139f288a9d..41cd6a0b0485 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -470,46 +470,6 @@ static int tcm825x_configure(struct v4l2_int_device *s) return 0; } -/* - * Given the image capture format in pix, the nominal frame period in - * timeperframe, calculate the required xclk frequency. - * - * TCM825X input frequency characteristics are: - * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz - */ -#define XCLK_MIN 11900000 -#define XCLK_MAX 25000000 - -static int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk) -{ - struct tcm825x_sensor *sensor = s->priv; - struct v4l2_fract *timeperframe = &sensor->timeperframe; - u32 tgt_xclk; /* target xclk */ - u32 tgt_fps; /* target frames per secound */ - - tgt_fps = timeperframe->denominator / timeperframe->numerator; - - tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? - (2457 * tgt_fps) / MAX_HALF_FPS : - (2457 * tgt_fps) / MAX_FPS; - tgt_xclk *= 10000; - - tgt_xclk = min(tgt_xclk, (u32)XCLK_MAX); - tgt_xclk = max(tgt_xclk, (u32)XCLK_MIN); - - *xclk = tgt_xclk; - - return 0; -} - -static int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk) -{ - if (xclk > XCLK_MAX || xclk < XCLK_MIN) - return -EINVAL; - - return 0; -} - static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc) { @@ -756,6 +716,41 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) return sensor->platform_data->power_set(on); } +/* + * Given the image capture format in pix, the nominal frame period in + * timeperframe, calculate the required xclk frequency. + * + * TCM825X input frequency characteristics are: + * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz + */ + +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &sensor->timeperframe; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + int rval; + + rval = sensor->platform_data->ifparm(p); + if (rval) + return rval; + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? + (2457 * tgt_fps) / MAX_HALF_FPS : + (2457 * tgt_fps) / MAX_FPS; + tgt_xclk *= 10000; + + tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN); + + p->u.bt656.clock_curr = tgt_xclk; + + return 0; +} + static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) { struct tcm825x_sensor *sensor = s->priv; @@ -793,43 +788,39 @@ static int ioctl_dev_init(struct v4l2_int_device *s) return 0; } -#define NUM_IOCTLS 17 - -static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[NUM_IOCTLS] = { +static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = { { vidioc_int_dev_init_num, - (v4l2_int_ioctl_func *)&ioctl_dev_init }, + (v4l2_int_ioctl_func *)ioctl_dev_init }, { vidioc_int_dev_exit_num, - (v4l2_int_ioctl_func *)&ioctl_dev_exit }, + (v4l2_int_ioctl_func *)ioctl_dev_exit }, { vidioc_int_s_power_num, - (v4l2_int_ioctl_func *)&ioctl_s_power }, - { vidioc_int_g_ext_clk_num, - (v4l2_int_ioctl_func *)&ioctl_g_ext_clk }, - { vidioc_int_s_ext_clk_num, - (v4l2_int_ioctl_func *)&ioctl_s_ext_clk }, + (v4l2_int_ioctl_func *)ioctl_s_power }, + { vidioc_int_g_ifparm_num, + (v4l2_int_ioctl_func *)ioctl_g_ifparm }, { vidioc_int_g_needs_reset_num, - (v4l2_int_ioctl_func *)&ioctl_g_needs_reset }, + (v4l2_int_ioctl_func *)ioctl_g_needs_reset }, { vidioc_int_reset_num, - (v4l2_int_ioctl_func *)&ioctl_reset }, + (v4l2_int_ioctl_func *)ioctl_reset }, { vidioc_int_init_num, - (v4l2_int_ioctl_func *)&ioctl_init }, + (v4l2_int_ioctl_func *)ioctl_init }, { vidioc_int_enum_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, { vidioc_int_try_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, { vidioc_int_g_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, { vidioc_int_s_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, { vidioc_int_g_parm_num, - (v4l2_int_ioctl_func *)&ioctl_g_parm }, + (v4l2_int_ioctl_func *)ioctl_g_parm }, { vidioc_int_s_parm_num, - (v4l2_int_ioctl_func *)&ioctl_s_parm }, + (v4l2_int_ioctl_func *)ioctl_s_parm }, { vidioc_int_queryctrl_num, - (v4l2_int_ioctl_func *)&ioctl_queryctrl }, + (v4l2_int_ioctl_func *)ioctl_queryctrl }, { vidioc_int_g_ctrl_num, - (v4l2_int_ioctl_func *)&ioctl_g_ctrl }, + (v4l2_int_ioctl_func *)ioctl_g_ctrl }, { vidioc_int_s_ctrl_num, - (v4l2_int_ioctl_func *)&ioctl_s_ctrl }, + (v4l2_int_ioctl_func *)ioctl_s_ctrl }, }; static struct v4l2_int_slave tcm825x_slave = { @@ -894,16 +885,16 @@ static int __exit tcm825x_remove(struct i2c_client *client) } static struct i2c_driver tcm825x_i2c_driver = { - .driver = { + .driver = { .name = TCM825X_NAME, }, - .probe = &tcm825x_probe, - .remove = __exit_p(&tcm825x_remove), + .probe = tcm825x_probe, + .remove = __exit_p(tcm825x_remove), }; static struct tcm825x_sensor tcm825x = { .timeperframe = { - .numerator = 1, + .numerator = 1, .denominator = DEFAULT_FPS, }, }; @@ -911,11 +902,6 @@ static struct tcm825x_sensor tcm825x = { static int __init tcm825x_init(void) { int rval; - int i = 0; - - /* Just an experiment --- don't use *_cb functions yet. */ - tcm825x_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init); - BUG_ON(i >= NUM_IOCTLS); rval = i2c_add_driver(&tcm825x_i2c_driver); if (rval) diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h index d6471ec40bc5..966765b66b3a 100644 --- a/drivers/media/video/tcm825x.h +++ b/drivers/media/video/tcm825x.h @@ -163,6 +163,9 @@ enum pixel_format { YUV422 = 0, RGB565 }; #define NUM_IMAGE_SIZES 6 #define NUM_PIXEL_FORMATS 2 +#define TCM825X_XCLK_MIN 11900000 +#define TCM825X_XCLK_MAX 25000000 + struct capture_size { unsigned long width; unsigned long height; @@ -178,6 +181,7 @@ struct tcm825x_platform_data { const struct tcm825x_reg *(*default_regs)(void); int (*needs_reset)(struct v4l2_int_device *s, void *buf, struct v4l2_pix_format *fmt); + int (*ifparm)(struct v4l2_ifparm *p); }; /* Array of image sizes supported by TCM825X. These must be ordered from From f64899ca5af69c33a446d355609831fad6f715cd Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 17 Sep 2007 22:17:12 -0300 Subject: [PATCH 0749/2804] V4L/DVB (6221): budget-ci: select TT keymap for DVB-S TT 1500 DVB-S TT 1500 must use the TT keymap. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-ci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 873c3ba296f2..509349211d4f 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -214,7 +214,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) case 0x100f: case 0x1011: case 0x1012: - case 0x1017: /* The hauppauge keymap is a superset of these remotes */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_hauppauge_new); @@ -225,6 +224,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) budget_ci->ir.rc5_device = rc5_device; break; case 0x1010: + case 0x1017: /* for the Technotrend 1500 bundled remote */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_tt_1500); From c8e2f07be0ac536c110702ed741c7bc6836e3438 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 15 Sep 2007 18:45:10 -0300 Subject: [PATCH 0750/2804] V4L/DVB (6222): select DVB_PLL if !DVB_FE_CUSTOMISE for FusionHDTV5 Express VIDEO_CX23885 must select DVB_PLL if !DVB_FE_CUSTOMISE for FusionHDTV5 Express Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 333dd29d44b4..45345fc189e0 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -11,6 +11,7 @@ config VIDEO_CX23885 select VIDEO_BUF_DVB select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. From 0e789d7ffafbfd44f7fb2bdbf1138547d8abc231 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 18 Sep 2007 13:25:45 -0300 Subject: [PATCH 0751/2804] V4L/DVB (6224): VIDEO_CX23885 depends on DVB_CORE Fix the following dependency issue: ERROR: "dvb_dmx_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_unregister_adapter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_register_frontend" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_unregister_frontend" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_net_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_frontend_detach" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmxdev_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmx_swfilter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_net_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmx_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_register_adapter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmxdev_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "mt2131_attach" [drivers/media/video/cx23885/cx23885.ko] undefined! ERROR: "s5h1409_attach" [drivers/media/video/cx23885/cx23885.ko] undefined! Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 45345fc189e0..ebfcc7c2a89e 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -1,6 +1,6 @@ config VIDEO_CX23885 tristate "Conexant cx23885 (2388x successor) support" - depends on VIDEO_DEV && PCI && I2C + depends on DVB_CORE && VIDEO_DEV && PCI && I2C select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX From f438d97447d4ccd241db8477f62a0647b9e8220e Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 17 Sep 2007 15:34:09 -0300 Subject: [PATCH 0752/2804] V4L/DVB (6225): AverTV Studio 307 has only one composite input AverTV Studio 307 has only one composite input. Signed-off-by: Stas Sergeev Acked-by: Nickolay V. Shmyrev Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index c4dc9868c48b..6b6eae82bcfc 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -32,6 +32,7 @@ static char name_mute[] = "mute"; static char name_radio[] = "Radio"; static char name_tv[] = "Television"; static char name_tv_mono[] = "TV (mono only)"; +static char name_comp[] = "Composite"; static char name_comp1[] = "Composite1"; static char name_comp2[] = "Composite2"; static char name_comp3[] = "Composite3"; @@ -1535,12 +1536,7 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, .gpio = 0x00, },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - .gpio = 0x02, - },{ - .name = name_comp2, + .name = name_comp, .vmux = 3, .amux = LINE1, .gpio = 0x02, From 5d7802b2617d785ea0b8631b0605defc19ee6561 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:03:58 -0300 Subject: [PATCH 0753/2804] V4L/DVB (6226): dvb-pll: pass fe pointer into dvb_pll_configure() and set() functions The pll-specific set() function will need access to the dvb_pll_priv structure for new functionality. This patch gives access to this structure to the required functions. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 36 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 11f7d5939bd9..59ae4ece65ab 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -29,7 +29,8 @@ struct dvb_pll_desc { u32 min; u32 max; u32 iffreq; - void (*set)(u8 *buf, const struct dvb_frontend_parameters *params); + void (*set)(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params); u8 *initdata; u8 *sleepdata; int count; @@ -89,7 +90,7 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { }, }; -static void thomson_dtt759x_bw(u8 *buf, +static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) @@ -210,7 +211,8 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = { /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tda665x_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x08; @@ -243,7 +245,8 @@ static struct dvb_pll_desc dvb_pll_tda665x = { /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tua6034_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) buf[3] |= 0x08; @@ -283,7 +286,8 @@ static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { /* Philips FMD1216ME * used in Medion Hybrid PCMCIA card and USB Box */ -static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && params->frequency >= 158870000) @@ -313,7 +317,8 @@ static struct dvb_pll_desc dvb_pll_fmd1216me = { /* ALPS TDED4 * used in Nebula-Cards and USB boxes */ -static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tded4_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x04; @@ -354,7 +359,8 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = { /* Philips TUV1236D * used in ATI HDTV Wonder */ -static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params) +static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { switch (params->u.vsb.modulation) { case QAM_64: @@ -420,7 +426,8 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { /* * Philips TD1316 Tuner. */ -static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void td1316_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { u8 band; @@ -474,7 +481,8 @@ static struct dvb_pll_desc dvb_pll_thomson_fe6600 = { } }; -static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void opera1_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[2] |= 0x08; @@ -567,9 +575,11 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, +static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { + struct dvb_pll_priv *priv = fe->tuner_priv; + struct dvb_pll_desc *desc = priv->pll_desc; u32 div; int i; @@ -597,7 +607,7 @@ static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, buf[3] = desc->entries[i].cb; if (desc->set) - desc->set(buf, params); + desc->set(fe, buf, params); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", @@ -654,7 +664,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, if (priv->i2c == NULL) return -EINVAL; - if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0) + if ((result = dvb_pll_configure(fe, buf, params)) < 0) return result; else frequency = result; @@ -682,7 +692,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, if (buf_len < 5) return -EINVAL; - if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0) + if ((result = dvb_pll_configure(fe, buf+1, params)) < 0) return result; else frequency = result; From a27e5e769e46626052fc18ff63f274ee97142bab Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:11:15 -0300 Subject: [PATCH 0754/2804] V4L/DVB (6227): dvb-pll: store instance ID in dvb_pll_priv structure Store an instance ID in the dvb_pll_priv structure, so that module options specific to a given pll may be used by the functions within the driver. When debug is turned on, print a message indicating which pll was attached and it's instance id. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 59ae4ece65ab..5f4762edc405 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -556,6 +556,9 @@ static struct dvb_pll_desc *pll_list[] = { /* ----------------------------------------------------------- */ struct dvb_pll_priv { + /* pll number */ + int nr; + /* i2c details */ int pll_i2c_address; struct i2c_adapter *i2c; @@ -575,6 +578,8 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); +static unsigned int dvb_pll_devcount; + static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { @@ -787,6 +792,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, priv->pll_i2c_address = pll_addr; priv->i2c = i2c; priv->pll_desc = desc; + priv->nr = dvb_pll_devcount++; memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -801,6 +807,14 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->ops.tuner_ops.sleep = NULL; fe->tuner_priv = priv; + + if (debug) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": id# %d (%s) attached\n", pll_desc_id, desc->name); + } + return fe; } EXPORT_SYMBOL(dvb_pll_attach); From 05a4611b5d71ad6f968fdeef092c24914570898b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:19:57 -0300 Subject: [PATCH 0755/2804] V4L/DVB (6228): dvb-pll: add module option to specify rf input Add a module option to dvb-pll, called "input" to specify which rf input to use on devices with multiple rf inputs. If the module option is not specified, then the driver will autoselect the rf input, as per previous behavior. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 82 +++++++++++++++++---------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 5f4762edc405..7b133248b2bd 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -24,6 +24,36 @@ #include "dvb-pll.h" +struct dvb_pll_priv { + /* pll number */ + int nr; + + /* i2c details */ + int pll_i2c_address; + struct i2c_adapter *i2c; + + /* the PLL descriptor */ + struct dvb_pll_desc *pll_desc; + + /* cached frequency/bandwidth */ + u32 frequency; + u32 bandwidth; +}; + +#define DVB_PLL_MAX 16 + +static unsigned int dvb_pll_devcount; + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 }; +module_param_array(input, int, NULL, 0644); +MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)"); + +/* ----------------------------------------------------------- */ + struct dvb_pll_desc { char *name; u32 min; @@ -362,14 +392,32 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = { static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { - switch (params->u.vsb.modulation) { - case QAM_64: - case QAM_256: + struct dvb_pll_priv *priv = fe->tuner_priv; + unsigned int new_rf = input[priv->nr]; + + if ((new_rf == 0) || (new_rf > 2)) { + switch (params->u.vsb.modulation) { + case QAM_64: + case QAM_256: + new_rf = 1; + break; + case VSB_8: + default: + new_rf = 2; + } + } + + switch (new_rf) { + case 1: buf[3] |= 0x08; break; - case VSB_8: - default: + case 2: buf[3] &= ~0x08; + break; + default: + printk(KERN_WARNING + "%s: unhandled rf input selection: %d", + __FUNCTION__, new_rf); } } @@ -553,33 +601,9 @@ static struct dvb_pll_desc *pll_list[] = { [DVB_PLL_FCV1236D] = &dvb_pll_fcv1236d, }; -/* ----------------------------------------------------------- */ - -struct dvb_pll_priv { - /* pll number */ - int nr; - - /* i2c details */ - int pll_i2c_address; - struct i2c_adapter *i2c; - - /* the PLL descriptor */ - struct dvb_pll_desc *pll_desc; - - /* cached frequency/bandwidth */ - u32 frequency; - u32 bandwidth; -}; - /* ----------------------------------------------------------- */ /* code */ -static int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static unsigned int dvb_pll_devcount; - static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { From ff3e7dd5809fb632447f1aa6de6b3ffb755727dd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 13:00:45 -0300 Subject: [PATCH 0756/2804] V4L/DVB (6229): dvb-pll: increase DVB_PLL_MAX to 64 Increased DVB_PLL_MAX from 16 to a figure that would never be reached in a practical sense. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 7b133248b2bd..0fb4d453ae5b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -40,7 +40,7 @@ struct dvb_pll_priv { u32 bandwidth; }; -#define DVB_PLL_MAX 16 +#define DVB_PLL_MAX 64 static unsigned int dvb_pll_devcount; From 704e39bf620810734a38b3f9c0e07cede2a76d91 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:27:43 -0300 Subject: [PATCH 0757/2804] V4L/DVB (6230): dvb-pll: add module option to force dvb-pll desc id (for debug use only) Add a module option to force the dvb-pll module to use an alternate dvb-pll description without having to recompile the kernel. Having a module option like this is useful in some cases, where the vendor may release an alternate revision of the hardware using a different tuner, but without changing the pci subsystem / usb device ids. This option is intended for debugging purposes _only_. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 0fb4d453ae5b..64007032997c 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -52,6 +52,11 @@ static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 }; module_param_array(input, int, NULL, 0644); MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)"); +static unsigned int id[DVB_PLL_MAX] = + { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED }; +module_param_array(id, int, NULL, 0644); +MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)"); + /* ----------------------------------------------------------- */ struct dvb_pll_desc { @@ -794,6 +799,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, int ret; struct dvb_pll_desc *desc; + if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) && + (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list))) + pll_desc_id = id[dvb_pll_devcount]; + BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); desc = pll_list[pll_desc_id]; @@ -836,7 +845,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, printk("dvb-pll[%d]", priv->nr); if (i2c != NULL) printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); - printk(": id# %d (%s) attached\n", pll_desc_id, desc->name); + printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, + id[priv->nr] == pll_desc_id ? + "insmod option" : "autodetected"); + } return fe; From 8528fa414703f5be17092be2d3a2c5389755253a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 05:08:30 -0300 Subject: [PATCH 0758/2804] V4L/DVB (6231): dvb-pll: always show pll name if forced via insmod option The name of the pll will be shown if forced via insmod option, or if debug is enabled. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 64007032997c..27b2d54b6972 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -841,7 +841,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->tuner_priv = priv; - if (debug) { + if ((debug) || (id[priv->nr] == pll_desc_id)) { printk("dvb-pll[%d]", priv->nr); if (i2c != NULL) printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); From 4562fbeac61468f80a8d05e5ed50660bd97b4859 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 05:16:34 -0300 Subject: [PATCH 0759/2804] V4L/DVB (6232): dvb-pll: report whether input rf will be autoselected or set via insmod option Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 27b2d54b6972..8c8d7342d0b3 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -848,7 +848,20 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, id[priv->nr] == pll_desc_id ? "insmod option" : "autodetected"); - + } + if ((debug) || (input[priv->nr] > 0)) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": tuner rf input will be "); + switch (input[priv->nr]) { + case 0: + printk("autoselected\n"); + break; + default: + printk("set to input %d (insmod option)\n", + input[priv->nr]); + } } return fe; From 23869e236846657415654e8f5fbda9faec8d19e4 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 19 Sep 2007 02:44:18 -0300 Subject: [PATCH 0760/2804] V4L/DVB (6235): cafe_ccic: default to allocating DMA buffers at probe time By default, we allocate DMA buffers when actually reading from the video capture device. On a system with 128MB or 256MB of ram, it's very easy for that memory to quickly become fragmented. We've had users report having 30+MB of memory free, but the cafe_ccic driver is still unable to allocate DMA buffers. Our workaround has been to make use of the 'alloc_bufs_at_load' parameter to allocate DMA buffers during device probing. This patch makes DMA buffer allocation happen during device probe by default, and changes the parameter to 'alloc_bufs_at_read'. The camera hardware is there, if the cafe_ccic driver is enabled/loaded it should do its best to ensure that the camera is actually usable; delaying DMA buffer allocation saves an insignicant amount of memory, and causes the driver to be much less useful. Signed-off-by: Andres Salomon Acked-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 0fae0e000f1a..ccb37006bb18 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -62,13 +62,13 @@ MODULE_SUPPORTED_DEVICE("Video"); */ #define MAX_DMA_BUFS 3 -static int alloc_bufs_at_load = 0; -module_param(alloc_bufs_at_load, bool, 0444); -MODULE_PARM_DESC(alloc_bufs_at_load, - "Non-zero value causes DMA buffers to be allocated at module " - "load time. This increases the chances of successfully getting " - "those buffers, but at the cost of nailing down the memory from " - "the outset."); +static int alloc_bufs_at_read = 0; +module_param(alloc_bufs_at_read, bool, 0444); +MODULE_PARM_DESC(alloc_bufs_at_read, + "Non-zero value causes DMA buffers to be allocated when the " + "video capture device is read, rather than at module load " + "time. This saves memory, but decreases the chances of " + "successfully getting those buffers."); static int n_dma_bufs = 3; module_param(n_dma_bufs, uint, 0644); @@ -1502,7 +1502,7 @@ static int cafe_v4l_release(struct inode *inode, struct file *filp) } if (cam->users == 0) { cafe_ctlr_power_down(cam); - if (! alloc_bufs_at_load) + if (alloc_bufs_at_read) cafe_free_dma_bufs(cam); } mutex_unlock(&cam->s_mutex); @@ -2161,7 +2161,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, /* * If so requested, try to get our DMA buffers now. */ - if (alloc_bufs_at_load) { + if (!alloc_bufs_at_read) { if (cafe_alloc_dma_bufs(cam, 1)) cam_warn(cam, "Unable to alloc DMA buffers at load" " will try again later."); From 0b67f5c568c545cb36f88e9f418af2df1cc58589 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 26 Sep 2007 10:19:01 -0300 Subject: [PATCH 0761/2804] V4L/DVB (6237): Oops in pwc v4l driver The pwc driver is defficient in locking, which can trigger an oops when disconnecting. Signed-off-by: Oliver Neukum CC: Luc Saillard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pwc/pwc-if.c | 96 ++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 1088ebf5744f..0ff5718bf9b9 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -907,31 +907,49 @@ int pwc_isoc_init(struct pwc_device *pdev) return 0; } -void pwc_isoc_cleanup(struct pwc_device *pdev) +static void pwc_iso_stop(struct pwc_device *pdev) { int i; - PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); - if (pdev == NULL) - return; - if (pdev->iso_init == 0) - return; - /* Unlinking ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { struct urb *urb; urb = pdev->sbuf[i].urb; if (urb != 0) { - if (pdev->iso_init) { - PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); - usb_kill_urb(urb); - } + PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); + usb_kill_urb(urb); + } + } +} + +static void pwc_iso_free(struct pwc_device *pdev) +{ + int i; + + /* Freeing ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = pdev->sbuf[i].urb; + if (urb != 0) { PWC_DEBUG_MEMORY("Freeing URB\n"); usb_free_urb(urb); pdev->sbuf[i].urb = NULL; } } +} + +void pwc_isoc_cleanup(struct pwc_device *pdev) +{ + PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); + if (pdev == NULL) + return; + if (pdev->iso_init == 0) + return; + + pwc_iso_stop(pdev); + pwc_iso_free(pdev); /* Stop camera, but only if we are sure the camera is still there (unplug is signalled by EPIPE) @@ -1211,6 +1229,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); + lock_kernel(); pdev = (struct pwc_device *)vdev->priv; if (pdev->vopen == 0) PWC_DEBUG_MODULE("video_close() called on closed device?\n"); @@ -1230,7 +1249,6 @@ static int pwc_video_close(struct inode *inode, struct file *file) pwc_isoc_cleanup(pdev); pwc_free_buffers(pdev); - lock_kernel(); /* Turn off LEDS and power down camera, but only when not unplugged */ if (!pdev->unplugged) { /* Turn LEDs off */ @@ -1276,7 +1294,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, struct pwc_device *pdev; int noblock = file->f_flags & O_NONBLOCK; DECLARE_WAITQUEUE(wait, current); - int bytes_to_read; + int bytes_to_read, rv = 0; void *image_buffer_addr; PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n", @@ -1286,8 +1304,12 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, pdev = vdev->priv; if (pdev == NULL) return -EFAULT; - if (pdev->error_status) - return -pdev->error_status; /* Something happened, report what. */ + + mutex_lock(&pdev->modlock); + if (pdev->error_status) { + rv = -pdev->error_status; /* Something happened, report what. */ + goto err_out; + } /* In case we're doing partial reads, we don't have to wait for a frame */ if (pdev->image_read_pos == 0) { @@ -1298,17 +1320,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, if (pdev->error_status) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -pdev->error_status ; + rv = -pdev->error_status ; + goto err_out; } if (noblock) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -EWOULDBLOCK; + rv = -EWOULDBLOCK; + goto err_out; } if (signal_pending(current)) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -ERESTARTSYS; + rv = -ERESTARTSYS; + goto err_out; } schedule(); set_current_state(TASK_INTERRUPTIBLE); @@ -1317,8 +1342,10 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, set_current_state(TASK_RUNNING); /* Decompress and release frame */ - if (pwc_handle_frame(pdev)) - return -EFAULT; + if (pwc_handle_frame(pdev)) { + rv = -EFAULT; + goto err_out; + } } PWC_DEBUG_READ("Copying data to user space.\n"); @@ -1333,14 +1360,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, image_buffer_addr = pdev->image_data; image_buffer_addr += pdev->images[pdev->fill_image].offset; image_buffer_addr += pdev->image_read_pos; - if (copy_to_user(buf, image_buffer_addr, count)) - return -EFAULT; + if (copy_to_user(buf, image_buffer_addr, count)) { + rv = -EFAULT; + goto err_out; + } pdev->image_read_pos += count; if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ pdev->image_read_pos = 0; pwc_next_image(pdev); } + mutex_unlock(&pdev->modlock); return count; +err_out: + mutex_unlock(&pdev->modlock); + return rv; } static unsigned int pwc_video_poll(struct file *file, poll_table *wait) @@ -1366,7 +1399,20 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) static int pwc_video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + int r = -ENODEV; + + if (!vdev) + goto out; + pdev = vdev->priv; + + mutex_lock(&pdev->modlock); + if (!pdev->unplugged) + r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); + mutex_unlock(&pdev->modlock); +out: + return r; } static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) @@ -1809,7 +1855,10 @@ static void usb_pwc_disconnect(struct usb_interface *intf) wake_up_interruptible(&pdev->frameq); /* Wait until device is closed */ if(pdev->vopen) { + mutex_lock(&pdev->modlock); pdev->unplugged = 1; + mutex_unlock(&pdev->modlock); + pwc_iso_stop(pdev); } else { /* Device is closed, so we can safely unregister it */ PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); @@ -1827,7 +1876,6 @@ disconnect_out: unlock_kernel(); } - /* *grunt* We have to do atoi ourselves :-( */ static int pwc_atoi(const char *s) { From 9e19db5b6dda251b8d76c3a0069e63faca6be3f0 Mon Sep 17 00:00:00 2001 From: Brett Warden Date: Fri, 28 Sep 2007 03:19:04 -0300 Subject: [PATCH 0762/2804] V4L/DVB (6238): bw-qcam: use data_reverse instead of manually poking the control register Fixes use of parport_write_control() to match the newer interface that requires explicit parport_data_reverse() and parport_data_forward() calls. This eliminates the following error message and restores the original intended behavior: parport0 (bw-qcam): use data_reverse for this! Also increases threshold in qc_detect() from 300 to 400, as my camera often results in a count of approx 330. Added a kernel error message to indicate detection failure. Thanks Ray and Randy for your comments, and for pointing out that I needed to reset the port to forward mode! Signed-off-by: Brett T. Warden Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bw-qcam.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 7d47cbe6ad25..0edd05ebcc3f 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -104,6 +104,17 @@ static inline void write_lpdata(struct qcam_device *q, int d) static inline void write_lpcontrol(struct qcam_device *q, int d) { + if(0x20 & d) { + /* Set bidirectional mode to reverse (data in) */ + parport_data_reverse(q->pport); + } else { + /* Set bidirectional mode to forward (data out) */ + parport_data_forward(q->pport); + } + + /* Now issue the regular port command, but strip out the + * direction flag */ + d &= ~0x20; parport_write_control(q->pport, d); } @@ -344,10 +355,13 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ /* if (count > 30 && count < 200) */ - if (count > 20 && count < 300) + if (count > 20 && count < 400) + { return 1; /* found */ - else + } else { + printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); return 0; /* not found */ + } } From 0173e4696f201c53ab17ee4d9da81d74b5f9eddc Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 27 Sep 2007 11:37:19 -0300 Subject: [PATCH 0763/2804] V4L/DVB (6241): fix typo in DVB_PLL Kconfig help text s/driver/drives/1 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 53e775539649..59b9ed1f1aec 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -299,7 +299,7 @@ config DVB_PLL depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help - This module driver a number of tuners based on PLL chips with a + This module drives a number of tuners based on PLL chips with a common I2C interface. Say Y when you want to support these tuners. config DVB_TDA826X From 3e7589c50771aa0f6eaa8de799e599c016f4029c Mon Sep 17 00:00:00 2001 From: Pekka Seppanen Date: Sun, 30 Sep 2007 21:49:01 -0300 Subject: [PATCH 0764/2804] V4L/DVB (6243): [PATCH 2/2] GemTek Radio card Details now match with radio-gemtek.c, eg. no more different ports. Included a short note about cards that should be compatible with radio-gemtek module. Signed-off-by: Pekka Seppanen Signed-off-by: Douglas Schilling Landgraf Reviewed-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index f8bf9fe37d36..11e962f1a97f 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -111,11 +111,16 @@ config RADIO_AZTECH_PORT jumper sets the card to 0x358. config RADIO_GEMTEK - tristate "GemTek Radio Card support" + tristate "GemTek Radio card (or compatible) support" depends on ISA && VIDEO_V4L2 ---help--- Choose Y here if you have this FM radio card, and then fill in the - port address below. + I/O port address and settings below. The following cards either have + GemTek Radio tuner or are rebranded GemTek Radio cards: + + - Sound Vision 16 Gold with FM Radio + - Typhoon Radio card (some models) + - Hama Radio card In order to control your radio card, you will need to use programs that are compatible with the Video For Linux API. Information on @@ -126,14 +131,25 @@ config RADIO_GEMTEK module will be called radio-gemtek. config RADIO_GEMTEK_PORT - hex "GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)" + hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)" depends on RADIO_GEMTEK=y default "34c" help Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is 0x34c, if you haven't changed the jumper setting on the card. On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O - port is 0x28c. + port is 0x20c, 0x248 or 0x28c. + If automatic I/O port probing is enabled this port will be used only + in case of automatic probing failure, ie. as a fallback. + +config RADIO_GEMTEK_PROBE + bool "Automatic I/O port probing" + depends on RADIO_GEMTEK=y + default y + help + Say Y here to enable automatic probing for GemTek Radio card. The + following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and + 0x28c. config RADIO_GEMTEK_PCI tristate "GemTek PCI Radio Card support" From 4753647e6422341a091e729b9d81a9a5e7fe6179 Mon Sep 17 00:00:00 2001 From: Pekka Seppanen Date: Mon, 1 Oct 2007 00:27:55 -0300 Subject: [PATCH 0765/2804] V4L/DVB (6244): [PATCH 1/2] GemTek Radio card Code cleanup for GemTek Radio card driver. Removed unnecessary / invalid I/O commands and rewrote code for tuning on-board BU2614FS chip. Adds several new module params for power users. Includes automatic device probing. Signed-off-by: Pekka Seppanen Signed-off-by: Douglas Schilling Landgraf Reviewed-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 661 ++++++++++++++++++++--------- 1 file changed, 467 insertions(+), 194 deletions(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index eab8c80a2e47..f959bb71c460 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -26,143 +26,413 @@ #include #include -#include /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) +#include /* for KERNEL_VERSION MACRO */ +#define RADIO_VERSION KERNEL_VERSION(0,0,3) +#define RADIO_BANNER "GemTek Radio card driver: v0.0.3" -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; +/* + * Module info. + */ + +MODULE_AUTHOR("Jonas Munsin, Pekka Seppไnen "); +MODULE_DESCRIPTION("A driver for the GemTek Radio card."); +MODULE_LICENSE("GPL"); + +/* + * Module params. + */ #ifndef CONFIG_RADIO_GEMTEK_PORT #define CONFIG_RADIO_GEMTEK_PORT -1 #endif +#ifndef CONFIG_RADIO_GEMTEK_PROBE +#define CONFIG_RADIO_GEMTEK_PROBE 1 +#endif -static int io = CONFIG_RADIO_GEMTEK_PORT; -static int radio_nr = -1; -static spinlock_t lock; +static int io = CONFIG_RADIO_GEMTEK_PORT; +static int probe = CONFIG_RADIO_GEMTEK_PROBE; +static int hardmute; +static int shutdown = 1; +static int keepmuted = 1; +static int initmute = 1; +static int radio_nr = -1; -struct gemtek_device -{ - int port; - unsigned long curfreq; +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic" + "probing is disabled or fails. The most common I/O ports are: 0x20c " + "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " + " work for the combined sound/radiocard)."); + +module_param(probe, bool, 0444); +MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " + "common I/O ports used by the card are probed."); + +module_param(hardmute, bool, 0644); +MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may " + "reduce static noise."); + +module_param(shutdown, bool, 0644); +MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when " + "module is unloaded."); + +module_param(keepmuted, bool, 0644); +MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed."); + +module_param(initmute, bool, 0444); +MODULE_PARM_DESC(initmute, "Mute card when module is loaded."); + +module_param(radio_nr, int, 0444); + +/* + * Functions for controlling the card. + */ +#define GEMTEK_LOWFREQ (87*16000) +#define GEMTEK_HIGHFREQ (108*16000) + +#define GEMTEK_CK 0x01 /* Clock signal */ +#define GEMTEK_DA 0x02 /* Serial data */ +#define GEMTEK_CE 0x04 /* Chip enable */ +#define GEMTEK_NS 0x08 /* No signal */ +#define GEMTEK_MT 0x10 /* Line mute */ +#define GEMTEK_STDF_3_125_KHZ 0x01 /* Standard frequency 3.125 kHz */ +#define GEMTEK_PLL_OFF 0x07 /* PLL off */ + +#define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */ +#define BU2614_NOPS 8 /* Number of supported operations */ + +#define SHORT_DELAY 5 /* usec */ +#define LONG_DELAY 75 /* usec */ + +struct gemtek_device { + unsigned long lastfreq; int muted; + unsigned long bu2614data[BU2614_NOPS]; }; +enum { + BU2614_VOID, + BU2614_FREQ, /* D0..D15, Frequency data */ + BU2614_PORT, /* P0..P2, Output port control data */ + BU2614_FMES, /* CT, Frequency measurement beginning data */ + BU2614_STDF, /* R0..R2, Standard frequency data */ + BU2614_SWIN, /* S, Switch between FMIN / AMIN */ + BU2614_SWAL, /* PS, Swallow counter division (AMIN only) */ + BU2614_FMUN, /* GT, Frequency measurement time and unlock */ + BU2614_TEST /* TS, Test data is input */ +}; -/* local things */ +struct bu2614_op { + int op; /* Operation */ + int size; /* Data size */ +}; -/* the correct way to mute the gemtek may be to write the last written - * frequency || 0x10, but just writing 0x10 once seems to do it as well +static struct gemtek_device gemtek_unit; + +static struct bu2614_op bu2614ops[] = { + {.op = BU2614_FREQ, + .size = 0x10}, + {.op = BU2614_PORT, + .size = 0x03}, + {.op = BU2614_VOID, + .size = 0x04}, + {.op = BU2614_FMES, + .size = 0x01}, + {.op = BU2614_STDF, + .size = 0x03}, + {.op = BU2614_SWIN, + .size = 0x01}, + {.op = BU2614_SWAL, + .size = 0x01}, + {.op = BU2614_VOID, + .size = 0x01}, + {.op = BU2614_FMUN, + .size = 0x01}, + {.op = BU2614_TEST, + .size = 0x01} +}; + +static spinlock_t lock; + +/* + * Set data which will be sent to BU2614FS. + */ +static void gemtek_bu2614_set(struct gemtek_device *dev, int op, + unsigned long data) +{ + int i, q; + + for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { + if (bu2614ops[i].op == op) { + dev->bu2614data[q] = + data & ((1 << bu2614ops[i].size) - 1); + return; + } + + if (bu2614ops[i].op != BU2614_VOID) + ++q; + } +} + +/* + * Transmit settings to BU2614FS over GemTek IC. + */ +static void gemtek_bu2614_transmit(struct gemtek_device *dev) +{ + int i, bit, q, mute; + + spin_lock(&lock); + + mute = dev->muted ? GEMTEK_MT : 0x00; + + outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); + udelay(LONG_DELAY); + + for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { + for (bit = 0; bit < bu2614ops[i].size; ++bit) { + if (bu2614ops[i].op != BU2614_VOID && + dev->bu2614data[q] & (1 << bit)) { + outb_p(mute | GEMTEK_CE | GEMTEK_DA, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | + GEMTEK_CK, io); + udelay(SHORT_DELAY); + } else { + outb_p(mute | GEMTEK_CE, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_CK, io); + udelay(SHORT_DELAY); + } + } + + if (bu2614ops[i].op != BU2614_VOID) + ++q; + } + + outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); + udelay(LONG_DELAY); + + spin_unlock(&lock); +} + +/* + * Convert FM-frequency for BU2614FS (3.125 KHz STDF expected). + */ +static inline void gemtek_convfreq(unsigned long *freq) +{ + (*freq) /= 160; + (*freq) += 1052; /* FMIN, 10.52 MHz */ + (*freq) *= 1565; /* STDF, 1 / 156.5 = 0.00639 */ + (*freq) /= 1000; +} + +/* + * Set FM-frequency. + */ +static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) +{ + + if (keepmuted && hardmute && dev->muted) + return; + + if (freq < GEMTEK_LOWFREQ) + freq = GEMTEK_LOWFREQ; + else if (freq > GEMTEK_HIGHFREQ) + freq = GEMTEK_HIGHFREQ; + + dev->lastfreq = freq; + dev->muted = 0; + + gemtek_bu2614_set(dev, BU2614_PORT, 0); + gemtek_bu2614_set(dev, BU2614_FMES, 0); + gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(dev, BU2614_SWAL, 0); + gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */ + gemtek_bu2614_set(dev, BU2614_TEST, 0); + + gemtek_convfreq(&freq); + + gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); + gemtek_bu2614_set(dev, BU2614_FREQ, freq); + + gemtek_bu2614_transmit(dev); +} + +/* + * Set mute flag. */ static void gemtek_mute(struct gemtek_device *dev) { - if(dev->muted) - return; - spin_lock(&lock); - outb(0x10, io); - spin_unlock(&lock); + int i; dev->muted = 1; + + if (hardmute) { + /* Turn off PLL, disable data output */ + gemtek_bu2614_set(dev, BU2614_PORT, 0); + gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off */ + gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(dev, BU2614_SWAL, 0); + gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off */ + gemtek_bu2614_set(dev, BU2614_TEST, 0); + gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF); + gemtek_bu2614_set(dev, BU2614_FREQ, 0); + gemtek_bu2614_transmit(dev); + } else { + spin_lock(&lock); + + /* Read bus contents (CE, CK and DA). */ + i = inb_p(io); + /* Write it back with mute flag set. */ + outb_p((i >> 5) | GEMTEK_MT, io); + udelay(SHORT_DELAY); + + spin_unlock(&lock); + } } +/* + * Unset mute flag. + */ static void gemtek_unmute(struct gemtek_device *dev) { - if(dev->muted == 0) - return; - spin_lock(&lock); - outb(0x20, io); - spin_unlock(&lock); + int i; dev->muted = 0; + + if (hardmute) { + /* Turn PLL back on. */ + gemtek_setfreq(dev, dev->lastfreq); + } else { + spin_lock(&lock); + + i = inb_p(io); + outb_p(i >> 5, io); + udelay(SHORT_DELAY); + + spin_unlock(&lock); + } } -static void zero(void) +/* + * Get signal strength (= stereo status). + */ +static inline int gemtek_getsigstr(void) { - outb_p(0x04, io); - udelay(5); - outb_p(0x05, io); - udelay(5); + return inb_p(io) & GEMTEK_NS ? 0 : 1; } -static void one(void) +/* + * Check if requested card acts like GemTek Radio card. + */ +static int gemtek_verify(int port) { - outb_p(0x06, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + static int verified = -1; + int i, q; + + if (verified == port) + return 1; + + spin_lock(&lock); + + q = inb_p(port); /* Read bus contents before probing. */ + /* Try to turn on CE, CK and DA respectively and check if card responds + properly. */ + for (i = 0; i < 3; ++i) { + outb_p(1 << i, port); + udelay(SHORT_DELAY); + + if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { + spin_unlock(&lock); + return 0; + } + } + outb_p(q >> 5, port); /* Write bus contents back. */ + udelay(SHORT_DELAY); + + spin_unlock(&lock); + verified = port; + + return 1; } -static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) +/* + * Automatic probing for card. + */ +static int gemtek_probe(void) { + int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; int i; -/* freq = 78.25*((float)freq/16000.0 + 10.52); */ + if (!probe) { + printk(KERN_INFO "Automatic device probing disabled.\n"); + return -1; + } - freq /= 16; - freq += 10520; - freq *= 7825; - freq /= 100000; + printk(KERN_INFO "Automatic device probing enabled.\n"); - spin_lock(&lock); + for (i = 0; i < ARRAY_SIZE(ioports); ++i) { + printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]); - /* 2 start bits */ - outb_p(0x03, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + if (!request_region(ioports[i], 1, "gemtek-probe")) { + printk(KERN_WARNING "I/O port 0x%x busy!\n", + ioports[i]); + continue; + } - /* 28 frequency bits (lsb first) */ - for (i = 0; i < 14; i++) - if (freq & (1 << i)) - one(); - else - zero(); - /* 36 unknown bits */ - for (i = 0; i < 11; i++) - zero(); - one(); - for (i = 0; i < 4; i++) - zero(); - one(); - zero(); + if (gemtek_verify(ioports[i])) { + printk(KERN_INFO "Card found from I/O port " + "0x%x!\n", ioports[i]); - /* 2 end bits */ - outb_p(0x03, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + release_region(ioports[i], 1); - spin_unlock(&lock); + io = ioports[i]; + return io; + } - return 0; + release_region(ioports[i], 1); + } + + printk(KERN_ERR "Automatic probing failed!\n"); + + return -1; } -static int gemtek_getsigstr(struct gemtek_device *dev) -{ - spin_lock(&lock); - inb(io); - udelay(5); - spin_unlock(&lock); - if (inb(io) & 8) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} +/* + * Video 4 Linux stuff. + */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) +static struct v4l2_queryctrl radio_qctrl[] = { + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535, + .default_value = 0xff, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; + +static struct file_operations gemtek_fops = { + .owner = THIS_MODULE, + .open = video_exclusive_open, + .release = video_exclusive_release, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) { strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); strlcpy(v->card, "GemTek", sizeof(v->card)); @@ -172,28 +442,29 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; - if (v->index > 0) return -EINVAL; strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; - v->rangelow = (87*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff*gemtek_getsigstr(rt); + v->rangelow = GEMTEK_LOWFREQ; + v->rangehigh = GEMTEK_HIGHFREQ; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + v->signal = 0xffff * gemtek_getsigstr(); + if (v->signal) { + v->audmode = V4L2_TUNER_MODE_STEREO; + v->rxsubchans = V4L2_TUNER_SUB_STEREO; + } else { + v->audmode = V4L2_TUNER_MODE_MONO; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + } + return 0; } -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { if (v->index > 0) return -EINVAL; @@ -201,38 +472,35 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; - rt->curfreq = f->frequency; - /* needs to be called twice in order for getsigstr to work */ - gemtek_setfreq(rt, rt->curfreq); - gemtek_setfreq(rt, rt->curfreq); + gemtek_setfreq(rt, f->frequency); + return 0; } static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; f->type = V4L2_TUNER_RADIO; - f->frequency = rt->curfreq; + f->frequency = rt->lastfreq; return 0; } static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) + struct v4l2_queryctrl *qc) { int i; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) { if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); return 0; } } @@ -240,7 +508,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, } static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) + struct v4l2_control *ctrl) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; @@ -260,7 +528,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, } static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) + struct v4l2_control *ctrl) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; @@ -282,8 +550,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_audio (struct file *file, void *priv, - struct v4l2_audio *a) +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { if (a->index > 1) return -EINVAL; @@ -306,99 +573,105 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { if (a->index != 0) return -EINVAL; return 0; } -static struct gemtek_device gemtek_unit; - -static const struct file_operations gemtek_fops = { - .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, +static struct video_device gemtek_radio = { + .owner = THIS_MODULE, + .name = "GemTek Radio card", + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_GEMTEK, + .fops = &gemtek_fops, + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl }; -static struct video_device gemtek_radio= -{ - .owner = THIS_MODULE, - .name = "GemTek radio", - .type = VID_TYPE_TUNER, - .fops = &gemtek_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; +/* + * Initialization / cleanup related stuff. + */ +/* + * Initilize card. + */ static int __init gemtek_init(void) { - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n"); - return -EINVAL; - } + int i; - if (!request_region(io, 4, "gemtek")) - { - printk(KERN_ERR "gemtek: port 0x%x already in use\n", io); - return -EBUSY; - } - - gemtek_radio.priv=&gemtek_unit; - - if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { - release_region(io, 4); - return -EINVAL; - } - printk(KERN_INFO "GemTek Radio Card driver.\n"); + printk(KERN_INFO RADIO_BANNER "\n"); spin_lock_init(&lock); - /* this is _maybe_ unnecessary */ - outb(0x01, io); + gemtek_probe(); + if (io) { + if (!request_region(io, 1, "gemtek")) { + printk(KERN_ERR "I/O port 0x%x already in use.\n", io); + return -EBUSY; + } - /* mute card - prevents noisy bootups */ - gemtek_unit.muted = 0; - gemtek_mute(&gemtek_unit); + if (!gemtek_verify(io)) + printk(KERN_WARNING "Card at I/O port 0x%x does not " + "respond properly, check your " + "configuration.\n", io); + else + printk(KERN_INFO "Using I/O port 0x%x.\n", io); + } else if (probe) { + printk(KERN_ERR "Automatic probing failed and no " + "fixed I/O port defined.\n"); + return -ENODEV; + } else { + printk(KERN_ERR "Automatic probing disabled but no fixed " + "I/O port defined."); + return -EINVAL; + } + + gemtek_radio.priv = &gemtek_unit; + + if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, + radio_nr) == -1) { + release_region(io, 1); + return -EBUSY; + } + + /* Set defaults */ + gemtek_unit.lastfreq = GEMTEK_LOWFREQ; + for (i = 0; i < ARRAY_SIZE(gemtek_unit.bu2614data); ++i) + gemtek_unit.bu2614data[i] = 0; + + if (initmute) + gemtek_mute(&gemtek_unit); return 0; } -MODULE_AUTHOR("Jonas Munsin"); -MODULE_DESCRIPTION("A driver for the GemTek Radio Card"); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard))."); -module_param(radio_nr, int, 0); - -static void __exit gemtek_cleanup(void) +/* + * Module cleanup + */ +static void __exit gemtek_exit(void) { + if (shutdown) { + hardmute = 1; /* Turn off PLL */ + gemtek_mute(&gemtek_unit); + } else { + printk(KERN_INFO "Module unloaded but card not muted!\n"); + } + video_unregister_device(&gemtek_radio); - release_region(io,4); + release_region(io, 1); } module_init(gemtek_init); -module_exit(gemtek_cleanup); - -/* - Local variables: - compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c" - End: -*/ +module_exit(gemtek_exit); From 857e594ad5662349d95ad33f987cbf55cc356a90 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 1 Oct 2007 00:32:25 -0300 Subject: [PATCH 0766/2804] V4L/DVB (6245): GemTek Radio card - frequency calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frequency calculation to use better math. It's still the same IF offset and step size (which are not the same as the datasheet says) as the code was before. It's just more efficient and accurate. Signed-off-by: Trent Piepho Reviewed-by: Pekka Seppรคnen Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index f959bb71c460..0fcd2b09218d 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -89,6 +89,14 @@ module_param(radio_nr, int, 0444); #define GEMTEK_LOWFREQ (87*16000) #define GEMTEK_HIGHFREQ (108*16000) +/* + * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal + * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz). + */ +#define FSCALE 8 +#define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1< Date: Mon, 1 Oct 2007 00:38:30 -0300 Subject: [PATCH 0767/2804] V4L/DVB (6246): GemTek Radio card - Control Word MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Redoes the way the control word is stored and set. The existing code was a lot more complicated than it needed to be. Signed-off-by: Trent Piepho Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Pekka Seppรคnen --- drivers/media/radio/radio-gemtek.c | 122 ++++++++++------------------- 1 file changed, 43 insertions(+), 79 deletions(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 0fcd2b09218d..0c963db03614 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -106,7 +106,6 @@ module_param(radio_nr, int, 0444); #define GEMTEK_PLL_OFF 0x07 /* PLL off */ #define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */ -#define BU2614_NOPS 8 /* Number of supported operations */ #define SHORT_DELAY 5 /* usec */ #define LONG_DELAY 75 /* usec */ @@ -114,72 +113,53 @@ module_param(radio_nr, int, 0444); struct gemtek_device { unsigned long lastfreq; int muted; - unsigned long bu2614data[BU2614_NOPS]; + u32 bu2614data; }; -enum { - BU2614_VOID, - BU2614_FREQ, /* D0..D15, Frequency data */ - BU2614_PORT, /* P0..P2, Output port control data */ - BU2614_FMES, /* CT, Frequency measurement beginning data */ - BU2614_STDF, /* R0..R2, Standard frequency data */ - BU2614_SWIN, /* S, Switch between FMIN / AMIN */ - BU2614_SWAL, /* PS, Swallow counter division (AMIN only) */ - BU2614_FMUN, /* GT, Frequency measurement time and unlock */ - BU2614_TEST /* TS, Test data is input */ -}; +#define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ +#define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ +#define BU2614_VOID_BITS 4 /* unused */ +#define BU2614_FMES_BITS 1 /* CT, Frequency measurement beginning data */ +#define BU2614_STDF_BITS 3 /* R0..R2, Standard frequency data */ +#define BU2614_SWIN_BITS 1 /* S, Switch between FMIN / AMIN */ +#define BU2614_SWAL_BITS 1 /* PS, Swallow counter division (AMIN only)*/ +#define BU2614_VOID2_BITS 1 /* unused */ +#define BU2614_FMUN_BITS 1 /* GT, Frequency measurement time & unlock */ +#define BU2614_TEST_BITS 1 /* TS, Test data is input */ -struct bu2614_op { - int op; /* Operation */ - int size; /* Data size */ -}; +#define BU2614_FREQ_SHIFT 0 +#define BU2614_PORT_SHIFT (BU2614_FREQ_BITS + BU2614_FREQ_SHIFT) +#define BU2614_VOID_SHIFT (BU2614_PORT_BITS + BU2614_PORT_SHIFT) +#define BU2614_FMES_SHIFT (BU2614_VOID_BITS + BU2614_VOID_SHIFT) +#define BU2614_STDF_SHIFT (BU2614_FMES_BITS + BU2614_FMES_SHIFT) +#define BU2614_SWIN_SHIFT (BU2614_STDF_BITS + BU2614_STDF_SHIFT) +#define BU2614_SWAL_SHIFT (BU2614_SWIN_BITS + BU2614_SWIN_SHIFT) +#define BU2614_VOID2_SHIFT (BU2614_SWAL_BITS + BU2614_SWAL_SHIFT) +#define BU2614_FMUN_SHIFT (BU2614_VOID2_BITS + BU2614_VOID2_SHIFT) +#define BU2614_TEST_SHIFT (BU2614_FMUN_BITS + BU2614_FMUN_SHIFT) + +#define MKMASK(field) (((1<bu2614data); ++i) { - if (bu2614ops[i].op == op) { - dev->bu2614data[q] = - data & ((1 << bu2614ops[i].size) - 1); - return; - } - - if (bu2614ops[i].op != BU2614_VOID) - ++q; - } -} +#define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \ + ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT)) /* * Transmit settings to BU2614FS over GemTek IC. @@ -197,25 +177,12 @@ static void gemtek_bu2614_transmit(struct gemtek_device *dev) outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); udelay(LONG_DELAY); - for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { - for (bit = 0; bit < bu2614ops[i].size; ++bit) { - if (bu2614ops[i].op != BU2614_VOID && - dev->bu2614data[q] & (1 << bit)) { - outb_p(mute | GEMTEK_CE | GEMTEK_DA, io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_DA | - GEMTEK_CK, io); - udelay(SHORT_DELAY); - } else { - outb_p(mute | GEMTEK_CE, io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_CK, io); - udelay(SHORT_DELAY); - } - } - - if (bu2614ops[i].op != BU2614_VOID) - ++q; + for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) { + bit = (q & 1) ? GEMTEK_DA : 0; + outb_p(mute | GEMTEK_CE | bit, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io); + udelay(SHORT_DELAY); } outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); @@ -612,8 +579,6 @@ static struct video_device gemtek_radio = { */ static int __init gemtek_init(void) { - int i; - printk(KERN_INFO RADIO_BANNER "\n"); spin_lock_init(&lock); @@ -651,8 +616,7 @@ static int __init gemtek_init(void) /* Set defaults */ gemtek_unit.lastfreq = GEMTEK_LOWFREQ; - for (i = 0; i < ARRAY_SIZE(gemtek_unit.bu2614data); ++i) - gemtek_unit.bu2614data[i] = 0; + gemtek_unit.bu2614data = 0; if (initmute) gemtek_mute(&gemtek_unit); From 13595a51c0da8ec212ba6f5df79519dbd74166c0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 1 Oct 2007 08:51:39 -0300 Subject: [PATCH 0768/2804] V4L/DVB (6247): Fix bug #8689: Fixes IR stop/start during suspend/resume IR workqueue should be disabled during suspend. This avoids some troubles, like the one reported on bug #8689: "The Hauppauge HVR 1100 ir-remote control does not work after resume from suspend to ram or disk." This patch disables IR before suspending, re-enabling it after resume. Thanks to Peter Poklop for reporting it and helping with the fix. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Peter Poklop --- drivers/media/video/cx88/cx88-core.c | 3 +++ drivers/media/video/cx88/cx88-input.c | 4 ++-- drivers/media/video/cx88/cx88-video.c | 6 ++++++ drivers/media/video/cx88/cx88.h | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 41f7f374c183..716154828ff0 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1084,6 +1084,9 @@ EXPORT_SYMBOL(cx88_vdev_init); EXPORT_SYMBOL(cx88_core_get); EXPORT_SYMBOL(cx88_core_put); +EXPORT_SYMBOL(cx88_ir_start); +EXPORT_SYMBOL(cx88_ir_stop); + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 78adf4d1cf63..e52de3968c63 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -158,7 +158,7 @@ static void cx88_ir_work(struct work_struct *work) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } -static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) +void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { setup_timer(&ir->timer, ir_timer, (unsigned long)ir); @@ -172,7 +172,7 @@ static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) } } -static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) +void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) { if (ir->sampling) { cx_write(MO_DDSCFG_IO, 0x0); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index f94a3b41782a..705c29b002ea 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1954,6 +1954,8 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) } spin_unlock(&dev->slock); + if (core->ir) + cx88_ir_stop(core, core->ir); /* FIXME -- shutdown device */ cx88_shutdown(core); @@ -1993,6 +1995,10 @@ static int cx8800_resume(struct pci_dev *pci_dev) /* FIXME: re-initialize hardware */ cx88_reset(core); + if (core->ir) + cx88_ir_start(core, core->ir); + + cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* restart video+vbi capture */ spin_lock(&dev->slock); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index e436a37b4404..0e4f8e278671 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -614,6 +614,8 @@ struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); int cx88_ir_fini(struct cx88_core *core); void cx88_ir_irq(struct cx88_core *core); +void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir); +void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir); /* ----------------------------------------------------------- */ /* cx88-mpeg.c */ From b5457b7bdf284d683880163a4c59fdde2f84325a Mon Sep 17 00:00:00 2001 From: Sascha Sommer Date: Tue, 2 Oct 2007 12:23:39 -0300 Subject: [PATCH 0769/2804] V4L/DVB (6249): Add Typhoon Tv-Tuner PCI to bttv-cards.c Adds an entry for the Typhoon Tv-Tuner PCI to bttv-cards.c Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.bttv | 1 + drivers/media/video/bt8xx/bttv-cards.c | 17 +++++++++++++++++ drivers/media/video/bt8xx/bttv.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv index 177159c5f4c4..d97cf7cc6088 100644 --- a/Documentation/video4linux/CARDLIST.bttv +++ b/Documentation/video4linux/CARDLIST.bttv @@ -147,3 +147,4 @@ 146 -> SSAI Ultrasound Video Interface [414a:5353] 147 -> VoodooTV 200 (USA) [121a:3000] 148 -> DViCO FusionHDTV 2 [dbc0:d200] +149 -> Typhoon TV-Tuner PCI (50684) diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 900d18e14060..dd6a7d68b07f 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -2988,6 +2988,23 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .no_tda7432 = 1, }, + /* ---- card 0x95---------------------------------- */ + [BTTV_BOARD_TYPHOON_TVTUNERPCI] = { + .name = "Typhoon TV-Tuner PCI (50684)", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x3014f, + .muxsel = { 2, 3, 1, 1 }, + .gpiomux = { 0x20001,0x10001, 0, 0 }, + .gpiomute = 10, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index dcc847dc2486..19e75d50a107 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -172,6 +172,8 @@ #define BTTV_BOARD_SSAI_ULTRASOUND 0x92 #define BTTV_BOARD_VOODOOTV_200 0x93 #define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 +#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 + /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 From 7c596fa964806acb3b5ababb7ec4e1da35b140b3 Mon Sep 17 00:00:00 2001 From: Brett Warden Date: Tue, 2 Oct 2007 17:37:21 -0300 Subject: [PATCH 0770/2804] V4L/DVB (6250): bw-qcam use data_reverse instead of manually poking the control register fix coding-style repairs Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bw-qcam.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 0edd05ebcc3f..7f7e3d3398d0 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -104,7 +104,7 @@ static inline void write_lpdata(struct qcam_device *q, int d) static inline void write_lpcontrol(struct qcam_device *q, int d) { - if(0x20 & d) { + if (d & 0x20) { /* Set bidirectional mode to reverse (data in) */ parport_data_reverse(q->pport); } else { @@ -355,11 +355,11 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ /* if (count > 30 && count < 200) */ - if (count > 20 && count < 400) - { + if (count > 20 && count < 400) { return 1; /* found */ } else { - printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); + printk(KERN_ERR "No Quickcam found on port %s\n", + q->pport->name); return 0; /* not found */ } } From 7a7d9a89d0307b1743d782197e2c5fc5ddf183f3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:26:14 -0300 Subject: [PATCH 0771/2804] V4L/DVB (6251): Replace video-buf to a more generic approach video-buf currently does two different tasks: - Manages video buffers with a common code that allows implementing all the V4L2 different modes of buffering; - Controls memory allocations While the first task is generic, the second were written to support PCI DMA Scatter/Gather needs. The original approach can't even work for those video capture hardware that don't support scatter/gather. I did one approach to make it more generic. While the approach worked fine for vivi driver, it were not generic enough to handle USB needs. This patch creates two different modules, one containing the generic video buffer handling (videobuf-core) and another with PCI DMA S/G. After this patch, it would be simpler to write an USB video-buf and a non-SG DMA module. Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 976 ++++++++++++++++++++++++++ drivers/media/video/videobuf-dma-sg.c | 772 ++++++++++++++++++++ include/media/videobuf-core.h | 236 +++++++ include/media/videobuf-dma-sg.h | 142 ++++ 4 files changed, 2126 insertions(+) create mode 100644 drivers/media/video/videobuf-core.c create mode 100644 drivers/media/video/videobuf-dma-sg.c create mode 100644 include/media/videobuf-core.h create mode 100644 include/media/videobuf-dma-sg.h diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c new file mode 100644 index 000000000000..256501384af7 --- /dev/null +++ b/drivers/media/video/videobuf-core.c @@ -0,0 +1,976 @@ +/* + * generic helper functions for handling video4linux capture buffers + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_BUFFER 0x20070728 +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf: " fmt , ## arg) + +/* --------------------------------------------------------------------- */ + +#define CALL(q, f, arg...) \ + ( (q->int_ops->f)? q->int_ops->f(arg) : 0) + +void* videobuf_alloc(struct videobuf_queue* q) +{ + struct videobuf_buffer *vb; + + BUG_ON (q->msizeint_ops || !q->int_ops->alloc) { + printk(KERN_ERR "No specific ops defined!\n"); + BUG(); + } + + vb = q->int_ops->alloc(q->msize); + + if (NULL != vb) { + init_waitqueue_head(&vb->done); + vb->magic = MAGIC_BUFFER; + } + + return vb; +} + +int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) +{ + int retval = 0; + DECLARE_WAITQUEUE(wait, current); + + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + add_wait_queue(&vb->done, &wait); + while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { + if (non_blocking) { + retval = -EAGAIN; + break; + } + set_current_state(intr ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE); + if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) + schedule(); + set_current_state(TASK_RUNNING); + if (intr && signal_pending(current)) { + dprintk(1,"buffer waiton: -EINTR\n"); + retval = -EINTR; + break; + } + } + remove_wait_queue(&vb->done, &wait); + return retval; +} + +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + return CALL(q,iolock,q,vb,fbuf); +} + +/* --------------------------------------------------------------------- */ + + +void videobuf_queue_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + memset(q,0,sizeof(*q)); + q->irqlock = irqlock; + q->dev = dev; + q->type = type; + q->field = field; + q->msize = msize; + q->ops = ops; + q->priv_data = priv; + + /* All buffer operations are mandatory */ + BUG_ON (!q->ops->buf_setup); + BUG_ON (!q->ops->buf_prepare); + BUG_ON (!q->ops->buf_queue); + BUG_ON (!q->ops->buf_release); + + mutex_init(&q->lock); + INIT_LIST_HEAD(&q->stream); +} + +int videobuf_queue_is_busy(struct videobuf_queue *q) +{ + int i; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + if (q->streaming) { + dprintk(1,"busy: streaming active\n"); + return 1; + } + if (q->reading) { + dprintk(1,"busy: pending read #1\n"); + return 1; + } + if (q->read_buf) { + dprintk(1,"busy: pending read #2\n"); + return 1; + } + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (CALL(q,is_mmapped,q->bufs[i])) { + dprintk(1,"busy: buffer #%d mapped\n",i); + return 1; + } + if (q->bufs[i]->state == STATE_QUEUED) { + dprintk(1,"busy: buffer #%d queued\n",i); + return 1; + } + if (q->bufs[i]->state == STATE_ACTIVE) { + dprintk(1,"busy: buffer #%d avtive\n",i); + return 1; + } + } + return 0; +} + +void videobuf_queue_cancel(struct videobuf_queue *q) +{ + unsigned long flags=0; + int i; + + /* remove queued buffers from list */ + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (q->bufs[i]->state == STATE_QUEUED) { + list_del(&q->bufs[i]->queue); + q->bufs[i]->state = STATE_ERROR; + } + } + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + + /* free all buffers + clear queue */ + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + } + INIT_LIST_HEAD(&q->stream); +} + +/* --------------------------------------------------------------------- */ + +enum v4l2_field videobuf_next_field(struct videobuf_queue *q) +{ + enum v4l2_field field = q->field; + + BUG_ON(V4L2_FIELD_ANY == field); + + if (V4L2_FIELD_ALTERNATE == field) { + if (V4L2_FIELD_TOP == q->last) { + field = V4L2_FIELD_BOTTOM; + q->last = V4L2_FIELD_BOTTOM; + } else { + field = V4L2_FIELD_TOP; + q->last = V4L2_FIELD_TOP; + } + } + return field; +} + +static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, + struct videobuf_buffer *vb, enum v4l2_buf_type type) +{ + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + b->index = vb->i; + b->type = type; + + b->memory = vb->memory; + switch (b->memory) { + case V4L2_MEMORY_MMAP: + b->m.offset = vb->boff; + b->length = vb->bsize; + break; + case V4L2_MEMORY_USERPTR: + b->m.userptr = vb->baddr; + b->length = vb->bsize; + break; + case V4L2_MEMORY_OVERLAY: + b->m.offset = vb->boff; + break; + } + + b->flags = 0; + if (CALL(q,is_mmapped,vb)) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + switch (vb->state) { + case STATE_PREPARED: + case STATE_QUEUED: + case STATE_ACTIVE: + b->flags |= V4L2_BUF_FLAG_QUEUED; + break; + case STATE_DONE: + case STATE_ERROR: + b->flags |= V4L2_BUF_FLAG_DONE; + break; + case STATE_NEEDS_INIT: + case STATE_IDLE: + /* nothing */ + break; + } + + if (vb->input != UNSET) { + b->flags |= V4L2_BUF_FLAG_INPUT; + b->input = vb->input; + } + + b->field = vb->field; + b->timestamp = vb->ts; + b->bytesused = vb->size; + b->sequence = vb->field_count >> 1; +} + +int videobuf_reqbufs(struct videobuf_queue *q, + struct v4l2_requestbuffers *req) +{ + unsigned int size,count; + int retval; + + if (req->type != q->type) { + dprintk(1,"reqbufs: queue type invalid\n"); + return -EINVAL; + } + if (req->count < 1) { + dprintk(1,"reqbufs: count invalid (%d)\n",req->count); + return -EINVAL; + } + if (req->memory != V4L2_MEMORY_MMAP && + req->memory != V4L2_MEMORY_USERPTR && + req->memory != V4L2_MEMORY_OVERLAY) { + dprintk(1,"reqbufs: memory type invalid\n"); + return -EINVAL; + } + + if (q->streaming) { + dprintk(1,"reqbufs: streaming already exists\n"); + return -EBUSY; + } + if (!list_empty(&q->stream)) { + dprintk(1,"reqbufs: stream running\n"); + return -EBUSY; + } + + mutex_lock(&q->lock); + count = req->count; + if (count > VIDEO_MAX_FRAME) + count = VIDEO_MAX_FRAME; + size = 0; + q->ops->buf_setup(q,&count,&size); + size = PAGE_ALIGN(size); + dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", + count, size, (count*size)>>PAGE_SHIFT); + + retval = videobuf_mmap_setup(q,count,size,req->memory); + if (retval < 0) { + dprintk(1,"reqbufs: mmap setup returned %d\n",retval); + goto done; + } + + req->count = count; + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) +{ + if (unlikely(b->type != q->type)) { + dprintk(1,"querybuf: Wrong type.\n"); + return -EINVAL; + } + if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { + dprintk(1,"querybuf: index out of range.\n"); + return -EINVAL; + } + if (unlikely(NULL == q->bufs[b->index])) { + dprintk(1,"querybuf: buffer is null.\n"); + return -EINVAL; + } + videobuf_status(q,b,q->bufs[b->index],q->type); + return 0; +} + +int videobuf_qbuf(struct videobuf_queue *q, + struct v4l2_buffer *b) +{ + struct videobuf_buffer *buf; + enum v4l2_field field; + unsigned long flags=0; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) { + dprintk(1,"qbuf: Reading running...\n"); + goto done; + } + retval = -EINVAL; + if (b->type != q->type) { + dprintk(1,"qbuf: Wrong type.\n"); + goto done; + } + if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { + dprintk(1,"qbuf: index out of range.\n"); + goto done; + } + buf = q->bufs[b->index]; + if (NULL == buf) { + dprintk(1,"qbuf: buffer is null.\n"); + goto done; + } + MAGIC_CHECK(buf->magic,MAGIC_BUFFER); + if (buf->memory != b->memory) { + dprintk(1,"qbuf: memory type is wrong.\n"); + goto done; + } + if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { + dprintk(1,"qbuf: buffer is already queued or active.\n"); + goto done; + } + + if (b->flags & V4L2_BUF_FLAG_INPUT) { + if (b->input >= q->inputs) { + dprintk(1,"qbuf: wrong input.\n"); + goto done; + } + buf->input = b->input; + } else { + buf->input = UNSET; + } + + switch (b->memory) { + case V4L2_MEMORY_MMAP: + if (0 == buf->baddr) { + dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); + goto done; + } + break; + case V4L2_MEMORY_USERPTR: + if (b->length < buf->bsize) { + dprintk(1,"qbuf: buffer length is not enough\n"); + goto done; + } + if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) + q->ops->buf_release(q,buf); + buf->baddr = b->m.userptr; + break; + case V4L2_MEMORY_OVERLAY: + buf->boff = b->m.offset; + break; + default: + dprintk(1,"qbuf: wrong memory type\n"); + goto done; + } + + dprintk(1,"qbuf: requesting next field\n"); + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,buf,field); + if (0 != retval) { + dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); + goto done; + } + + list_add_tail(&buf->stream,&q->stream); + if (q->streaming) { + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + } + dprintk(1,"qbuf: succeded\n"); + retval = 0; + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking) +{ + struct videobuf_buffer *buf; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) { + dprintk(1,"dqbuf: Reading running...\n"); + goto done; + } + retval = -EINVAL; + if (b->type != q->type) { + dprintk(1,"dqbuf: Wrong type.\n"); + goto done; + } + if (list_empty(&q->stream)) { + dprintk(1,"dqbuf: stream running\n"); + goto done; + } + buf = list_entry(q->stream.next, struct videobuf_buffer, stream); + retval = videobuf_waiton(buf, nonblocking, 1); + if (retval < 0) { + dprintk(1,"dqbuf: waiton returned %d\n",retval); + goto done; + } + switch (buf->state) { + case STATE_ERROR: + dprintk(1,"dqbuf: state is error\n"); + retval = -EIO; + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; + break; + case STATE_DONE: + dprintk(1,"dqbuf: state is done\n"); + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; + break; + default: + dprintk(1,"dqbuf: state invalid\n"); + retval = -EINVAL; + goto done; + } + list_del(&buf->stream); + memset(b,0,sizeof(*b)); + videobuf_status(q,b,buf,q->type); + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_streamon(struct videobuf_queue *q) +{ + struct videobuf_buffer *buf; + struct list_head *list; + unsigned long flags=0; + int retval; + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) + goto done; + retval = 0; + if (q->streaming) + goto done; + q->streaming = 1; + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + list_for_each(list,&q->stream) { + buf = list_entry(list, struct videobuf_buffer, stream); + if (buf->state == STATE_PREPARED) + q->ops->buf_queue(q,buf); + } + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_streamoff(struct videobuf_queue *q) +{ + int retval = -EINVAL; + + mutex_lock(&q->lock); + if (!q->streaming) + goto done; + videobuf_queue_cancel(q); + q->streaming = 0; + retval = 0; + + done: + mutex_unlock(&q->lock); + return retval; +} + +static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, + char __user *data, + size_t count, loff_t *ppos) +{ + enum v4l2_field field; + unsigned long flags=0; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + /* setup stuff */ + q->read_buf = videobuf_alloc(q); + if (NULL == q->read_buf) + return -ENOMEM; + + q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->baddr = (unsigned long)data; + q->read_buf->bsize = count; + + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,q->read_buf,field); + if (0 != retval) + goto done; + + /* start capture & wait */ + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + retval = videobuf_waiton(q->read_buf,0,0); + if (0 == retval) { + CALL(q,sync,q,q->read_buf); + if (STATE_ERROR == q->read_buf->state) + retval = -EIO; + else + retval = q->read_buf->size; + } + + done: + /* cleanup */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + return retval; +} + +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking) +{ + enum v4l2_field field; + unsigned long flags=0; + unsigned size, nbufs; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + + nbufs = 1; size = 0; + q->ops->buf_setup(q,&nbufs,&size); + + if (NULL == q->read_buf && + count >= size && + !nonblocking) { + retval = videobuf_read_zerocopy(q,data,count,ppos); + if (retval >= 0 || retval == -EIO) + /* ok, all done */ + goto done; + /* fallback to kernel bounce buffer on failures */ + } + + if (NULL == q->read_buf) { + /* need to capture a new frame */ + retval = -ENOMEM; + q->read_buf = videobuf_alloc(q); + + dprintk(1,"video alloc=0x%p\n", q->read_buf); + if (NULL == q->read_buf) + goto done; + q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->bsize = count; /* preferred size */ + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,q->read_buf,field); + + if (0 != retval) { + kfree (q->read_buf); + q->read_buf = NULL; + goto done; + } + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->read_off = 0; + } + + /* wait until capture is done */ + retval = videobuf_waiton(q->read_buf, nonblocking, 1); + if (0 != retval) + goto done; + + CALL(q,sync,q,q->read_buf); + + if (STATE_ERROR == q->read_buf->state) { + /* catch I/O errors */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + retval = -EIO; + goto done; + } + + /* Copy to userspace */ + retval=CALL(q,copy_to_user,q,data,count,nonblocking); + if (retval<0) + goto done; + + q->read_off += retval; + if (q->read_off == q->read_buf->size) { + /* all data copied, cleanup */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + } + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_read_start(struct videobuf_queue *q) +{ + enum v4l2_field field; + unsigned long flags=0; + int count = 0, size = 0; + int err, i; + + q->ops->buf_setup(q,&count,&size); + if (count < 2) + count = 2; + if (count > VIDEO_MAX_FRAME) + count = VIDEO_MAX_FRAME; + size = PAGE_ALIGN(size); + + err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); + if (err) + return err; + + for (i = 0; i < count; i++) { + field = videobuf_next_field(q); + err = q->ops->buf_prepare(q,q->bufs[i],field); + if (err) + return err; + list_add_tail(&q->bufs[i]->stream, &q->stream); + } + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + for (i = 0; i < count; i++) + q->ops->buf_queue(q,q->bufs[i]); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->reading = 1; + return 0; +} + +void videobuf_read_stop(struct videobuf_queue *q) +{ + int i; + + videobuf_queue_cancel(q); + videobuf_mmap_free(q); + INIT_LIST_HEAD(&q->stream); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + q->read_buf = NULL; + q->reading = 0; +} + +ssize_t videobuf_read_stream(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int vbihack, int nonblocking) +{ + int rc, retval; + unsigned long flags=0; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + dprintk(2,"%s\n",__FUNCTION__); + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->streaming) + goto done; + if (!q->reading) { + retval = videobuf_read_start(q); + if (retval < 0) + goto done; + } + + retval = 0; + while (count > 0) { + /* get / wait for data */ + if (NULL == q->read_buf) { + q->read_buf = list_entry(q->stream.next, + struct videobuf_buffer, + stream); + list_del(&q->read_buf->stream); + q->read_off = 0; + } + rc = videobuf_waiton(q->read_buf, nonblocking, 1); + if (rc < 0) { + if (0 == retval) + retval = rc; + break; + } + + if (q->read_buf->state == STATE_DONE) { + rc = CALL (q,copy_stream, q, data, count, + retval, vbihack, nonblocking); + if (rc < 0) { + retval = rc; + break; + } + retval += rc; + count -= rc; + q->read_off += rc; + } else { + /* some error */ + q->read_off = q->read_buf->size; + if (0 == retval) + retval = -EIO; + } + + /* requeue buffer when done with copying */ + if (q->read_off == q->read_buf->size) { + list_add_tail(&q->read_buf->stream, + &q->stream); + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->read_buf = NULL; + } + if (retval < 0) + break; + } + + done: + mutex_unlock(&q->lock); + return retval; +} + +unsigned int videobuf_poll_stream(struct file *file, + struct videobuf_queue *q, + poll_table *wait) +{ + struct videobuf_buffer *buf = NULL; + unsigned int rc = 0; + + mutex_lock(&q->lock); + if (q->streaming) { + if (!list_empty(&q->stream)) + buf = list_entry(q->stream.next, + struct videobuf_buffer, stream); + } else { + if (!q->reading) + videobuf_read_start(q); + if (!q->reading) { + rc = POLLERR; + } else if (NULL == q->read_buf) { + q->read_buf = list_entry(q->stream.next, + struct videobuf_buffer, + stream); + list_del(&q->read_buf->stream); + q->read_off = 0; + } + buf = q->read_buf; + } + if (!buf) + rc = POLLERR; + + if (0 == rc) { + poll_wait(file, &buf->done, wait); + if (buf->state == STATE_DONE || + buf->state == STATE_ERROR) + rc = POLLIN|POLLRDNORM; + } + mutex_unlock(&q->lock); + return rc; +} + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory) +{ + unsigned int i; + int err; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + err = videobuf_mmap_free(q); + if (0 != err) + return err; + + /* Allocate and initialize buffers */ + for (i = 0; i < bcount; i++) { + q->bufs[i] = videobuf_alloc(q); + + q->bufs[i]->i = i; + q->bufs[i]->input = UNSET; + q->bufs[i]->memory = memory; + q->bufs[i]->bsize = bsize; + switch (memory) { + case V4L2_MEMORY_MMAP: + q->bufs[i]->boff = bsize * i; + break; + case V4L2_MEMORY_USERPTR: + case V4L2_MEMORY_OVERLAY: + /* nothing */ + break; + } + } + + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + bcount,bsize); + + return 0; +} + +int videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + int rc; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + rc = CALL(q,mmap_free,q); + if (rc<0) + return rc; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + + return rc; +} + +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval=CALL(q,mmap_mapper,q,vma); + mutex_unlock(&q->lock); + + return retval; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +int videobuf_cgmbuf(struct videobuf_queue *q, + struct video_mbuf *mbuf, int count) +{ + struct v4l2_requestbuffers req; + int rc,i; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + memset(&req,0,sizeof(req)); + req.type = q->type; + req.count = count; + req.memory = V4L2_MEMORY_MMAP; + rc = videobuf_reqbufs(q,&req); + if (rc < 0) + return rc; + + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; + } + + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + +EXPORT_SYMBOL_GPL(videobuf_waiton); +EXPORT_SYMBOL_GPL(videobuf_iolock); + +EXPORT_SYMBOL_GPL(videobuf_alloc); + +EXPORT_SYMBOL_GPL(videobuf_queue_init); +EXPORT_SYMBOL_GPL(videobuf_queue_cancel); +EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); + +EXPORT_SYMBOL_GPL(videobuf_next_field); +EXPORT_SYMBOL_GPL(videobuf_reqbufs); +EXPORT_SYMBOL_GPL(videobuf_querybuf); +EXPORT_SYMBOL_GPL(videobuf_qbuf); +EXPORT_SYMBOL_GPL(videobuf_dqbuf); +EXPORT_SYMBOL_GPL(videobuf_cgmbuf); +EXPORT_SYMBOL_GPL(videobuf_streamon); +EXPORT_SYMBOL_GPL(videobuf_streamoff); + +EXPORT_SYMBOL_GPL(videobuf_read_start); +EXPORT_SYMBOL_GPL(videobuf_read_stop); +EXPORT_SYMBOL_GPL(videobuf_read_stream); +EXPORT_SYMBOL_GPL(videobuf_read_one); +EXPORT_SYMBOL_GPL(videobuf_poll_stream); + +EXPORT_SYMBOL_GPL(videobuf_mmap_setup); +EXPORT_SYMBOL_GPL(videobuf_mmap_free); +EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c new file mode 100644 index 000000000000..3345877c47d4 --- /dev/null +++ b/drivers/media/video/videobuf-dma-sg.c @@ -0,0 +1,772 @@ +/* + * helper functions for PCI DMA video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_DMABUF 0x19721112 +#define MAGIC_SG_MEM 0x17890714 + +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + +/* --------------------------------------------------------------------- */ + +struct scatterlist* +videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) +{ + struct scatterlist *sglist; + struct page *pg; + int i; + + sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { + pg = vmalloc_to_page(virt); + if (NULL == pg) + goto err; + BUG_ON(PageHighMem(pg)); + sglist[i].page = pg; + sglist[i].length = PAGE_SIZE; + } + return sglist; + + err: + kfree(sglist); + return NULL; +} + +struct scatterlist* +videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) +{ + struct scatterlist *sglist; + int i = 0; + + if (NULL == pages[0]) + return NULL; + sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + + if (NULL == pages[0]) + goto nopage; + if (PageHighMem(pages[0])) + /* DMA to highmem pages might not work */ + goto highmem; + sglist[0].page = pages[0]; + sglist[0].offset = offset; + sglist[0].length = PAGE_SIZE - offset; + for (i = 1; i < nr_pages; i++) { + if (NULL == pages[i]) + goto nopage; + if (PageHighMem(pages[i])) + goto highmem; + sglist[i].page = pages[i]; + sglist[i].length = PAGE_SIZE; + } + return sglist; + + nopage: + dprintk(2,"sgl: oops - no page\n"); + kfree(sglist); + return NULL; + + highmem: + dprintk(2,"sgl: oops - highmem page\n"); + kfree(sglist); + return NULL; +} + +/* --------------------------------------------------------------------- */ + +struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + BUG_ON (!mem); + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return &mem->dma; +} + +void videobuf_dma_init(struct videobuf_dmabuf *dma) +{ + memset(dma,0,sizeof(*dma)); + dma->magic = MAGIC_DMABUF; +} + +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size) +{ + unsigned long first,last; + int err, rw = 0; + + dma->direction = direction; + switch (dma->direction) { + case PCI_DMA_FROMDEVICE: rw = READ; break; + case PCI_DMA_TODEVICE: rw = WRITE; break; + default: BUG(); + } + + first = (data & PAGE_MASK) >> PAGE_SHIFT; + last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; + dma->offset = data & ~PAGE_MASK; + dma->nr_pages = last-first+1; + dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), + GFP_KERNEL); + if (NULL == dma->pages) + return -ENOMEM; + dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", + data,size,dma->nr_pages); + + dma->varea = (void *) data; + + down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, + data & PAGE_MASK, dma->nr_pages, + rw == READ, 1, /* force */ + dma->pages, NULL); + up_read(¤t->mm->mmap_sem); + if (err != dma->nr_pages) { + dma->nr_pages = (err >= 0) ? err : 0; + dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); + return err < 0 ? err : -EINVAL; + } + return 0; +} + +int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, + int nr_pages) +{ + dprintk(1,"init kernel [%d pages]\n",nr_pages); + dma->direction = direction; + dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == dma->vmalloc) { + dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); + return -ENOMEM; + } + dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)dma->vmalloc, + nr_pages << PAGE_SHIFT); + memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); + dma->nr_pages = nr_pages; + return 0; +} + +int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, + dma_addr_t addr, int nr_pages) +{ + dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", + nr_pages,(unsigned long)addr); + dma->direction = direction; + if (0 == addr) + return -EINVAL; + + dma->bus_addr = addr; + dma->nr_pages = nr_pages; + return 0; +} + +int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(0 == dma->nr_pages); + + if (dma->pages) { + dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, + dma->offset); + } + if (dma->vmalloc) { + dma->sglist = videobuf_vmalloc_to_sg + (dma->vmalloc,dma->nr_pages); + } + if (dma->bus_addr) { + dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + if (NULL != dma->sglist) { + dma->sglen = 1; + sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; + dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; + sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; + } + } + if (NULL == dma->sglist) { + dprintk(1,"scatterlist is NULL\n"); + return -ENOMEM; + } + if (!dma->bus_addr) { + if (ops && ops->vb_map_sg) { + dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->nr_pages, dma->direction); + } + if (0 == dma->sglen) { + printk(KERN_WARNING + "%s: videobuf_map_sg failed\n",__FUNCTION__); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return -EIO; + } + } + return 0; +} + +int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(!dma->sglen); + + if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) + ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, + dma->direction); + + return 0; +} + +int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + if (!dma->sglen) + return 0; + + if (!dma->bus_addr && ops && ops->vb_unmap_sg) + ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, + dma->direction); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return 0; +} + +int videobuf_dma_free(struct videobuf_dmabuf *dma) +{ + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(dma->sglen); + + if (dma->pages) { + int i; + for (i=0; i < dma->nr_pages; i++) + page_cache_release(dma->pages[i]); + kfree(dma->pages); + dma->pages = NULL; + } + + vfree(dma->vmalloc); + dma->vmalloc = NULL; + dma->varea = NULL; + + if (dma->bus_addr) { + dma->bus_addr = 0; + } + dma->direction = PCI_DMA_NONE; + return 0; +} + +/* --------------------------------------------------------------------- */ + +int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) +{ + struct videobuf_queue q; + struct videobuf_dma_sg_ops qops; + + q.dev=pci; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.priv_ops = &qops; + + return (videobuf_dma_map(&q,dma)); +} + +int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) +{ + struct videobuf_queue q; + struct videobuf_dma_sg_ops qops; + + q.dev=pci; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.priv_ops = &qops; + + return (videobuf_dma_unmap(&q,dma)); +} + +/* --------------------------------------------------------------------- */ + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + map->count++; +} + +static void +videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + struct videbuf_pci_sg_memory *mem; + int i; + + dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count--; + if (0 == map->count) { + dprintk(1,"munmap %p q=%p\n",map,q); + mutex_lock(&q->lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + mem=q->bufs[i]->priv; + + if (!mem) + continue; + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (mem->map != map) + continue; + mem->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); + } + mutex_unlock(&q->lock); + kfree(map); + } + return; +} + +/* + * Get a anonymous page for the mapping. Make sure we can DMA to that + * memory location with 32bit PCI devices (i.e. don't use highmem for + * now ...). Bounce buffers don't work very well for the data rates + * video capture has. + */ +static struct page* +videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, + int *type) +{ + struct page *page; + + dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", + vaddr,vma->vm_start,vma->vm_end); + if (vaddr > vma->vm_end) + return NOPAGE_SIGBUS; + page = alloc_page(GFP_USER | __GFP_DMA32); + if (!page) + return NOPAGE_OOM; + clear_user_page(page_address(page), vaddr, page); + if (type) + *type = VM_FAULT_MINOR; + return page; +} + +static struct vm_operations_struct videobuf_vm_ops = +{ + .open = videobuf_vm_open, + .close = videobuf_vm_close, + .nopage = videobuf_vm_nopage, +}; + +/* --------------------------------------------------------------------- + * PCI handlers for the generic methods + */ + +/* Allocated area consists on 3 parts: + struct video_buffer + struct _buffer (cx88_buffer, saa7134_buf, ...) + struct videobuf_pci_sg_memory + */ + +static void *__videobuf_alloc(size_t size) +{ + struct videbuf_pci_sg_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + + mem = vb->priv = ((char *)vb)+size; + mem->magic=MAGIC_SG_MEM; + + videobuf_dma_init(&mem->dma); + + dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), + mem,(long)sizeof(*mem)); + + return vb; +} + +static int __videobuf_iolock (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + int err,pages; + dma_addr_t bus; + struct videbuf_pci_sg_memory *mem=vb->priv; + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_USERPTR: + if (0 == vb->baddr) { + /* no userspace addr -- kernel bounce buffer */ + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + err = videobuf_dma_init_kernel( &mem->dma, + PCI_DMA_FROMDEVICE, + pages ); + if (0 != err) + return err; + } else { + /* dma directly to userspace */ + err = videobuf_dma_init_user( &mem->dma, + PCI_DMA_FROMDEVICE, + vb->baddr,vb->bsize ); + if (0 != err) + return err; + } + break; + case V4L2_MEMORY_OVERLAY: + if (NULL == fbuf) + return -EINVAL; + /* FIXME: need sanity checks for vb->boff */ + /* + * Using a double cast to avoid compiler warnings when + * building for PAE. Compiler doesn't like direct casting + * of a 32 bit ptr to 64 bit integer. + */ + bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE, + bus, pages); + if (0 != err) + return err; + break; + default: + BUG(); + } + err = videobuf_dma_map(q,&mem->dma); + if (0 != err) + return err; + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return videobuf_dma_sync(q,&mem->dma); +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i]) { + struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv; + if (mem && mem->map) + return -EBUSY; + } + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videbuf_pci_sg_memory *mem; + struct videobuf_mapping *map; + unsigned int first,last,size,i; + int retval; + + retval = -EINVAL; + if (!(vma->vm_flags & VM_WRITE)) { + dprintk(1,"mmap app bug: PROT_WRITE please\n"); + goto done; + } + if (!(vma->vm_flags & VM_SHARED)) { + dprintk(1,"mmap app bug: MAP_SHARED please\n"); + goto done; + } + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (NULL == q->bufs[first]) + continue; + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) + break; + } + if (VIDEO_MAX_FRAME == first) { + dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + goto done; + } + + /* look for last buffer to map */ + for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { + if (NULL == q->bufs[last]) + continue; + if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) + continue; + mem=q->bufs[last]->priv; + if (mem->map) { + retval = -EBUSY; + goto done; + } + size += q->bufs[last]->bsize; + if (size == (vma->vm_end - vma->vm_start)) + break; + } + if (VIDEO_MAX_FRAME == last) { + dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", + (vma->vm_end - vma->vm_start)); + goto done; + } + + /* create mapping + update buffer list */ + retval = -ENOMEM; + map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + if (NULL == map) + goto done; + for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { + mem=q->bufs[i]->priv; + mem->map = map; + q->bufs[i]->baddr = vma->vm_start + size; + } + map->count = 1; + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ + vma->vm_private_data = map; + dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", + map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); + retval = 0; + + done: + return retval; +} + +static int __videobuf_is_mmapped (struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return (mem->map)?1:0; +} + +static int __videobuf_copy_to_user ( struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking ) +{ + struct videbuf_pci_sg_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream ( struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking ) +{ + unsigned int *fc; + struct videbuf_pci_sg_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int*)mem->dma.vmalloc; + fc += (q->read_buf->size>>2) -1; + *fc = q->read_buf->field_count >> 1; + dprintk(1,"vbihack: %d\n",*fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user (q,data,count,nonblocking); + + if ( (count==-EFAULT) && (0 == pos) ) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops pci_ops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .is_mmapped = __videobuf_is_mmapped, + .copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, +}; + +void *videobuf_pci_alloc (size_t size) +{ + struct videobuf_queue q; + + /* Required to make generic handler to call __videobuf_alloc */ + q.int_ops=&pci_ops; + + q.msize=size; + + return videobuf_alloc (&q); +} + +void videobuf_queue_pci_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + struct videobuf_dma_sg_ops *priv_ops; + + videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); + q->int_ops=&pci_ops; + + /* FIXME: the code bellow should be removed after having a proper + * memory allocation method for vivi and tm6000 + */ + q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); + BUG_ON (!q->priv_ops); + + priv_ops=q->priv_ops; + + /* Sets default methods for handling Scatter Gather mapping */ + priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; + priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; +} + +void videobuf_set_pci_ops (struct videobuf_queue* q, + struct videobuf_dma_sg_ops *ops) +{ + kfree (q->priv_ops); + + q->priv_ops=ops; + + if (!ops) + return; + + /* If not specified, defaults to PCI map sg */ + if (!ops->vb_map_sg) + ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; + + if (!ops->vb_dma_sync_sg) + ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; + if (!ops->vb_unmap_sg) + ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; +} + + +/* --------------------------------------------------------------------- */ + +EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); + +EXPORT_SYMBOL_GPL(videobuf_to_dma); +EXPORT_SYMBOL_GPL(videobuf_dma_init); +EXPORT_SYMBOL_GPL(videobuf_dma_init_user); +EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); +EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); +EXPORT_SYMBOL_GPL(videobuf_dma_map); +EXPORT_SYMBOL_GPL(videobuf_dma_sync); +EXPORT_SYMBOL_GPL(videobuf_dma_unmap); +EXPORT_SYMBOL_GPL(videobuf_dma_free); + +EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); +EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); +EXPORT_SYMBOL_GPL(videobuf_pci_alloc); + +EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); +EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h new file mode 100644 index 000000000000..0ac21ae44f69 --- /dev/null +++ b/include/media/videobuf-core.h @@ -0,0 +1,236 @@ +/* + * generic helper functions for handling video4linux capture buffers + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * 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 + */ + +#include +#ifdef CONFIG_VIDEO_V4L1_COMPAT +#include +#endif +#include + +#define UNSET (-1U) + + +struct videobuf_buffer; +struct videobuf_queue; + +/* --------------------------------------------------------------------- */ + +/* + * A small set of helper functions to manage video4linux buffers. + * + * struct videobuf_buffer holds the data structures used by the helper + * functions, additionally some commonly used fields for v4l buffers + * (width, height, lists, waitqueue) are in there. That struct should + * be used as first element in the drivers buffer struct. + * + * about the mmap helpers (videobuf_mmap_*): + * + * The mmaper function allows to map any subset of contingous buffers. + * This includes one mmap() call for all buffers (which the original + * video4linux API uses) as well as one mmap() for every single buffer + * (which v4l2 uses). + * + * If there is a valid mapping for a buffer, buffer->baddr/bsize holds + * userspace address + size which can be feeded into the + * videobuf_dma_init_user function listed above. + * + */ + +struct videobuf_mapping { + unsigned int count; + unsigned long start; + unsigned long end; + struct videobuf_queue *q; +}; + +enum videobuf_state { + STATE_NEEDS_INIT = 0, + STATE_PREPARED = 1, + STATE_QUEUED = 2, + STATE_ACTIVE = 3, + STATE_DONE = 4, + STATE_ERROR = 5, + STATE_IDLE = 6, +}; + +struct videobuf_buffer { + unsigned int i; + u32 magic; + + /* info about the buffer */ + unsigned int width; + unsigned int height; + unsigned int bytesperline; /* use only if != 0 */ + unsigned long size; + unsigned int input; + enum v4l2_field field; + enum videobuf_state state; + struct list_head stream; /* QBUF/DQBUF list */ + + /* touched by irq handler */ + struct list_head queue; + wait_queue_head_t done; + unsigned int field_count; + struct timeval ts; + + /* Memory type */ + enum v4l2_memory memory; + + /* buffer size */ + size_t bsize; + + /* buffer offset (mmap + overlay) */ + size_t boff; + + /* buffer addr (userland ptr!) */ + unsigned long baddr; + + /* Private pointer to allow specific methods to store their data */ + int privsize; + void *priv; +}; + +struct videobuf_queue_ops { + int (*buf_setup)(struct videobuf_queue *q, + unsigned int *count, unsigned int *size); + int (*buf_prepare)(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field); + void (*buf_queue)(struct videobuf_queue *q, + struct videobuf_buffer *vb); + void (*buf_release)(struct videobuf_queue *q, + struct videobuf_buffer *vb); +}; + +#define MAGIC_QTYPE_OPS 0x12261003 + +/* Helper operations - device type dependent */ +struct videobuf_qtype_ops { + u32 magic; + + void* (*alloc) (size_t size); + int (*iolock) (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf); + int (*mmap) (struct videobuf_queue *q, + unsigned int *count, + unsigned int *size, + enum v4l2_memory memory); + int (*sync) (struct videobuf_queue* q, + struct videobuf_buffer *buf); + int (*copy_to_user) (struct videobuf_queue *q, + char __user *data, + size_t count, + int nonblocking); + int (*copy_stream) (struct videobuf_queue *q, + char __user *data, + size_t count, + size_t pos, + int vbihack, + int nonblocking); + int (*mmap_free) (struct videobuf_queue *q); + int (*mmap_mapper) (struct videobuf_queue *q, + struct vm_area_struct *vma); + int (*is_mmapped) (struct videobuf_buffer *buf); +}; + +struct videobuf_queue { + struct mutex lock; + spinlock_t *irqlock; + void *dev; /* on pci, points to struct pci_dev */ + + enum v4l2_buf_type type; + unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ + unsigned int msize; + enum v4l2_field field; + enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ + struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; + struct videobuf_queue_ops *ops; + struct videobuf_qtype_ops *int_ops; + + /* capture via mmap() + ioctl(QBUF/DQBUF) */ + unsigned int streaming; + struct list_head stream; + + /* capture via read() */ + unsigned int reading; + unsigned int read_off; + struct videobuf_buffer *read_buf; + + /* driver private data */ + void *priv_data; + + /*FIXME: should be removed after completing the vb conversion */ + void *priv_ops; +}; + +int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf); + +void *videobuf_alloc(struct videobuf_queue* q); + +void videobuf_queue_init(struct videobuf_queue *q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); +int videobuf_queue_is_busy(struct videobuf_queue *q); +void videobuf_queue_cancel(struct videobuf_queue *q); + +enum v4l2_field videobuf_next_field(struct videobuf_queue *q); +int videobuf_reqbufs(struct videobuf_queue *q, + struct v4l2_requestbuffers *req); +int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); +int videobuf_qbuf(struct videobuf_queue *q, + struct v4l2_buffer *b); +int videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking); +#ifdef CONFIG_VIDEO_V4L1_COMPAT +int videobuf_cgmbuf(struct videobuf_queue *q, + struct video_mbuf *mbuf, int count); +#endif +int videobuf_streamon(struct videobuf_queue *q); +int videobuf_streamoff(struct videobuf_queue *q); + +int videobuf_read_start(struct videobuf_queue *q); +void videobuf_read_stop(struct videobuf_queue *q); +ssize_t videobuf_read_stream(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int vbihack, int nonblocking); +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking); +unsigned int videobuf_poll_stream(struct file *file, + struct videobuf_queue *q, + poll_table *wait); + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory); +int videobuf_mmap_free(struct videobuf_queue *q); +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma); + +/* --------------------------------------------------------------------- */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h new file mode 100644 index 000000000000..62a3709905f3 --- /dev/null +++ b/include/media/videobuf-dma-sg.h @@ -0,0 +1,142 @@ +/* + * helper functions for PCI DMA video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * 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 + */ + +#include + +/* --------------------------------------------------------------------- */ + +/* + * Return a scatterlist for some page-aligned vmalloc()'ed memory + * block (NULL on errors). Memory for the scatterlist is allocated + * using kmalloc. The caller must free the memory. + */ +struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); + +/* + * Return a scatterlist for a an array of userpages (NULL on errors). + * Memory for the scatterlist is allocated using kmalloc. The caller + * must free the memory. + */ +struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, + int offset); + +/* --------------------------------------------------------------------- */ + +/* + * A small set of helper functions to manage buffers (both userland + * and kernel) for DMA. + * + * videobuf_dma_init_*() + * creates a buffer. The userland version takes a userspace + * pointer + length. The kernel version just wants the size and + * does memory allocation too using vmalloc_32(). + * + * videobuf_dma_*() + * see Documentation/DMA-mapping.txt, these functions to + * basically the same. The map function does also build a + * scatterlist for the buffer (and unmap frees it ...) + * + * videobuf_dma_free() + * no comment ... + * + */ + +struct videobuf_dmabuf { + u32 magic; + + /* for userland buffer */ + int offset; + struct page **pages; + + /* for kernel buffers */ + void *vmalloc; + + /* Stores the userspace pointer to vmalloc area */ + void *varea; + + /* for overlay buffers (pci-pci dma) */ + dma_addr_t bus_addr; + + /* common */ + struct scatterlist *sglist; + int sglen; + int nr_pages; + int direction; +}; + +struct videbuf_pci_sg_memory +{ + u32 magic; + + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + struct videobuf_dmabuf dma; +}; + +/* FIXME: To be removed soon */ +typedef int (vb_map_sg_t)(void *dev, struct scatterlist *sglist, int nr_pages, + int direction); + +/* FIXME: To be removed soon */ +struct videobuf_dma_sg_ops +{ + vb_map_sg_t *vb_map_sg; + vb_map_sg_t *vb_dma_sync_sg; + vb_map_sg_t *vb_unmap_sg; + +}; + +void videobuf_dma_init(struct videobuf_dmabuf *dma); +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size); +int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, + int nr_pages); +int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, + dma_addr_t addr, int nr_pages); +int videobuf_dma_free(struct videobuf_dmabuf *dma); + +int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf); + +void *videobuf_pci_alloc (size_t size); + +void videobuf_queue_pci_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + + /*FIXME: these variants are used only on *-alsa code, where videobuf is + * used without queue + */ +int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); +int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); + +/* FIXME: temporary routine for vivi and tm6000, while lacking implementation + * of videobuf-vmalloc + */ +void videobuf_set_pci_ops (struct videobuf_queue* q, + struct videobuf_dma_sg_ops *ops); + From c1accaa21bdef38ec0f36eaaf7ce3384fff9d0c5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:37:49 -0300 Subject: [PATCH 0772/2804] V4L/DVB (6252): Adapt drivers to use the newer videobuf modules PCI-dependent videobuf_foo methods were renamed as videobuf_pci_foo. Also, videobuf_dmabuf is now part of videobuf-dma-sg private struct. So, to access it, a subroutine call is needed. This patch renames all occurences of those function calls to be consistent with the video-buf split. Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- Documentation/dvb/faq.txt | 2 +- drivers/media/Kconfig | 6 ++- drivers/media/common/Kconfig | 2 +- drivers/media/common/saa7146_core.c | 2 +- drivers/media/common/saa7146_fops.c | 5 ++- drivers/media/common/saa7146_vbi.c | 9 +++-- drivers/media/common/saa7146_video.c | 9 +++-- drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 3 +- drivers/media/video/bt8xx/Kconfig | 2 +- drivers/media/video/bt8xx/bttv-driver.c | 17 +++++---- drivers/media/video/bt8xx/bttv-risc.c | 35 +++++++++-------- drivers/media/video/bt8xx/bttv-vbi.c | 5 ++- drivers/media/video/bt8xx/bttvp.h | 2 +- drivers/media/video/cafe_ccic.c | 2 +- drivers/media/video/cx88/Kconfig | 2 +- drivers/media/video/cx88/cx88-alsa.c | 24 +++++++----- drivers/media/video/cx88/cx88-blackbird.c | 2 +- drivers/media/video/cx88/cx88-core.c | 6 ++- drivers/media/video/cx88/cx88-dvb.c | 2 +- drivers/media/video/cx88/cx88-mpeg.c | 3 +- drivers/media/video/cx88/cx88-vbi.c | 3 +- drivers/media/video/cx88/cx88-video.c | 38 +++++-------------- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/saa7134/Kconfig | 2 +- drivers/media/video/saa7134/saa7134-core.c | 8 ++-- drivers/media/video/saa7134/saa7134-dvb.c | 2 +- drivers/media/video/saa7134/saa7134-empress.c | 2 +- drivers/media/video/saa7134/saa7134-ts.c | 6 ++- drivers/media/video/saa7134/saa7134-vbi.c | 6 ++- drivers/media/video/saa7134/saa7134-video.c | 34 ++++------------- drivers/media/video/saa7134/saa7134.h | 2 +- drivers/media/video/video-buf-dvb.c | 6 ++- include/media/saa7146_vv.h | 2 +- 34 files changed, 125 insertions(+), 130 deletions(-) diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt index dbcedf5833ee..2511a335abd6 100644 --- a/Documentation/dvb/faq.txt +++ b/Documentation/dvb/faq.txt @@ -150,7 +150,7 @@ Some very frequently asked questions about linuxtv-dvb - saa7146_vv: SAA7146 video and vbi functions. These are only needed for full-featured cards. - - video-buf: capture helper module for the saa7146_vv driver. This + - videobuf-dma-sg: capture helper module for the saa7146_vv driver. This one is responsible to handle capture buffers. - dvb-ttpci: The main driver for AV7110 based, full-featured diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 3f8cfa873de5..28ee65c53917 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -126,8 +126,12 @@ config TUNER_SIMPLE endif # VIDEO_TUNER_CUSTOMIZE -config VIDEO_BUF +config VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_SG depends on PCI + select VIDEOBUF_GEN tristate config VIDEO_BUF_DVB diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 5c63c8e24ee7..c5092ef1082f 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -5,5 +5,5 @@ config VIDEO_SAA7146 config VIDEO_SAA7146_VV tristate depends on VIDEO_DEV - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_SAA7146 diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 1c962a2b44df..365a22118a09 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -100,7 +100,7 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) * general helper functions ****************************************************************************/ -/* this is videobuf_vmalloc_to_sg() from video-buf.c +/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c make sure virt has been allocated with vmalloc_32(), otherwise the BUG() may be triggered on highmem machines */ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index b4770aecc01d..67d1b1b1b254 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -53,13 +53,14 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, struct saa7146_buf *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); DEB_EE(("dev:%p, buf:%p\n",dev,buf)); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 063608462ebe..6103484e4442 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -165,7 +165,7 @@ static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf /* we don't wait here for the first field anymore. this is different from the video capture and might cause that the first buffer is only half filled (with only one field). but since this is some sort of streaming data, this is not that negative. - but by doing this, we can use the whole engine from video-buf.c... */ + but by doing this, we can use the whole engine from videobuf-dma-sg.c... */ /* WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait); @@ -239,6 +239,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e saa7146_dma_free(dev,q,buf); if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -250,7 +252,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e err = videobuf_iolock(q,&buf->vb, NULL); if (err) goto oops; - err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen); + err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], + dma->sglist, dma->sglen); if (0 != err) return err; } @@ -404,7 +407,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) fh->vbi_fmt.start[1] = 312; fh->vbi_fmt.count[1] = 16; - videobuf_queue_init(&fh->vbi_q, &vbi_qops, + videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, // FIXME: does this really work? diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 664280c78ff2..29dbc602a484 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -594,8 +594,9 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) { struct pci_dev *pci = dev->pci; - struct scatterlist *list = buf->vb.dma.sglist; - int length = buf->vb.dma.sglen; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + struct scatterlist *list = dma->sglist; + int length = dma->sglen; struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); @@ -655,7 +656,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu /* if we have a user buffer, the first page may not be aligned to a page boundary. */ - pt1->offset = buf->vb.dma.sglist->offset; + pt1->offset = list->offset; pt2->offset = pt1->offset+o1; pt3->offset = pt1->offset+o2; @@ -1411,7 +1412,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file) sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; - videobuf_queue_init(&fh->video_q, &video_qops, + videobuf_queue_pci_init(&fh->video_q, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 5d74925748c0..c4f424422f70 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -364,7 +364,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI - select VIDEO_BUF + select VIDEOBUF_DMA_SG default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9e99d2e1c1bd..cb300241eb89 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -87,7 +87,8 @@ obj-$(CONFIG_TUNER_TDA8290) += tda8290.o obj-$(CONFIG_TUNER_TEA5767) += tea5767.o obj-$(CONFIG_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_VIDEO_BUF) += video-buf.o +obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o +obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 58eae887a629..2ca162b390a2 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -4,7 +4,7 @@ config VIDEO_BT848 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 0711c9507843..4ab4e14b5c64 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -2582,7 +2582,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); @@ -3048,7 +3048,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mutex_lock(&fh->cap.lock); if (*on) { fh->ov.tvnorm = btv->tvnorm; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); } else { @@ -3141,9 +3141,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, retval = -EIO; /* fall through */ case STATE_DONE: - videobuf_dma_sync(&fh->cap,&buf->vb.dma); + { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + videobuf_dma_sync(&fh->cap,dma); bttv_dma_free(&fh->cap,btv,buf); break; + } default: retval = -EINVAL; break; @@ -3337,7 +3340,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new); retval = bttv_switch_overlay(btv,fh,new); @@ -3696,7 +3699,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) mutex_unlock(&fh->cap.lock); return POLLERR; } - fh->cap.read_buf = videobuf_alloc(fh->cap.msize); + fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize); if (NULL == fh->cap.read_buf) { mutex_unlock(&fh->cap.lock); return POLLERR; @@ -3763,13 +3766,13 @@ static int bttv_open(struct inode *inode, struct file *file) fh->ov.setup_ok = 0; v4l2_prio_open(&btv->prio,&fh->prio); - videobuf_queue_init(&fh->cap, &bttv_video_qops, + videobuf_queue_pci_init(&fh->cap, &bttv_video_qops, btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct bttv_buffer), fh); - videobuf_queue_init(&fh->vbi, &bttv_vbi_qops, + videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops, btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index e7104d9cb4bd..58986f1a5f1a 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -574,10 +574,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, void bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); buf->vb.state = STATE_NEEDS_INIT; @@ -699,6 +701,7 @@ int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) { const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); dprintk(KERN_DEBUG "bttv%d: buffer field: %s format: %s size: %dx%d\n", @@ -716,25 +719,25 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) switch (buf->vb.field) { case V4L2_FIELD_TOP: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, /* offset */ 0,bpl, /* padding */ 0,/* skip_lines */ 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, 0,bpl,0,0,buf->vb.height); break; case V4L2_FIELD_INTERLACED: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,bpl,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpl,bpl,bpl,0,buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,0,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpf,bpl,0,0,buf->vb.height >> 1); break; default: @@ -767,7 +770,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,/* both_fields */ 0, tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist, + bttv_risc_planar(btv, &buf->top, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); @@ -776,7 +779,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,0, tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist, + bttv_risc_planar(btv, &buf->bottom, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); @@ -789,14 +792,14 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, - buf->vb.dma.sglist, + dma->sglist, 0,buf->vb.width,ypadding,lines, uoffset,voffset, buf->fmt->hshift, buf->fmt->vshift, cpadding); bttv_risc_planar(btv,&buf->bottom, - buf->vb.dma.sglist, + dma->sglist, ypadding,buf->vb.width,ypadding,lines, uoffset+cpadding, voffset+cpadding, @@ -812,7 +815,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, - buf->vb.dma.sglist, + dma->sglist, 0,buf->vb.width,0,lines, uoffset >> 1, voffset >> 1, @@ -820,7 +823,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) buf->fmt->vshift, 0); bttv_risc_planar(btv,&buf->bottom, - buf->vb.dma.sglist, + dma->sglist, lines * ypadding,buf->vb.width,0,lines, lines * ypadding + (uoffset >> 1), lines * ypadding + (voffset >> 1), @@ -839,10 +842,10 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) buf->vb.field = V4L2_FIELD_SEQ_TB; bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, 1,tvnorm,&buf->crop); - bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->top, dma->sglist, /* offset */ 0, RAW_BPL, /* padding */ 0, /* skip_lines */ 0, RAW_LINES); - bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->bottom, dma->sglist, buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); } diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 007485aa4f01..346ce019bdcb 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -150,13 +150,14 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, if (redo_dma_risc) { unsigned int bpl, padding, offset; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); bpl = 2044; /* max. vbipack */ padding = VBI_BPL - bpl; if (fh->vbi_fmt.fmt.count[0] > 0) { rc = bttv_risc_packed(btv, &buf->top, - buf->vb.dma.sglist, + dma->sglist, /* offset */ 0, bpl, padding, skip_lines0, fh->vbi_fmt.fmt.count[0]); @@ -168,7 +169,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL; rc = bttv_risc_packed(btv, &buf->bottom, - buf->vb.dma.sglist, + dma->sglist, offset, bpl, padding, skip_lines1, fh->vbi_fmt.fmt.count[1]); diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 5b25faca1504..0b92c35a8435 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index ccb37006bb18..b63cab336920 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1197,7 +1197,7 @@ static int cafe_setup_siobuf(struct cafe_camera *cam, int index) buf->v4lbuf.field = V4L2_FIELD_NONE; buf->v4lbuf.memory = V4L2_MEMORY_MMAP; /* - * Offset: must be 32-bit even on a 64-bit system. video-buf + * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg * just uses the length times the index, but the spec warns * against doing just that - vma merging problems. So we * leave a gap between each pair of buffers. diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index f750a543c961..c68ba74d44ec 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -4,7 +4,7 @@ config VIDEO_CX88 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index f4abed454fd4..90c36c5705c3 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -72,7 +72,7 @@ struct cx88_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf dma_risc; + struct videobuf_dmabuf *dma_risc; struct cx88_buffer *buf; @@ -282,11 +282,12 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) BUG_ON(!chip->dma_size); dprintk(2,"Freeing buffer\n"); - videobuf_pci_dma_unmap(chip->pci, &chip->dma_risc); - videobuf_dma_free(&chip->dma_risc); + videobuf_pci_dma_unmap(chip->pci, chip->dma_risc); + videobuf_dma_free(chip->dma_risc); btcx_riscmem_free(chip->pci,&chip->buf->risc); kfree(chip->buf); + chip->dma_risc = NULL; chip->dma_size = 0; return 0; @@ -366,6 +367,8 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, struct snd_pcm_hw_params * hw_params) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct videobuf_dmabuf *dma; + struct cx88_buffer *buf; int ret; @@ -381,7 +384,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, BUG_ON(!chip->dma_size); BUG_ON(chip->num_periods & (chip->num_periods-1)); - buf = kzalloc(sizeof(*buf), GFP_KERNEL); + buf = videobuf_pci_alloc(sizeof(*buf)); if (NULL == buf) return -ENOMEM; @@ -392,17 +395,18 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->vb.height = chip->num_periods; buf->vb.size = chip->dma_size; - videobuf_dma_init(&buf->vb.dma); - ret = videobuf_dma_init_kernel(&buf->vb.dma, PCI_DMA_FROMDEVICE, + dma=videobuf_to_dma(&buf->vb); + videobuf_dma_init(dma); + ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + ret = videobuf_pci_dma_map(chip->pci,dma); if (ret < 0) goto error; - ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->vb.dma.sglist, + ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist, buf->vb.width, buf->vb.height, 1); if (ret < 0) goto error; @@ -414,9 +418,9 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->vb.state = STATE_PREPARED; chip->buf = buf; - chip->dma_risc = buf->vb.dma; + chip->dma_risc = dma; - substream->runtime->dma_area = chip->dma_risc.vmalloc; + substream->runtime->dma_area = chip->dma_risc->vmalloc; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; return 0; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index fcaf4f51293f..6d6f5048d762 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1111,7 +1111,7 @@ static int mpeg_open(struct inode *inode, struct file *file) file->private_data = fh; fh->dev = dev; - videobuf_queue_init(&fh->mpegq, &blackbird_qops, + videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 716154828ff0..85609b41f86e 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -213,10 +213,12 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 00d0e43785a0..d16e5c6d21c0 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -710,7 +710,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* dvb stuff */ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); - videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops, + videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index d302793fcfb9..a652f294d23d 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -237,6 +237,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, struct cx88_buffer *buf, enum v4l2_field field) { int size = dev->ts_packet_size * dev->ts_packet_count; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc; dprintk(1, "%s: %p\n", __FUNCTION__, buf); @@ -252,7 +253,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; cx88_risc_databuffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, buf->vb.width, buf->vb.height, 0); } buf->vb.state = STATE_PREPARED; diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 72c1d19fa79f..aa40505c4b3a 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -172,6 +172,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, return -EINVAL; if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = VBI_LINE_LENGTH; buf->vb.height = VBI_LINE_COUNT; buf->vb.size = size; @@ -180,7 +181,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, 0, buf->vb.width * buf->vb.height, buf->vb.width, 0, buf->vb.height); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 705c29b002ea..1439b7268532 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -534,6 +534,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc, init_buffer = 0; BUG_ON(NULL == fh->fmt); @@ -566,30 +567,30 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, switch (buf->vb.field) { case V4L2_FIELD_TOP: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, 0, UNSET, + dma->sglist, 0, UNSET, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, UNSET, 0, + dma->sglist, UNSET, 0, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, 0, buf->bpl, + dma->sglist, 0, buf->bpl, buf->bpl, buf->bpl, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, 0, buf->bpl * (buf->vb.height >> 1), buf->bpl, 0, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_BT: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, buf->bpl * (buf->vb.height >> 1), 0, buf->bpl, 0, buf->vb.height >> 1); @@ -752,13 +753,13 @@ static int video_open(struct inode *inode, struct file *file) fh->height = 240; fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - videobuf_queue_init(&fh->vidq, &cx8800_video_qops, + videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct cx88_buffer), fh); - videobuf_queue_init(&fh->vbiq, &cx8800_vbi_qops, + videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, @@ -1104,28 +1105,9 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv, #ifdef CONFIG_VIDEO_V4L1_COMPAT static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { - struct cx8800_fh *fh = priv; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - int err; + struct cx8800_fh *fh = priv; - q = get_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; + return videobuf_cgmbuf (get_queue(fh), mbuf, 8); } #endif diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 0e4f8e278671..875a9abab2a2 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 9f1417a4f7d2..82bc4ef414ac 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -1,7 +1,7 @@ config VIDEO_SAA7134 tristate "Philips SAA7134 support" depends on VIDEO_DEV && PCI && I2C - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER select CRC32 diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 80108ddf4834..a1d986e01a30 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -236,9 +236,10 @@ int saa7134_buffer_startpage(struct saa7134_buf *buf) unsigned long saa7134_buffer_base(struct saa7134_buf *buf) { unsigned long base; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); base = saa7134_buffer_startpage(buf) * 4096; - base += buf->vb.dma.sglist[0].offset; + base += dma->sglist[0].offset; return base; } @@ -286,11 +287,12 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index bbab252cbeee..38d87332cc5d 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -850,7 +850,7 @@ static int dvb_init(struct saa7134_dev *dev) dev->ts.nr_bufs = 32; dev->ts.nr_packets = 32*4; dev->dvb.name = dev->name; - videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops, + videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_ALTERNATE, diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 7ed4eaf05e13..a16df57af63a 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -400,7 +400,7 @@ static int empress_init(struct saa7134_dev *dev) printk(KERN_INFO "%s: registered device video%d [mpeg]\n", dev->name,dev->empress_dev->minor & 0x1f); - videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops, + videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_ALTERNATE, diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 7780b2cce80d..5b1d1dafb5a5 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -92,6 +92,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -101,8 +103,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 0044079f5da2..81a2aedeff5c 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -137,6 +137,8 @@ static int buffer_prepare(struct videobuf_queue *q, saa7134_dma_free(q,buf); if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -146,8 +148,8 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9c317ed6b210..cf40a9690a50 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1037,6 +1037,8 @@ static int buffer_prepare(struct videobuf_queue *q, } if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = fh->width; buf->vb.height = fh->height; buf->vb.size = size; @@ -1048,8 +1050,8 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; @@ -1309,13 +1311,13 @@ static int video_open(struct inode *inode, struct file *file) fh->height = 576; v4l2_prio_open(&dev->prio,&fh->prio); - videobuf_queue_init(&fh->cap, &video_qops, + videobuf_queue_pci_init(&fh->cap, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct saa7134_buf), fh); - videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops, + videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, @@ -2137,29 +2139,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } #ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - - q = saa7134_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = gbuffers; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; - } + return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers); #endif case VIDIOC_REQBUFS: return videobuf_reqbufs(saa7134_queue(fh),arg); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index fd12942b3a10..dae608f9bf3b 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index d2af82dc8faf..9631ead297ee 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include /* ------------------------------------------------------------------ */ @@ -45,6 +45,7 @@ static int videobuf_dvb_thread(void *data) struct videobuf_buffer *buf; unsigned long flags; int err; + struct videobuf_dmabuf *dma; dprintk("dvb thread started\n"); set_freezable(); @@ -65,8 +66,9 @@ static int videobuf_dvb_thread(void *data) try_to_freeze(); /* feed buffer data to demux */ + dma=videobuf_to_dma(buf); if (buf->state == STATE_DONE) - dvb_dmx_swfilter(&dvb->demux, buf->dma.vmalloc, + dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, buf->size); /* requeue buffer */ diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index cce20ed5cf6c..e49f7e156061 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */ #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ From 6bb2790f8a0cf93d3dbed6b6e986441110e6174b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:41:14 -0300 Subject: [PATCH 0773/2804] V4L/DVB (6253): Convert vivi to use the newer videobuf-dma-sg module Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 53 ++++++++++++++------------------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index c10169e35753..89c40341007f 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -33,7 +33,7 @@ #include #endif #include -#include +#include #include #include #include @@ -327,19 +327,21 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) int wmax = buf->vb.width; struct timeval ts; char *tmpbuf; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - if (buf->vb.dma.varea) { + + if (dma->varea) { tmpbuf=kmalloc (wmax*2, GFP_KERNEL); } else { - tmpbuf=buf->vb.dma.vmalloc; + tmpbuf=dma->vmalloc; } for (h=0;hvb.dma.varea) { + if (dma->varea) { gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0) + if (copy_to_user(dma->varea+pos,tmpbuf,wmax*2)!=0) dprintk(2,"vivifill copy_to_user failed.\n"); } else { gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); @@ -369,7 +371,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) dev->h,dev->m,dev->s,(dev->us+500)/1000); dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)buf->vb.dma.varea,pos); + (unsigned long)dma->varea,pos); /* Advice that buffer was filled */ buf->vb.state = STATE_DONE; @@ -597,13 +599,19 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) if (0 == *count) *count = 32; + while (*size * *count > vid_limit * 1024 * 1024) (*count)--; + + dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size); + return 0; } static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + dprintk(1,"%s\n",__FUNCTION__); if (in_interrupt()) @@ -611,8 +619,8 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(vq, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(vq, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } @@ -626,7 +634,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); int rc, init_buffer = 0; -// dprintk(1,"%s, field=%d\n",__FUNCTION__,field); + dprintk(1,"%s, field=%d\n",__FUNCTION__,field); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw() || @@ -724,11 +732,6 @@ static struct videobuf_queue_ops vivi_video_qops = { .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release, - - /* Non-pci handling routines */ -// .vb_map_sg = vivi_map_sg, -// .vb_dma_sync_sg = vivi_dma_sync_sg, -// .vb_unmap_sg = vivi_unmap_sg, }; /* ------------------------------------------------------------------ @@ -904,25 +907,8 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { struct vivi_fh *fh=priv; - struct videobuf_queue *q=&fh->vb_vidq; - struct v4l2_requestbuffers req; - unsigned int i; - int ret; - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - ret = videobuf_reqbufs(q,&req); - if (ret < 0) - return (ret); - - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return (0); + return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8); } #endif @@ -1106,12 +1092,13 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); - videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, + videobuf_queue_pci_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); + return 0; } From 87b9ad070cf76c0f1e8cf836f7eb86e9ac94e34a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 2 Aug 2007 23:31:33 -0300 Subject: [PATCH 0774/2804] V4L/DVB (6254): Add videobuf-vmalloc Adds a newer videobuf-vmalloc module. This module uses the same videobuf controls, but implements memory allocation based on vmalloc methods. With this method, an USB driver can use video-buf, without needing to request memory from the DMA-safe area. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 4 + drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 1 + drivers/media/video/videobuf-vmalloc.c | 384 +++++++++++++++++++++++++ include/media/videobuf-vmalloc.h | 44 +++ 5 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 drivers/media/video/videobuf-vmalloc.c create mode 100644 include/media/videobuf-vmalloc.h diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 28ee65c53917..fc3ea4c67ccb 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -134,6 +134,10 @@ config VIDEOBUF_DMA_SG select VIDEOBUF_GEN tristate +config VIDEOBUF_VMALLOC + select VIDEOBUF_GEN + tristate + config VIDEO_BUF_DVB tristate diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c4f424422f70..2e571eb9313a 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -364,7 +364,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI - select VIDEOBUF_DMA_SG + select VIDEOBUF_VMALLOC default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index cb300241eb89..c8140aec1a16 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o +obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c new file mode 100644 index 000000000000..993d5285e18e --- /dev/null +++ b/drivers/media/video/videobuf-vmalloc.c @@ -0,0 +1,384 @@ +/* + * helper functions for vmalloc video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_DMABUF 0x17760309 +#define MAGIC_VMAL_MEM 0x18221223 + +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + + +/***************************************************************************/ + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count++; +} + +static void +videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + struct videbuf_vmalloc_memory *mem; + int i; + + dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count--; + if (0 == map->count) { + dprintk(1,"munmap %p q=%p\n",map,q); + mutex_lock(&q->lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + mem=q->bufs[i]->priv; + + if (!mem) + continue; + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + if (mem->map != map) + continue; + mem->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); + } + mutex_unlock(&q->lock); + kfree(map); + } + return; +} + +static struct vm_operations_struct videobuf_vm_ops = +{ + .open = videobuf_vm_open, + .close = videobuf_vm_close, +}; + +/* --------------------------------------------------------------------- + * vmalloc handlers for the generic methods + */ + +/* Allocated area consists on 3 parts: + struct video_buffer + struct _buffer (cx88_buffer, saa7134_buf, ...) + struct videobuf_pci_sg_memory + */ + +static void *__videobuf_alloc(size_t size) +{ + struct videbuf_vmalloc_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + + mem = vb->priv = ((char *)vb)+size; + mem->magic=MAGIC_VMAL_MEM; + + dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), + mem,(long)sizeof(*mem)); + + return vb; +} + +static int __videobuf_iolock (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + int pages; + + struct videbuf_vmalloc_memory *mem=vb->priv; + + + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + + /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ + if ((vb->memory != V4L2_MEMORY_MMAP) && + (vb->memory != V4L2_MEMORY_USERPTR) ) { + printk(KERN_ERR "Method currently unsupported.\n"); + return -EINVAL; + } + + /* FIXME: should be tested with kernel mmap mem */ + mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); + if (NULL == mem->vmalloc) { + dprintk(1,"vmalloc (%d pages) failed\n",pages); + return -ENOMEM; + } + + dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)mem->vmalloc, + pages << PAGE_SHIFT); + + /* It seems that some kernel versions need to do remap *after* + the mmap() call + */ + if (mem->vma) { + int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0); + kfree(mem->vma); + mem->vma=NULL; + if (retval<0) { + dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n", + mem->vmalloc,retval); + return retval; + } + } + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + return 0; +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + unsigned int i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i]) { + struct videbuf_vmalloc_memory *mem=q->bufs[i]->priv; + if (mem && mem->map) + return -EBUSY; + } + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videbuf_vmalloc_memory *mem; + struct videobuf_mapping *map; + unsigned int first; + int retval; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) + return -EINVAL; + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (NULL == q->bufs[first]) + continue; + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == offset) + break; + } + if (VIDEO_MAX_FRAME == first) { + dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + return -EINVAL; + } + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + /* create mapping + update buffer list */ + map = mem->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + if (NULL == map) + return -ENOMEM; + + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + + q->bufs[first]->baddr = vma->vm_start; + + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_private_data = map; + + /* Try to remap memory */ + retval=remap_vmalloc_range(vma, mem->vmalloc,0); + if (retval<0) { + dprintk(1,"mmap: postponing remap_vmalloc_range\n"); + mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); + if (!mem->vma) { + kfree(map); + mem->map=NULL; + return -ENOMEM; + } + memcpy(mem->vma,vma,sizeof(*vma)); + } + + dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", + map,q,vma->vm_start,vma->vm_end, + (long int) q->bufs[first]->bsize, + vma->vm_pgoff,first); + + videobuf_vm_open(vma); + + return (0); +} + +static int __videobuf_is_mmapped (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + return (mem->map)?1:0; +} + +static int __videobuf_copy_to_user ( struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking ) +{ + struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + BUG_ON (!mem->vmalloc); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + if (copy_to_user(data, mem->vmalloc+q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream ( struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking ) +{ + unsigned int *fc; + struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int*)mem->vmalloc; + fc += (q->read_buf->size>>2) -1; + *fc = q->read_buf->field_count >> 1; + dprintk(1,"vbihack: %d\n",*fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user (q,data,count,nonblocking); + + if ( (count==-EFAULT) && (0 == pos) ) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops qops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .is_mmapped = __videobuf_is_mmapped, + .copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, +}; + +void videobuf_queue_vmalloc_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); + q->int_ops=&qops; +} + +EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); + +void *videobuf_to_vmalloc (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + return mem->vmalloc; +} +EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); + +void videobuf_vmalloc_free (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + vfree(mem->vmalloc); + + return; +} +EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h new file mode 100644 index 000000000000..5fff68df6689 --- /dev/null +++ b/include/media/videobuf-vmalloc.h @@ -0,0 +1,44 @@ +/* + * helper functions for vmalloc capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * 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 + */ + +#include + +/* --------------------------------------------------------------------- */ + +struct videbuf_vmalloc_memory +{ + u32 magic; + + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + + void *vmalloc; + + /* remap_vmalloc_range seems to need to run after mmap() on some cases */ + struct vm_area_struct *vma; +}; + +void videobuf_queue_vmalloc_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + +void *videobuf_to_vmalloc (struct videobuf_buffer *buf); + +void videobuf_vmalloc_free (struct videobuf_buffer *buf); From 5a0377060efcf844f4e359f3ab013de7f1b98da2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 2 Aug 2007 23:31:54 -0300 Subject: [PATCH 0775/2804] V4L/DVB (6255): Convert vivi to use videobuf-vmalloc This patch removes the usage of videobuf-dma-sg from vivi driver, using instead videobuf-vmalloc. This way, vivi will be useful for testing the newer method. Reverting this patch won't hurt vivi, since both methods work fine. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 44 +++++++++++++------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 89c40341007f..c14e2b3e4241 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -33,7 +33,7 @@ #include #endif #include -#include +#include #include #include #include @@ -145,7 +145,6 @@ struct vivi_buffer { struct videobuf_buffer vb; struct vivi_fmt *fmt; - }; struct vivi_dmaqueue { @@ -326,29 +325,22 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) int hmax = buf->vb.height; int wmax = buf->vb.width; struct timeval ts; - char *tmpbuf; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - - if (dma->varea) { - tmpbuf=kmalloc (wmax*2, GFP_KERNEL); - } else { - tmpbuf=dma->vmalloc; - } + char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL); + void *vbuf=videobuf_to_vmalloc (&buf->vb); + if (!tmpbuf) + return; for (h=0;hvarea) { - gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); - /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(dma->varea+pos,tmpbuf,wmax*2)!=0) - dprintk(2,"vivifill copy_to_user failed.\n"); - } else { - gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); - } + gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); + /* FIXME: replacing to __copy_to_user */ + if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) + dprintk(2,"vivifill copy_to_user failed.\n"); pos += wmax*2; } + kfree(tmpbuf); + /* Updates stream time */ dev->us+=jiffies_to_usecs(jiffies-dev->jiffies); @@ -371,7 +363,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) dev->h,dev->m,dev->s,(dev->us+500)/1000); dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)dma->varea,pos); + (unsigned long)tmpbuf,pos); /* Advice that buffer was filled */ buf->vb.state = STATE_DONE; @@ -610,17 +602,13 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - dprintk(1,"%s\n",__FUNCTION__); if (in_interrupt()) BUG(); - videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(vq, dma); - videobuf_dma_free(dma); + videobuf_vmalloc_free(&buf->vb); buf->vb.state = STATE_NEEDS_INIT; } @@ -726,7 +714,6 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb free_buffer(vq,buf); } - static struct videobuf_queue_ops vivi_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, @@ -1092,13 +1079,12 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); - videobuf_queue_pci_init(&fh->vb_vidq, &vivi_video_qops, + videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); - return 0; } @@ -1192,7 +1178,7 @@ static const struct file_operations vivi_fops = { .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = vivi_mmap, + .mmap = vivi_mmap, .llseek = no_llseek, }; From 79618cf41337ccedb9abeee059ce76aac7962739 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:31:15 -0300 Subject: [PATCH 0776/2804] V4L/DVB (6256): Remove the obsolete video-buf module Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/video-buf.c | 1424 ------------------------------- include/media/video-buf.h | 289 ------- 2 files changed, 1713 deletions(-) delete mode 100644 drivers/media/video/video-buf.c delete mode 100644 include/media/video-buf.h diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c deleted file mode 100644 index f6f31e1773d1..000000000000 --- a/drivers/media/video/video-buf.c +++ /dev/null @@ -1,1424 +0,0 @@ -/* - * - * generic helper functions for video4linux capture buffers, to handle - * memory management and PCI DMA. - * Right now, bttv, saa7134, saa7146 and cx88 use it. - * - * The functions expect the hardware being able to scatter gatter - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * device specific map/unmap/sync stuff now are mapped as operations - * to allow its usage by USB and virtual devices. - * - * (c) 2001-2004 Gerd Knorr [SUSE Labs] - * (c) 2006 Mauro Carvalho Chehab - * (c) 2006 Ted Walther and John Sokol - * - * 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 - -#define MAGIC_DMABUF 0x19721112 -#define MAGIC_BUFFER 0x20040302 -#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ - { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } - -static int debug = 0; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers"); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt , ## arg) - -struct scatterlist* -videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) -{ - struct scatterlist *sglist; - struct page *pg; - int i; - - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { - pg = vmalloc_to_page(virt); - if (NULL == pg) - goto err; - BUG_ON(PageHighMem(pg)); - sglist[i].page = pg; - sglist[i].length = PAGE_SIZE; - } - return sglist; - - err: - kfree(sglist); - return NULL; -} - -struct scatterlist* -videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) -{ - struct scatterlist *sglist; - int i = 0; - - if (NULL == pages[0]) - return NULL; - sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - - if (NULL == pages[0]) - goto nopage; - if (PageHighMem(pages[0])) - /* DMA to highmem pages might not work */ - goto highmem; - sglist[0].page = pages[0]; - sglist[0].offset = offset; - sglist[0].length = PAGE_SIZE - offset; - for (i = 1; i < nr_pages; i++) { - if (NULL == pages[i]) - goto nopage; - if (PageHighMem(pages[i])) - goto highmem; - sglist[i].page = pages[i]; - sglist[i].length = PAGE_SIZE; - } - return sglist; - - nopage: - dprintk(2,"sgl: oops - no page\n"); - kfree(sglist); - return NULL; - - highmem: - dprintk(2,"sgl: oops - highmem page\n"); - kfree(sglist); - return NULL; -} - -/* --------------------------------------------------------------------- */ - -void videobuf_dma_init(struct videobuf_dmabuf *dma) -{ - memset(dma,0,sizeof(*dma)); - dma->magic = MAGIC_DMABUF; -} - -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) -{ - unsigned long first,last; - int err, rw = 0; - - dma->direction = direction; - switch (dma->direction) { - case PCI_DMA_FROMDEVICE: rw = READ; break; - case PCI_DMA_TODEVICE: rw = WRITE; break; - default: BUG(); - } - - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma->offset = data & ~PAGE_MASK; - dma->nr_pages = last-first+1; - dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), - GFP_KERNEL); - if (NULL == dma->pages) - return -ENOMEM; - dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", - data,size,dma->nr_pages); - - dma->varea = (void *) data; - - down_read(¤t->mm->mmap_sem); - err = get_user_pages(current,current->mm, - data & PAGE_MASK, dma->nr_pages, - rw == READ, 1, /* force */ - dma->pages, NULL); - up_read(¤t->mm->mmap_sem); - if (err != dma->nr_pages) { - dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); - return err < 0 ? err : -EINVAL; - } - return 0; -} - -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages) -{ - dprintk(1,"init kernel [%d pages]\n",nr_pages); - dma->direction = direction; - dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); - if (NULL == dma->vmalloc) { - dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); - return -ENOMEM; - } - dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vmalloc, - nr_pages << PAGE_SHIFT); - memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); - dma->nr_pages = nr_pages; - return 0; -} - -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages) -{ - dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", - nr_pages,(unsigned long)addr); - dma->direction = direction; - if (0 == addr) - return -EINVAL; - - dma->bus_addr = addr; - dma->nr_pages = nr_pages; - return 0; -} - -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(0 == dma->nr_pages); - - if (dma->pages) { - dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, - dma->offset); - } - if (dma->vmalloc) { - dma->sglist = videobuf_vmalloc_to_sg - (dma->vmalloc,dma->nr_pages); - } - if (dma->bus_addr) { - dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); - if (NULL != dma->sglist) { - dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; - sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; - } - } - if (NULL == dma->sglist) { - dprintk(1,"scatterlist is NULL\n"); - return -ENOMEM; - } - if (!dma->bus_addr) { - if (q->ops->vb_map_sg) { - dma->sglen = q->ops->vb_map_sg(dev,dma->sglist, - dma->nr_pages, dma->direction); - } - if (0 == dma->sglen) { - printk(KERN_WARNING - "%s: videobuf_map_sg failed\n",__FUNCTION__); - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return -EIO; - } - } - return 0; -} - -int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(!dma->sglen); - - if (!dma->bus_addr && q->ops->vb_dma_sync_sg) - q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - - return 0; -} - -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - if (!dma->sglen) - return 0; - - if (!dma->bus_addr && q->ops->vb_unmap_sg) - q->ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return 0; -} - -int videobuf_dma_free(struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(dma->sglen); - - if (dma->pages) { - int i; - for (i=0; i < dma->nr_pages; i++) - page_cache_release(dma->pages[i]); - kfree(dma->pages); - dma->pages = NULL; - } - - vfree(dma->vmalloc); - dma->vmalloc = NULL; - dma->varea = NULL; - - if (dma->bus_addr) { - dma->bus_addr = 0; - } - dma->direction = PCI_DMA_NONE; - return 0; -} - -/* --------------------------------------------------------------------- */ - -void* videobuf_alloc(unsigned int size) -{ - struct videobuf_buffer *vb; - - vb = kzalloc(size,GFP_KERNEL); - if (NULL != vb) { - videobuf_dma_init(&vb->dma); - init_waitqueue_head(&vb->done); - vb->magic = MAGIC_BUFFER; - } - return vb; -} - -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) -{ - int retval = 0; - DECLARE_WAITQUEUE(wait, current); - - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - add_wait_queue(&vb->done, &wait); - while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { - if (non_blocking) { - retval = -EAGAIN; - break; - } - set_current_state(intr ? TASK_INTERRUPTIBLE - : TASK_UNINTERRUPTIBLE); - if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) - schedule(); - set_current_state(TASK_RUNNING); - if (intr && signal_pending(current)) { - dprintk(1,"buffer waiton: -EINTR\n"); - retval = -EINTR; - break; - } - } - remove_wait_queue(&vb->done, &wait); - return retval; -} - -int -videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - int err,pages; - dma_addr_t bus; - - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_USERPTR: - if (0 == vb->baddr) { - /* no userspace addr -- kernel bounce buffer */ - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE, - pages); - if (0 != err) - return err; - } else { - /* dma directly to userspace */ - err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE, - vb->baddr,vb->bsize); - if (0 != err) - return err; - } - break; - case V4L2_MEMORY_OVERLAY: - if (NULL == fbuf) - return -EINVAL; - /* FIXME: need sanity checks for vb->boff */ - /* - * Using a double cast to avoid compiler warnings when - * building for PAE. Compiler doesn't like direct casting - * of a 32 bit ptr to 64 bit integer. - */ - bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE, - bus, pages); - if (0 != err) - return err; - break; - default: - BUG(); - } - err = videobuf_dma_map(q,&vb->dma); - if (0 != err) - return err; - - return 0; -} - -/* --------------------------------------------------------------------- */ - -void videobuf_queue_pci(struct videobuf_queue* q) -{ - /* If not specified, defaults to PCI map sg */ - if (!q->ops->vb_map_sg) - q->ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!q->ops->vb_dma_sync_sg) - q->ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!q->ops->vb_unmap_sg) - q->ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; -} - -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) -{ - struct videobuf_queue q; - struct videobuf_queue_ops qops; - - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.ops = &qops; - - return (videobuf_dma_map(&q,dma)); -} - -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) -{ - struct videobuf_queue q; - struct videobuf_queue_ops qops; - - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.ops = &qops; - - return (videobuf_dma_unmap(&q,dma)); -} - -void videobuf_queue_init(struct videobuf_queue* q, - struct videobuf_queue_ops *ops, - void *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv) -{ - memset(q,0,sizeof(*q)); - q->irqlock = irqlock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; - q->priv_data = priv; - - videobuf_queue_pci(q); - - mutex_init(&q->lock); - INIT_LIST_HEAD(&q->stream); -} - -int -videobuf_queue_is_busy(struct videobuf_queue *q) -{ - int i; - - if (q->streaming) { - dprintk(1,"busy: streaming active\n"); - return 1; - } - if (q->reading) { - dprintk(1,"busy: pending read #1\n"); - return 1; - } - if (q->read_buf) { - dprintk(1,"busy: pending read #2\n"); - return 1; - } - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->map) { - dprintk(1,"busy: buffer #%d mapped\n",i); - return 1; - } - if (q->bufs[i]->state == STATE_QUEUED) { - dprintk(1,"busy: buffer #%d queued\n",i); - return 1; - } - if (q->bufs[i]->state == STATE_ACTIVE) { - dprintk(1,"busy: buffer #%d avtive\n",i); - return 1; - } - } - return 0; -} - -void -videobuf_queue_cancel(struct videobuf_queue *q) -{ - unsigned long flags=0; - int i; - - /* remove queued buffers from list */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->state == STATE_QUEUED) { - list_del(&q->bufs[i]->queue); - q->bufs[i]->state = STATE_ERROR; - } - } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - - /* free all buffers + clear queue */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - } - INIT_LIST_HEAD(&q->stream); -} - -/* --------------------------------------------------------------------- */ - -enum v4l2_field -videobuf_next_field(struct videobuf_queue *q) -{ - enum v4l2_field field = q->field; - - BUG_ON(V4L2_FIELD_ANY == field); - - if (V4L2_FIELD_ALTERNATE == field) { - if (V4L2_FIELD_TOP == q->last) { - field = V4L2_FIELD_BOTTOM; - q->last = V4L2_FIELD_BOTTOM; - } else { - field = V4L2_FIELD_TOP; - q->last = V4L2_FIELD_TOP; - } - } - return field; -} - -void -videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - enum v4l2_buf_type type) -{ - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - - b->index = vb->i; - b->type = type; - - b->memory = vb->memory; - switch (b->memory) { - case V4L2_MEMORY_MMAP: - b->m.offset = vb->boff; - b->length = vb->bsize; - break; - case V4L2_MEMORY_USERPTR: - b->m.userptr = vb->baddr; - b->length = vb->bsize; - break; - case V4L2_MEMORY_OVERLAY: - b->m.offset = vb->boff; - break; - } - - b->flags = 0; - if (vb->map) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (vb->state) { - case STATE_PREPARED: - case STATE_QUEUED: - case STATE_ACTIVE: - b->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case STATE_DONE: - case STATE_ERROR: - b->flags |= V4L2_BUF_FLAG_DONE; - break; - case STATE_NEEDS_INIT: - case STATE_IDLE: - /* nothing */ - break; - } - - if (vb->input != UNSET) { - b->flags |= V4L2_BUF_FLAG_INPUT; - b->input = vb->input; - } - - b->field = vb->field; - b->timestamp = vb->ts; - b->bytesused = vb->size; - b->sequence = vb->field_count >> 1; -} - -int -videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req) -{ - unsigned int size,count; - int retval; - - if (req->type != q->type) { - dprintk(1,"reqbufs: queue type invalid\n"); - return -EINVAL; - } - if (req->count < 1) { - dprintk(1,"reqbufs: count invalid (%d)\n",req->count); - return -EINVAL; - } - if (req->memory != V4L2_MEMORY_MMAP && - req->memory != V4L2_MEMORY_USERPTR && - req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1,"reqbufs: memory type invalid\n"); - return -EINVAL; - } - - if (q->streaming) { - dprintk(1,"reqbufs: streaming already exists\n"); - return -EBUSY; - } - if (!list_empty(&q->stream)) { - dprintk(1,"reqbufs: stream running\n"); - return -EBUSY; - } - - mutex_lock(&q->lock); - count = req->count; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = 0; - q->ops->buf_setup(q,&count,&size); - size = PAGE_ALIGN(size); - dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", - count, size, (count*size)>>PAGE_SHIFT); - - retval = videobuf_mmap_setup(q,count,size,req->memory); - if (retval < 0) { - dprintk(1,"reqbufs: mmap setup returned %d\n",retval); - goto done; - } - - req->count = count; - - done: - mutex_unlock(&q->lock); - return retval; -} - -int -videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - if (unlikely(b->type != q->type)) { - dprintk(1,"querybuf: Wrong type.\n"); - return -EINVAL; - } - if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { - dprintk(1,"querybuf: index out of range.\n"); - return -EINVAL; - } - if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1,"querybuf: buffer is null.\n"); - return -EINVAL; - } - videobuf_status(b,q->bufs[b->index],q->type); - return 0; -} - -int -videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b) -{ - struct videobuf_buffer *buf; - enum v4l2_field field; - unsigned long flags=0; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) { - dprintk(1,"qbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1,"qbuf: Wrong type.\n"); - goto done; - } - if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { - dprintk(1,"qbuf: index out of range.\n"); - goto done; - } - buf = q->bufs[b->index]; - if (NULL == buf) { - dprintk(1,"qbuf: buffer is null.\n"); - goto done; - } - MAGIC_CHECK(buf->magic,MAGIC_BUFFER); - if (buf->memory != b->memory) { - dprintk(1,"qbuf: memory type is wrong.\n"); - goto done; - } - if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { - dprintk(1,"qbuf: buffer is already queued or active.\n"); - goto done; - } - - if (b->flags & V4L2_BUF_FLAG_INPUT) { - if (b->input >= q->inputs) { - dprintk(1,"qbuf: wrong input.\n"); - goto done; - } - buf->input = b->input; - } else { - buf->input = UNSET; - } - - switch (b->memory) { - case V4L2_MEMORY_MMAP: - if (0 == buf->baddr) { - dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); - goto done; - } - break; - case V4L2_MEMORY_USERPTR: - if (b->length < buf->bsize) { - dprintk(1,"qbuf: buffer length is not enough\n"); - goto done; - } - if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) - q->ops->buf_release(q,buf); - buf->baddr = b->m.userptr; - break; - case V4L2_MEMORY_OVERLAY: - buf->boff = b->m.offset; - break; - default: - dprintk(1,"qbuf: wrong memory type\n"); - goto done; - } - - dprintk(1,"qbuf: requesting next field\n"); - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,buf,field); - if (0 != retval) { - dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); - goto done; - } - - list_add_tail(&buf->stream,&q->stream); - if (q->streaming) { - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - } - dprintk(1,"qbuf: succeded\n"); - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -int -videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking) -{ - struct videobuf_buffer *buf; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) { - dprintk(1,"dqbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1,"dqbuf: Wrong type.\n"); - goto done; - } - if (list_empty(&q->stream)) { - dprintk(1,"dqbuf: stream running\n"); - goto done; - } - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(buf, nonblocking, 1); - if (retval < 0) { - dprintk(1,"dqbuf: waiton returned %d\n",retval); - goto done; - } - switch (buf->state) { - case STATE_ERROR: - dprintk(1,"dqbuf: state is error\n"); - retval = -EIO; - videobuf_dma_sync(q,&buf->dma); - buf->state = STATE_IDLE; - break; - case STATE_DONE: - dprintk(1,"dqbuf: state is done\n"); - videobuf_dma_sync(q,&buf->dma); - buf->state = STATE_IDLE; - break; - default: - dprintk(1,"dqbuf: state invalid\n"); - retval = -EINVAL; - goto done; - } - list_del(&buf->stream); - memset(b,0,sizeof(*b)); - videobuf_status(b,buf,q->type); - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_streamon(struct videobuf_queue *q) -{ - struct videobuf_buffer *buf; - struct list_head *list; - unsigned long flags=0; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) - goto done; - retval = 0; - if (q->streaming) - goto done; - q->streaming = 1; - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - list_for_each(list,&q->stream) { - buf = list_entry(list, struct videobuf_buffer, stream); - if (buf->state == STATE_PREPARED) - q->ops->buf_queue(q,buf); - } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_streamoff(struct videobuf_queue *q) -{ - int retval = -EINVAL; - - mutex_lock(&q->lock); - if (!q->streaming) - goto done; - videobuf_queue_cancel(q); - q->streaming = 0; - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -static ssize_t -videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, - size_t count, loff_t *ppos) -{ - enum v4l2_field field; - unsigned long flags=0; - int retval; - - /* setup stuff */ - q->read_buf = videobuf_alloc(q->msize); - if (NULL == q->read_buf) - return -ENOMEM; - - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->baddr = (unsigned long)data; - q->read_buf->bsize = count; - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) - goto done; - - /* start capture & wait */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - retval = videobuf_waiton(q->read_buf,0,0); - if (0 == retval) { - videobuf_dma_sync(q,&q->read_buf->dma); - if (STATE_ERROR == q->read_buf->state) - retval = -EIO; - else - retval = q->read_buf->size; - } - - done: - /* cleanup */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - return retval; -} - -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking) -{ - enum v4l2_field field; - unsigned long flags=0; - unsigned size, nbufs, bytes; - int retval; - - mutex_lock(&q->lock); - - nbufs = 1; size = 0; - q->ops->buf_setup(q,&nbufs,&size); - if (NULL == q->read_buf && - count >= size && - !nonblocking) { - retval = videobuf_read_zerocopy(q,data,count,ppos); - if (retval >= 0 || retval == -EIO) - /* ok, all done */ - goto done; - /* fallback to kernel bounce buffer on failures */ - } - - if (NULL == q->read_buf) { - /* need to capture a new frame */ - retval = -ENOMEM; - q->read_buf = videobuf_alloc(q->msize); - dprintk(1,"video alloc=0x%p\n", q->read_buf); - if (NULL == q->read_buf) - goto done; - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->bsize = count; /* preferred size */ - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) { - kfree (q->read_buf); - q->read_buf = NULL; - goto done; - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->read_off = 0; - } - - /* wait until capture is done */ - retval = videobuf_waiton(q->read_buf, nonblocking, 1); - if (0 != retval) - goto done; - videobuf_dma_sync(q,&q->read_buf->dma); - - if (STATE_ERROR == q->read_buf->state) { - /* catch I/O errors */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - retval = -EIO; - goto done; - } - - /* copy to userspace */ - bytes = count; - if (bytes > q->read_buf->size - q->read_off) - bytes = q->read_buf->size - q->read_off; - retval = -EFAULT; - if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes)) - goto done; - - retval = bytes; - q->read_off += bytes; - if (q->read_off == q->read_buf->size) { - /* all data copied, cleanup */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - } - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_read_start(struct videobuf_queue *q) -{ - enum v4l2_field field; - unsigned long flags=0; - int count = 0, size = 0; - int err, i; - - q->ops->buf_setup(q,&count,&size); - if (count < 2) - count = 2; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = PAGE_ALIGN(size); - - err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err) - return err; - for (i = 0; i < count; i++) { - field = videobuf_next_field(q); - err = q->ops->buf_prepare(q,q->bufs[i],field); - if (err) - return err; - list_add_tail(&q->bufs[i]->stream, &q->stream); - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - for (i = 0; i < count; i++) - q->ops->buf_queue(q,q->bufs[i]); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->reading = 1; - return 0; -} - -void videobuf_read_stop(struct videobuf_queue *q) -{ - int i; - - videobuf_queue_cancel(q); - videobuf_mmap_free(q); - INIT_LIST_HEAD(&q->stream); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - q->read_buf = NULL; - q->reading = 0; -} - -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking) -{ - unsigned int *fc, bytes; - int err, retval; - unsigned long flags=0; - - dprintk(2,"%s\n",__FUNCTION__); - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->streaming) - goto done; - if (!q->reading) { - retval = videobuf_read_start(q); - if (retval < 0) - goto done; - } - - retval = 0; - while (count > 0) { - /* get / wait for data */ - if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - err = videobuf_waiton(q->read_buf, nonblocking, 1); - if (err < 0) { - if (0 == retval) - retval = err; - break; - } - - if (q->read_buf->state == STATE_DONE) { - if (vbihack) { - /* dirty, undocumented hack -- pass the frame counter - * within the last four bytes of each vbi data block. - * We need that one to maintain backward compatibility - * to all vbi decoding software out there ... */ - fc = (unsigned int*)q->read_buf->dma.vmalloc; - fc += (q->read_buf->size>>2) -1; - *fc = q->read_buf->field_count >> 1; - dprintk(1,"vbihack: %d\n",*fc); - } - - /* copy stuff */ - bytes = count; - if (bytes > q->read_buf->size - q->read_off) - bytes = q->read_buf->size - q->read_off; - if (copy_to_user(data + retval, - q->read_buf->dma.vmalloc + q->read_off, - bytes)) { - if (0 == retval) - retval = -EFAULT; - break; - } - count -= bytes; - retval += bytes; - q->read_off += bytes; - } else { - /* some error */ - q->read_off = q->read_buf->size; - if (0 == retval) - retval = -EIO; - } - - /* requeue buffer when done with copying */ - if (q->read_off == q->read_buf->size) { - list_add_tail(&q->read_buf->stream, - &q->stream); - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->read_buf = NULL; - } - if (retval < 0) - break; - } - - done: - mutex_unlock(&q->lock); - return retval; -} - -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait) -{ - struct videobuf_buffer *buf = NULL; - unsigned int rc = 0; - - mutex_lock(&q->lock); - if (q->streaming) { - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, - struct videobuf_buffer, stream); - } else { - if (!q->reading) - videobuf_read_start(q); - if (!q->reading) { - rc = POLLERR; - } else if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - buf = q->read_buf; - } - if (!buf) - rc = POLLERR; - - if (0 == rc) { - poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) - rc = POLLIN|POLLRDNORM; - } - mutex_unlock(&q->lock); - return rc; -} - -/* --------------------------------------------------------------------- */ - -static void -videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); - map->count++; -} - -static void -videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); - - map->count--; - if (0 == map->count) { - dprintk(1,"munmap %p q=%p\n",map,q); - mutex_lock(&q->lock); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]) - ; - if (q->bufs[i]->map != map) - continue; - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - q->ops->buf_release(q,q->bufs[i]); - } - mutex_unlock(&q->lock); - kfree(map); - } - return; -} - -/* - * Get a anonymous page for the mapping. Make sure we can DMA to that - * memory location with 32bit PCI devices (i.e. don't use highmem for - * now ...). Bounce buffers don't work very well for the data rates - * video capture has. - */ -static struct page* -videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, - int *type) -{ - struct page *page; - - dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", - vaddr,vma->vm_start,vma->vm_end); - if (vaddr > vma->vm_end) - return NOPAGE_SIGBUS; - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return NOPAGE_OOM; - clear_user_page(page_address(page), vaddr, page); - if (type) - *type = VM_FAULT_MINOR; - return page; -} - -static struct vm_operations_struct videobuf_vm_ops = -{ - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .nopage = videobuf_vm_nopage, -}; - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - unsigned int i; - int err; - - err = videobuf_mmap_free(q); - if (0 != err) - return err; - - for (i = 0; i < bcount; i++) { - q->bufs[i] = videobuf_alloc(q->msize); - q->bufs[i]->i = i; - q->bufs[i]->input = UNSET; - q->bufs[i]->memory = memory; - q->bufs[i]->bsize = bsize; - switch (memory) { - case V4L2_MEMORY_MMAP: - q->bufs[i]->boff = bsize * i; - break; - case V4L2_MEMORY_USERPTR: - case V4L2_MEMORY_OVERLAY: - /* nothing */ - break; - } - } - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", - bcount,bsize); - return 0; -} - -int videobuf_mmap_free(struct videobuf_queue *q) -{ - int i; - - for (i = 0; i < VIDEO_MAX_FRAME; i++) - if (q->bufs[i] && q->bufs[i]->map) - return -EBUSY; - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - return 0; -} - -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma) -{ - struct videobuf_mapping *map; - unsigned int first,last,size,i; - int retval; - - mutex_lock(&q->lock); - retval = -EINVAL; - if (!(vma->vm_flags & VM_WRITE)) { - dprintk(1,"mmap app bug: PROT_WRITE please\n"); - goto done; - } - if (!(vma->vm_flags & VM_SHARED)) { - dprintk(1,"mmap app bug: MAP_SHARED please\n"); - goto done; - } - - /* look for first buffer to map */ - for (first = 0; first < VIDEO_MAX_FRAME; first++) { - if (NULL == q->bufs[first]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) - continue; - if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) - break; - } - if (VIDEO_MAX_FRAME == first) { - dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - goto done; - } - - /* look for last buffer to map */ - for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { - if (NULL == q->bufs[last]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) - continue; - if (q->bufs[last]->map) { - retval = -EBUSY; - goto done; - } - size += q->bufs[last]->bsize; - if (size == (vma->vm_end - vma->vm_start)) - break; - } - if (VIDEO_MAX_FRAME == last) { - dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", - (vma->vm_end - vma->vm_start)); - goto done; - } - - /* create mapping + update buffer list */ - retval = -ENOMEM; - map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); - if (NULL == map) - goto done; - for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { - q->bufs[i]->map = map; - q->bufs[i]->baddr = vma->vm_start + size; - } - map->count = 1; - map->start = vma->vm_start; - map->end = vma->vm_end; - map->q = q; - vma->vm_ops = &videobuf_vm_ops; - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ - vma->vm_private_data = map; - dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -/* --------------------------------------------------------------------- */ - -EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); - -EXPORT_SYMBOL_GPL(videobuf_dma_init); -EXPORT_SYMBOL_GPL(videobuf_dma_init_user); -EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); -EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); -EXPORT_SYMBOL_GPL(videobuf_dma_map); -EXPORT_SYMBOL_GPL(videobuf_dma_sync); -EXPORT_SYMBOL_GPL(videobuf_dma_unmap); -EXPORT_SYMBOL_GPL(videobuf_dma_free); - -EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); -EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); - -EXPORT_SYMBOL_GPL(videobuf_alloc); -EXPORT_SYMBOL_GPL(videobuf_waiton); -EXPORT_SYMBOL_GPL(videobuf_iolock); - -EXPORT_SYMBOL_GPL(videobuf_queue_init); -EXPORT_SYMBOL_GPL(videobuf_queue_cancel); -EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); - -EXPORT_SYMBOL_GPL(videobuf_next_field); -EXPORT_SYMBOL_GPL(videobuf_status); -EXPORT_SYMBOL_GPL(videobuf_reqbufs); -EXPORT_SYMBOL_GPL(videobuf_querybuf); -EXPORT_SYMBOL_GPL(videobuf_qbuf); -EXPORT_SYMBOL_GPL(videobuf_dqbuf); -EXPORT_SYMBOL_GPL(videobuf_streamon); -EXPORT_SYMBOL_GPL(videobuf_streamoff); - -EXPORT_SYMBOL_GPL(videobuf_read_start); -EXPORT_SYMBOL_GPL(videobuf_read_stop); -EXPORT_SYMBOL_GPL(videobuf_read_stream); -EXPORT_SYMBOL_GPL(videobuf_read_one); -EXPORT_SYMBOL_GPL(videobuf_poll_stream); - -EXPORT_SYMBOL_GPL(videobuf_mmap_setup); -EXPORT_SYMBOL_GPL(videobuf_mmap_free); -EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/include/media/video-buf.h b/include/media/video-buf.h deleted file mode 100644 index d6f079476db3..000000000000 --- a/include/media/video-buf.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * - * generic helper functions for video4linux capture buffers, to handle - * memory management and PCI DMA. - * Right now, bttv, saa7134, saa7146 and cx88 use it. - * - * The functions expect the hardware being able to scatter gatter - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * device specific map/unmap/sync stuff now are mapped as file operations - * to allow its usage by USB and virtual devices. - * - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - * - * 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 UNSET (-1U) - -/* --------------------------------------------------------------------- */ - -/* - * Return a scatterlist for some page-aligned vmalloc()'ed memory - * block (NULL on errors). Memory for the scatterlist is allocated - * using kmalloc. The caller must free the memory. - */ -struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); - -/* - * Return a scatterlist for a an array of userpages (NULL on errors). - * Memory for the scatterlist is allocated using kmalloc. The caller - * must free the memory. - */ -struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, - int offset); - -struct videobuf_buffer; -struct videobuf_queue; - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage buffers (both userland - * and kernel) for DMA. - * - * videobuf_dma_init_*() - * creates a buffer. The userland version takes a userspace - * pointer + length. The kernel version just wants the size and - * does memory allocation too using vmalloc_32(). - * - * videobuf_dma_*() - * see Documentation/DMA-mapping.txt, these functions to - * basically the same. The map function does also build a - * scatterlist for the buffer (and unmap frees it ...) - * - * videobuf_dma_free() - * no comment ... - * - */ - -struct videobuf_dmabuf { - u32 magic; - - /* for userland buffer */ - int offset; - struct page **pages; - - /* for kernel buffers */ - void *vmalloc; - - /* Stores the userspace pointer to vmalloc area */ - void *varea; - - /* for overlay buffers (pci-pci dma) */ - dma_addr_t bus_addr; - - /* common */ - struct scatterlist *sglist; - int sglen; - int nr_pages; - int direction; -}; - -void videobuf_dma_init(struct videobuf_dmabuf *dma); -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size); -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages); -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages); -int videobuf_dma_free(struct videobuf_dmabuf *dma); - -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma); -int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma); -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma); - - /*FIXME: these variants are used only on *-alsa code, where videobuf is - * used without queue - */ -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage video4linux buffers. - * - * struct videobuf_buffer holds the data structures used by the helper - * functions, additionally some commonly used fields for v4l buffers - * (width, height, lists, waitqueue) are in there. That struct should - * be used as first element in the drivers buffer struct. - * - * about the mmap helpers (videobuf_mmap_*): - * - * The mmaper function allows to map any subset of contingous buffers. - * This includes one mmap() call for all buffers (which the original - * video4linux API uses) as well as one mmap() for every single buffer - * (which v4l2 uses). - * - * If there is a valid mapping for a buffer, buffer->baddr/bsize holds - * userspace address + size which can be feeded into the - * videobuf_dma_init_user function listed above. - * - */ - -struct videobuf_mapping { - unsigned int count; - unsigned long start; - unsigned long end; - struct videobuf_queue *q; -}; - -enum videobuf_state { - STATE_NEEDS_INIT = 0, - STATE_PREPARED = 1, - STATE_QUEUED = 2, - STATE_ACTIVE = 3, - STATE_DONE = 4, - STATE_ERROR = 5, - STATE_IDLE = 6, -}; - -struct videobuf_buffer { - unsigned int i; - u32 magic; - - /* info about the buffer */ - unsigned int width; - unsigned int height; - unsigned int bytesperline; /* use only if != 0 */ - unsigned long size; - unsigned int input; - enum v4l2_field field; - enum videobuf_state state; - struct videobuf_dmabuf dma; - struct list_head stream; /* QBUF/DQBUF list */ - - /* for mmap'ed buffers */ - enum v4l2_memory memory; - size_t boff; /* buffer offset (mmap + overlay) */ - size_t bsize; /* buffer size */ - unsigned long baddr; /* buffer addr (userland ptr!) */ - struct videobuf_mapping *map; - - /* touched by irq handler */ - struct list_head queue; - wait_queue_head_t done; - unsigned int field_count; - struct timeval ts; -}; - -typedef int (vb_map_sg_t)(void *dev,struct scatterlist *sglist,int nr_pages, - int direction); - - -struct videobuf_queue_ops { - int (*buf_setup)(struct videobuf_queue *q, - unsigned int *count, unsigned int *size); - int (*buf_prepare)(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field); - void (*buf_queue)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - void (*buf_release)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - - /* Helper operations - device dependent. - * If null, videobuf_init defaults all to PCI handling - */ - - vb_map_sg_t *vb_map_sg; - vb_map_sg_t *vb_dma_sync_sg; - vb_map_sg_t *vb_unmap_sg; -}; - -struct videobuf_queue { - struct mutex lock; - spinlock_t *irqlock; - void *dev; /* on pci, points to struct pci_dev */ - - enum v4l2_buf_type type; - unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ - unsigned int msize; - enum v4l2_field field; - enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ - struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; - struct videobuf_queue_ops *ops; - - /* capture via mmap() + ioctl(QBUF/DQBUF) */ - unsigned int streaming; - struct list_head stream; - - /* capture via read() */ - unsigned int reading; - unsigned int read_off; - struct videobuf_buffer *read_buf; - - /* driver private data */ - void *priv_data; -}; - -void* videobuf_alloc(unsigned int size); -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); -int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - -/* Maps fops to PCI stuff */ -void videobuf_queue_pci(struct videobuf_queue* q); - -void videobuf_queue_init(struct videobuf_queue *q, - struct videobuf_queue_ops *ops, - void *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv); -int videobuf_queue_is_busy(struct videobuf_queue *q); -void videobuf_queue_cancel(struct videobuf_queue *q); - -enum v4l2_field videobuf_next_field(struct videobuf_queue *q); -void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - enum v4l2_buf_type type); -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req); -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); -int videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b); -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking); -int videobuf_streamon(struct videobuf_queue *q); -int videobuf_streamoff(struct videobuf_queue *q); - -int videobuf_read_start(struct videobuf_queue *q); -void videobuf_read_stop(struct videobuf_queue *q); -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking); -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking); -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory); -int videobuf_mmap_free(struct videobuf_queue *q); -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma); - -/* --------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ From 9eb59573d4b86f347e6cd04f47a4c2082009fa58 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 10 Oct 2007 02:18:27 +0200 Subject: [PATCH 0777/2804] [CPUFREQ] Don't take semaphore in cpufreq_quick_get() I don't see any reason to take an expensive lock in cpufreq_quick_get() Reading policy->cur is a single atomic operation and after the lock is dropped again the state could change any time anyways. So don't take the lock in the first place. This also makes this function interrupt safe which is useful for some code of mine. Signed-off-by: Andi Kleen Cc: "Pallipadi, Venkatesh" Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e027052a6604..f7b9d6fce123 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1111,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu) unsigned int ret_freq = 0; if (policy) { - if (unlikely(lock_policy_rwsem_read(cpu))) - return ret_freq; - ret_freq = policy->cur; - - unlock_policy_rwsem_read(cpu); cpufreq_cpu_put(policy); } From e54664c0958acf14ef3a65d1b78f4a54b437cdf7 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sun, 29 Jul 2007 15:12:26 -0500 Subject: [PATCH 0778/2804] RDMA/cxgb3: Make the iw_cxgb3 module parameters writable Allow changing parameter values without having to reload the module. This is safe because these parameters are only looked at when a new connection is established. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch_cm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 1cdfcd43b0bc..20ba372dd182 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -63,37 +63,37 @@ static char *states[] = { }; static int ep_timeout_secs = 10; -module_param(ep_timeout_secs, int, 0444); +module_param(ep_timeout_secs, int, 0644); MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout " "in seconds (default=10)"); static int mpa_rev = 1; -module_param(mpa_rev, int, 0444); +module_param(mpa_rev, int, 0644); MODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, " "1 is spec compliant. (default=1)"); static int markers_enabled = 0; -module_param(markers_enabled, int, 0444); +module_param(markers_enabled, int, 0644); MODULE_PARM_DESC(markers_enabled, "Enable MPA MARKERS (default(0)=disabled)"); static int crc_enabled = 1; -module_param(crc_enabled, int, 0444); +module_param(crc_enabled, int, 0644); MODULE_PARM_DESC(crc_enabled, "Enable MPA CRC (default(1)=enabled)"); static int rcv_win = 256 * 1024; -module_param(rcv_win, int, 0444); +module_param(rcv_win, int, 0644); MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256)"); static int snd_win = 32 * 1024; -module_param(snd_win, int, 0444); +module_param(snd_win, int, 0644); MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)"); static unsigned int nocong = 0; -module_param(nocong, uint, 0444); +module_param(nocong, uint, 0644); MODULE_PARM_DESC(nocong, "Turn off congestion control (default=0)"); static unsigned int cong_flavor = 1; -module_param(cong_flavor, uint, 0444); +module_param(cong_flavor, uint, 0644); MODULE_PARM_DESC(cong_flavor, "TCP Congestion control flavor (default=1)"); static void process_work(struct work_struct *work); From ce423ef50ee1b6b7db63c748034423aa0afce224 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:04 -0700 Subject: [PATCH 0779/2804] IPoIB: Make sure no receives are handled when stopping device The current IPoIB code might process receive completions from ipoib_drain_cq() when bringing down the interface. This could cause packets to be passed up the stack without the device's poll method being called. Avoid this by setting the status of any successful completions to IB_WC_WR_FLUSH_ERR. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 10944888cffd..5a70e287f25d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -558,6 +558,14 @@ void ipoib_drain_cq(struct net_device *dev) do { n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc); for (i = 0; i < n; ++i) { + /* + * Convert any successful completions to flush + * errors to avoid passing packets up the + * stack after bringing the device down. + */ + if (priv->ibwc[i].status == IB_WC_SUCCESS) + priv->ibwc[i].status = IB_WC_WR_FLUSH_ERR; + if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ) ipoib_cm_handle_rx_wc(dev, priv->ibwc + i); else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV) From 65d470b3ea52ee1402499d6fcb4632296452e5b1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:04 -0700 Subject: [PATCH 0780/2804] IB: find_first_zero_bit() takes unsigned pointer Fix sparse warning drivers/infiniband/core/device.c:142:6: warning: incorrect type in argument 1 (different signedness) drivers/infiniband/core/device.c:142:6: expected unsigned long const *addr drivers/infiniband/core/device.c:142:6: got long *[assigned] inuse by making the local variable inuse unsigned. Does not affect generated code at all. Signed-off-by: Roland Dreier --- drivers/infiniband/core/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 2506c43ba041..5ac5ffee05cb 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -120,12 +120,12 @@ static struct ib_device *__ib_device_get_by_name(const char *name) static int alloc_name(char *name) { - long *inuse; + unsigned long *inuse; char buf[IB_DEVICE_NAME_MAX]; struct ib_device *device; int i; - inuse = (long *) get_zeroed_page(GFP_KERNEL); + inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL); if (!inuse) return -ENOMEM; From 36ce10d3e849c2f9efa3fd647058de398ee276eb Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Tue, 7 Aug 2007 11:18:52 +0300 Subject: [PATCH 0781/2804] mlx4_core: Use enum value GO_BIT_TIMEOUT_MSECS Rename GO_BIT_TIMEOUT to GO_BIT_TIMEOUT_MSECS for clarity, and actually use it as the go bit timeout (instead of having the define but then ignoring it and using a hard-coded 10 * HZ for the actual timeout). Signed-off-by: Dotan Barak Signed-off-by: Roland Dreier --- drivers/net/mlx4/cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c index a9f31753661a..b540820e9c25 100644 --- a/drivers/net/mlx4/cmd.c +++ b/drivers/net/mlx4/cmd.c @@ -95,7 +95,7 @@ enum { }; enum { - GO_BIT_TIMEOUT = 10000 + GO_BIT_TIMEOUT_MSECS = 10000 }; struct mlx4_cmd_context { @@ -155,7 +155,7 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, end = jiffies; if (event) - end += HZ * 10; + end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); while (cmd_pending(dev)) { if (time_after_eq(jiffies, end)) From eaf559bf566f76887533c077d425adce847f06c8 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:05 -0700 Subject: [PATCH 0782/2804] mlx4_core: Don't free special QPs in QP number bitmap Special QPs are not allocated using the regular QP number bitmap, so when they are destroyed, their QP number should not be freed in the bitmap. Found by Dotan Barak of Mellanox. Signed-off-by: Roland Dreier --- drivers/net/mlx4/qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index 19b48c71cf7f..278414b2d01c 100644 --- a/drivers/net/mlx4/qp.c +++ b/drivers/net/mlx4/qp.c @@ -240,7 +240,8 @@ void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); - mlx4_bitmap_free(&qp_table->bitmap, qp->qpn); + if (qp->qpn < dev->caps.sqp_start + 8) + mlx4_bitmap_free(&qp_table->bitmap, qp->qpn); } EXPORT_SYMBOL_GPL(mlx4_qp_free); From 2242fa4f04d670f02efb43ec537d677edc220880 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:05 -0700 Subject: [PATCH 0783/2804] IB/mlx4: Use __set_data_seg() in mlx4_ib_post_recv() Use a __set_data_seg() helper in mlx4_ib_post_recv() too; in addition to making the code easier to read, this also allows gcc to generate better code -- on x86_64: add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-8 (-8) function old new delta mlx4_ib_post_recv 359 351 -8 Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/qp.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 85c51bdc36f1..31a480e5b0d0 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1249,6 +1249,13 @@ static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) dseg->byte_count = cpu_to_be32(sg->length); } +static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) +{ + dseg->byte_count = cpu_to_be32(sg->length); + dseg->lkey = cpu_to_be32(sg->lkey); + dseg->addr = cpu_to_be64(sg->addr); +} + int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { @@ -1464,11 +1471,8 @@ int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, scat = get_recv_wqe(qp, ind); - for (i = 0; i < wr->num_sge; ++i) { - scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length); - scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey); - scat[i].addr = cpu_to_be64(wr->sg_list[i].addr); - } + for (i = 0; i < wr->num_sge; ++i) + __set_data_seg(scat + i, wr->sg_list + i); if (i < qp->rq.max_gs) { scat[i].byte_count = 0; From 1fea391039d1c4e876a164099bff475a02a29d96 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:05 -0700 Subject: [PATCH 0784/2804] IB/ehca: Include from ehca_classes.h ehca_classes.h uses struct mutex, so while seems to be pulled in indirectly by one of the headers it includes, the right thing is to include directly. Signed-off-by: Michael S. Tsirkin Acked-by: Stefan Roscher Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index b5e960305316..0d69f0f001d9 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -53,6 +53,7 @@ struct ehca_pd; struct ehca_av; #include +#include #include #include From 8a68bbe31d51cc75d2acf1c9f5ceff91f7662ea4 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 29 Aug 2007 08:36:22 -0500 Subject: [PATCH 0785/2804] IB/fmr_pool: Clean up some error messages in fmr_pool.c A number of printks in fmr_pool.c dont have newlines, eg: fmr_create failed for FMR 0<5>FS-Cache: Loaded Fix them up. Signed-off-by: Anton Blanchard Signed-off-by: Roland Dreier --- drivers/infiniband/core/fmr_pool.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index a06bcc65a871..d7f64525469b 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -152,7 +152,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) #ifdef DEBUG if (fmr->ref_count !=0) { - printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d", + printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d\n", fmr, fmr->ref_count); } #endif @@ -170,7 +170,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) ret = ib_unmap_fmr(&fmr_list); if (ret) - printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret); + printk(KERN_WARNING PFX "ib_unmap_fmr returned %d\n", ret); spin_lock_irq(&pool->pool_lock); list_splice(&unmap_list, &pool->free_list); @@ -235,13 +235,13 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, attr = kmalloc(sizeof *attr, GFP_KERNEL); if (!attr) { - printk(KERN_WARNING PFX "couldn't allocate device attr struct"); + printk(KERN_WARNING PFX "couldn't allocate device attr struct\n"); return ERR_PTR(-ENOMEM); } ret = ib_query_device(device, attr); if (ret) { - printk(KERN_WARNING PFX "couldn't query device: %d", ret); + printk(KERN_WARNING PFX "couldn't query device: %d\n", ret); kfree(attr); return ERR_PTR(ret); } @@ -255,7 +255,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, pool = kmalloc(sizeof *pool, GFP_KERNEL); if (!pool) { - printk(KERN_WARNING PFX "couldn't allocate pool struct"); + printk(KERN_WARNING PFX "couldn't allocate pool struct\n"); return ERR_PTR(-ENOMEM); } @@ -272,7 +272,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket, GFP_KERNEL); if (!pool->cache_bucket) { - printk(KERN_WARNING PFX "Failed to allocate cache in pool"); + printk(KERN_WARNING PFX "Failed to allocate cache in pool\n"); ret = -ENOMEM; goto out_free_pool; } @@ -296,7 +296,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, "ib_fmr(%s)", device->name); if (IS_ERR(pool->thread)) { - printk(KERN_WARNING PFX "couldn't start cleanup thread"); + printk(KERN_WARNING PFX "couldn't start cleanup thread\n"); ret = PTR_ERR(pool->thread); goto out_free_pool; } @@ -314,7 +314,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, GFP_KERNEL); if (!fmr) { printk(KERN_WARNING PFX "failed to allocate fmr " - "struct for FMR %d", i); + "struct for FMR %d\n", i); goto out_fail; } @@ -326,7 +326,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr); if (IS_ERR(fmr->fmr)) { printk(KERN_WARNING PFX "fmr_create failed " - "for FMR %d", i); + "for FMR %d\n", i); kfree(fmr); goto out_fail; } @@ -381,7 +381,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool) } if (i < pool->pool_size) - printk(KERN_WARNING PFX "pool still has %d regions registered", + printk(KERN_WARNING PFX "pool still has %d regions registered\n", pool->pool_size - i); kfree(pool->cache_bucket); @@ -518,7 +518,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) #ifdef DEBUG if (fmr->ref_count < 0) - printk(KERN_WARNING PFX "FMR %p has ref count %d < 0", + printk(KERN_WARNING PFX "FMR %p has ref count %d < 0\n", fmr, fmr->ref_count); #endif From 08fb105540f4649eaa25270ec3ada1d35406afcc Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 7 Aug 2007 16:08:28 +0300 Subject: [PATCH 0786/2804] mlx4_core: Enable MSI-X by default Recover from MSI-X errors by automatically falling back on regular interrupt, instead of asking the user to do this manually. This makes it possible to enable MSI-X by default, and will make it possible to get rid of the msi_x module option in the future. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/net/mlx4/main.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 4dc9dc19b716..4b1269435586 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -61,7 +61,7 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); #ifdef CONFIG_PCI_MSI -static int msi_x; +static int msi_x = 1; module_param(msi_x, int, 0444); MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); @@ -599,13 +599,17 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev) err = mlx4_NOP(dev); if (err) { - mlx4_err(dev, "NOP command failed to generate interrupt " - "(IRQ %d), aborting.\n", - priv->eq_table.eq[MLX4_EQ_ASYNC].irq); - if (dev->flags & MLX4_FLAG_MSI_X) - mlx4_err(dev, "Try again with MSI-X disabled.\n"); - else + if (dev->flags & MLX4_FLAG_MSI_X) { + mlx4_warn(dev, "NOP command failed to generate MSI-X " + "interrupt IRQ %d).\n", + priv->eq_table.eq[MLX4_EQ_ASYNC].irq); + mlx4_warn(dev, "Trying again without MSI-X.\n"); + } else { + mlx4_err(dev, "NOP command failed to generate interrupt " + "(IRQ %d), aborting.\n", + priv->eq_table.eq[MLX4_EQ_ASYNC].irq); mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n"); + } goto err_cmd_poll; } @@ -803,8 +807,6 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev, goto err_free_dev; } - mlx4_enable_msi_x(dev); - if (mlx4_cmd_init(dev)) { mlx4_err(dev, "Failed to init command interface, aborting.\n"); goto err_free_dev; @@ -814,7 +816,15 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev, if (err) goto err_cmd; + mlx4_enable_msi_x(dev); + err = mlx4_setup_hca(dev); + if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) { + dev->flags &= ~MLX4_FLAG_MSI_X; + pci_disable_msix(pdev); + err = mlx4_setup_hca(dev); + } + if (err) goto err_close; @@ -838,15 +848,15 @@ err_cleanup: mlx4_cleanup_uar_table(dev); err_close: + if (dev->flags & MLX4_FLAG_MSI_X) + pci_disable_msix(pdev); + mlx4_close_hca(dev); err_cmd: mlx4_cmd_cleanup(dev); err_free_dev: - if (dev->flags & MLX4_FLAG_MSI_X) - pci_disable_msix(pdev); - kfree(priv); err_release_bar2: From 017aadc4b505ad3ec2acc4e6ba96d63ae1c997a5 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 7 Aug 2007 16:10:34 +0300 Subject: [PATCH 0787/2804] IB/mthca: Enable MSI-X by default Recover from MSI-X errors by automatically falling back on regular interrupt, instead of asking the user to do this manually. This makes it possible to enable MSI-X by default, and will make it possible to get rid of the msi_x module option in the future. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 77 ++++++++++++++---------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 76fed7545c53..04c1520524cd 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -61,7 +61,7 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); #ifdef CONFIG_PCI_MSI -static int msi_x = 0; +static int msi_x = 1; module_param(msi_x, int, 0444); MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); @@ -833,14 +833,19 @@ static int mthca_setup_hca(struct mthca_dev *dev) err = mthca_NOP(dev, &status); if (err || status) { - mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n", - dev->mthca_flags & MTHCA_FLAG_MSI_X ? - dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector : - dev->pdev->irq); - if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) - mthca_err(dev, "Try again with MSI/MSI-X disabled.\n"); - else + if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) { + mthca_warn(dev, "NOP command failed to generate interrupt " + "(IRQ %d).\n", + dev->mthca_flags & MTHCA_FLAG_MSI_X ? + dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector : + dev->pdev->irq); + mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n"); + } else { + mthca_err(dev, "NOP command failed to generate interrupt " + "(IRQ %d), aborting.\n", + dev->pdev->irq); mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n"); + } goto err_cmd_poll; } @@ -1115,24 +1120,6 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) goto err_free_dev; } - if (msi_x && !mthca_enable_msi_x(mdev)) - mdev->mthca_flags |= MTHCA_FLAG_MSI_X; - else if (msi) { - static int warned; - - if (!warned) { - printk(KERN_WARNING PFX "WARNING: MSI support will be " - "removed from the ib_mthca driver in January 2008.\n"); - printk(KERN_WARNING " If you are using MSI and cannot " - "switch to MSI-X, please tell " - ".\n"); - ++warned; - } - - if (!pci_enable_msi(pdev)) - mdev->mthca_flags |= MTHCA_FLAG_MSI; - } - if (mthca_cmd_init(mdev)) { mthca_err(mdev, "Failed to init command interface, aborting.\n"); goto err_free_dev; @@ -1156,7 +1143,35 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); } + if (msi_x && !mthca_enable_msi_x(mdev)) + mdev->mthca_flags |= MTHCA_FLAG_MSI_X; + else if (msi) { + static int warned; + + if (!warned) { + printk(KERN_WARNING PFX "WARNING: MSI support will be " + "removed from the ib_mthca driver in January 2008.\n"); + printk(KERN_WARNING " If you are using MSI and cannot " + "switch to MSI-X, please tell " + ".\n"); + ++warned; + } + + if (!pci_enable_msi(pdev)) + mdev->mthca_flags |= MTHCA_FLAG_MSI; + } + err = mthca_setup_hca(mdev); + if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) { + if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) + pci_disable_msix(pdev); + if (mdev->mthca_flags & MTHCA_FLAG_MSI) + pci_disable_msi(pdev); + mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI); + + err = mthca_setup_hca(mdev); + } + if (err) goto err_close; @@ -1192,17 +1207,17 @@ err_cleanup: mthca_cleanup_uar_table(mdev); err_close: + if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) + pci_disable_msix(pdev); + if (mdev->mthca_flags & MTHCA_FLAG_MSI) + pci_disable_msi(pdev); + mthca_close_hca(mdev); err_cmd: mthca_cmd_cleanup(mdev); err_free_dev: - if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) - pci_disable_msix(pdev); - if (mdev->mthca_flags & MTHCA_FLAG_MSI) - pci_disable_msi(pdev); - ib_dealloc_device(&mdev->ib_dev); err_free_res: From b3ac60fc243f2312d27ecded058ef96f52f25fe0 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 9 Oct 2007 19:59:06 -0700 Subject: [PATCH 0788/2804] IPoIB: Fix typo to end statement with ';' instead of ',' Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 563aeacf9e14..3c6e45db0ab5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -185,7 +185,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) goto out_free_cq; init_attr.send_cq = priv->cq; - init_attr.recv_cq = priv->cq, + init_attr.recv_cq = priv->cq; priv->qp = ib_create_qp(priv->pd, &init_attr); if (IS_ERR(priv->qp)) { From ca6de177acef8f2c7c3901ea583a263364ca7bbb Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 21 Aug 2007 18:46:10 +0300 Subject: [PATCH 0789/2804] IPoIB: Fix error path memory leak Clean up properly if ib_query_pkey() or ib_query_gid() fail. Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 894b1dcdf3eb..5f948b9a9943 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1083,7 +1083,7 @@ static struct net_device *ipoib_add_port(const char *format, if (result) { printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n", hca->name, port, result); - goto alloc_mem_failed; + goto device_init_failed; } /* @@ -1099,7 +1099,7 @@ static struct net_device *ipoib_add_port(const char *format, if (result) { printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n", hca->name, port, result); - goto alloc_mem_failed; + goto device_init_failed; } else memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid)); From d7dc3ccbe4dd1d37950da0138079e61d5be06ca9 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:06 -0700 Subject: [PATCH 0790/2804] IB/mlx4: Fix up SRQ limit_watermark endianness mlx4_srq_query() returns a big-endian 16-bit value through an int *, which screws up sparse checking. Fix this so that a CPU-endian value is returned. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/srq.c | 2 +- drivers/net/mlx4/srq.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 408748fb5285..e7e9a3d0dac3 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c @@ -251,7 +251,7 @@ int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) if (ret) return ret; - srq_attr->srq_limit = be16_to_cpu(limit_watermark); + srq_attr->srq_limit = limit_watermark; srq_attr->max_wr = srq->msrq.max - 1; srq_attr->max_sge = srq->msrq.max_gs; diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c index b061c86d6839..31b255a32915 100644 --- a/drivers/net/mlx4/srq.c +++ b/drivers/net/mlx4/srq.c @@ -227,7 +227,7 @@ int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_waterm err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn); if (err) goto err_out; - *limit_watermark = srq_context->limit_watermark; + *limit_watermark = be16_to_cpu(srq_context->limit_watermark); err_out: mlx4_free_cmd_mailbox(dev, mailbox); From 1f794483025bc1e9e8e3321089a7f29ad3cc448f Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 29 Aug 2007 11:05:35 -0500 Subject: [PATCH 0791/2804] IB/ehca: Make output clearer by removing some debug messages ehca spits out a lot of debugging information. I had to look closely to see the "Port 1 is not active" message within all the debug: eHCA Infiniband Device Driver (Rel.: SVNEHCA_0022) eHCA scaling code enabled ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_define_sqp Port 1 is not active. ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_create_qp ehca_define_sqp() failed rc=ffffffffffffffff ib_mad: Couldn't create ib_mad QP1 ib_mad: Couldn't open ehca0 port 1 ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_alloc_fmr unsupported fmr_attr->page_shift=9 ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_alloc_fmr rc=ffffffffffffffea pd=c000000b4b5b2420 mr_access_flags=7 fmr_attr=c0000005afd37394 fmr_create failed for FMR 0 Remove a few debug statements so that things are clearer: eHCA Infiniband Device Driver (Rel.: SVNEHCA_0022) eHCA scaling code enabled ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_define_sqp Port 1 is not active. ib_mad: Couldn't create ib_mad QP1 ib_mad: Couldn't open ehca0 port 1 ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_alloc_fmr unsupported fmr_attr->page_shift=9 fmr_create failed for FMR 0 Signed-off-by: Anton Blanchard Acked-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_mrmw.c | 4 ---- drivers/infiniband/hw/ehca/ehca_qp.c | 2 -- 2 files changed, 6 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index d97eda3e1da0..dc4c84040aad 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -846,10 +846,6 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd, alloc_fmr_exit1: ehca_mr_delete(e_fmr); alloc_fmr_exit0: - if (IS_ERR(ib_fmr)) - ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x " - "fmr_attr=%p", PTR_ERR(ib_fmr), pd, - mr_access_flags, fmr_attr); return ib_fmr; } /* end ehca_alloc_fmr() */ diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 84d435a5ee11..88f07451fb8b 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -714,8 +714,6 @@ static struct ehca_qp *internal_create_qp( if (qp_type == IB_QPT_GSI) { h_ret = ehca_define_sqp(shca, my_qp, init_attr); if (h_ret != H_SUCCESS) { - ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx", - h_ret); ret = ehca2ib_return_code(h_ret); goto create_qp_exit4; } From 339e2640a9f403f7b7acb2ea67f3568b8ac3eebf Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 29 Aug 2007 12:43:01 -0500 Subject: [PATCH 0792/2804] IB/ehca: Export module parameters in sysfs At the moment the ehca module parameters are not exported in sysfs. Export them with 0444 permissions. Signed-off-by: Anton Blanchard Acked-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_main.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 99036b65bb84..db041dfb4129 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -65,16 +65,16 @@ int ehca_static_rate = -1; int ehca_scaling_code = 0; int ehca_mr_largepage = 0; -module_param_named(open_aqp1, ehca_open_aqp1, int, 0); -module_param_named(debug_level, ehca_debug_level, int, 0); -module_param_named(hw_level, ehca_hw_level, int, 0); -module_param_named(nr_ports, ehca_nr_ports, int, 0); -module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0); -module_param_named(port_act_time, ehca_port_act_time, int, 0); -module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0); -module_param_named(static_rate, ehca_static_rate, int, 0); -module_param_named(scaling_code, ehca_scaling_code, int, 0); -module_param_named(mr_largepage, ehca_mr_largepage, int, 0); +module_param_named(open_aqp1, ehca_open_aqp1, int, S_IRUGO); +module_param_named(debug_level, ehca_debug_level, int, S_IRUGO); +module_param_named(hw_level, ehca_hw_level, int, S_IRUGO); +module_param_named(nr_ports, ehca_nr_ports, int, S_IRUGO); +module_param_named(use_hp_mr, ehca_use_hp_mr, int, S_IRUGO); +module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO); +module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, S_IRUGO); +module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); +module_param_named(scaling_code, ehca_scaling_code, int, S_IRUGO); +module_param_named(mr_largepage, ehca_mr_largepage, int, S_IRUGO); MODULE_PARM_DESC(open_aqp1, "AQP1 on startup (0: no (default), 1: yes)"); From 3c10c7c929b30e8813d15960cb97f95a0b2ba615 Mon Sep 17 00:00:00 2001 From: Ali Ayoub Date: Sun, 9 Sep 2007 14:55:11 +0300 Subject: [PATCH 0793/2804] IB/sa: Error handling thinko fix ib_create_send_mad() returns an error code pointer on error, not NULL. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/core/sa_query.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index d271bd715c12..312c8ff5ae88 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -531,7 +531,7 @@ static int alloc_mad(struct ib_sa_query *query, gfp_t gfp_mask) query->sm_ah->pkey_index, 0, IB_MGMT_SA_HDR, IB_MGMT_SA_DATA, gfp_mask); - if (!query->mad_buf) { + if (IS_ERR(query->mad_buf)) { kref_put(&query->sm_ah->ref, free_sm_ah); return -ENOMEM; } From a855b1a7423ac83c76638f156d79c854b0feb94d Mon Sep 17 00:00:00 2001 From: Peter Oruba Date: Fri, 10 Aug 2007 13:54:33 -0700 Subject: [PATCH 0794/2804] IB/mthca: Use PCI-X/PCI-Express read control interfaces These driver changes incorporate the proposed PCI-X / PCI-Express read byte count interface. Reading and setting those values doesn't take place "manually", instead wrapping functions are called to allow quirks for some PCI bridges. Signed-off by: Peter Oruba Based on work by Stephen Hemminger Cc: Roland Dreier Cc: Michael S. Tsirkin Signed-off-by: Andrew Morton Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 33 ++++++------------------ 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 04c1520524cd..60de6f93869e 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -137,40 +137,23 @@ static const char mthca_version[] __devinitdata = static int mthca_tune_pci(struct mthca_dev *mdev) { - int cap; - u16 val; - if (!tune_pci) return 0; /* First try to max out Read Byte Count */ - cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); - if (cap) { - if (pci_read_config_word(mdev->pdev, cap + PCI_X_CMD, &val)) { - mthca_err(mdev, "Couldn't read PCI-X command register, " - "aborting.\n"); - return -ENODEV; - } - val = (val & ~PCI_X_CMD_MAX_READ) | (3 << 2); - if (pci_write_config_word(mdev->pdev, cap + PCI_X_CMD, val)) { - mthca_err(mdev, "Couldn't write PCI-X command register, " - "aborting.\n"); + if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) { + if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) { + mthca_err(mdev, "Couldn't set PCI-X max read count, " + "aborting.\n"); return -ENODEV; } } else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) mthca_info(mdev, "No PCI-X capability, not setting RBC.\n"); - cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP); - if (cap) { - if (pci_read_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, &val)) { - mthca_err(mdev, "Couldn't read PCI Express device control " - "register, aborting.\n"); - return -ENODEV; - } - val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12); - if (pci_write_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, val)) { - mthca_err(mdev, "Couldn't write PCI Express device control " - "register, aborting.\n"); + if (pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP)) { + if (pcie_set_readrq(mdev->pdev, 4096)) { + mthca_err(mdev, "Couldn't write PCI Express read request, " + "aborting.\n"); return -ENODEV; } } else if (mdev->mthca_flags & MTHCA_FLAG_PCIE) From 441633b968a5be0ef9be7c37ae24c35eda5b730d Mon Sep 17 00:00:00 2001 From: Stefan Roscher Date: Tue, 11 Sep 2007 15:26:33 +0200 Subject: [PATCH 0795/2804] IB/ehca: Small QP userspace support Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 7 +++---- drivers/infiniband/hw/ehca/ipz_pt_fn.c | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 88f07451fb8b..87b32ab6caf6 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -273,6 +273,7 @@ static inline void queue2resp(struct ipzu_queue_resp *resp, resp->queue_length = queue->queue_length; resp->pagesize = queue->pagesize; resp->toggle_state = queue->toggle_state; + resp->offset = queue->offset; } /* @@ -598,8 +599,7 @@ static struct ehca_qp *internal_create_qp( parms.squeue.max_sge = max_send_sge; parms.rqueue.max_sge = max_recv_sge; - if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap) - && !(context && udata)) { /* no small QP support in userspace ATM */ + if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) { if (HAS_SQ(my_qp)) ehca_determine_small_queue( &parms.squeue, max_send_sge, is_llqp); @@ -739,8 +739,7 @@ static struct ehca_qp *internal_create_qp( resp.ext_type = my_qp->ext_type; resp.qkey = my_qp->qkey; resp.real_qp_num = my_qp->real_qp_num; - resp.ipz_rqueue.offset = my_qp->ipz_rqueue.offset; - resp.ipz_squeue.offset = my_qp->ipz_squeue.offset; + if (HAS_SQ(my_qp)) queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue); if (HAS_RQ(my_qp)) diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c index 29bd476fbd54..661f8db62706 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c @@ -158,6 +158,7 @@ static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd) queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9))); queue->small_page = page; + queue->offset = bit << (order + 9); return 1; out: From 5281a4b8a0c6bac0c070913ec25868faa06a3115 Mon Sep 17 00:00:00 2001 From: Stefan Roscher Date: Tue, 11 Sep 2007 15:29:39 +0200 Subject: [PATCH 0796/2804] IB/ehca: Support more than 4k QPs for userspace and kernelspace Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_cq.c | 7 ++++++- drivers/infiniband/hw/ehca/ehca_main.c | 2 +- drivers/infiniband/hw/ehca/ehca_qp.c | 9 +++++++-- drivers/infiniband/hw/ehca/ehca_uverbs.c | 22 +++++++++++----------- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 81aff36101ba..a6f17e488c77 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -166,7 +166,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, write_lock_irqsave(&ehca_cq_idr_lock, flags); ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token); write_unlock_irqrestore(&ehca_cq_idr_lock, flags); - } while (ret == -EAGAIN); if (ret) { @@ -176,6 +175,12 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, goto create_cq_exit1; } + if (my_cq->token > 0x1FFFFFF) { + cq = ERR_PTR(-ENOMEM); + ehca_err(device, "Invalid number of cq. device=%p", device); + goto create_cq_exit2; + } + /* * CQs maximum depth is 4GB-64, but we need additional 20 as buffer * for receiving errors CQEs. diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index db041dfb4129..991690739170 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -380,7 +380,7 @@ int ehca_init_device(struct ehca_shca *shca) strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX); shca->ib_device.owner = THIS_MODULE; - shca->ib_device.uverbs_abi_ver = 7; + shca->ib_device.uverbs_abi_ver = 8; shca->ib_device.uverbs_cmd_mask = (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 87b32ab6caf6..bfae1c228b2f 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -557,7 +557,6 @@ static struct ehca_qp *internal_create_qp( write_lock_irqsave(&ehca_qp_idr_lock, flags); ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token); write_unlock_irqrestore(&ehca_qp_idr_lock, flags); - } while (ret == -EAGAIN); if (ret) { @@ -566,11 +565,17 @@ static struct ehca_qp *internal_create_qp( goto create_qp_exit0; } + if (my_qp->token > 0x1FFFFFF) { + ret = -EINVAL; + ehca_err(pd->device, "Invalid number of qp"); + goto create_qp_exit1; + } + parms.servicetype = ibqptype2servicetype(qp_type); if (parms.servicetype < 0) { ret = -EINVAL; ehca_err(pd->device, "Invalid qp_type=%x", qp_type); - goto create_qp_exit0; + goto create_qp_exit1; } if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index 4bc687fdf531..3340f49f0211 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c @@ -164,7 +164,7 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, int ret; switch (rsrc_type) { - case 1: /* galpa fw handle */ + case 0: /* galpa fw handle */ ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number); ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa); if (unlikely(ret)) { @@ -175,7 +175,7 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, } break; - case 2: /* cq queue_addr */ + case 1: /* cq queue_addr */ ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number); ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue); if (unlikely(ret)) { @@ -201,7 +201,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, int ret; switch (rsrc_type) { - case 1: /* galpa fw handle */ + case 0: /* galpa fw handle */ ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num); ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa); if (unlikely(ret)) { @@ -212,7 +212,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, } break; - case 2: /* qp rqueue_addr */ + case 1: /* qp rqueue_addr */ ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue", qp->ib_qp.qp_num); ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, @@ -225,7 +225,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, } break; - case 3: /* qp squeue_addr */ + case 2: /* qp squeue_addr */ ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue", qp->ib_qp.qp_num); ret = ehca_mmap_queue(vma, &qp->ipz_squeue, @@ -249,10 +249,10 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { - u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT; - u32 idr_handle = fileoffset >> 32; - u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */ - u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */ + u64 fileoffset = vma->vm_pgoff; + u32 idr_handle = fileoffset & 0x1FFFFFF; + u32 q_type = (fileoffset >> 27) & 0x1; /* CQ, QP,... */ + u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */ u32 cur_pid = current->tgid; u32 ret; struct ehca_cq *cq; @@ -261,7 +261,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) struct ib_uobject *uobject; switch (q_type) { - case 1: /* CQ */ + case 0: /* CQ */ read_lock(&ehca_cq_idr_lock); cq = idr_find(&ehca_cq_idr, idr_handle); read_unlock(&ehca_cq_idr_lock); @@ -289,7 +289,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) } break; - case 2: /* QP */ + case 1: /* QP */ read_lock(&ehca_qp_idr_lock); qp = idr_find(&ehca_qp_idr, idr_handle); read_unlock(&ehca_qp_idr_lock); From e390d3b52f791fcea26312ba4982cda82052727b Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Tue, 11 Sep 2007 15:31:06 +0200 Subject: [PATCH 0797/2804] IB/ehca: Use remap_4k_pfn() to map firmware contexts to user space Use Paul's new remap_4k_pfn() function to map our 4K firmware contexts into user space on 64K-page machines without exposing neighboring firmware contexts. Return the context's offset within a 64K page to user space so it can determine the proper virtual address. For details about remap_4k_pfn(), see commit 721151d0 or http://patchwork.ozlabs.org/linuxppc/patch?id=10281 Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 4 +++- drivers/infiniband/hw/ehca/ehca_cq.c | 2 ++ drivers/infiniband/hw/ehca/ehca_qp.c | 2 ++ drivers/infiniband/hw/ehca/ehca_uverbs.c | 6 +++--- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 0d69f0f001d9..0942a173881c 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -338,6 +338,8 @@ struct ehca_create_cq_resp { u32 cq_number; u32 token; struct ipzu_queue_resp ipz_queue; + u32 fw_handle_ofs; + u32 dummy; }; struct ehca_create_qp_resp { @@ -348,7 +350,7 @@ struct ehca_create_qp_resp { u32 qkey; /* qp_num assigned by ehca: sqp0/1 may have got different numbers */ u32 real_qp_num; - u32 dummy; /* padding for 8 byte alignment */ + u32 fw_handle_ofs; struct ipzu_queue_resp ipz_squeue; struct ipzu_queue_resp ipz_rqueue; }; diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index a6f17e488c77..d68603ddfc2c 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -281,6 +281,8 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, resp.ipz_queue.queue_length = ipz_queue->queue_length; resp.ipz_queue.pagesize = ipz_queue->pagesize; resp.ipz_queue.toggle_state = ipz_queue->toggle_state; + resp.fw_handle_ofs = (u32) + (my_cq->galpas.user.fw_handle & (PAGE_SIZE - 1)); if (ib_copy_to_udata(udata, &resp, sizeof(resp))) { ehca_err(device, "Copy to udata failed."); goto create_cq_exit4; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index bfae1c228b2f..e89fdca7fa19 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -749,6 +749,8 @@ static struct ehca_qp *internal_create_qp( queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue); if (HAS_RQ(my_qp)) queue2resp(&resp.ipz_rqueue, &my_qp->ipz_rqueue); + resp.fw_handle_ofs = (u32) + (my_qp->galpas.user.fw_handle & (PAGE_SIZE - 1)); if (ib_copy_to_udata(udata, &resp, sizeof resp)) { ehca_err(pd->device, "Copy to udata failed"); diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index 3340f49f0211..84a16bcfd536 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c @@ -109,7 +109,7 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas, u64 vsize, physical; vsize = vma->vm_end - vma->vm_start; - if (vsize != EHCA_PAGESIZE) { + if (vsize < EHCA_PAGESIZE) { ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start); return -EINVAL; } @@ -118,8 +118,8 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas, vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical); /* VM_IO | VM_RESERVED are set by remap_pfn_range() */ - ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, - vsize, vma->vm_page_prot); + ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT, + vma->vm_page_prot); if (unlikely(ret)) { ehca_gen_err("remap_pfn_range() failed ret=%x", ret); return -ENOMEM; From 2863ad4bddf366790a733cfd71f2f480afdf36fc Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:31:49 +0200 Subject: [PATCH 0798/2804] IB/ehca: Refactor hvcall tracing Change hvcall trace output towards better readability: reg numbers instead of argument numbers, return code as signed decimal instead of unsigned hex. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/hcp_if.c | 55 ++++++++++++----------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index 24f454162f24..a762cc7e0165 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -84,6 +84,10 @@ #define H_MP_SHUTDOWN EHCA_BMASK_IBM(48, 48) #define H_MP_RESET_QKEY_CTR EHCA_BMASK_IBM(49, 49) +#define HCALL4_REGS_FORMAT "r4=%lx r5=%lx r6=%lx r7=%lx" +#define HCALL7_REGS_FORMAT HCALL4_REGS_FORMAT " r8=%lx r9=%lx r10=%lx" +#define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx" + static DEFINE_SPINLOCK(hcall_lock); static u32 get_longbusy_msecs(int longbusy_rc) @@ -118,8 +122,7 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, long ret; int i, sleep_msecs; - ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx " - "arg5=%lx arg6=%lx arg7=%lx", + ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); for (i = 0; i < 5; i++) { @@ -133,16 +136,13 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, } if (ret < H_SUCCESS) - ehca_gen_err("opcode=%lx ret=%lx" - " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" - " arg5=%lx arg6=%lx arg7=%lx ", - opcode, ret, - arg1, arg2, arg3, arg4, arg5, - arg6, arg7); + ehca_gen_err("opcode=%lx ret=%li " HCALL7_REGS_FORMAT, + opcode, ret, arg1, arg2, arg3, + arg4, arg5, arg6, arg7); + else + ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret); - ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret); return ret; - } return H_BUSY; @@ -164,10 +164,8 @@ static long ehca_plpar_hcall9(unsigned long opcode, int i, sleep_msecs, lock_is_set = 0; unsigned long flags = 0; - ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx " - "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx", - opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7, - arg8, arg9); + ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); for (i = 0; i < 5; i++) { if ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)) { @@ -188,26 +186,19 @@ static long ehca_plpar_hcall9(unsigned long opcode, continue; } - if (ret < H_SUCCESS) - ehca_gen_err("opcode=%lx ret=%lx" - " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" - " arg5=%lx arg6=%lx arg7=%lx arg8=%lx" - " arg9=%lx" - " out1=%lx out2=%lx out3=%lx out4=%lx" - " out5=%lx out6=%lx out7=%lx out8=%lx" - " out9=%lx", - opcode, ret, - arg1, arg2, arg3, arg4, arg5, - arg6, arg7, arg8, arg9, - outs[0], outs[1], outs[2], outs[3], + if (ret < H_SUCCESS) { + ehca_gen_err("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, + opcode, arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9); + ehca_gen_err("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT, + ret, outs[0], outs[1], outs[2], outs[3], + outs[4], outs[5], outs[6], outs[7], + outs[8]); + } else + ehca_gen_dbg("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT, + ret, outs[0], outs[1], outs[2], outs[3], outs[4], outs[5], outs[6], outs[7], outs[8]); - - ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx " - "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx " - "out9=%lx", - opcode, ret, outs[0], outs[1], outs[2], outs[3], - outs[4], outs[5], outs[6], outs[7], outs[8]); return ret; } From e37221928bf685d63ba5319746eafe463d61e330 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:32:22 +0200 Subject: [PATCH 0799/2804] IB/ehca: Print return codes as signed decimal integers ...because -12 is easier to read than FFFFFFF4. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_cq.c | 14 ++--- drivers/infiniband/hw/ehca/ehca_hca.c | 2 +- drivers/infiniband/hw/ehca/ehca_main.c | 24 ++++---- drivers/infiniband/hw/ehca/ehca_mcast.c | 4 +- drivers/infiniband/hw/ehca/ehca_mrmw.c | 73 ++++++++++++------------ drivers/infiniband/hw/ehca/ehca_qp.c | 42 +++++++------- drivers/infiniband/hw/ehca/ehca_reqs.c | 2 +- drivers/infiniband/hw/ehca/ehca_sqp.c | 2 +- drivers/infiniband/hw/ehca/ehca_uverbs.c | 18 +++--- drivers/infiniband/hw/ehca/hcp_if.c | 20 +++---- 10 files changed, 100 insertions(+), 101 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index d68603ddfc2c..79c25f51c21e 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -190,7 +190,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if (h_ret != H_SUCCESS) { ehca_err(device, "hipz_h_alloc_resource_cq() failed " - "h_ret=%lx device=%p", h_ret, device); + "h_ret=%li device=%p", h_ret, device); cq = ERR_PTR(ehca2ib_return_code(h_ret)); goto create_cq_exit2; } @@ -198,7 +198,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages, EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0); if (!ipz_rc) { - ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p", + ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%i device=%p", ipz_rc, device); cq = ERR_PTR(-EINVAL); goto create_cq_exit3; @@ -226,7 +226,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if (h_ret < H_SUCCESS) { ehca_err(device, "hipz_h_register_rpage_cq() failed " - "ehca_cq=%p cq_num=%x h_ret=%lx counter=%i " + "ehca_cq=%p cq_num=%x h_ret=%li counter=%i " "act_pages=%i", my_cq, my_cq->cq_number, h_ret, counter, param.act_pages); cq = ERR_PTR(-EINVAL); @@ -238,7 +238,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if ((h_ret != H_SUCCESS) || vpage) { ehca_err(device, "Registration of pages not " "complete ehca_cq=%p cq_num=%x " - "h_ret=%lx", my_cq, my_cq->cq_number, + "h_ret=%li", my_cq, my_cq->cq_number, h_ret); cq = ERR_PTR(-EAGAIN); goto create_cq_exit4; @@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, } else { if (h_ret != H_PAGE_REGISTERED) { ehca_err(device, "Registration of page failed " - "ehca_cq=%p cq_num=%x h_ret=%lx" + "ehca_cq=%p cq_num=%x h_ret=%li" "counter=%i act_pages=%i", my_cq, my_cq->cq_number, h_ret, counter, param.act_pages); @@ -298,7 +298,7 @@ create_cq_exit3: h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1); if (h_ret != H_SUCCESS) ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p " - "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret); + "cq_num=%x h_ret=%li", my_cq, my_cq->cq_number, h_ret); create_cq_exit2: write_lock_irqsave(&ehca_cq_idr_lock, flags); @@ -362,7 +362,7 @@ int ehca_destroy_cq(struct ib_cq *cq) cq_num); } if (h_ret != H_SUCCESS) { - ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lx " + ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%li " "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num); return ehca2ib_return_code(h_ret); } diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index cf22472d9414..3436c49eee06 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -352,7 +352,7 @@ int ehca_modify_port(struct ib_device *ibdev, hret = hipz_h_modify_port(shca->ipz_hca_handle, port, cap, props->init_type, port_modify_mask); if (hret != H_SUCCESS) { - ehca_err(&shca->ib_device, "Modify port failed hret=%lx", + ehca_err(&shca->ib_device, "Modify port failed h_ret=%li", hret); ret = -EINVAL; } diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 991690739170..0e3ffeef45d9 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -273,7 +273,7 @@ int ehca_sense_attributes(struct ehca_shca *shca) h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock); if (h_ret != H_SUCCESS) { - ehca_gen_err("Cannot query device properties. h_ret=%lx", + ehca_gen_err("Cannot query device properties. h_ret=%li", h_ret); ret = -EPERM; goto sense_attributes1; @@ -332,7 +332,7 @@ int ehca_sense_attributes(struct ehca_shca *shca) port = (struct hipz_query_port *)rblock; h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port); if (h_ret != H_SUCCESS) { - ehca_gen_err("Cannot query port properties. h_ret=%lx", + ehca_gen_err("Cannot query port properties. h_ret=%li", h_ret); ret = -EPERM; goto sense_attributes1; @@ -526,13 +526,13 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport) ret = ib_destroy_qp(sport->ibqp_aqp1); if (ret) { - ehca_gen_err("Cannot destroy AQP1 QP. ret=%x", ret); + ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret); return ret; } ret = ib_destroy_cq(sport->ibcq_aqp1); if (ret) - ehca_gen_err("Cannot destroy AQP1 CQ. ret=%x", ret); + ehca_gen_err("Cannot destroy AQP1 CQ. ret=%i", ret); return ret; } @@ -728,7 +728,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev, ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr); if (ret) { - ehca_err(&shca->ib_device, "Cannot create internal MR ret=%x", + ehca_err(&shca->ib_device, "Cannot create internal MR ret=%i", ret); goto probe5; } @@ -736,7 +736,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev, ret = ib_register_device(&shca->ib_device); if (ret) { ehca_err(&shca->ib_device, - "ib_register_device() failed ret=%x", ret); + "ib_register_device() failed ret=%i", ret); goto probe6; } @@ -777,7 +777,7 @@ probe8: ret = ehca_destroy_aqp1(&shca->sport[0]); if (ret) ehca_err(&shca->ib_device, - "Cannot destroy AQP1 for port 1. ret=%x", ret); + "Cannot destroy AQP1 for port 1. ret=%i", ret); probe7: ib_unregister_device(&shca->ib_device); @@ -826,7 +826,7 @@ static int __devexit ehca_remove(struct ibmebus_dev *dev) if (ret) ehca_err(&shca->ib_device, "Cannot destroy AQP1 for port %x " - "ret=%x", ret, i); + "ret=%i", ret, i); } } @@ -835,20 +835,20 @@ static int __devexit ehca_remove(struct ibmebus_dev *dev) ret = ehca_dereg_internal_maxmr(shca); if (ret) ehca_err(&shca->ib_device, - "Cannot destroy internal MR. ret=%x", ret); + "Cannot destroy internal MR. ret=%i", ret); ret = ehca_dealloc_pd(&shca->pd->ib_pd); if (ret) ehca_err(&shca->ib_device, - "Cannot destroy internal PD. ret=%x", ret); + "Cannot destroy internal PD. ret=%i", ret); ret = ehca_destroy_eq(shca, &shca->eq); if (ret) - ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%x", ret); + ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%i", ret); ret = ehca_destroy_eq(shca, &shca->neq); if (ret) - ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%x", ret); + ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%i", ret); ib_dealloc_device(&shca->ib_device); diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c index 32a870660bfe..e3ef0264ccc6 100644 --- a/drivers/infiniband/hw/ehca/ehca_mcast.c +++ b/drivers/infiniband/hw/ehca/ehca_mcast.c @@ -88,7 +88,7 @@ int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) if (h_ret != H_SUCCESS) ehca_err(ibqp->device, "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed " - "h_ret=%lx", my_qp, ibqp->qp_num, h_ret); + "h_ret=%li", my_qp, ibqp->qp_num, h_ret); return ehca2ib_return_code(h_ret); } @@ -125,7 +125,7 @@ int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) if (h_ret != H_SUCCESS) ehca_err(ibqp->device, "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed " - "h_ret=%lx", my_qp, ibqp->qp_num, h_ret); + "h_ret=%li", my_qp, ibqp->qp_num, h_ret); return ehca2ib_return_code(h_ret); } diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index dc4c84040aad..e925e84c9bc7 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -159,7 +159,7 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags) get_dma_mr_exit0: if (IS_ERR(ib_mr)) - ehca_err(&shca->ib_device, "rc=%lx pd=%p mr_access_flags=%x ", + ehca_err(&shca->ib_device, "h_ret=%li pd=%p mr_access_flags=%x", PTR_ERR(ib_mr), pd, mr_access_flags); return ib_mr; } /* end ehca_get_dma_mr() */ @@ -271,7 +271,7 @@ reg_phys_mr_exit1: ehca_mr_delete(e_mr); reg_phys_mr_exit0: if (IS_ERR(ib_mr)) - ehca_err(pd->device, "rc=%lx pd=%p phys_buf_array=%p " + ehca_err(pd->device, "h_ret=%li pd=%p phys_buf_array=%p " "num_phys_buf=%x mr_access_flags=%x iova_start=%p", PTR_ERR(ib_mr), pd, phys_buf_array, num_phys_buf, mr_access_flags, iova_start); @@ -403,8 +403,7 @@ reg_user_mr_exit1: ehca_mr_delete(e_mr); reg_user_mr_exit0: if (IS_ERR(ib_mr)) - ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x" - " udata=%p", + ehca_err(pd->device, "rc=%li pd=%p mr_access_flags=%x udata=%p", PTR_ERR(ib_mr), pd, mr_access_flags, udata); return ib_mr; } /* end ehca_reg_user_mr() */ @@ -565,7 +564,7 @@ rereg_phys_mr_exit1: spin_unlock_irqrestore(&e_mr->mrlock, sl_flags); rereg_phys_mr_exit0: if (ret) - ehca_err(mr->device, "ret=%x mr=%p mr_rereg_mask=%x pd=%p " + ehca_err(mr->device, "ret=%i mr=%p mr_rereg_mask=%x pd=%p " "phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x " "iova_start=%p", ret, mr, mr_rereg_mask, pd, phys_buf_array, @@ -607,7 +606,7 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lx mr=%p " + ehca_err(mr->device, "hipz_mr_query failed, h_ret=%li mr=%p " "hca_hndl=%lx mr_hndl=%lx lkey=%x", h_ret, mr, shca->ipz_hca_handle.handle, e_mr->ipz_mr_handle.handle, mr->lkey); @@ -625,7 +624,7 @@ query_mr_exit1: spin_unlock_irqrestore(&e_mr->mrlock, sl_flags); query_mr_exit0: if (ret) - ehca_err(mr->device, "ret=%x mr=%p mr_attr=%p", + ehca_err(mr->device, "ret=%i mr=%p mr_attr=%p", ret, mr, mr_attr); return ret; } /* end ehca_query_mr() */ @@ -667,7 +666,7 @@ int ehca_dereg_mr(struct ib_mr *mr) /* TODO: BUSY: MR still has bound window(s) */ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); if (h_ret != H_SUCCESS) { - ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lx shca=%p " + ehca_err(mr->device, "hipz_free_mr failed, h_ret=%li shca=%p " "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x", h_ret, shca, e_mr, shca->ipz_hca_handle.handle, e_mr->ipz_mr_handle.handle, mr->lkey); @@ -683,7 +682,7 @@ int ehca_dereg_mr(struct ib_mr *mr) dereg_mr_exit0: if (ret) - ehca_err(mr->device, "ret=%x mr=%p", ret, mr); + ehca_err(mr->device, "ret=%i mr=%p", ret, mr); return ret; } /* end ehca_dereg_mr() */ @@ -708,7 +707,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd) h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw, e_pd->fw_pd, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx " + ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%li " "shca=%p hca_hndl=%lx mw=%p", h_ret, shca, shca->ipz_hca_handle.handle, e_mw); ib_mw = ERR_PTR(ehca2ib_return_code(h_ret)); @@ -723,7 +722,7 @@ alloc_mw_exit1: ehca_mw_delete(e_mw); alloc_mw_exit0: if (IS_ERR(ib_mw)) - ehca_err(pd->device, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd); + ehca_err(pd->device, "h_ret=%li pd=%p", PTR_ERR(ib_mw), pd); return ib_mw; } /* end ehca_alloc_mw() */ @@ -750,7 +749,7 @@ int ehca_dealloc_mw(struct ib_mw *mw) h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw); if (h_ret != H_SUCCESS) { - ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lx shca=%p " + ehca_err(mw->device, "hipz_free_mw failed, h_ret=%li shca=%p " "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx", h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle, e_mw->ipz_mw_handle.handle); @@ -912,7 +911,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr, map_phys_fmr_exit0: if (ret) - ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x " + ehca_err(fmr->device, "ret=%i fmr=%p page_list=%p list_len=%x " "iova=%lx", ret, fmr, page_list, list_len, iova); return ret; } /* end ehca_map_phys_fmr() */ @@ -975,7 +974,7 @@ int ehca_unmap_fmr(struct list_head *fmr_list) unmap_fmr_exit0: if (ret) - ehca_gen_err("ret=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x", + ehca_gen_err("ret=%i fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x", ret, fmr_list, num_fmr, unmap_fmr_cnt); return ret; } /* end ehca_unmap_fmr() */ @@ -999,7 +998,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr) h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr); if (h_ret != H_SUCCESS) { - ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lx e_fmr=%p " + ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%li e_fmr=%p " "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x", h_ret, e_fmr, shca->ipz_hca_handle.handle, e_fmr->ipz_mr_handle.handle, fmr->lkey); @@ -1012,7 +1011,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr) free_fmr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x fmr=%p", ret, fmr); + ehca_err(&shca->ib_device, "ret=%i fmr=%p", ret, fmr); return ret; } /* end ehca_dealloc_fmr() */ @@ -1042,7 +1041,7 @@ int ehca_reg_mr(struct ehca_shca *shca, (u64)iova_start, size, hipz_acl, e_pd->fw_pd, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx " + ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%li " "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle); ret = ehca2ib_return_code(h_ret); goto ehca_reg_mr_exit0; @@ -1068,9 +1067,9 @@ int ehca_reg_mr(struct ehca_shca *shca, ehca_reg_mr_exit1: h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); if (h_ret != H_SUCCESS) { - ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p " + ehca_err(&shca->ib_device, "h_ret=%li shca=%p e_mr=%p " "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x " - "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%x", + "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%i", h_ret, shca, e_mr, iova_start, size, acl, e_pd, hipzout.lkey, pginfo, pginfo->num_kpages, pginfo->num_hwpages, ret); @@ -1079,7 +1078,7 @@ ehca_reg_mr_exit1: } ehca_reg_mr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " + ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p " "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo, @@ -1123,7 +1122,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, ret = ehca_set_pagebuf(pginfo, rnum, kpage); if (ret) { ehca_err(&shca->ib_device, "ehca_set_pagebuf " - "bad rc, ret=%x rnum=%x kpage=%p", + "bad rc, ret=%i rnum=%x kpage=%p", ret, rnum, kpage); goto ehca_reg_mr_rpages_exit1; } @@ -1151,7 +1150,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, */ if (h_ret != H_SUCCESS) { ehca_err(&shca->ib_device, "last " - "hipz_reg_rpage_mr failed, h_ret=%lx " + "hipz_reg_rpage_mr failed, h_ret=%li " "e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx" " lkey=%x", h_ret, e_mr, i, shca->ipz_hca_handle.handle, @@ -1163,7 +1162,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, ret = 0; } else if (h_ret != H_PAGE_REGISTERED) { ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, " - "h_ret=%lx e_mr=%p i=%x lkey=%x hca_hndl=%lx " + "h_ret=%li e_mr=%p i=%x lkey=%x hca_hndl=%lx " "mr_hndl=%lx", h_ret, e_mr, i, e_mr->ib.ib_mr.lkey, shca->ipz_hca_handle.handle, @@ -1179,7 +1178,7 @@ ehca_reg_mr_rpages_exit1: ehca_free_fw_ctrlblock(kpage); ehca_reg_mr_rpages_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p " + ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p pginfo=%p " "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr, pginfo, pginfo->num_kpages, pginfo->num_hwpages); return ret; @@ -1240,7 +1239,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, * (MW bound or MR is shared) */ ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed " - "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr); + "(Rereg1), h_ret=%li e_mr=%p", h_ret, e_mr); *pginfo = pginfo_save; ret = -EAGAIN; } else if ((u64 *)hipzout.vaddr != iova_start) { @@ -1269,7 +1268,7 @@ ehca_rereg_mr_rereg1_exit1: ehca_free_fw_ctrlblock(kpage); ehca_rereg_mr_rereg1_exit0: if ( ret && (ret != -EAGAIN) ) - ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x " + ehca_err(&shca->ib_device, "ret=%i lkey=%x rkey=%x " "pginfo=%p num_kpages=%lx num_hwpages=%lx", ret, *lkey, *rkey, pginfo, pginfo->num_kpages, pginfo->num_hwpages); @@ -1330,7 +1329,7 @@ int ehca_rereg_mr(struct ehca_shca *shca, h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); if (h_ret != H_SUCCESS) { ehca_err(&shca->ib_device, "hipz_free_mr failed, " - "h_ret=%lx e_mr=%p hca_hndl=%lx mr_hndl=%lx " + "h_ret=%li e_mr=%p hca_hndl=%lx mr_hndl=%lx " "mr->lkey=%x", h_ret, e_mr, shca->ipz_hca_handle.handle, e_mr->ipz_mr_handle.handle, @@ -1362,7 +1361,7 @@ int ehca_rereg_mr(struct ehca_shca *shca, ehca_rereg_mr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " + ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p " "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x " "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size, @@ -1406,7 +1405,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca, * FMRs are not shared and no MW bound to FMRs */ ehca_err(&shca->ib_device, "hipz_reregister_pmr failed " - "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx " + "(Rereg1), h_ret=%li e_fmr=%p hca_hndl=%lx " "mr_hndl=%lx lkey=%x lkey_out=%x", h_ret, e_fmr, shca->ipz_hca_handle.handle, e_fmr->ipz_mr_handle.handle, @@ -1418,7 +1417,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca, h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr); if (h_ret != H_SUCCESS) { ehca_err(&shca->ib_device, "hipz_free_mr failed, " - "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx " + "h_ret=%li e_fmr=%p hca_hndl=%lx mr_hndl=%lx " "lkey=%x", h_ret, e_fmr, shca->ipz_hca_handle.handle, e_fmr->ipz_mr_handle.handle, @@ -1453,7 +1452,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca, ehca_unmap_one_fmr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x " + ehca_err(&shca->ib_device, "ret=%i tmp_lkey=%x tmp_rkey=%x " "fmr_max_pages=%x", ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages); return ret; @@ -1482,7 +1481,7 @@ int ehca_reg_smr(struct ehca_shca *shca, (u64)iova_start, hipz_acl, e_pd->fw_pd, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx " + ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li " "shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x " "e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x", h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd, @@ -1506,7 +1505,7 @@ int ehca_reg_smr(struct ehca_shca *shca, ehca_reg_smr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_origmr=%p " + ehca_err(&shca->ib_device, "ret=%i shca=%p e_origmr=%p " "e_newmr=%p iova_start=%p acl=%x e_pd=%p", ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd); return ret; @@ -1581,7 +1580,7 @@ ehca_reg_internal_maxmr_exit1: ehca_mr_delete(e_mr); ehca_reg_internal_maxmr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_pd=%p e_maxmr=%p", + ehca_err(&shca->ib_device, "ret=%i shca=%p e_pd=%p e_maxmr=%p", ret, shca, e_pd, e_maxmr); return ret; } /* end ehca_reg_internal_maxmr() */ @@ -1608,7 +1607,7 @@ int ehca_reg_maxmr(struct ehca_shca *shca, (u64)iova_start, hipz_acl, e_pd->fw_pd, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx " + ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li " "e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x", h_ret, e_origmr, shca->ipz_hca_handle.handle, e_origmr->ipz_mr_handle.handle, @@ -1649,7 +1648,7 @@ int ehca_dereg_internal_maxmr(struct ehca_shca *shca) ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr); if (ret) { ehca_err(&shca->ib_device, "dereg internal max-MR failed, " - "ret=%x e_maxmr=%p shca=%p lkey=%x", + "ret=%i e_maxmr=%p shca=%p lkey=%x", ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey); shca->maxmr = e_maxmr; goto ehca_dereg_internal_maxmr_exit0; @@ -1659,7 +1658,7 @@ int ehca_dereg_internal_maxmr(struct ehca_shca *shca) ehca_dereg_internal_maxmr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p shca->maxmr=%p", + ehca_err(&shca->ib_device, "ret=%i shca=%p shca->maxmr=%p", ret, shca, shca->maxmr); return ret; } /* end ehca_dereg_internal_maxmr() */ diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index e89fdca7fa19..88d7dd946033 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -310,7 +310,7 @@ static inline int init_qp_queue(struct ehca_shca *shca, } if (!ipz_rc) { - ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x", + ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%i", ipz_rc); return -EBUSY; } @@ -334,7 +334,7 @@ static inline int init_qp_queue(struct ehca_shca *shca, if (cnt == (nr_q_pages - 1)) { /* last page! */ if (h_ret != expected_hret) { ehca_err(ib_dev, "hipz_qp_register_rpage() " - "h_ret= %lx ", h_ret); + "h_ret=%li", h_ret); ret = ehca2ib_return_code(h_ret); goto init_qp_queue1; } @@ -348,7 +348,7 @@ static inline int init_qp_queue(struct ehca_shca *shca, } else { if (h_ret != H_PAGE_REGISTERED) { ehca_err(ib_dev, "hipz_qp_register_rpage() " - "h_ret= %lx ", h_ret); + "h_ret=%li", h_ret); ret = ehca2ib_return_code(h_ret); goto init_qp_queue1; } @@ -617,7 +617,7 @@ static struct ehca_qp *internal_create_qp( h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms); if (h_ret != H_SUCCESS) { - ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx", + ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%li", h_ret); ret = ehca2ib_return_code(h_ret); goto create_qp_exit1; @@ -671,7 +671,7 @@ static struct ehca_qp *internal_create_qp( &parms.squeue, swqe_size); if (ret) { ehca_err(pd->device, "Couldn't initialize squeue " - "and pages ret=%x", ret); + "and pages ret=%i", ret); goto create_qp_exit2; } } @@ -682,7 +682,7 @@ static struct ehca_qp *internal_create_qp( H_SUCCESS, &parms.rqueue, rwqe_size); if (ret) { ehca_err(pd->device, "Couldn't initialize rqueue " - "and pages ret=%x", ret); + "and pages ret=%i", ret); goto create_qp_exit3; } } @@ -728,7 +728,7 @@ static struct ehca_qp *internal_create_qp( ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp); if (ret) { ehca_err(pd->device, - "Couldn't assign qp to send_cq ret=%x", ret); + "Couldn't assign qp to send_cq ret=%i", ret); goto create_qp_exit4; } } @@ -845,7 +845,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { ehca_err(pd->device, "Could not modify SRQ to INIT" - "ehca_qp=%p qp_num=%x hret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; } @@ -859,7 +859,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { ehca_err(pd->device, "Could not enable SRQ" - "ehca_qp=%p qp_num=%x hret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; } @@ -873,7 +873,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { ehca_err(pd->device, "Could not modify SRQ to RTR" - "ehca_qp=%p qp_num=%x hret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; } @@ -911,7 +911,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca, &bad_send_wqe_p, NULL, 2); if (h_ret != H_SUCCESS) { ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed" - " ehca_qp=%p qp_num=%x h_ret=%lx", + " ehca_qp=%p qp_num=%x h_ret=%li", my_qp, qp_num, h_ret); return ehca2ib_return_code(h_ret); } @@ -989,7 +989,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, mqpcb, my_qp->galpas.kernel); if (h_ret != H_SUCCESS) { ehca_err(ibqp->device, "hipz_h_query_qp() failed " - "ehca_qp=%p qp_num=%x h_ret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, ibqp->qp_num, h_ret); ret = ehca2ib_return_code(h_ret); goto modify_qp_exit1; @@ -1025,7 +1025,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, ibqp, &smiqp_attr, smiqp_attr_mask, 1); if (smirc) { ehca_err(ibqp->device, "SMI RESET -> INIT failed. " - "ehca_modify_qp() rc=%x", smirc); + "ehca_modify_qp() rc=%i", smirc); ret = H_PARAMETER; goto modify_qp_exit1; } @@ -1127,7 +1127,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt); if (ret) { ehca_err(ibqp->device, "prepare_sqe_rts() failed " - "ehca_qp=%p qp_num=%x ret=%x", + "ehca_qp=%p qp_num=%x ret=%i", my_qp, ibqp->qp_num, ret); goto modify_qp_exit2; } @@ -1352,7 +1352,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); - ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx " + ehca_err(ibqp->device, "hipz_h_modify_qp() failed h_ret=%li " "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num); goto modify_qp_exit2; } @@ -1385,7 +1385,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, ret = ehca2ib_return_code(h_ret); ehca_err(ibqp->device, "ENABLE in context of " "RESET_2_INIT failed! Maybe you didn't get " - "a LID h_ret=%lx ehca_qp=%p qp_num=%x", + "a LID h_ret=%li ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num); goto modify_qp_exit2; } @@ -1473,7 +1473,7 @@ int ehca_query_qp(struct ib_qp *qp, if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); ehca_err(qp->device, "hipz_h_query_qp() failed " - "ehca_qp=%p qp_num=%x h_ret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, qp->qp_num, h_ret); goto query_qp_exit1; } @@ -1648,7 +1648,7 @@ int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); - ehca_err(ibsrq->device, "hipz_h_modify_qp() failed rc=%lx " + ehca_err(ibsrq->device, "hipz_h_modify_qp() failed h_ret=%li " "ehca_qp=%p qp_num=%x", h_ret, my_qp, my_qp->real_qp_num); } @@ -1691,7 +1691,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr) if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); ehca_err(srq->device, "hipz_h_query_qp() failed " - "ehca_qp=%p qp_num=%x h_ret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, h_ret); goto query_srq_exit1; } @@ -1741,7 +1741,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, ret = ehca_cq_unassign_qp(my_qp->send_cq, qp_num); if (ret) { ehca_err(dev, "Couldn't unassign qp from " - "send_cq ret=%x qp_num=%x cq_num=%x", ret, + "send_cq ret=%i qp_num=%x cq_num=%x", ret, qp_num, my_qp->send_cq->cq_number); return ret; } @@ -1753,7 +1753,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); if (h_ret != H_SUCCESS) { - ehca_err(dev, "hipz_h_destroy_qp() failed rc=%lx " + ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li " "ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num); return ehca2ib_return_code(h_ret); } diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 94eed70fedf5..ea91360835d3 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -526,7 +526,7 @@ poll_cq_one_read_cqe: if (!cqe) { ret = -EAGAIN; ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p " - "cq_num=%x ret=%x", my_cq, my_cq->cq_number, ret); + "cq_num=%x ret=%i", my_cq, my_cq->cq_number, ret); goto poll_cq_one_exit0; } diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c index 9f16e9c79394..f0792e5fbd02 100644 --- a/drivers/infiniband/hw/ehca/ehca_sqp.c +++ b/drivers/infiniband/hw/ehca/ehca_sqp.c @@ -82,7 +82,7 @@ u64 ehca_define_sqp(struct ehca_shca *shca, if (ret != H_SUCCESS) { ehca_err(&shca->ib_device, - "Can't define AQP1 for port %x. rc=%lx", + "Can't define AQP1 for port %x. h_ret=%li", port, ret); return ret; } diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index 84a16bcfd536..5234d6c15c49 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c @@ -121,7 +121,7 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas, ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT, vma->vm_page_prot); if (unlikely(ret)) { - ehca_gen_err("remap_pfn_range() failed ret=%x", ret); + ehca_gen_err("remap_pfn_range() failed ret=%i", ret); return -ENOMEM; } @@ -146,7 +146,7 @@ static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue, page = virt_to_page(virt_addr); ret = vm_insert_page(vma, start, page); if (unlikely(ret)) { - ehca_gen_err("vm_insert_page() failed rc=%x", ret); + ehca_gen_err("vm_insert_page() failed rc=%i", ret); return ret; } start += PAGE_SIZE; @@ -169,7 +169,7 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa); if (unlikely(ret)) { ehca_err(cq->ib_cq.device, - "ehca_mmap_fw() failed rc=%x cq_num=%x", + "ehca_mmap_fw() failed rc=%i cq_num=%x", ret, cq->cq_number); return ret; } @@ -180,7 +180,7 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue); if (unlikely(ret)) { ehca_err(cq->ib_cq.device, - "ehca_mmap_queue() failed rc=%x cq_num=%x", + "ehca_mmap_queue() failed rc=%i cq_num=%x", ret, cq->cq_number); return ret; } @@ -206,7 +206,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa); if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "remap_pfn_range() failed ret=%x qp_num=%x", + "remap_pfn_range() failed ret=%i qp_num=%x", ret, qp->ib_qp.qp_num); return -ENOMEM; } @@ -219,7 +219,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, &qp->mm_count_rqueue); if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "ehca_mmap_queue(rq) failed rc=%x qp_num=%x", + "ehca_mmap_queue(rq) failed rc=%i qp_num=%x", ret, qp->ib_qp.qp_num); return ret; } @@ -232,7 +232,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, &qp->mm_count_squeue); if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "ehca_mmap_queue(sq) failed rc=%x qp_num=%x", + "ehca_mmap_queue(sq) failed rc=%i qp_num=%x", ret, qp->ib_qp.qp_num); return ret; } @@ -283,7 +283,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) ret = ehca_mmap_cq(vma, cq, rsrc_type); if (unlikely(ret)) { ehca_err(cq->ib_cq.device, - "ehca_mmap_cq() failed rc=%x cq_num=%x", + "ehca_mmap_cq() failed rc=%i cq_num=%x", ret, cq->cq_number); return ret; } @@ -313,7 +313,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) ret = ehca_mmap_qp(vma, qp, rsrc_type); if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "ehca_mmap_qp() failed rc=%x qp_num=%x", + "ehca_mmap_qp() failed rc=%i qp_num=%x", ret, qp->ib_qp.qp_num); return ret; } diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index a762cc7e0165..3d68f6536f9c 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -238,7 +238,7 @@ u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle, *eq_ist = (u32)outs[5]; if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Not enough resource - ret=%lx ", ret); + ehca_gen_err("Not enough resource - ret=%li ", ret); return ret; } @@ -276,7 +276,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle, hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]); if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Not enough resources. ret=%lx", ret); + ehca_gen_err("Not enough resources. ret=%li", ret); return ret; } @@ -351,7 +351,7 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]); if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Not enough resources. ret=%lx", ret); + ehca_gen_err("Not enough resources. ret=%li", ret); return ret; } @@ -546,7 +546,7 @@ u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle, 0, 0, 0, 0, 0); if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Insufficient resources ret=%lx", ret); + ehca_gen_err("Insufficient resources ret=%li", ret); return ret; } @@ -582,7 +582,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle, qp->ipz_qp_handle.handle, /* r6 */ 0, 0, 0, 0, 0, 0); if (ret == H_HARDWARE) - ehca_gen_err("HCA not operational. ret=%lx", ret); + ehca_gen_err("HCA not operational. ret=%li", ret); ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE, adapter_handle.handle, /* r4 */ @@ -590,7 +590,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle, 0, 0, 0, 0, 0); if (ret == H_RESOURCE) - ehca_gen_err("Resource still in use. ret=%lx", ret); + ehca_gen_err("Resource still in use. ret=%li", ret); return ret; } @@ -625,7 +625,7 @@ u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle, *bma_qp_nr = (u32)outs[1]; if (ret == H_ALIAS_EXIST) - ehca_gen_err("AQP1 already exists. ret=%lx", ret); + ehca_gen_err("AQP1 already exists. ret=%li", ret); return ret; } @@ -647,7 +647,7 @@ u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle, 0, 0); if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Not enough resources. ret=%lx", ret); + ehca_gen_err("Not enough resources. ret=%li", ret); return ret; } @@ -686,7 +686,7 @@ u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle, 0, 0, 0, 0); if (ret == H_RESOURCE) - ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret); + ehca_gen_err("H_FREE_RESOURCE failed ret=%li ", ret); return ret; } @@ -708,7 +708,7 @@ u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle, 0, 0, 0, 0, 0); if (ret == H_RESOURCE) - ehca_gen_err("Resource in use. ret=%lx ", ret); + ehca_gen_err("Resource in use. ret=%li ", ret); return ret; } From 86dce445e01a50339f8f86c466c64a863e5fd18a Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:32:50 +0200 Subject: [PATCH 0800/2804] IB/ehca: ehca_gen_warn() should always print Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_tools.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h index 57c77a715f46..f9b264b46970 100644 --- a/drivers/infiniband/hw/ehca/ehca_tools.h +++ b/drivers/infiniband/hw/ehca/ehca_tools.h @@ -98,15 +98,12 @@ extern int ehca_debug_level; } while (0) #define ehca_gen_warn(format, arg...) \ - do { \ - if (unlikely(ehca_debug_level)) \ - printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg); \ - } while (0) + printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \ + get_paca()->paca_index, __FUNCTION__, ## arg) #define ehca_gen_err(format, arg...) \ printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + get_paca()->paca_index, __FUNCTION__, ## arg) /** * ehca_dmp - printk a memory block, whose length is n*8 bytes. From b708fba3c2942a175c3cb04a7bb4c89f907b497b Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:33:40 +0200 Subject: [PATCH 0801/2804] IB/ehca: Add check for max #SGE to create_qp() Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 88d7dd946033..f95403cb523d 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -513,7 +513,7 @@ static struct ehca_qp *internal_create_qp( } else if (init_attr->cap.max_send_wr > 255) { ehca_err(pd->device, "Invalid Number of " - "ax_send_wr=%x for UD QP_TYPE=%x", + "max_send_wr=%x for UD QP_TYPE=%x", init_attr->cap.max_send_wr, qp_type); return ERR_PTR(-EINVAL); } @@ -524,6 +524,18 @@ static struct ehca_qp *internal_create_qp( return ERR_PTR(-EINVAL); break; } + } else { + int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI + || qp_type == IB_QPT_GSI) ? 250 : 252; + + if (init_attr->cap.max_send_sge > max_sge + || init_attr->cap.max_recv_sge > max_sge) { + ehca_err(pd->device, "Invalid number of SGEs requested " + "send_sge=%x recv_sge=%x max_sge=%x", + init_attr->cap.max_send_sge, + init_attr->cap.max_recv_sge, max_sge); + return ERR_PTR(-EINVAL); + } } if (pd->uobject && udata) From e90d0b3daede2bae2e78f8bf88c19182961cd19d Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:34:04 +0200 Subject: [PATCH 0802/2804] IB/ehca: Path migration support Fix some modify_qp() issues related to path migration. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_irq.c | 4 +- drivers/infiniband/hw/ehca/ehca_qp.c | 96 +++++++++++++++++++-------- 2 files changed, 71 insertions(+), 29 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index a925ea52443f..70939864fef3 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -294,8 +294,8 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe) case 0x11: /* unaffiliated access error */ ehca_err(&shca->ib_device, "Unaffiliated access error."); break; - case 0x12: /* path migrating error */ - ehca_err(&shca->ib_device, "Path migration error."); + case 0x12: /* path migrating */ + ehca_err(&shca->ib_device, "Path migrating."); break; case 0x13: /* interface trace stopped */ ehca_err(&shca->ib_device, "Interface trace stopped."); diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index f95403cb523d..b10c7df669bb 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -1165,6 +1165,13 @@ static int internal_modify_qp(struct ib_qp *ibqp, } if (attr_mask & IB_QP_PKEY_INDEX) { + if (attr->pkey_index >= 16) { + ret = -EINVAL; + ehca_err(ibqp->device, "Invalid pkey_index=%x. " + "ehca_qp=%p qp_num=%x max_pkey_index=f", + attr->pkey_index, my_qp, ibqp->qp_num); + goto modify_qp_exit2; + } mqpcb->prim_p_key_idx = attr->pkey_index; update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1); } @@ -1273,50 +1280,78 @@ static int internal_modify_qp(struct ib_qp *ibqp, int ehca_mult = ib_rate_to_mult( shca->sport[my_qp->init_attr.port_num].rate); - mqpcb->dlid_al = attr->alt_ah_attr.dlid; - update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1); - mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1); - mqpcb->service_level_al = attr->alt_ah_attr.sl; - update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1); + if (attr->alt_port_num < 1 + || attr->alt_port_num > shca->num_ports) { + ret = -EINVAL; + ehca_err(ibqp->device, "Invalid alt_port=%x. " + "ehca_qp=%p qp_num=%x num_ports=%x", + attr->alt_port_num, my_qp, ibqp->qp_num, + shca->num_ports); + goto modify_qp_exit2; + } + mqpcb->alt_phys_port = attr->alt_port_num; - if (ah_mult < ehca_mult) - mqpcb->max_static_rate = (ah_mult > 0) ? - ((ehca_mult - 1) / ah_mult) : 0; + if (attr->alt_pkey_index >= 16) { + ret = -EINVAL; + ehca_err(ibqp->device, "Invalid alt_pkey_index=%x. " + "ehca_qp=%p qp_num=%x max_pkey_index=f", + attr->pkey_index, my_qp, ibqp->qp_num); + goto modify_qp_exit2; + } + mqpcb->alt_p_key_idx = attr->alt_pkey_index; + + mqpcb->timeout_al = attr->alt_timeout; + mqpcb->dlid_al = attr->alt_ah_attr.dlid; + mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits; + mqpcb->service_level_al = attr->alt_ah_attr.sl; + + if (ah_mult > 0 && ah_mult < ehca_mult) + mqpcb->max_static_rate_al = (ehca_mult - 1) / ah_mult; else mqpcb->max_static_rate_al = 0; - update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1); + /* OpenIB doesn't support alternate retry counts - copy them */ + mqpcb->retry_count_al = mqpcb->retry_count; + mqpcb->rnr_retry_count_al = mqpcb->rnr_retry_count; + + update_mask |= EHCA_BMASK_SET(MQPCB_MASK_ALT_PHYS_PORT, 1) + | EHCA_BMASK_SET(MQPCB_MASK_ALT_P_KEY_IDX, 1) + | EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT_AL, 1); + + /* + * Always supply the GRH flag, even if it's zero, to give the + * hypervisor a clear "yes" or "no" instead of a "perhaps" + */ + update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1); /* * only if GRH is TRUE we might consider SOURCE_GID_IDX * and DEST_GID otherwise phype will return H_ATTR_PARM!!! */ if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) { - mqpcb->send_grh_flag_al = 1 << 31; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1); - mqpcb->source_gid_idx_al = - attr->alt_ah_attr.grh.sgid_index; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1); + mqpcb->send_grh_flag_al = 1; for (cnt = 0; cnt < 16; cnt++) mqpcb->dest_gid_al.byte[cnt] = attr->alt_ah_attr.grh.dgid.raw[cnt]; - - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1); + mqpcb->source_gid_idx_al = + attr->alt_ah_attr.grh.sgid_index; mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1); mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1); mqpcb->traffic_class_al = attr->alt_ah_attr.grh.traffic_class; + update_mask |= + EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1) | EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1); } } @@ -1338,7 +1373,14 @@ static int internal_modify_qp(struct ib_qp *ibqp, } if (attr_mask & IB_QP_PATH_MIG_STATE) { - mqpcb->path_migration_state = attr->path_mig_state; + if (attr->path_mig_state != IB_MIG_REARM + && attr->path_mig_state != IB_MIG_MIGRATED) { + ret = -EINVAL; + ehca_err(ibqp->device, "Invalid mig_state=%x", + attr->path_mig_state); + goto modify_qp_exit2; + } + mqpcb->path_migration_state = attr->path_mig_state + 1; update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1); } @@ -1506,7 +1548,7 @@ int ehca_query_qp(struct ib_qp *qp, qp_attr->qkey = qpcb->qkey; qp_attr->path_mtu = qpcb->path_mtu; - qp_attr->path_mig_state = qpcb->path_migration_state; + qp_attr->path_mig_state = qpcb->path_migration_state - 1; qp_attr->rq_psn = qpcb->receive_psn; qp_attr->sq_psn = qpcb->send_psn; qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field; From 0b5de96858e516311f2d3ca45073c2afd2eb5d94 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:34:35 +0200 Subject: [PATCH 0803/2804] IB/ehca: Serialize MR alloc and MR free hvCalls Some firmware levels exhibit a race condition between H_ALLOC_RESOURCE(MR) and H_FREE_RESOURCE(MR). Work around this problem by locking these hvCalls against each other. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/hcp_if.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index 3d68f6536f9c..c16a21374bb5 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -120,15 +120,28 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, unsigned long arg7) { long ret; - int i, sleep_msecs; + int i, sleep_msecs, do_lock; + unsigned long flags; ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + /* lock H_FREE_RESOURCE(MR) against itself and H_ALLOC_RESOURCE(MR) */ + if ((opcode == H_FREE_RESOURCE) && (arg7 == 5)) { + arg7 = 0; /* better not upset firmware */ + do_lock = 1; + } + for (i = 0; i < 5; i++) { + if (do_lock) + spin_lock_irqsave(&hcall_lock, flags); + ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + if (do_lock) + spin_unlock_irqrestore(&hcall_lock, flags); + if (H_IS_LONG_BUSY(ret)) { sleep_msecs = get_longbusy_msecs(ret); msleep_interruptible(sleep_msecs); @@ -161,23 +174,24 @@ static long ehca_plpar_hcall9(unsigned long opcode, unsigned long arg9) { long ret; - int i, sleep_msecs, lock_is_set = 0; + int i, sleep_msecs, do_lock; unsigned long flags = 0; ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + /* lock H_ALLOC_RESOURCE(MR) against itself and H_FREE_RESOURCE(MR) */ + do_lock = ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)); + for (i = 0; i < 5; i++) { - if ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)) { + if (do_lock) spin_lock_irqsave(&hcall_lock, flags); - lock_is_set = 1; - } ret = plpar_hcall9(opcode, outs, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - if (lock_is_set) + if (do_lock) spin_unlock_irqrestore(&hcall_lock, flags); if (H_IS_LONG_BUSY(ret)) { @@ -807,7 +821,7 @@ u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle, return ehca_plpar_hcall_norets(H_FREE_RESOURCE, adapter_handle.handle, /* r4 */ mr->ipz_mr_handle.handle, /* r5 */ - 0, 0, 0, 0, 0); + 0, 0, 0, 0, 5); } u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, From 5110e4de4995db1c28457b08ed1e291f9b38f2e7 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Wed, 12 Sep 2007 16:44:11 +0200 Subject: [PATCH 0804/2804] IB/ehca: Replace get_paca()->paca_index by the more portable raw_smp_processor_id() We can use raw_smp_processor_id() here because the processor ID is only used for debug output and therefore our use is preemption-unsafe. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_tools.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h index f9b264b46970..4a8346a2bc9e 100644 --- a/drivers/infiniband/hw/ehca/ehca_tools.h +++ b/drivers/infiniband/hw/ehca/ehca_tools.h @@ -73,37 +73,37 @@ extern int ehca_debug_level; if (unlikely(ehca_debug_level)) \ dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \ "PU%04x EHCA_DBG:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, \ + raw_smp_processor_id(), __FUNCTION__, \ ## arg); \ } while (0) #define ehca_info(ib_dev, format, arg...) \ dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) #define ehca_warn(ib_dev, format, arg...) \ dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) #define ehca_err(ib_dev, format, arg...) \ dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) /* use this one only if no ib_dev available */ #define ehca_gen_dbg(format, arg...) \ do { \ if (unlikely(ehca_debug_level)) \ printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg); \ + raw_smp_processor_id(), __FUNCTION__, ## arg); \ } while (0) #define ehca_gen_warn(format, arg...) \ printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) #define ehca_gen_err(format, arg...) \ printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) /** * ehca_dmp - printk a memory block, whose length is n*8 bytes. From 39089e77741a53874eb8a29e4516bbafcc29298a Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:35:32 +0200 Subject: [PATCH 0805/2804] IB/ehca: Bump version number and change its format Nobody needed the SVNEHCA_ prefix anyway. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 0e3ffeef45d9..403467f66fe6 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -49,10 +49,12 @@ #include "ehca_tools.h" #include "hcp_if.h" +#define HCAD_VERSION "0024" + MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch "); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); -MODULE_VERSION("SVNEHCA_0023"); +MODULE_VERSION(HCAD_VERSION); int ehca_open_aqp1 = 0; int ehca_debug_level = 0; @@ -909,7 +911,7 @@ int __init ehca_module_init(void) int ret; printk(KERN_INFO "eHCA Infiniband Device Driver " - "(Rel.: SVNEHCA_0023)\n"); + "(Version " HCAD_VERSION ")\n"); ret = ehca_create_comp_pool(); if (ret) { From 08c283ac262d7ab21c5733ff469ff88985381ca9 Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Thu, 13 Sep 2007 18:14:58 +0200 Subject: [PATCH 0806/2804] IB/ehca: Fix large page HW cap defines Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 0942a173881c..d6706966a010 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -100,10 +100,10 @@ struct ehca_sport { struct ehca_sma_attr saved_attr; }; -#define HCA_CAP_MR_PGSIZE_4K 1 -#define HCA_CAP_MR_PGSIZE_64K 2 -#define HCA_CAP_MR_PGSIZE_1M 4 -#define HCA_CAP_MR_PGSIZE_16M 8 +#define HCA_CAP_MR_PGSIZE_4K 0x80000000 +#define HCA_CAP_MR_PGSIZE_64K 0x40000000 +#define HCA_CAP_MR_PGSIZE_1M 0x20000000 +#define HCA_CAP_MR_PGSIZE_16M 0x10000000 struct ehca_shca { struct ib_device ib_device; From 81668838c4583b19276b16382e0c61e21ef5adf0 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Thu, 2 Aug 2007 12:21:31 -0700 Subject: [PATCH 0807/2804] IPoIB: Specify Traffic Class with path record queries for QoS support To support QoS within and between subnets, modify IPoIB to request specific Traffic Class values with path record queries, using the value associated with the IPoIB broadcast group. Signed-off-by: Sean Hefty [ See some comments I made on this at v1 and v2 of the posts ] Reviewed-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib.h | 22 ++++++++++++++++++- drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 ++++--- .../infiniband/ulp/ipoib/ipoib_multicast.c | 22 ------------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 285c143115cc..fc16bced8e54 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -113,7 +113,27 @@ struct ipoib_pseudoheader { u8 hwaddr[INFINIBAND_ALEN]; }; -struct ipoib_mcast; +/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ +struct ipoib_mcast { + struct ib_sa_mcmember_rec mcmember; + struct ib_sa_multicast *mc; + struct ipoib_ah *ah; + + struct rb_node rb_node; + struct list_head list; + + unsigned long created; + unsigned long backoff; + + unsigned long flags; + unsigned char logcount; + + struct list_head neigh_list; + + struct sk_buff_head pkt_queue; + + struct net_device *dev; +}; struct ipoib_rx_buf { struct sk_buff *skb; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 5f948b9a9943..900335a36e45 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -468,9 +468,10 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) INIT_LIST_HEAD(&path->neigh_list); memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); - path->pathrec.sgid = priv->local_gid; - path->pathrec.pkey = cpu_to_be16(priv->pkey); - path->pathrec.numb_path = 1; + path->pathrec.sgid = priv->local_gid; + path->pathrec.pkey = cpu_to_be16(priv->pkey); + path->pathrec.numb_path = 1; + path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; return path; } @@ -491,6 +492,7 @@ static int path_rec_start(struct net_device *dev, IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | IB_SA_PATH_REC_NUMB_PATH | + IB_SA_PATH_REC_TRAFFIC_CLASS | IB_SA_PATH_REC_PKEY, 1000, GFP_ATOMIC, path_rec_completion, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index aae367057a56..94a57097e2b4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -57,28 +57,6 @@ MODULE_PARM_DESC(mcast_debug_level, static DEFINE_MUTEX(mcast_mutex); -/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ -struct ipoib_mcast { - struct ib_sa_mcmember_rec mcmember; - struct ib_sa_multicast *mc; - struct ipoib_ah *ah; - - struct rb_node rb_node; - struct list_head list; - - unsigned long created; - unsigned long backoff; - - unsigned long flags; - unsigned char logcount; - - struct list_head neigh_list; - - struct sk_buff_head pkt_queue; - - struct net_device *dev; -}; - struct ipoib_mcast_iter { struct net_device *dev; union ib_gid mgid; From 733d65fe33b3002a6f2694c0fd8bd760dc13141f Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 8 Aug 2007 15:41:28 -0700 Subject: [PATCH 0808/2804] IB/sa: Add new QoS fields to path record The QoS annex defines new fields for path records. Add them to the ib_sa for consumers that want to use them. Signed-off-by: Sean Hefty Reviewed-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/core/sa_query.c | 10 +++------- include/rdma/ib_sa.h | 11 +++++------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 312c8ff5ae88..cf474ec27070 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -123,14 +123,10 @@ static u32 tid; .field_name = "sa_path_rec:" #field static const struct ib_field path_rec_table[] = { - { RESERVED, + { PATH_REC_FIELD(service_id), .offset_words = 0, .offset_bits = 0, - .size_bits = 32 }, - { RESERVED, - .offset_words = 1, - .offset_bits = 0, - .size_bits = 32 }, + .size_bits = 64 }, { PATH_REC_FIELD(dgid), .offset_words = 2, .offset_bits = 0, @@ -179,7 +175,7 @@ static const struct ib_field path_rec_table[] = { .offset_words = 12, .offset_bits = 16, .size_bits = 16 }, - { RESERVED, + { PATH_REC_FIELD(qos_class), .offset_words = 13, .offset_bits = 0, .size_bits = 12 }, diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index 5e26b2f53f86..942692b0b92e 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -109,8 +109,8 @@ enum ib_sa_selector { * Reserved rows are indicated with comments to help maintainability. */ -/* reserved: 0 */ -/* reserved: 1 */ +#define IB_SA_PATH_REC_SERVICE_ID (IB_SA_COMP_MASK( 0) |\ + IB_SA_COMP_MASK( 1)) #define IB_SA_PATH_REC_DGID IB_SA_COMP_MASK( 2) #define IB_SA_PATH_REC_SGID IB_SA_COMP_MASK( 3) #define IB_SA_PATH_REC_DLID IB_SA_COMP_MASK( 4) @@ -123,7 +123,7 @@ enum ib_sa_selector { #define IB_SA_PATH_REC_REVERSIBLE IB_SA_COMP_MASK(11) #define IB_SA_PATH_REC_NUMB_PATH IB_SA_COMP_MASK(12) #define IB_SA_PATH_REC_PKEY IB_SA_COMP_MASK(13) -/* reserved: 14 */ +#define IB_SA_PATH_REC_QOS_CLASS IB_SA_COMP_MASK(14) #define IB_SA_PATH_REC_SL IB_SA_COMP_MASK(15) #define IB_SA_PATH_REC_MTU_SELECTOR IB_SA_COMP_MASK(16) #define IB_SA_PATH_REC_MTU IB_SA_COMP_MASK(17) @@ -134,8 +134,7 @@ enum ib_sa_selector { #define IB_SA_PATH_REC_PREFERENCE IB_SA_COMP_MASK(22) struct ib_sa_path_rec { - /* reserved */ - /* reserved */ + __be64 service_id; union ib_gid dgid; union ib_gid sgid; __be16 dlid; @@ -148,7 +147,7 @@ struct ib_sa_path_rec { int reversible; u8 numb_path; __be16 pkey; - /* reserved */ + __be16 qos_class; u8 sl; u8 mtu_selector; u8 mtu; From a81c994d5eef87ed77cb30d8343d6be296528b3f Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 8 Aug 2007 15:51:06 -0700 Subject: [PATCH 0809/2804] RDMA/cma: Add ability to specify type of service Provide support to specify a type of service for a communication identifier. A new function call is used when dealing with IPv4 addresses. For IPv6 addresses, the ToS is specified through the traffic class field in the sockaddr_in6 structure. Signed-off-by: Sean Hefty [ The comments Eitan Zahavi and myself have made over the v1 post at were fully addressed. ] Reviewed-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/core/cma.c | 44 +++++++++++++++++++++++++++-------- include/rdma/rdma_cm.h | 14 +++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9ffb9987450a..19c9172f0cdc 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -138,6 +138,7 @@ struct rdma_id_private { u32 qkey; u32 qp_num; u8 srq; + u8 tos; }; struct cma_multicast { @@ -1474,6 +1475,15 @@ err: } EXPORT_SYMBOL(rdma_listen); +void rdma_set_service_type(struct rdma_cm_id *id, int tos) +{ + struct rdma_id_private *id_priv; + + id_priv = container_of(id, struct rdma_id_private, id); + id_priv->tos = (u8) tos; +} +EXPORT_SYMBOL(rdma_set_service_type); + static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, void *context) { @@ -1498,23 +1508,37 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, struct cma_work *work) { - struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr; + struct rdma_addr *addr = &id_priv->id.route.addr; struct ib_sa_path_rec path_rec; + ib_sa_comp_mask comp_mask; + struct sockaddr_in6 *sin6; memset(&path_rec, 0, sizeof path_rec); - ib_addr_get_sgid(addr, &path_rec.sgid); - ib_addr_get_dgid(addr, &path_rec.dgid); - path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr)); + ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid); + ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid); + path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); path_rec.numb_path = 1; path_rec.reversible = 1; + path_rec.service_id = cma_get_service_id(id_priv->id.ps, &addr->dst_addr); + + comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | + IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | + IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; + + if (addr->src_addr.sa_family == AF_INET) { + path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); + comp_mask |= IB_SA_PATH_REC_QOS_CLASS; + } else { + sin6 = (struct sockaddr_in6 *) &addr->src_addr; + path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); + comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; + } id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, - id_priv->id.port_num, &path_rec, - IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | - IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | - IB_SA_PATH_REC_REVERSIBLE, - timeout_ms, GFP_KERNEL, - cma_query_handler, work, &id_priv->query); + id_priv->id.port_num, &path_rec, + comp_mask, timeout_ms, + GFP_KERNEL, cma_query_handler, + work, &id_priv->query); return (id_priv->query_id < 0) ? id_priv->query_id : 0; } diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 2d6a7705eae7..010f876f41d8 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -314,4 +314,18 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, */ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr); +/** + * rdma_set_service_type - Set the type of service associated with a + * connection identifier. + * @id: Communication identifier to associated with service type. + * @tos: Type of service. + * + * The type of service is interpretted as a differentiated service + * field (RFC 2474). The service type should be specified before + * performing route resolution, as existing communication on the + * connection identifier may be unaffected. The type of service + * requested may not be supported by the network to all destinations. + */ +void rdma_set_service_type(struct rdma_cm_id *id, int tos); + #endif /* RDMA_CM_H */ From 7ce86409adcd2fda652b628173a66e905950ece1 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 8 Aug 2007 15:51:13 -0700 Subject: [PATCH 0810/2804] RDMA/ucma: Allow user space to set service type Export the ability to set the type of service to user space. Model the interface after setsockopt. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/ucma.c | 74 +++++++++++++++++++++++++++++++++- include/rdma/rdma_user_cm.h | 18 +++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 53b4c94a7eb5..90d675ad9ec8 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -792,6 +792,78 @@ out: return ret; } +static int ucma_set_option_id(struct ucma_context *ctx, int optname, + void *optval, size_t optlen) +{ + int ret = 0; + + switch (optname) { + case RDMA_OPTION_ID_TOS: + if (optlen != sizeof(u8)) { + ret = -EINVAL; + break; + } + rdma_set_service_type(ctx->cm_id, *((u8 *) optval)); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static int ucma_set_option_level(struct ucma_context *ctx, int level, + int optname, void *optval, size_t optlen) +{ + int ret; + + switch (level) { + case RDMA_OPTION_ID: + ret = ucma_set_option_id(ctx, optname, optval, optlen); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_set_option cmd; + struct ucma_context *ctx; + void *optval; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + optval = kmalloc(cmd.optlen, GFP_KERNEL); + if (!optval) { + ret = -ENOMEM; + goto out1; + } + + if (copy_from_user(optval, (void __user *) (unsigned long) cmd.optval, + cmd.optlen)) { + ret = -EFAULT; + goto out2; + } + + ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval, + cmd.optlen); +out2: + kfree(optval); +out1: + ucma_put_ctx(ctx); + return ret; +} + static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) { @@ -936,7 +1008,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr, [RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event, [RDMA_USER_CM_CMD_GET_OPTION] = NULL, - [RDMA_USER_CM_CMD_SET_OPTION] = NULL, + [RDMA_USER_CM_CMD_SET_OPTION] = ucma_set_option, [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, diff --git a/include/rdma/rdma_user_cm.h b/include/rdma/rdma_user_cm.h index f632b0c007c9..9749c1b34d00 100644 --- a/include/rdma/rdma_user_cm.h +++ b/include/rdma/rdma_user_cm.h @@ -212,4 +212,22 @@ struct rdma_ucm_event_resp { } param; }; +/* Option levels */ +enum { + RDMA_OPTION_ID = 0 +}; + +/* Option details */ +enum { + RDMA_OPTION_ID_TOS = 0 +}; + +struct rdma_ucm_set_option { + __u64 optval; + __u32 id; + __u32 level; + __u32 optname; + __u32 optlen; +}; + #endif /* RDMA_USER_CM_H */ From 247e020ee5e2a7bf46f2d7a3d4490a670a712a40 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 8 Aug 2007 15:51:18 -0700 Subject: [PATCH 0811/2804] IB/srp: Add QoS support through service ID Provide the target service ID when performing a path record query to support optional QoS capability. QoS requires support from the SA. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index f6a051428144..9ccc63886d92 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -285,6 +285,7 @@ static int srp_lookup_path(struct srp_target_port *target) target->srp_host->dev->dev, target->srp_host->port, &target->path, + IB_SA_PATH_REC_SERVICE_ID | IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | IB_SA_PATH_REC_NUMB_PATH | @@ -1692,6 +1693,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) goto out; } target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); + target->path.service_id = target->service_id; kfree(p); break; From c8d8beea0383e47c9d65d45f0ca95626ec435fcd Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Thu, 13 Sep 2007 18:15:28 +0200 Subject: [PATCH 0812/2804] IB/umem: Add hugetlb flag to struct ib_umem During ib_umem_get(), determine whether all pages from the memory region are hugetlb pages and report this in the "hugetlb" member. Low-level drivers can use this information if they need it. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/core/umem.c | 20 +++++++++++++++++++- include/rdma/ib_umem.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 664d2faa9e74..2f54e29dc7a6 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "uverbs.h" @@ -75,6 +76,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, { struct ib_umem *umem; struct page **page_list; + struct vm_area_struct **vma_list; struct ib_umem_chunk *chunk; unsigned long locked; unsigned long lock_limit; @@ -104,6 +106,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, */ umem->writable = !!(access & ~IB_ACCESS_REMOTE_READ); + /* We assume the memory is from hugetlb until proved otherwise */ + umem->hugetlb = 1; + INIT_LIST_HEAD(&umem->chunk_list); page_list = (struct page **) __get_free_page(GFP_KERNEL); @@ -112,6 +117,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, return ERR_PTR(-ENOMEM); } + /* + * if we can't alloc the vma_list, it's not so bad; + * just assume the memory is not hugetlb memory + */ + vma_list = (struct vm_area_struct **) __get_free_page(GFP_KERNEL); + if (!vma_list) + umem->hugetlb = 0; + npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT; down_write(¤t->mm->mmap_sem); @@ -131,7 +144,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, ret = get_user_pages(current, current->mm, cur_base, min_t(int, npages, PAGE_SIZE / sizeof (struct page *)), - 1, !umem->writable, page_list, NULL); + 1, !umem->writable, page_list, vma_list); if (ret < 0) goto out; @@ -152,6 +165,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK); for (i = 0; i < chunk->nents; ++i) { + if (vma_list && + !is_vm_hugetlb_page(vma_list[i + off])) + umem->hugetlb = 0; chunk->page_list[i].page = page_list[i + off]; chunk->page_list[i].offset = 0; chunk->page_list[i].length = PAGE_SIZE; @@ -186,6 +202,8 @@ out: current->mm->locked_vm = locked; up_write(¤t->mm->mmap_sem); + if (vma_list) + free_page((unsigned long) vma_list); free_page((unsigned long) page_list); return ret < 0 ? ERR_PTR(ret) : umem; diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h index c533d6c7903f..22298423cf0b 100644 --- a/include/rdma/ib_umem.h +++ b/include/rdma/ib_umem.h @@ -45,6 +45,7 @@ struct ib_umem { int offset; int page_size; int writable; + int hugetlb; struct list_head chunk_list; struct work_struct work; struct mm_struct *mm; From 3a31c41901b6bd3937ec36e0e4a930849e270df6 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Thu, 13 Sep 2007 18:16:20 +0200 Subject: [PATCH 0813/2804] IB/ehca: Only use MR large pages for hugetlb regions ...because, on virtualized hardware like System p, we can't be sure that the physical pages behind them are contiguous otherwise. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_mrmw.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index e925e84c9bc7..da88738265ed 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -51,6 +51,7 @@ #define NUM_CHUNKS(length, chunk_size) \ (((length) + (chunk_size - 1)) / (chunk_size)) + /* max number of rpages (per hcall register_rpages) */ #define MAX_RPAGES 512 @@ -64,6 +65,11 @@ enum ehca_mr_pgsize { EHCA_MR_PGSIZE16M = 0x1000000L }; +#define EHCA_MR_PGSHIFT4K 12 +#define EHCA_MR_PGSHIFT64K 16 +#define EHCA_MR_PGSHIFT1M 20 +#define EHCA_MR_PGSHIFT16M 24 + static u32 ehca_encode_hwpage_size(u32 pgsize) { u32 idx = 0; @@ -347,17 +353,16 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, /* select proper hw_pgsize */ if (ehca_mr_largepage && (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)) { - if (length <= EHCA_MR_PGSIZE4K - && PAGE_SIZE == EHCA_MR_PGSIZE4K) - hwpage_size = EHCA_MR_PGSIZE4K; - else if (length <= EHCA_MR_PGSIZE64K) - hwpage_size = EHCA_MR_PGSIZE64K; - else if (length <= EHCA_MR_PGSIZE1M) - hwpage_size = EHCA_MR_PGSIZE1M; - else - hwpage_size = EHCA_MR_PGSIZE16M; + int page_shift = PAGE_SHIFT; + if (e_mr->umem->hugetlb) { + /* determine page_shift, clamp between 4K and 16M */ + page_shift = (fls64(length - 1) + 3) & ~3; + page_shift = min(max(page_shift, EHCA_MR_PGSHIFT4K), + EHCA_MR_PGSHIFT16M); + } + hwpage_size = 1UL << page_shift; } else - hwpage_size = EHCA_MR_PGSIZE4K; + hwpage_size = EHCA_MR_PGSIZE4K; /* ehca1 only supports 4k */ ehca_dbg(pd->device, "hwpage_size=%lx", hwpage_size); reg_user_mr_fallback: From 935ef2d7a2910ca810fce57511f4d06a0cf00b5e Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 12 Sep 2007 05:00:25 -0500 Subject: [PATCH 0814/2804] RDMA/cma: Use neigh_event_send() to start neighbour discovery Calling arp_send() to initiate neighbour discovery (ND) doesn't do the full ND protocol. Namely, it doesn't handle retransmitting the arp request if it is dropped. The function neigh_event_send() does all this. Without doing full ND, RDMA address resolution fails in the presence of dropped ARP broadcast packets. Signed-off-by: Steve Wise Acked-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/addr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index c5c33d35f87d..5381c80de10a 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -161,8 +161,7 @@ static void addr_send_arp(struct sockaddr_in *dst_in) if (ip_route_output_key(&rt, &fl)) return; - arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev, - rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL); + neigh_event_send(rt->u.dst.neighbour, NULL); ip_rt_put(rt); } From ec2a1344ad348a789b1d9d9b32cccbef33161574 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:13 -0700 Subject: [PATCH 0815/2804] IB/iser: Remove unnecessary includes is not needed because everyplace it appears, also appears. is not needed because nothing seems to be using device IO anyway. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iser_initiator.c | 2 -- drivers/infiniband/ulp/iser/iser_memory.c | 2 -- drivers/infiniband/ulp/iser/iser_verbs.c | 1 - 3 files changed, 5 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 9ea5b9aaba7c..a6f2303ed14a 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -34,8 +34,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 36cdf77ae92a..e05690e3592f 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -36,8 +36,6 @@ #include #include #include -#include -#include #include #include "iscsi_iser.h" diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index d42ec0156eec..654a4dce0236 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -32,7 +32,6 @@ * * $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $ */ -#include #include #include #include From ea98054fefa28b646c740baffe83c2962f8228f6 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:13 -0700 Subject: [PATCH 0816/2804] mlx4_core: Change capability decoding: SRC->XRC The SRC ("scalable RC") transport has been renamed to XRC ("extended RC"), to avoid having an abbreviation that is so easily confused with an abbreviation for "source." Update the HCA capability decoding output to use the new name. Signed-off-by: Roland Dreier --- drivers/net/mlx4/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index c45cbe43a0c4..6471d33afb7d 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -76,7 +76,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags) [ 0] = "RC transport", [ 1] = "UC transport", [ 2] = "UD transport", - [ 3] = "SRC transport", + [ 3] = "XRC transport", [ 4] = "reliable multicast", [ 5] = "FCoIB support", [ 6] = "SRQ support", From 9faa559c01311281f26544291322252327b65922 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Thu, 23 Aug 2007 04:58:30 +0530 Subject: [PATCH 0817/2804] IB/ehca: Misc cpuinit section annotations and #ifdef cleanups * Replace {un}register_cpu_notifier with {un}register_hotcpu_notifier thereby losing a couple of #ifdef HOTPLUG_CPU pairs. * Move comp_pool_callback_nb declaration to below that of callback function so that initialization of .notifier_call and .priority can occur at build time itself and not runtime. * Mark the notifier_block (and callback function, and another static function used by it) as __cpuinit{data} for the sake of consistency and remove enclosing #ifdef. (This may increase size for modular build of this module, however, because these are no longer dropped unconditionally now.) Signed-off-by: Satyam Sharma Acked-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_irq.c | 29 ++++++++++----------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 70939864fef3..3f617b27b954 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -69,9 +69,6 @@ static void queue_comp_task(struct ehca_cq *__cq); static struct ehca_comp_pool *pool; -#ifdef CONFIG_HOTPLUG_CPU -static struct notifier_block comp_pool_callback_nb; -#endif static inline void comp_event_callback(struct ehca_cq *cq) { @@ -760,9 +757,7 @@ static void destroy_comp_task(struct ehca_comp_pool *pool, kthread_stop(task); } -#ifdef CONFIG_HOTPLUG_CPU -static void take_over_work(struct ehca_comp_pool *pool, - int cpu) +static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu) { struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); LIST_HEAD(list); @@ -785,9 +780,9 @@ static void take_over_work(struct ehca_comp_pool *pool, } -static int comp_pool_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) +static int __cpuinit comp_pool_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { unsigned int cpu = (unsigned long)hcpu; struct ehca_cpu_comp_task *cct; @@ -833,7 +828,11 @@ static int comp_pool_callback(struct notifier_block *nfb, return NOTIFY_OK; } -#endif + +static struct notifier_block comp_pool_callback_nb __cpuinitdata = { + .notifier_call = comp_pool_callback, + .priority = 0, +}; int ehca_create_comp_pool(void) { @@ -864,11 +863,7 @@ int ehca_create_comp_pool(void) } } -#ifdef CONFIG_HOTPLUG_CPU - comp_pool_callback_nb.notifier_call = comp_pool_callback; - comp_pool_callback_nb.priority = 0; - register_cpu_notifier(&comp_pool_callback_nb); -#endif + register_hotcpu_notifier(&comp_pool_callback_nb); printk(KERN_INFO "eHCA scaling code enabled\n"); @@ -882,9 +877,7 @@ void ehca_destroy_comp_pool(void) if (!ehca_scaling_code) return; -#ifdef CONFIG_HOTPLUG_CPU - unregister_cpu_notifier(&comp_pool_callback_nb); -#endif + unregister_hotcpu_notifier(&comp_pool_callback_nb); for (i = 0; i < NR_CPUS; i++) { if (cpu_online(i)) From 57cb61d587e990d556385d367589ff61f6c2c0f2 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Thu, 20 Sep 2007 16:33:44 -0700 Subject: [PATCH 0818/2804] IB/core: Fix handling of multicast response failures I was looking at the code for multicast.c and noticed that ib_sa_join_multicast() calls queue_join() which puts the request at the front of the group->pending_list. If this is a second request, it seems like it would interfere with process_join_error() since group->last_join won't point to the member at the head of the pending_list. The sequence would thus be: 1. ib_sa_join_multicast() puts member1 on head of pending_list and starts work thread 2. mcast_work_handler() calls send_join() which sets group->last_join to member1 3. ib_sa_join_multicast() puts member2 on head of pending_list 4. join operation for member1 receives failures response from SA. 5. join_handler() is called with error status 6. process_join_error() fails to process member1 since it doesn't match the first entry in the group->pending_list. The impact is that the failed join request is tossed. The second request is processed, and after it completes, the original request ends up being retried. This change also results in join requests being processed in FIFO order. Signed-off-by: Ralph Campbell Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/multicast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 15b4c4d3606d..1bc1fe605282 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -196,7 +196,7 @@ static void queue_join(struct mcast_member *member) unsigned long flags; spin_lock_irqsave(&group->lock, flags); - list_add(&member->list, &group->pending_list); + list_add_tail(&member->list, &group->pending_list); if (group->state == MCAST_IDLE) { group->state = MCAST_BUSY; atomic_inc(&group->refcount); From cd9281d873c91a01af0cb96ff0f75e9905e54403 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 18 Sep 2007 09:14:18 +0200 Subject: [PATCH 0819/2804] IB/mlx4: Display misc device information under /sys/class/infiniband/ display the following device information under /sys/class/infiniband/mlx4_X: board_id, fw_ver, hw_rev, hca_type. This patch makes this information available to userspace utilities such as ibstat and ibv_devinfo. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/main.c | 45 +++++++++++++++++++++++++++++++ drivers/net/mlx4/main.c | 4 +-- drivers/net/mlx4/mlx4.h | 7 ----- include/linux/mlx4/device.h | 6 +++++ 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index dde8fe9af47e..d9fc822a1468 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -476,9 +476,48 @@ out: return err; } +static ssize_t show_hca(struct class_device *cdev, char *buf) +{ + struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev); + return sprintf(buf, "MT%d\n", dev->dev->pdev->device); +} + +static ssize_t show_fw_ver(struct class_device *cdev, char *buf) +{ + struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev); + return sprintf(buf, "%d.%d.%d\n", (int) (dev->dev->caps.fw_ver >> 32), + (int) (dev->dev->caps.fw_ver >> 16) & 0xffff, + (int) dev->dev->caps.fw_ver & 0xffff); +} + +static ssize_t show_rev(struct class_device *cdev, char *buf) +{ + struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev); + return sprintf(buf, "%x\n", dev->dev->rev_id); +} + +static ssize_t show_board(struct class_device *cdev, char *buf) +{ + struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev); + return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, dev->dev->board_id); +} + +static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); +static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); +static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); + +static struct class_device_attribute *mlx4_class_attributes[] = { + &class_device_attr_hw_rev, + &class_device_attr_fw_ver, + &class_device_attr_hca_type, + &class_device_attr_board_id +}; + static void *mlx4_ib_add(struct mlx4_dev *dev) { struct mlx4_ib_dev *ibdev; + int i; ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev); if (!ibdev) { @@ -580,6 +619,12 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) if (mlx4_ib_mad_init(ibdev)) goto err_reg; + for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) { + if (class_device_create_file(&ibdev->ib_dev.class_dev, + mlx4_class_attributes[i])) + goto err_reg; + } + return ibdev; err_reg: diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 4b1269435586..9e590e11c1cf 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -524,8 +524,8 @@ static int __devinit mlx4_init_hca(struct mlx4_dev *dev) } priv->eq_table.inta_pin = adapter.inta_pin; - priv->rev_id = adapter.revision_id; - memcpy(priv->board_id, adapter.board_id, sizeof priv->board_id); + dev->rev_id = adapter.revision_id; + memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id); return 0; diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index be304a7c2c91..b9f839761919 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -55,10 +55,6 @@ enum { MLX4_CLR_INT_SIZE = 0x00008 }; -enum { - MLX4_BOARD_ID_LEN = 64 -}; - enum { MLX4_MGM_ENTRY_SIZE = 0x40, MLX4_QP_PER_MGM = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2), @@ -277,9 +273,6 @@ struct mlx4_priv { struct mlx4_uar driver_uar; void __iomem *kar; - - u32 rev_id; - char board_id[MLX4_BOARD_ID_LEN]; }; static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index cfb78fb2c046..a93520c76fde 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -48,6 +48,10 @@ enum { MLX4_MAX_PORTS = 2 }; +enum { + MLX4_BOARD_ID_LEN = 64 +}; + enum { MLX4_DEV_CAP_FLAG_RC = 1 << 0, MLX4_DEV_CAP_FLAG_UC = 1 << 1, @@ -272,6 +276,8 @@ struct mlx4_dev { unsigned long flags; struct mlx4_caps caps; struct radix_tree_root qp_table_tree; + u32 rev_id; + char board_id[MLX4_BOARD_ID_LEN]; }; struct mlx4_init_port_param { From 03f72a51cb1a0ba530e3308e3de84399a75b41ec Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Fri, 28 Sep 2007 17:16:27 +0200 Subject: [PATCH 0820/2804] IB/ehca: Fix mem leak of firmware ctrlblock in ehca_create_srq() Signed-off-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index b10c7df669bb..2591651dac94 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -890,6 +890,8 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, goto create_srq2; } + ehca_free_fw_ctrlblock(mqpcb); + return &my_qp->ib_srq; create_srq2: From a66072237500f31cec19fa688210150de9c9f957 Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Fri, 28 Sep 2007 17:18:47 +0200 Subject: [PATCH 0821/2804] IB/ehca: Adjust 64-bit alignment of create QP response for userspace Signed-off-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index d6706966a010..0f7a55d35ea7 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -351,6 +351,7 @@ struct ehca_create_qp_resp { /* qp_num assigned by ehca: sqp0/1 may have got different numbers */ u32 real_qp_num; u32 fw_handle_ofs; + u32 dummy; struct ipzu_queue_resp ipz_squeue; struct ipzu_queue_resp ipz_rqueue; }; From c01759cee91379cc3cb551bfd7c76f1b51f91ca2 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Fri, 28 Sep 2007 17:20:05 +0200 Subject: [PATCH 0822/2804] IB/ehca: Return srq_attr->max_sge in ehca_query_srq() Totally forgot this. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 2591651dac94..e2bd62be11e7 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -1753,6 +1753,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr) } srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1; + srq_attr->max_sge = qpcb->actual_nr_sges_in_rq_wqe; srq_attr->srq_limit = EHCA_BMASK_GET( MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit); From 2be8e3ee8efd6f99ce454115c29d09750915021a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:15 -0700 Subject: [PATCH 0823/2804] IB/umad: Add P_Key index support Add support for setting the P_Key index of sent MADs and getting the P_Key index of received MADs. This requires a change to the layout of the ABI structure struct ib_user_mad_hdr, so to avoid breaking compatibility, we default to the old (unchanged) ABI and add a new ioctl IB_USER_MAD_ENABLE_PKEY that allows applications that are aware of the new ABI to opt into using it. We plan on switching to the new ABI by default in a year or so, and this patch adds a warning that is printed when an application uses the old ABI, to push people towards converting to the new ABI. Signed-off-by: Roland Dreier Reviewed-by: Sean Hefty Reviewed-by: Hal Rosenstock --- Documentation/infiniband/user_mad.txt | 14 ++++ drivers/infiniband/core/user_mad.c | 102 ++++++++++++++++++-------- include/rdma/ib_user_mad.h | 50 ++++++++++++- 3 files changed, 136 insertions(+), 30 deletions(-) diff --git a/Documentation/infiniband/user_mad.txt b/Documentation/infiniband/user_mad.txt index 8ec54b974b67..744687dd195b 100644 --- a/Documentation/infiniband/user_mad.txt +++ b/Documentation/infiniband/user_mad.txt @@ -99,6 +99,20 @@ Transaction IDs request/response pairs. The upper 32 bits are reserved for use by the kernel and will be overwritten before a MAD is sent. +P_Key Index Handling + + The old ib_umad interface did not allow setting the P_Key index for + MADs that are sent and did not provide a way for obtaining the P_Key + index of received MADs. A new layout for struct ib_user_mad_hdr + with a pkey_index member has been defined; however, to preserve + binary compatibility with older applications, this new layout will + not be used unless the IB_USER_MAD_ENABLE_PKEY ioctl is called + before a file descriptor is used for anything else. + + In September 2008, the IB_USER_MAD_ABI_VERSION will be incremented + to 6, the new layout of struct ib_user_mad_hdr will be used by + default, and the IB_USER_MAD_ENABLE_PKEY ioctl will be removed. + Setting IsSM Capability Bit To set the IsSM capability bit for a port, simply open the diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index d97ded25c4ff..aee29139368c 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -118,6 +118,8 @@ struct ib_umad_file { wait_queue_head_t recv_wait; struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; int agents_dead; + u8 use_pkey_index; + u8 already_used; }; struct ib_umad_packet { @@ -147,6 +149,12 @@ static void ib_umad_release_dev(struct kref *ref) kfree(dev); } +static int hdr_size(struct ib_umad_file *file) +{ + return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) : + sizeof (struct ib_user_mad_hdr_old); +} + /* caller must hold port->mutex at least for reading */ static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id) { @@ -221,13 +229,13 @@ static void recv_handler(struct ib_mad_agent *agent, packet->length = mad_recv_wc->mad_len; packet->recv_wc = mad_recv_wc; - packet->mad.hdr.status = 0; - packet->mad.hdr.length = sizeof (struct ib_user_mad) + - mad_recv_wc->mad_len; - packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); - packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid); - packet->mad.hdr.sl = mad_recv_wc->wc->sl; - packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits; + packet->mad.hdr.status = 0; + packet->mad.hdr.length = hdr_size(file) + mad_recv_wc->mad_len; + packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); + packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid); + packet->mad.hdr.sl = mad_recv_wc->wc->sl; + packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits; + packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index; packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH); if (packet->mad.hdr.grh_present) { struct ib_ah_attr ah_attr; @@ -253,8 +261,8 @@ err1: ib_free_recv_mad(mad_recv_wc); } -static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, - size_t count) +static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf, + struct ib_umad_packet *packet, size_t count) { struct ib_mad_recv_buf *recv_buf; int left, seg_payload, offset, max_seg_payload; @@ -262,15 +270,15 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, /* We need enough room to copy the first (or only) MAD segment. */ recv_buf = &packet->recv_wc->recv_buf; if ((packet->length <= sizeof (*recv_buf->mad) && - count < sizeof (packet->mad) + packet->length) || + count < hdr_size(file) + packet->length) || (packet->length > sizeof (*recv_buf->mad) && - count < sizeof (packet->mad) + sizeof (*recv_buf->mad))) + count < hdr_size(file) + sizeof (*recv_buf->mad))) return -EINVAL; - if (copy_to_user(buf, &packet->mad, sizeof (packet->mad))) + if (copy_to_user(buf, &packet->mad, hdr_size(file))) return -EFAULT; - buf += sizeof (packet->mad); + buf += hdr_size(file); seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad)); if (copy_to_user(buf, recv_buf->mad, seg_payload)) return -EFAULT; @@ -280,7 +288,7 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, * Multipacket RMPP MAD message. Copy remainder of message. * Note that last segment may have a shorter payload. */ - if (count < sizeof (packet->mad) + packet->length) { + if (count < hdr_size(file) + packet->length) { /* * The buffer is too small, return the first RMPP segment, * which includes the RMPP message length. @@ -300,18 +308,23 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, return -EFAULT; } } - return sizeof (packet->mad) + packet->length; + return hdr_size(file) + packet->length; } -static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet, - size_t count) +static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf, + struct ib_umad_packet *packet, size_t count) { - ssize_t size = sizeof (packet->mad) + packet->length; + ssize_t size = hdr_size(file) + packet->length; if (count < size) return -EINVAL; - if (copy_to_user(buf, &packet->mad, size)) + if (copy_to_user(buf, &packet->mad, hdr_size(file))) + return -EFAULT; + + buf += hdr_size(file); + + if (copy_to_user(buf, packet->mad.data, packet->length)) return -EFAULT; return size; @@ -324,7 +337,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, struct ib_umad_packet *packet; ssize_t ret; - if (count < sizeof (struct ib_user_mad)) + if (count < hdr_size(file)) return -EINVAL; spin_lock_irq(&file->recv_lock); @@ -348,9 +361,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, spin_unlock_irq(&file->recv_lock); if (packet->recv_wc) - ret = copy_recv_mad(buf, packet, count); + ret = copy_recv_mad(file, buf, packet, count); else - ret = copy_send_mad(buf, packet, count); + ret = copy_send_mad(file, buf, packet, count); if (ret < 0) { /* Requeue packet */ @@ -442,15 +455,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, __be64 *tid; int ret, data_len, hdr_len, copy_offset, rmpp_active; - if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR) + if (count < hdr_size(file) + IB_MGMT_RMPP_HDR) return -EINVAL; packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); if (!packet) return -ENOMEM; - if (copy_from_user(&packet->mad, buf, - sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)) { + if (copy_from_user(&packet->mad, buf, hdr_size(file))) { ret = -EFAULT; goto err; } @@ -461,6 +473,13 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err; } + buf += hdr_size(file); + + if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) { + ret = -EFAULT; + goto err; + } + down_read(&file->port->mutex); agent = __get_agent(file, packet->mad.hdr.id); @@ -500,11 +519,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, IB_MGMT_RMPP_FLAG_ACTIVE; } - data_len = count - sizeof (struct ib_user_mad) - hdr_len; + data_len = count - hdr_size(file) - hdr_len; packet->msg = ib_create_send_mad(agent, be32_to_cpu(packet->mad.hdr.qpn), - 0, rmpp_active, hdr_len, - data_len, GFP_KERNEL); + packet->mad.hdr.pkey_index, rmpp_active, + hdr_len, data_len, GFP_KERNEL); if (IS_ERR(packet->msg)) { ret = PTR_ERR(packet->msg); goto err_ah; @@ -517,7 +536,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, /* Copy MAD header. Any RMPP header is already in place. */ memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR); - buf += sizeof (struct ib_user_mad); if (!rmpp_active) { if (copy_from_user(packet->msg->mad + copy_offset, @@ -646,6 +664,16 @@ found: goto out; } + if (!file->already_used) { + file->already_used = 1; + if (!file->use_pkey_index) { + printk(KERN_WARNING "user_mad: process %s did not enable " + "P_Key index support.\n", current->comm); + printk(KERN_WARNING "user_mad: Documentation/infiniband/user_mad.txt " + "has info on the new ABI.\n"); + } + } + file->agent[agent_id] = agent; ret = 0; @@ -682,6 +710,20 @@ out: return ret; } +static long ib_umad_enable_pkey(struct ib_umad_file *file) +{ + int ret = 0; + + down_write(&file->port->mutex); + if (file->already_used) + ret = -EINVAL; + else + file->use_pkey_index = 1; + up_write(&file->port->mutex); + + return ret; +} + static long ib_umad_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -690,6 +732,8 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, return ib_umad_reg_agent(filp->private_data, arg); case IB_USER_MAD_UNREGISTER_AGENT: return ib_umad_unreg_agent(filp->private_data, arg); + case IB_USER_MAD_ENABLE_PKEY: + return ib_umad_enable_pkey(filp->private_data); default: return -ENOIOCTLCMD; } diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h index d66b15ea82c4..2a32043d1abd 100644 --- a/include/rdma/ib_user_mad.h +++ b/include/rdma/ib_user_mad.h @@ -52,7 +52,7 @@ */ /** - * ib_user_mad_hdr - MAD packet header + * ib_user_mad_hdr_old - Old version of MAD packet header without pkey_index * @id - ID of agent MAD received with/to be sent with * @status - 0 on successful receive, ETIMEDOUT if no response * received (transaction ID in data[] will be set to TID of original @@ -71,6 +71,50 @@ * @gid - Remote GID in GRH * @flow_label - Flow label in GRH */ +struct ib_user_mad_hdr_old { + __u32 id; + __u32 status; + __u32 timeout_ms; + __u32 retries; + __u32 length; + __be32 qpn; + __be32 qkey; + __be16 lid; + __u8 sl; + __u8 path_bits; + __u8 grh_present; + __u8 gid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 gid[16]; + __be32 flow_label; +}; + +/** + * ib_user_mad_hdr - MAD packet header + * This layout allows specifying/receiving the P_Key index. To use + * this capability, an application must call the + * IB_USER_MAD_ENABLE_PKEY ioctl on the user MAD file handle before + * any other actions with the file handle. + * @id - ID of agent MAD received with/to be sent with + * @status - 0 on successful receive, ETIMEDOUT if no response + * received (transaction ID in data[] will be set to TID of original + * request) (ignored on send) + * @timeout_ms - Milliseconds to wait for response (unset on receive) + * @retries - Number of automatic retries to attempt + * @qpn - Remote QP number received from/to be sent to + * @qkey - Remote Q_Key to be sent with (unset on receive) + * @lid - Remote lid received from/to be sent to + * @sl - Service level received with/to be sent with + * @path_bits - Local path bits received with/to be sent with + * @grh_present - If set, GRH was received/should be sent + * @gid_index - Local GID index to send with (unset on receive) + * @hop_limit - Hop limit in GRH + * @traffic_class - Traffic class in GRH + * @gid - Remote GID in GRH + * @flow_label - Flow label in GRH + * @pkey_index - P_Key index + */ struct ib_user_mad_hdr { __u32 id; __u32 status; @@ -88,6 +132,8 @@ struct ib_user_mad_hdr { __u8 traffic_class; __u8 gid[16]; __be32 flow_label; + __u16 pkey_index; + __u8 reserved[6]; }; /** @@ -134,4 +180,6 @@ struct ib_user_mad_reg_req { #define IB_USER_MAD_UNREGISTER_AGENT _IOW(IB_IOCTL_MAGIC, 2, __u32) +#define IB_USER_MAD_ENABLE_PKEY _IO(IB_IOCTL_MAGIC, 3) + #endif /* IB_USER_MAD_H */ From a394f83bdfec10b09d8cb111e622556b2e6fd0de Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:15 -0700 Subject: [PATCH 0824/2804] IB/umad: Fix bit ordering and 32-on-64 problems on big endian systems The declaration of struct ib_user_mad_reg_req.method_mask[] exported to userspace was an array of __u32, but the kernel internally treated it as a bitmap made up of longs. This makes a difference for 64-bit big-endian kernels, where numbering the bits in an array of__u32 gives: |31.....0|63....31|95....64|127...96| while numbering the bits in an array of longs gives: |63..............0|127............64| 64-bit userspace can handle this by just treating method_mask[] as an array of longs, but 32-bit userspace is really stuck: the meaning of the bits in method_mask[] depends on whether the kernel is 32-bit or 64-bit, and there's no sane way for userspace to know that. Fix this by updating to make it clear that method_mask[] is an array of longs, and using a compat_ioctl method to convert to an array of 64-bit longs to handle the 32-on-64 problem. This fixes the interface description to match existing behavior (so working binaries continue to work) in almost all situations, and gives consistent semantics in the case of 32-bit userspace that can run on either a 32-bit or 64-bit kernel, so that the same binary can work for both 32-on-32 and 32-on-64 systems. Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 49 ++++++++++++++++++++++++------ include/rdma/ib_user_mad.h | 22 +++++++++++++- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index aee29139368c..b53eac4611de 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -607,7 +608,8 @@ static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wa return mask; } -static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) +static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, + int compat_method_mask) { struct ib_user_mad_reg_req ureq; struct ib_mad_reg_req req; @@ -622,7 +624,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) goto out; } - if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) { + if (copy_from_user(&ureq, arg, sizeof ureq)) { ret = -EFAULT; goto out; } @@ -643,8 +645,18 @@ found: if (ureq.mgmt_class) { req.mgmt_class = ureq.mgmt_class; req.mgmt_class_version = ureq.mgmt_class_version; - memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask); - memcpy(req.oui, ureq.oui, sizeof req.oui); + memcpy(req.oui, ureq.oui, sizeof req.oui); + + if (compat_method_mask) { + u32 *umm = (u32 *) ureq.method_mask; + int i; + + for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i) + req.method_mask[i] = + umm[i * 2] | ((u64) umm[i * 2 + 1] << 32); + } else + memcpy(req.method_mask, ureq.method_mask, + sizeof req.method_mask); } agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num, @@ -682,13 +694,13 @@ out: return ret; } -static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) +static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) { struct ib_mad_agent *agent = NULL; u32 id; int ret = 0; - if (get_user(id, (u32 __user *) arg)) + if (get_user(id, arg)) return -EFAULT; down_write(&file->port->mutex); @@ -729,9 +741,9 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, { switch (cmd) { case IB_USER_MAD_REGISTER_AGENT: - return ib_umad_reg_agent(filp->private_data, arg); + return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0); case IB_USER_MAD_UNREGISTER_AGENT: - return ib_umad_unreg_agent(filp->private_data, arg); + return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg); case IB_USER_MAD_ENABLE_PKEY: return ib_umad_enable_pkey(filp->private_data); default: @@ -739,6 +751,23 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, } } +#ifdef CONFIG_COMPAT +static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case IB_USER_MAD_REGISTER_AGENT: + return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1); + case IB_USER_MAD_UNREGISTER_AGENT: + return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg)); + case IB_USER_MAD_ENABLE_PKEY: + return ib_umad_enable_pkey(filp->private_data); + default: + return -ENOIOCTLCMD; + } +} +#endif + static int ib_umad_open(struct inode *inode, struct file *filp) { struct ib_umad_port *port; @@ -826,7 +855,9 @@ static const struct file_operations umad_fops = { .write = ib_umad_write, .poll = ib_umad_poll, .unlocked_ioctl = ib_umad_ioctl, - .compat_ioctl = ib_umad_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ib_umad_compat_ioctl, +#endif .open = ib_umad_open, .release = ib_umad_close }; diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h index 2a32043d1abd..29d2c7205a90 100644 --- a/include/rdma/ib_user_mad.h +++ b/include/rdma/ib_user_mad.h @@ -147,6 +147,26 @@ struct ib_user_mad { __u64 data[0]; }; +/* + * Earlier versions of this interface definition declared the + * method_mask[] member as an array of __u32 but treated it as a + * bitmap made up of longs in the kernel. This ambiguity meant that + * 32-bit big-endian applications that can run on both 32-bit and + * 64-bit kernels had no consistent ABI to rely on, and 64-bit + * big-endian applications that treated method_mask as being made up + * of 32-bit words would have their bitmap misinterpreted. + * + * To clear up this confusion, we change the declaration of + * method_mask[] to use unsigned long and handle the conversion from + * 32-bit userspace to 64-bit kernel for big-endian systems in the + * compat_ioctl method. Unfortunately, to keep the structure layout + * the same, we need the method_mask[] array to be aligned only to 4 + * bytes even when long is 64 bits, which forces us into this ugly + * typedef. + */ +typedef unsigned long __attribute__((aligned(4))) packed_ulong; +#define IB_USER_MAD_LONGS_PER_METHOD_MASK (128 / (8 * sizeof (long))) + /** * ib_user_mad_reg_req - MAD registration request * @id - Set by the kernel; used to identify agent in future requests. @@ -165,7 +185,7 @@ struct ib_user_mad { */ struct ib_user_mad_reg_req { __u32 id; - __u32 method_mask[4]; + packed_ulong method_mask[IB_USER_MAD_LONGS_PER_METHOD_MASK]; __u8 qpn; __u8 mgmt_class; __u8 mgmt_class_version; From 04d29b0ede242000b24cfc34cc78fbd164c47e1a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:15 -0700 Subject: [PATCH 0825/2804] IB/uverbs: Make ib_uverbs_release_event_file() static ib_uverbs_release_event_file() is only used in uverbs_main.c, so make it static to that file. Also move the definition before the first use, so a forward declaration is not needed. Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 1 - drivers/infiniband/core/uverbs_main.c | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index c33546f9e961..c75eb6c9bd49 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -148,7 +148,6 @@ void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, int is_async, int *fd); -void ib_uverbs_release_event_file(struct kref *ref); struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); void ib_uverbs_release_ucq(struct ib_uverbs_file *file, diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 14d7ccd89195..7c2ac3905582 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -125,6 +125,14 @@ static void ib_uverbs_release_dev(struct kref *ref) complete(&dev->comp); } +static void ib_uverbs_release_event_file(struct kref *ref) +{ + struct ib_uverbs_event_file *file = + container_of(ref, struct ib_uverbs_event_file, ref); + + kfree(file); +} + void ib_uverbs_release_ucq(struct ib_uverbs_file *file, struct ib_uverbs_event_file *ev_file, struct ib_ucq_object *uobj) @@ -331,14 +339,6 @@ static unsigned int ib_uverbs_event_poll(struct file *filp, return pollflags; } -void ib_uverbs_release_event_file(struct kref *ref) -{ - struct ib_uverbs_event_file *file = - container_of(ref, struct ib_uverbs_event_file, ref); - - kfree(file); -} - static int ib_uverbs_event_fasync(int fd, struct file *filp, int on) { struct ib_uverbs_event_file *file = filp->private_data; From 5b0bf5e25efea77103b0ac7c8057cd56c778ef41 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 1 Aug 2007 12:28:20 +0300 Subject: [PATCH 0826/2804] mlx4_core: Support ICM tables in coherent memory Enable having ICM tables in coherent memory, and use coherent memory for the dMPT table. This will allow writing MPT entries for MRs both via the SW2HW_MPT command and also directly by the driver for FMR remapping without needing to flush or worry about cacheline boundaries. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/net/mlx4/icm.c | 113 +++++++++++++++++++++++++++++++--------- drivers/net/mlx4/icm.h | 7 +-- drivers/net/mlx4/main.c | 40 +++++++------- drivers/net/mlx4/mlx4.h | 1 + 4 files changed, 112 insertions(+), 49 deletions(-) diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c index b7a4aa8476fb..250e24887578 100644 --- a/drivers/net/mlx4/icm.c +++ b/drivers/net/mlx4/icm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -50,19 +51,41 @@ enum { MLX4_TABLE_CHUNK_SIZE = 1 << 18 }; -void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm) +static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) { - struct mlx4_icm_chunk *chunk, *tmp; int i; - list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { - if (chunk->nsg > 0) - pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, - PCI_DMA_BIDIRECTIONAL); + if (chunk->nsg > 0) + pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, + PCI_DMA_BIDIRECTIONAL); - for (i = 0; i < chunk->npages; ++i) - __free_pages(chunk->mem[i].page, - get_order(chunk->mem[i].length)); + for (i = 0; i < chunk->npages; ++i) + __free_pages(chunk->mem[i].page, + get_order(chunk->mem[i].length)); +} + +static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) +{ + int i; + + for (i = 0; i < chunk->npages; ++i) + dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, + lowmem_page_address(chunk->mem[i].page), + sg_dma_address(&chunk->mem[i])); +} + +void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent) +{ + struct mlx4_icm_chunk *chunk, *tmp; + + if (!icm) + return; + + list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { + if (coherent) + mlx4_free_icm_coherent(dev, chunk); + else + mlx4_free_icm_pages(dev, chunk); kfree(chunk); } @@ -70,16 +93,45 @@ void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm) kfree(icm); } +static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask) +{ + mem->page = alloc_pages(gfp_mask, order); + if (!mem->page) + return -ENOMEM; + + mem->length = PAGE_SIZE << order; + mem->offset = 0; + return 0; +} + +static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, + int order, gfp_t gfp_mask) +{ + void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, + &sg_dma_address(mem), gfp_mask); + if (!buf) + return -ENOMEM; + + sg_set_buf(mem, buf, PAGE_SIZE << order); + BUG_ON(mem->offset); + sg_dma_len(mem) = PAGE_SIZE << order; + return 0; +} + struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, - gfp_t gfp_mask) + gfp_t gfp_mask, int coherent) { struct mlx4_icm *icm; struct mlx4_icm_chunk *chunk = NULL; int cur_order; + int ret; + + /* We use sg_set_buf for coherent allocs, which assumes low memory */ + BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM)); icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); if (!icm) - return icm; + return NULL; icm->refcount = 0; INIT_LIST_HEAD(&icm->chunk_list); @@ -101,12 +153,20 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, while (1 << cur_order > npages) --cur_order; - chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order); - if (chunk->mem[chunk->npages].page) { - chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order; - chunk->mem[chunk->npages].offset = 0; + if (coherent) + ret = mlx4_alloc_icm_coherent(&dev->pdev->dev, + &chunk->mem[chunk->npages], + cur_order, gfp_mask); + else + ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages], + cur_order, gfp_mask); - if (++chunk->npages == MLX4_ICM_CHUNK_LEN) { + if (!ret) { + ++chunk->npages; + + if (coherent) + ++chunk->nsg; + else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -125,7 +185,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, } } - if (chunk) { + if (!coherent && chunk) { chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -137,7 +197,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, return icm; fail: - mlx4_free_icm(dev, icm); + mlx4_free_icm(dev, icm, coherent); return NULL; } @@ -202,7 +262,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT, (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN); + __GFP_NOWARN, table->coherent); if (!table->icm[i]) { ret = -ENOMEM; goto out; @@ -210,7 +270,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) if (mlx4_MAP_ICM(dev, table->icm[i], table->virt + (u64) i * MLX4_TABLE_CHUNK_SIZE)) { - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], table->coherent); table->icm[i] = NULL; ret = -ENOMEM; goto out; @@ -234,7 +294,7 @@ void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) if (--table->icm[i]->refcount == 0) { mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], table->coherent); table->icm[i] = NULL; } @@ -309,7 +369,7 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, u64 virt, int obj_size, int nobj, int reserved, - int use_lowmem) + int use_lowmem, int use_coherent) { int obj_per_chunk; int num_icm; @@ -327,6 +387,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, table->num_obj = nobj; table->obj_size = obj_size; table->lowmem = use_lowmem; + table->coherent = use_coherent; mutex_init(&table->mutex); for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) { @@ -336,11 +397,11 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT, (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN); + __GFP_NOWARN, use_coherent); if (!table->icm[i]) goto err; if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) { - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], use_coherent); table->icm[i] = NULL; goto err; } @@ -359,7 +420,7 @@ err: if (table->icm[i]) { mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE, MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], use_coherent); } return -ENOMEM; @@ -373,7 +434,7 @@ void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table) if (table->icm[i]) { mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], table->coherent); } kfree(table->icm); diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h index bea223d879a5..a77db6de8597 100644 --- a/drivers/net/mlx4/icm.h +++ b/drivers/net/mlx4/icm.h @@ -67,8 +67,9 @@ struct mlx4_icm_iter { struct mlx4_dev; -struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, gfp_t gfp_mask); -void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm); +struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, + gfp_t gfp_mask, int coherent); +void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); @@ -78,7 +79,7 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, int start, int end); int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, u64 virt, int obj_size, int nobj, int reserved, - int use_lowmem); + int use_lowmem, int use_coherent); void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 9e590e11c1cf..07c2847a7cc8 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -168,7 +168,7 @@ static int __devinit mlx4_load_fw(struct mlx4_dev *dev) int err; priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages, - GFP_HIGHUSER | __GFP_NOWARN); + GFP_HIGHUSER | __GFP_NOWARN, 0); if (!priv->fw.fw_icm) { mlx4_err(dev, "Couldn't allocate FW area, aborting.\n"); return -ENOMEM; @@ -192,7 +192,7 @@ err_unmap_fa: mlx4_UNMAP_FA(dev); err_free: - mlx4_free_icm(dev, priv->fw.fw_icm); + mlx4_free_icm(dev, priv->fw.fw_icm, 0); return err; } @@ -207,7 +207,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, ((u64) (MLX4_CMPT_TYPE_QP * cmpt_entry_sz) << MLX4_CMPT_SHIFT), cmpt_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) goto err; @@ -216,7 +216,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, ((u64) (MLX4_CMPT_TYPE_SRQ * cmpt_entry_sz) << MLX4_CMPT_SHIFT), cmpt_entry_sz, dev->caps.num_srqs, - dev->caps.reserved_srqs, 0); + dev->caps.reserved_srqs, 0, 0); if (err) goto err_qp; @@ -225,7 +225,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, ((u64) (MLX4_CMPT_TYPE_CQ * cmpt_entry_sz) << MLX4_CMPT_SHIFT), cmpt_entry_sz, dev->caps.num_cqs, - dev->caps.reserved_cqs, 0); + dev->caps.reserved_cqs, 0, 0); if (err) goto err_srq; @@ -236,7 +236,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, cmpt_entry_sz, roundup_pow_of_two(MLX4_NUM_EQ + dev->caps.reserved_eqs), - MLX4_NUM_EQ + dev->caps.reserved_eqs, 0); + MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0); if (err) goto err_cq; @@ -275,7 +275,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, (unsigned long long) aux_pages << 2); priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages, - GFP_HIGHUSER | __GFP_NOWARN); + GFP_HIGHUSER | __GFP_NOWARN, 0); if (!priv->fw.aux_icm) { mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n"); return -ENOMEM; @@ -303,7 +303,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->mtt_base, dev->caps.mtt_entry_sz, dev->caps.num_mtt_segs, - dev->caps.reserved_mtts, 1); + dev->caps.reserved_mtts, 1, 0); if (err) { mlx4_err(dev, "Failed to map MTT context memory, aborting.\n"); goto err_unmap_eq; @@ -313,7 +313,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->dmpt_base, dev_cap->dmpt_entry_sz, dev->caps.num_mpts, - dev->caps.reserved_mrws, 1); + dev->caps.reserved_mrws, 1, 1); if (err) { mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n"); goto err_unmap_mtt; @@ -323,7 +323,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->qpc_base, dev_cap->qpc_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) { mlx4_err(dev, "Failed to map QP context memory, aborting.\n"); goto err_unmap_dmpt; @@ -333,7 +333,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->auxc_base, dev_cap->aux_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) { mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n"); goto err_unmap_qp; @@ -343,7 +343,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->altc_base, dev_cap->altc_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) { mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n"); goto err_unmap_auxc; @@ -353,7 +353,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->rdmarc_base, dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) { mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n"); goto err_unmap_altc; @@ -363,7 +363,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->cqc_base, dev_cap->cqc_entry_sz, dev->caps.num_cqs, - dev->caps.reserved_cqs, 0); + dev->caps.reserved_cqs, 0, 0); if (err) { mlx4_err(dev, "Failed to map CQ context memory, aborting.\n"); goto err_unmap_rdmarc; @@ -373,7 +373,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->srqc_base, dev_cap->srq_entry_sz, dev->caps.num_srqs, - dev->caps.reserved_srqs, 0); + dev->caps.reserved_srqs, 0, 0); if (err) { mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n"); goto err_unmap_cq; @@ -388,7 +388,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->mc_base, MLX4_MGM_ENTRY_SIZE, dev->caps.num_mgms + dev->caps.num_amgms, dev->caps.num_mgms + dev->caps.num_amgms, - 0); + 0, 0); if (err) { mlx4_err(dev, "Failed to map MCG context memory, aborting.\n"); goto err_unmap_srq; @@ -433,7 +433,7 @@ err_unmap_aux: mlx4_UNMAP_ICM_AUX(dev); err_free_aux: - mlx4_free_icm(dev, priv->fw.aux_icm); + mlx4_free_icm(dev, priv->fw.aux_icm, 0); return err; } @@ -458,7 +458,7 @@ static void mlx4_free_icms(struct mlx4_dev *dev) mlx4_unmap_eq_icm(dev); mlx4_UNMAP_ICM_AUX(dev); - mlx4_free_icm(dev, priv->fw.aux_icm); + mlx4_free_icm(dev, priv->fw.aux_icm, 0); } static void mlx4_close_hca(struct mlx4_dev *dev) @@ -466,7 +466,7 @@ static void mlx4_close_hca(struct mlx4_dev *dev) mlx4_CLOSE_HCA(dev, 0); mlx4_free_icms(dev); mlx4_UNMAP_FA(dev); - mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm); + mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0); } static int __devinit mlx4_init_hca(struct mlx4_dev *dev) @@ -537,7 +537,7 @@ err_free_icm: err_stop_fw: mlx4_UNMAP_FA(dev); - mlx4_free_icm(dev, priv->fw.fw_icm); + mlx4_free_icm(dev, priv->fw.fw_icm, 0); return err; } diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index b9f839761919..2bad045b25cf 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -129,6 +129,7 @@ struct mlx4_icm_table { int num_obj; int obj_size; int lowmem; + int coherent; struct mutex mutex; struct mlx4_icm **icm; }; From cf78237d7b0e683d172e40b1e85b26ca49a3cdba Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:16 -0700 Subject: [PATCH 0827/2804] mlx4_core: Reserve the correct number of MTT segments Taking ilog2(dev->caps.reserved_mtts) to find out the order to pass to the MTT buddy allocator will do the wrong thing if reserved_mtts is ever not a power of 2. Be safe and use fls(dev->caps.reserved_mtts - 1). Signed-off-by: Roland Dreier --- drivers/net/mlx4/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 5b87183e62ce..60a6ee27cfd4 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -444,7 +444,7 @@ int __devinit mlx4_init_mr_table(struct mlx4_dev *dev) goto err_buddy; if (dev->caps.reserved_mtts) { - if (mlx4_alloc_mtt_range(dev, ilog2(dev->caps.reserved_mtts)) == -1) { + if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) { mlx4_warn(dev, "MTT table of order %d is too small.\n", mr_table->mtt_buddy.max_order); err = -ENOMEM; From 121964ec38d3e17b5ea6183b3c0571df2f4b0eb6 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:16 -0700 Subject: [PATCH 0828/2804] mlx4_core: Fix meaning of dev->caps.reserved_mtts Everything that uses caps.reserved_mtts expects it to be a count of MTT segments, not MTT entries. So convert the value that the FW gives us to a count of segments. Signed-off-by: Roland Dreier --- drivers/net/mlx4/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 07c2847a7cc8..ed7e8d76cde0 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -149,7 +149,8 @@ static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev dev->caps.max_cqes = dev_cap->max_cq_sz - 1; dev->caps.reserved_cqs = dev_cap->reserved_cqs; dev->caps.reserved_eqs = dev_cap->reserved_eqs; - dev->caps.reserved_mtts = dev_cap->reserved_mtts; + dev->caps.reserved_mtts = DIV_ROUND_UP(dev_cap->reserved_mtts, + MLX4_MTT_ENTRY_PER_SEG); dev->caps.reserved_mrws = dev_cap->reserved_mrws; dev->caps.reserved_uars = dev_cap->reserved_uars; dev->caps.reserved_pds = dev_cap->reserved_pds; From d7bb58fb1c0e7264a7261c7d0304121ef9402e94 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 1 Aug 2007 12:28:53 +0300 Subject: [PATCH 0829/2804] mlx4_core: Write MTTs from CPU instead with of WRITE_MTT FW command Write MTT entries directly to ICM from the driver (eliminating use of WRITE_MTT command). This reduces the number of FW commands needed to register an MR by at least a factor of 2 and speeds up memory registration significantly. This code will also be used to implement FMRs. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/mr.c | 7 ++-- drivers/net/mlx4/icm.c | 21 +++++++--- drivers/net/mlx4/icm.h | 2 +- drivers/net/mlx4/main.c | 11 +++++ drivers/net/mlx4/mr.c | 73 ++++++++++++++++----------------- 5 files changed, 67 insertions(+), 47 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index 85ae906f1d12..734ec2bd15cd 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -96,11 +96,10 @@ int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt, pages[i++] = sg_dma_address(&chunk->page_list[j]) + umem->page_size * k; /* - * Be friendly to WRITE_MTT firmware - * command, and pass it chunks of - * appropriate size. + * Be friendly to mlx4_write_mtt() and + * pass it chunks of appropriate size. */ - if (i == PAGE_SIZE / sizeof (u64) - 2) { + if (i == PAGE_SIZE / sizeof (u64)) { err = mlx4_write_mtt(dev->dev, mtt, n, i, pages); if (err) diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c index 250e24887578..4b3c109d5eae 100644 --- a/drivers/net/mlx4/icm.c +++ b/drivers/net/mlx4/icm.c @@ -301,9 +301,9 @@ void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) mutex_unlock(&table->mutex); } -void *mlx4_table_find(struct mlx4_icm_table *table, int obj) +void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle) { - int idx, offset, i; + int idx, offset, dma_offset, i; struct mlx4_icm_chunk *chunk; struct mlx4_icm *icm; struct page *page = NULL; @@ -313,15 +313,26 @@ void *mlx4_table_find(struct mlx4_icm_table *table, int obj) mutex_lock(&table->mutex); - idx = obj & (table->num_obj - 1); - icm = table->icm[idx / (MLX4_TABLE_CHUNK_SIZE / table->obj_size)]; - offset = idx % (MLX4_TABLE_CHUNK_SIZE / table->obj_size); + idx = (obj & (table->num_obj - 1)) * table->obj_size; + icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE]; + dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE; if (!icm) goto out; list_for_each_entry(chunk, &icm->chunk_list, list) { for (i = 0; i < chunk->npages; ++i) { + if (dma_handle && dma_offset >= 0) { + if (sg_dma_len(&chunk->mem[i]) > dma_offset) + *dma_handle = sg_dma_address(&chunk->mem[i]) + + dma_offset; + dma_offset -= sg_dma_len(&chunk->mem[i]); + } + /* + * DMA mapping can merge pages but not split them, + * so if we found the page, dma_handle has already + * been assigned to. + */ if (chunk->mem[i].length > offset) { page = chunk->mem[i].page; goto out; diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h index a77db6de8597..6c44edf35847 100644 --- a/drivers/net/mlx4/icm.h +++ b/drivers/net/mlx4/icm.h @@ -83,7 +83,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); -void *mlx4_table_find(struct mlx4_icm_table *table, int obj); +void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle); int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, int start, int end); void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index ed7e8d76cde0..478b3ba74edc 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -300,6 +300,17 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, goto err_unmap_cmpt; } + /* + * Reserved MTT entries must be aligned up to a cacheline + * boundary, since the FW will write to them, while the driver + * writes to all other MTT entries. (The variable + * dev->caps.mtt_entry_sz below is really the MTT segment + * size, not the raw entry size) + */ + dev->caps.reserved_mtts = + ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz, + dma_get_cache_alignment()) / dev->caps.mtt_entry_sz; + err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table, init_hca->mtt_base, dev->caps.mtt_entry_sz, diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 60a6ee27cfd4..3cc98c699aaf 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -349,58 +349,57 @@ err_table: } EXPORT_SYMBOL_GPL(mlx4_mr_enable); -static int mlx4_WRITE_MTT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int num_mtt) +static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list) { - return mlx4_cmd(dev, mailbox->dma, num_mtt, 0, MLX4_CMD_WRITE_MTT, - MLX4_CMD_TIME_CLASS_B); + struct mlx4_priv *priv = mlx4_priv(dev); + __be64 *mtts; + dma_addr_t dma_handle; + int i; + int s = start_index * sizeof (u64); + + /* All MTTs must fit in the same page */ + if (start_index / (PAGE_SIZE / sizeof (u64)) != + (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64))) + return -EINVAL; + + if (start_index & (MLX4_MTT_ENTRY_PER_SEG - 1)) + return -EINVAL; + + mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg + + s / dev->caps.mtt_entry_sz, &dma_handle); + if (!mtts) + return -ENOMEM; + + for (i = 0; i < npages; ++i) + mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); + + return 0; } int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, int start_index, int npages, u64 *page_list) { - struct mlx4_cmd_mailbox *mailbox; - __be64 *mtt_entry; - int i; - int err = 0; + int chunk; + int err; if (mtt->order < 0) return -EINVAL; - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - mtt_entry = mailbox->buf; - while (npages > 0) { - mtt_entry[0] = cpu_to_be64(mlx4_mtt_addr(dev, mtt) + start_index * 8); - mtt_entry[1] = 0; - - for (i = 0; i < npages && i < MLX4_MAILBOX_SIZE / 8 - 2; ++i) - mtt_entry[i + 2] = cpu_to_be64(page_list[i] | - MLX4_MTT_FLAG_PRESENT); - - /* - * If we have an odd number of entries to write, add - * one more dummy entry for firmware efficiency. - */ - if (i & 1) - mtt_entry[i + 2] = 0; - - err = mlx4_WRITE_MTT(dev, mailbox, (i + 1) & ~1); + chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages); + err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); if (err) - goto out; + return err; - npages -= i; - start_index += i; - page_list += i; + npages -= chunk; + start_index += chunk; + page_list += chunk; } -out: - mlx4_free_cmd_mailbox(dev, mailbox); - - return err; + return 0; } EXPORT_SYMBOL_GPL(mlx4_write_mtt); From 8ad11fb6b0739e704953e2b0aed453bf7d75d4f6 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 1 Aug 2007 12:29:05 +0300 Subject: [PATCH 0830/2804] IB/mlx4: Implement FMRs Implement FMRs for mlx4. This is an adaptation of code from mthca. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/main.c | 5 + drivers/infiniband/hw/mlx4/mlx4_ib.h | 16 +++ drivers/infiniband/hw/mlx4/mr.c | 93 +++++++++++++++ drivers/net/mlx4/mr.c | 165 +++++++++++++++++++++++++++ include/linux/mlx4/device.h | 21 ++++ 5 files changed, 300 insertions(+) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index d9fc822a1468..d8287d9db41e 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -607,6 +607,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->ib_dev.detach_mcast = mlx4_ib_mcg_detach; ibdev->ib_dev.process_mad = mlx4_ib_process_mad; + ibdev->ib_dev.alloc_fmr = mlx4_ib_fmr_alloc; + ibdev->ib_dev.map_phys_fmr = mlx4_ib_map_phys_fmr; + ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr; + ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc; + if (init_node_data(ibdev)) goto err_map; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 705ff2fa237e..28697653a370 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -93,6 +93,11 @@ struct mlx4_ib_mr { struct ib_umem *umem; }; +struct mlx4_ib_fmr { + struct ib_fmr ibfmr; + struct mlx4_fmr mfmr; +}; + struct mlx4_ib_wq { u64 *wrid; spinlock_t lock; @@ -199,6 +204,10 @@ static inline struct mlx4_ib_mr *to_mmr(struct ib_mr *ibmr) return container_of(ibmr, struct mlx4_ib_mr, ibmr); } +static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr) +{ + return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr); +} static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp) { return container_of(ibqp, struct mlx4_ib_qp, ibqp); @@ -284,6 +293,13 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, int mlx4_ib_mad_init(struct mlx4_ib_dev *dev); void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev); +struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr); +int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages, + u64 iova); +int mlx4_ib_unmap_fmr(struct list_head *fmr_list); +int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr); + static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah) { return !!(ah->av.g_slid & 0x80); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index 734ec2bd15cd..7dc91a3e712d 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -181,3 +181,96 @@ int mlx4_ib_dereg_mr(struct ib_mr *ibmr) return 0; } + +struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc, + struct ib_fmr_attr *fmr_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_fmr *fmr; + int err = -ENOMEM; + + fmr = kmalloc(sizeof *fmr, GFP_KERNEL); + if (!fmr) + return ERR_PTR(-ENOMEM); + + err = mlx4_fmr_alloc(dev->dev, to_mpd(pd)->pdn, convert_access(acc), + fmr_attr->max_pages, fmr_attr->max_maps, + fmr_attr->page_shift, &fmr->mfmr); + if (err) + goto err_free; + + err = mlx4_mr_enable(to_mdev(pd->device)->dev, &fmr->mfmr.mr); + if (err) + goto err_mr; + + fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mfmr.mr.key; + + return &fmr->ibfmr; + +err_mr: + mlx4_mr_free(to_mdev(pd->device)->dev, &fmr->mfmr.mr); + +err_free: + kfree(fmr); + + return ERR_PTR(err); +} + +int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int npages, u64 iova) +{ + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + struct mlx4_ib_dev *dev = to_mdev(ifmr->ibfmr.device); + + return mlx4_map_phys_fmr(dev->dev, &ifmr->mfmr, page_list, npages, iova, + &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); +} + +int mlx4_ib_unmap_fmr(struct list_head *fmr_list) +{ + struct ib_fmr *ibfmr; + int err; + struct mlx4_dev *mdev = NULL; + + list_for_each_entry(ibfmr, fmr_list, list) { + if (mdev && to_mdev(ibfmr->device)->dev != mdev) + return -EINVAL; + mdev = to_mdev(ibfmr->device)->dev; + } + + if (!mdev) + return 0; + + list_for_each_entry(ibfmr, fmr_list, list) { + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + + mlx4_fmr_unmap(mdev, &ifmr->mfmr, &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); + } + + /* + * Make sure all MPT status updates are visible before issuing + * SYNC_TPT firmware command. + */ + wmb(); + + err = mlx4_SYNC_TPT(mdev); + if (err) + printk(KERN_WARNING "mlx4_ib: SYNC_TPT error %d when " + "unmapping FMRs\n", err); + + return 0; +} + +int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr) +{ + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + struct mlx4_ib_dev *dev = to_mdev(ibfmr->device); + int err; + + err = mlx4_fmr_free(dev->dev, &ifmr->mfmr); + + if (!err) + kfree(ifmr); + + return err; +} diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 3cc98c699aaf..4bc39e65015a 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -68,6 +68,9 @@ struct mlx4_mpt_entry { #define MLX4_MTT_FLAG_PRESENT 1 +#define MLX4_MPT_STATUS_SW 0xF0 +#define MLX4_MPT_STATUS_HW 0x00 + static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order) { int o; @@ -469,3 +472,165 @@ void mlx4_cleanup_mr_table(struct mlx4_dev *dev) mlx4_buddy_cleanup(&mr_table->mtt_buddy); mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); } + +static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova) +{ + int i, page_mask; + + if (npages > fmr->max_pages) + return -EINVAL; + + page_mask = (1 << fmr->page_shift) - 1; + + /* We are getting page lists, so va must be page aligned. */ + if (iova & page_mask) + return -EINVAL; + + /* Trust the user not to pass misaligned data in page_list */ + if (0) + for (i = 0; i < npages; ++i) { + if (page_list[i] & ~page_mask) + return -EINVAL; + } + + if (fmr->maps >= fmr->max_maps) + return -EINVAL; + + return 0; +} + +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 *lkey, u32 *rkey) +{ + u32 key; + int i, err; + + err = mlx4_check_fmr(fmr, page_list, npages, iova); + if (err) + return err; + + ++fmr->maps; + + key = key_to_hw_index(fmr->mr.key); + key += dev->caps.num_mpts; + *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; + + /* Make sure MPT status is visible before writing MTT entries */ + wmb(); + + for (i = 0; i < npages; ++i) + fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, fmr->dma_handle, + npages * sizeof(u64), DMA_TO_DEVICE); + + fmr->mpt->key = cpu_to_be32(key); + fmr->mpt->lkey = cpu_to_be32(key); + fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift)); + fmr->mpt->start = cpu_to_be64(iova); + + /* Make MTT entries are visible before setting MPT status */ + wmb(); + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW; + + /* Make sure MPT status is visible before consumer can use FMR */ + wmb(); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr); + +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u64 mtt_seg; + int err = -ENOMEM; + + if (page_shift < 12 || page_shift >= 32) + return -EINVAL; + + /* All MTTs must fit in the same page */ + if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) + return -EINVAL; + + fmr->page_shift = page_shift; + fmr->max_pages = max_pages; + fmr->max_maps = max_maps; + fmr->maps = 0; + + err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages, + page_shift, &fmr->mr); + if (err) + return err; + + mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz; + + fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, + fmr->mr.mtt.first_seg, + &fmr->dma_handle); + if (!fmr->mtts) { + err = -ENOMEM; + goto err_free; + } + + fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, + key_to_hw_index(fmr->mr.key), NULL); + if (!fmr->mpt) { + err = -ENOMEM; + goto err_free; + } + + return 0; + +err_free: + mlx4_mr_free(dev, &fmr->mr); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); + +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + return mlx4_mr_enable(dev, &fmr->mr); +} +EXPORT_SYMBOL_GPL(mlx4_fmr_enable); + +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u32 *lkey, u32 *rkey) +{ + u32 key; + + if (!fmr->maps) + return; + + key = key_to_hw_index(fmr->mr.key); + key &= dev->caps.num_mpts - 1; + *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); + + fmr->maps = 0; + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); + +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + if (fmr->maps) + return -EBUSY; + + fmr->mr.enabled = 0; + mlx4_mr_free(dev, &fmr->mr); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_free); + +int mlx4_SYNC_TPT(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000); +} +EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index a93520c76fde..222815d91c40 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -214,6 +214,17 @@ struct mlx4_mr { int enabled; }; +struct mlx4_fmr { + struct mlx4_mr mr; + struct mlx4_mpt_entry *mpt; + __be64 *mtts; + dma_addr_t dma_handle; + int max_pages; + int max_maps; + int maps; + u8 page_shift; +}; + struct mlx4_uar { unsigned long pfn; int index; @@ -337,4 +348,14 @@ int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port); int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]); int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]); +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 *lkey, u32 *rkey); +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr); +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u32 *lkey, u32 *rkey); +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +int mlx4_SYNC_TPT(struct mlx4_dev *dev); + #endif /* MLX4_DEVICE_H */ From e57ac0c297b9e1074dcb6b6ee5cd1d6407a7df14 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 2 Oct 2007 09:40:13 +0200 Subject: [PATCH 0831/2804] mlx4_core: Increase max number of QPs per multicast group to 56 Increase the number of QPs allowed per multicast group from 8 to 56. This allows for one QP per core on 16-core systems, which are now quite common, and allows some space for future growth. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/net/mlx4/mlx4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 2bad045b25cf..53a1cdddfc13 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -56,7 +56,7 @@ enum { }; enum { - MLX4_MGM_ENTRY_SIZE = 0x40, + MLX4_MGM_ENTRY_SIZE = 0x100, MLX4_QP_PER_MGM = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2), MLX4_MTT_ENTRY_PER_SEG = 8 }; From 1a1eb6a646f52dc62e3f9ceac4aab9c27e781186 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:17 -0700 Subject: [PATCH 0832/2804] IB/mthca: Increase max number of QPs per multicast group to 56 Increase the number of QPs allowed per multicast group from 8 to 56. This allows for one QP per core on 16-core systems, which are now quite common, and allows some space for future growth. This is basically the same patch that Jack Morgenstein just supplied for mlx4. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_dev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 9bae3cc60603..15aa32eb78b6 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -83,7 +83,7 @@ enum { MTHCA_QP_CONTEXT_SIZE = 0x200, MTHCA_RDB_ENTRY_SIZE = 0x20, MTHCA_AV_SIZE = 0x20, - MTHCA_MGM_ENTRY_SIZE = 0x40, + MTHCA_MGM_ENTRY_SIZE = 0x100, /* Arbel FW gives us these, but we need them for Tavor */ MTHCA_MPT_ENTRY_SIZE = 0x40, From de98b693e9857e183679cd2f49b3c30d2bc57629 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 1 Aug 2007 13:49:53 -0700 Subject: [PATCH 0833/2804] IB/cm: Modify interface to send MRAs in response to duplicate messages The IB CM provides a message received acknowledged (MRA) message that can be sent to indicate that a REQ or REP message has been received, but will require more time to process than the timeout specified by those messages. In many cases, the application may not know how long it will take to respond to a CM message, but the majority of the time, it will usually respond before a retry has been sent. Rather than sending an MRA in response to all messages just to handle the case where a longer timeout is needed, it is more efficient to queue the MRA for sending in case a duplicate message is received. This avoids sending an MRA when it is not needed, but limits the number of times that a REQ or REP will be resent. It also provides for a simpler implementation than generating the MRA based on a timer event. (That is, trying to send the MRA after receiving the first REQ or REP if a response has not been generated, so that it is received at the remote side before a duplicate REQ or REP has been received) Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 61 +++++++++++++++++------------------- include/rdma/ib_cm.h | 7 +++-- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 4df269f5d9ac..2e39236d189f 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -2219,6 +2219,9 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; + enum ib_cm_state cm_state; + enum ib_cm_lap_state lap_state; + enum cm_msg_response msg_response; void *data; unsigned long flags; int ret; @@ -2235,48 +2238,40 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, spin_lock_irqsave(&cm_id_priv->lock, flags); switch(cm_id_priv->id.state) { case IB_CM_REQ_RCVD: - ret = cm_alloc_msg(cm_id_priv, &msg); - if (ret) - goto error1; - - cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, - CM_MSG_RESPONSE_REQ, service_timeout, - private_data, private_data_len); - ret = ib_post_send_mad(msg, NULL); - if (ret) - goto error2; - cm_id->state = IB_CM_MRA_REQ_SENT; + cm_state = IB_CM_MRA_REQ_SENT; + lap_state = cm_id->lap_state; + msg_response = CM_MSG_RESPONSE_REQ; break; case IB_CM_REP_RCVD: - ret = cm_alloc_msg(cm_id_priv, &msg); - if (ret) - goto error1; - - cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, - CM_MSG_RESPONSE_REP, service_timeout, - private_data, private_data_len); - ret = ib_post_send_mad(msg, NULL); - if (ret) - goto error2; - cm_id->state = IB_CM_MRA_REP_SENT; + cm_state = IB_CM_MRA_REP_SENT; + lap_state = cm_id->lap_state; + msg_response = CM_MSG_RESPONSE_REP; break; case IB_CM_ESTABLISHED: - ret = cm_alloc_msg(cm_id_priv, &msg); - if (ret) - goto error1; - - cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, - CM_MSG_RESPONSE_OTHER, service_timeout, - private_data, private_data_len); - ret = ib_post_send_mad(msg, NULL); - if (ret) - goto error2; - cm_id->lap_state = IB_CM_MRA_LAP_SENT; + cm_state = cm_id->state; + lap_state = IB_CM_MRA_LAP_SENT; + msg_response = CM_MSG_RESPONSE_OTHER; break; default: ret = -EINVAL; goto error1; } + + if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) { + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto error1; + + cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, + msg_response, service_timeout, + private_data, private_data_len); + ret = ib_post_send_mad(msg, NULL); + if (ret) + goto error2; + } + + cm_id->state = cm_state; + cm_id->lap_state = lap_state; cm_id_priv->service_timeout = service_timeout; cm_set_private_data(cm_id_priv, data, private_data_len); spin_unlock_irqrestore(&cm_id_priv->lock, flags); diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 12243e80c706..a627c8682d2f 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -477,12 +477,15 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id, const void *private_data, u8 private_data_len); +#define IB_CM_MRA_FLAG_DELAY 0x80 /* Send MRA only after a duplicate msg */ + /** * ib_send_cm_mra - Sends a message receipt acknowledgement to a connection * message. * @cm_id: Connection identifier associated with the connection message. - * @service_timeout: The maximum time required for the sender to reply to - * to the connection message. + * @service_timeout: The lower 5-bits specify the maximum time required for + * the sender to reply to to the connection message. The upper 3-bits + * specify additional control flags. * @private_data: Optional user-defined private data sent with the * message receipt acknowledgement. * @private_data_len: Size of the private data buffer, in bytes. From dcb3f974da827c964cb8d419fbb4350cdc08a559 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 1 Aug 2007 14:47:16 -0700 Subject: [PATCH 0834/2804] RDMA/cma: Queue IB CM MRAs to avoid unnecessary remote retries Automatically queue MRA message to decrease the number of retries sent by the remote side during connection establishment. This also has the effect of increasing the overall connection timeout without using a longer retry time in the case of dropped packets. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 19c9172f0cdc..72539529fa66 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -52,6 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL"); #define CMA_CM_RESPONSE_TIMEOUT 20 #define CMA_MAX_CM_RETRIES 15 +#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) static void cma_add_one(struct ib_device *device); static void cma_remove_one(struct ib_device *device); @@ -1090,6 +1091,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) event.param.ud.private_data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; } else { + ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); conn_id = cma_new_conn_id(&listen_id->id, ib_event); cma_set_req_event_data(&event, &ib_event->param.req_rcvd, ib_event->private_data, offset); From 76d7cc0345a037e8eea426f8abc710abd22946dd Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:17 -0700 Subject: [PATCH 0835/2804] IB/mthca: Use mmiowb() to avoid firmware commands getting jumbled up Firmware commands are sent to the HCA by writing multiple words to a command register block. Access to this block of registers is serialized with a mutex. However, on large SGI systems, problems were seen with multiple CPUs issuing FW commands at the same time, because the writes to the register block may be reordered within the system interconnect and reach the HCA in a different order than they were issued (even with the mutex). Fix this by adding an mmiowb() before dropping the mutex. Tested-by: Arthur Kepner Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cmd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index acc95892713a..6966f943f440 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -290,6 +290,12 @@ static int mthca_cmd_post(struct mthca_dev *dev, err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier, op_modifier, op, token, event); + /* + * Make sure that our HCR writes don't get mixed in with + * writes from another CPU starting a FW command. + */ + mmiowb(); + mutex_unlock(&dev->cmd.hcr_mutex); return err; } From 2e61c646edfa013203e3428762f8d6a72e10bdea Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:18 -0700 Subject: [PATCH 0836/2804] mlx4_core: Use mmiowb() to avoid firmware commands getting jumbled up Firmware commands are sent to the HCA by writing multiple words to a command register block. Access to this block of registers is serialized with a mutex. However, on large SGI systems writes to the register block may be reordered within the system interconnect and reach the HCA in a different order than they were issued (even with the mutex). Fix this by adding an mmiowb() before dropping the mutex. This bug was observed with real workloads with the similar FW command code in the mthca driver, and adding the mmiowb() as in commit 66547550 ("IB/mthca: Use mmiowb() to avoid firmware commands getting jumbled up") was confirmed to fix the problems, so we should add the same fix to mlx4. Signed-off-by: Roland Dreier --- drivers/net/mlx4/cmd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c index b540820e9c25..db49051b97b1 100644 --- a/drivers/net/mlx4/cmd.c +++ b/drivers/net/mlx4/cmd.c @@ -184,6 +184,13 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, (event ? (1 << HCR_E_BIT) : 0) | (op_modifier << HCR_OPMOD_SHIFT) | op), hcr + 6); + + /* + * Make sure that our HCR writes don't get mixed in with + * writes from another CPU starting a FW command. + */ + mmiowb(); + cmd->toggle = cmd->toggle ^ 1; ret = 0; From ede6bc04f3a07a9c93f02c92cdc281d254398321 Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Sun, 7 Oct 2007 09:30:48 +0200 Subject: [PATCH 0837/2804] IPoIB/cm: Clean up initialization of QP attr in ipoib_cm_create_tx_qp() Make the way QP is being created in ipoib_cm_create_tx_qp() consistent with ipoib_cm_create_rx_qp(). Signed-off-by: Dotan Barak Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 08b4676a3820..23addb3a6f4e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -810,14 +810,16 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ib_cq *cq) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ib_qp_init_attr attr = {}; - attr.recv_cq = priv->cq; - attr.srq = priv->cm.srq; - attr.cap.max_send_wr = ipoib_sendq_size; - attr.cap.max_send_sge = 1; - attr.sq_sig_type = IB_SIGNAL_ALL_WR; - attr.qp_type = IB_QPT_RC; - attr.send_cq = cq; + struct ib_qp_init_attr attr = { + .send_cq = cq, + .recv_cq = priv->cq, + .srq = priv->cm.srq, + .cap.max_send_wr = ipoib_sendq_size, + .cap.max_send_sge = 1, + .sq_sig_type = IB_SIGNAL_ALL_WR, + .qp_type = IB_QPT_RC, + }; + return ib_create_qp(priv->pd, &attr); } From 76dea3bc2644e99cce1d98d0bbd3124314e5b50a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:18 -0700 Subject: [PATCH 0838/2804] IB/ehca: Fix clipping of device limits to INT_MAX Doing min_t(int, foo, INT_MAX) doesn't work correctly, because if foo is bigger than INT_MAX, then when treated as a signed integer, it will become negative and hence such an expression is just an elaborate NOP. Fix such cases in ehca to do min_t(unsigned, foo, INT_MAX) instead. This fixes negative reported values for max_cqe, max_pd and max_ah: Before: max_cqe: -64 max_pd: -1 max_ah: -1 After: max_cqe: 2147483647 max_pd: 2147483647 max_ah: 2147483647 Based on a bug report and fix from Anton Blanchard . Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_hca.c | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index 3436c49eee06..4aa3ffa6a19f 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -82,17 +82,17 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) props->vendor_id = rblock->vendor_id >> 8; props->vendor_part_id = rblock->vendor_part_id >> 16; props->hw_ver = rblock->hw_ver; - props->max_qp = min_t(int, rblock->max_qp, INT_MAX); - props->max_qp_wr = min_t(int, rblock->max_wqes_wq, INT_MAX); - props->max_sge = min_t(int, rblock->max_sge, INT_MAX); - props->max_sge_rd = min_t(int, rblock->max_sge_rd, INT_MAX); - props->max_cq = min_t(int, rblock->max_cq, INT_MAX); - props->max_cqe = min_t(int, rblock->max_cqe, INT_MAX); - props->max_mr = min_t(int, rblock->max_mr, INT_MAX); - props->max_mw = min_t(int, rblock->max_mw, INT_MAX); - props->max_pd = min_t(int, rblock->max_pd, INT_MAX); - props->max_ah = min_t(int, rblock->max_ah, INT_MAX); - props->max_fmr = min_t(int, rblock->max_mr, INT_MAX); + props->max_qp = min_t(unsigned, rblock->max_qp, INT_MAX); + props->max_qp_wr = min_t(unsigned, rblock->max_wqes_wq, INT_MAX); + props->max_sge = min_t(unsigned, rblock->max_sge, INT_MAX); + props->max_sge_rd = min_t(unsigned, rblock->max_sge_rd, INT_MAX); + props->max_cq = min_t(unsigned, rblock->max_cq, INT_MAX); + props->max_cqe = min_t(unsigned, rblock->max_cqe, INT_MAX); + props->max_mr = min_t(unsigned, rblock->max_mr, INT_MAX); + props->max_mw = min_t(unsigned, rblock->max_mw, INT_MAX); + props->max_pd = min_t(unsigned, rblock->max_pd, INT_MAX); + props->max_ah = min_t(unsigned, rblock->max_ah, INT_MAX); + props->max_fmr = min_t(unsigned, rblock->max_mr, INT_MAX); if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) { props->max_srq = props->max_qp; @@ -104,15 +104,15 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) props->local_ca_ack_delay = rblock->local_ca_ack_delay; props->max_raw_ipv6_qp - = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX); + = min_t(unsigned, rblock->max_raw_ipv6_qp, INT_MAX); props->max_raw_ethy_qp - = min_t(int, rblock->max_raw_ethy_qp, INT_MAX); + = min_t(unsigned, rblock->max_raw_ethy_qp, INT_MAX); props->max_mcast_grp - = min_t(int, rblock->max_mcast_grp, INT_MAX); + = min_t(unsigned, rblock->max_mcast_grp, INT_MAX); props->max_mcast_qp_attach - = min_t(int, rblock->max_mcast_qp_attach, INT_MAX); + = min_t(unsigned, rblock->max_mcast_qp_attach, INT_MAX); props->max_total_mcast_qp_attach - = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX); + = min_t(unsigned, rblock->max_total_mcast_qp_attach, INT_MAX); /* translate device capabilities */ props->device_cap_flags = IB_DEVICE_SYS_IMAGE_GUID | From ba366a23b68029fc8560acf1ad8735eed910f962 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 18:12:08 -0300 Subject: [PATCH 0839/2804] V4L/DVB (6257): Rename video-buf-dvb to videobuf-dvb to be consistent with the other patches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 2 +- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/saa7134/saa7134.h | 2 +- drivers/media/video/{video-buf-dvb.c => videobuf-dvb.c} | 2 +- include/media/{video-buf-dvb.h => videobuf-dvb.h} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename drivers/media/video/{video-buf-dvb.c => videobuf-dvb.c} (99%) rename include/media/{video-buf-dvb.h => videobuf-dvb.h} (100%) diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c8140aec1a16..b5a064163e03 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -90,7 +90,7 @@ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o -obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o +obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 875a9abab2a2..b3fe2d59cd13 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -32,7 +32,7 @@ #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) -#include +#include #endif #include "btcx-risc.h" diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index dae608f9bf3b..cb617c8dbb71 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -42,7 +42,7 @@ #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) -#include +#include #endif #define UNSET (-1U) diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/videobuf-dvb.c similarity index 99% rename from drivers/media/video/video-buf-dvb.c rename to drivers/media/video/videobuf-dvb.c index 9631ead297ee..880317e04a02 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -23,7 +23,7 @@ #include #include -#include +#include /* ------------------------------------------------------------------ */ diff --git a/include/media/video-buf-dvb.h b/include/media/videobuf-dvb.h similarity index 100% rename from include/media/video-buf-dvb.h rename to include/media/videobuf-dvb.h From 327a338d4fd018d33e7cacde46c0d82622b4bda8 Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Thu, 2 Aug 2007 14:46:29 -0700 Subject: [PATCH 0840/2804] IB/ipath: iba6110 rev4 GPIO counters support On iba6110 rev4, support for three more IB counters were added. The LocalLinkIntegrityError counter, the ExcessiveBufferOverrunErrors counter and support for error counting of flow control packets on an invalid VL. These counters trigger GPIO interrupts and the sw keeps track of the counts. Since we also use GPIO interrupts to signal packet reception, we need to turn off the fast interrupts, or we risk losing a GPIO interrupt. Signed-off-by: Arthur Jones Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_iba6110.c | 8 ++++++++ drivers/infiniband/hw/ipath/ipath_intr.c | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index 650745d83fac..e1c5998887ea 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -1559,6 +1559,14 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) ipath_dev_err(dd, "Unsupported InfiniPath serial " "number %.16s!\n", dd->ipath_serial); + if (dd->ipath_minrev >= 4) { + /* Rev4+ reports extra errors via internal GPIO pins */ + dd->ipath_flags |= IPATH_GPIO_ERRINTRS; + dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK; + ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, + dd->ipath_gpio_mask); + } + return 0; } diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index b29fe7e9b11a..11b361408ae6 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -1085,8 +1085,8 @@ irqreturn_t ipath_intr(int irq, void *data) * GPIO_2 indicates (on some HT4xx boards) that a packet * has arrived for Port 0. Checking for this * is controlled by flag IPATH_GPIO_INTR. - * GPIO_3..5 on IBA6120 Rev2 chips indicate errors - * that we need to count. Checking for this + * GPIO_3..5 on IBA6120 Rev2 and IBA6110 Rev4 chips indicate + * errors that we need to count. Checking for this * is controlled by flag IPATH_GPIO_ERRINTRS. */ u32 gpiostatus; From 40558dafff257d69248af8b96c7e896f6bc79dfa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Aug 2007 07:37:34 -0300 Subject: [PATCH 0841/2804] V4L/DVB (6259): Fix vivi poll() method Due to the replace of videobuf_read_one to videobuf_read_stream, poll() method implementation is wrong. This fixes poll() implementation, making read of /dev/video? to work again. With this method, an USB driver can use video-buf, without needing to request memory from the DMA-safe area. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index c14e2b3e4241..01c977671311 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1122,9 +1122,8 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) } else { dprintk(1,"poll: read() interface\n"); /* read() capture */ - buf = (struct vivi_buffer*)fh->vb_vidq.read_buf; - if (NULL == buf) - return POLLERR; + return videobuf_poll_stream(file, &fh-> vb_vidq, + wait); } poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == STATE_DONE || From 28318c72adc14952d05d8037d73cec852247791c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 2 Oct 2007 11:16:16 -0300 Subject: [PATCH 0842/2804] V4L/DVB (6260): Fix Kconfig dependency Thanks to Michael Krufky for pointing this to me. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 +- drivers/media/video/cx23885/Kconfig | 4 ++-- drivers/media/video/cx88/Kconfig | 2 +- drivers/media/video/saa7134/Kconfig | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index fc3ea4c67ccb..e705265909da 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -138,7 +138,7 @@ config VIDEOBUF_VMALLOC select VIDEOBUF_GEN tristate -config VIDEO_BUF_DVB +config VIDEOBUF_DVB tristate config VIDEO_BTCX diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ebfcc7c2a89e..af60700da8c0 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,11 +4,11 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index c68ba74d44ec..eeb5224ca101 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -46,7 +46,7 @@ config VIDEO_CX88_BLACKBIRD config VIDEO_CX88_DVB tristate "DVB/ATSC Support for cx2388x based TV cards" depends on VIDEO_CX88 && DVB_CORE - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 82bc4ef414ac..d6d8d660196d 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -38,7 +38,7 @@ config VIDEO_SAA7134_OSS config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE From c520a4970c7e5f18275ef935372e56eabd6d0e44 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 18:55:07 -0300 Subject: [PATCH 0843/2804] V4L/DVB (6261): Cleans mem->vmalloc after vfree Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 993d5285e18e..6ef4f523689a 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -372,6 +372,7 @@ void videobuf_vmalloc_free (struct videobuf_buffer *buf) MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); vfree(mem->vmalloc); + mem->vmalloc=NULL; return; } From e78dcf55520769471c66024b13df7e9e592436f4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 19:08:24 -0300 Subject: [PATCH 0844/2804] V4L/DVB (6262): An allocation error message were being printed as a debug msg Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 6ef4f523689a..b2abfc9d9a8e 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -140,7 +140,6 @@ static int __videobuf_iolock (struct videobuf_queue* q, MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ @@ -153,7 +152,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, /* FIXME: should be tested with kernel mmap mem */ mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); if (NULL == mem->vmalloc) { - dprintk(1,"vmalloc (%d pages) failed\n",pages); + printk(KERN_ERR "vmalloc (%d pages) failed\n",pages); return -ENOMEM; } From 123f8ef64e3996e06a930756b6b2cdede4b18da0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 20:11:35 -0300 Subject: [PATCH 0845/2804] V4L/DVB (6263): Fix buffer release code Release code should happen before the cleaning of map variable. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index b2abfc9d9a8e..fd059cde63f4 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -84,9 +84,11 @@ videobuf_vm_close(struct vm_area_struct *vma) if (mem->map != map) continue; + + q->ops->buf_release(q,q->bufs[i]); + mem->map = NULL; q->bufs[i]->baddr = 0; - q->ops->buf_release(q,q->bufs[i]); } mutex_unlock(&q->lock); kfree(map); From 3bef5e4a1f73898dc8c8433f938d3a8b22f2be22 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 22 Sep 2007 02:01:33 -0300 Subject: [PATCH 0846/2804] V4L/DVB (6264): Make the vertical lines to move While this is not the standard color bar behaviour, having some movement there allows to check if buffers are being properly handled. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 01c977671311..650e959aeb78 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -229,9 +229,8 @@ static u8 bars[8][3] = { #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 - static void gen_line(char *basep,int inipos,int wmax, - int hmax, int line, char *timestr) + int hmax, int line, int count, char *timestr) { int w,i,j,pos=inipos,y; char *p,*s; @@ -242,9 +241,10 @@ static void gen_line(char *basep,int inipos,int wmax, /* Generate a standard color bar pattern */ for (w=0;wvb); + /* FIXME: move to dev struct */ + static int mv_count=0; if (!tmpbuf) return; for (h=0;htimestr); + gen_line(tmpbuf,0,wmax,hmax,h,mv_count, + dev->timestr); /* FIXME: replacing to __copy_to_user */ if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) dprintk(2,"vivifill copy_to_user failed.\n"); pos += wmax*2; } + mv_count++; + kfree(tmpbuf); /* Updates stream time */ From cd4765efdd816ac14075fc7d5adf489502e75e1e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 25 Sep 2007 11:53:24 -0300 Subject: [PATCH 0847/2804] V4L/DVB (6265): Prevent for calling mmap_free without an allocated buffer Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 256501384af7..eb3b98400c1b 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -880,6 +880,9 @@ int videobuf_mmap_free(struct videobuf_queue *q) int i; int rc; + if (!q) + return 0; + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); rc = CALL(q,mmap_free,q); From 851c0c96b2212f48fe51afc1589541b5eae3a544 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Sep 2007 18:25:44 -0300 Subject: [PATCH 0848/2804] V4L/DVB (6266): videobuf cleanup: mmap check is common to all videobuf. Make it at core Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 4 +-- drivers/media/video/videobuf-dma-sg.c | 24 ++++------------- drivers/media/video/videobuf-vmalloc.c | 36 +++++++------------------- include/media/videobuf-core.h | 4 ++- include/media/videobuf-dma-sg.h | 1 - include/media/videobuf-vmalloc.h | 3 --- 6 files changed, 20 insertions(+), 52 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index eb3b98400c1b..3bd06bb633a7 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -149,7 +149,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - if (CALL(q,is_mmapped,q->bufs[i])) { + if (q->bufs[i]->map) { dprintk(1,"busy: buffer #%d mapped\n",i); return 1; } @@ -238,7 +238,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, } b->flags = 0; - if (CALL(q,is_mmapped,vb)) + if (vb->map) b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 3345877c47d4..0939ede831ab 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -374,9 +374,9 @@ videobuf_vm_close(struct vm_area_struct *vma) MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - if (mem->map != map) + if (q->bufs[i]->map != map) continue; - mem->map = NULL; + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; q->ops->buf_release(q,q->bufs[i]); } @@ -520,8 +520,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { - struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv; - if (mem && mem->map) + if (q->bufs[i]->map) return -EBUSY; } } @@ -572,8 +571,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, continue; if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) continue; - mem=q->bufs[last]->priv; - if (mem->map) { + if (q->bufs[last]->map) { retval = -EBUSY; goto done; } @@ -593,8 +591,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, if (NULL == map) goto done; for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { - mem=q->bufs[i]->priv; - mem->map = map; + q->bufs[i]->map = map; q->bufs[i]->baddr = vma->vm_start + size; } map->count = 1; @@ -613,16 +610,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, return retval; } -static int __videobuf_is_mmapped (struct videobuf_buffer *buf) -{ - struct videbuf_pci_sg_memory *mem=buf->priv; - - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - - return (mem->map)?1:0; -} - static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) @@ -678,7 +665,6 @@ static struct videobuf_qtype_ops pci_ops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .is_mmapped = __videobuf_is_mmapped, .copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index fd059cde63f4..c9d6ae0d3b49 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -62,7 +62,6 @@ videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; - struct videbuf_vmalloc_memory *mem; int i; dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, @@ -75,19 +74,13 @@ videobuf_vm_close(struct vm_area_struct *vma) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - mem=q->bufs[i]->priv; - if (!mem) - continue; - - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - - if (mem->map != map) + if (q->bufs[i]->map != map) continue; q->ops->buf_release(q,q->bufs[i]); - mem->map = NULL; + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; } mutex_unlock(&q->lock); @@ -191,8 +184,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { - struct videbuf_vmalloc_memory *mem=q->bufs[i]->priv; - if (mem && mem->map) + if (q->bufs[i]->map) return -EBUSY; } } @@ -227,12 +219,9 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, (vma->vm_pgoff << PAGE_SHIFT)); return -EINVAL; } - mem=q->bufs[first]->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); /* create mapping + update buffer list */ - map = mem->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + map = q->bufs[first]->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); if (NULL == map) return -ENOMEM; @@ -246,14 +235,19 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; vma->vm_private_data = map; + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + /* Try to remap memory */ retval=remap_vmalloc_range(vma, mem->vmalloc,0); if (retval<0) { dprintk(1,"mmap: postponing remap_vmalloc_range\n"); + mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); if (!mem->vma) { kfree(map); - mem->map=NULL; + q->bufs[first]->map=NULL; return -ENOMEM; } memcpy(mem->vma,vma,sizeof(*vma)); @@ -269,15 +263,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, return (0); } -static int __videobuf_is_mmapped (struct videobuf_buffer *buf) -{ - struct videbuf_vmalloc_memory *mem=buf->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - - return (mem->map)?1:0; -} - static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) @@ -335,7 +320,6 @@ static struct videobuf_qtype_ops qops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .is_mmapped = __videobuf_is_mmapped, .copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 0ac21ae44f69..96949e31eaf8 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -97,6 +97,9 @@ struct videobuf_buffer { /* buffer addr (userland ptr!) */ unsigned long baddr; + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + /* Private pointer to allow specific methods to store their data */ int privsize; void *priv; @@ -143,7 +146,6 @@ struct videobuf_qtype_ops { int (*mmap_free) (struct videobuf_queue *q); int (*mmap_mapper) (struct videobuf_queue *q, struct vm_area_struct *vma); - int (*is_mmapped) (struct videobuf_buffer *buf); }; struct videobuf_queue { diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index 62a3709905f3..206d9027b39f 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -86,7 +86,6 @@ struct videbuf_pci_sg_memory u32 magic; /* for mmap'ed buffers */ - struct videobuf_mapping *map; struct videobuf_dmabuf dma; }; diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h index 5fff68df6689..26a8958d23d1 100644 --- a/include/media/videobuf-vmalloc.h +++ b/include/media/videobuf-vmalloc.h @@ -21,9 +21,6 @@ struct videbuf_vmalloc_memory { u32 magic; - /* for mmap'ed buffers */ - struct videobuf_mapping *map; - void *vmalloc; /* remap_vmalloc_range seems to need to run after mmap() on some cases */ From 9900132f3437e9373aa030cdb5bd2d5db15566e3 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:09 -0300 Subject: [PATCH 0849/2804] V4L/DVB (6268): V4L: Fix a lock inversion in generic videobuf code videobuf_qbuf takes q->lock, and then calls q->ops->buf_prepare which by design in all drivers calls videobuf_iolock which calls videobuf_dma_init_user and this takes current->mm->mmap_sem on the other hand if user calls mumap from other thread, sys_munmap takes current->mm->mmap_sem and videobuf_vm_close takes q->lock Since this can occur only for V4L2_MEMORY_MMAP buffers, take current->mm->mmap_sem in qbuf, before q->lock, and don't take current->mm->mmap_sem videobuf_dma_init_user for those buffers Signed-off-by: Maxim Levitsky http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 7 ++++++ drivers/media/video/videobuf-dma-sg.c | 32 ++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 3bd06bb633a7..a27e114cacef 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -349,6 +349,9 @@ int videobuf_qbuf(struct videobuf_queue *q, MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + if (b->memory == V4L2_MEMORY_MMAP) + down_read(¤t->mm->mmap_sem); + mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { @@ -434,6 +437,10 @@ int videobuf_qbuf(struct videobuf_queue *q, done: mutex_unlock(&q->lock); + + if (b->memory == V4L2_MEMORY_MMAP) + up_read(¤t->mm->mmap_sem); + return retval; } diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 0939ede831ab..05dd38343fa3 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -134,8 +134,8 @@ void videobuf_dma_init(struct videobuf_dmabuf *dma) dma->magic = MAGIC_DMABUF; } -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) +static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, + int direction, unsigned long data, unsigned long size) { unsigned long first,last; int err, rw = 0; @@ -160,12 +160,12 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, dma->varea = (void *) data; - down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, data & PAGE_MASK, dma->nr_pages, rw == READ, 1, /* force */ dma->pages, NULL); - up_read(¤t->mm->mmap_sem); + if (err != dma->nr_pages) { dma->nr_pages = (err >= 0) ? err : 0; dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); @@ -174,6 +174,17 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, return 0; } +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size) +{ + int ret; + down_read(¤t->mm->mmap_sem); + ret = videobuf_dma_init_user_locked(dma, direction, data, size); + up_read(¤t->mm->mmap_sem); + + return ret; +} + int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, int nr_pages) { @@ -469,13 +480,24 @@ static int __videobuf_iolock (struct videobuf_queue* q, pages ); if (0 != err) return err; - } else { + } else if (vb->memory == V4L2_MEMORY_USERPTR) { /* dma directly to userspace */ err = videobuf_dma_init_user( &mem->dma, PCI_DMA_FROMDEVICE, vb->baddr,vb->bsize ); if (0 != err) return err; + } else { + /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP + buffers can only be called from videobuf_qbuf + we take current->mm->mmap_sem there, to prevent + locking inversion, so don't take it here */ + + err = videobuf_dma_init_user_locked(&mem->dma, + PCI_DMA_FROMDEVICE, + vb->baddr, vb->bsize); + if (0 != err) + return err; } break; case V4L2_MEMORY_OVERLAY: From b4aeb8b8232bd80764997bf38f574f63e118c259 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:15 -0300 Subject: [PATCH 0850/2804] V4L/DVB (6269): V4L: Fix a "scheduling while atomic" bug in saa7134 set_tvnorm can sleep in saa7134_i2c_xfer (it will be called through tuner code) but code calls it under spinlock. Fix that Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index cf40a9690a50..27c659cd0f30 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1834,7 +1834,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock, flags); + set_tvnorm(dev,&tvnorms[i]); + + spin_lock_irqsave(&dev->slock, flags); start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } else From f5a1ac64cc444cf19c8817d61a410b70bbb619d9 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:20 -0300 Subject: [PATCH 0851/2804] V4L/DVB (6270): V4L: Honor dev->ctl_invert when setting up the decoder in saa7134 When user sets dev->ctl_invert, driver writes negative values to SAA7134_DEC_LUMA_CONTRAST and SAA7134_DEC_CHROMA_SATURATION, but general code that initializes decorder ignores that Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 27c659cd0f30..525b5b77c13a 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -584,9 +584,13 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_SYNC_CTRL, sync_control); saa_writeb(SAA7134_LUMA_CTRL, luma_control); saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); - saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast); - saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation); + saa_writeb(SAA7134_DEC_LUMA_CONTRAST, + dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); + + saa_writeb(SAA7134_DEC_CHROMA_SATURATION, + dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); + saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); From cb71201f20e43581857043a1f856fb61ce44bdf8 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:25 -0300 Subject: [PATCH 0852/2804] V4L/DVB (6271): V4L: Add basic support for suspend/resume for saa7134 This adds support for suspend/resume for core of saa7134 Should fix bug#7220 Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 175 ++++++++++++++---- drivers/media/video/saa7134/saa7134-ts.c | 23 ++- drivers/media/video/saa7134/saa7134-tvaudio.c | 4 +- drivers/media/video/saa7134/saa7134-video.c | 123 ++++++------ drivers/media/video/saa7134/saa7134.h | 12 ++ 5 files changed, 243 insertions(+), 94 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index a1d986e01a30..7f5df32ed0e8 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "saa7134-reg.h" #include "saa7134.h" @@ -392,6 +393,38 @@ void saa7134_buffer_timeout(unsigned long data) spin_unlock_irqrestore(&dev->slock,flags); } +/* resends a current buffer in queue after resume */ + +int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) +{ + struct saa7134_buf *buf , *next; + unsigned long flags; + + spin_lock_irqsave(&dev->slock, flags); + + buf = q->curr; + next = buf; + + dprintk("buffer_requeue\n"); + + if (!buf) { + spin_unlock_irqrestore(&dev->slock, flags); + return 0; + } + + dprintk("buffer_requeue : resending active buffers \n"); + + if (!list_empty(&q->queue)) + next = list_entry(q->queue.next, struct saa7134_buf, + vb.queue); + + buf->activate(dev, buf, next); + spin_unlock_irqrestore(&dev->slock, flags); + + return 0; +} + /* ------------------------------------------------------------------ */ int saa7134_set_dmabits(struct saa7134_dev *dev) @@ -647,6 +680,39 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) /* ------------------------------------------------------------------ */ /* early init (no i2c, no irq) */ + +static int saa7134_hw_enable1(struct saa7134_dev *dev) +{ + /* RAM FIFO config */ + saa_writel(SAA7134_FIFO_SIZE, 0x08070503); + saa_writel(SAA7134_THRESHOULD, 0x02020202); + + /* enable audio + video processing */ + saa_writel(SAA7134_MAIN_CTRL, + SAA7134_MAIN_CTRL_VPLLE | + SAA7134_MAIN_CTRL_APLLE | + SAA7134_MAIN_CTRL_EXOSC | + SAA7134_MAIN_CTRL_EVFE1 | + SAA7134_MAIN_CTRL_EVFE2 | + SAA7134_MAIN_CTRL_ESFE | + SAA7134_MAIN_CTRL_EBDAC); + + /* + * Initialize OSS _after_ enabling audio clock PLL and audio processing. + * OSS initialization writes to registers via the audio DSP; these + * writes will fail unless the audio clock has been started. At worst, + * audio will not work. + */ + + /* enable peripheral devices */ + saa_writeb(SAA7134_SPECIAL_MODE, 0x01); + + /* set vertical line numbering start (vbi needs this) */ + saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); + + return 0; +} + static int saa7134_hwinit1(struct saa7134_dev *dev) { dprintk("hwinit1\n"); @@ -663,44 +729,16 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) saa7134_ts_init1(dev); saa7134_input_init1(dev); - /* RAM FIFO config */ - saa_writel(SAA7134_FIFO_SIZE, 0x08070503); - saa_writel(SAA7134_THRESHOULD,0x02020202); - - /* enable audio + video processing */ - saa_writel(SAA7134_MAIN_CTRL, - SAA7134_MAIN_CTRL_VPLLE | - SAA7134_MAIN_CTRL_APLLE | - SAA7134_MAIN_CTRL_EXOSC | - SAA7134_MAIN_CTRL_EVFE1 | - SAA7134_MAIN_CTRL_EVFE2 | - SAA7134_MAIN_CTRL_ESFE | - SAA7134_MAIN_CTRL_EBDAC); - - /* - * Initialize OSS _after_ enabling audio clock PLL and audio processing. - * OSS initialization writes to registers via the audio DSP; these - * writes will fail unless the audio clock has been started. At worst, - * audio will not work. - */ - - /* enable peripheral devices */ - saa_writeb(SAA7134_SPECIAL_MODE, 0x01); - - /* set vertical line numbering start (vbi needs this) */ - saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); + saa7134_hw_enable1(dev); return 0; } /* late init (with i2c + irq) */ -static int saa7134_hwinit2(struct saa7134_dev *dev) +static int saa7134_hw_enable2(struct saa7134_dev *dev) { - unsigned int irq2_mask; - dprintk("hwinit2\n"); - saa7134_video_init2(dev); - saa7134_tvaudio_init2(dev); + unsigned int irq2_mask; /* enable IRQ's */ irq2_mask = @@ -726,6 +764,20 @@ static int saa7134_hwinit2(struct saa7134_dev *dev) return 0; } +static int saa7134_hwinit2(struct saa7134_dev *dev) +{ + + dprintk("hwinit2\n"); + + saa7134_video_init2(dev); + saa7134_tvaudio_init2(dev); + + saa7134_hw_enable2(dev); + + return 0; +} + + /* shutdown */ static int saa7134_hwfini(struct saa7134_dev *dev) { @@ -1118,6 +1170,65 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) kfree(dev); } +static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) +{ + + /* Disable card's IRQs to prevent it from resuming computer */ + + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + + saa_writel(SAA7134_IRQ1, 0); + saa_writel(SAA7134_IRQ2, 0); + + + pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + pci_save_state(pci_dev); + + return 0; +} + +static int saa7134_resume(struct pci_dev *pci_dev) +{ + + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + + pci_restore_state(pci_dev); + pci_set_power_state(pci_dev, PCI_D0); + + /* Do things that are done in saa7134_initdev , + except of initializing memory structures.*/ + + saa7134_board_init1(dev); + + if (saa7134_boards[dev->board].video_out) + saa7134_videoport_init(dev); + + if (card_has_mpeg(dev)) + saa7134_ts_init_hw(dev); + + saa7134_hw_enable1(dev); + + saa7134_set_decoder(dev); + + saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); + + saa7134_board_init2(dev); + saa7134_hw_enable2(dev); + + dev->force_mute_update = 1; + saa7134_tvaudio_setmute(dev); + dev->force_mute_update = 0; + saa7134_tvaudio_setvolume(dev, dev->ctl_volume); + saa7134_enable_i2s(dev); + + /*recapture unfinished buffer(s)*/ + saa7134_buffer_requeue(dev, &dev->video_q); + saa7134_buffer_requeue(dev, &dev->vbi_q); + saa7134_buffer_requeue(dev, &dev->ts_q); + + return 0; +} + /* ----------------------------------------------------------- */ int saa7134_ts_register(struct saa7134_mpeg_ops *ops) @@ -1159,6 +1270,8 @@ static struct pci_driver saa7134_pci_driver = { .id_table = saa7134_pci_tbl, .probe = saa7134_initdev, .remove = __devexit_p(saa7134_finidev), + .suspend = saa7134_suspend, + .resume = saa7134_resume }; static int saa7134_init(void) diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 5b1d1dafb5a5..4b63ad3e8466 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -177,6 +177,22 @@ static unsigned int ts_nr_packets = 64; module_param(ts_nr_packets, int, 0444); MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)"); +int saa7134_ts_init_hw(struct saa7134_dev *dev) +{ + /* deactivate TS softreset */ + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + /* TSSOP high active, TSVAL high active, TSLOCK ignored */ + saa_writeb(SAA7134_TS_PARALLEL, 0xec); + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); + saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); + saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); + /* TSNOPIT=0, TSCOLAP=0 */ + saa_writeb(SAA7134_TS_DMA2, + ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); + + return 0; +} + int saa7134_ts_init1(struct saa7134_dev *dev) { /* sanitycheck insmod options */ @@ -200,12 +216,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev) saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts); /* init TS hw */ - saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* deactivate TS softreset */ - saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */ - saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); - saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); - saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); - saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */ + saa7134_ts_init_hw(dev); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 43501b5dc05b..df2dab06387d 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -231,7 +231,7 @@ static void mute_input_7134(struct saa7134_dev *dev) } if (dev->hw_mute == mute && - dev->hw_input == in) { + dev->hw_input == in && !dev->force_mute_update) { dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", mute,in->name); return; @@ -876,7 +876,7 @@ static int tvaudio_thread_ddep(void *data) /* ------------------------------------------------------------------ */ /* common stuff + external entry points */ -static void saa7134_enable_i2s(struct saa7134_dev *dev) +void saa7134_enable_i2s(struct saa7134_dev *dev) { int i2s_format; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 525b5b77c13a..24d579723b55 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -540,22 +540,12 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) /* ------------------------------------------------------------------ */ -static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) +void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - int luma_control,sync_control,mux; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; - mux = card_in(dev,dev->ctl_input).vmux; - luma_control = norm->luma_control; - sync_control = norm->sync_control; - - if (mux > 5) - luma_control |= 0x80; /* svideo */ - if (noninterlaced || dev->nosignal) - sync_control |= 0x20; - /* setup cropping */ dev->crop_bounds.left = norm->h_start; dev->crop_defrect.left = norm->h_start; @@ -570,6 +560,40 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) dev->crop_current = dev->crop_defrect; + saa7134_set_decoder(dev); + + if (card_in(dev, dev->ctl_input).tv) { + if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) + && ((card(dev).tuner_config == 1) + || (card(dev).tuner_config == 2))) + saa7134_set_gpio(dev, 22, 5); + saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &norm->id); + } +} + +static void video_mux(struct saa7134_dev *dev, int input) +{ + dprintk("video input = %d [%s]\n", input, card_in(dev, input).name); + dev->ctl_input = input; + set_tvnorm(dev, dev->tvnorm); + saa7134_tvaudio_setinput(dev, &card_in(dev, input)); +} + +void saa7134_set_decoder(struct saa7134_dev *dev) +{ + int luma_control, sync_control, mux; + + struct saa7134_tvnorm *norm = dev->tvnorm; + mux = card_in(dev, dev->ctl_input).vmux; + + luma_control = norm->luma_control; + sync_control = norm->sync_control; + + if (mux > 5) + luma_control |= 0x80; /* svideo */ + if (noninterlaced || dev->nosignal) + sync_control |= 0x20; + /* setup video decoder */ saa_writeb(SAA7134_INCR_DELAY, 0x08); saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); @@ -604,23 +628,6 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); - - /* only tell the tuner if this is a tv input */ - if (card_in(dev,dev->ctl_input).tv) { - if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) - && ((card(dev).tuner_config == 1) - || (card(dev).tuner_config == 2))) - saa7134_set_gpio(dev, 22, 5); - saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); - } -} - -static void video_mux(struct saa7134_dev *dev, int input) -{ - dprintk("video input = %d [%s]\n",input,card_in(dev,input).name); - dev->ctl_input = input; - set_tvnorm(dev,dev->tvnorm); - saa7134_tvaudio_setinput(dev,&card_in(dev,input)); } static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) @@ -2399,34 +2406,40 @@ int saa7134_video_init1(struct saa7134_dev *dev) dev->video_q.timeout.data = (unsigned long)(&dev->video_q); dev->video_q.dev = dev; - if (saa7134_boards[dev->board].video_out) { - /* enable video output */ - int vo = saa7134_boards[dev->board].video_out; - int video_reg; - unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; - saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); - video_reg = video_out[vo][1]; - if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) - video_reg &= ~VP_T_CODE_P_INVERTED; - saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); - saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); - video_reg = video_out[vo][5]; - if (vid_port_opts & SET_CLOCK_NOT_DELAYED) - video_reg &= ~VP_CLK_CTRL2_DELAYED; - if (vid_port_opts & SET_CLOCK_INVERTED) - video_reg |= VP_CLK_CTRL1_INVERTED; - saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); - video_reg = video_out[vo][6]; - if (vid_port_opts & SET_VSYNC_OFF) { - video_reg &= ~VP_VS_TYPE_MASK; - video_reg |= VP_VS_TYPE_OFF; - } - saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); - saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); + if (saa7134_boards[dev->board].video_out) + saa7134_videoport_init(dev); + + return 0; +} + +int saa7134_videoport_init(struct saa7134_dev *dev) +{ + /* enable video output */ + int vo = saa7134_boards[dev->board].video_out; + int video_reg; + unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; + saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); + video_reg = video_out[vo][1]; + if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) + video_reg &= ~VP_T_CODE_P_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); + saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); + video_reg = video_out[vo][5]; + if (vid_port_opts & SET_CLOCK_NOT_DELAYED) + video_reg &= ~VP_CLK_CTRL2_DELAYED; + if (vid_port_opts & SET_CLOCK_INVERTED) + video_reg |= VP_CLK_CTRL1_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); + video_reg = video_out[vo][6]; + if (vid_port_opts & SET_VSYNC_OFF) { + video_reg &= ~VP_VS_TYPE_MASK; + video_reg |= VP_VS_TYPE_OFF; } + saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); + saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); return 0; } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index cb617c8dbb71..5b1f22606558 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -522,6 +522,7 @@ struct saa7134_dev { struct saa7134_input *input; struct saa7134_input *hw_input; unsigned int hw_mute; + unsigned int force_mute_update; int last_carrier; int nosignal; @@ -594,6 +595,9 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); void saa7134_buffer_timeout(unsigned long data); void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); +int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q); + int saa7134_set_dmabits(struct saa7134_dev *dev); extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); @@ -626,6 +630,10 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; +void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm); +int saa7134_videoport_init(struct saa7134_dev *dev); +void saa7134_set_decoder(struct saa7134_dev *dev); + int saa7134_common_ioctl(struct saa7134_dev *dev, unsigned int cmd, void *arg); @@ -649,6 +657,8 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status); int saa7134_ts_register(struct saa7134_mpeg_ops *ops); void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops); +int saa7134_ts_init_hw(struct saa7134_dev *dev); + /* ----------------------------------------------------------- */ /* saa7134-vbi.c */ @@ -677,6 +687,8 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value); +void saa7134_enable_i2s(struct saa7134_dev *dev); + /* ----------------------------------------------------------- */ /* saa7134-oss.c */ From 11f7078c10944437b6cf335cea50ed7da675a8b1 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:44:39 -0300 Subject: [PATCH 0853/2804] V4L/DVB (6272): V4L: properly fix support for capturing interlaced video in saa7134 By "capturing interlaced video" I mean that card ensures that top field is really top and vice versa (I think it takes the filed ID from signal) Properly turn on/off that support depending on signal state Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 8 +++++--- drivers/media/video/saa7134/saa7134-video.c | 16 ++++++++++------ drivers/media/video/saa7134/saa7134.h | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 7f5df32ed0e8..fae0bfe7939f 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -594,8 +594,10 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) print_irqstatus(dev,loop,report,status); - if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */) - saa7134_irq_video_intl(dev); + if ((report & SAA7134_IRQ_REPORT_RDCAP) || + (report & SAA7134_IRQ_REPORT_INTL)) + saa7134_irq_video_signalchange(dev); + if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && (status & 0x60) == 0) @@ -1081,7 +1083,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, mutex_unlock(&devlist_lock); /* check for signal */ - saa7134_irq_video_intl(dev); + saa7134_irq_video_signalchange(dev); if (saa7134_dmasound_init && !dev->dmasound.priv_data) { saa7134_dmasound_init(dev); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 24d579723b55..7c97ac15e665 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -40,7 +40,7 @@ static unsigned int video_debug = 0; static unsigned int gbuffers = 8; -static unsigned int noninterlaced = 1; +static unsigned int noninterlaced = 0; static unsigned int gbufsize = 720*576*4; static unsigned int gbufsize_max = 720*576*4; static char secam[] = "--"; @@ -2454,7 +2454,7 @@ int saa7134_video_init2(struct saa7134_dev *dev) return 0; } -void saa7134_irq_video_intl(struct saa7134_dev *dev) +void saa7134_irq_video_signalchange(struct saa7134_dev *dev) { static const char *st[] = { "(no signal)", "NTSC", "PAL", "SECAM" }; @@ -2466,24 +2466,28 @@ void saa7134_irq_video_intl(struct saa7134_dev *dev) (st1 & 0x40) ? "not locked" : "locked", (st2 & 0x40) ? "no" : "yes", st[st1 & 0x03]); - dev->nosignal = (st1 & 0x40) || (st2 & 0x40); + dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1); if (dev->nosignal) { /* no video signal -> mute audio */ if (dev->ctl_automute) dev->automute = 1; saa7134_tvaudio_setmute(dev); - saa_setb(SAA7134_SYNC_CTRL, 0x20); } else { /* wake up tvaudio audio carrier scan thread */ saa7134_tvaudio_do_scan(dev); - if (!noninterlaced) - saa_clearb(SAA7134_SYNC_CTRL, 0x20); } + + if ((st2 & 0x80) && !noninterlaced && !dev->nosignal) + saa_clearb(SAA7134_SYNC_CTRL, 0x20); + else + saa_setb(SAA7134_SYNC_CTRL, 0x20); + if (dev->mops && dev->mops->signal_change) dev->mops->signal_change(dev); } + void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) { enum v4l2_field field; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 5b1f22606558..745b750cd3fe 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -639,7 +639,7 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, int saa7134_video_init1(struct saa7134_dev *dev); int saa7134_video_init2(struct saa7134_dev *dev); -void saa7134_irq_video_intl(struct saa7134_dev *dev); +void saa7134_irq_video_signalchange(struct saa7134_dev *dev); void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); From a326ae1126fddd07728e854322e0c657c6b1fbda Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:54:52 -0300 Subject: [PATCH 0854/2804] V4L/DVB (6273): V4L: vivi.c vidioc_try_fmt_cap() negotiate a valid field If the client provides V4L2_FIELD_ANY vivi should return a valid field :) Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 650e959aeb78..512128a6f58c 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -820,8 +820,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { -// field=V4L2_FIELD_INTERLACED; - field=V4L2_FIELD_SEQ_TB; + field=V4L2_FIELD_INTERLACED; } else if (V4L2_FIELD_INTERLACED != field) { dprintk(1,"Field type invalid.\n"); return -EINVAL; From 85c7c70bc241d506dffc1879158f77f8aac69734 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:02 -0300 Subject: [PATCH 0855/2804] V4L/DVB (6274): V4L: vivi.c replace logic in vivi_poll with videobuf_poll_stream Since vivi is using videobuf_read_stream() it can use videobuf_poll_stream() now. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 512128a6f58c..cdef622f6b32 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1111,29 +1111,14 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; struct vivi_buffer *buf; + struct videobuf_queue *q = &fh->vb_vidq; dprintk(1,"%s\n",__FUNCTION__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; - if (res_get(fh->dev,fh)) { - dprintk(1,"poll: mmap interface\n"); - /* streaming capture */ - if (list_empty(&fh->vb_vidq.stream)) - return POLLERR; - buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream); - } else { - dprintk(1,"poll: read() interface\n"); - /* read() capture */ - return videobuf_poll_stream(file, &fh-> vb_vidq, - wait); - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) - return POLLIN|POLLRDNORM; - return 0; + return videobuf_poll_stream(file, q, wait); } static int vivi_release(struct inode *inode, struct file *file) From ba32bd95d431525ad2ffac97cadf9ee40b63939e Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:17 -0300 Subject: [PATCH 0856/2804] V4L/DVB (6275): V4L: vivi.c remove the "resource" locking The "resource" locking in vivi isn't needed since streamon/streamoff/read_stream do mutual exclusion using q->reading/q->streaming. Plus it is sort of broken: a) res_locked() use in vivi_read() is racey. b) res_free() calls mutex_lock twice causing streamoff to break Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 48 ++++---------------------------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index cdef622f6b32..82755091648b 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -170,7 +170,6 @@ struct vivi_dev { int users; /* various device info */ - unsigned int resources; struct video_device vfd; struct vivi_dmaqueue vidq; @@ -726,40 +725,6 @@ static struct videobuf_queue_ops vivi_video_qops = { .buf_release = buffer_release, }; -/* ------------------------------------------------------------------ - IOCTL handling - ------------------------------------------------------------------*/ - - -static int res_get(struct vivi_dev *dev, struct vivi_fh *fh) -{ - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - dev->resources =1; - dprintk(1,"res: get\n"); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_locked(struct vivi_dev *dev) -{ - return (dev->resources); -} - -static void res_free(struct vivi_dev *dev, struct vivi_fh *fh) -{ - mutex_lock(&dev->lock); - dev->resources = 0; - dprintk(1,"res: put\n"); - mutex_lock(&dev->lock); -} - /* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/ @@ -913,9 +878,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) if (i != fh->type) return -EINVAL; - if (!res_get(dev,fh)) - return -EBUSY; - return (videobuf_streamon(&fh->vb_vidq)); + return videobuf_streamon(&fh->vb_vidq); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) @@ -928,10 +891,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) if (i != fh->type) return -EINVAL; - videobuf_streamoff(&fh->vb_vidq); - res_free(dev,fh); - - return (0); + return videobuf_streamoff(&fh->vb_vidq); } static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i) @@ -1096,10 +1056,10 @@ static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct vivi_fh *fh = file->private_data; + struct vivi_dev *dev = fh->dev; + struct videobuf_queue *q = &fh->vb_vidq; if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (res_locked(fh->dev)) - return -EBUSY; return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } From 00f98d0804c88c29bef81cb98c861f13c9b33f30 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:28 -0300 Subject: [PATCH 0857/2804] V4L/DVB (6276): V4L: videobuf-core.c lock before streaming check The reading/streaming fields are used for mutual exclusion of the queue and should be protected by the queue lock. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index a27e114cacef..ca67f80184bd 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -289,16 +289,18 @@ int videobuf_reqbufs(struct videobuf_queue *q, return -EINVAL; } + mutex_lock(&q->lock); if (q->streaming) { dprintk(1,"reqbufs: streaming already exists\n"); - return -EBUSY; + retval = -EBUSY; + goto done; } if (!list_empty(&q->stream)) { dprintk(1,"reqbufs: stream running\n"); - return -EBUSY; + retval = -EBUSY; + goto done; } - mutex_lock(&q->lock); count = req->count; if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; From 14f37aee299bf9a897516f5e33948ee1f014eae1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Sep 2007 21:00:50 -0300 Subject: [PATCH 0858/2804] V4L/DVB (6277): vivi cleanup: remove the unused vars Vivi driver is now simpler. This patch removes the now unused vars. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 82755091648b..61a6608d6e61 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -871,7 +871,6 @@ static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_fh *fh=priv; - struct vivi_dev *dev = fh->dev; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -884,7 +883,6 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_fh *fh=priv; - struct vivi_dev *dev = fh->dev; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1056,8 +1054,6 @@ static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct vivi_fh *fh = file->private_data; - struct vivi_dev *dev = fh->dev; - struct videobuf_queue *q = &fh->vb_vidq; if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, @@ -1070,7 +1066,6 @@ static unsigned int vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; - struct vivi_buffer *buf; struct videobuf_queue *q = &fh->vb_vidq; dprintk(1,"%s\n",__FUNCTION__); From d00cd2985e0e796621adf0f782af1563d990b0b5 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Tue, 2 Oct 2007 09:03:39 -0300 Subject: [PATCH 0859/2804] V4L/DVB (6278): Buf: fix typo that caused data loss when readng streams from device If videobuf_read_stream reads two or more buffers it was overwriting the first one Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index ca67f80184bd..8e4026e6fae3 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -771,7 +771,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, } if (q->read_buf->state == STATE_DONE) { - rc = CALL (q,copy_stream, q, data, count, + rc = CALL (q,copy_stream, q, data + retval, count, retval, vbihack, nonblocking); if (rc < 0) { retval = rc; From 9320874a3e6aea7044a4a7eedeab13db990424ab Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 3 Oct 2007 11:23:01 -0300 Subject: [PATCH 0860/2804] V4L/DVB (6279): en_50221: convert to kthread API Here's an attempted update to the full kthread API + wake_up_process: Signed-off-by: Andrew Morton CC: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 84 ++++----------------- 1 file changed, 16 insertions(+), 68 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 5c7bcb8393d2..084a508a03da 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "dvb_ca_en50221.h" #include "dvb_ringbuffer.h" @@ -139,13 +140,7 @@ struct dvb_ca_private { wait_queue_head_t wait_queue; /* PID of the monitoring thread */ - pid_t thread_pid; - - /* Wait queue used when shutting thread down */ - wait_queue_head_t thread_queue; - - /* Flag indicating when thread should exit */ - unsigned int exit:1; + struct task_struct *thread; /* Flag indicating if the CA device is open */ unsigned int open:1; @@ -901,27 +896,9 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) ca->wakeup = 1; mb(); - wake_up_interruptible(&ca->thread_queue); + wake_up_process(ca->thread); } -/** - * Used by the CA thread to determine if an early wakeup is necessary - * - * @param ca CA instance. - */ -static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca) -{ - if (ca->wakeup) { - ca->wakeup = 0; - return 1; - } - if (ca->exit) - return 1; - - return 0; -} - - /** * Update the delay used by the thread. * @@ -981,7 +958,6 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) static int dvb_ca_en50221_thread(void *data) { struct dvb_ca_private *ca = data; - char name[15]; int slot; int flags; int status; @@ -990,28 +966,17 @@ static int dvb_ca_en50221_thread(void *data) dprintk("%s\n", __FUNCTION__); - /* setup kernel thread */ - snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id); - - lock_kernel(); - daemonize(name); - sigfillset(¤t->blocked); - unlock_kernel(); - /* choose the correct initial delay */ dvb_ca_en50221_thread_update_delay(ca); /* main loop */ - while (!ca->exit) { + while (!kthread_should_stop()) { /* sleep for a bit */ - if (!ca->wakeup) { - flags = wait_event_interruptible_timeout(ca->thread_queue, - dvb_ca_en50221_thread_should_wakeup(ca), - ca->delay); - if ((flags == -ERESTARTSYS) || ca->exit) { - /* got signal or quitting */ - break; - } + while (!ca->wakeup) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ca->delay); + if (kthread_should_stop()) + return 0; } ca->wakeup = 0; @@ -1180,10 +1145,6 @@ static int dvb_ca_en50221_thread(void *data) } } - /* completed */ - ca->thread_pid = 0; - mb(); - wake_up_interruptible(&ca->thread_queue); return 0; } @@ -1683,9 +1644,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, goto error; } init_waitqueue_head(&ca->wait_queue); - ca->thread_pid = 0; - init_waitqueue_head(&ca->thread_queue); - ca->exit = 0; ca->open = 0; ca->wakeup = 0; ca->next_read_slot = 0; @@ -1711,14 +1669,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, mb(); /* create a kthread for monitoring this CA device */ - - ret = kernel_thread(dvb_ca_en50221_thread, ca, 0); - - if (ret < 0) { - printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret); + ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i", + ca->dvbdev->adapter->num, ca->dvbdev->id); + if (IS_ERR(ca->thread)) { + ret = PTR_ERR(ca->thread); + printk("dvb_ca_init: failed to start kernel_thread (%d)\n", + ret); goto error; } - ca->thread_pid = ret; return 0; error: @@ -1749,17 +1707,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) dprintk("%s\n", __FUNCTION__); /* shutdown the thread if there was one */ - if (ca->thread_pid) { - if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) { - printk("dvb_ca_release adapter %d: thread PID %d already died\n", - ca->dvbdev->adapter->num, ca->thread_pid); - } else { - ca->exit = 1; - mb(); - dvb_ca_en50221_thread_wakeup(ca); - wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0); - } - } + kthread_stop(ca->thread); for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); From 5a3ebe8755e88cd765f75121665c0d38004f8f37 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 4 Oct 2007 04:54:11 -0300 Subject: [PATCH 0861/2804] V4L/DVB (6283): videobuf: Remove references to old Kconfig option name CONFIG_VIDEO_BUF_DVB became CONFIG_VIDEOBUF_DVB. But in these cases, it makes more sense to use CONFIG_VIDEO_SAA7134_DVB or CONFIG_VIDEO_CX88_DVB_MODULE depending on the driver. The reference in cx23885.h should just be removed, as the code there needs to be included if DVB is on or off. I do not think you can even compile the cx23885 driver without DVB. It's clearly just leftover from when the file was obvious copied from the cx88 driver (which is not mentioned in the copyright BTW). Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885.h | 2 -- drivers/media/video/cx88/cx88-i2c.c | 2 +- drivers/media/video/cx88/cx88.h | 6 +++--- drivers/media/video/saa7134/saa7134.h | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 45c47cd60703..3d4fae565e35 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -28,9 +28,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) #include -#endif #include "btcx-risc.h" #include "cx23885-reg.h" diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 6ae21750b2c1..c8b1c50625f4 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -145,7 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) if (0 != core->i2c_rc) return; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) { if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl) core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index b3fe2d59cd13..42e0a9b8c550 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -31,7 +31,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) #include #endif @@ -311,7 +311,7 @@ struct cx88_core { unsigned int tuner_formats; /* config info -- dvb */ -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); #endif @@ -458,7 +458,7 @@ struct cx8802_dev { int width; int height; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) /* for dvb only */ struct videobuf_dvb dvb; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 745b750cd3fe..064f3dbe6951 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -41,7 +41,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE) #include #endif @@ -538,7 +538,7 @@ struct saa7134_dev { struct work_struct empress_workqueue; int empress_started; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE) /* SAA7134_MPEG_DVB only */ struct videobuf_dvb dvb; int (*original_demod_sleep)(struct dvb_frontend* fe); From 409d84f85a8d523ecd108cbe2c0e722682da95ff Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 4 Oct 2007 05:28:45 -0300 Subject: [PATCH 0862/2804] V4L/DVB (6284): cx23885: Update to new videobuf code cx23885 was still uses the old video-buf includes and code, which would only `work' if one happened to be compiling against a kernel that had the old headers. Even then, it wouldn't actually work, it would just compile without errors. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 10 ++++++---- drivers/media/video/cx23885/cx23885.h | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 51879961e3ea..4d0614093ad6 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1008,10 +1008,12 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) { + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb, 0, 0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); buf->vb.state = STATE_NEEDS_INIT; } @@ -1176,8 +1178,8 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); + videobuf_to_dma(&buf->vb)->sglist, + buf->vb.width, buf->vb.height); } buf->vb.state = STATE_PREPARED; return 0; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 3d4fae565e35..dec4dc2fcbb4 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -27,8 +27,8 @@ #include #include #include -#include -#include +#include +#include #include "btcx-risc.h" #include "cx23885-reg.h" From 925343ecdfd3f1dafd1049ddd4944621bbe3422e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 23 Aug 2007 21:22:15 -0300 Subject: [PATCH 0863/2804] V4L/DVB (6285): Remove pointless kmalloc() return value cast in Zoran PCI controller driver No need to cast the void pointer returned by kmalloc() in drivers/media/video/zoran_driver.c::v4l_fbuffer_alloc(). Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_driver.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index d831ca16d9e9..1c14fa2bd411 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -339,10 +339,7 @@ v4l_fbuffer_alloc (struct file *file) if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) { /* Use kmalloc */ - mem = - (unsigned char *) kmalloc(fh->v4l_buffers. - buffer_size, - GFP_KERNEL); + mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL); if (mem == 0) { dprintk(1, KERN_ERR From 593f18c6e4d04134f240fbad001d878802d8925f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Oct 2007 02:17:09 -0300 Subject: [PATCH 0864/2804] V4L/DVB (6286): Add support for MSI TV @nywhere A/D NB This is a Lifeview hybrid OEM board. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 831b4da48b80..67f08cc4be70 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -92,7 +92,7 @@ 91 -> AVerMedia A169 B [1461:7360] 92 -> AVerMedia A169 B1 [1461:6360] 93 -> Medion 7134 Bridge #2 [16be:0005] - 94 -> LifeView FlyDVB-T Hybrid Cardbus [5168:3306,5168:3502] + 94 -> LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB [5168:3306,5168:3502,4e42:3502] 95 -> LifeView FlyVIDEO3000 (NTSC) [5169:0138] 96 -> Medion Md8800 Quadro [16be:0007,16be:0008] 97 -> LifeView FlyDVB-S /Acorp TV134DS [5168:0300,4e42:0300] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 6b6eae82bcfc..62420d599d75 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2898,7 +2898,7 @@ struct saa7134_board saa7134_boards[] = { .radio_addr = ADDR_UNSET, }, [SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = { - .name = "LifeView FlyDVB-T Hybrid Cardbus", + .name = "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -4280,6 +4280,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x4e42, + .subdevice = 0x3502, + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, From aecfde539eeac11f269894413abf3b60cf74844f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 09:04:09 -0300 Subject: [PATCH 0865/2804] V4L/DVB (6287): Fix DMA Scatter/Gather constructor cx23885 driver were converted to use the newer videobuf support. Unfortunately, the constructor weren't changed. This causes an oops, since the abstract methods (implemented as callbacks) aren't defined. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Michael Krufky --- drivers/media/video/cx23885/cx23885-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index d952f3a67532..eda8c05d0931 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -186,7 +186,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, + videobuf_queue_pci_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, sizeof(struct cx23885_buffer), port); err = dvb_register(port); From 7568e3ce6710cb2c1bc1564a273e9f222efbc95e Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 8 Oct 2007 09:20:49 -0300 Subject: [PATCH 0866/2804] V4L/DVB (6289): Remove reference to dead CONFIG_UST and ust.h header Signed-off-by: Robert P. J. Day Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 0689a041d777..c3440b280d20 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -65,11 +65,6 @@ #include #endif -#if defined(CONFIG_UST) || defined(CONFIG_UST_MODULE) -#include -#endif - - #include MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); From 5ddff43435394c1c2540fcdeed00cb54862c31bf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 11:43:49 -0300 Subject: [PATCH 0867/2804] V4L/DVB (6290): remove videobuf_set_pci_ops Before the videobuf redesign, a procedure for re-using videobuf without PCI scatter/gather where provided by changing the pci-dependent operations by other operations. With the newer approach, those methods are obsolete and can safelly be removed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-dma-sg.c | 62 ++------------------------- include/media/videobuf-core.h | 3 -- include/media/videobuf-dma-sg.h | 19 -------- 3 files changed, 4 insertions(+), 80 deletions(-) diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 05dd38343fa3..a38efe10feb4 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -220,7 +220,6 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(0 == dma->nr_pages); @@ -247,10 +246,8 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) return -ENOMEM; } if (!dma->bus_addr) { - if (ops && ops->vb_map_sg) { - dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->sglen = pci_map_sg(dev,dma->sglist, dma->nr_pages, dma->direction); - } if (0 == dma->sglen) { printk(KERN_WARNING "%s: videobuf_map_sg failed\n",__FUNCTION__); @@ -266,30 +263,24 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(!dma->sglen); - if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - + pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction); return 0; } int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); if (!dma->sglen) return 0; - if (!dma->bus_addr && ops && ops->vb_unmap_sg) - ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); + pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction); + kfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; @@ -325,12 +316,8 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; return (videobuf_dma_map(&q,dma)); } @@ -338,12 +325,8 @@ int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; return (videobuf_dma_unmap(&q,dma)); } @@ -712,46 +695,10 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - struct videobuf_dma_sg_ops *priv_ops; - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); q->int_ops=&pci_ops; - - /* FIXME: the code bellow should be removed after having a proper - * memory allocation method for vivi and tm6000 - */ - q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); - BUG_ON (!q->priv_ops); - - priv_ops=q->priv_ops; - - /* Sets default methods for handling Scatter Gather mapping */ - priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; } -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops) -{ - kfree (q->priv_ops); - - q->priv_ops=ops; - - if (!ops) - return; - - /* If not specified, defaults to PCI map sg */ - if (!ops->vb_map_sg) - ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!ops->vb_unmap_sg) - ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; -} - - /* --------------------------------------------------------------------- */ EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); @@ -771,7 +718,6 @@ EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); EXPORT_SYMBOL_GPL(videobuf_pci_alloc); EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); -EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); /* * Local variables: diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 96949e31eaf8..9bae5a2eda66 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -173,9 +173,6 @@ struct videobuf_queue { /* driver private data */ void *priv_data; - - /*FIXME: should be removed after completing the vb conversion */ - void *priv_ops; }; int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index 206d9027b39f..38105031db23 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -89,19 +89,6 @@ struct videbuf_pci_sg_memory struct videobuf_dmabuf dma; }; -/* FIXME: To be removed soon */ -typedef int (vb_map_sg_t)(void *dev, struct scatterlist *sglist, int nr_pages, - int direction); - -/* FIXME: To be removed soon */ -struct videobuf_dma_sg_ops -{ - vb_map_sg_t *vb_map_sg; - vb_map_sg_t *vb_dma_sync_sg; - vb_map_sg_t *vb_unmap_sg; - -}; - void videobuf_dma_init(struct videobuf_dmabuf *dma); int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size); @@ -133,9 +120,3 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); -/* FIXME: temporary routine for vivi and tm6000, while lacking implementation - * of videobuf-vmalloc - */ -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops); - From d5f1b01644b6fd5e9eb480a4762cd6b569cb1246 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 11:48:57 -0300 Subject: [PATCH 0868/2804] V4L/DVB (6291): Fix: avoid oops on some SMP machines This workaround fix a bug that happens on some SMP machines. On those machines, videobuf_iolock is called too soon, before file .mmap handler. This patch calls the scheduler before iolocking, allowing it to properly call the pending mmap. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 8e4026e6fae3..aa402abc4b0c 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -94,6 +94,14 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, MAGIC_CHECK(vb->magic,MAGIC_BUFFER); MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper() + method should be called before _iolock. + On some cases, the mmap_mapper() is called only after scheduling. + + However, this way is just too dirty! Better to wait for some event. + */ + schedule_timeout(HZ); + return CALL(q,iolock,q,vb,fbuf); } From d4cae5a50021271b9ef4e5e39e71e177d12fa8cb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 12:20:02 -0300 Subject: [PATCH 0869/2804] V4L/DVB (6292): videobuf_core init always require callback implementation In the past, videobuf_queue_init were used to initialize PCI DMA videobuffers. This patch renames it, to avoid confusion with the previous kernel API, doing: s/videobuf_queue_init/void videobuf_queue_core_init/ Also, the operations is now part of the function parameter. The function will also add a test if this is defined, otherwise producing BUG. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 23 ++++++++++++++--------- drivers/media/video/videobuf-dma-sg.c | 4 ++-- drivers/media/video/videobuf-vmalloc.c | 4 ++-- include/media/videobuf-core.h | 5 +++-- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index aa402abc4b0c..f5c5ea8b6b08 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -108,23 +108,25 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, /* --------------------------------------------------------------------- */ -void videobuf_queue_init(struct videobuf_queue* q, +void videobuf_queue_core_init(struct videobuf_queue* q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, - void *priv) + void *priv, + struct videobuf_qtype_ops *int_ops) { memset(q,0,sizeof(*q)); - q->irqlock = irqlock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; + q->irqlock = irqlock; + q->dev = dev; + q->type = type; + q->field = field; + q->msize = msize; + q->ops = ops; q->priv_data = priv; + q->int_ops = int_ops; /* All buffer operations are mandatory */ BUG_ON (!q->ops->buf_setup); @@ -132,6 +134,9 @@ void videobuf_queue_init(struct videobuf_queue* q, BUG_ON (!q->ops->buf_queue); BUG_ON (!q->ops->buf_release); + /* Having implementations for abstract methods are mandatory */ + BUG_ON (!q->int_ops); + mutex_init(&q->lock); INIT_LIST_HEAD(&q->stream); } @@ -966,7 +971,7 @@ EXPORT_SYMBOL_GPL(videobuf_iolock); EXPORT_SYMBOL_GPL(videobuf_alloc); -EXPORT_SYMBOL_GPL(videobuf_queue_init); +EXPORT_SYMBOL_GPL(videobuf_queue_core_init); EXPORT_SYMBOL_GPL(videobuf_queue_cancel); EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index a38efe10feb4..8bb7fdd306d6 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -695,8 +695,8 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&pci_ops; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &pci_ops); } /* --------------------------------------------------------------------- */ diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index c9d6ae0d3b49..2e3689a12a28 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -333,8 +333,8 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&qops; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &qops); } EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 9bae5a2eda66..9fa09fb800a1 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -181,14 +181,15 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, void *videobuf_alloc(struct videobuf_queue* q); -void videobuf_queue_init(struct videobuf_queue *q, +void videobuf_queue_core_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, - void *priv); + void *priv, + struct videobuf_qtype_ops *int_ops); int videobuf_queue_is_busy(struct videobuf_queue *q); void videobuf_queue_cancel(struct videobuf_queue *q); From 54bd5b66c87d14e250f108aad1228b905d6882f6 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 8 Oct 2007 16:26:13 -0300 Subject: [PATCH 0870/2804] V4L/DVB (6293): V4L: convert struct class_device to struct device The currently used "struct class_device" will be removed from the kernel. Here is a patch that converts all users in drivers/media/video/ to struct device. Reviewed-by: Thierry Merle Reviewed-by: Mike Isely Reviewed-by: Luca Risolia Signed-off-by: Kay Sievers Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 11 +- drivers/media/video/et61x251/et61x251_core.c | 58 ++--- drivers/media/video/ov511.c | 81 ++++--- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 210 ++++++++++-------- drivers/media/video/pwc/pwc-if.c | 31 +-- drivers/media/video/sn9c102/sn9c102_core.c | 112 +++++----- drivers/media/video/stv680.c | 51 ++--- .../media/video/usbvision/usbvision-video.c | 119 +++++----- drivers/media/video/videodev.c | 40 ++-- include/media/v4l2-dev.h | 14 +- 10 files changed, 387 insertions(+), 340 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 4ab4e14b5c64..49278537eec4 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -154,13 +154,14 @@ MODULE_LICENSE("GPL"); /* ----------------------------------------------------------------------- */ /* sysfs */ -static ssize_t show_card(struct class_device *cd, char *buf) +static ssize_t show_card(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vfd = to_video_device(cd); struct bttv *btv = dev_get_drvdata(vfd->dev); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } -static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); +static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); /* ----------------------------------------------------------------------- */ /* dvb auto-load setup */ @@ -4615,9 +4616,9 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr,btv->video_dev->minor & 0x1f); - if (class_device_create_file(&btv->video_dev->class_dev, - &class_device_attr_card)<0) { - printk(KERN_ERR "bttv%d: class_device_create_file 'card' " + if (device_create_file(&btv->video_dev->class_dev, + &dev_attr_card)<0) { + printk(KERN_ERR "bttv%d: device_create_file 'card' " "failed\n", btv->c.nr); goto err; } diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 31062a981e36..d5fef4c01c87 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -706,7 +706,8 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) NOTE 2: buffers are PAGE_SIZE long */ -static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) +static ssize_t et61x251_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -729,7 +730,8 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) static ssize_t -et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) +et61x251_store_reg(struct device* cd, + struct device_attribute *attr, const char* buf, size_t len) { struct et61x251_device* cam; u8 index; @@ -761,7 +763,8 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_val(struct class_device* cd, char* buf) +static ssize_t et61x251_show_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -792,7 +795,8 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf) static ssize_t -et61x251_store_val(struct class_device* cd, const char* buf, size_t len) +et61x251_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 value; @@ -830,7 +834,8 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) +static ssize_t et61x251_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -855,7 +860,8 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) static ssize_t -et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 index; @@ -887,7 +893,8 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) +static ssize_t et61x251_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -923,7 +930,8 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) static ssize_t -et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 value; @@ -966,42 +974,40 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) } -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - et61x251_show_reg, et61x251_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - et61x251_show_val, et61x251_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - et61x251_show_i2c_reg, et61x251_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - et61x251_show_i2c_val, et61x251_store_i2c_val); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, + et61x251_show_reg, et61x251_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, + et61x251_show_val, et61x251_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + et61x251_show_i2c_reg, et61x251_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + et61x251_show_i2c_val, et61x251_store_i2c_val); static int et61x251_create_sysfs(struct et61x251_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = device_create_file(classdev, &dev_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = device_create_file(classdev, &dev_attr_val))) goto err_reg; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_reg))) + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) goto err_val; - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_val))) + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) goto err_i2c_reg; } err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + device_remove_file(classdev, &dev_attr_i2c_reg); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + device_remove_file(classdev, &dev_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + device_remove_file(classdev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index e5edff1059a2..9eb2562347a8 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -5554,41 +5554,46 @@ error: * sysfs ***************************************************************************/ -static inline struct usb_ov511 *cd_to_ov(struct class_device *cd) +static inline struct usb_ov511 *cd_to_ov(struct device *cd) { struct video_device *vdev = to_video_device(cd); return video_get_drvdata(vdev); } -static ssize_t show_custom_id(struct class_device *cd, char *buf) +static ssize_t show_custom_id(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%d\n", ov->customid); } -static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); +static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); -static ssize_t show_model(struct class_device *cd, char *buf) +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", ov->desc); } -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_bridge(struct class_device *cd, char *buf) +static ssize_t show_bridge(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); } -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); +static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); -static ssize_t show_sensor(struct class_device *cd, char *buf) +static ssize_t show_sensor(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); } -static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); +static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); -static ssize_t show_brightness(struct class_device *cd, char *buf) +static ssize_t show_brightness(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5598,9 +5603,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf) sensor_get_brightness(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *cd, char *buf) +static ssize_t show_saturation(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5610,9 +5616,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf) sensor_get_saturation(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_contrast(struct class_device *cd, char *buf) +static ssize_t show_contrast(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5622,9 +5629,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf) sensor_get_contrast(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_hue(struct class_device *cd, char *buf) +static ssize_t show_hue(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5634,9 +5642,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf) sensor_get_hue(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_exposure(struct class_device *cd, char *buf) +static ssize_t show_exposure(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned char exp = 0; @@ -5646,49 +5655,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf) sensor_get_exposure(ov, &exp); return sprintf(buf, "%d\n", exp >> 8); } -static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); +static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); static int ov_create_sysfs(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &class_device_attr_custom_id); + rc = video_device_create_file(vdev, &dev_attr_custom_id); if (rc) goto err; - rc = video_device_create_file(vdev, &class_device_attr_model); + rc = video_device_create_file(vdev, &dev_attr_model); if (rc) goto err_id; - rc = video_device_create_file(vdev, &class_device_attr_bridge); + rc = video_device_create_file(vdev, &dev_attr_bridge); if (rc) goto err_model; - rc = video_device_create_file(vdev, &class_device_attr_sensor); + rc = video_device_create_file(vdev, &dev_attr_sensor); if (rc) goto err_bridge; - rc = video_device_create_file(vdev, &class_device_attr_brightness); + rc = video_device_create_file(vdev, &dev_attr_brightness); if (rc) goto err_sensor; - rc = video_device_create_file(vdev, &class_device_attr_saturation); + rc = video_device_create_file(vdev, &dev_attr_saturation); if (rc) goto err_bright; - rc = video_device_create_file(vdev, &class_device_attr_contrast); + rc = video_device_create_file(vdev, &dev_attr_contrast); if (rc) goto err_sat; - rc = video_device_create_file(vdev, &class_device_attr_hue); + rc = video_device_create_file(vdev, &dev_attr_hue); if (rc) goto err_contrast; - rc = video_device_create_file(vdev, &class_device_attr_exposure); + rc = video_device_create_file(vdev, &dev_attr_exposure); if (rc) goto err_hue; return 0; err_hue: - video_device_remove_file(vdev, &class_device_attr_hue); + video_device_remove_file(vdev, &dev_attr_hue); err_contrast: - video_device_remove_file(vdev, &class_device_attr_contrast); + video_device_remove_file(vdev, &dev_attr_contrast); err_sat: - video_device_remove_file(vdev, &class_device_attr_saturation); + video_device_remove_file(vdev, &dev_attr_saturation); err_bright: - video_device_remove_file(vdev, &class_device_attr_brightness); + video_device_remove_file(vdev, &dev_attr_brightness); err_sensor: - video_device_remove_file(vdev, &class_device_attr_sensor); + video_device_remove_file(vdev, &dev_attr_sensor); err_bridge: - video_device_remove_file(vdev, &class_device_attr_bridge); + video_device_remove_file(vdev, &dev_attr_bridge); err_model: - video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &dev_attr_model); err_id: - video_device_remove_file(vdev, &class_device_attr_custom_id); + video_device_remove_file(vdev, &dev_attr_custom_id); err: return rc; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7ab79baa1c8c..b20dc4421d59 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -33,16 +33,16 @@ struct pvr2_sysfs { struct pvr2_channel channel; - struct class_device *class_dev; + struct device *class_dev; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc *debugifc; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item *item_first; struct pvr2_sysfs_ctl_item *item_last; - struct class_device_attribute attr_v4l_minor_number; - struct class_device_attribute attr_v4l_radio_minor_number; - struct class_device_attribute attr_unit_number; - struct class_device_attribute attr_bus_info; + struct device_attribute attr_v4l_minor_number; + struct device_attribute attr_v4l_radio_minor_number; + struct device_attribute attr_unit_number; + struct device_attribute attr_bus_info; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; @@ -51,22 +51,22 @@ struct pvr2_sysfs { #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc { - struct class_device_attribute attr_debugcmd; - struct class_device_attribute attr_debuginfo; + struct device_attribute attr_debugcmd; + struct device_attribute attr_debuginfo; int debugcmd_created_ok; int debuginfo_created_ok; }; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item { - struct class_device_attribute attr_name; - struct class_device_attribute attr_type; - struct class_device_attribute attr_min; - struct class_device_attribute attr_max; - struct class_device_attribute attr_enum; - struct class_device_attribute attr_bits; - struct class_device_attribute attr_val; - struct class_device_attribute attr_custom; + struct device_attribute attr_name; + struct device_attribute attr_type; + struct device_attribute attr_min; + struct device_attribute attr_max; + struct device_attribute attr_enum; + struct device_attribute attr_bits; + struct device_attribute attr_val; + struct device_attribute attr_custom; struct pvr2_ctrl *cptr; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; @@ -80,13 +80,13 @@ struct pvr2_sysfs_class { struct class class; }; -static ssize_t show_name(int id,struct class_device *class_dev,char *buf) +static ssize_t show_name(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -99,14 +99,14 @@ static ssize_t show_name(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%s\n",name); } -static ssize_t show_type(int id,struct class_device *class_dev,char *buf) +static ssize_t show_type(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; enum pvr2_ctl_type tp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -126,13 +126,13 @@ static ssize_t show_type(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%s\n",name); } -static ssize_t show_min(int id,struct class_device *class_dev,char *buf) +static ssize_t show_min(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -143,13 +143,13 @@ static ssize_t show_min(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%ld\n",val); } -static ssize_t show_max(int id,struct class_device *class_dev,char *buf) +static ssize_t show_max(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -160,14 +160,14 @@ static ssize_t show_max(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%ld\n",val); } -static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) +static ssize_t show_val_norm(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -184,14 +184,14 @@ static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) return cnt+1; } -static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) +static ssize_t show_val_custom(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -208,14 +208,14 @@ static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) return cnt+1; } -static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) +static ssize_t show_enum(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; unsigned int bcnt,ccnt,ecnt; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -233,14 +233,14 @@ static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) return bcnt; } -static ssize_t show_bits(int id,struct class_device *class_dev,char *buf) +static ssize_t show_bits(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int valid_bits,msk; unsigned int bcnt,ccnt; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -278,23 +278,23 @@ static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp, return ret; } -static ssize_t store_val_norm(int id,struct class_device *class_dev, +static ssize_t store_val_norm(int id,struct device *class_dev, const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,0,sfp,buf,count); if (!ret) ret = count; return ret; } -static ssize_t store_val_custom(int id,struct class_device *class_dev, +static ssize_t store_val_custom(int id,struct device *class_dev, const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,1,sfp,buf,count); if (!ret) ret = count; return ret; @@ -304,7 +304,7 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev, Mike Isely 30-April-2005 This next batch of horrible preprocessor hackery is needed because the - kernel's class_device_attribute mechanism fails to pass the actual + kernel's device_attribute mechanism fails to pass the actual attribute through to the show / store functions, which means we have no way to package up any attribute-specific parameters, like for example the control id. So we work around this brain-damage by encoding the control @@ -314,11 +314,13 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev, */ #define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \ +static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ +struct device_attribute *attr, char *buf) \ { return sf_name(ctl_id,class_dev,buf); } #define CREATE_STORE_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \ +static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ +struct device_attribute *attr, const char *buf, size_t count) \ { return sf_name(ctl_id,class_dev,buf,count); } #define CREATE_BATCH(ctl_id) \ @@ -395,17 +397,27 @@ CREATE_BATCH(58) CREATE_BATCH(59) struct pvr2_sysfs_func_set { - ssize_t (*show_name)(struct class_device *,char *); - ssize_t (*show_type)(struct class_device *,char *); - ssize_t (*show_min)(struct class_device *,char *); - ssize_t (*show_max)(struct class_device *,char *); - ssize_t (*show_enum)(struct class_device *,char *); - ssize_t (*show_bits)(struct class_device *,char *); - ssize_t (*show_val_norm)(struct class_device *,char *); - ssize_t (*store_val_norm)(struct class_device *, + ssize_t (*show_name)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_type)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_min)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_max)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_enum)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_bits)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_val_norm)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*store_val_norm)(struct device *, + struct device_attribute *attr, const char *,size_t); - ssize_t (*show_val_custom)(struct class_device *,char *); - ssize_t (*store_val_custom)(struct class_device *, + ssize_t (*show_val_custom)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*store_val_custom)(struct device *, + struct device_attribute *attr, const char *,size_t); }; @@ -597,9 +609,9 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) } #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct class_device *,char *); -static ssize_t debugcmd_show(struct class_device *,char *); -static ssize_t debugcmd_store(struct class_device *,const char *,size_t count); +static ssize_t debuginfo_show(struct device *,char *); +static ssize_t debugcmd_show(struct device *,char *); +static ssize_t debugcmd_store(struct device *,const char *,size_t count); static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) { @@ -616,16 +628,16 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) dip->attr_debuginfo.attr.mode = S_IRUGO; dip->attr_debuginfo.show = debuginfo_show; sfp->debugifc = dip; - ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd); + ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { dip->debugcmd_created_ok = !0; } - ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo); + ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { dip->debuginfo_created_ok = !0; @@ -637,11 +649,11 @@ static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) { if (!sfp->debugifc) return; if (sfp->debugifc->debuginfo_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->debugifc->attr_debuginfo); } if (sfp->debugifc->debugcmd_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->debugifc->attr_debugcmd); } kfree(sfp->debugifc); @@ -683,7 +695,7 @@ static void pvr2_sysfs_class_release(struct class *class) } -static void pvr2_sysfs_release(struct class_device *class_dev) +static void pvr2_sysfs_release(struct device *class_dev) { pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); kfree(class_dev); @@ -698,32 +710,33 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ pvr2_sysfs_tear_down_controls(sfp); if (sfp->bus_info_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_bus_info); } if (sfp->v4l_minor_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_v4l_minor_number); } if (sfp->v4l_radio_minor_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_v4l_radio_minor_number); } if (sfp->unit_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_unit_number); } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); - sfp->class_dev->class_data = NULL; - class_device_unregister(sfp->class_dev); + sfp->class_dev->driver_data = NULL; + device_unregister(sfp->class_dev); sfp->class_dev = NULL; } -static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) +static ssize_t v4l_minor_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -731,21 +744,23 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) } -static ssize_t bus_info_show(struct class_device *class_dev,char *buf) +static ssize_t bus_info_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_bus_info(sfp->channel.hdw)); } -static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, +static ssize_t v4l_radio_minor_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -753,10 +768,11 @@ static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, } -static ssize_t unit_number_show(struct class_device *class_dev,char *buf) +static ssize_t unit_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_get_unit_number(sfp->channel.hdw)); @@ -767,7 +783,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp, struct pvr2_sysfs_class *class_ptr) { struct usb_device *usb_dev; - struct class_device *class_dev; + struct device *class_dev; int ret; usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); @@ -779,23 +795,23 @@ static void class_dev_create(struct pvr2_sysfs *sfp, class_dev->class = &class_ptr->class; if (pvr2_hdw_get_sn(sfp->channel.hdw)) { - snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu", + snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu", pvr2_hdw_get_sn(sfp->channel.hdw)); } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) { - snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c", + snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c", pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a'); } else { kfree(class_dev); return; } - class_dev->dev = &usb_dev->dev; + class_dev->parent = &usb_dev->dev; sfp->class_dev = class_dev; - class_dev->class_data = sfp; - ret = class_device_register(class_dev); + class_dev->driver_data = sfp; + ret = device_register(class_dev); if (ret) { - printk(KERN_ERR "%s: class_device_register failed\n", + printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); kfree(class_dev); return; @@ -805,10 +821,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_minor_number.show = v4l_minor_number_show; sfp->attr_v4l_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_v4l_minor_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->v4l_minor_number_created_ok = !0; @@ -818,10 +834,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; sfp->attr_v4l_radio_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_v4l_radio_minor_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->v4l_radio_minor_number_created_ok = !0; @@ -831,9 +847,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_unit_number.attr.mode = S_IRUGO; sfp->attr_unit_number.show = unit_number_show; sfp->attr_unit_number.store = NULL; - ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number); + ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->unit_number_created_ok = !0; @@ -843,10 +859,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_bus_info.attr.mode = S_IRUGO; sfp->attr_bus_info.show = bus_info_show; sfp->attr_bus_info.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_bus_info); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->bus_info_created_ok = !0; @@ -886,7 +902,7 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp, +static int pvr2_sysfs_hotplug(struct device *cd,char **envp, int numenvp,char *buf,int size) { /* Even though we don't do anything here, we still need this function @@ -902,8 +918,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp); clp->class.name = "pvrusb2"; clp->class.class_release = pvr2_sysfs_class_release; - clp->class.release = pvr2_sysfs_release; - clp->class.uevent = pvr2_sysfs_hotplug; + clp->class.dev_release = pvr2_sysfs_release; + clp->class.dev_uevent = pvr2_sysfs_hotplug; if (class_register(&clp->class)) { pvr2_sysfs_trace( "Registration failed for pvr2_sysfs_class id=%p",clp); @@ -921,32 +937,32 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct class_device *class_dev,char *buf) +static ssize_t debuginfo_show(struct device *class_dev,char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; pvr2_hdw_trigger_module_log(sfp->channel.hdw); return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); } -static ssize_t debugcmd_show(struct class_device *class_dev,char *buf) +static ssize_t debugcmd_show(struct device *class_dev,char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); } -static ssize_t debugcmd_store(struct class_device *class_dev, - const char *buf,size_t count) +static ssize_t debugcmd_store(struct device *class_dev, + const char *buf, size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 0ff5718bf9b9..0b67d4ec0318 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -996,20 +996,22 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f /********* * sysfs *********/ -static struct pwc_device *cd_to_pwc(struct class_device *cd) +static struct pwc_device *cd_to_pwc(struct device *cd) { struct video_device *vdev = to_video_device(cd); return video_get_drvdata(vdev); } -static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf) +static ssize_t show_pan_tilt(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pwc_device *pdev = cd_to_pwc(class_dev); return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle); } -static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, - size_t count) +static ssize_t store_pan_tilt(struct device *class_dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct pwc_device *pdev = cd_to_pwc(class_dev); int pan, tilt; @@ -1025,10 +1027,11 @@ static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, return ret; return strlen(buf); } -static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); +static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, + store_pan_tilt); -static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf) +static ssize_t show_snapshot_button_status(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pwc_device *pdev = cd_to_pwc(class_dev); int status = pdev->snapshot_button_status; @@ -1036,26 +1039,26 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char return sprintf(buf, "%d\n", status); } -static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, - NULL); +static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, + NULL); static int pwc_create_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); int rc; - rc = video_device_create_file(vdev, &class_device_attr_button); + rc = video_device_create_file(vdev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = video_device_create_file(vdev,&class_device_attr_pan_tilt); + rc = video_device_create_file(vdev, &dev_attr_pan_tilt); if (rc) goto err_button; } return 0; err_button: - video_device_remove_file(vdev, &class_device_attr_button); + video_device_remove_file(vdev, &dev_attr_button); err: return rc; } @@ -1064,8 +1067,8 @@ static void pwc_remove_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_remove_file(vdev, &class_device_attr_pan_tilt); - video_device_remove_file(vdev, &class_device_attr_button); + video_device_remove_file(vdev, &dev_attr_pan_tilt); + video_device_remove_file(vdev, &dev_attr_button); } #ifdef CONFIG_USB_PWC_DEBUG diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index e0accf1b8713..6991e06f7651 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1029,7 +1029,8 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) NOTE 2: buffers are PAGE_SIZE long */ -static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1053,7 +1054,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 index; @@ -1086,7 +1088,8 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1118,7 +1121,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 value; @@ -1157,7 +1161,8 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1183,7 +1188,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 index; @@ -1216,7 +1222,8 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1253,7 +1260,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 value; @@ -1298,7 +1306,8 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) static ssize_t -sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_green(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; enum sn9c102_bridge bridge; @@ -1329,16 +1338,16 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) case BRIDGE_SN9C102: if (value > 0x0f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); break; case BRIDGE_SN9C103: case BRIDGE_SN9C105: case BRIDGE_SN9C120: if (value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); break; } @@ -1347,7 +1356,8 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) static ssize_t -sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_blue(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { ssize_t res = 0; u16 value; @@ -1357,15 +1367,16 @@ sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); return res; } static ssize_t -sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_red(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { ssize_t res = 0; u16 value; @@ -1375,14 +1386,16 @@ sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); return res; } -static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_frame_header(struct device* cd, + struct device_attribute *attr, + char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1401,72 +1414,63 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) } -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - sn9c102_show_reg, sn9c102_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - sn9c102_show_val, sn9c102_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); -static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); -static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); -static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, - sn9c102_show_frame_header, NULL); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_val, sn9c102_store_i2c_val); +static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); +static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); +static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); +static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); static int sn9c102_create_sysfs(struct sn9c102_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = device_create_file(classdev, &dev_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = device_create_file(classdev, &dev_attr_val))) goto err_reg; - if ((err = class_device_create_file(classdev, - &class_device_attr_frame_header))) + if ((err = device_create_file(classdev, &dev_attr_frame_header))) goto err_val; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_reg))) + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) goto err_frame_header; - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_val))) + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) goto err_i2c_reg; } if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if ((err = class_device_create_file(classdev, - &class_device_attr_green))) + if ((err = device_create_file(classdev, &dev_attr_green))) goto err_i2c_val; } else { - if ((err = class_device_create_file(classdev, - &class_device_attr_blue))) + if ((err = device_create_file(classdev, &dev_attr_blue))) goto err_i2c_val; - if ((err = class_device_create_file(classdev, - &class_device_attr_red))) + if ((err = device_create_file(classdev, &dev_attr_red))) goto err_blue; } return 0; err_blue: - class_device_remove_file(classdev, &class_device_attr_blue); + device_remove_file(classdev, &dev_attr_blue); err_i2c_val: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_val); + device_remove_file(classdev, &dev_attr_i2c_val); err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + device_remove_file(classdev, &dev_attr_i2c_reg); err_frame_header: - class_device_remove_file(classdev, &class_device_attr_frame_header); + device_remove_file(classdev, &dev_attr_frame_header); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + device_remove_file(classdev, &dev_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + device_remove_file(classdev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 4dc5bc714b95..9e009a7ab863 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -499,13 +499,14 @@ exit: * sysfs ***************************************************************************/ #define stv680_file(name, variable, field) \ -static ssize_t show_##name(struct class_device *class_dev, char *buf) \ +static ssize_t show_##name(struct device *class_dev, \ + struct device_attribute *attr, char *buf) \ { \ struct video_device *vdev = to_video_device(class_dev); \ struct usb_stv *stv = video_get_drvdata(vdev); \ return sprintf(buf, field, stv->variable); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); stv680_file(model, camera_name, "%s\n"); stv680_file(in_use, user, "%d\n"); @@ -520,53 +521,53 @@ static int stv680_create_sysfs_files(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &class_device_attr_model); + rc = video_device_create_file(vdev, &dev_attr_model); if (rc) goto err; - rc = video_device_create_file(vdev, &class_device_attr_in_use); + rc = video_device_create_file(vdev, &dev_attr_in_use); if (rc) goto err_model; - rc = video_device_create_file(vdev, &class_device_attr_streaming); + rc = video_device_create_file(vdev, &dev_attr_streaming); if (rc) goto err_inuse; - rc = video_device_create_file(vdev, &class_device_attr_palette); + rc = video_device_create_file(vdev, &dev_attr_palette); if (rc) goto err_stream; - rc = video_device_create_file(vdev, &class_device_attr_frames_total); + rc = video_device_create_file(vdev, &dev_attr_frames_total); if (rc) goto err_pal; - rc = video_device_create_file(vdev, &class_device_attr_frames_read); + rc = video_device_create_file(vdev, &dev_attr_frames_read); if (rc) goto err_framtot; - rc = video_device_create_file(vdev, &class_device_attr_packets_dropped); + rc = video_device_create_file(vdev, &dev_attr_packets_dropped); if (rc) goto err_framread; - rc = video_device_create_file(vdev, &class_device_attr_decoding_errors); + rc = video_device_create_file(vdev, &dev_attr_decoding_errors); if (rc) goto err_dropped; return 0; err_dropped: - video_device_remove_file(vdev, &class_device_attr_packets_dropped); + video_device_remove_file(vdev, &dev_attr_packets_dropped); err_framread: - video_device_remove_file(vdev, &class_device_attr_frames_read); + video_device_remove_file(vdev, &dev_attr_frames_read); err_framtot: - video_device_remove_file(vdev, &class_device_attr_frames_total); + video_device_remove_file(vdev, &dev_attr_frames_total); err_pal: - video_device_remove_file(vdev, &class_device_attr_palette); + video_device_remove_file(vdev, &dev_attr_palette); err_stream: - video_device_remove_file(vdev, &class_device_attr_streaming); + video_device_remove_file(vdev, &dev_attr_streaming); err_inuse: - video_device_remove_file(vdev, &class_device_attr_in_use); + video_device_remove_file(vdev, &dev_attr_in_use); err_model: - video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &dev_attr_model); err: return rc; } static void stv680_remove_sysfs_files(struct video_device *vdev) { - video_device_remove_file(vdev, &class_device_attr_model); - video_device_remove_file(vdev, &class_device_attr_in_use); - video_device_remove_file(vdev, &class_device_attr_streaming); - video_device_remove_file(vdev, &class_device_attr_palette); - video_device_remove_file(vdev, &class_device_attr_frames_total); - video_device_remove_file(vdev, &class_device_attr_frames_read); - video_device_remove_file(vdev, &class_device_attr_packets_dropped); - video_device_remove_file(vdev, &class_device_attr_decoding_errors); + video_device_remove_file(vdev, &dev_attr_model); + video_device_remove_file(vdev, &dev_attr_in_use); + video_device_remove_file(vdev, &dev_attr_streaming); + video_device_remove_file(vdev, &dev_attr_palette); + video_device_remove_file(vdev, &dev_attr_frames_total); + video_device_remove_file(vdev, &dev_attr_frames_read); + video_device_remove_file(vdev, &dev_attr_packets_dropped); + video_device_remove_file(vdev, &dev_attr_decoding_errors); } /******************************************************************** diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 2f9b2b9e3b09..e2f3c01cfa13 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -182,20 +182,22 @@ MODULE_ALIAS(DRIVER_ALIAS); #define YES_NO(x) ((x) ? "Yes" : "No") -static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) +static inline struct usb_usbvision *cd_to_usbvision(struct device *cd) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); return video_get_drvdata(vdev); } -static ssize_t show_version(struct class_device *cd, char *buf) +static ssize_t show_version(struct device *cd, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", USBVISION_VERSION_STRING); } -static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); +static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); -static ssize_t show_model(struct class_device *cd, char *buf) +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -203,9 +205,10 @@ static ssize_t show_model(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); } -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_hue(struct class_device *cd, char *buf) +static ssize_t show_hue(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -217,9 +220,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_contrast(struct class_device *cd, char *buf) +static ssize_t show_contrast(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -231,9 +235,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_brightness(struct class_device *cd, char *buf) +static ssize_t show_brightness(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -245,9 +250,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *cd, char *buf) +static ssize_t show_saturation(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -259,9 +265,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_streaming(struct class_device *cd, char *buf) +static ssize_t show_streaming(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -269,9 +276,10 @@ static ssize_t show_streaming(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); } -static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); +static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); -static ssize_t show_compression(struct class_device *cd, char *buf) +static ssize_t show_compression(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -279,16 +287,17 @@ static ssize_t show_compression(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); } -static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); +static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); -static ssize_t show_device_bridge(struct class_device *cd, char *buf) +static ssize_t show_device_bridge(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType); } -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); +static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); static void usbvision_create_sysfs(struct video_device *vdev) { @@ -296,40 +305,40 @@ static void usbvision_create_sysfs(struct video_device *vdev) if (!vdev) return; do { - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_version); + res = device_create_file(&vdev->class_dev, + &dev_attr_version); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_model); + res = device_create_file(&vdev->class_dev, + &dev_attr_model); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_hue); + res = device_create_file(&vdev->class_dev, + &dev_attr_hue); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_contrast); + res = device_create_file(&vdev->class_dev, + &dev_attr_contrast); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_brightness); + res = device_create_file(&vdev->class_dev, + &dev_attr_brightness); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_saturation); + res = device_create_file(&vdev->class_dev, + &dev_attr_saturation); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_streaming); + res = device_create_file(&vdev->class_dev, + &dev_attr_streaming); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_compression); + res = device_create_file(&vdev->class_dev, + &dev_attr_compression); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_bridge); + res = device_create_file(&vdev->class_dev, + &dev_attr_bridge); if (res>=0) return; } while (0); @@ -340,24 +349,24 @@ static void usbvision_create_sysfs(struct video_device *vdev) static void usbvision_remove_sysfs(struct video_device *vdev) { if (vdev) { - class_device_remove_file(&vdev->class_dev, - &class_device_attr_version); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_model); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_hue); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_contrast); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_brightness); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_saturation); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_streaming); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_compression); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_bridge); + device_remove_file(&vdev->class_dev, + &dev_attr_version); + device_remove_file(&vdev->class_dev, + &dev_attr_model); + device_remove_file(&vdev->class_dev, + &dev_attr_hue); + device_remove_file(&vdev->class_dev, + &dev_attr_contrast); + device_remove_file(&vdev->class_dev, + &dev_attr_brightness); + device_remove_file(&vdev->class_dev, + &dev_attr_saturation); + device_remove_file(&vdev->class_dev, + &dev_attr_streaming); + device_remove_file(&vdev->class_dev, + &dev_attr_compression); + device_remove_file(&vdev->class_dev, + &dev_attr_bridge); } } diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 0334b9aaf12a..0fbe8a1a91b3 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -54,15 +54,14 @@ * sysfs stuff */ -static ssize_t show_name(struct class_device *cd, char *buf) +static ssize_t show_name(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, - class_dev); - return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name); + class_dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); - struct video_device *video_device_alloc(void) { struct video_device *vfd; @@ -76,10 +75,9 @@ void video_device_release(struct video_device *vfd) kfree(vfd); } -static void video_release(struct class_device *cd) +static void video_release(struct device *cd) { - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); + struct video_device *vfd = container_of(cd, struct video_device, class_dev); #if 1 /* needed until all drivers are fixed */ @@ -89,9 +87,15 @@ static void video_release(struct class_device *cd) vfd->release(vfd); } +static struct device_attribute video_device_attrs[] = { + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR_NULL +}; + static struct class video_class = { .name = VIDEO_NAME, - .release = video_release, + .dev_attrs = video_device_attrs, + .dev_release = video_release, }; /* @@ -1753,22 +1757,16 @@ int video_register_device(struct video_device *vfd, int type, int nr) /* sysfs class */ memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); if (vfd->dev) - vfd->class_dev.dev = vfd->dev; + vfd->class_dev.parent = vfd->dev; vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); - sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base); - ret = class_device_register(&vfd->class_dev); + sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); + ret = device_register(&vfd->class_dev); if (ret < 0) { - printk(KERN_ERR "%s: class_device_register failed\n", + printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); goto fail_minor; } - ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name); - if (ret < 0) { - printk(KERN_ERR "%s: class_device_create_file 'name' failed\n", - __FUNCTION__); - goto fail_classdev; - } #if 1 /* needed until all drivers are fixed */ @@ -1779,8 +1777,6 @@ int video_register_device(struct video_device *vfd, int type, int nr) #endif return 0; -fail_classdev: - class_device_unregister(&vfd->class_dev); fail_minor: mutex_lock(&videodev_lock); video_device[vfd->minor] = NULL; @@ -1804,7 +1800,7 @@ void video_unregister_device(struct video_device *vfd) panic("videodev: bad unregister"); video_device[vfd->minor]=NULL; - class_device_unregister(&vfd->class_dev); + device_unregister(&vfd->class_dev); mutex_unlock(&videodev_lock); } diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 8b79e2cf77fa..e75d5e6c4cea 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -86,8 +86,11 @@ struct video_device /* device ops */ const struct file_operations *fops; + /* sysfs */ + struct device class_dev; /* v4l device */ + struct device *dev; /* device parent */ + /* device info */ - struct device *dev; char name[32]; int type; /* v4l1 */ int type2; /* v4l2 */ @@ -332,7 +335,6 @@ void *priv; /* for videodev.c intenal usage -- please don't touch */ int users; /* video_exclusive_{open|close} ... */ struct mutex lock; /* ... helper function uses these */ - struct class_device class_dev; /* sysfs */ }; /* Class-dev to video-device */ @@ -360,18 +362,18 @@ extern int video_usercopy(struct inode *inode, struct file *file, static inline int __must_check video_device_create_file(struct video_device *vfd, - struct class_device_attribute *attr) + struct device_attribute *attr) { - int ret = class_device_create_file(&vfd->class_dev, attr); + int ret = device_create_file(&vfd->class_dev, attr); if (ret < 0) printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret); return ret; } static inline void video_device_remove_file(struct video_device *vfd, - struct class_device_attribute *attr) + struct device_attribute *attr) { - class_device_remove_file(&vfd->class_dev, attr); + device_remove_file(&vfd->class_dev, attr); } #endif /* CONFIG_VIDEO_V4L1_COMPAT */ From 0ac3a5bbca33840542d98420d9d82e8738299b20 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 8 Oct 2007 16:13:02 -0300 Subject: [PATCH 0871/2804] V4L/DVB (6295): saa7134: add autodetection for KWorld ATSC-115 Recognize the KWorld ATSC115 PCI ID as a hardware clone of the ATSC110. Signed-off-by: Eric Sandeen Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 67f08cc4be70..a14545300e4c 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -88,7 +88,7 @@ 87 -> ADS Instant TV Duo Cardbus PTV331 [0331:1421] 88 -> Tevion/KWorld DVB-T 220RF [17de:7201] 89 -> ELSA EX-VISION 700TV [1048:226c] - 90 -> Kworld ATSC110 [17de:7350] + 90 -> Kworld ATSC110/115 [17de:7350,17de:7352] 91 -> AVerMedia A169 B [1461:7360] 92 -> AVerMedia A169 B1 [1461:6360] 93 -> Medion 7134 Bridge #2 [16be:0005] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 62420d599d75..a4c192fb4e41 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2822,7 +2822,7 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_KWORLD_ATSC110] = { - .name = "Kworld ATSC110", + .name = "Kworld ATSC110/115", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TUV1236D, .radio_type = UNSET, @@ -4082,6 +4082,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x17de, .subdevice = 0x7350, .driver_data = SAA7134_BOARD_KWORLD_ATSC110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ + .subvendor = 0x17de, + .subdevice = 0x7352, + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, From fa3b877e5c75a2f4d1706c40163dbf176a2fd80d Mon Sep 17 00:00:00 2001 From: Joachim Steiger Date: Mon, 8 Oct 2007 20:08:46 -0300 Subject: [PATCH 0872/2804] V4L/DVB (6296): dib0700: add support for AverMedia DVB-T Express card add Avermedia dvb-t express card 34 (usb2) id Signed-off-by: Joachim Steiger Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 063fb5095bda..e8c4a8694532 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -820,6 +820,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, +/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -861,7 +862,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 6, + .num_device_descs = 7, .devices = { { "DiBcom STK7700P reference design", { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, @@ -886,6 +887,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Leadtek Winfast DTV Dongle (STK7700P based)", { &dib0700_usb_id_table[8], NULL }, { NULL }, + }, + { "AVerMedia AVerTV DVB-T Express", + { &dib0700_usb_id_table[20] }, + { NULL }, } }, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 43bfe50a2227..4fa3e895028a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -121,6 +121,7 @@ #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 +#define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a From 21a7ad4a7e86a5da16caf61eb50bc92af4929672 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 8 Oct 2007 17:18:17 -0300 Subject: [PATCH 0873/2804] V4L/DVB (6297): cx23885: remove wrong Kconfig selection of VIDEOBUF fix bad Kconfig dependency of cx23885 module. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index af60700da8c0..72004a07b2d5 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,7 +4,6 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEOBUF select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR From 102abd826a20307c5a0d23f49b8a3b5d98bddf94 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 18:34:11 -0300 Subject: [PATCH 0874/2804] V4L/DVB (6299): dvb: Add dependencies for VIDEOBUF_DVB It needs to select VIDEOBUF_GEN and VIDEOBUF_DMA_SG, since it uses those modules. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index e705265909da..dd9bd4310c84 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -140,6 +140,8 @@ config VIDEOBUF_VMALLOC config VIDEOBUF_DVB tristate + select VIDEOBUF_GEN + select VIDEOBUF_DMA_SG config VIDEO_BTCX tristate From bde00cc027879a39f249ffedb048032cb7e484e4 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 18:36:21 -0300 Subject: [PATCH 0875/2804] V4L/DVB (6300): CodingStyle cleanup Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 0fbe8a1a91b3..8d8e517b344f 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -77,7 +77,8 @@ void video_device_release(struct video_device *vfd) static void video_release(struct device *cd) { - struct video_device *vfd = container_of(cd, struct video_device, class_dev); + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); #if 1 /* needed until all drivers are fixed */ From c726b65d079cafabc558616badbeead442e2b114 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 19:05:28 -0300 Subject: [PATCH 0876/2804] V4L/DVB (6301): pvrusb: Update DEBUGIFC sysfs to kernel 2.6.13+ The prototypes for the show and store methods of a device_attribute changed in kernel 2.6.13, but the code in pvrusb2 was never updated. I guess the DEBUGIFC stuff isn't used much.... Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index b20dc4421d59..7a78d6b34738 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -609,9 +609,12 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) } #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct device *,char *); -static ssize_t debugcmd_show(struct device *,char *); -static ssize_t debugcmd_store(struct device *,const char *,size_t count); +static ssize_t debuginfo_show(struct device *, struct device_attribute *, + char *); +static ssize_t debugcmd_show(struct device *, struct device_attribute *, + char *); +static ssize_t debugcmd_store(struct device *, struct device_attribute *, + const char *, size_t count); static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) { @@ -937,7 +940,8 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct device *class_dev,char *buf) +static ssize_t debuginfo_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; sfp = (struct pvr2_sysfs *)class_dev->driver_data; @@ -947,7 +951,8 @@ static ssize_t debuginfo_show(struct device *class_dev,char *buf) } -static ssize_t debugcmd_show(struct device *class_dev,char *buf) +static ssize_t debugcmd_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; sfp = (struct pvr2_sysfs *)class_dev->driver_data; @@ -957,6 +962,7 @@ static ssize_t debugcmd_show(struct device *class_dev,char *buf) static ssize_t debugcmd_store(struct device *class_dev, + struct device_attribute *attr, const char *buf, size_t count) { struct pvr2_sysfs *sfp; From 49ee718ef51f4d938f80f67207e1bfa2a38897a4 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Fri, 5 Oct 2007 16:26:27 -0300 Subject: [PATCH 0877/2804] V4L/DVB (6305): V4L: videobuf-core.c avoid NULL dereferences in videobuf-core The return value of videobuf_alloc() is unchecked but this function will return NULL on an error. Check for NULL and make videobuf_reqbufs() return the number of successfully allocated buffers. Also, fix saa7146_video.c and bttv-driver.c to use this returned buffer count. Tested against the vivi driver. Not tested against saa7146 or bt8xx devices. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_video.c | 2 ++ drivers/media/video/bt8xx/bttv-driver.c | 2 ++ drivers/media/video/videobuf-core.c | 20 ++++++++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 29dbc602a484..f245a3b2ef47 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1212,6 +1212,8 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int mutex_unlock(&q->lock); return err; } + + gbuffers = err; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 49278537eec4..7a332b3efe51 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3072,6 +3072,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, V4L2_MEMORY_MMAP); if (retval < 0) goto fh_unlock_and_return; + + gbuffers = retval; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index f5c5ea8b6b08..25a98496e3db 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -329,7 +329,7 @@ int videobuf_reqbufs(struct videobuf_queue *q, goto done; } - req->count = count; + req->count = retval; done: mutex_unlock(&q->lock); @@ -698,7 +698,7 @@ int videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; unsigned long flags=0; - int count = 0, size = 0; + unsigned int count = 0, size = 0; int err, i; q->ops->buf_setup(q,&count,&size); @@ -709,9 +709,11 @@ int videobuf_read_start(struct videobuf_queue *q) size = PAGE_ALIGN(size); err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err) + if (err < 0) return err; + count = err; + for (i = 0; i < count; i++) { field = videobuf_next_field(q); err = q->ops->buf_prepare(q,q->bufs[i],field); @@ -876,6 +878,9 @@ int videobuf_mmap_setup(struct videobuf_queue *q, for (i = 0; i < bcount; i++) { q->bufs[i] = videobuf_alloc(q); + if (q->bufs[i] == NULL) + break; + q->bufs[i]->i = i; q->bufs[i]->input = UNSET; q->bufs[i]->memory = memory; @@ -891,10 +896,13 @@ int videobuf_mmap_setup(struct videobuf_queue *q, } } - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", - bcount,bsize); + if (!i) + return -ENOMEM; - return 0; + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + i, bsize); + + return i; } int videobuf_mmap_free(struct videobuf_queue *q) From acd827d63a568a2cfa26ae8e6093b098c91c631b Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 8 Oct 2007 12:07:35 -0300 Subject: [PATCH 0878/2804] V4L/DVB (6306): Few clenups for saa7134 resume code *Disable DMA explictly on suspend *Enable DMA on resume, after all buffers were configured *Disable overlay on resume - apps should enable it when X is resumed Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 38 ++++++++++--------- drivers/media/video/saa7134/saa7134-tvaudio.c | 2 +- drivers/media/video/saa7134/saa7134.h | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index fae0bfe7939f..80f04f252fce 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -398,29 +398,23 @@ void saa7134_buffer_timeout(unsigned long data) int saa7134_buffer_requeue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q) { - struct saa7134_buf *buf , *next; - unsigned long flags; + struct saa7134_buf *buf, *next; - spin_lock_irqsave(&dev->slock, flags); + assert_spin_locked(&dev->slock); buf = q->curr; next = buf; - dprintk("buffer_requeue\n"); - if (!buf) { - spin_unlock_irqrestore(&dev->slock, flags); + if (!buf) return 0; - } dprintk("buffer_requeue : resending active buffers \n"); if (!list_empty(&q->queue)) next = list_entry(q->queue.next, struct saa7134_buf, vb.queue); - buf->activate(dev, buf, next); - spin_unlock_irqrestore(&dev->slock, flags); return 0; } @@ -435,6 +429,9 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) assert_spin_locked(&dev->slock); + if (dev->inresume) + return 0; + /* video capture -- dma 0 + video task A */ if (dev->video_q.curr) { task |= 0x01; @@ -1175,13 +1172,15 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) { - /* Disable card's IRQs to prevent it from resuming computer */ - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + /* disable overlay - apps should enable it explicitly on resume*/ + dev->ovenable = 0; + + /* Disable interrupts, DMA, and rest of the chip*/ saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); - + saa_writel(SAA7134_MAIN_CTRL, 0); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); pci_save_state(pci_dev); @@ -1193,6 +1192,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) { struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + unsigned int flags; pci_restore_state(pci_dev); pci_set_power_state(pci_dev, PCI_D0); @@ -1200,6 +1200,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) /* Do things that are done in saa7134_initdev , except of initializing memory structures.*/ + dev->inresume = 1; saa7134_board_init1(dev); if (saa7134_boards[dev->board].video_out) @@ -1209,25 +1210,26 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_ts_init_hw(dev); saa7134_hw_enable1(dev); - saa7134_set_decoder(dev); - saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); - saa7134_board_init2(dev); saa7134_hw_enable2(dev); - dev->force_mute_update = 1; saa7134_tvaudio_setmute(dev); - dev->force_mute_update = 0; saa7134_tvaudio_setvolume(dev, dev->ctl_volume); saa7134_enable_i2s(dev); - /*recapture unfinished buffer(s)*/ + /*resume unfinished buffer(s)*/ + spin_lock_irqsave(&dev->slock, flags); saa7134_buffer_requeue(dev, &dev->video_q); saa7134_buffer_requeue(dev, &dev->vbi_q); saa7134_buffer_requeue(dev, &dev->ts_q); + /* start DMA now*/ + dev->inresume = 0; + saa7134_set_dmabits(dev); + spin_unlock_irqrestore(&dev->slock, flags); + return 0; } diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index df2dab06387d..1b9e39a5ea47 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -231,7 +231,7 @@ static void mute_input_7134(struct saa7134_dev *dev) } if (dev->hw_mute == mute && - dev->hw_input == in && !dev->force_mute_update) { + dev->hw_input == in && !dev->inresume) { dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", mute,in->name); return; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 064f3dbe6951..28ec6804bd5d 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -522,9 +522,9 @@ struct saa7134_dev { struct saa7134_input *input; struct saa7134_input *hw_input; unsigned int hw_mute; - unsigned int force_mute_update; int last_carrier; int nosignal; + unsigned int inresume; /* SAA7134_MPEG_* */ struct saa7134_ts ts; From 3abff557d5eed7d6fd03aa11353a1c0f329cac2b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 9 Oct 2007 22:03:12 -0300 Subject: [PATCH 0879/2804] V4L/DVB (6307): V4L: w9968cf, remove bad usage of ERESTARTSYS w9968cf, remove bad usage of ERESTARTSYS down_read_trylock can't be interrupted and so ERESTARTSYS would reach userspace, which is not permitted. Change it to EAGAIN Signed-off-by: Jiri Slaby Acked-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/w9968cf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 77599f228b61..5a1b5f5a7d46 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -2679,7 +2679,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) /* This the only safe way to prevent race conditions with disconnect */ if (!down_read_trylock(&w9968cf_disconnect)) - return -ERESTARTSYS; + return -EAGAIN; cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); From c3e2a8e64cb2282a406ff6e63f7bd09eb6f61a1d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 9 Oct 2007 22:15:27 -0300 Subject: [PATCH 0880/2804] V4L/DVB (6308): V4L: zc0301, remove bad usage of ERESTARTSYS zc0301, remove bad usage of ERESTARTSYS down_read_trylock can't be interrupted and so ERESTARTSYS would reach userspace, which is not permitted. Change it to EAGAIN Signed-off-by: Jiri Slaby Acked-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zc0301/zc0301_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 35138c594be1..08a93c31c0a0 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -655,7 +655,7 @@ static int zc0301_open(struct inode* inode, struct file* filp) int err = 0; if (!down_read_trylock(&zc0301_dev_lock)) - return -ERESTARTSYS; + return -EAGAIN; cam = video_get_drvdata(video_devdata(filp)); From 210d6ca3db058cd1d6e6fd235ee3e25d6ac221cd Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Tue, 24 Jul 2007 13:55:39 -0700 Subject: [PATCH 0881/2804] IB/ipath: Performance optimization for CPU differences Different processors have different ordering restrictions for write combining. By taking advantage of this, we can eliminate some write barriers when writing to the send buffers. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_diag.c | 22 ++++---- drivers/infiniband/hw/ipath/ipath_iba6120.c | 2 + drivers/infiniband/hw/ipath/ipath_kernel.h | 2 + drivers/infiniband/hw/ipath/ipath_verbs.c | 62 ++++++++++++--------- 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index cf25cdab02f9..4137c7770f1b 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -446,19 +446,21 @@ static ssize_t ipath_diagpkt_write(struct file *fp, dd->ipath_unit, plen - 1, pbufn); if (dp.pbc_wd == 0) - /* Legacy operation, use computed pbc_wd */ dp.pbc_wd = plen; - - /* we have to flush after the PBC for correctness on some cpus - * or WC buffer can be written out of order */ writeq(dp.pbc_wd, piobuf); - ipath_flush_wc(); - /* copy all by the trigger word, then flush, so it's written + /* + * Copy all by the trigger word, then flush, so it's written * to chip before trigger word, then write trigger word, then - * flush again, so packet is sent. */ - __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); - ipath_flush_wc(); - __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); + * flush again, so packet is sent. + */ + if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) { + ipath_flush_wc(); + __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); + ipath_flush_wc(); + __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); + } else + __iowrite32_copy(piobuf + 2, tmpbuf, clen); + ipath_flush_wc(); ret = sizeof(dp); diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index 5b6ac9a1a709..a324c6f7aeba 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -1273,6 +1273,8 @@ static void ipath_pe_tidtemplate(struct ipath_devdata *dd) static int ipath_pe_early_init(struct ipath_devdata *dd) { dd->ipath_flags |= IPATH_4BYTE_TID; + if (ipath_unordered_wc()) + dd->ipath_flags |= IPATH_PIO_FLUSH_WC; /* * For openfabrics, we need to be able to handle an IB header of diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 7a7966f7e4ff..d983f92b9bcb 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -724,6 +724,8 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); #define IPATH_LINKACTIVE 0x200 /* link current state is unknown */ #define IPATH_LINKUNK 0x400 + /* Write combining flush needed for PIO */ +#define IPATH_PIO_FLUSH_WC 0x1000 /* no IB cable, or no device on IB cable */ #define IPATH_NOCABLE 0x4000 /* Supports port zero per packet receive interrupts via diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 16aa61fd8085..559d4a662937 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -631,7 +631,7 @@ static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off) #endif static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, - u32 length) + u32 length, unsigned flush_wc) { u32 extra = 0; u32 data = 0; @@ -757,11 +757,14 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, } /* Update address before sending packet. */ update_sge(ss, length); - /* must flush early everything before trigger word */ - ipath_flush_wc(); - __raw_writel(last, piobuf); - /* be sure trigger word is written */ - ipath_flush_wc(); + if (flush_wc) { + /* must flush early everything before trigger word */ + ipath_flush_wc(); + __raw_writel(last, piobuf); + /* be sure trigger word is written */ + ipath_flush_wc(); + } else + __raw_writel(last, piobuf); } /** @@ -776,6 +779,7 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, u32 *hdr, u32 len, struct ipath_sge_state *ss) { u32 __iomem *piobuf; + unsigned flush_wc; u32 plen; int ret; @@ -799,47 +803,55 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, * or WC buffer can be written out of order. */ writeq(plen, piobuf); - ipath_flush_wc(); piobuf += 2; + + flush_wc = dd->ipath_flags & IPATH_PIO_FLUSH_WC; if (len == 0) { /* * If there is just the header portion, must flush before * writing last word of header for correctness, and after * the last header word (trigger word). */ - __iowrite32_copy(piobuf, hdr, hdrwords - 1); - ipath_flush_wc(); - __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1); - ipath_flush_wc(); - ret = 0; - goto bail; + if (flush_wc) { + ipath_flush_wc(); + __iowrite32_copy(piobuf, hdr, hdrwords - 1); + ipath_flush_wc(); + __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1); + ipath_flush_wc(); + } else + __iowrite32_copy(piobuf, hdr, hdrwords); + goto done; } + if (flush_wc) + ipath_flush_wc(); __iowrite32_copy(piobuf, hdr, hdrwords); piobuf += hdrwords; /* The common case is aligned and contained in one segment. */ if (likely(ss->num_sge == 1 && len <= ss->sge.length && !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) { - u32 w; + u32 dwords; u32 *addr = (u32 *) ss->sge.vaddr; /* Update address before sending packet. */ update_sge(ss, len); /* Need to round up for the last dword in the packet. */ - w = (len + 3) >> 2; - __iowrite32_copy(piobuf, addr, w - 1); - /* must flush early everything before trigger word */ - ipath_flush_wc(); - __raw_writel(addr[w - 1], piobuf + w - 1); - /* be sure trigger word is written */ - ipath_flush_wc(); - ret = 0; - goto bail; + dwords = (len + 3) >> 2; + if (flush_wc) { + __iowrite32_copy(piobuf, addr, dwords - 1); + /* must flush early everything before trigger word */ + ipath_flush_wc(); + __raw_writel(addr[dwords - 1], piobuf + dwords - 1); + /* be sure trigger word is written */ + ipath_flush_wc(); + } else + __iowrite32_copy(piobuf, addr, dwords); + goto done; } - copy_io(piobuf, ss, len); + copy_io(piobuf, ss, len, flush_wc); +done: ret = 0; - bail: return ret; } From 4ee97180ac76deb5a715ac45b7d7516e6ee82ae7 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Wed, 25 Jul 2007 11:08:28 -0700 Subject: [PATCH 0882/2804] IB/ipath: Change UD to queue work requests like RC & UC The code to post UD sends tried to process work requests at the time ib_post_send() is called without using a WQE queue. This was fine as long as HW resources were available for sending a packet. This patch changes UD to be handled more like RC and UC and shares more code. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_qp.c | 11 +- drivers/infiniband/hw/ipath/ipath_rc.c | 61 ++-- drivers/infiniband/hw/ipath/ipath_ruc.c | 330 +++++++------------ drivers/infiniband/hw/ipath/ipath_uc.c | 77 ++--- drivers/infiniband/hw/ipath/ipath_ud.c | 376 ++++++++-------------- drivers/infiniband/hw/ipath/ipath_verbs.c | 241 +++++++++----- drivers/infiniband/hw/ipath/ipath_verbs.h | 35 +- 7 files changed, 507 insertions(+), 624 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index 1324b35ff1f8..a8c4a6b03d7a 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -338,6 +338,7 @@ static void ipath_reset_qp(struct ipath_qp *qp) qp->s_busy = 0; qp->s_flags &= IPATH_S_SIGNAL_REQ_WR; qp->s_hdrwords = 0; + qp->s_wqe = NULL; qp->s_psn = 0; qp->r_psn = 0; qp->r_msn = 0; @@ -751,6 +752,9 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, switch (init_attr->qp_type) { case IB_QPT_UC: case IB_QPT_RC: + case IB_QPT_UD: + case IB_QPT_SMI: + case IB_QPT_GSI: sz = sizeof(struct ipath_sge) * init_attr->cap.max_send_sge + sizeof(struct ipath_swqe); @@ -759,10 +763,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, ret = ERR_PTR(-ENOMEM); goto bail; } - /* FALLTHROUGH */ - case IB_QPT_UD: - case IB_QPT_SMI: - case IB_QPT_GSI: sz = sizeof(*qp); if (init_attr->srq) { struct ipath_srq *srq = to_isrq(init_attr->srq); @@ -805,8 +805,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, spin_lock_init(&qp->r_rq.lock); atomic_set(&qp->refcount, 0); init_waitqueue_head(&qp->wait); - tasklet_init(&qp->s_task, ipath_do_ruc_send, - (unsigned long)qp); + tasklet_init(&qp->s_task, ipath_do_send, (unsigned long)qp); INIT_LIST_HEAD(&qp->piowait); INIT_LIST_HEAD(&qp->timerwait); qp->state = IB_QPS_RESET; diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index 46744ea2babd..53259daeb4f8 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -81,9 +81,8 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe) * Note that we are in the responder's side of the QP context. * Note the QP s_lock must be held. */ -static int ipath_make_rc_ack(struct ipath_qp *qp, - struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p) +static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp, + struct ipath_other_headers *ohdr, u32 pmtu) { struct ipath_ack_entry *e; u32 hwords; @@ -192,8 +191,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp, } qp->s_hdrwords = hwords; qp->s_cur_size = len; - *bth0p = bth0 | (1 << 22); /* Set M bit */ - *bth2p = bth2; + ipath_make_ruc_header(dev, qp, ohdr, bth0, bth2); return 1; bail: @@ -203,32 +201,39 @@ bail: /** * ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC) * @qp: a pointer to the QP - * @ohdr: a pointer to the IB header being constructed - * @pmtu: the path MTU - * @bth0p: pointer to the BTH opcode word - * @bth2p: pointer to the BTH PSN word * * Return 1 if constructed; otherwise, return 0. - * Note the QP s_lock must be held and interrupts disabled. */ -int ipath_make_rc_req(struct ipath_qp *qp, - struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p) +int ipath_make_rc_req(struct ipath_qp *qp) { struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + struct ipath_other_headers *ohdr; struct ipath_sge_state *ss; struct ipath_swqe *wqe; u32 hwords; u32 len; u32 bth0; u32 bth2; + u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); char newreq; + unsigned long flags; + int ret = 0; + + ohdr = &qp->s_hdr.u.oth; + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + ohdr = &qp->s_hdr.u.l.oth; + + /* + * The lock is needed to synchronize between the sending tasklet, + * the receive interrupt handler, and timeout resends. + */ + spin_lock_irqsave(&qp->s_lock, flags); /* Sending responses has higher priority over sending requests. */ if ((qp->r_head_ack_queue != qp->s_tail_ack_queue || (qp->s_flags & IPATH_S_ACK_PENDING) || qp->s_ack_state != OP(ACKNOWLEDGE)) && - ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p)) + ipath_make_rc_ack(dev, qp, ohdr, pmtu)) goto done; if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) || @@ -560,13 +565,12 @@ int ipath_make_rc_req(struct ipath_qp *qp, qp->s_hdrwords = hwords; qp->s_cur_sge = ss; qp->s_cur_size = len; - *bth0p = bth0 | (qp->s_state << 24); - *bth2p = bth2; + ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2); done: - return 1; - + ret = 1; bail: - return 0; + spin_unlock_irqrestore(&qp->s_lock, flags); + return ret; } /** @@ -627,7 +631,7 @@ static void send_rc_ack(struct ipath_qp *qp) /* * If we can send the ACK, clear the ACK state. */ - if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) { + if (ipath_verbs_send(qp, &hdr, hwords, NULL, 0) == 0) { dev->n_unicast_xmit++; goto done; } @@ -757,7 +761,9 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc) wc->vendor_err = 0; wc->byte_len = 0; wc->qp = &qp->ibqp; + wc->imm_data = 0; wc->src_qp = qp->remote_qpn; + wc->wc_flags = 0; wc->pkey_index = 0; wc->slid = qp->remote_ah_attr.dlid; wc->sl = qp->remote_ah_attr.sl; @@ -1041,7 +1047,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode, wc.vendor_err = 0; wc.byte_len = 0; wc.qp = &qp->ibqp; + wc.imm_data = 0; wc.src_qp = qp->remote_qpn; + wc.wc_flags = 0; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; wc.sl = qp->remote_ah_attr.sl; @@ -1453,6 +1461,19 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, qp->r_ack_psn = qp->r_psn - 1; goto send_ack; } + /* + * Try to send a simple ACK to work around a Mellanox bug + * which doesn't accept a RDMA read response or atomic + * response as an ACK for earlier SENDs or RDMA writes. + */ + if (qp->r_head_ack_queue == qp->s_tail_ack_queue && + !(qp->s_flags & IPATH_S_ACK_PENDING) && + qp->s_ack_state == OP(ACKNOWLEDGE)) { + spin_unlock_irqrestore(&qp->s_lock, flags); + qp->r_nak_state = 0; + qp->r_ack_psn = qp->s_ack_queue[i].psn - 1; + goto send_ack; + } /* * Resend the RDMA read or atomic op which * ACKs this duplicate request. diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index c69c25239443..4b6b7ee8e5c1 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c @@ -31,6 +31,8 @@ * SOFTWARE. */ +#include + #include "ipath_verbs.h" #include "ipath_kernel.h" @@ -106,27 +108,30 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp) spin_unlock_irqrestore(&dev->pending_lock, flags); } -static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe) +/** + * ipath_init_sge - Validate a RWQE and fill in the SGE state + * @qp: the QP + * + * Return 1 if OK. + */ +int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe, + u32 *lengthp, struct ipath_sge_state *ss) { - int user = to_ipd(qp->ibqp.pd)->user; int i, j, ret; struct ib_wc wc; - qp->r_len = 0; + *lengthp = 0; for (i = j = 0; i < wqe->num_sge; i++) { if (wqe->sg_list[i].length == 0) continue; /* Check LKEY */ - if ((user && wqe->sg_list[i].lkey == 0) || - !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i], - IB_ACCESS_LOCAL_WRITE)) + if (!ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge, + &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE)) goto bad_lkey; - qp->r_len += wqe->sg_list[i].length; + *lengthp += wqe->sg_list[i].length; j++; } - qp->r_sge.sge = qp->r_sg_list[0]; - qp->r_sge.sg_list = qp->r_sg_list + 1; - qp->r_sge.num_sge = j; + ss->num_sge = j; ret = 1; goto bail; @@ -172,6 +177,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only) u32 tail; int ret; + qp->r_sge.sg_list = qp->r_sg_list; + if (qp->ibqp.srq) { srq = to_isrq(qp->ibqp.srq); handler = srq->ibsrq.event_handler; @@ -199,7 +206,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only) wqe = get_rwqe_ptr(rq, tail); if (++tail >= rq->size) tail = 0; - } while (!wr_id_only && !init_sge(qp, wqe)); + } while (!wr_id_only && !ipath_init_sge(qp, wqe, &qp->r_len, + &qp->r_sge)); qp->r_wr_id = wqe->wr_id; wq->tail = tail; @@ -239,9 +247,9 @@ bail: /** * ipath_ruc_loopback - handle UC and RC lookback requests - * @sqp: the loopback QP + * @sqp: the sending QP * - * This is called from ipath_do_uc_send() or ipath_do_rc_send() to + * This is called from ipath_do_send() to * forward a WQE addressed to the same HCA. * Note that although we are single threaded due to the tasklet, we still * have to protect against post_send(). We don't have to worry about @@ -450,40 +458,18 @@ again: wc.byte_len = wqe->length; wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; - /* XXX do we know which pkey matched? Only needed for GSI. */ wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; wc.sl = qp->remote_ah_attr.sl; wc.dlid_path_bits = 0; + wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, wqe->wr.send_flags & IB_SEND_SOLICITED); send_comp: sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; - - if (!(sqp->s_flags & IPATH_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED)) { - wc.wr_id = wqe->wr.wr_id; - wc.status = IB_WC_SUCCESS; - wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; - wc.vendor_err = 0; - wc.byte_len = wqe->length; - wc.qp = &sqp->ibqp; - wc.src_qp = 0; - wc.pkey_index = 0; - wc.slid = 0; - wc.sl = 0; - wc.dlid_path_bits = 0; - wc.port_num = 0; - ipath_cq_enter(to_icq(sqp->ibqp.send_cq), &wc, 0); - } - - /* Update s_last now that we are finished with the SWQE */ - spin_lock_irqsave(&sqp->s_lock, flags); - if (++sqp->s_last >= sqp->s_size) - sqp->s_last = 0; - spin_unlock_irqrestore(&sqp->s_lock, flags); + ipath_send_complete(sqp, wqe, IB_WC_SUCCESS); goto again; done: @@ -491,13 +477,11 @@ done: wake_up(&qp->wait); } -static int want_buffer(struct ipath_devdata *dd) +static void want_buffer(struct ipath_devdata *dd) { set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - - return 0; } /** @@ -507,14 +491,11 @@ static int want_buffer(struct ipath_devdata *dd) * * Called when we run out of PIO buffers. */ -static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev) +static void ipath_no_bufs_available(struct ipath_qp *qp, + struct ipath_ibdev *dev) { unsigned long flags; - spin_lock_irqsave(&dev->pending_lock, flags); - if (list_empty(&qp->piowait)) - list_add_tail(&qp->piowait, &dev->piowait); - spin_unlock_irqrestore(&dev->pending_lock, flags); /* * Note that as soon as want_buffer() is called and * possibly before it returns, ipath_ib_piobufavail() @@ -524,100 +505,13 @@ static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev * We leave the busy flag set so that another post send doesn't * try to put the same QP on the piowait list again. */ + spin_lock_irqsave(&dev->pending_lock, flags); + list_add_tail(&qp->piowait, &dev->piowait); + spin_unlock_irqrestore(&dev->pending_lock, flags); want_buffer(dev->dd); dev->n_piowait++; } -/** - * ipath_post_ruc_send - post RC and UC sends - * @qp: the QP to post on - * @wr: the work request to send - */ -int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr) -{ - struct ipath_swqe *wqe; - unsigned long flags; - u32 next; - int i, j; - int acc; - int ret; - - /* - * Don't allow RDMA reads or atomic operations on UC or - * undefined operations. - * Make sure buffer is large enough to hold the result for atomics. - */ - if (qp->ibqp.qp_type == IB_QPT_UC) { - if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) { - ret = -EINVAL; - goto bail; - } - } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) { - ret = -EINVAL; - goto bail; - } else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP && - (wr->num_sge == 0 || - wr->sg_list[0].length < sizeof(u64) || - wr->sg_list[0].addr & (sizeof(u64) - 1))) { - ret = -EINVAL; - goto bail; - } else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) { - ret = -EINVAL; - goto bail; - } - /* IB spec says that num_sge == 0 is OK. */ - if (wr->num_sge > qp->s_max_sge) { - ret = -ENOMEM; - goto bail; - } - spin_lock_irqsave(&qp->s_lock, flags); - next = qp->s_head + 1; - if (next >= qp->s_size) - next = 0; - if (next == qp->s_last) { - spin_unlock_irqrestore(&qp->s_lock, flags); - ret = -EINVAL; - goto bail; - } - - wqe = get_swqe_ptr(qp, qp->s_head); - wqe->wr = *wr; - wqe->ssn = qp->s_ssn++; - wqe->sg_list[0].mr = NULL; - wqe->sg_list[0].vaddr = NULL; - wqe->sg_list[0].length = 0; - wqe->sg_list[0].sge_length = 0; - wqe->length = 0; - acc = wr->opcode >= IB_WR_RDMA_READ ? IB_ACCESS_LOCAL_WRITE : 0; - for (i = 0, j = 0; i < wr->num_sge; i++) { - if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) { - spin_unlock_irqrestore(&qp->s_lock, flags); - ret = -EINVAL; - goto bail; - } - if (wr->sg_list[i].length == 0) - continue; - if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i], - acc)) { - spin_unlock_irqrestore(&qp->s_lock, flags); - ret = -EINVAL; - goto bail; - } - wqe->length += wr->sg_list[i].length; - j++; - } - wqe->wr.num_sge = j; - qp->s_head = next; - spin_unlock_irqrestore(&qp->s_lock, flags); - - ipath_do_ruc_send((unsigned long) qp); - - ret = 0; - -bail: - return ret; -} - /** * ipath_make_grh - construct a GRH header * @dev: a pointer to the ipath device @@ -648,81 +542,16 @@ u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr, return sizeof(struct ib_grh) / sizeof(u32); } -/** - * ipath_do_ruc_send - perform a send on an RC or UC QP - * @data: contains a pointer to the QP - * - * Process entries in the send work queue until credit or queue is - * exhausted. Only allow one CPU to send a packet per QP (tasklet). - * Otherwise, after we drop the QP s_lock, two threads could send - * packets out of order. - */ -void ipath_do_ruc_send(unsigned long data) +void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp, + struct ipath_other_headers *ohdr, + u32 bth0, u32 bth2) { - struct ipath_qp *qp = (struct ipath_qp *)data; - struct ipath_ibdev *dev = to_idev(qp->ibqp.device); - unsigned long flags; u16 lrh0; u32 nwords; u32 extra_bytes; - u32 bth0; - u32 bth2; - u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); - struct ipath_other_headers *ohdr; - - if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy)) - goto bail; - - if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) { - ipath_ruc_loopback(qp); - goto clear; - } - - ohdr = &qp->s_hdr.u.oth; - if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) - ohdr = &qp->s_hdr.u.l.oth; - -again: - /* Check for a constructed packet to be sent. */ - if (qp->s_hdrwords != 0) { - /* - * If no PIO bufs are available, return. An interrupt will - * call ipath_ib_piobufavail() when one is available. - */ - if (ipath_verbs_send(dev->dd, qp->s_hdrwords, - (u32 *) &qp->s_hdr, qp->s_cur_size, - qp->s_cur_sge)) { - ipath_no_bufs_available(qp, dev); - goto bail; - } - dev->n_unicast_xmit++; - /* Record that we sent the packet and s_hdr is empty. */ - qp->s_hdrwords = 0; - } - - /* - * The lock is needed to synchronize between setting - * qp->s_ack_state, resend timer, and post_send(). - */ - spin_lock_irqsave(&qp->s_lock, flags); - - if (!((qp->ibqp.qp_type == IB_QPT_RC) ? - ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) : - ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) { - /* - * Clear the busy bit before unlocking to avoid races with - * adding new work queue items and then failing to process - * them. - */ - clear_bit(IPATH_S_BUSY, &qp->s_busy); - spin_unlock_irqrestore(&qp->s_lock, flags); - goto bail; - } - - spin_unlock_irqrestore(&qp->s_lock, flags); /* Construct the header. */ - extra_bytes = (4 - qp->s_cur_size) & 3; + extra_bytes = -qp->s_cur_size & 3; nwords = (qp->s_cur_size + extra_bytes) >> 2; lrh0 = IPATH_LRH_BTH; if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { @@ -734,20 +563,99 @@ again: lrh0 |= qp->remote_ah_attr.sl << 4; qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); - qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + - SIZE_OF_CRC); + qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC); qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid); bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index); bth0 |= extra_bytes << 20; - ohdr->bth[0] = cpu_to_be32(bth0); + ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22)); ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); ohdr->bth[2] = cpu_to_be32(bth2); +} - /* Check for more work to do. */ - goto again; +/** + * ipath_do_send - perform a send on a QP + * @data: contains a pointer to the QP + * + * Process entries in the send work queue until credit or queue is + * exhausted. Only allow one CPU to send a packet per QP (tasklet). + * Otherwise, two threads could send packets out of order. + */ +void ipath_do_send(unsigned long data) +{ + struct ipath_qp *qp = (struct ipath_qp *)data; + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + int (*make_req)(struct ipath_qp *qp); + if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy)) + goto bail; + + if ((qp->ibqp.qp_type == IB_QPT_RC || + qp->ibqp.qp_type == IB_QPT_UC) && + qp->remote_ah_attr.dlid == dev->dd->ipath_lid) { + ipath_ruc_loopback(qp); + goto clear; + } + + if (qp->ibqp.qp_type == IB_QPT_RC) + make_req = ipath_make_rc_req; + else if (qp->ibqp.qp_type == IB_QPT_UC) + make_req = ipath_make_uc_req; + else + make_req = ipath_make_ud_req; + +again: + /* Check for a constructed packet to be sent. */ + if (qp->s_hdrwords != 0) { + /* + * If no PIO bufs are available, return. An interrupt will + * call ipath_ib_piobufavail() when one is available. + */ + if (ipath_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords, + qp->s_cur_sge, qp->s_cur_size)) { + ipath_no_bufs_available(qp, dev); + goto bail; + } + dev->n_unicast_xmit++; + /* Record that we sent the packet and s_hdr is empty. */ + qp->s_hdrwords = 0; + } + + if (make_req(qp)) + goto again; clear: clear_bit(IPATH_S_BUSY, &qp->s_busy); -bail: - return; +bail:; +} + +void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe, + enum ib_wc_status status) +{ + u32 last = qp->s_last; + + if (++last == qp->s_size) + last = 0; + qp->s_last = last; + + /* See ch. 11.2.4.1 and 10.7.3.1 */ + if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || + (wqe->wr.send_flags & IB_SEND_SIGNALED) || + status != IB_WC_SUCCESS) { + struct ib_wc wc; + + wc.wr_id = wqe->wr.wr_id; + wc.status = status; + wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + wc.vendor_err = 0; + wc.byte_len = wqe->length; + wc.imm_data = 0; + wc.qp = &qp->ibqp; + wc.src_qp = 0; + wc.wc_flags = 0; + wc.pkey_index = 0; + wc.slid = 0; + wc.sl = 0; + wc.dlid_path_bits = 0; + wc.port_num = 0; + ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); + } } diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c index 8380fbc50d2c..767beb903c25 100644 --- a/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/drivers/infiniband/hw/ipath/ipath_uc.c @@ -37,72 +37,40 @@ /* cut down ridiculously long IB macro names */ #define OP(x) IB_OPCODE_UC_##x -static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe, - struct ib_wc *wc) -{ - if (++qp->s_last == qp->s_size) - qp->s_last = 0; - if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED)) { - wc->wr_id = wqe->wr.wr_id; - wc->status = IB_WC_SUCCESS; - wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; - wc->vendor_err = 0; - wc->byte_len = wqe->length; - wc->qp = &qp->ibqp; - wc->src_qp = qp->remote_qpn; - wc->pkey_index = 0; - wc->slid = qp->remote_ah_attr.dlid; - wc->sl = qp->remote_ah_attr.sl; - wc->dlid_path_bits = 0; - wc->port_num = 0; - ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 0); - } -} - /** * ipath_make_uc_req - construct a request packet (SEND, RDMA write) * @qp: a pointer to the QP - * @ohdr: a pointer to the IB header being constructed - * @pmtu: the path MTU - * @bth0p: pointer to the BTH opcode word - * @bth2p: pointer to the BTH PSN word * * Return 1 if constructed; otherwise, return 0. - * Note the QP s_lock must be held and interrupts disabled. */ -int ipath_make_uc_req(struct ipath_qp *qp, - struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p) +int ipath_make_uc_req(struct ipath_qp *qp) { + struct ipath_other_headers *ohdr; struct ipath_swqe *wqe; u32 hwords; u32 bth0; u32 len; - struct ib_wc wc; + u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); + int ret = 0; if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) goto done; + ohdr = &qp->s_hdr.u.oth; + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + ohdr = &qp->s_hdr.u.l.oth; + /* header size in 32-bit words LRH+BTH = (8+12)/4. */ hwords = 5; bth0 = 1 << 22; /* Set M bit */ /* Get the next send request. */ - wqe = get_swqe_ptr(qp, qp->s_last); + wqe = get_swqe_ptr(qp, qp->s_cur); + qp->s_wqe = NULL; switch (qp->s_state) { default: - /* - * Signal the completion of the last send - * (if there is one). - */ - if (qp->s_last != qp->s_tail) { - complete_last_send(qp, wqe, &wc); - wqe = get_swqe_ptr(qp, qp->s_last); - } - /* Check if send work queue is empty. */ - if (qp->s_tail == qp->s_head) + if (qp->s_cur == qp->s_head) goto done; /* * Start a new request. @@ -131,6 +99,9 @@ int ipath_make_uc_req(struct ipath_qp *qp, } if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; break; case IB_WR_RDMA_WRITE: @@ -157,13 +128,14 @@ int ipath_make_uc_req(struct ipath_qp *qp, if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; } + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; break; default: goto done; } - if (++qp->s_tail >= qp->s_size) - qp->s_tail = 0; break; case OP(SEND_FIRST): @@ -185,6 +157,9 @@ int ipath_make_uc_req(struct ipath_qp *qp, } if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; break; case OP(RDMA_WRITE_FIRST): @@ -207,18 +182,22 @@ int ipath_make_uc_req(struct ipath_qp *qp, if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; } + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; break; } qp->s_len -= len; qp->s_hdrwords = hwords; qp->s_cur_sge = &qp->s_sge; qp->s_cur_size = len; - *bth0p = bth0 | (qp->s_state << 24); - *bth2p = qp->s_next_psn++ & IPATH_PSN_MASK; - return 1; + ipath_make_ruc_header(to_idev(qp->ibqp.device), + qp, ohdr, bth0 | (qp->s_state << 24), + qp->s_next_psn++ & IPATH_PSN_MASK); + ret = 1; done: - return 0; + return ret; } /** diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index f9a3338a5fb7..34c4a0a5be31 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -36,68 +36,17 @@ #include "ipath_verbs.h" #include "ipath_kernel.h" -static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe, - u32 *lengthp, struct ipath_sge_state *ss) -{ - int user = to_ipd(qp->ibqp.pd)->user; - int i, j, ret; - struct ib_wc wc; - - *lengthp = 0; - for (i = j = 0; i < wqe->num_sge; i++) { - if (wqe->sg_list[i].length == 0) - continue; - /* Check LKEY */ - if ((user && wqe->sg_list[i].lkey == 0) || - !ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge, - &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE)) - goto bad_lkey; - *lengthp += wqe->sg_list[i].length; - j++; - } - ss->num_sge = j; - ret = 1; - goto bail; - -bad_lkey: - wc.wr_id = wqe->wr_id; - wc.status = IB_WC_LOC_PROT_ERR; - wc.opcode = IB_WC_RECV; - wc.vendor_err = 0; - wc.byte_len = 0; - wc.imm_data = 0; - wc.qp = &qp->ibqp; - wc.src_qp = 0; - wc.wc_flags = 0; - wc.pkey_index = 0; - wc.slid = 0; - wc.sl = 0; - wc.dlid_path_bits = 0; - wc.port_num = 0; - /* Signal solicited completion event. */ - ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); - ret = 0; -bail: - return ret; -} - /** * ipath_ud_loopback - handle send on loopback QPs - * @sqp: the QP - * @ss: the SGE state - * @length: the length of the data to send - * @wr: the work request - * @wc: the work completion entry + * @sqp: the sending QP + * @swqe: the send work request * - * This is called from ipath_post_ud_send() to forward a WQE addressed + * This is called from ipath_make_ud_req() to forward a WQE addressed * to the same HCA. * Note that the receive interrupt handler may be calling ipath_ud_rcv() * while this is being called. */ -static void ipath_ud_loopback(struct ipath_qp *sqp, - struct ipath_sge_state *ss, - u32 length, struct ib_send_wr *wr, - struct ib_wc *wc) +static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) { struct ipath_ibdev *dev = to_idev(sqp->ibqp.device); struct ipath_qp *qp; @@ -110,12 +59,18 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_rwq *wq; struct ipath_rwqe *wqe; void (*handler)(struct ib_event *, void *); + struct ib_wc wc; u32 tail; u32 rlen; + u32 length; - qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn); - if (!qp) - return; + qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn); + if (!qp) { + dev->n_pkt_drops++; + goto send_comp; + } + + rsge.sg_list = NULL; /* * Check that the qkey matches (except for QP0, see 9.6.1.4.1). @@ -123,39 +78,34 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, * qkey from the QP context instead of the WR (see 10.2.5). */ if (unlikely(qp->ibqp.qp_num && - ((int) wr->wr.ud.remote_qkey < 0 - ? qp->qkey : wr->wr.ud.remote_qkey) != qp->qkey)) { + ((int) swqe->wr.wr.ud.remote_qkey < 0 ? + sqp->qkey : swqe->wr.wr.ud.remote_qkey) != qp->qkey)) { /* XXX OK to lose a count once in a while. */ dev->qkey_violations++; dev->n_pkt_drops++; - goto done; + goto drop; } /* * A GRH is expected to preceed the data even if not * present on the wire. */ - wc->byte_len = length + sizeof(struct ib_grh); + length = swqe->length; + wc.byte_len = length + sizeof(struct ib_grh); - if (wr->opcode == IB_WR_SEND_WITH_IMM) { - wc->wc_flags = IB_WC_WITH_IMM; - wc->imm_data = wr->imm_data; + if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) { + wc.wc_flags = IB_WC_WITH_IMM; + wc.imm_data = swqe->wr.imm_data; } else { - wc->wc_flags = 0; - wc->imm_data = 0; + wc.wc_flags = 0; + wc.imm_data = 0; } - if (wr->num_sge > 1) { - rsge.sg_list = kmalloc((wr->num_sge - 1) * - sizeof(struct ipath_sge), - GFP_ATOMIC); - } else - rsge.sg_list = NULL; - /* - * Get the next work request entry to find where to put the data. - * Note that it is safe to drop the lock after changing rq->tail - * since ipath_post_receive() won't fill the empty slot. + * This would be a lot simpler if we could call ipath_get_rwqe() + * but that uses state that the receive interrupt handler uses + * so we would need to lock out receive interrupts while doing + * local loopback. */ if (qp->ibqp.srq) { srq = to_isrq(qp->ibqp.srq); @@ -167,32 +117,53 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, rq = &qp->r_rq; } + if (rq->max_sge > 1) { + /* + * XXX We could use GFP_KERNEL if ipath_do_send() + * was always called from the tasklet instead of + * from ipath_post_send(). + */ + rsge.sg_list = kmalloc((rq->max_sge - 1) * + sizeof(struct ipath_sge), + GFP_ATOMIC); + if (!rsge.sg_list) { + dev->n_pkt_drops++; + goto drop; + } + } + + /* + * Get the next work request entry to find where to put the data. + * Note that it is safe to drop the lock after changing rq->tail + * since ipath_post_receive() won't fill the empty slot. + */ spin_lock_irqsave(&rq->lock, flags); wq = rq->wq; tail = wq->tail; - while (1) { - if (unlikely(tail == wq->head)) { - spin_unlock_irqrestore(&rq->lock, flags); - dev->n_pkt_drops++; - goto bail_sge; - } - /* Make sure entry is read after head index is read. */ - smp_rmb(); - wqe = get_rwqe_ptr(rq, tail); - if (++tail >= rq->size) - tail = 0; - if (init_sge(qp, wqe, &rlen, &rsge)) - break; - wq->tail = tail; - } - /* Silently drop packets which are too big. */ - if (wc->byte_len > rlen) { + /* Validate tail before using it since it is user writable. */ + if (tail >= rq->size) + tail = 0; + if (unlikely(tail == wq->head)) { spin_unlock_irqrestore(&rq->lock, flags); dev->n_pkt_drops++; - goto bail_sge; + goto drop; } + wqe = get_rwqe_ptr(rq, tail); + if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) { + spin_unlock_irqrestore(&rq->lock, flags); + dev->n_pkt_drops++; + goto drop; + } + /* Silently drop packets which are too big. */ + if (wc.byte_len > rlen) { + spin_unlock_irqrestore(&rq->lock, flags); + dev->n_pkt_drops++; + goto drop; + } + if (++tail >= rq->size) + tail = 0; wq->tail = tail; - wc->wr_id = wqe->wr_id; + wc.wr_id = wqe->wr_id; if (handler) { u32 n; @@ -221,13 +192,13 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, } else spin_unlock_irqrestore(&rq->lock, flags); - ah_attr = &to_iah(wr->wr.ud.ah)->attr; + ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr; if (ah_attr->ah_flags & IB_AH_GRH) { ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh)); - wc->wc_flags |= IB_WC_GRH; + wc.wc_flags |= IB_WC_GRH; } else ipath_skip_sge(&rsge, sizeof(struct ib_grh)); - sge = &ss->sge; + sge = swqe->sg_list; while (length) { u32 len = sge->length; @@ -241,8 +212,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, sge->length -= len; sge->sge_length -= len; if (sge->sge_length == 0) { - if (--ss->num_sge) - *sge = *ss->sg_list++; + if (--swqe->wr.num_sge) + sge++; } else if (sge->length == 0 && sge->mr != NULL) { if (++sge->n >= IPATH_SEGSZ) { if (++sge->m >= sge->mr->mapsz) @@ -256,123 +227,60 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, } length -= len; } - wc->status = IB_WC_SUCCESS; - wc->opcode = IB_WC_RECV; - wc->vendor_err = 0; - wc->qp = &qp->ibqp; - wc->src_qp = sqp->ibqp.qp_num; + wc.status = IB_WC_SUCCESS; + wc.opcode = IB_WC_RECV; + wc.vendor_err = 0; + wc.qp = &qp->ibqp; + wc.src_qp = sqp->ibqp.qp_num; /* XXX do we know which pkey matched? Only needed for GSI. */ - wc->pkey_index = 0; - wc->slid = dev->dd->ipath_lid | + wc.pkey_index = 0; + wc.slid = dev->dd->ipath_lid | (ah_attr->src_path_bits & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1)); - wc->sl = ah_attr->sl; - wc->dlid_path_bits = + wc.sl = ah_attr->sl; + wc.dlid_path_bits = ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ - ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc, - wr->send_flags & IB_SEND_SOLICITED); - -bail_sge: + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + swqe->wr.send_flags & IB_SEND_SOLICITED); +drop: kfree(rsge.sg_list); -done: if (atomic_dec_and_test(&qp->refcount)) wake_up(&qp->wait); +send_comp: + ipath_send_complete(sqp, swqe, IB_WC_SUCCESS); } /** - * ipath_post_ud_send - post a UD send on QP + * ipath_make_ud_req - construct a UD request packet * @qp: the QP - * @wr: the work request * - * Note that we actually send the data as it is posted instead of putting - * the request into a ring buffer. If we wanted to use a ring buffer, - * we would need to save a reference to the destination address in the SWQE. + * Return 1 if constructed; otherwise, return 0. */ -int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) +int ipath_make_ud_req(struct ipath_qp *qp) { struct ipath_ibdev *dev = to_idev(qp->ibqp.device); struct ipath_other_headers *ohdr; struct ib_ah_attr *ah_attr; - struct ipath_sge_state ss; - struct ipath_sge *sg_list; - struct ib_wc wc; - u32 hwords; + struct ipath_swqe *wqe; u32 nwords; - u32 len; u32 extra_bytes; u32 bth0; u16 lrh0; u16 lid; - int i; - int ret; + int ret = 0; - if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) { - ret = 0; + if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))) goto bail; - } - if (wr->wr.ud.ah->pd != qp->ibqp.pd) { - ret = -EPERM; + if (qp->s_cur == qp->s_head) goto bail; - } - /* IB spec says that num_sge == 0 is OK. */ - if (wr->num_sge > qp->s_max_sge) { - ret = -EINVAL; - goto bail; - } - - if (wr->num_sge > 1) { - sg_list = kmalloc((qp->s_max_sge - 1) * sizeof(*sg_list), - GFP_ATOMIC); - if (!sg_list) { - ret = -ENOMEM; - goto bail; - } - } else - sg_list = NULL; - - /* Check the buffer to send. */ - ss.sg_list = sg_list; - ss.sge.mr = NULL; - ss.sge.vaddr = NULL; - ss.sge.length = 0; - ss.sge.sge_length = 0; - ss.num_sge = 0; - len = 0; - for (i = 0; i < wr->num_sge; i++) { - /* Check LKEY */ - if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) { - ret = -EINVAL; - goto bail; - } - - if (wr->sg_list[i].length == 0) - continue; - if (!ipath_lkey_ok(qp, ss.num_sge ? - sg_list + ss.num_sge - 1 : &ss.sge, - &wr->sg_list[i], 0)) { - ret = -EINVAL; - goto bail; - } - len += wr->sg_list[i].length; - ss.num_sge++; - } - /* Check for invalid packet size. */ - if (len > dev->dd->ipath_ibmtu) { - ret = -EINVAL; - goto bail; - } - extra_bytes = (4 - len) & 3; - nwords = (len + extra_bytes) >> 2; + wqe = get_swqe_ptr(qp, qp->s_cur); /* Construct the header. */ - ah_attr = &to_iah(wr->wr.ud.ah)->attr; - if (ah_attr->dlid == 0) { - ret = -EINVAL; - goto bail; - } + ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr; if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) { if (ah_attr->dlid != IPATH_PERMISSIVE_LID) dev->n_multicast_xmit++; @@ -383,64 +291,53 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) lid = ah_attr->dlid & ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); if (unlikely(lid == dev->dd->ipath_lid)) { - /* - * Pass in an uninitialized ib_wc to save stack - * space. - */ - ipath_ud_loopback(qp, &ss, len, wr, &wc); + ipath_ud_loopback(qp, wqe); goto done; } } + + extra_bytes = -wqe->length & 3; + nwords = (wqe->length + extra_bytes) >> 2; + + /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */ + qp->s_hdrwords = 7; + if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) + qp->s_hdrwords++; + qp->s_cur_size = wqe->length; + qp->s_cur_sge = &qp->s_sge; + qp->s_wqe = wqe; + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + if (ah_attr->ah_flags & IB_AH_GRH) { /* Header size in 32-bit words. */ - hwords = 17; + qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh, + &ah_attr->grh, + qp->s_hdrwords, nwords); lrh0 = IPATH_LRH_GRH; ohdr = &qp->s_hdr.u.l.oth; - qp->s_hdr.u.l.grh.version_tclass_flow = - cpu_to_be32((6 << 28) | - (ah_attr->grh.traffic_class << 20) | - ah_attr->grh.flow_label); - qp->s_hdr.u.l.grh.paylen = - cpu_to_be16(((wr->opcode == - IB_WR_SEND_WITH_IMM ? 6 : 5) + - nwords + SIZE_OF_CRC) << 2); - /* next_hdr is defined by C8-7 in ch. 8.4.1 */ - qp->s_hdr.u.l.grh.next_hdr = 0x1B; - qp->s_hdr.u.l.grh.hop_limit = ah_attr->grh.hop_limit; - /* The SGID is 32-bit aligned. */ - qp->s_hdr.u.l.grh.sgid.global.subnet_prefix = - dev->gid_prefix; - qp->s_hdr.u.l.grh.sgid.global.interface_id = - dev->dd->ipath_guid; - qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid; /* * Don't worry about sending to locally attached multicast * QPs. It is unspecified by the spec. what happens. */ } else { /* Header size in 32-bit words. */ - hwords = 7; lrh0 = IPATH_LRH_BTH; ohdr = &qp->s_hdr.u.oth; } - if (wr->opcode == IB_WR_SEND_WITH_IMM) { - ohdr->u.ud.imm_data = wr->imm_data; - wc.imm_data = wr->imm_data; - hwords += 1; + if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) { + ohdr->u.ud.imm_data = wqe->wr.imm_data; bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24; - } else if (wr->opcode == IB_WR_SEND) { - wc.imm_data = 0; + } else bth0 = IB_OPCODE_UD_SEND_ONLY << 24; - } else { - ret = -EINVAL; - goto bail; - } lrh0 |= ah_attr->sl << 4; if (qp->ibqp.qp_type == IB_QPT_SMI) lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */ qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */ - qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC); + qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + + SIZE_OF_CRC); lid = dev->dd->ipath_lid; if (lid) { lid |= ah_attr->src_path_bits & @@ -448,7 +345,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) qp->s_hdr.lrh[3] = cpu_to_be16(lid); } else qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE; - if (wr->send_flags & IB_SEND_SOLICITED) + if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; bth0 |= extra_bytes << 20; bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY : @@ -460,38 +357,20 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE && ah_attr->dlid != IPATH_PERMISSIVE_LID ? __constant_cpu_to_be32(IPATH_MULTICAST_QPN) : - cpu_to_be32(wr->wr.ud.remote_qpn); - /* XXX Could lose a PSN count but not worth locking */ + cpu_to_be32(wqe->wr.wr.ud.remote_qpn); ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK); /* * Qkeys with the high order bit set mean use the * qkey from the QP context instead of the WR (see 10.2.5). */ - ohdr->u.ud.deth[0] = cpu_to_be32((int)wr->wr.ud.remote_qkey < 0 ? - qp->qkey : wr->wr.ud.remote_qkey); + ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ? + qp->qkey : wqe->wr.wr.ud.remote_qkey); ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num); - if (ipath_verbs_send(dev->dd, hwords, (u32 *) &qp->s_hdr, - len, &ss)) - dev->n_no_piobuf++; done: - /* Queue the completion status entry. */ - if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || - (wr->send_flags & IB_SEND_SIGNALED)) { - wc.wr_id = wr->wr_id; - wc.status = IB_WC_SUCCESS; - wc.vendor_err = 0; - wc.opcode = IB_WC_SEND; - wc.byte_len = len; - wc.qp = &qp->ibqp; - wc.src_qp = 0; - wc.wc_flags = 0; - /* XXX initialize other fields? */ - ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); - } - kfree(sg_list); - - ret = 0; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; + ret = 1; bail: return ret; @@ -673,6 +552,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, */ wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 : dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, (ohdr->bth[0] & diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 559d4a662937..3cc82b62b3c5 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -230,6 +230,103 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length) } } +/** + * ipath_post_one_send - post one RC, UC, or UD send work request + * @qp: the QP to post on + * @wr: the work request to send + */ +static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr) +{ + struct ipath_swqe *wqe; + u32 next; + int i; + int j; + int acc; + int ret; + unsigned long flags; + + spin_lock_irqsave(&qp->s_lock, flags); + + /* Check that state is OK to post send. */ + if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) + goto bail_inval; + + /* IB spec says that num_sge == 0 is OK. */ + if (wr->num_sge > qp->s_max_sge) + goto bail_inval; + + /* + * Don't allow RDMA reads or atomic operations on UC or + * undefined operations. + * Make sure buffer is large enough to hold the result for atomics. + */ + if (qp->ibqp.qp_type == IB_QPT_UC) { + if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) + goto bail_inval; + } else if (qp->ibqp.qp_type == IB_QPT_UD) { + /* Check UD opcode */ + if (wr->opcode != IB_WR_SEND && + wr->opcode != IB_WR_SEND_WITH_IMM) + goto bail_inval; + /* Check UD destination address PD */ + if (qp->ibqp.pd != wr->wr.ud.ah->pd) + goto bail_inval; + } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) + goto bail_inval; + else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP && + (wr->num_sge == 0 || + wr->sg_list[0].length < sizeof(u64) || + wr->sg_list[0].addr & (sizeof(u64) - 1))) + goto bail_inval; + else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) + goto bail_inval; + + next = qp->s_head + 1; + if (next >= qp->s_size) + next = 0; + if (next == qp->s_last) + goto bail_inval; + + wqe = get_swqe_ptr(qp, qp->s_head); + wqe->wr = *wr; + wqe->ssn = qp->s_ssn++; + wqe->length = 0; + if (wr->num_sge) { + acc = wr->opcode >= IB_WR_RDMA_READ ? + IB_ACCESS_LOCAL_WRITE : 0; + for (i = 0, j = 0; i < wr->num_sge; i++) { + u32 length = wr->sg_list[i].length; + int ok; + + if (length == 0) + continue; + ok = ipath_lkey_ok(qp, &wqe->sg_list[j], + &wr->sg_list[i], acc); + if (!ok) + goto bail_inval; + wqe->length += length; + j++; + } + wqe->wr.num_sge = j; + } + if (qp->ibqp.qp_type == IB_QPT_UC || + qp->ibqp.qp_type == IB_QPT_RC) { + if (wqe->length > 0x80000000U) + goto bail_inval; + } else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu) + goto bail_inval; + qp->s_head = next; + + ret = 0; + goto bail; + +bail_inval: + ret = -EINVAL; +bail: + spin_unlock_irqrestore(&qp->s_lock, flags); + return ret; +} + /** * ipath_post_send - post a send on a QP * @ibqp: the QP to post the send on @@ -244,35 +341,17 @@ static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ipath_qp *qp = to_iqp(ibqp); int err = 0; - /* Check that state is OK to post send. */ - if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) { - *bad_wr = wr; - err = -EINVAL; - goto bail; - } - for (; wr; wr = wr->next) { - switch (qp->ibqp.qp_type) { - case IB_QPT_UC: - case IB_QPT_RC: - err = ipath_post_ruc_send(qp, wr); - break; - - case IB_QPT_SMI: - case IB_QPT_GSI: - case IB_QPT_UD: - err = ipath_post_ud_send(qp, wr); - break; - - default: - err = -EINVAL; - } + err = ipath_post_one_send(qp, wr); if (err) { *bad_wr = wr; - break; + goto bail; } } + /* Try to do the send work in the caller's context. */ + ipath_do_send((unsigned long) qp); + bail: return err; } @@ -641,11 +720,11 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, u32 len = ss->sge.length; u32 off; - BUG_ON(len == 0); if (len > length) len = length; if (len > ss->sge.sge_length) len = ss->sge.sge_length; + BUG_ON(len == 0); /* If the source address is not aligned, try to align it. */ off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1); if (off) { @@ -767,30 +846,15 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, __raw_writel(last, piobuf); } -/** - * ipath_verbs_send - send a packet - * @dd: the infinipath device - * @hdrwords: the number of words in the header - * @hdr: the packet header - * @len: the length of the packet in bytes - * @ss: the SGE to send - */ -int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, - u32 *hdr, u32 len, struct ipath_sge_state *ss) +static int ipath_verbs_send_pio(struct ipath_qp *qp, u32 *hdr, u32 hdrwords, + struct ipath_sge_state *ss, u32 len, + u32 plen, u32 dwords) { + struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd; u32 __iomem *piobuf; unsigned flush_wc; - u32 plen; int ret; - /* +1 is for the qword padding of pbc */ - plen = hdrwords + ((len + 3) >> 2) + 1; - if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) { - ret = -EINVAL; - goto bail; - } - - /* Get a PIO buffer to use. */ piobuf = ipath_getpiobuf(dd, NULL); if (unlikely(piobuf == NULL)) { ret = -EBUSY; @@ -831,13 +895,10 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, /* The common case is aligned and contained in one segment. */ if (likely(ss->num_sge == 1 && len <= ss->sge.length && !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) { - u32 dwords; u32 *addr = (u32 *) ss->sge.vaddr; /* Update address before sending packet. */ update_sge(ss, len); - /* Need to round up for the last dword in the packet. */ - dwords = (len + 3) >> 2; if (flush_wc) { __iowrite32_copy(piobuf, addr, dwords - 1); /* must flush early everything before trigger word */ @@ -851,11 +912,37 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, } copy_io(piobuf, ss, len, flush_wc); done: + if (qp->s_wqe) + ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS); ret = 0; bail: return ret; } +/** + * ipath_verbs_send - send a packet + * @qp: the QP to send on + * @hdr: the packet header + * @hdrwords: the number of words in the header + * @ss: the SGE to send + * @len: the length of the packet in bytes + */ +int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, + u32 hdrwords, struct ipath_sge_state *ss, u32 len) +{ + u32 plen; + int ret; + u32 dwords = (len + 3) >> 2; + + /* +1 is for the qword padding of pbc */ + plen = hdrwords + dwords + 1; + + ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords, + ss, len, plen, dwords); + + return ret; +} + int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords, u64 *rwords, u64 *spkts, u64 *rpkts, u64 *xmit_wait) @@ -864,7 +951,6 @@ int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords, if (!(dd->ipath_flags & IPATH_INITTED)) { /* no hardware, freeze, etc. */ - ipath_dbg("unit %u not usable\n", dd->ipath_unit); ret = -EINVAL; goto bail; } @@ -890,48 +976,44 @@ bail: int ipath_get_counters(struct ipath_devdata *dd, struct ipath_verbs_counters *cntrs) { + struct ipath_cregs const *crp = dd->ipath_cregs; int ret; if (!(dd->ipath_flags & IPATH_INITTED)) { /* no hardware, freeze, etc. */ - ipath_dbg("unit %u not usable\n", dd->ipath_unit); ret = -EINVAL; goto bail; } cntrs->symbol_error_counter = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt); + ipath_snap_cntr(dd, crp->cr_ibsymbolerrcnt); cntrs->link_error_recovery_counter = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt); + ipath_snap_cntr(dd, crp->cr_iblinkerrrecovcnt); /* * The link downed counter counts when the other side downs the * connection. We add in the number of times we downed the link * due to local link integrity errors to compensate. */ cntrs->link_downed_counter = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt); + ipath_snap_cntr(dd, crp->cr_iblinkdowncnt); cntrs->port_rcv_errors = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) + + ipath_snap_cntr(dd, crp->cr_rxdroppktcnt) + + ipath_snap_cntr(dd, crp->cr_rcvovflcnt) + + ipath_snap_cntr(dd, crp->cr_portovflcnt) + + ipath_snap_cntr(dd, crp->cr_err_rlencnt) + + ipath_snap_cntr(dd, crp->cr_invalidrlencnt) + + ipath_snap_cntr(dd, crp->cr_errlinkcnt) + + ipath_snap_cntr(dd, crp->cr_erricrccnt) + + ipath_snap_cntr(dd, crp->cr_errvcrccnt) + + ipath_snap_cntr(dd, crp->cr_errlpcrccnt) + + ipath_snap_cntr(dd, crp->cr_badformatcnt) + dd->ipath_rxfc_unsupvl_errs; cntrs->port_rcv_remphys_errors = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt); - cntrs->port_xmit_discards = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt); - cntrs->port_xmit_data = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); - cntrs->port_rcv_data = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); - cntrs->port_xmit_packets = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); - cntrs->port_rcv_packets = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); + ipath_snap_cntr(dd, crp->cr_rcvebpcnt); + cntrs->port_xmit_discards = ipath_snap_cntr(dd, crp->cr_unsupvlcnt); + cntrs->port_xmit_data = ipath_snap_cntr(dd, crp->cr_wordsendcnt); + cntrs->port_rcv_data = ipath_snap_cntr(dd, crp->cr_wordrcvcnt); + cntrs->port_xmit_packets = ipath_snap_cntr(dd, crp->cr_pktsendcnt); + cntrs->port_rcv_packets = ipath_snap_cntr(dd, crp->cr_pktrcvcnt); cntrs->local_link_integrity_errors = (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ? dd->ipath_lli_errs : dd->ipath_lli_errors; @@ -1045,8 +1127,9 @@ static int ipath_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props) { struct ipath_ibdev *dev = to_idev(ibdev); + struct ipath_devdata *dd = dev->dd; enum ib_mtu mtu; - u16 lid = dev->dd->ipath_lid; + u16 lid = dd->ipath_lid; u64 ibcstat; memset(props, 0, sizeof(*props)); @@ -1054,16 +1137,16 @@ static int ipath_query_port(struct ib_device *ibdev, props->lmc = dev->mkeyprot_resv_lmc & 7; props->sm_lid = dev->sm_lid; props->sm_sl = dev->sm_sl; - ibcstat = dev->dd->ipath_lastibcstat; + ibcstat = dd->ipath_lastibcstat; props->state = ((ibcstat >> 4) & 0x3) + 1; /* See phys_state_show() */ props->phys_state = ipath_cvt_physportstate[ - dev->dd->ipath_lastibcstat & 0xf]; + dd->ipath_lastibcstat & 0xf]; props->port_cap_flags = dev->port_cap_flags; props->gid_tbl_len = 1; props->max_msg_sz = 0x80000000; - props->pkey_tbl_len = ipath_get_npkeys(dev->dd); - props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) - + props->pkey_tbl_len = ipath_get_npkeys(dd); + props->bad_pkey_cntr = ipath_get_cr_errpkey(dd) - dev->z_pkey_violations; props->qkey_viol_cntr = dev->qkey_violations; props->active_width = IB_WIDTH_4X; @@ -1073,12 +1156,12 @@ static int ipath_query_port(struct ib_device *ibdev, props->init_type_reply = 0; /* - * Note: the chips support a maximum MTU of 4096, but the driver + * Note: the chip supports a maximum MTU of 4096, but the driver * hasn't implemented this feature yet, so set the maximum value * to 2048. */ props->max_mtu = IB_MTU_2048; - switch (dev->dd->ipath_ibmtu) { + switch (dd->ipath_ibmtu) { case 4096: mtu = IB_MTU_4096; break; @@ -1427,9 +1510,7 @@ static int disable_timer(struct ipath_devdata *dd) { /* Disable GPIO bit 2 interrupt */ if (dd->ipath_flags & IPATH_GPIO_INTR) { - u64 val; /* Disable GPIO bit 2 interrupt */ - val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask); dd->ipath_gpio_mask &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT)); ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, dd->ipath_gpio_mask); diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 1a24c6a4a814..619ad728b07b 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -42,6 +42,8 @@ #include #include +#include "ipath_kernel.h" + #define IPATH_MAX_RDMA_ATOMIC 4 #define QPN_MAX (1 << 24) @@ -59,6 +61,7 @@ */ #define IB_CQ_NONE (IB_CQ_NEXT_COMP + 1) +/* AETH NAK opcode values */ #define IB_RNR_NAK 0x20 #define IB_NAK_PSN_ERROR 0x60 #define IB_NAK_INVALID_REQUEST 0x61 @@ -66,6 +69,7 @@ #define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63 #define IB_NAK_INVALID_RD_REQUEST 0x64 +/* Flags for checking QP state (see ib_ipath_state_ops[]) */ #define IPATH_POST_SEND_OK 0x01 #define IPATH_POST_RECV_OK 0x02 #define IPATH_PROCESS_RECV_OK 0x04 @@ -239,7 +243,7 @@ struct ipath_mregion { */ struct ipath_sge { struct ipath_mregion *mr; - void *vaddr; /* current pointer into the segment */ + void *vaddr; /* kernel virtual address of segment */ u32 sge_length; /* length of the SGE */ u32 length; /* remaining length of the segment */ u16 m; /* current index: mr->map[m] */ @@ -407,6 +411,7 @@ struct ipath_qp { u32 s_ssn; /* SSN of tail entry */ u32 s_lsn; /* limit sequence number (credit) */ struct ipath_swqe *s_wq; /* send work queue */ + struct ipath_swqe *s_wqe; struct ipath_rq r_rq; /* receive work queue */ struct ipath_sge r_sg_list[0]; /* verified SGEs */ }; @@ -683,8 +688,8 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc); void ipath_get_credit(struct ipath_qp *qp, u32 aeth); -int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, - u32 *hdr, u32 len, struct ipath_sge_state *ss); +int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, + u32 hdrwords, struct ipath_sge_state *ss, u32 len); void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); @@ -692,8 +697,6 @@ void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length); void ipath_skip_sge(struct ipath_sge_state *ss, u32 length); -int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr); - void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, int has_grh, void *data, u32 tlen, struct ipath_qp *qp); @@ -733,6 +736,8 @@ int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr); int ipath_destroy_srq(struct ib_srq *ibsrq); +void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); + int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector, @@ -782,18 +787,28 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); void ipath_insert_rnr_queue(struct ipath_qp *qp); +int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe, + u32 *lengthp, struct ipath_sge_state *ss); + int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only); u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr, struct ib_global_route *grh, u32 hwords, u32 nwords); -void ipath_do_ruc_send(unsigned long data); +void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp, + struct ipath_other_headers *ohdr, + u32 bth0, u32 bth2); -int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p); +void ipath_do_send(unsigned long data); -int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p); +void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe, + enum ib_wc_status status); + +int ipath_make_rc_req(struct ipath_qp *qp); + +int ipath_make_uc_req(struct ipath_qp *qp); + +int ipath_make_ud_req(struct ipath_qp *qp); int ipath_register_ib_device(struct ipath_devdata *); From 9bec3992312b8bb3aee71bd3b57d106a0a649479 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Fri, 1 Jun 2007 13:01:47 -0700 Subject: [PATCH 0883/2804] IB/ipath: Verify host bus bandwidth to chip will not limit performance There have been a number of issues where host bandwidth via HT or PCIe to the InfiniPath chip has been limited in some fashion (BIOS, configuration, etc.), resulting in user confusion. This check gives a clear warning that something is wrong and needs to be resolved. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_driver.c | 86 ++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 6ccba365a24c..5248f57fe198 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,89 @@ void __attribute__((weak)) ipath_disable_wc(struct ipath_devdata *dd) { } +/* + * Perform a PIO buffer bandwidth write test, to verify proper system + * configuration. Even when all the setup calls work, occasionally + * BIOS or other issues can prevent write combining from working, or + * can cause other bandwidth problems to the chip. + * + * This test simply writes the same buffer over and over again, and + * measures close to the peak bandwidth to the chip (not testing + * data bandwidth to the wire). On chips that use an address-based + * trigger to send packets to the wire, this is easy. On chips that + * use a count to trigger, we want to make sure that the packet doesn't + * go out on the wire, or trigger flow control checks. + */ +static void ipath_verify_pioperf(struct ipath_devdata *dd) +{ + u32 pbnum, cnt, lcnt; + u32 __iomem *piobuf; + u32 *addr; + u64 msecs, emsecs; + + piobuf = ipath_getpiobuf(dd, &pbnum); + if (!piobuf) { + dev_info(&dd->pcidev->dev, + "No PIObufs for checking perf, skipping\n"); + return; + } + + /* + * Enough to give us a reasonable test, less than piobuf size, and + * likely multiple of store buffer length. + */ + cnt = 1024; + + addr = vmalloc(cnt); + if (!addr) { + dev_info(&dd->pcidev->dev, + "Couldn't get memory for checking PIO perf," + " skipping\n"); + goto done; + } + + preempt_disable(); /* we want reasonably accurate elapsed time */ + msecs = 1 + jiffies_to_msecs(jiffies); + for (lcnt = 0; lcnt < 10000U; lcnt++) { + /* wait until we cross msec boundary */ + if (jiffies_to_msecs(jiffies) >= msecs) + break; + udelay(1); + } + + writeq(0, piobuf); /* length 0, no dwords actually sent */ + ipath_flush_wc(); + + /* + * this is only roughly accurate, since even with preempt we + * still take interrupts that could take a while. Running for + * >= 5 msec seems to get us "close enough" to accurate values + */ + msecs = jiffies_to_msecs(jiffies); + for (emsecs = lcnt = 0; emsecs <= 5UL; lcnt++) { + __iowrite32_copy(piobuf + 64, addr, cnt >> 2); + emsecs = jiffies_to_msecs(jiffies) - msecs; + } + + /* 1 GiB/sec, slightly over IB SDR line rate */ + if (lcnt < (emsecs * 1024U)) + ipath_dev_err(dd, + "Performance problem: bandwidth to PIO buffers is " + "only %u MiB/sec\n", + lcnt / (u32) emsecs); + else + ipath_dbg("PIO buffer bandwidth %u MiB/sec is OK\n", + lcnt / (u32) emsecs); + + preempt_enable(); + + vfree(addr); + +done: + /* disarm piobuf, so it's available again */ + ipath_disarm_piobufs(dd, pbnum, 1); +} + static int __devinit ipath_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -515,6 +599,8 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, ret = 0; } + ipath_verify_pioperf(dd); + ipath_device_create_group(&pdev->dev, dd); ipathfs_add_device(dd); ipath_user_add(dd); From 1793b4771d258c93ed86a6356c95cac418781fdd Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Tue, 7 Aug 2007 18:09:34 -0700 Subject: [PATCH 0884/2804] IB/ipath: Remove unneeded code for ipathfs The ipathfs file system is used to export binary data verses ASCII data such as through /sys. This patch removes some unneeded files since the data is available through other /sys files. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_fs.c | 187 ------------------------- 1 file changed, 187 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 2e689b974e1f..262c25db05cd 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -130,175 +130,6 @@ static const struct file_operations atomic_counters_ops = { .read = atomic_counters_read, }; -static ssize_t atomic_node_info_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - u32 nodeinfo[10]; - struct ipath_devdata *dd; - u64 guid; - - dd = file->f_path.dentry->d_inode->i_private; - - guid = be64_to_cpu(dd->ipath_guid); - - nodeinfo[0] = /* BaseVersion is SMA */ - /* ClassVersion is SMA */ - (1 << 8) /* NodeType */ - | (1 << 0); /* NumPorts */ - nodeinfo[1] = (u32) (guid >> 32); - nodeinfo[2] = (u32) (guid & 0xffffffff); - /* PortGUID == SystemImageGUID for us */ - nodeinfo[3] = nodeinfo[1]; - /* PortGUID == SystemImageGUID for us */ - nodeinfo[4] = nodeinfo[2]; - /* PortGUID == NodeGUID for us */ - nodeinfo[5] = nodeinfo[3]; - /* PortGUID == NodeGUID for us */ - nodeinfo[6] = nodeinfo[4]; - nodeinfo[7] = (4 << 16) /* we support 4 pkeys */ - | (dd->ipath_deviceid << 0); - /* our chip version as 16 bits major, 16 bits minor */ - nodeinfo[8] = dd->ipath_minrev | (dd->ipath_majrev << 16); - nodeinfo[9] = (dd->ipath_unit << 24) | (dd->ipath_vendorid << 0); - - return simple_read_from_buffer(buf, count, ppos, nodeinfo, - sizeof nodeinfo); -} - -static const struct file_operations atomic_node_info_ops = { - .read = atomic_node_info_read, -}; - -static ssize_t atomic_port_info_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - u32 portinfo[13]; - u32 tmp, tmp2; - struct ipath_devdata *dd; - - dd = file->f_path.dentry->d_inode->i_private; - - /* so we only initialize non-zero fields. */ - memset(portinfo, 0, sizeof portinfo); - - /* - * Notimpl yet M_Key (64) - * Notimpl yet GID (64) - */ - - portinfo[4] = (dd->ipath_lid << 16); - - /* - * Notimpl yet SMLID. - * CapabilityMask is 0, we don't support any of these - * DiagCode is 0; we don't store any diag info for now Notimpl yet - * M_KeyLeasePeriod (we don't support M_Key) - */ - - /* LocalPortNum is whichever port number they ask for */ - portinfo[7] = (dd->ipath_unit << 24) - /* LinkWidthEnabled */ - | (2 << 16) - /* LinkWidthSupported (really 2, but not IB valid) */ - | (3 << 8) - /* LinkWidthActive */ - | (2 << 0); - tmp = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK; - tmp2 = 5; - if (tmp == IPATH_IBSTATE_INIT) - tmp = 2; - else if (tmp == IPATH_IBSTATE_ARM) - tmp = 3; - else if (tmp == IPATH_IBSTATE_ACTIVE) - tmp = 4; - else { - tmp = 0; /* down */ - tmp2 = tmp & 0xf; - } - - portinfo[8] = (1 << 28) /* LinkSpeedSupported */ - | (tmp << 24) /* PortState */ - | (tmp2 << 20) /* PortPhysicalState */ - | (2 << 16) - - /* LinkDownDefaultState */ - /* M_KeyProtectBits == 0 */ - /* NotImpl yet LMC == 0 (we can support all values) */ - | (1 << 4) /* LinkSpeedActive */ - | (1 << 0); /* LinkSpeedEnabled */ - switch (dd->ipath_ibmtu) { - case 4096: - tmp = 5; - break; - case 2048: - tmp = 4; - break; - case 1024: - tmp = 3; - break; - case 512: - tmp = 2; - break; - case 256: - tmp = 1; - break; - default: /* oops, something is wrong */ - ipath_dbg("Problem, ipath_ibmtu 0x%x not a valid IB MTU, " - "treat as 2048\n", dd->ipath_ibmtu); - tmp = 4; - break; - } - portinfo[9] = (tmp << 28) - /* NeighborMTU */ - /* Notimpl MasterSMSL */ - | (1 << 20) - - /* VLCap */ - /* Notimpl InitType (actually, an SMA decision) */ - /* VLHighLimit is 0 (only one VL) */ - ; /* VLArbitrationHighCap is 0 (only one VL) */ - /* - * Note: the chips support a maximum MTU of 4096, but the driver - * hasn't implemented this feature yet, so set the maximum - * to 2048. - */ - portinfo[10] = /* VLArbitrationLowCap is 0 (only one VL) */ - /* InitTypeReply is SMA decision */ - (4 << 16) /* MTUCap 2048 */ - | (7 << 13) /* VLStallCount */ - | (0x1f << 8) /* HOQLife */ - | (1 << 4) - - /* OperationalVLs 0 */ - /* PartitionEnforcementInbound */ - /* PartitionEnforcementOutbound not enforced */ - /* FilterRawinbound not enforced */ - ; /* FilterRawOutbound not enforced */ - /* M_KeyViolations are not counted by hardware, SMA can count */ - tmp = ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey); - /* P_KeyViolations are counted by hardware. */ - portinfo[11] = ((tmp & 0xffff) << 0); - portinfo[12] = - /* Q_KeyViolations are not counted by hardware */ - (1 << 8) - - /* GUIDCap */ - /* SubnetTimeOut handled by SMA */ - /* RespTimeValue handled by SMA */ - ; - /* LocalPhyErrors are programmed to max */ - portinfo[12] |= (0xf << 20) - | (0xf << 16) /* OverRunErrors are programmed to max */ - ; - - return simple_read_from_buffer(buf, count, ppos, portinfo, - sizeof portinfo); -} - -static const struct file_operations atomic_port_info_ops = { - .read = atomic_port_info_read, -}; - static ssize_t flash_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -427,22 +258,6 @@ static int create_device_files(struct super_block *sb, goto bail; } - ret = create_file("node_info", S_IFREG|S_IRUGO, dir, &tmp, - &atomic_node_info_ops, dd); - if (ret) { - printk(KERN_ERR "create_file(%s/node_info) " - "failed: %d\n", unit, ret); - goto bail; - } - - ret = create_file("port_info", S_IFREG|S_IRUGO, dir, &tmp, - &atomic_port_info_ops, dd); - if (ret) { - printk(KERN_ERR "create_file(%s/port_info) " - "failed: %d\n", unit, ret); - goto bail; - } - ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp, &flash_ops, dd); if (ret) { @@ -508,8 +323,6 @@ static int remove_device_files(struct super_block *sb, } remove_file(dir, "flash"); - remove_file(dir, "port_info"); - remove_file(dir, "node_info"); remove_file(dir, "atomic_counters"); d_delete(dir); ret = simple_rmdir(root->d_inode, dir); From 9ef8617af77136e743e5dd4b081a61797888a977 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Thu, 9 Aug 2007 15:18:48 -0700 Subject: [PATCH 0885/2804] IB/ipath: Correctly describe workaround for TID write chip bug This is a comment change, only, correcting the comment to match the implemented workaround, rather than the original workaround, and clarifying why it's needed. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_iba6120.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index a324c6f7aeba..d43f0b3a43fe 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -1143,11 +1143,14 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr, pa |= 2 << 29; } - /* workaround chip bug 9437 by writing each TID twice - * and holding a spinlock around the writes, so they don't - * intermix with other TID (eager or expected) writes - * Unfortunately, this call can be done from interrupt level - * for the port 0 eager TIDs, so we have to use irqsave + /* + * Workaround chip bug 9437 by writing the scratch register + * before and after the TID, and with an io write barrier. + * We use a spinlock around the writes, so they can't intermix + * with other TID (eager or expected) writes (the chip bug + * is triggered by back to back TID writes). Unfortunately, this + * call can be done from interrupt level for the port 0 eager TIDs, + * so we have to use irqsave locks. */ spin_lock_irqsave(&dd->ipath_tid_lock, flags); ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf); From 55046698faf6357ff7c53593dbfd43a9a3f681a7 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Fri, 17 Aug 2007 11:28:48 -0700 Subject: [PATCH 0886/2804] IB/ipath: UC RDMA WRITE with IMMEDIATE doesn't send the immediate This patch fixes a bug in the receive processing for UC RDMA WRITE with immediate which caused the last packet to be dropped. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_uc.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c index 767beb903c25..2dd8de20d221 100644 --- a/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/drivers/infiniband/hw/ipath/ipath_uc.c @@ -464,6 +464,16 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): rdma_last_imm: + if (header_in_data) { + wc.imm_data = *(__be32 *) data; + data += sizeof(__be32); + } else { + /* Immediate data comes after BTH */ + wc.imm_data = ohdr->u.imm_data; + } + hdrsize += 4; + wc.wc_flags = IB_WC_WITH_IMM; + /* Get the number of bytes the message was padded by. */ pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; /* Check for invalid length. */ @@ -484,16 +494,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, dev->n_pkt_drops++; goto done; } - if (header_in_data) { - wc.imm_data = *(__be32 *) data; - data += sizeof(__be32); - } else { - /* Immediate data comes after BTH */ - wc.imm_data = ohdr->u.imm_data; - } - hdrsize += 4; - wc.wc_flags = IB_WC_WITH_IMM; - wc.byte_len = 0; + wc.byte_len = qp->r_len; goto last_imm; case OP(RDMA_WRITE_LAST): From d29cc6efb9731a415957b8d0ff16e31729ed6837 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Fri, 17 Aug 2007 14:42:14 -0700 Subject: [PATCH 0887/2804] IB/ipath: Future proof eeprom checksum code (contents reading) In an earlier change, the amount of data read from the flash was mistakenly limited to the size known to the current driver. This causes problems when the length is increased, and written with the new longer version; the checksum would fail because not enough data was read. Always read the full 128 byte length to prevent this. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_eeprom.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c index b4503e9c1e95..bcfa3ccb555f 100644 --- a/drivers/infiniband/hw/ipath/ipath_eeprom.c +++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c @@ -596,7 +596,11 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) goto bail; } - len = offsetof(struct ipath_flash, if_future); + /* + * read full flash, not just currently used part, since it may have + * been written with a newer definition + * */ + len = sizeof(struct ipath_flash); buf = vmalloc(len); if (!buf) { ipath_dev_err(dd, "Couldn't allocate memory to read %u " @@ -737,8 +741,10 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd) /* * The quick-check above determined that there is something worthy * of logging, so get current contents and do a more detailed idea. + * read full flash, not just currently used part, since it may have + * been written with a newer definition */ - len = offsetof(struct ipath_flash, if_future); + len = sizeof(struct ipath_flash); buf = vmalloc(len); ret = 1; if (!buf) { From 036be09ca55ee8512c05742f4f6b88911d012a90 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Mon, 20 Aug 2007 16:52:35 -0700 Subject: [PATCH 0888/2804] IB/ipath: Remove redundant code This patch removes some redundant initialization code. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_driver.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 5248f57fe198..44784d049b71 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -382,8 +382,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit); - read_bars(dd, pdev, &bar0, &bar1); - ret = pci_enable_device(pdev); if (ret) { /* This can happen iff: @@ -529,9 +527,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, goto bail_regions; } - dd->ipath_deviceid = ent->device; /* save for later use */ - dd->ipath_vendorid = ent->vendor; - dd->ipath_pcirev = pdev->revision; #if defined(__powerpc__) From c9cf7db2bca9180f5888eebc23dc607666a9685b Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Sat, 25 Aug 2007 16:48:29 -0700 Subject: [PATCH 0889/2804] IB/ipath: Generate flush CQE when QP is in error state Follow the IB spec. (C10-96) for post send which states that a flushed completion event should be generated for work requests posted when a QP is in the error state. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_verbs.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 3cc82b62b3c5..495194bb84a5 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -230,6 +230,18 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length) } } +static void ipath_flush_wqe(struct ipath_qp *qp, struct ib_send_wr *wr) +{ + struct ib_wc wc; + + memset(&wc, 0, sizeof(wc)); + wc.wr_id = wr->wr_id; + wc.status = IB_WC_WR_FLUSH_ERR; + wc.opcode = ib_ipath_wc_opcode[wr->opcode]; + wc.qp = &qp->ibqp; + ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1); +} + /** * ipath_post_one_send - post one RC, UC, or UD send work request * @qp: the QP to post on @@ -248,8 +260,14 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr) spin_lock_irqsave(&qp->s_lock, flags); /* Check that state is OK to post send. */ - if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) - goto bail_inval; + if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))) { + if (qp->state != IB_QPS_SQE && qp->state != IB_QPS_ERR) + goto bail_inval; + /* C10-96 says generate a flushed completion entry. */ + ipath_flush_wqe(qp, wr); + ret = 0; + goto bail; + } /* IB spec says that num_sge == 0 is OK. */ if (wr->num_sge > qp->s_max_sge) From d42b01b584b6f55f70c56f6a3dabc26f4982d30d Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Sat, 25 Aug 2007 16:45:03 -0700 Subject: [PATCH 0890/2804] IB/ipath: Implement IB_EVENT_QP_LAST_WQE_REACHED This patch implements the IB_EVENT_QP_LAST_WQE_REACHED event which is needed by ib_ipoib to destroy the QP when used in connected mode. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_qp.c | 20 +++++++++++++++++--- drivers/infiniband/hw/ipath/ipath_rc.c | 12 +++++++++++- drivers/infiniband/hw/ipath/ipath_verbs.h | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index a8c4a6b03d7a..6a41fdbc8e57 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -377,13 +377,15 @@ static void ipath_reset_qp(struct ipath_qp *qp) * @err: the receive completion error to signal if a RWQE is active * * Flushes both send and receive work queues. + * Returns true if last WQE event should be generated. * The QP s_lock should be held and interrupts disabled. */ -void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) +int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) { struct ipath_ibdev *dev = to_idev(qp->ibqp.device); struct ib_wc wc; + int ret = 0; ipath_dbg("QP%d/%d in error state\n", qp->ibqp.qp_num, qp->remote_qpn); @@ -454,7 +456,10 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) wq->tail = tail; spin_unlock(&qp->r_rq.lock); - } + } else if (qp->ibqp.event_handler) + ret = 1; + + return ret; } /** @@ -473,6 +478,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, struct ipath_qp *qp = to_iqp(ibqp); enum ib_qp_state cur_state, new_state; unsigned long flags; + int lastwqe = 0; int ret; spin_lock_irqsave(&qp->s_lock, flags); @@ -532,7 +538,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, break; case IB_QPS_ERR: - ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR); + lastwqe = ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR); break; default: @@ -591,6 +597,14 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, qp->state = new_state; spin_unlock_irqrestore(&qp->s_lock, flags); + if (lastwqe) { + struct ib_event ev; + + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_QP_LAST_WQE_REACHED; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); + } ret = 0; goto bail; diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index 53259daeb4f8..5c29b2bfea17 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -1497,11 +1497,21 @@ send_ack: static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err) { unsigned long flags; + int lastwqe; spin_lock_irqsave(&qp->s_lock, flags); qp->state = IB_QPS_ERR; - ipath_error_qp(qp, err); + lastwqe = ipath_error_qp(qp, err); spin_unlock_irqrestore(&qp->s_lock, flags); + + if (lastwqe) { + struct ib_event ev; + + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_QP_LAST_WQE_REACHED; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); + } } static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n) diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 619ad728b07b..a1972295bffd 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -672,7 +672,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, int ipath_destroy_qp(struct ib_qp *ibqp); -void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err); +int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err); int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata); From 6cff2faaf135b602c914710f3414630c3fc1ee83 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Fri, 7 Sep 2007 16:54:01 -0700 Subject: [PATCH 0891/2804] IB/ipath: Optimize completion queue entry insertion and polling The code to add an entry to the completion queue stored the QPN which is needed for the user level verbs view of the completion queue entry but the kernel struct ib_wc contains a pointer to the QP instead of a QPN. When the kernel polled for a completion queue entry, the QPN was lookup up and the QP pointer recovered. This patch stores the CQE differently based on whether the CQ is a kernel CQ or a user CQ thus avoiding the QPN to QP lookup overhead. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_cq.c | 94 ++++++++++++----------- drivers/infiniband/hw/ipath/ipath_verbs.h | 6 +- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c index a6f04d27ec57..645ed71fd797 100644 --- a/drivers/infiniband/hw/ipath/ipath_cq.c +++ b/drivers/infiniband/hw/ipath/ipath_cq.c @@ -76,22 +76,25 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited) } return; } - wc->queue[head].wr_id = entry->wr_id; - wc->queue[head].status = entry->status; - wc->queue[head].opcode = entry->opcode; - wc->queue[head].vendor_err = entry->vendor_err; - wc->queue[head].byte_len = entry->byte_len; - wc->queue[head].imm_data = (__u32 __force)entry->imm_data; - wc->queue[head].qp_num = entry->qp->qp_num; - wc->queue[head].src_qp = entry->src_qp; - wc->queue[head].wc_flags = entry->wc_flags; - wc->queue[head].pkey_index = entry->pkey_index; - wc->queue[head].slid = entry->slid; - wc->queue[head].sl = entry->sl; - wc->queue[head].dlid_path_bits = entry->dlid_path_bits; - wc->queue[head].port_num = entry->port_num; - /* Make sure queue entry is written before the head index. */ - smp_wmb(); + if (cq->ip) { + wc->uqueue[head].wr_id = entry->wr_id; + wc->uqueue[head].status = entry->status; + wc->uqueue[head].opcode = entry->opcode; + wc->uqueue[head].vendor_err = entry->vendor_err; + wc->uqueue[head].byte_len = entry->byte_len; + wc->uqueue[head].imm_data = (__u32 __force)entry->imm_data; + wc->uqueue[head].qp_num = entry->qp->qp_num; + wc->uqueue[head].src_qp = entry->src_qp; + wc->uqueue[head].wc_flags = entry->wc_flags; + wc->uqueue[head].pkey_index = entry->pkey_index; + wc->uqueue[head].slid = entry->slid; + wc->uqueue[head].sl = entry->sl; + wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits; + wc->uqueue[head].port_num = entry->port_num; + /* Make sure entry is written before the head index. */ + smp_wmb(); + } else + wc->kqueue[head] = *entry; wc->head = next; if (cq->notify == IB_CQ_NEXT_COMP || @@ -130,6 +133,12 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) int npolled; u32 tail; + /* The kernel can only poll a kernel completion queue */ + if (cq->ip) { + npolled = -EINVAL; + goto bail; + } + spin_lock_irqsave(&cq->lock, flags); wc = cq->queue; @@ -137,31 +146,10 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) if (tail > (u32) cq->ibcq.cqe) tail = (u32) cq->ibcq.cqe; for (npolled = 0; npolled < num_entries; ++npolled, ++entry) { - struct ipath_qp *qp; - if (tail == wc->head) break; - /* Make sure entry is read after head index is read. */ - smp_rmb(); - qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table, - wc->queue[tail].qp_num); - entry->qp = &qp->ibqp; - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); - - entry->wr_id = wc->queue[tail].wr_id; - entry->status = wc->queue[tail].status; - entry->opcode = wc->queue[tail].opcode; - entry->vendor_err = wc->queue[tail].vendor_err; - entry->byte_len = wc->queue[tail].byte_len; - entry->imm_data = wc->queue[tail].imm_data; - entry->src_qp = wc->queue[tail].src_qp; - entry->wc_flags = wc->queue[tail].wc_flags; - entry->pkey_index = wc->queue[tail].pkey_index; - entry->slid = wc->queue[tail].slid; - entry->sl = wc->queue[tail].sl; - entry->dlid_path_bits = wc->queue[tail].dlid_path_bits; - entry->port_num = wc->queue[tail].port_num; + /* The kernel doesn't need a RMB since it has the lock. */ + *entry = wc->kqueue[tail]; if (tail >= cq->ibcq.cqe) tail = 0; else @@ -171,6 +159,7 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) spin_unlock_irqrestore(&cq->lock, flags); +bail: return npolled; } @@ -215,6 +204,7 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec struct ipath_cq *cq; struct ipath_cq_wc *wc; struct ib_cq *ret; + u32 sz; if (entries < 1 || entries > ib_ipath_max_cqes) { ret = ERR_PTR(-EINVAL); @@ -235,7 +225,12 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec * We need to use vmalloc() in order to support mmap and large * numbers of entries. */ - wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries); + sz = sizeof(*wc); + if (udata && udata->outlen >= sizeof(__u64)) + sz += sizeof(struct ib_uverbs_wc) * (entries + 1); + else + sz += sizeof(struct ib_wc) * (entries + 1); + wc = vmalloc_user(sz); if (!wc) { ret = ERR_PTR(-ENOMEM); goto bail_cq; @@ -247,9 +242,8 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec */ if (udata && udata->outlen >= sizeof(__u64)) { int err; - u32 s = sizeof *wc + sizeof(struct ib_wc) * entries; - cq->ip = ipath_create_mmap_info(dev, s, context, wc); + cq->ip = ipath_create_mmap_info(dev, sz, context, wc); if (!cq->ip) { ret = ERR_PTR(-ENOMEM); goto bail_wc; @@ -380,6 +374,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) struct ipath_cq_wc *wc; u32 head, tail, n; int ret; + u32 sz; if (cqe < 1 || cqe > ib_ipath_max_cqes) { ret = -EINVAL; @@ -389,7 +384,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) /* * Need to use vmalloc() if we want to support large #s of entries. */ - wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe); + sz = sizeof(*wc); + if (udata && udata->outlen >= sizeof(__u64)) + sz += sizeof(struct ib_uverbs_wc) * (cqe + 1); + else + sz += sizeof(struct ib_wc) * (cqe + 1); + wc = vmalloc_user(sz); if (!wc) { ret = -ENOMEM; goto bail; @@ -430,7 +430,10 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) goto bail; } for (n = 0; tail != head; n++) { - wc->queue[n] = old_wc->queue[tail]; + if (cq->ip) + wc->uqueue[n] = old_wc->uqueue[tail]; + else + wc->kqueue[n] = old_wc->kqueue[tail]; if (tail == (u32) cq->ibcq.cqe) tail = 0; else @@ -447,9 +450,8 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) if (cq->ip) { struct ipath_ibdev *dev = to_idev(ibcq->device); struct ipath_mmap_info *ip = cq->ip; - u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe; - ipath_update_mmap_info(dev, ip, s, wc); + ipath_update_mmap_info(dev, ip, sz, wc); spin_lock_irq(&dev->pending_lock); if (list_empty(&ip->pending_mmaps)) list_add(&ip->pending_mmaps, &dev->pending_mmaps); diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index a1972295bffd..9be9bf91f4f0 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -191,7 +191,11 @@ struct ipath_mmap_info { struct ipath_cq_wc { u32 head; /* index of next entry to fill */ u32 tail; /* index of next ib_poll_cq() entry */ - struct ib_uverbs_wc queue[1]; /* this is actually size ibcq.cqe + 1 */ + union { + /* these are actually size ibcq.cqe + 1 */ + struct ib_uverbs_wc uqueue[0]; + struct ib_wc kqueue[0]; + }; }; /* From 15cba26f42c13ca30cbb4388f132ac0ddf4df538 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Wed, 12 Sep 2007 15:00:58 -0700 Subject: [PATCH 0892/2804] IB/ipath: Add ability to set the LMC via the sysfs debugging interface This patch adds the ability to set the LMC via a sysfs file as if the SM sent a SubnSet(PortInfo) MAD. It is useful for debugging when no SM is running. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_sysfs.c | 40 ++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c index 16238cd3a036..e1ad7cfc21fd 100644 --- a/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -163,6 +163,42 @@ static ssize_t show_boardversion(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion); } +static ssize_t show_lmc(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_lmc); +} + +static ssize_t store_lmc(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + u16 lmc = 0; + int ret; + + ret = ipath_parse_ushort(buf, &lmc); + if (ret < 0) + goto invalid; + + if (lmc > 7) { + ret = -EINVAL; + goto invalid; + } + + ipath_set_lid(dd, dd->ipath_lid, lmc); + + goto bail; +invalid: + ipath_dev_err(dd, "attempt to set invalid LMC %u\n", lmc); +bail: + return ret; +} + static ssize_t show_lid(struct device *dev, struct device_attribute *attr, char *buf) @@ -190,7 +226,7 @@ static ssize_t store_lid(struct device *dev, goto invalid; } - ipath_set_lid(dd, lid, 0); + ipath_set_lid(dd, lid, dd->ipath_lmc); goto bail; invalid: @@ -648,6 +684,7 @@ static struct attribute_group driver_attr_group = { }; static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid); +static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc); static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid); static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state); static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid); @@ -667,6 +704,7 @@ static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL); static struct attribute *dev_attributes[] = { &dev_attr_guid.attr, + &dev_attr_lmc.attr, &dev_attr_lid.attr, &dev_attr_link_state.attr, &dev_attr_mlid.attr, From 542869a17eee2edf389273f40f757aa4e662b3da Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Thu, 13 Sep 2007 11:42:52 -0700 Subject: [PATCH 0893/2804] IB/ipath: Remove duplicate copy of LMC The LMC value was being saved by the SMA in two places. This patch cleans it up so only one copy is kept. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_mad.c | 39 ++++++++++++----------- drivers/infiniband/hw/ipath/ipath_ud.c | 10 +++--- drivers/infiniband/hw/ipath/ipath_verbs.c | 4 +-- drivers/infiniband/hw/ipath/ipath_verbs.h | 2 +- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index d61c03044545..8f152167208a 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -245,7 +245,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, /* Only return the mkey if the protection field allows it. */ if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey || - (dev->mkeyprot_resv_lmc >> 6) == 0) + dev->mkeyprot == 0) pip->mkey = dev->mkey; pip->gid_prefix = dev->gid_prefix; lid = dev->dd->ipath_lid; @@ -264,7 +264,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, pip->portphysstate_linkdown = (ipath_cvt_physportstate[ibcstat & 0xf] << 4) | (get_linkdowndefaultstate(dev->dd) ? 1 : 2); - pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc; + pip->mkeyprot_resv_lmc = (dev->mkeyprot << 6) | dev->dd->ipath_lmc; pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */ switch (dev->dd->ipath_ibmtu) { case 4096: @@ -401,6 +401,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, struct ib_port_info *pip = (struct ib_port_info *)smp->data; struct ib_event event; struct ipath_ibdev *dev; + struct ipath_devdata *dd; u32 flags; char clientrereg = 0; u16 lid, smlid; @@ -415,6 +416,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, goto err; dev = to_idev(ibdev); + dd = dev->dd; event.device = ibdev; event.element.port_num = port; @@ -423,11 +425,12 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period); lid = be16_to_cpu(pip->lid); - if (lid != dev->dd->ipath_lid) { + if (dd->ipath_lid != lid || + dd->ipath_lmc != (pip->mkeyprot_resv_lmc & 7)) { /* Must be a valid unicast LID address. */ if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE) goto err; - ipath_set_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7); + ipath_set_lid(dd, lid, pip->mkeyprot_resv_lmc & 7); event.event = IB_EVENT_LID_CHANGE; ib_dispatch_event(&event); } @@ -461,18 +464,18 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, case 0: /* NOP */ break; case 1: /* SLEEP */ - if (set_linkdowndefaultstate(dev->dd, 1)) + if (set_linkdowndefaultstate(dd, 1)) goto err; break; case 2: /* POLL */ - if (set_linkdowndefaultstate(dev->dd, 0)) + if (set_linkdowndefaultstate(dd, 0)) goto err; break; default: goto err; } - dev->mkeyprot_resv_lmc = pip->mkeyprot_resv_lmc; + dev->mkeyprot = pip->mkeyprot_resv_lmc >> 6; dev->vl_high_limit = pip->vl_high_limit; switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) { @@ -495,7 +498,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, /* XXX We have already partially updated our state! */ goto err; } - ipath_set_mtu(dev->dd, mtu); + ipath_set_mtu(dd, mtu); dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF; @@ -511,16 +514,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, * later. */ if (pip->pkey_violations == 0) - dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd); + dev->z_pkey_violations = ipath_get_cr_errpkey(dd); if (pip->qkey_violations == 0) dev->qkey_violations = 0; ore = pip->localphyerrors_overrunerrors; - if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF)) + if (set_phyerrthreshold(dd, (ore >> 4) & 0xF)) goto err; - if (set_overrunthreshold(dev->dd, (ore & 0xF))) + if (set_overrunthreshold(dd, (ore & 0xF))) goto err; dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F; @@ -538,7 +541,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, * is down or is being set to down. */ state = pip->linkspeed_portstate & 0xF; - flags = dev->dd->ipath_flags; + flags = dd->ipath_flags; lstate = (pip->portphysstate_linkdown >> 4) & 0xF; if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP)) goto err; @@ -554,7 +557,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, /* FALLTHROUGH */ case IB_PORT_DOWN: if (lstate == 0) - if (get_linkdowndefaultstate(dev->dd)) + if (get_linkdowndefaultstate(dd)) lstate = IPATH_IB_LINKDOWN_SLEEP; else lstate = IPATH_IB_LINKDOWN; @@ -566,7 +569,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, lstate = IPATH_IB_LINKDOWN_DISABLE; else goto err; - ipath_set_linkstate(dev->dd, lstate); + ipath_set_linkstate(dd, lstate); if (flags & IPATH_LINKACTIVE) { event.event = IB_EVENT_PORT_ERR; ib_dispatch_event(&event); @@ -575,7 +578,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, case IB_PORT_ARMED: if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) break; - ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM); + ipath_set_linkstate(dd, IPATH_IB_LINKARM); if (flags & IPATH_LINKACTIVE) { event.event = IB_EVENT_PORT_ERR; ib_dispatch_event(&event); @@ -584,7 +587,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, case IB_PORT_ACTIVE: if (!(flags & IPATH_LINKARMED)) break; - ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE); + ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); event.event = IB_EVENT_PORT_ACTIVE; ib_dispatch_event(&event); break; @@ -1350,7 +1353,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags, if (dev->mkey_lease_timeout && jiffies >= dev->mkey_lease_timeout) { /* Clear timeout and mkey protection field. */ dev->mkey_lease_timeout = 0; - dev->mkeyprot_resv_lmc &= 0x3F; + dev->mkeyprot = 0; } /* @@ -1361,7 +1364,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags, dev->mkey != smp->mkey && (smp->method == IB_MGMT_METHOD_SET || (smp->method == IB_MGMT_METHOD_GET && - (dev->mkeyprot_resv_lmc >> 7) != 0))) { + dev->mkeyprot >= 2))) { if (dev->mkey_violations != 0xFFFF) ++dev->mkey_violations; if (dev->mkey_lease_timeout || diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 34c4a0a5be31..16a2a938b520 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -236,10 +236,10 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) wc.pkey_index = 0; wc.slid = dev->dd->ipath_lid | (ah_attr->src_path_bits & - ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1)); + ((1 << dev->dd->ipath_lmc) - 1)); wc.sl = ah_attr->sl; wc.dlid_path_bits = - ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + ah_attr->dlid & ((1 << dev->dd->ipath_lmc) - 1); wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, @@ -289,7 +289,7 @@ int ipath_make_ud_req(struct ipath_qp *qp) } else { dev->n_unicast_xmit++; lid = ah_attr->dlid & - ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + ~((1 << dev->dd->ipath_lmc) - 1); if (unlikely(lid == dev->dd->ipath_lid)) { ipath_ud_loopback(qp, wqe); goto done; @@ -341,7 +341,7 @@ int ipath_make_ud_req(struct ipath_qp *qp) lid = dev->dd->ipath_lid; if (lid) { lid |= ah_attr->src_path_bits & - ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + ((1 << dev->dd->ipath_lmc) - 1); qp->s_hdr.lrh[3] = cpu_to_be16(lid); } else qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE; @@ -551,7 +551,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, * Save the LMC lower bits if the destination LID is a unicast LID. */ wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 : - dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + dlid & ((1 << dev->dd->ipath_lmc) - 1); wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 495194bb84a5..13aba3d40543 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -513,7 +513,7 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data, /* Check for a valid destination LID (see ch. 7.11.1). */ lid = be16_to_cpu(hdr->lrh[1]); if (lid < IPATH_MULTICAST_LID_BASE) { - lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + lid &= ~((1 << dev->dd->ipath_lmc) - 1); if (unlikely(lid != dev->dd->ipath_lid)) { dev->rcv_errors++; goto bail; @@ -1152,7 +1152,7 @@ static int ipath_query_port(struct ib_device *ibdev, memset(props, 0, sizeof(*props)); props->lid = lid ? lid : __constant_be16_to_cpu(IB_LID_PERMISSIVE); - props->lmc = dev->mkeyprot_resv_lmc & 7; + props->lmc = dd->ipath_lmc; props->sm_lid = dev->sm_lid; props->sm_sl = dev->sm_sl; ibcstat = dd->ipath_lastibcstat; diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 9be9bf91f4f0..6ccb54f104a3 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -501,7 +501,7 @@ struct ipath_ibdev { int ib_unit; /* This is the device number */ u16 sm_lid; /* in host order */ u8 sm_sl; - u8 mkeyprot_resv_lmc; + u8 mkeyprot; /* non-zero when timer is set */ unsigned long mkey_lease_timeout; From 70c51da2c4f84317bb13a2b564600afdcebd686f Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Fri, 14 Sep 2007 12:22:49 -0700 Subject: [PATCH 0894/2804] IB/ipath: Use counters in ipath_poll and cleanup interrupts in ipath_close ipath_poll() suffered from a couple subtle bugs. Under the right conditions we could leave recv interrupts enabled on an ipath user context on close, thereby taking potentially unwanted interrupts on the next open -- this is fixed by unconditionally turning off recv interrupts on close. Also, we now use counters rather than set/clear bits which allows us to make sure we catch all interrupts at the cost of changing the semantics slightly (it's now give me all events since the last time I called poll() rather than give me all events since I called _this_ poll routine). We also added some memory barriers which may help ensure we get all notifications in a timely manner. Signed-off-by: Arthur Jones Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_file_ops.c | 67 ++++++++++++-------- drivers/infiniband/hw/ipath/ipath_intr.c | 33 +++------- drivers/infiniband/hw/ipath/ipath_kernel.h | 8 ++- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 33ab0d6b80ff..016e7c4e366b 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -1341,6 +1341,19 @@ bail: return ret; } +static unsigned ipath_poll_hdrqfull(struct ipath_portdata *pd) +{ + unsigned pollflag = 0; + + if ((pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) && + pd->port_hdrqfull != pd->port_hdrqfull_poll) { + pollflag |= POLLIN | POLLRDNORM; + pd->port_hdrqfull_poll = pd->port_hdrqfull; + } + + return pollflag; +} + static unsigned int ipath_poll_urgent(struct ipath_portdata *pd, struct file *fp, struct poll_table_struct *pt) @@ -1350,22 +1363,20 @@ static unsigned int ipath_poll_urgent(struct ipath_portdata *pd, dd = pd->port_dd; - if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) { - pollflag |= POLLERR; - clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag); - } + /* variable access in ipath_poll_hdrqfull() needs this */ + rmb(); + pollflag = ipath_poll_hdrqfull(pd); - if (test_bit(IPATH_PORT_WAITING_URG, &pd->int_flag)) { + if (pd->port_urgent != pd->port_urgent_poll) { pollflag |= POLLIN | POLLRDNORM; - clear_bit(IPATH_PORT_WAITING_URG, &pd->int_flag); + pd->port_urgent_poll = pd->port_urgent; } if (!pollflag) { + /* this saves a spin_lock/unlock in interrupt handler... */ set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag); - if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) - set_bit(IPATH_PORT_WAITING_OVERFLOW, - &pd->port_flag); - + /* flush waiting flag so don't miss an event... */ + wmb(); poll_wait(fp, &pd->port_wait, pt); } @@ -1376,31 +1387,27 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd, struct file *fp, struct poll_table_struct *pt) { - u32 head, tail; + u32 head; + u32 tail; unsigned pollflag = 0; struct ipath_devdata *dd; dd = pd->port_dd; + /* variable access in ipath_poll_hdrqfull() needs this */ + rmb(); + pollflag = ipath_poll_hdrqfull(pd); + head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port); tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr; - if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) { - pollflag |= POLLERR; - clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag); - } - - if (tail != head || - test_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag)) { + if (head != tail) pollflag |= POLLIN | POLLRDNORM; - clear_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag); - } - - if (!pollflag) { + else { + /* this saves a spin_lock/unlock in interrupt handler */ set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); - if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) - set_bit(IPATH_PORT_WAITING_OVERFLOW, - &pd->port_flag); + /* flush waiting flag so we don't miss an event */ + wmb(); set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, &dd->ipath_rcvctrl); @@ -1917,6 +1924,12 @@ static int ipath_do_user_init(struct file *fp, ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n", pd->port_port, head32); pd->port_tidcursor = 0; /* start at beginning after open */ + + /* initialize poll variables... */ + pd->port_urgent = 0; + pd->port_urgent_poll = 0; + pd->port_hdrqfull_poll = pd->port_hdrqfull; + /* * now enable the port; the tail registers will be written to memory * by the chip as soon as it sees the write to @@ -2039,9 +2052,11 @@ static int ipath_close(struct inode *in, struct file *fp) if (dd->ipath_kregbase) { int i; - /* atomically clear receive enable port. */ + /* atomically clear receive enable port and intr avail. */ clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port, &dd->ipath_rcvctrl); + clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, + &dd->ipath_rcvctrl); ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); /* and read back from chip to be sure that nothing diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 11b361408ae6..61eac8cc0d9f 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -688,17 +688,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) chkerrpkts = 1; dd->ipath_lastrcvhdrqtails[i] = tl; pd->port_hdrqfull++; - if (test_bit(IPATH_PORT_WAITING_OVERFLOW, - &pd->port_flag)) { - clear_bit( - IPATH_PORT_WAITING_OVERFLOW, - &pd->port_flag); - set_bit( - IPATH_PORT_WAITING_OVERFLOW, - &pd->int_flag); - wake_up_interruptible( - &pd->port_wait); - } + /* flush hdrqfull so that poll() sees it */ + wmb(); + wake_up_interruptible(&pd->port_wait); } } } @@ -960,6 +952,8 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) int i; int rcvdint = 0; + /* test_bit below needs this... */ + rmb(); portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & dd->ipath_i_rcvavail_mask) | ((istat >> INFINIPATH_I_RCVURG_SHIFT) & @@ -967,22 +961,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) for (i = 1; i < dd->ipath_cfgports; i++) { struct ipath_portdata *pd = dd->ipath_pd[i]; if (portr & (1 << i) && pd && pd->port_cnt) { - if (test_bit(IPATH_PORT_WAITING_RCV, - &pd->port_flag)) { - clear_bit(IPATH_PORT_WAITING_RCV, - &pd->port_flag); - set_bit(IPATH_PORT_WAITING_RCV, - &pd->int_flag); + if (test_and_clear_bit(IPATH_PORT_WAITING_RCV, + &pd->port_flag)) { clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, &dd->ipath_rcvctrl); wake_up_interruptible(&pd->port_wait); rcvdint = 1; - } else if (test_bit(IPATH_PORT_WAITING_URG, - &pd->port_flag)) { - clear_bit(IPATH_PORT_WAITING_URG, - &pd->port_flag); - set_bit(IPATH_PORT_WAITING_URG, - &pd->int_flag); + } else if (test_and_clear_bit(IPATH_PORT_WAITING_URG, + &pd->port_flag)) { + pd->port_urgent++; wake_up_interruptible(&pd->port_wait); } } diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index d983f92b9bcb..872fb36703d9 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -139,6 +139,12 @@ struct ipath_portdata { u32 port_pionowait; /* total number of rcvhdrqfull errors */ u32 port_hdrqfull; + /* saved total number of rcvhdrqfull errors for poll edge trigger */ + u32 port_hdrqfull_poll; + /* total number of polled urgent packets */ + u32 port_urgent; + /* saved total number of polled urgent packets for poll edge trigger */ + u32 port_urgent_poll; /* pid of process using this port */ pid_t port_pid; /* same size as task_struct .comm[] */ @@ -757,8 +763,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); #define IPATH_PORT_MASTER_UNINIT 4 /* waiting for an urgent packet to arrive */ #define IPATH_PORT_WAITING_URG 5 - /* waiting for a header overflow */ -#define IPATH_PORT_WAITING_OVERFLOW 6 /* free up any allocated data at closes */ void ipath_free_data(struct ipath_portdata *dd); From 4bec0b9155d6757847b754e21b55ecafcecef839 Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Tue, 18 Sep 2007 14:24:23 -0700 Subject: [PATCH 0895/2804] IB/ipath: iba6110 rev4 no longer needs recv header overrun workaround iba6110 rev3 and earlier had a chip bug where the chip could overrun the recv header queue. rev4 fixed this chip bug so userspace no longer needs to workaround it. Now we only set the workaround flag for older chip versions. Signed-off-by: Arthur Jones Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_iba6110.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index e1c5998887ea..d4940beb58c7 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -1599,8 +1599,10 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase) { struct ipath_base_info *kinfo = kbase; - kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT | - IPATH_RUNTIME_RCVHDR_COPY; + kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT; + + if (pd->port_dd->ipath_minrev < 4) + kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY; return 0; } From 20bed343142bfaf08765e35aaefa56dc5cc287db Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Tue, 18 Sep 2007 14:44:45 -0700 Subject: [PATCH 0896/2804] IB/ipath: Indicate a couple of chip bugs to userspace A couple of chip bugs in the iba6110 and in the iba6120 are not in more recent chips. This first bug swaps two of the pioavail register locations. In the second bug, the chip can sometimes forget to dma the pio avail register to memory. We indicate the presence of these bugs with runtime flags and we indicate the presence of the flags by bumping the SWMINOR. Signed-off-by: Arthur Jones Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_common.h | 4 +++- drivers/infiniband/hw/ipath/ipath_iba6110.c | 3 ++- drivers/infiniband/hw/ipath/ipath_iba6120.c | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index 6ad822c35930..851df8a75e79 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h @@ -189,6 +189,8 @@ typedef enum _ipath_ureg { #define IPATH_RUNTIME_RCVHDR_COPY 0x8 #define IPATH_RUNTIME_MASTER 0x10 /* 0x20 and 0x40 are no longer used, but are reserved for ABI compatibility */ +#define IPATH_RUNTIME_FORCE_PIOAVAIL 0x400 +#define IPATH_RUNTIME_PIO_REGSWAPPED 0x800 /* * This structure is returned by ipath_userinit() immediately after @@ -350,7 +352,7 @@ struct ipath_base_info { * may not be implemented; the user code must deal with this if it * cares, or it must abort after initialization reports the difference. */ -#define IPATH_USER_SWMINOR 5 +#define IPATH_USER_SWMINOR 6 #define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR) diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index d4940beb58c7..df42a1e3b6b7 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -1599,7 +1599,8 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase) { struct ipath_base_info *kinfo = kbase; - kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT; + kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT | + IPATH_RUNTIME_PIO_REGSWAPPED; if (pd->port_dd->ipath_minrev < 4) kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY; diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index d43f0b3a43fe..0103d6f4847b 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -1348,7 +1348,8 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase) dd = pd->port_dd; done: - kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE; + kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE | + IPATH_RUNTIME_FORCE_PIOAVAIL | IPATH_RUNTIME_PIO_REGSWAPPED; return 0; } From aa7c79abd154ed9aba4c19b861d439ef6af35d3a Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Thu, 16 Aug 2007 18:10:43 -0700 Subject: [PATCH 0897/2804] IB/ipath: Fix QHT7040 serial number check Remove all the OEM and bringup boards, and complain and fail initialization if one is found. QHT7040 with GPIO rework (128ywwuuuu) is OK, older 112ywwuuuu is no longer supported). The check that had been added was failing both the 112 and 128 series. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_iba6110.c | 44 +++++++-------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index df42a1e3b6b7..ddbebe4bdb27 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -631,56 +631,35 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, { char *n = NULL; u8 boardrev = dd->ipath_boardrev; - int ret; + int ret = 0; switch (boardrev) { - case 4: /* Ponderosa is one of the bringup boards */ - n = "Ponderosa"; - break; case 5: /* * original production board; two production levels, with * different serial number ranges. See ipath_ht_early_init() for * case where we enable IPATH_GPIO_INTR for later serial # range. + * Original 112* serial number is no longer supported. */ n = "InfiniPath_QHT7040"; break; - case 6: - n = "OEM_Board_3"; - break; case 7: /* small form factor production board */ n = "InfiniPath_QHT7140"; break; - case 8: - n = "LS/X-1"; - break; - case 9: /* Comstock bringup test board */ - n = "Comstock"; - break; - case 10: - n = "OEM_Board_2"; - break; - case 11: - n = "InfiniPath_HT-470"; /* obsoleted */ - break; - case 12: - n = "OEM_Board_4"; - break; default: /* don't know, just print the number */ ipath_dev_err(dd, "Don't yet know about board " "with ID %u\n", boardrev); snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u", boardrev); + ret = 1; break; } if (n) snprintf(name, namelen, "%s", n); - if (dd->ipath_boardrev != 6 && dd->ipath_boardrev != 7 && - dd->ipath_boardrev != 11) { + if (ret) { ipath_dev_err(dd, "Unsupported InfiniPath board %s!\n", name); - ret = 1; goto bail; } if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || @@ -1554,10 +1533,17 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) * can use GPIO interrupts. They have serial #'s starting * with 128, rather than 112. */ - dd->ipath_flags |= IPATH_GPIO_INTR; - } else - ipath_dev_err(dd, "Unsupported InfiniPath serial " - "number %.16s!\n", dd->ipath_serial); + if (dd->ipath_serial[0] == '1' && + dd->ipath_serial[1] == '2' && + dd->ipath_serial[2] == '8') + dd->ipath_flags |= IPATH_GPIO_INTR; + else { + ipath_dev_err(dd, "Unsupported InfiniPath board " + "(serial number %.16s)!\n", + dd->ipath_serial); + return 1; + } + } if (dd->ipath_minrev >= 4) { /* Rev4+ reports extra errors via internal GPIO pins */ From 192594d5230f447ef2df8de9d7902ac90d11c118 Mon Sep 17 00:00:00 2001 From: Michael Albaugh Date: Tue, 2 Oct 2007 13:26:45 -0700 Subject: [PATCH 0898/2804] IB/ipath: Maintain active time on all chips There is a count of "active hours" maintained in EEPROM, to aid troubleshooting. The definition of "active" is based on traffic exceeding a threshold in any given 5-second polling interval. As originally written, the check was inadvertently bypassed for chips whose counters were 64-bits wide, and only applied to chips with 32-bit wide counters. This patch moves the test for amount of traffic "out" to a more common location, rather than depending on a side-effect of the software emulation of 64-bit counts on chips whose hardware is only 32-bits wide. Signed-off-by: Michael Albaugh Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_stats.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c index bae4f56f7271..f0271415cd5b 100644 --- a/drivers/infiniband/hw/ipath/ipath_stats.c +++ b/drivers/infiniband/hw/ipath/ipath_stats.c @@ -55,7 +55,6 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg) u64 val64; unsigned long t0, t1; u64 ret; - unsigned long flags; t0 = jiffies; /* If fast increment counters are only 32 bits, snapshot them, @@ -92,18 +91,12 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg) if (creg == dd->ipath_cregs->cr_wordsendcnt) { if (val != dd->ipath_lastsword) { dd->ipath_sword += val - dd->ipath_lastsword; - spin_lock_irqsave(&dd->ipath_eep_st_lock, flags); - dd->ipath_traffic_wds += val - dd->ipath_lastsword; - spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags); dd->ipath_lastsword = val; } val64 = dd->ipath_sword; } else if (creg == dd->ipath_cregs->cr_wordrcvcnt) { if (val != dd->ipath_lastrword) { dd->ipath_rword += val - dd->ipath_lastrword; - spin_lock_irqsave(&dd->ipath_eep_st_lock, flags); - dd->ipath_traffic_wds += val - dd->ipath_lastrword; - spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags); dd->ipath_lastrword = val; } val64 = dd->ipath_rword; @@ -247,6 +240,7 @@ void ipath_get_faststats(unsigned long opaque) u32 val; static unsigned cnt; unsigned long flags; + u64 traffic_wds; /* * don't access the chip while running diags, or memory diags can @@ -262,12 +256,13 @@ void ipath_get_faststats(unsigned long opaque) * exceeding a threshold, so we need to check the word-counts * even if they are 64-bit. */ - ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); - ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); + traffic_wds = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); spin_lock_irqsave(&dd->ipath_eep_st_lock, flags); - if (dd->ipath_traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD) + traffic_wds -= dd->ipath_traffic_wds; + dd->ipath_traffic_wds += traffic_wds; + if (traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD) atomic_add(5, &dd->ipath_active_time); /* S/B #define */ - dd->ipath_traffic_wds = 0; spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags); if (dd->ipath_flags & IPATH_32BITCOUNTERS) { From 6a733cdc71b7aa8107caa57f2a16629aa731242a Mon Sep 17 00:00:00 2001 From: Michael Albaugh Date: Wed, 3 Oct 2007 10:47:38 -0700 Subject: [PATCH 0899/2804] IB/ipath: Better handling of unexpected GPIO interrupts The General Purpose I/O pins can be configured to cause interrupts. At the end of the interrupt code dealing with all known causes, a message is output if any bits remain un-handled. Since this is a "can't happen" scenario, it should only be triggered by bugs elsewhere. It is harmless, and potentially beneficial, to limit the damage by masking any such unexpected interrupts. This patch adds disabling of interrupts from any pins that should not have been allowed to interrupt, in addition to emitting a message. Signed-off-by: Michael Albaugh Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_intr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 61eac8cc0d9f..801a20d06de6 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -1124,10 +1124,8 @@ irqreturn_t ipath_intr(int irq, void *data) /* * Some unexpected bits remain. If they could have * caused the interrupt, complain and clear. - * MEA: this is almost certainly non-ideal. - * we should look into auto-disable of unexpected - * GPIO interrupts, possibly on a "three strikes" - * basis. + * To avoid repetition of this condition, also clear + * the mask. It is almost certainly due to error. */ const u32 mask = (u32) dd->ipath_gpio_mask; @@ -1135,6 +1133,10 @@ irqreturn_t ipath_intr(int irq, void *data) ipath_dbg("Unexpected GPIO IRQ bits %x\n", gpiostatus & mask); to_clear |= (gpiostatus & mask); + dd->ipath_gpio_mask &= ~(gpiostatus & mask); + ipath_write_kreg(dd, + dd->ipath_kregs->kr_gpio_mask, + dd->ipath_gpio_mask); } } if (to_clear) { From 49739b3e24a10d819d3167a1c5b319d0b1186245 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Wed, 19 Sep 2007 16:47:31 -0700 Subject: [PATCH 0900/2804] IB/ipath: Fix IB_EVENT_PORT_ERR event The link state event calls were being generated when the SM told the SMA to change link states. This works for IB_EVENT_PORT_ACTIVE but not if the link goes down and stays down. The fix is to generate event calls from the interrupt handler when the HW link state changes. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_driver.c | 2 ++ drivers/infiniband/hw/ipath/ipath_intr.c | 17 +++++++++++++++++ drivers/infiniband/hw/ipath/ipath_kernel.h | 2 ++ drivers/infiniband/hw/ipath/ipath_mad.c | 10 ---------- drivers/infiniband/hw/ipath/ipath_verbs.c | 12 ++++++++++-- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 44784d049b71..1f152ded1e3c 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -2086,6 +2086,8 @@ void ipath_shutdown_device(struct ipath_devdata *dd) INFINIPATH_IBCC_LINKINITCMD_SHIFT); ipath_cancel_sends(dd, 0); + signal_ib_event(dd, IB_EVENT_PORT_ERR); + /* disable IBC */ dd->ipath_control &= ~INFINIPATH_C_LINKENABLE; ipath_write_kreg(dd, dd->ipath_kregs->kr_control, diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 801a20d06de6..6a5dd5cd773d 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -275,6 +275,16 @@ static char *ib_linkstate(u32 linkstate) return ret; } +void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev) +{ + struct ib_event event; + + event.device = &dd->verbs_dev->ibdev; + event.element.port_num = 1; + event.event = ev; + ib_dispatch_event(&event); +} + static void handle_e_ibstatuschanged(struct ipath_devdata *dd, ipath_err_t errs, int noprint) { @@ -373,6 +383,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */ ipath_stats.sps_iblink++; if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) { + if (dd->ipath_flags & IPATH_LINKACTIVE) + signal_ib_event(dd, IB_EVENT_PORT_ERR); dd->ipath_flags |= IPATH_LINKDOWN; dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT | IPATH_LINKACTIVE | @@ -405,7 +417,10 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, *dd->ipath_statusp |= IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF; dd->ipath_f_setextled(dd, lstate, ltstate); + signal_ib_event(dd, IB_EVENT_PORT_ACTIVE); } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) { + if (dd->ipath_flags & IPATH_LINKACTIVE) + signal_ib_event(dd, IB_EVENT_PORT_ERR); /* * set INIT and DOWN. Down is checked by most of the other * code, but INIT is useful to know in a few places. @@ -418,6 +433,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | IPATH_STATUS_IB_READY); dd->ipath_f_setextled(dd, lstate, ltstate); } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) { + if (dd->ipath_flags & IPATH_LINKACTIVE) + signal_ib_event(dd, IB_EVENT_PORT_ERR); dd->ipath_flags |= IPATH_LINKARMED; dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT | diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 872fb36703d9..8786dd7922e4 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "ipath_common.h" #include "ipath_debug.h" @@ -775,6 +776,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *); int ipath_update_eeprom_log(struct ipath_devdata *dd); void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr); u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); +void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev); /* * Set LED override, only the two LSBs have "public" meaning, but diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index 8f152167208a..0ae3a7c3f86e 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -570,26 +570,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, else goto err; ipath_set_linkstate(dd, lstate); - if (flags & IPATH_LINKACTIVE) { - event.event = IB_EVENT_PORT_ERR; - ib_dispatch_event(&event); - } break; case IB_PORT_ARMED: if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) break; ipath_set_linkstate(dd, IPATH_IB_LINKARM); - if (flags & IPATH_LINKACTIVE) { - event.event = IB_EVENT_PORT_ERR; - ib_dispatch_event(&event); - } break; case IB_PORT_ACTIVE: if (!(flags & IPATH_LINKARMED)) break; ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); - event.event = IB_EVENT_PORT_ACTIVE; - ib_dispatch_event(&event); break; default: /* XXX We have already partially updated our state! */ diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 13aba3d40543..74f77e7c2c1b 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -948,6 +948,7 @@ bail: int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, u32 hdrwords, struct ipath_sge_state *ss, u32 len) { + struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd; u32 plen; int ret; u32 dwords = (len + 3) >> 2; @@ -955,8 +956,15 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, /* +1 is for the qword padding of pbc */ plen = hdrwords + dwords + 1; - ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords, - ss, len, plen, dwords); + /* Drop non-VL15 packets if we are not in the active state */ + if (!(dd->ipath_flags & IPATH_LINKACTIVE) && + qp->ibqp.qp_type != IB_QPT_SMI) { + if (qp->s_wqe) + ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS); + ret = 0; + } else + ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords, + ss, len, plen, dwords); return ret; } From bda94e32b39c0e60d43b34a175363601b6f12ca4 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Fri, 5 Oct 2007 16:03:21 -0700 Subject: [PATCH 0901/2804] IB/ipath: Remove redundant link state checks This patch removes some redundant checks when the SMA changes the link state since the same checks are made in the lower level function that sets the state. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_mad.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index 0ae3a7c3f86e..3d1432d1e3f4 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -402,7 +402,6 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, struct ib_event event; struct ipath_ibdev *dev; struct ipath_devdata *dd; - u32 flags; char clientrereg = 0; u16 lid, smlid; u8 lwe; @@ -541,7 +540,6 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, * is down or is being set to down. */ state = pip->linkspeed_portstate & 0xF; - flags = dd->ipath_flags; lstate = (pip->portphysstate_linkdown >> 4) & 0xF; if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP)) goto err; @@ -572,13 +570,9 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, ipath_set_linkstate(dd, lstate); break; case IB_PORT_ARMED: - if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) - break; ipath_set_linkstate(dd, IPATH_IB_LINKARM); break; case IB_PORT_ACTIVE: - if (!(flags & IPATH_LINKARMED)) - break; ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); break; default: From 3ac8c70f74ca67111c570f4ba828cc4b6fc229f4 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Wed, 3 Oct 2007 12:47:00 -0700 Subject: [PATCH 0902/2804] IB/ipath: Minor fix to ordering of freeing and zeroing of tid pages. Fixed to be the same as everywhere else. copy and then zero the page * in the array first, and then pass the copy to the VM routines. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_file_ops.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 016e7c4e366b..5de3243a47c3 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -538,6 +538,9 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport, continue; cnt++; if (dd->ipath_pageshadow[porttid + tid]) { + struct page *p; + p = dd->ipath_pageshadow[porttid + tid]; + dd->ipath_pageshadow[porttid + tid] = NULL; ipath_cdbg(VERBOSE, "PID %u freeing TID %u\n", pd->port_pid, tid); dd->ipath_f_put_tid(dd, &tidbase[tid], @@ -546,9 +549,7 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport, pci_unmap_page(dd->pcidev, dd->ipath_physshadow[porttid + tid], PAGE_SIZE, PCI_DMA_FROMDEVICE); - ipath_release_user_pages( - &dd->ipath_pageshadow[porttid + tid], 1); - dd->ipath_pageshadow[porttid + tid] = NULL; + ipath_release_user_pages(&p, 1); ipath_stats.sps_pageunlocks++; } else ipath_dbg("Unused tid %u, ignoring\n", tid); From 9dfa52831e96194b8649613e3131baa2c109f7dc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2007 13:27:52 +0200 Subject: [PATCH 0903/2804] Merge blk_recount_segments into blk_recalc_rq_segments blk_recalc_rq_segments calls blk_recount_segments on each bio, then does some extra calculations to handle segments that overlap two bios. If we merge the code from blk_recount_segments into blk_recalc_rq_segments, we can process the whole request one bio_vec at a time, and not need the messy cross-bio calculations. Then blk_recount_segments can be implemented by calling blk_recalc_rq_segments, passing it a simple on-stack request which stores just the bio. Signed-off-by: Neil Brown diff .prev/block/ll_rw_blk.c ./block/ll_rw_blk.c Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 106 ++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 60 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index ed39313c4085..e35119a72a44 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -42,6 +42,7 @@ static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io); static void init_request_from_bio(struct request *req, struct bio *bio); static int __make_request(struct request_queue *q, struct bio *bio); static struct io_context *current_io_context(gfp_t gfp_flags, int node); +static void blk_recalc_rq_segments(struct request *rq); /* * For the allocated request tables @@ -1220,16 +1221,42 @@ EXPORT_SYMBOL(blk_dump_rq_flags); void blk_recount_segments(struct request_queue *q, struct bio *bio) { - struct bio_vec *bv, *bvprv = NULL; - int i, nr_phys_segs, nr_hw_segs, seg_size, hw_seg_size, cluster; - int high, highprv = 1; + struct request rq; + struct bio *nxt = bio->bi_next; + rq.q = q; + rq.bio = rq.biotail = bio; + bio->bi_next = NULL; + blk_recalc_rq_segments(&rq); + bio->bi_next = nxt; + bio->bi_phys_segments = rq.nr_phys_segments; + bio->bi_hw_segments = rq.nr_hw_segments; + bio->bi_flags |= (1 << BIO_SEG_VALID); +} +EXPORT_SYMBOL(blk_recount_segments); - if (unlikely(!bio->bi_io_vec)) +static void blk_recalc_rq_segments(struct request *rq) +{ + int nr_phys_segs; + int nr_hw_segs; + unsigned int phys_size; + unsigned int hw_size; + struct bio_vec *bv, *bvprv = NULL; + int seg_size; + int hw_seg_size; + int cluster; + struct bio *bio; + int i; + int high, highprv = 1; + struct request_queue *q = rq->q; + + if (!rq->bio) return; cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER); - hw_seg_size = seg_size = nr_phys_segs = nr_hw_segs = 0; - bio_for_each_segment(bv, bio, i) { + hw_seg_size = seg_size = 0; + phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0; + rq_for_each_bio(bio, rq) + bio_for_each_segment(bv, bio, i) { /* * the trick here is making sure that a high page is never * considered part of another segment, since that might @@ -1255,12 +1282,13 @@ void blk_recount_segments(struct request_queue *q, struct bio *bio) } new_segment: if (BIOVEC_VIRT_MERGEABLE(bvprv, bv) && - !BIOVEC_VIRT_OVERSIZE(hw_seg_size + bv->bv_len)) { + !BIOVEC_VIRT_OVERSIZE(hw_seg_size + bv->bv_len)) hw_seg_size += bv->bv_len; - } else { + else { new_hw_segment: - if (hw_seg_size > bio->bi_hw_front_size) - bio->bi_hw_front_size = hw_seg_size; + if (nr_hw_segs == 1 && + hw_seg_size > rq->bio->bi_hw_front_size) + rq->bio->bi_hw_front_size = hw_seg_size; hw_seg_size = BIOVEC_VIRT_START_SIZE(bv) + bv->bv_len; nr_hw_segs++; } @@ -1270,15 +1298,15 @@ new_hw_segment: seg_size = bv->bv_len; highprv = high; } - if (hw_seg_size > bio->bi_hw_back_size) - bio->bi_hw_back_size = hw_seg_size; - if (nr_hw_segs == 1 && hw_seg_size > bio->bi_hw_front_size) - bio->bi_hw_front_size = hw_seg_size; - bio->bi_phys_segments = nr_phys_segs; - bio->bi_hw_segments = nr_hw_segs; - bio->bi_flags |= (1 << BIO_SEG_VALID); + + if (nr_hw_segs == 1 && + hw_seg_size > rq->bio->bi_hw_front_size) + rq->bio->bi_hw_front_size = hw_seg_size; + if (hw_seg_size > rq->biotail->bi_hw_back_size) + rq->biotail->bi_hw_back_size = hw_seg_size; + rq->nr_phys_segments = nr_phys_segs; + rq->nr_hw_segments = nr_hw_segs; } -EXPORT_SYMBOL(blk_recount_segments); static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, struct bio *nxt) @@ -3329,48 +3357,6 @@ void submit_bio(int rw, struct bio *bio) EXPORT_SYMBOL(submit_bio); -static void blk_recalc_rq_segments(struct request *rq) -{ - struct bio *bio, *prevbio = NULL; - int nr_phys_segs, nr_hw_segs; - unsigned int phys_size, hw_size; - struct request_queue *q = rq->q; - - if (!rq->bio) - return; - - phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0; - rq_for_each_bio(bio, rq) { - /* Force bio hw/phys segs to be recalculated. */ - bio->bi_flags &= ~(1 << BIO_SEG_VALID); - - nr_phys_segs += bio_phys_segments(q, bio); - nr_hw_segs += bio_hw_segments(q, bio); - if (prevbio) { - int pseg = phys_size + prevbio->bi_size + bio->bi_size; - int hseg = hw_size + prevbio->bi_size + bio->bi_size; - - if (blk_phys_contig_segment(q, prevbio, bio) && - pseg <= q->max_segment_size) { - nr_phys_segs--; - phys_size += prevbio->bi_size + bio->bi_size; - } else - phys_size = 0; - - if (blk_hw_contig_segment(q, prevbio, bio) && - hseg <= q->max_segment_size) { - nr_hw_segs--; - hw_size += prevbio->bi_size + bio->bi_size; - } else - hw_size = 0; - } - prevbio = bio; - } - - rq->nr_phys_segments = nr_phys_segs; - rq->nr_hw_segments = nr_hw_segs; -} - static void blk_recalc_rq_sectors(struct request *rq, int nsect) { if (blk_fs_request(rq)) { From 5705f7021748a69d84d6567e68e8851dab551464 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 25 Sep 2007 12:35:59 +0200 Subject: [PATCH 0904/2804] Introduce rq_for_each_segment replacing rq_for_each_bio Every usage of rq_for_each_bio wraps a usage of bio_for_each_segment, so these can be combined into rq_for_each_segment. We define "struct req_iterator" to hold the 'bio' and 'index' that are needed for the double iteration. Signed-off-by: Neil Brown Various compile fixes by me... Signed-off-by: Jens Axboe --- Documentation/block/biodoc.txt | 20 ++++----- block/ll_rw_blk.c | 19 +++----- drivers/block/floppy.c | 81 ++++++++++++++++------------------ drivers/block/lguest_blk.c | 10 ++--- drivers/block/nbd.c | 22 ++++----- drivers/block/ps3disk.c | 31 ++++++------- drivers/block/xen-blkfront.c | 7 +-- drivers/ide/ide-floppy.c | 16 +++---- drivers/s390/block/dasd_diag.c | 11 ++--- drivers/s390/block/dasd_eckd.c | 15 +++---- drivers/s390/block/dasd_fba.c | 15 +++---- drivers/s390/char/tape_34xx.c | 15 +++---- drivers/s390/char/tape_3590.c | 16 +++---- include/linux/blkdev.h | 15 ++++++- 14 files changed, 131 insertions(+), 162 deletions(-) diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 8af392fc6ef0..dc3f49e3e539 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -477,9 +477,9 @@ With this multipage bio design: the same bi_io_vec array, but with the index and size accordingly modified) - A linked list of bios is used as before for unrelated merges (*) - this avoids reallocs and makes independent completions easier to handle. -- Code that traverses the req list needs to make a distinction between - segments of a request (bio_for_each_segment) and the distinct completion - units/bios (rq_for_each_bio). +- Code that traverses the req list can find all the segments of a bio + by using rq_for_each_segment. This handles the fact that a request + has multiple bios, each of which can have multiple segments. - Drivers which can't process a large bio in one shot can use the bi_idx field to keep track of the next bio_vec entry to process. (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE) @@ -664,14 +664,14 @@ in lvm or md. 3.2.1 Traversing segments and completion units in a request -The macros bio_for_each_segment() and rq_for_each_bio() should be used for -traversing the bios in the request list (drivers should avoid directly -trying to do it themselves). Using these helpers should also make it easier -to cope with block changes in the future. +The macro rq_for_each_segment() should be used for traversing the bios +in the request list (drivers should avoid directly trying to do it +themselves). Using these helpers should also make it easier to cope +with block changes in the future. - rq_for_each_bio(bio, rq) - bio_for_each_segment(bio_vec, bio, i) - /* bio_vec is now current segment */ + struct req_iterator iter; + rq_for_each_segment(bio_vec, rq, iter) + /* bio_vec is now current segment */ I/O completion callbacks are per-bio rather than per-segment, so drivers that traverse bio chains on completion need to keep that in mind. Drivers diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index e35119a72a44..094c0fa5c405 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1244,8 +1244,7 @@ static void blk_recalc_rq_segments(struct request *rq) int seg_size; int hw_seg_size; int cluster; - struct bio *bio; - int i; + struct req_iterator iter; int high, highprv = 1; struct request_queue *q = rq->q; @@ -1255,8 +1254,7 @@ static void blk_recalc_rq_segments(struct request *rq) cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER); hw_seg_size = seg_size = 0; phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0; - rq_for_each_bio(bio, rq) - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, rq, iter) { /* * the trick here is making sure that a high page is never * considered part of another segment, since that might @@ -1353,8 +1351,8 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, struct scatterlist *sg) { struct bio_vec *bvec, *bvprv; - struct bio *bio; - int nsegs, i, cluster; + struct req_iterator iter; + int nsegs, cluster; nsegs = 0; cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER); @@ -1363,11 +1361,7 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, * for each bio in rq */ bvprv = NULL; - rq_for_each_bio(bio, rq) { - /* - * for each segment in bio - */ - bio_for_each_segment(bvec, bio, i) { + rq_for_each_segment(bvec, rq, iter) { int nbytes = bvec->bv_len; if (bvprv && cluster) { @@ -1390,8 +1384,7 @@ new_segment: nsegs++; } bvprv = bvec; - } /* segments in bio */ - } /* bios in rq */ + } /* segments in rq */ return nsegs; } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 085b7794fb3e..f0a86e201b44 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2437,22 +2437,19 @@ static void rw_interrupt(void) /* Compute maximal contiguous buffer size. */ static int buffer_chain_size(void) { - struct bio *bio; struct bio_vec *bv; - int size, i; + int size; + struct req_iterator iter; char *base; base = bio_data(current_req->bio); size = 0; - rq_for_each_bio(bio, current_req) { - bio_for_each_segment(bv, bio, i) { - if (page_address(bv->bv_page) + bv->bv_offset != - base + size) - break; + rq_for_each_segment(bv, current_req, iter) { + if (page_address(bv->bv_page) + bv->bv_offset != base + size) + break; - size += bv->bv_len; - } + size += bv->bv_len; } return size >> 9; @@ -2479,9 +2476,9 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) { int remaining; /* number of transferred 512-byte sectors */ struct bio_vec *bv; - struct bio *bio; char *buffer, *dma_buffer; - int size, i; + int size; + struct req_iterator iter; max_sector = transfer_size(ssize, min(max_sector, max_sector_2), @@ -2514,43 +2511,41 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) size = current_req->current_nr_sectors << 9; - rq_for_each_bio(bio, current_req) { - bio_for_each_segment(bv, bio, i) { - if (!remaining) - break; + rq_for_each_segment(bv, current_req, iter) { + if (!remaining) + break; - size = bv->bv_len; - SUPBOUND(size, remaining); + size = bv->bv_len; + SUPBOUND(size, remaining); - buffer = page_address(bv->bv_page) + bv->bv_offset; + buffer = page_address(bv->bv_page) + bv->bv_offset; #ifdef FLOPPY_SANITY_CHECK - if (dma_buffer + size > - floppy_track_buffer + (max_buffer_sectors << 10) || - dma_buffer < floppy_track_buffer) { - DPRINT("buffer overrun in copy buffer %d\n", - (int)((floppy_track_buffer - - dma_buffer) >> 9)); - printk("fsector_t=%d buffer_min=%d\n", - fsector_t, buffer_min); - printk("current_count_sectors=%ld\n", - current_count_sectors); - if (CT(COMMAND) == FD_READ) - printk("read\n"); - if (CT(COMMAND) == FD_WRITE) - printk("write\n"); - break; - } - if (((unsigned long)buffer) % 512) - DPRINT("%p buffer not aligned\n", buffer); -#endif + if (dma_buffer + size > + floppy_track_buffer + (max_buffer_sectors << 10) || + dma_buffer < floppy_track_buffer) { + DPRINT("buffer overrun in copy buffer %d\n", + (int)((floppy_track_buffer - + dma_buffer) >> 9)); + printk("fsector_t=%d buffer_min=%d\n", + fsector_t, buffer_min); + printk("current_count_sectors=%ld\n", + current_count_sectors); if (CT(COMMAND) == FD_READ) - memcpy(buffer, dma_buffer, size); - else - memcpy(dma_buffer, buffer, size); - - remaining -= size; - dma_buffer += size; + printk("read\n"); + if (CT(COMMAND) == FD_WRITE) + printk("write\n"); + break; } + if (((unsigned long)buffer) % 512) + DPRINT("%p buffer not aligned\n", buffer); +#endif + if (CT(COMMAND) == FD_READ) + memcpy(buffer, dma_buffer, size); + else + memcpy(dma_buffer, buffer, size); + + remaining -= size; + dma_buffer += size; } #ifdef FLOPPY_SANITY_CHECK if (remaining) { diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c index 160cf14431ac..1e838ae60a60 100644 --- a/drivers/block/lguest_blk.c +++ b/drivers/block/lguest_blk.c @@ -142,12 +142,11 @@ static irqreturn_t lgb_irq(int irq, void *_bd) * return the total length. */ static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma) { - unsigned int i = 0, idx, len = 0; - struct bio *bio; + unsigned int i = 0, len = 0; + struct req_iterator iter; + struct bio_vec *bvec; - rq_for_each_bio(bio, req) { - struct bio_vec *bvec; - bio_for_each_segment(bvec, bio, idx) { + rq_for_each_segment(bvec, req, iter) { /* We told the block layer not to give us too many. */ BUG_ON(i == LGUEST_MAX_DMA_SECTIONS); /* If we had a zero-length segment, it would look like @@ -160,7 +159,6 @@ static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma) dma->len[i] = bvec->bv_len; len += bvec->bv_len; i++; - } } /* If the array isn't full, we mark the end with a 0 length */ if (i < LGUEST_MAX_DMA_SECTIONS) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index be92c658f06e..228b2ff577aa 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -180,7 +180,7 @@ static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec, static int nbd_send_req(struct nbd_device *lo, struct request *req) { - int result, i, flags; + int result, flags; struct nbd_request request; unsigned long size = req->nr_sectors << 9; struct socket *sock = lo->sock; @@ -205,16 +205,15 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) } if (nbd_cmd(req) == NBD_CMD_WRITE) { - struct bio *bio; + struct req_iterator iter; + struct bio_vec *bvec; /* * we are really probing at internals to determine * whether to set MSG_MORE or not... */ - rq_for_each_bio(bio, req) { - struct bio_vec *bvec; - bio_for_each_segment(bvec, bio, i) { + rq_for_each_segment(bvec, req, iter) { flags = 0; - if ((i < (bio->bi_vcnt - 1)) || bio->bi_next) + if (!rq_iter_last(req, iter)) flags = MSG_MORE; dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", lo->disk->disk_name, req, @@ -226,7 +225,6 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) result); goto error_out; } - } } } return 0; @@ -321,11 +319,10 @@ static struct request *nbd_read_stat(struct nbd_device *lo) dprintk(DBG_RX, "%s: request %p: got reply\n", lo->disk->disk_name, req); if (nbd_cmd(req) == NBD_CMD_READ) { - int i; - struct bio *bio; - rq_for_each_bio(bio, req) { - struct bio_vec *bvec; - bio_for_each_segment(bvec, bio, i) { + struct req_iterator iter; + struct bio_vec *bvec; + + rq_for_each_segment(bvec, req, iter) { result = sock_recv_bvec(sock, bvec); if (result <= 0) { printk(KERN_ERR "%s: Receive data failed (result %d)\n", @@ -336,7 +333,6 @@ static struct request *nbd_read_stat(struct nbd_device *lo) } dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", lo->disk->disk_name, req, bvec->bv_len); - } } } return req; diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index aa8b890c80d7..8953e7ce0016 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -91,30 +91,30 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, struct request *req, int gather) { unsigned int offset = 0; - struct bio *bio; - sector_t sector; + struct req_iterator iter; struct bio_vec *bvec; - unsigned int i = 0, j; + unsigned int i = 0; size_t size; void *buf; - rq_for_each_bio(bio, req) { - sector = bio->bi_sector; + rq_for_each_segment(bvec, req, iter) { + unsigned long flags; dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u segs %u sectors from %lu\n", - __func__, __LINE__, i, bio_segments(bio), - bio_sectors(bio), sector); - bio_for_each_segment(bvec, bio, j) { + __func__, __LINE__, i, bio_segments(iter.bio), + bio_sectors(iter.bio), + (unsigned long)iter.bio->bi_sector); + size = bvec->bv_len; - buf = __bio_kmap_atomic(bio, j, KM_IRQ0); + buf = bvec_kmap_irq(bvec, &flags); if (gather) memcpy(dev->bounce_buf+offset, buf, size); else memcpy(buf, dev->bounce_buf+offset, size); offset += size; - flush_kernel_dcache_page(bio_iovec_idx(bio, j)->bv_page); - __bio_kunmap_atomic(bio, KM_IRQ0); - } + flush_kernel_dcache_page(bvec->bv_page); + bvec_kunmap_irq(bvec, &flags); + i++; } } @@ -130,12 +130,13 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, #ifdef DEBUG unsigned int n = 0; - struct bio *bio; + struct bio_vec *bv; + struct req_iterator iter; - rq_for_each_bio(bio, req) + rq_for_each_segment(bv, req, iter) n++; dev_dbg(&dev->sbd.core, - "%s:%u: %s req has %u bios for %lu sectors %lu hard sectors\n", + "%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n", __func__, __LINE__, op, n, req->nr_sectors, req->hard_nr_sectors); #endif diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 964e51634f2d..6af250113c2a 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -150,9 +150,8 @@ static int blkif_queue_request(struct request *req) struct blkfront_info *info = req->rq_disk->private_data; unsigned long buffer_mfn; struct blkif_request *ring_req; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bvec; - int idx; unsigned long id; unsigned int fsect, lsect; int ref; @@ -186,8 +185,7 @@ static int blkif_queue_request(struct request *req) ring_req->operation = BLKIF_OP_WRITE_BARRIER; ring_req->nr_segments = 0; - rq_for_each_bio (bio, req) { - bio_for_each_segment (bvec, bio, idx) { + rq_for_each_segment(bvec, req, iter) { BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST); buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page)); @@ -213,7 +211,6 @@ static int blkif_queue_request(struct request *req) .last_sect = lsect }; ring_req->nr_segments++; - } } info->ring.req_prod_pvt++; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index ae8e1a64b8ad..a775450d7a38 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -606,13 +606,12 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns { struct request *rq = pc->rq; struct bio_vec *bvec; - struct bio *bio; + struct req_iterator iter; unsigned long flags; char *data; - int count, i, done = 0; + int count, done = 0; - rq_for_each_bio(bio, rq) { - bio_for_each_segment(bvec, bio, i) { + rq_for_each_segment(bvec, rq, iter) { if (!bcount) break; @@ -625,7 +624,6 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns bcount -= count; pc->b_count += count; done += count; - } } idefloppy_do_end_request(drive, 1, done >> 9); @@ -639,14 +637,13 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount) { struct request *rq = pc->rq; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bvec; unsigned long flags; - int count, i, done = 0; + int count, done = 0; char *data; - rq_for_each_bio(bio, rq) { - bio_for_each_segment(bvec, bio, i) { + rq_for_each_segment(bvec, rq, iter) { if (!bcount) break; @@ -659,7 +656,6 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un bcount -= count; pc->b_count += count; done += count; - } } idefloppy_do_end_request(drive, 1, done >> 9); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index d32c60dbdd82..6bb9676f203e 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -472,14 +472,13 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) struct dasd_ccw_req *cqr; struct dasd_diag_req *dreq; struct dasd_diag_bio *dbio; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst; unsigned int count, datasize; sector_t recid, first_rec, last_rec; unsigned int blksize, off; unsigned char rw_cmd; - int i; if (rq_data_dir(req) == READ) rw_cmd = MDSK_READ_REQ; @@ -493,13 +492,11 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { if (bv->bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); count += bv->bv_len >> (device->s2b_shift + 9); - } } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -516,8 +513,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) dreq->block_count = count; dbio = dreq->bio; recid = first_rec; - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += blksize) { memset(dbio, 0, sizeof (struct dasd_diag_bio)); @@ -528,7 +524,6 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) dst += blksize; recid++; } - } } cqr->retries = DIAG_MAX_RETRIES; cqr->buildclk = get_clock(); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ea63ba7828f9..36ba45849874 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1176,7 +1176,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) struct LO_eckd_data *LO_data; struct dasd_ccw_req *cqr; struct ccw1 *ccw; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst; unsigned int blksize, blk_per_trk, off; @@ -1185,7 +1185,6 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) sector_t first_trk, last_trk; unsigned int first_offs, last_offs; unsigned char cmd, rcmd; - int i; private = (struct dasd_eckd_private *) device->private; if (rq_data_dir(req) == READ) @@ -1206,8 +1205,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { if (bv->bv_len & (blksize - 1)) /* Eckd can only do full blocks. */ return ERR_PTR(-EINVAL); @@ -1217,7 +1215,6 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) bv->bv_len)) cidaw += bv->bv_len >> (device->s2b_shift + 9); #endif - } } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -1257,7 +1254,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) locate_record(ccw++, LO_data++, first_trk, first_offs + 1, last_rec - recid + 1, cmd, device, blksize); } - rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; if (dasd_page_cache) { char *copy = kmem_cache_alloc(dasd_page_cache, @@ -1328,12 +1325,12 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) { struct dasd_eckd_private *private; struct ccw1 *ccw; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst, *cda; unsigned int blksize, blk_per_trk, off; sector_t recid; - int i, status; + int status; if (!dasd_page_cache) goto out; @@ -1346,7 +1343,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) ccw++; if (private->uses_cdl == 0 || recid > 2*blk_per_trk) ccw++; - rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += blksize) { /* Skip locate record. */ diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index da16ead8aff2..119b8d2d5f17 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -234,14 +234,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) struct LO_fba_data *LO_data; struct dasd_ccw_req *cqr; struct ccw1 *ccw; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst; int count, cidaw, cplength, datasize; sector_t recid, first_rec, last_rec; unsigned int blksize, off; unsigned char cmd; - int i; private = (struct dasd_fba_private *) device->private; if (rq_data_dir(req) == READ) { @@ -257,8 +256,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { if (bv->bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); @@ -268,7 +266,6 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) bv->bv_len)) cidaw += bv->bv_len / blksize; #endif - } } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -304,7 +301,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count); } recid = first_rec; - rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; if (dasd_page_cache) { char *copy = kmem_cache_alloc(dasd_page_cache, @@ -359,11 +356,11 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) { struct dasd_fba_private *private; struct ccw1 *ccw; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst, *cda; unsigned int blksize, off; - int i, status; + int status; if (!dasd_page_cache) goto out; @@ -374,7 +371,7 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) ccw++; if (private->rdc_data.mode.bits.data_chain != 0) ccw++; - rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += blksize) { /* Skip locate record. */ diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 80e7a537e7d2..ea3e6a345c89 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1134,21 +1134,18 @@ tape_34xx_bread(struct tape_device *device, struct request *req) { struct tape_request *request; struct ccw1 *ccw; - int count = 0, i; + int count = 0; unsigned off; char *dst; struct bio_vec *bv; - struct bio *bio; + struct req_iterator iter; struct tape_34xx_block_id * start_block; DBF_EVENT(6, "xBREDid:"); /* Count the number of blocks for the request. */ - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { - count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); - } - } + rq_for_each_segment(bv, req, iter) + count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); /* Allocate the ccw request. */ request = tape_alloc_request(3+count+1, 8); @@ -1175,8 +1172,7 @@ tape_34xx_bread(struct tape_device *device, struct request *req) ccw = tape_ccw_cc(ccw, NOP, 0, NULL); ccw = tape_ccw_cc(ccw, NOP, 0, NULL); - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = kmap(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { @@ -1187,7 +1183,6 @@ tape_34xx_bread(struct tape_device *device, struct request *req) ccw++; dst += TAPEBLOCK_HSEC_SIZE; } - } } ccw = tape_ccw_end(ccw, NOP, 0, NULL); diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 7e2b2ab49264..b16ad7a7631d 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -623,21 +623,19 @@ tape_3590_bread(struct tape_device *device, struct request *req) { struct tape_request *request; struct ccw1 *ccw; - int count = 0, start_block, i; + int count = 0, start_block; unsigned off; char *dst; struct bio_vec *bv; - struct bio *bio; + struct req_iterator iter; DBF_EVENT(6, "xBREDid:"); start_block = req->sector >> TAPEBLOCK_HSEC_S2B; DBF_EVENT(6, "start_block = %i\n", start_block); - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { - count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); - } - } + rq_for_each_segment(bv, req, iter) + count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); + request = tape_alloc_request(2 + count + 1, 4); if (IS_ERR(request)) return request; @@ -653,8 +651,7 @@ tape_3590_bread(struct tape_device *device, struct request *req) */ ccw = tape_ccw_cc(ccw, NOP, 0, NULL); - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { @@ -667,7 +664,6 @@ tape_3590_bread(struct tape_device *device, struct request *req) } if (off > bv->bv_len) BUG(); - } } ccw = tape_ccw_end(ccw, NOP, 0, NULL); DBF_EVENT(6, "xBREDccwg\n"); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index b126c6f68e27..a4b13b8a9d09 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -637,10 +637,23 @@ static inline void blk_queue_bounce(struct request_queue *q, struct bio **bio) } #endif /* CONFIG_MMU */ -#define rq_for_each_bio(_bio, rq) \ +struct req_iterator { + int i; + struct bio *bio; +}; + +/* This should not be used directly - use rq_for_each_segment */ +#define __rq_for_each_bio(_bio, rq) \ if ((rq->bio)) \ for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next) +#define rq_for_each_segment(bvl, _rq, _iter) \ + __rq_for_each_bio(_iter.bio, _rq) \ + bio_for_each_segment(bvl, _iter.bio, _iter.i) + +#define rq_iter_last(rq, _iter) \ + (_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1) + extern int blk_register_queue(struct gendisk *disk); extern void blk_unregister_queue(struct gendisk *disk); extern void register_disk(struct gendisk *dev); From eea9befaccb8d43ce89585d612159761c978f056 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2007 13:31:26 +0200 Subject: [PATCH 0905/2804] Fix various abuse of bio fields in umem.c umem.c: advances bi_idx and bi_sector to track where it is up to. But it is only ever doing this on one bio, so the updated fields can easily be kept elsewhere (current_*). updates bi_size, but never uses the updated values, so this isn't needed. reuses bi_phys_segments to count how many iovecs have been completely. As the completion happens sequentiually, we can store this information outside the bio too. Signed-off-by: Neil Brown diff .prev/drivers/block/umem.c ./drivers/block/umem.c Signed-off-by: Jens Axboe --- drivers/block/umem.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 6b7c02d6360d..c378e285d708 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -113,6 +113,8 @@ struct cardinfo { * have been written */ struct bio *bio, *currentbio, **biotail; + int current_idx; + sector_t current_sector; struct request_queue *queue; @@ -121,6 +123,7 @@ struct cardinfo { struct mm_dma_desc *desc; int cnt, headcnt; struct bio *bio, **biotail; + int idx; } mm_pages[2]; #define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc)) @@ -380,12 +383,16 @@ static int add_bio(struct cardinfo *card) dma_addr_t dma_handle; int offset; struct bio *bio; + struct bio_vec *vec; + int idx; int rw; int len; bio = card->currentbio; if (!bio && card->bio) { card->currentbio = card->bio; + card->current_idx = card->bio->bi_idx; + card->current_sector = card->bio->bi_sector; card->bio = card->bio->bi_next; if (card->bio == NULL) card->biotail = &card->bio; @@ -394,15 +401,17 @@ static int add_bio(struct cardinfo *card) } if (!bio) return 0; + idx = card->current_idx; rw = bio_rw(bio); if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE) return 0; - len = bio_iovec(bio)->bv_len; - dma_handle = pci_map_page(card->dev, - bio_page(bio), - bio_offset(bio), + vec = bio_iovec_idx(bio, idx); + len = vec->bv_len; + dma_handle = pci_map_page(card->dev, + vec->bv_page, + vec->bv_offset, len, (rw==READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); @@ -410,6 +419,8 @@ static int add_bio(struct cardinfo *card) p = &card->mm_pages[card->Ready]; desc = &p->desc[p->cnt]; p->cnt++; + if (p->bio == NULL) + p->idx = idx; if ((p->biotail) != &bio->bi_next) { *(p->biotail) = bio; p->biotail = &(bio->bi_next); @@ -419,7 +430,7 @@ static int add_bio(struct cardinfo *card) desc->data_dma_handle = dma_handle; desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle); - desc->local_addr= cpu_to_le64(bio->bi_sector << 9); + desc->local_addr = cpu_to_le64(card->current_sector << 9); desc->transfer_size = cpu_to_le32(len); offset = ( ((char*)&desc->sem_control_bits) - ((char*)p->desc)); desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset)); @@ -435,10 +446,10 @@ static int add_bio(struct cardinfo *card) desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ); desc->sem_control_bits = desc->control_bits; - bio->bi_sector += (len>>9); - bio->bi_size -= len; - bio->bi_idx++; - if (bio->bi_idx >= bio->bi_vcnt) + card->current_sector += (len >> 9); + idx++; + card->current_idx = idx; + if (idx >= bio->bi_vcnt) card->currentbio = NULL; return 1; @@ -474,10 +485,12 @@ static void process_page(unsigned long data) last=1; } page->headcnt++; - idx = bio->bi_phys_segments; - bio->bi_phys_segments++; - if (bio->bi_phys_segments >= bio->bi_vcnt) + idx = page->idx; + page->idx++; + if (page->idx >= bio->bi_vcnt) { page->bio = bio->bi_next; + page->idx = page->bio->bi_idx; + } pci_unmap_page(card->dev, desc->data_dma_handle, bio_iovec_idx(bio,idx)->bv_len, @@ -547,7 +560,6 @@ static int mm_make_request(struct request_queue *q, struct bio *bio) pr_debug("mm_make_request %llu %u\n", (unsigned long long)bio->bi_sector, bio->bi_size); - bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/ spin_lock_irq(&card->lock); *card->biotail = bio; bio->bi_next = NULL; From 3001ca77128273cc5634d79f5306ce2e5a14ec41 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2007 13:31:27 +0200 Subject: [PATCH 0906/2804] New function blk_req_append_bio ll_back_merge_fn is currently exported to SCSI where is it used, together with blk_rq_bio_prep, in exactly the same way these functions are used in __blk_rq_map_user. So move the common code into a new function (blk_rq_append_bio), and don't export ll_back_merge_fn any longer. Signed-off-by: Neil Brown diff .prev/block/ll_rw_blk.c ./block/ll_rw_blk.c Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 38 ++++++++++++++++++++++---------------- drivers/scsi/scsi_lib.c | 11 +---------- include/linux/blkdev.h | 4 ++-- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 094c0fa5c405..2de9bad1d042 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1441,7 +1441,8 @@ static inline int ll_new_hw_segment(struct request_queue *q, return 1; } -int ll_back_merge_fn(struct request_queue *q, struct request *req, struct bio *bio) +static int ll_back_merge_fn(struct request_queue *q, struct request *req, + struct bio *bio) { unsigned short max_sectors; int len; @@ -1477,7 +1478,6 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req, struct bio *b return ll_new_hw_segment(q, req, bio); } -EXPORT_SYMBOL(ll_back_merge_fn); static int ll_front_merge_fn(struct request_queue *q, struct request *req, struct bio *bio) @@ -2367,6 +2367,23 @@ static int __blk_rq_unmap_user(struct bio *bio) return ret; } +int blk_rq_append_bio(struct request_queue *q, struct request *rq, + struct bio *bio) +{ + if (!rq->bio) + blk_rq_bio_prep(q, rq, bio); + else if (!ll_back_merge_fn(q, rq, bio)) + return -EINVAL; + else { + rq->biotail->bi_next = bio; + rq->biotail = bio; + + rq->data_len += bio->bi_size; + } + return 0; +} +EXPORT_SYMBOL(blk_rq_append_bio); + static int __blk_rq_map_user(struct request_queue *q, struct request *rq, void __user *ubuf, unsigned int len) { @@ -2398,21 +2415,10 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq, */ bio_get(bio); - if (!rq->bio) - blk_rq_bio_prep(q, rq, bio); - else if (!ll_back_merge_fn(q, rq, bio)) { - ret = -EINVAL; - goto unmap_bio; - } else { - rq->biotail->bi_next = bio; - rq->biotail = bio; + ret = blk_rq_append_bio(q, rq, bio); + if (!ret) + return bio->bi_size; - rq->data_len += bio->bi_size; - } - - return bio->bi_size; - -unmap_bio: /* if it was boucned we must call the end io function */ bio_endio(bio, bio->bi_size, 0); __blk_rq_unmap_user(orig_bio); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index a417a6ff9f97..59b398530295 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -263,16 +263,7 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio) bio->bi_rw |= (1 << BIO_RW); blk_queue_bounce(q, &bio); - if (!rq->bio) - blk_rq_bio_prep(q, rq, bio); - else if (!ll_back_merge_fn(q, rq, bio)) - return -EINVAL; - else { - rq->biotail->bi_next = bio; - rq->biotail = bio; - } - - return 0; + return blk_rq_append_bio(q, rq, bio); } static int scsi_bi_endio(struct bio *bio, unsigned int bytes_done, int error) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a4b13b8a9d09..3021a5b1d392 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -675,8 +675,8 @@ extern int sg_scsi_ioctl(struct file *, struct request_queue *, /* * Temporary export, until SCSI gets fixed up. */ -extern int ll_back_merge_fn(struct request_queue *, struct request *, - struct bio *); +extern int blk_rq_append_bio(struct request_queue *q, struct request *rq, + struct bio *bio); /* * A queue has just exitted congestion. Note this in the global counter of From 66846572bfb4ec62bcba260028cbbcbdb77bd636 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2007 13:31:28 +0200 Subject: [PATCH 0907/2804] Stop exporting blk_rq_bio_prep blk_rq_bio_prep is exported for use in exactly one place. That place can benefit from using the new blk_rq_append_bio instead. So - change dm-emc to call blk_rq_append_bio - stop exporting blk_rq_bio_prep, and - initialise rq_disk in blk_rq_bio_prep, as dm-emc needs it. Signed-off-by: Neil Brown diff .prev/block/ll_rw_blk.c ./block/ll_rw_blk.c Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 11 +++++++---- drivers/md/dm-emc.c | 10 +--------- include/linux/blkdev.h | 1 - 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 2de9bad1d042..eb27b335d238 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -43,6 +43,8 @@ static void init_request_from_bio(struct request *req, struct bio *bio); static int __make_request(struct request_queue *q, struct bio *bio); static struct io_context *current_io_context(gfp_t gfp_flags, int node); static void blk_recalc_rq_segments(struct request *rq); +static void blk_rq_bio_prep(struct request_queue *q, struct request *rq, + struct bio *bio); /* * For the allocated request tables @@ -3665,8 +3667,8 @@ void end_request(struct request *req, int uptodate) EXPORT_SYMBOL(end_request); -void blk_rq_bio_prep(struct request_queue *q, struct request *rq, - struct bio *bio) +static void blk_rq_bio_prep(struct request_queue *q, struct request *rq, + struct bio *bio) { /* first two bits are identical in rq->cmd_flags and bio->bi_rw */ rq->cmd_flags |= (bio->bi_rw & 3); @@ -3680,9 +3682,10 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, rq->data_len = bio->bi_size; rq->bio = rq->biotail = bio; -} -EXPORT_SYMBOL(blk_rq_bio_prep); + if (bio->bi_bdev) + rq->rq_disk = bio->bi_bdev->bd_disk; +} int kblockd_schedule_work(struct work_struct *work) { diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index 265c467854da..71cc858b7860 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -109,15 +109,7 @@ static struct request *get_failover_req(struct emc_handler *h, return NULL; } - rq->bio = rq->biotail = bio; - blk_rq_bio_prep(q, rq, bio); - - rq->rq_disk = bdev->bd_contains->bd_disk; - - /* bio backed don't set data */ - rq->buffer = rq->data = NULL; - /* rq data_len used for pc cmd's request_bufflen */ - rq->data_len = bio->bi_size; + blk_rq_append_bio(q, rq, bio); rq->sense = h->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 3021a5b1d392..492ac946391e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -823,7 +823,6 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, return bqt->tag_index[tag]; } -extern void blk_rq_bio_prep(struct request_queue *, struct request *, struct bio *); extern int blkdev_issue_flush(struct block_device *, sector_t *); #define MAX_PHYS_SEGMENTS 128 From bc1c56fde6dd1c85e2047c276456c07bd4508b5c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2007 13:31:30 +0200 Subject: [PATCH 0908/2804] Share code between init_request_from_bio and blk_rq_bio_prep These have very similar functions and should share code where possible. Signed-off-by: Neil Brown diff .prev/block/ll_rw_blk.c ./block/ll_rw_blk.c Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index eb27b335d238..e0608c4ecc23 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2941,15 +2941,9 @@ static void init_request_from_bio(struct request *req, struct bio *bio) req->errors = 0; req->hard_sector = req->sector = bio->bi_sector; - req->hard_nr_sectors = req->nr_sectors = bio_sectors(bio); - req->current_nr_sectors = req->hard_cur_sectors = bio_cur_sectors(bio); - req->nr_phys_segments = bio_phys_segments(req->q, bio); - req->nr_hw_segments = bio_hw_segments(req->q, bio); - req->buffer = bio_data(bio); /* see ->buffer comment above */ - req->bio = req->biotail = bio; req->ioprio = bio_prio(bio); - req->rq_disk = bio->bi_bdev->bd_disk; req->start_time = jiffies; + blk_rq_bio_prep(req->q, req, bio); } static int __make_request(struct request_queue *q, struct bio *bio) From 6c92e699b56287da582ccb12a64b959b6d6109ba Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 16 Aug 2007 13:43:12 +0200 Subject: [PATCH 0909/2804] Fixup rq_for_each_segment() indentation Remove one level of nesting where appropriate. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 34 +++++++++++++-------------- drivers/block/lguest_blk.c | 24 +++++++++---------- drivers/block/nbd.c | 43 ++++++++++++++++------------------ drivers/block/ps3disk.c | 19 +++++++-------- drivers/block/xen-blkfront.c | 23 +++++++++--------- drivers/ide/ide-floppy.c | 36 ++++++++++++++-------------- drivers/s390/block/dasd_diag.c | 28 +++++++++++----------- drivers/s390/block/dasd_eckd.c | 13 +++++----- drivers/s390/block/dasd_fba.c | 13 +++++----- drivers/s390/char/tape_34xx.c | 19 +++++++-------- drivers/s390/char/tape_3590.c | 23 +++++++++--------- 11 files changed, 133 insertions(+), 142 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index e0608c4ecc23..c6b2a477d33e 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1364,28 +1364,28 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, */ bvprv = NULL; rq_for_each_segment(bvec, rq, iter) { - int nbytes = bvec->bv_len; + int nbytes = bvec->bv_len; - if (bvprv && cluster) { - if (sg[nsegs - 1].length + nbytes > q->max_segment_size) - goto new_segment; + if (bvprv && cluster) { + if (sg[nsegs - 1].length + nbytes > q->max_segment_size) + goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) - goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) - goto new_segment; + if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) + goto new_segment; + if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) + goto new_segment; - sg[nsegs - 1].length += nbytes; - } else { + sg[nsegs - 1].length += nbytes; + } else { new_segment: - memset(&sg[nsegs],0,sizeof(struct scatterlist)); - sg[nsegs].page = bvec->bv_page; - sg[nsegs].length = nbytes; - sg[nsegs].offset = bvec->bv_offset; + memset(&sg[nsegs],0,sizeof(struct scatterlist)); + sg[nsegs].page = bvec->bv_page; + sg[nsegs].length = nbytes; + sg[nsegs].offset = bvec->bv_offset; - nsegs++; - } - bvprv = bvec; + nsegs++; + } + bvprv = bvec; } /* segments in rq */ return nsegs; diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c index 1e838ae60a60..fa8e42341b87 100644 --- a/drivers/block/lguest_blk.c +++ b/drivers/block/lguest_blk.c @@ -147,18 +147,18 @@ static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma) struct bio_vec *bvec; rq_for_each_segment(bvec, req, iter) { - /* We told the block layer not to give us too many. */ - BUG_ON(i == LGUEST_MAX_DMA_SECTIONS); - /* If we had a zero-length segment, it would look like - * the end of the data referred to by the "struct - * lguest_dma", so make sure that doesn't happen. */ - BUG_ON(!bvec->bv_len); - /* Convert page & offset to a physical address */ - dma->addr[i] = page_to_phys(bvec->bv_page) - + bvec->bv_offset; - dma->len[i] = bvec->bv_len; - len += bvec->bv_len; - i++; + /* We told the block layer not to give us too many. */ + BUG_ON(i == LGUEST_MAX_DMA_SECTIONS); + /* If we had a zero-length segment, it would look like + * the end of the data referred to by the "struct + * lguest_dma", so make sure that doesn't happen. */ + BUG_ON(!bvec->bv_len); + /* Convert page & offset to a physical address */ + dma->addr[i] = page_to_phys(bvec->bv_page) + + bvec->bv_offset; + dma->len[i] = bvec->bv_len; + len += bvec->bv_len; + i++; } /* If the array isn't full, we mark the end with a 0 length */ if (i < LGUEST_MAX_DMA_SECTIONS) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 228b2ff577aa..be5ec3a9b1fc 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -212,19 +212,17 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) * whether to set MSG_MORE or not... */ rq_for_each_segment(bvec, req, iter) { - flags = 0; - if (!rq_iter_last(req, iter)) - flags = MSG_MORE; - dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", - lo->disk->disk_name, req, - bvec->bv_len); - result = sock_send_bvec(sock, bvec, flags); - if (result <= 0) { - printk(KERN_ERR "%s: Send data failed (result %d)\n", - lo->disk->disk_name, - result); - goto error_out; - } + flags = 0; + if (!rq_iter_last(req, iter)) + flags = MSG_MORE; + dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", + lo->disk->disk_name, req, bvec->bv_len); + result = sock_send_bvec(sock, bvec, flags); + if (result <= 0) { + printk(KERN_ERR "%s: Send data failed (result %d)\n", + lo->disk->disk_name, result); + goto error_out; + } } } return 0; @@ -323,16 +321,15 @@ static struct request *nbd_read_stat(struct nbd_device *lo) struct bio_vec *bvec; rq_for_each_segment(bvec, req, iter) { - result = sock_recv_bvec(sock, bvec); - if (result <= 0) { - printk(KERN_ERR "%s: Receive data failed (result %d)\n", - lo->disk->disk_name, - result); - req->errors++; - return req; - } - dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", - lo->disk->disk_name, req, bvec->bv_len); + result = sock_recv_bvec(sock, bvec); + if (result <= 0) { + printk(KERN_ERR "%s: Receive data failed (result %d)\n", + lo->disk->disk_name, result); + req->errors++; + return req; + } + dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", + lo->disk->disk_name, req, bvec->bv_len); } } return req; diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 8953e7ce0016..06d0552cf49c 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -105,16 +105,15 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, bio_sectors(iter.bio), (unsigned long)iter.bio->bi_sector); - size = bvec->bv_len; - buf = bvec_kmap_irq(bvec, &flags); - if (gather) - memcpy(dev->bounce_buf+offset, buf, size); - else - memcpy(buf, dev->bounce_buf+offset, size); - offset += size; - flush_kernel_dcache_page(bvec->bv_page); - bvec_kunmap_irq(bvec, &flags); - + size = bvec->bv_len; + buf = bvec_kmap_irq(bvec, &flags); + if (gather) + memcpy(dev->bounce_buf+offset, buf, size); + else + memcpy(buf, dev->bounce_buf+offset, size); + offset += size; + flush_kernel_dcache_page(bvec->bv_page); + bvec_kunmap_irq(bvec, &flags); i++; } } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 6af250113c2a..2bdebcb3ff16 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -186,31 +186,30 @@ static int blkif_queue_request(struct request *req) ring_req->nr_segments = 0; rq_for_each_segment(bvec, req, iter) { - BUG_ON(ring_req->nr_segments - == BLKIF_MAX_SEGMENTS_PER_REQUEST); - buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page)); - fsect = bvec->bv_offset >> 9; - lsect = fsect + (bvec->bv_len >> 9) - 1; - /* install a grant reference. */ - ref = gnttab_claim_grant_reference(&gref_head); - BUG_ON(ref == -ENOSPC); + BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST); + buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page)); + fsect = bvec->bv_offset >> 9; + lsect = fsect + (bvec->bv_len >> 9) - 1; + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head); + BUG_ON(ref == -ENOSPC); - gnttab_grant_foreign_access_ref( + gnttab_grant_foreign_access_ref( ref, info->xbdev->otherend_id, buffer_mfn, rq_data_dir(req) ); - info->shadow[id].frame[ring_req->nr_segments] = + info->shadow[id].frame[ring_req->nr_segments] = mfn_to_pfn(buffer_mfn); - ring_req->seg[ring_req->nr_segments] = + ring_req->seg[ring_req->nr_segments] = (struct blkif_request_segment) { .gref = ref, .first_sect = fsect, .last_sect = lsect }; - ring_req->nr_segments++; + ring_req->nr_segments++; } info->ring.req_prod_pvt++; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index a775450d7a38..04a357808f2e 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -612,18 +612,18 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns int count, done = 0; rq_for_each_segment(bvec, rq, iter) { - if (!bcount) - break; + if (!bcount) + break; - count = min(bvec->bv_len, bcount); + count = min(bvec->bv_len, bcount); - data = bvec_kmap_irq(bvec, &flags); - drive->hwif->atapi_input_bytes(drive, data, count); - bvec_kunmap_irq(data, &flags); + data = bvec_kmap_irq(bvec, &flags); + drive->hwif->atapi_input_bytes(drive, data, count); + bvec_kunmap_irq(data, &flags); - bcount -= count; - pc->b_count += count; - done += count; + bcount -= count; + pc->b_count += count; + done += count; } idefloppy_do_end_request(drive, 1, done >> 9); @@ -644,18 +644,18 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un char *data; rq_for_each_segment(bvec, rq, iter) { - if (!bcount) - break; + if (!bcount) + break; - count = min(bvec->bv_len, bcount); + count = min(bvec->bv_len, bcount); - data = bvec_kmap_irq(bvec, &flags); - drive->hwif->atapi_output_bytes(drive, data, count); - bvec_kunmap_irq(data, &flags); + data = bvec_kmap_irq(bvec, &flags); + drive->hwif->atapi_output_bytes(drive, data, count); + bvec_kunmap_irq(data, &flags); - bcount -= count; - pc->b_count += count; - done += count; + bcount -= count; + pc->b_count += count; + done += count; } idefloppy_do_end_request(drive, 1, done >> 9); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 6bb9676f203e..571320ab9e1a 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -493,10 +493,10 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) /* Check struct bio and count the number of blocks for the request. */ count = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) - /* Fba can only do full blocks. */ - return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + if (bv->bv_len & (blksize - 1)) + /* Fba can only do full blocks. */ + return ERR_PTR(-EINVAL); + count += bv->bv_len >> (device->s2b_shift + 9); } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -514,16 +514,16 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) dbio = dreq->bio; recid = first_rec; rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; off += blksize) { - memset(dbio, 0, sizeof (struct dasd_diag_bio)); - dbio->type = rw_cmd; - dbio->block_number = recid + 1; - dbio->buffer = dst; - dbio++; - dst += blksize; - recid++; - } + dst = page_address(bv->bv_page) + bv->bv_offset; + for (off = 0; off < bv->bv_len; off += blksize) { + memset(dbio, 0, sizeof (struct dasd_diag_bio)); + dbio->type = rw_cmd; + dbio->block_number = recid + 1; + dbio->buffer = dst; + dbio++; + dst += blksize; + recid++; + } } cqr->retries = DIAG_MAX_RETRIES; cqr->buildclk = get_clock(); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 36ba45849874..44adf8496bda 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1206,14 +1206,13 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) count = 0; cidaw = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) - /* Eckd can only do full blocks. */ - return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + if (bv->bv_len & (blksize - 1)) + /* Eckd can only do full blocks. */ + return ERR_PTR(-EINVAL); + count += bv->bv_len >> (device->s2b_shift + 9); #if defined(CONFIG_64BIT) - if (idal_is_needed (page_address(bv->bv_page), - bv->bv_len)) - cidaw += bv->bv_len >> (device->s2b_shift + 9); + if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) + cidaw += bv->bv_len >> (device->s2b_shift + 9); #endif } /* Paranoia. */ diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 119b8d2d5f17..1d95822e0b8e 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -257,14 +257,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) count = 0; cidaw = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) - /* Fba can only do full blocks. */ - return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + if (bv->bv_len & (blksize - 1)) + /* Fba can only do full blocks. */ + return ERR_PTR(-EINVAL); + count += bv->bv_len >> (device->s2b_shift + 9); #if defined(CONFIG_64BIT) - if (idal_is_needed (page_address(bv->bv_page), - bv->bv_len)) - cidaw += bv->bv_len / blksize; + if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) + cidaw += bv->bv_len / blksize; #endif } /* Paranoia. */ diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index ea3e6a345c89..5b47e9cce75f 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1173,16 +1173,15 @@ tape_34xx_bread(struct tape_device *device, struct request *req) ccw = tape_ccw_cc(ccw, NOP, 0, NULL); rq_for_each_segment(bv, req, iter) { - dst = kmap(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; - off += TAPEBLOCK_HSEC_SIZE) { - ccw->flags = CCW_FLAG_CC; - ccw->cmd_code = READ_FORWARD; - ccw->count = TAPEBLOCK_HSEC_SIZE; - set_normalized_cda(ccw, (void*) __pa(dst)); - ccw++; - dst += TAPEBLOCK_HSEC_SIZE; - } + dst = kmap(bv->bv_page) + bv->bv_offset; + for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { + ccw->flags = CCW_FLAG_CC; + ccw->cmd_code = READ_FORWARD; + ccw->count = TAPEBLOCK_HSEC_SIZE; + set_normalized_cda(ccw, (void*) __pa(dst)); + ccw++; + dst += TAPEBLOCK_HSEC_SIZE; + } } ccw = tape_ccw_end(ccw, NOP, 0, NULL); diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index b16ad7a7631d..9f244c591eeb 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -652,18 +652,17 @@ tape_3590_bread(struct tape_device *device, struct request *req) ccw = tape_ccw_cc(ccw, NOP, 0, NULL); rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; - off += TAPEBLOCK_HSEC_SIZE) { - ccw->flags = CCW_FLAG_CC; - ccw->cmd_code = READ_FORWARD; - ccw->count = TAPEBLOCK_HSEC_SIZE; - set_normalized_cda(ccw, (void *) __pa(dst)); - ccw++; - dst += TAPEBLOCK_HSEC_SIZE; - } - if (off > bv->bv_len) - BUG(); + dst = page_address(bv->bv_page) + bv->bv_offset; + for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { + ccw->flags = CCW_FLAG_CC; + ccw->cmd_code = READ_FORWARD; + ccw->count = TAPEBLOCK_HSEC_SIZE; + set_normalized_cda(ccw, (void *) __pa(dst)); + ccw++; + dst += TAPEBLOCK_HSEC_SIZE; + } + if (off > bv->bv_len) + BUG(); } ccw = tape_ccw_end(ccw, NOP, 0, NULL); DBF_EVENT(6, "xBREDccwg\n"); From db47d475371bc85dd122112e957669cbbcc70dee Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Thu, 23 Aug 2007 09:29:40 +0200 Subject: [PATCH 0910/2804] ll_rw_blk: blk_cpu_notifier should be __cpuinitdata blk_cpu_notifier is marked as __devinitdata, but __devinitdata need not be __init even if HOTPLUG_CPU=n, which wastes space. It should be marked __cpuinitdata, and the callback itself as __cpuinit. Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index c6b2a477d33e..3b2eff4e83a6 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -3555,7 +3555,7 @@ static void blk_done_softirq(struct softirq_action *h) } } -static int blk_cpu_notify(struct notifier_block *self, unsigned long action, +static int __cpuinit blk_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { /* @@ -3576,7 +3576,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action, } -static struct notifier_block __devinitdata blk_cpu_notifier = { +static struct notifier_block blk_cpu_notifier __cpuinitdata = { .notifier_call = blk_cpu_notify, }; From 3317fedba9446465082bcc6ce1232451ad1d51ce Mon Sep 17 00:00:00 2001 From: Dhaval Giani Date: Thu, 23 Aug 2007 10:43:07 +0200 Subject: [PATCH 0911/2804] Corrections in Documentation/block/ioprio.txt The newer glibc does not allow system calls to be made via _syscallN() wrapper. They have to be made through syscall(). The ionice code used the older interface. Correcting it to use syscall. Signed-off-by: Dhaval Giani Signed-off-by: Jens Axboe --- Documentation/block/ioprio.txt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/block/ioprio.txt b/Documentation/block/ioprio.txt index 1b930ef5a079..35e516b0b8a9 100644 --- a/Documentation/block/ioprio.txt +++ b/Documentation/block/ioprio.txt @@ -86,8 +86,15 @@ extern int sys_ioprio_get(int, int); #error "Unsupported arch" #endif -_syscall3(int, ioprio_set, int, which, int, who, int, ioprio); -_syscall2(int, ioprio_get, int, which, int, who); +static inline int ioprio_set(int which, int who, int ioprio) +{ + return syscall(__NR_ioprio_set, which, who, ioprio); +} + +static inline int ioprio_get(int which, int who) +{ + return syscall(__NR_ioprio_get, which, who); +} enum { IOPRIO_CLASS_NONE, From f5ff8422bbdd59f8c1f699df248e1b7a11073027 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 21 Sep 2007 09:19:54 +0200 Subject: [PATCH 0912/2804] Fix warnings with !CONFIG_BLOCK Hide everything in blkdev.h with CONFIG_BLOCK isn't set, and fixup the (few) files that fail to build because they were relying on blkdev.h pulling in extra includes for them. Signed-off-by: Jens Axboe --- fs/fs-writeback.c | 1 + include/linux/blkdev.h | 4 ++-- include/linux/writeback.h | 1 + kernel/sched.c | 1 + mm/readahead.c | 1 + 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index a4b142a6a2c7..8d23b0b38717 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 492ac946391e..a0a998140447 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1,6 +1,8 @@ #ifndef _LINUX_BLKDEV_H #define _LINUX_BLKDEV_H +#ifdef CONFIG_BLOCK + #include #include #include @@ -32,8 +34,6 @@ ) #endif -#ifdef CONFIG_BLOCK - struct scsi_ioctl_command; struct request_queue; diff --git a/include/linux/writeback.h b/include/linux/writeback.h index b4af6bcb7b7a..c7c3337c3a88 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -5,6 +5,7 @@ #define WRITEBACK_H #include +#include struct backing_dev_info; diff --git a/kernel/sched.c b/kernel/sched.c index 6107a0cd6325..6c10fa796ca0 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -61,6 +61,7 @@ #include #include #include +#include #include diff --git a/mm/readahead.c b/mm/readahead.c index 39bf45d43320..be20c9d699d3 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -15,6 +15,7 @@ #include #include #include +#include void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) { From d24517d793f21edab1a411da95f2c45cb88a84aa Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 27 Sep 2007 12:46:11 +0200 Subject: [PATCH 0913/2804] Remove flush_dry_bio_endio The entire function of flush_dry_bio_endio is to undo the effects of bio_endio (when called on a barrier request). So remove the function and the call to bio_endio. This allows us to remove "bi_size" from "struct request_queue". Signed-off-by: Neil Brown ### Diffstat output ./block/ll_rw_blk.c | 39 ++------------------------------------- ./include/linux/blkdev.h | 1 - 2 files changed, 2 insertions(+), 38 deletions(-) diff .prev/block/ll_rw_blk.c ./block/ll_rw_blk.c Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 39 ++------------------------------------- include/linux/blkdev.h | 1 - 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 3b2eff4e83a6..dfe0948ec8b2 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -431,7 +431,6 @@ static void queue_flush(struct request_queue *q, unsigned which) static inline struct request *start_ordered(struct request_queue *q, struct request *rq) { - q->bi_size = 0; q->orderr = 0; q->ordered = q->next_ordered; q->ordseq |= QUEUE_ORDSEQ_STARTED; @@ -528,55 +527,21 @@ int blk_do_ordered(struct request_queue *q, struct request **rqp) return 1; } -static int flush_dry_bio_endio(struct bio *bio, unsigned int bytes, int error) -{ - struct request_queue *q = bio->bi_private; - - /* - * This is dry run, restore bio_sector and size. We'll finish - * this request again with the original bi_end_io after an - * error occurs or post flush is complete. - */ - q->bi_size += bytes; - - if (bio->bi_size) - return 1; - - /* Reset bio */ - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio->bi_size = q->bi_size; - bio->bi_sector -= (q->bi_size >> 9); - q->bi_size = 0; - - return 0; -} - static int ordered_bio_endio(struct request *rq, struct bio *bio, unsigned int nbytes, int error) { struct request_queue *q = rq->q; - bio_end_io_t *endio; - void *private; if (&q->bar_rq != rq) return 0; /* - * Okay, this is the barrier request in progress, dry finish it. + * Okay, this is the barrier request in progress, just + * record the error; */ if (error && !q->orderr) q->orderr = error; - endio = bio->bi_end_io; - private = bio->bi_private; - bio->bi_end_io = flush_dry_bio_endio; - bio->bi_private = q; - - bio_endio(bio, nbytes, error); - - bio->bi_end_io = endio; - bio->bi_private = private; - return 1; } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a0a998140447..95be0ac57e76 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -471,7 +471,6 @@ struct request_queue int orderr, ordcolor; struct request pre_flush_rq, bar_rq, post_flush_rq; struct request *orig_bar_rq; - unsigned int bi_size; struct mutex sysfs_lock; From 9cc54d40b8ca01fcefc9151044b6996565061d90 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 27 Sep 2007 12:46:12 +0200 Subject: [PATCH 0914/2804] Only call bi_end_io once for any bio Currently bi_end_io can be called multiple times as sub-requests complete. However no ->bi_end_io function wants to know about that. So only call when the bio is complete. Signed-off-by: Neil Brown ### Diffstat output ./fs/bio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff .prev/fs/bio.c ./fs/bio.c Signed-off-by: Jens Axboe --- fs/bio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/bio.c b/fs/bio.c index 29a44c1b64c6..5720b940bb5f 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1018,6 +1018,8 @@ void bio_endio(struct bio *bio, unsigned int bytes_done, int error) { if (error) clear_bit(BIO_UPTODATE, &bio->bi_flags); + else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + error = -EIO; if (unlikely(bytes_done > bio->bi_size)) { printk("%s: want %u bytes done, only %u left\n", __FUNCTION__, @@ -1028,7 +1030,7 @@ void bio_endio(struct bio *bio, unsigned int bytes_done, int error) bio->bi_size -= bytes_done; bio->bi_sector += (bytes_done >> 9); - if (bio->bi_end_io) + if (bio->bi_size && bio->bi_end_io) bio->bi_end_io(bio, bytes_done, error); } From 5bb23a688b2de23d7765a1dd439d89c038378978 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 27 Sep 2007 12:46:13 +0200 Subject: [PATCH 0915/2804] Don't decrement bi_size in bio_endio The only caller of bio_endio that does not pass the full bi_size is end_that_request_first. Also, no ->bi_end_io method is really interested in bi_size being decremented. So move the decrement and related code into ll_rw_blk and merge it with order_bio_endio to form req_bio_endio which does endio functionality specific to request completion. As some ->bi_end_io methods do check bi_size of 0, we set it thus for now, but that will go in the next patch. Signed-off-by: Neil Brown ### Diffstat output ./block/ll_rw_blk.c | 42 +++++++++++++++++++++++++++--------------- ./fs/bio.c | 23 +++++++++++------------ 2 files changed, 38 insertions(+), 27 deletions(-) diff .prev/block/ll_rw_blk.c ./block/ll_rw_blk.c Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 42 +++++++++++++++++++++++++++--------------- fs/bio.c | 23 +++++++++++------------ 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index dfe0948ec8b2..b55ed0df33f0 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -527,22 +527,36 @@ int blk_do_ordered(struct request_queue *q, struct request **rqp) return 1; } -static int ordered_bio_endio(struct request *rq, struct bio *bio, - unsigned int nbytes, int error) +static void req_bio_endio(struct request *rq, struct bio *bio, + unsigned int nbytes, int error) { struct request_queue *q = rq->q; - if (&q->bar_rq != rq) - return 0; + if (&q->bar_rq != rq) { + if (error) + clear_bit(BIO_UPTODATE, &bio->bi_flags); + else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + error = -EIO; - /* - * Okay, this is the barrier request in progress, just - * record the error; - */ - if (error && !q->orderr) - q->orderr = error; + if (unlikely(nbytes > bio->bi_size)) { + printk("%s: want %u bytes done, only %u left\n", + __FUNCTION__, nbytes, bio->bi_size); + nbytes = bio->bi_size; + } - return 1; + bio->bi_size -= nbytes; + bio->bi_sector += (nbytes >> 9); + if (bio->bi_size == 0) + bio_endio(bio, bio->bi_size, error); + } else { + + /* + * Okay, this is the barrier request in progress, just + * record the error; + */ + if (error && !q->orderr) + q->orderr = error; + } } /** @@ -3388,8 +3402,7 @@ static int __end_that_request_first(struct request *req, int uptodate, if (nr_bytes >= bio->bi_size) { req->bio = bio->bi_next; nbytes = bio->bi_size; - if (!ordered_bio_endio(req, bio, nbytes, error)) - bio_endio(bio, nbytes, error); + req_bio_endio(req, bio, nbytes, error); next_idx = 0; bio_nbytes = 0; } else { @@ -3444,8 +3457,7 @@ static int __end_that_request_first(struct request *req, int uptodate, * if the request wasn't completed, update state */ if (bio_nbytes) { - if (!ordered_bio_endio(req, bio, bio_nbytes, error)) - bio_endio(bio, bio_nbytes, error); + req_bio_endio(req, bio, bio_nbytes, error); bio->bi_idx += next_idx; bio_iovec(bio)->bv_offset += nr_bytes; bio_iovec(bio)->bv_len -= nr_bytes; diff --git a/fs/bio.c b/fs/bio.c index 5720b940bb5f..3adecd64ff6e 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1006,13 +1006,14 @@ void bio_check_pages_dirty(struct bio *bio) * @error: error, if any * * Description: - * bio_endio() will end I/O on @bytes_done number of bytes. This may be - * just a partial part of the bio, or it may be the whole bio. bio_endio() - * is the preferred way to end I/O on a bio, it takes care of decrementing - * bi_size and clearing BIO_UPTODATE on error. @error is 0 on success, and - * and one of the established -Exxxx (-EIO, for instance) error values in - * case something went wrong. Noone should call bi_end_io() directly on - * a bio unless they own it and thus know that it has an end_io function. + * bio_endio() will end I/O on @bytes_done number of bytes. This + * must always be the whole (remaining) bio. bio_endio() is the + * preferred way to end I/O on a bio, it takes care of clearing + * BIO_UPTODATE on error. @error is 0 on success, and and one of the + * established -Exxxx (-EIO, for instance) error values in case + * something went wrong. Noone should call bi_end_io() directly on a + * bio unless they own it and thus know that it has an end_io + * function. **/ void bio_endio(struct bio *bio, unsigned int bytes_done, int error) { @@ -1021,16 +1022,14 @@ void bio_endio(struct bio *bio, unsigned int bytes_done, int error) else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) error = -EIO; - if (unlikely(bytes_done > bio->bi_size)) { + if (unlikely(bytes_done != bio->bi_size)) { printk("%s: want %u bytes done, only %u left\n", __FUNCTION__, bytes_done, bio->bi_size); bytes_done = bio->bi_size; } - bio->bi_size -= bytes_done; - bio->bi_sector += (bytes_done >> 9); - - if (bio->bi_size && bio->bi_end_io) + bio->bi_size = 0; /* expected by some callees - will be removed */ + if (bio->bi_end_io) bio->bi_end_io(bio, bytes_done, error); } From 6712ecf8f648118c3363c142196418f89a510b90 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 27 Sep 2007 12:47:43 +0200 Subject: [PATCH 0916/2804] Drop 'size' argument from bio_endio and bi_end_io As bi_end_io is only called once when the reqeust is complete, the 'size' argument is now redundant. Remove it. Now there is no need for bio_endio to subtract the size completed from bi_size. So don't do that either. While we are at it, change bi_end_io to return void. Signed-off-by: Neil Brown Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 10 ++++---- drivers/block/aoe/aoeblk.c | 4 +-- drivers/block/aoe/aoecmd.c | 2 +- drivers/block/aoe/aoedev.c | 4 +-- drivers/block/cciss.c | 2 +- drivers/block/cpqarray.c | 2 +- drivers/block/floppy.c | 6 +---- drivers/block/loop.c | 4 +-- drivers/block/pktcdvd.c | 25 +++++-------------- drivers/block/rd.c | 4 +-- drivers/block/umem.c | 2 +- drivers/md/dm-crypt.c | 21 ++++++---------- drivers/md/dm-emc.c | 5 +--- drivers/md/dm-io.c | 8 +----- drivers/md/dm-mpath.c | 4 +-- drivers/md/dm-raid1.c | 4 +-- drivers/md/dm-snap.c | 2 +- drivers/md/dm-zero.c | 2 +- drivers/md/dm.c | 18 ++++++-------- drivers/md/faulty.c | 10 +++----- drivers/md/linear.c | 4 +-- drivers/md/md.c | 25 ++++++------------- drivers/md/multipath.c | 13 +++------- drivers/md/raid0.c | 4 +-- drivers/md/raid1.c | 30 ++++++---------------- drivers/md/raid10.c | 31 ++++++----------------- drivers/md/raid5.c | 48 ++++++++++++------------------------ drivers/s390/block/dcssblk.c | 4 +-- drivers/s390/block/xpram.c | 6 ++--- drivers/scsi/scsi_lib.c | 10 +++----- fs/bio.c | 35 ++++++-------------------- fs/block_dev.c | 2 +- fs/buffer.c | 6 +---- fs/direct-io.c | 13 ++-------- fs/gfs2/super.c | 4 +-- fs/jfs/jfs_logmgr.c | 5 +--- fs/jfs/jfs_metapage.c | 12 ++------- fs/mpage.c | 12 ++------- fs/ocfs2/cluster/heartbeat.c | 4 --- fs/xfs/linux-2.6/xfs_aops.c | 4 --- fs/xfs/linux-2.6/xfs_buf.c | 4 --- include/linux/bio.h | 6 ++--- include/linux/swap.h | 2 +- mm/bounce.c | 25 ++++--------------- mm/page_io.c | 12 ++------- 45 files changed, 132 insertions(+), 328 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index b55ed0df33f0..cd9d2c5d91ae 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -547,7 +547,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, bio->bi_size -= nbytes; bio->bi_sector += (nbytes >> 9); if (bio->bi_size == 0) - bio_endio(bio, bio->bi_size, error); + bio_endio(bio, error); } else { /* @@ -2401,7 +2401,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq, return bio->bi_size; /* if it was boucned we must call the end io function */ - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); __blk_rq_unmap_user(orig_bio); bio_put(bio); return ret; @@ -2510,7 +2510,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, return PTR_ERR(bio); if (bio->bi_size != len) { - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); bio_unmap_user(bio); return -EINVAL; } @@ -3040,7 +3040,7 @@ out: return 0; end_io: - bio_endio(bio, nr_sectors << 9, err); + bio_endio(bio, err); return 0; } @@ -3187,7 +3187,7 @@ static inline void __generic_make_request(struct bio *bio) bdevname(bio->bi_bdev, b), (long long) bio->bi_sector); end_io: - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); break; } diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 007faaf008e7..b1d00ef6659c 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -138,7 +138,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) buf = mempool_alloc(d->bufpool, GFP_NOIO); if (buf == NULL) { printk(KERN_INFO "aoe: buf allocation failure\n"); - bio_endio(bio, bio->bi_size, -ENOMEM); + bio_endio(bio, -ENOMEM); return 0; } memset(buf, 0, sizeof(*buf)); @@ -159,7 +159,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) d->aoemajor, d->aoeminor); spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -ENXIO); + bio_endio(bio, -ENXIO); return 0; } diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 01fbdd38e3be..5abae34ad65b 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -652,7 +652,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) disk_stat_add(disk, sectors[rw], n_sect); disk_stat_add(disk, io_ticks, duration); n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; - bio_endio(buf->bio, buf->bio->bi_size, n); + bio_endio(buf->bio, n); mempool_free(buf, d->bufpool); } } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 05a97197c918..51f50710e5fc 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -119,7 +119,7 @@ aoedev_downdev(struct aoedev *d) bio = buf->bio; if (--buf->nframesout == 0) { mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); } skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; } @@ -130,7 +130,7 @@ aoedev_downdev(struct aoedev *d) list_del(d->bufq.next); bio = buf->bio; mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); } if (d->gd) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 084358a828e9..28d145756f6c 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1194,7 +1194,7 @@ static inline void complete_buffers(struct bio *bio, int status) int nr_sectors = bio_sectors(bio); bio->bi_next = NULL; - bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); + bio_endio(bio, status ? 0 : -EIO); bio = xbh; } } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index eb9799acf65b..3853c9a38d6a 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -987,7 +987,7 @@ static inline void complete_buffers(struct bio *bio, int ok) xbh = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO); + bio_endio(bio, ok ? 0 : -EIO); bio = xbh; } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index f0a86e201b44..80483aac4cc9 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3810,14 +3810,10 @@ static int check_floppy_change(struct gendisk *disk) * a disk in the drive, and whether that disk is writable. */ -static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done, +static void floppy_rb0_complete(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - complete((struct completion *)bio->bi_private); - return 0; } static int __floppy_read_block_0(struct block_device *bdev) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 9f015fce4135..b9233a06934c 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -551,7 +551,7 @@ static int loop_make_request(struct request_queue *q, struct bio *old_bio) out: spin_unlock_irq(&lo->lo_lock); - bio_io_error(old_bio, old_bio->bi_size); + bio_io_error(old_bio); return 0; } @@ -580,7 +580,7 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio) bio_put(bio); } else { int ret = do_bio_filebacked(lo, bio); - bio_endio(bio, bio->bi_size, ret); + bio_endio(bio, ret); } } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index fadbfd880bab..540bf3676985 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1058,15 +1058,12 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec) } } -static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err) +static void pkt_end_io_read(struct bio *bio, int err) { struct packet_data *pkt = bio->bi_private; struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - if (bio->bi_size) - return 1; - VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err); @@ -1077,19 +1074,14 @@ static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err) wake_up(&pd->wqueue); } pkt_bio_finished(pd); - - return 0; } -static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int err) +static void pkt_end_io_packet_write(struct bio *bio, int err) { struct packet_data *pkt = bio->bi_private; struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - if (bio->bi_size) - return 1; - VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err); pd->stats.pkt_ended++; @@ -1098,7 +1090,6 @@ static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int atomic_dec(&pkt->io_wait); atomic_inc(&pkt->run_sm); wake_up(&pd->wqueue); - return 0; } /* @@ -1470,7 +1461,7 @@ static void pkt_finish_packet(struct packet_data *pkt, int uptodate) while (bio) { next = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); + bio_endio(bio, uptodate ? 0 : -EIO); bio = next; } pkt->orig_bios = pkt->orig_bios_tail = NULL; @@ -2462,19 +2453,15 @@ static int pkt_close(struct inode *inode, struct file *file) } -static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err) +static void pkt_end_io_read_cloned(struct bio *bio, int err) { struct packet_stacked_data *psd = bio->bi_private; struct pktcdvd_device *pd = psd->pd; - if (bio->bi_size) - return 1; - bio_put(bio); - bio_endio(psd->bio, psd->bio->bi_size, err); + bio_endio(psd->bio, err); mempool_free(psd, psd_pool); pkt_bio_finished(pd); - return 0; } static int pkt_make_request(struct request_queue *q, struct bio *bio) @@ -2620,7 +2607,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) } return 0; end_io: - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 65150b548f3a..701ea77f62e9 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -287,10 +287,10 @@ static int rd_make_request(struct request_queue *q, struct bio *bio) if (ret) goto fail; - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); return 0; fail: - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/block/umem.c b/drivers/block/umem.c index c378e285d708..be7fac86725e 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -545,7 +545,7 @@ static void process_page(unsigned long data) return_bio = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); } } diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index bdc52d6922b7..8216a6f75be5 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -489,7 +489,7 @@ static void dec_pending(struct dm_crypt_io *io, int error) if (!atomic_dec_and_test(&io->pending)) return; - bio_endio(io->base_bio, io->base_bio->bi_size, io->error); + bio_endio(io->base_bio, io->error); mempool_free(io, cc->io_pool); } @@ -509,25 +509,19 @@ static void kcryptd_queue_io(struct dm_crypt_io *io) queue_work(_kcryptd_workqueue, &io->work); } -static int crypt_endio(struct bio *clone, unsigned int done, int error) +static void crypt_endio(struct bio *clone, int error) { struct dm_crypt_io *io = clone->bi_private; struct crypt_config *cc = io->target->private; unsigned read_io = bio_data_dir(clone) == READ; /* - * free the processed pages, even if - * it's only a partially completed write + * free the processed pages */ - if (!read_io) - crypt_free_buffer_pages(cc, clone, done); - - /* keep going - not finished yet */ - if (unlikely(clone->bi_size)) - return 1; - - if (!read_io) + if (!read_io) { + crypt_free_buffer_pages(cc, clone, clone->bi_size); goto out; + } if (unlikely(!bio_flagged(clone, BIO_UPTODATE))) { error = -EIO; @@ -537,12 +531,11 @@ static int crypt_endio(struct bio *clone, unsigned int done, int error) bio_put(clone); io->post_process = 1; kcryptd_queue_io(io); - return 0; + return; out: bio_put(clone); dec_pending(io, error); - return error; } static void clone_init(struct dm_crypt_io *io, struct bio *clone) diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index 71cc858b7860..a2191a4fcf77 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -38,13 +38,10 @@ static inline void free_bio(struct bio *bio) bio_put(bio); } -static int emc_endio(struct bio *bio, unsigned int bytes_done, int error) +static void emc_endio(struct bio *bio, int error) { struct dm_path *path = bio->bi_private; - if (bio->bi_size) - return 1; - /* We also need to look at the sense keys here whether or not to * switch to the next PG etc. * diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index f3a772486437..b8e342fe7586 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -124,15 +124,11 @@ static void dec_count(struct io *io, unsigned int region, int error) } } -static int endio(struct bio *bio, unsigned int done, int error) +static void endio(struct bio *bio, int error) { struct io *io; unsigned region; - /* keep going until we've finished */ - if (bio->bi_size) - return 1; - if (error && bio_data_dir(bio) == READ) zero_fill_bio(bio); @@ -146,8 +142,6 @@ static int endio(struct bio *bio, unsigned int done, int error) bio_put(bio); dec_count(io, region, error); - - return 0; } /*----------------------------------------------------------------- diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index d6ca9d0a6fd1..31056abca89d 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -390,11 +390,11 @@ static void dispatch_queued_ios(struct multipath *m) r = map_io(m, bio, mpio, 1); if (r < 0) - bio_endio(bio, bio->bi_size, r); + bio_endio(bio, r); else if (r == DM_MAPIO_REMAPPED) generic_make_request(bio); else if (r == DM_MAPIO_REQUEUE) - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); bio = next; } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 144071e70a93..d09ff15490a5 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -820,7 +820,7 @@ static void write_callback(unsigned long error, void *context) break; } } - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); } static void do_write(struct mirror_set *ms, struct bio *bio) @@ -900,7 +900,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) */ if (unlikely(ms->log_failure)) while ((bio = bio_list_pop(&sync))) - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); else while ((bio = bio_list_pop(&sync))) do_write(ms, bio); diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 83ddbfe6b8a4..98a633f3d6b0 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -636,7 +636,7 @@ static void error_bios(struct bio *bio) while (bio) { n = bio->bi_next; bio->bi_next = NULL; - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); bio = n; } } diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c index f314d7dc9c26..bdec206c404b 100644 --- a/drivers/md/dm-zero.c +++ b/drivers/md/dm-zero.c @@ -43,7 +43,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio, break; } - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); /* accepted bio, don't make new request */ return DM_MAPIO_SUBMITTED; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 2120155929a6..167765c47747 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -484,23 +484,20 @@ static void dec_pending(struct dm_io *io, int error) blk_add_trace_bio(io->md->queue, io->bio, BLK_TA_COMPLETE); - bio_endio(io->bio, io->bio->bi_size, io->error); + bio_endio(io->bio, io->error); } free_io(io->md, io); } } -static int clone_endio(struct bio *bio, unsigned int done, int error) +static void clone_endio(struct bio *bio, int error) { int r = 0; struct dm_target_io *tio = bio->bi_private; struct mapped_device *md = tio->io->md; dm_endio_fn endio = tio->ti->type->end_io; - if (bio->bi_size) - return 1; - if (!bio_flagged(bio, BIO_UPTODATE) && !error) error = -EIO; @@ -514,7 +511,7 @@ static int clone_endio(struct bio *bio, unsigned int done, int error) error = r; else if (r == DM_ENDIO_INCOMPLETE) /* The target will handle the io */ - return 1; + return; else if (r) { DMWARN("unimplemented target endio return value: %d", r); BUG(); @@ -530,7 +527,6 @@ static int clone_endio(struct bio *bio, unsigned int done, int error) bio_put(bio); free_tio(md, tio); - return r; } static sector_t max_io_len(struct mapped_device *md, @@ -761,7 +757,7 @@ static void __split_bio(struct mapped_device *md, struct bio *bio) ci.map = dm_get_table(md); if (!ci.map) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return; } @@ -803,7 +799,7 @@ static int dm_request(struct request_queue *q, struct bio *bio) * guarantee it is (or can be) handled by the targets correctly. */ if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -820,13 +816,13 @@ static int dm_request(struct request_queue *q, struct bio *bio) up_read(&md->io_lock); if (bio_rw(bio) == READA) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } r = queue_io(md, bio); if (r < 0) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } else if (r == 0) diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index cb059cf14c2e..cf2ddce34118 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -65,18 +65,16 @@ #include -static int faulty_fail(struct bio *bio, unsigned int bytes_done, int error) +static void faulty_fail(struct bio *bio, int error) { struct bio *b = bio->bi_private; b->bi_size = bio->bi_size; b->bi_sector = bio->bi_sector; - if (bio->bi_size == 0) - bio_put(bio); + bio_put(bio); - clear_bit(BIO_UPTODATE, &b->bi_flags); - return (b->bi_end_io)(b, bytes_done, -EIO); + bio_io_error(b); } typedef struct faulty_conf { @@ -179,7 +177,7 @@ static int make_request(struct request_queue *q, struct bio *bio) /* special case - don't decrement, don't generic_make_request, * just fail immediately */ - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); return 0; } diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 17f795c3e0ab..550148770bb2 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -338,7 +338,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) sector_t block; if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -358,7 +358,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) bdevname(tmp_dev->rdev->bdev, b), (unsigned long long)tmp_dev->size, (unsigned long long)tmp_dev->offset); - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } if (unlikely(bio->bi_sector + (bio->bi_size >> 9) > diff --git a/drivers/md/md.c b/drivers/md/md.c index f883b7e37f3d..e8f102ea9b03 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -213,7 +213,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock); static int md_fail_request (struct request_queue *q, struct bio *bio) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } @@ -384,12 +384,10 @@ static void free_disk_sb(mdk_rdev_t * rdev) } -static int super_written(struct bio *bio, unsigned int bytes_done, int error) +static void super_written(struct bio *bio, int error) { mdk_rdev_t *rdev = bio->bi_private; mddev_t *mddev = rdev->mddev; - if (bio->bi_size) - return 1; if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) { printk("md: super_written gets error=%d, uptodate=%d\n", @@ -401,16 +399,13 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error) if (atomic_dec_and_test(&mddev->pending_writes)) wake_up(&mddev->sb_wait); bio_put(bio); - return 0; } -static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int error) +static void super_written_barrier(struct bio *bio, int error) { struct bio *bio2 = bio->bi_private; mdk_rdev_t *rdev = bio2->bi_private; mddev_t *mddev = rdev->mddev; - if (bio->bi_size) - return 1; if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && error == -EOPNOTSUPP) { @@ -424,11 +419,11 @@ static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int e spin_unlock_irqrestore(&mddev->write_lock, flags); wake_up(&mddev->sb_wait); bio_put(bio); - return 0; + } else { + bio_put(bio2); + bio->bi_private = rdev; + super_written(bio, error); } - bio_put(bio2); - bio->bi_private = rdev; - return super_written(bio, bytes_done, error); } void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, @@ -489,13 +484,9 @@ void md_super_wait(mddev_t *mddev) finish_wait(&mddev->sb_wait, &wq); } -static int bi_complete(struct bio *bio, unsigned int bytes_done, int error) +static void bi_complete(struct bio *bio, int error) { - if (bio->bi_size) - return 1; - complete((struct completion*)bio->bi_private); - return 0; } int sync_page_io(struct block_device *bdev, sector_t sector, int size, diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 1e2af43a73b9..f2a63f394ad9 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -82,21 +82,17 @@ static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err) struct bio *bio = mp_bh->master_bio; multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); - bio_endio(bio, bio->bi_size, err); + bio_endio(bio, err); mempool_free(mp_bh, conf->pool); } -static int multipath_end_request(struct bio *bio, unsigned int bytes_done, - int error) +static void multipath_end_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private); multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev; - if (bio->bi_size) - return 1; - if (uptodate) multipath_end_bh_io(mp_bh, 0); else if (!bio_rw_ahead(bio)) { @@ -112,7 +108,6 @@ static int multipath_end_request(struct bio *bio, unsigned int bytes_done, } else multipath_end_bh_io(mp_bh, error); rdev_dec_pending(rdev, conf->mddev); - return 0; } static void unplug_slaves(mddev_t *mddev) @@ -155,7 +150,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio) const int rw = bio_data_dir(bio); if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -169,7 +164,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio) mp_bh->path = multipath_map(conf); if (mp_bh->path < 0) { - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); mempool_free(mp_bh, conf->pool); return 0; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index b8216bc6db45..ef0da2d84959 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -420,7 +420,7 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio) const int rw = bio_data_dir(bio); if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -490,7 +490,7 @@ bad_map: " or bigger than %dk %llu %d\n", chunk_size, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f33a729960ca..6d03bea6fa58 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -238,7 +238,7 @@ static void raid_end_bio_io(r1bio_t *r1_bio) (unsigned long long) bio->bi_sector + (bio->bi_size >> 9) - 1); - bio_endio(bio, bio->bi_size, + bio_endio(bio, test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO); } free_r1bio(r1_bio); @@ -255,16 +255,13 @@ static inline void update_head_pos(int disk, r1bio_t *r1_bio) r1_bio->sector + (r1_bio->sectors); } -static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int error) +static void raid1_end_read_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); int mirror; conf_t *conf = mddev_to_conf(r1_bio->mddev); - if (bio->bi_size) - return 1; - mirror = r1_bio->read_disk; /* * this branch is our 'one mirror IO has finished' event handler: @@ -301,10 +298,9 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int } rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); - return 0; } -static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int error) +static void raid1_end_write_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); @@ -312,8 +308,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int conf_t *conf = mddev_to_conf(r1_bio->mddev); struct bio *to_put = NULL; - if (bio->bi_size) - return 1; for (mirror = 0; mirror < conf->raid_disks; mirror++) if (r1_bio->bios[mirror] == bio) @@ -366,7 +360,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int (unsigned long long) mbio->bi_sector, (unsigned long long) mbio->bi_sector + (mbio->bi_size >> 9) - 1); - bio_endio(mbio, mbio->bi_size, 0); + bio_endio(mbio, 0); } } } @@ -400,8 +394,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int if (to_put) bio_put(to_put); - - return 0; } @@ -796,7 +788,7 @@ static int make_request(struct request_queue *q, struct bio * bio) if (unlikely(!mddev->barriers_work && bio_barrier(bio))) { if (rw == WRITE) md_write_end(mddev); - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -1137,14 +1129,11 @@ abort: } -static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) +static void end_sync_read(struct bio *bio, int error) { r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); int i; - if (bio->bi_size) - return 1; - for (i=r1_bio->mddev->raid_disks; i--; ) if (r1_bio->bios[i] == bio) break; @@ -1160,10 +1149,9 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) if (atomic_dec_and_test(&r1_bio->remaining)) reschedule_retry(r1_bio); - return 0; } -static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) +static void end_sync_write(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); @@ -1172,9 +1160,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) int i; int mirror=0; - if (bio->bi_size) - return 1; - for (i = 0; i < conf->raid_disks; i++) if (r1_bio->bios[i] == bio) { mirror = i; @@ -1200,7 +1185,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) md_done_sync(mddev, r1_bio->sectors, uptodate); put_buf(r1_bio); } - return 0; } static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 4e53792aa520..25a96c42bdb0 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -227,7 +227,7 @@ static void raid_end_bio_io(r10bio_t *r10_bio) { struct bio *bio = r10_bio->master_bio; - bio_endio(bio, bio->bi_size, + bio_endio(bio, test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO); free_r10bio(r10_bio); } @@ -243,15 +243,13 @@ static inline void update_head_pos(int slot, r10bio_t *r10_bio) r10_bio->devs[slot].addr + (r10_bio->sectors); } -static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int error) +static void raid10_end_read_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); int slot, dev; conf_t *conf = mddev_to_conf(r10_bio->mddev); - if (bio->bi_size) - return 1; slot = r10_bio->read_slot; dev = r10_bio->devs[slot].devnum; @@ -284,19 +282,15 @@ static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int } rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); - return 0; } -static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, int error) +static void raid10_end_write_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); int slot, dev; conf_t *conf = mddev_to_conf(r10_bio->mddev); - if (bio->bi_size) - return 1; - for (slot = 0; slot < conf->copies; slot++) if (r10_bio->devs[slot].bio == bio) break; @@ -339,7 +333,6 @@ static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, in } rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); - return 0; } @@ -787,7 +780,7 @@ static int make_request(struct request_queue *q, struct bio * bio) unsigned long flags; if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -819,7 +812,7 @@ static int make_request(struct request_queue *q, struct bio * bio) " or bigger than %dk %llu %d\n", chunk_sects/2, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } @@ -1155,15 +1148,12 @@ abort: } -static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) +static void end_sync_read(struct bio *bio, int error) { r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); conf_t *conf = mddev_to_conf(r10_bio->mddev); int i,d; - if (bio->bi_size) - return 1; - for (i=0; icopies; i++) if (r10_bio->devs[i].bio == bio) break; @@ -1192,10 +1182,9 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) reschedule_retry(r10_bio); } rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev); - return 0; } -static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) +static void end_sync_write(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); @@ -1203,9 +1192,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) conf_t *conf = mddev_to_conf(mddev); int i,d; - if (bio->bi_size) - return 1; - for (i = 0; i < conf->copies; i++) if (r10_bio->devs[i].bio == bio) break; @@ -1228,7 +1214,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) } } rdev_dec_pending(conf->mirrors[d].rdev, mddev); - return 0; } /* @@ -1374,7 +1359,7 @@ static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio) if (test_bit(R10BIO_Uptodate, &r10_bio->state)) generic_make_request(wbio); else - bio_endio(wbio, wbio->bi_size, -EIO); + bio_endio(wbio, -EIO); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f96dea975fa5..caaca9e178bc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -108,12 +108,11 @@ static void return_io(struct bio *return_bi) { struct bio *bi = return_bi; while (bi) { - int bytes = bi->bi_size; return_bi = bi->bi_next; bi->bi_next = NULL; bi->bi_size = 0; - bi->bi_end_io(bi, bytes, + bi->bi_end_io(bi, test_bit(BIO_UPTODATE, &bi->bi_flags) ? 0 : -EIO); bi = return_bi; @@ -382,10 +381,10 @@ static unsigned long get_stripe_work(struct stripe_head *sh) return pending; } -static int -raid5_end_read_request(struct bio *bi, unsigned int bytes_done, int error); -static int -raid5_end_write_request (struct bio *bi, unsigned int bytes_done, int error); +static void +raid5_end_read_request(struct bio *bi, int error); +static void +raid5_end_write_request(struct bio *bi, int error); static void ops_run_io(struct stripe_head *sh) { @@ -1110,8 +1109,7 @@ static void shrink_stripes(raid5_conf_t *conf) conf->slab_cache = NULL; } -static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, - int error) +static void raid5_end_read_request(struct bio * bi, int error) { struct stripe_head *sh = bi->bi_private; raid5_conf_t *conf = sh->raid_conf; @@ -1120,8 +1118,6 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; - if (bi->bi_size) - return 1; for (i=0 ; idev[i].req) @@ -1132,7 +1128,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, uptodate); if (i == disks) { BUG(); - return 0; + return; } if (uptodate) { @@ -1185,20 +1181,15 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); - return 0; } -static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, - int error) +static void raid5_end_write_request (struct bio *bi, int error) { struct stripe_head *sh = bi->bi_private; raid5_conf_t *conf = sh->raid_conf; int disks = sh->disks, i; int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); - if (bi->bi_size) - return 1; - for (i=0 ; idev[i].req) break; @@ -1208,7 +1199,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, uptodate); if (i == disks) { BUG(); - return 0; + return; } if (!uptodate) @@ -1219,7 +1210,6 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); - return 0; } @@ -3340,7 +3330,7 @@ static struct bio *remove_bio_from_retry(raid5_conf_t *conf) * first). * If the read failed.. */ -static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error) +static void raid5_align_endio(struct bio *bi, int error) { struct bio* raid_bi = bi->bi_private; mddev_t *mddev; @@ -3348,8 +3338,6 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error) int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); mdk_rdev_t *rdev; - if (bi->bi_size) - return 1; bio_put(bi); mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata; @@ -3360,17 +3348,16 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error) rdev_dec_pending(rdev, conf->mddev); if (!error && uptodate) { - bio_endio(raid_bi, bytes, 0); + bio_endio(raid_bi, 0); if (atomic_dec_and_test(&conf->active_aligned_reads)) wake_up(&conf->wait_for_stripe); - return 0; + return; } pr_debug("raid5_align_endio : io error...handing IO for a retry\n"); add_bio_to_retry(raid_bi, conf); - return 0; } static int bio_fits_rdev(struct bio *bi) @@ -3476,7 +3463,7 @@ static int make_request(struct request_queue *q, struct bio * bi) int remaining; if (unlikely(bio_barrier(bi))) { - bio_endio(bi, bi->bi_size, -EOPNOTSUPP); + bio_endio(bi, -EOPNOTSUPP); return 0; } @@ -3592,12 +3579,11 @@ static int make_request(struct request_queue *q, struct bio * bi) remaining = --bi->bi_phys_segments; spin_unlock_irq(&conf->device_lock); if (remaining == 0) { - int bytes = bi->bi_size; if ( rw == WRITE ) md_write_end(mddev); - bi->bi_size = 0; - bi->bi_end_io(bi, bytes, + + bi->bi_end_io(bi, test_bit(BIO_UPTODATE, &bi->bi_flags) ? 0 : -EIO); } @@ -3875,10 +3861,8 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio) remaining = --raid_bio->bi_phys_segments; spin_unlock_irq(&conf->device_lock); if (remaining == 0) { - int bytes = raid_bio->bi_size; - raid_bio->bi_size = 0; - raid_bio->bi_end_io(raid_bio, bytes, + raid_bio->bi_end_io(raid_bio, test_bit(BIO_UPTODATE, &raid_bio->bi_flags) ? 0 : -EIO); } diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 4d8798bacf97..859f870552e3 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -674,10 +674,10 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) } bytes_done += bvec->bv_len; } - bio_endio(bio, bytes_done, 0); + bio_endio(bio, 0); return 0; fail: - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 354a060e5bec..0fbacc8b1063 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -230,12 +230,10 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } } set_bit(BIO_UPTODATE, &bio->bi_flags); - bytes = bio->bi_size; - bio->bi_size = 0; - bio->bi_end_io(bio, bytes, 0); + bio_end_io(bio, 0); return 0; fail: - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 59b398530295..604f4d717933 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -266,13 +266,9 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio) return blk_rq_append_bio(q, rq, bio); } -static int scsi_bi_endio(struct bio *bio, unsigned int bytes_done, int error) +static void scsi_bi_endio(struct bio *bio, int error) { - if (bio->bi_size) - return 1; - bio_put(bio); - return 0; } /** @@ -328,7 +324,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, if (bio->bi_vcnt >= nr_vecs) { err = scsi_merge_bio(rq, bio); if (err) { - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); goto free_bios; } bio = NULL; @@ -350,7 +346,7 @@ free_bios: /* * call endio instead of bio_put incase it was bounced */ - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); } return err; diff --git a/fs/bio.c b/fs/bio.c index 3adecd64ff6e..5f604f269dfa 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -798,13 +798,9 @@ void bio_unmap_user(struct bio *bio) bio_put(bio); } -static int bio_map_kern_endio(struct bio *bio, unsigned int bytes_done, int err) +static void bio_map_kern_endio(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - bio_put(bio); - return 0; } @@ -1002,12 +998,10 @@ void bio_check_pages_dirty(struct bio *bio) /** * bio_endio - end I/O on a bio * @bio: bio - * @bytes_done: number of bytes completed * @error: error, if any * * Description: - * bio_endio() will end I/O on @bytes_done number of bytes. This - * must always be the whole (remaining) bio. bio_endio() is the + * bio_endio() will end I/O on the whole bio. bio_endio() is the * preferred way to end I/O on a bio, it takes care of clearing * BIO_UPTODATE on error. @error is 0 on success, and and one of the * established -Exxxx (-EIO, for instance) error values in case @@ -1015,22 +1009,15 @@ void bio_check_pages_dirty(struct bio *bio) * bio unless they own it and thus know that it has an end_io * function. **/ -void bio_endio(struct bio *bio, unsigned int bytes_done, int error) +void bio_endio(struct bio *bio, int error) { if (error) clear_bit(BIO_UPTODATE, &bio->bi_flags); else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) error = -EIO; - if (unlikely(bytes_done != bio->bi_size)) { - printk("%s: want %u bytes done, only %u left\n", __FUNCTION__, - bytes_done, bio->bi_size); - bytes_done = bio->bi_size; - } - - bio->bi_size = 0; /* expected by some callees - will be removed */ if (bio->bi_end_io) - bio->bi_end_io(bio, bytes_done, error); + bio->bi_end_io(bio, error); } void bio_pair_release(struct bio_pair *bp) @@ -1038,37 +1025,29 @@ void bio_pair_release(struct bio_pair *bp) if (atomic_dec_and_test(&bp->cnt)) { struct bio *master = bp->bio1.bi_private; - bio_endio(master, master->bi_size, bp->error); + bio_endio(master, bp->error); mempool_free(bp, bp->bio2.bi_private); } } -static int bio_pair_end_1(struct bio * bi, unsigned int done, int err) +static void bio_pair_end_1(struct bio *bi, int err) { struct bio_pair *bp = container_of(bi, struct bio_pair, bio1); if (err) bp->error = err; - if (bi->bi_size) - return 1; - bio_pair_release(bp); - return 0; } -static int bio_pair_end_2(struct bio * bi, unsigned int done, int err) +static void bio_pair_end_2(struct bio *bi, int err) { struct bio_pair *bp = container_of(bi, struct bio_pair, bio2); if (err) bp->error = err; - if (bi->bi_size) - return 1; - bio_pair_release(bp); - return 0; } /* diff --git a/fs/block_dev.c b/fs/block_dev.c index 2980eabe5779..6339a30879b7 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -172,7 +172,7 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, } #if 0 -static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error) +static void blk_end_aio(struct bio *bio, int error) { struct kiocb *iocb = bio->bi_private; atomic_t *bio_count = &iocb->ki_bio_count; diff --git a/fs/buffer.c b/fs/buffer.c index 0e5ec371ce72..75b51dfa5e03 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2634,13 +2634,10 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block, return tmp.b_blocknr; } -static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) +static void end_bio_bh_io_sync(struct bio *bio, int err) { struct buffer_head *bh = bio->bi_private; - if (bio->bi_size) - return 1; - if (err == -EOPNOTSUPP) { set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); set_bit(BH_Eopnotsupp, &bh->b_state); @@ -2648,7 +2645,6 @@ static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); bio_put(bio); - return 0; } int submit_bh(int rw, struct buffer_head * bh) diff --git a/fs/direct-io.c b/fs/direct-io.c index 901dc55e9f54..b5928a7b6a5a 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -264,15 +264,12 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio); /* * Asynchronous IO callback. */ -static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) +static void dio_bio_end_aio(struct bio *bio, int error) { struct dio *dio = bio->bi_private; unsigned long remaining; unsigned long flags; - if (bio->bi_size) - return 1; - /* cleanup the bio */ dio_bio_complete(dio, bio); @@ -287,8 +284,6 @@ static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) aio_complete(dio->iocb, ret, 0); kfree(dio); } - - return 0; } /* @@ -298,21 +293,17 @@ static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) * During I/O bi_private points at the dio. After I/O, bi_private is used to * implement a singly-linked list of completed BIOs, at dio->bio_list. */ -static int dio_bio_end_io(struct bio *bio, unsigned int bytes_done, int error) +static void dio_bio_end_io(struct bio *bio, int error) { struct dio *dio = bio->bi_private; unsigned long flags; - if (bio->bi_size) - return 1; - spin_lock_irqsave(&dio->bio_lock, flags); bio->bi_private = dio->bio_list; dio->bio_list = bio; if (--dio->refcount == 1 && dio->waiter) wake_up_process(dio->waiter); spin_unlock_irqrestore(&dio->bio_lock, flags); - return 0; } static int diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f916b9740c75..2473e2a86d1b 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -160,11 +160,9 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent) } -static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error) +static void end_bio_io_page(struct bio *bio, int error) { struct page *page = bio->bi_private; - if (bio->bi_size) - return 1; if (!error) SetPageUptodate(page); diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index de3e4a506dbc..57c3b8ac36bf 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2200,16 +2200,13 @@ static int lbmIOWait(struct lbuf * bp, int flag) * * executed at INTIODONE level */ -static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error) +static void lbmIODone(struct bio *bio, int error) { struct lbuf *bp = bio->bi_private; struct lbuf *nextbp, *tail; struct jfs_log *log; unsigned long flags; - if (bio->bi_size) - return 1; - /* * get back jfs buffer bound to the i/o buffer */ diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 62e96be02acf..1332adc0b9fa 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -280,14 +280,10 @@ static void last_read_complete(struct page *page) unlock_page(page); } -static int metapage_read_end_io(struct bio *bio, unsigned int bytes_done, - int err) +static void metapage_read_end_io(struct bio *bio, int err) { struct page *page = bio->bi_private; - if (bio->bi_size) - return 1; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { printk(KERN_ERR "metapage_read_end_io: I/O error\n"); SetPageError(page); @@ -341,16 +337,12 @@ static void last_write_complete(struct page *page) end_page_writeback(page); } -static int metapage_write_end_io(struct bio *bio, unsigned int bytes_done, - int err) +static void metapage_write_end_io(struct bio *bio, int err) { struct page *page = bio->bi_private; BUG_ON(!PagePrivate(page)); - if (bio->bi_size) - return 1; - if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) { printk(KERN_ERR "metapage_write_end_io: I/O error\n"); SetPageError(page); diff --git a/fs/mpage.c b/fs/mpage.c index c1698f2291aa..b1c3e5890508 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -39,14 +39,11 @@ * status of that page is hard. See end_buffer_async_read() for the details. * There is no point in duplicating all that complexity. */ -static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err) +static void mpage_end_io_read(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - do { struct page *page = bvec->bv_page; @@ -62,17 +59,13 @@ static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err) unlock_page(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); - return 0; } -static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) +static void mpage_end_io_write(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - do { struct page *page = bvec->bv_page; @@ -87,7 +80,6 @@ static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) end_page_writeback(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); - return 0; } static struct bio *mpage_bio_submit(int rw, struct bio *bio) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 2bd7f788cf34..da2c2b442b49 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -217,7 +217,6 @@ static void o2hb_wait_on_io(struct o2hb_region *reg, } static int o2hb_bio_end_io(struct bio *bio, - unsigned int bytes_done, int error) { struct o2hb_bio_wait_ctxt *wc = bio->bi_private; @@ -227,9 +226,6 @@ static int o2hb_bio_end_io(struct bio *bio, wc->wc_error = error; } - if (bio->bi_size) - return 1; - o2hb_bio_wait_dec(wc, 1); bio_put(bio); return 0; diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 5f152f60d74d..3f13519436af 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -326,14 +326,10 @@ xfs_iomap_valid( STATIC int xfs_end_bio( struct bio *bio, - unsigned int bytes_done, int error) { xfs_ioend_t *ioend = bio->bi_private; - if (bio->bi_size) - return 1; - ASSERT(atomic_read(&bio->bi_cnt) >= 1); ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index b0f0e58866de..6a75f4d984a1 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1106,16 +1106,12 @@ _xfs_buf_ioend( STATIC int xfs_buf_bio_end_io( struct bio *bio, - unsigned int bytes_done, int error) { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; unsigned int blocksize = bp->b_target->bt_bsize; struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) bp->b_error = EIO; diff --git a/include/linux/bio.h b/include/linux/bio.h index 1ddef34f43c3..089a8bc55dd4 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -64,7 +64,7 @@ struct bio_vec { struct bio_set; struct bio; -typedef int (bio_end_io_t) (struct bio *, unsigned int, int); +typedef void (bio_end_io_t) (struct bio *, int); typedef void (bio_destructor_t) (struct bio *); /* @@ -226,7 +226,7 @@ struct bio { #define BIO_SEG_BOUNDARY(q, b1, b2) \ BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2))) -#define bio_io_error(bio, bytes) bio_endio((bio), (bytes), -EIO) +#define bio_io_error(bio) bio_endio((bio), -EIO) /* * drivers should not use the __ version unless they _really_ want to @@ -286,7 +286,7 @@ extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *); extern void bio_put(struct bio *); extern void bio_free(struct bio *, struct bio_set *); -extern void bio_endio(struct bio *, unsigned int, int); +extern void bio_endio(struct bio *, int); struct request_queue; extern int bio_phys_segments(struct request_queue *, struct bio *); extern int bio_hw_segments(struct request_queue *, struct bio *); diff --git a/include/linux/swap.h b/include/linux/swap.h index 665f85f2a3af..edf681a7fd8f 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -221,7 +221,7 @@ extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *); /* linux/mm/page_io.c */ extern int swap_readpage(struct file *, struct page *); extern int swap_writepage(struct page *page, struct writeback_control *wbc); -extern int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err); +extern void end_swap_bio_read(struct bio *bio, int err); /* linux/mm/swap_state.c */ extern struct address_space swapper_space; diff --git a/mm/bounce.c b/mm/bounce.c index 179fe38a2416..3b549bf31f7d 100644 --- a/mm/bounce.c +++ b/mm/bounce.c @@ -140,26 +140,19 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool, int err) mempool_free(bvec->bv_page, pool); } - bio_endio(bio_orig, bio_orig->bi_size, err); + bio_endio(bio_orig, err); bio_put(bio); } -static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, int err) +static void bounce_end_io_write(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - bounce_end_io(bio, page_pool, err); - return 0; } -static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, int err) +static void bounce_end_io_write_isa(struct bio *bio, int err) { - if (bio->bi_size) - return 1; bounce_end_io(bio, isa_page_pool, err); - return 0; } static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err) @@ -172,22 +165,14 @@ static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err) bounce_end_io(bio, pool, err); } -static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err) +static void bounce_end_io_read(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - __bounce_end_io_read(bio, page_pool, err); - return 0; } -static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, int err) +static void bounce_end_io_read_isa(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - __bounce_end_io_read(bio, isa_page_pool, err); - return 0; } static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, diff --git a/mm/page_io.c b/mm/page_io.c index dbffec0d78c9..3b97f6850273 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -44,14 +44,11 @@ static struct bio *get_swap_bio(gfp_t gfp_flags, pgoff_t index, return bio; } -static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err) +static void end_swap_bio_write(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (bio->bi_size) - return 1; - if (!uptodate) { SetPageError(page); /* @@ -71,17 +68,13 @@ static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err) } end_page_writeback(page); bio_put(bio); - return 0; } -int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err) +void end_swap_bio_read(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (bio->bi_size) - return 1; - if (!uptodate) { SetPageError(page); ClearPageUptodate(page); @@ -94,7 +87,6 @@ int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err) } unlock_page(page); bio_put(bio); - return 0; } /* From c9d3d8ecf672c513435691a886876aee5ab11001 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:51 +0200 Subject: [PATCH 0917/2804] Add Xilinx SystemACE entry to maintainers I'm the author of the SystemACE driver Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9a91d9e3f1f2..53144f4737ff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4176,6 +4176,13 @@ W: http://oss.sgi.com/projects/xfs T: git git://oss.sgi.com:8090/xfs/xfs-2.6.git S: Supported +XILINX SYSTEMACE DRIVER +P: Grant Likely +M: grant.likely@secretlab.ca +W: http://www.secretlab.ca/ +L: linux-kernel@vger.kernel.org +S: Maintained + XILINX UARTLITE SERIAL DRIVER P: Peter Korsgaard M: jacmet@sunsite.dk From edec49616c7b4ad7ceb3b936a8d95b10652ee677 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:52 +0200 Subject: [PATCH 0918/2804] Sysace: Use the established platform bus api SystemACE uses the platform bus binding, but it doesn't use the platform bus API. Move to using the correct API for consistency sake and future proofing against platform bus changes. Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 48 +++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 3ede0b63da13..b10447611afd 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1060,13 +1060,12 @@ static void __devexit ace_teardown(struct ace_device *ace) * Platform Bus Support */ -static int __devinit ace_probe(struct device *device) +static int __devinit ace_probe(struct platform_device *dev) { - struct platform_device *dev = to_platform_device(device); struct ace_device *ace; int i; - dev_dbg(device, "ace_probe(%p)\n", device); + dev_dbg(&dev->dev, "ace_probe(%p)\n", dev); /* * Allocate the ace device structure @@ -1075,7 +1074,7 @@ static int __devinit ace_probe(struct device *device) if (!ace) goto err_alloc; - ace->dev = device; + ace->dev = &dev->dev; ace->id = dev->id; ace->irq = NO_IRQ; @@ -1089,7 +1088,7 @@ static int __devinit ace_probe(struct device *device) /* FIXME: Should get bus_width from the platform_device struct */ ace->bus_width = 1; - dev_set_drvdata(&dev->dev, ace); + platform_set_drvdata(dev, ace); /* Call the bus-independant setup code */ if (ace_setup(ace) != 0) @@ -1098,7 +1097,7 @@ static int __devinit ace_probe(struct device *device) return 0; err_setup: - dev_set_drvdata(&dev->dev, NULL); + platform_set_drvdata(dev, NULL); kfree(ace); err_alloc: printk(KERN_ERR "xsysace: could not initialize device\n"); @@ -1108,25 +1107,27 @@ static int __devinit ace_probe(struct device *device) /* * Platform bus remove() method */ -static int __devexit ace_remove(struct device *device) +static int __devexit ace_remove(struct platform_device *dev) { - struct ace_device *ace = dev_get_drvdata(device); - - dev_dbg(device, "ace_remove(%p)\n", device); + struct ace_device *ace = platform_get_drvdata(dev); + dev_dbg(&dev->dev, "ace_remove(%p)\n", dev); if (ace) { ace_teardown(ace); + platform_set_drvdata(dev, NULL); kfree(ace); } return 0; } -static struct device_driver ace_driver = { - .name = "xsysace", - .bus = &platform_bus_type, +static struct platform_driver ace_platform_driver = { .probe = ace_probe, .remove = __devexit_p(ace_remove), + .driver = { + .owner = THIS_MODULE, + .name = "xsysace", + }, }; /* --------------------------------------------------------------------- @@ -1134,20 +1135,31 @@ static struct device_driver ace_driver = { */ static int __init ace_init(void) { + int rc; + ace_major = register_blkdev(ace_major, "xsysace"); if (ace_major <= 0) { - printk(KERN_WARNING "xsysace: register_blkdev() failed\n"); - return ace_major; + rc = -ENOMEM; + goto err_blk; } - pr_debug("Registering Xilinx SystemACE driver, major=%i\n", ace_major); - return driver_register(&ace_driver); + if ((rc = platform_driver_register(&ace_platform_driver)) != 0) + goto err_plat; + + pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major); + return 0; + + err_plat: + unregister_blkdev(ace_major, "xsysace"); + err_blk: + printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); + return rc; } static void __exit ace_exit(void) { pr_debug("Unregistering Xilinx SystemACE driver\n"); - driver_unregister(&ace_driver); + platform_driver_unregister(&ace_platform_driver); unregister_blkdev(ace_major, "xsysace"); } From 1b455466549f46bab0a75a7a296a9331a38fd6fa Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:53 +0200 Subject: [PATCH 0919/2804] Sysace: Move structure allocation from bus binding into common code Split the determination of device registers/irqs/etc from the actual allocation and initialization of the device structure. This cleans up the code a bit in preparation to add an of_platform bus binding Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 103 ++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index b10447611afd..555939bd2d53 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1033,7 +1033,7 @@ static int __devinit ace_setup(struct ace_device *ace) if (ace->irq != NO_IRQ) free_irq(ace->irq, ace); err_ioremap: - printk(KERN_INFO "xsysace: error initializing device at 0x%lx\n", + dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n", ace->physaddr); return -ENOMEM; } @@ -1056,52 +1056,83 @@ static void __devexit ace_teardown(struct ace_device *ace) iounmap(ace->baseaddr); } +static int __devinit +ace_alloc(struct device *dev, int id, unsigned long physaddr, + int irq, int bus_width) +{ + struct ace_device *ace; + int rc; + dev_dbg(dev, "ace_alloc(%p)\n", dev); + + if (!physaddr) { + rc = -ENODEV; + goto err_noreg; + } + + /* Allocate and initialize the ace device structure */ + ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL); + if (!ace) { + rc = -ENOMEM; + goto err_alloc; + } + + ace->dev = dev; + ace->id = id; + ace->physaddr = physaddr; + ace->irq = irq; + ace->bus_width = bus_width; + + /* Call the setup code */ + if ((rc = ace_setup(ace)) != 0) + goto err_setup; + + dev_set_drvdata(dev, ace); + return 0; + + err_setup: + dev_set_drvdata(dev, NULL); + kfree(ace); + err_alloc: + err_noreg: + dev_err(dev, "could not initialize device, err=%i\n", rc); + return rc; +} + +static void __devexit ace_free(struct device *dev) +{ + struct ace_device *ace = dev_get_drvdata(dev); + dev_dbg(dev, "ace_free(%p)\n", dev); + + if (ace) { + ace_teardown(ace); + dev_set_drvdata(dev, NULL); + kfree(ace); + } +} + /* --------------------------------------------------------------------- * Platform Bus Support */ static int __devinit ace_probe(struct platform_device *dev) { - struct ace_device *ace; + unsigned long physaddr = 0; + int bus_width = 1; /* FIXME: should not be hard coded */ + int id = dev->id; + int irq = NO_IRQ; int i; dev_dbg(&dev->dev, "ace_probe(%p)\n", dev); - /* - * Allocate the ace device structure - */ - ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL); - if (!ace) - goto err_alloc; - - ace->dev = &dev->dev; - ace->id = dev->id; - ace->irq = NO_IRQ; - for (i = 0; i < dev->num_resources; i++) { if (dev->resource[i].flags & IORESOURCE_MEM) - ace->physaddr = dev->resource[i].start; + physaddr = dev->resource[i].start; if (dev->resource[i].flags & IORESOURCE_IRQ) - ace->irq = dev->resource[i].start; + irq = dev->resource[i].start; } - /* FIXME: Should get bus_width from the platform_device struct */ - ace->bus_width = 1; - - platform_set_drvdata(dev, ace); - /* Call the bus-independant setup code */ - if (ace_setup(ace) != 0) - goto err_setup; - - return 0; - - err_setup: - platform_set_drvdata(dev, NULL); - kfree(ace); - err_alloc: - printk(KERN_ERR "xsysace: could not initialize device\n"); - return -ENOMEM; + return ace_alloc(&dev->dev, id, physaddr, irq, bus_width); } /* @@ -1109,15 +1140,7 @@ static int __devinit ace_probe(struct platform_device *dev) */ static int __devexit ace_remove(struct platform_device *dev) { - struct ace_device *ace = platform_get_drvdata(dev); - dev_dbg(&dev->dev, "ace_remove(%p)\n", dev); - - if (ace) { - ace_teardown(ace); - platform_set_drvdata(dev, NULL); - kfree(ace); - } - + ace_free(&dev->dev); return 0; } From 4a24d8610df542b6599a65b100d438df144574de Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:54 +0200 Subject: [PATCH 0920/2804] Sysace: minor rework and cleanup changes Miscellanious rework to the sysace driver; Not critical, but makes the subsequent addition of the of_platform bus binding a wee bit cleaner Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 555939bd2d53..10bb4e54f685 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -158,6 +158,9 @@ MODULE_LICENSE("GPL"); #define ACE_FIFO_SIZE (32) #define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE) +#define ACE_BUS_WIDTH_8 0 +#define ACE_BUS_WIDTH_16 1 + struct ace_reg_ops; struct ace_device { @@ -931,9 +934,11 @@ static int __devinit ace_setup(struct ace_device *ace) { u16 version; u16 val; - int rc; + dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace); + dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq); + spin_lock_init(&ace->lock); init_completion(&ace->id_completion); @@ -982,7 +987,7 @@ static int __devinit ace_setup(struct ace_device *ace) snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a'); /* set bus width */ - if (ace->bus_width == 1) { + if (ace->bus_width == ACE_BUS_WIDTH_16) { /* 0x0101 should work regardless of endianess */ ace_out_le16(ace, ACE_BUSMODE, 0x0101); @@ -1117,7 +1122,7 @@ static void __devexit ace_free(struct device *dev) static int __devinit ace_probe(struct platform_device *dev) { unsigned long physaddr = 0; - int bus_width = 1; /* FIXME: should not be hard coded */ + int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */ int id = dev->id; int irq = NO_IRQ; int i; @@ -1166,6 +1171,7 @@ static int __init ace_init(void) goto err_blk; } + pr_debug("xsysace: registering platform binding\n"); if ((rc = platform_driver_register(&ace_platform_driver)) != 0) goto err_plat; From 32f6fff47df65d25d3dedbd2953508c05225b726 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:54 +0200 Subject: [PATCH 0921/2804] Sysace: Move IRQ handler registration to occur after FSM is initialized The FSM needs to be initialized before it is safe to call the ISR Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 10bb4e54f685..296d5674a3c1 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -949,15 +949,6 @@ static int __devinit ace_setup(struct ace_device *ace) if (!ace->baseaddr) goto err_ioremap; - if (ace->irq != NO_IRQ) { - rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); - if (rc) { - /* Failure - fall back to polled mode */ - dev_err(ace->dev, "request_irq failed\n"); - ace->irq = NO_IRQ; - } - } - /* * Initialize the state machine tasklet and stall timer */ @@ -1015,6 +1006,16 @@ static int __devinit ace_setup(struct ace_device *ace) val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; ace_out(ace, ACE_CTRL, val); + /* Now we can hook up the irq handler */ + if (ace->irq != NO_IRQ) { + rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); + if (rc) { + /* Failure - fall back to polled mode */ + dev_err(ace->dev, "request_irq failed\n"); + ace->irq = NO_IRQ; + } + } + /* Print the identification */ dev_info(ace->dev, "Xilinx SystemACE revision %i.%i.%i\n", (version >> 12) & 0xf, (version >> 8) & 0x0f, version & 0xff); @@ -1035,8 +1036,6 @@ static int __devinit ace_setup(struct ace_device *ace) blk_cleanup_queue(ace->queue); err_blk_initq: iounmap(ace->baseaddr); - if (ace->irq != NO_IRQ) - free_irq(ace->irq, ace); err_ioremap: dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n", ace->physaddr); From 95e896c35f3c3157159b89682b60281640b5d148 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:55 +0200 Subject: [PATCH 0922/2804] Sysace: Add of_platform_bus binding The of_platform bus binding is needed to make the device driver usable under arch/powerpc. Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 89 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 296d5674a3c1..56c4af3c2edb 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -91,6 +91,10 @@ #include #include #include +#if defined(CONFIG_OF) +#include +#include +#endif MODULE_AUTHOR("Grant Likely "); MODULE_DESCRIPTION("Xilinx SystemACE device driver"); @@ -1157,6 +1161,85 @@ static struct platform_driver ace_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * OF_Platform Bus Support + */ + +#if defined(CONFIG_OF) +static int __devinit +ace_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct resource res; + unsigned long physaddr; + const u32 *id; + int irq, bus_width, rc; + + dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match); + + /* device id */ + id = of_get_property(op->node, "port-number", NULL); + + /* physaddr */ + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalid address\n"); + return rc; + } + physaddr = res.start; + + /* irq */ + irq = irq_of_parse_and_map(op->node, 0); + + /* bus width */ + bus_width = ACE_BUS_WIDTH_16; + if (of_find_property(op->node, "8-bit", NULL)) + bus_width = ACE_BUS_WIDTH_8; + + /* Call the bus-independant setup code */ + return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width); +} + +static int __devexit ace_of_remove(struct of_device *op) +{ + ace_free(&op->dev); + return 0; +} + +/* Match table for of_platform binding */ +static struct of_device_id __devinit ace_of_match[] = { + { .compatible = "xilinx,xsysace", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ace_of_match); + +static struct of_platform_driver ace_of_driver = { + .owner = THIS_MODULE, + .name = "xsysace", + .match_table = ace_of_match, + .probe = ace_of_probe, + .remove = __devexit_p(ace_of_remove), + .driver = { + .name = "xsysace", + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init ace_of_register(void) +{ + pr_debug("xsysace: registering OF binding\n"); + return of_register_platform_driver(&ace_of_driver); +} + +static inline void __exit ace_of_unregister(void) +{ + of_unregister_platform_driver(&ace_of_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init ace_of_register(void) { return 0; } +static inline void __exit ace_of_unregister(void) { } +#endif /* CONFIG_OF */ + /* --------------------------------------------------------------------- * Module init/exit routines */ @@ -1170,6 +1253,9 @@ static int __init ace_init(void) goto err_blk; } + if ((rc = ace_of_register()) != 0) + goto err_of; + pr_debug("xsysace: registering platform binding\n"); if ((rc = platform_driver_register(&ace_platform_driver)) != 0) goto err_plat; @@ -1178,6 +1264,8 @@ static int __init ace_init(void) return 0; err_plat: + ace_of_unregister(); + err_of: unregister_blkdev(ace_major, "xsysace"); err_blk: printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); @@ -1188,6 +1276,7 @@ static void __exit ace_exit(void) { pr_debug("Unregistering Xilinx SystemACE driver\n"); platform_driver_unregister(&ace_platform_driver); + ace_of_unregister(); unregister_blkdev(ace_major, "xsysace"); } From ed155a95a4eb7d8dae61b64ab394314c5195e414 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:56 +0200 Subject: [PATCH 0923/2804] Sysace: Labels in C code should not be indented. Remove the indentation on labels Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 56c4af3c2edb..3ea172b7b7a4 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1034,13 +1034,13 @@ static int __devinit ace_setup(struct ace_device *ace) return 0; - err_read: +err_read: put_disk(ace->gd); - err_alloc_disk: +err_alloc_disk: blk_cleanup_queue(ace->queue); - err_blk_initq: +err_blk_initq: iounmap(ace->baseaddr); - err_ioremap: +err_ioremap: dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n", ace->physaddr); return -ENOMEM; @@ -1097,11 +1097,11 @@ ace_alloc(struct device *dev, int id, unsigned long physaddr, dev_set_drvdata(dev, ace); return 0; - err_setup: +err_setup: dev_set_drvdata(dev, NULL); kfree(ace); - err_alloc: - err_noreg: +err_alloc: +err_noreg: dev_err(dev, "could not initialize device, err=%i\n", rc); return rc; } @@ -1263,11 +1263,11 @@ static int __init ace_init(void) pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major); return 0; - err_plat: +err_plat: ace_of_unregister(); - err_of: +err_of: unregister_blkdev(ace_major, "xsysace"); - err_blk: +err_blk: printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); return rc; } From 3084f0c6105a71e43225c36b4d97c1407988a242 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 06:25:06 -0400 Subject: [PATCH 0924/2804] drivers/block/umem: move private include away from include/linux Move include/linux/umem.h to drivers/block, as umem.c is the only user, and its not an exported header. Move the PCI_{VENDOR,DEVICE}_ID_* constants to include/linux/pci_ids.h. Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 2 +- {include/linux => drivers/block}/umem.h | 5 ----- include/linux/pci_ids.h | 5 +++++ 3 files changed, 6 insertions(+), 6 deletions(-) rename {include/linux => drivers/block}/umem.h (95%) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index be7fac86725e..33ef7661e1c1 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -52,7 +52,7 @@ #include /* O_ACCMODE */ #include /* HDIO_GETGEO */ -#include +#include "umem.h" #include #include diff --git a/include/linux/umem.h b/drivers/block/umem.h similarity index 95% rename from include/linux/umem.h rename to drivers/block/umem.h index f36ebfc32bf6..3a3819afed92 100644 --- a/include/linux/umem.h +++ b/drivers/block/umem.h @@ -125,11 +125,6 @@ struct mm_dma_desc { __le64 sem_control_bits; } __attribute__((aligned(8))); -#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 -#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415 -#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425 -#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155 - /* bits for card->flags */ #define UM_FLAG_DMA_IN_REGS 1 #define UM_FLAG_NO_BYTE_STATUS 2 diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 55f307ffbf96..506b9ae241fd 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1736,6 +1736,11 @@ #define PCI_VENDOR_ID_RADISYS 0x1331 +#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 +#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415 +#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425 +#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155 + #define PCI_VENDOR_ID_DOMEX 0x134a #define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001 From 4e0af881afee2b399854b1cdfdbe37e6ab6a09ca Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 06:41:25 -0400 Subject: [PATCH 0925/2804] drivers/block/umem: use dev_printk() dev_printk() gives us a consistent prefix (driver name + PCI bus id), which allows us to eliminate the hand-rolled one. Also allows us to eliminate card->card_number, which was used solely in printk() calls. Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 111 ++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 49 deletions(-) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 33ef7661e1c1..32060b84c0fd 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -97,7 +97,6 @@ static int major_nr; #include struct cardinfo { - int card_number; struct pci_dev *dev; int irq; @@ -236,7 +235,7 @@ static void dump_regs(struct cardinfo *card) */ static void dump_dmastat(struct cardinfo *card, unsigned int dmastat) { - printk(KERN_DEBUG "MM%d*: DMAstat - ", card->card_number); + dev_printk(KERN_DEBUG, &card->dev->dev, "DMAstat - "); if (dmastat & DMASCR_ANY_ERR) printk("ANY_ERR "); if (dmastat & DMASCR_MBE_ERR) @@ -499,17 +498,17 @@ static void process_page(unsigned long data) if (control & DMASCR_HARD_ERROR) { /* error */ clear_bit(BIO_UPTODATE, &bio->bi_flags); - printk(KERN_WARNING "MM%d: I/O error on sector %d/%d\n", - card->card_number, - le32_to_cpu(desc->local_addr)>>9, - le32_to_cpu(desc->transfer_size)); + dev_printk(KERN_WARNING, &card->dev->dev, + "I/O error on sector %d/%d\n", + le32_to_cpu(desc->local_addr)>>9, + le32_to_cpu(desc->transfer_size)); dump_dmastat(card, control); } else if (test_bit(BIO_RW, &bio->bi_rw) && le32_to_cpu(desc->local_addr)>>9 == card->init_size) { card->init_size += le32_to_cpu(desc->transfer_size)>>9; if (card->init_size>>1 >= card->mm_size) { - printk(KERN_INFO "MM%d: memory now initialised\n", - card->card_number); + dev_printk(KERN_INFO, &card->dev->dev, + "memory now initialised\n"); set_userbit(card, MEMORY_INITIALIZED, 1); } } @@ -618,46 +617,51 @@ HW_TRACE(0x30); dump_dmastat(card, dma_status); if (stat & 0x01) - printk(KERN_ERR "MM%d*: Memory access error detected (err count %d)\n", - card->card_number, count); + dev_printk(KERN_ERR, &card->dev->dev, + "Memory access error detected (err count %d)\n", + count); if (stat & 0x02) - printk(KERN_ERR "MM%d*: Multi-bit EDC error\n", - card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "Multi-bit EDC error\n"); - printk(KERN_ERR "MM%d*: Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n", - card->card_number, addr_log2, addr_log1, data_log2, data_log1); - printk(KERN_ERR "MM%d*: Fault Check 0x%02x, Fault Syndrome 0x%02x\n", - card->card_number, check, syndrome); + dev_printk(KERN_ERR, &card->dev->dev, + "Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n", + addr_log2, addr_log1, data_log2, data_log1); + dev_printk(KERN_ERR, &card->dev->dev, + "Fault Check 0x%02x, Fault Syndrome 0x%02x\n", + check, syndrome); writeb(0, card->csr_remap + ERROR_COUNT); } if (dma_status & DMASCR_PARITY_ERR_REP) { - printk(KERN_ERR "MM%d*: PARITY ERROR REPORTED\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "PARITY ERROR REPORTED\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } if (dma_status & DMASCR_PARITY_ERR_DET) { - printk(KERN_ERR "MM%d*: PARITY ERROR DETECTED\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "PARITY ERROR DETECTED\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } if (dma_status & DMASCR_SYSTEM_ERR_SIG) { - printk(KERN_ERR "MM%d*: SYSTEM ERROR\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "SYSTEM ERROR\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } if (dma_status & DMASCR_TARGET_ABT) { - printk(KERN_ERR "MM%d*: TARGET ABORT\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "TARGET ABORT\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } if (dma_status & DMASCR_MASTER_ABT) { - printk(KERN_ERR "MM%d*: MASTER ABORT\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "MASTER ABORT\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } @@ -708,20 +712,20 @@ static int check_battery(struct cardinfo *card, int battery, int status) card->battery[battery].last_change = jiffies; if (card->battery[battery].good) { - printk(KERN_ERR "MM%d: Battery %d now good\n", - card->card_number, battery + 1); + dev_printk(KERN_ERR, &card->dev->dev, + "Battery %d now good\n", battery + 1); card->battery[battery].warned = 0; } else - printk(KERN_ERR "MM%d: Battery %d now FAILED\n", - card->card_number, battery + 1); + dev_printk(KERN_ERR, &card->dev->dev, + "Battery %d now FAILED\n", battery + 1); return 1; } else if (!card->battery[battery].good && !card->battery[battery].warned && time_after_eq(jiffies, card->battery[battery].last_change + (HZ * 60 * 60 * 5))) { - printk(KERN_ERR "MM%d: Battery %d still FAILED after 5 hours\n", - card->card_number, battery + 1); + dev_printk(KERN_ERR, &card->dev->dev, + "Battery %d still FAILED after 5 hours\n", battery + 1); card->battery[battery].warned = 1; return 1; @@ -745,8 +749,8 @@ static void check_batteries(struct cardinfo *card) status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY); if (debug & DEBUG_BATTERY_POLLING) - printk(KERN_DEBUG "MM%d: checking battery status, 1 = %s, 2 = %s\n", - card->card_number, + dev_printk(KERN_DEBUG, &card->dev->dev, + "checking battery status, 1 = %s, 2 = %s\n", (status & BATTERY_1_FAILURE) ? "FAILURE" : "OK", (status & BATTERY_2_FAILURE) ? "FAILURE" : "OK"); @@ -866,6 +870,10 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i unsigned char batt_status; unsigned int saved_bar, data; int magic_number; + static int printed_version; + + if (!printed_version++) + printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); if (pci_enable_device(dev) < 0) return -ENODEV; @@ -874,21 +882,21 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i pci_set_master(dev); card->dev = dev; - card->card_number = num_cards; card->csr_base = pci_resource_start(dev, 0); card->csr_len = pci_resource_len(dev, 0); - printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n", - card->card_number, dev->bus->number, dev->devfn); + dev_printk(KERN_INFO, &dev->dev, + "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n"); if (pci_set_dma_mask(dev, DMA_64BIT_MASK) && pci_set_dma_mask(dev, DMA_32BIT_MASK)) { - printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards); + dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n"); return -ENOMEM; } if (!request_mem_region(card->csr_base, card->csr_len, "Micro Memory")) { - printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "Unable to request memory region\n"); ret = -ENOMEM; goto failed_req_csr; @@ -896,13 +904,15 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->csr_remap = ioremap_nocache(card->csr_base, card->csr_len); if (!card->csr_remap) { - printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "Unable to remap memory region\n"); ret = -ENOMEM; goto failed_remap_csr; } - printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number, + dev_printk(KERN_INFO, &card->dev->dev, + "CSR 0x%08lx -> 0x%p (0x%lx)\n", card->csr_base, card->csr_remap, card->csr_len); switch(card->dev->device) { @@ -927,7 +937,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i } if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != magic_number) { - printk(KERN_ERR "MM%d: Magic number invalid\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "Magic number invalid\n"); ret = -ENOMEM; goto failed_magic; } @@ -940,7 +950,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i &card->mm_pages[1].page_dma); if (card->mm_pages[0].desc == NULL || card->mm_pages[1].desc == NULL) { - printk(KERN_ERR "MM%d: alloc failed\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n"); goto failed_alloc; } reset_page(&card->mm_pages[0]); @@ -995,11 +1005,12 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->battery[0].last_change = card->battery[1].last_change = jiffies; if (card->flags & UM_FLAG_NO_BATT) - printk(KERN_INFO "MM%d: Size %d KB\n", - card->card_number, card->mm_size); + dev_printk(KERN_INFO, &card->dev->dev, + "Size %d KB\n", card->mm_size); else { - printk(KERN_INFO "MM%d: Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n", - card->card_number, card->mm_size, + dev_printk(KERN_INFO, &card->dev->dev, + "Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n", + card->mm_size, (batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled"), card->battery[0].good ? "OK" : "FAILURE", (batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled"), @@ -1021,14 +1032,16 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) { - printk(KERN_ERR "MM%d: Unable to allocate IRQ\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "Unable to allocate IRQ\n"); ret = -ENODEV; goto failed_req_irq; } card->irq = dev->irq; - printk(KERN_INFO "MM%d: Window size %d bytes, IRQ %d\n", card->card_number, + dev_printk(KERN_INFO, &card->dev->dev, + "Window size %d bytes, IRQ %d\n", card->win_size, card->irq); spin_lock_init(&card->lock); @@ -1049,10 +1062,12 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i num_cards++; if (!get_userbit(card, MEMORY_INITIALIZED)) { - printk(KERN_INFO "MM%d: memory NOT initialized. Consider over-writing whole device.\n", card->card_number); + dev_printk(KERN_INFO, &card->dev->dev, + "memory NOT initialized. Consider over-writing whole device.\n"); card->init_size = 0; } else { - printk(KERN_INFO "MM%d: memory already initialized\n", card->card_number); + dev_printk(KERN_INFO, &card->dev->dev, + "memory already initialized\n"); card->init_size = card->mm_size; } @@ -1137,8 +1152,6 @@ static int __init mm_init(void) int retval, i; int err; - printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); - retval = pci_register_driver(&mm_pci_driver); if (retval) return -ENOMEM; @@ -1169,7 +1182,7 @@ static int __init mm_init(void) } init_battery_timer(); - printk("MM: desc_per_page = %ld\n", DESC_PER_PAGE); + printk(KERN_INFO "MM: desc_per_page = %ld\n", DESC_PER_PAGE); /* printk("mm_init: Done. 10-19-01 9:00\n"); */ return 0; From ee4a7b6874469244ed0e3b8fde20028e0bb52642 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 07:40:33 -0400 Subject: [PATCH 0926/2804] drivers/block/umem: minor cleanups * tab-align DRIVER_*, pci_driver entries * reduced wasted memory by killing unused struct cardinfo members * move free_irq() call above resource unmap, to fix tiny window where irq handler may access recently-unmapped memory * propagate pci_enable_device() return value * use pci_request_regions, pci_release_regions() for resource reservation * call pci_disable_device() in pci_driver::remove() Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 59 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 32060b84c0fd..97c5dc9436a9 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -67,9 +67,10 @@ * Version Information */ -#define DRIVER_VERSION "v2.3" -#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown" -#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver" +#define DRIVER_NAME "umem" +#define DRIVER_VERSION "v2.3" +#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown" +#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver" static int debug; /* #define HW_TRACE(x) writeb(x,cards[0].csr_remap + MEMCTRLSTATUS_MAGIC) */ @@ -99,12 +100,7 @@ static int major_nr; struct cardinfo { struct pci_dev *dev; - int irq; - - unsigned long csr_base; unsigned char __iomem *csr_remap; - unsigned long csr_len; - unsigned int win_size; /* PCI window size */ unsigned int mm_size; /* size in kbytes */ unsigned int init_size; /* initial segment, in sectors, @@ -869,22 +865,27 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i unsigned char mem_present; unsigned char batt_status; unsigned int saved_bar, data; + unsigned long csr_base; + unsigned long csr_len; int magic_number; static int printed_version; if (!printed_version++) printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); - if (pci_enable_device(dev) < 0) - return -ENODEV; + ret = pci_enable_device(dev); + if (ret) + return ret; pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF8); pci_set_master(dev); card->dev = dev; - card->csr_base = pci_resource_start(dev, 0); - card->csr_len = pci_resource_len(dev, 0); + csr_base = pci_resource_start(dev, 0); + csr_len = pci_resource_len(dev, 0); + if (!csr_base || !csr_len) + return -ENODEV; dev_printk(KERN_INFO, &dev->dev, "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n"); @@ -894,15 +895,15 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n"); return -ENOMEM; } - if (!request_mem_region(card->csr_base, card->csr_len, "Micro Memory")) { + + ret = pci_request_regions(dev, DRIVER_NAME); + if (ret) { dev_printk(KERN_ERR, &card->dev->dev, "Unable to request memory region\n"); - ret = -ENOMEM; - goto failed_req_csr; } - card->csr_remap = ioremap_nocache(card->csr_base, card->csr_len); + card->csr_remap = ioremap_nocache(csr_base, csr_len); if (!card->csr_remap) { dev_printk(KERN_ERR, &card->dev->dev, "Unable to remap memory region\n"); @@ -913,7 +914,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i dev_printk(KERN_INFO, &card->dev->dev, "CSR 0x%08lx -> 0x%p (0x%lx)\n", - card->csr_base, card->csr_remap, card->csr_len); + csr_base, card->csr_remap, csr_len); switch(card->dev->device) { case 0x5415: @@ -1028,9 +1029,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i data = ~data; data += 1; - card->win_size = data; - - if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) { dev_printk(KERN_ERR, &card->dev->dev, "Unable to allocate IRQ\n"); @@ -1039,10 +1037,8 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i goto failed_req_irq; } - card->irq = dev->irq; dev_printk(KERN_INFO, &card->dev->dev, - "Window size %d bytes, IRQ %d\n", - card->win_size, card->irq); + "Window size %d bytes, IRQ %d\n", data, dev->irq); spin_lock_init(&card->lock); @@ -1089,7 +1085,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i failed_magic: iounmap(card->csr_remap); failed_remap_csr: - release_mem_region(card->csr_base, card->csr_len); + pci_release_regions(dev); failed_req_csr: return ret; @@ -1104,9 +1100,8 @@ static void mm_pci_remove(struct pci_dev *dev) struct cardinfo *card = pci_get_drvdata(dev); tasklet_kill(&card->tasklet); + free_irq(dev->irq, card); iounmap(card->csr_remap); - release_mem_region(card->csr_base, card->csr_len); - free_irq(card->irq, card); if (card->mm_pages[0].desc) pci_free_consistent(card->dev, PAGE_SIZE*2, @@ -1117,6 +1112,9 @@ static void mm_pci_remove(struct pci_dev *dev) card->mm_pages[1].desc, card->mm_pages[1].page_dma); blk_cleanup_queue(card->queue); + + pci_release_regions(dev); + pci_disable_device(dev); } static const struct pci_device_id mm_pci_ids[] = { @@ -1136,11 +1134,12 @@ static const struct pci_device_id mm_pci_ids[] = { MODULE_DEVICE_TABLE(pci, mm_pci_ids); static struct pci_driver mm_pci_driver = { - .name = "umem", - .id_table = mm_pci_ids, - .probe = mm_pci_probe, - .remove = mm_pci_remove, + .name = DRIVER_NAME, + .id_table = mm_pci_ids, + .probe = mm_pci_probe, + .remove = mm_pci_remove, }; + /* ----------------------------------------------------------------------------------- -- mm_init From 4e953a216265f8646360fa909bdc87ea4bf446b3 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 07:41:50 -0400 Subject: [PATCH 0927/2804] drivers/block/umem: trim trailing whitespace Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 22 +++++++++++----------- drivers/block/umem.h | 14 +++++++------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 97c5dc9436a9..251041763690 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -293,7 +293,7 @@ static void mm_start_io(struct cardinfo *card) desc->control_bits &= ~cpu_to_le32(DMASCR_CHAIN_EN); desc->sem_control_bits = desc->control_bits; - + if (debug & DEBUG_LED_ON_TRANSFER) set_led(card, LED_REMOVE, LED_ON); @@ -327,7 +327,7 @@ static int add_bio(struct cardinfo *card); static void activate(struct cardinfo *card) { - /* if No page is Active, and Ready is + /* if No page is Active, and Ready is * not empty, then switch Ready page * to active and start IO. * Then add any bh's that are available to Ready @@ -366,7 +366,7 @@ static void mm_unplug_device(struct request_queue *q) spin_unlock_irqrestore(&card->lock, flags); } -/* +/* * If there is room on Ready page, take * one bh off list and add it. * return 1 if there was room, else 0. @@ -467,7 +467,7 @@ static void process_page(unsigned long data) if (card->Active < 0) goto out_unlock; page = &card->mm_pages[card->Active]; - + while (page->headcnt < page->cnt) { struct bio *bio = page->bio; struct mm_dma_desc *desc = &page->desc[page->headcnt]; @@ -477,7 +477,7 @@ static void process_page(unsigned long data) if (!(control & DMASCR_DMA_COMPLETE)) { control = dma_status; - last=1; + last=1; } page->headcnt++; idx = page->idx; @@ -487,7 +487,7 @@ static void process_page(unsigned long data) page->idx = page->bio->bi_idx; } - pci_unmap_page(card->dev, desc->data_dma_handle, + pci_unmap_page(card->dev, desc->data_dma_handle, bio_iovec_idx(bio,idx)->bv_len, (control& DMASCR_TRANSFER_READ) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); @@ -592,7 +592,7 @@ HW_TRACE(0x30); else writeb((DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE) >> 16, card->csr_remap+ DMA_STATUS_CTRL + 2); - + /* log errors and clear interrupt status */ if (dma_status & DMASCR_ANY_ERR) { unsigned int data_log1, data_log2; @@ -668,7 +668,7 @@ HW_TRACE(0x30); HW_TRACE(0x36); - return IRQ_HANDLED; + return IRQ_HANDLED; } /* ----------------------------------------------------------------------------------- @@ -761,7 +761,7 @@ static void check_all_batteries(unsigned long ptr) { int i; - for (i = 0; i < num_cards; i++) + for (i = 0; i < num_cards; i++) if (!(cards[i].flags & UM_FLAG_NO_BATT)) { struct cardinfo *card = &cards[i]; spin_lock_bh(&card->lock); @@ -972,7 +972,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i tasklet_init(&card->tasklet, process_page, (unsigned long)card); card->check_batteries = 0; - + mem_present = readb(card->csr_remap + MEMCTRLSTATUS_MEMORY); switch (mem_present) { case MEM_128_MB: @@ -1005,7 +1005,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->battery[1].good = !(batt_status & BATTERY_2_FAILURE); card->battery[0].last_change = card->battery[1].last_change = jiffies; - if (card->flags & UM_FLAG_NO_BATT) + if (card->flags & UM_FLAG_NO_BATT) dev_printk(KERN_INFO, &card->dev->dev, "Size %d KB\n", card->mm_size); else { diff --git a/drivers/block/umem.h b/drivers/block/umem.h index 3a3819afed92..375c68974c9a 100644 --- a/drivers/block/umem.h +++ b/drivers/block/umem.h @@ -87,13 +87,13 @@ #define DMASCR_DMA_COMPLETE 0x40000 #define DMASCR_CHAIN_COMPLETE 0x80000 -/* -3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE -READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA -TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE -TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS -(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6, -AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING +/* +3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE +READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA +TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE +TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS +(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6, +AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING DMA READ OPERATIONS. */ #define DMASCR_READ 0x60000000 From cb3503ca54dc34e8dc3b823a6bd52c0807c102f4 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 07:49:39 -0400 Subject: [PATCH 0928/2804] drivers/block/umem: use DRIVER_NAME where appropriate Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 251041763690..99806f9ee4ce 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -1029,7 +1029,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i data = ~data; data += 1; - if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) { + if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, DRIVER_NAME, card)) { dev_printk(KERN_ERR, &card->dev->dev, "Unable to allocate IRQ\n"); ret = -ENODEV; @@ -1155,7 +1155,7 @@ static int __init mm_init(void) if (retval) return -ENOMEM; - err = major_nr = register_blkdev(0, "umem"); + err = major_nr = register_blkdev(0, DRIVER_NAME); if (err < 0) { pci_unregister_driver(&mm_pci_driver); return -EIO; @@ -1187,7 +1187,7 @@ static int __init mm_init(void) out: pci_unregister_driver(&mm_pci_driver); - unregister_blkdev(major_nr, "umem"); + unregister_blkdev(major_nr, DRIVER_NAME); while (i--) put_disk(mm_gendisk[i]); return -ENOMEM; @@ -1210,7 +1210,7 @@ static void __exit mm_cleanup(void) pci_unregister_driver(&mm_pci_driver); - unregister_blkdev(major_nr, "umem"); + unregister_blkdev(major_nr, DRIVER_NAME); } module_init(mm_init); From 34e1b83413d91999416443f31c276095f9937aa6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 08:52:38 +0200 Subject: [PATCH 0929/2804] Sysace: Minor coding convention fixup Put function call and return code test on separate lines. Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 3ea172b7b7a4..3847464f5ea6 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1091,7 +1091,8 @@ ace_alloc(struct device *dev, int id, unsigned long physaddr, ace->bus_width = bus_width; /* Call the setup code */ - if ((rc = ace_setup(ace)) != 0) + rc = ace_setup(ace); + if (rc) goto err_setup; dev_set_drvdata(dev, ace); @@ -1253,11 +1254,13 @@ static int __init ace_init(void) goto err_blk; } - if ((rc = ace_of_register()) != 0) + rc = ace_of_register(); + if (rc) goto err_of; pr_debug("xsysace: registering platform binding\n"); - if ((rc = platform_driver_register(&ace_platform_driver)) != 0) + rc = platform_driver_register(&ace_platform_driver); + if (rc) goto err_plat; pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major); From b5515d86f2efd4dd3516c16c17c1a611a5800b19 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 08:52:39 +0200 Subject: [PATCH 0930/2804] Sysace: sparse fixes Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 3847464f5ea6..5b73471ada78 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -195,7 +195,7 @@ struct ace_device { /* Details of hardware device */ unsigned long physaddr; - void *baseaddr; + void __iomem *baseaddr; int irq; int bus_width; /* 0 := 8 bit; 1 := 16 bit */ struct ace_reg_ops *reg_ops; @@ -227,20 +227,20 @@ struct ace_reg_ops { /* 8 Bit bus width */ static u16 ace_in_8(struct ace_device *ace, int reg) { - void *r = ace->baseaddr + reg; + void __iomem *r = ace->baseaddr + reg; return in_8(r) | (in_8(r + 1) << 8); } static void ace_out_8(struct ace_device *ace, int reg, u16 val) { - void *r = ace->baseaddr + reg; + void __iomem *r = ace->baseaddr + reg; out_8(r, val); out_8(r + 1, val >> 8); } static void ace_datain_8(struct ace_device *ace) { - void *r = ace->baseaddr + 0x40; + void __iomem *r = ace->baseaddr + 0x40; u8 *dst = ace->data_ptr; int i = ACE_FIFO_SIZE; while (i--) @@ -250,7 +250,7 @@ static void ace_datain_8(struct ace_device *ace) static void ace_dataout_8(struct ace_device *ace) { - void *r = ace->baseaddr + 0x40; + void __iomem *r = ace->baseaddr + 0x40; u8 *src = ace->data_ptr; int i = ACE_FIFO_SIZE; while (i--) From d2bbf3da3759d04cd5836955cc59c8ae96092831 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 08:52:40 +0200 Subject: [PATCH 0931/2804] Sysace: Don't enable IRQ until after interrupt handler is registered The previous patch to move the interrupt handler registration moved it below enabling interrupts which could be a problem if the device is on a shared interrupt line. This patch fixes the order. Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 5b73471ada78..9e7652dcde6c 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1005,11 +1005,6 @@ static int __devinit ace_setup(struct ace_device *ace) ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE | ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ); - /* Enable interrupts */ - val = ace_in(ace, ACE_CTRL); - val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; - ace_out(ace, ACE_CTRL, val); - /* Now we can hook up the irq handler */ if (ace->irq != NO_IRQ) { rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); @@ -1020,6 +1015,11 @@ static int __devinit ace_setup(struct ace_device *ace) } } + /* Enable interrupts */ + val = ace_in(ace, ACE_CTRL); + val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; + ace_out(ace, ACE_CTRL, val); + /* Print the identification */ dev_info(ace->dev, "Xilinx SystemACE revision %i.%i.%i\n", (version >> 12) & 0xf, (version >> 8) & 0x0f, version & 0xff); From f58c4c0a17e500e767473598b3deafaa1d64051d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 9 Oct 2007 13:23:51 +0200 Subject: [PATCH 0932/2804] compat_ioctl: move common block ioctls to compat_blkdev_ioctl Make compat_blkdev_ioctl and blkdev_ioctl reflect the respective native versions. This is somewhat more efficient and makes it easier to keep the two in sync. Also get rid of the bogus handling for broken_blkgetsize and the duplicate entry for BLKRASET. Signed-off-by: Arnd Bergmann Signed-off-by: Jens Axboe --- block/Makefile | 1 + block/compat_ioctl.c | 121 +++++++++++++++++++++++++++++++++++++++++++ block/ioctl.c | 21 ++------ fs/compat_ioctl.c | 45 ---------------- 4 files changed, 126 insertions(+), 62 deletions(-) create mode 100644 block/compat_ioctl.c diff --git a/block/Makefile b/block/Makefile index 959feeb253be..3cfe7cebaa6a 100644 --- a/block/Makefile +++ b/block/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o +obj-$(CONFIG_COMPAT) += compat_ioctl.o diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c new file mode 100644 index 000000000000..d20fdb436f68 --- /dev/null +++ b/block/compat_ioctl.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int compat_put_ushort(unsigned long arg, unsigned short val) +{ + return put_user(val, (unsigned short __user *)compat_ptr(arg)); +} + +static int compat_put_int(unsigned long arg, int val) +{ + return put_user(val, (compat_int_t __user *)compat_ptr(arg)); +} + +static int compat_put_long(unsigned long arg, long val) +{ + return put_user(val, (compat_long_t __user *)compat_ptr(arg)); +} + +static int compat_put_ulong(unsigned long arg, compat_ulong_t val) +{ + return put_user(val, (compat_ulong_t __user *)compat_ptr(arg)); +} + +static int compat_put_u64(unsigned long arg, u64 val) +{ + return put_user(val, (compat_u64 __user *)compat_ptr(arg)); +} + +#define BLKBSZGET_32 _IOR(0x12, 112, int) +#define BLKBSZSET_32 _IOW(0x12, 113, int) +#define BLKGETSIZE64_32 _IOR(0x12, 114, int) + +static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file, + struct block_device *bdev, + unsigned cmd, unsigned long arg) +{ + struct backing_dev_info *bdi; + + switch (cmd) { + case BLKRAGET: + case BLKFRAGET: + if (!arg) + return -EINVAL; + bdi = blk_get_backing_dev_info(bdev); + if (bdi == NULL) + return -ENOTTY; + return compat_put_long(arg, + (bdi->ra_pages * PAGE_CACHE_SIZE) / 512); + case BLKROGET: /* compatible */ + return compat_put_int(arg, bdev_read_only(bdev) != 0); + case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */ + return compat_put_int(arg, block_size(bdev)); + case BLKSSZGET: /* get block device hardware sector size */ + return compat_put_int(arg, bdev_hardsect_size(bdev)); + case BLKSECTGET: + return compat_put_ushort(arg, + bdev_get_queue(bdev)->max_sectors); + case BLKRASET: /* compatible, but no compat_ptr (!) */ + case BLKFRASET: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + bdi = blk_get_backing_dev_info(bdev); + if (bdi == NULL) + return -ENOTTY; + bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE; + return 0; + case BLKGETSIZE: + if ((bdev->bd_inode->i_size >> 9) > ~0UL) + return -EFBIG; + return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9); + + case BLKGETSIZE64_32: + return compat_put_u64(arg, bdev->bd_inode->i_size); + } + return -ENOIOCTLCMD; +} + +/* Most of the generic ioctls are handled in the normal fallback path. + This assumes the blkdev's low level compat_ioctl always returns + ENOIOCTLCMD for unknown ioctls. */ +long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) +{ + int ret = -ENOIOCTLCMD; + struct inode *inode = file->f_mapping->host; + struct block_device *bdev = inode->i_bdev; + struct gendisk *disk = bdev->bd_disk; + + switch (cmd) { + case BLKFLSBUF: + case BLKROSET: + /* + * the ones below are implemented in blkdev_locked_ioctl, + * but we call blkdev_ioctl, which gets the lock for us + */ + case BLKRRPART: + return blkdev_ioctl(inode, file, cmd, + (unsigned long)compat_ptr(arg)); + case BLKBSZSET_32: + return blkdev_ioctl(inode, file, BLKBSZSET, + (unsigned long)compat_ptr(arg)); + } + + lock_kernel(); + ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg); + /* FIXME: why do we assume -> compat_ioctl needs the BKL? */ + if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl) + ret = disk->fops->compat_ioctl(file, cmd, arg); + unlock_kernel(); + + return ret; +} diff --git a/block/ioctl.c b/block/ioctl.c index f7e3e8abf887..52d6385216ad 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -217,6 +217,10 @@ int blkdev_driver_ioctl(struct inode *inode, struct file *file, } EXPORT_SYMBOL_GPL(blkdev_driver_ioctl); +/* + * always keep this in sync with compat_blkdev_ioctl() and + * compat_blkdev_locked_ioctl() + */ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg) { @@ -284,21 +288,4 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, return blkdev_driver_ioctl(inode, file, disk, cmd, arg); } - -/* Most of the generic ioctls are handled in the normal fallback path. - This assumes the blkdev's low level compat_ioctl always returns - ENOIOCTLCMD for unknown ioctls. */ -long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) -{ - struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev; - struct gendisk *disk = bdev->bd_disk; - int ret = -ENOIOCTLCMD; - if (disk->fops->compat_ioctl) { - lock_kernel(); - ret = disk->fops->compat_ioctl(file, cmd, arg); - unlock_kernel(); - } - return ret; -} - EXPORT_SYMBOL_GPL(blkdev_ioctl); diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 37310b0e8107..6be121868c60 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1537,12 +1537,6 @@ ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_BLOCK -static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - /* The mkswap binary hard codes it to Intel value :-((( */ - return w_long(fd, BLKGETSIZE, arg); -} - struct blkpg_ioctl_arg32 { compat_int_t op; compat_int_t flags; @@ -1578,29 +1572,6 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); } -#ifdef CONFIG_BLOCK -/* Fix sizeof(sizeof()) breakage */ -#define BLKBSZGET_32 _IOR(0x12,112,int) -#define BLKBSZSET_32 _IOW(0x12,113,int) -#define BLKGETSIZE64_32 _IOR(0x12,114,int) - -static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return sys_ioctl(fd, BLKBSZGET, (unsigned long)compat_ptr(arg)); -} - -static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return sys_ioctl(fd, BLKBSZSET, (unsigned long)compat_ptr(arg)); -} - -static int do_blkgetsize64(unsigned int fd, unsigned int cmd, - unsigned long arg) -{ - return sys_ioctl(fd, BLKGETSIZE64, (unsigned long)compat_ptr(arg)); -} -#endif - /* Bluetooth ioctls */ #define HCIUARTSETPROTO _IOW('U', 200, int) #define HCIUARTGETPROTO _IOR('U', 201, int) @@ -2546,19 +2517,11 @@ COMPATIBLE_IOCTL(FDFMTTRK) COMPATIBLE_IOCTL(FDRAWCMD) /* 0x12 */ #ifdef CONFIG_BLOCK -COMPATIBLE_IOCTL(BLKRASET) -COMPATIBLE_IOCTL(BLKROSET) -COMPATIBLE_IOCTL(BLKROGET) -COMPATIBLE_IOCTL(BLKRRPART) -COMPATIBLE_IOCTL(BLKFLSBUF) COMPATIBLE_IOCTL(BLKSECTSET) -COMPATIBLE_IOCTL(BLKSSZGET) COMPATIBLE_IOCTL(BLKTRACESTART) COMPATIBLE_IOCTL(BLKTRACESTOP) COMPATIBLE_IOCTL(BLKTRACESETUP) COMPATIBLE_IOCTL(BLKTRACETEARDOWN) -ULONG_IOCTL(BLKRASET) -ULONG_IOCTL(BLKFRASET) #endif /* RAID */ COMPATIBLE_IOCTL(RAID_VERSION) @@ -3337,11 +3300,6 @@ HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) #endif #ifdef CONFIG_BLOCK HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) -HANDLE_IOCTL(BLKRAGET, w_long) -HANDLE_IOCTL(BLKGETSIZE, w_long) -HANDLE_IOCTL(0x1260, broken_blkgetsize) -HANDLE_IOCTL(BLKFRAGET, w_long) -HANDLE_IOCTL(BLKSECTGET, w_long) HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) @@ -3415,9 +3373,6 @@ HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) /* block stuff */ #ifdef CONFIG_BLOCK -HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) -HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) -HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) /* Raw devices */ HANDLE_IOCTL(RAW_SETBIND, raw_ioctl) HANDLE_IOCTL(RAW_GETBIND, raw_ioctl) From 7199d4cdd8485f802df3e1bc131245c69009b9a4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 9 Oct 2007 13:23:52 +0200 Subject: [PATCH 0933/2804] compat_ioctl: add compat_blkdev_driver_ioctl() Handle those blockdev ioctl calls that are compatible directly from the compat_blkdev_ioctl() function, instead of having to go through the compat_ioctl hash lookup. Signed-off-by: Arnd Bergmann Signed-off-by: Jens Axboe --- block/compat_ioctl.c | 121 ++++++++++++++++++++++++++++++++++++++++++- fs/compat_ioctl.c | 83 ----------------------------- 2 files changed, 120 insertions(+), 84 deletions(-) diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index d20fdb436f68..500cc9e761c1 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -40,6 +40,122 @@ static int compat_put_u64(unsigned long arg, u64 val) #define BLKBSZSET_32 _IOW(0x12, 113, int) #define BLKGETSIZE64_32 _IOR(0x12, 114, int) +static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned cmd, unsigned long arg) +{ + int ret; + + switch (arg) { + /* + * No handler required for the ones below, we just need to + * convert arg to a 64 bit pointer. + */ + case BLKSECTSET: + /* + * 0x03 -- HD/IDE ioctl's used by hdparm and friends. + * Some need translations, these do not. + */ + case HDIO_GET_IDENTITY: + case HDIO_DRIVE_TASK: + case HDIO_DRIVE_CMD: + case HDIO_SCAN_HWIF: + /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */ + case 0x330: + /* 0x02 -- Floppy ioctls */ + case FDMSGON: + case FDMSGOFF: + case FDSETEMSGTRESH: + case FDFLUSH: + case FDWERRORCLR: + case FDSETMAXERRS: + case FDGETMAXERRS: + case FDGETDRVTYP: + case FDEJECT: + case FDCLRPRM: + case FDFMTBEG: + case FDFMTEND: + case FDRESET: + case FDTWADDLE: + case FDFMTTRK: + case FDRAWCMD: + /* CDROM stuff */ + case CDROMPAUSE: + case CDROMRESUME: + case CDROMPLAYMSF: + case CDROMPLAYTRKIND: + case CDROMREADTOCHDR: + case CDROMREADTOCENTRY: + case CDROMSTOP: + case CDROMSTART: + case CDROMEJECT: + case CDROMVOLCTRL: + case CDROMSUBCHNL: + case CDROMMULTISESSION: + case CDROM_GET_MCN: + case CDROMRESET: + case CDROMVOLREAD: + case CDROMSEEK: + case CDROMPLAYBLK: + case CDROMCLOSETRAY: + case CDROM_DISC_STATUS: + case CDROM_CHANGER_NSLOTS: + case CDROM_GET_CAPABILITY: + /* Ignore cdrom.h about these next 5 ioctls, they absolutely do + * not take a struct cdrom_read, instead they take a struct cdrom_msf + * which is compatible. + */ + case CDROMREADMODE2: + case CDROMREADMODE1: + case CDROMREADRAW: + case CDROMREADCOOKED: + case CDROMREADALL: + /* DVD ioctls */ + case DVD_READ_STRUCT: + case DVD_WRITE_STRUCT: + case DVD_AUTH: + arg = (unsigned long)compat_ptr(arg); + /* These intepret arg as an unsigned long, not as a pointer, + * so we must not do compat_ptr() conversion. */ + case HDIO_SET_MULTCOUNT: + case HDIO_SET_UNMASKINTR: + case HDIO_SET_KEEPSETTINGS: + case HDIO_SET_32BIT: + case HDIO_SET_NOWERR: + case HDIO_SET_DMA: + case HDIO_SET_PIO_MODE: + case HDIO_SET_NICE: + case HDIO_SET_WCACHE: + case HDIO_SET_ACOUSTIC: + case HDIO_SET_BUSSTATE: + case HDIO_SET_ADDRESS: + case CDROMEJECT_SW: + case CDROM_SET_OPTIONS: + case CDROM_CLEAR_OPTIONS: + case CDROM_SELECT_SPEED: + case CDROM_SELECT_DISC: + case CDROM_MEDIA_CHANGED: + case CDROM_DRIVE_STATUS: + case CDROM_LOCKDOOR: + case CDROM_DEBUG: + break; + default: + /* unknown ioctl number */ + return -ENOIOCTLCMD; + } + + if (disk->fops->unlocked_ioctl) + return disk->fops->unlocked_ioctl(file, cmd, arg); + + if (disk->fops->ioctl) { + lock_kernel(); + ret = disk->fops->ioctl(inode, file, cmd, arg); + unlock_kernel(); + return ret; + } + + return -ENOTTY; +} + static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file, struct block_device *bdev, unsigned cmd, unsigned long arg) @@ -117,5 +233,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = disk->fops->compat_ioctl(file, cmd, arg); unlock_kernel(); - return ret; + if (ret != -ENOIOCTLCMD) + return ret; + + return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg); } diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 6be121868c60..16d681c331f9 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -2477,47 +2477,8 @@ COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ /* 0x00 */ COMPATIBLE_IOCTL(FIBMAP) COMPATIBLE_IOCTL(FIGETBSZ) -/* 0x03 -- HD/IDE ioctl's used by hdparm and friends. - * Some need translations, these do not. - */ -COMPATIBLE_IOCTL(HDIO_GET_IDENTITY) -COMPATIBLE_IOCTL(HDIO_DRIVE_TASK) -COMPATIBLE_IOCTL(HDIO_DRIVE_CMD) -ULONG_IOCTL(HDIO_SET_MULTCOUNT) -ULONG_IOCTL(HDIO_SET_UNMASKINTR) -ULONG_IOCTL(HDIO_SET_KEEPSETTINGS) -ULONG_IOCTL(HDIO_SET_32BIT) -ULONG_IOCTL(HDIO_SET_NOWERR) -ULONG_IOCTL(HDIO_SET_DMA) -ULONG_IOCTL(HDIO_SET_PIO_MODE) -ULONG_IOCTL(HDIO_SET_NICE) -ULONG_IOCTL(HDIO_SET_WCACHE) -ULONG_IOCTL(HDIO_SET_ACOUSTIC) -ULONG_IOCTL(HDIO_SET_BUSSTATE) -ULONG_IOCTL(HDIO_SET_ADDRESS) -COMPATIBLE_IOCTL(HDIO_SCAN_HWIF) -/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */ -COMPATIBLE_IOCTL(0x330) -/* 0x02 -- Floppy ioctls */ -COMPATIBLE_IOCTL(FDMSGON) -COMPATIBLE_IOCTL(FDMSGOFF) -COMPATIBLE_IOCTL(FDSETEMSGTRESH) -COMPATIBLE_IOCTL(FDFLUSH) -COMPATIBLE_IOCTL(FDWERRORCLR) -COMPATIBLE_IOCTL(FDSETMAXERRS) -COMPATIBLE_IOCTL(FDGETMAXERRS) -COMPATIBLE_IOCTL(FDGETDRVTYP) -COMPATIBLE_IOCTL(FDEJECT) -COMPATIBLE_IOCTL(FDCLRPRM) -COMPATIBLE_IOCTL(FDFMTBEG) -COMPATIBLE_IOCTL(FDFMTEND) -COMPATIBLE_IOCTL(FDRESET) -COMPATIBLE_IOCTL(FDTWADDLE) -COMPATIBLE_IOCTL(FDFMTTRK) -COMPATIBLE_IOCTL(FDRAWCMD) /* 0x12 */ #ifdef CONFIG_BLOCK -COMPATIBLE_IOCTL(BLKSECTSET) COMPATIBLE_IOCTL(BLKTRACESTART) COMPATIBLE_IOCTL(BLKTRACESTOP) COMPATIBLE_IOCTL(BLKTRACESETUP) @@ -2770,50 +2731,6 @@ COMPATIBLE_IOCTL(PPGETMODE) COMPATIBLE_IOCTL(PPGETPHASE) COMPATIBLE_IOCTL(PPGETFLAGS) COMPATIBLE_IOCTL(PPSETFLAGS) -/* CDROM stuff */ -COMPATIBLE_IOCTL(CDROMPAUSE) -COMPATIBLE_IOCTL(CDROMRESUME) -COMPATIBLE_IOCTL(CDROMPLAYMSF) -COMPATIBLE_IOCTL(CDROMPLAYTRKIND) -COMPATIBLE_IOCTL(CDROMREADTOCHDR) -COMPATIBLE_IOCTL(CDROMREADTOCENTRY) -COMPATIBLE_IOCTL(CDROMSTOP) -COMPATIBLE_IOCTL(CDROMSTART) -COMPATIBLE_IOCTL(CDROMEJECT) -COMPATIBLE_IOCTL(CDROMVOLCTRL) -COMPATIBLE_IOCTL(CDROMSUBCHNL) -ULONG_IOCTL(CDROMEJECT_SW) -COMPATIBLE_IOCTL(CDROMMULTISESSION) -COMPATIBLE_IOCTL(CDROM_GET_MCN) -COMPATIBLE_IOCTL(CDROMRESET) -COMPATIBLE_IOCTL(CDROMVOLREAD) -COMPATIBLE_IOCTL(CDROMSEEK) -COMPATIBLE_IOCTL(CDROMPLAYBLK) -COMPATIBLE_IOCTL(CDROMCLOSETRAY) -ULONG_IOCTL(CDROM_SET_OPTIONS) -ULONG_IOCTL(CDROM_CLEAR_OPTIONS) -ULONG_IOCTL(CDROM_SELECT_SPEED) -ULONG_IOCTL(CDROM_SELECT_DISC) -ULONG_IOCTL(CDROM_MEDIA_CHANGED) -ULONG_IOCTL(CDROM_DRIVE_STATUS) -COMPATIBLE_IOCTL(CDROM_DISC_STATUS) -COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS) -ULONG_IOCTL(CDROM_LOCKDOOR) -ULONG_IOCTL(CDROM_DEBUG) -COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY) -/* Ignore cdrom.h about these next 5 ioctls, they absolutely do - * not take a struct cdrom_read, instead they take a struct cdrom_msf - * which is compatible. - */ -COMPATIBLE_IOCTL(CDROMREADMODE2) -COMPATIBLE_IOCTL(CDROMREADMODE1) -COMPATIBLE_IOCTL(CDROMREADRAW) -COMPATIBLE_IOCTL(CDROMREADCOOKED) -COMPATIBLE_IOCTL(CDROMREADALL) -/* DVD ioctls */ -COMPATIBLE_IOCTL(DVD_READ_STRUCT) -COMPATIBLE_IOCTL(DVD_WRITE_STRUCT) -COMPATIBLE_IOCTL(DVD_AUTH) /* pktcdvd */ COMPATIBLE_IOCTL(PACKET_CTRL_CMD) /* Big A */ From 171044d449611c6e5040b37210ff6aba47f33ee4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 9 Oct 2007 13:23:53 +0200 Subject: [PATCH 0934/2804] compat_ioctl: handle blk_trace ioctls blk_trace_setup is broken on x86_64 compat systems, this makes the code work correctly on all 64 bit architectures in compat mode. Signed-off-by: Arnd Bergmann Signed-off-by: Jens Axboe --- block/blktrace.c | 54 +++++++++++++++++++++++------------- block/compat_ioctl.c | 54 ++++++++++++++++++++++++++++++++++++ fs/compat_ioctl.c | 8 ------ include/linux/blktrace_api.h | 7 ++++- 4 files changed, 94 insertions(+), 29 deletions(-) diff --git a/block/blktrace.c b/block/blktrace.c index 20fa034ea4a2..775471ef84a5 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -312,33 +312,26 @@ static struct rchan_callbacks blk_relay_callbacks = { /* * Setup everything required to start tracing */ -static int blk_trace_setup(struct request_queue *q, struct block_device *bdev, - char __user *arg) +int do_blk_trace_setup(struct request_queue *q, struct block_device *bdev, + struct blk_user_trace_setup *buts) { - struct blk_user_trace_setup buts; struct blk_trace *old_bt, *bt = NULL; struct dentry *dir = NULL; char b[BDEVNAME_SIZE]; int ret, i; - if (copy_from_user(&buts, arg, sizeof(buts))) - return -EFAULT; - - if (!buts.buf_size || !buts.buf_nr) + if (!buts->buf_size || !buts->buf_nr) return -EINVAL; - strcpy(buts.name, bdevname(bdev, b)); + strcpy(buts->name, bdevname(bdev, b)); /* * some device names have larger paths - convert the slashes * to underscores for this to work as expected */ - for (i = 0; i < strlen(buts.name); i++) - if (buts.name[i] == '/') - buts.name[i] = '_'; - - if (copy_to_user(arg, &buts, sizeof(buts))) - return -EFAULT; + for (i = 0; i < strlen(buts->name); i++) + if (buts->name[i] == '/') + buts->name[i] = '_'; ret = -ENOMEM; bt = kzalloc(sizeof(*bt), GFP_KERNEL); @@ -350,7 +343,7 @@ static int blk_trace_setup(struct request_queue *q, struct block_device *bdev, goto err; ret = -ENOENT; - dir = blk_create_tree(buts.name); + dir = blk_create_tree(buts->name); if (!dir) goto err; @@ -363,20 +356,21 @@ static int blk_trace_setup(struct request_queue *q, struct block_device *bdev, if (!bt->dropped_file) goto err; - bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks, bt); + bt->rchan = relay_open("trace", dir, buts->buf_size, + buts->buf_nr, &blk_relay_callbacks, bt); if (!bt->rchan) goto err; - bt->act_mask = buts.act_mask; + bt->act_mask = buts->act_mask; if (!bt->act_mask) bt->act_mask = (u16) -1; - bt->start_lba = buts.start_lba; - bt->end_lba = buts.end_lba; + bt->start_lba = buts->start_lba; + bt->end_lba = buts->end_lba; if (!bt->end_lba) bt->end_lba = -1ULL; - bt->pid = buts.pid; + bt->pid = buts->pid; bt->trace_state = Blktrace_setup; ret = -EBUSY; @@ -401,6 +395,26 @@ err: return ret; } +static int blk_trace_setup(struct request_queue *q, struct block_device *bdev, + char __user *arg) +{ + struct blk_user_trace_setup buts; + int ret; + + ret = copy_from_user(&buts, arg, sizeof(buts)); + if (ret) + return -EFAULT; + + ret = do_blk_trace_setup(q, bdev, &buts); + if (ret) + return ret; + + if (copy_to_user(arg, &buts, sizeof(buts))) + return -EFAULT; + + return 0; +} + static int blk_trace_startstop(struct request_queue *q, int start) { struct blk_trace *bt; diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index 500cc9e761c1..219b7e76e8ad 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -40,6 +40,53 @@ static int compat_put_u64(unsigned long arg, u64 val) #define BLKBSZSET_32 _IOW(0x12, 113, int) #define BLKGETSIZE64_32 _IOR(0x12, 114, int) +struct compat_blk_user_trace_setup { + char name[32]; + u16 act_mask; + u32 buf_size; + u32 buf_nr; + compat_u64 start_lba; + compat_u64 end_lba; + u32 pid; +}; +#define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup) + +static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg) +{ + struct blk_user_trace_setup buts; + struct compat_blk_user_trace_setup cbuts; + struct request_queue *q; + int ret; + + q = bdev_get_queue(bdev); + if (!q) + return -ENXIO; + + if (copy_from_user(&cbuts, arg, sizeof(cbuts))) + return -EFAULT; + + buts = (struct blk_user_trace_setup) { + .act_mask = cbuts.act_mask, + .buf_size = cbuts.buf_size, + .buf_nr = cbuts.buf_nr, + .start_lba = cbuts.start_lba, + .end_lba = cbuts.end_lba, + .pid = cbuts.pid, + }; + memcpy(&buts.name, &cbuts.name, 32); + + mutex_lock(&bdev->bd_mutex); + ret = do_blk_trace_setup(q, bdev, &buts); + mutex_unlock(&bdev->bd_mutex); + if (ret) + return ret; + + if (copy_to_user(arg, &buts.name, 32)) + return -EFAULT; + + return 0; +} + static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file, struct gendisk *disk, unsigned cmd, unsigned long arg) { @@ -197,6 +244,13 @@ static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file, case BLKGETSIZE64_32: return compat_put_u64(arg, bdev->bd_inode->i_size); + + case BLKTRACESETUP32: + return compat_blk_trace_setup(bdev, compat_ptr(arg)); + case BLKTRACESTART: /* compatible */ + case BLKTRACESTOP: /* compatible */ + case BLKTRACETEARDOWN: /* compatible */ + return blk_trace_ioctl(bdev, cmd, compat_ptr(arg)); } return -ENOIOCTLCMD; } diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 16d681c331f9..71065603a581 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include @@ -2477,13 +2476,6 @@ COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ /* 0x00 */ COMPATIBLE_IOCTL(FIBMAP) COMPATIBLE_IOCTL(FIGETBSZ) -/* 0x12 */ -#ifdef CONFIG_BLOCK -COMPATIBLE_IOCTL(BLKTRACESTART) -COMPATIBLE_IOCTL(BLKTRACESTOP) -COMPATIBLE_IOCTL(BLKTRACESETUP) -COMPATIBLE_IOCTL(BLKTRACETEARDOWN) -#endif /* RAID */ COMPATIBLE_IOCTL(RAID_VERSION) COMPATIBLE_IOCTL(GET_ARRAY_INFO) diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index 7b5d56b82b59..972093bf1853 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -142,10 +142,14 @@ struct blk_user_trace_setup { u32 pid; }; +#ifdef __KERNEL__ #if defined(CONFIG_BLK_DEV_IO_TRACE) extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *); extern void blk_trace_shutdown(struct request_queue *); extern void __blk_add_trace(struct blk_trace *, sector_t, int, int, u32, int, int, void *); +extern int do_blk_trace_setup(struct request_queue *q, + struct block_device *bdev, struct blk_user_trace_setup *buts); + /** * blk_add_trace_rq - Add a trace for a request oriented action @@ -286,6 +290,7 @@ static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio, #define blk_add_trace_generic(q, rq, rw, what) do { } while (0) #define blk_add_trace_pdu_int(q, what, bio, pdu) do { } while (0) #define blk_add_trace_remap(q, bio, dev, f, t) do {} while (0) +#define do_blk_trace_setup(q, bdev, buts) do {} while (0) #endif /* CONFIG_BLK_DEV_IO_TRACE */ - +#endif /* __KERNEL__ */ #endif From 9617db085c119879cd371e3212806a15596e121a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 9 Oct 2007 13:23:55 +0200 Subject: [PATCH 0935/2804] compat_ioctl: move hdio calls to block/compat_ioctl.c These are common to multiple block drivers, so they should be handled by the block layer. Signed-off-by: Arnd Bergmann Signed-off-by: Jens Axboe --- block/compat_ioctl.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ fs/compat_ioctl.c | 60 ------------------------------------- 2 files changed, 70 insertions(+), 60 deletions(-) diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index 219b7e76e8ad..5c6dafaad938 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -36,6 +36,62 @@ static int compat_put_u64(unsigned long arg, u64 val) return put_user(val, (compat_u64 __user *)compat_ptr(arg)); } +struct compat_hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + u32 start; +}; + +static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev, + struct compat_hd_geometry __user *ugeo) +{ + struct hd_geometry geo; + int ret; + + if (!ugeo) + return -EINVAL; + if (!disk->fops->getgeo) + return -ENOTTY; + + /* + * We need to set the startsect first, the driver may + * want to override it. + */ + geo.start = get_start_sect(bdev); + ret = disk->fops->getgeo(bdev, &geo); + if (ret) + return ret; + + ret = copy_to_user(ugeo, &geo, 4); + ret |= __put_user(geo.start, &ugeo->start); + if (ret) + ret = -EFAULT; + + return ret; +} + +static int compat_hdio_ioctl(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + unsigned long kval; + unsigned int __user *uvp; + int error; + + set_fs(KERNEL_DS); + error = blkdev_driver_ioctl(inode, file, disk, + cmd, (unsigned long)(&kval)); + set_fs(old_fs); + + if (error == 0) { + uvp = compat_ptr(arg); + if (put_user(kval, uvp)) + error = -EFAULT; + } + return error; +} + #define BLKBSZGET_32 _IOR(0x12, 112, int) #define BLKBSZSET_32 _IOW(0x12, 113, int) #define BLKGETSIZE64_32 _IOR(0x12, 114, int) @@ -93,6 +149,18 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file, int ret; switch (arg) { + case HDIO_GET_UNMASKINTR: + case HDIO_GET_MULTCOUNT: + case HDIO_GET_KEEPSETTINGS: + case HDIO_GET_32BIT: + case HDIO_GET_NOWERR: + case HDIO_GET_DMA: + case HDIO_GET_NICE: + case HDIO_GET_WCACHE: + case HDIO_GET_ACOUSTIC: + case HDIO_GET_ADDRESS: + case HDIO_GET_BUSSTATE: + return compat_hdio_ioctl(inode, file, disk, cmd, arg); /* * No handler required for the ones below, we just need to * convert arg to a 64 bit pointer. @@ -266,6 +334,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) struct gendisk *disk = bdev->bd_disk; switch (cmd) { + case HDIO_GETGEO: + return compat_hdio_getgeo(disk, bdev, compat_ptr(arg)); case BLKFLSBUF: case BLKROSET: /* diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 71065603a581..e6a94714b1b0 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -667,53 +666,6 @@ out: #endif #ifdef CONFIG_BLOCK -struct hd_geometry32 { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - u32 start; -}; - -static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct hd_geometry geo; - struct hd_geometry32 __user *ugeo; - int err; - - set_fs (KERNEL_DS); - err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); - set_fs (old_fs); - ugeo = compat_ptr(arg); - if (!err) { - err = copy_to_user (ugeo, &geo, 4); - err |= __put_user (geo.start, &ugeo->start); - if (err) - err = -EFAULT; - } - return err; -} - -static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - unsigned long kval; - unsigned int __user *uvp; - int error; - - set_fs(KERNEL_DS); - error = sys_ioctl(fd, cmd, (long)&kval); - set_fs(old_fs); - - if(error == 0) { - uvp = compat_ptr(arg); - if(put_user(kval, uvp)) - error = -EFAULT; - } - return error; -} - - typedef struct sg_io_hdr32 { compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ compat_int_t dxfer_direction; /* [i] data transfer direction */ @@ -3208,19 +3160,7 @@ HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) #endif #ifdef CONFIG_BLOCK -HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_WCACHE, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_ACOUSTIC, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_ADDRESS, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_BUSSTATE, hdio_ioctl_trans) HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) From 18cf7f8723d913ce02bea43e468bebdd07bc880c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 9 Oct 2007 13:23:56 +0200 Subject: [PATCH 0936/2804] compat_ioctl: move BLKPG handling to block/compat_ioctl.c BLKPG is common to all block devices, so it should be handled by common code. Signed-off-by: Arnd Bergmann Signed-off-by: Jens Axboe --- block/compat_ioctl.c | 31 +++++++++++++++++++++++++++++++ fs/compat_ioctl.c | 33 --------------------------------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index 5c6dafaad938..44807d38b1e7 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -92,6 +92,35 @@ static int compat_hdio_ioctl(struct inode *inode, struct file *file, return error; } +struct compat_blkpg_ioctl_arg { + compat_int_t op; + compat_int_t flags; + compat_int_t datalen; + compat_caddr_t data; +}; + +static int compat_blkpg_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32) +{ + struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a)); + compat_caddr_t udata; + compat_int_t n; + int err; + + err = get_user(n, &ua32->op); + err |= put_user(n, &a->op); + err |= get_user(n, &ua32->flags); + err |= put_user(n, &a->flags); + err |= get_user(n, &ua32->datalen); + err |= put_user(n, &a->datalen); + err |= get_user(udata, &ua32->data); + err |= put_user(compat_ptr(udata), &a->data); + if (err) + return err; + + return blkdev_ioctl(inode, file, cmd, (unsigned long)a); +} + #define BLKBSZGET_32 _IOR(0x12, 112, int) #define BLKBSZSET_32 _IOW(0x12, 113, int) #define BLKGETSIZE64_32 _IOR(0x12, 114, int) @@ -348,6 +377,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case BLKBSZSET_32: return blkdev_ioctl(inode, file, BLKBSZSET, (unsigned long)compat_ptr(arg)); + case BLKPG: + return compat_blkpg_ioctl(inode, file, cmd, compat_ptr(arg)); } lock_kernel(); diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index e6a94714b1b0..3baa90d31090 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -1487,37 +1486,6 @@ ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) return -EINVAL; } -#ifdef CONFIG_BLOCK -struct blkpg_ioctl_arg32 { - compat_int_t op; - compat_int_t flags; - compat_int_t datalen; - compat_caddr_t data; -}; - -static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct blkpg_ioctl_arg32 __user *ua32 = compat_ptr(arg); - struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a)); - compat_caddr_t udata; - compat_int_t n; - int err; - - err = get_user(n, &ua32->op); - err |= put_user(n, &a->op); - err |= get_user(n, &ua32->flags); - err |= put_user(n, &a->flags); - err |= get_user(n, &ua32->datalen); - err |= put_user(n, &a->datalen); - err |= get_user(udata, &ua32->data); - err |= put_user(compat_ptr(udata), &a->data); - if (err) - return err; - - return sys_ioctl(fd, cmd, (unsigned long)a); -} -#endif - static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) { return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); @@ -3160,7 +3128,6 @@ HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) #endif #ifdef CONFIG_BLOCK -HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) From b3087cc4f31a66c8c7b63419e913ed9d34145f10 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 9 Oct 2007 13:23:56 +0200 Subject: [PATCH 0937/2804] compat_ioctl: move cdrom handlers to block/compat_ioctl.c These are shared by all cd-rom drivers and should have common handlers. Do slight cosmetic cleanups in the process. Signed-off-by: Arnd Bergmann Signed-off-by: Jens Axboe --- block/compat_ioctl.c | 83 ++++++++++++++++++++++++++++++++++ fs/compat_ioctl.c | 105 ------------------------------------------- 2 files changed, 83 insertions(+), 105 deletions(-) diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index 44807d38b1e7..92b3e8d07ca6 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -92,6 +92,84 @@ static int compat_hdio_ioctl(struct inode *inode, struct file *file, return error; } +struct compat_cdrom_read_audio { + union cdrom_addr addr; + u8 addr_format; + compat_int_t nframes; + compat_caddr_t buf; +}; + +struct compat_cdrom_generic_command { + unsigned char cmd[CDROM_PACKET_SIZE]; + compat_caddr_t buffer; + compat_uint_t buflen; + compat_int_t stat; + compat_caddr_t sense; + unsigned char data_direction; + compat_int_t quiet; + compat_int_t timeout; + compat_caddr_t reserved[1]; +}; + +static int compat_cdrom_read_audio(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned int cmd, unsigned long arg) +{ + struct cdrom_read_audio __user *cdread_audio; + struct compat_cdrom_read_audio __user *cdread_audio32; + __u32 data; + void __user *datap; + + cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio)); + cdread_audio32 = compat_ptr(arg); + + if (copy_in_user(&cdread_audio->addr, + &cdread_audio32->addr, + (sizeof(*cdread_audio32) - + sizeof(compat_caddr_t)))) + return -EFAULT; + + if (get_user(data, &cdread_audio32->buf)) + return -EFAULT; + datap = compat_ptr(data); + if (put_user(datap, &cdread_audio->buf)) + return -EFAULT; + + return blkdev_driver_ioctl(inode, file, disk, cmd, + (unsigned long)cdread_audio); +} + +static int compat_cdrom_generic_command(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned int cmd, unsigned long arg) +{ + struct cdrom_generic_command __user *cgc; + struct compat_cdrom_generic_command __user *cgc32; + u32 data; + unsigned char dir; + int itmp; + + cgc = compat_alloc_user_space(sizeof(*cgc)); + cgc32 = compat_ptr(arg); + + if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) || + get_user(data, &cgc32->buffer) || + put_user(compat_ptr(data), &cgc->buffer) || + copy_in_user(&cgc->buflen, &cgc32->buflen, + (sizeof(unsigned int) + sizeof(int))) || + get_user(data, &cgc32->sense) || + put_user(compat_ptr(data), &cgc->sense) || + get_user(dir, &cgc32->data_direction) || + put_user(dir, &cgc->data_direction) || + get_user(itmp, &cgc32->quiet) || + put_user(itmp, &cgc->quiet) || + get_user(itmp, &cgc32->timeout) || + put_user(itmp, &cgc->timeout) || + get_user(data, &cgc32->reserved[0]) || + put_user(compat_ptr(data), &cgc->reserved[0])) + return -EFAULT; + + return blkdev_driver_ioctl(inode, file, disk, cmd, (unsigned long)cgc); +} + struct compat_blkpg_ioctl_arg { compat_int_t op; compat_int_t flags; @@ -190,6 +268,11 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file, case HDIO_GET_ADDRESS: case HDIO_GET_BUSSTATE: return compat_hdio_ioctl(inode, file, disk, cmd, arg); + case CDROMREADAUDIO: + return compat_cdrom_read_audio(inode, file, disk, cmd, arg); + case CDROM_SEND_PACKET: + return compat_cdrom_generic_command(inode, file, disk, cmd, arg); + /* * No handler required for the ones below, we just need to * convert arg to a 64 bit pointer. diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 3baa90d31090..24c743571127 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -1039,108 +1038,6 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) return err ? -EFAULT: 0; } -struct cdrom_read_audio32 { - union cdrom_addr addr; - u8 addr_format; - compat_int_t nframes; - compat_caddr_t buf; -}; - -struct cdrom_generic_command32 { - unsigned char cmd[CDROM_PACKET_SIZE]; - compat_caddr_t buffer; - compat_uint_t buflen; - compat_int_t stat; - compat_caddr_t sense; - unsigned char data_direction; - compat_int_t quiet; - compat_int_t timeout; - compat_caddr_t reserved[1]; -}; - -static int cdrom_do_read_audio(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct cdrom_read_audio __user *cdread_audio; - struct cdrom_read_audio32 __user *cdread_audio32; - __u32 data; - void __user *datap; - - cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio)); - cdread_audio32 = compat_ptr(arg); - - if (copy_in_user(&cdread_audio->addr, - &cdread_audio32->addr, - (sizeof(*cdread_audio32) - - sizeof(compat_caddr_t)))) - return -EFAULT; - - if (get_user(data, &cdread_audio32->buf)) - return -EFAULT; - datap = compat_ptr(data); - if (put_user(datap, &cdread_audio->buf)) - return -EFAULT; - - return sys_ioctl(fd, cmd, (unsigned long) cdread_audio); -} - -static int cdrom_do_generic_command(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct cdrom_generic_command __user *cgc; - struct cdrom_generic_command32 __user *cgc32; - u32 data; - unsigned char dir; - int itmp; - - cgc = compat_alloc_user_space(sizeof(*cgc)); - cgc32 = compat_ptr(arg); - - if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) || - get_user(data, &cgc32->buffer) || - put_user(compat_ptr(data), &cgc->buffer) || - copy_in_user(&cgc->buflen, &cgc32->buflen, - (sizeof(unsigned int) + sizeof(int))) || - get_user(data, &cgc32->sense) || - put_user(compat_ptr(data), &cgc->sense) || - get_user(dir, &cgc32->data_direction) || - put_user(dir, &cgc->data_direction) || - get_user(itmp, &cgc32->quiet) || - put_user(itmp, &cgc->quiet) || - get_user(itmp, &cgc32->timeout) || - put_user(itmp, &cgc->timeout) || - get_user(data, &cgc32->reserved[0]) || - put_user(compat_ptr(data), &cgc->reserved[0])) - return -EFAULT; - - return sys_ioctl(fd, cmd, (unsigned long) cgc); -} - -static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - int err; - - switch(cmd) { - case CDROMREADAUDIO: - err = cdrom_do_read_audio(fd, cmd, arg); - break; - - case CDROM_SEND_PACKET: - err = cdrom_do_generic_command(fd, cmd, arg); - break; - - default: - do { - static int count; - if (++count <= 20) - printk("cdrom_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); - err = -EINVAL; - break; - }; - - return err; -} #endif /* CONFIG_BLOCK */ #ifdef CONFIG_VT @@ -3147,8 +3044,6 @@ HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans) #ifdef CONFIG_BLOCK HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) -HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) #endif #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) From 1ca91cd0336b05b91c51b403c9ed9d297813533f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 9 Oct 2007 13:23:57 +0200 Subject: [PATCH 0938/2804] compat_ioctl: move floppy handlers to block/compat_ioctl.c The floppy ioctls are used by multiple drivers, so they should be handled in a shared location. Also, add minor cleanups. Signed-off-by: Arnd Bergmann Signed-off-by: Jens Axboe --- block/compat_ioctl.c | 336 ++++++++++++++++++++++++++++++++++++++++++ fs/compat_ioctl.c | 337 ------------------------------------------- 2 files changed, 336 insertions(+), 337 deletions(-) diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index 92b3e8d07ca6..f84093b97f70 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -203,6 +203,332 @@ static int compat_blkpg_ioctl(struct inode *inode, struct file *file, #define BLKBSZSET_32 _IOW(0x12, 113, int) #define BLKGETSIZE64_32 _IOR(0x12, 114, int) +struct compat_floppy_struct { + compat_uint_t size; + compat_uint_t sect; + compat_uint_t head; + compat_uint_t track; + compat_uint_t stretch; + unsigned char gap; + unsigned char rate; + unsigned char spec1; + unsigned char fmt_gap; + const compat_caddr_t name; +}; + +struct compat_floppy_drive_params { + char cmos; + compat_ulong_t max_dtr; + compat_ulong_t hlt; + compat_ulong_t hut; + compat_ulong_t srt; + compat_ulong_t spinup; + compat_ulong_t spindown; + unsigned char spindown_offset; + unsigned char select_delay; + unsigned char rps; + unsigned char tracks; + compat_ulong_t timeout; + unsigned char interleave_sect; + struct floppy_max_errors max_errors; + char flags; + char read_track; + short autodetect[8]; + compat_int_t checkfreq; + compat_int_t native_format; +}; + +struct compat_floppy_drive_struct { + signed char flags; + compat_ulong_t spinup_date; + compat_ulong_t select_date; + compat_ulong_t first_read_date; + short probed_format; + short track; + short maxblock; + short maxtrack; + compat_int_t generation; + compat_int_t keep_data; + compat_int_t fd_ref; + compat_int_t fd_device; + compat_int_t last_checked; + compat_caddr_t dmabuf; + compat_int_t bufblocks; +}; + +struct compat_floppy_fdc_state { + compat_int_t spec1; + compat_int_t spec2; + compat_int_t dtr; + unsigned char version; + unsigned char dor; + compat_ulong_t address; + unsigned int rawcmd:2; + unsigned int reset:1; + unsigned int need_configure:1; + unsigned int perp_mode:2; + unsigned int has_fifo:1; + unsigned int driver_version; + unsigned char track[4]; +}; + +struct compat_floppy_write_errors { + unsigned int write_errors; + compat_ulong_t first_error_sector; + compat_int_t first_error_generation; + compat_ulong_t last_error_sector; + compat_int_t last_error_generation; + compat_uint_t badness; +}; + +#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct) +#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct) +#define FDGETPRM32 _IOR(2, 0x04, struct compat_floppy_struct) +#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params) +#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params) +#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct) +#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct) +#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state) +#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} fd_ioctl_trans_table[] = { + { FDSETPRM32, FDSETPRM }, + { FDDEFPRM32, FDDEFPRM }, + { FDGETPRM32, FDGETPRM }, + { FDSETDRVPRM32, FDSETDRVPRM }, + { FDGETDRVPRM32, FDGETDRVPRM }, + { FDGETDRVSTAT32, FDGETDRVSTAT }, + { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, + { FDGETFDCSTAT32, FDGETFDCSTAT }, + { FDWERRORGET32, FDWERRORGET } +}; + +#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table) + +static int compat_fd_ioctl(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + void *karg = NULL; + unsigned int kcmd = 0; + int i, err; + + for (i = 0; i < NR_FD_IOCTL_TRANS; i++) + if (cmd == fd_ioctl_trans_table[i].cmd32) { + kcmd = fd_ioctl_trans_table[i].cmd; + break; + } + if (!kcmd) + return -EINVAL; + + switch (cmd) { + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + { + compat_uptr_t name; + struct compat_floppy_struct __user *uf; + struct floppy_struct *f; + + uf = compat_ptr(arg); + f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); + if (!karg) + return -ENOMEM; + if (cmd == FDGETPRM32) + break; + err = __get_user(f->size, &uf->size); + err |= __get_user(f->sect, &uf->sect); + err |= __get_user(f->head, &uf->head); + err |= __get_user(f->track, &uf->track); + err |= __get_user(f->stretch, &uf->stretch); + err |= __get_user(f->gap, &uf->gap); + err |= __get_user(f->rate, &uf->rate); + err |= __get_user(f->spec1, &uf->spec1); + err |= __get_user(f->fmt_gap, &uf->fmt_gap); + err |= __get_user(name, &uf->name); + f->name = compat_ptr(name); + if (err) { + err = -EFAULT; + goto out; + } + break; + } + case FDSETDRVPRM32: + case FDGETDRVPRM32: + { + struct compat_floppy_drive_params __user *uf; + struct floppy_drive_params *f; + + uf = compat_ptr(arg); + f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL); + if (!karg) + return -ENOMEM; + if (cmd == FDGETDRVPRM32) + break; + err = __get_user(f->cmos, &uf->cmos); + err |= __get_user(f->max_dtr, &uf->max_dtr); + err |= __get_user(f->hlt, &uf->hlt); + err |= __get_user(f->hut, &uf->hut); + err |= __get_user(f->srt, &uf->srt); + err |= __get_user(f->spinup, &uf->spinup); + err |= __get_user(f->spindown, &uf->spindown); + err |= __get_user(f->spindown_offset, &uf->spindown_offset); + err |= __get_user(f->select_delay, &uf->select_delay); + err |= __get_user(f->rps, &uf->rps); + err |= __get_user(f->tracks, &uf->tracks); + err |= __get_user(f->timeout, &uf->timeout); + err |= __get_user(f->interleave_sect, &uf->interleave_sect); + err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors)); + err |= __get_user(f->flags, &uf->flags); + err |= __get_user(f->read_track, &uf->read_track); + err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect)); + err |= __get_user(f->checkfreq, &uf->checkfreq); + err |= __get_user(f->native_format, &uf->native_format); + if (err) { + err = -EFAULT; + goto out; + } + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + case FDGETFDCSTAT32: + karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + case FDWERRORGET32: + karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + default: + return -EINVAL; + } + set_fs(KERNEL_DS); + err = blkdev_driver_ioctl(inode, file, disk, kcmd, (unsigned long)karg); + set_fs(old_fs); + if (err) + goto out; + switch (cmd) { + case FDGETPRM32: + { + struct floppy_struct *f = karg; + struct compat_floppy_struct __user *uf = compat_ptr(arg); + + err = __put_user(f->size, &uf->size); + err |= __put_user(f->sect, &uf->sect); + err |= __put_user(f->head, &uf->head); + err |= __put_user(f->track, &uf->track); + err |= __put_user(f->stretch, &uf->stretch); + err |= __put_user(f->gap, &uf->gap); + err |= __put_user(f->rate, &uf->rate); + err |= __put_user(f->spec1, &uf->spec1); + err |= __put_user(f->fmt_gap, &uf->fmt_gap); + err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name); + break; + } + case FDGETDRVPRM32: + { + struct compat_floppy_drive_params __user *uf; + struct floppy_drive_params *f = karg; + + uf = compat_ptr(arg); + err = __put_user(f->cmos, &uf->cmos); + err |= __put_user(f->max_dtr, &uf->max_dtr); + err |= __put_user(f->hlt, &uf->hlt); + err |= __put_user(f->hut, &uf->hut); + err |= __put_user(f->srt, &uf->srt); + err |= __put_user(f->spinup, &uf->spinup); + err |= __put_user(f->spindown, &uf->spindown); + err |= __put_user(f->spindown_offset, &uf->spindown_offset); + err |= __put_user(f->select_delay, &uf->select_delay); + err |= __put_user(f->rps, &uf->rps); + err |= __put_user(f->tracks, &uf->tracks); + err |= __put_user(f->timeout, &uf->timeout); + err |= __put_user(f->interleave_sect, &uf->interleave_sect); + err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors)); + err |= __put_user(f->flags, &uf->flags); + err |= __put_user(f->read_track, &uf->read_track); + err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect)); + err |= __put_user(f->checkfreq, &uf->checkfreq); + err |= __put_user(f->native_format, &uf->native_format); + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + { + struct compat_floppy_drive_struct __user *uf; + struct floppy_drive_struct *f = karg; + + uf = compat_ptr(arg); + err = __put_user(f->flags, &uf->flags); + err |= __put_user(f->spinup_date, &uf->spinup_date); + err |= __put_user(f->select_date, &uf->select_date); + err |= __put_user(f->first_read_date, &uf->first_read_date); + err |= __put_user(f->probed_format, &uf->probed_format); + err |= __put_user(f->track, &uf->track); + err |= __put_user(f->maxblock, &uf->maxblock); + err |= __put_user(f->maxtrack, &uf->maxtrack); + err |= __put_user(f->generation, &uf->generation); + err |= __put_user(f->keep_data, &uf->keep_data); + err |= __put_user(f->fd_ref, &uf->fd_ref); + err |= __put_user(f->fd_device, &uf->fd_device); + err |= __put_user(f->last_checked, &uf->last_checked); + err |= __put_user((u64)f->dmabuf, &uf->dmabuf); + err |= __put_user((u64)f->bufblocks, &uf->bufblocks); + break; + } + case FDGETFDCSTAT32: + { + struct compat_floppy_fdc_state __user *uf; + struct floppy_fdc_state *f = karg; + + uf = compat_ptr(arg); + err = __put_user(f->spec1, &uf->spec1); + err |= __put_user(f->spec2, &uf->spec2); + err |= __put_user(f->dtr, &uf->dtr); + err |= __put_user(f->version, &uf->version); + err |= __put_user(f->dor, &uf->dor); + err |= __put_user(f->address, &uf->address); + err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address), + (char *)&f->address + sizeof(f->address), sizeof(int)); + err |= __put_user(f->driver_version, &uf->driver_version); + err |= __copy_to_user(uf->track, f->track, sizeof(f->track)); + break; + } + case FDWERRORGET32: + { + struct compat_floppy_write_errors __user *uf; + struct floppy_write_errors *f = karg; + + uf = compat_ptr(arg); + err = __put_user(f->write_errors, &uf->write_errors); + err |= __put_user(f->first_error_sector, &uf->first_error_sector); + err |= __put_user(f->first_error_generation, &uf->first_error_generation); + err |= __put_user(f->last_error_sector, &uf->last_error_sector); + err |= __put_user(f->last_error_generation, &uf->last_error_generation); + err |= __put_user(f->badness, &uf->badness); + break; + } + default: + break; + } + if (err) + err = -EFAULT; + +out: + kfree(karg); + return err; +} + struct compat_blk_user_trace_setup { char name[32]; u16 act_mask; @@ -268,6 +594,16 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file, case HDIO_GET_ADDRESS: case HDIO_GET_BUSSTATE: return compat_hdio_ioctl(inode, file, disk, cmd, arg); + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + case FDSETDRVPRM32: + case FDGETDRVPRM32: + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + case FDGETFDCSTAT32: + case FDWERRORGET32: + return compat_fd_ioctl(inode, file, disk, cmd, arg); case CDROMREADAUDIO: return compat_cdrom_read_audio(inode, file, disk, cmd, arg); case CDROM_SEND_PACKET: diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 24c743571127..b9e3357bcc2e 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -1407,333 +1406,6 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) #define HIDPGETCONNLIST _IOR('H', 210, int) #define HIDPGETCONNINFO _IOR('H', 211, int) -#ifdef CONFIG_BLOCK -struct floppy_struct32 { - compat_uint_t size; - compat_uint_t sect; - compat_uint_t head; - compat_uint_t track; - compat_uint_t stretch; - unsigned char gap; - unsigned char rate; - unsigned char spec1; - unsigned char fmt_gap; - const compat_caddr_t name; -}; - -struct floppy_drive_params32 { - char cmos; - compat_ulong_t max_dtr; - compat_ulong_t hlt; - compat_ulong_t hut; - compat_ulong_t srt; - compat_ulong_t spinup; - compat_ulong_t spindown; - unsigned char spindown_offset; - unsigned char select_delay; - unsigned char rps; - unsigned char tracks; - compat_ulong_t timeout; - unsigned char interleave_sect; - struct floppy_max_errors max_errors; - char flags; - char read_track; - short autodetect[8]; - compat_int_t checkfreq; - compat_int_t native_format; -}; - -struct floppy_drive_struct32 { - signed char flags; - compat_ulong_t spinup_date; - compat_ulong_t select_date; - compat_ulong_t first_read_date; - short probed_format; - short track; - short maxblock; - short maxtrack; - compat_int_t generation; - compat_int_t keep_data; - compat_int_t fd_ref; - compat_int_t fd_device; - compat_int_t last_checked; - compat_caddr_t dmabuf; - compat_int_t bufblocks; -}; - -struct floppy_fdc_state32 { - compat_int_t spec1; - compat_int_t spec2; - compat_int_t dtr; - unsigned char version; - unsigned char dor; - compat_ulong_t address; - unsigned int rawcmd:2; - unsigned int reset:1; - unsigned int need_configure:1; - unsigned int perp_mode:2; - unsigned int has_fifo:1; - unsigned int driver_version; - unsigned char track[4]; -}; - -struct floppy_write_errors32 { - unsigned int write_errors; - compat_ulong_t first_error_sector; - compat_int_t first_error_generation; - compat_ulong_t last_error_sector; - compat_int_t last_error_generation; - compat_uint_t badness; -}; - -#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) -#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) -#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) -#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) -#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) -#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) -#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) -#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) -#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) - -static struct { - unsigned int cmd32; - unsigned int cmd; -} fd_ioctl_trans_table[] = { - { FDSETPRM32, FDSETPRM }, - { FDDEFPRM32, FDDEFPRM }, - { FDGETPRM32, FDGETPRM }, - { FDSETDRVPRM32, FDSETDRVPRM }, - { FDGETDRVPRM32, FDGETDRVPRM }, - { FDGETDRVSTAT32, FDGETDRVSTAT }, - { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, - { FDGETFDCSTAT32, FDGETFDCSTAT }, - { FDWERRORGET32, FDWERRORGET } -}; - -#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table) - -static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - void *karg = NULL; - unsigned int kcmd = 0; - int i, err; - - for (i = 0; i < NR_FD_IOCTL_TRANS; i++) - if (cmd == fd_ioctl_trans_table[i].cmd32) { - kcmd = fd_ioctl_trans_table[i].cmd; - break; - } - if (!kcmd) - return -EINVAL; - - switch (cmd) { - case FDSETPRM32: - case FDDEFPRM32: - case FDGETPRM32: - { - compat_uptr_t name; - struct floppy_struct32 __user *uf; - struct floppy_struct *f; - - uf = compat_ptr(arg); - f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); - if (!karg) - return -ENOMEM; - if (cmd == FDGETPRM32) - break; - err = __get_user(f->size, &uf->size); - err |= __get_user(f->sect, &uf->sect); - err |= __get_user(f->head, &uf->head); - err |= __get_user(f->track, &uf->track); - err |= __get_user(f->stretch, &uf->stretch); - err |= __get_user(f->gap, &uf->gap); - err |= __get_user(f->rate, &uf->rate); - err |= __get_user(f->spec1, &uf->spec1); - err |= __get_user(f->fmt_gap, &uf->fmt_gap); - err |= __get_user(name, &uf->name); - f->name = compat_ptr(name); - if (err) { - err = -EFAULT; - goto out; - } - break; - } - case FDSETDRVPRM32: - case FDGETDRVPRM32: - { - struct floppy_drive_params32 __user *uf; - struct floppy_drive_params *f; - - uf = compat_ptr(arg); - f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL); - if (!karg) - return -ENOMEM; - if (cmd == FDGETDRVPRM32) - break; - err = __get_user(f->cmos, &uf->cmos); - err |= __get_user(f->max_dtr, &uf->max_dtr); - err |= __get_user(f->hlt, &uf->hlt); - err |= __get_user(f->hut, &uf->hut); - err |= __get_user(f->srt, &uf->srt); - err |= __get_user(f->spinup, &uf->spinup); - err |= __get_user(f->spindown, &uf->spindown); - err |= __get_user(f->spindown_offset, &uf->spindown_offset); - err |= __get_user(f->select_delay, &uf->select_delay); - err |= __get_user(f->rps, &uf->rps); - err |= __get_user(f->tracks, &uf->tracks); - err |= __get_user(f->timeout, &uf->timeout); - err |= __get_user(f->interleave_sect, &uf->interleave_sect); - err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors)); - err |= __get_user(f->flags, &uf->flags); - err |= __get_user(f->read_track, &uf->read_track); - err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect)); - err |= __get_user(f->checkfreq, &uf->checkfreq); - err |= __get_user(f->native_format, &uf->native_format); - if (err) { - err = -EFAULT; - goto out; - } - break; - } - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - case FDGETFDCSTAT32: - karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - case FDWERRORGET32: - karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - default: - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, kcmd, (unsigned long)karg); - set_fs (old_fs); - if (err) - goto out; - switch (cmd) { - case FDGETPRM32: - { - struct floppy_struct *f = karg; - struct floppy_struct32 __user *uf = compat_ptr(arg); - - err = __put_user(f->size, &uf->size); - err |= __put_user(f->sect, &uf->sect); - err |= __put_user(f->head, &uf->head); - err |= __put_user(f->track, &uf->track); - err |= __put_user(f->stretch, &uf->stretch); - err |= __put_user(f->gap, &uf->gap); - err |= __put_user(f->rate, &uf->rate); - err |= __put_user(f->spec1, &uf->spec1); - err |= __put_user(f->fmt_gap, &uf->fmt_gap); - err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name); - break; - } - case FDGETDRVPRM32: - { - struct floppy_drive_params32 __user *uf; - struct floppy_drive_params *f = karg; - - uf = compat_ptr(arg); - err = __put_user(f->cmos, &uf->cmos); - err |= __put_user(f->max_dtr, &uf->max_dtr); - err |= __put_user(f->hlt, &uf->hlt); - err |= __put_user(f->hut, &uf->hut); - err |= __put_user(f->srt, &uf->srt); - err |= __put_user(f->spinup, &uf->spinup); - err |= __put_user(f->spindown, &uf->spindown); - err |= __put_user(f->spindown_offset, &uf->spindown_offset); - err |= __put_user(f->select_delay, &uf->select_delay); - err |= __put_user(f->rps, &uf->rps); - err |= __put_user(f->tracks, &uf->tracks); - err |= __put_user(f->timeout, &uf->timeout); - err |= __put_user(f->interleave_sect, &uf->interleave_sect); - err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors)); - err |= __put_user(f->flags, &uf->flags); - err |= __put_user(f->read_track, &uf->read_track); - err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect)); - err |= __put_user(f->checkfreq, &uf->checkfreq); - err |= __put_user(f->native_format, &uf->native_format); - break; - } - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - { - struct floppy_drive_struct32 __user *uf; - struct floppy_drive_struct *f = karg; - - uf = compat_ptr(arg); - err = __put_user(f->flags, &uf->flags); - err |= __put_user(f->spinup_date, &uf->spinup_date); - err |= __put_user(f->select_date, &uf->select_date); - err |= __put_user(f->first_read_date, &uf->first_read_date); - err |= __put_user(f->probed_format, &uf->probed_format); - err |= __put_user(f->track, &uf->track); - err |= __put_user(f->maxblock, &uf->maxblock); - err |= __put_user(f->maxtrack, &uf->maxtrack); - err |= __put_user(f->generation, &uf->generation); - err |= __put_user(f->keep_data, &uf->keep_data); - err |= __put_user(f->fd_ref, &uf->fd_ref); - err |= __put_user(f->fd_device, &uf->fd_device); - err |= __put_user(f->last_checked, &uf->last_checked); - err |= __put_user((u64)f->dmabuf, &uf->dmabuf); - err |= __put_user((u64)f->bufblocks, &uf->bufblocks); - break; - } - case FDGETFDCSTAT32: - { - struct floppy_fdc_state32 __user *uf; - struct floppy_fdc_state *f = karg; - - uf = compat_ptr(arg); - err = __put_user(f->spec1, &uf->spec1); - err |= __put_user(f->spec2, &uf->spec2); - err |= __put_user(f->dtr, &uf->dtr); - err |= __put_user(f->version, &uf->version); - err |= __put_user(f->dor, &uf->dor); - err |= __put_user(f->address, &uf->address); - err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address), - (char *)&f->address + sizeof(f->address), sizeof(int)); - err |= __put_user(f->driver_version, &uf->driver_version); - err |= __copy_to_user(uf->track, f->track, sizeof(f->track)); - break; - } - case FDWERRORGET32: - { - struct floppy_write_errors32 __user *uf; - struct floppy_write_errors *f = karg; - - uf = compat_ptr(arg); - err = __put_user(f->write_errors, &uf->write_errors); - err |= __put_user(f->first_error_sector, &uf->first_error_sector); - err |= __put_user(f->first_error_generation, &uf->first_error_generation); - err |= __put_user(f->last_error_sector, &uf->last_error_sector); - err |= __put_user(f->last_error_generation, &uf->last_error_generation); - err |= __put_user(f->badness, &uf->badness); - break; - } - default: - break; - } - if (err) - err = -EFAULT; - -out: - kfree(karg); - return err; -} -#endif - struct mtd_oob_buf32 { u_int32_t start; u_int32_t length; @@ -3025,15 +2697,6 @@ HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) #endif #ifdef CONFIG_BLOCK -HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans) HANDLE_IOCTL(SG_IO,sg_ioctl_trans) HANDLE_IOCTL(SG_GET_REQUEST_TABLE, sg_grt_trans) #endif From 87124e581bfeaa5864662a435b6ee2a19e91b905 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 23 Jul 2007 09:54:36 +0100 Subject: [PATCH 0939/2804] [GFS2] Fix two races relating to glock callbacks One of the races relates to referencing a variable while not holding its protecting spinlock. The patch simply moves the test inside the spin lock. The other races occurs when a demote to unlocked request occurs during the time a demote to shared request is already running. This of course only happens in the case that the lock was in the exclusive mode to start with. The patch adds a check to see if another demote request has occurred in the mean time and if it has, then it performs a second demote. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 3f0974e1afef..6a3eeba102f9 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -545,12 +545,14 @@ static int rq_demote(struct gfs2_glock *gl) return 0; } set_bit(GLF_LOCK, &gl->gl_flags); - spin_unlock(&gl->gl_spin); if (gl->gl_demote_state == LM_ST_UNLOCKED || - gl->gl_state != LM_ST_EXCLUSIVE) + gl->gl_state != LM_ST_EXCLUSIVE) { + spin_unlock(&gl->gl_spin); gfs2_glock_drop_th(gl); - else + } else { + spin_unlock(&gl->gl_spin); gfs2_glock_xmote_th(gl, NULL); + } spin_lock(&gl->gl_spin); return 0; @@ -760,10 +762,20 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) if (!gh) { gl->gl_stamp = jiffies; - if (ret & LM_OUT_CANCELED) + if (ret & LM_OUT_CANCELED) { op_done = 0; - else + } else { + spin_lock(&gl->gl_spin); + if (gl->gl_state != gl->gl_demote_state) { + gl->gl_req_bh = NULL; + spin_unlock(&gl->gl_spin); + gfs2_glock_drop_th(gl); + gfs2_glock_put(gl); + return; + } gfs2_demote_wake(gl); + spin_unlock(&gl->gl_spin); + } } else { spin_lock(&gl->gl_spin); list_del_init(&gh->gh_list); @@ -817,7 +829,7 @@ out: * */ -void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) +static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) { struct gfs2_sbd *sdp = gl->gl_sbd; int flags = gh ? gh->gh_flags : 0; From 26caee5bc643b318fa2e9bd4f66dace1755ec413 Mon Sep 17 00:00:00 2001 From: Josef Whiter Date: Mon, 23 Jul 2007 10:02:40 +0100 Subject: [PATCH 0940/2804] [GFS2] Fix calculation of demote state If a glock is in the exclusive state and a request for demote to deferred has been received, then further requests for demote to shared are being ignored. This patch fixes that by ensuring that we demote to unlocked in that case. Signed-off-by: Josef Whiter Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 6a3eeba102f9..6b6ae4537340 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -697,8 +697,9 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remot } return; } - } else if (gl->gl_demote_state != LM_ST_UNLOCKED) { - gl->gl_demote_state = state; + } else if (gl->gl_demote_state != LM_ST_UNLOCKED && + gl->gl_demote_state != state) { + gl->gl_demote_state = LM_ST_UNLOCKED; } spin_unlock(&gl->gl_spin); } From aa0481e58a9a97a97035725a712920b5fe32f348 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 21 Jul 2007 17:03:22 +0200 Subject: [PATCH 0941/2804] [GFS2] Clean up duplicate includes in fs/gfs2/ This patch cleans up duplicate includes in fs/gfs2/ Signed-off-by: Jesper Juhl Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 2 -- fs/gfs2/locking/dlm/lock_dlm.h | 1 - fs/gfs2/locking/nolock/main.c | 1 - 3 files changed, 4 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 6b6ae4537340..d403fd708075 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include "gfs2.h" #include "incore.h" diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 24d70f73b651..9e8265d28377 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index 0d149c8c493a..d3b8ce6fbbe3 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include From afd0942d98f74296b74993739e41d2ca7cb9fd5a Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 20 Jul 2007 13:07:26 -0500 Subject: [PATCH 0942/2804] [GFS2] GFS2 not checking pointer on create when running under nfsd When looking at an unrelated problem, I noticed that nfsd does not set nameidata pointer on create (ie nd is NULL). This should cause an oops in some cases in which when NFSd is mounted over GFS2. Signed-off-by: Steve French Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 911c115b5c6c..5b8b994b9912 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -69,7 +69,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, mark_inode_dirty(inode); break; } else if (PTR_ERR(inode) != -EEXIST || - (nd->intent.open.flags & O_EXCL)) { + (nd && (nd->intent.open.flags & O_EXCL))) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); } From 7b08fc620109c2f66575e9ae884f45c37933ea18 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 24 Jul 2007 13:53:36 +0100 Subject: [PATCH 0943/2804] [GFS2] Fix an oops in glock dumping This fixes an oops which was occurring during glock dumping due to the seq file code not taking a reference to the glock. Also this fixes a memory leak which occurred in certain cases, in turn preventing the filesystem from unmounting. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 73 ++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index d403fd708075..e4bc8ae561aa 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -46,7 +46,6 @@ struct glock_iter { int hash; /* hash bucket index */ struct gfs2_sbd *sdp; /* incore superblock */ struct gfs2_glock *gl; /* current glock struct */ - struct hlist_head *hb_list; /* current hash bucket ptr */ struct seq_file *seq; /* sequence file for debugfs */ char string[512]; /* scratch space */ }; @@ -1990,47 +1989,38 @@ int __init gfs2_glock_init(void) static int gfs2_glock_iter_next(struct glock_iter *gi) { + struct gfs2_glock *gl; + read_lock(gl_lock_addr(gi->hash)); - while (1) { - if (!gi->hb_list) { /* If we don't have a hash bucket yet */ - gi->hb_list = &gl_hash_table[gi->hash].hb_list; - if (hlist_empty(gi->hb_list)) { - read_unlock(gl_lock_addr(gi->hash)); - gi->hash++; - read_lock(gl_lock_addr(gi->hash)); - gi->hb_list = NULL; - if (gi->hash >= GFS2_GL_HASH_SIZE) { - read_unlock(gl_lock_addr(gi->hash)); - return 1; - } - else - continue; - } - if (!hlist_empty(gi->hb_list)) { - gi->gl = list_entry(gi->hb_list->first, - struct gfs2_glock, - gl_list); - } - } else { - if (gi->gl->gl_list.next == NULL) { - read_unlock(gl_lock_addr(gi->hash)); - gi->hash++; - read_lock(gl_lock_addr(gi->hash)); - gi->hb_list = NULL; - continue; - } - gi->gl = list_entry(gi->gl->gl_list.next, - struct gfs2_glock, gl_list); - } + gl = gi->gl; + if (gl) { + gi->gl = hlist_entry(gl->gl_list.next, struct gfs2_glock, + gl_list); if (gi->gl) - break; + gfs2_glock_hold(gi->gl); } read_unlock(gl_lock_addr(gi->hash)); + if (gl) + gfs2_glock_put(gl); + + while(gi->gl == NULL) { + gi->hash++; + if (gi->hash >= GFS2_GL_HASH_SIZE) + return 1; + read_lock(gl_lock_addr(gi->hash)); + gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first, + struct gfs2_glock, gl_list); + if (gi->gl) + gfs2_glock_hold(gi->gl); + read_unlock(gl_lock_addr(gi->hash)); + } return 0; } static void gfs2_glock_iter_free(struct glock_iter *gi) { + if (gi->gl) + gfs2_glock_put(gi->gl); kfree(gi); } @@ -2044,12 +2034,17 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp) gi->sdp = sdp; gi->hash = 0; - gi->gl = NULL; - gi->hb_list = NULL; gi->seq = NULL; memset(gi->string, 0, sizeof(gi->string)); - if (gfs2_glock_iter_next(gi)) { + read_lock(gl_lock_addr(gi->hash)); + gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first, + struct gfs2_glock, gl_list); + if (gi->gl) + gfs2_glock_hold(gi->gl); + read_unlock(gl_lock_addr(gi->hash)); + + if (!gi->gl && gfs2_glock_iter_next(gi)) { gfs2_glock_iter_free(gi); return NULL; } @@ -2066,7 +2061,7 @@ static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos) if (!gi) return NULL; - while (n--) { + while(n--) { if (gfs2_glock_iter_next(gi)) { gfs2_glock_iter_free(gi); return NULL; @@ -2093,7 +2088,9 @@ static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr, static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr) { - /* nothing for now */ + struct glock_iter *gi = iter_ptr; + if (gi) + gfs2_glock_iter_free(gi); } static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr) From 905d2aefa9e06ebb995df96920d273a516fcd3f9 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 24 Jul 2007 14:05:31 -0500 Subject: [PATCH 0944/2804] [GFS2] Move some code inside the log lock This is the first of five patches for bug #248176: There were still some critical variables being manipulated outside the log_lock spinlock. That usually resulted in a hang. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 3b395c41b2f3..a0371f835cfb 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -117,7 +117,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) struct buffer_head *bh; struct gfs2_log_descriptor *ld; struct gfs2_bufdata *bd1 = NULL, *bd2; - unsigned int total = sdp->sd_log_num_buf; + unsigned int total; unsigned int offset = BUF_OFFSET; unsigned int limit; unsigned int num; @@ -127,12 +127,16 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) limit = buf_limit(sdp); /* for 4k blocks, limit = 503 */ + gfs2_log_lock(sdp); + total = sdp->sd_log_num_buf; bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list); while(total) { num = total; if (total > limit) num = limit; + gfs2_log_unlock(sdp); bh = gfs2_log_get_buf(sdp); + gfs2_log_lock(sdp); ld = (struct gfs2_log_descriptor *)bh->b_data; ptr = (__be64 *)(bh->b_data + offset); ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); @@ -152,21 +156,27 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) break; } + gfs2_log_unlock(sdp); set_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); + gfs2_log_lock(sdp); n = 0; list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf, bd_le.le_list) { + gfs2_log_unlock(sdp); bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); set_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); + gfs2_log_lock(sdp); if (++n >= num) break; } + BUG_ON(total < num); total -= num; } + gfs2_log_unlock(sdp); } static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) @@ -524,7 +534,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) struct gfs2_log_descriptor *ld; unsigned int limit; unsigned int total_dbuf; - unsigned int total_jdata = sdp->sd_log_num_jdata; + unsigned int total_jdata; unsigned int num, n; __be64 *ptr = NULL; @@ -536,6 +546,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) */ gfs2_log_lock(sdp); total_dbuf = sdp->sd_log_num_databuf; + total_jdata = sdp->sd_log_num_jdata; bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, bd_le.le_list); while(total_dbuf) { @@ -621,10 +632,10 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) } gfs2_log_unlock(sdp); if (bh) { - set_buffer_mapped(bh); set_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); bh = NULL; + ptr = NULL; } n = 0; gfs2_log_lock(sdp); From 693ddeabbb3e563f192a7ac74ec04168aa92e8d8 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 24 Jul 2007 14:07:33 -0500 Subject: [PATCH 0945/2804] [GFS2] Revert part of earlier log.c changes This is patch 2 of 5 for bug #248176. The list_move code previously concocted in log.c for bug #238162 (see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=238162#c23) never runs as bh can now never be NULL at this point. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index f49a12e24086..f7c0608332fb 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -83,11 +83,6 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) gfs2_assert(sdp, bd->bd_ail == ai); - if (!bh){ - list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); - continue; - } - if (!buffer_busy(bh)) { if (!buffer_uptodate(bh)) { gfs2_log_unlock(sdp); @@ -130,11 +125,6 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl bd_ail_st_list) { bh = bd->bd_bh; - if (!bh){ - list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); - continue; - } - gfs2_assert(sdp, bd->bd_ail == ai); if (buffer_busy(bh)) { @@ -155,13 +145,14 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) { - struct list_head *head = &sdp->sd_ail1_list; + struct list_head *head; u64 sync_gen; struct list_head *first; struct gfs2_ail *first_ai, *ai, *tmp; int done = 0; gfs2_log_lock(sdp); + head = &sdp->sd_ail1_list; if (list_empty(head)) { gfs2_log_unlock(sdp); return; From 6760bdcd03a12d7d082794311ccbaf44bfc23b06 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 24 Jul 2007 14:09:32 -0500 Subject: [PATCH 0946/2804] [GFS2] Prevent infinite loop in try_rgrp_unlink() This is patch three of five for bug #248176. The try_rgrp_unlink code in rgrp.c had an infinite loop. This was caused because the bitmap function rgblk_search can return a block less than the "goal" block, in which case it was looping. The fix is to make it always march forward as needed. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index ce48c4594ec8..b93ac45b88bb 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -31,6 +31,7 @@ #include "inode.h" #define BFITNOENT ((u32)~0) +#define NO_BLOCK ((u64)~0) /* * These routines are used by the resource group routines (rgrp.c) @@ -116,8 +117,7 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * @buffer: the buffer that holds the bitmaps * @buflen: the length (in bytes) of the buffer * @goal: start search at this block's bit-pair (within @buffer) - * @old_state: GFS2_BLKST_XXX the state of the block we're looking for; - * bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0) + * @old_state: GFS2_BLKST_XXX the state of the block we're looking for. * * Scope of @goal and returned block number is only within this bitmap buffer, * not entire rgrp or filesystem. @buffer will be offset from the actual @@ -137,9 +137,13 @@ static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, byte = buffer + (goal / GFS2_NBBY); bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; end = buffer + buflen; - alloc = (old_state & 1) ? 0 : 0x55; + alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0; while (byte < end) { + /* If we're looking for a free block we can eliminate all + bitmap settings with 0x55, which represents four data + blocks in a row. If we're looking for a data block, we can + eliminate 0x00 which corresponds to four free blocks. */ if ((*byte & 0x55) == alloc) { blk += (8 - bit) >> 1; @@ -859,19 +863,21 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) { struct inode *inode; - u32 goal = 0; + u32 goal = 0, block; u64 no_addr; for(;;) { if (goal >= rgd->rd_data) break; - goal = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, - GFS2_BLKST_UNLINKED); - if (goal == BFITNOENT) + block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, + GFS2_BLKST_UNLINKED); + if (block == BFITNOENT) break; - no_addr = goal + rgd->rd_data0; + /* rgblk_search can return a block < goal, so we need to + keep it marching forward. */ + no_addr = block + rgd->rd_data0; goal++; - if (no_addr < *last_unlinked) + if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked) continue; *last_unlinked = no_addr; inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, @@ -1152,7 +1158,7 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) struct gfs2_alloc *al = &ip->i_alloc; struct inode *inode; int error = 0; - u64 last_unlinked = 0; + u64 last_unlinked = NO_BLOCK; if (gfs2_assert_warn(sdp, al->al_requested)) return -EINVAL; @@ -1305,9 +1311,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, goal = 0; } - if (old_state != new_state) { - gfs2_assert_withdraw(rgd->rd_sbd, blk != BFITNOENT); - + if (blk != BFITNOENT && old_state != new_state) { gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, blk, new_state); From cee23c79d08c57bbbb9923703409af3b17518c58 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Wed, 25 Jul 2007 17:53:58 +0800 Subject: [PATCH 0947/2804] [GFS2] use an temp variable to reduce a spin_unlock this is more clear. Signed-off-by: Denis Cheng Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/gfs2/locking/dlm/plock.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index fba1f1d87e4f..1f7b038530b4 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -346,15 +346,16 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, static unsigned int dev_poll(struct file *file, poll_table *wait) { + unsigned int mask = 0; + poll_wait(file, &send_wq, wait); spin_lock(&ops_lock); - if (!list_empty(&send_list)) { - spin_unlock(&ops_lock); - return POLLIN | POLLRDNORM; - } + if (!list_empty(&send_list)) + mask = POLLIN | POLLRDNORM; spin_unlock(&ops_lock); - return 0; + + return mask; } static const struct file_operations dev_fops = { From 0f8468c8bef3d04637c924e7bef20ca53018b319 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 25 Jul 2007 10:06:22 -0500 Subject: [PATCH 0948/2804] [GFS2] Detach buf data during in-place writeback This is patch 5 of 5 for bug #248176 Metadata corruption was occurring because page references weren't being removed in all cases. I previously added a function called detach_bufdata, but I discovered there already WAS a function out there to do the job. It's called gfs2_meta_cache_flush. So I added a call to that to remove the page references. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index f7c0608332fb..00ab6c070a15 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -219,6 +219,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) { struct list_head *head = &ai->ai_ail2_list; struct gfs2_bufdata *bd; + struct gfs2_inode *bh_ip; while (!list_empty(head)) { bd = list_entry(head->prev, struct gfs2_bufdata, @@ -228,6 +229,8 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) list_del(&bd->bd_ail_st_list); list_del(&bd->bd_ail_gl_list); atomic_dec(&bd->bd_gl->gl_ail_count); + bh_ip = GFS2_I(bd->bd_bh->b_page->mapping->host); + gfs2_meta_cache_flush(bh_ip); brelse(bd->bd_bh); } } From 4ef290025ccde7c52ba219cf733a4295acd5401f Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Tue, 31 Jul 2007 18:31:11 +0800 Subject: [PATCH 0949/2804] [GFS2] mark struct *_operations const these struct *_operations are all method tables, thus should be const. Signed-off-by: Denis Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/eaops.c | 8 ++++---- fs/gfs2/eaops.h | 4 ++-- fs/gfs2/glock.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index 1ab3e9d73886..aa8dbf303f6d 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -200,28 +200,28 @@ static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) return gfs2_ea_remove_i(ip, er); } -static struct gfs2_eattr_operations gfs2_user_eaops = { +static const struct gfs2_eattr_operations gfs2_user_eaops = { .eo_get = user_eo_get, .eo_set = user_eo_set, .eo_remove = user_eo_remove, .eo_name = "user", }; -struct gfs2_eattr_operations gfs2_system_eaops = { +const struct gfs2_eattr_operations gfs2_system_eaops = { .eo_get = system_eo_get, .eo_set = system_eo_set, .eo_remove = system_eo_remove, .eo_name = "system", }; -static struct gfs2_eattr_operations gfs2_security_eaops = { +static const struct gfs2_eattr_operations gfs2_security_eaops = { .eo_get = security_eo_get, .eo_set = security_eo_set, .eo_remove = security_eo_remove, .eo_name = "security", }; -struct gfs2_eattr_operations *gfs2_ea_ops[] = { +const struct gfs2_eattr_operations *gfs2_ea_ops[] = { NULL, &gfs2_user_eaops, &gfs2_system_eaops, diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h index 508b4f7a2449..da2f7fbbb40d 100644 --- a/fs/gfs2/eaops.h +++ b/fs/gfs2/eaops.h @@ -22,9 +22,9 @@ struct gfs2_eattr_operations { unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name); -extern struct gfs2_eattr_operations gfs2_system_eaops; +extern const struct gfs2_eattr_operations gfs2_system_eaops; -extern struct gfs2_eattr_operations *gfs2_ea_ops[]; +extern const struct gfs2_eattr_operations *gfs2_ea_ops[]; #endif /* __EAOPS_DOT_H__ */ diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index e4bc8ae561aa..0054b7df714a 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2103,7 +2103,7 @@ static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr) return 0; } -static struct seq_operations gfs2_glock_seq_ops = { +static const struct seq_operations gfs2_glock_seq_ops = { .start = gfs2_glock_seq_start, .next = gfs2_glock_seq_next, .stop = gfs2_glock_seq_stop, From ca5a939b33166a9f5a2556e6c4ec031524852ba2 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Tue, 31 Jul 2007 18:31:12 +0800 Subject: [PATCH 0950/2804] [GFS2] use the declaration of gfs2_dops in the header file instead Signed-off-by: Denis Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index cf5aa5050548..9a5e84038dd6 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -28,6 +28,7 @@ #include "lm.h" #include "mount.h" #include "ops_fstype.h" +#include "ops_dentry.h" #include "ops_super.h" #include "recovery.h" #include "rgrp.h" @@ -38,8 +39,6 @@ #define DO 0 #define UNDO 1 -extern struct dentry_operations gfs2_dops; - static struct gfs2_sbd *init_sbd(struct super_block *sb) { struct gfs2_sbd *sdp; From 8fbbfd214c853102b614f4705c1904ed14f5a808 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 1 Aug 2007 13:57:10 +0100 Subject: [PATCH 0951/2804] [GFS2] Reduce number of gfs2_scand processes to one We only need a single gfs2_scand process rather than the one per filesystem which we had previously. As a result the parameter determining the frequency of gfs2_scand runs becomes a module parameter rather than a mount parameter as it was before. Signed-off-by: Steven Whitehouse --- fs/gfs2/daemon.c | 24 ----------------- fs/gfs2/daemon.h | 1 - fs/gfs2/glock.c | 63 +++++++++++++++++++++++++++++++++----------- fs/gfs2/glock.h | 4 +-- fs/gfs2/incore.h | 2 -- fs/gfs2/main.c | 3 +++ fs/gfs2/ops_fstype.c | 9 ------- fs/gfs2/ops_super.c | 1 - fs/gfs2/super.c | 1 - fs/gfs2/sys.c | 2 -- 10 files changed, 53 insertions(+), 57 deletions(-) diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index 3548d9f31e0d..3731ab0771d5 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -34,30 +34,6 @@ The kthread functions used to start these daemons block and flush signals. */ -/** - * gfs2_scand - Look for cached glocks and inodes to toss from memory - * @sdp: Pointer to GFS2 superblock - * - * One of these daemons runs, finding candidates to add to sd_reclaim_list. - * See gfs2_glockd() - */ - -int gfs2_scand(void *data) -{ - struct gfs2_sbd *sdp = data; - unsigned long t; - - while (!kthread_should_stop()) { - gfs2_scand_internal(sdp); - t = gfs2_tune_get(sdp, gt_scand_secs) * HZ; - if (freezing(current)) - refrigerator(); - schedule_timeout_interruptible(t); - } - - return 0; -} - /** * gfs2_glockd - Reclaim unused glock structures * @sdp: Pointer to GFS2 superblock diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h index 801007120fb2..0de9b3557955 100644 --- a/fs/gfs2/daemon.h +++ b/fs/gfs2/daemon.h @@ -10,7 +10,6 @@ #ifndef __DAEMON_DOT_H__ #define __DAEMON_DOT_H__ -int gfs2_scand(void *data); int gfs2_glockd(void *data); int gfs2_recoverd(void *data); int gfs2_logd(void *data); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 0054b7df714a..559937c710fc 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "gfs2.h" #include "incore.h" @@ -58,6 +60,8 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh); static void gfs2_glock_drop_th(struct gfs2_glock *gl); static DECLARE_RWSEM(gfs2_umount_flush_sem); static struct dentry *gfs2_root; +static struct task_struct *scand_process; +static unsigned int scand_secs = 5; #define GFS2_GL_HASH_SHIFT 15 #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) @@ -1627,7 +1631,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, goto out; gl = list_entry(head->first, struct gfs2_glock, gl_list); while(1) { - if (gl->gl_sbd == sdp) { + if (!sdp || gl->gl_sbd == sdp) { gfs2_glock_hold(gl); read_unlock(gl_lock_addr(hash)); if (prev) @@ -1645,6 +1649,7 @@ out: read_unlock(gl_lock_addr(hash)); if (prev) gfs2_glock_put(prev); + cond_resched(); return has_entries; } @@ -1672,20 +1677,6 @@ out_schedule: gfs2_glock_schedule_for_reclaim(gl); } -/** - * gfs2_scand_internal - Look for glocks and inodes to toss from memory - * @sdp: the filesystem - * - */ - -void gfs2_scand_internal(struct gfs2_sbd *sdp) -{ - unsigned int x; - - for (x = 0; x < GFS2_GL_HASH_SIZE; x++) - examine_bucket(scan_glock, sdp, x); -} - /** * clear_glock - look at a glock and see if we can free it from glock cache * @gl: the glock to look at @@ -1973,6 +1964,35 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) return error; } +/** + * gfs2_scand - Look for cached glocks and inodes to toss from memory + * @sdp: Pointer to GFS2 superblock + * + * One of these daemons runs, finding candidates to add to sd_reclaim_list. + * See gfs2_glockd() + */ + +static int gfs2_scand(void *data) +{ + unsigned x; + unsigned delay; + + while (!kthread_should_stop()) { + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) + examine_bucket(scan_glock, NULL, x); + if (freezing(current)) + refrigerator(); + delay = scand_secs; + if (delay < 1) + delay = 1; + schedule_timeout_interruptible(delay * HZ); + } + + return 0; +} + + + int __init gfs2_glock_init(void) { unsigned i; @@ -1984,9 +2004,22 @@ int __init gfs2_glock_init(void) rwlock_init(&gl_hash_locks[i]); } #endif + + scand_process = kthread_run(gfs2_scand, NULL, "gfs2_scand"); + if (IS_ERR(scand_process)) + return PTR_ERR(scand_process); + return 0; } +void gfs2_glock_exit(void) +{ + kthread_stop(scand_process); +} + +module_param(scand_secs, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(scand_secs, "The number of seconds between scand runs"); + static int gfs2_glock_iter_next(struct glock_iter *gi) { struct gfs2_glock *gl; diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 7721ca3fff9e..f7a8e626aa08 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -132,11 +132,11 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data); void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl); void gfs2_reclaim_glock(struct gfs2_sbd *sdp); - -void gfs2_scand_internal(struct gfs2_sbd *sdp); void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait); int __init gfs2_glock_init(void); +void gfs2_glock_exit(void); + int gfs2_create_debugfs_file(struct gfs2_sbd *sdp); void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp); int gfs2_register_debugfs(void); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 170ba93829c0..1390b30daf19 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -429,7 +429,6 @@ struct gfs2_tune { unsigned int gt_log_flush_secs; unsigned int gt_jindex_refresh_secs; /* Check for new journal index */ - unsigned int gt_scand_secs; unsigned int gt_recoverd_secs; unsigned int gt_logd_secs; unsigned int gt_quotad_secs; @@ -574,7 +573,6 @@ struct gfs2_sbd { /* Daemon stuff */ - struct task_struct *sd_scand_process; struct task_struct *sd_recoverd_process; struct task_struct *sd_logd_process; struct task_struct *sd_quotad_process; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index d5d4e68b8807..79c91fd8381b 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -107,6 +107,8 @@ static int __init init_gfs2_fs(void) fail_unregister: unregister_filesystem(&gfs2_fs_type); fail: + gfs2_glock_exit(); + if (gfs2_bufdata_cachep) kmem_cache_destroy(gfs2_bufdata_cachep); @@ -127,6 +129,7 @@ fail: static void __exit exit_gfs2_fs(void) { + gfs2_glock_exit(); gfs2_unregister_debugfs(); unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2meta_fs_type); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 9a5e84038dd6..58c730be2073 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -160,14 +160,6 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh, if (undo) goto fail_trans; - p = kthread_run(gfs2_scand, sdp, "gfs2_scand"); - error = IS_ERR(p); - if (error) { - fs_err(sdp, "can't start scand thread: %d\n", error); - return error; - } - sdp->sd_scand_process = p; - for (sdp->sd_glockd_num = 0; sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd; sdp->sd_glockd_num++) { @@ -228,7 +220,6 @@ fail: while (sdp->sd_glockd_num--) kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); - kthread_stop(sdp->sd_scand_process); return error; } diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 603d940f1159..4316690d86f6 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb) kthread_stop(sdp->sd_recoverd_process); while (sdp->sd_glockd_num--) kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); - kthread_stop(sdp->sd_scand_process); if (!(sb->s_flags & MS_RDONLY)) { error = gfs2_make_fs_ro(sdp); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f916b9740c75..55898023782b 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -58,7 +58,6 @@ void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_incore_log_blocks = 1024; gt->gt_log_flush_secs = 60; gt->gt_jindex_refresh_secs = 60; - gt->gt_scand_secs = 15; gt->gt_recoverd_secs = 60; gt->gt_logd_secs = 1; gt->gt_quotad_secs = 5; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index c26c21b53c19..ba3a1729cc1a 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -442,7 +442,6 @@ TUNE_ATTR(quota_simul_sync, 1); TUNE_ATTR(quota_cache_secs, 1); TUNE_ATTR(stall_secs, 1); TUNE_ATTR(statfs_quantum, 1); -TUNE_ATTR_DAEMON(scand_secs, scand_process); TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process); TUNE_ATTR_DAEMON(logd_secs, logd_process); TUNE_ATTR_DAEMON(quotad_secs, quotad_process); @@ -464,7 +463,6 @@ static struct attribute *tune_attrs[] = { &tune_attr_quota_cache_secs.attr, &tune_attr_stall_secs.attr, &tune_attr_statfs_quantum.attr, - &tune_attr_scand_secs.attr, &tune_attr_recoverd_secs.attr, &tune_attr_logd_secs.attr, &tune_attr_quotad_secs.attr, From 5f3eae7546093d845ca8ada1b95714202a136a1a Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 8 Aug 2007 16:52:09 -0500 Subject: [PATCH 0952/2804] [GFS2] invalid metadata block - REVISED This is for bugzilla bug #248176: GFS2: invalid metadata block Patches 1 thru 3 were accepted upstream, but there were problems with 4 and 5. Those issues have been resolved and now the recovery tests are passing without errors. This code has gone through 41 * 3 successful gfs2 recovery tests before it hit an unrelated (openais) problem. This is a complete rewrite of patch 4 for bug #248176. Part of the problem was that inodes were being recycled before their buffers were flushed to the journal logs. Another problem was that the clone bitmaps were being searched for deleted inodes to recycle, but only the "real" bitmaps should be searched for that purpose. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index b93ac45b88bb..2d7f7ea0c9a8 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -865,12 +865,15 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) struct inode *inode; u32 goal = 0, block; u64 no_addr; + struct gfs2_sbd *sdp = rgd->rd_sbd; for(;;) { if (goal >= rgd->rd_data) break; + down_write(&sdp->sd_log_flush_lock); block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, GFS2_BLKST_UNLINKED); + up_write(&sdp->sd_log_flush_lock); if (block == BFITNOENT) break; /* rgblk_search can return a block < goal, so we need to @@ -1295,7 +1298,9 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, allocatable block anywhere else, we want to be able wrap around and search in the first part of our first-searched bit block. */ for (x = 0; x <= length; x++) { - if (bi->bi_clone) + /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone + bitmaps, so we must search the originals for that. */ + if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset, bi->bi_len, goal, old_state); else From 75be73a8246ef96f7fa3f05a6a1450159fbb7a64 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 8 Aug 2007 17:08:14 -0500 Subject: [PATCH 0953/2804] [GFS2] Ensure journal file cache is flushed after recovery This is for bugzilla bug #248176: GFS2: invalid metadata block Patches 1 thru 3 were accepted upstream, but there were problems with 4 and 5. Those issues have been resolved and now the recovery tests are passing without errors. This code has gone through 41 * 3 successful gfs2 recovery tests before it hit an unrelated (openais) problem. I'm continuing to test it. This is a complete rewrite of patch 5 for bug #248176, written by Steve Whitehouse. This is referred to in the bugzilla record as "new 6" and "a different solution". The problem was that the journal inodes, although protected by a glock, were not synched with the other nodes because they don't use the inode glock synch operations (i.e. no "glops" were defined). Therefore, journal recovery on a journal-recovering node were causing the blocks to get out of sync with the node that was actually trying to use that journal as it comes back up from a reboot. There are two possible solutions: (1) To make the journals use the normal inode glock sync operations, or (2) To make the journal operations take effect immediately (i.e. no caching). Although option 1 works, it turns out to be a lot more code. Steve opted for option 2, which is much simpler and therefore less prone to regression errors. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse -- --- fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/recovery.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 58c730be2073..f0bcaa25737c 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -358,7 +358,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ip = GFS2_I(sdp->sd_jdesc->jd_inode); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, - LM_FLAG_NOEXP | GL_EXACT, + LM_FLAG_NOEXP | GL_EXACT | GL_NOCACHE, &sdp->sd_jinode_gh); if (error) { fs_err(sdp, "can't acquire journal inode glock: %d\n", diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 5ada38c99a2c..beb6c7ac0086 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -469,7 +469,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) }; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, - LM_FLAG_NOEXP, &ji_gh); + LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh); if (error) goto fail_gunlock_j; } else { From adb4ec13cdddb6ab8280e4c7808ba30f46504e1d Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Sat, 11 Aug 2007 10:27:07 +0800 Subject: [PATCH 0954/2804] [GFS2] use list_for_each_entry instead Signed-off-by: Denis Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index f0bcaa25737c..32b2859a89a5 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -808,7 +808,6 @@ static struct super_block* get_gfs2_sb(const char *dev_name) struct nameidata nd; struct file_system_type *fstype; struct super_block *sb = NULL, *s; - struct list_head *l; int error; error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); @@ -820,8 +819,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name) error = vfs_getattr(nd.mnt, nd.dentry, &stat); fstype = get_fs_type("gfs2"); - list_for_each(l, &fstype->fs_supers) { - s = list_entry(l, struct super_block, s_instances); + list_for_each_entry(s, &fstype->fs_supers, s_instances) { if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) || (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) { sb = s; From 2d3ba1ea97d839e60d742ccf9a6de5bf039c0b53 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Sat, 11 Aug 2007 10:27:08 +0800 Subject: [PATCH 0955/2804] [GFS2] unneeded typecast sb->s_fs_info is a void pointer, thus the type cast is not needed. Signed-off-by: Denis Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 32b2859a89a5..25cfab95eb9c 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -849,7 +849,7 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, error = -ENOENT; goto error; } - sdp = (struct gfs2_sbd*) sb->s_fs_info; + sdp = sb->s_fs_info; if (sdp->sd_vfs_meta) { printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n"); error = -EBUSY; From 5d35e31f43c4910d0b6afc5160728a84bbaf86f0 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Mon, 13 Aug 2007 11:01:58 +0800 Subject: [PATCH 0956/2804] [GFS2] better code for translating characters the original code could work, but I think this code could work better. Signed-off-by: Denis Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 25cfab95eb9c..6c820cb23473 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -144,7 +144,8 @@ static int init_names(struct gfs2_sbd *sdp, int silent) snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto); snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table); - while ((table = strchr(sdp->sd_table_name, '/'))) + table = sdp->sd_table_name; + while ((table = strchr(table, '/'))) *table = '_'; out: From 0fd5355470ea40355b8af76d01748ec7b9926d4d Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Tue, 14 Aug 2007 15:34:58 -0500 Subject: [PATCH 0957/2804] [GFS2] Force unstuff of hidden quota inode This patch forcibly unstuffs (if stuffed) the hidden quota inode at the first availble opportunity. In any practical scenario the quota inode won't be stuffed, so this is ok to do. Unstuffing the quota inode allows us to ignore the case of a stuffed quota inode in gfs2_adjust_quota(). Signed-off-by: Abhijith Das Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 6e546ee8f3d4..5dfa4656122b 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -614,6 +614,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, s64 value; int err = -EIO; + if (gfs2_is_stuffed(ip)) { + struct gfs2_alloc *al = NULL; + al = gfs2_alloc_get(ip); + /* just request 1 blk */ + al->al_requested = 1; + gfs2_inplace_reserve(ip); + gfs2_unstuff_dinode(ip, NULL); + gfs2_inplace_release(ip); + gfs2_alloc_put(ip); + } page = grab_cache_page(mapping, index); if (!page) return -ENOMEM; From 34eaae398e29dadeed95efd30f1eb694e5932b34 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Wed, 15 Aug 2007 23:54:44 +0800 Subject: [PATCH 0958/2804] [GFS2] fixed a NULL pointer assignment BUG Signed-off-by: Denis Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 6c820cb23473..c1c6672ebb83 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -292,8 +292,9 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) fs_err(sdp, "can't get root dentry\n"); error = -ENOMEM; iput(inode); - } - sb->s_root->d_op = &gfs2_dops; + } else + sb->s_root->d_op = &gfs2_dops; + out: gfs2_glock_dq_uninit(&sb_gh); return error; From 2d9a4bbf6d28673f4057682cc02d16bf288b4a35 Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Wed, 15 Aug 2007 11:25:05 -0500 Subject: [PATCH 0959/2804] [GFS2] Fix quota do_list operation hang This is the filesystem part of the patches to fix this bz. There are additional userland patches (gfs2_quota, libgfs2) for the complete solution. This patch adds a new field qu_ll_next to the gfs2_quota structure. This field allows us to create linked lists of quotas in the ondisk quota inode. Instead of scanning through the entire sparse quota file for valid quotas, we can now simply walk through the user and group quota linked lists to perform the do_list operation. Signed-off-by: Abhijith Das Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 3 +++ include/linux/gfs2_ondisk.h | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 5dfa4656122b..addb51e0f135 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -70,6 +70,7 @@ struct gfs2_quota_host { u64 qu_limit; u64 qu_warn; s64 qu_value; + u32 qu_ll_next; }; struct gfs2_quota_change_host { @@ -580,6 +581,7 @@ static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf) qu->qu_limit = be64_to_cpu(str->qu_limit); qu->qu_warn = be64_to_cpu(str->qu_warn); qu->qu_value = be64_to_cpu(str->qu_value); + qu->qu_ll_next = be32_to_cpu(str->qu_ll_next); } static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf) @@ -589,6 +591,7 @@ static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf) str->qu_limit = cpu_to_be64(qu->qu_limit); str->qu_warn = cpu_to_be64(qu->qu_warn); str->qu_value = cpu_to_be64(qu->qu_value); + str->qu_ll_next = cpu_to_be32(qu->qu_ll_next); memset(&str->qu_reserved, 0, sizeof(str->qu_reserved)); } diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index a44a6a078f0a..c3c19f926e6f 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -169,6 +169,33 @@ struct gfs2_rgrp { __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */ }; +/* + * quota linked list: user quotas and group quotas form two separate + * singly linked lists. ll_next stores uids or gids of next quotas in the + * linked list. + +Given the uid/gid, how to calculate the quota file offsets for the corresponding +gfs2_quota structures on disk: + +for user quotas, given uid, +offset = uid * sizeof(struct gfs2_quota); + +for group quotas, given gid, +offset = (gid * sizeof(struct gfs2_quota)) + sizeof(struct gfs2_quota); + + + uid:0 gid:0 uid:12 gid:12 uid:17 gid:17 uid:5142 gid:5142 ++-------+-------+ +-------+-------+ +-------+- - - -+ +- - - -+-------+ +| valid | valid | :: | valid | valid | :: | valid | inval | :: | inval | valid | ++-------+-------+ +-------+-------+ +-------+- - - -+ +- - - -+-------+ +next:12 next:12 next:17 next:5142 next:NULL next:NULL + | | | | |<-- user quota list | + \______|___________/ \______|___________/ group quota list -->| + | | | + \__________________/ \_______________________________________/ + +*/ + /* * quota structure */ @@ -177,7 +204,8 @@ struct gfs2_quota { __be64 qu_limit; __be64 qu_warn; __be64 qu_value; - __u8 qu_reserved[64]; + __be32 qu_ll_next; /* location of next quota in list */ + __u8 qu_reserved[60]; }; /* From bb3b0e3df5420fdf2c6bbb4417525c6d2ef55bbb Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 16 Aug 2007 16:03:57 +0100 Subject: [PATCH 0960/2804] [GFS2] Clean up invalidatepage/releasepage This patch fixes some bugs relating to journaled data files by cleaning up the gfs2_invalidatepage() and gfs2_releasepage() functions. We now never block during gfs2_releasepage(), instead we always either release or refuse to release depending on the status of the buffers. This fixes Red Hat bugzillas #248969 and #252392. Signed-off-by: Steven Whitehouse Cc: Bob Peterson --- fs/gfs2/glops.c | 4 +- fs/gfs2/log.c | 6 +- fs/gfs2/ops_address.c | 132 +++++------------------------------------- fs/gfs2/ops_fstype.c | 2 + 4 files changed, 24 insertions(+), 120 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 777ca46010e8..88342e0b4bc7 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -156,9 +156,11 @@ static void inode_go_sync(struct gfs2_glock *gl) ip = NULL; if (test_bit(GLF_DIRTY, &gl->gl_flags)) { - if (ip) + if (ip && !gfs2_is_jdata(ip)) filemap_fdatawrite(ip->i_inode.i_mapping); gfs2_log_flush(gl->gl_sbd, gl); + if (ip && gfs2_is_jdata(ip)) + filemap_fdatawrite(ip->i_inode.i_mapping); gfs2_meta_sync(gl); if (ip) { struct address_space *mapping = ip->i_inode.i_mapping; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 00ab6c070a15..d0e6b42c86e1 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -229,8 +229,10 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) list_del(&bd->bd_ail_st_list); list_del(&bd->bd_ail_gl_list); atomic_dec(&bd->bd_gl->gl_ail_count); - bh_ip = GFS2_I(bd->bd_bh->b_page->mapping->host); - gfs2_meta_cache_flush(bh_ip); + if (bd->bd_bh->b_page->mapping) { + bh_ip = GFS2_I(bd->bd_bh->b_page->mapping->host); + gfs2_meta_cache_flush(bh_ip); + } brelse(bd->bd_bh); } } diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 42a5f58f6fca..8407d1db4eac 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -616,58 +616,13 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) return dblock; } -static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh) -{ - struct gfs2_bufdata *bd; - - gfs2_log_lock(sdp); - bd = bh->b_private; - if (bd) { - bd->bd_bh = NULL; - bh->b_private = NULL; - if (!bd->bd_ail && list_empty(&bd->bd_le.le_list)) - kmem_cache_free(gfs2_bufdata_cachep, bd); - } - gfs2_log_unlock(sdp); - - lock_buffer(bh); - clear_buffer_dirty(bh); - bh->b_bdev = NULL; - clear_buffer_mapped(bh); - clear_buffer_req(bh); - clear_buffer_new(bh); - clear_buffer_delay(bh); - unlock_buffer(bh); -} - static void gfs2_invalidatepage(struct page *page, unsigned long offset) { - struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); - struct buffer_head *head, *bh, *next; - unsigned int curr_off = 0; - BUG_ON(!PageLocked(page)); if (offset == 0) ClearPageChecked(page); - if (!page_has_buffers(page)) - return; - bh = head = page_buffers(page); - do { - unsigned int next_off = curr_off + bh->b_size; - next = bh->b_this_page; - - if (offset <= curr_off) - discard_buffer(sdp, bh); - - curr_off = next_off; - bh = next; - } while (bh != head); - - if (!offset) - try_to_release_page(page, 0); - - return; + block_invalidatepage(page, offset); } /** @@ -735,59 +690,6 @@ out: return rv; } -/** - * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. - * @bh: the buffer we're stuck on - * - */ - -static void stuck_releasepage(struct buffer_head *bh) -{ - struct inode *inode = bh->b_page->mapping->host; - struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; - struct gfs2_bufdata *bd = bh->b_private; - struct gfs2_glock *gl; -static unsigned limit = 0; - - if (limit > 3) - return; - limit++; - - fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); - fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", - (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); - fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); - fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); - - if (!bd) - return; - - gl = bd->bd_gl; - - fs_warn(sdp, "gl = (%u, %llu)\n", - gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); - - fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", - (list_empty(&bd->bd_list_tr)) ? "no" : "yes", - (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); - - if (gl->gl_ops == &gfs2_inode_glops) { - struct gfs2_inode *ip = gl->gl_object; - unsigned int x; - - if (!ip) - return; - - fs_warn(sdp, "ip = %llu %llu\n", - (unsigned long long)ip->i_no_formal_ino, - (unsigned long long)ip->i_no_addr); - - for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) - fs_warn(sdp, "ip->i_cache[%u] = %s\n", - x, (ip->i_cache[x]) ? "!NULL" : "NULL"); - } -} - /** * gfs2_releasepage - free the metadata associated with a page * @page: the page that's being released @@ -805,38 +707,31 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; struct buffer_head *bh, *head; struct gfs2_bufdata *bd; - unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ; if (!page_has_buffers(page)) goto out; + gfs2_log_lock(sdp); head = bh = page_buffers(page); do { - while (atomic_read(&bh->b_count)) { - if (!atomic_read(&aspace->i_writecount)) - return 0; - - if (!(gfp_mask & __GFP_WAIT)) - return 0; - - if (time_after_eq(jiffies, t)) { - stuck_releasepage(bh); - /* should we withdraw here? */ - return 0; - } - - yield(); - } - + if (atomic_read(&bh->b_count)) + goto cannot_release; + bd = bh->b_private; + if (bd && bd->bd_ail) + goto cannot_release; gfs2_assert_warn(sdp, !buffer_pinned(bh)); gfs2_assert_warn(sdp, !buffer_dirty(bh)); + bh = bh->b_this_page; + } while(bh != head); + gfs2_log_unlock(sdp); + head = bh = page_buffers(page); + do { gfs2_log_lock(sdp); bd = bh->b_private; if (bd) { gfs2_assert_warn(sdp, bd->bd_bh == bh); gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); - gfs2_assert_warn(sdp, !bd->bd_ail); bd->bd_bh = NULL; if (!list_empty(&bd->bd_le.le_list)) bd = NULL; @@ -851,6 +746,9 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) out: return try_to_free_buffers(page); +cannot_release: + gfs2_log_unlock(sdp); + return 0; } const struct address_space_operations gfs2_file_aops = { diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c1c6672ebb83..9e0e9be1e41d 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -35,6 +35,7 @@ #include "super.h" #include "sys.h" #include "util.h" +#include "log.h" #define DO 0 #define UNDO 1 @@ -887,6 +888,7 @@ error: static void gfs2_kill_sb(struct super_block *sb) { gfs2_delete_debugfs_file(sb->s_fs_info); + gfs2_meta_syncfs(sb->s_fs_info); kill_block_super(sb); } From 382e6e256b0cb1a84a45a520cef75d1b8ff44663 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 16 Aug 2007 17:08:20 +0100 Subject: [PATCH 0961/2804] [GFS2] Add a missing gfs2_trans_add_bh() This was missing from the dir_split_leaf() function although in most cases its not a problem due to other functions having already previously called gfs2_trans_add_bh. This makes certain that it is correct. Signed-off-by: Steven Whitehouse Cc: Wendy Cheng --- fs/gfs2/dir.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 2beb2f401aa2..08c6dd0c6713 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1043,6 +1043,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { + gfs2_trans_add_bh(dip->i_gl, dibh, 1); dip->i_di.di_blocks++; gfs2_set_inode_blocks(&dip->i_inode); gfs2_dinode_out(dip, dibh->b_data); From 9a5ad13856cbd10be429f09517c51277c02530f7 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Fri, 17 Aug 2007 20:22:07 -0500 Subject: [PATCH 0962/2804] [GFS2] Add NULL entry to token table match_token() was returning garbage data instead of a fail value. This data happened to match a valid option id for an option that required an argument (in this case, lockproto=%s) For match_token() to correctly fail if the option doesn't match any of the tokens, the token table must end with a NULL entry. This patch adds the NULL entry. Signed-off-by: Benjamin E. Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/mount.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index 4864659555d4..b941f9f9f958 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -42,6 +42,7 @@ enum { Opt_nosuiddir, Opt_data_writeback, Opt_data_ordered, + Opt_err, }; static match_table_t tokens = { @@ -64,7 +65,8 @@ static match_table_t tokens = { {Opt_suiddir, "suiddir"}, {Opt_nosuiddir, "nosuiddir"}, {Opt_data_writeback, "data=writeback"}, - {Opt_data_ordered, "data=ordered"} + {Opt_data_ordered, "data=ordered"}, + {Opt_err, NULL} }; /** @@ -237,6 +239,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) case Opt_data_ordered: args->ar_data = GFS2_DATA_ORDERED; break; + case Opt_err: default: fs_info(sdp, "unknown option: %s\n", o); error = -EINVAL; From a13b8c5f2381495879e6facd3b3ada51c9e68194 Mon Sep 17 00:00:00 2001 From: Wendy Cheng Date: Mon, 20 Aug 2007 09:29:53 -0400 Subject: [PATCH 0963/2804] [GFS2] Reduce truncate IO traffic Current GFS2 setattr call unconditionally invokes do_shrink even the requested size and actual file size are equal. This has generated large amount of extra IOs found during NFS benchmark runs. This patch moves the relevant logic out of shrink code path. Since setattr is a system call, the time stamps update is still required. Signed-off-by: S. Wendy Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index cd805a66880d..9b8990444e6c 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -1085,6 +1085,33 @@ static int do_shrink(struct gfs2_inode *ip, u64 size) return error; } +static int do_touch(struct gfs2_inode *ip, u64 size) +{ + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct buffer_head *dibh; + int error; + + error = gfs2_trans_begin(sdp, RES_DINODE, 0); + if (error) + return error; + + down_write(&ip->i_rw_mutex); + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto do_touch_out; + + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + +do_touch_out: + up_write(&ip->i_rw_mutex); + gfs2_trans_end(sdp); + return error; +} + /** * gfs2_truncatei - make a file a given size * @ip: the inode @@ -1105,8 +1132,11 @@ int gfs2_truncatei(struct gfs2_inode *ip, u64 size) if (size > ip->i_di.di_size) error = do_grow(ip, size); - else + else if (size < ip->i_di.di_size) error = do_shrink(ip, size); + else + /* update time stamps */ + error = do_touch(ip, size); return error; } From 61d96be0f474df354c2ff4a2b2bf410b23a5cd60 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Mon, 20 Aug 2007 15:13:38 +0100 Subject: [PATCH 0964/2804] [DLM] Fix lowcomms socket closing This patch fixes the slight mess made in lowcomms closing by previous patches and fixes all sorts of DLM hangs. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/lowcomms.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 9e9d2e82f40f..62a8a6ccd992 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -334,18 +334,8 @@ static void close_connection(struct connection *con, bool and_other) con->rx_page = NULL; } - /* If we are an 'othercon' then NULL the pointer to us - from the parent and tidy ourself up */ - if (test_bit(CF_IS_OTHERCON, &con->flags)) { - struct connection *parent = __nodeid2con(con->nodeid, 0); - parent->othercon = NULL; - kmem_cache_free(con_cache, con); - } - else { - /* Parent connections get reused */ - con->retries = 0; - mutex_unlock(&con->sock_mutex); - } + con->retries = 0; + mutex_unlock(&con->sock_mutex); } /* We only send shutdown messages to nodes that are not part of the cluster */ @@ -731,6 +721,8 @@ static int tcp_accept_from_sock(struct connection *con) INIT_WORK(&othercon->swork, process_send_sockets); INIT_WORK(&othercon->rwork, process_recv_sockets); set_bit(CF_IS_OTHERCON, &othercon->flags); + } + if (!othercon->sock) { newcon->othercon = othercon; othercon->sock = newsock; newsock->sk->sk_user_data = othercon; From a947e0335699a1d387c3826e5b8eff9e0afe505e Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Tue, 21 Aug 2007 09:57:29 -0500 Subject: [PATCH 0965/2804] [GFS2] Wendy's dump lockname in hex & fix glock dump With this patch, gfs2 glockdump through the debugfs filesystem will only dump glocks for the specified filesystem instead of all glocks. Also, to aid debugging, the glock number is dumped in hex instead of decimal. Signed-off-by: Steven Whitehouse Signed-off-by: S. Wendy Cheng Signed-off-by: Abhijith Das --- fs/gfs2/glock.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 559937c710fc..3d949187fed0 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1844,7 +1844,7 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl) spin_lock(&gl->gl_spin); - print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type, + print_dbg(gi, "Glock 0x%p (%u, 0x%llx)\n", gl, gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); print_dbg(gi, " gl_flags ="); for (x = 0; x < 32; x++) { @@ -2024,20 +2024,21 @@ static int gfs2_glock_iter_next(struct glock_iter *gi) { struct gfs2_glock *gl; +restart: read_lock(gl_lock_addr(gi->hash)); gl = gi->gl; if (gl) { - gi->gl = hlist_entry(gl->gl_list.next, struct gfs2_glock, - gl_list); + gi->gl = hlist_entry(gl->gl_list.next, + struct gfs2_glock, gl_list); if (gi->gl) gfs2_glock_hold(gi->gl); } read_unlock(gl_lock_addr(gi->hash)); if (gl) gfs2_glock_put(gl); - - while(gi->gl == NULL) { + if (gl && gi->gl == NULL) gi->hash++; + while(gi->gl == NULL) { if (gi->hash >= GFS2_GL_HASH_SIZE) return 1; read_lock(gl_lock_addr(gi->hash)); @@ -2046,7 +2047,12 @@ static int gfs2_glock_iter_next(struct glock_iter *gi) if (gi->gl) gfs2_glock_hold(gi->gl); read_unlock(gl_lock_addr(gi->hash)); + gi->hash++; } + + if (gi->sdp != gi->gl->gl_sbd) + goto restart; + return 0; } @@ -2068,16 +2074,10 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp) gi->sdp = sdp; gi->hash = 0; gi->seq = NULL; + gi->gl = NULL; memset(gi->string, 0, sizeof(gi->string)); - read_lock(gl_lock_addr(gi->hash)); - gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first, - struct gfs2_glock, gl_list); - if (gi->gl) - gfs2_glock_hold(gi->gl); - read_unlock(gl_lock_addr(gi->hash)); - - if (!gi->gl && gfs2_glock_iter_next(gi)) { + if (gfs2_glock_iter_next(gi)) { gfs2_glock_iter_free(gi); return NULL; } From ec217e0ece60f2240772e6f08e0529775846c627 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 22 Aug 2007 11:15:29 -0500 Subject: [PATCH 0966/2804] [GFS2] Patch to protect sd_log_num_jdata This is a patch to GFS2 to protect sd_log_num_jdata with the gfs2_log_lock. Without this patch, there is a timing window where you can get hit the following assert from function gfs2_log_flush(): gfs2_assert_withdraw(sdp, sdp->sd_log_num_buf + sdp->sd_log_num_jdata == sdp->sd_log_commited_buf + sdp->sd_log_commited_databuf); I've tested it on my roth cluster and it fixes the problem. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index a0371f835cfb..7ef335623373 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -492,11 +492,12 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) gfs2_trans_add_gl(bd->bd_gl); if (gfs2_is_jdata(ip)) { - sdp->sd_log_num_jdata++; gfs2_pin(sdp, bd->bd_bh); tr->tr_num_databuf_new++; } gfs2_log_lock(sdp); + if (gfs2_is_jdata(ip)) + sdp->sd_log_num_jdata++; sdp->sd_log_num_databuf++; list_add(&le->le_list, &sdp->sd_log_le_databuf); gfs2_log_unlock(sdp); From d1e2777d4f419a865ddccdb9b3412021d0e4de51 Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Thu, 23 Aug 2007 13:33:01 -0500 Subject: [PATCH 0967/2804] [GFS2] panic after can't parse mount arguments When you try to mount gfs2 with -o garbage, the mount fails and the gfs2 superblock is deallocated and becomes NULL. The vfs comes around later on and calls gfs2_kill_sb. At this point the hidden gfs2 superblock pointer (sb->s_fs_info) is NULL and dereferencing it through gfs2_meta_syncfs causes the panic. (the other function call to gfs2_delete_debugfs_file() succeeds because this function already checks for a NULL pointer) Signed-off-by: Abhijith Das Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_fstype.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 9e0e9be1e41d..314c1134d12d 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -887,8 +887,10 @@ error: static void gfs2_kill_sb(struct super_block *sb) { - gfs2_delete_debugfs_file(sb->s_fs_info); - gfs2_meta_syncfs(sb->s_fs_info); + if (sb->s_fs_info) { + gfs2_delete_debugfs_file(sb->s_fs_info); + gfs2_meta_syncfs(sb->s_fs_info); + } kill_block_super(sb); } From c4f68a130fc1795e4a75ec5bdaf9e85d86c22419 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 23 Aug 2007 13:19:05 -0500 Subject: [PATCH 0968/2804] [GFS2] delay glock demote for a minimum hold time When a lot of IO, with some distributed mmap IO, is run on a GFS2 filesystem in a cluster, it will deadlock. The reason is that do_no_page() will repeatedly call gfs2_sharewrite_nopage(), because each node keeps giving up the glock too early, and is forced to call unmap_mapping_range(). This bumps the mapping->truncate_count sequence count, forcing do_no_page() to retry. This patch institutes a minimum glock hold time a tenth a second. This insures that even in heavy contention cases, the node has enough time to get some useful work done before it gives up the glock. A second issue is that when gfs2_glock_dq() is called from within a page fault to demote a lock, and the associated page needs to be written out, it will try to acqire a lock on it, but it has already been locked at a higher level. This patch puts makes gfs2_glock_dq() use the work queue as well, to avoid this issue. This is the same patch as Steve Whitehouse originally proposed to fix this issue, execpt that gfs2_glock_dq() now grabs a reference to the glock before it queues up the work on it. Signed-off-by: Benjamin E. Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 75 +++++++++++++++++++++++++++++++++++++----------- fs/gfs2/glops.c | 2 ++ fs/gfs2/incore.h | 5 ++++ 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 3d949187fed0..931368a385c8 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "gfs2.h" #include "incore.h" @@ -58,10 +60,13 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl); static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh); static void gfs2_glock_drop_th(struct gfs2_glock *gl); +static void run_queue(struct gfs2_glock *gl); + static DECLARE_RWSEM(gfs2_umount_flush_sem); static struct dentry *gfs2_root; static struct task_struct *scand_process; static unsigned int scand_secs = 5; +static struct workqueue_struct *glock_workqueue; #define GFS2_GL_HASH_SHIFT 15 #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) @@ -277,6 +282,18 @@ static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp, return gl; } +static void glock_work_func(struct work_struct *work) +{ + struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work); + + spin_lock(&gl->gl_spin); + if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags)) + set_bit(GLF_DEMOTE, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); + gfs2_glock_put(gl); +} + /** * gfs2_glock_get() - Get a glock, or create one if one doesn't exist * @sdp: The GFS2 superblock @@ -316,6 +333,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_name = name; atomic_set(&gl->gl_ref, 1); gl->gl_state = LM_ST_UNLOCKED; + gl->gl_demote_state = LM_ST_EXCLUSIVE; gl->gl_hash = hash; gl->gl_owner_pid = 0; gl->gl_ip = 0; @@ -324,10 +342,12 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_req_bh = NULL; gl->gl_vn = 0; gl->gl_stamp = jiffies; + gl->gl_tchange = jiffies; gl->gl_object = NULL; gl->gl_sbd = sdp; gl->gl_aspace = NULL; lops_init_le(&gl->gl_le, &gfs2_glock_lops); + INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); /* If this glock protects actual on-disk data or metadata blocks, create a VFS inode to manage the pages/buffers holding them. */ @@ -441,6 +461,8 @@ static void wait_on_holder(struct gfs2_holder *gh) static void gfs2_demote_wake(struct gfs2_glock *gl) { + BUG_ON(!spin_is_locked(&gl->gl_spin)); + gl->gl_demote_state = LM_ST_EXCLUSIVE; clear_bit(GLF_DEMOTE, &gl->gl_flags); smp_mb__after_clear_bit(); wake_up_bit(&gl->gl_flags, GLF_DEMOTE); @@ -682,10 +704,14 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl) * practise: LM_ST_SHARED and LM_ST_UNLOCKED */ -static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remote) +static void handle_callback(struct gfs2_glock *gl, unsigned int state, + int remote, unsigned long delay) { + int bit = delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE; + spin_lock(&gl->gl_spin); - if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) { + set_bit(bit, &gl->gl_flags); + if (gl->gl_demote_state == LM_ST_EXCLUSIVE) { gl->gl_demote_state = state; gl->gl_demote_time = jiffies; if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN && @@ -727,6 +753,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) } gl->gl_state = new_state; + gl->gl_tchange = jiffies; } /** @@ -813,7 +840,6 @@ out: gl->gl_req_gh = NULL; gl->gl_req_bh = NULL; clear_bit(GLF_LOCK, &gl->gl_flags); - run_queue(gl); spin_unlock(&gl->gl_spin); } @@ -885,7 +911,6 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) gfs2_assert_warn(sdp, !ret); state_change(gl, LM_ST_UNLOCKED); - gfs2_demote_wake(gl); if (glops->go_inval) glops->go_inval(gl, DIO_METADATA); @@ -898,10 +923,10 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) } spin_lock(&gl->gl_spin); + gfs2_demote_wake(gl); gl->gl_req_gh = NULL; gl->gl_req_bh = NULL; clear_bit(GLF_LOCK, &gl->gl_flags); - run_queue(gl); spin_unlock(&gl->gl_spin); gfs2_glock_put(gl); @@ -1209,9 +1234,10 @@ void gfs2_glock_dq(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; const struct gfs2_glock_operations *glops = gl->gl_ops; + unsigned delay = 0; if (gh->gh_flags & GL_NOCACHE) - handle_callback(gl, LM_ST_UNLOCKED, 0); + handle_callback(gl, LM_ST_UNLOCKED, 0, 0); gfs2_glmutex_lock(gl); @@ -1229,8 +1255,14 @@ void gfs2_glock_dq(struct gfs2_holder *gh) } clear_bit(GLF_LOCK, &gl->gl_flags); - run_queue(gl); spin_unlock(&gl->gl_spin); + + gfs2_glock_hold(gl); + if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) && + !test_bit(GLF_DEMOTE, &gl->gl_flags)) + delay = gl->gl_ops->go_min_hold_time; + if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0) + gfs2_glock_put(gl); } void gfs2_glock_dq_wait(struct gfs2_holder *gh) @@ -1457,18 +1489,21 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, unsigned int state) { struct gfs2_glock *gl; + unsigned long delay = 0; + unsigned long holdtime; + unsigned long now = jiffies; gl = gfs2_glock_find(sdp, name); if (!gl) return; - handle_callback(gl, state, 1); + holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time; + if (time_before(now, holdtime)) + delay = holdtime - now; - spin_lock(&gl->gl_spin); - run_queue(gl); - spin_unlock(&gl->gl_spin); - - gfs2_glock_put(gl); + handle_callback(gl, state, 1, delay); + if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0) + gfs2_glock_put(gl); } /** @@ -1509,7 +1544,8 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) return; if (!gfs2_assert_warn(sdp, gl->gl_req_bh)) gl->gl_req_bh(gl, async->lc_ret); - gfs2_glock_put(gl); + if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) + gfs2_glock_put(gl); up_read(&gfs2_umount_flush_sem); return; } @@ -1602,7 +1638,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) if (gfs2_glmutex_trylock(gl)) { if (list_empty(&gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) - handle_callback(gl, LM_ST_UNLOCKED, 0); + handle_callback(gl, LM_ST_UNLOCKED, 0, 0); gfs2_glmutex_unlock(gl); } @@ -1702,7 +1738,7 @@ static void clear_glock(struct gfs2_glock *gl) if (gfs2_glmutex_trylock(gl)) { if (list_empty(&gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED) - handle_callback(gl, LM_ST_UNLOCKED, 0); + handle_callback(gl, LM_ST_UNLOCKED, 0, 0); gfs2_glmutex_unlock(gl); } } @@ -2009,11 +2045,18 @@ int __init gfs2_glock_init(void) if (IS_ERR(scand_process)) return PTR_ERR(scand_process); + glock_workqueue = create_workqueue("glock_workqueue"); + if (IS_ERR(glock_workqueue)) { + kthread_stop(scand_process); + return PTR_ERR(glock_workqueue); + } + return 0; } void gfs2_glock_exit(void) { + destroy_workqueue(glock_workqueue); kthread_stop(scand_process); } diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 88342e0b4bc7..7ef6b23bb38a 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -454,6 +454,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = { .go_lock = inode_go_lock, .go_unlock = inode_go_unlock, .go_type = LM_TYPE_INODE, + .go_min_hold_time = HZ / 10, }; const struct gfs2_glock_operations gfs2_rgrp_glops = { @@ -464,6 +465,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { .go_lock = rgrp_go_lock, .go_unlock = rgrp_go_unlock, .go_type = LM_TYPE_RGRP, + .go_min_hold_time = HZ / 10, }; const struct gfs2_glock_operations gfs2_trans_glops = { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 1390b30daf19..23b611aa70d2 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -11,6 +11,7 @@ #define __INCORE_DOT_H__ #include +#include #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 @@ -130,6 +131,7 @@ struct gfs2_glock_operations { int (*go_lock) (struct gfs2_holder *gh); void (*go_unlock) (struct gfs2_holder *gh); const int go_type; + const unsigned long go_min_hold_time; }; enum { @@ -161,6 +163,7 @@ enum { GLF_LOCK = 1, GLF_STICKY = 2, GLF_DEMOTE = 3, + GLF_PENDING_DEMOTE = 4, GLF_DIRTY = 5, }; @@ -193,6 +196,7 @@ struct gfs2_glock { u64 gl_vn; unsigned long gl_stamp; + unsigned long gl_tchange; void *gl_object; struct list_head gl_reclaim; @@ -203,6 +207,7 @@ struct gfs2_glock { struct gfs2_log_element gl_le; struct list_head gl_ail_list; atomic_t gl_ail_count; + struct delayed_work gl_work; }; struct gfs2_alloc { From e9bd2b3bafd29bf75522546207f0bba0ec4515c2 Mon Sep 17 00:00:00 2001 From: Wendy Cheng Date: Fri, 24 Aug 2007 09:15:01 -0400 Subject: [PATCH 0969/2804] [GFS2] fix inode meta data corruption Fix a nasty inode meta data corruption issue by keeping the buffer head in icache array. This buffer needs to stay in memory until journal flush occurs Otherwise, gfs2_meta_inode_buffer could do a disk read before the inode hits disk. It ends up with meta data corruptions. The buffer will be released as part of the existing journal flush logic. Signed-off-by: S. Wendy Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 34f7bcdea1e9..013f00b90cc2 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -244,6 +244,11 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) return 0; } +static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh) +{ + ip->i_cache[0] = bh; +} + /** * gfs2_inode_refresh - Refresh the incore copy of the dinode * @ip: The GFS2 inode @@ -688,7 +693,7 @@ out: static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, const struct gfs2_inum_host *inum, unsigned int mode, unsigned int uid, unsigned int gid, - const u64 *generation, dev_t dev) + const u64 *generation, dev_t dev, struct buffer_head **bhp) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_dinode *di; @@ -743,13 +748,15 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); memset(&di->di_reserved, 0, sizeof(di->di_reserved)); + + set_buffer_uptodate(dibh); - brelse(dibh); + *bhp = dibh; } static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, unsigned int mode, const struct gfs2_inum_host *inum, - const u64 *generation, dev_t dev) + const u64 *generation, dev_t dev, struct buffer_head **bhp) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); unsigned int uid, gid; @@ -770,7 +777,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, if (error) goto out_quota; - init_dinode(dip, gl, inum, mode, uid, gid, generation, dev); + init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); gfs2_quota_change(dip, +1, uid, gid); gfs2_trans_end(sdp); @@ -909,6 +916,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; int error; u64 generation; + struct buffer_head *bh=NULL; if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG); @@ -935,7 +943,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (error) goto fail_gunlock; - error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev); + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); if (error) goto fail_gunlock2; @@ -945,6 +953,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (IS_ERR(inode)) goto fail_gunlock2; + gfs2_inode_bh(GFS2_I(inode), bh); + error = gfs2_inode_refresh(GFS2_I(inode)); if (error) goto fail_gunlock2; From 8497a46e178addb27ad1c981befaa17ca788b5c3 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sun, 26 Aug 2007 14:23:56 +0100 Subject: [PATCH 0970/2804] [GFS2] Correct lock ordering in unlink This patch corrects the lock ordering in unlink to be the same as that in the rest of GFS2, i.e. parent -> child -> rgrp. Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_inode.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 5b8b994b9912..2cbe5a321e89 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -278,17 +278,25 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); - error = gfs2_glock_nq_m(3, ghs); + error = gfs2_glock_nq(ghs); /* parent */ if (error) - goto out; + goto out_parent; + + error = gfs2_glock_nq(ghs + 1); /* child */ + if (error) + goto out_child; + + error = gfs2_glock_nq(ghs + 2); /* rgrp */ + if (error) + goto out_rgrp; error = gfs2_unlink_ok(dip, &dentry->d_name, ip); if (error) - goto out_gunlock; + goto out_rgrp; error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); if (error) - goto out_gunlock; + goto out_rgrp; error = gfs2_dir_del(dip, &dentry->d_name); if (error) @@ -298,12 +306,15 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) out_end_trans: gfs2_trans_end(sdp); -out_gunlock: - gfs2_glock_dq_m(3, ghs); -out: - gfs2_holder_uninit(ghs); - gfs2_holder_uninit(ghs + 1); + gfs2_glock_dq(ghs + 2); +out_rgrp: gfs2_holder_uninit(ghs + 2); + gfs2_glock_dq(ghs + 1); +out_child: + gfs2_holder_uninit(ghs + 1); + gfs2_glock_dq(ghs); +out_parent: + gfs2_holder_uninit(ghs); gfs2_glock_dq_uninit(&ri_gh); return error; } From 1e1a3d03e927d39282208aed676e49d25129feea Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Aug 2007 09:45:26 +0100 Subject: [PATCH 0971/2804] [GFS2] Introduce gfs2_remove_from_ail This collects together the operations required to remove a gfs2_bufdata from the ail lists. Its only called from two places to start with, but expect to see more of this function in future. Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 6 +----- fs/gfs2/log.c | 31 +++++++++++++++++++++---------- fs/gfs2/log.h | 1 + 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 7ef6b23bb38a..b17346a355bf 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -60,11 +60,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) blkno = bh->b_blocknr; gfs2_assert_withdraw(sdp, !buffer_busy(bh)); - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&gl->gl_ail_count); - brelse(bh); + gfs2_remove_from_ail(NULL, bd); gfs2_log_unlock(sdp); gfs2_trans_add_revoke(sdp, blkno); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index d0e6b42c86e1..d8232ec25397 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -59,6 +59,26 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, return blks; } +/** + * gfs2_remove_from_ail - Remove an entry from the ail lists, updating counters + * @mapping: The associated mapping (maybe NULL) + * @bd: The gfs2_bufdata to remove + * + * The log lock _must_ be held when calling this function + * + */ + +void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd) +{ + bd->bd_ail = NULL; + list_del(&bd->bd_ail_st_list); + list_del(&bd->bd_ail_gl_list); + atomic_dec(&bd->bd_gl->gl_ail_count); + if (mapping) + gfs2_meta_cache_flush(GFS2_I(mapping->host)); + brelse(bd->bd_bh); +} + /** * gfs2_ail1_start_one - Start I/O on a part of the AIL * @sdp: the filesystem @@ -219,21 +239,12 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) { struct list_head *head = &ai->ai_ail2_list; struct gfs2_bufdata *bd; - struct gfs2_inode *bh_ip; while (!list_empty(head)) { bd = list_entry(head->prev, struct gfs2_bufdata, bd_ail_st_list); gfs2_assert(sdp, bd->bd_ail == ai); - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&bd->bd_gl->gl_ail_count); - if (bd->bd_bh->b_page->mapping) { - bh_ip = GFS2_I(bd->bd_bh->b_page->mapping->host); - gfs2_meta_cache_flush(bh_ip); - } - brelse(bd->bd_bh); + gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd); } } diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 8e7aa0f29109..639423561b2d 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -58,6 +58,7 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, struct buffer_head *real); void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); +void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd); void gfs2_log_shutdown(struct gfs2_sbd *sdp); void gfs2_meta_syncfs(struct gfs2_sbd *sdp); From eaf965270ffff3086ef929e660ace45e862cfd2d Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Aug 2007 09:49:37 +0100 Subject: [PATCH 0972/2804] [GFS2] Don't mark jdata dirty in gfs2_unstuffer_page() Journaled data is marked dirty by gfs2_unpin and should not be marked dirty here. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 9b8990444e6c..1e56f4de7358 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -95,7 +95,8 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, set_buffer_uptodate(bh); if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) gfs2_trans_add_bh(ip->i_gl, bh, 0); - mark_buffer_dirty(bh); + if (!gfs2_is_jdata(ip)) + mark_buffer_dirty(bh); if (release) { unlock_page(page); From 9b9107a5a8b190e6cf09bbdf893869c6a9c482cc Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 27 Aug 2007 13:54:05 +0100 Subject: [PATCH 0973/2804] [GFS2] Move pin/unpin into lops.c, clean up locking gfs2_pin and gfs2_unpin are only used in lops.c, despite being defined in meta_io.c, so this patch moves them into lops.c and makes them static. At the same time, its possible to clean up the locking in the buf and databuf _lo_add() functions so that we only need to grab the spinlock once. Also we have to move lock_buffer() around the _lo_add() functions since we can't do that in gfs2_pin() any more since we hold the spinlock for the duration of that function. As a result, the code shrinks by 12 lines and we do far fewer operations when adding buffers to the log. It also makes the code somewhat easier to read & understand. Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 117 +++++++++++++++++++++++++++++++++++----------- fs/gfs2/meta_io.c | 70 --------------------------- fs/gfs2/meta_io.h | 3 -- 3 files changed, 89 insertions(+), 101 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 7ef335623373..3ec587135d46 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -27,7 +27,71 @@ #include "trans.h" #include "util.h" -static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +/** + * gfs2_pin - Pin a buffer in memory + * @sdp: The superblock + * @bh: The buffer to be pinned + * + * The log lock must be held when calling this function + */ +static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) +{ + struct gfs2_bufdata *bd; + + gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); + + clear_buffer_dirty(bh); + if (test_set_buffer_pinned(bh)) + gfs2_assert_withdraw(sdp, 0); + if (!buffer_uptodate(bh)) + gfs2_io_error_bh(sdp, bh); + bd = bh->b_private; + /* If this buffer is in the AIL and it has already been written + * to in-place disk block, remove it from the AIL. + */ + if (bd->bd_ail) + list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); + get_bh(bh); +} + +/** + * gfs2_unpin - Unpin a buffer + * @sdp: the filesystem the buffer belongs to + * @bh: The buffer to unpin + * @ai: + * + */ + +static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, + struct gfs2_ail *ai) +{ + struct gfs2_bufdata *bd = bh->b_private; + + gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); + + if (!buffer_pinned(bh)) + gfs2_assert_withdraw(sdp, 0); + + lock_buffer(bh); + mark_buffer_dirty(bh); + clear_buffer_pinned(bh); + + gfs2_log_lock(sdp); + if (bd->bd_ail) { + list_del(&bd->bd_ail_st_list); + brelse(bh); + } else { + struct gfs2_glock *gl = bd->bd_gl; + list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); + atomic_inc(&gl->gl_ail_count); + } + bd->bd_ail = ai; + list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); + gfs2_log_unlock(sdp); + unlock_buffer(bh); +} + +static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_glock *gl; struct gfs2_trans *tr = current->journal_info; @@ -38,15 +102,19 @@ static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl))) return; - gfs2_log_lock(sdp); - if (!list_empty(&le->le_list)){ - gfs2_log_unlock(sdp); + if (!list_empty(&le->le_list)) return; - } + gfs2_glock_hold(gl); set_bit(GLF_DIRTY, &gl->gl_flags); sdp->sd_log_num_gl++; list_add(&le->le_list, &sdp->sd_log_le_gl); +} + +static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) +{ + gfs2_log_lock(sdp); + __glock_lo_add(sdp, le); gfs2_log_unlock(sdp); } @@ -71,30 +139,25 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); struct gfs2_trans *tr; + lock_buffer(bd->bd_bh); gfs2_log_lock(sdp); - if (!list_empty(&bd->bd_list_tr)) { - gfs2_log_unlock(sdp); - return; - } + if (!list_empty(&bd->bd_list_tr)) + goto out; tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); - gfs2_log_unlock(sdp); - if (!list_empty(&le->le_list)) - return; - - gfs2_trans_add_gl(bd->bd_gl); - + goto out; + __glock_lo_add(sdp, &bd->bd_gl->gl_le); gfs2_meta_check(sdp, bd->bd_bh); gfs2_pin(sdp, bd->bd_bh); - gfs2_log_lock(sdp); sdp->sd_log_num_buf++; list_add(&le->le_list, &sdp->sd_log_le_buf); - gfs2_log_unlock(sdp); - tr->tr_num_buf_new++; +out: + gfs2_log_unlock(sdp); + unlock_buffer(bd->bd_bh); } static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) @@ -476,31 +539,29 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct address_space *mapping = bd->bd_bh->b_page->mapping; struct gfs2_inode *ip = GFS2_I(mapping->host); + lock_buffer(bd->bd_bh); gfs2_log_lock(sdp); - if (!list_empty(&bd->bd_list_tr)) { - gfs2_log_unlock(sdp); - return; - } + if (!list_empty(&bd->bd_list_tr)) + goto out; tr->tr_touched = 1; if (gfs2_is_jdata(ip)) { tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); } - gfs2_log_unlock(sdp); if (!list_empty(&le->le_list)) - return; + goto out; - gfs2_trans_add_gl(bd->bd_gl); + __glock_lo_add(sdp, &bd->bd_gl->gl_le); if (gfs2_is_jdata(ip)) { gfs2_pin(sdp, bd->bd_bh); tr->tr_num_databuf_new++; - } - gfs2_log_lock(sdp); - if (gfs2_is_jdata(ip)) sdp->sd_log_num_jdata++; + } sdp->sd_log_num_databuf++; list_add(&le->le_list, &sdp->sd_log_le_databuf); +out: gfs2_log_unlock(sdp); + unlock_buffer(bd->bd_bh); } static int gfs2_check_magic(struct buffer_head *bh) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 8da343b34ae7..d762e4f7044e 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -297,76 +297,6 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, unlock_page(bh->b_page); } -/** - * gfs2_pin - Pin a buffer in memory - * @sdp: the filesystem the buffer belongs to - * @bh: The buffer to be pinned - * - */ - -void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) -{ - struct gfs2_bufdata *bd = bh->b_private; - - gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); - - if (test_set_buffer_pinned(bh)) - gfs2_assert_withdraw(sdp, 0); - - wait_on_buffer(bh); - - /* If this buffer is in the AIL and it has already been written - to in-place disk block, remove it from the AIL. */ - - gfs2_log_lock(sdp); - if (bd->bd_ail && !buffer_in_io(bh)) - list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); - gfs2_log_unlock(sdp); - - clear_buffer_dirty(bh); - wait_on_buffer(bh); - - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - - get_bh(bh); -} - -/** - * gfs2_unpin - Unpin a buffer - * @sdp: the filesystem the buffer belongs to - * @bh: The buffer to unpin - * @ai: - * - */ - -void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, - struct gfs2_ail *ai) -{ - struct gfs2_bufdata *bd = bh->b_private; - - gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); - - if (!buffer_pinned(bh)) - gfs2_assert_withdraw(sdp, 0); - - mark_buffer_dirty(bh); - clear_buffer_pinned(bh); - - gfs2_log_lock(sdp); - if (bd->bd_ail) { - list_del(&bd->bd_ail_st_list); - brelse(bh); - } else { - struct gfs2_glock *gl = bd->bd_gl; - list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); - atomic_inc(&gl->gl_ail_count); - } - bd->bd_ail = ai; - list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); - gfs2_log_unlock(sdp); -} - /** * gfs2_meta_wipe - make inode's buffers so they aren't dirty/pinned anymore * @ip: the inode who owns the buffers diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 527bf19d9690..fd67f07cd60e 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -50,9 +50,6 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta); -void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); -void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, - struct gfs2_ail *ai); void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen); From d7b616e252b125f12b007c392f7644053bb6f140 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sun, 2 Sep 2007 10:48:13 +0100 Subject: [PATCH 0974/2804] [GFS2] Clean up ordered write code The following patch removes the ordered write processing from databuf_lo_before_commit() and moves it to log.c. This has the effect of greatly simplyfying databuf_lo_before_commit() and well as potentially making the ordered write code more efficient. As a side effect of this, its now possible to remove ordered buffers from the ordered buffer list at any time, so we now make use of this in invalidatepage and releasepage to ensure timely release of these buffers. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 2 +- fs/gfs2/log.c | 57 ++++++++++++++- fs/gfs2/lops.c | 160 +++++++++++------------------------------- fs/gfs2/ops_address.c | 50 +++++++++++-- fs/gfs2/ops_fstype.c | 1 + 5 files changed, 143 insertions(+), 127 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 23b611aa70d2..388dc1bd736f 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -612,13 +612,13 @@ struct gfs2_sbd { unsigned int sd_log_num_revoke; unsigned int sd_log_num_rg; unsigned int sd_log_num_databuf; - unsigned int sd_log_num_jdata; struct list_head sd_log_le_gl; struct list_head sd_log_le_buf; struct list_head sd_log_le_revoke; struct list_head sd_log_le_rg; struct list_head sd_log_le_databuf; + struct list_head sd_log_le_ordered; unsigned int sd_log_blks_free; struct mutex sd_log_reserve_mutex; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index d8232ec25397..20fa528d457d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -620,6 +620,57 @@ static void log_flush_commit(struct gfs2_sbd *sdp) } } +static void gfs2_ordered_write(struct gfs2_sbd *sdp) +{ + struct gfs2_bufdata *bd; + struct buffer_head *bh; + LIST_HEAD(written); + + gfs2_log_lock(sdp); + while (!list_empty(&sdp->sd_log_le_ordered)) { + bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list); + list_move(&bd->bd_le.le_list, &written); + bh = bd->bd_bh; + if (!buffer_dirty(bh)) + continue; + get_bh(bh); + gfs2_log_unlock(sdp); + lock_buffer(bh); + if (test_clear_buffer_dirty(bh)) { + bh->b_end_io = end_buffer_write_sync; + submit_bh(WRITE, bh); + } else { + unlock_buffer(bh); + brelse(bh); + } + gfs2_log_lock(sdp); + } + list_splice(&written, &sdp->sd_log_le_ordered); + gfs2_log_unlock(sdp); +} + +static void gfs2_ordered_wait(struct gfs2_sbd *sdp) +{ + struct gfs2_bufdata *bd; + struct buffer_head *bh; + + gfs2_log_lock(sdp); + while (!list_empty(&sdp->sd_log_le_ordered)) { + bd = list_entry(sdp->sd_log_le_ordered.prev, struct gfs2_bufdata, bd_le.le_list); + bh = bd->bd_bh; + if (buffer_locked(bh)) { + get_bh(bh); + gfs2_log_unlock(sdp); + wait_on_buffer(bh); + brelse(bh); + gfs2_log_lock(sdp); + continue; + } + list_del_init(&bd->bd_le.le_list); + } + gfs2_log_unlock(sdp); +} + /** * gfs2_log_flush - flush incore transaction(s) * @sdp: the filesystem @@ -648,7 +699,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) INIT_LIST_HEAD(&ai->ai_ail2_list); gfs2_assert_withdraw(sdp, - sdp->sd_log_num_buf + sdp->sd_log_num_jdata == + sdp->sd_log_num_buf + sdp->sd_log_num_databuf == sdp->sd_log_commited_buf + sdp->sd_log_commited_databuf); gfs2_assert_withdraw(sdp, @@ -658,7 +709,10 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) sdp->sd_log_flush_wrapped = 0; ai->ai_first = sdp->sd_log_flush_head; + gfs2_ordered_write(sdp); lops_before_commit(sdp); + gfs2_ordered_wait(sdp); + if (!list_empty(&sdp->sd_log_flush_list)) log_flush_commit(sdp); else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ @@ -751,7 +805,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); - gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 3ec587135d46..7e2d4e692b50 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -555,10 +555,11 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) if (gfs2_is_jdata(ip)) { gfs2_pin(sdp, bd->bd_bh); tr->tr_num_databuf_new++; - sdp->sd_log_num_jdata++; + sdp->sd_log_num_databuf++; + list_add(&le->le_list, &sdp->sd_log_le_databuf); + } else { + list_add(&le->le_list, &sdp->sd_log_le_ordered); } - sdp->sd_log_num_databuf++; - list_add(&le->le_list, &sdp->sd_log_le_databuf); out: gfs2_log_unlock(sdp); unlock_buffer(bd->bd_bh); @@ -583,114 +584,59 @@ static int gfs2_check_magic(struct buffer_head *bh) /** * databuf_lo_before_commit - Scan the data buffers, writing as we go * - * Here we scan through the lists of buffers and make the assumption - * that any buffer thats been pinned is being journaled, and that - * any unpinned buffer is an ordered write data buffer and therefore - * will be written back rather than journaled. */ + static void databuf_lo_before_commit(struct gfs2_sbd *sdp) { - LIST_HEAD(started); - struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt; + struct gfs2_bufdata *bd1 = NULL, *bd2; struct buffer_head *bh = NULL,*bh1 = NULL; struct gfs2_log_descriptor *ld; unsigned int limit; - unsigned int total_dbuf; - unsigned int total_jdata; + unsigned int total; unsigned int num, n; __be64 *ptr = NULL; + int magic; + limit = databuf_limit(sdp); - /* - * Start writing ordered buffers, write journaled buffers - * into the log along with a header - */ gfs2_log_lock(sdp); - total_dbuf = sdp->sd_log_num_databuf; - total_jdata = sdp->sd_log_num_jdata; + total = sdp->sd_log_num_databuf; bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, bd_le.le_list); - while(total_dbuf) { - num = total_jdata; + while(total) { + num = total; if (num > limit) num = limit; + + gfs2_log_unlock(sdp); + bh = gfs2_log_get_buf(sdp); + gfs2_log_lock(sdp); + + ld = (struct gfs2_log_descriptor *)bh->b_data; + ptr = (__be64 *)(bh->b_data + DATABUF_OFFSET); + ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); + ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); + ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_JDATA); + ld->ld_length = cpu_to_be32(num + 1); + ld->ld_data1 = cpu_to_be32(num); + ld->ld_data2 = cpu_to_be32(0); + memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); + n = 0; - list_for_each_entry_safe_continue(bd1, bdt, - &sdp->sd_log_le_databuf, - bd_le.le_list) { - /* store off the buffer head in a local ptr since - * gfs2_bufdata might change when we drop the log lock - */ + list_for_each_entry_continue(bd1, &sdp->sd_log_le_databuf, + bd_le.le_list) { bh1 = bd1->bd_bh; - /* An ordered write buffer */ - if (bh1 && !buffer_pinned(bh1)) { - list_move(&bd1->bd_le.le_list, &started); - if (bd1 == bd2) { - bd2 = NULL; - bd2 = list_prepare_entry(bd2, - &sdp->sd_log_le_databuf, - bd_le.le_list); - } - total_dbuf--; - if (bh1) { - if (buffer_dirty(bh1)) { - get_bh(bh1); - - gfs2_log_unlock(sdp); - - ll_rw_block(SWRITE, 1, &bh1); - brelse(bh1); - - gfs2_log_lock(sdp); - } - continue; - } - continue; - } else if (bh1) { /* A journaled buffer */ - int magic; - gfs2_log_unlock(sdp); - if (!bh) { - bh = gfs2_log_get_buf(sdp); - ld = (struct gfs2_log_descriptor *) - bh->b_data; - ptr = (__be64 *)(bh->b_data + - DATABUF_OFFSET); - ld->ld_header.mh_magic = - cpu_to_be32(GFS2_MAGIC); - ld->ld_header.mh_type = - cpu_to_be32(GFS2_METATYPE_LD); - ld->ld_header.mh_format = - cpu_to_be32(GFS2_FORMAT_LD); - ld->ld_type = - cpu_to_be32(GFS2_LOG_DESC_JDATA); - ld->ld_length = cpu_to_be32(num + 1); - ld->ld_data1 = cpu_to_be32(num); - ld->ld_data2 = cpu_to_be32(0); - memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); - } - magic = gfs2_check_magic(bh1); - *ptr++ = cpu_to_be64(bh1->b_blocknr); - *ptr++ = cpu_to_be64((__u64)magic); - clear_buffer_escaped(bh1); - if (unlikely(magic != 0)) - set_buffer_escaped(bh1); - gfs2_log_lock(sdp); - if (++n >= num) - break; - } else if (!bh1) { - total_dbuf--; - sdp->sd_log_num_databuf--; - list_del_init(&bd1->bd_le.le_list); - if (bd1 == bd2) { - bd2 = NULL; - bd2 = list_prepare_entry(bd2, - &sdp->sd_log_le_databuf, - bd_le.le_list); - } - kmem_cache_free(gfs2_bufdata_cachep, bd1); - } + magic = gfs2_check_magic(bh1); + *ptr++ = cpu_to_be64(bh1->b_blocknr); + *ptr++ = cpu_to_be64((__u64)magic); + clear_buffer_escaped(bh1); + if (unlikely(magic != 0)) + set_buffer_escaped(bh1); + if (++n >= num) + break; } gfs2_log_unlock(sdp); if (bh) { @@ -727,34 +673,10 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) break; } bh = NULL; - BUG_ON(total_dbuf < num); - total_dbuf -= num; - total_jdata -= num; + BUG_ON(total < num); + total -= num; } gfs2_log_unlock(sdp); - - /* Wait on all ordered buffers */ - while (!list_empty(&started)) { - gfs2_log_lock(sdp); - bd1 = list_entry(started.next, struct gfs2_bufdata, - bd_le.le_list); - list_del_init(&bd1->bd_le.le_list); - sdp->sd_log_num_databuf--; - bh = bd1->bd_bh; - if (bh) { - bh->b_private = NULL; - get_bh(bh); - gfs2_log_unlock(sdp); - wait_on_buffer(bh); - brelse(bh); - } else - gfs2_log_unlock(sdp); - - kmem_cache_free(gfs2_bufdata_cachep, bd1); - } - - /* We've removed all the ordered write bufs here, so only jdata left */ - gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata); } static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, @@ -838,11 +760,9 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); list_del_init(&bd->bd_le.le_list); sdp->sd_log_num_databuf--; - sdp->sd_log_num_jdata--; gfs2_unpin(sdp, bd->bd_bh, ai); } gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); - gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata); } diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 8407d1db4eac..dd1ea491ddcb 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -616,13 +616,50 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) return dblock; } +static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh) +{ + struct gfs2_bufdata *bd; + + lock_buffer(bh); + gfs2_log_lock(sdp); + clear_buffer_dirty(bh); + bd = bh->b_private; + if (bd) { + if (!list_empty(&bd->bd_le.le_list)) { + if (!buffer_pinned(bh)) + list_del_init(&bd->bd_le.le_list); + } + } + bh->b_bdev = NULL; + clear_buffer_mapped(bh); + clear_buffer_req(bh); + clear_buffer_new(bh); + gfs2_log_unlock(sdp); + unlock_buffer(bh); +} + static void gfs2_invalidatepage(struct page *page, unsigned long offset) { + struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); + struct buffer_head *bh, *head; + unsigned long pos = 0; + BUG_ON(!PageLocked(page)); if (offset == 0) ClearPageChecked(page); + if (!page_has_buffers(page)) + goto out; - block_invalidatepage(page, offset); + bh = head = page_buffers(page); + do { + if (offset <= pos) + gfs2_discard(sdp, bh); + pos += bh->b_size; + bh = bh->b_this_page; + } while (bh != head); +out: + if (offset == 0) + try_to_release_page(page, 0); } /** @@ -732,9 +769,14 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) if (bd) { gfs2_assert_warn(sdp, bd->bd_bh == bh); gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); - bd->bd_bh = NULL; - if (!list_empty(&bd->bd_le.le_list)) - bd = NULL; + if (!list_empty(&bd->bd_le.le_list)) { + if (!buffer_pinned(bh)) + list_del_init(&bd->bd_le.le_list); + else + bd = NULL; + } + if (bd) + bd->bd_bh = NULL; bh->b_private = NULL; } gfs2_log_unlock(sdp); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 314c1134d12d..35f3dfa9bfb1 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -82,6 +82,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) INIT_LIST_HEAD(&sdp->sd_log_le_revoke); INIT_LIST_HEAD(&sdp->sd_log_le_rg); INIT_LIST_HEAD(&sdp->sd_log_le_databuf); + INIT_LIST_HEAD(&sdp->sd_log_le_ordered); mutex_init(&sdp->sd_log_reserve_mutex); INIT_LIST_HEAD(&sdp->sd_ail1_list); From 8475487befb29eeb038fef374a7433d276336a25 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Sun, 2 Sep 2007 10:55:29 +0100 Subject: [PATCH 0975/2804] [GFS2] Fix ordering of dirty/journal for ordered buffer unstuffing Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 1e56f4de7358..93fa427bb5f5 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -93,10 +93,10 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, map_bh(bh, inode->i_sb, block); set_buffer_uptodate(bh); - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) - gfs2_trans_add_bh(ip->i_gl, bh, 0); if (!gfs2_is_jdata(ip)) mark_buffer_dirty(bh); + if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) + gfs2_trans_add_bh(ip->i_gl, bh, 0); if (release) { unlock_page(page); From 82e86087bb774cd54d47db4a7c771b5b29bea9ed Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sun, 2 Sep 2007 15:39:43 +0100 Subject: [PATCH 0976/2804] [GFS2] Replace revoke structure with bufdata structure Both the revoke structure and the bufdata structure are quite similar. They are basically small tags which are put on lists. In addition to which the revoke structure is always allocated when there is a bufdata structure which is (or can be) freed. As such it should be possible to reduce the number of frees and allocations by using the same structure for both purposes. This patch is the first step along that path. It replaces existing uses of the revoke structure with the bufdata structure. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 13 +++++++------ fs/gfs2/lops.c | 10 +++++----- fs/gfs2/trans.c | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 388dc1bd736f..8aa5780862be 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -114,7 +114,13 @@ struct gfs2_bufdata { struct buffer_head *bd_bh; struct gfs2_glock *bd_gl; - struct list_head bd_list_tr; + union { + struct list_head list_tr; + u64 blkno; + } u; +#define bd_list_tr u.list_tr +#define bd_blkno u.blkno + struct gfs2_log_element bd_le; struct gfs2_ail *bd_ail; @@ -298,11 +304,6 @@ struct gfs2_file { struct gfs2_holder f_fl_gh; }; -struct gfs2_revoke { - struct gfs2_log_element rv_le; - u64 rv_blkno; -}; - struct gfs2_revoke_replay { struct list_head rr_list; u64 rr_blkno; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 7e2d4e692b50..cf6fe3631554 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -357,7 +357,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) struct buffer_head *bh; unsigned int offset; struct list_head *head = &sdp->sd_log_le_revoke; - struct gfs2_revoke *rv; + struct gfs2_bufdata *bd; if (!sdp->sd_log_num_revoke) return; @@ -376,8 +376,8 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) offset = sizeof(struct gfs2_log_descriptor); while (!list_empty(head)) { - rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list); - list_del_init(&rv->rv_le.le_list); + bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); + list_del_init(&bd->bd_le.le_list); sdp->sd_log_num_revoke--; if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { @@ -392,8 +392,8 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) offset = sizeof(struct gfs2_meta_header); } - *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno); - kfree(rv); + *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno); + kfree(bd); offset += sizeof(u64); } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index f8dabf8446bb..eadf96e00510 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -144,23 +144,23 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno) { - struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke), - GFP_NOFS | __GFP_NOFAIL); - lops_init_le(&rv->rv_le, &gfs2_revoke_lops); - rv->rv_blkno = blkno; - lops_add(sdp, &rv->rv_le); + struct gfs2_bufdata *bd = kmalloc(sizeof(struct gfs2_bufdata), + GFP_NOFS | __GFP_NOFAIL); + lops_init_le(&bd->bd_le, &gfs2_revoke_lops); + bd->bd_blkno = blkno; + lops_add(sdp, &bd->bd_le); } void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) { - struct gfs2_revoke *rv; + struct gfs2_bufdata *bd; int found = 0; gfs2_log_lock(sdp); - list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) { - if (rv->rv_blkno == blkno) { - list_del(&rv->rv_le.le_list); + list_for_each_entry(bd, &sdp->sd_log_le_revoke, bd_le.le_list) { + if (bd->bd_blkno == blkno) { + list_del(&bd->bd_le.le_list); gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke); sdp->sd_log_num_revoke--; found = 1; @@ -172,7 +172,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) if (found) { struct gfs2_trans *tr = current->journal_info; - kfree(rv); + kfree(bd); tr->tr_num_revoke_rm++; } } From 0820ab517e1b100ee3f9584ec27f93309689ebe7 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Sun, 2 Sep 2007 16:47:38 +0100 Subject: [PATCH 0977/2804] [GFS2] Use slab operations for all gfs2_bufdata allocations The old revoke structure was allocated using kalloc/kfree but there is a slab cache for gfs2_bufdata, so we should use that now that the structures have been converted. This is part two of the patch series to merge the revoke and gfs2_bufdata structures. Signed-off-by: Steven Whitehouse --- fs/gfs2/lops.c | 2 +- fs/gfs2/trans.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index cf6fe3631554..4cbef4c23a6b 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -393,7 +393,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) } *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno); - kfree(bd); + kmem_cache_free(gfs2_bufdata_cachep, bd); offset += sizeof(u64); } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index eadf96e00510..01cc27fefd84 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -144,7 +144,7 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno) { - struct gfs2_bufdata *bd = kmalloc(sizeof(struct gfs2_bufdata), + struct gfs2_bufdata *bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL); lops_init_le(&bd->bd_le, &gfs2_revoke_lops); bd->bd_blkno = blkno; @@ -172,7 +172,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) if (found) { struct gfs2_trans *tr = current->journal_info; - kfree(bd); + kmem_cache_free(gfs2_bufdata_cachep, bd); tr->tr_num_revoke_rm++; } } From 1ad38c437fa33f85ba4b6a85ea8c5478ee72d5bd Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 3 Sep 2007 11:01:33 +0100 Subject: [PATCH 0978/2804] [GFS2] Clean up gfs2_trans_add_revoke() The following alters gfs2_trans_add_revoke() to take a struct gfs2_bufdata as an argument. This eliminates the memory allocation which was previously required by making use of the already existing struct gfs2_bufdata. It makes some sanity checks to ensure that the gfs2_bufdata has been removed from all the lists before its recycled as a revoke structure. This saves one memory allocation and one free per revoke structure. Also as a result, and to simplify the locking, since there is no longer any blocking code in gfs2_trans_add_revoke() we must hold the log lock whenever this function is called. This reduces the amount of times we take and unlock the log lock. Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 14 +++++--------- fs/gfs2/log.c | 4 ++-- fs/gfs2/lops.c | 3 --- fs/gfs2/meta_io.c | 35 ++++++++++++----------------------- fs/gfs2/trans.c | 10 +++++----- fs/gfs2/trans.h | 2 +- 6 files changed, 25 insertions(+), 43 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index b17346a355bf..4670dcb2a877 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -41,7 +41,6 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) struct list_head *head = &gl->gl_ail_list; struct gfs2_bufdata *bd; struct buffer_head *bh; - u64 blkno; int error; blocks = atomic_read(&gl->gl_ail_count); @@ -57,15 +56,12 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) bd = list_entry(head->next, struct gfs2_bufdata, bd_ail_gl_list); bh = bd->bd_bh; - blkno = bh->b_blocknr; - gfs2_assert_withdraw(sdp, !buffer_busy(bh)); - gfs2_remove_from_ail(NULL, bd); - gfs2_log_unlock(sdp); - - gfs2_trans_add_revoke(sdp, blkno); - - gfs2_log_lock(sdp); + bd->bd_bh = NULL; + bh->b_private = NULL; + bd->bd_blkno = bh->b_blocknr; + gfs2_assert_withdraw(sdp, !buffer_busy(bh)); + gfs2_trans_add_revoke(sdp, bd); } gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); gfs2_log_unlock(sdp); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 20fa528d457d..4d04e6f19706 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -71,8 +71,8 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd) { bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); + list_del_init(&bd->bd_ail_st_list); + list_del_init(&bd->bd_ail_gl_list); atomic_dec(&bd->bd_gl->gl_ail_count); if (mapping) gfs2_meta_cache_flush(GFS2_I(mapping->host)); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 4cbef4c23a6b..342c10e12af2 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -343,11 +343,8 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_revoke++; - - gfs2_log_lock(sdp); sdp->sd_log_num_revoke++; list_add(&le->le_list, &sdp->sd_log_le_revoke); - gfs2_log_unlock(sdp); } static void revoke_lo_before_commit(struct gfs2_sbd *sdp) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index d762e4f7044e..19097bc7c81d 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -313,42 +313,31 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) while (blen) { bh = getbuf(ip->i_gl, bstart, NO_CREATE); if (bh) { - struct gfs2_bufdata *bd = bh->b_private; + struct gfs2_bufdata *bd; + lock_buffer(bh); + gfs2_log_lock(sdp); + bd = bh->b_private; if (test_clear_buffer_pinned(bh)) { struct gfs2_trans *tr = current->journal_info; - struct gfs2_inode *bh_ip = - GFS2_I(bh->b_page->mapping->host); - - gfs2_log_lock(sdp); list_del_init(&bd->bd_le.le_list); gfs2_assert_warn(sdp, sdp->sd_log_num_buf); sdp->sd_log_num_buf--; - gfs2_log_unlock(sdp); - if (bh_ip->i_inode.i_private != NULL) - tr->tr_num_databuf_rm++; - else - tr->tr_num_buf_rm++; + tr->tr_num_buf_rm++; brelse(bh); } if (bd) { - gfs2_log_lock(sdp); if (bd->bd_ail) { - u64 blkno = bh->b_blocknr; - bd->bd_ail = NULL; - list_del(&bd->bd_ail_st_list); - list_del(&bd->bd_ail_gl_list); - atomic_dec(&bd->bd_gl->gl_ail_count); - brelse(bh); - gfs2_log_unlock(sdp); - gfs2_trans_add_revoke(sdp, blkno); - } else - gfs2_log_unlock(sdp); + gfs2_remove_from_ail(NULL, bd); + bh->b_private = NULL; + bd->bd_bh = NULL; + bd->bd_blkno = bh->b_blocknr; + gfs2_trans_add_revoke(sdp, bd); + } } - - lock_buffer(bh); clear_buffer_dirty(bh); clear_buffer_uptodate(bh); + gfs2_log_unlock(sdp); unlock_buffer(bh); brelse(bh); diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 01cc27fefd84..717983e2c2ae 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -142,12 +142,12 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) lops_add(sdp, &bd->bd_le); } -void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno) +void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) { - struct gfs2_bufdata *bd = kmem_cache_alloc(gfs2_bufdata_cachep, - GFP_NOFS | __GFP_NOFAIL); + BUG_ON(!list_empty(&bd->bd_le.le_list)); + BUG_ON(!list_empty(&bd->bd_ail_st_list)); + BUG_ON(!list_empty(&bd->bd_ail_gl_list)); lops_init_le(&bd->bd_le, &gfs2_revoke_lops); - bd->bd_blkno = blkno; lops_add(sdp, &bd->bd_le); } @@ -160,7 +160,7 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) list_for_each_entry(bd, &sdp->sd_log_le_revoke, bd_le.le_list) { if (bd->bd_blkno == blkno) { - list_del(&bd->bd_le.le_list); + list_del_init(&bd->bd_le.le_list); gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke); sdp->sd_log_num_revoke--; found = 1; diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index 23d4cbe1de5b..043d5f4b9c4c 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -32,7 +32,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp); void gfs2_trans_add_gl(struct gfs2_glock *gl); void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta); -void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno); +void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno); void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd); From b4c20166dcfca106f0f416bfce200099ed76ab18 Mon Sep 17 00:00:00 2001 From: Abhijith Das Date: Thu, 13 Sep 2007 23:35:27 -0500 Subject: [PATCH 0979/2804] [GFS2] flocks from same process trip kernel BUG at fs/gfs2/glock.c:1118! This patch adds a new flag to the gfs2_holder structure GL_FLOCK. It is set on holders of glocks representing flocks. This flag is checked in add_to_queue() and a process is permitted to queue more than one holder onto a glock if it is set. This solves the issue of a process not being able to do multiple flocks on the same file. Through a single descriptor, a process can now promote and demote flocks. Through multiple descriptors a process can now queue multiple flocks on the same file. There's still the problem of a process deadlocking itself (because gfs2 blocking locks are not interruptible) by queueing incompatible deadlock. Signed-off-by: Abhijith Das Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 43 +++++++++++++++++++++++++------------------ fs/gfs2/glock.h | 1 + fs/gfs2/ops_file.c | 13 ++++++------- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 931368a385c8..d631cad0aeee 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1106,24 +1106,31 @@ static void add_to_queue(struct gfs2_holder *gh) if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags)) BUG(); - existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid); - if (existing) { - print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip); - printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid); - printk(KERN_INFO "lock type : %d lock state : %d\n", - existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state); - print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); - printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid); - printk(KERN_INFO "lock type : %d lock state : %d\n", - gl->gl_name.ln_type, gl->gl_state); - BUG(); - } - - existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid); - if (existing) { - print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip); - print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); - BUG(); + if (!(gh->gh_flags & GL_FLOCK)) { + existing = find_holder_by_owner(&gl->gl_holders, + gh->gh_owner_pid); + if (existing) { + print_symbol(KERN_WARNING "original: %s\n", + existing->gh_ip); + printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid); + printk(KERN_INFO "lock type : %d lock state : %d\n", + existing->gh_gl->gl_name.ln_type, + existing->gh_gl->gl_state); + print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); + printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid); + printk(KERN_INFO "lock type : %d lock state : %d\n", + gl->gl_name.ln_type, gl->gl_state); + BUG(); + } + + existing = find_holder_by_owner(&gl->gl_waiters3, + gh->gh_owner_pid); + if (existing) { + print_symbol(KERN_WARNING "original: %s\n", + existing->gh_ip); + print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip); + BUG(); + } } if (gh->gh_flags & LM_FLAG_PRIORITY) diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index f7a8e626aa08..b16f604eea9f 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -26,6 +26,7 @@ #define GL_SKIP 0x00000100 #define GL_ATIME 0x00000200 #define GL_NOCACHE 0x00000400 +#define GL_FLOCK 0x00000800 #define GL_NOCANCEL 0x00001000 #define GLR_TRYFAILED 13 diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 94d76ace0b95..46a9e10ff17b 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -571,7 +571,8 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) int error = 0; state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED; - flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE; + flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE + | GL_FLOCK; mutex_lock(&fp->f_fl_mutex); @@ -579,21 +580,19 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) if (gl) { if (fl_gh->gh_state == state) goto out; - gfs2_glock_hold(gl); flock_lock_file_wait(file, &(struct file_lock){.fl_type = F_UNLCK}); - gfs2_glock_dq_uninit(fl_gh); + gfs2_glock_dq_wait(fl_gh); + gfs2_holder_reinit(state, flags, fl_gh); } else { error = gfs2_glock_get(GFS2_SB(&ip->i_inode), ip->i_no_addr, &gfs2_flock_glops, CREATE, &gl); if (error) goto out; + gfs2_holder_init(gl, state, flags, fl_gh); + gfs2_glock_put(gl); } - - gfs2_holder_init(gl, state, flags, fl_gh); - gfs2_glock_put(gl); - error = gfs2_glock_nq(fl_gh); if (error) { gfs2_holder_uninit(fl_gh); From 49e61f2ef6f7d1d0296e3e30d366b28e0ca595c2 Mon Sep 17 00:00:00 2001 From: Wendy Cheng Date: Thu, 13 Sep 2007 17:52:42 -0400 Subject: [PATCH 0980/2804] [GFS2] Move inode deletion out of blocking_cb Move inode deletion code out of blocking_cb handle_callback route to avoid racy conditions that end up blocking lock_dlm1 thread. Fix bugzilla 286821. Signed-off-by: Wendy Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index d631cad0aeee..a37efe4aae6f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -716,12 +716,8 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, gl->gl_demote_time = jiffies; if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN && gl->gl_object) { - struct inode *inode = igrab(gl->gl_object); + gfs2_glock_schedule_for_reclaim(gl); spin_unlock(&gl->gl_spin); - if (inode) { - d_prune_aliases(inode); - iput(inode); - } return; } } else if (gl->gl_demote_state != LM_ST_UNLOCKED && From d66f8277f53407754f50ae6bada68f1b68d04d48 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Fri, 14 Sep 2007 08:49:21 +0100 Subject: [PATCH 0981/2804] [DLM] Make dlm_sendd cond_resched more Under high recovery loads dlm_sendd can monopolise the CPU and cause soft lockups. This one extra and one moved cond_resched() make it yield a little more during such times keeping work moving. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/lowcomms.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 62a8a6ccd992..58bf3f5cdbe2 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1264,14 +1264,15 @@ static void send_to_sock(struct connection *con) if (len) { ret = sendpage(con->sock, e->page, offset, len, msg_flags); - if (ret == -EAGAIN || ret == 0) + if (ret == -EAGAIN || ret == 0) { + cond_resched(); goto out; + } if (ret <= 0) goto send_error; - } else { + } /* Don't starve people filling buffers */ cond_resched(); - } spin_lock(&con->writequeue_lock); e->offset += ret; From 55c0c4ac0be144014651b19e77c9b77f367955de Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Fri, 14 Sep 2007 09:27:59 -0500 Subject: [PATCH 0982/2804] [GFS2] GFS2: chmod hung - fix race in thread creation The problem boiled down to a race between the gdlm_init_threads() function initializing thread1 and its setting of blist = 1. Essentially, "if (current == ls->thread1)" was checked by the thread before the thread creator set ls->thread1. Since thread1 is the only thread who is allowed to work on the blocking queue, and since neither thread thought it was thread1, no one was working on the queue. So everything just sat. This patch reuses the ls->async_lock spin_lock to fix the race, and it fixes the problem. I've done more than 2000 iterations of the loop that was recreating the failure and it seems to work. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse -- --- fs/gfs2/locking/dlm/thread.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index 1aca51e45092..bd938f06481d 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -268,20 +268,16 @@ static inline int check_drop(struct gdlm_ls *ls) return 0; } -static int gdlm_thread(void *data) +static int gdlm_thread(void *data, int blist) { struct gdlm_ls *ls = (struct gdlm_ls *) data; struct gdlm_lock *lp = NULL; - int blist = 0; uint8_t complete, blocking, submit, drop; DECLARE_WAITQUEUE(wait, current); /* Only thread1 is allowed to do blocking callbacks since gfs may wait for a completion callback within a blocking cb. */ - if (current == ls->thread1) - blist = 1; - while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&ls->thread_wait, &wait); @@ -333,12 +329,22 @@ static int gdlm_thread(void *data) return 0; } +static int gdlm_thread1(void *data) +{ + return gdlm_thread(data, 1); +} + +static int gdlm_thread2(void *data) +{ + return gdlm_thread(data, 0); +} + int gdlm_init_threads(struct gdlm_ls *ls) { struct task_struct *p; int error; - p = kthread_run(gdlm_thread, ls, "lock_dlm1"); + p = kthread_run(gdlm_thread1, ls, "lock_dlm1"); error = IS_ERR(p); if (error) { log_error("can't start lock_dlm1 thread %d", error); @@ -346,7 +352,7 @@ int gdlm_init_threads(struct gdlm_ls *ls) } ls->thread1 = p; - p = kthread_run(gdlm_thread, ls, "lock_dlm2"); + p = kthread_run(gdlm_thread2, ls, "lock_dlm2"); error = IS_ERR(p); if (error) { log_error("can't start lock_dlm2 thread %d", error); From 16615be18cadf53ee6f8a4f0bdd647f0753421b1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 17 Sep 2007 10:59:52 +0100 Subject: [PATCH 0983/2804] [GFS2] Clean up journaled data writing This patch cleans up the code for writing journaled data into the log. It also removes the need to allocate a small "tag" structure for each block written into the log. Instead we just keep count of the outstanding I/O so that we can be sure that its all been written at the correct time. Another result of this patch is that a number of ll_rw_block() calls have become submit_bh() calls, closing some races at the same time. Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 9 +- fs/gfs2/log.c | 143 ++++++++++++++----------- fs/gfs2/log.h | 1 + fs/gfs2/lops.c | 244 ++++++++++++++++++++++-------------------- fs/gfs2/meta_io.c | 55 ++++++---- fs/gfs2/meta_io.h | 3 + fs/gfs2/ops_address.c | 11 +- fs/gfs2/ops_fstype.c | 3 +- fs/gfs2/ops_inode.c | 7 +- fs/gfs2/ops_super.c | 13 ++- 10 files changed, 269 insertions(+), 220 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 8aa5780862be..eaddfb5a8e6f 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -341,12 +341,6 @@ struct gfs2_quota_data { unsigned long qd_last_touched; }; -struct gfs2_log_buf { - struct list_head lb_list; - struct buffer_head *lb_bh; - struct buffer_head *lb_real; -}; - struct gfs2_trans { unsigned long tr_ip; @@ -631,7 +625,8 @@ struct gfs2_sbd { unsigned long sd_log_flush_time; struct rw_semaphore sd_log_flush_lock; - struct list_head sd_log_flush_list; + atomic_t sd_log_in_flight; + wait_queue_head_t sd_log_flush_wait; unsigned int sd_log_flush_head; u64 sd_log_flush_wrapped; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 4d04e6f19706..ee704676b2f1 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -104,11 +104,8 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) gfs2_assert(sdp, bd->bd_ail == ai); if (!buffer_busy(bh)) { - if (!buffer_uptodate(bh)) { - gfs2_log_unlock(sdp); + if (!buffer_uptodate(bh)) gfs2_io_error_bh(sdp, bh); - gfs2_log_lock(sdp); - } list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); continue; } @@ -118,9 +115,16 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); + get_bh(bh); gfs2_log_unlock(sdp); - wait_on_buffer(bh); - ll_rw_block(WRITE, 1, &bh); + lock_buffer(bh); + if (test_clear_buffer_dirty(bh)) { + bh->b_end_io = end_buffer_write_sync; + submit_bh(WRITE, bh); + } else { + unlock_buffer(bh); + brelse(bh); + } gfs2_log_lock(sdp); retry = 1; @@ -446,10 +450,10 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) return tail; } -static inline void log_incr_head(struct gfs2_sbd *sdp) +void gfs2_log_incr_head(struct gfs2_sbd *sdp) { if (sdp->sd_log_flush_head == sdp->sd_log_tail) - gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head); + BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head); if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { sdp->sd_log_flush_head = 0; @@ -457,6 +461,23 @@ static inline void log_incr_head(struct gfs2_sbd *sdp) } } +/** + * gfs2_log_write_endio - End of I/O for a log buffer + * @bh: The buffer head + * @uptodate: I/O Status + * + */ + +static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate) +{ + struct gfs2_sbd *sdp = bh->b_private; + bh->b_private = NULL; + + end_buffer_write_sync(bh, uptodate); + if (atomic_dec_and_test(&sdp->sd_log_in_flight)) + wake_up(&sdp->sd_log_flush_wait); +} + /** * gfs2_log_get_buf - Get and initialize a buffer to use for log control data * @sdp: The GFS2 superblock @@ -467,24 +488,41 @@ static inline void log_incr_head(struct gfs2_sbd *sdp) struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) { u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); - struct gfs2_log_buf *lb; struct buffer_head *bh; - lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); - list_add(&lb->lb_list, &sdp->sd_log_flush_list); - - bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno); + bh = sb_getblk(sdp->sd_vfs, blkno); lock_buffer(bh); memset(bh->b_data, 0, bh->b_size); set_buffer_uptodate(bh); clear_buffer_dirty(bh); - unlock_buffer(bh); - - log_incr_head(sdp); + gfs2_log_incr_head(sdp); + atomic_inc(&sdp->sd_log_in_flight); + bh->b_private = sdp; + bh->b_end_io = gfs2_log_write_endio; return bh; } +/** + * gfs2_fake_write_endio - + * @bh: The buffer head + * @uptodate: The I/O Status + * + */ + +static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate) +{ + struct buffer_head *real_bh = bh->b_private; + struct gfs2_sbd *sdp = GFS2_SB(real_bh->b_page->mapping->host); + + end_buffer_write_sync(bh, uptodate); + free_buffer_head(bh); + unlock_buffer(real_bh); + brelse(real_bh); + if (atomic_dec_and_test(&sdp->sd_log_in_flight)) + wake_up(&sdp->sd_log_flush_wait); +} + /** * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log * @sdp: the filesystem @@ -497,22 +535,20 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, struct buffer_head *real) { u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); - struct gfs2_log_buf *lb; struct buffer_head *bh; - lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); - list_add(&lb->lb_list, &sdp->sd_log_flush_list); - lb->lb_real = real; - - bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); + bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); atomic_set(&bh->b_count, 1); - bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate); + bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); set_bh_page(bh, real->b_page, bh_offset(real)); bh->b_blocknr = blkno; bh->b_size = sdp->sd_sb.sb_bsize; bh->b_bdev = sdp->sd_vfs->s_bdev; + bh->b_private = real; + bh->b_end_io = gfs2_fake_write_endio; - log_incr_head(sdp); + gfs2_log_incr_head(sdp); + atomic_inc(&sdp->sd_log_in_flight); return bh; } @@ -579,45 +615,24 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) gfs2_assert_withdraw(sdp, !pull); sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); - log_incr_head(sdp); + gfs2_log_incr_head(sdp); } static void log_flush_commit(struct gfs2_sbd *sdp) { - struct list_head *head = &sdp->sd_log_flush_list; - struct gfs2_log_buf *lb; - struct buffer_head *bh; - int flushcount = 0; + DEFINE_WAIT(wait); - while (!list_empty(head)) { - lb = list_entry(head->next, struct gfs2_log_buf, lb_list); - list_del(&lb->lb_list); - bh = lb->lb_bh; - - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - if (lb->lb_real) { - while (atomic_read(&bh->b_count) != 1) /* Grrrr... */ - schedule(); - free_buffer_head(bh); - } else - brelse(bh); - kfree(lb); - flushcount++; + if (atomic_read(&sdp->sd_log_in_flight)) { + do { + prepare_to_wait(&sdp->sd_log_flush_wait, &wait, + TASK_UNINTERRUPTIBLE); + if (atomic_read(&sdp->sd_log_in_flight)) + io_schedule(); + } while(atomic_read(&sdp->sd_log_in_flight)); + finish_wait(&sdp->sd_log_flush_wait, &wait); } - /* If nothing was journaled, the header is unplanned and unwanted. */ - if (flushcount) { - log_write_header(sdp, 0, 0); - } else { - unsigned int tail; - tail = current_tail(sdp); - - gfs2_ail1_empty(sdp, 0); - if (sdp->sd_log_tail != tail) - log_pull_tail(sdp, tail); - } + log_write_header(sdp, 0, 0); } static void gfs2_ordered_write(struct gfs2_sbd *sdp) @@ -698,10 +713,16 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) INIT_LIST_HEAD(&ai->ai_ail1_list); INIT_LIST_HEAD(&ai->ai_ail2_list); - gfs2_assert_withdraw(sdp, - sdp->sd_log_num_buf + sdp->sd_log_num_databuf == - sdp->sd_log_commited_buf + - sdp->sd_log_commited_databuf); + if (sdp->sd_log_num_buf != sdp->sd_log_commited_buf) { + printk(KERN_INFO "GFS2: log buf %u %u\n", sdp->sd_log_num_buf, + sdp->sd_log_commited_buf); + gfs2_assert_withdraw(sdp, 0); + } + if (sdp->sd_log_num_databuf != sdp->sd_log_commited_databuf) { + printk(KERN_INFO "GFS2: log databuf %u %u\n", + sdp->sd_log_num_databuf, sdp->sd_log_commited_databuf); + gfs2_assert_withdraw(sdp, 0); + } gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); @@ -713,7 +734,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) lops_before_commit(sdp); gfs2_ordered_wait(sdp); - if (!list_empty(&sdp->sd_log_flush_list)) + if (sdp->sd_log_head != sdp->sd_log_flush_head) log_flush_commit(sdp); else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ gfs2_log_lock(sdp); diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 639423561b2d..dae282400627 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -52,6 +52,7 @@ int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags); int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks); +void gfs2_log_incr_head(struct gfs2_sbd *sdp); struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp); struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 342c10e12af2..6c27cea761c6 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -91,6 +91,39 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, unlock_buffer(bh); } + +static inline struct gfs2_log_descriptor *bh_log_desc(struct buffer_head *bh) +{ + return (struct gfs2_log_descriptor *)bh->b_data; +} + +static inline __be64 *bh_log_ptr(struct buffer_head *bh) +{ + struct gfs2_log_descriptor *ld = bh_log_desc(bh); + return (__force __be64 *)(ld + 1); +} + +static inline __be64 *bh_ptr_end(struct buffer_head *bh) +{ + return (__force __be64 *)(bh->b_data + bh->b_size); +} + + +static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type) +{ + struct buffer_head *bh = gfs2_log_get_buf(sdp); + struct gfs2_log_descriptor *ld = bh_log_desc(bh); + ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); + ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); + ld->ld_type = cpu_to_be32(ld_type); + ld->ld_length = 0; + ld->ld_data1 = 0; + ld->ld_data2 = 0; + memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); + return bh; +} + static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_glock *gl; @@ -181,7 +214,6 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) struct gfs2_log_descriptor *ld; struct gfs2_bufdata *bd1 = NULL, *bd2; unsigned int total; - unsigned int offset = BUF_OFFSET; unsigned int limit; unsigned int num; unsigned n; @@ -198,18 +230,12 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) if (total > limit) num = limit; gfs2_log_unlock(sdp); - bh = gfs2_log_get_buf(sdp); + bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_METADATA); gfs2_log_lock(sdp); - ld = (struct gfs2_log_descriptor *)bh->b_data; - ptr = (__be64 *)(bh->b_data + offset); - ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); - ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); - ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); - ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA); + ld = bh_log_desc(bh); + ptr = bh_log_ptr(bh); ld->ld_length = cpu_to_be32(num + 1); ld->ld_data1 = cpu_to_be32(num); - ld->ld_data2 = cpu_to_be32(0); - memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); n = 0; list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf, @@ -220,17 +246,17 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) } gfs2_log_unlock(sdp); - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + submit_bh(WRITE, bh); gfs2_log_lock(sdp); n = 0; list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf, bd_le.le_list) { + get_bh(bd2->bd_bh); gfs2_log_unlock(sdp); + lock_buffer(bd2->bd_bh); bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + submit_bh(WRITE, bh); gfs2_log_lock(sdp); if (++n >= num) break; @@ -359,17 +385,11 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) if (!sdp->sd_log_num_revoke) return; - bh = gfs2_log_get_buf(sdp); - ld = (struct gfs2_log_descriptor *)bh->b_data; - ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); - ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); - ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); - ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE); + bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE); + ld = bh_log_desc(bh); ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, sizeof(u64))); ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke); - ld->ld_data2 = cpu_to_be32(0); - memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); offset = sizeof(struct gfs2_log_descriptor); while (!list_empty(head)) { @@ -378,8 +398,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) sdp->sd_log_num_revoke--; if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + submit_bh(WRITE, bh); bh = gfs2_log_get_buf(sdp); mh = (struct gfs2_meta_header *)bh->b_data; @@ -396,8 +415,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) } gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + submit_bh(WRITE, bh); } static void revoke_lo_before_scan(struct gfs2_jdesc *jd, @@ -562,20 +580,70 @@ out: unlock_buffer(bd->bd_bh); } -static int gfs2_check_magic(struct buffer_head *bh) +static void gfs2_check_magic(struct buffer_head *bh) { - struct page *page = bh->b_page; void *kaddr; __be32 *ptr; - int rv = 0; - kaddr = kmap_atomic(page, KM_USER0); + clear_buffer_escaped(bh); + kaddr = kmap_atomic(bh->b_page, KM_USER0); ptr = kaddr + bh_offset(bh); if (*ptr == cpu_to_be32(GFS2_MAGIC)) - rv = 1; + set_buffer_escaped(bh); kunmap_atomic(kaddr, KM_USER0); +} - return rv; +static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh, + struct list_head *list, struct list_head *done, + unsigned int n) +{ + struct buffer_head *bh1; + struct gfs2_log_descriptor *ld; + struct gfs2_bufdata *bd; + __be64 *ptr; + + if (!bh) + return; + + ld = bh_log_desc(bh); + ld->ld_length = cpu_to_be32(n + 1); + ld->ld_data1 = cpu_to_be32(n); + + ptr = bh_log_ptr(bh); + + get_bh(bh); + submit_bh(WRITE, bh); + gfs2_log_lock(sdp); + while(!list_empty(list)) { + bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list); + list_move_tail(&bd->bd_le.le_list, done); + get_bh(bd->bd_bh); + while (be64_to_cpu(*ptr) != bd->bd_bh->b_blocknr) { + gfs2_log_incr_head(sdp); + ptr += 2; + } + gfs2_log_unlock(sdp); + lock_buffer(bd->bd_bh); + if (buffer_escaped(bd->bd_bh)) { + void *kaddr; + bh1 = gfs2_log_get_buf(sdp); + kaddr = kmap_atomic(bd->bd_bh->b_page, KM_USER0); + memcpy(bh1->b_data, kaddr + bh_offset(bd->bd_bh), + bh1->b_size); + kunmap_atomic(kaddr, KM_USER0); + *(__be32 *)bh1->b_data = 0; + clear_buffer_escaped(bd->bd_bh); + unlock_buffer(bd->bd_bh); + brelse(bd->bd_bh); + } else { + bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh); + } + submit_bh(WRITE, bh1); + gfs2_log_lock(sdp); + ptr += 2; + } + gfs2_log_unlock(sdp); + brelse(bh); } /** @@ -585,95 +653,37 @@ static int gfs2_check_magic(struct buffer_head *bh) static void databuf_lo_before_commit(struct gfs2_sbd *sdp) { - struct gfs2_bufdata *bd1 = NULL, *bd2; - struct buffer_head *bh = NULL,*bh1 = NULL; - struct gfs2_log_descriptor *ld; - unsigned int limit; - unsigned int total; - unsigned int num, n; - __be64 *ptr = NULL; - int magic; - - - limit = databuf_limit(sdp); + struct gfs2_bufdata *bd = NULL; + struct buffer_head *bh = NULL; + unsigned int n = 0; + __be64 *ptr = NULL, *end = NULL; + LIST_HEAD(processed); + LIST_HEAD(in_progress); gfs2_log_lock(sdp); - total = sdp->sd_log_num_databuf; - bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, - bd_le.le_list); - while(total) { - num = total; - if (num > limit) - num = limit; - - gfs2_log_unlock(sdp); - bh = gfs2_log_get_buf(sdp); - gfs2_log_lock(sdp); - - ld = (struct gfs2_log_descriptor *)bh->b_data; - ptr = (__be64 *)(bh->b_data + DATABUF_OFFSET); - ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); - ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); - ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); - ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_JDATA); - ld->ld_length = cpu_to_be32(num + 1); - ld->ld_data1 = cpu_to_be32(num); - ld->ld_data2 = cpu_to_be32(0); - memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); - - n = 0; - list_for_each_entry_continue(bd1, &sdp->sd_log_le_databuf, - bd_le.le_list) { - bh1 = bd1->bd_bh; - - magic = gfs2_check_magic(bh1); - *ptr++ = cpu_to_be64(bh1->b_blocknr); - *ptr++ = cpu_to_be64((__u64)magic); - clear_buffer_escaped(bh1); - if (unlikely(magic != 0)) - set_buffer_escaped(bh1); - if (++n >= num) - break; - } - gfs2_log_unlock(sdp); - if (bh) { - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); - bh = NULL; - ptr = NULL; - } - n = 0; - gfs2_log_lock(sdp); - list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf, - bd_le.le_list) { - if (!bd2->bd_bh) - continue; - /* copy buffer if it needs escaping */ + while (!list_empty(&sdp->sd_log_le_databuf)) { + if (ptr == end) { gfs2_log_unlock(sdp); - if (unlikely(buffer_escaped(bd2->bd_bh))) { - void *kaddr; - struct page *page = bd2->bd_bh->b_page; - bh = gfs2_log_get_buf(sdp); - kaddr = kmap_atomic(page, KM_USER0); - memcpy(bh->b_data, - kaddr + bh_offset(bd2->bd_bh), - sdp->sd_sb.sb_bsize); - kunmap_atomic(kaddr, KM_USER0); - *(__be32 *)bh->b_data = 0; - } else { - bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); - } - set_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); + gfs2_write_blocks(sdp, bh, &in_progress, &processed, n); + n = 0; + bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_JDATA); + ptr = bh_log_ptr(bh); + end = bh_ptr_end(bh) - 1; gfs2_log_lock(sdp); - if (++n >= num) - break; + continue; } - bh = NULL; - BUG_ON(total < num); - total -= num; + bd = list_entry(sdp->sd_log_le_databuf.next, struct gfs2_bufdata, bd_le.le_list); + list_move_tail(&bd->bd_le.le_list, &in_progress); + gfs2_check_magic(bd->bd_bh); + *ptr++ = cpu_to_be64(bd->bd_bh->b_blocknr); + *ptr++ = cpu_to_be64(buffer_escaped(bh) ? 1 : 0); + n++; } gfs2_log_unlock(sdp); + gfs2_write_blocks(sdp, bh, &in_progress, &processed, n); + gfs2_log_lock(sdp); + list_splice(&processed, &sdp->sd_log_le_databuf); + gfs2_log_unlock(sdp); } static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, @@ -807,10 +817,10 @@ const struct gfs2_log_operations gfs2_databuf_lops = { const struct gfs2_log_operations *gfs2_log_ops[] = { &gfs2_glock_lops, - &gfs2_buf_lops, - &gfs2_revoke_lops, - &gfs2_rg_lops, &gfs2_databuf_lops, + &gfs2_buf_lops, + &gfs2_rg_lops, + &gfs2_revoke_lops, NULL, }; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 19097bc7c81d..1d80f2d42122 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -297,6 +297,37 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, unlock_page(bh->b_page); } +void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int meta) +{ + struct gfs2_sbd *sdp = GFS2_SB(bh->b_page->mapping->host); + struct gfs2_bufdata *bd = bh->b_private; + if (test_clear_buffer_pinned(bh)) { + list_del_init(&bd->bd_le.le_list); + if (meta) { + gfs2_assert_warn(sdp, sdp->sd_log_num_buf); + sdp->sd_log_num_buf--; + tr->tr_num_buf_rm++; + } else { + gfs2_assert_warn(sdp, sdp->sd_log_num_databuf); + sdp->sd_log_num_databuf--; + tr->tr_num_databuf_rm++; + } + tr->tr_touched = 1; + brelse(bh); + } + if (bd) { + if (bd->bd_ail) { + gfs2_remove_from_ail(NULL, bd); + bh->b_private = NULL; + bd->bd_bh = NULL; + bd->bd_blkno = bh->b_blocknr; + gfs2_trans_add_revoke(sdp, bd); + } + } + clear_buffer_dirty(bh); + clear_buffer_uptodate(bh); +} + /** * gfs2_meta_wipe - make inode's buffers so they aren't dirty/pinned anymore * @ip: the inode who owns the buffers @@ -313,33 +344,11 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) while (blen) { bh = getbuf(ip->i_gl, bstart, NO_CREATE); if (bh) { - struct gfs2_bufdata *bd; - lock_buffer(bh); gfs2_log_lock(sdp); - bd = bh->b_private; - if (test_clear_buffer_pinned(bh)) { - struct gfs2_trans *tr = current->journal_info; - list_del_init(&bd->bd_le.le_list); - gfs2_assert_warn(sdp, sdp->sd_log_num_buf); - sdp->sd_log_num_buf--; - tr->tr_num_buf_rm++; - brelse(bh); - } - if (bd) { - if (bd->bd_ail) { - gfs2_remove_from_ail(NULL, bd); - bh->b_private = NULL; - bd->bd_bh = NULL; - bd->bd_blkno = bh->b_blocknr; - gfs2_trans_add_revoke(sdp, bd); - } - } - clear_buffer_dirty(bh); - clear_buffer_uptodate(bh); + gfs2_remove_from_journal(bh, current->journal_info, 1); gfs2_log_unlock(sdp); unlock_buffer(bh); - brelse(bh); } diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index fd67f07cd60e..b7048222ebb4 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -51,6 +51,9 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, int meta); +void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, + int meta); + void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen); void gfs2_meta_cache_flush(struct gfs2_inode *ip); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index dd1ea491ddcb..b7baf1831912 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -414,7 +414,8 @@ static int gfs2_prepare_write(struct file *file, struct page *page, if (ind_blocks || data_blocks) rblocks += RES_STATFS + RES_QUOTA; - error = gfs2_trans_begin(sdp, rblocks, 0); + error = gfs2_trans_begin(sdp, rblocks, + PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); if (error) goto out_trans_fail; @@ -625,10 +626,10 @@ static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh) clear_buffer_dirty(bh); bd = bh->b_private; if (bd) { - if (!list_empty(&bd->bd_le.le_list)) { - if (!buffer_pinned(bh)) - list_del_init(&bd->bd_le.le_list); - } + if (!list_empty(&bd->bd_le.le_list) && !buffer_pinned(bh)) + list_del_init(&bd->bd_le.le_list); + else + gfs2_remove_from_journal(bh, current->journal_info, 0); } bh->b_bdev = NULL; clear_buffer_mapped(bh); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 35f3dfa9bfb1..1ac9afa58c65 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -89,7 +89,8 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) INIT_LIST_HEAD(&sdp->sd_ail2_list); init_rwsem(&sdp->sd_log_flush_lock); - INIT_LIST_HEAD(&sdp->sd_log_flush_list); + atomic_set(&sdp->sd_log_in_flight, 0); + init_waitqueue_head(&sdp->sd_log_flush_wait); INIT_LIST_HEAD(&sdp->sd_revoke_list); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 2cbe5a321e89..291f0c7eaa3b 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -905,12 +905,17 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) static int setattr_size(struct inode *inode, struct iattr *attr) { struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); int error; if (attr->ia_size != ip->i_di.di_size) { - error = vmtruncate(inode, attr->ia_size); + error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); if (error) return error; + error = vmtruncate(inode, attr->ia_size); + gfs2_trans_end(sdp); + if (error) + return error; } error = gfs2_truncatei(ip, attr->ia_size); diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 4316690d86f6..950f31460e8b 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -455,12 +455,15 @@ static void gfs2_delete_inode(struct inode *inode) } error = gfs2_dinode_dealloc(ip); - /* - * Must do this before unlock to avoid trying to write back - * potentially dirty data now that inode no longer exists - * on disk. - */ + if (error) + goto out_unlock; + + error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); + if (error) + goto out_unlock; + /* Needs to be done before glock release & also in a transaction */ truncate_inode_pages(&inode->i_data, 0); + gfs2_trans_end(sdp); out_unlock: gfs2_glock_dq(&ip->i_iopen_gh); From de986e859a29097fb9211b052d86a9a2c868f6cd Mon Sep 17 00:00:00 2001 From: Wendy Cheng Date: Tue, 18 Sep 2007 09:19:13 -0400 Subject: [PATCH 0984/2804] [GFS2] Data corruption fix * GFS2 has been using i_cache array to store its indirect meta blocks. Its flush routine doesn't correctly clean up all the entries. The problem would show while multiple nodes do simultaneous writes to the same file. Upon glock exclusive lock transfer, if the file is a sparse file with large file size where the indirect meta blocks span multiple array entries with "zero" entries in between. The flush routine prematurely stops the flushing that leaves old (stale) entries around. This leads to several nasty issues, including data corruption. * Fix gfs2_get_block_noalloc checking to correctly return EIO upon unmapped buffer. Signed-off-by: Wendy Cheng Signed-off-by: Steven Whitehouse --- fs/gfs2/meta_io.c | 8 ++++---- fs/gfs2/ops_address.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 1d80f2d42122..4da423985e4f 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -374,10 +374,10 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip) for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) { bh_slot = &ip->i_cache[x]; - if (!*bh_slot) - break; - brelse(*bh_slot); - *bh_slot = NULL; + if (*bh_slot) { + brelse(*bh_slot); + *bh_slot = NULL; + } } spin_unlock(&ip->i_spin); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index b7baf1831912..4002f417dc19 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -90,7 +90,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, error = gfs2_block_map(inode, lblock, 0, bh_result); if (error) return error; - if (bh_result->b_blocknr == 0) + if (!buffer_mapped(bh_result)) return -EIO; return 0; } From 7a9f53b3c1875bef22ad4588e818bc046ef183da Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Tue, 18 Sep 2007 13:33:18 -0500 Subject: [PATCH 0985/2804] [GFS2] Alternate gfs2_iget to avoid looking up inodes being freed There is a possible deadlock between two processes on the same node, where one process is deleting an inode, and another process is looking for allocated but unused inodes to delete in order to create more space. process A does an iput() on inode X, and it's i_count drops to 0. This causes iput_final() to be called, which puts an inode into state I_FREEING at generic_delete_inode(). There no point between when iput_final() is called, and when I_FREEING is set where GFS2 could acquire any glocks. Once I_FREEING is set, no other process on that node can successfully look up that inode until the delete finishes. process B locks the the resource group for the same inode in get_local_rgrp(), which is called by gfs2_inplace_reserve_i() process A tries to lock the resource group for the inode in gfs2_dinode_dealloc(), but it's already locked by process B process B waits in find_inode for the inode to have the I_FREEING state cleared. Deadlock. This patch solves the problem by adding an alternative to gfs2_iget(), gfs2_iget_skip(), that simply skips any inodes that are in the I_FREEING state.o The alternate test function is just like the original one, except that it fails if the inode is being freed, and sets a skipped flag. The alternate set function is just like the original, except that it fails if the skipped flag is set. Only try_rgrp_unlink() calls gfs2_iget_skip() instead of gfs2_iget(). Signed-off-by: Benjamin E. Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 2 +- fs/gfs2/inode.c | 58 +++++++++++++++++++++++++++++++++++++++++--- fs/gfs2/inode.h | 3 ++- fs/gfs2/ops_export.c | 2 +- fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/rgrp.c | 2 +- 6 files changed, 60 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 08c6dd0c6713..9949bb746a52 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1502,7 +1502,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) inode = gfs2_inode_lookup(dir->i_sb, be16_to_cpu(dent->de_type), be64_to_cpu(dent->de_inum.no_addr), - be64_to_cpu(dent->de_inum.no_formal_ino)); + be64_to_cpu(dent->de_inum.no_formal_ino), 0); brelse(bh); return inode; } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 013f00b90cc2..5f6dc32946cd 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -77,6 +77,49 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) return iget5_locked(sb, hash, iget_test, iget_set, &no_addr); } +struct gfs2_skip_data { + u64 no_addr; + int skipped; +}; + +static int iget_skip_test(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; + + if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){ + if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){ + data->skipped = 1; + return 0; + } + return 1; + } + return 0; +} + +static int iget_skip_set(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; + + if (data->skipped) + return 1; + inode->i_ino = (unsigned long)(data->no_addr); + ip->i_no_addr = data->no_addr; + return 0; +} + +static struct inode *gfs2_iget_skip(struct super_block *sb, + u64 no_addr) +{ + struct gfs2_skip_data data; + unsigned long hash = (unsigned long)no_addr; + + data.no_addr = no_addr; + data.skipped = 0; + return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data); +} + /** * GFS2 lookup code fills in vfs inode contents based on info obtained * from directory entry inside gfs2_inode_lookup(). This has caused issues @@ -112,6 +155,7 @@ void gfs2_set_iop(struct inode *inode) * @sb: The super block * @no_addr: The inode number * @type: The type of the inode + * @skip_freeing: set this not return an inode if it is currently being freed. * * Returns: A VFS inode, or an error */ @@ -119,13 +163,19 @@ void gfs2_set_iop(struct inode *inode) struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, u64 no_addr, - u64 no_formal_ino) + u64 no_formal_ino, int skip_freeing) { - struct inode *inode = gfs2_iget(sb, no_addr); - struct gfs2_inode *ip = GFS2_I(inode); + struct inode *inode; + struct gfs2_inode *ip; struct gfs2_glock *io_gl; int error; + if (skip_freeing) + inode = gfs2_iget_skip(sb, no_addr); + else + inode = gfs2_iget(sb, no_addr); + ip = GFS2_I(inode); + if (!inode) return ERR_PTR(-ENOBUFS); @@ -949,7 +999,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, - inum.no_formal_ino); + inum.no_formal_ino, 0); if (IS_ERR(inode)) goto fail_gunlock2; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 4517ac82c01c..351ac87ab384 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -49,7 +49,8 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip, void gfs2_inode_attr_in(struct gfs2_inode *ip); void gfs2_set_iop(struct inode *inode); struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, - u64 no_addr, u64 no_formal_ino); + u64 no_addr, u64 no_formal_ino, + int skip_freeing); struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); int gfs2_inode_refresh(struct gfs2_inode *ip); diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index b8312edee0e4..e2d1347796a9 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -237,7 +237,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj) inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, - 0); + 0, 0); if (!inode) goto fail; if (IS_ERR(inode)) { diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 1ac9afa58c65..17de58e83d92 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -230,7 +230,7 @@ fail: static inline struct inode *gfs2_lookup_root(struct super_block *sb, u64 no_addr) { - return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0); + return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0); } static int init_sb(struct gfs2_sbd *sdp, int silent, int undo) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 2d7f7ea0c9a8..708c287e1d0e 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -884,7 +884,7 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) continue; *last_unlinked = no_addr; inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, - no_addr, -1); + no_addr, -1, 1); if (!IS_ERR(inode)) return inode; } From 891ba6d4a5f9e6302bb6542592d73feb4d0d3687 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 20 Sep 2007 15:26:33 +0100 Subject: [PATCH 0986/2804] [GFS2] Don't try to remove buffers that don't exist Signed-off-by: Steven Whitehouse --- fs/gfs2/ops_address.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 4002f417dc19..873a511ef2be 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -747,7 +747,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) struct gfs2_bufdata *bd; if (!page_has_buffers(page)) - goto out; + return 0; gfs2_log_lock(sdp); head = bh = page_buffers(page); @@ -787,7 +787,6 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) bh = bh->b_this_page; } while (bh != head); -out: return try_to_free_buffers(page); cannot_release: gfs2_log_unlock(sdp); From 5a60c532c9224babc172fafccc9e2fec6937af6f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 26 Sep 2007 09:39:31 +0100 Subject: [PATCH 0987/2804] [GFS2] Get superblock a different way The mapping may be NULL by the time the I/O has completed, so we now get the superblock by a different route (via the bd and glock) to avoid this problem. Signed-off-by: Steven Whitehouse Cc: Wendy Cheng --- fs/gfs2/log.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index ee704676b2f1..7df702473252 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -513,7 +513,8 @@ struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate) { struct buffer_head *real_bh = bh->b_private; - struct gfs2_sbd *sdp = GFS2_SB(real_bh->b_page->mapping->host); + struct gfs2_bufdata *bd = real_bh->b_private; + struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; end_buffer_write_sync(bh, uptodate); free_buffer_head(bh); From b434eda6fda5bcdcc2dd918e5ffbf7184f2d4e17 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Mon, 1 Oct 2007 15:28:42 +0100 Subject: [PATCH 0988/2804] [DLM] don't overwrite castparam if it's NULL If the castaddr passed to the userland API is NULL then don't overwrite the existing castparam. This allows a different thread to cancel a lock request and the CANCEL AST gets delivered to the original thread. bz#306391 (for RHEL4) refers. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse --- fs/dlm/lock.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 2082daf083d8..031229f144fa 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -4429,7 +4429,8 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, if (lvb_in && ua->lksb.sb_lvbptr) memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN); - ua->castparam = ua_tmp->castparam; + if (ua_tmp->castparam) + ua->castparam = ua_tmp->castparam; ua->user_lksb = ua_tmp->user_lksb; error = set_unlock_args(flags, ua, &args); @@ -4474,7 +4475,8 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, goto out; ua = (struct dlm_user_args *)lkb->lkb_astparam; - ua->castparam = ua_tmp->castparam; + if (ua_tmp->castparam) + ua->castparam = ua_tmp->castparam; ua->user_lksb = ua_tmp->user_lksb; error = set_unlock_args(flags, ua, &args); From c36258b5925e6cf6bf72904635100593573bfcff Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 27 Sep 2007 15:53:38 -0500 Subject: [PATCH 0989/2804] [DLM] block dlm_recv in recovery transition Introduce a per-lockspace rwsem that's held in read mode by dlm_recv threads while working in the dlm. This allows dlm_recv activity to be suspended when the lockspace transitions to, from and between recovery cycles. The specific bug prompting this change is one where an in-progress recovery cycle is aborted by a new recovery cycle. While dlm_recv was processing a recovery message, the recovery cycle was aborted and dlm_recoverd began cleaning up. dlm_recv decremented recover_locks_count on an rsb after dlm_recoverd had reset it to zero. This is fixed by suspending dlm_recv (taking write lock on the rwsem) before aborting the current recovery. The transitions to/from normal and recovery modes are simplified by using this new ability to block dlm_recv. The switch from normal to recovery mode means dlm_recv goes from processing locking messages, to saving them for later, and vice versa. Races are avoided by blocking dlm_recv when setting the flag that switches between modes. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse --- fs/dlm/dlm_internal.h | 1 + fs/dlm/lock.c | 136 +++++++++++++++++++++++++----------------- fs/dlm/lock.h | 3 +- fs/dlm/lockspace.c | 1 + fs/dlm/member.c | 41 ++++++++----- fs/dlm/midcomms.c | 17 +----- fs/dlm/rcom.c | 36 +++-------- fs/dlm/rcom.h | 5 +- fs/dlm/recoverd.c | 11 +++- fs/dlm/requestqueue.c | 58 ++++++++---------- fs/dlm/requestqueue.h | 4 +- 11 files changed, 161 insertions(+), 152 deletions(-) diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 74901e981e10..d2fc2384c3be 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -491,6 +491,7 @@ struct dlm_ls { uint64_t ls_recover_seq; struct dlm_recover *ls_recover_args; struct rw_semaphore ls_in_recovery; /* block local requests */ + struct rw_semaphore ls_recv_active; /* block dlm_recv */ struct list_head ls_requestqueue;/* queue remote requests */ struct mutex ls_requestqueue_mutex; char *ls_recover_buf; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 031229f144fa..3915b8e14146 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3638,55 +3638,8 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms) dlm_put_lkb(lkb); } -int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) +static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms) { - struct dlm_message *ms = (struct dlm_message *) hd; - struct dlm_ls *ls; - int error = 0; - - if (!recovery) - dlm_message_in(ms); - - ls = dlm_find_lockspace_global(hd->h_lockspace); - if (!ls) { - log_print("drop message %d from %d for unknown lockspace %d", - ms->m_type, nodeid, hd->h_lockspace); - return -EINVAL; - } - - /* recovery may have just ended leaving a bunch of backed-up requests - in the requestqueue; wait while dlm_recoverd clears them */ - - if (!recovery) - dlm_wait_requestqueue(ls); - - /* recovery may have just started while there were a bunch of - in-flight requests -- save them in requestqueue to be processed - after recovery. we can't let dlm_recvd block on the recovery - lock. if dlm_recoverd is calling this function to clear the - requestqueue, it needs to be interrupted (-EINTR) if another - recovery operation is starting. */ - - while (1) { - if (dlm_locking_stopped(ls)) { - if (recovery) { - error = -EINTR; - goto out; - } - error = dlm_add_requestqueue(ls, nodeid, hd); - if (error == -EAGAIN) - continue; - else { - error = -EINTR; - goto out; - } - } - - if (dlm_lock_recovery_try(ls)) - break; - schedule(); - } - switch (ms->m_type) { /* messages sent to a master node */ @@ -3761,17 +3714,90 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) log_error(ls, "unknown message type %d", ms->m_type); } - dlm_unlock_recovery(ls); - out: - dlm_put_lockspace(ls); dlm_astd_wake(); - return error; } +/* If the lockspace is in recovery mode (locking stopped), then normal + messages are saved on the requestqueue for processing after recovery is + done. When not in recovery mode, we wait for dlm_recoverd to drain saved + messages off the requestqueue before we process new ones. This occurs right + after recovery completes when we transition from saving all messages on + requestqueue, to processing all the saved messages, to processing new + messages as they arrive. */ -/* - * Recovery related - */ +static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms, + int nodeid) +{ + if (dlm_locking_stopped(ls)) { + dlm_add_requestqueue(ls, nodeid, (struct dlm_header *) ms); + } else { + dlm_wait_requestqueue(ls); + _receive_message(ls, ms); + } +} + +/* This is called by dlm_recoverd to process messages that were saved on + the requestqueue. */ + +void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms) +{ + _receive_message(ls, ms); +} + +/* This is called by the midcomms layer when something is received for + the lockspace. It could be either a MSG (normal message sent as part of + standard locking activity) or an RCOM (recovery message sent as part of + lockspace recovery). */ + +void dlm_receive_buffer(struct dlm_header *hd, int nodeid) +{ + struct dlm_message *ms = (struct dlm_message *) hd; + struct dlm_rcom *rc = (struct dlm_rcom *) hd; + struct dlm_ls *ls; + int type = 0; + + switch (hd->h_cmd) { + case DLM_MSG: + dlm_message_in(ms); + type = ms->m_type; + break; + case DLM_RCOM: + dlm_rcom_in(rc); + type = rc->rc_type; + break; + default: + log_print("invalid h_cmd %d from %u", hd->h_cmd, nodeid); + return; + } + + if (hd->h_nodeid != nodeid) { + log_print("invalid h_nodeid %d from %d lockspace %x", + hd->h_nodeid, nodeid, hd->h_lockspace); + return; + } + + ls = dlm_find_lockspace_global(hd->h_lockspace); + if (!ls) { + log_print("invalid h_lockspace %x from %d cmd %d type %d", + hd->h_lockspace, nodeid, hd->h_cmd, type); + + if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS) + dlm_send_ls_not_ready(nodeid, rc); + return; + } + + /* this rwsem allows dlm_ls_stop() to wait for all dlm_recv threads to + be inactive (in this ls) before transitioning to recovery mode */ + + down_read(&ls->ls_recv_active); + if (hd->h_cmd == DLM_MSG) + dlm_receive_message(ls, ms, nodeid); + else + dlm_receive_rcom(ls, rc, nodeid); + up_read(&ls->ls_recv_active); + + dlm_put_lockspace(ls); +} static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb) { diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 1720313c22df..ada04680a1e5 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -16,7 +16,8 @@ void dlm_print_rsb(struct dlm_rsb *r); void dlm_dump_rsb(struct dlm_rsb *r); void dlm_print_lkb(struct dlm_lkb *lkb); -int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery); +void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms); +void dlm_receive_buffer(struct dlm_header *hd, int nodeid); int dlm_modes_compat(int mode1, int mode2); int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen, unsigned int flags, struct dlm_rsb **r_ret); diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 1dc72105ab12..628eaa669e68 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -519,6 +519,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ls->ls_recover_seq = 0; ls->ls_recover_args = NULL; init_rwsem(&ls->ls_in_recovery); + init_rwsem(&ls->ls_recv_active); INIT_LIST_HEAD(&ls->ls_requestqueue); mutex_init(&ls->ls_requestqueue_mutex); mutex_init(&ls->ls_clear_proc_locks); diff --git a/fs/dlm/member.c b/fs/dlm/member.c index d09977528f69..e9cdcab306e2 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -18,10 +18,6 @@ #include "rcom.h" #include "config.h" -/* - * Following called by dlm_recoverd thread - */ - static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new) { struct dlm_member *memb = NULL; @@ -250,18 +246,30 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) return error; } -/* - * Following called from lockspace.c - */ +/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before + dlm_ls_start() is called on any of them to start the new recovery. */ int dlm_ls_stop(struct dlm_ls *ls) { int new; /* - * A stop cancels any recovery that's in progress (see RECOVERY_STOP, - * dlm_recovery_stopped()) and prevents any new locks from being - * processed (see RUNNING, dlm_locking_stopped()). + * Prevent dlm_recv from being in the middle of something when we do + * the stop. This includes ensuring dlm_recv isn't processing a + * recovery message (rcom), while dlm_recoverd is aborting and + * resetting things from an in-progress recovery. i.e. we want + * dlm_recoverd to abort its recovery without worrying about dlm_recv + * processing an rcom at the same time. Stopping dlm_recv also makes + * it easy for dlm_receive_message() to check locking stopped and add a + * message to the requestqueue without races. + */ + + down_write(&ls->ls_recv_active); + + /* + * Abort any recovery that's in progress (see RECOVERY_STOP, + * dlm_recovery_stopped()) and tell any other threads running in the + * dlm to quit any processing (see RUNNING, dlm_locking_stopped()). */ spin_lock(&ls->ls_recover_lock); @@ -270,9 +278,15 @@ int dlm_ls_stop(struct dlm_ls *ls) ls->ls_recover_seq++; spin_unlock(&ls->ls_recover_lock); + /* + * Let dlm_recv run again, now any normal messages will be saved on the + * requestqueue for later. + */ + + up_write(&ls->ls_recv_active); + /* * This in_recovery lock does two things: - * * 1) Keeps this function from returning until all threads are out * of locking routines and locking is truely stopped. * 2) Keeps any new requests from being processed until it's unlocked @@ -284,9 +298,8 @@ int dlm_ls_stop(struct dlm_ls *ls) /* * The recoverd suspend/resume makes sure that dlm_recoverd (if - * running) has noticed the clearing of RUNNING above and quit - * processing the previous recovery. This will be true for all nodes - * before any nodes start the new recovery. + * running) has noticed RECOVERY_STOP above and quit processing the + * previous recovery. */ dlm_recoverd_suspend(ls); diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index a5126e0c68a6..f8c69dda16a0 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -27,7 +27,6 @@ #include "dlm_internal.h" #include "lowcomms.h" #include "config.h" -#include "rcom.h" #include "lock.h" #include "midcomms.h" @@ -117,19 +116,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, offset &= (limit - 1); len -= msglen; - switch (msg->h_cmd) { - case DLM_MSG: - dlm_receive_message(msg, nodeid, 0); - break; - - case DLM_RCOM: - dlm_receive_rcom(msg, nodeid); - break; - - default: - log_print("unknown msg type %x from %u: %u %u %u %u", - msg->h_cmd, nodeid, msglen, len, offset, ret); - } + dlm_receive_buffer(msg, nodeid); } if (msg != (struct dlm_header *) __tmp) diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 188b91c027e4..ae2fd97fa4ad 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -386,7 +386,10 @@ static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) dlm_recover_process_copy(ls, rc_in); } -static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) +/* If the lockspace doesn't exist then still send a status message + back; it's possible that it just doesn't have its global_id yet. */ + +int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) { struct dlm_rcom *rc; struct rcom_config *rf; @@ -446,28 +449,11 @@ static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc) return rv; } -/* Called by dlm_recvd; corresponds to dlm_receive_message() but special +/* Called by dlm_recv; corresponds to dlm_receive_message() but special recovery-only comms are sent through here. */ -void dlm_receive_rcom(struct dlm_header *hd, int nodeid) +void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid) { - struct dlm_rcom *rc = (struct dlm_rcom *) hd; - struct dlm_ls *ls; - - dlm_rcom_in(rc); - - /* If the lockspace doesn't exist then still send a status message - back; it's possible that it just doesn't have its global_id yet. */ - - ls = dlm_find_lockspace_global(hd->h_lockspace); - if (!ls) { - log_print("lockspace %x from %d type %x not found", - hd->h_lockspace, nodeid, rc->rc_type); - if (rc->rc_type == DLM_RCOM_STATUS) - send_ls_not_ready(nodeid, rc); - return; - } - if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) { log_debug(ls, "ignoring recovery message %x from %d", rc->rc_type, nodeid); @@ -477,12 +463,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid) if (is_old_reply(ls, rc)) goto out; - if (nodeid != rc->rc_header.h_nodeid) { - log_error(ls, "bad rcom nodeid %d from %d", - rc->rc_header.h_nodeid, nodeid); - goto out; - } - switch (rc->rc_type) { case DLM_RCOM_STATUS: receive_rcom_status(ls, rc); @@ -520,6 +500,6 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid) DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type);); } out: - dlm_put_lockspace(ls); + return; } diff --git a/fs/dlm/rcom.h b/fs/dlm/rcom.h index d7984321ff41..b09abd29ba38 100644 --- a/fs/dlm/rcom.h +++ b/fs/dlm/rcom.h @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -18,7 +18,8 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid); int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len); int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid); int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb); -void dlm_receive_rcom(struct dlm_header *hd, int nodeid); +void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid); +int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in); #endif diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 66575997861c..4b89e20eebe7 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c @@ -24,19 +24,28 @@ /* If the start for which we're re-enabling locking (seq) has been superseded - by a newer stop (ls_recover_seq), we need to leave locking disabled. */ + by a newer stop (ls_recover_seq), we need to leave locking disabled. + + We suspend dlm_recv threads here to avoid the race where dlm_recv a) sees + locking stopped and b) adds a message to the requestqueue, but dlm_recoverd + enables locking and clears the requestqueue between a and b. */ static int enable_locking(struct dlm_ls *ls, uint64_t seq) { int error = -EINTR; + down_write(&ls->ls_recv_active); + spin_lock(&ls->ls_recover_lock); if (ls->ls_recover_seq == seq) { set_bit(LSFL_RUNNING, &ls->ls_flags); + /* unblocks processes waiting to enter the dlm */ up_write(&ls->ls_in_recovery); error = 0; } spin_unlock(&ls->ls_recover_lock); + + up_write(&ls->ls_recv_active); return error; } diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c index 65008d79c96d..0de04f17ccea 100644 --- a/fs/dlm/requestqueue.c +++ b/fs/dlm/requestqueue.c @@ -1,7 +1,7 @@ /****************************************************************************** ******************************************************************************* ** -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -20,7 +20,7 @@ struct rq_entry { struct list_head list; int nodeid; - char request[1]; + char request[0]; }; /* @@ -30,42 +30,39 @@ struct rq_entry { * lockspace is enabled on some while still suspended on others. */ -int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) +void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) { struct rq_entry *e; int length = hd->h_length; - int rv = 0; e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL); if (!e) { - log_print("dlm_add_requestqueue: out of memory\n"); - return 0; + log_print("dlm_add_requestqueue: out of memory len %d", length); + return; } e->nodeid = nodeid; memcpy(e->request, hd, length); - /* We need to check dlm_locking_stopped() after taking the mutex to - avoid a race where dlm_recoverd enables locking and runs - process_requestqueue between our earlier dlm_locking_stopped check - and this addition to the requestqueue. */ - mutex_lock(&ls->ls_requestqueue_mutex); - if (dlm_locking_stopped(ls)) - list_add_tail(&e->list, &ls->ls_requestqueue); - else { - log_debug(ls, "dlm_add_requestqueue skip from %d", nodeid); - kfree(e); - rv = -EAGAIN; - } + list_add_tail(&e->list, &ls->ls_requestqueue); mutex_unlock(&ls->ls_requestqueue_mutex); - return rv; } +/* + * Called by dlm_recoverd to process normal messages saved while recovery was + * happening. Normal locking has been enabled before this is called. dlm_recv + * upon receiving a message, will wait for all saved messages to be drained + * here before processing the message it got. If a new dlm_ls_stop() arrives + * while we're processing these saved messages, it may block trying to suspend + * dlm_recv if dlm_recv is waiting for us in dlm_wait_requestqueue. In that + * case, we don't abort since locking_stopped is still 0. If dlm_recv is not + * waiting for us, then this processing may be aborted due to locking_stopped. + */ + int dlm_process_requestqueue(struct dlm_ls *ls) { struct rq_entry *e; - struct dlm_header *hd; int error = 0; mutex_lock(&ls->ls_requestqueue_mutex); @@ -79,14 +76,7 @@ int dlm_process_requestqueue(struct dlm_ls *ls) e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list); mutex_unlock(&ls->ls_requestqueue_mutex); - hd = (struct dlm_header *) e->request; - error = dlm_receive_message(hd, e->nodeid, 1); - - if (error == -EINTR) { - /* entry is left on requestqueue */ - log_debug(ls, "process_requestqueue abort eintr"); - break; - } + dlm_receive_message_saved(ls, (struct dlm_message *)e->request); mutex_lock(&ls->ls_requestqueue_mutex); list_del(&e->list); @@ -106,10 +96,12 @@ int dlm_process_requestqueue(struct dlm_ls *ls) /* * After recovery is done, locking is resumed and dlm_recoverd takes all the - * saved requests and processes them as they would have been by dlm_recvd. At - * the same time, dlm_recvd will start receiving new requests from remote - * nodes. We want to delay dlm_recvd processing new requests until - * dlm_recoverd has finished processing the old saved requests. + * saved requests and processes them as they would have been by dlm_recv. At + * the same time, dlm_recv will start receiving new requests from remote nodes. + * We want to delay dlm_recv processing new requests until dlm_recoverd has + * finished processing the old saved requests. We don't check for locking + * stopped here because dlm_ls_stop won't stop locking until it's suspended us + * (dlm_recv). */ void dlm_wait_requestqueue(struct dlm_ls *ls) @@ -118,8 +110,6 @@ void dlm_wait_requestqueue(struct dlm_ls *ls) mutex_lock(&ls->ls_requestqueue_mutex); if (list_empty(&ls->ls_requestqueue)) break; - if (dlm_locking_stopped(ls)) - break; mutex_unlock(&ls->ls_requestqueue_mutex); schedule(); } diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h index 6a53ea03335d..aba34fc05ee4 100644 --- a/fs/dlm/requestqueue.h +++ b/fs/dlm/requestqueue.h @@ -1,7 +1,7 @@ /****************************************************************************** ******************************************************************************* ** -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -13,7 +13,7 @@ #ifndef __REQUESTQUEUE_DOT_H__ #define __REQUESTQUEUE_DOT_H__ -int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd); +void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd); int dlm_process_requestqueue(struct dlm_ls *ls); void dlm_wait_requestqueue(struct dlm_ls *ls); void dlm_purge_requestqueue(struct dlm_ls *ls); From b9a22794f2c186b5722eac94b6735e797d976027 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [PATCH 0990/2804] [POWERPC] XilinxFB: sparse fixes Signed-off-by: Grant Likely --- drivers/video/xilinxfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e6e12be845a9..dec602c23075 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -118,7 +118,7 @@ struct xilinxfb_drvdata { u32 regs_phys; /* phys. address of the control registers */ u32 __iomem *regs; /* virt. address of the control registers */ - unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */ + void *fb_virt; /* virt. address of the frame buffer */ dma_addr_t fb_phys; /* phys. address of the frame buffer */ u32 reg_ctrl_default; @@ -246,7 +246,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Clear (turn to black) the framebuffer */ - memset_io(drvdata->fb_virt, 0, FB_SIZE); + memset_io((void __iomem *)drvdata->fb_virt, 0, FB_SIZE); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); @@ -259,7 +259,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Fill struct fb_info */ drvdata->info.device = dev; - drvdata->info.screen_base = drvdata->fb_virt; + drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt; drvdata->info.fbops = &xilinxfb_ops; drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; From f210d43ce1a41ba56640bbd8d8bfe817dd2b1297 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 3 Oct 2007 23:24:52 -0600 Subject: [PATCH 0991/2804] [POWERPC] Virtex: Fix URL for Xilinx Virtex support in MAINTAINERS Change URL in MAINTAINERS to a more relevant one. Signed-off-by: Grant Likely --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d47367f68406..4dbfa738b7ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2306,7 +2306,7 @@ S: Maintained LINUX FOR POWERPC EMBEDDED XILINX VIRTEX P: Grant Likely M: grant.likely@secretlab.ca -W: http://www.secretlab.ca/ +W: http://wiki.secretlab.ca/index.php/Linux_on_Xilinx_Virtex L: linuxppc-dev@ozlabs.org S: Maintained From 4c3d514d7e5b394d1df76201aada8956c9605882 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 15:44:51 -0600 Subject: [PATCH 0992/2804] [POWERPC] Don't build arch/powerpc/sysdev/dcr.c for ARCH=ppc kernels dcr.c is an arch/powerpc only thing. Compiling ppc405 arch/ppc kernels throws warnings without this change. Signed-off-by: Grant Likely --- arch/powerpc/sysdev/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 52e93bca10ca..1a6f5641ebc8 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -6,7 +6,6 @@ mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) obj-$(CONFIG_PPC_MPC106) += grackle.o -obj-$(CONFIG_PPC_DCR) += dcr.o obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o obj-$(CONFIG_PPC_PMI) += pmi.o obj-$(CONFIG_U3_DART) += dart_iommu.o @@ -33,6 +32,7 @@ endif ifeq ($(ARCH),powerpc) obj-$(CONFIG_CPM) += cpm_common.o obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o +obj-$(CONFIG_PPC_DCR) += dcr.o obj-$(CONFIG_8xx) += mpc8xx_pic.o commproc.o obj-$(CONFIG_UCODE_PATCH) += micropatch.o endif From 17c5c2093624e81acda16fb737e4679750addd7a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 15:44:54 -0600 Subject: [PATCH 0993/2804] [POWERPC] Uartlite: bootwrapper bug fix, getc loops forever Fixes inverted logic in uartlite_getc Signed-off-by: Grant Likely --- arch/powerpc/boot/uartlite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/uartlite.c b/arch/powerpc/boot/uartlite.c index 38a470b329e3..46bed69b4169 100644 --- a/arch/powerpc/boot/uartlite.c +++ b/arch/powerpc/boot/uartlite.c @@ -45,8 +45,8 @@ static void uartlite_putc(unsigned char c) static unsigned char uartlite_getc(void) { - u32 reg = ULITE_STATUS_RXVALID; - while (reg & ULITE_STATUS_RXVALID) /* spin on RXVALID bit */ + u32 reg = 0; + while (!(reg & ULITE_STATUS_RXVALID)) /* spin waiting for RXVALID bit */ reg = in_be32(reg_base + ULITE_STATUS); return in_be32(reg_base + ULITE_RX); } From aa2091b5403a9149bdb1329cc0575d8fa9c39633 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 9 Oct 2007 14:45:26 -0600 Subject: [PATCH 0994/2804] [POWERPC] MPC52xx: Drop show_cpuinfo platform hooks from Lite5200 This hook doesn't really add any new information. Signed-off-by: Grant Likely Signed-off-by: Sylvain Munaut --- arch/powerpc/platforms/52xx/lite5200.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index e11d27f9c4f0..08b9f210490f 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -150,20 +150,6 @@ static void __init lite5200_setup_arch(void) } -static void lite5200_show_cpuinfo(struct seq_file *m) -{ - struct device_node* np = of_find_all_nodes(NULL); - const char *model = NULL; - - if (np) - model = of_get_property(np, "model", NULL); - - seq_printf(m, "vendor\t\t: Freescale Semiconductor\n"); - seq_printf(m, "machine\t\t: %s\n", model ? model : "unknown"); - - of_node_put(np); -} - /* * Called very early, MMU is off, device-tree isn't unflattened */ @@ -187,6 +173,5 @@ define_machine(lite5200) { .init = mpc52xx_declare_of_platform_devices, .init_IRQ = mpc52xx_init_irq, .get_irq = mpc52xx_get_irq, - .show_cpuinfo = lite5200_show_cpuinfo, .calibrate_decr = generic_calibrate_decr, }; From 9fe2e7969d5e5af7dbd2086f2e18f4ebc585490d Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 10 Oct 2007 09:52:00 -0600 Subject: [PATCH 0995/2804] [POWERPC] MPC52xx: Trim includes on mpc5200 platform support code Drop unnecessary includes for MPC5200 based boards Signed-off-by: Grant Likely Signed-off-by: Sylvain Munaut --- arch/powerpc/platforms/52xx/efika.c | 19 +----------------- arch/powerpc/platforms/52xx/lite5200.c | 21 +------------------- arch/powerpc/platforms/52xx/mpc52xx_common.c | 3 +-- arch/powerpc/platforms/52xx/mpc52xx_pic.c | 11 +--------- 4 files changed, 4 insertions(+), 50 deletions(-) diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 4263158b3274..6fc17faf74b9 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -9,33 +9,16 @@ * kind, whether express or implied. */ -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include #include - -#include -#include -#include -#include -#include +#include #include #include #include #include -#include -#include #include - #define EFIKA_PLATFORM_NAME "Efika" diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 08b9f210490f..7fa0ec8d91cc 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -15,32 +15,13 @@ #undef DEBUG -#include -#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include +#include #include #include #include -#include -#include #include -#include -#include -#include - #include /* ************************************************************************ diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 2dd415ff55a9..3eeb6c62e0ff 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -13,10 +13,9 @@ #undef DEBUG #include - +#include #include #include -#include #include diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 0f4ca8a2b777..61100f270c68 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -18,18 +18,9 @@ #undef DEBUG -#include -#include -#include -#include -#include #include -#include - +#include #include -#include -#include -#include #include #include #include "mpc52xx_pic.h" From 4de3b992a6880828943f1b5849e1e7153fe4185c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 9 Oct 2007 14:45:28 -0600 Subject: [PATCH 0996/2804] [POWERPC] MPC5200: Don't make firmware fixups into common code The Lite5200 u-boot image doesn't entirely configure the processor correctly and so Linux needs to fixup the cpu setup in setup_arch. Fixing the CPU setup is good, but making it into common code is not a good idea. New board ports should be encouraged not to take the lead of the lite5200 and instead get their firmware to setup the CPU the right way. Signed-off-by: Grant Likely Signed-off-by: Sylvain Munaut --- arch/powerpc/platforms/52xx/lite5200.c | 59 ++++++++++++++++---- arch/powerpc/platforms/52xx/mpc52xx_common.c | 35 ++++-------- include/asm-powerpc/mpc52xx.h | 2 +- 3 files changed, 62 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 7fa0ec8d91cc..0caa3d955c3b 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -30,19 +30,56 @@ * */ +/* + * Fix clock configuration. + * + * Firmware is supposed to be responsible for this. If you are creating a + * new board port, do *NOT* duplicate this code. Fix your boot firmware + * to set it correctly in the first place + */ static void __init -lite5200_setup_cpu(void) +lite5200_fix_clock_config(void) +{ + struct mpc52xx_cdm __iomem *cdm; + + /* Map zones */ + cdm = mpc52xx_find_and_map("mpc5200-cdm"); + if (!cdm) { + printk(KERN_ERR "%s() failed; expect abnormal behaviour\n", + __FUNCTION__); + return; + } + + /* Use internal 48 Mhz */ + out_8(&cdm->ext_48mhz_en, 0x00); + out_8(&cdm->fd_enable, 0x01); + if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ + out_be16(&cdm->fd_counters, 0x0001); + else + out_be16(&cdm->fd_counters, 0x5555); + + /* Unmap the regs */ + iounmap(cdm); +} + +/* + * Fix setting of port_config register. + * + * Firmware is supposed to be responsible for this. If you are creating a + * new board port, do *NOT* duplicate this code. Fix your boot firmware + * to set it correctly in the first place + */ +static void __init +lite5200_fix_port_config(void) { struct mpc52xx_gpio __iomem *gpio; u32 port_config; - /* Map zones */ gpio = mpc52xx_find_and_map("mpc5200-gpio"); if (!gpio) { - printk(KERN_ERR __FILE__ ": " - "Error while mapping GPIO register for port config. " - "Expect some abnormal behavior\n"); - goto error; + printk(KERN_ERR "%s() failed. expect abnormal behavior\n", + __FUNCTION__); + return; } /* Set port config */ @@ -61,7 +98,6 @@ lite5200_setup_cpu(void) out_be32(&gpio->port_config, port_config); /* Unmap zone */ -error: iounmap(gpio); } @@ -100,9 +136,12 @@ static void __init lite5200_setup_arch(void) if (ppc_md.progress) ppc_md.progress("lite5200_setup_arch()", 0); - /* CPU & Port mux setup */ - mpc52xx_setup_cpu(); /* Generic */ - lite5200_setup_cpu(); /* Platorm specific */ + /* Fix things that firmware should have done. */ + lite5200_fix_clock_config(); + lite5200_fix_port_config(); + + /* Some mpc5200 & mpc5200b related configuration */ + mpc5200_setup_xlb_arbiter(); #ifdef CONFIG_PM mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 3eeb6c62e0ff..3bc201e07e6b 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -75,44 +75,33 @@ mpc52xx_find_ipb_freq(struct device_node *node) EXPORT_SYMBOL(mpc52xx_find_ipb_freq); +/* + * Configure the XLB arbiter settings to match what Linux expects. + */ void __init -mpc52xx_setup_cpu(void) +mpc5200_setup_xlb_arbiter(void) { - struct mpc52xx_cdm __iomem *cdm; struct mpc52xx_xlb __iomem *xlb; - /* Map zones */ - cdm = mpc52xx_find_and_map("mpc5200-cdm"); xlb = mpc52xx_find_and_map("mpc5200-xlb"); - - if (!cdm || !xlb) { + if (!xlb) { printk(KERN_ERR __FILE__ ": " - "Error while mapping CDM/XLB during mpc52xx_setup_cpu. " + "Error mapping XLB in mpc52xx_setup_cpu(). " "Expect some abnormal behavior\n"); - goto unmap_regs; + return; } - /* Use internal 48 Mhz */ - out_8(&cdm->ext_48mhz_en, 0x00); - out_8(&cdm->fd_enable, 0x01); - if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ - out_be16(&cdm->fd_counters, 0x0001); - else - out_be16(&cdm->fd_counters, 0x5555); - /* Configure the XLB Arbiter priorities */ out_be32(&xlb->master_pri_enable, 0xff); out_be32(&xlb->master_priority, 0x11111111); - /* Disable XLB pipelining */ - /* (cfr errate 292. We could do this only just before ATA PIO - transaction and re-enable it afterwards ...) */ + /* Disable XLB pipelining + * (cfr errate 292. We could do this only just before ATA PIO + * transaction and re-enable it afterwards ...) + */ out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS); - /* Unmap zones */ -unmap_regs: - if (cdm) iounmap(cdm); - if (xlb) iounmap(xlb); + iounmap(xlb); } void __init diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h index 1a3dbb743a3f..24751df791ac 100644 --- a/include/asm-powerpc/mpc52xx.h +++ b/include/asm-powerpc/mpc52xx.h @@ -243,7 +243,7 @@ struct mpc52xx_cdm { extern void __iomem * mpc52xx_find_and_map(const char *); extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node); -extern void mpc52xx_setup_cpu(void); +extern void mpc5200_setup_xlb_arbiter(void); extern void mpc52xx_declare_of_platform_devices(void); extern void mpc52xx_init_irq(void); From e1eea9fa00da50ed3dfb64ce669e9ae0b70c0629 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 9 Oct 2007 14:45:26 -0600 Subject: [PATCH 0997/2804] [POWERPC] Add co-maintainer for PowerPC MPC52xx platform Added at the request of Sylvain Munaut. Signed-off-by: Grant Likely Signed-off-by: Sylvain Munaut --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d47367f68406..146d0c6291d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2288,6 +2288,8 @@ S: Maintained LINUX FOR POWERPC EMBEDDED MPC52XX P: Sylvain Munaut M: tnt@246tNt.com +P: Grant Likely +M: grant.likely@secretlab.ca W: http://www.246tNt.com/mpc52xx/ W: http://www.penguinppc.org/ L: linuxppc-dev@ozlabs.org From 7948261942ffdb35e274b8e1a0889601f45d4603 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:39 -0300 Subject: [PATCH 0998/2804] V4L/DVB (6311): dvb: Replace list_for_each+list_entry with list_for_each_entry Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_demux.c | 5 +---- drivers/media/dvb/dvb-core/dvbdev.c | 27 ++++++++------------------ 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index cb6987fce26c..7959020f9317 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -373,13 +373,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) { struct dvb_demux_feed *feed; - struct list_head *pos, *head = &demux->feed_list; u16 pid = ts_pid(buf); int dvr_done = 0; - list_for_each(pos, head) { - feed = list_entry(pos, struct dvb_demux_feed, list_head); - + list_for_each_entry(feed, &demux->feed_list, list_head) { if ((feed->pid != pid) && (feed->pid != 0x2000)) continue; diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 6b7954daeb4a..56231d8edc07 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -58,18 +58,13 @@ static struct class *dvb_class; static struct dvb_device* dvbdev_find_device (int minor) { - struct list_head *entry; + struct dvb_adapter *adap; - list_for_each (entry, &dvb_adapter_list) { - struct list_head *entry0; - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); - list_for_each (entry0, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry0, struct dvb_device, list_head); + list_for_each_entry(adap, &dvb_adapter_list, list_head) { + struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) if (nums2minor(adap->num, dev->type, dev->id) == minor) return dev; - } } return NULL; @@ -179,13 +174,10 @@ static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) u32 id = 0; while (id < DVB_MAX_IDS) { - struct list_head *entry; - list_for_each (entry, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry, struct dvb_device, list_head); + struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) if (dev->type == type && dev->id == id) goto skip; - } return id; skip: id++; @@ -279,13 +271,10 @@ static int dvbdev_get_free_adapter_num (void) int num = 0; while (num < DVB_MAX_ADAPTERS) { - struct list_head *entry; - list_for_each (entry, &dvb_adapter_list) { - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); + struct dvb_adapter *adap; + list_for_each_entry(adap, &dvb_adapter_list, list_head) if (adap->num == num) goto skip; - } return num; skip: num++; From 8bb629e22f2547736c24fe4738673e20cc06d469 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:40 -0300 Subject: [PATCH 0999/2804] V4L/DVB (6312): cx88: Replace list_for_each+list_entry with list_for_each_entry Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 4 +--- drivers/media/video/cx88/cx88-vbi.c | 5 +---- drivers/media/video/cx88/cx88-video.c | 11 +++-------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 85609b41f86e..62e8dd24c5f5 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1013,11 +1013,9 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, struct cx88_core* cx88_core_get(struct pci_dev *pci) { struct cx88_core *core; - struct list_head *item; mutex_lock(&devlist); - list_for_each(item,&cx88_devlist) { - core = list_entry(item, struct cx88_core, devlist); + list_for_each_entry(core, &cx88_devlist, devlist) { if (pci->bus->number != core->pci_bus) continue; if (PCI_SLOT(pci->devfn) != core->pci_slot) diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index aa40505c4b3a..babb08556406 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -99,7 +99,6 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q) { struct cx88_buffer *buf; - struct list_head *item; if (list_empty(&q->active)) return 0; @@ -108,10 +107,8 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx8800_start_vbi_dma(dev, q, buf); - list_for_each(item,&q->active) { - buf = list_entry(item, struct cx88_buffer, vb.queue); + list_for_each_entry(buf, &q->active, vb.queue) buf->count = q->count++; - } mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); return 0; } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 1439b7268532..231ae6c4dd22 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -466,17 +466,14 @@ static int restart_video_queue(struct cx8800_dev *dev, { struct cx88_core *core = dev->core; struct cx88_buffer *buf, *prev; - struct list_head *item; if (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); start_video_dma(dev, q, buf); - list_for_each(item,&q->active) { - buf = list_entry(item, struct cx88_buffer, vb.queue); - buf->count = q->count++; - } + list_for_each_entry(buf, &q->active, vb.queue) + buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); return 0; } @@ -713,12 +710,10 @@ static int video_open(struct inode *inode, struct file *file) struct cx8800_dev *h,*dev = NULL; struct cx88_core *core; struct cx8800_fh *fh; - struct list_head *list; enum v4l2_buf_type type = 0; int radio = 0; - list_for_each(list,&cx8800_devlist) { - h = list_entry(list, struct cx8800_dev, devlist); + list_for_each_entry(h, &cx8800_devlist, devlist) { if (h->video_dev->minor == minor) { dev = h; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; From 805a43924158e4eb2bffc4cac0aedcfb42a89469 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:41 -0300 Subject: [PATCH 1000/2804] V4L/DVB (6313): ivtv: Replace list_for_each+list_entry with list_for_each_entry Also fixed a few cases of cut&paste errors where 'buf' would be set to the first entry in the list prior to be used as the loop iterator. In one case the value of buf was used before it was changed, but the rest were unnecessary. There was one list_for_each+list_entry loop that wasn't changed, since it depending on the loop iterator being left as NULL if the list was empty. Signed-off-by: Trent Piepho CC: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index bf7d99c6ffaf..fd1688e4757d 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -42,7 +42,6 @@ static void ivtv_pio_work_handler(struct ivtv *itv) { struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream]; struct ivtv_buffer *buf; - struct list_head *p; int i = 0; IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); @@ -54,9 +53,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv) return; } IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name); - buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list); - list_for_each(p, &s->q_dma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); + list_for_each_entry(buf, &s->q_dma.list, list) { u32 size = s->sg_processing[i].size & 0x3ffff; /* Copy the data from the card to the buffer */ @@ -97,7 +94,6 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA { struct ivtv *itv = s->itv; struct ivtv_buffer *buf; - struct list_head *p; u32 bytes_needed = 0; u32 offset, size; u32 UVoffset = 0, UVsize = 0; @@ -202,9 +198,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA /* got the buffers, now fill in sg_pending */ buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); memset(buf->buf, 0, 128); - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_predma.list, list) { if (skip_bufs-- > 0) continue; s->sg_pending[idx].dst = buf->dma_handle; @@ -289,9 +283,7 @@ static void dma_post(struct ivtv_stream *s) if (buf) buf->bytesused += s->dma_last_offset; if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { - list_for_each(p, &s->q_dma.list) { - buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_dma.list, list) { /* Parse and Groom VBI Data */ s->q_dma.bytesused -= buf->bytesused; ivtv_process_vbi_data(itv, buf, 0, s->type); @@ -311,7 +303,6 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) { struct ivtv *itv = s->itv; struct ivtv_buffer *buf; - struct list_head *p; u32 y_size = itv->params.height * itv->params.width; u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; int y_done = 0; @@ -320,10 +311,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) int idx = 0; IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); - buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_predma.list, list) { /* YUV UV Offset from Y Buffer */ if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { offset = uv_offset; @@ -677,11 +665,9 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) we just drop the old requests when there are already three requests queued. */ if (s->sg_pending_size > 2) { - struct list_head *p; - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); + struct ivtv_buffer *buf; + list_for_each_entry(buf, &s->q_predma.list, list) ivtv_buf_sync_for_cpu(s, buf); - } ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); s->sg_pending_size = 0; } From 6d28e98906aa9405895f92348543d08da1837ea5 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:42 -0300 Subject: [PATCH 1001/2804] V4L/DVB (6314): saa7134: Replace list_for_each+list_entry with list_for_each_entry A couple loops weren't changed because they expected the loop iterator to be left as NULL if the list was empty. Maybe the code should just check for that first, then loop? Adjust some of the loop logic to be simpler. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 20 ++------- drivers/media/video/saa7134/saa7134-empress.c | 15 +++---- drivers/media/video/saa7134/saa7134-oss.c | 42 +++++++------------ drivers/media/video/saa7134/saa7134-video.c | 22 +++++----- 4 files changed, 35 insertions(+), 64 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 80f04f252fce..1a4a24471f20 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -890,7 +890,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct saa7134_dev *dev; - struct list_head *item; struct saa7134_mpeg_ops *mops; int err; @@ -1072,10 +1071,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, saa7134_devcount++; mutex_lock(&devlist_lock); - list_for_each(item,&mops_list) { - mops = list_entry(item, struct saa7134_mpeg_ops, next); + list_for_each_entry(mops, &mops_list, next) mpeg_ops_attach(mops, dev); - } list_add_tail(&dev->devlist,&saa7134_devlist); mutex_unlock(&devlist_lock); @@ -1109,7 +1106,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, static void __devexit saa7134_finidev(struct pci_dev *pci_dev) { struct saa7134_dev *dev = pci_get_drvdata(pci_dev); - struct list_head *item; struct saa7134_mpeg_ops *mops; /* Release DMA sound modules if present */ @@ -1138,10 +1134,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) /* unregister */ mutex_lock(&devlist_lock); list_del(&dev->devlist); - list_for_each(item,&mops_list) { - mops = list_entry(item, struct saa7134_mpeg_ops, next); + list_for_each_entry(mops, &mops_list, next) mpeg_ops_detach(mops, dev); - } mutex_unlock(&devlist_lock); saa7134_devcount--; @@ -1237,14 +1231,11 @@ static int saa7134_resume(struct pci_dev *pci_dev) int saa7134_ts_register(struct saa7134_mpeg_ops *ops) { - struct list_head *item; struct saa7134_dev *dev; mutex_lock(&devlist_lock); - list_for_each(item,&saa7134_devlist) { - dev = list_entry(item, struct saa7134_dev, devlist); + list_for_each_entry(dev, &saa7134_devlist, devlist) mpeg_ops_attach(ops, dev); - } list_add_tail(&ops->next,&mops_list); mutex_unlock(&devlist_lock); return 0; @@ -1252,15 +1243,12 @@ int saa7134_ts_register(struct saa7134_mpeg_ops *ops) void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops) { - struct list_head *item; struct saa7134_dev *dev; mutex_lock(&devlist_lock); list_del(&ops->next); - list_for_each(item,&saa7134_devlist) { - dev = list_entry(item, struct saa7134_dev, devlist); + list_for_each_entry(dev, &saa7134_devlist, devlist) mpeg_ops_detach(ops, dev); - } mutex_unlock(&devlist_lock); } diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index a16df57af63a..34ca874dd7fe 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -76,17 +76,14 @@ static int ts_init_encoder(struct saa7134_dev* dev) static int ts_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; int err; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->empress_dev && h->empress_dev->minor == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->empress_dev && dev->empress_dev->minor == minor) + goto found; + return -ENODEV; + found: dprintk("open minor=%d\n",minor); err = -EBUSY; diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 1a737b647366..aedf04653e0e 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -239,17 +239,14 @@ static int dsp_rec_stop(struct saa7134_dev *dev) static int dsp_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; int err; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->dmasound.minor_dsp == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->dmasound.minor_dsp == minor) + goto found; + return -ENODEV; + found: mutex_lock(&dev->dmasound.lock); err = -EBUSY; @@ -680,19 +677,14 @@ mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level) static int mixer_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->dmasound.minor_mixer == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; - - file->private_data = dev; - return 0; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->dmasound.minor_mixer == minor) { + file->private_data = dev; + return 0; + } + return -ENODEV; } static int mixer_release(struct inode *inode, struct file *file) @@ -1022,18 +1014,14 @@ static int saa7134_oss_init(void) static void saa7134_oss_exit(void) { - struct saa7134_dev *dev = NULL; - struct list_head *list; - - list_for_each(list,&saa7134_devlist) { - dev = list_entry(list, struct saa7134_dev, devlist); + struct saa7134_dev *dev; + list_for_each_entry(dev, &saa7134_devlist, devlist) { /* Device isn't registered by OSS, probably ALSA's */ if (!dev->dmasound.minor_dsp) continue; oss_device_exit(dev); - } saa7134_dmasound_init = NULL; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 7c97ac15e665..471b92793c12 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1285,26 +1285,24 @@ static int saa7134_resource(struct saa7134_fh *fh) static int video_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; + struct saa7134_dev *dev; struct saa7134_fh *fh; - struct list_head *list; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->video_dev && (h->video_dev->minor == minor)) - dev = h; - if (h->radio_dev && (h->radio_dev->minor == minor)) { + list_for_each_entry(dev, &saa7134_devlist, devlist) { + if (dev->video_dev && (dev->video_dev->minor == minor)) + goto found; + if (dev->radio_dev && (dev->radio_dev->minor == minor)) { radio = 1; - dev = h; + goto found; } - if (h->vbi_dev && (h->vbi_dev->minor == minor)) { + if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { type = V4L2_BUF_TYPE_VBI_CAPTURE; - dev = h; + goto found; } } - if (NULL == dev) - return -ENODEV; + return -ENODEV; + found: dprintk("open minor=%d radio=%d type=%s\n",minor,radio, v4l2_type_names[type]); From e77e2c2f2989eefff7e1c0fff9cb72afaedf6796 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:42 -0300 Subject: [PATCH 1002/2804] V4L/DVB (6315): pvrusb2: Change list_for_each+list_entry to list_for_each_entry Signed-off-by: Trent Piepho Reviewed-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 4 +- .../media/video/pvrusb2/pvrusb2-i2c-core.c | 51 ++++++------------- 2 files changed, 17 insertions(+), 38 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index eec83d6ae788..27b12b4b5c88 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3458,7 +3458,6 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, int setFl,u64 *val_ptr) { #ifdef CONFIG_VIDEO_ADV_DEBUG - struct list_head *item; struct pvr2_i2c_client *cp; struct v4l2_register req; int stat = 0; @@ -3471,8 +3470,7 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, req.reg = reg_id; if (setFl) req.val = *val_ptr; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!v4l2_chip_match_i2c_client( cp->client, req.match_type, req.match_chip)) { diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 7697f391e8bb..898c9d2e4cdf 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -570,15 +570,13 @@ int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg) int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg) { - struct list_head *item,*nc; - struct pvr2_i2c_client *cp; + struct pvr2_i2c_client *cp, *ncp; int stat = -EINVAL; if (!hdw) return stat; mutex_lock(&hdw->i2c_list_lock); - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { if (!cp->recv_enable) continue; mutex_unlock(&hdw->i2c_list_lock); stat = pvr2_i2c_client_cmd(cp,cmd,arg); @@ -602,13 +600,11 @@ static int handler_check(struct pvr2_i2c_client *cp) void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw) { - struct list_head *item; struct pvr2_i2c_client *cp; mutex_lock(&hdw->i2c_list_lock); do { struct v4l2_tuner *vtp = &hdw->tuner_signal_info; memset(vtp,0,sizeof(*vtp)); - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!cp->detected_flag) continue; if (!cp->status_poll) continue; cp->status_poll(cp); @@ -630,8 +626,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) { unsigned long msk; unsigned int idx; - struct list_head *item,*nc; - struct pvr2_i2c_client *cp; + struct pvr2_i2c_client *cp, *ncp; if (!hdw->i2c_linked) return; if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) { @@ -649,9 +644,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) buf = kmalloc(BUFSIZE,GFP_KERNEL); pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT"); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!cp->detected_flag) { cp->ctl_mask = 0; pvr2_i2c_probe(hdw,cp); @@ -687,9 +680,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) "i2c: PEND_STALE (0x%lx)", hdw->i2c_stale_mask); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { m2 = hdw->i2c_stale_mask; m2 &= cp->ctl_mask; m2 &= ~cp->pend_mask; @@ -710,9 +701,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) and update each one. */ pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT"); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT; - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, + list) { if (!cp->handler) continue; if (!cp->handler->func_table->update) continue; pvr2_trace(PVR2_TRACE_I2C_CORE, @@ -744,10 +734,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) for (idx = 0, msk = 1; pm; idx++, msk <<= 1) { if (!(pm & msk)) continue; pm &= ~msk; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item, - struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, + list) { if (cp->pend_mask & msk) { cp->pend_mask &= ~msk; cp->recv_enable = !0; @@ -771,7 +759,6 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) unsigned long msk,sm,pm; unsigned int idx; const struct pvr2_i2c_op *opf; - struct list_head *item; struct pvr2_i2c_client *cp; unsigned int pt = 0; @@ -790,11 +777,9 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) } if (sm) pt |= PVR2_I2C_PEND_STALE; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); - if (!handler_check(cp)) continue; - pt |= PVR2_I2C_PEND_CLIENT; - } + list_for_each_entry(cp, &hdw->i2c_clients, list) + if (handler_check(cp)) + pt |= PVR2_I2C_PEND_CLIENT; if (pt) { mutex_lock(&hdw->i2c_list_lock); do { @@ -882,12 +867,10 @@ unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw, char *buf,unsigned int maxlen) { unsigned int ccnt,bcnt; - struct list_head *item; struct pvr2_i2c_client *cp; ccnt = 0; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { bcnt = pvr2_i2c_client_describe( cp, (PVR2_I2C_DETAIL_HANDLER| @@ -925,13 +908,11 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client) static int pvr2_i2c_detach_inform(struct i2c_client *client) { struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); - struct pvr2_i2c_client *cp; - struct list_head *item,*nc; + struct pvr2_i2c_client *cp, *ncp; unsigned long amask = 0; int foundfl = 0; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { if (cp->client == client) { trace_i2c("pvr2_i2c_detach" " [client=%s @ 0x%x ctxt=%p]", From a991f44b79fa49b281eb078eed4a76a42101012a Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:43 -0300 Subject: [PATCH 1003/2804] V4L/DVB (6316): Change list_for_each+list_entry to list_for_each_entry The rest of V4L files. There is one list_for_each+list_entry in cpia_pp.c that wasn't changed because it expects the loop iterator to remain NULL if the list is empty. A bug in vivi is fixed; the 'safe' version needs to be used because the loop deletes the list entries. Simplify a second loop in vivi and get rid if an un-used variable in that loop. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-gpio.c | 6 ++--- drivers/media/video/cx23885/cx23885-core.c | 5 +--- drivers/media/video/dpc7146.c | 5 +--- drivers/media/video/em28xx/em28xx-video.c | 4 +--- drivers/media/video/mxb.c | 4 +--- drivers/media/video/tvmixer.c | 5 +--- drivers/media/video/v4l2-int-device.c | 14 +++-------- drivers/media/video/videobuf-core.c | 5 +--- drivers/media/video/vivi.c | 27 ++++++++-------------- 9 files changed, 20 insertions(+), 55 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c index 84154c26f9c5..dce6dae5740e 100644 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ b/drivers/media/video/bt8xx/bttv-gpio.c @@ -106,11 +106,9 @@ int bttv_sub_add_device(struct bttv_core *core, char *name) int bttv_sub_del_devices(struct bttv_core *core) { - struct bttv_sub_device *sub; - struct list_head *item,*save; + struct bttv_sub_device *sub, *save; - list_for_each_safe(item,save,&core->subs) { - sub = list_entry(item,struct bttv_sub_device,list); + list_for_each_entry_safe(sub, save, &core->subs, list) { list_del(&sub->list); device_unregister(&sub->dev); } diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 4d0614093ad6..af16505bd2e0 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1100,7 +1100,6 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; - struct list_head *item; dprintk(5, "%s()\n", __FUNCTION__); if (list_empty(&q->active)) @@ -1148,10 +1147,8 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx23885_start_dma(port, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, vb.queue); + list_for_each_entry(buf, &q->active, vb.queue) buf->count = q->count++; - } mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); return 0; } diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c index 0fcc935828f8..255dae303708 100644 --- a/drivers/media/video/dpc7146.c +++ b/drivers/media/video/dpc7146.c @@ -92,7 +92,6 @@ static int dpc_probe(struct saa7146_dev* dev) { struct dpc* dpc = NULL; struct i2c_client *client; - struct list_head *item; dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL); if( NULL == dpc ) { @@ -116,11 +115,9 @@ static int dpc_probe(struct saa7146_dev* dev) } /* loop through all i2c-devices on the bus and look who is there */ - list_for_each(item,&dpc->i2c_adapter.clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &dpc->i2c_adapter.clients, list) if( I2C_SAA7111A == client->addr ) dpc->saa7111a = client; - } /* check if all devices are present */ if( 0 == dpc->saa7111a ) { diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index e4fba9068336..b8d5327c438d 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -252,10 +252,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) int minor = iminor(inode); int errCode = 0; struct em28xx *h,*dev = NULL; - struct list_head *list; - list_for_each(list,&em28xx_devlist) { - h = list_entry(list, struct em28xx, devlist); + list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { dev = h; dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 152cc6b3e152..98ad3092a079 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -153,7 +153,6 @@ static int mxb_probe(struct saa7146_dev* dev) { struct mxb* mxb = NULL; struct i2c_client *client; - struct list_head *item; int result; if ((result = request_module("saa7111")) < 0) { @@ -196,8 +195,7 @@ static int mxb_probe(struct saa7146_dev* dev) } /* loop through all i2c-devices on the bus and look who is there */ - list_for_each(item,&mxb->i2c_adapter.clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &mxb->i2c_adapter.clients, list) { if( I2C_ADDR_TEA6420_1 == client->addr ) mxb->tea6420_1 = client; if( I2C_ADDR_TEA6420_2 == client->addr ) diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 544a4ae7d2ed..9fa5b702e073 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -237,13 +237,10 @@ static const struct file_operations tvmixer_fops = { static int tvmixer_adapters(struct i2c_adapter *adap) { - struct list_head *item; struct i2c_client *client; - list_for_each(item,&adap->clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &adap->clients, list) tvmixer_clients(client); - } return 0; } diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index f497c9458344..8b4ef530a3a8 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -34,21 +34,13 @@ static LIST_HEAD(int_list); static void v4l2_int_device_try_attach_all(void) { - struct list_head *head_master; - - list_for_each(head_master, &int_list) { - struct list_head *head_slave; - struct v4l2_int_device *m = - list_entry(head_master, struct v4l2_int_device, head); + struct v4l2_int_device *m, *s; + list_for_each_entry(m, &int_list, head) { if (m->type != v4l2_int_type_master) continue; - list_for_each(head_slave, &int_list) { - struct v4l2_int_device *s = - list_entry(head_slave, - struct v4l2_int_device, head); - + list_for_each_entry(s, &int_list, head) { if (s->type != v4l2_int_type_slave) continue; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 25a98496e3db..c606332512b6 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -517,7 +517,6 @@ int videobuf_dqbuf(struct videobuf_queue *q, int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; - struct list_head *list; unsigned long flags=0; int retval; @@ -531,11 +530,9 @@ int videobuf_streamon(struct videobuf_queue *q) q->streaming = 1; if (q->irqlock) spin_lock_irqsave(q->irqlock,flags); - list_for_each(list,&q->stream) { - buf = list_entry(list, struct videobuf_buffer, stream); + list_for_each_entry(buf, &q->stream, stream) if (buf->state == STATE_PREPARED) q->ops->buf_queue(q,buf); - } if (q->irqlock) spin_unlock_irqrestore(q->irqlock,flags); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 61a6608d6e61..b532aa280a1b 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -507,7 +507,6 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) static int restart_video_queue(struct vivi_dmaqueue *dma_q) { struct vivi_buffer *buf, *prev; - struct list_head *item; dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); @@ -521,9 +520,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) // vivi_start_thread(dma_q); /* cancel all outstanding capture / vbi requests */ - list_for_each(item,&dma_q->active) { - buf = list_entry(item, struct vivi_buffer, vb.queue); - + list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { list_del(&buf->vb.queue); buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); @@ -982,31 +979,25 @@ static int vidioc_s_ctrl (struct file *file, void *priv, static int vivi_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct vivi_dev *h,*dev = NULL; + struct vivi_dev *dev; struct vivi_fh *fh; - struct list_head *list; - enum v4l2_buf_type type = 0; int i; printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); - list_for_each(list,&vivi_devlist) { - h = list_entry(list, struct vivi_dev, vivi_devlist); - if (h->vfd.minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &vivi_devlist, vivi_devlist) + if (dev->vfd.minor == minor) + goto found; + return -ENODEV; +found: /* If more than one user, mutex should be added */ dev->users++; - dprintk(1,"open minor=%d type=%s users=%d\n", - minor,v4l2_type_names[type],dev->users); + dprintk(1, "open minor=%d type=%s users=%d\n", minor, + v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); From c783837bc69dd0f329a441c1704f5a02d01d1bd5 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 9 Oct 2007 17:07:58 -0400 Subject: [PATCH 1004/2804] pxamci: support arbitrary block size The PXA has two transmit FIFOes, each32 byte deep. when one FIFO is full and the other one has been transmitted, they are automatically swapped and DMA is triggered for another 32 byte burst. However, when there is less than 32 bytes left to send, the FIFO swap has to be done manually. This is required for some SDIO transfers which are not required to be multiples of 32 bytes. A DMA completion interrupt is set for each descriptor which length isn't a multiple of 32 in order to force the FIFO swap. While at it, the DMA interrupt handler has been made a bit more resilient against errors. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 91e25683b397..657901eecfce 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -142,6 +142,10 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) host->dma_dir); for (i = 0; i < host->dma_len; i++) { + unsigned int length = sg_dma_len(&data->sg[i]); + host->sg_cpu[i].dcmd = dcmd | length; + if (length & 31 && !(data->flags & MMC_DATA_READ)) + host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; if (data->flags & MMC_DATA_READ) { host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); @@ -149,7 +153,6 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; } - host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]); host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); } @@ -414,8 +417,18 @@ static const struct mmc_host_ops pxamci_ops = { static void pxamci_dma_irq(int dma, void *devid) { - printk(KERN_ERR "DMA%d: IRQ???\n", dma); - DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; + struct pxamci_host *host = devid; + int dcsr = DCSR(dma); + DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; + + if (dcsr & DCSR_ENDINTR) { + writel(BUF_PART_FULL, host->base + MMC_PRTBUF); + } else { + printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", + mmc_hostname(host->mmc), dma, dcsr); + host->data->error = -EIO; + pxamci_data_done(host, 0); + } } static irqreturn_t pxamci_detect_irq(int irq, void *devid) From 55a98e955caab78a5959933a4a3a0136e2491d6c Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 10 Oct 2007 17:55:37 +0200 Subject: [PATCH 1005/2804] IB/mthca: Mark error paths as unlikely() in post_srq_recv functions Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_srq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 88d219e730ad..3f58c11a62b7 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -509,7 +509,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, for (nreq = 0; wr; wr = wr->next) { ind = srq->first_free; - if (ind < 0) { + if (unlikely(ind < 0)) { mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; @@ -519,7 +519,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, wqe = get_wqe(srq, ind); next_ind = *wqe_to_link(wqe); - if (next_ind < 0) { + if (unlikely(next_ind < 0)) { mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; @@ -623,7 +623,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, for (nreq = 0; wr; ++nreq, wr = wr->next) { ind = srq->first_free; - if (ind < 0) { + if (unlikely(ind < 0)) { mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; @@ -633,7 +633,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, wqe = get_wqe(srq, ind); next_ind = *wqe_to_link(wqe); - if (next_ind < 0) { + if (unlikely(next_ind < 0)) { mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; From 335a64a5a958002bc238c90de695e120c3c8c120 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Oct 2007 10:13:00 +0200 Subject: [PATCH 1006/2804] IPoIB: Allow setting policy to ignore multicast groups The kernel IB stack allows (through the RDMA CM) userspace applications to join and use multicast groups from the IPoIB MGID range. This allows multicast traffic to be handled directly from userspace QPs, without going through the kernel stack, which gives better performance for some applications. However, to fully interoperate with IP multicast, such userspace applications need to participate in IGMP reports and queries, or else routers may not forward the multicast traffic to the system where the application is running. The simplest way to do this is to share the kernel IGMP implementation by using the IP_ADD_MEMBERSHIP option to join multicast groups that are being handled directly in userspace. However, in such cases, the actual multicast traffic should not also be handled by the IPoIB interface, because that would burn resources handling multicast packets that will just be discarded in the kernel. To handle this, this patch adds lookup on the database used for IB multicast group reference counting when IPoIB is joining multicast groups, and if a multicast group is already handled by user space, then the IPoIB kernel driver ignores the group. This is controlled by a per-interface policy flag. When the flag is set, IPoIB will not join and attach its QP to a multicast group which already has an entry in the database; when the flag is cleared, IPoIB will behave as before this change. For each IPoIB interface, the /sys/class/net/$intf/umcast attribute controls the policy flag. The default value is off/0. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib.h | 2 ++ drivers/infiniband/ulp/ipoib/ipoib_main.c | 33 +++++++++++++++++++ .../infiniband/ulp/ipoib/ipoib_multicast.c | 9 +++++ drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 2 ++ 4 files changed, 46 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index fc16bced8e54..a198ce8371db 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -86,6 +86,7 @@ enum { IPOIB_MCAST_STARTED = 8, IPOIB_FLAG_NETIF_STOPPED = 9, IPOIB_FLAG_ADMIN_CM = 10, + IPOIB_FLAG_UMCAST = 11, IPOIB_MAX_BACKOFF_SECONDS = 16, @@ -384,6 +385,7 @@ static inline void ipoib_put_ah(struct ipoib_ah *ah) int ipoib_open(struct net_device *dev); int ipoib_add_pkey_attr(struct net_device *dev); +int ipoib_add_umcast_attr(struct net_device *dev); void ipoib_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_ah *address, u32 qpn); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 900335a36e45..ff17fe3c765b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1019,6 +1019,37 @@ static ssize_t show_pkey(struct device *dev, } static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); +static ssize_t show_umcast(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); + + return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags)); +} + +static ssize_t set_umcast(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); + unsigned long umcast_val = simple_strtoul(buf, NULL, 0); + + if (umcast_val > 0) { + set_bit(IPOIB_FLAG_UMCAST, &priv->flags); + ipoib_warn(priv, "ignoring multicast groups joined directly " + "by userspace\n"); + } else + clear_bit(IPOIB_FLAG_UMCAST, &priv->flags); + + return count; +} +static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast); + +int ipoib_add_umcast_attr(struct net_device *dev) +{ + return device_create_file(&dev->dev, &dev_attr_umcast); +} + static ssize_t create_child(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1136,6 +1167,8 @@ static struct net_device *ipoib_add_port(const char *format, goto sysfs_failed; if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; + if (ipoib_add_umcast_attr(priv->dev)) + goto sysfs_failed; if (device_create_file(&priv->dev->dev, &dev_attr_create_child)) goto sysfs_failed; if (device_create_file(&priv->dev->dev, &dev_attr_delete_child)) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 94a57097e2b4..62abfb6f35c1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -761,6 +761,7 @@ void ipoib_mcast_restart_task(struct work_struct *work) struct ipoib_mcast *mcast, *tmcast; LIST_HEAD(remove_list); unsigned long flags; + struct ib_sa_mcmember_rec rec; ipoib_dbg_mcast(priv, "restarting multicast task\n"); @@ -794,6 +795,14 @@ void ipoib_mcast_restart_task(struct work_struct *work) if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { struct ipoib_mcast *nmcast; + /* ignore group which is directly joined by userspace */ + if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) && + !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) { + ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid " + IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid)); + continue; + } + /* Not found or send-only group, let's add a new entry */ ipoib_dbg_mcast(priv, "adding multicast entry for mgid " IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid)); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 6762988439d1..293f5b892e3f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -119,6 +119,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) goto sysfs_failed; if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; + if (ipoib_add_umcast_attr(priv->dev)) + goto sysfs_failed; if (device_create_file(&priv->dev->dev, &dev_attr_parent)) goto sysfs_failed; From 3d73c2884f45f9a297cbc956cea101405a9703f2 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 10 Oct 2007 15:43:54 -0700 Subject: [PATCH 1007/2804] mlx4_core: Fix section mismatches Commit ee49bd93 ("mlx4_core: Reset device when internal error is detected") introduced some section mismatch problems when CONFIG_HOTPLUG=n, because the error recovery code tears down and reinitializes the device after everything is loaded, which ends up calling into lots of code marked __devinit and __devexit from regular .text. Fix this by getting rid of these now-incorrect section markers. Signed-off-by: Roland Dreier --- drivers/net/mlx4/cq.c | 2 +- drivers/net/mlx4/eq.c | 13 ++++++------- drivers/net/mlx4/main.c | 38 +++++++++++++++++++++----------------- drivers/net/mlx4/mcg.c | 2 +- drivers/net/mlx4/mr.c | 2 +- drivers/net/mlx4/pd.c | 2 +- drivers/net/mlx4/qp.c | 2 +- drivers/net/mlx4/srq.c | 2 +- 8 files changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 39253d0c1590..d4441fee3d80 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -231,7 +231,7 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) } EXPORT_SYMBOL_GPL(mlx4_cq_free); -int __devinit mlx4_init_cq_table(struct mlx4_dev *dev) +int mlx4_init_cq_table(struct mlx4_dev *dev) { struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; int err; diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 2095c843fa15..9c36c2034030 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -300,8 +300,7 @@ static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, MLX4_CMD_TIME_CLASS_A); } -static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, - struct mlx4_eq *eq) +static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) { struct mlx4_priv *priv = mlx4_priv(dev); int index; @@ -323,8 +322,8 @@ static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4); } -static int __devinit mlx4_create_eq(struct mlx4_dev *dev, int nent, - u8 intr, struct mlx4_eq *eq) +static int mlx4_create_eq(struct mlx4_dev *dev, int nent, + u8 intr, struct mlx4_eq *eq) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -485,7 +484,7 @@ static void mlx4_free_irqs(struct mlx4_dev *dev) free_irq(eq_table->eq[i].irq, eq_table->eq + i); } -static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev) +static int mlx4_map_clr_int(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -506,7 +505,7 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev) iounmap(priv->clr_base); } -int __devinit mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt) +int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt) { struct mlx4_priv *priv = mlx4_priv(dev); int ret; @@ -548,7 +547,7 @@ void mlx4_unmap_eq_icm(struct mlx4_dev *dev) __free_page(priv->eq_table.icm_page); } -int __devinit mlx4_init_eq_table(struct mlx4_dev *dev) +int mlx4_init_eq_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int err; diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 478b3ba74edc..e029b8afbd37 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -85,7 +85,7 @@ static struct mlx4_profile default_profile = { .num_mtt = 1 << 20, }; -static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) +static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) { int err; int i; @@ -256,10 +256,8 @@ err: return err; } -static int __devinit mlx4_init_icm(struct mlx4_dev *dev, - struct mlx4_dev_cap *dev_cap, - struct mlx4_init_hca_param *init_hca, - u64 icm_size) +static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, + struct mlx4_init_hca_param *init_hca, u64 icm_size) { struct mlx4_priv *priv = mlx4_priv(dev); u64 aux_pages; @@ -481,7 +479,7 @@ static void mlx4_close_hca(struct mlx4_dev *dev) mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0); } -static int __devinit mlx4_init_hca(struct mlx4_dev *dev) +static int mlx4_init_hca(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_adapter adapter; @@ -554,7 +552,7 @@ err_stop_fw: return err; } -static int __devinit mlx4_setup_hca(struct mlx4_dev *dev) +static int mlx4_setup_hca(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int err; @@ -721,19 +719,12 @@ no_msi: priv->eq_table.eq[i].irq = dev->pdev->irq; } -static int __devinit mlx4_init_one(struct pci_dev *pdev, - const struct pci_device_id *id) +static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { - static int mlx4_version_printed; struct mlx4_priv *priv; struct mlx4_dev *dev; int err; - if (!mlx4_version_printed) { - printk(KERN_INFO "%s", mlx4_version); - ++mlx4_version_printed; - } - printk(KERN_INFO PFX "Initializing %s\n", pci_name(pdev)); @@ -883,7 +874,20 @@ err_disable_pdev: return err; } -static void __devexit mlx4_remove_one(struct pci_dev *pdev) +static int __devinit mlx4_init_one(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + static int mlx4_version_printed; + + if (!mlx4_version_printed) { + printk(KERN_INFO "%s", mlx4_version); + ++mlx4_version_printed; + } + + return mlx4_init_one(pdev, id); +} + +static void mlx4_remove_one(struct pci_dev *pdev) { struct mlx4_dev *dev = pci_get_drvdata(pdev); struct mlx4_priv *priv = mlx4_priv(dev); @@ -924,7 +928,7 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev) int mlx4_restart_one(struct pci_dev *pdev) { mlx4_remove_one(pdev); - return mlx4_init_one(pdev, NULL); + return __mlx4_init_one(pdev, NULL); } static struct pci_device_id mlx4_pci_table[] = { diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 672024a0ee71..a99e7729d333 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -359,7 +359,7 @@ out: } EXPORT_SYMBOL_GPL(mlx4_multicast_detach); -int __devinit mlx4_init_mcg_table(struct mlx4_dev *dev) +int mlx4_init_mcg_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int err; diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 4bc39e65015a..0c05a10bae3b 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -430,7 +430,7 @@ int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, } EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt); -int __devinit mlx4_init_mr_table(struct mlx4_dev *dev) +int mlx4_init_mr_table(struct mlx4_dev *dev) { struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; int err; diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c index 23dea1ee7750..3a93c5f0f7ab 100644 --- a/drivers/net/mlx4/pd.c +++ b/drivers/net/mlx4/pd.c @@ -57,7 +57,7 @@ void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) } EXPORT_SYMBOL_GPL(mlx4_pd_free); -int __devinit mlx4_init_pd_table(struct mlx4_dev *dev) +int mlx4_init_pd_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index 278414b2d01c..cc4b1be18219 100644 --- a/drivers/net/mlx4/qp.c +++ b/drivers/net/mlx4/qp.c @@ -251,7 +251,7 @@ static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn) MLX4_CMD_TIME_CLASS_B); } -int __devinit mlx4_init_qp_table(struct mlx4_dev *dev) +int mlx4_init_qp_table(struct mlx4_dev *dev) { struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; int err; diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c index 31b255a32915..d23f46d692ef 100644 --- a/drivers/net/mlx4/srq.c +++ b/drivers/net/mlx4/srq.c @@ -235,7 +235,7 @@ err_out: } EXPORT_SYMBOL_GPL(mlx4_srq_query); -int __devinit mlx4_init_srq_table(struct mlx4_dev *dev) +int mlx4_init_srq_table(struct mlx4_dev *dev) { struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; int err; From 571ecf676d66735f59be6b950360e4074f02f47d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1008/2804] [MAC80211]: split RX handlers into own file Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- include/net/ieee80211_radiotap.h | 9 + net/mac80211/Makefile | 1 + net/mac80211/ieee80211.c | 1373 +----------------------------- net/mac80211/ieee80211_i.h | 22 + net/mac80211/rx.c | 1360 +++++++++++++++++++++++++++++ 5 files changed, 1400 insertions(+), 1365 deletions(-) create mode 100644 net/mac80211/rx.c diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index a0c2b41a24d7..22e047758ba1 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -255,4 +255,13 @@ enum ieee80211_radiotap_type { (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \ ((x) + 1000) * 5) +/* helpers */ +static inline int ieee80211_get_radiotap_len(unsigned char *data) +{ + struct ieee80211_radiotap_header *hdr = + (struct ieee80211_radiotap_header *)data; + + return le16_to_cpu(hdr->it_len); +} + #endif /* IEEE80211_RADIOTAP_H */ diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index a9c2d0787d4a..b5853991324b 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -18,4 +18,5 @@ mac80211-objs := \ aes_ccm.o \ wme.o \ ieee80211_cfg.o \ + rx.o \ $(mac80211-objs-y) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index ff2172ffd861..c0094209bed9 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -45,11 +45,11 @@ void *mac80211_wiphy_privid = &mac80211_wiphy_privid; /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static const unsigned char rfc1042_header[] = +const unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static const unsigned char bridge_tunnel_header[] = +const unsigned char bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; /* No encapsulation header if EtherType < 0x600 (=length) */ @@ -222,9 +222,9 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, } -static void ieee80211_key_threshold_notify(struct net_device *dev, - struct ieee80211_key *key, - struct sta_info *sta) +void ieee80211_key_threshold_notify(struct net_device *dev, + struct ieee80211_key *key, + struct sta_info *sta) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sk_buff *skb; @@ -258,7 +258,7 @@ static void ieee80211_key_threshold_notify(struct net_device *dev, } -static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) { u16 fc; @@ -345,13 +345,6 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); -static int ieee80211_get_radiotap_len(struct sk_buff *skb) -{ - struct ieee80211_radiotap_header *hdr = - (struct ieee80211_radiotap_header *) skb->data; - - return le16_to_cpu(hdr->it_len); -} #ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP static void ieee80211_dump_frame(const char *ifname, const char *title, @@ -392,7 +385,7 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title, #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ -static int ieee80211_is_eapol(const struct sk_buff *skb) +int ieee80211_is_eapol(const struct sk_buff *skb) { const struct ieee80211_hdr *hdr; u16 fc; @@ -2762,188 +2755,7 @@ static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) return ETH_ALEN; } -static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) -{ - return compare_ether_addr(raddr, addr) == 0 || - is_broadcast_ether_addr(raddr); -} - - -static ieee80211_txrx_result -ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) -{ - struct net_device *dev = rx->dev; - struct ieee80211_local *local = rx->local; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - u16 fc, hdrlen, ethertype; - u8 *payload; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - struct sk_buff *skb = rx->skb, *skb2; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - fc = rx->fc; - if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) - return TXRX_CONTINUE; - - if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return TXRX_DROP; - - hdrlen = ieee80211_get_hdrlen(fc); - - /* convert IEEE 802.11 header + possible LLC headers into Ethernet - * header - * IEEE 802.11 address fields: - * ToDS FromDS Addr1 Addr2 Addr3 Addr4 - * 0 0 DA SA BSSID n/a - * 0 1 DA BSSID SA n/a - * 1 0 BSSID SA DA n/a - * 1 1 RA TA DA SA - */ - - switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { - case IEEE80211_FCTL_TODS: - /* BSSID SA DA */ - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - - if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP && - sdata->type != IEEE80211_IF_TYPE_VLAN)) { - printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID=" - MAC_FMT " SA=" MAC_FMT " DA=" MAC_FMT ")\n", - dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3)); - return TXRX_DROP; - } - break; - case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): - /* RA TA DA SA */ - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr4, ETH_ALEN); - - if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) { - printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame (RA=" - MAC_FMT " TA=" MAC_FMT " DA=" MAC_FMT " SA=" - MAC_FMT ")\n", - rx->dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3), - MAC_ARG(hdr->addr4)); - return TXRX_DROP; - } - break; - case IEEE80211_FCTL_FROMDS: - /* DA BSSID SA */ - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr3, ETH_ALEN); - - if (sdata->type != IEEE80211_IF_TYPE_STA) { - return TXRX_DROP; - } - break; - case 0: - /* DA SA BSSID */ - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - - if (sdata->type != IEEE80211_IF_TYPE_IBSS) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped IBSS frame (DA=" - MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT - ")\n", - dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); - } - return TXRX_DROP; - } - break; - } - - payload = skb->data + hdrlen; - - if (unlikely(skb->len - hdrlen < 8)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: RX too short data frame " - "payload\n", dev->name); - } - return TXRX_DROP; - } - - ethertype = (payload[6] << 8) | payload[7]; - - if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - compare_ether_addr(payload, bridge_tunnel_header) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - struct ethhdr *ehdr; - __be16 len; - skb_pull(skb, hdrlen); - len = htons(skb->len); - ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); - memcpy(ehdr->h_dest, dst, ETH_ALEN); - memcpy(ehdr->h_source, src, ETH_ALEN); - ehdr->h_proto = len; - } - skb->dev = dev; - - skb2 = NULL; - - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; - - if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP - || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) { - if (is_multicast_ether_addr(skb->data)) { - /* send multicast frames both to higher layers in - * local net stack and back to the wireless media */ - skb2 = skb_copy(skb, GFP_ATOMIC); - if (!skb2) - printk(KERN_DEBUG "%s: failed to clone " - "multicast frame\n", dev->name); - } else { - struct sta_info *dsta; - dsta = sta_info_get(local, skb->data); - if (dsta && !dsta->dev) { - printk(KERN_DEBUG "Station with null dev " - "structure!\n"); - } else if (dsta && dsta->dev == dev) { - /* Destination station is associated to this - * AP, so send the frame directly to it and - * do not pass the frame to local net stack. - */ - skb2 = skb; - skb = NULL; - } - if (dsta) - sta_info_put(dsta); - } - } - - if (skb) { - /* deliver to local stack */ - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - } - - if (skb2) { - /* send to wireless media */ - skb2->protocol = __constant_htons(ETH_P_802_3); - skb_set_network_header(skb2, 0); - skb_set_mac_header(skb2, 0); - dev_queue_xmit(skb2); - } - - return TXRX_QUEUED; -} - - -static struct ieee80211_rate * +struct ieee80211_rate * ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) { struct ieee80211_hw_mode *mode; @@ -3071,69 +2883,6 @@ ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, netif_rx(skb); } -static void -ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_rx_status *status) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - struct ieee80211_rate *rate; - struct ieee80211_rtap_hdr { - struct ieee80211_radiotap_header hdr; - u8 flags; - u8 rate; - __le16 chan_freq; - __le16 chan_flags; - u8 antsignal; - } __attribute__ ((packed)) *rthdr; - - skb->dev = dev; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (status->flag & RX_FLAG_RADIOTAP) - goto out; - - if (skb_headroom(skb) < sizeof(*rthdr)) { - I802_DEBUG_INC(local->rx_expand_skb_head); - if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return; - } - } - - rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr)); - memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)); - rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? - IEEE80211_RADIOTAP_F_FCS : 0; - rate = ieee80211_get_rate(local, status->phymode, status->rate); - if (rate) - rthdr->rate = rate->rate / 5; - rthdr->chan_freq = cpu_to_le16(status->freq); - rthdr->chan_flags = - status->phymode == MODE_IEEE80211A ? - cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) : - cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ); - rthdr->antsignal = status->ssi; - - out: - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; - - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, int radar, int radar_type) { @@ -3163,1000 +2912,6 @@ int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, EXPORT_SYMBOL(ieee80211_radar_status); -static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata; - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - - if (sdata->bss) - atomic_inc(&sdata->bss->num_sta_ps); - sta->flags |= WLAN_STA_PS; - sta->pspoll = 0; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ -} - - -static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - int sent = 0; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - if (sdata->bss) - atomic_dec(&sdata->bss->num_sta_ps); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM); - sta->pspoll = 0; - if (!skb_queue_empty(&sta->ps_tx_buf)) { - if (local->ops->set_tim) - local->ops->set_tim(local_to_hw(local), sta->aid, 0); - if (sdata->bss) - bss_tim_clear(local, sdata->bss, sta->aid); - } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - /* Send all buffered frames to the station */ - while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - sent++; - pkt_data->requeue = 1; - dev_queue_xmit(skb); - } - while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - local->total_ps_buffered--; - sent++; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame " - "since STA not sleeping anymore\n", dev->name, - MAC_ARG(sta->addr), sta->aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - pkt_data->requeue = 1; - dev_queue_xmit(skb); - } - - return sent; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) -{ - struct sk_buff *skb; - int no_pending_pkts; - - if (likely(!rx->sta || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || - !rx->u.rx.ra_match)) - return TXRX_CONTINUE; - - skb = skb_dequeue(&rx->sta->tx_filtered); - if (!skb) { - skb = skb_dequeue(&rx->sta->ps_tx_buf); - if (skb) - rx->local->total_ps_buffered--; - } - no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) && - skb_queue_empty(&rx->sta->ps_tx_buf); - - if (skb) { - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) skb->data; - - /* tell TX path to send one frame even though the STA may - * still remain is PS mode after this frame exchange */ - rx->sta->pspoll = 1; - -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries " - "after %d)\n", - MAC_ARG(rx->sta->addr), rx->sta->aid, - skb_queue_len(&rx->sta->ps_tx_buf)); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - - /* Use MoreData flag to indicate whether there are more - * buffered frames for this STA */ - if (no_pending_pkts) { - hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); - rx->sta->flags &= ~WLAN_STA_TIM; - } else - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - - dev_queue_xmit(skb); - - if (no_pending_pkts) { - if (rx->local->ops->set_tim) - rx->local->ops->set_tim(local_to_hw(rx->local), - rx->sta->aid, 0); - if (rx->sdata->bss) - bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid); - } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - } else if (!rx->u.rx.sent_ps_buffered) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even " - "though there is no buffered frames for it\n", - rx->dev->name, MAC_ARG(rx->sta->addr)); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - - } - - /* Free PS Poll skb here instead of returning TXRX_DROP that would - * count as an dropped frame. */ - dev_kfree_skb(rx->skb); - - return TXRX_QUEUED; -} - - -static inline struct ieee80211_fragment_entry * -ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, - unsigned int frag, unsigned int seq, int rx_queue, - struct sk_buff **skb) -{ - struct ieee80211_fragment_entry *entry; - int idx; - - idx = sdata->fragment_next; - entry = &sdata->fragments[sdata->fragment_next++]; - if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) - sdata->fragment_next = 0; - - if (!skb_queue_empty(&entry->skb_list)) { -#ifdef CONFIG_MAC80211_DEBUG - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) entry->skb_list.next->data; - printk(KERN_DEBUG "%s: RX reassembly removed oldest " - "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " - "addr1=" MAC_FMT " addr2=" MAC_FMT "\n", - sdata->dev->name, idx, - jiffies - entry->first_frag_time, entry->seq, - entry->last_frag, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2)); -#endif /* CONFIG_MAC80211_DEBUG */ - __skb_queue_purge(&entry->skb_list); - } - - __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ - *skb = NULL; - entry->first_frag_time = jiffies; - entry->seq = seq; - entry->rx_queue = rx_queue; - entry->last_frag = frag; - entry->ccmp = 0; - entry->extra_len = 0; - - return entry; -} - - -static inline struct ieee80211_fragment_entry * -ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, - u16 fc, unsigned int frag, unsigned int seq, - int rx_queue, struct ieee80211_hdr *hdr) -{ - struct ieee80211_fragment_entry *entry; - int i, idx; - - idx = sdata->fragment_next; - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { - struct ieee80211_hdr *f_hdr; - u16 f_fc; - - idx--; - if (idx < 0) - idx = IEEE80211_FRAGMENT_MAX - 1; - - entry = &sdata->fragments[idx]; - if (skb_queue_empty(&entry->skb_list) || entry->seq != seq || - entry->rx_queue != rx_queue || - entry->last_frag + 1 != frag) - continue; - - f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; - f_fc = le16_to_cpu(f_hdr->frame_control); - - if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) || - compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 || - compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0) - continue; - - if (entry->first_frag_time + 2 * HZ < jiffies) { - __skb_queue_purge(&entry->skb_list); - continue; - } - return entry; - } - - return NULL; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_hdr *hdr; - u16 sc; - unsigned int frag, seq; - struct ieee80211_fragment_entry *entry; - struct sk_buff *skb; - - hdr = (struct ieee80211_hdr *) rx->skb->data; - sc = le16_to_cpu(hdr->seq_ctrl); - frag = sc & IEEE80211_SCTL_FRAG; - - if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) || - (rx->skb)->len < 24 || - is_multicast_ether_addr(hdr->addr1))) { - /* not fragmented */ - goto out; - } - I802_DEBUG_INC(rx->local->rx_handlers_fragments); - - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - - if (frag == 0) { - /* This is the first fragment of a new frame. */ - entry = ieee80211_reassemble_add(rx->sdata, frag, seq, - rx->u.rx.queue, &(rx->skb)); - if (rx->key && rx->key->alg == ALG_CCMP && - (rx->fc & IEEE80211_FCTL_PROTECTED)) { - /* Store CCMP PN so that we can verify that the next - * fragment has a sequential PN value. */ - entry->ccmp = 1; - memcpy(entry->last_pn, - rx->key->u.ccmp.rx_pn[rx->u.rx.queue], - CCMP_PN_LEN); - } - return TXRX_QUEUED; - } - - /* This is a fragment for a frame that should already be pending in - * fragment cache. Add this fragment to the end of the pending entry. - */ - entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq, - rx->u.rx.queue, hdr); - if (!entry) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - return TXRX_DROP; - } - - /* Verify that MPDUs within one MSDU have sequential PN values. - * (IEEE 802.11i, 8.3.3.4.5) */ - if (entry->ccmp) { - int i; - u8 pn[CCMP_PN_LEN], *rpn; - if (!rx->key || rx->key->alg != ALG_CCMP) - return TXRX_DROP; - memcpy(pn, entry->last_pn, CCMP_PN_LEN); - for (i = CCMP_PN_LEN - 1; i >= 0; i--) { - pn[i]++; - if (pn[i]) - break; - } - rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue]; - if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { - printk(KERN_DEBUG "%s: defrag: CCMP PN not sequential" - " A2=" MAC_FMT " PN=%02x%02x%02x%02x%02x%02x " - "(expected %02x%02x%02x%02x%02x%02x)\n", - rx->dev->name, MAC_ARG(hdr->addr2), - rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], - pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); - return TXRX_DROP; - } - memcpy(entry->last_pn, pn, CCMP_PN_LEN); - } - - skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc)); - __skb_queue_tail(&entry->skb_list, rx->skb); - entry->last_frag = frag; - entry->extra_len += rx->skb->len; - if (rx->fc & IEEE80211_FCTL_MOREFRAGS) { - rx->skb = NULL; - return TXRX_QUEUED; - } - - rx->skb = __skb_dequeue(&entry->skb_list); - if (skb_tailroom(rx->skb) < entry->extra_len) { - I802_DEBUG_INC(rx->local->rx_expand_skb_head2); - if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len, - GFP_ATOMIC))) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - __skb_queue_purge(&entry->skb_list); - return TXRX_DROP; - } - } - while ((skb = __skb_dequeue(&entry->skb_list))) { - memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len); - dev_kfree_skb(skb); - } - - /* Complete frame has been reassembled - process it now */ - rx->fragmented = 1; - - out: - if (rx->sta) - rx->sta->rx_packets++; - if (is_multicast_ether_addr(hdr->addr1)) - rx->local->dot11MulticastReceivedFrameCount++; - else - ieee80211_led_rx(rx->local); - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx) -{ - if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) { - ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status); - return TXRX_QUEUED; - } - - if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP) - skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb)); - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_hdr *hdr; - int always_sta_key; - hdr = (struct ieee80211_hdr *) rx->skb->data; - - /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ - if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { - if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && - rx->sta->last_seq_ctrl[rx->u.rx.queue] == - hdr->seq_ctrl)) { - if (rx->u.rx.ra_match) { - rx->local->dot11FrameDuplicateCount++; - rx->sta->num_duplicates++; - } - return TXRX_DROP; - } else - rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; - } - - if ((rx->local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) && - rx->skb->len > FCS_LEN) - skb_trim(rx->skb, rx->skb->len - FCS_LEN); - - if (unlikely(rx->skb->len < 16)) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_short); - return TXRX_DROP; - } - - if (!rx->u.rx.ra_match) - rx->skb->pkt_type = PACKET_OTHERHOST; - else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0) - rx->skb->pkt_type = PACKET_HOST; - else if (is_multicast_ether_addr(hdr->addr1)) { - if (is_broadcast_ether_addr(hdr->addr1)) - rx->skb->pkt_type = PACKET_BROADCAST; - else - rx->skb->pkt_type = PACKET_MULTICAST; - } else - rx->skb->pkt_type = PACKET_OTHERHOST; - - /* Drop disallowed frame classes based on STA auth/assoc state; - * IEEE 802.11, Chap 5.5. - * - * 80211.o does filtering only based on association state, i.e., it - * drops Class 3 frames from not associated stations. hostapd sends - * deauth/disassoc frames when needed. In addition, hostapd is - * responsible for filtering on both auth and assoc states. - */ - if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || - ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && - (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && - rx->sdata->type != IEEE80211_IF_TYPE_IBSS && - (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { - if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && - !(rx->fc & IEEE80211_FCTL_TODS) && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) - || !rx->u.rx.ra_match) { - /* Drop IBSS frames and frames for other hosts - * silently. */ - return TXRX_DROP; - } - - if (!rx->local->apdev) - return TXRX_DROP; - - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_sta_not_assoc); - return TXRX_QUEUED; - } - - if (rx->sdata->type == IEEE80211_IF_TYPE_STA) - always_sta_key = 0; - else - always_sta_key = 1; - - if (rx->sta && rx->sta->key && always_sta_key) { - rx->key = rx->sta->key; - } else { - if (rx->sta && rx->sta->key) - rx->key = rx->sta->key; - else - rx->key = rx->sdata->default_key; - - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->fc & IEEE80211_FCTL_PROTECTED) { - int keyidx = ieee80211_wep_get_keyidx(rx->skb); - - if (keyidx >= 0 && keyidx < NUM_DEFAULT_KEYS && - (!rx->sta || !rx->sta->key || keyidx > 0)) - rx->key = rx->sdata->keys[keyidx]; - - if (!rx->key) { - if (!rx->u.rx.ra_match) - return TXRX_DROP; - printk(KERN_DEBUG "%s: RX WEP frame with " - "unknown keyidx %d (A1=" MAC_FMT " A2=" - MAC_FMT " A3=" MAC_FMT ")\n", - rx->dev->name, keyidx, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt( - rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_wep_frame_unknown_key); - return TXRX_QUEUED; - } - } - } - - if (rx->fc & IEEE80211_FCTL_PROTECTED && rx->key && rx->u.rx.ra_match) { - rx->key->tx_rx_count++; - if (unlikely(rx->local->key_tx_rx_threshold && - rx->key->tx_rx_count > - rx->local->key_tx_rx_threshold)) { - ieee80211_key_threshold_notify(rx->dev, rx->key, - rx->sta); - } - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) -{ - struct sta_info *sta = rx->sta; - struct net_device *dev = rx->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - - if (!sta) - return TXRX_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. */ - if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) { - u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len); - if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0) - sta->last_rx = jiffies; - } else - if (!is_multicast_ether_addr(hdr->addr1) || - rx->sdata->type == IEEE80211_IF_TYPE_STA) { - /* 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. - */ - sta->last_rx = jiffies; - } - - if (!rx->u.rx.ra_match) - return TXRX_CONTINUE; - - sta->rx_fragments++; - sta->rx_bytes += rx->skb->len; - sta->last_rssi = (sta->last_rssi * 15 + - rx->u.rx.status->ssi) / 16; - sta->last_signal = (sta->last_signal * 15 + - rx->u.rx.status->signal) / 16; - sta->last_noise = (sta->last_noise * 15 + - rx->u.rx.status->noise) / 16; - - if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { - /* Change STA power saving mode only in the end of a frame - * exchange sequence */ - if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) - rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta); - else if (!(sta->flags & WLAN_STA_PS) && - (rx->fc & IEEE80211_FCTL_PM)) - ap_sta_ps_start(dev, sta); - } - - /* Drop data::nullfunc frames silently, since they are used only to - * control station power saving mode. */ - if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); - /* Update counter and free packet here to avoid counting this - * as a dropped packed. */ - sta->rx_packets++; - dev_kfree_skb(rx->skb); - return TXRX_QUEUED; - } - - return TXRX_CONTINUE; -} /* ieee80211_rx_h_sta_process */ - - -static ieee80211_txrx_result -ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) -{ - if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - !rx->key || rx->key->alg != ALG_WEP || !rx->u.rx.ra_match) - return TXRX_CONTINUE; - - /* Check for weak IVs, if hwaccel did not remove IV from the frame */ - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) || - rx->key->force_sw_encrypt) { - u8 *iv = ieee80211_wep_is_weak_iv(rx->skb, rx->key); - if (iv) { - rx->sta->wep_weak_iv_count++; - } - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) -{ - /* If the device handles decryption totally, skip this test */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) - return TXRX_CONTINUE; - - if ((rx->key && rx->key->alg != ALG_WEP) || - !(rx->fc & IEEE80211_FCTL_PROTECTED) || - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) - return TXRX_CONTINUE; - - if (!rx->key) { - printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n", - rx->dev->name); - return TXRX_DROP; - } - - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || - rx->key->force_sw_encrypt) { - if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { - printk(KERN_DEBUG "%s: RX WEP frame, decrypt " - "failed\n", rx->dev->name); - return TXRX_DROP; - } - } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); - /* remove ICV */ - skb_trim(rx->skb, rx->skb->len - 4); - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) -{ - if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && - rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) { - /* Pass both encrypted and unencrypted EAPOL frames to user - * space for processing. */ - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_normal); - return TXRX_QUEUED; - } - - if (unlikely(rx->sdata->ieee802_1x && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && - (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) && - !ieee80211_is_eapol(rx->skb))) { -#ifdef CONFIG_MAC80211_DEBUG - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) rx->skb->data; - printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT - " (unauthorized port)\n", rx->dev->name, - MAC_ARG(hdr->addr2)); -#endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) -{ - /* If the device handles decryption totally, skip this test */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) - return TXRX_CONTINUE; - - /* Drop unencrypted frames if key is set. */ - if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && - (rx->key || rx->sdata->drop_unencrypted) && - (rx->sdata->eapol == 0 || - !ieee80211_is_eapol(rx->skb)))) { - printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " - "encryption\n", rx->dev->name); - return TXRX_DROP; - } - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_sub_if_data *sdata; - - if (!rx->u.rx.ra_match) - return TXRX_DROP; - - sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); - if ((sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) && - !rx->local->user_space_mlme) { - ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); - } else { - /* Management frames are sent to hostapd for processing */ - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_normal); - } - return TXRX_QUEUED; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_local *local = rx->local; - struct sk_buff *skb = rx->skb; - - if (unlikely(local->sta_scanning != 0)) { - ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); - return TXRX_QUEUED; - } - - if (unlikely(rx->u.rx.in_scan)) { - /* scanning finished during invoking of handlers */ - I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return TXRX_DROP; - } - - return TXRX_CONTINUE; -} - - -static void ieee80211_rx_michael_mic_report(struct net_device *dev, - struct ieee80211_hdr *hdr, - struct sta_info *sta, - struct ieee80211_txrx_data *rx) -{ - int keyidx, hdrlen; - - hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb); - if (rx->skb->len >= hdrlen + 4) - keyidx = rx->skb->data[hdrlen + 3] >> 6; - else - keyidx = -1; - - /* TODO: verify that this is not triggered by fragmented - * frames (hw does not verify MIC for them). */ - printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " - "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", - dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), keyidx); - - if (!sta) { - /* Some hardware versions seem to generate incorrect - * Michael MIC reports; ignore them to avoid triggering - * countermeasures. */ - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for unknown address " MAC_FMT "\n", - dev->name, MAC_ARG(hdr->addr2)); - goto ignore; - } - - if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) { - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame with no ISWEP flag (src " - MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); - goto ignore; - } - - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->sdata->type == IEEE80211_IF_TYPE_AP) { - keyidx = ieee80211_wep_get_keyidx(rx->skb); - /* AP with Pairwise keys support should never receive Michael - * MIC errors for non-zero keyidx because these are reserved - * for group keys and only the AP is sending real multicast - * frames in BSS. */ - if (keyidx) { - printk(KERN_DEBUG "%s: ignored Michael MIC error for " - "a frame with non-zero keyidx (%d) (src " MAC_FMT - ")\n", dev->name, keyidx, MAC_ARG(hdr->addr2)); - goto ignore; - } - } - - if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) { - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame that cannot be encrypted " - "(fc=0x%04x) (src " MAC_FMT ")\n", - dev->name, rx->fc, MAC_ARG(hdr->addr2)); - goto ignore; - } - - do { - union iwreq_data wrqu; - char *buf = kmalloc(128, GFP_ATOMIC); - if (!buf) - break; - - /* TODO: needed parameters: count, key type, TSC */ - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=" MAC_FMT ")", - keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); - wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf); - kfree(buf); - } while (0); - - /* TODO: consider verifying the MIC error report with software - * implementation if we get too many spurious reports from the - * hardware. */ - if (!rx->local->apdev) - goto ignore; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_michael_mic_failure); - return; - - ignore: - dev_kfree_skb(rx->skb); - rx->skb = NULL; -} - -static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( - struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) -{ - ieee80211_rx_handler *handler; - ieee80211_txrx_result res = TXRX_DROP; - - for (handler = handlers; *handler != NULL; handler++) { - res = (*handler)(rx); - if (res != TXRX_CONTINUE) { - if (res == TXRX_DROP) { - I802_DEBUG_INC(local->rx_handlers_drop); - if (sta) - sta->rx_dropped++; - } - if (res == TXRX_QUEUED) - I802_DEBUG_INC(local->rx_handlers_queued); - break; - } - } - - if (res == TXRX_DROP) { - dev_kfree_skb(rx->skb); - } - return res; -} - -static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) -{ - if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == - TXRX_CONTINUE) - dev_kfree_skb(rx->skb); -} - -/* - * 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) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; - struct ieee80211_hdr *hdr; - struct ieee80211_txrx_data rx; - u16 type; - int multicast; - int radiotap_len = 0; - - if (status->flag & RX_FLAG_RADIOTAP) { - radiotap_len = ieee80211_get_radiotap_len(skb); - skb_pull(skb, radiotap_len); - } - - hdr = (struct ieee80211_hdr *) skb->data; - memset(&rx, 0, sizeof(rx)); - rx.skb = skb; - rx.local = local; - - rx.u.rx.status = status; - rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0; - type = rx.fc & IEEE80211_FCTL_FTYPE; - if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) - local->dot11ReceivedFragmentCount++; - multicast = is_multicast_ether_addr(hdr->addr1); - - if (skb->len >= 16) - sta = rx.sta = sta_info_get(local, hdr->addr2); - else - sta = rx.sta = NULL; - - if (sta) { - rx.dev = sta->dev; - rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); - } - - if ((status->flag & RX_FLAG_MMIC_ERROR)) { - ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); - goto end; - } - - if (unlikely(local->sta_scanning)) - rx.u.rx.in_scan = 1; - - if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, - sta) != TXRX_CONTINUE) - goto end; - skb = rx.skb; - - skb_push(skb, radiotap_len); - if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) && - !local->iff_promiscs && !multicast) { - rx.u.rx.ra_match = 1; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, - sta); - } else { - struct ieee80211_sub_if_data *prev = NULL; - struct sk_buff *skb_new; - u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len); - - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - rx.u.rx.ra_match = 1; - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - if (!bssid) - continue; - if (!ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { - if (!sdata->promisc) - continue; - rx.u.rx.ra_match = 0; - } - break; - case IEEE80211_IF_TYPE_IBSS: - if (!bssid) - continue; - if (!ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { - if (!sdata->promisc) - continue; - rx.u.rx.ra_match = 0; - } else if (!sta) - sta = rx.sta = - ieee80211_ibss_add_sta(sdata->dev, - skb, bssid, - hdr->addr2); - break; - case IEEE80211_IF_TYPE_AP: - if (!bssid) { - if (compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) - continue; - } else if (!ieee80211_bssid_match(bssid, - sdata->dev->dev_addr)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } - if (sdata->dev == local->mdev && - !rx.u.rx.in_scan) - /* do not receive anything via - * master device when not scanning */ - continue; - break; - case IEEE80211_IF_TYPE_WDS: - if (bssid || - (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - continue; - if (compare_ether_addr(sdata->u.wds.remote_addr, - hdr->addr2) != 0) - continue; - break; - } - - if (prev) { - skb_new = skb_copy(skb, GFP_ATOMIC); - if (!skb_new) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: failed to copy " - "multicast frame for %s", - local->mdev->name, prev->dev->name); - continue; - } - rx.skb = skb_new; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, - local->rx_handlers, - &rx, sta); - } - prev = sdata; - } - if (prev) { - rx.skb = skb; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); - } else - dev_kfree_skb(skb); - read_unlock(&local->sub_if_lock); - } - - end: - if (sta) - sta_info_put(sta); -} -EXPORT_SYMBOL(__ieee80211_rx); - static ieee80211_txrx_result ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) { @@ -4215,65 +2970,6 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) } -static ieee80211_txrx_result -ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_local *local = rx->local; - struct sk_buff *skb = rx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - struct ieee80211_rate *rate; - struct ieee80211_hw_mode *mode = local->hw.conf.mode; - int i; - - /* Estimate total channel use caused by this frame */ - - if (unlikely(mode->num_rates < 0)) - return TXRX_CONTINUE; - - rate = &mode->rates[0]; - for (i = 0; i < mode->num_rates; i++) { - if (mode->rates[i].val == rx->u.rx.status->rate) { - rate = &mode->rates[i]; - break; - } - } - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (mode->mode == MODE_IEEE80211A || - mode->mode == MODE_ATHEROS_TURBO || - mode->mode == MODE_ATHEROS_TURBOG || - (mode->mode == MODE_IEEE80211G && - rate->flags & IEEE80211_RATE_ERP)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - load += skb->len * rate->rate_inv; - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - local->channel_use_raw += load; - if (rx->sta) - rx->sta->channel_use_raw += load; - rx->u.rx.load = load; - - return TXRX_CONTINUE; -} - -static ieee80211_txrx_result -ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) -{ - rx->sdata->channel_use_raw += rx->u.rx.load; - return TXRX_CONTINUE; -} - static void ieee80211_stat_refresh(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; @@ -4311,24 +3007,6 @@ static void ieee80211_stat_refresh(unsigned long data) } -/* 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) -{ - 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); -} -EXPORT_SYMBOL(ieee80211_rx_irqsafe); - void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) @@ -4690,41 +3368,6 @@ EXPORT_SYMBOL(ieee80211_tx_status); /* TODO: implement register/unregister functions for adding TX/RX handlers * into ordered list */ -/* rx_pre handlers don't have dev and sdata fields available in - * ieee80211_txrx_data */ -static ieee80211_rx_handler ieee80211_rx_pre_handlers[] = -{ - ieee80211_rx_h_parse_qos, - ieee80211_rx_h_load_stats, - NULL -}; - -static ieee80211_rx_handler ieee80211_rx_handlers[] = -{ - ieee80211_rx_h_if_stats, - ieee80211_rx_h_monitor, - ieee80211_rx_h_passive_scan, - ieee80211_rx_h_check, - ieee80211_rx_h_sta_process, - ieee80211_rx_h_ccmp_decrypt, - ieee80211_rx_h_tkip_decrypt, - ieee80211_rx_h_wep_weak_iv_detection, - ieee80211_rx_h_wep_decrypt, - ieee80211_rx_h_defragment, - ieee80211_rx_h_ps_poll, - ieee80211_rx_h_michael_mic_verify, - /* this must be after decryption - so header is counted in MPDU mic - * must be before pae and data, so QOS_DATA format frames - * are not passed to user space by these functions - */ - ieee80211_rx_h_remove_qos_control, - ieee80211_rx_h_802_1x_pae, - ieee80211_rx_h_drop_unencrypted, - ieee80211_rx_h_data, - ieee80211_rx_h_mgmt, - NULL -}; - static ieee80211_tx_handler ieee80211_tx_handlers[] = { ieee80211_tx_h_check_assoc, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6f7bae7ef9c0..35e2ce52faeb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "ieee80211_key.h" #include "sta_info.h" @@ -707,6 +708,13 @@ static inline int ieee80211_is_erp_rate(int phymode, int rate) return 0; } +static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) +{ + return compare_ether_addr(raddr, addr) == 0 || + is_broadcast_ether_addr(raddr); +} + + /* ieee80211.c */ int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); @@ -730,6 +738,16 @@ void ieee80211_if_mgmt_setup(struct net_device *dev); int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, const char *name); struct net_device_stats *ieee80211_dev_stats(struct net_device *dev); +struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, + int phymode, int hwrate); +void ieee80211_key_threshold_notify(struct net_device *dev, + struct ieee80211_key *key, + struct sta_info *sta); +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); +int ieee80211_is_eapol(const struct sk_buff *skb); + +extern const unsigned char rfc1042_header[]; +extern const unsigned char bridge_tunnel_header[]; /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; @@ -801,6 +819,10 @@ void ieee80211_if_del_mgmt(struct ieee80211_local *local); void ieee80211_regdomain_init(void); void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode); +/* rx handling */ +extern ieee80211_rx_handler ieee80211_rx_pre_handlers[]; +extern ieee80211_rx_handler ieee80211_rx_handlers[]; + /* for wiphy privid */ extern void *mac80211_wiphy_privid; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c new file mode 100644 index 000000000000..8c0d14c5628f --- /dev/null +++ b/net/mac80211/rx.c @@ -0,0 +1,1360 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007 Johannes Berg + * + * 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 "ieee80211_i.h" +#include "ieee80211_led.h" +#include "ieee80211_common.h" +#include "wep.h" +#include "wpa.h" +#include "tkip.h" +#include "wme.h" + +/* pre-rx handlers + * + * these don't have dev/sdata fields in the rx data + */ + +static ieee80211_txrx_result +ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_local *local = rx->local; + struct sk_buff *skb = rx->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u32 load = 0, hdrtime; + struct ieee80211_rate *rate; + struct ieee80211_hw_mode *mode = local->hw.conf.mode; + int i; + + /* Estimate total channel use caused by this frame */ + + if (unlikely(mode->num_rates < 0)) + return TXRX_CONTINUE; + + rate = &mode->rates[0]; + for (i = 0; i < mode->num_rates; i++) { + if (mode->rates[i].val == rx->u.rx.status->rate) { + rate = &mode->rates[i]; + break; + } + } + + /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, + * 1 usec = 1/8 * (1080 / 10) = 13.5 */ + + if (mode->mode == MODE_IEEE80211A || + mode->mode == MODE_ATHEROS_TURBO || + mode->mode == MODE_ATHEROS_TURBOG || + (mode->mode == MODE_IEEE80211G && + rate->flags & IEEE80211_RATE_ERP)) + hdrtime = CHAN_UTIL_HDR_SHORT; + else + hdrtime = CHAN_UTIL_HDR_LONG; + + load = hdrtime; + if (!is_multicast_ether_addr(hdr->addr1)) + load += hdrtime; + + load += skb->len * rate->rate_inv; + + /* Divide channel_use by 8 to avoid wrapping around the counter */ + load >>= CHAN_UTIL_SHIFT; + local->channel_use_raw += load; + if (rx->sta) + rx->sta->channel_use_raw += load; + rx->u.rx.load = load; + + return TXRX_CONTINUE; +} + +ieee80211_rx_handler ieee80211_rx_pre_handlers[] = +{ + ieee80211_rx_h_parse_qos, + ieee80211_rx_h_load_stats, + NULL +}; + +/* rx handlers */ + +static ieee80211_txrx_result +ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) +{ + rx->sdata->channel_use_raw += rx->u.rx.load; + return TXRX_CONTINUE; +} + +static void +ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, + struct ieee80211_rx_status *status) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata; + struct ieee80211_rate *rate; + struct ieee80211_rtap_hdr { + struct ieee80211_radiotap_header hdr; + u8 flags; + u8 rate; + __le16 chan_freq; + __le16 chan_flags; + u8 antsignal; + } __attribute__ ((packed)) *rthdr; + + skb->dev = dev; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (status->flag & RX_FLAG_RADIOTAP) + goto out; + + if (skb_headroom(skb) < sizeof(*rthdr)) { + I802_DEBUG_INC(local->rx_expand_skb_head); + if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return; + } + } + + rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr)); + memset(rthdr, 0, sizeof(*rthdr)); + rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); + rthdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)); + rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? + IEEE80211_RADIOTAP_F_FCS : 0; + rate = ieee80211_get_rate(local, status->phymode, status->rate); + if (rate) + rthdr->rate = rate->rate / 5; + rthdr->chan_freq = cpu_to_le16(status->freq); + rthdr->chan_flags = + status->phymode == MODE_IEEE80211A ? + cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) : + cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ); + rthdr->antsignal = status->ssi; + + out: + sdata->stats.rx_packets++; + sdata->stats.rx_bytes += skb->len; + + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + +static ieee80211_txrx_result +ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx) +{ + if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) { + ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status); + return TXRX_QUEUED; + } + + if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP) + skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb->data)); + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_local *local = rx->local; + struct sk_buff *skb = rx->skb; + + if (unlikely(local->sta_scanning != 0)) { + ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); + return TXRX_QUEUED; + } + + if (unlikely(rx->u.rx.in_scan)) { + /* scanning finished during invoking of handlers */ + I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); + return TXRX_DROP; + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_hdr *hdr; + int always_sta_key; + hdr = (struct ieee80211_hdr *) rx->skb->data; + + /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ + if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { + if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && + rx->sta->last_seq_ctrl[rx->u.rx.queue] == + hdr->seq_ctrl)) { + if (rx->u.rx.ra_match) { + rx->local->dot11FrameDuplicateCount++; + rx->sta->num_duplicates++; + } + return TXRX_DROP; + } else + rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; + } + + if ((rx->local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) && + rx->skb->len > FCS_LEN) + skb_trim(rx->skb, rx->skb->len - FCS_LEN); + + if (unlikely(rx->skb->len < 16)) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_short); + return TXRX_DROP; + } + + if (!rx->u.rx.ra_match) + rx->skb->pkt_type = PACKET_OTHERHOST; + else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0) + rx->skb->pkt_type = PACKET_HOST; + else if (is_multicast_ether_addr(hdr->addr1)) { + if (is_broadcast_ether_addr(hdr->addr1)) + rx->skb->pkt_type = PACKET_BROADCAST; + else + rx->skb->pkt_type = PACKET_MULTICAST; + } else + rx->skb->pkt_type = PACKET_OTHERHOST; + + /* Drop disallowed frame classes based on STA auth/assoc state; + * IEEE 802.11, Chap 5.5. + * + * 80211.o does filtering only based on association state, i.e., it + * drops Class 3 frames from not associated stations. hostapd sends + * deauth/disassoc frames when needed. In addition, hostapd is + * responsible for filtering on both auth and assoc states. + */ + if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || + ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && + (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && + rx->sdata->type != IEEE80211_IF_TYPE_IBSS && + (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { + if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && + !(rx->fc & IEEE80211_FCTL_TODS) && + (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) + || !rx->u.rx.ra_match) { + /* Drop IBSS frames and frames for other hosts + * silently. */ + return TXRX_DROP; + } + + if (!rx->local->apdev) + return TXRX_DROP; + + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, + ieee80211_msg_sta_not_assoc); + return TXRX_QUEUED; + } + + if (rx->sdata->type == IEEE80211_IF_TYPE_STA) + always_sta_key = 0; + else + always_sta_key = 1; + + if (rx->sta && rx->sta->key && always_sta_key) { + rx->key = rx->sta->key; + } else { + if (rx->sta && rx->sta->key) + rx->key = rx->sta->key; + else + rx->key = rx->sdata->default_key; + + if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && + rx->fc & IEEE80211_FCTL_PROTECTED) { + int keyidx = ieee80211_wep_get_keyidx(rx->skb); + + if (keyidx >= 0 && keyidx < NUM_DEFAULT_KEYS && + (!rx->sta || !rx->sta->key || keyidx > 0)) + rx->key = rx->sdata->keys[keyidx]; + + if (!rx->key) { + if (!rx->u.rx.ra_match) + return TXRX_DROP; + printk(KERN_DEBUG "%s: RX WEP frame with " + "unknown keyidx %d (A1=" MAC_FMT " A2=" + MAC_FMT " A3=" MAC_FMT ")\n", + rx->dev->name, keyidx, + MAC_ARG(hdr->addr1), + MAC_ARG(hdr->addr2), + MAC_ARG(hdr->addr3)); + if (!rx->local->apdev) + return TXRX_DROP; + ieee80211_rx_mgmt( + rx->local, rx->skb, rx->u.rx.status, + ieee80211_msg_wep_frame_unknown_key); + return TXRX_QUEUED; + } + } + } + + if (rx->fc & IEEE80211_FCTL_PROTECTED && rx->key && rx->u.rx.ra_match) { + rx->key->tx_rx_count++; + if (unlikely(rx->local->key_tx_rx_threshold && + rx->key->tx_rx_count > + rx->local->key_tx_rx_threshold)) { + ieee80211_key_threshold_notify(rx->dev, rx->key, + rx->sta); + } + } + + return TXRX_CONTINUE; +} + +static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata; + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + if (sdata->bss) + atomic_inc(&sdata->bss->num_sta_ps); + sta->flags |= WLAN_STA_PS; + sta->pspoll = 0; +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power " + "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ +} + +static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + int sent = 0; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_packet_data *pkt_data; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + if (sdata->bss) + atomic_dec(&sdata->bss->num_sta_ps); + sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM); + sta->pspoll = 0; + if (!skb_queue_empty(&sta->ps_tx_buf)) { + if (local->ops->set_tim) + local->ops->set_tim(local_to_hw(local), sta->aid, 0); + if (sdata->bss) + bss_tim_clear(local, sdata->bss, sta->aid); + } +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power " + "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + /* Send all buffered frames to the station */ + while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { + pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + sent++; + pkt_data->requeue = 1; + dev_queue_xmit(skb); + } + while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { + pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + local->total_ps_buffered--; + sent++; +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame " + "since STA not sleeping anymore\n", dev->name, + MAC_ARG(sta->addr), sta->aid); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + pkt_data->requeue = 1; + dev_queue_xmit(skb); + } + + return sent; +} + +static ieee80211_txrx_result +ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) +{ + struct sta_info *sta = rx->sta; + struct net_device *dev = rx->dev; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + + if (!sta) + return TXRX_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. */ + if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) { + u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len); + if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0) + sta->last_rx = jiffies; + } else + if (!is_multicast_ether_addr(hdr->addr1) || + rx->sdata->type == IEEE80211_IF_TYPE_STA) { + /* 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. + */ + sta->last_rx = jiffies; + } + + if (!rx->u.rx.ra_match) + return TXRX_CONTINUE; + + sta->rx_fragments++; + sta->rx_bytes += rx->skb->len; + sta->last_rssi = (sta->last_rssi * 15 + + rx->u.rx.status->ssi) / 16; + sta->last_signal = (sta->last_signal * 15 + + rx->u.rx.status->signal) / 16; + sta->last_noise = (sta->last_noise * 15 + + rx->u.rx.status->noise) / 16; + + if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { + /* Change STA power saving mode only in the end of a frame + * exchange sequence */ + if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) + rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta); + else if (!(sta->flags & WLAN_STA_PS) && + (rx->fc & IEEE80211_FCTL_PM)) + ap_sta_ps_start(dev, sta); + } + + /* Drop data::nullfunc frames silently, since they are used only to + * control station power saving mode. */ + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); + /* Update counter and free packet here to avoid counting this + * as a dropped packed. */ + sta->rx_packets++; + dev_kfree_skb(rx->skb); + return TXRX_QUEUED; + } + + return TXRX_CONTINUE; +} /* ieee80211_rx_h_sta_process */ + +static ieee80211_txrx_result +ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) +{ + if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) || + (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || + !rx->key || rx->key->alg != ALG_WEP || !rx->u.rx.ra_match) + return TXRX_CONTINUE; + + /* Check for weak IVs, if hwaccel did not remove IV from the frame */ + if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) || + rx->key->force_sw_encrypt) { + u8 *iv = ieee80211_wep_is_weak_iv(rx->skb, rx->key); + if (iv) { + rx->sta->wep_weak_iv_count++; + } + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) +{ + /* If the device handles decryption totally, skip this test */ + if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) + return TXRX_CONTINUE; + + if ((rx->key && rx->key->alg != ALG_WEP) || + !(rx->fc & IEEE80211_FCTL_PROTECTED) || + ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && + ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) + return TXRX_CONTINUE; + + if (!rx->key) { + printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n", + rx->dev->name); + return TXRX_DROP; + } + + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || + rx->key->force_sw_encrypt) { + if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { + printk(KERN_DEBUG "%s: RX WEP frame, decrypt " + "failed\n", rx->dev->name); + return TXRX_DROP; + } + } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { + ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); + /* remove ICV */ + skb_trim(rx->skb, rx->skb->len - 4); + } + + return TXRX_CONTINUE; +} + +static inline struct ieee80211_fragment_entry * +ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, + unsigned int frag, unsigned int seq, int rx_queue, + struct sk_buff **skb) +{ + struct ieee80211_fragment_entry *entry; + int idx; + + idx = sdata->fragment_next; + entry = &sdata->fragments[sdata->fragment_next++]; + if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) + sdata->fragment_next = 0; + + if (!skb_queue_empty(&entry->skb_list)) { +#ifdef CONFIG_MAC80211_DEBUG + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) entry->skb_list.next->data; + printk(KERN_DEBUG "%s: RX reassembly removed oldest " + "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " + "addr1=" MAC_FMT " addr2=" MAC_FMT "\n", + sdata->dev->name, idx, + jiffies - entry->first_frag_time, entry->seq, + entry->last_frag, MAC_ARG(hdr->addr1), + MAC_ARG(hdr->addr2)); +#endif /* CONFIG_MAC80211_DEBUG */ + __skb_queue_purge(&entry->skb_list); + } + + __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ + *skb = NULL; + entry->first_frag_time = jiffies; + entry->seq = seq; + entry->rx_queue = rx_queue; + entry->last_frag = frag; + entry->ccmp = 0; + entry->extra_len = 0; + + return entry; +} + +static inline struct ieee80211_fragment_entry * +ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, + u16 fc, unsigned int frag, unsigned int seq, + int rx_queue, struct ieee80211_hdr *hdr) +{ + struct ieee80211_fragment_entry *entry; + int i, idx; + + idx = sdata->fragment_next; + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { + struct ieee80211_hdr *f_hdr; + u16 f_fc; + + idx--; + if (idx < 0) + idx = IEEE80211_FRAGMENT_MAX - 1; + + entry = &sdata->fragments[idx]; + if (skb_queue_empty(&entry->skb_list) || entry->seq != seq || + entry->rx_queue != rx_queue || + entry->last_frag + 1 != frag) + continue; + + f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; + f_fc = le16_to_cpu(f_hdr->frame_control); + + if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) || + compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 || + compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0) + continue; + + if (entry->first_frag_time + 2 * HZ < jiffies) { + __skb_queue_purge(&entry->skb_list); + continue; + } + return entry; + } + + return NULL; +} + +static ieee80211_txrx_result +ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_hdr *hdr; + u16 sc; + unsigned int frag, seq; + struct ieee80211_fragment_entry *entry; + struct sk_buff *skb; + + hdr = (struct ieee80211_hdr *) rx->skb->data; + sc = le16_to_cpu(hdr->seq_ctrl); + frag = sc & IEEE80211_SCTL_FRAG; + + if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) || + (rx->skb)->len < 24 || + is_multicast_ether_addr(hdr->addr1))) { + /* not fragmented */ + goto out; + } + I802_DEBUG_INC(rx->local->rx_handlers_fragments); + + seq = (sc & IEEE80211_SCTL_SEQ) >> 4; + + if (frag == 0) { + /* This is the first fragment of a new frame. */ + entry = ieee80211_reassemble_add(rx->sdata, frag, seq, + rx->u.rx.queue, &(rx->skb)); + if (rx->key && rx->key->alg == ALG_CCMP && + (rx->fc & IEEE80211_FCTL_PROTECTED)) { + /* Store CCMP PN so that we can verify that the next + * fragment has a sequential PN value. */ + entry->ccmp = 1; + memcpy(entry->last_pn, + rx->key->u.ccmp.rx_pn[rx->u.rx.queue], + CCMP_PN_LEN); + } + return TXRX_QUEUED; + } + + /* This is a fragment for a frame that should already be pending in + * fragment cache. Add this fragment to the end of the pending entry. + */ + entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq, + rx->u.rx.queue, hdr); + if (!entry) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); + return TXRX_DROP; + } + + /* Verify that MPDUs within one MSDU have sequential PN values. + * (IEEE 802.11i, 8.3.3.4.5) */ + if (entry->ccmp) { + int i; + u8 pn[CCMP_PN_LEN], *rpn; + if (!rx->key || rx->key->alg != ALG_CCMP) + return TXRX_DROP; + memcpy(pn, entry->last_pn, CCMP_PN_LEN); + for (i = CCMP_PN_LEN - 1; i >= 0; i--) { + pn[i]++; + if (pn[i]) + break; + } + rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue]; + if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { + printk(KERN_DEBUG "%s: defrag: CCMP PN not sequential" + " A2=" MAC_FMT " PN=%02x%02x%02x%02x%02x%02x " + "(expected %02x%02x%02x%02x%02x%02x)\n", + rx->dev->name, MAC_ARG(hdr->addr2), + rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], + pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); + return TXRX_DROP; + } + memcpy(entry->last_pn, pn, CCMP_PN_LEN); + } + + skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc)); + __skb_queue_tail(&entry->skb_list, rx->skb); + entry->last_frag = frag; + entry->extra_len += rx->skb->len; + if (rx->fc & IEEE80211_FCTL_MOREFRAGS) { + rx->skb = NULL; + return TXRX_QUEUED; + } + + rx->skb = __skb_dequeue(&entry->skb_list); + if (skb_tailroom(rx->skb) < entry->extra_len) { + I802_DEBUG_INC(rx->local->rx_expand_skb_head2); + if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len, + GFP_ATOMIC))) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); + __skb_queue_purge(&entry->skb_list); + return TXRX_DROP; + } + } + while ((skb = __skb_dequeue(&entry->skb_list))) { + memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len); + dev_kfree_skb(skb); + } + + /* Complete frame has been reassembled - process it now */ + rx->fragmented = 1; + + out: + if (rx->sta) + rx->sta->rx_packets++; + if (is_multicast_ether_addr(hdr->addr1)) + rx->local->dot11MulticastReceivedFrameCount++; + else + ieee80211_led_rx(rx->local); + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) +{ + struct sk_buff *skb; + int no_pending_pkts; + + if (likely(!rx->sta || + (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || + !rx->u.rx.ra_match)) + return TXRX_CONTINUE; + + skb = skb_dequeue(&rx->sta->tx_filtered); + if (!skb) { + skb = skb_dequeue(&rx->sta->ps_tx_buf); + if (skb) + rx->local->total_ps_buffered--; + } + no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) && + skb_queue_empty(&rx->sta->ps_tx_buf); + + if (skb) { + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) skb->data; + + /* tell TX path to send one frame even though the STA may + * still remain is PS mode after this frame exchange */ + rx->sta->pspoll = 1; + +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries " + "after %d)\n", + MAC_ARG(rx->sta->addr), rx->sta->aid, + skb_queue_len(&rx->sta->ps_tx_buf)); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + + /* Use MoreData flag to indicate whether there are more + * buffered frames for this STA */ + if (no_pending_pkts) { + hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); + rx->sta->flags &= ~WLAN_STA_TIM; + } else + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + + dev_queue_xmit(skb); + + if (no_pending_pkts) { + if (rx->local->ops->set_tim) + rx->local->ops->set_tim(local_to_hw(rx->local), + rx->sta->aid, 0); + if (rx->sdata->bss) + bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid); + } +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + } else if (!rx->u.rx.sent_ps_buffered) { + printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even " + "though there is no buffered frames for it\n", + rx->dev->name, MAC_ARG(rx->sta->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + + } + + /* Free PS Poll skb here instead of returning TXRX_DROP that would + * count as an dropped frame. */ + dev_kfree_skb(rx->skb); + + return TXRX_QUEUED; +} + +static ieee80211_txrx_result +ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) +{ + if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && + rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) { + /* Pass both encrypted and unencrypted EAPOL frames to user + * space for processing. */ + if (!rx->local->apdev) + return TXRX_DROP; + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, + ieee80211_msg_normal); + return TXRX_QUEUED; + } + + if (unlikely(rx->sdata->ieee802_1x && + (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && + (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) && + !ieee80211_is_eapol(rx->skb))) { +#ifdef CONFIG_MAC80211_DEBUG + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) rx->skb->data; + printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT + " (unauthorized port)\n", rx->dev->name, + MAC_ARG(hdr->addr2)); +#endif /* CONFIG_MAC80211_DEBUG */ + return TXRX_DROP; + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) +{ + /* If the device handles decryption totally, skip this test */ + if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) + return TXRX_CONTINUE; + + /* Drop unencrypted frames if key is set. */ + if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && + (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && + (rx->key || rx->sdata->drop_unencrypted) && + (rx->sdata->eapol == 0 || + !ieee80211_is_eapol(rx->skb)))) { + printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " + "encryption\n", rx->dev->name); + return TXRX_DROP; + } + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) +{ + struct net_device *dev = rx->dev; + struct ieee80211_local *local = rx->local; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + u16 fc, hdrlen, ethertype; + u8 *payload; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + struct sk_buff *skb = rx->skb, *skb2; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + fc = rx->fc; + if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) + return TXRX_CONTINUE; + + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return TXRX_DROP; + + hdrlen = ieee80211_get_hdrlen(fc); + + /* convert IEEE 802.11 header + possible LLC headers into Ethernet + * header + * IEEE 802.11 address fields: + * ToDS FromDS Addr1 Addr2 Addr3 Addr4 + * 0 0 DA SA BSSID n/a + * 0 1 DA BSSID SA n/a + * 1 0 BSSID SA DA n/a + * 1 1 RA TA DA SA + */ + + switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { + case IEEE80211_FCTL_TODS: + /* BSSID SA DA */ + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + + if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP && + sdata->type != IEEE80211_IF_TYPE_VLAN)) { + printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID=" + MAC_FMT " SA=" MAC_FMT " DA=" MAC_FMT ")\n", + dev->name, MAC_ARG(hdr->addr1), + MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3)); + return TXRX_DROP; + } + break; + case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + /* RA TA DA SA */ + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr4, ETH_ALEN); + + if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) { + printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame (RA=" + MAC_FMT " TA=" MAC_FMT " DA=" MAC_FMT " SA=" + MAC_FMT ")\n", + rx->dev->name, MAC_ARG(hdr->addr1), + MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3), + MAC_ARG(hdr->addr4)); + return TXRX_DROP; + } + break; + case IEEE80211_FCTL_FROMDS: + /* DA BSSID SA */ + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr3, ETH_ALEN); + + if (sdata->type != IEEE80211_IF_TYPE_STA) { + return TXRX_DROP; + } + break; + case 0: + /* DA SA BSSID */ + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + + if (sdata->type != IEEE80211_IF_TYPE_IBSS) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: dropped IBSS frame (DA=" + MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT + ")\n", + dev->name, MAC_ARG(hdr->addr1), + MAC_ARG(hdr->addr2), + MAC_ARG(hdr->addr3)); + } + return TXRX_DROP; + } + break; + } + + payload = skb->data + hdrlen; + + if (unlikely(skb->len - hdrlen < 8)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: RX too short data frame " + "payload\n", dev->name); + } + return TXRX_DROP; + } + + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + 6); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + struct ethhdr *ehdr; + __be16 len; + skb_pull(skb, hdrlen); + len = htons(skb->len); + ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dst, ETH_ALEN); + memcpy(ehdr->h_source, src, ETH_ALEN); + ehdr->h_proto = len; + } + skb->dev = dev; + + skb2 = NULL; + + sdata->stats.rx_packets++; + sdata->stats.rx_bytes += skb->len; + + if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP + || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) { + if (is_multicast_ether_addr(skb->data)) { + /* send multicast frames both to higher layers in + * local net stack and back to the wireless media */ + skb2 = skb_copy(skb, GFP_ATOMIC); + if (!skb2) + printk(KERN_DEBUG "%s: failed to clone " + "multicast frame\n", dev->name); + } else { + struct sta_info *dsta; + dsta = sta_info_get(local, skb->data); + if (dsta && !dsta->dev) { + printk(KERN_DEBUG "Station with null dev " + "structure!\n"); + } else if (dsta && dsta->dev == dev) { + /* Destination station is associated to this + * AP, so send the frame directly to it and + * do not pass the frame to local net stack. + */ + skb2 = skb; + skb = NULL; + } + if (dsta) + sta_info_put(dsta); + } + } + + if (skb) { + /* deliver to local stack */ + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); + } + + if (skb2) { + /* send to wireless media */ + skb2->protocol = __constant_htons(ETH_P_802_3); + skb_set_network_header(skb2, 0); + skb_set_mac_header(skb2, 0); + dev_queue_xmit(skb2); + } + + return TXRX_QUEUED; +} + +static ieee80211_txrx_result +ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_sub_if_data *sdata; + + if (!rx->u.rx.ra_match) + return TXRX_DROP; + + sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); + if ((sdata->type == IEEE80211_IF_TYPE_STA || + sdata->type == IEEE80211_IF_TYPE_IBSS) && + !rx->local->user_space_mlme) { + ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); + } else { + /* Management frames are sent to hostapd for processing */ + if (!rx->local->apdev) + return TXRX_DROP; + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, + ieee80211_msg_normal); + } + return TXRX_QUEUED; +} + +static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( + struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) +{ + ieee80211_rx_handler *handler; + ieee80211_txrx_result res = TXRX_DROP; + + for (handler = handlers; *handler != NULL; handler++) { + res = (*handler)(rx); + if (res != TXRX_CONTINUE) { + if (res == TXRX_DROP) { + I802_DEBUG_INC(local->rx_handlers_drop); + if (sta) + sta->rx_dropped++; + } + if (res == TXRX_QUEUED) + I802_DEBUG_INC(local->rx_handlers_queued); + break; + } + } + + if (res == TXRX_DROP) { + dev_kfree_skb(rx->skb); + } + return res; +} + +static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) +{ + if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == + TXRX_CONTINUE) + dev_kfree_skb(rx->skb); +} + +static void ieee80211_rx_michael_mic_report(struct net_device *dev, + struct ieee80211_hdr *hdr, + struct sta_info *sta, + struct ieee80211_txrx_data *rx) +{ + int keyidx, hdrlen; + + hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb); + if (rx->skb->len >= hdrlen + 4) + keyidx = rx->skb->data[hdrlen + 3] >> 6; + else + keyidx = -1; + + /* TODO: verify that this is not triggered by fragmented + * frames (hw does not verify MIC for them). */ + printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " + "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", + dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), keyidx); + + if (!sta) { + /* Some hardware versions seem to generate incorrect + * Michael MIC reports; ignore them to avoid triggering + * countermeasures. */ + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for unknown address " MAC_FMT "\n", + dev->name, MAC_ARG(hdr->addr2)); + goto ignore; + } + + if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) { + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for a frame with no ISWEP flag (src " + MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); + goto ignore; + } + + if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && + rx->sdata->type == IEEE80211_IF_TYPE_AP) { + keyidx = ieee80211_wep_get_keyidx(rx->skb); + /* AP with Pairwise keys support should never receive Michael + * MIC errors for non-zero keyidx because these are reserved + * for group keys and only the AP is sending real multicast + * frames in BSS. */ + if (keyidx) { + printk(KERN_DEBUG "%s: ignored Michael MIC error for " + "a frame with non-zero keyidx (%d) (src " MAC_FMT + ")\n", dev->name, keyidx, MAC_ARG(hdr->addr2)); + goto ignore; + } + } + + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && + ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) { + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for a frame that cannot be encrypted " + "(fc=0x%04x) (src " MAC_FMT ")\n", + dev->name, rx->fc, MAC_ARG(hdr->addr2)); + goto ignore; + } + + do { + union iwreq_data wrqu; + char *buf = kmalloc(128, GFP_ATOMIC); + if (!buf) + break; + + /* TODO: needed parameters: count, key type, TSC */ + sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" + "keyid=%d %scast addr=" MAC_FMT ")", + keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", + MAC_ARG(hdr->addr2)); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(buf); + wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf); + kfree(buf); + } while (0); + + /* TODO: consider verifying the MIC error report with software + * implementation if we get too many spurious reports from the + * hardware. */ + if (!rx->local->apdev) + goto ignore; + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, + ieee80211_msg_michael_mic_failure); + return; + + ignore: + dev_kfree_skb(rx->skb); + rx->skb = NULL; +} + +ieee80211_rx_handler ieee80211_rx_handlers[] = +{ + ieee80211_rx_h_if_stats, + ieee80211_rx_h_monitor, + ieee80211_rx_h_passive_scan, + ieee80211_rx_h_check, + ieee80211_rx_h_sta_process, + ieee80211_rx_h_ccmp_decrypt, + ieee80211_rx_h_tkip_decrypt, + ieee80211_rx_h_wep_weak_iv_detection, + ieee80211_rx_h_wep_decrypt, + ieee80211_rx_h_defragment, + ieee80211_rx_h_ps_poll, + ieee80211_rx_h_michael_mic_verify, + /* this must be after decryption - so header is counted in MPDU mic + * must be before pae and data, so QOS_DATA format frames + * are not passed to user space by these functions + */ + ieee80211_rx_h_remove_qos_control, + ieee80211_rx_h_802_1x_pae, + ieee80211_rx_h_drop_unencrypted, + ieee80211_rx_h_data, + ieee80211_rx_h_mgmt, + NULL +}; + +/* main receive path */ + +/* + * 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) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + struct ieee80211_hdr *hdr; + struct ieee80211_txrx_data rx; + u16 type; + int multicast; + int radiotap_len = 0; + + if (status->flag & RX_FLAG_RADIOTAP) { + radiotap_len = ieee80211_get_radiotap_len(skb->data); + skb_pull(skb, radiotap_len); + } + + hdr = (struct ieee80211_hdr *) skb->data; + memset(&rx, 0, sizeof(rx)); + rx.skb = skb; + rx.local = local; + + rx.u.rx.status = status; + rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0; + type = rx.fc & IEEE80211_FCTL_FTYPE; + if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) + local->dot11ReceivedFragmentCount++; + multicast = is_multicast_ether_addr(hdr->addr1); + + if (skb->len >= 16) + sta = rx.sta = sta_info_get(local, hdr->addr2); + else + sta = rx.sta = NULL; + + if (sta) { + rx.dev = sta->dev; + rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); + } + + if ((status->flag & RX_FLAG_MMIC_ERROR)) { + ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); + goto end; + } + + if (unlikely(local->sta_scanning)) + rx.u.rx.in_scan = 1; + + if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, + sta) != TXRX_CONTINUE) + goto end; + skb = rx.skb; + + skb_push(skb, radiotap_len); + if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) && + !local->iff_promiscs && !multicast) { + rx.u.rx.ra_match = 1; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, + sta); + } else { + struct ieee80211_sub_if_data *prev = NULL; + struct sk_buff *skb_new; + u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len); + + read_lock(&local->sub_if_lock); + list_for_each_entry(sdata, &local->sub_if_list, list) { + rx.u.rx.ra_match = 1; + switch (sdata->type) { + case IEEE80211_IF_TYPE_STA: + if (!bssid) + continue; + if (!ieee80211_bssid_match(bssid, + sdata->u.sta.bssid)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } else if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!sdata->promisc) + continue; + rx.u.rx.ra_match = 0; + } + break; + case IEEE80211_IF_TYPE_IBSS: + if (!bssid) + continue; + if (!ieee80211_bssid_match(bssid, + sdata->u.sta.bssid)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } else if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!sdata->promisc) + continue; + rx.u.rx.ra_match = 0; + } else if (!sta) + sta = rx.sta = + ieee80211_ibss_add_sta(sdata->dev, + skb, bssid, + hdr->addr2); + break; + case IEEE80211_IF_TYPE_AP: + if (!bssid) { + if (compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) + continue; + } else if (!ieee80211_bssid_match(bssid, + sdata->dev->dev_addr)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } + if (sdata->dev == local->mdev && + !rx.u.rx.in_scan) + /* do not receive anything via + * master device when not scanning */ + continue; + break; + case IEEE80211_IF_TYPE_WDS: + if (bssid || + (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + continue; + if (compare_ether_addr(sdata->u.wds.remote_addr, + hdr->addr2) != 0) + continue; + break; + } + + if (prev) { + skb_new = skb_copy(skb, GFP_ATOMIC); + if (!skb_new) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: failed to copy " + "multicast frame for %s", + local->mdev->name, prev->dev->name); + continue; + } + rx.skb = skb_new; + rx.dev = prev->dev; + rx.sdata = prev; + ieee80211_invoke_rx_handlers(local, + local->rx_handlers, + &rx, sta); + } + prev = sdata; + } + if (prev) { + rx.skb = skb; + rx.dev = prev->dev; + rx.sdata = prev; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, + &rx, sta); + } else + dev_kfree_skb(skb); + read_unlock(&local->sub_if_lock); + } + + end: + if (sta) + sta_info_put(sta); +} +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) +{ + 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); +} +EXPORT_SYMBOL(ieee80211_rx_irqsafe); From 6e0d114d52833449a4e40f6dc8582e88d0742be4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1009/2804] [MAC80211]: move QoS rx handlers into rx.c This patch moves the QoS handlers into rx.c making it possible to compile wme.c only when NET_SCHED is defined. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/Makefile | 2 +- net/mac80211/rx.c | 55 ++++++++++++++++++++++++++++++++++++ net/mac80211/wme.c | 65 ------------------------------------------- net/mac80211/wme.h | 9 +++--- 4 files changed, 60 insertions(+), 71 deletions(-) diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index b5853991324b..0353e75ec963 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o +mac80211-objs-$(CONFIG_NET_SCHED) += wme.o mac80211-objs := \ ieee80211.o \ @@ -16,7 +17,6 @@ mac80211-objs := \ regdomain.o \ tkip.o \ aes_ccm.o \ - wme.o \ ieee80211_cfg.o \ rx.o \ $(mac80211-objs-y) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8c0d14c5628f..c5a6bb200726 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -30,6 +30,41 @@ * these don't have dev/sdata fields in the rx data */ +static ieee80211_txrx_result +ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) +{ + u8 *data = rx->skb->data; + int tid; + + /* does the frame have a qos control field? */ + if (WLAN_FC_IS_QOS_DATA(rx->fc)) { + u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN; + /* frame has qos control */ + tid = qc[0] & QOS_CONTROL_TID_MASK; + } else { + if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { + /* Separate TID for management frames */ + tid = NUM_RX_DATA_QUEUES - 1; + } else { + /* no qos control present */ + tid = 0; /* 802.1d - Best Effort */ + } + } +#ifdef CONFIG_MAC80211_DEBUG_COUNTERS + I802_DEBUG_INC(rx->local->wme_rx_queue[tid]); + if (rx->sta) { + I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); + } +#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ + + rx->u.rx.queue = tid; + /* Set skb->priority to 1d tag if highest order bit of TID is not set. + * For now, set skb->priority to 0 for other cases. */ + rx->skb->priority = (tid > 7) ? 0 : tid; + + return TXRX_CONTINUE; +} + static ieee80211_txrx_result ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) { @@ -764,6 +799,26 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) return TXRX_QUEUED; } +static ieee80211_txrx_result +ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) +{ + u16 fc = rx->fc; + u8 *data = rx->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data; + + if (!WLAN_FC_IS_QOS_DATA(fc)) + return TXRX_CONTINUE; + + /* remove the qos control field, update frame type and meta-data */ + memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2); + hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2); + /* change frame type to non QOS */ + rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA; + hdr->frame_control = cpu_to_le16(fc); + + return TXRX_CONTINUE; +} + static ieee80211_txrx_result ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) { diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 7ab82b376e1b..0f11ccd30a36 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -18,70 +18,6 @@ #include "ieee80211_i.h" #include "wme.h" -static inline int WLAN_FC_IS_QOS_DATA(u16 fc) -{ - return (fc & 0x8C) == 0x88; -} - - -ieee80211_txrx_result -ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) -{ - u8 *data = rx->skb->data; - int tid; - - /* does the frame have a qos control field? */ - if (WLAN_FC_IS_QOS_DATA(rx->fc)) { - u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN; - /* frame has qos control */ - tid = qc[0] & QOS_CONTROL_TID_MASK; - } else { - if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { - /* Separate TID for management frames */ - tid = NUM_RX_DATA_QUEUES - 1; - } else { - /* no qos control present */ - tid = 0; /* 802.1d - Best Effort */ - } - } -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - I802_DEBUG_INC(rx->local->wme_rx_queue[tid]); - if (rx->sta) { - I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); - } -#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ - - rx->u.rx.queue = tid; - /* Set skb->priority to 1d tag if highest order bit of TID is not set. - * For now, set skb->priority to 0 for other cases. */ - rx->skb->priority = (tid > 7) ? 0 : tid; - - return TXRX_CONTINUE; -} - - -ieee80211_txrx_result -ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) -{ - u16 fc = rx->fc; - u8 *data = rx->skb->data; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data; - - if (!WLAN_FC_IS_QOS_DATA(fc)) - return TXRX_CONTINUE; - - /* remove the qos control field, update frame type and meta-data */ - memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2); - hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2); - /* change frame type to non QOS */ - rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA; - hdr->frame_control = cpu_to_le16(fc); - - return TXRX_CONTINUE; -} - - -#ifdef CONFIG_NET_SCHED /* maximum number of hardware queues we support. */ #define TC_80211_MAX_QUEUES 8 @@ -675,4 +611,3 @@ void ieee80211_wme_unregister(void) { unregister_qdisc(&wme_qdisc_ops); } -#endif /* CONFIG_NET_SCHED */ diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index f0bff10f0e08..76c713a6450c 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -24,11 +24,10 @@ #define QOS_CONTROL_TAG1D_MASK 0x07 -ieee80211_txrx_result -ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx); - -ieee80211_txrx_result -ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx); +static inline int WLAN_FC_IS_QOS_DATA(u16 fc) +{ + return (fc & 0x8C) == 0x88; +} #ifdef CONFIG_NET_SCHED void ieee80211_install_qdisc(struct net_device *dev); From 8e6f003274147359ea612663048298823bed131f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1010/2804] [MAC80211]: rx cleanups (1) Make some really indented code more readable by outdenting. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/rx.c | 204 +++++++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 100 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c5a6bb200726..b46ba7c67453 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1079,21 +1079,24 @@ static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( for (handler = handlers; *handler != NULL; handler++) { res = (*handler)(rx); - if (res != TXRX_CONTINUE) { - if (res == TXRX_DROP) { - I802_DEBUG_INC(local->rx_handlers_drop); - if (sta) - sta->rx_dropped++; - } - if (res == TXRX_QUEUED) - I802_DEBUG_INC(local->rx_handlers_queued); + + switch (res) { + case TXRX_CONTINUE: + continue; + case TXRX_DROP: + I802_DEBUG_INC(local->rx_handlers_drop); + if (sta) + sta->rx_dropped++; + break; + case TXRX_QUEUED: + I802_DEBUG_INC(local->rx_handlers_queued); break; } + break; } - if (res == TXRX_DROP) { + if (res == TXRX_DROP) dev_kfree_skb(rx->skb); - } return res; } @@ -1242,6 +1245,9 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, u16 type; int multicast; int radiotap_len = 0; + struct ieee80211_sub_if_data *prev = NULL; + struct sk_buff *skb_new; + u8 *bssid; if (status->flag & RX_FLAG_RADIOTAP) { radiotap_len = ieee80211_get_radiotap_len(skb->data); @@ -1289,108 +1295,106 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, rx.u.rx.ra_match = 1; ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, sta); - } else { - struct ieee80211_sub_if_data *prev = NULL; - struct sk_buff *skb_new; - u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len); + sta_info_put(sta); + return; + } - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - rx.u.rx.ra_match = 1; - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - if (!bssid) - continue; - if (!ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { - if (!sdata->promisc) - continue; - rx.u.rx.ra_match = 0; - } - break; - case IEEE80211_IF_TYPE_IBSS: - if (!bssid) - continue; - if (!ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { - if (!sdata->promisc) - continue; - rx.u.rx.ra_match = 0; - } else if (!sta) - sta = rx.sta = - ieee80211_ibss_add_sta(sdata->dev, - skb, bssid, - hdr->addr2); - break; - case IEEE80211_IF_TYPE_AP: - if (!bssid) { - if (compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) - continue; - } else if (!ieee80211_bssid_match(bssid, - sdata->dev->dev_addr)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } - if (sdata->dev == local->mdev && - !rx.u.rx.in_scan) - /* do not receive anything via - * master device when not scanning */ - continue; - break; - case IEEE80211_IF_TYPE_WDS: - if (bssid || - (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - continue; - if (compare_ether_addr(sdata->u.wds.remote_addr, - hdr->addr2) != 0) - continue; - break; - } + bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len); - if (prev) { - skb_new = skb_copy(skb, GFP_ATOMIC); - if (!skb_new) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: failed to copy " - "multicast frame for %s", - local->mdev->name, prev->dev->name); + read_lock(&local->sub_if_lock); + list_for_each_entry(sdata, &local->sub_if_list, list) { + rx.u.rx.ra_match = 1; + switch (sdata->type) { + case IEEE80211_IF_TYPE_STA: + if (!bssid) + continue; + if (!ieee80211_bssid_match(bssid, + sdata->u.sta.bssid)) { + if (!rx.u.rx.in_scan) continue; - } - rx.skb = skb_new; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, - local->rx_handlers, - &rx, sta); + rx.u.rx.ra_match = 0; + } else if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!sdata->promisc) + continue; + rx.u.rx.ra_match = 0; } - prev = sdata; + break; + case IEEE80211_IF_TYPE_IBSS: + if (!bssid) + continue; + if (!ieee80211_bssid_match(bssid, + sdata->u.sta.bssid)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } else if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!sdata->promisc) + continue; + rx.u.rx.ra_match = 0; + } else if (!sta) + sta = rx.sta = + ieee80211_ibss_add_sta(sdata->dev, + skb, bssid, + hdr->addr2); + break; + case IEEE80211_IF_TYPE_AP: + if (!bssid) { + if (compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1)) + continue; + } else if (!ieee80211_bssid_match(bssid, + sdata->dev->dev_addr)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } + if (sdata->dev == local->mdev && !rx.u.rx.in_scan) + /* do not receive anything via + * master device when not scanning */ + continue; + break; + case IEEE80211_IF_TYPE_WDS: + if (bssid || + (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + continue; + if (compare_ether_addr(sdata->u.wds.remote_addr, + hdr->addr2)) + continue; + break; } + if (prev) { - rx.skb = skb; + skb_new = skb_copy(skb, GFP_ATOMIC); + if (!skb_new) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: failed to copy " + "multicast frame for %s", + local->mdev->name, prev->dev->name); + continue; + } + rx.skb = skb_new; rx.dev = prev->dev; rx.sdata = prev; ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, sta); - } else - dev_kfree_skb(skb); - read_unlock(&local->sub_if_lock); + } + prev = sdata; } + if (prev) { + rx.skb = skb; + rx.dev = prev->dev; + rx.sdata = prev; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, + &rx, sta); + } else + dev_kfree_skb(skb); + read_unlock(&local->sub_if_lock); - end: + end: if (sta) sta_info_put(sta); } From 570bd537a9a1520ddebfed772bcf6eaf7510bec4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1011/2804] [MAC80211]: split ieee80211_rx_h_check handler The ieee80211_rx_h_check handler really does two things, it's a lot easier to understand if it's split into ieee80211_rx_h_check and ieee80211_rx_h_load_key, and it may be possible in the future to optimise the key loading to not do it for each interface. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/rx.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b46ba7c67453..f7a1b61f9bef 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -234,7 +234,6 @@ static ieee80211_txrx_result ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr; - int always_sta_key; hdr = (struct ieee80211_hdr *) rx->skb->data; /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ @@ -302,6 +301,16 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) return TXRX_QUEUED; } + return TXRX_CONTINUE; +} + + +static ieee80211_txrx_result +ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + int always_sta_key; + if (rx->sdata->type == IEEE80211_IF_TYPE_STA) always_sta_key = 0; else @@ -1208,6 +1217,7 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = ieee80211_rx_h_monitor, ieee80211_rx_h_passive_scan, ieee80211_rx_h_check, + ieee80211_rx_h_load_key, ieee80211_rx_h_sta_process, ieee80211_rx_h_ccmp_decrypt, ieee80211_rx_h_tkip_decrypt, From 23a24defa0da567eac615828563935c195fb48dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1012/2804] [MAC80211]: split up __ieee80211_rx The really indented part that does the huge switch on the interface type is a nuisance. Put it into an own function 'prepare_for_handlers'. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/rx.c | 157 ++++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 74 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f7a1b61f9bef..21d401523d13 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1240,6 +1240,73 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = /* main receive path */ +static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, + u8 *bssid, struct ieee80211_txrx_data *rx, + struct ieee80211_hdr *hdr) +{ + int multicast = is_multicast_ether_addr(hdr->addr1); + + switch (sdata->type) { + case IEEE80211_IF_TYPE_STA: + if (!bssid) + return 0; + if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { + if (!rx->u.rx.in_scan) + return 0; + rx->u.rx.ra_match = 0; + } else if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!sdata->promisc) + return 0; + rx->u.rx.ra_match = 0; + } + break; + case IEEE80211_IF_TYPE_IBSS: + if (!bssid) + return 0; + if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { + if (!rx->u.rx.in_scan) + return 0; + rx->u.rx.ra_match = 0; + } else if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!sdata->promisc) + return 0; + rx->u.rx.ra_match = 0; + } else if (!rx->sta) + rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, + bssid, hdr->addr2); + break; + case IEEE80211_IF_TYPE_AP: + if (!bssid) { + if (compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1)) + return 0; + } else if (!ieee80211_bssid_match(bssid, + sdata->dev->dev_addr)) { + if (!rx->u.rx.in_scan) + return 0; + rx->u.rx.ra_match = 0; + } + if (sdata->dev == sdata->local->mdev && !rx->u.rx.in_scan) + /* do not receive anything via + * master device when not scanning */ + return 0; + break; + case IEEE80211_IF_TYPE_WDS: + if (bssid || + (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + return 0; + if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2)) + return 0; + break; + } + + return 1; +} + /* * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. @@ -1253,8 +1320,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_hdr *hdr; struct ieee80211_txrx_data rx; u16 type; - int multicast; - int radiotap_len = 0; + int radiotap_len = 0, prepres; struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; u8 *bssid; @@ -1274,18 +1340,16 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, type = rx.fc & IEEE80211_FCTL_FTYPE; if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) local->dot11ReceivedFragmentCount++; - multicast = is_multicast_ether_addr(hdr->addr1); - if (skb->len >= 16) + if (skb->len >= 16) { sta = rx.sta = sta_info_get(local, hdr->addr2); - else + if (sta) { + rx.dev = rx.sta->dev; + rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); + } + } else sta = rx.sta = NULL; - if (sta) { - rx.dev = sta->dev; - rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); - } - if ((status->flag & RX_FLAG_MMIC_ERROR)) { ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); goto end; @@ -1301,10 +1365,10 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, skb_push(skb, radiotap_len); if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) && - !local->iff_promiscs && !multicast) { + !local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) { rx.u.rx.ra_match = 1; ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, - sta); + rx.sta); sta_info_put(sta); return; } @@ -1314,68 +1378,13 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, read_lock(&local->sub_if_lock); list_for_each_entry(sdata, &local->sub_if_list, list) { rx.u.rx.ra_match = 1; - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - if (!bssid) - continue; - if (!ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { - if (!sdata->promisc) - continue; - rx.u.rx.ra_match = 0; - } - break; - case IEEE80211_IF_TYPE_IBSS: - if (!bssid) - continue; - if (!ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { - if (!sdata->promisc) - continue; - rx.u.rx.ra_match = 0; - } else if (!sta) - sta = rx.sta = - ieee80211_ibss_add_sta(sdata->dev, - skb, bssid, - hdr->addr2); - break; - case IEEE80211_IF_TYPE_AP: - if (!bssid) { - if (compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1)) - continue; - } else if (!ieee80211_bssid_match(bssid, - sdata->dev->dev_addr)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } - if (sdata->dev == local->mdev && !rx.u.rx.in_scan) - /* do not receive anything via - * master device when not scanning */ - continue; - break; - case IEEE80211_IF_TYPE_WDS: - if (bssid || - (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - continue; - if (compare_ether_addr(sdata->u.wds.remote_addr, - hdr->addr2)) - continue; - break; - } + + prepres = prepare_for_handlers(sdata, bssid, &rx, hdr); + /* prepare_for_handlers can change sta */ + sta = rx.sta; + + if (!prepres) + continue; if (prev) { skb_new = skb_copy(skb, GFP_ATOMIC); From 52865dfd520ddd3d1176947106759ff944f0f8af Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1013/2804] [MAC80211]: fix bug for per-sta stats pre_rx handlers can't really touch sta since for IBSS it might not be assigned yet, it can create sta info structs on-the-fly. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/rx.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 21d401523d13..f255579dc564 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -28,6 +28,8 @@ /* pre-rx handlers * * these don't have dev/sdata fields in the rx data + * The sta value should also not be used because it may + * be NULL even though a STA (in IBSS mode) will be added. */ static ieee80211_txrx_result @@ -50,12 +52,11 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) tid = 0; /* 802.1d - Best Effort */ } } -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS + I802_DEBUG_INC(rx->local->wme_rx_queue[tid]); - if (rx->sta) { + /* only a debug counter, sta might not be assigned properly yet */ + if (rx->sta) I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); - } -#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ rx->u.rx.queue = tid; /* Set skb->priority to 1d tag if highest order bit of TID is not set. @@ -110,8 +111,6 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) /* Divide channel_use by 8 to avoid wrapping around the counter */ load >>= CHAN_UTIL_SHIFT; local->channel_use_raw += load; - if (rx->sta) - rx->sta->channel_use_raw += load; rx->u.rx.load = load; return TXRX_CONTINUE; @@ -129,6 +128,8 @@ ieee80211_rx_handler ieee80211_rx_pre_handlers[] = static ieee80211_txrx_result ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) { + if (rx->sta) + rx->sta->channel_use_raw += rx->u.rx.load; rx->sdata->channel_use_raw += rx->u.rx.load; return TXRX_CONTINUE; } From 340e11f332c695c43f506e82b1d39d00716c5005 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1014/2804] [MAC80211]: rx cleanups (2) Some more outdenting to make the code more readable. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/rx.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f255579dc564..95a00eb57249 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1387,21 +1387,35 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, if (!prepres) continue; - if (prev) { - skb_new = skb_copy(skb, GFP_ATOMIC); - if (!skb_new) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: failed to copy " - "multicast frame for %s", - local->mdev->name, prev->dev->name); - continue; - } - rx.skb = skb_new; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); + /* + * frame is destined for this interface, but if it's not + * also for the previous one we handle that after the + * loop to avoid copying the SKB once too much + */ + + if (!prev) { + prev = sdata; + continue; } + + /* + * frame was destined for the previous interface + * so invoke RX handlers for it + */ + + skb_new = skb_copy(skb, GFP_ATOMIC); + if (!skb_new) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: failed to copy " + "multicast frame for %s", + local->mdev->name, prev->dev->name); + continue; + } + rx.skb = skb_new; + rx.dev = prev->dev; + rx.sdata = prev; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, + &rx, sta); prev = sdata; } if (prev) { From e2ebc74d7e3d71600640db6fbb28cc2f362184c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1015/2804] [MAC80211]: split TX path into own file Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/Makefile | 1 + net/mac80211/ieee80211.c | 1845 ----------------------------------- net/mac80211/ieee80211_i.h | 18 +- net/mac80211/tx.c | 1869 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1884 insertions(+), 1849 deletions(-) create mode 100644 net/mac80211/tx.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 0353e75ec963..848260296a0c 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -19,4 +19,5 @@ mac80211-objs := \ aes_ccm.o \ ieee80211_cfg.o \ rx.o \ + tx.o \ $(mac80211-objs-y) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index c0094209bed9..a35e3a95a15a 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "ieee80211_common.h" #include "ieee80211_i.h" @@ -68,16 +67,6 @@ struct ieee80211_tx_status_rtap_hdr { } __attribute__ ((packed)); -static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, - struct ieee80211_hdr *hdr) -{ - /* Set the sequence number for this frame. */ - hdr->seq_ctrl = cpu_to_le16(sdata->sequence); - - /* Increase the sequence number. */ - sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ; -} - struct ieee80211_key_conf * ieee80211_key_data2conf(struct ieee80211_local *local, const struct ieee80211_key *data) @@ -346,45 +335,6 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); -#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP -static void ieee80211_dump_frame(const char *ifname, const char *title, - const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc; - int hdrlen; - - printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); - if (skb->len < 4) { - printk("\n"); - return; - } - - fc = le16_to_cpu(hdr->frame_control); - hdrlen = ieee80211_get_hdrlen(fc); - if (hdrlen > skb->len) - hdrlen = skb->len; - if (hdrlen >= 4) - printk(" FC=0x%04x DUR=0x%04x", - fc, le16_to_cpu(hdr->duration_id)); - if (hdrlen >= 10) - printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1)); - if (hdrlen >= 16) - printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2)); - if (hdrlen >= 24) - printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3)); - if (hdrlen >= 30) - printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4)); - printk("\n"); -} -#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ -static inline void ieee80211_dump_frame(const char *ifname, const char *title, - struct sk_buff *skb) -{ -} -#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ - - int ieee80211_is_eapol(const struct sk_buff *skb) { const struct ieee80211_hdr *hdr; @@ -411,187 +361,6 @@ int ieee80211_is_eapol(const struct sk_buff *skb) } -static ieee80211_txrx_result -ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) -{ - struct rate_control_extra extra; - - memset(&extra, 0, sizeof(extra)); - extra.mode = tx->u.tx.mode; - extra.mgmt_data = tx->sdata && - tx->sdata->type == IEEE80211_IF_TYPE_MGMT; - extra.ethertype = tx->ethertype; - - tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb, - &extra); - if (unlikely(extra.probe != NULL)) { - tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; - tx->u.tx.probe_last_frag = 1; - tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; - tx->u.tx.rate = extra.probe; - } else { - tx->u.tx.control->alt_retry_rate = -1; - } - if (!tx->u.tx.rate) - return TXRX_DROP; - if (tx->u.tx.mode->mode == MODE_IEEE80211G && - tx->sdata->use_protection && tx->fragmented && - extra.nonerp) { - tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.probe_last_frag = extra.probe ? 1 : 0; - - tx->u.tx.rate = extra.nonerp; - tx->u.tx.control->rate = extra.nonerp; - tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; - } else { - tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.control->rate = tx->u.tx.rate; - } - tx->u.tx.control->tx_rate = tx->u.tx.rate->val; - if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && - tx->local->short_preamble && - (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->u.tx.short_preamble = 1; - tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) -{ - if (tx->sta) - tx->u.tx.control->key_idx = tx->sta->key_idx_compression; - else - tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; - - if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - tx->key = NULL; - else if (tx->sta && tx->sta->key) - tx->key = tx->sta->key; - else if (tx->sdata->default_key) - tx->key = tx->sdata->default_key; - else if (tx->sdata->drop_unencrypted && - !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { - I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); - return TXRX_DROP; - } else - tx->key = NULL; - - if (tx->key) { - tx->key->tx_rx_count++; - if (unlikely(tx->local->key_tx_rx_threshold && - tx->key->tx_rx_count > - tx->local->key_tx_rx_threshold)) { - ieee80211_key_threshold_notify(tx->dev, tx->key, - tx->sta); - } - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - size_t hdrlen, per_fragm, num_fragm, payload_len, left; - struct sk_buff **frags, *first, *frag; - int i; - u16 seq; - u8 *pos; - int frag_threshold = tx->local->fragmentation_threshold; - - if (!tx->fragmented) - return TXRX_CONTINUE; - - first = tx->skb; - - hdrlen = ieee80211_get_hdrlen(tx->fc); - payload_len = first->len - hdrlen; - per_fragm = frag_threshold - hdrlen - FCS_LEN; - num_fragm = (payload_len + per_fragm - 1) / per_fragm; - - frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); - if (!frags) - goto fail; - - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); - seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; - pos = first->data + hdrlen + per_fragm; - left = payload_len - per_fragm; - for (i = 0; i < num_fragm - 1; i++) { - struct ieee80211_hdr *fhdr; - size_t copylen; - - if (left <= 0) - goto fail; - - /* reserve enough extra head and tail room for possible - * encryption */ - frag = frags[i] = - dev_alloc_skb(tx->local->tx_headroom + - frag_threshold + - IEEE80211_ENCRYPT_HEADROOM + - IEEE80211_ENCRYPT_TAILROOM); - if (!frag) - goto fail; - /* Make sure that all fragments use the same priority so - * that they end up using the same TX queue */ - frag->priority = first->priority; - skb_reserve(frag, tx->local->tx_headroom + - IEEE80211_ENCRYPT_HEADROOM); - fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); - memcpy(fhdr, first->data, hdrlen); - if (i == num_fragm - 2) - fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); - fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); - copylen = left > per_fragm ? per_fragm : left; - memcpy(skb_put(frag, copylen), pos, copylen); - - pos += copylen; - left -= copylen; - } - skb_trim(first, hdrlen + per_fragm); - - tx->u.tx.num_extra_frag = num_fragm - 1; - tx->u.tx.extra_frag = frags; - - return TXRX_CONTINUE; - - fail: - printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); - if (frags) { - for (i = 0; i < num_fragm - 1; i++) - if (frags[i]) - dev_kfree_skb(frags[i]); - kfree(frags); - } - I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); - return TXRX_DROP; -} - - -static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) -{ - if (tx->key->force_sw_encrypt) { - if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) - return -1; - } else { - tx->u.tx.control->key_idx = tx->key->hw_key_idx; - if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (ieee80211_wep_add_iv(tx->local, skb, tx->key) == - NULL) - return -1; - } - } - return 0; -} - - void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; @@ -609,44 +378,6 @@ void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) } -static ieee80211_txrx_result -ieee80211_tx_h_wep_encrypt(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 fc; - - fc = le16_to_cpu(hdr->frame_control); - - if (!tx->key || tx->key->alg != ALG_WEP || - ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) - return TXRX_CONTINUE; - - tx->u.tx.control->iv_len = WEP_IV_LEN; - tx->u.tx.control->icv_len = WEP_ICV_LEN; - ieee80211_tx_set_iswep(tx); - - if (wep_encrypt_skb(tx, tx->skb) < 0) { - I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); - return TXRX_DROP; - } - - if (tx->u.tx.extra_frag) { - int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { - I802_DEBUG_INC(tx->local-> - tx_handlers_drop_wep); - return TXRX_DROP; - } - } - } - - return TXRX_CONTINUE; -} - - static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int rate, int erp, int short_preamble) { @@ -720,1400 +451,6 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, EXPORT_SYMBOL(ieee80211_generic_frame_duration); -static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, - int next_frag_len) -{ - int rate, mrate, erp, dur, i; - struct ieee80211_rate *txrate = tx->u.tx.rate; - struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; - - erp = txrate->flags & IEEE80211_RATE_ERP; - - /* - * data and mgmt (except PS Poll): - * - during CFP: 32768 - * - during contention period: - * if addr1 is group address: 0 - * if more fragments = 0 and addr1 is individual address: time to - * transmit one ACK plus SIFS - * if more fragments = 1 and addr1 is individual address: time to - * transmit next fragment plus 2 x ACK plus 3 x SIFS - * - * IEEE 802.11, 9.6: - * - control response frame (CTS or ACK) shall be transmitted using the - * same rate as the immediately previous frame in the frame exchange - * sequence, if this rate belongs to the PHY mandatory rates, or else - * at the highest possible rate belonging to the PHY rates in the - * BSSBasicRateSet - */ - - if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) { - /* TODO: These control frames are not currently sent by - * 80211.o, but should they be implemented, this function - * needs to be updated to support duration field calculation. - * - * RTS: time needed to transmit pending data/mgmt frame plus - * one CTS frame plus one ACK frame plus 3 x SIFS - * CTS: duration of immediately previous RTS minus time - * required to transmit CTS and its SIFS - * ACK: 0 if immediately previous directed data/mgmt had - * more=0, with more=1 duration in ACK frame is duration - * from previous frame minus time needed to transmit ACK - * and its SIFS - * PS Poll: BIT(15) | BIT(14) | aid - */ - return 0; - } - - /* data/mgmt */ - if (0 /* FIX: data/mgmt during CFP */) - return 32768; - - if (group_addr) /* Group address as the destination - no ACK */ - return 0; - - /* Individual destination address: - * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes) - * CTS and ACK frames shall be transmitted using the highest rate in - * basic rate set that is less than or equal to the rate of the - * immediately previous frame and that is using the same modulation - * (CCK or OFDM). If no basic rate set matches with these requirements, - * the highest mandatory rate of the PHY that is less than or equal to - * the rate of the previous frame is used. - * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps - */ - rate = -1; - mrate = 10; /* use 1 Mbps if everything fails */ - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; - if (r->rate > txrate->rate) - break; - - if (IEEE80211_RATE_MODULATION(txrate->flags) != - IEEE80211_RATE_MODULATION(r->flags)) - continue; - - if (r->flags & IEEE80211_RATE_BASIC) - rate = r->rate; - else if (r->flags & IEEE80211_RATE_MANDATORY) - mrate = r->rate; - } - if (rate == -1) { - /* No matching basic rate found; use highest suitable mandatory - * PHY rate */ - rate = mrate; - } - - /* Time needed to transmit ACK - * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up - * to closest integer */ - - dur = ieee80211_frame_duration(local, 10, rate, erp, - local->short_preamble); - - if (next_frag_len) { - /* Frame is fragmented: duration increases with time needed to - * transmit next fragment plus ACK and 2 x SIFS. */ - dur *= 2; /* ACK + SIFS */ - /* next fragment */ - dur += ieee80211_frame_duration(local, next_frag_len, - txrate->rate, erp, - local->short_preamble); - } - - return dur; -} - - -static ieee80211_txrx_result -ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 dur; - struct ieee80211_tx_control *control = tx->u.tx.control; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; - - if (!is_multicast_ether_addr(hdr->addr1)) { - if (tx->skb->len + FCS_LEN > tx->local->rts_threshold && - tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) { - control->flags |= IEEE80211_TXCTL_USE_RTS_CTS; - control->retry_limit = - tx->local->long_retry_limit; - } else { - control->retry_limit = - tx->local->short_retry_limit; - } - } else { - control->retry_limit = 1; - } - - if (tx->fragmented) { - /* Do not use multiple retry rates when sending fragmented - * frames. - * TODO: The last fragment could still use multiple retry - * rates. */ - control->alt_retry_rate = -1; - } - - /* Use CTS protection for unicast frames sent using extended rates if - * there are associated non-ERP stations and RTS/CTS is not configured - * for the frame. */ - if (mode->mode == MODE_IEEE80211G && - (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && - tx->u.tx.unicast && tx->sdata->use_protection && - !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) - control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; - - /* Setup duration field for the first fragment of the frame. Duration - * for remaining fragments will be updated when they are being sent - * to low-level driver in ieee80211_tx(). */ - dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), - tx->fragmented ? tx->u.tx.extra_frag[0]->len : - 0); - hdr->duration_id = cpu_to_le16(dur); - - if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { - struct ieee80211_rate *rate; - - /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = -1; - - /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = tx->u.tx.rate; - while (rate > mode->rates && - !(rate->flags & IEEE80211_RATE_BASIC)) - rate--; - - control->rts_cts_rate = rate->val; - control->rts_rate = rate; - } - - if (tx->sta) { - tx->sta->tx_packets++; - tx->sta->tx_fragments++; - tx->sta->tx_bytes += tx->skb->len; - if (tx->u.tx.extra_frag) { - int i; - tx->sta->tx_fragments += tx->u.tx.num_extra_frag; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - tx->sta->tx_bytes += - tx->u.tx.extra_frag[i]->len; - } - } - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) -{ -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - u32 sta_flags; - - if (unlikely(tx->local->sta_scanning != 0) && - ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) - return TXRX_DROP; - - if (tx->u.tx.ps_buffered) - return TXRX_CONTINUE; - - sta_flags = tx->sta ? tx->sta->flags : 0; - - if (likely(tx->u.tx.unicast)) { - if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && - tx->sdata->type != IEEE80211_IF_TYPE_IBSS && - (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped data frame to not " - "associated station " MAC_FMT "\n", - tx->dev->name, MAC_ARG(hdr->addr1)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); - return TXRX_DROP; - } - } else { - if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - tx->local->num_sta == 0 && - !tx->local->allow_broadcast_always && - tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) { - /* - * No associated STAs - no need to send multicast - * frames. - */ - return TXRX_DROP; - } - return TXRX_CONTINUE; - } - - if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x && - !(sta_flags & WLAN_STA_AUTHORIZED))) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT - " (unauthorized port)\n", tx->dev->name, - MAC_ARG(hdr->addr1)); -#endif - I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port); - return TXRX_DROP; - } - - return TXRX_CONTINUE; -} - -static ieee80211_txrx_result -ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; - - if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) - ieee80211_include_sequence(tx->sdata, hdr); - - return TXRX_CONTINUE; -} - -/* This function is called whenever the AP is about to exceed the maximum limit - * of buffered frames for power saving STAs. This situation should not really - * happen often during normal operation, so dropping the oldest buffered packet - * from each queue should be OK to make some room for new frames. */ -static void purge_old_ps_buffers(struct ieee80211_local *local) -{ - int total = 0, purged = 0; - struct sk_buff *skb; - struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; - - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - struct ieee80211_if_ap *ap; - if (sdata->dev == local->mdev || - sdata->type != IEEE80211_IF_TYPE_AP) - continue; - ap = &sdata->u.ap; - skb = skb_dequeue(&ap->ps_bc_buf); - if (skb) { - purged++; - dev_kfree_skb(skb); - } - total += skb_queue_len(&ap->ps_bc_buf); - } - read_unlock(&local->sub_if_lock); - - spin_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { - skb = skb_dequeue(&sta->ps_tx_buf); - if (skb) { - purged++; - dev_kfree_skb(skb); - } - total += skb_queue_len(&sta->ps_tx_buf); - } - spin_unlock_bh(&local->sta_lock); - - local->total_ps_buffered = total; - printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", - local->mdev->name, purged); -} - - -static inline ieee80211_txrx_result -ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) -{ - /* broadcast/multicast frame */ - /* If any of the associated stations is in power save mode, - * the frame is buffered to be sent after DTIM beacon frame */ - if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) && - tx->sdata->type != IEEE80211_IF_TYPE_WDS && - tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) && - !(tx->fc & IEEE80211_FCTL_ORDER)) { - 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 (net_ratelimit()) { - printk(KERN_DEBUG "%s: BC TX buffer full - " - "dropping the oldest frame\n", - tx->dev->name); - } - 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 TXRX_QUEUED; - } - - return TXRX_CONTINUE; -} - - -static inline ieee80211_txrx_result -ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) -{ - struct sta_info *sta = tx->sta; - - if (unlikely(!sta || - ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && - (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) - return TXRX_CONTINUE; - - if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { - struct ieee80211_tx_packet_data *pkt_data; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries " - "before %d)\n", - MAC_ARG(sta->addr), sta->aid, - skb_queue_len(&sta->ps_tx_buf)); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->flags |= WLAN_STA_TIM; - if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) - purge_old_ps_buffers(tx->local); - if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { - struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " TX " - "buffer full - dropping oldest frame\n", - tx->dev->name, MAC_ARG(sta->addr)); - } - dev_kfree_skb(old); - } else - tx->local->total_ps_buffered++; - /* Queue frame to be sent after STA sends an PS Poll frame */ - if (skb_queue_empty(&sta->ps_tx_buf)) { - if (tx->local->ops->set_tim) - tx->local->ops->set_tim(local_to_hw(tx->local), - sta->aid, 1); - if (tx->sdata->bss) - bss_tim_set(tx->local, tx->sdata->bss, sta->aid); - } - pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; - pkt_data->jiffies = jiffies; - skb_queue_tail(&sta->ps_tx_buf, tx->skb); - return TXRX_QUEUED; - } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(sta->flags & WLAN_STA_PS)) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll " - "set -> send frame\n", tx->dev->name, - MAC_ARG(sta->addr)); - } -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->pspoll = 0; - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) -{ - if (unlikely(tx->u.tx.ps_buffered)) - return TXRX_CONTINUE; - - if (tx->u.tx.unicast) - return ieee80211_tx_h_unicast_ps_buf(tx); - else - return ieee80211_tx_h_multicast_ps_buf(tx); -} - - -/* - * deal with packet injection down monitor interface - * with Radiotap Header -- only called for monitor mode interface - */ - -static ieee80211_txrx_result -__ieee80211_parse_tx_radiotap( - struct ieee80211_txrx_data *tx, - struct sk_buff *skb, struct ieee80211_tx_control *control) -{ - /* - * this is the moment to interpret and discard the radiotap header that - * must be at the start of the packet injected in Monitor mode - * - * Need to take some care with endian-ness since radiotap - * args are little-endian - */ - - struct ieee80211_radiotap_iterator iterator; - struct ieee80211_radiotap_header *rthdr = - (struct ieee80211_radiotap_header *) skb->data; - struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; - int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); - - /* - * default control situation for all injected packets - * FIXME: this does not suit all usage cases, expand to allow control - */ - - control->retry_limit = 1; /* no retry */ - control->key_idx = -1; /* no encryption key */ - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT); - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT | - IEEE80211_TXCTL_NO_ACK; - control->antenna_sel_tx = 0; /* default to default antenna */ - - /* - * for every radiotap entry that is present - * (ieee80211_radiotap_iterator_next returns -ENOENT when no more - * entries present, or -EINVAL on error) - */ - - while (!ret) { - int i, target_rate; - - ret = ieee80211_radiotap_iterator_next(&iterator); - - if (ret) - continue; - - /* see if this argument is something we can use */ - switch (iterator.this_arg_index) { - /* - * You must take care when dereferencing iterator.this_arg - * for multibyte types... the pointer is not aligned. Use - * get_unaligned((type *)iterator.this_arg) to dereference - * iterator.this_arg for type "type" safely on all arches. - */ - case IEEE80211_RADIOTAP_RATE: - /* - * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps - * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps - */ - target_rate = (*iterator.this_arg) * 5; - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; - - if (r->rate > target_rate) - continue; - - control->rate = r; - - if (r->flags & IEEE80211_RATE_PREAMBLE2) - control->tx_rate = r->val2; - else - control->tx_rate = r->val; - - /* end on exact match */ - if (r->rate == target_rate) - i = mode->num_rates; - } - break; - - case IEEE80211_RADIOTAP_ANTENNA: - /* - * radiotap uses 0 for 1st ant, mac80211 is 1 for - * 1st ant - */ - control->antenna_sel_tx = (*iterator.this_arg) + 1; - break; - - case IEEE80211_RADIOTAP_DBM_TX_POWER: - control->power_level = *iterator.this_arg; - break; - - case IEEE80211_RADIOTAP_FLAGS: - if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { - /* - * this indicates that the skb we have been - * handed has the 32-bit FCS CRC at the end... - * we should react to that by snipping it off - * because it will be recomputed and added - * on transmission - */ - if (skb->len < (iterator.max_length + FCS_LEN)) - return TXRX_DROP; - - skb_trim(skb, skb->len - FCS_LEN); - } - break; - - default: - break; - } - } - - if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ - return TXRX_DROP; - - /* - * remove the radiotap header - * iterator->max_length was sanity-checked against - * skb->len by iterator init - */ - skb_pull(skb, iterator.max_length); - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result inline -__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, - struct sk_buff *skb, - struct net_device *dev, - struct ieee80211_tx_control *control) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_sub_if_data *sdata; - ieee80211_txrx_result res = TXRX_CONTINUE; - - int hdrlen; - - memset(tx, 0, sizeof(*tx)); - tx->skb = skb; - tx->dev = dev; /* use original interface */ - tx->local = local; - tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); - tx->sta = sta_info_get(local, hdr->addr1); - tx->fc = le16_to_cpu(hdr->frame_control); - - /* - * set defaults for things that can be set by - * injected radiotap headers - */ - control->power_level = local->hw.conf.power_level; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta) - control->antenna_sel_tx = tx->sta->antenna_sel_tx; - - /* process and remove the injection radiotap header */ - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { - if (__ieee80211_parse_tx_radiotap(tx, skb, control) == - TXRX_DROP) { - return TXRX_DROP; - } - /* - * we removed the radiotap header after this point, - * we filled control with what we could use - * set to the actual ieee header now - */ - hdr = (struct ieee80211_hdr *) skb->data; - res = TXRX_QUEUED; /* indication it was monitor packet */ - } - - tx->u.tx.control = control; - tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1); - if (is_multicast_ether_addr(hdr->addr1)) - control->flags |= IEEE80211_TXCTL_NO_ACK; - else - control->flags &= ~IEEE80211_TXCTL_NO_ACK; - tx->fragmented = local->fragmentation_threshold < - IEEE80211_MAX_FRAG_THRESHOLD && tx->u.tx.unicast && - skb->len + FCS_LEN > local->fragmentation_threshold && - (!local->ops->set_frag_threshold); - if (!tx->sta) - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - else if (tx->sta->clear_dst_mask) { - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - tx->sta->clear_dst_mask = 0; - } - hdrlen = ieee80211_get_hdrlen(tx->fc); - if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { - u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; - tx->ethertype = (pos[0] << 8) | pos[1]; - } - control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; - - return res; -} - -static int inline is_ieee80211_device(struct net_device *dev, - struct net_device *master) -{ - return (wdev_priv(dev->ieee80211_ptr) == - wdev_priv(master->ieee80211_ptr)); -} - -/* Device in tx->dev has a reference added; use dev_put(tx->dev) when - * finished with it. */ -static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, - struct sk_buff *skb, - struct net_device *mdev, - struct ieee80211_tx_control *control) -{ - struct ieee80211_tx_packet_data *pkt_data; - struct net_device *dev; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - dev = dev_get_by_index(pkt_data->ifindex); - if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { - dev_put(dev); - dev = NULL; - } - if (unlikely(!dev)) - return -ENODEV; - __ieee80211_tx_prepare(tx, skb, dev, control); - return 0; -} - -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} - -static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); -} - -#define IEEE80211_TX_OK 0 -#define IEEE80211_TX_AGAIN 1 -#define IEEE80211_TX_FRAG_AGAIN 2 - -static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_txrx_data *tx) -{ - struct ieee80211_tx_control *control = tx->u.tx.control; - int ret, i; - - if (!ieee80211_qdisc_installed(local->mdev) && - __ieee80211_queue_stopped(local, 0)) { - netif_stop_queue(local->mdev); - return IEEE80211_TX_AGAIN; - } - if (skb) { - ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb); - ret = local->ops->tx(local_to_hw(local), skb, control); - if (ret) - return IEEE80211_TX_AGAIN; - local->mdev->trans_start = jiffies; - ieee80211_led_tx(local, 1); - } - if (tx->u.tx.extra_frag) { - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_DST_MASK | - IEEE80211_TXCTL_FIRST_FRAGMENT); - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (!tx->u.tx.extra_frag[i]) - continue; - if (__ieee80211_queue_stopped(local, control->queue)) - return IEEE80211_TX_FRAG_AGAIN; - if (i == tx->u.tx.num_extra_frag) { - control->tx_rate = tx->u.tx.last_frag_hwrate; - control->rate = tx->u.tx.last_frag_rate; - if (tx->u.tx.probe_last_frag) - control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; - else - control->flags &= - ~IEEE80211_TXCTL_RATE_CTRL_PROBE; - } - - ieee80211_dump_frame(local->mdev->name, - "TX to low-level driver", - tx->u.tx.extra_frag[i]); - ret = local->ops->tx(local_to_hw(local), - tx->u.tx.extra_frag[i], - control); - if (ret) - return IEEE80211_TX_FRAG_AGAIN; - local->mdev->trans_start = jiffies; - ieee80211_led_tx(local, 1); - tx->u.tx.extra_frag[i] = NULL; - } - kfree(tx->u.tx.extra_frag); - tx->u.tx.extra_frag = NULL; - } - return IEEE80211_TX_OK; -} - -static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control, int mgmt) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - ieee80211_tx_handler *handler; - struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP, res_prepare; - int ret, i; - - WARN_ON(__ieee80211_queue_pending(local, control->queue)); - - if (unlikely(skb->len < 10)) { - dev_kfree_skb(skb); - return 0; - } - - res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); - - if (res_prepare == TXRX_DROP) { - dev_kfree_skb(skb); - return 0; - } - - sta = tx.sta; - tx.u.tx.mgmt_interface = mgmt; - tx.u.tx.mode = local->hw.conf.mode; - - if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */ - res = TXRX_CONTINUE; - } else { - for (handler = local->tx_handlers; *handler != NULL; - handler++) { - res = (*handler)(&tx); - if (res != TXRX_CONTINUE) - break; - } - } - - skb = tx.skb; /* handlers are allowed to change skb */ - - if (sta) - sta_info_put(sta); - - if (unlikely(res == TXRX_DROP)) { - I802_DEBUG_INC(local->tx_handlers_drop); - goto drop; - } - - if (unlikely(res == TXRX_QUEUED)) { - I802_DEBUG_INC(local->tx_handlers_queued); - return 0; - } - - if (tx.u.tx.extra_frag) { - for (i = 0; i < tx.u.tx.num_extra_frag; i++) { - int next_len, dur; - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) - tx.u.tx.extra_frag[i]->data; - - if (i + 1 < tx.u.tx.num_extra_frag) { - next_len = tx.u.tx.extra_frag[i + 1]->len; - } else { - next_len = 0; - tx.u.tx.rate = tx.u.tx.last_frag_rate; - tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val; - } - dur = ieee80211_duration(&tx, 0, next_len); - hdr->duration_id = cpu_to_le16(dur); - } - } - -retry: - ret = __ieee80211_tx(local, skb, &tx); - if (ret) { - struct ieee80211_tx_stored_packet *store = - &local->pending_packet[control->queue]; - - if (ret == IEEE80211_TX_FRAG_AGAIN) - skb = NULL; - set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - smp_mb(); - /* When the driver gets out of buffers during sending of - * fragments and calls ieee80211_stop_queue, there is - * a small window between IEEE80211_LINK_STATE_XOFF and - * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer - * gets available in that window (i.e. driver calls - * ieee80211_wake_queue), we would end up with ieee80211_tx - * called with IEEE80211_LINK_STATE_PENDING. Prevent this by - * continuing transmitting here when that situation is - * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, control->queue)) { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - goto retry; - } - memcpy(&store->control, control, - sizeof(struct ieee80211_tx_control)); - store->skb = skb; - store->extra_frag = tx.u.tx.extra_frag; - store->num_extra_frag = tx.u.tx.num_extra_frag; - store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; - store->last_frag_rate = tx.u.tx.last_frag_rate; - store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag; - } - return 0; - - drop: - if (skb) - dev_kfree_skb(skb); - for (i = 0; i < tx.u.tx.num_extra_frag; i++) - if (tx.u.tx.extra_frag[i]) - dev_kfree_skb(tx.u.tx.extra_frag[i]); - kfree(tx.u.tx.extra_frag); - return 0; -} - -static void ieee80211_tx_pending(unsigned long data) -{ - struct ieee80211_local *local = (struct ieee80211_local *)data; - struct net_device *dev = local->mdev; - struct ieee80211_tx_stored_packet *store; - struct ieee80211_txrx_data tx; - int i, ret, reschedule = 0; - - netif_tx_lock_bh(dev); - for (i = 0; i < local->hw.queues; i++) { - if (__ieee80211_queue_stopped(local, i)) - continue; - if (!__ieee80211_queue_pending(local, i)) { - reschedule = 1; - continue; - } - store = &local->pending_packet[i]; - tx.u.tx.control = &store->control; - tx.u.tx.extra_frag = store->extra_frag; - tx.u.tx.num_extra_frag = store->num_extra_frag; - tx.u.tx.last_frag_hwrate = store->last_frag_hwrate; - tx.u.tx.last_frag_rate = store->last_frag_rate; - tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe; - ret = __ieee80211_tx(local, store->skb, &tx); - if (ret) { - if (ret == IEEE80211_TX_FRAG_AGAIN) - store->skb = NULL; - } else { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[i]); - reschedule = 1; - } - } - netif_tx_unlock_bh(dev); - if (reschedule) { - if (!ieee80211_qdisc_installed(dev)) { - if (!__ieee80211_queue_stopped(local, 0)) - netif_wake_queue(dev); - } else - netif_schedule(dev); - } -} - -static void ieee80211_clear_tx_pending(struct ieee80211_local *local) -{ - int i, j; - struct ieee80211_tx_stored_packet *store; - - for (i = 0; i < local->hw.queues; i++) { - if (!__ieee80211_queue_pending(local, i)) - continue; - store = &local->pending_packet[i]; - kfree_skb(store->skb); - for (j = 0; j < store->num_extra_frag; j++) - kfree_skb(store->extra_frag[j]); - kfree(store->extra_frag); - clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); - } -} - -static int ieee80211_master_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct ieee80211_tx_control control; - struct ieee80211_tx_packet_data *pkt_data; - struct net_device *odev = NULL; - struct ieee80211_sub_if_data *osdata; - int headroom; - int ret; - - /* - * copy control out of the skb so other people can use skb->cb - */ - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(&control, 0, sizeof(struct ieee80211_tx_control)); - - if (pkt_data->ifindex) - odev = dev_get_by_index(pkt_data->ifindex); - if (unlikely(odev && !is_ieee80211_device(odev, dev))) { - 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 0; - } - osdata = IEEE80211_DEV_TO_SUB_IF(odev); - - headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; - if (skb_headroom(skb) < headroom) { - if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - dev_put(odev); - return 0; - } - } - - control.ifindex = odev->ifindex; - control.type = osdata->type; - if (pkt_data->req_tx_status) - control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; - if (pkt_data->do_not_encrypt) - control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - if (pkt_data->requeue) - control.flags |= IEEE80211_TXCTL_REQUEUE; - control.queue = pkt_data->queue; - - ret = ieee80211_tx(odev, skb, &control, - control.type == IEEE80211_IF_TYPE_MGMT); - dev_put(odev); - - return ret; -} - - -int ieee80211_monitor_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; - struct ieee80211_radiotap_header *prthdr = - (struct ieee80211_radiotap_header *)skb->data; - u16 len; - - /* - * there must be a radiotap header at the - * start in this case - */ - if (unlikely(prthdr->it_version)) { - /* only version 0 is supported */ - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - skb->dev = local->mdev; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(*pkt_data)); - pkt_data->ifindex = dev->ifindex; - pkt_data->mgmt_iface = 0; - pkt_data->do_not_encrypt = 1; - - /* above needed because we set skb device to master */ - - /* - * fix up the pointers accounting for the radiotap - * header still being in there. We are being given - * a precooked IEEE80211 header so no need for - * normal processing - */ - len = le16_to_cpu(get_unaligned(&prthdr->it_len)); - skb_set_mac_header(skb, len); - skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr)); - skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr)); - - /* - * pass the radiotap header up to - * the next stage intact - */ - dev_queue_xmit(skb); - - return NETDEV_TX_OK; -} - - -/** - * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type - * subinterfaces (wlan#, WDS, and VLAN interfaces) - * @skb: packet to be sent - * @dev: incoming interface - * - * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will - * not be freed, and caller is responsible for either retrying later or freeing - * skb). - * - * This function takes in an Ethernet header and encapsulates it with suitable - * IEEE 802.11 header based on which interface the packet is coming in. The - * 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) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; - struct ieee80211_sub_if_data *sdata; - int ret = 1, head_need; - u16 ethertype, hdrlen, fc; - struct ieee80211_hdr hdr; - const u8 *encaps_data; - int encaps_len, skip_header_bytes; - int nh_pos, h_pos, no_encrypt = 0; - struct sta_info *sta; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (unlikely(skb->len < ETH_HLEN)) { - printk(KERN_DEBUG "%s: short skb (len=%d)\n", - dev->name, skb->len); - ret = 0; - goto fail; - } - - nh_pos = skb_network_header(skb) - skb->data; - h_pos = skb_transport_header(skb) - skb->data; - - /* convert Ethernet header to proper 802.11 header (based on - * operation mode) */ - ethertype = (skb->data[12] << 8) | skb->data[13]; - /* TODO: handling for 802.1x authorized/unauthorized port */ - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; - - if (likely(sdata->type == IEEE80211_IF_TYPE_AP || - sdata->type == IEEE80211_IF_TYPE_VLAN)) { - fc |= IEEE80211_FCTL_FROMDS; - /* DA BSSID SA */ - memcpy(hdr.addr1, skb->data, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); - memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); - hdrlen = 24; - } else if (sdata->type == IEEE80211_IF_TYPE_WDS) { - fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; - /* RA TA DA SA */ - memcpy(hdr.addr1, sdata->u.wds.remote_addr, 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); - hdrlen = 30; - } else if (sdata->type == IEEE80211_IF_TYPE_STA) { - fc |= IEEE80211_FCTL_TODS; - /* BSSID SA DA */ - memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); - memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); - memcpy(hdr.addr3, skb->data, ETH_ALEN); - hdrlen = 24; - } else if (sdata->type == IEEE80211_IF_TYPE_IBSS) { - /* DA SA BSSID */ - memcpy(hdr.addr1, skb->data, ETH_ALEN); - memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); - memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN); - hdrlen = 24; - } else { - ret = 0; - goto fail; - } - - /* receiver is QoS enabled, use a QoS type frame */ - sta = sta_info_get(local, hdr.addr1); - if (sta) { - if (sta->flags & WLAN_STA_WME) { - fc |= IEEE80211_STYPE_QOS_DATA; - hdrlen += 2; - } - sta_info_put(sta); - } - - hdr.frame_control = cpu_to_le16(fc); - hdr.duration_id = 0; - hdr.seq_ctrl = 0; - - skip_header_bytes = ETH_HLEN; - if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { - encaps_data = bridge_tunnel_header; - encaps_len = sizeof(bridge_tunnel_header); - skip_header_bytes -= 2; - } else if (ethertype >= 0x600) { - encaps_data = rfc1042_header; - encaps_len = sizeof(rfc1042_header); - skip_header_bytes -= 2; - } else { - encaps_data = NULL; - encaps_len = 0; - } - - skb_pull(skb, skip_header_bytes); - nh_pos -= skip_header_bytes; - h_pos -= skip_header_bytes; - - /* TODO: implement support for fragments so that there is no need to - * reallocate and copy payload; it might be enough to support one - * extra fragment that would be copied in the beginning of the frame - * data.. anyway, it would be nice to include this into skb structure - * somehow - * - * There are few options for this: - * use skb->cb as an extra space for 802.11 header - * allocate new buffer if not enough headroom - * make sure that there is enough headroom in every skb by increasing - * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and - * alloc_skb() (net/core/skbuff.c) - */ - head_need = hdrlen + encaps_len + local->tx_headroom; - head_need -= skb_headroom(skb); - - /* We are going to modify skb data, so make a copy of it if happens to - * be cloned. This could happen, e.g., with Linux bridge code passing - * us broadcast frames. */ - - if (head_need > 0 || skb_cloned(skb)) { -#if 0 - printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes " - "of headroom\n", dev->name, head_need); -#endif - - if (skb_cloned(skb)) - I802_DEBUG_INC(local->tx_expand_skb_head_cloned); - else - I802_DEBUG_INC(local->tx_expand_skb_head); - /* Since we have to reallocate the buffer, make sure that there - * is enough room for possible WEP IV/ICV and TKIP (8 bytes - * before payload and 12 after). */ - if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8), - 12, GFP_ATOMIC)) { - printk(KERN_DEBUG "%s: failed to reallocate TX buffer" - "\n", dev->name); - goto fail; - } - } - - if (encaps_data) { - memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); - nh_pos += encaps_len; - h_pos += encaps_len; - } - memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); - nh_pos += hdrlen; - h_pos += hdrlen; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = dev->ifindex; - pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); - pkt_data->do_not_encrypt = no_encrypt; - - skb->dev = local->mdev; - sdata->stats.tx_packets++; - sdata->stats.tx_bytes += skb->len; - - /* Update skb pointers to various headers since this modified frame - * is going to go through Linux networking code that may potentially - * need things like pointer to IP header. */ - skb_set_mac_header(skb, 0); - skb_set_network_header(skb, nh_pos); - skb_set_transport_header(skb, h_pos); - - dev->trans_start = jiffies; - dev_queue_xmit(skb); - - return 0; - - fail: - if (!ret) - dev_kfree_skb(skb); - - return ret; -} - - -/* - * This is the transmit routine for the 802.11 type interfaces - * called by upper layers of the linux networking - * stack when it has a frame to transmit - */ -static int -ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; - struct ieee80211_hdr *hdr; - u16 fc; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (skb->len < 10) { - dev_kfree_skb(skb); - return 0; - } - - if (skb_headroom(skb) < sdata->local->tx_headroom) { - if (pskb_expand_head(skb, sdata->local->tx_headroom, - 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return 0; - } - } - - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; - pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); - - skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ - skb->dev = sdata->local->mdev; - - /* - * We're using the protocol field of the the frame control header - * to request TX callback for hostapd. BIT(1) is checked. - */ - if ((fc & BIT(1)) == BIT(1)) { - pkt_data->req_tx_status = 1; - fc &= ~BIT(1); - hdr->frame_control = cpu_to_le16(fc); - } - - pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED); - - sdata->stats.tx_packets++; - sdata->stats.tx_bytes += skb->len; - - dev_queue_xmit(skb); - - return 0; -} - - -static void ieee80211_beacon_add_tim(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, - struct sk_buff *skb) -{ - u8 *pos, *tim; - int aid0 = 0; - int i, have_bits = 0, n1, n2; - - /* Generate bitmap for TIM only if there are any STAs in power save - * mode. */ - spin_lock_bh(&local->sta_lock); - if (atomic_read(&bss->num_sta_ps) > 0) - /* in the hope that this is faster than - * checking byte-for-byte */ - have_bits = !bitmap_empty((unsigned long*)bss->tim, - IEEE80211_MAX_AID+1); - - if (bss->dtim_count == 0) - bss->dtim_count = bss->dtim_period - 1; - else - bss->dtim_count--; - - tim = pos = (u8 *) skb_put(skb, 6); - *pos++ = WLAN_EID_TIM; - *pos++ = 4; - *pos++ = bss->dtim_count; - *pos++ = bss->dtim_period; - - if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) - aid0 = 1; - - if (have_bits) { - /* Find largest even number N1 so that bits numbered 1 through - * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits - * (N2 + 1) x 8 through 2007 are 0. */ - n1 = 0; - for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) { - if (bss->tim[i]) { - n1 = i & 0xfe; - break; - } - } - n2 = n1; - for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) { - if (bss->tim[i]) { - n2 = i; - break; - } - } - - /* Bitmap control */ - *pos++ = n1 | aid0; - /* Part Virt Bitmap */ - memcpy(pos, bss->tim + n1, n2 - n1 + 1); - - tim[1] = n2 - n1 + 4; - skb_put(skb, n2 - n1); - } else { - *pos++ = aid0; /* Bitmap control */ - *pos++ = 0; /* Part Virt Bitmap */ - } - spin_unlock_bh(&local->sta_lock); -} - - -struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, - struct ieee80211_tx_control *control) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct sk_buff *skb; - struct net_device *bdev; - struct ieee80211_sub_if_data *sdata = NULL; - struct ieee80211_if_ap *ap = NULL; - struct ieee80211_rate *rate; - struct rate_control_extra extra; - u8 *b_head, *b_tail; - int bh_len, bt_len; - - bdev = dev_get_by_index(if_id); - if (bdev) { - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - ap = &sdata->u.ap; - dev_put(bdev); - } - - if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || - !ap->beacon_head) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "no beacon data avail for idx=%d " - "(%s)\n", if_id, bdev ? bdev->name : "N/A"); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - return NULL; - } - - /* Assume we are generating the normal beacon locally */ - b_head = ap->beacon_head; - b_tail = ap->beacon_tail; - bh_len = ap->beacon_head_len; - bt_len = ap->beacon_tail_len; - - skb = dev_alloc_skb(local->tx_headroom + - bh_len + bt_len + 256 /* maximum TIM len */); - if (!skb) - return NULL; - - skb_reserve(skb, local->tx_headroom); - memcpy(skb_put(skb, bh_len), b_head, bh_len); - - ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); - - ieee80211_beacon_add_tim(local, ap, skb); - - if (b_tail) { - memcpy(skb_put(skb, bt_len), b_tail, bt_len); - } - - if (control) { - memset(&extra, 0, sizeof(extra)); - extra.mode = local->oper_hw_mode; - - rate = rate_control_get_rate(local, local->mdev, skb, &extra); - if (!rate) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate " - "found\n", local->mdev->name); - } - dev_kfree_skb(skb); - return NULL; - } - - control->tx_rate = (local->short_preamble && - (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - rate->val2 : rate->val; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->power_level = local->hw.conf.power_level; - control->flags |= IEEE80211_TXCTL_NO_ACK; - control->retry_limit = 1; - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - } - - ap->num_beacons++; - return skb; -} -EXPORT_SYMBOL(ieee80211_beacon_get); - __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, size_t frame_len, const struct ieee80211_tx_control *frame_txctl) @@ -2168,110 +505,6 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_ctstoself_duration); -void ieee80211_rts_get(struct ieee80211_hw *hw, - const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, - struct ieee80211_rts *rts) -{ - const struct ieee80211_hdr *hdr = frame; - u16 fctl; - - fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; - rts->frame_control = cpu_to_le16(fctl); - rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl); - memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); - memcpy(rts->ta, hdr->addr2, sizeof(rts->ta)); -} -EXPORT_SYMBOL(ieee80211_rts_get); - -void ieee80211_ctstoself_get(struct ieee80211_hw *hw, - const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, - struct ieee80211_cts *cts) -{ - const struct ieee80211_hdr *hdr = frame; - u16 fctl; - - fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; - cts->frame_control = cpu_to_le16(fctl); - cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl); - memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); -} -EXPORT_SYMBOL(ieee80211_ctstoself_get); - -struct sk_buff * -ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, - struct ieee80211_tx_control *control) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct sk_buff *skb; - struct sta_info *sta; - ieee80211_tx_handler *handler; - struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP; - struct net_device *bdev; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_ap *bss = NULL; - - bdev = dev_get_by_index(if_id); - if (bdev) { - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - bss = &sdata->u.ap; - dev_put(bdev); - } - if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head) - return NULL; - - if (bss->dtim_count != 0) - return NULL; /* send buffered bc/mc only after DTIM beacon */ - memset(control, 0, sizeof(*control)); - while (1) { - skb = skb_dequeue(&bss->ps_bc_buf); - if (!skb) - return NULL; - local->total_ps_buffered--; - - if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) { - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) skb->data; - /* more buffered multicast/broadcast frames ==> set - * MoreData flag in IEEE 802.11 header to inform PS - * STAs */ - hdr->frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - if (ieee80211_tx_prepare(&tx, skb, local->mdev, control) == 0) - break; - dev_kfree_skb_any(skb); - } - sta = tx.sta; - tx.u.tx.ps_buffered = 1; - - for (handler = local->tx_handlers; *handler != NULL; handler++) { - res = (*handler)(&tx); - if (res == TXRX_DROP || res == TXRX_QUEUED) - break; - } - dev_put(tx.dev); - skb = tx.skb; /* handlers are allowed to change skb */ - - if (res == TXRX_DROP) { - I802_DEBUG_INC(local->tx_handlers_drop); - dev_kfree_skb(skb); - skb = NULL; - } else if (res == TXRX_QUEUED) { - I802_DEBUG_INC(local->tx_handlers_queued); - skb = NULL; - } - - if (sta) - sta_info_put(sta); - - return skb; -} -EXPORT_SYMBOL(ieee80211_get_buffered_bc); - static int __ieee80211_if_config(struct net_device *dev, struct sk_buff *beacon, struct ieee80211_tx_control *control) @@ -2912,64 +1145,6 @@ int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, EXPORT_SYMBOL(ieee80211_radar_status); -static ieee80211_txrx_result -ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - - /* TODO: this could be part of tx_status handling, so that the number - * of retries would be known; TX rate should in that case be stored - * somewhere with the packet */ - - /* Estimate total channel use caused by this frame */ - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (mode->mode == MODE_IEEE80211A || - mode->mode == MODE_ATHEROS_TURBO || - mode->mode == MODE_ATHEROS_TURBOG || - (mode->mode == MODE_IEEE80211G && - tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS) - load += 2 * hdrtime; - else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) - load += hdrtime; - - load += skb->len * tx->u.tx.rate->rate_inv; - - if (tx->u.tx.extra_frag) { - int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - load += 2 * hdrtime; - load += tx->u.tx.extra_frag[i]->len * - tx->u.tx.rate->rate; - } - } - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - local->channel_use_raw += load; - if (tx->sta) - tx->sta->channel_use_raw += load; - tx->sdata->channel_use_raw += load; - - return TXRX_CONTINUE; -} - - static void ieee80211_stat_refresh(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; @@ -3365,26 +1540,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, } EXPORT_SYMBOL(ieee80211_tx_status); -/* TODO: implement register/unregister functions for adding TX/RX handlers - * into ordered list */ - -static ieee80211_tx_handler ieee80211_tx_handlers[] = -{ - ieee80211_tx_h_check_assoc, - ieee80211_tx_h_sequence, - ieee80211_tx_h_ps_buf, - ieee80211_tx_h_select_key, - ieee80211_tx_h_michael_mic_add, - ieee80211_tx_h_fragment, - ieee80211_tx_h_tkip_encrypt, - ieee80211_tx_h_ccmp_encrypt, - ieee80211_tx_h_wep_encrypt, - ieee80211_tx_h_rate_ctrl, - ieee80211_tx_h_misc, - ieee80211_tx_h_load_stats, - NULL -}; - int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) { diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 35e2ce52faeb..9d3401d12917 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -731,8 +731,6 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, struct ieee80211_hw_mode *mode); void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); -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); void ieee80211_if_setup(struct net_device *dev); void ieee80211_if_mgmt_setup(struct net_device *dev); int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, @@ -746,8 +744,11 @@ void ieee80211_key_threshold_notify(struct net_device *dev, u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); int ieee80211_is_eapol(const struct sk_buff *skb); -extern const unsigned char rfc1042_header[]; -extern const unsigned char bridge_tunnel_header[]; +extern const unsigned char rfc1042_header[6]; +extern const unsigned char bridge_tunnel_header[6]; + +int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, + int rate, int erp, int short_preamble); /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; @@ -823,6 +824,15 @@ void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode); extern ieee80211_rx_handler ieee80211_rx_pre_handlers[]; extern ieee80211_rx_handler ieee80211_rx_handlers[]; +/* tx handling */ +extern ieee80211_tx_handler ieee80211_tx_handlers[]; +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); +int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); + /* for wiphy privid */ extern void *mac80211_wiphy_privid; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c new file mode 100644 index 000000000000..dc128b412eab --- /dev/null +++ b/net/mac80211/tx.c @@ -0,0 +1,1869 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007 Johannes Berg + * + * 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. + * + * + * Transmit and frame generation functions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211_i.h" +#include "ieee80211_led.h" +#include "wep.h" +#include "wpa.h" +#include "wme.h" +#include "ieee80211_rate.h" + +#define IEEE80211_TX_OK 0 +#define IEEE80211_TX_AGAIN 1 +#define IEEE80211_TX_FRAG_AGAIN 2 + +/* misc utils */ + +static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, + struct ieee80211_hdr *hdr) +{ + /* Set the sequence number for this frame. */ + hdr->seq_ctrl = cpu_to_le16(sdata->sequence); + + /* Increase the sequence number. */ + sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ; +} + +#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP +static void ieee80211_dump_frame(const char *ifname, const char *title, + const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 fc; + int hdrlen; + + printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); + if (skb->len < 4) { + printk("\n"); + return; + } + + fc = le16_to_cpu(hdr->frame_control); + hdrlen = ieee80211_get_hdrlen(fc); + if (hdrlen > skb->len) + hdrlen = skb->len; + if (hdrlen >= 4) + printk(" FC=0x%04x DUR=0x%04x", + fc, le16_to_cpu(hdr->duration_id)); + if (hdrlen >= 10) + printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1)); + if (hdrlen >= 16) + printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2)); + if (hdrlen >= 24) + printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3)); + if (hdrlen >= 30) + printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4)); + printk("\n"); +} +#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ +static inline void ieee80211_dump_frame(const char *ifname, const char *title, + struct sk_buff *skb) +{ +} +#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ + +static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, + int next_frag_len) +{ + int rate, mrate, erp, dur, i; + struct ieee80211_rate *txrate = tx->u.tx.rate; + struct ieee80211_local *local = tx->local; + struct ieee80211_hw_mode *mode = tx->u.tx.mode; + + erp = txrate->flags & IEEE80211_RATE_ERP; + + /* + * data and mgmt (except PS Poll): + * - during CFP: 32768 + * - during contention period: + * if addr1 is group address: 0 + * if more fragments = 0 and addr1 is individual address: time to + * transmit one ACK plus SIFS + * if more fragments = 1 and addr1 is individual address: time to + * transmit next fragment plus 2 x ACK plus 3 x SIFS + * + * IEEE 802.11, 9.6: + * - control response frame (CTS or ACK) shall be transmitted using the + * same rate as the immediately previous frame in the frame exchange + * sequence, if this rate belongs to the PHY mandatory rates, or else + * at the highest possible rate belonging to the PHY rates in the + * BSSBasicRateSet + */ + + if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) { + /* TODO: These control frames are not currently sent by + * 80211.o, but should they be implemented, this function + * needs to be updated to support duration field calculation. + * + * RTS: time needed to transmit pending data/mgmt frame plus + * one CTS frame plus one ACK frame plus 3 x SIFS + * CTS: duration of immediately previous RTS minus time + * required to transmit CTS and its SIFS + * ACK: 0 if immediately previous directed data/mgmt had + * more=0, with more=1 duration in ACK frame is duration + * from previous frame minus time needed to transmit ACK + * and its SIFS + * PS Poll: BIT(15) | BIT(14) | aid + */ + return 0; + } + + /* data/mgmt */ + if (0 /* FIX: data/mgmt during CFP */) + return 32768; + + if (group_addr) /* Group address as the destination - no ACK */ + return 0; + + /* Individual destination address: + * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes) + * CTS and ACK frames shall be transmitted using the highest rate in + * basic rate set that is less than or equal to the rate of the + * immediately previous frame and that is using the same modulation + * (CCK or OFDM). If no basic rate set matches with these requirements, + * the highest mandatory rate of the PHY that is less than or equal to + * the rate of the previous frame is used. + * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps + */ + rate = -1; + mrate = 10; /* use 1 Mbps if everything fails */ + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *r = &mode->rates[i]; + if (r->rate > txrate->rate) + break; + + if (IEEE80211_RATE_MODULATION(txrate->flags) != + IEEE80211_RATE_MODULATION(r->flags)) + continue; + + if (r->flags & IEEE80211_RATE_BASIC) + rate = r->rate; + else if (r->flags & IEEE80211_RATE_MANDATORY) + mrate = r->rate; + } + if (rate == -1) { + /* No matching basic rate found; use highest suitable mandatory + * PHY rate */ + rate = mrate; + } + + /* Time needed to transmit ACK + * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up + * to closest integer */ + + dur = ieee80211_frame_duration(local, 10, rate, erp, + local->short_preamble); + + if (next_frag_len) { + /* Frame is fragmented: duration increases with time needed to + * transmit next fragment plus ACK and 2 x SIFS. */ + dur *= 2; /* ACK + SIFS */ + /* next fragment */ + dur += ieee80211_frame_duration(local, next_frag_len, + txrate->rate, erp, + local->short_preamble); + } + + return dur; +} + +static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, + int queue) +{ + return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); +} + +static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, + int queue) +{ + return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); +} + +static int inline is_ieee80211_device(struct net_device *dev, + struct net_device *master) +{ + return (wdev_priv(dev->ieee80211_ptr) == + wdev_priv(master->ieee80211_ptr)); +} + +/* tx handlers */ + +static ieee80211_txrx_result +ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) +{ +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + struct sk_buff *skb = tx->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + u32 sta_flags; + + if (unlikely(tx->local->sta_scanning != 0) && + ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) + return TXRX_DROP; + + if (tx->u.tx.ps_buffered) + return TXRX_CONTINUE; + + sta_flags = tx->sta ? tx->sta->flags : 0; + + if (likely(tx->u.tx.unicast)) { + if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && + tx->sdata->type != IEEE80211_IF_TYPE_IBSS && + (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: dropped data frame to not " + "associated station " MAC_FMT "\n", + tx->dev->name, MAC_ARG(hdr->addr1)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); + return TXRX_DROP; + } + } else { + if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + tx->local->num_sta == 0 && + !tx->local->allow_broadcast_always && + tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) { + /* + * No associated STAs - no need to send multicast + * frames. + */ + return TXRX_DROP; + } + return TXRX_CONTINUE; + } + + if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x && + !(sta_flags & WLAN_STA_AUTHORIZED))) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT + " (unauthorized port)\n", tx->dev->name, + MAC_ARG(hdr->addr1)); +#endif + I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port); + return TXRX_DROP; + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + + if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) + ieee80211_include_sequence(tx->sdata, hdr); + + return TXRX_CONTINUE; +} + +/* This function is called whenever the AP is about to exceed the maximum limit + * of buffered frames for power saving STAs. This situation should not really + * happen often during normal operation, so dropping the oldest buffered packet + * from each queue should be OK to make some room for new frames. */ +static void purge_old_ps_buffers(struct ieee80211_local *local) +{ + int total = 0, purged = 0; + struct sk_buff *skb; + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + + read_lock(&local->sub_if_lock); + list_for_each_entry(sdata, &local->sub_if_list, list) { + struct ieee80211_if_ap *ap; + if (sdata->dev == local->mdev || + sdata->type != IEEE80211_IF_TYPE_AP) + continue; + ap = &sdata->u.ap; + skb = skb_dequeue(&ap->ps_bc_buf); + if (skb) { + purged++; + dev_kfree_skb(skb); + } + total += skb_queue_len(&ap->ps_bc_buf); + } + read_unlock(&local->sub_if_lock); + + spin_lock_bh(&local->sta_lock); + list_for_each_entry(sta, &local->sta_list, list) { + skb = skb_dequeue(&sta->ps_tx_buf); + if (skb) { + purged++; + dev_kfree_skb(skb); + } + total += skb_queue_len(&sta->ps_tx_buf); + } + spin_unlock_bh(&local->sta_lock); + + local->total_ps_buffered = total; + printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", + local->mdev->name, purged); +} + +static inline ieee80211_txrx_result +ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) +{ + /* broadcast/multicast frame */ + /* If any of the associated stations is in power save mode, + * the frame is buffered to be sent after DTIM beacon frame */ + if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) && + tx->sdata->type != IEEE80211_IF_TYPE_WDS && + tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) && + !(tx->fc & IEEE80211_FCTL_ORDER)) { + 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 (net_ratelimit()) { + printk(KERN_DEBUG "%s: BC TX buffer full - " + "dropping the oldest frame\n", + tx->dev->name); + } + 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 TXRX_QUEUED; + } + + return TXRX_CONTINUE; +} + +static inline ieee80211_txrx_result +ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) +{ + struct sta_info *sta = tx->sta; + + if (unlikely(!sta || + ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && + (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) + return TXRX_CONTINUE; + + if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { + struct ieee80211_tx_packet_data *pkt_data; +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries " + "before %d)\n", + MAC_ARG(sta->addr), sta->aid, + skb_queue_len(&sta->ps_tx_buf)); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + sta->flags |= WLAN_STA_TIM; + if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) + purge_old_ps_buffers(tx->local); + if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { + struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: STA " MAC_FMT " TX " + "buffer full - dropping oldest frame\n", + tx->dev->name, MAC_ARG(sta->addr)); + } + dev_kfree_skb(old); + } else + tx->local->total_ps_buffered++; + /* Queue frame to be sent after STA sends an PS Poll frame */ + if (skb_queue_empty(&sta->ps_tx_buf)) { + if (tx->local->ops->set_tim) + tx->local->ops->set_tim(local_to_hw(tx->local), + sta->aid, 1); + if (tx->sdata->bss) + bss_tim_set(tx->local, tx->sdata->bss, sta->aid); + } + pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; + pkt_data->jiffies = jiffies; + skb_queue_tail(&sta->ps_tx_buf, tx->skb); + return TXRX_QUEUED; + } +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + else if (unlikely(sta->flags & WLAN_STA_PS)) { + printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll " + "set -> send frame\n", tx->dev->name, + MAC_ARG(sta->addr)); + } +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + sta->pspoll = 0; + + return TXRX_CONTINUE; +} + + +static ieee80211_txrx_result +ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) +{ + if (unlikely(tx->u.tx.ps_buffered)) + return TXRX_CONTINUE; + + if (tx->u.tx.unicast) + return ieee80211_tx_h_unicast_ps_buf(tx); + else + return ieee80211_tx_h_multicast_ps_buf(tx); +} + + + + +static ieee80211_txrx_result +ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) +{ + if (tx->sta) + tx->u.tx.control->key_idx = tx->sta->key_idx_compression; + else + tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; + + if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + tx->key = NULL; + else if (tx->sta && tx->sta->key) + tx->key = tx->sta->key; + else if (tx->sdata->default_key) + tx->key = tx->sdata->default_key; + else if (tx->sdata->drop_unencrypted && + !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { + I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); + return TXRX_DROP; + } else + tx->key = NULL; + + if (tx->key) { + tx->key->tx_rx_count++; + if (unlikely(tx->local->key_tx_rx_threshold && + tx->key->tx_rx_count > + tx->local->key_tx_rx_threshold)) { + ieee80211_key_threshold_notify(tx->dev, tx->key, + tx->sta); + } + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + size_t hdrlen, per_fragm, num_fragm, payload_len, left; + struct sk_buff **frags, *first, *frag; + int i; + u16 seq; + u8 *pos; + int frag_threshold = tx->local->fragmentation_threshold; + + if (!tx->fragmented) + return TXRX_CONTINUE; + + first = tx->skb; + + hdrlen = ieee80211_get_hdrlen(tx->fc); + payload_len = first->len - hdrlen; + per_fragm = frag_threshold - hdrlen - FCS_LEN; + num_fragm = (payload_len + per_fragm - 1) / per_fragm; + + frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); + if (!frags) + goto fail; + + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); + seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; + pos = first->data + hdrlen + per_fragm; + left = payload_len - per_fragm; + for (i = 0; i < num_fragm - 1; i++) { + struct ieee80211_hdr *fhdr; + size_t copylen; + + if (left <= 0) + goto fail; + + /* reserve enough extra head and tail room for possible + * encryption */ + frag = frags[i] = + dev_alloc_skb(tx->local->tx_headroom + + frag_threshold + + IEEE80211_ENCRYPT_HEADROOM + + IEEE80211_ENCRYPT_TAILROOM); + if (!frag) + goto fail; + /* Make sure that all fragments use the same priority so + * that they end up using the same TX queue */ + frag->priority = first->priority; + skb_reserve(frag, tx->local->tx_headroom + + IEEE80211_ENCRYPT_HEADROOM); + fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); + memcpy(fhdr, first->data, hdrlen); + if (i == num_fragm - 2) + fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); + fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); + copylen = left > per_fragm ? per_fragm : left; + memcpy(skb_put(frag, copylen), pos, copylen); + + pos += copylen; + left -= copylen; + } + skb_trim(first, hdrlen + per_fragm); + + tx->u.tx.num_extra_frag = num_fragm - 1; + tx->u.tx.extra_frag = frags; + + return TXRX_CONTINUE; + + fail: + printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); + if (frags) { + for (i = 0; i < num_fragm - 1; i++) + if (frags[i]) + dev_kfree_skb(frags[i]); + kfree(frags); + } + I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); + return TXRX_DROP; +} + +static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) +{ + if (tx->key->force_sw_encrypt) { + if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) + return -1; + } else { + tx->u.tx.control->key_idx = tx->key->hw_key_idx; + if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { + if (ieee80211_wep_add_iv(tx->local, skb, tx->key) == + NULL) + return -1; + } + } + return 0; +} + +static ieee80211_txrx_result +ieee80211_tx_h_wep_encrypt(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + u16 fc; + + fc = le16_to_cpu(hdr->frame_control); + + if (!tx->key || tx->key->alg != ALG_WEP || + ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && + ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) + return TXRX_CONTINUE; + + tx->u.tx.control->iv_len = WEP_IV_LEN; + tx->u.tx.control->icv_len = WEP_ICV_LEN; + ieee80211_tx_set_iswep(tx); + + if (wep_encrypt_skb(tx, tx->skb) < 0) { + I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); + return TXRX_DROP; + } + + if (tx->u.tx.extra_frag) { + int i; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { + I802_DEBUG_INC(tx->local-> + tx_handlers_drop_wep); + return TXRX_DROP; + } + } + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) +{ + struct rate_control_extra extra; + + memset(&extra, 0, sizeof(extra)); + extra.mode = tx->u.tx.mode; + extra.mgmt_data = tx->sdata && + tx->sdata->type == IEEE80211_IF_TYPE_MGMT; + extra.ethertype = tx->ethertype; + + tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb, + &extra); + if (unlikely(extra.probe != NULL)) { + tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; + tx->u.tx.probe_last_frag = 1; + tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; + tx->u.tx.rate = extra.probe; + } else { + tx->u.tx.control->alt_retry_rate = -1; + } + if (!tx->u.tx.rate) + return TXRX_DROP; + if (tx->u.tx.mode->mode == MODE_IEEE80211G && + tx->sdata->use_protection && tx->fragmented && + extra.nonerp) { + tx->u.tx.last_frag_rate = tx->u.tx.rate; + tx->u.tx.probe_last_frag = extra.probe ? 1 : 0; + + tx->u.tx.rate = extra.nonerp; + tx->u.tx.control->rate = extra.nonerp; + tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + } else { + tx->u.tx.last_frag_rate = tx->u.tx.rate; + tx->u.tx.control->rate = tx->u.tx.rate; + } + tx->u.tx.control->tx_rate = tx->u.tx.rate->val; + if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && + tx->local->short_preamble && + (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { + tx->u.tx.short_preamble = 1; + tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + u16 dur; + struct ieee80211_tx_control *control = tx->u.tx.control; + struct ieee80211_hw_mode *mode = tx->u.tx.mode; + + if (!is_multicast_ether_addr(hdr->addr1)) { + if (tx->skb->len + FCS_LEN > tx->local->rts_threshold && + tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) { + control->flags |= IEEE80211_TXCTL_USE_RTS_CTS; + control->retry_limit = + tx->local->long_retry_limit; + } else { + control->retry_limit = + tx->local->short_retry_limit; + } + } else { + control->retry_limit = 1; + } + + if (tx->fragmented) { + /* Do not use multiple retry rates when sending fragmented + * frames. + * TODO: The last fragment could still use multiple retry + * rates. */ + control->alt_retry_rate = -1; + } + + /* Use CTS protection for unicast frames sent using extended rates if + * there are associated non-ERP stations and RTS/CTS is not configured + * for the frame. */ + if (mode->mode == MODE_IEEE80211G && + (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && + tx->u.tx.unicast && tx->sdata->use_protection && + !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) + control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; + + /* Setup duration field for the first fragment of the frame. Duration + * for remaining fragments will be updated when they are being sent + * to low-level driver in ieee80211_tx(). */ + dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), + tx->fragmented ? tx->u.tx.extra_frag[0]->len : + 0); + hdr->duration_id = cpu_to_le16(dur); + + if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || + (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + struct ieee80211_rate *rate; + + /* Do not use multiple retry rates when using RTS/CTS */ + control->alt_retry_rate = -1; + + /* Use min(data rate, max base rate) as CTS/RTS rate */ + rate = tx->u.tx.rate; + while (rate > mode->rates && + !(rate->flags & IEEE80211_RATE_BASIC)) + rate--; + + control->rts_cts_rate = rate->val; + control->rts_rate = rate; + } + + if (tx->sta) { + tx->sta->tx_packets++; + tx->sta->tx_fragments++; + tx->sta->tx_bytes += tx->skb->len; + if (tx->u.tx.extra_frag) { + int i; + tx->sta->tx_fragments += tx->u.tx.num_extra_frag; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + tx->sta->tx_bytes += + tx->u.tx.extra_frag[i]->len; + } + } + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_local *local = tx->local; + struct ieee80211_hw_mode *mode = tx->u.tx.mode; + struct sk_buff *skb = tx->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u32 load = 0, hdrtime; + + /* TODO: this could be part of tx_status handling, so that the number + * of retries would be known; TX rate should in that case be stored + * somewhere with the packet */ + + /* Estimate total channel use caused by this frame */ + + /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, + * 1 usec = 1/8 * (1080 / 10) = 13.5 */ + + if (mode->mode == MODE_IEEE80211A || + mode->mode == MODE_ATHEROS_TURBO || + mode->mode == MODE_ATHEROS_TURBOG || + (mode->mode == MODE_IEEE80211G && + tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) + hdrtime = CHAN_UTIL_HDR_SHORT; + else + hdrtime = CHAN_UTIL_HDR_LONG; + + load = hdrtime; + if (!is_multicast_ether_addr(hdr->addr1)) + load += hdrtime; + + if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + load += 2 * hdrtime; + else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + load += hdrtime; + + load += skb->len * tx->u.tx.rate->rate_inv; + + if (tx->u.tx.extra_frag) { + int i; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + load += 2 * hdrtime; + load += tx->u.tx.extra_frag[i]->len * + tx->u.tx.rate->rate; + } + } + + /* Divide channel_use by 8 to avoid wrapping around the counter */ + load >>= CHAN_UTIL_SHIFT; + local->channel_use_raw += load; + if (tx->sta) + tx->sta->channel_use_raw += load; + tx->sdata->channel_use_raw += load; + + return TXRX_CONTINUE; +} + +/* TODO: implement register/unregister functions for adding TX/RX handlers + * into ordered list */ + +ieee80211_tx_handler ieee80211_tx_handlers[] = +{ + ieee80211_tx_h_check_assoc, + ieee80211_tx_h_sequence, + ieee80211_tx_h_ps_buf, + ieee80211_tx_h_select_key, + ieee80211_tx_h_michael_mic_add, + ieee80211_tx_h_fragment, + ieee80211_tx_h_tkip_encrypt, + ieee80211_tx_h_ccmp_encrypt, + ieee80211_tx_h_wep_encrypt, + ieee80211_tx_h_rate_ctrl, + ieee80211_tx_h_misc, + ieee80211_tx_h_load_stats, + NULL +}; + +/* actual transmit path */ + +/* + * deal with packet injection down monitor interface + * with Radiotap Header -- only called for monitor mode interface + */ +static ieee80211_txrx_result +__ieee80211_parse_tx_radiotap( + struct ieee80211_txrx_data *tx, + struct sk_buff *skb, struct ieee80211_tx_control *control) +{ + /* + * this is the moment to interpret and discard the radiotap header that + * must be at the start of the packet injected in Monitor mode + * + * Need to take some care with endian-ness since radiotap + * args are little-endian + */ + + struct ieee80211_radiotap_iterator iterator; + struct ieee80211_radiotap_header *rthdr = + (struct ieee80211_radiotap_header *) skb->data; + struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; + int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); + + /* + * default control situation for all injected packets + * FIXME: this does not suit all usage cases, expand to allow control + */ + + control->retry_limit = 1; /* no retry */ + control->key_idx = -1; /* no encryption key */ + control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT); + control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT | + IEEE80211_TXCTL_NO_ACK; + control->antenna_sel_tx = 0; /* default to default antenna */ + + /* + * for every radiotap entry that is present + * (ieee80211_radiotap_iterator_next returns -ENOENT when no more + * entries present, or -EINVAL on error) + */ + + while (!ret) { + int i, target_rate; + + ret = ieee80211_radiotap_iterator_next(&iterator); + + if (ret) + continue; + + /* see if this argument is something we can use */ + switch (iterator.this_arg_index) { + /* + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + */ + case IEEE80211_RADIOTAP_RATE: + /* + * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps + * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps + */ + target_rate = (*iterator.this_arg) * 5; + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *r = &mode->rates[i]; + + if (r->rate > target_rate) + continue; + + control->rate = r; + + if (r->flags & IEEE80211_RATE_PREAMBLE2) + control->tx_rate = r->val2; + else + control->tx_rate = r->val; + + /* end on exact match */ + if (r->rate == target_rate) + i = mode->num_rates; + } + break; + + case IEEE80211_RADIOTAP_ANTENNA: + /* + * radiotap uses 0 for 1st ant, mac80211 is 1 for + * 1st ant + */ + control->antenna_sel_tx = (*iterator.this_arg) + 1; + break; + + case IEEE80211_RADIOTAP_DBM_TX_POWER: + control->power_level = *iterator.this_arg; + break; + + case IEEE80211_RADIOTAP_FLAGS: + if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { + /* + * this indicates that the skb we have been + * handed has the 32-bit FCS CRC at the end... + * we should react to that by snipping it off + * because it will be recomputed and added + * on transmission + */ + if (skb->len < (iterator.max_length + FCS_LEN)) + return TXRX_DROP; + + skb_trim(skb, skb->len - FCS_LEN); + } + break; + + default: + break; + } + } + + if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ + return TXRX_DROP; + + /* + * remove the radiotap header + * iterator->max_length was sanity-checked against + * skb->len by iterator init + */ + skb_pull(skb, iterator.max_length); + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result inline +__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, + struct sk_buff *skb, + struct net_device *dev, + struct ieee80211_tx_control *control) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_sub_if_data *sdata; + ieee80211_txrx_result res = TXRX_CONTINUE; + + int hdrlen; + + memset(tx, 0, sizeof(*tx)); + tx->skb = skb; + tx->dev = dev; /* use original interface */ + tx->local = local; + tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); + tx->sta = sta_info_get(local, hdr->addr1); + tx->fc = le16_to_cpu(hdr->frame_control); + + /* + * set defaults for things that can be set by + * injected radiotap headers + */ + control->power_level = local->hw.conf.power_level; + control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta) + control->antenna_sel_tx = tx->sta->antenna_sel_tx; + + /* process and remove the injection radiotap header */ + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { + if (__ieee80211_parse_tx_radiotap(tx, skb, control) == + TXRX_DROP) { + return TXRX_DROP; + } + /* + * we removed the radiotap header after this point, + * we filled control with what we could use + * set to the actual ieee header now + */ + hdr = (struct ieee80211_hdr *) skb->data; + res = TXRX_QUEUED; /* indication it was monitor packet */ + } + + tx->u.tx.control = control; + tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1); + if (is_multicast_ether_addr(hdr->addr1)) + control->flags |= IEEE80211_TXCTL_NO_ACK; + else + control->flags &= ~IEEE80211_TXCTL_NO_ACK; + tx->fragmented = local->fragmentation_threshold < + IEEE80211_MAX_FRAG_THRESHOLD && tx->u.tx.unicast && + skb->len + FCS_LEN > local->fragmentation_threshold && + (!local->ops->set_frag_threshold); + if (!tx->sta) + control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; + else if (tx->sta->clear_dst_mask) { + control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; + tx->sta->clear_dst_mask = 0; + } + hdrlen = ieee80211_get_hdrlen(tx->fc); + if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { + u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; + tx->ethertype = (pos[0] << 8) | pos[1]; + } + control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; + + return res; +} + +/* Device in tx->dev has a reference added; use dev_put(tx->dev) when + * finished with it. */ +static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, + struct sk_buff *skb, + struct net_device *mdev, + struct ieee80211_tx_control *control) +{ + struct ieee80211_tx_packet_data *pkt_data; + struct net_device *dev; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + dev = dev_get_by_index(pkt_data->ifindex); + if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { + dev_put(dev); + dev = NULL; + } + if (unlikely(!dev)) + return -ENODEV; + __ieee80211_tx_prepare(tx, skb, dev, control); + return 0; +} + +static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, + struct ieee80211_txrx_data *tx) +{ + struct ieee80211_tx_control *control = tx->u.tx.control; + int ret, i; + + if (!ieee80211_qdisc_installed(local->mdev) && + __ieee80211_queue_stopped(local, 0)) { + netif_stop_queue(local->mdev); + return IEEE80211_TX_AGAIN; + } + if (skb) { + ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb); + ret = local->ops->tx(local_to_hw(local), skb, control); + if (ret) + return IEEE80211_TX_AGAIN; + local->mdev->trans_start = jiffies; + ieee80211_led_tx(local, 1); + } + if (tx->u.tx.extra_frag) { + control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT | + IEEE80211_TXCTL_CLEAR_DST_MASK | + IEEE80211_TXCTL_FIRST_FRAGMENT); + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + if (!tx->u.tx.extra_frag[i]) + continue; + if (__ieee80211_queue_stopped(local, control->queue)) + return IEEE80211_TX_FRAG_AGAIN; + if (i == tx->u.tx.num_extra_frag) { + control->tx_rate = tx->u.tx.last_frag_hwrate; + control->rate = tx->u.tx.last_frag_rate; + if (tx->u.tx.probe_last_frag) + control->flags |= + IEEE80211_TXCTL_RATE_CTRL_PROBE; + else + control->flags &= + ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + } + + ieee80211_dump_frame(local->mdev->name, + "TX to low-level driver", + tx->u.tx.extra_frag[i]); + ret = local->ops->tx(local_to_hw(local), + tx->u.tx.extra_frag[i], + control); + if (ret) + return IEEE80211_TX_FRAG_AGAIN; + local->mdev->trans_start = jiffies; + ieee80211_led_tx(local, 1); + tx->u.tx.extra_frag[i] = NULL; + } + kfree(tx->u.tx.extra_frag); + tx->u.tx.extra_frag = NULL; + } + return IEEE80211_TX_OK; +} + +static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control, int mgmt) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + ieee80211_tx_handler *handler; + struct ieee80211_txrx_data tx; + ieee80211_txrx_result res = TXRX_DROP, res_prepare; + int ret, i; + + WARN_ON(__ieee80211_queue_pending(local, control->queue)); + + if (unlikely(skb->len < 10)) { + dev_kfree_skb(skb); + return 0; + } + + res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); + + if (res_prepare == TXRX_DROP) { + dev_kfree_skb(skb); + return 0; + } + + sta = tx.sta; + tx.u.tx.mgmt_interface = mgmt; + tx.u.tx.mode = local->hw.conf.mode; + + if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */ + res = TXRX_CONTINUE; + } else { + for (handler = local->tx_handlers; *handler != NULL; + handler++) { + res = (*handler)(&tx); + if (res != TXRX_CONTINUE) + break; + } + } + + skb = tx.skb; /* handlers are allowed to change skb */ + + if (sta) + sta_info_put(sta); + + if (unlikely(res == TXRX_DROP)) { + I802_DEBUG_INC(local->tx_handlers_drop); + goto drop; + } + + if (unlikely(res == TXRX_QUEUED)) { + I802_DEBUG_INC(local->tx_handlers_queued); + return 0; + } + + if (tx.u.tx.extra_frag) { + for (i = 0; i < tx.u.tx.num_extra_frag; i++) { + int next_len, dur; + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) + tx.u.tx.extra_frag[i]->data; + + if (i + 1 < tx.u.tx.num_extra_frag) { + next_len = tx.u.tx.extra_frag[i + 1]->len; + } else { + next_len = 0; + tx.u.tx.rate = tx.u.tx.last_frag_rate; + tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val; + } + dur = ieee80211_duration(&tx, 0, next_len); + hdr->duration_id = cpu_to_le16(dur); + } + } + +retry: + ret = __ieee80211_tx(local, skb, &tx); + if (ret) { + struct ieee80211_tx_stored_packet *store = + &local->pending_packet[control->queue]; + + if (ret == IEEE80211_TX_FRAG_AGAIN) + skb = NULL; + set_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[control->queue]); + smp_mb(); + /* When the driver gets out of buffers during sending of + * fragments and calls ieee80211_stop_queue, there is + * a small window between IEEE80211_LINK_STATE_XOFF and + * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer + * gets available in that window (i.e. driver calls + * ieee80211_wake_queue), we would end up with ieee80211_tx + * called with IEEE80211_LINK_STATE_PENDING. Prevent this by + * continuing transmitting here when that situation is + * possible to have happened. */ + if (!__ieee80211_queue_stopped(local, control->queue)) { + clear_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[control->queue]); + goto retry; + } + memcpy(&store->control, control, + sizeof(struct ieee80211_tx_control)); + store->skb = skb; + store->extra_frag = tx.u.tx.extra_frag; + store->num_extra_frag = tx.u.tx.num_extra_frag; + store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; + store->last_frag_rate = tx.u.tx.last_frag_rate; + store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag; + } + return 0; + + drop: + if (skb) + dev_kfree_skb(skb); + for (i = 0; i < tx.u.tx.num_extra_frag; i++) + if (tx.u.tx.extra_frag[i]) + dev_kfree_skb(tx.u.tx.extra_frag[i]); + kfree(tx.u.tx.extra_frag); + return 0; +} + +/* device xmit handlers */ + +int ieee80211_master_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_tx_control control; + struct ieee80211_tx_packet_data *pkt_data; + struct net_device *odev = NULL; + struct ieee80211_sub_if_data *osdata; + int headroom; + int ret; + + /* + * copy control out of the skb so other people can use skb->cb + */ + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + memset(&control, 0, sizeof(struct ieee80211_tx_control)); + + if (pkt_data->ifindex) + odev = dev_get_by_index(pkt_data->ifindex); + if (unlikely(odev && !is_ieee80211_device(odev, dev))) { + 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 0; + } + osdata = IEEE80211_DEV_TO_SUB_IF(odev); + + headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; + if (skb_headroom(skb) < headroom) { + if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + dev_put(odev); + return 0; + } + } + + control.ifindex = odev->ifindex; + control.type = osdata->type; + if (pkt_data->req_tx_status) + control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; + if (pkt_data->do_not_encrypt) + control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + if (pkt_data->requeue) + control.flags |= IEEE80211_TXCTL_REQUEUE; + control.queue = pkt_data->queue; + + ret = ieee80211_tx(odev, skb, &control, + control.type == IEEE80211_IF_TYPE_MGMT); + dev_put(odev); + + return ret; +} + +int ieee80211_monitor_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_radiotap_header *prthdr = + (struct ieee80211_radiotap_header *)skb->data; + u16 len; + + /* + * there must be a radiotap header at the + * start in this case + */ + if (unlikely(prthdr->it_version)) { + /* only version 0 is supported */ + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + skb->dev = local->mdev; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + memset(pkt_data, 0, sizeof(*pkt_data)); + pkt_data->ifindex = dev->ifindex; + pkt_data->mgmt_iface = 0; + pkt_data->do_not_encrypt = 1; + + /* above needed because we set skb device to master */ + + /* + * fix up the pointers accounting for the radiotap + * header still being in there. We are being given + * a precooked IEEE80211 header so no need for + * normal processing + */ + len = le16_to_cpu(get_unaligned(&prthdr->it_len)); + skb_set_mac_header(skb, len); + skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr)); + skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr)); + + /* + * pass the radiotap header up to + * the next stage intact + */ + dev_queue_xmit(skb); + + return NETDEV_TX_OK; +} + +/** + * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type + * subinterfaces (wlan#, WDS, and VLAN interfaces) + * @skb: packet to be sent + * @dev: incoming interface + * + * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will + * not be freed, and caller is responsible for either retrying later or freeing + * skb). + * + * This function takes in an Ethernet header and encapsulates it with suitable + * IEEE 802.11 header based on which interface the packet is coming in. The + * 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) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_sub_if_data *sdata; + int ret = 1, head_need; + u16 ethertype, hdrlen, fc; + struct ieee80211_hdr hdr; + const u8 *encaps_data; + int encaps_len, skip_header_bytes; + int nh_pos, h_pos, no_encrypt = 0; + struct sta_info *sta; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (unlikely(skb->len < ETH_HLEN)) { + printk(KERN_DEBUG "%s: short skb (len=%d)\n", + dev->name, skb->len); + ret = 0; + goto fail; + } + + nh_pos = skb_network_header(skb) - skb->data; + h_pos = skb_transport_header(skb) - skb->data; + + /* convert Ethernet header to proper 802.11 header (based on + * operation mode) */ + ethertype = (skb->data[12] << 8) | skb->data[13]; + /* TODO: handling for 802.1x authorized/unauthorized port */ + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; + + if (likely(sdata->type == IEEE80211_IF_TYPE_AP || + sdata->type == IEEE80211_IF_TYPE_VLAN)) { + fc |= IEEE80211_FCTL_FROMDS; + /* DA BSSID SA */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); + hdrlen = 24; + } else if (sdata->type == IEEE80211_IF_TYPE_WDS) { + fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; + /* RA TA DA SA */ + memcpy(hdr.addr1, sdata->u.wds.remote_addr, 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); + hdrlen = 30; + } else if (sdata->type == IEEE80211_IF_TYPE_STA) { + fc |= IEEE80211_FCTL_TODS; + /* BSSID SA DA */ + memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + hdrlen = 24; + } else if (sdata->type == IEEE80211_IF_TYPE_IBSS) { + /* DA SA BSSID */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN); + hdrlen = 24; + } else { + ret = 0; + goto fail; + } + + /* receiver is QoS enabled, use a QoS type frame */ + sta = sta_info_get(local, hdr.addr1); + if (sta) { + if (sta->flags & WLAN_STA_WME) { + fc |= IEEE80211_STYPE_QOS_DATA; + hdrlen += 2; + } + sta_info_put(sta); + } + + hdr.frame_control = cpu_to_le16(fc); + hdr.duration_id = 0; + hdr.seq_ctrl = 0; + + skip_header_bytes = ETH_HLEN; + if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { + encaps_data = bridge_tunnel_header; + encaps_len = sizeof(bridge_tunnel_header); + skip_header_bytes -= 2; + } else if (ethertype >= 0x600) { + encaps_data = rfc1042_header; + encaps_len = sizeof(rfc1042_header); + skip_header_bytes -= 2; + } else { + encaps_data = NULL; + encaps_len = 0; + } + + skb_pull(skb, skip_header_bytes); + nh_pos -= skip_header_bytes; + h_pos -= skip_header_bytes; + + /* TODO: implement support for fragments so that there is no need to + * reallocate and copy payload; it might be enough to support one + * extra fragment that would be copied in the beginning of the frame + * data.. anyway, it would be nice to include this into skb structure + * somehow + * + * There are few options for this: + * use skb->cb as an extra space for 802.11 header + * allocate new buffer if not enough headroom + * make sure that there is enough headroom in every skb by increasing + * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and + * alloc_skb() (net/core/skbuff.c) + */ + head_need = hdrlen + encaps_len + local->tx_headroom; + head_need -= skb_headroom(skb); + + /* We are going to modify skb data, so make a copy of it if happens to + * be cloned. This could happen, e.g., with Linux bridge code passing + * us broadcast frames. */ + + if (head_need > 0 || skb_cloned(skb)) { +#if 0 + printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes " + "of headroom\n", dev->name, head_need); +#endif + + if (skb_cloned(skb)) + I802_DEBUG_INC(local->tx_expand_skb_head_cloned); + else + I802_DEBUG_INC(local->tx_expand_skb_head); + /* Since we have to reallocate the buffer, make sure that there + * is enough room for possible WEP IV/ICV and TKIP (8 bytes + * before payload and 12 after). */ + if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8), + 12, GFP_ATOMIC)) { + printk(KERN_DEBUG "%s: failed to reallocate TX buffer" + "\n", dev->name); + goto fail; + } + } + + if (encaps_data) { + memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); + nh_pos += encaps_len; + h_pos += encaps_len; + } + memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + nh_pos += hdrlen; + h_pos += hdrlen; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); + pkt_data->ifindex = dev->ifindex; + pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); + pkt_data->do_not_encrypt = no_encrypt; + + skb->dev = local->mdev; + sdata->stats.tx_packets++; + sdata->stats.tx_bytes += skb->len; + + /* Update skb pointers to various headers since this modified frame + * is going to go through Linux networking code that may potentially + * need things like pointer to IP header. */ + skb_set_mac_header(skb, 0); + skb_set_network_header(skb, nh_pos); + skb_set_transport_header(skb, h_pos); + + dev->trans_start = jiffies; + dev_queue_xmit(skb); + + return 0; + + fail: + if (!ret) + dev_kfree_skb(skb); + + return ret; +} + +/* + * This is the transmit routine for the 802.11 type interfaces + * called by upper layers of the linux networking + * stack when it has a frame to transmit + */ +int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_hdr *hdr; + u16 fc; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (skb->len < 10) { + dev_kfree_skb(skb); + return 0; + } + + if (skb_headroom(skb) < sdata->local->tx_headroom) { + if (pskb_expand_head(skb, sdata->local->tx_headroom, + 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return 0; + } + } + + hdr = (struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); + pkt_data->ifindex = sdata->dev->ifindex; + pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); + + skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ + skb->dev = sdata->local->mdev; + + /* + * We're using the protocol field of the the frame control header + * to request TX callback for hostapd. BIT(1) is checked. + */ + if ((fc & BIT(1)) == BIT(1)) { + pkt_data->req_tx_status = 1; + fc &= ~BIT(1); + hdr->frame_control = cpu_to_le16(fc); + } + + pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED); + + sdata->stats.tx_packets++; + sdata->stats.tx_bytes += skb->len; + + dev_queue_xmit(skb); + + return 0; +} + +/* helper functions for pending packets for when queues are stopped */ + +void ieee80211_clear_tx_pending(struct ieee80211_local *local) +{ + int i, j; + struct ieee80211_tx_stored_packet *store; + + for (i = 0; i < local->hw.queues; i++) { + if (!__ieee80211_queue_pending(local, i)) + continue; + store = &local->pending_packet[i]; + kfree_skb(store->skb); + for (j = 0; j < store->num_extra_frag; j++) + kfree_skb(store->extra_frag[j]); + kfree(store->extra_frag); + clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); + } +} + +void ieee80211_tx_pending(unsigned long data) +{ + struct ieee80211_local *local = (struct ieee80211_local *)data; + struct net_device *dev = local->mdev; + struct ieee80211_tx_stored_packet *store; + struct ieee80211_txrx_data tx; + int i, ret, reschedule = 0; + + netif_tx_lock_bh(dev); + for (i = 0; i < local->hw.queues; i++) { + if (__ieee80211_queue_stopped(local, i)) + continue; + if (!__ieee80211_queue_pending(local, i)) { + reschedule = 1; + continue; + } + store = &local->pending_packet[i]; + tx.u.tx.control = &store->control; + tx.u.tx.extra_frag = store->extra_frag; + tx.u.tx.num_extra_frag = store->num_extra_frag; + tx.u.tx.last_frag_hwrate = store->last_frag_hwrate; + tx.u.tx.last_frag_rate = store->last_frag_rate; + tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe; + ret = __ieee80211_tx(local, store->skb, &tx); + if (ret) { + if (ret == IEEE80211_TX_FRAG_AGAIN) + store->skb = NULL; + } else { + clear_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[i]); + reschedule = 1; + } + } + netif_tx_unlock_bh(dev); + if (reschedule) { + if (!ieee80211_qdisc_installed(dev)) { + if (!__ieee80211_queue_stopped(local, 0)) + netif_wake_queue(dev); + } else + netif_schedule(dev); + } +} + +/* functions for drivers to get certain frames */ + +static void ieee80211_beacon_add_tim(struct ieee80211_local *local, + struct ieee80211_if_ap *bss, + struct sk_buff *skb) +{ + u8 *pos, *tim; + int aid0 = 0; + int i, have_bits = 0, n1, n2; + + /* Generate bitmap for TIM only if there are any STAs in power save + * mode. */ + spin_lock_bh(&local->sta_lock); + if (atomic_read(&bss->num_sta_ps) > 0) + /* in the hope that this is faster than + * checking byte-for-byte */ + have_bits = !bitmap_empty((unsigned long*)bss->tim, + IEEE80211_MAX_AID+1); + + if (bss->dtim_count == 0) + bss->dtim_count = bss->dtim_period - 1; + else + bss->dtim_count--; + + tim = pos = (u8 *) skb_put(skb, 6); + *pos++ = WLAN_EID_TIM; + *pos++ = 4; + *pos++ = bss->dtim_count; + *pos++ = bss->dtim_period; + + if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) + aid0 = 1; + + if (have_bits) { + /* Find largest even number N1 so that bits numbered 1 through + * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits + * (N2 + 1) x 8 through 2007 are 0. */ + n1 = 0; + for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) { + if (bss->tim[i]) { + n1 = i & 0xfe; + break; + } + } + n2 = n1; + for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) { + if (bss->tim[i]) { + n2 = i; + break; + } + } + + /* Bitmap control */ + *pos++ = n1 | aid0; + /* Part Virt Bitmap */ + memcpy(pos, bss->tim + n1, n2 - n1 + 1); + + tim[1] = n2 - n1 + 4; + skb_put(skb, n2 - n1); + } else { + *pos++ = aid0; /* Bitmap control */ + *pos++ = 0; /* Part Virt Bitmap */ + } + spin_unlock_bh(&local->sta_lock); +} + +struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, + struct ieee80211_tx_control *control) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sk_buff *skb; + struct net_device *bdev; + struct ieee80211_sub_if_data *sdata = NULL; + struct ieee80211_if_ap *ap = NULL; + struct ieee80211_rate *rate; + struct rate_control_extra extra; + u8 *b_head, *b_tail; + int bh_len, bt_len; + + bdev = dev_get_by_index(if_id); + if (bdev) { + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + ap = &sdata->u.ap; + dev_put(bdev); + } + + if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || + !ap->beacon_head) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "no beacon data avail for idx=%d " + "(%s)\n", if_id, bdev ? bdev->name : "N/A"); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + return NULL; + } + + /* Assume we are generating the normal beacon locally */ + b_head = ap->beacon_head; + b_tail = ap->beacon_tail; + bh_len = ap->beacon_head_len; + bt_len = ap->beacon_tail_len; + + skb = dev_alloc_skb(local->tx_headroom + + bh_len + bt_len + 256 /* maximum TIM len */); + if (!skb) + return NULL; + + skb_reserve(skb, local->tx_headroom); + memcpy(skb_put(skb, bh_len), b_head, bh_len); + + ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); + + ieee80211_beacon_add_tim(local, ap, skb); + + if (b_tail) { + memcpy(skb_put(skb, bt_len), b_tail, bt_len); + } + + if (control) { + memset(&extra, 0, sizeof(extra)); + extra.mode = local->oper_hw_mode; + + rate = rate_control_get_rate(local, local->mdev, skb, &extra); + if (!rate) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate " + "found\n", local->mdev->name); + } + dev_kfree_skb(skb); + return NULL; + } + + control->tx_rate = (local->short_preamble && + (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? + rate->val2 : rate->val; + control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + control->power_level = local->hw.conf.power_level; + control->flags |= IEEE80211_TXCTL_NO_ACK; + control->retry_limit = 1; + control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; + } + + ap->num_beacons++; + return skb; +} +EXPORT_SYMBOL(ieee80211_beacon_get); + +void ieee80211_rts_get(struct ieee80211_hw *hw, + const void *frame, size_t frame_len, + const struct ieee80211_tx_control *frame_txctl, + struct ieee80211_rts *rts) +{ + const struct ieee80211_hdr *hdr = frame; + u16 fctl; + + fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; + rts->frame_control = cpu_to_le16(fctl); + rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl); + memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); + memcpy(rts->ta, hdr->addr2, sizeof(rts->ta)); +} +EXPORT_SYMBOL(ieee80211_rts_get); + +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, + const void *frame, size_t frame_len, + const struct ieee80211_tx_control *frame_txctl, + struct ieee80211_cts *cts) +{ + const struct ieee80211_hdr *hdr = frame; + u16 fctl; + + fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; + cts->frame_control = cpu_to_le16(fctl); + cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl); + memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); +} +EXPORT_SYMBOL(ieee80211_ctstoself_get); + +struct sk_buff * +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, + struct ieee80211_tx_control *control) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sk_buff *skb; + struct sta_info *sta; + ieee80211_tx_handler *handler; + struct ieee80211_txrx_data tx; + ieee80211_txrx_result res = TXRX_DROP; + struct net_device *bdev; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_ap *bss = NULL; + + bdev = dev_get_by_index(if_id); + if (bdev) { + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + bss = &sdata->u.ap; + dev_put(bdev); + } + if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head) + return NULL; + + if (bss->dtim_count != 0) + return NULL; /* send buffered bc/mc only after DTIM beacon */ + memset(control, 0, sizeof(*control)); + while (1) { + skb = skb_dequeue(&bss->ps_bc_buf); + if (!skb) + return NULL; + local->total_ps_buffered--; + + if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) { + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) skb->data; + /* more buffered multicast/broadcast frames ==> set + * MoreData flag in IEEE 802.11 header to inform PS + * STAs */ + hdr->frame_control |= + cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } + + if (ieee80211_tx_prepare(&tx, skb, local->mdev, control) == 0) + break; + dev_kfree_skb_any(skb); + } + sta = tx.sta; + tx.u.tx.ps_buffered = 1; + + for (handler = local->tx_handlers; *handler != NULL; handler++) { + res = (*handler)(&tx); + if (res == TXRX_DROP || res == TXRX_QUEUED) + break; + } + dev_put(tx.dev); + skb = tx.skb; /* handlers are allowed to change skb */ + + if (res == TXRX_DROP) { + I802_DEBUG_INC(local->tx_handlers_drop); + dev_kfree_skb(skb); + skb = NULL; + } else if (res == TXRX_QUEUED) { + I802_DEBUG_INC(local->tx_handlers_queued); + skb = NULL; + } + + if (sta) + sta_info_put(sta); + + return skb; +} +EXPORT_SYMBOL(ieee80211_get_buffered_bc); From 75c35aa4e2931b22e8e95fa2d6380eebac229f30 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:22 +0200 Subject: [PATCH 1016/2804] [MAC80211]: remove some unnecessary includes Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index a35e3a95a15a..02fb00ec2ed3 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include @@ -29,8 +27,6 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "wep.h" -#include "wpa.h" -#include "tkip.h" #include "wme.h" #include "aes_ccm.h" #include "ieee80211_led.h" From 1f5a7e47ae58cc23c623c09f1c9d97b7a8cf6344 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:23 +0200 Subject: [PATCH 1017/2804] [MAC80211]: split out some key functions from ieee80211.c into a new file key.c which doesn't have much code right now but it makes ieee80211.c easier to read. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/Makefile | 1 + net/mac80211/ieee80211.c | 56 ------------------------------- net/mac80211/ieee80211_i.h | 14 ++++---- net/mac80211/key.c | 69 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 62 deletions(-) create mode 100644 net/mac80211/key.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 848260296a0c..d95de3f8a4b1 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -20,4 +20,5 @@ mac80211-objs := \ ieee80211_cfg.o \ rx.o \ tx.o \ + key.o \ $(mac80211-objs-y) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 02fb00ec2ed3..f20e647552ec 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -33,7 +33,6 @@ #include "ieee80211_cfg.h" #include "debugfs.h" #include "debugfs_netdev.h" -#include "debugfs_key.h" /* privid for wiphys to determine whether they belong to us or not */ void *mac80211_wiphy_privid = &mac80211_wiphy_privid; @@ -63,61 +62,6 @@ struct ieee80211_tx_status_rtap_hdr { } __attribute__ ((packed)); -struct ieee80211_key_conf * -ieee80211_key_data2conf(struct ieee80211_local *local, - const struct ieee80211_key *data) -{ - struct ieee80211_key_conf *conf; - - conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC); - if (!conf) - return NULL; - - conf->hw_key_idx = data->hw_key_idx; - conf->alg = data->alg; - conf->keylen = data->keylen; - conf->flags = 0; - if (data->force_sw_encrypt) - conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - conf->keyidx = data->keyidx; - if (data->default_tx_key) - conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY; - if (local->default_wep_only) - conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY; - memcpy(conf->key, data->key, data->keylen); - - return conf; -} - -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - int idx, size_t key_len, gfp_t flags) -{ - struct ieee80211_key *key; - - key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags); - if (!key) - return NULL; - kref_init(&key->kref); - return key; -} - -static void ieee80211_key_release(struct kref *kref) -{ - struct ieee80211_key *key; - - key = container_of(kref, struct ieee80211_key, kref); - if (key->alg == ALG_CCMP) - ieee80211_aes_key_free(key->u.ccmp.tfm); - ieee80211_debugfs_key_remove(key); - kfree(key); -} - -void ieee80211_key_free(struct ieee80211_key *key) -{ - if (key) - kref_put(&key->kref, ieee80211_key_release); -} - static int rate_list_match(const int *rate_list, int rate) { int i; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9d3401d12917..af8b9848e021 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -719,12 +719,6 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); -struct ieee80211_key_conf * -ieee80211_key_data2conf(struct ieee80211_local *local, - const struct ieee80211_key *data); -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - int idx, size_t key_len, gfp_t flags); -void ieee80211_key_free(struct ieee80211_key *key); void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_rx_status *status, u32 msg_type); void ieee80211_prepare_rates(struct ieee80211_local *local, @@ -833,6 +827,14 @@ 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); int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); +/* key handling */ +struct ieee80211_key_conf * +ieee80211_key_data2conf(struct ieee80211_local *local, + const struct ieee80211_key *data); +struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, + int idx, size_t key_len, gfp_t flags); +void ieee80211_key_free(struct ieee80211_key *key); + /* for wiphy privid */ extern void *mac80211_wiphy_privid; diff --git a/net/mac80211/key.c b/net/mac80211/key.c new file mode 100644 index 000000000000..b67558c24639 --- /dev/null +++ b/net/mac80211/key.c @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * + * 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 "ieee80211_i.h" +#include "debugfs_key.h" +#include "aes_ccm.h" + +struct ieee80211_key_conf * +ieee80211_key_data2conf(struct ieee80211_local *local, + const struct ieee80211_key *data) +{ + struct ieee80211_key_conf *conf; + + conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC); + if (!conf) + return NULL; + + conf->hw_key_idx = data->hw_key_idx; + conf->alg = data->alg; + conf->keylen = data->keylen; + conf->flags = 0; + if (data->force_sw_encrypt) + conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; + conf->keyidx = data->keyidx; + if (data->default_tx_key) + conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY; + if (local->default_wep_only) + conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY; + memcpy(conf->key, data->key, data->keylen); + + return conf; +} + +struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, + int idx, size_t key_len, gfp_t flags) +{ + struct ieee80211_key *key; + + key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags); + if (!key) + return NULL; + kref_init(&key->kref); + return key; +} + +static void ieee80211_key_release(struct kref *kref) +{ + struct ieee80211_key *key; + + key = container_of(kref, struct ieee80211_key, kref); + if (key->alg == ALG_CCMP) + ieee80211_aes_key_free(key->u.ccmp.tfm); + ieee80211_debugfs_key_remove(key); + kfree(key); +} + +void ieee80211_key_free(struct ieee80211_key *key) +{ + if (key) + kref_put(&key->kref, ieee80211_key_release); +} From ff6880892990aece71a3271425dfde35344d51bb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:23 +0200 Subject: [PATCH 1018/2804] [MAC80211]: move some rate control functions out of ieee80211.c I think these can go with rate control just as well and it makes ieee80211.c more readable. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 41 ---------------------------------- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/ieee80211_rate.c | 42 +++++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_rate.h | 6 +++++ 4 files changed, 48 insertions(+), 43 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index f20e647552ec..2b15505a6e48 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1542,47 +1542,6 @@ void ieee80211_if_mgmt_setup(struct net_device *dev) dev->destructor = ieee80211_if_free; } -int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, - const char *name) -{ - struct rate_control_ref *ref, *old; - - ASSERT_RTNL(); - if (local->open_count || netif_running(local->mdev) || - (local->apdev && netif_running(local->apdev))) - return -EBUSY; - - ref = rate_control_alloc(name, local); - if (!ref) { - printk(KERN_WARNING "%s: Failed to select rate control " - "algorithm\n", local->mdev->name); - return -ENOENT; - } - - old = local->rate_ctrl; - local->rate_ctrl = ref; - if (old) { - rate_control_put(old); - sta_info_flush(local, NULL); - } - - printk(KERN_DEBUG "%s: Selected rate control " - "algorithm '%s'\n", local->mdev->name, - ref->ops->name); - - - return 0; -} - -static void rate_control_deinitialize(struct ieee80211_local *local) -{ - struct rate_control_ref *ref; - - ref = local->rate_ctrl; - local->rate_ctrl = NULL; - rate_control_put(ref); -} - struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index af8b9848e021..28414b3e0c34 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -727,8 +727,6 @@ void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); void ieee80211_if_mgmt_setup(struct net_device *dev); -int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, - const char *name); struct net_device_stats *ieee80211_dev_stats(struct net_device *dev); struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hwrate); diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index 2118de04fc35..a1ded7449784 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c @@ -9,6 +9,7 @@ */ #include +#include #include "ieee80211_rate.h" #include "ieee80211_i.h" @@ -137,3 +138,44 @@ void rate_control_put(struct rate_control_ref *ref) { kref_put(&ref->kref, rate_control_release); } + +int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, + const char *name) +{ + struct rate_control_ref *ref, *old; + + ASSERT_RTNL(); + if (local->open_count || netif_running(local->mdev) || + (local->apdev && netif_running(local->apdev))) + return -EBUSY; + + ref = rate_control_alloc(name, local); + if (!ref) { + printk(KERN_WARNING "%s: Failed to select rate control " + "algorithm\n", local->mdev->name); + return -ENOENT; + } + + old = local->rate_ctrl; + local->rate_ctrl = ref; + if (old) { + rate_control_put(old); + sta_info_flush(local, NULL); + } + + printk(KERN_DEBUG "%s: Selected rate control " + "algorithm '%s'\n", local->mdev->name, + ref->ops->name); + + + return 0; +} + +void rate_control_deinitialize(struct ieee80211_local *local) +{ + struct rate_control_ref *ref; + + ref = local->rate_ctrl; + local->rate_ctrl = NULL; + rate_control_put(ref); +} diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index f021a028d9d0..cac91a960ff4 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h @@ -141,4 +141,10 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) #endif } + +/* functions for rate control related to a device */ +int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, + const char *name); +void rate_control_deinitialize(struct ieee80211_local *local); + #endif /* IEEE80211_RATE_H */ From b2c258fb11b3fc77a73f8b0453ff1256de812bc6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:23 +0200 Subject: [PATCH 1019/2804] [MAC80211]: reorder interface related functions This patch groups a whole bunch of functions together to make ieee80211.c more maintainable. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 1813 +++++++++++++++++++------------------- 1 file changed, 903 insertions(+), 910 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 2b15505a6e48..f240f9706081 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -61,602 +61,7 @@ struct ieee80211_tx_status_rtap_hdr { u8 data_retries; } __attribute__ ((packed)); - -static int rate_list_match(const int *rate_list, int rate) -{ - int i; - - if (!rate_list) - return 0; - - for (i = 0; rate_list[i] >= 0; i++) - if (rate_list[i] == rate) - return 1; - - return 0; -} - - -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode) -{ - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - rate->flags &= ~(IEEE80211_RATE_SUPPORTED | - IEEE80211_RATE_BASIC); - - if (local->supp_rates[mode->mode]) { - if (!rate_list_match(local->supp_rates[mode->mode], - rate->rate)) - continue; - } - - rate->flags |= IEEE80211_RATE_SUPPORTED; - - /* Use configured basic rate set if it is available. If not, - * use defaults that are sane for most cases. */ - if (local->basic_rates[mode->mode]) { - if (rate_list_match(local->basic_rates[mode->mode], - rate->rate)) - rate->flags |= IEEE80211_RATE_BASIC; - } else switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211B: - if (rate->rate == 10 || rate->rate == 20) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_ATHEROS_TURBO: - if (rate->rate == 120 || rate->rate == 240 || - rate->rate == 480) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110) - rate->flags |= IEEE80211_RATE_BASIC; - break; - } - - /* Set ERP and MANDATORY flags based on phymode */ - switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211B: - if (rate->rate == 10) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_ATHEROS_TURBO: - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110 || - rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - } - if (ieee80211_is_erp_rate(mode->mode, rate->rate)) - rate->flags |= IEEE80211_RATE_ERP; - } -} - - -void ieee80211_key_threshold_notify(struct net_device *dev, - struct ieee80211_key *key, - struct sta_info *sta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - struct ieee80211_msg_key_notification *msg; - - /* if no one will get it anyway, don't even allocate it. - * unlikely because this is only relevant for APs - * where the device must be open... */ - if (unlikely(!local->apdev)) - return; - - skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + - sizeof(struct ieee80211_msg_key_notification)); - if (!skb) - return; - - skb_reserve(skb, sizeof(struct ieee80211_frame_info)); - msg = (struct ieee80211_msg_key_notification *) - skb_put(skb, sizeof(struct ieee80211_msg_key_notification)); - msg->tx_rx_count = key->tx_rx_count; - memcpy(msg->ifname, dev->name, IFNAMSIZ); - if (sta) - memcpy(msg->addr, sta->addr, ETH_ALEN); - else - memset(msg->addr, 0xff, ETH_ALEN); - - key->tx_rx_count = 0; - - ieee80211_rx_mgmt(local, skb, NULL, - ieee80211_msg_key_threshold_notification); -} - - -u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) -{ - u16 fc; - - if (len < 24) - return NULL; - - fc = le16_to_cpu(hdr->frame_control); - - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { - case IEEE80211_FCTL_TODS: - return hdr->addr1; - case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): - return NULL; - case IEEE80211_FCTL_FROMDS: - return hdr->addr2; - case 0: - return hdr->addr3; - } - break; - case IEEE80211_FTYPE_MGMT: - return hdr->addr3; - case IEEE80211_FTYPE_CTL: - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) - return hdr->addr1; - else - return NULL; - } - - return NULL; -} - -int ieee80211_get_hdrlen(u16 fc) -{ - int hdrlen = 24; - - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = 30; /* Addr4 */ - /* - * The QoS Control field is two bytes and its presence is - * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to - * hdrlen if that bit is set. - * This works by masking out the bit and shifting it to - * bit position 1 so the result has the value 0 or 2. - */ - hdrlen += (fc & IEEE80211_STYPE_QOS_DATA) - >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1); - break; - case IEEE80211_FTYPE_CTL: - /* - * ACK and CTS are 10 bytes, all others 16. To see how - * to get this condition consider - * subtype mask: 0b0000000011110000 (0x00F0) - * ACK subtype: 0b0000000011010000 (0x00D0) - * CTS subtype: 0b0000000011000000 (0x00C0) - * bits that matter: ^^^ (0x00E0) - * value of those: 0b0000000011000000 (0x00C0) - */ - if ((fc & 0xE0) == 0xC0) - hdrlen = 10; - else - hdrlen = 16; - break; - } - - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_get_hdrlen); - -int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data; - int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); - if (unlikely(hdrlen > skb->len)) - return 0; - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); - - -int ieee80211_is_eapol(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr; - u16 fc; - int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - - hdr = (const struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return 0; - - hdrlen = ieee80211_get_hdrlen(fc); - - if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) && - memcmp(skb->data + hdrlen, eapol_header, - sizeof(eapol_header)) == 0)) - return 1; - - return 0; -} - - -void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - if (tx->u.tx.extra_frag) { - struct ieee80211_hdr *fhdr; - int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - fhdr = (struct ieee80211_hdr *) - tx->u.tx.extra_frag[i]->data; - fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - } - } -} - - -static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, - int rate, int erp, int short_preamble) -{ - int dur; - - /* calculate duration (in microseconds, rounded up to next higher - * integer if it includes a fractional microsecond) to send frame of - * len bytes (does not include FCS) at the given rate. Duration will - * also include SIFS. - * - * rate is in 100 kbps, so divident is multiplied by 10 in the - * DIV_ROUND_UP() operations. - */ - - if (local->hw.conf.phymode == MODE_IEEE80211A || erp || - local->hw.conf.phymode == MODE_ATHEROS_TURBO) { - /* - * OFDM: - * - * N_DBPS = DATARATE x 4 - * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) - * (16 = SIGNAL time, 6 = tail bits) - * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext - * - * T_SYM = 4 usec - * 802.11a - 17.5.2: aSIFSTime = 16 usec - * 802.11g - 19.8.4: aSIFSTime = 10 usec + - * signal ext = 6 usec - */ - /* FIX: Atheros Turbo may have different (shorter) duration? */ - dur = 16; /* SIFS + signal ext */ - dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ - dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ - dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, - 4 * rate); /* T_SYM x N_SYM */ - } else { - /* - * 802.11b or 802.11g with 802.11b compatibility: - * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + - * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. - * - * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 - * aSIFSTime = 10 usec - * aPreambleLength = 144 usec or 72 usec with short preamble - * aPLCPHeaderLength = 48 usec or 24 usec with short preamble - */ - dur = 10; /* aSIFSTime = 10 usec */ - dur += short_preamble ? (72 + 24) : (144 + 48); - - dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); - } - - return dur; -} - - -/* Exported duration function for driver use */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, - size_t frame_len, int rate) -{ - struct ieee80211_local *local = hw_to_local(hw); - u16 dur; - int erp; - - erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); - dur = ieee80211_frame_duration(local, frame_len, rate, - erp, local->short_preamble); - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_generic_frame_duration); - - -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, - size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; - int erp; - u16 dur; - - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); - - /* CTS duration */ - dur = ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - /* Data frame duration */ - dur += ieee80211_frame_duration(local, frame_len, rate->rate, - erp, short_preamble); - /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_rts_duration); - - -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, - size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; - int erp; - u16 dur; - - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); - - /* Data frame duration */ - dur = ieee80211_frame_duration(local, frame_len, rate->rate, - erp, short_preamble); - if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { - /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - } - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_ctstoself_duration); - -static int __ieee80211_if_config(struct net_device *dev, - struct sk_buff *beacon, - struct ieee80211_tx_control *control) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_if_conf conf; - static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - if (!local->ops->config_interface || !netif_running(dev)) - return 0; - - memset(&conf, 0, sizeof(conf)); - conf.type = sdata->type; - if (sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) { - if (local->sta_scanning && - local->scan_dev == dev) - conf.bssid = scan_bssid; - else - conf.bssid = sdata->u.sta.bssid; - conf.ssid = sdata->u.sta.ssid; - conf.ssid_len = sdata->u.sta.ssid_len; - conf.generic_elem = sdata->u.sta.extra_ie; - conf.generic_elem_len = sdata->u.sta.extra_ie_len; - } else if (sdata->type == IEEE80211_IF_TYPE_AP) { - conf.ssid = sdata->u.ap.ssid; - conf.ssid_len = sdata->u.ap.ssid_len; - conf.generic_elem = sdata->u.ap.generic_elem; - conf.generic_elem_len = sdata->u.ap.generic_elem_len; - conf.beacon = beacon; - conf.beacon_control = control; - } - return local->ops->config_interface(local_to_hw(local), - dev->ifindex, &conf); -} - -int ieee80211_if_config(struct net_device *dev) -{ - return __ieee80211_if_config(dev, NULL, NULL); -} - -int ieee80211_if_config_beacon(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_control control; - struct sk_buff *skb; - - if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) - return 0; - skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control); - if (!skb) - return -ENOMEM; - return __ieee80211_if_config(dev, skb, &control); -} - -int ieee80211_hw_config(struct ieee80211_local *local) -{ - struct ieee80211_hw_mode *mode; - struct ieee80211_channel *chan; - int ret = 0; - - if (local->sta_scanning) { - chan = local->scan_channel; - mode = local->scan_hw_mode; - } else { - chan = local->oper_channel; - mode = local->oper_hw_mode; - } - - local->hw.conf.channel = chan->chan; - local->hw.conf.channel_val = chan->val; - local->hw.conf.power_level = chan->power_level; - local->hw.conf.freq = chan->freq; - local->hw.conf.phymode = mode->mode; - local->hw.conf.antenna_max = chan->antenna_max; - local->hw.conf.chan = chan; - local->hw.conf.mode = mode; - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d " - "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq, - local->hw.conf.phymode); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - - if (local->ops->config) - ret = local->ops->config(local_to_hw(local), &local->hw.conf); - - return ret; -} - - -static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) -{ - /* FIX: what would be proper limits for MTU? - * This interface uses 802.3 frames. */ - if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) { - printk(KERN_WARNING "%s: invalid MTU %d\n", - dev->name, new_mtu); - return -EINVAL; - } - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - dev->mtu = new_mtu; - return 0; -} - - -static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu) -{ - /* FIX: what would be proper limits for MTU? - * This interface uses 802.11 frames. */ - if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) { - printk(KERN_WARNING "%s: invalid MTU %d\n", - dev->name, new_mtu); - return -EINVAL; - } - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - dev->mtu = new_mtu; - return 0; -} - -enum netif_tx_lock_class { - TX_LOCK_NORMAL, - TX_LOCK_MASTER, -}; - -static inline void netif_tx_lock_nested(struct net_device *dev, int subclass) -{ - spin_lock_nested(&dev->_xmit_lock, subclass); - dev->xmit_lock_owner = smp_processor_id(); -} - -static void ieee80211_set_multicast_list(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - unsigned short flags; - - netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); - if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) { - if (sdata->allmulti) { - sdata->allmulti = 0; - local->iff_allmultis--; - } else { - sdata->allmulti = 1; - local->iff_allmultis++; - } - } - if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) { - if (sdata->promisc) { - sdata->promisc = 0; - local->iff_promiscs--; - } else { - sdata->promisc = 1; - local->iff_promiscs++; - } - } - if (dev->mc_count != sdata->mc_count) { - local->mc_count = local->mc_count - sdata->mc_count + - dev->mc_count; - sdata->mc_count = dev->mc_count; - } - if (local->ops->set_multicast_list) { - flags = local->mdev->flags; - if (local->iff_allmultis) - flags |= IFF_ALLMULTI; - if (local->iff_promiscs) - flags |= IFF_PROMISC; - read_lock(&local->sub_if_lock); - local->ops->set_multicast_list(local_to_hw(local), flags, - local->mc_count); - read_unlock(&local->sub_if_lock); - } - netif_tx_unlock(local->mdev); -} - -struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, - struct dev_mc_list *prev, - void **ptr) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata = *ptr; - struct dev_mc_list *mc; - - if (!prev) { - WARN_ON(sdata); - sdata = NULL; - } - if (!prev || !prev->next) { - if (sdata) - sdata = list_entry(sdata->list.next, - struct ieee80211_sub_if_data, list); - else - sdata = list_entry(local->sub_if_list.next, - struct ieee80211_sub_if_data, list); - if (&sdata->list != &local->sub_if_list) - mc = sdata->dev->mc_list; - else - mc = NULL; - } else - mc = prev->next; - - *ptr = sdata; - return mc; -} -EXPORT_SYMBOL(ieee80211_get_mc_list_item); +/* common interface routines */ static struct net_device_stats *ieee80211_get_stats(struct net_device *dev) { @@ -665,43 +70,13 @@ static struct net_device_stats *ieee80211_get_stats(struct net_device *dev) return &(sdata->stats); } -static void ieee80211_if_shutdown(struct net_device *dev) +static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - ASSERT_RTNL(); - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - sdata->u.sta.state = IEEE80211_DISABLED; - del_timer_sync(&sdata->u.sta.timer); - skb_queue_purge(&sdata->u.sta.skb_queue); - if (!local->ops->hw_scan && - local->scan_dev == sdata->dev) { - local->sta_scanning = 0; - cancel_delayed_work(&local->scan_work); - } - flush_workqueue(local->hw.workqueue); - break; - } + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ + return ETH_ALEN; } -static inline int identical_mac_addr_allowed(int type1, int type2) -{ - return (type1 == IEEE80211_IF_TYPE_MNTR || - type2 == IEEE80211_IF_TYPE_MNTR || - (type1 == IEEE80211_IF_TYPE_AP && - type2 == IEEE80211_IF_TYPE_WDS) || - (type1 == IEEE80211_IF_TYPE_WDS && - (type2 == IEEE80211_IF_TYPE_WDS || - type2 == IEEE80211_IF_TYPE_AP)) || - (type1 == IEEE80211_IF_TYPE_AP && - type2 == IEEE80211_IF_TYPE_VLAN) || - (type1 == IEEE80211_IF_TYPE_VLAN && - (type2 == IEEE80211_IF_TYPE_AP || - type2 == IEEE80211_IF_TYPE_VLAN))); -} +/* master interface */ static int ieee80211_master_open(struct net_device *dev) { @@ -734,220 +109,7 @@ static int ieee80211_master_stop(struct net_device *dev) return 0; } -static int ieee80211_mgmt_open(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (!netif_running(local->mdev)) - return -EOPNOTSUPP; - return 0; -} - -static int ieee80211_mgmt_stop(struct net_device *dev) -{ - return 0; -} - -/* Check if running monitor interfaces should go to a "soft monitor" mode - * and switch them if necessary. */ -static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && - local->ops->remove_interface) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->remove_interface(local_to_hw(local), &conf); - } -} - -/* Check if running monitor interfaces should go to a "hard monitor" mode - * and switch them if necessary. */ -static void ieee80211_start_hard_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->add_interface(local_to_hw(local), &conf); - } -} - -static int ieee80211_open(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata, *nsdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_if_init_conf conf; - int res; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - read_lock(&local->sub_if_lock); - list_for_each_entry(nsdata, &local->sub_if_list, list) { - struct net_device *ndev = nsdata->dev; - - if (ndev != dev && ndev != local->mdev && netif_running(ndev) && - compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 && - !identical_mac_addr_allowed(sdata->type, nsdata->type)) { - read_unlock(&local->sub_if_lock); - return -ENOTUNIQ; - } - } - read_unlock(&local->sub_if_lock); - - if (sdata->type == IEEE80211_IF_TYPE_WDS && - is_zero_ether_addr(sdata->u.wds.remote_addr)) - return -ENOLINK; - - if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* run the interface in a "soft monitor" mode */ - local->monitors++; - local->open_count++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - return 0; - } - ieee80211_start_soft_monitor(local); - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - conf.mac_addr = dev->dev_addr; - res = local->ops->add_interface(local_to_hw(local), &conf); - if (res) { - if (sdata->type == IEEE80211_IF_TYPE_MNTR) - ieee80211_start_hard_monitor(local); - return res; - } - - if (local->open_count == 0) { - res = 0; - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - if (local->ops->open) - res = local->ops->open(local_to_hw(local)); - if (res == 0) { - res = dev_open(local->mdev); - if (res) { - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - } else { - res = ieee80211_hw_config(local); - if (res && local->ops->stop) - local->ops->stop(local_to_hw(local)); - else if (!res && local->apdev) - dev_open(local->apdev); - } - } - if (res) { - if (local->ops->remove_interface) - local->ops->remove_interface(local_to_hw(local), - &conf); - return res; - } - } - local->open_count++; - - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { - local->monitors++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - } else - ieee80211_if_config(dev); - - if (sdata->type == IEEE80211_IF_TYPE_STA && - !local->user_space_mlme) - netif_carrier_off(dev); - else - netif_carrier_on(dev); - - netif_start_queue(dev); - return 0; -} - - -static int ieee80211_stop(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR && - local->open_count > 1 && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* remove "soft monitor" interface */ - local->open_count--; - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - return 0; - } - - netif_stop_queue(dev); - ieee80211_if_shutdown(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - } - - local->open_count--; - if (local->open_count == 0) { - if (netif_running(local->mdev)) - dev_close(local->mdev); - if (local->apdev) - dev_close(local->apdev); - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - tasklet_disable(&local->tx_pending_tasklet); - tasklet_disable(&local->tasklet); - } - if (local->ops->remove_interface) { - struct ieee80211_if_init_conf conf; - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - conf.mac_addr = dev->dev_addr; - local->ops->remove_interface(local_to_hw(local), &conf); - } - - ieee80211_start_hard_monitor(local); - - return 0; -} - - -static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - -struct ieee80211_rate * -ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) -{ - struct ieee80211_hw_mode *mode; - int r; - - list_for_each_entry(mode, &local->modes_list, list) { - if (mode->mode != phymode) - continue; - for (r = 0; r < mode->num_rates; r++) { - struct ieee80211_rate *rate = &mode->rates[r]; - if (rate->val == hw_rate || - (rate->flags & IEEE80211_RATE_PREAMBLE2 && - rate->val2 == hw_rate)) - return rate; - } - } - - return NULL; -} +/* management interface */ static void ieee80211_fill_frame_info(struct ieee80211_local *local, @@ -1084,6 +246,903 @@ int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, } EXPORT_SYMBOL(ieee80211_radar_status); +void ieee80211_key_threshold_notify(struct net_device *dev, + struct ieee80211_key *key, + struct sta_info *sta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_msg_key_notification *msg; + + /* if no one will get it anyway, don't even allocate it. + * unlikely because this is only relevant for APs + * where the device must be open... */ + if (unlikely(!local->apdev)) + return; + + skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + + sizeof(struct ieee80211_msg_key_notification)); + if (!skb) + return; + + skb_reserve(skb, sizeof(struct ieee80211_frame_info)); + msg = (struct ieee80211_msg_key_notification *) + skb_put(skb, sizeof(struct ieee80211_msg_key_notification)); + msg->tx_rx_count = key->tx_rx_count; + memcpy(msg->ifname, dev->name, IFNAMSIZ); + if (sta) + memcpy(msg->addr, sta->addr, ETH_ALEN); + else + memset(msg->addr, 0xff, ETH_ALEN); + + key->tx_rx_count = 0; + + ieee80211_rx_mgmt(local, skb, NULL, + ieee80211_msg_key_threshold_notification); +} + +static int ieee80211_mgmt_open(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + if (!netif_running(local->mdev)) + return -EOPNOTSUPP; + return 0; +} + +static int ieee80211_mgmt_stop(struct net_device *dev) +{ + return 0; +} + +static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu) +{ + /* FIX: what would be proper limits for MTU? + * This interface uses 802.11 frames. */ + if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) { + printk(KERN_WARNING "%s: invalid MTU %d\n", + dev->name, new_mtu); + return -EINVAL; + } + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + dev->mtu = new_mtu; + return 0; +} + +void ieee80211_if_mgmt_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->hard_start_xmit = ieee80211_mgmt_start_xmit; + dev->change_mtu = ieee80211_change_mtu_apdev; + dev->get_stats = ieee80211_get_stats; + dev->open = ieee80211_mgmt_open; + dev->stop = ieee80211_mgmt_stop; + dev->type = ARPHRD_IEEE80211_PRISM; + dev->hard_header_parse = header_parse_80211; + dev->uninit = ieee80211_if_reinit; + dev->destructor = ieee80211_if_free; +} + +/* regular interfaces */ + +static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) +{ + /* FIX: what would be proper limits for MTU? + * This interface uses 802.3 frames. */ + if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) { + printk(KERN_WARNING "%s: invalid MTU %d\n", + dev->name, new_mtu); + return -EINVAL; + } + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + dev->mtu = new_mtu; + return 0; +} + +static inline int identical_mac_addr_allowed(int type1, int type2) +{ + return (type1 == IEEE80211_IF_TYPE_MNTR || + type2 == IEEE80211_IF_TYPE_MNTR || + (type1 == IEEE80211_IF_TYPE_AP && + type2 == IEEE80211_IF_TYPE_WDS) || + (type1 == IEEE80211_IF_TYPE_WDS && + (type2 == IEEE80211_IF_TYPE_WDS || + type2 == IEEE80211_IF_TYPE_AP)) || + (type1 == IEEE80211_IF_TYPE_AP && + type2 == IEEE80211_IF_TYPE_VLAN) || + (type1 == IEEE80211_IF_TYPE_VLAN && + (type2 == IEEE80211_IF_TYPE_AP || + type2 == IEEE80211_IF_TYPE_VLAN))); +} + +/* Check if running monitor interfaces should go to a "soft monitor" mode + * and switch them if necessary. */ +static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) +{ + struct ieee80211_if_init_conf conf; + + if (local->open_count && local->open_count == local->monitors && + !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && + local->ops->remove_interface) { + conf.if_id = -1; + conf.type = IEEE80211_IF_TYPE_MNTR; + conf.mac_addr = NULL; + local->ops->remove_interface(local_to_hw(local), &conf); + } +} + +/* Check if running monitor interfaces should go to a "hard monitor" mode + * and switch them if necessary. */ +static void ieee80211_start_hard_monitor(struct ieee80211_local *local) +{ + struct ieee80211_if_init_conf conf; + + if (local->open_count && local->open_count == local->monitors && + !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { + conf.if_id = -1; + conf.type = IEEE80211_IF_TYPE_MNTR; + conf.mac_addr = NULL; + local->ops->add_interface(local_to_hw(local), &conf); + } +} + +static int ieee80211_open(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata, *nsdata; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_if_init_conf conf; + int res; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + read_lock(&local->sub_if_lock); + list_for_each_entry(nsdata, &local->sub_if_list, list) { + struct net_device *ndev = nsdata->dev; + + if (ndev != dev && ndev != local->mdev && netif_running(ndev) && + compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 && + !identical_mac_addr_allowed(sdata->type, nsdata->type)) { + read_unlock(&local->sub_if_lock); + return -ENOTUNIQ; + } + } + read_unlock(&local->sub_if_lock); + + if (sdata->type == IEEE80211_IF_TYPE_WDS && + is_zero_ether_addr(sdata->u.wds.remote_addr)) + return -ENOLINK; + + if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count && + !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { + /* run the interface in a "soft monitor" mode */ + local->monitors++; + local->open_count++; + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + return 0; + } + ieee80211_start_soft_monitor(local); + + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; + res = local->ops->add_interface(local_to_hw(local), &conf); + if (res) { + if (sdata->type == IEEE80211_IF_TYPE_MNTR) + ieee80211_start_hard_monitor(local); + return res; + } + + if (local->open_count == 0) { + res = 0; + tasklet_enable(&local->tx_pending_tasklet); + tasklet_enable(&local->tasklet); + if (local->ops->open) + res = local->ops->open(local_to_hw(local)); + if (res == 0) { + res = dev_open(local->mdev); + if (res) { + if (local->ops->stop) + local->ops->stop(local_to_hw(local)); + } else { + res = ieee80211_hw_config(local); + if (res && local->ops->stop) + local->ops->stop(local_to_hw(local)); + else if (!res && local->apdev) + dev_open(local->apdev); + } + } + if (res) { + if (local->ops->remove_interface) + local->ops->remove_interface(local_to_hw(local), + &conf); + return res; + } + } + local->open_count++; + + if (sdata->type == IEEE80211_IF_TYPE_MNTR) { + local->monitors++; + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + } else + ieee80211_if_config(dev); + + if (sdata->type == IEEE80211_IF_TYPE_STA && + !local->user_space_mlme) + netif_carrier_off(dev); + else + netif_carrier_on(dev); + + netif_start_queue(dev); + return 0; +} + +static void ieee80211_if_shutdown(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + ASSERT_RTNL(); + switch (sdata->type) { + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.state = IEEE80211_DISABLED; + del_timer_sync(&sdata->u.sta.timer); + skb_queue_purge(&sdata->u.sta.skb_queue); + if (!local->ops->hw_scan && + local->scan_dev == sdata->dev) { + local->sta_scanning = 0; + cancel_delayed_work(&local->scan_work); + } + flush_workqueue(local->hw.workqueue); + break; + } +} + +static int ieee80211_stop(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->type == IEEE80211_IF_TYPE_MNTR && + local->open_count > 1 && + !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { + /* remove "soft monitor" interface */ + local->open_count--; + local->monitors--; + if (!local->monitors) + local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; + return 0; + } + + netif_stop_queue(dev); + ieee80211_if_shutdown(dev); + + if (sdata->type == IEEE80211_IF_TYPE_MNTR) { + local->monitors--; + if (!local->monitors) + local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; + } + + local->open_count--; + if (local->open_count == 0) { + if (netif_running(local->mdev)) + dev_close(local->mdev); + if (local->apdev) + dev_close(local->apdev); + if (local->ops->stop) + local->ops->stop(local_to_hw(local)); + tasklet_disable(&local->tx_pending_tasklet); + tasklet_disable(&local->tasklet); + } + if (local->ops->remove_interface) { + struct ieee80211_if_init_conf conf; + + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; + local->ops->remove_interface(local_to_hw(local), &conf); + } + + ieee80211_start_hard_monitor(local); + + return 0; +} + +enum netif_tx_lock_class { + TX_LOCK_NORMAL, + TX_LOCK_MASTER, +}; + +static inline void netif_tx_lock_nested(struct net_device *dev, int subclass) +{ + spin_lock_nested(&dev->_xmit_lock, subclass); + dev->xmit_lock_owner = smp_processor_id(); +} + +static void ieee80211_set_multicast_list(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + unsigned short flags; + + netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); + if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) { + if (sdata->allmulti) { + sdata->allmulti = 0; + local->iff_allmultis--; + } else { + sdata->allmulti = 1; + local->iff_allmultis++; + } + } + if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) { + if (sdata->promisc) { + sdata->promisc = 0; + local->iff_promiscs--; + } else { + sdata->promisc = 1; + local->iff_promiscs++; + } + } + if (dev->mc_count != sdata->mc_count) { + local->mc_count = local->mc_count - sdata->mc_count + + dev->mc_count; + sdata->mc_count = dev->mc_count; + } + if (local->ops->set_multicast_list) { + flags = local->mdev->flags; + if (local->iff_allmultis) + flags |= IFF_ALLMULTI; + if (local->iff_promiscs) + flags |= IFF_PROMISC; + read_lock(&local->sub_if_lock); + local->ops->set_multicast_list(local_to_hw(local), flags, + local->mc_count); + read_unlock(&local->sub_if_lock); + } + netif_tx_unlock(local->mdev); +} + +/* Must not be called for mdev and apdev */ +void ieee80211_if_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->hard_start_xmit = ieee80211_subif_start_xmit; + dev->wireless_handlers = &ieee80211_iw_handler_def; + dev->set_multicast_list = ieee80211_set_multicast_list; + dev->change_mtu = ieee80211_change_mtu; + dev->get_stats = ieee80211_get_stats; + dev->open = ieee80211_open; + dev->stop = ieee80211_stop; + dev->uninit = ieee80211_if_reinit; + dev->destructor = ieee80211_if_free; +} + +/* WDS specialties */ + +int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sta_info *sta; + + if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) + return 0; + + /* Create STA entry for the new peer */ + sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); + if (!sta) + return -ENOMEM; + sta_info_put(sta); + + /* Remove STA entry for the old peer */ + sta = sta_info_get(local, sdata->u.wds.remote_addr); + if (sta) { + sta_info_put(sta); + sta_info_free(sta, 0); + } else { + printk(KERN_DEBUG "%s: could not find STA entry for WDS link " + "peer " MAC_FMT "\n", + dev->name, MAC_ARG(sdata->u.wds.remote_addr)); + } + + /* Update WDS link data */ + memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); + + return 0; +} + +/* everything else */ + +static int rate_list_match(const int *rate_list, int rate) +{ + int i; + + if (!rate_list) + return 0; + + for (i = 0; rate_list[i] >= 0; i++) + if (rate_list[i] == rate) + return 1; + + return 0; +} + +void ieee80211_prepare_rates(struct ieee80211_local *local, + struct ieee80211_hw_mode *mode) +{ + int i; + + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *rate = &mode->rates[i]; + + rate->flags &= ~(IEEE80211_RATE_SUPPORTED | + IEEE80211_RATE_BASIC); + + if (local->supp_rates[mode->mode]) { + if (!rate_list_match(local->supp_rates[mode->mode], + rate->rate)) + continue; + } + + rate->flags |= IEEE80211_RATE_SUPPORTED; + + /* Use configured basic rate set if it is available. If not, + * use defaults that are sane for most cases. */ + if (local->basic_rates[mode->mode]) { + if (rate_list_match(local->basic_rates[mode->mode], + rate->rate)) + rate->flags |= IEEE80211_RATE_BASIC; + } else switch (mode->mode) { + case MODE_IEEE80211A: + if (rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case MODE_IEEE80211B: + if (rate->rate == 10 || rate->rate == 20) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case MODE_ATHEROS_TURBO: + if (rate->rate == 120 || rate->rate == 240 || + rate->rate == 480) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case MODE_IEEE80211G: + if (rate->rate == 10 || rate->rate == 20 || + rate->rate == 55 || rate->rate == 110) + rate->flags |= IEEE80211_RATE_BASIC; + break; + } + + /* Set ERP and MANDATORY flags based on phymode */ + switch (mode->mode) { + case MODE_IEEE80211A: + if (rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + case MODE_IEEE80211B: + if (rate->rate == 10) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + case MODE_ATHEROS_TURBO: + break; + case MODE_IEEE80211G: + if (rate->rate == 10 || rate->rate == 20 || + rate->rate == 55 || rate->rate == 110 || + rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + } + if (ieee80211_is_erp_rate(mode->mode, rate->rate)) + rate->flags |= IEEE80211_RATE_ERP; + } +} + +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) +{ + u16 fc; + + if (len < 24) + return NULL; + + fc = le16_to_cpu(hdr->frame_control); + + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_DATA: + switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { + case IEEE80211_FCTL_TODS: + return hdr->addr1; + case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + return NULL; + case IEEE80211_FCTL_FROMDS: + return hdr->addr2; + case 0: + return hdr->addr3; + } + break; + case IEEE80211_FTYPE_MGMT: + return hdr->addr3; + case IEEE80211_FTYPE_CTL: + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) + return hdr->addr1; + else + return NULL; + } + + return NULL; +} + +int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = 30; /* Addr4 */ + /* + * The QoS Control field is two bytes and its presence is + * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to + * hdrlen if that bit is set. + * This works by masking out the bit and shifting it to + * bit position 1 so the result has the value 0 or 2. + */ + hdrlen += (fc & IEEE80211_STYPE_QOS_DATA) + >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1); + break; + case IEEE80211_FTYPE_CTL: + /* + * ACK and CTS are 10 bytes, all others 16. To see how + * to get this condition consider + * subtype mask: 0b0000000011110000 (0x00F0) + * ACK subtype: 0b0000000011010000 (0x00D0) + * CTS subtype: 0b0000000011000000 (0x00C0) + * bits that matter: ^^^ (0x00E0) + * value of those: 0b0000000011000000 (0x00C0) + */ + if ((fc & 0xE0) == 0xC0) + hdrlen = 10; + else + hdrlen = 16; + break; + } + + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen); + +int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data; + int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + if (unlikely(hdrlen > skb->len)) + return 0; + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); + + +int ieee80211_is_eapol(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr; + u16 fc; + int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + + hdr = (const struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return 0; + + hdrlen = ieee80211_get_hdrlen(fc); + + if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) && + memcmp(skb->data + hdrlen, eapol_header, + sizeof(eapol_header)) == 0)) + return 1; + + return 0; +} + +void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + if (tx->u.tx.extra_frag) { + struct ieee80211_hdr *fhdr; + int i; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + fhdr = (struct ieee80211_hdr *) + tx->u.tx.extra_frag[i]->data; + fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + } + } +} + +static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, + int rate, int erp, int short_preamble) +{ + int dur; + + /* calculate duration (in microseconds, rounded up to next higher + * integer if it includes a fractional microsecond) to send frame of + * len bytes (does not include FCS) at the given rate. Duration will + * also include SIFS. + * + * rate is in 100 kbps, so divident is multiplied by 10 in the + * DIV_ROUND_UP() operations. + */ + + if (local->hw.conf.phymode == MODE_IEEE80211A || erp || + local->hw.conf.phymode == MODE_ATHEROS_TURBO) { + /* + * OFDM: + * + * N_DBPS = DATARATE x 4 + * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) + * (16 = SIGNAL time, 6 = tail bits) + * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext + * + * T_SYM = 4 usec + * 802.11a - 17.5.2: aSIFSTime = 16 usec + * 802.11g - 19.8.4: aSIFSTime = 10 usec + + * signal ext = 6 usec + */ + /* FIX: Atheros Turbo may have different (shorter) duration? */ + dur = 16; /* SIFS + signal ext */ + dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ + dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ + dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, + 4 * rate); /* T_SYM x N_SYM */ + } else { + /* + * 802.11b or 802.11g with 802.11b compatibility: + * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + + * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. + * + * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 + * aSIFSTime = 10 usec + * aPreambleLength = 144 usec or 72 usec with short preamble + * aPLCPHeaderLength = 48 usec or 24 usec with short preamble + */ + dur = 10; /* aSIFSTime = 10 usec */ + dur += short_preamble ? (72 + 24) : (144 + 48); + + dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); + } + + return dur; +} + +/* Exported duration function for driver use */ +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, + size_t frame_len, int rate) +{ + struct ieee80211_local *local = hw_to_local(hw); + u16 dur; + int erp; + + erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); + dur = ieee80211_frame_duration(local, frame_len, rate, + erp, local->short_preamble); + + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_generic_frame_duration); + +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, + size_t frame_len, + const struct ieee80211_tx_control *frame_txctl) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rate *rate; + int short_preamble = local->short_preamble; + int erp; + u16 dur; + + rate = frame_txctl->rts_rate; + erp = !!(rate->flags & IEEE80211_RATE_ERP); + + /* CTS duration */ + dur = ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + /* Data frame duration */ + dur += ieee80211_frame_duration(local, frame_len, rate->rate, + erp, short_preamble); + /* ACK duration */ + dur += ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_rts_duration); + +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, + size_t frame_len, + const struct ieee80211_tx_control *frame_txctl) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rate *rate; + int short_preamble = local->short_preamble; + int erp; + u16 dur; + + rate = frame_txctl->rts_rate; + erp = !!(rate->flags & IEEE80211_RATE_ERP); + + /* Data frame duration */ + dur = ieee80211_frame_duration(local, frame_len, rate->rate, + erp, short_preamble); + if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { + /* ACK duration */ + dur += ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + } + + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_ctstoself_duration); + +static int __ieee80211_if_config(struct net_device *dev, + struct sk_buff *beacon, + struct ieee80211_tx_control *control) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_if_conf conf; + static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + if (!local->ops->config_interface || !netif_running(dev)) + return 0; + + memset(&conf, 0, sizeof(conf)); + conf.type = sdata->type; + if (sdata->type == IEEE80211_IF_TYPE_STA || + sdata->type == IEEE80211_IF_TYPE_IBSS) { + if (local->sta_scanning && + local->scan_dev == dev) + conf.bssid = scan_bssid; + else + conf.bssid = sdata->u.sta.bssid; + conf.ssid = sdata->u.sta.ssid; + conf.ssid_len = sdata->u.sta.ssid_len; + conf.generic_elem = sdata->u.sta.extra_ie; + conf.generic_elem_len = sdata->u.sta.extra_ie_len; + } else if (sdata->type == IEEE80211_IF_TYPE_AP) { + conf.ssid = sdata->u.ap.ssid; + conf.ssid_len = sdata->u.ap.ssid_len; + conf.generic_elem = sdata->u.ap.generic_elem; + conf.generic_elem_len = sdata->u.ap.generic_elem_len; + conf.beacon = beacon; + conf.beacon_control = control; + } + return local->ops->config_interface(local_to_hw(local), + dev->ifindex, &conf); +} + +int ieee80211_if_config(struct net_device *dev) +{ + return __ieee80211_if_config(dev, NULL, NULL); +} + +int ieee80211_if_config_beacon(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_control control; + struct sk_buff *skb; + + if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) + return 0; + skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control); + if (!skb) + return -ENOMEM; + return __ieee80211_if_config(dev, skb, &control); +} + +int ieee80211_hw_config(struct ieee80211_local *local) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_channel *chan; + int ret = 0; + + if (local->sta_scanning) { + chan = local->scan_channel; + mode = local->scan_hw_mode; + } else { + chan = local->oper_channel; + mode = local->oper_hw_mode; + } + + local->hw.conf.channel = chan->chan; + local->hw.conf.channel_val = chan->val; + local->hw.conf.power_level = chan->power_level; + local->hw.conf.freq = chan->freq; + local->hw.conf.phymode = mode->mode; + local->hw.conf.antenna_max = chan->antenna_max; + local->hw.conf.chan = chan; + local->hw.conf.mode = mode; + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d " + "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq, + local->hw.conf.phymode); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + + if (local->ops->config) + ret = local->ops->config(local_to_hw(local), &local->hw.conf); + + return ret; +} + +struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, + struct dev_mc_list *prev, + void **ptr) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = *ptr; + struct dev_mc_list *mc; + + if (!prev) { + WARN_ON(sdata); + sdata = NULL; + } + if (!prev || !prev->next) { + if (sdata) + sdata = list_entry(sdata->list.next, + struct ieee80211_sub_if_data, list); + else + sdata = list_entry(local->sub_if_list.next, + struct ieee80211_sub_if_data, list); + if (&sdata->list != &local->sub_if_list) + mc = sdata->dev->mc_list; + else + mc = NULL; + } else + mc = prev->next; + + *ptr = sdata; + return mc; +} +EXPORT_SYMBOL(ieee80211_get_mc_list_item); + +struct ieee80211_rate * +ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) +{ + struct ieee80211_hw_mode *mode; + int r; + + list_for_each_entry(mode, &local->modes_list, list) { + if (mode->mode != phymode) + continue; + for (r = 0; r < mode->num_rates; r++) { + struct ieee80211_rate *rate = &mode->rates[r]; + if (rate->val == hw_rate || + (rate->flags & IEEE80211_RATE_PREAMBLE2 && + rate->val2 == hw_rate)) + return rate; + } + } + + return NULL; +} static void ieee80211_stat_refresh(unsigned long data) { @@ -1121,7 +1180,6 @@ static void ieee80211_stat_refresh(unsigned long data) add_timer(&local->stat_timer); } - void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) @@ -1198,7 +1256,6 @@ static void ieee80211_tasklet_handler(unsigned long data) } } - /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to * make a prepared TX frame (one that has been given to hw) to look like brand * new IEEE 802.11 frame that is ready to go through TX processing again. @@ -1261,7 +1318,6 @@ no_key: } } - void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) { @@ -1480,68 +1536,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, } EXPORT_SYMBOL(ieee80211_tx_status); - -int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sta_info *sta; - - if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) - return 0; - - /* Create STA entry for the new peer */ - sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); - if (!sta) - return -ENOMEM; - sta_info_put(sta); - - /* Remove STA entry for the old peer */ - sta = sta_info_get(local, sdata->u.wds.remote_addr); - if (sta) { - sta_info_put(sta); - sta_info_free(sta, 0); - } else { - printk(KERN_DEBUG "%s: could not find STA entry for WDS link " - "peer " MAC_FMT "\n", - dev->name, MAC_ARG(sdata->u.wds.remote_addr)); - } - - /* Update WDS link data */ - memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); - - return 0; -} - -/* Must not be called for mdev and apdev */ -void ieee80211_if_setup(struct net_device *dev) -{ - ether_setup(dev); - dev->hard_start_xmit = ieee80211_subif_start_xmit; - dev->wireless_handlers = &ieee80211_iw_handler_def; - dev->set_multicast_list = ieee80211_set_multicast_list; - dev->change_mtu = ieee80211_change_mtu; - dev->get_stats = ieee80211_get_stats; - dev->open = ieee80211_open; - dev->stop = ieee80211_stop; - dev->uninit = ieee80211_if_reinit; - dev->destructor = ieee80211_if_free; -} - -void ieee80211_if_mgmt_setup(struct net_device *dev) -{ - ether_setup(dev); - dev->hard_start_xmit = ieee80211_mgmt_start_xmit; - dev->change_mtu = ieee80211_change_mtu_apdev; - dev->get_stats = ieee80211_get_stats; - dev->open = ieee80211_mgmt_open; - dev->stop = ieee80211_mgmt_stop; - dev->type = ARPHRD_IEEE80211_PRISM; - dev->hard_header_parse = header_parse_80211; - dev->uninit = ieee80211_if_reinit; - dev->destructor = ieee80211_if_free; -} - struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { @@ -1948,7 +1942,6 @@ static int __init ieee80211_init(void) return 0; } - static void __exit ieee80211_exit(void) { ieee80211_wme_unregister(); From c2d1560ad8c2f6e0dd0d34102d022f3709325c26 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:23 +0200 Subject: [PATCH 1020/2804] [MAC80211]: introduce util.c Introduce a new file util.c and move a whole bunch of functions into it. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/Makefile | 1 + net/mac80211/ieee80211.c | 437 ---------------------------------- net/mac80211/ieee80211_i.h | 18 +- net/mac80211/util.c | 463 +++++++++++++++++++++++++++++++++++++ 4 files changed, 472 insertions(+), 447 deletions(-) create mode 100644 net/mac80211/util.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index d95de3f8a4b1..122b23eb15d1 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -21,4 +21,5 @@ mac80211-objs := \ rx.o \ tx.o \ key.o \ + util.o \ $(mac80211-objs-y) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index f240f9706081..1981058907b7 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -34,23 +34,6 @@ #include "debugfs.h" #include "debugfs_netdev.h" -/* privid for wiphys to determine whether they belong to us or not */ -void *mac80211_wiphy_privid = &mac80211_wiphy_privid; - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -const unsigned char rfc1042_header[] = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -const unsigned char bridge_tunnel_header[] = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; - -/* No encapsulation header if EtherType < 0x600 (=length) */ -static const unsigned char eapol_header[] = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; - - /* * For seeing transmitted packets on monitor interfaces * we have a radiotap header too. @@ -661,346 +644,6 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) /* everything else */ -static int rate_list_match(const int *rate_list, int rate) -{ - int i; - - if (!rate_list) - return 0; - - for (i = 0; rate_list[i] >= 0; i++) - if (rate_list[i] == rate) - return 1; - - return 0; -} - -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode) -{ - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - rate->flags &= ~(IEEE80211_RATE_SUPPORTED | - IEEE80211_RATE_BASIC); - - if (local->supp_rates[mode->mode]) { - if (!rate_list_match(local->supp_rates[mode->mode], - rate->rate)) - continue; - } - - rate->flags |= IEEE80211_RATE_SUPPORTED; - - /* Use configured basic rate set if it is available. If not, - * use defaults that are sane for most cases. */ - if (local->basic_rates[mode->mode]) { - if (rate_list_match(local->basic_rates[mode->mode], - rate->rate)) - rate->flags |= IEEE80211_RATE_BASIC; - } else switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211B: - if (rate->rate == 10 || rate->rate == 20) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_ATHEROS_TURBO: - if (rate->rate == 120 || rate->rate == 240 || - rate->rate == 480) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110) - rate->flags |= IEEE80211_RATE_BASIC; - break; - } - - /* Set ERP and MANDATORY flags based on phymode */ - switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211B: - if (rate->rate == 10) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_ATHEROS_TURBO: - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110 || - rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - } - if (ieee80211_is_erp_rate(mode->mode, rate->rate)) - rate->flags |= IEEE80211_RATE_ERP; - } -} - -u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) -{ - u16 fc; - - if (len < 24) - return NULL; - - fc = le16_to_cpu(hdr->frame_control); - - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { - case IEEE80211_FCTL_TODS: - return hdr->addr1; - case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): - return NULL; - case IEEE80211_FCTL_FROMDS: - return hdr->addr2; - case 0: - return hdr->addr3; - } - break; - case IEEE80211_FTYPE_MGMT: - return hdr->addr3; - case IEEE80211_FTYPE_CTL: - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) - return hdr->addr1; - else - return NULL; - } - - return NULL; -} - -int ieee80211_get_hdrlen(u16 fc) -{ - int hdrlen = 24; - - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = 30; /* Addr4 */ - /* - * The QoS Control field is two bytes and its presence is - * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to - * hdrlen if that bit is set. - * This works by masking out the bit and shifting it to - * bit position 1 so the result has the value 0 or 2. - */ - hdrlen += (fc & IEEE80211_STYPE_QOS_DATA) - >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1); - break; - case IEEE80211_FTYPE_CTL: - /* - * ACK and CTS are 10 bytes, all others 16. To see how - * to get this condition consider - * subtype mask: 0b0000000011110000 (0x00F0) - * ACK subtype: 0b0000000011010000 (0x00D0) - * CTS subtype: 0b0000000011000000 (0x00C0) - * bits that matter: ^^^ (0x00E0) - * value of those: 0b0000000011000000 (0x00C0) - */ - if ((fc & 0xE0) == 0xC0) - hdrlen = 10; - else - hdrlen = 16; - break; - } - - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_get_hdrlen); - -int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data; - int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); - if (unlikely(hdrlen > skb->len)) - return 0; - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); - - -int ieee80211_is_eapol(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr; - u16 fc; - int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - - hdr = (const struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return 0; - - hdrlen = ieee80211_get_hdrlen(fc); - - if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) && - memcmp(skb->data + hdrlen, eapol_header, - sizeof(eapol_header)) == 0)) - return 1; - - return 0; -} - -void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - if (tx->u.tx.extra_frag) { - struct ieee80211_hdr *fhdr; - int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - fhdr = (struct ieee80211_hdr *) - tx->u.tx.extra_frag[i]->data; - fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - } - } -} - -static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, - int rate, int erp, int short_preamble) -{ - int dur; - - /* calculate duration (in microseconds, rounded up to next higher - * integer if it includes a fractional microsecond) to send frame of - * len bytes (does not include FCS) at the given rate. Duration will - * also include SIFS. - * - * rate is in 100 kbps, so divident is multiplied by 10 in the - * DIV_ROUND_UP() operations. - */ - - if (local->hw.conf.phymode == MODE_IEEE80211A || erp || - local->hw.conf.phymode == MODE_ATHEROS_TURBO) { - /* - * OFDM: - * - * N_DBPS = DATARATE x 4 - * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) - * (16 = SIGNAL time, 6 = tail bits) - * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext - * - * T_SYM = 4 usec - * 802.11a - 17.5.2: aSIFSTime = 16 usec - * 802.11g - 19.8.4: aSIFSTime = 10 usec + - * signal ext = 6 usec - */ - /* FIX: Atheros Turbo may have different (shorter) duration? */ - dur = 16; /* SIFS + signal ext */ - dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ - dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ - dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, - 4 * rate); /* T_SYM x N_SYM */ - } else { - /* - * 802.11b or 802.11g with 802.11b compatibility: - * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + - * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. - * - * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 - * aSIFSTime = 10 usec - * aPreambleLength = 144 usec or 72 usec with short preamble - * aPLCPHeaderLength = 48 usec or 24 usec with short preamble - */ - dur = 10; /* aSIFSTime = 10 usec */ - dur += short_preamble ? (72 + 24) : (144 + 48); - - dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); - } - - return dur; -} - -/* Exported duration function for driver use */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, - size_t frame_len, int rate) -{ - struct ieee80211_local *local = hw_to_local(hw); - u16 dur; - int erp; - - erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); - dur = ieee80211_frame_duration(local, frame_len, rate, - erp, local->short_preamble); - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_generic_frame_duration); - -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, - size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; - int erp; - u16 dur; - - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); - - /* CTS duration */ - dur = ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - /* Data frame duration */ - dur += ieee80211_frame_duration(local, frame_len, rate->rate, - erp, short_preamble); - /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_rts_duration); - -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, - size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; - int erp; - u16 dur; - - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); - - /* Data frame duration */ - dur = ieee80211_frame_duration(local, frame_len, rate->rate, - erp, short_preamble); - if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { - /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - } - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_ctstoself_duration); - static int __ieee80211_if_config(struct net_device *dev, struct sk_buff *beacon, struct ieee80211_tx_control *control) @@ -1123,27 +766,6 @@ struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_get_mc_list_item); -struct ieee80211_rate * -ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) -{ - struct ieee80211_hw_mode *mode; - int r; - - list_for_each_entry(mode, &local->modes_list, list) { - if (mode->mode != phymode) - continue; - for (r = 0; r < mode->num_rates; r++) { - struct ieee80211_rate *rate = &mode->rates[r]; - if (rate->val == hw_rate || - (rate->flags & IEEE80211_RATE_PREAMBLE2 && - rate->val2 == hw_rate)) - return rate; - } - } - - return NULL; -} - static void ieee80211_stat_refresh(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; @@ -1856,65 +1478,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_free_hw); -void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) -{ - struct ieee80211_local *local = hw_to_local(hw); - - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) { - if (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - else - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); - } -} -EXPORT_SYMBOL(ieee80211_wake_queue); - -void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) -{ - struct ieee80211_local *local = hw_to_local(hw); - - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) - netif_stop_queue(local->mdev); - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} -EXPORT_SYMBOL(ieee80211_stop_queue); - -void ieee80211_start_queues(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - int i; - - for (i = 0; i < local->hw.queues; i++) - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); - if (!ieee80211_qdisc_installed(local->mdev)) - netif_start_queue(local->mdev); -} -EXPORT_SYMBOL(ieee80211_start_queues); - -void ieee80211_stop_queues(struct ieee80211_hw *hw) -{ - int i; - - for (i = 0; i < hw->queues; i++) - ieee80211_stop_queue(hw, i); -} -EXPORT_SYMBOL(ieee80211_stop_queues); - -void ieee80211_wake_queues(struct ieee80211_hw *hw) -{ - int i; - - for (i = 0; i < hw->queues; i++) - ieee80211_wake_queue(hw, i); -} -EXPORT_SYMBOL(ieee80211_wake_queues); - struct net_device_stats *ieee80211_dev_stats(struct net_device *dev) { struct ieee80211_sub_if_data *sdata; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 28414b3e0c34..ed00552b3418 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -733,14 +733,6 @@ struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, void ieee80211_key_threshold_notify(struct net_device *dev, struct ieee80211_key *key, struct sta_info *sta); -u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); -int ieee80211_is_eapol(const struct sk_buff *skb); - -extern const unsigned char rfc1042_header[6]; -extern const unsigned char bridge_tunnel_header[6]; - -int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, - int rate, int erp, int short_preamble); /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; @@ -833,7 +825,13 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, int idx, size_t key_len, gfp_t flags); void ieee80211_key_free(struct ieee80211_key *key); -/* for wiphy privid */ -extern void *mac80211_wiphy_privid; +/* utility functions/constants */ +extern void *mac80211_wiphy_privid; /* for wiphy privid */ +extern const unsigned char rfc1042_header[6]; +extern const unsigned char bridge_tunnel_header[6]; +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); +int ieee80211_is_eapol(const struct sk_buff *skb); +int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, + int rate, int erp, int short_preamble); #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c new file mode 100644 index 000000000000..c45658309472 --- /dev/null +++ b/net/mac80211/util.c @@ -0,0 +1,463 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007 Johannes Berg + * + * 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. + * + * utilities for mac80211 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211_i.h" +#include "ieee80211_rate.h" +#include "wme.h" + +/* privid for wiphys to determine whether they belong to us or not */ +void *mac80211_wiphy_privid = &mac80211_wiphy_privid; + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +const unsigned char rfc1042_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +const unsigned char bridge_tunnel_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; + +/* No encapsulation header if EtherType < 0x600 (=length) */ +static const unsigned char eapol_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; + + +static int rate_list_match(const int *rate_list, int rate) +{ + int i; + + if (!rate_list) + return 0; + + for (i = 0; rate_list[i] >= 0; i++) + if (rate_list[i] == rate) + return 1; + + return 0; +} + +void ieee80211_prepare_rates(struct ieee80211_local *local, + struct ieee80211_hw_mode *mode) +{ + int i; + + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *rate = &mode->rates[i]; + + rate->flags &= ~(IEEE80211_RATE_SUPPORTED | + IEEE80211_RATE_BASIC); + + if (local->supp_rates[mode->mode]) { + if (!rate_list_match(local->supp_rates[mode->mode], + rate->rate)) + continue; + } + + rate->flags |= IEEE80211_RATE_SUPPORTED; + + /* Use configured basic rate set if it is available. If not, + * use defaults that are sane for most cases. */ + if (local->basic_rates[mode->mode]) { + if (rate_list_match(local->basic_rates[mode->mode], + rate->rate)) + rate->flags |= IEEE80211_RATE_BASIC; + } else switch (mode->mode) { + case MODE_IEEE80211A: + if (rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case MODE_IEEE80211B: + if (rate->rate == 10 || rate->rate == 20) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case MODE_ATHEROS_TURBO: + if (rate->rate == 120 || rate->rate == 240 || + rate->rate == 480) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case MODE_IEEE80211G: + if (rate->rate == 10 || rate->rate == 20 || + rate->rate == 55 || rate->rate == 110) + rate->flags |= IEEE80211_RATE_BASIC; + break; + } + + /* Set ERP and MANDATORY flags based on phymode */ + switch (mode->mode) { + case MODE_IEEE80211A: + if (rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + case MODE_IEEE80211B: + if (rate->rate == 10) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + case MODE_ATHEROS_TURBO: + break; + case MODE_IEEE80211G: + if (rate->rate == 10 || rate->rate == 20 || + rate->rate == 55 || rate->rate == 110 || + rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + } + if (ieee80211_is_erp_rate(mode->mode, rate->rate)) + rate->flags |= IEEE80211_RATE_ERP; + } +} + +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) +{ + u16 fc; + + if (len < 24) + return NULL; + + fc = le16_to_cpu(hdr->frame_control); + + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_DATA: + switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { + case IEEE80211_FCTL_TODS: + return hdr->addr1; + case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + return NULL; + case IEEE80211_FCTL_FROMDS: + return hdr->addr2; + case 0: + return hdr->addr3; + } + break; + case IEEE80211_FTYPE_MGMT: + return hdr->addr3; + case IEEE80211_FTYPE_CTL: + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) + return hdr->addr1; + else + return NULL; + } + + return NULL; +} + +int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = 30; /* Addr4 */ + /* + * The QoS Control field is two bytes and its presence is + * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to + * hdrlen if that bit is set. + * This works by masking out the bit and shifting it to + * bit position 1 so the result has the value 0 or 2. + */ + hdrlen += (fc & IEEE80211_STYPE_QOS_DATA) + >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1); + break; + case IEEE80211_FTYPE_CTL: + /* + * ACK and CTS are 10 bytes, all others 16. To see how + * to get this condition consider + * subtype mask: 0b0000000011110000 (0x00F0) + * ACK subtype: 0b0000000011010000 (0x00D0) + * CTS subtype: 0b0000000011000000 (0x00C0) + * bits that matter: ^^^ (0x00E0) + * value of those: 0b0000000011000000 (0x00C0) + */ + if ((fc & 0xE0) == 0xC0) + hdrlen = 10; + else + hdrlen = 16; + break; + } + + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen); + +int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data; + int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + if (unlikely(hdrlen > skb->len)) + return 0; + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); + +int ieee80211_is_eapol(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr; + u16 fc; + int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + + hdr = (const struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return 0; + + hdrlen = ieee80211_get_hdrlen(fc); + + if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) && + memcmp(skb->data + hdrlen, eapol_header, + sizeof(eapol_header)) == 0)) + return 1; + + return 0; +} + +void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + if (tx->u.tx.extra_frag) { + struct ieee80211_hdr *fhdr; + int i; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + fhdr = (struct ieee80211_hdr *) + tx->u.tx.extra_frag[i]->data; + fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + } + } +} + +int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, + int rate, int erp, int short_preamble) +{ + int dur; + + /* calculate duration (in microseconds, rounded up to next higher + * integer if it includes a fractional microsecond) to send frame of + * len bytes (does not include FCS) at the given rate. Duration will + * also include SIFS. + * + * rate is in 100 kbps, so divident is multiplied by 10 in the + * DIV_ROUND_UP() operations. + */ + + if (local->hw.conf.phymode == MODE_IEEE80211A || erp || + local->hw.conf.phymode == MODE_ATHEROS_TURBO) { + /* + * OFDM: + * + * N_DBPS = DATARATE x 4 + * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) + * (16 = SIGNAL time, 6 = tail bits) + * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext + * + * T_SYM = 4 usec + * 802.11a - 17.5.2: aSIFSTime = 16 usec + * 802.11g - 19.8.4: aSIFSTime = 10 usec + + * signal ext = 6 usec + */ + /* FIX: Atheros Turbo may have different (shorter) duration? */ + dur = 16; /* SIFS + signal ext */ + dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ + dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ + dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, + 4 * rate); /* T_SYM x N_SYM */ + } else { + /* + * 802.11b or 802.11g with 802.11b compatibility: + * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + + * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. + * + * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 + * aSIFSTime = 10 usec + * aPreambleLength = 144 usec or 72 usec with short preamble + * aPLCPHeaderLength = 48 usec or 24 usec with short preamble + */ + dur = 10; /* aSIFSTime = 10 usec */ + dur += short_preamble ? (72 + 24) : (144 + 48); + + dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); + } + + return dur; +} + +/* Exported duration function for driver use */ +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, + size_t frame_len, int rate) +{ + struct ieee80211_local *local = hw_to_local(hw); + u16 dur; + int erp; + + erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); + dur = ieee80211_frame_duration(local, frame_len, rate, + erp, local->short_preamble); + + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_generic_frame_duration); + +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, + size_t frame_len, + const struct ieee80211_tx_control *frame_txctl) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rate *rate; + int short_preamble = local->short_preamble; + int erp; + u16 dur; + + rate = frame_txctl->rts_rate; + erp = !!(rate->flags & IEEE80211_RATE_ERP); + + /* CTS duration */ + dur = ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + /* Data frame duration */ + dur += ieee80211_frame_duration(local, frame_len, rate->rate, + erp, short_preamble); + /* ACK duration */ + dur += ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_rts_duration); + +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, + size_t frame_len, + const struct ieee80211_tx_control *frame_txctl) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rate *rate; + int short_preamble = local->short_preamble; + int erp; + u16 dur; + + rate = frame_txctl->rts_rate; + erp = !!(rate->flags & IEEE80211_RATE_ERP); + + /* Data frame duration */ + dur = ieee80211_frame_duration(local, frame_len, rate->rate, + erp, short_preamble); + if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { + /* ACK duration */ + dur += ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + } + + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_ctstoself_duration); + +struct ieee80211_rate * +ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) +{ + struct ieee80211_hw_mode *mode; + int r; + + list_for_each_entry(mode, &local->modes_list, list) { + if (mode->mode != phymode) + continue; + for (r = 0; r < mode->num_rates; r++) { + struct ieee80211_rate *rate = &mode->rates[r]; + if (rate->val == hw_rate || + (rate->flags & IEEE80211_RATE_PREAMBLE2 && + rate->val2 == hw_rate)) + return rate; + } + } + + return NULL; +} + +void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, + &local->state[queue])) { + if (test_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[queue])) + tasklet_schedule(&local->tx_pending_tasklet); + else + if (!ieee80211_qdisc_installed(local->mdev)) { + if (queue == 0) + netif_wake_queue(local->mdev); + } else + __netif_schedule(local->mdev); + } +} +EXPORT_SYMBOL(ieee80211_wake_queue); + +void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) + netif_stop_queue(local->mdev); + set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); +} +EXPORT_SYMBOL(ieee80211_stop_queue); + +void ieee80211_start_queues(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + int i; + + for (i = 0; i < local->hw.queues; i++) + clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); + if (!ieee80211_qdisc_installed(local->mdev)) + netif_start_queue(local->mdev); +} +EXPORT_SYMBOL(ieee80211_start_queues); + +void ieee80211_stop_queues(struct ieee80211_hw *hw) +{ + int i; + + for (i = 0; i < hw->queues; i++) + ieee80211_stop_queue(hw, i); +} +EXPORT_SYMBOL(ieee80211_stop_queues); + +void ieee80211_wake_queues(struct ieee80211_hw *hw) +{ + int i; + + for (i = 0; i < hw->queues; i++) + ieee80211_wake_queue(hw, i); +} +EXPORT_SYMBOL(ieee80211_wake_queues); From be8755e1804d6f60e6a96a46ac6bc46ce6dfca53 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Fri, 27 Jul 2007 15:43:23 +0200 Subject: [PATCH 1021/2804] [MAC80211]: improve locking of sta_info related structures The sta_info code has some awkward locking which prevents some driver callbacks from being allowed to sleep. This patch makes the locking more focused so code that calls driver callbacks are allowed to sleep. It also converts sta_lock to a rwlock. Signed-off-by: Michael Wu Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- include/net/mac80211.h | 3 +- net/mac80211/ieee80211.c | 6 +- net/mac80211/ieee80211_i.h | 11 +- net/mac80211/ieee80211_iface.c | 2 +- net/mac80211/ieee80211_sta.c | 20 ++-- net/mac80211/sta_info.c | 184 +++++++++++++-------------------- net/mac80211/sta_info.h | 11 +- net/mac80211/tx.c | 8 +- 8 files changed, 109 insertions(+), 136 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c34fd9a6160a..8a086a8ac270 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -626,8 +626,7 @@ struct ieee80211_ops { * station hwaddr for individual keys. aid of the station is given * to help low-level driver in selecting which key->hw_key_idx to use * for this key. TX control data will use the hw_key_idx selected by - * the low-level driver. - * Must be atomic. */ + * the low-level driver. */ int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, u8 *addr, struct ieee80211_key_conf *key, int aid); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 1981058907b7..566bdca32b86 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -628,8 +628,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) /* Remove STA entry for the old peer */ sta = sta_info_get(local, sdata->u.wds.remote_addr); if (sta) { + sta_info_free(sta); sta_info_put(sta); - sta_info_free(sta, 0); } else { printk(KERN_DEBUG "%s: could not find STA entry for WDS link " "peer " MAC_FMT "\n", @@ -776,13 +776,13 @@ static void ieee80211_stat_refresh(unsigned long data) return; /* go through all stations */ - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); list_for_each_entry(sta, &local->sta_list, list) { sta->channel_use = (sta->channel_use_raw / local->stat_time) / CHAN_UTIL_PER_10MS; sta->channel_use_raw = 0; } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); /* go through all subinterfaces */ read_lock(&local->sub_if_lock); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ed00552b3418..e76a58678959 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -417,10 +417,9 @@ struct ieee80211_local { struct sk_buff_head skb_queue_unreliable; /* Station data structures */ - spinlock_t sta_lock; /* mutex for STA data structures */ + rwlock_t sta_lock; /* protects STA data structures */ int num_sta; /* number of stations in sta_list */ struct list_head sta_list; - struct list_head deleted_sta_list; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; @@ -669,9 +668,9 @@ static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid) static inline void bss_tim_set(struct ieee80211_local *local, struct ieee80211_if_ap *bss, int aid) { - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); __bss_tim_set(bss, aid); - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); } static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid) @@ -686,9 +685,9 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid) static inline void bss_tim_clear(struct ieee80211_local *local, struct ieee80211_if_ap *bss, int aid) { - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); __bss_tim_clear(bss, aid); - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); } /** diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 8532a5ccdd1e..6db67767801d 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -272,8 +272,8 @@ void ieee80211_if_reinit(struct net_device *dev) case IEEE80211_IF_TYPE_WDS: sta = sta_info_get(local, sdata->u.wds.remote_addr); if (sta) { + sta_info_free(sta); sta_info_put(sta); - sta_info_free(sta, 0); } else { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Someone had deleted my STA " diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 0d99b685df5f..9aee1abae127 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -773,7 +773,7 @@ static void ieee80211_associated(struct net_device *dev, "range\n", dev->name, MAC_ARG(ifsta->bssid)); disassoc = 1; - sta_info_free(sta, 0); + sta_info_free(sta); ifsta->probereq_poll = 0; } else { ieee80211_send_probe_req(dev, ifsta->bssid, @@ -1890,7 +1890,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) int active = 0; struct sta_info *sta; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); list_for_each_entry(sta, &local->sta_list, list) { if (sta->dev == dev && time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, @@ -1899,7 +1899,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) break; } } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); return active; } @@ -1909,16 +1909,24 @@ static void ieee80211_sta_expire(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta, *tmp; + LIST_HEAD(tmp_list); - spin_lock_bh(&local->sta_lock); + write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + IEEE80211_IBSS_INACTIVITY_LIMIT)) { printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT "\n", dev->name, MAC_ARG(sta->addr)); - sta_info_free(sta, 1); + __sta_info_get(sta); + sta_info_remove(sta); + list_add(&sta->list, &tmp_list); } - spin_unlock_bh(&local->sta_lock); + write_unlock_bh(&local->sta_lock); + + list_for_each_entry_safe(sta, tmp, &tmp_list, list) { + sta_info_free(sta); + sta_info_put(sta); + } } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ab7b1f067c6e..34245b882c2b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -32,38 +32,34 @@ static void sta_info_hash_add(struct ieee80211_local *local, /* Caller must hold local->sta_lock */ -static void sta_info_hash_del(struct ieee80211_local *local, - struct sta_info *sta) +static int sta_info_hash_del(struct ieee80211_local *local, + struct sta_info *sta) { struct sta_info *s; s = local->sta_hash[STA_HASH(sta->addr)]; if (!s) - return; - if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) { + return -ENOENT; + if (s == sta) { local->sta_hash[STA_HASH(sta->addr)] = s->hnext; - return; + return 0; } - while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) + while (s->hnext && s->hnext != sta) s = s->hnext; - if (s->hnext) - s->hnext = s->hnext->hnext; - else - printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from " - "hash table\n", local->mdev->name, MAC_ARG(sta->addr)); -} + if (s->hnext) { + s->hnext = sta->hnext; + return 0; + } -static inline void __sta_info_get(struct sta_info *sta) -{ - kref_get(&sta->kref); + return -ENOENT; } struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) { struct sta_info *sta; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); sta = local->sta_hash[STA_HASH(addr)]; while (sta) { if (memcmp(sta->addr, addr, ETH_ALEN) == 0) { @@ -72,7 +68,7 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) } sta = sta->hnext; } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); return sta; } @@ -85,7 +81,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local) int min_txrate = 9999999; int i; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); mode = local->oper_hw_mode; for (i = 0; i < STA_HASH_SIZE; i++) { sta = local->sta_hash[i]; @@ -95,7 +91,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local) sta = sta->hnext; } } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); if (min_txrate == 9999999) min_txrate = 0; @@ -150,7 +146,6 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); if (!sta->rate_ctrl_priv) { rate_control_put(sta->rate_ctrl); - kref_put(&sta->kref, sta_info_release); kfree(sta); return NULL; } @@ -162,14 +157,14 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, skb_queue_head_init(&sta->tx_filtered); __sta_info_get(sta); /* sta used by caller, decremented by * sta_info_put() */ - spin_lock_bh(&local->sta_lock); + write_lock_bh(&local->sta_lock); list_add(&sta->list, &local->sta_list); local->num_sta++; sta_info_hash_add(local, sta); - spin_unlock_bh(&local->sta_lock); if (local->ops->sta_table_notification) local->ops->sta_table_notification(local_to_hw(local), local->num_sta); + write_unlock_bh(&local->sta_lock); sta->key_idx_compression = HW_KEY_IDX_INVALID; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -178,47 +173,25 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_DEBUGFS - if (!in_interrupt()) { - sta->debugfs_registered = 1; - ieee80211_sta_debugfs_add(sta); - rate_control_add_sta_debugfs(sta); - } else { - /* debugfs entry adding might sleep, so schedule process - * context task for adding entry for STAs that do not yet - * have one. */ - queue_work(local->hw.workqueue, &local->sta_debugfs_add); - } + /* debugfs entry adding might sleep, so schedule process + * context task for adding entry for STAs that do not yet + * have one. */ + queue_work(local->hw.workqueue, &local->sta_debugfs_add); #endif return sta; } -static void finish_sta_info_free(struct ieee80211_local *local, - struct sta_info *sta) -{ -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", - local->mdev->name, MAC_ARG(sta->addr)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - - if (sta->key) { - ieee80211_debugfs_key_remove(sta->key); - ieee80211_key_free(sta->key); - sta->key = NULL; - } - - rate_control_remove_sta_debugfs(sta); - ieee80211_sta_debugfs_remove(sta); - - sta_info_put(sta); -} - -static void sta_info_remove(struct sta_info *sta) +/* Caller must hold local->sta_lock */ +void sta_info_remove(struct sta_info *sta) { struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata; - sta_info_hash_del(local, sta); + /* don't do anything if we've been removed already */ + if (sta_info_hash_del(local, sta)) + return; + list_del(&sta->list); sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sta->flags & WLAN_STA_PS) { @@ -228,30 +201,29 @@ static void sta_info_remove(struct sta_info *sta) } local->num_sta--; sta_info_remove_aid_ptr(sta); + + if (local->ops->sta_table_notification) + local->ops->sta_table_notification(local_to_hw(local), + local->num_sta); } -void sta_info_free(struct sta_info *sta, int locked) +void sta_info_free(struct sta_info *sta) { struct sk_buff *skb; struct ieee80211_local *local = sta->local; - if (!locked) { - spin_lock_bh(&local->sta_lock); - sta_info_remove(sta); - spin_unlock_bh(&local->sta_lock); - } else { - sta_info_remove(sta); - } - if (local->ops->sta_table_notification) - local->ops->sta_table_notification(local_to_hw(local), - local->num_sta); + might_sleep(); + + write_lock_bh(&local->sta_lock); + sta_info_remove(sta); + write_unlock_bh(&local->sta_lock); while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { local->total_ps_buffered--; - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); } while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); } if (sta->key) { @@ -276,13 +248,21 @@ void sta_info_free(struct sta_info *sta, int locked) sta->key_idx_compression = HW_KEY_IDX_INVALID; } -#ifdef CONFIG_MAC80211_DEBUGFS - if (in_atomic()) { - list_add(&sta->list, &local->deleted_sta_list); - queue_work(local->hw.workqueue, &local->sta_debugfs_add); - } else -#endif - finish_sta_info_free(local, sta); +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", + local->mdev->name, MAC_ARG(sta->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + + if (sta->key) { + ieee80211_debugfs_key_remove(sta->key); + ieee80211_key_free(sta->key); + sta->key = NULL; + } + + rate_control_remove_sta_debugfs(sta); + ieee80211_sta_debugfs_remove(sta); + + sta_info_put(sta); } @@ -343,13 +323,13 @@ static void sta_info_cleanup(unsigned long data) struct ieee80211_local *local = (struct ieee80211_local *) data; struct sta_info *sta; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); list_for_each_entry(sta, &local->sta_list, list) { __sta_info_get(sta); sta_info_cleanup_expire_buffered(local, sta); sta_info_put(sta); } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; add_timer(&local->sta_cleanup); @@ -362,36 +342,21 @@ static void sta_info_debugfs_add_task(struct work_struct *work) container_of(work, struct ieee80211_local, sta_debugfs_add); struct sta_info *sta, *tmp; - while (1) { - spin_lock_bh(&local->sta_lock); - if (!list_empty(&local->deleted_sta_list)) { - sta = list_entry(local->deleted_sta_list.next, - struct sta_info, list); - list_del(local->deleted_sta_list.next); - } else - sta = NULL; - spin_unlock_bh(&local->sta_lock); - if (!sta) - break; - finish_sta_info_free(local, sta); - } - while (1) { sta = NULL; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); list_for_each_entry(tmp, &local->sta_list, list) { - if (!tmp->debugfs_registered) { + if (!tmp->debugfs.dir) { sta = tmp; __sta_info_get(sta); break; } } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); if (!sta) break; - sta->debugfs_registered = 1; ieee80211_sta_debugfs_add(sta); rate_control_add_sta_debugfs(sta); sta_info_put(sta); @@ -401,9 +366,8 @@ static void sta_info_debugfs_add_task(struct work_struct *work) void sta_info_init(struct ieee80211_local *local) { - spin_lock_init(&local->sta_lock); + rwlock_init(&local->sta_lock); INIT_LIST_HEAD(&local->sta_list); - INIT_LIST_HEAD(&local->deleted_sta_list); init_timer(&local->sta_cleanup); local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; @@ -423,17 +387,8 @@ int sta_info_start(struct ieee80211_local *local) void sta_info_stop(struct ieee80211_local *local) { - struct sta_info *sta, *tmp; - del_timer(&local->sta_cleanup); - - list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { - /* sta_info_free must be called with 0 as the last - * parameter to ensure all debugfs sta entries are - * unregistered. We don't need locking at this - * point. */ - sta_info_free(sta, 0); - } + sta_info_flush(local, NULL); } void sta_info_remove_aid_ptr(struct sta_info *sta) @@ -461,10 +416,19 @@ void sta_info_remove_aid_ptr(struct sta_info *sta) void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) { struct sta_info *sta, *tmp; + LIST_HEAD(tmp_list); - spin_lock_bh(&local->sta_lock); + write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) - if (!dev || dev == sta->dev) - sta_info_free(sta, 1); - spin_unlock_bh(&local->sta_lock); + if (!dev || dev == sta->dev) { + __sta_info_get(sta); + sta_info_remove(sta); + list_add_tail(&sta->list, &tmp_list); + } + write_unlock_bh(&local->sta_lock); + + list_for_each_entry_safe(sta, tmp, &tmp_list, list) { + sta_info_free(sta); + sta_info_put(sta); + } } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b5591d2f60a4..b5ef72379add 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -98,9 +98,6 @@ struct sta_info { * filtering; used only if sta->key is not * set */ -#ifdef CONFIG_MAC80211_DEBUGFS - int debugfs_registered; -#endif int assoc_ap; /* whether this is an AP that we are * associated with as a client */ @@ -149,12 +146,18 @@ struct sta_info { */ #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) +static inline void __sta_info_get(struct sta_info *sta) +{ + kref_get(&sta->kref); +} + struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); int sta_info_min_txrate_get(struct ieee80211_local *local); void sta_info_put(struct sta_info *sta); struct sta_info * sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp); -void sta_info_free(struct sta_info *sta, int locked); +void sta_info_remove(struct sta_info *sta); +void sta_info_free(struct sta_info *sta); void sta_info_init(struct ieee80211_local *local); int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index dc128b412eab..2a1a7d457136 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -306,7 +306,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) } read_unlock(&local->sub_if_lock); - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); list_for_each_entry(sta, &local->sta_list, list) { skb = skb_dequeue(&sta->ps_tx_buf); if (skb) { @@ -315,7 +315,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) } total += skb_queue_len(&sta->ps_tx_buf); } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); local->total_ps_buffered = total; printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", @@ -1629,7 +1629,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, /* Generate bitmap for TIM only if there are any STAs in power save * mode. */ - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); if (atomic_read(&bss->num_sta_ps) > 0) /* in the hope that this is faster than * checking byte-for-byte */ @@ -1680,7 +1680,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, *pos++ = aid0; /* Bitmap control */ *pos++ = 0; /* Part Virt Bitmap */ } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); } struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, From 8a69aa93d54cb56017159b08512c80ede2263060 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 27 Jul 2007 15:43:23 +0200 Subject: [PATCH 1022/2804] [MAC80211]: STA reassociation improvements My cheapy D-Link AP behaves strangely w.r.t reassociations. The following sequence of commands causes me to lose association and to be unable to regain it: ifconfig eth8 down ifconfig eth8 up iwconfig eth8 essid This is because mac80211 tries to reassociate, rather than just associate. My AP replies with an association response (not a reassociation response...) denying the association with code 12: "Association denied due to reason outside the scope of this standard" mac80211 tries this reassociation another 4 times or so before finally giving up. I see 2 problems here: 1. bringing the interface down and up again should be resetting interface state i.e. after the interface is brought down, it should have no memory of if or where it was previously associated 2. after the first reassociation fails, mac80211 should fall back to standard association for the next attempt Signed-off-by: Daniel Drake Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 13 +++++++++++++ net/mac80211/ieee80211_sta.c | 6 ++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 566bdca32b86..f811a260ee9c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -375,6 +375,18 @@ static void ieee80211_start_hard_monitor(struct ieee80211_local *local) } } +static void ieee80211_if_open(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + switch (sdata->type) { + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.prev_bssid_set = 0; + break; + } +} + static int ieee80211_open(struct net_device *dev) { struct ieee80211_sub_if_data *sdata, *nsdata; @@ -408,6 +420,7 @@ static int ieee80211_open(struct net_device *dev) local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; return 0; } + ieee80211_if_open(dev); ieee80211_start_soft_monitor(local); conf.if_id = dev->ifindex; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 9aee1abae127..8e6548974a9f 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1187,8 +1187,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", dev->name, status_code); - if (status_code == WLAN_STATUS_REASSOC_NO_ASSOC) - ifsta->prev_bssid_set = 0; + /* 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. */ + ifsta->prev_bssid_set = 0; return; } From d5d08def9216c445339c5a24a2cdc9cc2c8c13f7 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 27 Jul 2007 15:43:23 +0200 Subject: [PATCH 1023/2804] [MAC80211]: Add LONG_RETRY flag to ieee80211_tx_control mac80211 informs the driver what the short and long retry values are through set_retry_limit(), but when packets are being transmitted it did not inform the driver which of the 2 retry limits should actually be used. Instead it sends the actual value, but for drivers that can only set the retry limit and the register and in the descriptor need to indicate which of the limits should be used this is not really useful. This patch will add a IEEE80211_TXCTL_LONG_RETRY_LIMIT flag to the ieee80211_tx_control structure. By default the short retry limit should be used but if the flag is set the long retry should be used. This does not prevent the driver to ignore the request for "no retry" packets, but at least those will be send out with the short retry limit. But there is no perfect cure for this problem.. :( Signed-off-by: Ivo van Doorn Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- include/net/mac80211.h | 8 +++++++- net/mac80211/tx.c | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8a086a8ac270..91cee0f0aa71 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -192,9 +192,15 @@ struct ieee80211_tx_control { #define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of * the frame */ #define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9) +#define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send + * using the through + * set_retry_limit configured + * long retry value */ u32 flags; /* tx control flags defined * above */ - u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. */ + u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. + * This could be used when set_retry_limit + * is not implemented by the driver */ u8 power_level; /* per-packet transmit power level, in dBm */ u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ s8 key_idx; /* -1 = do not encrypt, >= 0 keyidx from diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2a1a7d457136..532cf5127b70 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -649,6 +649,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) if (tx->skb->len + FCS_LEN > tx->local->rts_threshold && tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) { control->flags |= IEEE80211_TXCTL_USE_RTS_CTS; + control->flags |= IEEE80211_TXCTL_LONG_RETRY_LIMIT; control->retry_limit = tx->local->long_retry_limit; } else { From 7e9ed18874f0df84b6651f0636e1cfdac43bc610 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 27 Jul 2007 15:43:24 +0200 Subject: [PATCH 1024/2804] [MAC80211]: improved short preamble handling Similarly to CTS protection, whether short preambles are used for 802.11b transmissions should be a per-subif setting, not device global. For STAs, this patch makes short preamble handling automatic based on the ERP IE. For APs, hostapd still uses the prism ioctls, but the write ioctl has been restricted to AP-only subifs. ieee80211_txrx_data.short_preamble (an unused field) was removed. Unfortunately, some API changes were required for the following functions: - ieee80211_generic_frame_duration - ieee80211_rts_duration - ieee80211_ctstoself_duration - ieee80211_rts_get - ieee80211_ctstoself_get Affected drivers were updated accordingly. Signed-off-by: Daniel Drake Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187.h | 1 + drivers/net/wireless/rtl8187_dev.c | 4 +++- include/net/mac80211.h | 15 ++++++++---- net/mac80211/ieee80211_i.h | 7 ++++-- net/mac80211/ieee80211_ioctl.c | 7 ++++-- net/mac80211/ieee80211_sta.c | 16 ++++++++++++- net/mac80211/tx.c | 31 ++++++++++++++----------- net/mac80211/util.c | 37 +++++++++++++++++++++++++----- 8 files changed, 88 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 6124e467b156..7993b3d87203 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -67,6 +67,7 @@ struct rtl8187_priv { struct rtl818x_csr *map; void (*rf_init)(struct ieee80211_hw *); int mode; + int if_id; /* rtl8187 specific */ struct ieee80211_channel channels[14]; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index e61c6d5ba1a9..73f1ebc7eec7 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -96,7 +96,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { tmp |= RTL8187_TX_FLAG_RTS; hdr->rts_duration = - ieee80211_rts_duration(dev, skb->len, control); + ieee80211_rts_duration(dev, priv->if_id, skb->len, control); } if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) tmp |= RTL8187_TX_FLAG_CTS; @@ -510,6 +510,8 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id, struct rtl8187_priv *priv = dev->priv; int i; + priv->if_id = if_id; + for (i = 0; i < ETH_ALEN; i++) rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 91cee0f0aa71..3282038a1510 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -835,6 +835,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, /** * ieee80211_rts_get - RTS frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the RTS. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_control of the frame. @@ -845,7 +846,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * the next RTS frame from the 802.11 code. The low-level is responsible * for calling this function before and RTS frame is needed. */ -void ieee80211_rts_get(struct ieee80211_hw *hw, +void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_rts *rts); @@ -853,6 +854,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, /** * ieee80211_rts_duration - Get the duration field for an RTS frame * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the RTS. * @frame_txctl: &struct ieee80211_tx_control of the frame. * @@ -860,13 +862,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, * the duration field, the low-level driver uses this function to receive * the duration field value in little-endian byteorder. */ -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, const struct ieee80211_tx_control *frame_txctl); /** * ieee80211_ctstoself_get - CTS-to-self frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the CTS-to-self. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_control of the frame. @@ -877,7 +880,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, * the next CTS-to-self frame from the 802.11 code. The low-level is responsible * for calling this function before and CTS-to-self frame is needed. */ -void ieee80211_ctstoself_get(struct ieee80211_hw *hw, +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_cts *cts); @@ -885,6 +888,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, /** * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. * @frame_txctl: &struct ieee80211_tx_control of the frame. * @@ -892,20 +896,21 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, * the duration field, the low-level driver uses this function to receive * the duration field value in little-endian byteorder. */ -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, const struct ieee80211_tx_control *frame_txctl); /** * ieee80211_generic_frame_duration - Calculate the duration field for a frame * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame. * @rate: the rate (in 100kbps) at which the frame is going to be transmitted. * * Calculate the duration field of some generic frame, given its * length and transmission rate (in 100kbps). */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, int rate); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e76a58678959..b0af6e9f5319 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -127,7 +127,6 @@ struct ieee80211_txrx_data { struct ieee80211_tx_control *control; unsigned int unicast:1; unsigned int ps_buffered:1; - unsigned int short_preamble:1; unsigned int probe_last_frag:1; struct ieee80211_hw_mode *mode; struct ieee80211_rate *rate; @@ -286,6 +285,11 @@ struct ieee80211_sub_if_data { unsigned int promisc:1; unsigned int use_protection:1; /* CTS protect ERP frames */ + /* use short preamble with IEEE 802.11b: this flag is set when the AP + * or beacon generator reports that there are no present stations that + * cannot support short preambles */ + unsigned int short_preamble:1; + struct net_device_stats stats; int drop_unencrypted; int eapol; /* 0 = process EAPOL frames as normal data frames, @@ -447,7 +451,6 @@ struct ieee80211_local { int fragmentation_threshold; int short_retry_limit; /* dot11ShortRetryLimit */ int long_retry_limit; /* dot11LongRetryLimit */ - int short_preamble; /* use short preamble with IEEE 802.11b */ struct crypto_blkcipher *wep_tx_tfm; struct crypto_blkcipher *wep_rx_tfm; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index e7904db55325..8292431ac48f 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1061,7 +1061,10 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_PREAMBLE: - local->short_preamble = value; + if (sdata->type != IEEE80211_IF_TYPE_AP) + ret = -ENOENT; + else + sdata->short_preamble = value; break; case PRISM2_PARAM_STAT_TIME: @@ -1184,7 +1187,7 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_PREAMBLE: - *param = local->short_preamble; + *param = sdata->short_preamble; break; case PRISM2_PARAM_STAT_TIME: diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 8e6548974a9f..0f5f8131bd71 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -318,6 +318,7 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta = &sdata->u.sta; int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; + int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; if (use_protection != sdata->use_protection) { if (net_ratelimit()) { @@ -329,6 +330,18 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) } sdata->use_protection = use_protection; } + + if (!preamble_mode != sdata->short_preamble) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: switched to %s barker preamble" + " (BSSID=" MAC_FMT ")\n", + dev->name, + (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ? + "short" : "long", + MAC_ARG(ifsta->bssid)); + } + sdata->short_preamble = !preamble_mode; + } } @@ -415,6 +428,7 @@ static void ieee80211_set_associated(struct net_device *dev, ieee80211_sta_send_associnfo(dev, ifsta); } else { netif_carrier_off(dev); + sdata->short_preamble = 0; sdata->use_protection = 0; memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); } @@ -2281,7 +2295,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, "for IBSS beacon\n", dev->name); break; } - control.tx_rate = (local->short_preamble && + control.tx_rate = (sdata->short_preamble && (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? rate->val2 : rate->val; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 532cf5127b70..36761c7139bc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -173,7 +173,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, * to closest integer */ dur = ieee80211_frame_duration(local, 10, rate, erp, - local->short_preamble); + tx->sdata->short_preamble); if (next_frag_len) { /* Frame is fragmented: duration increases with time needed to @@ -182,7 +182,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, /* next fragment */ dur += ieee80211_frame_duration(local, next_frag_len, txrate->rate, erp, - local->short_preamble); + tx->sdata->short_preamble); } return dur; @@ -627,12 +627,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) tx->u.tx.control->rate = tx->u.tx.rate; } tx->u.tx.control->tx_rate = tx->u.tx.rate->val; - if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && - tx->local->short_preamble && - (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->u.tx.short_preamble = 1; - tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; - } return TXRX_CONTINUE; } @@ -641,6 +635,7 @@ static ieee80211_txrx_result ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->u.tx.control; struct ieee80211_hw_mode *mode = tx->u.tx.mode; @@ -677,6 +672,16 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; + /* Transmit data frames using short preambles if the driver supports + * short preambles at the selected rate and short preambles are + * available on the network at the current point in time. */ + if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && + tx->sdata->short_preamble && + (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { + tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; + } + /* Setup duration field for the first fragment of the frame. Duration * for remaining fragments will be updated when they are being sent * to low-level driver in ieee80211_tx(). */ @@ -1750,7 +1755,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, return NULL; } - control->tx_rate = (local->short_preamble && + control->tx_rate = (sdata->short_preamble && (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? rate->val2 : rate->val; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; @@ -1765,7 +1770,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, } EXPORT_SYMBOL(ieee80211_beacon_get); -void ieee80211_rts_get(struct ieee80211_hw *hw, +void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_rts *rts) @@ -1775,13 +1780,13 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; rts->frame_control = cpu_to_le16(fctl); - rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl); + rts->duration = ieee80211_rts_duration(hw, if_id, frame_len, frame_txctl); memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); memcpy(rts->ta, hdr->addr2, sizeof(rts->ta)); } EXPORT_SYMBOL(ieee80211_rts_get); -void ieee80211_ctstoself_get(struct ieee80211_hw *hw, +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_cts *cts) @@ -1791,7 +1796,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; cts->frame_control = cpu_to_le16(fctl); - cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl); + cts->duration = ieee80211_ctstoself_duration(hw, if_id, frame_len, frame_txctl); memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); } EXPORT_SYMBOL(ieee80211_ctstoself_get); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c45658309472..091ac0d634a5 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -314,31 +314,46 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, } /* Exported duration function for driver use */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, int rate) { struct ieee80211_local *local = hw_to_local(hw); + struct net_device *bdev = dev_get_by_index(if_id); + struct ieee80211_sub_if_data *sdata; u16 dur; int erp; + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); dur = ieee80211_frame_duration(local, frame_len, rate, - erp, local->short_preamble); + erp, sdata->short_preamble); + dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_generic_frame_duration); -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, const struct ieee80211_tx_control *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; + struct net_device *bdev = dev_get_by_index(if_id); + struct ieee80211_sub_if_data *sdata; + int short_preamble; int erp; u16 dur; + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + short_preamble = sdata->short_preamble; + rate = frame_txctl->rts_rate; erp = !!(rate->flags & IEEE80211_RATE_ERP); @@ -352,20 +367,29 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, dur += ieee80211_frame_duration(local, 10, rate->rate, erp, short_preamble); + dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_rts_duration); -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, const struct ieee80211_tx_control *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; + struct net_device *bdev = dev_get_by_index(if_id); + struct ieee80211_sub_if_data *sdata; + int short_preamble; int erp; u16 dur; + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + short_preamble = sdata->short_preamble; + rate = frame_txctl->rts_rate; erp = !!(rate->flags & IEEE80211_RATE_ERP); @@ -378,6 +402,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, erp, short_preamble); } + dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_ctstoself_duration); From d9430a32886f70c0c16d67c525f6cda2df7906ee Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 27 Jul 2007 15:43:24 +0200 Subject: [PATCH 1025/2804] [MAC80211]: implement ERP info change notifications zd1211rw and bcm43xx are interested in being notified when ERP IE conditions change, so that they can reprogram a register which affects how control frames are transmitted. This patch adds an interface similar to the one that can be found in softmac. Signed-off-by: Daniel Drake Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- include/net/mac80211.h | 8 ++++++++ net/mac80211/ieee80211.c | 25 ++++++++++++++++++++++++- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/ieee80211_ioctl.c | 16 ++++++++++------ net/mac80211/ieee80211_sta.c | 10 +++++++--- 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3282038a1510..e503cd37f82e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -697,6 +697,14 @@ struct ieee80211_ops { void (*sta_table_notification)(struct ieee80211_hw *hw, int num_sta); + /* Handle ERP IE change notifications. Must be atomic. */ + void (*erp_ie_changed)(struct ieee80211_hw *hw, u8 changes, + int cts_protection, int preamble); + + /* Flags for the erp_ie_changed changes parameter */ +#define IEEE80211_ERP_CHANGE_PROTECTION (1<<0) /* protection flag changed */ +#define IEEE80211_ERP_CHANGE_PREAMBLE (1<<1) /* barker preamble mode changed */ + /* Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), * bursting) for a hardware TX queue. * queue = IEEE80211_TX_QUEUE_*. diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index f811a260ee9c..4715a9525918 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -464,8 +464,10 @@ static int ieee80211_open(struct net_device *dev) if (sdata->type == IEEE80211_IF_TYPE_MNTR) { local->monitors++; local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - } else + } else { ieee80211_if_config(dev); + ieee80211_reset_erp_info(dev); + } if (sdata->type == IEEE80211_IF_TYPE_STA && !local->user_space_mlme) @@ -748,6 +750,27 @@ int ieee80211_hw_config(struct ieee80211_local *local) return ret; } +void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (local->ops->erp_ie_changed) + local->ops->erp_ie_changed(local_to_hw(local), changes, + sdata->use_protection, + !sdata->short_preamble); +} + +void ieee80211_reset_erp_info(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + sdata->short_preamble = 0; + sdata->use_protection = 0; + ieee80211_erp_info_change_notify(dev, + IEEE80211_ERP_CHANGE_PROTECTION | + IEEE80211_ERP_CHANGE_PREAMBLE); +} + struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, struct dev_mc_list *prev, void **ptr) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b0af6e9f5319..cc9999cd089c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -788,6 +788,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, u8 *addr); int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason); int ieee80211_sta_disassociate(struct net_device *dev, u16 reason); +void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes); +void ieee80211_reset_erp_info(struct net_device *dev); /* ieee80211_iface.c */ int ieee80211_if_add(struct net_device *dev, const char *name, diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 8292431ac48f..1fde214faecb 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1054,17 +1054,21 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: - if (sdata->type != IEEE80211_IF_TYPE_AP) + if (sdata->type == IEEE80211_IF_TYPE_AP) { + sdata->use_protection = !!value; + ieee80211_erp_info_change_notify(dev, IEEE80211_ERP_CHANGE_PROTECTION); + } else { ret = -ENOENT; - else - sdata->use_protection = value; + } break; case PRISM2_PARAM_PREAMBLE: - if (sdata->type != IEEE80211_IF_TYPE_AP) + if (sdata->type != IEEE80211_IF_TYPE_AP) { + sdata->short_preamble = !!value; + ieee80211_erp_info_change_notify(dev, IEEE80211_ERP_CHANGE_PREAMBLE); + } else { ret = -ENOENT; - else - sdata->short_preamble = value; + } break; case PRISM2_PARAM_STAT_TIME: diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 0f5f8131bd71..33414f160538 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -319,6 +319,7 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) struct ieee80211_if_sta *ifsta = &sdata->u.sta; int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; + u8 changes = 0; if (use_protection != sdata->use_protection) { if (net_ratelimit()) { @@ -329,6 +330,7 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) MAC_ARG(ifsta->bssid)); } sdata->use_protection = use_protection; + changes |= IEEE80211_ERP_CHANGE_PROTECTION; } if (!preamble_mode != sdata->short_preamble) { @@ -341,7 +343,11 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) MAC_ARG(ifsta->bssid)); } sdata->short_preamble = !preamble_mode; + changes |= IEEE80211_ERP_CHANGE_PREAMBLE; } + + if (changes) + ieee80211_erp_info_change_notify(dev, changes); } @@ -400,7 +406,6 @@ static void ieee80211_set_associated(struct net_device *dev, struct ieee80211_if_sta *ifsta, int assoc) { union iwreq_data wrqu; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (ifsta->associated == assoc) return; @@ -428,8 +433,7 @@ static void ieee80211_set_associated(struct net_device *dev, ieee80211_sta_send_associnfo(dev, ifsta); } else { netif_carrier_off(dev); - sdata->short_preamble = 0; - sdata->use_protection = 0; + ieee80211_reset_erp_info(dev); memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); } wrqu.ap_addr.sa_family = ARPHRD_ETHER; From 0ec0b7ac3cdfb8635d75aead5733f7a424ea4ad3 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Fri, 27 Jul 2007 15:43:24 +0200 Subject: [PATCH 1026/2804] [MAC80211]: use more GFP_KERNEL instead of GFP_ATOMIC This patch replaces atomic allocations with regular ones where possible. Merged with "revert some GFP_ATOMIC -> GFP_KERNEL changes" from Michael Wu: > Some of the allocations made with GFP_ATOMIC really were necessary. Signed-off-by: Michael Wu Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 33414f160538..f43c39f11223 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -363,7 +363,7 @@ static void ieee80211_sta_send_associnfo(struct net_device *dev, return; buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + - ifsta->assocresp_ies_len), GFP_ATOMIC); + ifsta->assocresp_ies_len), GFP_KERNEL); if (!buf) return; @@ -644,7 +644,7 @@ static void ieee80211_send_assoc(struct net_device *dev, kfree(ifsta->assocreq_ies); ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; - ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_ATOMIC); + ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); if (ifsta->assocreq_ies) memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); @@ -1244,7 +1244,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, kfree(ifsta->assocresp_ies); ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); - ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_ATOMIC); + ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); if (ifsta->assocresp_ies) memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); @@ -1254,7 +1254,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, sta = sta_info_get(local, ifsta->bssid); if (!sta) { struct ieee80211_sta_bss *bss; - sta = sta_info_add(local, dev, ifsta->bssid, GFP_ATOMIC); + sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); if (!sta) { printk(KERN_DEBUG "%s: failed to add STA entry for the" " AP\n", dev->name); @@ -1771,7 +1771,7 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, } /* Reply with ProbeResp */ - skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC); + skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); if (!skb) return; From dfe6e81deaa79c85086c0cc8d85b229e444ab97f Mon Sep 17 00:00:00 2001 From: Andy Green Date: Fri, 27 Jul 2007 15:43:24 +0200 Subject: [PATCH 1027/2804] [MAC80211]: Add get_unaligned to ieee80211_get_radiotap_len ieee80211_get_radiotap_len() tries to dereference radiotap length without taking care that it is completely unaligned and get_unaligned() is required. Signed-off-by: Andy Green Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- include/net/ieee80211_radiotap.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index 22e047758ba1..dfd8bf66ce27 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -40,6 +40,7 @@ #include #include +#include /* Radiotap header version (from official NetBSD feed) */ #define IEEE80211RADIOTAP_VERSION "1.5" @@ -261,7 +262,7 @@ static inline int ieee80211_get_radiotap_len(unsigned char *data) struct ieee80211_radiotap_header *hdr = (struct ieee80211_radiotap_header *)data; - return le16_to_cpu(hdr->it_len); + return le16_to_cpu(get_unaligned(&hdr->it_len)); } #endif /* IEEE80211_RADIOTAP_H */ From 9b8a74e3482f9fc077a88c13fa0ceca8feb0b772 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Fri, 27 Jul 2007 15:43:24 +0200 Subject: [PATCH 1028/2804] [MAC80211]: Improve sanity checks on injected packets Michael Wu noticed that the skb length checking is not taken care of enough when a packet is presented on the Monitor interface for injection. This patch improves the sanity checking and removes fake offsets placed into the skb network and transport header. Signed-off-by: Andy Green Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/tx.c | 48 +++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 36761c7139bc..457166889cc7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1270,46 +1270,54 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct ieee80211_tx_packet_data *pkt_data; struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; - u16 len; + u16 len_rthdr; - /* - * there must be a radiotap header at the - * start in this case - */ - if (unlikely(prthdr->it_version)) { - /* only version 0 is supported */ - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } + /* check for not even having the fixed radiotap header part */ + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; /* too short to be possibly valid */ + + /* is it a header version we can trust to find length from? */ + if (unlikely(prthdr->it_version)) + goto fail; /* only version 0 is supported */ + + /* then there must be a radiotap header with a length we can use */ + len_rthdr = ieee80211_get_radiotap_len(skb->data); + + /* does the skb contain enough to deliver on the alleged length? */ + if (unlikely(skb->len < len_rthdr)) + goto fail; /* skb too short for claimed rt header extent */ skb->dev = local->mdev; pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(pkt_data, 0, sizeof(*pkt_data)); + /* needed because we set skb device to master */ pkt_data->ifindex = dev->ifindex; + pkt_data->mgmt_iface = 0; pkt_data->do_not_encrypt = 1; - /* above needed because we set skb device to master */ - /* * fix up the pointers accounting for the radiotap * header still being in there. We are being given * a precooked IEEE80211 header so no need for * normal processing */ - len = le16_to_cpu(get_unaligned(&prthdr->it_len)); - skb_set_mac_header(skb, len); - skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr)); - skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr)); - + skb_set_mac_header(skb, len_rthdr); /* - * pass the radiotap header up to - * the next stage intact + * these are just fixed to the end of the rt area since we + * don't have any better information and at this point, nobody cares */ - dev_queue_xmit(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); return NETDEV_TX_OK; + +fail: + dev_kfree_skb(skb); + return NETDEV_TX_OK; /* meaning, we dealt with the skb */ } /** From 1bec3f1a3ec5d922d1040c7845b82cd496c02d90 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Jul 2007 15:43:24 +0200 Subject: [PATCH 1029/2804] [MAC80211]: fix add_interface monitor mode behaviour This makes it behave the same whether we have monitor during operation or not. Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 4715a9525918..5fc240259f55 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -425,7 +425,10 @@ static int ieee80211_open(struct net_device *dev) conf.if_id = dev->ifindex; conf.type = sdata->type; - conf.mac_addr = dev->dev_addr; + if (sdata->type == IEEE80211_IF_TYPE_MNTR) + conf.mac_addr = NULL; + else + conf.mac_addr = dev->dev_addr; res = local->ops->add_interface(local_to_hw(local), &conf); if (res) { if (sdata->type == IEEE80211_IF_TYPE_MNTR) From 744b096e2b0976a10ae9a66aa6a3ae7fa4fce9f1 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sun, 22 Jul 2007 12:43:32 +0200 Subject: [PATCH 1030/2804] [WIRELESS]: Use type safe netlink interface Makes use of the type safe netlink interface and adds a warning if the message is too big for NLMSG_DEFAULT_SIZE to help debug. Signed-off-by: Thomas Graf Signed-off-by: John W. Linville --- net/wireless/wext.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/net/wireless/wext.c b/net/wireless/wext.c index d6aaf65192e9..debf5191a128 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -1129,10 +1129,12 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, { struct ifinfomsg *r; struct nlmsghdr *nlh; - unsigned char *b = skb_tail_pointer(skb); - nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); - r = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0); + if (nlh == NULL) + return -EMSGSIZE; + + r = nlmsg_data(nlh); r->ifi_family = AF_UNSPEC; r->__ifi_pad = 0; r->ifi_type = dev->type; @@ -1141,15 +1143,13 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, r->ifi_change = 0; /* Wireless changes don't affect those flags */ /* Add the wireless events in the netlink packet */ - RTA_PUT(skb, IFLA_WIRELESS, event_len, event); + NLA_PUT(skb, IFLA_WIRELESS, event_len, event); - nlh->nlmsg_len = skb_tail_pointer(skb) - b; - return skb->len; + return nlmsg_end(skb, nlh); -nlmsg_failure: -rtattr_failure: - nlmsg_trim(skb, b); - return -1; +nla_put_failure: + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } /* ---------------------------------------------------------------- */ @@ -1162,17 +1162,19 @@ rtattr_failure: static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) { struct sk_buff *skb; - int size = NLMSG_GOODSIZE; + int err; - skb = alloc_skb(size, GFP_ATOMIC); + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!skb) return; - if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, - event, event_len) < 0) { + 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(&wireless_nlevent_queue, skb); tasklet_schedule(&wireless_nlevent_tasklet); From fe6aa301c747e0eca140428426e065657b6ab412 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 10 Aug 2007 11:23:20 -0500 Subject: [PATCH 1031/2804] [MAC80211]: Add SIOCGIWTXPOWER routine The wireless extensions ioctl's implemented in mac80211 do not include SIOCGIWTXPOWER. This patch adds the necessary code. Acked-by: Michael Buesch Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- net/mac80211/ieee80211_ioctl.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 1fde214faecb..0e88564e524a 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -798,6 +798,20 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, return 0; } +static int ieee80211_ioctl_giwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + data->txpower.fixed = 1; + data->txpower.disabled = !(local->hw.conf.radio_enabled); + data->txpower.value = local->hw.conf.power_level; + data->txpower.flags = IW_TXPOW_DBM; + + return 0; +} + static int ieee80211_ioctl_siwrts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) @@ -1587,7 +1601,7 @@ static const iw_handler ieee80211_handler[] = (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ From dde4e47e8fe333a5649a3fa0e7db1fa7c08d6158 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Aug 2007 14:04:30 +0200 Subject: [PATCH 1032/2804] [WIRELESS] radiotap parser: accept all other fields This makes the radiotap parser accept all other fields that are currently defined. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/radiotap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index 68c11d099917..28fbd0b0b568 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c @@ -161,7 +161,11 @@ int ieee80211_radiotap_iterator_next( [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, [IEEE80211_RADIOTAP_ANTENNA] = 0x11, [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, - [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11 + [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, + [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, + [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, + [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, + [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, /* * add more here as they are defined in * include/net/ieee80211_radiotap.h From bea3348eef27e6044b6161fd04c3152215f96411 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 3 Oct 2007 16:41:36 -0700 Subject: [PATCH 1033/2804] [NET]: Make NAPI polling independent of struct net_device objects. Several devices have multiple independant RX queues per net device, and some have a single interrupt doorbell for several queues. In either case, it's easier to support layouts like that if the structure representing the poll is independant from the net device itself. The signature of the ->poll() call back goes from: int foo_poll(struct net_device *dev, int *budget) to int foo_poll(struct napi_struct *napi, int budget) The caller is returned the number of RX packets processed (or the number of "NAPI credits" consumed if you want to get abstract). The callee no longer messes around bumping dev->quota, *budget, etc. because that is all handled in the caller upon return. The napi_struct is to be embedded in the device driver private data structures. Furthermore, it is the driver's responsibility to disable all NAPI instances in it's ->stop() device close handler. Since the napi_struct is privatized into the driver's private data structures, only the driver knows how to get at all of the napi_struct instances it may have per-device. With lots of help and suggestions from Rusty Russell, Roland Dreier, Michael Chan, Jeff Garzik, and Jamal Hadi Salim. Bug fixes from Thomas Graf, Roland Dreier, Peter Zijlstra, Joseph Fannin, Scott Wood, Hans J. Koch, and Michael Chan. [ Ported to current tree and all drivers converted. Integrated Stephen's follow-on kerneldoc additions, and restored poll_list handling to the old style to fix mutual exclusion issues. -DaveM ] Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/DocBook/kernel-api.tmpl | 12 +- Documentation/networking/NAPI_HOWTO.txt | 766 ---------------------- Documentation/networking/netdevices.txt | 12 +- drivers/infiniband/ulp/ipoib/ipoib.h | 4 +- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 43 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 11 +- drivers/net/8139cp.c | 41 +- drivers/net/8139too.c | 48 +- drivers/net/amd8111e.c | 30 +- drivers/net/amd8111e.h | 2 + drivers/net/arm/ep93xx_eth.c | 70 +- drivers/net/b44.c | 48 +- drivers/net/b44.h | 2 + drivers/net/bnx2.c | 47 +- drivers/net/bnx2.h | 2 + drivers/net/cassini.c | 40 +- drivers/net/cassini.h | 2 + drivers/net/chelsio/common.h | 1 + drivers/net/chelsio/cxgb2.c | 9 +- drivers/net/chelsio/sge.c | 29 +- drivers/net/chelsio/sge.h | 2 +- drivers/net/cxgb3/adapter.h | 22 +- drivers/net/cxgb3/cxgb3_main.c | 96 +-- drivers/net/cxgb3/sge.c | 170 ++--- drivers/net/e100.c | 37 +- drivers/net/e1000/e1000.h | 1 + drivers/net/e1000/e1000_main.c | 45 +- drivers/net/ehea/ehea.h | 2 +- drivers/net/ehea/ehea_main.c | 129 ++-- drivers/net/epic100.c | 36 +- drivers/net/fec_8xx/fec_8xx.h | 2 + drivers/net/fec_8xx/fec_main.c | 59 +- drivers/net/forcedeth.c | 69 +- drivers/net/fs_enet/fs_enet-main.c | 55 +- drivers/net/fs_enet/fs_enet.h | 1 + drivers/net/gianfar.c | 47 +- drivers/net/gianfar.h | 3 + drivers/net/ibmveth.c | 125 ++-- drivers/net/ibmveth.h | 1 + drivers/net/ixgb/ixgb.h | 1 + drivers/net/ixgb/ixgb_main.c | 29 +- drivers/net/ixp2000/ixpdev.c | 39 +- drivers/net/ixp2000/ixpdev.h | 2 + drivers/net/macb.c | 40 +- drivers/net/macb.h | 1 + drivers/net/mv643xx_eth.c | 48 +- drivers/net/mv643xx_eth.h | 2 + drivers/net/myri10ge/myri10ge.c | 40 +- drivers/net/natsemi.c | 42 +- drivers/net/netxen/netxen_nic.h | 1 + drivers/net/netxen/netxen_nic_main.c | 39 +- drivers/net/pasemi_mac.c | 36 +- drivers/net/pasemi_mac.h | 1 + drivers/net/pcnet32.c | 84 ++- drivers/net/ps3_gelic_net.c | 45 +- drivers/net/ps3_gelic_net.h | 1 + drivers/net/qla3xxx.c | 29 +- drivers/net/qla3xxx.h | 2 + drivers/net/r8169.c | 58 +- drivers/net/s2io.c | 35 +- drivers/net/s2io.h | 3 +- drivers/net/sb1250-mac.c | 47 +- drivers/net/sis190.c | 19 +- drivers/net/skge.c | 44 +- drivers/net/skge.h | 1 + drivers/net/sky2.c | 94 ++- drivers/net/sky2.h | 1 + drivers/net/spider_net.c | 58 +- drivers/net/spider_net.h | 2 + drivers/net/starfire.c | 51 +- drivers/net/sungem.c | 52 +- drivers/net/sungem.h | 1 + drivers/net/tc35815.c | 49 +- drivers/net/tg3.c | 61 +- drivers/net/tg3.h | 1 + drivers/net/tsi108_eth.c | 40 +- drivers/net/tulip/interrupt.c | 54 +- drivers/net/tulip/tulip.h | 3 +- drivers/net/tulip/tulip_core.c | 11 +- drivers/net/typhoon.c | 47 +- drivers/net/ucc_geth.c | 64 +- drivers/net/ucc_geth.h | 1 + drivers/net/via-rhine.c | 42 +- drivers/net/xen-netfront.c | 33 +- include/linux/netdevice.h | 361 ++++++++-- include/linux/netpoll.h | 55 +- net/core/dev.c | 184 +++--- net/core/net-sysfs.c | 15 - net/core/netpoll.c | 39 +- net/core/rtnetlink.c | 6 - net/sched/sch_generic.c | 12 + 91 files changed, 1765 insertions(+), 2382 deletions(-) delete mode 100644 Documentation/networking/NAPI_HOWTO.txt diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index b886f52a9aac..e5da4f2b7c22 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -240,17 +240,23 @@ X!Ilib/string.c Driver Support !Enet/core/dev.c !Enet/ethernet/eth.c +!Enet/sched/sch_generic.c !Iinclude/linux/etherdevice.h +!Iinclude/linux/netdevice.h + + PHY Support !Edrivers/net/phy/phy.c !Idrivers/net/phy/phy.c !Edrivers/net/phy/phy_device.c !Idrivers/net/phy/phy_device.c !Edrivers/net/phy/mdio_bus.c !Idrivers/net/phy/mdio_bus.c - + Synchronous PPP !Edrivers/net/wan/syncppp.c diff --git a/Documentation/networking/NAPI_HOWTO.txt b/Documentation/networking/NAPI_HOWTO.txt deleted file mode 100644 index 7907435a661c..000000000000 --- a/Documentation/networking/NAPI_HOWTO.txt +++ /dev/null @@ -1,766 +0,0 @@ -HISTORY: -February 16/2002 -- revision 0.2.1: -COR typo corrected -February 10/2002 -- revision 0.2: -some spell checking ;-> -January 12/2002 -- revision 0.1 -This is still work in progress so may change. -To keep up to date please watch this space. - -Introduction to NAPI -==================== - -NAPI is a proven (www.cyberus.ca/~hadi/usenix-paper.tgz) technique -to improve network performance on Linux. For more details please -read that paper. -NAPI provides a "inherent mitigation" which is bound by system capacity -as can be seen from the following data collected by Robert on Gigabit -ethernet (e1000): - - Psize Ipps Tput Rxint Txint Done Ndone - --------------------------------------------------------------- - 60 890000 409362 17 27622 7 6823 - 128 758150 464364 21 9301 10 7738 - 256 445632 774646 42 15507 21 12906 - 512 232666 994445 241292 19147 241192 1062 - 1024 119061 1000003 872519 19258 872511 0 - 1440 85193 1000003 946576 19505 946569 0 - - -Legend: -"Ipps" stands for input packets per second. -"Tput" == packets out of total 1M that made it out. -"txint" == transmit completion interrupts seen -"Done" == The number of times that the poll() managed to pull all -packets out of the rx ring. Note from this that the lower the -load the more we could clean up the rxring -"Ndone" == is the converse of "Done". Note again, that the higher -the load the more times we couldn't clean up the rxring. - -Observe that: -when the NIC receives 890Kpackets/sec only 17 rx interrupts are generated. -The system cant handle the processing at 1 interrupt/packet at that load level. -At lower rates on the other hand, rx interrupts go up and therefore the -interrupt/packet ratio goes up (as observable from that table). So there is -possibility that under low enough input, you get one poll call for each -input packet caused by a single interrupt each time. And if the system -cant handle interrupt per packet ratio of 1, then it will just have to -chug along .... - - -0) Prerequisites: -================== -A driver MAY continue using the old 2.4 technique for interfacing -to the network stack and not benefit from the NAPI changes. -NAPI additions to the kernel do not break backward compatibility. -NAPI, however, requires the following features to be available: - -A) DMA ring or enough RAM to store packets in software devices. - -B) Ability to turn off interrupts or maybe events that send packets up -the stack. - -NAPI processes packet events in what is known as dev->poll() method. -Typically, only packet receive events are processed in dev->poll(). -The rest of the events MAY be processed by the regular interrupt handler -to reduce processing latency (justified also because there are not that -many of them). -Note, however, NAPI does not enforce that dev->poll() only processes -receive events. -Tests with the tulip driver indicated slightly increased latency if -all of the interrupt handler is moved to dev->poll(). Also MII handling -gets a little trickier. -The example used in this document is to move the receive processing only -to dev->poll(); this is shown with the patch for the tulip driver. -For an example of code that moves all the interrupt driver to -dev->poll() look at the ported e1000 code. - -There are caveats that might force you to go with moving everything to -dev->poll(). Different NICs work differently depending on their status/event -acknowledgement setup. -There are two types of event register ACK mechanisms. - I) what is known as Clear-on-read (COR). - when you read the status/event register, it clears everything! - The natsemi and sunbmac NICs are known to do this. - In this case your only choice is to move all to dev->poll() - - II) Clear-on-write (COW) - i) you clear the status by writing a 1 in the bit-location you want. - These are the majority of the NICs and work the best with NAPI. - Put only receive events in dev->poll(); leave the rest in - the old interrupt handler. - ii) whatever you write in the status register clears every thing ;-> - Cant seem to find any supported by Linux which do this. If - someone knows such a chip email us please. - Move all to dev->poll() - -C) Ability to detect new work correctly. -NAPI works by shutting down event interrupts when there's work and -turning them on when there's none. -New packets might show up in the small window while interrupts were being -re-enabled (refer to appendix 2). A packet might sneak in during the period -we are enabling interrupts. We only get to know about such a packet when the -next new packet arrives and generates an interrupt. -Essentially, there is a small window of opportunity for a race condition -which for clarity we'll refer to as the "rotting packet". - -This is a very important topic and appendix 2 is dedicated for more -discussion. - -Locking rules and environmental guarantees -========================================== - --Guarantee: Only one CPU at any time can call dev->poll(); this is because -only one CPU can pick the initial interrupt and hence the initial -netif_rx_schedule(dev); -- The core layer invokes devices to send packets in a round robin format. -This implies receive is totally lockless because of the guarantee that only -one CPU is executing it. -- contention can only be the result of some other CPU accessing the rx -ring. This happens only in close() and suspend() (when these methods -try to clean the rx ring); -****guarantee: driver authors need not worry about this; synchronization -is taken care for them by the top net layer. --local interrupts are enabled (if you dont move all to dev->poll()). For -example link/MII and txcomplete continue functioning just same old way. -This improves the latency of processing these events. It is also assumed that -the receive interrupt is the largest cause of noise. Note this might not -always be true. -[according to Manfred Spraul, the winbond insists on sending one -txmitcomplete interrupt for each packet (although this can be mitigated)]. -For these broken drivers, move all to dev->poll(). - -For the rest of this text, we'll assume that dev->poll() only -processes receive events. - -new methods introduce by NAPI -============================= - -a) netif_rx_schedule(dev) -Called by an IRQ handler to schedule a poll for device - -b) netif_rx_schedule_prep(dev) -puts the device in a state which allows for it to be added to the -CPU polling list if it is up and running. You can look at this as -the first half of netif_rx_schedule(dev) above; the second half -being c) below. - -c) __netif_rx_schedule(dev) -Add device to the poll list for this CPU; assuming that _prep above -has already been called and returned 1. - -d) netif_rx_reschedule(dev, undo) -Called to reschedule polling for device specifically for some -deficient hardware. Read Appendix 2 for more details. - -e) netif_rx_complete(dev) - -Remove interface from the CPU poll list: it must be in the poll list -on current cpu. This primitive is called by dev->poll(), when -it completes its work. The device cannot be out of poll list at this -call, if it is then clearly it is a BUG(). You'll know ;-> - -All of the above methods are used below, so keep reading for clarity. - -Device driver changes to be made when porting NAPI -================================================== - -Below we describe what kind of changes are required for NAPI to work. - -1) introduction of dev->poll() method -===================================== - -This is the method that is invoked by the network core when it requests -for new packets from the driver. A driver is allowed to send upto -dev->quota packets by the current CPU before yielding to the network -subsystem (so other devices can also get opportunity to send to the stack). - -dev->poll() prototype looks as follows: -int my_poll(struct net_device *dev, int *budget) - -budget is the remaining number of packets the network subsystem on the -current CPU can send up the stack before yielding to other system tasks. -*Each driver is responsible for decrementing budget by the total number of -packets sent. - Total number of packets cannot exceed dev->quota. - -dev->poll() method is invoked by the top layer, the driver just sends if it -can to the stack the packet quantity requested. - -more on dev->poll() below after the interrupt changes are explained. - -2) registering dev->poll() method -=================================== - -dev->poll should be set in the dev->probe() method. -e.g: -dev->open = my_open; -. -. -/* two new additions */ -/* first register my poll method */ -dev->poll = my_poll; -/* next register my weight/quanta; can be overridden in /proc */ -dev->weight = 16; -. -. -dev->stop = my_close; - - - -3) scheduling dev->poll() -============================= -This involves modifying the interrupt handler and the code -path which takes the packet off the NIC and sends them to the -stack. - -it's important at this point to introduce the classical D Becker -interrupt processor: - ------------------- -static irqreturn_t -netdevice_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - - struct net_device *dev = (struct net_device *)dev_instance; - struct my_private *tp = (struct my_private *)dev->priv; - - int work_count = my_work_count; - status = read_interrupt_status_reg(); - if (status == 0) - return IRQ_NONE; /* Shared IRQ: not us */ - if (status == 0xffff) - return IRQ_HANDLED; /* Hot unplug */ - if (status & error) - do_some_error_handling() - - do { - acknowledge_ints_ASAP(); - - if (status & link_interrupt) { - spin_lock(&tp->link_lock); - do_some_link_stat_stuff(); - spin_lock(&tp->link_lock); - } - - if (status & rx_interrupt) { - receive_packets(dev); - } - - if (status & rx_nobufs) { - make_rx_buffs_avail(); - } - - if (status & tx_related) { - spin_lock(&tp->lock); - tx_ring_free(dev); - if (tx_died) - restart_tx(); - spin_unlock(&tp->lock); - } - - status = read_interrupt_status_reg(); - - } while (!(status & error) || more_work_to_be_done); - return IRQ_HANDLED; -} - ----------------------------------------------------------------------- - -We now change this to what is shown below to NAPI-enable it: - ----------------------------------------------------------------------- -static irqreturn_t -netdevice_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct my_private *tp = (struct my_private *)dev->priv; - - status = read_interrupt_status_reg(); - if (status == 0) - return IRQ_NONE; /* Shared IRQ: not us */ - if (status == 0xffff) - return IRQ_HANDLED; /* Hot unplug */ - if (status & error) - do_some_error_handling(); - - do { -/************************ start note *********************************/ - acknowledge_ints_ASAP(); // dont ack rx and rxnobuff here -/************************ end note *********************************/ - - if (status & link_interrupt) { - spin_lock(&tp->link_lock); - do_some_link_stat_stuff(); - spin_unlock(&tp->link_lock); - } -/************************ start note *********************************/ - if (status & rx_interrupt || (status & rx_nobuffs)) { - if (netif_rx_schedule_prep(dev)) { - - /* disable interrupts caused - * by arriving packets */ - disable_rx_and_rxnobuff_ints(); - /* tell system we have work to be done. */ - __netif_rx_schedule(dev); - } else { - printk("driver bug! interrupt while in poll\n"); - /* FIX by disabling interrupts */ - disable_rx_and_rxnobuff_ints(); - } - } -/************************ end note note *********************************/ - - if (status & tx_related) { - spin_lock(&tp->lock); - tx_ring_free(dev); - - if (tx_died) - restart_tx(); - spin_unlock(&tp->lock); - } - - status = read_interrupt_status_reg(); - -/************************ start note *********************************/ - } while (!(status & error) || more_work_to_be_done(status)); -/************************ end note note *********************************/ - return IRQ_HANDLED; -} - ---------------------------------------------------------------------- - - -We note several things from above: - -I) Any interrupt source which is caused by arriving packets is now -turned off when it occurs. Depending on the hardware, there could be -several reasons that arriving packets would cause interrupts; these are the -interrupt sources we wish to avoid. The two common ones are a) a packet -arriving (rxint) b) a packet arriving and finding no DMA buffers available -(rxnobuff) . -This means also acknowledge_ints_ASAP() will not clear the status -register for those two items above; clearing is done in the place where -proper work is done within NAPI; at the poll() and refill_rx_ring() -discussed further below. -netif_rx_schedule_prep() returns 1 if device is in running state and -gets successfully added to the core poll list. If we get a zero value -we can _almost_ assume are already added to the list (instead of not running. -Logic based on the fact that you shouldn't get interrupt if not running) -We rectify this by disabling rx and rxnobuf interrupts. - -II) that receive_packets(dev) and make_rx_buffs_avail() may have disappeared. -These functionalities are still around actually...... - -infact, receive_packets(dev) is very close to my_poll() and -make_rx_buffs_avail() is invoked from my_poll() - -4) converting receive_packets() to dev->poll() -=============================================== - -We need to convert the classical D Becker receive_packets(dev) to my_poll() - -First the typical receive_packets() below: -------------------------------------------------------------------- - -/* this is called by interrupt handler */ -static void receive_packets (struct net_device *dev) -{ - - struct my_private *tp = (struct my_private *)dev->priv; - rx_ring = tp->rx_ring; - cur_rx = tp->cur_rx; - int entry = cur_rx % RX_RING_SIZE; - int received = 0; - int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; - - while (rx_ring_not_empty) { - u32 rx_status; - unsigned int rx_size; - unsigned int pkt_size; - struct sk_buff *skb; - /* read size+status of next frame from DMA ring buffer */ - /* the number 16 and 4 are just examples */ - rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); - rx_size = rx_status >> 16; - pkt_size = rx_size - 4; - - /* process errors */ - if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || - (!(rx_status & RxStatusOK))) { - netdrv_rx_err (rx_status, dev, tp, ioaddr); - return; - } - - if (--rx_work_limit < 0) - break; - - /* grab a skb */ - skb = dev_alloc_skb (pkt_size + 2); - if (skb) { - . - . - netif_rx (skb); - . - . - } else { /* OOM */ - /*seems very driver specific ... some just pass - whatever is on the ring already. */ - } - - /* move to the next skb on the ring */ - entry = (++tp->cur_rx) % RX_RING_SIZE; - received++ ; - - } - - /* store current ring pointer state */ - tp->cur_rx = cur_rx; - - /* Refill the Rx ring buffers if they are needed */ - refill_rx_ring(); - . - . - -} -------------------------------------------------------------------- -We change it to a new one below; note the additional parameter in -the call. - -------------------------------------------------------------------- - -/* this is called by the network core */ -static int my_poll (struct net_device *dev, int *budget) -{ - - struct my_private *tp = (struct my_private *)dev->priv; - rx_ring = tp->rx_ring; - cur_rx = tp->cur_rx; - int entry = cur_rx % RX_BUF_LEN; - /* maximum packets to send to the stack */ -/************************ note note *********************************/ - int rx_work_limit = dev->quota; - -/************************ end note note *********************************/ - do { // outer beginning loop starts here - - clear_rx_status_register_bit(); - - while (rx_ring_not_empty) { - u32 rx_status; - unsigned int rx_size; - unsigned int pkt_size; - struct sk_buff *skb; - /* read size+status of next frame from DMA ring buffer */ - /* the number 16 and 4 are just examples */ - rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); - rx_size = rx_status >> 16; - pkt_size = rx_size - 4; - - /* process errors */ - if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || - (!(rx_status & RxStatusOK))) { - netdrv_rx_err (rx_status, dev, tp, ioaddr); - return 1; - } - -/************************ note note *********************************/ - if (--rx_work_limit < 0) { /* we got packets, but no quota */ - /* store current ring pointer state */ - tp->cur_rx = cur_rx; - - /* Refill the Rx ring buffers if they are needed */ - refill_rx_ring(dev); - goto not_done; - } -/********************** end note **********************************/ - - /* grab a skb */ - skb = dev_alloc_skb (pkt_size + 2); - if (skb) { - . - . -/************************ note note *********************************/ - netif_receive_skb (skb); -/********************** end note **********************************/ - . - . - } else { /* OOM */ - /*seems very driver specific ... common is just pass - whatever is on the ring already. */ - } - - /* move to the next skb on the ring */ - entry = (++tp->cur_rx) % RX_RING_SIZE; - received++ ; - - } - - /* store current ring pointer state */ - tp->cur_rx = cur_rx; - - /* Refill the Rx ring buffers if they are needed */ - refill_rx_ring(dev); - - /* no packets on ring; but new ones can arrive since we last - checked */ - status = read_interrupt_status_reg(); - if (rx status is not set) { - /* If something arrives in this narrow window, - an interrupt will be generated */ - goto done; - } - /* done! at least that's what it looks like ;-> - if new packets came in after our last check on status bits - they'll be caught by the while check and we go back and clear them - since we havent exceeded our quota */ - } while (rx_status_is_set); - -done: - -/************************ note note *********************************/ - dev->quota -= received; - *budget -= received; - - /* If RX ring is not full we are out of memory. */ - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - goto oom; - - /* we are happy/done, no more packets on ring; put us back - to where we can start processing interrupts again */ - netif_rx_complete(dev); - enable_rx_and_rxnobuf_ints(); - - /* The last op happens after poll completion. Which means the following: - * 1. it can race with disabling irqs in irq handler (which are done to - * schedule polls) - * 2. it can race with dis/enabling irqs in other poll threads - * 3. if an irq raised after the beginning of the outer beginning - * loop (marked in the code above), it will be immediately - * triggered here. - * - * Summarizing: the logic may result in some redundant irqs both - * due to races in masking and due to too late acking of already - * processed irqs. The good news: no events are ever lost. - */ - - return 0; /* done */ - -not_done: - if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || - tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - refill_rx_ring(dev); - - if (!received) { - printk("received==0\n"); - received = 1; - } - dev->quota -= received; - *budget -= received; - return 1; /* not_done */ - -oom: - /* Start timer, stop polling, but do not enable rx interrupts. */ - start_poll_timer(dev); - return 0; /* we'll take it from here so tell core "done"*/ - -/************************ End note note *********************************/ -} -------------------------------------------------------------------- - -From above we note that: -0) rx_work_limit = dev->quota -1) refill_rx_ring() is in charge of clearing the bit for rxnobuff when -it does the work. -2) We have a done and not_done state. -3) instead of netif_rx() we call netif_receive_skb() to pass the skb. -4) we have a new way of handling oom condition -5) A new outer for (;;) loop has been added. This serves the purpose of -ensuring that if a new packet has come in, after we are all set and done, -and we have not exceeded our quota that we continue sending packets up. - - ------------------------------------------------------------ -Poll timer code will need to do the following: - -a) - - if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || - tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - refill_rx_ring(dev); - - /* If RX ring is not full we are still out of memory. - Restart the timer again. Else we re-add ourselves - to the master poll list. - */ - - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - restart_timer(); - - else netif_rx_schedule(dev); /* we are back on the poll list */ - -5) dev->close() and dev->suspend() issues -========================================== -The driver writer needn't worry about this; the top net layer takes -care of it. - -6) Adding new Stats to /proc -============================= -In order to debug some of the new features, we introduce new stats -that need to be collected. -TODO: Fill this later. - -APPENDIX 1: discussion on using ethernet HW FC -============================================== -Most chips with FC only send a pause packet when they run out of Rx buffers. -Since packets are pulled off the DMA ring by a softirq in NAPI, -if the system is slow in grabbing them and we have a high input -rate (faster than the system's capacity to remove packets), then theoretically -there will only be one rx interrupt for all packets during a given packetstorm. -Under low load, we might have a single interrupt per packet. -FC should be programmed to apply in the case when the system cant pull out -packets fast enough i.e send a pause only when you run out of rx buffers. -Note FC in itself is a good solution but we have found it to not be -much of a commodity feature (both in NICs and switches) and hence falls -under the same category as using NIC based mitigation. Also, experiments -indicate that it's much harder to resolve the resource allocation -issue (aka lazy receiving that NAPI offers) and hence quantify its usefulness -proved harder. In any case, FC works even better with NAPI but is not -necessary. - - -APPENDIX 2: the "rotting packet" race-window avoidance scheme -============================================================= - -There are two types of associations seen here - -1) status/int which honors level triggered IRQ - -If a status bit for receive or rxnobuff is set and the corresponding -interrupt-enable bit is not on, then no interrupts will be generated. However, -as soon as the "interrupt-enable" bit is unmasked, an immediate interrupt is -generated. [assuming the status bit was not turned off]. -Generally the concept of level triggered IRQs in association with a status and -interrupt-enable CSR register set is used to avoid the race. - -If we take the example of the tulip: -"pending work" is indicated by the status bit(CSR5 in tulip). -the corresponding interrupt bit (CSR7 in tulip) might be turned off (but -the CSR5 will continue to be turned on with new packet arrivals even if -we clear it the first time) -Very important is the fact that if we turn on the interrupt bit on when -status is set that an immediate irq is triggered. - -If we cleared the rx ring and proclaimed there was "no more work -to be done" and then went on to do a few other things; then when we enable -interrupts, there is a possibility that a new packet might sneak in during -this phase. It helps to look at the pseudo code for the tulip poll -routine: - --------------------------- - do { - ACK; - while (ring_is_not_empty()) { - work-work-work - if quota is exceeded: exit, no touching irq status/mask - } - /* No packets, but new can arrive while we are doing this*/ - CSR5 := read - if (CSR5 is not set) { - /* If something arrives in this narrow window here, - * where the comments are ;-> irq will be generated */ - unmask irqs; - exit poll; - } - } while (rx_status_is_set); ------------------------- - -CSR5 bit of interest is only the rx status. -If you look at the last if statement: -you just finished grabbing all the packets from the rx ring .. you check if -status bit says there are more packets just in ... it says none; you then -enable rx interrupts again; if a new packet just came in during this check, -we are counting that CSR5 will be set in that small window of opportunity -and that by re-enabling interrupts, we would actually trigger an interrupt -to register the new packet for processing. - -[The above description nay be very verbose, if you have better wording -that will make this more understandable, please suggest it.] - -2) non-capable hardware - -These do not generally respect level triggered IRQs. Normally, -irqs may be lost while being masked and the only way to leave poll is to do -a double check for new input after netif_rx_complete() is invoked -and re-enable polling (after seeing this new input). - -Sample code: - ---------- - . - . -restart_poll: - while (ring_is_not_empty()) { - work-work-work - if quota is exceeded: exit, not touching irq status/mask - } - . - . - . - enable_rx_interrupts() - netif_rx_complete(dev); - if (ring_has_new_packet() && netif_rx_reschedule(dev, received)) { - disable_rx_and_rxnobufs() - goto restart_poll - } while (rx_status_is_set); ---------- - -Basically netif_rx_complete() removes us from the poll list, but because a -new packet which will never be caught due to the possibility of a race -might come in, we attempt to re-add ourselves to the poll list. - - - - -APPENDIX 3: Scheduling issues. -============================== -As seen NAPI moves processing to softirq level. Linux uses the ksoftirqd as the -general solution to schedule softirq's to run before next interrupt and by putting -them under scheduler control. Also this prevents consecutive softirq's from -monopolize the CPU. This also have the effect that the priority of ksoftirq needs -to be considered when running very CPU-intensive applications and networking to -get the proper balance of softirq/user balance. Increasing ksoftirq priority to 0 -(eventually more) is reported cure problems with low network performance at high -CPU load. - -Most used processes in a GIGE router: -USER PID %CPU %MEM SIZE RSS TTY STAT START TIME COMMAND -root 3 0.2 0.0 0 0 ? RWN Aug 15 602:00 (ksoftirqd_CPU0) -root 232 0.0 7.9 41400 40884 ? S Aug 15 74:12 gated - --------------------------------------------------------------------- - -relevant sites: -================== -ftp://robur.slu.se/pub/Linux/net-development/NAPI/ - - --------------------------------------------------------------------- -TODO: Write net-skeleton.c driver. -------------------------------------------------------------- - -Authors: -======== -Alexey Kuznetsov -Jamal Hadi Salim -Robert Olsson - -Acknowledgements: -================ -People who made this document better: - -Lennert Buytenhek -Andrew Morton -Manfred Spraul -Donald Becker -Jeff Garzik diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt index 37869295fc70..9f7be9b7785e 100644 --- a/Documentation/networking/netdevices.txt +++ b/Documentation/networking/netdevices.txt @@ -95,9 +95,13 @@ dev->set_multicast_list: Synchronization: netif_tx_lock spinlock. Context: BHs disabled -dev->poll: - Synchronization: __LINK_STATE_RX_SCHED bit in dev->state. See - dev_close code and comments in net/core/dev.c for more info. +struct napi_struct synchronization rules +======================================== +napi->poll: + Synchronization: NAPI_STATE_SCHED bit in napi->state. Device + driver's dev->close method will invoke napi_disable() on + all NAPI instances which will do a sleeping poll on the + NAPI_STATE_SCHED napi->state bit, waiting for all pending + NAPI activity to cease. Context: softirq will be called with interrupts disabled by netconsole. - diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 285c143115cc..35f3ca42bd60 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -228,6 +228,8 @@ struct ipoib_dev_priv { struct net_device *dev; + struct napi_struct napi; + unsigned long flags; struct mutex mcast_mutex; @@ -351,7 +353,7 @@ extern struct workqueue_struct *ipoib_workqueue; /* functions */ -int ipoib_poll(struct net_device *dev, int *budget); +int ipoib_poll(struct napi_struct *napi, int budget); void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr); struct ipoib_ah *ipoib_create_ah(struct net_device *dev, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 10944888cffd..481e4b6bd949 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -281,63 +281,58 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) wc->status, wr_id, wc->vendor_err); } -int ipoib_poll(struct net_device *dev, int *budget) +int ipoib_poll(struct napi_struct *napi, int budget) { - struct ipoib_dev_priv *priv = netdev_priv(dev); - int max = min(*budget, dev->quota); + struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi); + struct net_device *dev = priv->dev; int done; int t; - int empty; int n, i; done = 0; - empty = 0; - while (max) { +poll_more: + while (done < budget) { + int max = (budget - done); + t = min(IPOIB_NUM_WC, max); n = ib_poll_cq(priv->cq, t, priv->ibwc); - for (i = 0; i < n; ++i) { + for (i = 0; i < n; i++) { struct ib_wc *wc = priv->ibwc + i; if (wc->wr_id & IPOIB_CM_OP_SRQ) { ++done; - --max; ipoib_cm_handle_rx_wc(dev, wc); } else if (wc->wr_id & IPOIB_OP_RECV) { ++done; - --max; ipoib_ib_handle_rx_wc(dev, wc); } else ipoib_ib_handle_tx_wc(dev, wc); } - if (n != t) { - empty = 1; + if (n != t) break; - } } - dev->quota -= done; - *budget -= done; - - if (empty) { - netif_rx_complete(dev); + if (done < budget) { + netif_rx_complete(dev, napi); if (unlikely(ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)) && - netif_rx_reschedule(dev, 0)) - return 1; - - return 0; + netif_rx_reschedule(dev, napi)) + goto poll_more; } - return 1; + return done; } void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) { - netif_rx_schedule(dev_ptr); + struct net_device *dev = dev_ptr; + struct ipoib_dev_priv *priv = netdev_priv(dev); + + netif_rx_schedule(dev, &priv->napi); } static inline int post_send(struct ipoib_dev_priv *priv, @@ -577,7 +572,6 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush) int i; clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags); - netif_poll_disable(dev); ipoib_cm_dev_stop(dev); @@ -660,7 +654,6 @@ timeout: msleep(1); } - netif_poll_enable(dev); ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP); return 0; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 894b1dcdf3eb..a59ff07ec3cd 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -98,16 +98,20 @@ int ipoib_open(struct net_device *dev) ipoib_dbg(priv, "bringing up interface\n"); + napi_enable(&priv->napi); set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); if (ipoib_pkey_dev_delay_open(dev)) return 0; - if (ipoib_ib_dev_open(dev)) + if (ipoib_ib_dev_open(dev)) { + napi_disable(&priv->napi); return -EINVAL; + } if (ipoib_ib_dev_up(dev)) { ipoib_ib_dev_stop(dev, 1); + napi_disable(&priv->napi); return -EINVAL; } @@ -140,6 +144,7 @@ static int ipoib_stop(struct net_device *dev) ipoib_dbg(priv, "stopping interface\n"); clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); + napi_disable(&priv->napi); netif_stop_queue(dev); @@ -948,8 +953,8 @@ static void ipoib_setup(struct net_device *dev) dev->hard_header = ipoib_hard_header; dev->set_multicast_list = ipoib_set_mcast_list; dev->neigh_setup = ipoib_neigh_setup_dev; - dev->poll = ipoib_poll; - dev->weight = 100; + + netif_napi_add(dev, &priv->napi, ipoib_poll, 100); dev->watchdog_timeo = HZ; diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index a79f28c7a100..7f18ca23d9f8 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -334,6 +334,8 @@ struct cp_private { spinlock_t lock; u32 msg_enable; + struct napi_struct napi; + struct pci_dev *pdev; u32 rx_config; u16 cpcmd; @@ -501,12 +503,12 @@ static inline unsigned int cp_rx_csum_ok (u32 status) return 0; } -static int cp_rx_poll (struct net_device *dev, int *budget) +static int cp_rx_poll(struct napi_struct *napi, int budget) { - struct cp_private *cp = netdev_priv(dev); - unsigned rx_tail = cp->rx_tail; - unsigned rx_work = dev->quota; - unsigned rx; + struct cp_private *cp = container_of(napi, struct cp_private, napi); + struct net_device *dev = cp->dev; + unsigned int rx_tail = cp->rx_tail; + int rx; rx_status_loop: rx = 0; @@ -588,33 +590,28 @@ rx_next: desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); rx_tail = NEXT_RX(rx_tail); - if (!rx_work--) + if (rx >= budget) break; } cp->rx_tail = rx_tail; - dev->quota -= rx; - *budget -= rx; - /* if we did not reach work limit, then we're done with * this round of polling */ - if (rx_work) { + if (rx < budget) { unsigned long flags; if (cpr16(IntrStatus) & cp_rx_intr_mask) goto rx_status_loop; - local_irq_save(flags); + spin_lock_irqsave(&cp->lock, flags); cpw16_f(IntrMask, cp_intr_mask); - __netif_rx_complete(dev); - local_irq_restore(flags); - - return 0; /* done */ + __netif_rx_complete(dev, napi); + spin_unlock_irqrestore(&cp->lock, flags); } - return 1; /* not done */ + return rx; } static irqreturn_t cp_interrupt (int irq, void *dev_instance) @@ -647,9 +644,9 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) } if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &cp->napi)) { cpw16_f(IntrMask, cp_norx_intr_mask); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &cp->napi); } if (status & (TxOK | TxErr | TxEmpty | SWInt)) @@ -1175,6 +1172,8 @@ static int cp_open (struct net_device *dev) if (rc) return rc; + napi_enable(&cp->napi); + cp_init_hw(cp); rc = request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name, dev); @@ -1188,6 +1187,7 @@ static int cp_open (struct net_device *dev) return 0; err_out_hw: + napi_disable(&cp->napi); cp_stop_hw(cp); cp_free_rings(cp); return rc; @@ -1198,6 +1198,8 @@ static int cp_close (struct net_device *dev) struct cp_private *cp = netdev_priv(dev); unsigned long flags; + napi_disable(&cp->napi); + if (netif_msg_ifdown(cp)) printk(KERN_DEBUG "%s: disabling interface\n", dev->name); @@ -1933,11 +1935,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev->hard_start_xmit = cp_start_xmit; dev->get_stats = cp_get_stats; dev->do_ioctl = cp_ioctl; - dev->poll = cp_rx_poll; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = cp_poll_controller; #endif - dev->weight = 16; /* arbitrary? from NAPI_HOWTO.txt. */ + netif_napi_add(dev, &cp->napi, cp_rx_poll, 16); #ifdef BROKEN dev->change_mtu = cp_change_mtu; #endif diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index f4e4298d24b9..20af6baecfcb 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -573,6 +573,8 @@ struct rtl8139_private { int drv_flags; struct pci_dev *pci_dev; u32 msg_enable; + struct napi_struct napi; + struct net_device *dev; struct net_device_stats stats; unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ @@ -625,10 +627,10 @@ 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 int rtl8139_poll(struct net_device *dev, int *budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void rtl8139_poll_controller(struct net_device *dev); #endif +static int rtl8139_poll(struct napi_struct *napi, int budget); static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance); static int rtl8139_close (struct net_device *dev); static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); @@ -963,6 +965,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, assert (dev != NULL); tp = netdev_priv(dev); + tp->dev = dev; ioaddr = tp->mmio_addr; assert (ioaddr != NULL); @@ -976,8 +979,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; dev->hard_start_xmit = rtl8139_start_xmit; - dev->poll = rtl8139_poll; - dev->weight = 64; + netif_napi_add(dev, &tp->napi, rtl8139_poll, 64); dev->stop = rtl8139_close; dev->get_stats = rtl8139_get_stats; dev->set_multicast_list = rtl8139_set_rx_mode; @@ -1332,6 +1334,8 @@ static int rtl8139_open (struct net_device *dev) } + napi_enable(&tp->napi); + tp->mii.full_duplex = tp->mii.force_media; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; @@ -2103,39 +2107,32 @@ static void rtl8139_weird_interrupt (struct net_device *dev, } } -static int rtl8139_poll(struct net_device *dev, int *budget) +static int rtl8139_poll(struct napi_struct *napi, int budget) { - struct rtl8139_private *tp = netdev_priv(dev); + struct rtl8139_private *tp = container_of(napi, struct rtl8139_private, napi); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->mmio_addr; - int orig_budget = min(*budget, dev->quota); - int done = 1; + int work_done; spin_lock(&tp->rx_lock); - if (likely(RTL_R16(IntrStatus) & RxAckBits)) { - int work_done; + work_done = 0; + if (likely(RTL_R16(IntrStatus) & RxAckBits)) + work_done += rtl8139_rx(dev, tp, budget); - work_done = rtl8139_rx(dev, tp, orig_budget); - if (likely(work_done > 0)) { - *budget -= work_done; - dev->quota -= work_done; - done = (work_done < orig_budget); - } - } - - if (done) { + if (work_done < budget) { unsigned long flags; /* * Order is important since data can get interrupted * again when we think we are done. */ - local_irq_save(flags); + spin_lock_irqsave(&tp->lock, flags); RTL_W16_F(IntrMask, rtl8139_intr_mask); - __netif_rx_complete(dev); - local_irq_restore(flags); + __netif_rx_complete(dev, napi); + spin_unlock_irqrestore(&tp->lock, flags); } spin_unlock(&tp->rx_lock); - return !done; + return work_done; } /* The interrupt handler does all of the Rx thread work and cleans up @@ -2180,9 +2177,9 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance) /* Receive packets are processed by poll routine. If not running start it now. */ if (status & RxAckBits){ - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &tp->napi)) { RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); - __netif_rx_schedule (dev); + __netif_rx_schedule(dev, &tp->napi); } } @@ -2223,7 +2220,8 @@ static int rtl8139_close (struct net_device *dev) void __iomem *ioaddr = tp->mmio_addr; unsigned long flags; - netif_stop_queue (dev); + netif_stop_queue(dev); + napi_disable(&tp->napi); if (netif_msg_ifdown(tp)) printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index a61b2f89fc33..cf06fc067e92 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -723,9 +723,10 @@ static int amd8111e_tx(struct net_device *dev) #ifdef CONFIG_AMD8111E_NAPI /* This function handles the driver receive operation in polling mode */ -static int amd8111e_rx_poll(struct net_device *dev, int * budget) +static int amd8111e_rx_poll(struct napi_struct *napi, int budget) { - struct amd8111e_priv *lp = netdev_priv(dev); + struct amd8111e_priv *lp = container_of(napi, struct amd8111e_priv, napi); + struct net_device *dev = lp->amd8111e_net_dev; int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK; void __iomem *mmio = lp->mmio; struct sk_buff *skb,*new_skb; @@ -737,7 +738,7 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) #if AMD8111E_VLAN_TAG_USED short vtag; #endif - int rx_pkt_limit = dev->quota; + int rx_pkt_limit = budget; unsigned long flags; do{ @@ -838,21 +839,14 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) } while(intr0 & RINT0); /* Receive descriptor is empty now */ - dev->quota -= num_rx_pkt; - *budget -= num_rx_pkt; - spin_lock_irqsave(&lp->lock, flags); - netif_rx_complete(dev); + __netif_rx_complete(dev, napi); writel(VAL0|RINTEN0, mmio + INTEN0); writel(VAL2 | RDMD0, mmio + CMD0); spin_unlock_irqrestore(&lp->lock, flags); - return 0; rx_not_empty: - /* Do not call a netif_rx_complete */ - dev->quota -= num_rx_pkt; - *budget -= num_rx_pkt; - return 1; + return num_rx_pkt; } #else @@ -1287,11 +1281,11 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) /* Check if Receive Interrupt has occurred. */ #ifdef CONFIG_AMD8111E_NAPI if(intr0 & RINT0){ - if(netif_rx_schedule_prep(dev)){ + if(netif_rx_schedule_prep(dev, &lp->napi)){ /* Disable receive interupts */ writel(RINTEN0, mmio + INTEN0); /* Schedule a polling routine */ - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &lp->napi); } else if (intren0 & RINTEN0) { printk("************Driver bug! \ @@ -1345,6 +1339,8 @@ static int amd8111e_close(struct net_device * dev) struct amd8111e_priv *lp = netdev_priv(dev); netif_stop_queue(dev); + napi_disable(&lp->napi); + spin_lock_irq(&lp->lock); amd8111e_disable_interrupt(lp); @@ -1375,12 +1371,15 @@ static int amd8111e_open(struct net_device * dev ) dev->name, dev)) return -EAGAIN; + napi_enable(&lp->napi); + spin_lock_irq(&lp->lock); amd8111e_init_hw_default(lp); if(amd8111e_restart(dev)){ spin_unlock_irq(&lp->lock); + napi_disable(&lp->napi); if (dev->irq) free_irq(dev->irq, dev); return -ENOMEM; @@ -2031,8 +2030,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; #ifdef CONFIG_AMD8111E_NAPI - dev->poll = amd8111e_rx_poll; - dev->weight = 32; + netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32); #endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = amd8111e_poll; diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h index e65080a5994a..612e653610e1 100644 --- a/drivers/net/amd8111e.h +++ b/drivers/net/amd8111e.h @@ -763,6 +763,8 @@ struct amd8111e_priv{ /* Reg memory mapped address */ void __iomem *mmio; + struct napi_struct napi; + spinlock_t lock; /* Guard lock */ unsigned long rx_idx, tx_idx; /* The next free ring entry */ unsigned long tx_complete_idx; diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index f6ece1d43f6e..7f016f3d5bf0 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -169,6 +169,9 @@ struct ep93xx_priv spinlock_t tx_pending_lock; unsigned int tx_pending; + struct net_device *dev; + struct napi_struct napi; + struct net_device_stats stats; struct mii_if_info mii; @@ -190,15 +193,11 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev) return &(ep->stats); } -static int ep93xx_rx(struct net_device *dev, int *budget) +static int ep93xx_rx(struct net_device *dev, int processed, int budget) { struct ep93xx_priv *ep = netdev_priv(dev); - int rx_done; - int processed; - rx_done = 0; - processed = 0; - while (*budget > 0) { + while (processed < budget) { int entry; struct ep93xx_rstat *rstat; u32 rstat0; @@ -211,10 +210,8 @@ static int ep93xx_rx(struct net_device *dev, int *budget) rstat0 = rstat->rstat0; rstat1 = rstat->rstat1; - if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) { - rx_done = 1; + if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) break; - } rstat->rstat0 = 0; rstat->rstat1 = 0; @@ -275,8 +272,6 @@ static int ep93xx_rx(struct net_device *dev, int *budget) err: ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1); processed++; - dev->quota--; - (*budget)--; } if (processed) { @@ -284,7 +279,7 @@ err: wrw(ep, REG_RXSTSENQ, processed); } - return !rx_done; + return processed; } static int ep93xx_have_more_rx(struct ep93xx_priv *ep) @@ -293,36 +288,32 @@ static int ep93xx_have_more_rx(struct ep93xx_priv *ep) return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP)); } -static int ep93xx_poll(struct net_device *dev, int *budget) +static int ep93xx_poll(struct napi_struct *napi, int budget) { - struct ep93xx_priv *ep = netdev_priv(dev); - - /* - * @@@ Have to stop polling if device is downed while we - * are polling. - */ + struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi); + struct net_device *dev = ep->dev; + int rx = 0; poll_some_more: - if (ep93xx_rx(dev, budget)) - return 1; + rx = ep93xx_rx(dev, rx, budget); + if (rx < budget) { + int more = 0; - netif_rx_complete(dev); - - spin_lock_irq(&ep->rx_lock); - wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); - if (ep93xx_have_more_rx(ep)) { - wrl(ep, REG_INTEN, REG_INTEN_TX); - wrl(ep, REG_INTSTSP, REG_INTSTS_RX); + spin_lock_irq(&ep->rx_lock); + __netif_rx_complete(dev, napi); + wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); + if (ep93xx_have_more_rx(ep)) { + wrl(ep, REG_INTEN, REG_INTEN_TX); + wrl(ep, REG_INTSTSP, REG_INTSTS_RX); + more = 1; + } spin_unlock_irq(&ep->rx_lock); - if (netif_rx_reschedule(dev, 0)) + if (more && netif_rx_reschedule(dev, napi)) goto poll_some_more; - - return 0; } - spin_unlock_irq(&ep->rx_lock); - return 0; + return rx; } static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) @@ -426,9 +417,9 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id) if (status & REG_INTSTS_RX) { spin_lock(&ep->rx_lock); - if (likely(__netif_rx_schedule_prep(dev))) { + if (likely(__netif_rx_schedule_prep(dev, &ep->napi))) { wrl(ep, REG_INTEN, REG_INTEN_TX); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &ep->napi); } spin_unlock(&ep->rx_lock); } @@ -648,7 +639,10 @@ static int ep93xx_open(struct net_device *dev) dev->dev_addr[4], dev->dev_addr[5]); } + napi_enable(&ep->napi); + if (ep93xx_start_hw(dev)) { + napi_disable(&ep->napi); ep93xx_free_buffers(ep); return -EIO; } @@ -662,6 +656,7 @@ static int ep93xx_open(struct net_device *dev) err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev); if (err) { + napi_disable(&ep->napi); ep93xx_stop_hw(dev); ep93xx_free_buffers(ep); return err; @@ -678,6 +673,7 @@ static int ep93xx_close(struct net_device *dev) { struct ep93xx_priv *ep = netdev_priv(dev); + napi_disable(&ep->napi); netif_stop_queue(dev); wrl(ep, REG_GIINTMSK, 0); @@ -788,14 +784,12 @@ struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) dev->get_stats = ep93xx_get_stats; dev->ethtool_ops = &ep93xx_ethtool_ops; - dev->poll = ep93xx_poll; dev->hard_start_xmit = ep93xx_xmit; dev->open = ep93xx_open; dev->stop = ep93xx_close; dev->do_ioctl = ep93xx_ioctl; dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - dev->weight = 64; return dev; } @@ -847,6 +841,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev) goto err_out; } ep = netdev_priv(dev); + ep->dev = dev; + netif_napi_add(dev, &ep->napi, ep93xx_poll, 64); platform_set_drvdata(pdev, dev); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 0795df235492..b92b3e25c42a 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -848,10 +848,11 @@ static int b44_rx(struct b44 *bp, int budget) return received; } -static int b44_poll(struct net_device *netdev, int *budget) +static int b44_poll(struct napi_struct *napi, int budget) { - struct b44 *bp = netdev_priv(netdev); - int done; + struct b44 *bp = container_of(napi, struct b44, napi); + struct net_device *netdev = bp->dev; + int work_done; spin_lock_irq(&bp->lock); @@ -862,22 +863,9 @@ static int b44_poll(struct net_device *netdev, int *budget) } spin_unlock_irq(&bp->lock); - done = 1; - if (bp->istat & ISTAT_RX) { - int orig_budget = *budget; - int work_done; - - if (orig_budget > netdev->quota) - orig_budget = netdev->quota; - - work_done = b44_rx(bp, orig_budget); - - *budget -= work_done; - netdev->quota -= work_done; - - if (work_done >= orig_budget) - done = 0; - } + work_done = 0; + if (bp->istat & ISTAT_RX) + work_done += b44_rx(bp, budget); if (bp->istat & ISTAT_ERRORS) { unsigned long flags; @@ -888,15 +876,15 @@ static int b44_poll(struct net_device *netdev, int *budget) b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY); netif_wake_queue(bp->dev); spin_unlock_irqrestore(&bp->lock, flags); - done = 1; + work_done = 0; } - if (done) { - netif_rx_complete(netdev); + if (work_done < budget) { + netif_rx_complete(netdev, napi); b44_enable_ints(bp); } - return (done ? 0 : 1); + return work_done; } static irqreturn_t b44_interrupt(int irq, void *dev_id) @@ -924,13 +912,13 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id) goto irq_ack; } - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &bp->napi)) { /* NOTE: These writes are posted by the readback of * the ISTAT register below. */ bp->istat = istat; __b44_disable_ints(bp); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &bp->napi); } else { printk(KERN_ERR PFX "%s: Error, poll already scheduled\n", dev->name); @@ -1420,6 +1408,8 @@ static int b44_open(struct net_device *dev) if (err) goto out; + napi_enable(&bp->napi); + b44_init_rings(bp); b44_init_hw(bp, B44_FULL_RESET); @@ -1427,6 +1417,7 @@ static int b44_open(struct net_device *dev) err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); if (unlikely(err < 0)) { + napi_disable(&bp->napi); b44_chip_reset(bp); b44_free_rings(bp); b44_free_consistent(bp); @@ -1609,7 +1600,7 @@ static int b44_close(struct net_device *dev) netif_stop_queue(dev); - netif_poll_disable(dev); + napi_disable(&bp->napi); del_timer_sync(&bp->timer); @@ -1626,8 +1617,6 @@ static int b44_close(struct net_device *dev) free_irq(dev->irq, dev); - netif_poll_enable(dev); - if (bp->flags & B44_FLAG_WOL_ENABLE) { b44_init_hw(bp, B44_PARTIAL_RESET); b44_setup_wol(bp); @@ -2194,8 +2183,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev, dev->set_mac_address = b44_set_mac_addr; dev->do_ioctl = b44_ioctl; dev->tx_timeout = b44_tx_timeout; - dev->poll = b44_poll; - dev->weight = 64; + netif_napi_add(dev, &bp->napi, b44_poll, 64); dev->watchdog_timeo = B44_TX_TIMEOUT; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = b44_poll_controller; diff --git a/drivers/net/b44.h b/drivers/net/b44.h index e537e63f292e..63c55a4ab3cd 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -423,6 +423,8 @@ struct b44 { struct ring_info *rx_buffers; struct ring_info *tx_buffers; + struct napi_struct napi; + u32 dma_offset; u32 flags; #define B44_FLAG_B0_ANDLATER 0x00000001 diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 66eed22cbd21..ab028ad04235 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -428,7 +428,7 @@ bnx2_netif_stop(struct bnx2 *bp) { bnx2_disable_int_sync(bp); if (netif_running(bp->dev)) { - netif_poll_disable(bp->dev); + napi_disable(&bp->napi); netif_tx_disable(bp->dev); bp->dev->trans_start = jiffies; /* prevent tx timeout */ } @@ -440,7 +440,7 @@ bnx2_netif_start(struct bnx2 *bp) if (atomic_dec_and_test(&bp->intr_sem)) { if (netif_running(bp->dev)) { netif_wake_queue(bp->dev); - netif_poll_enable(bp->dev); + napi_enable(&bp->napi); bnx2_enable_int(bp); } } @@ -2551,7 +2551,7 @@ bnx2_msi(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev); + netif_rx_schedule(dev, &bp->napi); return IRQ_HANDLED; } @@ -2568,7 +2568,7 @@ bnx2_msi_1shot(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev); + netif_rx_schedule(dev, &bp->napi); return IRQ_HANDLED; } @@ -2604,9 +2604,9 @@ bnx2_interrupt(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &bp->napi)) { bp->last_status_idx = sblk->status_idx; - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &bp->napi); } return IRQ_HANDLED; @@ -2632,12 +2632,14 @@ bnx2_has_work(struct bnx2 *bp) } static int -bnx2_poll(struct net_device *dev, int *budget) +bnx2_poll(struct napi_struct *napi, int budget) { - struct bnx2 *bp = netdev_priv(dev); + struct bnx2 *bp = container_of(napi, struct bnx2, napi); + struct net_device *dev = bp->dev; struct status_block *sblk = bp->status_blk; u32 status_attn_bits = sblk->status_attn_bits; u32 status_attn_bits_ack = sblk->status_attn_bits_ack; + int work_done = 0; if ((status_attn_bits & STATUS_ATTN_EVENTS) != (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { @@ -2655,23 +2657,14 @@ bnx2_poll(struct net_device *dev, int *budget) if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) bnx2_tx_int(bp); - if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) { - int orig_budget = *budget; - int work_done; - - if (orig_budget > dev->quota) - orig_budget = dev->quota; - - work_done = bnx2_rx_int(bp, orig_budget); - *budget -= work_done; - dev->quota -= work_done; - } + if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) + work_done = bnx2_rx_int(bp, budget); bp->last_status_idx = bp->status_blk->status_idx; rmb(); if (!bnx2_has_work(bp)) { - netif_rx_complete(dev); + netif_rx_complete(dev, napi); if (likely(bp->flags & USING_MSI_FLAG)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | @@ -2686,10 +2679,9 @@ bnx2_poll(struct net_device *dev, int *budget) REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); - return 0; } - return 1; + return work_done; } /* Called with rtnl_lock from vlan functions and also netif_tx_lock @@ -5039,6 +5031,8 @@ bnx2_open(struct net_device *dev) if (rc) return rc; + napi_enable(&bp->napi); + if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) { if (pci_enable_msi(bp->pdev) == 0) { bp->flags |= USING_MSI_FLAG; @@ -5049,6 +5043,7 @@ bnx2_open(struct net_device *dev) rc = bnx2_request_irq(bp); if (rc) { + napi_disable(&bp->napi); bnx2_free_mem(bp); return rc; } @@ -5056,6 +5051,7 @@ bnx2_open(struct net_device *dev) rc = bnx2_init_nic(bp); if (rc) { + napi_disable(&bp->napi); bnx2_free_irq(bp); bnx2_free_skbs(bp); bnx2_free_mem(bp); @@ -5088,6 +5084,7 @@ bnx2_open(struct net_device *dev) rc = bnx2_request_irq(bp); if (rc) { + napi_disable(&bp->napi); bnx2_free_skbs(bp); bnx2_free_mem(bp); del_timer_sync(&bp->timer); @@ -5301,7 +5298,8 @@ bnx2_close(struct net_device *dev) while (bp->in_reset_task) msleep(1); - bnx2_netif_stop(bp); + bnx2_disable_int_sync(bp); + napi_disable(&bp->napi); del_timer_sync(&bp->timer); if (bp->flags & NO_WOL_FLAG) reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; @@ -6858,11 +6856,10 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef BCM_VLAN dev->vlan_rx_register = bnx2_vlan_rx_register; #endif - dev->poll = bnx2_poll; dev->ethtool_ops = &bnx2_ethtool_ops; - dev->weight = 64; bp = netdev_priv(dev); + netif_napi_add(dev, &bp->napi, bnx2_poll, 64); #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) dev->poll_controller = poll_bnx2; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 102adfe1e923..fbae439db647 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6473,6 +6473,8 @@ struct bnx2 { struct net_device *dev; struct pci_dev *pdev; + struct napi_struct napi; + atomic_t intr_sem; struct status_block *status_blk; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f6e4030c73d1..13f14df21e6e 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2485,7 +2485,7 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id) if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &cp->napi); #else cas_rx_ringN(cp, ring, 0); #endif @@ -2536,7 +2536,7 @@ static irqreturn_t cas_interrupt1(int irq, void *dev_id) if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &cp->napi); #else cas_rx_ringN(cp, 1, 0); #endif @@ -2592,7 +2592,7 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id) if (status & INTR_RX_DONE) { #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &cp->napi); #else cas_rx_ringN(cp, 0, 0); #endif @@ -2607,9 +2607,10 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id) #ifdef USE_NAPI -static int cas_poll(struct net_device *dev, int *budget) +static int cas_poll(struct napi_struct *napi, int budget) { - struct cas *cp = netdev_priv(dev); + struct cas *cp = container_of(napi, struct cas, napi); + struct net_device *dev = cp->dev; int i, enable_intr, todo, credits; u32 status = readl(cp->regs + REG_INTR_STATUS); unsigned long flags; @@ -2620,20 +2621,18 @@ static int cas_poll(struct net_device *dev, int *budget) /* NAPI rx packets. we spread the credits across all of the * rxc rings - */ - todo = min(*budget, dev->quota); - - /* to make sure we're fair with the work we loop through each + * + * to make sure we're fair with the work we loop through each * ring N_RX_COMP_RING times with a request of - * todo / N_RX_COMP_RINGS + * budget / N_RX_COMP_RINGS */ enable_intr = 1; credits = 0; for (i = 0; i < N_RX_COMP_RINGS; i++) { int j; for (j = 0; j < N_RX_COMP_RINGS; j++) { - credits += cas_rx_ringN(cp, j, todo / N_RX_COMP_RINGS); - if (credits >= todo) { + credits += cas_rx_ringN(cp, j, budget / N_RX_COMP_RINGS); + if (credits >= budget) { enable_intr = 0; goto rx_comp; } @@ -2641,9 +2640,6 @@ static int cas_poll(struct net_device *dev, int *budget) } rx_comp: - *budget -= credits; - dev->quota -= credits; - /* final rx completion */ spin_lock_irqsave(&cp->lock, flags); if (status) @@ -2674,11 +2670,10 @@ rx_comp: #endif spin_unlock_irqrestore(&cp->lock, flags); if (enable_intr) { - netif_rx_complete(dev); + netif_rx_complete(dev, napi); cas_unmask_intr(cp); - return 0; } - return 1; + return credits; } #endif @@ -4351,6 +4346,9 @@ static int cas_open(struct net_device *dev) goto err_spare; } +#ifdef USE_NAPI + napi_enable(&cp->napi); +#endif /* init hw */ cas_lock_all_save(cp, flags); cas_clean_rings(cp); @@ -4376,6 +4374,9 @@ static int cas_close(struct net_device *dev) unsigned long flags; struct cas *cp = netdev_priv(dev); +#ifdef USE_NAPI + napi_enable(&cp->napi); +#endif /* Make sure we don't get distracted by suspend/resume */ mutex_lock(&cp->pm_mutex); @@ -5062,8 +5063,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, dev->watchdog_timeo = CAS_TX_TIMEOUT; dev->change_mtu = cas_change_mtu; #ifdef USE_NAPI - dev->poll = cas_poll; - dev->weight = 64; + netif_napi_add(dev, &cp->napi, cas_poll, 64); #endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = cas_netpoll; diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h index a970804487c7..2f93f83342d2 100644 --- a/drivers/net/cassini.h +++ b/drivers/net/cassini.h @@ -4280,6 +4280,8 @@ struct cas { int rx_cur[N_RX_COMP_RINGS], rx_new[N_RX_COMP_RINGS]; int rx_last[N_RX_DESC_RINGS]; + struct napi_struct napi; + /* Set when chip is actually in operational state * (ie. not power managed) */ int hw_running; diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 8ba702c8b560..b5de4452cf24 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -278,6 +278,7 @@ struct adapter { struct peespi *espi; struct petp *tp; + struct napi_struct napi; struct port_info port[MAX_NPORTS]; struct delayed_work stats_update_task; struct timer_list stats_update_timer; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 231ce43b97cf..593736c7550d 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -255,8 +255,11 @@ static int cxgb_open(struct net_device *dev) struct adapter *adapter = dev->priv; int other_ports = adapter->open_device_map & PORT_MASK; - if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) + napi_enable(&adapter->napi); + if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) { + napi_disable(&adapter->napi); return err; + } __set_bit(dev->if_port, &adapter->open_device_map); link_start(&adapter->port[dev->if_port]); @@ -274,6 +277,7 @@ static int cxgb_close(struct net_device *dev) struct cmac *mac = p->mac; netif_stop_queue(dev); + napi_disable(&adapter->napi); mac->ops->disable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); netif_carrier_off(dev); @@ -1113,8 +1117,7 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->poll_controller = t1_netpoll; #endif #ifdef CONFIG_CHELSIO_T1_NAPI - netdev->weight = 64; - netdev->poll = t1_poll; + netif_napi_add(netdev, &adapter->napi, t1_poll, 64); #endif SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index e4f874a70fe5..ffa7e649a6ef 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1620,23 +1620,20 @@ static int process_pure_responses(struct adapter *adapter) * or protection from interrupts as data interrupts are off at this point and * other adapter interrupts do not interfere. */ -int t1_poll(struct net_device *dev, int *budget) +int t1_poll(struct napi_struct *napi, int budget) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = container_of(napi, struct adapter, napi); + struct net_device *dev = adapter->port[0].dev; int work_done; - work_done = process_responses(adapter, min(*budget, dev->quota)); - *budget -= work_done; - dev->quota -= work_done; - - if (unlikely(responses_pending(adapter))) - return 1; - - netif_rx_complete(dev); - writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - - return 0; + work_done = process_responses(adapter, budget); + if (likely(!responses_pending(adapter))) { + netif_rx_complete(dev, napi); + writel(adapter->sge->respQ.cidx, + adapter->regs + A_SG_SLEEPING); + } + return work_done; } /* @@ -1653,13 +1650,13 @@ irqreturn_t t1_interrupt(int irq, void *data) writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - if (__netif_rx_schedule_prep(dev)) { + if (napi_schedule_prep(&adapter->napi)) { if (process_pure_responses(adapter)) - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &adapter->napi); else { /* no data, no NAPI needed */ writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - netif_poll_enable(dev); /* undo schedule_prep */ + napi_enable(&adapter->napi); /* undo schedule_prep */ } } return IRQ_HANDLED; diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h index d132a0ef2a22..713d9c55f24d 100644 --- a/drivers/net/chelsio/sge.h +++ b/drivers/net/chelsio/sge.h @@ -77,7 +77,7 @@ int t1_sge_configure(struct sge *, struct sge_params *); int t1_sge_set_coalesce_params(struct sge *, struct sge_params *); void t1_sge_destroy(struct sge *); irqreturn_t t1_interrupt(int irq, void *cookie); -int t1_poll(struct net_device *, int *); +int t1_poll(struct napi_struct *, int); int t1_start_xmit(struct sk_buff *skb, struct net_device *dev); void t1_set_vlan_accel(struct adapter *adapter, int on_off); diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 20e887de2545..044261703381 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -49,11 +49,13 @@ typedef irqreturn_t(*intr_handler_t) (int, void *); struct vlan_group; - struct adapter; +struct sge_qset; + struct port_info { struct adapter *adapter; struct vlan_group *vlan_grp; + struct sge_qset *qs; const struct port_type_info *port_type; u8 port_id; u8 rx_csum_offload; @@ -173,10 +175,12 @@ enum { /* per port SGE statistics */ }; struct sge_qset { /* an SGE queue set */ + struct adapter *adap; + struct napi_struct napi; struct sge_rspq rspq; struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; - struct net_device *netdev; /* associated net device */ + struct net_device *netdev; unsigned long txq_stopped; /* which Tx queues are stopped */ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ unsigned long port_stats[SGE_PSTAT_MAX]; @@ -221,12 +225,6 @@ struct adapter { struct delayed_work adap_check_task; struct work_struct ext_intr_handler_task; - /* - * Dummy netdevices are needed when using multiple receive queues with - * NAPI as each netdevice can service only one queue. - */ - struct net_device *dummy_netdev[SGE_QSETS - 1]; - struct dentry *debugfs_root; struct mutex mdio_lock; @@ -253,12 +251,6 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) return netdev_priv(adap->port[idx]); } -/* - * We use the spare atalk_ptr to map a net device to its SGE queue set. - * This is a macro so it can be used as l-value. - */ -#define dev2qset(netdev) ((netdev)->atalk_ptr) - #define OFFLOAD_DEVMAP_BIT 15 #define tdev2adap(d) container_of(d, struct adapter, tdev) @@ -284,7 +276,7 @@ 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, int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *netdev); + int ntxq, struct net_device *dev); 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); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 5ab319cfe5de..5db7d4e27ec0 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -339,49 +339,17 @@ static void setup_rss(struct adapter *adap) V_RRCPLCPUSIZE(6), cpus, rspq_map); } -/* - * If we have multiple receive queues per port serviced by NAPI we need one - * netdevice per queue as NAPI operates on netdevices. We already have one - * netdevice, namely the one associated with the interface, so we use dummy - * ones for any additional queues. Note that these netdevices exist purely - * so that NAPI has something to work with, they do not represent network - * ports and are not registered. - */ -static int init_dummy_netdevs(struct adapter *adap) +static void init_napi(struct adapter *adap) { - int i, j, dummy_idx = 0; - struct net_device *nd; + int i; - for_each_port(adap, i) { - struct net_device *dev = adap->port[i]; - const struct port_info *pi = netdev_priv(dev); + for (i = 0; i < SGE_QSETS; i++) { + struct sge_qset *qs = &adap->sge.qs[i]; - for (j = 0; j < pi->nqsets - 1; j++) { - if (!adap->dummy_netdev[dummy_idx]) { - struct port_info *p; - - nd = alloc_netdev(sizeof(*p), "", ether_setup); - if (!nd) - goto free_all; - - p = netdev_priv(nd); - p->adapter = adap; - nd->weight = 64; - set_bit(__LINK_STATE_START, &nd->state); - adap->dummy_netdev[dummy_idx] = nd; - } - strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name); - dummy_idx++; - } + if (qs->adap) + netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll, + 64); } - return 0; - -free_all: - while (--dummy_idx >= 0) { - free_netdev(adap->dummy_netdev[dummy_idx]); - adap->dummy_netdev[dummy_idx] = NULL; - } - return -ENOMEM; } /* @@ -392,20 +360,18 @@ free_all: static void quiesce_rx(struct adapter *adap) { int i; - struct net_device *dev; - for_each_port(adap, i) { - dev = adap->port[i]; - while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) - msleep(1); - } + for (i = 0; i < SGE_QSETS; i++) + if (adap->sge.qs[i].adap) + napi_disable(&adap->sge.qs[i].napi); +} - for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) { - dev = adap->dummy_netdev[i]; - if (dev) - while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) - msleep(1); - } +static void enable_all_napi(struct adapter *adap) +{ + int i; + for (i = 0; i < SGE_QSETS; i++) + if (adap->sge.qs[i].adap) + napi_enable(&adap->sge.qs[i].napi); } /** @@ -418,7 +384,7 @@ static void quiesce_rx(struct adapter *adap) */ static int setup_sge_qsets(struct adapter *adap) { - int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0; + int i, j, err, irq_idx = 0, qset_idx = 0; unsigned int ntxq = SGE_TXQ_PER_SET; if (adap->params.rev > 0 && !(adap->flags & USING_MSI)) @@ -426,15 +392,14 @@ static int setup_sge_qsets(struct adapter *adap) for_each_port(adap, i) { struct net_device *dev = adap->port[i]; - const struct port_info *pi = netdev_priv(dev); + struct port_info *pi = netdev_priv(dev); + pi->qs = &adap->sge.qs[pi->first_qset]; for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, - &adap->params.sge.qset[qset_idx], ntxq, - j == 0 ? dev : - adap-> dummy_netdev[dummy_dev_idx++]); + &adap->params.sge.qset[qset_idx], ntxq, dev); if (err) { t3_free_sge_resources(adap); return err; @@ -845,21 +810,18 @@ static int cxgb_up(struct adapter *adap) goto out; } - err = init_dummy_netdevs(adap); - if (err) - goto out; - err = t3_init_hw(adap, 0); if (err) goto out; t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); - + err = setup_sge_qsets(adap); if (err) goto out; setup_rss(adap); + init_napi(adap); adap->flags |= FULL_INIT_DONE; } @@ -886,6 +848,7 @@ static int cxgb_up(struct adapter *adap) adap->name, adap))) goto irq_err; + enable_all_napi(adap); t3_sge_start(adap); t3_intr_enable(adap); @@ -1012,8 +975,10 @@ static int cxgb_open(struct net_device *dev) int other_ports = adapter->open_device_map & PORT_MASK; int err; - if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) + if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) { + quiesce_rx(adapter); return err; + } set_bit(pi->port_id, &adapter->open_device_map); if (is_offload(adapter) && !ofld_disable) { @@ -2524,7 +2489,6 @@ static int __devinit init_one(struct pci_dev *pdev, #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = cxgb_netpoll; #endif - netdev->weight = 64; SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); } @@ -2625,12 +2589,6 @@ static void __devexit remove_one(struct pci_dev *pdev) t3_free_sge_resources(adapter); cxgb_disable_msi(adapter); - for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++) - if (adapter->dummy_netdev[i]) { - free_netdev(adapter->dummy_netdev[i]); - adapter->dummy_netdev[i] = NULL; - } - for_each_port(adapter, i) if (adapter->port[i]) free_netdev(adapter->port[i]); diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 58a5f60521ed..069c1aca8a6b 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -591,9 +591,6 @@ void t3_free_qset(struct adapter *adapter, struct sge_qset *q) q->rspq.desc, q->rspq.phys_addr); } - if (q->netdev) - q->netdev->atalk_ptr = NULL; - memset(q, 0, sizeof(*q)); } @@ -1074,7 +1071,7 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int ndesc, pidx, credits, gen, compl; const struct port_info *pi = netdev_priv(dev); struct adapter *adap = pi->adapter; - struct sge_qset *qs = dev2qset(dev); + struct sge_qset *qs = pi->qs; struct sge_txq *q = &qs->txq[TXQ_ETH]; /* @@ -1326,13 +1323,12 @@ static void restart_ctrlq(unsigned long data) struct sk_buff *skb; struct sge_qset *qs = (struct sge_qset *)data; struct sge_txq *q = &qs->txq[TXQ_CTRL]; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; spin_lock(&q->lock); again:reclaim_completed_tx_imm(q); - while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) { + while (q->in_use < q->size && + (skb = __skb_dequeue(&q->sendq)) != NULL) { write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); @@ -1354,7 +1350,7 @@ static void restart_ctrlq(unsigned long data) } spin_unlock(&q->lock); - t3_write_reg(adap, A_SG_KDOORBELL, + t3_write_reg(qs->adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); } @@ -1638,8 +1634,7 @@ static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) else { struct sge_qset *qs = rspq_to_qset(q); - if (__netif_rx_schedule_prep(qs->netdev)) - __netif_rx_schedule(qs->netdev); + napi_schedule(&qs->napi); q->rx_head = skb; } q->rx_tail = skb; @@ -1675,34 +1670,30 @@ static inline void deliver_partial_bundle(struct t3cdev *tdev, * receive handler. Batches need to be of modest size as we do prefetches * on the packets in each. */ -static int ofld_poll(struct net_device *dev, int *budget) +static int ofld_poll(struct napi_struct *napi, int budget) { - const struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct sge_qset *qs = dev2qset(dev); + struct sge_qset *qs = container_of(napi, struct sge_qset, napi); struct sge_rspq *q = &qs->rspq; - int work_done, limit = min(*budget, dev->quota), avail = limit; + struct adapter *adapter = qs->adap; + int work_done = 0; - while (avail) { + while (work_done < budget) { struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE]; int ngathered; spin_lock_irq(&q->lock); head = q->rx_head; if (!head) { - work_done = limit - avail; - *budget -= work_done; - dev->quota -= work_done; - __netif_rx_complete(dev); + napi_complete(napi); spin_unlock_irq(&q->lock); - return 0; + return work_done; } tail = q->rx_tail; q->rx_head = q->rx_tail = NULL; spin_unlock_irq(&q->lock); - for (ngathered = 0; avail && head; avail--) { + for (ngathered = 0; work_done < budget && head; work_done++) { prefetch(head->data); skbs[ngathered] = head; head = head->next; @@ -1724,10 +1715,8 @@ static int ofld_poll(struct net_device *dev, int *budget) } deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); } - work_done = limit - avail; - *budget -= work_done; - dev->quota -= work_done; - return 1; + + return work_done; } /** @@ -2071,50 +2060,47 @@ static inline int is_pure_response(const struct rsp_desc *r) /** * napi_rx_handler - the NAPI handler for Rx processing - * @dev: the net device + * @napi: the napi instance * @budget: how many packets we can process in this round * * Handler for new data events when using NAPI. */ -static int napi_rx_handler(struct net_device *dev, int *budget) +static int napi_rx_handler(struct napi_struct *napi, int budget) { - const struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct sge_qset *qs = dev2qset(dev); - int effective_budget = min(*budget, dev->quota); + struct sge_qset *qs = container_of(napi, struct sge_qset, napi); + struct adapter *adap = qs->adap; + int work_done = process_responses(adap, qs, budget); - int work_done = process_responses(adap, qs, effective_budget); - *budget -= work_done; - dev->quota -= work_done; + if (likely(work_done < budget)) { + napi_complete(napi); - if (work_done >= effective_budget) - return 1; - - netif_rx_complete(dev); - - /* - * Because we don't atomically flush the following write it is - * possible that in very rare cases it can reach the device in a way - * that races with a new response being written plus an error interrupt - * causing the NAPI interrupt handler below to return unhandled status - * to the OS. To protect against this would require flushing the write - * and doing both the write and the flush with interrupts off. Way too - * expensive and unjustifiable given the rarity of the race. - * - * The race cannot happen at all with MSI-X. - */ - t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | - V_NEWTIMER(qs->rspq.next_holdoff) | - V_NEWINDEX(qs->rspq.cidx)); - return 0; + /* + * Because we don't atomically flush the following + * write it is possible that in very rare cases it can + * reach the device in a way that races with a new + * response being written plus an error interrupt + * causing the NAPI interrupt handler below to return + * unhandled status to the OS. To protect against + * this would require flushing the write and doing + * both the write and the flush with interrupts off. + * Way too expensive and unjustifiable given the + * rarity of the race. + * + * The race cannot happen at all with MSI-X. + */ + t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | + V_NEWTIMER(qs->rspq.next_holdoff) | + V_NEWINDEX(qs->rspq.cidx)); + } + return work_done; } /* * Returns true if the device is already scheduled for polling. */ -static inline int napi_is_scheduled(struct net_device *dev) +static inline int napi_is_scheduled(struct napi_struct *napi) { - return test_bit(__LINK_STATE_RX_SCHED, &dev->state); + return test_bit(NAPI_STATE_SCHED, &napi->state); } /** @@ -2197,8 +2183,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); return 0; } - if (likely(__netif_rx_schedule_prep(qs->netdev))) - __netif_rx_schedule(qs->netdev); + napi_schedule(&qs->napi); return 1; } @@ -2209,8 +2194,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) irqreturn_t t3_sge_intr_msix(int irq, void *cookie) { struct sge_qset *qs = cookie; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; + struct adapter *adap = qs->adap; struct sge_rspq *q = &qs->rspq; spin_lock(&q->lock); @@ -2229,13 +2213,11 @@ irqreturn_t t3_sge_intr_msix(int irq, void *cookie) irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) { struct sge_qset *qs = cookie; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; struct sge_rspq *q = &qs->rspq; spin_lock(&q->lock); - if (handle_responses(adap, q) < 0) + if (handle_responses(qs->adap, q) < 0) q->unhandled_irqs++; spin_unlock(&q->lock); return IRQ_HANDLED; @@ -2278,11 +2260,13 @@ static irqreturn_t t3_intr_msi(int irq, void *cookie) return IRQ_HANDLED; } -static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q) +static int rspq_check_napi(struct sge_qset *qs) { - if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) { - if (likely(__netif_rx_schedule_prep(dev))) - __netif_rx_schedule(dev); + struct sge_rspq *q = &qs->rspq; + + if (!napi_is_scheduled(&qs->napi) && + is_new_response(&q->desc[q->cidx], q)) { + napi_schedule(&qs->napi); return 1; } return 0; @@ -2303,10 +2287,9 @@ irqreturn_t t3_intr_msi_napi(int irq, void *cookie) spin_lock(&q->lock); - new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q); + new_packets = rspq_check_napi(&adap->sge.qs[0]); if (adap->params.nports == 2) - new_packets += rspq_check_napi(adap->sge.qs[1].netdev, - &adap->sge.qs[1].rspq); + new_packets += rspq_check_napi(&adap->sge.qs[1]); if (!new_packets && t3_slow_intr_handler(adap) == 0) q->unhandled_irqs++; @@ -2409,9 +2392,9 @@ static irqreturn_t t3b_intr(int irq, void *cookie) static irqreturn_t t3b_intr_napi(int irq, void *cookie) { u32 map; - struct net_device *dev; struct adapter *adap = cookie; - struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + struct sge_qset *qs0 = &adap->sge.qs[0]; + struct sge_rspq *q0 = &qs0->rspq; t3_write_reg(adap, A_PL_CLI, 0); map = t3_read_reg(adap, A_SG_DATA_INTR); @@ -2424,18 +2407,11 @@ static irqreturn_t t3b_intr_napi(int irq, void *cookie) if (unlikely(map & F_ERRINTR)) t3_slow_intr_handler(adap); - if (likely(map & 1)) { - dev = adap->sge.qs[0].netdev; + if (likely(map & 1)) + napi_schedule(&qs0->napi); - if (likely(__netif_rx_schedule_prep(dev))) - __netif_rx_schedule(dev); - } - if (map & 2) { - dev = adap->sge.qs[1].netdev; - - if (likely(__netif_rx_schedule_prep(dev))) - __netif_rx_schedule(dev); - } + if (map & 2) + napi_schedule(&adap->sge.qs[1].napi); spin_unlock(&q0->lock); return IRQ_HANDLED; @@ -2514,8 +2490,7 @@ static void sge_timer_cb(unsigned long data) { spinlock_t *lock; struct sge_qset *qs = (struct sge_qset *)data; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; + struct adapter *adap = qs->adap; if (spin_trylock(&qs->txq[TXQ_ETH].lock)) { reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]); @@ -2526,9 +2501,9 @@ static void sge_timer_cb(unsigned long data) spin_unlock(&qs->txq[TXQ_OFLD].lock); } lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock : - &adap->sge.qs[0].rspq.lock; + &adap->sge.qs[0].rspq.lock; if (spin_trylock_irq(lock)) { - if (!napi_is_scheduled(qs->netdev)) { + if (!napi_is_scheduled(&qs->napi)) { u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS); if (qs->fl[0].credits < qs->fl[0].size) @@ -2562,12 +2537,9 @@ static void sge_timer_cb(unsigned long data) */ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) { - if (!qs->netdev) - return; - qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */ qs->rspq.polling = p->polling; - qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll; + qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll; } /** @@ -2587,7 +2559,7 @@ 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, int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *netdev) + int ntxq, struct net_device *dev) { int i, ret = -ENOMEM; struct sge_qset *q = &adapter->sge.qs[id]; @@ -2708,16 +2680,10 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, } spin_unlock(&adapter->sge.reg_lock); - q->netdev = netdev; - t3_update_qset_coalesce(q, p); - /* - * We use atalk_ptr as a backpointer to a qset. In case a device is - * associated with multiple queue sets only the first one sets - * atalk_ptr. - */ - if (netdev->atalk_ptr == NULL) - netdev->atalk_ptr = q; + q->adap = adapter; + q->netdev = dev; + t3_update_qset_coalesce(q, p); refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 280313b9b069..e25f5ec2b279 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -539,6 +539,7 @@ struct nic { struct csr __iomem *csr; enum scb_cmd_lo cuc_cmd; unsigned int cbs_avail; + struct napi_struct napi; struct cb *cbs; struct cb *cb_to_use; struct cb *cb_to_send; @@ -1974,35 +1975,31 @@ static irqreturn_t e100_intr(int irq, void *dev_id) if(stat_ack & stat_ack_rnr) nic->ru_running = RU_SUSPENDED; - if(likely(netif_rx_schedule_prep(netdev))) { + if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) { e100_disable_irq(nic); - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &nic->napi); } return IRQ_HANDLED; } -static int e100_poll(struct net_device *netdev, int *budget) +static int e100_poll(struct napi_struct *napi, int budget) { - struct nic *nic = netdev_priv(netdev); - unsigned int work_to_do = min(netdev->quota, *budget); - unsigned int work_done = 0; + struct nic *nic = container_of(napi, struct nic, napi); + struct net_device *netdev = nic->netdev; + int work_done = 0; int tx_cleaned; - e100_rx_clean(nic, &work_done, work_to_do); + e100_rx_clean(nic, &work_done, budget); tx_cleaned = e100_tx_clean(nic); /* If no Rx and Tx cleanup work was done, exit polling mode. */ if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); e100_enable_irq(nic); - return 0; } - *budget -= work_done; - netdev->quota -= work_done; - - return 1; + return work_done; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2071,7 +2068,7 @@ static int e100_up(struct nic *nic) nic->netdev->name, nic->netdev))) goto err_no_irq; netif_wake_queue(nic->netdev); - netif_poll_enable(nic->netdev); + napi_enable(&nic->napi); /* enable ints _after_ enabling poll, preventing a race between * disable ints+schedule */ e100_enable_irq(nic); @@ -2089,7 +2086,7 @@ err_rx_clean_list: static void e100_down(struct nic *nic) { /* wait here for poll to complete */ - netif_poll_disable(nic->netdev); + napi_disable(&nic->napi); netif_stop_queue(nic->netdev); e100_hw_reset(nic); free_irq(nic->pdev->irq, nic->netdev); @@ -2572,14 +2569,13 @@ static int __devinit e100_probe(struct pci_dev *pdev, SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); netdev->tx_timeout = e100_tx_timeout; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; - netdev->poll = e100_poll; - netdev->weight = E100_NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = e100_netpoll; #endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); nic = netdev_priv(netdev); + netif_napi_add(netdev, &nic->napi, e100_poll, E100_NAPI_WEIGHT); nic->netdev = netdev; nic->pdev = pdev; nic->msg_enable = (1 << debug) - 1; @@ -2733,7 +2729,7 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) struct nic *nic = netdev_priv(netdev); if (netif_running(netdev)) - netif_poll_disable(nic->netdev); + napi_disable(&nic->napi); del_timer_sync(&nic->watchdog); netif_carrier_off(nic->netdev); netif_device_detach(netdev); @@ -2779,7 +2775,7 @@ static void e100_shutdown(struct pci_dev *pdev) struct nic *nic = netdev_priv(netdev); if (netif_running(netdev)) - netif_poll_disable(nic->netdev); + napi_disable(&nic->napi); del_timer_sync(&nic->watchdog); netif_carrier_off(nic->netdev); @@ -2804,12 +2800,13 @@ static void e100_shutdown(struct pci_dev *pdev) static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); /* Similar to calling e100_down(), but avoids adpater I/O. */ netdev->stop(netdev); /* Detach; put netif into state similar to hotplug unplug. */ - netif_poll_enable(netdev); + napi_enable(&nic->napi); netif_device_detach(netdev); pci_disable_device(pdev); diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 16a6edfeba41..781ed9968489 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -300,6 +300,7 @@ struct e1000_adapter { int cleaned_count); struct e1000_rx_ring *rx_ring; /* One per active queue */ #ifdef CONFIG_E1000_NAPI + struct napi_struct napi; struct net_device *polling_netdev; /* One per active queue */ #endif int num_tx_queues; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index e7c8951f47fa..723568d6e44a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -166,7 +166,7 @@ static irqreturn_t e1000_intr_msi(int irq, void *data); static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring); #ifdef CONFIG_E1000_NAPI -static int e1000_clean(struct net_device *poll_dev, int *budget); +static int e1000_clean(struct napi_struct *napi, int budget); static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); @@ -545,7 +545,7 @@ int e1000_up(struct e1000_adapter *adapter) clear_bit(__E1000_DOWN, &adapter->flags); #ifdef CONFIG_E1000_NAPI - netif_poll_enable(adapter->netdev); + napi_enable(&adapter->napi); #endif e1000_irq_enable(adapter); @@ -634,7 +634,7 @@ e1000_down(struct e1000_adapter *adapter) set_bit(__E1000_DOWN, &adapter->flags); #ifdef CONFIG_E1000_NAPI - netif_poll_disable(netdev); + napi_disable(&adapter->napi); #endif e1000_irq_disable(adapter); @@ -936,8 +936,7 @@ e1000_probe(struct pci_dev *pdev, netdev->tx_timeout = &e1000_tx_timeout; netdev->watchdog_timeo = 5 * HZ; #ifdef CONFIG_E1000_NAPI - netdev->poll = &e1000_clean; - netdev->weight = 64; + netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); #endif netdev->vlan_rx_register = e1000_vlan_rx_register; netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; @@ -1151,9 +1150,6 @@ e1000_probe(struct pci_dev *pdev, /* tell the stack to leave us alone until e1000_open() is called */ netif_carrier_off(netdev); netif_stop_queue(netdev); -#ifdef CONFIG_E1000_NAPI - netif_poll_disable(netdev); -#endif strcpy(netdev->name, "eth%d"); if ((err = register_netdev(netdev))) @@ -1222,12 +1218,13 @@ e1000_remove(struct pci_dev *pdev) * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); - unregister_netdev(netdev); #ifdef CONFIG_E1000_NAPI for (i = 0; i < adapter->num_rx_queues; i++) dev_put(&adapter->polling_netdev[i]); #endif + unregister_netdev(netdev); + if (!e1000_check_phy_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); @@ -1325,8 +1322,6 @@ e1000_sw_init(struct e1000_adapter *adapter) #ifdef CONFIG_E1000_NAPI for (i = 0; i < adapter->num_rx_queues; i++) { adapter->polling_netdev[i].priv = adapter; - adapter->polling_netdev[i].poll = &e1000_clean; - adapter->polling_netdev[i].weight = 64; dev_hold(&adapter->polling_netdev[i]); set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); } @@ -1443,7 +1438,7 @@ e1000_open(struct net_device *netdev) clear_bit(__E1000_DOWN, &adapter->flags); #ifdef CONFIG_E1000_NAPI - netif_poll_enable(netdev); + napi_enable(&adapter->napi); #endif e1000_irq_enable(adapter); @@ -3786,12 +3781,12 @@ e1000_intr_msi(int irq, void *data) } #ifdef CONFIG_E1000_NAPI - if (likely(netif_rx_schedule_prep(netdev))) { + if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } else e1000_irq_enable(adapter); #else @@ -3871,12 +3866,12 @@ e1000_intr(int irq, void *data) E1000_WRITE_REG(hw, IMC, ~0); E1000_WRITE_FLUSH(hw); } - if (likely(netif_rx_schedule_prep(netdev))) { + if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } else /* this really should not happen! if it does it is basically a * bug, but not a hard error, so enable ints and continue */ @@ -3924,10 +3919,10 @@ e1000_intr(int irq, void *data) **/ static int -e1000_clean(struct net_device *poll_dev, int *budget) +e1000_clean(struct napi_struct *napi, int budget) { - struct e1000_adapter *adapter; - int work_to_do = min(*budget, poll_dev->quota); + struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); + struct net_device *poll_dev = adapter->netdev; int tx_cleaned = 0, work_done = 0; /* Must NOT use netdev_priv macro here. */ @@ -3948,23 +3943,19 @@ e1000_clean(struct net_device *poll_dev, int *budget) } adapter->clean_rx(adapter, &adapter->rx_ring[0], - &work_done, work_to_do); - - *budget -= work_done; - poll_dev->quota -= work_done; + &work_done, budget); /* If no Tx and not enough Rx work done, exit the polling mode */ - if ((!tx_cleaned && (work_done == 0)) || + if ((!tx_cleaned && (work_done < budget)) || !netif_running(poll_dev)) { quit_polling: if (likely(adapter->itr_setting & 3)) e1000_set_itr(adapter); - netif_rx_complete(poll_dev); + netif_rx_complete(poll_dev, napi); e1000_irq_enable(adapter); - return 0; } - return 1; + return work_done; } #endif diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 8d58be56f4e3..a154681165b9 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -351,6 +351,7 @@ struct ehea_q_skb_arr { * Port resources */ struct ehea_port_res { + struct napi_struct napi; struct port_stats p_stats; struct ehea_mr send_mr; /* send memory region */ struct ehea_mr recv_mr; /* receive memory region */ @@ -362,7 +363,6 @@ struct ehea_port_res { struct ehea_cq *send_cq; struct ehea_cq *recv_cq; struct ehea_eq *eq; - struct net_device *d_netdev; struct ehea_q_skb_arr rq1_skba; struct ehea_q_skb_arr rq2_skba; struct ehea_q_skb_arr rq3_skba; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 717b12984d10..5ebd545ab04e 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -393,9 +393,9 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, return 0; } -static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, - struct ehea_port_res *pr, - int *budget) +static int ehea_proc_rwqes(struct net_device *dev, + struct ehea_port_res *pr, + int budget) { struct ehea_port *port = pr->port; struct ehea_qp *qp = pr->qp; @@ -408,18 +408,16 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, int skb_arr_rq2_len = pr->rq2_skba.len; int skb_arr_rq3_len = pr->rq3_skba.len; int processed, processed_rq1, processed_rq2, processed_rq3; - int wqe_index, last_wqe_index, rq, my_quota, port_reset; + int wqe_index, last_wqe_index, rq, port_reset; processed = processed_rq1 = processed_rq2 = processed_rq3 = 0; last_wqe_index = 0; - my_quota = min(*budget, dev->quota); cqe = ehea_poll_rq1(qp, &wqe_index); - while ((my_quota > 0) && cqe) { + while ((processed < budget) && cqe) { ehea_inc_rq1(qp); processed_rq1++; processed++; - my_quota--; if (netif_msg_rx_status(port)) ehea_dump(cqe, sizeof(*cqe), "CQE"); @@ -434,14 +432,14 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, if (netif_msg_rx_err(port)) ehea_error("LL rq1: skb=NULL"); - skb = netdev_alloc_skb(port->netdev, + skb = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); if (!skb) break; } skb_copy_to_linear_data(skb, ((char*)cqe) + 64, cqe->num_bytes_transfered - 4); - ehea_fill_skb(port->netdev, skb, cqe); + ehea_fill_skb(dev, skb, cqe); } else if (rq == 2) { /* RQ2 */ skb = get_skb_by_index(skb_arr_rq2, skb_arr_rq2_len, cqe); @@ -450,7 +448,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, ehea_error("rq2: skb=NULL"); break; } - ehea_fill_skb(port->netdev, skb, cqe); + ehea_fill_skb(dev, skb, cqe); processed_rq2++; } else { /* RQ3 */ skb = get_skb_by_index(skb_arr_rq3, @@ -460,7 +458,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, ehea_error("rq3: skb=NULL"); break; } - ehea_fill_skb(port->netdev, skb, cqe); + ehea_fill_skb(dev, skb, cqe); processed_rq3++; } @@ -471,7 +469,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, else netif_receive_skb(skb); - port->netdev->last_rx = jiffies; + dev->last_rx = jiffies; } else { pr->p_stats.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, @@ -484,14 +482,12 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, } pr->rx_packets += processed; - *budget -= processed; ehea_refill_rq1(pr, last_wqe_index, processed_rq1); ehea_refill_rq2(pr, processed_rq2); ehea_refill_rq3(pr, processed_rq3); - cqe = ehea_poll_rq1(qp, &wqe_index); - return cqe; + return processed; } static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) @@ -554,22 +550,27 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) } #define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16 +#define EHEA_POLL_MAX_CQES 65535 -static int ehea_poll(struct net_device *dev, int *budget) +static int ehea_poll(struct napi_struct *napi, int budget) { - struct ehea_port_res *pr = dev->priv; + struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi); + struct net_device *dev = pr->port->netdev; struct ehea_cqe *cqe; struct ehea_cqe *cqe_skb = NULL; int force_irq, wqe_index; - - cqe = ehea_poll_rq1(pr->qp, &wqe_index); - cqe_skb = ehea_poll_cq(pr->send_cq); + int rx = 0; force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ); + cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES); - if ((!cqe && !cqe_skb) || force_irq) { + if (!force_irq) + rx += ehea_proc_rwqes(dev, pr, budget - rx); + + while ((rx != budget) || force_irq) { pr->poll_counter = 0; - netif_rx_complete(dev); + force_irq = 0; + netif_rx_complete(dev, napi); ehea_reset_cq_ep(pr->recv_cq); ehea_reset_cq_ep(pr->send_cq); ehea_reset_cq_n1(pr->recv_cq); @@ -578,43 +579,35 @@ static int ehea_poll(struct net_device *dev, int *budget) cqe_skb = ehea_poll_cq(pr->send_cq); if (!cqe && !cqe_skb) - return 0; + return rx; - if (!netif_rx_reschedule(dev, dev->quota)) - return 0; + if (!netif_rx_reschedule(dev, napi)) + return rx; + + cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES); + rx += ehea_proc_rwqes(dev, pr, budget - rx); } - cqe = ehea_proc_rwqes(dev, pr, budget); - cqe_skb = ehea_proc_cqes(pr, 300); - - if (cqe || cqe_skb) - pr->poll_counter++; - - return 1; + pr->poll_counter++; + return rx; } #ifdef CONFIG_NET_POLL_CONTROLLER static void ehea_netpoll(struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); + int i; - netif_rx_schedule(port->port_res[0].d_netdev); + for (i = 0; i < port->num_def_qps; i++) + netif_rx_schedule(dev, &port->port_res[i].napi); } #endif -static int ehea_poll_firstqueue(struct net_device *dev, int *budget) -{ - struct ehea_port *port = netdev_priv(dev); - struct net_device *d_dev = port->port_res[0].d_netdev; - - return ehea_poll(d_dev, budget); -} - static irqreturn_t ehea_recv_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; - netif_rx_schedule(pr->d_netdev); + netif_rx_schedule(pr->port->netdev, &pr->napi); return IRQ_HANDLED; } @@ -1236,14 +1229,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, kfree(init_attr); - pr->d_netdev = alloc_netdev(0, "", ether_setup); - if (!pr->d_netdev) - goto out_free; - pr->d_netdev->priv = pr; - pr->d_netdev->weight = 64; - pr->d_netdev->poll = ehea_poll; - set_bit(__LINK_STATE_START, &pr->d_netdev->state); - strcpy(pr->d_netdev->name, port->netdev->name); + netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64); ret = 0; goto out; @@ -1266,8 +1252,6 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr) { int ret, i; - free_netdev(pr->d_netdev); - ret = ehea_destroy_qp(pr->qp); if (!ret) { @@ -2248,6 +2232,22 @@ out: return ret; } +static void port_napi_disable(struct ehea_port *port) +{ + int i; + + for (i = 0; i < port->num_def_qps; i++) + napi_disable(&port->port_res[i].napi); +} + +static void port_napi_enable(struct ehea_port *port) +{ + int i; + + for (i = 0; i < port->num_def_qps; i++) + napi_enable(&port->port_res[i].napi); +} + static int ehea_open(struct net_device *dev) { int ret; @@ -2259,8 +2259,10 @@ static int ehea_open(struct net_device *dev) ehea_info("enabling port %s", dev->name); ret = ehea_up(dev); - if (!ret) + if (!ret) { + port_napi_enable(port); netif_start_queue(dev); + } up(&port->port_lock); @@ -2269,7 +2271,7 @@ static int ehea_open(struct net_device *dev) static int ehea_down(struct net_device *dev) { - int ret, i; + int ret; struct ehea_port *port = netdev_priv(dev); if (port->state == EHEA_PORT_DOWN) @@ -2278,10 +2280,7 @@ static int ehea_down(struct net_device *dev) ehea_drop_multicast_list(dev); ehea_free_interrupts(dev); - for (i = 0; i < port->num_def_qps; i++) - while (test_bit(__LINK_STATE_RX_SCHED, - &port->port_res[i].d_netdev->state)) - msleep(1); + port_napi_disable(port); port->state = EHEA_PORT_DOWN; @@ -2319,7 +2318,8 @@ static void ehea_reset_port(struct work_struct *work) port->resets++; down(&port->port_lock); netif_stop_queue(dev); - netif_poll_disable(dev); + + port_napi_disable(port); ehea_down(dev); @@ -2330,7 +2330,8 @@ static void ehea_reset_port(struct work_struct *work) if (netif_msg_timer(port)) ehea_info("Device %s resetted successfully", dev->name); - netif_poll_enable(dev); + port_napi_enable(port); + netif_wake_queue(dev); out: up(&port->port_lock); @@ -2358,7 +2359,9 @@ static void ehea_rereg_mrs(struct work_struct *work) dev->name); down(&port->port_lock); netif_stop_queue(dev); - netif_poll_disable(dev); + + port_napi_disable(port); + ehea_down(dev); up(&port->port_lock); } @@ -2406,7 +2409,7 @@ static void ehea_rereg_mrs(struct work_struct *work) ret = ehea_up(dev); if (!ret) { - netif_poll_enable(dev); + port_napi_enable(port); netif_wake_queue(dev); } @@ -2644,11 +2647,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN); dev->open = ehea_open; - dev->poll = ehea_poll_firstqueue; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ehea_netpoll; #endif - dev->weight = 64; dev->stop = ehea_stop; dev->hard_start_xmit = ehea_start_xmit; dev->get_stats = ehea_get_stats; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 119778401e48..f8446e373bdd 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -262,6 +262,7 @@ struct epic_private { /* Ring pointers. */ spinlock_t lock; /* Group with Tx control cache line. */ spinlock_t napi_lock; + struct napi_struct napi; unsigned int reschedule_in_poll; unsigned int cur_tx, dirty_tx; @@ -294,7 +295,7 @@ 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 int epic_rx(struct net_device *dev, int budget); -static int epic_poll(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); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; @@ -487,8 +488,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; - dev->poll = epic_poll; - dev->weight = 64; + netif_napi_add(dev, &ep->napi, epic_poll, 64); ret = register_netdev(dev); if (ret < 0) @@ -660,8 +660,11 @@ static int epic_open(struct net_device *dev) /* Soft reset the chip. */ outl(0x4001, ioaddr + GENCTL); - if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) + napi_enable(&ep->napi); + if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) { + napi_disable(&ep->napi); return retval; + } epic_init_ring(dev); @@ -1103,9 +1106,9 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance) if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { spin_lock(&ep->napi_lock); - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &ep->napi)) { epic_napi_irq_off(dev, ep); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &ep->napi); } else ep->reschedule_in_poll++; spin_unlock(&ep->napi_lock); @@ -1257,26 +1260,22 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep) outw(RxQueued, ioaddr + COMMAND); } -static int epic_poll(struct net_device *dev, int *budget) +static int epic_poll(struct napi_struct *napi, int budget) { - struct epic_private *ep = dev->priv; - int work_done = 0, orig_budget; + struct epic_private *ep = container_of(napi, struct epic_private, napi); + struct net_device *dev = ep->mii.dev; + int work_done = 0; long ioaddr = dev->base_addr; - orig_budget = (*budget > dev->quota) ? dev->quota : *budget; - rx_action: epic_tx(dev, ep); - work_done += epic_rx(dev, *budget); + work_done += epic_rx(dev, budget); epic_rx_err(dev, ep); - *budget -= work_done; - dev->quota -= work_done; - - if (netif_running(dev) && (work_done < orig_budget)) { + if (netif_running(dev) && (work_done < budget)) { unsigned long flags; int more; @@ -1286,7 +1285,7 @@ rx_action: more = ep->reschedule_in_poll; if (!more) { - __netif_rx_complete(dev); + __netif_rx_complete(dev, napi); outl(EpicNapiEvent, ioaddr + INTSTAT); epic_napi_irq_on(dev, ep); } else @@ -1298,7 +1297,7 @@ rx_action: goto rx_action; } - return (work_done >= orig_budget); + return work_done; } static int epic_close(struct net_device *dev) @@ -1309,6 +1308,7 @@ static int epic_close(struct net_device *dev) int i; netif_stop_queue(dev); + napi_disable(&ep->napi); if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", diff --git a/drivers/net/fec_8xx/fec_8xx.h b/drivers/net/fec_8xx/fec_8xx.h index 5af60b0f9208..f3b1c6fbba8b 100644 --- a/drivers/net/fec_8xx/fec_8xx.h +++ b/drivers/net/fec_8xx/fec_8xx.h @@ -105,6 +105,8 @@ struct fec; struct fec_enet_private { spinlock_t lock; /* during all ops except TX pckt processing */ spinlock_t tx_lock; /* during fec_start_xmit and fec_tx */ + struct net_device *dev; + struct napi_struct napi; int fecno; struct fec *fecp; const struct fec_platform_info *fpi; diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index e5502af5b8e2..6348fb93ca9c 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -465,9 +465,9 @@ void fec_stop(struct net_device *dev) } /* common receive function */ -static int fec_enet_rx_common(struct net_device *dev, int *budget) +static int fec_enet_rx_common(struct fec_enet_private *ep, + struct net_device *dev, int budget) { - struct fec_enet_private *fep = netdev_priv(dev); fec_t *fecp = fep->fecp; const struct fec_platform_info *fpi = fep->fpi; cbd_t *bdp; @@ -475,11 +475,8 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget) int received = 0; __u16 pkt_len, sc; int curidx; - int rx_work_limit; if (fpi->use_napi) { - rx_work_limit = min(dev->quota, *budget); - if (!netif_running(dev)) return 0; } @@ -530,11 +527,6 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget) BUG_ON(skbn == NULL); } else { - - /* napi, got packet but no quota */ - if (fpi->use_napi && --rx_work_limit < 0) - break; - skb = fep->rx_skbuff[curidx]; BUG_ON(skb == NULL); @@ -599,25 +591,24 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget) * able to keep up at the expense of system resources. */ FW(fecp, r_des_active, 0x01000000); + + if (received >= budget) + break; + } fep->cur_rx = bdp; if (fpi->use_napi) { - dev->quota -= received; - *budget -= received; + if (received < budget) { + netif_rx_complete(dev, &fep->napi); - if (rx_work_limit < 0) - return 1; /* not done */ - - /* done */ - netif_rx_complete(dev); - - /* enable RX interrupt bits */ - FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); + /* enable RX interrupt bits */ + FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); + } } - return 0; + return received; } static void fec_enet_tx(struct net_device *dev) @@ -743,12 +734,12 @@ fec_enet_interrupt(int irq, void *dev_id) if ((int_events & FEC_ENET_RXF) != 0) { if (!fpi->use_napi) - fec_enet_rx_common(dev, NULL); + fec_enet_rx_common(fep, dev, ~0); else { - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &fep->napi)) { /* disable rx interrupts */ FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &fep->napi); } else { printk(KERN_ERR DRV_MODULE_NAME ": %s driver bug! interrupt while in poll!\n", @@ -893,10 +884,13 @@ static int fec_enet_open(struct net_device *dev) const struct fec_platform_info *fpi = fep->fpi; unsigned long flags; + napi_enable(&fep->napi); + /* Install our interrupt handler. */ if (request_irq(fpi->fec_irq, fec_enet_interrupt, 0, "fec", dev) != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate FEC IRQ!", dev->name); + napi_disable(&fep->napi); return -EINVAL; } @@ -907,6 +901,7 @@ static int fec_enet_open(struct net_device *dev) printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate PHY IRQ!", dev->name); free_irq(fpi->fec_irq, dev); + napi_disable(&fep->napi); return -EINVAL; } @@ -932,6 +927,7 @@ static int fec_enet_close(struct net_device *dev) unsigned long flags; netif_stop_queue(dev); + napi_disable(&fep->napi); netif_carrier_off(dev); if (fpi->use_mdio) @@ -955,9 +951,12 @@ static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) return &fep->stats; } -static int fec_enet_poll(struct net_device *dev, int *budget) +static int fec_enet_poll(struct napi_struct *napi, int budget) { - return fec_enet_rx_common(dev, budget); + struct fec_enet_private *fep = container_of(napi, struct fec_enet_private, napi); + struct net_device *dev = fep->dev; + + return fec_enet_rx_common(fep, dev, budget); } /*************************************************************************/ @@ -1107,6 +1106,7 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi, SET_MODULE_OWNER(dev); fep = netdev_priv(dev); + fep->dev = dev; /* partial reset of FEC */ fec_whack_reset(fecp); @@ -1172,10 +1172,9 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi, dev->get_stats = fec_enet_get_stats; dev->set_multicast_list = fec_set_multicast_list; dev->set_mac_address = fec_set_mac_address; - if (fpi->use_napi) { - dev->poll = fec_enet_poll; - dev->weight = fpi->napi_weight; - } + netif_napi_add(dev, &fec->napi, + fec_enet_poll, fpi->napi_weight); + dev->ethtool_ops = &fec_ethtool_ops; dev->do_ioctl = fec_ioctl; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 1938d6dfc863..24c1294614f2 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -159,6 +159,8 @@ #define dprintk(x...) do { } while (0) #endif +#define TX_WORK_PER_LOOP 64 +#define RX_WORK_PER_LOOP 64 /* * Hardware access: @@ -745,6 +747,9 @@ struct nv_skb_map { struct fe_priv { spinlock_t lock; + struct net_device *dev; + struct napi_struct napi; + /* General data: * Locking: spin_lock(&np->lock); */ struct net_device_stats stats; @@ -1586,9 +1591,10 @@ static int nv_alloc_rx_optimized(struct net_device *dev) static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); /* Just reschedule NAPI rx processing */ - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); } #else static void nv_do_rx_refill(unsigned long data) @@ -2997,7 +3003,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); /* Disable furthur receive irq's */ spin_lock(&np->lock); @@ -3010,7 +3016,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); } #else - if (nv_rx_process(dev, dev->weight)) { + if (nv_rx_process(dev, RX_WORK_PER_LOOP)) { if (unlikely(nv_alloc_rx(dev))) { spin_lock(&np->lock); if (!np->in_shutdown) @@ -3079,8 +3085,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data) return IRQ_RETVAL(i); } -#define TX_WORK_PER_LOOP 64 -#define RX_WORK_PER_LOOP 64 /** * All _optimized functions are used to help increase performance * (reduce CPU and increase throughput). They use descripter version 3, @@ -3114,7 +3118,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); /* Disable furthur receive irq's */ spin_lock(&np->lock); @@ -3127,7 +3131,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) spin_unlock(&np->lock); } #else - if (nv_rx_process_optimized(dev, dev->weight)) { + if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) { if (unlikely(nv_alloc_rx_optimized(dev))) { spin_lock(&np->lock); if (!np->in_shutdown) @@ -3245,19 +3249,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) } #ifdef CONFIG_FORCEDETH_NAPI -static int nv_napi_poll(struct net_device *dev, int *budget) +static int nv_napi_poll(struct napi_struct *napi, int budget) { - int pkts, limit = min(*budget, dev->quota); - struct fe_priv *np = netdev_priv(dev); + struct fe_priv *np = container_of(napi, struct fe_priv, napi); + struct net_device *dev = np->dev; u8 __iomem *base = get_hwbase(dev); unsigned long flags; - int retcode; + int pkts, retcode; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - pkts = nv_rx_process(dev, limit); + pkts = nv_rx_process(dev, budget); retcode = nv_alloc_rx(dev); } else { - pkts = nv_rx_process_optimized(dev, limit); + pkts = nv_rx_process_optimized(dev, budget); retcode = nv_alloc_rx_optimized(dev); } @@ -3268,13 +3272,12 @@ static int nv_napi_poll(struct net_device *dev, int *budget) spin_unlock_irqrestore(&np->lock, flags); } - if (pkts < limit) { - /* all done, no more packets present */ - netif_rx_complete(dev); - + if (pkts < budget) { /* re-enable receive interrupts */ spin_lock_irqsave(&np->lock, flags); + __netif_rx_complete(dev, napi); + np->irqmask |= NVREG_IRQ_RX_ALL; if (np->msi_flags & NV_MSI_X_ENABLED) writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); @@ -3282,13 +3285,8 @@ static int nv_napi_poll(struct net_device *dev, int *budget) writel(np->irqmask, base + NvRegIrqMask); spin_unlock_irqrestore(&np->lock, flags); - return 0; - } else { - /* used up our quantum, so reschedule */ - dev->quota -= pkts; - *budget -= pkts; - return 1; } + return pkts; } #endif @@ -3296,6 +3294,7 @@ static int nv_napi_poll(struct net_device *dev, int *budget) static irqreturn_t nv_nic_irq_rx(int foo, void *data) { struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 events; @@ -3303,7 +3302,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); if (events) { - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); /* disable receive interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); @@ -3329,7 +3328,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) if (!(events & np->irqmask)) break; - if (nv_rx_process_optimized(dev, dev->weight)) { + if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) { if (unlikely(nv_alloc_rx_optimized(dev))) { spin_lock_irqsave(&np->lock, flags); if (!np->in_shutdown) @@ -4620,7 +4619,9 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 if (test->flags & ETH_TEST_FL_OFFLINE) { if (netif_running(dev)) { netif_stop_queue(dev); - netif_poll_disable(dev); +#ifdef CONFIG_FORCEDETH_NAPI + napi_disable(&np->napi); +#endif netif_tx_lock_bh(dev); spin_lock_irq(&np->lock); nv_disable_hw_interrupts(dev, np->irqmask); @@ -4679,7 +4680,9 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 nv_start_rx(dev); nv_start_tx(dev); netif_start_queue(dev); - netif_poll_enable(dev); +#ifdef CONFIG_FORCEDETH_NAPI + napi_enable(&np->napi); +#endif nv_enable_hw_interrupts(dev, np->irqmask); } } @@ -4911,7 +4914,9 @@ static int nv_open(struct net_device *dev) nv_start_rx(dev); nv_start_tx(dev); netif_start_queue(dev); - netif_poll_enable(dev); +#ifdef CONFIG_FORCEDETH_NAPI + napi_enable(&np->napi); +#endif if (ret) { netif_carrier_on(dev); @@ -4942,7 +4947,9 @@ static int nv_close(struct net_device *dev) spin_lock_irq(&np->lock); np->in_shutdown = 1; spin_unlock_irq(&np->lock); - netif_poll_disable(dev); +#ifdef CONFIG_FORCEDETH_NAPI + napi_disable(&np->napi); +#endif synchronize_irq(dev->irq); del_timer_sync(&np->oom_kick); @@ -4994,6 +5001,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i goto out; np = netdev_priv(dev); + np->dev = dev; np->pci_dev = pci_dev; spin_lock_init(&np->lock); SET_MODULE_OWNER(dev); @@ -5155,9 +5163,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = nv_poll_controller; #endif - dev->weight = RX_WORK_PER_LOOP; #ifdef CONFIG_FORCEDETH_NAPI - dev->poll = nv_napi_poll; + netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP); #endif SET_ETHTOOL_OPS(dev, &ops); dev->tx_timeout = nv_tx_timeout; diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a4a2a0ea43d3..c509cb13222d 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -70,18 +70,16 @@ static void fs_set_multicast_list(struct net_device *dev) } /* NAPI receive function */ -static int fs_enet_rx_napi(struct net_device *dev, int *budget) +static int fs_enet_rx_napi(struct napi_struct *napi, int budget) { - struct fs_enet_private *fep = netdev_priv(dev); + struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); + struct net_device *dev = to_net_dev(fep->dev); const struct fs_platform_info *fpi = fep->fpi; cbd_t *bdp; struct sk_buff *skb, *skbn, *skbt; int received = 0; u16 pkt_len, sc; int curidx; - int rx_work_limit = 0; /* pacify gcc */ - - rx_work_limit = min(dev->quota, *budget); if (!netif_running(dev)) return 0; @@ -96,7 +94,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget) (*fep->ops->napi_clear_rx_event)(dev); while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { - curidx = bdp - fep->rx_bd_base; /* @@ -136,11 +133,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget) skbn = skb; } else { - - /* napi, got packet but no quota */ - if (--rx_work_limit < 0) - break; - skb = fep->rx_skbuff[curidx]; dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), @@ -199,22 +191,19 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget) bdp = fep->rx_bd_base; (*fep->ops->rx_bd_done)(dev); + + if (received >= budget) + break; } fep->cur_rx = bdp; - dev->quota -= received; - *budget -= received; - - if (rx_work_limit < 0) - return 1; /* not done */ - - /* done */ - netif_rx_complete(dev); - - (*fep->ops->napi_enable_rx)(dev); - - return 0; + if (received >= budget) { + /* done */ + netif_rx_complete(dev, napi); + (*fep->ops->napi_enable_rx)(dev); + } + return received; } /* non NAPI receive function */ @@ -470,7 +459,7 @@ fs_enet_interrupt(int irq, void *dev_id) if (!fpi->use_napi) fs_enet_rx_non_napi(dev); else { - napi_ok = netif_rx_schedule_prep(dev); + napi_ok = napi_schedule_prep(&fep->napi); (*fep->ops->napi_disable_rx)(dev); (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); @@ -478,7 +467,7 @@ fs_enet_interrupt(int irq, void *dev_id) /* NOTE: it is possible for FCCs in NAPI mode */ /* to submit a spurious interrupt while in poll */ if (napi_ok) - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &fep->napi); } } @@ -799,18 +788,22 @@ static int fs_enet_open(struct net_device *dev) int r; int err; + napi_enable(&fep->napi); + /* Install our interrupt handler. */ r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); if (r != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate FS_ENET IRQ!", dev->name); + napi_disable(&fep->napi); return -EINVAL; } err = fs_init_phy(dev); - if(err) + if(err) { + napi_disable(&fep->napi); return err; - + } phy_start(fep->phydev); return 0; @@ -823,6 +816,7 @@ static int fs_enet_close(struct net_device *dev) netif_stop_queue(dev); netif_carrier_off(dev); + napi_disable(&fep->napi); phy_stop(fep->phydev); spin_lock_irqsave(&fep->lock, flags); @@ -1047,10 +1041,9 @@ static struct net_device *fs_init_instance(struct device *dev, ndev->stop = fs_enet_close; ndev->get_stats = fs_enet_get_stats; ndev->set_multicast_list = fs_set_multicast_list; - if (fpi->use_napi) { - ndev->poll = fs_enet_rx_napi; - ndev->weight = fpi->napi_weight; - } + netif_napi_add(ndev, &fep->napi, + fs_enet_rx_napi, fpi->napi_weight); + ndev->ethtool_ops = &fs_ethtool_ops; ndev->do_ioctl = fs_ioctl; diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 569be225cd05..46d0606b1439 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -121,6 +121,7 @@ struct fs_enet_mii_bus { }; struct fs_enet_private { + struct napi_struct napi; struct device *dev; /* pointer back to the device (must be initialized first) */ spinlock_t lock; /* during all ops except TX pckt processing */ spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index f92690555dd9..bd2de325bbdd 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -134,7 +134,7 @@ static void gfar_configure_serdes(struct net_device *dev); extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value); extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum); #ifdef CONFIG_GFAR_NAPI -static int gfar_poll(struct net_device *dev, int *budget); +static int gfar_poll(struct napi_struct *napi, int budget); #endif #ifdef CONFIG_NET_POLL_CONTROLLER static void gfar_netpoll(struct net_device *dev); @@ -188,6 +188,7 @@ static int gfar_probe(struct platform_device *pdev) return -ENOMEM; priv = netdev_priv(dev); + priv->dev = dev; /* Set the info in the priv to the current info */ priv->einfo = einfo; @@ -261,10 +262,7 @@ static int gfar_probe(struct platform_device *pdev) dev->hard_start_xmit = gfar_start_xmit; dev->tx_timeout = gfar_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_GFAR_NAPI - dev->poll = gfar_poll; - dev->weight = GFAR_DEV_WEIGHT; -#endif + netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = gfar_netpoll; #endif @@ -939,6 +937,8 @@ static int gfar_enet_open(struct net_device *dev) { int err; + napi_enable(&priv->napi); + /* Initialize a bunch of registers */ init_registers(dev); @@ -946,10 +946,14 @@ static int gfar_enet_open(struct net_device *dev) err = init_phy(dev); - if(err) + if(err) { + napi_disable(&priv->napi); return err; + } err = startup_gfar(dev); + if (err) + napi_disable(&priv->napi); netif_start_queue(dev); @@ -1102,6 +1106,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + + napi_disable(&priv->napi); + stop_gfar(dev); /* Disconnect from the PHY */ @@ -1318,7 +1325,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) return NULL; alignamount = RXBUF_ALIGNMENT - - (((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1)); + (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1)); /* We need the data buffer to be aligned properly. We will reserve * as many bytes as needed to align the data properly @@ -1390,12 +1397,12 @@ irqreturn_t gfar_receive(int irq, void *dev_id) /* support NAPI */ #ifdef CONFIG_GFAR_NAPI - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &priv->napi)) { tempval = gfar_read(&priv->regs->imask); tempval &= IMASK_RX_DISABLED; gfar_write(&priv->regs->imask, tempval); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &priv->napi); } else { if (netif_msg_rx_err(priv)) printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n", @@ -1569,23 +1576,16 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) } #ifdef CONFIG_GFAR_NAPI -static int gfar_poll(struct net_device *dev, int *budget) +static int gfar_poll(struct napi_struct *napi, int budget) { + struct gfar_private *priv = container_of(napi, struct gfar_private, napi); + struct net_device *dev = priv->dev; int howmany; - struct gfar_private *priv = netdev_priv(dev); - int rx_work_limit = *budget; - if (rx_work_limit > dev->quota) - rx_work_limit = dev->quota; + howmany = gfar_clean_rx_ring(dev, budget); - howmany = gfar_clean_rx_ring(dev, rx_work_limit); - - dev->quota -= howmany; - rx_work_limit -= howmany; - *budget -= howmany; - - if (rx_work_limit > 0) { - netif_rx_complete(dev); + if (howmany < budget) { + netif_rx_complete(dev, napi); /* Clear the halt bit in RSTAT */ gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); @@ -1601,8 +1601,7 @@ static int gfar_poll(struct net_device *dev, int *budget) gfar_write(&priv->regs->rxic, 0); } - /* Return 1 if there's more work to do */ - return (rx_work_limit > 0) ? 0 : 1; + return howmany; } #endif diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index d8e779c102fa..b8714e00482d 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -691,6 +691,9 @@ struct gfar_private { /* RX Locked fields */ spinlock_t rxlock; + struct net_device *dev; + struct napi_struct napi; + /* skb array and index */ struct sk_buff ** rx_skbuff; u16 skb_currx; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index acba90f1638e..78e28ada1e21 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -83,7 +83,7 @@ static int ibmveth_open(struct net_device *dev); static int ibmveth_close(struct net_device *dev); static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int ibmveth_poll(struct net_device *dev, int *budget); +static int ibmveth_poll(struct napi_struct *napi, int budget); static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *ibmveth_get_stats(struct net_device *dev); static void ibmveth_set_multicast_list(struct net_device *dev); @@ -480,6 +480,8 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_debug_printk("open starting\n"); + napi_enable(&adapter->napi); + for(i = 0; irx_buff_pool[i].size; @@ -489,6 +491,7 @@ static int ibmveth_open(struct net_device *netdev) if(!adapter->buffer_list_addr || !adapter->filter_list_addr) { ibmveth_error_printk("unable to allocate filter or buffer list pages\n"); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENOMEM; } @@ -498,6 +501,7 @@ static int ibmveth_open(struct net_device *netdev) if(!adapter->rx_queue.queue_addr) { ibmveth_error_printk("unable to allocate rx queue pages\n"); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENOMEM; } @@ -514,6 +518,7 @@ static int ibmveth_open(struct net_device *netdev) (dma_mapping_error(adapter->rx_queue.queue_dma))) { ibmveth_error_printk("unable to map filter or buffer list pages\n"); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENOMEM; } @@ -545,6 +550,7 @@ static int ibmveth_open(struct net_device *netdev) rxq_desc.desc, mac_address); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENONET; } @@ -555,6 +561,7 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_error_printk("unable to alloc pool\n"); adapter->rx_buff_pool[i].active = 0; ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENOMEM ; } } @@ -567,6 +574,7 @@ static int ibmveth_open(struct net_device *netdev) } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return rc; } @@ -587,6 +595,8 @@ static int ibmveth_close(struct net_device *netdev) ibmveth_debug_printk("close starting\n"); + napi_disable(&adapter->napi); + if (!adapter->pool_config) netif_stop_queue(netdev); @@ -767,80 +777,68 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags); return 0; } -static int ibmveth_poll(struct net_device *netdev, int *budget) +static int ibmveth_poll(struct napi_struct *napi, int budget) { - struct ibmveth_adapter *adapter = netdev->priv; - int max_frames_to_process = netdev->quota; + struct ibmveth_adapter *adapter = container_of(napi, struct ibmveth_adapter, napi); + struct net_device *netdev = adapter->netdev; int frames_processed = 0; - int more_work = 1; unsigned long lpar_rc; restart_poll: do { - struct net_device *netdev = adapter->netdev; + struct sk_buff *skb; - if(ibmveth_rxq_pending_buffer(adapter)) { - struct sk_buff *skb; + if (!ibmveth_rxq_pending_buffer(adapter)) + break; - rmb(); - - if(!ibmveth_rxq_buffer_valid(adapter)) { - wmb(); /* suggested by larson1 */ - adapter->rx_invalid_buffer++; - ibmveth_debug_printk("recycling invalid buffer\n"); - ibmveth_rxq_recycle_buffer(adapter); - } else { - int length = ibmveth_rxq_frame_length(adapter); - int offset = ibmveth_rxq_frame_offset(adapter); - skb = ibmveth_rxq_get_buffer(adapter); - - ibmveth_rxq_harvest_buffer(adapter); - - skb_reserve(skb, offset); - skb_put(skb, length); - skb->protocol = eth_type_trans(skb, netdev); - - netif_receive_skb(skb); /* send it up */ - - adapter->stats.rx_packets++; - adapter->stats.rx_bytes += length; - frames_processed++; - netdev->last_rx = jiffies; - } + rmb(); + if (!ibmveth_rxq_buffer_valid(adapter)) { + wmb(); /* suggested by larson1 */ + adapter->rx_invalid_buffer++; + ibmveth_debug_printk("recycling invalid buffer\n"); + ibmveth_rxq_recycle_buffer(adapter); } else { - more_work = 0; + int length = ibmveth_rxq_frame_length(adapter); + int offset = ibmveth_rxq_frame_offset(adapter); + skb = ibmveth_rxq_get_buffer(adapter); + + ibmveth_rxq_harvest_buffer(adapter); + + skb_reserve(skb, offset); + skb_put(skb, length); + skb->protocol = eth_type_trans(skb, netdev); + + netif_receive_skb(skb); /* send it up */ + + adapter->stats.rx_packets++; + adapter->stats.rx_bytes += length; + frames_processed++; + netdev->last_rx = jiffies; } - } while(more_work && (frames_processed < max_frames_to_process)); + } while (frames_processed < budget); ibmveth_replenish_task(adapter); - if(more_work) { - /* more work to do - return that we are not done yet */ - netdev->quota -= frames_processed; - *budget -= frames_processed; - return 1; - } + if (frames_processed < budget) { + /* We think we are done - reenable interrupts, + * then check once more to make sure we are done. + */ + lpar_rc = h_vio_signal(adapter->vdev->unit_address, + VIO_IRQ_ENABLE); - /* we think we are done - reenable interrupts, then check once more to make sure we are done */ - lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_ENABLE); - - ibmveth_assert(lpar_rc == H_SUCCESS); - - netif_rx_complete(netdev); - - if(ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, frames_processed)) - { - lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); ibmveth_assert(lpar_rc == H_SUCCESS); - more_work = 1; - goto restart_poll; + + netif_rx_complete(netdev, napi); + + if (ibmveth_rxq_pending_buffer(adapter) && + netif_rx_reschedule(netdev, napi)) { + lpar_rc = h_vio_signal(adapter->vdev->unit_address, + VIO_IRQ_DISABLE); + goto restart_poll; + } } - netdev->quota -= frames_processed; - *budget -= frames_processed; - - /* we really are done */ - return 0; + return frames_processed; } static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) @@ -849,10 +847,11 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) struct ibmveth_adapter *adapter = netdev->priv; unsigned long lpar_rc; - if(netif_rx_schedule_prep(netdev)) { - lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + lpar_rc = h_vio_signal(adapter->vdev->unit_address, + VIO_IRQ_DISABLE); ibmveth_assert(lpar_rc == H_SUCCESS); - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } return IRQ_HANDLED; } @@ -1004,6 +1003,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ adapter->mcastFilterSize= *mcastFilterSize_p; adapter->pool_config = 0; + netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16); + /* Some older boxes running PHYP non-natively have an OF that returns a 8-byte local-mac-address field (and the first 2 bytes have to be ignored) while newer boxes' OF return @@ -1020,8 +1021,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->irq = dev->irq; netdev->open = ibmveth_open; - netdev->poll = ibmveth_poll; - netdev->weight = 16; netdev->stop = ibmveth_close; netdev->hard_start_xmit = ibmveth_start_xmit; netdev->get_stats = ibmveth_get_stats; diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 72cc15a6cab7..e05694126f85 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -112,6 +112,7 @@ struct ibmveth_rx_q { struct ibmveth_adapter { struct vio_dev *vdev; struct net_device *netdev; + struct napi_struct napi; struct net_device_stats stats; unsigned int mcastFilterSize; unsigned long mac_addr; diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 3569d5b03388..1eee8894c732 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -184,6 +184,7 @@ struct ixgb_adapter { boolean_t rx_csum; /* OS defined structs */ + struct napi_struct napi; struct net_device *netdev; struct pci_dev *pdev; struct net_device_stats net_stats; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 991c8833e23c..e3f27c67fb28 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -97,7 +97,7 @@ static irqreturn_t ixgb_intr(int irq, void *data); static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter); #ifdef CONFIG_IXGB_NAPI -static int ixgb_clean(struct net_device *netdev, int *budget); +static int ixgb_clean(struct napi_struct *napi, int budget); static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do); #else @@ -288,7 +288,7 @@ ixgb_up(struct ixgb_adapter *adapter) mod_timer(&adapter->watchdog_timer, jiffies); #ifdef CONFIG_IXGB_NAPI - netif_poll_enable(netdev); + napi_enable(&adapter->napi); #endif ixgb_irq_enable(adapter); @@ -309,7 +309,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) if(kill_watchdog) del_timer_sync(&adapter->watchdog_timer); #ifdef CONFIG_IXGB_NAPI - netif_poll_disable(netdev); + napi_disable(&adapter->napi); #endif adapter->link_speed = 0; adapter->link_duplex = 0; @@ -421,8 +421,7 @@ ixgb_probe(struct pci_dev *pdev, netdev->tx_timeout = &ixgb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; #ifdef CONFIG_IXGB_NAPI - netdev->poll = &ixgb_clean; - netdev->weight = 64; + netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64); #endif netdev->vlan_rx_register = ixgb_vlan_rx_register; netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid; @@ -1746,7 +1745,7 @@ ixgb_intr(int irq, void *data) } #ifdef CONFIG_IXGB_NAPI - if(netif_rx_schedule_prep(netdev)) { + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { /* Disable interrupts and register for poll. The flush of the posted write is intentionally left out. @@ -1754,7 +1753,7 @@ ixgb_intr(int irq, void *data) atomic_inc(&adapter->irq_sem); IXGB_WRITE_REG(&adapter->hw, IMC, ~0); - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } #else /* yes, that is actually a & and it is meant to make sure that @@ -1776,27 +1775,23 @@ ixgb_intr(int irq, void *data) **/ static int -ixgb_clean(struct net_device *netdev, int *budget) +ixgb_clean(struct napi_struct *napi, int budget) { - struct ixgb_adapter *adapter = netdev_priv(netdev); - int work_to_do = min(*budget, netdev->quota); + struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi); + struct net_device *netdev = adapter->netdev; int tx_cleaned; int work_done = 0; tx_cleaned = ixgb_clean_tx_irq(adapter); - ixgb_clean_rx_irq(adapter, &work_done, work_to_do); - - *budget -= work_done; - netdev->quota -= work_done; + ixgb_clean_rx_irq(adapter, &work_done, budget); /* if no Tx and not enough Rx work done, exit the polling mode */ if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); ixgb_irq_enable(adapter); - return 0; } - return 1; + return work_done; } #endif diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index d9ce1aef148a..6c0dd49149d0 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -74,9 +74,9 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) } -static int ixpdev_rx(struct net_device *dev, int *budget) +static int ixpdev_rx(struct net_device *dev, int processed, int budget) { - while (*budget > 0) { + while (processed < budget) { struct ixpdev_rx_desc *desc; struct sk_buff *skb; void *buf; @@ -122,29 +122,34 @@ static int ixpdev_rx(struct net_device *dev, int *budget) err: ixp2000_reg_write(RING_RX_PENDING, _desc); - dev->quota--; - (*budget)--; + processed++; } - return 1; + return processed; } /* dev always points to nds[0]. */ -static int ixpdev_poll(struct net_device *dev, int *budget) +static int ixpdev_poll(struct napi_struct *napi, int budget) { + struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi); + struct net_device *dev = ip->dev; + int rx; + /* @@@ Have to stop polling when nds[0] is administratively * downed while we are polling. */ + rx = 0; do { ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff); - if (ixpdev_rx(dev, budget)) - return 1; + rx = ixpdev_rx(dev, rx, budget); + if (rx >= budget) + break; } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); - return 0; + return rx; } static void ixpdev_tx_complete(void) @@ -199,9 +204,12 @@ static irqreturn_t ixpdev_interrupt(int irq, void *dev_id) * Any of the eight receive units signaled RX? */ if (status & 0x00ff) { + struct net_device *dev = nds[0]; + struct ixpdev_priv *ip = netdev_priv(dev); + ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); - if (likely(__netif_rx_schedule_prep(nds[0]))) { - __netif_rx_schedule(nds[0]); + if (likely(napi_schedule_prep(&ip->napi))) { + __netif_rx_schedule(dev, &ip->napi); } else { printk(KERN_CRIT "ixp2000: irq while polling!!\n"); } @@ -232,11 +240,13 @@ static int ixpdev_open(struct net_device *dev) struct ixpdev_priv *ip = netdev_priv(dev); int err; + napi_enable(&ip->napi); if (!nds_open++) { err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt, IRQF_SHARED, "ixp2000_eth", nds); if (err) { nds_open--; + napi_disable(&ip->napi); return err; } @@ -254,6 +264,7 @@ static int ixpdev_close(struct net_device *dev) struct ixpdev_priv *ip = netdev_priv(dev); netif_stop_queue(dev); + napi_disable(&ip->napi); set_port_admin_status(ip->channel, 0); if (!--nds_open) { @@ -274,7 +285,6 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv) return NULL; dev->hard_start_xmit = ixpdev_xmit; - dev->poll = ixpdev_poll; dev->open = ixpdev_open; dev->stop = ixpdev_close; #ifdef CONFIG_NET_POLL_CONTROLLER @@ -282,9 +292,10 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv) #endif dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - dev->weight = 64; ip = netdev_priv(dev); + ip->dev = dev; + netif_napi_add(dev, &ip->napi, ixpdev_poll, 64); ip->channel = channel; ip->tx_queue_entries = 0; diff --git a/drivers/net/ixp2000/ixpdev.h b/drivers/net/ixp2000/ixpdev.h index bd686cb63058..391ece623243 100644 --- a/drivers/net/ixp2000/ixpdev.h +++ b/drivers/net/ixp2000/ixpdev.h @@ -14,6 +14,8 @@ struct ixpdev_priv { + struct net_device *dev; + struct napi_struct napi; int channel; int tx_queue_entries; }; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index a4bb0264180a..74c3f7a7ae4a 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -470,47 +470,41 @@ static int macb_rx(struct macb *bp, int budget) return received; } -static int macb_poll(struct net_device *dev, int *budget) +static int macb_poll(struct napi_struct *napi, int budget) { - struct macb *bp = netdev_priv(dev); - int orig_budget, work_done, retval = 0; + struct macb *bp = container_of(napi, struct macb, napi); + struct net_device *dev = bp->dev; + int work_done; u32 status; status = macb_readl(bp, RSR); macb_writel(bp, RSR, status); + work_done = 0; if (!status) { /* * This may happen if an interrupt was pending before * this function was called last time, and no packets * have been received since. */ - netif_rx_complete(dev); + netif_rx_complete(dev, napi); goto out; } dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n", - (unsigned long)status, *budget); + (unsigned long)status, budget); if (!(status & MACB_BIT(REC))) { dev_warn(&bp->pdev->dev, "No RX buffers complete, status = %02lx\n", (unsigned long)status); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); goto out; } - orig_budget = *budget; - if (orig_budget > dev->quota) - orig_budget = dev->quota; - - work_done = macb_rx(bp, orig_budget); - if (work_done < orig_budget) { - netif_rx_complete(dev); - retval = 0; - } else { - retval = 1; - } + work_done = macb_rx(bp, budget); + if (work_done < budget) + netif_rx_complete(dev, napi); /* * We've done what we can to clean the buffers. Make sure we @@ -521,7 +515,7 @@ out: /* TODO: Handle errors */ - return retval; + return work_done; } static irqreturn_t macb_interrupt(int irq, void *dev_id) @@ -545,7 +539,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) } if (status & MACB_RX_INT_FLAGS) { - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &bp->napi)) { /* * There's no point taking any more interrupts * until we have processed the buffers @@ -553,7 +547,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) macb_writel(bp, IDR, MACB_RX_INT_FLAGS); dev_dbg(&bp->pdev->dev, "scheduling RX softirq\n"); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &bp->napi); } } @@ -937,6 +931,8 @@ static int macb_open(struct net_device *dev) return err; } + napi_enable(&bp->napi); + macb_init_rings(bp); macb_init_hw(bp); @@ -954,6 +950,7 @@ static int macb_close(struct net_device *dev) unsigned long flags; netif_stop_queue(dev); + napi_disable(&bp->napi); if (bp->phy_dev) phy_stop(bp->phy_dev); @@ -1146,8 +1143,7 @@ static int __devinit macb_probe(struct platform_device *pdev) dev->get_stats = macb_get_stats; dev->set_multicast_list = macb_set_rx_mode; dev->do_ioctl = macb_ioctl; - dev->poll = macb_poll; - dev->weight = 64; + netif_napi_add(dev, &bp->napi, macb_poll, 64); dev->ethtool_ops = &macb_ethtool_ops; dev->base_addr = regs->start; diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 4e3283ebd97c..57b85acf0d16 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -374,6 +374,7 @@ struct macb { struct clk *pclk; struct clk *hclk; struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; struct macb_stats hw_stats; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 315335671f0f..702eba549161 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -66,7 +66,7 @@ static int mv643xx_eth_change_mtu(struct net_device *, int); static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *); static void eth_port_init_mac_tables(unsigned int eth_port_num); #ifdef MV643XX_NAPI -static int mv643xx_poll(struct net_device *dev, int *budget); +static int mv643xx_poll(struct napi_struct *napi, int budget); #endif static int ethernet_phy_get(unsigned int eth_port_num); static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); @@ -562,7 +562,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) /* wait for previous write to complete */ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &mp->napi); } #else if (eth_int_cause & ETH_INT_CAUSE_RX) @@ -880,6 +880,10 @@ static int mv643xx_eth_open(struct net_device *dev) mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */ +#ifdef MV643XX_NAPI + napi_enable(&mp->napi); +#endif + eth_port_start(dev); /* Interrupt Coalescing */ @@ -982,7 +986,7 @@ static int mv643xx_eth_stop(struct net_device *dev) mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); #ifdef MV643XX_NAPI - netif_poll_disable(dev); + napi_disable(&mp->napi); #endif netif_carrier_off(dev); netif_stop_queue(dev); @@ -992,10 +996,6 @@ static int mv643xx_eth_stop(struct net_device *dev) mv643xx_eth_free_tx_rings(dev); mv643xx_eth_free_rx_rings(dev); -#ifdef MV643XX_NAPI - netif_poll_enable(dev); -#endif - free_irq(dev->irq, dev); return 0; @@ -1007,11 +1007,12 @@ static int mv643xx_eth_stop(struct net_device *dev) * * This function is used in case of NAPI */ -static int mv643xx_poll(struct net_device *dev, int *budget) +static int mv643xx_poll(struct napi_struct *napi, int budget) { - struct mv643xx_private *mp = netdev_priv(dev); - int done = 1, orig_budget, work_done; + struct mv643xx_private *mp = container_of(napi, struct mv643xx_private, napi); + struct net_device *dev = mp->dev; unsigned int port_num = mp->port_num; + int work_done; #ifdef MV643XX_TX_FAST_REFILL if (++mp->tx_clean_threshold > 5) { @@ -1020,27 +1021,20 @@ static int mv643xx_poll(struct net_device *dev, int *budget) } #endif + work_done = 0; if ((mv_read(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num))) - != (u32) mp->rx_used_desc_q) { - orig_budget = *budget; - if (orig_budget > dev->quota) - orig_budget = dev->quota; - work_done = mv643xx_eth_receive_queue(dev, orig_budget); - *budget -= work_done; - dev->quota -= work_done; - if (work_done >= orig_budget) - done = 0; - } + != (u32) mp->rx_used_desc_q) + work_done = mv643xx_eth_receive_queue(dev, budget); - if (done) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL); } - return done ? 0 : 1; + return work_done; } #endif @@ -1333,6 +1327,10 @@ static int mv643xx_eth_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); mp = netdev_priv(dev); + mp->dev = dev; +#ifdef MV643XX_NAPI + netif_napi_add(dev, &mp->napi, mv643xx_poll, 64); +#endif res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); BUG_ON(!res); @@ -1347,10 +1345,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) /* No need to Tx Timeout */ dev->tx_timeout = mv643xx_eth_tx_timeout; -#ifdef MV643XX_NAPI - dev->poll = mv643xx_poll; - dev->weight = 64; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = mv643xx_netpoll; diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 565b96696aca..be669eb23788 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -320,6 +320,8 @@ struct mv643xx_private { struct work_struct tx_timeout_task; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; struct mv643xx_mib_counters mib_counters; spinlock_t lock; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 556962f9612d..a30146ea51f0 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -163,6 +163,7 @@ struct myri10ge_priv { int small_bytes; int big_bytes; struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; u8 __iomem *sram; int sram_size; @@ -1100,7 +1101,7 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index) } } -static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) +static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget) { struct myri10ge_rx_done *rx_done = &mgp->rx_done; unsigned long rx_bytes = 0; @@ -1109,10 +1110,11 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) int idx = rx_done->idx; int cnt = rx_done->cnt; + int work_done = 0; u16 length; __wsum checksum; - while (rx_done->entry[idx].length != 0 && *limit != 0) { + while (rx_done->entry[idx].length != 0 && work_done++ < budget) { length = ntohs(rx_done->entry[idx].length); rx_done->entry[idx].length = 0; checksum = csum_unfold(rx_done->entry[idx].checksum); @@ -1128,10 +1130,6 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) rx_bytes += rx_ok * (unsigned long)length; cnt++; idx = cnt & (myri10ge_max_intr_slots - 1); - - /* limit potential for livelock by only handling a - * limited number of frames. */ - (*limit)--; } rx_done->idx = idx; rx_done->cnt = cnt; @@ -1145,6 +1143,7 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh) myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0); + return work_done; } static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) @@ -1189,26 +1188,21 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) } } -static int myri10ge_poll(struct net_device *netdev, int *budget) +static int myri10ge_poll(struct napi_struct *napi, int budget) { - struct myri10ge_priv *mgp = netdev_priv(netdev); + struct myri10ge_priv *mgp = container_of(napi, struct myri10ge_priv, napi); + struct net_device *netdev = mgp->dev; struct myri10ge_rx_done *rx_done = &mgp->rx_done; - int limit, orig_limit, work_done; + int work_done; /* process as many rx events as NAPI will allow */ - limit = min(*budget, netdev->quota); - orig_limit = limit; - myri10ge_clean_rx_done(mgp, &limit); - work_done = orig_limit - limit; - *budget -= work_done; - netdev->quota -= work_done; + work_done = myri10ge_clean_rx_done(mgp, budget); if (rx_done->entry[rx_done->idx].length == 0 || !netif_running(netdev)) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); put_be32(htonl(3), mgp->irq_claim); - return 0; } - return 1; + return work_done; } static irqreturn_t myri10ge_intr(int irq, void *arg) @@ -1226,7 +1220,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) /* low bit indicates receives are present, so schedule * napi poll handler */ if (stats->valid & 1) - netif_rx_schedule(mgp->dev); + netif_rx_schedule(mgp->dev, &mgp->napi); if (!mgp->msi_enabled) { put_be32(0, mgp->irq_deassert); @@ -1853,7 +1847,7 @@ static int myri10ge_open(struct net_device *dev) mgp->link_state = htonl(~0U); mgp->rdma_tags_available = 15; - netif_poll_enable(mgp->dev); /* must happen prior to any irq */ + napi_enable(&mgp->napi); /* must happen prior to any irq */ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); if (status) { @@ -1897,7 +1891,7 @@ static int myri10ge_close(struct net_device *dev) del_timer_sync(&mgp->watchdog_timer); mgp->running = MYRI10GE_ETH_STOPPING; - netif_poll_disable(mgp->dev); + napi_disable(&mgp->napi); netif_carrier_off(dev); netif_stop_queue(dev); old_down_cnt = mgp->down_cnt; @@ -2857,6 +2851,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp = netdev_priv(netdev); memset(mgp, 0, sizeof(*mgp)); mgp->dev = netdev; + netif_napi_add(netdev, &mgp->napi, + myri10ge_poll, myri10ge_napi_weight); mgp->pdev = pdev; mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; @@ -2981,8 +2977,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; - netdev->poll = myri10ge_poll; - netdev->weight = myri10ge_napi_weight; /* make sure we can get an irq, and that MSI can be * setup (if available). Also ensure netdev->irq diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index b47a12d684f9..43cfa4b3e294 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -560,6 +560,8 @@ struct netdev_private { /* address of a sent-in-place packet/buffer, for later free() */ struct sk_buff *tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_dma[TX_RING_SIZE]; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; /* Media monitoring timer */ struct timer_list timer; @@ -636,7 +638,7 @@ static void init_registers(struct net_device *dev); static int 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 net_device *dev, int *budget); +static int natsemi_poll(struct napi_struct *napi, int budget); static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do); static void netdev_tx_done(struct net_device *dev); static int natsemi_change_mtu(struct net_device *dev, int new_mtu); @@ -861,6 +863,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev->irq = irq; np = netdev_priv(dev); + netif_napi_add(dev, &np->napi, natsemi_poll, 64); np->pci_dev = pdev; pci_set_drvdata(pdev, dev); @@ -931,8 +934,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->poll = natsemi_poll; - dev->weight = 64; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &natsemi_poll_controller; @@ -1554,6 +1555,8 @@ static int netdev_open(struct net_device *dev) free_irq(dev->irq, dev); return i; } + napi_enable(&np->napi); + init_ring(dev); spin_lock_irq(&np->lock); init_registers(dev); @@ -2200,10 +2203,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]); - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &np->napi)) { /* Disable interrupts and register for poll */ natsemi_irq_disable(dev); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &np->napi); } else printk(KERN_WARNING "%s: Ignoring interrupt, status %#08x, mask %#08x.\n", @@ -2216,12 +2219,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) /* This is the NAPI poll routine. As well as the standard RX handling * it also handles all other interrupts that the chip might raise. */ -static int natsemi_poll(struct net_device *dev, int *budget) +static int natsemi_poll(struct napi_struct *napi, int budget) { - struct netdev_private *np = netdev_priv(dev); + struct netdev_private *np = container_of(napi, struct netdev_private, napi); + struct net_device *dev = np->dev; void __iomem * ioaddr = ns_ioaddr(dev); - - int work_to_do = min(*budget, dev->quota); int work_done = 0; do { @@ -2236,7 +2238,7 @@ static int natsemi_poll(struct net_device *dev, int *budget) if (np->intr_status & (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | IntrRxErr | IntrRxOverrun)) { - netdev_rx(dev, &work_done, work_to_do); + netdev_rx(dev, &work_done, budget); } if (np->intr_status & @@ -2250,16 +2252,13 @@ static int natsemi_poll(struct net_device *dev, int *budget) if (np->intr_status & IntrAbnormalSummary) netdev_error(dev, np->intr_status); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done >= work_to_do) - return 1; + if (work_done >= budget) + return work_done; np->intr_status = readl(ioaddr + IntrStatus); } while (np->intr_status); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); /* Reenable interrupts providing nothing is trying to shut * the chip down. */ @@ -2268,7 +2267,7 @@ static int natsemi_poll(struct net_device *dev, int *budget) natsemi_irq_enable(dev); spin_unlock(&np->lock); - return 0; + return work_done; } /* This routine is logically part of the interrupt handler, but separated @@ -3158,6 +3157,8 @@ static int netdev_close(struct net_device *dev) dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + napi_disable(&np->napi); + /* * FIXME: what if someone tries to close a device * that is suspended? @@ -3253,7 +3254,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) * disable_irq() to enforce synchronization. * * natsemi_poll: checks before reenabling interrupts. suspend * sets hands_off, disables interrupts and then waits with - * netif_poll_disable(). + * napi_disable(). * * Interrupts must be disabled, otherwise hands_off can cause irq storms. */ @@ -3279,7 +3280,7 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state) spin_unlock_irq(&np->lock); enable_irq(dev->irq); - netif_poll_disable(dev); + napi_disable(&np->napi); /* Update the error counts. */ __get_stats(dev); @@ -3320,6 +3321,8 @@ static int natsemi_resume (struct pci_dev *pdev) pci_enable_device(pdev); /* pci_power_on(pdev); */ + napi_enable(&np->napi); + natsemi_reset(dev); init_ring(dev); disable_irq(dev->irq); @@ -3333,7 +3336,6 @@ static int natsemi_resume (struct pci_dev *pdev) mod_timer(&np->timer, jiffies + 1*HZ); } netif_device_attach(dev); - netif_poll_enable(dev); out: rtnl_unlock(); return 0; diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d4c92cc879d4..aaa34939485b 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -880,6 +880,7 @@ struct netxen_adapter { struct netxen_adapter *master; struct net_device *netdev; struct pci_dev *pdev; + struct napi_struct napi; struct net_device_stats net_stats; unsigned char mac_addr[ETH_ALEN]; int mtu; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 3122d0101638..a10bbefbdadd 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -68,7 +68,7 @@ static void netxen_tx_timeout(struct net_device *netdev); static void netxen_tx_timeout_task(struct work_struct *work); static void netxen_watchdog(unsigned long); static int netxen_handle_int(struct netxen_adapter *, struct net_device *); -static int netxen_nic_poll(struct net_device *dev, int *budget); +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 @@ -402,6 +402,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->netdev = netdev; adapter->pdev = pdev; + netif_napi_add(netdev, &adapter->napi, + netxen_nic_poll, NETXEN_NETDEV_WEIGHT); + /* this will be read from FW later */ adapter->intr_scheme = -1; @@ -422,8 +425,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netxen_nic_change_mtu(netdev, netdev->mtu); SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); - netdev->poll = netxen_nic_poll; - netdev->weight = NETXEN_NETDEV_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = netxen_nic_poll_controller; #endif @@ -885,6 +886,8 @@ static int netxen_nic_open(struct net_device *netdev) if (!adapter->driver_mismatch) mod_timer(&adapter->watchdog_timer, jiffies); + napi_enable(&adapter->napi); + netxen_nic_enable_int(adapter); /* Done here again so that even if phantom sw overwrote it, @@ -894,6 +897,7 @@ static int netxen_nic_open(struct net_device *netdev) del_timer_sync(&adapter->watchdog_timer); printk(KERN_ERR "%s: Failed to initialize port %d\n", netxen_nic_driver_name, adapter->portnum); + napi_disable(&adapter->napi); return -EIO; } if (adapter->macaddr_set) @@ -923,6 +927,7 @@ static int netxen_nic_close(struct net_device *netdev) netif_carrier_off(netdev); netif_stop_queue(netdev); + napi_disable(&adapter->napi); netxen_nic_disable_int(adapter); @@ -1243,11 +1248,11 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) netxen_nic_disable_int(adapter); if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) { - if (netif_rx_schedule_prep(netdev)) { + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { /* * Interrupts are already disabled. */ - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } else { static unsigned int intcount = 0; if ((++intcount & 0xfff) == 0xfff) @@ -1305,14 +1310,13 @@ irqreturn_t netxen_intr(int irq, void *data) return IRQ_HANDLED; } -static int netxen_nic_poll(struct net_device *netdev, int *budget) +static int netxen_nic_poll(struct napi_struct *napi, int budget) { - struct netxen_adapter *adapter = netdev_priv(netdev); - int work_to_do = min(*budget, netdev->quota); + struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi); + struct net_device *netdev = adapter->netdev; int done = 1; int ctx; - int this_work_done; - int work_done = 0; + int work_done; DPRINTK(INFO, "polling for %d descriptors\n", *budget); @@ -1330,16 +1334,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) * packets are on one context, it gets only half of the quota, * and ends up not processing it. */ - this_work_done = netxen_process_rcv_ring(adapter, ctx, - work_to_do / - MAX_RCV_CTX); - work_done += this_work_done; + work_done += netxen_process_rcv_ring(adapter, ctx, + budget / MAX_RCV_CTX); } - netdev->quota -= work_done; - *budget -= work_done; - - if (work_done >= work_to_do && netxen_nic_rx_has_work(adapter) != 0) + if (work_done >= budget && netxen_nic_rx_has_work(adapter) != 0) done = 0; if (netxen_process_cmd_ring((unsigned long)adapter) == 0) @@ -1348,11 +1347,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) DPRINTK(INFO, "new work_done: %d work_to_do: %d\n", work_done, work_to_do); if (done) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); netxen_nic_enable_int(adapter); } - return !done; + return work_done; } #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 0b3066a6fe40..e63cc335a4ba 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -584,7 +584,7 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) if (*mac->rx_status & PAS_STATUS_TIMER) reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; - netif_rx_schedule(dev); + netif_rx_schedule(dev, &mac->napi); pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); @@ -808,7 +808,7 @@ static int pasemi_mac_open(struct net_device *dev) dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret); netif_start_queue(dev); - netif_poll_enable(dev); + napi_enable(&mac->napi); /* Interrupts are a bit different for our DMA controller: While * it's got one a regular PCI device header, the interrupt there @@ -845,7 +845,7 @@ static int pasemi_mac_open(struct net_device *dev) out_rx_int: free_irq(mac->tx_irq, dev); out_tx_int: - netif_poll_disable(dev); + napi_disable(&mac->napi); netif_stop_queue(dev); pasemi_mac_free_tx_resources(dev); out_tx_resources: @@ -869,6 +869,7 @@ static int pasemi_mac_close(struct net_device *dev) } netif_stop_queue(dev); + napi_disable(&mac->napi); /* Clean out any pending buffers */ pasemi_mac_clean_tx(mac); @@ -1047,26 +1048,20 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev) } -static int pasemi_mac_poll(struct net_device *dev, int *budget) +static int pasemi_mac_poll(struct napi_struct *napi, int budget) { - int pkts, limit = min(*budget, dev->quota); - struct pasemi_mac *mac = netdev_priv(dev); + struct pasemi_mac *mac = container_of(napi, struct pasemi_mac, napi); + struct net_device *dev = mac->netdev; + int pkts; - pkts = pasemi_mac_clean_rx(mac, limit); - - dev->quota -= pkts; - *budget -= pkts; - - if (pkts < limit) { + pkts = pasemi_mac_clean_rx(mac, budget); + if (pkts < budget) { /* all done, no more packets present */ - netif_rx_complete(dev); + netif_rx_complete(dev, napi); pasemi_mac_restart_rx_intr(mac); - return 0; - } else { - /* used up our quantum, so reschedule */ - return 1; } + return pkts; } static int __devinit @@ -1099,6 +1094,10 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mac->netdev = dev; mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); + netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); + + dev->features = NETIF_F_HW_CSUM; + if (!mac->dma_pdev) { dev_err(&pdev->dev, "Can't find DMA Controller\n"); err = -ENODEV; @@ -1150,9 +1149,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->hard_start_xmit = pasemi_mac_start_tx; dev->get_stats = pasemi_mac_get_stats; dev->set_multicast_list = pasemi_mac_set_rx_mode; - dev->weight = 64; - dev->poll = pasemi_mac_poll; - dev->features = NETIF_F_HW_CSUM; /* The dma status structure is located in the I/O bridge, and * is cache coherent. diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index c29ee159c33d..85d3b7856e5f 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -56,6 +56,7 @@ struct pasemi_mac { struct pci_dev *dma_pdev; struct pci_dev *iob_pdev; struct phy_device *phydev; + struct napi_struct napi; struct net_device_stats stats; /* Pointer to the cacheable per-channel status registers */ diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index e6a67531de99..a9973490dba9 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -280,6 +280,8 @@ struct pcnet32_private { unsigned int dirty_rx, /* ring entries to be freed. */ dirty_tx; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; char tx_full; char phycount; /* number of phys found */ @@ -440,15 +442,21 @@ static struct pcnet32_access pcnet32_dwio = { static void pcnet32_netif_stop(struct net_device *dev) { + struct pcnet32_private *lp = netdev_priv(dev); dev->trans_start = jiffies; - netif_poll_disable(dev); +#ifdef CONFIG_PCNET32_NAPI + napi_disable(&lp->napi); +#endif netif_tx_disable(dev); } static void pcnet32_netif_start(struct net_device *dev) { + struct pcnet32_private *lp = netdev_priv(dev); netif_wake_queue(dev); - netif_poll_enable(dev); +#ifdef CONFIG_PCNET32_NAPI + napi_enable(&lp->napi); +#endif } /* @@ -816,7 +824,7 @@ static int pcnet32_set_ringparam(struct net_device *dev, if ((1 << i) != lp->rx_ring_size) pcnet32_realloc_rx_ring(dev, lp, i); - dev->weight = lp->rx_ring_size / 2; + lp->napi.weight = lp->rx_ring_size / 2; if (netif_running(dev)) { pcnet32_netif_start(dev); @@ -1255,7 +1263,7 @@ static void pcnet32_rx_entry(struct net_device *dev, return; } -static int pcnet32_rx(struct net_device *dev, int quota) +static int pcnet32_rx(struct net_device *dev, int budget) { struct pcnet32_private *lp = netdev_priv(dev); int entry = lp->cur_rx & lp->rx_mod_mask; @@ -1263,7 +1271,7 @@ static int pcnet32_rx(struct net_device *dev, int quota) int npackets = 0; /* If we own the next entry, it's a new packet. Send it up. */ - while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) { + while (npackets < budget && (short)le16_to_cpu(rxp->status) >= 0) { pcnet32_rx_entry(dev, lp, rxp, entry); npackets += 1; /* @@ -1379,15 +1387,16 @@ static int pcnet32_tx(struct net_device *dev) } #ifdef CONFIG_PCNET32_NAPI -static int pcnet32_poll(struct net_device *dev, int *budget) +static int pcnet32_poll(struct napi_struct *napi, int budget) { - struct pcnet32_private *lp = netdev_priv(dev); - int quota = min(dev->quota, *budget); + struct pcnet32_private *lp = container_of(napi, struct pcnet32_private, napi); + struct net_device *dev = lp->dev; unsigned long ioaddr = dev->base_addr; unsigned long flags; + int work_done; u16 val; - quota = pcnet32_rx(dev, quota); + work_done = pcnet32_rx(dev, budget); spin_lock_irqsave(&lp->lock, flags); if (pcnet32_tx(dev)) { @@ -1399,28 +1408,22 @@ static int pcnet32_poll(struct net_device *dev, int *budget) } spin_unlock_irqrestore(&lp->lock, flags); - *budget -= quota; - dev->quota -= quota; + if (work_done < budget) { + spin_lock_irqsave(&lp->lock, flags); - if (dev->quota == 0) { - return 1; + __netif_rx_complete(dev, napi); + + /* clear interrupt masks */ + val = lp->a.read_csr(ioaddr, CSR3); + val &= 0x00ff; + lp->a.write_csr(ioaddr, CSR3, val); + + /* Set interrupt enable. */ + lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN); + mmiowb(); + spin_unlock_irqrestore(&lp->lock, flags); } - - netif_rx_complete(dev); - - spin_lock_irqsave(&lp->lock, flags); - - /* clear interrupt masks */ - val = lp->a.read_csr(ioaddr, CSR3); - val &= 0x00ff; - lp->a.write_csr(ioaddr, CSR3, val); - - /* Set interrupt enable. */ - lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN); - mmiowb(); - spin_unlock_irqrestore(&lp->lock, flags); - - return 0; + return work_done; } #endif @@ -1815,6 +1818,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } lp->pci_dev = pdev; + lp->dev = dev; + spin_lock_init(&lp->lock); SET_MODULE_OWNER(dev); @@ -1843,6 +1848,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) lp->mii_if.mdio_read = mdio_read; lp->mii_if.mdio_write = mdio_write; +#ifdef CONFIG_PCNET32_NAPI + netif_napi_add(dev, &lp->napi, pcnet32_poll, lp->rx_ring_size / 2); +#endif + if (fdx && !(lp->options & PCNET32_PORT_ASEL) && ((cards_found >= MAX_UNITS) || full_duplex[cards_found])) lp->options |= PCNET32_PORT_FD; @@ -1953,10 +1962,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) dev->ethtool_ops = &pcnet32_ethtool_ops; dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5 * HZ); - dev->weight = lp->rx_ring_size / 2; -#ifdef CONFIG_PCNET32_NAPI - dev->poll = pcnet32_poll; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = pcnet32_poll_controller; @@ -2276,6 +2281,10 @@ static int pcnet32_open(struct net_device *dev) goto err_free_ring; } +#ifdef CONFIG_PCNET32_NAPI + napi_enable(&lp->napi); +#endif + /* Re-initialize the PCNET32, and start it when done. */ lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff)); lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16)); @@ -2599,18 +2608,18 @@ pcnet32_interrupt(int irq, void *dev_id) /* unlike for the lance, there is no restart needed */ } #ifdef CONFIG_PCNET32_NAPI - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &lp->napi)) { u16 val; /* set interrupt masks */ val = lp->a.read_csr(ioaddr, CSR3); val |= 0x5f00; lp->a.write_csr(ioaddr, CSR3, val); mmiowb(); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &lp->napi); break; } #else - pcnet32_rx(dev, dev->weight); + pcnet32_rx(dev, lp->napi.weight); if (pcnet32_tx(dev)) { /* reset the chip to clear the error condition, then restart */ lp->a.reset(ioaddr); @@ -2645,6 +2654,9 @@ static int pcnet32_close(struct net_device *dev) del_timer_sync(&lp->watchdog_timer); netif_stop_queue(dev); +#ifdef CONFIG_PCNET32_NAPI + napi_disable(&lp->napi); +#endif spin_lock_irqsave(&lp->lock, flags); diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index e56503918436..92561c0450bc 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -556,6 +556,7 @@ static int gelic_net_stop(struct net_device *netdev) { struct gelic_net_card *card = netdev_priv(netdev); + napi_disable(&card->napi); netif_stop_queue(netdev); /* turn off DMA, force end */ @@ -987,32 +988,24 @@ refill: * if the quota is exceeded, but the driver has still packets. * */ -static int gelic_net_poll(struct net_device *netdev, int *budget) +static int gelic_net_poll(struct napi_struct *napi, int budget) { - struct gelic_net_card *card = netdev_priv(netdev); - int packets_to_do, packets_done = 0; - int no_more_packets = 0; + struct gelic_net_card *card = container_of(napi, struct gelic_net_card, napi); + struct net_device *netdev = card->netdev; + int packets_done = 0; - packets_to_do = min(*budget, netdev->quota); - - while (packets_to_do) { - if (gelic_net_decode_one_descr(card)) { - packets_done++; - packets_to_do--; - } else { - /* no more packets for the stack */ - no_more_packets = 1; + while (packets_done < budget) { + if (!gelic_net_decode_one_descr(card)) break; - } + + packets_done++; } - netdev->quota -= packets_done; - *budget -= packets_done; - if (no_more_packets) { - netif_rx_complete(netdev); + + if (packets_done < budget) { + netif_rx_complete(netdev, napi); gelic_net_rx_irq_on(card); - return 0; - } else - return 1; + } + return packets_done; } /** * gelic_net_change_mtu - changes the MTU of an interface @@ -1055,7 +1048,7 @@ static irqreturn_t gelic_net_interrupt(int irq, void *ptr) if (status & GELIC_NET_RXINT) { gelic_net_rx_irq_off(card); - netif_rx_schedule(netdev); + netif_rx_schedule(netdev, &card->napi); } if (status & GELIC_NET_TXINT) { @@ -1159,6 +1152,8 @@ static int gelic_net_open(struct net_device *netdev) if (gelic_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; + napi_enable(&card->napi); + card->tx_dma_progress = 0; card->ghiintmask = GELIC_NET_RXINT | GELIC_NET_TXINT; @@ -1360,9 +1355,6 @@ static void gelic_net_setup_netdev_ops(struct net_device *netdev) /* tx watchdog */ netdev->tx_timeout = &gelic_net_tx_timeout; netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT; - /* NAPI */ - netdev->poll = &gelic_net_poll; - netdev->weight = GELIC_NET_NAPI_WEIGHT; netdev->ethtool_ops = &gelic_net_ethtool_ops; } @@ -1390,6 +1382,9 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) gelic_net_setup_netdev_ops(netdev); + netif_napi_add(netdev, &card->napi, + gelic_net_poll, GELIC_NET_NAPI_WEIGHT); + netdev->features = NETIF_F_IP_CSUM; status = lv1_net_control(bus_id(card), dev_id(card), diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index a9c4c4fc2547..968560269a3b 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -194,6 +194,7 @@ struct gelic_net_descr_chain { struct gelic_net_card { struct net_device *netdev; + struct napi_struct napi; /* * hypervisor requires irq_status should be * 8 bytes aligned, but u64 member is diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index ea151315050c..bf9f8f64ba67 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2310,10 +2310,10 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev, return work_done; } -static int ql_poll(struct net_device *ndev, int *budget) +static int ql_poll(struct napi_struct *napi, int budget) { - struct ql3_adapter *qdev = netdev_priv(ndev); - int work_to_do = min(*budget, ndev->quota); + struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi); + struct net_device *ndev = qdev->ndev; int rx_cleaned = 0, tx_cleaned = 0; unsigned long hw_flags; struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; @@ -2321,16 +2321,13 @@ static int ql_poll(struct net_device *ndev, int *budget) if (!netif_carrier_ok(ndev)) goto quit_polling; - ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do); - *budget -= rx_cleaned; - ndev->quota -= rx_cleaned; + ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, budget); - if( tx_cleaned + rx_cleaned != work_to_do || + if (tx_cleaned + rx_cleaned != budget || !netif_running(ndev)) { quit_polling: - netif_rx_complete(ndev); - spin_lock_irqsave(&qdev->hw_lock, hw_flags); + __netif_rx_complete(ndev, napi); ql_update_small_bufq_prod_index(qdev); ql_update_lrg_bufq_prod_index(qdev); writel(qdev->rsp_consumer_index, @@ -2338,9 +2335,8 @@ quit_polling: spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); ql_enable_interrupts(qdev); - return 0; } - return 1; + return tx_cleaned + rx_cleaned; } static irqreturn_t ql3xxx_isr(int irq, void *dev_id) @@ -2390,8 +2386,8 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) spin_unlock(&qdev->adapter_lock); } else if (value & ISP_IMR_DISABLE_CMPL_INT) { ql_disable_interrupts(qdev); - if (likely(netif_rx_schedule_prep(ndev))) { - __netif_rx_schedule(ndev); + if (likely(netif_rx_schedule_prep(ndev, &qdev->napi))) { + __netif_rx_schedule(ndev, &qdev->napi); } } else { return IRQ_NONE; @@ -3617,7 +3613,7 @@ static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset) del_timer_sync(&qdev->adapter_timer); - netif_poll_disable(ndev); + napi_disable(&qdev->napi); if (do_reset) { int soft_reset; @@ -3705,7 +3701,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev) mod_timer(&qdev->adapter_timer, jiffies + HZ * 1); - netif_poll_enable(ndev); + napi_enable(&qdev->napi); ql_enable_interrupts(qdev); return 0; @@ -4061,8 +4057,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, ndev->tx_timeout = ql3xxx_tx_timeout; ndev->watchdog_timeo = 5 * HZ; - ndev->poll = &ql_poll; - ndev->weight = 64; + netif_napi_add(ndev, &qdev->napi, ql_poll, 64); ndev->irq = pdev->irq; diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index 4a832c46c274..aa2216f0d7b8 100755 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -1175,6 +1175,8 @@ struct ql3_adapter { struct pci_dev *pdev; struct net_device *ndev; /* Parent NET device */ + struct napi_struct napi; + /* Hardware information */ u8 chip_rev_id; u8 pci_slot; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c76dd29c8e9a..3f2306e3f517 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -384,6 +384,7 @@ struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ u32 msg_enable; @@ -443,13 +444,13 @@ static void rtl_set_rx_mode(struct net_device *dev); static void rtl8169_tx_timeout(struct net_device *dev); static struct net_device_stats *rtl8169_get_stats(struct net_device *dev); static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *, - void __iomem *); + void __iomem *, u32 budget); static int rtl8169_change_mtu(struct net_device *dev, int new_mtu); static void rtl8169_down(struct net_device *dev); static void rtl8169_rx_clear(struct rtl8169_private *tp); #ifdef CONFIG_R8169_NAPI -static int rtl8169_poll(struct net_device *dev, int *budget); +static int rtl8169_poll(struct napi_struct *napi, int budget); #endif static const unsigned int rtl8169_rx_config = @@ -1656,8 +1657,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->set_mac_address = rtl_set_mac_address; #ifdef CONFIG_R8169_NAPI - dev->poll = rtl8169_poll; - dev->weight = R8169_NAPI_WEIGHT; + netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); #endif #ifdef CONFIG_R8169_VLAN @@ -1777,6 +1777,10 @@ static int rtl8169_open(struct net_device *dev) if (retval < 0) goto err_release_ring_2; +#ifdef CONFIG_R8169_NAPI + napi_enable(&tp->napi); +#endif + rtl_hw_start(dev); rtl8169_request_timer(dev); @@ -2082,7 +2086,9 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) if (ret < 0) goto out; - netif_poll_enable(dev); +#ifdef CONFIG_R8169_NAPI + napi_enable(&tp->napi); +#endif rtl_hw_start(dev); @@ -2274,11 +2280,15 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev) synchronize_irq(dev->irq); /* Wait for any pending NAPI task to complete */ - netif_poll_disable(dev); +#ifdef CONFIG_R8169_NAPI + napi_disable(&tp->napi); +#endif rtl8169_irq_mask_and_ack(ioaddr); - netif_poll_enable(dev); +#ifdef CONFIG_R8169_NAPI + napi_enable(&tp->napi); +#endif } static void rtl8169_reinit_task(struct work_struct *work) @@ -2322,7 +2332,7 @@ static void rtl8169_reset_task(struct work_struct *work) rtl8169_wait_for_quiescence(dev); - rtl8169_rx_interrupt(dev, tp, tp->mmio_addr); + rtl8169_rx_interrupt(dev, tp, tp->mmio_addr, ~(u32)0); rtl8169_tx_clear(tp); if (tp->dirty_rx == tp->cur_rx) { @@ -2636,14 +2646,14 @@ out: static int rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, - void __iomem *ioaddr) + void __iomem *ioaddr, u32 budget) { unsigned int cur_rx, rx_left; unsigned int delta, count; cur_rx = tp->cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; - rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota); + rx_left = rtl8169_rx_quota(rx_left, budget); for (; rx_left > 0; rx_left--, cur_rx++) { unsigned int entry = cur_rx % NUM_RX_DESC; @@ -2792,8 +2802,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); tp->intr_mask = ~tp->napi_event; - if (likely(netif_rx_schedule_prep(dev))) - __netif_rx_schedule(dev); + if (likely(netif_rx_schedule_prep(dev, &tp->napi))) + __netif_rx_schedule(dev, &tp->napi); else if (netif_msg_intr(tp)) { printk(KERN_INFO "%s: interrupt %04x in poll\n", dev->name, status); @@ -2803,7 +2813,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) #else /* Rx interrupt */ if (status & (RxOK | RxOverflow | RxFIFOOver)) - rtl8169_rx_interrupt(dev, tp, ioaddr); + rtl8169_rx_interrupt(dev, tp, ioaddr, ~(u32)0); /* Tx interrupt */ if (status & (TxOK | TxErr)) @@ -2826,20 +2836,18 @@ out: } #ifdef CONFIG_R8169_NAPI -static int rtl8169_poll(struct net_device *dev, int *budget) +static int rtl8169_poll(struct napi_struct *napi, int budget) { - unsigned int work_done, work_to_do = min(*budget, dev->quota); - struct rtl8169_private *tp = netdev_priv(dev); + struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->mmio_addr; + int work_done; - work_done = rtl8169_rx_interrupt(dev, tp, ioaddr); + work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget); rtl8169_tx_interrupt(dev, tp, ioaddr); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done < work_to_do) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); tp->intr_mask = 0xffff; /* * 20040426: the barrier is not strictly required but the @@ -2851,7 +2859,7 @@ static int rtl8169_poll(struct net_device *dev, int *budget) RTL_W16(IntrMask, tp->intr_event); } - return (work_done >= work_to_do); + return work_done; } #endif @@ -2880,7 +2888,7 @@ core_down: synchronize_irq(dev->irq); if (!poll_locked) { - netif_poll_disable(dev); + napi_disable(&tp->napi); poll_locked++; } @@ -2918,8 +2926,6 @@ static int rtl8169_close(struct net_device *dev) free_irq(dev->irq, dev); - netif_poll_enable(dev); - pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, tp->RxPhyAddr); pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 24feb00600ee..dd012322cdbe 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2568,7 +2568,7 @@ static void free_rx_buffers(struct s2io_nic *sp) /** * s2io_poll - Rx interrupt handler for NAPI support - * @dev : pointer to the device structure. + * @napi : pointer to the napi structure. * @budget : The number of packets that were budgeted to be processed * during one pass through the 'Poll" function. * Description: @@ -2579,9 +2579,10 @@ static void free_rx_buffers(struct s2io_nic *sp) * 0 on success and 1 if there are No Rx packets to be processed. */ -static int s2io_poll(struct net_device *dev, int *budget) +static int s2io_poll(struct napi_struct *napi, int budget) { - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); + struct net_device *dev = nic->dev; int pkt_cnt = 0, org_pkts_to_process; struct mac_info *mac_control; struct config_param *config; @@ -2592,9 +2593,7 @@ static int s2io_poll(struct net_device *dev, int *budget) mac_control = &nic->mac_control; config = &nic->config; - nic->pkts_to_process = *budget; - if (nic->pkts_to_process > dev->quota) - nic->pkts_to_process = dev->quota; + nic->pkts_to_process = budget; org_pkts_to_process = nic->pkts_to_process; writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); @@ -2608,12 +2607,8 @@ static int s2io_poll(struct net_device *dev, int *budget) goto no_rx; } } - if (!pkt_cnt) - pkt_cnt = 1; - dev->quota -= pkt_cnt; - *budget -= pkt_cnt; - netif_rx_complete(dev); + netif_rx_complete(dev, napi); for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { @@ -2626,12 +2621,9 @@ static int s2io_poll(struct net_device *dev, int *budget) writeq(0x0, &bar0->rx_traffic_mask); readl(&bar0->rx_traffic_mask); atomic_dec(&nic->isr_cnt); - return 0; + return pkt_cnt; no_rx: - dev->quota -= pkt_cnt; - *budget -= pkt_cnt; - for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); @@ -2640,7 +2632,7 @@ no_rx: } } atomic_dec(&nic->isr_cnt); - return 1; + return pkt_cnt; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -3809,6 +3801,8 @@ static int s2io_open(struct net_device *dev) netif_carrier_off(dev); sp->last_link_state = 0; + napi_enable(&sp->napi); + /* Initialize H/W and enable interrupts */ err = s2io_card_up(sp); if (err) { @@ -3828,6 +3822,7 @@ static int s2io_open(struct net_device *dev) return 0; hw_init_failed: + napi_disable(&sp->napi); if (sp->intr_type == MSI_X) { if (sp->entries) { kfree(sp->entries); @@ -3861,6 +3856,7 @@ static int s2io_close(struct net_device *dev) struct s2io_nic *sp = dev->priv; netif_stop_queue(dev); + napi_disable(&sp->napi); /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); @@ -4232,8 +4228,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (napi) { if (reason & GEN_INTR_RXTRAFFIC) { - if ( likely ( netif_rx_schedule_prep(dev)) ) { - __netif_rx_schedule(dev); + if (likely (netif_rx_schedule_prep(dev, &sp->napi))) { + __netif_rx_schedule(dev, &sp->napi); writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); } else @@ -7215,8 +7211,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) * will use eth_mac_addr() for dev->set_mac_address * mac address will be set every time dev->open() is called */ - dev->poll = s2io_poll; - dev->weight = 32; + netif_napi_add(dev, &sp->napi, s2io_poll, 32); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = s2io_netpoll; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 92983ee7df8c..420fefb99188 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -786,6 +786,7 @@ struct s2io_nic { */ int pkts_to_process; struct net_device *dev; + struct napi_struct napi; struct mac_info mac_control; struct config_param config; struct pci_dev *pdev; @@ -1019,7 +1020,7 @@ static void s2io_set_multicast(struct net_device *dev); static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); static void s2io_link(struct s2io_nic * sp, int link); static void s2io_reset(struct s2io_nic * sp); -static int s2io_poll(struct net_device *dev, int *budget); +static int s2io_poll(struct napi_struct *napi, int budget); static void s2io_init_pci(struct s2io_nic * sp); static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); static void s2io_alarm_handle(unsigned long data); diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index e7fdcf15b5a7..53845ebb649f 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -238,6 +238,7 @@ struct sbmac_softc { */ struct net_device *sbm_dev; /* pointer to linux device */ + struct napi_struct napi; spinlock_t sbm_lock; /* spin lock */ struct timer_list sbm_timer; /* for monitoring MII */ struct net_device_stats sbm_stats; @@ -320,7 +321,7 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev); static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); -static int sbmac_poll(struct net_device *poll_dev, int *budget); +static int sbmac_poll(struct napi_struct *napi, int budget); static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); static int sbmac_mii_probe(struct net_device *dev); @@ -2154,20 +2155,13 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) * Transmits on channel 0 */ - if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { + if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) sbdma_tx_process(sc,&(sc->sbm_txdma), 0); -#ifdef CONFIG_NETPOLL_TRAP - if (netpoll_trap()) { - if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) - __netif_schedule(dev); - } -#endif - } if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &sc->napi)) { __raw_writeq(0, sc->sbm_imr); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &sc->napi); /* Depend on the exit from poll to reenable intr */ } else { @@ -2470,8 +2464,8 @@ static int sbmac_init(struct net_device *dev, int idx) dev->do_ioctl = sbmac_mii_ioctl; dev->tx_timeout = sbmac_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->poll = sbmac_poll; - dev->weight = 16; + + netif_napi_add(dev, &sc->napi, sbmac_poll, 16); dev->change_mtu = sb1250_change_mtu; #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2537,6 +2531,8 @@ static int sbmac_open(struct net_device *dev) return -EINVAL; } + napi_enable(&sc->napi); + /* * Configure default speed */ @@ -2850,6 +2846,8 @@ static int sbmac_close(struct net_device *dev) unsigned long flags; int irq; + napi_disable(&sc->napi); + sbmac_set_channel_state(sc,sbmac_state_off); del_timer_sync(&sc->sbm_timer); @@ -2874,26 +2872,17 @@ static int sbmac_close(struct net_device *dev) return 0; } -static int sbmac_poll(struct net_device *dev, int *budget) +static int sbmac_poll(struct napi_struct *napi, int budget) { - int work_to_do; + struct sbmac_softc *sc = container_of(napi, struct sbmac_softc, napi); + struct net_device *dev = sc->sbm_dev; int work_done; - struct sbmac_softc *sc = netdev_priv(dev); - - work_to_do = min(*budget, dev->quota); - work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1); - - if (work_done > work_to_do) - printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n", - sc->sbm_dev->name, *budget, dev->quota, work_done); + work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), budget, 1); sbdma_tx_process(sc, &(sc->sbm_txdma), 1); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done < work_to_do) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); #ifdef CONFIG_SBMAC_COALESCE __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | @@ -2905,7 +2894,7 @@ static int sbmac_poll(struct net_device *dev, int *budget) #endif } - return (work_done >= work_to_do); + return work_done; } #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index d470b19c0810..038ccfbafdd1 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -47,24 +47,13 @@ #define PHY_ID_ANY 0x1f #define MII_REG_ANY 0x1f -#ifdef CONFIG_SIS190_NAPI -#define NAPI_SUFFIX "-NAPI" -#else -#define NAPI_SUFFIX "" -#endif - -#define DRV_VERSION "1.2" NAPI_SUFFIX +#define DRV_VERSION "1.2" #define DRV_NAME "sis190" #define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " -#ifdef CONFIG_SIS190_NAPI -#define sis190_rx_skb netif_receive_skb -#define sis190_rx_quota(count, quota) min(count, quota) -#else #define sis190_rx_skb netif_rx #define sis190_rx_quota(count, quota) count -#endif #define MAC_ADDR_LEN 6 @@ -1115,10 +1104,8 @@ static void sis190_down(struct net_device *dev) synchronize_irq(dev->irq); - if (!poll_locked) { - netif_poll_disable(dev); + if (!poll_locked) poll_locked++; - } synchronize_sched(); @@ -1137,8 +1124,6 @@ static int sis190_close(struct net_device *dev) free_irq(dev->irq, dev); - netif_poll_enable(dev); - pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma); pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index e3d8520209b8..0bf46ed4e684 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2528,7 +2528,7 @@ static int skge_up(struct net_device *dev) skge_write32(hw, B0_IMSK, hw->intr_mask); spin_unlock_irq(&hw->hw_lock); - netif_poll_enable(dev); + napi_enable(&skge->napi); return 0; free_rx_ring: @@ -2558,7 +2558,7 @@ static int skge_down(struct net_device *dev) if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) del_timer_sync(&skge->link_timer); - netif_poll_disable(dev); + napi_disable(&skge->napi); netif_carrier_off(dev); spin_lock_irq(&hw->hw_lock); @@ -3044,14 +3044,13 @@ static void skge_tx_done(struct net_device *dev) } } -static int skge_poll(struct net_device *dev, int *budget) +static int skge_poll(struct napi_struct *napi, int to_do) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = container_of(napi, struct skge_port, napi); + struct net_device *dev = skge->netdev; struct skge_hw *hw = skge->hw; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - unsigned long flags; - int to_do = min(dev->quota, *budget); int work_done = 0; skge_tx_done(dev); @@ -3082,20 +3081,16 @@ static int skge_poll(struct net_device *dev, int *budget) wmb(); skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START); - *budget -= work_done; - dev->quota -= work_done; + if (work_done < to_do) { + spin_lock_irq(&hw->hw_lock); + __netif_rx_complete(dev, napi); + hw->intr_mask |= napimask[skge->port]; + skge_write32(hw, B0_IMSK, hw->intr_mask); + skge_read32(hw, B0_IMSK); + spin_unlock_irq(&hw->hw_lock); + } - if (work_done >= to_do) - return 1; /* not done */ - - spin_lock_irqsave(&hw->hw_lock, flags); - __netif_rx_complete(dev); - hw->intr_mask |= napimask[skge->port]; - skge_write32(hw, B0_IMSK, hw->intr_mask); - skge_read32(hw, B0_IMSK); - spin_unlock_irqrestore(&hw->hw_lock, flags); - - return 0; + return work_done; } /* Parity errors seem to happen when Genesis is connected to a switch @@ -3252,8 +3247,9 @@ static irqreturn_t skge_intr(int irq, void *dev_id) } if (status & (IS_XA1_F|IS_R1_F)) { + struct skge_port *skge = netdev_priv(hw->dev[0]); hw->intr_mask &= ~(IS_XA1_F|IS_R1_F); - netif_rx_schedule(hw->dev[0]); + netif_rx_schedule(hw->dev[0], &skge->napi); } if (status & IS_PA_TO_TX1) @@ -3271,13 +3267,14 @@ static irqreturn_t skge_intr(int irq, void *dev_id) skge_mac_intr(hw, 0); if (hw->dev[1]) { + struct skge_port *skge = netdev_priv(hw->dev[1]); + if (status & (IS_XA2_F|IS_R2_F)) { hw->intr_mask &= ~(IS_XA2_F|IS_R2_F); - netif_rx_schedule(hw->dev[1]); + netif_rx_schedule(hw->dev[1], &skge->napi); } if (status & IS_PA_TO_RX2) { - struct skge_port *skge = netdev_priv(hw->dev[1]); ++skge->net_stats.rx_over_errors; skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2); } @@ -3569,8 +3566,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, SET_ETHTOOL_OPS(dev, &skge_ethtool_ops); dev->tx_timeout = skge_tx_timeout; dev->watchdog_timeo = TX_WATCHDOG; - dev->poll = skge_poll; - dev->weight = NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = skge_netpoll; #endif @@ -3580,6 +3575,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, dev->features |= NETIF_F_HIGHDMA; skge = netdev_priv(dev); + netif_napi_add(dev, &skge->napi, skge_poll, NAPI_WEIGHT); skge->netdev = dev; skge->hw = hw; skge->msg_enable = netif_msg_init(debug, default_msg); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index edd71468220c..dd0fd45c7155 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2448,6 +2448,7 @@ enum pause_status { struct skge_port { struct skge_hw *hw; struct net_device *netdev; + struct napi_struct napi; int port; u32 msg_enable; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ea117fc3d5e3..a0d75b0f3798 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1130,7 +1130,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp u16 port = sky2->port; netif_tx_lock_bh(dev); - netif_poll_disable(sky2->hw->dev[0]); + napi_disable(&hw->napi); sky2->vlgrp = grp; if (grp) { @@ -1145,7 +1145,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp TX_VLAN_TAG_OFF); } - netif_poll_enable(sky2->hw->dev[0]); + napi_enable(&hw->napi); netif_tx_unlock_bh(dev); } #endif @@ -1385,9 +1385,13 @@ static int sky2_up(struct net_device *dev) sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, TX_RING_SIZE - 1); + napi_enable(&hw->napi); + err = sky2_rx_start(sky2); - if (err) + if (err) { + napi_disable(&hw->napi); goto err_out; + } /* Enable interrupts from phy/mac for port */ imask = sky2_read32(hw, B0_IMSK); @@ -1676,6 +1680,8 @@ static int sky2_down(struct net_device *dev) /* Stop more packets from being queued */ netif_stop_queue(dev); + napi_disable(&hw->napi); + /* Disable port IRQ */ imask = sky2_read32(hw, B0_IMSK); imask &= ~portirq_msk[port]; @@ -2016,7 +2022,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) dev->trans_start = jiffies; /* prevent tx timeout */ netif_stop_queue(dev); - netif_poll_disable(hw->dev[0]); + napi_disable(&hw->napi); synchronize_irq(hw->pdev->irq); @@ -2043,12 +2049,16 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) err = sky2_rx_start(sky2); sky2_write32(hw, B0_IMSK, imask); + /* Unconditionally re-enable NAPI because even if we + * call dev_close() that will do a napi_disable(). + */ + napi_enable(&hw->napi); + if (err) dev_close(dev); else { gma_write16(hw, port, GM_GP_CTRL, ctl); - netif_poll_enable(hw->dev[0]); netif_wake_queue(dev); } @@ -2544,18 +2554,15 @@ static int sky2_rx_hung(struct net_device *dev) static void sky2_watchdog(unsigned long arg) { struct sky2_hw *hw = (struct sky2_hw *) arg; - struct net_device *dev; /* Check for lost IRQ once a second */ if (sky2_read32(hw, B0_ISRC)) { - dev = hw->dev[0]; - if (__netif_rx_schedule_prep(dev)) - __netif_rx_schedule(dev); + napi_schedule(&hw->napi); } else { int i, active = 0; for (i = 0; i < hw->ports; i++) { - dev = hw->dev[i]; + struct net_device *dev = hw->dev[i]; if (!netif_running(dev)) continue; ++active; @@ -2605,11 +2612,11 @@ static void sky2_err_intr(struct sky2_hw *hw, u32 status) sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE); } -static int sky2_poll(struct net_device *dev0, int *budget) +static int sky2_poll(struct napi_struct *napi, int work_limit) { - struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; - int work_done; + struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi); u32 status = sky2_read32(hw, B0_Y2_SP_EISR); + int work_done; if (unlikely(status & Y2_IS_ERROR)) sky2_err_intr(hw, status); @@ -2620,31 +2627,27 @@ static int sky2_poll(struct net_device *dev0, int *budget) if (status & Y2_IS_IRQ_PHY2) sky2_phy_intr(hw, 1); - work_done = sky2_status_intr(hw, min(dev0->quota, *budget)); - *budget -= work_done; - dev0->quota -= work_done; + work_done = sky2_status_intr(hw, work_limit); /* More work? */ - if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX)) - return 1; + if (hw->st_idx == sky2_read16(hw, STAT_PUT_IDX)) { + /* Bug/Errata workaround? + * Need to kick the TX irq moderation timer. + */ + if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); + } - /* Bug/Errata workaround? - * Need to kick the TX irq moderation timer. - */ - if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); + napi_complete(napi); + sky2_read32(hw, B0_Y2_SP_LISR); } - netif_rx_complete(dev0); - - sky2_read32(hw, B0_Y2_SP_LISR); - return 0; + return work_done; } static irqreturn_t sky2_intr(int irq, void *dev_id) { struct sky2_hw *hw = dev_id; - struct net_device *dev0 = hw->dev[0]; u32 status; /* Reading this mask interrupts as side effect */ @@ -2653,8 +2656,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id) return IRQ_NONE; prefetch(&hw->st_le[hw->st_idx]); - if (likely(__netif_rx_schedule_prep(dev0))) - __netif_rx_schedule(dev0); + + napi_schedule(&hw->napi); return IRQ_HANDLED; } @@ -2663,10 +2666,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id) static void sky2_netpoll(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - struct net_device *dev0 = sky2->hw->dev[0]; - if (netif_running(dev) && __netif_rx_schedule_prep(dev0)) - __netif_rx_schedule(dev0); + napi_schedule(&sky2->hw->napi); } #endif @@ -2914,8 +2915,6 @@ static void sky2_restart(struct work_struct *work) sky2_write32(hw, B0_IMSK, 0); sky2_read32(hw, B0_IMSK); - netif_poll_disable(hw->dev[0]); - for (i = 0; i < hw->ports; i++) { dev = hw->dev[i]; if (netif_running(dev)) @@ -2924,7 +2923,6 @@ static void sky2_restart(struct work_struct *work) sky2_reset(hw); sky2_write32(hw, B0_IMSK, Y2_IS_BASE); - netif_poll_enable(hw->dev[0]); for (i = 0; i < hw->ports; i++) { dev = hw->dev[i]; @@ -3735,7 +3733,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v) { struct net_device *dev = seq->private; const struct sky2_port *sky2 = netdev_priv(dev); - const struct sky2_hw *hw = sky2->hw; + struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; unsigned idx, last; int sop; @@ -3748,7 +3746,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v) sky2_read32(hw, B0_IMSK), sky2_read32(hw, B0_Y2_SP_ICR)); - netif_poll_disable(hw->dev[0]); + napi_disable(&hw->napi); last = sky2_read16(hw, STAT_PUT_IDX); if (hw->st_idx == last) @@ -3818,7 +3816,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v) last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)), sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX))); - netif_poll_enable(hw->dev[0]); + napi_enable(&hw->napi); return 0; } @@ -3943,15 +3941,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops); dev->tx_timeout = sky2_tx_timeout; dev->watchdog_timeo = TX_WATCHDOG; - if (port == 0) - dev->poll = sky2_poll; - dev->weight = NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER - /* Network console (only works on port 0) - * because netpoll makes assumptions about NAPI - */ - if (port == 0) - dev->poll_controller = sky2_netpoll; + dev->poll_controller = sky2_netpoll; #endif sky2 = netdev_priv(dev); @@ -4166,6 +4157,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, err = -ENOMEM; goto err_out_free_pci; } + netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT); if (!disable_msi && pci_enable_msi(pdev) == 0) { err = sky2_test_msi(hw); @@ -4288,8 +4280,6 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) if (!hw) return 0; - netif_poll_disable(hw->dev[0]); - for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; struct sky2_port *sky2 = netdev_priv(dev); @@ -4356,8 +4346,6 @@ static int sky2_resume(struct pci_dev *pdev) } } - netif_poll_enable(hw->dev[0]); - return 0; out: dev_err(&pdev->dev, "resume failed (%d)\n", err); @@ -4374,7 +4362,7 @@ static void sky2_shutdown(struct pci_dev *pdev) if (!hw) return; - netif_poll_disable(hw->dev[0]); + napi_disable(&hw->napi); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 8bc5c54e3efa..f18f8752118e 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2057,6 +2057,7 @@ struct sky2_port { struct sky2_hw { void __iomem *regs; struct pci_dev *pdev; + struct napi_struct napi; struct net_device *dev[2]; unsigned long flags; #define SKY2_HW_USE_MSI 0x00000001 diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 82d837ab4db9..6d8f2bb7e0f9 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1278,34 +1278,26 @@ bad_desc: * (using netif_receive_skb). If all/enough packets are up, the driver * reenables interrupts and returns 0. If not, 1 is returned. */ -static int -spider_net_poll(struct net_device *netdev, int *budget) +static int spider_net_poll(struct napi_struct *napi, int budget) { - struct spider_net_card *card = netdev_priv(netdev); - int packets_to_do, packets_done = 0; - int no_more_packets = 0; + struct spider_net_card *card = container_of(napi, struct spider_net_card, napi); + struct net_device *netdev = card->netdev; + int packets_done = 0; - packets_to_do = min(*budget, netdev->quota); - - while (packets_to_do) { - if (spider_net_decode_one_descr(card)) { - packets_done++; - packets_to_do--; - } else { - /* no more packets for the stack */ - no_more_packets = 1; + while (packets_done < budget) { + if (!spider_net_decode_one_descr(card)) break; - } + + packets_done++; } if ((packets_done == 0) && (card->num_rx_ints != 0)) { - no_more_packets = spider_net_resync_tail_ptr(card); + if (!spider_net_resync_tail_ptr(card)) + packets_done = budget; spider_net_resync_head_ptr(card); } card->num_rx_ints = 0; - netdev->quota -= packets_done; - *budget -= packets_done; spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); @@ -1313,14 +1305,13 @@ spider_net_poll(struct net_device *netdev, int *budget) /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ - if (no_more_packets) { - netif_rx_complete(netdev); + if (packets_done < budget) { + netif_rx_complete(netdev, napi); spider_net_rx_irq_on(card); card->ignore_rx_ramfull = 0; - return 0; } - return 1; + return packets_done; } /** @@ -1560,7 +1551,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev); + netif_rx_schedule(card->netdev, + &card->napi); } show_error = 0; break; @@ -1580,7 +1572,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev); + netif_rx_schedule(card->netdev, + &card->napi); show_error = 0; break; @@ -1594,7 +1587,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev); + netif_rx_schedule(card->netdev, + &card->napi); show_error = 0; break; @@ -1686,11 +1680,11 @@ spider_net_interrupt(int irq, void *ptr) if (status_reg & SPIDER_NET_RXINT ) { spider_net_rx_irq_off(card); - netif_rx_schedule(netdev); + netif_rx_schedule(netdev, &card->napi); card->num_rx_ints ++; } if (status_reg & SPIDER_NET_TXINT) - netif_rx_schedule(netdev); + netif_rx_schedule(netdev, &card->napi); if (status_reg & SPIDER_NET_LINKINT) spider_net_link_reset(netdev); @@ -2034,7 +2028,7 @@ spider_net_open(struct net_device *netdev) netif_start_queue(netdev); netif_carrier_on(netdev); - netif_poll_enable(netdev); + napi_enable(&card->napi); spider_net_enable_interrupts(card); @@ -2204,7 +2198,7 @@ spider_net_stop(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - netif_poll_disable(netdev); + napi_disable(&card->napi); netif_carrier_off(netdev); netif_stop_queue(netdev); del_timer_sync(&card->tx_timer); @@ -2304,9 +2298,6 @@ spider_net_setup_netdev_ops(struct net_device *netdev) /* tx watchdog */ netdev->tx_timeout = &spider_net_tx_timeout; netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT; - /* NAPI */ - netdev->poll = &spider_net_poll; - netdev->weight = SPIDER_NET_NAPI_WEIGHT; /* HW VLAN */ #ifdef CONFIG_NET_POLL_CONTROLLER /* poll controller */ @@ -2351,6 +2342,9 @@ spider_net_setup_netdev(struct spider_net_card *card) card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; + netif_napi_add(netdev, &card->napi, + spider_net_poll, SPIDER_NET_NAPI_WEIGHT); + spider_net_setup_netdev_ops(netdev); netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index dbbdb8cee3c6..a2fcdebc3790 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -466,6 +466,8 @@ struct spider_net_card { struct pci_dev *pdev; struct mii_phy phy; + struct napi_struct napi; + int medium; void __iomem *regs; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 8b6478663a56..3b9336c34206 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -178,16 +178,13 @@ static int full_duplex[MAX_UNITS] = {0, }; #define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1) #ifdef HAVE_NETDEV_POLL -#define init_poll(dev) \ -do { \ - dev->poll = &netdev_poll; \ - dev->weight = max_interrupt_work; \ -} while (0) -#define netdev_rx(dev, ioaddr) \ +#define init_poll(dev, np) \ + netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work) +#define netdev_rx(dev, np, ioaddr) \ do { \ u32 intr_enable; \ - if (netif_rx_schedule_prep(dev)) { \ - __netif_rx_schedule(dev); \ + if (netif_rx_schedule_prep(dev, &np->napi)) { \ + __netif_rx_schedule(dev, &np->napi); \ intr_enable = readl(ioaddr + IntrEnable); \ intr_enable &= ~(IntrRxDone | IntrRxEmpty); \ writel(intr_enable, ioaddr + IntrEnable); \ @@ -204,12 +201,12 @@ do { \ } while (0) #define netdev_receive_skb(skb) netif_receive_skb(skb) #define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_receive_skb(skb, vlgrp, vlid) -static int netdev_poll(struct net_device *dev, int *budget); +static int netdev_poll(struct napi_struct *napi, int budget); #else /* not HAVE_NETDEV_POLL */ -#define init_poll(dev) +#define init_poll(dev, np) #define netdev_receive_skb(skb) netif_rx(skb) #define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_rx(skb, vlgrp, vlid) -#define netdev_rx(dev, ioaddr) \ +#define netdev_rx(dev, np, ioaddr) \ do { \ int quota = np->dirty_rx + RX_RING_SIZE - np->cur_rx; \ __netdev_rx(dev, "a);\ @@ -599,6 +596,8 @@ struct netdev_private { struct tx_done_desc *tx_done_q; dma_addr_t tx_done_q_dma; unsigned int tx_done; + struct napi_struct napi; + struct net_device *dev; struct net_device_stats stats; struct pci_dev *pci_dev; #ifdef VLAN_SUPPORT @@ -791,6 +790,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, dev->irq = irq; np = netdev_priv(dev); + np->dev = dev; np->base = base; spin_lock_init(&np->lock); pci_set_drvdata(pdev, dev); @@ -851,7 +851,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, dev->hard_start_xmit = &start_tx; dev->tx_timeout = tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - init_poll(dev); + init_poll(dev, np); dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; @@ -1056,6 +1056,9 @@ static int netdev_open(struct net_device *dev) writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl); +#ifdef HAVE_NETDEV_POLL + napi_enable(&np->napi); +#endif netif_start_queue(dev); if (debug > 1) @@ -1330,7 +1333,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) handled = 1; if (intr_status & (IntrRxDone | IntrRxEmpty)) - netdev_rx(dev, ioaddr); + netdev_rx(dev, np, ioaddr); /* Scavenge the skbuff list based on the Tx-done queue. There are redundant checks here that may be cleaned up @@ -1531,36 +1534,35 @@ static int __netdev_rx(struct net_device *dev, int *quota) #ifdef HAVE_NETDEV_POLL -static int netdev_poll(struct net_device *dev, int *budget) +static int netdev_poll(struct napi_struct *napi, int budget) { + struct netdev_private *np = container_of(napi, struct netdev_private, napi); + struct net_device *dev = np->dev; u32 intr_status; - struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base; - int retcode = 0, quota = dev->quota; + int quota = budget; do { writel(IntrRxDone | IntrRxEmpty, ioaddr + IntrClear); - retcode = __netdev_rx(dev, "a); - *budget -= (dev->quota - quota); - dev->quota = quota; - if (retcode) + if (__netdev_rx(dev, "a)) goto out; intr_status = readl(ioaddr + IntrStatus); } while (intr_status & (IntrRxDone | IntrRxEmpty)); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); intr_status = readl(ioaddr + IntrEnable); intr_status |= IntrRxDone | IntrRxEmpty; writel(intr_status, ioaddr + IntrEnable); out: if (debug > 5) - printk(KERN_DEBUG " exiting netdev_poll(): %d.\n", retcode); + printk(KERN_DEBUG " exiting netdev_poll(): %d.\n", + budget - quota); /* Restart Rx engine if stopped. */ - return retcode; + return budget - quota; } #endif /* HAVE_NETDEV_POLL */ @@ -1904,6 +1906,9 @@ static int netdev_close(struct net_device *dev) int i; netif_stop_queue(dev); +#ifdef HAVE_NETDEV_POLL + napi_disable(&np->napi); +#endif if (debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n", diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 432803855034..bf821e96f7b2 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -19,7 +19,7 @@ * * gem_change_mtu() and gem_set_multicast() are called with a read_lock() * help by net/core/dev.c, thus they can't schedule. That means they can't - * call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock + * call napi_disable() neither, thus force gem_poll() to keep a spinlock * where it could have been dropped. change_mtu especially would love also to * be able to msleep instead of horrid locked delays when resetting the HW, * but that read_lock() makes it impossible, unless I defer it's action to @@ -878,19 +878,20 @@ static int gem_rx(struct gem *gp, int work_to_do) return work_done; } -static int gem_poll(struct net_device *dev, int *budget) +static int gem_poll(struct napi_struct *napi, int budget) { - struct gem *gp = dev->priv; + struct gem *gp = container_of(napi, struct gem, napi); + struct net_device *dev = gp->dev; unsigned long flags; + int work_done; /* * NAPI locking nightmare: See comment at head of driver */ spin_lock_irqsave(&gp->lock, flags); + work_done = 0; do { - int work_to_do, work_done; - /* Handle anomalies */ if (gp->status & GREG_STAT_ABNORMAL) { if (gem_abnormal_irq(dev, gp, gp->status)) @@ -906,29 +907,25 @@ static int gem_poll(struct net_device *dev, int *budget) /* Run RX thread. We don't use any locking here, * code willing to do bad things - like cleaning the - * rx ring - must call netif_poll_disable(), which + * rx ring - must call napi_disable(), which * schedule_timeout()'s if polling is already disabled. */ - work_to_do = min(*budget, dev->quota); + work_done += gem_rx(gp, budget); - work_done = gem_rx(gp, work_to_do); - - *budget -= work_done; - dev->quota -= work_done; - - if (work_done >= work_to_do) - return 1; + if (work_done >= budget) + return work_done; spin_lock_irqsave(&gp->lock, flags); gp->status = readl(gp->regs + GREG_STAT); } while (gp->status & GREG_STAT_NAPI); - __netif_rx_complete(dev); + __netif_rx_complete(dev, napi); gem_enable_ints(gp); spin_unlock_irqrestore(&gp->lock, flags); - return 0; + + return work_done; } static irqreturn_t gem_interrupt(int irq, void *dev_id) @@ -946,17 +943,17 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) spin_lock_irqsave(&gp->lock, flags); - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &gp->napi)) { u32 gem_status = readl(gp->regs + GREG_STAT); if (gem_status == 0) { - netif_poll_enable(dev); + napi_enable(&gp->napi); spin_unlock_irqrestore(&gp->lock, flags); return IRQ_NONE; } gp->status = gem_status; gem_disable_ints(gp); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &gp->napi); } spin_unlock_irqrestore(&gp->lock, flags); @@ -2284,7 +2281,7 @@ static void gem_reset_task(struct work_struct *work) mutex_lock(&gp->pm_mutex); - netif_poll_disable(gp->dev); + napi_disable(&gp->napi); spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); @@ -2307,7 +2304,7 @@ static void gem_reset_task(struct work_struct *work) spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); - netif_poll_enable(gp->dev); + napi_enable(&gp->napi); mutex_unlock(&gp->pm_mutex); } @@ -2324,6 +2321,8 @@ static int gem_open(struct net_device *dev) if (!gp->asleep) rc = gem_do_start(dev); gp->opened = (rc == 0); + if (gp->opened) + napi_enable(&gp->napi); mutex_unlock(&gp->pm_mutex); @@ -2334,9 +2333,7 @@ static int gem_close(struct net_device *dev) { struct gem *gp = dev->priv; - /* Note: we don't need to call netif_poll_disable() here because - * our caller (dev_close) already did it for us - */ + napi_disable(&gp->napi); mutex_lock(&gp->pm_mutex); @@ -2358,7 +2355,7 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state) mutex_lock(&gp->pm_mutex); - netif_poll_disable(dev); + napi_disable(&gp->napi); printk(KERN_INFO "%s: suspending, WakeOnLan %s\n", dev->name, @@ -2482,7 +2479,7 @@ static int gem_resume(struct pci_dev *pdev) spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); - netif_poll_enable(dev); + napi_enable(&gp->napi); mutex_unlock(&gp->pm_mutex); @@ -3121,8 +3118,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, dev->get_stats = gem_get_stats; dev->set_multicast_list = gem_set_multicast; dev->do_ioctl = gem_ioctl; - dev->poll = gem_poll; - dev->weight = 64; + netif_napi_add(dev, &gp->napi, gem_poll, 64); dev->ethtool_ops = &gem_ethtool_ops; dev->tx_timeout = gem_tx_timeout; dev->watchdog_timeo = 5 * HZ; diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index 58cf87c5751e..76d760acc9e2 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -993,6 +993,7 @@ struct gem { u32 msg_enable; u32 status; + struct napi_struct napi; struct net_device_stats net_stats; int tx_fifo_sz; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index ec41469eee82..b5e0dff67230 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -414,6 +414,9 @@ enum tc35815_timer_state { struct tc35815_local { struct pci_dev *pci_dev; + struct net_device *dev; + struct napi_struct napi; + /* statistics */ struct net_device_stats stats; struct { @@ -566,7 +569,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t tc35815_interrupt(int irq, void *dev_id); #ifdef TC35815_NAPI static int tc35815_rx(struct net_device *dev, int limit); -static int tc35815_poll(struct net_device *dev, int *budget); +static int tc35815_poll(struct napi_struct *napi, int budget); #else static void tc35815_rx(struct net_device *dev); #endif @@ -685,6 +688,7 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); lp = dev->priv; + lp->dev = dev; /* enable device (incl. PCI PM wakeup), and bus-mastering */ rc = pci_enable_device (pdev); @@ -738,8 +742,7 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, dev->tx_timeout = tc35815_tx_timeout; dev->watchdog_timeo = TC35815_TX_TIMEOUT; #ifdef TC35815_NAPI - dev->poll = tc35815_poll; - dev->weight = NAPI_WEIGHT; + netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT); #endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = tc35815_poll_controller; @@ -748,8 +751,6 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; - /* dev->priv/lp zeroed and aligned in alloc_etherdev */ - lp = dev->priv; spin_lock_init(&lp->lock); lp->pci_dev = pdev; lp->boardtype = ent->driver_data; @@ -1237,6 +1238,10 @@ tc35815_open(struct net_device *dev) return -EAGAIN; } +#ifdef TC35815_NAPI + napi_enable(&lp->napi); +#endif + /* Reset the hardware here. Don't forget to set the station address. */ spin_lock_irq(&lp->lock); tc35815_chip_init(dev); @@ -1436,6 +1441,7 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status) static irqreturn_t tc35815_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; + struct tc35815_local *lp = netdev_priv(dev); struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; #ifdef TC35815_NAPI @@ -1444,8 +1450,8 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) if (!(dmactl & DMA_IntMask)) { /* disable interrupts */ tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl); - if (netif_rx_schedule_prep(dev)) - __netif_rx_schedule(dev); + if (netif_rx_schedule_prep(dev, &lp->napi)) + __netif_rx_schedule(dev, &lp->napi); else { printk(KERN_ERR "%s: interrupt taken in poll\n", dev->name); @@ -1726,13 +1732,12 @@ tc35815_rx(struct net_device *dev) } #ifdef TC35815_NAPI -static int -tc35815_poll(struct net_device *dev, int *budget) +static int tc35815_poll(struct napi_struct *napi, int budget) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi); + struct net_device *dev = lp->dev; struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; - int limit = min(*budget, dev->quota); int received = 0, handled; u32 status; @@ -1744,23 +1749,19 @@ tc35815_poll(struct net_device *dev, int *budget) handled = tc35815_do_interrupt(dev, status, limit); if (handled >= 0) { received += handled; - limit -= handled; - if (limit <= 0) + if (received >= budget) break; } status = tc_readl(&tr->Int_Src); } while (status); spin_unlock(&lp->lock); - dev->quota -= received; - *budget -= received; - if (limit <= 0) - return 1; - - netif_rx_complete(dev); - /* enable interrupts */ - tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); - return 0; + if (received < budget) { + netif_rx_complete(dev, napi); + /* enable interrupts */ + tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); + } + return received; } #endif @@ -1949,7 +1950,11 @@ static int tc35815_close(struct net_device *dev) { struct tc35815_local *lp = dev->priv; + netif_stop_queue(dev); +#ifdef TC35815_NAPI + napi_disable(&lp->napi); +#endif /* Flush the Tx and disable Rx here. */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9034a05734ef..ef1e3d1173c4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -574,7 +574,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 */ - netif_poll_disable(tp->dev); + napi_disable(&tp->napi); netif_tx_disable(tp->dev); } @@ -585,7 +585,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) */ - netif_poll_enable(tp->dev); + napi_enable(&tp->napi); tp->hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); } @@ -3471,11 +3471,12 @@ next_pkt_nopost: return received; } -static int tg3_poll(struct net_device *netdev, int *budget) +static int tg3_poll(struct napi_struct *napi, int budget) { - struct tg3 *tp = netdev_priv(netdev); + struct tg3 *tp = container_of(napi, struct tg3, napi); + struct net_device *netdev = tp->dev; struct tg3_hw_status *sblk = tp->hw_status; - int done; + int work_done = 0; /* handle link change and other phy events */ if (!(tp->tg3_flags & @@ -3494,7 +3495,7 @@ static int tg3_poll(struct net_device *netdev, int *budget) if (sblk->idx[0].tx_consumer != tp->tx_cons) { tg3_tx(tp); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); schedule_work(&tp->reset_task); return 0; } @@ -3502,20 +3503,10 @@ static int tg3_poll(struct net_device *netdev, int *budget) /* run RX thread, within the bounds set by NAPI. * All RX "locking" is done by ensuring outside - * code synchronizes with dev->poll() + * code synchronizes with tg3->napi.poll() */ - if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) { - int orig_budget = *budget; - int work_done; - - if (orig_budget > netdev->quota) - orig_budget = netdev->quota; - - work_done = tg3_rx(tp, orig_budget); - - *budget -= work_done; - netdev->quota -= work_done; - } + if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) + work_done = tg3_rx(tp, budget); if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { tp->last_tag = sblk->status_tag; @@ -3524,13 +3515,12 @@ static int tg3_poll(struct net_device *netdev, int *budget) sblk->status &= ~SD_STATUS_UPDATED; /* if no more work, tell net stack and NIC we're done */ - done = !tg3_has_work(tp); - if (done) { - netif_rx_complete(netdev); + if (!tg3_has_work(tp)) { + netif_rx_complete(netdev, napi); tg3_restart_ints(tp); } - return (done ? 0 : 1); + return work_done; } static void tg3_irq_quiesce(struct tg3 *tp) @@ -3577,7 +3567,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))) - netif_rx_schedule(dev); /* schedule NAPI poll */ + netif_rx_schedule(dev, &tp->napi); return IRQ_HANDLED; } @@ -3602,7 +3592,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))) - netif_rx_schedule(dev); /* schedule NAPI poll */ + netif_rx_schedule(dev, &tp->napi); return IRQ_RETVAL(1); } @@ -3644,7 +3634,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]); - netif_rx_schedule(dev); /* schedule NAPI poll */ + netif_rx_schedule(dev, &tp->napi); } else { /* No work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write @@ -3690,7 +3680,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (tg3_irq_sync(tp)) goto out; - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &tp->napi)) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); /* Update last_tag to mark that this status has been * seen. Because interrupt may be shared, we may be @@ -3698,7 +3688,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * if tg3_poll() is not scheduled. */ tp->last_tag = sblk->status_tag; - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &tp->napi); } out: return IRQ_RETVAL(handled); @@ -3737,7 +3727,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; - netif_poll_enable(tp->dev); + napi_enable(&tp->napi); dev_close(tp->dev); tg3_full_lock(tp, 0); } @@ -3932,7 +3922,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) len = skb_headlen(skb); /* We are running in BH disabled context with netif_tx_lock - * and TX reclaim runs via tp->poll inside of a software + * and TX reclaim runs via tp->napi.poll inside of a software * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ @@ -4087,7 +4077,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) len = skb_headlen(skb); /* We are running in BH disabled context with netif_tx_lock - * and TX reclaim runs via tp->poll inside of a software + * and TX reclaim runs via tp->napi.poll inside of a software * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ @@ -7147,6 +7137,8 @@ static int tg3_open(struct net_device *dev) return err; } + napi_enable(&tp->napi); + tg3_full_lock(tp, 0); err = tg3_init_hw(tp, 1); @@ -7174,6 +7166,7 @@ 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); @@ -7199,6 +7192,8 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); + napi_disable(&tp->napi); + return err; } @@ -7460,6 +7455,7 @@ static int tg3_close(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); + napi_disable(&tp->napi); cancel_work_sync(&tp->reset_task); netif_stop_queue(dev); @@ -11900,9 +11896,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->set_mac_address = tg3_set_mac_addr; dev->do_ioctl = tg3_ioctl; dev->tx_timeout = tg3_tx_timeout; - dev->poll = tg3_poll; + netif_napi_add(dev, &tp->napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; - dev->weight = 64; dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5c21f49026c9..a6a23bbcdfee 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2176,6 +2176,7 @@ struct tg3 { dma_addr_t tx_desc_mapping; /* begin "rx thread" cacheline section */ + struct napi_struct napi; void (*write32_rx_mbox) (struct tg3 *, u32, u32); u32 rx_rcb_ptr; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 1aabc91f6458..b3069ee34bd2 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -79,6 +79,9 @@ struct tsi108_prv_data { void __iomem *regs; /* Base of normal regs */ void __iomem *phyregs; /* Base of register bank used for PHY access */ + struct net_device *dev; + struct napi_struct napi; + unsigned int phy; /* Index of PHY for this interface */ unsigned int irq_num; unsigned int id; @@ -837,13 +840,13 @@ static int tsi108_refill_rx(struct net_device *dev, int budget) return done; } -static int tsi108_poll(struct net_device *dev, int *budget) +static int tsi108_poll(struct napi_struct *napi, int budget) { - struct tsi108_prv_data *data = netdev_priv(dev); + struct tsi108_prv_data *data = container_of(napi, struct tsi108_prv_data, napi); + struct net_device *dev = data->dev; u32 estat = TSI_READ(TSI108_EC_RXESTAT); u32 intstat = TSI_READ(TSI108_EC_INTSTAT); - int total_budget = min(*budget, dev->quota); - int num_received = 0, num_filled = 0, budget_used; + int num_received = 0, num_filled = 0; intstat &= TSI108_INT_RXQUEUE0 | TSI108_INT_RXTHRESH | TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT; @@ -852,7 +855,7 @@ static int tsi108_poll(struct net_device *dev, int *budget) TSI_WRITE(TSI108_EC_INTSTAT, intstat); if (data->rxpending || (estat & TSI108_EC_RXESTAT_Q0_DESCINT)) - num_received = tsi108_complete_rx(dev, total_budget); + num_received = tsi108_complete_rx(dev, budget); /* This should normally fill no more slots than the number of * packets received in tsi108_complete_rx(). The exception @@ -867,7 +870,7 @@ static int tsi108_poll(struct net_device *dev, int *budget) */ if (data->rxfree < TSI108_RXRING_LEN) - num_filled = tsi108_refill_rx(dev, total_budget * 2); + num_filled = tsi108_refill_rx(dev, budget * 2); if (intstat & TSI108_INT_RXERROR) { u32 err = TSI_READ(TSI108_EC_RXERR); @@ -890,14 +893,9 @@ static int tsi108_poll(struct net_device *dev, int *budget) spin_unlock_irq(&data->misclock); } - budget_used = max(num_received, num_filled / 2); - - *budget -= budget_used; - dev->quota -= budget_used; - - if (budget_used != total_budget) { + if (num_received < budget) { data->rxpending = 0; - netif_rx_complete(dev); + netif_rx_complete(dev, napi); TSI_WRITE(TSI108_EC_INTMASK, TSI_READ(TSI108_EC_INTMASK) @@ -906,14 +904,11 @@ static int tsi108_poll(struct net_device *dev, int *budget) TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT)); - - /* IRQs are level-triggered, so no need to re-check */ - return 0; } else { data->rxpending = 1; } - return 1; + return num_received; } static void tsi108_rx_int(struct net_device *dev) @@ -931,7 +926,7 @@ static void tsi108_rx_int(struct net_device *dev) * from tsi108_check_rxring(). */ - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &data->napi)) { /* Mask, rather than ack, the receive interrupts. The ack * will happen in tsi108_poll(). */ @@ -942,7 +937,7 @@ static void tsi108_rx_int(struct net_device *dev) | TSI108_INT_RXTHRESH | TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &data->napi); } else { if (!netif_running(dev)) { /* This can happen if an interrupt occurs while the @@ -1401,6 +1396,8 @@ static int tsi108_open(struct net_device *dev) TSI_WRITE(TSI108_EC_TXQ_PTRLOW, data->txdma); tsi108_init_phy(dev); + napi_enable(&data->napi); + setup_timer(&data->timer, tsi108_timed_checker, (unsigned long)dev); mod_timer(&data->timer, jiffies + 1); @@ -1425,6 +1422,7 @@ static int tsi108_close(struct net_device *dev) struct tsi108_prv_data *data = netdev_priv(dev); netif_stop_queue(dev); + napi_disable(&data->napi); del_timer_sync(&data->timer); @@ -1562,6 +1560,7 @@ tsi108_init_one(struct platform_device *pdev) printk("tsi108_eth%d: probe...\n", pdev->id); data = netdev_priv(dev); + data->dev = dev; pr_debug("tsi108_eth%d:regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n", pdev->id, einfo->regs, einfo->phyregs, @@ -1597,9 +1596,8 @@ tsi108_init_one(struct platform_device *pdev) dev->set_mac_address = tsi108_set_mac; dev->set_multicast_list = tsi108_set_rx_mode; dev->get_stats = tsi108_get_stats; - dev->poll = tsi108_poll; + netif_napi_add(dev, &data->napi, tsi108_poll, 64); dev->do_ioctl = tsi108_do_ioctl; - dev->weight = 64; /* 64 is more suitable for GigE interface - klai */ /* Apparently, the Linux networking code won't use scatter-gather * if the hardware doesn't do checksums. However, it's faster diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 53efd6694e75..365331446387 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -103,28 +103,29 @@ int tulip_refill_rx(struct net_device *dev) void oom_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - netif_rx_schedule(dev); + struct tulip_private *tp = netdev_priv(dev); + netif_rx_schedule(dev, &tp->napi); } -int tulip_poll(struct net_device *dev, int *budget) +int tulip_poll(struct napi_struct *napi, int budget) { - struct tulip_private *tp = netdev_priv(dev); + struct tulip_private *tp = container_of(napi, struct tulip_private, napi); + struct net_device *dev = tp->dev; int entry = tp->cur_rx % RX_RING_SIZE; - int rx_work_limit = *budget; + int work_done = 0; +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION int received = 0; +#endif if (!netif_running(dev)) goto done; - if (rx_work_limit > dev->quota) - rx_work_limit = dev->quota; - #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION /* that one buffer is needed for mit activation; or might be a bug in the ring buffer code; check later -- JHS*/ - if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--; + if (budget >=RX_RING_SIZE) budget--; #endif if (tulip_debug > 4) @@ -144,14 +145,13 @@ int tulip_poll(struct net_device *dev, int *budget) while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); - if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) break; if (tulip_debug > 5) printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", dev->name, entry, status); - if (--rx_work_limit < 0) + if (work_done++ >= budget) goto not_done; if ((status & 0x38008300) != 0x0300) { @@ -238,7 +238,9 @@ int tulip_poll(struct net_device *dev, int *budget) tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; } - received++; +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION + received++; +#endif entry = (++tp->cur_rx) % RX_RING_SIZE; if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) @@ -296,17 +298,15 @@ done: #endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ - dev->quota -= received; - *budget -= received; - tulip_refill_rx(dev); /* If RX ring is not full we are out of memory. */ - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + goto oom; /* Remove us from polling list and enable RX intr. */ - netif_rx_complete(dev); + netif_rx_complete(dev, napi); iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7); /* The last op happens after poll completion. Which means the following: @@ -320,28 +320,20 @@ done: * processed irqs. But it must not result in losing events. */ - return 0; + return work_done; not_done: - if (!received) { - - received = dev->quota; /* Not to happen */ - } - dev->quota -= received; - *budget -= received; - if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) tulip_refill_rx(dev); - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; - - return 1; + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + goto oom; + return work_done; oom: /* Executed with RX ints disabled */ - /* Start timer, stop polling, but do not enable rx interrupts. */ mod_timer(&tp->oom_timer, jiffies+1); @@ -350,9 +342,9 @@ done: * before we did netif_rx_complete(). See? We would lose it. */ /* remove ourselves from the polling list */ - netif_rx_complete(dev); + netif_rx_complete(dev, napi); - return 0; + return work_done; } #else /* CONFIG_TULIP_NAPI */ @@ -534,7 +526,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) rxd++; /* Mask RX intrs and add the device to poll list. */ iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &tp->napi); if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) break; diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 16f26a8364f0..5a4d7270973e 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -353,6 +353,7 @@ struct tulip_private { int chip_id; int revision; int flags; + struct napi_struct napi; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ struct timer_list oom_timer; /* Out of memory timer. */ @@ -429,7 +430,7 @@ extern int tulip_rx_copybreak; irqreturn_t tulip_interrupt(int irq, void *dev_instance); int tulip_refill_rx(struct net_device *dev); #ifdef CONFIG_TULIP_NAPI -int tulip_poll(struct net_device *dev, int *budget); +int tulip_poll(struct napi_struct *napi, int budget); #endif diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index eca984f89bbf..7040a59fa3c9 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -294,6 +294,10 @@ static void tulip_up(struct net_device *dev) int next_tick = 3*HZ; int i; +#ifdef CONFIG_TULIP_NAPI + napi_enable(&tp->napi); +#endif + /* Wake the chip from sleep/snooze mode. */ tulip_set_power_state (tp, 0, 0); @@ -728,6 +732,10 @@ static void tulip_down (struct net_device *dev) flush_scheduled_work(); +#ifdef CONFIG_TULIP_NAPI + napi_disable(&tp->napi); +#endif + del_timer_sync (&tp->timer); #ifdef CONFIG_TULIP_NAPI del_timer_sync (&tp->oom_timer); @@ -1606,8 +1614,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->tx_timeout = tulip_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #ifdef CONFIG_TULIP_NAPI - dev->poll = tulip_poll; - dev->weight = 16; + netif_napi_add(dev, &tp->napi, tulip_poll, 16); #endif dev->stop = tulip_close; dev->get_stats = tulip_get_stats; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 03587205546e..0377b8b64c78 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -284,6 +284,7 @@ struct typhoon { struct basic_ring rxLoRing; struct pci_dev * pdev; struct net_device * dev; + struct napi_struct napi; spinlock_t state_lock; struct vlan_group * vlgrp; struct basic_ring rxHiRing; @@ -1759,12 +1760,12 @@ typhoon_fill_free_ring(struct typhoon *tp) } static int -typhoon_poll(struct net_device *dev, int *total_budget) +typhoon_poll(struct napi_struct *napi, int budget) { - struct typhoon *tp = netdev_priv(dev); + struct typhoon *tp = container_of(napi, struct typhoon, napi); + struct net_device *dev = tp->dev; struct typhoon_indexes *indexes = tp->indexes; - int orig_budget = *total_budget; - int budget, work_done, done; + int work_done; rmb(); if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared) @@ -1773,30 +1774,16 @@ typhoon_poll(struct net_device *dev, int *total_budget) if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead) typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared); - if(orig_budget > dev->quota) - orig_budget = dev->quota; - - budget = orig_budget; work_done = 0; - done = 1; if(indexes->rxHiCleared != indexes->rxHiReady) { - work_done = typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady, + work_done += typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady, &indexes->rxHiCleared, budget); - budget -= work_done; } if(indexes->rxLoCleared != indexes->rxLoReady) { work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady, - &indexes->rxLoCleared, budget); - } - - if(work_done) { - *total_budget -= work_done; - dev->quota -= work_done; - - if(work_done >= orig_budget) - done = 0; + &indexes->rxLoCleared, budget - work_done); } if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) { @@ -1804,14 +1791,14 @@ typhoon_poll(struct net_device *dev, int *total_budget) typhoon_fill_free_ring(tp); } - if(done) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); iowrite32(TYPHOON_INTR_NONE, tp->ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(tp->ioaddr); } - return (done ? 0 : 1); + return work_done; } static irqreturn_t @@ -1828,10 +1815,10 @@ typhoon_interrupt(int irq, void *dev_instance) iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS); - if(netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &tp->napi)) { iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(ioaddr); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &tp->napi); } else { printk(KERN_ERR "%s: Error, poll already scheduled\n", dev->name); @@ -2119,9 +2106,13 @@ typhoon_open(struct net_device *dev) if(err < 0) goto out_sleep; + napi_enable(&tp->napi); + err = typhoon_start_runtime(tp); - if(err < 0) + if(err < 0) { + napi_disable(&tp->napi); goto out_irq; + } netif_start_queue(dev); return 0; @@ -2150,6 +2141,7 @@ typhoon_close(struct net_device *dev) struct typhoon *tp = netdev_priv(dev); netif_stop_queue(dev); + napi_disable(&tp->napi); if(typhoon_stop_runtime(tp, WaitSleep) < 0) printk(KERN_ERR "%s: unable to stop runtime\n", dev->name); @@ -2521,8 +2513,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->stop = typhoon_close; dev->set_multicast_list = typhoon_set_rx_mode; dev->tx_timeout = typhoon_tx_timeout; - dev->poll = typhoon_poll; - dev->weight = 16; + netif_napi_add(dev, &tp->napi, typhoon_poll, 16); dev->watchdog_timeo = TX_TIMEOUT; dev->get_stats = typhoon_get_stats; dev->set_mac_address = typhoon_set_mac_address; diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 9a38dfe45f8f..72f617bf2520 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3582,41 +3582,31 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) } #ifdef CONFIG_UGETH_NAPI -static int ucc_geth_poll(struct net_device *dev, int *budget) +static int ucc_geth_poll(struct napi_struct *napi, int budget) { - struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi); + struct net_device *dev = ugeth->dev; struct ucc_geth_info *ug_info; - struct ucc_fast_private *uccf; - int howmany; - u8 i; - int rx_work_limit; - register u32 uccm; + int howmany, i; ug_info = ugeth->ug_info; - rx_work_limit = *budget; - if (rx_work_limit > dev->quota) - rx_work_limit = dev->quota; - howmany = 0; + for (i = 0; i < ug_info->numQueuesRx; i++) + howmany += ucc_geth_rx(ugeth, i, budget - howmany); - for (i = 0; i < ug_info->numQueuesRx; i++) { - howmany += ucc_geth_rx(ugeth, i, rx_work_limit); - } + if (howmany < budget) { + struct ucc_fast_private *uccf; + u32 uccm; - dev->quota -= howmany; - rx_work_limit -= howmany; - *budget -= howmany; - - if (rx_work_limit > 0) { - netif_rx_complete(dev); + netif_rx_complete(dev, napi); uccf = ugeth->uccf; uccm = in_be32(uccf->p_uccm); uccm |= UCCE_RX_EVENTS; out_be32(uccf->p_uccm, uccm); } - return (rx_work_limit > 0) ? 0 : 1; + return howmany; } #endif /* CONFIG_UGETH_NAPI */ @@ -3651,10 +3641,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* check for receive events that require processing */ if (ucce & UCCE_RX_EVENTS) { #ifdef CONFIG_UGETH_NAPI - if (netif_rx_schedule_prep(dev)) { - uccm &= ~UCCE_RX_EVENTS; + if (netif_rx_schedule_prep(dev, &ugeth->napi)) { + uccm &= ~UCCE_RX_EVENTS; out_be32(uccf->p_uccm, uccm); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &ugeth->napi); } #else rx_mask = UCCE_RXBF_SINGLE_MASK; @@ -3717,12 +3707,15 @@ static int ucc_geth_open(struct net_device *dev) return err; } +#ifdef CONFIG_UGETH_NAPI + napi_enable(&ugeth->napi); +#endif err = ucc_geth_startup(ugeth); if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure net device, aborting.", dev->name); - return err; + goto out_err; } err = adjust_enet_interface(ugeth); @@ -3730,7 +3723,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); - return err; + goto out_err; } /* Set MACSTNADDR1, MACSTNADDR2 */ @@ -3748,7 +3741,7 @@ static int ucc_geth_open(struct net_device *dev) if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name); - return err; + goto out_err; } phy_start(ugeth->phydev); @@ -3761,7 +3754,7 @@ static int ucc_geth_open(struct net_device *dev) ugeth_err("%s: Cannot get IRQ for net device, aborting.", dev->name); ucc_geth_stop(ugeth); - return err; + goto out_err; } err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); @@ -3769,12 +3762,18 @@ static int ucc_geth_open(struct net_device *dev) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot enable net device, aborting.", dev->name); ucc_geth_stop(ugeth); - return err; + goto out_err; } netif_start_queue(dev); return err; + +out_err: +#ifdef CONFIG_UGETH_NAPI + napi_disable(&ugeth->napi); +#endif + return err; } /* Stops the kernel queue, and halts the controller */ @@ -3784,6 +3783,10 @@ static int ucc_geth_close(struct net_device *dev) ugeth_vdbg("%s: IN", __FUNCTION__); +#ifdef CONFIG_UGETH_NAPI + napi_disable(&ugeth->napi); +#endif + ucc_geth_stop(ugeth); phy_disconnect(ugeth->phydev); @@ -3964,8 +3967,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->tx_timeout = ucc_geth_timeout; dev->watchdog_timeo = TX_TIMEOUT; #ifdef CONFIG_UGETH_NAPI - dev->poll = ucc_geth_poll; - dev->weight = UCC_GETH_DEV_WEIGHT; + netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); #endif /* CONFIG_UGETH_NAPI */ dev->stop = ucc_geth_close; dev->get_stats = ucc_geth_get_stats; diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index bb4dac8c0c65..0579ba081aa5 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1184,6 +1184,7 @@ struct ucc_geth_private { struct ucc_geth_info *ug_info; struct ucc_fast_private *uccf; struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; /* linux network statistics */ struct ucc_geth *ug_regs; struct ucc_geth_init_pram *p_init_enet_param_shadow; diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index b56dff26772d..7a5899059c44 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -389,6 +389,8 @@ struct rhine_private { struct pci_dev *pdev; long pioaddr; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; spinlock_t lock; @@ -582,28 +584,25 @@ static void rhine_poll(struct net_device *dev) #endif #ifdef CONFIG_VIA_RHINE_NAPI -static int rhine_napipoll(struct net_device *dev, int *budget) +static int rhine_napipoll(struct napi_struct *napi, int budget) { - struct rhine_private *rp = netdev_priv(dev); + struct rhine_private *rp = container_of(napi, struct rhine_private, napi); + struct net_device *dev = rp->dev; void __iomem *ioaddr = rp->base; - int done, limit = min(dev->quota, *budget); + int work_done; - done = rhine_rx(dev, limit); - *budget -= done; - dev->quota -= done; + work_done = rhine_rx(dev, budget); - if (done < limit) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | IntrRxDropped | IntrRxNoBuf | IntrTxAborted | IntrTxDone | IntrTxError | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - return 0; } - else - return 1; + return work_done; } #endif @@ -707,6 +706,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); rp = netdev_priv(dev); + rp->dev = dev; rp->quirks = quirks; rp->pioaddr = pioaddr; rp->pdev = pdev; @@ -785,8 +785,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, dev->poll_controller = rhine_poll; #endif #ifdef CONFIG_VIA_RHINE_NAPI - dev->poll = rhine_napipoll; - dev->weight = 64; + netif_napi_add(dev, &rp->napi, rhine_napipoll, 64); #endif if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; @@ -1061,7 +1060,9 @@ static void init_registers(struct net_device *dev) rhine_set_rx_mode(dev); - netif_poll_enable(dev); +#ifdef CONFIG_VIA_RHINE_NAPI + napi_enable(&rp->napi); +#endif /* Enable interrupts by setting the interrupt mask. */ iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | @@ -1196,6 +1197,10 @@ static void rhine_tx_timeout(struct net_device *dev) /* protect against concurrent rx interrupts */ disable_irq(rp->pdev->irq); +#ifdef CONFIG_VIA_RHINE_NAPI + napi_disable(&rp->napi); +#endif + spin_lock(&rp->lock); /* clear all descriptors */ @@ -1324,7 +1329,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &rp->napi); #else rhine_rx(dev, RX_RING_SIZE); #endif @@ -1837,7 +1842,9 @@ static int rhine_close(struct net_device *dev) spin_lock_irq(&rp->lock); netif_stop_queue(dev); - netif_poll_disable(dev); +#ifdef CONFIG_VIA_RHINE_NAPI + napi_disable(&rp->napi); +#endif if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, " @@ -1936,6 +1943,9 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state) if (!netif_running(dev)) return 0; +#ifdef CONFIG_VIA_RHINE_NAPI + napi_disable(&rp->napi); +#endif netif_device_detach(dev); pci_save_state(pdev); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 4445810335a8..70e551c19e3a 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -72,6 +72,7 @@ struct netfront_info { struct list_head list; struct net_device *netdev; + struct napi_struct napi; struct net_device_stats stats; struct xen_netif_tx_front_ring tx; @@ -185,7 +186,8 @@ static int xennet_can_sg(struct net_device *dev) static void rx_refill_timeout(unsigned long data) { struct net_device *dev = (struct net_device *)data; - netif_rx_schedule(dev); + struct netfront_info *np = netdev_priv(dev); + netif_rx_schedule(dev, &np->napi); } static int netfront_tx_slot_available(struct netfront_info *np) @@ -342,12 +344,14 @@ static int xennet_open(struct net_device *dev) memset(&np->stats, 0, sizeof(np->stats)); + napi_enable(&np->napi); + spin_lock_bh(&np->rx_lock); if (netif_carrier_ok(dev)) { xennet_alloc_rx_buffers(dev); np->rx.sring->rsp_event = np->rx.rsp_cons + 1; if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); } spin_unlock_bh(&np->rx_lock); @@ -589,6 +593,7 @@ static int xennet_close(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); netif_stop_queue(np->netdev); + napi_disable(&np->napi); return 0; } @@ -872,15 +877,16 @@ static int handle_incoming_queue(struct net_device *dev, return packets_dropped; } -static int xennet_poll(struct net_device *dev, int *pbudget) +static int xennet_poll(struct napi_struct *napi, int budget) { - struct netfront_info *np = netdev_priv(dev); + struct netfront_info *np = container_of(napi, struct netfront_info, napi); + struct net_device *dev = np->netdev; struct sk_buff *skb; struct netfront_rx_info rinfo; struct xen_netif_rx_response *rx = &rinfo.rx; struct xen_netif_extra_info *extras = rinfo.extras; RING_IDX i, rp; - int work_done, budget, more_to_do = 1; + int work_done; struct sk_buff_head rxq; struct sk_buff_head errq; struct sk_buff_head tmpq; @@ -899,9 +905,6 @@ static int xennet_poll(struct net_device *dev, int *pbudget) skb_queue_head_init(&errq); skb_queue_head_init(&tmpq); - budget = *pbudget; - if (budget > dev->quota) - budget = dev->quota; rp = np->rx.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ @@ -1006,22 +1009,21 @@ err: xennet_alloc_rx_buffers(dev); - *pbudget -= work_done; - dev->quota -= work_done; - if (work_done < budget) { + int more_to_do = 0; + local_irq_save(flags); RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do); if (!more_to_do) - __netif_rx_complete(dev); + __netif_rx_complete(dev, napi); local_irq_restore(flags); } spin_unlock(&np->rx_lock); - return more_to_do; + return work_done; } static int xennet_change_mtu(struct net_device *dev, int mtu) @@ -1201,10 +1203,9 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->hard_start_xmit = xennet_start_xmit; netdev->stop = xennet_close; netdev->get_stats = xennet_get_stats; - netdev->poll = xennet_poll; + netif_napi_add(netdev, &np->napi, xennet_poll, 64); netdev->uninit = xennet_uninit; netdev->change_mtu = xennet_change_mtu; - netdev->weight = 64; netdev->features = NETIF_F_IP_CSUM; SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); @@ -1349,7 +1350,7 @@ static irqreturn_t xennet_interrupt(int irq, void *dev_id) xennet_tx_buf_gc(dev); /* Under tx_lock: protects access to rx shared-ring indexes. */ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); } spin_unlock_irqrestore(&np->tx_lock, flags); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e679b2751665..b93575db8cce 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -31,6 +31,7 @@ #ifdef __KERNEL__ #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include struct vlan_group; struct ethtool_ops; @@ -258,7 +260,6 @@ enum netdev_state_t __LINK_STATE_PRESENT, __LINK_STATE_SCHED, __LINK_STATE_NOCARRIER, - __LINK_STATE_RX_SCHED, __LINK_STATE_LINKWATCH_PENDING, __LINK_STATE_DORMANT, __LINK_STATE_QDISC_RUNNING, @@ -277,6 +278,110 @@ struct netdev_boot_setup { extern int __init netdev_boot_setup(char *str); +/* + * Structure for NAPI scheduling similar to tasklet but with weighting + */ +struct napi_struct { + /* The poll_list must only be managed by the entity which + * changes the state of the NAPI_STATE_SCHED bit. This means + * whoever atomically sets that bit can add this napi_struct + * to the per-cpu poll_list, and whoever clears that bit + * can remove from the list right before clearing the bit. + */ + struct list_head poll_list; + + unsigned long state; + int weight; + int (*poll)(struct napi_struct *, int); +#ifdef CONFIG_NETPOLL + spinlock_t poll_lock; + int poll_owner; + struct net_device *dev; + struct list_head dev_list; +#endif +}; + +enum +{ + NAPI_STATE_SCHED, /* Poll is scheduled */ +}; + +extern void FASTCALL(__napi_schedule(struct napi_struct *n)); + +/** + * napi_schedule_prep - check if napi can be scheduled + * @n: napi context + * + * Test if NAPI routine is already running, and if not mark + * it as running. This is used as a condition variable + * insure only one NAPI poll instance runs + */ +static inline int napi_schedule_prep(struct napi_struct *n) +{ + return !test_and_set_bit(NAPI_STATE_SCHED, &n->state); +} + +/** + * napi_schedule - schedule NAPI poll + * @n: napi context + * + * Schedule NAPI poll routine to be called if it is not already + * running. + */ +static inline void napi_schedule(struct napi_struct *n) +{ + if (napi_schedule_prep(n)) + __napi_schedule(n); +} + +/** + * napi_complete - NAPI processing complete + * @n: napi context + * + * Mark NAPI processing as complete. + */ +static inline void __napi_complete(struct napi_struct *n) +{ + BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); + list_del(&n->poll_list); + smp_mb__before_clear_bit(); + clear_bit(NAPI_STATE_SCHED, &n->state); +} + +static inline void napi_complete(struct napi_struct *n) +{ + local_irq_disable(); + __napi_complete(n); + local_irq_enable(); +} + +/** + * napi_disable - prevent NAPI from scheduling + * @n: napi context + * + * Stop NAPI from being scheduled on this context. + * Waits till any outstanding processing completes. + */ +static inline void napi_disable(struct napi_struct *n) +{ + while (test_and_set_bit(NAPI_STATE_SCHED, &n->state)) + msleep_interruptible(1); +} + +/** + * napi_enable - enable NAPI scheduling + * @n: napi context + * + * Resume NAPI from being scheduled on this context. + * Must be paired with napi_disable. + */ +static inline void napi_enable(struct napi_struct *n) +{ + BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); + smp_mb__before_clear_bit(); + clear_bit(NAPI_STATE_SCHED, &n->state); +} + /* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O @@ -319,6 +424,9 @@ struct net_device unsigned long state; struct list_head dev_list; +#ifdef CONFIG_NETPOLL + struct list_head napi_list; +#endif /* The device initialization function. Called only once. */ int (*init)(struct net_device *dev); @@ -430,12 +538,6 @@ struct net_device /* * Cache line mostly used on receive path (including eth_type_trans()) */ - struct list_head poll_list ____cacheline_aligned_in_smp; - /* Link to poll list */ - - int (*poll) (struct net_device *dev, int *quota); - int quota; - int weight; unsigned long last_rx; /* Time of last Rx */ /* Interface address info used in eth_type_trans() */ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast @@ -582,6 +684,12 @@ struct net_device #define NETDEV_ALIGN 32 #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) +/** + * netdev_priv - access network device private data + * @dev: network device + * + * Get network device private data + */ static inline void *netdev_priv(const struct net_device *dev) { return dev->priv; @@ -593,6 +701,23 @@ static inline void *netdev_priv(const struct net_device *dev) */ #define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev)) +static inline void netif_napi_add(struct net_device *dev, + struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), + int weight) +{ + INIT_LIST_HEAD(&napi->poll_list); + napi->poll = poll; + napi->weight = weight; +#ifdef CONFIG_NETPOLL + napi->dev = dev; + list_add(&napi->dev_list, &dev->napi_list); + spin_lock_init(&napi->poll_lock); + napi->poll_owner = -1; +#endif + set_bit(NAPI_STATE_SCHED, &napi->state); +} + struct packet_type { __be16 type; /* This is really htons(ether_type). */ struct net_device *dev; /* NULL is wildcarded here */ @@ -678,7 +803,6 @@ static inline int unregister_gifconf(unsigned int family) * Incoming packets are placed on per-cpu queues so that * no locking is needed. */ - struct softnet_data { struct net_device *output_queue; @@ -686,7 +810,7 @@ struct softnet_data struct list_head poll_list; struct sk_buff *completion_queue; - struct net_device backlog_dev; /* Sorry. 8) */ + struct napi_struct backlog; #ifdef CONFIG_NET_DMA struct dma_chan *net_dma; #endif @@ -704,11 +828,24 @@ static inline void netif_schedule(struct net_device *dev) __netif_schedule(dev); } +/** + * netif_start_queue - allow transmit + * @dev: network device + * + * Allow upper layers to call the device hard_start_xmit routine. + */ static inline void netif_start_queue(struct net_device *dev) { clear_bit(__LINK_STATE_XOFF, &dev->state); } +/** + * netif_wake_queue - restart transmit + * @dev: network device + * + * Allow upper layers to call the device hard_start_xmit routine. + * Used for flow control when transmit resources are available. + */ static inline void netif_wake_queue(struct net_device *dev) { #ifdef CONFIG_NETPOLL_TRAP @@ -721,16 +858,35 @@ static inline void netif_wake_queue(struct net_device *dev) __netif_schedule(dev); } +/** + * netif_stop_queue - stop transmitted packets + * @dev: network device + * + * Stop upper layers calling the device hard_start_xmit routine. + * Used for flow control when transmit resources are unavailable. + */ static inline void netif_stop_queue(struct net_device *dev) { set_bit(__LINK_STATE_XOFF, &dev->state); } +/** + * netif_queue_stopped - test if transmit queue is flowblocked + * @dev: network device + * + * Test if transmit queue on device is currently unable to send. + */ static inline int netif_queue_stopped(const struct net_device *dev) { return test_bit(__LINK_STATE_XOFF, &dev->state); } +/** + * netif_running - test if up + * @dev: network device + * + * Test if the device has been brought up. + */ static inline int netif_running(const struct net_device *dev) { return test_bit(__LINK_STATE_START, &dev->state); @@ -742,6 +898,14 @@ static inline int netif_running(const struct net_device *dev) * done at the overall netdevice level. * Also test the device if we're multiqueue. */ + +/** + * netif_start_subqueue - allow sending packets on subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Start individual transmit queue of a device with multiple transmit queues. + */ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) { #ifdef CONFIG_NETDEVICES_MULTIQUEUE @@ -749,6 +913,13 @@ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) #endif } +/** + * netif_stop_subqueue - stop sending packets on subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Stop individual transmit queue of a device with multiple transmit queues. + */ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) { #ifdef CONFIG_NETDEVICES_MULTIQUEUE @@ -760,6 +931,13 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) #endif } +/** + * netif_subqueue_stopped - test status of subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Check individual transmit queue of a device with multiple transmit queues. + */ static inline int netif_subqueue_stopped(const struct net_device *dev, u16 queue_index) { @@ -771,6 +949,14 @@ static inline int netif_subqueue_stopped(const struct net_device *dev, #endif } + +/** + * netif_wake_subqueue - allow sending packets on subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Resume individual transmit queue of a device with multiple transmit queues. + */ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index) { #ifdef CONFIG_NETDEVICES_MULTIQUEUE @@ -784,6 +970,13 @@ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index) #endif } +/** + * netif_is_multiqueue - test if device has multiple transmit queues + * @dev: network device + * + * Check if device has multiple transmit queues + * Always falls if NETDEVICE_MULTIQUEUE is not configured + */ static inline int netif_is_multiqueue(const struct net_device *dev) { #ifdef CONFIG_NETDEVICES_MULTIQUEUE @@ -796,20 +989,7 @@ static inline int netif_is_multiqueue(const struct net_device *dev) /* Use this variant when it is known for sure that it * is executing from interrupt context. */ -static inline void dev_kfree_skb_irq(struct sk_buff *skb) -{ - if (atomic_dec_and_test(&skb->users)) { - struct softnet_data *sd; - unsigned long flags; - - local_irq_save(flags); - sd = &__get_cpu_var(softnet_data); - skb->next = sd->completion_queue; - sd->completion_queue = skb; - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); - } -} +extern void dev_kfree_skb_irq(struct sk_buff *skb); /* Use this variant in places where it could be invoked * either from interrupt or non-interrupt context. @@ -833,18 +1013,28 @@ extern int dev_set_mac_address(struct net_device *, extern int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); -extern void dev_init(void); - extern int netdev_budget; /* Called by rtnetlink.c:rtnl_unlock() */ extern void netdev_run_todo(void); +/** + * dev_put - release reference to device + * @dev: network device + * + * Hold reference to device to keep it from being freed. + */ static inline void dev_put(struct net_device *dev) { atomic_dec(&dev->refcnt); } +/** + * dev_hold - get reference to device + * @dev: network device + * + * Release reference to device to allow it to be freed. + */ static inline void dev_hold(struct net_device *dev) { atomic_inc(&dev->refcnt); @@ -861,6 +1051,12 @@ static inline void dev_hold(struct net_device *dev) extern void linkwatch_fire_event(struct net_device *dev); +/** + * netif_carrier_ok - test if carrier present + * @dev: network device + * + * Check if carrier is present on device + */ static inline int netif_carrier_ok(const struct net_device *dev) { return !test_bit(__LINK_STATE_NOCARRIER, &dev->state); @@ -872,30 +1068,66 @@ extern void netif_carrier_on(struct net_device *dev); extern void netif_carrier_off(struct net_device *dev); +/** + * netif_dormant_on - mark device as dormant. + * @dev: network device + * + * Mark device as dormant (as per RFC2863). + * + * The dormant state indicates that the relevant interface is not + * actually in a condition to pass packets (i.e., it is not 'up') but is + * in a "pending" state, waiting for some external event. For "on- + * demand" interfaces, this new state identifies the situation where the + * interface is waiting for events to place it in the up state. + * + */ static inline void netif_dormant_on(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_DORMANT, &dev->state)) linkwatch_fire_event(dev); } +/** + * netif_dormant_off - set device as not dormant. + * @dev: network device + * + * Device is not in dormant state. + */ static inline void netif_dormant_off(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_DORMANT, &dev->state)) linkwatch_fire_event(dev); } +/** + * netif_dormant - test if carrier present + * @dev: network device + * + * Check if carrier is present on device + */ static inline int netif_dormant(const struct net_device *dev) { return test_bit(__LINK_STATE_DORMANT, &dev->state); } +/** + * netif_oper_up - test if device is operational + * @dev: network device + * + * Check if carrier is operational + */ static inline int netif_oper_up(const struct net_device *dev) { return (dev->operstate == IF_OPER_UP || dev->operstate == IF_OPER_UNKNOWN /* backward compat */); } -/* Hot-plugging. */ +/** + * netif_device_present - is device available or removed + * @dev: network device + * + * Check if device has not been removed from system. + */ static inline int netif_device_present(struct net_device *dev) { return test_bit(__LINK_STATE_PRESENT, &dev->state); @@ -955,46 +1187,38 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits) return (1 << debug_value) - 1; } -/* Test if receive needs to be scheduled */ -static inline int __netif_rx_schedule_prep(struct net_device *dev) -{ - return !test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state); -} - /* Test if receive needs to be scheduled but only if up */ -static inline int netif_rx_schedule_prep(struct net_device *dev) +static inline int netif_rx_schedule_prep(struct net_device *dev, + struct napi_struct *napi) { - return netif_running(dev) && __netif_rx_schedule_prep(dev); + return netif_running(dev) && napi_schedule_prep(napi); } /* Add interface to tail of rx poll list. This assumes that _prep has * already been called and returned 1. */ - -extern void __netif_rx_schedule(struct net_device *dev); +static inline void __netif_rx_schedule(struct net_device *dev, + struct napi_struct *napi) +{ + dev_hold(dev); + __napi_schedule(napi); +} /* Try to reschedule poll. Called by irq handler. */ -static inline void netif_rx_schedule(struct net_device *dev) +static inline void netif_rx_schedule(struct net_device *dev, + struct napi_struct *napi) { - if (netif_rx_schedule_prep(dev)) - __netif_rx_schedule(dev); + if (netif_rx_schedule_prep(dev, napi)) + __netif_rx_schedule(dev, napi); } -/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). - * Do not inline this? - */ -static inline int netif_rx_reschedule(struct net_device *dev, int undo) +/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). */ +static inline int netif_rx_reschedule(struct net_device *dev, + struct napi_struct *napi) { - if (netif_rx_schedule_prep(dev)) { - unsigned long flags; - - dev->quota += undo; - - local_irq_save(flags); - list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - local_irq_restore(flags); + if (napi_schedule_prep(napi)) { + __netif_rx_schedule(dev, napi); return 1; } return 0; @@ -1003,12 +1227,11 @@ static inline int netif_rx_reschedule(struct net_device *dev, int undo) /* same as netif_rx_complete, except that local_irq_save(flags) * has already been issued */ -static inline void __netif_rx_complete(struct net_device *dev) +static inline void __netif_rx_complete(struct net_device *dev, + struct napi_struct *napi) { - BUG_ON(!test_bit(__LINK_STATE_RX_SCHED, &dev->state)); - list_del(&dev->poll_list); - smp_mb__before_clear_bit(); - clear_bit(__LINK_STATE_RX_SCHED, &dev->state); + __napi_complete(napi); + dev_put(dev); } /* Remove interface from poll list: it must be in the poll list @@ -1016,28 +1239,22 @@ static inline void __netif_rx_complete(struct net_device *dev) * it completes the work. The device cannot be out of poll list at this * moment, it is BUG(). */ -static inline void netif_rx_complete(struct net_device *dev) +static inline void netif_rx_complete(struct net_device *dev, + struct napi_struct *napi) { unsigned long flags; local_irq_save(flags); - __netif_rx_complete(dev); + __netif_rx_complete(dev, napi); local_irq_restore(flags); } -static inline void netif_poll_disable(struct net_device *dev) -{ - while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) - /* No hurry. */ - schedule_timeout_interruptible(1); -} - -static inline void netif_poll_enable(struct net_device *dev) -{ - smp_mb__before_clear_bit(); - clear_bit(__LINK_STATE_RX_SCHED, &dev->state); -} - +/** + * netif_tx_lock - grab network device transmit lock + * @dev: network device + * + * Get network device transmit lock + */ static inline void netif_tx_lock(struct net_device *dev) { spin_lock(&dev->_xmit_lock); diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 29930b71a9aa..08dcc39ec18d 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -25,8 +25,6 @@ struct netpoll { struct netpoll_info { atomic_t refcnt; - spinlock_t poll_lock; - int poll_owner; int rx_flags; spinlock_t rx_lock; struct netpoll *rx_np; /* netpoll that registered an rx_hook */ @@ -64,32 +62,61 @@ static inline int netpoll_rx(struct sk_buff *skb) return ret; } -static inline void *netpoll_poll_lock(struct net_device *dev) +static inline int netpoll_receive_skb(struct sk_buff *skb) { + if (!list_empty(&skb->dev->napi_list)) + return netpoll_rx(skb); + return 0; +} + +static inline void *netpoll_poll_lock(struct napi_struct *napi) +{ + struct net_device *dev = napi->dev; + rcu_read_lock(); /* deal with race on ->npinfo */ - if (dev->npinfo) { - spin_lock(&dev->npinfo->poll_lock); - dev->npinfo->poll_owner = smp_processor_id(); - return dev->npinfo; + if (dev && dev->npinfo) { + spin_lock(&napi->poll_lock); + napi->poll_owner = smp_processor_id(); + return napi; } return NULL; } static inline void netpoll_poll_unlock(void *have) { - struct netpoll_info *npi = have; + struct napi_struct *napi = have; - if (npi) { - npi->poll_owner = -1; - spin_unlock(&npi->poll_lock); + if (napi) { + napi->poll_owner = -1; + spin_unlock(&napi->poll_lock); } rcu_read_unlock(); } +static inline void netpoll_netdev_init(struct net_device *dev) +{ + INIT_LIST_HEAD(&dev->napi_list); +} + #else -#define netpoll_rx(a) 0 -#define netpoll_poll_lock(a) NULL -#define netpoll_poll_unlock(a) +static inline int netpoll_rx(struct sk_buff *skb) +{ + return 0; +} +static inline int netpoll_receive_skb(struct sk_buff *skb) +{ + return 0; +} +static inline void *netpoll_poll_lock(struct napi_struct *napi) +{ + return NULL; +} +static inline void netpoll_poll_unlock(void *have) +{ +} +static inline void netpoll_netdev_init(struct net_device *dev) +{ +} #endif #endif diff --git a/net/core/dev.c b/net/core/dev.c index a76021c71207..29cf00c5d865 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -220,7 +220,8 @@ static RAW_NOTIFIER_HEAD(netdev_chain); * Device drivers call our routines to queue packets here. We empty the * queue in the local softnet handler. */ -DEFINE_PER_CPU(struct softnet_data, softnet_data) = { NULL }; + +DEFINE_PER_CPU(struct softnet_data, softnet_data); #ifdef CONFIG_SYSFS extern int netdev_sysfs_init(void); @@ -1018,16 +1019,12 @@ int dev_close(struct net_device *dev) clear_bit(__LINK_STATE_START, &dev->state); /* Synchronize to scheduled poll. We cannot touch poll list, - * it can be even on different cpu. So just clear netif_running(), - * and wait when poll really will happen. Actually, the best place - * for this is inside dev->stop() after device stopped its irq - * engine, but this requires more changes in devices. */ - + * it can be even on different cpu. So just clear netif_running(). + * + * dev->stop() will invoke napi_disable() on all of it's + * napi_struct instances on this device. + */ smp_mb__after_clear_bit(); /* Commit netif_running(). */ - while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) { - /* No hurry. */ - msleep(1); - } /* * Call the device specific close. This cannot fail. @@ -1233,21 +1230,21 @@ void __netif_schedule(struct net_device *dev) } EXPORT_SYMBOL(__netif_schedule); -void __netif_rx_schedule(struct net_device *dev) +void dev_kfree_skb_irq(struct sk_buff *skb) { - unsigned long flags; + if (atomic_dec_and_test(&skb->users)) { + struct softnet_data *sd; + unsigned long flags; - local_irq_save(flags); - dev_hold(dev); - list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); - if (dev->quota < 0) - dev->quota += dev->weight; - else - dev->quota = dev->weight; - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - local_irq_restore(flags); + local_irq_save(flags); + sd = &__get_cpu_var(softnet_data); + skb->next = sd->completion_queue; + sd->completion_queue = skb; + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_restore(flags); + } } -EXPORT_SYMBOL(__netif_rx_schedule); +EXPORT_SYMBOL(dev_kfree_skb_irq); void dev_kfree_skb_any(struct sk_buff *skb) { @@ -1259,7 +1256,12 @@ void dev_kfree_skb_any(struct sk_buff *skb) EXPORT_SYMBOL(dev_kfree_skb_any); -/* Hot-plugging. */ +/** + * netif_device_detach - mark device as removed + * @dev: network device + * + * Mark device as removed from system and therefore no longer available. + */ void netif_device_detach(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && @@ -1269,6 +1271,12 @@ void netif_device_detach(struct net_device *dev) } EXPORT_SYMBOL(netif_device_detach); +/** + * netif_device_attach - mark device as attached + * @dev: network device + * + * Mark device as attached from system and restart if needed. + */ void netif_device_attach(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && @@ -1730,7 +1738,7 @@ enqueue: return NET_RX_SUCCESS; } - netif_rx_schedule(&queue->backlog_dev); + napi_schedule(&queue->backlog); goto enqueue; } @@ -1771,6 +1779,7 @@ static inline struct net_device *skb_bond(struct sk_buff *skb) return dev; } + static void net_tx_action(struct softirq_action *h) { struct softnet_data *sd = &__get_cpu_var(softnet_data); @@ -1927,7 +1936,7 @@ int netif_receive_skb(struct sk_buff *skb) __be16 type; /* if we've gotten here through NAPI, check netpoll */ - if (skb->dev->poll && netpoll_rx(skb)) + if (netpoll_receive_skb(skb)) return NET_RX_DROP; if (!skb->tstamp.tv64) @@ -2017,22 +2026,25 @@ out: return ret; } -static int process_backlog(struct net_device *backlog_dev, int *budget) +static int process_backlog(struct napi_struct *napi, int quota) { int work = 0; - int quota = min(backlog_dev->quota, *budget); struct softnet_data *queue = &__get_cpu_var(softnet_data); unsigned long start_time = jiffies; - backlog_dev->weight = weight_p; - for (;;) { + napi->weight = weight_p; + do { struct sk_buff *skb; struct net_device *dev; local_irq_disable(); skb = __skb_dequeue(&queue->input_pkt_queue); - if (!skb) - goto job_done; + if (!skb) { + __napi_complete(napi); + local_irq_enable(); + break; + } + local_irq_enable(); dev = skb->dev; @@ -2040,67 +2052,86 @@ static int process_backlog(struct net_device *backlog_dev, int *budget) netif_receive_skb(skb); dev_put(dev); + } while (++work < quota && jiffies == start_time); - work++; - - if (work >= quota || jiffies - start_time > 1) - break; - - } - - backlog_dev->quota -= work; - *budget -= work; - return -1; - -job_done: - backlog_dev->quota -= work; - *budget -= work; - - list_del(&backlog_dev->poll_list); - smp_mb__before_clear_bit(); - netif_poll_enable(backlog_dev); - - local_irq_enable(); - return 0; + return work; } +/** + * __napi_schedule - schedule for receive + * @napi: entry to schedule + * + * The entry's receive function will be scheduled to run + */ +void fastcall __napi_schedule(struct napi_struct *n) +{ + unsigned long flags; + + local_irq_save(flags); + list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list); + __raise_softirq_irqoff(NET_RX_SOFTIRQ); + local_irq_restore(flags); +} +EXPORT_SYMBOL(__napi_schedule); + + static void net_rx_action(struct softirq_action *h) { - struct softnet_data *queue = &__get_cpu_var(softnet_data); + struct list_head *list = &__get_cpu_var(softnet_data).poll_list; unsigned long start_time = jiffies; int budget = netdev_budget; void *have; local_irq_disable(); - while (!list_empty(&queue->poll_list)) { - struct net_device *dev; + while (!list_empty(list)) { + struct napi_struct *n; + int work, weight; - if (budget <= 0 || jiffies - start_time > 1) + /* If softirq window is exhuasted then punt. + * + * Note that this is a slight policy change from the + * previous NAPI code, which would allow up to 2 + * jiffies to pass before breaking out. The test + * used to be "jiffies - start_time > 1". + */ + if (unlikely(budget <= 0 || jiffies != start_time)) goto softnet_break; local_irq_enable(); - dev = list_entry(queue->poll_list.next, - struct net_device, poll_list); - have = netpoll_poll_lock(dev); + /* Even though interrupts have been re-enabled, this + * access is safe because interrupts can only add new + * entries to the tail of this list, and only ->poll() + * calls can remove this head entry from the list. + */ + n = list_entry(list->next, struct napi_struct, poll_list); - if (dev->quota <= 0 || dev->poll(dev, &budget)) { - netpoll_poll_unlock(have); - local_irq_disable(); - list_move_tail(&dev->poll_list, &queue->poll_list); - if (dev->quota < 0) - dev->quota += dev->weight; - else - dev->quota = dev->weight; - } else { - netpoll_poll_unlock(have); - dev_put(dev); - local_irq_disable(); - } + have = netpoll_poll_lock(n); + + weight = n->weight; + + work = n->poll(n, weight); + + WARN_ON_ONCE(work > weight); + + budget -= work; + + local_irq_disable(); + + /* Drivers must not modify the NAPI state if they + * consume the entire weight. In such cases this code + * still "owns" the NAPI instance and therefore can + * move the instance around on the list at-will. + */ + if (unlikely(work == weight)) + list_move_tail(&n->poll_list, list); + + netpoll_poll_unlock(have); } out: local_irq_enable(); + #ifdef CONFIG_NET_DMA /* * There may not be any more sk_buffs coming right now, so push @@ -2115,6 +2146,7 @@ out: } } #endif + return; softnet_break: @@ -3704,6 +3736,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev->egress_subqueue_count = queue_count; dev->get_stats = internal_stats; + netpoll_netdev_init(dev); setup(dev); strcpy(dev->name, name); return dev; @@ -4076,10 +4109,9 @@ static int __init net_dev_init(void) skb_queue_head_init(&queue->input_pkt_queue); queue->completion_queue = NULL; INIT_LIST_HEAD(&queue->poll_list); - set_bit(__LINK_STATE_START, &queue->backlog_dev.state); - queue->backlog_dev.weight = weight_p; - queue->backlog_dev.poll = process_backlog; - atomic_set(&queue->backlog_dev.refcnt, 1); + + queue->backlog.poll = process_backlog; + queue->backlog.weight = weight_p; } netdev_dma_register(); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 5c19b0646d7a..79159db6acb9 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -216,20 +216,6 @@ static ssize_t store_tx_queue_len(struct device *dev, return netdev_store(dev, attr, buf, len, change_tx_queue_len); } -NETDEVICE_SHOW(weight, fmt_dec); - -static int change_weight(struct net_device *net, unsigned long new_weight) -{ - net->weight = new_weight; - return 0; -} - -static ssize_t store_weight(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_weight); -} - static struct device_attribute net_class_attributes[] = { __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), __ATTR(iflink, S_IRUGO, show_iflink, NULL), @@ -246,7 +232,6 @@ static struct device_attribute net_class_attributes[] = { __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, store_tx_queue_len), - __ATTR(weight, S_IRUGO | S_IWUSR, show_weight, store_weight), {} }; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index de1b26aa5720..abe6e3a4cc44 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -119,19 +119,22 @@ static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, static void poll_napi(struct netpoll *np) { struct netpoll_info *npinfo = np->dev->npinfo; + struct napi_struct *napi; int budget = 16; - if (test_bit(__LINK_STATE_RX_SCHED, &np->dev->state) && - npinfo->poll_owner != smp_processor_id() && - spin_trylock(&npinfo->poll_lock)) { - npinfo->rx_flags |= NETPOLL_RX_DROP; - atomic_inc(&trapped); + list_for_each_entry(napi, &np->dev->napi_list, dev_list) { + if (test_bit(NAPI_STATE_SCHED, &napi->state) && + napi->poll_owner != smp_processor_id() && + spin_trylock(&napi->poll_lock)) { + npinfo->rx_flags |= NETPOLL_RX_DROP; + atomic_inc(&trapped); - np->dev->poll(np->dev, &budget); + napi->poll(napi, budget); - atomic_dec(&trapped); - npinfo->rx_flags &= ~NETPOLL_RX_DROP; - spin_unlock(&npinfo->poll_lock); + atomic_dec(&trapped); + npinfo->rx_flags &= ~NETPOLL_RX_DROP; + spin_unlock(&napi->poll_lock); + } } } @@ -157,7 +160,7 @@ void netpoll_poll(struct netpoll *np) /* Process pending work on NIC */ np->dev->poll_controller(np->dev); - if (np->dev->poll) + if (!list_empty(&np->dev->napi_list)) poll_napi(np); service_arp_queue(np->dev->npinfo); @@ -233,6 +236,17 @@ repeat: return skb; } +static int netpoll_owner_active(struct net_device *dev) +{ + struct napi_struct *napi; + + list_for_each_entry(napi, &dev->napi_list, dev_list) { + if (napi->poll_owner == smp_processor_id()) + return 1; + } + return 0; +} + static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) { int status = NETDEV_TX_BUSY; @@ -246,8 +260,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) } /* don't get messages out of order, and no recursion */ - if (skb_queue_len(&npinfo->txq) == 0 && - npinfo->poll_owner != smp_processor_id()) { + if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) { unsigned long flags; local_irq_save(flags); @@ -652,8 +665,6 @@ int netpoll_setup(struct netpoll *np) npinfo->rx_flags = 0; npinfo->rx_np = NULL; - spin_lock_init(&npinfo->poll_lock); - npinfo->poll_owner = -1; spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4756d5857abf..2b0b6fac6cef 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -634,7 +634,6 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len); - NLA_PUT_U32(skb, IFLA_WEIGHT, dev->weight); NLA_PUT_U8(skb, IFLA_OPERSTATE, netif_running(dev) ? dev->operstate : IF_OPER_DOWN); NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode); @@ -834,9 +833,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, if (tb[IFLA_TXQLEN]) dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); - if (tb[IFLA_WEIGHT]) - dev->weight = nla_get_u32(tb[IFLA_WEIGHT]); - if (tb[IFLA_OPERSTATE]) set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); @@ -1074,8 +1070,6 @@ replay: nla_len(tb[IFLA_BROADCAST])); if (tb[IFLA_TXQLEN]) dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); - if (tb[IFLA_WEIGHT]) - dev->weight = nla_get_u32(tb[IFLA_WEIGHT]); if (tb[IFLA_OPERSTATE]) set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); if (tb[IFLA_LINKMODE]) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index c81649cf0b9e..e970e8e75720 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -256,6 +256,12 @@ static void dev_watchdog_down(struct net_device *dev) netif_tx_unlock_bh(dev); } +/** + * netif_carrier_on - set carrier + * @dev: network device + * + * Device has detected that carrier. + */ void netif_carrier_on(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) @@ -264,6 +270,12 @@ void netif_carrier_on(struct net_device *dev) __netdev_watchdog_up(dev); } +/** + * netif_carrier_off - clear carrier + * @dev: network device + * + * Device has detected loss of carrier. + */ void netif_carrier_off(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) From e71992889ee289a87f6641cfa40d64a5699bcb53 Mon Sep 17 00:00:00 2001 From: Pavel Emelianov Date: Wed, 8 Aug 2007 22:16:38 -0700 Subject: [PATCH 1034/2804] [RTNETLINK]: Introduce generic rtnl_create_link(). This routine gets the parsed rtnl attributes and creates a new link with generic info (IFLA_LINKINFO policy). Its intention is to help the drivers, that need to create several links at once (like VETH). This is nothing but a copy-paste-ed part of rtnl_newlink() function that is responsible for creation of new device. Signed-off-by: Pavel Emelianov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/rtnetlink.h | 4 +++ net/core/rtnetlink.c | 79 ++++++++++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 3861c05cdf0f..8218288ab7ee 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -78,6 +78,10 @@ extern void __rtnl_link_unregister(struct rtnl_link_ops *ops); extern int rtnl_link_register(struct rtnl_link_ops *ops); extern void rtnl_link_unregister(struct rtnl_link_ops *ops); +extern struct net_device *rtnl_create_link(char *ifname, + const struct rtnl_link_ops *ops, struct nlattr *tb[]); +extern const struct nla_policy ifla_policy[IFLA_MAX+1]; + #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) #endif diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2b0b6fac6cef..dca9e80ba574 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -713,7 +713,7 @@ cont: return skb->len; } -static const struct nla_policy ifla_policy[IFLA_MAX+1] = { +const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, @@ -937,6 +937,48 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return 0; } +struct net_device *rtnl_create_link(char *ifname, + const struct rtnl_link_ops *ops, struct nlattr *tb[]) +{ + int err; + struct net_device *dev; + + err = -ENOMEM; + dev = alloc_netdev(ops->priv_size, ifname, ops->setup); + if (!dev) + goto err; + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err_free; + } + + dev->rtnl_link_ops = ops; + + if (tb[IFLA_MTU]) + dev->mtu = nla_get_u32(tb[IFLA_MTU]); + if (tb[IFLA_ADDRESS]) + memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), + nla_len(tb[IFLA_ADDRESS])); + if (tb[IFLA_BROADCAST]) + memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), + nla_len(tb[IFLA_BROADCAST])); + if (tb[IFLA_TXQLEN]) + dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); + if (tb[IFLA_OPERSTATE]) + set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); + if (tb[IFLA_LINKMODE]) + dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); + + return dev; + +err_free: + free_netdev(dev); +err: + return ERR_PTR(err); +} + static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { const struct rtnl_link_ops *ops; @@ -1049,38 +1091,17 @@ replay: if (!ifname[0]) snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); - dev = alloc_netdev(ops->priv_size, ifname, ops->setup); - if (!dev) - return -ENOMEM; - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err_free; - } - dev->rtnl_link_ops = ops; + dev = rtnl_create_link(ifname, ops, tb); - if (tb[IFLA_MTU]) - dev->mtu = nla_get_u32(tb[IFLA_MTU]); - if (tb[IFLA_ADDRESS]) - memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), - nla_len(tb[IFLA_ADDRESS])); - if (tb[IFLA_BROADCAST]) - memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), - nla_len(tb[IFLA_BROADCAST])); - if (tb[IFLA_TXQLEN]) - dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); - if (tb[IFLA_OPERSTATE]) - set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); - if (tb[IFLA_LINKMODE]) - dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); - - if (ops->newlink) + if (IS_ERR(dev)) + err = PTR_ERR(dev); + else if (ops->newlink) err = ops->newlink(dev, tb, data); else err = register_netdevice(dev); -err_free: - if (err < 0) + + if (err < 0 && !IS_ERR(dev)) free_netdev(dev); return err; } @@ -1329,3 +1350,5 @@ EXPORT_SYMBOL(rtnl_unlock); EXPORT_SYMBOL(rtnl_unicast); EXPORT_SYMBOL(rtnl_notify); EXPORT_SYMBOL(rtnl_set_sk_err); +EXPORT_SYMBOL(rtnl_create_link); +EXPORT_SYMBOL(ifla_policy); From e314dbdc1c0dc6a548ecf0afce28ecfd538ff568 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 25 Sep 2007 16:14:46 -0700 Subject: [PATCH 1035/2804] [NET]: Virtual ethernet device driver. Veth stands for Virtual ETHernet. It is a simple tunnel driver that works at the link layer and looks like a pair of ethernet devices interconnected with each other. Mainly it allows to communicate between network namespaces but it can be used as is as well. The newlink callback is organized that way to make it easy to create the peer device in the separate namespace when we have them in kernel. This implementation uses another interface - the RTM_NRELINK message introduced by Patric. Bug fixes from Daniel Lezcano. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/net/Kconfig | 6 + drivers/net/Makefile | 1 + drivers/net/veth.c | 477 +++++++++++++++++++++++++++++++++++++++++++ include/net/veth.h | 12 ++ 4 files changed, 496 insertions(+) create mode 100644 drivers/net/veth.c create mode 100644 include/net/veth.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c5519250efd9..e0a979184c0a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -135,6 +135,12 @@ config TUN If you don't know what to use this for, you don't need it. +config VETH + tristate "Virtual ethernet device" + ---help--- + The device is an ethernet tunnel. Devices are created in pairs. When + one end receives the packet it appears on its pair and vice versa. + config NET_SB1000 tristate "General Instruments Surfboard 1000" depends on PNP diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9c928a845841..d6f7302ab72d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -193,6 +193,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_TUN) += tun.o +obj-$(CONFIG_VETH) += veth.o obj-$(CONFIG_NET_NETX) += netx-eth.o obj-$(CONFIG_DL2K) += dl2k.o obj-$(CONFIG_R8169) += r8169.o diff --git a/drivers/net/veth.c b/drivers/net/veth.c new file mode 100644 index 000000000000..ca1c6893b809 --- /dev/null +++ b/drivers/net/veth.c @@ -0,0 +1,477 @@ +/* + * drivers/net/veth.c + * + * Copyright (C) 2007 OpenVZ http://openvz.org, SWsoft Inc + * + * Author: Pavel Emelianov + * Ethtool interface from: Eric W. Biederman + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define DRV_NAME "veth" +#define DRV_VERSION "1.0" + +struct veth_net_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + unsigned long tx_dropped; +}; + +struct veth_priv { + struct net_device *peer; + struct net_device *dev; + struct list_head list; + struct veth_net_stats *stats; + unsigned ip_summed; +}; + +static LIST_HEAD(veth_list); + +/* + * ethtool interface + */ + +static struct { + const char string[ETH_GSTRING_LEN]; +} ethtool_stats_keys[] = { + { "peer_ifindex" }, +}; + +static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->supported = 0; + cmd->advertising = 0; + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_TP; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); +} + +static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + switch(stringset) { + case ETH_SS_STATS: + memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); + break; + } +} + +static int veth_get_stats_count(struct net_device *dev) +{ + return ARRAY_SIZE(ethtool_stats_keys); +} + +static void veth_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + data[0] = priv->peer->ifindex; +} + +static u32 veth_get_rx_csum(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + return priv->ip_summed == CHECKSUM_UNNECESSARY; +} + +static int veth_set_rx_csum(struct net_device *dev, u32 data) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; + return 0; +} + +static u32 veth_get_tx_csum(struct net_device *dev) +{ + return (dev->features & NETIF_F_NO_CSUM) != 0; +} + +static int veth_set_tx_csum(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= NETIF_F_NO_CSUM; + else + dev->features &= ~NETIF_F_NO_CSUM; + return 0; +} + +static struct ethtool_ops veth_ethtool_ops = { + .get_settings = veth_get_settings, + .get_drvinfo = veth_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_rx_csum = veth_get_rx_csum, + .set_rx_csum = veth_set_rx_csum, + .get_tx_csum = veth_get_tx_csum, + .set_tx_csum = veth_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_strings = veth_get_strings, + .get_stats_count = veth_get_stats_count, + .get_ethtool_stats = veth_get_ethtool_stats, +}; + +/* + * xmit + */ + +static int veth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device *rcv = NULL; + struct veth_priv *priv, *rcv_priv; + struct veth_net_stats *stats; + int length, cpu; + + skb_orphan(skb); + + priv = netdev_priv(dev); + rcv = priv->peer; + rcv_priv = netdev_priv(rcv); + + cpu = smp_processor_id(); + stats = per_cpu_ptr(priv->stats, cpu); + + if (!(rcv->flags & IFF_UP)) + goto outf; + + skb->pkt_type = PACKET_HOST; + skb->protocol = eth_type_trans(skb, rcv); + if (dev->features & NETIF_F_NO_CSUM) + skb->ip_summed = rcv_priv->ip_summed; + + dst_release(skb->dst); + skb->dst = NULL; + skb->mark = 0; + secpath_reset(skb); + nf_reset(skb); + + length = skb->len; + + stats->tx_bytes += length; + stats->tx_packets++; + + stats = per_cpu_ptr(rcv_priv->stats, cpu); + stats->rx_bytes += length; + stats->rx_packets++; + + netif_rx(skb); + return 0; + +outf: + kfree_skb(skb); + stats->tx_dropped++; + return 0; +} + +/* + * general routines + */ + +static struct net_device_stats *veth_get_stats(struct net_device *dev) +{ + struct veth_priv *priv; + struct net_device_stats *dev_stats; + int cpu; + struct veth_net_stats *stats; + + priv = netdev_priv(dev); + dev_stats = &dev->stats; + + dev_stats->rx_packets = 0; + dev_stats->tx_packets = 0; + dev_stats->rx_bytes = 0; + dev_stats->tx_bytes = 0; + dev_stats->tx_dropped = 0; + + for_each_online_cpu(cpu) { + stats = per_cpu_ptr(priv->stats, cpu); + + dev_stats->rx_packets += stats->rx_packets; + dev_stats->tx_packets += stats->tx_packets; + dev_stats->rx_bytes += stats->rx_bytes; + dev_stats->tx_bytes += stats->tx_bytes; + dev_stats->tx_dropped += stats->tx_dropped; + } + + return dev_stats; +} + +static int veth_open(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + if (priv->peer == NULL) + return -ENOTCONN; + + if (priv->peer->flags & IFF_UP) { + netif_carrier_on(dev); + netif_carrier_on(priv->peer); + } + return 0; +} + +static int veth_close(struct net_device *dev) +{ + struct veth_priv *priv; + + if (netif_carrier_ok(dev)) { + priv = netdev_priv(dev); + netif_carrier_off(dev); + netif_carrier_off(priv->peer); + } + return 0; +} + +static int veth_dev_init(struct net_device *dev) +{ + struct veth_net_stats *stats; + struct veth_priv *priv; + + stats = alloc_percpu(struct veth_net_stats); + if (stats == NULL) + return -ENOMEM; + + priv = netdev_priv(dev); + priv->stats = stats; + return 0; +} + +static void veth_dev_free(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + free_percpu(priv->stats); + free_netdev(dev); +} + +static void veth_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->hard_start_xmit = veth_xmit; + dev->get_stats = veth_get_stats; + dev->open = veth_open; + dev->stop = veth_close; + dev->ethtool_ops = &veth_ethtool_ops; + dev->features |= NETIF_F_LLTX; + dev->init = veth_dev_init; + dev->destructor = veth_dev_free; +} + +/* + * netlink interface + */ + +static int veth_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + return 0; +} + +static struct rtnl_link_ops veth_link_ops; + +static int veth_newlink(struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + int err; + struct net_device *peer; + struct veth_priv *priv; + char ifname[IFNAMSIZ]; + struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; + + /* + * create and register peer first + * + * struct ifinfomsg is at the head of VETH_INFO_PEER, but we + * skip it since no info from it is useful yet + */ + + if (data != NULL && data[VETH_INFO_PEER] != NULL) { + struct nlattr *nla_peer; + + nla_peer = data[VETH_INFO_PEER]; + err = nla_parse(peer_tb, IFLA_MAX, + nla_data(nla_peer) + sizeof(struct ifinfomsg), + nla_len(nla_peer) - sizeof(struct ifinfomsg), + ifla_policy); + if (err < 0) + return err; + + err = veth_validate(peer_tb, NULL); + if (err < 0) + return err; + + tbp = peer_tb; + } else + tbp = tb; + + if (tbp[IFLA_IFNAME]) + nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); + else + snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); + + peer = rtnl_create_link(ifname, &veth_link_ops, tbp); + if (IS_ERR(peer)) + return PTR_ERR(peer); + + if (tbp[IFLA_ADDRESS] == NULL) + random_ether_addr(peer->dev_addr); + + err = register_netdevice(peer); + if (err < 0) + goto err_register_peer; + + netif_carrier_off(peer); + + /* + * register dev last + * + * note, that since we've registered new device the dev's name + * should be re-allocated + */ + + if (tb[IFLA_ADDRESS] == NULL) + random_ether_addr(dev->dev_addr); + + if (tb[IFLA_IFNAME]) + nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); + else + snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err_alloc_name; + } + + err = register_netdevice(dev); + if (err < 0) + goto err_register_dev; + + netif_carrier_off(dev); + + /* + * tie the deviced together + */ + + priv = netdev_priv(dev); + priv->dev = dev; + priv->peer = peer; + list_add(&priv->list, &veth_list); + + priv = netdev_priv(peer); + priv->dev = peer; + priv->peer = dev; + INIT_LIST_HEAD(&priv->list); + return 0; + +err_register_dev: + /* nothing to do */ +err_alloc_name: + unregister_netdevice(peer); + return err; + +err_register_peer: + free_netdev(peer); + return err; +} + +static void veth_dellink(struct net_device *dev) +{ + struct veth_priv *priv; + struct net_device *peer; + + priv = netdev_priv(dev); + peer = priv->peer; + + if (!list_empty(&priv->list)) + list_del(&priv->list); + + priv = netdev_priv(peer); + if (!list_empty(&priv->list)) + list_del(&priv->list); + + unregister_netdevice(dev); + unregister_netdevice(peer); +} + +static const struct nla_policy veth_policy[VETH_INFO_MAX + 1]; + +static struct rtnl_link_ops veth_link_ops = { + .kind = DRV_NAME, + .priv_size = sizeof(struct veth_priv), + .setup = veth_setup, + .validate = veth_validate, + .newlink = veth_newlink, + .dellink = veth_dellink, + .policy = veth_policy, + .maxtype = VETH_INFO_MAX, +}; + +/* + * init/fini + */ + +static __init int veth_init(void) +{ + return rtnl_link_register(&veth_link_ops); +} + +static __exit void veth_exit(void) +{ + struct veth_priv *priv, *next; + + rtnl_lock(); + /* + * cannot trust __rtnl_link_unregister() to unregister all + * devices, as each ->dellink call will remove two devices + * from the list at once. + */ + list_for_each_entry_safe(priv, next, &veth_list, list) + veth_dellink(priv->dev); + + __rtnl_link_unregister(&veth_link_ops); + rtnl_unlock(); +} + +module_init(veth_init); +module_exit(veth_exit); + +MODULE_DESCRIPTION("Virtual Ethernet Tunnel"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_RTNL_LINK(DRV_NAME); diff --git a/include/net/veth.h b/include/net/veth.h new file mode 100644 index 000000000000..3354c1eb424e --- /dev/null +++ b/include/net/veth.h @@ -0,0 +1,12 @@ +#ifndef __NET_VETH_H_ +#define __NET_VETH_H_ + +enum { + VETH_INFO_UNSPEC, + VETH_INFO_PEER, + + __VETH_INFO_MAX +#define VETH_INFO_MAX (__VETH_INFO_MAX - 1) +}; + +#endif From 71c87e0cedca843162206c698cfa02e5fea9e2e3 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Wed, 8 Aug 2007 22:38:05 -0700 Subject: [PATCH 1036/2804] [NET]: Generic Large Receive Offload for TCP traffic This patch provides generic Large Receive Offload (LRO) functionality for IPv4/TCP traffic. LRO combines received tcp packets to a single larger tcp packet and passes them then to the network stack in order to increase performance (throughput). The interface supports two modes: Drivers can either pass SKBs or fragment lists to the LRO engine. Signed-off-by: Jan-Bernd Themann Signed-off-by: David S. Miller --- include/linux/inet_lro.h | 177 ++++++++++++ net/ipv4/Kconfig | 8 + net/ipv4/Makefile | 1 + net/ipv4/inet_lro.c | 600 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 786 insertions(+) create mode 100644 include/linux/inet_lro.h create mode 100644 net/ipv4/inet_lro.c diff --git a/include/linux/inet_lro.h b/include/linux/inet_lro.h new file mode 100644 index 000000000000..e1fc1d16d3cd --- /dev/null +++ b/include/linux/inet_lro.h @@ -0,0 +1,177 @@ +/* + * linux/include/linux/inet_lro.h + * + * Large Receive Offload (ipv4 / tcp) + * + * (C) Copyright IBM Corp. 2007 + * + * Authors: + * Jan-Bernd Themann + * Christoph Raisch + * + * + * 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; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __INET_LRO_H_ +#define __INET_LRO_H_ + +#include +#include + +/* + * LRO statistics + */ + +struct net_lro_stats { + unsigned long aggregated; + unsigned long flushed; + unsigned long no_desc; +}; + +/* + * LRO descriptor for a tcp session + */ +struct net_lro_desc { + struct sk_buff *parent; + struct sk_buff *last_skb; + struct skb_frag_struct *next_frag; + struct iphdr *iph; + struct tcphdr *tcph; + struct vlan_group *vgrp; + __wsum data_csum; + u32 tcp_rcv_tsecr; + u32 tcp_rcv_tsval; + u32 tcp_ack; + u32 tcp_next_seq; + u32 skb_tot_frags_len; + u16 ip_tot_len; + u16 tcp_saw_tstamp; /* timestamps enabled */ + u16 tcp_window; + u16 vlan_tag; + int pkt_aggr_cnt; /* counts aggregated packets */ + int vlan_packet; + int mss; + int active; +}; + +/* + * Large Receive Offload (LRO) Manager + * + * Fields must be set by driver + */ + +struct net_lro_mgr { + struct net_device *dev; + struct net_lro_stats stats; + + /* LRO features */ + unsigned long features; +#define LRO_F_NAPI 1 /* Pass packets to stack via NAPI */ +#define LRO_F_EXTRACT_VLAN_ID 2 /* Set flag if VLAN IDs are extracted + from received packets and eth protocol + is still ETH_P_8021Q */ + + u32 ip_summed; /* Set in non generated SKBs in page mode */ + u32 ip_summed_aggr; /* Set in aggregated SKBs: CHECKSUM_UNNECESSARY + * or CHECKSUM_NONE */ + + int max_desc; /* Max number of LRO descriptors */ + int max_aggr; /* Max number of LRO packets to be aggregated */ + + struct net_lro_desc *lro_arr; /* Array of LRO descriptors */ + + /* + * Optimized driver functions + * + * get_skb_header: returns tcp and ip header for packet in SKB + */ + int (*get_skb_header)(struct sk_buff *skb, void **ip_hdr, + void **tcpudp_hdr, u64 *hdr_flags, void *priv); + + /* hdr_flags: */ +#define LRO_IPV4 1 /* ip_hdr is IPv4 header */ +#define LRO_TCP 2 /* tcpudp_hdr is TCP header */ + + /* + * get_frag_header: returns mac, tcp and ip header for packet in SKB + * + * @hdr_flags: Indicate what kind of LRO has to be done + * (IPv4/IPv6/TCP/UDP) + */ + int (*get_frag_header)(struct skb_frag_struct *frag, void **mac_hdr, + void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags, + void *priv); +}; + +/* + * Processes a SKB + * + * @lro_mgr: LRO manager to use + * @skb: SKB to aggregate + * @priv: Private data that may be used by driver functions + * (for example get_tcp_ip_hdr) + */ + +void lro_receive_skb(struct net_lro_mgr *lro_mgr, + struct sk_buff *skb, + void *priv); + +/* + * Processes a SKB with VLAN HW acceleration support + */ + +void lro_vlan_hwaccel_receive_skb(struct net_lro_mgr *lro_mgr, + struct sk_buff *skb, + struct vlan_group *vgrp, + u16 vlan_tag, + void *priv); + +/* + * Processes a fragment list + * + * This functions aggregate fragments and generate SKBs do pass + * the packets to the stack. + * + * @lro_mgr: LRO manager to use + * @frags: Fragment to be processed. Must contain entire header in first + * element. + * @len: Length of received data + * @true_size: Actual size of memory the fragment is consuming + * @priv: Private data that may be used by driver functions + * (for example get_tcp_ip_hdr) + */ + +void lro_receive_frags(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, void *priv, __wsum sum); + +void lro_vlan_hwaccel_receive_frags(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, + struct vlan_group *vgrp, + u16 vlan_tag, + void *priv, __wsum sum); + +/* + * Forward all aggregated SKBs held by lro_mgr to network stack + */ + +void lro_flush_all(struct net_lro_mgr *lro_mgr); + +void lro_flush_pkt(struct net_lro_mgr *lro_mgr, + struct iphdr *iph, struct tcphdr *tcph); + +#endif diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index fb7909774254..d894f616c3d6 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -394,6 +394,14 @@ config INET_XFRM_MODE_BEET If unsure, say Y. +config INET_LRO + tristate "Large Receive Offload (ipv4/tcp)" + + ---help--- + Support for Large Receive Offload (ipv4/tcp). + + If unsure, say Y. + config INET_DIAG tristate "INET: socket monitoring interface" default y diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index fbf1674e0c2a..a02c36d0a13e 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_INET_ESP) += esp4.o obj-$(CONFIG_INET_IPCOMP) += ipcomp.o obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o +obj-$(CONFIG_INET_LRO) += inet_lro.o obj-$(CONFIG_INET_TUNNEL) += tunnel4.o obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c new file mode 100644 index 000000000000..20bc593bb963 --- /dev/null +++ b/net/ipv4/inet_lro.c @@ -0,0 +1,600 @@ +/* + * linux/net/ipv4/inet_lro.c + * + * Large Receive Offload (ipv4 / tcp) + * + * (C) Copyright IBM Corp. 2007 + * + * Authors: + * Jan-Bernd Themann + * Christoph Raisch + * + * + * 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; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jan-Bernd Themann "); +MODULE_DESCRIPTION("Large Receive Offload (ipv4 / tcp)"); + +#define TCP_HDR_LEN(tcph) (tcph->doff << 2) +#define IP_HDR_LEN(iph) (iph->ihl << 2) +#define TCP_PAYLOAD_LENGTH(iph, tcph) \ + (ntohs(iph->tot_len) - IP_HDR_LEN(iph) - TCP_HDR_LEN(tcph)) + +#define IPH_LEN_WO_OPTIONS 5 +#define TCPH_LEN_WO_OPTIONS 5 +#define TCPH_LEN_W_TIMESTAMP 8 + +#define LRO_MAX_PG_HLEN 64 + +#define LRO_INC_STATS(lro_mgr, attr) { lro_mgr->stats.attr++; } + +/* + * Basic tcp checks whether packet is suitable for LRO + */ + +static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph, + int len, struct net_lro_desc *lro_desc) +{ + /* check ip header: don't aggregate padded frames */ + if (ntohs(iph->tot_len) != len) + return -1; + + if (TCP_PAYLOAD_LENGTH(iph, tcph) == 0) + return -1; + + if (iph->ihl != IPH_LEN_WO_OPTIONS) + return -1; + + if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack + || tcph->rst || tcph->syn || tcph->fin) + return -1; + + if (INET_ECN_is_ce(ipv4_get_dsfield(iph))) + return -1; + + if (tcph->doff != TCPH_LEN_WO_OPTIONS + && tcph->doff != TCPH_LEN_W_TIMESTAMP) + return -1; + + /* check tcp options (only timestamp allowed) */ + if (tcph->doff == TCPH_LEN_W_TIMESTAMP) { + u32 *topt = (u32 *)(tcph + 1); + + if (*topt != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) + | (TCPOPT_TIMESTAMP << 8) + | TCPOLEN_TIMESTAMP)) + return -1; + + /* timestamp should be in right order */ + topt++; + if (lro_desc && after(ntohl(lro_desc->tcp_rcv_tsval), + ntohl(*topt))) + return -1; + + /* timestamp reply should not be zero */ + topt++; + if (*topt == 0) + return -1; + } + + return 0; +} + +static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc) +{ + struct iphdr *iph = lro_desc->iph; + struct tcphdr *tcph = lro_desc->tcph; + u32 *p; + __wsum tcp_hdr_csum; + + tcph->ack_seq = lro_desc->tcp_ack; + tcph->window = lro_desc->tcp_window; + + if (lro_desc->tcp_saw_tstamp) { + p = (u32 *)(tcph + 1); + *(p+2) = lro_desc->tcp_rcv_tsecr; + } + + iph->tot_len = htons(lro_desc->ip_tot_len); + + iph->check = 0; + iph->check = ip_fast_csum((u8 *)lro_desc->iph, iph->ihl); + + tcph->check = 0; + tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), 0); + lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum); + tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, + lro_desc->ip_tot_len - + IP_HDR_LEN(iph), IPPROTO_TCP, + lro_desc->data_csum); +} + +static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len) +{ + __wsum tcp_csum; + __wsum tcp_hdr_csum; + __wsum tcp_ps_hdr_csum; + + tcp_csum = ~csum_unfold(tcph->check); + tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), tcp_csum); + + tcp_ps_hdr_csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, + len + TCP_HDR_LEN(tcph), + IPPROTO_TCP, 0); + + return csum_sub(csum_sub(tcp_csum, tcp_hdr_csum), + tcp_ps_hdr_csum); +} + +static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb, + struct iphdr *iph, struct tcphdr *tcph, + u16 vlan_tag, struct vlan_group *vgrp) +{ + int nr_frags; + u32 *ptr; + u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); + + nr_frags = skb_shinfo(skb)->nr_frags; + lro_desc->parent = skb; + lro_desc->next_frag = &(skb_shinfo(skb)->frags[nr_frags]); + lro_desc->iph = iph; + lro_desc->tcph = tcph; + lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len; + lro_desc->tcp_ack = ntohl(tcph->ack_seq); + lro_desc->tcp_window = tcph->window; + + lro_desc->pkt_aggr_cnt = 1; + lro_desc->ip_tot_len = ntohs(iph->tot_len); + + if (tcph->doff == 8) { + ptr = (u32 *)(tcph+1); + lro_desc->tcp_saw_tstamp = 1; + lro_desc->tcp_rcv_tsval = *(ptr+1); + lro_desc->tcp_rcv_tsecr = *(ptr+2); + } + + lro_desc->mss = tcp_data_len; + lro_desc->vgrp = vgrp; + lro_desc->vlan_tag = vlan_tag; + lro_desc->active = 1; + + lro_desc->data_csum = lro_tcp_data_csum(iph, tcph, + tcp_data_len); +} + +static inline void lro_clear_desc(struct net_lro_desc *lro_desc) +{ + memset(lro_desc, 0, sizeof(struct net_lro_desc)); +} + +static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph, + struct tcphdr *tcph, int tcp_data_len) +{ + struct sk_buff *parent = lro_desc->parent; + u32 *topt; + + lro_desc->pkt_aggr_cnt++; + lro_desc->ip_tot_len += tcp_data_len; + lro_desc->tcp_next_seq += tcp_data_len; + lro_desc->tcp_window = tcph->window; + lro_desc->tcp_ack = tcph->ack_seq; + + /* don't update tcp_rcv_tsval, would not work with PAWS */ + if (lro_desc->tcp_saw_tstamp) { + topt = (u32 *) (tcph + 1); + lro_desc->tcp_rcv_tsecr = *(topt + 2); + } + + lro_desc->data_csum = csum_block_add(lro_desc->data_csum, + lro_tcp_data_csum(iph, tcph, + tcp_data_len), + parent->len); + + parent->len += tcp_data_len; + parent->data_len += tcp_data_len; + if (tcp_data_len > lro_desc->mss) + lro_desc->mss = tcp_data_len; +} + +static void lro_add_packet(struct net_lro_desc *lro_desc, struct sk_buff *skb, + struct iphdr *iph, struct tcphdr *tcph) +{ + struct sk_buff *parent = lro_desc->parent; + int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); + + lro_add_common(lro_desc, iph, tcph, tcp_data_len); + + skb_pull(skb, (skb->len - tcp_data_len)); + parent->truesize += skb->truesize; + + if (lro_desc->last_skb) + lro_desc->last_skb->next = skb; + else + skb_shinfo(parent)->frag_list = skb; + + lro_desc->last_skb = skb; +} + +static void lro_add_frags(struct net_lro_desc *lro_desc, + int len, int hlen, int truesize, + struct skb_frag_struct *skb_frags, + struct iphdr *iph, struct tcphdr *tcph) +{ + struct sk_buff *skb = lro_desc->parent; + int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); + + lro_add_common(lro_desc, iph, tcph, tcp_data_len); + + skb->truesize += truesize; + + skb_frags[0].page_offset += hlen; + skb_frags[0].size -= hlen; + + while (tcp_data_len > 0) { + *(lro_desc->next_frag) = *skb_frags; + tcp_data_len -= skb_frags->size; + lro_desc->next_frag++; + skb_frags++; + skb_shinfo(skb)->nr_frags++; + } +} + +static int lro_check_tcp_conn(struct net_lro_desc *lro_desc, + struct iphdr *iph, + struct tcphdr *tcph) +{ + if ((lro_desc->iph->saddr != iph->saddr) + || (lro_desc->iph->daddr != iph->daddr) + || (lro_desc->tcph->source != tcph->source) + || (lro_desc->tcph->dest != tcph->dest)) + return -1; + return 0; +} + +static struct net_lro_desc *lro_get_desc(struct net_lro_mgr *lro_mgr, + struct net_lro_desc *lro_arr, + struct iphdr *iph, + struct tcphdr *tcph) +{ + struct net_lro_desc *lro_desc = NULL; + struct net_lro_desc *tmp; + int max_desc = lro_mgr->max_desc; + int i; + + for (i = 0; i < max_desc; i++) { + tmp = &lro_arr[i]; + if (tmp->active) + if (!lro_check_tcp_conn(tmp, iph, tcph)) { + lro_desc = tmp; + goto out; + } + } + + for (i = 0; i < max_desc; i++) { + if (!lro_arr[i].active) { + lro_desc = &lro_arr[i]; + goto out; + } + } + + LRO_INC_STATS(lro_mgr, no_desc); +out: + return lro_desc; +} + +static void lro_flush(struct net_lro_mgr *lro_mgr, + struct net_lro_desc *lro_desc) +{ + if (lro_desc->pkt_aggr_cnt > 1) + lro_update_tcp_ip_header(lro_desc); + + skb_shinfo(lro_desc->parent)->gso_size = lro_desc->mss; + + if (lro_desc->vgrp) { + if (test_bit(LRO_F_NAPI, &lro_mgr->features)) + vlan_hwaccel_receive_skb(lro_desc->parent, + lro_desc->vgrp, + lro_desc->vlan_tag); + else + vlan_hwaccel_rx(lro_desc->parent, + lro_desc->vgrp, + lro_desc->vlan_tag); + + } else { + if (test_bit(LRO_F_NAPI, &lro_mgr->features)) + netif_receive_skb(lro_desc->parent); + else + netif_rx(lro_desc->parent); + } + + LRO_INC_STATS(lro_mgr, flushed); + lro_clear_desc(lro_desc); +} + +static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, + struct vlan_group *vgrp, u16 vlan_tag, void *priv) +{ + struct net_lro_desc *lro_desc; + struct iphdr *iph; + struct tcphdr *tcph; + u64 flags; + int vlan_hdr_len = 0; + + if (!lro_mgr->get_skb_header + || lro_mgr->get_skb_header(skb, (void *)&iph, (void *)&tcph, + &flags, priv)) + goto out; + + if (!(flags & LRO_IPV4) || !(flags & LRO_TCP)) + goto out; + + lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + if (!lro_desc) + goto out; + + if ((skb->protocol == htons(ETH_P_8021Q)) + && !test_bit(LRO_F_EXTRACT_VLAN_ID, &lro_mgr->features)) + vlan_hdr_len = VLAN_HLEN; + + if (!lro_desc->active) { /* start new lro session */ + if (lro_tcp_ip_check(iph, tcph, skb->len - vlan_hdr_len, NULL)) + goto out; + + skb->ip_summed = lro_mgr->ip_summed_aggr; + lro_init_desc(lro_desc, skb, iph, tcph, vlan_tag, vgrp); + LRO_INC_STATS(lro_mgr, aggregated); + return 0; + } + + if (lro_desc->tcp_next_seq != ntohl(tcph->seq)) + goto out2; + + if (lro_tcp_ip_check(iph, tcph, skb->len, lro_desc)) + goto out2; + + lro_add_packet(lro_desc, skb, iph, tcph); + LRO_INC_STATS(lro_mgr, aggregated); + + if ((lro_desc->pkt_aggr_cnt >= lro_mgr->max_aggr) || + lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu)) + lro_flush(lro_mgr, lro_desc); + + return 0; + +out2: /* send aggregated SKBs to stack */ + lro_flush(lro_mgr, lro_desc); + +out: /* Original SKB has to be posted to stack */ + skb->ip_summed = lro_mgr->ip_summed; + return 1; +} + + +static struct sk_buff *lro_gen_skb(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, + void *mac_hdr, + int hlen, __wsum sum, + u32 ip_summed) +{ + struct sk_buff *skb; + struct skb_frag_struct *skb_frags; + int data_len = len; + int hdr_len = min(len, hlen); + + skb = netdev_alloc_skb(lro_mgr->dev, hlen); + if (!skb) + return NULL; + + skb->len = len; + skb->data_len = len - hdr_len; + skb->truesize += true_size; + skb->tail += hdr_len; + + memcpy(skb->data, mac_hdr, hdr_len); + + skb_frags = skb_shinfo(skb)->frags; + while (data_len > 0) { + *skb_frags = *frags; + data_len -= frags->size; + skb_frags++; + frags++; + skb_shinfo(skb)->nr_frags++; + } + + skb_shinfo(skb)->frags[0].page_offset += hdr_len; + skb_shinfo(skb)->frags[0].size -= hdr_len; + + skb->ip_summed = ip_summed; + skb->csum = sum; + skb->protocol = eth_type_trans(skb, lro_mgr->dev); + return skb; +} + +static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, + struct vlan_group *vgrp, + u16 vlan_tag, void *priv, __wsum sum) +{ + struct net_lro_desc *lro_desc; + struct iphdr *iph; + struct tcphdr *tcph; + struct sk_buff *skb; + u64 flags; + void *mac_hdr; + int mac_hdr_len; + int hdr_len = LRO_MAX_PG_HLEN; + int vlan_hdr_len = 0; + + if (!lro_mgr->get_frag_header + || lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph, + (void *)&tcph, &flags, priv)) { + mac_hdr = page_address(frags->page) + frags->page_offset; + goto out1; + } + + if (!(flags & LRO_IPV4) || !(flags & LRO_TCP)) + goto out1; + + hdr_len = (int)((void *)(tcph) + TCP_HDR_LEN(tcph) - mac_hdr); + mac_hdr_len = (int)((void *)(iph) - mac_hdr); + + lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + if (!lro_desc) + goto out1; + + if (!lro_desc->active) { /* start new lro session */ + if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, NULL)) + goto out1; + + skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, + hdr_len, 0, lro_mgr->ip_summed_aggr); + if (!skb) + goto out; + + if ((skb->protocol == htons(ETH_P_8021Q)) + && !test_bit(LRO_F_EXTRACT_VLAN_ID, &lro_mgr->features)) + vlan_hdr_len = VLAN_HLEN; + + iph = (void *)(skb->data + vlan_hdr_len); + tcph = (void *)((u8 *)skb->data + vlan_hdr_len + + IP_HDR_LEN(iph)); + + lro_init_desc(lro_desc, skb, iph, tcph, 0, NULL); + LRO_INC_STATS(lro_mgr, aggregated); + return 0; + } + + if (lro_desc->tcp_next_seq != ntohl(tcph->seq)) + goto out2; + + if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, lro_desc)) + goto out2; + + lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph); + LRO_INC_STATS(lro_mgr, aggregated); + + if ((skb_shinfo(lro_desc->parent)->nr_frags >= lro_mgr->max_aggr) || + lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu)) + lro_flush(lro_mgr, lro_desc); + + return NULL; + +out2: /* send aggregated packets to the stack */ + lro_flush(lro_mgr, lro_desc); + +out1: /* Original packet has to be posted to the stack */ + skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, + hdr_len, sum, lro_mgr->ip_summed); +out: + return skb; +} + +void lro_receive_skb(struct net_lro_mgr *lro_mgr, + struct sk_buff *skb, + void *priv) +{ + if (__lro_proc_skb(lro_mgr, skb, NULL, 0, priv)) { + if (test_bit(LRO_F_NAPI, &lro_mgr->features)) + netif_receive_skb(skb); + else + netif_rx(skb); + } +} +EXPORT_SYMBOL(lro_receive_skb); + +void lro_vlan_hwaccel_receive_skb(struct net_lro_mgr *lro_mgr, + struct sk_buff *skb, + struct vlan_group *vgrp, + u16 vlan_tag, + void *priv) +{ + if (__lro_proc_skb(lro_mgr, skb, vgrp, vlan_tag, priv)) { + if (test_bit(LRO_F_NAPI, &lro_mgr->features)) + vlan_hwaccel_receive_skb(skb, vgrp, vlan_tag); + else + vlan_hwaccel_rx(skb, vgrp, vlan_tag); + } +} +EXPORT_SYMBOL(lro_vlan_hwaccel_receive_skb); + +void lro_receive_frags(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, void *priv, __wsum sum) +{ + struct sk_buff *skb; + + skb = __lro_proc_segment(lro_mgr, frags, len, true_size, NULL, 0, + priv, sum); + if (!skb) + return; + + if (test_bit(LRO_F_NAPI, &lro_mgr->features)) + netif_receive_skb(skb); + else + netif_rx(skb); +} +EXPORT_SYMBOL(lro_receive_frags); + +void lro_vlan_hwaccel_receive_frags(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, + struct vlan_group *vgrp, + u16 vlan_tag, void *priv, __wsum sum) +{ + struct sk_buff *skb; + + skb = __lro_proc_segment(lro_mgr, frags, len, true_size, vgrp, + vlan_tag, priv, sum); + if (!skb) + return; + + if (test_bit(LRO_F_NAPI, &lro_mgr->features)) + vlan_hwaccel_receive_skb(skb, vgrp, vlan_tag); + else + vlan_hwaccel_rx(skb, vgrp, vlan_tag); +} +EXPORT_SYMBOL(lro_vlan_hwaccel_receive_frags); + +void lro_flush_all(struct net_lro_mgr *lro_mgr) +{ + int i; + struct net_lro_desc *lro_desc = lro_mgr->lro_arr; + + for (i = 0; i < lro_mgr->max_desc; i++) { + if (lro_desc[i].active) + lro_flush(lro_mgr, &lro_desc[i]); + } +} +EXPORT_SYMBOL(lro_flush_all); + +void lro_flush_pkt(struct net_lro_mgr *lro_mgr, + struct iphdr *iph, struct tcphdr *tcph) +{ + struct net_lro_desc *lro_desc; + + lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + if (lro_desc->active) + lro_flush(lro_mgr, lro_desc); +} +EXPORT_SYMBOL(lro_flush_pkt); From d4dc4ec9d84e0578b9bfbe56a11fafdb7cbac771 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Tue, 25 Sep 2007 16:16:34 -0700 Subject: [PATCH 1037/2804] [EHEA]: Use LRO. Signed-off-by: Jan-Bernd Themann Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 + drivers/net/ehea/ehea.h | 7 +++ drivers/net/ehea/ehea_ethtool.c | 15 ++++++ drivers/net/ehea/ehea_main.c | 84 ++++++++++++++++++++++++++++++--- 4 files changed, 100 insertions(+), 7 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e0a979184c0a..61dedfeed62a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2507,6 +2507,7 @@ config CHELSIO_T3 config EHEA tristate "eHEA Ethernet support" depends on IBMEBUS + select INET_LRO ---help--- This driver supports the IBM pSeries eHEA ethernet adapter. diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index a154681165b9..c0cbd949e336 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,7 @@ #define EHEA_SMALL_QUEUES #define EHEA_NUM_TX_QP 1 +#define EHEA_LRO_MAX_AGGR 64 #ifdef EHEA_SMALL_QUEUES #define EHEA_MAX_CQE_COUNT 1023 @@ -84,6 +86,8 @@ #define EHEA_RQ2_PKT_SIZE 1522 #define EHEA_L_PKT_SIZE 256 /* low latency */ +#define MAX_LRO_DESCRIPTORS 8 + /* Send completion signaling */ /* Protection Domain Identifier */ @@ -376,6 +380,8 @@ struct ehea_port_res { u64 tx_packets; u64 rx_packets; u32 poll_counter; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS]; }; @@ -429,6 +435,7 @@ struct ehea_port { u32 msg_enable; u32 sig_comp_iv; u32 state; + u32 lro_max_aggr; u8 phy_link; u8 full_duplex; u8 autoneg; diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index decec8cfe96b..29ef7a98f8be 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -183,6 +183,9 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"PR5 free_swqes"}, {"PR6 free_swqes"}, {"PR7 free_swqes"}, + {"LRO aggregated"}, + {"LRO flushed"}, + {"LRO no_desc"}, }; static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -239,6 +242,18 @@ static void ehea_get_ethtool_stats(struct net_device *dev, for (k = 0; k < 8; k++) data[i++] = atomic_read(&port->port_res[k].swqe_avail); + for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) + tmp |= port->port_res[k].lro_mgr.stats.aggregated; + data[i++] = tmp; + + for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) + tmp |= port->port_res[k].lro_mgr.stats.flushed; + data[i++] = tmp; + + for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) + tmp |= port->port_res[k].lro_mgr.stats.no_desc; + data[i++] = tmp; + } const struct ethtool_ops ehea_ethtool_ops = { diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 5ebd545ab04e..b8e00391a5e3 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -52,6 +52,8 @@ static int rq2_entries = EHEA_DEF_ENTRIES_RQ2; static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; static int sq_entries = EHEA_DEF_ENTRIES_SQ; static int use_mcs = 0; +static int use_lro = 0; +static int lro_max_aggr = EHEA_LRO_MAX_AGGR; static int num_tx_qps = EHEA_NUM_TX_QP; static int prop_carrier_state = 0; @@ -62,6 +64,8 @@ module_param(rq3_entries, int, 0); module_param(sq_entries, int, 0); module_param(prop_carrier_state, int, 0); module_param(use_mcs, int, 0); +module_param(use_lro, int, 0); +module_param(lro_max_aggr, int, 0); module_param(num_tx_qps, int, 0); MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS"); @@ -82,6 +86,11 @@ MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 "); +MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = " + __MODULE_STRING(EHEA_LRO_MAX_AGGR)); +MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, " + "Default = 0"); + static int port_name_cnt = 0; static LIST_HEAD(adapter_list); u64 ehea_driver_flags = 0; @@ -393,6 +402,60 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, return 0; } +static int get_skb_hdr(struct sk_buff *skb, void **iphdr, + void **tcph, u64 *hdr_flags, void *priv) +{ + struct ehea_cqe *cqe = priv; + unsigned int ip_len; + struct iphdr *iph; + + /* non tcp/udp packets */ + if (!cqe->header_length) + return -1; + + /* non tcp packet */ + skb_reset_network_header(skb); + iph = ip_hdr(skb); + if (iph->protocol != IPPROTO_TCP) + return -1; + + ip_len = ip_hdrlen(skb); + skb_set_transport_header(skb, ip_len); + *tcph = tcp_hdr(skb); + + /* check if ip header and tcp header are complete */ + if (iph->tot_len < ip_len + tcp_hdrlen(skb)) + return -1; + + *hdr_flags = LRO_IPV4 | LRO_TCP; + *iphdr = iph; + + return 0; +} + +static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe, + struct sk_buff *skb) +{ + int vlan_extracted = (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) + && pr->port->vgrp; + + if (use_lro) { + if (vlan_extracted) + lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb, + pr->port->vgrp, + cqe->vlan_tag, + cqe); + else + lro_receive_skb(&pr->lro_mgr, skb, cqe); + } else { + if (vlan_extracted) + vlan_hwaccel_receive_skb(skb, pr->port->vgrp, + cqe->vlan_tag); + else + netif_receive_skb(skb); + } +} + static int ehea_proc_rwqes(struct net_device *dev, struct ehea_port_res *pr, int budget) @@ -462,13 +525,7 @@ static int ehea_proc_rwqes(struct net_device *dev, processed_rq3++; } - if ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) - && port->vgrp) - vlan_hwaccel_receive_skb(skb, port->vgrp, - cqe->vlan_tag); - else - netif_receive_skb(skb); - + ehea_proc_skb(pr, cqe, skb); dev->last_rx = jiffies; } else { pr->p_stats.poll_receive_errors++; @@ -480,6 +537,8 @@ static int ehea_proc_rwqes(struct net_device *dev, } cqe = ehea_poll_rq1(qp, &wqe_index); } + if (use_lro) + lro_flush_all(&pr->lro_mgr); pr->rx_packets += processed; @@ -1231,6 +1290,15 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64); + pr->lro_mgr.max_aggr = pr->port->lro_max_aggr; + pr->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; + pr->lro_mgr.lro_arr = pr->lro_desc; + pr->lro_mgr.get_skb_header = get_skb_hdr; + pr->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + pr->lro_mgr.dev = port->netdev; + pr->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + pr->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + ret = 0; goto out; @@ -2682,6 +2750,8 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, goto out_dereg_bc; } + port->lro_max_aggr = lro_max_aggr; + ret = ehea_get_jumboframe_status(port, &jumbo); if (ret) ehea_error("failed determining jumbo frame status for %s", From 1e6e9342d41ff80ced0ad5dfcf084926700cdfc5 Mon Sep 17 00:00:00 2001 From: Andrew Gallatin Date: Mon, 17 Sep 2007 11:37:42 -0700 Subject: [PATCH 1038/2804] [MYRI10GE]: Use LRO. Singed off by: Andrew Gallatin Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 + drivers/net/myri10ge/myri10ge.c | 109 +++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 61dedfeed62a..40ff9a5269a2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2583,6 +2583,7 @@ config MYRI10GE depends on PCI select FW_LOADER select CRC32 + select INET_LRO ---help--- This driver supports Myricom Myri-10G Dual Protocol interface in Ethernet mode. If the eeprom on your board is not recent enough, diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index a30146ea51f0..48b23c592406 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,8 @@ #include #include #include +#include +#include #include #include #include @@ -89,6 +92,8 @@ MODULE_LICENSE("Dual BSD/GPL"); #define MYRI10GE_EEPROM_STRINGS_SIZE 256 #define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2) +#define MYRI10GE_MAX_LRO_DESCRIPTORS 8 +#define MYRI10GE_LRO_MAX_PKTS 64 #define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff) #define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff @@ -151,6 +156,8 @@ struct myri10ge_rx_done { dma_addr_t bus; int cnt; int idx; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS]; }; struct myri10ge_priv { @@ -278,6 +285,14 @@ static int myri10ge_debug = -1; /* defaults above */ module_param(myri10ge_debug, int, 0); MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)"); +static int myri10ge_lro = 1; +module_param(myri10ge_lro, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload\n"); + +static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS; +module_param(myri10ge_lro_max_pkts, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_lro, "Number of LRO packets to be aggregated\n"); + static int myri10ge_fill_thresh = 256; module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n"); @@ -1021,6 +1036,15 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, remainder -= MYRI10GE_ALLOC_SIZE; } + if (mgp->csum_flag && myri10ge_lro) { + rx_frags[0].page_offset += MXGEFW_PAD; + rx_frags[0].size -= MXGEFW_PAD; + len -= MXGEFW_PAD; + lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags, + len, len, (void *)(unsigned long)csum, csum); + return 1; + } + hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN; /* allocate an skb to attach the page(s) to. */ @@ -1136,6 +1160,9 @@ static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget) mgp->stats.rx_packets += rx_packets; mgp->stats.rx_bytes += rx_bytes; + if (myri10ge_lro) + lro_flush_all(&rx_done->lro_mgr); + /* restock receive rings if needed */ if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh) myri10ge_alloc_rx_pages(mgp, &mgp->rx_small, @@ -1373,7 +1400,8 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", "dropped_unicast_filtered", "dropped_multicast_filtered", "dropped_runt", "dropped_overrun", "dropped_no_small_buffer", - "dropped_no_big_buffer" + "dropped_no_big_buffer", "LRO aggregated", "LRO flushed", + "LRO avg aggr", "LRO no_desc" }; #define MYRI10GE_NET_STATS_LEN 21 @@ -1439,6 +1467,14 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer); + data[i++] = mgp->rx_done.lro_mgr.stats.aggregated; + data[i++] = mgp->rx_done.lro_mgr.stats.flushed; + if (mgp->rx_done.lro_mgr.stats.flushed) + data[i++] = mgp->rx_done.lro_mgr.stats.aggregated / + mgp->rx_done.lro_mgr.stats.flushed; + else + data[i++] = 0; + data[i++] = mgp->rx_done.lro_mgr.stats.no_desc; } static void myri10ge_set_msglevel(struct net_device *netdev, u32 value) @@ -1712,10 +1748,69 @@ static void myri10ge_free_irq(struct myri10ge_priv *mgp) pci_disable_msi(pdev); } +static int +myri10ge_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; + __wsum csum = (__wsum) (unsigned long)priv; + + /* find the mac header, aborting if not IPv4 */ + + 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; + + /* + * HW checksum starts ETH_HLEN bytes into + * frame, so we must subtract off the VLAN + * header's checksum before csum can be used + */ + csum = csum_sub(csum, csum_partial(va + ETH_HLEN, + VLAN_HLEN, 0)); + } 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); + + /* verify the IP checksum */ + if (unlikely(ip_fast_csum((u8 *) iph, iph->ihl))) + return -1; + + /* verify the checksum */ + if (unlikely(csum_tcpudp_magic(iph->saddr, iph->daddr, + ntohs(iph->tot_len) - (iph->ihl << 2), + IPPROTO_TCP, csum))) + return -1; + + return 0; +} + static int myri10ge_open(struct net_device *dev) { struct myri10ge_priv *mgp; struct myri10ge_cmd cmd; + struct net_lro_mgr *lro_mgr; int status, big_pow2; mgp = netdev_priv(dev); @@ -1847,6 +1942,18 @@ static int myri10ge_open(struct net_device *dev) mgp->link_state = htonl(~0U); mgp->rdma_tags_available = 15; + lro_mgr = &mgp->rx_done.lro_mgr; + lro_mgr->dev = dev; + lro_mgr->features = LRO_F_NAPI; + lro_mgr->ip_summed = CHECKSUM_COMPLETE; + lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS; + lro_mgr->lro_arr = mgp->rx_done.lro_desc; + lro_mgr->get_frag_header = myri10ge_get_frag_header; + lro_mgr->max_aggr = myri10ge_lro_max_pkts; + if (lro_mgr->max_aggr > MAX_SKB_FRAGS) + lro_mgr->max_aggr = MAX_SKB_FRAGS; + napi_enable(&mgp->napi); /* must happen prior to any irq */ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); From 4f494554f9b95d0de57c14c460d525e3715e3f6f Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 8 Aug 2007 23:12:36 -0700 Subject: [PATCH 1039/2804] [NEIGH]: Combine neighbour cleanup and release Introduces neigh_cleanup_and_release() to be used after a neighbour has been removed from its neighbour table. Serves as preparation to add event notifications. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/core/neighbour.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index f7de8f24d8dd..4b815db94b6b 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -105,6 +105,14 @@ static int neigh_blackhole(struct sk_buff *skb) return -ENETDOWN; } +static void neigh_cleanup_and_release(struct neighbour *neigh) +{ + if (neigh->parms->neigh_cleanup) + neigh->parms->neigh_cleanup(neigh); + + neigh_release(neigh); +} + /* * It is random distribution in the interval (1/2)*base...(3/2)*base. * It corresponds to default IPv6 settings and is not overridable, @@ -141,9 +149,7 @@ static int neigh_forced_gc(struct neigh_table *tbl) n->dead = 1; shrunk = 1; write_unlock(&n->lock); - if (n->parms->neigh_cleanup) - n->parms->neigh_cleanup(n); - neigh_release(n); + neigh_cleanup_and_release(n); continue; } write_unlock(&n->lock); @@ -214,9 +220,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) NEIGH_PRINTK2("neigh %p is stray.\n", n); } write_unlock(&n->lock); - if (n->parms->neigh_cleanup) - n->parms->neigh_cleanup(n); - neigh_release(n); + neigh_cleanup_and_release(n); } } } @@ -677,9 +681,7 @@ static void neigh_periodic_timer(unsigned long arg) *np = n->next; n->dead = 1; write_unlock(&n->lock); - if (n->parms->neigh_cleanup) - n->parms->neigh_cleanup(n); - neigh_release(n); + neigh_cleanup_and_release(n); continue; } write_unlock(&n->lock); @@ -2095,11 +2097,8 @@ void __neigh_for_each_release(struct neigh_table *tbl, } else np = &n->next; write_unlock(&n->lock); - if (release) { - if (n->parms->neigh_cleanup) - n->parms->neigh_cleanup(n); - neigh_release(n); - } + if (release) + neigh_cleanup_and_release(n); } } } From d961db358f41033a8fc7b62948bc7cff1b4bb1fe Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 8 Aug 2007 23:12:56 -0700 Subject: [PATCH 1040/2804] [NEIGH]: Netlink notifications Currently neighbour event notifications are limited to update notifications and only sent if the ARP daemon is enabled. This patch extends the existing notification code by also reporting neighbours being removed due to gc or administratively and removes the dependency on the ARP daemon. This allows to keep track of neighbour states without periodically fetching the complete neighbour table. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/core/neighbour.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 4b815db94b6b..ecd43c4a2221 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -55,9 +55,8 @@ #define PNEIGH_HASHMASK 0xF static void neigh_timer_handler(unsigned long arg); -#ifdef CONFIG_ARPD -static void neigh_app_notify(struct neighbour *n); -#endif +static void __neigh_notify(struct neighbour *n, int type, int flags); +static void neigh_update_notify(struct neighbour *neigh); static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); @@ -110,6 +109,7 @@ static void neigh_cleanup_and_release(struct neighbour *neigh) if (neigh->parms->neigh_cleanup) neigh->parms->neigh_cleanup(neigh); + __neigh_notify(neigh, RTM_DELNEIGH, 0); neigh_release(neigh); } @@ -830,13 +830,10 @@ static void neigh_timer_handler(unsigned long arg) out: write_unlock(&neigh->lock); } - if (notify) - call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); -#ifdef CONFIG_ARPD - if (notify && neigh->parms->app_probes) - neigh_app_notify(neigh); -#endif + if (notify) + neigh_update_notify(neigh); + neigh_release(neigh); } @@ -1065,11 +1062,8 @@ out: write_unlock_bh(&neigh->lock); if (notify) - call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); -#ifdef CONFIG_ARPD - if (notify && neigh->parms->app_probes) - neigh_app_notify(neigh); -#endif + neigh_update_notify(neigh); + return err; } @@ -2002,6 +1996,11 @@ nla_put_failure: return -EMSGSIZE; } +static void neigh_update_notify(struct neighbour *neigh) +{ + call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); + __neigh_notify(neigh, RTM_NEWNEIGH, 0); +} static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, struct netlink_callback *cb) @@ -2421,7 +2420,6 @@ static const struct file_operations neigh_stat_seq_fops = { #endif /* CONFIG_PROC_FS */ -#ifdef CONFIG_ARPD static inline size_t neigh_nlmsg_size(void) { return NLMSG_ALIGN(sizeof(struct ndmsg)) @@ -2453,16 +2451,11 @@ errout: rtnl_set_sk_err(RTNLGRP_NEIGH, err); } +#ifdef CONFIG_ARPD void neigh_app_ns(struct neighbour *n) { __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST); } - -static void neigh_app_notify(struct neighbour *n) -{ - __neigh_notify(n, RTM_NEWNEIGH, 0); -} - #endif /* CONFIG_ARPD */ #ifdef CONFIG_SYSCTL From d738cd8fca948e45d53120247cb7a5f5be3ca09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sat, 24 Mar 2007 21:03:23 -0700 Subject: [PATCH 1041/2804] [TCP]: Add highest_sack seqno, points to globally highest SACK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is guaranteed to be valid only when !tp->sacked_out. In most cases this seqno is available in the last ACK but there is no guarantee for that. The new fast recovery loss marking algorithm needs this as entry point. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 ++ net/ipv4/tcp_input.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index c6b9f92e8289..c072f88afb97 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -333,6 +333,8 @@ struct tcp_sock { struct tcp_sack_block_wire recv_sack_cache[4]; + u32 highest_sack; /* Start seq of globally highest revd SACK (valid only in slowpath) */ + /* from STCP, retrans queue hinting */ struct sk_buff* lost_skb_hint; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f893e90061eb..813f2049b85d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -979,8 +979,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ int i; int first_sack_index; - if (!tp->sacked_out) + if (!tp->sacked_out) { tp->fackets_out = 0; + tp->highest_sack = tp->snd_una; + } prior_fackets = tp->fackets_out; /* Check for D-SACK. */ @@ -1217,6 +1219,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (fack_count > tp->fackets_out) tp->fackets_out = fack_count; + + if (after(TCP_SKB_CB(skb)->seq, + tp->highest_sack)) + tp->highest_sack = TCP_SKB_CB(skb)->seq; } else { if (dup_sack && (sacked&TCPCB_RETRANS)) reord = min(fack_count, reord); From d8f4f2235abc7b30cf447ca3e22ac28326b12f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 20 Apr 2007 22:56:38 -0700 Subject: [PATCH 1042/2804] [TCP]: Extracted rexmit hint clearing from the LOST marking code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 813f2049b85d..7d843c429381 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1765,6 +1765,20 @@ static inline void tcp_reset_reno_sack(struct tcp_sock *tp) tp->left_out = tp->lost_out; } +/* RFC: This is from the original, I doubt that this is necessary at all: + * clear xmit_retrans hint if seq of this skb is beyond hint. How could we + * retransmitted past LOST markings in the first place? I'm not fully sure + * about undo and end of connection cases, which can cause R without L? + */ +static void tcp_verify_retransmit_hint(struct tcp_sock *tp, + struct sk_buff *skb) +{ + if ((tp->retransmit_skb_hint != NULL) && + before(TCP_SKB_CB(skb)->seq, + TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) + tp->retransmit_skb_hint = skb; +} + /* Mark head of queue up as lost. */ static void tcp_mark_head_lost(struct sock *sk, int packets, u32 high_seq) @@ -1795,14 +1809,7 @@ static void tcp_mark_head_lost(struct sock *sk, if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; tp->lost_out += tcp_skb_pcount(skb); - - /* clear xmit_retransmit_queue hints - * if this is beyond hint */ - if (tp->retransmit_skb_hint != NULL && - before(TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) - tp->retransmit_skb_hint = NULL; - + tcp_verify_retransmit_hint(tp, skb); } } tcp_sync_left_out(tp); @@ -1843,13 +1850,7 @@ static void tcp_update_scoreboard(struct sock *sk) if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; tp->lost_out += tcp_skb_pcount(skb); - - /* clear xmit_retrans hint */ - if (tp->retransmit_skb_hint && - before(TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) - - tp->retransmit_skb_hint = NULL; + tcp_verify_retransmit_hint(tp, skb); } } From 19b2b486580f5939688d3e225acdc0f4b291ed0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Wed, 28 Mar 2007 12:06:37 -0700 Subject: [PATCH 1043/2804] [TCP]: Rexmit hint must be cleared instead of setting it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stupid error from my side. Even though now that I noticed this, I hoped it would have been an optimization but no, the counter hint is then incorrect. Thus clearing is necessary for now (I still suspect though that this path is never executed). Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7d843c429381..0aa17243d369 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1776,7 +1776,7 @@ static void tcp_verify_retransmit_hint(struct tcp_sock *tp, if ((tp->retransmit_skb_hint != NULL) && before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) - tp->retransmit_skb_hint = skb; + tp->retransmit_skb_hint = NULL; } /* Mark head of queue up as lost. */ From d06e021d71d95aae402340dc3d9f79f9c8ad11d7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 18 Jun 2007 22:43:06 -0700 Subject: [PATCH 1044/2804] [TCP]: Extract DSACK detection code from tcp_sacktag_write_queue(). Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0aa17243d369..5187870d0333 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -960,6 +960,39 @@ static void tcp_update_reordering(struct sock *sk, const int metric, * Both of these heuristics are not used in Loss state, when we cannot * account for retransmits accurately. */ +static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, + struct tcp_sack_block_wire *sp, int num_sacks, + u32 prior_snd_una) +{ + u32 start_seq_0 = ntohl(get_unaligned(&sp[0].start_seq)); + u32 end_seq_0 = ntohl(get_unaligned(&sp[0].end_seq)); + int dup_sack = 0; + + if (before(start_seq_0, TCP_SKB_CB(ack_skb)->ack_seq)) { + dup_sack = 1; + tp->rx_opt.sack_ok |= 4; + NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV); + } else if (num_sacks > 1) { + u32 end_seq_1 = ntohl(get_unaligned(&sp[1].end_seq)); + u32 start_seq_1 = ntohl(get_unaligned(&sp[1].start_seq)); + + if (!after(end_seq_0, end_seq_1) && + !before(start_seq_0, start_seq_1)) { + dup_sack = 1; + tp->rx_opt.sack_ok |= 4; + NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV); + } + } + + /* D-SACK for already forgotten data... Do dumb counting. */ + if (dup_sack && + !after(end_seq_0, prior_snd_una) && + after(end_seq_0, tp->undo_marker)) + tp->undo_retrans--; + + return dup_sack; +} + static int tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una) { @@ -985,27 +1018,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ } prior_fackets = tp->fackets_out; - /* Check for D-SACK. */ - if (before(ntohl(sp[0].start_seq), TCP_SKB_CB(ack_skb)->ack_seq)) { + found_dup_sack = tcp_check_dsack(tp, ack_skb, sp, + num_sacks, prior_snd_una); + if (found_dup_sack) flag |= FLAG_DSACKING_ACK; - found_dup_sack = 1; - tp->rx_opt.sack_ok |= 4; - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV); - } else if (num_sacks > 1 && - !after(ntohl(sp[0].end_seq), ntohl(sp[1].end_seq)) && - !before(ntohl(sp[0].start_seq), ntohl(sp[1].start_seq))) { - flag |= FLAG_DSACKING_ACK; - found_dup_sack = 1; - tp->rx_opt.sack_ok |= 4; - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV); - } - - /* D-SACK for already forgotten data... - * Do dumb counting. */ - if (found_dup_sack && - !after(ntohl(sp[0].end_seq), prior_snd_una) && - after(ntohl(sp[0].end_seq), tp->undo_marker)) - tp->undo_retrans--; /* Eliminate too old ACKs, but take into * account more or less fresh ones, they can From 4ddf66769d2df868071420e2e0106746c6204ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sun, 27 May 2007 01:52:00 -0700 Subject: [PATCH 1045/2804] [TCP]: Move Reno SACKed_out counter functions earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 98 +++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 5187870d0333..2711ef7df7b5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1314,6 +1314,53 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ /* F-RTO can only be used if TCP has never retransmitted anything other than * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here) */ +static void tcp_check_reno_reordering(struct sock *sk, const int addend) +{ + struct tcp_sock *tp = tcp_sk(sk); + u32 holes; + + holes = max(tp->lost_out, 1U); + holes = min(holes, tp->packets_out); + + if ((tp->sacked_out + holes) > tp->packets_out) { + tp->sacked_out = tp->packets_out - holes; + tcp_update_reordering(sk, tp->packets_out + addend, 0); + } +} + +/* Emulate SACKs for SACKless connection: account for a new dupack. */ + +static void tcp_add_reno_sack(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + tp->sacked_out++; + tcp_check_reno_reordering(sk, 0); + tcp_sync_left_out(tp); +} + +/* Account for ACK, ACKing some data in Reno Recovery phase. */ + +static void tcp_remove_reno_sacks(struct sock *sk, int acked) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (acked > 0) { + /* One ACK acked hole. The rest eat duplicate ACKs. */ + if (acked-1 >= tp->sacked_out) + tp->sacked_out = 0; + else + tp->sacked_out -= acked-1; + } + tcp_check_reno_reordering(sk, acked); + tcp_sync_left_out(tp); +} + +static inline void tcp_reset_reno_sack(struct tcp_sock *tp) +{ + tp->sacked_out = 0; + tp->left_out = tp->lost_out; +} + int tcp_use_frto(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); @@ -1730,57 +1777,6 @@ static int tcp_time_to_recover(struct sock *sk) return 0; } -/* If we receive more dupacks than we expected counting segments - * in assumption of absent reordering, interpret this as reordering. - * The only another reason could be bug in receiver TCP. - */ -static void tcp_check_reno_reordering(struct sock *sk, const int addend) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 holes; - - holes = max(tp->lost_out, 1U); - holes = min(holes, tp->packets_out); - - if ((tp->sacked_out + holes) > tp->packets_out) { - tp->sacked_out = tp->packets_out - holes; - tcp_update_reordering(sk, tp->packets_out + addend, 0); - } -} - -/* Emulate SACKs for SACKless connection: account for a new dupack. */ - -static void tcp_add_reno_sack(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - tp->sacked_out++; - tcp_check_reno_reordering(sk, 0); - tcp_sync_left_out(tp); -} - -/* Account for ACK, ACKing some data in Reno Recovery phase. */ - -static void tcp_remove_reno_sacks(struct sock *sk, int acked) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (acked > 0) { - /* One ACK acked hole. The rest eat duplicate ACKs. */ - if (acked-1 >= tp->sacked_out) - tp->sacked_out = 0; - else - tp->sacked_out -= acked-1; - } - tcp_check_reno_reordering(sk, acked); - tcp_sync_left_out(tp); -} - -static inline void tcp_reset_reno_sack(struct tcp_sock *tp) -{ - tp->sacked_out = 0; - tp->left_out = tp->lost_out; -} - /* RFC: This is from the original, I doubt that this is necessary at all: * clear xmit_retrans hint if seq of this skb is beyond hint. How could we * retransmitted past LOST markings in the first place? I'm not fully sure From 9bff40fda015c4d0b57b444626cdcbf66066dbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sun, 27 May 2007 01:53:49 -0700 Subject: [PATCH 1046/2804] [TCP] FRTO: remove unnecessary fackets/sacked_out recounting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit F-RTO does not touch SACKED_ACKED bits at all, so there is no need to recount them in tcp_enter_frto_loss. After removal of the else branch, nested ifs can be combined. This must also reset sacked_out when SACK is not in use as TCP could have received some duplicate ACKs prior RTO. To achieve that in a sane manner, tcp_reset_reno_sack was re-placed by the previous patch. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2711ef7df7b5..29999ef73b43 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1474,17 +1474,15 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; - int cnt = 0; - tp->sacked_out = 0; tp->lost_out = 0; - tp->fackets_out = 0; tp->retrans_out = 0; + if (IsReno(tp)) + tcp_reset_reno_sack(tp); tcp_for_write_queue(skb, sk) { if (skb == tcp_send_head(sk)) break; - cnt += tcp_skb_pcount(skb); /* * Count the retransmission made on RTO correctly (only when * waiting for the first ACK and did not get it)... @@ -1498,19 +1496,12 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) } else { TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); } - if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) { - /* Do not mark those segments lost that were - * forward transmitted after RTO - */ - if (!after(TCP_SKB_CB(skb)->end_seq, - tp->frto_highmark)) { - TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; - tp->lost_out += tcp_skb_pcount(skb); - } - } else { - tp->sacked_out += tcp_skb_pcount(skb); - tp->fackets_out = cnt; + /* Don't lost mark skbs that were fwd transmitted after RTO */ + if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) && + !after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark)) { + TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; + tp->lost_out += tcp_skb_pcount(skb); } } tcp_sync_left_out(tp); From 539d243fdd7900fa5a544c7c154dc3ddf627e840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sun, 27 May 2007 02:03:20 -0700 Subject: [PATCH 1047/2804] [TCP]: Access to highest_sack obsoletes forward_cnt_hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In addition, added a reference about the purpose of the loop. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/linux/tcp.h | 1 - net/ipv4/tcp_output.c | 23 +++++++++-------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index c072f88afb97..d64734389fb6 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -346,7 +346,6 @@ struct tcp_sock { int fastpath_cnt_hint; int lost_cnt_hint; int retransmit_cnt_hint; - int forward_cnt_hint; u16 advmss; /* Advertised MSS */ u16 prior_ssthresh; /* ssthresh saved at recovery start */ diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 666d8a58d14a..b11025e8a49e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1945,33 +1945,28 @@ void tcp_xmit_retransmit_queue(struct sock *sk) * and retransmission... Both ways have their merits... * * For now we do not retransmit anything, while we have some new - * segments to send. + * segments to send. In the other cases, follow rule 3 for + * NextSeg() specified in RFC3517. */ if (tcp_may_send_now(sk)) return; - if (tp->forward_skb_hint) { + /* If nothing is SACKed, highest_sack in the loop won't be valid */ + if (!tp->sacked_out) + return; + + if (tp->forward_skb_hint) skb = tp->forward_skb_hint; - packet_cnt = tp->forward_cnt_hint; - } else{ + else skb = tcp_write_queue_head(sk); - packet_cnt = 0; - } tcp_for_write_queue_from(skb, sk) { if (skb == tcp_send_head(sk)) break; - tp->forward_cnt_hint = packet_cnt; tp->forward_skb_hint = skb; - /* Similar to the retransmit loop above we - * can pretend that the retransmitted SKB - * we send out here will be composed of one - * real MSS sized packet because tcp_retransmit_skb() - * will fragment it if necessary. - */ - if (++packet_cnt > tp->fackets_out) + if (after(TCP_SKB_CB(skb)->seq, tp->highest_sack)) break; if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) From bdf1ee5d3bd38d0c44bd7baa74e07adcbe4ceab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sun, 27 May 2007 02:04:16 -0700 Subject: [PATCH 1048/2804] [TCP]: Move code from tcp_ecn.h to tcp*.c and tcp.h & remove it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No other users exist for tcp_ecn.h. Very few things remain in tcp.h, for most TCP ECN functions callers reside within a single .c file and can be placed there. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 14 ++++- include/net/tcp_ecn.h | 130 --------------------------------------- net/ipv4/tcp_input.c | 50 +++++++++++++++ net/ipv4/tcp_minisocks.c | 6 ++ net/ipv4/tcp_output.c | 50 +++++++++++++++ 5 files changed, 118 insertions(+), 132 deletions(-) delete mode 100644 include/net/tcp_ecn.h diff --git a/include/net/tcp.h b/include/net/tcp.h index 54053de0bdd7..dde04afbe0a4 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -330,6 +331,17 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt) rx_opt->tstamp_ok = rx_opt->sack_ok = rx_opt->wscale_ok = rx_opt->snd_wscale = 0; } +#define TCP_ECN_OK 1 +#define TCP_ECN_QUEUE_CWR 2 +#define TCP_ECN_DEMAND_CWR 4 + +static __inline__ void +TCP_ECN_create_request(struct request_sock *req, struct tcphdr *th) +{ + if (sysctl_tcp_ecn && th->ece && th->cwr) + inet_rsk(req)->ecn_ok = 1; +} + enum tcp_tw_status { TCP_TW_SUCCESS = 0, @@ -573,8 +585,6 @@ struct tcp_skb_cb { #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) -#include - /* Due to TSO, an SKB can be composed of multiple actual * packets. To keep these tracked properly, we use this. */ diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h deleted file mode 100644 index 89eb3e05116d..000000000000 --- a/include/net/tcp_ecn.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef _NET_TCP_ECN_H_ -#define _NET_TCP_ECN_H_ 1 - -#include -#include - -#define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) - -#define TCP_ECN_OK 1 -#define TCP_ECN_QUEUE_CWR 2 -#define TCP_ECN_DEMAND_CWR 4 - -static inline void TCP_ECN_queue_cwr(struct tcp_sock *tp) -{ - if (tp->ecn_flags&TCP_ECN_OK) - tp->ecn_flags |= TCP_ECN_QUEUE_CWR; -} - - -/* Output functions */ - -static inline void TCP_ECN_send_synack(struct tcp_sock *tp, - struct sk_buff *skb) -{ - TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR; - if (!(tp->ecn_flags&TCP_ECN_OK)) - TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE; -} - -static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - - tp->ecn_flags = 0; - if (sysctl_tcp_ecn) { - TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR; - tp->ecn_flags = TCP_ECN_OK; - } -} - -static __inline__ void -TCP_ECN_make_synack(struct request_sock *req, struct tcphdr *th) -{ - if (inet_rsk(req)->ecn_ok) - th->ece = 1; -} - -static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb, - int tcp_header_len) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tp->ecn_flags & TCP_ECN_OK) { - /* Not-retransmitted data segment: set ECT and inject CWR. */ - if (skb->len != tcp_header_len && - !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) { - INET_ECN_xmit(sk); - if (tp->ecn_flags&TCP_ECN_QUEUE_CWR) { - tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR; - tcp_hdr(skb)->cwr = 1; - skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; - } - } else { - /* ACK or retransmitted segment: clear ECT|CE */ - INET_ECN_dontxmit(sk); - } - if (tp->ecn_flags & TCP_ECN_DEMAND_CWR) - tcp_hdr(skb)->ece = 1; - } -} - -/* Input functions */ - -static inline void TCP_ECN_accept_cwr(struct tcp_sock *tp, struct sk_buff *skb) -{ - if (tcp_hdr(skb)->cwr) - tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; -} - -static inline void TCP_ECN_withdraw_cwr(struct tcp_sock *tp) -{ - tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; -} - -static inline void TCP_ECN_check_ce(struct tcp_sock *tp, struct sk_buff *skb) -{ - if (tp->ecn_flags&TCP_ECN_OK) { - if (INET_ECN_is_ce(TCP_SKB_CB(skb)->flags)) - tp->ecn_flags |= TCP_ECN_DEMAND_CWR; - /* Funny extension: if ECT is not set on a segment, - * it is surely retransmit. It is not in ECN RFC, - * but Linux follows this rule. */ - else if (INET_ECN_is_not_ect((TCP_SKB_CB(skb)->flags))) - tcp_enter_quickack_mode((struct sock *)tp); - } -} - -static inline void TCP_ECN_rcv_synack(struct tcp_sock *tp, struct tcphdr *th) -{ - if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || th->cwr)) - tp->ecn_flags &= ~TCP_ECN_OK; -} - -static inline void TCP_ECN_rcv_syn(struct tcp_sock *tp, struct tcphdr *th) -{ - if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || !th->cwr)) - tp->ecn_flags &= ~TCP_ECN_OK; -} - -static inline int TCP_ECN_rcv_ecn_echo(struct tcp_sock *tp, struct tcphdr *th) -{ - if (th->ece && !th->syn && (tp->ecn_flags&TCP_ECN_OK)) - return 1; - return 0; -} - -static inline void TCP_ECN_openreq_child(struct tcp_sock *tp, - struct request_sock *req) -{ - tp->ecn_flags = inet_rsk(req)->ecn_ok ? TCP_ECN_OK : 0; -} - -static __inline__ void -TCP_ECN_create_request(struct request_sock *req, struct tcphdr *th) -{ - if (sysctl_tcp_ecn && th->ece && th->cwr) - inet_rsk(req)->ecn_ok = 1; -} - -#endif diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 29999ef73b43..ea690afa592a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -118,6 +118,7 @@ int sysctl_tcp_abc __read_mostly; #define IsSackFrto() (sysctl_tcp_frto == 0x2) #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) +#define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) /* Adapt the MSS value used to make delayed ack decision to the * real world. @@ -198,6 +199,55 @@ static inline int tcp_in_quickack_mode(const struct sock *sk) return icsk->icsk_ack.quick && !icsk->icsk_ack.pingpong; } +static inline void TCP_ECN_queue_cwr(struct tcp_sock *tp) +{ + if (tp->ecn_flags&TCP_ECN_OK) + tp->ecn_flags |= TCP_ECN_QUEUE_CWR; +} + +static inline void TCP_ECN_accept_cwr(struct tcp_sock *tp, struct sk_buff *skb) +{ + if (tcp_hdr(skb)->cwr) + tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; +} + +static inline void TCP_ECN_withdraw_cwr(struct tcp_sock *tp) +{ + tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; +} + +static inline void TCP_ECN_check_ce(struct tcp_sock *tp, struct sk_buff *skb) +{ + if (tp->ecn_flags&TCP_ECN_OK) { + if (INET_ECN_is_ce(TCP_SKB_CB(skb)->flags)) + tp->ecn_flags |= TCP_ECN_DEMAND_CWR; + /* Funny extension: if ECT is not set on a segment, + * it is surely retransmit. It is not in ECN RFC, + * but Linux follows this rule. */ + else if (INET_ECN_is_not_ect((TCP_SKB_CB(skb)->flags))) + tcp_enter_quickack_mode((struct sock *)tp); + } +} + +static inline void TCP_ECN_rcv_synack(struct tcp_sock *tp, struct tcphdr *th) +{ + if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || th->cwr)) + tp->ecn_flags &= ~TCP_ECN_OK; +} + +static inline void TCP_ECN_rcv_syn(struct tcp_sock *tp, struct tcphdr *th) +{ + if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || !th->cwr)) + tp->ecn_flags &= ~TCP_ECN_OK; +} + +static inline int TCP_ECN_rcv_ecn_echo(struct tcp_sock *tp, struct tcphdr *th) +{ + if (th->ece && !th->syn && (tp->ecn_flags&TCP_ECN_OK)) + return 1; + return 0; +} + /* Buffer size and advertised window tuning. * * 1. Tuning sk->sk_sndbuf, when connection enters established state. diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index a12b08fca5ad..36a8fbd0e64e 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -368,6 +368,12 @@ void tcp_twsk_destructor(struct sock *sk) EXPORT_SYMBOL_GPL(tcp_twsk_destructor); +static inline void TCP_ECN_openreq_child(struct tcp_sock *tp, + struct request_sock *req) +{ + tp->ecn_flags = inet_rsk(req)->ecn_ok ? TCP_ECN_OK : 0; +} + /* This is not only more efficient than what we used to do, it eliminates * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM * diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b11025e8a49e..3abe22e4b576 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -269,6 +269,56 @@ static u16 tcp_select_window(struct sock *sk) return new_win; } +static inline void TCP_ECN_send_synack(struct tcp_sock *tp, + struct sk_buff *skb) +{ + TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR; + if (!(tp->ecn_flags&TCP_ECN_OK)) + TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE; +} + +static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_sock *tp = tcp_sk(sk); + + tp->ecn_flags = 0; + if (sysctl_tcp_ecn) { + TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR; + tp->ecn_flags = TCP_ECN_OK; + } +} + +static __inline__ void +TCP_ECN_make_synack(struct request_sock *req, struct tcphdr *th) +{ + if (inet_rsk(req)->ecn_ok) + th->ece = 1; +} + +static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb, + int tcp_header_len) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (tp->ecn_flags & TCP_ECN_OK) { + /* Not-retransmitted data segment: set ECT and inject CWR. */ + if (skb->len != tcp_header_len && + !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) { + INET_ECN_xmit(sk); + if (tp->ecn_flags&TCP_ECN_QUEUE_CWR) { + tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR; + tcp_hdr(skb)->cwr = 1; + skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; + } + } else { + /* ACK or retransmitted segment: clear ECT|CE */ + INET_ECN_dontxmit(sk); + } + if (tp->ecn_flags & TCP_ECN_DEMAND_CWR) + tcp_hdr(skb)->ece = 1; + } +} + static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, __u32 tstamp, __u8 **md5_hash) { From af610b4ca19f513a50d47ea93ed57241383c8081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 15 Jun 2007 12:58:38 +0300 Subject: [PATCH 1049/2804] [TCP]: Add tcp_dec_pcount_approx int variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 11 ++++++++--- net/ipv4/tcp_output.c | 12 +++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index dde04afbe0a4..9d3438f6b52f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -599,16 +599,21 @@ static inline int tcp_skb_mss(const struct sk_buff *skb) return skb_shinfo(skb)->gso_size; } -static inline void tcp_dec_pcount_approx(__u32 *count, - const struct sk_buff *skb) +static inline void tcp_dec_pcount_approx_int(__u32 *count, const int decr) { if (*count) { - *count -= tcp_skb_pcount(skb); + *count -= decr; if ((int)*count < 0) *count = 0; } } +static inline void tcp_dec_pcount_approx(__u32 *count, + const struct sk_buff *skb) +{ + tcp_dec_pcount_approx_int(count, tcp_skb_pcount(skb)); +} + static inline void tcp_packets_out_inc(struct sock *sk, const struct sk_buff *skb) { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 3abe22e4b576..3c8c8e7f6f6d 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -740,22 +740,16 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss if (diff > 0) { /* Adjust Reno SACK estimate. */ if (!tp->rx_opt.sack_ok) { - tp->sacked_out -= diff; - if ((int)tp->sacked_out < 0) - tp->sacked_out = 0; + tcp_dec_pcount_approx_int(&tp->sacked_out, diff); tcp_sync_left_out(tp); } - tp->fackets_out -= diff; - if ((int)tp->fackets_out < 0) - tp->fackets_out = 0; + tcp_dec_pcount_approx_int(&tp->fackets_out, diff); /* SACK fastpath might overwrite it unless dealt with */ if (tp->fastpath_skb_hint != NULL && after(TCP_SKB_CB(tp->fastpath_skb_hint)->seq, TCP_SKB_CB(skb)->seq)) { - tp->fastpath_cnt_hint -= diff; - if ((int)tp->fastpath_cnt_hint < 0) - tp->fastpath_cnt_hint = 0; + tcp_dec_pcount_approx_int(&tp->fastpath_cnt_hint, diff); } } } From 35e8694198ba94b62df8aa35fa6e52a1cfb86df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 31 May 2007 10:16:47 +0300 Subject: [PATCH 1050/2804] [TCP]: Remove num_acked>0 checks from cong.ctrl mods pkts_acked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for such check in pkts_acked because the callback is not invoked unless at least one segment got fully ACKed (i.e., the snd_una moved past skb's end_seq) by the cumulative ACK's snd_una advancement. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_bic.c | 2 +- net/ipv4/tcp_cubic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c index 4586211e3757..5dba0fc8f579 100644 --- a/net/ipv4/tcp_bic.c +++ b/net/ipv4/tcp_bic.c @@ -210,7 +210,7 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt) { const struct inet_connection_sock *icsk = inet_csk(sk); - if (cnt > 0 && icsk->icsk_ca_state == TCP_CA_Open) { + if (icsk->icsk_ca_state == TCP_CA_Open) { struct bictcp *ca = inet_csk_ca(sk); cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT; ca->delayed_ack += cnt; diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 485d7ea35f75..80bd084a9f91 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -314,7 +314,7 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us) struct bictcp *ca = inet_csk_ca(sk); u32 delay; - if (cnt > 0 && icsk->icsk_ca_state == TCP_CA_Open) { + if (icsk->icsk_ca_state == TCP_CA_Open) { cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT; ca->delayed_ack += cnt; } From b5860bbac7be1381626f3dc8a0cb970a60fcefb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 9 Aug 2007 14:33:18 +0300 Subject: [PATCH 1051/2804] [TCP]: Tighten tcp_sock's belt, drop left_out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is easily calculable when needed and user are not that many after all. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/linux/tcp.h | 1 - include/net/tcp.h | 4 ++-- net/ipv4/tcp_input.c | 11 ++--------- net/ipv4/tcp_minisocks.c | 1 - net/ipv4/tcp_output.c | 12 +++--------- 5 files changed, 7 insertions(+), 22 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index d64734389fb6..1f12fa0b67d7 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -304,7 +304,6 @@ struct tcp_sock { u32 rtt_seq; /* sequence number to update rttvar */ u32 packets_out; /* Packets which are "in flight" */ - u32 left_out; /* Packets which leaved network */ u32 retrans_out; /* Retransmitted packets out */ /* * Options received (usually on last packet, some only on SYN packets). diff --git a/include/net/tcp.h b/include/net/tcp.h index 9d3438f6b52f..299872d461c7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -735,7 +735,8 @@ static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) */ static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp) { - return (tp->packets_out - tp->left_out + tp->retrans_out); + return tp->packets_out - (tp->sacked_out + tp->lost_out) + + tp->retrans_out; } /* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. @@ -757,7 +758,6 @@ static inline void tcp_sync_left_out(struct tcp_sock *tp) { BUG_ON(tp->rx_opt.sack_ok && (tp->sacked_out + tp->lost_out > tp->packets_out)); - tp->left_out = tp->sacked_out + tp->lost_out; } extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ea690afa592a..957e0fb8afb7 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1346,8 +1346,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ } } - tp->left_out = tp->sacked_out + tp->lost_out; - if ((reord < tp->fackets_out) && icsk->icsk_ca_state != TCP_CA_Loss && (!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark))) tcp_update_reordering(sk, ((tp->fackets_out + 1) - reord), 0); @@ -1408,7 +1406,6 @@ static void tcp_remove_reno_sacks(struct sock *sk, int acked) static inline void tcp_reset_reno_sack(struct tcp_sock *tp) { tp->sacked_out = 0; - tp->left_out = tp->lost_out; } int tcp_use_frto(struct sock *sk) @@ -1573,7 +1570,6 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) void tcp_clear_retrans(struct tcp_sock *tp) { - tp->left_out = 0; tp->retrans_out = 0; tp->fackets_out = 0; @@ -1973,7 +1969,7 @@ static void DBGUNDO(struct sock *sk, const char *msg) printk(KERN_DEBUG "Undo %s %u.%u.%u.%u/%u c%u l%u ss%u/%u p%u\n", msg, NIPQUAD(inet->daddr), ntohs(inet->dport), - tp->snd_cwnd, tp->left_out, + tp->snd_cwnd, tp->sacked_out + tp->lost_out, tp->snd_ssthresh, tp->prior_ssthresh, tp->packets_out); } @@ -2102,7 +2098,6 @@ static int tcp_try_undo_loss(struct sock *sk) DBGUNDO(sk, "partial loss"); tp->lost_out = 0; - tp->left_out = tp->sacked_out; tcp_undo_cwr(sk, 1); NET_INC_STATS_BH(LINUX_MIB_TCPLOSSUNDO); inet_csk(sk)->icsk_retransmits = 0; @@ -2126,8 +2121,6 @@ static void tcp_try_to_open(struct sock *sk, int flag) { struct tcp_sock *tp = tcp_sk(sk); - tcp_sync_left_out(tp); - if (tp->retrans_out == 0) tp->retrans_stamp = 0; @@ -2137,7 +2130,7 @@ static void tcp_try_to_open(struct sock *sk, int flag) if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { int state = TCP_CA_Open; - if (tp->left_out || tp->retrans_out || tp->undo_marker) + if (tp->sacked_out || tp->retrans_out || tp->undo_marker) state = TCP_CA_Disorder; if (inet_csk(sk)->icsk_ca_state != state) { diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 36a8fbd0e64e..fdfe89fe646b 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -405,7 +405,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newicsk->icsk_rto = TCP_TIMEOUT_INIT; newtp->packets_out = 0; - newtp->left_out = 0; newtp->retrans_out = 0; newtp->sacked_out = 0; newtp->fackets_out = 0; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 3c8c8e7f6f6d..7434944caa8f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -732,10 +732,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) tp->retrans_out -= diff; - if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { + if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) tp->lost_out -= diff; - tp->left_out -= diff; - } if (diff > 0) { /* Adjust Reno SACK estimate. */ @@ -1727,15 +1725,11 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m TCP_SKB_CB(skb)->sacked |= TCP_SKB_CB(next_skb)->sacked&(TCPCB_EVER_RETRANS|TCPCB_AT_TAIL); if (TCP_SKB_CB(next_skb)->sacked&TCPCB_SACKED_RETRANS) tp->retrans_out -= tcp_skb_pcount(next_skb); - if (TCP_SKB_CB(next_skb)->sacked&TCPCB_LOST) { + if (TCP_SKB_CB(next_skb)->sacked&TCPCB_LOST) tp->lost_out -= tcp_skb_pcount(next_skb); - tp->left_out -= tcp_skb_pcount(next_skb); - } /* Reno case is special. Sigh... */ - if (!tp->rx_opt.sack_ok && tp->sacked_out) { + if (!tp->rx_opt.sack_ok && tp->sacked_out) tcp_dec_pcount_approx(&tp->sacked_out, next_skb); - tp->left_out -= tcp_skb_pcount(next_skb); - } /* Not quite right: it can be > snd.fack, but * it is better to underestimate fackets. From 83ae40885f33e406c87c86b0bd4b6fd31a741f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 9 Aug 2007 14:37:30 +0300 Subject: [PATCH 1052/2804] [TCP]: Add tcp_left_out(tp) "back" to get cleaner looking lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tp->left_out got removed but nothing came to replace it back then (users just did addition by themselves), so add function for users now. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 11 +++++++---- net/ipv4/tcp_input.c | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 299872d461c7..39d0df6afe47 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -719,6 +719,11 @@ static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) icsk->icsk_ca_ops->cwnd_event(sk, event); } +static inline unsigned int tcp_left_out(const struct tcp_sock *tp) +{ + return tp->sacked_out + tp->lost_out; +} + /* This determines how many packets are "in the network" to the best * of our knowledge. In many cases it is conservative, but where * detailed information is available from the receiver (via SACK @@ -735,8 +740,7 @@ static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) */ static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp) { - return tp->packets_out - (tp->sacked_out + tp->lost_out) + - tp->retrans_out; + return tp->packets_out - tcp_left_out(tp) + tp->retrans_out; } /* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. @@ -756,8 +760,7 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk) static inline void tcp_sync_left_out(struct tcp_sock *tp) { - BUG_ON(tp->rx_opt.sack_ok && - (tp->sacked_out + tp->lost_out > tp->packets_out)); + BUG_ON(tp->rx_opt.sack_ok && (tcp_left_out(tp) > tp->packets_out)); } extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 957e0fb8afb7..6bdd053e252f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1969,7 +1969,7 @@ static void DBGUNDO(struct sock *sk, const char *msg) printk(KERN_DEBUG "Undo %s %u.%u.%u.%u/%u c%u l%u ss%u/%u p%u\n", msg, NIPQUAD(inet->daddr), ntohs(inet->dport), - tp->snd_cwnd, tp->sacked_out + tp->lost_out, + tp->snd_cwnd, tcp_left_out(tp), tp->snd_ssthresh, tp->prior_ssthresh, tp->packets_out); } From 005903bc3a0e8473fef809e8775db52dcd3cde63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 9 Aug 2007 14:44:16 +0300 Subject: [PATCH 1053/2804] [TCP]: Left out sync->verify (the new meaning of it) & definify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Left_out was dropped a while ago, thus leaving verifying consistency of the "left out" as only task for the function in question. Thus make it's name more appropriate. In addition, it is intentionally converted to #define instead of static inline because the location of the invariant failure is the most important thing to have if this ever triggers. I think it would have been helpful e.g. in this case where the location of the failure point had to be based on some quesswork: http://lkml.org/lkml/2007/5/2/464 ...Luckily the guesswork seems to have proved to be correct. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 7 +++---- net/ipv4/tcp_input.c | 20 ++++++++++---------- net/ipv4/tcp_output.c | 4 ++-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 39d0df6afe47..7042c32085f5 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -758,10 +758,9 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk) (tp->snd_cwnd >> 2))); } -static inline void tcp_sync_left_out(struct tcp_sock *tp) -{ - BUG_ON(tp->rx_opt.sack_ok && (tcp_left_out(tp) > tp->packets_out)); -} +/* Use define here intentionally to get BUG_ON location shown at the caller */ +#define tcp_verify_left_out(tp) \ + BUG_ON(tp->rx_opt.sack_ok && (tcp_left_out(tp) > tp->packets_out)) extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh); extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6bdd053e252f..b11bd1624227 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1383,7 +1383,7 @@ static void tcp_add_reno_sack(struct sock *sk) struct tcp_sock *tp = tcp_sk(sk); tp->sacked_out++; tcp_check_reno_reordering(sk, 0); - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); } /* Account for ACK, ACKing some data in Reno Recovery phase. */ @@ -1400,7 +1400,7 @@ static void tcp_remove_reno_sacks(struct sock *sk, int acked) tp->sacked_out -= acked-1; } tcp_check_reno_reordering(sk, acked); - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); } static inline void tcp_reset_reno_sack(struct tcp_sock *tp) @@ -1496,7 +1496,7 @@ void tcp_enter_frto(struct sock *sk) TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; tp->retrans_out -= tcp_skb_pcount(skb); } - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); /* Earlier loss recovery underway (see RFC4138; Appendix B). * The last condition is necessary at least in tp->frto_counter case. @@ -1551,7 +1551,7 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) tp->lost_out += tcp_skb_pcount(skb); } } - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments; tp->snd_cwnd_cnt = 0; @@ -1626,7 +1626,7 @@ void tcp_enter_loss(struct sock *sk, int how) tp->fackets_out = cnt; } } - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); tp->reordering = min_t(unsigned int, tp->reordering, sysctl_tcp_reordering); @@ -1861,7 +1861,7 @@ static void tcp_mark_head_lost(struct sock *sk, tcp_verify_retransmit_hint(tp, skb); } } - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); } /* Account newly detected lost packet(s) */ @@ -1905,7 +1905,7 @@ static void tcp_update_scoreboard(struct sock *sk) tp->scoreboard_skb_hint = skb; - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); } } @@ -2217,8 +2217,8 @@ tcp_fastretrans_alert(struct sock *sk, int prior_packets, int flag) NET_INC_STATS_BH(LINUX_MIB_TCPLOSS); } - /* D. Synchronize left_out to current state. */ - tcp_sync_left_out(tp); + /* D. Check consistency of the current state. */ + tcp_verify_left_out(tp); /* E. Check state exit conditions. State can be terminated * when high_seq is ACKed. */ @@ -2765,7 +2765,7 @@ static int tcp_process_frto(struct sock *sk, int flag) { struct tcp_sock *tp = tcp_sk(sk); - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); /* Duplicate the behavior from Loss state (fastretrans_alert) */ if (flag&FLAG_DATA_ACKED) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7434944caa8f..a92fad55cd32 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -739,7 +739,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss /* Adjust Reno SACK estimate. */ if (!tp->rx_opt.sack_ok) { tcp_dec_pcount_approx_int(&tp->sacked_out, diff); - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); } tcp_dec_pcount_approx_int(&tp->fackets_out, diff); @@ -1774,7 +1774,7 @@ void tcp_simple_retransmit(struct sock *sk) if (!lost) return; - tcp_sync_left_out(tp); + tcp_verify_left_out(tp); /* Don't muck with the congestion window here. * Reason is that we do not increase amount of _data_ From 86426c22d24e0c904012711a14cb5021f4a167dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 9 Aug 2007 14:45:17 +0300 Subject: [PATCH 1054/2804] [TCP]: Restore over-zealous tcp_sync_left_out-like removals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tcp_verify_left_out is useful for verifying S+L condition, so add it back to couple of places in where the code was not calling to tcp_sync_left_out but used own ad-hoc solution (before the tcp_sync_left_out got removed). Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b11bd1624227..93823b83522b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1346,6 +1346,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ } } + tcp_verify_left_out(tp); + if ((reord < tp->fackets_out) && icsk->icsk_ca_state != TCP_CA_Loss && (!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark))) tcp_update_reordering(sk, ((tp->fackets_out + 1) - reord), 0); @@ -2121,6 +2123,8 @@ static void tcp_try_to_open(struct sock *sk, int flag) { struct tcp_sock *tp = tcp_sk(sk); + tcp_verify_left_out(tp); + if (tp->retrans_out == 0) tp->retrans_stamp = 0; From d02596e32925edaeccee0af8eb6c229b5615de42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sat, 7 Jul 2007 13:39:02 +0300 Subject: [PATCH 1055/2804] [TCP]: Keep state in Disorder also if only lost_out > 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This happens rather infrequently and is only possible during FRTO. We must not allow TCP to slip to Open state because tcp_fastretrans_alert might then not be called on it's time when FRTO has exited. This become a problem when left_out got removed and was replaced by just sacked_out. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 93823b83522b..bf4fc3516fb9 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2134,7 +2134,7 @@ static void tcp_try_to_open(struct sock *sk, int flag) if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { int state = TCP_CA_Open; - if (tp->sacked_out || tp->retrans_out || tp->undo_marker) + if (tcp_left_out(tp) || tp->retrans_out || tp->undo_marker) state = TCP_CA_Disorder; if (inet_csk(sk)->icsk_ca_state != state) { From 1b6d427bb7eb69e6dc4f194a5b0f4a382a16ff82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 9 Aug 2007 14:53:36 +0300 Subject: [PATCH 1056/2804] [TCP]: Reduce sacked_out with reno when purging write_queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously TCP had a transitional state during which reno counted segments that are already below the current window into sacked_out, which is now prevented. In addition, re-try now the unconditional S+L skb catching. This approach conservatively calls just remove_sack and leaves reset_sack() calls alone. The best solution to the whole problem would be to first calculate the new sacked_out fully (this patch does not move reno_sack_reset calls from original sites and thus does not implement this). However, that would require very invasive change to fastretrans_alert (perhaps even slicing it to two halves). Alternatively, all callers of tcp_packets_in_flight (i.e., users that depend on sacked_out) should be postponed until the new sacked_out has been calculated but it isn't any simpler alternative. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 3 +-- net/ipv4/tcp_input.c | 15 +++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 7042c32085f5..064c92fe00d2 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -759,8 +759,7 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk) } /* Use define here intentionally to get BUG_ON location shown at the caller */ -#define tcp_verify_left_out(tp) \ - BUG_ON(tp->rx_opt.sack_ok && (tcp_left_out(tp) > tp->packets_out)) +#define tcp_verify_left_out(tp) BUG_ON(tcp_left_out(tp) > tp->packets_out) extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh); extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bf4fc3516fb9..f8af018dd224 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2187,7 +2187,7 @@ static void tcp_mtup_probe_success(struct sock *sk, struct sk_buff *skb) * tcp_xmit_retransmit_queue(). */ static void -tcp_fastretrans_alert(struct sock *sk, int prior_packets, int flag) +tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) { struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); @@ -2273,12 +2273,8 @@ tcp_fastretrans_alert(struct sock *sk, int prior_packets, int flag) if (!(flag & FLAG_SND_UNA_ADVANCED)) { if (IsReno(tp) && is_dupack) tcp_add_reno_sack(sk); - } else { - int acked = prior_packets - tp->packets_out; - if (IsReno(tp)) - tcp_remove_reno_sacks(sk, acked); - do_lost = tcp_try_undo_partial(sk, acked); - } + } else + do_lost = tcp_try_undo_partial(sk, pkts_acked); break; case TCP_CA_Loss: if (flag&FLAG_DATA_ACKED) @@ -2577,6 +2573,9 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) tcp_ack_update_rtt(sk, acked, seq_rtt); tcp_ack_packets_out(sk); + if (IsReno(tp)) + tcp_remove_reno_sacks(sk, pkts_acked); + if (ca_ops->pkts_acked) { s32 rtt_us = -1; @@ -2927,7 +2926,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) if ((flag & FLAG_DATA_ACKED) && !frto_cwnd && tcp_may_raise_cwnd(sk, flag)) tcp_cong_avoid(sk, ack, prior_in_flight, 0); - tcp_fastretrans_alert(sk, prior_packets, flag); + tcp_fastretrans_alert(sk, prior_packets - tp->packets_out, flag); } else { if ((flag & FLAG_DATA_ACKED) && !frto_cwnd) tcp_cong_avoid(sk, ack, prior_in_flight, 1); From b9c4595bc4947faa236a849324fe3492e388d949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 27 Jul 2007 16:36:17 +0300 Subject: [PATCH 1057/2804] [TCP]: Don't panic if S+L skb is detected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG_ON is an overkill. In fact, I was mislead by BUG_TRAP severity (equals to WARN_ON) which is much lower than BUG_ON's (that panics). Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 064c92fe00d2..b92bdc7c92a9 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -758,8 +758,8 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk) (tp->snd_cwnd >> 2))); } -/* Use define here intentionally to get BUG_ON location shown at the caller */ -#define tcp_verify_left_out(tp) BUG_ON(tcp_left_out(tp) > tp->packets_out) +/* Use define here intentionally to get WARN_ON location shown at the caller */ +#define tcp_verify_left_out(tp) WARN_ON(tcp_left_out(tp) > tp->packets_out) extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh); extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst); From e60402d0a909ca2e6e2fbdf9ed004ef0fae36d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 9 Aug 2007 15:14:46 +0300 Subject: [PATCH 1058/2804] [TCP]: Move sack_ok access to obviously named funcs & cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously code had IsReno/IsFack defined as macros that were local to tcp_input.c though sack_ok field has user elsewhere too for the same purpose. This changes them to static inlines as preferred according the current coding style and unifies the access to sack_ok across multiple files. Magic bitops of sack_ok for FACK and DSACK are also abstracted to functions with appropriate names. Note: - One sack_ok = 1 remains but that's self explanary, i.e., it enables sack - Couple of !IsReno cases are changed to tcp_is_sack - There were no users for IsDSack => I dropped it Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 28 ++++++++++++++ net/ipv4/tcp.c | 2 +- net/ipv4/tcp_input.c | 82 ++++++++++++++++++++++------------------ net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_output.c | 6 +-- net/ipv4/tcp_timer.c | 2 +- 6 files changed, 80 insertions(+), 42 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index b92bdc7c92a9..0a4ed6e85c6f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -719,6 +719,34 @@ static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) icsk->icsk_ca_ops->cwnd_event(sk, event); } +/* These functions determine how the current flow behaves in respect of SACK + * handling. SACK is negotiated with the peer, and therefore it can vary + * between different flows. + * + * tcp_is_sack - SACK enabled + * tcp_is_reno - No SACK + * tcp_is_fack - FACK enabled, implies SACK enabled + */ +static inline int tcp_is_sack(const struct tcp_sock *tp) +{ + return tp->rx_opt.sack_ok; +} + +static inline int tcp_is_reno(const struct tcp_sock *tp) +{ + return !tcp_is_sack(tp); +} + +static inline int tcp_is_fack(const struct tcp_sock *tp) +{ + return tp->rx_opt.sack_ok & 2; +} + +static inline void tcp_enable_fack(struct tcp_sock *tp) +{ + tp->rx_opt.sack_ok |= 2; +} + static inline unsigned int tcp_left_out(const struct tcp_sock *tp) { return tp->sacked_out + tp->lost_out; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7e740112b238..aff31427f525 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2014,7 +2014,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) if (tp->rx_opt.tstamp_ok) info->tcpi_options |= TCPI_OPT_TIMESTAMPS; - if (tp->rx_opt.sack_ok) + if (tcp_is_sack(tp)) info->tcpi_options |= TCPI_OPT_SACK; if (tp->rx_opt.wscale_ok) { info->tcpi_options |= TCPI_OPT_WSCALE; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f8af018dd224..faba9beb3613 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -111,10 +111,6 @@ int sysctl_tcp_abc __read_mostly; #define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) #define FLAG_ANY_PROGRESS (FLAG_FORWARD_PROGRESS|FLAG_SND_UNA_ADVANCED) -#define IsReno(tp) ((tp)->rx_opt.sack_ok == 0) -#define IsFack(tp) ((tp)->rx_opt.sack_ok & 2) -#define IsDSack(tp) ((tp)->rx_opt.sack_ok & 4) - #define IsSackFrto() (sysctl_tcp_frto == 0x2) #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) @@ -860,6 +856,21 @@ void tcp_enter_cwr(struct sock *sk, const int set_ssthresh) } } +/* + * Packet counting of FACK is based on in-order assumptions, therefore TCP + * disables it when reordering is detected + */ +static void tcp_disable_fack(struct tcp_sock *tp) +{ + tp->rx_opt.sack_ok &= ~2; +} + +/* Take a notice that peer is sending DSACKs */ +static void tcp_dsack_seen(struct tcp_sock *tp) +{ + tp->rx_opt.sack_ok |= 4; +} + /* Initialize metrics on socket. */ static void tcp_init_metrics(struct sock *sk) @@ -881,7 +892,7 @@ static void tcp_init_metrics(struct sock *sk) } if (dst_metric(dst, RTAX_REORDERING) && tp->reordering != dst_metric(dst, RTAX_REORDERING)) { - tp->rx_opt.sack_ok &= ~2; + tcp_disable_fack(tp); tp->reordering = dst_metric(dst, RTAX_REORDERING); } @@ -943,9 +954,9 @@ static void tcp_update_reordering(struct sock *sk, const int metric, /* This exciting event is worth to be remembered. 8) */ if (ts) NET_INC_STATS_BH(LINUX_MIB_TCPTSREORDER); - else if (IsReno(tp)) + else if (tcp_is_reno(tp)) NET_INC_STATS_BH(LINUX_MIB_TCPRENOREORDER); - else if (IsFack(tp)) + else if (tcp_is_fack(tp)) NET_INC_STATS_BH(LINUX_MIB_TCPFACKREORDER); else NET_INC_STATS_BH(LINUX_MIB_TCPSACKREORDER); @@ -957,8 +968,7 @@ static void tcp_update_reordering(struct sock *sk, const int metric, tp->sacked_out, tp->undo_marker ? tp->undo_retrans : 0); #endif - /* Disable FACK yet. */ - tp->rx_opt.sack_ok &= ~2; + tcp_disable_fack(tp); } } @@ -1020,7 +1030,7 @@ static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, if (before(start_seq_0, TCP_SKB_CB(ack_skb)->ack_seq)) { dup_sack = 1; - tp->rx_opt.sack_ok |= 4; + tcp_dsack_seen(tp); NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV); } else if (num_sacks > 1) { u32 end_seq_1 = ntohl(get_unaligned(&sp[1].end_seq)); @@ -1029,7 +1039,7 @@ static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, if (!after(end_seq_0, end_seq_1) && !before(start_seq_0, start_seq_1)) { dup_sack = 1; - tp->rx_opt.sack_ok |= 4; + tcp_dsack_seen(tp); NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV); } } @@ -1326,7 +1336,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ continue; if ((TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) && after(lost_retrans, TCP_SKB_CB(skb)->ack_seq) && - (IsFack(tp) || + (tcp_is_fack(tp) || !before(lost_retrans, TCP_SKB_CB(skb)->ack_seq + tp->reordering * tp->mss_cache))) { @@ -1526,7 +1536,7 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) tp->lost_out = 0; tp->retrans_out = 0; - if (IsReno(tp)) + if (tcp_is_reno(tp)) tcp_reset_reno_sack(tp); tcp_for_write_queue(skb, sk) { @@ -1668,7 +1678,7 @@ static int tcp_check_sack_reneging(struct sock *sk) static inline int tcp_fackets_out(struct tcp_sock *tp) { - return IsReno(tp) ? tp->sacked_out+1 : tp->fackets_out; + return tcp_is_reno(tp) ? tp->sacked_out+1 : tp->fackets_out; } static inline int tcp_skb_timedout(struct sock *sk, struct sk_buff *skb) @@ -1872,7 +1882,7 @@ static void tcp_update_scoreboard(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); - if (IsFack(tp)) { + if (tcp_is_fack(tp)) { int lost = tp->fackets_out - tp->reordering; if (lost <= 0) lost = 1; @@ -1886,7 +1896,7 @@ static void tcp_update_scoreboard(struct sock *sk) * Hence, we can detect timed out packets during fast * retransmit without falling to slow start. */ - if (!IsReno(tp) && tcp_head_timedout(sk)) { + if (!tcp_is_reno(tp) && tcp_head_timedout(sk)) { struct sk_buff *skb; skb = tp->scoreboard_skb_hint ? tp->scoreboard_skb_hint @@ -1938,7 +1948,7 @@ static void tcp_cwnd_down(struct sock *sk, int flag) int decr = tp->snd_cwnd_cnt + 1; if ((flag&(FLAG_ANY_PROGRESS|FLAG_DSACKING_ACK)) || - (IsReno(tp) && !(flag&FLAG_NOT_DUP))) { + (tcp_is_reno(tp) && !(flag&FLAG_NOT_DUP))) { tp->snd_cwnd_cnt = decr&1; decr >>= 1; @@ -2029,7 +2039,7 @@ static int tcp_try_undo_recovery(struct sock *sk) NET_INC_STATS_BH(LINUX_MIB_TCPFULLUNDO); tp->undo_marker = 0; } - if (tp->snd_una == tp->high_seq && IsReno(tp)) { + if (tp->snd_una == tp->high_seq && tcp_is_reno(tp)) { /* Hold old state until something *above* high_seq * is ACKed. For Reno it is MUST to prevent false * fast retransmits (RFC2582). SACK TCP is safe. */ @@ -2059,7 +2069,7 @@ static int tcp_try_undo_partial(struct sock *sk, int acked) { struct tcp_sock *tp = tcp_sk(sk); /* Partial ACK arrived. Force Hoe's retransmit. */ - int failed = IsReno(tp) || tp->fackets_out>tp->reordering; + int failed = tcp_is_reno(tp) || tp->fackets_out>tp->reordering; if (tcp_may_undo(tp)) { /* Plain luck! Hole if filled with delayed @@ -2104,7 +2114,7 @@ static int tcp_try_undo_loss(struct sock *sk) NET_INC_STATS_BH(LINUX_MIB_TCPLOSSUNDO); inet_csk(sk)->icsk_retransmits = 0; tp->undo_marker = 0; - if (!IsReno(tp)) + if (tcp_is_sack(tp)) tcp_set_ca_state(sk, TCP_CA_Open); return 1; } @@ -2251,14 +2261,14 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) if (!tp->undo_marker || /* For SACK case do not Open to allow to undo * catching for all duplicate ACKs. */ - IsReno(tp) || tp->snd_una != tp->high_seq) { + tcp_is_reno(tp) || tp->snd_una != tp->high_seq) { tp->undo_marker = 0; tcp_set_ca_state(sk, TCP_CA_Open); } break; case TCP_CA_Recovery: - if (IsReno(tp)) + if (tcp_is_reno(tp)) tcp_reset_reno_sack(tp); if (tcp_try_undo_recovery(sk)) return; @@ -2271,7 +2281,7 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) switch (icsk->icsk_ca_state) { case TCP_CA_Recovery: if (!(flag & FLAG_SND_UNA_ADVANCED)) { - if (IsReno(tp) && is_dupack) + if (tcp_is_reno(tp) && is_dupack) tcp_add_reno_sack(sk); } else do_lost = tcp_try_undo_partial(sk, pkts_acked); @@ -2288,7 +2298,7 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) return; /* Loss is undone; fall through to processing in Open state. */ default: - if (IsReno(tp)) { + if (tcp_is_reno(tp)) { if (flag & FLAG_SND_UNA_ADVANCED) tcp_reset_reno_sack(tp); if (is_dupack) @@ -2316,7 +2326,7 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) /* Otherwise enter Recovery state */ - if (IsReno(tp)) + if (tcp_is_reno(tp)) NET_INC_STATS_BH(LINUX_MIB_TCPRENORECOVERY); else NET_INC_STATS_BH(LINUX_MIB_TCPSACKRECOVERY); @@ -2573,7 +2583,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) tcp_ack_update_rtt(sk, acked, seq_rtt); tcp_ack_packets_out(sk); - if (IsReno(tp)) + if (tcp_is_reno(tp)) tcp_remove_reno_sacks(sk, pkts_acked); if (ca_ops->pkts_acked) { @@ -2599,7 +2609,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) BUG_TRAP((int)tp->sacked_out >= 0); BUG_TRAP((int)tp->lost_out >= 0); BUG_TRAP((int)tp->retrans_out >= 0); - if (!tp->packets_out && tp->rx_opt.sack_ok) { + if (!tp->packets_out && tcp_is_sack(tp)) { const struct inet_connection_sock *icsk = inet_csk(sk); if (tp->lost_out) { printk(KERN_DEBUG "Leak l=%u %d\n", @@ -2779,7 +2789,7 @@ static int tcp_process_frto(struct sock *sk, int flag) return 1; } - if (!IsSackFrto() || IsReno(tp)) { + if (!IsSackFrto() || tcp_is_reno(tp)) { /* RFC4138 shortcoming in step 2; should also have case c): * ACK isn't duplicate nor advances window, e.g., opposite dir * data, winupdate @@ -3263,7 +3273,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) * Probably, we should reset in this case. For now drop them. */ __skb_queue_purge(&tp->out_of_order_queue); - if (tp->rx_opt.sack_ok) + if (tcp_is_sack(tp)) tcp_sack_reset(&tp->rx_opt); sk_stream_mem_reclaim(sk); @@ -3293,7 +3303,7 @@ static inline int tcp_sack_extend(struct tcp_sack_block *sp, u32 seq, u32 end_se static void tcp_dsack_set(struct tcp_sock *tp, u32 seq, u32 end_seq) { - if (tp->rx_opt.sack_ok && sysctl_tcp_dsack) { + if (tcp_is_sack(tp) && sysctl_tcp_dsack) { if (before(seq, tp->rcv_nxt)) NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOLDSENT); else @@ -3323,7 +3333,7 @@ static void tcp_send_dupack(struct sock *sk, struct sk_buff *skb) NET_INC_STATS_BH(LINUX_MIB_DELAYEDACKLOST); tcp_enter_quickack_mode(sk); - if (tp->rx_opt.sack_ok && sysctl_tcp_dsack) { + if (tcp_is_sack(tp) && sysctl_tcp_dsack) { u32 end_seq = TCP_SKB_CB(skb)->end_seq; if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) @@ -3639,7 +3649,7 @@ drop: if (!skb_peek(&tp->out_of_order_queue)) { /* Initial out of order segment, build 1 SACK. */ - if (tp->rx_opt.sack_ok) { + if (tcp_is_sack(tp)) { tp->rx_opt.num_sacks = 1; tp->rx_opt.dsack = 0; tp->rx_opt.eff_sacks = 1; @@ -3704,7 +3714,7 @@ drop: } add_sack: - if (tp->rx_opt.sack_ok) + if (tcp_is_sack(tp)) tcp_sack_new_ofo_skb(sk, seq, end_seq); } } @@ -3893,7 +3903,7 @@ static int tcp_prune_queue(struct sock *sk) * is in a sad state like this, we care only about integrity * of the connection not performance. */ - if (tp->rx_opt.sack_ok) + if (tcp_is_sack(tp)) tcp_sack_reset(&tp->rx_opt); sk_stream_mem_reclaim(sk); } @@ -4594,8 +4604,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tp->tcp_header_len = sizeof(struct tcphdr); } - if (tp->rx_opt.sack_ok && sysctl_tcp_fack) - tp->rx_opt.sack_ok |= 2; + if (tcp_is_sack(tp) && sysctl_tcp_fack) + tcp_enable_fack(tp); tcp_mtup_init(sk); tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index fdfe89fe646b..b61b76847ad9 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -445,7 +445,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->rx_opt.tstamp_ok = ireq->tstamp_ok; if ((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) { if (sysctl_tcp_fack) - newtp->rx_opt.sack_ok |= 2; + tcp_enable_fack(newtp); } newtp->window_clamp = req->window_clamp; newtp->rcv_ssthresh = req->rcv_wnd; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a92fad55cd32..a3679174e78a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -737,7 +737,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss if (diff > 0) { /* Adjust Reno SACK estimate. */ - if (!tp->rx_opt.sack_ok) { + if (tcp_is_reno(tp)) { tcp_dec_pcount_approx_int(&tp->sacked_out, diff); tcp_verify_left_out(tp); } @@ -1728,7 +1728,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m if (TCP_SKB_CB(next_skb)->sacked&TCPCB_LOST) tp->lost_out -= tcp_skb_pcount(next_skb); /* Reno case is special. Sigh... */ - if (!tp->rx_opt.sack_ok && tp->sacked_out) + if (tcp_is_reno(tp) && tp->sacked_out) tcp_dec_pcount_approx(&tp->sacked_out, next_skb); /* Not quite right: it can be > snd.fack, but @@ -1976,7 +1976,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk) return; /* No forward retransmissions in Reno are possible. */ - if (!tp->rx_opt.sack_ok) + if (tcp_is_reno(tp)) return; /* Yeah, we have to make difficult choice between forward transmission diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index e9b151b3a598..d8970ecfcfc8 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -315,7 +315,7 @@ static void tcp_retransmit_timer(struct sock *sk) if (icsk->icsk_retransmits == 0) { if (icsk->icsk_ca_state == TCP_CA_Disorder || icsk->icsk_ca_state == TCP_CA_Recovery) { - if (tp->rx_opt.sack_ok) { + if (tcp_is_sack(tp)) { if (icsk->icsk_ca_state == TCP_CA_Recovery) NET_INC_STATS_BH(LINUX_MIB_TCPSACKRECOVERYFAIL); else From 13dae426318aae073028a4b3bd493104a991e800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 10 Aug 2007 14:31:21 -0700 Subject: [PATCH 1059/2804] [TCP]: Update comment about highest_sack validity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This stale info came from the original idea, which proved to be unnecessarily complex, sacked_out > 0 is easy to do and that when it's going to be needed anyway (it _can_ be valid also when sacked_out == 0 but there's not going to be a guarantee about it for now). Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/linux/tcp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 1f12fa0b67d7..f8cf090e8f49 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -332,7 +332,8 @@ struct tcp_sock { struct tcp_sack_block_wire recv_sack_cache[4]; - u32 highest_sack; /* Start seq of globally highest revd SACK (valid only in slowpath) */ + u32 highest_sack; /* Start seq of globally highest revd SACK + * (validity guaranteed only if sacked_out > 0) */ /* from STCP, retrans queue hinting */ struct sk_buff* lost_skb_hint; From 0680191642c27c81c9be4557d9c6aa3487c15f69 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 10 Aug 2007 15:22:13 -0700 Subject: [PATCH 1060/2804] [IPV4] fib_trie: cleanup Try this out: * replace macro's with inlines * get rid of places doing multiple evaluations of NODE_PARENT [akpm@linux-foundation.org: rcu_dereference wants an lval] Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 68 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 9ca786a6fd3c..f28f9f5f240c 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -93,15 +93,8 @@ typedef unsigned int t_key; #define T_TNODE 0 #define T_LEAF 1 #define NODE_TYPE_MASK 0x1UL -#define NODE_PARENT(node) \ - ((struct tnode *)rcu_dereference(((node)->parent & ~NODE_TYPE_MASK))) - #define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK) -#define NODE_SET_PARENT(node, ptr) \ - rcu_assign_pointer((node)->parent, \ - ((unsigned long)(ptr)) | NODE_TYPE(node)) - #define IS_TNODE(n) (!(n->parent & T_LEAF)) #define IS_LEAF(n) (n->parent & T_LEAF) @@ -174,6 +167,19 @@ static void tnode_free(struct tnode *tn); static struct kmem_cache *fn_alias_kmem __read_mostly; static struct trie *trie_local = NULL, *trie_main = NULL; +static inline struct tnode *node_parent(struct node *node) +{ + struct tnode *ret; + + ret = (struct tnode *)(node->parent & ~NODE_TYPE_MASK); + return rcu_dereference(ret); +} + +static inline void node_set_parent(struct node *node, struct tnode *ptr) +{ + rcu_assign_pointer(node->parent, + (unsigned long)ptr | NODE_TYPE(node)); +} /* rcu_read_lock needs to be hold by caller from readside */ @@ -446,7 +452,7 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int w tn->full_children++; if (n) - NODE_SET_PARENT(n, tn); + node_set_parent(n, tn); rcu_assign_pointer(tn->child[i], n); } @@ -481,7 +487,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) continue; /* compress one level */ - NODE_SET_PARENT(n, NULL); + node_set_parent(n, NULL); tnode_free(tn); return n; } @@ -636,7 +642,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* compress one level */ - NODE_SET_PARENT(n, NULL); + node_set_parent(n, NULL); tnode_free(tn); return n; } @@ -961,24 +967,21 @@ fib_find_node(struct trie *t, u32 key) static struct node *trie_rebalance(struct trie *t, struct tnode *tn) { int wasfull; - t_key cindex, key; - struct tnode *tp = NULL; + t_key cindex, key = tn->key; + struct tnode *tp; - key = tn->key; - - while (tn != NULL && NODE_PARENT(tn) != NULL) { - - tp = NODE_PARENT(tn); + while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { cindex = tkey_extract_bits(key, tp->pos, tp->bits); wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); tn = (struct tnode *) resize (t, (struct tnode *)tn); tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull); - if (!NODE_PARENT(tn)) + tp = node_parent((struct node *) tn); + if (!tp) break; - - tn = NODE_PARENT(tn); + tn = tp; } + /* Handle last (top) tnode */ if (IS_TNODE(tn)) tn = (struct tnode*) resize(t, (struct tnode *)tn); @@ -1031,7 +1034,7 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen) pos = tn->pos + tn->bits; n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits)); - BUG_ON(n && NODE_PARENT(n) != tn); + BUG_ON(n && node_parent(n) != tn); } else break; } @@ -1083,7 +1086,7 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen) if (t->trie && n == NULL) { /* Case 2: n is NULL, and will just insert a new leaf */ - NODE_SET_PARENT(l, tp); + node_set_parent((struct node *)l, tp); cindex = tkey_extract_bits(key, tp->pos, tp->bits); put_child(t, (struct tnode *)tp, cindex, (struct node *)l); @@ -1114,7 +1117,7 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen) goto err; } - NODE_SET_PARENT(tn, tp); + node_set_parent((struct node *)tn, tp); missbit = tkey_extract_bits(key, newpos, 1); put_child(t, tn, missbit, (struct node *)l); @@ -1495,12 +1498,13 @@ backtrace: if (chopped_off <= pn->bits) { cindex &= ~(1 << (chopped_off-1)); } else { - if (NODE_PARENT(pn) == NULL) + struct tnode *parent = node_parent((struct node *) pn); + if (!parent) goto failed; /* Get Child's index */ - cindex = tkey_extract_bits(pn->key, NODE_PARENT(pn)->pos, NODE_PARENT(pn)->bits); - pn = NODE_PARENT(pn); + cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits); + pn = parent; chopped_off = 0; #ifdef CONFIG_IP_FIB_TRIE_STATS @@ -1536,7 +1540,7 @@ static int trie_leaf_remove(struct trie *t, t_key key) check_tnode(tn); n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits)); - BUG_ON(n && NODE_PARENT(n) != tn); + BUG_ON(n && node_parent(n) != tn); } l = (struct leaf *) n; @@ -1551,7 +1555,7 @@ static int trie_leaf_remove(struct trie *t, t_key key) t->revision++; t->size--; - tp = NODE_PARENT(n); + tp = node_parent(n); tnode_free((struct tnode *) n); if (tp) { @@ -1703,7 +1707,7 @@ static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf) p = (struct tnode*) trie; /* Start */ } else - p = (struct tnode *) NODE_PARENT(c); + p = node_parent(c); while (p) { int pos, last; @@ -1740,7 +1744,7 @@ static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf) up: /* No more children go up one step */ c = (struct node *) p; - p = (struct tnode *) NODE_PARENT(p); + p = node_parent(c); } return NULL; /* Ready. Root of trie */ } @@ -2043,7 +2047,7 @@ rescan: } /* Current node exhausted, pop back up */ - p = NODE_PARENT(tn); + p = node_parent((struct node *)tn); if (p) { cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1; tn = p; @@ -2317,7 +2321,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) return 0; - if (!NODE_PARENT(n)) { + if (!node_parent(n)) { if (iter->trie == trie_local) seq_puts(seq, ":\n"); else From ab66b4a7a3969077f6e2a18a0d2d849d3b84a337 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 10 Aug 2007 15:22:58 -0700 Subject: [PATCH 1061/2804] [IPV4] fib_trie: macro cleanup This patch converts the messy macro for MASK_PFX to inline function and expands TKEY_GET_MASK in the one place it is used. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index f28f9f5f240c..52b2891c63b7 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -85,8 +85,6 @@ #define MAX_STAT_DEPTH 32 #define KEYLENGTH (8*sizeof(t_key)) -#define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l)) -#define TKEY_GET_MASK(offset, bits) (((bits)==0)?0:((t_key)(-1) << (KEYLENGTH - bits) >> offset)) typedef unsigned int t_key; @@ -195,6 +193,11 @@ static inline int tnode_child_length(const struct tnode *tn) return 1 << tn->bits; } +static inline t_key mask_pfx(t_key k, unsigned short l) +{ + return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l); +} + static inline t_key tkey_extract_bits(t_key a, int offset, int bits) { if (offset < KEYLENGTH) @@ -679,7 +682,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) inode->pos == oldtnode->pos + oldtnode->bits && inode->bits > 1) { struct tnode *left, *right; - t_key m = TKEY_GET_MASK(inode->pos, 1); + t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos; left = tnode_new(inode->key&(~m), inode->pos + 1, inode->bits - 1); @@ -1367,7 +1370,8 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result bits = pn->bits; if (!chopped_off) - cindex = tkey_extract_bits(MASK_PFX(key, current_prefix_length), pos, bits); + cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length), + pos, bits); n = tnode_get_child(pn, cindex); @@ -1453,8 +1457,8 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result * to find a matching prefix. */ - node_prefix = MASK_PFX(cn->key, cn->pos); - key_prefix = MASK_PFX(key, cn->pos); + node_prefix = mask_pfx(cn->key, cn->pos); + key_prefix = mask_pfx(key, cn->pos); pref_mismatch = key_prefix^node_prefix; mp = 0; @@ -2330,7 +2334,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) if (IS_TNODE(n)) { struct tnode *tn = (struct tnode *) n; - __be32 prf = htonl(MASK_PFX(tn->key, tn->pos)); + __be32 prf = htonl(mask_pfx(tn->key, tn->pos)); seq_indent(seq, iter->depth-1); seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n", From d39badf05b52f99169b22ce324fd31c8b44a0473 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:27:24 -0700 Subject: [PATCH 1062/2804] [NET] netconsole: Cleanups, codingstyle, prettyfication Based upon initial work by Keiichi Kii . (1) Remove unwanted headers. (2) Mark __init and __exit as appropriate. (3) Various trivial codingstyle and prettification stuff. Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 55 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 69233f6aa05c..f1c2a2defd70 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -35,35 +35,32 @@ ****************************************************************/ #include -#include #include #include #include -#include #include #include -#include -#include #include MODULE_AUTHOR("Maintainer: Matt Mackall "); MODULE_DESCRIPTION("Console driver for network interfaces"); MODULE_LICENSE("GPL"); -static char config[256]; -module_param_string(netconsole, config, 256, 0); +#define MAX_PARAM_LENGTH 256 +#define MAX_PRINT_CHUNK 1000 + +static char config[MAX_PARAM_LENGTH]; +module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); static struct netpoll np = { - .name = "netconsole", - .dev_name = "eth0", - .local_port = 6665, - .remote_port = 6666, - .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, }; -static int configured = 0; - -#define MAX_PRINT_CHUNK 1000 +static int configured; static void write_msg(struct console *con, const char *msg, unsigned int len) { @@ -75,7 +72,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) local_irq_save(flags); - for(left = len; left; ) { + for (left = len; left;) { frag = min(left, MAX_PRINT_CHUNK); netpoll_send_udp(&np, msg, frag); msg += frag; @@ -86,12 +83,12 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) } static struct console netconsole = { - .name = "netcon", - .flags = CON_ENABLED | CON_PRINTBUFFER, - .write = write_msg + .name = "netcon", + .flags = CON_ENABLED | CON_PRINTBUFFER, + .write = write_msg, }; -static int option_setup(char *opt) +static int __init option_setup(char *opt) { configured = !netpoll_parse_options(&np, opt); return 1; @@ -99,28 +96,30 @@ static int option_setup(char *opt) __setup("netconsole=", option_setup); -static int init_netconsole(void) +static int __init init_netconsole(void) { - int err; + int err = 0; - if(strlen(config)) + if (strnlen(config, MAX_PARAM_LENGTH)) option_setup(config); - if(!configured) { - printk("netconsole: not configured, aborting\n"); - return 0; + if (!configured) { + printk(KERN_INFO "netconsole: not configured, aborting\n"); + goto out; } err = netpoll_setup(&np); if (err) - return err; + goto out; register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); - return 0; + +out: + return err; } -static void cleanup_netconsole(void) +static void __exit cleanup_netconsole(void) { unregister_console(&netconsole); netpoll_cleanup(&np); From d133ccbdc30c7f86459519cec1126d6473762b10 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:28:10 -0700 Subject: [PATCH 1063/2804] [NET] netconsole: Remove bogus check Based upon initial work by Keiichi Kii . The (!np.dev) check in write_msg() is bogus (always false), because: np.dev is set by netpoll_setup(), which is called by init_netconsole() before register_console(), so write_msg() cannot be triggered unless netpoll_setup() successfully set np.dev. Also np.dev cannot go away from under us, because netpoll_setup() grabs us reference on it. So let's remove the bogus check. Signed-off-by: Satyam Sharma Acked-by: Keiichi Kii Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index f1c2a2defd70..2c2aef1ae8eb 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -67,9 +67,6 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) int frag, left; unsigned long flags; - if (!np.dev) - return; - local_irq_save(flags); for (left = len; left;) { From d2b60881e28072109601c373abd1085499ccfef0 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:29:47 -0700 Subject: [PATCH 1064/2804] [NET] netconsole: Simplify boot/module option setup logic Based upon initial work by Keiichi Kii . Presently, boot/module parameters are set up quite differently for the case of built-in netconsole (__setup() -> obsolete_checksetup() -> netpoll_parse_options() -> strlen(config) == 0 in init_netconsole()) vs modular netconsole (module_param_string() -> string copied to the config variable -> strlen(config) != 0 init_netconsole() -> netpoll_parse_options()). This patch makes both of them similar by doing exactly the equivalent of a module_param_string() in option_setup() also -- just copying the param string passed from the kernel command line into "config" variable. So, strlen(config) != 0 in both cases, and netpoll_parse_options() is always called from init_netconsole(), thus making the setup logic for both cases similar. Now, option_setup() is only ever called / used for the built-in case, so we put it inside a #ifndef MODULE, otherwise gcc will complain about option_setup() being "defined but not used". Also, the "configured" variable is redundant with this patch and hence removed. Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 2c2aef1ae8eb..e56aa6c9743f 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -53,6 +53,15 @@ static char config[MAX_PARAM_LENGTH]; module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); +#ifndef MODULE +static int __init option_setup(char *opt) +{ + strlcpy(config, opt, MAX_PARAM_LENGTH); + return 1; +} +__setup("netconsole=", option_setup); +#endif /* MODULE */ + static struct netpoll np = { .name = "netconsole", .dev_name = "eth0", @@ -60,7 +69,6 @@ static struct netpoll np = { .remote_port = 6666, .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, }; -static int configured; static void write_msg(struct console *con, const char *msg, unsigned int len) { @@ -85,26 +93,19 @@ static struct console netconsole = { .write = write_msg, }; -static int __init option_setup(char *opt) -{ - configured = !netpoll_parse_options(&np, opt); - return 1; -} - -__setup("netconsole=", option_setup); - static int __init init_netconsole(void) { int err = 0; - if (strnlen(config, MAX_PARAM_LENGTH)) - option_setup(config); - - if (!configured) { + if (!strnlen(config, MAX_PARAM_LENGTH)) { printk(KERN_INFO "netconsole: not configured, aborting\n"); goto out; } + err = netpoll_parse_options(&np, config); + if (err) + goto out; + err = netpoll_setup(&np); if (err) goto out; From 0cc120bea1d4ba3893a26c70d271e89f928b8a97 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:30:31 -0700 Subject: [PATCH 1065/2804] [NET] netconsole: Use netif_running() in write_msg() Based upon initial work by Keiichi Kii . Avoid unnecessarily disabling interrupts and calling netpoll_send_udp() if the corresponding local interface is not up. Signed-off-by: Satyam Sharma Acked-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e56aa6c9743f..75cb76139ddc 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -75,16 +75,16 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) int frag, left; unsigned long flags; - local_irq_save(flags); - - for (left = len; left;) { - frag = min(left, MAX_PRINT_CHUNK); - netpoll_send_udp(&np, msg, frag); - msg += frag; - left -= frag; + if (netif_running(np.dev)) { + local_irq_save(flags); + for (left = len; left;) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&np, msg, frag); + msg += frag; + left -= frag; + } + local_irq_restore(flags); } - - local_irq_restore(flags); } static struct console netconsole = { From 8d4ef88b5df1afe097e38aef8cab2ed35ca141ea Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:31:19 -0700 Subject: [PATCH 1066/2804] [NET] netconsole: Add some useful tips to documentation Based upon initial work by Keiichi Kii . Add some useful general-purpose tips. Also suggest solution for the frequent problem of console loglevel set too low numerically (i.e. for high priority messages only) on the sender. Signed-off-by: Satyam Sharma Acked-by: Keiichi Kii Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- Documentation/networking/netconsole.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt index 1caa6c734691..5962f45815a2 100644 --- a/Documentation/networking/netconsole.txt +++ b/Documentation/networking/netconsole.txt @@ -44,11 +44,36 @@ WARNING: the default target ethernet setting uses the broadcast ethernet address to send packets, which can cause increased load on other systems on the same ethernet segment. +TIP: some LAN switches may be configured to suppress ethernet broadcasts +so it is advised to explicitly specify the remote agents' MAC addresses +from the config parameters passed to netconsole. + +TIP: to find out the MAC address of, say, 10.0.0.2, you may try using: + + ping -c 1 10.0.0.2 ; /sbin/arp -n | grep 10.0.0.2 + +TIP: in case the remote logging agent is on a separate LAN subnet than +the sender, it is suggested to try specifying the MAC address of the +default gateway (you may use /sbin/route -n to find it out) as the +remote MAC address instead. + NOTE: the network device (eth1 in the above case) can run any kind of other network traffic, netconsole is not intrusive. Netconsole might cause slight delays in other traffic if the volume of kernel messages is high, but should have no other impact. +NOTE: if you find that the remote logging agent is not receiving or +printing all messages from the sender, it is likely that you have set +the "console_loglevel" parameter (on the sender) to only send high +priority messages to the console. You can change this at runtime using: + + dmesg -n 8 + +or by specifying "debug" on the kernel command line at boot, to send +all kernel messages to the console. A specific value for this parameter +can also be set using the "loglevel" kernel boot option. See the +dmesg(8) man page and Documentation/kernel-parameters.txt for details. + Netconsole was designed to be as instantaneous as possible, to enable the logging of even the most critical kernel bugs. It works from IRQ contexts as well, and does not enable interrupts while From df180e369cf54a8ef8440667ab1d13d452fc7215 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:32:14 -0700 Subject: [PATCH 1067/2804] [NET] netconsole: Introduce netconsole_target Based upon initial work by Keiichi Kii . Introduce a wrapper structure over netpoll to represent logging targets configured in netconsole. This will get extended with other members in further patches. This is done independent of the (to-be-introduced) NETCONSOLE_DYNAMIC config option so that we're able to drastically cut down on the #ifdef complexity of final netconsole.c. Also, struct netconsole_target would be required for multiple targets support also, and not just dynamic reconfigurability. Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 75cb76139ddc..be15ca6205a8 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -62,24 +62,35 @@ static int __init option_setup(char *opt) __setup("netconsole=", option_setup); #endif /* MODULE */ -static struct netpoll np = { - .name = "netconsole", - .dev_name = "eth0", - .local_port = 6665, - .remote_port = 6666, - .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +/** + * struct netconsole_target - Represents a configured netconsole target. + * @np: The netpoll structure for this target. + */ +struct netconsole_target { + struct netpoll np; +}; + +static struct netconsole_target default_target = { + .np = { + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, }; static void write_msg(struct console *con, const char *msg, unsigned int len) { int frag, left; unsigned long flags; + struct netconsole_target *nt = &default_target; - if (netif_running(np.dev)) { + if (netif_running(nt->np.dev)) { local_irq_save(flags); for (left = len; left;) { frag = min(left, MAX_PRINT_CHUNK); - netpoll_send_udp(&np, msg, frag); + netpoll_send_udp(&nt->np, msg, frag); msg += frag; left -= frag; } @@ -96,17 +107,18 @@ static struct console netconsole = { static int __init init_netconsole(void) { int err = 0; + struct netconsole_target *nt = &default_target; if (!strnlen(config, MAX_PARAM_LENGTH)) { printk(KERN_INFO "netconsole: not configured, aborting\n"); goto out; } - err = netpoll_parse_options(&np, config); + err = netpoll_parse_options(&nt->np, config); if (err) goto out; - err = netpoll_setup(&np); + err = netpoll_setup(&nt->np); if (err) goto out; @@ -119,8 +131,10 @@ out: static void __exit cleanup_netconsole(void) { + struct netconsole_target *nt = &default_target; + unregister_console(&netconsole); - netpoll_cleanup(&np); + netpoll_cleanup(&nt->np); } module_init(init_netconsole); From 17951f34b0970b05e29fd93a5b93fa05ec71308b Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:33:01 -0700 Subject: [PATCH 1068/2804] [NET] netconsole: Introduce netconsole_netdev_notifier Based upon initial work by Keiichi Kii . To update fields of underlying netpoll structure at runtime on corresponding NETDEV_CHANGEADDR or NETDEV_CHANGENAME notifications. ioctl(SIOCSIFHWADDR or SIOCSIFNAME) could be used to change the hardware/MAC address or name of the local interface that our netpoll is attached to. Whenever this happens, netdev notifier chain is called out with the NETDEV_CHANGEADDR or NETDEV_CHANGENAME event message. We respond to that and update the local_mac or dev_name field of the struct netpoll. This makes sense anyway, but is especially required for dynamic netconsole because the netpoll structure's internal members become user visible files when either sysfs or configfs are used. So this helps us to keep up with the MAC address/name changes and keep values in struct netpoll uptodate. [ Note that ioctl(SIOCSIFADDR) to change IP address of interface at runtime is not handled (to update local_ip of netpoll) on purpose -- some setups may set the local_ip to a private address, not necessary the actual IP address of the sender host, as presently allowed. ] Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index be15ca6205a8..55570988250b 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -80,6 +80,33 @@ static struct netconsole_target default_target = { }, }; +/* Handle network interface device notifications */ +static int netconsole_netdev_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + struct netconsole_target *nt = &default_target; + + if (nt->np.dev == dev) { + switch (event) { + case NETDEV_CHANGEADDR: + memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN); + break; + + case NETDEV_CHANGENAME: + strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); + break; + } + } + + return NOTIFY_DONE; +} + +static struct notifier_block netconsole_netdev_notifier = { + .notifier_call = netconsole_netdev_event, +}; + static void write_msg(struct console *con, const char *msg, unsigned int len) { int frag, left; @@ -122,6 +149,10 @@ static int __init init_netconsole(void) if (err) goto out; + err = register_netdevice_notifier(&netconsole_netdev_notifier); + if (err) + goto out; + register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); @@ -134,6 +165,7 @@ static void __exit cleanup_netconsole(void) struct netconsole_target *nt = &default_target; unregister_console(&netconsole); + unregister_netdevice_notifier(&netconsole_netdev_notifier); netpoll_cleanup(&nt->np); } From b5427c27173e128dda1541bd9d3b05df79af5882 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:33:40 -0700 Subject: [PATCH 1069/2804] [NET] netconsole: Support multiple logging targets Based upon initial work by Keiichi Kii . This patch introduces support for multiple targets, independent of CONFIG_NETCONSOLE_DYNAMIC -- this is useful even in the default case and (including the infrastructure introduced in previous patches) doesn't really add too many bytes to module text. All the complexity (and size) comes with the dynamic reconfigurability / userspace interface patch, and so it's plausible users may want to keep this enabled but that disabled (say to avoid a dependency on CONFIG_CONFIGFS_FS too). Also update documentation to mention the use of ";" separator to specify multiple logging targets in the boot/module option string. Brief overview: We maintain a target_list (and corresponding lock). Get rid of the static "default_target" and introduce allocation and release functions for our netconsole_target objects (but keeping sure to preserve previous behaviour such as default values). During init_netconsole(), ";" is used as the separator to identify multiple target specifications in the boot/module option string. The target specifications are parsed and netpolls setup. During exit, the target_list is torn down and all items released. Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- Documentation/networking/netconsole.txt | 6 + drivers/net/netconsole.c | 169 ++++++++++++++++++------ 2 files changed, 136 insertions(+), 39 deletions(-) diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt index 5962f45815a2..1aaa7383e41d 100644 --- a/Documentation/networking/netconsole.txt +++ b/Documentation/networking/netconsole.txt @@ -34,6 +34,12 @@ Examples: insmod netconsole netconsole=@/,@10.0.0.2/ +It also supports logging to multiple remote agents by specifying +parameters for the multiple agents separated by semicolons and the +complete string enclosed in "quotes", thusly: + + modprobe netconsole netconsole="@/,@10.0.0.2/;@/eth1,6892@10.0.0.3/" + Built-in netconsole starts immediately after the TCP stack is initialized and attempts to bring up the supplied dev at the supplied address. diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 55570988250b..458c4d674a9e 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -62,44 +62,93 @@ static int __init option_setup(char *opt) __setup("netconsole=", option_setup); #endif /* MODULE */ +/* Linked list of all configured targets */ +static LIST_HEAD(target_list); + +/* This needs to be a spinlock because write_msg() cannot sleep */ +static DEFINE_SPINLOCK(target_list_lock); + /** * struct netconsole_target - Represents a configured netconsole target. + * @list: Links this target into the target_list. * @np: The netpoll structure for this target. */ struct netconsole_target { + struct list_head list; struct netpoll np; }; -static struct netconsole_target default_target = { - .np = { - .name = "netconsole", - .dev_name = "eth0", - .local_port = 6665, - .remote_port = 6666, - .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - }, -}; +/* Allocate new target and setup netpoll for it */ +static struct netconsole_target *alloc_target(char *target_config) +{ + int err = -ENOMEM; + struct netconsole_target *nt; + + /* Allocate and initialize with defaults */ + nt = kzalloc(sizeof(*nt), GFP_KERNEL); + if (!nt) { + printk(KERN_ERR "netconsole: failed to allocate memory\n"); + goto fail; + } + + nt->np.name = "netconsole"; + strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); + nt->np.local_port = 6665; + nt->np.remote_port = 6666; + memset(nt->np.remote_mac, 0xff, ETH_ALEN); + + /* Parse parameters and setup netpoll */ + err = netpoll_parse_options(&nt->np, target_config); + if (err) + goto fail; + + err = netpoll_setup(&nt->np); + if (err) + goto fail; + + return nt; + +fail: + kfree(nt); + return ERR_PTR(err); +} + +/* Cleanup netpoll for given target and free it */ +static void free_target(struct netconsole_target *nt) +{ + netpoll_cleanup(&nt->np); + kfree(nt); +} /* Handle network interface device notifications */ static int netconsole_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { + unsigned long flags; + struct netconsole_target *nt; struct net_device *dev = ptr; - struct netconsole_target *nt = &default_target; - if (nt->np.dev == dev) { - switch (event) { - case NETDEV_CHANGEADDR: - memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN); - break; + if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME)) + goto done; - case NETDEV_CHANGENAME: - strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); - break; + spin_lock_irqsave(&target_list_lock, flags); + list_for_each_entry(nt, &target_list, list) { + if (nt->np.dev == dev) { + switch (event) { + case NETDEV_CHANGEADDR: + memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN); + break; + + case NETDEV_CHANGENAME: + strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); + break; + } } } + spin_unlock_irqrestore(&target_list_lock, flags); +done: return NOTIFY_DONE; } @@ -111,18 +160,32 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) { int frag, left; unsigned long flags; - struct netconsole_target *nt = &default_target; + struct netconsole_target *nt; + const char *tmp; - if (netif_running(nt->np.dev)) { - local_irq_save(flags); - for (left = len; left;) { - frag = min(left, MAX_PRINT_CHUNK); - netpoll_send_udp(&nt->np, msg, frag); - msg += frag; - left -= frag; + /* Avoid taking lock and disabling interrupts unnecessarily */ + if (list_empty(&target_list)) + return; + + spin_lock_irqsave(&target_list_lock, flags); + list_for_each_entry(nt, &target_list, list) { + if (netif_running(nt->np.dev)) { + /* + * We nest this inside the for-each-target loop above + * so that we're able to get as much logging out to + * at least one target if we die inside here, instead + * of unnecessarily keeping all targets in lock-step. + */ + tmp = msg; + for (left = len; left;) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&nt->np, tmp, frag); + tmp += frag; + left -= frag; + } } - local_irq_restore(flags); } + spin_unlock_irqrestore(&target_list_lock, flags); } static struct console netconsole = { @@ -134,39 +197,67 @@ static struct console netconsole = { static int __init init_netconsole(void) { int err = 0; - struct netconsole_target *nt = &default_target; + struct netconsole_target *nt, *tmp; + unsigned long flags; + char *target_config; + char *input = config; - if (!strnlen(config, MAX_PARAM_LENGTH)) { + if (!strnlen(input, MAX_PARAM_LENGTH)) { printk(KERN_INFO "netconsole: not configured, aborting\n"); goto out; } - err = netpoll_parse_options(&nt->np, config); - if (err) - goto out; - - err = netpoll_setup(&nt->np); - if (err) - goto out; + while ((target_config = strsep(&input, ";"))) { + nt = alloc_target(target_config); + if (IS_ERR(nt)) { + err = PTR_ERR(nt); + goto fail; + } + spin_lock_irqsave(&target_list_lock, flags); + list_add(&nt->list, &target_list); + spin_unlock_irqrestore(&target_list_lock, flags); + } err = register_netdevice_notifier(&netconsole_netdev_notifier); if (err) - goto out; + goto fail; register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); out: return err; + +fail: + printk(KERN_ERR "netconsole: cleaning up\n"); + + /* + * Remove all targets and destroy them. Skipping the list + * lock is safe here, and netpoll_cleanup() will sleep. + */ + list_for_each_entry_safe(nt, tmp, &target_list, list) { + list_del(&nt->list); + free_target(nt); + } + + return err; } static void __exit cleanup_netconsole(void) { - struct netconsole_target *nt = &default_target; + struct netconsole_target *nt, *tmp; unregister_console(&netconsole); unregister_netdevice_notifier(&netconsole_netdev_notifier); - netpoll_cleanup(&nt->np); + + /* + * Remove all targets and destroy them. Skipping the list + * lock is safe here, and netpoll_cleanup() will sleep. + */ + list_for_each_entry_safe(nt, tmp, &target_list, list) { + list_del(&nt->list); + free_target(nt); + } } module_init(init_netconsole); From 0bcc1816188e570bde1d56a208996660f2633ae0 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:35:05 -0700 Subject: [PATCH 1070/2804] [NET] netconsole: Support dynamic reconfiguration using configfs Based upon initial work by Keiichi Kii . This patch introduces support for dynamic reconfiguration (adding, removing and/or modifying parameters of netconsole targets at runtime) using a userspace interface exported via configfs. Documentation is also updated accordingly. Issues and brief design overview: (1) Kernel-initiated creation / destruction of kernel objects is not possible with configfs -- the lifetimes of the "config items" is managed exclusively from userspace. But netconsole must support boot/module params too, and these are parsed in kernel and hence netpolls must be setup from the kernel. Joel Becker suggested to separately manage the lifetimes of the two kinds of netconsole_target objects -- those created via configfs mkdir(2) from userspace and those specified from the boot/module option string. This adds complexity and some redundancy here and also means that boot/module param-created targets are not exposed through the configfs namespace (and hence cannot be updated / destroyed dynamically). However, this saves us from locking / refcounting complexities that would need to be introduced in configfs to support kernel-initiated item creation / destroy there. (2) In configfs, item creation takes place in the call chain of the mkdir(2) syscall in the driver subsystem. If we used an ioctl(2) to create / destroy objects from userspace, the special userspace program is able to fill out the structure to be passed into the ioctl and hence specify attributes such as local interface that are required at the time we set up the netpoll. For configfs, this information is not available at the time of mkdir(2). So, we keep all newly-created targets (via configfs) disabled by default. The user is expected to set various attributes appropriately (including the local network interface if required) and then write(2) "1" to the "enabled" attribute. Thus, netpoll_setup() is then called on the set parameters in the context of _this_ write(2) on the "enabled" attribute itself. This design enables the user to reconfigure existing netconsole targets at runtime to be attached to newly-come-up interfaces that may not have existed when netconsole was loaded or when the targets were actually created. All this effectively enables us to get rid of custom ioctls. (3) Ultra-paranoid configfs attribute show() and store() operations, with sanity and input range checking, using only safe string primitives, and compliant with the recommendations in Documentation/filesystems/sysfs.txt. (4) A new function netpoll_print_options() is created in the netpoll API, that just prints out the configured parameters for a netpoll structure. netpoll_parse_options() is modified to use that and it is also exported to be used from netconsole. Signed-off-by: Satyam Sharma Acked-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- Documentation/networking/netconsole.txt | 68 +++ drivers/net/Kconfig | 10 + drivers/net/netconsole.c | 605 +++++++++++++++++++++++- include/linux/netpoll.h | 1 + net/core/netpoll.c | 44 +- 5 files changed, 683 insertions(+), 45 deletions(-) diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt index 1aaa7383e41d..3c2f2b328638 100644 --- a/Documentation/networking/netconsole.txt +++ b/Documentation/networking/netconsole.txt @@ -3,6 +3,10 @@ started by Ingo Molnar , 2001.09.17 2.6 port and netpoll api by Matt Mackall , Sep 9 2003 Please send bug reports to Matt Mackall +and Satyam Sharma + +Introduction: +============= This module logs kernel printk messages over UDP allowing debugging of problem where disk logging fails and serial consoles are impractical. @@ -13,6 +17,9 @@ the specified interface as soon as possible. While this doesn't allow capture of early kernel panics, it does capture most of the boot process. +Sender and receiver configuration: +================================== + It takes a string configuration parameter "netconsole" in the following format: @@ -46,6 +53,67 @@ address. The remote host can run either 'netcat -u -l -p ' or syslogd. +Dynamic reconfiguration: +======================== + +Dynamic reconfigurability is a useful addition to netconsole that enables +remote logging targets to be dynamically added, removed, or have their +parameters reconfigured at runtime from a configfs-based userspace interface. +[ Note that the parameters of netconsole targets that were specified/created +from the boot/module option are not exposed via this interface, and hence +cannot be modified dynamically. ] + +To include this feature, select CONFIG_NETCONSOLE_DYNAMIC when building the +netconsole module (or kernel, if netconsole is built-in). + +Some examples follow (where configfs is mounted at the /sys/kernel/config +mountpoint). + +To add a remote logging target (target names can be arbitrary): + + cd /sys/kernel/config/netconsole/ + mkdir target1 + +Note that newly created targets have default parameter values (as mentioned +above) and are disabled by default -- they must first be enabled by writing +"1" to the "enabled" attribute (usually after setting parameters accordingly) +as described below. + +To remove a target: + + rmdir /sys/kernel/config/netconsole/othertarget/ + +The interface exposes these parameters of a netconsole target to userspace: + + enabled Is this target currently enabled? (read-write) + dev_name Local network interface name (read-write) + local_port Source UDP port to use (read-write) + remote_port Remote agent's UDP port (read-write) + local_ip Source IP address to use (read-write) + remote_ip Remote agent's IP address (read-write) + local_mac Local interface's MAC address (read-only) + remote_mac Remote agent's MAC address (read-write) + +The "enabled" attribute is also used to control whether the parameters of +a target can be updated or not -- you can modify the parameters of only +disabled targets (i.e. if "enabled" is 0). + +To update a target's parameters: + + cat enabled # check if enabled is 1 + echo 0 > enabled # disable the target (if required) + echo eth2 > dev_name # set local interface + echo 10.0.0.4 > remote_ip # update some parameter + echo cb:a9:87:65:43:21 > remote_mac # update more parameters + echo 1 > enabled # enable target again + +You can also update the local interface dynamically. This is especially +useful if you want to use interfaces that have newly come up (and may not +have existed when netconsole was loaded / initialized). + +Miscellaneous notes: +==================== + WARNING: the default target ethernet setting uses the broadcast ethernet address to send packets, which can cause increased load on other systems on the same ethernet segment. diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 40ff9a5269a2..10ed28ef3566 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -3082,6 +3082,16 @@ config NETCONSOLE If you want to log kernel messages over the network, enable this. See for details. +config NETCONSOLE_DYNAMIC + bool "Dynamic reconfiguration of logging targets (EXPERIMENTAL)" + depends on NETCONSOLE && SYSFS && EXPERIMENTAL + select CONFIGFS_FS + help + This option enables the ability to dynamically reconfigure target + parameters (interface, IP addresses, port numbers, MAC addresses) + at runtime through a userspace interface exported using configfs. + See for details. + config NETPOLL def_bool NETCONSOLE diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 458c4d674a9e..69ef1eb03bea 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include MODULE_AUTHOR("Maintainer: Matt Mackall "); MODULE_DESCRIPTION("Console driver for network interfaces"); @@ -71,20 +73,100 @@ static DEFINE_SPINLOCK(target_list_lock); /** * struct netconsole_target - Represents a configured netconsole target. * @list: Links this target into the target_list. + * @item: Links us into the configfs subsystem hierarchy. + * @enabled: On / off knob to enable / disable target. + * Visible from userspace (read-write). + * We maintain a strict 1:1 correspondence between this and + * whether the corresponding netpoll is active or inactive. + * Also, other parameters of a target may be modified at + * runtime only when it is disabled (enabled == 0). * @np: The netpoll structure for this target. + * Contains the other userspace visible parameters: + * dev_name (read-write) + * local_port (read-write) + * remote_port (read-write) + * local_ip (read-write) + * remote_ip (read-write) + * local_mac (read-only) + * remote_mac (read-write) */ struct netconsole_target { struct list_head list; +#ifdef CONFIG_NETCONSOLE_DYNAMIC + struct config_item item; +#endif + int enabled; struct netpoll np; }; -/* Allocate new target and setup netpoll for it */ -static struct netconsole_target *alloc_target(char *target_config) +#ifdef CONFIG_NETCONSOLE_DYNAMIC + +static struct configfs_subsystem netconsole_subsys; + +static int __init dynamic_netconsole_init(void) +{ + config_group_init(&netconsole_subsys.su_group); + mutex_init(&netconsole_subsys.su_mutex); + return configfs_register_subsystem(&netconsole_subsys); +} + +static void __exit dynamic_netconsole_exit(void) +{ + configfs_unregister_subsystem(&netconsole_subsys); +} + +/* + * Targets that were created by parsing the boot/module option string + * do not exist in the configfs hierarchy (and have NULL names) and will + * never go away, so make these a no-op for them. + */ +static void netconsole_target_get(struct netconsole_target *nt) +{ + if (config_item_name(&nt->item)) + config_item_get(&nt->item); +} + +static void netconsole_target_put(struct netconsole_target *nt) +{ + if (config_item_name(&nt->item)) + config_item_put(&nt->item); +} + +#else /* !CONFIG_NETCONSOLE_DYNAMIC */ + +static int __init dynamic_netconsole_init(void) +{ + return 0; +} + +static void __exit dynamic_netconsole_exit(void) +{ +} + +/* + * No danger of targets going away from under us when dynamic + * reconfigurability is off. + */ +static void netconsole_target_get(struct netconsole_target *nt) +{ +} + +static void netconsole_target_put(struct netconsole_target *nt) +{ +} + +#endif /* CONFIG_NETCONSOLE_DYNAMIC */ + +/* Allocate new target (from boot/module param) and setup netpoll for it */ +static struct netconsole_target *alloc_param_target(char *target_config) { int err = -ENOMEM; struct netconsole_target *nt; - /* Allocate and initialize with defaults */ + /* + * Allocate and initialize with defaults. + * Note that these targets get their config_item fields zeroed-out. + */ nt = kzalloc(sizeof(*nt), GFP_KERNEL); if (!nt) { printk(KERN_ERR "netconsole: failed to allocate memory\n"); @@ -106,6 +188,8 @@ static struct netconsole_target *alloc_target(char *target_config) if (err) goto fail; + nt->enabled = 1; + return nt; fail: @@ -113,13 +197,469 @@ fail: return ERR_PTR(err); } -/* Cleanup netpoll for given target and free it */ -static void free_target(struct netconsole_target *nt) +/* Cleanup netpoll for given target (from boot/module param) and free it */ +static void free_param_target(struct netconsole_target *nt) { netpoll_cleanup(&nt->np); kfree(nt); } +#ifdef CONFIG_NETCONSOLE_DYNAMIC + +/* + * Our subsystem hierarchy is: + * + * /sys/kernel/config/netconsole/ + * | + * / + * | enabled + * | dev_name + * | local_port + * | remote_port + * | local_ip + * | remote_ip + * | local_mac + * | remote_mac + * | + * /... + */ + +struct netconsole_target_attr { + struct configfs_attribute attr; + ssize_t (*show)(struct netconsole_target *nt, + char *buf); + ssize_t (*store)(struct netconsole_target *nt, + const char *buf, + size_t count); +}; + +static struct netconsole_target *to_target(struct config_item *item) +{ + return item ? + container_of(item, struct netconsole_target, item) : + NULL; +} + +/* + * Wrapper over simple_strtol (base 10) with sanity and range checking. + * We return (signed) long only because we may want to return errors. + * Do not use this to convert numbers that are allowed to be negative. + */ +static long strtol10_check_range(const char *cp, long min, long max) +{ + long ret; + char *p = (char *) cp; + + WARN_ON(min < 0); + WARN_ON(max < min); + + ret = simple_strtol(p, &p, 10); + + if (*p && (*p != '\n')) { + printk(KERN_ERR "netconsole: invalid input\n"); + return -EINVAL; + } + if ((ret < min) || (ret > max)) { + printk(KERN_ERR "netconsole: input %ld must be between " + "%ld and %ld\n", ret, min, max); + return -EINVAL; + } + + return ret; +} + +/* + * Attribute operations for netconsole_target. + */ + +static ssize_t show_enabled(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); +} + +static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name); +} + +static ssize_t show_local_port(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port); +} + +static ssize_t show_remote_port(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port); +} + +static ssize_t show_local_ip(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n", + HIPQUAD(nt->np.local_ip)); +} + +static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n", + HIPQUAD(nt->np.remote_ip)); +} + +static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", + nt->np.local_mac[0], nt->np.local_mac[1], + nt->np.local_mac[2], nt->np.local_mac[3], + nt->np.local_mac[4], nt->np.local_mac[5]); +} + +static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", + nt->np.remote_mac[0], nt->np.remote_mac[1], + nt->np.remote_mac[2], nt->np.remote_mac[3], + nt->np.remote_mac[4], nt->np.remote_mac[5]); +} + +/* + * This one is special -- targets created through the configfs interface + * are not enabled (and the corresponding netpoll activated) by default. + * The user is expected to set the desired parameters first (which + * would enable him to dynamically add new netpoll targets for new + * network interfaces as and when they come up). + */ +static ssize_t store_enabled(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + int err; + long enabled; + + enabled = strtol10_check_range(buf, 0, 1); + if (enabled < 0) + return enabled; + + if (enabled) { /* 1 */ + + /* + * Skip netpoll_parse_options() -- all the attributes are + * already configured via configfs. Just print them out. + */ + netpoll_print_options(&nt->np); + + err = netpoll_setup(&nt->np); + if (err) + return err; + + printk(KERN_INFO "netconsole: network logging started\n"); + + } else { /* 0 */ + netpoll_cleanup(&nt->np); + } + + nt->enabled = enabled; + + return strnlen(buf, count); +} + +static ssize_t store_dev_name(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + size_t len; + + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + strlcpy(nt->np.dev_name, buf, IFNAMSIZ); + + /* Get rid of possible trailing newline from echo(1) */ + len = strnlen(nt->np.dev_name, IFNAMSIZ); + if (nt->np.dev_name[len - 1] == '\n') + nt->np.dev_name[len - 1] = '\0'; + + return strnlen(buf, count); +} + +static ssize_t store_local_port(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + long local_port; +#define __U16_MAX ((__u16) ~0U) + + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + local_port = strtol10_check_range(buf, 0, __U16_MAX); + if (local_port < 0) + return local_port; + + nt->np.local_port = local_port; + + return strnlen(buf, count); +} + +static ssize_t store_remote_port(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + long remote_port; +#define __U16_MAX ((__u16) ~0U) + + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + remote_port = strtol10_check_range(buf, 0, __U16_MAX); + if (remote_port < 0) + return remote_port; + + nt->np.remote_port = remote_port; + + return strnlen(buf, count); +} + +static ssize_t store_local_ip(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + nt->np.local_ip = ntohl(in_aton(buf)); + + return strnlen(buf, count); +} + +static ssize_t store_remote_ip(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + nt->np.remote_ip = ntohl(in_aton(buf)); + + return strnlen(buf, count); +} + +static ssize_t store_remote_mac(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + u8 remote_mac[ETH_ALEN]; + char *p = (char *) buf; + int i; + + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + for (i = 0; i < ETH_ALEN - 1; i++) { + remote_mac[i] = simple_strtoul(p, &p, 16); + if (*p != ':') + goto invalid; + p++; + } + remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16); + if (*p && (*p != '\n')) + goto invalid; + + memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); + + return strnlen(buf, count); + +invalid: + printk(KERN_ERR "netconsole: invalid input\n"); + return -EINVAL; +} + +/* + * Attribute definitions for netconsole_target. + */ + +#define NETCONSOLE_TARGET_ATTR_RO(_name) \ +static struct netconsole_target_attr netconsole_target_##_name = \ + __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL) + +#define NETCONSOLE_TARGET_ATTR_RW(_name) \ +static struct netconsole_target_attr netconsole_target_##_name = \ + __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name) + +NETCONSOLE_TARGET_ATTR_RW(enabled); +NETCONSOLE_TARGET_ATTR_RW(dev_name); +NETCONSOLE_TARGET_ATTR_RW(local_port); +NETCONSOLE_TARGET_ATTR_RW(remote_port); +NETCONSOLE_TARGET_ATTR_RW(local_ip); +NETCONSOLE_TARGET_ATTR_RW(remote_ip); +NETCONSOLE_TARGET_ATTR_RO(local_mac); +NETCONSOLE_TARGET_ATTR_RW(remote_mac); + +static struct configfs_attribute *netconsole_target_attrs[] = { + &netconsole_target_enabled.attr, + &netconsole_target_dev_name.attr, + &netconsole_target_local_port.attr, + &netconsole_target_remote_port.attr, + &netconsole_target_local_ip.attr, + &netconsole_target_remote_ip.attr, + &netconsole_target_local_mac.attr, + &netconsole_target_remote_mac.attr, + NULL, +}; + +/* + * Item operations and type for netconsole_target. + */ + +static void netconsole_target_release(struct config_item *item) +{ + kfree(to_target(item)); +} + +static ssize_t netconsole_target_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *buf) +{ + ssize_t ret = -EINVAL; + struct netconsole_target *nt = to_target(item); + struct netconsole_target_attr *na = + container_of(attr, struct netconsole_target_attr, attr); + + if (na->show) + ret = na->show(nt, buf); + + return ret; +} + +static ssize_t netconsole_target_attr_store(struct config_item *item, + struct configfs_attribute *attr, + const char *buf, + size_t count) +{ + ssize_t ret = -EINVAL; + struct netconsole_target *nt = to_target(item); + struct netconsole_target_attr *na = + container_of(attr, struct netconsole_target_attr, attr); + + if (na->store) + ret = na->store(nt, buf, count); + + return ret; +} + +static struct configfs_item_operations netconsole_target_item_ops = { + .release = netconsole_target_release, + .show_attribute = netconsole_target_attr_show, + .store_attribute = netconsole_target_attr_store, +}; + +static struct config_item_type netconsole_target_type = { + .ct_attrs = netconsole_target_attrs, + .ct_item_ops = &netconsole_target_item_ops, + .ct_owner = THIS_MODULE, +}; + +/* + * Group operations and type for netconsole_subsys. + */ + +static struct config_item *make_netconsole_target(struct config_group *group, + const char *name) +{ + unsigned long flags; + struct netconsole_target *nt; + + /* + * Allocate and initialize with defaults. + * Target is disabled at creation (enabled == 0). + */ + nt = kzalloc(sizeof(*nt), GFP_KERNEL); + if (!nt) { + printk(KERN_ERR "netconsole: failed to allocate memory\n"); + return NULL; + } + + nt->np.name = "netconsole"; + strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); + nt->np.local_port = 6665; + nt->np.remote_port = 6666; + memset(nt->np.remote_mac, 0xff, ETH_ALEN); + + /* Initialize the config_item member */ + config_item_init_type_name(&nt->item, name, &netconsole_target_type); + + /* Adding, but it is disabled */ + spin_lock_irqsave(&target_list_lock, flags); + list_add(&nt->list, &target_list); + spin_unlock_irqrestore(&target_list_lock, flags); + + return &nt->item; +} + +static void drop_netconsole_target(struct config_group *group, + struct config_item *item) +{ + unsigned long flags; + struct netconsole_target *nt = to_target(item); + + spin_lock_irqsave(&target_list_lock, flags); + list_del(&nt->list); + spin_unlock_irqrestore(&target_list_lock, flags); + + /* + * The target may have never been enabled, or was manually disabled + * before being removed so netpoll may have already been cleaned up. + */ + if (nt->enabled) + netpoll_cleanup(&nt->np); + + config_item_put(&nt->item); +} + +static struct configfs_group_operations netconsole_subsys_group_ops = { + .make_item = make_netconsole_target, + .drop_item = drop_netconsole_target, +}; + +static struct config_item_type netconsole_subsys_type = { + .ct_group_ops = &netconsole_subsys_group_ops, + .ct_owner = THIS_MODULE, +}; + +/* The netconsole configfs subsystem */ +static struct configfs_subsystem netconsole_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "netconsole", + .ci_type = &netconsole_subsys_type, + }, + }, +}; + +#endif /* CONFIG_NETCONSOLE_DYNAMIC */ + /* Handle network interface device notifications */ static int netconsole_netdev_event(struct notifier_block *this, unsigned long event, @@ -134,6 +674,7 @@ static int netconsole_netdev_event(struct notifier_block *this, spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { + netconsole_target_get(nt); if (nt->np.dev == dev) { switch (event) { case NETDEV_CHANGEADDR: @@ -145,6 +686,7 @@ static int netconsole_netdev_event(struct notifier_block *this, break; } } + netconsole_target_put(nt); } spin_unlock_irqrestore(&target_list_lock, flags); @@ -169,7 +711,8 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { - if (netif_running(nt->np.dev)) { + netconsole_target_get(nt); + if (nt->enabled && netif_running(nt->np.dev)) { /* * We nest this inside the for-each-target loop above * so that we're able to get as much logging out to @@ -184,6 +727,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) left -= frag; } } + netconsole_target_put(nt); } spin_unlock_irqrestore(&target_list_lock, flags); } @@ -196,48 +740,52 @@ static struct console netconsole = { static int __init init_netconsole(void) { - int err = 0; + int err; struct netconsole_target *nt, *tmp; unsigned long flags; char *target_config; char *input = config; - if (!strnlen(input, MAX_PARAM_LENGTH)) { - printk(KERN_INFO "netconsole: not configured, aborting\n"); - goto out; - } - - while ((target_config = strsep(&input, ";"))) { - nt = alloc_target(target_config); - if (IS_ERR(nt)) { - err = PTR_ERR(nt); - goto fail; + if (strnlen(input, MAX_PARAM_LENGTH)) { + while ((target_config = strsep(&input, ";"))) { + nt = alloc_param_target(target_config); + if (IS_ERR(nt)) { + err = PTR_ERR(nt); + goto fail; + } + spin_lock_irqsave(&target_list_lock, flags); + list_add(&nt->list, &target_list); + spin_unlock_irqrestore(&target_list_lock, flags); } - spin_lock_irqsave(&target_list_lock, flags); - list_add(&nt->list, &target_list); - spin_unlock_irqrestore(&target_list_lock, flags); } err = register_netdevice_notifier(&netconsole_netdev_notifier); if (err) goto fail; + err = dynamic_netconsole_init(); + if (err) + goto undonotifier; + register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); -out: return err; +undonotifier: + unregister_netdevice_notifier(&netconsole_netdev_notifier); + fail: printk(KERN_ERR "netconsole: cleaning up\n"); /* - * Remove all targets and destroy them. Skipping the list + * Remove all targets and destroy them (only targets created + * from the boot/module option exist here). Skipping the list * lock is safe here, and netpoll_cleanup() will sleep. */ list_for_each_entry_safe(nt, tmp, &target_list, list) { list_del(&nt->list); - free_target(nt); + free_param_target(nt); } return err; @@ -248,15 +796,20 @@ static void __exit cleanup_netconsole(void) struct netconsole_target *nt, *tmp; unregister_console(&netconsole); + dynamic_netconsole_exit(); unregister_netdevice_notifier(&netconsole_netdev_notifier); /* - * Remove all targets and destroy them. Skipping the list - * lock is safe here, and netpoll_cleanup() will sleep. + * Targets created via configfs pin references on our module + * and would first be rmdir(2)'ed from userspace. We reach + * here only when they are already destroyed, and only those + * created from the boot/module option are left, so remove and + * destroy them. Skipping the list lock is safe here, and + * netpoll_cleanup() will sleep. */ list_for_each_entry_safe(nt, tmp, &target_list, list) { list_del(&nt->list); - free_target(nt); + free_param_target(nt); } } diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 08dcc39ec18d..20250d963d72 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -35,6 +35,7 @@ struct netpoll_info { void netpoll_poll(struct netpoll *np); void netpoll_send_udp(struct netpoll *np, const char *msg, int len); +void netpoll_print_options(struct netpoll *np); int netpoll_parse_options(struct netpoll *np, char *opt); int netpoll_setup(struct netpoll *np); int netpoll_trap(void); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index abe6e3a4cc44..0952f936b292 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -532,6 +532,29 @@ out: return 0; } +void netpoll_print_options(struct netpoll *np) +{ + printk(KERN_INFO "%s: local port %d\n", + np->name, np->local_port); + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + printk(KERN_INFO "%s: interface %s\n", + np->name, np->dev_name); + printk(KERN_INFO "%s: remote port %d\n", + np->name, np->remote_port); + printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->remote_ip)); + printk(KERN_INFO "%s: remote ethernet address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + np->name, + np->remote_mac[0], + np->remote_mac[1], + np->remote_mac[2], + np->remote_mac[3], + np->remote_mac[4], + np->remote_mac[5]); +} + int netpoll_parse_options(struct netpoll *np, char *opt) { char *cur=opt, *delim; @@ -544,7 +567,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) cur = delim; } cur++; - printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); if (*cur != '/') { if ((delim = strchr(cur, '/')) == NULL) @@ -552,9 +574,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) *delim = 0; np->local_ip = ntohl(in_aton(cur)); cur = delim; - - printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", - np->name, HIPQUAD(np->local_ip)); } cur++; @@ -568,8 +587,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) } cur++; - printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name); - if (*cur != '@') { /* dst port */ if ((delim = strchr(cur, '@')) == NULL) @@ -579,7 +596,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) cur = delim; } cur++; - printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); /* dst ip */ if ((delim = strchr(cur, '/')) == NULL) @@ -588,9 +604,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) np->remote_ip = ntohl(in_aton(cur)); cur = delim + 1; - printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", - np->name, HIPQUAD(np->remote_ip)); - if (*cur != 0) { /* MAC address */ if ((delim = strchr(cur, ':')) == NULL) @@ -621,15 +634,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) np->remote_mac[5] = simple_strtol(cur, NULL, 16); } - printk(KERN_INFO "%s: remote ethernet address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - np->name, - np->remote_mac[0], - np->remote_mac[1], - np->remote_mac[2], - np->remote_mac[3], - np->remote_mac[4], - np->remote_mac[5]); + netpoll_print_options(np); return 0; @@ -831,6 +836,7 @@ void netpoll_set_trap(int trap) EXPORT_SYMBOL(netpoll_set_trap); EXPORT_SYMBOL(netpoll_trap); +EXPORT_SYMBOL(netpoll_print_options); EXPORT_SYMBOL(netpoll_parse_options); EXPORT_SYMBOL(netpoll_setup); EXPORT_SYMBOL(netpoll_cleanup); From 3ae7c0b2e3747b50c3a6c63ebb67469e0a6b3203 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 15 Aug 2007 16:00:51 -0700 Subject: [PATCH 1071/2804] [ETHTOOL]: Add ETHTOOL_[GS]FLAGS sub-ioctls Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- include/linux/ethtool.h | 21 ++++++++++++++ include/linux/netdevice.h | 1 + net/core/ethtool.c | 61 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 23ccea811297..0e5de2fb960c 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -256,6 +256,19 @@ struct ethtool_perm_addr { __u8 data[0]; }; +/* boolean flags controlling per-interface behavior characteristics. + * When reading, the flag indicates whether or not a certain behavior + * is enabled/present. When writing, the flag indicates whether + * or not the driver should turn on (set) or off (clear) a behavior. + * + * Some behaviors may read-only (unconditionally absent or present). + * If such is the case, return EINVAL in the set-flags operation if the + * flag differs from the read-only value. + */ +enum ethtool_flags { + ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */ +}; + #ifdef __KERNEL__ struct net_device; @@ -272,6 +285,8 @@ u32 ethtool_op_get_tso(struct net_device *dev); int ethtool_op_set_tso(struct net_device *dev, u32 data); u32 ethtool_op_get_ufo(struct net_device *dev); int ethtool_op_set_ufo(struct net_device *dev, u32 data); +u32 ethtool_op_get_flags(struct net_device *dev); +int ethtool_op_set_flags(struct net_device *dev, u32 data); /** * ðtool_ops - Alter and report network device settings @@ -307,6 +322,8 @@ int ethtool_op_set_ufo(struct net_device *dev, u32 data); * get_strings: Return a set of strings that describe the requested objects * phys_id: Identify the device * get_stats: Return statistics about the device + * get_flags: get 32-bit flags bitmap + * set_flags: set 32-bit flags bitmap * * Description: * @@ -369,6 +386,8 @@ struct ethtool_ops { void (*complete)(struct net_device *); u32 (*get_ufo)(struct net_device *); int (*set_ufo)(struct net_device *, u32); + u32 (*get_flags)(struct net_device *); + int (*set_flags)(struct net_device *, u32); }; #endif /* __KERNEL__ */ @@ -410,6 +429,8 @@ struct ethtool_ops { #define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ #define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */ #define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */ +#define ETHTOOL_GFLAGS 0x00000025 /* Get flags bitmap(ethtool_value) */ +#define ETHTOOL_SFLAGS 0x00000026 /* Set flags bitmap(ethtool_value) */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b93575db8cce..8f00bdf95ef4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -449,6 +449,7 @@ struct net_device #define NETIF_F_GSO 2048 /* Enable software GSO. */ #define NETIF_F_LLTX 4096 /* LockLess TX */ #define NETIF_F_MULTI_QUEUE 16384 /* Has multiple TX/RX queues */ +#define NETIF_F_LRO 32768 /* large receive offload */ /* Segmentation offload features */ #define NETIF_F_GSO_SHIFT 16 diff --git a/net/core/ethtool.c b/net/core/ethtool.c index c5e059352d43..6f8b78bcfd84 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -109,6 +109,32 @@ int ethtool_op_set_ufo(struct net_device *dev, u32 data) return 0; } +/* the following list of flags are the same as their associated + * NETIF_F_xxx values in include/linux/netdevice.h + */ +static const u32 flags_dup_features = + ETH_FLAG_LRO; + +u32 ethtool_op_get_flags(struct net_device *dev) +{ + /* in the future, this function will probably contain additional + * handling for flags which are not so easily handled + * by a simple masking operation + */ + + return dev->features & flags_dup_features; +} + +int ethtool_op_set_flags(struct net_device *dev, u32 data) +{ + if (data & ETH_FLAG_LRO) + dev->features |= NETIF_F_LRO; + else + dev->features &= ~NETIF_F_LRO; + + return 0; +} + /* Handlers for each ethtool command */ static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) @@ -783,6 +809,33 @@ static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) return 0; } +static int ethtool_get_flags(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GFLAGS }; + + if (!dev->ethtool_ops->get_flags) + return -EOPNOTSUPP; + + edata.data = dev->ethtool_ops->get_flags(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_flags(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata; + + if (!dev->ethtool_ops->set_flags) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + return dev->ethtool_ops->set_flags(dev, edata.data); +} + /* The main entry point in this file. Called from net/core/dev.c */ int dev_ethtool(struct ifreq *ifr) @@ -935,6 +988,12 @@ int dev_ethtool(struct ifreq *ifr) case ETHTOOL_SGSO: rc = ethtool_set_gso(dev, useraddr); break; + case ETHTOOL_GFLAGS: + rc = ethtool_get_flags(dev, useraddr); + break; + case ETHTOOL_SFLAGS: + rc = ethtool_set_flags(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } @@ -959,3 +1018,5 @@ EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum); EXPORT_SYMBOL(ethtool_op_set_ufo); EXPORT_SYMBOL(ethtool_op_get_ufo); +EXPORT_SYMBOL(ethtool_op_set_flags); +EXPORT_SYMBOL(ethtool_op_get_flags); From ff03d49f0ca1959246068b315d26e009da692ff2 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 15 Aug 2007 16:01:08 -0700 Subject: [PATCH 1072/2804] [ETHTOOL]: Introduce get_sset_count. Obsolete get_stats_count, self_test_count Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- include/linux/ethtool.h | 7 ++- net/core/ethtool.c | 95 ++++++++++++++++++++++++++++++----------- 2 files changed, 75 insertions(+), 27 deletions(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 0e5de2fb960c..f617998b87f1 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -376,11 +376,9 @@ struct ethtool_ops { int (*set_sg)(struct net_device *, u32); u32 (*get_tso)(struct net_device *); int (*set_tso)(struct net_device *, u32); - int (*self_test_count)(struct net_device *); void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); void (*get_strings)(struct net_device *, u32 stringset, u8 *); int (*phys_id)(struct net_device *, u32); - int (*get_stats_count)(struct net_device *); void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); int (*begin)(struct net_device *); void (*complete)(struct net_device *); @@ -388,6 +386,11 @@ struct ethtool_ops { int (*set_ufo)(struct net_device *, u32); u32 (*get_flags)(struct net_device *); int (*set_flags)(struct net_device *, u32); + int (*get_sset_count)(struct net_device *, int); + + /* the following hooks are obsolete */ + int (*self_test_count)(struct net_device *);/* use get_sset_count */ + int (*get_stats_count)(struct net_device *);/* use get_sset_count */ }; #endif /* __KERNEL__ */ diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 6f8b78bcfd84..1edae460d616 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -179,10 +179,23 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) info.cmd = ETHTOOL_GDRVINFO; ops->get_drvinfo(dev, &info); - if (ops->self_test_count) - info.testinfo_len = ops->self_test_count(dev); - if (ops->get_stats_count) - info.n_stats = ops->get_stats_count(dev); + if (ops->get_sset_count) { + int rc; + + rc = ops->get_sset_count(dev, ETH_SS_TEST); + if (rc >= 0) + info.testinfo_len = rc; + rc = ops->get_sset_count(dev, ETH_SS_STATS); + if (rc >= 0) + info.n_stats = rc; + } else { + /* code path for obsolete hooks */ + + if (ops->self_test_count) + info.testinfo_len = ops->self_test_count(dev); + if (ops->get_stats_count) + info.n_stats = ops->get_stats_count(dev); + } if (ops->get_regs_len) info.regdump_len = ops->get_regs_len(dev); if (ops->get_eeprom_len) @@ -669,16 +682,27 @@ static int ethtool_self_test(struct net_device *dev, char __user *useraddr) struct ethtool_test test; const struct ethtool_ops *ops = dev->ethtool_ops; u64 *data; - int ret; + int ret, test_len; - if (!ops->self_test || !ops->self_test_count) + if (!ops->self_test) return -EOPNOTSUPP; + if (!ops->get_sset_count && !ops->self_test_count) + return -EOPNOTSUPP; + + if (ops->get_sset_count) + test_len = ops->get_sset_count(dev, ETH_SS_TEST); + else + /* code path for obsolete hook */ + test_len = ops->self_test_count(dev); + if (test_len < 0) + return test_len; + WARN_ON(test_len == 0); if (copy_from_user(&test, useraddr, sizeof(test))) return -EFAULT; - test.len = ops->self_test_count(dev); - data = kmalloc(test.len * sizeof(u64), GFP_USER); + test.len = test_len; + data = kmalloc(test_len * sizeof(u64), GFP_USER); if (!data) return -ENOMEM; @@ -710,19 +734,29 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) return -EFAULT; - switch (gstrings.string_set) { - case ETH_SS_TEST: - if (!ops->self_test_count) - return -EOPNOTSUPP; - gstrings.len = ops->self_test_count(dev); - break; - case ETH_SS_STATS: - if (!ops->get_stats_count) - return -EOPNOTSUPP; - gstrings.len = ops->get_stats_count(dev); - break; - default: - return -EINVAL; + if (ops->get_sset_count) { + ret = ops->get_sset_count(dev, gstrings.string_set); + if (ret < 0) + return ret; + + gstrings.len = ret; + } else { + /* code path for obsolete hooks */ + + switch (gstrings.string_set) { + case ETH_SS_TEST: + if (!ops->self_test_count) + return -EOPNOTSUPP; + gstrings.len = ops->self_test_count(dev); + break; + case ETH_SS_STATS: + if (!ops->get_stats_count) + return -EOPNOTSUPP; + gstrings.len = ops->get_stats_count(dev); + break; + default: + return -EINVAL; + } } data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); @@ -762,16 +796,27 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) struct ethtool_stats stats; const struct ethtool_ops *ops = dev->ethtool_ops; u64 *data; - int ret; + int ret, n_stats; - if (!ops->get_ethtool_stats || !ops->get_stats_count) + if (!ops->get_ethtool_stats) return -EOPNOTSUPP; + if (!ops->get_sset_count && !ops->get_stats_count) + return -EOPNOTSUPP; + + if (ops->get_sset_count) + n_stats = ops->get_sset_count(dev, ETH_SS_STATS); + else + /* code path for obsolete hook */ + n_stats = ops->get_stats_count(dev); + if (n_stats < 0) + return n_stats; + WARN_ON(n_stats == 0); if (copy_from_user(&stats, useraddr, sizeof(stats))) return -EFAULT; - stats.n_stats = ops->get_stats_count(dev); - data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER); + stats.n_stats = n_stats; + data = kmalloc(n_stats * sizeof(u64), GFP_USER); if (!data) return -ENOMEM; From 339bf024756690949f536777b921f34186eaa8b4 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 15 Aug 2007 16:01:32 -0700 Subject: [PATCH 1073/2804] [ETHTOOL]: Introduce ->{get,set}_priv_flags, ETHTOOL_[GS]PFLAGS Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- include/linux/ethtool.h | 8 +++++++- net/core/ethtool.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index f617998b87f1..71d4ada6f315 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -39,7 +39,8 @@ struct ethtool_drvinfo { char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ /* For PCI devices, use pci_name(pci_dev). */ char reserved1[32]; - char reserved2[16]; + char reserved2[12]; + __u32 n_priv_flags; /* number of flags valid in ETHTOOL_GPFLAGS */ __u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */ __u32 testinfo_len; __u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ @@ -219,6 +220,7 @@ struct ethtool_pauseparam { enum ethtool_stringset { ETH_SS_TEST = 0, ETH_SS_STATS, + ETH_SS_PRIV_FLAGS, }; /* for passing string sets for data tagging */ @@ -386,6 +388,8 @@ struct ethtool_ops { int (*set_ufo)(struct net_device *, u32); u32 (*get_flags)(struct net_device *); int (*set_flags)(struct net_device *, u32); + u32 (*get_priv_flags)(struct net_device *); + int (*set_priv_flags)(struct net_device *, u32); int (*get_sset_count)(struct net_device *, int); /* the following hooks are obsolete */ @@ -434,6 +438,8 @@ struct ethtool_ops { #define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */ #define ETHTOOL_GFLAGS 0x00000025 /* Get flags bitmap(ethtool_value) */ #define ETHTOOL_SFLAGS 0x00000026 /* Set flags bitmap(ethtool_value) */ +#define ETHTOOL_GPFLAGS 0x00000027 /* Get driver-private flags bitmap */ +#define ETHTOOL_SPFLAGS 0x00000028 /* Set driver-private flags bitmap */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 1edae460d616..d255209dc110 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -188,6 +188,9 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) rc = ops->get_sset_count(dev, ETH_SS_STATS); if (rc >= 0) info.n_stats = rc; + rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS); + if (rc >= 0) + info.n_priv_flags = rc; } else { /* code path for obsolete hooks */ @@ -881,6 +884,33 @@ static int ethtool_set_flags(struct net_device *dev, char __user *useraddr) return dev->ethtool_ops->set_flags(dev, edata.data); } +static int ethtool_get_priv_flags(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GPFLAGS }; + + if (!dev->ethtool_ops->get_priv_flags) + return -EOPNOTSUPP; + + edata.data = dev->ethtool_ops->get_priv_flags(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_priv_flags(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata; + + if (!dev->ethtool_ops->set_priv_flags) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + return dev->ethtool_ops->set_priv_flags(dev, edata.data); +} + /* The main entry point in this file. Called from net/core/dev.c */ int dev_ethtool(struct ifreq *ifr) @@ -915,6 +945,8 @@ int dev_ethtool(struct ifreq *ifr) case ETHTOOL_GPERMADDR: case ETHTOOL_GUFO: case ETHTOOL_GGSO: + case ETHTOOL_GFLAGS: + case ETHTOOL_GPFLAGS: break; default: if (!capable(CAP_NET_ADMIN)) @@ -1039,6 +1071,12 @@ int dev_ethtool(struct ifreq *ifr) case ETHTOOL_SFLAGS: rc = ethtool_set_flags(dev, useraddr); break; + case ETHTOOL_GPFLAGS: + rc = ethtool_get_priv_flags(dev, useraddr); + break; + case ETHTOOL_SPFLAGS: + rc = ethtool_set_priv_flags(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } From 13c99b248f06e0b71d925f162d8e3b0084886a21 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 15 Aug 2007 16:01:56 -0700 Subject: [PATCH 1074/2804] [ETHTOOL]: Internal cleanup of ethtool_value-related handlers Several get/set functions can be handled by a passing the ethtool_op function pointer directly to a generic function. This permits deletion of a fair bit of redundant code. Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- net/core/ethtool.c | 199 +++++++++------------------------------------ 1 file changed, 39 insertions(+), 160 deletions(-) diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d255209dc110..7c43f032a7f9 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -272,34 +272,6 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) return dev->ethtool_ops->set_wol(dev, &wol); } -static int ethtool_get_msglevel(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GMSGLVL }; - - if (!dev->ethtool_ops->get_msglevel) - return -EOPNOTSUPP; - - edata.data = dev->ethtool_ops->get_msglevel(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - -static int ethtool_set_msglevel(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - - if (!dev->ethtool_ops->set_msglevel) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - dev->ethtool_ops->set_msglevel(dev, edata.data); - return 0; -} - static int ethtool_nway_reset(struct net_device *dev) { if (!dev->ethtool_ops->nway_reset) @@ -308,20 +280,6 @@ static int ethtool_nway_reset(struct net_device *dev) return dev->ethtool_ops->nway_reset(dev); } -static int ethtool_get_link(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GLINK }; - - if (!dev->ethtool_ops->get_link) - return -EOPNOTSUPP; - - edata.data = dev->ethtool_ops->get_link(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) { struct ethtool_eeprom eeprom; @@ -489,48 +447,6 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr) return dev->ethtool_ops->set_pauseparam(dev, &pauseparam); } -static int ethtool_get_rx_csum(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GRXCSUM }; - - if (!dev->ethtool_ops->get_rx_csum) - return -EOPNOTSUPP; - - edata.data = dev->ethtool_ops->get_rx_csum(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - -static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - - if (!dev->ethtool_ops->set_rx_csum) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - dev->ethtool_ops->set_rx_csum(dev, edata.data); - return 0; -} - -static int ethtool_get_tx_csum(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GTXCSUM }; - - if (!dev->ethtool_ops->get_tx_csum) - return -EOPNOTSUPP; - - edata.data = dev->ethtool_ops->get_tx_csum(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - static int __ethtool_set_sg(struct net_device *dev, u32 data) { int err; @@ -569,20 +485,6 @@ static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr) return dev->ethtool_ops->set_tx_csum(dev, edata.data); } -static int ethtool_get_sg(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GSG }; - - if (!dev->ethtool_ops->get_sg) - return -EOPNOTSUPP; - - edata.data = dev->ethtool_ops->get_sg(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - static int ethtool_set_sg(struct net_device *dev, char __user *useraddr) { struct ethtool_value edata; @@ -600,20 +502,6 @@ static int ethtool_set_sg(struct net_device *dev, char __user *useraddr) return __ethtool_set_sg(dev, edata.data); } -static int ethtool_get_tso(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GTSO }; - - if (!dev->ethtool_ops->get_tso) - return -EOPNOTSUPP; - - edata.data = dev->ethtool_ops->get_tso(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - static int ethtool_set_tso(struct net_device *dev, char __user *useraddr) { struct ethtool_value edata; @@ -630,18 +518,6 @@ static int ethtool_set_tso(struct net_device *dev, char __user *useraddr) return dev->ethtool_ops->set_tso(dev, edata.data); } -static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GUFO }; - - if (!dev->ethtool_ops->get_ufo) - return -EOPNOTSUPP; - edata.data = dev->ethtool_ops->get_ufo(dev); - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) { struct ethtool_value edata; @@ -857,58 +733,48 @@ static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) return 0; } -static int ethtool_get_flags(struct net_device *dev, char __user *useraddr) +static int ethtool_get_value(struct net_device *dev, char __user *useraddr, + u32 cmd, u32 (*actor)(struct net_device *)) { - struct ethtool_value edata = { ETHTOOL_GFLAGS }; + struct ethtool_value edata = { cmd }; - if (!dev->ethtool_ops->get_flags) + if (!actor) return -EOPNOTSUPP; - edata.data = dev->ethtool_ops->get_flags(dev); + edata.data = actor(dev); if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } -static int ethtool_set_flags(struct net_device *dev, char __user *useraddr) +static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr, + void (*actor)(struct net_device *, u32)) { struct ethtool_value edata; - if (!dev->ethtool_ops->set_flags) + if (!actor) return -EOPNOTSUPP; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; - return dev->ethtool_ops->set_flags(dev, edata.data); -} - -static int ethtool_get_priv_flags(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GPFLAGS }; - - if (!dev->ethtool_ops->get_priv_flags) - return -EOPNOTSUPP; - - edata.data = dev->ethtool_ops->get_priv_flags(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; + actor(dev, edata.data); return 0; } -static int ethtool_set_priv_flags(struct net_device *dev, char __user *useraddr) +static int ethtool_set_value(struct net_device *dev, char __user *useraddr, + int (*actor)(struct net_device *, u32)) { struct ethtool_value edata; - if (!dev->ethtool_ops->set_priv_flags) + if (!actor) return -EOPNOTSUPP; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; - return dev->ethtool_ops->set_priv_flags(dev, edata.data); + return actor(dev, edata.data); } /* The main entry point in this file. Called from net/core/dev.c */ @@ -979,16 +845,19 @@ int dev_ethtool(struct ifreq *ifr) rc = ethtool_set_wol(dev, useraddr); break; case ETHTOOL_GMSGLVL: - rc = ethtool_get_msglevel(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_msglevel); break; case ETHTOOL_SMSGLVL: - rc = ethtool_set_msglevel(dev, useraddr); + rc = ethtool_set_value_void(dev, useraddr, + dev->ethtool_ops->set_msglevel); break; case ETHTOOL_NWAY_RST: rc = ethtool_nway_reset(dev); break; case ETHTOOL_GLINK: - rc = ethtool_get_link(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_link); break; case ETHTOOL_GEEPROM: rc = ethtool_get_eeprom(dev, useraddr); @@ -1015,25 +884,30 @@ int dev_ethtool(struct ifreq *ifr) rc = ethtool_set_pauseparam(dev, useraddr); break; case ETHTOOL_GRXCSUM: - rc = ethtool_get_rx_csum(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_rx_csum); break; case ETHTOOL_SRXCSUM: - rc = ethtool_set_rx_csum(dev, useraddr); + rc = ethtool_set_value(dev, useraddr, + dev->ethtool_ops->set_rx_csum); break; case ETHTOOL_GTXCSUM: - rc = ethtool_get_tx_csum(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_tx_csum); break; case ETHTOOL_STXCSUM: rc = ethtool_set_tx_csum(dev, useraddr); break; case ETHTOOL_GSG: - rc = ethtool_get_sg(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_sg); break; case ETHTOOL_SSG: rc = ethtool_set_sg(dev, useraddr); break; case ETHTOOL_GTSO: - rc = ethtool_get_tso(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_tso); break; case ETHTOOL_STSO: rc = ethtool_set_tso(dev, useraddr); @@ -1054,7 +928,8 @@ int dev_ethtool(struct ifreq *ifr) rc = ethtool_get_perm_addr(dev, useraddr); break; case ETHTOOL_GUFO: - rc = ethtool_get_ufo(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_ufo); break; case ETHTOOL_SUFO: rc = ethtool_set_ufo(dev, useraddr); @@ -1066,16 +941,20 @@ int dev_ethtool(struct ifreq *ifr) rc = ethtool_set_gso(dev, useraddr); break; case ETHTOOL_GFLAGS: - rc = ethtool_get_flags(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_flags); break; case ETHTOOL_SFLAGS: - rc = ethtool_set_flags(dev, useraddr); + rc = ethtool_set_value(dev, useraddr, + dev->ethtool_ops->set_flags); break; case ETHTOOL_GPFLAGS: - rc = ethtool_get_priv_flags(dev, useraddr); + rc = ethtool_get_value(dev, useraddr, ethcmd, + dev->ethtool_ops->get_priv_flags); break; case ETHTOOL_SPFLAGS: - rc = ethtool_set_priv_flags(dev, useraddr); + rc = ethtool_set_value(dev, useraddr, + dev->ethtool_ops->set_priv_flags); break; default: rc = -EOPNOTSUPP; From 4d93df0abd50b9c9e2d4561439a1a1d21ec5e68f Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 15 Aug 2007 16:07:44 -0700 Subject: [PATCH 1075/2804] [SCTP]: Rewrite of sctp buffer management code This patch introduces autotuning to the sctp buffer management code similar to the TCP. The buffer space can be grown if the advertised receive window still has room. This might happen if small message sizes are used, which is common in telecom environmens. New tunables are introduced that provide limits to buffer growth and memory pressure is entered if to much buffer spaces is used. Signed-off-by: Neil Horman Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 5 +++ net/sctp/endpointola.c | 1 + net/sctp/protocol.c | 32 ++++++++++++++++++ net/sctp/sm_statefuns.c | 72 ++++++++++------------------------------- net/sctp/socket.c | 69 ++++++++++++++++++++++++++++++++------- net/sctp/sysctl.c | 33 +++++++++++++++++++ net/sctp/ulpevent.c | 18 +++++++++++ net/sctp/ulpqueue.c | 1 + 8 files changed, 164 insertions(+), 67 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index c9cc00c85782..d5a1ddc7483f 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -469,6 +469,11 @@ static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) skb->sk = sk; skb->destructor = sctp_sock_rfree; atomic_add(event->rmem_len, &sk->sk_rmem_alloc); + /* + * This mimics the behavior of + * sk_stream_set_owner_r + */ + sk->sk_forward_alloc -= event->rmem_len; } /* Tests if the list has one and only one entry. */ diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 8f485a0d14bd..22371185efb6 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -102,6 +102,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, /* Use SCTP specific send buffer space queues. */ ep->sndbuf_policy = sctp_sndbuf_policy; + sk->sk_write_space = sctp_write_space; sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 3d036cdfae41..957c118a6068 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,10 @@ static struct sctp_af *sctp_af_v6_specific; struct kmem_cache *sctp_chunk_cachep __read_mostly; struct kmem_cache *sctp_bucket_cachep __read_mostly; +extern int sysctl_sctp_mem[3]; +extern int sysctl_sctp_rmem[3]; +extern int sysctl_sctp_wmem[3]; + /* Return the address of the control sock. */ struct sock *sctp_get_ctl_sock(void) { @@ -987,6 +992,8 @@ SCTP_STATIC __init int sctp_init(void) int i; int status = -EINVAL; unsigned long goal; + unsigned long limit; + int max_share; int order; /* SCTP_DEBUG sanity check. */ @@ -1077,6 +1084,31 @@ SCTP_STATIC __init int sctp_init(void) /* Initialize handle used for association ids. */ idr_init(&sctp_assocs_id); + /* Set the pressure threshold to be a fraction of global memory that + * is up to 1/2 at 256 MB, decreasing toward zero with the amount of + * memory, with a floor of 128 pages. + * Note this initalizes the data in sctpv6_prot too + * Unabashedly stolen from tcp_init + */ + limit = min(num_physpages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); + limit = (limit * (num_physpages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); + limit = max(limit, 128UL); + sysctl_sctp_mem[0] = limit / 4 * 3; + sysctl_sctp_mem[1] = limit; + sysctl_sctp_mem[2] = sysctl_sctp_mem[0] * 2; + + /* Set per-socket limits to no more than 1/128 the pressure threshold*/ + limit = (sysctl_sctp_mem[1]) << (PAGE_SHIFT - 7); + max_share = min(4UL*1024*1024, limit); + + sysctl_sctp_rmem[0] = PAGE_SIZE; /* give each asoc 1 page min */ + sysctl_sctp_rmem[1] = (1500 *(sizeof(struct sk_buff) + 1)); + sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share); + + sysctl_sctp_wmem[0] = SK_STREAM_MEM_QUANTUM; + sysctl_sctp_wmem[1] = 16*1024; + sysctl_sctp_wmem[2] = max(64*1024, max_share); + /* Size and allocate the association hash table. * The methodology is similar to that of the tcp hash tables. */ diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a583d67cab63..ec0328b1cdb1 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5428,10 +5428,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, sctp_verb_t deliver; int tmp; __u32 tsn; - int account_value; struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; struct sock *sk = asoc->base.sk; - int rcvbuf_over = 0; data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); @@ -5441,48 +5439,6 @@ static int sctp_eat_data(const struct sctp_association *asoc, /* ASSERT: Now skb->data is really the user data. */ - /* - * If we are established, and we have used up our receive buffer - * memory, think about droping the frame. - * Note that we have an opportunity to improve performance here. - * If we accept one chunk from an skbuff, we have to keep all the - * memory of that skbuff around until the chunk is read into user - * space. Therefore, once we accept 1 chunk we may as well accept all - * remaining chunks in the skbuff. The data_accepted flag helps us do - * that. - */ - if ((asoc->state == SCTP_STATE_ESTABLISHED) && (!chunk->data_accepted)) { - /* - * If the receive buffer policy is 1, then each - * association can allocate up to sk_rcvbuf bytes - * otherwise, all the associations in aggregate - * may allocate up to sk_rcvbuf bytes - */ - if (asoc->ep->rcvbuf_policy) - account_value = atomic_read(&asoc->rmem_alloc); - else - account_value = atomic_read(&sk->sk_rmem_alloc); - if (account_value > sk->sk_rcvbuf) { - /* - * We need to make forward progress, even when we are - * under memory pressure, so we always allow the - * next tsn after the ctsn ack point to be accepted. - * This lets us avoid deadlocks in which we have to - * drop frames that would otherwise let us drain the - * receive queue. - */ - if ((sctp_tsnmap_get_ctsn(map) + 1) != tsn) - return SCTP_IERROR_IGNORE_TSN; - - /* - * We're going to accept the frame but we should renege - * to make space for it. This will send us down that - * path later in this function. - */ - rcvbuf_over = 1; - } - } - /* Process ECN based congestion. * * Since the chunk structure is reused for all chunks within @@ -5542,18 +5498,9 @@ static int sctp_eat_data(const struct sctp_association *asoc, * seems a bit troublesome in that frag_point varies based on * PMTU. In cases, such as loopback, this might be a rather * large spill over. - * NOTE: If we have a full receive buffer here, we only renege if - * our receiver can still make progress without the tsn being - * received. We do this because in the event that the associations - * receive queue is empty we are filling a leading gap, and since - * reneging moves the gap to the end of the tsn stream, we are likely - * to stall again very shortly. Avoiding the renege when we fill a - * leading gap is a good heuristic for avoiding such steady state - * stalls. */ - if (!asoc->rwnd || asoc->rwnd_over || - (datalen > asoc->rwnd + asoc->frag_point) || - (rcvbuf_over && (!skb_queue_len(&sk->sk_receive_queue)))) { + if ((!chunk->data_accepted) && (!asoc->rwnd || asoc->rwnd_over || + (datalen > asoc->rwnd + asoc->frag_point))) { /* If this is the next TSN, consider reneging to make * room. Note: Playing nice with a confused sender. A @@ -5573,6 +5520,21 @@ static int sctp_eat_data(const struct sctp_association *asoc, } } + /* + * Also try to renege to limit our memory usage in the event that + * we are under memory pressure + * If we can't renege, don't worry about it, the sk_stream_rmem_schedule + * in sctp_ulpevent_make_rcvmsg will drop the frame if we grow our + * memory usage too much + */ + if (*sk->sk_prot_creator->memory_pressure) { + if (sctp_tsnmap_has_gap(map) && + (sctp_tsnmap_get_ctsn(map) + 1) == tsn) { + SCTP_DEBUG_PRINTK("Under Pressure! Reneging for tsn:%u\n", tsn); + deliver = SCTP_CMD_RENEGE; + } + } + /* * Section 3.3.10.9 No User Data (9) * diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 772fbfb4bfda..b9952425c79a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -107,23 +107,42 @@ static void sctp_sock_migrate(struct sock *, struct sock *, struct sctp_association *, sctp_socket_type_t); static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; +extern struct kmem_cache *sctp_bucket_cachep; +extern int sysctl_sctp_mem[3]; +extern int sysctl_sctp_rmem[3]; +extern int sysctl_sctp_wmem[3]; + +int sctp_memory_pressure; +atomic_t sctp_memory_allocated; +atomic_t sctp_sockets_allocated; + +static void sctp_enter_memory_pressure(void) +{ + sctp_memory_pressure = 1; +} + + /* Get the sndbuf space available at the time on the association. */ static inline int sctp_wspace(struct sctp_association *asoc) { - struct sock *sk = asoc->base.sk; - int amt = 0; + int amt; - if (asoc->ep->sndbuf_policy) { - /* make sure that no association uses more than sk_sndbuf */ - amt = sk->sk_sndbuf - asoc->sndbuf_used; + if (asoc->ep->sndbuf_policy) + amt = asoc->sndbuf_used; + else + amt = atomic_read(&asoc->base.sk->sk_wmem_alloc); + + if (amt >= asoc->base.sk->sk_sndbuf) { + if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK) + amt = 0; + else { + amt = sk_stream_wspace(asoc->base.sk); + if (amt < 0) + amt = 0; + } } else { - /* do socket level accounting */ - amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + amt = asoc->base.sk->sk_sndbuf - amt; } - - if (amt < 0) - amt = 0; - return amt; } @@ -155,6 +174,7 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) sizeof(struct sctp_chunk); atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); + sk_charge_skb(sk, chunk->skb); } /* Verify that this is a valid address. */ @@ -3293,6 +3313,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->hmac = NULL; SCTP_DBG_OBJCNT_INC(sock); + atomic_inc(&sctp_sockets_allocated); return 0; } @@ -3306,7 +3327,7 @@ SCTP_STATIC int sctp_destroy_sock(struct sock *sk) /* Release our hold on the endpoint. */ ep = sctp_sk(sk)->ep; sctp_endpoint_free(ep); - + atomic_dec(&sctp_sockets_allocated); return 0; } @@ -5720,6 +5741,12 @@ static void sctp_wfree(struct sk_buff *skb) atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); + /* + * This undoes what is done via sk_charge_skb + */ + sk->sk_wmem_queued -= skb->truesize; + sk->sk_forward_alloc += skb->truesize; + sock_wfree(skb); __sctp_write_space(asoc); @@ -5737,6 +5764,11 @@ void sctp_sock_rfree(struct sk_buff *skb) struct sctp_ulpevent *event = sctp_skb2event(skb); atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); + + /* + * Mimic the behavior of sk_stream_rfree + */ + sk->sk_forward_alloc += event->rmem_len; } @@ -6126,6 +6158,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, sctp_release_sock(newsk); } + /* This proto struct describes the ULP interface for SCTP. */ struct proto sctp_prot = { .name = "SCTP", @@ -6148,6 +6181,12 @@ struct proto sctp_prot = { .unhash = sctp_unhash, .get_port = sctp_get_port, .obj_size = sizeof(struct sctp_sock), + .sysctl_mem = sysctl_sctp_mem, + .sysctl_rmem = sysctl_sctp_rmem, + .sysctl_wmem = sysctl_sctp_wmem, + .memory_pressure = &sctp_memory_pressure, + .enter_memory_pressure = sctp_enter_memory_pressure, + .memory_allocated = &sctp_memory_allocated, }; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -6172,5 +6211,11 @@ struct proto sctpv6_prot = { .unhash = sctp_unhash, .get_port = sctp_get_port, .obj_size = sizeof(struct sctp6_sock), + .sysctl_mem = sysctl_sctp_mem, + .sysctl_rmem = sysctl_sctp_rmem, + .sysctl_wmem = sysctl_sctp_wmem, + .memory_pressure = &sctp_memory_pressure, + .enter_memory_pressure = sctp_enter_memory_pressure, + .memory_allocated = &sctp_memory_allocated, }; #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index e2c679baf912..ba75ef4669e3 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -52,6 +52,15 @@ static int int_max = INT_MAX; static long sack_timer_min = 1; static long sack_timer_max = 500; +int sysctl_sctp_mem[3]; +int sysctl_sctp_rmem[3]; +int sysctl_sctp_wmem[3]; + +/* + * per assoc memory limitationf for sends + */ +int sysctl_sctp_wmem[3]; + static ctl_table sctp_table[] = { { .ctl_name = NET_SCTP_RTO_INITIAL, @@ -226,6 +235,30 @@ static ctl_table sctp_table[] = { .extra1 = &sack_timer_min, .extra2 = &sack_timer_max, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "sctp_mem", + .data = &sysctl_sctp_mem, + .maxlen = sizeof(sysctl_sctp_mem), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "sctp_rmem", + .data = &sysctl_sctp_rmem, + .maxlen = sizeof(sysctl_sctp_rmem), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "sctp_wmem", + .data = &sysctl_sctp_wmem, + .maxlen = sizeof(sysctl_sctp_wmem), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = 0 } }; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index bfecb353ab3d..5dc094b9732d 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -685,6 +685,24 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, struct sctp_ulpevent *event = NULL; struct sk_buff *skb; size_t padding, len; + int rx_count; + + /* + * check to see if we need to make space for this + * new skb, expand the rcvbuffer if needed, or drop + * the frame + */ + if (asoc->ep->rcvbuf_policy) + rx_count = atomic_read(&asoc->rmem_alloc); + else + rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc); + + if (rx_count >= asoc->base.sk->sk_rcvbuf) { + + if ((asoc->base.sk->sk_userlocks & SOCK_RCVBUF_LOCK) || + (!sk_stream_rmem_schedule(asoc->base.sk, chunk->skb))) + goto fail; + } /* Clone the original skb, sharing the data. */ skb = skb_clone(chunk->skb, gfp); diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index fa0ba2a5564e..b9370956b187 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -1027,6 +1027,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, sctp_ulpq_partial_delivery(ulpq, chunk, gfp); } + sk_stream_mem_reclaim(asoc->base.sk); return; } From ac198ea8d94a46830080372a539420cf4a8de4a3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:14:27 -0700 Subject: [PATCH 1076/2804] [DCCP]: Make ccid3_hc_tx_update_x get a timestamp if needed The code was too complicated, if p > 0 in ccid3_hc_tx_no_feedback_timer the timestamp was being obtained to be passed to ccid3_hc_tx_update_x, where only if p > 0 the timestamp was needed, so just leave it to ccid3_hc_tx_update_x to obtain the timestamp if needed. This will help in the upcoming changesets where we'll convert t_ld to ktime_t. We'll eventually try to reuse ktime_get_real() calls again. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index e91c2b9dc27b..d0763adbce26 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -128,7 +128,7 @@ static inline void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hctx) * throughout the code. Only X_calc is unscaled (in bytes/second). * */ -static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) +static void ccid3_hc_tx_update_x(struct sock *sk) { struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); @@ -153,14 +153,20 @@ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) (((__u64)hctx->ccid3hctx_s) << 6) / TFRC_T_MBI); - } else if (timeval_delta(now, &hctx->ccid3hctx_t_ld) - - (suseconds_t)hctx->ccid3hctx_rtt >= 0) { + } else { + struct timeval now; - hctx->ccid3hctx_x = - max(min(2 * hctx->ccid3hctx_x, min_rate), - scaled_div(((__u64)hctx->ccid3hctx_s) << 6, - hctx->ccid3hctx_rtt)); - hctx->ccid3hctx_t_ld = *now; + dccp_timestamp(sk, &now); + + if ((timeval_delta(&now, &hctx->ccid3hctx_t_ld) - + (suseconds_t)hctx->ccid3hctx_rtt) >= 0) { + + hctx->ccid3hctx_x = + max(min(2 * hctx->ccid3hctx_x, min_rate), + scaled_div(((__u64)hctx->ccid3hctx_s) << 6, + hctx->ccid3hctx_rtt)); + hctx->ccid3hctx_t_ld = now; + } } if (hctx->ccid3hctx_x != old_x) { @@ -214,7 +220,6 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) { struct sock *sk = (struct sock *)data; struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - struct timeval now; unsigned long t_nfb = USEC_PER_SEC / 5; bh_lock_sock(sk); @@ -265,15 +270,12 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) max(hctx->ccid3hctx_x_recv / 2, (((__u64)hctx->ccid3hctx_s) << 6) / (2 * TFRC_T_MBI)); - - if (hctx->ccid3hctx_p == 0) - dccp_timestamp(sk, &now); } else { hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc; hctx->ccid3hctx_x_recv <<= 4; } /* Now recalculate X [RFC 3448, 4.3, step (4)] */ - ccid3_hc_tx_update_x(sk, &now); + ccid3_hc_tx_update_x(sk); /* * Schedule no feedback timer to expire in * max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi) @@ -496,7 +498,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) tfrc_calc_x(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt, hctx->ccid3hctx_p); - ccid3_hc_tx_update_x(sk, &now); + ccid3_hc_tx_update_x(sk); ccid3_pr_debug("%s(%p), RTT=%uus (sample=%uus), s=%u, " "p=%u, X_calc=%u, X_recv=%u, X=%u\n", From 23f062af6e90654ef939462c2c060ad103dec6f2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:14:52 -0700 Subject: [PATCH 1077/2804] [DCCP]: Convert ccid3hctx_t_ld to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 12 +++++------- net/dccp/ccids/ccid3.h | 3 +-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index d0763adbce26..42d3dbc1874e 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -154,12 +154,10 @@ static void ccid3_hc_tx_update_x(struct sock *sk) TFRC_T_MBI); } else { - struct timeval now; + const ktime_t now = ktime_get_real(); - dccp_timestamp(sk, &now); - - if ((timeval_delta(&now, &hctx->ccid3hctx_t_ld) - - (suseconds_t)hctx->ccid3hctx_rtt) >= 0) { + if ((ktime_us_delta(now, hctx->ccid3hctx_t_ld) - + (s64)hctx->ccid3hctx_rtt) >= 0) { hctx->ccid3hctx_x = max(min(2 * hctx->ccid3hctx_x, min_rate), @@ -343,7 +341,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) ccid3_pr_debug("SYN RTT = %uus\n", dp->dccps_syn_rtt); hctx->ccid3hctx_rtt = dp->dccps_syn_rtt; hctx->ccid3hctx_x = rfc3390_initial_rate(sk); - hctx->ccid3hctx_t_ld = ktime_to_timeval(now); + hctx->ccid3hctx_t_ld = now; } else { /* Sender does not have RTT sample: X = MSS/second */ hctx->ccid3hctx_x = dp->dccps_mss_cache; @@ -477,7 +475,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) */ hctx->ccid3hctx_rtt = r_sample; hctx->ccid3hctx_x = rfc3390_initial_rate(sk); - hctx->ccid3hctx_t_ld = now; + hctx->ccid3hctx_t_ld = timeval_to_ktime(now); ccid3_update_send_interval(hctx); diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 51d4b804e334..dcb6b677348b 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -38,7 +38,6 @@ #include #include -#include #include #include #include "../ccid.h" @@ -111,7 +110,7 @@ struct ccid3_hc_tx_sock { u8 ccid3hctx_idle; ktime_t ccid3hctx_t_last_win_count; struct timer_list ccid3hctx_no_feedback_timer; - struct timeval ccid3hctx_t_ld; + ktime_t ccid3hctx_t_ld; ktime_t ccid3hctx_t_nom; u32 ccid3hctx_delta; struct list_head ccid3hctx_hist; From 1faf0a1f5d9cafe031b8faa91636b67cdca726a3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:15:13 -0700 Subject: [PATCH 1078/2804] [DCCP]: Convert ccid3hcrx_tstamp_last_ack to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 22 ++++++++++++++-------- net/dccp/ccids/ccid3.h | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 42d3dbc1874e..63051eb1779d 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -876,7 +876,6 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); const struct dccp_options_received *opt_recv; struct dccp_rx_hist_entry *packet; - struct timeval now; u32 p_prev, r_sample, rtt_prev; int loss, payload_size; @@ -888,7 +887,9 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) case DCCP_PKT_ACK: if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) return; - case DCCP_PKT_DATAACK: + case DCCP_PKT_DATAACK: { + struct timeval now; + if (opt_recv->dccpor_timestamp_echo == 0) break; rtt_prev = hcrx->ccid3hcrx_rtt; @@ -906,6 +907,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) dccp_role(sk), sk, hcrx->ccid3hcrx_rtt, opt_recv->dccpor_elapsed_time); break; + } case DCCP_PKT_DATA: break; default: /* We're not interested in other packet types, move along */ @@ -936,18 +938,21 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) ccid3_hc_rx_send_feedback(sk); ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA); return; - case TFRC_RSTATE_DATA: + case TFRC_RSTATE_DATA: { + ktime_t now; + hcrx->ccid3hcrx_bytes_recv += payload_size; if (loss) break; - dccp_timestamp(sk, &now); - if ((timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) - - (suseconds_t)hcrx->ccid3hcrx_rtt) >= 0) { + now = ktime_get_real(); + if ((ktime_us_delta(now, hcrx->ccid3hcrx_tstamp_last_ack) - + (s64)hcrx->ccid3hcrx_rtt) >= 0) { hcrx->ccid3hcrx_tstamp_last_ack = now; ccid3_hc_rx_send_feedback(sk); } return; + } case TFRC_RSTATE_TERM: DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk); return; @@ -984,8 +989,9 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk) hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist); INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist); - dccp_timestamp(sk, &hcrx->ccid3hcrx_tstamp_last_ack); - hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack; + hcrx->ccid3hcrx_tstamp_last_ack = ktime_get_real(); + hcrx->ccid3hcrx_tstamp_last_feedback = + ktime_to_timeval(hcrx->ccid3hcrx_tstamp_last_ack); hcrx->ccid3hcrx_s = 0; hcrx->ccid3hcrx_rtt = 0; return 0; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index dcb6b677348b..a69cf887e3e3 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -153,7 +153,7 @@ struct ccid3_hc_rx_sock { enum ccid3_hc_rx_states ccid3hcrx_state:8; u32 ccid3hcrx_bytes_recv; struct timeval ccid3hcrx_tstamp_last_feedback; - struct timeval ccid3hcrx_tstamp_last_ack; + ktime_t ccid3hcrx_tstamp_last_ack; struct list_head ccid3hcrx_hist; struct list_head ccid3hcrx_li_hist; u16 ccid3hcrx_s; From e7a81c6d62cbefdeb23d92ad891f429bde1c49d2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:15:37 -0700 Subject: [PATCH 1079/2804] [DCCP]: Convert ccid3hcrx_tstamp_last_feedback to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 19 +++++++++++-------- net/dccp/ccids/ccid3.h | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 63051eb1779d..1a0c5edb7b35 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -729,20 +729,21 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); struct dccp_sock *dp = dccp_sk(sk); struct dccp_rx_hist_entry *packet; - struct timeval now; + struct timeval tnow; + ktime_t now; suseconds_t delta; ccid3_pr_debug("%s(%p) - entry \n", dccp_role(sk), sk); - dccp_timestamp(sk, &now); + now = ktime_get_real(); switch (hcrx->ccid3hcrx_state) { case TFRC_RSTATE_NO_DATA: hcrx->ccid3hcrx_x_recv = 0; break; case TFRC_RSTATE_DATA: - delta = timeval_delta(&now, - &hcrx->ccid3hcrx_tstamp_last_feedback); + delta = ktime_us_delta(now, + hcrx->ccid3hcrx_tstamp_last_feedback); DCCP_BUG_ON(delta < 0); hcrx->ccid3hcrx_x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta); @@ -764,7 +765,8 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) hcrx->ccid3hcrx_bytes_recv = 0; /* Elapsed time information [RFC 4340, 13.2] in units of 10 * usecs */ - delta = timeval_delta(&now, &packet->dccphrx_tstamp); + tnow = ktime_to_timeval(now); + delta = timeval_delta(&tnow, &packet->dccphrx_tstamp); DCCP_BUG_ON(delta < 0); hcrx->ccid3hcrx_elapsed_time = delta / 10; @@ -835,11 +837,13 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk, while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno) > TFRC_RECV_NUM_LATE_LOSS) { + struct timeval tstamp = + ktime_to_timeval(hcrx->ccid3hcrx_tstamp_last_feedback); loss = 1; dccp_li_update_li(sk, &hcrx->ccid3hcrx_li_hist, &hcrx->ccid3hcrx_hist, - &hcrx->ccid3hcrx_tstamp_last_feedback, + &tstamp, hcrx->ccid3hcrx_s, hcrx->ccid3hcrx_bytes_recv, hcrx->ccid3hcrx_x_recv, @@ -989,9 +993,8 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk) hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist); INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist); - hcrx->ccid3hcrx_tstamp_last_ack = ktime_get_real(); hcrx->ccid3hcrx_tstamp_last_feedback = - ktime_to_timeval(hcrx->ccid3hcrx_tstamp_last_ack); + hcrx->ccid3hcrx_tstamp_last_ack = ktime_get_real(); hcrx->ccid3hcrx_s = 0; hcrx->ccid3hcrx_rtt = 0; return 0; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index a69cf887e3e3..7cbf2b1329d9 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -152,7 +152,7 @@ struct ccid3_hc_rx_sock { ccid3hcrx_ccval_last_counter:4; enum ccid3_hc_rx_states ccid3hcrx_state:8; u32 ccid3hcrx_bytes_recv; - struct timeval ccid3hcrx_tstamp_last_feedback; + ktime_t ccid3hcrx_tstamp_last_feedback; ktime_t ccid3hcrx_tstamp_last_ack; struct list_head ccid3hcrx_hist; struct list_head ccid3hcrx_li_hist; From a272378d1128d1c60a463a315646c86d174ff74c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:16:05 -0700 Subject: [PATCH 1080/2804] [KTIME]: Introduce ktime_sub_ns and ktime_sub_us First user will be the DCCP transport networking protocol. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/linux/ktime.h | 21 +++++++++++++++++++++ kernel/hrtimer.c | 24 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/linux/ktime.h b/include/linux/ktime.h index dae7143644fe..a6ddec141f96 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -102,6 +102,13 @@ static inline ktime_t ktime_set(const long secs, const unsigned long nsecs) #define ktime_add_ns(kt, nsval) \ ({ (ktime_t){ .tv64 = (kt).tv64 + (nsval) }; }) +/* + * Subtract a scalar nanosecod from a ktime_t variable + * res = kt - nsval: + */ +#define ktime_sub_ns(kt, nsval) \ + ({ (ktime_t){ .tv64 = (kt).tv64 - (nsval) }; }) + /* convert a timespec to ktime_t format: */ static inline ktime_t timespec_to_ktime(struct timespec ts) { @@ -199,6 +206,15 @@ static inline ktime_t ktime_add(const ktime_t add1, const ktime_t add2) */ extern ktime_t ktime_add_ns(const ktime_t kt, u64 nsec); +/** + * ktime_sub_ns - Subtract a scalar nanoseconds value from a ktime_t variable + * @kt: minuend + * @nsec: the scalar nsec value to subtract + * + * Returns the subtraction of @nsec from @kt in ktime_t format + */ +extern ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec); + /** * timespec_to_ktime - convert a timespec to ktime_t format * @ts: the timespec variable to convert @@ -289,6 +305,11 @@ static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec) return ktime_add_ns(kt, usec * 1000); } +static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec) +{ + return ktime_sub_ns(kt, usec * 1000); +} + /* * The resolution of the clocks. The resolution value is returned in * the clock_getres() system call to give application programmers an diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index c21ca6bfaa66..dc8a4451d79b 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -277,6 +277,30 @@ ktime_t ktime_add_ns(const ktime_t kt, u64 nsec) } EXPORT_SYMBOL_GPL(ktime_add_ns); + +/** + * ktime_sub_ns - Subtract a scalar nanoseconds value from a ktime_t variable + * @kt: minuend + * @nsec: the scalar nsec value to subtract + * + * Returns the subtraction of @nsec from @kt in ktime_t format + */ +ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec) +{ + ktime_t tmp; + + if (likely(nsec < NSEC_PER_SEC)) { + tmp.tv64 = nsec; + } else { + unsigned long rem = do_div(nsec, NSEC_PER_SEC); + + tmp = ktime_set((long)nsec, rem); + } + + return ktime_sub(kt, tmp); +} + +EXPORT_SYMBOL_GPL(ktime_sub_ns); # endif /* !CONFIG_KTIME_SCALAR */ /* From 9823b7b5542858afe5b6a1e2df83b3847c28f3d6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:16:35 -0700 Subject: [PATCH 1081/2804] [DCCP]: Convert dccp_sample_rtt to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 25 ++++++++++--------------- net/dccp/dccp.h | 5 +++-- net/dccp/input.c | 23 ++++++++++------------- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 1a0c5edb7b35..3524328db0b9 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -414,7 +414,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct ccid3_options_received *opt_recv; struct dccp_tx_hist_entry *packet; - struct timeval now; + ktime_t now, t_hist; unsigned long t_nfb; u32 pinv, r_sample; @@ -452,13 +452,13 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) else /* can not exceed 100% */ hctx->ccid3hctx_p = 1000000 / pinv; - dccp_timestamp(sk, &now); - + now = ktime_get_real(); + t_hist = timeval_to_ktime(packet->dccphtx_tstamp); /* * Calculate new round trip sample as per [RFC 3448, 4.3] by * R_sample = (now - t_recvdata) - t_elapsed */ - r_sample = dccp_sample_rtt(sk, &now, &packet->dccphtx_tstamp); + r_sample = dccp_sample_rtt(sk, now, &t_hist); /* * Update RTT estimate by @@ -475,7 +475,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) */ hctx->ccid3hctx_rtt = r_sample; hctx->ccid3hctx_x = rfc3390_initial_rate(sk); - hctx->ccid3hctx_t_ld = timeval_to_ktime(now); + hctx->ccid3hctx_t_ld = now; ccid3_update_send_interval(hctx); @@ -882,6 +882,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) struct dccp_rx_hist_entry *packet; u32 p_prev, r_sample, rtt_prev; int loss, payload_size; + ktime_t now; BUG_ON(hcrx == NULL); @@ -891,14 +892,12 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) case DCCP_PKT_ACK: if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) return; - case DCCP_PKT_DATAACK: { - struct timeval now; - + case DCCP_PKT_DATAACK: if (opt_recv->dccpor_timestamp_echo == 0) break; rtt_prev = hcrx->ccid3hcrx_rtt; - dccp_timestamp(sk, &now); - r_sample = dccp_sample_rtt(sk, &now, NULL); + now = ktime_get_real(); + r_sample = dccp_sample_rtt(sk, now, NULL); if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) hcrx->ccid3hcrx_rtt = r_sample; @@ -911,7 +910,6 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) dccp_role(sk), sk, hcrx->ccid3hcrx_rtt, opt_recv->dccpor_elapsed_time); break; - } case DCCP_PKT_DATA: break; default: /* We're not interested in other packet types, move along */ @@ -942,9 +940,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) ccid3_hc_rx_send_feedback(sk); ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA); return; - case TFRC_RSTATE_DATA: { - ktime_t now; - + case TFRC_RSTATE_DATA: hcrx->ccid3hcrx_bytes_recv += payload_size; if (loss) break; @@ -956,7 +952,6 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) ccid3_hc_rx_send_feedback(sk); } return; - } case TFRC_RSTATE_TERM: DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk); return; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index e2d74cd7eeeb..20a7bedfe996 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -296,8 +297,8 @@ extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); extern void dccp_send_close(struct sock *sk, const int active); extern int dccp_invalid_packet(struct sk_buff *skb); -extern u32 dccp_sample_rtt(struct sock *sk, struct timeval *t_recv, - struct timeval *t_history); +extern u32 dccp_sample_rtt(struct sock *sk, ktime_t t_recv, + ktime_t *t_history); static inline int dccp_bad_service_code(const struct sock *sk, const __be32 service) diff --git a/net/dccp/input.c b/net/dccp/input.c index da6ec185ed5b..782cdb7292fa 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -301,12 +301,10 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, goto out_invalid_packet; /* Obtain RTT sample from SYN exchange (used by CCID 3) */ - if (dp->dccps_options_received.dccpor_timestamp_echo) { - struct timeval now; - - dccp_timestamp(sk, &now); - dp->dccps_syn_rtt = dccp_sample_rtt(sk, &now, NULL); - } + if (dp->dccps_options_received.dccpor_timestamp_echo) + dp->dccps_syn_rtt = dccp_sample_rtt(sk, + ktime_get_real(), + NULL); if (dccp_msk(sk)->dccpms_send_ack_vector && dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, @@ -593,22 +591,21 @@ EXPORT_SYMBOL_GPL(dccp_rcv_state_process); * @t_recv: receive timestamp of packet with timestamp echo * @t_hist: packet history timestamp or NULL */ -u32 dccp_sample_rtt(struct sock *sk, struct timeval *t_recv, - struct timeval *t_hist) +u32 dccp_sample_rtt(struct sock *sk, ktime_t t_recv, ktime_t *t_hist) { struct dccp_sock *dp = dccp_sk(sk); struct dccp_options_received *or = &dp->dccps_options_received; - suseconds_t delta; + s64 delta; if (t_hist == NULL) { if (!or->dccpor_timestamp_echo) { DCCP_WARN("packet without timestamp echo\n"); return DCCP_SANE_RTT_MAX; } - timeval_sub_usecs(t_recv, or->dccpor_timestamp_echo * 10); - delta = timeval_usecs(t_recv); + ktime_sub_us(t_recv, or->dccpor_timestamp_echo * 10); + delta = ktime_to_us(t_recv); } else - delta = timeval_delta(t_recv, t_hist); + delta = ktime_us_delta(t_recv, *t_hist); delta -= or->dccpor_elapsed_time * 10; /* either set or 0 */ @@ -616,7 +613,7 @@ u32 dccp_sample_rtt(struct sock *sk, struct timeval *t_recv, DCCP_WARN("unusable RTT sample %ld, using min\n", (long)delta); return DCCP_SANE_RTT_MIN; } - if (unlikely(delta - (suseconds_t)DCCP_SANE_RTT_MAX > 0)) { + if (unlikely(delta - (s64)DCCP_SANE_RTT_MAX > 0)) { DCCP_WARN("RTT sample %ld too large, using max\n", (long)delta); return DCCP_SANE_RTT_MAX; } From 668348a4232d3dd0ee48b3dc13228b5a7eb57565 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:17:02 -0700 Subject: [PATCH 1082/2804] [DCCP] CCID3: Stop using dccp_timestamp Now to convert the ackvec code to ktime_t so that we can get rid of dccp_timestamp and the epoch thing in dccp_sock. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 3524328db0b9..6b12e9faef30 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -388,7 +388,6 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) { struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - struct timeval now; struct dccp_tx_hist_entry *packet; BUG_ON(hctx == NULL); @@ -402,8 +401,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, } dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, packet); - dccp_timestamp(sk, &now); - packet->dccphtx_tstamp = now; + packet->dccphtx_tstamp = ktime_to_timeval(ktime_get_real()); packet->dccphtx_seqno = dccp_sk(sk)->dccps_gss; packet->dccphtx_rtt = hctx->ccid3hctx_rtt; packet->dccphtx_sent = 1; @@ -729,8 +727,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); struct dccp_sock *dp = dccp_sk(sk); struct dccp_rx_hist_entry *packet; - struct timeval tnow; - ktime_t now; + ktime_t now, t_hist; suseconds_t delta; ccid3_pr_debug("%s(%p) - entry \n", dccp_role(sk), sk); @@ -765,8 +762,8 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) hcrx->ccid3hcrx_bytes_recv = 0; /* Elapsed time information [RFC 4340, 13.2] in units of 10 * usecs */ - tnow = ktime_to_timeval(now); - delta = timeval_delta(&tnow, &packet->dccphrx_tstamp); + t_hist = timeval_to_ktime(packet->dccphrx_tstamp); + delta = ktime_us_delta(now, t_hist); DCCP_BUG_ON(delta < 0); hcrx->ccid3hcrx_elapsed_time = delta / 10; From b8bda9d70842dab7902f0681e1297dcf0460fc94 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:17:25 -0700 Subject: [PATCH 1083/2804] [DCCP] ackvec: Convert to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ackvec.c | 11 +++++------ net/dccp/ackvec.h | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 7ac775f9a64b..3f8984b5f6e8 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -73,17 +73,17 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) DCCP_MAX_ACKVEC_OPT_LEN - 1) / DCCP_MAX_ACKVEC_OPT_LEN; u16 len = av->dccpav_vec_len + 2 * nr_opts, i; - struct timeval now; u32 elapsed_time; const unsigned char *tail, *from; unsigned char *to; struct dccp_ackvec_record *avr; + suseconds_t delta; if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) return -1; - dccp_timestamp(sk, &now); - elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10; + delta = ktime_us_delta(ktime_get_real(), av->dccpav_time); + elapsed_time = delta / 10; if (elapsed_time != 0 && dccp_insert_option_elapsed_time(sk, skb, elapsed_time)) @@ -159,8 +159,7 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority) av->dccpav_buf_head = DCCP_MAX_ACKVEC_LEN - 1; av->dccpav_buf_ackno = UINT48_MAX + 1; av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0; - av->dccpav_time.tv_sec = 0; - av->dccpav_time.tv_usec = 0; + av->dccpav_time = ktime_set(0, 0); av->dccpav_vec_len = 0; INIT_LIST_HEAD(&av->dccpav_records); } @@ -321,7 +320,7 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, } av->dccpav_buf_ackno = ackno; - dccp_timestamp(sk, &av->dccpav_time); + av->dccpav_time = ktime_get_real(); out: return 0; diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index 96504a3b16e4..9ef0737043ee 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -12,8 +12,8 @@ */ #include +#include #include -#include #include /* Read about the ECN nonce to see why it is 253 */ @@ -52,7 +52,7 @@ struct dccp_ackvec { u64 dccpav_buf_ackno; struct list_head dccpav_records; - struct timeval dccpav_time; + ktime_t dccpav_time; u16 dccpav_buf_head; u16 dccpav_vec_len; u8 dccpav_buf_nonce; From e7c2335794b949292ecfd01902c429e2ac3937e1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:17:51 -0700 Subject: [PATCH 1084/2804] [DCCP] packet_history: convert dccphrx_tstamp to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 11 ++++------- net/dccp/ccids/lib/loss_interval.c | 11 +++++------ net/dccp/ccids/lib/loss_interval.h | 4 ++-- net/dccp/ccids/lib/packet_history.h | 6 +++--- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 6b12e9faef30..b21d8110298c 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -727,7 +727,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); struct dccp_sock *dp = dccp_sk(sk); struct dccp_rx_hist_entry *packet; - ktime_t now, t_hist; + ktime_t now; suseconds_t delta; ccid3_pr_debug("%s(%p) - entry \n", dccp_role(sk), sk); @@ -762,8 +762,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) hcrx->ccid3hcrx_bytes_recv = 0; /* Elapsed time information [RFC 4340, 13.2] in units of 10 * usecs */ - t_hist = timeval_to_ktime(packet->dccphrx_tstamp); - delta = ktime_us_delta(now, t_hist); + delta = ktime_us_delta(now, packet->dccphrx_tstamp); DCCP_BUG_ON(delta < 0); hcrx->ccid3hcrx_elapsed_time = delta / 10; @@ -834,13 +833,11 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk, while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno) > TFRC_RECV_NUM_LATE_LOSS) { - struct timeval tstamp = - ktime_to_timeval(hcrx->ccid3hcrx_tstamp_last_feedback); loss = 1; dccp_li_update_li(sk, &hcrx->ccid3hcrx_li_hist, &hcrx->ccid3hcrx_hist, - &tstamp, + hcrx->ccid3hcrx_tstamp_last_feedback, hcrx->ccid3hcrx_s, hcrx->ccid3hcrx_bytes_recv, hcrx->ccid3hcrx_x_recv, @@ -913,7 +910,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) return; } - packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp, + packet = dccp_rx_hist_entry_new(ccid3_rx_hist, opt_recv->dccpor_ndp, skb, GFP_ATOMIC); if (unlikely(packet == NULL)) { DCCP_WARN("%s(%p), Not enough mem to add rx packet " diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c index 174d3f13d93f..40ad428a27f5 100644 --- a/net/dccp/ccids/lib/loss_interval.c +++ b/net/dccp/ccids/lib/loss_interval.c @@ -125,14 +125,14 @@ static int dccp_li_hist_interval_new(struct list_head *list, * returns estimated loss interval in usecs */ static u32 dccp_li_calc_first_li(struct sock *sk, struct list_head *hist_list, - struct timeval *last_feedback, + ktime_t last_feedback, u16 s, u32 bytes_recv, u32 previous_x_recv) { struct dccp_rx_hist_entry *entry, *next, *tail = NULL; u32 x_recv, p; suseconds_t rtt, delta; - struct timeval tstamp = { 0, 0 }; + ktime_t tstamp = ktime_set(0, 0); int interval = 0; int win_count = 0; int step = 0; @@ -176,7 +176,7 @@ found: return ~0; } - delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp); + delta = ktime_us_delta(tstamp, tail->dccphrx_tstamp); DCCP_BUG_ON(delta < 0); rtt = delta * 4 / interval; @@ -196,8 +196,7 @@ found: return ~0; } - dccp_timestamp(sk, &tstamp); - delta = timeval_delta(&tstamp, last_feedback); + delta = ktime_us_delta(ktime_get_real(), last_feedback); DCCP_BUG_ON(delta <= 0); x_recv = scaled_div32(bytes_recv, delta); @@ -226,7 +225,7 @@ found: void dccp_li_update_li(struct sock *sk, struct list_head *li_hist_list, struct list_head *hist_list, - struct timeval *last_feedback, u16 s, u32 bytes_recv, + ktime_t last_feedback, u16 s, u32 bytes_recv, u32 previous_x_recv, u64 seq_loss, u8 win_loss) { struct dccp_li_hist_entry *head; diff --git a/net/dccp/ccids/lib/loss_interval.h b/net/dccp/ccids/lib/loss_interval.h index 906c806d6d9d..27bee92dae13 100644 --- a/net/dccp/ccids/lib/loss_interval.h +++ b/net/dccp/ccids/lib/loss_interval.h @@ -13,8 +13,8 @@ * any later version. */ +#include #include -#include extern void dccp_li_hist_purge(struct list_head *list); @@ -23,7 +23,7 @@ extern u32 dccp_li_hist_calc_i_mean(struct list_head *list); extern void dccp_li_update_li(struct sock *sk, struct list_head *li_hist_list, struct list_head *hist_list, - struct timeval *last_feedback, u16 s, + ktime_t last_feedback, u16 s, u32 bytes_recv, u32 previous_x_recv, u64 seq_loss, u8 win_loss); #endif /* _DCCP_LI_HIST_ */ diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index 60d00f015390..d9d68964d952 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h @@ -37,6 +37,7 @@ #ifndef _DCCP_PKT_HIST_ #define _DCCP_PKT_HIST_ +#include #include #include #include @@ -124,7 +125,7 @@ struct dccp_rx_hist_entry { dccphrx_ccval:4, dccphrx_type:4; u32 dccphrx_ndp; /* In fact it is from 8 to 24 bits */ - struct timeval dccphrx_tstamp; + ktime_t dccphrx_tstamp; }; struct dccp_rx_hist { @@ -136,7 +137,6 @@ extern void dccp_rx_hist_delete(struct dccp_rx_hist *hist); static inline struct dccp_rx_hist_entry * dccp_rx_hist_entry_new(struct dccp_rx_hist *hist, - const struct sock *sk, const u32 ndp, const struct sk_buff *skb, const gfp_t prio) @@ -151,7 +151,7 @@ static inline struct dccp_rx_hist_entry * entry->dccphrx_ccval = dh->dccph_ccval; entry->dccphrx_type = dh->dccph_type; entry->dccphrx_ndp = ndp; - dccp_timestamp(sk, &entry->dccphrx_tstamp); + entry->dccphrx_tstamp = ktime_get_real(); } return entry; From 0740d49c2465bdd2644455c4bc49794395b73433 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:18:13 -0700 Subject: [PATCH 1085/2804] [DCCP] packet_history: Convert dccphtx_tstamp to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 7 +++---- net/dccp/ccids/lib/packet_history.h | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index b21d8110298c..e75efe72da2b 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -401,7 +401,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, } dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, packet); - packet->dccphtx_tstamp = ktime_to_timeval(ktime_get_real()); + packet->dccphtx_tstamp = ktime_get_real(); packet->dccphtx_seqno = dccp_sk(sk)->dccps_gss; packet->dccphtx_rtt = hctx->ccid3hctx_rtt; packet->dccphtx_sent = 1; @@ -412,7 +412,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct ccid3_options_received *opt_recv; struct dccp_tx_hist_entry *packet; - ktime_t now, t_hist; + ktime_t now; unsigned long t_nfb; u32 pinv, r_sample; @@ -451,12 +451,11 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) hctx->ccid3hctx_p = 1000000 / pinv; now = ktime_get_real(); - t_hist = timeval_to_ktime(packet->dccphtx_tstamp); /* * Calculate new round trip sample as per [RFC 3448, 4.3] by * R_sample = (now - t_recvdata) - t_elapsed */ - r_sample = dccp_sample_rtt(sk, now, &t_hist); + r_sample = dccp_sample_rtt(sk, now, &packet->dccphtx_tstamp); /* * Update RTT estimate by diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index d9d68964d952..032bb61c6e39 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h @@ -40,7 +40,6 @@ #include #include #include -#include #include "../../dccp.h" @@ -58,7 +57,7 @@ struct dccp_tx_hist_entry { u64 dccphtx_seqno:48, dccphtx_sent:1; u32 dccphtx_rtt; - struct timeval dccphtx_tstamp; + ktime_t dccphtx_tstamp; }; struct dccp_tx_hist { From 19ac21465e15e476220909c01b23df847b6ffa30 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:18:33 -0700 Subject: [PATCH 1086/2804] [DCCP]: Convert dccps_timestamp_time to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/linux/dccp.h | 3 ++- net/dccp/options.c | 13 +++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/include/linux/dccp.h b/include/linux/dccp.h index fda2148d8c85..3a4b96becfc4 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -215,6 +215,7 @@ struct dccp_so_feat { #ifdef __KERNEL__ #include +#include #include #include #include @@ -498,7 +499,7 @@ struct dccp_sock { __u64 dccps_gar; __be32 dccps_service; struct dccp_service_list *dccps_service_list; - struct timeval dccps_timestamp_time; + ktime_t dccps_timestamp_time; __u32 dccps_timestamp_echo; __u16 dccps_l_ack_ratio; __u16 dccps_r_ack_ratio; diff --git a/net/dccp/options.c b/net/dccp/options.c index 34d536d5f1a1..95b75d8354ff 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -158,7 +158,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) opt_recv->dccpor_timestamp = ntohl(*(__be32 *)value); dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; - dccp_timestamp(sk, &dp->dccps_timestamp_time); + dp->dccps_timestamp_time = ktime_get_real(); dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n", dccp_role(sk), opt_recv->dccpor_timestamp, @@ -405,14 +405,12 @@ static int dccp_insert_option_timestamp_echo(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); - struct timeval now; __be32 tstamp_echo; - u32 elapsed_time; int len, elapsed_time_len; unsigned char *to; - - dccp_timestamp(sk, &now); - elapsed_time = timeval_delta(&now, &dp->dccps_timestamp_time) / 10; + const suseconds_t delta = ktime_us_delta(ktime_get_real(), + dp->dccps_timestamp_time); + u32 elapsed_time = delta / 10; elapsed_time_len = dccp_elapsed_time_len(elapsed_time); len = 6 + elapsed_time_len; @@ -438,8 +436,7 @@ static int dccp_insert_option_timestamp_echo(struct sock *sk, } dp->dccps_timestamp_echo = 0; - dp->dccps_timestamp_time.tv_sec = 0; - dp->dccps_timestamp_time.tv_usec = 0; + dp->dccps_timestamp_time = ktime_set(0, 0); return 0; } From 234748954a9880cce8a065698dcbf692f9c23918 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:18:55 -0700 Subject: [PATCH 1087/2804] [DCCP] options: convert dccp_insert_option_timestamp to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/options.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/dccp/options.c b/net/dccp/options.c index 95b75d8354ff..439e25daa963 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -388,11 +388,7 @@ EXPORT_SYMBOL_GPL(dccp_timestamp); int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) { - struct timeval tv; - __be32 now; - - dccp_timestamp(sk, &tv); - now = htonl(timeval_usecs(&tv) / 10); + __be32 now = htonl(((suseconds_t)ktime_to_us(ktime_get_real())) / 10); /* yes this will overflow but that is the point as we want a * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ From 8fb8354af9b92ce3bd41083995f1fe26024d0959 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:19:21 -0700 Subject: [PATCH 1088/2804] [DCCP]: Nuke dccp_timestamp and dccps_epoch, not used anymore Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/linux/dccp.h | 1 - net/dccp/dccp.h | 2 -- net/dccp/minisocks.c | 1 - net/dccp/options.c | 16 ---------------- net/dccp/proto.c | 1 - 5 files changed, 21 deletions(-) diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 3a4b96becfc4..a0441190dc71 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -512,7 +512,6 @@ struct dccp_sock { struct ccid *dccps_hc_rx_ccid; struct ccid *dccps_hc_tx_ccid; struct dccp_options_received dccps_options_received; - struct timeval dccps_epoch; enum dccp_role dccps_role:2; __u8 dccps_hc_rx_insert_options:1; __u8 dccps_hc_tx_insert_options:1; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 20a7bedfe996..6fbe293bb271 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -402,8 +402,6 @@ extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb, unsigned char option, const void *value, unsigned char len); -extern void dccp_timestamp(const struct sock *sk, struct timeval *tv); - static inline suseconds_t timeval_usecs(const struct timeval *tv) { return tv->tv_sec * USEC_PER_SEC + tv->tv_usec; diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index e18e249ac49b..91685990d57e 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -112,7 +112,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk, newdp->dccps_service_list = NULL; newdp->dccps_service = dreq->dreq_service; newicsk->icsk_rto = DCCP_TIMEOUT_INIT; - do_gettimeofday(&newdp->dccps_epoch); if (dccp_feat_clone(sk, newsk)) goto out_free; diff --git a/net/dccp/options.c b/net/dccp/options.c index 439e25daa963..167415677a75 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -370,22 +370,6 @@ int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb, EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); -void dccp_timestamp(const struct sock *sk, struct timeval *tv) -{ - const struct dccp_sock *dp = dccp_sk(sk); - - do_gettimeofday(tv); - tv->tv_sec -= dp->dccps_epoch.tv_sec; - tv->tv_usec -= dp->dccps_epoch.tv_usec; - - while (tv->tv_usec < 0) { - tv->tv_sec--; - tv->tv_usec += USEC_PER_SEC; - } -} - -EXPORT_SYMBOL_GPL(dccp_timestamp); - int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) { __be32 now = htonl(((suseconds_t)ktime_to_us(ktime_get_real())) / 10); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 04b59ec4f512..8d545da35262 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -172,7 +172,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) struct inet_connection_sock *icsk = inet_csk(sk); dccp_minisock_init(&dp->dccps_minisock); - do_gettimeofday(&dp->dccps_epoch); /* * FIXME: We're hardcoding the CCID, and doing this at this point makes From 6168b96c07d8d40f83622cfb488ca27e4178a603 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 19 Aug 2007 17:19:44 -0700 Subject: [PATCH 1089/2804] [DCCP]: Nuke the timeval helpers now that we fully converted to ktime_t Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/dccp.h | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 6fbe293bb271..ddacc23be5e8 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -402,45 +402,6 @@ extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb, unsigned char option, const void *value, unsigned char len); -static inline suseconds_t timeval_usecs(const struct timeval *tv) -{ - return tv->tv_sec * USEC_PER_SEC + tv->tv_usec; -} - -static inline suseconds_t timeval_delta(const struct timeval *large, - const struct timeval *small) -{ - time_t secs = large->tv_sec - small->tv_sec; - suseconds_t usecs = large->tv_usec - small->tv_usec; - - if (usecs < 0) { - secs--; - usecs += USEC_PER_SEC; - } - return secs * USEC_PER_SEC + usecs; -} - -static inline void timeval_add_usecs(struct timeval *tv, - const suseconds_t usecs) -{ - tv->tv_usec += usecs; - while (tv->tv_usec >= USEC_PER_SEC) { - tv->tv_sec++; - tv->tv_usec -= USEC_PER_SEC; - } -} - -static inline void timeval_sub_usecs(struct timeval *tv, - const suseconds_t usecs) -{ - tv->tv_usec -= usecs; - while (tv->tv_usec < 0) { - tv->tv_sec--; - tv->tv_usec += USEC_PER_SEC; - } - DCCP_BUG_ON(tv->tv_sec < 0); -} - #ifdef CONFIG_SYSCTL extern int dccp_sysctl_init(void); extern void dccp_sysctl_exit(void); From 79b8b7f4ab686e0f14ceb9a6fa4437eb1e73a0e5 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 12:46:53 -0700 Subject: [PATCH 1090/2804] [XFRM] netlink: Use nlmsg_put() instead of NLMSG_PUT() Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 83 +++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 61339e17a0f5..ec480b69510b 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -588,10 +588,10 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) if (sp->this_idx < sp->start_idx) goto out; - nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, - sp->nlmsg_seq, - XFRM_MSG_NEWSA, sizeof(*p)); - nlh->nlmsg_flags = sp->nlmsg_flags; + nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, + XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); + if (nlh == NULL) + return -EMSGSIZE; p = NLMSG_DATA(nlh); copy_to_user_state(x, p); @@ -633,7 +633,6 @@ out: sp->this_idx++; return 0; -nlmsg_failure: rtattr_failure: nlmsg_trim(skb, b); return -1; @@ -1276,11 +1275,11 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr if (sp->this_idx < sp->start_idx) goto out; - nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, - sp->nlmsg_seq, - XFRM_MSG_NEWPOLICY, sizeof(*p)); + nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, + XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); + if (nlh == NULL) + return -EMSGSIZE; p = NLMSG_DATA(nlh); - nlh->nlmsg_flags = sp->nlmsg_flags; copy_to_user_policy(xp, p, dir); if (copy_to_user_tmpl(xp, skb) < 0) @@ -1449,9 +1448,10 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve struct xfrm_lifetime_cur ltime; unsigned char *b = skb_tail_pointer(skb); - nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); + nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0); + if (nlh == NULL) + return -EMSGSIZE; id = NLMSG_DATA(nlh); - nlh->nlmsg_flags = 0; memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr)); id->sa_id.spi = x->id.spi; @@ -1483,7 +1483,6 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve return skb->len; rtattr_failure: -nlmsg_failure: nlmsg_trim(skb, b); return -1; } @@ -1866,9 +1865,10 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, unsigned char *b = skb_tail_pointer(skb); int i; - nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id)); + nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0); + if (nlh == NULL) + return -EMSGSIZE; pol_id = NLMSG_DATA(nlh); - nlh->nlmsg_flags = 0; /* copy data from selector, dir, and type to the pol_id */ memset(pol_id, 0, sizeof(*pol_id)); @@ -2045,20 +2045,16 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); - nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, - sizeof(*ue)); + nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0); + if (nlh == NULL) + return -EMSGSIZE; ue = NLMSG_DATA(nlh); - nlh->nlmsg_flags = 0; copy_to_user_state(x, &ue->state); ue->hard = (c->data.hard != 0) ? 1 : 0; nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; - -nlmsg_failure: - nlmsg_trim(skb, b); - return -1; } static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) @@ -2108,9 +2104,11 @@ static int xfrm_notify_sa_flush(struct km_event *c) return -ENOMEM; b = skb->tail; - nlh = NLMSG_PUT(skb, c->pid, c->seq, - XFRM_MSG_FLUSHSA, sizeof(*p)); - nlh->nlmsg_flags = 0; + nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0); + if (nlh == NULL) { + kfree_skb(skb); + return -EMSGSIZE; + } p = NLMSG_DATA(nlh); p->proto = c->data.proto; @@ -2119,10 +2117,6 @@ static int xfrm_notify_sa_flush(struct km_event *c) NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); - -nlmsg_failure: - kfree_skb(skb); - return -1; } static inline int xfrm_sa_len(struct xfrm_state *x) @@ -2162,8 +2156,9 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) return -ENOMEM; b = skb->tail; - nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen); - nlh->nlmsg_flags = 0; + nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); + if (nlh == NULL) + goto nlmsg_failure; p = NLMSG_DATA(nlh); if (c->event == XFRM_MSG_DELSA) { @@ -2233,10 +2228,10 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, unsigned char *b = skb_tail_pointer(skb); __u32 seq = xfrm_get_acqseq(); - nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE, - sizeof(*ua)); + nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0); + if (nlh == NULL) + return -EMSGSIZE; ua = NLMSG_DATA(nlh); - nlh->nlmsg_flags = 0; memcpy(&ua->id, &x->id, sizeof(ua->id)); memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); @@ -2352,9 +2347,10 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, int hard = c->data.hard; unsigned char *b = skb_tail_pointer(skb); - nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); + nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0); + if (nlh == NULL) + return -EMSGSIZE; upe = NLMSG_DATA(nlh); - nlh->nlmsg_flags = 0; copy_to_user_policy(xp, &upe->pol, dir); if (copy_to_user_tmpl(xp, skb) < 0) @@ -2420,7 +2416,9 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * return -ENOMEM; b = skb->tail; - nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen); + nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); + if (nlh == NULL) + goto nlmsg_failure; p = NLMSG_DATA(nlh); if (c->event == XFRM_MSG_DELPOLICY) { @@ -2435,8 +2433,6 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * p = RTA_DATA(__RTA_PUT(skb, XFRMA_POLICY, sizeof(*p))); } - nlh->nlmsg_flags = 0; - copy_to_user_policy(xp, p, dir); if (copy_to_user_tmpl(xp, skb) < 0) goto nlmsg_failure; @@ -2471,8 +2467,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) b = skb->tail; - nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); - nlh->nlmsg_flags = 0; + nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0); + if (nlh == NULL) + goto nlmsg_failure; if (copy_to_user_policy_type(c->data.type, skb) < 0) goto nlmsg_failure; @@ -2513,9 +2510,10 @@ static int build_report(struct sk_buff *skb, u8 proto, struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); - nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur)); + nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0); + if (nlh == NULL) + return -EMSGSIZE; ur = NLMSG_DATA(nlh); - nlh->nlmsg_flags = 0; ur->proto = proto; memcpy(&ur->sel, sel, sizeof(ur->sel)); @@ -2526,7 +2524,6 @@ static int build_report(struct sk_buff *skb, u8 proto, nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; -nlmsg_failure: rtattr_failure: nlmsg_trim(skb, b); return -1; From 9825069d09d0201e547e9ee3f3b990cddef68788 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 12:47:26 -0700 Subject: [PATCH 1091/2804] [XFRM] netlink: Use nlmsg_end() and nlmsg_cancel() Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 75 +++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 49 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ec480b69510b..2c74db0c9233 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -583,7 +583,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) struct sk_buff *skb = sp->out_skb; struct xfrm_usersa_info *p; struct nlmsghdr *nlh; - unsigned char *b = skb_tail_pointer(skb); if (sp->this_idx < sp->start_idx) goto out; @@ -628,14 +627,14 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) if (x->lastused) RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); - nlh->nlmsg_len = skb_tail_pointer(skb) - b; + nlmsg_end(skb, nlh); out: sp->this_idx++; return 0; rtattr_failure: - nlmsg_trim(skb, b); - return -1; + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) @@ -1270,7 +1269,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr struct sk_buff *in_skb = sp->in_skb; struct sk_buff *skb = sp->out_skb; struct nlmsghdr *nlh; - unsigned char *b = skb_tail_pointer(skb); if (sp->this_idx < sp->start_idx) goto out; @@ -1289,14 +1287,14 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr if (copy_to_user_policy_type(xp->type, skb) < 0) goto nlmsg_failure; - nlh->nlmsg_len = skb_tail_pointer(skb) - b; + nlmsg_end(skb, nlh); out: sp->this_idx++; return 0; nlmsg_failure: - nlmsg_trim(skb, b); - return -1; + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) @@ -1446,7 +1444,6 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve struct xfrm_aevent_id *id; struct nlmsghdr *nlh; struct xfrm_lifetime_cur ltime; - unsigned char *b = skb_tail_pointer(skb); nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0); if (nlh == NULL) @@ -1479,12 +1476,11 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); } - nlh->nlmsg_len = skb_tail_pointer(skb) - b; - return skb->len; + return nlmsg_end(skb, nlh); rtattr_failure: - nlmsg_trim(skb, b); - return -1; + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -1862,7 +1858,6 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, struct xfrm_migrate *mp; struct xfrm_userpolicy_id *pol_id; struct nlmsghdr *nlh; - unsigned char *b = skb_tail_pointer(skb); int i; nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0); @@ -1883,11 +1878,10 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, goto nlmsg_failure; } - nlh->nlmsg_len = skb_tail_pointer(skb) - b; - return skb->len; + return nlmsg_end(skb, nlh); nlmsg_failure: - nlmsg_trim(skb, b); - return -1; + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, @@ -2043,7 +2037,6 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve { struct xfrm_user_expire *ue; struct nlmsghdr *nlh; - unsigned char *b = skb_tail_pointer(skb); nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0); if (nlh == NULL) @@ -2053,8 +2046,7 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve copy_to_user_state(x, &ue->state); ue->hard = (c->data.hard != 0) ? 1 : 0; - nlh->nlmsg_len = skb_tail_pointer(skb) - b; - return skb->len; + return nlmsg_end(skb, nlh); } static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) @@ -2096,13 +2088,11 @@ static int xfrm_notify_sa_flush(struct km_event *c) struct xfrm_usersa_flush *p; struct nlmsghdr *nlh; struct sk_buff *skb; - sk_buff_data_t b; int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)); skb = alloc_skb(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; - b = skb->tail; nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0); if (nlh == NULL) { @@ -2113,7 +2103,7 @@ static int xfrm_notify_sa_flush(struct km_event *c) p = NLMSG_DATA(nlh); p->proto = c->data.proto; - nlh->nlmsg_len = skb->tail - b; + nlmsg_end(skb, nlh); NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); @@ -2140,7 +2130,6 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) struct xfrm_usersa_id *id; struct nlmsghdr *nlh; struct sk_buff *skb; - sk_buff_data_t b; int len = xfrm_sa_len(x); int headlen; @@ -2154,7 +2143,6 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) skb = alloc_skb(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; - b = skb->tail; nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); if (nlh == NULL) @@ -2185,7 +2173,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) if (x->encap) RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); - nlh->nlmsg_len = skb->tail - b; + nlmsg_end(skb, nlh); NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); @@ -2225,7 +2213,6 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, { struct xfrm_user_acquire *ua; struct nlmsghdr *nlh; - unsigned char *b = skb_tail_pointer(skb); __u32 seq = xfrm_get_acqseq(); nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0); @@ -2249,12 +2236,11 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, if (copy_to_user_policy_type(xp->type, skb) < 0) goto nlmsg_failure; - nlh->nlmsg_len = skb_tail_pointer(skb) - b; - return skb->len; + return nlmsg_end(skb, nlh); nlmsg_failure: - nlmsg_trim(skb, b); - return -1; + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, @@ -2345,7 +2331,6 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, struct xfrm_user_polexpire *upe; struct nlmsghdr *nlh; int hard = c->data.hard; - unsigned char *b = skb_tail_pointer(skb); nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0); if (nlh == NULL) @@ -2361,12 +2346,11 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, goto nlmsg_failure; upe->hard = !!hard; - nlh->nlmsg_len = skb_tail_pointer(skb) - b; - return skb->len; + return nlmsg_end(skb, nlh); nlmsg_failure: - nlmsg_trim(skb, b); - return -1; + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) @@ -2397,7 +2381,6 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * struct xfrm_userpolicy_id *id; struct nlmsghdr *nlh; struct sk_buff *skb; - sk_buff_data_t b; int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); int headlen; @@ -2414,7 +2397,6 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * skb = alloc_skb(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; - b = skb->tail; nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); if (nlh == NULL) @@ -2439,7 +2421,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * if (copy_to_user_policy_type(xp->type, skb) < 0) goto nlmsg_failure; - nlh->nlmsg_len = skb->tail - b; + nlmsg_end(skb, nlh); NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); @@ -2454,7 +2436,6 @@ static int xfrm_notify_policy_flush(struct km_event *c) { struct nlmsghdr *nlh; struct sk_buff *skb; - sk_buff_data_t b; int len = 0; #ifdef CONFIG_XFRM_SUB_POLICY len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); @@ -2464,8 +2445,6 @@ static int xfrm_notify_policy_flush(struct km_event *c) skb = alloc_skb(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; - b = skb->tail; - nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0); if (nlh == NULL) @@ -2473,7 +2452,7 @@ static int xfrm_notify_policy_flush(struct km_event *c) if (copy_to_user_policy_type(c->data.type, skb) < 0) goto nlmsg_failure; - nlh->nlmsg_len = skb->tail - b; + nlmsg_end(skb, nlh); NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); @@ -2508,7 +2487,6 @@ static int build_report(struct sk_buff *skb, u8 proto, { struct xfrm_user_report *ur; struct nlmsghdr *nlh; - unsigned char *b = skb_tail_pointer(skb); nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0); if (nlh == NULL) @@ -2521,12 +2499,11 @@ static int build_report(struct sk_buff *skb, u8 proto, if (addr) RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); - nlh->nlmsg_len = skb_tail_pointer(skb) - b; - return skb->len; + return nlmsg_end(skb, nlh); rtattr_failure: - nlmsg_trim(skb, b); - return -1; + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, From 7b67c8575f1ed0d5fd7524a33d34f5c88c52a194 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:53:52 -0700 Subject: [PATCH 1092/2804] [XFRM] netlink: Use nlmsg_data() instead of NLMSG_DATA() Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 56 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 2c74db0c9233..c9bb7210eb69 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -443,7 +443,7 @@ error_no_put: static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { - struct xfrm_usersa_info *p = NLMSG_DATA(nlh); + struct xfrm_usersa_info *p = nlmsg_data(nlh); struct xfrm_state *x; int err; struct km_event c; @@ -520,7 +520,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct xfrm_state *x; int err = -ESRCH; struct km_event c; - struct xfrm_usersa_id *p = NLMSG_DATA(nlh); + struct xfrm_usersa_id *p = nlmsg_data(nlh); x = xfrm_user_state_lookup(p, xfrma, &err); if (x == NULL) @@ -592,7 +592,7 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) if (nlh == NULL) return -EMSGSIZE; - p = NLMSG_DATA(nlh); + p = nlmsg_data(nlh); copy_to_user_state(x, p); if (x->aalg) @@ -715,7 +715,7 @@ static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { struct sk_buff *r_skb; - u32 *flags = NLMSG_DATA(nlh); + u32 *flags = nlmsg_data(nlh); u32 spid = NETLINK_CB(skb).pid; u32 seq = nlh->nlmsg_seq; int len = NLMSG_LENGTH(sizeof(u32)); @@ -765,7 +765,7 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { struct sk_buff *r_skb; - u32 *flags = NLMSG_DATA(nlh); + u32 *flags = nlmsg_data(nlh); u32 spid = NETLINK_CB(skb).pid; u32 seq = nlh->nlmsg_seq; int len = NLMSG_LENGTH(sizeof(u32)); @@ -787,7 +787,7 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { - struct xfrm_usersa_id *p = NLMSG_DATA(nlh); + struct xfrm_usersa_id *p = nlmsg_data(nlh); struct xfrm_state *x; struct sk_buff *resp_skb; int err = -ESRCH; @@ -841,7 +841,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, int family; int err; - p = NLMSG_DATA(nlh); + p = nlmsg_data(nlh); err = verify_userspi_info(p); if (err) goto out_noput; @@ -1130,7 +1130,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { - struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh); + struct xfrm_userpolicy_info *p = nlmsg_data(nlh); struct xfrm_policy *xp; struct km_event c; int err; @@ -1277,8 +1277,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); if (nlh == NULL) return -EMSGSIZE; - p = NLMSG_DATA(nlh); + p = nlmsg_data(nlh); copy_to_user_policy(xp, p, dir); if (copy_to_user_tmpl(xp, skb) < 0) goto nlmsg_failure; @@ -1351,7 +1351,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, struct km_event c; int delete; - p = NLMSG_DATA(nlh); + p = nlmsg_data(nlh); delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; err = copy_from_user_policy_type(&type, xfrma); @@ -1420,7 +1420,7 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { struct km_event c; - struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); + struct xfrm_usersa_flush *p = nlmsg_data(nlh); struct xfrm_audit audit_info; int err; @@ -1448,8 +1448,8 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0); if (nlh == NULL) return -EMSGSIZE; - id = NLMSG_DATA(nlh); + id = nlmsg_data(nlh); memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr)); id->sa_id.spi = x->id.spi; id->sa_id.family = x->props.family; @@ -1490,7 +1490,7 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, struct sk_buff *r_skb; int err; struct km_event c; - struct xfrm_aevent_id *p = NLMSG_DATA(nlh); + struct xfrm_aevent_id *p = nlmsg_data(nlh); int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); struct xfrm_usersa_id *id = &p->sa_id; @@ -1538,7 +1538,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, struct xfrm_state *x; struct km_event c; int err = - EINVAL; - struct xfrm_aevent_id *p = NLMSG_DATA(nlh); + struct xfrm_aevent_id *p = nlmsg_data(nlh); struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; @@ -1602,7 +1602,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { struct xfrm_policy *xp; - struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); + struct xfrm_user_polexpire *up = nlmsg_data(nlh); struct xfrm_userpolicy_info *p = &up->pol; u8 type = XFRM_POLICY_TYPE_MAIN; int err = -ENOENT; @@ -1664,7 +1664,7 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, { struct xfrm_state *x; int err; - struct xfrm_user_expire *ue = NLMSG_DATA(nlh); + struct xfrm_user_expire *ue = nlmsg_data(nlh); struct xfrm_usersa_info *p = &ue->state; x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); @@ -1699,7 +1699,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, int i; struct rtattr *rt = xfrma[XFRMA_TMPL-1]; - struct xfrm_user_acquire *ua = NLMSG_DATA(nlh); + struct xfrm_user_acquire *ua = nlmsg_data(nlh); struct xfrm_state *x = xfrm_state_alloc(); int err = -ENOMEM; @@ -1794,7 +1794,7 @@ static int copy_from_user_migrate(struct xfrm_migrate *ma, static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { - struct xfrm_userpolicy_id *pi = NLMSG_DATA(nlh); + struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); struct xfrm_migrate m[XFRM_MAX_DEPTH]; u8 type; int err; @@ -1863,8 +1863,8 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0); if (nlh == NULL) return -EMSGSIZE; - pol_id = NLMSG_DATA(nlh); + pol_id = nlmsg_data(nlh); /* copy data from selector, dir, and type to the pol_id */ memset(pol_id, 0, sizeof(*pol_id)); memcpy(&pol_id->sel, sel, sizeof(pol_id->sel)); @@ -2041,8 +2041,8 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0); if (nlh == NULL) return -EMSGSIZE; - ue = NLMSG_DATA(nlh); + ue = nlmsg_data(nlh); copy_to_user_state(x, &ue->state); ue->hard = (c->data.hard != 0) ? 1 : 0; @@ -2100,7 +2100,7 @@ static int xfrm_notify_sa_flush(struct km_event *c) return -EMSGSIZE; } - p = NLMSG_DATA(nlh); + p = nlmsg_data(nlh); p->proto = c->data.proto; nlmsg_end(skb, nlh); @@ -2148,9 +2148,9 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) if (nlh == NULL) goto nlmsg_failure; - p = NLMSG_DATA(nlh); + p = nlmsg_data(nlh); if (c->event == XFRM_MSG_DELSA) { - id = NLMSG_DATA(nlh); + id = nlmsg_data(nlh); memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr)); id->spi = x->id.spi; id->family = x->props.family; @@ -2218,8 +2218,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0); if (nlh == NULL) return -EMSGSIZE; - ua = NLMSG_DATA(nlh); + ua = nlmsg_data(nlh); memcpy(&ua->id, &x->id, sizeof(ua->id)); memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); memcpy(&ua->sel, &x->sel, sizeof(ua->sel)); @@ -2335,8 +2335,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0); if (nlh == NULL) return -EMSGSIZE; - upe = NLMSG_DATA(nlh); + upe = nlmsg_data(nlh); copy_to_user_policy(xp, &upe->pol, dir); if (copy_to_user_tmpl(xp, skb) < 0) goto nlmsg_failure; @@ -2402,9 +2402,9 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * if (nlh == NULL) goto nlmsg_failure; - p = NLMSG_DATA(nlh); + p = nlmsg_data(nlh); if (c->event == XFRM_MSG_DELPOLICY) { - id = NLMSG_DATA(nlh); + id = nlmsg_data(nlh); memset(id, 0, sizeof(*id)); id->dir = dir; if (c->data.byid) @@ -2491,8 +2491,8 @@ static int build_report(struct sk_buff *skb, u8 proto, nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0); if (nlh == NULL) return -EMSGSIZE; - ur = NLMSG_DATA(nlh); + ur = nlmsg_data(nlh); ur->proto = proto; memcpy(&ur->sel, sel, sizeof(ur->sel)); From 082a1ad573b76c8342c1da9d623aaeb5901e440b Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:54:36 -0700 Subject: [PATCH 1093/2804] [XFRM] netlink: Use nlmsg_broadcast() and nlmsg_unicast() This simplifies successful return codes from >0 to 0. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 45 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c9bb7210eb69..249940eaced8 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -800,8 +800,7 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); } else { - err = netlink_unicast(xfrm_nl, resp_skb, - NETLINK_CB(skb).pid, MSG_DONTWAIT); + err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid); } xfrm_state_put(x); out_noput: @@ -882,8 +881,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; } - err = netlink_unicast(xfrm_nl, resp_skb, - NETLINK_CB(skb).pid, MSG_DONTWAIT); + err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid); out: xfrm_state_put(x); @@ -1393,9 +1391,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); } else { - err = netlink_unicast(xfrm_nl, resp_skb, - NETLINK_CB(skb).pid, - MSG_DONTWAIT); + err = nlmsg_unicast(xfrm_nl, resp_skb, + NETLINK_CB(skb).pid); } } else { xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, @@ -1525,8 +1522,7 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, if (build_aevent(r_skb, x, &c) < 0) BUG(); - err = netlink_unicast(xfrm_nl, r_skb, - NETLINK_CB(skb).pid, MSG_DONTWAIT); + err = nlmsg_unicast(xfrm_nl, r_skb, NETLINK_CB(skb).pid); spin_unlock_bh(&x->lock); xfrm_state_put(x); return err; @@ -1903,9 +1899,7 @@ static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0) BUG(); - NETLINK_CB(skb).dst_group = XFRMNLGRP_MIGRATE; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, - GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); } #else static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, @@ -2061,8 +2055,7 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) if (build_expire(skb, x, c) < 0) BUG(); - NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); } static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) @@ -2079,8 +2072,7 @@ static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) if (build_aevent(skb, x, c) < 0) BUG(); - NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); } static int xfrm_notify_sa_flush(struct km_event *c) @@ -2105,8 +2097,7 @@ static int xfrm_notify_sa_flush(struct km_event *c) nlmsg_end(skb, nlh); - NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); } static inline int xfrm_sa_len(struct xfrm_state *x) @@ -2175,8 +2166,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) nlmsg_end(skb, nlh); - NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); nlmsg_failure: rtattr_failure: @@ -2262,8 +2252,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, if (build_acquire(skb, x, xt, xp, dir) < 0) BUG(); - NETLINK_CB(skb).dst_group = XFRMNLGRP_ACQUIRE; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); } /* User gives us xfrm_user_policy_info followed by an array of 0 @@ -2371,8 +2360,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve if (build_polexpire(skb, xp, dir, c) < 0) BUG(); - NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); } static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) @@ -2423,8 +2411,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * nlmsg_end(skb, nlh); - NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); nlmsg_failure: rtattr_failure: @@ -2454,8 +2441,7 @@ static int xfrm_notify_policy_flush(struct km_event *c) nlmsg_end(skb, nlh); - NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); nlmsg_failure: kfree_skb(skb); @@ -2520,8 +2506,7 @@ static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, if (build_report(skb, proto, sel, addr) < 0) BUG(); - NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); + return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); } static struct xfrm_mgr netlink_mgr = { From c0144beaeca42b643f4d1632f2b24fdc6c48a170 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:55:43 -0700 Subject: [PATCH 1094/2804] [XFRM] netlink: Use nla_put()/NLA_PUT() variantes Also makes use of copy_sec_ctx() in another place and removes duplicated code. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 156 +++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 89 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 249940eaced8..24a97b1179f8 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -576,6 +576,27 @@ struct xfrm_dump_info { int this_idx; }; +static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) +{ + int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; + struct xfrm_user_sec_ctx *uctx; + struct nlattr *attr; + + attr = nla_reserve(skb, XFRMA_SEC_CTX, ctx_size); + if (attr == NULL) + return -EMSGSIZE; + + uctx = nla_data(attr); + uctx->exttype = XFRMA_SEC_CTX; + uctx->len = ctx_size; + uctx->ctx_doi = s->ctx_doi; + uctx->ctx_alg = s->ctx_alg; + uctx->ctx_len = s->ctx_len; + memcpy(uctx + 1, s->ctx_str, s->ctx_len); + + return 0; +} + static int dump_one_state(struct xfrm_state *x, int count, void *ptr) { struct xfrm_dump_info *sp = ptr; @@ -596,43 +617,32 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) copy_to_user_state(x, p); if (x->aalg) - RTA_PUT(skb, XFRMA_ALG_AUTH, + NLA_PUT(skb, XFRMA_ALG_AUTH, sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); if (x->ealg) - RTA_PUT(skb, XFRMA_ALG_CRYPT, + NLA_PUT(skb, XFRMA_ALG_CRYPT, sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); if (x->calg) - RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); + NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); if (x->encap) - RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); + NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); - if (x->security) { - int ctx_size = sizeof(struct xfrm_sec_ctx) + - x->security->ctx_len; - struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); - struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); - - uctx->exttype = XFRMA_SEC_CTX; - uctx->len = ctx_size; - uctx->ctx_doi = x->security->ctx_doi; - uctx->ctx_alg = x->security->ctx_alg; - uctx->ctx_len = x->security->ctx_len; - memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); - } + if (x->security && copy_sec_ctx(x->security, skb) < 0) + goto nla_put_failure; if (x->coaddr) - RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); + NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); if (x->lastused) - RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); + NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); nlmsg_end(skb, nlh); out: sp->this_idx++; return 0; -rtattr_failure: +nla_put_failure: nlmsg_cancel(skb, nlh); return -EMSGSIZE; } @@ -1193,32 +1203,9 @@ static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb) up->ealgos = kp->ealgos; up->calgos = kp->calgos; } - RTA_PUT(skb, XFRMA_TMPL, - (sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr), - vec); - return 0; - -rtattr_failure: - return -1; -} - -static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) -{ - int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; - struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); - struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); - - uctx->exttype = XFRMA_SEC_CTX; - uctx->len = ctx_size; - uctx->ctx_doi = s->ctx_doi; - uctx->ctx_alg = s->ctx_alg; - uctx->ctx_len = s->ctx_len; - memcpy(uctx + 1, s->ctx_str, s->ctx_len); - return 0; - - rtattr_failure: - return -1; + return nla_put(skb, XFRMA_TMPL, + sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr, vec); } static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) @@ -1240,17 +1227,11 @@ static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *s #ifdef CONFIG_XFRM_SUB_POLICY static int copy_to_user_policy_type(u8 type, struct sk_buff *skb) { - struct xfrm_userpolicy_type upt; + struct xfrm_userpolicy_type upt = { + .type = type, + }; - memset(&upt, 0, sizeof(upt)); - upt.type = type; - - RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); - - return 0; - -rtattr_failure: - return -1; + return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); } #else @@ -1440,7 +1421,6 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve { struct xfrm_aevent_id *id; struct nlmsghdr *nlh; - struct xfrm_lifetime_cur ltime; nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0); if (nlh == NULL) @@ -1455,27 +1435,19 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve id->reqid = x->props.reqid; id->flags = c->data.aevent; - RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); + NLA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); + NLA_PUT(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft); - ltime.bytes = x->curlft.bytes; - ltime.packets = x->curlft.packets; - ltime.add_time = x->curlft.add_time; - ltime.use_time = x->curlft.use_time; + if (id->flags & XFRM_AE_RTHR) + NLA_PUT_U32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff); - RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime); - - if (id->flags&XFRM_AE_RTHR) { - RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff); - } - - if (id->flags&XFRM_AE_ETHR) { - u32 etimer = x->replay_maxage*10/HZ; - RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); - } + if (id->flags & XFRM_AE_ETHR) + NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH, + x->replay_maxage * 10 / HZ); return nlmsg_end(skb, nlh); -rtattr_failure: +nla_put_failure: nlmsg_cancel(skb, nlh); return -EMSGSIZE; } @@ -1840,11 +1812,7 @@ static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb) memcpy(&um.new_daddr, &m->new_daddr, sizeof(um.new_daddr)); memcpy(&um.new_saddr, &m->new_saddr, sizeof(um.new_saddr)); - RTA_PUT(skb, XFRMA_MIGRATE, sizeof(um), &um); - return 0; - -rtattr_failure: - return -1; + return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um); } static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, @@ -2137,39 +2105,44 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); if (nlh == NULL) - goto nlmsg_failure; + goto nla_put_failure; p = nlmsg_data(nlh); if (c->event == XFRM_MSG_DELSA) { + struct nlattr *attr; + id = nlmsg_data(nlh); memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr)); id->spi = x->id.spi; id->family = x->props.family; id->proto = x->id.proto; - p = RTA_DATA(__RTA_PUT(skb, XFRMA_SA, sizeof(*p))); + attr = nla_reserve(skb, XFRMA_SA, sizeof(*p)); + if (attr == NULL) + goto nla_put_failure; + + p = nla_data(attr); } copy_to_user_state(x, p); if (x->aalg) - RTA_PUT(skb, XFRMA_ALG_AUTH, + NLA_PUT(skb, XFRMA_ALG_AUTH, sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); if (x->ealg) - RTA_PUT(skb, XFRMA_ALG_CRYPT, + NLA_PUT(skb, XFRMA_ALG_CRYPT, sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); if (x->calg) - RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); + NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); if (x->encap) - RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); + NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); nlmsg_end(skb, nlh); return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); -nlmsg_failure: -rtattr_failure: +nla_put_failure: kfree_skb(skb); return -1; } @@ -2392,6 +2365,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * p = nlmsg_data(nlh); if (c->event == XFRM_MSG_DELPOLICY) { + struct nlattr *attr; + id = nlmsg_data(nlh); memset(id, 0, sizeof(*id)); id->dir = dir; @@ -2400,7 +2375,11 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * else memcpy(&id->sel, &xp->selector, sizeof(id->sel)); - p = RTA_DATA(__RTA_PUT(skb, XFRMA_POLICY, sizeof(*p))); + attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p)); + if (attr == NULL) + goto nlmsg_failure; + + p = nla_data(attr); } copy_to_user_policy(xp, p, dir); @@ -2414,7 +2393,6 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); nlmsg_failure: -rtattr_failure: kfree_skb(skb); return -1; } @@ -2483,11 +2461,11 @@ static int build_report(struct sk_buff *skb, u8 proto, memcpy(&ur->sel, sel, sizeof(ur->sel)); if (addr) - RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); + NLA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); return nlmsg_end(skb, nlh); -rtattr_failure: +nla_put_failure: nlmsg_cancel(skb, nlh); return -EMSGSIZE; } From c26445acbc292ab0466407db6d3bdcc5cbe1d03b Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:56:23 -0700 Subject: [PATCH 1095/2804] [XFRM] netlink: Move algorithm length calculation to its own function Adds alg_len() to calculate the properly padded length of an algorithm attribute to simplify the code. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 24a97b1179f8..30e47c678d5e 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -33,6 +33,11 @@ #endif #include +static inline int alg_len(struct xfrm_algo *alg) +{ + return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); +} + static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) { struct rtattr *rt = xfrma[type - 1]; @@ -232,7 +237,6 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, struct rtattr *rta = u_arg; struct xfrm_algo *p, *ualg; struct xfrm_algo_desc *algo; - int len; if (!rta) return 0; @@ -244,8 +248,7 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, return -ENOSYS; *props = algo->desc.sadb_alg_id; - len = sizeof(*ualg) + (ualg->alg_key_len + 7U) / 8; - p = kmemdup(ualg, len, GFP_KERNEL); + p = kmemdup(ualg, alg_len(ualg), GFP_KERNEL); if (!p) return -ENOMEM; @@ -617,11 +620,9 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) copy_to_user_state(x, p); if (x->aalg) - NLA_PUT(skb, XFRMA_ALG_AUTH, - sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); + NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg); if (x->ealg) - NLA_PUT(skb, XFRMA_ALG_CRYPT, - sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); + NLA_PUT(skb, XFRMA_ALG_CRYPT, alg_len(x->ealg), x->ealg); if (x->calg) NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); @@ -2072,9 +2073,9 @@ static inline int xfrm_sa_len(struct xfrm_state *x) { int l = 0; if (x->aalg) - l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8); + l += RTA_SPACE(alg_len(x->aalg)); if (x->ealg) - l += RTA_SPACE(sizeof(*x->ealg) + (x->ealg->alg_key_len+7)/8); + l += RTA_SPACE(alg_len(x->ealg)); if (x->calg) l += RTA_SPACE(sizeof(*x->calg)); if (x->encap) @@ -2127,11 +2128,9 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) copy_to_user_state(x, p); if (x->aalg) - NLA_PUT(skb, XFRMA_ALG_AUTH, - sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); + NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg); if (x->ealg) - NLA_PUT(skb, XFRMA_ALG_CRYPT, - sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); + NLA_PUT(skb, XFRMA_ALG_CRYPT, alg_len(x->ealg), x->ealg); if (x->calg) NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); From cfbfd45a8c4c0c8dd8ed491caefdeffd94acf9e4 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:57:04 -0700 Subject: [PATCH 1096/2804] [XFRM] netlink: Clear up some of the CONFIG_XFRM_SUB_POLICY ifdef mess Moves all of the SUB_POLICY ifdefs related to the attribute size calculation into a function. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 30e47c678d5e..5efaf4582700 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1224,6 +1224,14 @@ static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *s } return 0; } +static inline size_t userpolicy_type_attrsize(void) +{ +#ifdef CONFIG_XFRM_SUB_POLICY + return nla_total_size(sizeof(struct xfrm_userpolicy_type)); +#else + return 0; +#endif +} #ifdef CONFIG_XFRM_SUB_POLICY static int copy_to_user_policy_type(u8 type, struct sk_buff *skb) @@ -1857,9 +1865,7 @@ static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, len = RTA_SPACE(sizeof(struct xfrm_user_migrate) * num_migrate); len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_id)); -#ifdef CONFIG_XFRM_SUB_POLICY - len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); -#endif + len += userpolicy_type_attrsize(); skb = alloc_skb(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2214,9 +2220,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); len += RTA_SPACE(xfrm_user_sec_ctx_size(x->security)); -#ifdef CONFIG_XFRM_SUB_POLICY - len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); -#endif + len += userpolicy_type_attrsize(); skb = alloc_skb(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2322,9 +2326,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); len += RTA_SPACE(xfrm_user_sec_ctx_size(xp->security)); -#ifdef CONFIG_XFRM_SUB_POLICY - len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); -#endif + len += userpolicy_type_attrsize(); skb = alloc_skb(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2349,9 +2351,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * len += RTA_SPACE(headlen); headlen = sizeof(*id); } -#ifdef CONFIG_XFRM_SUB_POLICY - len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); -#endif + len += userpolicy_type_attrsize(); len += NLMSG_SPACE(headlen); skb = alloc_skb(len, GFP_ATOMIC); @@ -2401,9 +2401,7 @@ static int xfrm_notify_policy_flush(struct km_event *c) struct nlmsghdr *nlh; struct sk_buff *skb; int len = 0; -#ifdef CONFIG_XFRM_SUB_POLICY - len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); -#endif + len += userpolicy_type_attrsize(); len += NLMSG_LENGTH(0); skb = alloc_skb(len, GFP_ATOMIC); From 7deb2264909ec82ae4696dd73d8ffce6814c9114 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:57:39 -0700 Subject: [PATCH 1097/2804] [XFRM] netlink: Use nlmsg_new() and type-safe size calculation helpers Moves all complex message size calculation into own inlined helper functions and makes use of the type-safe netlink interface. Using nlmsg_new() simplifies the calculation itself as it takes care of the netlink header length by itself. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 152 +++++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 69 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5efaf4582700..783332987491 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -670,7 +670,7 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, struct xfrm_dump_info info; struct sk_buff *skb; - skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!skb) return ERR_PTR(-ENOMEM); @@ -688,6 +688,13 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, return skb; } +static inline size_t xfrm_spdinfo_msgsize(void) +{ + return NLMSG_ALIGN(4) + + nla_total_size(sizeof(struct xfrmu_spdinfo)) + + nla_total_size(sizeof(struct xfrmu_spdhinfo)); +} + static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) { struct xfrmk_spdinfo si; @@ -729,12 +736,8 @@ static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, u32 *flags = nlmsg_data(nlh); u32 spid = NETLINK_CB(skb).pid; u32 seq = nlh->nlmsg_seq; - int len = NLMSG_LENGTH(sizeof(u32)); - len += RTA_SPACE(sizeof(struct xfrmu_spdinfo)); - len += RTA_SPACE(sizeof(struct xfrmu_spdhinfo)); - - r_skb = alloc_skb(len, GFP_ATOMIC); + r_skb = nlmsg_new(xfrm_spdinfo_msgsize(), GFP_ATOMIC); if (r_skb == NULL) return -ENOMEM; @@ -744,6 +747,13 @@ static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, return nlmsg_unicast(xfrm_nl, r_skb, spid); } +static inline size_t xfrm_sadinfo_msgsize(void) +{ + return NLMSG_ALIGN(4) + + nla_total_size(sizeof(struct xfrmu_sadhinfo)) + + nla_total_size(4); /* XFRMA_SAD_CNT */ +} + static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) { struct xfrmk_sadinfo si; @@ -779,13 +789,8 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, u32 *flags = nlmsg_data(nlh); u32 spid = NETLINK_CB(skb).pid; u32 seq = nlh->nlmsg_seq; - int len = NLMSG_LENGTH(sizeof(u32)); - - len += RTA_SPACE(sizeof(struct xfrmu_sadhinfo)); - len += RTA_SPACE(sizeof(u32)); - - r_skb = alloc_skb(len, GFP_ATOMIC); + r_skb = nlmsg_new(xfrm_sadinfo_msgsize(), GFP_ATOMIC); if (r_skb == NULL) return -ENOMEM; @@ -1311,7 +1316,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, struct xfrm_dump_info info; struct sk_buff *skb; - skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!skb) return ERR_PTR(-ENOMEM); @@ -1425,6 +1430,14 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, return 0; } +static inline size_t xfrm_aevent_msgsize(void) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) + + nla_total_size(sizeof(struct xfrm_replay_state)) + + nla_total_size(sizeof(struct xfrm_lifetime_cur)) + + nla_total_size(4) /* XFRM_AE_RTHR */ + + nla_total_size(4); /* XFRM_AE_ETHR */ +} static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) { @@ -1469,19 +1482,9 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, int err; struct km_event c; struct xfrm_aevent_id *p = nlmsg_data(nlh); - int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); struct xfrm_usersa_id *id = &p->sa_id; - len += RTA_SPACE(sizeof(struct xfrm_replay_state)); - len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); - - if (p->flags&XFRM_AE_RTHR) - len+=RTA_SPACE(sizeof(u32)); - - if (p->flags&XFRM_AE_ETHR) - len+=RTA_SPACE(sizeof(u32)); - - r_skb = alloc_skb(len, GFP_ATOMIC); + r_skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC); if (r_skb == NULL) return -ENOMEM; @@ -1824,6 +1827,13 @@ static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb) return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um); } +static inline size_t xfrm_migrate_msgsize(int num_migrate) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id)) + + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate) + + userpolicy_type_attrsize(); +} + static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, int num_migrate, struct xfrm_selector *sel, u8 dir, u8 type) @@ -1861,12 +1871,8 @@ static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_migrate) { struct sk_buff *skb; - size_t len; - len = RTA_SPACE(sizeof(struct xfrm_user_migrate) * num_migrate); - len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_id)); - len += userpolicy_type_attrsize(); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2002,6 +2008,11 @@ static void xfrm_netlink_rcv(struct sock *sk, int len) } while (qlen); } +static inline size_t xfrm_expire_msgsize(void) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)); +} + static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) { struct xfrm_user_expire *ue; @@ -2021,9 +2032,8 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) { struct sk_buff *skb; - int len = NLMSG_LENGTH(sizeof(struct xfrm_user_expire)); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2036,11 +2046,8 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) { struct sk_buff *skb; - int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); - len += RTA_SPACE(sizeof(struct xfrm_replay_state)); - len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2055,9 +2062,9 @@ static int xfrm_notify_sa_flush(struct km_event *c) struct xfrm_usersa_flush *p; struct nlmsghdr *nlh; struct sk_buff *skb; - int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)); + int len = NLMSG_ALIGN(sizeof(struct xfrm_usersa_flush)); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2075,17 +2082,17 @@ static int xfrm_notify_sa_flush(struct km_event *c) return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); } -static inline int xfrm_sa_len(struct xfrm_state *x) +static inline size_t xfrm_sa_len(struct xfrm_state *x) { - int l = 0; + size_t l = 0; if (x->aalg) - l += RTA_SPACE(alg_len(x->aalg)); + l += nla_total_size(alg_len(x->aalg)); if (x->ealg) - l += RTA_SPACE(alg_len(x->ealg)); + l += nla_total_size(alg_len(x->ealg)); if (x->calg) - l += RTA_SPACE(sizeof(*x->calg)); + l += nla_total_size(sizeof(*x->calg)); if (x->encap) - l += RTA_SPACE(sizeof(*x->encap)); + l += nla_total_size(sizeof(*x->encap)); return l; } @@ -2101,12 +2108,12 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) headlen = sizeof(*p); if (c->event == XFRM_MSG_DELSA) { - len += RTA_SPACE(headlen); + len += nla_total_size(headlen); headlen = sizeof(*id); } - len += NLMSG_SPACE(headlen); + len += NLMSG_ALIGN(headlen); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2175,6 +2182,15 @@ static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) } +static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x, + struct xfrm_policy *xp) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) + + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) + + nla_total_size(xfrm_user_sec_ctx_size(x->security)) + + userpolicy_type_attrsize(); +} + static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, struct xfrm_tmpl *xt, struct xfrm_policy *xp, int dir) @@ -2215,13 +2231,8 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, struct xfrm_policy *xp, int dir) { struct sk_buff *skb; - size_t len; - len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); - len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); - len += RTA_SPACE(xfrm_user_sec_ctx_size(x->security)); - len += userpolicy_type_attrsize(); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2290,6 +2301,14 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, return xp; } +static inline size_t xfrm_polexpire_msgsize(struct xfrm_policy *xp) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire)) + + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) + + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) + + userpolicy_type_attrsize(); +} + static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, int dir, struct km_event *c) { @@ -2321,13 +2340,8 @@ nlmsg_failure: static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) { struct sk_buff *skb; - size_t len; - len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); - len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); - len += RTA_SPACE(xfrm_user_sec_ctx_size(xp->security)); - len += userpolicy_type_attrsize(); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2343,18 +2357,18 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * struct xfrm_userpolicy_id *id; struct nlmsghdr *nlh; struct sk_buff *skb; - int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); + int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); int headlen; headlen = sizeof(*p); if (c->event == XFRM_MSG_DELPOLICY) { - len += RTA_SPACE(headlen); + len += nla_total_size(headlen); headlen = sizeof(*id); } len += userpolicy_type_attrsize(); - len += NLMSG_SPACE(headlen); + len += NLMSG_ALIGN(headlen); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(len, GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2400,11 +2414,8 @@ static int xfrm_notify_policy_flush(struct km_event *c) { struct nlmsghdr *nlh; struct sk_buff *skb; - int len = 0; - len += userpolicy_type_attrsize(); - len += NLMSG_LENGTH(0); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(userpolicy_type_attrsize(), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; @@ -2443,6 +2454,11 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_ev } +static inline size_t xfrm_report_msgsize(void) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_user_report)); +} + static int build_report(struct sk_buff *skb, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) { @@ -2471,10 +2487,8 @@ static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) { struct sk_buff *skb; - size_t len; - len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report))); - skb = alloc_skb(len, GFP_ATOMIC); + skb = nlmsg_new(xfrm_report_msgsize(), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; From a7bd9a45c8c8901f800a461a4098ebae2b8a4b78 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:58:18 -0700 Subject: [PATCH 1098/2804] [XFRM] netlink: Use nlmsg_parse() to parse attributes Uses nlmsg_parse() to parse the attributes. This actually changes behaviour as unknown attributes (type > MAXTYPE) no longer cause an error. Instead unknown attributes will be ignored henceforth to keep older kernels compatible with more recent userspace tools. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 783332987491..9103af02473c 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1890,7 +1890,7 @@ static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, } #endif -#define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) +#define XMSGSIZE(type) sizeof(struct type) static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), @@ -1906,13 +1906,13 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), - [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), + [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0, [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), - [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)), - [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)), + [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32), + [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32), }; #undef XMSGSIZE @@ -1946,9 +1946,9 @@ static struct xfrm_link { static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { - struct rtattr *xfrma[XFRMA_MAX]; + struct nlattr *xfrma[XFRMA_MAX+1]; struct xfrm_link *link; - int type, min_len; + int type, err; type = nlh->nlmsg_type; if (type > XFRM_MSG_MAX) @@ -1970,30 +1970,16 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); } - memset(xfrma, 0, sizeof(xfrma)); - - if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type])) - return -EINVAL; - - if (nlh->nlmsg_len > min_len) { - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - struct rtattr *attr = (void *) nlh + NLMSG_ALIGN(min_len); - - while (RTA_OK(attr, attrlen)) { - unsigned short flavor = attr->rta_type; - if (flavor) { - if (flavor > XFRMA_MAX) - return -EINVAL; - xfrma[flavor - 1] = attr; - } - attr = RTA_NEXT(attr, attrlen); - } - } + /* FIXME: Temporary hack, nlmsg_parse() starts at xfrma[1], old code + * expects first attribute at xfrma[0] */ + err = nlmsg_parse(nlh, xfrm_msg_min[type], xfrma-1, XFRMA_MAX, NULL); + if (err < 0) + return err; if (link->doit == NULL) return -EINVAL; - return link->doit(skb, nlh, xfrma); + return link->doit(skb, nlh, (struct rtattr **) xfrma); } static void xfrm_netlink_rcv(struct sock *sk, int len) From cf5cb79f6946063b04be3df16dcaa781e48bdbef Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:59:04 -0700 Subject: [PATCH 1099/2804] [XFRM] netlink: Establish an attribute policy Adds a policy defining the minimal payload lengths for all the attributes allowing for most attribute validation checks to be removed from in the middle of the code path. Makes updates more consistent as many format errors are recognised earlier, before any changes have been attempted. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 125 +++++++++++-------------------------------- 1 file changed, 31 insertions(+), 94 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 9103af02473c..1371a0ae0606 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -42,19 +42,12 @@ static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) { struct rtattr *rt = xfrma[type - 1]; struct xfrm_algo *algp; - int len; if (!rt) return 0; - len = (rt->rta_len - sizeof(*rt)) - sizeof(*algp); - if (len < 0) - return -EINVAL; - algp = RTA_DATA(rt); - - len -= (algp->alg_key_len + 7U) / 8; - if (len < 0) + if (RTA_PAYLOAD(rt) < alg_len(algp)) return -EINVAL; switch (type) { @@ -82,55 +75,25 @@ static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) return 0; } -static int verify_encap_tmpl(struct rtattr **xfrma) -{ - struct rtattr *rt = xfrma[XFRMA_ENCAP - 1]; - struct xfrm_encap_tmpl *encap; - - if (!rt) - return 0; - - if ((rt->rta_len - sizeof(*rt)) < sizeof(*encap)) - return -EINVAL; - - return 0; -} - -static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, +static void verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, xfrm_address_t **addrp) { struct rtattr *rt = xfrma[type - 1]; - if (!rt) - return 0; - - if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp)) - return -EINVAL; - - if (addrp) + if (rt && addrp) *addrp = RTA_DATA(rt); - - return 0; } static inline int verify_sec_ctx_len(struct rtattr **xfrma) { struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1]; struct xfrm_user_sec_ctx *uctx; - int len = 0; if (!rt) return 0; - if (rt->rta_len < sizeof(*uctx)) - return -EINVAL; - uctx = RTA_DATA(rt); - - len += sizeof(struct xfrm_user_sec_ctx); - len += uctx->ctx_len; - - if (uctx->len != len) + if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len)) return -EINVAL; return 0; @@ -205,12 +168,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, goto out; if ((err = verify_one_alg(xfrma, XFRMA_ALG_COMP))) goto out; - if ((err = verify_encap_tmpl(xfrma))) - goto out; if ((err = verify_sec_ctx_len(xfrma))) goto out; - if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL))) - goto out; err = -EINVAL; switch (p->mode) { @@ -339,9 +298,8 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * * somehow made shareable and move it to xfrm_state.c - JHS * */ -static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) +static void xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) { - int err = - EINVAL; struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; @@ -349,8 +307,6 @@ static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) if (rp) { struct xfrm_replay_state *replay; - if (RTA_PAYLOAD(rp) < sizeof(*replay)) - goto error; replay = RTA_DATA(rp); memcpy(&x->replay, replay, sizeof(*replay)); memcpy(&x->preplay, replay, sizeof(*replay)); @@ -358,8 +314,6 @@ static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) if (lt) { struct xfrm_lifetime_cur *ltime; - if (RTA_PAYLOAD(lt) < sizeof(*ltime)) - goto error; ltime = RTA_DATA(lt); x->curlft.bytes = ltime->bytes; x->curlft.packets = ltime->packets; @@ -367,21 +321,11 @@ static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) x->curlft.use_time = ltime->use_time; } - if (et) { - if (RTA_PAYLOAD(et) < sizeof(u32)) - goto error; + if (et) x->replay_maxage = *(u32*)RTA_DATA(et); - } - if (rt) { - if (RTA_PAYLOAD(rt) < sizeof(u32)) - goto error; + if (rt) x->replay_maxdiff = *(u32*)RTA_DATA(rt); - } - - return 0; -error: - return err; } static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, @@ -429,9 +373,7 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, /* override default values from above */ - err = xfrm_update_ae_params(x, (struct rtattr **)xfrma); - if (err < 0) - goto error; + xfrm_update_ae_params(x, (struct rtattr **)xfrma); return x; @@ -497,10 +439,7 @@ static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, } else { xfrm_address_t *saddr = NULL; - err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); - if (err) - goto out; - + verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); if (!saddr) { err = -EINVAL; goto out; @@ -1072,9 +1011,6 @@ static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) int err; if (rt) { - if (rt->rta_len < sizeof(*upt)) - return -EINVAL; - upt = RTA_DATA(rt); type = upt->type; } @@ -1537,10 +1473,8 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; spin_lock_bh(&x->lock); - err = xfrm_update_ae_params(x, xfrma); + xfrm_update_ae_params(x, xfrma); spin_unlock_bh(&x->lock); - if (err < 0) - goto out; c.event = nlh->nlmsg_type; c.seq = nlh->nlmsg_seq; @@ -1726,20 +1660,6 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, } #ifdef CONFIG_XFRM_MIGRATE -static int verify_user_migrate(struct rtattr **xfrma) -{ - struct rtattr *rt = xfrma[XFRMA_MIGRATE-1]; - struct xfrm_user_migrate *um; - - if (!rt) - return -EINVAL; - - if ((rt->rta_len - sizeof(*rt)) < sizeof(*um)) - return -EINVAL; - - return 0; -} - static int copy_from_user_migrate(struct xfrm_migrate *ma, struct rtattr **xfrma, int *num) { @@ -1780,9 +1700,8 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, int err; int n = 0; - err = verify_user_migrate((struct rtattr **)xfrma); - if (err) - return err; + if (xfrma[XFRMA_MIGRATE-1] == NULL) + return -EINVAL; err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); if (err) @@ -1917,6 +1836,23 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { #undef XMSGSIZE +static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { + [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, + [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, + [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, + [XFRMA_ENCAP] = { .len = sizeof(struct xfrm_encap_tmpl) }, + [XFRMA_TMPL] = { .len = sizeof(struct xfrm_user_tmpl) }, + [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_sec_ctx) }, + [XFRMA_LTIME_VAL] = { .len = sizeof(struct xfrm_lifetime_cur) }, + [XFRMA_REPLAY_VAL] = { .len = sizeof(struct xfrm_replay_state) }, + [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 }, + [XFRMA_ETIMER_THRESH] = { .type = NLA_U32 }, + [XFRMA_SRCADDR] = { .len = sizeof(xfrm_address_t) }, + [XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) }, + [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, + [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, +}; + static struct xfrm_link { int (*doit)(struct sk_buff *, struct nlmsghdr *, struct rtattr **); int (*dump)(struct sk_buff *, struct netlink_callback *); @@ -1972,7 +1908,8 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) /* FIXME: Temporary hack, nlmsg_parse() starts at xfrma[1], old code * expects first attribute at xfrma[0] */ - err = nlmsg_parse(nlh, xfrm_msg_min[type], xfrma-1, XFRMA_MAX, NULL); + err = nlmsg_parse(nlh, xfrm_msg_min[type], xfrma-1, XFRMA_MAX, + xfrma_policy); if (err < 0) return err; From fab448991df4ecca6c244e23982c70f7e715b864 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 13:59:43 -0700 Subject: [PATCH 1100/2804] [XFRM] netlink: Enhance indexing of the attribute array nlmsg_parse() puts attributes at array[type] so the indexing method can be simpilfied by removing the obscuring "- 1". Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 80 +++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 1371a0ae0606..8c323b187e6a 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -40,7 +40,7 @@ static inline int alg_len(struct xfrm_algo *alg) static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) { - struct rtattr *rt = xfrma[type - 1]; + struct rtattr *rt = xfrma[type]; struct xfrm_algo *algp; if (!rt) @@ -78,7 +78,7 @@ static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) static void verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, xfrm_address_t **addrp) { - struct rtattr *rt = xfrma[type - 1]; + struct rtattr *rt = xfrma[type]; if (rt && addrp) *addrp = RTA_DATA(rt); @@ -86,7 +86,7 @@ static void verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, static inline int verify_sec_ctx_len(struct rtattr **xfrma) { - struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1]; + struct rtattr *rt = xfrma[XFRMA_SEC_CTX]; struct xfrm_user_sec_ctx *uctx; if (!rt) @@ -125,35 +125,35 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, err = -EINVAL; switch (p->id.proto) { case IPPROTO_AH: - if (!xfrma[XFRMA_ALG_AUTH-1] || - xfrma[XFRMA_ALG_CRYPT-1] || - xfrma[XFRMA_ALG_COMP-1]) + if (!xfrma[XFRMA_ALG_AUTH] || + xfrma[XFRMA_ALG_CRYPT] || + xfrma[XFRMA_ALG_COMP]) goto out; break; case IPPROTO_ESP: - if ((!xfrma[XFRMA_ALG_AUTH-1] && - !xfrma[XFRMA_ALG_CRYPT-1]) || - xfrma[XFRMA_ALG_COMP-1]) + if ((!xfrma[XFRMA_ALG_AUTH] && + !xfrma[XFRMA_ALG_CRYPT]) || + xfrma[XFRMA_ALG_COMP]) goto out; break; case IPPROTO_COMP: - if (!xfrma[XFRMA_ALG_COMP-1] || - xfrma[XFRMA_ALG_AUTH-1] || - xfrma[XFRMA_ALG_CRYPT-1]) + if (!xfrma[XFRMA_ALG_COMP] || + xfrma[XFRMA_ALG_AUTH] || + xfrma[XFRMA_ALG_CRYPT]) goto out; break; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: - if (xfrma[XFRMA_ALG_COMP-1] || - xfrma[XFRMA_ALG_AUTH-1] || - xfrma[XFRMA_ALG_CRYPT-1] || - xfrma[XFRMA_ENCAP-1] || - xfrma[XFRMA_SEC_CTX-1] || - !xfrma[XFRMA_COADDR-1]) + if (xfrma[XFRMA_ALG_COMP] || + xfrma[XFRMA_ALG_AUTH] || + xfrma[XFRMA_ALG_CRYPT] || + xfrma[XFRMA_ENCAP] || + xfrma[XFRMA_SEC_CTX] || + !xfrma[XFRMA_COADDR]) goto out; break; #endif @@ -300,10 +300,10 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * */ static void xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) { - struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; - struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; - struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; - struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1]; + struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL]; + struct rtattr *lt = xfrma[XFRMA_LTIME_VAL]; + struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH]; + struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH]; if (rp) { struct xfrm_replay_state *replay; @@ -342,25 +342,25 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, xfrm_aalg_get_byname, - xfrma[XFRMA_ALG_AUTH-1]))) + xfrma[XFRMA_ALG_AUTH]))) goto error; if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, xfrm_ealg_get_byname, - xfrma[XFRMA_ALG_CRYPT-1]))) + xfrma[XFRMA_ALG_CRYPT]))) goto error; if ((err = attach_one_algo(&x->calg, &x->props.calgo, xfrm_calg_get_byname, - xfrma[XFRMA_ALG_COMP-1]))) + xfrma[XFRMA_ALG_COMP]))) goto error; - if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) + if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP]))) goto error; - if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1]))) + if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR]))) goto error; err = xfrm_init_state(x); if (err) goto error; - if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX-1]))) + if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX]))) goto error; x->km.seq = p->seq; @@ -917,7 +917,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma) { - struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1]; + struct rtattr *rt = xfrma[XFRMA_SEC_CTX]; struct xfrm_user_sec_ctx *uctx; if (!rt) @@ -985,7 +985,7 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) { - struct rtattr *rt = xfrma[XFRMA_TMPL-1]; + struct rtattr *rt = xfrma[XFRMA_TMPL]; if (!rt) { pol->xfrm_nr = 0; @@ -1005,7 +1005,7 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) { - struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1]; + struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE]; struct xfrm_userpolicy_type *upt; u8 type = XFRM_POLICY_TYPE_MAIN; int err; @@ -1294,7 +1294,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (p->index) xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); else { - struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1]; + struct rtattr *rt = xfrma[XFRMA_SEC_CTX]; struct xfrm_policy tmp; err = verify_sec_ctx_len(xfrma); @@ -1455,8 +1455,8 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, struct km_event c; int err = - EINVAL; struct xfrm_aevent_id *p = nlmsg_data(nlh); - struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; - struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; + struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL]; + struct rtattr *lt = xfrma[XFRMA_LTIME_VAL]; if (!lt && !rp) return err; @@ -1528,7 +1528,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, if (p->index) xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); else { - struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1]; + struct rtattr *rt = xfrma[XFRMA_SEC_CTX]; struct xfrm_policy tmp; err = verify_sec_ctx_len(xfrma); @@ -1611,7 +1611,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, struct xfrm_policy *xp; struct xfrm_user_tmpl *ut; int i; - struct rtattr *rt = xfrma[XFRMA_TMPL-1]; + struct rtattr *rt = xfrma[XFRMA_TMPL]; struct xfrm_user_acquire *ua = nlmsg_data(nlh); struct xfrm_state *x = xfrm_state_alloc(); @@ -1663,7 +1663,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, static int copy_from_user_migrate(struct xfrm_migrate *ma, struct rtattr **xfrma, int *num) { - struct rtattr *rt = xfrma[XFRMA_MIGRATE-1]; + struct rtattr *rt = xfrma[XFRMA_MIGRATE]; struct xfrm_user_migrate *um; int i, num_migrate; @@ -1700,7 +1700,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, int err; int n = 0; - if (xfrma[XFRMA_MIGRATE-1] == NULL) + if (xfrma[XFRMA_MIGRATE] == NULL) return -EINVAL; err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); @@ -1906,9 +1906,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); } - /* FIXME: Temporary hack, nlmsg_parse() starts at xfrma[1], old code - * expects first attribute at xfrma[0] */ - err = nlmsg_parse(nlh, xfrm_msg_min[type], xfrma-1, XFRMA_MAX, + err = nlmsg_parse(nlh, xfrm_msg_min[type], xfrma, XFRMA_MAX, xfrma_policy); if (err < 0) return err; From 35a7aa08bf7863dbfdb0eb69122d8aeaedd52748 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 14:00:40 -0700 Subject: [PATCH 1101/2804] [XFRM] netlink: Rename attribute array from xfrma[] to attrs[] Increases readability a lot. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 188 +++++++++++++++++++++---------------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 8c323b187e6a..7319c7f8060d 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -38,9 +38,9 @@ static inline int alg_len(struct xfrm_algo *alg) return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); } -static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) +static int verify_one_alg(struct rtattr **attrs, enum xfrm_attr_type_t type) { - struct rtattr *rt = xfrma[type]; + struct rtattr *rt = attrs[type]; struct xfrm_algo *algp; if (!rt) @@ -75,18 +75,18 @@ static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) return 0; } -static void verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, +static void verify_one_addr(struct rtattr **attrs, enum xfrm_attr_type_t type, xfrm_address_t **addrp) { - struct rtattr *rt = xfrma[type]; + struct rtattr *rt = attrs[type]; if (rt && addrp) *addrp = RTA_DATA(rt); } -static inline int verify_sec_ctx_len(struct rtattr **xfrma) +static inline int verify_sec_ctx_len(struct rtattr **attrs) { - struct rtattr *rt = xfrma[XFRMA_SEC_CTX]; + struct rtattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_user_sec_ctx *uctx; if (!rt) @@ -101,7 +101,7 @@ static inline int verify_sec_ctx_len(struct rtattr **xfrma) static int verify_newsa_info(struct xfrm_usersa_info *p, - struct rtattr **xfrma) + struct rtattr **attrs) { int err; @@ -125,35 +125,35 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, err = -EINVAL; switch (p->id.proto) { case IPPROTO_AH: - if (!xfrma[XFRMA_ALG_AUTH] || - xfrma[XFRMA_ALG_CRYPT] || - xfrma[XFRMA_ALG_COMP]) + if (!attrs[XFRMA_ALG_AUTH] || + attrs[XFRMA_ALG_CRYPT] || + attrs[XFRMA_ALG_COMP]) goto out; break; case IPPROTO_ESP: - if ((!xfrma[XFRMA_ALG_AUTH] && - !xfrma[XFRMA_ALG_CRYPT]) || - xfrma[XFRMA_ALG_COMP]) + if ((!attrs[XFRMA_ALG_AUTH] && + !attrs[XFRMA_ALG_CRYPT]) || + attrs[XFRMA_ALG_COMP]) goto out; break; case IPPROTO_COMP: - if (!xfrma[XFRMA_ALG_COMP] || - xfrma[XFRMA_ALG_AUTH] || - xfrma[XFRMA_ALG_CRYPT]) + if (!attrs[XFRMA_ALG_COMP] || + attrs[XFRMA_ALG_AUTH] || + attrs[XFRMA_ALG_CRYPT]) goto out; break; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: - if (xfrma[XFRMA_ALG_COMP] || - xfrma[XFRMA_ALG_AUTH] || - xfrma[XFRMA_ALG_CRYPT] || - xfrma[XFRMA_ENCAP] || - xfrma[XFRMA_SEC_CTX] || - !xfrma[XFRMA_COADDR]) + if (attrs[XFRMA_ALG_COMP] || + attrs[XFRMA_ALG_AUTH] || + attrs[XFRMA_ALG_CRYPT] || + attrs[XFRMA_ENCAP] || + attrs[XFRMA_SEC_CTX] || + !attrs[XFRMA_COADDR]) goto out; break; #endif @@ -162,13 +162,13 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, goto out; } - if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH))) + if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) goto out; - if ((err = verify_one_alg(xfrma, XFRMA_ALG_CRYPT))) + if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) goto out; - if ((err = verify_one_alg(xfrma, XFRMA_ALG_COMP))) + if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP))) goto out; - if ((err = verify_sec_ctx_len(xfrma))) + if ((err = verify_sec_ctx_len(attrs))) goto out; err = -EINVAL; @@ -298,12 +298,12 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * * somehow made shareable and move it to xfrm_state.c - JHS * */ -static void xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) +static void xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **attrs) { - struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL]; - struct rtattr *lt = xfrma[XFRMA_LTIME_VAL]; - struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH]; - struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH]; + struct rtattr *rp = attrs[XFRMA_REPLAY_VAL]; + struct rtattr *lt = attrs[XFRMA_LTIME_VAL]; + struct rtattr *et = attrs[XFRMA_ETIMER_THRESH]; + struct rtattr *rt = attrs[XFRMA_REPLAY_THRESH]; if (rp) { struct xfrm_replay_state *replay; @@ -329,7 +329,7 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) } static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, - struct rtattr **xfrma, + struct rtattr **attrs, int *errp) { struct xfrm_state *x = xfrm_state_alloc(); @@ -342,25 +342,25 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, xfrm_aalg_get_byname, - xfrma[XFRMA_ALG_AUTH]))) + attrs[XFRMA_ALG_AUTH]))) goto error; if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, xfrm_ealg_get_byname, - xfrma[XFRMA_ALG_CRYPT]))) + attrs[XFRMA_ALG_CRYPT]))) goto error; if ((err = attach_one_algo(&x->calg, &x->props.calgo, xfrm_calg_get_byname, - xfrma[XFRMA_ALG_COMP]))) + attrs[XFRMA_ALG_COMP]))) goto error; - if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP]))) + if ((err = attach_encap_tmpl(&x->encap, attrs[XFRMA_ENCAP]))) goto error; - if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR]))) + if ((err = attach_one_addr(&x->coaddr, attrs[XFRMA_COADDR]))) goto error; err = xfrm_init_state(x); if (err) goto error; - if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX]))) + if ((err = attach_sec_ctx(x, attrs[XFRMA_SEC_CTX]))) goto error; x->km.seq = p->seq; @@ -373,7 +373,7 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, /* override default values from above */ - xfrm_update_ae_params(x, (struct rtattr **)xfrma); + xfrm_update_ae_params(x, (struct rtattr **)attrs); return x; @@ -386,18 +386,18 @@ error_no_put: } static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_usersa_info *p = nlmsg_data(nlh); struct xfrm_state *x; int err; struct km_event c; - err = verify_newsa_info(p, xfrma); + err = verify_newsa_info(p, attrs); if (err) return err; - x = xfrm_state_construct(p, xfrma, &err); + x = xfrm_state_construct(p, attrs, &err); if (!x) return err; @@ -427,7 +427,7 @@ out: } static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, - struct rtattr **xfrma, + struct rtattr **attrs, int *errp) { struct xfrm_state *x = NULL; @@ -439,7 +439,7 @@ static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, } else { xfrm_address_t *saddr = NULL; - verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); + verify_one_addr(attrs, XFRMA_SRCADDR, &saddr); if (!saddr) { err = -EINVAL; goto out; @@ -457,14 +457,14 @@ static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, } static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_state *x; int err = -ESRCH; struct km_event c; struct xfrm_usersa_id *p = nlmsg_data(nlh); - x = xfrm_user_state_lookup(p, xfrma, &err); + x = xfrm_user_state_lookup(p, attrs, &err); if (x == NULL) return err; @@ -669,7 +669,7 @@ nla_put_failure: } static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct sk_buff *r_skb; u32 *flags = nlmsg_data(nlh); @@ -722,7 +722,7 @@ nla_put_failure: } static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct sk_buff *r_skb; u32 *flags = nlmsg_data(nlh); @@ -740,14 +740,14 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, } static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_usersa_id *p = nlmsg_data(nlh); struct xfrm_state *x; struct sk_buff *resp_skb; int err = -ESRCH; - x = xfrm_user_state_lookup(p, xfrma, &err); + x = xfrm_user_state_lookup(p, attrs, &err); if (x == NULL) goto out_noput; @@ -786,7 +786,7 @@ static int verify_userspi_info(struct xfrm_userspi_info *p) } static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_state *x; struct xfrm_userspi_info *p; @@ -915,9 +915,9 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) return verify_policy_dir(p->dir); } -static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma) +static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **attrs) { - struct rtattr *rt = xfrma[XFRMA_SEC_CTX]; + struct rtattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_user_sec_ctx *uctx; if (!rt) @@ -983,9 +983,9 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) return 0; } -static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) +static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **attrs) { - struct rtattr *rt = xfrma[XFRMA_TMPL]; + struct rtattr *rt = attrs[XFRMA_TMPL]; if (!rt) { pol->xfrm_nr = 0; @@ -1003,9 +1003,9 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) return 0; } -static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) +static int copy_from_user_policy_type(u8 *tp, struct rtattr **attrs) { - struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE]; + struct rtattr *rt = attrs[XFRMA_POLICY_TYPE]; struct xfrm_userpolicy_type *upt; u8 type = XFRM_POLICY_TYPE_MAIN; int err; @@ -1049,7 +1049,7 @@ static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_i p->share = XFRM_SHARE_ANY; /* XXX xp->share */ } -static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp) +static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **attrs, int *errp) { struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL); int err; @@ -1061,12 +1061,12 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, copy_from_user_policy(xp, p); - err = copy_from_user_policy_type(&xp->type, xfrma); + err = copy_from_user_policy_type(&xp->type, attrs); if (err) goto error; - if (!(err = copy_from_user_tmpl(xp, xfrma))) - err = copy_from_user_sec_ctx(xp, xfrma); + if (!(err = copy_from_user_tmpl(xp, attrs))) + err = copy_from_user_sec_ctx(xp, attrs); if (err) goto error; @@ -1078,7 +1078,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, } static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_userpolicy_info *p = nlmsg_data(nlh); struct xfrm_policy *xp; @@ -1089,11 +1089,11 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, err = verify_newpolicy_info(p); if (err) return err; - err = verify_sec_ctx_len(xfrma); + err = verify_sec_ctx_len(attrs); if (err) return err; - xp = xfrm_policy_construct(p, xfrma, &err); + xp = xfrm_policy_construct(p, attrs, &err); if (!xp) return err; @@ -1271,7 +1271,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, } static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_policy *xp; struct xfrm_userpolicy_id *p; @@ -1283,7 +1283,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, p = nlmsg_data(nlh); delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; - err = copy_from_user_policy_type(&type, xfrma); + err = copy_from_user_policy_type(&type, attrs); if (err) return err; @@ -1294,10 +1294,10 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (p->index) xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); else { - struct rtattr *rt = xfrma[XFRMA_SEC_CTX]; + struct rtattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_policy tmp; - err = verify_sec_ctx_len(xfrma); + err = verify_sec_ctx_len(attrs); if (err) return err; @@ -1345,7 +1345,7 @@ out: } static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct km_event c; struct xfrm_usersa_flush *p = nlmsg_data(nlh); @@ -1411,7 +1411,7 @@ nla_put_failure: } static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_state *x; struct sk_buff *r_skb; @@ -1449,14 +1449,14 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, } static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_state *x; struct km_event c; int err = - EINVAL; struct xfrm_aevent_id *p = nlmsg_data(nlh); - struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL]; - struct rtattr *lt = xfrma[XFRMA_LTIME_VAL]; + struct rtattr *rp = attrs[XFRMA_REPLAY_VAL]; + struct rtattr *lt = attrs[XFRMA_LTIME_VAL]; if (!lt && !rp) return err; @@ -1473,7 +1473,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; spin_lock_bh(&x->lock); - xfrm_update_ae_params(x, xfrma); + xfrm_update_ae_params(x, attrs); spin_unlock_bh(&x->lock); c.event = nlh->nlmsg_type; @@ -1488,14 +1488,14 @@ out: } static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct km_event c; u8 type = XFRM_POLICY_TYPE_MAIN; int err; struct xfrm_audit audit_info; - err = copy_from_user_policy_type(&type, xfrma); + err = copy_from_user_policy_type(&type, attrs); if (err) return err; @@ -1513,7 +1513,7 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, } static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_policy *xp; struct xfrm_user_polexpire *up = nlmsg_data(nlh); @@ -1521,17 +1521,17 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, u8 type = XFRM_POLICY_TYPE_MAIN; int err = -ENOENT; - err = copy_from_user_policy_type(&type, xfrma); + err = copy_from_user_policy_type(&type, attrs); if (err) return err; if (p->index) xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); else { - struct rtattr *rt = xfrma[XFRMA_SEC_CTX]; + struct rtattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_policy tmp; - err = verify_sec_ctx_len(xfrma); + err = verify_sec_ctx_len(attrs); if (err) return err; @@ -1574,7 +1574,7 @@ out: } static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_state *x; int err; @@ -1606,12 +1606,12 @@ out: } static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_policy *xp; struct xfrm_user_tmpl *ut; int i; - struct rtattr *rt = xfrma[XFRMA_TMPL]; + struct rtattr *rt = attrs[XFRMA_TMPL]; struct xfrm_user_acquire *ua = nlmsg_data(nlh); struct xfrm_state *x = xfrm_state_alloc(); @@ -1628,7 +1628,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, } /* build an XP */ - xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); + xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) attrs, &err); if (!xp) { kfree(x); return err; @@ -1661,9 +1661,9 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, #ifdef CONFIG_XFRM_MIGRATE static int copy_from_user_migrate(struct xfrm_migrate *ma, - struct rtattr **xfrma, int *num) + struct rtattr **attrs, int *num) { - struct rtattr *rt = xfrma[XFRMA_MIGRATE]; + struct rtattr *rt = attrs[XFRMA_MIGRATE]; struct xfrm_user_migrate *um; int i, num_migrate; @@ -1692,7 +1692,7 @@ static int copy_from_user_migrate(struct xfrm_migrate *ma, } static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); struct xfrm_migrate m[XFRM_MAX_DEPTH]; @@ -1700,15 +1700,15 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, int err; int n = 0; - if (xfrma[XFRMA_MIGRATE] == NULL) + if (attrs[XFRMA_MIGRATE] == NULL) return -EINVAL; - err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); + err = copy_from_user_policy_type(&type, (struct rtattr **)attrs); if (err) return err; err = copy_from_user_migrate((struct xfrm_migrate *)m, - (struct rtattr **)xfrma, &n); + (struct rtattr **)attrs, &n); if (err) return err; @@ -1721,7 +1721,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, } #else static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **xfrma) + struct rtattr **attrs) { return -ENOPROTOOPT; } @@ -1882,7 +1882,7 @@ static struct xfrm_link { static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { - struct nlattr *xfrma[XFRMA_MAX+1]; + struct nlattr *attrs[XFRMA_MAX+1]; struct xfrm_link *link; int type, err; @@ -1906,7 +1906,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); } - err = nlmsg_parse(nlh, xfrm_msg_min[type], xfrma, XFRMA_MAX, + err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, xfrma_policy); if (err < 0) return err; @@ -1914,7 +1914,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->doit == NULL) return -EINVAL; - return link->doit(skb, nlh, (struct rtattr **) xfrma); + return link->doit(skb, nlh, (struct rtattr **) attrs); } static void xfrm_netlink_rcv(struct sock *sk, int len) From 5424f32e484b9697808bbc0c0088dc2ead018d4f Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 14:01:33 -0700 Subject: [PATCH 1102/2804] [XFRM] netlink: Use nlattr instead of rtattr Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 157 +++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 80 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7319c7f8060d..e46bcf02ac69 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -38,16 +38,16 @@ static inline int alg_len(struct xfrm_algo *alg) return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); } -static int verify_one_alg(struct rtattr **attrs, enum xfrm_attr_type_t type) +static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) { - struct rtattr *rt = attrs[type]; + struct nlattr *rt = attrs[type]; struct xfrm_algo *algp; if (!rt) return 0; - algp = RTA_DATA(rt); - if (RTA_PAYLOAD(rt) < alg_len(algp)) + algp = nla_data(rt); + if (nla_len(rt) < alg_len(algp)) return -EINVAL; switch (type) { @@ -75,24 +75,24 @@ static int verify_one_alg(struct rtattr **attrs, enum xfrm_attr_type_t type) return 0; } -static void verify_one_addr(struct rtattr **attrs, enum xfrm_attr_type_t type, +static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, xfrm_address_t **addrp) { - struct rtattr *rt = attrs[type]; + struct nlattr *rt = attrs[type]; if (rt && addrp) - *addrp = RTA_DATA(rt); + *addrp = nla_data(rt); } -static inline int verify_sec_ctx_len(struct rtattr **attrs) +static inline int verify_sec_ctx_len(struct nlattr **attrs) { - struct rtattr *rt = attrs[XFRMA_SEC_CTX]; + struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_user_sec_ctx *uctx; if (!rt) return 0; - uctx = RTA_DATA(rt); + uctx = nla_data(rt); if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len)) return -EINVAL; @@ -101,7 +101,7 @@ static inline int verify_sec_ctx_len(struct rtattr **attrs) static int verify_newsa_info(struct xfrm_usersa_info *p, - struct rtattr **attrs) + struct nlattr **attrs) { int err; @@ -191,16 +191,15 @@ out: static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, struct xfrm_algo_desc *(*get_byname)(char *, int), - struct rtattr *u_arg) + struct nlattr *rta) { - struct rtattr *rta = u_arg; struct xfrm_algo *p, *ualg; struct xfrm_algo_desc *algo; if (!rta) return 0; - ualg = RTA_DATA(rta); + ualg = nla_data(rta); algo = get_byname(ualg->alg_name, 1); if (!algo) @@ -216,15 +215,14 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, return 0; } -static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_arg) +static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct nlattr *rta) { - struct rtattr *rta = u_arg; struct xfrm_encap_tmpl *p, *uencap; if (!rta) return 0; - uencap = RTA_DATA(rta); + uencap = nla_data(rta); p = kmemdup(uencap, sizeof(*p), GFP_KERNEL); if (!p) return -ENOMEM; @@ -245,26 +243,25 @@ static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) return len; } -static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) +static int attach_sec_ctx(struct xfrm_state *x, struct nlattr *u_arg) { struct xfrm_user_sec_ctx *uctx; if (!u_arg) return 0; - uctx = RTA_DATA(u_arg); + uctx = nla_data(u_arg); return security_xfrm_state_alloc(x, uctx); } -static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg) +static int attach_one_addr(xfrm_address_t **addrpp, struct nlattr *rta) { - struct rtattr *rta = u_arg; xfrm_address_t *p, *uaddrp; if (!rta) return 0; - uaddrp = RTA_DATA(rta); + uaddrp = nla_data(rta); p = kmemdup(uaddrp, sizeof(*p), GFP_KERNEL); if (!p) return -ENOMEM; @@ -298,23 +295,23 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * * somehow made shareable and move it to xfrm_state.c - JHS * */ -static void xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **attrs) +static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs) { - struct rtattr *rp = attrs[XFRMA_REPLAY_VAL]; - struct rtattr *lt = attrs[XFRMA_LTIME_VAL]; - struct rtattr *et = attrs[XFRMA_ETIMER_THRESH]; - struct rtattr *rt = attrs[XFRMA_REPLAY_THRESH]; + struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; + struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; + struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; + struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; if (rp) { struct xfrm_replay_state *replay; - replay = RTA_DATA(rp); + replay = nla_data(rp); memcpy(&x->replay, replay, sizeof(*replay)); memcpy(&x->preplay, replay, sizeof(*replay)); } if (lt) { struct xfrm_lifetime_cur *ltime; - ltime = RTA_DATA(lt); + ltime = nla_data(lt); x->curlft.bytes = ltime->bytes; x->curlft.packets = ltime->packets; x->curlft.add_time = ltime->add_time; @@ -322,14 +319,14 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **attrs) } if (et) - x->replay_maxage = *(u32*)RTA_DATA(et); + x->replay_maxage = nla_get_u32(et); if (rt) - x->replay_maxdiff = *(u32*)RTA_DATA(rt); + x->replay_maxdiff = nla_get_u32(rt); } static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, - struct rtattr **attrs, + struct nlattr **attrs, int *errp) { struct xfrm_state *x = xfrm_state_alloc(); @@ -373,7 +370,7 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, /* override default values from above */ - xfrm_update_ae_params(x, (struct rtattr **)attrs); + xfrm_update_ae_params(x, attrs); return x; @@ -386,7 +383,7 @@ error_no_put: } static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_usersa_info *p = nlmsg_data(nlh); struct xfrm_state *x; @@ -427,7 +424,7 @@ out: } static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, - struct rtattr **attrs, + struct nlattr **attrs, int *errp) { struct xfrm_state *x = NULL; @@ -457,7 +454,7 @@ static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, } static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_state *x; int err = -ESRCH; @@ -669,7 +666,7 @@ nla_put_failure: } static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct sk_buff *r_skb; u32 *flags = nlmsg_data(nlh); @@ -722,7 +719,7 @@ nla_put_failure: } static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct sk_buff *r_skb; u32 *flags = nlmsg_data(nlh); @@ -740,7 +737,7 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, } static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_usersa_id *p = nlmsg_data(nlh); struct xfrm_state *x; @@ -786,7 +783,7 @@ static int verify_userspi_info(struct xfrm_userspi_info *p) } static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_state *x; struct xfrm_userspi_info *p; @@ -915,15 +912,15 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) return verify_policy_dir(p->dir); } -static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **attrs) +static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs) { - struct rtattr *rt = attrs[XFRMA_SEC_CTX]; + struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_user_sec_ctx *uctx; if (!rt) return 0; - uctx = RTA_DATA(rt); + uctx = nla_data(rt); return security_xfrm_policy_alloc(pol, uctx); } @@ -983,35 +980,35 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) return 0; } -static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **attrs) +static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs) { - struct rtattr *rt = attrs[XFRMA_TMPL]; + struct nlattr *rt = attrs[XFRMA_TMPL]; if (!rt) { pol->xfrm_nr = 0; } else { - struct xfrm_user_tmpl *utmpl = RTA_DATA(rt); - int nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); + struct xfrm_user_tmpl *utmpl = nla_data(rt); + int nr = nla_len(rt) / sizeof(*utmpl); int err; err = validate_tmpl(nr, utmpl, pol->family); if (err) return err; - copy_templates(pol, RTA_DATA(rt), nr); + copy_templates(pol, utmpl, nr); } return 0; } -static int copy_from_user_policy_type(u8 *tp, struct rtattr **attrs) +static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs) { - struct rtattr *rt = attrs[XFRMA_POLICY_TYPE]; + struct nlattr *rt = attrs[XFRMA_POLICY_TYPE]; struct xfrm_userpolicy_type *upt; u8 type = XFRM_POLICY_TYPE_MAIN; int err; if (rt) { - upt = RTA_DATA(rt); + upt = nla_data(rt); type = upt->type; } @@ -1049,7 +1046,7 @@ static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_i p->share = XFRM_SHARE_ANY; /* XXX xp->share */ } -static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **attrs, int *errp) +static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp) { struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL); int err; @@ -1078,7 +1075,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, } static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_userpolicy_info *p = nlmsg_data(nlh); struct xfrm_policy *xp; @@ -1271,7 +1268,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, } static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_policy *xp; struct xfrm_userpolicy_id *p; @@ -1294,7 +1291,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (p->index) xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); else { - struct rtattr *rt = attrs[XFRMA_SEC_CTX]; + struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_policy tmp; err = verify_sec_ctx_len(attrs); @@ -1303,7 +1300,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, memset(&tmp, 0, sizeof(struct xfrm_policy)); if (rt) { - struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); + struct xfrm_user_sec_ctx *uctx = nla_data(rt); if ((err = security_xfrm_policy_alloc(&tmp, uctx))) return err; @@ -1345,7 +1342,7 @@ out: } static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct km_event c; struct xfrm_usersa_flush *p = nlmsg_data(nlh); @@ -1411,7 +1408,7 @@ nla_put_failure: } static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_state *x; struct sk_buff *r_skb; @@ -1449,14 +1446,14 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, } static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_state *x; struct km_event c; int err = - EINVAL; struct xfrm_aevent_id *p = nlmsg_data(nlh); - struct rtattr *rp = attrs[XFRMA_REPLAY_VAL]; - struct rtattr *lt = attrs[XFRMA_LTIME_VAL]; + struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; + struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; if (!lt && !rp) return err; @@ -1488,7 +1485,7 @@ out: } static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct km_event c; u8 type = XFRM_POLICY_TYPE_MAIN; @@ -1513,7 +1510,7 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, } static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_policy *xp; struct xfrm_user_polexpire *up = nlmsg_data(nlh); @@ -1528,7 +1525,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, if (p->index) xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); else { - struct rtattr *rt = attrs[XFRMA_SEC_CTX]; + struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_policy tmp; err = verify_sec_ctx_len(attrs); @@ -1537,7 +1534,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, memset(&tmp, 0, sizeof(struct xfrm_policy)); if (rt) { - struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); + struct xfrm_user_sec_ctx *uctx = nla_data(rt); if ((err = security_xfrm_policy_alloc(&tmp, uctx))) return err; @@ -1574,7 +1571,7 @@ out: } static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_state *x; int err; @@ -1606,12 +1603,12 @@ out: } static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_policy *xp; struct xfrm_user_tmpl *ut; int i; - struct rtattr *rt = attrs[XFRMA_TMPL]; + struct nlattr *rt = attrs[XFRMA_TMPL]; struct xfrm_user_acquire *ua = nlmsg_data(nlh); struct xfrm_state *x = xfrm_state_alloc(); @@ -1628,7 +1625,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, } /* build an XP */ - xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) attrs, &err); + xp = xfrm_policy_construct(&ua->policy, attrs, &err); if (!xp) { kfree(x); return err; @@ -1638,7 +1635,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); - ut = RTA_DATA(rt); + ut = nla_data(rt); /* extract the templates and for each call km_key */ for (i = 0; i < xp->xfrm_nr; i++, ut++) { struct xfrm_tmpl *t = &xp->xfrm_vec[i]; @@ -1661,14 +1658,14 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, #ifdef CONFIG_XFRM_MIGRATE static int copy_from_user_migrate(struct xfrm_migrate *ma, - struct rtattr **attrs, int *num) + struct nlattr **attrs, int *num) { - struct rtattr *rt = attrs[XFRMA_MIGRATE]; + struct nlattr *rt = attrs[XFRMA_MIGRATE]; struct xfrm_user_migrate *um; int i, num_migrate; - um = RTA_DATA(rt); - num_migrate = (rt->rta_len - sizeof(*rt)) / sizeof(*um); + um = nla_data(rt); + num_migrate = nla_len(rt) / sizeof(*um); if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH) return -EINVAL; @@ -1692,7 +1689,7 @@ static int copy_from_user_migrate(struct xfrm_migrate *ma, } static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); struct xfrm_migrate m[XFRM_MAX_DEPTH]; @@ -1703,12 +1700,12 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, if (attrs[XFRMA_MIGRATE] == NULL) return -EINVAL; - err = copy_from_user_policy_type(&type, (struct rtattr **)attrs); + err = copy_from_user_policy_type(&type, attrs); if (err) return err; err = copy_from_user_migrate((struct xfrm_migrate *)m, - (struct rtattr **)attrs, &n); + attrs, &n); if (err) return err; @@ -1721,7 +1718,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, } #else static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, - struct rtattr **attrs) + struct nlattr **attrs) { return -ENOPROTOOPT; } @@ -1854,7 +1851,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { }; static struct xfrm_link { - int (*doit)(struct sk_buff *, struct nlmsghdr *, struct rtattr **); + int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); int (*dump)(struct sk_buff *, struct netlink_callback *); } xfrm_dispatch[XFRM_NR_MSGTYPES] = { [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, @@ -1914,7 +1911,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->doit == NULL) return -EINVAL; - return link->doit(skb, nlh, (struct rtattr **) attrs); + return link->doit(skb, nlh, attrs); } static void xfrm_netlink_rcv(struct sock *sk, int len) From 15901a2746e6a2dbe03043609f1575c2bcf726e8 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Aug 2007 14:02:39 -0700 Subject: [PATCH 1103/2804] [XFRM] netlink: Remove dependency on rtnetlink Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index e46bcf02ac69..70dca1e48242 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include From fd21150a0fe10c504160db359a4eb425576f6e7d Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 6 Sep 2007 03:28:08 -0700 Subject: [PATCH 1104/2804] [XFRM] netlink: Inline attach_encap_tmpl(), attach_sec_ctx(), and attach_one_addr() These functions are only used once and are a lot easier to understand if inlined directly into the function. Fixes by Masahide NAKAMURA. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 66 ++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 49 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 70dca1e48242..9e516f5cbb5e 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -214,23 +214,6 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, return 0; } -static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct nlattr *rta) -{ - struct xfrm_encap_tmpl *p, *uencap; - - if (!rta) - return 0; - - uencap = nla_data(rta); - p = kmemdup(uencap, sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - *encapp = p; - return 0; -} - - static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) { int len = 0; @@ -242,33 +225,6 @@ static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) return len; } -static int attach_sec_ctx(struct xfrm_state *x, struct nlattr *u_arg) -{ - struct xfrm_user_sec_ctx *uctx; - - if (!u_arg) - return 0; - - uctx = nla_data(u_arg); - return security_xfrm_state_alloc(x, uctx); -} - -static int attach_one_addr(xfrm_address_t **addrpp, struct nlattr *rta) -{ - xfrm_address_t *p, *uaddrp; - - if (!rta) - return 0; - - uaddrp = nla_data(rta); - p = kmemdup(uaddrp, sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - *addrpp = p; - return 0; -} - static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) { memcpy(&x->id, &p->id, sizeof(x->id)); @@ -348,15 +304,27 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, xfrm_calg_get_byname, attrs[XFRMA_ALG_COMP]))) goto error; - if ((err = attach_encap_tmpl(&x->encap, attrs[XFRMA_ENCAP]))) - goto error; - if ((err = attach_one_addr(&x->coaddr, attrs[XFRMA_COADDR]))) - goto error; + + if (attrs[XFRMA_ENCAP]) { + x->encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]), + sizeof(*x->encap), GFP_KERNEL); + if (x->encap == NULL) + goto error; + } + + if (attrs[XFRMA_COADDR]) { + x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]), + sizeof(*x->coaddr), GFP_KERNEL); + if (x->coaddr == NULL) + goto error; + } + err = xfrm_init_state(x); if (err) goto error; - if ((err = attach_sec_ctx(x, attrs[XFRMA_SEC_CTX]))) + if (attrs[XFRMA_SEC_CTX] && + security_xfrm_state_alloc(x, nla_data(attrs[XFRMA_SEC_CTX]))) goto error; x->km.seq = p->seq; From 23f1f4eff85d3d2ec9ed589e3fdcbba59eaa083e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Aug 2007 22:35:44 -0700 Subject: [PATCH 1105/2804] [NET] ethernet: optimize memcpy and memset The ethernet header management only needs to handle a fixed size address (6 bytes). If the memcpy/memset are changed to be passed a constant length, then compiler can optimize for this case (and if it is smart eliminate string instructions). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ethernet/eth.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 12c765715acf..57c592ed0105 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -91,10 +91,10 @@ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, if (!saddr) saddr = dev->dev_addr; - memcpy(eth->h_source, saddr, dev->addr_len); + memcpy(eth->h_source, saddr, ETH_ALEN); if (daddr) { - memcpy(eth->h_dest, daddr, dev->addr_len); + memcpy(eth->h_dest, daddr, ETH_ALEN); return ETH_HLEN; } @@ -103,7 +103,7 @@ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, */ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { - memset(eth->h_dest, 0, dev->addr_len); + memset(eth->h_dest, 0, ETH_ALEN); return ETH_HLEN; } @@ -135,7 +135,7 @@ int eth_rebuild_header(struct sk_buff *skb) "%s: unable to resolve type %X addresses.\n", dev->name, (int)eth->h_proto); - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); break; } @@ -233,8 +233,8 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) return -1; eth->h_proto = type; - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - memcpy(eth->h_dest, neigh->ha, dev->addr_len); + memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); + memcpy(eth->h_dest, neigh->ha, ETH_ALEN); hh->hh_len = ETH_HLEN; return 0; } @@ -251,7 +251,7 @@ void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char *haddr) { memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), - haddr, dev->addr_len); + haddr, ETH_ALEN); } /** @@ -271,7 +271,7 @@ static int eth_mac_addr(struct net_device *dev, void *p) return -EBUSY; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); return 0; } From 522400623e240ad134cb4101b1fddc3245d2a7ed Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 28 Aug 2007 15:22:09 -0700 Subject: [PATCH 1106/2804] [ATM]: Replace DPRINTK() with pr_debug(). Get rid of using DPRINTK macro in ATM and use pr_debug (in kernel.h). Using the standard macro is cleaner and forces code to check for bad arguments and formatting. Fixes from Thomas Graf. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/atm/br2684.c | 28 +++++------- net/atm/clip.c | 62 ++++++++++++-------------- net/atm/common.c | 23 ++++------ net/atm/lec.c | 104 +++++++++++++++++++++----------------------- net/atm/pppoatm.c | 23 +++------- net/atm/raw.c | 12 +---- net/atm/signaling.c | 25 ++++------- net/atm/svc.c | 25 ++++------- 8 files changed, 120 insertions(+), 182 deletions(-) diff --git a/net/atm/br2684.c b/net/atm/br2684.c index c0f6861eefe3..81eb4f4cbe10 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -34,12 +34,6 @@ Author: Marcell GAL, 2000, XDSL Ltd, Hungary */ /* #define FASTER_VERSION */ -#ifdef DEBUG -#define DPRINTK(format, args...) printk(KERN_DEBUG "br2684: " format, ##args) -#else -#define DPRINTK(format, args...) -#endif - #ifdef SKB_DEBUG static void skb_debug(const struct sk_buff *skb) { @@ -180,7 +174,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev, skb_debug(skb); ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; - DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); + 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 point it supplied wasn't freed yet. @@ -209,11 +203,11 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) struct br2684_dev *brdev = BRPRIV(dev); struct br2684_vcc *brvcc; - DPRINTK("br2684_start_xmit, skb->dst=%p\n", skb->dst); + pr_debug("br2684_start_xmit, skb->dst=%p\n", skb->dst); read_lock(&devs_lock); brvcc = pick_outgoing_vcc(skb, brdev); if (brvcc == NULL) { - DPRINTK("no vcc attached to dev %s\n", dev->name); + pr_debug("no vcc attached to dev %s\n", dev->name); brdev->stats.tx_errors++; brdev->stats.tx_carrier_errors++; /* netif_stop_queue(dev); */ @@ -239,7 +233,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *br2684_get_stats(struct net_device *dev) { - DPRINTK("br2684_get_stats\n"); + pr_debug("br2684_get_stats\n"); return &BRPRIV(dev)->stats; } @@ -390,7 +384,7 @@ packet_fails_filter(__be16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) static void br2684_close_vcc(struct br2684_vcc *brvcc) { - DPRINTK("removing VCC %p from dev %p\n", brvcc, brvcc->device); + pr_debug("removing VCC %p from dev %p\n", brvcc, brvcc->device); write_lock_irq(&devs_lock); list_del(&brvcc->brvccs); write_unlock_irq(&devs_lock); @@ -408,7 +402,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) struct br2684_dev *brdev = BRPRIV(net_dev); int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN; - DPRINTK("br2684_push\n"); + pr_debug("br2684_push\n"); if (unlikely(skb == NULL)) { /* skb==NULL means VCC is being destroyed */ @@ -425,7 +419,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) skb_debug(skb); atm_return(atmvcc, skb->truesize); - DPRINTK("skb from brdev %p\n", brdev); + pr_debug("skb from brdev %p\n", brdev); if (brvcc->encaps == e_llc) { /* let us waste some time for checking the encapsulation. Note, that only 7 char is checked so frames with a valid FCS @@ -474,7 +468,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) #endif /* CONFIG_ATM_BR2684_IPFILTER */ skb->dev = net_dev; ATM_SKB(skb)->vcc = atmvcc; /* needed ? */ - DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol)); + pr_debug("received packet's protocol: %x\n", ntohs(skb->protocol)); skb_debug(skb); if (unlikely(!(net_dev->flags & IFF_UP))) { /* sigh, interface is down */ @@ -532,7 +526,7 @@ Note: we do not have explicit unassign, but look at _push() err = -EINVAL; goto error; } - DPRINTK("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, + pr_debug("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, brvcc); if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { unsigned char *esi = atmvcc->dev->esi; @@ -612,7 +606,7 @@ static int br2684_create(void __user *arg) struct br2684_dev *brdev; struct atm_newif_br2684 ni; - DPRINTK("br2684_create\n"); + pr_debug("br2684_create\n"); if (copy_from_user(&ni, arg, sizeof ni)) { return -EFAULT; @@ -629,7 +623,7 @@ static int br2684_create(void __user *arg) brdev = BRPRIV(netdev); - DPRINTK("registered netdev %s\n", netdev->name); + pr_debug("registered netdev %s\n", netdev->name); /* open, stop, do_ioctl ? */ err = register_netdev(netdev); if (err < 0) { diff --git a/net/atm/clip.c b/net/atm/clip.c index ecf0f79b94ae..806ea98567c6 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -40,14 +40,6 @@ #include "resources.h" #include - -#if 0 -#define DPRINTK(format,args...) printk(format,##args) -#else -#define DPRINTK(format,args...) -#endif - - static struct net_device *clip_devs; static struct atm_vcc *atmarpd; static struct neigh_table clip_tbl; @@ -59,7 +51,7 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip) struct atmarp_ctrl *ctrl; struct sk_buff *skb; - DPRINTK("to_atmarpd(%d)\n", type); + pr_debug("to_atmarpd(%d)\n", type); if (!atmarpd) return -EUNATCH; skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC); @@ -79,7 +71,7 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip) static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry) { - DPRINTK("link_vcc %p to entry %p (neigh %p)\n", clip_vcc, entry, + pr_debug("link_vcc %p to entry %p (neigh %p)\n", clip_vcc, entry, entry->neigh); clip_vcc->entry = entry; clip_vcc->xoff = 0; /* @@@ may overrun buffer by one packet */ @@ -134,7 +126,7 @@ static int neigh_check_cb(struct neighbour *n) unsigned long exp = cv->last_use + cv->idle_timeout; if (cv->idle_timeout && time_after(jiffies, exp)) { - DPRINTK("releasing vcc %p->%p of entry %p\n", + pr_debug("releasing vcc %p->%p of entry %p\n", cv, cv->vcc, entry); vcc_release_async(cv->vcc, -ETIMEDOUT); } @@ -146,7 +138,7 @@ static int neigh_check_cb(struct neighbour *n) if (atomic_read(&n->refcnt) > 1) { struct sk_buff *skb; - DPRINTK("destruction postponed with ref %d\n", + pr_debug("destruction postponed with ref %d\n", atomic_read(&n->refcnt)); while ((skb = skb_dequeue(&n->arp_queue)) != NULL) @@ -155,7 +147,7 @@ static int neigh_check_cb(struct neighbour *n) return 0; } - DPRINTK("expired neigh %p\n", n); + pr_debug("expired neigh %p\n", n); return 1; } @@ -171,14 +163,14 @@ static int clip_arp_rcv(struct sk_buff *skb) { struct atm_vcc *vcc; - DPRINTK("clip_arp_rcv\n"); + pr_debug("clip_arp_rcv\n"); vcc = ATM_SKB(skb)->vcc; if (!vcc || !atm_charge(vcc, skb->truesize)) { dev_kfree_skb_any(skb); return 0; } - DPRINTK("pushing to %p\n", vcc); - DPRINTK("using %p\n", CLIP_VCC(vcc)->old_push); + pr_debug("pushing to %p\n", vcc); + pr_debug("using %p\n", CLIP_VCC(vcc)->old_push); CLIP_VCC(vcc)->old_push(vcc, skb); return 0; } @@ -196,9 +188,9 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb) { struct clip_vcc *clip_vcc = CLIP_VCC(vcc); - DPRINTK("clip push\n"); + pr_debug("clip push\n"); if (!skb) { - DPRINTK("removing VCC %p\n", clip_vcc); + pr_debug("removing VCC %p\n", clip_vcc); if (clip_vcc->entry) unlink_clip_vcc(clip_vcc); clip_vcc->old_push(vcc, NULL); /* pass on the bad news */ @@ -247,7 +239,7 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb) int old; unsigned long flags; - DPRINTK("clip_pop(vcc %p)\n", vcc); + pr_debug("clip_pop(vcc %p)\n", vcc); clip_vcc->old_pop(vcc, skb); /* skb->dev == NULL in outbound ARP packets */ if (!dev) @@ -263,7 +255,7 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb) static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb) { - DPRINTK("clip_neigh_solicit (neigh %p, skb %p)\n", neigh, skb); + pr_debug("clip_neigh_solicit (neigh %p, skb %p)\n", neigh, skb); to_atmarpd(act_need, PRIV(neigh->dev)->number, NEIGH2ENTRY(neigh)->ip); } @@ -292,7 +284,7 @@ static int clip_constructor(struct neighbour *neigh) struct in_device *in_dev; struct neigh_parms *parms; - DPRINTK("clip_constructor (neigh %p, entry %p)\n", neigh, entry); + pr_debug("clip_constructor (neigh %p, entry %p)\n", neigh, entry); neigh->type = inet_addr_type(entry->ip); if (neigh->type != RTN_UNICAST) return -EINVAL; @@ -376,7 +368,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) int old; unsigned long flags; - DPRINTK("clip_start_xmit (skb %p)\n", skb); + pr_debug("clip_start_xmit (skb %p)\n", skb); if (!skb->dst) { printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n"); dev_kfree_skb(skb); @@ -412,9 +404,9 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) } return 0; } - DPRINTK("neigh %p, vccs %p\n", entry, entry->vccs); + pr_debug("neigh %p, vccs %p\n", entry, entry->vccs); ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; - DPRINTK("using neighbour %p, vcc %p\n", skb->dst->neighbour, vcc); + pr_debug("using neighbour %p, vcc %p\n", skb->dst->neighbour, vcc); if (entry->vccs->encap) { void *here; @@ -425,7 +417,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); ATM_SKB(skb)->atm_options = vcc->atm_options; entry->vccs->last_use = jiffies; - DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev); + pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev); old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */ if (old) { printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n"); @@ -468,7 +460,7 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout) clip_vcc = kmalloc(sizeof(struct clip_vcc), GFP_KERNEL); if (!clip_vcc) return -ENOMEM; - DPRINTK("mkip clip_vcc %p vcc %p\n", clip_vcc, vcc); + pr_debug("mkip clip_vcc %p vcc %p\n", clip_vcc, vcc); clip_vcc->vcc = vcc; vcc->user_back = clip_vcc; set_bit(ATM_VF_IS_CLIP, &vcc->flags); @@ -538,7 +530,7 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip) printk(KERN_ERR "hiding hidden ATMARP entry\n"); return 0; } - DPRINTK("setentry: remove\n"); + pr_debug("setentry: remove\n"); unlink_clip_vcc(clip_vcc); return 0; } @@ -552,9 +544,9 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip) entry = NEIGH2ENTRY(neigh); if (entry != clip_vcc->entry) { if (!clip_vcc->entry) - DPRINTK("setentry: add\n"); + pr_debug("setentry: add\n"); else { - DPRINTK("setentry: update\n"); + pr_debug("setentry: update\n"); unlink_clip_vcc(clip_vcc); } link_vcc(clip_vcc, entry); @@ -611,7 +603,7 @@ static int clip_create(int number) } clip_priv->next = clip_devs; clip_devs = dev; - DPRINTK("registered (net:%s)\n", dev->name); + pr_debug("registered (net:%s)\n", dev->name); return number; } @@ -631,16 +623,16 @@ static int clip_device_event(struct notifier_block *this, unsigned long event, switch (event) { case NETDEV_UP: - DPRINTK("clip_device_event NETDEV_UP\n"); + pr_debug("clip_device_event NETDEV_UP\n"); to_atmarpd(act_up, PRIV(dev)->number, 0); break; case NETDEV_GOING_DOWN: - DPRINTK("clip_device_event NETDEV_DOWN\n"); + pr_debug("clip_device_event NETDEV_DOWN\n"); to_atmarpd(act_down, PRIV(dev)->number, 0); break; case NETDEV_CHANGE: case NETDEV_CHANGEMTU: - DPRINTK("clip_device_event NETDEV_CHANGE*\n"); + pr_debug("clip_device_event NETDEV_CHANGE*\n"); to_atmarpd(act_change, PRIV(dev)->number, 0); break; } @@ -681,14 +673,14 @@ static struct notifier_block clip_inet_notifier = { static void atmarpd_close(struct atm_vcc *vcc) { - DPRINTK("atmarpd_close\n"); + pr_debug("atmarpd_close\n"); rtnl_lock(); atmarpd = NULL; skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); rtnl_unlock(); - DPRINTK("(done)\n"); + pr_debug("(done)\n"); module_put(THIS_MODULE); } diff --git a/net/atm/common.c b/net/atm/common.c index 282d761454ba..299ec1eb872a 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -30,13 +30,6 @@ #include "addr.h" /* address registry */ #include "signaling.h" /* for WAITING and sigd_attach */ - -#if 0 -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - struct hlist_head vcc_hash[VCC_HTABLE_SIZE]; DEFINE_RWLOCK(vcc_sklist_lock); @@ -70,13 +63,13 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) struct sock *sk = sk_atm(vcc); if (atomic_read(&sk->sk_wmem_alloc) && !atm_may_send(vcc, size)) { - DPRINTK("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n", + pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n", atomic_read(&sk->sk_wmem_alloc), size, sk->sk_sndbuf); return NULL; } while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); - DPRINTK("AlTx %d += %d\n", atomic_read(&sk->sk_wmem_alloc), + pr_debug("AlTx %d += %d\n", atomic_read(&sk->sk_wmem_alloc), skb->truesize); atomic_add(skb->truesize, &sk->sk_wmem_alloc); return skb; @@ -392,10 +385,10 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi, if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal); if (error) goto fail; - DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal); - DPRINTK(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class, + pr_debug("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal); + pr_debug(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class, vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu); - DPRINTK(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class, + pr_debug(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class, vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu); if (dev->ops->open) { @@ -420,7 +413,7 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) struct atm_vcc *vcc = ATM_SD(sock); int error; - DPRINTK("vcc_connect (vpi %d, vci %d)\n",vpi,vci); + pr_debug("vcc_connect (vpi %d, vci %d)\n",vpi,vci); if (sock->state == SS_CONNECTED) return -EISCONN; if (sock->state != SS_UNCONNECTED) @@ -433,7 +426,7 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL; - DPRINTK("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; " + pr_debug("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; " "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu, @@ -504,7 +497,7 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, if (error) return error; sock_recv_timestamp(msg, sk, skb); - DPRINTK("RcvM %d -= %d\n", atomic_read(&sk->rmem_alloc), skb->truesize); + pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize); atm_return(vcc, skb->truesize); skb_free_datagram(sk, skb); return copied; diff --git a/net/atm/lec.c b/net/atm/lec.c index 59d5aa3366f2..813a090dcaf4 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -48,12 +48,6 @@ static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; #include "lec_arpc.h" #include "resources.h" -#if 0 -#define DPRINTK printk -#else -#define DPRINTK(format,args...) -#endif - #define DUMP_PACKETS 0 /* * 0 = None, * 1 = 30 first bytes @@ -273,7 +267,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) int i = 0; #endif /* DUMP_PACKETS >0 */ - DPRINTK("lec_start_xmit called\n"); + pr_debug("lec_start_xmit called\n"); if (!priv->lecd) { printk("%s:No lecd attached\n", dev->name); priv->stats.tx_errors++; @@ -281,7 +275,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) return -EUNATCH; } - DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n", + pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n", (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb), (long)skb_end_pointer(skb)); #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) @@ -292,7 +286,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Make sure we have room for lec_id */ if (skb_headroom(skb) < 2) { - DPRINTK("lec_start_xmit: reallocating skb\n"); + pr_debug("lec_start_xmit: reallocating skb\n"); skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); kfree_skb(skb); if (skb2 == NULL) @@ -373,22 +367,22 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif entry = NULL; vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry); - DPRINTK("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name, + pr_debug("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name, vcc, vcc ? vcc->flags : 0, entry); if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) { if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { - DPRINTK("%s:lec_start_xmit: queuing packet, ", + pr_debug("%s:lec_start_xmit: queuing packet, ", dev->name); - DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); skb_queue_tail(&entry->tx_wait, skb); } else { - DPRINTK + pr_debug ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", dev->name); - DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); @@ -402,8 +396,8 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif /* DUMP_PACKETS > 0 */ while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { - DPRINTK("lec.c: emptying tx queue, "); - DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + pr_debug("lec.c: emptying tx queue, "); + pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); lec_send(vcc, skb2, priv); @@ -464,7 +458,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) mesg = (struct atmlec_msg *)skb->data; tmp = skb->data; tmp += sizeof(struct atmlec_msg); - DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type); + pr_debug("%s: msg from zeppelin:%d\n", dev->name, mesg->type); switch (mesg->type) { case l_set_mac_addr: for (i = 0; i < 6; i++) { @@ -500,9 +494,9 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) mesg->content.normal.atm_addr, mesg->content.normal.flag, mesg->content.normal.targetless_le_arp); - DPRINTK("lec: in l_arp_update\n"); + pr_debug("lec: in l_arp_update\n"); if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */ - DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n", + pr_debug("lec: LANE2 3.1.5, got tlvs, size %d\n", mesg->sizeoftlvs); lane2_associate_ind(dev, mesg->content.normal.mac_addr, tmp, mesg->sizeoftlvs); @@ -544,7 +538,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) { struct net_bridge_fdb_entry *f; - DPRINTK + pr_debug ("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, mesg->content.proxy.mac_addr[0], mesg->content.proxy.mac_addr[1], @@ -564,7 +558,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) struct sk_buff *skb2; struct sock *sk; - DPRINTK + pr_debug ("%s: entry found, responding to zeppelin\n", dev->name); skb2 = @@ -670,7 +664,7 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, sk->sk_data_ready(sk, skb->len); if (data != NULL) { - DPRINTK("lec: about to send %d bytes of data\n", data->len); + pr_debug("lec: about to send %d bytes of data\n", data->len); atm_force_charge(priv->lecd, data->truesize); skb_queue_tail(&sk->sk_receive_queue, data); sk->sk_data_ready(sk, skb->len); @@ -742,7 +736,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) vcc->vpi, vcc->vci); #endif if (!skb) { - DPRINTK("%s: null skb\n", dev->name); + pr_debug("%s: null skb\n", dev->name); lec_vcc_close(priv, vcc); return; } @@ -766,7 +760,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { /* Control frame, to daemon */ struct sock *sk = sk_atm(vcc); - DPRINTK("%s: To daemon\n", dev->name); + pr_debug("%s: To daemon\n", dev->name); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); } else { /* Data frame, queue to protocol handlers */ @@ -780,7 +774,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) * Probably looping back, or if lecd is missing, * lecd has gone down */ - DPRINTK("Ignoring frame...\n"); + pr_debug("Ignoring frame...\n"); dev_kfree_skb(skb); return; } @@ -1442,9 +1436,9 @@ static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr, #include #if 0 -#define DPRINTK(format,args...) +#define pr_debug(format,args...) /* -#define DPRINTK printk +#define pr_debug printk */ #endif #define DEBUG_ARP_TABLE 0 @@ -1513,7 +1507,7 @@ lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry) tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])]; hlist_add_head(&entry->next, tmp); - DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + pr_debug("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", 0xff & entry->mac_addr[0], 0xff & entry->mac_addr[1], 0xff & entry->mac_addr[2], 0xff & entry->mac_addr[3], 0xff & entry->mac_addr[4], 0xff & entry->mac_addr[5]); @@ -1555,7 +1549,7 @@ lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove) } skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */ - DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + pr_debug("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", 0xff & to_remove->mac_addr[0], 0xff & to_remove->mac_addr[1], 0xff & to_remove->mac_addr[2], 0xff & to_remove->mac_addr[3], 0xff & to_remove->mac_addr[4], 0xff & to_remove->mac_addr[5]); @@ -1777,7 +1771,7 @@ static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, struct hlist_head *head; struct lec_arp_table *entry; - DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", + pr_debug("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", mac_addr[0] & 0xff, mac_addr[1] & 0xff, mac_addr[2] & 0xff, mac_addr[3] & 0xff, mac_addr[4] & 0xff, mac_addr[5] & 0xff); @@ -1819,7 +1813,7 @@ static void lec_arp_expire_arp(unsigned long data) entry = (struct lec_arp_table *)data; - DPRINTK("lec_arp_expire_arp\n"); + pr_debug("lec_arp_expire_arp\n"); if (entry->status == ESI_ARP_PENDING) { if (entry->no_tries <= entry->priv->max_retry_count) { if (entry->is_rdesc) @@ -1843,7 +1837,7 @@ static void lec_arp_expire_vcc(unsigned long data) del_timer(&to_remove->timer); - DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n", + pr_debug("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n", to_remove, priv, to_remove->vcc ? to_remove->recv_vcc->vpi : 0, to_remove->vcc ? to_remove->recv_vcc->vci : 0); @@ -1883,7 +1877,7 @@ static void lec_arp_check_expire(struct work_struct *work) unsigned long time_to_check; int i; - DPRINTK("lec_arp_check_expire %p\n", priv); + pr_debug("lec_arp_check_expire %p\n", priv); now = jiffies; restart: spin_lock_irqsave(&priv->lec_arp_lock, flags); @@ -1895,13 +1889,13 @@ restart: else time_to_check = priv->aging_time; - DPRINTK("About to expire: %lx - %lx > %lx\n", + pr_debug("About to expire: %lx - %lx > %lx\n", now, entry->last_used, time_to_check); if (time_after(now, entry->last_used + time_to_check) && !(entry->flags & LEC_PERMANENT_FLAG) && !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */ /* Remove entry */ - DPRINTK("LEC:Entry timed out\n"); + pr_debug("LEC:Entry timed out\n"); lec_arp_remove(priv, entry); lec_arp_put(entry); } else { @@ -1999,7 +1993,7 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, entry->packets_flooded < priv->maximum_unknown_frame_count) { entry->packets_flooded++; - DPRINTK("LEC_ARP: Flooding..\n"); + pr_debug("LEC_ARP: Flooding..\n"); found = priv->mcast_vcc; goto out; } @@ -2010,13 +2004,13 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, */ lec_arp_hold(entry); *ret_entry = entry; - DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status, + pr_debug("lec: entry->status %d entry->vcc %p\n", entry->status, entry->vcc); found = NULL; } else { /* No matching entry was found */ entry = make_entry(priv, mac_to_find); - DPRINTK("LEC_ARP: Making entry\n"); + pr_debug("LEC_ARP: Making entry\n"); if (!entry) { found = priv->mcast_vcc; goto out; @@ -2053,7 +2047,7 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, struct lec_arp_table *entry; int i; - DPRINTK("lec_addr_delete\n"); + pr_debug("lec_addr_delete\n"); spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { @@ -2084,8 +2078,8 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, struct lec_arp_table *entry, *tmp; int i; - DPRINTK("lec:%s", (targetless_le_arp) ? "targetless " : " "); - DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + pr_debug("lec:%s", (targetless_le_arp) ? "targetless " : " "); + pr_debug("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); @@ -2122,7 +2116,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, entry->flags |= LEC_REMOTE_FLAG; else entry->flags &= ~LEC_REMOTE_FLAG; - DPRINTK("After update\n"); + pr_debug("After update\n"); dump_arp_table(priv); goto out; } @@ -2166,7 +2160,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, entry->status = ESI_VC_PENDING; send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL); } - DPRINTK("After update2\n"); + pr_debug("After update2\n"); dump_arp_table(priv); out: spin_unlock_irqrestore(&priv->lec_arp_lock, flags); @@ -2189,7 +2183,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, if (ioc_data->receive == 2) { /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */ - DPRINTK("LEC_ARP: Attaching mcast forward\n"); + pr_debug("LEC_ARP: Attaching mcast forward\n"); #if 0 entry = lec_arp_find(priv, bus_mac); if (!entry) { @@ -2214,7 +2208,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, * Vcc which we don't want to make default vcc, * attach it anyway. */ - DPRINTK + pr_debug ("LEC_ARP:Attaching data direct, not default: " "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", ioc_data->atm_addr[0], ioc_data->atm_addr[1], @@ -2242,7 +2236,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, dump_arp_table(priv); goto out; } - DPRINTK + pr_debug ("LEC_ARP:Attaching data direct, default: " "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", ioc_data->atm_addr[0], ioc_data->atm_addr[1], @@ -2260,8 +2254,8 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, if (memcmp (ioc_data->atm_addr, entry->atm_addr, ATM_ESA_LEN) == 0) { - DPRINTK("LEC_ARP: Attaching data direct\n"); - DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n", + pr_debug("LEC_ARP: Attaching data direct\n"); + pr_debug("Currently -> Vcc: %d, Rvcc:%d\n", entry->vcc ? entry->vcc->vci : 0, entry->recv_vcc ? entry->recv_vcc-> vci : 0); @@ -2303,7 +2297,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, } } if (found_entry) { - DPRINTK("After vcc was added\n"); + pr_debug("After vcc was added\n"); dump_arp_table(priv); goto out; } @@ -2323,7 +2317,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, entry->timer.expires = jiffies + priv->vcc_timeout_period; entry->timer.function = lec_arp_expire_vcc; add_timer(&entry->timer); - DPRINTK("After vcc was added\n"); + pr_debug("After vcc was added\n"); dump_arp_table(priv); out: spin_unlock_irqrestore(&priv->lec_arp_lock, flags); @@ -2336,7 +2330,7 @@ static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id) struct lec_arp_table *entry; int i; - DPRINTK("LEC:lec_flush_complete %lx\n", tran_id); + pr_debug("LEC:lec_flush_complete %lx\n", tran_id); restart: spin_lock_irqsave(&priv->lec_arp_lock, flags); for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { @@ -2353,7 +2347,7 @@ restart: entry->last_used = jiffies; entry->status = ESI_FORWARD_DIRECT; lec_arp_put(entry); - DPRINTK("LEC_ARP: Flushed\n"); + pr_debug("LEC_ARP: Flushed\n"); goto restart; } } @@ -2376,7 +2370,7 @@ lec_set_flush_tran_id(struct lec_priv *priv, hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) { if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) { entry->flush_tran_id = tran_id; - DPRINTK("Set flush transaction id to %lx for %p\n", + pr_debug("Set flush transaction id to %lx for %p\n", tran_id, entry); } } @@ -2427,7 +2421,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) struct lec_arp_table *entry; int i; - DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci); + pr_debug("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci); dump_arp_table(priv); spin_lock_irqsave(&priv->lec_arp_lock, flags); @@ -2510,7 +2504,7 @@ lec_arp_check_empties(struct lec_priv *priv, goto out; } } - DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n"); + pr_debug("LEC_ARP: Arp_check_empties: entry not found!\n"); out: spin_unlock_irqrestore(&priv->lec_arp_lock, flags); } diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 19d5dfc0702f..0af84cd4f65b 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -46,13 +46,6 @@ #include "common.h" -#if 0 -#define DPRINTK(format, args...) \ - printk(KERN_DEBUG "pppoatm: " format, ##args) -#else -#define DPRINTK(format, args...) -#endif - enum pppoatm_encaps { e_autodetect = PPPOATM_ENCAPS_AUTODETECT, e_vc = PPPOATM_ENCAPS_VC, @@ -139,9 +132,9 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc) static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) { struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); - DPRINTK("pppoatm push\n"); + pr_debug("pppoatm push\n"); if (skb == NULL) { /* VCC was closed */ - DPRINTK("removing ATMPPP VCC %p\n", pvcc); + pr_debug("removing ATMPPP VCC %p\n", pvcc); pppoatm_unassign_vcc(atmvcc); atmvcc->push(atmvcc, NULL); /* Pass along bad news */ return; @@ -172,9 +165,8 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) pvcc->chan.mtu += LLC_LEN; break; } - DPRINTK("(unit %d): Couldn't autodetect yet " + pr_debug("Couldn't autodetect yet " "(skb: %02X %02X %02X %02X %02X %02X)\n", - pvcc->chan.unit, skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5]); goto error; @@ -202,8 +194,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) { struct pppoatm_vcc *pvcc = chan_to_pvcc(chan); ATM_SKB(skb)->vcc = pvcc->atmvcc; - DPRINTK("(unit %d): pppoatm_send (skb=0x%p, vcc=0x%p)\n", - pvcc->chan.unit, skb, pvcc->atmvcc); + pr_debug("pppoatm_send (skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) (void) skb_pull(skb, 1); switch (pvcc->encaps) { /* LLC encapsulation needed */ @@ -228,16 +219,14 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) goto nospace; break; case e_autodetect: - DPRINTK("(unit %d): Trying to send without setting encaps!\n", - pvcc->chan.unit); + pr_debug("Trying to send without setting encaps!\n"); kfree_skb(skb); return 1; } atomic_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc); ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; - DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n", - pvcc->chan.unit, skb, ATM_SKB(skb)->vcc, + pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) ? DROP_PACKET : 1; diff --git a/net/atm/raw.c b/net/atm/raw.c index 1378f61c5c31..b0a2d8cb6744 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -13,14 +13,6 @@ #include "common.h" #include "protocols.h" - -#if 0 -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - - /* * SKB == NULL indicates that the link is being closed */ @@ -40,8 +32,8 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) { struct sock *sk = sk_atm(vcc); - DPRINTK("APopR (%d) %d -= %d\n", vcc->vci, sk->sk_wmem_alloc, - skb->truesize); + pr_debug("APopR (%d) %d -= %d\n", vcc->vci, + atomic_read(&sk->sk_wmem_alloc), skb->truesize); atomic_sub(skb->truesize, &sk->sk_wmem_alloc); dev_kfree_skb_any(skb); sk->sk_write_space(sk); diff --git a/net/atm/signaling.c b/net/atm/signaling.c index d14baaf1f4c3..bced78b77f12 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -23,13 +23,6 @@ Danger: may cause nasty hangs if the demon crashes. */ -#if 0 -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - - struct atm_vcc *sigd = NULL; #ifdef WAIT_FOR_DEMON static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep); @@ -44,14 +37,14 @@ static void sigd_put_skb(struct sk_buff *skb) add_wait_queue(&sigd_sleep,&wait); while (!sigd) { set_current_state(TASK_UNINTERRUPTIBLE); - DPRINTK("atmsvc: waiting for signaling demon...\n"); + pr_debug("atmsvc: waiting for signaling demon...\n"); schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&sigd_sleep,&wait); #else if (!sigd) { - DPRINTK("atmsvc: no signaling demon\n"); + pr_debug("atmsvc: no signaling demon\n"); kfree_skb(skb); return; } @@ -96,9 +89,9 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) msg = (struct atmsvc_msg *) skb->data; atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); - DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type, - (unsigned long) msg->vcc); vcc = *(struct atm_vcc **) &msg->vcc; + pr_debug("sigd_send %d (0x%lx)\n",(int) msg->type, + (unsigned long) vcc); sk = sk_atm(vcc); switch (msg->type) { @@ -130,7 +123,7 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) case as_indicate: vcc = *(struct atm_vcc **) &msg->listen_vcc; sk = sk_atm(vcc); - DPRINTK("as_indicate!!!\n"); + pr_debug("as_indicate!!!\n"); lock_sock(sk); if (sk_acceptq_is_full(sk)) { sigd_enq(NULL,as_reject,vcc,NULL,NULL); @@ -139,7 +132,7 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) } sk->sk_ack_backlog++; skb_queue_tail(&sk->sk_receive_queue, skb); - DPRINTK("waking sk->sk_sleep 0x%p\n", sk->sk_sleep); + pr_debug("waking sk->sk_sleep 0x%p\n", sk->sk_sleep); sk->sk_state_change(sk); as_indicate_complete: release_sock(sk); @@ -176,7 +169,7 @@ void sigd_enq2(struct atm_vcc *vcc,enum atmsvc_msg_type type, struct atmsvc_msg *msg; static unsigned session = 0; - DPRINTK("sigd_enq %d (0x%p)\n",(int) type,vcc); + pr_debug("sigd_enq %d (0x%p)\n",(int) type,vcc); while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL))) schedule(); msg = (struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg)); @@ -226,7 +219,7 @@ static void sigd_close(struct atm_vcc *vcc) struct sock *s; int i; - DPRINTK("sigd_close\n"); + pr_debug("sigd_close\n"); sigd = NULL; if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) printk(KERN_ERR "sigd_close: closing with requests pending\n"); @@ -263,7 +256,7 @@ static struct atm_dev sigd_dev = { int sigd_attach(struct atm_vcc *vcc) { if (sigd) return -EADDRINUSE; - DPRINTK("sigd_attach\n"); + pr_debug("sigd_attach\n"); sigd = vcc; vcc->dev = &sigd_dev; vcc_insert_socket(sk_atm(vcc)); diff --git a/net/atm/svc.c b/net/atm/svc.c index 876ec7b47a2f..53d04c7992cf 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -25,17 +25,8 @@ #include "signaling.h" #include "addr.h" - -#if 0 -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - - static int svc_create(struct socket *sock,int protocol); - /* * Note: since all this is still nicely synchronized with the signaling demon, * there's no need to protect sleep loops with clis. If signaling is @@ -55,7 +46,7 @@ static void svc_disconnect(struct atm_vcc *vcc) struct sk_buff *skb; struct sock *sk = sk_atm(vcc); - DPRINTK("svc_disconnect %p\n",vcc); + pr_debug("svc_disconnect %p\n",vcc); if (test_bit(ATM_VF_REGIS,&vcc->flags)) { prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_close,NULL,NULL,NULL); @@ -69,7 +60,7 @@ static void svc_disconnect(struct atm_vcc *vcc) as_indicate has been answered */ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { atm_return(vcc, skb->truesize); - DPRINTK("LISTEN REL\n"); + pr_debug("LISTEN REL\n"); sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0); dev_kfree_skb(skb); } @@ -85,7 +76,7 @@ static int svc_release(struct socket *sock) if (sk) { vcc = ATM_SD(sock); - DPRINTK("svc_release %p\n", vcc); + pr_debug("svc_release %p\n", vcc); clear_bit(ATM_VF_READY, &vcc->flags); /* VCC pointer is used as a reference, so we must not free it (thereby subjecting it to re-use) before all pending connections @@ -162,7 +153,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, struct atm_vcc *vcc = ATM_SD(sock); int error; - DPRINTK("svc_connect %p\n",vcc); + pr_debug("svc_connect %p\n",vcc); lock_sock(sk); if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { error = -EINVAL; @@ -224,7 +215,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); continue; } - DPRINTK("*ABORT*\n"); + pr_debug("*ABORT*\n"); /* * This is tricky: * Kernel ---close--> Demon @@ -295,7 +286,7 @@ static int svc_listen(struct socket *sock,int backlog) struct atm_vcc *vcc = ATM_SD(sock); int error; - DPRINTK("svc_listen %p\n",vcc); + pr_debug("svc_listen %p\n",vcc); lock_sock(sk); /* let server handle listen on unbound sockets */ if (test_bit(ATM_VF_SESSION,&vcc->flags)) { @@ -341,7 +332,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) new_vcc = ATM_SD(newsock); - DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc); + pr_debug("svc_accept %p -> %p\n",old_vcc,new_vcc); while (1) { DEFINE_WAIT(wait); @@ -545,7 +536,7 @@ static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr, error = -EINPROGRESS; goto out; } - DPRINTK("svc_addparty added wait queue\n"); + pr_debug("svc_addparty added wait queue\n"); while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { schedule(); prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); From e9144bd8da80f3136b23c615609798e371e885ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Aug 2007 22:43:14 -0700 Subject: [PATCH 1107/2804] [TCP]: Remove unnecessary wrapper tcp_packets_out_dec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes caller side more obvious, there's no need to have a wrapper for this oneliner! Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 6 ------ net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_output.c | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 0a4ed6e85c6f..66827177ae8b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -626,12 +626,6 @@ static inline void tcp_packets_out_inc(struct sock *sk, inet_csk(sk)->icsk_rto, TCP_RTO_MAX); } -static inline void tcp_packets_out_dec(struct tcp_sock *tp, - const struct sk_buff *skb) -{ - tp->packets_out -= tcp_skb_pcount(skb); -} - /* Events passed to congestion control interface */ enum tcp_ca_event { CA_EVENT_TX_START, /* first transmit when no packets in flight */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index faba9beb3613..593960d66ed9 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2569,7 +2569,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) last_ackt = skb->tstamp; } tcp_dec_pcount_approx(&tp->fackets_out, skb); - tcp_packets_out_dec(tp, skb); + tp->packets_out -= tcp_skb_pcount(skb); tcp_unlink_write_queue(skb, sk); sk_stream_free_skb(sk, skb); clear_all_retrans_hints(tp); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a3679174e78a..1d65ce1b68d7 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1735,7 +1735,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m * it is better to underestimate fackets. */ tcp_dec_pcount_approx(&tp->fackets_out, next_skb); - tcp_packets_out_dec(tp, next_skb); + tp->packets_out -= tcp_skb_pcount(next_skb); sk_stream_free_skb(sk, next_skb); } } From 6ff03ac355cc6c10f7b1f44dd466d41213acebca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Aug 2007 22:44:06 -0700 Subject: [PATCH 1108/2804] [TCP]: tcp_packets_out_inc to tcp_output.c (no callers elsewhere) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 12 ------------ net/ipv4/tcp_output.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 66827177ae8b..4ba256a3f5e0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -614,18 +614,6 @@ static inline void tcp_dec_pcount_approx(__u32 *count, tcp_dec_pcount_approx_int(count, tcp_skb_pcount(skb)); } -static inline void tcp_packets_out_inc(struct sock *sk, - const struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - int orig = tp->packets_out; - - tp->packets_out += tcp_skb_pcount(skb); - if (!orig) - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - inet_csk(sk)->icsk_rto, TCP_RTO_MAX); -} - /* Events passed to congestion control interface */ enum tcp_ca_event { CA_EVENT_TX_START, /* first transmit when no packets in flight */ diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 1d65ce1b68d7..a61a3e3082ae 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -61,6 +61,18 @@ int sysctl_tcp_base_mss __read_mostly = 512; /* By default, RFC2861 behavior. */ int sysctl_tcp_slow_start_after_idle __read_mostly = 1; +static inline void tcp_packets_out_inc(struct sock *sk, + const struct sk_buff *skb) +{ + struct tcp_sock *tp = tcp_sk(sk); + int orig = tp->packets_out; + + tp->packets_out += tcp_skb_pcount(skb); + if (!orig) + inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, + inet_csk(sk)->icsk_rto, TCP_RTO_MAX); +} + static void update_send_head(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); From 6728e7dc3e577241f36921c720cfb4eb8f5aed1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Aug 2007 22:53:26 -0700 Subject: [PATCH 1109/2804] [TCP]: Rename tcp_ack_packets_out -> tcp_rearm_rto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only thing that tiny function does is rearming the RTO (if necessary), name it accordingly. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 593960d66ed9..0ead46f2bcd5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2424,8 +2424,7 @@ static void tcp_cong_avoid(struct sock *sk, u32 ack, /* Restart timer after forward progress on connection. * RFC2988 recommends to restart timer to now+rto. */ - -static void tcp_ack_packets_out(struct sock *sk) +static void tcp_rearm_rto(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -2581,7 +2580,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) = inet_csk(sk)->icsk_ca_ops; tcp_ack_update_rtt(sk, acked, seq_rtt); - tcp_ack_packets_out(sk); + tcp_rearm_rto(sk); if (tcp_is_reno(tp)) tcp_remove_reno_sacks(sk, pkts_acked); From 5b3c98821a8753239aefc1c217409aa3e5c90787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Aug 2007 22:54:44 -0700 Subject: [PATCH 1110/2804] [TCP]: Discard fuzzy SACK blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SACK processing code has been a sort of russian roulette as no validation of SACK blocks is previously attempted. Besides, it is not very clear what all kinds of broken SACK blocks really mean (e.g., one that has start and end sequence numbers reversed). So now close the roulette once and for all. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0ead46f2bcd5..a2364ebf8585 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1019,7 +1019,86 @@ static void tcp_update_reordering(struct sock *sk, const int metric, * for retransmitted and already SACKed segment -> reordering.. * Both of these heuristics are not used in Loss state, when we cannot * account for retransmits accurately. + * + * SACK block validation. + * ---------------------- + * + * SACK block range validation checks that the received SACK block fits to + * the expected sequence limits, i.e., it is between SND.UNA and SND.NXT. + * Note that SND.UNA is not included to the range though being valid because + * it means that the receiver is rather inconsistent with itself (reports + * SACK reneging when it should advance SND.UNA). + * + * Implements also blockage to start_seq wrap-around. Problem lies in the + * fact that though start_seq (s) is before end_seq (i.e., not reversed), + * there's no guarantee that it will be before snd_nxt (n). The problem + * happens when start_seq resides between end_seq wrap (e_w) and snd_nxt + * wrap (s_w): + * + * <- outs wnd -> <- wrapzone -> + * u e n u_w e_w s n_w + * | | | | | | | + * |<------------+------+----- TCP seqno space --------------+---------->| + * ...-- <2^31 ->| |<--------... + * ...---- >2^31 ------>| |<--------... + * + * Current code wouldn't be vulnerable but it's better still to discard such + * crazy SACK blocks. Doing this check for start_seq alone closes somewhat + * similar case (end_seq after snd_nxt wrap) as earlier reversed check in + * snd_nxt wrap -> snd_una region will then become "well defined", i.e., + * equal to the ideal case (infinite seqno space without wrap caused issues). + * + * With D-SACK the lower bound is extended to cover sequence space below + * SND.UNA down to undo_marker, which is the last point of interest. Yet + * again, DSACK block must not to go across snd_una (for the same reason as + * for the normal SACK blocks, explained above). But there all simplicity + * ends, TCP might receive valid D-SACKs below that. As long as they reside + * fully below undo_marker they do not affect behavior in anyway and can + * therefore be safely ignored. In rare cases (which are more or less + * theoretical ones), the D-SACK will nicely cross that boundary due to skb + * fragmentation and packet reordering past skb's retransmission. To consider + * them correctly, the acceptable range must be extended even more though + * the exact amount is rather hard to quantify. However, tp->max_window can + * be used as an exaggerated estimate. */ +static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack, + u32 start_seq, u32 end_seq) +{ + /* Too far in future, or reversed (interpretation is ambiguous) */ + if (after(end_seq, tp->snd_nxt) || !before(start_seq, end_seq)) + return 0; + + /* Nasty start_seq wrap-around check (see comments above) */ + if (!before(start_seq, tp->snd_nxt)) + return 0; + + /* In outstanding window? ...This is valid exit for DSACKs too. + * start_seq == snd_una is non-sensical (see comments above) + */ + if (after(start_seq, tp->snd_una)) + return 1; + + if (!is_dsack || !tp->undo_marker) + return 0; + + /* ...Then it's D-SACK, and must reside below snd_una completely */ + if (!after(end_seq, tp->snd_una)) + return 0; + + if (!before(start_seq, tp->undo_marker)) + return 1; + + /* Too old */ + if (!after(end_seq, tp->undo_marker)) + return 0; + + /* Undo_marker boundary crossing (overestimates a lot). Known already: + * start_seq < undo_marker and end_seq >= undo_marker. + */ + return !before(start_seq, end_seq - tp->max_window); +} + + static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, struct tcp_sack_block_wire *sp, int num_sacks, u32 prior_snd_una) @@ -1161,6 +1240,9 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ int fack_count; int dup_sack = (found_dup_sack && (i == first_sack_index)); + if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) + continue; + skb = cached_skb; fack_count = cached_fack_count; From 18f02545a9a16c9a89778b91a162ad16d510bb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Aug 2007 22:55:52 -0700 Subject: [PATCH 1111/2804] [TCP] MIB: Add counters for discarded SACK blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In DSACK case, some events are not extraordinary, such as packet duplication generated DSACK. They can arrive easily below snd_una when undo_marker is not set (TCP being in CA_Open), counting such DSACKs amoung SACK discards will likely just mislead if they occur in some scenario when there are other problems as well. Similarly, excessively delayed packets could cause "normal" DSACKs. Therefore, separate counters are allocated for DSACK events. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/linux/snmp.h | 3 +++ net/ipv4/proc.c | 3 +++ net/ipv4/tcp_input.c | 10 +++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/linux/snmp.h b/include/linux/snmp.h index 802b3a38b041..d24c55473821 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -231,6 +231,9 @@ enum LINUX_MIB_TCPABORTONLINGER, /* TCPAbortOnLinger */ LINUX_MIB_TCPABORTFAILED, /* TCPAbortFailed */ LINUX_MIB_TCPMEMORYPRESSURES, /* TCPMemoryPressures */ + LINUX_MIB_TCPSACKDISCARD, /* TCPSACKDiscard */ + LINUX_MIB_TCPDSACKIGNOREDOLD, /* TCPSACKIgnoredOld */ + LINUX_MIB_TCPDSACKIGNOREDNOUNDO, /* TCPSACKIgnoredNoUndo */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 3b690cf2a4ee..986d1c83a000 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -244,6 +244,9 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPAbortOnLinger", LINUX_MIB_TCPABORTONLINGER), SNMP_MIB_ITEM("TCPAbortFailed", LINUX_MIB_TCPABORTFAILED), SNMP_MIB_ITEM("TCPMemoryPressures", LINUX_MIB_TCPMEMORYPRESSURES), + SNMP_MIB_ITEM("TCPSACKDiscard", LINUX_MIB_TCPSACKDISCARD), + SNMP_MIB_ITEM("TCPDSACKIgnoredOld", LINUX_MIB_TCPDSACKIGNOREDOLD), + SNMP_MIB_ITEM("TCPDSACKIgnoredNoUndo", LINUX_MIB_TCPDSACKIGNOREDNOUNDO), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a2364ebf8585..f9e4d7ad68b7 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1240,8 +1240,16 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ int fack_count; int dup_sack = (found_dup_sack && (i == first_sack_index)); - if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) + if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) { + if (dup_sack) { + if (!tp->undo_marker) + NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO); + else + NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD); + } else + NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD); continue; + } skb = cached_skb; fack_count = cached_fack_count; From 356f89e12e301376f26795643f3b5931c81c9cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 24 Aug 2007 23:00:31 -0700 Subject: [PATCH 1112/2804] [NET] Cleanup: DIV_ROUND_UP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 6 +----- net/key/af_key.c | 17 +++++------------ 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a61a3e3082ae..d65d17bb2a09 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -646,11 +646,7 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned skb_shinfo(skb)->gso_size = 0; skb_shinfo(skb)->gso_type = 0; } else { - unsigned int factor; - - factor = skb->len + (mss_now - 1); - factor /= mss_now; - skb_shinfo(skb)->gso_segs = factor; + skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss_now); skb_shinfo(skb)->gso_size = mss_now; skb_shinfo(skb)->gso_type = sk->sk_gso_type; } diff --git a/net/key/af_key.c b/net/key/af_key.c index 5502df115a63..17b2a6927f01 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -352,16 +352,14 @@ static int verify_address_len(void *p) switch (addr->sa_family) { case AF_INET: - len = sizeof(*sp) + sizeof(*sin) + (sizeof(uint64_t) - 1); - len /= sizeof(uint64_t); + len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t)); if (sp->sadb_address_len != len || sp->sadb_address_prefixlen > 32) return -EINVAL; break; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case AF_INET6: - len = sizeof(*sp) + sizeof(*sin6) + (sizeof(uint64_t) - 1); - len /= sizeof(uint64_t); + len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin6), sizeof(uint64_t)); if (sp->sadb_address_len != len || sp->sadb_address_prefixlen > 128) return -EINVAL; @@ -386,14 +384,9 @@ static int verify_address_len(void *p) static inline int pfkey_sec_ctx_len(struct sadb_x_sec_ctx *sec_ctx) { - int len = 0; - - len += sizeof(struct sadb_x_sec_ctx); - len += sec_ctx->sadb_x_ctx_len; - len += sizeof(uint64_t) - 1; - len /= sizeof(uint64_t); - - return len; + return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) + + sec_ctx->sadb_x_ctx_len, + sizeof(uint64_t)); } static inline int verify_sec_ctx_len(void *p) From 32c1da70810017a98aa6c431a5494a302b6b9a30 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Aug 2007 23:09:41 -0700 Subject: [PATCH 1113/2804] [UDP]: Randomize port selection. This patch causes UDP port allocation to be randomized like TCP. The earlier code would always choose same port (ie first empty list). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/udp.c | 80 ++++++++++++++++++++++++--------------------- net/ipv4/udp_impl.h | 2 +- net/ipv4/udplite.c | 3 +- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 69d4bd10f9c6..a581b543bff7 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -113,9 +113,8 @@ DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly; struct hlist_head udp_hash[UDP_HTABLE_SIZE]; DEFINE_RWLOCK(udp_hash_lock); -static int udp_port_rover; - -static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[]) +static inline int __udp_lib_lport_inuse(__u16 num, + const struct hlist_head udptable[]) { struct sock *sk; struct hlist_node *node; @@ -132,11 +131,10 @@ static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[]) * @sk: socket struct in question * @snum: port number to look up * @udptable: hash list table, must be of UDP_HTABLE_SIZE - * @port_rover: pointer to record of last unallocated port * @saddr_comp: AF-dependent comparison of bound local IP addresses */ int __udp_lib_get_port(struct sock *sk, unsigned short snum, - struct hlist_head udptable[], int *port_rover, + struct hlist_head udptable[], int (*saddr_comp)(const struct sock *sk1, const struct sock *sk2 ) ) { @@ -146,49 +144,56 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, int error = 1; write_lock_bh(&udp_hash_lock); - if (snum == 0) { - int best_size_so_far, best, result, i; - if (*port_rover > sysctl_local_port_range[1] || - *port_rover < sysctl_local_port_range[0]) - *port_rover = sysctl_local_port_range[0]; - best_size_so_far = 32767; - best = result = *port_rover; - for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { - int size; + if (!snum) { + int i; + int low = sysctl_local_port_range[0]; + int high = sysctl_local_port_range[1]; + unsigned rover, best, best_size_so_far; - head = &udptable[result & (UDP_HTABLE_SIZE - 1)]; - if (hlist_empty(head)) { - if (result > sysctl_local_port_range[1]) - result = sysctl_local_port_range[0] + - ((result - sysctl_local_port_range[0]) & - (UDP_HTABLE_SIZE - 1)); + best_size_so_far = UINT_MAX; + best = rover = net_random() % (high - low) + low; + + /* 1st pass: look for empty (or shortest) hash chain */ + for (i = 0; i < UDP_HTABLE_SIZE; i++) { + int size = 0; + + head = &udptable[rover & (UDP_HTABLE_SIZE - 1)]; + if (hlist_empty(head)) goto gotit; - } - size = 0; + sk_for_each(sk2, node, head) { if (++size >= best_size_so_far) goto next; } best_size_so_far = size; - best = result; + best = rover; next: - ; + /* fold back if end of range */ + if (++rover > high) + rover = low + ((rover - low) + & (UDP_HTABLE_SIZE - 1)); + + } - result = best; - for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; - i++, result += UDP_HTABLE_SIZE) { - if (result > sysctl_local_port_range[1]) - result = sysctl_local_port_range[0] - + ((result - sysctl_local_port_range[0]) & - (UDP_HTABLE_SIZE - 1)); - if (! __udp_lib_lport_inuse(result, udptable)) - break; + + /* 2nd pass: find hole in shortest hash chain */ + rover = best; + for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) { + if (! __udp_lib_lport_inuse(rover, udptable)) + goto gotit; + rover += UDP_HTABLE_SIZE; + if (rover > high) + rover = low + ((rover - low) + & (UDP_HTABLE_SIZE - 1)); } - if (i >= (1 << 16) / UDP_HTABLE_SIZE) - goto fail; + + + /* All ports in use! */ + goto fail; + gotit: - *port_rover = snum = result; + snum = rover; } else { head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; @@ -201,6 +206,7 @@ gotit: (*saddr_comp)(sk, sk2) ) goto fail; } + inet_sk(sk)->num = snum; sk->sk_hash = snum; if (sk_unhashed(sk)) { @@ -217,7 +223,7 @@ fail: int udp_get_port(struct sock *sk, unsigned short snum, int (*scmp)(const struct sock *, const struct sock *)) { - return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp); + return __udp_lib_get_port(sk, snum, udp_hash, scmp); } int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 820a477cfaa6..6c55828e41ba 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -9,7 +9,7 @@ extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, - struct hlist_head udptable[], int *port_rover, + struct hlist_head udptable[], int (*)(const struct sock*,const struct sock*)); extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index f34fd686a8f1..94977205abb4 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -16,12 +16,11 @@ DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; -static int udplite_port_rover; int udplite_get_port(struct sock *sk, unsigned short p, int (*c)(const struct sock *, const struct sock *)) { - return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); + return __udp_lib_get_port(sk, p, udplite_hash, c); } static int udplite_v4_get_port(struct sock *sk, unsigned short snum) From 6f4fc423b96c8fdf6f5c8b8ad79b75b7fb5a5c59 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 17 Sep 2007 11:44:25 -0700 Subject: [PATCH 1114/2804] [SHAPER]: Mark for removal. This driver has been marked obsolete for a long time and is superseded by traffic schedulers. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/feature-removal-schedule.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 00928d2ecfb2..64831def40ab 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -306,3 +306,12 @@ Why: In kernel tree version of driver is unmaintained. Sk98lin driver Who: Stephen Hemminger --------------------------- + +What: shaper network driver +When: January 2008 +Files: drivers/net/shaper.c, include/linux/if_shaper.h +Why: This driver has been marked obsolete for many years. + It was only designed to work on lower speed links and has design + flaws that lead to machine crashes. The qdisc infrastructure in + 2.4 or later kernels, provides richer features and is more robust. +Who: Stephen Hemminger From e773e4faa19c54c2f32ddd16add2919588488bd9 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Fri, 24 Aug 2007 23:16:08 -0700 Subject: [PATCH 1115/2804] [IPV6]: Add v4mapped address inline Add v4mapped address inline to avoid calls to ipv6_addr_type(). Signed-off-by: Brian Haley Signed-off-by: David S. Miller --- include/net/ipv6.h | 6 ++++++ net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/tcp_ipv6.c | 4 ++-- net/ipv6/udp.c | 2 +- net/sctp/ipv6.c | 4 ++-- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9059e0ed7fe3..9573c8d19153 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -377,6 +377,12 @@ static inline int ipv6_addr_any(const struct in6_addr *a) a->s6_addr32[2] | a->s6_addr32[3] ) == 0); } +static inline int ipv6_addr_v4mapped(const struct in6_addr *a) +{ + return ((a->s6_addr32[0] | a->s6_addr32[1]) == 0 && + a->s6_addr32[2] == htonl(0x0000ffff)); +} + /* * find the first different bit between two addresses * length of address must be a multiple of 32bits diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 6b038aa72e88..74254fccbcc8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -249,7 +249,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, } if (ipv6_only_sock(sk) || - !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) { + !ipv6_addr_v4mapped(&np->daddr)) { retv = -EADDRNOTAVAIL; break; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3e06799b37a6..a07b59c528f3 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -697,7 +697,7 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, if (!cmd.tcpm_keylen) { if (!tcp_sk(sk)->md5sig_info) return -ENOENT; - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED) + if (ipv6_addr_v4mapped(&sin6->sin6_addr)) return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]); return tcp_v6_md5_do_del(sk, &sin6->sin6_addr); } @@ -720,7 +720,7 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); if (!newkey) return -ENOMEM; - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED) { + if (ipv6_addr_v4mapped(&sin6->sin6_addr)) { return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3], newkey, cmd.tcpm_keylen); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index c347f3e30e2e..82ff26dd4470 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -612,7 +612,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, daddr = NULL; if (daddr) { - if (ipv6_addr_type(daddr) == IPV6_ADDR_MAPPED) { + if (ipv6_addr_v4mapped(daddr)) { struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 670fd2740b89..ec29b97dbab9 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -493,7 +493,7 @@ static int sctp_v6_cmp_addr(const union sctp_addr *addr1, if (addr1->sa.sa_family != addr2->sa.sa_family) { if (addr1->sa.sa_family == AF_INET && addr2->sa.sa_family == AF_INET6 && - IPV6_ADDR_MAPPED == ipv6_addr_type(&addr2->v6.sin6_addr)) { + ipv6_addr_v4mapped(&addr2->v6.sin6_addr)) { if (addr2->v6.sin6_port == addr1->v4.sin_port && addr2->v6.sin6_addr.s6_addr32[3] == addr1->v4.sin_addr.s_addr) @@ -501,7 +501,7 @@ static int sctp_v6_cmp_addr(const union sctp_addr *addr1, } if (addr2->sa.sa_family == AF_INET && addr1->sa.sa_family == AF_INET6 && - IPV6_ADDR_MAPPED == ipv6_addr_type(&addr1->v6.sin6_addr)) { + ipv6_addr_v4mapped(&addr1->v6.sin6_addr)) { if (addr1->v6.sin6_port == addr2->v4.sin_port && addr1->v6.sin6_addr.s6_addr32[3] == addr2->v4.sin_addr.s_addr) From a47ed4cd8cb0709723392f5b841e9015f765d0a6 Mon Sep 17 00:00:00 2001 From: Noriaki TAKAMIYA Date: Thu, 6 Sep 2007 03:31:25 -0700 Subject: [PATCH 1116/2804] [IPV6] XFRM: Fix connected socket to use transformation. When XFRM policy and state are ready after TCP connection is started, the traffic should be transformed immediately, however it does not on IPv6 TCP. It depends on a dst cache replacement policy with connected socket. It seems that the replacement is always done for IPv4, however, on IPv6 case it is done only when routing cookie is changed. This patch fix that non-transformation dst can be changed to transformation one. This behavior is required by MIPv6 and improves IPv6 IPsec. Fixes by Masahide NAKAMURA. Signed-off-by: Noriaki TAKAMIYA Signed-off-by: Masahide NAKAMURA Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 4 ++++ net/ipv6/inet6_connection_sock.c | 39 ++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index c48ea873f1e0..857821360bb6 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -105,6 +105,10 @@ struct rt6_info struct rt6key rt6i_src; u8 rt6i_protocol; + +#ifdef CONFIG_XFRM + u32 rt6i_flow_cache_genid; +#endif }; static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 116f94a49071..25b931709749 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -139,6 +139,41 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr); +static inline +void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst, + struct in6_addr *daddr, struct in6_addr *saddr) +{ + __ip6_dst_store(sk, dst, daddr, saddr); + +#ifdef CONFIG_XFRM + if (dst) { + struct rt6_info *rt = (struct rt6_info *)dst; + rt->rt6i_flow_cache_genid = atomic_read(&flow_cache_genid); + } +#endif +} + +static inline +struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) +{ + struct dst_entry *dst; + + dst = __sk_dst_check(sk, cookie); + +#ifdef CONFIG_XFRM + if (dst) { + struct rt6_info *rt = (struct rt6_info *)dst; + if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) { + sk->sk_dst_cache = NULL; + dst_release(dst); + dst = NULL; + } + } +#endif + + return dst; +} + int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) { struct sock *sk = skb->sk; @@ -166,7 +201,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) final_p = &final; } - dst = __sk_dst_check(sk, np->dst_cookie); + dst = __inet6_csk_dst_check(sk, np->dst_cookie); if (dst == NULL) { int err = ip6_dst_lookup(sk, &dst, &fl); @@ -186,7 +221,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) return err; } - __ip6_dst_store(sk, dst, NULL, NULL); + __inet6_csk_dst_store(sk, dst, NULL, NULL); } skb->dst = dst_clone(dst); From 1e5dc146173251e7baad9a1f7586d5a009b6d9f9 Mon Sep 17 00:00:00 2001 From: Masahide NAKAMURA Date: Fri, 24 Aug 2007 19:08:55 +0900 Subject: [PATCH 1117/2804] [IPV6] IPSEC: Omit redirect for tunnelled packet. IPv6 IPsec tunnel gateway incorrectly sends redirect to router or sender when network device the IPsec tunnelled packet is arrived is the same as the one the decapsulated packet is sent. With this patch, it omits to send the redirect when the forwarding skbuff carries secpath, since such skbuff should be assumed as a decapsulated packet from IPsec tunnel by own. It may be a rare case for an IPsec security gateway, however it is not rare when the gateway is MIPv6 Home Agent since the another tunnel end-point is Mobile Node and it changes the attached network. Signed-off-by: Masahide NAKAMURA Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 26de3c0ea31e..e46d4683eab0 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -441,8 +441,10 @@ int ip6_forward(struct sk_buff *skb) /* IPv6 specs say nothing about it, but it is clear that we cannot send redirects to source routed frames. + We don't send redirects to frames decapsulated from IPsec. */ - if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0) { + if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 && + !skb->sp) { struct in6_addr *target = NULL; struct rt6_info *rt; struct neighbour *n = dst->neighbour; From 3b26a9a655ee73a87071a9f6a1fdd5311e31d7c9 Mon Sep 17 00:00:00 2001 From: Masahide NAKAMURA Date: Fri, 24 Aug 2007 23:33:01 -0700 Subject: [PATCH 1118/2804] [IPV4] IPSEC: Omit redirect for tunnelled packet. IPv4 IPsec tunnel gateway incorrectly sends redirect to sender if it is onlink host when network device the IPsec tunnelled packet is arrived is the same as the one the decapsulated packet is sent. With this patch, it omits to send the redirect when the forwarding skbuff carries secpath, since such skbuff should be assumed as a decapsulated packet from IPsec tunnel by own. Request for comments: Alternatively we'd have another way to change net/ipv4/route.c (__mkroute_input) to use RTCF_DOREDIRECT flag unless skbuff has no secpath. It is better than this patch at performance point of view because IPv4 redirect judgement is done at routing slow-path. However, it should be taken care of resource changes between SAD(XFRM states) and routing table. In other words, When IPv4 SAD is changed does the related routing entry go to its slow-path? If not, it is reasonable to apply this patch. Signed-off-by: Masahide NAKAMURA Signed-off-by: David S. Miller --- net/ipv4/ip_forward.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 8c95cf09f87a..afbf938836f5 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -105,7 +105,7 @@ int ip_forward(struct sk_buff *skb) * We now generate an ICMP HOST REDIRECT giving the route * we calculated. */ - if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr) + if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb->sp) ip_rt_send_redirect(skb); skb->priority = rt_tos2priority(iph->tos); From f7944fb1913130ae7858008af96e52a3a6b04118 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sat, 25 Aug 2007 13:46:55 -0700 Subject: [PATCH 1119/2804] [XFRM] policy: Replace magic number with XFRM_POLICY_OUT Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/xfrm/xfrm_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 7012891d39f2..6ab81b1d215e 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1477,7 +1477,7 @@ restart: pol_dead = 0; xfrm_nr = 0; - if (sk && sk->sk_policy[1]) { + if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); if (IS_ERR(policy)) return PTR_ERR(policy); From 32b21e034be9954eaae0278df20e0251eb958ded Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Tue, 28 Aug 2007 15:41:11 -0700 Subject: [PATCH 1120/2804] [NETLINK]: use container_of instead This could make future redesign of struct netlink_sock easier. Signed-off-by: Denis Cheng Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 5681ce3aebca..a78d962e2c70 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -88,7 +88,7 @@ struct netlink_sock { static inline struct netlink_sock *nlk_sk(struct sock *sk) { - return (struct netlink_sock *)sk; + return container_of(sk, struct netlink_sock, sk); } struct nl_pid_hash { From 45b270f880d32252ded95865390e69deb714e080 Mon Sep 17 00:00:00 2001 From: Robert Olsson Date: Tue, 28 Aug 2007 15:45:55 -0700 Subject: [PATCH 1121/2804] [PKTGEN]: Multiqueue support. Below some pktgen support to send into different TX queues. This can of course be feed into input queues on other machines Signed-off-by: Robert Olsson Signed-off-by: David S. Miller --- net/core/pktgen.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 803d0c8826af..1d6f1c6270b6 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -189,6 +189,7 @@ #define F_SVID_RND (1<<10) /* Random SVLAN ID */ #define F_FLOW_SEQ (1<<11) /* Sequential flows */ #define F_IPSEC_ON (1<<12) /* ipsec on for flows */ +#define F_QUEUE_MAP_RND (1<<13) /* queue map Random */ /* Thread control flag bits */ #define T_TERMINATE (1<<0) @@ -331,6 +332,7 @@ struct pktgen_dev { __be32 cur_daddr; __u16 cur_udp_dst; __u16 cur_udp_src; + __u16 cur_queue_map; __u32 cur_pkt_size; __u8 hh[14]; @@ -358,6 +360,10 @@ struct pktgen_dev { unsigned lflow; /* Flow length (config) */ unsigned nflows; /* accumulated flows (stats) */ unsigned curfl; /* current sequenced flow (state)*/ + + u16 queue_map_min; + u16 queue_map_max; + #ifdef CONFIG_XFRM __u8 ipsmode; /* IPSEC mode (config) */ __u8 ipsproto; /* IPSEC type (config) */ @@ -613,6 +619,11 @@ static int pktgen_if_show(struct seq_file *seq, void *v) seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow); + seq_printf(seq, + " queue_map_min: %u queue_map_max: %u\n", + pkt_dev->queue_map_min, + pkt_dev->queue_map_max); + if (pkt_dev->flags & F_IPV6) { char b1[128], b2[128], b3[128]; fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); @@ -709,6 +720,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) if (pkt_dev->flags & F_MPLS_RND) seq_printf(seq, "MPLS_RND "); + if (pkt_dev->flags & F_QUEUE_MAP_RND) + seq_printf(seq, "QUEUE_MAP_RND "); + if (pkt_dev->cflows) { if (pkt_dev->flags & F_FLOW_SEQ) seq_printf(seq, "FLOW_SEQ "); /*in sequence flows*/ @@ -764,6 +778,8 @@ static int pktgen_if_show(struct seq_file *seq, void *v) seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); + seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); + seq_printf(seq, " flows: %u\n", pkt_dev->nflows); if (pkt_dev->result[0]) @@ -1215,6 +1231,11 @@ static ssize_t pktgen_if_write(struct file *file, else if (strcmp(f, "FLOW_SEQ") == 0) pkt_dev->flags |= F_FLOW_SEQ; + else if (strcmp(f, "QUEUE_MAP_RND") == 0) + pkt_dev->flags |= F_QUEUE_MAP_RND; + + else if (strcmp(f, "!QUEUE_MAP_RND") == 0) + pkt_dev->flags &= ~F_QUEUE_MAP_RND; #ifdef CONFIG_XFRM else if (strcmp(f, "IPSEC") == 0) pkt_dev->flags |= F_IPSEC_ON; @@ -1526,6 +1547,28 @@ static ssize_t pktgen_if_write(struct file *file, return count; } + if (!strcmp(name, "queue_map_min")) { + len = num_arg(&user_buffer[i], 5, &value); + 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); + return count; + } + + if (!strcmp(name, "queue_map_max")) { + len = num_arg(&user_buffer[i], 5, &value); + 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); + return count; + } + if (!strcmp(name, "mpls")) { unsigned n, offset; len = get_labels(&user_buffer[i], pkt_dev); @@ -2387,6 +2430,20 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) pkt_dev->cur_pkt_size = t; } + if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) { + __u16 t; + if (pkt_dev->flags & F_QUEUE_MAP_RND) { + t = random32() % + (pkt_dev->queue_map_max - pkt_dev->queue_map_min + 1) + + pkt_dev->queue_map_min; + } else { + t = pkt_dev->cur_queue_map + 1; + if (t > pkt_dev->queue_map_max) + t = pkt_dev->queue_map_min; + } + pkt_dev->cur_queue_map = t; + } + pkt_dev->flows[flow].count++; } @@ -2557,6 +2614,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, skb->network_header = skb->tail; skb->transport_header = skb->network_header + sizeof(struct iphdr); skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); + skb->queue_mapping = pkt_dev->cur_queue_map; iph = ip_hdr(skb); udph = udp_hdr(skb); @@ -2898,6 +2956,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, skb->network_header = skb->tail; skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); + skb->queue_mapping = pkt_dev->cur_queue_map; iph = ipv6_hdr(skb); udph = udp_hdr(skb); From b163911f8abf89bafb9cc0ec02a9c43af450ea81 Mon Sep 17 00:00:00 2001 From: Robert Olsson Date: Tue, 28 Aug 2007 15:46:58 -0700 Subject: [PATCH 1122/2804] [PKTGEN]: Remove softirq scheduling. It's not a job for pktgen. Signed-off-by: Robert Olsson Signed-off-by: David S. Miller --- net/core/pktgen.c | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 1d6f1c6270b6..84c0edeedf6d 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -167,7 +167,7 @@ #include /* do_div */ #include -#define VERSION "pktgen v2.68: Packet Generator for packet performance testing.\n" +#define VERSION "pktgen v2.69: Packet Generator for packet performance testing.\n" /* The buckets are exponential in 'width' */ #define LAT_BUCKETS_MAX 32 @@ -384,7 +384,6 @@ struct pktgen_thread { struct list_head th_list; struct task_struct *tsk; char result[512]; - u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ /* Field for thread to receive "posted" events terminate, stop ifs etc. */ @@ -1761,9 +1760,6 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) BUG_ON(!t); - seq_printf(seq, "Name: %s max_before_softirq: %d\n", - t->tsk->comm, t->max_before_softirq); - seq_printf(seq, "Running: "); if_lock(t); @@ -1796,7 +1792,6 @@ static ssize_t pktgen_thread_write(struct file *file, int i = 0, max, len, ret; char name[40]; char *pg_result; - unsigned long value = 0; if (count < 1) { // sprintf(pg_result, "Wrong command format"); @@ -1870,12 +1865,8 @@ static ssize_t pktgen_thread_write(struct file *file, } if (!strcmp(name, "max_before_softirq")) { - len = num_arg(&user_buffer[i], 10, &value); - mutex_lock(&pktgen_thread_lock); - t->max_before_softirq = value; - mutex_unlock(&pktgen_thread_lock); + sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); ret = count; - sprintf(pg_result, "OK: max_before_softirq=%lu", value); goto out; } @@ -2154,7 +2145,6 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us) if (spin_until_us - now > jiffies_to_usecs(1) + 1) schedule_timeout_interruptible(1); else if (spin_until_us - now > 100) { - do_softirq(); if (!pkt_dev->running) return; if (need_resched()) @@ -3524,8 +3514,6 @@ static int pktgen_thread_worker(void *arg) struct pktgen_thread *t = arg; struct pktgen_dev *pkt_dev = NULL; int cpu = t->cpu; - u32 max_before_softirq; - u32 tx_since_softirq = 0; BUG_ON(smp_processor_id() != cpu); @@ -3533,8 +3521,6 @@ static int pktgen_thread_worker(void *arg) pr_debug("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid); - max_before_softirq = t->max_before_softirq; - set_current_state(TASK_INTERRUPTIBLE); set_freezable(); @@ -3553,24 +3539,9 @@ static int pktgen_thread_worker(void *arg) __set_current_state(TASK_RUNNING); - if (pkt_dev) { - + if (pkt_dev) pktgen_xmit(pkt_dev); - /* - * We like to stay RUNNING but must also give - * others fair share. - */ - - tx_since_softirq += pkt_dev->last_ok; - - if (tx_since_softirq > max_before_softirq) { - if (local_softirq_pending()) - do_softirq(); - tx_since_softirq = 0; - } - } - if (t->control & T_STOP) { pktgen_stop(t); t->control &= ~(T_STOP); From c45248c70125cc374fdf264659643276c72801bf Mon Sep 17 00:00:00 2001 From: Robert Olsson Date: Mon, 17 Sep 2007 11:47:12 -0700 Subject: [PATCH 1123/2804] [SOFTIRQ]: Remove do_softirq() symbol export. As noted by Christoph Hellwig, pktgen was the only user so it can now be removed. [ Add missing cases caught by Adrian Bunk. -DaveM ] Signed-off-by: Robert Olsson Signed-off-by: David S. Miller --- arch/i386/kernel/irq.c | 2 -- arch/powerpc/kernel/irq.c | 1 - arch/s390/kernel/irq.c | 1 - arch/sh/kernel/irq.c | 1 - arch/x86_64/kernel/irq.c | 1 - kernel/softirq.c | 2 -- 6 files changed, 8 deletions(-) diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index dd2b97fc00b2..4f681bcdb1fc 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -231,8 +231,6 @@ asmlinkage void do_softirq(void) local_irq_restore(flags); } - -EXPORT_SYMBOL(do_softirq); #endif /* diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 24bea97c736c..9bf63d5256db 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -395,7 +395,6 @@ void do_softirq(void) local_irq_restore(flags); } -EXPORT_SYMBOL(do_softirq); /* diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 8f0cbca31203..c36d8123ca14 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -95,7 +95,6 @@ asmlinkage void do_softirq(void) local_irq_restore(flags); } -EXPORT_SYMBOL(do_softirq); void init_irq_proc(void) { diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 03404987528d..4b49d03ffbd2 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -245,7 +245,6 @@ asmlinkage void do_softirq(void) local_irq_restore(flags); } -EXPORT_SYMBOL(do_softirq); #endif void __init init_IRQ(void) diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 39cb3fa83ebb..bd11e42b22bf 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -210,4 +210,3 @@ asmlinkage void do_softirq(void) } local_irq_restore(flags); } -EXPORT_SYMBOL(do_softirq); diff --git a/kernel/softirq.c b/kernel/softirq.c index 0f546ddea43d..dbbdcd7f3c2e 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -271,8 +271,6 @@ asmlinkage void do_softirq(void) local_irq_restore(flags); } -EXPORT_SYMBOL(do_softirq); - #endif /* From 172589ccdde41b59861c92c4a971b95514ef24e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 28 Aug 2007 15:50:33 -0700 Subject: [PATCH 1124/2804] [NET]: DIV_ROUND_UP cleanup (part two) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hopefully captured all single statement cases under net/. I'm not too sure if there is some policy about #includes that are "guaranteed" (ie., in the current tree) to be available through some other #included header, so I just added linux/kernel.h to each changed file that didn't #include it previously. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/sock.h | 3 ++- net/bridge/br_stp_bpdu.c | 2 +- net/dccp/ackvec.c | 5 ++--- net/ieee80211/ieee80211_crypt_ccmp.c | 5 +++-- net/ipv4/inet_diag.c | 5 +++-- net/ipv4/inet_timewait_sock.c | 4 ++-- net/ipv4/tcp.c | 3 ++- net/mac80211/aes_ccm.c | 5 +++-- net/mac80211/tx.c | 2 +- net/sunrpc/svcsock.c | 3 ++- 10 files changed, 21 insertions(+), 16 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index dfeb8b13024f..802c670ba820 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -40,6 +40,7 @@ #ifndef _SOCK_H #define _SOCK_H +#include #include #include #include @@ -702,7 +703,7 @@ extern int sk_stream_mem_schedule(struct sock *sk, int size, int kind); static inline int sk_stream_pages(int amt) { - return (amt + SK_STREAM_MEM_QUANTUM - 1) / SK_STREAM_MEM_QUANTUM; + return DIV_ROUND_UP(amt, SK_STREAM_MEM_QUANTUM); } static inline void sk_stream_mem_reclaim(struct sock *sk) diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 60112bce6698..14f0c888eecc 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -64,7 +64,7 @@ static inline int br_get_ticks(const unsigned char *src) { unsigned long ticks = ntohs(get_unaligned((__be16 *)src)); - return (ticks * HZ + STP_HZ - 1) / STP_HZ; + return DIV_ROUND_UP(ticks * HZ, STP_HZ); } /* called under bridge lock */ diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 3f8984b5f6e8..83378f379f72 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -69,9 +69,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) struct dccp_sock *dp = dccp_sk(sk); struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; /* Figure out how many options do we need to represent the ackvec */ - const u16 nr_opts = (av->dccpav_vec_len + - DCCP_MAX_ACKVEC_OPT_LEN - 1) / - DCCP_MAX_ACKVEC_OPT_LEN; + const u16 nr_opts = DIV_ROUND_UP(av->dccpav_vec_len, + DCCP_MAX_ACKVEC_OPT_LEN); u16 len = av->dccpav_vec_len + 2 * nr_opts, i; u32 elapsed_time; const unsigned char *tail, *from; diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index b016b4104de6..2e6b099fc84c 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -9,6 +9,7 @@ * more details. */ +#include #include #include #include @@ -241,7 +242,7 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) hdr = (struct ieee80211_hdr_4addr *)skb->data; ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); - blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last = data_len % AES_BLOCK_LEN; for (i = 1; i <= blocks; i++) { @@ -351,7 +352,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); xor_block(mic, b, CCMP_MIC_LEN); - blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last = data_len % AES_BLOCK_LEN; for (i = 1; i <= blocks; i++) { diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index def007ec1d6f..686ddd62f71a 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -11,6 +11,7 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -112,7 +113,7 @@ static int inet_csk_diag_fill(struct sock *sk, } #endif -#define EXPIRES_IN_MS(tmo) ((tmo - jiffies) * 1000 + HZ - 1) / HZ +#define EXPIRES_IN_MS(tmo) DIV_ROUND_UP((tmo - jiffies) * 1000, HZ) if (icsk->icsk_pending == ICSK_TIME_RETRANS) { r->idiag_timer = 1; @@ -190,7 +191,7 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw, r->id.idiag_dst[0] = tw->tw_daddr; r->idiag_state = tw->tw_substate; r->idiag_timer = 3; - r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ; + r->idiag_expires = DIV_ROUND_UP(tmo * 1000, HZ); r->idiag_rqueue = 0; r->idiag_wqueue = 0; r->idiag_uid = 0; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 2586df09b9b6..4e189e28f306 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -8,7 +8,7 @@ * From code orinally in TCP */ - +#include #include #include #include @@ -292,7 +292,7 @@ void inet_twsk_schedule(struct inet_timewait_sock *tw, if (timeo >= timewait_len) { slot = INET_TWDR_TWKILL_SLOTS - 1; } else { - slot = (timeo + twdr->period - 1) / twdr->period; + slot = DIV_ROUND_UP(timeo, twdr->period); if (slot >= INET_TWDR_TWKILL_SLOTS) slot = INET_TWDR_TWKILL_SLOTS - 1; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index aff31427f525..18c64c74f6d5 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -247,6 +247,7 @@ * TCP_CLOSE socket is finished */ +#include #include #include #include @@ -2210,7 +2211,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) goto out; mss = skb_shinfo(skb)->gso_size; - skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss; + skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); segs = NULL; goto out; diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index e55569bee7d0..bf7ba128b963 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -7,6 +7,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -63,7 +64,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, s_0 = scratch + AES_BLOCK_LEN; e = scratch + 2 * AES_BLOCK_LEN; - num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; aes_ccm_prepare(tfm, b_0, aad, b, s_0, b); @@ -102,7 +103,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, s_0 = scratch + AES_BLOCK_LEN; a = scratch + 2 * AES_BLOCK_LEN; - num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; aes_ccm_prepare(tfm, b_0, aad, b, s_0, a); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 457166889cc7..4ab29282dd67 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -476,7 +476,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) hdrlen = ieee80211_get_hdrlen(tx->fc); payload_len = first->len - hdrlen; per_fragm = frag_threshold - hdrlen - FCS_LEN; - num_fragm = (payload_len + per_fragm - 1) / per_fragm; + num_fragm = DIV_ROUND_UP(payload_len, per_fragm); frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); if (!frags) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 036ab520df21..406b3e687952 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -19,6 +19,7 @@ * Copyright (C) 1995, 1996 Olaf Kirch */ +#include #include #include #include @@ -877,7 +878,7 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) } else { rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len; rqstp->rq_respages = rqstp->rq_pages + 1 + - (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE; + DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); } if (serv->sv_stats) From bcb5e0eef35059af372a7bd3fc68915278d74bc0 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 28 Aug 2007 15:57:12 -0700 Subject: [PATCH 1125/2804] [IrDA]: MSG_NOSIGNAL support for IrDA sockets Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- net/irda/af_irda.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 4c670cf6aefa..c80949a71923 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -1245,18 +1245,17 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, struct sock *sk = sock->sk; struct irda_sock *self; struct sk_buff *skb; - int err; + int err = -EPIPE; IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len); /* Note : socket.c set MSG_EOR on SEQPACKET sockets */ - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) + if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT | + MSG_NOSIGNAL)) return -EINVAL; - if (sk->sk_shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 0); - return -EPIPE; - } + if (sk->sk_shutdown & SEND_SHUTDOWN) + goto out_err; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; @@ -1283,7 +1282,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, skb = sock_alloc_send_skb(sk, len + self->max_header_size + 16, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) - return -ENOBUFS; + goto out_err; skb_reserve(skb, self->max_header_size + 16); skb_reset_transport_header(skb); @@ -1291,7 +1290,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len); if (err) { kfree_skb(skb); - return err; + goto out_err; } /* @@ -1301,10 +1300,14 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, err = irttp_data_request(self->tsap, skb); if (err) { IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err); - return err; + goto out_err; } /* Tell client how much data we actually sent */ return len; + + out_err: + return sk_stream_error(sk, msg->msg_flags, err); + } /* From 4a1d7c25cb438f96b700ac26dc5aa0a38a6d86ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Villac=C3=ADs=20Lasso?= Date: Tue, 28 Aug 2007 15:57:50 -0700 Subject: [PATCH 1126/2804] [IrDA]: Kingsun Dazzle IrDA USB driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This dongle does not follow the usb-irda specification, so it needs its own special driver. Just like the Kingsun/Donshine dongle, it exposes two interrupt endpoints. Reception is performed through direct reads from the input endpoint. Transmission requires splitting the IrDA frames into 8-byte segments, in which the first byte encodes how many of the remaining 7 bytes are used as data. Speed change is made with a control URB just like the one in cypress_m8, and it seems to support up to 115200 bps. On plugin, this dongle reports vendor and device IDs: 0x07d0:0x4100 Signed-off-by: Alex Villacรญs Lasso Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/Kconfig | 12 + drivers/net/irda/Makefile | 1 + drivers/net/irda/ksdazzle-sir.c | 823 ++++++++++++++++++++++++++++++++ 3 files changed, 836 insertions(+) create mode 100644 drivers/net/irda/ksdazzle-sir.c diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 2098d0af8ff5..cfa7b8835d3d 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -162,7 +162,19 @@ config EP7211_DONGLE Say Y here if you want to build support for the Cirrus logic EP7211 chipset's infrared module. +config KSDAZZLE_DONGLE + tristate "KingSun Dazzle IrDA-USB dongle (EXPERIMENTAL)" + depends on IRDA && USB && EXPERIMENTAL + help + Say Y or M here if you want to build support for the KingSun Dazzle + IrDA-USB bridge device driver. + This USB bridge does not conform to the IrDA-USB device class + specification, and therefore needs its own specific driver. This + dongle supports SIR speeds only (9600 through 115200 bps). + + To compile it as a module, choose M here: the module will be called + ksdazzle-sir. comment "Old SIR device drivers" diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 2808ef5c7b79..e19da3b919a2 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o +obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o # The SIR helper module sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c new file mode 100644 index 000000000000..12b0e7a15bef --- /dev/null +++ b/drivers/net/irda/ksdazzle-sir.c @@ -0,0 +1,823 @@ +/***************************************************************************** +* +* Filename: ksdazzle.c +* Version: 0.1.1 +* Description: Irda KingSun Dazzle USB Dongle +* Status: Experimental +* Author: Alex Villacรญs Lasso +* +* Based on stir4200, mcs7780, kingsun-sir drivers. +* +* 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. +* +* 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. +* +*****************************************************************************/ + +/* + * Following is my most current (2007-07-26) understanding of how the Kingsun + * 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This + * information was deduced by examining the USB traffic captured with USBSnoopy + * from the WinXP driver. Feel free to update here as more of the dongle is + * known. + * + * General: This dongle exposes one interface with two interrupt endpoints, one + * IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine + * dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and + * unwrapped manually as in stir4200, kingsun-sir, and ks959-sir. + * + * Transmission: To transmit an IrDA frame, it is necessary to wrap it, then + * split it into multiple segments of up to 7 bytes each, and transmit each in + * sequence. It seems that sending a single big block (like kingsun-sir does) + * won't work with this dongle. Each segment needs to be prefixed with a value + * equal to (unsigned char)0xF8 + , inside a payload + * of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9, + * and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the + * payload, not considered by the prefix, are ignored (set to 0 by this + * implementation). + * + * Reception: To receive data, the driver must poll the dongle regularly (like + * kingsun-sir.c) with interrupt URBs. If data is available, it will be returned + * in payloads from 0 to 8 bytes long. When concatenated, these payloads form + * a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir + * + * Speed change: To change the speed of the dongle, the driver prepares a + * control URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue 0x0200 + * wIndex 0x0001 + * wLength 0x0008 (length of the payload) + * The payload is a 8-byte record, apparently identical to the one used in + * drivers/usb/serial/cypress_m8.c to change speed: + * __u32 baudSpeed; + * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits + * unsigned int : 1; + * unsigned int stopBits : 1; + * unsigned int parityEnable : 1; + * unsigned int parityType : 1; + * unsigned int : 1; + * unsigned int reset : 1; + * unsigned char reserved[3]; // set to 0 + * + * For now only SIR speeds have been observed with this dongle. Therefore, + * nothing is known on what changes (if any) must be done to frame wrapping / + * unwrapping for higher than SIR speeds. This driver assumes no change is + * necessary and announces support for all the way to 115200 bps. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define KSDAZZLE_VENDOR_ID 0x07d0 +#define KSDAZZLE_PRODUCT_ID 0x4100 + +/* These are the currently known USB ids */ +static struct usb_device_id dongles[] = { + /* KingSun Co,Ltd IrDA/USB Bridge */ + {USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +#define KINGSUN_MTT 0x07 +#define KINGSUN_REQ_RECV 0x01 +#define KINGSUN_REQ_SEND 0x09 + +#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ + +struct ksdazzle_speedparams { + __le32 baudrate; /* baud rate, little endian */ + __u8 flags; + __u8 reserved[3]; +} __attribute__ ((packed)); + +#define KS_DATA_5_BITS 0x00 +#define KS_DATA_6_BITS 0x01 +#define KS_DATA_7_BITS 0x02 +#define KS_DATA_8_BITS 0x03 + +#define KS_STOP_BITS_1 0x00 +#define KS_STOP_BITS_2 0x08 + +#define KS_PAR_DISABLE 0x00 +#define KS_PAR_EVEN 0x10 +#define KS_PAR_ODD 0x30 +#define KS_RESET 0x80 + +#define KINGSUN_EP_IN 0 +#define KINGSUN_EP_OUT 1 + +struct ksdazzle_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct net_device_stats stats; /* network statistics */ + struct qos_info qos; + + struct urb *tx_urb; + __u8 *tx_buf_clear; + unsigned int tx_buf_clear_used; + unsigned int tx_buf_clear_sent; + __u8 tx_payload[8]; + + struct urb *rx_urb; + __u8 rx_payload[8]; + iobuff_t rx_unwrap_buff; + + struct usb_ctrlrequest *speed_setuprequest; + struct urb *speed_urb; + struct ksdazzle_speedparams speedparams; + unsigned int new_speed; + + __u8 ep_in; + __u8 ep_out; + + spinlock_t lock; + int receiving; +}; + +/* Callback transmission routine */ +static void ksdazzle_speed_irq(struct urb *urb) +{ + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ksdazzle_speed_irq: urb asynchronously failed - %d", + urb->status); + } +} + +/* Send a control request to change speed of the dongle */ +static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed) +{ + static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400, + 57600, 115200, 576000, 1152000, 4000000, 0 + }; + int err; + unsigned int i; + + if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL) + return -ENOMEM; + + /* Check that requested speed is among the supported ones */ + for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ; + if (supported_speeds[i] == 0) + return -EOPNOTSUPP; + + memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams)); + kingsun->speedparams.baudrate = cpu_to_le32(speed); + kingsun->speedparams.flags = KS_DATA_8_BITS; + + /* speed_setuprequest pre-filled in ksdazzle_probe */ + usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->speed_setuprequest, + &(kingsun->speedparams), + sizeof(struct ksdazzle_speedparams), + ksdazzle_speed_irq, kingsun); + kingsun->speed_urb->status = 0; + err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC); + + return err; +} + +/* Submit one fragment of an IrDA frame to the dongle */ +static void ksdazzle_send_irq(struct urb *urb); +static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun) +{ + unsigned int wraplen; + int ret; + + /* We can send at most 7 bytes of payload at a time */ + wraplen = 7; + if (wraplen > kingsun->tx_buf_clear_used) + wraplen = kingsun->tx_buf_clear_used; + + /* Prepare payload prefix with used length */ + memset(kingsun->tx_payload, 0, 8); + kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen; + memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen); + + usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev, + usb_sndintpipe(kingsun->usbdev, kingsun->ep_out), + kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1); + kingsun->tx_urb->status = 0; + ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC); + + /* Remember how much data was sent, in order to update at callback */ + kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0; + return ret; +} + +/* Callback transmission routine */ +static void ksdazzle_send_irq(struct urb *urb) +{ + struct ksdazzle_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; + int ret = 0; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + err("ksdazzle_send_irq: Network not running!"); + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ksdazzle_send_irq: urb asynchronously failed - %d", + urb->status); + return; + } + + if (kingsun->tx_buf_clear_used > 0) { + /* Update data remaining to be sent */ + if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) { + memmove(kingsun->tx_buf_clear, + kingsun->tx_buf_clear + + kingsun->tx_buf_clear_sent, + kingsun->tx_buf_clear_used - + kingsun->tx_buf_clear_sent); + } + kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent; + kingsun->tx_buf_clear_sent = 0; + + if (kingsun->tx_buf_clear_used > 0) { + /* There is more data to be sent */ + if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { + err("ksdazzle_send_irq: failed tx_urb submit: %d", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + kingsun->stats.tx_errors++; + netif_start_queue(netdev); + } + } + } else { + /* All data sent, send next speed && wake network queue */ + if (kingsun->new_speed != -1 && + cpu_to_le32(kingsun->new_speed) != + kingsun->speedparams.baudrate) + ksdazzle_change_speed(kingsun, + kingsun->new_speed); + + netif_wake_queue(netdev); + } + } +} + +/* + * Called from net/core when new frame is available. + */ +static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun; + unsigned int wraplen; + int ret = 0; + + if (skb == NULL || netdev == NULL) + return -EINVAL; + + netif_stop_queue(netdev); + + /* the IRDA wrapping routines don't deal with non linear skb */ + SKB_LINEAR_ASSERT(skb); + + kingsun = netdev_priv(netdev); + + spin_lock(&kingsun->lock); + kingsun->new_speed = irda_get_next_speed(skb); + + /* Append data to the end of whatever data remains to be transmitted */ + wraplen = + async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE); + kingsun->tx_buf_clear_used = wraplen; + + if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { + err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + kingsun->stats.tx_errors++; + netif_start_queue(netdev); + } + } else { + kingsun->stats.tx_packets++; + kingsun->stats.tx_bytes += skb->len; + + } + + dev_kfree_skb(skb); + spin_unlock(&kingsun->lock); + + return ret; +} + +/* Receive callback function */ +static void ksdazzle_rcv_irq(struct urb *urb) +{ + struct ksdazzle_cb *kingsun = urb->context; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + kingsun->receiving = 0; + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ksdazzle_rcv_irq: urb asynchronously failed - %d", + urb->status); + kingsun->receiving = 0; + return; + } + + if (urb->actual_length > 0) { + __u8 *bytes = urb->transfer_buffer; + unsigned int i; + + for (i = 0; i < urb->actual_length; i++) { + async_unwrap_char(kingsun->netdev, &kingsun->stats, + &kingsun->rx_unwrap_buff, bytes[i]); + } + kingsun->netdev->last_rx = jiffies; + kingsun->receiving = + (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; + } + + /* This urb has already been filled in ksdazzle_net_open. It is assumed that + urb keeps the pointer to the payload buffer. + */ + urb->status = 0; + usb_submit_urb(urb, GFP_ATOMIC); +} + +/* + * Function ksdazzle_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + */ +static int ksdazzle_net_open(struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + int err = -ENOMEM; + char hwname[16]; + + /* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */ + kingsun->receiving = 0; + + /* Initialize for SIR to copy data directly into skb. */ + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU; + kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!kingsun->rx_unwrap_buff.skb) + goto free_mem; + + skb_reserve(kingsun->rx_unwrap_buff.skb, 1); + kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; + + kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->rx_urb) + goto free_mem; + + kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->tx_urb) + goto free_mem; + + kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->speed_urb) + goto free_mem; + + /* Initialize speed for dongle */ + kingsun->new_speed = 9600; + err = ksdazzle_change_speed(kingsun, 9600); + if (err < 0) + goto free_mem; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + */ + sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); + kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); + if (!kingsun->irlap) { + err("ksdazzle-sir: irlap_open failed"); + goto free_mem; + } + + /* Start reception. */ + usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, + usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), + kingsun->rx_payload, 8, ksdazzle_rcv_irq, kingsun, 1); + kingsun->rx_urb->status = 0; + err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + if (err) { + err("ksdazzle-sir: first urb-submit failed: %d", err); + goto close_irlap; + } + + netif_start_queue(netdev); + + /* Situation at this point: + - all work buffers allocated + - urbs allocated and ready to fill + - max rx packet known (in max_rx) + - unwrap state machine initialized, in state outside of any frame + - receive request in progress + - IrLAP layer started, about to hand over packets to send + */ + + return 0; + + close_irlap: + irlap_close(kingsun->irlap); + free_mem: + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + if (kingsun->rx_unwrap_buff.skb) { + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + } + return err; +} + +/* + * Function ksdazzle_net_close (dev) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int ksdazzle_net_close(struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->receiving = 0; + + /* Stop and remove instance of IrLAP */ + irlap_close(kingsun->irlap); + + kingsun->irlap = NULL; + + return 0; +} + +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq, + int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *)rq; + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the device is still there */ + if (netif_device_present(kingsun->netdev)) + return ksdazzle_change_speed(kingsun, + irq->ifr_baudrate); + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the IrDA stack is still there */ + if (netif_running(kingsun->netdev)) + irda_device_set_media_busy(kingsun->netdev, TRUE); + break; + + case SIOCGRECEIVING: + /* Only approximately true */ + irq->ifr_receiving = kingsun->receiving; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* + * Get device stats (for /proc/net/dev and ifconfig) + */ +static struct net_device_stats *ksdazzle_net_get_stats(struct net_device + *netdev) +{ + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + return &kingsun->stats; +} + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + */ +static int ksdazzle_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + + struct usb_device *dev = interface_to_usbdev(intf); + struct ksdazzle_cb *kingsun = NULL; + struct net_device *net = NULL; + int ret = -ENOMEM; + int pipe, maxp_in, maxp_out; + __u8 ep_in; + __u8 ep_out; + + /* Check that there really are two interrupt endpoints. Check based on the + one in drivers/usb/input/usbmouse.c + */ + interface = intf->cur_altsetting; + if (interface->desc.bNumEndpoints != 2) { + err("ksdazzle: expected 2 endpoints, found %d", + interface->desc.bNumEndpoints); + return -ENODEV; + } + endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; + if (!usb_endpoint_is_int_in(endpoint)) { + err("ksdazzle: endpoint 0 is not interrupt IN"); + return -ENODEV; + } + + ep_in = endpoint->bEndpointAddress; + pipe = usb_rcvintpipe(dev, ep_in); + maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + if (maxp_in > 255 || maxp_in <= 1) { + err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in); + return -ENODEV; + } + + endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; + if (!usb_endpoint_is_int_out(endpoint)) { + err("ksdazzle: endpoint 1 is not interrupt OUT"); + return -ENODEV; + } + + ep_out = endpoint->bEndpointAddress; + pipe = usb_sndintpipe(dev, ep_out); + maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + /* Allocate network device container. */ + net = alloc_irdadev(sizeof(*kingsun)); + if (!net) + goto err_out1; + + SET_MODULE_OWNER(net); + SET_NETDEV_DEV(net, &intf->dev); + kingsun = netdev_priv(net); + kingsun->netdev = net; + kingsun->usbdev = dev; + kingsun->ep_in = ep_in; + kingsun->ep_out = ep_out; + kingsun->irlap = NULL; + kingsun->tx_urb = NULL; + kingsun->tx_buf_clear = NULL; + kingsun->tx_buf_clear_used = 0; + kingsun->tx_buf_clear_sent = 0; + + kingsun->rx_urb = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->receiving = 0; + spin_lock_init(&kingsun->lock); + + kingsun->speed_setuprequest = NULL; + kingsun->speed_urb = NULL; + kingsun->speedparams.baudrate = 0; + + /* Allocate output buffer */ + kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_clear) + goto free_mem; + + /* Allocate and initialize speed setup packet */ + kingsun->speed_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->speed_setuprequest) + goto free_mem; + kingsun->speed_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001); + kingsun->speed_setuprequest->wLength = + cpu_to_le16(sizeof(struct ksdazzle_speedparams)); + + printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, " + "Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&kingsun->qos); + + /* Baud rates known to be supported. Please uncomment if devices (other + than a SonyEriccson K300 phone) can be shown to support higher speeds + with this dongle. + */ + kingsun->qos.baud_rate.bits = + IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200; + kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; + irda_qos_bits_to_value(&kingsun->qos); + + /* Override the network functions we need to use */ + net->hard_start_xmit = ksdazzle_hard_xmit; + net->open = ksdazzle_net_open; + net->stop = ksdazzle_net_close; + net->get_stats = ksdazzle_net_get_stats; + net->do_ioctl = ksdazzle_net_ioctl; + + ret = register_netdev(net); + if (ret != 0) + goto free_mem; + + info("IrDA: Registered KingSun/Dazzle device %s", net->name); + + usb_set_intfdata(intf, kingsun); + + /* Situation at this point: + - all work buffers allocated + - setup requests pre-filled + - urbs not allocated, set to NULL + - max rx packet known (is KINGSUN_FIFO_SIZE) + - unwrap state machine (partially) initialized, but skb == NULL + */ + + return 0; + + free_mem: + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_buf_clear); + free_netdev(net); + err_out1: + return ret; +} + +/* + * The current device is removed, the USB layer tell us to shut it down... + */ +static void ksdazzle_disconnect(struct usb_interface *intf) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + if (!kingsun) + return; + + unregister_netdev(kingsun->netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_buf_clear); + free_netdev(kingsun->netdev); + + usb_set_intfdata(intf, NULL); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + netif_device_detach(kingsun->netdev); + if (kingsun->speed_urb != NULL) + usb_kill_urb(kingsun->speed_urb); + if (kingsun->tx_urb != NULL) + usb_kill_urb(kingsun->tx_urb); + if (kingsun->rx_urb != NULL) + usb_kill_urb(kingsun->rx_urb); + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int ksdazzle_resume(struct usb_interface *intf) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + if (kingsun->rx_urb != NULL) { + /* Setup request already filled in ksdazzle_probe */ + usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + } + netif_device_attach(kingsun->netdev); + + return 0; +} +#endif + +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "ksdazzle-sir", + .probe = ksdazzle_probe, + .disconnect = ksdazzle_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = ksdazzle_suspend, + .resume = ksdazzle_resume, +#endif +}; + +/* + * Module insertion + */ +static int __init ksdazzle_init(void) +{ + return usb_register(&irda_driver); +} + +module_init(ksdazzle_init); + +/* + * Module removal + */ +static void __exit ksdazzle_cleanup(void) +{ + /* Deregister the driver and remove all pending instances */ + usb_deregister(&irda_driver); +} + +module_exit(ksdazzle_cleanup); + +MODULE_AUTHOR("Alex Villacรญs Lasso "); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle"); +MODULE_LICENSE("GPL"); From 4b6aa59999a3a12dd4740a52299c6c33e85a8747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Villac=C3=ADs=20Lasso?= Date: Tue, 28 Aug 2007 15:58:31 -0700 Subject: [PATCH 1127/2804] [IrDA]: Kingsun KS-959 IrDA USB driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This dongle does not follow the usb-irda specification, so it needs its own special driver. First, it uses control URBs for data transfer, instead of bulk or interrupt transfers; the only interrupt endpoint exposed seems to be a dummy to prevent the interface from being rejected. Second, it uses obfuscation and padding at the USB traffic level, for no apparent reason other than to make reverse engineering harder (full details on obfuscation in comments at beginning of source). Although it is advertised as a "4 Mbps FIR dongle", it apparently loses packets at speeds greater than 57600 bps. On plugin, this dongle reports vendor and device IDs: 0x07d0:0x4959 . The Windows driver that is used normally to control this dongle has a filename of KS-959.SYS . Signed-off-by: Alex Villacรญs Lasso Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/Kconfig | 14 + drivers/net/irda/Makefile | 1 + drivers/net/irda/ks959-sir.c | 939 +++++++++++++++++++++++++++++++++++ 3 files changed, 954 insertions(+) create mode 100644 drivers/net/irda/ks959-sir.c diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index cfa7b8835d3d..65806956728a 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -176,6 +176,20 @@ config KSDAZZLE_DONGLE To compile it as a module, choose M here: the module will be called ksdazzle-sir. +config KS959_DONGLE + tristate "KingSun KS-959 IrDA-USB dongle (EXPERIMENTAL)" + depends on IRDA && USB && EXPERIMENTAL + help + Say Y or M here if you want to build support for the KingSun KS-959 + IrDA-USB bridge device driver. + + This USB bridge does not conform to the IrDA-USB device class + specification, and therefore needs its own specific driver. This + dongle supports SIR speeds only (9600 through 57600 bps). + + To compile it as a module, choose M here: the module will be called + ks959-sir. + comment "Old SIR device drivers" config IRPORT_SIR diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index e19da3b919a2..fefbb5909081 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o +obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o # The SIR helper module sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c new file mode 100644 index 000000000000..407afba1a597 --- /dev/null +++ b/drivers/net/irda/ks959-sir.c @@ -0,0 +1,939 @@ +/***************************************************************************** +* +* Filename: ks959-sir.c +* Version: 0.1.2 +* Description: Irda KingSun KS-959 USB Dongle +* Status: Experimental +* Author: Alex Villacรญs Lasso +* with help from Domen Puncer +* +* Based on stir4200, mcs7780, kingsun-sir drivers. +* +* 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. +* +* 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. +* +*****************************************************************************/ + +/* + * Following is my most current (2007-07-17) understanding of how the Kingsun + * KS-959 dongle is supposed to work. This information was deduced by + * reverse-engineering and examining the USB traffic captured with USBSnoopy + * from the WinXP driver. Feel free to update here as more of the dongle is + * known. + * + * My most sincere thanks must go to Domen Puncer for + * invaluable help in cracking the obfuscation and padding required for this + * dongle. + * + * General: This dongle exposes one interface with one interrupt IN endpoint. + * However, the interrupt endpoint is NOT used at all for this dongle. Instead, + * this dongle uses control transfers for everything, including sending and + * receiving the IrDA frame data. Apparently the interrupt endpoint is just a + * dummy to ensure the dongle has a valid interface to present to the PC.And I + * thought the DonShine dongle was weird... In addition, this dongle uses + * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent + * and received, from the dongle. I call it obfuscation because the XOR keying + * and padding required to produce an USB traffic acceptable for the dongle can + * not be explained by any other technical requirement. + * + * Transmission: To transmit an IrDA frame, the driver must prepare a control + * URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue + * wIndex 0x0000 + * wLength + * The payload packet must be manually wrapped and escaped (as in stir4200.c), + * then padded and obfuscated before being sent. Both padding and obfuscation + * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the + * designer/programmer of the dongle used his name as a source for the + * obfuscation. WTF?! + * Apparently the dongle cannot handle payloads larger than 256 bytes. The + * driver has to perform fragmentation in order to send anything larger than + * this limit. + * + * Reception: To receive data, the driver must poll the dongle regularly (like + * kingsun-sir.c) with control URBs and the following as a setup packet: + * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x01 + * wValue 0x0200 + * wIndex 0x0000 + * wLength 0x0800 (size of available buffer) + * If there is data to be read, it will be returned as the response payload. + * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate + * it, the driver must XOR every byte, in sequence, with a value that starts at + * 1 and is incremented with each byte processed, and then with 0x55. The value + * incremented with each byte processed overflows as an unsigned char. The + * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped + * as in stir4200.c The incremented value is NOT reset with each frame, but is + * kept across the entire session with the dongle. Also, the dongle inserts an + * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which + * must be skipped. + * + * Speed change: To change the speed of the dongle, the driver prepares a + * control URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue 0x0200 + * wIndex 0x0001 + * wLength 0x0008 (length of the payload) + * The payload is a 8-byte record, apparently identical to the one used in + * drivers/usb/serial/cypress_m8.c to change speed: + * __u32 baudSpeed; + * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits + * unsigned int : 1; + * unsigned int stopBits : 1; + * unsigned int parityEnable : 1; + * unsigned int parityType : 1; + * unsigned int : 1; + * unsigned int reset : 1; + * unsigned char reserved[3]; // set to 0 + * + * For now only SIR speeds have been observed with this dongle. Therefore, + * nothing is known on what changes (if any) must be done to frame wrapping / + * unwrapping for higher than SIR speeds. This driver assumes no change is + * necessary and announces support for all the way to 57600 bps. Although the + * package announces support for up to 4MBps, tests with a Sony Ericcson K300 + * phone show corruption when receiving large frames at 115200 bps, the highest + * speed announced by the phone. However, transmission at 115200 bps is OK. Go + * figure. Since I don't know whether the phone or the dongle is at fault, max + * announced speed is 57600 bps until someone produces a device that can run + * at higher speeds with this dongle. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define KS959_VENDOR_ID 0x07d0 +#define KS959_PRODUCT_ID 0x4959 + +/* These are the currently known USB ids */ +static struct usb_device_id dongles[] = { + /* KingSun Co,Ltd IrDA/USB Bridge */ + {USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +#define KINGSUN_MTT 0x07 +#define KINGSUN_REQ_RECV 0x01 +#define KINGSUN_REQ_SEND 0x09 + +#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */ +#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ +#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */ + +struct ks959_speedparams { + __le32 baudrate; /* baud rate, little endian */ + __u8 flags; + __u8 reserved[3]; +} __attribute__ ((packed)); + +#define KS_DATA_5_BITS 0x00 +#define KS_DATA_6_BITS 0x01 +#define KS_DATA_7_BITS 0x02 +#define KS_DATA_8_BITS 0x03 + +#define KS_STOP_BITS_1 0x00 +#define KS_STOP_BITS_2 0x08 + +#define KS_PAR_DISABLE 0x00 +#define KS_PAR_EVEN 0x10 +#define KS_PAR_ODD 0x30 +#define KS_RESET 0x80 + +struct ks959_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct net_device_stats stats; /* network statistics */ + struct qos_info qos; + + struct usb_ctrlrequest *tx_setuprequest; + struct urb *tx_urb; + __u8 *tx_buf_clear; + unsigned int tx_buf_clear_used; + unsigned int tx_buf_clear_sent; + __u8 *tx_buf_xored; + + struct usb_ctrlrequest *rx_setuprequest; + struct urb *rx_urb; + __u8 *rx_buf; + __u8 rx_variable_xormask; + iobuff_t rx_unwrap_buff; + struct timeval rx_time; + + struct usb_ctrlrequest *speed_setuprequest; + struct urb *speed_urb; + struct ks959_speedparams speedparams; + unsigned int new_speed; + + spinlock_t lock; + int receiving; +}; + +/* Procedure to perform the obfuscation/padding expected by the dongle + * + * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit + * len_cleartext (IN) Length of the cleartext version of IrDA frame + * buf_xoredtext (OUT) Obfuscated version of frame built by proc + * len_maxbuf (OUT) Maximum space available at buf_xoredtext + * + * (return) length of obfuscated frame with padding + * + * If not enough space (as indicated by len_maxbuf vs. required padding), + * zero is returned + * + * The value of lookup_string is actually a required portion of the algorithm. + * Seems the designer of the dongle wanted to state who exactly is responsible + * for implementing obfuscation. Send your best (or other) wishes to him ]:-) + */ +static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext, + unsigned int len_cleartext, + __u8 * buf_xoredtext, + unsigned int len_maxbuf) +{ + unsigned int len_xoredtext; + + /* Calculate required length with padding, check for necessary space */ + len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10; + if (len_xoredtext <= len_maxbuf) { + static const __u8 lookup_string[] = "wangshuofei19710"; + __u8 xor_mask; + + /* Unlike the WinXP driver, we *do* clear out the padding */ + memset(buf_xoredtext, 0, len_xoredtext); + + xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55; + + while (len_cleartext-- > 0) { + *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask; + } + } else { + len_xoredtext = 0; + } + return len_xoredtext; +} + +/* Callback transmission routine */ +static void ks959_speed_irq(struct urb *urb) +{ + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ks959_speed_irq: urb asynchronously failed - %d", + urb->status); + } +} + +/* Send a control request to change speed of the dongle */ +static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed) +{ + static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400, + 57600, 115200, 576000, 1152000, 4000000, 0 + }; + int err; + unsigned int i; + + if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL) + return -ENOMEM; + + /* Check that requested speed is among the supported ones */ + for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ; + if (supported_speeds[i] == 0) + return -EOPNOTSUPP; + + memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams)); + kingsun->speedparams.baudrate = cpu_to_le32(speed); + kingsun->speedparams.flags = KS_DATA_8_BITS; + + /* speed_setuprequest pre-filled in ks959_probe */ + usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->speed_setuprequest, + &(kingsun->speedparams), + sizeof(struct ks959_speedparams), ks959_speed_irq, + kingsun); + kingsun->speed_urb->status = 0; + err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC); + + return err; +} + +/* Submit one fragment of an IrDA frame to the dongle */ +static void ks959_send_irq(struct urb *urb); +static int ks959_submit_tx_fragment(struct ks959_cb *kingsun) +{ + unsigned int padlen; + unsigned int wraplen; + int ret; + + /* Check whether current plaintext can produce a padded buffer that fits + within the range handled by the dongle */ + wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10; + if (wraplen > kingsun->tx_buf_clear_used) + wraplen = kingsun->tx_buf_clear_used; + + /* Perform dongle obfuscation. Also remove the portion of the frame that + was just obfuscated and will now be sent to the dongle. */ + padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen, + kingsun->tx_buf_xored, + KINGSUN_SND_PACKET_SIZE); + + /* Calculate how much data can be transmitted in this urb */ + kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen); + kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen); + /* Rest of the fields were filled in ks959_probe */ + usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->tx_setuprequest, + kingsun->tx_buf_xored, padlen, + ks959_send_irq, kingsun); + kingsun->tx_urb->status = 0; + ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC); + + /* Remember how much data was sent, in order to update at callback */ + kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0; + return ret; +} + +/* Callback transmission routine */ +static void ks959_send_irq(struct urb *urb) +{ + struct ks959_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; + int ret = 0; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + err("ks959_send_irq: Network not running!"); + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ks959_send_irq: urb asynchronously failed - %d", + urb->status); + return; + } + + if (kingsun->tx_buf_clear_used > 0) { + /* Update data remaining to be sent */ + if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) { + memmove(kingsun->tx_buf_clear, + kingsun->tx_buf_clear + + kingsun->tx_buf_clear_sent, + kingsun->tx_buf_clear_used - + kingsun->tx_buf_clear_sent); + } + kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent; + kingsun->tx_buf_clear_sent = 0; + + if (kingsun->tx_buf_clear_used > 0) { + /* There is more data to be sent */ + if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { + err("ks959_send_irq: failed tx_urb submit: %d", + ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + kingsun->stats.tx_errors++; + netif_start_queue(netdev); + } + } + } else { + /* All data sent, send next speed && wake network queue */ + if (kingsun->new_speed != -1 && + cpu_to_le32(kingsun->new_speed) != + kingsun->speedparams.baudrate) + ks959_change_speed(kingsun, kingsun->new_speed); + + netif_wake_queue(netdev); + } + } +} + +/* + * Called from net/core when new frame is available. + */ +static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct ks959_cb *kingsun; + unsigned int wraplen; + int ret = 0; + + if (skb == NULL || netdev == NULL) + return -EINVAL; + + netif_stop_queue(netdev); + + /* the IRDA wrapping routines don't deal with non linear skb */ + SKB_LINEAR_ASSERT(skb); + + kingsun = netdev_priv(netdev); + + spin_lock(&kingsun->lock); + kingsun->new_speed = irda_get_next_speed(skb); + + /* Append data to the end of whatever data remains to be transmitted */ + wraplen = + async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE); + kingsun->tx_buf_clear_used = wraplen; + + if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { + err("ks959_hard_xmit: failed tx_urb submit: %d", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + kingsun->stats.tx_errors++; + netif_start_queue(netdev); + } + } else { + kingsun->stats.tx_packets++; + kingsun->stats.tx_bytes += skb->len; + + } + + dev_kfree_skb(skb); + spin_unlock(&kingsun->lock); + + return ret; +} + +/* Receive callback function */ +static void ks959_rcv_irq(struct urb *urb) +{ + struct ks959_cb *kingsun = urb->context; + int ret; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + kingsun->receiving = 0; + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("kingsun_rcv_irq: urb asynchronously failed - %d", + urb->status); + kingsun->receiving = 0; + return; + } + + if (urb->actual_length > 0) { + __u8 *bytes = urb->transfer_buffer; + unsigned int i; + + for (i = 0; i < urb->actual_length; i++) { + /* De-obfuscation implemented here: variable portion of + xormask is incremented, and then used with the encoded + byte for the XOR. The result of the operation is used + to unwrap the SIR frame. */ + kingsun->rx_variable_xormask++; + bytes[i] = + bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u; + + /* rx_variable_xormask doubles as an index counter so we + can skip the byte at 0xff (wrapped around to 0). + */ + if (kingsun->rx_variable_xormask != 0) { + async_unwrap_char(kingsun->netdev, + &kingsun->stats, + &kingsun->rx_unwrap_buff, + bytes[i]); + } + } + kingsun->netdev->last_rx = jiffies; + do_gettimeofday(&kingsun->rx_time); + kingsun->receiving = + (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; + } + + /* This urb has already been filled in kingsun_net_open. Setup + packet must be re-filled, but it is assumed that urb keeps the + pointer to the initial setup packet, as well as the payload buffer. + Setup packet is already pre-filled at ks959_probe. + */ + urb->status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); +} + +/* + * Function kingsun_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + */ +static int ks959_net_open(struct net_device *netdev) +{ + struct ks959_cb *kingsun = netdev_priv(netdev); + int err = -ENOMEM; + char hwname[16]; + + /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */ + kingsun->receiving = 0; + + /* Initialize for SIR to copy data directly into skb. */ + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU; + kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!kingsun->rx_unwrap_buff.skb) + goto free_mem; + + skb_reserve(kingsun->rx_unwrap_buff.skb, 1); + kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; + do_gettimeofday(&kingsun->rx_time); + + kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->rx_urb) + goto free_mem; + + kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->tx_urb) + goto free_mem; + + kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->speed_urb) + goto free_mem; + + /* Initialize speed for dongle */ + kingsun->new_speed = 9600; + err = ks959_change_speed(kingsun, 9600); + if (err < 0) + goto free_mem; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + */ + sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); + kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); + if (!kingsun->irlap) { + err("ks959-sir: irlap_open failed"); + goto free_mem; + } + + /* Start reception. Setup request already pre-filled in ks959_probe */ + usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev, + usb_rcvctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->rx_setuprequest, + kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE, + ks959_rcv_irq, kingsun); + kingsun->rx_urb->status = 0; + err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + if (err) { + err("ks959-sir: first urb-submit failed: %d", err); + goto close_irlap; + } + + netif_start_queue(netdev); + + /* Situation at this point: + - all work buffers allocated + - urbs allocated and ready to fill + - max rx packet known (in max_rx) + - unwrap state machine initialized, in state outside of any frame + - receive request in progress + - IrLAP layer started, about to hand over packets to send + */ + + return 0; + + close_irlap: + irlap_close(kingsun->irlap); + free_mem: + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + if (kingsun->rx_unwrap_buff.skb) { + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + } + return err; +} + +/* + * Function kingsun_net_close (kingsun) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int ks959_net_close(struct net_device *netdev) +{ + struct ks959_cb *kingsun = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->receiving = 0; + + /* Stop and remove instance of IrLAP */ + if (kingsun->irlap) + irlap_close(kingsun->irlap); + + kingsun->irlap = NULL; + + return 0; +} + +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *)rq; + struct ks959_cb *kingsun = netdev_priv(netdev); + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the device is still there */ + if (netif_device_present(kingsun->netdev)) + return ks959_change_speed(kingsun, irq->ifr_baudrate); + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the IrDA stack is still there */ + if (netif_running(kingsun->netdev)) + irda_device_set_media_busy(kingsun->netdev, TRUE); + break; + + case SIOCGRECEIVING: + /* Only approximately true */ + irq->ifr_receiving = kingsun->receiving; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* + * Get device stats (for /proc/net/dev and ifconfig) + */ +static struct net_device_stats *ks959_net_get_stats(struct net_device *netdev) +{ + struct ks959_cb *kingsun = netdev_priv(netdev); + return &kingsun->stats; +} + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + */ +static int ks959_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct ks959_cb *kingsun = NULL; + struct net_device *net = NULL; + int ret = -ENOMEM; + + /* Allocate network device container. */ + net = alloc_irdadev(sizeof(*kingsun)); + if (!net) + goto err_out1; + + SET_MODULE_OWNER(net); + SET_NETDEV_DEV(net, &intf->dev); + kingsun = netdev_priv(net); + kingsun->netdev = net; + kingsun->usbdev = dev; + kingsun->irlap = NULL; + kingsun->tx_setuprequest = NULL; + kingsun->tx_urb = NULL; + kingsun->tx_buf_clear = NULL; + kingsun->tx_buf_xored = NULL; + kingsun->tx_buf_clear_used = 0; + kingsun->tx_buf_clear_sent = 0; + + kingsun->rx_setuprequest = NULL; + kingsun->rx_urb = NULL; + kingsun->rx_buf = NULL; + kingsun->rx_variable_xormask = 0; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->receiving = 0; + spin_lock_init(&kingsun->lock); + + kingsun->speed_setuprequest = NULL; + kingsun->speed_urb = NULL; + kingsun->speedparams.baudrate = 0; + + /* Allocate input buffer */ + kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->rx_buf) + goto free_mem; + + /* Allocate input setup packet */ + kingsun->rx_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->rx_setuprequest) + goto free_mem; + kingsun->rx_setuprequest->bRequestType = + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV; + kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->rx_setuprequest->wIndex = 0; + kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE); + + /* Allocate output buffer */ + kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_clear) + goto free_mem; + kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_xored) + goto free_mem; + + /* Allocate and initialize output setup packet */ + kingsun->tx_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->tx_setuprequest) + goto free_mem; + kingsun->tx_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->tx_setuprequest->wValue = 0; + kingsun->tx_setuprequest->wIndex = 0; + kingsun->tx_setuprequest->wLength = 0; + + /* Allocate and initialize speed setup packet */ + kingsun->speed_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->speed_setuprequest) + goto free_mem; + kingsun->speed_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001); + kingsun->speed_setuprequest->wLength = + cpu_to_le16(sizeof(struct ks959_speedparams)); + + printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, " + "Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&kingsun->qos); + + /* Baud rates known to be supported. Please uncomment if devices (other + than a SonyEriccson K300 phone) can be shown to support higher speed + with this dongle. + */ + kingsun->qos.baud_rate.bits = + IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600; + kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; + irda_qos_bits_to_value(&kingsun->qos); + + /* Override the network functions we need to use */ + net->hard_start_xmit = ks959_hard_xmit; + net->open = ks959_net_open; + net->stop = ks959_net_close; + net->get_stats = ks959_net_get_stats; + net->do_ioctl = ks959_net_ioctl; + + ret = register_netdev(net); + if (ret != 0) + goto free_mem; + + info("IrDA: Registered KingSun KS-959 device %s", net->name); + + usb_set_intfdata(intf, kingsun); + + /* Situation at this point: + - all work buffers allocated + - setup requests pre-filled + - urbs not allocated, set to NULL + - max rx packet known (is KINGSUN_FIFO_SIZE) + - unwrap state machine (partially) initialized, but skb == NULL + */ + + return 0; + + free_mem: + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_setuprequest); + kfree(kingsun->tx_buf_xored); + kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_setuprequest); + kfree(kingsun->rx_buf); + free_netdev(net); + err_out1: + return ret; +} + +/* + * The current device is removed, the USB layer tell us to shut it down... + */ +static void ks959_disconnect(struct usb_interface *intf) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + if (!kingsun) + return; + + unregister_netdev(kingsun->netdev); + + /* Mop up receive && transmit urb's */ + if (kingsun->speed_urb != NULL) { + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + } + if (kingsun->tx_urb != NULL) { + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + } + if (kingsun->rx_urb != NULL) { + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + } + + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_setuprequest); + kfree(kingsun->tx_buf_xored); + kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_setuprequest); + kfree(kingsun->rx_buf); + free_netdev(kingsun->netdev); + + usb_set_intfdata(intf, NULL); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int ks959_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + netif_device_detach(kingsun->netdev); + if (kingsun->speed_urb != NULL) + usb_kill_urb(kingsun->speed_urb); + if (kingsun->tx_urb != NULL) + usb_kill_urb(kingsun->tx_urb); + if (kingsun->rx_urb != NULL) + usb_kill_urb(kingsun->rx_urb); + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int ks959_resume(struct usb_interface *intf) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + if (kingsun->rx_urb != NULL) { + /* Setup request already filled in ks959_probe */ + usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + } + netif_device_attach(kingsun->netdev); + + return 0; +} +#endif + +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "ks959-sir", + .probe = ks959_probe, + .disconnect = ks959_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = ks959_suspend, + .resume = ks959_resume, +#endif +}; + +/* + * Module insertion + */ +static int __init ks959_init(void) +{ + return usb_register(&irda_driver); +} + +module_init(ks959_init); + +/* + * Module removal + */ +static void __exit ks959_cleanup(void) +{ + /* Deregister the driver and remove all pending instances */ + usb_deregister(&irda_driver); +} + +module_exit(ks959_cleanup); + +MODULE_AUTHOR("Alex Villacรญs Lasso "); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959"); +MODULE_LICENSE("GPL"); From 2a8a9a88fc1b18f5c45244d0ef8a5352f6cf761f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:52 -0400 Subject: [PATCH 1128/2804] [MAC80211]: avoid copying packets to interfaces that are down David Woodhouse noticed that under some circumstances the number of slab allocations kept growing. After looking a bit, this seemed to happen when you had a management mode interface that was *down*. The reason for this is that when the device is down, all management frames get queued to the in-kernel MLME (via ieee80211_sta_rx_mgmt) but then the sta work is invoked but doesn't run when the netif is down. When you then bring the interface up, all such frames are freed, but if you change the mode all of them are lost because the skb queue is reinitialised as soon as you go back to managed mode. The skb queue is correctly cleared when the interface is brought down, but the code doesn't account for the fact that it may be filled while it is not up. This patch should fix the issue by simply ignoring all interfaces that are down when going through the RX handlers. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211.c | 9 +++++++++ net/mac80211/rx.c | 3 +++ 2 files changed, 12 insertions(+) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 5fc240259f55..00df2a9a2661 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -493,7 +493,16 @@ static void ieee80211_if_shutdown(struct net_device *dev) case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.state = IEEE80211_DISABLED; del_timer_sync(&sdata->u.sta.timer); + /* + * Holding the sub_if_lock for writing here blocks + * out the receive path and makes sure it's not + * currently processing a packet that may get + * added to the queue. + */ + write_lock_bh(&local->sub_if_lock); skb_queue_purge(&sdata->u.sta.skb_queue); + write_unlock_bh(&local->sub_if_lock); + if (!local->ops->hw_scan && local->scan_dev == sdata->dev) { local->sta_scanning = 0; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 95a00eb57249..01176ba52df4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1380,6 +1380,9 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, list_for_each_entry(sdata, &local->sub_if_list, list) { rx.u.rx.ra_match = 1; + if (!netif_running(sdata->dev)) + continue; + prepres = prepare_for_handlers(sdata, bssid, &rx, hdr); /* prepare_for_handlers can change sta */ sta = rx.sta; From 50339a67e2d4386d8919195989371579cab8649d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:52 -0400 Subject: [PATCH 1129/2804] [MAC80211]: fix key debugfs This fixes two issues with the key debugfs: 1) key index obviously isn't unique 2) various missing break statements led to bogus output Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/debugfs_key.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7d56dc9e7326..077f907271cf 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -77,14 +77,17 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, switch (key->alg) { case ALG_WEP: len = scnprintf(buf, sizeof(buf), "\n"); + break; case ALG_TKIP: len = scnprintf(buf, sizeof(buf), "%08x %04x\n", key->u.tkip.iv32, key->u.tkip.iv16); + break; case ALG_CCMP: tpn = key->u.ccmp.tx_pn; len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); + break; default: return 0; } @@ -103,6 +106,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, switch (key->alg) { case ALG_WEP: len = scnprintf(buf, sizeof(buf), "\n"); + break; case ALG_TKIP: for (i = 0; i < NUM_RX_DATA_QUEUES; i++) p += scnprintf(p, sizeof(buf)+buf-p, @@ -110,6 +114,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, key->u.tkip.iv32_rx[i], key->u.tkip.iv16_rx[i]); len = p - buf; + break; case ALG_CCMP: for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { rpn = key->u.ccmp.rx_pn[i]; @@ -119,6 +124,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, rpn[3], rpn[4], rpn[5]); } len = p - buf; + break; default: return 0; } @@ -164,12 +170,14 @@ KEY_OPS(key); void ieee80211_debugfs_key_add(struct ieee80211_local *local, struct ieee80211_key *key) { + static int keycount; char buf[20]; if (!local->debugfs.keys) return; - sprintf(buf, "%d", key->keyidx); + sprintf(buf, "%d", keycount); + keycount++; key->debugfs.dir = debugfs_create_dir(buf, local->debugfs.keys); @@ -239,7 +247,7 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, if (!key->debugfs.dir) return; - sprintf(buf, "../sta/" MAC_FMT, MAC_ARG(sta->addr)); + sprintf(buf, "../../stations/" MAC_FMT, MAC_ARG(sta->addr)); key->debugfs.stalink = debugfs_create_symlink("station", key->debugfs.dir, buf); } From 4dfd1d2f6aeeac67d17d6c22052ae3a86db85c0b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:52 -0400 Subject: [PATCH 1130/2804] [MAC80211]: remove reset callback The callback isn't used so remove it. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e503cd37f82e..233444b46d9a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -568,9 +568,6 @@ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control); - /* Handler for performing hardware reset. */ - int (*reset)(struct ieee80211_hw *hw); - /* Handler that is called when any netdevice attached to the hardware * device is set UP for the first time. This can be used, e.g., to * enable interrupts and beacon sending. */ From 0ef6e49b75d0d64d5deab890c72d19fe86488f73 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:52 -0400 Subject: [PATCH 1131/2804] [MAC80211]: remove IEEE80211_HW_HOST_GEN_BEACON flag The flag is never checked because drivers can simply call ieee80211_beacon_get() regardless of setting this flag. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 233444b46d9a..e635ca41a0df 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -463,14 +463,13 @@ struct ieee80211_hw { /* TODO: frame_type 802.11/802.3, sw_encryption requirements */ - /* Some wireless LAN chipsets generate beacons in the hardware/firmware - * and others rely on host generated beacons. This option is used to - * configure the upper layer IEEE 802.11 module to generate beacons. - * The low-level driver can use ieee80211_beacon_get() to fetch the - * next beacon frame. */ -#define IEEE80211_HW_HOST_GEN_BEACON (1<<0) +/* hole at 0 */ - /* The device needs to be supplied with a beacon template only. */ + /* + * The device only needs to be supplied with a beacon template. + * If you need the host to generate each beacon then don't use + * this flag and use ieee80211_beacon_get(). + */ #define IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE (1<<1) /* Some devices handle decryption internally and do not From e6660d9832f62e97941492b83eccbe370dfa72ba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:52 -0400 Subject: [PATCH 1132/2804] [MAC80211]: remove PRISM2_PARAM_RADIO_ENABLED This now is unused in hostapd/wpa_supplicant. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/hostapd_ioctl.h | 1 - net/mac80211/ieee80211_ioctl.c | 14 -------------- 2 files changed, 15 deletions(-) diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h index 52da513f060a..77a5c8813aee 100644 --- a/net/mac80211/hostapd_ioctl.h +++ b/net/mac80211/hostapd_ioctl.h @@ -32,7 +32,6 @@ enum { PRISM2_PARAM_PREAMBLE = 1003, PRISM2_PARAM_SHORT_SLOT_TIME = 1006, PRISM2_PARAM_NEXT_MODE = 1008, - PRISM2_PARAM_RADIO_ENABLED = 1010, PRISM2_PARAM_ANTENNA_MODE = 1013, PRISM2_PARAM_STAT_TIME = 1016, PRISM2_PARAM_STA_ANTENNA_SEL = 1017, diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 0e88564e524a..b89fb1f2f241 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -287,16 +287,6 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, return -EOPNOTSUPP; } -static int ieee80211_ioctl_set_radio_enabled(struct net_device *dev, - int val) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; - - conf->radio_enabled = val; - return ieee80211_hw_config(wdev_priv(dev->ieee80211_ptr)); -} - static int ieee80211_ioctl_giwname(struct net_device *dev, struct iw_request_info *info, char *name, char *extra) @@ -1107,10 +1097,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, local->next_mode = value; break; - case PRISM2_PARAM_RADIO_ENABLED: - ret = ieee80211_ioctl_set_radio_enabled(dev, value); - break; - case PRISM2_PARAM_ANTENNA_MODE: local->hw.conf.antenna_mode = value; if (ieee80211_hw_config(local)) From aaa92e9a743c740005d8a592dbc1b3ca310d35b5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Sep 2007 03:36:10 -0700 Subject: [PATCH 1133/2804] [MAC80211]: remove IEEE80211_HW_DATA_NULLFUNC_ACK Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/rtl8187_dev.c | 3 +-- include/net/mac80211.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 73f1ebc7eec7..9db9ece31b49 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -606,8 +606,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = IEEE80211_IF_TYPE_MGMT; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_WEP_INCLUDE_IV | - IEEE80211_HW_DATA_NULLFUNC_ACK; + IEEE80211_HW_WEP_INCLUDE_IV; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); dev->queues = 1; dev->max_rssi = 65; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e635ca41a0df..427ff6d36265 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -491,8 +491,7 @@ struct ieee80211_hw { #define IEEE80211_HW_WEP_INCLUDE_IV (1<<5) - /* will data nullfunc frames get proper TX status callback */ -#define IEEE80211_HW_DATA_NULLFUNC_ACK (1<<6) +/* hole at 6 */ /* Force software encryption for TKIP packets if WMM is enabled. */ #define IEEE80211_HW_NO_TKIP_WMM_HWACCEL (1<<7) From 1a84f3fd141d2105d80290316bfa772ba34e9c64 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:52 -0400 Subject: [PATCH 1134/2804] [MAC80211]: ratelimit some RX messages Many if not all of these messages can be triggered by sending a few rogue frames which is trivially done and then we overflow our logs. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/rx.c | 122 ++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 48 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 01176ba52df4..7a6e60fcf9d0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -336,13 +336,16 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) if (!rx->key) { if (!rx->u.rx.ra_match) return TXRX_DROP; - printk(KERN_DEBUG "%s: RX WEP frame with " - "unknown keyidx %d (A1=" MAC_FMT " A2=" - MAC_FMT " A3=" MAC_FMT ")\n", - rx->dev->name, keyidx, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX WEP frame " + "with unknown keyidx %d " + "(A1=" MAC_FMT + " A2=" MAC_FMT + " A3=" MAC_FMT ")\n", + rx->dev->name, keyidx, + MAC_ARG(hdr->addr1), + MAC_ARG(hdr->addr2), + MAC_ARG(hdr->addr3)); if (!rx->local->apdev) return TXRX_DROP; ieee80211_rx_mgmt( @@ -526,16 +529,18 @@ ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; if (!rx->key) { - printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n", - rx->dev->name); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n", + rx->dev->name); return TXRX_DROP; } if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || rx->key->force_sw_encrypt) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { - printk(KERN_DEBUG "%s: RX WEP frame, decrypt " - "failed\n", rx->dev->name); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX WEP frame, decrypt " + "failed\n", rx->dev->name); return TXRX_DROP; } } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { @@ -692,12 +697,15 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) } rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue]; if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { - printk(KERN_DEBUG "%s: defrag: CCMP PN not sequential" - " A2=" MAC_FMT " PN=%02x%02x%02x%02x%02x%02x " - "(expected %02x%02x%02x%02x%02x%02x)\n", - rx->dev->name, MAC_ARG(hdr->addr2), - rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], - pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: defrag: CCMP PN not " + "sequential A2=" MAC_FMT + " PN=%02x%02x%02x%02x%02x%02x " + "(expected %02x%02x%02x%02x%02x%02x)\n", + rx->dev->name, MAC_ARG(hdr->addr2), + rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], + rpn[5], pn[0], pn[1], pn[2], pn[3], + pn[4], pn[5]); return TXRX_DROP; } memcpy(entry->last_pn, pn, CCMP_PN_LEN); @@ -875,8 +883,9 @@ ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) (rx->key || rx->sdata->drop_unencrypted) && (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) { - printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " - "encryption\n", rx->dev->name); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " + "encryption\n", rx->dev->name); return TXRX_DROP; } return TXRX_CONTINUE; @@ -922,10 +931,15 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP && sdata->type != IEEE80211_IF_TYPE_VLAN)) { - printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID=" - MAC_FMT " SA=" MAC_FMT " DA=" MAC_FMT ")\n", - dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3)); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped ToDS frame " + "(BSSID=" MAC_FMT + " SA=" MAC_FMT + " DA=" MAC_FMT ")\n", + dev->name, + MAC_ARG(hdr->addr1), + MAC_ARG(hdr->addr2), + MAC_ARG(hdr->addr3)); return TXRX_DROP; } break; @@ -935,12 +949,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) memcpy(src, hdr->addr4, ETH_ALEN); if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) { - printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame (RA=" - MAC_FMT " TA=" MAC_FMT " DA=" MAC_FMT " SA=" - MAC_FMT ")\n", - rx->dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3), - MAC_ARG(hdr->addr4)); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped FromDS&ToDS " + "frame (RA=" MAC_FMT + " TA=" MAC_FMT " DA=" MAC_FMT + " SA=" MAC_FMT ")\n", + rx->dev->name, + MAC_ARG(hdr->addr1), + MAC_ARG(hdr->addr2), + MAC_ARG(hdr->addr3), + MAC_ARG(hdr->addr4)); return TXRX_DROP; } break; @@ -1015,15 +1033,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) /* send multicast frames both to higher layers in * local net stack and back to the wireless media */ skb2 = skb_copy(skb, GFP_ATOMIC); - if (!skb2) + if (!skb2 && net_ratelimit()) printk(KERN_DEBUG "%s: failed to clone " "multicast frame\n", dev->name); } else { struct sta_info *dsta; dsta = sta_info_get(local, skb->data); if (dsta && !dsta->dev) { - printk(KERN_DEBUG "Station with null dev " - "structure!\n"); + if (net_ratelimit()) + printk(KERN_DEBUG "Station with null " + "dev structure!\n"); } else if (dsta && dsta->dev == dev) { /* Destination station is associated to this * AP, so send the frame directly to it and @@ -1135,24 +1154,28 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, /* TODO: verify that this is not triggered by fragmented * frames (hw does not verify MIC for them). */ - printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " - "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", - dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), keyidx); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " + "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", + dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), + keyidx); if (!sta) { /* Some hardware versions seem to generate incorrect * Michael MIC reports; ignore them to avoid triggering * countermeasures. */ - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for unknown address " MAC_FMT "\n", - dev->name, MAC_ARG(hdr->addr2)); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for unknown address " MAC_FMT "\n", + dev->name, MAC_ARG(hdr->addr2)); goto ignore; } if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) { - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame with no ISWEP flag (src " - MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for a frame with no ISWEP flag (src " + MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); goto ignore; } @@ -1164,9 +1187,11 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, * for group keys and only the AP is sending real multicast * frames in BSS. */ if (keyidx) { - printk(KERN_DEBUG "%s: ignored Michael MIC error for " - "a frame with non-zero keyidx (%d) (src " MAC_FMT - ")\n", dev->name, keyidx, MAC_ARG(hdr->addr2)); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored Michael MIC " + "error for a frame with non-zero keyidx" + " (%d) (src " MAC_FMT ")\n", dev->name, + keyidx, MAC_ARG(hdr->addr2)); goto ignore; } } @@ -1174,10 +1199,11 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) { - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame that cannot be encrypted " - "(fc=0x%04x) (src " MAC_FMT ")\n", - dev->name, rx->fc, MAC_ARG(hdr->addr2)); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for a frame that cannot be encrypted " + "(fc=0x%04x) (src " MAC_FMT ")\n", + dev->name, rx->fc, MAC_ARG(hdr->addr2)); goto ignore; } From 643856729e2fde781f63eb84ecb43bbad35bf1ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:53 -0400 Subject: [PATCH 1135/2804] [MAC80211]: remove ieee80211_msg_wep_frame_unknown_key Neither hostapd nor wpa_supplicant really use it. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville --- net/mac80211/ieee80211_common.h | 2 +- net/mac80211/rx.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h index 77c6afb7f6a8..dd315a057510 100644 --- a/net/mac80211/ieee80211_common.h +++ b/net/mac80211/ieee80211_common.h @@ -48,7 +48,7 @@ enum ieee80211_msg_type { ieee80211_msg_tx_callback_ack = 1, ieee80211_msg_tx_callback_fail = 2, /* hole at 3, was ieee80211_msg_passive_scan but unused */ - ieee80211_msg_wep_frame_unknown_key = 4, + /* hole at 4, was ieee80211_msg_wep_frame_unknown_key but now unused */ ieee80211_msg_michael_mic_failure = 5, /* hole at 6, was monitor but never sent to userspace */ ieee80211_msg_sta_not_assoc = 7, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7a6e60fcf9d0..b0959c249869 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -346,12 +346,11 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) MAC_ARG(hdr->addr1), MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3)); - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt( - rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_wep_frame_unknown_key); - return TXRX_QUEUED; + /* + * TODO: notify userspace about this + * via cfg/nl80211 + */ + return TXRX_DROP; } } } From 82f716056fb1c214289fe6c284b0316858c1b70c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:53 -0400 Subject: [PATCH 1136/2804] [MAC80211]: remove radar stuff Unused in drivers, userspace and mac80211. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 6 ------ net/mac80211/ieee80211.c | 28 ---------------------------- net/mac80211/ieee80211_common.h | 2 +- 3 files changed, 1 insertion(+), 35 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 427ff6d36265..000b8e3133ba 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1015,12 +1015,6 @@ ieee80211_get_mc_list_item(struct ieee80211_hw *hw, /* called by driver to notify scan status completed */ void ieee80211_scan_completed(struct ieee80211_hw *hw); -/* Function to indicate Radar Detection. The low level driver must call this - * function to indicate the presence of radar in the current channel. - * Additionally the radar type also could be sent */ -int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, - int radar, int radar_type); - /* return a pointer to the source address (SA) */ static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) { diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 00df2a9a2661..703f998292c8 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -201,34 +201,6 @@ ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, netif_rx(skb); } -int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, - int radar, int radar_type) -{ - struct sk_buff *skb; - struct ieee80211_radar_info *msg; - struct ieee80211_local *local = hw_to_local(hw); - - if (!local->apdev) - return 0; - - skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + - sizeof(struct ieee80211_radar_info)); - - if (!skb) - return -ENOMEM; - skb_reserve(skb, sizeof(struct ieee80211_frame_info)); - - msg = (struct ieee80211_radar_info *) - skb_put(skb, sizeof(struct ieee80211_radar_info)); - msg->channel = channel; - msg->radar = radar; - msg->radar_type = radar_type; - - ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar); - return 0; -} -EXPORT_SYMBOL(ieee80211_radar_status); - void ieee80211_key_threshold_notify(struct net_device *dev, struct ieee80211_key *key, struct sta_info *sta) diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h index dd315a057510..d0bbd00b4617 100644 --- a/net/mac80211/ieee80211_common.h +++ b/net/mac80211/ieee80211_common.h @@ -54,7 +54,7 @@ enum ieee80211_msg_type { ieee80211_msg_sta_not_assoc = 7, /* 8 was ieee80211_msg_set_aid_for_sta */ ieee80211_msg_key_threshold_notification = 9, - ieee80211_msg_radar = 11, + /* 11 was ieee80211_msg_radar */ }; struct ieee80211_msg_key_notification { From 3017b80bf0c4d6a44ccf0d35db9dadf01092b54e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:53 -0400 Subject: [PATCH 1137/2804] [MAC80211]: fix software decryption When doing key selection for software decryption, mac80211 gets a few things wrong: it always uses pairwise keys if configured, even if the frame is addressed to a multicast address. Also, it doesn't allow using a key index of zero if a pairwise key has also been found. This patch changes the key selection code to be (more) in line with the 802.11 specification. I have confirmed that with this, multicast frames are correctly decrypted and I've tested with WEP as well. While at it, I've cleaned up the semantics of the hardware flags IEEE80211_HW_WEP_INCLUDE_IV and IEEE80211_HW_DEVICE_HIDES_WEP and clarified them in the mac80211.h header; it is also now allowed to set the IEEE80211_HW_DEVICE_HIDES_WEP option even if it only applies to frames that have been decrypted by the hw, unencrypted frames must be dropped but encrypted frames that the hardware couldn't handle can be passed up unmodified. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville --- include/net/mac80211.h | 37 +++++++++++--- net/mac80211/rx.c | 113 +++++++++++++++++++++++++---------------- net/mac80211/wpa.c | 7 +-- 3 files changed, 103 insertions(+), 54 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 000b8e3133ba..6a2a0c3e7255 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1,7 +1,9 @@ /* - * Low-level hardware driver -- IEEE 802.11 driver (80211.o) interface + * mac80211 <-> driver interface + * * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc + * Copyright 2007 Johannes Berg * * 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 @@ -472,10 +474,16 @@ struct ieee80211_hw { */ #define IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE (1<<1) - /* Some devices handle decryption internally and do not + /* + * Some devices handle decryption internally and do not * indicate whether the frame was encrypted (unencrypted frames * will be dropped by the hardware, unless specifically allowed - * through) */ + * through.) + * It is permissible to not handle all encrypted frames and fall + * back to software encryption; however, if this flag is set + * unencrypted frames must be dropped unless the driver is told + * otherwise via the set_ieee8021x() callback. + */ #define IEEE80211_HW_DEVICE_HIDES_WEP (1<<2) /* Whether RX frames passed to ieee80211_rx() include FCS in the end */ @@ -489,6 +497,18 @@ struct ieee80211_hw { * can fetch them with ieee80211_get_buffered_bc(). */ #define IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING (1<<4) + /* + * This flag is only relevant if hardware encryption is used. + * If set, it has two meanings: + * 1) the IV and ICV are present in received frames that have + * been decrypted (unless IEEE80211_HW_DEVICE_HIDES_WEP is + * also set) + * 2) on transmission, the IV should be generated in software. + * + * Please let us know if you *don't* use this flag, the stack would + * really like to be able to get the IV to keep key statistics + * accurate. + */ #define IEEE80211_HW_WEP_INCLUDE_IV (1<<5) /* hole at 6 */ @@ -496,11 +516,12 @@ struct ieee80211_hw { /* Force software encryption for TKIP packets if WMM is enabled. */ #define IEEE80211_HW_NO_TKIP_WMM_HWACCEL (1<<7) - /* Some devices handle Michael MIC internally and do not include MIC in - * the received packets passed up. device_strips_mic must be set - * for such devices. The 'encryption' frame control bit is expected to - * be still set in the IEEE 802.11 header with this option unlike with - * the device_hides_wep configuration option. + /* + * Some devices handle Michael MIC internally and do not include MIC in + * the received packets passed up. This flag must be set for such + * devices. The 'encryption' frame control bit is expected to be still + * set in the IEEE 802.11 header with this option unlike with the + * IEEE80211_HW_DEVICE_HIDES_WEP flag. */ #define IEEE80211_HW_DEVICE_STRIPS_MIC (1<<8) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b0959c249869..08ca066246b9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -310,52 +310,77 @@ static ieee80211_txrx_result ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - int always_sta_key; + int keyidx; + int hdrlen; - if (rx->sdata->type == IEEE80211_IF_TYPE_STA) - always_sta_key = 0; - else - always_sta_key = 1; + /* + * Key selection 101 + * + * There are three types of keys: + * - GTK (group keys) + * - PTK (pairwise keys) + * - STK (station-to-station pairwise keys) + * + * When selecting a key, we have to distinguish between multicast + * (including broadcast) and unicast frames, the latter can only + * use PTKs and STKs while the former always use GTKs. Unless, of + * course, actual WEP keys ("pre-RSNA") are used, then unicast + * frames can also use key indizes like GTKs. Hence, if we don't + * have a PTK/STK we check the key index for a WEP key. + * + * There is also a slight problem in IBSS mode: GTKs are negotiated + * with each station, that is something we don't currently handle. + */ - if (rx->sta && rx->sta->key && always_sta_key) { + if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) + return TXRX_CONTINUE; + + /* + * No point in finding a key if the frame is neither + * addressed to us nor a multicast frame. + */ + if (!rx->u.rx.ra_match) + return TXRX_CONTINUE; + + if (!is_multicast_ether_addr(hdr->addr1) && rx->sta && rx->sta->key) { rx->key = rx->sta->key; } else { - if (rx->sta && rx->sta->key) - rx->key = rx->sta->key; - else - rx->key = rx->sdata->default_key; + /* + * The device doesn't give us the IV so we won't be + * able to look up the key. That's ok though, we + * don't need to decrypt the frame, we just won't + * be able to keep statistics accurate. + * Except for key threshold notifications, should + * we somehow allow the driver to tell us which key + * the hardware used if this flag is set? + */ + if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) + return TXRX_CONTINUE; - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->fc & IEEE80211_FCTL_PROTECTED) { - int keyidx = ieee80211_wep_get_keyidx(rx->skb); + hdrlen = ieee80211_get_hdrlen(rx->fc); - if (keyidx >= 0 && keyidx < NUM_DEFAULT_KEYS && - (!rx->sta || !rx->sta->key || keyidx > 0)) - rx->key = rx->sdata->keys[keyidx]; + if (rx->skb->len < 8 + hdrlen) + return TXRX_DROP; /* TODO: count this? */ - if (!rx->key) { - if (!rx->u.rx.ra_match) - return TXRX_DROP; - if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX WEP frame " - "with unknown keyidx %d " - "(A1=" MAC_FMT - " A2=" MAC_FMT - " A3=" MAC_FMT ")\n", - rx->dev->name, keyidx, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); - /* - * TODO: notify userspace about this - * via cfg/nl80211 - */ - return TXRX_DROP; - } - } + /* + * no need to call ieee80211_wep_get_keyidx, + * it verifies a bunch of things we've done already + */ + keyidx = rx->skb->data[hdrlen + 3] >> 6; + + rx->key = rx->sdata->keys[keyidx]; + + /* + * RSNA-protected unicast frames should always be sent with + * pairwise or station-to-station keys, but for WEP we allow + * using a key index as well. + */ + if (rx->key && rx->key->alg != ALG_WEP && + !is_multicast_ether_addr(hdr->addr1)) + rx->key = NULL; } - if (rx->fc & IEEE80211_FCTL_PROTECTED && rx->key && rx->u.rx.ra_match) { + if (rx->key) { rx->key->tx_rx_count++; if (unlikely(rx->local->key_tx_rx_threshold && rx->key->tx_rx_count > @@ -516,10 +541,6 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) static ieee80211_txrx_result ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) { - /* If the device handles decryption totally, skip this test */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) - return TXRX_CONTINUE; - if ((rx->key && rx->key->alg != ALG_WEP) || !(rx->fc & IEEE80211_FCTL_PROTECTED) || ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && @@ -871,8 +892,14 @@ ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) static ieee80211_txrx_result ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) { - /* If the device handles decryption totally, skip this test */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) + /* + * Pass through unencrypted frames if the hardware might have + * decrypted them already without telling us, but that can only + * be true if we either didn't find a key or the found key is + * uploaded to the hardware. + */ + if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) && + (!rx->key || !rx->key->force_sw_encrypt)) return TXRX_CONTINUE; /* Drop unencrypted frames if key is set. */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 783af32c6911..f5723ea15aae 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -137,9 +137,10 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) fc = rx->fc; - /* If device handles decryption totally, skip this check */ - if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) || - (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC)) + /* + * No way to verify the MIC if the hardware stripped it + */ + if (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC) return TXRX_CONTINUE; if (!rx->key || rx->key->alg != ALG_TKIP || From b2446b36800948586f1d1b8ef05803bba5f7489e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:53 -0400 Subject: [PATCH 1138/2804] [MAC80211]: remove unused ioctls (1) The ioctls * PRISM2_PARAM_ANTENNA_MODE * PRISM2_PARAM_STAT_TIME are not used by hostapd or wpa_supplicant. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 3 --- net/mac80211/hostapd_ioctl.h | 2 -- net/mac80211/ieee80211.c | 42 ---------------------------------- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/ieee80211_ioctl.c | 22 ------------------ 5 files changed, 71 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6a2a0c3e7255..ff6a9c35e6d6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -302,9 +302,6 @@ struct ieee80211_conf { u8 antenna_sel_tx; u8 antenna_sel_rx; - int antenna_def; - int antenna_mode; - /* Following five fields are used for IEEE 802.11H */ unsigned int radar_detect; unsigned int spect_mgmt; diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h index 77a5c8813aee..f0f8051502da 100644 --- a/net/mac80211/hostapd_ioctl.h +++ b/net/mac80211/hostapd_ioctl.h @@ -32,8 +32,6 @@ enum { PRISM2_PARAM_PREAMBLE = 1003, PRISM2_PARAM_SHORT_SLOT_TIME = 1006, PRISM2_PARAM_NEXT_MODE = 1008, - PRISM2_PARAM_ANTENNA_MODE = 1013, - PRISM2_PARAM_STAT_TIME = 1016, PRISM2_PARAM_STA_ANTENNA_SEL = 1017, PRISM2_PARAM_TX_POWER_REDUCTION = 1022, PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024, diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 703f998292c8..8f472379b128 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -786,42 +786,6 @@ struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_get_mc_list_item); -static void ieee80211_stat_refresh(unsigned long data) -{ - struct ieee80211_local *local = (struct ieee80211_local *) data; - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; - - if (!local->stat_time) - return; - - /* go through all stations */ - read_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { - sta->channel_use = (sta->channel_use_raw / local->stat_time) / - CHAN_UTIL_PER_10MS; - sta->channel_use_raw = 0; - } - read_unlock_bh(&local->sta_lock); - - /* go through all subinterfaces */ - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - sdata->channel_use = (sdata->channel_use_raw / - local->stat_time) / CHAN_UTIL_PER_10MS; - sdata->channel_use_raw = 0; - } - read_unlock(&local->sub_if_lock); - - /* hardware interface */ - local->channel_use = (local->channel_use_raw / - local->stat_time) / CHAN_UTIL_PER_10MS; - local->channel_use_raw = 0; - - local->stat_timer.expires = jiffies + HZ * local->stat_time / 100; - add_timer(&local->stat_timer); -} - void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) @@ -1260,9 +1224,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_LIST_HEAD(&local->sub_if_list); INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); - init_timer(&local->stat_timer); - local->stat_timer.function = ieee80211_stat_refresh; - local->stat_timer.data = (unsigned long) local; ieee80211_rx_bss_list_init(mdev); sta_info_init(local); @@ -1461,9 +1422,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rtnl_unlock(); - if (local->stat_time) - del_timer_sync(&local->stat_timer); - ieee80211_rx_bss_list_deinit(local->mdev); ieee80211_clear_tx_pending(local); sta_info_stop(local); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cc9999cd089c..2caf1a2f31f7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -509,8 +509,6 @@ struct ieee80211_local { u32 channel_use; u32 channel_use_raw; - u32 stat_time; - struct timer_list stat_timer; #ifdef CONFIG_MAC80211_DEBUGFS struct work_struct sta_debugfs_add; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index b89fb1f2f241..946aeb51a12b 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1075,15 +1075,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, } break; - case PRISM2_PARAM_STAT_TIME: - if (!local->stat_time && value) { - local->stat_timer.expires = jiffies + HZ * value / 100; - add_timer(&local->stat_timer); - } else if (local->stat_time && !value) { - del_timer_sync(&local->stat_timer); - } - local->stat_time = value; - break; case PRISM2_PARAM_SHORT_SLOT_TIME: if (value) local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME; @@ -1097,12 +1088,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, local->next_mode = value; break; - case PRISM2_PARAM_ANTENNA_MODE: - local->hw.conf.antenna_mode = value; - if (ieee80211_hw_config(local)) - ret = -EINVAL; - break; - case PRISM2_PARAM_STA_ANTENNA_SEL: local->sta_antenna_sel = value; break; @@ -1194,9 +1179,6 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, *param = sdata->short_preamble; break; - case PRISM2_PARAM_STAT_TIME: - *param = local->stat_time; - break; case PRISM2_PARAM_SHORT_SLOT_TIME: *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME); break; @@ -1205,10 +1187,6 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, *param = local->next_mode; break; - case PRISM2_PARAM_ANTENNA_MODE: - *param = local->hw.conf.antenna_mode; - break; - case PRISM2_PARAM_STA_ANTENNA_SEL: *param = local->sta_antenna_sel; break; From 53cb670042999b8acb70945ce522b015dcdf7b43 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:53 -0400 Subject: [PATCH 1139/2804] [MAC80211]: remove unused ioctls (2) The ioctls * PRISM2_PARAM_STA_ANTENNA_SEL * PRISM2_PARAM_TX_POWER_REDUCTION * PRISM2_PARAM_DEFAULT_WEP_ONLY are not used by hostapd or wpa_supplicant. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 1 - net/mac80211/debugfs.c | 5 ----- net/mac80211/hostapd_ioctl.h | 3 --- net/mac80211/ieee80211_i.h | 11 ----------- net/mac80211/ieee80211_ioctl.c | 27 --------------------------- net/mac80211/rc80211_simple.c | 8 -------- net/mac80211/sta_info.h | 4 ---- net/mac80211/tx.c | 3 --- 8 files changed, 62 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ff6a9c35e6d6..1c59e24544c7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -296,7 +296,6 @@ struct ieee80211_conf { u8 power_level; /* transmit power limit for current * regulatory domain; in dBm */ u8 antenna_max; /* maximum antenna gain */ - short tx_power_reduction; /* in 0.1 dBm */ /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ u8 antenna_sel_tx; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 476c8486f789..76c39eb72817 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -110,9 +110,6 @@ DEBUGFS_READONLY_FILE(mode, 20, "%s", ieee80211_mode_str(local->hw.conf.phymode)); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", local->wep_iv & 0xffffff); -DEBUGFS_READONLY_FILE(tx_power_reduction, 20, "%d.%d dBm", - local->hw.conf.tx_power_reduction / 10, - local->hw.conf.tx_power_reduction % 10); DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", local->rate_ctrl ? local->rate_ctrl->ops->name : ""); @@ -317,7 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(total_ps_buffered); DEBUGFS_ADD(mode); DEBUGFS_ADD(wep_iv); - DEBUGFS_ADD(tx_power_reduction); DEBUGFS_ADD(modes); statsd = debugfs_create_dir("statistics", phyd); @@ -382,7 +378,6 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_DEL(total_ps_buffered); DEBUGFS_DEL(mode); DEBUGFS_DEL(wep_iv); - DEBUGFS_DEL(tx_power_reduction); DEBUGFS_DEL(modes); DEBUGFS_STATS_DEL(transmitted_fragment_count); diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h index f0f8051502da..8d219d67db35 100644 --- a/net/mac80211/hostapd_ioctl.h +++ b/net/mac80211/hostapd_ioctl.h @@ -32,10 +32,7 @@ enum { PRISM2_PARAM_PREAMBLE = 1003, PRISM2_PARAM_SHORT_SLOT_TIME = 1006, PRISM2_PARAM_NEXT_MODE = 1008, - PRISM2_PARAM_STA_ANTENNA_SEL = 1017, - PRISM2_PARAM_TX_POWER_REDUCTION = 1022, PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024, - PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026, PRISM2_PARAM_WIFI_WME_NOACK_TEST = 1033, PRISM2_PARAM_SCAN_FLAGS = 1035, PRISM2_PARAM_HW_MODES = 1036, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2caf1a2f31f7..2f6fff6317eb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -514,12 +514,6 @@ struct ieee80211_local { struct work_struct sta_debugfs_add; #endif - enum { - STA_ANTENNA_SEL_AUTO = 0, - STA_ANTENNA_SEL_SW_CTRL = 1, - STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2 - } sta_antenna_sel; - #ifdef CONFIG_MAC80211_DEBUG_COUNTERS /* TX/RX handler statistics */ unsigned int tx_handlers_drop; @@ -555,10 +549,6 @@ struct ieee80211_local { int total_ps_buffered; /* total number of all buffered unicast and * multicast packets for power saving stations */ - int allow_broadcast_always; /* whether to allow TX of broadcast frames - * even when there are no associated STAs - */ - int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ @@ -585,7 +575,6 @@ struct ieee80211_local { struct dentry *total_ps_buffered; struct dentry *mode; struct dentry *wep_iv; - struct dentry *tx_power_reduction; struct dentry *modes; struct dentry *statistics; struct local_debugfsdentries_statsdentries { diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 946aeb51a12b..2e85032808fe 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1088,25 +1088,10 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, local->next_mode = value; break; - case PRISM2_PARAM_STA_ANTENNA_SEL: - local->sta_antenna_sel = value; - break; - - case PRISM2_PARAM_TX_POWER_REDUCTION: - if (value < 0) - ret = -EINVAL; - else - local->hw.conf.tx_power_reduction = value; - break; - case PRISM2_PARAM_KEY_TX_RX_THRESHOLD: local->key_tx_rx_threshold = value; break; - case PRISM2_PARAM_DEFAULT_WEP_ONLY: - ret = ieee80211_ioctl_default_wep_only(local, value); - break; - case PRISM2_PARAM_WIFI_WME_NOACK_TEST: local->wifi_wme_noack_test = value; break; @@ -1187,22 +1172,10 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, *param = local->next_mode; break; - case PRISM2_PARAM_STA_ANTENNA_SEL: - *param = local->sta_antenna_sel; - break; - - case PRISM2_PARAM_TX_POWER_REDUCTION: - *param = local->hw.conf.tx_power_reduction; - break; - case PRISM2_PARAM_KEY_TX_RX_THRESHOLD: *param = local->key_tx_rx_threshold; break; - case PRISM2_PARAM_DEFAULT_WEP_ONLY: - *param = local->default_wep_only; - break; - case PRISM2_PARAM_WIFI_WME_NOACK_TEST: *param = local->wifi_wme_noack_test; break; diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index 17b9f46bbf2b..ef91ce428aca 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -147,14 +147,6 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, srctrl = sta->rate_ctrl_priv; srctrl->tx_num_xmit++; if (status->excessive_retries) { - sta->antenna_sel_tx = sta->antenna_sel_tx == 1 ? 2 : 1; - sta->antenna_sel_rx = sta->antenna_sel_rx == 1 ? 2 : 1; - if (local->sta_antenna_sel == STA_ANTENNA_SEL_SW_CTRL_DEBUG) { - printk(KERN_DEBUG "%s: " MAC_FMT " TX antenna --> %d " - "RX antenna --> %d (@%lu)\n", - dev->name, MAC_ARG(hdr->addr1), - sta->antenna_sel_tx, sta->antenna_sel_rx, jiffies); - } srctrl->tx_num_failures++; sta->tx_retry_failed++; sta->tx_num_consecutive_failures++; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b5ef72379add..4afa7df2a180 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -90,10 +90,6 @@ struct sta_info { int channel_use; int channel_use_raw; - u8 antenna_sel_tx; - u8 antenna_sel_rx; - - int key_idx_compression; /* key table index for compression and TX * filtering; used only if sta->key is not * set */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4ab29282dd67..c9b909d9498b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -243,7 +243,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) } else { if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && tx->local->num_sta == 0 && - !tx->local->allow_broadcast_always && tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) { /* * No associated STAs - no need to send multicast @@ -959,8 +958,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, */ control->power_level = local->hw.conf.power_level; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta) - control->antenna_sel_tx = tx->sta->antenna_sel_tx; /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); From 7b33a57f0f5ed9fcc87f98ff5f6aa54291bd0558 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:53 -0400 Subject: [PATCH 1140/2804] [MAC80211]: remove unused ioctls (3) The ioctls * PRISM2_PARAM_RADAR_DETECT * PRISM2_PARAM_SPECTRUM_MGMT are not used by hostapd or wpa_supplicant, Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 14 -------------- net/mac80211/debugfs.c | 4 ---- net/mac80211/hostapd_ioctl.h | 2 -- net/mac80211/ieee80211_i.h | 1 - net/mac80211/ieee80211_ioctl.c | 6 ------ 5 files changed, 27 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1c59e24544c7..029e8cb7bf4e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -300,20 +300,6 @@ struct ieee80211_conf { /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ u8 antenna_sel_tx; u8 antenna_sel_rx; - - /* Following five fields are used for IEEE 802.11H */ - unsigned int radar_detect; - unsigned int spect_mgmt; - /* All following fields are currently unused. */ - unsigned int quiet_duration; /* duration of quiet period */ - unsigned int quiet_offset; /* how far into the beacon is the quiet - * period */ - unsigned int quiet_period; - u8 radar_firpwr_threshold; - u8 radar_rssi_threshold; - u8 pulse_height_threshold; - u8 pulse_rssi_threshold; - u8 pulse_inband_threshold; }; /** diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 76c39eb72817..dc5ed1a8bf62 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -86,8 +86,6 @@ DEBUGFS_READONLY_FILE(channel, 20, "%d", local->hw.conf.channel); DEBUGFS_READONLY_FILE(frequency, 20, "%d", local->hw.conf.freq); -DEBUGFS_READONLY_FILE(radar_detect, 20, "%d", - local->hw.conf.radar_detect); DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d", local->hw.conf.antenna_sel_tx); DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", @@ -302,7 +300,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(channel); DEBUGFS_ADD(frequency); - DEBUGFS_ADD(radar_detect); DEBUGFS_ADD(antenna_sel_tx); DEBUGFS_ADD(antenna_sel_rx); DEBUGFS_ADD(bridge_packets); @@ -366,7 +363,6 @@ void debugfs_hw_del(struct ieee80211_local *local) { DEBUGFS_DEL(channel); DEBUGFS_DEL(frequency); - DEBUGFS_DEL(radar_detect); DEBUGFS_DEL(antenna_sel_tx); DEBUGFS_DEL(antenna_sel_rx); DEBUGFS_DEL(bridge_packets); diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h index 8d219d67db35..fd072cb24e50 100644 --- a/net/mac80211/hostapd_ioctl.h +++ b/net/mac80211/hostapd_ioctl.h @@ -39,8 +39,6 @@ enum { PRISM2_PARAM_CREATE_IBSS = 1037, PRISM2_PARAM_WMM_ENABLED = 1038, PRISM2_PARAM_MIXED_CELL = 1039, - PRISM2_PARAM_RADAR_DETECT = 1043, - PRISM2_PARAM_SPECTRUM_MGMT = 1044, }; enum { diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2f6fff6317eb..c557d578aa30 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -563,7 +563,6 @@ struct ieee80211_local { struct local_debugfsdentries { struct dentry *channel; struct dentry *frequency; - struct dentry *radar_detect; struct dentry *antenna_sel_tx; struct dentry *antenna_sel_rx; struct dentry *bridge_packets; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 2e85032808fe..785f437b306a 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1125,12 +1125,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, else sdata->u.sta.wmm_enabled = !!value; break; - case PRISM2_PARAM_RADAR_DETECT: - local->hw.conf.radar_detect = value; - break; - case PRISM2_PARAM_SPECTRUM_MGMT: - local->hw.conf.spect_mgmt = value; - break; default: ret = -EOPNOTSUPP; break; From 808718c1477b8350e9e329bf4a35391ac7c7f982 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:53 -0400 Subject: [PATCH 1141/2804] [MAC80211]: kill key_mgmt, use key_management_enabled The key_mgmt variable for STA interfaces doesn't seem well-defined nor do we actually use the values other than "NONE", so change it to be named better. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/hostapd_ioctl.h | 8 -------- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/ieee80211_ioctl.c | 20 +++++--------------- net/mac80211/ieee80211_sta.c | 3 +-- 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h index fd072cb24e50..d43711aff4c5 100644 --- a/net/mac80211/hostapd_ioctl.h +++ b/net/mac80211/hostapd_ioctl.h @@ -41,14 +41,6 @@ enum { PRISM2_PARAM_MIXED_CELL = 1039, }; -enum { - IEEE80211_KEY_MGMT_NONE = 0, - IEEE80211_KEY_MGMT_IEEE8021X = 1, - IEEE80211_KEY_MGMT_WPA_PSK = 2, - IEEE80211_KEY_MGMT_WPA_EAP = 3, -}; - - /* Data structures used for get_hw_features ioctl */ struct hostapd_ioctl_hw_modes_hdr { int mode; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c557d578aa30..c771b7a76959 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -253,7 +253,7 @@ struct ieee80211_if_sta { unsigned long request; struct sk_buff_head skb_queue; - int key_mgmt; + int key_management_enabled; unsigned long last_probe; #define IEEE80211_AUTH_ALG_OPEN BIT(0) diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 785f437b306a..643c8855801c 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1342,22 +1342,12 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, ret = -EINVAL; else { /* - * TODO: sdata->u.sta.key_mgmt does not match with WE18 - * value completely; could consider modifying this to - * be closer to WE18. For now, this value is not really - * used for anything else than Privacy matching, so the - * current code here should be more or less OK. + * Key management was set by wpa_supplicant, + * we only need this to associate to a network + * that has privacy enabled regardless of not + * having a key. */ - if (data->value & IW_AUTH_KEY_MGMT_802_1X) { - sdata->u.sta.key_mgmt = - IEEE80211_KEY_MGMT_WPA_EAP; - } else if (data->value & IW_AUTH_KEY_MGMT_PSK) { - sdata->u.sta.key_mgmt = - IEEE80211_KEY_MGMT_WPA_PSK; - } else { - sdata->u.sta.key_mgmt = - IEEE80211_KEY_MGMT_NONE; - } + sdata->u.sta.key_management_enabled = !!data->value; } break; case IW_AUTH_80211_AUTH_ALG: diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index f43c39f11223..1b3304454356 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -716,8 +716,7 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, struct ieee80211_sta_bss *bss; int res = 0; - if (!ifsta || ifsta->mixed_cell || - ifsta->key_mgmt != IEEE80211_KEY_MGMT_NONE) + if (!ifsta || ifsta->mixed_cell || ifsta->key_management_enabled) return 0; bss = ieee80211_rx_bss_get(dev, ifsta->bssid); From eb063c1702a84d58eb4c05a032bbff6f1c29049d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:53 -0400 Subject: [PATCH 1142/2804] [MAC80211]: refactor event sending Create a new file event.c that will contain code to send mac/mlme events to userspace. For now put the Michael MIC failure condition into it and remove sending of that condition via the management interface, hostapd interestingly doesn't do anything when it gets such a packet besides printing a message, it reacts only on the private iwevent. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/Makefile | 1 + net/mac80211/event.c | 42 ++++++++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/rx.c | 41 ++++++++----------------------------- net/mac80211/wpa.c | 34 ++++-------------------------- 5 files changed, 57 insertions(+), 63 deletions(-) create mode 100644 net/mac80211/event.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 122b23eb15d1..793733835628 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -22,4 +22,5 @@ mac80211-objs := \ tx.o \ key.o \ util.o \ + event.o \ $(mac80211-objs-y) diff --git a/net/mac80211/event.c b/net/mac80211/event.c new file mode 100644 index 000000000000..68a526cb7623 --- /dev/null +++ b/net/mac80211/event.c @@ -0,0 +1,42 @@ +/* + * Copyright 2007 Johannes Berg + * + * 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. + * + * mac80211 - events + */ + +#include +#include +#include "ieee80211_i.h" + +/* + * indicate a failed Michael MIC to userspace; the passed packet + * (in the variable hdr) must be long enough to extract the TKIP + * fields like TSC + */ +void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, + struct ieee80211_hdr *hdr) +{ + 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=" MAC_FMT ")", + keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", + MAC_ARG(hdr->addr2)); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(buf); + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); + kfree(buf); + } + + /* + * TODO: re-add support for sending MIC failure indication + * with all info via nl80211 + */ +} diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c771b7a76959..9c5fd861eb72 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -823,5 +823,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); int ieee80211_is_eapol(const struct sk_buff *skb); 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 net_device *dev, int keyidx, + struct ieee80211_hdr *hdr); #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 08ca066246b9..5a66269d9435 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -1206,20 +1205,17 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, } if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->sdata->type == IEEE80211_IF_TYPE_AP) { - keyidx = ieee80211_wep_get_keyidx(rx->skb); + rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { /* AP with Pairwise keys support should never receive Michael * MIC errors for non-zero keyidx because these are reserved * for group keys and only the AP is sending real multicast * frames in BSS. */ - if (keyidx) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: ignored Michael MIC " - "error for a frame with non-zero keyidx" - " (%d) (src " MAC_FMT ")\n", dev->name, - keyidx, MAC_ARG(hdr->addr2)); - goto ignore; - } + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored Michael MIC error for " + "a frame with non-zero keyidx (%d)" + " (src " MAC_FMT ")\n", dev->name, keyidx, + MAC_ARG(hdr->addr2)); + goto ignore; } if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && @@ -1233,32 +1229,11 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, goto ignore; } - do { - union iwreq_data wrqu; - char *buf = kmalloc(128, GFP_ATOMIC); - if (!buf) - break; - - /* TODO: needed parameters: count, key type, TSC */ - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=" MAC_FMT ")", - keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); - wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf); - kfree(buf); - } while (0); - /* TODO: consider verifying the MIC error report with software * implementation if we get too many spurious reports from the * hardware. */ - if (!rx->local->apdev) - goto ignore; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_michael_mic_failure); - return; + mac80211_ev_michael_mic_failure(rx->dev, keyidx, hdr); ignore: dev_kfree_skb(rx->skb); rx->skb = NULL; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index f5723ea15aae..742b5585d1b7 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -11,10 +11,8 @@ #include #include #include -#include - #include -#include "ieee80211_common.h" + #include "ieee80211_i.h" #include "michael.h" #include "tkip.h" @@ -181,33 +179,9 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " MAC_FMT "\n", rx->dev->name, MAC_ARG(sa)); - do { - struct ieee80211_hdr *hdr; - union iwreq_data wrqu; - char *buf = kmalloc(128, GFP_ATOMIC); - if (!buf) - break; - - /* TODO: needed parameters: count, key type, TSC */ - hdr = (struct ieee80211_hdr *) skb->data; - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=" MAC_FMT ")", - rx->key->keyidx, - hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); - wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf); - kfree(buf); - } while (0); - - if (!rx->local->apdev) - return TXRX_DROP; - - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_michael_mic_failure); - - return TXRX_QUEUED; + mac80211_ev_michael_mic_failure(rx->dev, rx->key->keyidx, + (void *) skb->data); + return TXRX_DROP; } remove_mic: From cf966838cd5596ca61d3e9949050442a943f6238 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:54 -0400 Subject: [PATCH 1143/2804] [MAC80211]: use switch statement in tx code The transmit code needs to set the addresses depending on the interface type, a likely() for AP/VLAN is quite wrong since most people will be using STA; convert to a switch statement to make it look nicer. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/tx.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c9b909d9498b..53efcf6f769c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1363,15 +1363,17 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, /* TODO: handling for 802.1x authorized/unauthorized port */ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; - if (likely(sdata->type == IEEE80211_IF_TYPE_AP || - sdata->type == IEEE80211_IF_TYPE_VLAN)) { + switch (sdata->type) { + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_VLAN: fc |= IEEE80211_FCTL_FROMDS; /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 24; - } else if (sdata->type == IEEE80211_IF_TYPE_WDS) { + break; + case IEEE80211_IF_TYPE_WDS: fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; /* RA TA DA SA */ memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); @@ -1379,20 +1381,23 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; - } else if (sdata->type == IEEE80211_IF_TYPE_STA) { + break; + case IEEE80211_IF_TYPE_STA: fc |= IEEE80211_FCTL_TODS; /* BSSID SA DA */ memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); hdrlen = 24; - } else if (sdata->type == IEEE80211_IF_TYPE_IBSS) { + break; + case IEEE80211_IF_TYPE_IBSS: /* DA SA BSSID */ memcpy(hdr.addr1, skb->data, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN); hdrlen = 24; - } else { + break; + default: ret = 0; goto fail; } From e8bf96495cd67090b4900ddaf8e8672a17ec39fa Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 28 Aug 2007 17:01:54 -0400 Subject: [PATCH 1144/2804] [MAC80211]: Remove bitfields from struct ieee80211_tx_packet_data remove bitfields from struct ieee80211_tx_packet_data [Johannes: completely clear flags in ieee80211_remove_tx_extra] Signed-off-by: Jiri Slaby Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211.c | 13 +++++++++---- net/mac80211/ieee80211_i.h | 12 +++++++----- net/mac80211/ieee80211_sta.c | 6 ++++-- net/mac80211/rx.c | 4 ++-- net/mac80211/tx.c | 23 ++++++++++++----------- net/mac80211/wme.c | 4 ++-- 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 8f472379b128..289b33ce45cf 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -876,10 +876,15 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; pkt_data->ifindex = control->ifindex; - pkt_data->mgmt_iface = (control->type == IEEE80211_IF_TYPE_MGMT); - pkt_data->req_tx_status = !!(control->flags & IEEE80211_TXCTL_REQ_TX_STATUS); - pkt_data->do_not_encrypt = !!(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT); - pkt_data->requeue = !!(control->flags & IEEE80211_TXCTL_REQUEUE); + pkt_data->flags = 0; + if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) + pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; + if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT) + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + if (control->flags & IEEE80211_TXCTL_REQUEUE) + pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + if (control->type == IEEE80211_IF_TYPE_MGMT) + pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; pkt_data->queue = control->queue; hdrlen = ieee80211_get_hdrlen_from_skb(skb); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9c5fd861eb72..a2b018bae180 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -155,15 +155,17 @@ struct ieee80211_txrx_data { } u; }; +/* flags used in struct ieee80211_tx_packet_data.flags */ +#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) +#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) +#define IEEE80211_TXPD_REQUEUE BIT(2) +#define IEEE80211_TXPD_MGMT_IFACE BIT(3) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { int ifindex; unsigned long jiffies; - unsigned int req_tx_status:1; - unsigned int do_not_encrypt:1; - unsigned int requeue:1; - unsigned int mgmt_iface:1; - unsigned int queue:4; + unsigned int flags; + u8 queue; }; struct ieee80211_tx_stored_packet { diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 1b3304454356..3757298c5a60 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -465,8 +465,10 @@ static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = sdata->dev->ifindex; - pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); - pkt_data->do_not_encrypt = !encrypt; + if (sdata->type == IEEE80211_IF_TYPE_MGMT) + pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; + if (!encrypt) + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; dev_queue_xmit(skb); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5a66269d9435..441383ced931 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -434,7 +434,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; sent++; - pkt_data->requeue = 1; + pkt_data->flags |= IEEE80211_TXPD_REQUEUE; dev_queue_xmit(skb); } while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { @@ -446,7 +446,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) "since STA not sleeping anymore\n", dev->name, MAC_ARG(sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - pkt_data->requeue = 1; + pkt_data->flags |= IEEE80211_TXPD_REQUEUE; dev_queue_xmit(skb); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 53efcf6f769c..eb4d9eab0f3f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1245,11 +1245,11 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, control.ifindex = odev->ifindex; control.type = osdata->type; - if (pkt_data->req_tx_status) + if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; - if (pkt_data->do_not_encrypt) + if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - if (pkt_data->requeue) + if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) control.flags |= IEEE80211_TXCTL_REQUEUE; control.queue = pkt_data->queue; @@ -1291,8 +1291,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, /* needed because we set skb device to master */ pkt_data->ifindex = dev->ifindex; - pkt_data->mgmt_iface = 0; - pkt_data->do_not_encrypt = 1; + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; /* * fix up the pointers accounting for the radiotap @@ -1343,7 +1342,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct ieee80211_hdr hdr; const u8 *encaps_data; int encaps_len, skip_header_bytes; - int nh_pos, h_pos, no_encrypt = 0; + int nh_pos, h_pos; struct sta_info *sta; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1487,8 +1486,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = dev->ifindex; - pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); - pkt_data->do_not_encrypt = no_encrypt; + if (sdata->type == IEEE80211_IF_TYPE_MGMT) + pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; skb->dev = local->mdev; sdata->stats.tx_packets++; @@ -1546,7 +1545,8 @@ int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = sdata->dev->ifindex; - pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); + if (sdata->type == IEEE80211_IF_TYPE_MGMT) + pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ skb->dev = sdata->local->mdev; @@ -1556,12 +1556,13 @@ int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) * to request TX callback for hostapd. BIT(1) is checked. */ if ((fc & BIT(1)) == BIT(1)) { - pkt_data->req_tx_status = 1; + pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; fc &= ~BIT(1); hdr->frame_control = cpu_to_le16(fc); } - pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED); + if (!(fc & IEEE80211_FCTL_PROTECTED)) + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; sdata->stats.tx_packets++; sdata->stats.tx_bytes += skb->len; diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 0f11ccd30a36..d303229249e7 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -108,7 +108,7 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) return IEEE80211_TX_QUEUE_DATA0; } - if (unlikely(pkt_data->mgmt_iface)) { + if (unlikely(pkt_data->flags & IEEE80211_TXPD_MGMT_IFACE)) { /* Data frames from hostapd (mainly, EAPOL) use AC_VO * and they will include QoS control fields if * the target STA is using WME. */ @@ -153,7 +153,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) struct Qdisc *qdisc; int err, queue; - if (pkt_data->requeue) { + if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { skb_queue_tail(&q->requeued[pkt_data->queue], skb); qd->q.qlen++; return 0; From badffb725c86cc2d46f7cb3f520f58f1c863b56c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 28 Aug 2007 17:01:54 -0400 Subject: [PATCH 1145/2804] [MAC80211]: Remove bitfields from struct ieee80211_txrx_data mac80211, remove bitfields from struct ieee80211_txrx_data Signed-off-by: Jiri Slaby Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_i.h | 20 +++++++------ net/mac80211/rx.c | 52 +++++++++++++++++--------------- net/mac80211/tx.c | 61 ++++++++++++++++++++++---------------- net/mac80211/wpa.c | 6 ++-- 4 files changed, 78 insertions(+), 61 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a2b018bae180..9888611660b7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -113,6 +113,15 @@ typedef enum { TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED } ieee80211_txrx_result; +/* flags used in struct ieee80211_txrx_data.flags */ +/* whether the MSDU was fragmented */ +#define IEEE80211_TXRXD_FRAGMENTED BIT(0) +#define IEEE80211_TXRXD_TXUNICAST BIT(1) +#define IEEE80211_TXRXD_TXPS_BUFFERED BIT(2) +#define IEEE80211_TXRXD_TXPROBE_LAST_FRAG BIT(3) +#define IEEE80211_TXRXD_RXIN_SCAN BIT(4) +/* frame is destined to interface currently processed (incl. multicast frames) */ +#define IEEE80211_TXRXD_RXRA_MATCH BIT(5) struct ieee80211_txrx_data { struct sk_buff *skb; struct net_device *dev; @@ -121,13 +130,10 @@ struct ieee80211_txrx_data { struct sta_info *sta; u16 fc, ethertype; struct ieee80211_key *key; - unsigned int fragmented:1; /* whether the MSDU was fragmented */ + unsigned int flags; union { struct { struct ieee80211_tx_control *control; - unsigned int unicast:1; - unsigned int ps_buffered:1; - unsigned int probe_last_frag:1; struct ieee80211_hw_mode *mode; struct ieee80211_rate *rate; /* use this rate (if set) for last fragment; rate can @@ -147,10 +153,6 @@ struct ieee80211_txrx_data { int sent_ps_buffered; int queue; int load; - unsigned int in_scan:1; - /* frame is destined to interface currently processed - * (including multicast frames) */ - unsigned int ra_match:1; } rx; } u; }; @@ -176,7 +178,7 @@ struct ieee80211_tx_stored_packet { int last_frag_rateidx; int last_frag_hwrate; struct ieee80211_rate *last_frag_rate; - unsigned int last_frag_rate_ctrl_probe:1; + unsigned int last_frag_rate_ctrl_probe; }; typedef ieee80211_txrx_result (*ieee80211_tx_handler) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 441383ced931..af94fb597415 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -221,7 +221,7 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) return TXRX_QUEUED; } - if (unlikely(rx->u.rx.in_scan)) { + if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) { /* scanning finished during invoking of handlers */ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); return TXRX_DROP; @@ -241,7 +241,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && rx->sta->last_seq_ctrl[rx->u.rx.queue] == hdr->seq_ctrl)) { - if (rx->u.rx.ra_match) { + if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) { rx->local->dot11FrameDuplicateCount++; rx->sta->num_duplicates++; } @@ -259,7 +259,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - if (!rx->u.rx.ra_match) + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) rx->skb->pkt_type = PACKET_OTHERHOST; else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0) rx->skb->pkt_type = PACKET_HOST; @@ -287,7 +287,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && !(rx->fc & IEEE80211_FCTL_TODS) && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) - || !rx->u.rx.ra_match) { + || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { /* Drop IBSS frames and frames for other hosts * silently. */ return TXRX_DROP; @@ -338,7 +338,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) * No point in finding a key if the frame is neither * addressed to us nor a multicast frame. */ - if (!rx->u.rx.ra_match) + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) return TXRX_CONTINUE; if (!is_multicast_ether_addr(hdr->addr1) && rx->sta && rx->sta->key) { @@ -480,7 +480,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) sta->last_rx = jiffies; } - if (!rx->u.rx.ra_match) + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) return TXRX_CONTINUE; sta->rx_fragments++; @@ -522,7 +522,8 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) { if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - !rx->key || rx->key->alg != ALG_WEP || !rx->u.rx.ra_match) + !rx->key || rx->key->alg != ALG_WEP || + !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) return TXRX_CONTINUE; /* Check for weak IVs, if hwaccel did not remove IV from the frame */ @@ -755,7 +756,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) } /* Complete frame has been reassembled - process it now */ - rx->fragmented = 1; + rx->flags |= IEEE80211_TXRXD_FRAGMENTED; out: if (rx->sta) @@ -776,7 +777,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) if (likely(!rx->sta || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || - !rx->u.rx.ra_match)) + !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))) return TXRX_CONTINUE; skb = skb_dequeue(&rx->sta->tx_filtered); @@ -860,7 +861,8 @@ static ieee80211_txrx_result ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) { if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && - rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) { + rx->sdata->type != IEEE80211_IF_TYPE_STA && + (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { /* Pass both encrypted and unencrypted EAPOL frames to user * space for processing. */ if (!rx->local->apdev) @@ -1053,7 +1055,8 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) sdata->stats.rx_bytes += skb->len; if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP - || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) { + || sdata->type == IEEE80211_IF_TYPE_VLAN) && + (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { if (is_multicast_ether_addr(skb->data)) { /* send multicast frames both to higher layers in * local net stack and back to the wireless media */ @@ -1104,7 +1107,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) { struct ieee80211_sub_if_data *sdata; - if (!rx->u.rx.ra_match) + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) return TXRX_DROP; sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); @@ -1279,30 +1282,30 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, if (!bssid) return 0; if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { - if (!rx->u.rx.in_scan) + if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) return 0; - rx->u.rx.ra_match = 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!sdata->promisc) return 0; - rx->u.rx.ra_match = 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } break; case IEEE80211_IF_TYPE_IBSS: if (!bssid) return 0; if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { - if (!rx->u.rx.in_scan) + if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) return 0; - rx->u.rx.ra_match = 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!sdata->promisc) return 0; - rx->u.rx.ra_match = 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } else if (!rx->sta) rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, bssid, hdr->addr2); @@ -1314,11 +1317,12 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, return 0; } else if (!ieee80211_bssid_match(bssid, sdata->dev->dev_addr)) { - if (!rx->u.rx.in_scan) + if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) return 0; - rx->u.rx.ra_match = 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } - if (sdata->dev == sdata->local->mdev && !rx->u.rx.in_scan) + if (sdata->dev == sdata->local->mdev && + !(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) /* do not receive anything via * master device when not scanning */ return 0; @@ -1384,7 +1388,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, } if (unlikely(local->sta_scanning)) - rx.u.rx.in_scan = 1; + rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, sta) != TXRX_CONTINUE) @@ -1394,7 +1398,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, skb_push(skb, radiotap_len); if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) && !local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) { - rx.u.rx.ra_match = 1; + rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, rx.sta); sta_info_put(sta); @@ -1405,7 +1409,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, read_lock(&local->sub_if_lock); list_for_each_entry(sdata, &local->sub_if_list, list) { - rx.u.rx.ra_match = 1; + rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; if (!netif_running(sdata->dev)) continue; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index eb4d9eab0f3f..01e7a734f867 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -223,12 +223,12 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) return TXRX_DROP; - if (tx->u.tx.ps_buffered) + if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) return TXRX_CONTINUE; sta_flags = tx->sta ? tx->sta->flags : 0; - if (likely(tx->u.tx.unicast)) { + if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) { if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && tx->sdata->type != IEEE80211_IF_TYPE_IBSS && (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { @@ -410,10 +410,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) static ieee80211_txrx_result ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) { - if (unlikely(tx->u.tx.ps_buffered)) + if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)) return TXRX_CONTINUE; - if (tx->u.tx.unicast) + if (tx->flags & IEEE80211_TXRXD_TXUNICAST) return ieee80211_tx_h_unicast_ps_buf(tx); else return ieee80211_tx_h_multicast_ps_buf(tx); @@ -467,7 +467,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) u8 *pos; int frag_threshold = tx->local->fragmentation_threshold; - if (!tx->fragmented) + if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) return TXRX_CONTINUE; first = tx->skb; @@ -604,7 +604,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) &extra); if (unlikely(extra.probe != NULL)) { tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; - tx->u.tx.probe_last_frag = 1; + tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; tx->u.tx.rate = extra.probe; } else { @@ -613,11 +613,13 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) if (!tx->u.tx.rate) return TXRX_DROP; if (tx->u.tx.mode->mode == MODE_IEEE80211G && - tx->sdata->use_protection && tx->fragmented && - extra.nonerp) { + tx->sdata->use_protection && + (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) { tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.probe_last_frag = extra.probe ? 1 : 0; - + if (extra.probe) + tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG; + else + tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; tx->u.tx.rate = extra.nonerp; tx->u.tx.control->rate = extra.nonerp; tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; @@ -654,7 +656,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) control->retry_limit = 1; } - if (tx->fragmented) { + if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { /* Do not use multiple retry rates when sending fragmented * frames. * TODO: The last fragment could still use multiple retry @@ -667,7 +669,8 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * for the frame. */ if (mode->mode == MODE_IEEE80211G && (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && - tx->u.tx.unicast && tx->sdata->use_protection && + (tx->flags & IEEE80211_TXRXD_TXUNICAST) && + tx->sdata->use_protection && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; @@ -685,8 +688,8 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * for remaining fragments will be updated when they are being sent * to low-level driver in ieee80211_tx(). */ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), - tx->fragmented ? tx->u.tx.extra_frag[0]->len : - 0); + (tx->flags & IEEE80211_TXRXD_FRAGMENTED) ? + tx->u.tx.extra_frag[0]->len : 0); hdr->duration_id = cpu_to_le16(dur); if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -976,15 +979,20 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } tx->u.tx.control = control; - tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1); - if (is_multicast_ether_addr(hdr->addr1)) + if (is_multicast_ether_addr(hdr->addr1)) { + tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; control->flags |= IEEE80211_TXCTL_NO_ACK; - else + } else { + tx->flags |= IEEE80211_TXRXD_TXUNICAST; control->flags &= ~IEEE80211_TXCTL_NO_ACK; - tx->fragmented = local->fragmentation_threshold < - IEEE80211_MAX_FRAG_THRESHOLD && tx->u.tx.unicast && - skb->len + FCS_LEN > local->fragmentation_threshold && - (!local->ops->set_frag_threshold); + } + if (local->fragmentation_threshold < IEEE80211_MAX_FRAG_THRESHOLD && + (tx->flags & IEEE80211_TXRXD_TXUNICAST) && + skb->len + FCS_LEN > local->fragmentation_threshold && + !local->ops->set_frag_threshold) + tx->flags |= IEEE80211_TXRXD_FRAGMENTED; + else + tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; if (!tx->sta) control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; else if (tx->sta->clear_dst_mask) { @@ -1055,7 +1063,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (i == tx->u.tx.num_extra_frag) { control->tx_rate = tx->u.tx.last_frag_hwrate; control->rate = tx->u.tx.last_frag_rate; - if (tx->u.tx.probe_last_frag) + if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; else @@ -1186,7 +1194,8 @@ retry: store->num_extra_frag = tx.u.tx.num_extra_frag; store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; store->last_frag_rate = tx.u.tx.last_frag_rate; - store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag; + store->last_frag_rate_ctrl_probe = + !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); } return 0; @@ -1613,7 +1622,9 @@ void ieee80211_tx_pending(unsigned long data) tx.u.tx.num_extra_frag = store->num_extra_frag; tx.u.tx.last_frag_hwrate = store->last_frag_hwrate; tx.u.tx.last_frag_rate = store->last_frag_rate; - tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe; + tx.flags = 0; + if (store->last_frag_rate_ctrl_probe) + tx.flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; ret = __ieee80211_tx(local, store->skb, &tx); if (ret) { if (ret == IEEE80211_TX_FRAG_AGAIN) @@ -1859,7 +1870,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, dev_kfree_skb_any(skb); } sta = tx.sta; - tx.u.tx.ps_buffered = 1; + tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; for (handler = local->tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 742b5585d1b7..1142b42b5fe9 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -90,7 +90,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) return TXRX_DROP; if (!tx->key->force_sw_encrypt && - !tx->fragmented && + !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) && !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC @@ -154,7 +154,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) /* Need to verify Michael MIC sometimes in software even when * hwaccel is used. Atheros ar5212: fragmented frames and QoS * frames. */ - if (!rx->fragmented && !wpa_test) + if (!(rx->flags & IEEE80211_TXRXD_FRAGMENTED) && !wpa_test) goto remove_mic; } @@ -173,7 +173,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { - if (!rx->u.rx.ra_match) + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) return TXRX_DROP; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " From d6f2da5b33911a31eb61e1790ef8e555e9605837 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 28 Aug 2007 17:01:54 -0400 Subject: [PATCH 1146/2804] [MAC80211]: Remove bitfields from struct ieee80211_if_sta mac80211, remove bitfields from struct ieee80211_if_sta Signed-off-by: Jiri Slaby Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/debugfs_netdev.c | 14 ++--- net/mac80211/ieee80211.c | 2 +- net/mac80211/ieee80211_i.h | 26 +++++---- net/mac80211/ieee80211_iface.c | 8 +-- net/mac80211/ieee80211_ioctl.c | 57 ++++++++++++------ net/mac80211/ieee80211_sta.c | 102 ++++++++++++++++++--------------- 6 files changed, 121 insertions(+), 88 deletions(-) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 095be91829ca..099dac95b09b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -112,13 +112,13 @@ 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.sta.ssid_set ? "SSID\n" : "", - sdata->u.sta.bssid_set ? "BSSID\n" : "", - sdata->u.sta.prev_bssid_set ? "prev BSSID\n" : "", - sdata->u.sta.authenticated ? "AUTH\n" : "", - sdata->u.sta.associated ? "ASSOC\n" : "", - sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "", - sdata->use_protection ? "CTS prot\n" : ""); + sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", + sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", + sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", + sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", + sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", + sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", + sdata->use_protection ? "CTS prot\n" : ""); } __IEEE80211_IF_FILE(flags); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 289b33ce45cf..be678c61afa5 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -354,7 +354,7 @@ static void ieee80211_if_open(struct net_device *dev) switch (sdata->type) { case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: - sdata->u.sta.prev_bssid_set = 0; + sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; break; } } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9888611660b7..28c5d514e6d5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -217,6 +217,19 @@ struct ieee80211_if_vlan { u8 id; }; +/* flags used in struct ieee80211_if_sta.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_MIXED_CELL BIT(7) +#define IEEE80211_STA_WMM_ENABLED BIT(8) +#define IEEE80211_STA_AUTO_SSID_SEL BIT(10) +#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) +#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) struct ieee80211_if_sta { enum { IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, @@ -239,18 +252,7 @@ struct ieee80211_if_sta { int auth_tries, assoc_tries; - unsigned int ssid_set:1; - unsigned int bssid_set:1; - unsigned int prev_bssid_set:1; - unsigned int authenticated:1; - unsigned int associated:1; - unsigned int probereq_poll:1; - unsigned int create_ibss:1; - unsigned int mixed_cell:1; - unsigned int wmm_enabled:1; - unsigned int auto_ssid_sel:1; - unsigned int auto_bssid_sel:1; - unsigned int auto_channel_sel:1; + unsigned int flags; #define IEEE80211_STA_REQ_SCAN 0 #define IEEE80211_STA_REQ_AUTH 1 #define IEEE80211_STA_REQ_RUN 2 diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 6db67767801d..61009176d51b 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -187,10 +187,10 @@ void ieee80211_if_set_type(struct net_device *dev, int type) ifsta->capab = WLAN_CAPABILITY_ESS; ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | IEEE80211_AUTH_ALG_SHARED_KEY; - ifsta->create_ibss = 1; - ifsta->wmm_enabled = 1; - ifsta->auto_channel_sel = 1; - ifsta->auto_bssid_sel = 1; + ifsta->flags |= IEEE80211_STA_CREATE_IBSS | + IEEE80211_STA_WMM_ENABLED | + IEEE80211_STA_AUTO_BSSID_SEL | + IEEE80211_STA_AUTO_CHANNEL_SEL; msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); sdata->bss = &msdata->u.ap; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 643c8855801c..ea2e0f958ac3 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -270,7 +270,7 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length); if (ret) return ret; - sdata->u.sta.auto_bssid_sel = 0; + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; ieee80211_sta_req_auth(dev, &sdata->u.sta); return 0; } @@ -502,13 +502,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_STA) - sdata->u.sta.auto_channel_sel = 0; + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) { if (freq->m < 0) { if (sdata->type == IEEE80211_IF_TYPE_STA) - sdata->u.sta.auto_channel_sel = 1; + sdata->u.sta.flags |= + IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else return ieee80211_set_channel(local, freq->m, -1); @@ -563,7 +564,10 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, sdata->u.sta.ssid_len = len; return 0; } - sdata->u.sta.auto_ssid_sel = !data->flags; + if (data->flags) + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; + else + sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL; ret = ieee80211_sta_set_ssid(dev, ssid, len); if (ret) return ret; @@ -630,13 +634,13 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, ETH_ALEN); return 0; } - if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) { - sdata->u.sta.auto_bssid_sel = 1; - sdata->u.sta.auto_channel_sel = 1; - } else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.sta.auto_bssid_sel = 1; + if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) + sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL | + IEEE80211_STA_AUTO_CHANNEL_SEL; + else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) + sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL; else - sdata->u.sta.auto_bssid_sel = 0; + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data); if (ret) return ret; @@ -1104,8 +1108,12 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, if (sdata->type != IEEE80211_IF_TYPE_STA && sdata->type != IEEE80211_IF_TYPE_IBSS) ret = -EINVAL; - else - sdata->u.sta.mixed_cell = !!value; + else { + if (value) + sdata->u.sta.flags |= IEEE80211_STA_MIXED_CELL; + else + sdata->u.sta.flags &= ~IEEE80211_STA_MIXED_CELL; + } break; case PRISM2_PARAM_HW_MODES: @@ -1115,15 +1123,23 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, case PRISM2_PARAM_CREATE_IBSS: if (sdata->type != IEEE80211_IF_TYPE_IBSS) ret = -EINVAL; - else - sdata->u.sta.create_ibss = !!value; + else { + if (value) + sdata->u.sta.flags |= IEEE80211_STA_CREATE_IBSS; + else + sdata->u.sta.flags &= ~IEEE80211_STA_CREATE_IBSS; + } break; case PRISM2_PARAM_WMM_ENABLED: if (sdata->type != IEEE80211_IF_TYPE_STA && sdata->type != IEEE80211_IF_TYPE_IBSS) ret = -EINVAL; - else - sdata->u.sta.wmm_enabled = !!value; + else { + if (value) + sdata->u.sta.flags |= IEEE80211_STA_WMM_ENABLED; + else + sdata->u.sta.flags &= ~IEEE80211_STA_WMM_ENABLED; + } break; default: ret = -EOPNOTSUPP; @@ -1186,7 +1202,8 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, if (sdata->type != IEEE80211_IF_TYPE_IBSS) ret = -EINVAL; else - *param = !!sdata->u.sta.create_ibss; + *param = !!(sdata->u.sta.flags & + IEEE80211_STA_CREATE_IBSS); break; case PRISM2_PARAM_MIXED_CELL: @@ -1194,14 +1211,16 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, sdata->type != IEEE80211_IF_TYPE_IBSS) ret = -EINVAL; else - *param = !!sdata->u.sta.mixed_cell; + *param = !!(sdata->u.sta.flags & + IEEE80211_STA_MIXED_CELL); break; case PRISM2_PARAM_WMM_ENABLED: if (sdata->type != IEEE80211_IF_TYPE_STA && sdata->type != IEEE80211_IF_TYPE_IBSS) ret = -EINVAL; else - *param = !!sdata->u.sta.wmm_enabled; + *param = !!(sdata->u.sta.flags & + IEEE80211_STA_WMM_ENABLED); break; default: ret = -EOPNOTSUPP; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 3757298c5a60..6a57333dc75c 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -403,18 +403,20 @@ static void ieee80211_sta_send_associnfo(struct net_device *dev, static void ieee80211_set_associated(struct net_device *dev, - struct ieee80211_if_sta *ifsta, int assoc) + struct ieee80211_if_sta *ifsta, + unsigned int assoc) { union iwreq_data wrqu; - if (ifsta->associated == assoc) + if (!!(ifsta->flags & IEEE80211_STA_ASSOCIATED) == assoc) return; - ifsta->associated = assoc; - if (assoc) { struct ieee80211_sub_if_data *sdata; struct ieee80211_sta_bss *bss; + + ifsta->flags |= IEEE80211_STA_ASSOCIATED; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type != IEEE80211_IF_TYPE_STA) return; @@ -427,11 +429,13 @@ static void ieee80211_set_associated(struct net_device *dev, } netif_carrier_on(dev); - ifsta->prev_bssid_set = 1; + ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); ieee80211_sta_send_associnfo(dev, ifsta); } else { + ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; + netif_carrier_off(dev); ieee80211_reset_erp_info(dev); memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); @@ -579,7 +583,7 @@ static void ieee80211_send_assoc(struct net_device *dev, memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - if (ifsta->prev_bssid_set) { + if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { skb_put(skb, 10); mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_REASSOC_REQ); @@ -631,7 +635,7 @@ static void ieee80211_send_assoc(struct net_device *dev, memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); } - if (wmm && ifsta->wmm_enabled) { + if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { pos = skb_put(skb, 9); *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = 7; /* len */ @@ -718,7 +722,8 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, struct ieee80211_sta_bss *bss; int res = 0; - if (!ifsta || ifsta->mixed_cell || ifsta->key_management_enabled) + if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) || + ifsta->key_management_enabled) return 0; bss = ieee80211_rx_bss_get(dev, ifsta->bssid); @@ -786,22 +791,20 @@ static void ieee80211_associated(struct net_device *dev, disassoc = 0; if (time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { - if (ifsta->probereq_poll) { + if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { printk(KERN_DEBUG "%s: No ProbeResp from " "current AP " MAC_FMT " - assume out of " "range\n", dev->name, MAC_ARG(ifsta->bssid)); disassoc = 1; sta_info_free(sta); - ifsta->probereq_poll = 0; - } else { + } else ieee80211_send_probe_req(dev, ifsta->bssid, local->scan_ssid, local->scan_ssid_len); - ifsta->probereq_poll = 1; - } + ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; } else { - ifsta->probereq_poll = 0; + ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; if (time_after(jiffies, ifsta->last_probe + IEEE80211_PROBE_INTERVAL)) { ifsta->last_probe = jiffies; @@ -905,7 +908,7 @@ static void ieee80211_auth_completed(struct net_device *dev, struct ieee80211_if_sta *ifsta) { printk(KERN_DEBUG "%s: authenticated\n", dev->name); - ifsta->authenticated = 1; + ifsta->flags |= IEEE80211_STA_AUTHENTICATED; ieee80211_associate(dev, ifsta); } @@ -1092,7 +1095,7 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, " (reason=%d)\n", dev->name, MAC_ARG(mgmt->sa), reason_code); - if (ifsta->authenticated) { + if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); } @@ -1105,7 +1108,7 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, } ieee80211_set_disassoc(dev, ifsta, 1); - ifsta->authenticated = 0; + ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; } @@ -1137,7 +1140,7 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, " (reason=%d)\n", dev->name, MAC_ARG(mgmt->sa), reason_code); - if (ifsta->associated) + if (ifsta->flags & IEEE80211_STA_ASSOCIATED) printk(KERN_DEBUG "%s: disassociated\n", dev->name); if (ifsta->state == IEEE80211_ASSOCIATED) { @@ -1209,7 +1212,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, /* 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. */ - ifsta->prev_bssid_set = 0; + ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; return; } @@ -1296,7 +1299,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, rate_control_rate_init(sta, local); - if (elems.wmm_param && ifsta->wmm_enabled) { + if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { sta->flags |= WLAN_STA_WME; ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); @@ -1693,7 +1696,7 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, return; ifsta = &sdata->u.sta; - if (!ifsta->associated || + if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) return; @@ -1709,7 +1712,7 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, if (elems.erp_info && elems.erp_info_len >= 1) ieee80211_handle_erp_ie(dev, elems.erp_info[0]); - if (elems.wmm_param && ifsta->wmm_enabled) { + if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); } @@ -2076,7 +2079,8 @@ static void ieee80211_sta_reset_auth(struct net_device *dev, printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name, ifsta->auth_alg); ifsta->auth_transaction = -1; - ifsta->associated = ifsta->auth_tries = ifsta->assoc_tries = 0; + ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; + ifsta->auth_tries = ifsta->assoc_tries = 0; netif_carrier_off(dev); } @@ -2090,8 +2094,10 @@ void ieee80211_sta_req_auth(struct net_device *dev, if (sdata->type != IEEE80211_IF_TYPE_STA) return; - if ((ifsta->bssid_set || ifsta->auto_bssid_sel) && - (ifsta->ssid_set || ifsta->auto_ssid_sel)) { + if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | + IEEE80211_STA_AUTO_BSSID_SEL)) && + (ifsta->flags & (IEEE80211_STA_SSID_SET | + IEEE80211_STA_AUTO_SSID_SEL))) { set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); queue_work(local->hw.workqueue, &ifsta->work); } @@ -2105,7 +2111,7 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, if (!memcmp(ifsta->ssid, ssid, ssid_len)) return 1; - if (ifsta->auto_bssid_sel) + if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) return 0; hidden_ssid = 1; @@ -2134,8 +2140,8 @@ static int ieee80211_sta_config_auth(struct net_device *dev, struct ieee80211_sta_bss *bss, *selected = NULL; int top_rssi = 0, freq; - if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel && - !ifsta->auto_ssid_sel) { + if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | + IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) { ifsta->state = IEEE80211_AUTHENTICATE; ieee80211_sta_reset_auth(dev, ifsta); return 0; @@ -2151,14 +2157,15 @@ static int ieee80211_sta_config_auth(struct net_device *dev, !!sdata->default_key) continue; - if (!ifsta->auto_channel_sel && bss->freq != freq) + if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && + bss->freq != freq) continue; - if (!ifsta->auto_bssid_sel && + if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) continue; - if (!ifsta->auto_ssid_sel && + if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) continue; @@ -2173,7 +2180,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, if (selected) { ieee80211_set_channel(local, -1, selected->freq); - if (!ifsta->ssid_set) + if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); ieee80211_sta_set_bssid(dev, selected->bssid); @@ -2183,7 +2190,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, return 0; } else { if (ifsta->state != IEEE80211_AUTHENTICATE) { - if (ifsta->auto_ssid_sel) + if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) ieee80211_sta_start_scan(dev, NULL, 0); else ieee80211_sta_start_scan(dev, ifsta->ssid, @@ -2480,10 +2487,10 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, if (time_after(jiffies, ifsta->ibss_join_req + IEEE80211_IBSS_JOIN_TIMEOUT)) { - if (ifsta->create_ibss && + if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && local->oper_channel->flag & IEEE80211_CHAN_W_IBSS) return ieee80211_sta_create_ibss(dev, ifsta); - if (ifsta->create_ibss) { + if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { printk(KERN_DEBUG "%s: IBSS not allowed on the" " configured channel %d (%d MHz)\n", dev->name, local->hw.conf.channel, @@ -2544,13 +2551,17 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) ifsta = &sdata->u.sta; if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) - ifsta->prev_bssid_set = 0; + ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; memcpy(ifsta->ssid, ssid, len); memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); ifsta->ssid_len = len; - ifsta->ssid_set = len ? 1 : 0; - if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) { + if (len) + ifsta->flags |= IEEE80211_STA_SSID_SET; + else + ifsta->flags &= ~IEEE80211_STA_SSID_SET; + if (sdata->type == IEEE80211_IF_TYPE_IBSS && + !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { ifsta->ibss_join_req = jiffies; ifsta->state = IEEE80211_IBSS_SEARCH; return ieee80211_sta_find_ibss(dev, ifsta); @@ -2588,10 +2599,11 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid) } } - if (!is_valid_ether_addr(bssid)) - ifsta->bssid_set = 0; + if (is_valid_ether_addr(bssid)) + ifsta->flags |= IEEE80211_STA_BSSID_SET; else - ifsta->bssid_set = 1; + ifsta->flags &= ~IEEE80211_STA_BSSID_SET; + return 0; } @@ -2658,7 +2670,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) continue; if (sdata->type == IEEE80211_IF_TYPE_STA) { - if (sdata->u.sta.associated) + if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) ieee80211_send_nullfunc(local, sdata, 0); ieee80211_sta_timer((unsigned long)sdata); } @@ -2670,7 +2682,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_IBSS) { struct ieee80211_if_sta *ifsta = &sdata->u.sta; - if (!ifsta->bssid_set || + if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || (!ifsta->state == IEEE80211_IBSS_JOINED && !ieee80211_sta_active_ibss(dev))) ieee80211_sta_find_ibss(dev, ifsta); @@ -2812,7 +2824,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev, netif_stop_queue(sdata->dev); if (sdata->type == IEEE80211_IF_TYPE_STA && - sdata->u.sta.associated) + (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) ieee80211_send_nullfunc(local, sdata, 1); } read_unlock(&local->sub_if_lock); @@ -3125,7 +3137,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason) if (sdata->type != IEEE80211_IF_TYPE_STA) return -EINVAL; - if (!ifsta->associated) + if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) return -1; ieee80211_send_disassoc(dev, ifsta, reason); From 13262ffd4902805acad2618c12b41fcaa6c50791 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 28 Aug 2007 17:01:54 -0400 Subject: [PATCH 1147/2804] [MAC80211]: Remove bitfields from struct ieee80211_sub_if_data mac80211, remove bitfields from struct ieee80211_sub_if_data Signed-off-by: Jiri Slaby Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/ieee80211.c | 30 ++++++++++++++---------------- net/mac80211/ieee80211_i.h | 16 +++++++++------- net/mac80211/ieee80211_ioctl.c | 20 ++++++++++++++------ net/mac80211/ieee80211_sta.c | 19 +++++++++++++------ net/mac80211/rx.c | 4 ++-- net/mac80211/tx.c | 18 ++++++++++-------- net/mac80211/util.c | 6 +++--- 8 files changed, 66 insertions(+), 49 deletions(-) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 099dac95b09b..8ceda33efc12 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -118,7 +118,7 @@ static ssize_t ieee80211_if_fmt_flags( sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", - sdata->use_protection ? "CTS prot\n" : ""); + sdata->flags & IEEE80211_SDATA_USE_PROTECTION ? "CTS prot\n" : ""); } __IEEE80211_IF_FILE(flags); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index be678c61afa5..50d7af3018ea 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -555,23 +555,21 @@ static void ieee80211_set_multicast_list(struct net_device *dev) unsigned short flags; netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); - if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) { - if (sdata->allmulti) { - sdata->allmulti = 0; + if (((dev->flags & IFF_ALLMULTI) != 0) ^ + ((sdata->flags & IEEE80211_SDATA_ALLMULTI) != 0)) { + if (sdata->flags & IEEE80211_SDATA_ALLMULTI) local->iff_allmultis--; - } else { - sdata->allmulti = 1; + else local->iff_allmultis++; - } + sdata->flags ^= IEEE80211_SDATA_ALLMULTI; } - if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) { - if (sdata->promisc) { - sdata->promisc = 0; + if (((dev->flags & IFF_PROMISC) != 0) ^ + ((sdata->flags & IEEE80211_SDATA_PROMISC) != 0)) { + if (sdata->flags & IEEE80211_SDATA_PROMISC) local->iff_promiscs--; - } else { - sdata->promisc = 1; + else local->iff_promiscs++; - } + sdata->flags ^= IEEE80211_SDATA_PROMISC; } if (dev->mc_count != sdata->mc_count) { local->mc_count = local->mc_count - sdata->mc_count + @@ -740,16 +738,16 @@ void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (local->ops->erp_ie_changed) local->ops->erp_ie_changed(local_to_hw(local), changes, - sdata->use_protection, - !sdata->short_preamble); + !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION), + !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)); } void ieee80211_reset_erp_info(struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sdata->short_preamble = 0; - sdata->use_protection = 0; + sdata->flags &= ~(IEEE80211_SDATA_USE_PROTECTION | + IEEE80211_SDATA_SHORT_PREAMBLE); ieee80211_erp_info_change_notify(dev, IEEE80211_ERP_CHANGE_PROTECTION | IEEE80211_ERP_CHANGE_PREAMBLE); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 28c5d514e6d5..ef633a041dab 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -277,6 +277,14 @@ struct ieee80211_if_sta { }; +/* flags used in struct ieee80211_sub_if_data.flags */ +#define IEEE80211_SDATA_ALLMULTI BIT(0) +#define IEEE80211_SDATA_PROMISC BIT(1) +#define IEEE80211_SDATA_USE_PROTECTION BIT(2) /* CTS protect ERP frames */ +/* use short preamble with IEEE 802.11b: this flag is set when the AP or beacon + * generator reports that there are no present stations that cannot support short + * preambles */ +#define IEEE80211_SDATA_SHORT_PREAMBLE BIT(3) struct ieee80211_sub_if_data { struct list_head list; unsigned int type; @@ -287,14 +295,8 @@ struct ieee80211_sub_if_data { struct ieee80211_local *local; int mc_count; - unsigned int allmulti:1; - unsigned int promisc:1; - unsigned int use_protection:1; /* CTS protect ERP frames */ - /* use short preamble with IEEE 802.11b: this flag is set when the AP - * or beacon generator reports that there are no present stations that - * cannot support short preambles */ - unsigned int short_preamble:1; + unsigned int flags; struct net_device_stats stats; int drop_unencrypted; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index ea2e0f958ac3..9964f057bcef 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1063,8 +1063,12 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: if (sdata->type == IEEE80211_IF_TYPE_AP) { - sdata->use_protection = !!value; - ieee80211_erp_info_change_notify(dev, IEEE80211_ERP_CHANGE_PROTECTION); + if (value) + sdata->flags |= IEEE80211_SDATA_USE_PROTECTION; + else + sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION; + ieee80211_erp_info_change_notify(dev, + IEEE80211_ERP_CHANGE_PROTECTION); } else { ret = -ENOENT; } @@ -1072,8 +1076,12 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, case PRISM2_PARAM_PREAMBLE: if (sdata->type != IEEE80211_IF_TYPE_AP) { - sdata->short_preamble = !!value; - ieee80211_erp_info_change_notify(dev, IEEE80211_ERP_CHANGE_PREAMBLE); + if (value) + sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE; + else + sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE; + ieee80211_erp_info_change_notify(dev, + IEEE80211_ERP_CHANGE_PREAMBLE); } else { ret = -ENOENT; } @@ -1167,11 +1175,11 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: - *param = sdata->use_protection; + *param = !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION); break; case PRISM2_PARAM_PREAMBLE: - *param = sdata->short_preamble; + *param = !!(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE); break; case PRISM2_PARAM_SHORT_SLOT_TIME: diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 6a57333dc75c..fe94ebfcb157 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -321,7 +321,7 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; u8 changes = 0; - if (use_protection != sdata->use_protection) { + if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" MAC_FMT ")\n", @@ -329,11 +329,14 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) use_protection ? "enabled" : "disabled", MAC_ARG(ifsta->bssid)); } - sdata->use_protection = use_protection; + if (use_protection) + sdata->flags |= IEEE80211_SDATA_USE_PROTECTION; + else + sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION; changes |= IEEE80211_ERP_CHANGE_PROTECTION; } - if (!preamble_mode != sdata->short_preamble) { + if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: switched to %s barker preamble" " (BSSID=" MAC_FMT ")\n", @@ -342,7 +345,10 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) "short" : "long", MAC_ARG(ifsta->bssid)); } - sdata->short_preamble = !preamble_mode; + if (preamble_mode) + sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE; + else + sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE; changes |= IEEE80211_ERP_CHANGE_PREAMBLE; } @@ -2307,8 +2313,9 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, "for IBSS beacon\n", dev->name); break; } - control.tx_rate = (sdata->short_preamble && - (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? + control.tx_rate = + ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && + (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? rate->val2 : rate->val; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; control.power_level = local->hw.conf.power_level; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index af94fb597415..b52e3305a8f8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1288,7 +1288,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { - if (!sdata->promisc) + if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } @@ -1303,7 +1303,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { - if (!sdata->promisc) + if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } else if (!rx->sta) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 01e7a734f867..ddb104a70161 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -173,7 +173,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, * to closest integer */ dur = ieee80211_frame_duration(local, 10, rate, erp, - tx->sdata->short_preamble); + tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE); if (next_frag_len) { /* Frame is fragmented: duration increases with time needed to @@ -181,8 +181,9 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, dur *= 2; /* ACK + SIFS */ /* next fragment */ dur += ieee80211_frame_duration(local, next_frag_len, - txrate->rate, erp, - tx->sdata->short_preamble); + txrate->rate, erp, + tx->sdata->flags & + IEEE80211_SDATA_SHORT_PREAMBLE); } return dur; @@ -613,7 +614,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) if (!tx->u.tx.rate) return TXRX_DROP; if (tx->u.tx.mode->mode == MODE_IEEE80211G && - tx->sdata->use_protection && + (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) { tx->u.tx.last_frag_rate = tx->u.tx.rate; if (extra.probe) @@ -670,7 +671,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) if (mode->mode == MODE_IEEE80211G && (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && (tx->flags & IEEE80211_TXRXD_TXUNICAST) && - tx->sdata->use_protection && + (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; @@ -679,7 +680,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && - tx->sdata->short_preamble && + (tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; } @@ -1777,8 +1778,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, return NULL; } - control->tx_rate = (sdata->short_preamble && - (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? + control->tx_rate = + ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && + (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? rate->val2 : rate->val; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; control->power_level = local->hw.conf.power_level; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 091ac0d634a5..07686bda26cd 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -329,7 +329,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, sdata = IEEE80211_DEV_TO_SUB_IF(bdev); erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); dur = ieee80211_frame_duration(local, frame_len, rate, - erp, sdata->short_preamble); + erp, sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE); dev_put(bdev); return cpu_to_le16(dur); @@ -352,7 +352,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, return 0; sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - short_preamble = sdata->short_preamble; + short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE; rate = frame_txctl->rts_rate; erp = !!(rate->flags & IEEE80211_RATE_ERP); @@ -388,7 +388,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, return 0; sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - short_preamble = sdata->short_preamble; + short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE; rate = frame_txctl->rts_rate; erp = !!(rate->flags & IEEE80211_RATE_ERP); From 8f20fc24986a083228823d9b68adca20714b254e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:54 -0400 Subject: [PATCH 1148/2804] [MAC80211]: embed key conf in key, fix driver interface This patch embeds the struct ieee80211_key_conf into struct ieee80211_key and thus avoids allocations and having data present twice. This required some more changes: 1) The removal of the IEEE80211_KEY_DEFAULT_TX_KEY key flag. This flag isn't used by drivers nor should it be since we have a set_key_idx() callback. Maybe that callback needs to be extended to include the key conf, but only a driver that requires it will tell. 2) The removal of the IEEE80211_KEY_DEFAULT_WEP_ONLY key flag. This flag is global, so it shouldn't be passed in the key conf structure. Pass it to the function instead. Also, this patch removes the AID parameter to the set_key() callback because it is currently unused and the hardware currently cannot know about the AID anyway. I suspect this was used with some hardware that actually selected the AID itself, but that functionality was removed. Additionally, I've removed the ALG_NULL key algorithm since we have ALG_NONE. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 51 +++++++++++----------- net/mac80211/debugfs_key.c | 49 +++++++++++++-------- net/mac80211/ieee80211.c | 5 ++- net/mac80211/ieee80211_i.h | 3 -- net/mac80211/ieee80211_iface.c | 3 +- net/mac80211/ieee80211_ioctl.c | 79 +++++++++++++--------------------- net/mac80211/ieee80211_key.h | 20 ++++----- net/mac80211/ieee80211_sta.c | 2 +- net/mac80211/key.c | 28 +----------- net/mac80211/rx.c | 22 +++++----- net/mac80211/sta_info.c | 17 +++----- net/mac80211/tkip.c | 18 ++++---- net/mac80211/tx.c | 6 +-- net/mac80211/wep.c | 18 ++++---- net/mac80211/wpa.c | 61 ++++++++++++++------------ 15 files changed, 177 insertions(+), 205 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 029e8cb7bf4e..056c225173d8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -205,8 +205,8 @@ struct ieee80211_tx_control { * is not implemented by the driver */ u8 power_level; /* per-packet transmit power level, in dBm */ u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ - s8 key_idx; /* -1 = do not encrypt, >= 0 keyidx from - * hw->set_key() */ + s8 key_idx; /* HW_KEY_IDX_INVALID = do not encrypt, + * other values: keyidx from hw->set_key() */ u8 icv_len; /* length of the ICV/MIC field in octets */ u8 iv_len; /* length of the IV field in octets */ u8 tkip_key[16]; /* generated phase2/phase1 key for hw TKIP */ @@ -392,26 +392,23 @@ struct ieee80211_if_conf { struct ieee80211_tx_control *beacon_control; }; -typedef enum { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, ALG_NULL } -ieee80211_key_alg; - +typedef enum { + ALG_NONE, + ALG_WEP, + ALG_TKIP, + ALG_CCMP, +} ieee80211_key_alg; struct ieee80211_key_conf { + /* shall be changed by the driver to anything but HW_KEY_IDX_INVALID */ + int hw_key_idx; - int hw_key_idx; /* filled + used by low-level driver */ ieee80211_key_alg alg; + int keylen; #define IEEE80211_KEY_FORCE_SW_ENCRYPT (1<<0) /* to be cleared by low-level driver */ -#define IEEE80211_KEY_DEFAULT_TX_KEY (1<<1) /* This key is the new default TX - key (used only for broadcast - keys). */ -#define IEEE80211_KEY_DEFAULT_WEP_ONLY (1<<2) /* static WEP is the only - configured security policy; - this allows some low-level - drivers to determine when - hwaccel can be used */ u32 flags; /* key configuration flags defined above */ s8 keyidx; /* WEP key index */ @@ -625,20 +622,26 @@ struct ieee80211_ops { * Must be atomic. */ int (*set_tim)(struct ieee80211_hw *hw, int aid, int set); - /* Set encryption key. IEEE 802.11 module calls this function to set - * encryption keys. addr is ff:ff:ff:ff:ff:ff for default keys and - * station hwaddr for individual keys. aid of the station is given - * to help low-level driver in selecting which key->hw_key_idx to use - * for this key. TX control data will use the hw_key_idx selected by - * the low-level driver. */ + /* + * Set encryption key. + * + * This is called to enable hardware acceleration of encryption and + * decryption. The address will be the broadcast address for default + * keys and the other station's hardware address for individual keys. + * When transmitting, the TX control data will use the hw_key_idx + * selected by the low-level driver. + */ int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, - u8 *addr, struct ieee80211_key_conf *key, int aid); + u8 *address, struct ieee80211_key_conf *key, + int static_wep_only); - /* Set TX key index for default/broadcast keys. This is needed in cases + /* + * Set TX key index for default/broadcast keys. This is needed in cases * where wlan card is doing full WEP/TKIP encapsulation (wep_include_iv * is not set), in other cases, this function pointer can be set to - * NULL since the IEEE 802. 11 module takes care of selecting the key - * index for each TX frame. */ + * NULL since the IEEE 802.11 module takes care of selecting the key + * index for each TX frame. + */ int (*set_key_idx)(struct ieee80211_hw *hw, int idx); /* Enable/disable IEEE 802.1X. This item requests wlan card to pass diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 077f907271cf..246938c32d4d 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -14,17 +14,17 @@ #include "debugfs.h" #include "debugfs_key.h" -#define KEY_READ(name, buflen, format_string) \ +#define KEY_READ(name, prop, buflen, format_string) \ static ssize_t key_##name##_read(struct file *file, \ char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ char buf[buflen]; \ struct ieee80211_key *key = file->private_data; \ - int res = scnprintf(buf, buflen, format_string, key->name); \ + int res = scnprintf(buf, buflen, format_string, key->prop); \ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ } -#define KEY_READ_D(name) KEY_READ(name, 20, "%d\n") +#define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n") #define KEY_OPS(name) \ static const struct file_operations key_ ##name## _ops = { \ @@ -36,10 +36,25 @@ static const struct file_operations key_ ##name## _ops = { \ KEY_READ_##format(name) \ KEY_OPS(name) -KEY_FILE(keylen, D); -KEY_FILE(force_sw_encrypt, D); -KEY_FILE(keyidx, D); -KEY_FILE(hw_key_idx, D); +#define KEY_CONF_READ(name, buflen, format_string) \ + KEY_READ(conf_##name, conf.name, buflen, format_string) +#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n") +#define KEY_CONF_READ_X(name) KEY_CONF_READ(name, 20, "0x%x\n") + +#define KEY_CONF_OPS(name) \ +static const struct file_operations key_ ##name## _ops = { \ + .read = key_conf_##name##_read, \ + .open = mac80211_open_file_generic, \ +} + +#define KEY_CONF_FILE(name, format) \ + KEY_CONF_READ_##format(name) \ + KEY_CONF_OPS(name) + +KEY_CONF_FILE(keylen, D); +KEY_CONF_FILE(keyidx, D); +KEY_CONF_FILE(hw_key_idx, D); +KEY_CONF_FILE(flags, X); KEY_FILE(tx_rx_count, D); static ssize_t key_algorithm_read(struct file *file, @@ -49,7 +64,7 @@ static ssize_t key_algorithm_read(struct file *file, char *alg; struct ieee80211_key *key = file->private_data; - switch (key->alg) { + switch (key->conf.alg) { case ALG_WEP: alg = "WEP\n"; break; @@ -74,7 +89,7 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, int len; struct ieee80211_key *key = file->private_data; - switch (key->alg) { + switch (key->conf.alg) { case ALG_WEP: len = scnprintf(buf, sizeof(buf), "\n"); break; @@ -103,7 +118,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, int i, len; const u8 *rpn; - switch (key->alg) { + switch (key->conf.alg) { case ALG_WEP: len = scnprintf(buf, sizeof(buf), "\n"); break; @@ -139,7 +154,7 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf, char buf[20]; int len; - if (key->alg != ALG_CCMP) + if (key->conf.alg != ALG_CCMP) return 0; len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); return simple_read_from_buffer(userbuf, count, ppos, buf, len); @@ -150,12 +165,12 @@ static ssize_t key_key_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct ieee80211_key *key = file->private_data; - int i, res, bufsize = 2*key->keylen+2; + int i, res, bufsize = 2 * key->conf.keylen + 2; char *buf = kmalloc(bufsize, GFP_KERNEL); char *p = buf; - for (i = 0; i < key->keylen; i++) - p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]); + for (i = 0; i < key->conf.keylen; i++) + p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]); p += scnprintf(p, bufsize+buf-p, "\n"); res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); kfree(buf); @@ -185,7 +200,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_local *local, return; DEBUGFS_ADD(keylen); - DEBUGFS_ADD(force_sw_encrypt); + DEBUGFS_ADD(flags); DEBUGFS_ADD(keyidx); DEBUGFS_ADD(hw_key_idx); DEBUGFS_ADD(tx_rx_count); @@ -205,7 +220,7 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key) return; DEBUGFS_DEL(keylen); - DEBUGFS_DEL(force_sw_encrypt); + DEBUGFS_DEL(flags); DEBUGFS_DEL(keyidx); DEBUGFS_DEL(hw_key_idx); DEBUGFS_DEL(tx_rx_count); @@ -227,7 +242,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) if (!sdata->debugfsdir) return; - sprintf(buf, "../keys/%d", sdata->default_key->keyidx); + sprintf(buf, "../keys/%d", sdata->default_key->conf.keyidx); sdata->debugfs.default_key = debugfs_create_symlink("default_key", sdata->debugfsdir, buf); } diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 50d7af3018ea..5d5034f36fde 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -890,7 +890,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, if (!key) goto no_key; - switch (key->alg) { + switch (key->conf.alg) { case ALG_WEP: iv_len = WEP_IV_LEN; mic_len = WEP_ICV_LEN; @@ -907,7 +907,8 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, goto no_key; } - if (skb->len >= mic_len && key->force_sw_encrypt) + if (skb->len >= mic_len && + (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) skb_trim(skb, skb->len - mic_len); if (skb->len >= iv_len && skb->len > hdrlen) { memmove(skb->data + iv_len, skb->data, hdrlen); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ef633a041dab..cc87e9d988f8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -816,9 +816,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); /* key handling */ -struct ieee80211_key_conf * -ieee80211_key_data2conf(struct ieee80211_local *local, - const struct ieee80211_key *data); struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, int idx, size_t key_len, gfp_t flags); void ieee80211_key_free(struct ieee80211_key *key); diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 61009176d51b..3e59afa23e4e 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -227,7 +227,8 @@ void ieee80211_if_reinit(struct net_device *dev) memset(addr, 0xff, ETH_ALEN); if (local->ops->set_key) local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr, - local->keys[i], 0); + local->keys[i], + local->default_wep_only); #endif ieee80211_key_free(sdata->keys[i]); sdata->keys[i] = NULL; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 9964f057bcef..380670c7a0ca 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -31,29 +31,20 @@ static void ieee80211_set_hw_encryption(struct net_device *dev, struct sta_info *sta, u8 addr[ETH_ALEN], struct ieee80211_key *key) { - struct ieee80211_key_conf *keyconf = NULL; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); /* default to sw encryption; this will be cleared by low-level * driver if the hw supports requested encryption */ if (key) - key->force_sw_encrypt = 1; + key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - if (key && local->ops->set_key && - (keyconf = ieee80211_key_data2conf(local, key))) { + if (key && local->ops->set_key) { if (local->ops->set_key(local_to_hw(local), SET_KEY, addr, - keyconf, sta ? sta->aid : 0)) { - key->force_sw_encrypt = 1; - key->hw_key_idx = HW_KEY_IDX_INVALID; - } else { - key->force_sw_encrypt = - !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT); - key->hw_key_idx = - keyconf->hw_key_idx; - + &key->conf, local->default_wep_only)) { + key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; + key->conf.hw_key_idx = HW_KEY_IDX_INVALID; } } - kfree(keyconf); } @@ -66,7 +57,6 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, struct sta_info *sta; struct ieee80211_key *key, *old_key; int try_hwaccel = 1; - struct ieee80211_key_conf *keyconf; struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -154,18 +144,16 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, } if (alg == ALG_NONE) { - keyconf = NULL; if (try_hwaccel && key && - key->hw_key_idx != HW_KEY_IDX_INVALID && + key->conf.hw_key_idx != HW_KEY_IDX_INVALID && local->ops->set_key && - (keyconf = ieee80211_key_data2conf(local, key)) != NULL && local->ops->set_key(local_to_hw(local), DISABLE_KEY, - sta_addr, keyconf, sta ? sta->aid : 0)) { + sta_addr, &key->conf, + local->default_wep_only)) { printk(KERN_DEBUG "%s: set_encrypt - low-level disable" " failed\n", dev->name); ret = -EINVAL; } - kfree(keyconf); if (set_tx_key || sdata->default_key == key) { ieee80211_debugfs_key_remove_default(sdata); @@ -189,22 +177,20 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, /* default to sw encryption; low-level driver sets these if the * requested encryption is supported */ - key->hw_key_idx = HW_KEY_IDX_INVALID; - key->force_sw_encrypt = 1; + key->conf.hw_key_idx = HW_KEY_IDX_INVALID; + key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - key->alg = alg; - key->keyidx = idx; - key->keylen = key_len; - memcpy(key->key, _key, key_len); - if (set_tx_key) - key->default_tx_key = 1; + key->conf.alg = alg; + key->conf.keyidx = idx; + key->conf.keylen = key_len; + memcpy(key->conf.key, _key, key_len); if (alg == ALG_CCMP) { /* Initialize AES key state here as an optimization * so that it does not need to be initialized for every * packet. */ key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt( - key->key); + key->conf.key); if (!key->u.ccmp.tfm) { ret = -ENOMEM; goto err_free; @@ -941,43 +927,38 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev, static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local, struct ieee80211_key *key) { - struct ieee80211_key_conf *keyconf; u8 addr[ETH_ALEN]; - if (!key || key->alg != ALG_WEP || !key->force_sw_encrypt || + if (!key || key->conf.alg != ALG_WEP || + !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) || (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)) return; memset(addr, 0xff, ETH_ALEN); - keyconf = ieee80211_key_data2conf(local, key); - if (keyconf && local->ops->set_key && + + if (local->ops->set_key) local->ops->set_key(local_to_hw(local), - SET_KEY, addr, keyconf, 0) == 0) { - key->force_sw_encrypt = - !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT); - key->hw_key_idx = keyconf->hw_key_idx; - } - kfree(keyconf); + SET_KEY, addr, &key->conf, + local->default_wep_only); } static void ieee80211_key_disable_hwaccel(struct ieee80211_local *local, struct ieee80211_key *key) { - struct ieee80211_key_conf *keyconf; u8 addr[ETH_ALEN]; - if (!key || key->alg != ALG_WEP || key->force_sw_encrypt || + if (!key || key->conf.alg != ALG_WEP || + (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) || (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)) return; memset(addr, 0xff, ETH_ALEN); - keyconf = ieee80211_key_data2conf(local, key); - if (keyconf && local->ops->set_key) + if (local->ops->set_key) local->ops->set_key(local_to_hw(local), DISABLE_KEY, - addr, keyconf, 0); - kfree(keyconf); - key->force_sw_encrypt = 1; + addr, &key->conf, + local->default_wep_only); + key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; } @@ -1341,9 +1322,9 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev, return 0; } - memcpy(key, sdata->keys[idx]->key, - min((int)erq->length, sdata->keys[idx]->keylen)); - erq->length = sdata->keys[idx]->keylen; + memcpy(key, sdata->keys[idx]->conf.key, + min((int)erq->length, sdata->keys[idx]->conf.keylen)); + erq->length = sdata->keys[idx]->conf.keylen; erq->flags |= IW_ENCODE_ENABLED; return 0; diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index c33384912782..1b5e539c678f 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -44,8 +44,6 @@ struct ieee80211_key { struct kref kref; - int hw_key_idx; /* filled and used by low-level driver */ - ieee80211_key_alg alg; union { struct { /* last used TSC */ @@ -73,22 +71,16 @@ struct ieee80211_key { u8 rx_crypto_buf[6 * AES_BLOCK_LEN]; } ccmp; } u; - int tx_rx_count; /* number of times this key has been used */ - int keylen; - /* if the low level driver can provide hardware acceleration it should - * clear this flag */ - unsigned int force_sw_encrypt:1; - unsigned int default_tx_key:1; /* This key is the new default TX key - * (used only for broadcast keys). */ - s8 keyidx; /* WEP key index */ + /* number of times this key has been used */ + int tx_rx_count; #ifdef CONFIG_MAC80211_DEBUGFS struct { struct dentry *stalink; struct dentry *dir; struct dentry *keylen; - struct dentry *force_sw_encrypt; + struct dentry *flags; struct dentry *keyidx; struct dentry *hw_key_idx; struct dentry *tx_rx_count; @@ -100,7 +92,11 @@ struct ieee80211_key { } debugfs; #endif - u8 key[0]; + /* + * key config, must be last because it contains key + * material as variable length member + */ + struct ieee80211_key_conf conf; }; #endif /* IEEE80211_KEY_H */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index fe94ebfcb157..a2443271629a 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -904,7 +904,7 @@ static int ieee80211_sta_wep_configured(struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (!sdata || !sdata->default_key || - sdata->default_key->alg != ALG_WEP) + sdata->default_key->conf.alg != ALG_WEP) return 0; return 1; } diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b67558c24639..92d994f090b6 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -13,32 +13,6 @@ #include "debugfs_key.h" #include "aes_ccm.h" -struct ieee80211_key_conf * -ieee80211_key_data2conf(struct ieee80211_local *local, - const struct ieee80211_key *data) -{ - struct ieee80211_key_conf *conf; - - conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC); - if (!conf) - return NULL; - - conf->hw_key_idx = data->hw_key_idx; - conf->alg = data->alg; - conf->keylen = data->keylen; - conf->flags = 0; - if (data->force_sw_encrypt) - conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - conf->keyidx = data->keyidx; - if (data->default_tx_key) - conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY; - if (local->default_wep_only) - conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY; - memcpy(conf->key, data->key, data->keylen); - - return conf; -} - struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, int idx, size_t key_len, gfp_t flags) { @@ -56,7 +30,7 @@ static void ieee80211_key_release(struct kref *kref) struct ieee80211_key *key; key = container_of(kref, struct ieee80211_key, kref); - if (key->alg == ALG_CCMP) + if (key->conf.alg == ALG_CCMP) ieee80211_aes_key_free(key->u.ccmp.tfm); ieee80211_debugfs_key_remove(key); kfree(key); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b52e3305a8f8..976b646a40de 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -374,7 +374,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) * pairwise or station-to-station keys, but for WEP we allow * using a key index as well. */ - if (rx->key && rx->key->alg != ALG_WEP && + if (rx->key && rx->key->conf.alg != ALG_WEP && !is_multicast_ether_addr(hdr->addr1)) rx->key = NULL; } @@ -522,18 +522,15 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) { if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - !rx->key || rx->key->alg != ALG_WEP || + !rx->key || rx->key->conf.alg != ALG_WEP || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) return TXRX_CONTINUE; /* Check for weak IVs, if hwaccel did not remove IV from the frame */ if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) || - rx->key->force_sw_encrypt) { - u8 *iv = ieee80211_wep_is_weak_iv(rx->skb, rx->key); - if (iv) { + (rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) + if (ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; - } - } return TXRX_CONTINUE; } @@ -541,7 +538,7 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) static ieee80211_txrx_result ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) { - if ((rx->key && rx->key->alg != ALG_WEP) || + if ((rx->key && rx->key->conf.alg != ALG_WEP) || !(rx->fc & IEEE80211_FCTL_PROTECTED) || ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || @@ -556,7 +553,7 @@ ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) } if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || - rx->key->force_sw_encrypt) { + (rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " @@ -680,7 +677,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) /* This is the first fragment of a new frame. */ entry = ieee80211_reassemble_add(rx->sdata, frag, seq, rx->u.rx.queue, &(rx->skb)); - if (rx->key && rx->key->alg == ALG_CCMP && + if (rx->key && rx->key->conf.alg == ALG_CCMP && (rx->fc & IEEE80211_FCTL_PROTECTED)) { /* Store CCMP PN so that we can verify that the next * fragment has a sequential PN value. */ @@ -707,7 +704,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) if (entry->ccmp) { int i; u8 pn[CCMP_PN_LEN], *rpn; - if (!rx->key || rx->key->alg != ALG_CCMP) + if (!rx->key || rx->key->conf.alg != ALG_CCMP) return TXRX_DROP; memcpy(pn, entry->last_pn, CCMP_PN_LEN); for (i = CCMP_PN_LEN - 1; i >= 0; i--) { @@ -900,7 +897,8 @@ ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) * uploaded to the hardware. */ if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) && - (!rx->key || !rx->key->force_sw_encrypt)) + (!rx->key || + !(rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT))) return TXRX_CONTINUE; /* Drop unencrypted frames if key is set. */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 34245b882c2b..7e10c692c4ad 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -228,23 +228,20 @@ void sta_info_free(struct sta_info *sta) if (sta->key) { if (local->ops->set_key) { - struct ieee80211_key_conf *key; - key = ieee80211_key_data2conf(local, sta->key); - if (key) { - local->ops->set_key(local_to_hw(local), - DISABLE_KEY, - sta->addr, key, sta->aid); - kfree(key); - } + local->ops->set_key(local_to_hw(local), + DISABLE_KEY, sta->addr, + &sta->key->conf, + local->default_wep_only); } } else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) { struct ieee80211_key_conf conf; memset(&conf, 0, sizeof(conf)); conf.hw_key_idx = sta->key_idx_compression; - conf.alg = ALG_NULL; + conf.alg = ALG_NONE; conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; local->ops->set_key(local_to_hw(local), DISABLE_KEY, - sta->addr, &conf, sta->aid); + sta->addr, &conf, + local->default_wep_only); sta->key_idx_compression = HW_KEY_IDX_INVALID; } diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 41621720e560..b9c1d5405180 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -182,7 +182,7 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, *pos++ = iv0; *pos++ = iv1; *pos++ = iv2; - *pos++ = (key->keyidx << 6) | (1 << 5) /* Ext IV */; + *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; *pos++ = key->u.tkip.iv32 & 0xff; *pos++ = (key->u.tkip.iv32 >> 8) & 0xff; *pos++ = (key->u.tkip.iv32 >> 16) & 0xff; @@ -194,7 +194,7 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta, u16 *phase1key) { - tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY], + tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], key->u.tkip.iv32, phase1key); } @@ -204,12 +204,13 @@ void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, /* Calculate per-packet key */ if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) { /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY], + tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], key->u.tkip.iv32, key->u.tkip.p1k); key->u.tkip.tx_initialized = 1; } - tkip_mixing_phase2(key->u.tkip.p1k, &key->key[ALG_TKIP_TEMP_ENCR_KEY], + tkip_mixing_phase2(key->u.tkip.p1k, + &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], key->u.tkip.iv16, rc4key); } @@ -266,7 +267,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if (!(keyid & (1 << 5))) return TKIP_DECRYPT_NO_EXT_IV; - if ((keyid >> 6) != key->keyidx) + if ((keyid >> 6) != key->conf.keyidx) return TKIP_DECRYPT_INVALID_KEYIDX; if (key->u.tkip.rx_initialized[queue] && @@ -293,7 +294,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, key->u.tkip.iv32_rx[queue] != iv32) { key->u.tkip.rx_initialized[queue] = 1; /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY], + tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv32, key->u.tkip.p1k_rx[queue]); #ifdef CONFIG_TKIP_DEBUG { @@ -302,7 +303,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, " TK=", MAC_ARG(ta)); for (i = 0; i < 16; i++) printk("%02x ", - key->key[ALG_TKIP_TEMP_ENCR_KEY + i]); + key->conf.key[ + ALG_TKIP_TEMP_ENCR_KEY + i]); printk("\n"); printk(KERN_DEBUG "TKIP decrypt: P1K="); for (i = 0; i < 5; i++) @@ -313,7 +315,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, } tkip_mixing_phase2(key->u.tkip.p1k_rx[queue], - &key->key[ALG_TKIP_TEMP_ENCR_KEY], + &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, rc4key); #ifdef CONFIG_TKIP_DEBUG { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ddb104a70161..684f928def93 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -539,11 +539,11 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) { - if (tx->key->force_sw_encrypt) { + if (tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { - tx->u.tx.control->key_idx = tx->key->hw_key_idx; + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { if (ieee80211_wep_add_iv(tx->local, skb, tx->key) == NULL) @@ -561,7 +561,7 @@ ieee80211_tx_h_wep_encrypt(struct ieee80211_txrx_data *tx) fc = le16_to_cpu(hdr->frame_control); - if (!tx->key || tx->key->alg != ALG_WEP || + if (!tx->key || tx->key->conf.alg != ALG_WEP || ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 1ad3d75281cc..0b19e89fcf6a 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -67,7 +67,7 @@ void ieee80211_wep_get_iv(struct ieee80211_local *local, struct ieee80211_key *key, u8 *iv) { local->wep_iv++; - if (ieee80211_wep_weak_iv(local->wep_iv, key->keylen)) + if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen)) local->wep_iv += 0x0100; if (!iv) @@ -76,7 +76,7 @@ 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->keyidx << 6; + *iv++ = key->conf.keyidx << 6; } @@ -159,10 +159,10 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, u8 *rc4key, *iv; size_t len; - if (!key || key->alg != ALG_WEP) + if (!key || key->conf.alg != ALG_WEP) return -1; - klen = 3 + key->keylen; + klen = 3 + key->conf.keylen; rc4key = kmalloc(klen, GFP_ATOMIC); if (!rc4key) return -1; @@ -179,7 +179,7 @@ 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->key, key->keylen); + memcpy(rc4key + 3, key->conf.key, key->conf.keylen); /* Add room for ICV */ skb_put(skb, WEP_ICV_LEN); @@ -251,10 +251,10 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, keyidx = skb->data[hdrlen + 3] >> 6; - if (!key || keyidx != key->keyidx || key->alg != ALG_WEP) + if (!key || keyidx != key->conf.keyidx || key->conf.alg != ALG_WEP) return -1; - klen = 3 + key->keylen; + klen = 3 + key->conf.keylen; rc4key = kmalloc(klen, GFP_ATOMIC); if (!rc4key) @@ -264,7 +264,7 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, memcpy(rc4key, skb->data + hdrlen, 3); /* Copy rest of the WEP key (the secret part) */ - memcpy(rc4key + 3, key->key, key->keylen); + memcpy(rc4key + 3, key->conf.key, key->conf.keylen); if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen, skb->data + hdrlen + WEP_IV_LEN, @@ -321,7 +321,7 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) ivpos = skb->data + hdrlen; iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; - if (ieee80211_wep_weak_iv(iv, key->keylen)) + if (ieee80211_wep_weak_iv(iv, key->conf.keylen)) return ivpos; return NULL; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 1142b42b5fe9..4a2a9aa638b3 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -82,14 +82,14 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) fc = tx->fc; - if (!tx->key || tx->key->alg != ALG_TKIP || skb->len < 24 || + if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 || !WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)) return TXRX_DROP; - if (!tx->key->force_sw_encrypt && + if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) && !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) && !wpa_test) { @@ -114,8 +114,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) #else authenticator = 1; #endif - key = &tx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY : - ALG_TKIP_TEMP_AUTH_RX_MIC_KEY]; + key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY : + ALG_TKIP_TEMP_AUTH_RX_MIC_KEY]; mic = skb_put(skb, MICHAEL_MIC_LEN); michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); @@ -141,12 +141,12 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) if (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC) return TXRX_CONTINUE; - if (!rx->key || rx->key->alg != ALG_TKIP || + if (!rx->key || rx->key->conf.alg != ALG_TKIP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !rx->key->force_sw_encrypt) { + !(rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { if (skb->len < MICHAEL_MIC_LEN) return TXRX_DROP; @@ -169,8 +169,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) #else authenticator = 1; #endif - key = &rx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY : - ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; + key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY : + ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) @@ -179,7 +179,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " MAC_FMT "\n", rx->dev->name, MAC_ARG(sa)); - mac80211_ev_michael_mic_failure(rx->dev, rx->key->keyidx, + mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, (void *) skb->data); return TXRX_DROP; } @@ -205,7 +205,11 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; - tailneed = !tx->key->force_sw_encrypt ? 0 : TKIP_ICV_LEN; + if (tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) + tailneed = TKIP_ICV_LEN; + else + tailneed = 0; + if ((skb_headroom(skb) < TKIP_IV_LEN || skb_tailroom(skb) < tailneed)) { I802_DEBUG_INC(tx->local->tx_expand_skb_head); @@ -223,7 +227,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, if (key->u.tkip.iv16 == 0) key->u.tkip.iv32++; - if (!tx->key->force_sw_encrypt) { + if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { u32 flags = tx->local->hw.flags; hdr = (struct ieee80211_hdr *)skb->data; @@ -250,7 +254,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, ~IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY; } - tx->u.tx.control->key_idx = tx->key->hw_key_idx; + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; return 0; } @@ -275,18 +279,18 @@ ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx) fc = le16_to_cpu(hdr->frame_control); - if (!key || key->alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc)) + if (!key || key->conf.alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; tx->u.tx.control->icv_len = TKIP_ICV_LEN; tx->u.tx.control->iv_len = TKIP_IV_LEN; ieee80211_tx_set_iswep(tx); - if (!tx->key->force_sw_encrypt && + if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) && !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ - tx->u.tx.control->key_idx = tx->key->hw_key_idx; + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; return TXRX_CONTINUE; } @@ -318,7 +322,7 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); - if (!rx->key || rx->key->alg != ALG_TKIP || + if (!rx->key || rx->key->conf.alg != ALG_TKIP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) return TXRX_CONTINUE; @@ -327,7 +331,7 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !rx->key->force_sw_encrypt) { + !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { /* Hardware takes care of all processing, including * replay protection, so no need to continue here. */ @@ -471,7 +475,10 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; - tailneed = !key->force_sw_encrypt ? 0 : CCMP_MIC_LEN; + if (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) + tailneed = CCMP_MIC_LEN; + else + tailneed = 0; if ((skb_headroom(skb) < CCMP_HDR_LEN || skb_tailroom(skb) < tailneed)) { @@ -495,11 +502,11 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, break; } - ccmp_pn2hdr(pos, pn, key->keyidx); + ccmp_pn2hdr(pos, pn, key->conf.keyidx); - if (!key->force_sw_encrypt) { + if (!(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { /* hwaccel - with preallocated room for CCMP header */ - tx->u.tx.control->key_idx = key->hw_key_idx; + tx->u.tx.control->key_idx = key->conf.hw_key_idx; return 0; } @@ -523,18 +530,18 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) fc = le16_to_cpu(hdr->frame_control); - if (!key || key->alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc)) + if (!key || key->conf.alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; tx->u.tx.control->icv_len = CCMP_MIC_LEN; tx->u.tx.control->iv_len = CCMP_HDR_LEN; ieee80211_tx_set_iswep(tx); - if (!tx->key->force_sw_encrypt && + if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) && !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ - tx->u.tx.control->key_idx = tx->key->hw_key_idx; + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; return TXRX_CONTINUE; } @@ -569,7 +576,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); - if (!key || key->alg != ALG_CCMP || + if (!key || key->conf.alg != ALG_CCMP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) return TXRX_CONTINUE; @@ -579,7 +586,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !key->force_sw_encrypt && + !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) && !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) return TXRX_CONTINUE; @@ -600,7 +607,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) } if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !key->force_sw_encrypt) { + !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { /* hwaccel has already decrypted frame and verified MIC */ } else { u8 *scratch, *b_0, *aad; From 8f37171a6243a8370211a1e86d58be683ccf01f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:54 -0400 Subject: [PATCH 1149/2804] [MAC80211]: remove krefs for keys they aren't really refcounted anyway Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_key.h | 4 +--- net/mac80211/key.c | 13 +++---------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index 1b5e539c678f..58e192530826 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -11,7 +11,7 @@ #define IEEE80211_KEY_H #include -#include +#include #include #include @@ -42,8 +42,6 @@ #define NUM_RX_DATA_QUEUES 17 struct ieee80211_key { - struct kref kref; - union { struct { /* last used TSC */ diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 92d994f090b6..843d1577f00f 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -21,23 +21,16 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags); if (!key) return NULL; - kref_init(&key->kref); return key; } -static void ieee80211_key_release(struct kref *kref) +void ieee80211_key_free(struct ieee80211_key *key) { - struct ieee80211_key *key; + if (!key) + return; - key = container_of(kref, struct ieee80211_key, kref); if (key->conf.alg == ALG_CCMP) ieee80211_aes_key_free(key->u.ccmp.tfm); ieee80211_debugfs_key_remove(key); kfree(key); } - -void ieee80211_key_free(struct ieee80211_key *key) -{ - if (key) - kref_put(&key->kref, ieee80211_key_release); -} From f658eb90d065c2d76ab3f3eb676ebf53462e323b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:54 -0400 Subject: [PATCH 1150/2804] [MAC80211] key handling: remove default_wep_only Remove the default_wep_only stuff, this wasn't really done well and no current driver actually cares. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 3 +- net/mac80211/ieee80211_i.h | 5 -- net/mac80211/ieee80211_iface.c | 5 -- net/mac80211/ieee80211_ioctl.c | 97 ++-------------------------------- net/mac80211/sta_info.c | 6 +-- 5 files changed, 6 insertions(+), 110 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 056c225173d8..3437fa16eea5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -632,8 +632,7 @@ struct ieee80211_ops { * selected by the low-level driver. */ int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, - u8 *address, struct ieee80211_key_conf *key, - int static_wep_only); + u8 *address, struct ieee80211_key_conf *key); /* * Set TX key index for default/broadcast keys. This is needed in cases diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cc87e9d988f8..7b5cc146c81b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -551,9 +551,6 @@ struct ieee80211_local { #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ - int default_wep_only; /* only default WEP keys are used with this - * interface; this is used to decide when hwaccel - * can be used with default keys */ int total_ps_buffered; /* total number of all buffered unicast and * multicast packets for power saving stations */ @@ -733,8 +730,6 @@ void ieee80211_key_threshold_notify(struct net_device *dev, /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; -void ieee80211_update_default_wep_only(struct ieee80211_local *local); - /* Least common multiple of the used rates (in 100 kbps). This is used to * calculate rate_inv values for each rate so that only integers are needed. */ diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 3e59afa23e4e..8bb85f194385 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -88,8 +88,6 @@ int ieee80211_if_add(struct net_device *dev, const char *name, *new_dev = ndev; write_unlock_bh(&local->sub_if_lock); - ieee80211_update_default_wep_only(local); - return 0; fail: @@ -154,7 +152,6 @@ void ieee80211_if_del_mgmt(struct ieee80211_local *local) void ieee80211_if_set_type(struct net_device *dev, int type) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int oldtype = sdata->type; dev->hard_start_xmit = ieee80211_subif_start_xmit; @@ -205,7 +202,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type) dev->name, __FUNCTION__, type); } ieee80211_debugfs_change_if_type(sdata, oldtype); - ieee80211_update_default_wep_only(local); } /* Must be called with rtnl lock held. */ @@ -336,7 +332,6 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id) list_del(&sdata->list); write_unlock_bh(&local->sub_if_lock); __ieee80211_if_del(local, sdata); - ieee80211_update_default_wep_only(local); return 0; } } diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 380670c7a0ca..dc05bc66fbb8 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -40,7 +40,7 @@ static void ieee80211_set_hw_encryption(struct net_device *dev, if (key && local->ops->set_key) { if (local->ops->set_key(local_to_hw(local), SET_KEY, addr, - &key->conf, local->default_wep_only)) { + &key->conf)) { key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; key->conf.hw_key_idx = HW_KEY_IDX_INVALID; } @@ -111,7 +111,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, * possibility of conflict with default keys. This can maybe later be * optimized by using non-default keys (at least with Atheros ar521x). */ - if (!sta && alg == ALG_WEP && !local->default_wep_only && + if (!sta && alg == ALG_WEP && sdata->type != IEEE80211_IF_TYPE_IBSS && sdata->type != IEEE80211_IF_TYPE_AP) { try_hwaccel = 0; @@ -148,8 +148,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, key->conf.hw_key_idx != HW_KEY_IDX_INVALID && local->ops->set_key && local->ops->set_key(local_to_hw(local), DISABLE_KEY, - sta_addr, &key->conf, - local->default_wep_only)) { + sta_addr, &key->conf)) { printk(KERN_DEBUG "%s: set_encrypt - low-level disable" " failed\n", dev->name); ret = -EINVAL; @@ -924,96 +923,6 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev, return 0; } -static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local, - struct ieee80211_key *key) -{ - u8 addr[ETH_ALEN]; - - if (!key || key->conf.alg != ALG_WEP || - !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) || - (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)) - return; - - memset(addr, 0xff, ETH_ALEN); - - if (local->ops->set_key) - local->ops->set_key(local_to_hw(local), - SET_KEY, addr, &key->conf, - local->default_wep_only); -} - - -static void ieee80211_key_disable_hwaccel(struct ieee80211_local *local, - struct ieee80211_key *key) -{ - u8 addr[ETH_ALEN]; - - if (!key || key->conf.alg != ALG_WEP || - (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) || - (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)) - return; - - memset(addr, 0xff, ETH_ALEN); - if (local->ops->set_key) - local->ops->set_key(local_to_hw(local), DISABLE_KEY, - addr, &key->conf, - local->default_wep_only); - key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; -} - - -static int ieee80211_ioctl_default_wep_only(struct ieee80211_local *local, - int value) -{ - int i; - struct ieee80211_sub_if_data *sdata; - - local->default_wep_only = value; - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) - for (i = 0; i < NUM_DEFAULT_KEYS; i++) - if (value) - ieee80211_key_enable_hwaccel(local, - sdata->keys[i]); - else - ieee80211_key_disable_hwaccel(local, - sdata->keys[i]); - read_unlock(&local->sub_if_lock); - - return 0; -} - - -void ieee80211_update_default_wep_only(struct ieee80211_local *local) -{ - int i = 0; - struct ieee80211_sub_if_data *sdata; - - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - - if (sdata->dev == local->mdev) - continue; - - /* If there is an AP interface then depend on userspace to - set default_wep_only correctly. */ - if (sdata->type == IEEE80211_IF_TYPE_AP) { - read_unlock(&local->sub_if_lock); - return; - } - - i++; - } - - read_unlock(&local->sub_if_lock); - - if (i <= 1) - ieee80211_ioctl_default_wep_only(local, 1); - else - ieee80211_ioctl_default_wep_only(local, 0); -} - - static int ieee80211_ioctl_prism2_param(struct net_device *dev, struct iw_request_info *info, void *wrqu, char *extra) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7e10c692c4ad..a1f766fcf966 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -230,8 +230,7 @@ void sta_info_free(struct sta_info *sta) if (local->ops->set_key) { local->ops->set_key(local_to_hw(local), DISABLE_KEY, sta->addr, - &sta->key->conf, - local->default_wep_only); + &sta->key->conf); } } else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) { struct ieee80211_key_conf conf; @@ -240,8 +239,7 @@ void sta_info_free(struct sta_info *sta) conf.alg = ALG_NONE; conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; local->ops->set_key(local_to_hw(local), DISABLE_KEY, - sta->addr, &conf, - local->default_wep_only); + sta->addr, &conf); sta->key_idx_compression = HW_KEY_IDX_INVALID; } From 3aefaa3294193c931b20a574f718efee6baf27d4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1151/2804] [MAC80211]: remove fake set_key() call Remove adding a fake key with a NONE key algorithm for each associated STA. If we have hardware with such TX filtering we should probably extend the sta_table_notification() callback with the sta information instead; the fact that it's treated as a key for some atheros hardware shouldn't bother the stack. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/debugfs_sta.c | 1 - net/mac80211/sta_info.c | 18 ------------------ net/mac80211/sta_info.h | 4 ---- net/mac80211/tx.c | 5 +---- 4 files changed, 1 insertion(+), 27 deletions(-) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index da34ea70276f..2daaa802bbd0 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -60,7 +60,6 @@ static const struct file_operations sta_ ##name## _ops = { \ STA_OPS(name) STA_FILE(aid, aid, D); -STA_FILE(key_idx_compression, key_idx_compression, D); STA_FILE(dev, dev->name, S); STA_FILE(vlan_id, vlan_id, D); STA_FILE(rx_packets, rx_packets, LU); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a1f766fcf966..fba2d79e4d2b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -165,7 +165,6 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, local->ops->sta_table_notification(local_to_hw(local), local->num_sta); write_unlock_bh(&local->sta_lock); - sta->key_idx_compression = HW_KEY_IDX_INVALID; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n", @@ -226,23 +225,6 @@ void sta_info_free(struct sta_info *sta) dev_kfree_skb(skb); } - if (sta->key) { - if (local->ops->set_key) { - local->ops->set_key(local_to_hw(local), - DISABLE_KEY, sta->addr, - &sta->key->conf); - } - } else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) { - struct ieee80211_key_conf conf; - memset(&conf, 0, sizeof(conf)); - conf.hw_key_idx = sta->key_idx_compression; - conf.alg = ALG_NONE; - conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - local->ops->set_key(local_to_hw(local), DISABLE_KEY, - sta->addr, &conf); - sta->key_idx_compression = HW_KEY_IDX_INVALID; - } - #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", local->mdev->name, MAC_ARG(sta->addr)); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4afa7df2a180..3b0fcb255717 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -90,10 +90,6 @@ struct sta_info { int channel_use; int channel_use_raw; - int key_idx_compression; /* key table index for compression and TX - * filtering; used only if sta->key is not - * set */ - int assoc_ap; /* whether this is an AP that we are * associated with as a client */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 684f928def93..d70140cbd66a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -426,10 +426,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) static ieee80211_txrx_result ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) { - if (tx->sta) - tx->u.tx.control->key_idx = tx->sta->key_idx_compression; - else - tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; + tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) tx->key = NULL; From 11a843b7e16062389c53ba393c7913956e034eb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1152/2804] [MAC80211]: rework key handling This moves all the key handling code out from ieee80211_ioctl.c into key.c and also does the following changes including documentation updates in mac80211.h: 1) Turn off hardware acceleration for keys when the interface is down. This is necessary because otherwise monitor interfaces could be decrypting frames for other interfaces that are down at the moment. Also, it should go some way towards better suspend/resume support, in any case the routines used here could be used for that as well. Additionally, this makes the driver interface nicer, keys for a specific local MAC address are only ever present while an interface with that MAC address is enabled. 2) Change driver set_key() callback interface to allow only return values of -ENOSPC, -EOPNOTSUPP and 0, warn on all other return values. This allows debugging the stack when a driver notices it's handed a key while it is down. 3) Invert the flag meaning to KEY_FLAG_UPLOADED_TO_HARDWARE. 4) Remove REMOVE_ALL_KEYS command as it isn't used nor do we want to use it, we'll use DISABLE_KEY for each key. It is hard to use REMOVE_ALL_KEYS because we can handle multiple virtual interfaces with different key configuration, so we'd have to keep track of a lot of state for this and that isn't worth it. 5) Warn when disabling a key fails, it musn't. 6) Remove IEEE80211_HW_NO_TKIP_WMM_HWACCEL in favour of per-key IEEE80211_KEY_FLAG_WMM_STA to let driver sort it out itself. 7) Tell driver that a (non-WEP) key is used only for transmission by using an all-zeroes station MAC address when configuring. 8) Change the set_key() callback to have access to the local MAC address the key is being added for. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 59 ++++++-- net/mac80211/debugfs_key.c | 4 +- net/mac80211/ieee80211.c | 6 +- net/mac80211/ieee80211_i.h | 8 +- net/mac80211/ieee80211_iface.c | 21 +-- net/mac80211/ieee80211_ioctl.c | 177 ++---------------------- net/mac80211/ieee80211_key.h | 26 ++++ net/mac80211/key.c | 243 ++++++++++++++++++++++++++++++++- net/mac80211/rx.c | 7 +- net/mac80211/sta_info.c | 10 +- net/mac80211/tx.c | 4 +- net/mac80211/wpa.c | 30 ++-- 12 files changed, 366 insertions(+), 229 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3437fa16eea5..ec8c7393956b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -399,19 +399,34 @@ typedef enum { ALG_CCMP, } ieee80211_key_alg; +/* + * This flag indiciates that the station this key is being + * configured for may use QoS. If your hardware cannot handle + * that situation it should reject that key. + */ +#define IEEE80211_KEY_FLAG_WMM_STA (1<<0) + struct ieee80211_key_conf { - /* shall be changed by the driver to anything but HW_KEY_IDX_INVALID */ + /* + * To be set by the driver to the key index it would like to + * get in the ieee80211_tx_control.key_idx which defaults + * to HW_KEY_IDX_INVALID so that shouldn't be used. + */ int hw_key_idx; + /* key algorithm, ALG_NONE should never be seen by the driver */ ieee80211_key_alg alg; - int keylen; + /* key flags, see above */ + u8 flags; -#define IEEE80211_KEY_FORCE_SW_ENCRYPT (1<<0) /* to be cleared by low-level - driver */ - u32 flags; /* key configuration flags defined above */ + /* key index: 0-3 */ + s8 keyidx; - s8 keyidx; /* WEP key index */ + /* length of key material */ + u8 keylen; + + /* the key material */ u8 key[0]; }; @@ -419,7 +434,7 @@ struct ieee80211_key_conf { #define IEEE80211_SEQ_COUNTER_TX 1 typedef enum { - SET_KEY, DISABLE_KEY, REMOVE_ALL_KEYS, + SET_KEY, DISABLE_KEY, } set_key_cmd; /* This is driver-visible part of the per-hw state the stack keeps. */ @@ -492,8 +507,7 @@ struct ieee80211_hw { /* hole at 6 */ - /* Force software encryption for TKIP packets if WMM is enabled. */ -#define IEEE80211_HW_NO_TKIP_WMM_HWACCEL (1<<7) +/* hole at 7 */ /* * Some devices handle Michael MIC internally and do not include MIC in @@ -627,12 +641,31 @@ struct ieee80211_ops { * * This is called to enable hardware acceleration of encryption and * decryption. The address will be the broadcast address for default - * keys and the other station's hardware address for individual keys. + * keys, the other station's hardware address for individual keys or + * the zero address for keys that will be used only for transmission. + * + * The local_address parameter will always be set to our own address, + * this is only relevant if you support multiple local addresses. + * * When transmitting, the TX control data will use the hw_key_idx * selected by the low-level driver. + * + * Return 0 if the key is now in use, -EOPNOTSUPP or -ENOSPC if it + * couldn't be added; if you return 0 then hw_key_idx must be + * assigned to something other than HW_KEY_IDX_INVALID. When the cmd + * is DISABLE_KEY then it must succeed. + * + * This callback can sleep, and is only called between add_interface + * and remove_interface calls, i.e. while the interface with the + * given local_address is enabled. + * + * The ieee80211_key_conf structure pointed to by the key parameter + * is guaranteed to be valid until another call to set_key removes + * it, but it can only be used as a cookie to differentiate keys. */ int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, - u8 *address, struct ieee80211_key_conf *key); + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key); /* * Set TX key index for default/broadcast keys. This is needed in cases @@ -640,6 +673,10 @@ struct ieee80211_ops { * is not set), in other cases, this function pointer can be set to * NULL since the IEEE 802.11 module takes care of selecting the key * index for each TX frame. + * + * TODO: If you use this callback in your driver tell us if you need + * any other information from it to make it easier, like the + * key_conf instead. */ int (*set_key_idx)(struct ieee80211_hw *hw, int idx); diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 246938c32d4d..36e7812da556 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -25,6 +25,7 @@ static ssize_t key_##name##_read(struct file *file, \ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ } #define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n") +#define KEY_READ_X(name) KEY_READ(name, name, 20, "0x%x\n") #define KEY_OPS(name) \ static const struct file_operations key_ ##name## _ops = { \ @@ -39,7 +40,6 @@ static const struct file_operations key_ ##name## _ops = { \ #define KEY_CONF_READ(name, buflen, format_string) \ KEY_READ(conf_##name, conf.name, buflen, format_string) #define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n") -#define KEY_CONF_READ_X(name) KEY_CONF_READ(name, 20, "0x%x\n") #define KEY_CONF_OPS(name) \ static const struct file_operations key_ ##name## _ops = { \ @@ -54,7 +54,7 @@ static const struct file_operations key_ ##name## _ops = { \ KEY_CONF_FILE(keylen, D); KEY_CONF_FILE(keyidx, D); KEY_CONF_FILE(hw_key_idx, D); -KEY_CONF_FILE(flags, X); +KEY_FILE(flags, X); KEY_FILE(tx_rx_count, D); static ssize_t key_algorithm_read(struct file *file, diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 5d5034f36fde..73e314e33de2 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -442,6 +442,7 @@ static int ieee80211_open(struct net_device *dev) } else { ieee80211_if_config(dev); ieee80211_reset_erp_info(dev); + ieee80211_enable_keys(sdata); } if (sdata->type == IEEE80211_IF_TYPE_STA && @@ -510,6 +511,9 @@ static int ieee80211_stop(struct net_device *dev) local->monitors--; if (!local->monitors) local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; + } else { + /* disable all keys for as long as this netdev is down */ + ieee80211_disable_keys(sdata); } local->open_count--; @@ -908,7 +912,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, } if (skb->len >= mic_len && - (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) + !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) skb_trim(skb, skb->len - mic_len); if (skb->len >= iv_len && skb->len > hdrlen) { memmove(skb->data + iv_len, skb->data, hdrlen); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7b5cc146c81b..0149f9055918 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -291,6 +291,9 @@ struct ieee80211_sub_if_data { struct wireless_dev wdev; + /* keys */ + struct list_head key_list; + struct net_device *dev; struct ieee80211_local *local; @@ -810,11 +813,6 @@ 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); int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); -/* key handling */ -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - int idx, size_t key_len, gfp_t flags); -void ieee80211_key_free(struct ieee80211_key *key); - /* utility functions/constants */ extern void *mac80211_wiphy_privid; /* for wiphy privid */ extern const unsigned char rfc1042_header[6]; diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 8bb85f194385..f9c74bb09d31 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -25,6 +25,8 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) sdata->eapol = 1; for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) skb_queue_head_init(&sdata->fragments[i].skb_list); + + INIT_LIST_HEAD(&sdata->key_list); } static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) @@ -210,25 +212,12 @@ void ieee80211_if_reinit(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; - int i; ASSERT_RTNL(); + + ieee80211_free_keys(sdata); + ieee80211_if_sdata_deinit(sdata); - for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (!sdata->keys[i]) - continue; -#if 0 - /* The interface is down at the moment, so there is not - * really much point in disabling the keys at this point. */ - memset(addr, 0xff, ETH_ALEN); - if (local->ops->set_key) - local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr, - local->keys[i], - local->default_wep_only); -#endif - ieee80211_key_free(sdata->keys[i]); - sdata->keys[i] = NULL; - } switch (sdata->type) { case IEEE80211_IF_TYPE_AP: { diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index dc05bc66fbb8..8296e7de12c7 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -25,28 +25,6 @@ #include "ieee80211_rate.h" #include "wpa.h" #include "aes_ccm.h" -#include "debugfs_key.h" - -static void ieee80211_set_hw_encryption(struct net_device *dev, - struct sta_info *sta, u8 addr[ETH_ALEN], - struct ieee80211_key *key) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - /* default to sw encryption; this will be cleared by low-level - * driver if the hw supports requested encryption */ - if (key) - key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - - if (key && local->ops->set_key) { - if (local->ops->set_key(local_to_hw(local), SET_KEY, addr, - &key->conf)) { - key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - key->conf.hw_key_idx = HW_KEY_IDX_INVALID; - } - } -} - static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, int idx, int alg, int set_tx_key, @@ -55,8 +33,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int ret = 0; struct sta_info *sta; - struct ieee80211_key *key, *old_key; - int try_hwaccel = 1; + struct ieee80211_key *key; struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -69,16 +46,6 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, return -EINVAL; } key = sdata->keys[idx]; - - /* TODO: consider adding hwaccel support for these; at least - * Atheros key cache should be able to handle this since AP is - * only transmitting frames with default keys. */ - /* FIX: hw key cache can be used when only one virtual - * STA is associated with each AP. If more than one STA - * is associated to the same AP, software encryption - * must be used. This should be done automatically - * based on configured station devices. For the time - * being, this can be only set at compile time. */ } else { set_tx_key = 0; if (idx != 0) { @@ -101,139 +68,28 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, key = sta->key; } - /* FIX: - * Cannot configure default hwaccel keys with WEP algorithm, if - * any of the virtual interfaces is using static WEP - * configuration because hwaccel would otherwise try to decrypt - * these frames. - * - * For now, just disable WEP hwaccel for broadcast when there is - * possibility of conflict with default keys. This can maybe later be - * optimized by using non-default keys (at least with Atheros ar521x). - */ - if (!sta && alg == ALG_WEP && - sdata->type != IEEE80211_IF_TYPE_IBSS && - sdata->type != IEEE80211_IF_TYPE_AP) { - try_hwaccel = 0; - } - - if (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) { - /* Software encryption cannot be used with devices that hide - * encryption from the host system, so always try to use - * hardware acceleration with such devices. */ - try_hwaccel = 1; - } - - if ((local->hw.flags & IEEE80211_HW_NO_TKIP_WMM_HWACCEL) && - alg == ALG_TKIP) { - if (sta && (sta->flags & WLAN_STA_WME)) { - /* Hardware does not support hwaccel with TKIP when using WMM. - */ - try_hwaccel = 0; - } - else if (sdata->type == IEEE80211_IF_TYPE_STA) { - sta = sta_info_get(local, sdata->u.sta.bssid); - if (sta) { - if (sta->flags & WLAN_STA_WME) { - try_hwaccel = 0; - } - sta_info_put(sta); - sta = NULL; - } - } - } - if (alg == ALG_NONE) { - if (try_hwaccel && key && - key->conf.hw_key_idx != HW_KEY_IDX_INVALID && - local->ops->set_key && - local->ops->set_key(local_to_hw(local), DISABLE_KEY, - sta_addr, &key->conf)) { - printk(KERN_DEBUG "%s: set_encrypt - low-level disable" - " failed\n", dev->name); - ret = -EINVAL; - } - - if (set_tx_key || sdata->default_key == key) { - ieee80211_debugfs_key_remove_default(sdata); - sdata->default_key = NULL; - } - ieee80211_debugfs_key_remove(key); - if (sta) - sta->key = NULL; - else - sdata->keys[idx] = NULL; ieee80211_key_free(key); key = NULL; } else { - old_key = key; - key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len, - GFP_KERNEL); + /* + * Need to free it before allocating a new one with + * with the same index or the ordering to the driver's + * set_key() callback becomes confused. + */ + ieee80211_key_free(key); + key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key); if (!key) { ret = -ENOMEM; goto err_out; } - - /* default to sw encryption; low-level driver sets these if the - * requested encryption is supported */ - key->conf.hw_key_idx = HW_KEY_IDX_INVALID; - key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - - key->conf.alg = alg; - key->conf.keyidx = idx; - key->conf.keylen = key_len; - memcpy(key->conf.key, _key, key_len); - - if (alg == ALG_CCMP) { - /* Initialize AES key state here as an optimization - * so that it does not need to be initialized for every - * packet. */ - key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt( - key->conf.key); - if (!key->u.ccmp.tfm) { - ret = -ENOMEM; - goto err_free; - } - } - - if (set_tx_key || sdata->default_key == old_key) { - ieee80211_debugfs_key_remove_default(sdata); - sdata->default_key = NULL; - } - ieee80211_debugfs_key_remove(old_key); - if (sta) - sta->key = key; - else - sdata->keys[idx] = key; - ieee80211_key_free(old_key); - ieee80211_debugfs_key_add(local, key); - if (sta) - ieee80211_debugfs_key_sta_link(key, sta); - - if (try_hwaccel && - (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) - ieee80211_set_hw_encryption(dev, sta, sta_addr, key); } - if (set_tx_key || (!sta && !sdata->default_key && key)) { - sdata->default_key = key; - if (key) - ieee80211_debugfs_key_add_default(sdata); + if (set_tx_key || (!sta && !sdata->default_key && key)) + ieee80211_set_default_key(sdata, idx); - if (local->ops->set_key_idx && - local->ops->set_key_idx(local_to_hw(local), idx)) - printk(KERN_DEBUG "%s: failed to set TX key idx for " - "low-level driver\n", dev->name); - } - - if (sta) - sta_info_put(sta); - - return 0; - -err_free: - ieee80211_key_free(key); -err_out: + ret = 0; + err_out: if (sta) sta_info_put(sta); return ret; @@ -1181,12 +1037,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, alg = ALG_NONE; else if (erq->length == 0) { /* No key data - just set the default TX key index */ - if (sdata->default_key != sdata->keys[idx]) { - ieee80211_debugfs_key_remove_default(sdata); - sdata->default_key = sdata->keys[idx]; - if (sdata->default_key) - ieee80211_debugfs_key_add_default(sdata); - } + ieee80211_set_default_key(sdata, idx); return 0; } @@ -1232,7 +1083,7 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev, } memcpy(key, sdata->keys[idx]->conf.key, - min((int)erq->length, sdata->keys[idx]->conf.keylen)); + min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); erq->length = sdata->keys[idx]->conf.keylen; erq->flags |= IW_ENCODE_ENABLED; diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index 58e192530826..a4e5fbbe045c 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -41,7 +41,21 @@ #define NUM_RX_DATA_QUEUES 17 +struct ieee80211_local; +struct ieee80211_sub_if_data; +struct sta_info; + +#define KEY_FLAG_UPLOADED_TO_HARDWARE (1<<0) + struct ieee80211_key { + struct ieee80211_local *local; + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + + struct list_head list; + + unsigned int flags; + union { struct { /* last used TSC */ @@ -97,4 +111,16 @@ struct ieee80211_key { struct ieee80211_key_conf conf; }; +struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + ieee80211_key_alg alg, + int idx, + size_t key_len, + const u8 *key_data); +void ieee80211_key_free(struct ieee80211_key *key); +void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); +void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); +void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); +void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); + #endif /* IEEE80211_KEY_H */ diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 843d1577f00f..178f00cf61b9 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -2,25 +2,198 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc + * Copyright 2007 Johannes Berg * * 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 "ieee80211_i.h" #include "debugfs_key.h" #include "aes_ccm.h" + +/* + * Key handling basics + * + * Key handling in mac80211 is done based on per-interface (sub_if_data) + * keys and per-station keys. Since each station belongs to an interface, + * each station key also belongs to that interface. + * + * Hardware acceleration is done on a best-effort basis, for each key + * that is eligible the hardware is asked to enable that key but if + * it cannot do that they key is simply kept for software encryption. + * There is currently no way of knowing this except by looking into + * debugfs. + * + * All operations here are called under RTNL so no extra locking is + * required. + */ + +static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 zero_addr[ETH_ALEN]; + +static const u8 *get_mac_for_key(struct ieee80211_key *key) +{ + const u8 *addr = bcast_addr; + + /* + * If we're an AP we won't ever receive frames with a non-WEP + * group key so we tell the driver that by using the zero MAC + * address to indicate a transmit-only key. + */ + if (key->conf.alg != ALG_WEP && + (key->sdata->type == IEEE80211_IF_TYPE_AP || + key->sdata->type == IEEE80211_IF_TYPE_VLAN)) + addr = zero_addr; + + if (key->sta) + addr = key->sta->addr; + + return addr; +} + +static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) +{ + const u8 *addr; + int ret; + + if (!key->local->ops->set_key) + return; + + addr = get_mac_for_key(key); + + ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, + key->sdata->dev->dev_addr, addr, + &key->conf); + + WARN_ON(!ret && (key->conf.hw_key_idx == HW_KEY_IDX_INVALID)); + + if (!ret) + key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) + printk(KERN_ERR "mac80211-%s: failed to set key " + "(%d, " MAC_FMT ") to hardware (%d)\n", + wiphy_name(key->local->hw.wiphy), + key->conf.keyidx, MAC_ARG(addr), ret); +} + +static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) +{ + const u8 *addr; + int ret; + + if (!key->local->ops->set_key) + return; + + if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + return; + + addr = get_mac_for_key(key); + + ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY, + key->sdata->dev->dev_addr, addr, + &key->conf); + + if (ret) + printk(KERN_ERR "mac80211-%s: failed to remove key " + "(%d, " MAC_FMT ") from hardware (%d)\n", + wiphy_name(key->local->hw.wiphy), + key->conf.keyidx, MAC_ARG(addr), ret); + + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + key->conf.hw_key_idx = HW_KEY_IDX_INVALID; +} + struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - int idx, size_t key_len, gfp_t flags) + struct sta_info *sta, + ieee80211_key_alg alg, + int idx, + size_t key_len, + const u8 *key_data) { struct ieee80211_key *key; - key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags); + BUG_ON(alg == ALG_NONE); + + key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); if (!key) return NULL; + + /* + * Default to software encryption; we'll later upload the + * key to the hardware if possible. + */ + key->conf.hw_key_idx = HW_KEY_IDX_INVALID; + key->conf.flags = 0; + key->flags = 0; + + key->conf.alg = alg; + key->conf.keyidx = idx; + key->conf.keylen = key_len; + memcpy(key->conf.key, key_data, key_len); + + key->local = sdata->local; + key->sdata = sdata; + key->sta = sta; + + if (alg == ALG_CCMP) { + /* + * Initialize AES key state here as an optimization so that + * it does not need to be initialized for every packet. + */ + key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); + if (!key->u.ccmp.tfm) { + ieee80211_key_free(key); + return NULL; + } + } + + ieee80211_debugfs_key_add(key->local, key); + + if (sta) { + ieee80211_debugfs_key_sta_link(key, sta); + sta->key = key; + /* + * some hardware cannot handle TKIP with QoS, so + * we indicate whether QoS could be in use. + */ + if (sta->flags & WLAN_STA_WME) + key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; + } else { + if (sdata->type == IEEE80211_IF_TYPE_STA) { + struct sta_info *ap; + + /* same here, the AP could be using QoS */ + ap = sta_info_get(key->local, key->sdata->u.sta.bssid); + if (ap) { + if (ap->flags & WLAN_STA_WME) + key->conf.flags |= + IEEE80211_KEY_FLAG_WMM_STA; + sta_info_put(ap); + } + } + + if (idx >= 0 && idx < NUM_DEFAULT_KEYS) { + if (!sdata->keys[idx]) + sdata->keys[idx] = key; + else + WARN_ON(1); + } else + WARN_ON(1); + } + + list_add(&key->list, &sdata->key_list); + + if (netif_running(key->sdata->dev)) + ieee80211_key_enable_hw_accel(key); + return key; } @@ -29,8 +202,74 @@ void ieee80211_key_free(struct ieee80211_key *key) if (!key) return; + ieee80211_key_disable_hw_accel(key); + + if (key->sta) { + key->sta->key = NULL; + } else { + if (key->sdata->default_key == key) + ieee80211_set_default_key(key->sdata, -1); + if (key->conf.keyidx >= 0 && + key->conf.keyidx < NUM_DEFAULT_KEYS) + key->sdata->keys[key->conf.keyidx] = NULL; + else + WARN_ON(1); + } + if (key->conf.alg == ALG_CCMP) ieee80211_aes_key_free(key->u.ccmp.tfm); ieee80211_debugfs_key_remove(key); + + list_del(&key->list); + kfree(key); } + +void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) +{ + struct ieee80211_key *key = NULL; + + if (idx >= 0 && idx < NUM_DEFAULT_KEYS) + key = sdata->keys[idx]; + + if (sdata->default_key != key) { + ieee80211_debugfs_key_remove_default(sdata); + + sdata->default_key = key; + + if (sdata->default_key) + ieee80211_debugfs_key_add_default(sdata); + + if (sdata->local->ops->set_key_idx) + sdata->local->ops->set_key_idx( + local_to_hw(sdata->local), idx); + } +} + +void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_key *key, *tmp; + + list_for_each_entry_safe(key, tmp, &sdata->key_list, list) + ieee80211_key_free(key); +} + +void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_key *key; + + WARN_ON(!netif_running(sdata->dev)); + if (!netif_running(sdata->dev)) + return; + + list_for_each_entry(key, &sdata->key_list, list) + ieee80211_key_enable_hw_accel(key); +} + +void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_key *key; + + list_for_each_entry(key, &sdata->key_list, list) + ieee80211_key_disable_hw_accel(key); +} diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 976b646a40de..ba94f58ba02e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -528,7 +528,7 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) /* Check for weak IVs, if hwaccel did not remove IV from the frame */ if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) || - (rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) + !(rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) if (ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; @@ -553,7 +553,7 @@ ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) } if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || - (rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { + !(rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " @@ -897,8 +897,7 @@ ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) * uploaded to the hardware. */ if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) && - (!rx->key || - !(rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT))) + (!rx->key || (rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))) return TXRX_CONTINUE; /* Drop unencrypted frames if key is set. */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index fba2d79e4d2b..c17172abb21c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -19,7 +19,6 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "sta_info.h" -#include "debugfs_key.h" #include "debugfs_sta.h" /* Caller must hold local->sta_lock */ @@ -118,8 +117,6 @@ static void sta_info_release(struct kref *kref) } rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_put(sta->rate_ctrl); - if (sta->key) - ieee80211_debugfs_key_sta_del(sta->key, sta); kfree(sta); } @@ -230,11 +227,8 @@ void sta_info_free(struct sta_info *sta) local->mdev->name, MAC_ARG(sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - if (sta->key) { - ieee80211_debugfs_key_remove(sta->key); - ieee80211_key_free(sta->key); - sta->key = NULL; - } + ieee80211_key_free(sta->key); + sta->key = NULL; rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d70140cbd66a..b65ff6536244 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -536,7 +536,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) { - if (tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) { + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { @@ -832,7 +832,7 @@ __ieee80211_parse_tx_radiotap( */ control->retry_limit = 1; /* no retry */ - control->key_idx = -1; /* no encryption key */ + control->key_idx = HW_KEY_IDX_INVALID; control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | IEEE80211_TXCTL_USE_CTS_PROTECT); control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT | diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 4a2a9aa638b3..b6cd66e0ee58 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -89,7 +89,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)) return TXRX_DROP; - if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) && + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) && !wpa_test) { @@ -146,7 +146,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !(rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { + (rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { if (skb->len < MICHAEL_MIC_LEN) return TXRX_DROP; @@ -205,10 +205,10 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; - if (tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) - tailneed = TKIP_ICV_LEN; - else + if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) tailneed = 0; + else + tailneed = TKIP_ICV_LEN; if ((skb_headroom(skb) < TKIP_IV_LEN || skb_tailroom(skb) < tailneed)) { @@ -227,7 +227,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, if (key->u.tkip.iv16 == 0) key->u.tkip.iv32++; - if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { + if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { u32 flags = tx->local->hw.flags; hdr = (struct ieee80211_hdr *)skb->data; @@ -286,7 +286,7 @@ ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx) tx->u.tx.control->iv_len = TKIP_IV_LEN; ieee80211_tx_set_iswep(tx); - if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) && + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ @@ -331,7 +331,7 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { + (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { /* Hardware takes care of all processing, including * replay protection, so no need to continue here. */ @@ -475,10 +475,10 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; - if (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) - tailneed = CCMP_MIC_LEN; - else + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) tailneed = 0; + else + tailneed = CCMP_MIC_LEN; if ((skb_headroom(skb) < CCMP_HDR_LEN || skb_tailroom(skb) < tailneed)) { @@ -504,7 +504,7 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, ccmp_pn2hdr(pos, pn, key->conf.keyidx); - if (!(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { /* hwaccel - with preallocated room for CCMP header */ tx->u.tx.control->key_idx = key->conf.hw_key_idx; return 0; @@ -537,7 +537,7 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) tx->u.tx.control->iv_len = CCMP_HDR_LEN; ieee80211_tx_set_iswep(tx); - if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) && + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ @@ -586,7 +586,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) && + (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) return TXRX_CONTINUE; @@ -607,7 +607,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) } if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) { + (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { /* hwaccel has already decrypted frame and verified MIC */ } else { u8 *scratch, *b_0, *aad; From e7a64f12a452d39ab50e5580e93bc48b3b15f30c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1153/2804] [MAC80211]: add interface index to key debugfs Add a new file 'ifindex' to each key's debugfs dir to allow finding which interface the key was configured on. This isn't done as a symlink because of possible netdev name changes. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/debugfs_key.c | 4 ++++ net/mac80211/ieee80211_key.h | 1 + 2 files changed, 5 insertions(+) diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 36e7812da556..8e4a1bcd16ea 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -56,6 +56,8 @@ KEY_CONF_FILE(keyidx, D); KEY_CONF_FILE(hw_key_idx, D); KEY_FILE(flags, X); KEY_FILE(tx_rx_count, D); +KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n"); +KEY_OPS(ifindex); static ssize_t key_algorithm_read(struct file *file, char __user *userbuf, @@ -209,6 +211,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_local *local, DEBUGFS_ADD(rx_spec); DEBUGFS_ADD(replays); DEBUGFS_ADD(key); + DEBUGFS_ADD(ifindex); }; #define DEBUGFS_DEL(name) \ @@ -229,6 +232,7 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key) DEBUGFS_DEL(rx_spec); DEBUGFS_DEL(replays); DEBUGFS_DEL(key); + DEBUGFS_DEL(ifindex); debugfs_remove(key->debugfs.stalink); key->debugfs.stalink = NULL; diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index a4e5fbbe045c..ae49418f18b4 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -101,6 +101,7 @@ struct ieee80211_key { struct dentry *rx_spec; struct dentry *replays; struct dentry *key; + struct dentry *ifindex; } debugfs; #endif From 6c55aa97359af4b503a8baf914de48f2406a895f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1154/2804] [MAC80211]: Remove overly sticky averaging filters for rssi, signal, noise The current version of wireless statistics contains a bug in the averaging that makes the numbers be too sticky and not react to small changes. This patch removes all averaging. Signed-off-by: Larry Finger Signed-off-by: Jiri Benc Signed-off-by: John W. Linville Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/rx.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ba94f58ba02e..e2c6f5cd1cf7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -485,12 +485,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; - sta->last_rssi = (sta->last_rssi * 15 + - rx->u.rx.status->ssi) / 16; - sta->last_signal = (sta->last_signal * 15 + - rx->u.rx.status->signal) / 16; - sta->last_noise = (sta->last_noise * 15 + - rx->u.rx.status->noise) / 16; + sta->last_rssi = rx->u.rx.status->ssi; + sta->last_signal = rx->u.rx.status->signal; + sta->last_noise = rx->u.rx.status->noise; if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { /* Change STA power saving mode only in the end of a frame From b63bde7bb75f74acf974f43dc2be8798be115007 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1155/2804] [MAC80211]: fix preamble setting It looks like in commit 28487a90 the condition was unintentionally negated by moving some code, fix it. Signed-off-by: Johannes Berg Cc: Daniel Drake Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 8296e7de12c7..d48f3aa30e30 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -821,7 +821,7 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_PREAMBLE: - if (sdata->type != IEEE80211_IF_TYPE_AP) { + if (sdata->type == IEEE80211_IF_TYPE_AP) { if (value) sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE; else From 3c3b00caf98e5fdaa0184026a68f0008a5bf393e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1156/2804] [MAC80211]: clean up whitespace This cleans up some whitespace to make the mac80211 version in mainline diverge less from wireless-dev. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_ioctl.c | 1 + net/mac80211/ieee80211_sta.c | 1 - net/mac80211/wme.c | 7 +++---- net/mac80211/wpa.c | 1 - 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index d48f3aa30e30..383ad5f64c1f 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -968,6 +968,7 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, *param = !!(sdata->u.sta.flags & IEEE80211_STA_MIXED_CELL); break; + case PRISM2_PARAM_WMM_ENABLED: if (sdata->type != IEEE80211_IF_TYPE_STA && sdata->type != IEEE80211_IF_TYPE_IBSS) diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index a2443271629a..f98b2e1cedf3 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -234,7 +234,6 @@ static int ecw2cw(int ecw) return cw - 1; } - static void ieee80211_sta_wmm_params(struct net_device *dev, struct ieee80211_if_sta *ifsta, u8 *wmm_param, size_t wmm_param_len) diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index d303229249e7..fcc8921722f4 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -125,14 +125,13 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) } /* use the data classifier to determine what 802.1d tag the - * data frame has */ + * data frame has */ skb->priority = classify_1d(skb, qd); - /* incase we are a client verify acm is not set for this ac */ + /* in case we are a client verify acm is not set for this ac */ while (unlikely(local->wmm_acm & BIT(skb->priority))) { if (wme_downgrade_ac(skb)) { - /* No AC with lower priority has acm=0, - * drop packet. */ + /* No AC with lower priority has acm=0, drop packet. */ return -1; } } diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index b6cd66e0ee58..775f89e42a43 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -550,7 +550,6 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) if (tx->u.tx.extra_frag) { int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) < 0) From b331615722779b078822988843ddffd4eaec9f83 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1157/2804] [MAC80211]: filter locally-originated multicast frames In STA mode, the AP will echo our traffic. This includes multicast traffic. Receiving these frames confuses some protocols and applications, notably IPv6 Duplicate Address Detection. Signed-off-by: John W. Linville Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/rx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e2c6f5cd1cf7..969be3adda7a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -988,9 +988,10 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) memcpy(dst, hdr->addr1, ETH_ALEN); memcpy(src, hdr->addr3, ETH_ALEN); - if (sdata->type != IEEE80211_IF_TYPE_STA) { + if (sdata->type != IEEE80211_IF_TYPE_STA || + (is_multicast_ether_addr(dst) && + !compare_ether_addr(src, dev->dev_addr))) return TXRX_DROP; - } break; case 0: /* DA SA BSSID */ From 8dc06a1c6112fef7616d26e0b001455b5d8c3c5e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1158/2804] [MAC80211]: improve key selection comment When I changed the code there I forgot to mention what happens with multicast frames in a regular BSS and keep wondering myself if the code is correct. Add appropriate comments. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/rx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 969be3adda7a..75a1e204b9b6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -327,8 +327,15 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) * frames can also use key indizes like GTKs. Hence, if we don't * have a PTK/STK we check the key index for a WEP key. * + * Note that in a regular BSS, multicast frames are sent by the + * AP only, associated stations unicast the frame to the AP first + * which then multicasts it on their behalf. + * * There is also a slight problem in IBSS mode: GTKs are negotiated * with each station, that is something we don't currently handle. + * The spec seems to expect that one negotiates the same key with + * every station but there's no such requirement; VLANs could be + * possible. */ if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) From 52aa944a182545a987dc753f9602235a3359df0c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1159/2804] [MAC80211]: remove hostapd interface stuff This removes some definitions that are used only within ioctls that will never make it into mainline. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/hostapd_ioctl.h | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h index d43711aff4c5..ac812ec9fa2f 100644 --- a/net/mac80211/hostapd_ioctl.h +++ b/net/mac80211/hostapd_ioctl.h @@ -59,26 +59,4 @@ struct ieee80211_rate_data { int flags; /* IEEE80211_RATE_ flags */ }; - -/* ADD_IF, REMOVE_IF, and UPDATE_IF 'type' argument */ -enum { - HOSTAP_IF_WDS = 1, HOSTAP_IF_VLAN = 2, HOSTAP_IF_BSS = 3, - HOSTAP_IF_STA = 4 -}; - -struct hostapd_if_wds { - u8 remote_addr[ETH_ALEN]; -}; - -struct hostapd_if_vlan { - u8 id; -}; - -struct hostapd_if_bss { - u8 bssid[ETH_ALEN]; -}; - -struct hostapd_if_sta { -}; - #endif /* HOSTAPD_IOCTL_H */ From c9ee23dfac61a713de48b20999dcacb7ef3c5ed0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Aug 2007 17:01:55 -0400 Subject: [PATCH 1160/2804] [MAC80211]: make assoc_ap a flag The sta_info.assoc_ap value is used as a flag, move it into flags. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_sta.c | 3 +-- net/mac80211/rx.c | 2 +- net/mac80211/sta_info.h | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index f98b2e1cedf3..1b4ebe81191c 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1279,8 +1279,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, } sta->dev = dev; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->assoc_ap = 1; + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP; rates = 0; mode = local->oper_hw_mode; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 75a1e204b9b6..4fb8c7026f11 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1398,7 +1398,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, skb = rx.skb; skb_push(skb, radiotap_len); - if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) && + if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) && !local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) { rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3b0fcb255717..e3ae0f5cc228 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -26,6 +26,8 @@ * send and receive non-IEEE 802.1X frames */ #define WLAN_STA_SHORT_PREAMBLE BIT(7) +/* whether this is an AP that we are associated with as a client */ +#define WLAN_STA_ASSOC_AP BIT(8) #define WLAN_STA_WME BIT(9) #define WLAN_STA_WDS BIT(27) @@ -90,9 +92,6 @@ struct sta_info { int channel_use; int channel_use_raw; - int assoc_ap; /* whether this is an AP that we are - * associated with as a client */ - #ifdef CONFIG_MAC80211_DEBUG_COUNTERS unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; From 1dfcae776548f464bee793d06484be275ba8efe7 Mon Sep 17 00:00:00 2001 From: Micah Gruber Date: Wed, 5 Sep 2007 07:56:50 -0700 Subject: [PATCH 1161/2804] [IPV6]: Remove unneeded pointer iph from ipcomp6_input() in net/ipv6/ipcomp6.c This trivial patch removes the unneeded pointer iph, which is never used. Signed-off-by: Micah Gruber Signed-off-by: David S. Miller --- net/ipv6/ipcomp6.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 473f165310ea..91b2a75b7d09 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -65,7 +65,6 @@ static LIST_HEAD(ipcomp6_tfms_list); static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) { int err = -ENOMEM; - struct ipv6hdr *iph; struct ipv6_comp_hdr *ipch; int plen, dlen; struct ipcomp_data *ipcd = x->data; @@ -79,7 +78,6 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) skb->ip_summed = CHECKSUM_NONE; /* Remove ipcomp header and decompress original payload */ - iph = ipv6_hdr(skb); ipch = (void *)skb->data; skb->transport_header = skb->network_header + sizeof(*ipch); __skb_pull(skb, sizeof(*ipch)); From c7261872256f9172eb26438b96725b6f2115e955 Mon Sep 17 00:00:00 2001 From: Micah Gruber Date: Wed, 5 Sep 2007 07:58:14 -0700 Subject: [PATCH 1162/2804] [DCCP]: Remove unneeded pointer newdp from dccp_v4_request_recv_sock() This trivial patch removes the unneeded pointer newdp, which is never used. Signed-off-by: Micah Gruber Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 718f2fa923a1..2c6282815264 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -381,7 +381,6 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, { struct inet_request_sock *ireq; struct inet_sock *newinet; - struct dccp_sock *newdp; struct sock *newsk; if (sk_acceptq_is_full(sk)) @@ -396,7 +395,6 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, sk_setup_caps(newsk, dst); - newdp = dccp_sk(newsk); newinet = inet_sk(newsk); ireq = inet_rsk(req); newinet->daddr = ireq->rmt_addr; From 50f17787e9b0222ce65cc831407c3ba4790db3ff Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 6 Sep 2007 13:55:02 +0100 Subject: [PATCH 1163/2804] [AF_PACKET]: Don't enable global timestamps. Andi mentioned he did something like this already, but never submitted it. The dhcp client application uses AF_PACKET with a packet filter to receive data. The application doesn't even use timestamps, but because the AF_PACKET API has timestamps, they get turned on globally which causes an expensive time of day lookup for every packet received on any system that uses the standard DHCP client. The fix is to not enable the timestamp (but use if if available). This causes the time lookup to only occur on those packets that are destined for the AF_PACKET socket. The timestamping occurs after packet filtering so all packets dropped by filtering to not cause a clock call. The one downside of this a a few microseconds additional delay added from the normal timestamping location (netif_rx) until the receive callback in AF_PACKET. But since the offset is fairly consistent it should not upset applications that do want really use timestamps, like wireshark. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/packet/af_packet.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 1322d62b5d97..9c26dd9ee649 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -640,11 +640,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe h->tp_snaplen = snaplen; h->tp_mac = macoff; h->tp_net = netoff; - if (skb->tstamp.tv64 == 0) { - __net_timestamp(skb); - sock_enable_timestamp(sk); - } - tv = ktime_to_timeval(skb->tstamp); + if (skb->tstamp.tv64) + tv = ktime_to_timeval(skb->tstamp); + else + do_gettimeofday(&tv); h->tp_sec = tv.tv_sec; h->tp_usec = tv.tv_usec; From ab0049b4a2f66074dff6af851b35bba888f53972 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Thu, 6 Sep 2007 20:42:14 +0100 Subject: [PATCH 1164/2804] [TG3]: remove sparse warnings Removed sparse warnings from tg3 driver. The new logic seems fine (I don't immediately see where we are running over values for any of the variables that need to be saved). This patch compiles fine and I'm currently using a tg3 with the patched driver to post this patch as a basic proof of concept. Signed-off-by: Andy Gospodarek Signed-off-by: David S. Miller --- drivers/net/tg3.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ef1e3d1173c4..cbfa4df09592 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4870,7 +4870,6 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { - u32 val; /* Chip reset on 5780 will reset MSI enable bit, * so need to restore it. @@ -5027,7 +5026,7 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(GRC_MODE, tp->grc_mode); if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) { - u32 val = tr32(0xc4); + val = tr32(0xc4); tw32(0xc4, val | (1 << 15)); } @@ -5056,7 +5055,7 @@ static int tg3_chip_reset(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) { - u32 val = tr32(0x7c00); + val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); } @@ -7991,7 +7990,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, buf = data; if (b_offset || odd_len) { buf = kmalloc(len, GFP_KERNEL); - if (buf == 0) + if (!buf) return -ENOMEM; if (b_offset) memcpy(buf, &start, 4); @@ -8420,7 +8419,7 @@ static void tg3_get_ethtool_stats (struct net_device *dev, static int tg3_test_nvram(struct tg3 *tp) { u32 *buf, csum, magic; - int i, j, err = 0, size; + int i, j, k, err = 0, size; if (tg3_nvram_read_swab(tp, 0, &magic) != 0) return -EIO; @@ -8474,7 +8473,6 @@ static int tg3_test_nvram(struct tg3 *tp) u8 data[NVRAM_SELFBOOT_DATA_SIZE]; u8 parity[NVRAM_SELFBOOT_DATA_SIZE]; u8 *buf8 = (u8 *) buf; - int j, k; /* Separate the parity bits and the data bytes. */ for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) { @@ -10730,7 +10728,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) { u32 pm_reg; - u16 pci_cmd; tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; @@ -11876,7 +11873,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, INIT_WORK(&tp->reset_task, tg3_reset_task); tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len); - if (tp->regs == 0UL) { + if (!tp->regs) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); err = -ENOMEM; From 02b3d34631831a19ee691516e233756b270eac6d Mon Sep 17 00:00:00 2001 From: John Heffner Date: Wed, 12 Sep 2007 10:42:12 +0200 Subject: [PATCH 1165/2804] [NET] Cleanup: Use sock_owned_by_user() macro Changes asserts in sunrpc to use sock_owned_by_user() macro instead of referencing sock_lock.owner directly. Signed-off-by: John Heffner Signed-off-by: David S. Miller --- net/sunrpc/svcsock.c | 2 +- net/sunrpc/xprtsock.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 406b3e687952..c75bffeb89eb 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -104,7 +104,7 @@ static struct lock_class_key svc_slock_key[2]; static inline void svc_reclassify_socket(struct socket *sock) { struct sock *sk = sock->sk; - BUG_ON(sk->sk_lock.owner != NULL); + BUG_ON(sock_owned_by_user(sk)); switch (sk->sk_family) { case AF_INET: sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD", diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 4ae7eed7f617..282efd447a61 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1186,7 +1186,7 @@ static struct lock_class_key xs_slock_key[2]; static inline void xs_reclassify_socket(struct socket *sock) { struct sock *sk = sock->sk; - BUG_ON(sk->sk_lock.owner != NULL); + BUG_ON(sock_owned_by_user(sk)); switch (sk->sk_family) { case AF_INET: sock_lock_init_class_and_name(sk, "slock-AF_INET-NFS", From d2e9117c7aa9544d910634e17e3519fd67155229 Mon Sep 17 00:00:00 2001 From: John Heffner Date: Wed, 12 Sep 2007 10:44:19 +0200 Subject: [PATCH 1166/2804] [NET]: Change type of owner in sock_lock_t to int, rename The type of owner in sock_lock_t is currently (struct sock_iocb *), presumably for historical reasons. It is never used as this type, only tested as NULL or set to (void *)1. For clarity, this changes it to type int, and renames to owned, to avoid any possible type casting errors. Signed-off-by: John Heffner Signed-off-by: David S. Miller --- include/net/sock.h | 7 +++---- net/core/sock.c | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 802c670ba820..5ed9fa42b6e8 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -76,10 +76,9 @@ * between user contexts and software interrupt processing, whereas the * mini-semaphore synchronizes multiple users amongst themselves. */ -struct sock_iocb; typedef struct { spinlock_t slock; - struct sock_iocb *owner; + int owned; wait_queue_head_t wq; /* * We express the mutex-alike socket_lock semantics @@ -737,7 +736,7 @@ static inline int sk_stream_wmem_schedule(struct sock *sk, int size) * Since ~2.3.5 it is also exclusive sleep lock serializing * accesses from user process context. */ -#define sock_owned_by_user(sk) ((sk)->sk_lock.owner) +#define sock_owned_by_user(sk) ((sk)->sk_lock.owned) /* * Macro so as to not evaluate some arguments when @@ -748,7 +747,7 @@ static inline int sk_stream_wmem_schedule(struct sock *sk, int size) */ #define sock_lock_init_class_and_name(sk, sname, skey, name, key) \ do { \ - sk->sk_lock.owner = NULL; \ + sk->sk_lock.owned = 0; \ init_waitqueue_head(&sk->sk_lock.wq); \ spin_lock_init(&(sk)->sk_lock.slock); \ debug_check_no_locks_freed((void *)&(sk)->sk_lock, \ diff --git a/net/core/sock.c b/net/core/sock.c index 190de61cd648..beb924c248e8 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1585,9 +1585,9 @@ void fastcall lock_sock_nested(struct sock *sk, int subclass) { might_sleep(); spin_lock_bh(&sk->sk_lock.slock); - if (sk->sk_lock.owner) + if (sk->sk_lock.owned) __lock_sock(sk); - sk->sk_lock.owner = (void *)1; + sk->sk_lock.owned = 1; spin_unlock(&sk->sk_lock.slock); /* * The sk_lock has mutex_lock() semantics here: @@ -1608,7 +1608,7 @@ void fastcall release_sock(struct sock *sk) spin_lock_bh(&sk->sk_lock.slock); if (sk->sk_backlog.tail) __release_sock(sk); - sk->sk_lock.owner = NULL; + sk->sk_lock.owned = 0; if (waitqueue_active(&sk->sk_lock.wq)) wake_up(&sk->sk_lock.wq); spin_unlock_bh(&sk->sk_lock.slock); From ab5f5e8b144e4c804ef3aa1ce08a9ca9f01187ce Mon Sep 17 00:00:00 2001 From: Joy Latten Date: Mon, 17 Sep 2007 11:51:22 -0700 Subject: [PATCH 1167/2804] [XFRM]: xfrm audit calls This patch modifies the current ipsec audit layer by breaking it up into purpose driven audit calls. So far, the only audit calls made are when add/delete an SA/policy. It had been discussed to give each key manager it's own calls to do this, but I found there to be much redundnacy since they did the exact same things, except for how they got auid and sid, so I combined them. The below audit calls can be made by any key manager. Hopefully, this is ok. Signed-off-by: Joy Latten Signed-off-by: David S. Miller --- include/linux/audit.h | 9 +- include/net/xfrm.h | 40 +++++++- net/key/af_key.c | 21 ++--- net/xfrm/xfrm_policy.c | 210 +++++++++++++++-------------------------- net/xfrm/xfrm_state.c | 89 ++++++++++++++--- net/xfrm/xfrm_user.c | 26 ++--- 6 files changed, 218 insertions(+), 177 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index d6579df8dadf..9ae740936a65 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -108,10 +108,11 @@ #define AUDIT_MAC_CIPSOV4_DEL 1408 /* NetLabel: del CIPSOv4 DOI entry */ #define AUDIT_MAC_MAP_ADD 1409 /* NetLabel: add LSM domain mapping */ #define AUDIT_MAC_MAP_DEL 1410 /* NetLabel: del LSM domain mapping */ -#define AUDIT_MAC_IPSEC_ADDSA 1411 /* Add a XFRM state */ -#define AUDIT_MAC_IPSEC_DELSA 1412 /* Delete a XFRM state */ -#define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Add a XFRM policy */ -#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Delete a XFRM policy */ +#define AUDIT_MAC_IPSEC_ADDSA 1411 /* Not used */ +#define AUDIT_MAC_IPSEC_DELSA 1412 /* Not used */ +#define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Not used */ +#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */ +#define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */ #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG 1799 diff --git a/include/net/xfrm.h b/include/net/xfrm.h index a5f80bfbaaa4..760d2432be6b 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -421,15 +422,46 @@ extern unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; /* Audit Information */ struct xfrm_audit { - uid_t loginuid; + u32 loginuid; u32 secid; }; #ifdef CONFIG_AUDITSYSCALL -extern void xfrm_audit_log(uid_t auid, u32 secid, int type, int result, - struct xfrm_policy *xp, struct xfrm_state *x); +static inline struct audit_buffer *xfrm_audit_start(u32 auid, u32 sid) +{ + struct audit_buffer *audit_buf = NULL; + char *secctx; + u32 secctx_len; + + audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, + AUDIT_MAC_IPSEC_EVENT); + if (audit_buf == NULL) + return NULL; + + audit_log_format(audit_buf, "auid=%u", auid); + + if (sid != 0 && + security_secid_to_secctx(sid, &secctx, &secctx_len) == 0) { + audit_log_format(audit_buf, " subj=%s", secctx); + security_release_secctx(secctx, secctx_len); + } else + audit_log_task_context(audit_buf); + return audit_buf; +} + +extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, + u32 auid, u32 sid); +extern void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, + u32 auid, u32 sid); +extern void xfrm_audit_state_add(struct xfrm_state *x, int result, + u32 auid, u32 sid); +extern void xfrm_audit_state_delete(struct xfrm_state *x, int result, + u32 auid, u32 sid); #else -#define xfrm_audit_log(a,s,t,r,p,x) do { ; } while (0) +#define xfrm_audit_policy_add(x, r, a, s) do { ; } while (0) +#define xfrm_audit_policy_delete(x, r, a, s) do { ; } while (0) +#define xfrm_audit_state_add(x, r, a, s) do { ; } while (0) +#define xfrm_audit_state_delete(x, r, a, s) do { ; } while (0) #endif /* CONFIG_AUDITSYSCALL */ static inline void xfrm_pol_hold(struct xfrm_policy *policy) diff --git a/net/key/af_key.c b/net/key/af_key.c index 17b2a6927f01..0241fff95137 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -1454,8 +1453,8 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, else err = xfrm_state_update(x); - xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, - AUDIT_MAC_IPSEC_ADDSA, err ? 0 : 1, NULL, x); + xfrm_audit_state_add(x, err ? 0 : 1, + audit_get_loginuid(current->audit_context), 0); if (err < 0) { x->km.state = XFRM_STATE_DEAD; @@ -1508,8 +1507,8 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h c.event = XFRM_MSG_DELSA; km_state_notify(x, &c); out: - xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, - AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x); + xfrm_audit_state_delete(x, err ? 0 : 1, + audit_get_loginuid(current->audit_context), 0); xfrm_state_put(x); return err; @@ -2261,8 +2260,8 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, hdr->sadb_msg_type != SADB_X_SPDUPDATE); - xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, - AUDIT_MAC_IPSEC_ADDSPD, err ? 0 : 1, xp, NULL); + xfrm_audit_policy_add(xp, err ? 0 : 1, + audit_get_loginuid(current->audit_context), 0); if (err) goto out; @@ -2345,8 +2344,8 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg if (xp == NULL) return -ENOENT; - xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, - AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL); + xfrm_audit_policy_delete(xp, err ? 0 : 1, + audit_get_loginuid(current->audit_context), 0); if (err) goto out; @@ -2606,8 +2605,8 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h return -ENOENT; if (delete) { - xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, - AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL); + xfrm_audit_policy_delete(xp, err ? 0 : 1, + audit_get_loginuid(current->audit_context), 0); if (err) goto out; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 6ab81b1d215e..36dd31c40f4a 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -850,10 +849,9 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) continue; err = security_xfrm_policy_delete(pol); if (err) { - xfrm_audit_log(audit_info->loginuid, - audit_info->secid, - AUDIT_MAC_IPSEC_DELSPD, 0, - pol, NULL); + xfrm_audit_policy_delete(pol, 0, + audit_info->loginuid, + audit_info->secid); return err; } } @@ -865,10 +863,9 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) continue; err = security_xfrm_policy_delete(pol); if (err) { - xfrm_audit_log(audit_info->loginuid, - audit_info->secid, - AUDIT_MAC_IPSEC_DELSPD, - 0, pol, NULL); + xfrm_audit_policy_delete(pol, 0, + audit_info->loginuid, + audit_info->secid); return err; } } @@ -909,8 +906,8 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) hlist_del(&pol->byidx); write_unlock_bh(&xfrm_policy_lock); - xfrm_audit_log(audit_info->loginuid, audit_info->secid, - AUDIT_MAC_IPSEC_DELSPD, 1, pol, NULL); + xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, + audit_info->secid); xfrm_policy_kill(pol); killed++; @@ -930,11 +927,9 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) hlist_del(&pol->byidx); write_unlock_bh(&xfrm_policy_lock); - xfrm_audit_log(audit_info->loginuid, - audit_info->secid, - AUDIT_MAC_IPSEC_DELSPD, 1, - pol, NULL); - + xfrm_audit_policy_delete(pol, 1, + audit_info->loginuid, + audit_info->secid); xfrm_policy_kill(pol); killed++; @@ -2150,123 +2145,6 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, EXPORT_SYMBOL(xfrm_bundle_ok); -#ifdef CONFIG_AUDITSYSCALL -/* Audit addition and deletion of SAs and ipsec policy */ - -void xfrm_audit_log(uid_t auid, u32 sid, int type, int result, - struct xfrm_policy *xp, struct xfrm_state *x) -{ - - char *secctx; - u32 secctx_len; - struct xfrm_sec_ctx *sctx = NULL; - struct audit_buffer *audit_buf; - int family; - extern int audit_enabled; - - if (audit_enabled == 0) - return; - - BUG_ON((type == AUDIT_MAC_IPSEC_ADDSA || - type == AUDIT_MAC_IPSEC_DELSA) && !x); - BUG_ON((type == AUDIT_MAC_IPSEC_ADDSPD || - type == AUDIT_MAC_IPSEC_DELSPD) && !xp); - - audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, type); - if (audit_buf == NULL) - return; - - switch(type) { - case AUDIT_MAC_IPSEC_ADDSA: - audit_log_format(audit_buf, "SAD add: auid=%u", auid); - break; - case AUDIT_MAC_IPSEC_DELSA: - audit_log_format(audit_buf, "SAD delete: auid=%u", auid); - break; - case AUDIT_MAC_IPSEC_ADDSPD: - audit_log_format(audit_buf, "SPD add: auid=%u", auid); - break; - case AUDIT_MAC_IPSEC_DELSPD: - audit_log_format(audit_buf, "SPD delete: auid=%u", auid); - break; - default: - return; - } - - if (sid != 0 && - security_secid_to_secctx(sid, &secctx, &secctx_len) == 0) { - audit_log_format(audit_buf, " subj=%s", secctx); - security_release_secctx(secctx, secctx_len); - } else - audit_log_task_context(audit_buf); - - if (xp) { - family = xp->selector.family; - if (xp->security) - sctx = xp->security; - } else { - family = x->props.family; - if (x->security) - sctx = x->security; - } - - if (sctx) - audit_log_format(audit_buf, - " sec_alg=%u sec_doi=%u sec_obj=%s", - sctx->ctx_alg, sctx->ctx_doi, sctx->ctx_str); - - switch(family) { - case AF_INET: - { - struct in_addr saddr, daddr; - if (xp) { - saddr.s_addr = xp->selector.saddr.a4; - daddr.s_addr = xp->selector.daddr.a4; - } else { - saddr.s_addr = x->props.saddr.a4; - daddr.s_addr = x->id.daddr.a4; - } - audit_log_format(audit_buf, - " src=%u.%u.%u.%u dst=%u.%u.%u.%u", - NIPQUAD(saddr), NIPQUAD(daddr)); - } - break; - case AF_INET6: - { - struct in6_addr saddr6, daddr6; - if (xp) { - memcpy(&saddr6, xp->selector.saddr.a6, - sizeof(struct in6_addr)); - memcpy(&daddr6, xp->selector.daddr.a6, - sizeof(struct in6_addr)); - } else { - memcpy(&saddr6, x->props.saddr.a6, - sizeof(struct in6_addr)); - memcpy(&daddr6, x->id.daddr.a6, - sizeof(struct in6_addr)); - } - audit_log_format(audit_buf, - " src=" NIP6_FMT " dst=" NIP6_FMT, - NIP6(saddr6), NIP6(daddr6)); - } - break; - } - - if (x) - audit_log_format(audit_buf, " spi=%lu(0x%lx) protocol=%s", - (unsigned long)ntohl(x->id.spi), - (unsigned long)ntohl(x->id.spi), - x->id.proto == IPPROTO_AH ? "AH" : - (x->id.proto == IPPROTO_ESP ? - "ESP" : "IPCOMP")); - - audit_log_format(audit_buf, " res=%u", result); - audit_log_end(audit_buf); -} - -EXPORT_SYMBOL(xfrm_audit_log); -#endif /* CONFIG_AUDITSYSCALL */ - int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) { int err = 0; @@ -2412,6 +2290,72 @@ void __init xfrm_init(void) xfrm_input_init(); } +#ifdef CONFIG_AUDITSYSCALL +static inline void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, + struct audit_buffer *audit_buf) +{ + if (xp->security) + audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", + xp->security->ctx_alg, xp->security->ctx_doi, + xp->security->ctx_str); + + switch(xp->selector.family) { + case AF_INET: + audit_log_format(audit_buf, " src=%u.%u.%u.%u dst=%u.%u.%u.%u", + NIPQUAD(xp->selector.saddr.a4), + NIPQUAD(xp->selector.daddr.a4)); + break; + case AF_INET6: + { + struct in6_addr saddr6, daddr6; + + memcpy(&saddr6, xp->selector.saddr.a6, + sizeof(struct in6_addr)); + memcpy(&daddr6, xp->selector.daddr.a6, + sizeof(struct in6_addr)); + audit_log_format(audit_buf, + " src=" NIP6_FMT " dst=" NIP6_FMT, + NIP6(saddr6), NIP6(daddr6)); + } + break; + } +} + +void +xfrm_audit_policy_add(struct xfrm_policy *xp, int result, u32 auid, u32 sid) +{ + struct audit_buffer *audit_buf; + extern int audit_enabled; + + if (audit_enabled == 0) + return; + audit_buf = xfrm_audit_start(sid, auid); + if (audit_buf == NULL) + return; + audit_log_format(audit_buf, " op=SPD-add res=%u", result); + xfrm_audit_common_policyinfo(xp, audit_buf); + audit_log_end(audit_buf); +} +EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); + +void +xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, u32 auid, u32 sid) +{ + struct audit_buffer *audit_buf; + extern int audit_enabled; + + if (audit_enabled == 0) + return; + audit_buf = xfrm_audit_start(sid, auid); + if (audit_buf == NULL) + return; + audit_log_format(audit_buf, " op=SPD-delete res=%u", result); + xfrm_audit_common_policyinfo(xp, audit_buf); + audit_log_end(audit_buf); +} +EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete); +#endif + #ifdef CONFIG_XFRM_MIGRATE static int xfrm_migrate_selector_match(struct xfrm_selector *sel_cmp, struct xfrm_selector *sel_tgt) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index d4356e6f7f9b..15734adc9367 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "xfrm_hash.h" @@ -301,8 +300,8 @@ expired: if (!err && x->id.spi) km_state_expired(x, 1, 0); - xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, - AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x); + xfrm_audit_state_delete(x, err ? 0 : 1, + audit_get_loginuid(current->audit_context), 0); out: spin_unlock(&x->lock); @@ -403,11 +402,9 @@ xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { if (xfrm_id_proto_match(x->id.proto, proto) && (err = security_xfrm_state_delete(x)) != 0) { - xfrm_audit_log(audit_info->loginuid, - audit_info->secid, - AUDIT_MAC_IPSEC_DELSA, - 0, NULL, x); - + xfrm_audit_state_delete(x, 0, + audit_info->loginuid, + audit_info->secid); return err; } } @@ -443,10 +440,9 @@ restart: spin_unlock_bh(&xfrm_state_lock); err = xfrm_state_delete(x); - xfrm_audit_log(audit_info->loginuid, - audit_info->secid, - AUDIT_MAC_IPSEC_DELSA, - err ? 0 : 1, NULL, x); + xfrm_audit_state_delete(x, err ? 0 : 1, + audit_info->loginuid, + audit_info->secid); xfrm_state_put(x); spin_lock_bh(&xfrm_state_lock); @@ -1821,3 +1817,72 @@ void __init xfrm_state_init(void) INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task); } +#ifdef CONFIG_AUDITSYSCALL +static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x, + struct audit_buffer *audit_buf) +{ + if (x->security) + audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", + x->security->ctx_alg, x->security->ctx_doi, + x->security->ctx_str); + + switch(x->props.family) { + case AF_INET: + audit_log_format(audit_buf, " src=%u.%u.%u.%u dst=%u.%u.%u.%u", + NIPQUAD(x->props.saddr.a4), + NIPQUAD(x->id.daddr.a4)); + break; + case AF_INET6: + { + struct in6_addr saddr6, daddr6; + + memcpy(&saddr6, x->props.saddr.a6, + sizeof(struct in6_addr)); + memcpy(&daddr6, x->id.daddr.a6, + sizeof(struct in6_addr)); + audit_log_format(audit_buf, + " src=" NIP6_FMT " dst=" NIP6_FMT, + NIP6(saddr6), NIP6(daddr6)); + } + break; + } +} + +void +xfrm_audit_state_add(struct xfrm_state *x, int result, u32 auid, u32 sid) +{ + struct audit_buffer *audit_buf; + extern int audit_enabled; + + if (audit_enabled == 0) + return; + audit_buf = xfrm_audit_start(sid, auid); + if (audit_buf == NULL) + return; + audit_log_format(audit_buf, " op=SAD-add res=%u",result); + xfrm_audit_common_stateinfo(x, audit_buf); + audit_log_format(audit_buf, " spi=%lu(0x%lx)", + (unsigned long)x->id.spi, (unsigned long)x->id.spi); + audit_log_end(audit_buf); +} +EXPORT_SYMBOL_GPL(xfrm_audit_state_add); + +void +xfrm_audit_state_delete(struct xfrm_state *x, int result, u32 auid, u32 sid) +{ + struct audit_buffer *audit_buf; + extern int audit_enabled; + + if (audit_enabled == 0) + return; + audit_buf = xfrm_audit_start(sid, auid); + if (audit_buf == NULL) + return; + audit_log_format(audit_buf, " op=SAD-delete res=%u",result); + xfrm_audit_common_stateinfo(x, audit_buf); + audit_log_format(audit_buf, " spi=%lu(0x%lx)", + (unsigned long)x->id.spi, (unsigned long)x->id.spi); + audit_log_end(audit_buf); +} +EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); +#endif /* CONFIG_AUDITSYSCALL */ diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 9e516f5cbb5e..0d81c0f23919 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -30,7 +30,6 @@ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #include #endif -#include static inline int alg_len(struct xfrm_algo *alg) { @@ -371,8 +370,8 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, else err = xfrm_state_update(x); - xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, - AUDIT_MAC_IPSEC_ADDSA, err ? 0 : 1, NULL, x); + xfrm_audit_state_add(x, err ? 0 : 1, NETLINK_CB(skb).loginuid, + NETLINK_CB(skb).sid); if (err < 0) { x->km.state = XFRM_STATE_DEAD; @@ -451,8 +450,8 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, km_state_notify(x, &c); out: - xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, - AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x); + xfrm_audit_state_delete(x, err ? 0 : 1, NETLINK_CB(skb).loginuid, + NETLINK_CB(skb).sid); xfrm_state_put(x); return err; } @@ -1067,8 +1066,8 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, * a type XFRM_MSG_UPDPOLICY - JHS */ excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; err = xfrm_policy_insert(p->dir, xp, excl); - xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, - AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL); + xfrm_audit_policy_add(xp, err ? 0 : 1, NETLINK_CB(skb).loginuid, + NETLINK_CB(skb).sid); if (err) { security_xfrm_policy_free(xp); @@ -1290,8 +1289,9 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, NETLINK_CB(skb).pid); } } else { - xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, - AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL); + xfrm_audit_policy_delete(xp, err ? 0 : 1, + NETLINK_CB(skb).loginuid, + NETLINK_CB(skb).sid); if (err != 0) goto out; @@ -1523,8 +1523,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, err = 0; if (up->hard) { xfrm_policy_delete(xp, p->dir); - xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, - AUDIT_MAC_IPSEC_DELSPD, 1, xp, NULL); + xfrm_audit_policy_delete(xp, 1, NETLINK_CB(skb).loginuid, + NETLINK_CB(skb).sid); } else { // reset the timers here? @@ -1559,8 +1559,8 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, if (ue->hard) { __xfrm_state_delete(x); - xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid, - AUDIT_MAC_IPSEC_DELSA, 1, NULL, x); + xfrm_audit_state_delete(x, 1, NETLINK_CB(skb).loginuid, + NETLINK_CB(skb).sid); } err = 0; out: From 890d52d3f1e28888c4122e120426588f5ad63d37 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 11:26:59 +0200 Subject: [PATCH 1168/2804] [ATALK]: In notifier handlers convert the void pointer to a netdevice This slightly improves code safety and clarity. Later network namespace patches touch this code so this is a preliminary cleanup. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/appletalk/aarp.c | 7 ++++--- net/appletalk/ddp.c | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 3d1655f98388..80b54148460f 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -330,15 +330,16 @@ static void aarp_expire_timeout(unsigned long unused) static int aarp_device_event(struct notifier_block *this, unsigned long event, void *ptr) { + struct net_device *dev = ptr; int ct; if (event == NETDEV_DOWN) { write_lock_bh(&aarp_lock); for (ct = 0; ct < AARP_HASH_SIZE; ct++) { - __aarp_expire_device(&resolved[ct], ptr); - __aarp_expire_device(&unresolved[ct], ptr); - __aarp_expire_device(&proxies[ct], ptr); + __aarp_expire_device(&resolved[ct], dev); + __aarp_expire_device(&unresolved[ct], dev); + __aarp_expire_device(&proxies[ct], dev); } write_unlock_bh(&aarp_lock); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index fbdfb1224ae1..594b59739546 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -647,9 +647,11 @@ static inline void atalk_dev_down(struct net_device *dev) static int ddp_device_event(struct notifier_block *this, unsigned long event, void *ptr) { + struct net_device *dev = ptr; + if (event == NETDEV_DOWN) /* Discard any use of this */ - atalk_dev_down(ptr); + atalk_dev_down(dev); return NOTIFY_DONE; } From 32da477a5bfe96b6dfc8960e0d22d89ca09fd10a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 11:37:03 +0200 Subject: [PATCH 1169/2804] [NET]: Don't implement dev_ifname32 inline The current implementation of dev_ifname makes maintenance difficult because updates to the implementation of the ioctl have to made in two places. So this patch updates dev_ifname32 to do a classic 32/64 structure conversion and call sys_ioctl like the rest of the compat calls do. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- fs/compat_ioctl.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 37310b0e8107..d917e4a26a43 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -324,22 +324,21 @@ struct ifconf32 { static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct net_device *dev; - struct ifreq32 ifr32; + struct ifreq __user *uifr; int err; - if (copy_from_user(&ifr32, compat_ptr(arg), sizeof(ifr32))) + uifr = compat_alloc_user_space(sizeof(struct ifreq)); + if (copy_in_user(uifr, compat_ptr(arg), sizeof(struct ifreq32))); return -EFAULT; - dev = dev_get_by_index(ifr32.ifr_ifindex); - if (!dev) - return -ENODEV; + err = sys_ioctl(fd, SIOCGIFNAME, (unsigned long)uifr); + if (err) + return err; - strlcpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)); - dev_put(dev); - - err = copy_to_user(compat_ptr(arg), &ifr32, sizeof(ifr32)); - return (err ? -EFAULT : 0); + if (copy_in_user(compat_ptr(arg), uifr, sizeof(struct ifreq32))) + return -EFAULT; + + return 0; } static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) From 5f256becd868bf63b70da8f2769033d6734670e9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 11:50:50 +0200 Subject: [PATCH 1170/2804] [NET]: Basic network namespace infrastructure. This is the basic infrastructure needed to support network namespaces. This infrastructure is: - Registration functions to support initializing per network namespace data when a network namespaces is created or destroyed. - struct net. The network namespace data structure. This structure will grow as variables are made per network namespace but this is the minimal starting point. - Functions to grab a reference to the network namespace. I provide both get/put functions that keep a network namespace from being freed. And hold/release functions serve as weak references and will warn if their count is not zero when the data structure is freed. Useful for dealing with more complicated data structures like the ipv4 route cache. - A list of all of the network namespaces so we can iterate over them. - A slab for the network namespace data structure allowing leaks to be spotted. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/net_namespace.h | 68 +++++++++ net/core/Makefile | 2 +- net/core/net_namespace.c | 292 ++++++++++++++++++++++++++++++++++++ 3 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 include/net/net_namespace.h create mode 100644 net/core/net_namespace.c diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h new file mode 100644 index 000000000000..6344b77f81a2 --- /dev/null +++ b/include/net/net_namespace.h @@ -0,0 +1,68 @@ +/* + * Operations on the network namespace + */ +#ifndef __NET_NET_NAMESPACE_H +#define __NET_NET_NAMESPACE_H + +#include +#include +#include + +struct net { + atomic_t count; /* To decided when the network + * namespace should be freed. + */ + atomic_t use_count; /* To track references we + * destroy on demand + */ + struct list_head list; /* list of network namespaces */ + struct work_struct work; /* work struct for freeing */ +}; + +extern struct net init_net; +extern struct list_head net_namespace_list; + +extern void __put_net(struct net *net); + +static inline struct net *get_net(struct net *net) +{ + atomic_inc(&net->count); + return net; +} + +static inline void put_net(struct net *net) +{ + if (atomic_dec_and_test(&net->count)) + __put_net(net); +} + +static inline struct net *hold_net(struct net *net) +{ + atomic_inc(&net->use_count); + return net; +} + +static inline void release_net(struct net *net) +{ + atomic_dec(&net->use_count); +} + +extern void net_lock(void); +extern void net_unlock(void); + +#define for_each_net(VAR) \ + list_for_each_entry(VAR, &net_namespace_list, list) + + +struct pernet_operations { + struct list_head list; + int (*init)(struct net *net); + void (*exit)(struct net *net); +}; + +extern int register_pernet_subsys(struct pernet_operations *); +extern void unregister_pernet_subsys(struct pernet_operations *); +extern int register_pernet_device(struct pernet_operations *); +extern void unregister_pernet_device(struct pernet_operations *); + +#endif /* __NET_NET_NAMESPACE_H */ diff --git a/net/core/Makefile b/net/core/Makefile index 4751613e1b59..ea9b3f32d1c0 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -3,7 +3,7 @@ # obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \ - gen_stats.o gen_estimator.o + gen_stats.o gen_estimator.o net_namespace.o obj-$(CONFIG_SYSCTL) += sysctl_net_core.o diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c new file mode 100644 index 000000000000..f259a9b6fdc1 --- /dev/null +++ b/net/core/net_namespace.c @@ -0,0 +1,292 @@ +#include +#include +#include +#include +#include +#include +#include + +/* + * Our network namespace constructor/destructor lists + */ + +static LIST_HEAD(pernet_list); +static struct list_head *first_device = &pernet_list; +static DEFINE_MUTEX(net_mutex); + +static DEFINE_MUTEX(net_list_mutex); +LIST_HEAD(net_namespace_list); + +static struct kmem_cache *net_cachep; + +struct net init_net; +EXPORT_SYMBOL_GPL(init_net); + +void net_lock(void) +{ + mutex_lock(&net_list_mutex); +} + +void net_unlock(void) +{ + mutex_unlock(&net_list_mutex); +} + +static struct net *net_alloc(void) +{ + return kmem_cache_alloc(net_cachep, GFP_KERNEL); +} + +static void net_free(struct net *net) +{ + if (!net) + return; + + if (unlikely(atomic_read(&net->use_count) != 0)) { + printk(KERN_EMERG "network namespace not free! Usage: %d\n", + atomic_read(&net->use_count)); + return; + } + + kmem_cache_free(net_cachep, net); +} + +static void cleanup_net(struct work_struct *work) +{ + struct pernet_operations *ops; + struct list_head *ptr; + struct net *net; + + net = container_of(work, struct net, work); + + mutex_lock(&net_mutex); + + /* Don't let anyone else find us. */ + net_lock(); + list_del(&net->list); + net_unlock(); + + /* Run all of the network namespace exit methods */ + list_for_each_prev(ptr, &pernet_list) { + ops = list_entry(ptr, struct pernet_operations, list); + if (ops->exit) + ops->exit(net); + } + + mutex_unlock(&net_mutex); + + /* Ensure there are no outstanding rcu callbacks using this + * network namespace. + */ + rcu_barrier(); + + /* Finally it is safe to free my network namespace structure */ + net_free(net); +} + + +void __put_net(struct net *net) +{ + /* Cleanup the network namespace in process context */ + INIT_WORK(&net->work, cleanup_net); + schedule_work(&net->work); +} +EXPORT_SYMBOL_GPL(__put_net); + +/* + * setup_net runs the initializers for the network namespace object. + */ +static int setup_net(struct net *net) +{ + /* Must be called with net_mutex held */ + struct pernet_operations *ops; + struct list_head *ptr; + int error; + + memset(net, 0, sizeof(struct net)); + atomic_set(&net->count, 1); + atomic_set(&net->use_count, 0); + + error = 0; + list_for_each(ptr, &pernet_list) { + ops = list_entry(ptr, struct pernet_operations, list); + if (ops->init) { + error = ops->init(net); + if (error < 0) + goto out_undo; + } + } +out: + return error; +out_undo: + /* Walk through the list backwards calling the exit functions + * for the pernet modules whose init functions did not fail. + */ + for (ptr = ptr->prev; ptr != &pernet_list; ptr = ptr->prev) { + ops = list_entry(ptr, struct pernet_operations, list); + if (ops->exit) + ops->exit(net); + } + goto out; +} + +static int __init net_ns_init(void) +{ + int err; + + printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net)); + net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), + SMP_CACHE_BYTES, + SLAB_PANIC, NULL); + mutex_lock(&net_mutex); + err = setup_net(&init_net); + + net_lock(); + list_add_tail(&init_net.list, &net_namespace_list); + net_unlock(); + + mutex_unlock(&net_mutex); + if (err) + panic("Could not setup the initial network namespace"); + + return 0; +} + +pure_initcall(net_ns_init); + +static int register_pernet_operations(struct list_head *list, + struct pernet_operations *ops) +{ + struct net *net, *undo_net; + int error; + + error = 0; + list_add_tail(&ops->list, list); + for_each_net(net) { + if (ops->init) { + error = ops->init(net); + if (error) + goto out_undo; + } + } +out: + return error; + +out_undo: + /* If I have an error cleanup all namespaces I initialized */ + list_del(&ops->list); + for_each_net(undo_net) { + if (undo_net == net) + goto undone; + if (ops->exit) + ops->exit(undo_net); + } +undone: + goto out; +} + +static void unregister_pernet_operations(struct pernet_operations *ops) +{ + struct net *net; + + list_del(&ops->list); + for_each_net(net) + if (ops->exit) + ops->exit(net); +} + +/** + * register_pernet_subsys - register a network namespace subsystem + * @ops: pernet operations structure for the subsystem + * + * Register a subsystem which has init and exit functions + * that are called when network namespaces are created and + * destroyed respectively. + * + * When registered all network namespace init functions are + * called for every existing network namespace. Allowing kernel + * modules to have a race free view of the set of network namespaces. + * + * When a new network namespace is created all of the init + * methods are called in the order in which they were registered. + * + * When a network namespace is destroyed all of the exit methods + * are called in the reverse of the order with which they were + * registered. + */ +int register_pernet_subsys(struct pernet_operations *ops) +{ + int error; + mutex_lock(&net_mutex); + error = register_pernet_operations(first_device, ops); + mutex_unlock(&net_mutex); + return error; +} +EXPORT_SYMBOL_GPL(register_pernet_subsys); + +/** + * unregister_pernet_subsys - unregister a network namespace subsystem + * @ops: pernet operations structure to manipulate + * + * Remove the pernet operations structure from the list to be + * used when network namespaces are created or destoryed. In + * addition run the exit method for all existing network + * namespaces. + */ +void unregister_pernet_subsys(struct pernet_operations *module) +{ + mutex_lock(&net_mutex); + unregister_pernet_operations(module); + mutex_unlock(&net_mutex); +} +EXPORT_SYMBOL_GPL(unregister_pernet_subsys); + +/** + * register_pernet_device - register a network namespace device + * @ops: pernet operations structure for the subsystem + * + * Register a device which has init and exit functions + * that are called when network namespaces are created and + * destroyed respectively. + * + * When registered all network namespace init functions are + * called for every existing network namespace. Allowing kernel + * modules to have a race free view of the set of network namespaces. + * + * When a new network namespace is created all of the init + * methods are called in the order in which they were registered. + * + * When a network namespace is destroyed all of the exit methods + * are called in the reverse of the order with which they were + * registered. + */ +int register_pernet_device(struct pernet_operations *ops) +{ + int error; + mutex_lock(&net_mutex); + error = register_pernet_operations(&pernet_list, ops); + if (!error && (first_device == &pernet_list)) + first_device = &ops->list; + mutex_unlock(&net_mutex); + return error; +} +EXPORT_SYMBOL_GPL(register_pernet_device); + +/** + * unregister_pernet_device - unregister a network namespace netdevice + * @ops: pernet operations structure to manipulate + * + * Remove the pernet operations structure from the list to be + * used when network namespaces are created or destoryed. In + * addition run the exit method for all existing network + * namespaces. + */ +void unregister_pernet_device(struct pernet_operations *ops) +{ + mutex_lock(&net_mutex); + if (&ops->list == first_device) + first_device = first_device->next; + unregister_pernet_operations(ops); + mutex_unlock(&net_mutex); +} +EXPORT_SYMBOL_GPL(unregister_pernet_device); From 772698f6362680b65211f7efc68121f1e4c28aa5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 11:55:17 +0200 Subject: [PATCH 1171/2804] [NET]: Add a network namespace parameter to tasks This is the network namespace from which all which all sockets and anything else under user control ultimately get their network namespace parameters. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/linux/init_task.h | 2 ++ include/linux/nsproxy.h | 1 + 2 files changed, 3 insertions(+) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index f8abfa349ef9..e2c1ffcff62c 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -9,6 +9,7 @@ #include #include #include +#include #define INIT_FDTABLE \ { \ @@ -78,6 +79,7 @@ extern struct nsproxy init_nsproxy; .nslock = __SPIN_LOCK_UNLOCKED(nsproxy.nslock), \ .uts_ns = &init_uts_ns, \ .mnt_ns = NULL, \ + .net_ns = &init_net, \ INIT_IPC_NS(ipc_ns) \ .user_ns = &init_user_ns, \ } diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index ce06188b7a56..bec4485e3d76 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h @@ -29,6 +29,7 @@ struct nsproxy { struct mnt_namespace *mnt_ns; struct pid_namespace *pid_ns; struct user_namespace *user_ns; + struct net *net_ns; }; extern struct nsproxy init_nsproxy; From 4a1c537113cdc688aabc3fb9bb6ed18ec821c779 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 11:56:32 +0200 Subject: [PATCH 1172/2804] [NET]: Add a network namespace tag to struct net_device Please note that network devices do not increase the count count on the network namespace. The are inside the network namespace and so the network namespace tag is in the nature of a back pointer and so getting and putting the network namespace is unnecessary. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8f00bdf95ef4..dc3c15b726bc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -41,6 +41,7 @@ #include #include +struct net; struct vlan_group; struct ethtool_ops; struct netpoll_info; @@ -663,6 +664,9 @@ struct net_device void (*poll_controller)(struct net_device *dev); #endif + /* Network namespace this network device is inside */ + struct net *nd_net; + /* bridge stuff */ struct net_bridge_port *br_port; /* macvlan */ From 07feaebfcc10cd35e745c7073667935246494bee Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 11:58:02 +0200 Subject: [PATCH 1173/2804] [NET]: Add a network namespace parameter to struct sock Sockets need to get a reference to their network namespace, or possibly a simple hold if someone registers on the network namespace notifier and will free the sockets when the namespace is going to be destroyed. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/inet_timewait_sock.h | 1 + include/net/sock.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 47d52b2414db..abaff0597270 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -115,6 +115,7 @@ struct inet_timewait_sock { #define tw_refcnt __tw_common.skc_refcnt #define tw_hash __tw_common.skc_hash #define tw_prot __tw_common.skc_prot +#define tw_net __tw_common.skc_net volatile unsigned char tw_substate; /* 3 bits hole, try to pack */ unsigned char tw_rcv_wscale; diff --git a/include/net/sock.h b/include/net/sock.h index 5ed9fa42b6e8..9ef8b5fb7936 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -105,6 +105,7 @@ struct proto; * @skc_refcnt: reference count * @skc_hash: hash value used with various protocol lookup tables * @skc_prot: protocol handlers inside a network family + * @skc_net: reference to the network namespace of this socket * * This is the minimal network layer representation of sockets, the header * for struct sock and struct inet_timewait_sock. @@ -119,6 +120,7 @@ struct sock_common { atomic_t skc_refcnt; unsigned int skc_hash; struct proto *skc_prot; + struct net *skc_net; }; /** @@ -195,6 +197,7 @@ struct sock { #define sk_refcnt __sk_common.skc_refcnt #define sk_hash __sk_common.skc_hash #define sk_prot __sk_common.skc_prot +#define sk_net __sk_common.skc_net unsigned char sk_shutdown : 2, sk_no_check : 2, sk_userlocks : 4; From 457c4cbc5a3dde259d2a1f15d5f9785290397267 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 12:01:34 +0200 Subject: [PATCH 1174/2804] [NET]: Make /proc/net per network namespace This patch makes /proc/net per network namespace. It modifies the global variables proc_net and proc_net_stat to be per network namespace. The proc_net file helpers are modified to take a network namespace argument, and all of their callers are fixed to pass &init_net for that argument. This ensures that all of the /proc/net files are only visible and usable in the initial network namespace until the code behind them has been updated to be handle multiple network namespaces. Making /proc/net per namespace is necessary as at least some files in /proc/net depend upon the set of network devices which is per network namespace, and even more files in /proc/net have contents that are relevant to a single network namespace. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/isdn/divert/divert_procfs.c | 7 +-- drivers/isdn/hardware/eicon/diva_didd.c | 5 ++- drivers/isdn/hysdn/hysdn_procconf.c | 5 ++- drivers/net/bonding/bond_main.c | 7 +-- drivers/net/hamradio/bpqether.c | 5 ++- drivers/net/hamradio/scc.c | 5 ++- drivers/net/hamradio/yam.c | 5 ++- drivers/net/ibmveth.c | 7 +-- drivers/net/pppoe.c | 5 ++- drivers/net/pppol2tp.c | 5 ++- drivers/net/tokenring/lanstreamer.c | 5 ++- drivers/net/tokenring/olympic.c | 9 ++-- drivers/net/wireless/hostap/hostap_main.c | 7 +-- drivers/net/wireless/strip.c | 5 ++- fs/proc/Makefile | 1 + fs/proc/internal.h | 5 +++ fs/proc/root.c | 8 ++-- include/linux/proc_fs.h | 44 ++++++++----------- include/net/net_namespace.h | 5 +++ net/802/tr.c | 3 +- net/8021q/vlanproc.c | 5 ++- net/appletalk/atalk_proc.c | 7 +-- net/atm/proc.c | 5 ++- net/ax25/af_ax25.c | 13 +++--- net/core/dev.c | 19 ++++---- net/core/dev_mcast.c | 3 +- net/core/neighbour.c | 3 +- net/core/pktgen.c | 9 ++-- net/core/sock.c | 3 +- net/dccp/probe.c | 7 +-- net/decnet/af_decnet.c | 5 ++- net/decnet/dn_dev.c | 5 ++- net/decnet/dn_neigh.c | 5 ++- net/decnet/dn_route.c | 5 ++- net/ieee80211/ieee80211_module.c | 7 +-- net/ipv4/arp.c | 3 +- net/ipv4/fib_hash.c | 5 ++- net/ipv4/fib_trie.c | 17 +++---- net/ipv4/igmp.c | 5 ++- net/ipv4/ipconfig.c | 3 +- net/ipv4/ipmr.c | 5 ++- net/ipv4/ipvs/ip_vs_app.c | 5 ++- net/ipv4/ipvs/ip_vs_conn.c | 5 ++- net/ipv4/ipvs/ip_vs_ctl.c | 9 ++-- net/ipv4/ipvs/ip_vs_lblcr.c | 5 ++- net/ipv4/netfilter/ip_queue.c | 8 ++-- net/ipv4/netfilter/ipt_CLUSTERIP.c | 3 +- net/ipv4/netfilter/ipt_recent.c | 5 ++- .../nf_conntrack_l3proto_ipv4_compat.c | 17 +++---- net/ipv4/proc.c | 11 ++--- net/ipv4/raw.c | 5 ++- net/ipv4/route.c | 7 +-- net/ipv4/tcp_ipv4.c | 5 ++- net/ipv4/tcp_probe.c | 7 +-- net/ipv4/udp.c | 5 ++- net/ipv6/addrconf.c | 7 +-- net/ipv6/anycast.c | 5 ++- net/ipv6/ip6_flowlabel.c | 5 ++- net/ipv6/mcast.c | 9 ++-- net/ipv6/netfilter/ip6_queue.c | 7 +-- net/ipv6/proc.c | 17 +++---- net/ipv6/raw.c | 5 ++- net/ipv6/route.c | 9 ++-- net/ipx/ipx_proc.c | 7 +-- net/irda/irproc.c | 5 ++- net/key/af_key.c | 5 ++- net/llc/llc_proc.c | 7 +-- net/netfilter/core.c | 3 +- net/netfilter/nf_conntrack_expect.c | 5 ++- net/netfilter/nf_conntrack_standalone.c | 13 +++--- net/netfilter/x_tables.c | 17 +++---- net/netfilter/xt_hashlimit.c | 11 ++--- net/netlink/af_netlink.c | 3 +- net/netrom/af_netrom.c | 13 +++--- net/packet/af_packet.c | 5 ++- net/rose/af_rose.c | 17 +++---- net/rxrpc/af_rxrpc.c | 9 ++-- net/sched/sch_api.c | 3 +- net/sctp/protocol.c | 5 ++- net/sunrpc/stats.c | 5 ++- net/unix/af_unix.c | 5 ++- net/wanrouter/wanproc.c | 7 +-- net/wireless/wext.c | 3 +- net/x25/x25_proc.c | 7 +-- 84 files changed, 342 insertions(+), 261 deletions(-) diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 559a0d0244cf..4fd4c46892e3 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -17,6 +17,7 @@ #include #endif #include +#include #include "isdn_divert.h" @@ -284,12 +285,12 @@ divert_dev_init(void) init_waitqueue_head(&rd_queue); #ifdef CONFIG_PROC_FS - isdn_proc_entry = proc_mkdir("net/isdn", NULL); + isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net); if (!isdn_proc_entry) return (-1); isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry); if (!isdn_divert_entry) { - remove_proc_entry("net/isdn", NULL); + remove_proc_entry("isdn", init_net.proc_net); return (-1); } isdn_divert_entry->proc_fops = &isdn_fops; @@ -309,7 +310,7 @@ divert_dev_deinit(void) #ifdef CONFIG_PROC_FS remove_proc_entry("divert", isdn_proc_entry); - remove_proc_entry("net/isdn", NULL); + remove_proc_entry("isdn", init_net.proc_net); #endif /* CONFIG_PROC_FS */ return (0); diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c index d755d904e62c..993b14cf1778 100644 --- a/drivers/isdn/hardware/eicon/diva_didd.c +++ b/drivers/isdn/hardware/eicon/diva_didd.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "platform.h" #include "di_defs.h" @@ -86,7 +87,7 @@ proc_read(char *page, char **start, off_t off, int count, int *eof, static int DIVA_INIT_FUNCTION create_proc(void) { - proc_net_eicon = proc_mkdir("net/eicon", NULL); + proc_net_eicon = proc_mkdir("eicon", init_net.proc_net); if (proc_net_eicon) { if ((proc_didd = @@ -102,7 +103,7 @@ static int DIVA_INIT_FUNCTION create_proc(void) static void remove_proc(void) { remove_proc_entry(DRIVERLNAME, proc_net_eicon); - remove_proc_entry("net/eicon", NULL); + remove_proc_entry("eicon", init_net.proc_net); } static int DIVA_INIT_FUNCTION divadidd_init(void) diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index dc477e0aab0e..27d890b48f88 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "hysdn_defs.h" @@ -392,7 +393,7 @@ hysdn_procconf_init(void) hysdn_card *card; unsigned char conf_name[20]; - hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, proc_net); + hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, init_net.proc_net); if (!hysdn_proc_entry) { printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n"); return (-1); @@ -437,5 +438,5 @@ hysdn_procconf_release(void) card = card->next; /* point to next card */ } - remove_proc_entry(PROC_SUBDIR_NAME, proc_net); + remove_proc_entry(PROC_SUBDIR_NAME, init_net.proc_net); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1afda3230def..5de648f90a45 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -75,6 +75,7 @@ #include #include #include +#include #include "bonding.h" #include "bond_3ad.h" #include "bond_alb.h" @@ -3144,7 +3145,7 @@ static void bond_create_proc_dir(void) { int len = strlen(DRV_NAME); - for (bond_proc_dir = proc_net->subdir; bond_proc_dir; + for (bond_proc_dir = init_net.proc_net->subdir; bond_proc_dir; bond_proc_dir = bond_proc_dir->next) { if ((bond_proc_dir->namelen == len) && !memcmp(bond_proc_dir->name, DRV_NAME, len)) { @@ -3153,7 +3154,7 @@ static void bond_create_proc_dir(void) } if (!bond_proc_dir) { - bond_proc_dir = proc_mkdir(DRV_NAME, proc_net); + bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net); if (bond_proc_dir) { bond_proc_dir->owner = THIS_MODULE; } else { @@ -3188,7 +3189,7 @@ static void bond_destroy_proc_dir(void) bond_proc_dir->owner = NULL; } } else { - remove_proc_entry(DRV_NAME, proc_net); + remove_proc_entry(DRV_NAME, init_net.proc_net); bond_proc_dir = NULL; } } diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index cc0ee93669ea..1699d42d13ca 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -83,6 +83,7 @@ #include #include +#include #include @@ -594,7 +595,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi static int __init bpq_init_driver(void) { #ifdef CONFIG_PROC_FS - if (!proc_net_fops_create("bpqether", S_IRUGO, &bpq_info_fops)) { + if (!proc_net_fops_create(&init_net, "bpqether", S_IRUGO, &bpq_info_fops)) { printk(KERN_ERR "bpq: cannot create /proc/net/bpqether entry.\n"); return -ENOENT; @@ -618,7 +619,7 @@ static void __exit bpq_cleanup_driver(void) unregister_netdevice_notifier(&bpq_dev_notifier); - proc_net_remove("bpqether"); + proc_net_remove(&init_net, "bpqether"); rtnl_lock(); while (!list_empty(&bpq_devices)) { diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 6fdaad5a4577..39b3b82aa4a4 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -174,6 +174,7 @@ #include #include +#include #include #include @@ -2114,7 +2115,7 @@ static int __init scc_init_driver (void) } rtnl_unlock(); - proc_net_fops_create("z8530drv", 0, &scc_net_seq_fops); + proc_net_fops_create(&init_net, "z8530drv", 0, &scc_net_seq_fops); return 0; } @@ -2169,7 +2170,7 @@ static void __exit scc_cleanup_driver(void) if (Vector_Latch) release_region(Vector_Latch, 1); - proc_net_remove("z8530drv"); + proc_net_remove(&init_net, "z8530drv"); } MODULE_AUTHOR("Joerg Reuter "); diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 467559debfd6..401724ddafcd 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -1142,7 +1143,7 @@ static int __init yam_init_driver(void) yam_timer.expires = jiffies + HZ / 100; add_timer(&yam_timer); - proc_net_fops_create("yam", S_IRUGO, &yam_info_fops); + proc_net_fops_create(&init_net, "yam", S_IRUGO, &yam_info_fops); return 0; error: while (--i >= 0) { @@ -1174,7 +1175,7 @@ static void __exit yam_cleanup_driver(void) kfree(p); } - proc_net_remove("yam"); + proc_net_remove(&init_net, "yam"); } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 78e28ada1e21..0c35d72f5f8d 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -97,7 +98,7 @@ static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); static struct kobj_type ktype_veth_pool; #ifdef CONFIG_PROC_FS -#define IBMVETH_PROC_DIR "net/ibmveth" +#define IBMVETH_PROC_DIR "ibmveth" static struct proc_dir_entry *ibmveth_proc_dir; #endif @@ -1091,7 +1092,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev) #ifdef CONFIG_PROC_FS static void ibmveth_proc_register_driver(void) { - ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, NULL); + ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net); if (ibmveth_proc_dir) { SET_MODULE_OWNER(ibmveth_proc_dir); } @@ -1099,7 +1100,7 @@ static void ibmveth_proc_register_driver(void) static void ibmveth_proc_unregister_driver(void) { - remove_proc_entry(IBMVETH_PROC_DIR, NULL); + remove_proc_entry(IBMVETH_PROC_DIR, init_net.proc_net); } static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 9b30cd600a64..ee8ce195c538 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -78,6 +78,7 @@ #include #include +#include #include #include @@ -1042,7 +1043,7 @@ static int __init pppoe_proc_init(void) { struct proc_dir_entry *p; - p = create_proc_entry("net/pppoe", S_IRUGO, NULL); + p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net); if (!p) return -ENOMEM; @@ -1113,7 +1114,7 @@ static void __exit pppoe_exit(void) dev_remove_pack(&pppoes_ptype); dev_remove_pack(&pppoed_ptype); unregister_netdevice_notifier(&pppoe_notifier); - remove_proc_entry("net/pppoe", NULL); + remove_proc_entry("pppoe", init_net.proc_net); proto_unregister(&pppoe_sk_proto); } diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index abe91cb595f4..2eb424ba58e5 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -2444,7 +2445,7 @@ static int __init pppol2tp_init(void) goto out_unregister_pppol2tp_proto; #ifdef CONFIG_PROC_FS - pppol2tp_proc = create_proc_entry("pppol2tp", 0, proc_net); + pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net); if (!pppol2tp_proc) { err = -ENOMEM; goto out_unregister_pppox_proto; @@ -2469,7 +2470,7 @@ static void __exit pppol2tp_exit(void) unregister_pppox_proto(PX_PROTO_OL2TP); #ifdef CONFIG_PROC_FS - remove_proc_entry("pppol2tp", proc_net); + remove_proc_entry("pppol2tp", init_net.proc_net); #endif proto_unregister(&pppol2tp_sk_proto); } diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 5d849c089a3b..fc4495581f96 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -123,6 +123,7 @@ #include #include +#include #include #include @@ -250,7 +251,7 @@ static int __devinit streamer_init_one(struct pci_dev *pdev, #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS if (!dev_streamer) - create_proc_read_entry("net/streamer_tr", 0, 0, + create_proc_read_entry("streamer_tr", 0, init_net.proc_net, streamer_proc_info, NULL); streamer_priv->next = dev_streamer; dev_streamer = streamer_priv; @@ -423,7 +424,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev) } } if (!dev_streamer) - remove_proc_entry("net/streamer_tr", NULL); + remove_proc_entry("streamer_tr", init_net.proc_net); } #endif #endif diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 09b3cfb8e809..c323101a895b 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -102,6 +102,7 @@ #include #include +#include #include #include @@ -268,9 +269,9 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device printk("Olympic: %s registered as: %s\n",olympic_priv->olympic_card_name,dev->name); if (olympic_priv->olympic_network_monitor) { /* Must go after register_netdev as we need the device name */ char proc_name[20] ; - strcpy(proc_name,"net/olympic_") ; + strcpy(proc_name,"olympic_") ; strcat(proc_name,dev->name) ; - create_proc_read_entry(proc_name,0,NULL,olympic_proc_info,(void *)dev) ; + create_proc_read_entry(proc_name,0,init_net.proc_net,olympic_proc_info,(void *)dev) ; printk("Olympic: Network Monitor information: /proc/%s\n",proc_name); } return 0 ; @@ -1752,9 +1753,9 @@ static void __devexit olympic_remove_one(struct pci_dev *pdev) if (olympic_priv->olympic_network_monitor) { char proc_name[20] ; - strcpy(proc_name,"net/olympic_") ; + strcpy(proc_name,"olympic_") ; strcat(proc_name,dev->name) ; - remove_proc_entry(proc_name,NULL); + remove_proc_entry(proc_name,init_net.proc_net); } unregister_netdev(dev) ; iounmap(olympic_priv->olympic_mmio) ; diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 446de51bab74..9a470e80ca24 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1093,8 +1094,8 @@ struct proc_dir_entry *hostap_proc; static int __init hostap_init(void) { - if (proc_net != NULL) { - hostap_proc = proc_mkdir("hostap", proc_net); + if (init_net.proc_net != NULL) { + hostap_proc = proc_mkdir("hostap", init_net.proc_net); if (!hostap_proc) printk(KERN_WARNING "Failed to mkdir " "/proc/net/hostap\n"); @@ -1109,7 +1110,7 @@ static void __exit hostap_exit(void) { if (hostap_proc != NULL) { hostap_proc = NULL; - remove_proc_entry("hostap", proc_net); + remove_proc_entry("hostap", init_net.proc_net); } } diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index ef32a5c1e818..edb214e8c744 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -107,6 +107,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; #include #include #include +#include #include #include @@ -2787,7 +2788,7 @@ static int __init strip_init_driver(void) /* * Register the status file with /proc */ - proc_net_fops_create("strip", S_IFREG | S_IRUGO, &strip_seq_fops); + proc_net_fops_create(&init_net, "strip", S_IFREG | S_IRUGO, &strip_seq_fops); return status; } @@ -2809,7 +2810,7 @@ static void __exit strip_exit_driver(void) } /* Unregister with the /proc/net file here. */ - proc_net_remove("strip"); + proc_net_remove(&init_net, "strip"); if ((i = tty_unregister_ldisc(N_STRIP))) printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); diff --git a/fs/proc/Makefile b/fs/proc/Makefile index bce38e3f06cb..ebaba0213546 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -11,6 +11,7 @@ proc-y += inode.o root.o base.o generic.o array.o \ proc_tty.o proc_misc.o proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o +proc-$(CONFIG_NET) += proc_net.o proc-$(CONFIG_PROC_KCORE) += kcore.o proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o diff --git a/fs/proc/internal.h b/fs/proc/internal.h index b215c3524fa6..1820eb2ef762 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -16,6 +16,11 @@ extern int proc_sys_init(void); #else static inline void proc_sys_init(void) { } #endif +#ifdef CONFIG_NET +extern int proc_net_init(void); +#else +static inline int proc_net_init(void) { return 0; } +#endif struct vmalloc_info { unsigned long used; diff --git a/fs/proc/root.c b/fs/proc/root.c index 41f17037f738..cf3046638b09 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -21,7 +21,7 @@ #include "internal.h" -struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; +struct proc_dir_entry *proc_bus, *proc_root_fs, *proc_root_driver; static int proc_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) @@ -61,8 +61,8 @@ void __init proc_root_init(void) return; } proc_misc_init(); - proc_net = proc_mkdir("net", NULL); - proc_net_stat = proc_mkdir("net/stat", NULL); + + proc_net_init(); #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); @@ -159,7 +159,5 @@ EXPORT_SYMBOL(create_proc_entry); EXPORT_SYMBOL(remove_proc_entry); EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_root_fs); -EXPORT_SYMBOL(proc_net); -EXPORT_SYMBOL(proc_net_stat); EXPORT_SYMBOL(proc_bus); EXPORT_SYMBOL(proc_root_driver); diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index cd13a78c5db8..59646705f151 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -7,6 +7,7 @@ #include #include +struct net; struct completion; /* @@ -97,8 +98,6 @@ struct vmcore { extern struct proc_dir_entry proc_root; extern struct proc_dir_entry *proc_root_fs; -extern struct proc_dir_entry *proc_net; -extern struct proc_dir_entry *proc_net_stat; extern struct proc_dir_entry *proc_bus; extern struct proc_dir_entry *proc_root_driver; extern struct proc_dir_entry *proc_root_kcore; @@ -192,36 +191,21 @@ static inline struct proc_dir_entry *create_proc_info_entry(const char *name, if (res) res->get_info=get_info; return res; } - -static inline struct proc_dir_entry *proc_net_create(const char *name, - mode_t mode, get_info_t *get_info) -{ - return create_proc_info_entry(name,mode,proc_net,get_info); -} -static inline struct proc_dir_entry *proc_net_fops_create(const char *name, - mode_t mode, const struct file_operations *fops) -{ - struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net); - if (res) - res->proc_fops = fops; - return res; -} - -static inline void proc_net_remove(const char *name) -{ - remove_proc_entry(name,proc_net); -} +extern struct proc_dir_entry *proc_net_create(struct net *net, + const char *name, mode_t mode, get_info_t *get_info); +extern struct proc_dir_entry *proc_net_fops_create(struct net *net, + const char *name, mode_t mode, const struct file_operations *fops); +extern void proc_net_remove(struct net *net, const char *name); #else #define proc_root_driver NULL -#define proc_net NULL #define proc_bus NULL -#define proc_net_fops_create(name, mode, fops) ({ (void)(mode), NULL; }) -#define proc_net_create(name, mode, info) ({ (void)(mode), NULL; }) -static inline void proc_net_remove(const char *name) {} +#define proc_net_fops_create(net, name, mode, fops) ({ (void)(mode), NULL; }) +#define proc_net_create(net, name, mode, info) ({ (void)(mode), NULL; }) +static inline void proc_net_remove(struct net *net, const char *name) {} static inline void proc_flush_task(struct task_struct *task) { } @@ -281,6 +265,16 @@ static inline struct proc_dir_entry *PDE(const struct inode *inode) return PROC_I(inode)->pde; } +static inline struct net *PDE_NET(struct proc_dir_entry *pde) +{ + return pde->parent->data; +} + +static inline struct net *PROC_NET(const struct inode *inode) +{ + return PDE_NET(PDE(inode)); +} + struct proc_maps_private { struct pid *pid; struct task_struct *task; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 6344b77f81a2..547247681345 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -8,6 +8,7 @@ #include #include +struct proc_dir_entry; struct net { atomic_t count; /* To decided when the network * namespace should be freed. @@ -17,6 +18,10 @@ struct net { */ struct list_head list; /* list of network namespaces */ struct work_struct work; /* work struct for freeing */ + + struct proc_dir_entry *proc_net; + struct proc_dir_entry *proc_net_stat; + struct proc_dir_entry *proc_net_root; }; extern struct net init_net; diff --git a/net/802/tr.c b/net/802/tr.c index e56e61a7f545..032c31e748eb 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -36,6 +36,7 @@ #include #include #include +#include static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev); static void rif_check_expire(unsigned long dummy); @@ -639,7 +640,7 @@ static int __init rif_init(void) rif_timer.function = rif_check_expire; add_timer(&rif_timer); - proc_net_fops_create("tr_rif", S_IRUGO, &rif_seq_fops); + proc_net_fops_create(&init_net, "tr_rif", S_IRUGO, &rif_seq_fops); return 0; } diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index bd08aa090763..ac80e6b9ef53 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "vlanproc.h" #include "vlan.h" @@ -143,7 +144,7 @@ void vlan_proc_cleanup(void) remove_proc_entry(name_conf, proc_vlan_dir); if (proc_vlan_dir) - proc_net_remove(name_root); + proc_net_remove(&init_net, name_root); /* Dynamically added entries should be cleaned up as their vlan_device * is removed, so we should not have to take care of it here... @@ -156,7 +157,7 @@ void vlan_proc_cleanup(void) int __init vlan_proc_init(void) { - proc_vlan_dir = proc_mkdir(name_root, proc_net); + proc_vlan_dir = proc_mkdir(name_root, init_net.proc_net); if (proc_vlan_dir) { proc_vlan_conf = create_proc_entry(name_conf, S_IFREG|S_IRUSR|S_IWUSR, diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c index 87a582cc8111..05d9652afcb6 100644 --- a/net/appletalk/atalk_proc.c +++ b/net/appletalk/atalk_proc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -271,7 +272,7 @@ int __init atalk_proc_init(void) struct proc_dir_entry *p; int rc = -ENOMEM; - atalk_proc_dir = proc_mkdir("atalk", proc_net); + atalk_proc_dir = proc_mkdir("atalk", init_net.proc_net); if (!atalk_proc_dir) goto out; atalk_proc_dir->owner = THIS_MODULE; @@ -306,7 +307,7 @@ out_socket: out_route: remove_proc_entry("interface", atalk_proc_dir); out_interface: - remove_proc_entry("atalk", proc_net); + remove_proc_entry("atalk", init_net.proc_net); goto out; } @@ -316,5 +317,5 @@ void __exit atalk_proc_exit(void) remove_proc_entry("route", atalk_proc_dir); remove_proc_entry("socket", atalk_proc_dir); remove_proc_entry("arp", atalk_proc_dir); - remove_proc_entry("atalk", proc_net); + remove_proc_entry("atalk", init_net.proc_net); } diff --git a/net/atm/proc.c b/net/atm/proc.c index 99fc1fe950ee..3a6be64b0512 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -22,6 +22,7 @@ #include #include #include /* for __init */ +#include #include #include #include @@ -475,7 +476,7 @@ static void atm_proc_dirs_remove(void) if (e->dirent) remove_proc_entry(e->name, atm_proc_root); } - remove_proc_entry("net/atm", NULL); + remove_proc_entry("atm", init_net.proc_net); } int __init atm_proc_init(void) @@ -483,7 +484,7 @@ int __init atm_proc_init(void) static struct atm_proc_entry *e; int ret; - atm_proc_root = proc_mkdir("net/atm",NULL); + atm_proc_root = proc_mkdir("atm", init_net.proc_net); if (!atm_proc_root) goto err_out; for (e = atm_proc_ents; e->name; e++) { diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index dae2a42d3d86..1d71f85680b8 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -1998,9 +1999,9 @@ static int __init ax25_init(void) register_netdevice_notifier(&ax25_dev_notifier); ax25_register_sysctl(); - proc_net_fops_create("ax25_route", S_IRUGO, &ax25_route_fops); - proc_net_fops_create("ax25", S_IRUGO, &ax25_info_fops); - proc_net_fops_create("ax25_calls", S_IRUGO, &ax25_uid_fops); + proc_net_fops_create(&init_net, "ax25_route", S_IRUGO, &ax25_route_fops); + proc_net_fops_create(&init_net, "ax25", S_IRUGO, &ax25_info_fops); + proc_net_fops_create(&init_net, "ax25_calls", S_IRUGO, &ax25_uid_fops); out: return rc; } @@ -2014,9 +2015,9 @@ MODULE_ALIAS_NETPROTO(PF_AX25); static void __exit ax25_exit(void) { - proc_net_remove("ax25_route"); - proc_net_remove("ax25"); - proc_net_remove("ax25_calls"); + proc_net_remove(&init_net, "ax25_route"); + proc_net_remove(&init_net, "ax25"); + proc_net_remove(&init_net, "ax25_calls"); ax25_rt_free(); ax25_uid_free(); ax25_dev_free(); diff --git a/net/core/dev.c b/net/core/dev.c index 29cf00c5d865..618fb1c1dd47 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -92,6 +92,7 @@ #include #include #include +#include #include #include #include @@ -2556,24 +2557,24 @@ static int __init dev_proc_init(void) { int rc = -ENOMEM; - if (!proc_net_fops_create("dev", S_IRUGO, &dev_seq_fops)) + if (!proc_net_fops_create(&init_net, "dev", S_IRUGO, &dev_seq_fops)) goto out; - if (!proc_net_fops_create("softnet_stat", S_IRUGO, &softnet_seq_fops)) + if (!proc_net_fops_create(&init_net, "softnet_stat", S_IRUGO, &softnet_seq_fops)) goto out_dev; - if (!proc_net_fops_create("ptype", S_IRUGO, &ptype_seq_fops)) - goto out_dev2; + if (!proc_net_fops_create(&init_net, "ptype", S_IRUGO, &ptype_seq_fops)) + goto out_softnet; if (wext_proc_init()) - goto out_softnet; + goto out_ptype; rc = 0; out: return rc; +out_ptype: + proc_net_remove(&init_net, "ptype"); out_softnet: - proc_net_remove("ptype"); -out_dev2: - proc_net_remove("softnet_stat"); + proc_net_remove(&init_net, "softnet_stat"); out_dev: - proc_net_remove("dev"); + proc_net_remove(&init_net, "dev"); goto out; } #else diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 20330c572610..8e069fc207cb 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -254,7 +255,7 @@ static const struct file_operations dev_mc_seq_fops = { void __init dev_mcast_init(void) { - proc_net_fops_create("dev_mcast", 0, &dev_mc_seq_fops); + proc_net_fops_create(&init_net, "dev_mcast", 0, &dev_mc_seq_fops); } EXPORT_SYMBOL(dev_mc_add); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index ecd43c4a2221..5f25f4f79b8c 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -25,6 +25,7 @@ #include #endif #include +#include #include #include #include @@ -1350,7 +1351,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) panic("cannot create neighbour cache statistics"); #ifdef CONFIG_PROC_FS - tbl->pde = create_proc_entry(tbl->id, 0, proc_net_stat); + tbl->pde = create_proc_entry(tbl->id, 0, init_net.proc_net_stat); if (!tbl->pde) panic("cannot create neighbour proc dir entry"); tbl->pde->proc_fops = &neigh_stat_seq_fops; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 84c0edeedf6d..33d7247fb19d 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -152,6 +152,7 @@ #include #include #include +#include #include #include #include @@ -3808,7 +3809,7 @@ static int __init pg_init(void) printk(KERN_INFO "%s", version); - pg_proc_dir = proc_mkdir(PG_PROC_DIR, proc_net); + pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net); if (!pg_proc_dir) return -ENODEV; pg_proc_dir->owner = THIS_MODULE; @@ -3817,7 +3818,7 @@ static int __init pg_init(void) if (pe == NULL) { printk(KERN_ERR "pktgen: ERROR: cannot create %s " "procfs entry.\n", PGCTRL); - proc_net_remove(PG_PROC_DIR); + proc_net_remove(&init_net, PG_PROC_DIR); return -EINVAL; } @@ -3841,7 +3842,7 @@ static int __init pg_init(void) "all threads\n"); unregister_netdevice_notifier(&pktgen_notifier_block); remove_proc_entry(PGCTRL, pg_proc_dir); - proc_net_remove(PG_PROC_DIR); + proc_net_remove(&init_net, PG_PROC_DIR); return -ENODEV; } @@ -3868,7 +3869,7 @@ static void __exit pg_cleanup(void) /* Clean up proc file system */ remove_proc_entry(PGCTRL, pg_proc_dir); - proc_net_remove(PG_PROC_DIR); + proc_net_remove(&init_net, PG_PROC_DIR); } module_init(pg_init); diff --git a/net/core/sock.c b/net/core/sock.c index beb924c248e8..bbc726a49d87 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -119,6 +119,7 @@ #include #include #include +#include #include #include #include @@ -1973,7 +1974,7 @@ static const struct file_operations proto_seq_fops = { static int __init proto_init(void) { /* register /proc/net/protocols */ - return proc_net_fops_create("protocols", S_IRUGO, &proto_seq_fops) == NULL ? -ENOBUFS : 0; + return proc_net_fops_create(&init_net, "protocols", S_IRUGO, &proto_seq_fops) == NULL ? -ENOBUFS : 0; } subsys_initcall(proto_init); diff --git a/net/dccp/probe.c b/net/dccp/probe.c index bae10b0f2fc3..7053bb827bc8 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "dccp.h" #include "ccid.h" @@ -168,7 +169,7 @@ static __init int dccpprobe_init(void) if (IS_ERR(dccpw.fifo)) return PTR_ERR(dccpw.fifo); - if (!proc_net_fops_create(procname, S_IRUSR, &dccpprobe_fops)) + if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &dccpprobe_fops)) goto err0; ret = register_jprobe(&dccp_send_probe); @@ -178,7 +179,7 @@ static __init int dccpprobe_init(void) pr_info("DCCP watch registered (port=%d)\n", port); return 0; err1: - proc_net_remove(procname); + proc_net_remove(&init_net, procname); err0: kfifo_free(dccpw.fifo); return ret; @@ -188,7 +189,7 @@ module_init(dccpprobe_init); static __exit void dccpprobe_exit(void) { kfifo_free(dccpw.fifo); - proc_net_remove(procname); + proc_net_remove(&init_net, procname); unregister_jprobe(&dccp_send_probe); } diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index ed76d4aab4a9..625d5955b8e2 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -128,6 +128,7 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat #include #include #include +#include #include #include #include @@ -2399,7 +2400,7 @@ static int __init decnet_init(void) dev_add_pack(&dn_dix_packet_type); register_netdevice_notifier(&dn_dev_notifier); - proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops); + proc_net_fops_create(&init_net, "decnet", S_IRUGO, &dn_socket_seq_fops); dn_register_sysctl(); out: return rc; @@ -2428,7 +2429,7 @@ static void __exit decnet_exit(void) dn_neigh_cleanup(); dn_fib_cleanup(); - proc_net_remove("decnet"); + proc_net_remove(&init_net, "decnet"); proto_unregister(&dn_proto); } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 8def68209edd..83cb0761336a 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1462,7 +1463,7 @@ void __init dn_dev_init(void) rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL); rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr); - proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops); + proc_net_fops_create(&init_net, "decnet_dev", S_IRUGO, &dn_dev_seq_fops); #ifdef CONFIG_SYSCTL { @@ -1483,7 +1484,7 @@ void __exit dn_dev_cleanup(void) } #endif /* CONFIG_SYSCTL */ - proc_net_remove("decnet_dev"); + proc_net_remove(&init_net, "decnet_dev"); dn_dev_devices_off(); } diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 174d8a7a6dac..a424a8ddbaf7 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -611,11 +612,11 @@ static const struct file_operations dn_neigh_seq_fops = { void __init dn_neigh_init(void) { neigh_table_init(&dn_neigh_table); - proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops); + proc_net_fops_create(&init_net, "decnet_neigh", S_IRUGO, &dn_neigh_seq_fops); } void __exit dn_neigh_cleanup(void) { - proc_net_remove("decnet_neigh"); + proc_net_remove(&init_net, "decnet_neigh"); neigh_table_clear(&dn_neigh_table); } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index a4a620971ef0..4cfea9563d2a 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -1814,7 +1815,7 @@ void __init dn_route_init(void) dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1); - proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops); + proc_net_fops_create(&init_net, "decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops); #ifdef CONFIG_DECNET_ROUTER rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute, dn_fib_dump); @@ -1829,6 +1830,6 @@ void __exit dn_route_cleanup(void) del_timer(&dn_route_timer); dn_run_flush(0); - proc_net_remove("decnet_cache"); + proc_net_remove(&init_net, "decnet_cache"); } diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 17ad278696ed..69cb6aad25be 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -264,7 +265,7 @@ static int __init ieee80211_init(void) struct proc_dir_entry *e; ieee80211_debug_level = debug; - ieee80211_proc = proc_mkdir(DRV_NAME, proc_net); + ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net); if (ieee80211_proc == NULL) { IEEE80211_ERROR("Unable to create " DRV_NAME " proc directory\n"); @@ -273,7 +274,7 @@ static int __init ieee80211_init(void) e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, ieee80211_proc); if (!e) { - remove_proc_entry(DRV_NAME, proc_net); + remove_proc_entry(DRV_NAME, init_net.proc_net); ieee80211_proc = NULL; return -EIO; } @@ -293,7 +294,7 @@ static void __exit ieee80211_exit(void) #ifdef CONFIG_IEEE80211_DEBUG if (ieee80211_proc) { remove_proc_entry("debug_level", ieee80211_proc); - remove_proc_entry(DRV_NAME, proc_net); + remove_proc_entry(DRV_NAME, init_net.proc_net); ieee80211_proc = NULL; } #endif /* CONFIG_IEEE80211_DEBUG */ diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 9ab9d534fbac..78dd3443016c 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -103,6 +103,7 @@ #include #endif +#include #include #include #include @@ -1400,7 +1401,7 @@ static const struct file_operations arp_seq_fops = { static int __init arp_proc_init(void) { - if (!proc_net_fops_create("arp", S_IRUGO, &arp_seq_fops)) + if (!proc_net_fops_create(&init_net, "arp", S_IRUGO, &arp_seq_fops)) return -ENOMEM; return 0; } diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 9ad1d9ff9ce7..9fafbeea8fe6 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -1068,13 +1069,13 @@ static const struct file_operations fib_seq_fops = { int __init fib_proc_init(void) { - if (!proc_net_fops_create("route", S_IRUGO, &fib_seq_fops)) + if (!proc_net_fops_create(&init_net, "route", S_IRUGO, &fib_seq_fops)) return -ENOMEM; return 0; } void __init fib_proc_exit(void) { - proc_net_remove("route"); + proc_net_remove(&init_net, "route"); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 52b2891c63b7..be34bd556d58 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -2530,30 +2531,30 @@ static const struct file_operations fib_route_fops = { int __init fib_proc_init(void) { - if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_fops)) + if (!proc_net_fops_create(&init_net, "fib_trie", S_IRUGO, &fib_trie_fops)) goto out1; - if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_fops)) + if (!proc_net_fops_create(&init_net, "fib_triestat", S_IRUGO, &fib_triestat_fops)) goto out2; - if (!proc_net_fops_create("route", S_IRUGO, &fib_route_fops)) + if (!proc_net_fops_create(&init_net, "route", S_IRUGO, &fib_route_fops)) goto out3; return 0; out3: - proc_net_remove("fib_triestat"); + proc_net_remove(&init_net, "fib_triestat"); out2: - proc_net_remove("fib_trie"); + proc_net_remove(&init_net, "fib_trie"); out1: return -ENOMEM; } void __init fib_proc_exit(void) { - proc_net_remove("fib_trie"); - proc_net_remove("fib_triestat"); - proc_net_remove("route"); + proc_net_remove(&init_net, "fib_trie"); + proc_net_remove(&init_net, "fib_triestat"); + proc_net_remove(&init_net, "route"); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a646409c2d06..d78599a9dbd5 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -91,6 +91,7 @@ #include #include +#include #include #include #include @@ -2613,8 +2614,8 @@ static const struct file_operations igmp_mcf_seq_fops = { int __init igmp_mc_proc_init(void) { - proc_net_fops_create("igmp", S_IRUGO, &igmp_mc_seq_fops); - proc_net_fops_create("mcfilter", S_IRUGO, &igmp_mcf_seq_fops); + proc_net_fops_create(&init_net, "igmp", S_IRUGO, &igmp_mc_seq_fops); + proc_net_fops_create(&init_net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops); return 0; } #endif diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index c5b247077539..5ae4849878a3 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -1253,7 +1254,7 @@ static int __init ip_auto_config(void) __be32 addr; #ifdef CONFIG_PROC_FS - proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops); + proc_net_fops_create(&init_net, "pnp", S_IRUGO, &pnp_seq_fops); #endif /* CONFIG_PROC_FS */ if (!ic_enable) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 7003cc1b7fe2..35683e1a42e8 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -1922,7 +1923,7 @@ void __init ip_mr_init(void) ipmr_expire_timer.function=ipmr_expire_process; register_netdevice_notifier(&ip_mr_notifier); #ifdef CONFIG_PROC_FS - proc_net_fops_create("ip_mr_vif", 0, &ipmr_vif_fops); - proc_net_fops_create("ip_mr_cache", 0, &ipmr_mfc_fops); + proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops); + proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops); #endif } diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c index 8d6901d4e94f..341474eefa55 100644 --- a/net/ipv4/ipvs/ip_vs_app.c +++ b/net/ipv4/ipvs/ip_vs_app.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -616,12 +617,12 @@ int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri, int ip_vs_app_init(void) { /* we will replace it with proc_net_ipvs_create() soon */ - proc_net_fops_create("ip_vs_app", 0, &ip_vs_app_fops); + proc_net_fops_create(&init_net, "ip_vs_app", 0, &ip_vs_app_fops); return 0; } void ip_vs_app_cleanup(void) { - proc_net_remove("ip_vs_app"); + proc_net_remove(&init_net, "ip_vs_app"); } diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index d612a6a5d957..4b702f708d30 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -35,6 +35,7 @@ #include #include +#include #include @@ -922,7 +923,7 @@ int ip_vs_conn_init(void) rwlock_init(&__ip_vs_conntbl_lock_array[idx].l); } - proc_net_fops_create("ip_vs_conn", 0, &ip_vs_conn_fops); + proc_net_fops_create(&init_net, "ip_vs_conn", 0, &ip_vs_conn_fops); /* calculate the random value for connection hash */ get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd)); @@ -938,6 +939,6 @@ void ip_vs_conn_cleanup(void) /* Release the empty cache */ kmem_cache_destroy(ip_vs_conn_cachep); - proc_net_remove("ip_vs_conn"); + proc_net_remove(&init_net, "ip_vs_conn"); vfree(ip_vs_conn_tab); } diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index f656d41d8d41..61d023d58b5d 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -2356,8 +2357,8 @@ int ip_vs_control_init(void) return ret; } - proc_net_fops_create("ip_vs", 0, &ip_vs_info_fops); - proc_net_fops_create("ip_vs_stats",0, &ip_vs_stats_fops); + proc_net_fops_create(&init_net, "ip_vs", 0, &ip_vs_info_fops); + proc_net_fops_create(&init_net, "ip_vs_stats",0, &ip_vs_stats_fops); sysctl_header = register_sysctl_table(vs_root_table); @@ -2390,8 +2391,8 @@ void ip_vs_control_cleanup(void) cancel_work_sync(&defense_work.work); ip_vs_kill_estimator(&ip_vs_stats); unregister_sysctl_table(sysctl_header); - proc_net_remove("ip_vs_stats"); - proc_net_remove("ip_vs"); + proc_net_remove(&init_net, "ip_vs_stats"); + proc_net_remove(&init_net, "ip_vs"); nf_unregister_sockopt(&ip_vs_sockopts); LeaveFunction(2); } diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c index 6225acac7a3b..6a1fec416eaf 100644 --- a/net/ipv4/ipvs/ip_vs_lblcr.c +++ b/net/ipv4/ipvs/ip_vs_lblcr.c @@ -50,6 +50,7 @@ #include /* for proc_net_create/proc_net_remove */ #include +#include #include @@ -843,7 +844,7 @@ static int __init ip_vs_lblcr_init(void) INIT_LIST_HEAD(&ip_vs_lblcr_scheduler.n_list); sysctl_header = register_sysctl_table(lblcr_root_table); #ifdef CONFIG_IP_VS_LBLCR_DEBUG - proc_net_create("ip_vs_lblcr", 0, ip_vs_lblcr_getinfo); + proc_net_create(&init_net, "ip_vs_lblcr", 0, ip_vs_lblcr_getinfo); #endif return register_ip_vs_scheduler(&ip_vs_lblcr_scheduler); } @@ -852,7 +853,7 @@ static int __init ip_vs_lblcr_init(void) static void __exit ip_vs_lblcr_cleanup(void) { #ifdef CONFIG_IP_VS_LBLCR_DEBUG - proc_net_remove("ip_vs_lblcr"); + proc_net_remove(&init_net, "ip_vs_lblcr"); #endif unregister_sysctl_table(sysctl_header); unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler); diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 702d94db19b9..cb5e61a1d7ab 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -674,7 +675,7 @@ static int __init ip_queue_init(void) goto cleanup_netlink_notifier; } - proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info); + proc = proc_net_create(&init_net, IPQ_PROC_FS_NAME, 0, ipq_get_info); if (proc) proc->owner = THIS_MODULE; else { @@ -695,8 +696,7 @@ static int __init ip_queue_init(void) cleanup_sysctl: unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); - proc_net_remove(IPQ_PROC_FS_NAME); - + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); cleanup_ipqnl: sock_release(ipqnl->sk_socket); mutex_lock(&ipqnl_mutex); @@ -715,7 +715,7 @@ static void __exit ip_queue_fini(void) unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); - proc_net_remove(IPQ_PROC_FS_NAME); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); sock_release(ipqnl->sk_socket); mutex_lock(&ipqnl_mutex); diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 69bd362b5fa2..50fc9e009fe4 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define CLUSTERIP_VERSION "0.8" @@ -726,7 +727,7 @@ static int __init ipt_clusterip_init(void) goto cleanup_target; #ifdef CONFIG_PROC_FS - clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", proc_net); + clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", init_net.proc_net); if (!clusterip_procdir) { printk(KERN_ERR "CLUSTERIP: Unable to proc dir entry\n"); ret = -ENOMEM; diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 6d0c0f7364ad..db2a79889f9a 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -487,7 +488,7 @@ static int __init ipt_recent_init(void) #ifdef CONFIG_PROC_FS if (err) return err; - proc_dir = proc_mkdir("ipt_recent", proc_net); + proc_dir = proc_mkdir("ipt_recent", init_net.proc_net); if (proc_dir == NULL) { xt_unregister_match(&recent_match); err = -ENOMEM; @@ -501,7 +502,7 @@ static void __exit ipt_recent_exit(void) BUG_ON(!list_empty(&tables)); xt_unregister_match(&recent_match); #ifdef CONFIG_PROC_FS - remove_proc_entry("ipt_recent", proc_net); + remove_proc_entry("ipt_recent", init_net.proc_net); #endif } diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index b3dd5de9a258..a5ae2eabf0f3 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -408,16 +409,16 @@ int __init nf_conntrack_ipv4_compat_init(void) { struct proc_dir_entry *proc, *proc_exp, *proc_stat; - proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops); + proc = proc_net_fops_create(&init_net, "ip_conntrack", 0440, &ct_file_ops); if (!proc) goto err1; - proc_exp = proc_net_fops_create("ip_conntrack_expect", 0440, + proc_exp = proc_net_fops_create(&init_net, "ip_conntrack_expect", 0440, &ip_exp_file_ops); if (!proc_exp) goto err2; - proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat); + proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, init_net.proc_net_stat); if (!proc_stat) goto err3; @@ -427,16 +428,16 @@ int __init nf_conntrack_ipv4_compat_init(void) return 0; err3: - proc_net_remove("ip_conntrack_expect"); + proc_net_remove(&init_net, "ip_conntrack_expect"); err2: - proc_net_remove("ip_conntrack"); + proc_net_remove(&init_net, "ip_conntrack"); err1: return -ENOMEM; } void __exit nf_conntrack_ipv4_compat_fini(void) { - remove_proc_entry("ip_conntrack", proc_net_stat); - proc_net_remove("ip_conntrack_expect"); - proc_net_remove("ip_conntrack"); + remove_proc_entry("ip_conntrack", init_net.proc_net_stat); + proc_net_remove(&init_net, "ip_conntrack_expect"); + proc_net_remove(&init_net, "ip_conntrack"); } diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 986d1c83a000..95a8f8f2de71 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -34,6 +34,7 @@ * 2 of the License, or (at your option) any later version. */ #include +#include #include #include #include @@ -383,20 +384,20 @@ int __init ip_misc_proc_init(void) { int rc = 0; - if (!proc_net_fops_create("netstat", S_IRUGO, &netstat_seq_fops)) + if (!proc_net_fops_create(&init_net, "netstat", S_IRUGO, &netstat_seq_fops)) goto out_netstat; - if (!proc_net_fops_create("snmp", S_IRUGO, &snmp_seq_fops)) + if (!proc_net_fops_create(&init_net, "snmp", S_IRUGO, &snmp_seq_fops)) goto out_snmp; - if (!proc_net_fops_create("sockstat", S_IRUGO, &sockstat_seq_fops)) + if (!proc_net_fops_create(&init_net, "sockstat", S_IRUGO, &sockstat_seq_fops)) goto out_sockstat; out: return rc; out_sockstat: - proc_net_remove("snmp"); + proc_net_remove(&init_net, "snmp"); out_snmp: - proc_net_remove("netstat"); + proc_net_remove(&init_net, "netstat"); out_netstat: rc = -ENOMEM; goto out; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index c6d71526f625..216e01b0f44a 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -928,13 +929,13 @@ static const struct file_operations raw_seq_fops = { int __init raw_proc_init(void) { - if (!proc_net_fops_create("raw", S_IRUGO, &raw_seq_fops)) + if (!proc_net_fops_create(&init_net, "raw", S_IRUGO, &raw_seq_fops)) return -ENOMEM; return 0; } void __init raw_proc_exit(void) { - proc_net_remove("raw"); + proc_net_remove(&init_net, "raw"); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c7ca94bd152c..efd2a9202d68 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -3011,15 +3012,15 @@ int __init ip_rt_init(void) #ifdef CONFIG_PROC_FS { struct proc_dir_entry *rtstat_pde = NULL; /* keep gcc happy */ - if (!proc_net_fops_create("rt_cache", S_IRUGO, &rt_cache_seq_fops) || + if (!proc_net_fops_create(&init_net, "rt_cache", S_IRUGO, &rt_cache_seq_fops) || !(rtstat_pde = create_proc_entry("rt_cache", S_IRUGO, - proc_net_stat))) { + init_net.proc_net_stat))) { return -ENOMEM; } rtstat_pde->proc_fops = &rt_cpu_seq_fops; } #ifdef CONFIG_NET_CLS_ROUTE - create_proc_read_entry("rt_acct", 0, proc_net, ip_rt_acct_read, NULL); + create_proc_read_entry("rt_acct", 0, init_net.proc_net, ip_rt_acct_read, NULL); #endif #endif #ifdef CONFIG_XFRM diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e089a978e128..8855e640e958 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -62,6 +62,7 @@ #include #include +#include #include #include #include @@ -2249,7 +2250,7 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo) afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = seq_release_private; - p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); + p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else @@ -2261,7 +2262,7 @@ void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo) { if (!afinfo) return; - proc_net_remove(afinfo->name); + proc_net_remove(&init_net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index b76398d1b454..87dd5bff315f 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -228,7 +229,7 @@ static __init int tcpprobe_init(void) if (!tcp_probe.log) goto err0; - if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops)) + if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &tcpprobe_fops)) goto err0; ret = register_jprobe(&tcp_jprobe); @@ -238,7 +239,7 @@ static __init int tcpprobe_init(void) pr_info("TCP probe registered (port=%d)\n", port); return 0; err1: - proc_net_remove(procname); + proc_net_remove(&init_net, procname); err0: kfree(tcp_probe.log); return ret; @@ -247,7 +248,7 @@ module_init(tcpprobe_init); static __exit void tcpprobe_exit(void) { - proc_net_remove(procname); + proc_net_remove(&init_net, procname); unregister_jprobe(&tcp_jprobe); kfree(tcp_probe.log); } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a581b543bff7..ef4d901ee9ad 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -98,6 +98,7 @@ #include #include #include +#include #include #include #include @@ -1566,7 +1567,7 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo) afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = seq_release_private; - p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); + p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else @@ -1578,7 +1579,7 @@ void udp_proc_unregister(struct udp_seq_afinfo *afinfo) { if (!afinfo) return; - proc_net_remove(afinfo->name); + proc_net_remove(&init_net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 45b4c82148a0..cd2db728d183 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -62,6 +62,7 @@ #include #include +#include #include #include @@ -2827,14 +2828,14 @@ static const struct file_operations if6_fops = { int __init if6_proc_init(void) { - if (!proc_net_fops_create("if_inet6", S_IRUGO, &if6_fops)) + if (!proc_net_fops_create(&init_net, "if_inet6", S_IRUGO, &if6_fops)) return -ENOMEM; return 0; } void if6_proc_exit(void) { - proc_net_remove("if_inet6"); + proc_net_remove(&init_net, "if_inet6"); } #endif /* CONFIG_PROC_FS */ @@ -4293,6 +4294,6 @@ void __exit addrconf_cleanup(void) rtnl_unlock(); #ifdef CONFIG_PROC_FS - proc_net_remove("if_inet6"); + proc_net_remove(&init_net, "if_inet6"); #endif } diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index b8c533fbdb63..0bd665498d06 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -578,7 +579,7 @@ static const struct file_operations ac6_seq_fops = { int __init ac6_proc_init(void) { - if (!proc_net_fops_create("anycast6", S_IRUGO, &ac6_seq_fops)) + if (!proc_net_fops_create(&init_net, "anycast6", S_IRUGO, &ac6_seq_fops)) return -ENOMEM; return 0; @@ -586,7 +587,7 @@ int __init ac6_proc_init(void) void ac6_proc_exit(void) { - proc_net_remove("anycast6"); + proc_net_remove(&init_net, "anycast6"); } #endif diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 413a4ebb195c..1791399c7f10 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -690,7 +691,7 @@ static const struct file_operations ip6fl_seq_fops = { void ip6_flowlabel_init(void) { #ifdef CONFIG_PROC_FS - proc_net_fops_create("ip6_flowlabel", S_IRUGO, &ip6fl_seq_fops); + proc_net_fops_create(&init_net, "ip6_flowlabel", S_IRUGO, &ip6fl_seq_fops); #endif } @@ -698,6 +699,6 @@ void ip6_flowlabel_cleanup(void) { del_timer(&ip6_fl_gc_timer); #ifdef CONFIG_PROC_FS - proc_net_remove("ip6_flowlabel"); + proc_net_remove(&init_net, "ip6_flowlabel"); #endif } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index ae9881832a7e..a41d5a0b50cc 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -2658,8 +2659,8 @@ int __init igmp6_init(struct net_proto_family *ops) np->hop_limit = 1; #ifdef CONFIG_PROC_FS - proc_net_fops_create("igmp6", S_IRUGO, &igmp6_mc_seq_fops); - proc_net_fops_create("mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); + proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops); + proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); #endif return 0; @@ -2671,7 +2672,7 @@ void igmp6_cleanup(void) igmp6_socket = NULL; /* for safety */ #ifdef CONFIG_PROC_FS - proc_net_remove("mcfilter6"); - proc_net_remove("igmp6"); + proc_net_remove(&init_net, "mcfilter6"); + proc_net_remove(&init_net, "igmp6"); #endif } diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 0004db38af6d..dfc58fbdb68b 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -664,7 +665,7 @@ static int __init ip6_queue_init(void) goto cleanup_netlink_notifier; } - proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info); + proc = proc_net_create(&init_net, IPQ_PROC_FS_NAME, 0, ipq_get_info); if (proc) proc->owner = THIS_MODULE; else { @@ -685,7 +686,7 @@ static int __init ip6_queue_init(void) cleanup_sysctl: unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); - proc_net_remove(IPQ_PROC_FS_NAME); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); cleanup_ipqnl: sock_release(ipqnl->sk_socket); @@ -705,7 +706,7 @@ static void __exit ip6_queue_fini(void) unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); - proc_net_remove(IPQ_PROC_FS_NAME); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); sock_release(ipqnl->sk_socket); mutex_lock(&ipqnl_mutex); diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 920dc9cf6a84..a712a2289484 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -231,22 +232,22 @@ int __init ipv6_misc_proc_init(void) { int rc = 0; - if (!proc_net_fops_create("snmp6", S_IRUGO, &snmp6_seq_fops)) + if (!proc_net_fops_create(&init_net, "snmp6", S_IRUGO, &snmp6_seq_fops)) goto proc_snmp6_fail; - proc_net_devsnmp6 = proc_mkdir("dev_snmp6", proc_net); + proc_net_devsnmp6 = proc_mkdir("dev_snmp6", init_net.proc_net); if (!proc_net_devsnmp6) goto proc_dev_snmp6_fail; - if (!proc_net_fops_create("sockstat6", S_IRUGO, &sockstat6_seq_fops)) + if (!proc_net_fops_create(&init_net, "sockstat6", S_IRUGO, &sockstat6_seq_fops)) goto proc_sockstat6_fail; out: return rc; proc_sockstat6_fail: - proc_net_remove("dev_snmp6"); + proc_net_remove(&init_net, "dev_snmp6"); proc_dev_snmp6_fail: - proc_net_remove("snmp6"); + proc_net_remove(&init_net, "snmp6"); proc_snmp6_fail: rc = -ENOMEM; goto out; @@ -254,8 +255,8 @@ proc_snmp6_fail: void ipv6_misc_proc_exit(void) { - proc_net_remove("sockstat6"); - proc_net_remove("dev_snmp6"); - proc_net_remove("snmp6"); + proc_net_remove(&init_net, "sockstat6"); + proc_net_remove(&init_net, "dev_snmp6"); + proc_net_remove(&init_net, "snmp6"); } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 77167afa3455..38a3d21c2585 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -1315,13 +1316,13 @@ static const struct file_operations raw6_seq_fops = { int __init raw6_proc_init(void) { - if (!proc_net_fops_create("raw6", S_IRUGO, &raw6_seq_fops)) + if (!proc_net_fops_create(&init_net, "raw6", S_IRUGO, &raw6_seq_fops)) return -ENOMEM; return 0; } void raw6_proc_exit(void) { - proc_net_remove("raw6"); + proc_net_remove(&init_net, "raw6"); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 55ea80fac601..f4f0c341e5c8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -44,6 +44,7 @@ #include #endif +#include #include #include #include @@ -2561,11 +2562,11 @@ void __init ip6_route_init(void) fib6_init(); #ifdef CONFIG_PROC_FS - p = proc_net_create("ipv6_route", 0, rt6_proc_info); + p = proc_net_create(&init_net, "ipv6_route", 0, rt6_proc_info); if (p) p->owner = THIS_MODULE; - proc_net_fops_create("rt6_stats", S_IRUGO, &rt6_stats_seq_fops); + proc_net_fops_create(&init_net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); #endif #ifdef CONFIG_XFRM xfrm6_init(); @@ -2585,8 +2586,8 @@ void ip6_route_cleanup(void) fib6_rules_cleanup(); #endif #ifdef CONFIG_PROC_FS - proc_net_remove("ipv6_route"); - proc_net_remove("rt6_stats"); + proc_net_remove(&init_net, "ipv6_route"); + proc_net_remove(&init_net, "rt6_stats"); #endif #ifdef CONFIG_XFRM xfrm6_fini(); diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c index 4226e71ae1e3..d483a00dc427 100644 --- a/net/ipx/ipx_proc.c +++ b/net/ipx/ipx_proc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -353,7 +354,7 @@ int __init ipx_proc_init(void) struct proc_dir_entry *p; int rc = -ENOMEM; - ipx_proc_dir = proc_mkdir("ipx", proc_net); + ipx_proc_dir = proc_mkdir("ipx", init_net.proc_net); if (!ipx_proc_dir) goto out; @@ -381,7 +382,7 @@ out_socket: out_route: remove_proc_entry("interface", ipx_proc_dir); out_interface: - remove_proc_entry("ipx", proc_net); + remove_proc_entry("ipx", init_net.proc_net); goto out; } @@ -390,7 +391,7 @@ void __exit ipx_proc_exit(void) remove_proc_entry("interface", ipx_proc_dir); remove_proc_entry("route", ipx_proc_dir); remove_proc_entry("socket", ipx_proc_dir); - remove_proc_entry("ipx", proc_net); + remove_proc_entry("ipx", init_net.proc_net); } #else /* CONFIG_PROC_FS */ diff --git a/net/irda/irproc.c b/net/irda/irproc.c index 181cb51b48a8..cae24fbda966 100644 --- a/net/irda/irproc.c +++ b/net/irda/irproc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -66,7 +67,7 @@ void __init irda_proc_register(void) int i; struct proc_dir_entry *d; - proc_irda = proc_mkdir("irda", proc_net); + proc_irda = proc_mkdir("irda", init_net.proc_net); if (proc_irda == NULL) return; proc_irda->owner = THIS_MODULE; @@ -92,7 +93,7 @@ void irda_proc_unregister(void) for (i=0; i #include #include +#include #include #include @@ -3776,7 +3777,7 @@ static struct xfrm_mgr pfkeyv2_mgr = static void __exit ipsec_pfkey_exit(void) { xfrm_unregister_km(&pfkeyv2_mgr); - remove_proc_entry("net/pfkey", NULL); + remove_proc_entry("pfkey", init_net.proc_net); sock_unregister(PF_KEY); proto_unregister(&key_proto); } @@ -3793,7 +3794,7 @@ static int __init ipsec_pfkey_init(void) goto out_unregister_key_proto; #ifdef CONFIG_PROC_FS err = -ENOMEM; - if (create_proc_read_entry("net/pfkey", 0, NULL, pfkey_read_proc, NULL) == NULL) + if (create_proc_read_entry("pfkey", 0, init_net.proc_net, pfkey_read_proc, NULL) == NULL) goto out_sock_unregister; #endif err = xfrm_register_km(&pfkeyv2_mgr); diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 49be6c902c83..4865d82896b1 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -231,7 +232,7 @@ int __init llc_proc_init(void) int rc = -ENOMEM; struct proc_dir_entry *p; - llc_proc_dir = proc_mkdir("llc", proc_net); + llc_proc_dir = proc_mkdir("llc", init_net.proc_net); if (!llc_proc_dir) goto out; llc_proc_dir->owner = THIS_MODULE; @@ -254,7 +255,7 @@ out: out_core: remove_proc_entry("socket", llc_proc_dir); out_socket: - remove_proc_entry("llc", proc_net); + remove_proc_entry("llc", init_net.proc_net); goto out; } @@ -262,5 +263,5 @@ void llc_proc_exit(void) { remove_proc_entry("socket", llc_proc_dir); remove_proc_entry("core", llc_proc_dir); - remove_proc_entry("llc", proc_net); + remove_proc_entry("llc", init_net.proc_net); } diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 381a77cf0c9e..a523fa4136ed 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "nf_internals.h" @@ -293,7 +294,7 @@ void __init netfilter_init(void) } #ifdef CONFIG_PROC_FS - proc_net_netfilter = proc_mkdir("netfilter", proc_net); + proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net); if (!proc_net_netfilter) panic("cannot create netfilter proc entry"); #endif diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 3ac64e25f10c..8a3e3af656bf 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -505,7 +506,7 @@ static int __init exp_proc_init(void) #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc; - proc = proc_net_fops_create("nf_conntrack_expect", 0440, &exp_file_ops); + proc = proc_net_fops_create(&init_net, "nf_conntrack_expect", 0440, &exp_file_ops); if (!proc) return -ENOMEM; #endif /* CONFIG_PROC_FS */ @@ -515,7 +516,7 @@ static int __init exp_proc_init(void) static void exp_proc_remove(void) { #ifdef CONFIG_PROC_FS - proc_net_remove("nf_conntrack_expect"); + proc_net_remove(&init_net, "nf_conntrack_expect"); #endif /* CONFIG_PROC_FS */ } diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index a4ce5e887997..2a19c5f1240f 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef CONFIG_SYSCTL #include #endif @@ -420,10 +421,10 @@ static int __init nf_conntrack_standalone_init(void) return ret; #ifdef CONFIG_PROC_FS - proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops); + proc = proc_net_fops_create(&init_net, "nf_conntrack", 0440, &ct_file_ops); if (!proc) goto cleanup_init; - proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat); + proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, init_net.proc_net_stat); if (!proc_stat) goto cleanup_proc; @@ -444,9 +445,9 @@ static int __init nf_conntrack_standalone_init(void) cleanup_proc_stat: #endif #ifdef CONFIG_PROC_FS - remove_proc_entry("nf_conntrack", proc_net_stat); + remove_proc_entry("nf_conntrack", init_net. proc_net_stat); cleanup_proc: - proc_net_remove("nf_conntrack"); + proc_net_remove(&init_net, "nf_conntrack"); cleanup_init: #endif /* CNFIG_PROC_FS */ nf_conntrack_cleanup(); @@ -459,8 +460,8 @@ static void __exit nf_conntrack_standalone_fini(void) unregister_sysctl_table(nf_ct_sysctl_header); #endif #ifdef CONFIG_PROC_FS - remove_proc_entry("nf_conntrack", proc_net_stat); - proc_net_remove("nf_conntrack"); + remove_proc_entry("nf_conntrack", init_net.proc_net_stat); + proc_net_remove(&init_net, "nf_conntrack"); #endif /* CNFIG_PROC_FS */ nf_conntrack_cleanup(); } diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index cc2baa6d5a7a..d9a3bded0d00 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -795,7 +796,7 @@ int xt_proto_init(int af) #ifdef CONFIG_PROC_FS strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TABLES, sizeof(buf)); - proc = proc_net_fops_create(buf, 0440, &xt_file_ops); + proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); if (!proc) goto out; proc->data = (void *) ((unsigned long) af | (TABLE << 16)); @@ -803,14 +804,14 @@ int xt_proto_init(int af) strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_MATCHES, sizeof(buf)); - proc = proc_net_fops_create(buf, 0440, &xt_file_ops); + proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); if (!proc) goto out_remove_tables; proc->data = (void *) ((unsigned long) af | (MATCH << 16)); strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TARGETS, sizeof(buf)); - proc = proc_net_fops_create(buf, 0440, &xt_file_ops); + proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); if (!proc) goto out_remove_matches; proc->data = (void *) ((unsigned long) af | (TARGET << 16)); @@ -822,12 +823,12 @@ int xt_proto_init(int af) out_remove_matches: strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_MATCHES, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); out_remove_tables: strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TABLES, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); out: return -1; #endif @@ -841,15 +842,15 @@ void xt_proto_fini(int af) strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TABLES, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TARGETS, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_MATCHES, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); #endif /*CONFIG_PROC_FS*/ } EXPORT_SYMBOL_GPL(xt_proto_fini); diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index bd45f9d3f7d0..19103678bf20 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -743,13 +744,13 @@ static int __init xt_hashlimit_init(void) printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); goto err2; } - hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", proc_net); + hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", init_net.proc_net); if (!hashlimit_procdir4) { printk(KERN_ERR "xt_hashlimit: unable to create proc dir " "entry\n"); goto err3; } - hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", proc_net); + hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", init_net.proc_net); if (!hashlimit_procdir6) { printk(KERN_ERR "xt_hashlimit: unable to create proc dir " "entry\n"); @@ -757,7 +758,7 @@ static int __init xt_hashlimit_init(void) } return 0; err4: - remove_proc_entry("ipt_hashlimit", proc_net); + remove_proc_entry("ipt_hashlimit", init_net.proc_net); err3: kmem_cache_destroy(hashlimit_cachep); err2: @@ -769,8 +770,8 @@ err1: static void __exit xt_hashlimit_fini(void) { - remove_proc_entry("ipt_hashlimit", proc_net); - remove_proc_entry("ip6t_hashlimit", proc_net); + remove_proc_entry("ipt_hashlimit", init_net.proc_net); + remove_proc_entry("ip6t_hashlimit", init_net.proc_net); kmem_cache_destroy(hashlimit_cachep); xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a78d962e2c70..3982f13dab17 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -57,6 +57,7 @@ #include #include +#include #include #include #include @@ -1927,7 +1928,7 @@ static int __init netlink_proto_init(void) sock_register(&netlink_family_ops); #ifdef CONFIG_PROC_FS - proc_net_fops_create("netlink", 0, &netlink_seq_fops); + proc_net_fops_create(&init_net, "netlink", 0, &netlink_seq_fops); #endif /* The netlink device handler may be needed early. */ rtnetlink_init(); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index dc9273295a38..15c8a92bd719 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1447,9 +1448,9 @@ static int __init nr_proto_init(void) nr_loopback_init(); - proc_net_fops_create("nr", S_IRUGO, &nr_info_fops); - proc_net_fops_create("nr_neigh", S_IRUGO, &nr_neigh_fops); - proc_net_fops_create("nr_nodes", S_IRUGO, &nr_nodes_fops); + proc_net_fops_create(&init_net, "nr", S_IRUGO, &nr_info_fops); + proc_net_fops_create(&init_net, "nr_neigh", S_IRUGO, &nr_neigh_fops); + proc_net_fops_create(&init_net, "nr_nodes", S_IRUGO, &nr_nodes_fops); out: return rc; fail: @@ -1477,9 +1478,9 @@ static void __exit nr_exit(void) { int i; - proc_net_remove("nr"); - proc_net_remove("nr_neigh"); - proc_net_remove("nr_nodes"); + proc_net_remove(&init_net, "nr"); + proc_net_remove(&init_net, "nr_neigh"); + proc_net_remove(&init_net, "nr_nodes"); nr_loopback_clear(); nr_rt_free(); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9c26dd9ee649..56502292f24c 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -1951,7 +1952,7 @@ static const struct file_operations packet_seq_fops = { static void __exit packet_exit(void) { - proc_net_remove("packet"); + proc_net_remove(&init_net, "packet"); unregister_netdevice_notifier(&packet_netdev_notifier); sock_unregister(PF_PACKET); proto_unregister(&packet_proto); @@ -1966,7 +1967,7 @@ static int __init packet_init(void) sock_register(&packet_family_ops); register_netdevice_notifier(&packet_netdev_notifier); - proc_net_fops_create("packet", 0, &packet_seq_fops); + proc_net_fops_create(&init_net, "packet", 0, &packet_seq_fops); out: return rc; } diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 976c3cc86a29..48319f7991ac 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1576,10 +1577,10 @@ static int __init rose_proto_init(void) rose_add_loopback_neigh(); - proc_net_fops_create("rose", S_IRUGO, &rose_info_fops); - proc_net_fops_create("rose_neigh", S_IRUGO, &rose_neigh_fops); - proc_net_fops_create("rose_nodes", S_IRUGO, &rose_nodes_fops); - proc_net_fops_create("rose_routes", S_IRUGO, &rose_routes_fops); + proc_net_fops_create(&init_net, "rose", S_IRUGO, &rose_info_fops); + proc_net_fops_create(&init_net, "rose_neigh", S_IRUGO, &rose_neigh_fops); + proc_net_fops_create(&init_net, "rose_nodes", S_IRUGO, &rose_nodes_fops); + proc_net_fops_create(&init_net, "rose_routes", S_IRUGO, &rose_routes_fops); out: return rc; fail: @@ -1606,10 +1607,10 @@ static void __exit rose_exit(void) { int i; - proc_net_remove("rose"); - proc_net_remove("rose_neigh"); - proc_net_remove("rose_nodes"); - proc_net_remove("rose_routes"); + proc_net_remove(&init_net, "rose"); + proc_net_remove(&init_net, "rose_neigh"); + proc_net_remove(&init_net, "rose_nodes"); + proc_net_remove(&init_net, "rose_routes"); rose_loopback_clear(); rose_rt_free(); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index c58fa0d1be26..122d55d992e1 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "ar-internal.h" @@ -829,8 +830,8 @@ static int __init af_rxrpc_init(void) } #ifdef CONFIG_PROC_FS - proc_net_fops_create("rxrpc_calls", 0, &rxrpc_call_seq_fops); - proc_net_fops_create("rxrpc_conns", 0, &rxrpc_connection_seq_fops); + proc_net_fops_create(&init_net, "rxrpc_calls", 0, &rxrpc_call_seq_fops); + proc_net_fops_create(&init_net, "rxrpc_conns", 0, &rxrpc_connection_seq_fops); #endif return 0; @@ -868,8 +869,8 @@ static void __exit af_rxrpc_exit(void) _debug("flush scheduled work"); flush_workqueue(rxrpc_workqueue); - proc_net_remove("rxrpc_conns"); - proc_net_remove("rxrpc_calls"); + proc_net_remove(&init_net, "rxrpc_conns"); + proc_net_remove(&init_net, "rxrpc_calls"); destroy_workqueue(rxrpc_workqueue); kmem_cache_destroy(rxrpc_call_jar); _leave(""); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index dee0d5fb39c5..efc383c58f1e 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -1251,7 +1252,7 @@ static int __init pktsched_init(void) { register_qdisc(&pfifo_qdisc_ops); register_qdisc(&bfifo_qdisc_ops); - proc_net_fops_create("psched", 0, &psched_fops); + proc_net_fops_create(&init_net, "psched", 0, &psched_fops); rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL); rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 957c118a6068..30929e3ca05a 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -98,7 +99,7 @@ static __init int sctp_proc_init(void) { if (!proc_net_sctp) { struct proc_dir_entry *ent; - ent = proc_mkdir("net/sctp", NULL); + ent = proc_mkdir("sctp", init_net.proc_net); if (ent) { ent->owner = THIS_MODULE; proc_net_sctp = ent; @@ -131,7 +132,7 @@ static void sctp_proc_exit(void) if (proc_net_sctp) { proc_net_sctp = NULL; - remove_proc_entry("net/sctp", NULL); + remove_proc_entry("sctp", init_net.proc_net); } } diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 74ba7d443dfc..4d4f3738b688 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -21,6 +21,7 @@ #include #include #include +#include #define RPCDBG_FACILITY RPCDBG_MISC @@ -265,7 +266,7 @@ rpc_proc_init(void) dprintk("RPC: registering /proc/net/rpc\n"); if (!proc_net_rpc) { struct proc_dir_entry *ent; - ent = proc_mkdir("rpc", proc_net); + ent = proc_mkdir("rpc", init_net.proc_net); if (ent) { ent->owner = THIS_MODULE; proc_net_rpc = ent; @@ -279,7 +280,7 @@ rpc_proc_exit(void) dprintk("RPC: unregistering /proc/net/rpc\n"); if (proc_net_rpc) { proc_net_rpc = NULL; - remove_proc_entry("net/rpc", NULL); + remove_proc_entry("rpc", init_net.proc_net); } } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index a05c34260e70..2386090c3a16 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -103,6 +103,7 @@ #include #include #include +#include #include #include #include @@ -2135,7 +2136,7 @@ static int __init af_unix_init(void) sock_register(&unix_family_ops); #ifdef CONFIG_PROC_FS - proc_net_fops_create("unix", 0, &unix_seq_fops); + proc_net_fops_create(&init_net, "unix", 0, &unix_seq_fops); #endif unix_sysctl_register(); out: @@ -2146,7 +2147,7 @@ static void __exit af_unix_exit(void) { sock_unregister(PF_UNIX); unix_sysctl_unregister(); - proc_net_remove("unix"); + proc_net_remove(&init_net, "unix"); proto_unregister(&unix_proto); } diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c index 236e7eaf1b7f..f2e54c3f064e 100644 --- a/net/wanrouter/wanproc.c +++ b/net/wanrouter/wanproc.c @@ -29,6 +29,7 @@ #include #include +#include #include #define PROC_STATS_FORMAT "%30s: %12lu\n" @@ -287,7 +288,7 @@ static const struct file_operations wandev_fops = { int __init wanrouter_proc_init(void) { struct proc_dir_entry *p; - proc_router = proc_mkdir(ROUTER_NAME, proc_net); + proc_router = proc_mkdir(ROUTER_NAME, init_net.proc_net); if (!proc_router) goto fail; @@ -303,7 +304,7 @@ int __init wanrouter_proc_init(void) fail_stat: remove_proc_entry("config", proc_router); fail_config: - remove_proc_entry(ROUTER_NAME, proc_net); + remove_proc_entry(ROUTER_NAME, init_net.proc_net); fail: return -ENOMEM; } @@ -316,7 +317,7 @@ void wanrouter_proc_cleanup(void) { remove_proc_entry("config", proc_router); remove_proc_entry("status", proc_router); - remove_proc_entry(ROUTER_NAME, proc_net); + remove_proc_entry(ROUTER_NAME, init_net.proc_net); } /* diff --git a/net/wireless/wext.c b/net/wireless/wext.c index debf5191a128..b8069afe0410 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -93,6 +93,7 @@ #include /* ARPHRD_ETHER */ #include /* compare_ether_addr */ #include +#include #include /* Pretty obvious */ #include /* New driver API */ @@ -686,7 +687,7 @@ static const struct file_operations wireless_seq_fops = { int __init wext_proc_init(void) { /* Create /proc/net/wireless entry */ - if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops)) + if (!proc_net_fops_create(&init_net, "wireless", S_IRUGO, &wireless_seq_fops)) return -ENOMEM; return 0; diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c index 7405b9c5b7f2..7d55e50c936f 100644 --- a/net/x25/x25_proc.c +++ b/net/x25/x25_proc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -301,7 +302,7 @@ int __init x25_proc_init(void) struct proc_dir_entry *p; int rc = -ENOMEM; - x25_proc_dir = proc_mkdir("x25", proc_net); + x25_proc_dir = proc_mkdir("x25", init_net.proc_net); if (!x25_proc_dir) goto out; @@ -328,7 +329,7 @@ out_forward: out_socket: remove_proc_entry("route", x25_proc_dir); out_route: - remove_proc_entry("x25", proc_net); + remove_proc_entry("x25", init_net.proc_net); goto out; } @@ -337,7 +338,7 @@ void __exit x25_proc_exit(void) remove_proc_entry("forward", x25_proc_dir); remove_proc_entry("route", x25_proc_dir); remove_proc_entry("socket", x25_proc_dir); - remove_proc_entry("x25", proc_net); + remove_proc_entry("x25", init_net.proc_net); } #else /* CONFIG_PROC_FS */ From 1b8d7ae42d02e483ad94035cca851e4f7fbecb40 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 8 Oct 2007 23:24:22 -0700 Subject: [PATCH 1175/2804] [NET]: Make socket creation namespace safe. This patch passes in the namespace a new socket should be created in and has the socket code do the appropriate reference counting. By virtue of this all socket create methods are touched. In addition the socket create methods are modified so that they will fail if you attempt to create a socket in a non-default network namespace. Failing if we attempt to create a socket outside of the default network namespace ensures that as we incrementally make the network stack network namespace aware we will not export functionality that someone has not audited and made certain is network namespace safe. Allowing us to partially enable network namespaces before all of the exotic protocols are supported. Any protocol layers I have missed will fail to compile because I now pass an extra parameter into the socket creation code. [ Integrated AF_IUCV build fixes from Andrew Morton... -DaveM ] Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/pppoe.c | 4 ++-- drivers/net/pppol2tp.c | 4 ++-- drivers/net/pppox.c | 7 +++++-- include/linux/if_pppox.h | 2 +- include/linux/net.h | 3 ++- include/net/iucv/af_iucv.h | 1 - include/net/llc_conn.h | 2 +- include/net/sock.h | 4 +++- net/appletalk/ddp.c | 7 +++++-- net/atm/common.c | 4 ++-- net/atm/common.h | 2 +- net/atm/pvc.c | 7 +++++-- net/atm/svc.c | 11 +++++++---- net/ax25/af_ax25.c | 9 ++++++--- net/bluetooth/af_bluetooth.c | 7 +++++-- net/bluetooth/bnep/sock.c | 4 ++-- net/bluetooth/cmtp/sock.c | 4 ++-- net/bluetooth/hci_sock.c | 4 ++-- net/bluetooth/hidp/sock.c | 4 ++-- net/bluetooth/l2cap.c | 10 +++++----- net/bluetooth/rfcomm/sock.c | 10 +++++----- net/bluetooth/sco.c | 10 +++++----- net/core/sock.c | 6 ++++-- net/decnet/af_decnet.c | 13 ++++++++----- net/econet/af_econet.c | 7 +++++-- net/ipv4/af_inet.c | 7 +++++-- net/ipv6/af_inet6.c | 7 +++++-- net/ipx/af_ipx.c | 7 +++++-- net/irda/af_irda.c | 11 +++++++---- net/iucv/af_iucv.c | 4 ++-- net/key/af_key.c | 7 +++++-- net/llc/af_llc.c | 7 +++++-- net/llc/llc_conn.c | 6 +++--- net/netlink/af_netlink.c | 15 +++++++++------ net/netrom/af_netrom.c | 9 ++++++--- net/packet/af_packet.c | 7 +++++-- net/rose/af_rose.c | 9 ++++++--- net/rxrpc/af_rxrpc.c | 7 +++++-- net/sctp/ipv6.c | 2 +- net/sctp/protocol.c | 2 +- net/socket.c | 9 +++++---- net/tipc/socket.c | 9 ++++++--- net/unix/af_unix.c | 13 ++++++++----- net/x25/af_x25.c | 13 ++++++++----- 44 files changed, 184 insertions(+), 113 deletions(-) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index ee8ce195c538..53fcee26d6ae 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -477,12 +477,12 @@ static struct proto pppoe_sk_proto = { * Initialize a new struct sock. * **********************************************************************/ -static int pppoe_create(struct socket *sock) +static int pppoe_create(struct net *net, struct socket *sock) { int error = -ENOMEM; struct sock *sk; - sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1); if (!sk) goto out; diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 2eb424ba58e5..921d4ef6d14b 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -1411,12 +1411,12 @@ static struct proto pppol2tp_sk_proto = { /* socket() handler. Initialize a new struct sock. */ -static int pppol2tp_create(struct socket *sock) +static int pppol2tp_create(struct net *net, struct socket *sock) { int error = -ENOMEM; struct sock *sk; - sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1); if (!sk) goto out; diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index 25c52b55c38f..c6898c1fc54d 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -104,10 +104,13 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) EXPORT_SYMBOL(pppox_ioctl); -static int pppox_create(struct socket *sock, int protocol) +static int pppox_create(struct net *net, struct socket *sock, int protocol) { int rc = -EPROTOTYPE; + if (net != &init_net) + return -EAFNOSUPPORT; + if (protocol < 0 || protocol > PX_MAX_PROTO) goto out; @@ -123,7 +126,7 @@ static int pppox_create(struct socket *sock, int protocol) !try_module_get(pppox_protos[protocol]->owner)) goto out; - rc = pppox_protos[protocol]->create(sock); + rc = pppox_protos[protocol]->create(net, sock); module_put(pppox_protos[protocol]->owner); out: diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h index 25652545ba6e..43cfc9f0c078 100644 --- a/include/linux/if_pppox.h +++ b/include/linux/if_pppox.h @@ -172,7 +172,7 @@ static inline struct sock *sk_pppox(struct pppox_sock *po) struct module; struct pppox_proto { - int (*create)(struct socket *sock); + int (*create)(struct net *net, struct socket *sock); int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg); struct module *owner; diff --git a/include/linux/net.h b/include/linux/net.h index efc45177b503..c136abce7ef6 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -23,6 +23,7 @@ struct poll_table_struct; struct inode; +struct net; #define NPROTO 34 /* should be enough for now.. */ @@ -169,7 +170,7 @@ struct proto_ops { struct net_proto_family { int family; - int (*create)(struct socket *sock, int protocol); + int (*create)(struct net *net, struct socket *sock, int protocol); struct module *owner; }; diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index b6c468cd7f5b..c661c6fd6fd5 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -78,7 +78,6 @@ static void iucv_sock_destruct(struct sock *sk); static void iucv_sock_cleanup_listen(struct sock *parent); static void iucv_sock_kill(struct sock *sk); static void iucv_sock_close(struct sock *sk); -static int iucv_sock_create(struct socket *sock, int proto); static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len); static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index 00730d21b522..e2374e34989f 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -93,7 +93,7 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb) return skb->cb[sizeof(skb->cb) - 1]; } -extern struct sock *llc_sk_alloc(int family, gfp_t priority, +extern struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot); extern void llc_sk_free(struct sock *sk); diff --git a/include/net/sock.h b/include/net/sock.h index 9ef8b5fb7936..74e1f7d90d73 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -56,6 +56,7 @@ #include #include #include +#include /* * This structure really needs to be cleaned up. @@ -776,7 +777,7 @@ extern void FASTCALL(release_sock(struct sock *sk)); SINGLE_DEPTH_NESTING) #define bh_unlock_sock(__sk) spin_unlock(&((__sk)->sk_lock.slock)) -extern struct sock *sk_alloc(int family, +extern struct sock *sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot, int zero_it); extern void sk_free(struct sock *sk); @@ -1005,6 +1006,7 @@ static inline void sock_copy(struct sock *nsk, const struct sock *osk) #endif memcpy(nsk, osk, osk->sk_prot->obj_size); + get_net(nsk->sk_net); #ifdef CONFIG_SECURITY_NETWORK nsk->sk_security = sptr; security_sk_clone(osk, nsk); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 594b59739546..fd1d52f09707 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1026,11 +1026,14 @@ static struct proto ddp_proto = { * Create a socket. Initialise the socket, blank the addresses * set the state. */ -static int atalk_create(struct socket *sock, int protocol) +static int atalk_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; int rc = -ESOCKTNOSUPPORT; + if (net != &init_net) + return -EAFNOSUPPORT; + /* * We permit SOCK_DGRAM and RAW is an extension. It is trivial to do * and gives you the full ELAP frame. Should be handy for CAP 8) @@ -1038,7 +1041,7 @@ static int atalk_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) goto out; rc = -ENOMEM; - sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, &ddp_proto, 1); + sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto, 1); if (!sk) goto out; rc = 0; diff --git a/net/atm/common.c b/net/atm/common.c index 299ec1eb872a..e166d9e0ffd9 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -125,7 +125,7 @@ static struct proto vcc_proto = { .obj_size = sizeof(struct atm_vcc), }; -int vcc_create(struct socket *sock, int protocol, int family) +int vcc_create(struct net *net, struct socket *sock, int protocol, int family) { struct sock *sk; struct atm_vcc *vcc; @@ -133,7 +133,7 @@ int vcc_create(struct socket *sock, int protocol, int family) sock->sk = NULL; if (sock->type == SOCK_STREAM) return -EINVAL; - sk = sk_alloc(family, GFP_KERNEL, &vcc_proto, 1); + sk = sk_alloc(net, family, GFP_KERNEL, &vcc_proto, 1); if (!sk) return -ENOMEM; sock_init_data(sock, sk); diff --git a/net/atm/common.h b/net/atm/common.h index ad78c9e1117d..16f32c1fa1c9 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -10,7 +10,7 @@ #include /* for poll_table */ -int vcc_create(struct socket *sock, int protocol, int family); +int vcc_create(struct net *net, struct socket *sock, int protocol, int family); int vcc_release(struct socket *sock); int vcc_connect(struct socket *sock, int itf, short vpi, int vci); int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 848e6e191cc7..43e8bf5ed001 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -124,10 +124,13 @@ static const struct proto_ops pvc_proto_ops = { }; -static int pvc_create(struct socket *sock,int protocol) +static int pvc_create(struct net *net, struct socket *sock,int protocol) { + if (net != &init_net) + return -EAFNOSUPPORT; + sock->ops = &pvc_proto_ops; - return vcc_create(sock, protocol, PF_ATMPVC); + return vcc_create(net, sock, protocol, PF_ATMPVC); } diff --git a/net/atm/svc.c b/net/atm/svc.c index 53d04c7992cf..daf9a48a7db0 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -25,7 +25,7 @@ #include "signaling.h" #include "addr.h" -static int svc_create(struct socket *sock,int protocol); +static int svc_create(struct net *net, struct socket *sock,int protocol); /* * Note: since all this is still nicely synchronized with the signaling demon, @@ -326,7 +326,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) lock_sock(sk); - error = svc_create(newsock,0); + error = svc_create(sk->sk_net, newsock,0); if (error) goto out; @@ -627,12 +627,15 @@ static const struct proto_ops svc_proto_ops = { }; -static int svc_create(struct socket *sock,int protocol) +static int svc_create(struct net *net, struct socket *sock,int protocol) { int error; + if (net != &init_net) + return -EAFNOSUPPORT; + sock->ops = &svc_proto_ops; - error = vcc_create(sock, protocol, AF_ATMSVC); + error = vcc_create(net, sock, protocol, AF_ATMSVC); if (error) return error; ATM_SD(sock)->local.sas_family = AF_ATMSVC; ATM_SD(sock)->remote.sas_family = AF_ATMSVC; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 1d71f85680b8..def6c42ad165 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -780,11 +780,14 @@ static struct proto ax25_proto = { .obj_size = sizeof(struct sock), }; -static int ax25_create(struct socket *sock, int protocol) +static int ax25_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; ax25_cb *ax25; + if (net != &init_net) + return -EAFNOSUPPORT; + switch (sock->type) { case SOCK_DGRAM: if (protocol == 0 || protocol == PF_AX25) @@ -830,7 +833,7 @@ static int ax25_create(struct socket *sock, int protocol) return -ESOCKTNOSUPPORT; } - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, &ax25_proto, 1)) == NULL) + if ((sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto, 1)) == NULL) return -ENOMEM; ax25 = sk->sk_protinfo = ax25_create_cb(); @@ -855,7 +858,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) struct sock *sk; ax25_cb *ax25, *oax25; - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) + if ((sk = sk_alloc(osk->sk_net, PF_AX25, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) return NULL; if ((ax25 = ax25_create_cb()) == NULL) { diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index d942b946ba07..1220d8a41eb5 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -95,10 +95,13 @@ int bt_sock_unregister(int proto) } EXPORT_SYMBOL(bt_sock_unregister); -static int bt_sock_create(struct socket *sock, int proto) +static int bt_sock_create(struct net *net, struct socket *sock, int proto) { int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (proto < 0 || proto >= BT_MAX_PROTO) return -EINVAL; @@ -113,7 +116,7 @@ static int bt_sock_create(struct socket *sock, int proto) read_lock(&bt_proto_lock); if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { - err = bt_proto[proto]->create(sock, proto); + err = bt_proto[proto]->create(net, sock, proto); module_put(bt_proto[proto]->owner); } diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 10292e776046..f718965f296c 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -204,7 +204,7 @@ static struct proto bnep_proto = { .obj_size = sizeof(struct bt_sock) }; -static int bnep_sock_create(struct socket *sock, int protocol) +static int bnep_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -213,7 +213,7 @@ static int bnep_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 19be7861e51e..cf700c20d11e 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -195,7 +195,7 @@ static struct proto cmtp_proto = { .obj_size = sizeof(struct bt_sock) }; -static int cmtp_sock_create(struct socket *sock, int protocol) +static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -204,7 +204,7 @@ static int cmtp_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 5ccea5fbd236..43dd6373bff9 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -634,7 +634,7 @@ static struct proto hci_sk_proto = { .obj_size = sizeof(struct hci_pinfo) }; -static int hci_sock_create(struct socket *sock, int protocol) +static int hci_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -645,7 +645,7 @@ static int hci_sock_create(struct socket *sock, int protocol) sock->ops = &hci_sock_ops; - sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 0c185257e55b..1de2b6fbcac0 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -246,7 +246,7 @@ static struct proto hidp_proto = { .obj_size = sizeof(struct bt_sock) }; -static int hidp_sock_create(struct socket *sock, int protocol) +static int hidp_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -255,7 +255,7 @@ static int hidp_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c4e4ce4ebb2b..36ef27b625db 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -518,11 +518,11 @@ static struct proto l2cap_proto = { .obj_size = sizeof(struct l2cap_pinfo) }; -static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, gfp_t prio) +static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) { struct sock *sk; - sk = sk_alloc(PF_BLUETOOTH, prio, &l2cap_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto, 1); if (!sk) return NULL; @@ -543,7 +543,7 @@ static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, gfp_t prio) return sk; } -static int l2cap_sock_create(struct socket *sock, int protocol) +static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -560,7 +560,7 @@ static int l2cap_sock_create(struct socket *sock, int protocol) sock->ops = &l2cap_sock_ops; - sk = l2cap_sock_alloc(sock, protocol, GFP_ATOMIC); + sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; @@ -1425,7 +1425,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } - sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC); + sk = l2cap_sock_alloc(parent->sk_net, NULL, BTPROTO_L2CAP, GFP_ATOMIC); if (!sk) goto response; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 30586ab9e878..266b6972667d 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -282,12 +282,12 @@ static struct proto rfcomm_proto = { .obj_size = sizeof(struct rfcomm_pinfo) }; -static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio) +static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) { struct rfcomm_dlc *d; struct sock *sk; - sk = sk_alloc(PF_BLUETOOTH, prio, &rfcomm_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto, 1); if (!sk) return NULL; @@ -323,7 +323,7 @@ static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio return sk; } -static int rfcomm_sock_create(struct socket *sock, int protocol) +static int rfcomm_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -336,7 +336,7 @@ static int rfcomm_sock_create(struct socket *sock, int protocol) sock->ops = &rfcomm_sock_ops; - sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC); + sk = rfcomm_sock_alloc(net, sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; @@ -868,7 +868,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * goto done; } - sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC); + sk = rfcomm_sock_alloc(parent->sk_net, NULL, BTPROTO_RFCOMM, GFP_ATOMIC); if (!sk) goto done; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 3f5163e725ed..65b6fb1c4154 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -414,11 +414,11 @@ static struct proto sco_proto = { .obj_size = sizeof(struct sco_pinfo) }; -static struct sock *sco_sock_alloc(struct socket *sock, int proto, gfp_t prio) +static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) { struct sock *sk; - sk = sk_alloc(PF_BLUETOOTH, prio, &sco_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto, 1); if (!sk) return NULL; @@ -439,7 +439,7 @@ static struct sock *sco_sock_alloc(struct socket *sock, int proto, gfp_t prio) return sk; } -static int sco_sock_create(struct socket *sock, int protocol) +static int sco_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -452,7 +452,7 @@ static int sco_sock_create(struct socket *sock, int protocol) sock->ops = &sco_sock_ops; - sk = sco_sock_alloc(sock, protocol, GFP_ATOMIC); + sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; @@ -807,7 +807,7 @@ static void sco_conn_ready(struct sco_conn *conn) bh_lock_sock(parent); - sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC); + sk = sco_sock_alloc(parent->sk_net, NULL, BTPROTO_SCO, GFP_ATOMIC); if (!sk) { bh_unlock_sock(parent); goto done; diff --git a/net/core/sock.c b/net/core/sock.c index bbc726a49d87..a31455dc7024 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -873,7 +873,7 @@ static inline void sock_lock_init(struct sock *sk) * @prot: struct proto associated with this new sock instance * @zero_it: if we should zero the newly allocated sock */ -struct sock *sk_alloc(int family, gfp_t priority, +struct sock *sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot, int zero_it) { struct sock *sk = NULL; @@ -894,6 +894,7 @@ struct sock *sk_alloc(int family, gfp_t priority, */ sk->sk_prot = sk->sk_prot_creator = prot; sock_lock_init(sk); + sk->sk_net = get_net(net); } if (security_sk_alloc(sk, family, priority)) @@ -933,6 +934,7 @@ void sk_free(struct sock *sk) __FUNCTION__, atomic_read(&sk->sk_omem_alloc)); security_sk_free(sk); + put_net(sk->sk_net); if (sk->sk_prot_creator->slab != NULL) kmem_cache_free(sk->sk_prot_creator->slab, sk); else @@ -942,7 +944,7 @@ void sk_free(struct sock *sk) struct sock *sk_clone(const struct sock *sk, const gfp_t priority) { - struct sock *newsk = sk_alloc(sk->sk_family, priority, sk->sk_prot, 0); + struct sock *newsk = sk_alloc(sk->sk_net, sk->sk_family, priority, sk->sk_prot, 0); if (newsk != NULL) { struct sk_filter *filter; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 625d5955b8e2..aca4c4930eb6 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -471,10 +471,10 @@ static struct proto dn_proto = { .obj_size = sizeof(struct dn_sock), }; -static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp) +static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gfp) { struct dn_scp *scp; - struct sock *sk = sk_alloc(PF_DECnet, gfp, &dn_proto, 1); + struct sock *sk = sk_alloc(net, PF_DECnet, gfp, &dn_proto, 1); if (!sk) goto out; @@ -675,10 +675,13 @@ char *dn_addr2asc(__u16 addr, char *buf) -static int dn_create(struct socket *sock, int protocol) +static int dn_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; + if (net != &init_net) + return -EAFNOSUPPORT; + switch(sock->type) { case SOCK_SEQPACKET: if (protocol != DNPROTO_NSP) @@ -691,7 +694,7 @@ static int dn_create(struct socket *sock, int protocol) } - if ((sk = dn_alloc_sock(sock, GFP_KERNEL)) == NULL) + if ((sk = dn_alloc_sock(net, sock, GFP_KERNEL)) == NULL) return -ENOBUFS; sk->sk_protocol = protocol; @@ -1091,7 +1094,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) cb = DN_SKB_CB(skb); sk->sk_ack_backlog--; - newsk = dn_alloc_sock(newsock, sk->sk_allocation); + newsk = dn_alloc_sock(sk->sk_net, newsock, sk->sk_allocation); if (newsk == NULL) { release_sock(sk); kfree_skb(skb); diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 35c96bcc0f32..a2429dbcb86e 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -608,12 +608,15 @@ static struct proto econet_proto = { * Create an Econet socket */ -static int econet_create(struct socket *sock, int protocol) +static int econet_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct econet_sock *eo; int err; + if (net != &init_net) + return -EAFNOSUPPORT; + /* Econet only provides datagram services. */ if (sock->type != SOCK_DGRAM) return -ESOCKTNOSUPPORT; @@ -621,7 +624,7 @@ static int econet_create(struct socket *sock, int protocol) sock->state = SS_UNCONNECTED; err = -ENOBUFS; - sk = sk_alloc(PF_ECONET, GFP_KERNEL, &econet_proto, 1); + sk = sk_alloc(net, PF_ECONET, GFP_KERNEL, &econet_proto, 1); if (sk == NULL) goto out; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index e68103475cca..110a19edacc8 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -241,7 +241,7 @@ EXPORT_SYMBOL(build_ehash_secret); * Create an inet socket. */ -static int inet_create(struct socket *sock, int protocol) +static int inet_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct list_head *p; @@ -253,6 +253,9 @@ static int inet_create(struct socket *sock, int protocol) int try_loading_module = 0; int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM && !inet_ehash_secret) @@ -320,7 +323,7 @@ lookup_protocol: BUG_TRAP(answer_prot->slab != NULL); err = -ENOBUFS; - sk = sk_alloc(PF_INET, GFP_KERNEL, answer_prot, 1); + sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, 1); if (sk == NULL) goto out; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index b5f96372ad73..21931c86e95b 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -81,7 +81,7 @@ static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) return (struct ipv6_pinfo *)(((u8 *)sk) + offset); } -static int inet6_create(struct socket *sock, int protocol) +static int inet6_create(struct net *net, struct socket *sock, int protocol) { struct inet_sock *inet; struct ipv6_pinfo *np; @@ -94,6 +94,9 @@ static int inet6_create(struct socket *sock, int protocol) int try_loading_module = 0; int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM && !inet_ehash_secret) @@ -159,7 +162,7 @@ lookup_protocol: BUG_TRAP(answer_prot->slab != NULL); err = -ENOBUFS; - sk = sk_alloc(PF_INET6, GFP_KERNEL, answer_prot, 1); + sk = sk_alloc(net, PF_INET6, GFP_KERNEL, answer_prot, 1); if (sk == NULL) goto out; diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 8400525177ab..ee28babad227 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1360,11 +1360,14 @@ static struct proto ipx_proto = { .obj_size = sizeof(struct ipx_sock), }; -static int ipx_create(struct socket *sock, int protocol) +static int ipx_create(struct net *net, struct socket *sock, int protocol) { int rc = -ESOCKTNOSUPPORT; struct sock *sk; + if (net != &init_net) + return -EAFNOSUPPORT; + /* * SPX support is not anymore in the kernel sources. If you want to * ressurrect it, completing it and making it understand shared skbs, @@ -1375,7 +1378,7 @@ static int ipx_create(struct socket *sock, int protocol) goto out; rc = -ENOMEM; - sk = sk_alloc(PF_IPX, GFP_KERNEL, &ipx_proto, 1); + sk = sk_alloc(net, PF_IPX, GFP_KERNEL, &ipx_proto, 1); if (!sk) goto out; #ifdef IPX_REFCNT_DEBUG diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index c80949a71923..0328ae2654f4 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -60,7 +60,7 @@ #include -static int irda_create(struct socket *sock, int protocol); +static int irda_create(struct net *net, struct socket *sock, int protocol); static const struct proto_ops irda_stream_ops; static const struct proto_ops irda_seqpacket_ops; @@ -831,7 +831,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - err = irda_create(newsock, sk->sk_protocol); + err = irda_create(sk->sk_net, newsock, sk->sk_protocol); if (err) return err; @@ -1057,13 +1057,16 @@ static struct proto irda_proto = { * Create IrDA socket * */ -static int irda_create(struct socket *sock, int protocol) +static int irda_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct irda_sock *self; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + if (net != &init_net) + return -EAFNOSUPPORT; + /* Check for valid socket type */ switch (sock->type) { case SOCK_STREAM: /* For TTP connections with SAR disabled */ @@ -1075,7 +1078,7 @@ static int irda_create(struct socket *sock, int protocol) } /* Allocate networking socket */ - sk = sk_alloc(PF_IRDA, GFP_ATOMIC, &irda_proto, 1); + sk = sk_alloc(net, PF_IRDA, GFP_ATOMIC, &irda_proto, 1); if (sk == NULL) return -ENOMEM; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 53ae14c35f70..53668585e947 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -213,7 +213,7 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) { struct sock *sk; - sk = sk_alloc(PF_IUCV, prio, &iucv_proto, 1); + sk = sk_alloc(&init_net, PF_IUCV, prio, &iucv_proto, 1); if (!sk) return NULL; @@ -240,7 +240,7 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) } /* Create an IUCV socket */ -static int iucv_sock_create(struct socket *sock, int protocol) +static int iucv_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; diff --git a/net/key/af_key.c b/net/key/af_key.c index 5b802bbb856e..ff5c3d03005e 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -136,11 +136,14 @@ static struct proto key_proto = { .obj_size = sizeof(struct pfkey_sock), }; -static int pfkey_create(struct socket *sock, int protocol) +static int pfkey_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (sock->type != SOCK_RAW) @@ -149,7 +152,7 @@ static int pfkey_create(struct socket *sock, int protocol) return -EPROTONOSUPPORT; err = -ENOMEM; - sk = sk_alloc(PF_KEY, GFP_KERNEL, &key_proto, 1); + sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto, 1); if (sk == NULL) goto out; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 6b8a103cf9e6..b48244156e75 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -150,14 +150,17 @@ static struct proto llc_proto = { * socket type we have available. * Returns 0 upon success, negative upon failure. */ -static int llc_ui_create(struct socket *sock, int protocol) +static int llc_ui_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; int rc = -ESOCKTNOSUPPORT; + if (net != &init_net) + return -EAFNOSUPPORT; + if (likely(sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM)) { rc = -ENOMEM; - sk = llc_sk_alloc(PF_LLC, GFP_KERNEL, &llc_proto); + sk = llc_sk_alloc(net, PF_LLC, GFP_KERNEL, &llc_proto); if (sk) { rc = 0; llc_ui_sk_init(sock, sk); diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 3b8cfbe029a7..8ebc2769dfda 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -700,7 +700,7 @@ static struct sock *llc_create_incoming_sock(struct sock *sk, struct llc_addr *saddr, struct llc_addr *daddr) { - struct sock *newsk = llc_sk_alloc(sk->sk_family, GFP_ATOMIC, + struct sock *newsk = llc_sk_alloc(sk->sk_net, sk->sk_family, GFP_ATOMIC, sk->sk_prot); struct llc_sock *newllc, *llc = llc_sk(sk); @@ -867,9 +867,9 @@ static void llc_sk_init(struct sock* sk) * Allocates a LLC sock and initializes it. Returns the new LLC sock * or %NULL if there's no memory available for one */ -struct sock *llc_sk_alloc(int family, gfp_t priority, struct proto *prot) +struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot) { - struct sock *sk = sk_alloc(family, priority, prot, 1); + struct sock *sk = sk_alloc(net, family, priority, prot, 1); if (!sk) goto out; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3982f13dab17..406a493300d8 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -384,15 +384,15 @@ static struct proto netlink_proto = { .obj_size = sizeof(struct netlink_sock), }; -static int __netlink_create(struct socket *sock, struct mutex *cb_mutex, - int protocol) +static int __netlink_create(struct net *net, struct socket *sock, + struct mutex *cb_mutex, int protocol) { struct sock *sk; struct netlink_sock *nlk; sock->ops = &netlink_ops; - sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); + sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); if (!sk) return -ENOMEM; @@ -412,13 +412,16 @@ static int __netlink_create(struct socket *sock, struct mutex *cb_mutex, return 0; } -static int netlink_create(struct socket *sock, int protocol) +static int netlink_create(struct net *net, struct socket *sock, int protocol) { struct module *module = NULL; struct mutex *cb_mutex; struct netlink_sock *nlk; int err = 0; + if (net != &init_net) + return -EAFNOSUPPORT; + sock->state = SS_UNCONNECTED; if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) @@ -441,7 +444,7 @@ static int netlink_create(struct socket *sock, int protocol) cb_mutex = nl_table[protocol].cb_mutex; netlink_unlock_table(); - if ((err = __netlink_create(sock, cb_mutex, protocol)) < 0) + if ((err = __netlink_create(net, sock, cb_mutex, protocol)) < 0) goto out_module; nlk = nlk_sk(sock->sk); @@ -1318,7 +1321,7 @@ netlink_kernel_create(int unit, unsigned int groups, if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) return NULL; - if (__netlink_create(sock, cb_mutex, unit) < 0) + if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0) goto out_sock_release; if (groups < 32) diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 15c8a92bd719..e969d1bc765c 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -409,15 +409,18 @@ static struct proto nr_proto = { .obj_size = sizeof(struct nr_sock), }; -static int nr_create(struct socket *sock, int protocol) +static int nr_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct nr_sock *nr; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_SEQPACKET || protocol != 0) return -ESOCKTNOSUPPORT; - if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, &nr_proto, 1)) == NULL) + if ((sk = sk_alloc(net, PF_NETROM, GFP_ATOMIC, &nr_proto, 1)) == NULL) return -ENOMEM; nr = nr_sk(sk); @@ -459,7 +462,7 @@ static struct sock *nr_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) + if ((sk = sk_alloc(osk->sk_net, PF_NETROM, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) return NULL; nr = nr_sk(sk); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 56502292f24c..766b5faaed21 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -977,13 +977,16 @@ static struct proto packet_proto = { * Create a packet of type SOCK_PACKET. */ -static int packet_create(struct socket *sock, int protocol) +static int packet_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct packet_sock *po; __be16 proto = (__force __be16)protocol; /* weird, but documented */ int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (!capable(CAP_NET_RAW)) return -EPERM; if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW && @@ -993,7 +996,7 @@ static int packet_create(struct socket *sock, int protocol) sock->state = SS_UNCONNECTED; err = -ENOBUFS; - sk = sk_alloc(PF_PACKET, GFP_KERNEL, &packet_proto, 1); + sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto, 1); if (sk == NULL) goto out; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 48319f7991ac..67e06ab7f854 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -499,15 +499,18 @@ static struct proto rose_proto = { .obj_size = sizeof(struct rose_sock), }; -static int rose_create(struct socket *sock, int protocol) +static int rose_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct rose_sock *rose; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_SEQPACKET || protocol != 0) return -ESOCKTNOSUPPORT; - if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL) + if ((sk = sk_alloc(net, PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL) return -ENOMEM; rose = rose_sk(sk); @@ -545,7 +548,7 @@ static struct sock *rose_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL) + if ((sk = sk_alloc(osk->sk_net, PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL) return NULL; rose = rose_sk(sk); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 122d55d992e1..0803f305ed08 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -606,13 +606,16 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock, /* * create an RxRPC socket */ -static int rxrpc_create(struct socket *sock, int protocol) +static int rxrpc_create(struct net *net, struct socket *sock, int protocol) { struct rxrpc_sock *rx; struct sock *sk; _enter("%p,%d", sock, protocol); + if (net != &init_net) + return -EAFNOSUPPORT; + /* we support transport protocol UDP only */ if (protocol != PF_INET) return -EPROTONOSUPPORT; @@ -623,7 +626,7 @@ static int rxrpc_create(struct socket *sock, int protocol) sock->ops = &rxrpc_rpc_ops; sock->state = SS_UNCONNECTED; - sk = sk_alloc(PF_RXRPC, GFP_KERNEL, &rxrpc_proto, 1); + sk = sk_alloc(net, PF_RXRPC, GFP_KERNEL, &rxrpc_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index ec29b97dbab9..ddeb4882ec75 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -631,7 +631,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct sctp6_sock *newsctp6sk; - newsk = sk_alloc(PF_INET6, GFP_KERNEL, sk->sk_prot, 1); + newsk = sk_alloc(sk->sk_net, PF_INET6, GFP_KERNEL, sk->sk_prot, 1); if (!newsk) goto out; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 30929e3ca05a..af67c839ef98 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -552,7 +552,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, { struct inet_sock *inet = inet_sk(sk); struct inet_sock *newinet; - struct sock *newsk = sk_alloc(PF_INET, GFP_KERNEL, sk->sk_prot, 1); + struct sock *newsk = sk_alloc(sk->sk_net, PF_INET, GFP_KERNEL, sk->sk_prot, 1); if (!newsk) goto out; diff --git a/net/socket.c b/net/socket.c index b09eb9036a17..a714c6d4e4a1 100644 --- a/net/socket.c +++ b/net/socket.c @@ -84,6 +84,7 @@ #include #include #include +#include #include #include @@ -1071,7 +1072,7 @@ call_kill: return 0; } -static int __sock_create(int family, int type, int protocol, +static int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern) { int err; @@ -1147,7 +1148,7 @@ static int __sock_create(int family, int type, int protocol, /* Now protected by module ref count */ rcu_read_unlock(); - err = pf->create(sock, protocol); + err = pf->create(net, sock, protocol); if (err < 0) goto out_module_put; @@ -1186,12 +1187,12 @@ out_release: int sock_create(int family, int type, int protocol, struct socket **res) { - return __sock_create(family, type, protocol, res, 0); + return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); } int sock_create_kern(int family, int type, int protocol, struct socket **res) { - return __sock_create(family, type, protocol, res, 1); + return __sock_create(&init_net, family, type, protocol, res, 1); } asmlinkage long sys_socket(int family, int type, int protocol) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 84110172031e..e36b4b5a5222 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -162,13 +162,16 @@ static void advance_queue(struct tipc_sock *tsock) * * Returns 0 on success, errno otherwise */ -static int tipc_create(struct socket *sock, int protocol) +static int tipc_create(struct net *net, struct socket *sock, int protocol) { struct tipc_sock *tsock; struct tipc_port *port; struct sock *sk; u32 ref; + if (net != &init_net) + return -EAFNOSUPPORT; + if (unlikely(protocol != 0)) return -EPROTONOSUPPORT; @@ -198,7 +201,7 @@ static int tipc_create(struct socket *sock, int protocol) return -EPROTOTYPE; } - sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1); + sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto, 1); if (!sk) { tipc_deleteport(ref); return -ENOMEM; @@ -1372,7 +1375,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) } buf = skb_peek(&sock->sk->sk_receive_queue); - res = tipc_create(newsock, 0); + res = tipc_create(sock->sk->sk_net, newsock, 0); if (!res) { struct tipc_sock *new_tsock = tipc_sk(newsock->sk); struct tipc_portid id; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2386090c3a16..10e73122c34c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -594,7 +594,7 @@ static struct proto unix_proto = { */ static struct lock_class_key af_unix_sk_receive_queue_lock_key; -static struct sock * unix_create1(struct socket *sock) +static struct sock * unix_create1(struct net *net, struct socket *sock) { struct sock *sk = NULL; struct unix_sock *u; @@ -602,7 +602,7 @@ static struct sock * unix_create1(struct socket *sock) if (atomic_read(&unix_nr_socks) >= 2*get_max_files()) goto out; - sk = sk_alloc(PF_UNIX, GFP_KERNEL, &unix_proto, 1); + sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto, 1); if (!sk) goto out; @@ -628,8 +628,11 @@ out: return sk; } -static int unix_create(struct socket *sock, int protocol) +static int unix_create(struct net *net, struct socket *sock, int protocol) { + if (net != &init_net) + return -EAFNOSUPPORT; + if (protocol && protocol != PF_UNIX) return -EPROTONOSUPPORT; @@ -655,7 +658,7 @@ static int unix_create(struct socket *sock, int protocol) return -ESOCKTNOSUPPORT; } - return unix_create1(sock) ? 0 : -ENOMEM; + return unix_create1(net, sock) ? 0 : -ENOMEM; } static int unix_release(struct socket *sock) @@ -1039,7 +1042,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, err = -ENOMEM; /* create new sock for complete connection */ - newsk = unix_create1(NULL); + newsk = unix_create1(sk->sk_net, NULL); if (newsk == NULL) goto out; diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 479927cb45ca..2e9931571a4d 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -466,10 +466,10 @@ static struct proto x25_proto = { .obj_size = sizeof(struct x25_sock), }; -static struct sock *x25_alloc_socket(void) +static struct sock *x25_alloc_socket(struct net *net) { struct x25_sock *x25; - struct sock *sk = sk_alloc(AF_X25, GFP_ATOMIC, &x25_proto, 1); + struct sock *sk = sk_alloc(net, AF_X25, GFP_ATOMIC, &x25_proto, 1); if (!sk) goto out; @@ -485,17 +485,20 @@ out: return sk; } -static int x25_create(struct socket *sock, int protocol) +static int x25_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct x25_sock *x25; int rc = -ESOCKTNOSUPPORT; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_SEQPACKET || protocol) goto out; rc = -ENOMEM; - if ((sk = x25_alloc_socket()) == NULL) + if ((sk = x25_alloc_socket(net)) == NULL) goto out; x25 = x25_sk(sk); @@ -543,7 +546,7 @@ static struct sock *x25_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) goto out; - if ((sk = x25_alloc_socket()) == NULL) + if ((sk = x25_alloc_socket(osk->sk_net)) == NULL) goto out; x25 = x25_sk(sk); From 6d34b1c27a72d5d1c73c567b2f6b1fde316e0eae Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 12:57:33 +0200 Subject: [PATCH 1176/2804] [NET]: Initialize the network namespace of network devices. Except for carefully selected pseudo devices all network interfaces should start out in the initial network namespace. Ultimately it will be register_netdev that examines what dev->nd_net is set to and places a device in a network namespace. This patch modifies alloc_netdev to initialize the network namespace a device is in with the initial network namespace. This gets it right for the vast majority of devices so their drivers need not be modified and for those few pseudo devices that need something different they can change this parameter before calling register_netdevice. The network namespace parameter on a network device is not reference counted as the devices are inside of a network namespace and cannot remain in that namespace past the lifetime of the network namespace. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/core/dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/dev.c b/net/core/dev.c index 618fb1c1dd47..40fd66fbe4e1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3725,6 +3725,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev = (struct net_device *) (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); dev->padded = (char *)dev - (char *)p; + dev->nd_net = &init_net; if (sizeof_priv) { dev->priv = ((char *)dev + From e730c15519d09ea528b4d2f1103681fa5937c0e6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 17 Sep 2007 11:53:39 -0700 Subject: [PATCH 1177/2804] [NET]: Make packet reception network namespace safe This patch modifies every packet receive function registered with dev_add_pack() to drop packets if they are not from the initial network namespace. This should ensure that the various network stacks do not receive packets in a anything but the initial network namespace until the code has been converted and is ready for them. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/block/aoe/aoenet.c | 4 ++++ drivers/net/bonding/bond_3ad.c | 4 ++++ drivers/net/bonding/bond_alb.c | 3 +++ drivers/net/bonding/bond_main.c | 3 +++ drivers/net/hamradio/bpqether.c | 3 +++ drivers/net/pppoe.c | 6 ++++++ drivers/net/wan/hdlc.c | 7 +++++++ drivers/net/wan/lapbether.c | 3 +++ drivers/net/wan/syncppp.c | 6 ++++++ net/8021q/vlan_dev.c | 5 +++++ net/appletalk/aarp.c | 3 +++ net/appletalk/ddp.c | 6 ++++++ net/ax25/ax25_in.c | 5 +++++ net/bridge/br_stp_bpdu.c | 4 ++++ net/decnet/dn_route.c | 3 +++ net/econet/af_econet.c | 3 +++ net/ipv4/arp.c | 3 +++ net/ipv4/ip_input.c | 3 +++ net/ipv4/ipconfig.c | 6 ++++++ net/ipv6/ip6_input.c | 5 +++++ net/ipx/af_ipx.c | 3 +++ net/irda/irlap_frame.c | 3 +++ net/llc/llc_input.c | 4 ++++ net/packet/af_packet.c | 9 +++++++++ net/tipc/eth_media.c | 6 ++++++ net/x25/x25_dev.c | 3 +++ 26 files changed, 113 insertions(+) diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index f9ddfda4d9cb..4dc0fb7da94b 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "aoe.h" @@ -114,6 +115,9 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct aoe_hdr *h; u32 n; + if (ifp->nd_net != &init_net) + goto exit; + skb = skb_share_check(skb, GFP_ATOMIC); if (skb == NULL) return 0; diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index f829e4ad8b49..94bd73941451 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "bonding.h" #include "bond_3ad.h" @@ -2448,6 +2449,9 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac struct slave *slave = NULL; int ret = NET_RX_DROP; + if (dev->nd_net != &init_net) + goto out; + if (!(dev->flags & IFF_MASTER)) goto out; diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 92c3b6f6a8e7..419a9f8fdd53 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -345,6 +345,9 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct struct arp_pkt *arp = (struct arp_pkt *)skb->data; int res = NET_RX_DROP; + if (bond_dev->nd_net != &init_net) + goto out; + if (!(bond_dev->flags & IFF_MASTER)) goto out; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5de648f90a45..e4e5fdc0430b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2458,6 +2458,9 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack unsigned char *arp_ptr; u32 sip, tip; + if (dev->nd_net != &init_net) + goto out; + if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) goto out; diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 1699d42d13ca..85fb8e7efacf 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -173,6 +173,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty struct ethhdr *eth; struct bpqdev *bpq; + if (dev->nd_net != &init_net) + goto drop; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 53fcee26d6ae..60c0e4e17875 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -389,6 +389,9 @@ static int pppoe_rcv(struct sk_buff *skb, if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; + if (dev->nd_net != &init_net) + goto drop; + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) goto drop; @@ -418,6 +421,9 @@ static int pppoe_disc_rcv(struct sk_buff *skb, struct pppoe_hdr *ph; struct pppox_sock *po; + if (dev->nd_net != &init_net) + goto abort; + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) goto abort; diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 65ad2e24caf0..3b57350eacca 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -36,6 +36,7 @@ #include #include #include +#include static const char* version = "HDLC support module revision 1.21"; @@ -66,6 +67,12 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { struct hdlc_device_desc *desc = dev_to_desc(dev); + + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return 0; + } + if (desc->netif_rx) return desc->netif_rx(skb); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 6c302e9dbca2..ca8b3c3cb931 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -91,6 +91,9 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe int len, err; struct lapbethdev *lapbeth; + if (dev->nd_net != &init_net) + goto drop; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 67fc67cfd452..5c71af6ea3a5 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -1445,6 +1446,11 @@ static void sppp_print_bytes (u_char *p, u16 len) static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return 0; + } + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; sppp_input(dev,skb); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 328759c32d61..6644e8f5f199 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -122,6 +122,11 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, unsigned short vlan_TCI; __be16 proto; + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return -1; + } + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return -1; diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 80b54148460f..9267f4818795 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -713,6 +713,9 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, struct atalk_addr sa, *ma, da; struct atalk_iface *ifa; + if (dev->nd_net != &init_net) + goto out0; + /* We only do Ethernet SNAP AARP. */ if (dev->type != ARPHRD_ETHER) goto out0; diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index fd1d52f09707..c1f1367cad48 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1403,6 +1403,9 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, int origlen; __u16 len_hops; + if (dev->nd_net != &init_net) + goto freeit; + /* Don't mangle buffer if shared */ if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; @@ -1488,6 +1491,9 @@ freeit: static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { + if (dev->nd_net != &init_net) + goto freeit; + /* Expand any short form frames */ if (skb_mac_header(skb)[2] == 1) { struct ddpehdr *ddp; diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 0ddaff0df217..3b7d1720c2ee 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -451,6 +451,11 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, skb->sk = NULL; /* Initially we don't know who it's for */ skb->destructor = NULL; /* Who initializes this, dammit?! */ + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return 0; + } + if ((*skb->data & 0x0F) != 0) { kfree_skb(skb); /* Not a KISS data frame */ return 0; diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 14f0c888eecc..0edbd2a1c3f3 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -141,6 +142,9 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, struct net_bridge *br; const unsigned char *buf; + if (dev->nd_net != &init_net) + goto err; + if (!p) goto err; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 4cfea9563d2a..580e786d0c38 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -584,6 +584,9 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; unsigned char padlen = 0; + if (dev->nd_net != &init_net) + goto dump_it; + if (dn == NULL) goto dump_it; diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index a2429dbcb86e..7de3006af206 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -1065,6 +1065,9 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet struct sock *sk; struct ec_device *edev = dev->ec_ptr; + if (dev->nd_net != &init_net) + goto drop; + if (skb->pkt_type == PACKET_OTHERHOST) goto drop; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 78dd3443016c..bde129708e22 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -932,6 +932,9 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev, { struct arphdr *arp; + if (dev->nd_net != &init_net) + goto freeskb; + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ if (!pskb_may_pull(skb, (sizeof(struct arphdr) + (2 * dev->addr_len) + diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 97069399d864..41d8964591e7 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -382,6 +382,9 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct iphdr *iph; u32 len; + if (dev->nd_net != &init_net) + goto drop; + /* When the interface is in promisc. mode, drop all the crap * that it receives, do not try to analyse it. */ diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 5ae4849878a3..08ff623371f0 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -426,6 +426,9 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt unsigned char *sha, *tha; /* s for "source", t for "target" */ struct ic_device *d; + if (dev->nd_net != &init_net) + goto drop; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; @@ -835,6 +838,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str struct ic_device *d; int len, ext_len; + if (dev->nd_net != &init_net) + goto drop; + /* Perform verifications before taking the lock. */ if (skb->pkt_type == PACKET_OTHERHOST) goto drop; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 30a5cb1b203e..7d18cac3f110 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -61,6 +61,11 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt u32 pkt_len; struct inet6_dev *idev; + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return 0; + } + if (skb->pkt_type == PACKET_OTHERHOST) { kfree_skb(skb); return 0; diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index ee28babad227..f7b4d383c609 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1647,6 +1647,9 @@ static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty u16 ipx_pktsize; int rc = 0; + if (dev->nd_net != &init_net) + goto drop; + /* Not ours */ if (skb->pkt_type == PACKET_OTHERHOST) goto drop; diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 25a3444a9234..77ac27e81161 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -1326,6 +1326,9 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, int command; __u8 control; + if (dev->nd_net != &init_net) + goto out; + /* FIXME: should we get our own field? */ self = (struct irlap_cb *) dev->atalk_ptr; diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index 099ed8fec145..c40c9b2a345a 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -12,6 +12,7 @@ * See the GNU General Public License for more details. */ #include +#include #include #include #include @@ -145,6 +146,9 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, int (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); + if (dev->nd_net != &init_net) + goto drop; + /* * When the interface is in promisc. mode, drop all the crap that it * receives, do not try to analyse it. diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 766b5faaed21..cae1ee4f2ad6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -252,6 +252,9 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct struct sock *sk; struct sockaddr_pkt *spkt; + if (dev->nd_net != &init_net) + goto out; + /* * When we registered the protocol we saved the socket in the data * field for just this event. @@ -452,6 +455,9 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet int skb_len = skb->len; unsigned int snaplen, res; + if (dev->nd_net != &init_net) + goto drop; + if (skb->pkt_type == PACKET_LOOPBACK) goto drop; @@ -568,6 +574,9 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe struct sk_buff *copy_skb = NULL; struct timeval tv; + if (dev->nd_net != &init_net) + goto drop; + if (skb->pkt_type == PACKET_LOOPBACK) goto drop; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 711ca4b1f051..d2ed23704189 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -38,6 +38,7 @@ #include #include #include +#include #define MAX_ETH_BEARERS 2 #define ETH_LINK_PRIORITY TIPC_DEF_LINK_PRI @@ -100,6 +101,11 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv; u32 size; + if (dev->nd_net != &init_net) { + kfree_skb(buf); + return 0; + } + if (likely(eb_ptr->bearer)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { size = msg_size((struct tipc_msg *)buf->data); diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index 848a6b6f90a6..f0679d283110 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -95,6 +95,9 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, struct sk_buff *nskb; struct x25_neigh *nb; + if (dev->nd_net != &init_net) + goto drop; + nskb = skb_copy(skb, GFP_ATOMIC); if (!nskb) goto drop; From e9dc86534051b78e41e5b746cccc291b57a3a311 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:02:17 +0200 Subject: [PATCH 1178/2804] [NET]: Make device event notification network namespace safe Every user of the network device notifiers is either a protocol stack or a pseudo device. If a protocol stack that does not have support for multiple network namespaces receives an event for a device that is not in the initial network namespace it quite possibly can get confused and do the wrong thing. To avoid problems until all of the protocol stacks are converted this patch modifies all netdev event handlers to ignore events on devices that are not in the initial network namespace. As the rest of the code is made network namespace aware these checks can be removed. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- arch/ia64/hp/sim/simeth.c | 3 +++ drivers/net/bonding/bond_main.c | 3 +++ drivers/net/hamradio/bpqether.c | 3 +++ drivers/net/pppoe.c | 3 +++ drivers/net/wan/dlci.c | 3 +++ drivers/net/wan/hdlc.c | 3 +++ drivers/net/wan/lapbether.c | 3 +++ net/8021q/vlan.c | 4 ++++ net/appletalk/aarp.c | 3 +++ net/appletalk/ddp.c | 3 +++ net/atm/clip.c | 3 +++ net/atm/mpc.c | 4 ++++ net/ax25/af_ax25.c | 3 +++ net/bridge/br_notify.c | 4 ++++ net/core/dst.c | 4 ++++ net/core/fib_rules.c | 4 ++++ net/core/pktgen.c | 3 +++ net/core/rtnetlink.c | 4 ++++ net/decnet/af_decnet.c | 3 +++ net/econet/af_econet.c | 3 +++ net/ipv4/arp.c | 3 +++ net/ipv4/devinet.c | 3 +++ net/ipv4/fib_frontend.c | 3 +++ net/ipv4/ipmr.c | 7 ++++++- net/ipv4/netfilter/ip_queue.c | 3 +++ net/ipv4/netfilter/ipt_MASQUERADE.c | 3 +++ net/ipv6/addrconf.c | 3 +++ net/ipv6/ndisc.c | 3 +++ net/ipv6/netfilter/ip6_queue.c | 3 +++ net/ipx/af_ipx.c | 3 +++ net/netfilter/nfnetlink_queue.c | 3 +++ net/netrom/af_netrom.c | 3 +++ net/packet/af_packet.c | 3 +++ net/rose/af_rose.c | 3 +++ net/tipc/eth_media.c | 3 +++ net/x25/af_x25.c | 3 +++ net/xfrm/xfrm_policy.c | 5 +++++ security/selinux/netif.c | 4 ++++ 38 files changed, 126 insertions(+), 1 deletion(-) diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index 4017696ada63..08b117e2c54b 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -294,6 +294,9 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) return NOTIFY_DONE; } + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE; /* diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e4e5fdc0430b..cf97d8a6326e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3299,6 +3299,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v { struct net_device *event_dev = (struct net_device *)ptr; + if (event_dev->nd_net != &init_net) + return NOTIFY_DONE; + dprintk("event_dev: %s, event: %lx\n", (event_dev ? event_dev->name : "None"), event); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 85fb8e7efacf..df09210f7351 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -563,6 +563,9 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (!dev_is_ethdev(dev)) return NOTIFY_DONE; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 60c0e4e17875..c5c70e4b1d36 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -301,6 +301,9 @@ static int pppoe_device_event(struct notifier_block *this, { struct net_device *dev = (struct net_device *) ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Only look at sockets that are using this specific device. */ switch (event) { case NETDEV_CHANGEMTU: diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 66be20c292b6..61041d5186ac 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -513,6 +513,9 @@ static int dlci_dev_event(struct notifier_block *unused, { struct net_device *dev = (struct net_device *) ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_UNREGISTER) { struct dlci_local *dlp; diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 3b57350eacca..ee23b91f23d9 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -109,6 +109,9 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event, unsigned long flags; int on; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (dev->get_stats != hdlc_get_stats) return NOTIFY_DONE; /* not an HDLC device */ diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index ca8b3c3cb931..699b93406dfb 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -394,6 +394,9 @@ static int lapbeth_device_event(struct notifier_block *this, struct lapbethdev *lapbeth; struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (!dev_is_ethdev(dev)) return NOTIFY_DONE; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 2a546919d6fb..d0d36fdedbe9 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "vlan.h" @@ -603,6 +604,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, int i, flgs; struct net_device *vlandev; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (!grp) goto out; diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 9267f4818795..e9a51a69870e 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -333,6 +333,9 @@ static int aarp_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; int ct; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_DOWN) { write_lock_bh(&aarp_lock); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index c1f1367cad48..36fcdbf923c4 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -649,6 +649,9 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_DOWN) /* Discard any use of this */ atalk_dev_down(dev); diff --git a/net/atm/clip.c b/net/atm/clip.c index 806ea98567c6..741742f00797 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -612,6 +612,9 @@ static int clip_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = arg; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_UNREGISTER) { neigh_ifdown(&clip_tbl, dev); return NOTIFY_DONE; diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 7c85aa551d5e..0968430a7f58 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -956,6 +956,10 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo struct lec_priv *priv; dev = (struct net_device *)dev_ptr; + + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (dev->name == NULL || strncmp(dev->name, "lec", 3)) return NOTIFY_DONE; /* we are only interested in lec:s */ diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index def6c42ad165..8d13a8bca0e0 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -104,6 +104,9 @@ static int ax25_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Reject non AX.25 devices */ if (dev->type != ARPHRD_AX25) return NOTIFY_DONE; diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index c8451d3a070c..07ac3ae68d8f 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -15,6 +15,7 @@ #include #include +#include #include "br_private.h" @@ -36,6 +37,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v struct net_bridge_port *p = dev->br_port; struct net_bridge *br; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* not a port of a bridge */ if (p == NULL) return NOTIFY_DONE; diff --git a/net/core/dst.c b/net/core/dst.c index c6a05879d58c..32267a16e01e 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -252,6 +253,9 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void struct net_device *dev = ptr; struct dst_entry *dst; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_UNREGISTER: case NETDEV_DOWN: diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 8c5474e16683..9eabe1ae01dc 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -11,6 +11,7 @@ #include #include #include +#include #include static LIST_HEAD(rules_ops); @@ -596,6 +597,9 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct fib_rules_ops *ops; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + ASSERT_RTNL(); rcu_read_lock(); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 33d7247fb19d..d7c30ce095a1 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1975,6 +1975,9 @@ static int pktgen_device_event(struct notifier_block *unused, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* It is OK that we do not hold the group lock right now, * as we run under the RTNL lock. */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index dca9e80ba574..41859508bedd 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1286,6 +1286,10 @@ static void rtnetlink_rcv(struct sock *sk, int len) static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; + + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_UNREGISTER: rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index aca4c4930eb6..83398da5d763 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -2089,6 +2089,9 @@ static int dn_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch(event) { case NETDEV_UP: dn_dev_up(dev); diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 7de3006af206..f877f3b5c725 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -1122,6 +1122,9 @@ static int econet_notifier(struct notifier_block *this, unsigned long msg, void struct net_device *dev = (struct net_device *)data; struct ec_device *edev; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (msg) { case NETDEV_UNREGISTER: /* A device has gone down - kill any data we hold for it. */ diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index bde129708e22..a11e7a5c1da4 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1205,6 +1205,9 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&arp_tbl, dev); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5dbe5803b7d5..c5eb1a29a5cf 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1051,6 +1051,9 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get_rtnl(dev); + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + ASSERT_RTNL(); if (!in_dev) { diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index eff6bce453ee..cefb55ec3d62 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -860,6 +860,9 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get_rtnl(dev); + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_UNREGISTER) { fib_disable_ip(dev, 2); return NOTIFY_DONE; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 35683e1a42e8..036598835c63 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1083,13 +1083,18 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr) { + struct net_device *dev = ptr; struct vif_device *v; int ct; + + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; v=&vif_table[0]; for (ct=0;ctdev==ptr) + if (v->dev==dev) vif_delete(ct); } return NOTIFY_DONE; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index cb5e61a1d7ab..d91856097f25 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -557,6 +557,9 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) ipq_dev_drop(dev->ifindex); diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 7c4e4be7c8b3..3e0b562b2db7 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -125,6 +125,9 @@ static int masq_device_event(struct notifier_block *this, { const struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_DOWN) { /* Device was downed. Search entire table for conntracks which were associated with that device, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cd2db728d183..1a6783646520 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2259,6 +2259,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, int run_pending = 0; int err; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch(event) { case NETDEV_REGISTER: if (!idev && dev->mtu >= IPV6_MIN_MTU) { diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 5b596659177c..d2d44dc22f19 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1525,6 +1525,9 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index dfc58fbdb68b..64536a3ef2f6 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -547,6 +547,9 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) ipq_dev_drop(dev->ifindex); diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index f7b4d383c609..24921f12e9af 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -347,6 +347,9 @@ static int ipxitf_device_event(struct notifier_block *notifier, struct net_device *dev = ptr; struct ipx_interface *i, *tmp; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event != NETDEV_DOWN && event != NETDEV_UP) goto out; diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index bb65a38c816c..5a8e8ff76641 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -734,6 +734,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) nfqnl_dev_drop(dev->ifindex); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index e969d1bc765c..3a4d479ea64e 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -106,6 +106,9 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event != NETDEV_DOWN) return NOTIFY_DONE; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index cae1ee4f2ad6..ad0052524e88 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1477,6 +1477,9 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void struct hlist_node *node; struct net_device *dev = data; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + read_lock(&packet_sklist_lock); sk_for_each(sk, node, &packet_sklist) { struct packet_sock *po = pkt_sk(sk); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 67e06ab7f854..509defe53ee5 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -197,6 +197,9 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event != NETDEV_DOWN) return NOTIFY_DONE; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index d2ed23704189..406f0d26fa81 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -198,6 +198,9 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, struct eth_bearer *eb_ptr = ð_bearers[0]; struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + while ((eb_ptr->dev != dev)) { if (++eb_ptr == stop) return NOTIFY_DONE; /* couldn't find device */ diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 2e9931571a4d..fc416f9606a9 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -191,6 +191,9 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct x25_neigh *nb; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (dev->type == ARPHRD_X25 #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) || dev->type == ARPHRD_ETHER diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 36dd31c40f4a..50682d3cd7a9 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2236,6 +2236,11 @@ static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo) static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) { + struct net_device *dev = ptr; + + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_DOWN: xfrm_flush_bundles(); diff --git a/security/selinux/netif.c b/security/selinux/netif.c index b10c34e8a743..e87ab948104c 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "security.h" #include "objsec.h" @@ -234,6 +235,9 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_DOWN) sel_netif_kill(dev); From b4b510290b056b86611757ce1175a230f1080f53 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:05:38 +0200 Subject: [PATCH 1179/2804] [NET]: Support multiple network namespaces with netlink Each netlink socket will live in exactly one network namespace, this includes the controlling kernel sockets. This patch updates all of the existing netlink protocols to only support the initial network namespace. Request by clients in other namespaces will get -ECONREFUSED. As they would if the kernel did not have the support for that netlink protocol compiled in. As each netlink protocol is updated to be multiple network namespace safe it can register multiple kernel sockets to acquire a presence in the rest of the network namespaces. The implementation in af_netlink is a simple filter implementation at hash table insertion and hash table look up time. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/connector/connector.c | 2 +- drivers/scsi/scsi_netlink.c | 2 +- drivers/scsi/scsi_transport_iscsi.c | 2 +- fs/ecryptfs/netlink.c | 2 +- include/linux/netlink.h | 6 +- kernel/audit.c | 4 +- lib/kobject_uevent.c | 5 +- net/bridge/netfilter/ebt_ulog.c | 5 +- net/core/rtnetlink.c | 4 +- net/decnet/netfilter/dn_rtmsg.c | 3 +- net/ipv4/fib_frontend.c | 4 +- net/ipv4/inet_diag.c | 4 +- net/ipv4/netfilter/ip_queue.c | 6 +- net/ipv4/netfilter/ipt_ULOG.c | 3 +- net/ipv6/netfilter/ip6_queue.c | 6 +- net/netfilter/nfnetlink.c | 2 +- net/netfilter/nfnetlink_log.c | 3 +- net/netfilter/nfnetlink_queue.c | 3 +- net/netlink/af_netlink.c | 104 +++++++++++++++++++++------- net/netlink/genetlink.c | 4 +- net/xfrm/xfrm_user.c | 2 +- security/selinux/netlink.c | 5 +- 22 files changed, 121 insertions(+), 60 deletions(-) diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index a7b9e9bb3e8d..569070997cc1 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -446,7 +446,7 @@ static int __devinit cn_init(void) dev->id.idx = cn_idx; dev->id.val = cn_val; - dev->nls = netlink_kernel_create(NETLINK_CONNECTOR, + dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, CN_NETLINK_USERS + 0xf, dev->input, NULL, THIS_MODULE); if (!dev->nls) diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 4bf9aa547c78..163acf6ad2d3 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -167,7 +167,7 @@ scsi_netlink_init(void) return; } - scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT, + scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL, THIS_MODULE); if (!scsi_nl_sock) { diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 34c1860a259d..4916f01230dc 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1523,7 +1523,7 @@ static __init int iscsi_transport_init(void) if (err) goto unregister_conn_class; - nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, NULL, + nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL, THIS_MODULE); if (!nls) { err = -ENOBUFS; diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c index fe9186312d7c..056519cd92bc 100644 --- a/fs/ecryptfs/netlink.c +++ b/fs/ecryptfs/netlink.c @@ -227,7 +227,7 @@ int ecryptfs_init_netlink(void) { int rc; - ecryptfs_nl_sock = netlink_kernel_create(NETLINK_ECRYPTFS, 0, + ecryptfs_nl_sock = netlink_kernel_create(&init_net, NETLINK_ECRYPTFS, 0, ecryptfs_receive_nl_message, NULL, THIS_MODULE); if (!ecryptfs_nl_sock) { diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 83d8239f0cce..d2843ae4a83a 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -27,6 +27,8 @@ #define MAX_LINKS 32 +struct net; + struct sockaddr_nl { sa_family_t nl_family; /* AF_NETLINK */ @@ -157,7 +159,8 @@ struct netlink_skb_parms #define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds) -extern struct sock *netlink_kernel_create(int unit, unsigned int groups, +extern struct sock *netlink_kernel_create(struct net *net, + int unit,unsigned int groups, void (*input)(struct sock *sk, int len), struct mutex *cb_mutex, struct module *module); @@ -206,6 +209,7 @@ struct netlink_callback struct netlink_notify { + struct net *net; int pid; int protocol; }; diff --git a/kernel/audit.c b/kernel/audit.c index eb0f9165b401..f3c390f6c0b4 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -876,8 +876,8 @@ static int __init audit_init(void) printk(KERN_INFO "audit: initializing netlink socket (%s)\n", audit_default ? "enabled" : "disabled"); - audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive, - NULL, THIS_MODULE); + audit_sock = netlink_kernel_create(&init_net, NETLINK_AUDIT, 0, + audit_receive, NULL, THIS_MODULE); if (!audit_sock) audit_panic("cannot initialize netlink socket"); else diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index df02814699d7..e06a8dcec0f0 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -280,9 +280,8 @@ EXPORT_SYMBOL_GPL(add_uevent_var); #if defined(CONFIG_NET) static int __init kobject_uevent_init(void) { - uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL, - NULL, THIS_MODULE); - + uevent_sock = netlink_kernel_create(&init_net, NETLINK_KOBJECT_UEVENT, + 1, NULL, NULL, THIS_MODULE); if (!uevent_sock) { printk(KERN_ERR "kobject_uevent: unable to create netlink socket!\n"); diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index 204c968fa86d..e7cfd30bac75 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -300,8 +300,9 @@ static int __init ebt_ulog_init(void) spin_lock_init(&ulog_buffers[i].lock); } - ebtulognl = netlink_kernel_create(NETLINK_NFLOG, EBT_ULOG_MAXNLGROUPS, - NULL, NULL, THIS_MODULE); + ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, + EBT_ULOG_MAXNLGROUPS, NULL, NULL, + THIS_MODULE); if (!ebtulognl) ret = -ENOMEM; else if ((ret = ebt_register_watcher(&ulog))) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 41859508bedd..416768d1e0cd 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1327,8 +1327,8 @@ void __init rtnetlink_init(void) if (!rta_buf) panic("rtnetlink_init: cannot allocate rta_buf\n"); - rtnl = netlink_kernel_create(NETLINK_ROUTE, RTNLGRP_MAX, rtnetlink_rcv, - &rtnl_mutex, THIS_MODULE); + rtnl = netlink_kernel_create(&init_net, NETLINK_ROUTE, RTNLGRP_MAX, + rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); if (rtnl == NULL) panic("rtnetlink_init: cannot initialize rtnetlink\n"); netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index 696234688cf6..ebb38feb4df3 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -137,7 +137,8 @@ static int __init dn_rtmsg_init(void) { int rv = 0; - dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, DNRNG_NLGRP_MAX, + dnrmg = netlink_kernel_create(&init_net, + NETLINK_DNRTMSG, DNRNG_NLGRP_MAX, dnrmg_receive_user_sk, NULL, THIS_MODULE); if (dnrmg == NULL) { printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket"); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index cefb55ec3d62..140bf7a8d877 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -816,8 +816,8 @@ static void nl_fib_input(struct sock *sk, int len) static void nl_fib_lookup_init(void) { - netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, NULL, - THIS_MODULE); + netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0, nl_fib_input, + NULL, THIS_MODULE); } static void fib_disable_ip(struct net_device *dev, int force) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 686ddd62f71a..031cc4856b49 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -897,8 +897,8 @@ static int __init inet_diag_init(void) if (!inet_diag_table) goto out; - idiagnl = netlink_kernel_create(NETLINK_INET_DIAG, 0, inet_diag_rcv, - NULL, THIS_MODULE); + idiagnl = netlink_kernel_create(&init_net, NETLINK_INET_DIAG, 0, + inet_diag_rcv, NULL, THIS_MODULE); if (idiagnl == NULL) goto out_free_table; err = 0; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index d91856097f25..82fda92e6b97 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -579,7 +579,7 @@ ipq_rcv_nl_event(struct notifier_block *this, if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL && n->pid) { write_lock_bh(&queue_lock); - if (n->pid == peer_pid) + if ((n->net == &init_net) && (n->pid == peer_pid)) __ipq_reset(); write_unlock_bh(&queue_lock); } @@ -671,8 +671,8 @@ static int __init ip_queue_init(void) struct proc_dir_entry *proc; netlink_register_notifier(&ipq_nl_notifier); - ipqnl = netlink_kernel_create(NETLINK_FIREWALL, 0, ipq_rcv_sk, - NULL, THIS_MODULE); + ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0, + ipq_rcv_sk, NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 6ca43e4ca7e3..c636d6d63574 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -409,7 +409,8 @@ static int __init ipt_ulog_init(void) for (i = 0; i < ULOG_MAXNLGROUPS; i++) setup_timer(&ulog_buffers[i].timer, ulog_timer, i); - nflognl = netlink_kernel_create(NETLINK_NFLOG, ULOG_MAXNLGROUPS, NULL, + nflognl = netlink_kernel_create(&init_net, + NETLINK_NFLOG, ULOG_MAXNLGROUPS, NULL, NULL, THIS_MODULE); if (!nflognl) return -ENOMEM; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 64536a3ef2f6..2f5a52453834 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -569,7 +569,7 @@ ipq_rcv_nl_event(struct notifier_block *this, if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW && n->pid) { write_lock_bh(&queue_lock); - if (n->pid == peer_pid) + if ((n->net == &init_net) && (n->pid == peer_pid)) __ipq_reset(); write_unlock_bh(&queue_lock); } @@ -661,8 +661,8 @@ static int __init ip6_queue_init(void) struct proc_dir_entry *proc; netlink_register_notifier(&ipq_nl_notifier); - ipqnl = netlink_kernel_create(NETLINK_IP6_FW, 0, ipq_rcv_sk, NULL, - THIS_MODULE); + ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, ipq_rcv_sk, + NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip6_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 8797e6953ef2..fa974e8e0ce6 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -264,7 +264,7 @@ static int __init nfnetlink_init(void) { printk("Netfilter messages via NETLINK v%s.\n", nfversion); - nfnl = netlink_kernel_create(NETLINK_NETFILTER, NFNLGRP_MAX, + nfnl = netlink_kernel_create(&init_net, NETLINK_NETFILTER, NFNLGRP_MAX, nfnetlink_rcv, NULL, THIS_MODULE); if (!nfnl) { printk(KERN_ERR "cannot initialize nfnetlink!\n"); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 2351533a8507..8e4001b8f764 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -706,7 +706,8 @@ nfulnl_rcv_nl_event(struct notifier_block *this, hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { UDEBUG("node = %p\n", inst); - if (n->pid == inst->peer_pid) + if ((n->net == &init_net) && + (n->pid == inst->peer_pid)) __instance_destroy(inst); } } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 5a8e8ff76641..c97369f48db7 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -765,7 +765,8 @@ nfqnl_rcv_nl_event(struct notifier_block *this, struct hlist_head *head = &instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if (n->pid == inst->peer_pid) + if ((n->net == &init_net) && + (n->pid == inst->peer_pid)) __instance_destroy(inst); } } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 406a493300d8..3029f865cd61 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -211,7 +211,7 @@ netlink_unlock_table(void) wake_up(&nl_table_wait); } -static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) +static __inline__ struct sock *netlink_lookup(struct net *net, int protocol, u32 pid) { struct nl_pid_hash *hash = &nl_table[protocol].hash; struct hlist_head *head; @@ -221,7 +221,7 @@ static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) read_lock(&nl_table_lock); head = nl_pid_hashfn(hash, pid); sk_for_each(sk, node, head) { - if (nlk_sk(sk)->pid == pid) { + if ((sk->sk_net == net) && (nlk_sk(sk)->pid == pid)) { sock_hold(sk); goto found; } @@ -328,7 +328,7 @@ netlink_update_listeners(struct sock *sk) * makes sure updates are visible before bind or setsockopt return. */ } -static int netlink_insert(struct sock *sk, u32 pid) +static int netlink_insert(struct sock *sk, struct net *net, u32 pid) { struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; struct hlist_head *head; @@ -341,7 +341,7 @@ static int netlink_insert(struct sock *sk, u32 pid) head = nl_pid_hashfn(hash, pid); len = 0; sk_for_each(osk, node, head) { - if (nlk_sk(osk)->pid == pid) + if ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid)) break; len++; } @@ -419,9 +419,6 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol) struct netlink_sock *nlk; int err = 0; - if (net != &init_net) - return -EAFNOSUPPORT; - sock->state = SS_UNCONNECTED; if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) @@ -481,6 +478,7 @@ static int netlink_release(struct socket *sock) if (nlk->pid && !nlk->subscriptions) { struct netlink_notify n = { + .net = sk->sk_net, .protocol = sk->sk_protocol, .pid = nlk->pid, }; @@ -509,6 +507,7 @@ static int netlink_release(struct socket *sock) static int netlink_autobind(struct socket *sock) { struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; struct hlist_head *head; struct sock *osk; @@ -522,6 +521,8 @@ retry: netlink_table_grab(); head = nl_pid_hashfn(hash, pid); sk_for_each(osk, node, head) { + if ((osk->sk_net != net)) + continue; if (nlk_sk(osk)->pid == pid) { /* Bind collision, search negative pid values. */ pid = rover--; @@ -533,7 +534,7 @@ retry: } netlink_table_ungrab(); - err = netlink_insert(sk, pid); + err = netlink_insert(sk, net, pid); if (err == -EADDRINUSE) goto retry; @@ -598,6 +599,7 @@ static int netlink_realloc_groups(struct sock *sk) static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; int err; @@ -619,7 +621,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len return -EINVAL; } else { err = nladdr->nl_pid ? - netlink_insert(sk, nladdr->nl_pid) : + netlink_insert(sk, net, nladdr->nl_pid) : netlink_autobind(sock); if (err) return err; @@ -703,10 +705,12 @@ static void netlink_overrun(struct sock *sk) static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) { int protocol = ssk->sk_protocol; + struct net *net; struct sock *sock; struct netlink_sock *nlk; - sock = netlink_lookup(protocol, pid); + net = ssk->sk_net; + sock = netlink_lookup(net, protocol, pid); if (!sock) return ERR_PTR(-ECONNREFUSED); @@ -887,6 +891,7 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff struct netlink_broadcast_data { struct sock *exclude_sk; + struct net *net; u32 pid; u32 group; int failure; @@ -909,6 +914,9 @@ static inline int do_one_broadcast(struct sock *sk, !test_bit(p->group - 1, nlk->groups)) goto out; + if ((sk->sk_net != p->net)) + goto out; + if (p->failure) { netlink_overrun(sk); goto out; @@ -947,6 +955,7 @@ out: int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation) { + struct net *net = ssk->sk_net; struct netlink_broadcast_data info; struct hlist_node *node; struct sock *sk; @@ -954,6 +963,7 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, skb = netlink_trim(skb, allocation); info.exclude_sk = ssk; + info.net = net; info.pid = pid; info.group = group; info.failure = 0; @@ -1002,6 +1012,9 @@ static inline int do_one_set_err(struct sock *sk, if (sk == p->exclude_sk) goto out; + if (sk->sk_net != p->exclude_sk->sk_net) + goto out; + if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || !test_bit(p->group - 1, nlk->groups)) goto out; @@ -1304,7 +1317,7 @@ static void netlink_data_ready(struct sock *sk, int len) */ struct sock * -netlink_kernel_create(int unit, unsigned int groups, +netlink_kernel_create(struct net *net, int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct mutex *cb_mutex, struct module *module) { @@ -1321,7 +1334,7 @@ netlink_kernel_create(int unit, unsigned int groups, if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) return NULL; - if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0) + if (__netlink_create(net, sock, cb_mutex, unit) < 0) goto out_sock_release; if (groups < 32) @@ -1336,18 +1349,20 @@ netlink_kernel_create(int unit, unsigned int groups, if (input) nlk_sk(sk)->data_ready = input; - if (netlink_insert(sk, 0)) + if (netlink_insert(sk, net, 0)) goto out_sock_release; nlk = nlk_sk(sk); nlk->flags |= NETLINK_KERNEL_SOCKET; netlink_table_grab(); - nl_table[unit].groups = groups; - nl_table[unit].listeners = listeners; - nl_table[unit].cb_mutex = cb_mutex; - nl_table[unit].module = module; - nl_table[unit].registered = 1; + if (!nl_table[unit].registered) { + nl_table[unit].groups = groups; + nl_table[unit].listeners = listeners; + nl_table[unit].cb_mutex = cb_mutex; + nl_table[unit].module = module; + nl_table[unit].registered = 1; + } netlink_table_ungrab(); return sk; @@ -1513,7 +1528,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, atomic_inc(&skb->users); cb->skb = skb; - sk = netlink_lookup(ssk->sk_protocol, NETLINK_CB(skb).pid); + sk = netlink_lookup(ssk->sk_net, ssk->sk_protocol, NETLINK_CB(skb).pid); if (sk == NULL) { netlink_destroy_callback(cb); return -ECONNREFUSED; @@ -1555,7 +1570,8 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) if (!skb) { struct sock *sk; - sk = netlink_lookup(in_skb->sk->sk_protocol, + sk = netlink_lookup(in_skb->sk->sk_net, + in_skb->sk->sk_protocol, NETLINK_CB(in_skb).pid); if (sk) { sk->sk_err = ENOBUFS; @@ -1706,6 +1722,7 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, #ifdef CONFIG_PROC_FS struct nl_seq_iter { + struct net *net; int link; int hash_idx; }; @@ -1723,6 +1740,8 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) for (j = 0; j <= hash->mask; j++) { sk_for_each(s, node, &hash->table[j]) { + if (iter->net != s->sk_net) + continue; if (off == pos) { iter->link = i; iter->hash_idx = j; @@ -1752,11 +1771,14 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) if (v == SEQ_START_TOKEN) return netlink_seq_socket_idx(seq, 0); - s = sk_next(v); + iter = seq->private; + s = v; + do { + s = sk_next(s); + } while (s && (iter->net != s->sk_net)); if (s) return s; - iter = seq->private; i = iter->link; j = iter->hash_idx + 1; @@ -1765,6 +1787,8 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) for (; j <= hash->mask; j++) { s = sk_head(&hash->table[j]); + while (s && (iter->net != s->sk_net)) + s = sk_next(s); if (s) { iter->link = i; iter->hash_idx = j; @@ -1835,15 +1859,24 @@ static int netlink_seq_open(struct inode *inode, struct file *file) seq = file->private_data; seq->private = iter; + iter->net = get_net(PROC_NET(inode)); return 0; } +static int netlink_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct nl_seq_iter *iter = seq->private; + put_net(iter->net); + return seq_release_private(inode, file); +} + static const struct file_operations netlink_seq_fops = { .owner = THIS_MODULE, .open = netlink_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = netlink_seq_release, }; #endif @@ -1885,6 +1918,27 @@ static struct net_proto_family netlink_family_ops = { .owner = THIS_MODULE, /* for consistency 8) */ }; +static int netlink_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_net_fops_create(net, "netlink", 0, &netlink_seq_fops)) + return -ENOMEM; +#endif + return 0; +} + +static void netlink_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(net, "netlink"); +#endif +} + +static struct pernet_operations netlink_net_ops = { + .init = netlink_net_init, + .exit = netlink_net_exit, +}; + static int __init netlink_proto_init(void) { struct sk_buff *dummy_skb; @@ -1930,9 +1984,7 @@ static int __init netlink_proto_init(void) } sock_register(&netlink_family_ops); -#ifdef CONFIG_PROC_FS - proc_net_fops_create(&init_net, "netlink", 0, &netlink_seq_fops); -#endif + register_pernet_subsys(&netlink_net_ops); /* The netlink device handler may be needed early. */ rtnetlink_init(); out: diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 8c11ca4a2121..af8fe26815fa 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -782,8 +782,8 @@ static int __init genl_init(void) netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); /* we'll bump the group number right afterwards */ - genl_sock = netlink_kernel_create(NETLINK_GENERIC, 0, genl_rcv, - NULL, THIS_MODULE); + genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0, + genl_rcv, NULL, THIS_MODULE); if (genl_sock == NULL) panic("GENL: Cannot initialize generic netlink\n"); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0d81c0f23919..1f8e7c22ddbd 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2399,7 +2399,7 @@ static int __init xfrm_user_init(void) printk(KERN_INFO "Initializing XFRM netlink socket\n"); - nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, + nlsk = netlink_kernel_create(&init_net, NETLINK_XFRM, XFRMNLGRP_MAX, xfrm_netlink_rcv, NULL, THIS_MODULE); if (nlsk == NULL) return -ENOMEM; diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index f49046de63a2..b59871d74dad 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c @@ -17,6 +17,7 @@ #include #include #include +#include static struct sock *selnl; @@ -104,8 +105,8 @@ void selnl_notify_policyload(u32 seqno) static int __init selnl_init(void) { - selnl = netlink_kernel_create(NETLINK_SELINUX, SELNLGRP_MAX, NULL, NULL, - THIS_MODULE); + selnl = netlink_kernel_create(&init_net, NETLINK_SELINUX, + SELNLGRP_MAX, NULL, NULL, THIS_MODULE); if (selnl == NULL) panic("SELinux: Cannot create netlink socket."); netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV); From 881d966b48b035ab3f3aeaae0f3d3f9b584f45b2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 17 Sep 2007 11:56:21 -0700 Subject: [PATCH 1180/2804] [NET]: Make the device list and device lookups per namespace. This patch makes most of the generic device layer network namespace safe. This patch makes dev_base_head a network namespace variable, and then it picks up a few associated variables. The functions: dev_getbyhwaddr dev_getfirsthwbytype dev_get_by_flags dev_get_by_name __dev_get_by_name dev_get_by_index __dev_get_by_index dev_ioctl dev_ethtool dev_load wireless_process_ioctl were modified to take a network namespace argument, and deal with it. vlan_ioctl_set and brioctl_set were modified so their hooks will receive a network namespace argument. So basically anthing in the core of the network stack that was affected to by the change of dev_base was modified to handle multiple network namespaces. The rest of the network stack was simply modified to explicitly use &init_net the initial network namespace. This can be fixed when those components of the network stack are modified to handle multiple network namespaces. For now the ifindex generator is left global. Fundametally ifindex numbers are per namespace, or else we will have corner case problems with migration when we get that far. At the same time there are assumptions in the network stack that the ifindex of a network device won't change. Making the ifindex number global seems a good compromise until the network stack can cope with ifindex changes when you change namespaces, and the like. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- arch/s390/appldata/appldata_net_sum.c | 3 +- arch/sparc64/solaris/ioctl.c | 3 +- drivers/atm/idt77252.c | 2 +- drivers/block/aoe/aoecmd.c | 3 +- drivers/infiniband/hw/cxgb3/cxio_hal.c | 3 +- drivers/net/bonding/bond_main.c | 2 +- drivers/net/bonding/bond_sysfs.c | 3 +- drivers/net/eql.c | 9 +- drivers/net/ifb.c | 3 +- drivers/net/macvlan.c | 2 +- drivers/net/pppoe.c | 4 +- drivers/net/shaper.c | 3 +- drivers/net/tun.c | 3 +- drivers/net/veth.c | 2 +- drivers/net/wan/dlci.c | 4 +- drivers/net/wan/sbni.c | 3 +- drivers/net/wireless/strip.c | 2 +- drivers/parisc/led.c | 2 +- fs/afs/netdevices.c | 5 +- include/linux/if_bridge.h | 2 +- include/linux/if_vlan.h | 2 +- include/linux/netdevice.h | 64 +++--- include/net/net_namespace.h | 4 + include/net/pkt_cls.h | 3 +- include/net/rtnetlink.h | 2 +- include/net/wext.h | 15 +- net/802/tr.c | 2 +- net/8021q/vlan.c | 6 +- net/8021q/vlan_netlink.c | 3 +- net/8021q/vlanproc.c | 6 +- net/appletalk/ddp.c | 6 +- net/atm/mpc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/bridge/br_if.c | 4 +- net/bridge/br_ioctl.c | 7 +- net/bridge/br_netlink.c | 5 +- net/bridge/br_private.h | 2 +- net/core/dev.c | 269 ++++++++++++++++--------- net/core/dev_mcast.c | 41 +++- net/core/ethtool.c | 4 +- net/core/fib_rules.c | 4 +- net/core/neighbour.c | 6 +- net/core/netpoll.c | 2 +- net/core/pktgen.c | 2 +- net/core/rtnetlink.c | 35 ++-- net/core/sock.c | 3 +- net/decnet/af_decnet.c | 2 +- net/decnet/dn_dev.c | 20 +- net/decnet/dn_fib.c | 8 +- net/decnet/dn_route.c | 6 +- net/decnet/sysctl_net_decnet.c | 4 +- net/econet/af_econet.c | 2 +- net/ipv4/arp.c | 4 +- net/ipv4/devinet.c | 18 +- net/ipv4/fib_frontend.c | 2 +- net/ipv4/fib_semantics.c | 4 +- net/ipv4/icmp.c | 2 +- net/ipv4/igmp.c | 4 +- net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_gre.c | 4 +- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/ipconfig.c | 2 +- net/ipv4/ipip.c | 4 +- net/ipv4/ipmr.c | 4 +- net/ipv4/ipvs/ip_vs_sync.c | 10 +- net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +- net/ipv4/route.c | 4 +- net/ipv6/addrconf.c | 28 +-- net/ipv6/af_inet6.c | 2 +- net/ipv6/anycast.c | 12 +- net/ipv6/datagram.c | 2 +- net/ipv6/ip6_tunnel.c | 6 +- net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/mcast.c | 12 +- net/ipv6/raw.c | 2 +- net/ipv6/reassembly.c | 2 +- net/ipv6/route.c | 4 +- net/ipv6/sit.c | 4 +- net/ipx/af_ipx.c | 6 +- net/irda/irnetlink.c | 9 +- net/llc/af_llc.c | 4 +- net/llc/llc_core.c | 3 +- net/mac80211/ieee80211.c | 1 + net/mac80211/ieee80211_cfg.c | 3 +- net/mac80211/tx.c | 9 +- net/mac80211/util.c | 7 +- net/netrom/nr_route.c | 6 +- net/packet/af_packet.c | 18 +- net/rose/rose_route.c | 8 +- net/sched/act_mirred.c | 3 +- net/sched/cls_api.c | 4 +- net/sched/em_meta.c | 2 +- net/sched/sch_api.c | 10 +- net/sctp/ipv6.c | 4 +- net/sctp/protocol.c | 2 +- net/socket.c | 22 +- net/tipc/eth_media.c | 2 +- net/wireless/wext.c | 38 +++- net/x25/x25_route.c | 2 +- 99 files changed, 553 insertions(+), 360 deletions(-) diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 2180ac105b05..6c1815a47714 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "appldata.h" @@ -107,7 +108,7 @@ static void appldata_get_net_sum_data(void *data) tx_dropped = 0; collisions = 0; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { stats = dev->get_stats(dev); rx_packets += stats->rx_packets; tx_packets += stats->tx_packets; diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c index 18352a498628..8ad10a6d993b 100644 --- a/arch/sparc64/solaris/ioctl.c +++ b/arch/sparc64/solaris/ioctl.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -686,7 +687,7 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg) int i = 0; read_lock_bh(&dev_base_lock); - for_each_netdev(d) + for_each_netdev(&init_net, d) i++; read_unlock_bh(&dev_base_lock); diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index f8b1700f4c16..eee54c0cde68 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -3576,7 +3576,7 @@ init_card(struct atm_dev *dev) * XXX: */ sprintf(tname, "eth%d", card->index); - tmp = dev_get_by_name(tname); /* jhs: was "tmp = dev_get(tname);" */ + tmp = dev_get_by_name(&init_net, tname); /* jhs: was "tmp = dev_get(tname);" */ if (tmp) { memcpy(card->atmdev->esi, tmp->dev_addr, 6); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 01fbdd38e3be..30394f78cac2 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "aoe.h" @@ -194,7 +195,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) sl = sl_tail = NULL; read_lock(&dev_base_lock); - for_each_netdev(ifp) { + for_each_netdev(&init_net, ifp) { dev_hold(ifp); if (!is_aoe_netif(ifp)) goto cont; diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index beb2a381467f..eec6a30840ca 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "cxio_resource.h" #include "cxio_hal.h" @@ -894,7 +895,7 @@ int cxio_rdev_open(struct cxio_rdev *rdev_p) if (cxio_hal_find_rdev_by_name(rdev_p->dev_name)) { return -EBUSY; } - netdev_p = dev_get_by_name(rdev_p->dev_name); + netdev_p = dev_get_by_name(&init_net, rdev_p->dev_name); if (!netdev_p) { return -EINVAL; } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index cf97d8a6326e..559fe9437e0b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3719,7 +3719,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd } down_write(&(bonding_rwsem)); - slave_dev = dev_get_by_name(ifr->ifr_slave); + slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave); dprintk("slave_dev=%p: \n", slave_dev); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 60cccf2aa959..8289e27a360a 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -35,6 +35,7 @@ #include #include #include +#include /* #define BONDING_DEBUG 1 */ #include "bonding.h" @@ -299,7 +300,7 @@ static ssize_t bonding_store_slaves(struct device *d, read_unlock_bh(&bond->lock); printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n", bond->dev->name, ifname); - dev = dev_get_by_name(ifname); + dev = dev_get_by_name(&init_net, ifname); if (!dev) { printk(KERN_INFO DRV_NAME ": %s: Interface %s does not exist!\n", diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 102218c4a907..f1cc66dcbdfd 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -116,6 +116,7 @@ #include #include #include +#include #include #include @@ -412,7 +413,7 @@ static int eql_enslave(struct net_device *master_dev, slaving_request_t __user * if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) return -EFAULT; - slave_dev = dev_get_by_name(srq.slave_name); + slave_dev = dev_get_by_name(&init_net, srq.slave_name); if (slave_dev) { if ((master_dev->flags & IFF_UP) == IFF_UP) { /* slave is not a master & not already a slave: */ @@ -460,7 +461,7 @@ static int eql_emancipate(struct net_device *master_dev, slaving_request_t __use if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) return -EFAULT; - slave_dev = dev_get_by_name(srq.slave_name); + slave_dev = dev_get_by_name(&init_net, srq.slave_name); ret = -EINVAL; if (slave_dev) { spin_lock_bh(&eql->queue.lock); @@ -493,7 +494,7 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp) if (copy_from_user(&sc, scp, sizeof (slave_config_t))) return -EFAULT; - slave_dev = dev_get_by_name(sc.slave_name); + slave_dev = dev_get_by_name(&init_net, sc.slave_name); if (!slave_dev) return -ENODEV; @@ -528,7 +529,7 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp) if (copy_from_user(&sc, scp, sizeof (slave_config_t))) return -EFAULT; - slave_dev = dev_get_by_name(sc.slave_name); + slave_dev = dev_get_by_name(&init_net, sc.slave_name); if (!slave_dev) return -ENODEV; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index f5c3598e59af..b06c6db4383a 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -34,6 +34,7 @@ #include #include #include +#include #define TX_TIMEOUT (2*HZ) @@ -97,7 +98,7 @@ static void ri_tasklet(unsigned long dev) stats->tx_packets++; stats->tx_bytes +=skb->len; - skb->dev = __dev_get_by_index(skb->iif); + skb->dev = __dev_get_by_index(&init_net, skb->iif); if (!skb->dev) { dev_kfree_skb(skb); stats->tx_dropped++; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index dc74d006e01f..2de073da182c 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -376,7 +376,7 @@ static int macvlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - lowerdev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK])); + lowerdev = __dev_get_by_index(dev->nd_net, nla_get_u32(tb[IFLA_LINK])); if (lowerdev == NULL) return -ENODEV; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index c5c70e4b1d36..2f130e06b6dc 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -216,7 +216,7 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) struct net_device *dev; int ifindex; - dev = dev_get_by_name(sp->sa_addr.pppoe.dev); + dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev); if(!dev) return NULL; ifindex = dev->ifindex; @@ -603,7 +603,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, /* Don't re-bind if sid==0 */ if (sp->sa_addr.pppoe.sid != 0) { - dev = dev_get_by_name(sp->sa_addr.pppoe.dev); + dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev); error = -ENODEV; if (!dev) diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 4c3d98ff4cd4..3773b3858bd4 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -86,6 +86,7 @@ #include #include +#include struct shaper_cb { unsigned long shapeclock; /* Time it should go out */ @@ -488,7 +489,7 @@ static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { case SHAPER_SET_DEV: { - struct net_device *them=__dev_get_by_name(ss->ss_name); + struct net_device *them=__dev_get_by_name(&init_net, ss->ss_name); if(them==NULL) return -ENODEV; if(sh->dev) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 62b2b3005019..691d264fbb6f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -475,7 +476,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) !capable(CAP_NET_ADMIN)) return -EPERM; } - else if (__dev_get_by_name(ifr->ifr_name)) + else if (__dev_get_by_name(&init_net, ifr->ifr_name)) return -EINVAL; else { char *name; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index ca1c6893b809..2c86a4459d8a 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -345,7 +345,7 @@ static int veth_newlink(struct net_device *dev, else snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); - peer = rtnl_create_link(ifname, &veth_link_ops, tbp); + peer = rtnl_create_link(dev->nd_net, ifname, &veth_link_ops, tbp); if (IS_ERR(peer)) return PTR_ERR(peer); diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 61041d5186ac..bc12810157e0 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -361,7 +361,7 @@ static int dlci_add(struct dlci_add *dlci) /* validate slave device */ - slave = dev_get_by_name(dlci->devname); + slave = dev_get_by_name(&init_net, dlci->devname); if (!slave) return -ENODEV; @@ -427,7 +427,7 @@ static int dlci_del(struct dlci_add *dlci) int err; /* validate slave device */ - master = __dev_get_by_name(dlci->devname); + master = __dev_get_by_name(&init_net, dlci->devname); if (!master) return(-ENODEV); diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 1cc18e787a65..8d7e01e8f56f 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -54,6 +54,7 @@ #include #include +#include #include #include @@ -1361,7 +1362,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) if (copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name )) return -EFAULT; - slave_dev = dev_get_by_name( slave_name ); + slave_dev = dev_get_by_name(&init_net, slave_name ); if( !slave_dev || !(slave_dev->flags & IFF_UP) ) { printk( KERN_ERR "%s: trying to enslave non-active " "device %s\n", dev->name, slave_name ); diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index edb214e8c744..904e548e6795 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1972,7 +1972,7 @@ static struct net_device *get_strip_dev(struct strip *strip_info) sizeof(zero_address))) { struct net_device *dev; read_lock_bh(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev->type == strip_info->dev->type && !memcmp(dev->dev_addr, &strip_info->true_dev_addr, diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index e5d7ed92d6f7..a6d6b2488ffc 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -359,7 +359,7 @@ static __inline__ int led_get_net_activity(void) * for reading should be OK */ read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct net_device_stats *stats; struct in_device *in_dev = __in_dev_get_rcu(dev); if (!in_dev || !in_dev->ifa_list) diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c index fc27d4b52e5f..49f189423063 100644 --- a/fs/afs/netdevices.c +++ b/fs/afs/netdevices.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "internal.h" /* @@ -23,7 +24,7 @@ int afs_get_MAC_address(u8 *mac, size_t maclen) BUG(); rtnl_lock(); - dev = __dev_getfirstbyhwtype(ARPHRD_ETHER); + dev = __dev_getfirstbyhwtype(&init_net, ARPHRD_ETHER); if (dev) { memcpy(mac, dev->dev_addr, maclen); ret = 0; @@ -47,7 +48,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs, ASSERT(maxbufs > 0); rtnl_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev->type == ARPHRD_LOOPBACK && !wantloopback) continue; idev = __in_dev_get_rtnl(dev); diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 4ff211d98769..99e3a1a00099 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -104,7 +104,7 @@ struct __fdb_entry #include -extern void brioctl_set(int (*ioctl_hook)(unsigned int, void __user *)); +extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff *skb); extern int (*br_should_route_hook)(struct sk_buff **pskb); diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index f8443fdb124a..976d4b1067d1 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -62,7 +62,7 @@ struct vlan_hdr { #define VLAN_VID_MASK 0xfff /* found in socket.c */ -extern void vlan_ioctl_set(int (*hook)(void __user *)); +extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); #define VLAN_NAME "vlan" diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index dc3c15b726bc..7353b3e1f4fc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -741,44 +741,48 @@ struct packet_type { #include extern struct net_device loopback_dev; /* The loopback */ -extern struct list_head dev_base_head; /* All devices */ extern rwlock_t dev_base_lock; /* Device list lock */ -#define for_each_netdev(d) \ - list_for_each_entry(d, &dev_base_head, dev_list) -#define for_each_netdev_safe(d, n) \ - list_for_each_entry_safe(d, n, &dev_base_head, dev_list) -#define for_each_netdev_continue(d) \ - list_for_each_entry_continue(d, &dev_base_head, dev_list) + +#define for_each_netdev(net, d) \ + list_for_each_entry(d, &(net)->dev_base_head, dev_list) +#define for_each_netdev_safe(net, d, n) \ + list_for_each_entry_safe(d, n, &(net)->dev_base_head, dev_list) +#define for_each_netdev_continue(net, d) \ + list_for_each_entry_continue(d, &(net)->dev_base_head, dev_list) #define net_device_entry(lh) list_entry(lh, struct net_device, dev_list) -static inline struct net_device *next_net_device(struct net_device *dev) -{ - struct list_head *lh; +#define next_net_device(d) \ +({ \ + struct net_device *dev = d; \ + struct list_head *lh; \ + struct net *net; \ + \ + net = dev->nd_net; \ + lh = dev->dev_list.next; \ + lh == &net->dev_base_head ? NULL : net_device_entry(lh); \ +}) - lh = dev->dev_list.next; - return lh == &dev_base_head ? NULL : net_device_entry(lh); -} - -static inline struct net_device *first_net_device(void) -{ - return list_empty(&dev_base_head) ? NULL : - net_device_entry(dev_base_head.next); -} +#define first_net_device(N) \ +({ \ + struct net *NET = (N); \ + list_empty(&NET->dev_base_head) ? NULL : \ + net_device_entry(NET->dev_base_head.next); \ +}) extern int netdev_boot_setup_check(struct net_device *dev); extern unsigned long netdev_boot_base(const char *prefix, int unit); -extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr); -extern struct net_device *dev_getfirstbyhwtype(unsigned short type); -extern struct net_device *__dev_getfirstbyhwtype(unsigned short type); +extern struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *hwaddr); +extern struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type); +extern struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type); extern void dev_add_pack(struct packet_type *pt); extern void dev_remove_pack(struct packet_type *pt); extern void __dev_remove_pack(struct packet_type *pt); -extern struct net_device *dev_get_by_flags(unsigned short flags, +extern struct net_device *dev_get_by_flags(struct net *net, unsigned short flags, unsigned short mask); -extern struct net_device *dev_get_by_name(const char *name); -extern struct net_device *__dev_get_by_name(const char *name); +extern struct net_device *dev_get_by_name(struct net *net, const char *name); +extern struct net_device *__dev_get_by_name(struct net *net, const char *name); extern int dev_alloc_name(struct net_device *dev, const char *name); extern int dev_open(struct net_device *dev); extern int dev_close(struct net_device *dev); @@ -790,8 +794,8 @@ extern void synchronize_net(void); extern int register_netdevice_notifier(struct notifier_block *nb); extern int unregister_netdevice_notifier(struct notifier_block *nb); extern int call_netdevice_notifiers(unsigned long val, void *v); -extern struct net_device *dev_get_by_index(int ifindex); -extern struct net_device *__dev_get_by_index(int ifindex); +extern struct net_device *dev_get_by_index(struct net *net, int ifindex); +extern struct net_device *__dev_get_by_index(struct net *net, int ifindex); extern int dev_restart(struct net_device *dev); #ifdef CONFIG_NETPOLL_TRAP extern int netpoll_trap(void); @@ -1007,8 +1011,8 @@ extern int netif_rx_ni(struct sk_buff *skb); #define HAVE_NETIF_RECEIVE_SKB 1 extern int netif_receive_skb(struct sk_buff *skb); extern int dev_valid_name(const char *name); -extern int dev_ioctl(unsigned int cmd, void __user *); -extern int dev_ethtool(struct ifreq *); +extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *); +extern int dev_ethtool(struct net *net, struct ifreq *); extern unsigned dev_get_flags(const struct net_device *); extern int dev_change_flags(struct net_device *, unsigned); extern int dev_change_name(struct net_device *, char *); @@ -1327,7 +1331,7 @@ extern void dev_set_allmulti(struct net_device *dev, int inc); extern void netdev_state_change(struct net_device *dev); extern void netdev_features_change(struct net_device *dev); /* Load a device via the kmod */ -extern void dev_load(const char *name); +extern void dev_load(struct net *net, const char *name); extern void dev_mcast_init(void); extern int netdev_max_backlog; extern int weight_p; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 547247681345..fac42db7f6d0 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -22,6 +22,10 @@ struct net { struct proc_dir_entry *proc_net; struct proc_dir_entry *proc_net_stat; struct proc_dir_entry *proc_net_root; + + struct list_head dev_base_head; + struct hlist_head *dev_name_head; + struct hlist_head *dev_index_head; }; extern struct net init_net; diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 7968b1d66369..f285de69c615 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -2,6 +2,7 @@ #define __NET_PKT_CLS_H #include +#include #include #include @@ -351,7 +352,7 @@ tcf_match_indev(struct sk_buff *skb, char *indev) if (indev[0]) { if (!skb->iif) return 0; - dev = __dev_get_by_index(skb->iif); + dev = __dev_get_by_index(&init_net, skb->iif); if (!dev || strcmp(indev, dev->name)) return 0; } diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 8218288ab7ee..793863e09c69 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -78,7 +78,7 @@ extern void __rtnl_link_unregister(struct rtnl_link_ops *ops); extern int rtnl_link_register(struct rtnl_link_ops *ops); extern void rtnl_link_unregister(struct rtnl_link_ops *ops); -extern struct net_device *rtnl_create_link(char *ifname, +extern struct net_device *rtnl_create_link(struct net *net, char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]); extern const struct nla_policy ifla_policy[IFLA_MAX+1]; diff --git a/include/net/wext.h b/include/net/wext.h index c02b8decf3af..80b31d826b7a 100644 --- a/include/net/wext.h +++ b/include/net/wext.h @@ -5,16 +5,23 @@ * wireless extensions interface to the core code */ +struct net; + #ifdef CONFIG_WIRELESS_EXT -extern int wext_proc_init(void); -extern int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd, +extern int wext_proc_init(struct net *net); +extern void wext_proc_exit(struct net *net); +extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg); #else -static inline int wext_proc_init(void) +static inline int wext_proc_init(struct net *net) { return 0; } -static inline int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd, +static inline void wext_proc_exit(struct net *net) +{ + return; +} +static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg) { return -EINVAL; diff --git a/net/802/tr.c b/net/802/tr.c index 032c31e748eb..55c76d77d322 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -533,7 +533,7 @@ static int rif_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "if TR address TTL rcf routing segments\n"); else { - struct net_device *dev = dev_get_by_index(entry->iface); + struct net_device *dev = dev_get_by_index(&init_net, entry->iface); long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout) - (long) jiffies; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index d0d36fdedbe9..a9ced0a6f4c0 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -51,7 +51,7 @@ static char vlan_copyright[] = "Ben Greear "; static char vlan_buggyright[] = "David S. Miller "; static int vlan_device_event(struct notifier_block *, unsigned long, void *); -static int vlan_ioctl_handler(void __user *); +static int vlan_ioctl_handler(struct net *net, void __user *); static int unregister_vlan_dev(struct net_device *, unsigned short ); static struct notifier_block vlan_notifier_block = { @@ -697,7 +697,7 @@ out: * o execute requested action or pass command to the device driver * arg is really a struct vlan_ioctl_args __user *. */ -static int vlan_ioctl_handler(void __user *arg) +static int vlan_ioctl_handler(struct net *net, void __user *arg) { int err; unsigned short vid = 0; @@ -726,7 +726,7 @@ static int vlan_ioctl_handler(void __user *arg) case GET_VLAN_REALDEV_NAME_CMD: case GET_VLAN_VID_CMD: err = -ENODEV; - dev = __dev_get_by_name(args.device1); + dev = __dev_get_by_name(&init_net, args.device1); if (!dev) goto out; diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 6cdd1e015e2d..0996185e2ed5 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "vlan.h" @@ -112,7 +113,7 @@ static int vlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - real_dev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK])); + real_dev = __dev_get_by_index(&init_net, nla_get_u32(tb[IFLA_LINK])); if (!real_dev) return -ENODEV; diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index ac80e6b9ef53..6cefdf8e381a 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -254,7 +254,7 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (!is_vlan_dev(dev)) continue; @@ -273,9 +273,9 @@ static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) dev = (struct net_device *)v; if (v == SEQ_START_TOKEN) - dev = net_device_entry(&dev_base_head); + dev = net_device_entry(&init_net.dev_base_head); - for_each_netdev_continue(dev) { + for_each_netdev_continue(&init_net, dev) { if (!is_vlan_dev(dev)) continue; diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 36fcdbf923c4..7c0b5151d526 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -677,7 +677,7 @@ static int atif_ioctl(int cmd, void __user *arg) if (copy_from_user(&atreq, arg, sizeof(atreq))) return -EFAULT; - dev = __dev_get_by_name(atreq.ifr_name); + dev = __dev_get_by_name(&init_net, atreq.ifr_name); if (!dev) return -ENODEV; @@ -901,7 +901,7 @@ static int atrtr_ioctl(unsigned int cmd, void __user *arg) if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1)) return -EFAULT; name[IFNAMSIZ-1] = '\0'; - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(&init_net, name); if (!dev) return -ENODEV; } @@ -1273,7 +1273,7 @@ static __inline__ int is_ip_over_ddp(struct sk_buff *skb) static int handle_ip_over_ddp(struct sk_buff *skb) { - struct net_device *dev = __dev_get_by_name("ipddp0"); + struct net_device *dev = __dev_get_by_name(&init_net, "ipddp0"); struct net_device_stats *stats; /* This needs to be able to handle ipddp"N" devices */ diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 0968430a7f58..2086396de177 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -244,7 +244,7 @@ static struct net_device *find_lec_by_itfnum(int itf) char name[IFNAMSIZ]; sprintf(name, "lec%d", itf); - dev = dev_get_by_name(name); + dev = dev_get_by_name(&init_net, name); return dev; } diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 8d13a8bca0e0..993e5c75e909 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -631,7 +631,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, break; } - dev = dev_get_by_name(devname); + dev = dev_get_by_name(&init_net, devname); if (dev == NULL) { res = -ENODEV; break; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 9272f12f664c..935784f736b3 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -303,7 +303,7 @@ int br_del_bridge(const char *name) int ret = 0; rtnl_lock(); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(&init_net, name); if (dev == NULL) ret = -ENXIO; /* Could not find device */ @@ -444,7 +444,7 @@ void __exit br_cleanup_bridges(void) struct net_device *dev, *nxt; rtnl_lock(); - for_each_netdev_safe(dev, nxt) + for_each_netdev_safe(&init_net, dev, nxt) if (dev->priv_flags & IFF_EBRIDGE) del_br(dev->priv); rtnl_unlock(); diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index bb15e9e259b1..0655a5f07f58 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "br_private.h" @@ -27,7 +28,7 @@ static int get_bridge_ifindices(int *indices, int num) struct net_device *dev; int i = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (i >= num) break; if (dev->priv_flags & IFF_EBRIDGE) @@ -90,7 +91,7 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd) if (!capable(CAP_NET_ADMIN)) return -EPERM; - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev == NULL) return -EINVAL; @@ -364,7 +365,7 @@ static int old_deviceless(void __user *uarg) return -EOPNOTSUPP; } -int br_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg) +int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg) { switch (cmd) { case SIOCGIFBR: diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 0fcf6f073064..53ab8e0cb518 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -12,6 +12,7 @@ #include #include +#include #include "br_private.h" static inline size_t br_nlmsg_size(void) @@ -110,7 +111,7 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) int idx; idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { /* not a bridge port */ if (dev->br_port == NULL || idx < cb->args[0]) goto skip; @@ -155,7 +156,7 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) if (new_state > BR_STATE_BLOCKING) return -EINVAL; - dev = __dev_get_by_index(ifm->ifi_index); + dev = __dev_get_by_index(&init_net, ifm->ifi_index); if (!dev) return -ENODEV; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index e6dc6f52990d..f666f7b28ff5 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -192,7 +192,7 @@ extern struct sk_buff *br_handle_frame(struct net_bridge_port *p, /* br_ioctl.c */ extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -extern int br_ioctl_deviceless_stub(unsigned int cmd, void __user *arg); +extern int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *arg); /* br_netfilter.c */ #ifdef CONFIG_BRIDGE_NETFILTER diff --git a/net/core/dev.c b/net/core/dev.c index 40fd66fbe4e1..3a3d5ee73909 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -190,25 +190,22 @@ static struct net_dma net_dma = { * unregister_netdevice(), which must be called with the rtnl * semaphore held. */ -LIST_HEAD(dev_base_head); DEFINE_RWLOCK(dev_base_lock); -EXPORT_SYMBOL(dev_base_head); EXPORT_SYMBOL(dev_base_lock); #define NETDEV_HASHBITS 8 -static struct hlist_head dev_name_head[1<dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)]; } -static inline struct hlist_head *dev_index_hash(int ifindex) +static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) { - return &dev_index_head[ifindex & ((1<dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; } /* @@ -492,7 +489,7 @@ unsigned long netdev_boot_base(const char *prefix, int unit) * If device already registered then return base of 1 * to indicate not to probe for this interface */ - if (__dev_get_by_name(name)) + if (__dev_get_by_name(&init_net, name)) return 1; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) @@ -547,11 +544,11 @@ __setup("netdev=", netdev_boot_setup); * careful with locks. */ -struct net_device *__dev_get_by_name(const char *name) +struct net_device *__dev_get_by_name(struct net *net, const char *name) { struct hlist_node *p; - hlist_for_each(p, dev_name_hash(name)) { + hlist_for_each(p, dev_name_hash(net, name)) { struct net_device *dev = hlist_entry(p, struct net_device, name_hlist); if (!strncmp(dev->name, name, IFNAMSIZ)) @@ -571,12 +568,12 @@ struct net_device *__dev_get_by_name(const char *name) * matching device is found. */ -struct net_device *dev_get_by_name(const char *name) +struct net_device *dev_get_by_name(struct net *net, const char *name) { struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(net, name); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); @@ -594,11 +591,11 @@ struct net_device *dev_get_by_name(const char *name) * or @dev_base_lock. */ -struct net_device *__dev_get_by_index(int ifindex) +struct net_device *__dev_get_by_index(struct net *net, int ifindex) { struct hlist_node *p; - hlist_for_each(p, dev_index_hash(ifindex)) { + hlist_for_each(p, dev_index_hash(net, ifindex)) { struct net_device *dev = hlist_entry(p, struct net_device, index_hlist); if (dev->ifindex == ifindex) @@ -618,12 +615,12 @@ struct net_device *__dev_get_by_index(int ifindex) * dev_put to indicate they have finished with it. */ -struct net_device *dev_get_by_index(int ifindex) +struct net_device *dev_get_by_index(struct net *net, int ifindex) { struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifindex); + dev = __dev_get_by_index(net, ifindex); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); @@ -644,13 +641,13 @@ struct net_device *dev_get_by_index(int ifindex) * If the API was consistent this would be __dev_get_by_hwaddr */ -struct net_device *dev_getbyhwaddr(unsigned short type, char *ha) +struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *ha) { struct net_device *dev; ASSERT_RTNL(); - for_each_netdev(dev) + for_each_netdev(&init_net, dev) if (dev->type == type && !memcmp(dev->dev_addr, ha, dev->addr_len)) return dev; @@ -660,12 +657,12 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha) EXPORT_SYMBOL(dev_getbyhwaddr); -struct net_device *__dev_getfirstbyhwtype(unsigned short type) +struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) { struct net_device *dev; ASSERT_RTNL(); - for_each_netdev(dev) + for_each_netdev(net, dev) if (dev->type == type) return dev; @@ -674,12 +671,12 @@ struct net_device *__dev_getfirstbyhwtype(unsigned short type) EXPORT_SYMBOL(__dev_getfirstbyhwtype); -struct net_device *dev_getfirstbyhwtype(unsigned short type) +struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type) { struct net_device *dev; rtnl_lock(); - dev = __dev_getfirstbyhwtype(type); + dev = __dev_getfirstbyhwtype(net, type); if (dev) dev_hold(dev); rtnl_unlock(); @@ -699,13 +696,13 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype); * dev_put to indicate they have finished with it. */ -struct net_device * dev_get_by_flags(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; ret = NULL; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(net, dev) { if (((dev->flags ^ if_flags) & mask) == 0) { dev_hold(dev); ret = dev; @@ -763,6 +760,10 @@ int dev_alloc_name(struct net_device *dev, const char *name) const int max_netdevices = 8*PAGE_SIZE; long *inuse; struct net_device *d; + struct net *net; + + BUG_ON(!dev->nd_net); + net = dev->nd_net; p = strnchr(name, IFNAMSIZ-1, '%'); if (p) { @@ -779,7 +780,7 @@ int dev_alloc_name(struct net_device *dev, const char *name) if (!inuse) return -ENOMEM; - for_each_netdev(d) { + for_each_netdev(net, d) { if (!sscanf(d->name, name, &i)) continue; if (i < 0 || i >= max_netdevices) @@ -796,7 +797,7 @@ int dev_alloc_name(struct net_device *dev, const char *name) } snprintf(buf, sizeof(buf), name, i); - if (!__dev_get_by_name(buf)) { + if (!__dev_get_by_name(net, buf)) { strlcpy(dev->name, buf, IFNAMSIZ); return i; } @@ -822,9 +823,12 @@ int dev_change_name(struct net_device *dev, char *newname) char oldname[IFNAMSIZ]; int err = 0; int ret; + struct net *net; ASSERT_RTNL(); + BUG_ON(!dev->nd_net); + net = dev->nd_net; if (dev->flags & IFF_UP) return -EBUSY; @@ -839,7 +843,7 @@ int dev_change_name(struct net_device *dev, char *newname) return err; strcpy(newname, dev->name); } - else if (__dev_get_by_name(newname)) + else if (__dev_get_by_name(net, newname)) return -EEXIST; else strlcpy(dev->name, newname, IFNAMSIZ); @@ -849,7 +853,7 @@ rollback: write_lock_bh(&dev_base_lock); hlist_del(&dev->name_hlist); - hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); + hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); write_unlock_bh(&dev_base_lock); ret = raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); @@ -908,12 +912,12 @@ void netdev_state_change(struct net_device *dev) * available in this kernel then it becomes a nop. */ -void dev_load(const char *name) +void dev_load(struct net *net, const char *name) { struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(net, name); read_unlock(&dev_base_lock); if (!dev && capable(CAP_SYS_MODULE)) @@ -1052,6 +1056,8 @@ int dev_close(struct net_device *dev) } +static int dev_boot_phase = 1; + /* * Device change register/unregister. These are not inline or static * as we export them to the world. @@ -1075,23 +1081,27 @@ int register_netdevice_notifier(struct notifier_block *nb) { struct net_device *dev; struct net_device *last; + struct net *net; int err; rtnl_lock(); err = raw_notifier_chain_register(&netdev_chain, nb); if (err) goto unlock; + if (dev_boot_phase) + goto unlock; + for_each_net(net) { + for_each_netdev(net, dev) { + err = nb->notifier_call(nb, NETDEV_REGISTER, dev); + err = notifier_to_errno(err); + if (err) + goto rollback; - for_each_netdev(dev) { - err = nb->notifier_call(nb, NETDEV_REGISTER, dev); - err = notifier_to_errno(err); - if (err) - goto rollback; + if (!(dev->flags & IFF_UP)) + continue; - if (!(dev->flags & IFF_UP)) - continue; - - nb->notifier_call(nb, NETDEV_UP, dev); + nb->notifier_call(nb, NETDEV_UP, dev); + } } unlock: @@ -1100,15 +1110,17 @@ unlock: rollback: last = dev; - for_each_netdev(dev) { - if (dev == last) - break; + for_each_net(net) { + for_each_netdev(net, dev) { + if (dev == last) + break; - if (dev->flags & IFF_UP) { - nb->notifier_call(nb, NETDEV_GOING_DOWN, dev); - nb->notifier_call(nb, NETDEV_DOWN, dev); + if (dev->flags & IFF_UP) { + nb->notifier_call(nb, NETDEV_GOING_DOWN, dev); + nb->notifier_call(nb, NETDEV_DOWN, dev); + } + nb->notifier_call(nb, NETDEV_UNREGISTER, dev); } - nb->notifier_call(nb, NETDEV_UNREGISTER, dev); } goto unlock; } @@ -2187,7 +2199,7 @@ int register_gifconf(unsigned int family, gifconf_func_t * gifconf) * match. --pb */ -static int dev_ifname(struct ifreq __user *arg) +static int dev_ifname(struct net *net, struct ifreq __user *arg) { struct net_device *dev; struct ifreq ifr; @@ -2200,7 +2212,7 @@ static int dev_ifname(struct ifreq __user *arg) return -EFAULT; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifr.ifr_ifindex); + dev = __dev_get_by_index(net, ifr.ifr_ifindex); if (!dev) { read_unlock(&dev_base_lock); return -ENODEV; @@ -2220,7 +2232,7 @@ static int dev_ifname(struct ifreq __user *arg) * Thus we will need a 'compatibility mode'. */ -static int dev_ifconf(char __user *arg) +static int dev_ifconf(struct net *net, char __user *arg) { struct ifconf ifc; struct net_device *dev; @@ -2244,7 +2256,7 @@ static int dev_ifconf(char __user *arg) */ total = 0; - for_each_netdev(dev) { + for_each_netdev(net, dev) { for (i = 0; i < NPROTO; i++) { if (gifconf_list[i]) { int done; @@ -2278,6 +2290,7 @@ static int dev_ifconf(char __user *arg) */ void *dev_seq_start(struct seq_file *seq, loff_t *pos) { + struct net *net = seq->private; loff_t off; struct net_device *dev; @@ -2286,7 +2299,7 @@ void *dev_seq_start(struct seq_file *seq, loff_t *pos) return SEQ_START_TOKEN; off = 1; - for_each_netdev(dev) + for_each_netdev(net, dev) if (off++ == *pos) return dev; @@ -2295,9 +2308,10 @@ void *dev_seq_start(struct seq_file *seq, loff_t *pos) void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { + struct net *net = seq->private; ++*pos; return v == SEQ_START_TOKEN ? - first_net_device() : next_net_device((struct net_device *)v); + first_net_device(net) : next_net_device((struct net_device *)v); } void dev_seq_stop(struct seq_file *seq, void *v) @@ -2393,7 +2407,22 @@ static const struct seq_operations dev_seq_ops = { static int dev_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &dev_seq_ops); + struct seq_file *seq; + int res; + res = seq_open(file, &dev_seq_ops); + if (!res) { + seq = file->private_data; + seq->private = get_net(PROC_NET(inode)); + } + return res; +} + +static int dev_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = seq->private; + put_net(net); + return seq_release(inode, file); } static const struct file_operations dev_seq_fops = { @@ -2401,7 +2430,7 @@ static const struct file_operations dev_seq_fops = { .open = dev_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = dev_seq_release, }; static const struct seq_operations softnet_seq_ops = { @@ -2553,30 +2582,49 @@ static const struct file_operations ptype_seq_fops = { }; -static int __init dev_proc_init(void) +static int dev_proc_net_init(struct net *net) { int rc = -ENOMEM; - if (!proc_net_fops_create(&init_net, "dev", S_IRUGO, &dev_seq_fops)) + if (!proc_net_fops_create(net, "dev", S_IRUGO, &dev_seq_fops)) goto out; - if (!proc_net_fops_create(&init_net, "softnet_stat", S_IRUGO, &softnet_seq_fops)) + if (!proc_net_fops_create(net, "softnet_stat", S_IRUGO, &softnet_seq_fops)) goto out_dev; - if (!proc_net_fops_create(&init_net, "ptype", S_IRUGO, &ptype_seq_fops)) + if (!proc_net_fops_create(net, "ptype", S_IRUGO, &ptype_seq_fops)) goto out_softnet; - if (wext_proc_init()) + if (wext_proc_init(net)) goto out_ptype; rc = 0; out: return rc; out_ptype: - proc_net_remove(&init_net, "ptype"); + proc_net_remove(net, "ptype"); out_softnet: - proc_net_remove(&init_net, "softnet_stat"); + proc_net_remove(net, "softnet_stat"); out_dev: - proc_net_remove(&init_net, "dev"); + proc_net_remove(net, "dev"); goto out; } + +static void dev_proc_net_exit(struct net *net) +{ + wext_proc_exit(net); + + proc_net_remove(net, "ptype"); + proc_net_remove(net, "softnet_stat"); + proc_net_remove(net, "dev"); +} + +static struct pernet_operations dev_proc_ops = { + .init = dev_proc_net_init, + .exit = dev_proc_net_exit, +}; + +static int __init dev_proc_init(void) +{ + return register_pernet_subsys(&dev_proc_ops); +} #else #define dev_proc_init() 0 #endif /* CONFIG_PROC_FS */ @@ -3011,10 +3059,10 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) /* * Perform the SIOCxIFxxx calls. */ -static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) +static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) { int err; - struct net_device *dev = __dev_get_by_name(ifr->ifr_name); + struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); if (!dev) return -ENODEV; @@ -3167,7 +3215,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) * positive or a negative errno code on error. */ -int dev_ioctl(unsigned int cmd, void __user *arg) +int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) { struct ifreq ifr; int ret; @@ -3180,12 +3228,12 @@ int dev_ioctl(unsigned int cmd, void __user *arg) if (cmd == SIOCGIFCONF) { rtnl_lock(); - ret = dev_ifconf((char __user *) arg); + ret = dev_ifconf(net, (char __user *) arg); rtnl_unlock(); return ret; } if (cmd == SIOCGIFNAME) - return dev_ifname((struct ifreq __user *)arg); + return dev_ifname(net, (struct ifreq __user *)arg); if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; @@ -3215,9 +3263,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) case SIOCGIFMAP: case SIOCGIFINDEX: case SIOCGIFTXQLEN: - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); read_lock(&dev_base_lock); - ret = dev_ifsioc(&ifr, cmd); + ret = dev_ifsioc(net, &ifr, cmd); read_unlock(&dev_base_lock); if (!ret) { if (colon) @@ -3229,9 +3277,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) return ret; case SIOCETHTOOL: - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); rtnl_lock(); - ret = dev_ethtool(&ifr); + ret = dev_ethtool(net, &ifr); rtnl_unlock(); if (!ret) { if (colon) @@ -3253,9 +3301,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) case SIOCSIFNAME: if (!capable(CAP_NET_ADMIN)) return -EPERM; - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); rtnl_lock(); - ret = dev_ifsioc(&ifr, cmd); + ret = dev_ifsioc(net, &ifr, cmd); rtnl_unlock(); if (!ret) { if (colon) @@ -3294,9 +3342,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) /* fall through */ case SIOCBONDSLAVEINFOQUERY: case SIOCBONDINFOQUERY: - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); rtnl_lock(); - ret = dev_ifsioc(&ifr, cmd); + ret = dev_ifsioc(net, &ifr, cmd); rtnl_unlock(); return ret; @@ -3316,9 +3364,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) if (cmd == SIOCWANDEV || (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15)) { - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); rtnl_lock(); - ret = dev_ifsioc(&ifr, cmd); + ret = dev_ifsioc(net, &ifr, cmd); rtnl_unlock(); if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) @@ -3327,7 +3375,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) } /* Take care of Wireless Extensions */ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) - return wext_handle_ioctl(&ifr, cmd, arg); + return wext_handle_ioctl(net, &ifr, cmd, arg); return -EINVAL; } } @@ -3340,19 +3388,17 @@ int dev_ioctl(unsigned int cmd, void __user *arg) * number. The caller must hold the rtnl semaphore or the * dev_base_lock to be sure it remains unique. */ -static int dev_new_index(void) +static int dev_new_index(struct net *net) { static int ifindex; for (;;) { if (++ifindex <= 0) ifindex = 1; - if (!__dev_get_by_index(ifindex)) + if (!__dev_get_by_index(net, ifindex)) return ifindex; } } -static int dev_boot_phase = 1; - /* Delayed registration/unregisteration */ static DEFINE_SPINLOCK(net_todo_list_lock); static struct list_head net_todo_list = LIST_HEAD_INIT(net_todo_list); @@ -3386,6 +3432,7 @@ int register_netdevice(struct net_device *dev) struct hlist_head *head; struct hlist_node *p; int ret; + struct net *net; BUG_ON(dev_boot_phase); ASSERT_RTNL(); @@ -3394,6 +3441,8 @@ int register_netdevice(struct net_device *dev) /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); + BUG_ON(!dev->nd_net); + net = dev->nd_net; spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->_xmit_lock); @@ -3418,12 +3467,12 @@ int register_netdevice(struct net_device *dev) goto err_uninit; } - dev->ifindex = dev_new_index(); + dev->ifindex = dev_new_index(net); if (dev->iflink == -1) dev->iflink = dev->ifindex; /* Check for existence of name */ - head = dev_name_hash(dev->name); + head = dev_name_hash(net, dev->name); hlist_for_each(p, head) { struct net_device *d = hlist_entry(p, struct net_device, name_hlist); @@ -3501,9 +3550,9 @@ int register_netdevice(struct net_device *dev) dev_init_scheduler(dev); write_lock_bh(&dev_base_lock); - list_add_tail(&dev->dev_list, &dev_base_head); + list_add_tail(&dev->dev_list, &net->dev_base_head); hlist_add_head(&dev->name_hlist, head); - hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex)); + hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); dev_hold(dev); write_unlock_bh(&dev_base_lock); @@ -4067,6 +4116,45 @@ int netdev_compute_features(unsigned long all, unsigned long one) } EXPORT_SYMBOL(netdev_compute_features); +/* Initialize per network namespace state */ +static int netdev_init(struct net *net) +{ + int i; + INIT_LIST_HEAD(&net->dev_base_head); + rwlock_init(&dev_base_lock); + + net->dev_name_head = kmalloc( + sizeof(*net->dev_name_head)*NETDEV_HASHENTRIES, GFP_KERNEL); + if (!net->dev_name_head) + return -ENOMEM; + + net->dev_index_head = kmalloc( + sizeof(*net->dev_index_head)*NETDEV_HASHENTRIES, GFP_KERNEL); + if (!net->dev_index_head) { + kfree(net->dev_name_head); + return -ENOMEM; + } + + for (i = 0; i < NETDEV_HASHENTRIES; i++) + INIT_HLIST_HEAD(&net->dev_name_head[i]); + + for (i = 0; i < NETDEV_HASHENTRIES; i++) + INIT_HLIST_HEAD(&net->dev_index_head[i]); + + return 0; +} + +static void netdev_exit(struct net *net) +{ + kfree(net->dev_name_head); + kfree(net->dev_index_head); +} + +static struct pernet_operations netdev_net_ops = { + .init = netdev_init, + .exit = netdev_exit, +}; + /* * Initialize the DEV module. At boot time this walks the device list and * unhooks any devices that fail to initialise (normally hardware not @@ -4094,11 +4182,8 @@ static int __init net_dev_init(void) for (i = 0; i < 16; i++) INIT_LIST_HEAD(&ptype_base[i]); - for (i = 0; i < ARRAY_SIZE(dev_name_head); i++) - INIT_HLIST_HEAD(&dev_name_head[i]); - - for (i = 0; i < ARRAY_SIZE(dev_index_head); i++) - INIT_HLIST_HEAD(&dev_index_head[i]); + if (register_pernet_subsys(&netdev_net_ops)) + goto out; /* * Initialise the packet receive queues. diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 8e069fc207cb..1c4f6198459b 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -187,11 +187,12 @@ EXPORT_SYMBOL(dev_mc_unsync); #ifdef CONFIG_PROC_FS static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos) { + struct net *net = seq->private; struct net_device *dev; loff_t off = 0; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(net, dev) { if (off++ == *pos) return dev; } @@ -240,7 +241,22 @@ static const struct seq_operations dev_mc_seq_ops = { static int dev_mc_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &dev_mc_seq_ops); + struct seq_file *seq; + int res; + res = seq_open(file, &dev_mc_seq_ops); + if (!res) { + seq = file->private_data; + seq->private = get_net(PROC_NET(inode)); + } + return res; +} + +static int dev_mc_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = seq->private; + put_net(net); + return seq_release(inode, file); } static const struct file_operations dev_mc_seq_fops = { @@ -248,14 +264,31 @@ static const struct file_operations dev_mc_seq_fops = { .open = dev_mc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = dev_mc_seq_release, }; #endif +static int dev_mc_net_init(struct net *net) +{ + if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops)) + return -ENOMEM; + return 0; +} + +static void dev_mc_net_exit(struct net *net) +{ + proc_net_remove(net, "dev_mcast"); +} + +static struct pernet_operations dev_mc_net_ops = { + .init = dev_mc_net_init, + .exit = dev_mc_net_exit, +}; + void __init dev_mcast_init(void) { - proc_net_fops_create(&init_net, "dev_mcast", 0, &dev_mc_seq_fops); + register_pernet_subsys(&dev_mc_net_ops); } EXPORT_SYMBOL(dev_mc_add); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 7c43f032a7f9..0d0b13cc1dd3 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -779,9 +779,9 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr, /* The main entry point in this file. Called from net/core/dev.c */ -int dev_ethtool(struct ifreq *ifr) +int dev_ethtool(struct net *net, struct ifreq *ifr) { - struct net_device *dev = __dev_get_by_name(ifr->ifr_name); + struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); void __user *useraddr = ifr->ifr_data; u32 ethcmd; int rc; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 9eabe1ae01dc..1ba71baf87ef 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -12,6 +12,7 @@ #include #include #include +#include #include static LIST_HEAD(rules_ops); @@ -198,6 +199,7 @@ errout: static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct fib_rule_hdr *frh = nlmsg_data(nlh); struct fib_rules_ops *ops = NULL; struct fib_rule *rule, *r, *last = NULL; @@ -235,7 +237,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) rule->ifindex = -1; nla_strlcpy(rule->ifname, tb[FRA_IFNAME], IFNAMSIZ); - dev = __dev_get_by_name(rule->ifname); + dev = __dev_get_by_name(net, rule->ifname); if (dev) rule->ifindex = dev->ifindex; } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 5f25f4f79b8c..2c6577c1eedd 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1441,6 +1441,7 @@ int neigh_table_clear(struct neigh_table *tbl) static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct ndmsg *ndm; struct nlattr *dst_attr; struct neigh_table *tbl; @@ -1456,7 +1457,7 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ndm = nlmsg_data(nlh); if (ndm->ndm_ifindex) { - dev = dev_get_by_index(ndm->ndm_ifindex); + dev = dev_get_by_index(net, ndm->ndm_ifindex); if (dev == NULL) { err = -ENODEV; goto out; @@ -1506,6 +1507,7 @@ out: static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct ndmsg *ndm; struct nlattr *tb[NDA_MAX+1]; struct neigh_table *tbl; @@ -1522,7 +1524,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ndm = nlmsg_data(nlh); if (ndm->ndm_ifindex) { - dev = dev_get_by_index(ndm->ndm_ifindex); + dev = dev_get_by_index(net, ndm->ndm_ifindex); if (dev == NULL) { err = -ENODEV; goto out; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 0952f936b292..bb7523a5b408 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -653,7 +653,7 @@ int netpoll_setup(struct netpoll *np) int err; if (np->dev_name) - ndev = dev_get_by_name(np->dev_name); + ndev = dev_get_by_name(&init_net, np->dev_name); if (!ndev) { printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", np->name, np->dev_name); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index d7c30ce095a1..94e42be16daa 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2008,7 +2008,7 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) pkt_dev->odev = NULL; } - odev = dev_get_by_name(ifname); + odev = dev_get_by_name(&init_net, ifname); if (!odev) { printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname); return -ENODEV; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 416768d1e0cd..44f91bb1ae8d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -306,10 +306,13 @@ EXPORT_SYMBOL_GPL(rtnl_link_register); void __rtnl_link_unregister(struct rtnl_link_ops *ops) { struct net_device *dev, *n; + struct net *net; - for_each_netdev_safe(dev, n) { - if (dev->rtnl_link_ops == ops) - ops->dellink(dev); + for_each_net(net) { + for_each_netdev_safe(net, dev, n) { + if (dev->rtnl_link_ops == ops) + ops->dellink(dev); + } } list_del(&ops->list); } @@ -693,12 +696,13 @@ nla_put_failure: static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = skb->sk->sk_net; int idx; int s_idx = cb->args[0]; struct net_device *dev; idx = 0; - for_each_netdev(dev) { + for_each_netdev(net, dev) { if (idx < s_idx) goto cont; if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, @@ -858,6 +862,7 @@ errout: static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct ifinfomsg *ifm; struct net_device *dev; int err; @@ -876,9 +881,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) err = -EINVAL; ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) - dev = dev_get_by_index(ifm->ifi_index); + dev = dev_get_by_index(net, ifm->ifi_index); else if (tb[IFLA_IFNAME]) - dev = dev_get_by_name(ifname); + dev = dev_get_by_name(net, ifname); else goto errout; @@ -904,6 +909,7 @@ errout: static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; @@ -920,9 +926,9 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) - dev = __dev_get_by_index(ifm->ifi_index); + dev = __dev_get_by_index(net, ifm->ifi_index); else if (tb[IFLA_IFNAME]) - dev = __dev_get_by_name(ifname); + dev = __dev_get_by_name(net, ifname); else return -EINVAL; @@ -937,7 +943,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return 0; } -struct net_device *rtnl_create_link(char *ifname, +struct net_device *rtnl_create_link(struct net *net, char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) { int err; @@ -954,6 +960,7 @@ struct net_device *rtnl_create_link(char *ifname, goto err_free; } + dev->nd_net = net; dev->rtnl_link_ops = ops; if (tb[IFLA_MTU]) @@ -981,6 +988,7 @@ err: static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; @@ -1004,9 +1012,9 @@ replay: ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) - dev = __dev_get_by_index(ifm->ifi_index); + dev = __dev_get_by_index(net, ifm->ifi_index); else if (ifname[0]) - dev = __dev_get_by_name(ifname); + dev = __dev_get_by_name(net, ifname); else dev = NULL; @@ -1092,7 +1100,7 @@ replay: if (!ifname[0]) snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); - dev = rtnl_create_link(ifname, ops, tb); + dev = rtnl_create_link(net, ifname, ops, tb); if (IS_ERR(dev)) err = PTR_ERR(dev); @@ -1109,6 +1117,7 @@ replay: static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct ifinfomsg *ifm; struct nlattr *tb[IFLA_MAX+1]; struct net_device *dev = NULL; @@ -1121,7 +1130,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) { - dev = dev_get_by_index(ifm->ifi_index); + dev = dev_get_by_index(net, ifm->ifi_index); if (dev == NULL) return -ENODEV; } else diff --git a/net/core/sock.c b/net/core/sock.c index a31455dc7024..4ed9b507c1e7 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -367,6 +367,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) { int ret = -ENOPROTOOPT; #ifdef CONFIG_NETDEVICES + struct net *net = sk->sk_net; char devname[IFNAMSIZ]; int index; @@ -395,7 +396,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) if (devname[0] == '\0') { index = 0; } else { - struct net_device *dev = dev_get_by_name(devname); + struct net_device *dev = dev_get_by_name(net, devname); ret = -ENODEV; if (!dev) diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 83398da5d763..aabe98d9402f 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -751,7 +751,7 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (dn_ntohs(saddr->sdn_nodeaddrl)) { read_lock(&dev_base_lock); ldev = NULL; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (!dev->dn_ptr) continue; if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) { diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 83cb0761336a..ddfd2aff44d8 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -513,7 +513,7 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) ifr->ifr_name[IFNAMSIZ-1] = 0; #ifdef CONFIG_KMOD - dev_load(ifr->ifr_name); + dev_load(&init_net, ifr->ifr_name); #endif switch(cmd) { @@ -531,7 +531,7 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) rtnl_lock(); - if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) { + if ((dev = __dev_get_by_name(&init_net, ifr->ifr_name)) == NULL) { ret = -ENODEV; goto done; } @@ -629,7 +629,7 @@ static struct dn_dev *dn_dev_by_index(int ifindex) { struct net_device *dev; struct dn_dev *dn_dev = NULL; - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev) { dn_dev = dev->dn_ptr; dev_put(dev); @@ -694,7 +694,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return -EINVAL; ifm = nlmsg_data(nlh); - if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) + if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL) return -ENODEV; if ((dn_db = dev->dn_ptr) == NULL) { @@ -800,7 +800,7 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) skip_naddr = cb->args[1]; idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < skip_ndevs) goto cont; else if (idx > skip_ndevs) { @@ -1297,7 +1297,7 @@ void dn_dev_devices_off(void) struct net_device *dev; rtnl_lock(); - for_each_netdev(dev) + for_each_netdev(&init_net, dev) dn_dev_down(dev); rtnl_unlock(); @@ -1308,7 +1308,7 @@ void dn_dev_devices_on(void) struct net_device *dev; rtnl_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev->flags & IFF_UP) dn_dev_up(dev); } @@ -1342,7 +1342,7 @@ static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) return SEQ_START_TOKEN; i = 1; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (!is_dn_dev(dev)) continue; @@ -1361,9 +1361,9 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) dev = (struct net_device *)v; if (v == SEQ_START_TOKEN) - dev = net_device_entry(&dev_base_head); + dev = net_device_entry(&init_net.dev_base_head); - for_each_netdev_continue(dev) { + for_each_netdev_continue(&init_net, dev) { if (!is_dn_dev(dev)) continue; diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index d2bc19d47950..3760a20d10d0 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -212,7 +212,7 @@ static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct return -EINVAL; if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST) return -EINVAL; - if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL) + if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) return -ENETDOWN; @@ -255,7 +255,7 @@ out: if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) return -EINVAL; - dev = __dev_get_by_index(nh->nh_oif); + dev = __dev_get_by_index(&init_net, nh->nh_oif); if (dev == NULL || dev->dn_ptr == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) @@ -355,7 +355,7 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta if (nhs != 1 || nh->nh_gw) goto err_inval; nh->nh_scope = RT_SCOPE_NOWHERE; - nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif); + nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif); err = -ENODEV; if (nh->nh_dev == NULL) goto failure; @@ -602,7 +602,7 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa) /* Scan device list */ read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { dn_db = dev->dn_ptr; if (dn_db == NULL) continue; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 580e786d0c38..70b1c3fa00f3 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -908,7 +908,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old /* If we have an output interface, verify its a DECnet device */ if (oldflp->oif) { - dev_out = dev_get_by_index(oldflp->oif); + dev_out = dev_get_by_index(&init_net, oldflp->oif); err = -ENODEV; if (dev_out && dev_out->dn_ptr == NULL) { dev_put(dev_out); @@ -929,7 +929,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old goto out; } read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (!dev->dn_ptr) continue; if (!dn_dev_islocal(dev, oldflp->fld_src)) @@ -1556,7 +1556,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void if (fl.iif) { struct net_device *dev; - if ((dev = dev_get_by_index(fl.iif)) == NULL) { + if ((dev = dev_get_by_index(&init_net, fl.iif)) == NULL) { kfree_skb(skb); return -ENODEV; } diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 52e40d7eb22d..ae354a43fb97 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -259,7 +259,7 @@ static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen, devname[newlen] = 0; - dev = dev_get_by_name(devname); + dev = dev_get_by_name(&init_net, devname); if (dev == NULL) return -ENODEV; @@ -299,7 +299,7 @@ static int dn_def_dev_handler(ctl_table *table, int write, devname[*lenp] = 0; strip_it(devname); - dev = dev_get_by_name(devname); + dev = dev_get_by_name(&init_net, devname); if (dev == NULL) return -ENODEV; diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index f877f3b5c725..9938e76a8ff6 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -662,7 +662,7 @@ static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void __user *arg) if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; - if ((dev = dev_get_by_name(ifr.ifr_name)) == NULL) + if ((dev = dev_get_by_name(&init_net, ifr.ifr_name)) == NULL) return -ENODEV; sec = (struct sockaddr_ec *)&ifr.ifr_addr; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index a11e7a5c1da4..3a683006d761 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -981,7 +981,7 @@ static int arp_req_set(struct arpreq *r, struct net_device * dev) if (mask && mask != htonl(0xFFFFFFFF)) return -EINVAL; if (!dev && (r->arp_flags & ATF_COM)) { - dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data); + dev = dev_getbyhwaddr(&init_net, r->arp_ha.sa_family, r->arp_ha.sa_data); if (!dev) return -ENODEV; } @@ -1169,7 +1169,7 @@ int arp_ioctl(unsigned int cmd, void __user *arg) rtnl_lock(); if (r.arp_dev[0]) { err = -ENODEV; - if ((dev = __dev_get_by_name(r.arp_dev)) == NULL) + if ((dev = __dev_get_by_name(&init_net, r.arp_dev)) == NULL) goto out; /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c5eb1a29a5cf..721b89b60963 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -420,7 +420,7 @@ struct in_device *inetdev_by_index(int ifindex) struct net_device *dev; struct in_device *in_dev = NULL; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifindex); + dev = __dev_get_by_index(&init_net, ifindex); if (dev) in_dev = in_dev_get(dev); read_unlock(&dev_base_lock); @@ -506,7 +506,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh) goto errout; } - dev = __dev_get_by_index(ifm->ifa_index); + dev = __dev_get_by_index(&init_net, ifm->ifa_index); if (dev == NULL) { err = -ENODEV; goto errout; @@ -628,7 +628,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) *colon = 0; #ifdef CONFIG_KMOD - dev_load(ifr.ifr_name); + dev_load(&init_net, ifr.ifr_name); #endif switch (cmd) { @@ -669,7 +669,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) rtnl_lock(); ret = -ENODEV; - if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL) goto done; if (colon) @@ -909,7 +909,7 @@ no_in_dev: */ read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((in_dev = __in_dev_get_rcu(dev)) == NULL) continue; @@ -988,7 +988,7 @@ __be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((in_dev = __in_dev_get_rcu(dev))) { addr = confirm_addr_indev(in_dev, dst, local, scope); if (addr) @@ -1185,7 +1185,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) s_ip_idx = ip_idx = cb->args[1]; idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < s_idx) goto cont; if (idx > s_idx) @@ -1244,7 +1244,7 @@ static void devinet_copy_dflt_conf(int i) struct net_device *dev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct in_device *in_dev; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); @@ -1333,7 +1333,7 @@ void inet_forward_change(void) IPV4_DEVCONF_DFLT(FORWARDING) = on; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct in_device *in_dev; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 140bf7a8d877..df17aab193b4 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -334,7 +334,7 @@ static int rtentry_to_fib_config(int cmd, struct rtentry *rt, colon = strchr(devname, ':'); if (colon) *colon = 0; - dev = __dev_get_by_name(devname); + dev = __dev_get_by_name(&init_net, devname); if (!dev) return -ENODEV; cfg->fc_oif = dev->ifindex; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index c434119deb52..d30fb68d5f4e 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -533,7 +533,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, return -EINVAL; if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) return -EINVAL; - if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL) + if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) return -ENETDOWN; @@ -799,7 +799,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) if (nhs != 1 || nh->nh_gw) goto err_inval; nh->nh_scope = RT_SCOPE_NOWHERE; - nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif); + nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif); err = -ENODEV; if (nh->nh_dev == NULL) goto failure; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 02a899bec196..68a22670f597 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -517,7 +517,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct net_device *dev = NULL; if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr) - dev = dev_get_by_index(rt->fl.iif); + dev = dev_get_by_index(&init_net, rt->fl.iif); if (dev) { saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d78599a9dbd5..ad500a43b359 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2292,7 +2292,7 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); state->in_dev = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct in_device *in_dev; in_dev = in_dev_get(state->dev); if (!in_dev) @@ -2454,7 +2454,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) state->idev = NULL; state->im = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct in_device *idev; idev = in_dev_get(state->dev); if (unlikely(idev == NULL)) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 0231bdcb2ab7..fabb86db763b 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -292,7 +292,7 @@ static void ip_expire(unsigned long arg) if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) { struct sk_buff *head = qp->fragments; /* Send an ICMP "Fragment Reassembly Timeout" message. */ - if ((head->dev = dev_get_by_index(qp->iif)) != NULL) { + if ((head->dev = dev_get_by_index(&init_net, qp->iif)) != NULL) { icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); dev_put(head->dev); } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 5c14ed63e56c..3106225c5e50 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -262,7 +262,7 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int int i; for (i=1; i<100; i++) { sprintf(name, "gre%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(&init_net, name) == NULL) break; } if (i==100) @@ -1196,7 +1196,7 @@ static int ipgre_tunnel_init(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(&init_net, tunnel->parms.link); if (tdev) { hlen = tdev->hard_header_len; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 6b420aedcdcf..b2b3053dfef7 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -602,7 +602,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, dev_put(dev); } } else - dev = __dev_get_by_index(mreq.imr_ifindex); + dev = __dev_get_by_index(&init_net, mreq.imr_ifindex); err = -EADDRNOTAVAIL; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 08ff623371f0..4303851749f6 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -193,7 +193,7 @@ static int __init ic_open_devs(void) if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0) printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev.name); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev == &loopback_dev) continue; if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 396437242a1b..652bd86e33a3 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -225,7 +225,7 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c int i; for (i=1; i<100; i++) { sprintf(name, "tunl%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(&init_net, name) == NULL) break; } if (i==100) @@ -822,7 +822,7 @@ static int ipip_tunnel_init(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(&init_net, tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 036598835c63..b8b4b497fb57 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -125,7 +125,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) { struct net_device *dev; - dev = __dev_get_by_name("tunl0"); + dev = __dev_get_by_name(&init_net, "tunl0"); if (dev) { int err; @@ -149,7 +149,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) dev = NULL; - if (err == 0 && (dev = __dev_get_by_name(p.name)) != NULL) { + if (err == 0 && (dev = __dev_get_by_name(&init_net, p.name)) != NULL) { dev->flags |= IFF_MULTICAST; in_dev = __in_dev_get_rtnl(dev); diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c index 356f067484e3..1960747f354c 100644 --- a/net/ipv4/ipvs/ip_vs_sync.c +++ b/net/ipv4/ipvs/ip_vs_sync.c @@ -387,7 +387,7 @@ static int set_mcast_if(struct sock *sk, char *ifname) struct net_device *dev; struct inet_sock *inet = inet_sk(sk); - if ((dev = __dev_get_by_name(ifname)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) return -ENODEV; if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) @@ -412,7 +412,7 @@ static int set_sync_mesg_maxlen(int sync_state) int num; if (sync_state == IP_VS_STATE_MASTER) { - if ((dev = __dev_get_by_name(ip_vs_master_mcast_ifn)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ip_vs_master_mcast_ifn)) == NULL) return -ENODEV; num = (dev->mtu - sizeof(struct iphdr) - @@ -423,7 +423,7 @@ static int set_sync_mesg_maxlen(int sync_state) IP_VS_DBG(7, "setting the maximum length of sync sending " "message %d.\n", sync_send_mesg_maxlen); } else if (sync_state == IP_VS_STATE_BACKUP) { - if ((dev = __dev_get_by_name(ip_vs_backup_mcast_ifn)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ip_vs_backup_mcast_ifn)) == NULL) return -ENODEV; sync_recv_mesg_maxlen = dev->mtu - @@ -451,7 +451,7 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname) memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr)); - if ((dev = __dev_get_by_name(ifname)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) return -ENODEV; if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) return -EINVAL; @@ -472,7 +472,7 @@ static int bind_mcastif_addr(struct socket *sock, char *ifname) __be32 addr; struct sockaddr_in sin; - if ((dev = __dev_get_by_name(ifname)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) return -ENODEV; addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 50fc9e009fe4..27f14e1ebd8b 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -401,7 +401,7 @@ checkentry(const char *tablename, return false; } - dev = dev_get_by_name(e->ip.iniface); + dev = dev_get_by_name(&init_net, e->ip.iniface); if (!dev) { printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface); return false; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index efd2a9202d68..396c631166a4 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2213,7 +2213,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) if (oldflp->oif) { - dev_out = dev_get_by_index(oldflp->oif); + dev_out = dev_get_by_index(&init_net, oldflp->oif); err = -ENODEV; if (dev_out == NULL) goto out; @@ -2592,7 +2592,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (iif) { struct net_device *dev; - dev = __dev_get_by_index(iif); + dev = __dev_get_by_index(&init_net, iif); if (dev == NULL) { err = -ENODEV; goto errout_free; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1a6783646520..ee55be975407 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -450,7 +450,7 @@ static void addrconf_forward_change(void) struct inet6_dev *idev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { rcu_read_lock(); idev = __in6_dev_get(dev); if (idev) { @@ -912,7 +912,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; @@ -1858,7 +1858,7 @@ int addrconf_set_dstaddr(void __user *arg) if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) goto err_exit; - dev = __dev_get_by_index(ireq.ifr6_ifindex); + dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex); err = -ENODEV; if (dev == NULL) @@ -1889,7 +1889,7 @@ int addrconf_set_dstaddr(void __user *arg) if (err == 0) { err = -ENOBUFS; - if ((dev = __dev_get_by_name(p.name)) == NULL) + if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL) goto err_exit; err = dev_open(dev); } @@ -1919,7 +1919,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, if (!valid_lft || prefered_lft > valid_lft) return -EINVAL; - if ((dev = __dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) return -ENODEV; if ((idev = addrconf_add_dev(dev)) == NULL) @@ -1970,7 +1970,7 @@ static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen) struct inet6_dev *idev; struct net_device *dev; - if ((dev = __dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) return -ENODEV; if ((idev = __in6_dev_get(dev)) == NULL) @@ -2065,7 +2065,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) return; } - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct in_device * in_dev = __in_dev_get_rtnl(dev); if (in_dev && (dev->flags & IFF_UP)) { struct in_ifaddr * ifa; @@ -2221,12 +2221,12 @@ static void ip6_tnl_add_linklocal(struct inet6_dev *idev) /* first try to inherit the link-local address from the link device */ if (idev->dev->iflink && - (link_dev = __dev_get_by_index(idev->dev->iflink))) { + (link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) { if (!ipv6_inherit_linklocal(idev, link_dev)) return; } /* then try to inherit it from any device */ - for_each_netdev(link_dev) { + for_each_netdev(&init_net, link_dev) { if (!ipv6_inherit_linklocal(idev, link_dev)) return; } @@ -3084,7 +3084,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) valid_lft = INFINITY_LIFE_TIME; } - dev = __dev_get_by_index(ifm->ifa_index); + dev = __dev_get_by_index(&init_net, ifm->ifa_index); if (dev == NULL) return -ENODEV; @@ -3268,7 +3268,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, s_ip_idx = ip_idx = cb->args[1]; idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < s_idx) goto cont; if (idx > s_idx) @@ -3377,7 +3377,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, ifm = nlmsg_data(nlh); if (ifm->ifa_index) - dev = __dev_get_by_index(ifm->ifa_index); + dev = __dev_get_by_index(&init_net, ifm->ifa_index); if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) { err = -EADDRNOTAVAIL; @@ -3589,7 +3589,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) read_lock(&dev_base_lock); idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < s_idx) goto cont; if ((idev = in6_dev_get(dev)) == NULL) @@ -4266,7 +4266,7 @@ void __exit addrconf_cleanup(void) * clean dev list. */ - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (__in6_dev_get(dev) == NULL) continue; addrconf_ifdown(dev, 1); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 21931c86e95b..e5c5aad44bb1 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -302,7 +302,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) err = -EINVAL; goto out; } - dev = dev_get_by_index(sk->sk_bound_dev_if); + dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 0bd665498d06..d407992c1481 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -112,10 +112,10 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) } else { /* router, no matching interface: just pick one */ - dev = dev_get_by_flags(IFF_UP, IFF_UP|IFF_LOOPBACK); + dev = dev_get_by_flags(&init_net, IFF_UP, IFF_UP|IFF_LOOPBACK); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev == NULL) { err = -ENODEV; @@ -196,7 +196,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) write_unlock_bh(&ipv6_sk_ac_lock); - dev = dev_get_by_index(pac->acl_ifindex); + dev = dev_get_by_index(&init_net, pac->acl_ifindex); if (dev) { ipv6_dev_ac_dec(dev, &pac->acl_addr); dev_put(dev); @@ -224,7 +224,7 @@ void ipv6_sock_ac_close(struct sock *sk) if (pac->acl_ifindex != prev_index) { if (dev) dev_put(dev); - dev = dev_get_by_index(pac->acl_ifindex); + dev = dev_get_by_index(&init_net, pac->acl_ifindex); prev_index = pac->acl_ifindex; } if (dev) @@ -429,7 +429,7 @@ int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr) if (dev) return ipv6_chk_acast_dev(dev, addr); read_lock(&dev_base_lock); - for_each_netdev(dev) + for_each_netdev(&init_net, dev) if (ipv6_chk_acast_dev(dev, addr)) { found = 1; break; @@ -453,7 +453,7 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) struct ac6_iter_state *state = ac6_seq_private(seq); state->idev = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (!idev) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index fe0f49024a0a..2ed689ac449e 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -544,7 +544,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, if (!src_info->ipi6_ifindex) return -EINVAL; else { - dev = dev_get_by_index(src_info->ipi6_ifindex); + dev = dev_get_by_index(&init_net, src_info->ipi6_ifindex); if (!dev) return -ENODEV; } diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index ca774d8e3be3..937625e577c1 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -235,7 +235,7 @@ static struct ip6_tnl *ip6_tnl_create(struct ip6_tnl_parm *p) int i; for (i = 1; i < IP6_TNL_MAX; i++) { sprintf(name, "ip6tnl%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(&init_net, name) == NULL) break; } if (i == IP6_TNL_MAX) @@ -650,7 +650,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) struct net_device *ldev = NULL; if (p->link) - ldev = dev_get_by_index(p->link); + ldev = dev_get_by_index(&init_net, p->link); if ((ipv6_addr_is_multicast(&p->laddr) || likely(ipv6_chk_addr(&p->laddr, ldev, 0))) && @@ -786,7 +786,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) struct net_device *ldev = NULL; if (p->link) - ldev = dev_get_by_index(p->link); + ldev = dev_get_by_index(&init_net, p->link); if (unlikely(!ipv6_chk_addr(&p->laddr, ldev, 0))) printk(KERN_WARNING diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 74254fccbcc8..eb330a44bacd 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -542,7 +542,7 @@ done: if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) goto e_inval; - if (__dev_get_by_index(val) == NULL) { + if (__dev_get_by_index(&init_net, val) == NULL) { retv = -ENODEV; break; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index a41d5a0b50cc..e2ab43c989d4 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -215,7 +215,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) dst_release(&rt->u.dst); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev == NULL) { sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); @@ -266,7 +266,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) *lnk = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) { + if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) { struct inet6_dev *idev = in6_dev_get(dev); (void) ip6_mc_leave_src(sk, mc_lst, idev); @@ -301,7 +301,7 @@ static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) dst_release(&rt->u.dst); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (!dev) return NULL; @@ -332,7 +332,7 @@ void ipv6_sock_mc_close(struct sock *sk) np->ipv6_mc_list = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - dev = dev_get_by_index(mc_lst->ifindex); + dev = dev_get_by_index(&init_net, mc_lst->ifindex); if (dev) { struct inet6_dev *idev = in6_dev_get(dev); @@ -2333,7 +2333,7 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); state->idev = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (!idev) @@ -2477,7 +2477,7 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) state->idev = NULL; state->im = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (unlikely(idev == NULL)) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 38a3d21c2585..bdd0974e6775 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -283,7 +283,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (!sk->sk_bound_dev_if) goto out; - dev = dev_get_by_index(sk->sk_bound_dev_if); + dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index de795c04e34c..31601c993541 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -301,7 +301,7 @@ static void ip6_frag_expire(unsigned long data) fq_kill(fq); - dev = dev_get_by_index(fq->iif); + dev = dev_get_by_index(&init_net, fq->iif); if (!dev) goto out; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f4f0c341e5c8..5bdd9d4010fe 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1130,7 +1130,7 @@ int ip6_route_add(struct fib6_config *cfg) #endif if (cfg->fc_ifindex) { err = -ENODEV; - dev = dev_get_by_index(cfg->fc_ifindex); + dev = dev_get_by_index(&init_net, cfg->fc_ifindex); if (!dev) goto out; idev = in6_dev_get(dev); @@ -2265,7 +2265,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (iif) { struct net_device *dev; - dev = __dev_get_by_index(iif); + dev = __dev_get_by_index(&init_net, iif); if (!dev) { err = -ENODEV; goto errout; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index eb20bb690abd..e79f419b1731 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -167,7 +167,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int int i; for (i=1; i<100; i++) { sprintf(name, "sit%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(&init_net, name) == NULL) break; } if (i==100) @@ -761,7 +761,7 @@ static int ipip6_tunnel_init(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(&init_net, tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 24921f12e9af..29b063d43120 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -989,7 +989,7 @@ static int ipxitf_create(struct ipx_interface_definition *idef) if (intrfc) ipxitf_put(intrfc); - dev = dev_get_by_name(idef->ipx_device); + dev = dev_get_by_name(&init_net, idef->ipx_device); rc = -ENODEV; if (!dev) goto out; @@ -1097,7 +1097,7 @@ static int ipxitf_delete(struct ipx_interface_definition *idef) if (!dlink_type) goto out; - dev = __dev_get_by_name(idef->ipx_device); + dev = __dev_get_by_name(&init_net, idef->ipx_device); rc = -ENODEV; if (!dev) goto out; @@ -1192,7 +1192,7 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg) if (copy_from_user(&ifr, arg, sizeof(ifr))) break; sipx = (struct sockaddr_ipx *)&ifr.ifr_addr; - dev = __dev_get_by_name(ifr.ifr_name); + dev = __dev_get_by_name(&init_net, ifr.ifr_name); rc = -ENODEV; if (!dev) break; diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index 1e429c929739..cd9ff176ecde 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -30,7 +31,7 @@ static struct genl_family irda_nl_family = { .maxattr = IRDA_NL_CMD_MAX, }; -static struct net_device * ifname_to_netdev(struct genl_info *info) +static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *info) { char * ifname; @@ -41,7 +42,7 @@ static struct net_device * ifname_to_netdev(struct genl_info *info) IRDA_DEBUG(5, "%s(): Looking for %s\n", __FUNCTION__, ifname); - return dev_get_by_name(ifname); + return dev_get_by_name(net, ifname); } static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info) @@ -57,7 +58,7 @@ static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info) IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __FUNCTION__, mode); - dev = ifname_to_netdev(info); + dev = ifname_to_netdev(&init_net, info); if (!dev) return -ENODEV; @@ -82,7 +83,7 @@ static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info) void *hdr; int ret = -ENOBUFS; - dev = ifname_to_netdev(info); + dev = ifname_to_netdev(&init_net, info); if (!dev) return -ENODEV; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index b48244156e75..49eacba824df 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -252,7 +252,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) if (!sock_flag(sk, SOCK_ZAPPED)) goto out; rc = -ENODEV; - llc->dev = dev_getfirstbyhwtype(addr->sllc_arphrd); + llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); if (!llc->dev) goto out; rc = -EUSERS; @@ -303,7 +303,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) goto out; rc = -ENODEV; rtnl_lock(); - llc->dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_mac); + llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, addr->sllc_mac); rtnl_unlock(); if (!llc->dev) goto out; diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index d4b13a031fd5..248b5903bb13 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include LIST_HEAD(llc_sap_list); @@ -162,7 +163,7 @@ static int __init llc_init(void) { struct net_device *dev; - dev = first_net_device(); + dev = first_net_device(&init_net); if (dev != NULL) dev = next_net_device(dev); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 73e314e33de2..506cfa06b184 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "ieee80211_common.h" diff --git a/net/mac80211/ieee80211_cfg.c b/net/mac80211/ieee80211_cfg.c index 509096edb324..b1c13bc9c3ca 100644 --- a/net/mac80211/ieee80211_cfg.c +++ b/net/mac80211/ieee80211_cfg.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "ieee80211_i.h" #include "ieee80211_cfg.h" @@ -50,7 +51,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) return -ENODEV; - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (!dev) return 0; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b65ff6536244..9e952e37b7df 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1018,7 +1019,7 @@ static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct net_device *dev; pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - dev = dev_get_by_index(pkt_data->ifindex); + dev = dev_get_by_index(&init_net, pkt_data->ifindex); if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { dev_put(dev); dev = NULL; @@ -1226,7 +1227,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, memset(&control, 0, sizeof(struct ieee80211_tx_control)); if (pkt_data->ifindex) - odev = dev_get_by_index(pkt_data->ifindex); + odev = dev_get_by_index(&init_net, pkt_data->ifindex); if (unlikely(odev && !is_ieee80211_device(odev, dev))) { dev_put(odev); odev = NULL; @@ -1722,7 +1723,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, u8 *b_head, *b_tail; int bh_len, bt_len; - bdev = dev_get_by_index(if_id); + bdev = dev_get_by_index(&init_net, if_id); if (bdev) { sdata = IEEE80211_DEV_TO_SUB_IF(bdev); ap = &sdata->u.ap; @@ -1836,7 +1837,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; - bdev = dev_get_by_index(if_id); + bdev = dev_get_by_index(&init_net, if_id); if (bdev) { sdata = IEEE80211_DEV_TO_SUB_IF(bdev); bss = &sdata->u.ap; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 07686bda26cd..c970996ba6f9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "ieee80211_i.h" @@ -318,7 +319,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, int rate) { struct ieee80211_local *local = hw_to_local(hw); - struct net_device *bdev = dev_get_by_index(if_id); + struct net_device *bdev = dev_get_by_index(&init_net, if_id); struct ieee80211_sub_if_data *sdata; u16 dur; int erp; @@ -342,7 +343,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - struct net_device *bdev = dev_get_by_index(if_id); + struct net_device *bdev = dev_get_by_index(&init_net, if_id); struct ieee80211_sub_if_data *sdata; int short_preamble; int erp; @@ -378,7 +379,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - struct net_device *bdev = dev_get_by_index(if_id); + struct net_device *bdev = dev_get_by_index(&init_net, if_id); struct ieee80211_sub_if_data *sdata; int short_preamble; int erp; diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index 24fe4a66d297..e943c16552a2 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -580,7 +580,7 @@ static struct net_device *nr_ax25_dev_get(char *devname) { struct net_device *dev; - if ((dev = dev_get_by_name(devname)) == NULL) + if ((dev = dev_get_by_name(&init_net, devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) @@ -598,7 +598,7 @@ struct net_device *nr_dev_first(void) struct net_device *dev, *first = NULL; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM) if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; @@ -618,7 +618,7 @@ struct net_device *nr_dev_get(ax25_address *addr) struct net_device *dev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) { dev_hold(dev); goto out; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ad0052524e88..745e2cb87c96 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -347,7 +347,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, */ saddr->spkt_device[13] = 0; - dev = dev_get_by_name(saddr->spkt_device); + dev = dev_get_by_name(&init_net, saddr->spkt_device); err = -ENODEV; if (dev == NULL) goto out_unlock; @@ -742,7 +742,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, } - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); err = -ENXIO; if (dev == NULL) goto out_unlock; @@ -937,7 +937,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add return -EINVAL; strlcpy(name,uaddr->sa_data,sizeof(name)); - dev = dev_get_by_name(name); + dev = dev_get_by_name(&init_net, name); if (dev) { err = packet_do_bind(sk, dev, pkt_sk(sk)->num); dev_put(dev); @@ -964,7 +964,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len if (sll->sll_ifindex) { err = -ENODEV; - dev = dev_get_by_index(sll->sll_ifindex); + dev = dev_get_by_index(&init_net, sll->sll_ifindex); if (dev == NULL) goto out; } @@ -1161,7 +1161,7 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr, return -EOPNOTSUPP; uaddr->sa_family = AF_PACKET; - dev = dev_get_by_index(pkt_sk(sk)->ifindex); + dev = dev_get_by_index(&init_net, pkt_sk(sk)->ifindex); if (dev) { strlcpy(uaddr->sa_data, dev->name, 15); dev_put(dev); @@ -1186,7 +1186,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, sll->sll_family = AF_PACKET; sll->sll_ifindex = po->ifindex; sll->sll_protocol = po->num; - dev = dev_get_by_index(po->ifindex); + dev = dev_get_by_index(&init_net, po->ifindex); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; @@ -1238,7 +1238,7 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) rtnl_lock(); err = -ENODEV; - dev = __dev_get_by_index(mreq->mr_ifindex); + dev = __dev_get_by_index(&init_net, mreq->mr_ifindex); if (!dev) goto done; @@ -1292,7 +1292,7 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) if (--ml->count == 0) { struct net_device *dev; *mlp = ml->next; - dev = dev_get_by_index(ml->ifindex); + dev = dev_get_by_index(&init_net, ml->ifindex); if (dev) { packet_dev_mc(dev, ml, -1); dev_put(dev); @@ -1320,7 +1320,7 @@ static void packet_flush_mclist(struct sock *sk) struct net_device *dev; po->mclist = ml->next; - if ((dev = dev_get_by_index(ml->ifindex)) != NULL) { + if ((dev = dev_get_by_index(&init_net, ml->ifindex)) != NULL) { packet_dev_mc(dev, ml, -1); dev_put(dev); } diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 96f61a71b252..540c0f26ffee 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -583,7 +583,7 @@ static struct net_device *rose_ax25_dev_get(char *devname) { struct net_device *dev; - if ((dev = dev_get_by_name(devname)) == NULL) + if ((dev = dev_get_by_name(&init_net, devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) @@ -601,7 +601,7 @@ struct net_device *rose_dev_first(void) struct net_device *dev, *first = NULL; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE) if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; @@ -619,7 +619,7 @@ struct net_device *rose_dev_get(rose_address *addr) struct net_device *dev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) { dev_hold(dev); goto out; @@ -636,7 +636,7 @@ static int rose_dev_exists(rose_address *addr) struct net_device *dev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) goto out; } diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 579578944ae7..fd7bca4d5c20 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,7 @@ static int tcf_mirred_init(struct rtattr *rta, struct rtattr *est, parm = RTA_DATA(tb[TCA_MIRRED_PARMS-1]); if (parm->ifindex) { - dev = __dev_get_by_index(parm->ifindex); + dev = __dev_get_by_index(&init_net, parm->ifindex); if (dev == NULL) return -ENODEV; switch (dev->type) { diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 5f0fbca7393f..03657976fd50 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -154,7 +154,7 @@ replay: /* Find head of filter chain. */ /* Find link */ - if ((dev = __dev_get_by_index(t->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, t->tcm_ifindex)) == NULL) return -ENODEV; /* Find qdisc */ @@ -387,7 +387,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return skb->len; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return skb->len; if (!tcm->tcm_parent) diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 650f09c8bd6a..e9989610712c 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -291,7 +291,7 @@ META_COLLECTOR(var_sk_bound_if) } else { struct net_device *dev; - dev = dev_get_by_index(skb->sk->sk_bound_dev_if); + dev = dev_get_by_index(&init_net, skb->sk->sk_bound_dev_if); *err = var_dev(dev, dst); if (dev) dev_put(dev); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index efc383c58f1e..39d32780c80b 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -607,7 +607,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) struct Qdisc *p = NULL; int err; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; if (clid) { @@ -674,7 +674,7 @@ replay: clid = tcm->tcm_parent; q = p = NULL; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; if (clid) { @@ -881,7 +881,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) s_q_idx = q_idx = cb->args[1]; read_lock(&dev_base_lock); idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < s_idx) goto cont; if (idx > s_idx) @@ -932,7 +932,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) u32 qid = TC_H_MAJ(clid); int err; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; /* @@ -1115,7 +1115,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return 0; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return 0; s_t = cb->args[0]; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index ddeb4882ec75..9de3ddaa2768 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -855,7 +855,7 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0; - dev = dev_get_by_index(addr->v6.sin6_scope_id); + dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); if (!dev) return 0; if (!ipv6_chk_addr(&addr->v6.sin6_addr, dev, 0)) { @@ -886,7 +886,7 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr) if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0; - dev = dev_get_by_index(addr->v6.sin6_scope_id); + dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); if (!dev) return 0; dev_put(dev); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index af67c839ef98..54edcd978f75 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -179,7 +179,7 @@ static void sctp_get_local_addr_list(void) struct sctp_af *af; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { __list_for_each(pos, &sctp_address_families) { af = list_entry(pos, struct sctp_af, list); af->copy_addrlist(&sctp_local_addr_list, dev); diff --git a/net/socket.c b/net/socket.c index a714c6d4e4a1..bc16eee4dc80 100644 --- a/net/socket.c +++ b/net/socket.c @@ -791,9 +791,9 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, */ static DEFINE_MUTEX(br_ioctl_mutex); -static int (*br_ioctl_hook) (unsigned int cmd, void __user *arg) = NULL; +static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg) = NULL; -void brioctl_set(int (*hook) (unsigned int, void __user *)) +void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) { mutex_lock(&br_ioctl_mutex); br_ioctl_hook = hook; @@ -803,9 +803,9 @@ void brioctl_set(int (*hook) (unsigned int, void __user *)) EXPORT_SYMBOL(brioctl_set); static DEFINE_MUTEX(vlan_ioctl_mutex); -static int (*vlan_ioctl_hook) (void __user *arg); +static int (*vlan_ioctl_hook) (struct net *, void __user *arg); -void vlan_ioctl_set(int (*hook) (void __user *)) +void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) { mutex_lock(&vlan_ioctl_mutex); vlan_ioctl_hook = hook; @@ -834,16 +834,20 @@ EXPORT_SYMBOL(dlci_ioctl_set); static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { struct socket *sock; + struct sock *sk; void __user *argp = (void __user *)arg; int pid, err; + struct net *net; sock = file->private_data; + sk = sock->sk; + net = sk->sk_net; if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { - err = dev_ioctl(cmd, argp); + err = dev_ioctl(net, cmd, argp); } else #ifdef CONFIG_WIRELESS_EXT if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { - err = dev_ioctl(cmd, argp); + err = dev_ioctl(net, cmd, argp); } else #endif /* CONFIG_WIRELESS_EXT */ switch (cmd) { @@ -869,7 +873,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_lock(&br_ioctl_mutex); if (br_ioctl_hook) - err = br_ioctl_hook(cmd, argp); + err = br_ioctl_hook(net, cmd, argp); mutex_unlock(&br_ioctl_mutex); break; case SIOCGIFVLAN: @@ -880,7 +884,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_lock(&vlan_ioctl_mutex); if (vlan_ioctl_hook) - err = vlan_ioctl_hook(argp); + err = vlan_ioctl_hook(net, argp); mutex_unlock(&vlan_ioctl_mutex); break; case SIOCADDDLCI: @@ -903,7 +907,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) * to the NIC driver. */ if (err == -ENOIOCTLCMD) - err = dev_ioctl(cmd, argp); + err = dev_ioctl(net, cmd, argp); break; } return err; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 406f0d26fa81..d6fc0575816b 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -135,7 +135,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) /* Find device with specified name */ - for_each_netdev(pdev){ + for_each_netdev(&init_net, pdev){ if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) { dev = pdev; break; diff --git a/net/wireless/wext.c b/net/wireless/wext.c index b8069afe0410..e8b3409d6c8b 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -673,7 +673,22 @@ static const struct seq_operations wireless_seq_ops = { static int wireless_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &wireless_seq_ops); + struct seq_file *seq; + int res; + res = seq_open(file, &wireless_seq_ops); + if (!res) { + seq = file->private_data; + seq->private = get_net(PROC_NET(inode)); + } + return res; +} + +static int wireless_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = seq->private; + put_net(net); + return seq_release(inode, file); } static const struct file_operations wireless_seq_fops = { @@ -681,17 +696,22 @@ static const struct file_operations wireless_seq_fops = { .open = wireless_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = wireless_seq_release, }; -int __init wext_proc_init(void) +int wext_proc_init(struct net *net) { /* Create /proc/net/wireless entry */ - if (!proc_net_fops_create(&init_net, "wireless", S_IRUGO, &wireless_seq_fops)) + if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) return -ENOMEM; return 0; } + +void wext_proc_exit(struct net *net) +{ + proc_net_remove(net, "wireless"); +} #endif /* CONFIG_PROC_FS */ /************************** IOCTL SUPPORT **************************/ @@ -1011,7 +1031,7 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, * Main IOCTl dispatcher. * Check the type of IOCTL and call the appropriate wrapper... */ -static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) +static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd) { struct net_device *dev; iw_handler handler; @@ -1020,7 +1040,7 @@ static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) * The copy_to/from_user() of ifr is also dealt with in there */ /* Make sure the device exist */ - if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) + if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) return -ENODEV; /* A bunch of special cases, then the generic case... @@ -1054,7 +1074,7 @@ static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) } /* entry point from dev ioctl */ -int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd, +int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg) { int ret; @@ -1066,9 +1086,9 @@ int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd, && !capable(CAP_NET_ADMIN)) return -EPERM; - dev_load(ifr->ifr_name); + dev_load(net, ifr->ifr_name); rtnl_lock(); - ret = wireless_process_ioctl(ifr, cmd); + ret = wireless_process_ioctl(net, ifr, cmd); rtnl_unlock(); if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct ifreq))) return -EFAULT; diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c index 060fcfaa2f47..86b5b4da097c 100644 --- a/net/x25/x25_route.c +++ b/net/x25/x25_route.c @@ -129,7 +129,7 @@ void x25_route_device_down(struct net_device *dev) */ struct net_device *x25_dev_get(char *devname) { - struct net_device *dev = dev_get_by_name(devname); + struct net_device *dev = dev_get_by_name(&init_net, devname); if (dev && (!(dev->flags & IFF_UP) || (dev->type != ARPHRD_X25 From b267b179648e46ea8e2a44f7314a23eb6aee1d6c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:48:45 +0200 Subject: [PATCH 1181/2804] [NET]: Factor out __dev_alloc_name from dev_alloc_name When forcibly changing the network namespace of a device I need something that can generate a name for the device in the new namespace without overwriting the old name. __dev_alloc_name provides me that functionality. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 3a3d5ee73909..520ef7b20862 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -739,9 +739,10 @@ int dev_valid_name(const char *name) } /** - * dev_alloc_name - allocate a name for a device - * @dev: device + * __dev_alloc_name - allocate a name for a device + * @net: network namespace to allocate the device name in * @name: name format string + * @buf: scratch buffer and result name string * * Passed a format string - eg "lt%d" it will try and find a suitable * id. It scans list of devices to build up a free map, then chooses @@ -752,18 +753,13 @@ int dev_valid_name(const char *name) * Returns the number of the unit assigned or a negative errno code. */ -int dev_alloc_name(struct net_device *dev, const char *name) +static int __dev_alloc_name(struct net *net, const char *name, char *buf) { int i = 0; - char buf[IFNAMSIZ]; const char *p; const int max_netdevices = 8*PAGE_SIZE; long *inuse; struct net_device *d; - struct net *net; - - BUG_ON(!dev->nd_net); - net = dev->nd_net; p = strnchr(name, IFNAMSIZ-1, '%'); if (p) { @@ -787,7 +783,7 @@ int dev_alloc_name(struct net_device *dev, const char *name) continue; /* avoid cases where sscanf is not exact inverse of printf */ - snprintf(buf, sizeof(buf), name, i); + snprintf(buf, IFNAMSIZ, name, i); if (!strncmp(buf, d->name, IFNAMSIZ)) set_bit(i, inuse); } @@ -796,11 +792,9 @@ int dev_alloc_name(struct net_device *dev, const char *name) free_page((unsigned long) inuse); } - snprintf(buf, sizeof(buf), name, i); - if (!__dev_get_by_name(net, buf)) { - strlcpy(dev->name, buf, IFNAMSIZ); + snprintf(buf, IFNAMSIZ, name, i); + if (!__dev_get_by_name(net, buf)) return i; - } /* It is possible to run out of possible slots * when the name is long and there isn't enough space left @@ -809,6 +803,34 @@ int dev_alloc_name(struct net_device *dev, const char *name) return -ENFILE; } +/** + * dev_alloc_name - allocate a name for a device + * @dev: device + * @name: name format string + * + * Passed a format string - eg "lt%d" it will try and find a suitable + * id. It scans list of devices to build up a free map, then chooses + * the first empty slot. The caller must hold the dev_base or rtnl lock + * while allocating the name and adding the device in order to avoid + * duplicates. + * Limited to bits_per_byte * page size devices (ie 32K on most platforms). + * Returns the number of the unit assigned or a negative errno code. + */ + +int dev_alloc_name(struct net_device *dev, const char *name) +{ + char buf[IFNAMSIZ]; + struct net *net; + int ret; + + BUG_ON(!dev->nd_net); + net = dev->nd_net; + ret = __dev_alloc_name(net, name, buf); + if (ret >= 0) + strlcpy(dev->name, buf, IFNAMSIZ); + return ret; +} + /** * dev_change_name - change name of a device From ce286d327341295f58d89864d746a524287cfdf9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:53:49 +0200 Subject: [PATCH 1182/2804] [NET]: Implement network device movement between namespaces This patch introduces NETIF_F_NETNS_LOCAL a flag to indicate a network device is local to a single network namespace and should never be moved. Useful for pseudo devices that we need an instance in each network namespace (like the loopback device) and for any device we find that cannot handle multiple network namespaces so we may trap them in the initial network namespace. This patch introduces the function dev_change_net_namespace a function used to move a network device from one network namespace to another. To the network device nothing special appears to happen, to the components of the network stack it appears as if the network device was unregistered in the network namespace it is in, and a new device was registered in the network namespace the device was moved to. This patch sets up a namespace device destructor that upon the exit of a network namespace moves all of the movable network devices to the initial network namespace so they are not lost. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/loopback.c | 3 +- include/linux/netdevice.h | 3 + net/core/dev.c | 189 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 184 insertions(+), 11 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 5106c2328d12..e399f7b201e3 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -222,7 +222,8 @@ struct net_device loopback_dev = { | NETIF_F_TSO #endif | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA - | NETIF_F_LLTX, + | NETIF_F_LLTX + | NETIF_F_NETNS_LOCAL, .ethtool_ops = &loopback_ethtool_ops, }; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7353b3e1f4fc..407658c64fb6 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -449,6 +449,7 @@ struct net_device #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ #define NETIF_F_GSO 2048 /* Enable software GSO. */ #define NETIF_F_LLTX 4096 /* LockLess TX */ +#define NETIF_F_NETNS_LOCAL 8192 /* Does not change network namespaces */ #define NETIF_F_MULTI_QUEUE 16384 /* Has multiple TX/RX queues */ #define NETIF_F_LRO 32768 /* large receive offload */ @@ -1016,6 +1017,8 @@ extern int dev_ethtool(struct net *net, struct ifreq *); extern unsigned dev_get_flags(const struct net_device *); extern int dev_change_flags(struct net_device *, unsigned); extern int dev_change_name(struct net_device *, char *); +extern int dev_change_net_namespace(struct net_device *, + struct net *, const char *); extern int dev_set_mtu(struct net_device *, int); extern int dev_set_mac_address(struct net_device *, struct sockaddr *); diff --git a/net/core/dev.c b/net/core/dev.c index 520ef7b20862..215b8e97690a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -208,6 +208,34 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; } +/* Device list insertion */ +static int list_netdevice(struct net_device *dev) +{ + struct net *net = dev->nd_net; + + ASSERT_RTNL(); + + write_lock_bh(&dev_base_lock); + list_add_tail(&dev->dev_list, &net->dev_base_head); + hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); + hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); + write_unlock_bh(&dev_base_lock); + return 0; +} + +/* Device list removal */ +static void unlist_netdevice(struct net_device *dev) +{ + ASSERT_RTNL(); + + /* Unlink dev from the device chain */ + write_lock_bh(&dev_base_lock); + list_del(&dev->dev_list); + hlist_del(&dev->name_hlist); + hlist_del(&dev->index_hlist); + write_unlock_bh(&dev_base_lock); +} + /* * Our notifier list */ @@ -3571,12 +3599,8 @@ int register_netdevice(struct net_device *dev) set_bit(__LINK_STATE_PRESENT, &dev->state); dev_init_scheduler(dev); - write_lock_bh(&dev_base_lock); - list_add_tail(&dev->dev_list, &net->dev_base_head); - hlist_add_head(&dev->name_hlist, head); - hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); dev_hold(dev); - write_unlock_bh(&dev_base_lock); + list_netdevice(dev); /* Notify protocols, that a new device appeared. */ ret = raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); @@ -3883,11 +3907,7 @@ void unregister_netdevice(struct net_device *dev) dev_close(dev); /* And unlink it from device chain. */ - write_lock_bh(&dev_base_lock); - list_del(&dev->dev_list); - hlist_del(&dev->name_hlist); - hlist_del(&dev->index_hlist); - write_unlock_bh(&dev_base_lock); + unlist_netdevice(dev); dev->reg_state = NETREG_UNREGISTERING; @@ -3945,6 +3965,122 @@ void unregister_netdev(struct net_device *dev) EXPORT_SYMBOL(unregister_netdev); +/** + * dev_change_net_namespace - move device to different nethost namespace + * @dev: device + * @net: network namespace + * @pat: If not NULL name pattern to try if the current device name + * is already taken in the destination network namespace. + * + * This function shuts down a device interface and moves it + * to a new network namespace. On success 0 is returned, on + * a failure a netagive errno code is returned. + * + * Callers must hold the rtnl semaphore. + */ + +int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) +{ + char buf[IFNAMSIZ]; + const char *destname; + int err; + + ASSERT_RTNL(); + + /* Don't allow namespace local devices to be moved. */ + err = -EINVAL; + if (dev->features & NETIF_F_NETNS_LOCAL) + goto out; + + /* Ensure the device has been registrered */ + err = -EINVAL; + if (dev->reg_state != NETREG_REGISTERED) + goto out; + + /* Get out if there is nothing todo */ + err = 0; + if (dev->nd_net == net) + goto out; + + /* Pick the destination device name, and ensure + * we can use it in the destination network namespace. + */ + err = -EEXIST; + destname = dev->name; + if (__dev_get_by_name(net, destname)) { + /* We get here if we can't use the current device name */ + if (!pat) + goto out; + if (!dev_valid_name(pat)) + goto out; + if (strchr(pat, '%')) { + if (__dev_alloc_name(net, pat, buf) < 0) + goto out; + destname = buf; + } else + destname = pat; + if (__dev_get_by_name(net, destname)) + goto out; + } + + /* + * And now a mini version of register_netdevice unregister_netdevice. + */ + + /* If device is running close it first. */ + if (dev->flags & IFF_UP) + dev_close(dev); + + /* And unlink it from device chain */ + err = -ENODEV; + unlist_netdevice(dev); + + synchronize_net(); + + /* Shutdown queueing discipline. */ + dev_shutdown(dev); + + /* Notify protocols, that we are about to destroy + this device. They should clean all the things. + */ + call_netdevice_notifiers(NETDEV_UNREGISTER, dev); + + /* + * Flush the unicast and multicast chains + */ + dev_addr_discard(dev); + + /* Actually switch the network namespace */ + dev->nd_net = net; + + /* Assign the new device name */ + if (destname != dev->name) + strcpy(dev->name, destname); + + /* If there is an ifindex conflict assign a new one */ + if (__dev_get_by_index(net, dev->ifindex)) { + int iflink = (dev->iflink == dev->ifindex); + dev->ifindex = dev_new_index(net); + if (iflink) + dev->iflink = dev->ifindex; + } + + /* Fixup sysfs */ + err = device_rename(&dev->dev, dev->name); + BUG_ON(err); + + /* Add the device back in the hashes */ + list_netdevice(dev); + + /* Notify protocols, that a new device appeared. */ + call_netdevice_notifiers(NETDEV_REGISTER, dev); + + synchronize_net(); + err = 0; +out: + return err; +} + static int dev_cpu_callback(struct notifier_block *nfb, unsigned long action, void *ocpu) @@ -4177,6 +4313,36 @@ static struct pernet_operations netdev_net_ops = { .exit = netdev_exit, }; +static void default_device_exit(struct net *net) +{ + struct net_device *dev, *next; + /* + * Push all migratable of the network devices back to the + * initial network namespace + */ + rtnl_lock(); + for_each_netdev_safe(net, dev, next) { + int err; + + /* Ignore unmoveable devices (i.e. loopback) */ + if (dev->features & NETIF_F_NETNS_LOCAL) + continue; + + /* Push remaing network devices to init_net */ + err = dev_change_net_namespace(dev, &init_net, "dev%d"); + if (err) { + printk(KERN_WARNING "%s: failed to move %s to init_net: %d\n", + __func__, dev->name, err); + unregister_netdevice(dev); + } + } + rtnl_unlock(); +} + +static struct pernet_operations default_device_ops = { + .exit = default_device_exit, +}; + /* * Initialize the DEV module. At boot time this walks the device list and * unhooks any devices that fail to initialise (normally hardware not @@ -4207,6 +4373,9 @@ static int __init net_dev_init(void) if (register_pernet_subsys(&netdev_net_ops)) goto out; + if (register_pernet_device(&default_device_ops)) + goto out; + /* * Initialise the packet receive queues. */ From d8a5ec672768c3cf4d51d7a63fc071520afa1617 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:57:04 +0200 Subject: [PATCH 1183/2804] [NET]: netlink support for moving devices between network namespaces. The simplest thing to implement is moving network devices between namespaces. However with the same attribute IFLA_NET_NS_PID we can easily implement creating devices in the destination network namespace as well. However that is a little bit trickier so this patch sticks to what is simple and easy. A pid is used to identify a process that happens to be a member of the network namespace we want to move the network device to. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/linux/if_link.h | 1 + net/core/rtnetlink.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 422084d18ce1..84c3492ae5cb 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -78,6 +78,7 @@ enum IFLA_LINKMODE, IFLA_LINKINFO, #define IFLA_LINKINFO IFLA_LINKINFO + IFLA_NET_NS_PID, __IFLA_MAX }; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 44f91bb1ae8d..1b9c32d79917 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -727,6 +728,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_WEIGHT] = { .type = NLA_U32 }, [IFLA_OPERSTATE] = { .type = NLA_U8 }, [IFLA_LINKMODE] = { .type = NLA_U8 }, + [IFLA_NET_NS_PID] = { .type = NLA_U32 }, }; static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { @@ -734,12 +736,45 @@ 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_pid(pid); + if (tsk) { + task_lock(tsk); + if (tsk->nsproxy) + net = get_net(tsk->nsproxy->net_ns); + task_unlock(tsk); + } + rcu_read_unlock(); + return net; +} + static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, struct nlattr **tb, char *ifname, int modified) { int send_addr_notify = 0; int err; + if (tb[IFLA_NET_NS_PID]) { + struct net *net; + net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); + if (IS_ERR(net)) { + err = PTR_ERR(net); + goto errout; + } + err = dev_change_net_namespace(dev, net, ifname); + put_net(net); + if (err) + goto errout; + modified = 1; + } + if (tb[IFLA_MAP]) { struct rtnl_link_ifmap *u_map; struct ifmap k_map; From c48dad7ecd84eac92afbe02bd69fca9983a65a56 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:58:02 +0200 Subject: [PATCH 1184/2804] [NET]: Disable netfilter sockopts when not in the initial network namespace Until we support multiple network namespaces with netfilter only allow netfilter configuration in the initial network namespace. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/netfilter/nf_sockopt.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index e32761ce260c..aa2831587b82 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c @@ -69,6 +69,9 @@ static int nf_sockopt(struct sock *sk, int pf, int val, struct nf_sockopt_ops *ops; int ret; + if (sk->sk_net != &init_net) + return -ENOPROTOOPT; + if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) return -EINTR; @@ -125,6 +128,10 @@ static int compat_nf_sockopt(struct sock *sk, int pf, int val, struct nf_sockopt_ops *ops; int ret; + if (sk->sk_net != &init_net) + return -ENOPROTOOPT; + + if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) return -EINTR; From 678aa8e4eb1e5d78dfdb70934932c9c90e315f62 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 12 Sep 2007 14:01:08 +0200 Subject: [PATCH 1185/2804] [NET]: #if 0 out net_alloc() for now. We will undo this once it is actually used. Signed-off-by: David S. Miller --- net/core/net_namespace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index f259a9b6fdc1..1fc513c4c79e 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -32,10 +32,12 @@ void net_unlock(void) mutex_unlock(&net_list_mutex); } +#if 0 static struct net *net_alloc(void) { return kmem_cache_alloc(net_cachep, GFP_KERNEL); } +#endif static void net_free(struct net *net) { From 3c12afe75f61d9402797d63941367962ca36fcc9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 12 Sep 2007 14:18:18 +0200 Subject: [PATCH 1186/2804] [NET]: Fix missed addition of fs/proc/proc_net.c My bad. Signed-off-by: David S. Miller --- fs/proc/proc_net.c | 192 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 fs/proc/proc_net.c diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c new file mode 100644 index 000000000000..45dde2f7034d --- /dev/null +++ b/fs/proc/proc_net.c @@ -0,0 +1,192 @@ +/* + * linux/fs/proc/net.c + * + * Copyright (C) 2007 + * + * Author: Eric Biederman + * + * proc net directory handling functions + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +struct proc_dir_entry *proc_net_create(struct net *net, + const char *name, mode_t mode, get_info_t *get_info) +{ + return create_proc_info_entry(name,mode, net->proc_net, get_info); +} + +struct proc_dir_entry *proc_net_fops_create(struct net *net, + const char *name, mode_t mode, const struct file_operations *fops) +{ + struct proc_dir_entry *res; + + res = create_proc_entry(name, mode, net->proc_net); + if (res) + res->proc_fops = fops; + return res; +} + +void proc_net_remove(struct net *net, const char *name) +{ + remove_proc_entry(name, net->proc_net); +} + + +static struct proc_dir_entry *proc_net_shadow; + +static struct dentry *proc_net_shadow_dentry(struct dentry *parent, + struct proc_dir_entry *de) +{ + struct dentry *shadow = NULL; + struct inode *inode; + if (!de) + goto out; + de_get(de); + inode = proc_get_inode(parent->d_inode->i_sb, de->low_ino, de); + if (!inode) + goto out_de_put; + shadow = d_alloc_name(parent, de->name); + if (!shadow) + goto out_iput; + shadow->d_op = parent->d_op; /* proc_dentry_operations */ + d_instantiate(shadow, inode); +out: + return shadow; +out_iput: + iput(inode); +out_de_put: + de_put(de); + goto out; +} + +static void *proc_net_follow_link(struct dentry *parent, struct nameidata *nd) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + shadow = proc_net_shadow_dentry(parent, net->proc_net); + if (!shadow) + return ERR_PTR(-ENOENT); + + dput(nd->dentry); + /* My dentry count is 1 and that should be enough as the + * shadow dentry is thrown away immediately. + */ + nd->dentry = shadow; + return NULL; +} + +static struct dentry *proc_net_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + + shadow = proc_net_shadow_dentry(nd->dentry, net->proc_net); + if (!shadow) + return ERR_PTR(-ENOENT); + + dput(nd->dentry); + nd->dentry = shadow; + + return shadow->d_inode->i_op->lookup(shadow->d_inode, dentry, nd); +} + +static int proc_net_setattr(struct dentry *dentry, struct iattr *iattr) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + int ret; + + shadow = proc_net_shadow_dentry(dentry->d_parent, net->proc_net); + if (!shadow) + return -ENOENT; + ret = shadow->d_inode->i_op->setattr(shadow, iattr); + dput(shadow); + return ret; +} + +static const struct file_operations proc_net_dir_operations = { + .read = generic_read_dir, +}; + +static struct inode_operations proc_net_dir_inode_operations = { + .follow_link = proc_net_follow_link, + .lookup = proc_net_lookup, + .setattr = proc_net_setattr, +}; + +static int proc_net_ns_init(struct net *net) +{ + struct proc_dir_entry *root, *netd, *net_statd; + int err; + + err = -ENOMEM; + root = kzalloc(sizeof(*root), GFP_KERNEL); + if (!root) + goto out; + + err = -EEXIST; + netd = proc_mkdir("net", root); + if (!netd) + goto free_root; + + err = -EEXIST; + net_statd = proc_mkdir("stat", netd); + if (!net_statd) + goto free_net; + + root->data = net; + netd->data = net; + net_statd->data = net; + + net->proc_net_root = root; + net->proc_net = netd; + net->proc_net_stat = net_statd; + err = 0; + +out: + return err; +free_net: + remove_proc_entry("net", root); +free_root: + kfree(root); + goto out; +} + +static void proc_net_ns_exit(struct net *net) +{ + remove_proc_entry("stat", net->proc_net); + remove_proc_entry("net", net->proc_net_root); + kfree(net->proc_net_root); +} + +struct pernet_operations proc_net_ns_ops = { + .init = proc_net_ns_init, + .exit = proc_net_ns_exit, +}; + +int proc_net_init(void) +{ + proc_net_shadow = proc_mkdir("net", NULL); + proc_net_shadow->proc_iops = &proc_net_dir_inode_operations; + proc_net_shadow->proc_fops = &proc_net_dir_operations; + + return register_pernet_subsys(&proc_net_ns_ops); +} From 86bba269d08f0c545ae76c90b56727f65d62d57f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 12 Sep 2007 14:29:01 +0200 Subject: [PATCH 1187/2804] [PATCH] NET : convert IP route cache garbage collection from softirq processing to a workqueue When the periodic IP route cache flush is done (every 600 seconds on default configuration), some hosts suffer a lot and eventually trigger the "soft lockup" message. dst_run_gc() is doing a scan of a possibly huge list of dst_entries, eventually freeing some (less than 1%) of them, while holding the dst_lock spinlock for the whole scan. Then it rearms a timer to redo the full thing 1/10 s later... The slowdown can last one minute or so, depending on how active are the tcp sessions. This second version of the patch converts the processing from a softirq based one to a workqueue. Even if the list of entries in garbage_list is huge, host is still responsive to softirqs and can make progress. Instead of resetting gc timer to 0.1 second if one entry was freed in a gc run, we do this if more than 10% of entries were freed. Before patch : Aug 16 06:21:37 SRV1 kernel: BUG: soft lockup detected on CPU#0! Aug 16 06:21:37 SRV1 kernel: Aug 16 06:21:37 SRV1 kernel: Call Trace: Aug 16 06:21:37 SRV1 kernel: [] wake_up_process+0x10/0x20 Aug 16 06:21:37 SRV1 kernel: [] softlockup_tick+0xe9/0x110 Aug 16 06:21:37 SRV1 kernel: [] dst_run_gc+0x0/0x140 Aug 16 06:21:37 SRV1 kernel: [] run_local_timers+0x13/0x20 Aug 16 06:21:37 SRV1 kernel: [] update_process_times+0x57/0x90 Aug 16 06:21:37 SRV1 kernel: [] smp_local_timer_interrupt+0x34/0x60 Aug 16 06:21:37 SRV1 kernel: [] smp_apic_timer_interrupt+0x5c/0x80 Aug 16 06:21:37 SRV1 kernel: [] apic_timer_interrupt+0x66/0x70 Aug 16 06:21:37 SRV1 kernel: [] dst_run_gc+0x53/0x140 Aug 16 06:21:37 SRV1 kernel: [] dst_run_gc+0x46/0x140 Aug 16 06:21:37 SRV1 kernel: [] run_timer_softirq+0x148/0x1c0 Aug 16 06:21:37 SRV1 kernel: [] __do_softirq+0x6c/0xe0 Aug 16 06:21:37 SRV1 kernel: [] call_softirq+0x1c/0x30 Aug 16 06:21:37 SRV1 kernel: [] do_softirq+0x34/0x90 Aug 16 06:21:37 SRV1 kernel: [] local_bh_enable_ip+0x3f/0x60 Aug 16 06:21:37 SRV1 kernel: [] _spin_unlock_bh+0x13/0x20 Aug 16 06:21:37 SRV1 kernel: [] rt_garbage_collect+0x1d8/0x320 Aug 16 06:21:37 SRV1 kernel: [] dst_alloc+0x1d/0xa0 Aug 16 06:21:37 SRV1 kernel: [] __ip_route_output_key+0x573/0x800 Aug 16 06:21:37 SRV1 kernel: [] sock_common_recvmsg+0x32/0x50 Aug 16 06:21:37 SRV1 kernel: [] ip_route_output_flow+0x1c/0x60 Aug 16 06:21:37 SRV1 kernel: [] tcp_v4_connect+0x150/0x610 Aug 16 06:21:37 SRV1 kernel: [] inet_bind_bucket_create+0x17/0x60 Aug 16 06:21:37 SRV1 kernel: [] inet_stream_connect+0xa6/0x2c0 Aug 16 06:21:37 SRV1 kernel: [] _spin_lock_bh+0x11/0x30 Aug 16 06:21:37 SRV1 kernel: [] lock_sock_nested+0xcf/0xe0 Aug 16 06:21:37 SRV1 kernel: [] _spin_lock_bh+0x11/0x30 Aug 16 06:21:37 SRV1 kernel: [] sys_connect+0x71/0xa0 Aug 16 06:21:37 SRV1 kernel: [] tcp_setsockopt+0x1f/0x30 Aug 16 06:21:37 SRV1 kernel: [] sock_common_setsockopt+0xf/0x20 Aug 16 06:21:37 SRV1 kernel: [] sys_setsockopt+0x9d/0xc0 Aug 16 06:21:37 SRV1 kernel: [] sys_ioctl+0x5e/0x80 Aug 16 06:21:37 SRV1 kernel: [] system_call+0x7e/0x83 After patch : (RT_CACHE_DEBUG set to 2 to get following traces) dst_total: 75469 delayed: 74109 work_perf: 141 expires: 150 elapsed: 8092 us dst_total: 78725 delayed: 73366 work_perf: 743 expires: 400 elapsed: 8542 us dst_total: 86126 delayed: 71844 work_perf: 1522 expires: 775 elapsed: 8849 us dst_total: 100173 delayed: 68791 work_perf: 3053 expires: 1256 elapsed: 9748 us dst_total: 121798 delayed: 64711 work_perf: 4080 expires: 1997 elapsed: 10146 us dst_total: 154522 delayed: 58316 work_perf: 6395 expires: 25 elapsed: 11402 us dst_total: 154957 delayed: 58252 work_perf: 64 expires: 150 elapsed: 6148 us dst_total: 157377 delayed: 57843 work_perf: 409 expires: 400 elapsed: 6350 us dst_total: 163745 delayed: 56679 work_perf: 1164 expires: 775 elapsed: 7051 us dst_total: 176577 delayed: 53965 work_perf: 2714 expires: 1389 elapsed: 8120 us dst_total: 198993 delayed: 49627 work_perf: 4338 expires: 1997 elapsed: 8909 us dst_total: 226638 delayed: 46865 work_perf: 2762 expires: 2748 elapsed: 7351 us I successfully reduced the IP route cache of many hosts by a four factor thanks to this patch. Previously, I had to disable "ip route flush cache" to avoid crashes. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dst.c | 195 +++++++++++++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 70 deletions(-) diff --git a/net/core/dst.c b/net/core/dst.c index 32267a16e01e..38c741ac5d08 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -19,50 +20,72 @@ #include -/* Locking strategy: - * 1) Garbage collection state of dead destination cache - * entries is protected by dst_lock. - * 2) GC is run only from BH context, and is the only remover - * of entries. - * 3) Entries are added to the garbage list from both BH - * and non-BH context, so local BH disabling is needed. - * 4) All operations modify state, so a spinlock is used. +/* + * Theory of operations: + * 1) We use a list, protected by a spinlock, to add + * new entries from both BH and non-BH context. + * 2) In order to keep spinlock held for a small delay, + * we use a second list where are stored long lived + * entries, that are handled by the garbage collect thread + * fired by a workqueue. + * 3) This list is guarded by a mutex, + * so that the gc_task and dst_dev_event() can be synchronized. */ -static struct dst_entry *dst_garbage_list; #if RT_CACHE_DEBUG >= 2 static atomic_t dst_total = ATOMIC_INIT(0); #endif -static DEFINE_SPINLOCK(dst_lock); -static unsigned long dst_gc_timer_expires; -static unsigned long dst_gc_timer_inc = DST_GC_MAX; -static void dst_run_gc(unsigned long); +/* + * We want to keep lock & list close together + * to dirty as few cache lines as possible in __dst_free(). + * As this is not a very strong hint, we dont force an alignment on SMP. + */ +static struct { + spinlock_t lock; + struct dst_entry *list; + unsigned long timer_inc; + unsigned long timer_expires; +} dst_garbage = { + .lock = __SPIN_LOCK_UNLOCKED(dst_garbage.lock), + .timer_inc = DST_GC_MAX, +}; +static void dst_gc_task(struct work_struct *work); static void ___dst_free(struct dst_entry * dst); -static DEFINE_TIMER(dst_gc_timer, dst_run_gc, DST_GC_MIN, 0); +static DECLARE_DELAYED_WORK(dst_gc_work, dst_gc_task); -static void dst_run_gc(unsigned long dummy) +static DEFINE_MUTEX(dst_gc_mutex); +/* + * long lived entries are maintained in this list, guarded by dst_gc_mutex + */ +static struct dst_entry *dst_busy_list; + +static void dst_gc_task(struct work_struct *work) { int delayed = 0; - int work_performed; - struct dst_entry * dst, **dstp; + int work_performed = 0; + unsigned long expires = ~0L; + struct dst_entry *dst, *next, head; + struct dst_entry *last = &head; +#if RT_CACHE_DEBUG >= 2 + ktime_t time_start = ktime_get(); + struct timespec elapsed; +#endif - if (!spin_trylock(&dst_lock)) { - mod_timer(&dst_gc_timer, jiffies + HZ/10); - return; - } + mutex_lock(&dst_gc_mutex); + next = dst_busy_list; - del_timer(&dst_gc_timer); - dstp = &dst_garbage_list; - work_performed = 0; - while ((dst = *dstp) != NULL) { - if (atomic_read(&dst->__refcnt)) { - dstp = &dst->next; +loop: + while ((dst = next) != NULL) { + next = dst->next; + prefetch(&next->next); + if (likely(atomic_read(&dst->__refcnt))) { + last->next = dst; + last = dst; delayed++; continue; } - *dstp = dst->next; - work_performed = 1; + work_performed++; dst = dst_destroy(dst); if (dst) { @@ -78,38 +101,56 @@ static void dst_run_gc(unsigned long dummy) continue; ___dst_free(dst); - dst->next = *dstp; - *dstp = dst; - dstp = &dst->next; + dst->next = next; + next = dst; } } - if (!dst_garbage_list) { - dst_gc_timer_inc = DST_GC_MAX; - goto out; - } - if (!work_performed) { - if ((dst_gc_timer_expires += dst_gc_timer_inc) > DST_GC_MAX) - dst_gc_timer_expires = DST_GC_MAX; - dst_gc_timer_inc += DST_GC_INC; - } else { - dst_gc_timer_inc = DST_GC_INC; - dst_gc_timer_expires = DST_GC_MIN; - } -#if RT_CACHE_DEBUG >= 2 - printk("dst_total: %d/%d %ld\n", - atomic_read(&dst_total), delayed, dst_gc_timer_expires); -#endif - /* if the next desired timer is more than 4 seconds in the future - * then round the timer to whole seconds - */ - if (dst_gc_timer_expires > 4*HZ) - mod_timer(&dst_gc_timer, - round_jiffies(jiffies + dst_gc_timer_expires)); - else - mod_timer(&dst_gc_timer, jiffies + dst_gc_timer_expires); -out: - spin_unlock(&dst_lock); + spin_lock_bh(&dst_garbage.lock); + next = dst_garbage.list; + if (next) { + dst_garbage.list = NULL; + spin_unlock_bh(&dst_garbage.lock); + goto loop; + } + last->next = NULL; + dst_busy_list = head.next; + if (!dst_busy_list) + dst_garbage.timer_inc = DST_GC_MAX; + else { + /* + * if we freed less than 1/10 of delayed entries, + * we can sleep longer. + */ + if (work_performed <= delayed/10) { + dst_garbage.timer_expires += dst_garbage.timer_inc; + if (dst_garbage.timer_expires > DST_GC_MAX) + dst_garbage.timer_expires = DST_GC_MAX; + dst_garbage.timer_inc += DST_GC_INC; + } else { + dst_garbage.timer_inc = DST_GC_INC; + dst_garbage.timer_expires = DST_GC_MIN; + } + expires = dst_garbage.timer_expires; + /* + * if the next desired timer is more than 4 seconds in the future + * then round the timer to whole seconds + */ + if (expires > 4*HZ) + expires = round_jiffies_relative(expires); + schedule_delayed_work(&dst_gc_work, expires); + } + + spin_unlock_bh(&dst_garbage.lock); + mutex_unlock(&dst_gc_mutex); +#if RT_CACHE_DEBUG >= 2 + elapsed = ktime_to_timespec(ktime_sub(ktime_get(), time_start)); + printk(KERN_DEBUG "dst_total: %d delayed: %d work_perf: %d" + " expires: %lu elapsed: %lu us\n", + atomic_read(&dst_total), delayed, work_performed, + expires, + elapsed.tv_sec * USEC_PER_SEC + elapsed.tv_nsec / NSEC_PER_USEC); +#endif } static int dst_discard(struct sk_buff *skb) @@ -154,16 +195,16 @@ static void ___dst_free(struct dst_entry * dst) void __dst_free(struct dst_entry * dst) { - spin_lock_bh(&dst_lock); + spin_lock_bh(&dst_garbage.lock); ___dst_free(dst); - dst->next = dst_garbage_list; - dst_garbage_list = dst; - if (dst_gc_timer_inc > DST_GC_INC) { - dst_gc_timer_inc = DST_GC_INC; - dst_gc_timer_expires = DST_GC_MIN; - mod_timer(&dst_gc_timer, jiffies + dst_gc_timer_expires); + dst->next = dst_garbage.list; + dst_garbage.list = dst; + if (dst_garbage.timer_inc > DST_GC_INC) { + dst_garbage.timer_inc = DST_GC_INC; + dst_garbage.timer_expires = DST_GC_MIN; + schedule_delayed_work(&dst_gc_work, dst_garbage.timer_expires); } - spin_unlock_bh(&dst_lock); + spin_unlock_bh(&dst_garbage.lock); } struct dst_entry *dst_destroy(struct dst_entry * dst) @@ -251,7 +292,7 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev, static int dst_dev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; - struct dst_entry *dst; + struct dst_entry *dst, *last = NULL; if (dev->nd_net != &init_net) return NOTIFY_DONE; @@ -259,11 +300,25 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void switch (event) { case NETDEV_UNREGISTER: case NETDEV_DOWN: - spin_lock_bh(&dst_lock); - for (dst = dst_garbage_list; dst; dst = dst->next) { + mutex_lock(&dst_gc_mutex); + for (dst = dst_busy_list; dst; dst = dst->next) { + last = dst; dst_ifdown(dst, dev, event != NETDEV_DOWN); } - spin_unlock_bh(&dst_lock); + + spin_lock_bh(&dst_garbage.lock); + dst = dst_garbage.list; + dst_garbage.list = NULL; + spin_unlock_bh(&dst_garbage.lock); + + if (last) + last->next = dst; + else + dst_busy_list = dst; + for (; dst; dst = dst->next) { + dst_ifdown(dst, dev, event != NETDEV_DOWN); + } + mutex_unlock(&dst_gc_mutex); break; } return NOTIFY_DONE; From 9d5010db7ecfd6ec00119d3b185c4c0cd3265167 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 12 Sep 2007 14:33:25 +0200 Subject: [PATCH 1188/2804] [NET]: Add a might_sleep() to dev_close(). Requested by Johannes Berg. Signed-off-by: David S. Miller --- net/core/dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 215b8e97690a..d16dcab49c60 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1060,6 +1060,8 @@ int dev_open(struct net_device *dev) */ int dev_close(struct net_device *dev) { + might_sleep(); + if (!(dev->flags & IFF_UP)) return 0; From 8f4c1f9b049df3be11090f1c2c4738700302acae Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 12 Sep 2007 14:44:36 +0200 Subject: [PATCH 1189/2804] [NETLINK]: Introduce nested and byteorder flag to netlink attribute This change allows the generic attribute interface to be used within the netfilter subsystem where this flag was initially introduced. The byte-order flag is yet unused, it's intended use is to allow automatic byte order convertions for all atomic types. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/netlink.h | 14 ++++++++++++++ include/net/netlink.h | 9 +++++++++ net/ipv4/fib_frontend.c | 2 +- net/ipv4/fib_semantics.c | 2 +- net/ipv6/route.c | 2 +- net/netlabel/netlabel_cipso_v4.c | 14 +++++++------- net/netlink/attr.c | 10 +++++----- 7 files changed, 38 insertions(+), 15 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index d2843ae4a83a..e638256ce472 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -131,6 +131,20 @@ struct nlattr __u16 nla_type; }; +/* + * nla_type (16 bits) + * +---+---+-------------------------------+ + * | N | O | Attribute Type | + * +---+---+-------------------------------+ + * N := Carries nested attributes + * O := Payload stored in network byte order + * + * Note: The N and O flag are mutually exclusive. + */ +#define NLA_F_NESTED (1 << 15) +#define NLA_F_NET_BYTEORDER (1 << 14) +#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) + #define NLA_ALIGNTO 4 #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) diff --git a/include/net/netlink.h b/include/net/netlink.h index d7b824be5422..695e613a207b 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -666,6 +666,15 @@ static inline int nla_padlen(int payload) return nla_total_size(payload) - nla_attr_size(payload); } +/** + * nla_type - attribute type + * @nla: netlink attribute + */ +static inline int nla_type(const struct nlattr *nla) +{ + return nla->nla_type & NLA_TYPE_MASK; +} + /** * nla_data - head of payload * @nla: netlink attribute diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index df17aab193b4..f823ca34cb12 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -487,7 +487,7 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh, } nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) { - switch (attr->nla_type) { + switch (nla_type(attr)) { case RTA_DST: cfg->fc_dst = nla_get_be32(attr); break; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index d30fb68d5f4e..1351a2617dce 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -743,7 +743,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) int remaining; nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { - int type = nla->nla_type; + int type = nla_type(nla); if (type) { if (type > RTAX_MAX) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 5bdd9d4010fe..104070e92cea 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1279,7 +1279,7 @@ install_route: int remaining; nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { - int type = nla->nla_type; + int type = nla_type(nla); if (type) { if (type > RTAX_MAX) { diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index c060e3f991f1..ba0ca8d3f77d 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -130,7 +130,7 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, return -EINVAL; nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem) - if (nla->nla_type == NLBL_CIPSOV4_A_TAG) { + if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) { if (iter >= CIPSO_V4_TAG_MAXCNT) return -EINVAL; doi_def->tags[iter++] = nla_get_u8(nla); @@ -192,13 +192,13 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) nla_for_each_nested(nla_a, info->attrs[NLBL_CIPSOV4_A_MLSLVLLST], nla_a_rem) - if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) { + if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) { if (nla_validate_nested(nla_a, NLBL_CIPSOV4_A_MAX, netlbl_cipsov4_genl_policy) != 0) goto add_std_failure; nla_for_each_nested(nla_b, nla_a, nla_b_rem) - switch (nla_b->nla_type) { + switch (nla_type(nla_b)) { case NLBL_CIPSOV4_A_MLSLVLLOC: if (nla_get_u32(nla_b) > CIPSO_V4_MAX_LOC_LVLS) @@ -240,7 +240,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) nla_for_each_nested(nla_a, info->attrs[NLBL_CIPSOV4_A_MLSLVLLST], nla_a_rem) - if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) { + if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) { struct nlattr *lvl_loc; struct nlattr *lvl_rem; @@ -265,13 +265,13 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) nla_for_each_nested(nla_a, info->attrs[NLBL_CIPSOV4_A_MLSCATLST], nla_a_rem) - if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) { + if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) { if (nla_validate_nested(nla_a, NLBL_CIPSOV4_A_MAX, netlbl_cipsov4_genl_policy) != 0) goto add_std_failure; nla_for_each_nested(nla_b, nla_a, nla_b_rem) - switch (nla_b->nla_type) { + switch (nla_type(nla_b)) { case NLBL_CIPSOV4_A_MLSCATLOC: if (nla_get_u32(nla_b) > CIPSO_V4_MAX_LOC_CATS) @@ -315,7 +315,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) nla_for_each_nested(nla_a, info->attrs[NLBL_CIPSOV4_A_MLSCATLST], nla_a_rem) - if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) { + if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) { struct nlattr *cat_loc; struct nlattr *cat_rem; diff --git a/net/netlink/attr.c b/net/netlink/attr.c index e4d7bed99c2e..ec39d12c2423 100644 --- a/net/netlink/attr.c +++ b/net/netlink/attr.c @@ -27,12 +27,12 @@ static int validate_nla(struct nlattr *nla, int maxtype, const struct nla_policy *policy) { const struct nla_policy *pt; - int minlen = 0, attrlen = nla_len(nla); + int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); - if (nla->nla_type <= 0 || nla->nla_type > maxtype) + if (type <= 0 || type > maxtype) return 0; - pt = &policy[nla->nla_type]; + pt = &policy[type]; BUG_ON(pt->type > NLA_TYPE_MAX); @@ -149,7 +149,7 @@ int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); nla_for_each_attr(nla, head, len, rem) { - u16 type = nla->nla_type; + u16 type = nla_type(nla); if (type > 0 && type <= maxtype) { if (policy) { @@ -185,7 +185,7 @@ struct nlattr *nla_find(struct nlattr *head, int len, int attrtype) int rem; nla_for_each_attr(nla, head, len, rem) - if (nla->nla_type == attrtype) + if (nla_type(nla) == attrtype) return nla; return NULL; From 36ac3135f5e824942fada4efa3204066b4b40ab1 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Sep 2007 14:51:47 +0200 Subject: [PATCH 1190/2804] [NETNS]: Fix export symbols. Add the appropriate EXPORT_SYMBOLS for proc_net_create, proc_net_fops_create and proc_net_remove to fix errors when compiling allmodconfig Signed-off-by: Mark Nelson Acked-by: Benjamin Thery Signed-off-by: David S. Miller --- fs/proc/proc_net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 45dde2f7034d..358930a3142a 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -31,6 +31,7 @@ struct proc_dir_entry *proc_net_create(struct net *net, { return create_proc_info_entry(name,mode, net->proc_net, get_info); } +EXPORT_SYMBOL_GPL(proc_net_create); struct proc_dir_entry *proc_net_fops_create(struct net *net, const char *name, mode_t mode, const struct file_operations *fops) @@ -42,12 +43,13 @@ struct proc_dir_entry *proc_net_fops_create(struct net *net, res->proc_fops = fops; return res; } +EXPORT_SYMBOL_GPL(proc_net_fops_create); void proc_net_remove(struct net *net, const char *name) { remove_proc_entry(name, net->proc_net); } - +EXPORT_SYMBOL_GPL(proc_net_remove); static struct proc_dir_entry *proc_net_shadow; From abf07acbb9f122218095d0d221e0f949160ccc37 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Sep 2007 14:54:14 +0200 Subject: [PATCH 1191/2804] [NETNS]: Fix loopback network namespace initialization. The core patchset of the network namespace sent by Eric Biederman does not do dynamic loopback creation. So there is no call to alloc_netdev_mq which fills the network namespace field of the netdevice. This patch assign the loopback to the init network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- drivers/net/loopback.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index e399f7b201e3..a328da72833c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -225,6 +225,7 @@ struct net_device loopback_dev = { | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL, .ethtool_ops = &loopback_ethtool_ops, + .nd_net = &init_net, }; /* Setup and register the loopback device. */ From a050c33f4a4d5babaf94a8ba6ae7a200135240b3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Sep 2007 14:57:09 +0200 Subject: [PATCH 1192/2804] [NETNS]: Fix bad macro definition. The macro definition is bad. When calling next_net_device with parameter name "dev", the resulting code is: struct net_device *dev = dev and that leads to an unexpected behavior. Especially when llc_core is compiled in, the kernel panics at boot time. The patchset change macro definition with static inline functions as they were defined before. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/linux/netdevice.h | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 407658c64fb6..625240ce27f1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -41,7 +41,8 @@ #include #include -struct net; +#include + struct vlan_group; struct ethtool_ops; struct netpoll_info; @@ -753,23 +754,21 @@ extern rwlock_t dev_base_lock; /* Device list lock */ list_for_each_entry_continue(d, &(net)->dev_base_head, dev_list) #define net_device_entry(lh) list_entry(lh, struct net_device, dev_list) -#define next_net_device(d) \ -({ \ - struct net_device *dev = d; \ - struct list_head *lh; \ - struct net *net; \ - \ - net = dev->nd_net; \ - lh = dev->dev_list.next; \ - lh == &net->dev_base_head ? NULL : net_device_entry(lh); \ -}) +static inline struct net_device *next_net_device(struct net_device *dev) +{ + struct list_head *lh; + struct net *net; -#define first_net_device(N) \ -({ \ - struct net *NET = (N); \ - list_empty(&NET->dev_base_head) ? NULL : \ - net_device_entry(NET->dev_base_head.next); \ -}) + net = dev->nd_net; + lh = dev->dev_list.next; + return lh == &net->dev_base_head ? NULL : net_device_entry(lh); +} + +static inline struct net_device *first_net_device(struct net *net) +{ + return list_empty(&net->dev_base_head) ? NULL : + net_device_entry(net->dev_base_head.next); +} extern int netdev_boot_setup_check(struct net_device *dev); extern unsigned long netdev_boot_base(const char *prefix, int unit); From 464771fe4743afd00ebff65aee0983fa1aa1da4f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 12 Sep 2007 15:14:45 +0200 Subject: [PATCH 1193/2804] [KERNEL]: Unexport raise_softirq_irqoff raise_softirq_irqoff no longer has any modular user. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- kernel/softirq.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index dbbdcd7f3c2e..bd89bc4eb0b9 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -330,8 +330,6 @@ inline fastcall void raise_softirq_irqoff(unsigned int nr) wakeup_softirqd(); } -EXPORT_SYMBOL(raise_softirq_irqoff); - void fastcall raise_softirq(unsigned int nr) { unsigned long flags; From 5c94bf86c865fb779f1743672b4d0f6cdd706728 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 12 Sep 2007 15:16:21 +0200 Subject: [PATCH 1194/2804] [SCTP]: Make sctp_addto_param() static. sctp_addto_param() can become static. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 1 - net/sctp/sm_make_chunk.c | 39 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index baff49dfcdbd..67c91d01b635 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -731,7 +731,6 @@ int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, struct iovec *data); void sctp_chunk_free(struct sctp_chunk *); void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); -void *sctp_addto_param(struct sctp_chunk *, int len, const void *data); struct sctp_chunk *sctp_chunkify(struct sk_buff *, const struct sctp_association *, struct sock *); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 23ae37ec8711..d84e575f7409 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -839,6 +839,26 @@ err_chunk: return retval; } +/* Append bytes to the end of a parameter. Will panic if chunk is not big + * enough. + */ +static void *sctp_addto_param(struct sctp_chunk *chunk, int len, + const void *data) +{ + void *target; + int chunklen = ntohs(chunk->chunk_hdr->length); + + target = skb_put(chunk->skb, len); + + memcpy(target, data, len); + + /* Adjust the chunk length field. */ + chunk->chunk_hdr->length = htons(chunklen + len); + chunk->chunk_end = skb_tail_pointer(chunk->skb); + + return target; +} + /* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */ struct sctp_chunk *sctp_make_abort_violation( const struct sctp_association *asoc, @@ -1146,25 +1166,6 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) return target; } -/* Append bytes to the end of a parameter. Will panic if chunk is not big - * enough. - */ -void *sctp_addto_param(struct sctp_chunk *chunk, int len, const void *data) -{ - void *target; - int chunklen = ntohs(chunk->chunk_hdr->length); - - target = skb_put(chunk->skb, len); - - memcpy(target, data, len); - - /* Adjust the chunk length field. */ - chunk->chunk_hdr->length = htons(chunklen + len); - chunk->chunk_end = skb_tail_pointer(chunk->skb); - - return target; -} - /* Append bytes from user space to the end of a chunk. Will panic if * chunk is not big enough. * Returns a kernel err value. From b6fa1a4d746488a7de95ec16afcaf3247fedb003 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 12 Sep 2007 15:18:00 +0200 Subject: [PATCH 1195/2804] [SCTP] net/sctp/socket.c: make 3 variables static This patch makes the following needlessly global variables static: - sctp_memory_pressure - sctp_memory_allocated - sctp_sockets_allocated Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- net/sctp/socket.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b9952425c79a..7738915011a0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -112,9 +112,9 @@ extern int sysctl_sctp_mem[3]; extern int sysctl_sctp_rmem[3]; extern int sysctl_sctp_wmem[3]; -int sctp_memory_pressure; -atomic_t sctp_memory_allocated; -atomic_t sctp_sockets_allocated; +static int sctp_memory_pressure; +static atomic_t sctp_memory_allocated; +static atomic_t sctp_sockets_allocated; static void sctp_enter_memory_pressure(void) { From e9bef55d3d062ee7a78fde2913ec87ca9305a1e0 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Wed, 12 Sep 2007 16:35:24 +0200 Subject: [PATCH 1196/2804] [NET_SCHED]: Cleanup L2T macros and handle oversized packets Change L2T (length to time) macros, in all rate based schedulers, to call a common function qdisc_l2t() that does the rate table lookup. This function handles if the packet size lookup is larger than the rate table, which often occurs with TSO enabled. Signed-off-by: Jesper Dangaard Brouer Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/sch_generic.h | 12 ++++++++++++ net/sched/act_police.c | 4 ++-- net/sched/sch_cbq.c | 2 +- net/sched/sch_htb.c | 6 ++---- net/sched/sch_tbf.c | 4 ++-- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 8a67f24cbe02..4ebd615bd013 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -302,4 +302,16 @@ drop: return NET_XMIT_DROP; } +/* Length to Time (L2T) lookup in a qdisc_rate_table, to determine how + long it will take to send a packet given its size. + */ +static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen) +{ + int slot = pktlen; + slot >>= rtab->rate.cell_log; + if (slot > 255) + return (rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF]); + return rtab->data[slot]; +} + #endif diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 17f6f27e28a2..a73e3e6d87ea 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -21,8 +21,8 @@ #include #include -#define L2T(p,L) ((p)->tcfp_R_tab->data[(L)>>(p)->tcfp_R_tab->rate.cell_log]) -#define L2T_P(p,L) ((p)->tcfp_P_tab->data[(L)>>(p)->tcfp_P_tab->rate.cell_log]) +#define L2T(p,L) qdisc_l2t((p)->tcfp_R_tab, L) +#define L2T_P(p,L) qdisc_l2t((p)->tcfp_P_tab, L) #define POL_TAB_MASK 15 static struct tcf_common *tcf_police_ht[POL_TAB_MASK + 1]; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index cbef3bbfc20f..4de3744e65c3 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -175,7 +175,7 @@ struct cbq_sched_data }; -#define L2T(cl,len) ((cl)->R_tab->data[(len)>>(cl)->R_tab->rate.cell_log]) +#define L2T(cl,len) qdisc_l2t((cl)->R_tab,len) static __inline__ unsigned cbq_hash(u32 h) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 246a2f9765f1..5e608a64935a 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -132,10 +132,8 @@ struct htb_class { static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate, int size) { - int slot = size >> rate->rate.cell_log; - if (slot > 255) - return (rate->data[255]*(slot >> 8) + rate->data[slot & 0xFF]); - return rate->data[slot]; + long result = qdisc_l2t(rate, size); + return result; } struct htb_sched { diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 8c2639af4c6a..b0d81098b0ee 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -115,8 +115,8 @@ struct tbf_sched_data struct qdisc_watchdog watchdog; /* Watchdog timer */ }; -#define L2T(q,L) ((q)->R_tab->data[(L)>>(q)->R_tab->rate.cell_log]) -#define L2T_P(q,L) ((q)->P_tab->data[(L)>>(q)->P_tab->rate.cell_log]) +#define L2T(q,L) qdisc_l2t((q)->R_tab,L) +#define L2T_P(q,L) qdisc_l2t((q)->P_tab,L) static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) { From e08b09983fe9cf379faf1aefdf9164268d4610e7 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Wed, 12 Sep 2007 16:36:28 +0200 Subject: [PATCH 1197/2804] [NET_SCHED]: Making rate table lookups more flexible. This is done in order to, add support to changing the rate table to use the upper-boundry L2T (length to time) value. Currently we use the lower-boundry, which result in under-estimating the actual bandwidth usage. Extend the tc_ratespec struct, with two parameters: 1) "cell_align" that allow adjusting the alignment of the rate table. 2) "overhead" that allow adding a packet overhead before the lookup. Signed-off-by: Jesper Dangaard Brouer Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/pkt_sched.h | 4 ++-- include/net/sch_generic.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 268c51599eb8..919af93b7059 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -77,8 +77,8 @@ struct tc_ratespec { unsigned char cell_log; unsigned char __reserved; - unsigned short feature; - short addend; + unsigned short overhead; + short cell_align; unsigned short mpu; __u32 rate; }; diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 4ebd615bd013..a02ec9e5fea5 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -307,7 +307,9 @@ drop: */ static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen) { - int slot = pktlen; + int slot = pktlen + rtab->rate.cell_align + rtab->rate.overhead; + if (slot < 0) + slot = 0; slot >>= rtab->rate.cell_log; if (slot > 255) return (rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF]); From 4fabcd7118162e36eea5c53e8895ecc13762bef3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 13 Sep 2007 09:16:29 +0200 Subject: [PATCH 1198/2804] [NETNS]: Fix allnoconfig compilation error. When CONFIG_NET=no, init_net is unresolved because net_namespace.c is not compiled and the include pull init_net definition. This problem was very similar with the ipc namespace where the kernel can be compiled with SYSV ipc out. This patch fix that defining a macro which simply remove init_net initialization from nsproxy namespace aggregator. Compiled and booted on qemu-i386 with CONFIG_NET=no and CONFIG_NET=yes. Signed-off-by: Daniel Lezcano Acked-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/linux/init_task.h | 2 +- include/net/net_namespace.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index e2c1ffcff62c..513bc3e489f0 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -79,7 +79,7 @@ extern struct nsproxy init_nsproxy; .nslock = __SPIN_LOCK_UNLOCKED(nsproxy.nslock), \ .uts_ns = &init_uts_ns, \ .mnt_ns = NULL, \ - .net_ns = &init_net, \ + INIT_NET_NS(net_ns) \ INIT_IPC_NS(ipc_ns) \ .user_ns = &init_user_ns, \ } diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index fac42db7f6d0..3081b6ed35fe 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -28,7 +28,14 @@ struct net { struct hlist_head *dev_index_head; }; +#ifdef CONFIG_NET +/* Init's network namespace */ extern struct net init_net; +#define INIT_NET_NS(net_ns) .net_ns = &init_net, +#else +#define INIT_NET_NS(net_ns) +#endif + extern struct list_head net_namespace_list; extern void __put_net(struct net *net); From 077130c0cf7d5ba1992f5b51b96136d7b1c8aad5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 13 Sep 2007 09:18:57 +0200 Subject: [PATCH 1199/2804] [NET]: Fix race when opening a proc file while a network namespace is exiting. The problem: proc_net files remember which network namespace the are against but do not remember hold a reference count (as that would pin the network namespace). So we currently have a small window where the reference count on a network namespace may be incremented when opening a /proc file when it has already gone to zero. To fix this introduce maybe_get_net and get_proc_net. maybe_get_net increments the network namespace reference count only if it is greater then zero, ensuring we don't increment a reference count after it has gone to zero. get_proc_net handles all of the magic to go from a proc inode to the network namespace instance and call maybe_get_net on it. PROC_NET the old accessor is removed so that we don't get confused and use the wrong helper function. Then I fix up the callers to use get_proc_net and handle the case case where get_proc_net returns NULL. In that case I return -ENXIO because effectively the network namespace has already gone away so the files we are trying to access don't exist anymore. Signed-off-by: Eric W. Biederman Acked-by: Paul E. McKenney Signed-off-by: David S. Miller --- fs/proc/proc_net.c | 6 ++++++ include/linux/proc_fs.h | 5 +---- include/net/net_namespace.h | 12 ++++++++++++ net/core/dev.c | 6 +++++- net/core/dev_mcast.c | 6 +++++- net/netlink/af_netlink.c | 6 +++++- net/wireless/wext.c | 6 +++++- 7 files changed, 39 insertions(+), 8 deletions(-) diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 358930a3142a..85cc8e8bb862 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -51,6 +51,12 @@ void proc_net_remove(struct net *net, const char *name) } EXPORT_SYMBOL_GPL(proc_net_remove); +struct net *get_proc_net(const struct inode *inode) +{ + return maybe_get_net(PDE_NET(PDE(inode))); +} +EXPORT_SYMBOL_GPL(get_proc_net); + static struct proc_dir_entry *proc_net_shadow; static struct dentry *proc_net_shadow_dentry(struct dentry *parent, diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 59646705f151..20741f668f7b 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -270,10 +270,7 @@ static inline struct net *PDE_NET(struct proc_dir_entry *pde) return pde->parent->data; } -static inline struct net *PROC_NET(const struct inode *inode) -{ - return PDE_NET(PDE(inode)); -} +struct net *get_proc_net(const struct inode *inode); struct proc_maps_private { struct pid *pid; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3081b6ed35fe..ac8f8304094e 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -46,6 +46,18 @@ static inline struct net *get_net(struct net *net) return net; } +static inline struct net *maybe_get_net(struct net *net) +{ + /* Used when we know struct net exists but we + * aren't guaranteed a previous reference count + * exists. If the reference count is zero this + * function fails and returns NULL. + */ + if (!atomic_inc_not_zero(&net->count)) + net = NULL; + return net; +} + static inline void put_net(struct net *net) { if (atomic_dec_and_test(&net->count)) diff --git a/net/core/dev.c b/net/core/dev.c index d16dcab49c60..666c112efb55 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2464,7 +2464,11 @@ static int dev_seq_open(struct inode *inode, struct file *file) res = seq_open(file, &dev_seq_ops); if (!res) { seq = file->private_data; - seq->private = get_net(PROC_NET(inode)); + seq->private = get_proc_net(inode); + if (!seq->private) { + seq_release(inode, file); + res = -ENXIO; + } } return res; } diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 1c4f6198459b..896b0ca5aed7 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -246,7 +246,11 @@ static int dev_mc_seq_open(struct inode *inode, struct file *file) res = seq_open(file, &dev_mc_seq_ops); if (!res) { seq = file->private_data; - seq->private = get_net(PROC_NET(inode)); + seq->private = get_proc_net(inode); + if (!seq->private) { + seq_release(inode, file); + res = -ENXIO; + } } return res; } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3029f865cd61..dc9f8c2ab1d5 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1859,7 +1859,11 @@ static int netlink_seq_open(struct inode *inode, struct file *file) seq = file->private_data; seq->private = iter; - iter->net = get_net(PROC_NET(inode)); + iter->net = get_proc_net(inode); + if (!iter->net) { + seq_release_private(inode, file); + return -ENXIO; + } return 0; } diff --git a/net/wireless/wext.c b/net/wireless/wext.c index e8b3409d6c8b..85e5f9dd0d8e 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -678,7 +678,11 @@ static int wireless_seq_open(struct inode *inode, struct file *file) res = seq_open(file, &wireless_seq_ops); if (!res) { seq = file->private_data; - seq->private = get_net(PROC_NET(inode)); + seq->private = get_proc_net(inode); + if (!seq->private) { + seq_release(inode, file); + res = -ENXIO; + } } return res; } From 234a0ca6f1d67ba4c3c3fc8378bbd98d722468e1 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 13 Sep 2007 09:20:42 +0200 Subject: [PATCH 1200/2804] [RFKILL]: Remove IRDA As Dmitry pointed out earlier, rfkill-input.c doesn't support irda because there are no users and we shouldn't add unrequired KEY_ defines. However, RFKILL_TYPE_IRDA was defined in the rfkill.h header file and would confuse people about whether it is implemented or not. This patch removes IRDA support completely, so it can be added whenever a driver wants the feature. Signed-off-by: Ivo van Doorn Signed-off-by: David S. Miller --- include/linux/rfkill.h | 8 +++----- net/rfkill/Kconfig | 2 +- net/rfkill/rfkill.c | 5 +---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index a8a6ea809da0..c4546e15c853 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -31,13 +31,11 @@ * enum rfkill_type - type of rfkill switch. * RFKILL_TYPE_WLAN: switch is no a Wireless network devices. * RFKILL_TYPE_BlUETOOTH: switch is on a bluetooth device. - * RFKILL_TYPE_IRDA: switch is on an infrared devices. */ enum rfkill_type { - RFKILL_TYPE_WLAN = 0, - RFKILL_TYPE_BLUETOOTH = 1, - RFKILL_TYPE_IRDA = 2, - RFKILL_TYPE_MAX = 3, + RFKILL_TYPE_WLAN , + RFKILL_TYPE_BLUETOOTH, + RFKILL_TYPE_MAX, }; enum rfkill_state { diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index 8b31759ee8b0..d28a6d9303e4 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -5,7 +5,7 @@ menuconfig RFKILL tristate "RF switch subsystem support" help Say Y here if you want to have control over RF switches - found on many WiFi, Bluetooth and IRDA cards. + found on many WiFi and Bluetooth cards. To compile this driver as a module, choose M here: the module will be called rfkill. diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index db3395bfbcfa..50e010272e47 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -106,9 +106,6 @@ static ssize_t rfkill_type_show(struct device *dev, case RFKILL_TYPE_BLUETOOTH: type = "bluetooth"; break; - case RFKILL_TYPE_IRDA: - type = "irda"; - break; default: BUG(); } @@ -281,7 +278,7 @@ static void rfkill_remove_switch(struct rfkill *rfkill) /** * rfkill_allocate - allocate memory for rfkill structure. * @parent: device that has rf switch on it - * @type: type of the switch (wlan, bluetooth, irda) + * @type: type of the switch (RFKILL_TYPE_*) * * This function should be called by the network driver when it needs * rfkill structure. Once the structure is allocated the driver shoud From e0665486b78b8efb9c25019ad29b4a4c9c1e9dfc Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 13 Sep 2007 09:21:31 +0200 Subject: [PATCH 1201/2804] [RFKILL]: Add support for ultrawideband This patch will add support for UWB keys to rfkill, support for this has been requested by Inaky. Signed-off-by: Ivo van Doorn Signed-off-by: David S. Miller --- include/linux/input.h | 1 + include/linux/rfkill.h | 2 ++ net/rfkill/rfkill-input.c | 9 +++++++++ net/rfkill/rfkill.c | 3 +++ 4 files changed, 15 insertions(+) diff --git a/include/linux/input.h b/include/linux/input.h index 36e00aa6f03b..6eb3aead7f1d 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -360,6 +360,7 @@ struct input_absinfo { #define KEY_BLUETOOTH 237 #define KEY_WLAN 238 +#define KEY_UWB 239 #define KEY_UNKNOWN 240 diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index c4546e15c853..f9a50dab4168 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -31,10 +31,12 @@ * enum rfkill_type - type of rfkill switch. * RFKILL_TYPE_WLAN: switch is no a Wireless network devices. * RFKILL_TYPE_BlUETOOTH: switch is on a bluetooth device. + * RFKILL_TYPE_UWB: switch is on a Ultra wideband device. */ enum rfkill_type { RFKILL_TYPE_WLAN , RFKILL_TYPE_BLUETOOTH, + RFKILL_TYPE_UWB, RFKILL_TYPE_MAX, }; diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c index 9f746be58854..8e4516a5fe32 100644 --- a/net/rfkill/rfkill-input.c +++ b/net/rfkill/rfkill-input.c @@ -81,6 +81,7 @@ static void rfkill_schedule_toggle(struct rfkill_task *task) static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); +static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB); static void rfkill_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) @@ -93,6 +94,9 @@ static void rfkill_event(struct input_handle *handle, unsigned int type, case KEY_BLUETOOTH: rfkill_schedule_toggle(&rfkill_bt); break; + case KEY_UWB: + rfkill_schedule_toggle(&rfkill_uwb); + break; default: break; } @@ -148,6 +152,11 @@ static const struct input_device_id rfkill_ids[] = { .evbit = { BIT(EV_KEY) }, .keybit = { [LONG(KEY_BLUETOOTH)] = BIT(KEY_BLUETOOTH) }, }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT(EV_KEY) }, + .keybit = { [LONG(KEY_UWB)] = BIT(KEY_UWB) }, + }, { } }; diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 50e010272e47..03ed7fd8afe0 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -106,6 +106,9 @@ static ssize_t rfkill_type_show(struct device *dev, case RFKILL_TYPE_BLUETOOTH: type = "bluetooth"; break; + case RFKILL_TYPE_UWB: + type = "ultrawideband"; + break; default: BUG(); } From dac24ab396fc92985060d5cb3c467d2d0ffc0c20 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 13 Sep 2007 09:22:55 +0200 Subject: [PATCH 1202/2804] [RFKILL]: Add rfkill documentation Add a documentation file which contains a short description about rfkill with some notes about drivers and the userspace interface. Changes since v1 and v2: - Spellchecking Signed-off-by: Ivo van Doorn Acked-by: Dmitry Torokhov Acked-by: Randy Dunlap --- Documentation/rfkill.txt | 89 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Documentation/rfkill.txt diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt new file mode 100644 index 000000000000..a83ff23cd68c --- /dev/null +++ b/Documentation/rfkill.txt @@ -0,0 +1,89 @@ +rfkill - RF switch subsystem support +==================================== + +1 Implementation details +2 Driver support +3 Userspace support + +=============================================================================== +1: Implementation details + +The rfkill switch subsystem offers support for keys often found on laptops +to enable wireless devices like WiFi and Bluetooth. + +This is done by providing the user 3 possibilities: + 1 - The rfkill system handles all events; userspace is not aware of events. + 2 - The rfkill system handles all events; userspace is informed about the events. + 3 - The rfkill system does not handle events; userspace handles all events. + +The buttons to enable and disable the wireless radios are important in +situations where the user is for example using his laptop on a location where +wireless radios _must_ be disabled (e.g. airplanes). +Because of this requirement, userspace support for the keys should not be +made mandatory. Because userspace might want to perform some additional smarter +tasks when the key is pressed, rfkill still provides userspace the possibility +to take over the task to handle the key events. + +The system inside the kernel has been split into 2 separate sections: + 1 - RFKILL + 2 - RFKILL_INPUT + +The first option enables rfkill support and will make sure userspace will +be notified of any events through the input device. It also creates several +sysfs entries which can be used by userspace. See section "Userspace support". + +The second option provides an rfkill input handler. This handler will +listen to all rfkill key events and will toggle the radio accordingly. +With this option enabled userspace could either do nothing or simply +perform monitoring tasks. + +==================================== +2: Driver support + +To build a driver with rfkill subsystem support, the driver should +depend on the Kconfig symbol RFKILL; it should _not_ depend on +RKFILL_INPUT. + +Unless key events trigger an interrupt to which the driver listens, polling +will be required to determine the key state changes. For this the input +layer providers the input-polldev handler. + +A driver should implement a few steps to correctly make use of the +rfkill subsystem. First for non-polling drivers: + + - rfkill_allocate() + - input_allocate_device() + - rfkill_register() + - input_register_device() + +For polling drivers: + + - rfkill_allocate() + - input_allocate_polled_device() + - rfkill_register() + - input_register_polled_device() + +When a key event has been detected, the correct event should be +sent over the input device which has been registered by the driver. + +==================================== +3: Userspace support + +For each key an input device will be created which will send out the correct +key event when the rfkill key has been pressed. + +The following sysfs entries will be created: + + name: Name assigned by driver to this key (interface or driver name). + type: Name of the key type ("wlan", "bluetooth", etc). + state: Current state of the key. 1: On, 0: Off. + claim: 1: Userspace handles events, 0: Kernel handles events + +Both the "state" and "claim" entries are also writable. For the "state" entry +this means that when 1 or 0 is written all radios, not yet in the requested +state, will be will be toggled accordingly. +For the "claim" entry writing 1 to it means that the kernel no longer handles +key events even though RFKILL_INPUT input was enabled. When "claim" has been +set to 0, userspace should make sure that it listens for the input events or +check the sysfs "state" entry regularly to correctly perform the required +tasks when the rkfill key is pressed. From 39c90ece7565f5c47110c2fa77409d7a9478bd5b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 15 Sep 2007 10:55:54 -0700 Subject: [PATCH 1203/2804] [IPV4]: Convert rt_check_expire() from softirq processing to workqueue. On loaded/big hosts, rt_check_expire() if of litle use, because it generally breaks out of its main loop because of a jiffies change. It can take a long time (read : timer invocations) to actually scan the whole hash table, freeing unused entries. Converting it to use a workqueue instead of softirq is a nice move because we can allow rt_check_expire() to do the scan it is supposed to do, without hogging the CPU. This has an impact on the average number of entries in cache, reducing ram usage. Cache is more responsive to parameter changes (/proc/sys/net/ipv4/route/gc_timeout and /proc/sys/net/ipv4/route/gc_interval) Note: Maybe the default value of gc_interval (60 seconds) is too high, since this means we actually need 5 (300/60) invocations to scan the whole table. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/route.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 396c631166a4..006d6058a806 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include @@ -136,7 +137,8 @@ static unsigned long rt_deadline; #define RTprint(a...) printk(KERN_DEBUG a) static struct timer_list rt_flush_timer; -static struct timer_list rt_periodic_timer; +static void rt_check_expire(struct work_struct *work); +static DECLARE_DELAYED_WORK(expires_work, rt_check_expire); static struct timer_list rt_secret_timer; /* @@ -572,20 +574,19 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) (fl1->iif ^ fl2->iif)) == 0; } -/* This runs via a timer and thus is always in BH context. */ -static void rt_check_expire(unsigned long dummy) +static void rt_check_expire(struct work_struct *work) { static unsigned int rover; unsigned int i = rover, goal; struct rtable *rth, **rthp; - unsigned long now = jiffies; u64 mult; mult = ((u64)ip_rt_gc_interval) << rt_hash_log; if (ip_rt_gc_timeout > 1) do_div(mult, ip_rt_gc_timeout); goal = (unsigned int)mult; - if (goal > rt_hash_mask) goal = rt_hash_mask + 1; + if (goal > rt_hash_mask) + goal = rt_hash_mask + 1; for (; goal > 0; goal--) { unsigned long tmo = ip_rt_gc_timeout; @@ -594,11 +595,11 @@ static void rt_check_expire(unsigned long dummy) if (*rthp == 0) continue; - spin_lock(rt_hash_lock_addr(i)); + spin_lock_bh(rt_hash_lock_addr(i)); while ((rth = *rthp) != NULL) { if (rth->u.dst.expires) { /* Entry is expired even if it is in use */ - if (time_before_eq(now, rth->u.dst.expires)) { + if (time_before_eq(jiffies, rth->u.dst.expires)) { tmo >>= 1; rthp = &rth->u.dst.rt_next; continue; @@ -613,14 +614,10 @@ static void rt_check_expire(unsigned long dummy) *rthp = rth->u.dst.rt_next; rt_free(rth); } - spin_unlock(rt_hash_lock_addr(i)); - - /* Fallback loop breaker. */ - if (time_after(jiffies, now)) - break; + spin_unlock_bh(rt_hash_lock_addr(i)); } rover = i; - mod_timer(&rt_periodic_timer, jiffies + ip_rt_gc_interval); + schedule_delayed_work(&expires_work, ip_rt_gc_interval); } /* This can run from both BH and non-BH contexts, the latter @@ -2993,17 +2990,14 @@ int __init ip_rt_init(void) init_timer(&rt_flush_timer); rt_flush_timer.function = rt_run_flush; - init_timer(&rt_periodic_timer); - rt_periodic_timer.function = rt_check_expire; init_timer(&rt_secret_timer); rt_secret_timer.function = rt_secret_rebuild; /* All the timers, started at system startup tend to synchronize. Perturb it a bit. */ - rt_periodic_timer.expires = jiffies + net_random() % ip_rt_gc_interval + - ip_rt_gc_interval; - add_timer(&rt_periodic_timer); + schedule_delayed_work(&expires_work, + net_random() % ip_rt_gc_interval + ip_rt_gc_interval); rt_secret_timer.expires = jiffies + net_random() % ip_rt_secret_interval + ip_rt_secret_interval; From 5d4ecd9370da6e32588f218a5495806635154352 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:24 -0400 Subject: [PATCH 1204/2804] [MAC80211]: remove spy wext ioctls mac80211 never calls wireless_spy_update so these aren't useful. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_ioctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 383ad5f64c1f..1d585cc2c8c7 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1268,10 +1268,10 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - iw_handler_set_spy, /* SIOCSIWSPY */ - iw_handler_get_spy, /* SIOCGIWSPY */ - iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ - iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (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) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ From c29b9b9b0235d56e5602f61ed38702dd376aae20 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:24 -0400 Subject: [PATCH 1205/2804] [MAC80211]: don't send invalid QoS frames Kalle Valo noticed that QoS frames are sent with an invalid QoS control field; this is because we increase the header length but neither initialise the space nor actually have enough space in the header structure for the QoS control field. This patch fixes it by treating the QoS field specially and appending it explicitly, initialising it to zero. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/tx.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9e952e37b7df..0820f127da2b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1487,7 +1487,20 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, nh_pos += encaps_len; h_pos += encaps_len; } - memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + + if (fc & IEEE80211_STYPE_QOS_DATA) { + __le16 *qos_control; + + qos_control = (__le16*) skb_push(skb, 2); + memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2); + /* + * Maybe we could actually set some fields here, for now just + * initialise to zero to indicate no special operation. + */ + *qos_control = 0; + } else + memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + nh_pos += hdrlen; h_pos += hdrlen; From d4e46a3d9869563c6210b01bb651c40cbe65da80 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:24 -0400 Subject: [PATCH 1206/2804] [MAC80211]: fix race conditions with keys During receive processing, we select the key long before using it and because there's no locking it is possible that we kfree() the key after having selected it but before using it for crypto operations. Obviously, this is bad. Secondly, during transmit processing, there are two possible races: We have a similar race between select_key() and using it for encryption, but we also have a race here between select_key() and hardware encryption (both when a key is removed.) This patch solves these issues by using RCU: when a key is to be freed, we first remove the pointer from the appropriate places (sdata->keys, sdata->default_key, sta->key) using rcu_assign_pointer() and then synchronize_rcu(). Then, we can safely kfree() the key and remove it from the hardware. There's a window here where the hardware may still be using it for decryption, but we can't work around that without having two hardware callbacks, one to disable the key for RX and one to disable it for TX; but the worst thing that will happen is that we receive a packet decrypted that we don't find a key for any more and then drop it. When we add a key, we first need to upload it to the hardware and then, using rcu_assign_pointer() again, link it into our structures. In the code using keys (TX/RX paths) we use rcu_dereference() to get the key and enclose the whole tx/rx section in a rcu_read_lock() ... rcu_read_unlock() block. Because we've uploaded the key to hardware before linking it into internal structures, we can guarantee that it is valid once get to into tx(). One possible race condition remains, however: when we have hardware acceleration enabled and the driver shuts down the queues, we end up queueing the frame. If now somebody removes the key, the key will be removed from hwaccel and then then driver will be asked to encrypt the frame with a key index that has been removed. Hence, drivers will need to be aware that the hw_key_index they are passed might not be under all circumstances. Most drivers will, however, simply ignore that condition and encrypt the frame with the selected key anyway, this only results in a frame being encrypted with a wrong key or dropped (rightfully) because the key was not valid. There isn't much we can do about it unless we want to walk the pending frame queue every time a key is removed and remove all frames that used it. This race condition, however, will most likely be solved once we add multiqueue support to mac80211 because then frames will be queued further up the stack instead of after being processed. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_ioctl.c | 5 +--- net/mac80211/key.c | 43 +++++++++++++++++++++------------- net/mac80211/rx.c | 20 +++++++++++++--- net/mac80211/tx.c | 20 ++++++++++++---- 4 files changed, 61 insertions(+), 27 deletions(-) diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 1d585cc2c8c7..10ec05624a67 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -73,11 +73,8 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, key = NULL; } else { /* - * Need to free it before allocating a new one with - * with the same index or the ordering to the driver's - * set_key() callback becomes confused. + * Automatically frees any old key if present. */ - ieee80211_key_free(key); key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key); if (!key) { ret = -ENOMEM; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 178f00cf61b9..19e77f626d84 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "ieee80211_i.h" #include "debugfs_key.h" @@ -120,6 +121,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, { struct ieee80211_key *key; + BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS); BUG_ON(alg == ALG_NONE); key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); @@ -157,9 +159,15 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, ieee80211_debugfs_key_add(key->local, key); + /* remove key first */ + if (sta) + ieee80211_key_free(sta->key); + else + ieee80211_key_free(sdata->keys[idx]); + if (sta) { ieee80211_debugfs_key_sta_link(key, sta); - sta->key = key; + /* * some hardware cannot handle TKIP with QoS, so * we indicate whether QoS could be in use. @@ -179,21 +187,19 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, sta_info_put(ap); } } - - if (idx >= 0 && idx < NUM_DEFAULT_KEYS) { - if (!sdata->keys[idx]) - sdata->keys[idx] = key; - else - WARN_ON(1); - } else - WARN_ON(1); } - list_add(&key->list, &sdata->key_list); - + /* enable hwaccel if appropriate */ if (netif_running(key->sdata->dev)) ieee80211_key_enable_hw_accel(key); + if (sta) + rcu_assign_pointer(sta->key, key); + else + rcu_assign_pointer(sdata->keys[idx], key); + + list_add(&key->list, &sdata->key_list); + return key; } @@ -202,20 +208,25 @@ void ieee80211_key_free(struct ieee80211_key *key) if (!key) return; - ieee80211_key_disable_hw_accel(key); - if (key->sta) { - key->sta->key = NULL; + rcu_assign_pointer(key->sta->key, NULL); } else { if (key->sdata->default_key == key) ieee80211_set_default_key(key->sdata, -1); if (key->conf.keyidx >= 0 && key->conf.keyidx < NUM_DEFAULT_KEYS) - key->sdata->keys[key->conf.keyidx] = NULL; + rcu_assign_pointer(key->sdata->keys[key->conf.keyidx], + NULL); else WARN_ON(1); } + /* wait for all key users to complete */ + synchronize_rcu(); + + /* remove from hwaccel if appropriate */ + ieee80211_key_disable_hw_accel(key); + if (key->conf.alg == ALG_CCMP) ieee80211_aes_key_free(key->u.ccmp.tfm); ieee80211_debugfs_key_remove(key); @@ -235,7 +246,7 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) if (sdata->default_key != key) { ieee80211_debugfs_key_remove_default(sdata); - sdata->default_key = key; + rcu_assign_pointer(sdata->default_key, key); if (sdata->default_key) ieee80211_debugfs_key_add_default(sdata); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4fb8c7026f11..91b7886bf797 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -311,6 +312,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; int keyidx; int hdrlen; + struct ieee80211_key *stakey = NULL; /* * Key selection 101 @@ -348,8 +350,11 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) return TXRX_CONTINUE; - if (!is_multicast_ether_addr(hdr->addr1) && rx->sta && rx->sta->key) { - rx->key = rx->sta->key; + if (rx->sta) + stakey = rcu_dereference(rx->sta->key); + + if (!is_multicast_ether_addr(hdr->addr1) && stakey) { + rx->key = stakey; } else { /* * The device doesn't give us the IV so we won't be @@ -374,7 +379,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) */ keyidx = rx->skb->data[hdrlen + 3] >> 6; - rx->key = rx->sdata->keys[keyidx]; + rx->key = rcu_dereference(rx->sdata->keys[keyidx]); /* * RSNA-protected unicast frames should always be sent with @@ -1364,6 +1369,12 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, skb_pull(skb, radiotap_len); } + /* + * key references are protected using RCU and this requires that + * we are in a read-site RCU section during receive processing + */ + rcu_read_lock(); + hdr = (struct ieee80211_hdr *) skb->data; memset(&rx, 0, sizeof(rx)); rx.skb = skb; @@ -1404,6 +1415,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, rx.sta); sta_info_put(sta); + rcu_read_unlock(); return; } @@ -1465,6 +1477,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, read_unlock(&local->sub_if_lock); end: + rcu_read_unlock(); + if (sta) sta_info_put(sta); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0820f127da2b..b29dc70b2f01 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -427,14 +428,16 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) static ieee80211_txrx_result ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) { + struct ieee80211_key *key; + tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) tx->key = NULL; - else if (tx->sta && tx->sta->key) - tx->key = tx->sta->key; - else if (tx->sdata->default_key) - tx->key = tx->sdata->default_key; + else if (tx->sta && (key = rcu_dereference(tx->sta->key))) + tx->key = key; + else if ((key = rcu_dereference(tx->sdata->default_key))) + tx->key = key; else if (tx->sdata->drop_unencrypted && !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); @@ -1112,6 +1115,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, return 0; } + /* + * key references are protected using RCU and this requires that + * we are in a read-site RCU section during receive processing + */ + rcu_read_lock(); + sta = tx.sta; tx.u.tx.mgmt_interface = mgmt; tx.u.tx.mode = local->hw.conf.mode; @@ -1139,6 +1148,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, if (unlikely(res == TXRX_QUEUED)) { I802_DEBUG_INC(local->tx_handlers_queued); + rcu_read_unlock(); return 0; } @@ -1196,6 +1206,7 @@ retry: store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); } + rcu_read_unlock(); return 0; drop: @@ -1205,6 +1216,7 @@ retry: if (tx.u.tx.extra_frag[i]) dev_kfree_skb(tx.u.tx.extra_frag[i]); kfree(tx.u.tx.extra_frag); + rcu_read_unlock(); return 0; } From b708e610622cff07f4374a2b4410884f964b8489 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [PATCH 1207/2804] [MAC80211]: remove turbo modes This patch removes all mention of the atheros turbo modes that can't possibly work properly anyway since in some places we don't check for them when we should. I have no idea what the iwlwifi drivers were doing with these but it can't possibly have been correct. Cc: Zhu Yi Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 7 ++-- net/mac80211/debugfs.c | 2 -- net/mac80211/ieee80211.c | 6 +--- net/mac80211/ieee80211_common.h | 2 -- net/mac80211/ieee80211_ioctl.c | 63 ++++++++++++++++++++++++++++----- net/mac80211/ieee80211_sta.c | 19 +--------- net/mac80211/regdomain.c | 6 ---- net/mac80211/rx.c | 2 -- net/mac80211/tx.c | 2 -- net/mac80211/util.c | 11 +----- 10 files changed, 59 insertions(+), 61 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ec8c7393956b..fcb7e3f9c669 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -73,14 +73,13 @@ struct ieee80211_channel { #define IEEE80211_RATE_SUPPORTED 0x00000010 #define IEEE80211_RATE_OFDM 0x00000020 #define IEEE80211_RATE_CCK 0x00000040 -#define IEEE80211_RATE_TURBO 0x00000080 #define IEEE80211_RATE_MANDATORY 0x00000100 #define IEEE80211_RATE_CCK_2 (IEEE80211_RATE_CCK | IEEE80211_RATE_PREAMBLE2) #define IEEE80211_RATE_MODULATION(f) \ (f & (IEEE80211_RATE_CCK | IEEE80211_RATE_OFDM)) -/* Low-level driver should set PREAMBLE2, OFDM, CCK, and TURBO flags. +/* Low-level driver should set PREAMBLE2, OFDM and CCK flags. * BASIC, SUPPORTED, ERP, and MANDATORY flags are set in 80211.o based on the * configuration. */ struct ieee80211_rate { @@ -101,12 +100,10 @@ struct ieee80211_rate { /* 802.11g is backwards-compatible with 802.11b, so a wlan card can * actually be both in 11b and 11g modes at the same time. */ -enum { +enum ieee80211_phymode { MODE_IEEE80211A, /* IEEE 802.11a */ MODE_IEEE80211B, /* IEEE 802.11b only */ - MODE_ATHEROS_TURBO, /* Atheros Turbo mode (2x.11a at 5 GHz) */ MODE_IEEE80211G, /* IEEE 802.11g (and 802.11b compatibility) */ - MODE_ATHEROS_TURBOG, /* Atheros Turbo mode (2x.11g at 2.4 GHz) */ /* keep last */ NUM_IEEE80211_MODES diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index dc5ed1a8bf62..12db9adc0361 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -28,8 +28,6 @@ static const char *ieee80211_mode_str(int mode) return "IEEE 802.11b"; case MODE_IEEE80211G: return "IEEE 802.11g"; - case MODE_ATHEROS_TURBO: - return "Atheros Turbo (5 GHz)"; default: return "UNKNOWN"; } diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 506cfa06b184..0e8a70f408e2 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -118,10 +118,6 @@ ieee80211_fill_frame_info(struct ieee80211_local *local, case MODE_IEEE80211G: fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g); break; - case MODE_ATHEROS_TURBO: - fi->phytype = - htonl(ieee80211_phytype_dsss_dot11_turbo); - break; default: fi->phytype = htonl(0xAAAAAAAA); break; @@ -1225,7 +1221,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->long_retry_limit = 4; local->hw.conf.radio_enabled = 1; - local->enabled_modes = (unsigned int) -1; + local->enabled_modes = ~0; INIT_LIST_HEAD(&local->modes_list); diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h index d0bbd00b4617..5b5fb7bcfd72 100644 --- a/net/mac80211/ieee80211_common.h +++ b/net/mac80211/ieee80211_common.h @@ -73,8 +73,6 @@ enum ieee80211_phytype { ieee80211_phytype_ofdm_dot11_g = 6, ieee80211_phytype_pbcc_dot11_g = 7, ieee80211_phytype_ofdm_dot11_a = 8, - ieee80211_phytype_dsss_dot11_turbog = 255, - ieee80211_phytype_dsss_dot11_turbo = 256, }; enum ieee80211_ssi_type { diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 10ec05624a67..e1c4502b26bf 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -26,6 +26,41 @@ #include "wpa.h" #include "aes_ccm.h" + +/* + * Wow. This ioctl interface is such crap, it's tied + * to internal definitions. I hope it dies soon. + */ +static int mode_to_hostapd_mode(enum ieee80211_phymode mode) +{ + switch (mode) { + case MODE_IEEE80211A: + return 0; + case MODE_IEEE80211B: + return 1; + case MODE_IEEE80211G: + return 3; + case NUM_IEEE80211_MODES: + WARN_ON(1); + break; + } + WARN_ON(1); + return -1; +} + +static enum ieee80211_phymode hostapd_mode_to_mode(int hostapd_mode) +{ + switch (hostapd_mode) { + case 0: + return MODE_IEEE80211A; + case 1: + return MODE_IEEE80211B; + case 3: + return MODE_IEEE80211G; + } + return NUM_IEEE80211_MODES; +} + static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, int idx, int alg, int set_tx_key, const u8 *_key, size_t key_len) @@ -141,9 +176,6 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, case MODE_IEEE80211G: strcpy(name, "IEEE 802.11g"); break; - case MODE_ATHEROS_TURBO: - strcpy(name, "5GHz Turbo"); - break; default: strcpy(name, "IEEE 802.11"); break; @@ -594,9 +626,6 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, struct ieee80211_rate *rates = &mode->rates[i]; int this_rate = rates->rate; - if (mode->mode == MODE_ATHEROS_TURBO || - mode->mode == MODE_ATHEROS_TURBOG) - this_rate *= 2; if (target_rate == this_rate) { sdata->bss->max_ratectrl_rateidx = i; if (rate->fixed) @@ -786,6 +815,7 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, int param = *i; int value = *(i + 1); int ret = 0; + int mode; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -840,7 +870,7 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_NEXT_MODE: - local->next_mode = value; + local->next_mode = hostapd_mode_to_mode(value); break; case PRISM2_PARAM_KEY_TX_RX_THRESHOLD: @@ -868,7 +898,15 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_HW_MODES: - local->enabled_modes = value; + mode = 1; + local->enabled_modes = 0; + while (value) { + if (value & 1) + local->enabled_modes |= + hostapd_mode_to_mode(mode); + mode <<= 1; + value >>= 1; + } break; case PRISM2_PARAM_CREATE_IBSS: @@ -909,6 +947,7 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, struct ieee80211_sub_if_data *sdata; int *param = (int *) extra; int ret = 0; + int mode; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -946,7 +985,13 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_HW_MODES: - *param = local->enabled_modes; + mode = 0; + *param = 0; + while (mode < NUM_IEEE80211_MODES) { + if (local->enabled_modes & (1<rates[i].rate; - if (mode->mode == MODE_ATHEROS_TURBO) - rate /= 2; *pos++ = (u8) (rate / 5); } @@ -629,8 +627,6 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = mode->num_rates - len; for (i = len; i < mode->num_rates; i++) { int rate = mode->rates[i].rate; - if (mode->mode == MODE_ATHEROS_TURBO) - rate /= 2; *pos++ = (u8) (rate / 5); } } @@ -889,10 +885,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, pos = skb_put(skb, 1); supp_rates[1]++; } - if (mode->mode == MODE_ATHEROS_TURBO) - *pos = rate->rate / 10; - else - *pos = rate->rate / 5; + *pos = rate->rate / 5; } ieee80211_sta_tx(dev, skb, 0); @@ -1285,16 +1278,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, mode = local->oper_hw_mode; for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; - if (mode->mode == MODE_ATHEROS_TURBO) - rate *= 2; for (j = 0; j < mode->num_rates; j++) if (mode->rates[j].rate == rate) rates |= BIT(j); } for (i = 0; i < elems.ext_supp_rates_len; i++) { int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; - if (mode->mode == MODE_ATHEROS_TURBO) - rate *= 2; for (j = 0; j < mode->num_rates; j++) if (mode->rates[j].rate == rate) rates |= BIT(j); @@ -1514,8 +1503,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev, rate = elems.ext_supp_rates [i - elems.supp_rates_len]; own_rate = 5 * (rate & 0x7f); - if (mode->mode == MODE_ATHEROS_TURBO) - own_rate *= 2; for (j = 0; j < num_rates; j++) if (rates[j].rate == own_rate) supp_rates |= BIT(j); @@ -2344,8 +2331,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, mode = local->oper_hw_mode; for (i = 0; i < bss->supp_rates_len; i++) { int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - if (mode->mode == MODE_ATHEROS_TURBO) - bitrate *= 2; for (j = 0; j < mode->num_rates; j++) if (mode->rates[j].rate == bitrate) rates |= BIT(j); @@ -2418,8 +2403,6 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, pos = bss->supp_rates; for (i = 0; i < mode->num_rates; i++) { int rate = mode->rates[i].rate; - if (mode->mode == MODE_ATHEROS_TURBO) - rate /= 2; *pos++ = (u8) (rate / 5); } diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c index b697a2afbb4b..f42678fa62d1 100644 --- a/net/mac80211/regdomain.c +++ b/net/mac80211/regdomain.c @@ -82,12 +82,6 @@ static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan) chan->flag = 0; - if (ieee80211_regdom == 64 && - (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) { - /* Do not allow Turbo modes in Japan. */ - return; - } - for (i = 0; channel_range[i].start_freq; i++) { const struct ieee80211_channel_range *r = &channel_range[i]; if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 91b7886bf797..8c6e29089216 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -94,8 +94,6 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) * 1 usec = 1/8 * (1080 / 10) = 13.5 */ if (mode->mode == MODE_IEEE80211A || - mode->mode == MODE_ATHEROS_TURBO || - mode->mode == MODE_ATHEROS_TURBOG || (mode->mode == MODE_IEEE80211G && rate->flags & IEEE80211_RATE_ERP)) hdrtime = CHAN_UTIL_HDR_SHORT; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b29dc70b2f01..08d221674bc0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -747,8 +747,6 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) * 1 usec = 1/8 * (1080 / 10) = 13.5 */ if (mode->mode == MODE_IEEE80211A || - mode->mode == MODE_ATHEROS_TURBO || - mode->mode == MODE_ATHEROS_TURBOG || (mode->mode == MODE_IEEE80211G && tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) hdrtime = CHAN_UTIL_HDR_SHORT; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c970996ba6f9..29c0a0e1f52c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -93,11 +93,6 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, if (rate->rate == 10 || rate->rate == 20) rate->flags |= IEEE80211_RATE_BASIC; break; - case MODE_ATHEROS_TURBO: - if (rate->rate == 120 || rate->rate == 240 || - rate->rate == 480) - rate->flags |= IEEE80211_RATE_BASIC; - break; case MODE_IEEE80211G: if (rate->rate == 10 || rate->rate == 20 || rate->rate == 55 || rate->rate == 110) @@ -116,8 +111,6 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, if (rate->rate == 10) rate->flags |= IEEE80211_RATE_MANDATORY; break; - case MODE_ATHEROS_TURBO: - break; case MODE_IEEE80211G: if (rate->rate == 10 || rate->rate == 20 || rate->rate == 55 || rate->rate == 110 || @@ -273,8 +266,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, * DIV_ROUND_UP() operations. */ - if (local->hw.conf.phymode == MODE_IEEE80211A || erp || - local->hw.conf.phymode == MODE_ATHEROS_TURBO) { + if (local->hw.conf.phymode == MODE_IEEE80211A || erp) { /* * OFDM: * @@ -288,7 +280,6 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, * 802.11g - 19.8.4: aSIFSTime = 10 usec + * signal ext = 6 usec */ - /* FIX: Atheros Turbo may have different (shorter) duration? */ dur = 16; /* SIFS + signal ext */ dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ From 7848ba7d7a010ccb265617fc2bc053e2bdf06f48 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [PATCH 1208/2804] [MAC80211]: rework hardware crypto flags This patch reworks the various hardware crypto related flags to make them more local, i.e. put them with each key or each packet instead of into the hw struct. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/rtl8187_dev.c | 3 +- include/net/mac80211.h | 49 +++++++++--------------------- net/mac80211/rx.c | 24 ++++++--------- net/mac80211/tx.c | 5 ++- net/mac80211/wpa.c | 43 +++++++++----------------- 5 files changed, 42 insertions(+), 82 deletions(-) diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 9db9ece31b49..7dbf11e30db3 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -605,8 +605,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->modes[1].channels = priv->channels; priv->mode = IEEE80211_IF_TYPE_MGMT; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_WEP_INCLUDE_IV; + IEEE80211_HW_RX_INCLUDES_FCS; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); dev->queues = 1; dev->max_rssi = 65; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fcb7e3f9c669..9137579c12a4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -240,6 +240,8 @@ struct ieee80211_rx_status { #define RX_FLAG_MMIC_ERROR (1<<0) #define RX_FLAG_DECRYPTED (1<<1) #define RX_FLAG_RADIOTAP (1<<2) +#define RX_FLAG_MMIC_STRIPPED (1<<3) +#define RX_FLAG_IV_STRIPPED (1<<4) int flag; }; @@ -402,6 +404,16 @@ typedef enum { * that situation it should reject that key. */ #define IEEE80211_KEY_FLAG_WMM_STA (1<<0) +/* + * This flag should be set by the driver if it requires + * IV generation in software for this key. + */ +#define IEEE80211_KEY_FLAG_GENERATE_IV (1<<1) +/* + * This flag should be set by the driver if it requires + * MMIC generation in software for this key. + */ +#define IEEE80211_KEY_FLAG_GENERATE_MMIC (1<<2) struct ieee80211_key_conf { /* @@ -465,17 +477,7 @@ struct ieee80211_hw { */ #define IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE (1<<1) - /* - * Some devices handle decryption internally and do not - * indicate whether the frame was encrypted (unencrypted frames - * will be dropped by the hardware, unless specifically allowed - * through.) - * It is permissible to not handle all encrypted frames and fall - * back to software encryption; however, if this flag is set - * unencrypted frames must be dropped unless the driver is told - * otherwise via the set_ieee8021x() callback. - */ -#define IEEE80211_HW_DEVICE_HIDES_WEP (1<<2) +/* hole at 2 */ /* Whether RX frames passed to ieee80211_rx() include FCS in the end */ #define IEEE80211_HW_RX_INCLUDES_FCS (1<<3) @@ -488,32 +490,13 @@ struct ieee80211_hw { * can fetch them with ieee80211_get_buffered_bc(). */ #define IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING (1<<4) - /* - * This flag is only relevant if hardware encryption is used. - * If set, it has two meanings: - * 1) the IV and ICV are present in received frames that have - * been decrypted (unless IEEE80211_HW_DEVICE_HIDES_WEP is - * also set) - * 2) on transmission, the IV should be generated in software. - * - * Please let us know if you *don't* use this flag, the stack would - * really like to be able to get the IV to keep key statistics - * accurate. - */ -#define IEEE80211_HW_WEP_INCLUDE_IV (1<<5) +/* hole at 5 */ /* hole at 6 */ /* hole at 7 */ - /* - * Some devices handle Michael MIC internally and do not include MIC in - * the received packets passed up. This flag must be set for such - * devices. The 'encryption' frame control bit is expected to be still - * set in the IEEE 802.11 header with this option unlike with the - * IEEE80211_HW_DEVICE_HIDES_WEP flag. - */ -#define IEEE80211_HW_DEVICE_STRIPS_MIC (1<<8) +/* hole at 8 */ /* Device is capable of performing full monitor mode even during * normal operation. */ @@ -527,8 +510,6 @@ struct ieee80211_hw { * specified in the device's EEPROM */ #define IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED (1<<11) - /* calculate Michael MIC for an MSDU when doing hwcrypto */ -#define IEEE80211_HW_TKIP_INCLUDE_MMIC (1<<12) /* Do TKIP phase1 key mixing in stack to support cards only do * phase2 key mixing when doing hwcrypto */ #define IEEE80211_HW_TKIP_REQ_PHASE1_KEY (1<<13) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8c6e29089216..28b8b6af4c42 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -363,7 +363,8 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) * we somehow allow the driver to tell us which key * the hardware used if this flag is set? */ - if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) + if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && + (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) return TXRX_CONTINUE; hdrlen = ieee80211_get_hdrlen(rx->fc); @@ -534,8 +535,8 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; /* Check for weak IVs, if hwaccel did not remove IV from the frame */ - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) || - !(rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || + !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) if (ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; @@ -559,15 +560,14 @@ ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || - !(rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " "failed\n", rx->dev->name); return TXRX_DROP; } - } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { + } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ skb_trim(rx->skb, rx->skb->len - 4); @@ -898,13 +898,10 @@ static ieee80211_txrx_result ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) { /* - * Pass through unencrypted frames if the hardware might have - * decrypted them already without telling us, but that can only - * be true if we either didn't find a key or the found key is - * uploaded to the hardware. + * Pass through unencrypted frames if the hardware has + * decrypted them already. */ - if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) && - (!rx->key || (rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))) + if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) return TXRX_CONTINUE; /* Drop unencrypted frames if key is set. */ @@ -1212,8 +1209,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, goto ignore; } - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { + if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { /* AP with Pairwise keys support should never receive Michael * MIC errors for non-zero keyidx because these are reserved * for group keys and only the AP is sending real multicast diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 08d221674bc0..e2ae1e1fcc7b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -545,9 +545,8 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) return -1; } else { tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (ieee80211_wep_add_iv(tx->local, skb, tx->key) == - NULL) + if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { + if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; } } diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 775f89e42a43..a23531cef5b0 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -91,7 +91,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && - !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC */ @@ -138,26 +138,13 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) /* * No way to verify the MIC if the hardware stripped it */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC) + if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) return TXRX_CONTINUE; if (!rx->key || rx->key->conf.alg != ALG_TKIP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (skb->len < MICHAEL_MIC_LEN) - return TXRX_DROP; - } - /* Need to verify Michael MIC sometimes in software even when - * hwaccel is used. Atheros ar5212: fragmented frames and QoS - * frames. */ - if (!(rx->flags & IEEE80211_TXRXD_FRAGMENTED) && !wpa_test) - goto remove_mic; - } - if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) || data_len < MICHAEL_MIC_LEN) return TXRX_DROP; @@ -184,7 +171,6 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - remove_mic: /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); @@ -287,7 +273,7 @@ ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx) ieee80211_tx_set_iswep(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; @@ -330,11 +316,13 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) if (!rx->sta || skb->len - hdrlen < 12) return TXRX_DROP; - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { - /* Hardware takes care of all processing, including - * replay protection, so no need to continue here. */ + if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { + if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { + /* + * Hardware took care of all processing, including + * replay protection, and stripped the ICV/IV so + * we cannot do any checks here. + */ return TXRX_CONTINUE; } @@ -538,7 +526,7 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) ieee80211_tx_set_iswep(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; @@ -585,8 +573,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) + (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) return TXRX_CONTINUE; (void) ccmp_hdr2pn(pn, skb->data + hdrlen); @@ -605,10 +592,8 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - /* hwaccel has already decrypted frame and verified MIC */ - } else { + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { + /* hardware didn't decrypt/verify MIC */ u8 *scratch, *b_0, *aad; scratch = key->u.ccmp.rx_crypto_buf; From c15a205070fac9fab0d9d4642b9342677b67f933 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [PATCH 1209/2804] [MAC80211]: remove set_key_idx callback No existing drivers use this callback, hence there's no telling how it might be used. In fact, it is unlikely to be of much use as-is because the default key index isn't something that the driver can do much with without knowing which interface it was for etc. And if it needs the key index for the transmitted frame, it can get it by keeping a reference to the key_conf structure and looking it up by hw_key_idx. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 13 ------------- net/mac80211/key.c | 4 ---- 2 files changed, 17 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9137579c12a4..8f22b7384805 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -645,19 +645,6 @@ struct ieee80211_ops { const u8 *local_address, const u8 *address, struct ieee80211_key_conf *key); - /* - * Set TX key index for default/broadcast keys. This is needed in cases - * where wlan card is doing full WEP/TKIP encapsulation (wep_include_iv - * is not set), in other cases, this function pointer can be set to - * NULL since the IEEE 802.11 module takes care of selecting the key - * index for each TX frame. - * - * TODO: If you use this callback in your driver tell us if you need - * any other information from it to make it easier, like the - * key_conf instead. - */ - int (*set_key_idx)(struct ieee80211_hw *hw, int idx); - /* Enable/disable IEEE 802.1X. This item requests wlan card to pass * unencrypted EAPOL-Key frames even when encryption is configured. * If the wlan card does not require such a configuration, this diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 19e77f626d84..b10e33deb63e 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -250,10 +250,6 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) if (sdata->default_key) ieee80211_debugfs_key_add_default(sdata); - - if (sdata->local->ops->set_key_idx) - sdata->local->ops->set_key_idx( - local_to_hw(sdata->local), idx); } } From 7ac1bd6aecc92cfe6ec11891819dd4c26f2f7879 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [PATCH 1210/2804] [MAC80211]: some more documentation This patch formats some documentation in mac80211.h into kerneldoc and also adds some more explanations for hardware crypto. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 150 +++++++++++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 44 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8f22b7384805..950a4827507f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -224,24 +224,56 @@ struct ieee80211_tx_control { int ifindex; /* internal */ }; -/* Receive status. The low-level driver should provide this information - * (the subset supported by hardware) to the 802.11 code with each received - * frame. */ + +/** + * enum mac80211_rx_flags - receive flags + * + * These flags are used with the @flag member of &struct ieee80211_rx_status. + * @RX_FLAG_MMIC_ERROR: Michael MIC error was reported on this frame. + * Use together with %RX_FLAG_MMIC_STRIPPED. + * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware. + * @RX_FLAG_RADIOTAP: This frame starts with a radiotap header. + * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame, + * verification has been done by the hardware. + * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. + * If this flag is set, the stack cannot do any replay detection + * hence the driver or hardware will have to do that. + */ +enum mac80211_rx_flags { + RX_FLAG_MMIC_ERROR = 1<<0, + RX_FLAG_DECRYPTED = 1<<1, + RX_FLAG_RADIOTAP = 1<<2, + RX_FLAG_MMIC_STRIPPED = 1<<3, + RX_FLAG_IV_STRIPPED = 1<<4, +}; + +/** + * struct ieee80211_rx_status - receive status + * + * The low-level driver should provide this information (the subset + * supported by hardware) to the 802.11 code with each received + * frame. + * @mactime: MAC timestamp as defined by 802.11 + * @freq: frequency the radio was tuned to when receiving this frame, in MHz + * @channel: channel the radio was tuned to + * @phymode: active PHY mode + * @ssi: signal strength when receiving this frame + * @signal: used as 'qual' in statistics reporting + * @noise: PHY noise when receiving this frame + * @antenna: antenna used + * @rate: data rate + * @flag: %RX_FLAG_* + */ struct ieee80211_rx_status { u64 mactime; - int freq; /* receive frequency in Mhz */ + int freq; int channel; int phymode; int ssi; - int signal; /* used as qual in statistics reporting */ + int signal; int noise; int antenna; int rate; -#define RX_FLAG_MMIC_ERROR (1<<0) -#define RX_FLAG_DECRYPTED (1<<1) -#define RX_FLAG_RADIOTAP (1<<2) -#define RX_FLAG_MMIC_STRIPPED (1<<3) -#define RX_FLAG_IV_STRIPPED (1<<4) int flag; }; @@ -391,62 +423,87 @@ struct ieee80211_if_conf { struct ieee80211_tx_control *beacon_control; }; -typedef enum { +/** + * enum ieee80211_key_alg - key algorithm + * @ALG_NONE: Unset key algorithm, will never be passed to the driver + * @ALG_WEP: WEP40 or WEP104 + * @ALG_TKIP: TKIP + * @ALG_CCMP: CCMP (AES) + */ +typedef enum ieee80211_key_alg { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, } ieee80211_key_alg; -/* - * This flag indiciates that the station this key is being - * configured for may use QoS. If your hardware cannot handle - * that situation it should reject that key. - */ -#define IEEE80211_KEY_FLAG_WMM_STA (1<<0) -/* - * This flag should be set by the driver if it requires - * IV generation in software for this key. - */ -#define IEEE80211_KEY_FLAG_GENERATE_IV (1<<1) -/* - * This flag should be set by the driver if it requires - * MMIC generation in software for this key. - */ -#define IEEE80211_KEY_FLAG_GENERATE_MMIC (1<<2) +/** + * enum ieee80211_key_flags - key flags + * + * These flags are used for communication about keys between the driver + * and mac80211, with the @flags parameter of &struct ieee80211_key_conf. + * + * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates + * that the STA this key will be used with could be using QoS. + * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the + * driver to indicate that it requires IV generation for this + * particular key. + * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by + * the driver for a TKIP key if it requires Michael MIC + * generation in software. + */ +enum ieee80211_key_flags { + IEEE80211_KEY_FLAG_WMM_STA = 1<<0, + IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, + IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, +}; + +/** + * struct ieee80211_key_conf - key information + * + * This key information is given by mac80211 to the driver by + * the set_key() callback in &struct ieee80211_ops. + * + * @hw_key_idx: To be set by the driver, this is the key index the driver + * wants to be given when a frame is transmitted and needs to be + * encrypted in hardware. It defaults to %HW_KEY_IDX_INVALID which + * the driver may not use. + * @alg: The key algorithm. + * @flags: key flags, see &enum ieee80211_key_flags. + * @keyidx: the key index (0-3) + * @keylen: key material length + * @key: key material + */ struct ieee80211_key_conf { - /* - * To be set by the driver to the key index it would like to - * get in the ieee80211_tx_control.key_idx which defaults - * to HW_KEY_IDX_INVALID so that shouldn't be used. - */ int hw_key_idx; - - /* key algorithm, ALG_NONE should never be seen by the driver */ ieee80211_key_alg alg; - - /* key flags, see above */ u8 flags; - - /* key index: 0-3 */ s8 keyidx; - - /* length of key material */ u8 keylen; - - /* the key material */ u8 key[0]; }; #define IEEE80211_SEQ_COUNTER_RX 0 #define IEEE80211_SEQ_COUNTER_TX 1 -typedef enum { +/** + * enum set_key_cmd - key command + * + * Used with the set_key() callback in &struct ieee80211_ops, this + * indicates whether a key is being removed or added. + * + * @SET_KEY: a key is set + * @DISABLE_KEY: a key must be disabled + */ +typedef enum set_key_cmd { SET_KEY, DISABLE_KEY, } set_key_cmd; -/* This is driver-visible part of the per-hw state the stack keeps. */ +/** + * struct ieee80211_hw - hardware information and state + * TODO: move documentation into kernel-doc format + */ struct ieee80211_hw { /* points to the cfg80211 wiphy for this piece. Note * that you must fill in the perm_addr and dev fields @@ -633,6 +690,11 @@ struct ieee80211_ops { * assigned to something other than HW_KEY_IDX_INVALID. When the cmd * is DISABLE_KEY then it must succeed. * + * Note that it is permissible to not decrypt a frame even if a key + * for it has been uploaded to hardware, the stack will not make any + * decision based on whether a key has been uploaded or not but rather + * based on the receive flags. + * * This callback can sleep, and is only called between add_interface * and remove_interface calls, i.e. while the interface with the * given local_address is enabled. From 6a7664d451e7014b1a6828e50ccb3308d0b84816 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [PATCH 1211/2804] [MAC80211]: remove HW_KEY_IDX_INVALID This patch makes the mac80211/driver interface rely only on the IEEE80211_TXCTL_DO_NOT_ENCRYPT flag to signal to the driver whether a frame should be encrypted or not, since mac80211 internally no longer relies on HW_KEY_IDX_INVALID either this removes it, changes the key index to be a u8 in all places and makes the full range of the value available to drivers. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 17 ++++++++--------- net/mac80211/key.c | 4 ---- net/mac80211/tx.c | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 950a4827507f..652dced0f3ec 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -164,7 +164,6 @@ struct ieee80211_low_level_stats { /* Transmit control fields. This data structure is passed to low-level driver * with each TX frame. The low-level driver is responsible for configuring * the hardware to use given values (depending on what is supported). */ -#define HW_KEY_IDX_INVALID -1 struct ieee80211_tx_control { int tx_rate; /* Transmit rate, given as the hw specific value for the @@ -197,13 +196,13 @@ struct ieee80211_tx_control { * long retry value */ u32 flags; /* tx control flags defined * above */ + u8 key_idx; /* keyidx from hw->set_key(), undefined if + * IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. * This could be used when set_retry_limit * is not implemented by the driver */ u8 power_level; /* per-packet transmit power level, in dBm */ u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ - s8 key_idx; /* HW_KEY_IDX_INVALID = do not encrypt, - * other values: keyidx from hw->set_key() */ u8 icv_len; /* length of the ICV/MIC field in octets */ u8 iv_len; /* length of the IV field in octets */ u8 tkip_key[16]; /* generated phase2/phase1 key for hw TKIP */ @@ -467,8 +466,7 @@ enum ieee80211_key_flags { * * @hw_key_idx: To be set by the driver, this is the key index the driver * wants to be given when a frame is transmitted and needs to be - * encrypted in hardware. It defaults to %HW_KEY_IDX_INVALID which - * the driver may not use. + * encrypted in hardware. * @alg: The key algorithm. * @flags: key flags, see &enum ieee80211_key_flags. * @keyidx: the key index (0-3) @@ -476,8 +474,8 @@ enum ieee80211_key_flags { * @key: key material */ struct ieee80211_key_conf { - int hw_key_idx; ieee80211_key_alg alg; + u8 hw_key_idx; u8 flags; s8 keyidx; u8 keylen; @@ -686,9 +684,10 @@ struct ieee80211_ops { * selected by the low-level driver. * * Return 0 if the key is now in use, -EOPNOTSUPP or -ENOSPC if it - * couldn't be added; if you return 0 then hw_key_idx must be - * assigned to something other than HW_KEY_IDX_INVALID. When the cmd - * is DISABLE_KEY then it must succeed. + * couldn't be added; if you return 0 then hw_key_idx must be assigned + * to the hardware key index, you are free to use the full u8 range. + * + * When the cmd is DISABLE_KEY then it must succeed. * * Note that it is permissible to not decrypt a frame even if a key * for it has been uploaded to hardware, the stack will not make any diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b10e33deb63e..dd6fc4aa3ff5 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -73,8 +73,6 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) key->sdata->dev->dev_addr, addr, &key->conf); - WARN_ON(!ret && (key->conf.hw_key_idx == HW_KEY_IDX_INVALID)); - if (!ret) key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; @@ -109,7 +107,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, MAC_ARG(addr), ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - key->conf.hw_key_idx = HW_KEY_IDX_INVALID; } struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, @@ -132,7 +129,6 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, * Default to software encryption; we'll later upload the * key to the hardware if possible. */ - key->conf.hw_key_idx = HW_KEY_IDX_INVALID; key->conf.flags = 0; key->flags = 0; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e2ae1e1fcc7b..3d57e6d80f6d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -430,8 +430,6 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) { struct ieee80211_key *key; - tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; - if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) tx->key = NULL; else if (tx->sta && (key = rcu_dereference(tx->sta->key))) @@ -442,8 +440,10 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TXRX_DROP; - } else + } else { tx->key = NULL; + tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + } if (tx->key) { tx->key->tx_rx_count++; @@ -724,6 +724,15 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) } } + /* + * Tell hardware to not encrypt when we had sw crypto. + * Because we use the same flag to internally indicate that + * no (software) encryption should be done, we have to set it + * after all crypto handlers. + */ + if (tx->key && !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + return TXRX_CONTINUE; } @@ -833,7 +842,6 @@ __ieee80211_parse_tx_radiotap( */ control->retry_limit = 1; /* no retry */ - control->key_idx = HW_KEY_IDX_INVALID; control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | IEEE80211_TXCTL_USE_CTS_PROTECT); control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT | From c39e3a0d0380b12f45bf85a619d3df45e437ee45 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [PATCH 1212/2804] [MAC80211]: remove TKIP mixing for hw accel again The TKIP mixing code was added for the benefit of Intel's ipw3945 chipset but that code ended up not using it. We have previously identified many problems with this code and it crystallized that library functions for mixing are likely to handle this in much more generality and might allow b43 to take advantage of hardware acceleration for TKIP. Due to these reasons, remove the TKIP mixing for hardware accelerated crypto operations. Signed-off-by: Johannes Berg Acked-by: Michael Buesch Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 9 --------- net/mac80211/wpa.c | 17 ----------------- 2 files changed, 26 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 652dced0f3ec..a2c14f95b9a0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -189,7 +189,6 @@ struct ieee80211_tx_control { #define IEEE80211_TXCTL_REQUEUE (1<<7) #define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of * the frame */ -#define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9) #define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send * using the through * set_retry_limit configured @@ -205,7 +204,6 @@ struct ieee80211_tx_control { u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ u8 icv_len; /* length of the ICV/MIC field in octets */ u8 iv_len; /* length of the IV field in octets */ - u8 tkip_key[16]; /* generated phase2/phase1 key for hw TKIP */ u8 queue; /* hardware queue to use for this frame; * 0 = highest, hw->queues-1 = lowest */ u8 sw_retry_attempt; /* number of times hw has tried to @@ -565,13 +563,6 @@ struct ieee80211_hw { * specified in the device's EEPROM */ #define IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED (1<<11) - /* Do TKIP phase1 key mixing in stack to support cards only do - * phase2 key mixing when doing hwcrypto */ -#define IEEE80211_HW_TKIP_REQ_PHASE1_KEY (1<<13) - /* Do TKIP phase1 and phase2 key mixing in stack and send the generated - * per-packet RC4 key with each TX frame when doing hwcrypto */ -#define IEEE80211_HW_TKIP_REQ_PHASE2_KEY (1<<14) - u32 flags; /* hardware flags defined above */ /* Set to the size of a needed device specific skb headroom for TX skbs. */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index a23531cef5b0..6e12638054aa 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -214,7 +214,6 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, key->u.tkip.iv32++; if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { - u32 flags = tx->local->hw.flags; hdr = (struct ieee80211_hdr *)skb->data; /* hwaccel - with preallocated room for IV */ @@ -224,22 +223,6 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, 0x7f), (u8) key->u.tkip.iv16); - if (flags & IEEE80211_HW_TKIP_REQ_PHASE2_KEY) - ieee80211_tkip_gen_rc4key(key, hdr->addr2, - tx->u.tx.control->tkip_key); - else if (flags & IEEE80211_HW_TKIP_REQ_PHASE1_KEY) { - if (key->u.tkip.iv16 == 0 || - !key->u.tkip.tx_initialized) { - ieee80211_tkip_gen_phase1key(key, hdr->addr2, - (u16 *)tx->u.tx.control->tkip_key); - key->u.tkip.tx_initialized = 1; - tx->u.tx.control->flags |= - IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY; - } else - tx->u.tx.control->flags &= - ~IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY; - } - tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; return 0; } From 139c3a0492745192f999aaa67d11cb63983211f5 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [PATCH 1213/2804] [MAC80211]: ignore key index on pairwise key (WEP only) Work-around for broken APs that use a non-zero key index for WEP pairwise keys. With this patch, WEP encryption only is exempt from providing a zero key index. Signed-off-by: Volker Braun Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_ioctl.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index e1c4502b26bf..51dca21f77c7 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -73,17 +73,23 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { + printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", + dev->name, idx); + return -EINVAL; + } + if (is_broadcast_ether_addr(sta_addr)) { sta = NULL; - if (idx >= NUM_DEFAULT_KEYS) { - printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", - dev->name, idx); - return -EINVAL; - } key = sdata->keys[idx]; } else { set_tx_key = 0; - if (idx != 0) { + /* + * According to the standard, the key index of a pairwise + * key must be zero. However, some AP are broken when it + * comes to WEP key indices, so we work around this. + */ + if (idx != 0 && alg != ALG_WEP) { printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for " "individual key\n", dev->name); return -EINVAL; From 24338793eea9dcc0865826e1115af86a19af8d18 Mon Sep 17 00:00:00 2001 From: warmcat Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [PATCH 1214/2804] [MAC80211]: get STA after tx radiotap snipped Johannes Berg noticed that in __ieee80211_tx_prepare() we try to get the STA from addr1 of the ieee80211 header when the radiotap header is actually still at the front of the packet. This patch defers doing that until the radiotap header is gone. Signed-off-by: Andy Green Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3d57e6d80f6d..1780c24f7957 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -959,8 +959,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, tx->dev = dev; /* use original interface */ tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); - tx->sta = sta_info_get(local, hdr->addr1); - tx->fc = le16_to_cpu(hdr->frame_control); /* * set defaults for things that can be set by @@ -985,6 +983,8 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, res = TXRX_QUEUED; /* indication it was monitor packet */ } + tx->sta = sta_info_get(local, hdr->addr1); + tx->fc = le16_to_cpu(hdr->frame_control); tx->u.tx.control = control; if (is_multicast_ether_addr(hdr->addr1)) { tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; From 68aae11674b9d6598b660d1148ffba9eef3f895f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Aug 2007 11:29:34 -0700 Subject: [PATCH 1215/2804] [MAC80211]: use internal network device stats Stats are now available for device usage inside network_device Signed-off-by: Stephen Hemminger Acked-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211.c | 26 ++++---------------------- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/rx.c | 11 ++++------- net/mac80211/tx.c | 8 ++++---- 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 0e8a70f408e2..0c1f7b2e157c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -47,13 +47,6 @@ struct ieee80211_tx_status_rtap_hdr { /* common interface routines */ -static struct net_device_stats *ieee80211_get_stats(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - return &(sdata->stats); -} - static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) { memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ @@ -168,11 +161,9 @@ ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, { struct ieee80211_frame_info *fi; const size_t hlen = sizeof(struct ieee80211_frame_info); - struct ieee80211_sub_if_data *sdata; + struct net_device *dev = local->apdev; - skb->dev = local->apdev; - - sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev); + skb->dev = dev; if (skb_headroom(skb) < hlen) { I802_DEBUG_INC(local->rx_expand_skb_head); @@ -187,8 +178,8 @@ ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, ieee80211_fill_frame_info(local, fi, status); fi->msg_type = htonl(msg_type); - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; skb_set_mac_header(skb, 0); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -269,7 +260,6 @@ void ieee80211_if_mgmt_setup(struct net_device *dev) ether_setup(dev); dev->hard_start_xmit = ieee80211_mgmt_start_xmit; dev->change_mtu = ieee80211_change_mtu_apdev; - dev->get_stats = ieee80211_get_stats; dev->open = ieee80211_mgmt_open; dev->stop = ieee80211_mgmt_stop; dev->type = ARPHRD_IEEE80211_PRISM; @@ -599,7 +589,6 @@ void ieee80211_if_setup(struct net_device *dev) dev->wireless_handlers = &ieee80211_iw_handler_def; dev->set_multicast_list = ieee80211_set_multicast_list; dev->change_mtu = ieee80211_change_mtu; - dev->get_stats = ieee80211_get_stats; dev->open = ieee80211_open; dev->stop = ieee80211_stop; dev->uninit = ieee80211_if_reinit; @@ -1461,13 +1450,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_free_hw); -struct net_device_stats *ieee80211_dev_stats(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - return &sdata->stats; -} - static int __init ieee80211_init(void) { struct sk_buff *skb; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0149f9055918..14e8c366af3d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -301,7 +301,6 @@ struct ieee80211_sub_if_data { unsigned int flags; - struct net_device_stats stats; int drop_unencrypted; int eapol; /* 0 = process EAPOL frames as normal data frames, * 1 = send EAPOL frames through wlan#ap to hostapd @@ -723,7 +722,6 @@ void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); void ieee80211_if_mgmt_setup(struct net_device *dev); -struct net_device_stats *ieee80211_dev_stats(struct net_device *dev); struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hwrate); void ieee80211_key_threshold_notify(struct net_device *dev, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 28b8b6af4c42..a5619d1f9a3b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -137,7 +137,6 @@ ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, struct ieee80211_rx_status *status) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; struct ieee80211_rate *rate; struct ieee80211_rtap_hdr { struct ieee80211_radiotap_header hdr; @@ -150,8 +149,6 @@ ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, skb->dev = dev; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (status->flag & RX_FLAG_RADIOTAP) goto out; @@ -184,8 +181,8 @@ ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, rthdr->antsignal = status->ssi; out: - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; skb_set_mac_header(skb, 0); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1053,8 +1050,8 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) skb2 = NULL; - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP || sdata->type == IEEE80211_IF_TYPE_VLAN) && diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1780c24f7957..acfc3054d467 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1528,8 +1528,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; skb->dev = local->mdev; - sdata->stats.tx_packets++; - sdata->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* Update skb pointers to various headers since this modified frame * is going to go through Linux networking code that may potentially @@ -1602,8 +1602,8 @@ int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!(fc & IEEE80211_FCTL_PROTECTED)) pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - sdata->stats.tx_packets++; - sdata->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; dev_queue_xmit(skb); From 475fa49c125d914451805a9fb3cd1baa53591538 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 2 Sep 2007 22:58:21 +0300 Subject: [PATCH 1216/2804] [MAC80211]: PS mode fix tx.mode must be set also for buffered frames. It is used in the tx hanlders Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/tx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index acfc3054d467..ca262a99e56f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1901,6 +1901,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, } sta = tx.sta; tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; + tx.u.tx.mode = local->hw.conf.mode; for (handler = local->tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); From aa0daf0e020de9c20e653e437deaa1153c4d134e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Sep 2007 14:15:25 +0200 Subject: [PATCH 1217/2804] [MAC80211]: remove/change some comments about Michael MIC hardware offload There are a few TODO comments in the mac80211 sources regarding hardware offload for Michael MIC verification. Those items are, however, better handled in the driver instead of the stack, if any device requires such hand-holding. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/rx.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a5619d1f9a3b..c985c7a537db 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1179,8 +1179,6 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, else keyidx = -1; - /* TODO: verify that this is not triggered by fragmented - * frames (hw does not verify MIC for them). */ if (net_ratelimit()) printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", @@ -1188,9 +1186,10 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, keyidx); if (!sta) { - /* Some hardware versions seem to generate incorrect - * Michael MIC reports; ignore them to avoid triggering - * countermeasures. */ + /* + * Some hardware seem to generate incorrect Michael MIC + * reports; ignore them to avoid triggering countermeasures. + */ if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " "error for unknown address " MAC_FMT "\n", @@ -1201,16 +1200,18 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame with no ISWEP flag (src " + "error for a frame with no PROTECTED flag (src " MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); goto ignore; } if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { - /* AP with Pairwise keys support should never receive Michael - * MIC errors for non-zero keyidx because these are reserved - * for group keys and only the AP is sending real multicast - * frames in BSS. */ + /* + * APs with pairwise keys should never receive Michael MIC + * errors for non-zero keyidx because these are reserved for + * group keys and only the AP is sending real multicast + * frames in the BSS. + */ if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored Michael MIC error for " "a frame with non-zero keyidx (%d)" @@ -1230,10 +1231,6 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, goto ignore; } - /* TODO: consider verifying the MIC error report with software - * implementation if we get too many spurious reports from the - * hardware. */ - mac80211_ev_michael_mic_failure(rx->dev, keyidx, hdr); ignore: dev_kfree_skb(rx->skb); From cc0b88cf5ecf13cdd750f08e201ce8fadcdb601f Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Fri, 31 Aug 2007 01:15:25 -0400 Subject: [PATCH 1218/2804] [PATCH] Add adm8211 802.11b wireless driver This patch adds a mac80211 wireless driver for ADMtek ADM8211 based wireless cards. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- MAINTAINERS | 8 + drivers/net/wireless/Kconfig | 27 + drivers/net/wireless/Makefile | 2 + drivers/net/wireless/adm8211.c | 2063 ++++++++++++++++++++++++++++++++ drivers/net/wireless/adm8211.h | 659 ++++++++++ 5 files changed, 2759 insertions(+) create mode 100644 drivers/net/wireless/adm8211.c create mode 100644 drivers/net/wireless/adm8211.h diff --git a/MAINTAINERS b/MAINTAINERS index 9a91d9e3f1f2..e0861f7e1ccf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -284,6 +284,14 @@ M: corentin.labbe@geomatys.fr L: lm-sensors@lm-sensors.org S: Maintained +ADM8211 WIRELESS DRIVER +P: Michael Wu +M: flamingice@sourmilk.net +L: linux-wireless@vger.kernel.org +W: http://linuxwireless.org/ +T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git +S: Maintained + ADT746X FAN DRIVER P: Colin Leroy M: colin@colino.net diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ae27af0141c0..86480afe5351 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -558,6 +558,33 @@ config RTL8187 Thanks to Realtek for their support! +config ADM8211 + tristate "ADMtek ADM8211 support" + depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + select CRC32 + select EEPROM_93CX6 + ---help--- + This driver is for ADM8211A, ADM8211B, and ADM8211C based cards. + These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as: + + Xterasys Cardbus XN-2411b + Blitz NetWave Point PC + TrendNet 221pc + Belkin F5D6001 + SMC 2635W + Linksys WPC11 v1 + Fiberline FL-WL-200X + 3com Office Connect (3CRSHPW796) + Corega WLPCIB-11 + SMC 2602W V2 EU + D-Link DWL-520 Revision C + + However, some of these cards have been replaced with other chips + like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or + the Ralink RT2400 (SMC2635W) without a model number change. + + Thanks to Infineon-ADMtek for their support of this driver. + source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 4eb6d9752881..e9bffdae0a04 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -47,3 +47,5 @@ obj-$(CONFIG_LIBERTAS) += libertas/ rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o obj-$(CONFIG_RTL8187) += rtl8187.o + +obj-$(CONFIG_ADM8211) += adm8211.o diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c new file mode 100644 index 000000000000..eec01fc15282 --- /dev/null +++ b/drivers/net/wireless/adm8211.c @@ -0,0 +1,2063 @@ + +/* + * Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP) + * + * Copyright (c) 2003, Jouni Malinen + * Copyright (c) 2004-2007, Michael Wu + * Some parts copyright (c) 2003 by David Young + * and used with permission. + * + * Much thanks to Infineon-ADMtek for their support of this 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. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adm8211.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_AUTHOR("Jouni Malinen "); +MODULE_DESCRIPTION("Driver for IEEE 802.11b wireless cards based on ADMtek ADM8211"); +MODULE_SUPPORTED_DEVICE("ADM8211"); +MODULE_LICENSE("GPL"); + +static unsigned int tx_ring_size __read_mostly = 16; +static unsigned int rx_ring_size __read_mostly = 16; + +module_param(tx_ring_size, uint, 0); +module_param(rx_ring_size, uint, 0); + +static const char version[] = KERN_INFO "adm8211: " +"Copyright 2003, Jouni Malinen ; " +"Copyright 2004-2007, Michael Wu \n"; + + +static struct pci_device_id adm8211_pci_id_table[] __devinitdata = { + /* ADMtek ADM8211 */ + { PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */ + { PCI_DEVICE(0x1200, 0x8201) }, /* ? */ + { PCI_DEVICE(0x1317, 0x8201) }, /* ADM8211A */ + { PCI_DEVICE(0x1317, 0x8211) }, /* ADM8211B/C */ + { 0 } +}; + +static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct adm8211_priv *priv = eeprom->data; + u32 reg = ADM8211_CSR_READ(SPR); + + eeprom->reg_data_in = reg & ADM8211_SPR_SDI; + eeprom->reg_data_out = reg & ADM8211_SPR_SDO; + eeprom->reg_data_clock = reg & ADM8211_SPR_SCLK; + eeprom->reg_chip_select = reg & ADM8211_SPR_SCS; +} + +static void adm8211_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct adm8211_priv *priv = eeprom->data; + u32 reg = 0x4000 | ADM8211_SPR_SRS; + + if (eeprom->reg_data_in) + reg |= ADM8211_SPR_SDI; + if (eeprom->reg_data_out) + reg |= ADM8211_SPR_SDO; + if (eeprom->reg_data_clock) + reg |= ADM8211_SPR_SCLK; + if (eeprom->reg_chip_select) + reg |= ADM8211_SPR_SCS; + + ADM8211_CSR_WRITE(SPR, reg); + ADM8211_CSR_READ(SPR); /* eeprom_delay */ +} + +static int adm8211_read_eeprom(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int words, i; + struct ieee80211_chan_range chan_range; + u16 cr49; + struct eeprom_93cx6 eeprom = { + .data = priv, + .register_read = adm8211_eeprom_register_read, + .register_write = adm8211_eeprom_register_write + }; + + if (ADM8211_CSR_READ(CSR_TEST0) & ADM8211_CSR_TEST0_EPTYP) { + /* 256 * 16-bit = 512 bytes */ + eeprom.width = PCI_EEPROM_WIDTH_93C66; + words = 256; + } else { + /* 64 * 16-bit = 128 bytes */ + eeprom.width = PCI_EEPROM_WIDTH_93C46; + words = 64; + } + + priv->eeprom_len = words * 2; + priv->eeprom = kmalloc(priv->eeprom_len, GFP_KERNEL); + if (!priv->eeprom) + return -ENOMEM; + + eeprom_93cx6_multiread(&eeprom, 0, (__le16 __force *)priv->eeprom, words); + + cr49 = le16_to_cpu(priv->eeprom->cr49); + priv->rf_type = (cr49 >> 3) & 0x7; + switch (priv->rf_type) { + case ADM8211_TYPE_INTERSIL: + case ADM8211_TYPE_RFMD: + case ADM8211_TYPE_MARVEL: + case ADM8211_TYPE_AIROHA: + case ADM8211_TYPE_ADMTEK: + break; + + default: + if (priv->revid < ADM8211_REV_CA) + priv->rf_type = ADM8211_TYPE_RFMD; + else + priv->rf_type = ADM8211_TYPE_AIROHA; + + printk(KERN_WARNING "%s (adm8211): Unknown RFtype %d\n", + pci_name(priv->pdev), (cr49 >> 3) & 0x7); + } + + priv->bbp_type = cr49 & 0x7; + switch (priv->bbp_type) { + case ADM8211_TYPE_INTERSIL: + case ADM8211_TYPE_RFMD: + case ADM8211_TYPE_MARVEL: + case ADM8211_TYPE_AIROHA: + case ADM8211_TYPE_ADMTEK: + break; + default: + if (priv->revid < ADM8211_REV_CA) + priv->bbp_type = ADM8211_TYPE_RFMD; + else + priv->bbp_type = ADM8211_TYPE_ADMTEK; + + printk(KERN_WARNING "%s (adm8211): Unknown BBPtype: %d\n", + pci_name(priv->pdev), cr49 >> 3); + } + + if (priv->eeprom->country_code >= ARRAY_SIZE(cranges)) { + printk(KERN_WARNING "%s (adm8211): Invalid country code (%d)\n", + pci_name(priv->pdev), priv->eeprom->country_code); + + chan_range = cranges[2]; + } else + chan_range = cranges[priv->eeprom->country_code]; + + printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n", + pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max); + + priv->modes[0].num_channels = chan_range.max - chan_range.min + 1; + priv->modes[0].channels = priv->channels; + + memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels)); + + for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++) + if (i >= chan_range.min && i <= chan_range.max) + priv->channels[i - 1].flag = + IEEE80211_CHAN_W_SCAN | + IEEE80211_CHAN_W_ACTIVE_SCAN | + IEEE80211_CHAN_W_IBSS; + + switch (priv->eeprom->specific_bbptype) { + case ADM8211_BBP_RFMD3000: + case ADM8211_BBP_RFMD3002: + case ADM8211_BBP_ADM8011: + priv->specific_bbptype = priv->eeprom->specific_bbptype; + break; + + default: + if (priv->revid < ADM8211_REV_CA) + priv->specific_bbptype = ADM8211_BBP_RFMD3000; + else + priv->specific_bbptype = ADM8211_BBP_ADM8011; + + printk(KERN_WARNING "%s (adm8211): Unknown specific BBP: %d\n", + pci_name(priv->pdev), priv->eeprom->specific_bbptype); + } + + switch (priv->eeprom->specific_rftype) { + case ADM8211_RFMD2948: + case ADM8211_RFMD2958: + case ADM8211_RFMD2958_RF3000_CONTROL_POWER: + case ADM8211_MAX2820: + case ADM8211_AL2210L: + priv->transceiver_type = priv->eeprom->specific_rftype; + break; + + default: + if (priv->revid == ADM8211_REV_BA) + priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER; + else if (priv->revid == ADM8211_REV_CA) + priv->transceiver_type = ADM8211_AL2210L; + else if (priv->revid == ADM8211_REV_AB) + priv->transceiver_type = ADM8211_RFMD2948; + + printk(KERN_WARNING "%s (adm8211): Unknown transceiver: %d\n", + pci_name(priv->pdev), priv->eeprom->specific_rftype); + + break; + } + + printk(KERN_DEBUG "%s (adm8211): RFtype=%d BBPtype=%d Specific BBP=%d " + "Transceiver=%d\n", pci_name(priv->pdev), priv->rf_type, + priv->bbp_type, priv->specific_bbptype, priv->transceiver_type); + + return 0; +} + +static inline void adm8211_write_sram(struct ieee80211_hw *dev, + u32 addr, u32 data) +{ + struct adm8211_priv *priv = dev->priv; + + ADM8211_CSR_WRITE(WEPCTL, addr | ADM8211_WEPCTL_TABLE_WR | + (priv->revid < ADM8211_REV_BA ? + 0 : ADM8211_WEPCTL_SEL_WEPTABLE )); + ADM8211_CSR_READ(WEPCTL); + msleep(1); + + ADM8211_CSR_WRITE(WESK, data); + ADM8211_CSR_READ(WESK); + msleep(1); +} + +static void adm8211_write_sram_bytes(struct ieee80211_hw *dev, + unsigned int addr, u8 *buf, + unsigned int len) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg = ADM8211_CSR_READ(WEPCTL); + unsigned int i; + + if (priv->revid < ADM8211_REV_BA) { + for (i = 0; i < len; i += 2) { + u16 val = buf[i] | (buf[i + 1] << 8); + adm8211_write_sram(dev, addr + i / 2, val); + } + } else { + for (i = 0; i < len; i += 4) { + u32 val = (buf[i + 0] << 0 ) | (buf[i + 1] << 8 ) | + (buf[i + 2] << 16) | (buf[i + 3] << 24); + adm8211_write_sram(dev, addr + i / 4, val); + } + } + + ADM8211_CSR_WRITE(WEPCTL, reg); +} + +static void adm8211_clear_sram(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg = ADM8211_CSR_READ(WEPCTL); + unsigned int addr; + + for (addr = 0; addr < ADM8211_SRAM_SIZE; addr++) + adm8211_write_sram(dev, addr, 0); + + ADM8211_CSR_WRITE(WEPCTL, reg); +} + +static int adm8211_get_stats(struct ieee80211_hw *dev, + struct ieee80211_low_level_stats *stats) +{ + struct adm8211_priv *priv = dev->priv; + + memcpy(stats, &priv->stats, sizeof(*stats)); + + return 0; +} + +static void adm8211_set_rx_mode(struct ieee80211_hw *dev, + unsigned short flags, int mc_count) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int bit_nr; + u32 mc_filter[2]; + struct dev_mc_list *mclist; + void *tmp; + + if (flags & IFF_PROMISC) { + priv->nar |= ADM8211_NAR_PR; + priv->nar &= ~ADM8211_NAR_MM; + mc_filter[1] = mc_filter[0] = ~0; + } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) { + 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; + mclist = NULL; + while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) { + bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + + bit_nr &= 0x3F; + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + } + } + + ADM8211_IDLE_RX(); + + ADM8211_CSR_WRITE(MAR0, mc_filter[0]); + ADM8211_CSR_WRITE(MAR1, mc_filter[1]); + ADM8211_CSR_READ(NAR); + + if (flags & IFF_PROMISC) + dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + + ADM8211_RESTORE(); +} + +static int adm8211_get_tx_stats(struct ieee80211_hw *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct adm8211_priv *priv = dev->priv; + struct ieee80211_tx_queue_stats_data *data = &stats->data[0]; + + data->len = priv->cur_tx - priv->dirty_tx; + data->limit = priv->tx_ring_size - 2; + data->count = priv->dirty_tx; + + return 0; +} + +static void adm8211_interrupt_tci(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int dirty_tx; + + spin_lock(&priv->lock); + + for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) { + unsigned int entry = dirty_tx % priv->tx_ring_size; + u32 status = le32_to_cpu(priv->tx_ring[entry].status); + struct adm8211_tx_ring_info *info; + struct sk_buff *skb; + + if (status & TDES0_CONTROL_OWN || + !(status & TDES0_CONTROL_DONE)) + break; + + info = &priv->tx_buffers[entry]; + skb = info->skb; + + /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */ + + pci_unmap_single(priv->pdev, info->mapping, + info->skb->len, PCI_DMA_TODEVICE); + + if (info->tx_control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) { + struct ieee80211_tx_status tx_status = {{0}}; + struct ieee80211_hdr *hdr; + size_t hdrlen = info->hdrlen; + + skb_pull(skb, sizeof(struct adm8211_tx_hdr)); + hdr = (struct ieee80211_hdr *)skb_push(skb, hdrlen); + memcpy(hdr, skb->cb, hdrlen); + memcpy(&tx_status.control, &info->tx_control, + sizeof(tx_status.control)); + if (!(status & TDES0_STATUS_ES)) + tx_status.flags |= IEEE80211_TX_STATUS_ACK; + ieee80211_tx_status_irqsafe(dev, skb, &tx_status); + } else + dev_kfree_skb_irq(skb); + info->skb = NULL; + } + + if (priv->cur_tx - dirty_tx < priv->tx_ring_size - 2) + ieee80211_wake_queue(dev, 0); + + priv->dirty_tx = dirty_tx; + spin_unlock(&priv->lock); +} + + +static void adm8211_interrupt_rci(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int entry = priv->cur_rx % priv->rx_ring_size; + u32 status; + unsigned int pktlen; + struct sk_buff *skb, *newskb; + unsigned int limit = priv->rx_ring_size; + static const u8 rate_tbl[] = {10, 20, 55, 110, 220}; + u8 rssi, rate; + + while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) { + if (!limit--) + break; + + status = le32_to_cpu(priv->rx_ring[entry].status); + rate = (status & RDES0_STATUS_RXDR) >> 12; + rssi = le32_to_cpu(priv->rx_ring[entry].length) & + RDES1_STATUS_RSSI; + + pktlen = status & RDES0_STATUS_FL; + if (pktlen > RX_PKT_SIZE) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: frame too long (%d)\n", + wiphy_name(dev->wiphy), pktlen); + pktlen = RX_PKT_SIZE; + } + + if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) { + skb = NULL; /* old buffer will be reused */ + /* TODO: update RX error stats */ + /* TODO: check RDES0_STATUS_CRC*E */ + } else if (pktlen < RX_COPY_BREAK) { + skb = dev_alloc_skb(pktlen); + if (skb) { + pci_dma_sync_single_for_cpu( + priv->pdev, + priv->rx_buffers[entry].mapping, + pktlen, PCI_DMA_FROMDEVICE); + memcpy(skb_put(skb, pktlen), + skb_tail_pointer(priv->rx_buffers[entry].skb), + pktlen); + pci_dma_sync_single_for_device( + priv->pdev, + priv->rx_buffers[entry].mapping, + RX_PKT_SIZE, PCI_DMA_FROMDEVICE); + } + } else { + newskb = dev_alloc_skb(RX_PKT_SIZE); + if (newskb) { + skb = priv->rx_buffers[entry].skb; + skb_put(skb, pktlen); + pci_unmap_single( + priv->pdev, + priv->rx_buffers[entry].mapping, + RX_PKT_SIZE, PCI_DMA_FROMDEVICE); + priv->rx_buffers[entry].skb = newskb; + priv->rx_buffers[entry].mapping = + pci_map_single(priv->pdev, + skb_tail_pointer(newskb), + RX_PKT_SIZE, + PCI_DMA_FROMDEVICE); + } else { + skb = NULL; + /* TODO: update rx dropped stats */ + } + + priv->rx_ring[entry].buffer1 = + cpu_to_le32(priv->rx_buffers[entry].mapping); + } + + priv->rx_ring[entry].status = cpu_to_le32(RDES0_STATUS_OWN | + RDES0_STATUS_SQL); + priv->rx_ring[entry].length = + cpu_to_le32(RX_PKT_SIZE | + (entry == priv->rx_ring_size - 1 ? + RDES1_CONTROL_RER : 0)); + + if (skb) { + struct ieee80211_rx_status rx_status = {0}; + + if (priv->revid < ADM8211_REV_CA) + rx_status.ssi = rssi; + else + rx_status.ssi = 100 - rssi; + + if (rate <= 4) + rx_status.rate = rate_tbl[rate]; + + rx_status.channel = priv->channel; + rx_status.freq = adm8211_channels[priv->channel - 1].freq; + rx_status.phymode = MODE_IEEE80211B; + + ieee80211_rx_irqsafe(dev, skb, &rx_status); + } + + entry = (++priv->cur_rx) % priv->rx_ring_size; + } + + /* TODO: check LPC and update stats? */ +} + + +static irqreturn_t adm8211_interrupt(int irq, void *dev_id) +{ +#define ADM8211_INT(x) \ +do { \ + if (unlikely(stsr & ADM8211_STSR_ ## x)) \ + printk(KERN_DEBUG "%s: " #x "\n", wiphy_name(dev->wiphy)); \ +} while (0) + + struct ieee80211_hw *dev = dev_id; + struct adm8211_priv *priv = dev->priv; + unsigned int count = 0; + u32 stsr; + + do { + stsr = ADM8211_CSR_READ(STSR); + ADM8211_CSR_WRITE(STSR, stsr); + if (stsr == 0xffffffff) + return IRQ_HANDLED; + + if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS))) + break; + + if (stsr & ADM8211_STSR_RCI) + adm8211_interrupt_rci(dev); + if (stsr & ADM8211_STSR_TCI) + adm8211_interrupt_tci(dev); + + /*ADM8211_INT(LinkOn);*/ + /*ADM8211_INT(LinkOff);*/ + + ADM8211_INT(PCF); + ADM8211_INT(BCNTC); + ADM8211_INT(GPINT); + ADM8211_INT(ATIMTC); + ADM8211_INT(TSFTF); + ADM8211_INT(TSCZ); + ADM8211_INT(SQL); + ADM8211_INT(WEPTD); + ADM8211_INT(ATIME); + /*ADM8211_INT(TBTT);*/ + ADM8211_INT(TEIS); + ADM8211_INT(FBE); + ADM8211_INT(REIS); + ADM8211_INT(GPTT); + ADM8211_INT(RPS); + ADM8211_INT(RDU); + ADM8211_INT(TUF); + /*ADM8211_INT(TRT);*/ + /*ADM8211_INT(TLT);*/ + /*ADM8211_INT(TDU);*/ + ADM8211_INT(TPS); + + } while (count++ < 20); + + return IRQ_RETVAL(count); + +#undef ADM8211_INT +} + +#define WRITE_SYN(name,v_mask,v_shift,a_mask,a_shift,bits,prewrite,postwrite)\ +static void adm8211_rf_write_syn_ ## name (struct ieee80211_hw *dev, \ + u16 addr, u32 value) { \ + struct adm8211_priv *priv = dev->priv; \ + unsigned int i; \ + u32 reg, bitbuf; \ + \ + value &= v_mask; \ + addr &= a_mask; \ + bitbuf = (value << v_shift) | (addr << a_shift); \ + \ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_1); \ + ADM8211_CSR_READ(SYNRF); \ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_0); \ + ADM8211_CSR_READ(SYNRF); \ + \ + if (prewrite) { \ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_WRITE_SYNDATA_0); \ + ADM8211_CSR_READ(SYNRF); \ + } \ + \ + for (i = 0; i <= bits; i++) { \ + if (bitbuf & (1 << (bits - i))) \ + reg = ADM8211_SYNRF_WRITE_SYNDATA_1; \ + else \ + reg = ADM8211_SYNRF_WRITE_SYNDATA_0; \ + \ + ADM8211_CSR_WRITE(SYNRF, reg); \ + ADM8211_CSR_READ(SYNRF); \ + \ + ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_1); \ + ADM8211_CSR_READ(SYNRF); \ + ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_0); \ + ADM8211_CSR_READ(SYNRF); \ + } \ + \ + if (postwrite == 1) { \ + ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_0); \ + ADM8211_CSR_READ(SYNRF); \ + } \ + if (postwrite == 2) { \ + ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_1); \ + ADM8211_CSR_READ(SYNRF); \ + } \ + \ + ADM8211_CSR_WRITE(SYNRF, 0); \ + ADM8211_CSR_READ(SYNRF); \ +} + +WRITE_SYN(max2820, 0x00FFF, 0, 0x0F, 12, 15, 1, 1) +WRITE_SYN(al2210l, 0xFFFFF, 4, 0x0F, 0, 23, 1, 1) +WRITE_SYN(rfmd2958, 0x3FFFF, 0, 0x1F, 18, 23, 0, 1) +WRITE_SYN(rfmd2948, 0x0FFFF, 4, 0x0F, 0, 21, 0, 2) + +#undef WRITE_SYN + +static int adm8211_write_bbp(struct ieee80211_hw *dev, u8 addr, u8 data) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int timeout; + u32 reg; + + timeout = 10; + while (timeout > 0) { + reg = ADM8211_CSR_READ(BBPCTL); + if (!(reg & (ADM8211_BBPCTL_WR | ADM8211_BBPCTL_RD))) + break; + timeout--; + msleep(2); + } + + if (timeout == 0) { + printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed" + " prewrite (reg=0x%08x)\n", + wiphy_name(dev->wiphy), addr, data, reg); + return -ETIMEDOUT; + } + + switch (priv->bbp_type) { + case ADM8211_TYPE_INTERSIL: + reg = ADM8211_BBPCTL_MMISEL; /* three wire interface */ + break; + case ADM8211_TYPE_RFMD: + reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP | + (0x01 << 18); + break; + case ADM8211_TYPE_ADMTEK: + reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP | + (0x05 << 18); + break; + } + reg |= ADM8211_BBPCTL_WR | (addr << 8) | data; + + ADM8211_CSR_WRITE(BBPCTL, reg); + + timeout = 10; + while (timeout > 0) { + reg = ADM8211_CSR_READ(BBPCTL); + if (!(reg & ADM8211_BBPCTL_WR)) + break; + timeout--; + msleep(2); + } + + if (timeout == 0) { + ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) & + ~ADM8211_BBPCTL_WR); + printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed" + " postwrite (reg=0x%08x)\n", + wiphy_name(dev->wiphy), addr, data, reg); + return -ETIMEDOUT; + } + + return 0; +} + +static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) +{ + static const u32 adm8211_rfmd2958_reg5[] = + {0x22BD, 0x22D2, 0x22E8, 0x22FE, 0x2314, 0x232A, 0x2340, + 0x2355, 0x236B, 0x2381, 0x2397, 0x23AD, 0x23C2, 0x23F7}; + static const u32 adm8211_rfmd2958_reg6[] = + {0x05D17, 0x3A2E8, 0x2E8BA, 0x22E8B, 0x1745D, 0x0BA2E, 0x00000, + 0x345D1, 0x28BA2, 0x1D174, 0x11745, 0x05D17, 0x3A2E8, 0x11745}; + + struct adm8211_priv *priv = dev->priv; + u8 ant_power = priv->ant_power > 0x3F ? + priv->eeprom->antenna_power[chan - 1] : priv->ant_power; + u8 tx_power = priv->tx_power > 0x3F ? + priv->eeprom->tx_power[chan - 1] : priv->tx_power; + u8 lpf_cutoff = priv->lpf_cutoff == 0xFF ? + priv->eeprom->lpf_cutoff[chan - 1] : priv->lpf_cutoff; + u8 lnags_thresh = priv->lnags_threshold == 0xFF ? + priv->eeprom->lnags_threshold[chan - 1] : priv->lnags_threshold; + u32 reg; + + ADM8211_IDLE(); + + /* Program synthesizer to new channel */ + switch (priv->transceiver_type) { + case ADM8211_RFMD2958: + case ADM8211_RFMD2958_RF3000_CONTROL_POWER: + adm8211_rf_write_syn_rfmd2958(dev, 0x00, 0x04007); + adm8211_rf_write_syn_rfmd2958(dev, 0x02, 0x00033); + + adm8211_rf_write_syn_rfmd2958(dev, 0x05, + adm8211_rfmd2958_reg5[chan - 1]); + adm8211_rf_write_syn_rfmd2958(dev, 0x06, + adm8211_rfmd2958_reg6[chan - 1]); + break; + + case ADM8211_RFMD2948: + adm8211_rf_write_syn_rfmd2948(dev, SI4126_MAIN_CONF, + SI4126_MAIN_XINDIV2); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_POWERDOWN, + SI4126_POWERDOWN_PDIB | + SI4126_POWERDOWN_PDRB); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_PHASE_DET_GAIN, 0); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_N_DIV, + (chan == 14 ? + 2110 : (2033 + (chan * 5)))); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_N_DIV, 1496); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_R_DIV, 44); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_R_DIV, 44); + break; + + case ADM8211_MAX2820: + adm8211_rf_write_syn_max2820(dev, 0x3, + (chan == 14 ? 0x054 : (0x7 + (chan * 5)))); + break; + + case ADM8211_AL2210L: + adm8211_rf_write_syn_al2210l(dev, 0x0, + (chan == 14 ? 0x229B4 : (0x22967 + (chan * 5)))); + break; + + default: + printk(KERN_DEBUG "%s: unsupported transceiver type %d\n", + wiphy_name(dev->wiphy), priv->transceiver_type); + break; + } + + /* write BBP regs */ + if (priv->bbp_type == ADM8211_TYPE_RFMD) { + + /* SMC 2635W specific? adm8211b doesn't use the 2948 though.. */ + /* TODO: remove if SMC 2635W doesn't need this */ + if (priv->transceiver_type == ADM8211_RFMD2948) { + reg = ADM8211_CSR_READ(GPIO); + reg &= 0xfffc0000; + reg |= ADM8211_CSR_GPIO_EN0; + if (chan != 14) + reg |= ADM8211_CSR_GPIO_O0; + ADM8211_CSR_WRITE(GPIO, reg); + } + + if (priv->transceiver_type == ADM8211_RFMD2958) { + /* set PCNT2 */ + adm8211_rf_write_syn_rfmd2958(dev, 0x0B, 0x07100); + /* set PCNT1 P_DESIRED/MID_BIAS */ + reg = le16_to_cpu(priv->eeprom->cr49); + reg >>= 13; + reg <<= 15; + reg |= ant_power << 9; + adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg); + /* set TXRX TX_GAIN */ + adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 | + (priv->revid < ADM8211_REV_CA ? tx_power : 0)); + } else { + reg = ADM8211_CSR_READ(PLCPHD); + reg &= 0xff00ffff; + reg |= tx_power << 18; + ADM8211_CSR_WRITE(PLCPHD, reg); + } + + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF | + ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST); + ADM8211_CSR_READ(SYNRF); + msleep(30); + + /* RF3000 BBP */ + if (priv->transceiver_type != ADM8211_RFMD2958) + adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, + tx_power<<2); + adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff); + adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh); + adm8211_write_bbp(dev, 0x1c, priv->revid == ADM8211_REV_BA ? + priv->eeprom->cr28 : 0); + adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29); + + ADM8211_CSR_WRITE(SYNRF, 0); + + /* Nothing to do for ADMtek BBP */ + } else if (priv->bbp_type != ADM8211_TYPE_ADMTEK) + printk(KERN_DEBUG "%s: unsupported BBP type %d\n", + wiphy_name(dev->wiphy), priv->bbp_type); + + ADM8211_RESTORE(); + + /* update current channel for adhoc (and maybe AP mode) */ + reg = ADM8211_CSR_READ(CAP0); + reg &= ~0xF; + reg |= chan; + ADM8211_CSR_WRITE(CAP0, reg); + + return 0; +} + +static void adm8211_update_mode(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + + ADM8211_IDLE(); + + priv->soft_rx_crc = 0; + switch (priv->mode) { + case IEEE80211_IF_TYPE_STA: + priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA); + priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR; + break; + case IEEE80211_IF_TYPE_IBSS: + priv->nar &= ~ADM8211_NAR_PR; + priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR; + + /* don't trust the error bits on rev 0x20 and up in adhoc */ + if (priv->revid >= ADM8211_REV_BA) + priv->soft_rx_crc = 1; + break; + case IEEE80211_IF_TYPE_MNTR: + priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST); + priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR; + break; + } + + ADM8211_RESTORE(); +} + +static void adm8211_hw_init_syn(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + + switch (priv->transceiver_type) { + case ADM8211_RFMD2958: + case ADM8211_RFMD2958_RF3000_CONTROL_POWER: + /* comments taken from ADMtek vendor driver */ + + /* Reset RF2958 after power on */ + adm8211_rf_write_syn_rfmd2958(dev, 0x1F, 0x00000); + /* Initialize RF VCO Core Bias to maximum */ + adm8211_rf_write_syn_rfmd2958(dev, 0x0C, 0x3001F); + /* Initialize IF PLL */ + adm8211_rf_write_syn_rfmd2958(dev, 0x01, 0x29C03); + /* Initialize IF PLL Coarse Tuning */ + adm8211_rf_write_syn_rfmd2958(dev, 0x03, 0x1FF6F); + /* Initialize RF PLL */ + adm8211_rf_write_syn_rfmd2958(dev, 0x04, 0x29403); + /* Initialize RF PLL Coarse Tuning */ + adm8211_rf_write_syn_rfmd2958(dev, 0x07, 0x1456F); + /* Initialize TX gain and filter BW (R9) */ + adm8211_rf_write_syn_rfmd2958(dev, 0x09, + (priv->transceiver_type == ADM8211_RFMD2958 ? + 0x10050 : 0x00050)); + /* Initialize CAL register */ + adm8211_rf_write_syn_rfmd2958(dev, 0x08, 0x3FFF8); + break; + + case ADM8211_MAX2820: + adm8211_rf_write_syn_max2820(dev, 0x1, 0x01E); + adm8211_rf_write_syn_max2820(dev, 0x2, 0x001); + adm8211_rf_write_syn_max2820(dev, 0x3, 0x054); + adm8211_rf_write_syn_max2820(dev, 0x4, 0x310); + adm8211_rf_write_syn_max2820(dev, 0x5, 0x000); + break; + + case ADM8211_AL2210L: + adm8211_rf_write_syn_al2210l(dev, 0x0, 0x0196C); + adm8211_rf_write_syn_al2210l(dev, 0x1, 0x007CB); + adm8211_rf_write_syn_al2210l(dev, 0x2, 0x3582F); + adm8211_rf_write_syn_al2210l(dev, 0x3, 0x010A9); + adm8211_rf_write_syn_al2210l(dev, 0x4, 0x77280); + adm8211_rf_write_syn_al2210l(dev, 0x5, 0x45641); + adm8211_rf_write_syn_al2210l(dev, 0x6, 0xEA130); + adm8211_rf_write_syn_al2210l(dev, 0x7, 0x80000); + adm8211_rf_write_syn_al2210l(dev, 0x8, 0x7850F); + adm8211_rf_write_syn_al2210l(dev, 0x9, 0xF900C); + adm8211_rf_write_syn_al2210l(dev, 0xA, 0x00000); + adm8211_rf_write_syn_al2210l(dev, 0xB, 0x00000); + break; + + case ADM8211_RFMD2948: + default: + break; + } +} + +static int adm8211_hw_init_bbp(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + + /* write addresses */ + if (priv->bbp_type == ADM8211_TYPE_INTERSIL) { + ADM8211_CSR_WRITE(MMIWA, 0x100E0C0A); + ADM8211_CSR_WRITE(MMIRD0, 0x00007C7E); + ADM8211_CSR_WRITE(MMIRD1, 0x00100000); + } else if (priv->bbp_type == ADM8211_TYPE_RFMD || + priv->bbp_type == ADM8211_TYPE_ADMTEK) { + /* check specific BBP type */ + switch (priv->specific_bbptype) { + case ADM8211_BBP_RFMD3000: + case ADM8211_BBP_RFMD3002: + ADM8211_CSR_WRITE(MMIWA, 0x00009101); + ADM8211_CSR_WRITE(MMIRD0, 0x00000301); + break; + + case ADM8211_BBP_ADM8011: + ADM8211_CSR_WRITE(MMIWA, 0x00008903); + ADM8211_CSR_WRITE(MMIRD0, 0x00001716); + + reg = ADM8211_CSR_READ(BBPCTL); + reg &= ~ADM8211_BBPCTL_TYPE; + reg |= 0x5 << 18; + ADM8211_CSR_WRITE(BBPCTL, reg); + break; + } + + switch (priv->revid) { + case ADM8211_REV_CA: + if (priv->transceiver_type == ADM8211_RFMD2958 || + priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || + priv->transceiver_type == ADM8211_RFMD2948) + ADM8211_CSR_WRITE(SYNCTL, 0x1 << 22); + else if (priv->transceiver_type == ADM8211_MAX2820 || + priv->transceiver_type == ADM8211_AL2210L) + ADM8211_CSR_WRITE(SYNCTL, 0x3 << 22); + break; + + case ADM8211_REV_BA: + reg = ADM8211_CSR_READ(MMIRD1); + reg &= 0x0000FFFF; + reg |= 0x7e100000; + ADM8211_CSR_WRITE(MMIRD1, reg); + break; + + case ADM8211_REV_AB: + case ADM8211_REV_AF: + default: + ADM8211_CSR_WRITE(MMIRD1, 0x7e100000); + break; + } + + /* For RFMD */ + ADM8211_CSR_WRITE(MACTEST, 0x800); + } + + adm8211_hw_init_syn(dev); + + /* Set RF Power control IF pin to PE1+PHYRST# */ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF | + ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST); + ADM8211_CSR_READ(SYNRF); + msleep(20); + + /* write BBP regs */ + if (priv->bbp_type == ADM8211_TYPE_RFMD) { + /* RF3000 BBP */ + /* another set: + * 11: c8 + * 14: 14 + * 15: 50 (chan 1..13; chan 14: d0) + * 1c: 00 + * 1d: 84 + */ + adm8211_write_bbp(dev, RF3000_CCA_CTRL, 0x80); + /* antenna selection: diversity */ + adm8211_write_bbp(dev, RF3000_DIVERSITY__RSSI, 0x80); + adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, 0x74); + adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, 0x38); + adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, 0x40); + + if (priv->eeprom->major_version < 2) { + adm8211_write_bbp(dev, 0x1c, 0x00); + adm8211_write_bbp(dev, 0x1d, 0x80); + } else { + if (priv->revid == ADM8211_REV_BA) + adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28); + else + adm8211_write_bbp(dev, 0x1c, 0x00); + + adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29); + } + } else if (priv->bbp_type == ADM8211_TYPE_ADMTEK) { + /* reset baseband */ + adm8211_write_bbp(dev, 0x00, 0xFF); + /* antenna selection: diversity */ + adm8211_write_bbp(dev, 0x07, 0x0A); + + /* TODO: find documentation for this */ + switch (priv->transceiver_type) { + case ADM8211_RFMD2958: + case ADM8211_RFMD2958_RF3000_CONTROL_POWER: + adm8211_write_bbp(dev, 0x00, 0x00); + adm8211_write_bbp(dev, 0x01, 0x00); + adm8211_write_bbp(dev, 0x02, 0x00); + adm8211_write_bbp(dev, 0x03, 0x00); + adm8211_write_bbp(dev, 0x06, 0x0f); + adm8211_write_bbp(dev, 0x09, 0x00); + adm8211_write_bbp(dev, 0x0a, 0x00); + adm8211_write_bbp(dev, 0x0b, 0x00); + adm8211_write_bbp(dev, 0x0c, 0x00); + adm8211_write_bbp(dev, 0x0f, 0xAA); + adm8211_write_bbp(dev, 0x10, 0x8c); + adm8211_write_bbp(dev, 0x11, 0x43); + adm8211_write_bbp(dev, 0x18, 0x40); + adm8211_write_bbp(dev, 0x20, 0x23); + adm8211_write_bbp(dev, 0x21, 0x02); + adm8211_write_bbp(dev, 0x22, 0x28); + adm8211_write_bbp(dev, 0x23, 0x30); + adm8211_write_bbp(dev, 0x24, 0x2d); + adm8211_write_bbp(dev, 0x28, 0x35); + adm8211_write_bbp(dev, 0x2a, 0x8c); + adm8211_write_bbp(dev, 0x2b, 0x81); + adm8211_write_bbp(dev, 0x2c, 0x44); + adm8211_write_bbp(dev, 0x2d, 0x0A); + adm8211_write_bbp(dev, 0x29, 0x40); + adm8211_write_bbp(dev, 0x60, 0x08); + adm8211_write_bbp(dev, 0x64, 0x01); + break; + + case ADM8211_MAX2820: + adm8211_write_bbp(dev, 0x00, 0x00); + adm8211_write_bbp(dev, 0x01, 0x00); + adm8211_write_bbp(dev, 0x02, 0x00); + adm8211_write_bbp(dev, 0x03, 0x00); + adm8211_write_bbp(dev, 0x06, 0x0f); + adm8211_write_bbp(dev, 0x09, 0x05); + adm8211_write_bbp(dev, 0x0a, 0x02); + adm8211_write_bbp(dev, 0x0b, 0x00); + adm8211_write_bbp(dev, 0x0c, 0x0f); + adm8211_write_bbp(dev, 0x0f, 0x55); + adm8211_write_bbp(dev, 0x10, 0x8d); + adm8211_write_bbp(dev, 0x11, 0x43); + adm8211_write_bbp(dev, 0x18, 0x4a); + adm8211_write_bbp(dev, 0x20, 0x20); + adm8211_write_bbp(dev, 0x21, 0x02); + adm8211_write_bbp(dev, 0x22, 0x23); + adm8211_write_bbp(dev, 0x23, 0x30); + adm8211_write_bbp(dev, 0x24, 0x2d); + adm8211_write_bbp(dev, 0x2a, 0x8c); + adm8211_write_bbp(dev, 0x2b, 0x81); + adm8211_write_bbp(dev, 0x2c, 0x44); + adm8211_write_bbp(dev, 0x29, 0x4a); + adm8211_write_bbp(dev, 0x60, 0x2b); + adm8211_write_bbp(dev, 0x64, 0x01); + break; + + case ADM8211_AL2210L: + adm8211_write_bbp(dev, 0x00, 0x00); + adm8211_write_bbp(dev, 0x01, 0x00); + adm8211_write_bbp(dev, 0x02, 0x00); + adm8211_write_bbp(dev, 0x03, 0x00); + adm8211_write_bbp(dev, 0x06, 0x0f); + adm8211_write_bbp(dev, 0x07, 0x05); + adm8211_write_bbp(dev, 0x08, 0x03); + adm8211_write_bbp(dev, 0x09, 0x00); + adm8211_write_bbp(dev, 0x0a, 0x00); + adm8211_write_bbp(dev, 0x0b, 0x00); + adm8211_write_bbp(dev, 0x0c, 0x10); + adm8211_write_bbp(dev, 0x0f, 0x55); + adm8211_write_bbp(dev, 0x10, 0x8d); + adm8211_write_bbp(dev, 0x11, 0x43); + adm8211_write_bbp(dev, 0x18, 0x4a); + adm8211_write_bbp(dev, 0x20, 0x20); + adm8211_write_bbp(dev, 0x21, 0x02); + adm8211_write_bbp(dev, 0x22, 0x23); + adm8211_write_bbp(dev, 0x23, 0x30); + adm8211_write_bbp(dev, 0x24, 0x2d); + adm8211_write_bbp(dev, 0x2a, 0xaa); + adm8211_write_bbp(dev, 0x2b, 0x81); + adm8211_write_bbp(dev, 0x2c, 0x44); + adm8211_write_bbp(dev, 0x29, 0xfa); + adm8211_write_bbp(dev, 0x60, 0x2d); + adm8211_write_bbp(dev, 0x64, 0x01); + break; + + case ADM8211_RFMD2948: + break; + + default: + printk(KERN_DEBUG "%s: unsupported transceiver %d\n", + wiphy_name(dev->wiphy), priv->transceiver_type); + break; + } + } else + printk(KERN_DEBUG "%s: unsupported BBP %d\n", + wiphy_name(dev->wiphy), priv->bbp_type); + + ADM8211_CSR_WRITE(SYNRF, 0); + + /* Set RF CAL control source to MAC control */ + reg = ADM8211_CSR_READ(SYNCTL); + reg |= ADM8211_SYNCTL_SELCAL; + ADM8211_CSR_WRITE(SYNCTL, reg); + + return 0; +} + +/* configures hw beacons/probe responses */ +static int adm8211_set_rate(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + int i = 0; + u8 rate_buf[12] = {0}; + + /* write supported rates */ + if (priv->revid != ADM8211_REV_BA) { + rate_buf[0] = ARRAY_SIZE(adm8211_rates); + for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++) + rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80; + } else { + /* workaround for rev BA specific bug */ + rate_buf[0] = 0x04; + rate_buf[1] = 0x82; + rate_buf[2] = 0x04; + rate_buf[3] = 0x0b; + rate_buf[4] = 0x16; + } + + adm8211_write_sram_bytes(dev, ADM8211_SRAM_SUPP_RATE, rate_buf, + ARRAY_SIZE(adm8211_rates) + 1); + + reg = ADM8211_CSR_READ(PLCPHD) & 0x00FFFFFF; /* keep bits 0-23 */ + reg |= 1 << 15; /* short preamble */ + reg |= 110 << 24; + ADM8211_CSR_WRITE(PLCPHD, reg); + + /* MTMLT = 512 TU (max TX MSDU lifetime) + * BCNTSIG = plcp_signal (beacon, probe resp, and atim TX rate) + * SRTYLIM = 224 (short retry limit, TX header value is default) */ + ADM8211_CSR_WRITE(TXLMT, (512 << 16) | (110 << 8) | (224 << 0)); + + return 0; +} + +static void adm8211_hw_init(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + u8 cline; + + reg = le32_to_cpu(ADM8211_CSR_READ(PAR)); + reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME; + reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL); + + if (!pci_set_mwi(priv->pdev)) { + reg |= 0x1 << 24; + pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cline); + + switch (cline) { + case 0x8: reg |= (0x1 << 14); + break; + case 0x16: reg |= (0x2 << 14); + break; + case 0x32: reg |= (0x3 << 14); + break; + default: reg |= (0x0 << 14); + break; + } + } + + ADM8211_CSR_WRITE(PAR, reg); + + reg = ADM8211_CSR_READ(CSR_TEST1); + reg &= ~(0xF << 28); + reg |= (1 << 28) | (1 << 31); + ADM8211_CSR_WRITE(CSR_TEST1, reg); + + /* lose link after 4 lost beacons */ + reg = (0x04 << 21) | ADM8211_WCSR_TSFTWE | ADM8211_WCSR_LSOE; + ADM8211_CSR_WRITE(WCSR, reg); + + /* Disable APM, enable receive FIFO threshold, and set drain receive + * threshold to store-and-forward */ + reg = ADM8211_CSR_READ(CMDR); + reg &= ~(ADM8211_CMDR_APM | ADM8211_CMDR_DRT); + reg |= ADM8211_CMDR_RTE | ADM8211_CMDR_DRT_SF; + ADM8211_CSR_WRITE(CMDR, reg); + + adm8211_set_rate(dev); + + /* 4-bit values: + * PWR1UP = 8 * 2 ms + * PWR0PAPE = 8 us or 5 us + * PWR1PAPE = 1 us or 3 us + * PWR0TRSW = 5 us + * PWR1TRSW = 12 us + * PWR0PE2 = 13 us + * PWR1PE2 = 1 us + * PWR0TXPE = 8 or 6 */ + if (priv->revid < ADM8211_REV_CA) + ADM8211_CSR_WRITE(TOFS2, 0x8815cd18); + else + ADM8211_CSR_WRITE(TOFS2, 0x8535cd16); + + /* Enable store and forward for transmit */ + priv->nar = ADM8211_NAR_SF | ADM8211_NAR_PB; + ADM8211_CSR_WRITE(NAR, priv->nar); + + /* Reset RF */ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_RADIO); + ADM8211_CSR_READ(SYNRF); + msleep(10); + ADM8211_CSR_WRITE(SYNRF, 0); + ADM8211_CSR_READ(SYNRF); + msleep(5); + + /* Set CFP Max Duration to 0x10 TU */ + reg = ADM8211_CSR_READ(CFPP); + reg &= ~(0xffff << 8); + reg |= 0x0010 << 8; + ADM8211_CSR_WRITE(CFPP, reg); + + /* USCNT = 0x16 (number of system clocks, 22 MHz, in 1us + * TUCNT = 0x3ff - Tu counter 1024 us */ + ADM8211_CSR_WRITE(TOFS0, (0x16 << 24) | 0x3ff); + + /* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us), + * DIFS=50 us, EIFS=100 us */ + if (priv->revid < ADM8211_REV_CA) + ADM8211_CSR_WRITE(IFST, (20 << 23) | (110 << 15) | + (50 << 9) | 100); + else + ADM8211_CSR_WRITE(IFST, (20 << 23) | (24 << 15) | + (50 << 9) | 100); + + /* PCNT = 1 (MAC idle time awake/sleep, unit S) + * RMRD = 2346 * 8 + 1 us (max RX duration) */ + ADM8211_CSR_WRITE(RMD, (1 << 16) | 18769); + + /* MART=65535 us, MIRT=256 us, TSFTOFST=0 us */ + ADM8211_CSR_WRITE(RSPT, 0xffffff00); + + /* Initialize BBP (and SYN) */ + adm8211_hw_init_bbp(dev); + + /* make sure interrupts are off */ + ADM8211_CSR_WRITE(IER, 0); + + /* ACK interrupts */ + ADM8211_CSR_WRITE(STSR, ADM8211_CSR_READ(STSR)); + + /* Setup WEP (turns it off for now) */ + reg = ADM8211_CSR_READ(MACTEST); + reg &= ~(7 << 20); + ADM8211_CSR_WRITE(MACTEST, reg); + + reg = ADM8211_CSR_READ(WEPCTL); + reg &= ~ADM8211_WEPCTL_WEPENABLE; + reg |= ADM8211_WEPCTL_WEPRXBYP; + ADM8211_CSR_WRITE(WEPCTL, reg); + + /* Clear the missed-packet counter. */ + ADM8211_CSR_READ(LPC); + + if (!priv->mac_addr) + return; + + /* set mac address */ + ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr); + ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]); +} + +static int adm8211_hw_reset(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg, tmp; + int timeout = 100; + + /* Power-on issue */ + /* TODO: check if this is necessary */ + ADM8211_CSR_WRITE(FRCTL, 0); + + /* Reset the chip */ + tmp = ADM8211_CSR_READ(PAR); + ADM8211_CSR_WRITE(PAR, ADM8211_PAR_SWR); + + while ((ADM8211_CSR_READ(PAR) & ADM8211_PAR_SWR) && timeout--) + msleep(50); + + if (timeout <= 0) + return -ETIMEDOUT; + + ADM8211_CSR_WRITE(PAR, tmp); + + if (priv->revid == ADM8211_REV_BA && + (priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || + priv->transceiver_type == ADM8211_RFMD2958)) { + reg = ADM8211_CSR_READ(CSR_TEST1); + reg |= (1 << 4) | (1 << 5); + ADM8211_CSR_WRITE(CSR_TEST1, reg); + } else if (priv->revid == ADM8211_REV_CA) { + reg = ADM8211_CSR_READ(CSR_TEST1); + reg &= ~((1 << 4) | (1 << 5)); + ADM8211_CSR_WRITE(CSR_TEST1, reg); + } + + ADM8211_CSR_WRITE(FRCTL, 0); + + reg = ADM8211_CSR_READ(CSR_TEST0); + reg |= ADM8211_CSR_TEST0_EPRLD; /* EEPROM Recall */ + ADM8211_CSR_WRITE(CSR_TEST0, reg); + + adm8211_clear_sram(dev); + + return 0; +} + +static u64 adm8211_get_tsft(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 tsftl; + u64 tsft; + + tsftl = ADM8211_CSR_READ(TSFTL); + tsft = ADM8211_CSR_READ(TSFTH); + tsft <<= 32; + tsft |= tsftl; + + return tsft; +} + +static void adm8211_set_interval(struct ieee80211_hw *dev, + unsigned short bi, unsigned short li) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + + /* BP (beacon interval) = data->beacon_interval + * LI (listen interval) = data->listen_interval (in beacon intervals) */ + reg = (bi << 16) | li; + ADM8211_CSR_WRITE(BPLI, reg); +} + +static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + + reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24); + ADM8211_CSR_WRITE(BSSID0, reg); + reg = ADM8211_CSR_READ(ABDA1); + reg &= 0x0000ffff; + reg |= (bssid[4] << 16) | (bssid[5] << 24); + ADM8211_CSR_WRITE(ABDA1, reg); +} + +static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) +{ + struct adm8211_priv *priv = dev->priv; + u8 buf[36]; + + if (ssid_len > 32) + return -EINVAL; + + memset(buf, 0, sizeof(buf)); + buf[0] = ssid_len; + memcpy(buf + 1, ssid, ssid_len); + adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33); + /* TODO: configure beacon for adhoc? */ + return 0; +} + +static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +{ + struct adm8211_priv *priv = dev->priv; + + if (conf->channel != priv->channel) { + priv->channel = conf->channel; + adm8211_rf_set_channel(dev, priv->channel); + } + + return 0; +} + +static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id, + struct ieee80211_if_conf *conf) +{ + struct adm8211_priv *priv = dev->priv; + + if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { + adm8211_set_bssid(dev, conf->bssid); + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + } + + if (conf->ssid_len != priv->ssid_len || + memcmp(conf->ssid, priv->ssid, conf->ssid_len)) { + adm8211_set_ssid(dev, conf->ssid, conf->ssid_len); + priv->ssid_len = conf->ssid_len; + memcpy(priv->ssid, conf->ssid, conf->ssid_len); + } + + return 0; +} + +static int adm8211_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct adm8211_priv *priv = dev->priv; + /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ + if (priv->mode != IEEE80211_IF_TYPE_MGMT) + return -1; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + priv->mac_addr = conf->mac_addr; + + return 0; +} + +static void adm8211_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct adm8211_priv *priv = dev->priv; + priv->mode = IEEE80211_IF_TYPE_MGMT; +} + +static int adm8211_init_rings(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + struct adm8211_desc *desc = NULL; + struct adm8211_rx_ring_info *rx_info; + struct adm8211_tx_ring_info *tx_info; + unsigned int i; + + for (i = 0; i < priv->rx_ring_size; i++) { + desc = &priv->rx_ring[i]; + desc->status = 0; + desc->length = cpu_to_le32(RX_PKT_SIZE); + priv->rx_buffers[i].skb = NULL; + } + /* Mark the end of RX ring; hw returns to base address after this + * descriptor */ + desc->length |= cpu_to_le32(RDES1_CONTROL_RER); + + for (i = 0; i < priv->rx_ring_size; i++) { + desc = &priv->rx_ring[i]; + rx_info = &priv->rx_buffers[i]; + + rx_info->skb = dev_alloc_skb(RX_PKT_SIZE); + if (rx_info->skb == NULL) + break; + rx_info->mapping = pci_map_single(priv->pdev, + skb_tail_pointer(rx_info->skb), + RX_PKT_SIZE, + PCI_DMA_FROMDEVICE); + desc->buffer1 = cpu_to_le32(rx_info->mapping); + desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL); + } + + /* Setup TX ring. TX buffers descriptors will be filled in as needed */ + for (i = 0; i < priv->tx_ring_size; i++) { + desc = &priv->tx_ring[i]; + tx_info = &priv->tx_buffers[i]; + + tx_info->skb = NULL; + tx_info->mapping = 0; + desc->status = 0; + } + desc->length = cpu_to_le32(TDES1_CONTROL_TER); + + priv->cur_rx = priv->cur_tx = priv->dirty_tx = 0; + ADM8211_CSR_WRITE(RDB, priv->rx_ring_dma); + ADM8211_CSR_WRITE(TDBD, priv->tx_ring_dma); + + return 0; +} + +static void adm8211_free_rings(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int i; + + for (i = 0; i < priv->rx_ring_size; i++) { + if (!priv->rx_buffers[i].skb) + continue; + + pci_unmap_single( + priv->pdev, + priv->rx_buffers[i].mapping, + RX_PKT_SIZE, PCI_DMA_FROMDEVICE); + + dev_kfree_skb(priv->rx_buffers[i].skb); + } + + for (i = 0; i < priv->tx_ring_size; i++) { + if (!priv->tx_buffers[i].skb) + continue; + + pci_unmap_single(priv->pdev, + priv->tx_buffers[i].mapping, + priv->tx_buffers[i].skb->len, + PCI_DMA_TODEVICE); + + dev_kfree_skb(priv->tx_buffers[i].skb); + } +} + +static int adm8211_open(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + int retval; + + /* Power up MAC and RF chips */ + retval = adm8211_hw_reset(dev); + if (retval) { + printk(KERN_ERR "%s: hardware reset failed\n", + wiphy_name(dev->wiphy)); + goto fail; + } + + retval = adm8211_init_rings(dev); + if (retval) { + printk(KERN_ERR "%s: failed to initialize rings\n", + wiphy_name(dev->wiphy)); + goto fail; + } + + /* Init hardware */ + adm8211_hw_init(dev); + adm8211_rf_set_channel(dev, priv->channel); + + retval = request_irq(priv->pdev->irq, &adm8211_interrupt, + IRQF_SHARED, "adm8211", dev); + if (retval) { + printk(KERN_ERR "%s: failed to register IRQ handler\n", + wiphy_name(dev->wiphy)); + goto fail; + } + + ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | + ADM8211_IER_RCIE | ADM8211_IER_TCIE | + ADM8211_IER_TDUIE | ADM8211_IER_GPTIE); + adm8211_update_mode(dev); + ADM8211_CSR_WRITE(RDR, 0); + + adm8211_set_interval(dev, 100, 10); + return 0; + +fail: + return retval; +} + +static int adm8211_stop(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + + priv->nar = 0; + ADM8211_CSR_WRITE(NAR, 0); + ADM8211_CSR_WRITE(IER, 0); + ADM8211_CSR_READ(NAR); + + free_irq(priv->pdev->irq, dev); + + adm8211_free_rings(dev); + return 0; +} + +static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len, + int plcp_signal, int short_preamble) +{ + /* Alternative calculation from NetBSD: */ + +/* IEEE 802.11b durations for DSSS PHY in microseconds */ +#define IEEE80211_DUR_DS_LONG_PREAMBLE 144 +#define IEEE80211_DUR_DS_SHORT_PREAMBLE 72 +#define IEEE80211_DUR_DS_FAST_PLCPHDR 24 +#define IEEE80211_DUR_DS_SLOW_PLCPHDR 48 +#define IEEE80211_DUR_DS_SLOW_ACK 112 +#define IEEE80211_DUR_DS_FAST_ACK 56 +#define IEEE80211_DUR_DS_SLOW_CTS 112 +#define IEEE80211_DUR_DS_FAST_CTS 56 +#define IEEE80211_DUR_DS_SLOT 20 +#define IEEE80211_DUR_DS_SIFS 10 + + int remainder; + + *dur = (80 * (24 + payload_len) + plcp_signal - 1) + / plcp_signal; + + if (plcp_signal <= PLCP_SIGNAL_2M) + /* 1-2Mbps WLAN: send ACK/CTS at 1Mbps */ + *dur += 3 * (IEEE80211_DUR_DS_SIFS + + IEEE80211_DUR_DS_SHORT_PREAMBLE + + IEEE80211_DUR_DS_FAST_PLCPHDR) + + IEEE80211_DUR_DS_SLOW_CTS + IEEE80211_DUR_DS_SLOW_ACK; + else + /* 5-11Mbps WLAN: send ACK/CTS at 2Mbps */ + *dur += 3 * (IEEE80211_DUR_DS_SIFS + + IEEE80211_DUR_DS_SHORT_PREAMBLE + + IEEE80211_DUR_DS_FAST_PLCPHDR) + + IEEE80211_DUR_DS_FAST_CTS + IEEE80211_DUR_DS_FAST_ACK; + + /* lengthen duration if long preamble */ + if (!short_preamble) + *dur += 3 * (IEEE80211_DUR_DS_LONG_PREAMBLE - + IEEE80211_DUR_DS_SHORT_PREAMBLE) + + 3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR - + IEEE80211_DUR_DS_FAST_PLCPHDR); + + + *plcp = (80 * len) / plcp_signal; + remainder = (80 * len) % plcp_signal; + if (plcp_signal == PLCP_SIGNAL_11M && + remainder <= 30 && remainder > 0) + *plcp = (*plcp | 0x8000) + 1; + else if (remainder) + (*plcp)++; +} + +/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */ +static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, + u16 plcp_signal, + struct ieee80211_tx_control *control, + size_t hdrlen) +{ + struct adm8211_priv *priv = dev->priv; + unsigned long flags; + dma_addr_t mapping; + unsigned int entry; + u32 flag; + + mapping = pci_map_single(priv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2) + flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS; + else + flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS; + + if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size - 2) + ieee80211_stop_queue(dev, 0); + + entry = priv->cur_tx % priv->tx_ring_size; + + priv->tx_buffers[entry].skb = skb; + priv->tx_buffers[entry].mapping = mapping; + memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control)); + priv->tx_buffers[entry].hdrlen = hdrlen; + priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping); + + if (entry == priv->tx_ring_size - 1) + flag |= TDES1_CONTROL_TER; + priv->tx_ring[entry].length = cpu_to_le32(flag | skb->len); + + /* Set TX rate (SIGNAL field in PLCP PPDU format) */ + flag = TDES0_CONTROL_OWN | (plcp_signal << 20) | 8 /* ? */; + priv->tx_ring[entry].status = cpu_to_le32(flag); + + priv->cur_tx++; + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Trigger transmit poll */ + ADM8211_CSR_WRITE(TDR, 0); +} + +/* Put adm8211_tx_hdr on skb and transmit */ +static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct adm8211_tx_hdr *txhdr; + u16 fc; + size_t payload_len, hdrlen; + int plcp, dur, len, plcp_signal, short_preamble; + struct ieee80211_hdr *hdr; + + if (control->tx_rate < 0) { + short_preamble = 1; + plcp_signal = -control->tx_rate; + } else { + short_preamble = 0; + plcp_signal = control->tx_rate; + } + + hdr = (struct ieee80211_hdr *)skb->data; + fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED; + hdrlen = ieee80211_get_hdrlen(fc); + memcpy(skb->cb, skb->data, hdrlen); + hdr = (struct ieee80211_hdr *)skb->cb; + skb_pull(skb, hdrlen); + payload_len = skb->len; + + txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr)); + memset(txhdr, 0, sizeof(*txhdr)); + memcpy(txhdr->da, ieee80211_get_DA(hdr), ETH_ALEN); + txhdr->signal = plcp_signal; + txhdr->frame_body_size = cpu_to_le16(payload_len); + txhdr->frame_control = hdr->frame_control; + + len = hdrlen + payload_len + FCS_LEN; + if (fc & IEEE80211_FCTL_PROTECTED) + len += 8; + + txhdr->frag = cpu_to_le16(0x0FFF); + adm8211_calc_durations(&dur, &plcp, payload_len, + len, plcp_signal, short_preamble); + txhdr->plcp_frag_head_len = cpu_to_le16(plcp); + txhdr->plcp_frag_tail_len = cpu_to_le16(plcp); + txhdr->dur_frag_head = cpu_to_le16(dur); + txhdr->dur_frag_tail = cpu_to_le16(dur); + + txhdr->header_control = cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER); + + if (short_preamble) + txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); + + if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); + + if (fc & IEEE80211_FCTL_PROTECTED) + txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE); + + txhdr->retry_limit = control->retry_limit; + + adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen); + + return NETDEV_TX_OK; +} + +static int adm8211_alloc_rings(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int ring_size; + + priv->rx_buffers = kmalloc(sizeof(*priv->rx_buffers) * priv->rx_ring_size + + sizeof(*priv->tx_buffers) * priv->tx_ring_size, GFP_KERNEL); + if (!priv->rx_buffers) + return -ENOMEM; + + priv->tx_buffers = (void *)priv->rx_buffers + + sizeof(*priv->rx_buffers) * priv->rx_ring_size; + + /* Allocate TX/RX descriptors */ + ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size + + sizeof(struct adm8211_desc) * priv->tx_ring_size; + priv->rx_ring = pci_alloc_consistent(priv->pdev, ring_size, + &priv->rx_ring_dma); + + if (!priv->rx_ring) { + kfree(priv->rx_buffers); + priv->rx_buffers = NULL; + priv->tx_buffers = NULL; + return -ENOMEM; + } + + priv->tx_ring = (struct adm8211_desc *)(priv->rx_ring + + priv->rx_ring_size); + priv->tx_ring_dma = priv->rx_ring_dma + + sizeof(struct adm8211_desc) * priv->rx_ring_size; + + return 0; +} + +static const struct ieee80211_ops adm8211_ops = { + .tx = adm8211_tx, + .open = adm8211_open, + .stop = adm8211_stop, + .add_interface = adm8211_add_interface, + .remove_interface = adm8211_remove_interface, + .config = adm8211_config, + .config_interface = adm8211_config_interface, + .set_multicast_list = adm8211_set_rx_mode, + .get_stats = adm8211_get_stats, + .get_tx_stats = adm8211_get_tx_stats, + .get_tsf = adm8211_get_tsft +}; + +static int __devinit adm8211_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ieee80211_hw *dev; + struct adm8211_priv *priv; + unsigned long mem_addr, mem_len; + unsigned int io_addr, io_len; + int err; + u32 reg; + u8 perm_addr[ETH_ALEN]; + +#ifndef MODULE + static unsigned int cardidx; + if (!cardidx++) + printk(version); +#endif + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n", + pci_name(pdev)); + return err; + } + + io_addr = pci_resource_start(pdev, 0); + io_len = pci_resource_len(pdev, 0); + mem_addr = pci_resource_start(pdev, 1); + mem_len = pci_resource_len(pdev, 1); + if (io_len < 256 || mem_len < 1024) { + printk(KERN_ERR "%s (adm8211): Too short PCI resources\n", + pci_name(pdev)); + goto err_disable_pdev; + } + + + /* check signature */ + pci_read_config_dword(pdev, 0x80 /* CR32 */, ®); + if (reg != ADM8211_SIG1 && reg != ADM8211_SIG2) { + printk(KERN_ERR "%s (adm8211): Invalid signature (0x%x)\n", + pci_name(pdev), reg); + goto err_disable_pdev; + } + + err = pci_request_regions(pdev, "adm8211"); + if (err) { + printk(KERN_ERR "%s (adm8211): Cannot obtain PCI resources\n", + pci_name(pdev)); + return err; /* someone else grabbed it? don't disable it */ + } + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || + pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR "%s (adm8211): No suitable DMA available\n", + pci_name(pdev)); + goto err_free_reg; + } + + pci_set_master(pdev); + + dev = ieee80211_alloc_hw(sizeof(*priv), &adm8211_ops); + if (!dev) { + printk(KERN_ERR "%s (adm8211): ieee80211 alloc failed\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + priv = dev->priv; + priv->pdev = pdev; + + spin_lock_init(&priv->lock); + + SET_IEEE80211_DEV(dev, &pdev->dev); + + pci_set_drvdata(pdev, dev); + + priv->map = pci_iomap(pdev, 1, mem_len); + if (!priv->map) + priv->map = pci_iomap(pdev, 0, io_len); + + if (!priv->map) { + printk(KERN_ERR "%s (adm8211): Cannot map device memory\n", + pci_name(pdev)); + goto err_free_dev; + } + + priv->rx_ring_size = rx_ring_size; + priv->tx_ring_size = tx_ring_size; + + if (adm8211_alloc_rings(dev)) { + printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n", + pci_name(pdev)); + goto err_iounmap; + } + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &priv->revid); + + *(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0)); + *(u16 *)&perm_addr[4] = + le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF); + + if (!is_valid_ether_addr(perm_addr)) { + printk(KERN_WARNING "%s (adm8211): Invalid hwaddr in EEPROM!\n", + pci_name(pdev)); + random_ether_addr(perm_addr); + } + SET_IEEE80211_PERM_ADDR(dev, perm_addr); + + dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); + dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED; + /* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ + + dev->channel_change_time = 1000; + dev->max_rssi = 100; /* FIXME: find better value */ + + priv->modes[0].mode = MODE_IEEE80211B; + /* channel info filled in by adm8211_read_eeprom */ + memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates)); + priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates); + priv->modes[0].rates = priv->rates; + + dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */ + + priv->retry_limit = 3; + priv->ant_power = 0x40; + priv->tx_power = 0x40; + priv->lpf_cutoff = 0xFF; + priv->lnags_threshold = 0xFF; + priv->mode = IEEE80211_IF_TYPE_MGMT; + + /* Power-on issue. EEPROM won't read correctly without */ + if (priv->revid >= ADM8211_REV_BA) { + ADM8211_CSR_WRITE(FRCTL, 0); + ADM8211_CSR_READ(FRCTL); + ADM8211_CSR_WRITE(FRCTL, 1); + ADM8211_CSR_READ(FRCTL); + msleep(100); + } + + err = adm8211_read_eeprom(dev); + if (err) { + printk(KERN_ERR "%s (adm8211): Can't alloc eeprom buffer\n", + pci_name(pdev)); + goto err_free_desc; + } + + priv->channel = priv->modes[0].channels[0].chan; + + err = ieee80211_register_hwmode(dev, &priv->modes[0]); + if (err) { + printk(KERN_ERR "%s (adm8211): Can't register hwmode\n", + pci_name(pdev)); + goto err_free_desc; + } + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "%s (adm8211): Cannot register device\n", + pci_name(pdev)); + goto err_free_desc; + } + + printk(KERN_INFO "%s: hwaddr " MAC_FMT ", Rev 0x%02x\n", + wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), + priv->revid); + + return 0; + + err_free_desc: + pci_free_consistent(pdev, + sizeof(struct adm8211_desc) * priv->rx_ring_size + + sizeof(struct adm8211_desc) * priv->tx_ring_size, + priv->rx_ring, priv->rx_ring_dma); + kfree(priv->rx_buffers); + + err_iounmap: + pci_iounmap(pdev, priv->map); + + err_free_dev: + pci_set_drvdata(pdev, NULL); + ieee80211_free_hw(dev); + + err_free_reg: + pci_release_regions(pdev); + + err_disable_pdev: + pci_disable_device(pdev); + return err; +} + + +static void __devexit adm8211_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct adm8211_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + + pci_free_consistent(pdev, + sizeof(struct adm8211_desc) * priv->rx_ring_size + + sizeof(struct adm8211_desc) * priv->tx_ring_size, + priv->rx_ring, priv->rx_ring_dma); + + kfree(priv->rx_buffers); + kfree(priv->eeprom); + pci_iounmap(pdev, priv->map); + pci_release_regions(pdev); + pci_disable_device(pdev); + ieee80211_free_hw(dev); +} + + +#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 != IEEE80211_IF_TYPE_MGMT) { + ieee80211_stop_queues(dev); + adm8211_stop(dev); + } + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +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 != IEEE80211_IF_TYPE_MGMT) { + adm8211_open(dev); + ieee80211_start_queues(dev); + } + + return 0; +} +#endif /* CONFIG_PM */ + + +MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table); + +/* TODO: implement enable_wake */ +static struct pci_driver adm8211_driver = { + .name = "adm8211", + .id_table = adm8211_pci_id_table, + .probe = adm8211_probe, + .remove = __devexit_p(adm8211_remove), +#ifdef CONFIG_PM + .suspend = adm8211_suspend, + .resume = adm8211_resume, +#endif /* CONFIG_PM */ +}; + + + +static int __init adm8211_init(void) +{ +#ifdef MODULE + printk(version); +#endif + + return pci_register_driver(&adm8211_driver); +} + + +static void __exit adm8211_exit(void) +{ + pci_unregister_driver(&adm8211_driver); +} + + +module_init(adm8211_init); +module_exit(adm8211_exit); diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h new file mode 100644 index 000000000000..795d895f5c99 --- /dev/null +++ b/drivers/net/wireless/adm8211.h @@ -0,0 +1,659 @@ +#ifndef ADM8211_H +#define ADM8211_H + +/* ADM8211 Registers */ + +/* CR32 (SIG) signature */ +#define ADM8211_SIG1 0x82011317 /* ADM8211A */ +#define ADM8211_SIG2 0x82111317 /* ADM8211B/ADM8211C */ + +#define ADM8211_CSR_READ(r) ioread32(&priv->map->r) +#define ADM8211_CSR_WRITE(r, val) iowrite32((val), &priv->map->r) + +/* CSR (Host Control and Status Registers) */ +struct adm8211_csr { + __le32 PAR; /* 0x00 CSR0 */ + __le32 FRCTL; /* 0x04 CSR0A */ + __le32 TDR; /* 0x08 CSR1 */ + __le32 WTDP; /* 0x0C CSR1A */ + __le32 RDR; /* 0x10 CSR2 */ + __le32 WRDP; /* 0x14 CSR2A */ + __le32 RDB; /* 0x18 CSR3 */ + __le32 TDBH; /* 0x1C CSR3A */ + __le32 TDBD; /* 0x20 CSR4 */ + __le32 TDBP; /* 0x24 CSR4A */ + __le32 STSR; /* 0x28 CSR5 */ + __le32 TDBB; /* 0x2C CSR5A */ + __le32 NAR; /* 0x30 CSR6 */ + __le32 CSR6A; /* reserved */ + __le32 IER; /* 0x38 CSR7 */ + __le32 TKIPSCEP; /* 0x3C CSR7A */ + __le32 LPC; /* 0x40 CSR8 */ + __le32 CSR_TEST1; /* 0x44 CSR8A */ + __le32 SPR; /* 0x48 CSR9 */ + __le32 CSR_TEST0; /* 0x4C CSR9A */ + __le32 WCSR; /* 0x50 CSR10 */ + __le32 WPDR; /* 0x54 CSR10A */ + __le32 GPTMR; /* 0x58 CSR11 */ + __le32 GPIO; /* 0x5C CSR11A */ + __le32 BBPCTL; /* 0x60 CSR12 */ + __le32 SYNCTL; /* 0x64 CSR12A */ + __le32 PLCPHD; /* 0x68 CSR13 */ + __le32 MMIWA; /* 0x6C CSR13A */ + __le32 MMIRD0; /* 0x70 CSR14 */ + __le32 MMIRD1; /* 0x74 CSR14A */ + __le32 TXBR; /* 0x78 CSR15 */ + __le32 SYNDATA; /* 0x7C CSR15A */ + __le32 ALCS; /* 0x80 CSR16 */ + __le32 TOFS2; /* 0x84 CSR17 */ + __le32 CMDR; /* 0x88 CSR18 */ + __le32 PCIC; /* 0x8C CSR19 */ + __le32 PMCSR; /* 0x90 CSR20 */ + __le32 PAR0; /* 0x94 CSR21 */ + __le32 PAR1; /* 0x98 CSR22 */ + __le32 MAR0; /* 0x9C CSR23 */ + __le32 MAR1; /* 0xA0 CSR24 */ + __le32 ATIMDA0; /* 0xA4 CSR25 */ + __le32 ABDA1; /* 0xA8 CSR26 */ + __le32 BSSID0; /* 0xAC CSR27 */ + __le32 TXLMT; /* 0xB0 CSR28 */ + __le32 MIBCNT; /* 0xB4 CSR29 */ + __le32 BCNT; /* 0xB8 CSR30 */ + __le32 TSFTH; /* 0xBC CSR31 */ + __le32 TSC; /* 0xC0 CSR32 */ + __le32 SYNRF; /* 0xC4 CSR33 */ + __le32 BPLI; /* 0xC8 CSR34 */ + __le32 CAP0; /* 0xCC CSR35 */ + __le32 CAP1; /* 0xD0 CSR36 */ + __le32 RMD; /* 0xD4 CSR37 */ + __le32 CFPP; /* 0xD8 CSR38 */ + __le32 TOFS0; /* 0xDC CSR39 */ + __le32 TOFS1; /* 0xE0 CSR40 */ + __le32 IFST; /* 0xE4 CSR41 */ + __le32 RSPT; /* 0xE8 CSR42 */ + __le32 TSFTL; /* 0xEC CSR43 */ + __le32 WEPCTL; /* 0xF0 CSR44 */ + __le32 WESK; /* 0xF4 CSR45 */ + __le32 WEPCNT; /* 0xF8 CSR46 */ + __le32 MACTEST; /* 0xFC CSR47 */ + __le32 FER; /* 0x100 */ + __le32 FEMR; /* 0x104 */ + __le32 FPSR; /* 0x108 */ + __le32 FFER; /* 0x10C */ +} __attribute__ ((packed)); + +/* CSR0 - PAR (PCI Address Register) */ +#define ADM8211_PAR_MWIE (1 << 24) +#define ADM8211_PAR_MRLE (1 << 23) +#define ADM8211_PAR_MRME (1 << 21) +#define ADM8211_PAR_RAP ((1 << 18) | (1 << 17)) +#define ADM8211_PAR_CAL ((1 << 15) | (1 << 14)) +#define ADM8211_PAR_PBL 0x00003f00 +#define ADM8211_PAR_BLE (1 << 7) +#define ADM8211_PAR_DSL 0x0000007c +#define ADM8211_PAR_BAR (1 << 1) +#define ADM8211_PAR_SWR (1 << 0) + +/* CSR1 - FRCTL (Frame Control Register) */ +#define ADM8211_FRCTL_PWRMGT (1 << 31) +#define ADM8211_FRCTL_MAXPSP (1 << 27) +#define ADM8211_FRCTL_DRVPRSP (1 << 26) +#define ADM8211_FRCTL_DRVBCON (1 << 25) +#define ADM8211_FRCTL_AID 0x0000ffff +#define ADM8211_FRCTL_AID_ON 0x0000c000 + +/* CSR5 - STSR (Status Register) */ +#define ADM8211_STSR_PCF (1 << 31) +#define ADM8211_STSR_BCNTC (1 << 30) +#define ADM8211_STSR_GPINT (1 << 29) +#define ADM8211_STSR_LinkOff (1 << 28) +#define ADM8211_STSR_ATIMTC (1 << 27) +#define ADM8211_STSR_TSFTF (1 << 26) +#define ADM8211_STSR_TSCZ (1 << 25) +#define ADM8211_STSR_LinkOn (1 << 24) +#define ADM8211_STSR_SQL (1 << 23) +#define ADM8211_STSR_WEPTD (1 << 22) +#define ADM8211_STSR_ATIME (1 << 21) +#define ADM8211_STSR_TBTT (1 << 20) +#define ADM8211_STSR_NISS (1 << 16) +#define ADM8211_STSR_AISS (1 << 15) +#define ADM8211_STSR_TEIS (1 << 14) +#define ADM8211_STSR_FBE (1 << 13) +#define ADM8211_STSR_REIS (1 << 12) +#define ADM8211_STSR_GPTT (1 << 11) +#define ADM8211_STSR_RPS (1 << 8) +#define ADM8211_STSR_RDU (1 << 7) +#define ADM8211_STSR_RCI (1 << 6) +#define ADM8211_STSR_TUF (1 << 5) +#define ADM8211_STSR_TRT (1 << 4) +#define ADM8211_STSR_TLT (1 << 3) +#define ADM8211_STSR_TDU (1 << 2) +#define ADM8211_STSR_TPS (1 << 1) +#define ADM8211_STSR_TCI (1 << 0) + +/* CSR6 - NAR (Network Access Register) */ +#define ADM8211_NAR_TXCF (1 << 31) +#define ADM8211_NAR_HF (1 << 30) +#define ADM8211_NAR_UTR (1 << 29) +#define ADM8211_NAR_SQ (1 << 28) +#define ADM8211_NAR_CFP (1 << 27) +#define ADM8211_NAR_SF (1 << 21) +#define ADM8211_NAR_TR ((1 << 15) | (1 << 14)) +#define ADM8211_NAR_ST (1 << 13) +#define ADM8211_NAR_OM ((1 << 11) | (1 << 10)) +#define ADM8211_NAR_MM (1 << 7) +#define ADM8211_NAR_PR (1 << 6) +#define ADM8211_NAR_EA (1 << 5) +#define ADM8211_NAR_PB (1 << 3) +#define ADM8211_NAR_STPDMA (1 << 2) +#define ADM8211_NAR_SR (1 << 1) +#define ADM8211_NAR_CTX (1 << 0) + +#define ADM8211_IDLE() \ +do { \ + if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) { \ + ADM8211_CSR_WRITE(NAR, priv->nar & \ + ~(ADM8211_NAR_SR | ADM8211_NAR_ST));\ + ADM8211_CSR_READ(NAR); \ + msleep(20); \ + } \ +} while (0) + +#define ADM8211_IDLE_RX() \ +do { \ + if (priv->nar & ADM8211_NAR_SR) { \ + ADM8211_CSR_WRITE(NAR, priv->nar & ~ADM8211_NAR_SR); \ + ADM8211_CSR_READ(NAR); \ + mdelay(20); \ + } \ +} while (0) + +#define ADM8211_RESTORE() \ +do { \ + if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) \ + ADM8211_CSR_WRITE(NAR, priv->nar); \ +} while (0) + +/* CSR7 - IER (Interrupt Enable Register) */ +#define ADM8211_IER_PCFIE (1 << 31) +#define ADM8211_IER_BCNTCIE (1 << 30) +#define ADM8211_IER_GPIE (1 << 29) +#define ADM8211_IER_LinkOffIE (1 << 28) +#define ADM8211_IER_ATIMTCIE (1 << 27) +#define ADM8211_IER_TSFTFIE (1 << 26) +#define ADM8211_IER_TSCZE (1 << 25) +#define ADM8211_IER_LinkOnIE (1 << 24) +#define ADM8211_IER_SQLIE (1 << 23) +#define ADM8211_IER_WEPIE (1 << 22) +#define ADM8211_IER_ATIMEIE (1 << 21) +#define ADM8211_IER_TBTTIE (1 << 20) +#define ADM8211_IER_NIE (1 << 16) +#define ADM8211_IER_AIE (1 << 15) +#define ADM8211_IER_TEIE (1 << 14) +#define ADM8211_IER_FBEIE (1 << 13) +#define ADM8211_IER_REIE (1 << 12) +#define ADM8211_IER_GPTIE (1 << 11) +#define ADM8211_IER_RSIE (1 << 8) +#define ADM8211_IER_RUIE (1 << 7) +#define ADM8211_IER_RCIE (1 << 6) +#define ADM8211_IER_TUIE (1 << 5) +#define ADM8211_IER_TRTIE (1 << 4) +#define ADM8211_IER_TLTTIE (1 << 3) +#define ADM8211_IER_TDUIE (1 << 2) +#define ADM8211_IER_TPSIE (1 << 1) +#define ADM8211_IER_TCIE (1 << 0) + +/* CSR9 - SPR (Serial Port Register) */ +#define ADM8211_SPR_SRS (1 << 11) +#define ADM8211_SPR_SDO (1 << 3) +#define ADM8211_SPR_SDI (1 << 2) +#define ADM8211_SPR_SCLK (1 << 1) +#define ADM8211_SPR_SCS (1 << 0) + +/* CSR9A - CSR_TEST0 */ +#define ADM8211_CSR_TEST0_EPNE (1 << 18) +#define ADM8211_CSR_TEST0_EPSNM (1 << 17) +#define ADM8211_CSR_TEST0_EPTYP (1 << 16) +#define ADM8211_CSR_TEST0_EPRLD (1 << 15) + +/* CSR10 - WCSR (Wake-up Control/Status Register) */ +#define ADM8211_WCSR_CRCT (1 << 30) +#define ADM8211_WCSR_TSFTWE (1 << 20) +#define ADM8211_WCSR_TIMWE (1 << 19) +#define ADM8211_WCSR_ATIMWE (1 << 18) +#define ADM8211_WCSR_KEYWE (1 << 17) +#define ADM8211_WCSR_MPRE (1 << 9) +#define ADM8211_WCSR_LSOE (1 << 8) +#define ADM8211_WCSR_KEYUP (1 << 6) +#define ADM8211_WCSR_TSFTW (1 << 5) +#define ADM8211_WCSR_TIMW (1 << 4) +#define ADM8211_WCSR_ATIMW (1 << 3) +#define ADM8211_WCSR_MPR (1 << 1) +#define ADM8211_WCSR_LSO (1 << 0) + +/* CSR11A - GPIO */ +#define ADM8211_CSR_GPIO_EN5 (1 << 17) +#define ADM8211_CSR_GPIO_EN4 (1 << 16) +#define ADM8211_CSR_GPIO_EN3 (1 << 15) +#define ADM8211_CSR_GPIO_EN2 (1 << 14) +#define ADM8211_CSR_GPIO_EN1 (1 << 13) +#define ADM8211_CSR_GPIO_EN0 (1 << 12) +#define ADM8211_CSR_GPIO_O5 (1 << 11) +#define ADM8211_CSR_GPIO_O4 (1 << 10) +#define ADM8211_CSR_GPIO_O3 (1 << 9) +#define ADM8211_CSR_GPIO_O2 (1 << 8) +#define ADM8211_CSR_GPIO_O1 (1 << 7) +#define ADM8211_CSR_GPIO_O0 (1 << 6) +#define ADM8211_CSR_GPIO_IN 0x0000003f + +/* CSR12 - BBPCTL (BBP Control port) */ +#define ADM8211_BBPCTL_MMISEL (1 << 31) +#define ADM8211_BBPCTL_SPICADD (0x7F << 24) +#define ADM8211_BBPCTL_RF3000 (0x20 << 24) +#define ADM8211_BBPCTL_TXCE (1 << 23) +#define ADM8211_BBPCTL_RXCE (1 << 22) +#define ADM8211_BBPCTL_CCAP (1 << 21) +#define ADM8211_BBPCTL_TYPE 0x001c0000 +#define ADM8211_BBPCTL_WR (1 << 17) +#define ADM8211_BBPCTL_RD (1 << 16) +#define ADM8211_BBPCTL_ADDR 0x0000ff00 +#define ADM8211_BBPCTL_DATA 0x000000ff + +/* CSR12A - SYNCTL (Synthesizer Control port) */ +#define ADM8211_SYNCTL_WR (1 << 31) +#define ADM8211_SYNCTL_RD (1 << 30) +#define ADM8211_SYNCTL_CS0 (1 << 29) +#define ADM8211_SYNCTL_CS1 (1 << 28) +#define ADM8211_SYNCTL_CAL (1 << 27) +#define ADM8211_SYNCTL_SELCAL (1 << 26) +#define ADM8211_SYNCTL_RFtype ((1 << 24) || (1 << 23) || (1 << 22)) +#define ADM8211_SYNCTL_RFMD (1 << 22) +#define ADM8211_SYNCTL_GENERAL (0x7 << 22) +/* SYNCTL 21:0 Data (Si4126: 18-bit data, 4-bit address) */ + +/* CSR18 - CMDR (Command Register) */ +#define ADM8211_CMDR_PM (1 << 19) +#define ADM8211_CMDR_APM (1 << 18) +#define ADM8211_CMDR_RTE (1 << 4) +#define ADM8211_CMDR_DRT ((1 << 3) | (1 << 2)) +#define ADM8211_CMDR_DRT_8DW (0x0 << 2) +#define ADM8211_CMDR_DRT_16DW (0x1 << 2) +#define ADM8211_CMDR_DRT_SF (0x2 << 2) + +/* CSR33 - SYNRF (SYNRF direct control) */ +#define ADM8211_SYNRF_SELSYN (1 << 31) +#define ADM8211_SYNRF_SELRF (1 << 30) +#define ADM8211_SYNRF_LERF (1 << 29) +#define ADM8211_SYNRF_LEIF (1 << 28) +#define ADM8211_SYNRF_SYNCLK (1 << 27) +#define ADM8211_SYNRF_SYNDATA (1 << 26) +#define ADM8211_SYNRF_PE1 (1 << 25) +#define ADM8211_SYNRF_PE2 (1 << 24) +#define ADM8211_SYNRF_PA_PE (1 << 23) +#define ADM8211_SYNRF_TR_SW (1 << 22) +#define ADM8211_SYNRF_TR_SWN (1 << 21) +#define ADM8211_SYNRF_RADIO (1 << 20) +#define ADM8211_SYNRF_CAL_EN (1 << 19) +#define ADM8211_SYNRF_PHYRST (1 << 18) + +#define ADM8211_SYNRF_IF_SELECT_0 (1 << 31) +#define ADM8211_SYNRF_IF_SELECT_1 ((1 << 31) | (1 << 28)) +#define ADM8211_SYNRF_WRITE_SYNDATA_0 (1 << 31) +#define ADM8211_SYNRF_WRITE_SYNDATA_1 ((1 << 31) | (1 << 26)) +#define ADM8211_SYNRF_WRITE_CLOCK_0 (1 << 31) +#define ADM8211_SYNRF_WRITE_CLOCK_1 ((1 << 31) | (1 << 27)) + +/* CSR44 - WEPCTL (WEP Control) */ +#define ADM8211_WEPCTL_WEPENABLE (1 << 31) +#define ADM8211_WEPCTL_WPAENABLE (1 << 30) +#define ADM8211_WEPCTL_CURRENT_TABLE (1 << 29) +#define ADM8211_WEPCTL_TABLE_WR (1 << 28) +#define ADM8211_WEPCTL_TABLE_RD (1 << 27) +#define ADM8211_WEPCTL_WEPRXBYP (1 << 25) +#define ADM8211_WEPCTL_SEL_WEPTABLE (1 << 23) +#define ADM8211_WEPCTL_ADDR (0x000001ff) + +/* CSR45 - WESK (Data Entry for Share/Individual Key) */ +#define ADM8211_WESK_DATA (0x0000ffff) + +/* FER (Function Event Register) */ +#define ADM8211_FER_INTR_EV_ENT (1 << 15) + + +/* Si4126 RF Synthesizer - Control Registers */ +#define SI4126_MAIN_CONF 0 +#define SI4126_PHASE_DET_GAIN 1 +#define SI4126_POWERDOWN 2 +#define SI4126_RF1_N_DIV 3 /* only Si4136 */ +#define SI4126_RF2_N_DIV 4 +#define SI4126_IF_N_DIV 5 +#define SI4126_RF1_R_DIV 6 /* only Si4136 */ +#define SI4126_RF2_R_DIV 7 +#define SI4126_IF_R_DIV 8 + +/* Main Configuration */ +#define SI4126_MAIN_XINDIV2 (1 << 6) +#define SI4126_MAIN_IFDIV ((1 << 11) | (1 << 10)) +/* Powerdown */ +#define SI4126_POWERDOWN_PDIB (1 << 1) +#define SI4126_POWERDOWN_PDRB (1 << 0) + + +/* RF3000 BBP - Control Port Registers */ +/* 0x00 - reserved */ +#define RF3000_MODEM_CTRL__RX_STATUS 0x01 +#define RF3000_CCA_CTRL 0x02 +#define RF3000_DIVERSITY__RSSI 0x03 +#define RF3000_RX_SIGNAL_FIELD 0x04 +#define RF3000_RX_LEN_MSB 0x05 +#define RF3000_RX_LEN_LSB 0x06 +#define RF3000_RX_SERVICE_FIELD 0x07 +#define RF3000_TX_VAR_GAIN__TX_LEN_EXT 0x11 +#define RF3000_TX_LEN_MSB 0x12 +#define RF3000_TX_LEN_LSB 0x13 +#define RF3000_LOW_GAIN_CALIB 0x14 +#define RF3000_HIGH_GAIN_CALIB 0x15 + +/* ADM8211 revisions */ +#define ADM8211_REV_AB 0x11 +#define ADM8211_REV_AF 0x15 +#define ADM8211_REV_BA 0x20 +#define ADM8211_REV_CA 0x30 + +struct adm8211_desc { + __le32 status; + __le32 length; + __le32 buffer1; + __le32 buffer2; +}; + +#define RDES0_STATUS_OWN (1 << 31) +#define RDES0_STATUS_ES (1 << 30) +#define RDES0_STATUS_SQL (1 << 29) +#define RDES0_STATUS_DE (1 << 28) +#define RDES0_STATUS_FS (1 << 27) +#define RDES0_STATUS_LS (1 << 26) +#define RDES0_STATUS_PCF (1 << 25) +#define RDES0_STATUS_SFDE (1 << 24) +#define RDES0_STATUS_SIGE (1 << 23) +#define RDES0_STATUS_CRC16E (1 << 22) +#define RDES0_STATUS_RXTOE (1 << 21) +#define RDES0_STATUS_CRC32E (1 << 20) +#define RDES0_STATUS_ICVE (1 << 19) +#define RDES0_STATUS_DA1 (1 << 17) +#define RDES0_STATUS_DA0 (1 << 16) +#define RDES0_STATUS_RXDR ((1 << 15) | (1 << 14) | (1 << 13) | (1 << 12)) +#define RDES0_STATUS_FL (0x00000fff) + +#define RDES1_CONTROL_RER (1 << 25) +#define RDES1_CONTROL_RCH (1 << 24) +#define RDES1_CONTROL_RBS2 (0x00fff000) +#define RDES1_CONTROL_RBS1 (0x00000fff) + +#define RDES1_STATUS_RSSI (0x0000007f) + + +#define TDES0_CONTROL_OWN (1 << 31) +#define TDES0_CONTROL_DONE (1 << 30) +#define TDES0_CONTROL_TXDR (0x0ff00000) + +#define TDES0_STATUS_OWN (1 << 31) +#define TDES0_STATUS_DONE (1 << 30) +#define TDES0_STATUS_ES (1 << 29) +#define TDES0_STATUS_TLT (1 << 28) +#define TDES0_STATUS_TRT (1 << 27) +#define TDES0_STATUS_TUF (1 << 26) +#define TDES0_STATUS_TRO (1 << 25) +#define TDES0_STATUS_SOFBR (1 << 24) +#define TDES0_STATUS_ACR (0x00000fff) + +#define TDES1_CONTROL_IC (1 << 31) +#define TDES1_CONTROL_LS (1 << 30) +#define TDES1_CONTROL_FS (1 << 29) +#define TDES1_CONTROL_TER (1 << 25) +#define TDES1_CONTROL_TCH (1 << 24) +#define TDES1_CONTROL_RBS2 (0x00fff000) +#define TDES1_CONTROL_RBS1 (0x00000fff) + +/* SRAM offsets */ +#define ADM8211_SRAM(x) (priv->revid < ADM8211_REV_BA ? \ + ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x) + +#define ADM8211_SRAM_INDIV_KEY 0x0000 +#define ADM8211_SRAM_A_SHARE_KEY 0x0160 +#define ADM8211_SRAM_B_SHARE_KEY 0x00c0 + +#define ADM8211_SRAM_A_SSID 0x0180 +#define ADM8211_SRAM_B_SSID 0x00d4 +#define ADM8211_SRAM_SSID ADM8211_SRAM(SSID) + +#define ADM8211_SRAM_A_SUPP_RATE 0x0191 +#define ADM8211_SRAM_B_SUPP_RATE 0x00dd +#define ADM8211_SRAM_SUPP_RATE ADM8211_SRAM(SUPP_RATE) + +#define ADM8211_SRAM_A_SIZE 0x0200 +#define ADM8211_SRAM_B_SIZE 0x01c0 +#define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE) + +struct adm8211_rx_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct adm8211_tx_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; + struct ieee80211_tx_control tx_control; + size_t hdrlen; +}; + +#define PLCP_SIGNAL_1M 0x0a +#define PLCP_SIGNAL_2M 0x14 +#define PLCP_SIGNAL_5M5 0x37 +#define PLCP_SIGNAL_11M 0x6e + +struct adm8211_tx_hdr { + u8 da[6]; + u8 signal; /* PLCP signal / TX rate in 100 Kbps */ + u8 service; + __le16 frame_body_size; + __le16 frame_control; + __le16 plcp_frag_tail_len; + __le16 plcp_frag_head_len; + __le16 dur_frag_tail; + __le16 dur_frag_head; + u8 addr4[6]; + +#define ADM8211_TXHDRCTL_SHORT_PREAMBLE (1 << 0) +#define ADM8211_TXHDRCTL_MORE_FRAG (1 << 1) +#define ADM8211_TXHDRCTL_MORE_DATA (1 << 2) +#define ADM8211_TXHDRCTL_FRAG_NO (1 << 3) /* ? */ +#define ADM8211_TXHDRCTL_ENABLE_RTS (1 << 4) +#define ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE (1 << 5) +#define ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER (1 << 15) /* ? */ + __le16 header_control; + __le16 frag; + u8 reserved_0; + u8 retry_limit; + + u32 wep2key0; + u32 wep2key1; + u32 wep2key2; + u32 wep2key3; + + u8 keyid; + u8 entry_control; // huh?? + u16 reserved_1; + u32 reserved_2; +} __attribute__ ((packed)); + + +#define RX_COPY_BREAK 128 +#define RX_PKT_SIZE 2500 + +struct adm8211_eeprom { + __le16 signature; /* 0x00 */ + u8 major_version; /* 0x02 */ + u8 minor_version; /* 0x03 */ + u8 reserved_1[4]; /* 0x04 */ + u8 hwaddr[6]; /* 0x08 */ + u8 reserved_2[8]; /* 0x1E */ + __le16 cr49; /* 0x16 */ + u8 cr03; /* 0x18 */ + u8 cr28; /* 0x19 */ + u8 cr29; /* 0x1A */ + u8 country_code; /* 0x1B */ + +/* specific bbp types */ +#define ADM8211_BBP_RFMD3000 0x00 +#define ADM8211_BBP_RFMD3002 0x01 +#define ADM8211_BBP_ADM8011 0x04 + u8 specific_bbptype; /* 0x1C */ + u8 specific_rftype; /* 0x1D */ + u8 reserved_3[2]; /* 0x1E */ + __le16 device_id; /* 0x20 */ + __le16 vendor_id; /* 0x22 */ + __le16 subsystem_id; /* 0x24 */ + __le16 subsystem_vendor_id; /* 0x26 */ + u8 maxlat; /* 0x28 */ + u8 mingnt; /* 0x29 */ + __le16 cis_pointer_low; /* 0x2A */ + __le16 cis_pointer_high; /* 0x2C */ + __le16 csr18; /* 0x2E */ + u8 reserved_4[16]; /* 0x30 */ + u8 d1_pwrdara; /* 0x40 */ + u8 d0_pwrdara; /* 0x41 */ + u8 d3_pwrdara; /* 0x42 */ + u8 d2_pwrdara; /* 0x43 */ + u8 antenna_power[14]; /* 0x44 */ + __le16 cis_wordcnt; /* 0x52 */ + u8 tx_power[14]; /* 0x54 */ + u8 lpf_cutoff[14]; /* 0x62 */ + u8 lnags_threshold[14]; /* 0x70 */ + __le16 checksum; /* 0x7E */ + u8 cis_data[0]; /* 0x80, 384 bytes */ +} __attribute__ ((packed)); + +static const struct ieee80211_rate adm8211_rates[] = { + { .rate = 10, + .val = 10, + .val2 = -10, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 20, + .val = 20, + .val2 = -20, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 55, + .val = 55, + .val2 = -55, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 110, + .val = 110, + .val2 = -110, + .flags = IEEE80211_RATE_CCK_2 } +}; + +struct ieee80211_chan_range { + u8 min; + u8 max; +}; + +static const struct ieee80211_channel adm8211_channels[] = { + { .chan = 1, + .freq = 2412}, + { .chan = 2, + .freq = 2417}, + { .chan = 3, + .freq = 2422}, + { .chan = 4, + .freq = 2427}, + { .chan = 5, + .freq = 2432}, + { .chan = 6, + .freq = 2437}, + { .chan = 7, + .freq = 2442}, + { .chan = 8, + .freq = 2447}, + { .chan = 9, + .freq = 2452}, + { .chan = 10, + .freq = 2457}, + { .chan = 11, + .freq = 2462}, + { .chan = 12, + .freq = 2467}, + { .chan = 13, + .freq = 2472}, + { .chan = 14, + .freq = 2484}, +}; + +struct adm8211_priv { + struct pci_dev *pdev; + spinlock_t lock; + struct adm8211_csr __iomem *map; + struct adm8211_desc *rx_ring; + struct adm8211_desc *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + struct adm8211_rx_ring_info *rx_buffers; + struct adm8211_tx_ring_info *tx_buffers; + unsigned int rx_ring_size, tx_ring_size; + unsigned int cur_tx, dirty_tx, cur_rx; + + struct ieee80211_low_level_stats stats; + struct ieee80211_hw_mode modes[1]; + struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)]; + struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)]; + int mode; + + int channel; + u8 bssid[ETH_ALEN]; + u8 ssid[32]; + size_t ssid_len; + u8 *mac_addr; + + u8 soft_rx_crc; + u8 retry_limit; + + u8 ant_power; + u8 tx_power; + u8 lpf_cutoff; + u8 lnags_threshold; + struct adm8211_eeprom *eeprom; + size_t eeprom_len; + + u8 revid; + + u32 nar; + +#define ADM8211_TYPE_INTERSIL 0x00 +#define ADM8211_TYPE_RFMD 0x01 +#define ADM8211_TYPE_MARVEL 0x02 +#define ADM8211_TYPE_AIROHA 0x03 +#define ADM8211_TYPE_ADMTEK 0x05 + unsigned int rf_type:3; + unsigned int bbp_type:3; + + u8 specific_bbptype; + enum { + ADM8211_RFMD2948 = 0x0, + ADM8211_RFMD2958 = 0x1, + ADM8211_RFMD2958_RF3000_CONTROL_POWER = 0x2, + ADM8211_MAX2820 = 0x8, + ADM8211_AL2210L = 0xC, /* Airoha */ + } transceiver_type; +}; + +static const struct ieee80211_chan_range cranges[] = { + {1, 11}, /* FCC */ + {1, 11}, /* IC */ + {1, 13}, /* ETSI */ + {10, 11}, /* SPAIN */ + {10, 13}, /* FRANCE */ + {14, 14}, /* MMK */ + {1, 14}, /* MMK2 */ +}; + +#endif /* ADM8211_H */ From c5691235cf70ae2bd71c1f445eb991191530ec6c Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Sat, 21 Jul 2007 22:42:13 +0100 Subject: [PATCH 1219/2804] [PATCH] zd1211rw: monitor all packets While in monitor mode the zd1211rw received only a limited set of packets. This patch forwards now all packets the device receives. Notify that while monitoring no FCS checks are done; so strange packets might appear in the network sniffer of your choice. ATTENTION: Support for multiple interfaces on a single ZD1211 device is currently broken. So this code works only on the first interface. Here is an example to put the device in monitor mode. iwconfig wlan0 mode monitor ifconfig wlan0 up iwconfig wlan0 channel 10 [dsd@gentoo.org: backport to mainline] Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.h | 5 --- drivers/net/wireless/zd1211rw/zd_mac.c | 44 +++++++++++++++++++++---- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index f4698576ab71..8009b70213e2 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -871,11 +871,6 @@ static inline int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) return r; } -static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter) -{ - return zd_iowrite32(chip, CR_RX_FILTER, filter); -} - int zd_chip_lock_phy_regs(struct zd_chip *chip); int zd_chip_unlock_phy_regs(struct zd_chip *chip); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 26869d107e52..7ec1fcf37fc3 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -161,13 +161,33 @@ void zd_mac_clear(struct zd_mac *mac) ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); } -static int reset_mode(struct zd_mac *mac) +static int set_rx_filter(struct zd_mac *mac) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER; return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); } +static int set_sniffer(struct zd_mac *mac) +{ + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + return zd_iowrite32(&mac->chip, CR_SNIFFER_ON, + ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0); + return 0; +} + +static int set_mc_hash(struct zd_mac *mac) +{ + struct zd_mc_hash hash; + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + + zd_mc_clear(&hash); + if (ieee->iw_mode == IW_MODE_MONITOR) + zd_mc_add_all(&hash); + + return zd_chip_set_multicast_hash(&mac->chip, &hash); +} + int zd_mac_open(struct net_device *netdev) { struct zd_mac *mac = zd_netdev_mac(netdev); @@ -194,7 +214,13 @@ int zd_mac_open(struct net_device *netdev) r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G); if (r < 0) goto disable_int; - r = reset_mode(mac); + r = set_rx_filter(mac); + if (r) + goto disable_int; + r = set_sniffer(mac); + if (r) + goto disable_int; + r = set_mc_hash(mac); if (r) goto disable_int; r = zd_chip_switch_radio_on(chip); @@ -298,12 +324,14 @@ static void set_multicast_hash_handler(struct work_struct *work) void zd_mac_set_multicast_list(struct net_device *dev) { - struct zd_mc_hash hash; struct zd_mac *mac = zd_netdev_mac(dev); + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + struct zd_mc_hash hash; struct dev_mc_list *mc; unsigned long flags; - if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) { + if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) || + ieee->iw_mode == IW_MODE_MONITOR) { zd_mc_add_all(&hash); } else { zd_mc_clear(&hash); @@ -628,8 +656,12 @@ int zd_mac_set_mode(struct zd_mac *mac, u32 mode) ieee->iw_mode = mode; spin_unlock_irq(&ieee->lock); - if (netif_running(mac->netdev)) - return reset_mode(mac); + if (netif_running(mac->netdev)) { + int r = set_rx_filter(mac); + if (r) + return r; + return set_sniffer(mac); + } return 0; } From e12dcb05bf70dfa328173fd55b7c13e71dfdb453 Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Sun, 22 Jul 2007 16:16:36 +0300 Subject: [PATCH 1220/2804] [PATCH] Kconfig: order options Reorder the Atmel options so that the menu appears saner. Before: < > Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) <*> Atmel at76c50x chipset 802.11b support < > Atmel at76c506 PCI cards (NEW) < > Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards < > Atmel at76c502/at76c504 PCMCIA cards (NEW) After: < > Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) <*> Atmel at76c50x chipset 802.11b support < > Atmel at76c506 PCI cards (NEW) < > Atmel at76c502/at76c504 PCMCIA cards (NEW) < > Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards Signed-off-by: Faidon Liambotis Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 86480afe5351..8c103f92ed6e 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -379,30 +379,6 @@ config PCI_HERMES common. Some of the built-in wireless adaptors in laptops are of this variety. -config ATMEL - tristate "Atmel at76c50x chipset 802.11b support" - depends on (PCI || PCMCIA) && WLAN_80211 - select WIRELESS_EXT - select FW_LOADER - select CRC32 - ---help--- - A driver 802.11b wireless cards based on the Atmel fast-vnet - chips. This driver supports standard Linux wireless extensions. - - Many cards based on this chipset do not have flash memory - and need their firmware loaded at start-up. If yours is - one of these, you will need to provide a firmware image - to be loaded into the card by the driver. The Atmel - firmware package can be downloaded from - - -config PCI_ATMEL - tristate "Atmel at76c506 PCI cards" - depends on ATMEL && PCI - ---help--- - Enable support for PCI and mini-PCI cards containing the - Atmel at76c506 chip. - config PCMCIA_HERMES tristate "Hermes PCMCIA card support" depends on PCMCIA && HERMES @@ -437,6 +413,40 @@ config PCMCIA_SPECTRUM for downloading Symbol firmware are available at +config ATMEL + tristate "Atmel at76c50x chipset 802.11b support" + depends on (PCI || PCMCIA) && WLAN_80211 + select WIRELESS_EXT + select FW_LOADER + select CRC32 + ---help--- + A driver 802.11b wireless cards based on the Atmel fast-vnet + chips. This driver supports standard Linux wireless extensions. + + Many cards based on this chipset do not have flash memory + and need their firmware loaded at start-up. If yours is + one of these, you will need to provide a firmware image + to be loaded into the card by the driver. The Atmel + firmware package can be downloaded from + + +config PCI_ATMEL + tristate "Atmel at76c506 PCI cards" + depends on ATMEL && PCI + ---help--- + Enable support for PCI and mini-PCI cards containing the + Atmel at76c506 chip. + +config PCMCIA_ATMEL + tristate "Atmel at76c502/at76c504 PCMCIA cards" + depends on ATMEL && PCMCIA + select WIRELESS_EXT + select FW_LOADER + select CRC32 + ---help--- + Enable support for PCMCIA cards containing the + Atmel at76c502 and at76c504 chips. + config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211 @@ -462,16 +472,6 @@ config AIRO_CS for location). You also want to check out the PCMCIA-HOWTO, available from . -config PCMCIA_ATMEL - tristate "Atmel at76c502/at76c504 PCMCIA cards" - depends on ATMEL && PCMCIA - select WIRELESS_EXT - select FW_LOADER - select CRC32 - ---help--- - Enable support for PCMCIA cards containing the - Atmel at76c502 and at76c504 chips. - config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" depends on EXPERIMENTAL && PCMCIA && WLAN_80211 From cfbde697e48891f6216aa9fd14652e099d5cd5fb Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Sun, 22 Jul 2007 16:16:59 +0300 Subject: [PATCH 1221/2804] [PATCH] Kconfig: remove references of pcmcia-cs pcmcia-cs/cardmgr is deprecated and mentioning it in the help text is misleading. Signed-off-by: Faidon Liambotis Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8c103f92ed6e..adf0d207da88 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -63,11 +63,6 @@ config WAVELAN a Radio LAN (wireless Ethernet-like Local Area Network) using the radio frequencies 900 MHz and 2.4 GHz. - This driver support the ISA version of the WaveLAN card. A separate - driver for the PCMCIA (PC-card) hardware is available in David - Hinds' pcmcia-cs package (see the file - for location). - If you want to use an ISA WaveLAN card under Linux, say Y and read the Ethernet-HOWTO, available from . Some more specific @@ -390,12 +385,7 @@ config PCMCIA_HERMES such as the Linksys, D-Link and Farallon Skyline. It should also work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. - To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file - for location). You also want to check out the PCMCIA-HOWTO, - available from . - - You will also very likely also need the Wireless Tools in order to + You will very likely need the Wireless Tools in order to configure your card and that /etc/pcmcia/wireless.opts works: . @@ -467,11 +457,6 @@ config AIRO_CS and Cisco proprietary API, so both the Linux Wireless Tools and the Cisco Linux utilities can be used to configure the card. - To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file - for location). You also want to check out the PCMCIA-HOWTO, - available from . - config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" depends on EXPERIMENTAL && PCMCIA && WLAN_80211 From d73ae55ad46be6a0a11b9b71f9910c73c1b9dbb7 Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Fri, 27 Jul 2007 19:43:17 -0400 Subject: [PATCH 1222/2804] [PATCH] remove gratuitous space in airo module description Currently the modinfo looks like: description: Support for Cisco/Aironet 802.11 wireless ethernet cards. Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs. Arguably, it should be cut at the end of the first sentence. This at least makes it somewhat more legible. Signed-off-by: Bill Nottingham Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index ee1cc14db389..a152797b951a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -241,8 +241,8 @@ static int proc_perm = 0644; MODULE_AUTHOR("Benjamin Reed"); MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \ - cards. Direct support for ISA/PCI/MPI cards and support \ - for PCMCIA when used with airo_cs."); +cards. Direct support for ISA/PCI/MPI cards and support \ +for PCMCIA when used with airo_cs."); MODULE_LICENSE("Dual BSD/GPL"); MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350"); module_param_array(io, int, NULL, 0); From 3623060abbf1cdd7f292645bea31d024e21792ef Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 30 Jul 2007 07:40:04 +0200 Subject: [PATCH 1223/2804] [PATCH] Use mutex instead of semaphore in the Host AP driver The Host AP driver uses a semaphore as mutex. Use the mutex API instead of the (binary) semaphore. Signed-off-by: Matthias Kaehlcke Acked-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_hw.c | 14 +++++++------- drivers/net/wireless/hostap/hostap_wlan.h | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 959887b70ca7..d3dacbceabb3 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -825,7 +825,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, local->hw_downloading) return -ENODEV; - res = down_interruptible(&local->rid_bap_sem); + res = mutex_lock_interruptible(&local->rid_bap_mtx); if (res) return res; @@ -834,7 +834,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " "(res=%d, rid=%04x, len=%d)\n", dev->name, res, rid, len); - up(&local->rid_bap_sem); + mutex_unlock(&local->rid_bap_mtx); return res; } @@ -861,7 +861,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, res = hfa384x_from_bap(dev, BAP0, buf, len); spin_unlock_bh(&local->baplock); - up(&local->rid_bap_sem); + mutex_unlock(&local->rid_bap_mtx); if (res) { if (res != -ENODATA) @@ -902,7 +902,7 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) /* RID len in words and +1 for rec.rid */ rec.len = cpu_to_le16(len / 2 + len % 2 + 1); - res = down_interruptible(&local->rid_bap_sem); + res = mutex_lock_interruptible(&local->rid_bap_mtx); if (res) return res; @@ -917,12 +917,12 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) if (res) { printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " "failed - res=%d\n", dev->name, rid, len, res); - up(&local->rid_bap_sem); + mutex_unlock(&local->rid_bap_mtx); return res; } res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); - up(&local->rid_bap_sem); + mutex_unlock(&local->rid_bap_mtx); if (res) { printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " @@ -3171,7 +3171,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, spin_lock_init(&local->cmdlock); spin_lock_init(&local->baplock); spin_lock_init(&local->lock); - init_MUTEX(&local->rid_bap_sem); + mutex_init(&local->rid_bap_mtx); if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) card_idx = 0; diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 87a54aa6f4dd..a42325c145b4 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "hostap_config.h" @@ -641,7 +642,7 @@ struct local_info { * when removing entries from the list. * TX and RX paths can use read lock. */ spinlock_t cmdlock, baplock, lock; - struct semaphore rid_bap_sem; + struct mutex rid_bap_mtx; u16 infofid; /* MAC buffer id for info frame */ /* txfid, intransmitfid, next_txtid, and next_alloc are protected by * txfidlock */ From 8951554dba0c7962ae72faece66e8f5085a777d6 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 23:34:50 +0200 Subject: [PATCH 1224/2804] [PATCH] drivers/net/wireless/prism54/oid_mgt.c: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/prism54/oid_mgt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c index 42780320cd5c..57a4ac34bed6 100644 --- a/drivers/net/wireless/prism54/oid_mgt.c +++ b/drivers/net/wireless/prism54/oid_mgt.c @@ -244,13 +244,11 @@ mgt_init(islpci_private *priv) /* Alloc the cache */ for (i = 0; i < OID_NUM_LAST; i++) { if (isl_oid[i].flags & OID_FLAG_CACHED) { - priv->mib[i] = kmalloc(isl_oid[i].size * + priv->mib[i] = kzalloc(isl_oid[i].size * (isl_oid[i].range + 1), GFP_KERNEL); if (!priv->mib[i]) return -ENOMEM; - memset(priv->mib[i], 0, - isl_oid[i].size * (isl_oid[i].range + 1)); } else priv->mib[i] = NULL; } From 6dbc9c89fb242873bd3e83890e59da3d6e462025 Mon Sep 17 00:00:00 2001 From: Yoann Padioleau Date: Fri, 3 Aug 2007 19:37:16 +0200 Subject: [PATCH 1225/2804] [PATCH] dev->priv to netdev_priv(dev), for drivers/net/wireless Replacing accesses to dev->priv to netdev_priv(dev). The replacment is safe when netdev_priv is used to access a private structure that is right next to the net_device structure in memory. Cf http://groups.google.com/group/comp.os.linux.development.system/browse_thread/thread/de19321bcd94dbb8/0d74a4adcd6177bd This is the case when the net_device structure was allocated with a call to alloc_netdev or one of its derivative. Signed-off-by: Yoann Padioleau Cc: mcgrof@gmail.com Cc: linux-wireless@vger.kernel.org Cc: akpm@linux-foundation.org Signed-off-by: John W. Linville --- drivers/net/wireless/arlan-proc.c | 14 ++--- drivers/net/wireless/hostap/hostap_cs.c | 2 +- drivers/net/wireless/hostap/hostap_hw.c | 2 +- drivers/net/wireless/hostap/hostap_ioctl.c | 14 ++--- drivers/net/wireless/orinoco_tmd.c | 2 +- drivers/net/wireless/prism54/isl_ioctl.c | 6 +- drivers/net/wireless/ray_cs.c | 66 +++++++++++----------- drivers/net/wireless/strip.c | 2 +- drivers/net/wireless/wl3501_cs.c | 66 +++++++++++----------- 9 files changed, 87 insertions(+), 87 deletions(-) diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c index 015abd928ab0..c6e70dbc5de8 100644 --- a/drivers/net/wireless/arlan-proc.c +++ b/drivers/net/wireless/arlan-proc.c @@ -435,7 +435,7 @@ static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp, goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { @@ -654,7 +654,7 @@ static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); @@ -688,7 +688,7 @@ static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); @@ -716,7 +716,7 @@ static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp pos += sprintf(arlan_drive_info + pos, "No device found here \n"); goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); @@ -745,7 +745,7 @@ static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp, goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); @@ -780,7 +780,7 @@ static int arlan_configure(ctl_table * ctl, int write, struct file *filp, } else if (arlan_device[devnum] != NULL) { - priv = arlan_device[devnum]->priv; + priv = netdev_priv(arlan_device[devnum]); arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF); } @@ -805,7 +805,7 @@ static int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp, } else if (arlan_device[devnum] != NULL) { - priv = arlan_device[devnum]->priv; + priv = netdev_priv(arlan_device[devnum]); arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET); } else diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 30e723f65979..f9cf22bda42e 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -272,7 +272,7 @@ static int sandisk_enable_wireless(struct net_device *dev) { int res, ret = 0; conf_reg_t reg; - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; tuple_t tuple; cisparse_t *parse = NULL; diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index d3dacbceabb3..adedb9716542 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3424,7 +3424,7 @@ static void prism2_suspend(struct net_device *dev) struct local_info *local; union iwreq_data wrqu; - iface = dev->priv; + iface = netdev_priv(dev); local = iface->local; /* Send disconnect event, e.g., to trigger reassociation after resume diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 8c71077d653c..d58ac84f4e9e 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -3088,7 +3088,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) static int prism2_set_genericelement(struct net_device *dev, u8 *elem, size_t len) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; u8 *buf; @@ -3116,7 +3116,7 @@ static int prism2_ioctl_siwauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *data, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; switch (data->flags & IW_AUTH_INDEX) { @@ -3182,7 +3182,7 @@ static int prism2_ioctl_giwauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *data, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; switch (data->flags & IW_AUTH_INDEX) { @@ -3221,7 +3221,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; int i, ret = 0; @@ -3395,7 +3395,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; struct ieee80211_crypt_data **crypt; void *sta_ptr; @@ -3716,7 +3716,7 @@ static int prism2_ioctl_giwgenie(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; int len = local->generic_elem_len - 2; @@ -3755,7 +3755,7 @@ static int prism2_ioctl_siwmlme(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; struct iw_mlme *mlme = (struct iw_mlme *) extra; u16 reason; diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index 7c7b960c91df..b9c54d8fceb9 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -190,7 +190,7 @@ 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 = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pci_card *card = priv->card; unregister_netdev(dev); diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 585f5996d292..f1066614dc31 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -1753,7 +1753,7 @@ prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, int rvalue; enum oid_num_t n = dwrq->flags; - rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r); + rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r); dwrq->length = mgt_response_to_str(n, &r, extra); if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32) kfree(r.ptr); @@ -1766,7 +1766,7 @@ prism54_set_u32(struct net_device *ndev, struct iw_request_info *info, { u32 oid = uwrq[0], u = uwrq[1]; - return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u); + return mgt_set_request(netdev_priv(ndev), oid, 0, &u); } static int @@ -1775,7 +1775,7 @@ prism54_set_raw(struct net_device *ndev, struct iw_request_info *info, { u32 oid = dwrq->flags; - return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra); + return mgt_set_request(netdev_priv(ndev), oid, 0, extra); } void diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 3be624295a1f..1d9dbf830015 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -314,7 +314,7 @@ static int ray_probe(struct pcmcia_device *p_dev) if (!dev) goto fail_alloc_dev; - local = dev->priv; + local = netdev_priv(dev); local->finder = p_dev; /* The io structure describes IO port mapping. None used here */ @@ -388,7 +388,7 @@ static void ray_detach(struct pcmcia_device *link) ray_release(link); - local = (ray_dev_t *)dev->priv; + local = netdev_priv(dev); del_timer(&local->timer); if (link->priv) { @@ -412,7 +412,7 @@ static int ray_config(struct pcmcia_device *link) win_req_t req; memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); DEBUG(1, "ray_config(0x%p)\n", link); @@ -520,7 +520,7 @@ static int ray_init(struct net_device *dev) int i; UCHAR *p; struct ccs __iomem *pccs; - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; DEBUG(1, "ray_init(0x%p)\n", dev); if (!(pcmcia_dev_present(link))) { @@ -581,7 +581,7 @@ static int ray_init(struct net_device *dev) static int dl_startup_params(struct net_device *dev) { int ccsindex; - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct ccs __iomem *pccs; struct pcmcia_device *link = local->finder; @@ -786,7 +786,7 @@ static void join_net(u_long data) static void ray_release(struct pcmcia_device *link) { struct net_device *dev = link->priv; - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); int i; DEBUG(1, "ray_release(0x%p)\n", link); @@ -834,7 +834,7 @@ int ray_dev_init(struct net_device *dev) #ifdef RAY_IMMEDIATE_INIT int i; #endif /* RAY_IMMEDIATE_INIT */ - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; DEBUG(1,"ray_dev_init(dev=%p)\n",dev); @@ -868,7 +868,7 @@ int ray_dev_init(struct net_device *dev) /*===========================================================================*/ static int ray_dev_config(struct net_device *dev, struct ifmap *map) { - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; /* Dummy routine to satisfy device structure */ DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map); @@ -882,7 +882,7 @@ 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) { - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; short length = skb->len; @@ -925,7 +925,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR msg_type) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct ccs __iomem *pccs; int ccsindex; int offset; @@ -1099,7 +1099,7 @@ static int ray_set_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ /* Reject if card is already initialised */ @@ -1124,7 +1124,7 @@ static int ray_get_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); fwrq->m = local->sparm.b5.a_hop_pattern; fwrq->e = 0; @@ -1140,7 +1140,7 @@ static int ray_set_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); /* Reject if card is already initialised */ if(local->card_status != CARD_AWAITING_PARAM) @@ -1173,7 +1173,7 @@ static int ray_get_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); /* Get the essid that was set */ memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); @@ -1194,7 +1194,7 @@ static int ray_get_wap(struct net_device *dev, struct sockaddr *awrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); memcpy(awrq->sa_data, local->bss_id, ETH_ALEN); awrq->sa_family = ARPHRD_ETHER; @@ -1211,7 +1211,7 @@ static int ray_set_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); /* Reject if card is already initialised */ if(local->card_status != CARD_AWAITING_PARAM) @@ -1240,7 +1240,7 @@ static int ray_get_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); if(local->net_default_tx_rate == 3) vwrq->value = 2000000; /* Hum... */ @@ -1260,7 +1260,7 @@ static int ray_set_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); int rthr = vwrq->value; /* Reject if card is already initialised */ @@ -1290,7 +1290,7 @@ static int ray_get_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8) + local->sparm.b5.a_rts_threshold[1]; @@ -1309,7 +1309,7 @@ static int ray_set_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); int fthr = vwrq->value; /* Reject if card is already initialised */ @@ -1338,7 +1338,7 @@ static int ray_get_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8) + local->sparm.b5.a_frag_threshold[1]; @@ -1357,7 +1357,7 @@ static int ray_set_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ char card_mode = 1; @@ -1389,7 +1389,7 @@ static int ray_get_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); if(local->sparm.b5.a_network_type) *uwrq = IW_MODE_INFRA; @@ -1492,7 +1492,7 @@ static int ray_commit(struct net_device *dev, */ static iw_stats * ray_get_wireless_stats(struct net_device * dev) { - ray_dev_t * local = (ray_dev_t *) dev->priv; + ray_dev_t * local = netdev_priv(dev); struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; @@ -1580,7 +1580,7 @@ static const struct iw_handler_def ray_handler_def = /*===========================================================================*/ static int ray_open(struct net_device *dev) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link; link = local->finder; @@ -1614,7 +1614,7 @@ static int ray_open(struct net_device *dev) /*===========================================================================*/ static int ray_dev_close(struct net_device *dev) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link; link = local->finder; @@ -1773,7 +1773,7 @@ static int parse_addr(char *in_str, UCHAR *out) /*===========================================================================*/ static struct net_device_stats *ray_get_stats(struct net_device *dev) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; if (!(pcmcia_dev_present(link))) { @@ -1803,7 +1803,7 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev) /*===========================================================================*/ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; int ccsindex; int i; @@ -1840,7 +1840,7 @@ static void ray_update_multi_list(struct net_device *dev, int all) int ccsindex; struct ccs __iomem *pccs; int i = 0; - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; void __iomem *p = local->sram + HOST_TO_ECF_BASE; @@ -1884,7 +1884,7 @@ static void ray_update_multi_list(struct net_device *dev, int all) /*===========================================================================*/ static void set_multicast_list(struct net_device *dev) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); UCHAR promisc; DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev); @@ -1935,7 +1935,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); - local = (ray_dev_t *)dev->priv; + local = netdev_priv(dev); link = (struct pcmcia_device *)local->finder; if (!pcmcia_dev_present(link)) { DEBUG(2,"ray_cs interrupt from device not present or suspended.\n"); @@ -2165,7 +2165,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i { struct sk_buff *skb = NULL; struct rcs __iomem *prcslink = prcs; - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); UCHAR *rx_ptr; int total_len; int tmp; @@ -2618,7 +2618,7 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) dev = (struct net_device *)link->priv; if (!dev) return 0; - local = (ray_dev_t *)dev->priv; + local = netdev_priv(dev); if (!local) return 0; diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 904e548e6795..c49d5a1f94a2 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -2572,7 +2572,7 @@ static struct strip *strip_alloc(void) return NULL; /* If no more memory, return */ - strip_info = dev->priv; + strip_info = netdev_priv(dev); strip_info->dev = dev; strip_info->magic = STRIP_MAGIC; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index c8b5c2271938..72f3d97e7cb4 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -859,7 +859,7 @@ static int wl3501_esbq_confirm(struct wl3501_card *this) static void wl3501_online(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); printk(KERN_INFO "%s: Wireless LAN online. BSSID: " "%02X %02X %02X %02X %02X %02X\n", dev->name, @@ -907,7 +907,7 @@ static int wl3501_mgmt_association(struct wl3501_card *this) static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); struct wl3501_join_confirm sig; dprintk(3, "entry"); @@ -1046,7 +1046,7 @@ static inline void wl3501_start_confirm_interrupt(struct net_device *dev, static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, u16 addr) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); struct wl3501_assoc_confirm sig; dprintk(3, "entry"); @@ -1075,7 +1075,7 @@ static inline void wl3501_rx_interrupt(struct net_device *dev) int morepkts; u16 addr; u8 sig_id; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); dprintk(3, "entry"); loop: @@ -1257,7 +1257,7 @@ fail: static int wl3501_close(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = -ENODEV; unsigned long flags; struct pcmcia_device *link; @@ -1289,7 +1289,7 @@ static int wl3501_close(struct net_device *dev) */ static int wl3501_reset(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = -ENODEV; wl3501_block_interrupt(this); @@ -1318,7 +1318,7 @@ out: static void wl3501_tx_timeout(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); struct net_device_stats *stats = &this->stats; unsigned long flags; int rc; @@ -1344,7 +1344,7 @@ static void wl3501_tx_timeout(struct net_device *dev) static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { int enabled, rc; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&this->lock, flags); @@ -1371,7 +1371,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static int wl3501_open(struct net_device *dev) { int rc = -ENODEV; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); unsigned long flags; struct pcmcia_device *link; link = this->p_dev; @@ -1410,14 +1410,14 @@ fail: static struct net_device_stats *wl3501_get_stats(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); return &this->stats; } static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); struct iw_statistics *wstats = &this->wstats; u32 value; /* size checked: it is u32 */ @@ -1497,7 +1497,7 @@ static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int channel = wrqu->freq.m; int rc = -EINVAL; @@ -1511,7 +1511,7 @@ static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000; wrqu->freq.e = 1; @@ -1526,7 +1526,7 @@ static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, if (wrqu->mode == IW_MODE_INFRA || wrqu->mode == IW_MODE_ADHOC || wrqu->mode == IW_MODE_AUTO) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); this->net_type = wrqu->mode; rc = wl3501_reset(dev); @@ -1537,7 +1537,7 @@ static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); wrqu->mode = this->net_type; return 0; @@ -1546,7 +1546,7 @@ static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); wrqu->sens.value = this->rssi; wrqu->sens.disabled = !wrqu->sens.value; @@ -1577,7 +1577,7 @@ static int wl3501_get_range(struct net_device *dev, static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; int rc = -EINVAL; @@ -1597,7 +1597,7 @@ out: static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); wrqu->ap_addr.sa_family = ARPHRD_ETHER; memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); @@ -1616,7 +1616,7 @@ static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int i; char *current_ev = extra; struct iw_event iwe; @@ -1666,7 +1666,7 @@ static int wl3501_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); if (wrqu->data.flags) { iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, @@ -1683,7 +1683,7 @@ static int wl3501_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&this->lock, flags); @@ -1697,7 +1697,7 @@ static int wl3501_get_essid(struct net_device *dev, static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); if (wrqu->data.length > sizeof(this->nick)) return -E2BIG; @@ -1708,7 +1708,7 @@ static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); strlcpy(extra, this->nick, 32); wrqu->data.length = strlen(extra); @@ -1733,7 +1733,7 @@ static int wl3501_get_rts_threshold(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, &threshold, sizeof(threshold)); if (!rc) { @@ -1749,7 +1749,7 @@ static int wl3501_get_frag_threshold(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, &threshold, sizeof(threshold)); if (!rc) { @@ -1765,7 +1765,7 @@ static int wl3501_get_txpow(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u16 txpow; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, &txpow, sizeof(txpow)); @@ -1787,7 +1787,7 @@ static int wl3501_get_retry(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u8 retry; /* size checked: it is u8 */ - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_LONG_RETRY_LIMIT, &retry, sizeof(retry)); @@ -1814,7 +1814,7 @@ static int wl3501_get_encode(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u8 implemented, restricted, keys[100], len_keys, tocopy; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, &implemented, sizeof(implemented)); @@ -1852,7 +1852,7 @@ static int wl3501_get_power(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u8 pwr_state; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_CURRENT_PWR_STATE, &pwr_state, sizeof(pwr_state)); @@ -1937,7 +1937,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev) dev->tx_timeout = wl3501_tx_timeout; dev->watchdog_timeo = 5 * HZ; dev->get_stats = wl3501_get_stats; - this = dev->priv; + this = netdev_priv(dev); this->wireless_data.spy_data = &this->spy_data; this->p_dev = p_dev; dev->wireless_data = &this->wireless_data; @@ -2006,7 +2006,7 @@ static int wl3501_config(struct pcmcia_device *link) SET_MODULE_OWNER(dev); - this = dev->priv; + this = netdev_priv(dev); /* * At this point, the dev_node_t structure(s) should be initialized and * arranged in a linked list at link->dev_node. @@ -2079,7 +2079,7 @@ static int wl3501_suspend(struct pcmcia_device *link) { struct net_device *dev = link->priv; - wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); + wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND); if (link->open) netif_device_detach(dev); @@ -2090,7 +2090,7 @@ static int wl3501_resume(struct pcmcia_device *link) { struct net_device *dev = link->priv; - wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); + wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME); if (link->open) { wl3501_reset(dev); netif_device_attach(dev); From 0c9ca690e0117e1bf415d5f3e392e27c0c472c68 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 10:43:44 -0400 Subject: [PATCH 1226/2804] [PATCH] libertas: kill ieeetypes_capinfo bitfield, use ieee80211.h types Use standard BSS capability field constants from ieee80211.h. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 12 +-- drivers/net/wireless/libertas/dev.h | 2 +- drivers/net/wireless/libertas/fw.c | 6 +- drivers/net/wireless/libertas/hostcmd.h | 20 ++--- drivers/net/wireless/libertas/join.c | 111 +++++++++++------------- drivers/net/wireless/libertas/scan.c | 58 +++++-------- drivers/net/wireless/libertas/scan.h | 4 +- drivers/net/wireless/libertas/types.h | 42 +-------- 8 files changed, 91 insertions(+), 164 deletions(-) diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 715cbdaa1d4b..e5cbfa8d6e3f 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -70,18 +70,18 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, mutex_lock(&priv->adapter->lock); list_for_each_entry (iter_bss, &priv->adapter->network_list, list) { - u16 cap; + u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS); + u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); + u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); - memcpy(&cap, &iter_bss->cap, sizeof(cap)); pos += snprintf(buf+pos, len-pos, "%02u| %03d | %03ld | " MAC_FMT " |", numscansdone, iter_bss->channel, iter_bss->rssi, MAC_ARG(iter_bss->bssid)); - pos += snprintf(buf+pos, len-pos, " %04x-", cap); + pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", - iter_bss->cap.ibss ? 'A' : 'I', - iter_bss->cap.privacy ? 'P' : ' ', - iter_bss->cap.spectrummgmt ? 'S' : ' '); + ibss ? 'A' : 'I', privacy ? 'P' : ' ', + spectrum_mgmt ? 'S' : ' '); pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf); pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 785192b884bc..675c65dbc070 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -275,7 +275,7 @@ struct _wlan_adapter { u8 adhoccreate; /** capability Info used in Association, start, join */ - struct ieeetypes_capinfo capinfo; + u16 capability; /** MAC address information */ u8 current_addr[ETH_ALEN]; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index 2dc84ff7a54a..6c2b3c25b821 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -217,10 +217,8 @@ static void wlan_init_adapter(wlan_private * priv) adapter->is_datarate_auto = 1; adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; - // set default value of capinfo. -#define SHORT_PREAMBLE_ALLOWED 1 - memset(&adapter->capinfo, 0, sizeof(adapter->capinfo)); - adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED; + // set default capabilities + adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; adapter->psmode = wlan802_11powermodecam; adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 09b898f6719c..1322552fa6c9 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -108,12 +108,6 @@ struct wlan_offset_value { u32 value; }; -struct WLAN_802_11_FIXED_IEs { - __le64 timestamp; - __le16 beaconinterval; - u16 capabilities; /* Actually struct ieeetypes_capinfo */ -}; - struct WLAN_802_11_VARIABLE_IEs { u8 elementid; u8 length; @@ -237,7 +231,7 @@ struct cmd_ds_802_11_deauthenticate { struct cmd_ds_802_11_associate { u8 peerstaaddr[6]; - struct ieeetypes_capinfo capinfo; + __le16 capability; __le16 listeninterval; __le16 bcnperiod; u8 dtimperiod; @@ -469,22 +463,22 @@ struct cmd_ds_802_11_ad_hoc_start { union IEEEtypes_ssparamset ssparamset; union ieeetypes_phyparamset phyparamset; __le16 probedelay; - struct ieeetypes_capinfo cap; + __le16 capability; u8 datarate[G_SUPPORTED_RATES]; u8 tlv_memory_size_pad[100]; } __attribute__ ((packed)); struct adhoc_bssdesc { - u8 BSSID[6]; - u8 SSID[32]; - u8 bsstype; + u8 bssid[6]; + u8 ssid[32]; + u8 type; __le16 beaconperiod; u8 dtimperiod; __le64 timestamp; __le64 localtime; union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; - struct ieeetypes_capinfo cap; + __le16 capability; u8 datarates[G_SUPPORTED_RATES]; /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the @@ -494,7 +488,7 @@ struct adhoc_bssdesc { } __attribute__ ((packed)); struct cmd_ds_802_11_ad_hoc_join { - struct adhoc_bssdesc bssdescriptor; + struct adhoc_bssdesc bss; __le16 failtimeout; __le16 probedelay; diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 78ac3064a0bd..2db7fbfcaeb4 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -17,8 +17,6 @@ #include "dev.h" #include "assoc.h" -#define AD_HOC_CAP_PRIVACY_ON 1 - /** * @brief This function finds out the common rates between rate1 and rate2. * @@ -121,7 +119,8 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) goto done; /* set preamble to firmware */ - if (adapter->capinfo.shortpreamble && assoc_req->bss.cap.shortpreamble) + if ( (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) adapter->preamble = cmd_type_short_preamble; else adapter->preamble = cmd_type_long_preamble; @@ -150,12 +149,12 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass adapter->adhoccreate = 1; - if (!adapter->capinfo.shortpreamble) { - lbs_deb_join("AdhocStart: Long preamble\n"); - adapter->preamble = cmd_type_long_preamble; - } else { + if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocStart: Short preamble\n"); adapter->preamble = cmd_type_short_preamble; + } else { + lbs_deb_join("AdhocStart: Long preamble\n"); + adapter->preamble = cmd_type_long_preamble; } libertas_set_radio_control(priv); @@ -205,9 +204,10 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso return -1; } - /*Use shortpreamble only when both creator and card supports + /* Use shortpreamble only when both creator and card supports short preamble */ - if (!bss->cap.shortpreamble || !adapter->capinfo.shortpreamble) { + if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Long preamble\n"); adapter->preamble = cmd_type_long_preamble; } else { @@ -357,7 +357,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, /* set the listen interval */ passo->listeninterval = cpu_to_le16(adapter->listeninterval); - pos += sizeof(passo->capinfo); + pos += sizeof(passo->capability); pos += sizeof(passo->listeninterval); pos += sizeof(passo->bcnperiod); pos += sizeof(passo->dtimperiod); @@ -427,12 +427,6 @@ int libertas_cmd_80211_associate(wlan_private * priv, lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n", cpu_to_le16(rates->header.len)); - /* set IBSS field */ - if (bss->mode == IW_MODE_INFRA) { -#define CAPINFO_ESS_MODE 1 - passo->capinfo.ess = CAPINFO_ESS_MODE; - } - if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { ret = -1; goto done; @@ -440,12 +434,13 @@ int libertas_cmd_80211_associate(wlan_private * priv, cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); - /* set the capability info at last */ - memcpy(&tmpcap, &bss->cap, sizeof(passo->capinfo)); - tmpcap &= CAPINFO_MASK; - lbs_deb_join("ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + /* set the capability info */ + tmpcap = (bss->capability & CAPINFO_MASK); + if (bss->mode == IW_MODE_INFRA) + tmpcap |= WLAN_CAPABILITY_ESS; + passo->capability = cpu_to_le16(tmpcap); + lbs_deb_join("ASSOC_CMD: capability=%4X CAPINFO_MASK=%4X\n", tmpcap, CAPINFO_MASK); - memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo)); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); @@ -461,6 +456,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, int cmdappendsize = 0; int i; struct assoc_request * assoc_req = pdata_buf; + u16 tmpcap = 0; lbs_deb_enter(LBS_DEB_JOIN); @@ -518,19 +514,17 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow); /* set capability info */ - adhs->cap.ess = 0; - adhs->cap.ibss = 1; - - /* probedelay */ - adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); - - /* set up privacy in adapter->scantable[i] */ + tmpcap = WLAN_CAPABILITY_IBSS; if (assoc_req->secinfo.wep_enabled) { lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n"); - adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON; + tmpcap |= WLAN_CAPABILITY_PRIVACY; } else { lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n"); } + adhs->capability = cpu_to_le16(tmpcap); + + /* probedelay */ + adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); memset(adhs->datarate, 0, sizeof(adhs->datarate)); @@ -585,67 +579,58 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf) { wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj; + struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; struct assoc_request * assoc_req = pdata_buf; struct bss_descriptor *bss = &assoc_req->bss; int cmdappendsize = 0; int ret = 0; u8 *card_rates; int card_rates_size; - u16 tmpcap; int i; lbs_deb_enter(LBS_DEB_JOIN); cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join); - padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss; + join_cmd->bss.type = cmd_bss_type_ibss; + join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); - padhocjoin->bssdescriptor.beaconperiod = cpu_to_le16(bss->beaconperiod); + memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); + memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); - memcpy(&padhocjoin->bssdescriptor.BSSID, &bss->bssid, ETH_ALEN); - memcpy(&padhocjoin->bssdescriptor.SSID, &bss->ssid, bss->ssid_len); + memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, + sizeof(union ieeetypes_phyparamset)); - memcpy(&padhocjoin->bssdescriptor.phyparamset, - &bss->phyparamset, sizeof(union ieeetypes_phyparamset)); - - memcpy(&padhocjoin->bssdescriptor.ssparamset, - &bss->ssparamset, sizeof(union IEEEtypes_ssparamset)); - - memcpy(&tmpcap, &bss->cap, sizeof(struct ieeetypes_capinfo)); - tmpcap &= CAPINFO_MASK; + memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, + sizeof(union IEEEtypes_ssparamset)); + join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - tmpcap, CAPINFO_MASK); - memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap, - sizeof(struct ieeetypes_capinfo)); + bss->capability, CAPINFO_MASK); /* information on BSSID descriptor passed to FW */ lbs_deb_join( "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n", - MAC_ARG(padhocjoin->bssdescriptor.BSSID), - padhocjoin->bssdescriptor.SSID); + MAC_ARG(join_cmd->bss.bssid), join_cmd->bss.ssid); /* failtimeout */ - padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); /* probedelay */ - padhocjoin->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); + join_cmd->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); /* Copy Data rates from the rates recorded in scan response */ - memset(padhocjoin->bssdescriptor.datarates, 0, - sizeof(padhocjoin->bssdescriptor.datarates)); - memcpy(padhocjoin->bssdescriptor.datarates, bss->datarates, - min(sizeof(padhocjoin->bssdescriptor.datarates), - sizeof(bss->datarates))); + memset(join_cmd->bss.datarates, 0, sizeof(join_cmd->bss.datarates)); + memcpy(join_cmd->bss.datarates, bss->datarates, + min(sizeof(join_cmd->bss.datarates), sizeof(bss->datarates))); card_rates = libertas_supported_rates; card_rates_size = sizeof(libertas_supported_rates); adapter->curbssparams.channel = bss->channel; - if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates, - sizeof(padhocjoin->bssdescriptor.datarates), + if (get_common_rates(adapter, join_cmd->bss.datarates, + sizeof(join_cmd->bss.datarates), card_rates, card_rates_size)) { lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); ret = -1; @@ -653,8 +638,8 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, } /* Find the last non zero */ - for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates) - && padhocjoin->bssdescriptor.datarates[i]; i++) ; + for (i = 0; i < sizeof(join_cmd->bss.datarates) + && join_cmd->bss.datarates[i]; i++) ; adapter->curbssparams.numofrates = i; @@ -662,14 +647,16 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, * Copy the adhoc joining rates to Current BSS State structure */ memcpy(adapter->curbssparams.datarates, - padhocjoin->bssdescriptor.datarates, + join_cmd->bss.datarates, adapter->curbssparams.numofrates); - padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow = + join_cmd->bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); if (assoc_req->secinfo.wep_enabled) { - padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON; + u16 tmp = le16_to_cpu(join_cmd->bss.capability); + tmp |= WLAN_CAPABILITY_PRIVACY; + join_cmd->bss.capability = cpu_to_le16(tmp); } if (adapter->psmode == wlan802_11powermodemax_psp) { diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index c3043dcb541e..8753f9344f3e 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -76,7 +76,7 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, && !secinfo->WPA2enabled && match_bss->wpa_ie[0] != WPA_IE && match_bss->rsn_ie[0] != WPA2_IE - && !match_bss->privacy) { + && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } return 0; @@ -88,7 +88,7 @@ static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo, if ( secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && match_bss->privacy) { + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } return 0; @@ -101,7 +101,8 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, && secinfo->WPAenabled && (match_bss->wpa_ie[0] == WPA_IE) /* privacy bit may NOT be set in some APs like LinkSys WRT54G - && bss->privacy */ + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { + */ ) { return 1; } @@ -115,7 +116,8 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, && secinfo->WPA2enabled && (match_bss->rsn_ie[0] == WPA2_IE) /* privacy bit may NOT be set in some APs like LinkSys WRT54G - && bss->privacy */ + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { + */ ) { return 1; } @@ -130,7 +132,7 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, && !secinfo->WPA2enabled && (match_bss->wpa_ie[0] != WPA_IE) && (match_bss->rsn_ie[0] != WPA2_IE) - && match_bss->privacy) { + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } return 0; @@ -177,7 +179,7 @@ static int is_network_compatible(wlan_adapter * adapter, adapter->secinfo.wep_enabled ? "e" : "d", adapter->secinfo.WPAenabled ? "e" : "d", adapter->secinfo.WPA2enabled ? "e" : "d", - bss->privacy); + (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; } else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) { lbs_deb_scan( @@ -187,15 +189,14 @@ static int is_network_compatible(wlan_adapter * adapter, adapter->secinfo.wep_enabled ? "e" : "d", adapter->secinfo.WPAenabled ? "e" : "d", adapter->secinfo.WPA2enabled ? "e" : "d", - bss->privacy); + (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; } else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) { lbs_deb_scan( "is_network_compatible() dynamic WEP: " "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n", - bss->wpa_ie[0], - bss->rsn_ie[0], - bss->privacy); + bss->wpa_ie[0], bss->rsn_ie[0], + (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; } @@ -207,7 +208,7 @@ static int is_network_compatible(wlan_adapter * adapter, adapter->secinfo.wep_enabled ? "e" : "d", adapter->secinfo.WPAenabled ? "e" : "d", adapter->secinfo.WPA2enabled ? "e" : "d", - bss->privacy); + (bss->capability & WLAN_CAPABILITY_PRIVACY)); done: lbs_deb_leave(LBS_DEB_SCAN); @@ -904,8 +905,6 @@ static int libertas_process_bss(struct bss_descriptor * bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - struct ieeetypes_capinfo *pcap; - struct WLAN_802_11_FIXED_IEs fixedie; u8 *pcurrentptr; u8 *pRate; u8 elemlen; @@ -974,24 +973,28 @@ static int libertas_process_bss(struct bss_descriptor * bss, bytesleftforcurrentbeacon -= 1; /* time stamp is 8 bytes long */ - fixedie.timestamp = bss->timestamp = le64_to_cpup((void *)pcurrentptr); + bss->timestamp = le64_to_cpup((void *)pcurrentptr); pcurrentptr += 8; bytesleftforcurrentbeacon -= 8; /* beacon interval is 2 bytes long */ - fixedie.beaconinterval = bss->beaconperiod = le16_to_cpup((void *)pcurrentptr); + bss->beaconperiod = le16_to_cpup((void *)pcurrentptr); pcurrentptr += 2; bytesleftforcurrentbeacon -= 2; /* capability information is 2 bytes long */ - memcpy(&fixedie.capabilities, pcurrentptr, 2); - lbs_deb_scan("process_bss: fixedie.capabilities=0x%X\n", - fixedie.capabilities); - pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities; - memcpy(&bss->cap, pcap, sizeof(struct ieeetypes_capinfo)); + bss->capability = le16_to_cpup((void *)pcurrentptr); + lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability); pcurrentptr += 2; bytesleftforcurrentbeacon -= 2; + if (bss->capability & WLAN_CAPABILITY_PRIVACY) + lbs_deb_scan("process_bss: AP WEP enabled\n"); + if (bss->capability & WLAN_CAPABILITY_IBSS) + bss->mode = IW_MODE_ADHOC; + else + bss->mode = IW_MODE_INFRA; + /* rest of the current buffer are IE's */ lbs_deb_scan("process_bss: IE length for this AP = %d\n", bytesleftforcurrentbeacon); @@ -999,19 +1002,6 @@ static int libertas_process_bss(struct bss_descriptor * bss, lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr, bytesleftforcurrentbeacon); - if (pcap->privacy) { - lbs_deb_scan("process_bss: AP WEP enabled\n"); - bss->privacy = wlan802_11privfilter8021xWEP; - } else { - bss->privacy = wlan802_11privfilteracceptall; - } - - if (pcap->ibss == 1) { - bss->mode = IW_MODE_ADHOC; - } else { - bss->mode = IW_MODE_INFRA; - } - /* process variable IE */ while (bytesleftforcurrentbeacon >= 2) { elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr)); @@ -1550,7 +1540,7 @@ static inline char *libertas_translate_scan(wlan_private *priv, /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; - if (bss->privacy) { + if (bss->capability & WLAN_CAPABILITY_PRIVACY) { iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; } else { iwe.u.data.flags = IW_ENCODE_DISABLED; diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index bd019e5ff1eb..2a095733f194 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -140,8 +140,7 @@ struct bss_descriptor { u8 ssid[IW_ESSID_MAX_SIZE + 1]; u8 ssid_len; - /* WEP encryption requirement */ - u32 privacy; + u16 capability; /* receive signal strength in dBm */ long rssi; @@ -160,7 +159,6 @@ struct bss_descriptor { union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; - struct ieeetypes_capinfo cap; u8 datarates[WLAN_SUPPORTED_RATES]; u64 networktsf; //!< TSF timestamp from the current firmware TSF diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 028e2f3b53d6..f4be1293cd16 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -30,47 +30,7 @@ enum ieeetypes_elementid { EXTRA_IE = 133, } __attribute__ ((packed)); -#ifdef __BIG_ENDIAN -#define CAPINFO_MASK (~(0xda00)) -#else #define CAPINFO_MASK (~(0x00da)) -#endif - -struct ieeetypes_capinfo { -#ifdef __BIG_ENDIAN_BITFIELD - u8 chanagility:1; - u8 pbcc:1; - u8 shortpreamble:1; - u8 privacy:1; - u8 cfpollrqst:1; - u8 cfpollable:1; - u8 ibss:1; - u8 ess:1; - u8 rsrvd1:2; - u8 dsssofdm:1; - u8 rsvrd2:1; - u8 apsd:1; - u8 shortslottime:1; - u8 rsrvd3:1; - u8 spectrummgmt:1; -#else - u8 ess:1; - u8 ibss:1; - u8 cfpollable:1; - u8 cfpollrqst:1; - u8 privacy:1; - u8 shortpreamble:1; - u8 pbcc:1; - u8 chanagility:1; - u8 spectrummgmt:1; - u8 rsrvd3:1; - u8 shortslottime:1; - u8 apsd:1; - u8 rsvrd2:1; - u8 dsssofdm:1; - u8 rsrvd1:2; -#endif -} __attribute__ ((packed)); struct ieeetypes_cfparamset { u8 elementid; @@ -114,7 +74,7 @@ union ieeetypes_phyparamset { } __attribute__ ((packed)); struct ieeetypes_assocrsp { - struct ieeetypes_capinfo capability; + __le16 capability; __le16 statuscode; __le16 aid; u8 iebuffer[1]; From 1443b6530d8db779082dc9fabbd894e2b551b101 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 10:45:55 -0400 Subject: [PATCH 1227/2804] [PATCH] libertas: rename WLAN_802_11_KEY to enc_key and clean up usage It doesn't touch hardware and therefore doesn't need endian notations either. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 8 ++++---- drivers/net/wireless/libertas/cmd.c | 7 +++---- drivers/net/wireless/libertas/cmdresp.c | 19 ++++++++++--------- drivers/net/wireless/libertas/defs.h | 3 --- drivers/net/wireless/libertas/dev.h | 12 ++++++------ drivers/net/wireless/libertas/fw.c | 2 +- drivers/net/wireless/libertas/hostcmd.h | 16 ++++++---------- drivers/net/wireless/libertas/wext.c | 14 +++++++------- 8 files changed, 37 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index afd5617dd92b..307ebcb94b18 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -307,7 +307,7 @@ static int assoc_helper_wep_keys(wlan_private *priv, /* Copy WEP keys into adapter wep key fields */ for (i = 0; i < 4; i++) { memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i], - sizeof(struct WLAN_802_11_KEY)); + sizeof(struct enc_key)); } adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx; @@ -703,7 +703,7 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) int i; for (i = 0; i < 4; i++) { memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i], - sizeof(struct WLAN_802_11_KEY)); + sizeof(struct enc_key)); } } @@ -712,12 +712,12 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key, - sizeof(struct WLAN_802_11_KEY)); + sizeof(struct enc_key)); } if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key, - sizeof(struct WLAN_802_11_KEY)); + sizeof(struct enc_key)); } if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 4a8f5dc70239..355a3960323b 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -181,7 +181,7 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, /* Copy key types and material to host command structure */ for (i = 0; i < 4; i++) { - struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i]; + struct enc_key * pkey = &assoc_req->wep_keys[i]; switch (pkey->len) { case KEY_LEN_WEP_40: @@ -249,10 +249,8 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, - struct WLAN_802_11_KEY * pkey) + struct enc_key * pkey) { - pkeyparamset->keytypeid = cpu_to_le16(pkey->type); - if (pkey->flags & KEY_INFO_WPA_ENABLED) { pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); } @@ -264,6 +262,7 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, } pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + pkeyparamset->keytypeid = cpu_to_le16(pkey->type); pkeyparamset->keylen = cpu_to_le16(pkey->len); memcpy(pkeyparamset->key, pkey->key, pkey->len); pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 6ac0d4752fa4..89bd43c2efa3 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -321,11 +321,12 @@ static int wlan_ret_802_11_key_material(wlan_private * priv, while (buf_ptr < resp_end) { struct MrvlIEtype_keyParamSet * pkeyparamset = (struct MrvlIEtype_keyParamSet *) buf_ptr; - struct WLAN_802_11_KEY * pkey; - u16 key_info = le16_to_cpu(pkeyparamset->keyinfo); + struct enc_key * pkey; u16 param_set_len = le16_to_cpu(pkeyparamset->length); - u8 * end; u16 key_len = le16_to_cpu(pkeyparamset->keylen); + u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo); + u16 key_type = le16_to_cpu(pkeyparamset->keytypeid); + u8 * end; end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) + sizeof (pkeyparamset->length) @@ -334,20 +335,20 @@ static int wlan_ret_802_11_key_material(wlan_private * priv, if (end > resp_end) break; - if (key_info & KEY_INFO_WPA_UNICAST) + if (key_flags & KEY_INFO_WPA_UNICAST) pkey = &adapter->wpa_unicast_key; - else if (key_info & KEY_INFO_WPA_MCAST) + else if (key_flags & KEY_INFO_WPA_MCAST) pkey = &adapter->wpa_mcast_key; else break; /* Copy returned key into driver */ - memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); + memset(pkey, 0, sizeof(struct enc_key)); if (key_len > sizeof(pkey->key)) break; - pkey->type = le16_to_cpu(pkeyparamset->keytypeid); - pkey->flags = le16_to_cpu(pkeyparamset->keyinfo); - pkey->len = le16_to_cpu(pkeyparamset->keylen); + pkey->type = key_type; + pkey->flags = key_flags; + pkey->len = key_len; memcpy(pkey->key, pkeyparamset->key, pkey->len); buf_ptr = end + 1; diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 4dd43e59bda0..de0756ee15ad 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -218,9 +218,6 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) #define CMD_F_HOSTCMD (1 << 0) #define FW_CAPINFO_WPA (1 << 0) -/** WPA key LENGTH*/ -#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32 - #define KEY_LEN_WPA_AES 16 #define KEY_LEN_WPA_TKIP 32 #define KEY_LEN_WEP_104 13 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 675c65dbc070..184eee548572 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -188,12 +188,12 @@ struct assoc_request { u8 bssid[ETH_ALEN]; /** WEP keys */ - struct WLAN_802_11_KEY wep_keys[4]; + struct enc_key wep_keys[4]; u16 wep_tx_keyidx; /** WPA keys */ - struct WLAN_802_11_KEY wpa_mcast_key; - struct WLAN_802_11_KEY wpa_unicast_key; + struct enc_key wpa_mcast_key; + struct enc_key wpa_unicast_key; struct wlan_802_11_security secinfo; @@ -335,12 +335,12 @@ struct _wlan_adapter { struct wlan_802_11_security secinfo; /** WEP keys */ - struct WLAN_802_11_KEY wep_keys[4]; + struct enc_key wep_keys[4]; u16 wep_tx_keyidx; /** WPA keys */ - struct WLAN_802_11_KEY wpa_mcast_key; - struct WLAN_802_11_KEY wpa_unicast_key; + struct enc_key wpa_mcast_key; + struct enc_key wpa_unicast_key; /** WPA Information Elements*/ u8 wpa_ie[MAX_WPA_IE_LEN]; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index 6c2b3c25b821..288e47c33555 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -181,7 +181,7 @@ static void wlan_init_adapter(wlan_private * priv) adapter->secinfo.wep_enabled = 0; for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); i++) - memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY)); + memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); adapter->wep_tx_keyidx = 0; adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; adapter->mode = IW_MODE_INFRA; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 1322552fa6c9..01a97d0fa98a 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -83,16 +83,12 @@ struct cmd_ctrl_node { wait_queue_head_t cmdwait_q; }; -/* WLAN_802_11_KEY - * - * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES) - * is determined from the keylength field. - */ -struct WLAN_802_11_KEY { - __le32 len; - __le32 flags; /* KEY_INFO_* from wlan_defs.h */ - u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH]; - __le16 type; /* KEY_TYPE_* from wlan_defs.h */ +/* Generic structure to hold all key types. */ +struct enc_key { + u16 len; + u16 flags; /* KEY_INFO_* from wlan_defs.h */ + u16 type; /* KEY_TYPE_* from wlan_defs.h */ + u8 key[32]; }; struct IE_WPA { diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 2fcc3bf21081..f7df8c71a544 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1325,7 +1325,7 @@ static int wlan_set_wep_key(struct assoc_request *assoc_req, int set_tx_key) { int ret = 0; - struct WLAN_802_11_KEY *pkey; + struct enc_key *pkey; lbs_deb_enter(LBS_DEB_WEXT); @@ -1344,7 +1344,7 @@ static int wlan_set_wep_key(struct assoc_request *assoc_req, pkey = &assoc_req->wep_keys[index]; if (key_length > 0) { - memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); + memset(pkey, 0, sizeof(struct enc_key)); pkey->type = KEY_TYPE_ID_WEP; /* Standardize the key length */ @@ -1412,11 +1412,11 @@ static void disable_wpa(struct assoc_request *assoc_req) { lbs_deb_enter(LBS_DEB_WEXT); - memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct WLAN_802_11_KEY)); + memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key)); assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST; set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); - memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct WLAN_802_11_KEY)); + memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key)); assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST; set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); @@ -1567,7 +1567,7 @@ static int wlan_get_encodeext(struct net_device *dev, && (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled)) { /* WPA */ - struct WLAN_802_11_KEY * pkey = NULL; + struct enc_key * pkey = NULL; if ( adapter->wpa_mcast_key.len && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED)) @@ -1679,7 +1679,7 @@ static int wlan_set_encodeext(struct net_device *dev, if (set_tx_key) set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { - struct WLAN_802_11_KEY * pkey; + struct enc_key * pkey; /* validate key length */ if (((alg == IW_ENCODE_ALG_TKIP) @@ -1702,7 +1702,7 @@ static int wlan_set_encodeext(struct net_device *dev, set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); } - memset(pkey, 0, sizeof (struct WLAN_802_11_KEY)); + memset(pkey, 0, sizeof (struct enc_key)); memcpy(pkey->key, ext->key, ext->key_len); pkey->len = ext->key_len; if (pkey->len) From 2950cd26308ced650cf7cc3199eae3eb27f9917f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 10:47:17 -0400 Subject: [PATCH 1228/2804] [PATCH] libertas: clean up indentation in libertas_association_worker Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 307ebcb94b18..36586db3e1f7 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -556,7 +556,8 @@ void libertas_association_worker(struct work_struct *work) if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { ret = assoc_helper_mode(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", + __LINE__, ret); goto out; } } @@ -574,7 +575,8 @@ lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret); || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { ret = assoc_helper_wep_keys(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", + __LINE__, ret); goto out; } } @@ -582,7 +584,8 @@ lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret); if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { ret = assoc_helper_secinfo(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", + __LINE__, ret); goto out; } } @@ -590,7 +593,8 @@ lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret); if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { ret = assoc_helper_wpa_ie(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", + __LINE__, ret); goto out; } } @@ -599,7 +603,8 @@ lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret); || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { ret = assoc_helper_wpa_keys(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", + __LINE__, ret); goto out; } } From ab6179711a5e46ed1db739bef7752d65ce836dce Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 10:48:02 -0400 Subject: [PATCH 1229/2804] [PATCH] libertas: clean up 802.11 IE post-scan handling Remove struct IE_WPA and just use direct checking of the IE bytes like ipw. Remove WLAN_802_11_VARIABLE_IEs because it's unused. Kill ieeetypes_elementid enum and just use MFIE_* from ieee80211.h. Also use struct ieee80211_info_element for scan buffer processing to simplify pointer usage. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/hostcmd.h | 13 -- drivers/net/wireless/libertas/scan.c | 201 ++++++++++-------------- drivers/net/wireless/libertas/types.h | 23 --- 3 files changed, 85 insertions(+), 152 deletions(-) diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 01a97d0fa98a..05ea54df71bd 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -91,25 +91,12 @@ struct enc_key { u8 key[32]; }; -struct IE_WPA { - u8 elementid; - u8 len; - u8 oui[4]; - __le16 version; -}; - /* wlan_offset_value */ struct wlan_offset_value { u32 offset; u32 value; }; -struct WLAN_802_11_VARIABLE_IEs { - u8 elementid; - u8 length; - u8 data[1]; -}; - /* Define general data structure */ /* cmd_DS_GEN */ struct cmd_ds_gen { diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8753f9344f3e..2d6bc7811b27 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -74,8 +74,8 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, if ( !secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && match_bss->wpa_ie[0] != WPA_IE - && match_bss->rsn_ie[0] != WPA2_IE + && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC + && match_bss->rsn_ie[0] != MFIE_TYPE_RSN && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } @@ -99,7 +99,7 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, { if ( !secinfo->wep_enabled && secinfo->WPAenabled - && (match_bss->wpa_ie[0] == WPA_IE) + && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { */ @@ -114,7 +114,7 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, { if ( !secinfo->wep_enabled && secinfo->WPA2enabled - && (match_bss->rsn_ie[0] == WPA2_IE) + && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { */ @@ -130,8 +130,8 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, if ( !secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && (match_bss->wpa_ie[0] != WPA_IE) - && (match_bss->rsn_ie[0] != WPA2_IE) + && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC) + && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN) && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } @@ -900,24 +900,18 @@ void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, static int libertas_process_bss(struct bss_descriptor * bss, u8 ** pbeaconinfo, int *bytesleft) { - enum ieeetypes_elementid elemID; struct ieeetypes_fhparamset *pFH; struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - u8 *pcurrentptr; + u8 *pos, *end; u8 *pRate; - u8 elemlen; u8 bytestocopy; u8 ratesize; u16 beaconsize; u8 founddatarateie; - int bytesleftforcurrentbeacon; int ret; - struct IE_WPA *pIe; - const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 }; - struct ieeetypes_countryinfoset *pcountryinfo; lbs_deb_enter(LBS_DEB_ASSOC); @@ -934,29 +928,24 @@ static int libertas_process_bss(struct bss_descriptor * bss, } if (beaconsize == 0 || beaconsize > *bytesleft) { - *pbeaconinfo += *bytesleft; *bytesleft = 0; - return -1; } /* Initialize the current working beacon pointer for this BSS iteration */ - pcurrentptr = *pbeaconinfo; + pos = *pbeaconinfo; + end = pos + beaconsize; /* Advance the return beacon pointer past the current beacon */ *pbeaconinfo += beaconsize; *bytesleft -= beaconsize; - bytesleftforcurrentbeacon = beaconsize; - - memcpy(bss->bssid, pcurrentptr, ETH_ALEN); + memcpy(bss->bssid, pos, ETH_ALEN); lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", MAC_ARG(bss->bssid)); + pos += ETH_ALEN; - pcurrentptr += ETH_ALEN; - bytesleftforcurrentbeacon -= ETH_ALEN; - - if (bytesleftforcurrentbeacon < 12) { + if ((end - pos) < 12) { lbs_deb_scan("process_bss: Not enough bytes left\n"); return -1; } @@ -967,26 +956,22 @@ static int libertas_process_bss(struct bss_descriptor * bss, */ /* RSSI is 1 byte long */ - bss->rssi = *pcurrentptr; - lbs_deb_scan("process_bss: RSSI=%02X\n", *pcurrentptr); - pcurrentptr += 1; - bytesleftforcurrentbeacon -= 1; + bss->rssi = *pos; + lbs_deb_scan("process_bss: RSSI=%02X\n", *pos); + pos++; /* time stamp is 8 bytes long */ - bss->timestamp = le64_to_cpup((void *)pcurrentptr); - pcurrentptr += 8; - bytesleftforcurrentbeacon -= 8; + bss->timestamp = le64_to_cpup((void *) pos); + pos += 8; /* beacon interval is 2 bytes long */ - bss->beaconperiod = le16_to_cpup((void *)pcurrentptr); - pcurrentptr += 2; - bytesleftforcurrentbeacon -= 2; + bss->beaconperiod = le16_to_cpup((void *) pos); + pos += 2; /* capability information is 2 bytes long */ - bss->capability = le16_to_cpup((void *)pcurrentptr); + bss->capability = le16_to_cpup((void *) pos); lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability); - pcurrentptr += 2; - bytesleftforcurrentbeacon -= 2; + pos += 2; if (bss->capability & WLAN_CAPABILITY_PRIVACY) lbs_deb_scan("process_bss: AP WEP enabled\n"); @@ -996,47 +981,39 @@ static int libertas_process_bss(struct bss_descriptor * bss, bss->mode = IW_MODE_INFRA; /* rest of the current buffer are IE's */ - lbs_deb_scan("process_bss: IE length for this AP = %d\n", - bytesleftforcurrentbeacon); - - lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr, - bytesleftforcurrentbeacon); + lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos); + lbs_dbg_hex("process_bss: IE info", pos, end - pos); /* process variable IE */ - while (bytesleftforcurrentbeacon >= 2) { - elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr)); - elemlen = *((u8 *) pcurrentptr + 1); + while (pos <= end - 2) { + struct ieee80211_info_element * elem = + (struct ieee80211_info_element *) pos; - if (bytesleftforcurrentbeacon < elemlen) { + if (pos + elem->len > end) { lbs_deb_scan("process_bss: error in processing IE, " "bytes left < IE length\n"); - bytesleftforcurrentbeacon = 0; - continue; + break; } - switch (elemID) { - case SSID: - bss->ssid_len = elemlen; - memcpy(bss->ssid, (pcurrentptr + 2), elemlen); + switch (elem->id) { + case MFIE_TYPE_SSID: + bss->ssid_len = elem->len; + memcpy(bss->ssid, elem->data, elem->len); lbs_deb_scan("ssid '%s', ssid length %u\n", escape_essid(bss->ssid, bss->ssid_len), bss->ssid_len); break; - case SUPPORTED_RATES: - memcpy(bss->datarates, (pcurrentptr + 2), elemlen); - memmove(bss->libertas_supported_rates, (pcurrentptr + 2), - elemlen); - ratesize = elemlen; + case MFIE_TYPE_RATES: + memcpy(bss->datarates, elem->data, elem->len); + memmove(bss->libertas_supported_rates, elem->data, + elem->len); + ratesize = elem->len; founddatarateie = 1; break; - case EXTRA_IE: - lbs_deb_scan("process_bss: EXTRA_IE Found!\n"); - break; - - case FH_PARAM_SET: - pFH = (struct ieeetypes_fhparamset *) pcurrentptr; + case MFIE_TYPE_FH_SET: + pFH = (struct ieeetypes_fhparamset *) pos; memmove(&bss->phyparamset.fhparamset, pFH, sizeof(struct ieeetypes_fhparamset)); #if 0 /* I think we can store these LE */ @@ -1045,21 +1022,21 @@ static int libertas_process_bss(struct bss_descriptor * bss, #endif break; - case DS_PARAM_SET: - pDS = (struct ieeetypes_dsparamset *) pcurrentptr; + case MFIE_TYPE_DS_SET: + pDS = (struct ieeetypes_dsparamset *) pos; bss->channel = pDS->currentchan; memcpy(&bss->phyparamset.dsparamset, pDS, sizeof(struct ieeetypes_dsparamset)); break; - case CF_PARAM_SET: - pCF = (struct ieeetypes_cfparamset *) pcurrentptr; + case MFIE_TYPE_CF_SET: + pCF = (struct ieeetypes_cfparamset *) pos; memcpy(&bss->ssparamset.cfparamset, pCF, sizeof(struct ieeetypes_cfparamset)); break; - case IBSS_PARAM_SET: - pibss = (struct ieeetypes_ibssparamset *) pcurrentptr; + case MFIE_TYPE_IBSS_SET: + pibss = (struct ieeetypes_ibssparamset *) pos; bss->atimwindow = le32_to_cpu(pibss->atimwindow); memmove(&bss->ssparamset.ibssparamset, pibss, sizeof(struct ieeetypes_ibssparamset)); @@ -1069,9 +1046,8 @@ static int libertas_process_bss(struct bss_descriptor * bss, #endif break; - /* Handle Country Info IE */ - case COUNTRY_INFO: - pcountryinfo = (struct ieeetypes_countryinfoset *) pcurrentptr; + case MFIE_TYPE_COUNTRY: + pcountryinfo = (struct ieeetypes_countryinfoset *) pos; if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) || pcountryinfo->len > 254) { lbs_deb_scan("process_bss: 11D- Err " @@ -1089,62 +1065,55 @@ static int libertas_process_bss(struct bss_descriptor * bss, (u32) (pcountryinfo->len + 2)); break; - case EXTENDED_SUPPORTED_RATES: - /* - * only process extended supported rate - * if data rate is already found. - * data rate IE should come before + case MFIE_TYPE_RATES_EX: + /* only process extended supported rate if data rate is + * already found. Data rate IE should come before * extended supported rate IE */ - if (founddatarateie) { - if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) { - bytestocopy = - (WLAN_SUPPORTED_RATES - ratesize); - } else { - bytestocopy = elemlen; - } + if (!founddatarateie) + break; - pRate = (u8 *) bss->datarates; - pRate += ratesize; - memmove(pRate, (pcurrentptr + 2), bytestocopy); - pRate = (u8 *) bss->libertas_supported_rates; - pRate += ratesize; - memmove(pRate, (pcurrentptr + 2), bytestocopy); + if ((elem->len + ratesize) > WLAN_SUPPORTED_RATES) { + bytestocopy = + (WLAN_SUPPORTED_RATES - ratesize); + } else { + bytestocopy = elem->len; + } + + pRate = (u8 *) bss->datarates; + pRate += ratesize; + memmove(pRate, elem->data, bytestocopy); + pRate = (u8 *) bss->libertas_supported_rates; + pRate += ratesize; + memmove(pRate, elem->data, bytestocopy); + break; + + case MFIE_TYPE_GENERIC: + if (elem->len >= 4 && + elem->data[0] == 0x00 && + elem->data[1] == 0x50 && + elem->data[2] == 0xf2 && + elem->data[3] == 0x01) { + bss->wpa_ie_len = min(elem->len + 2, + MAX_WPA_IE_LEN); + memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); + lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, + elem->len); } break; - case VENDOR_SPECIFIC_221: -#define IE_ID_LEN_FIELDS_BYTES 2 - pIe = (struct IE_WPA *)pcurrentptr; - - if (memcmp(pIe->oui, oui01, sizeof(oui01))) - break; - - bss->wpa_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES, - MAX_WPA_IE_LEN); - memcpy(bss->wpa_ie, pcurrentptr, bss->wpa_ie_len); - lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elemlen); - break; - case WPA2_IE: - pIe = (struct IE_WPA *)pcurrentptr; - bss->rsn_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES, - MAX_WPA_IE_LEN); - memcpy(bss->rsn_ie, pcurrentptr, bss->rsn_ie_len); - lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elemlen); - break; - case TIM: + case MFIE_TYPE_RSN: + bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); + memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); + lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elem->len); break; - case CHALLENGE_TEXT: + default: break; } - pcurrentptr += elemlen + 2; - - /* need to account for IE ID and IE len */ - bytesleftforcurrentbeacon -= (elemlen + 2); - - } /* while (bytesleftforcurrentbeacon > 2) */ + pos += elem->len + 2; + } /* Timestamp */ bss->last_scanned = jiffies; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index f4be1293cd16..2df352db1557 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -7,29 +7,6 @@ #include #include -/** IEEE type definitions */ -enum ieeetypes_elementid { - SSID = 0, - SUPPORTED_RATES, - FH_PARAM_SET, - DS_PARAM_SET, - CF_PARAM_SET, - TIM, - IBSS_PARAM_SET, - COUNTRY_INFO = 7, - - CHALLENGE_TEXT = 16, - - EXTENDED_SUPPORTED_RATES = 50, - - VENDOR_SPECIFIC_221 = 221, - - WPA_IE = 221, - WPA2_IE = 48, - - EXTRA_IE = 133, -} __attribute__ ((packed)); - #define CAPINFO_MASK (~(0x00da)) struct ieeetypes_cfparamset { From 1e838bf31c3a24596621026c7d1ca69da068af83 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 10:51:27 -0400 Subject: [PATCH 1230/2804] [PATCH] libertas: specific mesh scan for mshX interface With this patch, scanning with mshX interface will only return mesh networks. To differentiate them, a specific mesh IE in beacons/probe responses is used. This IE has been introduced in firmware release 5.110.14. Note: Even though there can be at most a single mesh per channel, this scan might return several networks in the same channel. If all nodes in a mesh network are associated to an AP, they won't produce beacons/probe responses, thus the network will not be listed. This will be fixed in future firmware releases. Scan on ethX interface is not filtered, so it will list both mesh and non-mesh networks. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/defs.h | 2 ++ drivers/net/wireless/libertas/scan.c | 10 ++++++++++ drivers/net/wireless/libertas/scan.h | 2 ++ 3 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index de0756ee15ad..a5d70c19768b 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -156,6 +156,8 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) #define MRVDRV_MAX_BEACON_INTERVAL 1000 #define MRVDRV_BEACON_INTERVAL 100 +#define MARVELL_MESH_IE_LENGTH 9 + /** INT status Bit Definition*/ #define his_cmddnldrdy 0x01 #define his_cardevent 0x02 diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 2d6bc7811b27..a98feedf001c 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1099,6 +1099,12 @@ static int libertas_process_bss(struct bss_descriptor * bss, memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elem->len); + } else if (elem->len >= MARVELL_MESH_IE_LENGTH && + elem->data[0] == 0x00 && + elem->data[1] == 0x50 && + elem->data[2] == 0x43 && + elem->data[3] == 0x04) { + bss->mesh = 1; } break; @@ -1611,6 +1617,10 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, break; } + /* For mesh device, list only mesh networks */ + if (dev == priv->mesh_dev && !iter_bss->mesh) + continue; + /* Prune old an old scan result */ stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_after(jiffies, stale_time)) { diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 2a095733f194..23c539c22634 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -170,6 +170,8 @@ struct bss_descriptor { u8 rsn_ie[MAX_WPA_IE_LEN]; size_t rsn_ie_len; + u8 mesh; + struct list_head list; }; From 9e22cb67d9a8acde7a5af6ed8cd5e74ebd6551b3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:14:49 -0400 Subject: [PATCH 1231/2804] [PATCH] libertas: remove if_bootcmd.c Move the only function in it to if_usb.c, which was its only user anyway. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Makefile | 1 - drivers/net/wireless/libertas/if_bootcmd.c | 40 ---------------------- drivers/net/wireless/libertas/if_usb.c | 24 +++++++++++++ drivers/net/wireless/libertas/if_usb.h | 1 - 4 files changed, 24 insertions(+), 42 deletions(-) delete mode 100644 drivers/net/wireless/libertas/if_bootcmd.c diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 32ed4136b0d4..61e0d6e07901 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -5,7 +5,6 @@ libertas-objs := main.o fw.o wext.o \ debugfs.o \ ethtool.o assoc.o -usb8xxx-objs += if_bootcmd.o usb8xxx-objs += if_usb.o obj-$(CONFIG_LIBERTAS) += libertas.o diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c deleted file mode 100644 index 8bca306ffad9..000000000000 --- a/drivers/net/wireless/libertas/if_bootcmd.c +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This file contains functions used in USB Boot command - * and Boot2/FW update - */ - -#include -#include -#include -#include - -#define DRV_NAME "usb8xxx" - -#include "defs.h" -#include "dev.h" -#include "if_usb.h" - -/** - * @brief This function issues Boot command to the Boot2 code - * @param ivalue 1:Boot from FW by USB-Download - * 2:Boot from FW in EEPROM - * @return 0 - */ -int if_usb_issue_boot_command(wlan_private *priv, int ivalue) -{ - struct usb_card_rec *cardp = priv->card; - struct bootcmdstr sbootcmd; - int i; - - /* Prepare command */ - sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); - sbootcmd.u8cmd_tag = ivalue; - for (i=0; i<11; i++) - sbootcmd.au8dumy[i]=0x00; - memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); - - /* Issue command */ - usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); - - return 0; -} diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 998317571ec2..11687b84c596 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -803,6 +803,30 @@ static int if_usb_register_dev(wlan_private * priv) return 0; } +/** + * @brief This function issues Boot command to the Boot2 code + * @param ivalue 1:Boot from FW by USB-Download + * 2:Boot from FW in EEPROM + * @return 0 + */ +static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) +{ + struct usb_card_rec *cardp = priv->card; + struct bootcmdstr sbootcmd; + int i; + + /* Prepare command */ + sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); + sbootcmd.u8cmd_tag = ivalue; + for (i=0; i<11; i++) + sbootcmd.au8dumy[i]=0x00; + memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); + + /* Issue command */ + usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); + + return 0; +} static int if_usb_prog_firmware(wlan_private * priv) diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 156bb485e1a6..5da8c94ca4c5 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -104,6 +104,5 @@ struct fwsyncheader { int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); void if_usb_free(struct usb_card_rec *cardp); -int if_usb_issue_boot_command(wlan_private *priv, int ivalue); #endif From 492b6da7d220b37275efb03710d57215304149fa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:16:07 -0400 Subject: [PATCH 1232/2804] [PATCH] libertas: fix mixed-case abuse in cmd_ds_802_11_scan Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/hostcmd.h | 2 +- drivers/net/wireless/libertas/scan.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 05ea54df71bd..e4fafbfa358d 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -159,7 +159,7 @@ struct cmd_ds_802_11_subscribe_event { */ struct cmd_ds_802_11_scan { u8 bsstype; - u8 BSSID[ETH_ALEN]; + u8 bssid[ETH_ALEN]; u8 tlvbuffer[1]; #if 0 mrvlietypes_ssidparamset_t ssidParamSet; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index a98feedf001c..2937f79c4a01 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1677,15 +1677,14 @@ int libertas_cmd_80211_scan(wlan_private * priv, /* Set fixed field variables in scan command */ pscan->bsstype = pscancfg->bsstype; - memcpy(pscan->BSSID, pscancfg->bssid, sizeof(pscan->BSSID)); + memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN); memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); cmd->command = cpu_to_le16(cmd_802_11_scan); /* size is equal to the sizeof(fixed portions) + the TLV len + header */ - cmd->size = cpu_to_le16(sizeof(pscan->bsstype) - + sizeof(pscan->BSSID) - + pscancfg->tlvbufferlen + S_DS_GEN); + cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN + + pscancfg->tlvbufferlen + S_DS_GEN); lbs_deb_scan("SCAN_CMD: command=%x, size=%x, seqnum=%x\n", le16_to_cpu(cmd->command), le16_to_cpu(cmd->size), From ea8da92d70c4e320c282d4e94138e40e36880be3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:18:23 -0400 Subject: [PATCH 1233/2804] [PATCH] libertas: fix mixed-case abuse in cmd_ds_802_11_ad_hoc_result Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/hostcmd.h | 4 ++-- drivers/net/wireless/libertas/join.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index e4fafbfa358d..6b5e58c88c4e 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -237,8 +237,8 @@ struct cmd_ds_802_11_associate_rsp { }; struct cmd_ds_802_11_ad_hoc_result { - u8 PAD[3]; - u8 BSSID[ETH_ALEN]; + u8 pad[3]; + u8 bssid[ETH_ALEN]; }; struct cmd_ds_802_11_set_wep { diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 2db7fbfcaeb4..526b0b9db944 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -821,7 +821,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, if (command == cmd_ret_802_11_ad_hoc_start) { /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, padhocresult->BSSID, ETH_ALEN); + memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); } /* Set the BSSID from the joined/started descriptor */ From b44898eb2c917cd397a0d8654f1c249dd3cdc67e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:18:40 -0400 Subject: [PATCH 1234/2804] [PATCH] libertas: fix mixed-case abuse in cmd_ds_802_11_ad_hoc_start Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/hostcmd.h | 2 +- drivers/net/wireless/libertas/join.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 6b5e58c88c4e..23871c0f882a 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -439,7 +439,7 @@ struct cmd_ds_802_11_rate_adapt_rateset { }; struct cmd_ds_802_11_ad_hoc_start { - u8 SSID[IW_ESSID_MAX_SIZE]; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 bsstype; __le16 beaconperiod; u8 dtimperiod; diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 526b0b9db944..db467e7876f2 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -479,8 +479,8 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, * and operational rates. */ - memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE); - memcpy(adhs->SSID, assoc_req->ssid, assoc_req->ssid_len); + memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); + memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", escape_essid(assoc_req->ssid, assoc_req->ssid_len), From 0aef64d75851c9f3545d0793f26486ed862306d8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:31:18 -0400 Subject: [PATCH 1235/2804] [PATCH] libertas: re-uppercase command defines and other constants For readability. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 22 +- drivers/net/wireless/libertas/assoc.c | 68 ++-- drivers/net/wireless/libertas/cmd.c | 322 +++++++++--------- drivers/net/wireless/libertas/cmdresp.c | 140 ++++---- drivers/net/wireless/libertas/debugfs.c | 92 ++--- drivers/net/wireless/libertas/defs.h | 50 +-- drivers/net/wireless/libertas/ethtool.c | 8 +- drivers/net/wireless/libertas/fw.c | 24 +- drivers/net/wireless/libertas/host.h | 424 ++++++++++++------------ drivers/net/wireless/libertas/hostcmd.h | 4 +- drivers/net/wireless/libertas/if_usb.c | 6 +- drivers/net/wireless/libertas/join.c | 74 ++--- drivers/net/wireless/libertas/main.c | 52 +-- drivers/net/wireless/libertas/scan.c | 20 +- drivers/net/wireless/libertas/tx.c | 2 +- drivers/net/wireless/libertas/wext.c | 86 ++--- 16 files changed, 697 insertions(+), 697 deletions(-) diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 4cf0ff7b833d..26d85ec37d9e 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -422,13 +422,13 @@ done: u8 libertas_get_scan_type_11d(u8 chan, struct parsed_region_chan_11d * parsed_region_chan) { - u8 scan_type = cmd_scan_type_passive; + u8 scan_type = CMD_SCAN_TYPE_PASSIVE; lbs_deb_enter(LBS_DEB_11D); if (wlan_channel_known_11d(chan, parsed_region_chan)) { lbs_deb_11d("11D: Found and do Active Scan\n"); - scan_type = cmd_scan_type_active; + scan_type = CMD_SCAN_TYPE_ACTIVE; } else { lbs_deb_11d("11D: Not Find and do Passive Scan\n"); } @@ -454,9 +454,9 @@ static int wlan_enable_11d(wlan_private * priv, u8 flag) /* send cmd to FW to enable/disable 11D function in FW */ ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_set, - cmd_option_waitforrsp, + CMD_802_11_SNMP_MIB, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, OID_802_11D_ENABLE, &priv->adapter->enable11d); if (ret) @@ -479,9 +479,9 @@ static int set_domain_info_11d(wlan_private * priv) return 0; } - ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) lbs_deb_11d("11D: Fail to dnld domain Info\n"); @@ -541,7 +541,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, cmd->command = cpu_to_le16(cmdno); pdomaininfo->action = cpu_to_le16(cmdoption); - if (cmdoption == cmd_act_get) { + if (cmdoption == CMD_ACT_GET) { cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, @@ -633,10 +633,10 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv, } switch (action) { - case cmd_act_set: /*Proc Set action */ + case CMD_ACT_SET: /*Proc Set action */ break; - case cmd_act_get: + case CMD_ACT_GET: break; default: lbs_deb_11d("Invalid action:%d\n", domaininfo->action); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 36586db3e1f7..5fdc96f289b8 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -175,14 +175,14 @@ static int assoc_helper_mode(wlan_private *priv, if (assoc_req->mode == IW_MODE_INFRA) { if (adapter->psstate != PS_STATE_FULL_POWER) - libertas_ps_wakeup(priv, cmd_option_waitforrsp); - adapter->psmode = wlan802_11powermodecam; + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); + adapter->psmode = WLAN802_11POWERMODECAM; } adapter->mode = assoc_req->mode; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - 0, cmd_option_waitforrsp, + CMD_802_11_SNMP_MIB, + 0, CMD_OPTION_WAITFORRSP, OID_802_11_INFRASTRUCTURE_MODE, /* Shoot me now */ (void *) (size_t) assoc_req->mode); @@ -195,9 +195,9 @@ done: static int update_channel(wlan_private * priv) { /* the channel in f/w could be out of sync, get the current channel */ - return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, - cmd_opt_802_11_rf_channel_get, - cmd_option_waitforrsp, 0, NULL); + return libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL, + CMD_OPT_802_11_RF_CHANNEL_GET, + CMD_OPTION_WAITFORRSP, 0, NULL); } void libertas_sync_channel(struct work_struct *work) @@ -227,9 +227,9 @@ static int assoc_helper_channel(wlan_private *priv, lbs_deb_assoc("ASSOC: channel: %d -> %d\n", adapter->curbssparams.channel, assoc_req->channel); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, - cmd_opt_802_11_rf_channel_set, - cmd_option_waitforrsp, 0, &assoc_req->channel); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL, + CMD_OPT_802_11_RF_CHANNEL_SET, + CMD_OPTION_WAITFORRSP, 0, &assoc_req->channel); if (ret < 0) { lbs_deb_assoc("ASSOC: channel: error setting channel."); } @@ -278,15 +278,15 @@ static int assoc_helper_wep_keys(wlan_private *priv, || assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len) { ret = libertas_prepare_and_send_command(priv, - cmd_802_11_set_wep, - cmd_act_add, - cmd_option_waitforrsp, + CMD_802_11_SET_WEP, + CMD_ACT_ADD, + CMD_OPTION_WAITFORRSP, 0, assoc_req); } else { ret = libertas_prepare_and_send_command(priv, - cmd_802_11_set_wep, - cmd_act_remove, - cmd_option_waitforrsp, + CMD_802_11_SET_WEP, + CMD_ACT_REMOVE, + CMD_OPTION_WAITFORRSP, 0, NULL); } @@ -295,9 +295,9 @@ static int assoc_helper_wep_keys(wlan_private *priv, /* enable/disable the MAC's WEP packet filter */ if (assoc_req->secinfo.wep_enabled) - adapter->currentpacketfilter |= cmd_act_mac_wep_enable; + adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE; else - adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable; + adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE; ret = libertas_set_mac_packet_filter(priv); if (ret) goto out; @@ -342,9 +342,9 @@ static int assoc_helper_secinfo(wlan_private *priv, /* Get RSN enabled/disabled */ ret = libertas_prepare_and_send_command(priv, - cmd_802_11_enable_rsn, - cmd_act_set, - cmd_option_waitforrsp, + CMD_802_11_ENABLE_RSN, + CMD_ACT_GET, + CMD_OPTION_WAITFORRSP, 0, &rsn); if (ret) { lbs_deb_assoc("Failed to get RSN status: %d", ret); @@ -359,9 +359,9 @@ static int assoc_helper_secinfo(wlan_private *priv, /* Set RSN enabled/disabled */ rsn = do_wpa; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_enable_rsn, - cmd_act_set, - cmd_option_waitforrsp, + CMD_802_11_ENABLE_RSN, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, &rsn); out: @@ -378,9 +378,9 @@ static int assoc_helper_wpa_keys(wlan_private *priv, lbs_deb_enter(LBS_DEB_ASSOC); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_key_material, - cmd_act_set, - cmd_option_waitforrsp, + CMD_802_11_KEY_MATERIAL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, assoc_req); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -412,7 +412,7 @@ static int assoc_helper_wpa_ie(wlan_private *priv, static int should_deauth_infrastructure(wlan_adapter *adapter, struct assoc_request * assoc_req) { - if (adapter->connect_status != libertas_connected) + if (adapter->connect_status != LIBERTAS_CONNECTED) return 0; if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { @@ -453,7 +453,7 @@ static int should_deauth_infrastructure(wlan_adapter *adapter, static int should_stop_adhoc(wlan_adapter *adapter, struct assoc_request * assoc_req) { - if (adapter->connect_status != libertas_connected) + if (adapter->connect_status != LIBERTAS_CONNECTED) return 0; if (libertas_ssid_cmp(adapter->curbssparams.ssid, @@ -623,7 +623,7 @@ void libertas_association_worker(struct work_struct *work) success = 0; } - if (adapter->connect_status != libertas_connected) { + if (adapter->connect_status != LIBERTAS_CONNECTED) { lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, " "not connected.\n"); success = 0; @@ -636,12 +636,12 @@ void libertas_association_worker(struct work_struct *work) adapter->curbssparams.ssid_len), MAC_ARG(adapter->curbssparams.bssid)); libertas_prepare_and_send_command(priv, - cmd_802_11_rssi, - 0, cmd_option_waitforrsp, 0, NULL); + CMD_802_11_RSSI, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); libertas_prepare_and_send_command(priv, - cmd_802_11_get_log, - 0, cmd_option_waitforrsp, 0, NULL); + CMD_802_11_GET_LOG, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); } else { ret = -1; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 355a3960323b..e0eab6e3a9b0 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -15,7 +15,7 @@ static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode); static u16 commands_allowed_in_ps[] = { - cmd_802_11_rssi, + CMD_802_11_RSSI, }; /** @@ -43,7 +43,7 @@ static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd) lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_get_hw_spec); + cmd->command = cpu_to_le16(CMD_GET_HW_SPEC); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN); memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN); @@ -60,13 +60,13 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_ps_mode); + cmd->command = cpu_to_le16(CMD_802_11_PS_MODE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) + S_DS_GEN); psm->action = cpu_to_le16(cmd_action); psm->multipledtim = 0; switch (cmd_action) { - case cmd_subcmd_enter_ps: + case CMD_SUBCMD_ENTER_PS: lbs_deb_cmd("PS command:" "SubCode- Enter PS\n"); lbs_deb_cmd("locallisteninterval = %d\n", adapter->locallisteninterval); @@ -79,11 +79,11 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, cpu_to_le16(priv->adapter->multipledtim); break; - case cmd_subcmd_exit_ps: + case CMD_SUBCMD_EXIT_PS: lbs_deb_cmd("PS command:" "SubCode- Exit PS\n"); break; - case cmd_subcmd_sleep_confirmed: + case CMD_SUBCMD_SLEEP_CONFIRMED: lbs_deb_cmd("PS command: SubCode- sleep confirm\n"); break; @@ -101,7 +101,7 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, { u16 *timeout = pdata_buf; - cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout); + cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout) + S_DS_GEN); @@ -127,13 +127,13 @@ static int wlan_cmd_802_11_sleep_params(wlan_private * priv, cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_sleep_params); + cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS); - if (cmd_action == cmd_act_get) { + if (cmd_action == CMD_ACT_GET) { memset(&adapter->sp, 0, sizeof(struct sleep_params)); memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params)); sp->action = cpu_to_le16(cmd_action); - } else if (cmd_action == cmd_act_set) { + } else if (cmd_action == CMD_ACT_SET) { sp->action = cpu_to_le16(cmd_action); sp->error = cpu_to_le16(adapter->sp.sp_error); sp->offset = cpu_to_le16(adapter->sp.sp_offset); @@ -159,10 +159,10 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_set_wep); + cmd->command = cpu_to_le16(CMD_802_11_SET_WEP); cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN); - if (cmd_act == cmd_act_add) { + if (cmd_act == CMD_ACT_ADD) { int i; if (!assoc_req) { @@ -171,11 +171,11 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, goto done; } - wep->action = cpu_to_le16(cmd_act_add); + wep->action = cpu_to_le16(CMD_ACT_ADD); /* default tx key index */ wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx & - (u32)cmd_WEP_KEY_INDEX_MASK)); + (u32)CMD_WEP_KEY_INDEX_MASK)); lbs_deb_cmd("Tx key Index: %u\n", le16_to_cpu(wep->keyindex)); @@ -186,13 +186,13 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, switch (pkey->len) { case KEY_LEN_WEP_40: wep->keytype[i] = - cpu_to_le16(cmd_type_wep_40_bit); + cpu_to_le16(CMD_TYPE_WEP_40_BIT); memmove(&wep->keymaterial[i], pkey->key, pkey->len); break; case KEY_LEN_WEP_104: wep->keytype[i] = - cpu_to_le16(cmd_type_wep_104_bit); + cpu_to_le16(CMD_TYPE_WEP_104_BIT); memmove(&wep->keymaterial[i], pkey->key, pkey->len); break; @@ -206,13 +206,13 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, break; } } - } else if (cmd_act == cmd_act_remove) { + } else if (cmd_act == CMD_ACT_REMOVE) { /* ACT_REMOVE clears _all_ WEP keys */ - wep->action = cpu_to_le16(cmd_act_remove); + wep->action = cpu_to_le16(CMD_ACT_REMOVE); /* default tx key index */ wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx & - (u32)cmd_WEP_KEY_INDEX_MASK)); + (u32)CMD_WEP_KEY_INDEX_MASK)); } ret = 0; @@ -232,15 +232,15 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_enable_rsn); + cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN); cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN); penableRSN->action = cpu_to_le16(cmd_action); - if (cmd_action == cmd_act_set) { + if (cmd_action == CMD_ACT_SET) { if (*enable) - penableRSN->enable = cpu_to_le16(cmd_enable_rsn); + penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN); else - penableRSN->enable = cpu_to_le16(cmd_disable_rsn); + penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN); } lbs_deb_leave(LBS_DEB_CMD); @@ -284,10 +284,10 @@ static int wlan_cmd_802_11_key_material(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_key_material); + cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL); pkeymaterial->action = cpu_to_le16(cmd_action); - if (cmd_action == cmd_act_get) { + if (cmd_action == CMD_ACT_GET) { cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action)); ret = 0; goto done; @@ -323,7 +323,7 @@ static int wlan_cmd_802_11_reset(wlan_private * priv, { struct cmd_ds_802_11_reset *reset = &cmd->params.reset; - cmd->command = cpu_to_le16(cmd_802_11_reset); + cmd->command = cpu_to_le16(CMD_802_11_RESET); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); reset->action = cpu_to_le16(cmd_action); @@ -333,7 +333,7 @@ static int wlan_cmd_802_11_reset(wlan_private * priv, static int wlan_cmd_802_11_get_log(wlan_private * priv, struct cmd_ds_command *cmd) { - cmd->command = cpu_to_le16(cmd_802_11_get_log); + cmd->command = cpu_to_le16(CMD_802_11_GET_LOG); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN); @@ -343,7 +343,7 @@ static int wlan_cmd_802_11_get_log(wlan_private * priv, static int wlan_cmd_802_11_get_stat(wlan_private * priv, struct cmd_ds_command *cmd) { - cmd->command = cpu_to_le16(cmd_802_11_get_stat); + cmd->command = cpu_to_le16(CMD_802_11_GET_STAT); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN); @@ -363,15 +363,15 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); - cmd->command = cpu_to_le16(cmd_802_11_snmp_mib); + cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB); cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN); switch (cmd_oid) { case OID_802_11_INFRASTRUCTURE_MODE: { u8 mode = (u8) (size_t) pdata_buf; - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); - pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i); + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); + pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I); pSNMPMIB->bufsize = sizeof(u8); if (mode == IW_MODE_ADHOC) { ucTemp = SNMP_MIB_VALUE_ADHOC; @@ -389,10 +389,10 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, { u32 ulTemp; - pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i); + pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I); - if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cmd_act_set; + if (cmd_action == CMD_ACT_SET) { + pSNMPMIB->querytype = CMD_ACT_SET; pSNMPMIB->bufsize = sizeof(u16); ulTemp = *(u32 *)pdata_buf; *((__le16 *)(pSNMPMIB->value)) = @@ -405,12 +405,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, { u32 ulTemp; - pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i); + pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I); - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); + if (cmd_action == CMD_ACT_GET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); + } else if (cmd_action == CMD_ACT_SET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); ulTemp = *((u32 *) pdata_buf); *((__le16 *)(pSNMPMIB->value)) = @@ -425,12 +425,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, { u32 ulTemp; - pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i); + pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I); - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); + if (cmd_action == CMD_ACT_GET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); + } else if (cmd_action == CMD_ACT_SET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); ulTemp = *((u32 *)pdata_buf); *(__le16 *)(pSNMPMIB->value) = @@ -440,12 +440,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, break; } case OID_802_11_TX_RETRYCOUNT: - pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i); + pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I); - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); + if (cmd_action == CMD_ACT_GET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); + } else if (cmd_action == CMD_ACT_SET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); *((__le16 *)(pSNMPMIB->value)) = cpu_to_le16((u16) adapter->txretrycount); @@ -483,20 +483,20 @@ static int wlan_cmd_802_11_radio_control(wlan_private * priv, cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_radio_control); + cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL); pradiocontrol->action = cpu_to_le16(cmd_action); switch (adapter->preamble) { - case cmd_type_short_preamble: + case CMD_TYPE_SHORT_PREAMBLE: pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE); break; - case cmd_type_long_preamble: + case CMD_TYPE_LONG_PREAMBLE: pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE); break; - case cmd_type_auto_preamble: + case CMD_TYPE_AUTO_PREAMBLE: default: pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE); break; @@ -522,7 +522,7 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power); + cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER); prtp->action = cpu_to_le16(cmd_action); lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", @@ -530,23 +530,23 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, le16_to_cpu(prtp->action)); switch (cmd_action) { - case cmd_act_tx_power_opt_get: - prtp->action = cpu_to_le16(cmd_act_get); + case CMD_ACT_TX_POWER_OPT_GET: + prtp->action = cpu_to_le16(CMD_ACT_GET); prtp->currentlevel = 0; break; - case cmd_act_tx_power_opt_set_high: - prtp->action = cpu_to_le16(cmd_act_set); - prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_high); + case CMD_ACT_TX_POWER_OPT_SET_HIGH: + prtp->action = cpu_to_le16(CMD_ACT_SET); + prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH); break; - case cmd_act_tx_power_opt_set_mid: - prtp->action = cpu_to_le16(cmd_act_set); - prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_mid); + case CMD_ACT_TX_POWER_OPT_SET_MID: + prtp->action = cpu_to_le16(CMD_ACT_SET); + prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID); break; - case cmd_act_tx_power_opt_set_low: - prtp->action = cpu_to_le16(cmd_act_set); + case CMD_ACT_TX_POWER_OPT_SET_LOW: + prtp->action = cpu_to_le16(CMD_ACT_SET); prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); break; } @@ -561,12 +561,12 @@ static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, { struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; - cmd->command = cpu_to_le16(cmd_802_11_rf_antenna); + cmd->command = cpu_to_le16(CMD_802_11_RF_ANTENNA); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + S_DS_GEN); rant->action = cpu_to_le16(cmd_action); - if ((cmd_action == cmd_act_set_rx) || (cmd_action == cmd_act_set_tx)) { + if ((cmd_action == CMD_ACT_SET_rx) || (cmd_action == CMD_ACT_SET_tx)) { rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf)); } @@ -584,7 +584,7 @@ static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset); + cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET); lbs_deb_enter(LBS_DEB_CMD); @@ -608,17 +608,17 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_data_rate); + cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE); memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); pdatarate->action = cpu_to_le16(cmd_action); - if (cmd_action == cmd_act_set_tx_fix_rate) { + if (cmd_action == CMD_ACT_SET_tx_fix_rate) { pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", adapter->datarate); - } else if (cmd_action == cmd_act_set_tx_auto) { + } else if (cmd_action == CMD_ACT_SET_tx_auto) { lbs_deb_cmd("Setting FW for AUTO rate\n"); } @@ -635,7 +635,7 @@ static int wlan_cmd_mac_multicast_adr(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_mac_multicast_adr); + cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR); pMCastAdr->action = cpu_to_le16(cmd_action); pMCastAdr->nr_of_adrs = @@ -652,11 +652,11 @@ static int wlan_cmd_802_11_rf_channel(wlan_private * priv, { struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel; - cmd->command = cpu_to_le16(cmd_802_11_rf_channel); + cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) + S_DS_GEN); - if (option == cmd_opt_802_11_rf_channel_set) { + if (option == CMD_OPT_802_11_RF_CHANNEL_SET) { rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf)); } @@ -670,7 +670,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, { wlan_adapter *adapter = priv->adapter; - cmd->command = cpu_to_le16(cmd_802_11_rssi); + cmd->command = cpu_to_le16(CMD_802_11_RSSI); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor); @@ -696,7 +696,7 @@ static int wlan_cmd_reg_access(wlan_private * priv, offval = (struct wlan_offset_value *)pdata_buf; switch (cmdptr->command) { - case cmd_mac_reg_access: + case CMD_MAC_REG_ACCESS: { struct cmd_ds_mac_reg_access *macreg; @@ -714,7 +714,7 @@ static int wlan_cmd_reg_access(wlan_private * priv, break; } - case cmd_bbp_reg_access: + case CMD_BBP_REG_ACCESS: { struct cmd_ds_bbp_reg_access *bbpreg; @@ -733,7 +733,7 @@ static int wlan_cmd_reg_access(wlan_private * priv, break; } - case cmd_rf_reg_access: + case CMD_RF_REG_ACCESS: { struct cmd_ds_rf_reg_access *rfreg; @@ -766,14 +766,14 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, { wlan_adapter *adapter = priv->adapter; - cmd->command = cpu_to_le16(cmd_802_11_mac_address); + cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + S_DS_GEN); cmd->result = 0; cmd->params.macadd.action = cpu_to_le16(cmd_action); - if (cmd_action == cmd_act_set) { + if (cmd_action == CMD_ACT_SET) { memcpy(cmd->params.macadd.macadd, adapter->current_addr, ETH_ALEN); lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6); @@ -790,7 +790,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_eeprom_access); + cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) + S_DS_GEN); cmd->result = 0; @@ -810,29 +810,29 @@ static int wlan_cmd_bt_access(wlan_private * priv, struct cmd_ds_bt_access *bt_access = &cmd->params.bt; lbs_deb_cmd("BT CMD(%d)\n", cmd_action); - cmd->command = cpu_to_le16(cmd_bt_access); + cmd->command = cpu_to_le16(CMD_BT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN); cmd->result = 0; bt_access->action = cpu_to_le16(cmd_action); switch (cmd_action) { - case cmd_act_bt_access_add: + case CMD_ACT_BT_ACCESS_ADD: memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6); break; - case cmd_act_bt_access_del: + case CMD_ACT_BT_ACCESS_DEL: memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6); break; - case cmd_act_bt_access_list: + case CMD_ACT_BT_ACCESS_LIST: bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); break; - case cmd_act_bt_access_reset: + case CMD_ACT_BT_ACCESS_RESET: break; - case cmd_act_bt_access_set_invert: + case CMD_ACT_BT_ACCESS_SET_INVERT: bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); break; - case cmd_act_bt_access_get_invert: + case CMD_ACT_BT_ACCESS_GET_INVERT: break; default: break; @@ -847,7 +847,7 @@ static int wlan_cmd_fwt_access(wlan_private * priv, struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; lbs_deb_cmd("FWT CMD(%d)\n", cmd_action); - cmd->command = cpu_to_le16(cmd_fwt_access); + cmd->command = cpu_to_le16(CMD_FWT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN); cmd->result = 0; @@ -868,7 +868,7 @@ static int wlan_cmd_mesh_access(wlan_private * priv, struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh; lbs_deb_cmd("FWT CMD(%d)\n", cmd_action); - cmd->command = cpu_to_le16(cmd_mesh_access); + cmd->command = cpu_to_le16(CMD_MESH_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN); cmd->result = 0; @@ -901,9 +901,9 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u } /* Exit_PS command needs to be queued in the header always. */ - if (cmdptr->command == cmd_802_11_ps_mode) { + if (cmdptr->command == CMD_802_11_PS_MODE) { struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; - if (psm->action == cpu_to_le16(cmd_subcmd_exit_ps)) { + if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { if (adapter->psstate != PS_STATE_FULL_POWER) addtail = 0; } @@ -1000,8 +1000,8 @@ static int DownloadcommandToStation(wlan_private * priv, lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize); /* Setup the timer after transmit command */ - if (command == cmd_802_11_scan || command == cmd_802_11_authenticate - || command == cmd_802_11_associate) + if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE + || command == CMD_802_11_ASSOCIATE) mod_timer(&adapter->command_timer, jiffies + (10*HZ)); else mod_timer(&adapter->command_timer, jiffies + (5*HZ)); @@ -1020,7 +1020,7 @@ static int wlan_cmd_mac_control(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_mac_control); + cmd->command = cpu_to_le16(CMD_MAC_CONTROL); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); mac->action = cpu_to_le16(priv->adapter->currentpacketfilter); @@ -1064,9 +1064,9 @@ int libertas_set_radio_control(wlan_private * priv) lbs_deb_enter(LBS_DEB_CMD); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_radio_control, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_RADIO_CONTROL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); lbs_deb_cmd("RADIO_SET: on or off: 0x%X, preamble = 0x%X\n", priv->adapter->radioon, priv->adapter->preamble); @@ -1086,7 +1086,7 @@ int libertas_set_mac_packet_filter(wlan_private * priv) /* Send MAC control command to station */ ret = libertas_prepare_and_send_command(priv, - cmd_mac_control, 0, 0, 0, NULL); + CMD_MAC_CONTROL, 0, 0, 0, NULL); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; @@ -1161,136 +1161,136 @@ int libertas_prepare_and_send_command(wlan_private * priv, cmdptr->result = 0; switch (cmd_no) { - case cmd_get_hw_spec: + case CMD_GET_HW_SPEC: ret = wlan_cmd_hw_spec(priv, cmdptr); break; - case cmd_802_11_ps_mode: + case CMD_802_11_PS_MODE: ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); break; - case cmd_802_11_scan: + case CMD_802_11_SCAN: ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf); break; - case cmd_mac_control: + case CMD_MAC_CONTROL: ret = wlan_cmd_mac_control(priv, cmdptr); break; - case cmd_802_11_associate: - case cmd_802_11_reassociate: + case CMD_802_11_ASSOCIATE: + case CMD_802_11_REASSOCIATE: ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case cmd_802_11_deauthenticate: + case CMD_802_11_DEAUTHENTICATE: ret = libertas_cmd_80211_deauthenticate(priv, cmdptr); break; - case cmd_802_11_set_wep: + case CMD_802_11_SET_WEP: ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_ad_hoc_start: + case CMD_802_11_AD_HOC_START: ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); break; - case cmd_code_dnld: + case CMD_CODE_DNLD: break; - case cmd_802_11_reset: + case CMD_802_11_RESET: ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action); break; - case cmd_802_11_get_log: + case CMD_802_11_GET_LOG: ret = wlan_cmd_802_11_get_log(priv, cmdptr); break; - case cmd_802_11_authenticate: + case CMD_802_11_AUTHENTICATE: ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf); break; - case cmd_802_11_get_stat: + case CMD_802_11_GET_STAT: ret = wlan_cmd_802_11_get_stat(priv, cmdptr); break; - case cmd_802_11_snmp_mib: + case CMD_802_11_SNMP_MIB: ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); break; - case cmd_mac_reg_access: - case cmd_bbp_reg_access: - case cmd_rf_reg_access: + case CMD_MAC_REG_ACCESS: + case CMD_BBP_REG_ACCESS: + case CMD_RF_REG_ACCESS: ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_rf_channel: + case CMD_802_11_RF_CHANNEL: ret = wlan_cmd_802_11_rf_channel(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_rf_tx_power: + case CMD_802_11_RF_TX_POWER: ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_radio_control: + case CMD_802_11_RADIO_CONTROL: ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); break; - case cmd_802_11_rf_antenna: + case CMD_802_11_RF_ANTENNA: ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_data_rate: + case CMD_802_11_DATA_RATE: ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); break; - case cmd_802_11_rate_adapt_rateset: + case CMD_802_11_RATE_ADAPT_RATESET: ret = wlan_cmd_802_11_rate_adapt_rateset(priv, cmdptr, cmd_action); break; - case cmd_mac_multicast_adr: + case CMD_MAC_MULTICAST_ADR: ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); break; - case cmd_802_11_ad_hoc_join: + case CMD_802_11_AD_HOC_JOIN: ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); break; - case cmd_802_11_rssi: + case CMD_802_11_RSSI: ret = wlan_cmd_802_11_rssi(priv, cmdptr); break; - case cmd_802_11_ad_hoc_stop: + case CMD_802_11_AD_HOC_STOP: ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr); break; - case cmd_802_11_enable_rsn: + case CMD_802_11_ENABLE_RSN: ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_key_material: + case CMD_802_11_KEY_MATERIAL: ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); break; - case cmd_802_11_pairwise_tsc: + case CMD_802_11_PAIRWISE_TSC: break; - case cmd_802_11_group_tsc: + case CMD_802_11_GROUP_TSC: break; - case cmd_802_11_mac_address: + case CMD_802_11_MAC_ADDRESS: ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action); break; - case cmd_802_11_eeprom_access: + case CMD_802_11_EEPROM_ACCESS: ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_set_afc: - case cmd_802_11_get_afc: + case CMD_802_11_SET_AFC: + case CMD_802_11_GET_AFC: cmdptr->command = cpu_to_le16(cmd_no); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) + @@ -1302,22 +1302,22 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; goto done; - case cmd_802_11d_domain_info: + case CMD_802_11D_DOMAIN_INFO: ret = libertas_cmd_802_11d_domain_info(priv, cmdptr, cmd_no, cmd_action); break; - case cmd_802_11_sleep_params: + case CMD_802_11_SLEEP_PARAMS: ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action); break; - case cmd_802_11_inactivity_timeout: + case CMD_802_11_INACTIVITY_TIMEOUT: ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr, cmd_action, pdata_buf); libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf); break; - case cmd_802_11_tpc_cfg: - cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg); + case CMD_802_11_TPC_CFG: + cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) + S_DS_GEN); @@ -1327,7 +1327,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; - case cmd_802_11_led_gpio_ctrl: + case CMD_802_11_LED_GPIO_CTRL: { struct mrvlietypes_ledgpio *gpio = (struct mrvlietypes_ledgpio*) @@ -1338,7 +1338,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, sizeof(struct cmd_ds_802_11_led_ctrl)); cmdptr->command = - cpu_to_le16(cmd_802_11_led_gpio_ctrl); + cpu_to_le16(CMD_802_11_LED_GPIO_CTRL); #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 cmdptr->size = @@ -1349,8 +1349,8 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; } - case cmd_802_11_pwr_cfg: - cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg); + case CMD_802_11_PWR_CFG: + cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) + S_DS_GEN); @@ -1359,26 +1359,26 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; - case cmd_bt_access: + case CMD_BT_ACCESS: ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_fwt_access: + case CMD_FWT_ACCESS: ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_mesh_access: + case CMD_MESH_ACCESS: ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_get_tsf: - cmdptr->command = cpu_to_le16(cmd_get_tsf); + case CMD_GET_TSF: + cmdptr->command = cpu_to_le16(CMD_GET_TSF); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) + S_DS_GEN); ret = 0; break; - case cmd_802_11_tx_rate_query: - cmdptr->command = cpu_to_le16(cmd_802_11_tx_rate_query); + case CMD_802_11_TX_RATE_QUERY: + cmdptr->command = cpu_to_le16(CMD_802_11_TX_RATE_QUERY); cmdptr->size = cpu_to_le16(sizeof(struct cmd_tx_rate_query) + S_DS_GEN); adapter->txrate = 0; @@ -1404,7 +1404,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, adapter->nr_cmd_pending++; wake_up_interruptible(&priv->mainthread.waitq); - if (wait_option & cmd_option_waitforrsp) { + if (wait_option & CMD_OPTION_WAITFORRSP) { lbs_deb_cmd("PREP_CMD: Wait for CMD response\n"); might_sleep(); wait_event_interruptible(cmdnode->cmdwait_q, @@ -1680,7 +1680,7 @@ int libertas_execute_next_command(wlan_private * priv) * immediately. */ if (cmdptr->command != - cpu_to_le16(cmd_802_11_ps_mode)) { + cpu_to_le16(CMD_802_11_PS_MODE)) { /* Prepare to send Exit PS, * this non PS command will be sent later */ if ((adapter->psstate == PS_STATE_SLEEP) @@ -1706,7 +1706,7 @@ int libertas_execute_next_command(wlan_private * priv) "EXEC_NEXT_CMD: PS cmd- action=0x%x\n", psm->action); if (psm->action != - cpu_to_le16(cmd_subcmd_exit_ps)) { + cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { lbs_deb_cmd( "EXEC_NEXT_CMD: Ignore Enter PS cmd\n"); list_del((struct list_head *)cmdnode); @@ -1741,9 +1741,9 @@ int libertas_execute_next_command(wlan_private * priv) * check if in power save mode, if yes, put the device back * to PS mode */ - if ((adapter->psmode != wlan802_11powermodecam) && + if ((adapter->psmode != WLAN802_11POWERMODECAM) && (adapter->psstate == PS_STATE_FULL_POWER) && - (adapter->connect_status == libertas_connected)) { + (adapter->connect_status == LIBERTAS_CONNECTED)) { if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { /* check for valid WPA group keys */ @@ -1845,8 +1845,8 @@ void libertas_ps_sleep(wlan_private * priv, int wait_option) * Remove this check if it is to be supported in IBSS mode also */ - libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, - cmd_subcmd_enter_ps, wait_option, 0, NULL); + libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL); lbs_deb_leave(LBS_DEB_CMD); } @@ -1864,12 +1864,12 @@ void libertas_ps_wakeup(wlan_private * priv, int wait_option) lbs_deb_enter(LBS_DEB_CMD); - Localpsmode = cpu_to_le32(wlan802_11powermodecam); + Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM); - lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", wlan802_11powermodecam); + lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", WLAN802_11POWERMODECAM); - libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, - cmd_subcmd_exit_ps, + libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + CMD_SUBCMD_EXIT_PS, wait_option, 0, &Localpsmode); lbs_deb_leave(LBS_DEB_CMD); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 89bd43c2efa3..4c15071984b9 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -28,7 +28,7 @@ void libertas_mac_event_disconnected(wlan_private * priv) wlan_adapter *adapter = priv->adapter; union iwreq_data wrqu; - if (adapter->connect_status != libertas_connected) + if (adapter->connect_status != LIBERTAS_CONNECTED) return; lbs_deb_cmd("Handles disconnect event.\n"); @@ -69,7 +69,7 @@ void libertas_mac_event_disconnected(wlan_private * priv) escape_essid(adapter->prev_ssid, adapter->prev_ssid_len), adapter->prev_ssid_len); - adapter->connect_status = libertas_disconnected; + adapter->connect_status = LIBERTAS_DISCONNECTED; /* Save previous SSID and BSSID for possible reassociation */ memcpy(&adapter->prev_ssid, &adapter->curbssparams.ssid, @@ -124,7 +124,7 @@ static int wlan_ret_reg_access(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); switch (type) { - case cmd_ret_mac_reg_access: + case CMD_RET_MAC_REG_ACCESS: { struct cmd_ds_mac_reg_access *reg = &resp->params.macreg; @@ -133,7 +133,7 @@ static int wlan_ret_reg_access(wlan_private * priv, break; } - case cmd_ret_bbp_reg_access: + case CMD_RET_BBP_REG_ACCESS: { struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg; @@ -142,7 +142,7 @@ static int wlan_ret_reg_access(wlan_private * priv, break; } - case cmd_ret_rf_reg_access: + case CMD_RET_RF_REG_ACCESS: { struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg; @@ -274,21 +274,21 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv, querytype); lbs_deb_cmd("SNMP_RESP: Buf size = %x\n", le16_to_cpu(smib->bufsize)); - if (querytype == cmd_act_get) { + if (querytype == CMD_ACT_GET) { switch (oid) { - case fragthresh_i: + case FRAGTHRESH_I: priv->adapter->fragthsd = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: fragthsd =%u\n", priv->adapter->fragthsd); break; - case rtsthresh_i: + case RTSTHRESH_I: priv->adapter->rtsthsd = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: rtsthsd =%u\n", priv->adapter->rtsthsd); break; - case short_retrylim_i: + case SHORT_RETRYLIM_I: priv->adapter->txretrycount = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: txretrycount =%u\n", @@ -314,7 +314,7 @@ static int wlan_ret_802_11_key_material(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); /* Copy the returned key to driver private data */ - if (action == cmd_act_get) { + if (action == CMD_ACT_GET) { u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); @@ -396,10 +396,10 @@ static int wlan_ret_802_11_rf_antenna(wlan_private * priv, wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(pAntenna->action); - if (action == cmd_act_get_rx) + if (action == CMD_ACT_GET_rx) adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode); - if (action == cmd_act_get_tx) + if (action == CMD_ACT_GET_tx) adapter->txantennamode = le16_to_cpu(pAntenna->antennamode); lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", @@ -416,7 +416,7 @@ static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - if (rates->action == cmd_act_get) { + if (rates->action == CMD_ACT_GET) { adapter->enablehwauto = le16_to_cpu(rates->enablehwauto); adapter->ratebitmap = le16_to_cpu(rates->bitmap); } @@ -438,7 +438,7 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); dot11datarate = pdatarate->datarate[0]; - if (pdatarate->action == cpu_to_le16(cmd_act_get_tx_rate)) { + if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_tx_rate)) { memcpy(adapter->libertas_supported_rates, pdatarate->datarate, sizeof(adapter->libertas_supported_rates)); } @@ -458,7 +458,7 @@ static int wlan_ret_802_11_rf_channel(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - if (action == cmd_opt_802_11_rf_channel_get + if (action == CMD_OPT_802_11_RF_CHANNEL_GET && adapter->curbssparams.channel != newchannel) { lbs_deb_cmd("channel Switch: %d to %d\n", adapter->curbssparams.channel, newchannel); @@ -547,7 +547,7 @@ static int libertas_ret_802_11_enable_rsn(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - if (enable_rsn->action == cpu_to_le16(cmd_act_get)) { + if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) { if (pdata_buf) *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable); } @@ -565,134 +565,134 @@ static inline int handle_cmd_response(u16 respcmd, wlan_adapter *adapter = priv->adapter; switch (respcmd) { - case cmd_ret_mac_reg_access: - case cmd_ret_bbp_reg_access: - case cmd_ret_rf_reg_access: + case CMD_RET_MAC_REG_ACCESS: + case CMD_RET_BBP_REG_ACCESS: + case CMD_RET_RF_REG_ACCESS: ret = wlan_ret_reg_access(priv, respcmd, resp); break; - case cmd_ret_hw_spec_info: + case CMD_RET_HW_SPEC_INFO: ret = wlan_ret_get_hw_spec(priv, resp); break; - case cmd_ret_802_11_scan: + case CMD_RET_802_11_SCAN: ret = libertas_ret_80211_scan(priv, resp); break; - case cmd_ret_802_11_get_log: + case CMD_RET_802_11_GET_LOG: ret = wlan_ret_get_log(priv, resp); break; - case cmd_ret_802_11_associate: - case cmd_ret_802_11_reassociate: + case CMD_RET_802_11_ASSOCIATE: + case CMD_RET_802_11_REASSOCIATE: ret = libertas_ret_80211_associate(priv, resp); break; - case cmd_ret_802_11_disassociate: - case cmd_ret_802_11_deauthenticate: + case CMD_RET_802_11_DISASSOCIATE: + case CMD_RET_802_11_DEAUTHENTICATE: ret = libertas_ret_80211_disassociate(priv, resp); break; - case cmd_ret_802_11_ad_hoc_start: - case cmd_ret_802_11_ad_hoc_join: + case CMD_RET_802_11_AD_HOC_START: + case CMD_RET_802_11_AD_HOC_JOIN: ret = libertas_ret_80211_ad_hoc_start(priv, resp); break; - case cmd_ret_802_11_stat: + case CMD_RET_802_11_STAT: ret = wlan_ret_802_11_stat(priv, resp); break; - case cmd_ret_802_11_snmp_mib: + case CMD_RET_802_11_SNMP_MIB: ret = wlan_ret_802_11_snmp_mib(priv, resp); break; - case cmd_ret_802_11_rf_tx_power: + case CMD_RET_802_11_RF_TX_POWER: ret = wlan_ret_802_11_rf_tx_power(priv, resp); break; - case cmd_ret_802_11_set_afc: - case cmd_ret_802_11_get_afc: + case CMD_RET_802_11_SET_AFC: + case CMD_RET_802_11_GET_AFC: spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc, sizeof(struct cmd_ds_802_11_afc)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_802_11_rf_antenna: + case CMD_RET_802_11_RF_ANTENNA: ret = wlan_ret_802_11_rf_antenna(priv, resp); break; - case cmd_ret_mac_multicast_adr: - case cmd_ret_mac_control: - case cmd_ret_802_11_set_wep: - case cmd_ret_802_11_reset: - case cmd_ret_802_11_authenticate: - case cmd_ret_802_11_radio_control: - case cmd_ret_802_11_beacon_stop: + case CMD_RET_MAC_MULTICAST_ADR: + case CMD_RET_MAC_CONTROL: + case CMD_RET_802_11_SET_WEP: + case CMD_RET_802_11_RESET: + case CMD_RET_802_11_AUTHENTICATE: + case CMD_RET_802_11_RADIO_CONTROL: + case CMD_RET_802_11_BEACON_STOP: break; - case cmd_ret_802_11_enable_rsn: + case CMD_RET_802_11_ENABLE_RSN: ret = libertas_ret_802_11_enable_rsn(priv, resp); break; - case cmd_ret_802_11_data_rate: + case CMD_RET_802_11_DATA_RATE: ret = wlan_ret_802_11_data_rate(priv, resp); break; - case cmd_ret_802_11_rate_adapt_rateset: + case CMD_RET_802_11_RATE_ADAPT_RATESET: ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); break; - case cmd_ret_802_11_rf_channel: + case CMD_RET_802_11_RF_CHANNEL: ret = wlan_ret_802_11_rf_channel(priv, resp); break; - case cmd_ret_802_11_rssi: + case CMD_RET_802_11_RSSI: ret = wlan_ret_802_11_rssi(priv, resp); break; - case cmd_ret_802_11_mac_address: + case CMD_RET_802_11_MAC_ADDRESS: ret = wlan_ret_802_11_mac_address(priv, resp); break; - case cmd_ret_802_11_ad_hoc_stop: + case CMD_RET_802_11_AD_HOC_STOP: ret = libertas_ret_80211_ad_hoc_stop(priv, resp); break; - case cmd_ret_802_11_key_material: + case CMD_RET_802_11_KEY_MATERIAL: lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n"); ret = wlan_ret_802_11_key_material(priv, resp); break; - case cmd_ret_802_11_eeprom_access: + case CMD_RET_802_11_EEPROM_ACCESS: ret = wlan_ret_802_11_eeprom_access(priv, resp); break; - case cmd_ret_802_11d_domain_info: + case CMD_RET_802_11D_DOMAIN_INFO: ret = libertas_ret_802_11d_domain_info(priv, resp); break; - case cmd_ret_802_11_sleep_params: + case CMD_RET_802_11_SLEEP_PARAMS: ret = wlan_ret_802_11_sleep_params(priv, resp); break; - case cmd_ret_802_11_inactivity_timeout: + case CMD_RET_802_11_INACTIVITY_TIMEOUT: spin_lock_irqsave(&adapter->driver_lock, flags); *((u16 *) adapter->cur_cmd->pdata_buf) = le16_to_cpu(resp->params.inactivity_timeout.timeout); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_802_11_tpc_cfg: + case CMD_RET_802_11_TPC_CFG: spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg, sizeof(struct cmd_ds_802_11_tpc_cfg)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_802_11_led_gpio_ctrl: + case CMD_RET_802_11_LED_GPIO_CTRL: spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio, sizeof(struct cmd_ds_802_11_led_ctrl)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_802_11_pwr_cfg: + case CMD_RET_802_11_PWR_CFG: spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg, sizeof(struct cmd_ds_802_11_pwr_cfg)); @@ -700,32 +700,32 @@ static inline int handle_cmd_response(u16 respcmd, break; - case cmd_ret_get_tsf: + case CMD_RET_GET_TSF: spin_lock_irqsave(&adapter->driver_lock, flags); memcpy(priv->adapter->cur_cmd->pdata_buf, &resp->params.gettsf.tsfvalue, sizeof(u64)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_bt_access: + case CMD_RET_BT_ACCESS: spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.bt.addr1, 2 * ETH_ALEN); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_fwt_access: + case CMD_RET_FWT_ACCESS: spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt, sizeof(resp->params.fwt)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_mesh_access: + case CMD_RET_MESH_ACCESS: if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh, sizeof(resp->params.mesh)); break; - case cmd_rte_802_11_tx_rate_query: + case CMD_RTE_802_11_TX_RATE_QUERY: priv->adapter->txrate = resp->params.txrate.txrate; break; default: @@ -787,7 +787,7 @@ int libertas_process_rx_command(wlan_private * priv) /* Store the response code to cur_cmd_retcode. */ adapter->cur_cmd_retcode = result;; - if (respcmd == cmd_ret_802_11_ps_mode) { + if (respcmd == CMD_RET_802_11_PS_MODE) { struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; u16 action = le16_to_cpu(psmode->action); @@ -804,14 +804,14 @@ int libertas_process_rx_command(wlan_private * priv) * libertas_execute_next_command(). */ if (adapter->mode == IW_MODE_ADHOC && - action == cmd_subcmd_enter_ps) - adapter->psmode = wlan802_11powermodecam; - } else if (action == cmd_subcmd_enter_ps) { + action == CMD_SUBCMD_ENTER_PS) + adapter->psmode = WLAN802_11POWERMODECAM; + } else if (action == CMD_SUBCMD_ENTER_PS) { adapter->needtowakeup = 0; adapter->psstate = PS_STATE_AWAKE; lbs_deb_cmd("CMD_RESP: Enter_PS command response\n"); - if (adapter->connect_status != libertas_connected) { + if (adapter->connect_status != LIBERTAS_CONNECTED) { /* * When Deauth Event received before Enter_PS command * response, We need to wake up the firmware. @@ -825,7 +825,7 @@ int libertas_process_rx_command(wlan_private * priv) mutex_lock(&adapter->lock); spin_lock_irqsave(&adapter->driver_lock, flags); } - } else if (action == cmd_subcmd_exit_ps) { + } else if (action == CMD_SUBCMD_EXIT_PS) { adapter->needtowakeup = 0; adapter->psstate = PS_STATE_FULL_POWER; lbs_deb_cmd("CMD_RESP: Exit_PS command response\n"); @@ -857,8 +857,8 @@ int libertas_process_rx_command(wlan_private * priv) * Handling errors here */ switch (respcmd) { - case cmd_ret_hw_spec_info: - case cmd_ret_802_11_reset: + case CMD_RET_HW_SPEC_INFO: + case CMD_RET_802_11_RESET: lbs_deb_cmd("CMD_RESP: Reset command failed\n"); break; @@ -1003,7 +1003,7 @@ int libertas_process_event(wlan_private * priv) case MACREG_INT_CODE_MESH_AUTO_STARTED: lbs_pr_alert( "EVENT: MESH_AUTO_STARTED\n"); - adapter->connect_status = libertas_connected ; + adapter->connect_status = LIBERTAS_CONNECTED ; if (priv->mesh_open == 1) { netif_wake_queue(priv->mesh_dev) ; netif_carrier_on(priv->mesh_dev) ; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index e5cbfa8d6e3f..a206f49f810c 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -125,9 +125,9 @@ static ssize_t libertas_sleepparams_write(struct file *file, priv->adapter->sp.sp_reserved = p6; res = libertas_prepare_and_send_command(priv, - cmd_802_11_sleep_params, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_SLEEP_PARAMS, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (!res) res = count; @@ -150,9 +150,9 @@ static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf char *buf = (char *)addr; res = libertas_prepare_and_send_command(priv, - cmd_802_11_sleep_params, - cmd_act_get, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_SLEEP_PARAMS, + CMD_ACT_GET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (res) { res = -EFAULT; goto out_unlock; @@ -386,7 +386,7 @@ static int libertas_event_initcmd(wlan_private *priv, void **response_buf, struct cmd_ctrl_node **cmdnode, struct cmd_ds_command **cmd) { - u16 wait_option = cmd_option_waitforrsp; + u16 wait_option = CMD_OPTION_WAITFORRSP; if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) { lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n"); @@ -402,7 +402,7 @@ static int libertas_event_initcmd(wlan_private *priv, void **response_buf, (*cmdnode)->cmdflags |= CMD_F_HOSTCMD; (*cmdnode)->cmdwaitqwoken = 0; *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr; - (*cmd)->command = cpu_to_le16(cmd_802_11_subscribe_event); + (*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT); (*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum); (*cmd)->result = 0; return 0; @@ -429,7 +429,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -447,7 +447,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -493,7 +493,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) return res; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -511,7 +511,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) return 0; } - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + if (pcmdptr->command != CMD_RET_802_11_SUBSCRIBE_EVENT) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; @@ -559,7 +559,7 @@ static ssize_t libertas_lowrssi_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_rssithreshold)); @@ -591,7 +591,7 @@ static ssize_t libertas_lowrssi_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -625,7 +625,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -644,7 +644,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -712,7 +712,7 @@ static ssize_t libertas_lowsnr_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_snrthreshold)); @@ -743,7 +743,7 @@ static ssize_t libertas_lowsnr_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -778,7 +778,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -797,7 +797,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -864,7 +864,7 @@ static ssize_t libertas_failcount_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_failurecount)); @@ -895,7 +895,7 @@ static ssize_t libertas_failcount_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -929,7 +929,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -948,7 +948,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); free_page(addr); kfree(response_buf); @@ -1015,7 +1015,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_beaconsmissed)); @@ -1045,7 +1045,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); free_page(addr); kfree(response_buf); @@ -1079,7 +1079,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -1098,7 +1098,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1166,7 +1166,7 @@ static ssize_t libertas_highrssi_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_rssithreshold)); @@ -1196,7 +1196,7 @@ static ssize_t libertas_highrssi_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; @@ -1229,7 +1229,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -1248,7 +1248,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1316,7 +1316,7 @@ static ssize_t libertas_highsnr_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_snrthreshold)); @@ -1347,7 +1347,7 @@ static ssize_t libertas_highsnr_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1375,8 +1375,8 @@ static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf, offval.value = 0; ret = libertas_prepare_and_send_command(priv, - cmd_mac_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); + CMD_MAC_REG_ACCESS, 0, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", priv->mac_offset, adapter->offsetvalue.value); @@ -1433,8 +1433,8 @@ static ssize_t libertas_wrmac_write(struct file *file, offval.offset = offset; offval.value = value; res = libertas_prepare_and_send_command(priv, - cmd_mac_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); + CMD_MAC_REG_ACCESS, 1, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); res = count; @@ -1458,8 +1458,8 @@ static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf, offval.value = 0; ret = libertas_prepare_and_send_command(priv, - cmd_bbp_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); + CMD_BBP_REG_ACCESS, 0, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", priv->bbp_offset, adapter->offsetvalue.value); @@ -1517,8 +1517,8 @@ static ssize_t libertas_wrbbp_write(struct file *file, offval.offset = offset; offval.value = value; res = libertas_prepare_and_send_command(priv, - cmd_bbp_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); + CMD_BBP_REG_ACCESS, 1, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); res = count; @@ -1542,8 +1542,8 @@ static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf, offval.value = 0; ret = libertas_prepare_and_send_command(priv, - cmd_rf_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); + CMD_RF_REG_ACCESS, 0, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", priv->rf_offset, adapter->offsetvalue.value); @@ -1601,8 +1601,8 @@ static ssize_t libertas_wrrf_write(struct file *file, offval.offset = offset; offval.value = value; res = libertas_prepare_and_send_command(priv, - cmd_rf_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); + CMD_RF_REG_ACCESS, 1, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); res = count; diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index a5d70c19768b..862292913c2c 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -286,11 +286,11 @@ enum SNRNF_DATA { /** WLAN_802_11_POWER_MODE */ enum WLAN_802_11_POWER_MODE { - wlan802_11powermodecam, - wlan802_11powermodemax_psp, - wlan802_11Powermodefast_psp, + WLAN802_11POWERMODECAM, + WLAN802_11POWERMODEMAX_PSP, + WLAN802_11POWERMODEFAST_PSP, /*not a real mode, defined as an upper bound */ - wlan802_11powemodemax + WLAN802_11POWEMODEMAX }; /** PS_STATE */ @@ -310,14 +310,14 @@ enum DNLD_STATE { /** WLAN_MEDIA_STATE */ enum WLAN_MEDIA_STATE { - libertas_connected, - libertas_disconnected + LIBERTAS_CONNECTED, + LIBERTAS_DISCONNECTED }; /** WLAN_802_11_PRIVACY_FILTER */ enum WLAN_802_11_PRIVACY_FILTER { - wlan802_11privfilteracceptall, - wlan802_11privfilter8021xWEP + WLAN802_11PRIVFILTERACCEPTALL, + WLAN802_11PRIVFILTER8021XWEP }; /** mv_ms_type */ @@ -330,23 +330,23 @@ enum mv_ms_type { /** SNMP_MIB_INDEX_e */ enum SNMP_MIB_INDEX_e { - desired_bsstype_i = 0, - op_rateset_i, - bcnperiod_i, - dtimperiod_i, - assocrsp_timeout_i, - rtsthresh_i, - short_retrylim_i, - long_retrylim_i, - fragthresh_i, - dot11d_i, - dot11h_i, - manufid_i, - prodID_i, - manuf_oui_i, - manuf_name_i, - manuf_prodname_i, - manuf_prodver_i, + DESIRED_BSSTYPE_I = 0, + OP_RATESET_I, + BCNPERIOD_I, + DTIMPERIOD_I, + ASSOCRSP_TIMEOUT_I, + RTSTHRESH_I, + SHORT_RETRYLIM_I, + LONG_RETRYLIM_I, + FRAGTHRESH_I, + DOT11D_I, + DOT11H_I, + MANUFID_I, + PRODID_I, + MANUF_OUI_I, + MANUF_NAME_I, + MANUF_PRODNAME_I, + MANUF_PRODVER_I, }; /** KEY_TYPE_ID */ diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 96f1974685d4..ec99cb825871 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -72,9 +72,9 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev, regctrl.action, regctrl.offset, regctrl.NOB); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_eeprom_access, + CMD_802_11_EEPROM_ACCESS, regctrl.action, - cmd_option_waitforrsp, 0, + CMD_OPTION_WAITFORRSP, 0, ®ctrl); if (ret) { @@ -138,8 +138,8 @@ static int libertas_ethtool_get_stats_count(struct net_device * dev) /* Get Mesh Statistics */ ret = libertas_prepare_and_send_command(priv, - cmd_mesh_access, cmd_act_mesh_get_stats, - cmd_option_waitforrsp, 0, &mesh_access); + CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS, + CMD_OPTION_WAITFORRSP, 0, &mesh_access); if (ret) { ret = 0; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index 288e47c33555..39b0a094b626 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -99,8 +99,8 @@ static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) */ memset(adapter->current_addr, 0xff, ETH_ALEN); - ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec, - 0, cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) { ret = -1; @@ -110,9 +110,9 @@ static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) libertas_set_mac_packet_filter(priv); /* Get the supported Data rates */ - ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, - cmd_act_get_tx_rate, - cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, + CMD_ACT_GET_tx_rate, + CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) { ret = -1; @@ -145,12 +145,12 @@ static int wlan_allocate_adapter(wlan_private * priv) memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); adapter->libertas_ps_confirm_sleep.command = - cpu_to_le16(cmd_802_11_ps_mode); + cpu_to_le16(CMD_802_11_PS_MODE); adapter->libertas_ps_confirm_sleep.size = cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); adapter->libertas_ps_confirm_sleep.result = 0; adapter->libertas_ps_confirm_sleep.action = - cpu_to_le16(cmd_subcmd_sleep_confirmed); + cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); return 0; } @@ -168,14 +168,14 @@ static void wlan_init_adapter(wlan_private * priv) /* ATIM params */ adapter->atimwindow = 0; - adapter->connect_status = libertas_disconnected; + adapter->connect_status = LIBERTAS_DISCONNECTED; memset(adapter->current_addr, 0xff, ETH_ALEN); /* scan type */ - adapter->scantype = cmd_scan_type_active; + adapter->scantype = CMD_SCAN_TYPE_ACTIVE; /* scan mode */ - adapter->scanmode = cmd_bss_type_any; + adapter->scanmode = CMD_BSS_TYPE_ANY; /* 802.11 specific */ adapter->secinfo.wep_enabled = 0; @@ -208,7 +208,7 @@ static void wlan_init_adapter(wlan_private * priv) adapter->surpriseremoved = 0; adapter->currentpacketfilter = - cmd_act_mac_rx_on | cmd_act_mac_tx_on; + CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; adapter->radioon = RADIO_ON; adapter->txantenna = RF_ANTENNA_2; @@ -220,7 +220,7 @@ static void wlan_init_adapter(wlan_private * priv) // set default capabilities adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; - adapter->psmode = wlan802_11powermodecam; + adapter->psmode = WLAN802_11POWERMODECAM; adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 7509cc10af3c..4bd2e88116cc 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -20,224 +20,224 @@ #define OID_802_11_TX_RETRYCOUNT 0x0000801D #define OID_802_11D_ENABLE 0x00008020 -#define cmd_option_waitforrsp 0x0002 +#define CMD_OPTION_WAITFORRSP 0x0002 /** Host command ID */ -#define cmd_code_dnld 0x0002 -#define cmd_get_hw_spec 0x0003 -#define cmd_eeprom_update 0x0004 -#define cmd_802_11_reset 0x0005 -#define cmd_802_11_scan 0x0006 -#define cmd_802_11_get_log 0x000b -#define cmd_mac_multicast_adr 0x0010 -#define cmd_802_11_authenticate 0x0011 -#define cmd_802_11_eeprom_access 0x0059 -#define cmd_802_11_associate 0x0050 -#define cmd_802_11_set_wep 0x0013 -#define cmd_802_11_get_stat 0x0014 -#define cmd_802_3_get_stat 0x0015 -#define cmd_802_11_snmp_mib 0x0016 -#define cmd_mac_reg_map 0x0017 -#define cmd_bbp_reg_map 0x0018 -#define cmd_mac_reg_access 0x0019 -#define cmd_bbp_reg_access 0x001a -#define cmd_rf_reg_access 0x001b -#define cmd_802_11_radio_control 0x001c -#define cmd_802_11_rf_channel 0x001d -#define cmd_802_11_rf_tx_power 0x001e -#define cmd_802_11_rssi 0x001f -#define cmd_802_11_rf_antenna 0x0020 +#define CMD_CODE_DNLD 0x0002 +#define CMD_GET_HW_SPEC 0x0003 +#define CMD_EEPROM_UPDATE 0x0004 +#define CMD_802_11_RESET 0x0005 +#define CMD_802_11_SCAN 0x0006 +#define CMD_802_11_GET_LOG 0x000b +#define CMD_MAC_MULTICAST_ADR 0x0010 +#define CMD_802_11_AUTHENTICATE 0x0011 +#define CMD_802_11_EEPROM_ACCESS 0x0059 +#define CMD_802_11_ASSOCIATE 0x0050 +#define CMD_802_11_SET_WEP 0x0013 +#define CMD_802_11_GET_STAT 0x0014 +#define CMD_802_3_GET_STAT 0x0015 +#define CMD_802_11_SNMP_MIB 0x0016 +#define CMD_MAC_REG_MAP 0x0017 +#define CMD_BBP_REG_MAP 0x0018 +#define CMD_MAC_REG_ACCESS 0x0019 +#define CMD_BBP_REG_ACCESS 0x001a +#define CMD_RF_REG_ACCESS 0x001b +#define CMD_802_11_RADIO_CONTROL 0x001c +#define CMD_802_11_RF_CHANNEL 0x001d +#define CMD_802_11_RF_TX_POWER 0x001e +#define CMD_802_11_RSSI 0x001f +#define CMD_802_11_RF_ANTENNA 0x0020 -#define cmd_802_11_ps_mode 0x0021 +#define CMD_802_11_PS_MODE 0x0021 -#define cmd_802_11_data_rate 0x0022 -#define cmd_rf_reg_map 0x0023 -#define cmd_802_11_deauthenticate 0x0024 -#define cmd_802_11_reassociate 0x0025 -#define cmd_802_11_disassociate 0x0026 -#define cmd_mac_control 0x0028 -#define cmd_802_11_ad_hoc_start 0x002b -#define cmd_802_11_ad_hoc_join 0x002c +#define CMD_802_11_DATA_RATE 0x0022 +#define CMD_RF_REG_MAP 0x0023 +#define CMD_802_11_DEAUTHENTICATE 0x0024 +#define CMD_802_11_REASSOCIATE 0x0025 +#define CMD_802_11_DISASSOCIATE 0x0026 +#define CMD_MAC_CONTROL 0x0028 +#define CMD_802_11_AD_HOC_START 0x002b +#define CMD_802_11_AD_HOC_JOIN 0x002c -#define cmd_802_11_query_tkip_reply_cntrs 0x002e -#define cmd_802_11_enable_rsn 0x002f -#define cmd_802_11_pairwise_tsc 0x0036 -#define cmd_802_11_group_tsc 0x0037 -#define cmd_802_11_key_material 0x005e +#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e +#define CMD_802_11_ENABLE_RSN 0x002f +#define CMD_802_11_PAIRWISE_TSC 0x0036 +#define CMD_802_11_GROUP_TSC 0x0037 +#define CMD_802_11_KEY_MATERIAL 0x005e -#define cmd_802_11_set_afc 0x003c -#define cmd_802_11_get_afc 0x003d +#define CMD_802_11_SET_AFC 0x003c +#define CMD_802_11_GET_AFC 0x003d -#define cmd_802_11_ad_hoc_stop 0x0040 +#define CMD_802_11_AD_HOC_STOP 0x0040 -#define cmd_802_11_beacon_stop 0x0049 +#define CMD_802_11_BEACON_STOP 0x0049 -#define cmd_802_11_mac_address 0x004D -#define cmd_802_11_eeprom_access 0x0059 +#define CMD_802_11_MAC_ADDRESS 0x004D +#define CMD_802_11_EEPROM_ACCESS 0x0059 -#define cmd_802_11_band_config 0x0058 +#define CMD_802_11_BAND_CONFIG 0x0058 -#define cmd_802_11d_domain_info 0x005b +#define CMD_802_11D_DOMAIN_INFO 0x005b -#define cmd_802_11_sleep_params 0x0066 +#define CMD_802_11_SLEEP_PARAMS 0x0066 -#define cmd_802_11_inactivity_timeout 0x0067 +#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 -#define cmd_802_11_tpc_cfg 0x0072 -#define cmd_802_11_pwr_cfg 0x0073 +#define CMD_802_11_TPC_CFG 0x0072 +#define CMD_802_11_PWR_CFG 0x0073 -#define cmd_802_11_led_gpio_ctrl 0x004e +#define CMD_802_11_LED_GPIO_CTRL 0x004e -#define cmd_802_11_subscribe_event 0x0075 +#define CMD_802_11_SUBSCRIBE_EVENT 0x0075 -#define cmd_802_11_rate_adapt_rateset 0x0076 +#define CMD_802_11_RATE_ADAPT_RATESET 0x0076 -#define cmd_802_11_tx_rate_query 0x007f +#define CMD_802_11_TX_RATE_QUERY 0x007f -#define cmd_get_tsf 0x0080 +#define CMD_GET_TSF 0x0080 -#define cmd_bt_access 0x0087 -#define cmd_ret_bt_access 0x8087 +#define CMD_BT_ACCESS 0x0087 +#define CMD_RET_BT_ACCESS 0x8087 -#define cmd_fwt_access 0x0095 -#define cmd_ret_fwt_access 0x8095 +#define CMD_FWT_ACCESS 0x0095 +#define CMD_RET_FWT_ACCESS 0x8095 -#define cmd_mesh_access 0x009b -#define cmd_ret_mesh_access 0x809b +#define CMD_MESH_ACCESS 0x009b +#define CMD_RET_MESH_ACCESS 0x809b /* For the IEEE Power Save */ -#define cmd_subcmd_enter_ps 0x0030 -#define cmd_subcmd_exit_ps 0x0031 -#define cmd_subcmd_sleep_confirmed 0x0034 -#define cmd_subcmd_full_powerdown 0x0035 -#define cmd_subcmd_full_powerup 0x0036 +#define CMD_SUBCMD_ENTER_PS 0x0030 +#define CMD_SUBCMD_EXIT_PS 0x0031 +#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034 +#define CMD_SUBCMD_FULL_POWERDOWN 0x0035 +#define CMD_SUBCMD_FULL_POWERUP 0x0036 /* command RET code, MSB is set to 1 */ -#define cmd_ret_hw_spec_info 0x8003 -#define cmd_ret_eeprom_update 0x8004 -#define cmd_ret_802_11_reset 0x8005 -#define cmd_ret_802_11_scan 0x8006 -#define cmd_ret_802_11_get_log 0x800b -#define cmd_ret_mac_control 0x8028 -#define cmd_ret_mac_multicast_adr 0x8010 -#define cmd_ret_802_11_authenticate 0x8011 -#define cmd_ret_802_11_deauthenticate 0x8024 -#define cmd_ret_802_11_associate 0x8012 -#define cmd_ret_802_11_reassociate 0x8025 -#define cmd_ret_802_11_disassociate 0x8026 -#define cmd_ret_802_11_set_wep 0x8013 -#define cmd_ret_802_11_stat 0x8014 -#define cmd_ret_802_3_stat 0x8015 -#define cmd_ret_802_11_snmp_mib 0x8016 -#define cmd_ret_mac_reg_map 0x8017 -#define cmd_ret_bbp_reg_map 0x8018 -#define cmd_ret_rf_reg_map 0x8023 -#define cmd_ret_mac_reg_access 0x8019 -#define cmd_ret_bbp_reg_access 0x801a -#define cmd_ret_rf_reg_access 0x801b -#define cmd_ret_802_11_radio_control 0x801c -#define cmd_ret_802_11_rf_channel 0x801d -#define cmd_ret_802_11_rssi 0x801f -#define cmd_ret_802_11_rf_tx_power 0x801e -#define cmd_ret_802_11_rf_antenna 0x8020 -#define cmd_ret_802_11_ps_mode 0x8021 -#define cmd_ret_802_11_data_rate 0x8022 +#define CMD_RET_HW_SPEC_INFO 0x8003 +#define CMD_RET_EEPROM_UPDATE 0x8004 +#define CMD_RET_802_11_RESET 0x8005 +#define CMD_RET_802_11_SCAN 0x8006 +#define CMD_RET_802_11_GET_LOG 0x800b +#define CMD_RET_MAC_CONTROL 0x8028 +#define CMD_RET_MAC_MULTICAST_ADR 0x8010 +#define CMD_RET_802_11_AUTHENTICATE 0x8011 +#define CMD_RET_802_11_DEAUTHENTICATE 0x8024 +#define CMD_RET_802_11_ASSOCIATE 0x8012 +#define CMD_RET_802_11_REASSOCIATE 0x8025 +#define CMD_RET_802_11_DISASSOCIATE 0x8026 +#define CMD_RET_802_11_SET_WEP 0x8013 +#define CMD_RET_802_11_STAT 0x8014 +#define CMD_RET_802_3_STAT 0x8015 +#define CMD_RET_802_11_SNMP_MIB 0x8016 +#define CMD_RET_MAC_REG_MAP 0x8017 +#define CMD_RET_BBP_REG_MAP 0x8018 +#define CMD_RET_RF_REG_MAP 0x8023 +#define CMD_RET_MAC_REG_ACCESS 0x8019 +#define CMD_RET_BBP_REG_ACCESS 0x801a +#define CMD_RET_RF_REG_ACCESS 0x801b +#define CMD_RET_802_11_RADIO_CONTROL 0x801c +#define CMD_RET_802_11_RF_CHANNEL 0x801d +#define CMD_RET_802_11_RSSI 0x801f +#define CMD_RET_802_11_RF_TX_POWER 0x801e +#define CMD_RET_802_11_RF_ANTENNA 0x8020 +#define CMD_RET_802_11_PS_MODE 0x8021 +#define CMD_RET_802_11_DATA_RATE 0x8022 -#define cmd_ret_802_11_ad_hoc_start 0x802B -#define cmd_ret_802_11_ad_hoc_join 0x802C +#define CMD_RET_802_11_AD_HOC_START 0x802B +#define CMD_RET_802_11_AD_HOC_JOIN 0x802C -#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e -#define cmd_ret_802_11_enable_rsn 0x802f -#define cmd_ret_802_11_pairwise_tsc 0x8036 -#define cmd_ret_802_11_group_tsc 0x8037 -#define cmd_ret_802_11_key_material 0x805e +#define CMD_RET_802_11_QUERY_TKIP_REPLY_CNTRS 0x802e +#define CMD_RET_802_11_ENABLE_RSN 0x802f +#define CMD_RET_802_11_PAIRWISE_TSC 0x8036 +#define CMD_RET_802_11_GROUP_TSC 0x8037 +#define CMD_RET_802_11_KEY_MATERIAL 0x805e -#define cmd_enable_rsn 0x0001 -#define cmd_disable_rsn 0x0000 +#define CMD_ENABLE_RSN 0x0001 +#define CMD_DISABLE_RSN 0x0000 -#define cmd_act_set 0x0001 -#define cmd_act_get 0x0000 +#define CMD_ACT_SET 0x0001 +#define CMD_ACT_GET 0x0000 -#define cmd_act_get_AES (cmd_act_get + 2) -#define cmd_act_set_AES (cmd_act_set + 2) -#define cmd_act_remove_aes (cmd_act_set + 3) +#define CMD_ACT_GET_AES (CMD_ACT_GET + 2) +#define CMD_ACT_SET_AES (CMD_ACT_SET + 2) +#define CMD_ACT_REMOVE_AES (CMD_ACT_SET + 3) -#define cmd_ret_802_11_set_afc 0x803c -#define cmd_ret_802_11_get_afc 0x803d +#define CMD_RET_802_11_SET_AFC 0x803c +#define CMD_RET_802_11_GET_AFC 0x803d -#define cmd_ret_802_11_ad_hoc_stop 0x8040 +#define CMD_RET_802_11_AD_HOC_STOP 0x8040 -#define cmd_ret_802_11_beacon_stop 0x8049 +#define CMD_RET_802_11_BEACON_STOP 0x8049 -#define cmd_ret_802_11_mac_address 0x804D -#define cmd_ret_802_11_eeprom_access 0x8059 +#define CMD_RET_802_11_MAC_ADDRESS 0x804D +#define CMD_RET_802_11_EEPROM_ACCESS 0x8059 -#define cmd_ret_802_11_band_config 0x8058 +#define CMD_RET_802_11_BAND_CONFIG 0x8058 -#define cmd_ret_802_11_sleep_params 0x8066 +#define CMD_RET_802_11_SLEEP_PARAMS 0x8066 -#define cmd_ret_802_11_inactivity_timeout 0x8067 +#define CMD_RET_802_11_INACTIVITY_TIMEOUT 0x8067 -#define cmd_ret_802_11d_domain_info (0x8000 | \ - cmd_802_11d_domain_info) +#define CMD_RET_802_11D_DOMAIN_INFO (0x8000 | \ + CMD_802_11D_DOMAIN_INFO) -#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000) -#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000) +#define CMD_RET_802_11_TPC_CFG (CMD_802_11_TPC_CFG | 0x8000) +#define CMD_RET_802_11_PWR_CFG (CMD_802_11_PWR_CFG | 0x8000) -#define cmd_ret_802_11_led_gpio_ctrl 0x804e +#define CMD_RET_802_11_LED_GPIO_CTRL 0x804e -#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000) +#define CMD_RET_802_11_SUBSCRIBE_EVENT (CMD_802_11_SUBSCRIBE_EVENT | 0x8000) -#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000) +#define CMD_RET_802_11_RATE_ADAPT_RATESET (CMD_802_11_RATE_ADAPT_RATESET | 0x8000) -#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000) +#define CMD_RTE_802_11_TX_RATE_QUERY (CMD_802_11_TX_RATE_QUERY | 0x8000) -#define cmd_ret_get_tsf 0x8080 +#define CMD_RET_GET_TSF 0x8080 -/* Define action or option for cmd_802_11_set_wep */ -#define cmd_act_add 0x0002 -#define cmd_act_remove 0x0004 -#define cmd_act_use_default 0x0008 +/* Define action or option for CMD_802_11_SET_WEP */ +#define CMD_ACT_ADD 0x0002 +#define CMD_ACT_REMOVE 0x0004 +#define CMD_ACT_USE_DEFAULT 0x0008 -#define cmd_type_wep_40_bit 0x0001 -#define cmd_type_wep_104_bit 0x0002 +#define CMD_TYPE_WEP_40_BIT 0x0001 +#define CMD_TYPE_WEP_104_BIT 0x0002 -#define cmd_NUM_OF_WEP_KEYS 4 +#define CMD_NUM_OF_WEP_KEYS 4 -#define cmd_WEP_KEY_INDEX_MASK 0x3fff +#define CMD_WEP_KEY_INDEX_MASK 0x3fff -/* Define action or option for cmd_802_11_reset */ -#define cmd_act_halt 0x0003 +/* Define action or option for CMD_802_11_RESET */ +#define CMD_ACT_HALT 0x0003 -/* Define action or option for cmd_802_11_scan */ -#define cmd_bss_type_bss 0x0001 -#define cmd_bss_type_ibss 0x0002 -#define cmd_bss_type_any 0x0003 +/* Define action or option for CMD_802_11_SCAN */ +#define CMD_BSS_TYPE_BSS 0x0001 +#define CMD_BSS_TYPE_IBSS 0x0002 +#define CMD_BSS_TYPE_ANY 0x0003 -/* Define action or option for cmd_802_11_scan */ -#define cmd_scan_type_active 0x0000 -#define cmd_scan_type_passive 0x0001 +/* Define action or option for CMD_802_11_SCAN */ +#define CMD_SCAN_TYPE_ACTIVE 0x0000 +#define CMD_SCAN_TYPE_PASSIVE 0x0001 -#define cmd_scan_radio_type_bg 0 +#define CMD_SCAN_RADIO_TYPE_BG 0 -#define cmd_scan_probe_delay_time 0 +#define CMD_SCAN_PROBE_DELAY_TIME 0 -/* Define action or option for cmd_mac_control */ -#define cmd_act_mac_rx_on 0x0001 -#define cmd_act_mac_tx_on 0x0002 -#define cmd_act_mac_loopback_on 0x0004 -#define cmd_act_mac_wep_enable 0x0008 -#define cmd_act_mac_int_enable 0x0010 -#define cmd_act_mac_multicast_enable 0x0020 -#define cmd_act_mac_broadcast_enable 0x0040 -#define cmd_act_mac_promiscuous_enable 0x0080 -#define cmd_act_mac_all_multicast_enable 0x0100 -#define cmd_act_mac_strict_protection_enable 0x0400 +/* Define action or option for CMD_MAC_CONTROL */ +#define CMD_ACT_MAC_RX_ON 0x0001 +#define CMD_ACT_MAC_TX_ON 0x0002 +#define CMD_ACT_MAC_LOOPBACK_ON 0x0004 +#define CMD_ACT_MAC_WEP_ENABLE 0x0008 +#define CMD_ACT_MAC_INT_ENABLE 0x0010 +#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 +#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 +#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 +#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 -/* Define action or option for cmd_802_11_radio_control */ -#define cmd_type_auto_preamble 0x0001 -#define cmd_type_short_preamble 0x0002 -#define cmd_type_long_preamble 0x0003 +/* Define action or option for CMD_802_11_RADIO_CONTROL */ +#define CMD_TYPE_AUTO_PREAMBLE 0x0001 +#define CMD_TYPE_SHORT_PREAMBLE 0x0002 +#define CMD_TYPE_LONG_PREAMBLE 0x0003 #define TURN_ON_RF 0x01 #define RADIO_ON 0x01 @@ -248,70 +248,70 @@ #define SET_LONG_PREAMBLE 0x01 /* Define action or option for CMD_802_11_RF_CHANNEL */ -#define cmd_opt_802_11_rf_channel_get 0x00 -#define cmd_opt_802_11_rf_channel_set 0x01 +#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 +#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 -/* Define action or option for cmd_802_11_rf_tx_power */ -#define cmd_act_tx_power_opt_get 0x0000 -#define cmd_act_tx_power_opt_set_high 0x8007 -#define cmd_act_tx_power_opt_set_mid 0x8004 -#define cmd_act_tx_power_opt_set_low 0x8000 +/* Define action or option for CMD_802_11_RF_TX_POWER */ +#define CMD_ACT_TX_POWER_OPT_GET 0x0000 +#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007 +#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004 +#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000 -#define cmd_act_tx_power_index_high 0x0007 -#define cmd_act_tx_power_index_mid 0x0004 -#define cmd_act_tx_power_index_low 0x0000 +#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007 +#define CMD_ACT_TX_POWER_INDEX_MID 0x0004 +#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 -/* Define action or option for cmd_802_11_data_rate */ -#define cmd_act_set_tx_auto 0x0000 -#define cmd_act_set_tx_fix_rate 0x0001 -#define cmd_act_get_tx_rate 0x0002 +/* Define action or option for CMD_802_11_DATA_RATE */ +#define CMD_ACT_SET_tx_auto 0x0000 +#define CMD_ACT_SET_tx_fix_rate 0x0001 +#define CMD_ACT_GET_tx_rate 0x0002 -#define cmd_act_set_rx 0x0001 -#define cmd_act_set_tx 0x0002 -#define cmd_act_set_both 0x0003 -#define cmd_act_get_rx 0x0004 -#define cmd_act_get_tx 0x0008 -#define cmd_act_get_both 0x000c +#define CMD_ACT_SET_rx 0x0001 +#define CMD_ACT_SET_tx 0x0002 +#define CMD_ACT_SET_both 0x0003 +#define CMD_ACT_GET_rx 0x0004 +#define CMD_ACT_GET_tx 0x0008 +#define CMD_ACT_GET_both 0x000c -/* Define action or option for cmd_802_11_ps_mode */ -#define cmd_type_cam 0x0000 -#define cmd_type_max_psp 0x0001 -#define cmd_type_fast_psp 0x0002 +/* Define action or option for CMD_802_11_PS_MODE */ +#define CMD_TYPE_CAM 0x0000 +#define CMD_TYPE_MAX_PSP 0x0001 +#define CMD_TYPE_FAST_PSP 0x0002 -/* Define action or option for cmd_bt_access */ -enum cmd_bt_access_opts { +/* Define action or option for CMD_BT_ACCESS */ +enum CMD_BT_ACCESS_opts { /* The bt commands start at 5 instead of 1 because the old dft commands * are mapped to 1-4. These old commands are no longer maintained and * should not be called. */ - cmd_act_bt_access_add = 5, - cmd_act_bt_access_del, - cmd_act_bt_access_list, - cmd_act_bt_access_reset, - cmd_act_bt_access_set_invert, - cmd_act_bt_access_get_invert + CMD_ACT_BT_ACCESS_ADD = 5, + CMD_ACT_BT_ACCESS_DEL, + CMD_ACT_BT_ACCESS_LIST, + CMD_ACT_BT_ACCESS_RESET, + CMD_ACT_BT_ACCESS_SET_INVERT, + CMD_ACT_BT_ACCESS_GET_INVERT }; -/* Define action or option for cmd_fwt_access */ -enum cmd_fwt_access_opts { - cmd_act_fwt_access_add = 1, - cmd_act_fwt_access_del, - cmd_act_fwt_access_lookup, - cmd_act_fwt_access_list, - cmd_act_fwt_access_list_route, - cmd_act_fwt_access_list_neighbor, - cmd_act_fwt_access_reset, - cmd_act_fwt_access_cleanup, - cmd_act_fwt_access_time, +/* Define action or option for CMD_FWT_ACCESS */ +enum CMD_FWT_ACCESS_opts { + CMD_ACT_FWT_ACCESS_ADD = 1, + CMD_ACT_FWT_ACCESS_DEL, + CMD_ACT_FWT_ACCESS_LOOKUP, + CMD_ACT_FWT_ACCESS_LIST, + CMD_ACT_FWT_ACCESS_LIST_route, + CMD_ACT_FWT_ACCESS_LIST_neighbor, + CMD_ACT_FWT_ACCESS_RESET, + CMD_ACT_FWT_ACCESS_CLEANUP, + CMD_ACT_FWT_ACCESS_TIME, }; -/* Define action or option for cmd_mesh_access */ -enum cmd_mesh_access_opts { - cmd_act_mesh_get_ttl = 1, - cmd_act_mesh_set_ttl, - cmd_act_mesh_get_stats, - cmd_act_mesh_get_anycast, - cmd_act_mesh_set_anycast, +/* Define action or option for CMD_MESH_ACCESS */ +enum CMD_MESH_ACCESS_opts { + CMD_ACT_MESH_GET_TTL = 1, + CMD_ACT_MESH_SET_TTL, + CMD_ACT_MESH_GET_STATS, + CMD_ACT_MESH_GET_ANYCAST, + CMD_ACT_MESH_SET_ANYCAST, }; /** Card Event definition */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 23871c0f882a..76c5fdeb256a 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -108,7 +108,7 @@ struct cmd_ds_gen { #define S_DS_GEN sizeof(struct cmd_ds_gen) /* - * Define data structure for cmd_get_hw_spec + * Define data structure for CMD_GET_HW_SPEC * This structure defines the response for the GET_HW_SPEC command */ struct cmd_ds_get_hw_spec { @@ -155,7 +155,7 @@ struct cmd_ds_802_11_subscribe_event { /* * This scan handle Country Information IE(802.11d compliant) - * Define data structure for cmd_802_11_scan + * Define data structure for CMD_802_11_SCAN */ struct cmd_ds_802_11_scan { u8 bsstype; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 11687b84c596..cf522c6ef57a 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -78,7 +78,7 @@ static void if_usb_write_bulk_callback(struct urb *urb) /* Wake main thread if commands are pending */ if (!adapter->cur_cmd) wake_up_interruptible(&priv->mainthread.waitq); - if ((adapter->connect_status == libertas_connected)) { + if ((adapter->connect_status == LIBERTAS_CONNECTED)) { netif_wake_queue(dev); netif_wake_queue(priv->mesh_dev); } @@ -758,8 +758,8 @@ static int if_usb_reset_device(wlan_private *priv) int ret; lbs_deb_enter(LBS_DEB_USB); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset, - cmd_act_halt, 0, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET, + CMD_ACT_HALT, 0, 0, NULL); msleep_interruptible(10); lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index db467e7876f2..3530c23da798 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -88,7 +88,7 @@ int libertas_send_deauth(wlan_private * priv) int ret = 0; if (adapter->mode == IW_MODE_INFRA && - adapter->connect_status == libertas_connected) + adapter->connect_status == LIBERTAS_CONNECTED) ret = libertas_send_deauthentication(priv); else ret = -ENOTSUPP; @@ -111,8 +111,8 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) lbs_deb_enter(LBS_DEB_JOIN); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate, - 0, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, + 0, CMD_OPTION_WAITFORRSP, 0, assoc_req->bss.bssid); if (ret) @@ -121,14 +121,14 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) /* set preamble to firmware */ if ( (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - adapter->preamble = cmd_type_short_preamble; + adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; else - adapter->preamble = cmd_type_long_preamble; + adapter->preamble = CMD_TYPE_LONG_PREAMBLE; libertas_set_radio_control(priv); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate, - 0, cmd_option_waitforrsp, 0, assoc_req); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, + 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); @@ -151,10 +151,10 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocStart: Short preamble\n"); - adapter->preamble = cmd_type_short_preamble; + adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; } else { lbs_deb_join("AdhocStart: Long preamble\n"); - adapter->preamble = cmd_type_long_preamble; + adapter->preamble = CMD_TYPE_LONG_PREAMBLE; } libertas_set_radio_control(priv); @@ -162,8 +162,8 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start, - 0, cmd_option_waitforrsp, 0, assoc_req); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, + 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); return ret; } @@ -209,10 +209,10 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Long preamble\n"); - adapter->preamble = cmd_type_long_preamble; + adapter->preamble = CMD_TYPE_LONG_PREAMBLE; } else { lbs_deb_join("AdhocJoin: Short preamble\n"); - adapter->preamble = cmd_type_short_preamble; + adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; } libertas_set_radio_control(priv); @@ -222,8 +222,8 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso adapter->adhoccreate = 0; - ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join, - 0, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, + 0, CMD_OPTION_WAITFORRSP, OID_802_11_SSID, assoc_req); return ret; @@ -231,8 +231,8 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso int libertas_stop_adhoc_network(wlan_private * priv) { - return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop, - 0, cmd_option_waitforrsp, 0, NULL); + return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); } /** @@ -243,8 +243,8 @@ int libertas_stop_adhoc_network(wlan_private * priv) */ int libertas_send_deauthentication(wlan_private * priv) { - return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate, - 0, cmd_option_waitforrsp, 0, NULL); + return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); } /** @@ -267,7 +267,7 @@ int libertas_cmd_80211_authenticate(wlan_private * priv, lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(cmd_802_11_authenticate); + cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) + S_DS_GEN); @@ -307,7 +307,7 @@ int libertas_cmd_80211_deauthenticate(wlan_private * priv, lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(cmd_802_11_deauthenticate); + cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + S_DS_GEN); @@ -349,7 +349,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, goto done; } - cmd->command = cpu_to_le16(cmd_802_11_associate); + cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); pos += sizeof(passo->peerstaaddr); @@ -465,7 +465,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, goto done; } - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start); + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); /* * Fill in the parameters for 2 data structures: @@ -487,7 +487,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, assoc_req->ssid_len); /* set the BSS type */ - adhs->bsstype = cmd_bss_type_ibss; + adhs->bsstype = CMD_BSS_TYPE_IBSS; adapter->mode = IW_MODE_ADHOC; adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod); @@ -524,7 +524,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->capability = cpu_to_le16(tmpcap); /* probedelay */ - adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); + adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); memset(adhs->datarate, 0, sizeof(adhs->datarate)); @@ -569,7 +569,7 @@ done: int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, struct cmd_ds_command *cmd) { - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop); + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); cmd->size = cpu_to_le16(S_DS_GEN); return 0; @@ -590,9 +590,9 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join); + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); - join_cmd->bss.type = cmd_bss_type_ibss; + join_cmd->bss.type = CMD_BSS_TYPE_IBSS; join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); @@ -617,7 +617,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); /* probedelay */ - join_cmd->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); + join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); /* Copy Data rates from the rates recorded in scan response */ memset(join_cmd->bss.datarates, 0, sizeof(join_cmd->bss.datarates)); @@ -659,14 +659,14 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, join_cmd->bss.capability = cpu_to_le16(tmp); } - if (adapter->psmode == wlan802_11powermodemax_psp) { + if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { /* wake up first */ __le32 Localpsmode; - Localpsmode = cpu_to_le32(wlan802_11powermodecam); + Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_ps_mode, - cmd_act_set, + CMD_802_11_PS_MODE, + CMD_ACT_SET, 0, 0, &Localpsmode); if (ret) { @@ -722,7 +722,7 @@ int libertas_ret_80211_associate(wlan_private * priv, le16_to_cpu(resp->size) - S_DS_GEN); /* Send a Media Connected event, according to the Spec */ - adapter->connect_status = libertas_connected; + adapter->connect_status = LIBERTAS_CONNECTED; lbs_deb_join("ASSOC_RESP: assocated to '%s'\n", escape_essid(bss->ssid, bss->ssid_len)); @@ -802,7 +802,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, */ if (result) { lbs_deb_join("ADHOC_RESP: failed\n"); - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { libertas_mac_event_disconnected(priv); } ret = -1; @@ -817,9 +817,9 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, escape_essid(bss->ssid, bss->ssid_len)); /* Send a Media Connected event, according to the Spec */ - adapter->connect_status = libertas_connected; + adapter->connect_status = LIBERTAS_CONNECTED; - if (command == cmd_ret_802_11_ad_hoc_start) { + if (command == CMD_RET_802_11_AD_HOC_START) { /* Update the created network descriptor with the new BSSID */ memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 9f366242c392..2315eb61836e 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -187,9 +187,9 @@ static ssize_t libertas_anycast_get(struct device * dev, memset(&mesh_access, 0, sizeof(mesh_access)); libertas_prepare_and_send_command(to_net_dev(dev)->priv, - cmd_mesh_access, - cmd_act_mesh_get_anycast, - cmd_option_waitforrsp, 0, (void *)&mesh_access); + CMD_MESH_ACCESS, + CMD_ACT_MESH_GET_ANYCAST, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0])); } @@ -208,9 +208,9 @@ static ssize_t libertas_anycast_set(struct device * dev, mesh_access.data[0] = cpu_to_le32(datum); libertas_prepare_and_send_command((to_net_dev(dev))->priv, - cmd_mesh_access, - cmd_act_mesh_set_anycast, - cmd_option_waitforrsp, 0, (void *)&mesh_access); + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_ANYCAST, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); return strlen(buf); } @@ -264,7 +264,7 @@ static int wlan_dev_open(struct net_device *dev) priv->open = 1; - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); netif_carrier_on(priv->mesh_dev); } else { @@ -439,7 +439,7 @@ static void wlan_tx_timeout(struct net_device *dev) libertas_send_tx_feedback(priv); } else wake_up_interruptible(&priv->mainthread.waitq); - } else if (priv->adapter->connect_status == libertas_connected) { + } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); netif_wake_queue(priv->mesh_dev); } @@ -480,9 +480,9 @@ static int wlan_set_mac_address(struct net_device *dev, void *addr) lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN); memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) { lbs_deb_net("set MAC address failed\n"); @@ -528,36 +528,36 @@ static void wlan_set_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { lbs_deb_net("enable promiscuous mode\n"); adapter->currentpacketfilter |= - cmd_act_mac_promiscuous_enable; + CMD_ACT_MAC_PROMISCUOUS_ENABLE; adapter->currentpacketfilter &= - ~(cmd_act_mac_all_multicast_enable | - cmd_act_mac_multicast_enable); + ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | + CMD_ACT_MAC_MULTICAST_ENABLE); } else { /* Multicast */ adapter->currentpacketfilter &= - ~cmd_act_mac_promiscuous_enable; + ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; if (dev->flags & IFF_ALLMULTI || dev->mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { lbs_deb_net( "enabling all multicast\n"); adapter->currentpacketfilter |= - cmd_act_mac_all_multicast_enable; + CMD_ACT_MAC_ALL_MULTICAST_ENABLE; adapter->currentpacketfilter &= - ~cmd_act_mac_multicast_enable; + ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { adapter->currentpacketfilter &= - ~cmd_act_mac_all_multicast_enable; + ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; if (!dev->mc_count) { lbs_deb_net("no multicast addresses, " "disabling multicast\n"); adapter->currentpacketfilter &= - ~cmd_act_mac_multicast_enable; + ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { int i; adapter->currentpacketfilter |= - cmd_act_mac_multicast_enable; + CMD_ACT_MAC_MULTICAST_ENABLE; adapter->nr_of_multicastmacaddr = wlan_copy_multicast_address(adapter, dev); @@ -577,8 +577,8 @@ static void wlan_set_multicast_list(struct net_device *dev) } /* send multicast addresses to firmware */ libertas_prepare_and_send_command(priv, - cmd_mac_multicast_adr, - cmd_act_set, 0, 0, + CMD_MAC_MULTICAST_ADR, + CMD_ACT_SET, 0, 0, NULL); } } @@ -711,7 +711,7 @@ static int wlan_service_main_thread(void *data) if (adapter->psstate == PS_STATE_PRE_SLEEP) { if (!priv->dnld_sent && !adapter->cur_cmd) { if (adapter->connect_status == - libertas_connected) { + LIBERTAS_CONNECTED) { lbs_deb_thread( "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p " "dnld_sent=%d cur_cmd=%p, confirm now\n", @@ -1005,9 +1005,9 @@ int libertas_remove_card(wlan_private *priv) cancel_delayed_work(&priv->assoc_work); destroy_workqueue(priv->assoc_thread); - if (adapter->psmode == wlan802_11powermodemax_psp) { - adapter->psmode = wlan802_11powermodecam; - libertas_ps_wakeup(priv, cmd_option_waitforrsp); + if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { + adapter->psmode = WLAN802_11POWERMODECAM; + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 2937f79c4a01..2cac47fc4cd9 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -255,7 +255,7 @@ static void wlan_scan_create_channel_list(wlan_private * priv, for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { if (priv->adapter->enable11d && - adapter->connect_status != libertas_connected) { + adapter->connect_status != LIBERTAS_CONNECTED) { /* Scan all the supported chan for the first scan */ if (!adapter->universal_channel[rgnidx].valid) continue; @@ -287,11 +287,11 @@ static void wlan_scan_create_channel_list(wlan_private * priv, case BAND_G: default: scanchanlist[chanidx].radiotype = - cmd_scan_radio_type_bg; + CMD_SCAN_RADIO_TYPE_BG; break; } - if (scantype == cmd_scan_type_passive) { + if (scantype == CMD_SCAN_TYPE_PASSIVE) { scanchanlist[chanidx].maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME); scanchanlist[chanidx].chanscanmode.passivescan = @@ -486,7 +486,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, scantype = puserscanin->chanlist[chanidx].scantype; - if (scantype == cmd_scan_type_passive) { + if (scantype == CMD_SCAN_TYPE_PASSIVE) { (pscanchanlist + chanidx)->chanscanmode.passivescan = 1; } else { @@ -498,7 +498,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, scandur = puserscanin->chanlist[chanidx].scantime; } else { - if (scantype == cmd_scan_type_passive) { + if (scantype == CMD_SCAN_TYPE_PASSIVE) { scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; } else { scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; @@ -668,7 +668,7 @@ static int wlan_scan_channel_list(wlan_private * priv, } /* Send the scan command to the firmware with the specified cfg */ - ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SCAN, 0, 0, 0, pscancfgout); if (scanned >= 2 && !full_scan) { ret = 0; @@ -816,7 +816,7 @@ int wlan_scan_networks(wlan_private * priv, mutex_unlock(&adapter->lock); #endif - if (priv->adapter->connect_status == libertas_connected) { + if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); netif_carrier_on(priv->mesh_dev); @@ -1603,8 +1603,8 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, /* Update RSSI if current BSS is a locally created ad-hoc BSS */ if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { - libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0, - cmd_option_waitforrsp, 0, NULL); + libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + CMD_OPTION_WAITFORRSP, 0, NULL); } mutex_lock(&adapter->lock); @@ -1680,7 +1680,7 @@ int libertas_cmd_80211_scan(wlan_private * priv, memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN); memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); - cmd->command = cpu_to_le16(cmd_802_11_scan); + cmd->command = cpu_to_le16(CMD_802_11_SCAN); /* size is equal to the sizeof(fixed portions) + the TLV len + header */ cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 17c437635a00..c2271020aafe 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -283,7 +283,7 @@ void libertas_send_tx_feedback(wlan_private * priv) libertas_upload_rx_packet(priv, adapter->currenttxskb); adapter->currenttxskb = NULL; priv->adapter->TxLockFlag = 0; - if (priv->adapter->connect_status == libertas_connected) { + if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); netif_wake_queue(priv->mesh_dev); } diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index f7df8c71a544..7cfca5f3a5ef 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -177,9 +177,9 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option) adapter->radioon = option; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_radio_control, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_RADIO_CONTROL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); } lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -221,7 +221,7 @@ static int get_active_data_rates(wlan_adapter * adapter, lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status != libertas_connected) { + if (adapter->connect_status != LIBERTAS_CONNECTED) { if (adapter->mode == IW_MODE_INFRA) { lbs_deb_wext("infra\n"); k = copyrates(rates, k, libertas_supported_rates, @@ -305,7 +305,7 @@ static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN); } else { memset(awrq->sa_data, 0, ETH_ALEN); @@ -382,7 +382,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, /* Use nickname to indicate that mesh is on */ - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { strncpy(extra, "Mesh", 12); extra[12] = '\0'; dwrq->length = strlen(extra) + 1; @@ -414,8 +414,8 @@ static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, adapter->rtsthsd = rthr; } - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + CMD_ACT_SET, CMD_OPTION_WAITFORRSP, OID_802_11_RTS_THRESHOLD, &rthr); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -432,8 +432,8 @@ static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); adapter->rtsthsd = 0; - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_RTS_THRESHOLD, NULL); if (ret) goto out; @@ -467,8 +467,8 @@ static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, adapter->fragthsd = fthr; } - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + CMD_ACT_SET, CMD_OPTION_WAITFORRSP, OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -486,8 +486,8 @@ static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, adapter->fragthsd = 0; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, + CMD_802_11_SNMP_MIB, + CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_FRAGMENTATION_THRESHOLD, NULL); if (ret) goto out; @@ -539,9 +539,9 @@ static int wlan_get_txpow(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rf_tx_power, - cmd_act_tx_power_opt_get, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_RF_TX_POWER, + CMD_ACT_TX_POWER_OPT_GET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) goto out; @@ -581,9 +581,9 @@ static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, /* Adding 1 to convert retry count to try count */ adapter->txretrycount = vwrq->value + 1; - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, - cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, OID_802_11_TX_RETRYCOUNT, NULL); if (ret) @@ -608,8 +608,8 @@ static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, adapter->txretrycount = 0; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, + CMD_802_11_SNMP_MIB, + CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_TX_RETRYCOUNT, NULL); if (ret) goto out; @@ -698,7 +698,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, range->num_frequency = 0; if (priv->adapter->enable11d && - adapter->connect_status == libertas_connected) { + adapter->connect_status == LIBERTAS_CONNECTED) { u8 chan_no; u8 band; @@ -858,9 +858,9 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, */ if (vwrq->disabled) { - adapter->psmode = wlan802_11powermodecam; + adapter->psmode = WLAN802_11POWERMODECAM; if (adapter->psstate != PS_STATE_FULL_POWER) { - libertas_ps_wakeup(priv, cmd_option_waitforrsp); + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } return 0; @@ -875,14 +875,14 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, return -EINVAL; } - if (adapter->psmode != wlan802_11powermodecam) { + if (adapter->psmode != WLAN802_11POWERMODECAM) { return 0; } - adapter->psmode = wlan802_11powermodemax_psp; + adapter->psmode = WLAN802_11POWERMODEMAX_PSP; - if (adapter->connect_status == libertas_connected) { - libertas_ps_sleep(priv, cmd_option_waitforrsp); + if (adapter->connect_status == LIBERTAS_CONNECTED) { + libertas_ps_sleep(priv, CMD_OPTION_WAITFORRSP); } lbs_deb_leave(LBS_DEB_WEXT); @@ -900,8 +900,8 @@ static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, mode = adapter->psmode; - if ((vwrq->disabled = (mode == wlan802_11powermodecam)) - || adapter->connect_status == libertas_disconnected) + if ((vwrq->disabled = (mode == WLAN802_11POWERMODECAM)) + || adapter->connect_status == LIBERTAS_DISCONNECTED) { goto out; } @@ -937,7 +937,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) priv->wstats.status = adapter->mode; /* If we're not associated, all quality values are meaningless */ - if (adapter->connect_status != libertas_connected) + if (adapter->connect_status != LIBERTAS_CONNECTED) goto out; /* Quality by RSSI */ @@ -1000,9 +1000,9 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) stats_valid = 1; /* update stats asynchronously for future calls */ - libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0, + libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, 0, 0, NULL); - libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0, + libertas_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0, 0, 0, NULL); out: if (!stats_valid) { @@ -1128,7 +1128,7 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("vwrq->value %d\n", vwrq->value); if (vwrq->value == -1) { - action = cmd_act_set_tx_auto; // Auto + action = CMD_ACT_SET_tx_auto; // Auto adapter->is_datarate_auto = 1; adapter->datarate = 0; } else { @@ -1155,12 +1155,12 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, } adapter->datarate = data_rate; - action = cmd_act_set_tx_fix_rate; + action = CMD_ACT_SET_tx_fix_rate; adapter->is_datarate_auto = 0; } - ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, - action, cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, + action, CMD_OPTION_WAITFORRSP, 0, NULL); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -1976,7 +1976,7 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, return 0; } - adapter->preamble = cmd_type_auto_preamble; + adapter->preamble = CMD_TYPE_AUTO_PREAMBLE; wlan_radio_ioctl(priv, RADIO_ON); @@ -1993,9 +1993,9 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("txpower set %d dbm\n", dbm); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rf_tx_power, - cmd_act_tx_power_opt_set_low, - cmd_option_waitforrsp, 0, (void *)&dbm); + CMD_802_11_RF_TX_POWER, + CMD_ACT_TX_POWER_OPT_SET_LOW, + CMD_OPTION_WAITFORRSP, 0, (void *)&dbm); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -2017,7 +2017,7 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, /* * Get the current SSID */ - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { memcpy(extra, adapter->curbssparams.ssid, adapter->curbssparams.ssid_len); extra[adapter->curbssparams.ssid_len] = '\0'; From 2ca10e6d6a3052e7a8380b20588a7b1985ea1197 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:31:49 -0400 Subject: [PATCH 1236/2804] [PATCH] libertas: fix debug build breakage due to field rename Missed when fixing mixed-case structure field names. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 3530c23da798..381739d6ed96 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -845,7 +845,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel); lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n", - MAC_ARG(padhocresult->BSSID)); + MAC_ARG(padhocresult->bssid)); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); From fe3361507af44d00d5b42b91c1626321765a11bc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:32:25 -0400 Subject: [PATCH 1237/2804] [PATCH] libertas: remove thread.h and make kthread usage clearer Remove the thread.h abstractions and opencode kthread stuff to make it clearer. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 4 +- drivers/net/wireless/libertas/debugfs.c | 26 ++++++------- drivers/net/wireless/libertas/dev.h | 4 +- drivers/net/wireless/libertas/fw.c | 2 +- drivers/net/wireless/libertas/if_usb.c | 2 +- drivers/net/wireless/libertas/main.c | 36 ++++++++--------- drivers/net/wireless/libertas/thread.h | 52 ------------------------- 7 files changed, 37 insertions(+), 89 deletions(-) delete mode 100644 drivers/net/wireless/libertas/thread.h diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index e0eab6e3a9b0..401a630ed4e5 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1134,7 +1134,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, lbs_deb_cmd("PREP_CMD: No free cmdnode\n"); /* Wake up main thread to execute next command */ - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); ret = -1; goto done; } @@ -1402,7 +1402,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, libertas_queue_cmd(adapter, cmdnode, 1); adapter->nr_cmd_pending++; - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); if (wait_option & CMD_OPTION_WAITFORRSP) { lbs_deb_cmd("PREP_CMD: Wait for CMD response\n"); diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index a206f49f810c..9439005db4e6 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -432,7 +432,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -496,7 +496,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -575,7 +575,7 @@ static ssize_t libertas_lowrssi_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -628,7 +628,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -727,7 +727,7 @@ static ssize_t libertas_lowsnr_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -781,7 +781,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -879,7 +879,7 @@ static ssize_t libertas_failcount_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -932,7 +932,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1029,7 +1029,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1082,7 +1082,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1181,7 +1181,7 @@ static ssize_t libertas_highrssi_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1232,7 +1232,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1331,7 +1331,7 @@ static ssize_t libertas_highsnr_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 184eee548572..c6fb703f665b 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -14,7 +14,6 @@ #include "defs.h" #include "scan.h" -#include "thread.h" extern struct ethtool_ops libertas_ethtool_ops; @@ -146,7 +145,8 @@ struct _wlan_private { struct device *hotplug_device; /** thread to service interrupts */ - struct wlan_thread mainthread; + struct task_struct *main_thread; + wait_queue_head_t waitq; struct delayed_work assoc_work; struct workqueue_struct *assoc_thread; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index 39b0a094b626..e7177598f94b 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -341,7 +341,7 @@ static void command_timer_fn(unsigned long data) lbs_deb_fw("re-sending same command because of timeout\n"); libertas_queue_cmd(adapter, ptempnode, 0); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); return; } diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index cf522c6ef57a..a3334f63a80d 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -77,7 +77,7 @@ static void if_usb_write_bulk_callback(struct urb *urb) priv->dnld_sent = DNLD_RES_RECEIVED; /* Wake main thread if commands are pending */ if (!adapter->cur_cmd) - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); if ((adapter->connect_status == LIBERTAS_CONNECTED)) { netif_wake_queue(dev); netif_wake_queue(priv->mesh_dev); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2315eb61836e..e24875de8dc8 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -438,7 +439,7 @@ static void wlan_tx_timeout(struct net_device *dev) priv->adapter->eventcause = 0x01000000; libertas_send_tx_feedback(priv); } else - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); netif_wake_queue(priv->mesh_dev); @@ -599,28 +600,25 @@ static void wlan_set_multicast_list(struct net_device *dev) * @param data A pointer to wlan_thread structure * @return 0 */ -static int wlan_service_main_thread(void *data) +static int libertas_thread(void *data) { - struct wlan_thread *thread = data; - wlan_private *priv = thread->priv; + struct net_device *dev = data; + wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; wait_queue_t wait; u8 ireg = 0; lbs_deb_enter(LBS_DEB_THREAD); - wlan_activate_thread(thread); - init_waitqueue_entry(&wait, current); - set_freezable(); for (;;) { lbs_deb_thread( "main-thread 111: intcounter=%d " "currenttxskb=%p dnld_sent=%d\n", adapter->intcounter, adapter->currenttxskb, priv->dnld_sent); - add_wait_queue(&thread->waitq, &wait); + add_wait_queue(&priv->waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irq(&adapter->driver_lock); if ((adapter->psstate == PS_STATE_SLEEP) || @@ -643,7 +641,7 @@ static int wlan_service_main_thread(void *data) adapter->currenttxskb, priv->dnld_sent); set_current_state(TASK_RUNNING); - remove_wait_queue(&thread->waitq, &wait); + remove_wait_queue(&priv->waitq, &wait); try_to_freeze(); lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p " @@ -758,7 +756,6 @@ static int wlan_service_main_thread(void *data) del_timer(&adapter->command_timer); adapter->nr_cmd_pending = 0; wake_up_all(&adapter->cmd_pending); - wlan_deactivate_thread(thread); lbs_deb_leave(LBS_DEB_THREAD); return 0; @@ -841,10 +838,13 @@ int libertas_activate_card(wlan_private *priv, char *fw_name) lbs_deb_enter(LBS_DEB_MAIN); - lbs_deb_thread("Starting kthread...\n"); - priv->mainthread.priv = priv; - wlan_create_thread(wlan_service_main_thread, - &priv->mainthread, "wlan_main_service"); + lbs_deb_thread("Starting main thread...\n"); + init_waitqueue_head(&priv->waitq); + priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); + if (IS_ERR(priv->main_thread)) { + lbs_deb_thread("Error creating main thread.\n"); + goto done; + } priv->assoc_thread = create_singlethread_workqueue("libertas_assoc"); @@ -884,8 +884,8 @@ err_init_fw: err_registerdev: destroy_workqueue(priv->assoc_thread); /* Stop the thread servicing the interrupts */ - wake_up_interruptible(&priv->mainthread.waitq); - wlan_terminate_thread(&priv->mainthread); + wake_up_interruptible(&priv->waitq); + kthread_stop(priv->main_thread); done: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; @@ -1017,7 +1017,7 @@ int libertas_remove_card(wlan_private *priv) adapter->surpriseremoved = 1; /* Stop the thread servicing the interrupts */ - wlan_terminate_thread(&priv->mainthread); + kthread_stop(priv->main_thread); libertas_debugfs_remove_one(priv); @@ -1151,7 +1151,7 @@ void libertas_interrupt(struct net_device *dev) netif_wake_queue(priv->mesh_dev); } - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); lbs_deb_leave(LBS_DEB_THREAD); } diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h deleted file mode 100644 index b1f34d92ff3e..000000000000 --- a/drivers/net/wireless/libertas/thread.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef __WLAN_THREAD_H_ -#define __WLAN_THREAD_H_ - -#include - -struct wlan_thread { - struct task_struct *task; - wait_queue_head_t waitq; - pid_t pid; - void *priv; -}; - -static inline void wlan_activate_thread(struct wlan_thread * thr) -{ - /** Record the thread pid */ - thr->pid = current->pid; - - /** Initialize the wait queue */ - init_waitqueue_head(&thr->waitq); -} - -static inline void wlan_deactivate_thread(struct wlan_thread * thr) -{ - lbs_deb_enter(LBS_DEB_THREAD); - - thr->pid = 0; - - lbs_deb_leave(LBS_DEB_THREAD); -} - -static inline void wlan_create_thread(int (*wlanfunc) (void *), - struct wlan_thread * thr, char *name) -{ - thr->task = kthread_run(wlanfunc, thr, "%s", name); -} - -static inline int wlan_terminate_thread(struct wlan_thread * thr) -{ - lbs_deb_enter(LBS_DEB_THREAD); - - /* Check if the thread is active or not */ - if (!thr->pid) { - printk(KERN_ERR "Thread does not exist\n"); - return -1; - } - kthread_stop(thr->task); - - lbs_deb_leave(LBS_DEB_THREAD); - return 0; -} - -#endif From 276c015e1bf8d158df336bc2676c142e4bc391c1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:34:24 -0400 Subject: [PATCH 1238/2804] [PATCH] libertas: new mesh control knobs Support for new mesh control knobs on firmware 5.220.11.p4: Signed-off-by: Luis Carlos Cobo Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/host.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 4bd2e88116cc..7af921b0832f 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -312,6 +312,14 @@ enum CMD_MESH_ACCESS_opts { CMD_ACT_MESH_GET_STATS, CMD_ACT_MESH_GET_ANYCAST, CMD_ACT_MESH_SET_ANYCAST, + CMD_ACT_MESH_SET_LINK_COSTS, + CMD_ACT_MESH_GET_LINK_COSTS, + CMD_ACT_MESH_SET_BCAST_RATE, + CMD_ACT_MESH_GET_BCAST_RATE, + CMD_ACT_MESH_SET_RREQ_DELAY, + CMD_ACT_MESH_GET_RREQ_DELAY, + CMD_ACT_MESH_SET_ROUTE_EXP, + CMD_ACT_MESH_GET_ROUTE_EXP, }; /** Card Event definition */ From 125dcabf724bdfbe55240aef3b35b0ca16f3d61d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:34:47 -0400 Subject: [PATCH 1239/2804] [PATCH] libertas: bump version to 322.p1 Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e24875de8dc8..b9e4bf293224 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -22,7 +22,7 @@ #include "debugfs.h" #include "assoc.h" -#define DRIVER_RELEASE_VERSION "322.p0" +#define DRIVER_RELEASE_VERSION "322.p1" const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION #ifdef DEBUG "-dbg" From ffcae953ac021f5051a201c18e133cb0ce38c2b9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:35:46 -0400 Subject: [PATCH 1240/2804] [PATCH] libertas: fix more mixed-case abuse Mistakently introduced by a previous patch to upper-case all command constants. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 +++--- drivers/net/wireless/libertas/cmdresp.c | 6 +++--- drivers/net/wireless/libertas/fw.c | 2 +- drivers/net/wireless/libertas/host.h | 24 ++++++++++++------------ drivers/net/wireless/libertas/wext.c | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 401a630ed4e5..c96ced963d69 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -566,7 +566,7 @@ static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, S_DS_GEN); rant->action = cpu_to_le16(cmd_action); - if ((cmd_action == CMD_ACT_SET_rx) || (cmd_action == CMD_ACT_SET_tx)) { + if ((cmd_action == CMD_ACT_SET_RX) || (cmd_action == CMD_ACT_SET_TX)) { rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf)); } @@ -614,11 +614,11 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv, pdatarate->action = cpu_to_le16(cmd_action); - if (cmd_action == CMD_ACT_SET_tx_fix_rate) { + if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) { pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", adapter->datarate); - } else if (cmd_action == CMD_ACT_SET_tx_auto) { + } else if (cmd_action == CMD_ACT_SET_TX_AUTO) { lbs_deb_cmd("Setting FW for AUTO rate\n"); } diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 4c15071984b9..d90279269e7b 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -396,10 +396,10 @@ static int wlan_ret_802_11_rf_antenna(wlan_private * priv, wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(pAntenna->action); - if (action == CMD_ACT_GET_rx) + if (action == CMD_ACT_GET_RX) adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode); - if (action == CMD_ACT_GET_tx) + if (action == CMD_ACT_GET_TX) adapter->txantennamode = le16_to_cpu(pAntenna->antennamode); lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", @@ -438,7 +438,7 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); dot11datarate = pdatarate->datarate[0]; - if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_tx_rate)) { + if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_TX_RATE)) { memcpy(adapter->libertas_supported_rates, pdatarate->datarate, sizeof(adapter->libertas_supported_rates)); } diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index e7177598f94b..d214692eb209 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -111,7 +111,7 @@ static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) /* Get the supported Data rates */ ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, - CMD_ACT_GET_tx_rate, + CMD_ACT_GET_TX_RATE, CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) { diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 7af921b0832f..308ccdbed344 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -262,16 +262,16 @@ #define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 /* Define action or option for CMD_802_11_DATA_RATE */ -#define CMD_ACT_SET_tx_auto 0x0000 -#define CMD_ACT_SET_tx_fix_rate 0x0001 -#define CMD_ACT_GET_tx_rate 0x0002 +#define CMD_ACT_SET_TX_AUTO 0x0000 +#define CMD_ACT_SET_TX_FIX_RATE 0x0001 +#define CMD_ACT_GET_TX_RATE 0x0002 -#define CMD_ACT_SET_rx 0x0001 -#define CMD_ACT_SET_tx 0x0002 -#define CMD_ACT_SET_both 0x0003 -#define CMD_ACT_GET_rx 0x0004 -#define CMD_ACT_GET_tx 0x0008 -#define CMD_ACT_GET_both 0x000c +#define CMD_ACT_SET_RX 0x0001 +#define CMD_ACT_SET_TX 0x0002 +#define CMD_ACT_SET_BOTH 0x0003 +#define CMD_ACT_GET_RX 0x0004 +#define CMD_ACT_GET_TX 0x0008 +#define CMD_ACT_GET_BOTH 0x000c /* Define action or option for CMD_802_11_PS_MODE */ #define CMD_TYPE_CAM 0x0000 @@ -279,7 +279,7 @@ #define CMD_TYPE_FAST_PSP 0x0002 /* Define action or option for CMD_BT_ACCESS */ -enum CMD_BT_ACCESS_opts { +enum cmd_bt_access_opts { /* The bt commands start at 5 instead of 1 because the old dft commands * are mapped to 1-4. These old commands are no longer maintained and * should not be called. @@ -293,7 +293,7 @@ enum CMD_BT_ACCESS_opts { }; /* Define action or option for CMD_FWT_ACCESS */ -enum CMD_FWT_ACCESS_opts { +enum cmd_fwt_access_opts { CMD_ACT_FWT_ACCESS_ADD = 1, CMD_ACT_FWT_ACCESS_DEL, CMD_ACT_FWT_ACCESS_LOOKUP, @@ -306,7 +306,7 @@ enum CMD_FWT_ACCESS_opts { }; /* Define action or option for CMD_MESH_ACCESS */ -enum CMD_MESH_ACCESS_opts { +enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_TTL = 1, CMD_ACT_MESH_SET_TTL, CMD_ACT_MESH_GET_STATS, diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 7cfca5f3a5ef..115f02c010a1 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1128,7 +1128,7 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("vwrq->value %d\n", vwrq->value); if (vwrq->value == -1) { - action = CMD_ACT_SET_tx_auto; // Auto + action = CMD_ACT_SET_TX_AUTO; // Auto adapter->is_datarate_auto = 1; adapter->datarate = 0; } else { @@ -1155,7 +1155,7 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, } adapter->datarate = data_rate; - action = CMD_ACT_SET_tx_fix_rate; + action = CMD_ACT_SET_TX_FIX_RATE; adapter->is_datarate_auto = 0; } From eedc2a319154a64f5ca7f281c92b7af3691fe73c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:36:22 -0400 Subject: [PATCH 1241/2804] [PATCH] libertas: move generic firmware reset command to common code It's not USB specific, so move it out of the USB interface code. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/decl.h | 2 +- drivers/net/wireless/libertas/if_usb.c | 30 +++++++++----------------- drivers/net/wireless/libertas/main.c | 14 ++++++++++++ 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 40f56bb1eac8..846e79a77f67 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -86,6 +86,6 @@ int libertas_activate_card(wlan_private *priv, char *fw_name); int libertas_remove_card(wlan_private *priv); int libertas_add_mesh(wlan_private *priv, struct device *dev); void libertas_remove_mesh(wlan_private *priv); - +int libertas_reset_device(wlan_private *priv); #endif /* _WLAN_DECL_H_ */ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index a3334f63a80d..e38fce73cf74 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -15,6 +15,7 @@ #include "defs.h" #include "dev.h" #include "if_usb.h" +#include "decl.h" #define MESSAGE_HEADER_LEN 4 @@ -44,7 +45,6 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); static void if_usb_receive(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb); -static int if_usb_reset_device(wlan_private *priv); static int if_usb_register_dev(wlan_private * priv); static int if_usb_unregister_dev(wlan_private *); static int if_usb_prog_firmware(wlan_private *); @@ -355,17 +355,20 @@ static int if_prog_firmware(wlan_private * priv) return 0; } -static int libertas_do_reset(wlan_private *priv) +static int if_usb_reset_device(wlan_private *priv) { int ret; struct usb_card_rec *cardp = priv->card; lbs_deb_enter(LBS_DEB_USB); + /* Try a USB port reset first, if that fails send the reset + * command to the firmware. + */ ret = usb_reset_device(cardp->udev); if (!ret) { msleep(10); - if_usb_reset_device(priv); + ret = libertas_reset_device(priv); msleep(10); } @@ -753,19 +756,6 @@ static int if_usb_read_event_cause(wlan_private * priv) return 0; } -static int if_usb_reset_device(wlan_private *priv) -{ - int ret; - - lbs_deb_enter(LBS_DEB_USB); - ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET, - CMD_ACT_HALT, 0, 0, NULL); - msleep_interruptible(10); - - lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); - return ret; -} - static int if_usb_unregister_dev(wlan_private * priv) { int ret = 0; @@ -775,7 +765,7 @@ static int if_usb_unregister_dev(wlan_private * priv) * again. */ if (priv) - if_usb_reset_device(priv); + libertas_reset_device(priv); return ret; } @@ -862,7 +852,7 @@ restart: if (cardp->bootcmdresp == 0) { if (--reset_count >= 0) { - libertas_do_reset(priv); + if_usb_reset_device(priv); goto restart; } return -1; @@ -892,7 +882,7 @@ restart: if (!cardp->fwdnldover) { lbs_pr_info("failed to load fw, resetting device!\n"); if (--reset_count >= 0) { - libertas_do_reset(priv); + if_usb_reset_device(priv); goto restart; } @@ -995,7 +985,7 @@ static void if_usb_exit_module(void) lbs_deb_enter(LBS_DEB_MAIN); list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) - if_usb_reset_device((wlan_private *) cardp->priv); + libertas_reset_device((wlan_private *) cardp->priv); /* API unregisters the driver from USB subsystem */ usb_deregister(&if_usb_driver); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index b9e4bf293224..589c583ddbeb 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1157,6 +1157,20 @@ void libertas_interrupt(struct net_device *dev) } EXPORT_SYMBOL_GPL(libertas_interrupt); +int libertas_reset_device(wlan_private *priv) +{ + int ret; + + lbs_deb_enter(LBS_DEB_MAIN); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET, + CMD_ACT_HALT, 0, 0, NULL); + msleep_interruptible(10); + + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(libertas_reset_device); + static int libertas_init_module(void) { lbs_deb_enter(LBS_DEB_MAIN); From e52414728b930f0adcbc38c6498dd03b3568fe99 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:39:19 -0400 Subject: [PATCH 1242/2804] [PATCH] libertas: wlan_ -> libertas_ function prefix renames for main.c Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 71 ++++++++++++++-------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 589c583ddbeb..26948595d952 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -256,7 +256,7 @@ static int pre_open_check(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int wlan_dev_open(struct net_device *dev) +static int libertas_dev_open(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv; wlan_adapter *adapter = priv->adapter; @@ -282,7 +282,7 @@ static int wlan_dev_open(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int mesh_open(struct net_device *dev) +static int libertas_mesh_open(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv ; @@ -291,7 +291,7 @@ static int mesh_open(struct net_device *dev) priv->mesh_open = 1 ; netif_wake_queue(priv->mesh_dev); if (priv->infra_open == 0) - return wlan_dev_open(priv->dev) ; + return libertas_dev_open(priv->dev) ; return 0; } @@ -301,7 +301,7 @@ static int mesh_open(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int wlan_open(struct net_device *dev) +static int libertas_open(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv ; @@ -310,11 +310,11 @@ static int wlan_open(struct net_device *dev) priv->infra_open = 1 ; netif_wake_queue(priv->dev); if (priv->open == 0) - return wlan_dev_open(priv->dev) ; + return libertas_dev_open(priv->dev) ; return 0; } -static int wlan_dev_close(struct net_device *dev) +static int libertas_dev_close(struct net_device *dev) { wlan_private *priv = dev->priv; @@ -333,14 +333,14 @@ static int wlan_dev_close(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int mesh_close(struct net_device *dev) +static int libertas_mesh_close(struct net_device *dev) { wlan_private *priv = (wlan_private *) (dev->priv); priv->mesh_open = 0; netif_stop_queue(priv->mesh_dev); if (priv->infra_open == 0) - return wlan_dev_close(dev); + return libertas_dev_close(dev); else return 0; } @@ -351,20 +351,20 @@ static int mesh_close(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int wlan_close(struct net_device *dev) +static int libertas_close(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv; netif_stop_queue(dev); priv->infra_open = 0; if (priv->mesh_open == 0) - return wlan_dev_close(dev); + return libertas_dev_close(dev); else return 0; } -static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { int ret = 0; wlan_private *priv = dev->priv; @@ -387,10 +387,11 @@ done: } /** - * @brief Mark mesh packets and handover them to wlan_hard_start_xmit + * @brief Mark mesh packets and handover them to libertas_hard_start_xmit * */ -static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int libertas_mesh_pre_start_xmit(struct sk_buff *skb, + struct net_device *dev) { wlan_private *priv = dev->priv; int ret; @@ -399,16 +400,16 @@ static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) SET_MESH_FRAME(skb); - ret = wlan_hard_start_xmit(skb, priv->dev); + ret = libertas_hard_start_xmit(skb, priv->dev); lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } /** - * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit + * @brief Mark non-mesh packets and handover them to libertas_hard_start_xmit * */ -static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) { int ret; @@ -416,12 +417,12 @@ static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) UNSET_MESH_FRAME(skb); - ret = wlan_hard_start_xmit(skb, dev); + ret = libertas_hard_start_xmit(skb, dev); lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } -static void wlan_tx_timeout(struct net_device *dev) +static void libertas_tx_timeout(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv; @@ -454,14 +455,14 @@ static void wlan_tx_timeout(struct net_device *dev) * @param dev A pointer to wlan_private structure * @return A pointer to net_device_stats structure */ -static struct net_device_stats *wlan_get_stats(struct net_device *dev) +static struct net_device_stats *libertas_get_stats(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv; return &priv->stats; } -static int wlan_set_mac_address(struct net_device *dev, void *addr) +static int libertas_set_mac_address(struct net_device *dev, void *addr) { int ret = 0; wlan_private *priv = (wlan_private *) dev->priv; @@ -501,7 +502,7 @@ done: return ret; } -static int wlan_copy_multicast_address(wlan_adapter * adapter, +static int libertas_copy_multicast_address(wlan_adapter * adapter, struct net_device *dev) { int i = 0; @@ -516,7 +517,7 @@ static int wlan_copy_multicast_address(wlan_adapter * adapter, } -static void wlan_set_multicast_list(struct net_device *dev) +static void libertas_set_multicast_list(struct net_device *dev) { wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; @@ -561,7 +562,7 @@ static void wlan_set_multicast_list(struct net_device *dev) CMD_ACT_MAC_MULTICAST_ENABLE; adapter->nr_of_multicastmacaddr = - wlan_copy_multicast_address(adapter, dev); + libertas_copy_multicast_address(adapter, dev); lbs_deb_net("multicast addresses: %d\n", dev->mc_count); @@ -796,12 +797,12 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) SET_MODULE_OWNER(dev); /* Setup the OS Interface to our functions */ - dev->open = wlan_open; - dev->hard_start_xmit = wlan_pre_start_xmit; - dev->stop = wlan_close; - dev->set_mac_address = wlan_set_mac_address; - dev->tx_timeout = wlan_tx_timeout; - dev->get_stats = wlan_get_stats; + dev->open = libertas_open; + dev->hard_start_xmit = libertas_pre_start_xmit; + dev->stop = libertas_close; + dev->set_mac_address = libertas_set_mac_address; + dev->tx_timeout = libertas_tx_timeout; + dev->get_stats = libertas_get_stats; dev->watchdog_timeo = 5 * HZ; dev->ethtool_ops = &libertas_ethtool_ops; #ifdef WIRELESS_EXT @@ -810,7 +811,7 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) #define NETIF_F_DYNALLOC 16 dev->features |= NETIF_F_DYNALLOC; dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - dev->set_multicast_list = wlan_set_multicast_list; + dev->set_multicast_list = libertas_set_multicast_list; SET_NETDEV_DEV(dev, dmdev); @@ -917,11 +918,11 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) SET_MODULE_OWNER(mesh_dev); - mesh_dev->open = mesh_open; - mesh_dev->hard_start_xmit = mesh_pre_start_xmit; - mesh_dev->stop = mesh_close; - mesh_dev->get_stats = wlan_get_stats; - mesh_dev->set_mac_address = wlan_set_mac_address; + mesh_dev->open = libertas_mesh_open; + mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit; + mesh_dev->stop = libertas_mesh_close; + mesh_dev->get_stats = libertas_get_stats; + mesh_dev->set_mac_address = libertas_set_mac_address; mesh_dev->ethtool_ops = &libertas_ethtool_ops; memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, sizeof(priv->dev->dev_addr)); From 8c5127657549d055ac9d709cdea73902a6ef392c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:40:45 -0400 Subject: [PATCH 1243/2804] [PATCH] libertas: simplify and clean up data rate handling Remove unused/duplicated fields and consolidate static data rate arrays, for example the libertas_supported_rates[] and datarates[] arrays in the bss_descriptor structure, and the libertas_supported_rates field in the wlan_adapter structure. Introduce libertas_fw_index_to_data_rate and libertas_data_rate_to_fw_index functions and use them everywhere firmware requires a rate index rather than a rate array. The firmware requires the 4 basic rates to have the MSB set, but most other stuff doesn't, like WEXT and mesh ioctls. Therefore, only set the MSB on basic rates when pushing rate arrays to firmware instead of doing a ton of (rate & 0x7f) everywhere. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 7 +- drivers/net/wireless/libertas/cmdresp.c | 17 +- drivers/net/wireless/libertas/decl.h | 4 +- drivers/net/wireless/libertas/defs.h | 11 +- drivers/net/wireless/libertas/dev.h | 16 +- drivers/net/wireless/libertas/fw.c | 9 +- drivers/net/wireless/libertas/hostcmd.h | 8 +- drivers/net/wireless/libertas/join.c | 203 ++++++++++++------------ drivers/net/wireless/libertas/join.h | 2 + drivers/net/wireless/libertas/main.c | 69 +++++--- drivers/net/wireless/libertas/rx.c | 9 +- drivers/net/wireless/libertas/scan.c | 54 +++---- drivers/net/wireless/libertas/scan.h | 4 +- drivers/net/wireless/libertas/wext.c | 165 +++++-------------- 14 files changed, 248 insertions(+), 330 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c96ced963d69..c3fc074b6e3a 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -607,17 +607,14 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE); - memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); - pdatarate->action = cpu_to_le16(cmd_action); if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) { - pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); + pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate); lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", - adapter->datarate); + adapter->cur_rate); } else if (cmd_action == CMD_ACT_SET_TX_AUTO) { lbs_deb_cmd("Setting FW for AUTO rate\n"); } diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index d90279269e7b..577c434089b0 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -430,21 +430,18 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, { struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; wlan_adapter *adapter = priv->adapter; - u8 dot11datarate; lbs_deb_enter(LBS_DEB_CMD); - lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", - (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); + lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate, + sizeof(struct cmd_ds_802_11_data_rate)); - dot11datarate = pdatarate->datarate[0]; - if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_TX_RATE)) { - memcpy(adapter->libertas_supported_rates, pdatarate->datarate, - sizeof(adapter->libertas_supported_rates)); - } - adapter->datarate = libertas_index_to_data_rate(dot11datarate); + /* FIXME: get actual rates FW can do if this command actually returns + * all data rates supported. + */ + adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]); - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 846e79a77f67..129b021d35fd 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -44,8 +44,8 @@ int libertas_execute_next_command(wlan_private * priv); int libertas_process_event(wlan_private * priv); void libertas_interrupt(struct net_device *); int libertas_set_radio_control(wlan_private * priv); -u32 libertas_index_to_data_rate(u8 index); -u8 libertas_data_rate_to_index(u32 rate); +u32 libertas_fw_index_to_data_rate(u8 index); +u8 libertas_data_rate_to_fw_index(u32 rate); void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen); void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 862292913c2c..a1c6dae1ba46 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -246,10 +246,7 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \ AVG_SCALE)) / N)) -#define B_SUPPORTED_RATES 8 -#define G_SUPPORTED_RATES 14 - -#define WLAN_SUPPORTED_RATES 14 +#define MAX_RATES 14 #define MAX_LEDS 8 @@ -263,11 +260,7 @@ typedef struct _wlan_adapter wlan_adapter; extern const char libertas_driver_version[]; extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE]; -extern u8 libertas_supported_rates[G_SUPPORTED_RATES]; - -extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES]; - -extern u8 libertas_adhoc_rates_b[4]; +extern u8 libertas_bg_rates[MAX_RATES]; /** ENUM definition*/ /** SNRNF_TYPE */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index c6fb703f665b..6acb8fb8733e 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -72,10 +72,8 @@ struct current_bss_params { u8 band; /** channel */ u8 channel; - /** number of rates supported */ - int numofrates; - /** supported rates*/ - u8 datarates[WLAN_SUPPORTED_RATES]; + /** zero-terminated array of supported data rates */ + u8 rates[MAX_RATES + 1]; }; /** sleep_params */ @@ -296,9 +294,6 @@ struct _wlan_adapter { u32 fragthsd; u32 rtsthsd; - u32 datarate; - u8 is_datarate_auto; - u16 listeninterval; u16 prescan; u8 txretrycount; @@ -364,10 +359,9 @@ struct _wlan_adapter { u8 radioon; u32 preamble; - /** Multi bands Parameter*/ - u8 libertas_supported_rates[G_SUPPORTED_RATES]; - - /** Blue Tooth Co-existence Arbitration */ + /** data rate stuff */ + u8 cur_rate; + u8 auto_rate; /** sleep_params */ struct sleep_params sp; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index d214692eb209..6c259878da96 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -214,7 +214,10 @@ static void wlan_init_adapter(wlan_private * priv) adapter->txantenna = RF_ANTENNA_2; adapter->rxantenna = RF_ANTENNA_AUTO; - adapter->is_datarate_auto = 1; + adapter->auto_rate = 1; + adapter->cur_rate = 0; + adapter->adhoc_grate_enabled = 0; + adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; // set default capabilities @@ -229,10 +232,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->needtowakeup = 0; adapter->locallisteninterval = 0; /* default value in firmware will be used */ - adapter->datarate = 0; // Initially indicate the rate as auto - - adapter->adhoc_grate_enabled = 0; - adapter->intcounter = 0; adapter->currenttxskb = NULL; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 76c5fdeb256a..44cf39c8d1b8 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -428,8 +428,8 @@ struct PS_CMD_ConfirmSleep { struct cmd_ds_802_11_data_rate { __le16 action; - __le16 reserverd; - u8 datarate[G_SUPPORTED_RATES]; + __le16 reserved; + u8 rates[MAX_RATES]; }; struct cmd_ds_802_11_rate_adapt_rateset { @@ -447,7 +447,7 @@ struct cmd_ds_802_11_ad_hoc_start { union ieeetypes_phyparamset phyparamset; __le16 probedelay; __le16 capability; - u8 datarate[G_SUPPORTED_RATES]; + u8 rates[MAX_RATES]; u8 tlv_memory_size_pad[100]; } __attribute__ ((packed)); @@ -462,7 +462,7 @@ struct adhoc_bssdesc { union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; __le16 capability; - u8 datarates[G_SUPPORTED_RATES]; + u8 rates[MAX_RATES]; /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the * Adhoc join command and will cause a binary layout mismatch with diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 381739d6ed96..78e398d6f5f3 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -17,8 +17,12 @@ #include "dev.h" #include "assoc.h" +/* Supported rates for ad-hoc B mode */ +u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; + + /** - * @brief This function finds out the common rates between rate1 and rate2. + * @brief This function finds common rates between rate1 and card rates. * * It will fill common rates in rate1 as output if found. * @@ -27,61 +31,87 @@ * * @param adapter A pointer to wlan_adapter structure * @param rate1 the buffer which keeps input and output - * @param rate1_size the size of rate1 buffer - * @param rate2 the buffer which keeps rate2 - * @param rate2_size the size of rate2 buffer. + * @param rate1_size the size of rate1 buffer; new size of buffer on return * * @return 0 or -1 */ -static int get_common_rates(wlan_adapter * adapter, u8 * rate1, - int rate1_size, u8 * rate2, int rate2_size) +static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size) { - u8 *ptr = rate1; - int ret = 0; + u8 *card_rates = libertas_bg_rates; + size_t num_card_rates = sizeof(libertas_bg_rates); + int ret = 0, i, j; u8 tmp[30]; - int i; + size_t tmp_size = 0; - memset(&tmp, 0, sizeof(tmp)); - memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp))); - memset(rate1, 0, rate1_size); - - /* Mask the top bit of the original values */ - for (i = 0; tmp[i] && i < sizeof(tmp); i++) - tmp[i] &= 0x7F; - - for (i = 0; rate2[i] && i < rate2_size; i++) { - /* Check for Card Rate in tmp, excluding the top bit */ - if (strchr(tmp, rate2[i] & 0x7F)) { - /* values match, so copy the Card Rate to rate1 */ - *rate1++ = rate2[i]; + /* 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]; } } - lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp)); - lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size); - lbs_dbg_hex("Common rates:", ptr, rate1_size); - lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate); + lbs_dbg_hex("rate1 (AP) rates:", rates, *rates_size); + lbs_dbg_hex("rate2 (Card) rates:", card_rates, num_card_rates); + lbs_dbg_hex("Common rates:", tmp, tmp_size); + lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate); - if (!adapter->is_datarate_auto) { - while (*ptr) { - if ((*ptr & 0x7f) == adapter->datarate) { - ret = 0; + if (!adapter->auto_rate) { + for (i = 0; i < tmp_size; i++) { + if (tmp[i] == adapter->cur_rate) goto done; - } - ptr++; } - lbs_pr_alert( "Previously set fixed data rate %#x isn't " - "compatible with the network.\n", adapter->datarate); - + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", adapter->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); return ret; } + +/** + * @brief Sets the MSB on basic rates as the firmware requires + * + * Scan through an array and set the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +static void libertas_set_basic_rate_flags(u8 * rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (rates[i] == 0x02 || rates[i] == 0x04 || + rates[i] == 0x0b || rates[i] == 0x16) + rates[i] |= 0x80; + } +} + +/** + * @brief Unsets the MSB on basic rates + * + * Scan through an array and unset the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +void libertas_unset_basic_rate_flags(u8 * rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + rates[i] &= 0x7f; +} + + int libertas_send_deauth(wlan_private * priv) { wlan_adapter *adapter = priv->adapter; @@ -330,9 +360,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, int ret = 0; struct assoc_request * assoc_req = pdata_buf; struct bss_descriptor * bss = &assoc_req->bss; - u8 *card_rates; u8 *pos; - int card_rates_size; u16 tmpcap, tmplen; struct mrvlietypes_ssidparamset *ssid; struct mrvlietypes_phyparamset *phy; @@ -386,23 +414,24 @@ int libertas_cmd_80211_associate(wlan_private * priv, rates = (struct mrvlietypes_ratesparamset *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - - memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES); - - card_rates = libertas_supported_rates; - card_rates_size = sizeof(libertas_supported_rates); - - if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES, - card_rates, card_rates_size)) { + memcpy(&rates->rates, &bss->rates, MAX_RATES); + tmplen = MAX_RATES; + if (get_common_rates(adapter, rates->rates, &tmplen)) { ret = -1; goto done; } - - tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES); - adapter->curbssparams.numofrates = tmplen; - pos += sizeof(rates->header) + tmplen; rates->header.len = cpu_to_le16(tmplen); + lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen); + + /* Copy the infra. association rates into Current BSS state structure */ + memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); + memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + libertas_set_basic_rate_flags(rates->rates, tmplen); if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { rsn = (struct mrvlietypes_rsnparamset *) pos; @@ -419,14 +448,6 @@ int libertas_cmd_80211_associate(wlan_private * priv, /* update curbssparams */ adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; - /* Copy the infra. association rates into Current BSS state structure */ - memcpy(&adapter->curbssparams.datarates, &rates->rates, - min_t(size_t, sizeof(adapter->curbssparams.datarates), - cpu_to_le16(rates->header.len))); - - lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n", - cpu_to_le16(rates->header.len)); - if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { ret = -1; goto done; @@ -454,9 +475,9 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; int ret = 0; int cmdappendsize = 0; - int i; struct assoc_request * assoc_req = pdata_buf; u16 tmpcap = 0; + size_t ratesize = 0; lbs_deb_enter(LBS_DEB_JOIN); @@ -526,28 +547,26 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, /* probedelay */ adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - memset(adhs->datarate, 0, sizeof(adhs->datarate)); - + memset(adhs->rates, 0, sizeof(adhs->rates)); if (adapter->adhoc_grate_enabled) { - memcpy(adhs->datarate, libertas_adhoc_rates_g, - min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g))); + ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates)); + memcpy(adhs->rates, libertas_bg_rates, ratesize); } else { - memcpy(adhs->datarate, libertas_adhoc_rates_b, - min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b))); + ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b)); + memcpy(adhs->rates, adhoc_rates_b, ratesize); } - /* Find the last non zero */ - for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ; - - adapter->curbssparams.numofrates = i; - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memcpy(&adapter->curbssparams.datarates, - &adhs->datarate, adapter->curbssparams.numofrates); + memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); + memcpy(&adapter->curbssparams.rates, &adhs->rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + libertas_set_basic_rate_flags(adhs->rates, ratesize); lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", - adhs->datarate[0], adhs->datarate[1], - adhs->datarate[2], adhs->datarate[3]); + adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); @@ -584,9 +603,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, struct bss_descriptor *bss = &assoc_req->bss; int cmdappendsize = 0; int ret = 0; - u8 *card_rates; - int card_rates_size; - int i; + u16 ratesize = 0; lbs_deb_enter(LBS_DEB_JOIN); @@ -619,36 +636,26 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, /* probedelay */ join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - /* Copy Data rates from the rates recorded in scan response */ - memset(join_cmd->bss.datarates, 0, sizeof(join_cmd->bss.datarates)); - memcpy(join_cmd->bss.datarates, bss->datarates, - min(sizeof(join_cmd->bss.datarates), sizeof(bss->datarates))); - - card_rates = libertas_supported_rates; - card_rates_size = sizeof(libertas_supported_rates); - adapter->curbssparams.channel = bss->channel; - if (get_common_rates(adapter, join_cmd->bss.datarates, - sizeof(join_cmd->bss.datarates), - card_rates, card_rates_size)) { + /* Copy Data rates from the rates recorded in scan response */ + memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); + ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); + memcpy(join_cmd->bss.rates, bss->rates, ratesize); + if (get_common_rates(adapter, join_cmd->bss.rates, &ratesize)) { lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); ret = -1; goto done; } - /* Find the last non zero */ - for (i = 0; i < sizeof(join_cmd->bss.datarates) - && join_cmd->bss.datarates[i]; i++) ; + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); + memcpy(&adapter->curbssparams.rates, join_cmd->bss.rates, ratesize); - adapter->curbssparams.numofrates = i; - - /* - * Copy the adhoc joining rates to Current BSS State structure + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. */ - memcpy(adapter->curbssparams.datarates, - join_cmd->bss.datarates, - adapter->curbssparams.numofrates); + libertas_set_basic_rate_flags(join_cmd->bss.rates, ratesize); join_cmd->bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h index d522630ff8cf..8ea5ae30f4ab 100644 --- a/drivers/net/wireless/libertas/join.h +++ b/drivers/net/wireless/libertas/join.h @@ -53,4 +53,6 @@ extern int libertas_do_adhocstop_ioctl(wlan_private * priv); int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req); +void libertas_unset_basic_rate_flags(u8 * rates, size_t len); + #endif diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 26948595d952..03217f5537ad 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -149,31 +149,62 @@ static struct region_cfp_table region_cfp_table[] = { /*Add new region here */ }; -/** - * the rates supported - */ -u8 libertas_supported_rates[G_SUPPORTED_RATES] = - { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, -0 }; - -/** - * the rates supported for ad-hoc G mode - */ -u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] = - { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, -0 }; - -/** - * the rates supported for ad-hoc B mode - */ -u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 }; - /** * the table to keep region code */ u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; +/** + * 802.11b/g supported bitrates (in 500Kb/s units) + */ +u8 libertas_bg_rates[MAX_RATES] = + { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, +0x00, 0x00 }; + +/** + * FW rate table. FW refers to rates by their index in this table, not by the + * rate value itself. Values of 0x00 are + * reserved positions. + */ +static u8 fw_data_rates[MAX_RATES] = + { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, + 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00 +}; + +/** + * @brief use index to get the data rate + * + * @param idx The index of data rate + * @return data rate or 0 + */ +u32 libertas_fw_index_to_data_rate(u8 idx) +{ + if (idx >= sizeof(fw_data_rates)) + idx = 0; + return fw_data_rates[idx]; +} + +/** + * @brief use rate to get the index + * + * @param rate data rate + * @return index or 0 + */ +u8 libertas_data_rate_to_fw_index(u32 rate) +{ + u8 i; + + if (!rate) + return 0; + + for (i = 0; i < sizeof(fw_data_rates); i++) { + if (rate == fw_data_rates[i]) + return i; + } + return 0; +} + /** * Attributes exported through sysfs */ diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 769c86fb9509..e78636d6651a 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -260,8 +260,8 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (adapter->is_datarate_auto) - adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate); + if (adapter->auto_rate) + adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate); wlan_compute_rssi(priv, p_rx_pd); @@ -424,9 +424,8 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (adapter->is_datarate_auto) { - adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate); - } + if (adapter->auto_rate) + adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate); wlan_compute_rssi(priv, prxpd); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 2cac47fc4cd9..790e9888ea2b 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -17,6 +17,7 @@ #include "decl.h" #include "dev.h" #include "scan.h" +#include "join.h" //! Approximate amount of data needed to pass a scan result back to iwlist #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ @@ -904,22 +905,14 @@ static int libertas_process_bss(struct bss_descriptor * bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - u8 *pos, *end; - u8 *pRate; - u8 bytestocopy; - u8 ratesize; - u16 beaconsize; - u8 founddatarateie; + struct ieeetypes_countryinfoset *pcountryinfo; + u8 *pos, *end, *p; + u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; + u16 beaconsize = 0; int ret; - struct ieeetypes_countryinfoset *pcountryinfo; - lbs_deb_enter(LBS_DEB_ASSOC); - founddatarateie = 0; - ratesize = 0; - beaconsize = 0; - if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ beaconsize = le16_to_cpup((void *)*pbeaconinfo); @@ -1005,11 +998,9 @@ static int libertas_process_bss(struct bss_descriptor * bss, break; case MFIE_TYPE_RATES: - memcpy(bss->datarates, elem->data, elem->len); - memmove(bss->libertas_supported_rates, elem->data, - elem->len); - ratesize = elem->len; - founddatarateie = 1; + n_basic_rates = min_t(u8, MAX_RATES, elem->len); + memcpy(bss->rates, elem->data, n_basic_rates); + got_basic_rates = 1; break; case MFIE_TYPE_FH_SET: @@ -1070,22 +1061,15 @@ static int libertas_process_bss(struct bss_descriptor * bss, * already found. Data rate IE should come before * extended supported rate IE */ - if (!founddatarateie) + if (!got_basic_rates) break; - if ((elem->len + ratesize) > WLAN_SUPPORTED_RATES) { - bytestocopy = - (WLAN_SUPPORTED_RATES - ratesize); - } else { - bytestocopy = elem->len; - } + n_ex_rates = elem->len; + if (n_basic_rates + n_ex_rates > MAX_RATES) + n_ex_rates = MAX_RATES - n_basic_rates; - pRate = (u8 *) bss->datarates; - pRate += ratesize; - memmove(pRate, elem->data, bytestocopy); - pRate = (u8 *) bss->libertas_supported_rates; - pRate += ratesize; - memmove(pRate, elem->data, bytestocopy); + p = bss->rates + n_basic_rates; + memcpy(p, elem->data, n_ex_rates); break; case MFIE_TYPE_GENERIC: @@ -1123,6 +1107,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* Timestamp */ bss->last_scanned = jiffies; + libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); ret = 0; @@ -1530,12 +1515,9 @@ static inline char *libertas_translate_scan(wlan_private *priv, iwe.u.bitrate.disabled = 0; iwe.u.bitrate.value = 0; - for (j = 0; j < sizeof(bss->libertas_supported_rates); j++) { - u8 rate = bss->libertas_supported_rates[j]; - if (rate == 0) - break; /* no more rates */ - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = (rate & 0x7f) * 500000; + for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) { + /* Bit rate given in 500 kb/s units */ + iwe.u.bitrate.value = bss->rates[j] * 500000; current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); } diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 23c539c22634..8c3508b3257f 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -152,14 +152,14 @@ struct bss_descriptor { u32 atimwindow; u8 mode; - u8 libertas_supported_rates[WLAN_SUPPORTED_RATES]; + /* zero-terminated array of supported data rates */ + u8 rates[MAX_RATES + 1]; __le64 timestamp; //!< TSF value included in the beacon/probe response unsigned long last_scanned; union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; - u8 datarates[WLAN_SUPPORTED_RATES]; u64 networktsf; //!< TSF timestamp from the current firmware TSF diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 115f02c010a1..0b805e32993a 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -21,14 +21,6 @@ #include "assoc.h" -/** - * the rates supported by the card - */ -static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] = - { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, - 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00 -}; - /** * @brief Convert mw value to dbm value * @@ -187,57 +179,21 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option) } /** - * @brief Copy rates - * - * @param dest A pointer to Dest Buf - * @param src A pointer to Src Buf - * @param len The len of Src Buf - * @return Number of rates copyed - */ -static inline int copyrates(u8 * dest, int pos, u8 * src, int len) -{ - int i; - - for (i = 0; i < len && src[i]; i++, pos++) { - if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES) - break; - dest[pos] = src[i]; - } - - return pos; -} - -/** - * @brief Get active data rates + * @brief Copy active data rates based on adapter mode and status * * @param adapter A pointer to wlan_adapter structure * @param rate The buf to return the active rates - * @return The number of rates */ -static int get_active_data_rates(wlan_adapter * adapter, - u8* rates) +static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates) { - int k = 0; - lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status != LIBERTAS_CONNECTED) { - if (adapter->mode == IW_MODE_INFRA) { - lbs_deb_wext("infra\n"); - k = copyrates(rates, k, libertas_supported_rates, - sizeof(libertas_supported_rates)); - } else { - lbs_deb_wext("Adhoc G\n"); - k = copyrates(rates, k, libertas_adhoc_rates_g, - sizeof(libertas_adhoc_rates_g)); - } - } else { - k = copyrates(rates, 0, adapter->curbssparams.datarates, - adapter->curbssparams.numofrates); - } + if (adapter->connect_status != LIBERTAS_CONNECTED) + memcpy(rates, libertas_bg_rates, MAX_RATES); + else + memcpy(rates, adapter->curbssparams.rates, MAX_RATES); - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k); - return k; + lbs_deb_leave(LBS_DEB_WEXT); } static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, @@ -673,7 +629,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, wlan_adapter *adapter = priv->adapter; struct iw_range *range = (struct iw_range *)extra; struct chan_freq_power *cfp; - u8 rates[WLAN_SUPPORTED_RATES]; + u8 rates[MAX_RATES + 1]; u8 flag = 0; @@ -686,12 +642,10 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, range->max_nwid = 0; memset(rates, 0, sizeof(rates)); - range->num_bitrates = get_active_data_rates(adapter, rates); - - for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i]; - i++) { - range->bitrate[i] = (rates[i] & 0x7f) * 500000; - } + copy_active_data_rates(adapter, rates); + range->num_bitrates = strnlen(rates, IW_MAX_BITRATES); + for (i = 0; i < range->num_bitrates; i++) + range->bitrate[i] = rates[i] * 500000; range->num_bitrates = i; lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES, range->num_bitrates); @@ -1080,88 +1034,46 @@ out: return ret; } -/** - * @brief use index to get the data rate - * - * @param index The index of data rate - * @return data rate or 0 - */ -u32 libertas_index_to_data_rate(u8 index) -{ - if (index >= sizeof(libertas_wlan_data_rates)) - index = 0; - - return libertas_wlan_data_rates[index]; -} - -/** - * @brief use rate to get the index - * - * @param rate data rate - * @return index or 0 - */ -u8 libertas_data_rate_to_index(u32 rate) -{ - u8 *ptr; - - if (rate) - if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate, - sizeof(libertas_wlan_data_rates)))) - return (ptr - libertas_wlan_data_rates); - - return 0; -} - static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; - u32 data_rate; + u32 new_rate; u16 action; - int ret = 0; - u8 rates[WLAN_SUPPORTED_RATES]; - u8 *rate; + int ret = -EINVAL; + u8 rates[MAX_RATES + 1]; lbs_deb_enter(LBS_DEB_WEXT); - lbs_deb_wext("vwrq->value %d\n", vwrq->value); + /* Auto rate? */ if (vwrq->value == -1) { - action = CMD_ACT_SET_TX_AUTO; // Auto - adapter->is_datarate_auto = 1; - adapter->datarate = 0; + action = CMD_ACT_SET_TX_AUTO; + adapter->auto_rate = 1; + adapter->cur_rate = 0; } else { - if (vwrq->value % 100000) { - return -EINVAL; - } - - data_rate = vwrq->value / 500000; + if (vwrq->value % 100000) + goto out; memset(rates, 0, sizeof(rates)); - get_active_data_rates(adapter, rates); - rate = rates; - while (*rate) { - lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate, - data_rate); - if ((*rate & 0x7f) == (data_rate & 0x7f)) - break; - rate++; - } - if (!*rate) { - lbs_pr_alert("fixed data rate 0x%X out " - "of range\n", data_rate); - return -EINVAL; + copy_active_data_rates(adapter, rates); + new_rate = vwrq->value / 500000; + if (!memchr(rates, new_rate, sizeof(rates))) { + lbs_pr_alert("fixed data rate 0x%X out of range\n", + new_rate); + goto out; } - adapter->datarate = data_rate; + adapter->cur_rate = new_rate; action = CMD_ACT_SET_TX_FIX_RATE; - adapter->is_datarate_auto = 0; + adapter->auto_rate = 0; } ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, action, CMD_OPTION_WAITFORRSP, 0, NULL); +out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } @@ -1174,13 +1086,18 @@ static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->is_datarate_auto) { - vwrq->fixed = 0; - } else { - vwrq->fixed = 1; - } + if (adapter->connect_status == LIBERTAS_CONNECTED) { + vwrq->value = adapter->cur_rate * 500000; - vwrq->value = adapter->datarate * 500000; + if (adapter->auto_rate) + vwrq->fixed = 0; + else + vwrq->fixed = 1; + + } else { + vwrq->fixed = 0; + vwrq->value = 0; + } lbs_deb_leave(LBS_DEB_WEXT); return 0; From 1df4e8fe91d5bab3fd7ae7f115e43c52010cd4ad Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:45:12 -0400 Subject: [PATCH 1244/2804] [PATCH] libertas: remove fw.c Firmware download is quite different for different hardware. The SDIO and CF cards have two flat files that need to be downloaded, whereas the USB driver needs only one file, but with an internal structure. The code that handles this (USB only) structured file is currently in fw.c. This patch moves this code into if_usb.c. The remaining functions in fw.c have not much to do with firmware, they are various card- and network-stack initialisation functions. I've moved them into main.c. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Makefile | 2 +- drivers/net/wireless/libertas/decl.h | 5 +- drivers/net/wireless/libertas/fw.c | 346 ------------------------- drivers/net/wireless/libertas/if_usb.c | 78 +++++- drivers/net/wireless/libertas/main.c | 278 +++++++++++++++++++- 5 files changed, 354 insertions(+), 355 deletions(-) delete mode 100644 drivers/net/wireless/libertas/fw.c diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 61e0d6e07901..b56b4c55de31 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,4 +1,4 @@ -libertas-objs := main.o fw.o wext.o \ +libertas-objs := main.o wext.o \ rx.o tx.o cmd.o \ cmdresp.o scan.o \ join.o 11d.o \ diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 129b021d35fd..113cfc1395e3 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -75,14 +75,11 @@ void libertas_mac_event_disconnected(wlan_private * priv); void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); -/* fw.c */ -int libertas_init_fw(wlan_private * priv, char *fw_name); - /* main.c */ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no); wlan_private *libertas_add_card(void *card, struct device *dmdev); -int libertas_activate_card(wlan_private *priv, char *fw_name); +int libertas_activate_card(wlan_private *priv); int libertas_remove_card(wlan_private *priv); int libertas_add_mesh(wlan_private *priv, struct device *dev); void libertas_remove_mesh(wlan_private *priv); diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c deleted file mode 100644 index 6c259878da96..000000000000 --- a/drivers/net/wireless/libertas/fw.c +++ /dev/null @@ -1,346 +0,0 @@ -/** - * This file contains the initialization for FW and HW - */ -#include - -#include "host.h" -#include "defs.h" -#include "decl.h" -#include "dev.h" -#include "wext.h" -#include "if_usb.h" - -/** - * @brief This function checks the validity of Boot2/FW image. - * - * @param data pointer to image - * len image length - * @return 0 or -1 - */ -static int check_fwfile_format(u8 *data, u32 totlen) -{ - u32 bincmd, exit; - u32 blksize, offset, len; - int ret; - - ret = 1; - exit = len = 0; - - do { - struct fwheader *fwh = (void *)data; - - bincmd = le32_to_cpu(fwh->dnldcmd); - blksize = le32_to_cpu(fwh->datalength); - switch (bincmd) { - case FW_HAS_DATA_TO_RECV: - offset = sizeof(struct fwheader) + blksize; - data += offset; - len += offset; - if (len >= totlen) - exit = 1; - break; - case FW_HAS_LAST_BLOCK: - exit = 1; - ret = 0; - break; - default: - exit = 1; - break; - } - } while (!exit); - - if (ret) - lbs_pr_err("firmware file format check FAIL\n"); - else - lbs_deb_fw("firmware file format check PASS\n"); - - return ret; -} - -/** - * @brief This function downloads firmware image, gets - * HW spec from firmware and set basic parameters to - * firmware. - * - * @param priv A pointer to wlan_private structure - * @return 0 or -1 - */ -static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; - - lbs_deb_enter(LBS_DEB_FW); - - if ((ret = request_firmware(&priv->firmware, fw_name, - priv->hotplug_device)) < 0) { - lbs_pr_err("request_firmware() failed with %#x\n", ret); - lbs_pr_err("firmware %s not found\n", fw_name); - goto done; - } - - if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) { - release_firmware(priv->firmware); - goto done; - } - - ret = priv->hw_prog_firmware(priv); - - release_firmware(priv->firmware); - - if (ret) { - lbs_deb_fw("bootloader in invalid state\n"); - ret = -1; - goto done; - } - - /* - * Read MAC address from HW - */ - memset(adapter->current_addr, 0xff, ETH_ALEN); - - ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); - - if (ret) { - ret = -1; - goto done; - } - - libertas_set_mac_packet_filter(priv); - - /* Get the supported Data rates */ - ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, - CMD_ACT_GET_TX_RATE, - CMD_OPTION_WAITFORRSP, 0, NULL); - - if (ret) { - ret = -1; - goto done; - } - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); - return ret; -} - -static int wlan_allocate_adapter(wlan_private * priv) -{ - size_t bufsize; - wlan_adapter *adapter = priv->adapter; - - /* Allocate buffer to store the BSSID list */ - bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); - adapter->networks = kzalloc(bufsize, GFP_KERNEL); - if (!adapter->networks) { - lbs_pr_err("Out of memory allocating beacons\n"); - libertas_free_adapter(priv); - return -ENOMEM; - } - - /* Allocate the command buffers */ - libertas_allocate_cmd_buffer(priv); - - memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); - adapter->libertas_ps_confirm_sleep.command = - cpu_to_le16(CMD_802_11_PS_MODE); - adapter->libertas_ps_confirm_sleep.size = - cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.result = 0; - adapter->libertas_ps_confirm_sleep.action = - cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); - - return 0; -} - -static void wlan_init_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int i; - - adapter->scanprobes = 0; - - adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; - adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; - - /* ATIM params */ - adapter->atimwindow = 0; - - adapter->connect_status = LIBERTAS_DISCONNECTED; - memset(adapter->current_addr, 0xff, ETH_ALEN); - - /* scan type */ - adapter->scantype = CMD_SCAN_TYPE_ACTIVE; - - /* scan mode */ - adapter->scanmode = CMD_BSS_TYPE_ANY; - - /* 802.11 specific */ - adapter->secinfo.wep_enabled = 0; - for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); - i++) - memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); - adapter->wep_tx_keyidx = 0; - adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; - adapter->mode = IW_MODE_INFRA; - - adapter->pending_assoc_req = NULL; - adapter->in_progress_assoc_req = NULL; - - /* Initialize scan result lists */ - INIT_LIST_HEAD(&adapter->network_free_list); - INIT_LIST_HEAD(&adapter->network_list); - for (i = 0; i < MAX_NETWORK_COUNT; i++) { - list_add_tail(&adapter->networks[i].list, - &adapter->network_free_list); - } - - mutex_init(&adapter->lock); - - adapter->prescan = 1; - - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); - adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; - - /* PnP and power profile */ - adapter->surpriseremoved = 0; - - adapter->currentpacketfilter = - CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - - adapter->radioon = RADIO_ON; - adapter->txantenna = RF_ANTENNA_2; - adapter->rxantenna = RF_ANTENNA_AUTO; - - adapter->auto_rate = 1; - adapter->cur_rate = 0; - adapter->adhoc_grate_enabled = 0; - - adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; - - // set default capabilities - adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; - - adapter->psmode = WLAN802_11POWERMODECAM; - adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; - - adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; - - adapter->psstate = PS_STATE_FULL_POWER; - adapter->needtowakeup = 0; - adapter->locallisteninterval = 0; /* default value in firmware will be used */ - - adapter->intcounter = 0; - - adapter->currenttxskb = NULL; - adapter->pkttxctrl = 0; - - memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); - adapter->tx_queue_idx = 0; - spin_lock_init(&adapter->txqueue_lock); - - return; -} - -static void command_timer_fn(unsigned long data); - -int libertas_init_fw(wlan_private * priv, char *fw_name) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; - - lbs_deb_enter(LBS_DEB_FW); - - /* Allocate adapter structure */ - if ((ret = wlan_allocate_adapter(priv)) != 0) - goto done; - - /* init adapter structure */ - wlan_init_adapter(priv); - - /* init timer etc. */ - setup_timer(&adapter->command_timer, command_timer_fn, - (unsigned long)priv); - - /* download fimrware etc. */ - if ((ret = wlan_setup_station_hw(priv, fw_name)) != 0) { - del_timer_sync(&adapter->command_timer); - goto done; - } - - /* init 802.11d */ - libertas_init_11d(priv); - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); - return ret; -} - -void libertas_free_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - - if (!adapter) { - lbs_deb_fw("why double free adapter?\n"); - return; - } - - lbs_deb_fw("free command buffer\n"); - libertas_free_cmd_buffer(priv); - - lbs_deb_fw("free command_timer\n"); - del_timer(&adapter->command_timer); - - lbs_deb_fw("free scan results table\n"); - kfree(adapter->networks); - adapter->networks = NULL; - - /* Free the adapter object itself */ - lbs_deb_fw("free adapter\n"); - kfree(adapter); - priv->adapter = NULL; -} - -/** - * This function handles the timeout of command sending. - * It will re-send the same command again. - */ -static void command_timer_fn(unsigned long data) -{ - wlan_private *priv = (wlan_private *)data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *ptempnode; - struct cmd_ds_command *cmd; - unsigned long flags; - - ptempnode = adapter->cur_cmd; - if (ptempnode == NULL) { - lbs_deb_fw("ptempnode empty\n"); - return; - } - - cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; - if (!cmd) { - lbs_deb_fw("cmd is NULL\n"); - return; - } - - lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command); - - if (!adapter->fw_ready) - return; - - spin_lock_irqsave(&adapter->driver_lock, flags); - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - lbs_deb_fw("re-sending same command because of timeout\n"); - libertas_queue_cmd(adapter, ptempnode, 0); - - wake_up_interruptible(&priv->waitq); - - return; -} diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index e38fce73cf74..ac1cfc253fdc 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -216,7 +216,7 @@ static int if_usb_probe(struct usb_interface *intf, priv->hw_get_int_status = if_usb_get_int_status; priv->hw_read_event_cause = if_usb_read_event_cause; - if (libertas_activate_card(priv, libertas_fw_name)) + if (libertas_activate_card(priv)) goto err_activate_card; list_add_tail(&cardp->list, &usb_devices); @@ -819,7 +819,7 @@ static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) } -static int if_usb_prog_firmware(wlan_private * priv) +static int if_usb_do_prog_firmware(wlan_private * priv) { struct usb_card_rec *cardp = priv->card; int i = 0; @@ -903,6 +903,80 @@ done: return ret; } +/** + * @brief This function checks the validity of Boot2/FW image. + * + * @param data pointer to image + * len image length + * @return 0 or -1 + */ +static int check_fwfile_format(u8 *data, u32 totlen) +{ + u32 bincmd, exit; + u32 blksize, offset, len; + int ret; + + ret = 1; + exit = len = 0; + + do { + struct fwheader *fwh = (void *)data; + + bincmd = le32_to_cpu(fwh->dnldcmd); + blksize = le32_to_cpu(fwh->datalength); + switch (bincmd) { + case FW_HAS_DATA_TO_RECV: + offset = sizeof(struct fwheader) + blksize; + data += offset; + len += offset; + if (len >= totlen) + exit = 1; + break; + case FW_HAS_LAST_BLOCK: + exit = 1; + ret = 0; + break; + default: + exit = 1; + break; + } + } while (!exit); + + if (ret) + lbs_pr_err("firmware file format check FAIL\n"); + else + lbs_deb_fw("firmware file format check PASS\n"); + + return ret; +} + + +static int if_usb_prog_firmware(wlan_private *priv) +{ + int ret = -1; + + lbs_deb_enter(LBS_DEB_FW); + + if ((ret = request_firmware(&priv->firmware, libertas_fw_name, + priv->hotplug_device)) < 0) { + lbs_pr_err("request_firmware() failed with %#x\n", ret); + lbs_pr_err("firmware %s not found\n", libertas_fw_name); + goto done; + } + + if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) { + release_firmware(priv->firmware); + goto done; + } + + ret = if_usb_do_prog_firmware(priv); + + release_firmware(priv->firmware); +done: + return ret; +} + + #ifdef CONFIG_PM static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) { diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 03217f5537ad..7e417eacbc77 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -793,6 +793,280 @@ static int libertas_thread(void *data) return 0; } +/** + * @brief This function downloads firmware image, gets + * HW spec from firmware and set basic parameters to + * firmware. + * + * @param priv A pointer to wlan_private structure + * @return 0 or -1 + */ +static int wlan_setup_station_hw(wlan_private * priv) +{ + int ret = -1; + wlan_adapter *adapter = priv->adapter; + + lbs_deb_enter(LBS_DEB_FW); + + ret = priv->hw_prog_firmware(priv); + + if (ret) { + lbs_deb_fw("bootloader in invalid state\n"); + ret = -1; + goto done; + } + + /* + * Read MAC address from HW + */ + memset(adapter->current_addr, 0xff, ETH_ALEN); + + ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + ret = -1; + goto done; + } + + libertas_set_mac_packet_filter(priv); + + /* Get the supported Data rates */ + ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, + CMD_ACT_GET_TX_RATE, + CMD_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + ret = -1; + goto done; + } + + ret = 0; +done: + lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); + return ret; +} + +static void command_timer_fn(unsigned long data); + +/** + * This function handles the timeout of command sending. + * It will re-send the same command again. + */ +static void command_timer_fn(unsigned long data) +{ + wlan_private *priv = (wlan_private *)data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *ptempnode; + struct cmd_ds_command *cmd; + unsigned long flags; + + ptempnode = adapter->cur_cmd; + if (ptempnode == NULL) { + lbs_deb_fw("ptempnode empty\n"); + return; + } + + cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; + if (!cmd) { + lbs_deb_fw("cmd is NULL\n"); + return; + } + + lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command); + + if (!adapter->fw_ready) + return; + + spin_lock_irqsave(&adapter->driver_lock, flags); + adapter->cur_cmd = NULL; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + lbs_deb_fw("re-sending same command because of timeout\n"); + libertas_queue_cmd(adapter, ptempnode, 0); + + wake_up_interruptible(&priv->waitq); + + return; +} + +static int wlan_allocate_adapter(wlan_private * priv) +{ + size_t bufsize; + wlan_adapter *adapter = priv->adapter; + + /* Allocate buffer to store the BSSID list */ + bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); + adapter->networks = kzalloc(bufsize, GFP_KERNEL); + if (!adapter->networks) { + lbs_pr_err("Out of memory allocating beacons\n"); + libertas_free_adapter(priv); + return -ENOMEM; + } + + /* Allocate the command buffers */ + libertas_allocate_cmd_buffer(priv); + + memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); + adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); + adapter->libertas_ps_confirm_sleep.command = + cpu_to_le16(CMD_802_11_PS_MODE); + adapter->libertas_ps_confirm_sleep.size = + cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); + adapter->libertas_ps_confirm_sleep.result = 0; + adapter->libertas_ps_confirm_sleep.action = + cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); + + return 0; +} + +static void wlan_init_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + int i; + + adapter->scanprobes = 0; + + adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; + adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + + /* ATIM params */ + adapter->atimwindow = 0; + + adapter->connect_status = LIBERTAS_DISCONNECTED; + memset(adapter->current_addr, 0xff, ETH_ALEN); + + /* scan type */ + adapter->scantype = CMD_SCAN_TYPE_ACTIVE; + + /* scan mode */ + adapter->scanmode = CMD_BSS_TYPE_ANY; + + /* 802.11 specific */ + adapter->secinfo.wep_enabled = 0; + for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); + i++) + memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); + adapter->wep_tx_keyidx = 0; + adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + adapter->mode = IW_MODE_INFRA; + + adapter->pending_assoc_req = NULL; + adapter->in_progress_assoc_req = NULL; + + /* Initialize scan result lists */ + INIT_LIST_HEAD(&adapter->network_free_list); + INIT_LIST_HEAD(&adapter->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + list_add_tail(&adapter->networks[i].list, + &adapter->network_free_list); + } + + mutex_init(&adapter->lock); + + adapter->prescan = 1; + + memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); + adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; + + /* PnP and power profile */ + adapter->surpriseremoved = 0; + + adapter->currentpacketfilter = + CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; + + adapter->radioon = RADIO_ON; + adapter->txantenna = RF_ANTENNA_2; + adapter->rxantenna = RF_ANTENNA_AUTO; + + adapter->auto_rate = 1; + adapter->cur_rate = 0; + adapter->adhoc_grate_enabled = 0; + + adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; + + // set default capabilities + adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; + + adapter->psmode = WLAN802_11POWERMODECAM; + adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; + + adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; + + adapter->psstate = PS_STATE_FULL_POWER; + adapter->needtowakeup = 0; + adapter->locallisteninterval = 0; /* default value in firmware will be used */ + + adapter->intcounter = 0; + + adapter->currenttxskb = NULL; + adapter->pkttxctrl = 0; + + memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); + adapter->tx_queue_idx = 0; + spin_lock_init(&adapter->txqueue_lock); + + return; +} + +void libertas_free_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + + if (!adapter) { + lbs_deb_fw("why double free adapter?\n"); + return; + } + + lbs_deb_fw("free command buffer\n"); + libertas_free_cmd_buffer(priv); + + lbs_deb_fw("free command_timer\n"); + del_timer(&adapter->command_timer); + + lbs_deb_fw("free scan results table\n"); + kfree(adapter->networks); + adapter->networks = NULL; + + /* Free the adapter object itself */ + lbs_deb_fw("free adapter\n"); + kfree(adapter); + priv->adapter = NULL; +} + +static int libertas_init_fw(wlan_private * priv) +{ + int ret = -1; + wlan_adapter *adapter = priv->adapter; + + lbs_deb_enter(LBS_DEB_FW); + + /* Allocate adapter structure */ + if ((ret = wlan_allocate_adapter(priv)) != 0) + goto done; + + /* init adapter structure */ + wlan_init_adapter(priv); + + /* init timer etc. */ + setup_timer(&adapter->command_timer, command_timer_fn, + (unsigned long)priv); + + /* download fimrware etc. */ + if ((ret = wlan_setup_station_hw(priv)) != 0) { + del_timer_sync(&adapter->command_timer); + goto done; + } + + /* init 802.11d */ + libertas_init_11d(priv); + + ret = 0; +done: + lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); + return ret; +} + /** * @brief This function adds the card. it will probe the * card, allocate the wlan_priv and initialize the device. @@ -863,7 +1137,7 @@ done: } EXPORT_SYMBOL_GPL(libertas_add_card); -int libertas_activate_card(wlan_private *priv, char *fw_name) +int libertas_activate_card(wlan_private *priv) { struct net_device *dev = priv->dev; int ret = -1; @@ -894,7 +1168,7 @@ int libertas_activate_card(wlan_private *priv, char *fw_name) } /* init FW and HW */ - if (fw_name && libertas_init_fw(priv, fw_name)) { + if (libertas_init_fw(priv)) { lbs_pr_err("firmware init failed\n"); goto err_registerdev; } From c23a24f6ae083e058ed1e9472979df09915ffdf5 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:45:30 -0400 Subject: [PATCH 1245/2804] [PATCH] libertas: fix one more sparse warning adhoc_rates_b is only used locally, so make it static Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 78e398d6f5f3..f71c172101a8 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -18,7 +18,7 @@ #include "assoc.h" /* Supported rates for ad-hoc B mode */ -u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; +static u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; /** From ac558ca2ae878bd7a77831cda684702a2fa23d95 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:49:06 -0400 Subject: [PATCH 1246/2804] [PATCH] libertas: make more functions static & remove unused functions Some functions where declared in header files, but used only once. They are now static functions. After doing this, I found out that some functions weren't used at all. I removed this dead code. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 44 ----------------------- drivers/net/wireless/libertas/11d.h | 4 --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/decl.h | 7 ---- drivers/net/wireless/libertas/if_usb.c | 8 +++-- drivers/net/wireless/libertas/if_usb.h | 3 -- drivers/net/wireless/libertas/join.c | 14 -------- drivers/net/wireless/libertas/join.h | 33 ++++++++--------- drivers/net/wireless/libertas/main.c | 50 +++++++++++++------------- drivers/net/wireless/libertas/scan.c | 35 +----------------- drivers/net/wireless/libertas/scan.h | 19 ++++------ drivers/net/wireless/libertas/wext.c | 2 +- drivers/net/wireless/libertas/wext.h | 4 --- 13 files changed, 54 insertions(+), 171 deletions(-) diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 26d85ec37d9e..ba4cbcb59113 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -446,25 +446,6 @@ void libertas_init_11d(wlan_private * priv) return; } -static int wlan_enable_11d(wlan_private * priv, u8 flag) -{ - int ret; - - priv->adapter->enable11d = flag; - - /* send cmd to FW to enable/disable 11D function in FW */ - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_SNMP_MIB, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - OID_802_11D_ENABLE, - &priv->adapter->enable11d); - if (ret) - lbs_deb_11d("11D: Fail to enable 11D \n"); - - return 0; -} - /** * @brief This function sets DOMAIN INFO to FW * @param priv pointer to wlan_private @@ -577,31 +558,6 @@ done: return 0; } -/** - * @brief This function implements private cmd: enable/disable 11D - * @param priv pointer to wlan_private - * @param wrq pointer to user data - * @return 0 or -1 - */ -int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq) -{ - int data = 0; - int *val; - - lbs_deb_enter(LBS_DEB_11D); - data = SUBCMD_DATA(wrq); - - lbs_deb_11d("enable 11D: %s\n", - (data == 1) ? "enable" : "Disable"); - - wlan_enable_11d(priv, data); - val = (int *)wrq->u.name; - *val = priv->adapter->enable11d; - - lbs_deb_enter(LBS_DEB_11D); - return 0; -} - /** * @brief This function parses countryinfo from AP and download country info to FW * @param priv pointer to wlan_private diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index 73e42e712911..3a6d1f8db78f 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h @@ -83,8 +83,6 @@ u8 libertas_get_scan_type_11d(u8 chan, u32 libertas_chan_2_freq(u8 chan, u8 band); -enum state_11d libertas_get_state_11d(wlan_private * priv); - void libertas_init_11d(wlan_private * priv); int libertas_set_universaltable(wlan_private * priv, u8 band); @@ -93,8 +91,6 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, struct cmd_ds_command *cmd, u16 cmdno, u16 cmdOption); -int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq); - int libertas_ret_802_11d_domain_info(wlan_private * priv, struct cmd_ds_command *resp); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c3fc074b6e3a..85b573770704 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1045,7 +1045,7 @@ done: return; } -void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) +static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) { unsigned long flags; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 113cfc1395e3..095edf6a4c29 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -15,14 +15,9 @@ struct wlan_private; struct sk_buff; struct net_device; -extern char *libertas_fw_name; - -void libertas_free_adapter(wlan_private * priv); int libertas_set_mac_packet_filter(wlan_private * priv); -int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt); void libertas_send_tx_feedback(wlan_private * priv); -u8 libertas_check_last_packet_indication(wlan_private * priv); int libertas_free_cmd_buffer(wlan_private * priv); struct cmd_ctrl_node; @@ -53,8 +48,6 @@ void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); /** The proc fs interface */ int libertas_process_rx_command(wlan_private * priv); int libertas_process_tx(wlan_private * priv, struct sk_buff *skb); -void libertas_cleanup_and_insert_cmd(wlan_private * priv, - struct cmd_ctrl_node *ptempcmd); void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd); diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index ac1cfc253fdc..c28d9747b865 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -22,7 +22,7 @@ static const char usbdriver_name[] = "usb8xxx"; static u8 *default_fw_name = "usb8388.bin"; -char *libertas_fw_name = NULL; +static char *libertas_fw_name = NULL; module_param_named(fw_name, libertas_fw_name, charp, 0644); /* @@ -51,6 +51,8 @@ static int if_usb_prog_firmware(wlan_private *); static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); static int if_usb_get_int_status(wlan_private * priv, u8 *); static int if_usb_read_event_cause(wlan_private *); +static int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); +static void if_usb_free(struct usb_card_rec *cardp); /** * @brief call back function to handle the status of the URB @@ -92,7 +94,7 @@ static void if_usb_write_bulk_callback(struct urb *urb) * @param cardp pointer usb_card_rec * @return N/A */ -void if_usb_free(struct usb_card_rec *cardp) +static void if_usb_free(struct usb_card_rec *cardp) { lbs_deb_enter(LBS_DEB_USB); @@ -384,7 +386,7 @@ static int if_usb_reset_device(wlan_private *priv) * @param nb data length * @return 0 or -1 */ -int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) +static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) { /* pointer to card structure */ struct usb_card_rec *cardp = priv->card; diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 5da8c94ca4c5..8b3b4f1e47f6 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -102,7 +102,4 @@ struct fwsyncheader { #define FW_DATA_XMIT_SIZE \ sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32) -int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); -void if_usb_free(struct usb_card_rec *cardp); - #endif diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index f71c172101a8..f9799c3b81c2 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -112,20 +112,6 @@ void libertas_unset_basic_rate_flags(u8 * rates, size_t len) } -int libertas_send_deauth(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - if (adapter->mode == IW_MODE_INFRA && - adapter->connect_status == LIBERTAS_CONNECTED) - ret = libertas_send_deauthentication(priv); - else - ret = -ENOTSUPP; - - return ret; -} - /** * @brief Associate to a specific BSS discovered in a scan * diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h index 8ea5ae30f4ab..894a072b9f8d 100644 --- a/drivers/net/wireless/libertas/join.h +++ b/drivers/net/wireless/libertas/join.h @@ -12,44 +12,39 @@ #include "dev.h" struct cmd_ds_command; -extern int libertas_cmd_80211_authenticate(wlan_private * priv, +int libertas_cmd_80211_authenticate(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, +int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, +int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, struct cmd_ds_command *cmd); -extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, +int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_cmd_80211_deauthenticate(wlan_private * priv, +int libertas_cmd_80211_deauthenticate(wlan_private * priv, struct cmd_ds_command *cmd); -extern int libertas_cmd_80211_associate(wlan_private * priv, +int libertas_cmd_80211_associate(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv, +int libertas_ret_80211_ad_hoc_start(wlan_private * priv, struct cmd_ds_command *resp); -extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, +int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, struct cmd_ds_command *resp); -extern int libertas_ret_80211_disassociate(wlan_private * priv, +int libertas_ret_80211_disassociate(wlan_private * priv, struct cmd_ds_command *resp); -extern int libertas_ret_80211_associate(wlan_private * priv, +int libertas_ret_80211_associate(wlan_private * priv, struct cmd_ds_command *resp); -extern int libertas_reassociation_thread(void *data); - -extern int libertas_start_adhoc_network(wlan_private * priv, +int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req); -extern int libertas_join_adhoc_network(wlan_private * priv, +int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req); -extern int libertas_stop_adhoc_network(wlan_private * priv); +int libertas_stop_adhoc_network(wlan_private * priv); -extern int libertas_send_deauthentication(wlan_private * priv); -extern int libertas_send_deauth(wlan_private * priv); - -extern int libertas_do_adhocstop_ioctl(wlan_private * priv); +int libertas_send_deauthentication(wlan_private * priv); int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 7e417eacbc77..e8555de65762 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -890,6 +890,31 @@ static void command_timer_fn(unsigned long data) return; } +static void libertas_free_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + + if (!adapter) { + lbs_deb_fw("why double free adapter?\n"); + return; + } + + lbs_deb_fw("free command buffer\n"); + libertas_free_cmd_buffer(priv); + + lbs_deb_fw("free command_timer\n"); + del_timer(&adapter->command_timer); + + lbs_deb_fw("free scan results table\n"); + kfree(adapter->networks); + adapter->networks = NULL; + + /* Free the adapter object itself */ + lbs_deb_fw("free adapter\n"); + kfree(adapter); + priv->adapter = NULL; +} + static int wlan_allocate_adapter(wlan_private * priv) { size_t bufsize; @@ -1009,31 +1034,6 @@ static void wlan_init_adapter(wlan_private * priv) return; } -void libertas_free_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - - if (!adapter) { - lbs_deb_fw("why double free adapter?\n"); - return; - } - - lbs_deb_fw("free command buffer\n"); - libertas_free_cmd_buffer(priv); - - lbs_deb_fw("free command_timer\n"); - del_timer(&adapter->command_timer); - - lbs_deb_fw("free scan results table\n"); - kfree(adapter->networks); - adapter->networks = NULL; - - /* Free the adapter object itself */ - lbs_deb_fw("free adapter\n"); - kfree(adapter); - priv->adapter = NULL; -} - static int libertas_init_fw(wlan_private * priv) { int ret = -1; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 790e9888ea2b..683fa1ba5cac 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1254,7 +1254,7 @@ out: * * @return index in BSSID list */ -struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, +static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, u8 mode) { u8 bestrssi = 0; @@ -1386,39 +1386,6 @@ out: return ret; } -/** - * @brief scan an AP with specific BSSID - * - * @param priv A pointer to wlan_private structure - * @param bssid A pointer to AP's bssid - * @param keeppreviousscan Flag used to save/clear scan table before scan - * - * @return 0-success, otherwise fail - */ -int libertas_send_specific_bssid_scan(wlan_private * priv, u8 * bssid, u8 clear_bssid) -{ - struct wlan_ioctl_user_scan_cfg scancfg; - - lbs_deb_enter(LBS_DEB_ASSOC); - - if (bssid == NULL) - goto out; - - memset(&scancfg, 0x00, sizeof(scancfg)); - memcpy(scancfg.bssid, bssid, ETH_ALEN); - scancfg.clear_bssid = clear_bssid; - - wlan_scan_networks(priv, &scancfg, 1); - if (priv->adapter->surpriseremoved) - return -1; - wait_event_interruptible(priv->adapter->cmd_pending, - !priv->adapter->nr_cmd_pending); - -out: - lbs_deb_leave(LBS_DEB_ASSOC); - return 0; -} - static inline char *libertas_translate_scan(wlan_private *priv, char *start, char *stop, struct bss_descriptor *bss) diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 8c3508b3257f..def0db5c4e61 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -175,31 +175,26 @@ struct bss_descriptor { struct list_head list; }; -extern int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); +int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode, int channel); -struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, - u8 mode); - -extern struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, +struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, u8 * bssid, u8 mode); int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode); -extern int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid, +int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid, u8 ssid_len, u8 clear_ssid); -extern int libertas_send_specific_bssid_scan(wlan_private * priv, - u8 * bssid, u8 clear_bssid); -extern int libertas_cmd_80211_scan(wlan_private * priv, +int libertas_cmd_80211_scan(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_ret_80211_scan(wlan_private * priv, +int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp); int wlan_scan_networks(wlan_private * priv, @@ -211,9 +206,9 @@ struct ifreq; struct iw_point; struct iw_param; struct iw_request_info; -extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, +int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra); -extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, +int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra); #endif /* _WLAN_SCAN_H */ diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 0b805e32993a..e8c0629f9a4b 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -157,7 +157,7 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter, * @option Radio Option * @return 0 --success, otherwise fail */ -int wlan_radio_ioctl(wlan_private * priv, u8 option) +static int wlan_radio_ioctl(wlan_private * priv, u8 option) { int ret = 0; wlan_adapter *adapter = priv->adapter; diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 3d5196c9553a..5b0bbc99a21e 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -4,9 +4,6 @@ #ifndef _WLAN_WEXT_H_ #define _WLAN_WEXT_H_ -#define SUBCMD_OFFSET 4 -#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET)) - /** wlan_ioctl_regrdwr */ struct wlan_ioctl_regrdwr { /** Which register to access */ @@ -25,6 +22,5 @@ struct wlan_ioctl_regrdwr { extern struct iw_handler_def libertas_handler_def; extern struct iw_handler_def mesh_handler_def; -int wlan_radio_ioctl(wlan_private * priv, u8 option); #endif /* _WLAN_WEXT_H_ */ From c95c7f930ec6fee029c8e7957ab95b3967578070 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:49:45 -0400 Subject: [PATCH 1247/2804] [PATCH] libertas: uppercase some #defines Usually constants defined by #define are in ALL_UPPERCASE. This patch fixes this. I also shuffled the bits around so that they match the bit positions in the host-interrupt-state register of the CF/SDIO card :-) Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/defs.h | 8 +++++--- drivers/net/wireless/libertas/if_usb.c | 6 +++--- drivers/net/wireless/libertas/main.c | 8 ++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index a1c6dae1ba46..eee8a49e358f 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -159,9 +159,11 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) #define MARVELL_MESH_IE_LENGTH 9 /** INT status Bit Definition*/ -#define his_cmddnldrdy 0x01 -#define his_cardevent 0x02 -#define his_cmdupldrdy 0x04 +#define MRVDRV_TX_DNLD_RDY 0x0001 +#define MRVDRV_RX_UPLD_RDY 0x0002 +#define MRVDRV_CMD_DNLD_RDY 0x0004 +#define MRVDRV_CMD_UPLD_RDY 0x0008 +#define MRVDRV_CARDEVENT 0x0010 #define SBI_EVENT_CAUSE_SHIFT 3 diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index c28d9747b865..5efdeac6e208 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -601,11 +601,11 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, * data to clear the interrupt */ if (!priv->adapter->cur_cmd) { cmdbuf = priv->upld_buf; - priv->adapter->hisregcpy &= ~his_cmdupldrdy; + priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; } else cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; - cardp->usb_int_cause |= his_cmdupldrdy; + cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY; priv->upld_len = (recvlength - MESSAGE_HEADER_LEN); memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len); @@ -682,7 +682,7 @@ static void if_usb_receive(struct urb *urb) break; } cardp->usb_event_cause <<= 3; - cardp->usb_int_cause |= his_cardevent; + cardp->usb_int_cause |= MRVDRV_CARDEVENT; kfree_skb(skb); libertas_interrupt(priv->dev); spin_unlock(&priv->adapter->driver_lock); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e8555de65762..170dc2394d25 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -711,20 +711,20 @@ static int libertas_thread(void *data) adapter->currenttxskb, priv->dnld_sent); /* command response? */ - if (adapter->hisregcpy & his_cmdupldrdy) { + if (adapter->hisregcpy & MRVDRV_CMD_UPLD_RDY) { lbs_deb_thread("main-thread: cmd response ready\n"); - adapter->hisregcpy &= ~his_cmdupldrdy; + adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; spin_unlock_irq(&adapter->driver_lock); libertas_process_rx_command(priv); spin_lock_irq(&adapter->driver_lock); } /* Any Card Event */ - if (adapter->hisregcpy & his_cardevent) { + if (adapter->hisregcpy & MRVDRV_CARDEVENT) { lbs_deb_thread("main-thread: Card Event Activity\n"); - adapter->hisregcpy &= ~his_cardevent; + adapter->hisregcpy &= ~MRVDRV_CARDEVENT; if (priv->hw_read_event_cause(priv)) { lbs_pr_alert( From 3cf840914bd467fa4cc76af1a01bba4d2813131c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:50:12 -0400 Subject: [PATCH 1248/2804] [PATCH] libertas: access mesh_dev more carefully The CF/SDIO firmware doesn't support Mesh, so priv->mesh_dev is NULL there. Protect all accesses. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 12 ++++++++---- drivers/net/wireless/libertas/main.c | 16 ++++++++++------ drivers/net/wireless/libertas/scan.c | 12 ++++++++---- drivers/net/wireless/libertas/tx.c | 12 ++++++++---- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index f9799c3b81c2..da47c225e101 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -739,8 +739,10 @@ int libertas_ret_80211_associate(wlan_private * priv, netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); - netif_carrier_on(priv->mesh_dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) { + netif_carrier_on(priv->mesh_dev); + netif_wake_queue(priv->mesh_dev); + } lbs_deb_join("ASSOC_RESP: Associated \n"); @@ -827,8 +829,10 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); - netif_carrier_on(priv->mesh_dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) { + netif_carrier_on(priv->mesh_dev); + netif_wake_queue(priv->mesh_dev); + } memset(&wrqu, 0, sizeof(wrqu)); memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 170dc2394d25..b4e2cd19c3bc 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -298,10 +298,12 @@ static int libertas_dev_open(struct net_device *dev) if (adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); - netif_carrier_on(priv->mesh_dev); + if (priv->mesh_dev) + netif_carrier_on(priv->mesh_dev); } else { netif_carrier_off(priv->dev); - netif_carrier_off(priv->mesh_dev); + if (priv->mesh_dev) + netif_carrier_off(priv->mesh_dev); } lbs_deb_leave(LBS_DEB_NET); @@ -408,7 +410,8 @@ static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } netif_stop_queue(priv->dev); - netif_stop_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_stop_queue(priv->mesh_dev); if (libertas_process_tx(priv, skb) == 0) dev->trans_start = jiffies; @@ -474,7 +477,8 @@ static void libertas_tx_timeout(struct net_device *dev) wake_up_interruptible(&priv->waitq); } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_wake_queue(priv->mesh_dev); } lbs_deb_leave(LBS_DEB_TX); @@ -1254,7 +1258,6 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) ret = 0; goto done; - err_unregister: unregister_netdev(mesh_dev); @@ -1454,7 +1457,8 @@ void libertas_interrupt(struct net_device *dev) if (priv->adapter->psstate == PS_STATE_SLEEP) { priv->adapter->psstate = PS_STATE_AWAKE; netif_wake_queue(dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_wake_queue(priv->mesh_dev); } wake_up_interruptible(&priv->waitq); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 683fa1ba5cac..7f045ec2441d 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -793,8 +793,10 @@ int wlan_scan_networks(wlan_private * priv, if (!scancurrentchanonly) { netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); - netif_stop_queue(priv->mesh_dev); - netif_carrier_off(priv->mesh_dev); + if (priv->mesh_dev) { + netif_stop_queue(priv->mesh_dev); + netif_carrier_off(priv->mesh_dev); + } } ret = wlan_scan_channel_list(priv, @@ -820,8 +822,10 @@ int wlan_scan_networks(wlan_private * priv, if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); - netif_carrier_on(priv->mesh_dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) { + netif_carrier_on(priv->mesh_dev); + netif_wake_queue(priv->mesh_dev); + } } out: diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index c2271020aafe..7c383014a274 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -159,7 +159,8 @@ done: skb_orphan(skb); /* stop processing outgoing pkts */ netif_stop_queue(priv->dev); - netif_stop_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_stop_queue(priv->mesh_dev); /* freeze any packets already in our queues */ priv->adapter->TxLockFlag = 1; } else { @@ -198,10 +199,12 @@ static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb) adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb; if (adapter->tx_queue_idx == NR_TX_QUEUE) { netif_stop_queue(priv->dev); - netif_stop_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_stop_queue(priv->mesh_dev); } else { netif_start_queue(priv->dev); - netif_start_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_start_queue(priv->mesh_dev); } spin_unlock(&adapter->txqueue_lock); @@ -285,7 +288,8 @@ void libertas_send_tx_feedback(wlan_private * priv) priv->adapter->TxLockFlag = 0; if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_wake_queue(priv->mesh_dev); } } EXPORT_SYMBOL_GPL(libertas_send_tx_feedback); From 0a6d0555e90850b7ce90e8937858f11b6b98b6d4 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:50:35 -0400 Subject: [PATCH 1249/2804] [PATCH] libertas: tune hardware info output This changes the output of hardware related info from: libertas: GET_HW_SPEC: FWReleaseVersion- 5.0.11.p0 libertas: GET_HW_SPEC: Permanent addr- 0:16:41:72:f6:a8 libertas: GET_HW_SPEC: hwifversion=0x2 version=0x213 to: libertas: GET_HW_SPEC: FWReleaseVersion: 5.0.11.p0 libertas: GET_HW_SPEC: Permanent addr: 00:16:41:72:f6:a8 libertas: GET_HW_SPEC: hwifversion: 0x2, version: 0x213 Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 577c434089b0..bb1d72b2b524 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -173,14 +173,12 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4); - lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion- %u.%u.%u.p%u\n", + lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion: %u.%u.%u.p%u\n", adapter->fwreleasenumber[2], adapter->fwreleasenumber[1], adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]); - lbs_deb_cmd("GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n", - hwspec->permanentaddr[0], hwspec->permanentaddr[1], - hwspec->permanentaddr[2], hwspec->permanentaddr[3], - hwspec->permanentaddr[4], hwspec->permanentaddr[5]); - lbs_deb_cmd("GET_HW_SPEC: hwifversion=0x%X version=0x%X\n", + lbs_deb_cmd("GET_HW_SPEC: Permanent addr: " MAC_FMT "\n", + MAC_ARG(hwspec->permanentaddr)); + lbs_deb_cmd("GET_HW_SPEC: hwifversion: 0x%x version:0x%x\n", hwspec->hwifversion, hwspec->version); adapter->regioncode = le16_to_cpu(hwspec->regioncode); From f455eb1a4ba2bf0ff1bde7844bf3a811269d2d79 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:51:18 -0400 Subject: [PATCH 1250/2804] [PATCH] libertas: remove debugmode There is nowhere any place that set's this variable. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/defs.h | 3 --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/rx.c | 4 ---- drivers/net/wireless/libertas/tx.c | 8 -------- 4 files changed, 16 deletions(-) diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index eee8a49e358f..e47fadf37220 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -149,9 +149,6 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) #define MRVDRV_CHANNELS_PER_SCAN 4 #define MRVDRV_MAX_CHANNELS_PER_SCAN 14 -#define MRVDRV_DEBUG_RX_PATH 0x00000001 -#define MRVDRV_DEBUG_TX_PATH 0x00000002 - #define MRVDRV_MIN_BEACON_INTERVAL 20 #define MRVDRV_MAX_BEACON_INTERVAL 1000 #define MRVDRV_BEACON_INTERVAL 100 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 6acb8fb8733e..7c565cbf8cc4 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -393,7 +393,6 @@ struct _wlan_adapter { u16 txrate; u32 linkmode; u32 radiomode; - u32 debugmode; u8 fw_ready; u8 last_scanned_channel; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index e78636d6651a..c9251abbb964 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -172,10 +172,6 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) lbs_deb_enter(LBS_DEB_RX); - if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH) - lbs_dbg_hex("RX packet: ", skb->data, - min_t(unsigned int, skb->len, 100)); - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) return process_rxed_802_11_packet(priv, skb); diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 7c383014a274..7743d3f30f61 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -72,10 +72,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) if (priv->adapter->surpriseremoved) return -1; - if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) - lbs_dbg_hex("TX packet: ", skb->data, - min_t(unsigned int, skb->len, 100)); - if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { lbs_deb_tx("tx err: skb length %d 0 or > %zd\n", skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); @@ -267,10 +263,6 @@ void libertas_send_tx_feedback(wlan_private * priv) radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data; - if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) - lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr, - min_t(unsigned int, adapter->currenttxskb->len, 100)); - txfail = (status >> 24); #if 0 From a9f38d023b65c9fe2602303c1101c868be4fcbcc Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 11:52:29 -0400 Subject: [PATCH 1251/2804] [PATCH] Support for mesh autostart deactivation through sysfs echo 0 > /sys/class/net/mshX/autostart_enabled This is supported from Marvell firmware version 5.110.16.p0 (to be released). Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/host.h | 2 ++ drivers/net/wireless/libertas/main.c | 48 ++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 308ccdbed344..12d5dd9af40c 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -320,6 +320,8 @@ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_RREQ_DELAY, CMD_ACT_MESH_SET_ROUTE_EXP, CMD_ACT_MESH_GET_ROUTE_EXP, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_ACT_MESH_GET_AUTOSTART_ENABLED, }; /** Card Event definition */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index b4e2cd19c3bc..717b33616ea8 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -252,6 +252,50 @@ static ssize_t libertas_anycast_set(struct device * dev, */ static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set); +static ssize_t libertas_autostart_enabled_get(struct device * dev, + struct device_attribute *attr, char * buf) +{ + struct cmd_ds_mesh_access mesh_access; + + memset(&mesh_access, 0, sizeof(mesh_access)); + libertas_prepare_and_send_command(to_net_dev(dev)->priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_GET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + + return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0])); +} + +static ssize_t libertas_autostart_enabled_set(struct device * dev, + struct device_attribute *attr, const char * buf, size_t count) +{ + struct cmd_ds_mesh_access mesh_access; + uint32_t datum; + + memset(&mesh_access, 0, sizeof(mesh_access)); + sscanf(buf, "%d", &datum); + mesh_access.data[0] = cpu_to_le32(datum); + + libertas_prepare_and_send_command((to_net_dev(dev))->priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + return strlen(buf); +} + +static DEVICE_ATTR(autostart_enabled, 0644, + libertas_autostart_enabled_get, libertas_autostart_enabled_set); + +static struct attribute *libertas_mesh_sysfs_entries[] = { + &dev_attr_anycast_mask.attr, + &dev_attr_autostart_enabled.attr, + NULL, +}; + +static struct attribute_group libertas_mesh_attr_group = { + .attrs = libertas_mesh_sysfs_entries, +}; + /** * @brief Check if the device can be open and wait if necessary. * @@ -1250,7 +1294,7 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) goto err_free; } - ret = device_create_file(&(mesh_dev->dev), &dev_attr_anycast_mask); + ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group); if (ret) goto err_unregister; @@ -1359,7 +1403,7 @@ void libertas_remove_mesh(wlan_private *priv) netif_stop_queue(mesh_dev); netif_carrier_off(priv->mesh_dev); - device_remove_file(&(mesh_dev->dev), &dev_attr_anycast_mask); + sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group); unregister_netdev(mesh_dev); priv->mesh_dev = NULL ; From ece561919326236c7fb791a5e883f0eb76af029e Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:53:06 -0400 Subject: [PATCH 1252/2804] [PATCH] libertas: make the hex dumper nicer Currently, when you define LBS_DEB_HEX, you get every hex dump in the whole driver, e.g. for LBS_DEB_CMD, LBS_DEB_RX, LBS_DEB_TX etc. This patch makes sure that you only get the hexdump that you're interested in. Renamed lbs_dbg_hex() into lbs_deb_hex(), like the other lbs_deb_XXX() macros. Made lbs_deb_hex() issue a line feed (and a new prompt) after 16 bytes. As lbs_deb_hex() now prints the ":" after the prompt by itself, removed the misc colons in the various *.c files. lbs_deb_XXX() now print the debug category as well. As lbs_deb_XXX() --- and especially lbs_deb_11d() --- now print the category, I removed various "11D:" prefixes in 11d.c as well. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 62 +++++++++---------- drivers/net/wireless/libertas/cmd.c | 12 ++-- drivers/net/wireless/libertas/cmdresp.c | 6 +- drivers/net/wireless/libertas/defs.h | 80 +++++++++++++------------ drivers/net/wireless/libertas/join.c | 10 ++-- drivers/net/wireless/libertas/main.c | 6 +- drivers/net/wireless/libertas/rx.c | 13 ++-- drivers/net/wireless/libertas/scan.c | 12 ++-- drivers/net/wireless/libertas/tx.c | 6 +- 9 files changed, 105 insertions(+), 102 deletions(-) diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index ba4cbcb59113..8b366ef2fe95 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -124,17 +124,17 @@ static u8 wlan_channel_known_11d(u8 chan, u8 nr_chan = parsed_region_chan->nr_chan; u8 i = 0; - lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr, + lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr, sizeof(struct chan_power_11d) * nr_chan); for (i = 0; i < nr_chan; i++) { if (chan == chanpwr[i].chan) { - lbs_deb_11d("11D: Found Chan:%d\n", chan); + lbs_deb_11d("found chan %d\n", chan); return 1; } } - lbs_deb_11d("11D: Not Find Chan:%d\n", chan); + lbs_deb_11d("chan %d not found\n", chan); return 0; } @@ -174,8 +174,8 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d memcpy(domaininfo->countrycode, parsed_region_chan->countrycode, COUNTRY_CODE_LEN); - lbs_deb_11d("11D:nrchan=%d\n", nr_chan); - lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan, + lbs_deb_11d("nrchan %d\n", nr_chan); + lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan, sizeof(struct parsed_region_chan_11d)); for (i = 0; i < nr_chan; i++) { @@ -213,7 +213,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d domaininfo->nr_subband = nr_subband; lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); - lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo, + lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, COUNTRY_CODE_LEN + 1 + sizeof(struct ieeetypes_subbandset) * nr_subband); return 0; @@ -233,13 +233,13 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_ struct chan_freq_power *cfp; if (region_chan == NULL) { - lbs_deb_11d("11D: region_chan is NULL\n"); + lbs_deb_11d("region_chan is NULL\n"); return; } cfp = region_chan->CFP; if (cfp == NULL) { - lbs_deb_11d("11D: cfp equal NULL \n"); + lbs_deb_11d("cfp is NULL \n"); return; } @@ -248,19 +248,19 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_ memcpy(parsed_region_chan->countrycode, wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN); - lbs_deb_11d("11D: region[0x%x] band[%d]\n", parsed_region_chan->region, + lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region, parsed_region_chan->band); for (i = 0; i < region_chan->nrcfp; i++, cfp++) { parsed_region_chan->chanpwr[i].chan = cfp->channel; parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower; - lbs_deb_11d("11D: Chan[%d] Pwr[%d]\n", + lbs_deb_11d("chan %d, pwr %d\n", parsed_region_chan->chanpwr[i].chan, parsed_region_chan->chanpwr[i].pwr); } parsed_region_chan->nr_chan = region_chan->nrcfp; - lbs_deb_11d("11D: nrchan[%d]\n", parsed_region_chan->nr_chan); + lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan); return; } @@ -336,7 +336,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* 6. Others */ - lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30); + lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); if ((*(countryinfo->countrycode)) == 0 || (countryinfo->len <= COUNTRY_CODE_LEN)) { @@ -349,7 +349,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* wlan_region_2_code(countryinfo->countrycode); lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region); - lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode, + lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode, COUNTRY_CODE_LEN); parsed_region_chan->band = band; @@ -364,7 +364,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* if (countryinfo->subband[j].firstchan <= lastchan) { /*Step2&3. Check First Chan Num increment and no overlap */ - lbs_deb_11d("11D: Chan[%d>%d] Overlap\n", + lbs_deb_11d("chan %d>%d, overlap\n", countryinfo->subband[j].firstchan, lastchan); continue; } @@ -393,7 +393,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* } else { /*not supported and ignore the chan */ lbs_deb_11d( - "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n", + "i %d, chan %d unsupported in region %x, band %d\n", i, curchan, region, band); } } @@ -405,7 +405,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* parsed_region_chan->nr_chan = idx; lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan); - lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan, + lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan, 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); done: @@ -427,10 +427,10 @@ u8 libertas_get_scan_type_11d(u8 chan, lbs_deb_enter(LBS_DEB_11D); if (wlan_channel_known_11d(chan, parsed_region_chan)) { - lbs_deb_11d("11D: Found and do Active Scan\n"); + lbs_deb_11d("found, do active scan\n"); scan_type = CMD_SCAN_TYPE_ACTIVE; } else { - lbs_deb_11d("11D: Not Find and do Passive Scan\n"); + lbs_deb_11d("not found, do passive scan\n"); } lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type); @@ -456,7 +456,7 @@ static int set_domain_info_11d(wlan_private * priv) int ret; if (!priv->adapter->enable11d) { - lbs_deb_11d("11D: dnld domain Info with 11d disabled\n"); + lbs_deb_11d("dnld domain Info with 11d disabled\n"); return 0; } @@ -464,7 +464,7 @@ static int set_domain_info_11d(wlan_private * priv) CMD_ACT_SET, CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) - lbs_deb_11d("11D: Fail to dnld domain Info\n"); + lbs_deb_11d("fail to dnld domain info\n"); return ret; } @@ -486,7 +486,7 @@ int libertas_set_universaltable(wlan_private * priv, u8 band) adapter->universal_channel[i].nrcfp = sizeof(channel_freq_power_UN_BG) / size; - lbs_deb_11d("11D: BG-band nrcfp=%d\n", + lbs_deb_11d("BG-band nrcfp %d\n", adapter->universal_channel[i].nrcfp); adapter->universal_channel[i].CFP = channel_freq_power_UN_BG; @@ -525,7 +525,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, if (cmdoption == CMD_ACT_GET) { cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); - lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, + lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, (int)(cmd->size)); goto done; } @@ -551,7 +551,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); } - lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, le16_to_cpu(cmd->size)); + lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size)); done: lbs_deb_enter(LBS_DEB_11D); @@ -575,13 +575,13 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv, lbs_deb_enter(LBS_DEB_11D); - lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp, + lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp, (int)le16_to_cpu(resp->size)); nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / sizeof(struct ieeetypes_subbandset); - lbs_deb_11d("11D Domain Info Resp: nr_subband=%d\n", nr_subband); + lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) { lbs_deb_11d("Invalid Numrer of Subband returned!!\n"); @@ -623,7 +623,7 @@ int libertas_parse_dnld_countryinfo_11d(wlan_private * priv, &adapter->parsed_region_chan); if (ret == -1) { - lbs_deb_11d("11D: Err Parse domain_info from AP..\n"); + lbs_deb_11d("error parsing domain_info from AP\n"); goto done; } @@ -635,7 +635,7 @@ int libertas_parse_dnld_countryinfo_11d(wlan_private * priv, ret = set_domain_info_11d(priv); if (ret) { - lbs_deb_11d("11D: Err set domainInfo to FW\n"); + lbs_deb_11d("error setting domain info\n"); goto done; } } @@ -659,7 +659,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) u8 j; lbs_deb_enter(LBS_DEB_11D); - lbs_deb_11d("11D:curbssparams.band[%d]\n", adapter->curbssparams.band); + lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band); if (priv->adapter->enable11d) { /* update parsed_region_chan_11; dnld domaininf to FW */ @@ -668,7 +668,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) sizeof(adapter->region_channel[0]); j++) { region_chan = &adapter->region_channel[j]; - lbs_deb_11d("11D:[%d] region_chan->band[%d]\n", j, + lbs_deb_11d("%d region_chan->band %d\n", j, region_chan->band); if (!region_chan || !region_chan->valid @@ -681,7 +681,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) if (j >= sizeof(adapter->region_channel) / sizeof(adapter->region_channel[0])) { - lbs_deb_11d("11D:region_chan not found. band[%d]\n", + lbs_deb_11d("region_chan not found, band %d\n", adapter->curbssparams.band); ret = -1; goto done; @@ -701,7 +701,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) ret = set_domain_info_11d(priv); if (ret) { - lbs_deb_11d("11D: Err set domainInfo to FW\n"); + lbs_deb_11d("error setting domain info\n"); goto done; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 85b573770704..8d2f9bad8680 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -773,7 +773,7 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, if (cmd_action == CMD_ACT_SET) { memcpy(cmd->params.macadd.macadd, adapter->current_addr, ETH_ALEN); - lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6); + lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6); } return 0; @@ -815,11 +815,11 @@ static int wlan_cmd_bt_access(wlan_private * priv, switch (cmd_action) { case CMD_ACT_BT_ACCESS_ADD: memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); - lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6); + lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6); break; case CMD_ACT_BT_ACCESS_DEL: memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); - lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6); + lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6); break; case CMD_ACT_BT_ACCESS_LIST: bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); @@ -993,8 +993,8 @@ static int DownloadcommandToStation(wlan_private * priv, goto done; } - lbs_deb_cmd("DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies); - lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize); + lbs_deb_cmd("DNLD_CMD: sent command 0x%x, jiffies %lu\n", command, jiffies); + lbs_deb_hex(LBS_DEB_CMD, "command", cmdnode->bufvirtualaddr, cmdsize); /* Setup the timer after transmit command */ if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE @@ -1801,7 +1801,7 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) lbs_deb_cmd("SEND_SLEEPC_CMD: Before download, size of cmd = %d\n", size); - lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size); + lbs_deb_hex(LBS_DEB_CMD, "sleep confirm command", cmdptr, size); ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size); priv->dnld_sent = DNLD_RES_RECEIVED; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bb1d72b2b524..6166bbc0528e 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -431,7 +431,7 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate, + lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); /* FIXME: get actual rates FW can do if this command actually returns @@ -512,7 +512,7 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv, memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, le16_to_cpu(resp->params.rdeeprom.bytecount)); - lbs_dbg_hex("adapter", (char *)&pbuf->value, + lbs_deb_hex(LBS_DEB_CMD, "adapter", (char *)&pbuf->value, le16_to_cpu(resp->params.rdeeprom.bytecount)); } return 0; @@ -758,7 +758,7 @@ int libertas_process_rx_command(wlan_private * priv) } resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); - lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr, + lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr, priv->upld_len); respcmd = le16_to_cpu(resp->command); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index e47fadf37220..7c5b7f7b45db 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -43,43 +43,43 @@ extern unsigned int libertas_debug; #ifdef DEBUG -#define LBS_DEB_LL(grp, fmt, args...) \ +#define LBS_DEB_LL(grp, grpnam, fmt, args...) \ do { if ((libertas_debug & (grp)) == (grp)) \ - printk(KERN_DEBUG DRV_NAME "%s: " fmt, \ + printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \ in_interrupt() ? " (INT)" : "", ## args); } while (0) #else -#define LBS_DEB_LL(grp, fmt, args...) do {} while (0) +#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0) #endif #define lbs_deb_enter(grp) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s():%d enter\n", __FUNCTION__, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__); #define lbs_deb_enter_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__); #define lbs_deb_leave(grp) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave\n", __FUNCTION__, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__); #define lbs_deb_leave_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave, " fmt "\n", \ + LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \ __FUNCTION__, __LINE__, ##args); -#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, fmt, ##args) -#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, fmt, ##args) -#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, fmt, ##args) -#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, fmt, ##args) -#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, fmt, ##args) -#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, fmt, ##args) -#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, fmt, ##args) -#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, fmt, ##args) -#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, fmt, ##args) -#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, fmt, ##args) -#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, fmt, ##args) -#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, fmt, ##args) -#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, fmt, ##args) -#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, fmt, ##args) -#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, fmt, ##args) -#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, fmt, ##args) -#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, fmt, ##args) -#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, "%s:" fmt, (dev)->bus_id, ##args) -#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, fmt, ##args) -#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, fmt, ##args) +#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args) +#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args) +#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args) +#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args) +#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args) +#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args) +#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args) +#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args) +#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args) +#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args) +#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args) +#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args) +#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args) +#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args) +#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args) +#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args) +#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args) +#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) +#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) +#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) #define lbs_pr_info(format, args...) \ printk(KERN_INFO DRV_NAME": " format, ## args) @@ -89,22 +89,28 @@ do { if ((libertas_debug & (grp)) == (grp)) \ printk(KERN_ALERT DRV_NAME": " format, ## args) #ifdef DEBUG -static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) +static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len) { int i = 0; - if (!(libertas_debug & LBS_DEB_HEX)) - return; - - printk(KERN_DEBUG "%s: ", prompt); - for (i = 1; i <= len; i++) { - printk("%02x ", (u8) * buf); - buf++; + if (len && + (libertas_debug & LBS_DEB_HEX) && + (libertas_debug & grp)) + { + for (i = 1; i <= len; i++) { + if ((i & 0xf) == 1) { + if (i != 1) + printk("\n"); + printk(DRV_NAME " %s: ", prompt); + } + printk("%02x ", (u8) * buf); + buf++; + } + printk("\n"); } - printk("\n"); } #else -#define lbs_dbg_hex(x,y,z) do {} while (0) +#define lbs_deb_hex(grp,prompt,buf,len) do {} while (0) #endif diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index da47c225e101..2b538ab51d40 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -51,9 +51,9 @@ static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size) } } - lbs_dbg_hex("rate1 (AP) rates:", rates, *rates_size); - lbs_dbg_hex("rate2 (Card) rates:", card_rates, num_card_rates); - lbs_dbg_hex("Common rates:", tmp, tmp_size); + 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_join("Tx datarate is currently 0x%X\n", adapter->cur_rate); if (!adapter->auto_rate) { @@ -426,7 +426,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, tmplen = (u16) assoc_req->wpa_ie[1]; rsn->header.len = cpu_to_le16(tmplen); memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); - lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn, + lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, sizeof(rsn->header) + tmplen); pos += sizeof(rsn->header) + tmplen; } @@ -711,7 +711,7 @@ int libertas_ret_80211_associate(wlan_private * priv, goto done; } - lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params, + lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_RESP", (void *)&resp->params, le16_to_cpu(resp->size) - S_DS_GEN); /* Send a Media Connected event, according to the Spec */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 717b33616ea8..2713f57e9bc8 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -556,9 +556,9 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr) memset(adapter->current_addr, 0, ETH_ALEN); /* dev->dev_addr is 8 bytes */ - lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN); + lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN); - lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN); + lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN); memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN); ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS, @@ -571,7 +571,7 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr) goto done; } - lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN); + lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN); memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN); if (priv->mesh_dev) memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index c9251abbb964..25d45c646d71 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -182,7 +182,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) else UNSET_MESH_FRAME(skb); - lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, + lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min_t(unsigned int, skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { @@ -206,9 +206,9 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); - lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, + lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); - lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, + lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, sizeof(p_rx_pkt->eth803_hdr.src_addr)); if (memcmp(&p_rx_pkt->rfc1042_hdr, @@ -240,7 +240,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) */ hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt; } else { - lbs_dbg_hex("RX Data: LLC/SNAP", + lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP", (u8 *) & p_rx_pkt->rfc1042_hdr, sizeof(p_rx_pkt->rfc1042_hdr)); @@ -336,7 +336,7 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) p_rx_pkt = (struct rx80211packethdr *) skb->data; prxpd = &p_rx_pkt->rx_pd; - // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); + // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received wit bad length\n"); @@ -385,8 +385,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); - // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100)); - /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); @@ -404,7 +402,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); - //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100)); break; default: diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 7f045ec2441d..f471157c02df 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -867,7 +867,7 @@ void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, *ptsftlv = NULL; lbs_deb_scan("SCAN_RESP: tlvbufsize = %d\n", tlvbufsize); - lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); + lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); while (tlvbufleft >= sizeof(struct mrvlietypesheader)) { tlvtype = le16_to_cpu(pcurrenttlv->header.type); @@ -979,7 +979,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* rest of the current buffer are IE's */ lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos); - lbs_dbg_hex("process_bss: IE info", pos, end - pos); + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos); /* process variable IE */ while (pos <= end - 2) { @@ -1055,7 +1055,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); - lbs_dbg_hex("process_bss: 11D- CountryInfo:", + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", (u8 *) pcountryinfo, (u32) (pcountryinfo->len + 2)); break; @@ -1085,7 +1085,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); - lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie, elem->len); } else if (elem->len >= MARVELL_MESH_IE_LENGTH && elem->data[0] == 0x00 && @@ -1099,7 +1099,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, case MFIE_TYPE_RSN: bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); - lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elem->len); + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len); break; default: @@ -1154,7 +1154,7 @@ struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, if (!bssid) return NULL; - lbs_dbg_hex("libertas_find_BSSID_in_list: looking for ", + lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); /* Look through the scan table for a compatible match. The loop will diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 7743d3f30f61..56d84027ec2b 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -116,7 +116,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) else memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); - lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); + lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); if (IS_MESH_FRAME(skb)) { plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); @@ -126,7 +126,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) ptr += sizeof(struct txpd); - lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); + lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); ret = priv->hw_host_to_card(priv, MVMS_DAT, priv->adapter->tmptxbuf, @@ -218,7 +218,7 @@ int libertas_process_tx(wlan_private * priv, struct sk_buff *skb) int ret = -1; lbs_deb_enter(LBS_DEB_TX); - lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100)); + lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100)); if (priv->dnld_sent) { lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n", From 6b63cd0f420c3c3002024da6c9eff252a3772021 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:53:36 -0400 Subject: [PATCH 1253/2804] [PATCH] libertas: remove a hundred CMD_RET_xxx definitions types.h contains the same amount of CMD_RET_xxx and CMD_xxx definitions. They contains the same info: the firmware command opcode and, when the firmware sends back a result, the command opcode ORed with 0x8000. Having the same data twice in the source code is redundant and can lead to errors (e.g. if you update or delete only one instance). This patch removed all CMD_RET_xxx definitions and introduces a simple CMD_RET() macro. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 101 ++++++++++++------------ drivers/net/wireless/libertas/debugfs.c | 26 +++--- drivers/net/wireless/libertas/host.h | 87 +++----------------- drivers/net/wireless/libertas/join.c | 2 +- 4 files changed, 76 insertions(+), 140 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 6166bbc0528e..ae11e1f2739f 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -124,7 +124,7 @@ static int wlan_ret_reg_access(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); switch (type) { - case CMD_RET_MAC_REG_ACCESS: + case CMD_RET(CMD_MAC_REG_ACCESS): { struct cmd_ds_mac_reg_access *reg = &resp->params.macreg; @@ -133,7 +133,7 @@ static int wlan_ret_reg_access(wlan_private * priv, break; } - case CMD_RET_BBP_REG_ACCESS: + case CMD_RET(CMD_BBP_REG_ACCESS): { struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg; @@ -142,7 +142,7 @@ static int wlan_ret_reg_access(wlan_private * priv, break; } - case CMD_RET_RF_REG_ACCESS: + case CMD_RET(CMD_RF_REG_ACCESS): { struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg; @@ -560,134 +560,135 @@ static inline int handle_cmd_response(u16 respcmd, wlan_adapter *adapter = priv->adapter; switch (respcmd) { - case CMD_RET_MAC_REG_ACCESS: - case CMD_RET_BBP_REG_ACCESS: - case CMD_RET_RF_REG_ACCESS: + case CMD_RET(CMD_MAC_REG_ACCESS): + case CMD_RET(CMD_BBP_REG_ACCESS): + case CMD_RET(CMD_RF_REG_ACCESS): ret = wlan_ret_reg_access(priv, respcmd, resp); break; - case CMD_RET_HW_SPEC_INFO: + case CMD_RET(CMD_GET_HW_SPEC): ret = wlan_ret_get_hw_spec(priv, resp); break; - case CMD_RET_802_11_SCAN: + case CMD_RET(CMD_802_11_SCAN): ret = libertas_ret_80211_scan(priv, resp); break; - case CMD_RET_802_11_GET_LOG: + case CMD_RET(CMD_802_11_GET_LOG): ret = wlan_ret_get_log(priv, resp); break; case CMD_RET_802_11_ASSOCIATE: - case CMD_RET_802_11_REASSOCIATE: + case CMD_RET(CMD_802_11_ASSOCIATE): + case CMD_RET(CMD_802_11_REASSOCIATE): ret = libertas_ret_80211_associate(priv, resp); break; - case CMD_RET_802_11_DISASSOCIATE: - case CMD_RET_802_11_DEAUTHENTICATE: + case CMD_RET(CMD_802_11_DISASSOCIATE): + case CMD_RET(CMD_802_11_DEAUTHENTICATE): ret = libertas_ret_80211_disassociate(priv, resp); break; - case CMD_RET_802_11_AD_HOC_START: - case CMD_RET_802_11_AD_HOC_JOIN: + case CMD_RET(CMD_802_11_AD_HOC_START): + case CMD_RET(CMD_802_11_AD_HOC_JOIN): ret = libertas_ret_80211_ad_hoc_start(priv, resp); break; - case CMD_RET_802_11_STAT: + case CMD_RET(CMD_802_11_GET_STAT): ret = wlan_ret_802_11_stat(priv, resp); break; - case CMD_RET_802_11_SNMP_MIB: + case CMD_RET(CMD_802_11_SNMP_MIB): ret = wlan_ret_802_11_snmp_mib(priv, resp); break; - case CMD_RET_802_11_RF_TX_POWER: + case CMD_RET(CMD_802_11_RF_TX_POWER): ret = wlan_ret_802_11_rf_tx_power(priv, resp); break; - case CMD_RET_802_11_SET_AFC: - case CMD_RET_802_11_GET_AFC: + case CMD_RET(CMD_802_11_SET_AFC): + case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc, sizeof(struct cmd_ds_802_11_afc)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_802_11_RF_ANTENNA: + case CMD_RET(CMD_802_11_RF_ANTENNA): ret = wlan_ret_802_11_rf_antenna(priv, resp); break; - case CMD_RET_MAC_MULTICAST_ADR: - case CMD_RET_MAC_CONTROL: - case CMD_RET_802_11_SET_WEP: - case CMD_RET_802_11_RESET: - case CMD_RET_802_11_AUTHENTICATE: - case CMD_RET_802_11_RADIO_CONTROL: - case CMD_RET_802_11_BEACON_STOP: + case CMD_RET(CMD_MAC_MULTICAST_ADR): + case CMD_RET(CMD_MAC_CONTROL): + case CMD_RET(CMD_802_11_SET_WEP): + case CMD_RET(CMD_802_11_RESET): + case CMD_RET(CMD_802_11_AUTHENTICATE): + case CMD_RET(CMD_802_11_RADIO_CONTROL): + case CMD_RET(CMD_802_11_BEACON_STOP): break; - case CMD_RET_802_11_ENABLE_RSN: + case CMD_RET(CMD_802_11_ENABLE_RSN): ret = libertas_ret_802_11_enable_rsn(priv, resp); break; - case CMD_RET_802_11_DATA_RATE: + case CMD_RET(CMD_802_11_DATA_RATE): ret = wlan_ret_802_11_data_rate(priv, resp); break; - case CMD_RET_802_11_RATE_ADAPT_RATESET: + case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET): ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); break; - case CMD_RET_802_11_RF_CHANNEL: + case CMD_RET(CMD_802_11_RF_CHANNEL): ret = wlan_ret_802_11_rf_channel(priv, resp); break; - case CMD_RET_802_11_RSSI: + case CMD_RET(CMD_802_11_RSSI): ret = wlan_ret_802_11_rssi(priv, resp); break; - case CMD_RET_802_11_MAC_ADDRESS: + case CMD_RET(CMD_802_11_MAC_ADDRESS): ret = wlan_ret_802_11_mac_address(priv, resp); break; - case CMD_RET_802_11_AD_HOC_STOP: + case CMD_RET(CMD_802_11_AD_HOC_STOP): ret = libertas_ret_80211_ad_hoc_stop(priv, resp); break; - case CMD_RET_802_11_KEY_MATERIAL: + case CMD_RET(CMD_802_11_KEY_MATERIAL): lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n"); ret = wlan_ret_802_11_key_material(priv, resp); break; - case CMD_RET_802_11_EEPROM_ACCESS: + case CMD_RET(CMD_802_11_EEPROM_ACCESS): ret = wlan_ret_802_11_eeprom_access(priv, resp); break; - case CMD_RET_802_11D_DOMAIN_INFO: + case CMD_RET(CMD_802_11D_DOMAIN_INFO): ret = libertas_ret_802_11d_domain_info(priv, resp); break; - case CMD_RET_802_11_SLEEP_PARAMS: + case CMD_RET(CMD_802_11_SLEEP_PARAMS): ret = wlan_ret_802_11_sleep_params(priv, resp); break; - case CMD_RET_802_11_INACTIVITY_TIMEOUT: + case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT): spin_lock_irqsave(&adapter->driver_lock, flags); *((u16 *) adapter->cur_cmd->pdata_buf) = le16_to_cpu(resp->params.inactivity_timeout.timeout); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_802_11_TPC_CFG: + case CMD_RET(CMD_802_11_TPC_CFG): spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg, sizeof(struct cmd_ds_802_11_tpc_cfg)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_802_11_LED_GPIO_CTRL: + case CMD_RET(CMD_802_11_LED_GPIO_CTRL): spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio, sizeof(struct cmd_ds_802_11_led_ctrl)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_802_11_PWR_CFG: + case CMD_RET(CMD_802_11_PWR_CFG): spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg, sizeof(struct cmd_ds_802_11_pwr_cfg)); @@ -695,32 +696,32 @@ static inline int handle_cmd_response(u16 respcmd, break; - case CMD_RET_GET_TSF: + case CMD_RET(CMD_GET_TSF): spin_lock_irqsave(&adapter->driver_lock, flags); memcpy(priv->adapter->cur_cmd->pdata_buf, &resp->params.gettsf.tsfvalue, sizeof(u64)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_BT_ACCESS: + case CMD_RET(CMD_BT_ACCESS): spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.bt.addr1, 2 * ETH_ALEN); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_FWT_ACCESS: + case CMD_RET(CMD_FWT_ACCESS): spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt, sizeof(resp->params.fwt)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_MESH_ACCESS: + case CMD_RET(CMD_MESH_ACCESS): if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh, sizeof(resp->params.mesh)); break; - case CMD_RTE_802_11_TX_RATE_QUERY: + case CMD_RET(CMD_802_11_TX_RATE_QUERY): priv->adapter->txrate = resp->params.txrate.txrate; break; default: @@ -782,7 +783,7 @@ int libertas_process_rx_command(wlan_private * priv) /* Store the response code to cur_cmd_retcode. */ adapter->cur_cmd_retcode = result;; - if (respcmd == CMD_RET_802_11_PS_MODE) { + if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; u16 action = le16_to_cpu(psmode->action); @@ -852,8 +853,8 @@ int libertas_process_rx_command(wlan_private * priv) * Handling errors here */ switch (respcmd) { - case CMD_RET_HW_SPEC_INFO: - case CMD_RET_802_11_RESET: + case CMD_RET(CMD_GET_HW_SPEC): + case CMD_RET(CMD_802_11_RESET): lbs_deb_cmd("CMD_RESP: Reset command failed\n"); break; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 9439005db4e6..4b9533a66511 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -447,7 +447,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -511,7 +511,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) return 0; } - if (pcmdptr->command != CMD_RET_802_11_SUBSCRIBE_EVENT) { + if (pcmdptr->command != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; @@ -591,7 +591,7 @@ static ssize_t libertas_lowrssi_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -644,7 +644,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -743,7 +743,7 @@ static ssize_t libertas_lowsnr_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -797,7 +797,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -895,7 +895,7 @@ static ssize_t libertas_failcount_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -948,7 +948,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); free_page(addr); kfree(response_buf); @@ -1045,7 +1045,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); free_page(addr); kfree(response_buf); @@ -1098,7 +1098,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1196,7 +1196,7 @@ static ssize_t libertas_highrssi_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; @@ -1248,7 +1248,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1347,7 +1347,7 @@ static ssize_t libertas_highsnr_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 12d5dd9af40c..c6b44c831594 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -22,7 +22,17 @@ #define CMD_OPTION_WAITFORRSP 0x0002 -/** Host command ID */ +/** Host command IDs */ + +/* Return command are almost always the same as the host command, but with + * bit 15 set high. There are a few exceptions, though... + */ +#define CMD_RET(cmd) (0x8000 | cmd) + +/* Return command convention exceptions: */ +#define CMD_RET_802_11_ASSOCIATE 0x8012 + +/* Command codes */ #define CMD_CODE_DNLD 0x0002 #define CMD_GET_HW_SPEC 0x0003 #define CMD_EEPROM_UPDATE 0x0004 @@ -97,13 +107,10 @@ #define CMD_GET_TSF 0x0080 #define CMD_BT_ACCESS 0x0087 -#define CMD_RET_BT_ACCESS 0x8087 #define CMD_FWT_ACCESS 0x0095 -#define CMD_RET_FWT_ACCESS 0x8095 #define CMD_MESH_ACCESS 0x009b -#define CMD_RET_MESH_ACCESS 0x809b /* For the IEEE Power Save */ #define CMD_SUBCMD_ENTER_PS 0x0030 @@ -112,46 +119,6 @@ #define CMD_SUBCMD_FULL_POWERDOWN 0x0035 #define CMD_SUBCMD_FULL_POWERUP 0x0036 -/* command RET code, MSB is set to 1 */ -#define CMD_RET_HW_SPEC_INFO 0x8003 -#define CMD_RET_EEPROM_UPDATE 0x8004 -#define CMD_RET_802_11_RESET 0x8005 -#define CMD_RET_802_11_SCAN 0x8006 -#define CMD_RET_802_11_GET_LOG 0x800b -#define CMD_RET_MAC_CONTROL 0x8028 -#define CMD_RET_MAC_MULTICAST_ADR 0x8010 -#define CMD_RET_802_11_AUTHENTICATE 0x8011 -#define CMD_RET_802_11_DEAUTHENTICATE 0x8024 -#define CMD_RET_802_11_ASSOCIATE 0x8012 -#define CMD_RET_802_11_REASSOCIATE 0x8025 -#define CMD_RET_802_11_DISASSOCIATE 0x8026 -#define CMD_RET_802_11_SET_WEP 0x8013 -#define CMD_RET_802_11_STAT 0x8014 -#define CMD_RET_802_3_STAT 0x8015 -#define CMD_RET_802_11_SNMP_MIB 0x8016 -#define CMD_RET_MAC_REG_MAP 0x8017 -#define CMD_RET_BBP_REG_MAP 0x8018 -#define CMD_RET_RF_REG_MAP 0x8023 -#define CMD_RET_MAC_REG_ACCESS 0x8019 -#define CMD_RET_BBP_REG_ACCESS 0x801a -#define CMD_RET_RF_REG_ACCESS 0x801b -#define CMD_RET_802_11_RADIO_CONTROL 0x801c -#define CMD_RET_802_11_RF_CHANNEL 0x801d -#define CMD_RET_802_11_RSSI 0x801f -#define CMD_RET_802_11_RF_TX_POWER 0x801e -#define CMD_RET_802_11_RF_ANTENNA 0x8020 -#define CMD_RET_802_11_PS_MODE 0x8021 -#define CMD_RET_802_11_DATA_RATE 0x8022 - -#define CMD_RET_802_11_AD_HOC_START 0x802B -#define CMD_RET_802_11_AD_HOC_JOIN 0x802C - -#define CMD_RET_802_11_QUERY_TKIP_REPLY_CNTRS 0x802e -#define CMD_RET_802_11_ENABLE_RSN 0x802f -#define CMD_RET_802_11_PAIRWISE_TSC 0x8036 -#define CMD_RET_802_11_GROUP_TSC 0x8037 -#define CMD_RET_802_11_KEY_MATERIAL 0x805e - #define CMD_ENABLE_RSN 0x0001 #define CMD_DISABLE_RSN 0x0000 @@ -162,38 +129,6 @@ #define CMD_ACT_SET_AES (CMD_ACT_SET + 2) #define CMD_ACT_REMOVE_AES (CMD_ACT_SET + 3) -#define CMD_RET_802_11_SET_AFC 0x803c -#define CMD_RET_802_11_GET_AFC 0x803d - -#define CMD_RET_802_11_AD_HOC_STOP 0x8040 - -#define CMD_RET_802_11_BEACON_STOP 0x8049 - -#define CMD_RET_802_11_MAC_ADDRESS 0x804D -#define CMD_RET_802_11_EEPROM_ACCESS 0x8059 - -#define CMD_RET_802_11_BAND_CONFIG 0x8058 - -#define CMD_RET_802_11_SLEEP_PARAMS 0x8066 - -#define CMD_RET_802_11_INACTIVITY_TIMEOUT 0x8067 - -#define CMD_RET_802_11D_DOMAIN_INFO (0x8000 | \ - CMD_802_11D_DOMAIN_INFO) - -#define CMD_RET_802_11_TPC_CFG (CMD_802_11_TPC_CFG | 0x8000) -#define CMD_RET_802_11_PWR_CFG (CMD_802_11_PWR_CFG | 0x8000) - -#define CMD_RET_802_11_LED_GPIO_CTRL 0x804e - -#define CMD_RET_802_11_SUBSCRIBE_EVENT (CMD_802_11_SUBSCRIBE_EVENT | 0x8000) - -#define CMD_RET_802_11_RATE_ADAPT_RATESET (CMD_802_11_RATE_ADAPT_RATESET | 0x8000) - -#define CMD_RTE_802_11_TX_RATE_QUERY (CMD_802_11_TX_RATE_QUERY | 0x8000) - -#define CMD_RET_GET_TSF 0x8080 - /* Define action or option for CMD_802_11_SET_WEP */ #define CMD_ACT_ADD 0x0002 #define CMD_ACT_REMOVE 0x0004 diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 2b538ab51d40..08034917d4b5 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -814,7 +814,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, /* Send a Media Connected event, according to the Spec */ adapter->connect_status = LIBERTAS_CONNECTED; - if (command == CMD_RET_802_11_AD_HOC_START) { + if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { /* Update the created network descriptor with the new BSSID */ memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); } From a6c8700f36cd8f217420bbe26721094824fab8de Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:54:10 -0400 Subject: [PATCH 1254/2804] [PATCH] libertas: use LBS_DEB_HOST for host-to-card communications ... and LBS_DEB_CMD for command execution. Also tidies misc comments to give a consistent output. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 147 +++++++++++++----------- 1 file changed, 78 insertions(+), 69 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index ae11e1f2739f..197d04517840 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -31,7 +31,7 @@ void libertas_mac_event_disconnected(wlan_private * priv) if (adapter->connect_status != LIBERTAS_CONNECTED) return; - lbs_deb_cmd("Handles disconnect event.\n"); + lbs_deb_enter(LBS_DEB_CMD); memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; @@ -61,11 +61,11 @@ void libertas_mac_event_disconnected(wlan_private * priv) adapter->nextSNRNF = 0; adapter->numSNRNF = 0; adapter->rxpd_rate = 0; - lbs_deb_cmd("Current SSID='%s', ssid length=%u\n", + lbs_deb_cmd("current SSID '%s', length %u\n", escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), adapter->curbssparams.ssid_len); - lbs_deb_cmd("Previous SSID='%s', ssid length=%u\n", + lbs_deb_cmd("previous SSID '%s', length %u\n", escape_essid(adapter->prev_ssid, adapter->prev_ssid_len), adapter->prev_ssid_len); @@ -86,9 +86,10 @@ void libertas_mac_event_disconnected(wlan_private * priv) if (adapter->psstate != PS_STATE_FULL_POWER) { /* make firmware to exit PS mode */ - lbs_deb_cmd("Disconnected, so exit PS mode.\n"); + lbs_deb_cmd("disconnected, so exit PS mode\n"); libertas_ps_wakeup(priv, 0); } + lbs_deb_leave(LBS_DEB_CMD); } /** @@ -102,6 +103,7 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event) { char buf[50]; + lbs_deb_enter(LBS_DEB_CMD); memset(buf, 0, sizeof(buf)); sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); @@ -113,6 +115,7 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event) } libertas_send_iwevcustom_event(priv, buf); + lbs_deb_leave(LBS_DEB_CMD); } static int wlan_ret_reg_access(wlan_private * priv, @@ -173,12 +176,12 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4); - lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion: %u.%u.%u.p%u\n", + lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n", adapter->fwreleasenumber[2], adapter->fwreleasenumber[1], adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]); - lbs_deb_cmd("GET_HW_SPEC: Permanent addr: " MAC_FMT "\n", + lbs_deb_cmd("GET_HW_SPEC: MAC addr " MAC_FMT "\n", MAC_ARG(hwspec->permanentaddr)); - lbs_deb_cmd("GET_HW_SPEC: hwifversion: 0x%x version:0x%x\n", + lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", hwspec->hwifversion, hwspec->version); adapter->regioncode = le16_to_cpu(hwspec->regioncode); @@ -228,8 +231,8 @@ static int wlan_ret_802_11_sleep_params(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("error=%x offset=%x stabletime=%x calcontrol=%x\n" - " extsleepclk=%x\n", le16_to_cpu(sp->error), + lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x " + "extsleepclk 0x%x\n", le16_to_cpu(sp->error), le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime), sp->calcontrol, sp->externalsleepclk); @@ -247,6 +250,7 @@ static int wlan_ret_802_11_sleep_params(wlan_private * priv, static int wlan_ret_802_11_stat(wlan_private * priv, struct cmd_ds_command *resp) { + lbs_deb_enter(LBS_DEB_CMD); /* currently adapter->wlan802_11Stat is unused struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; @@ -256,6 +260,7 @@ static int wlan_ret_802_11_stat(wlan_private * priv, memcpy(&adapter->wlan802_11Stat, p11Stat, sizeof(struct cmd_ds_802_11_get_stat)); */ + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -268,28 +273,28 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("SNMP_RESP: value of the oid = %x, querytype=%x\n", oid, + lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid, querytype); - lbs_deb_cmd("SNMP_RESP: Buf size = %x\n", le16_to_cpu(smib->bufsize)); + lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize)); if (querytype == CMD_ACT_GET) { switch (oid) { case FRAGTHRESH_I: priv->adapter->fragthsd = le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: fragthsd =%u\n", + lbs_deb_cmd("SNMP_RESP: frag threshold %u\n", priv->adapter->fragthsd); break; case RTSTHRESH_I: priv->adapter->rtsthsd = le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: rtsthsd =%u\n", + lbs_deb_cmd("SNMP_RESP: rts threshold %u\n", priv->adapter->rtsthsd); break; case SHORT_RETRYLIM_I: priv->adapter->txretrycount = le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: txretrycount =%u\n", + lbs_deb_cmd("SNMP_RESP: tx retry count %u\n", priv->adapter->rtsthsd); break; default: @@ -381,9 +386,9 @@ static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel); - lbs_deb_cmd("Current TxPower Level = %d\n", adapter->txpowerlevel); + lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel); - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -394,15 +399,17 @@ static int wlan_ret_802_11_rf_antenna(wlan_private * priv, wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(pAntenna->action); + lbs_deb_enter(LBS_DEB_CMD); if (action == CMD_ACT_GET_RX) adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode); if (action == CMD_ACT_GET_TX) adapter->txantennamode = le16_to_cpu(pAntenna->antennamode); - lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", + lbs_deb_cmd("RF_ANT_RESP: action 0x%x, mode 0x%04x\n", action, le16_to_cpu(pAntenna->antennamode)); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -419,7 +426,7 @@ static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, adapter->ratebitmap = le16_to_cpu(rates->bitmap); } - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -431,13 +438,14 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate, + lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); /* FIXME: get actual rates FW can do if this command actually returns * all data rates supported. */ adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]); + lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate); lbs_deb_leave(LBS_DEB_CMD); return 0; @@ -455,7 +463,7 @@ static int wlan_ret_802_11_rf_channel(wlan_private * priv, if (action == CMD_OPT_802_11_RF_CHANNEL_GET && adapter->curbssparams.channel != newchannel) { - lbs_deb_cmd("channel Switch: %d to %d\n", + lbs_deb_cmd("channel switch from %d to %d\n", adapter->curbssparams.channel, newchannel); /* Update the channel again */ @@ -472,6 +480,8 @@ static int wlan_ret_802_11_rssi(wlan_private * priv, struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); + /* store the non average value */ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); @@ -487,9 +497,11 @@ static int wlan_ret_802_11_rssi(wlan_private * priv, CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); - lbs_deb_cmd("Beacon RSSI value = 0x%x\n", + lbs_deb_cmd("RSSI: beacon %d, avg %d\n", + adapter->RSSI[TYPE_BEACON][TYPE_NOAVG], adapter->RSSI[TYPE_BEACON][TYPE_AVG]); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -500,11 +512,11 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv, struct wlan_ioctl_regrdwr *pbuf; pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom; - lbs_deb_cmd("eeprom read len=%x\n", + lbs_deb_enter_args(LBS_DEB_CMD, "len %d", le16_to_cpu(resp->params.rdeeprom.bytecount)); if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { pbuf->NOB = 0; - lbs_deb_cmd("eeprom read return length is too big\n"); + lbs_deb_cmd("EEPROM read length too big\n"); return -1; } pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); @@ -512,9 +524,10 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv, memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, le16_to_cpu(resp->params.rdeeprom.bytecount)); - lbs_deb_hex(LBS_DEB_CMD, "adapter", (char *)&pbuf->value, + lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value, le16_to_cpu(resp->params.rdeeprom.bytecount)); } + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -529,7 +542,7 @@ static int wlan_ret_get_log(wlan_private * priv, /* Stored little-endian */ memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log)); - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -547,7 +560,7 @@ static int libertas_ret_802_11_enable_rsn(wlan_private * priv, *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable); } - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -559,6 +572,8 @@ static inline int handle_cmd_response(u16 respcmd, unsigned long flags; wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_HOST); + switch (respcmd) { case CMD_RET(CMD_MAC_REG_ACCESS): case CMD_RET(CMD_BBP_REG_ACCESS): @@ -654,7 +669,6 @@ static inline int handle_cmd_response(u16 respcmd, break; case CMD_RET(CMD_802_11_KEY_MATERIAL): - lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n"); ret = wlan_ret_802_11_key_material(priv, resp); break; @@ -725,10 +739,11 @@ static inline int handle_cmd_response(u16 respcmd, priv->adapter->txrate = resp->params.txrate.txrate; break; default: - lbs_deb_cmd("CMD_RESP: Unknown command response %#x\n", + lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", resp->command); break; } + lbs_deb_leave(LBS_DEB_HOST); return ret; } @@ -741,9 +756,7 @@ int libertas_process_rx_command(wlan_private * priv) ulong flags; u16 result; - lbs_deb_enter(LBS_DEB_CMD); - - lbs_deb_cmd("CMD_RESP: @ %lu\n", jiffies); + lbs_deb_enter(LBS_DEB_HOST); /* Now we got response from FW, cancel the command timer */ del_timer(&adapter->command_timer); @@ -752,25 +765,23 @@ int libertas_process_rx_command(wlan_private * priv) spin_lock_irqsave(&adapter->driver_lock, flags); if (!adapter->cur_cmd) { - lbs_deb_cmd("CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd); + lbs_deb_host("CMD_RESP: cur_cmd is NULL\n"); ret = -1; spin_unlock_irqrestore(&adapter->driver_lock, flags); goto done; } resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); - lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr, - priv->upld_len); - respcmd = le16_to_cpu(resp->command); - result = le16_to_cpu(resp->result); - lbs_deb_cmd("CMD_RESP: %x result: %d length: %d\n", respcmd, - result, priv->upld_len); + lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", + respcmd, priv->upld_len, jiffies); + lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr, + priv->upld_len); if (!(respcmd & 0x8000)) { - lbs_deb_cmd("Invalid response to command!"); + lbs_deb_host("invalid response!\n"); adapter->cur_cmd_retcode = -1; __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->nr_cmd_pending--; @@ -787,12 +798,12 @@ int libertas_process_rx_command(wlan_private * priv) struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; u16 action = le16_to_cpu(psmode->action); - lbs_deb_cmd( - "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n", + lbs_deb_host( + "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n", result, action); if (result) { - lbs_deb_cmd("CMD_RESP: PS command failed- %#x \n", + lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n", result); /* * We should not re-try enter-ps command in @@ -806,14 +817,14 @@ int libertas_process_rx_command(wlan_private * priv) adapter->needtowakeup = 0; adapter->psstate = PS_STATE_AWAKE; - lbs_deb_cmd("CMD_RESP: Enter_PS command response\n"); + lbs_deb_host("CMD_RESP: ENTER_PS command response\n"); if (adapter->connect_status != LIBERTAS_CONNECTED) { /* * When Deauth Event received before Enter_PS command * response, We need to wake up the firmware. */ - lbs_deb_cmd( - "Disconnected, Going to invoke libertas_ps_wakeup\n"); + lbs_deb_host( + "disconnected, invoking libertas_ps_wakeup\n"); spin_unlock_irqrestore(&adapter->driver_lock, flags); mutex_unlock(&adapter->lock); @@ -824,9 +835,9 @@ int libertas_process_rx_command(wlan_private * priv) } else if (action == CMD_SUBCMD_EXIT_PS) { adapter->needtowakeup = 0; adapter->psstate = PS_STATE_FULL_POWER; - lbs_deb_cmd("CMD_RESP: Exit_PS command response\n"); + lbs_deb_host("CMD_RESP: EXIT_PS command response\n"); } else { - lbs_deb_cmd("CMD_RESP: PS- action=0x%X\n", action); + lbs_deb_host("CMD_RESP: PS action 0x%X\n", action); } __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); @@ -847,15 +858,15 @@ int libertas_process_rx_command(wlan_private * priv) /* If the command is not successful, cleanup and return failure */ if ((result != 0 || !(respcmd & 0x8000))) { - lbs_deb_cmd("CMD_RESP: command reply %#x result=%#x\n", - respcmd, result); + lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n", + result, respcmd); /* * Handling errors here */ switch (respcmd) { case CMD_RET(CMD_GET_HW_SPEC): case CMD_RET(CMD_802_11_RESET): - lbs_deb_cmd("CMD_RESP: Reset command failed\n"); + lbs_deb_host("CMD_RESP: reset failed\n"); break; } @@ -885,7 +896,7 @@ int libertas_process_rx_command(wlan_private * priv) done: mutex_unlock(&adapter->lock); - lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -901,7 +912,7 @@ int libertas_process_event(wlan_private * priv) lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("EVENT Cause %x\n", eventcause); + lbs_deb_cmd("event cause 0x%x\n", eventcause); switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { case MACREG_INT_CODE_LINK_SENSED: @@ -909,28 +920,27 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_DEAUTHENTICATED: - lbs_deb_cmd("EVENT: Deauthenticated\n"); + lbs_deb_cmd("EVENT: deauthenticated\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_DISASSOCIATED: - lbs_deb_cmd("EVENT: Disassociated\n"); + lbs_deb_cmd("EVENT: disassociated\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: - lbs_deb_cmd("EVENT: Link lost\n"); + lbs_deb_cmd("EVENT: link lost\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_PS_SLEEP: - lbs_deb_cmd("EVENT: SLEEP\n"); - lbs_deb_cmd("_"); + lbs_deb_cmd("EVENT: sleep\n"); /* handle unexpected PS SLEEP event */ if (adapter->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( - "EVENT: In FULL POWER mode - ignore PS SLEEP\n"); + "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n"); break; } adapter->psstate = PS_STATE_PRE_SLEEP; @@ -940,8 +950,7 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_PS_AWAKE: - lbs_deb_cmd("EVENT: AWAKE \n"); - lbs_deb_cmd("|"); + lbs_deb_cmd("EVENT: awake\n"); /* handle unexpected PS AWAKE event */ if (adapter->psstate == PS_STATE_FULL_POWER) { @@ -959,7 +968,7 @@ int libertas_process_event(wlan_private * priv) * adapter->needtowakeup will be set to FALSE * in libertas_ps_wakeup() */ - lbs_deb_cmd("Waking up...\n"); + lbs_deb_cmd("waking up ...\n"); libertas_ps_wakeup(priv, 0); } break; @@ -978,27 +987,27 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_ADHOC_BCN_LOST: - lbs_deb_cmd("EVENT: HWAC - ADHOC BCN LOST\n"); + lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: - lbs_pr_alert( "EVENT: RSSI_LOW\n"); + lbs_pr_alert("EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: - lbs_pr_alert( "EVENT: SNR_LOW\n"); + lbs_pr_alert("EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: - lbs_pr_alert( "EVENT: MAX_FAIL\n"); + lbs_pr_alert("EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: - lbs_pr_alert( "EVENT: RSSI_HIGH\n"); + lbs_pr_alert("EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: - lbs_pr_alert( "EVENT: SNR_HIGH\n"); + lbs_pr_alert("EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: - lbs_pr_alert( "EVENT: MESH_AUTO_STARTED\n"); + lbs_pr_alert("EVENT: MESH_AUTO_STARTED\n"); adapter->connect_status = LIBERTAS_CONNECTED ; if (priv->mesh_open == 1) { netif_wake_queue(priv->mesh_dev) ; @@ -1009,7 +1018,7 @@ int libertas_process_event(wlan_private * priv) break; default: - lbs_pr_alert( "EVENT: unknown event id: %#x\n", + lbs_pr_alert("EVENT: unknown event id 0x%04x\n", eventcause >> SBI_EVENT_CAUSE_SHIFT); break; } From 8ff12da121af175a14c4cedbba0fd16ff0cfc07a Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:54:31 -0400 Subject: [PATCH 1255/2804] [PATCH] libertas: use LBS_DEB_HOST for host-to-card communications ... and LBS_DEB_CMD for command execution. Also tidies misc comments to give a consistent output. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 259 ++++++++++++++------------- drivers/net/wireless/libertas/main.c | 2 +- 2 files changed, 137 insertions(+), 124 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8d2f9bad8680..d3402e1b760b 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -68,7 +68,7 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, switch (cmd_action) { case CMD_SUBCMD_ENTER_PS: lbs_deb_cmd("PS command:" "SubCode- Enter PS\n"); - lbs_deb_cmd("locallisteninterval = %d\n", + lbs_deb_cmd("locallisteninterval %d\n", adapter->locallisteninterval); psm->locallisteninterval = @@ -101,6 +101,8 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, { u16 *timeout = pdata_buf; + lbs_deb_enter(LBS_DEB_CMD); + cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout) @@ -113,6 +115,7 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, else cmd->params.inactivity_timeout.timeout = 0; + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -177,8 +180,6 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx & (u32)CMD_WEP_KEY_INDEX_MASK)); - lbs_deb_cmd("Tx key Index: %u\n", le16_to_cpu(wep->keyindex)); - /* Copy key types and material to host command structure */ for (i = 0; i < 4; i++) { struct enc_key * pkey = &assoc_req->wep_keys[i]; @@ -189,17 +190,19 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, cpu_to_le16(CMD_TYPE_WEP_40_BIT); memmove(&wep->keymaterial[i], pkey->key, pkey->len); + lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); break; case KEY_LEN_WEP_104: wep->keytype[i] = cpu_to_le16(CMD_TYPE_WEP_104_BIT); memmove(&wep->keymaterial[i], pkey->key, pkey->len); + lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); break; case 0: break; default: - lbs_deb_cmd("Invalid WEP key %d length of %d\n", + lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n", i, pkey->len); ret = -1; goto done; @@ -213,6 +216,7 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, /* default tx key index */ wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx & (u32)CMD_WEP_KEY_INDEX_MASK)); + lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx); } ret = 0; @@ -241,6 +245,7 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN); else penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN); + lbs_deb_cmd("ENABLE_RSN: %d\n", *enable); } lbs_deb_leave(LBS_DEB_CMD); @@ -251,6 +256,8 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, struct enc_key * pkey) { + lbs_deb_enter(LBS_DEB_CMD); + if (pkey->flags & KEY_INFO_WPA_ENABLED) { pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); } @@ -269,6 +276,7 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, + sizeof(pkeyparamset->keyinfo) + sizeof(pkeyparamset->keylen) + sizeof(pkeyparamset->key)); + lbs_deb_leave(LBS_DEB_CMD); } static int wlan_cmd_802_11_key_material(wlan_private * priv, @@ -323,30 +331,37 @@ static int wlan_cmd_802_11_reset(wlan_private * priv, { struct cmd_ds_802_11_reset *reset = &cmd->params.reset; + lbs_deb_enter(LBS_DEB_CMD); + cmd->command = cpu_to_le16(CMD_802_11_RESET); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); reset->action = cpu_to_le16(cmd_action); + lbs_deb_leave(LBS_DEB_CMD); return 0; } static int wlan_cmd_802_11_get_log(wlan_private * priv, struct cmd_ds_command *cmd) { + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_GET_LOG); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN); + lbs_deb_leave(LBS_DEB_CMD); return 0; } static int wlan_cmd_802_11_get_stat(wlan_private * priv, struct cmd_ds_command *cmd) { + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_GET_STAT); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -462,7 +477,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result)); lbs_deb_cmd( - "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n", + "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n", le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid), le16_to_cpu(pSNMPMIB->bufsize), le16_to_cpu(*(__le16 *) pSNMPMIB->value)); @@ -561,6 +576,7 @@ static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, { struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RF_ANTENNA); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + S_DS_GEN); @@ -570,6 +586,7 @@ static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf)); } + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -581,13 +598,12 @@ static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, *rateadapt = &cmd->params.rateset; wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) + S_DS_GEN); cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET); - lbs_deb_enter(LBS_DEB_CMD); - rateadapt->action = cpu_to_le16(cmd_action); rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto); rateadapt->bitmap = cpu_to_le16(adapter->ratebitmap); @@ -613,10 +629,10 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv, if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) { pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate); - lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", + lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", adapter->cur_rate); } else if (cmd_action == CMD_ACT_SET_TX_AUTO) { - lbs_deb_cmd("Setting FW for AUTO rate\n"); + lbs_deb_cmd("DATA_RATE: setting auto\n"); } lbs_deb_leave(LBS_DEB_CMD); @@ -630,16 +646,19 @@ static int wlan_cmd_mac_multicast_adr(wlan_private * priv, struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + S_DS_GEN); cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR); + lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs); pMCastAdr->action = cpu_to_le16(cmd_action); pMCastAdr->nr_of_adrs = cpu_to_le16((u16) adapter->nr_of_multicastmacaddr); memcpy(pMCastAdr->maclist, adapter->multicastlist, adapter->nr_of_multicastmacaddr * ETH_ALEN); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -649,6 +668,7 @@ static int wlan_cmd_802_11_rf_channel(wlan_private * priv, { struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel; + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) + S_DS_GEN); @@ -659,6 +679,7 @@ static int wlan_cmd_802_11_rf_channel(wlan_private * priv, rfchan->action = cpu_to_le16(option); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -667,6 +688,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, { wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RSSI); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor); @@ -679,6 +701,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0; + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -763,6 +786,7 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, { wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + S_DS_GEN); @@ -776,6 +800,7 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6); } + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -797,6 +822,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB); cmd->params.rdeeprom.value = 0; + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -805,7 +831,7 @@ static int wlan_cmd_bt_access(wlan_private * priv, u16 cmd_action, void *pdata_buf) { struct cmd_ds_bt_access *bt_access = &cmd->params.bt; - lbs_deb_cmd("BT CMD(%d)\n", cmd_action); + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_BT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN); @@ -834,6 +860,7 @@ static int wlan_cmd_bt_access(wlan_private * priv, default: break; } + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -842,7 +869,7 @@ static int wlan_cmd_fwt_access(wlan_private * priv, u16 cmd_action, void *pdata_buf) { struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; - lbs_deb_cmd("FWT CMD(%d)\n", cmd_action); + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_FWT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN); @@ -855,6 +882,7 @@ static int wlan_cmd_fwt_access(wlan_private * priv, fwt_access->action = cpu_to_le16(cmd_action); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -863,7 +891,7 @@ static int wlan_cmd_mesh_access(wlan_private * priv, u16 cmd_action, void *pdata_buf) { struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh; - lbs_deb_cmd("FWT CMD(%d)\n", cmd_action); + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_MESH_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN); @@ -876,6 +904,7 @@ static int wlan_cmd_mesh_access(wlan_private * priv, mesh_access->action = cpu_to_le16(cmd_action); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -884,16 +913,16 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u unsigned long flags; struct cmd_ds_command *cmdptr; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (!cmdnode) { - lbs_deb_cmd("QUEUE_CMD: cmdnode is NULL\n"); + lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n"); goto done; } cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; if (!cmdptr) { - lbs_deb_cmd("QUEUE_CMD: cmdptr is NULL\n"); + lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n"); goto done; } @@ -916,17 +945,16 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u spin_unlock_irqrestore(&adapter->driver_lock, flags); - lbs_deb_cmd("QUEUE_CMD: Inserted node=%p, cmd=0x%x in cmdpendingq\n", - cmdnode, + lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n", le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command)); done: - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } /* * TODO: Fix the issue when DownloadcommandToStation is being called the - * second time when the command timesout. All the cmdptr->xxx are in little + * second time when the command times out. All the cmdptr->xxx are in little * endian and therefore all the comparissions will fail. * For now - we are not performing the endian conversion the second time - but * for PS and DEEP_SLEEP we need to worry @@ -941,11 +969,10 @@ static int DownloadcommandToStation(wlan_private * priv, u16 cmdsize; u16 command; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (!adapter || !cmdnode) { - lbs_deb_cmd("DNLD_CMD: adapter = %p, cmdnode = %p\n", - adapter, cmdnode); + lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n"); if (cmdnode) { spin_lock_irqsave(&adapter->driver_lock, flags); __libertas_cleanup_and_insert_cmd(priv, cmdnode); @@ -957,11 +984,9 @@ static int DownloadcommandToStation(wlan_private * priv, cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - spin_lock_irqsave(&adapter->driver_lock, flags); if (!cmdptr || !cmdptr->size) { - lbs_deb_cmd("DNLD_CMD: cmdptr is Null or cmd size is Zero, " - "Not sending\n"); + lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n"); __libertas_cleanup_and_insert_cmd(priv, cmdnode); spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = -1; @@ -971,20 +996,21 @@ static int DownloadcommandToStation(wlan_private * priv, adapter->cur_cmd = cmdnode; adapter->cur_cmd_retcode = 0; spin_unlock_irqrestore(&adapter->driver_lock, flags); - lbs_deb_cmd("DNLD_CMD:: Before download, size of cmd = %d\n", - le16_to_cpu(cmdptr->size)); cmdsize = cmdptr->size; - command = cpu_to_le16(cmdptr->command); + lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n", + command, le16_to_cpu(cmdptr->size), jiffies); + lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize); + cmdnode->cmdwaitqwoken = 0; cmdsize = cpu_to_le16(cmdsize); ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize); if (ret != 0) { - lbs_deb_cmd("DNLD_CMD: Host to Card failed\n"); + lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n"); spin_lock_irqsave(&adapter->driver_lock, flags); __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->cur_cmd = NULL; @@ -993,8 +1019,7 @@ static int DownloadcommandToStation(wlan_private * priv, goto done; } - lbs_deb_cmd("DNLD_CMD: sent command 0x%x, jiffies %lu\n", command, jiffies); - lbs_deb_hex(LBS_DEB_CMD, "command", cmdnode->bufvirtualaddr, cmdsize); + lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies); /* Setup the timer after transmit command */ if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE @@ -1006,7 +1031,7 @@ static int DownloadcommandToStation(wlan_private * priv, ret = 0; done: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -1021,7 +1046,7 @@ static int wlan_cmd_mac_control(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); mac->action = cpu_to_le16(priv->adapter->currentpacketfilter); - lbs_deb_cmd("wlan_cmd_mac_control(): action=0x%X size=%d\n", + lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n", le16_to_cpu(mac->action), le16_to_cpu(cmd->size)); lbs_deb_leave(LBS_DEB_CMD); @@ -1037,12 +1062,10 @@ void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node wlan_adapter *adapter = priv->adapter; if (!ptempcmd) - goto done; + return; cleanup_cmdnode(ptempcmd); list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq); -done: - return; } static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) @@ -1065,7 +1088,7 @@ int libertas_set_radio_control(wlan_private * priv) CMD_ACT_SET, CMD_OPTION_WAITFORRSP, 0, NULL); - lbs_deb_cmd("RADIO_SET: on or off: 0x%X, preamble = 0x%X\n", + lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->adapter->radioon, priv->adapter->preamble); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); @@ -1078,9 +1101,6 @@ int libertas_set_mac_packet_filter(wlan_private * priv) lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("libertas_set_mac_packet_filter value = %x\n", - priv->adapter->currentpacketfilter); - /* Send MAC control command to station */ ret = libertas_prepare_and_send_command(priv, CMD_MAC_CONTROL, 0, 0, 0, NULL); @@ -1111,16 +1131,16 @@ int libertas_prepare_and_send_command(wlan_private * priv, struct cmd_ds_command *cmdptr; unsigned long flags; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (!adapter) { - lbs_deb_cmd("PREP_CMD: adapter is Null\n"); + lbs_deb_host("PREP_CMD: adapter is NULL\n"); ret = -1; goto done; } if (adapter->surpriseremoved) { - lbs_deb_cmd("PREP_CMD: Card is Removed\n"); + lbs_deb_host("PREP_CMD: card removed\n"); ret = -1; goto done; } @@ -1128,7 +1148,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, cmdnode = libertas_get_free_cmd_ctrl_node(priv); if (cmdnode == NULL) { - lbs_deb_cmd("PREP_CMD: No free cmdnode\n"); + lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); /* Wake up main thread to execute next command */ wake_up_interruptible(&priv->waitq); @@ -1140,11 +1160,10 @@ int libertas_prepare_and_send_command(wlan_private * priv, cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - lbs_deb_cmd("PREP_CMD: Val of cmd ptr=%p, command=0x%X\n", - cmdptr, cmd_no); + lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no); if (!cmdptr) { - lbs_deb_cmd("PREP_CMD: bufvirtualaddr of cmdnode is NULL\n"); + lbs_deb_host("PREP_CMD: cmdptr is NULL\n"); libertas_cleanup_and_insert_cmd(priv, cmdnode); ret = -1; goto done; @@ -1382,14 +1401,14 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; default: - lbs_deb_cmd("PREP_CMD: unknown command- %#x\n", cmd_no); + lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; break; } /* return error, since the command preparation failed */ if (ret != 0) { - lbs_deb_cmd("PREP_CMD: command preparation failed\n"); + lbs_deb_host("PREP_CMD: command preparation failed\n"); libertas_cleanup_and_insert_cmd(priv, cmdnode); ret = -1; goto done; @@ -1402,7 +1421,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, wake_up_interruptible(&priv->waitq); if (wait_option & CMD_OPTION_WAITFORRSP) { - lbs_deb_cmd("PREP_CMD: Wait for CMD response\n"); + lbs_deb_host("PREP_CMD: wait for response\n"); might_sleep(); wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken); @@ -1410,7 +1429,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd_retcode) { - lbs_deb_cmd("PREP_CMD: command failed with return code=%d\n", + lbs_deb_host("PREP_CMD: command failed with return code %d\n", adapter->cur_cmd_retcode); adapter->cur_cmd_retcode = 0; ret = -1; @@ -1418,7 +1437,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, spin_unlock_irqrestore(&adapter->driver_lock, flags); done: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(libertas_prepare_and_send_command); @@ -1439,14 +1458,13 @@ int libertas_allocate_cmd_buffer(wlan_private * priv) u8 *ptempvirtualaddr; wlan_adapter *adapter = priv->adapter; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); /* Allocate and initialize cmdCtrlNode */ ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER; if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) { - lbs_deb_cmd( - "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n"); + lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n"); ret = -1; goto done; } @@ -1456,8 +1474,7 @@ int libertas_allocate_cmd_buffer(wlan_private * priv) ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) { - lbs_deb_cmd( - "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n"); + lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n"); ret = -1; goto done; } @@ -1474,7 +1491,7 @@ int libertas_allocate_cmd_buffer(wlan_private * priv) ret = 0; done: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -1491,11 +1508,11 @@ int libertas_free_cmd_buffer(wlan_private * priv) struct cmd_ctrl_node *tempcmd_array; wlan_adapter *adapter = priv->adapter; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); /* need to check if cmd array is allocated or not */ if (adapter->cmd_array == NULL) { - lbs_deb_cmd("FREE_CMD_BUF: cmd_array is Null\n"); + lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n"); goto done; } @@ -1505,7 +1522,6 @@ int libertas_free_cmd_buffer(wlan_private * priv) ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { if (tempcmd_array[i].bufvirtualaddr) { - lbs_deb_cmd("Free all the array\n"); kfree(tempcmd_array[i].bufvirtualaddr); tempcmd_array[i].bufvirtualaddr = NULL; } @@ -1513,13 +1529,12 @@ int libertas_free_cmd_buffer(wlan_private * priv) /* Release cmd_ctrl_node */ if (adapter->cmd_array) { - lbs_deb_cmd("Free cmd_array\n"); kfree(adapter->cmd_array); adapter->cmd_array = NULL; } done: - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); return 0; } @@ -1536,6 +1551,8 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) wlan_adapter *adapter = priv->adapter; unsigned long flags; + lbs_deb_enter(LBS_DEB_HOST); + if (!adapter) return NULL; @@ -1545,21 +1562,16 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next; list_del((struct list_head *)tempnode); } else { - lbs_deb_cmd("GET_CMD_NODE: cmd_ctrl_node is not available\n"); + lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n"); tempnode = NULL; } spin_unlock_irqrestore(&adapter->driver_lock, flags); - if (tempnode) { - /* - lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n"); - lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n", - tempnode); - */ + if (tempnode) cleanup_cmdnode(tempnode); - } + lbs_deb_leave(LBS_DEB_HOST); return tempnode; } @@ -1571,6 +1583,8 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) */ static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode) { + lbs_deb_enter(LBS_DEB_HOST); + if (!ptempnode) return; ptempnode->cmdwaitqwoken = 1; @@ -1582,7 +1596,8 @@ static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode) if (ptempnode->bufvirtualaddr != NULL) memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER); - return; + + lbs_deb_leave(LBS_DEB_HOST); } /** @@ -1599,7 +1614,7 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv, struct cmd_ctrl_node *ptempnode, u32 cmd_oid, u16 wait_option, void *pdata_buf) { - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (!ptempnode) return; @@ -1608,7 +1623,7 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv, ptempnode->wait_option = wait_option; ptempnode->pdata_buf = pdata_buf; - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } /** @@ -1627,12 +1642,15 @@ int libertas_execute_next_command(wlan_private * priv) unsigned long flags; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); + // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the + // only caller to us is libertas_thread() and we get even when a + // data packet is received + lbs_deb_enter(LBS_DEB_THREAD); spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd) { - lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n"); + lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n"); spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = -1; goto done; @@ -1646,22 +1664,20 @@ int libertas_execute_next_command(wlan_private * priv) spin_unlock_irqrestore(&adapter->driver_lock, flags); if (cmdnode) { - lbs_deb_cmd( - "EXEC_NEXT_CMD: Got next command from cmdpendingq\n"); cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; if (is_command_allowed_in_ps(cmdptr->command)) { if ((adapter->psstate == PS_STATE_SLEEP) || (adapter->psstate == PS_STATE_PRE_SLEEP)) { - lbs_deb_cmd( - "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n", + lbs_deb_host( + "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n", le16_to_cpu(cmdptr->command), adapter->psstate); ret = -1; goto done; } - lbs_deb_cmd("EXEC_NEXT_CMD: OK to send command " - "0x%x in psstate %d\n", + lbs_deb_host("EXEC_NEXT_CMD: OK to send command " + "0x%04x in psstate %d\n", le16_to_cpu(cmdptr->command), adapter->psstate); } else if (adapter->psstate != PS_STATE_FULL_POWER) { @@ -1699,13 +1715,13 @@ int libertas_execute_next_command(wlan_private * priv) struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; - lbs_deb_cmd( - "EXEC_NEXT_CMD: PS cmd- action=0x%x\n", + lbs_deb_host( + "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n", psm->action); if (psm->action != cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { - lbs_deb_cmd( - "EXEC_NEXT_CMD: Ignore Enter PS cmd\n"); + lbs_deb_host( + "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n"); list_del((struct list_head *)cmdnode); libertas_cleanup_and_insert_cmd(priv, cmdnode); @@ -1715,8 +1731,8 @@ int libertas_execute_next_command(wlan_private * priv) if ((adapter->psstate == PS_STATE_SLEEP) || (adapter->psstate == PS_STATE_PRE_SLEEP)) { - lbs_deb_cmd( - "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n"); + lbs_deb_host( + "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n"); list_del((struct list_head *)cmdnode); libertas_cleanup_and_insert_cmd(priv, cmdnode); adapter->needtowakeup = 1; @@ -1725,12 +1741,12 @@ int libertas_execute_next_command(wlan_private * priv) goto done; } - lbs_deb_cmd( - "EXEC_NEXT_CMD: Sending Exit_PS down...\n"); + lbs_deb_host( + "EXEC_NEXT_CMD: sending EXIT_PS\n"); } } list_del((struct list_head *)cmdnode); - lbs_deb_cmd("EXEC_NEXT_CMD: Sending 0x%04X command\n", + lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n", le16_to_cpu(cmdptr->command)); DownloadcommandToStation(priv, cmdnode); } else { @@ -1746,15 +1762,15 @@ int libertas_execute_next_command(wlan_private * priv) /* check for valid WPA group keys */ if (adapter->wpa_mcast_key.len || adapter->wpa_unicast_key.len) { - lbs_deb_cmd( + lbs_deb_host( "EXEC_NEXT_CMD: WPA enabled and GTK_SET" " go back to PS_SLEEP"); libertas_ps_sleep(priv, 0); } } else { - lbs_deb_cmd( - "EXEC_NEXT_CMD: command PendQ is empty," - " go back to PS_SLEEP"); + lbs_deb_host( + "EXEC_NEXT_CMD: cmdpendingq empty, " + "go back to PS_SLEEP"); libertas_ps_sleep(priv, 0); } } @@ -1762,7 +1778,7 @@ int libertas_execute_next_command(wlan_private * priv) ret = 0; done: - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_THREAD); return ret; } @@ -1771,7 +1787,7 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) union iwreq_data iwrq; u8 buf[50]; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_WEXT); memset(&iwrq, 0, sizeof(union iwreq_data)); memset(buf, 0, sizeof(buf)); @@ -1781,13 +1797,13 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; /* Send Event to upper layer */ - lbs_deb_cmd("Event Indication string = %s\n", (char *)buf); - lbs_deb_cmd("Event Indication String length = %d\n", iwrq.data.length); + lbs_deb_wext("event indication string %s\n", (char *)buf); + lbs_deb_wext("event indication length %d\n", iwrq.data.length); + lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str); - lbs_deb_cmd("Sending wireless event IWEVCUSTOM for %s\n", str); wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf); - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_WEXT); } static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) @@ -1796,19 +1812,19 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) wlan_adapter *adapter = priv->adapter; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); - lbs_deb_cmd("SEND_SLEEPC_CMD: Before download, size of cmd = %d\n", + lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n", size); - lbs_deb_hex(LBS_DEB_CMD, "sleep confirm command", cmdptr, size); + lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size); ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size); priv->dnld_sent = DNLD_RES_RECEIVED; spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->intcounter || adapter->currenttxskb) - lbs_deb_cmd("SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n", + lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n", adapter->intcounter, adapter->currenttxskb); spin_unlock_irqrestore(&adapter->driver_lock, flags); @@ -1820,22 +1836,21 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) if (!adapter->intcounter) { adapter->psstate = PS_STATE_SLEEP; } else { - lbs_deb_cmd("SEND_SLEEPC_CMD: After sent,IntC=%d\n", + lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n", adapter->intcounter); } spin_unlock_irqrestore(&adapter->driver_lock, flags); - lbs_deb_cmd("SEND_SLEEPC_CMD: Sent Confirm Sleep command\n"); - lbs_deb_cmd("+"); + lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n"); } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } void libertas_ps_sleep(wlan_private * priv, int wait_option) { - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); /* * PS is currently supported only in Infrastructure mode @@ -1845,11 +1860,11 @@ void libertas_ps_sleep(wlan_private * priv, int wait_option) libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL); - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } /** - * @brief This function sends Eixt_PS command to firmware. + * @brief This function sends Exit_PS command to firmware. * * @param priv A pointer to wlan_private structure * @param wait_option wait response or not @@ -1859,17 +1874,15 @@ void libertas_ps_wakeup(wlan_private * priv, int wait_option) { __le32 Localpsmode; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM); - lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", WLAN802_11POWERMODECAM); - libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, CMD_SUBCMD_EXIT_PS, wait_option, 0, &Localpsmode); - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } /** @@ -1886,31 +1899,31 @@ void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode) wlan_adapter *adapter = priv->adapter; u8 allowed = 1; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (priv->dnld_sent) { allowed = 0; - lbs_deb_cmd("D"); + lbs_deb_host("dnld_sent was set"); } spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd) { allowed = 0; - lbs_deb_cmd("C"); + lbs_deb_host("cur_cmd was set"); } if (adapter->intcounter > 0) { allowed = 0; - lbs_deb_cmd("I%d", adapter->intcounter); + lbs_deb_host("intcounter %d", adapter->intcounter); } spin_unlock_irqrestore(&adapter->driver_lock, flags); if (allowed) { - lbs_deb_cmd("Sending libertas_ps_confirm_sleep\n"); + lbs_deb_host("sending libertas_ps_confirm_sleep\n"); sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep, sizeof(struct PS_CMD_ConfirmSleep)); } else { - lbs_deb_cmd("Sleep Confirm has been delayed\n"); + lbs_deb_host("sleep confirm has been delayed\n"); } - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2713f57e9bc8..1b6b09d5f973 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1319,7 +1319,7 @@ static void wake_pending_cmdnodes(wlan_private *priv) struct cmd_ctrl_node *cmdnode; unsigned long flags; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); spin_lock_irqsave(&priv->adapter->driver_lock, flags); list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { From 9cdc6d295b97dc4a36569ddd0b0540aeba351149 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 11:55:22 -0400 Subject: [PATCH 1256/2804] [PATCH] libertas: Avoid MESH_AUTOSTARTED spam on console Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 197d04517840..bf672f51f163 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -1007,13 +1007,13 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_MESH_AUTO_STARTED: - lbs_pr_alert("EVENT: MESH_AUTO_STARTED\n"); - adapter->connect_status = LIBERTAS_CONNECTED ; + lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); + adapter->connect_status = LIBERTAS_CONNECTED; if (priv->mesh_open == 1) { - netif_wake_queue(priv->mesh_dev) ; - netif_carrier_on(priv->mesh_dev) ; + netif_wake_queue(priv->mesh_dev); + netif_carrier_on(priv->mesh_dev); } - adapter->mode = IW_MODE_ADHOC ; + adapter->mode = IW_MODE_ADHOC; schedule_work(&priv->sync_channel); break; From 27590d06e136167101c8c6347e7c2885c7f014b9 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 3 Oct 2007 17:25:41 -0700 Subject: [PATCH 1257/2804] [PATCH] add support for Marvell 8385 CF cards This patch adds support for Marvell based 8385 compact flash cards. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/Kconfig | 7 + drivers/net/wireless/libertas/Makefile | 2 + drivers/net/wireless/libertas/if_cs.c | 1005 ++++++++++++++++++++++++ 3 files changed, 1014 insertions(+) create mode 100644 drivers/net/wireless/libertas/if_cs.c diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index adf0d207da88..8d1541bbe257 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -275,6 +275,13 @@ config LIBERTAS_USB ---help--- A driver for Marvell Libertas 8388 USB devices. +config LIBERTAS_CS + tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" + depends on LIBERTAS && PCMCIA && EXPERIMENTAL + select FW_LOADER + ---help--- + A driver for Marvell Libertas 8385 CompactFlash devices. + config LIBERTAS_DEBUG bool "Enable full debugging output in the Libertas module." depends on LIBERTAS diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index b56b4c55de31..c469d569f090 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -6,6 +6,8 @@ libertas-objs := main.o wext.o \ ethtool.o assoc.o usb8xxx-objs += if_usb.o +libertas_cs-objs += if_cs.o obj-$(CONFIG_LIBERTAS) += libertas.o obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o +obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c new file mode 100644 index 000000000000..888f023a74e1 --- /dev/null +++ b/drivers/net/wireless/libertas/if_cs.c @@ -0,0 +1,1005 @@ +/* + + Driver for the Marvell 8385 based compact flash WLAN cards. + + (C) 2007 by Holger Schurig + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define DRV_NAME "libertas_cs" + +#include "decl.h" +#include "defs.h" +#include "dev.h" + + +/********************************************************************/ +/* Module stuff */ +/********************************************************************/ + +MODULE_AUTHOR("Holger Schurig "); +MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); +MODULE_LICENSE("GPL"); + + + +/********************************************************************/ +/* Data structures */ +/********************************************************************/ + +struct if_cs_card { + struct pcmcia_device *p_dev; + wlan_private *priv; + void __iomem *iobase; +}; + + + +/********************************************************************/ +/* Hardware access */ +/********************************************************************/ + +/* This define enables wrapper functions which allow you + to dump all register accesses. You normally won't this, + except for development */ +/* #define DEBUG_IO */ + +#ifdef DEBUG_IO +static int debug_output = 0; +#else +/* This way the compiler optimizes the printk's away */ +#define debug_output 0 +#endif + +static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg) +{ + unsigned int val = ioread8(card->iobase + reg); + if (debug_output) + printk(KERN_INFO "##inb %08x<%02x\n", reg, val); + return val; +} +static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg) +{ + unsigned int val = ioread16(card->iobase + reg); + if (debug_output) + printk(KERN_INFO "##inw %08x<%04x\n", reg, val); + return val; +} +static inline void if_cs_read16_rep( + struct if_cs_card *card, + uint reg, + void *buf, + unsigned long count) +{ + if (debug_output) + printk(KERN_INFO "##insw %08x<(0x%lx words)\n", + reg, count); + ioread16_rep(card->iobase + reg, buf, count); +} + +static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val) +{ + if (debug_output) + printk(KERN_INFO "##outb %08x>%02x\n", reg, val); + iowrite8(val, card->iobase + reg); +} + +static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val) +{ + if (debug_output) + printk(KERN_INFO "##outw %08x>%04x\n", reg, val); + iowrite16(val, card->iobase + reg); +} + +static inline void if_cs_write16_rep( + struct if_cs_card *card, + uint reg, + void *buf, + unsigned long count) +{ + if (debug_output) + printk(KERN_INFO "##outsw %08x>(0x%lx words)\n", + reg, count); + iowrite16_rep(card->iobase + reg, buf, count); +} + + +/* + * I know that polling/delaying is frowned upon. However, this procedure + * with polling is needed while downloading the firmware. At this stage, + * the hardware does unfortunately not create any interrupts. + * + * Fortunately, this function is never used once the firmware is in + * the card. :-) + * + * As a reference, see the "Firmware Specification v5.1", page 18 + * and 19. I did not follow their suggested timing to the word, + * but this works nice & fast anyway. + */ +static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg) +{ + int i; + + for (i = 0; i < 500; i++) { + u8 val = if_cs_read8(card, addr); + if (val == reg) + return i; + udelay(100); + } + return -ETIME; +} + + + +/* Host control registers and their bit definitions */ + +#define IF_CS_H_STATUS 0x00000000 +#define IF_CS_H_STATUS_TX_OVER 0x0001 +#define IF_CS_H_STATUS_RX_OVER 0x0002 +#define IF_CS_H_STATUS_DNLD_OVER 0x0004 + +#define IF_CS_H_INT_CAUSE 0x00000002 +#define IF_CS_H_IC_TX_OVER 0x0001 +#define IF_CS_H_IC_RX_OVER 0x0002 +#define IF_CS_H_IC_DNLD_OVER 0x0004 +#define IF_CS_H_IC_HOST_EVENT 0x0008 +#define IF_CS_H_IC_MASK 0x001f + +#define IF_CS_H_INT_MASK 0x00000004 +#define IF_CS_H_IM_MASK 0x001f + +#define IF_CS_H_WRITE_LEN 0x00000014 + +#define IF_CS_H_WRITE 0x00000016 + +#define IF_CS_H_CMD_LEN 0x00000018 + +#define IF_CS_H_CMD 0x0000001A + +#define IF_CS_C_READ_LEN 0x00000024 + +#define IF_CS_H_READ 0x00000010 + +/* Card control registers and their bit definitions */ + +#define IF_CS_C_STATUS 0x00000020 +#define IF_CS_C_S_TX_DNLD_RDY 0x0001 +#define IF_CS_C_S_RX_UPLD_RDY 0x0002 +#define IF_CS_C_S_CMD_DNLD_RDY 0x0004 +#define IF_CS_C_S_CMD_UPLD_RDY 0x0008 +#define IF_CS_C_S_CARDEVENT 0x0010 +#define IF_CS_C_S_MASK 0x001f +#define IF_CS_C_S_STATUS_MASK 0x7f00 +/* The following definitions should be the same as the MRVDRV_ ones */ + +#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY +#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync +#endif +#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY +#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync +#endif +#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT +#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync +#endif + +#define IF_CS_C_INT_CAUSE 0x00000022 +#define IF_CS_C_IC_MASK 0x001f + +#define IF_CS_C_SQ_READ_LOW 0x00000028 +#define IF_CS_C_SQ_HELPER_OK 0x10 + +#define IF_CS_C_CMD_LEN 0x00000030 + +#define IF_CS_C_CMD 0x00000012 + +#define IF_CS_SCRATCH 0x0000003F + + + +/********************************************************************/ +/* Interrupts */ +/********************************************************************/ + +static inline void if_cs_enable_ints(struct if_cs_card *card) +{ + lbs_deb_enter(LBS_DEB_CS); + if_cs_write16(card, IF_CS_H_INT_MASK, 0); +} + +static inline void if_cs_disable_ints(struct if_cs_card *card) +{ + lbs_deb_enter(LBS_DEB_CS); + if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK); +} + +static irqreturn_t if_cs_interrupt(int irq, void *data) +{ + struct if_cs_card *card = (struct if_cs_card *)data; + u16 int_cause; + + lbs_deb_enter(LBS_DEB_CS); + + int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); + switch (int_cause) { + case 0x0000: + /* not for us */ + return IRQ_NONE; + case 0xffff: + /* if one reads junk, then probably the card was removed */ + card->priv->adapter->surpriseremoved = 1; + break; + case IF_CS_H_IC_TX_OVER: + if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED) + netif_wake_queue(card->priv->dev); + /* fallthrought */ + default: + /* clear interrupt */ + if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK); + if_cs_disable_ints(card); + } + + libertas_interrupt(card->priv->dev); + + return IRQ_HANDLED; +} + + + + +/********************************************************************/ +/* I/O */ +/********************************************************************/ + +/* + * Called from if_cs_host_to_card to send a command to the hardware + */ +static int if_cs_send_cmd(wlan_private *priv, u8 *buf, u16 nb) +{ + struct if_cs_card *card = (struct if_cs_card *)priv->card; + int ret = -1; + int loops = 0; + + lbs_deb_enter(LBS_DEB_CS); + + /* Is hardware ready? */ + while (1) { + u16 val = if_cs_read16(card, IF_CS_C_STATUS); + if (val & IF_CS_C_S_CMD_DNLD_RDY) + break; + if (++loops > 100) { + lbs_pr_err("card not ready for commands\n"); + goto done; + } + mdelay(1); + } + + if_cs_write16(card, IF_CS_H_CMD_LEN, nb); + + if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2); + /* Are we supposed to transfer an odd amount of bytes? */ + if (nb & 1) + if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]); + + /* "Assert the download over interrupt command in the Host + * status register" */ + if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + + /* "Assert the download over interrupt command in the Card + * interrupt case register" */ + if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + ret = 0; + +done: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + +/* + * Called from if_cs_host_to_card to send a data to the hardware + */ +static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb) +{ + struct if_cs_card *card = (struct if_cs_card *)priv->card; + + lbs_deb_enter(LBS_DEB_CS); + + if_cs_write16(card, IF_CS_H_WRITE_LEN, nb); + + /* write even number of bytes, then odd byte if necessary */ + if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2); + if (nb & 1) + if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]); + + if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER); + if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER); + + lbs_deb_leave(LBS_DEB_CS); +} + + +/* + * Get the command result out of the card. + */ +static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len) +{ + int ret = -1; + u16 val; + + lbs_deb_enter(LBS_DEB_CS); + + /* is hardware ready? */ + val = if_cs_read16(priv->card, IF_CS_C_STATUS); + if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) { + lbs_pr_err("card not ready for CMD\n"); + goto out; + } + + *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN); + if ((*len == 0) || (*len > MRVDRV_SIZE_OF_CMD_BUFFER)) { + lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); + goto out; + } + + /* read even number of bytes, then odd byte if necessary */ + if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16)); + if (*len & 1) + data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD); + + ret = 0; +out: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len); + return ret; +} + + +static struct sk_buff *if_cs_receive_data(wlan_private *priv) +{ + struct sk_buff *skb = NULL; + u16 len; + u8 *data; + + lbs_deb_enter(LBS_DEB_CS); + + len = if_cs_read16(priv->card, IF_CS_C_READ_LEN); + if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { + lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); + priv->stats.rx_dropped++; + printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__); + goto dat_err; + } + + //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN); + skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); + if (!skb) + goto out; + data = skb_put(skb, len); + + /* read even number of bytes, then odd byte if necessary */ + if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16)); + if (len & 1) + data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ); + +dat_err: + if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER); + if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER); + +out: + lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb); + return skb; +} + + + +/********************************************************************/ +/* Firmware */ +/********************************************************************/ + +/* + * Tries to program the helper firmware. + * + * Return 0 on success + */ +static int if_cs_prog_helper(struct if_cs_card *card) +{ + int ret = 0; + int sent = 0; + u8 scratch; + const struct firmware *fw; + + lbs_deb_enter(LBS_DEB_CS); + + scratch = if_cs_read8(card, IF_CS_SCRATCH); + + /* "If the value is 0x5a, the firmware is already + * downloaded successfully" + */ + if (scratch == 0x5a) + goto done; + + /* "If the value is != 00, it is invalid value of register */ + if (scratch != 0x00) { + ret = -ENODEV; + goto done; + } + + /* TODO: make firmware file configurable */ + ret = request_firmware(&fw, "libertas_cs_helper.fw", + &handle_to_dev(card->p_dev)); + if (ret) { + lbs_pr_err("can't load helper firmware\n"); + ret = -ENODEV; + goto done; + } + lbs_deb_cs("helper size %d\n", fw->size); + + /* "Set the 5 bytes of the helper image to 0" */ + /* Not needed, this contains an ARM branch instruction */ + + for (;;) { + /* "the number of bytes to send is 256" */ + int count = 256; + int remain = fw->size - sent; + + if (remain < count) + count = remain; + /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n", + __LINE__, sent, fw->size); */ + + /* "write the number of bytes to be sent to the I/O Command + * write length register" */ + if_cs_write16(card, IF_CS_H_CMD_LEN, count); + + /* "write this to I/O Command port register as 16 bit writes */ + if (count) + if_cs_write16_rep(card, IF_CS_H_CMD, + &fw->data[sent], + count >> 1); + + /* "Assert the download over interrupt command in the Host + * status register" */ + if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + + /* "Assert the download over interrupt command in the Card + * interrupt case register" */ + if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + + /* "The host polls the Card Status register ... for 50 ms before + declaring a failure */ + ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, + IF_CS_C_S_CMD_DNLD_RDY); + if (ret < 0) { + lbs_pr_err("can't download helper at 0x%x, ret %d\n", + sent, ret); + goto done; + } + + if (count == 0) + break; + + sent += count; + } + + release_firmware(fw); + ret = 0; + +done: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + +static int if_cs_prog_real(struct if_cs_card *card) +{ + const struct firmware *fw; + int ret = 0; + int retry = 0; + int len = 0; + int sent; + + lbs_deb_enter(LBS_DEB_CS); + + /* TODO: make firmware file configurable */ + ret = request_firmware(&fw, "libertas_cs.fw", + &handle_to_dev(card->p_dev)); + if (ret) { + lbs_pr_err("can't load firmware\n"); + ret = -ENODEV; + goto done; + } + lbs_deb_cs("fw size %d\n", fw->size); + + ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); + if (ret < 0) { + int i; + lbs_pr_err("helper firmware doesn't answer\n"); + for (i = 0; i < 0x50; i += 2) + printk(KERN_INFO "## HS %02x: %04x\n", + i, if_cs_read16(card, i)); + goto err_release; + } + + for (sent = 0; sent < fw->size; sent += len) { + len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW); + /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n", + __LINE__, sent, fw->size); */ + if (len & 1) { + retry++; + lbs_pr_info("odd, need to retry this firmware block\n"); + } else { + retry = 0; + } + + if (retry > 20) { + lbs_pr_err("could not download firmware\n"); + ret = -ENODEV; + goto err_release; + } + if (retry) { + sent -= len; + } + + + if_cs_write16(card, IF_CS_H_CMD_LEN, len); + + if_cs_write16_rep(card, IF_CS_H_CMD, + &fw->data[sent], + (len+1) >> 1); + if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + + ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, + IF_CS_C_S_CMD_DNLD_RDY); + if (ret < 0) { + lbs_pr_err("can't download firmware at 0x%x\n", sent); + goto err_release; + } + } + + ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); + if (ret < 0) { + lbs_pr_err("firmware download failed\n"); + goto err_release; + } + + ret = 0; + goto done; + + +err_release: + release_firmware(fw); + +done: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + + +/********************************************************************/ +/* Callback functions for libertas.ko */ +/********************************************************************/ + +static int if_cs_register_dev(wlan_private *priv) +{ + struct if_cs_card *card = (struct if_cs_card *)priv->card; + + lbs_deb_enter(LBS_DEB_CS); + + card->priv = priv; + + return 0; +} + + +static int if_cs_unregister_dev(wlan_private *priv) +{ + lbs_deb_enter(LBS_DEB_CS); + + /* + * Nothing special here. Because the device's power gets turned off + * anyway, there's no need to send a RESET command like in if_usb.c + */ + + return 0; +} + + +/* + * This callback is a dummy. The reason is that the USB code needs + * to have various things set up in order to be able to download the + * firmware. That's not needed in our case. + * + * On the contrary, if libertas_add_card() has been called and we're + * then later called via libertas_activate_card(), but without a valid + * firmware, then it's quite tedious to tear down the half-installed + * card. Therefore, we download the firmware before calling adding/ + * activating the card in the first place. If that doesn't work, we + * won't call into libertas.ko at all. + */ + +static int if_cs_prog_firmware(wlan_private *priv) +{ + priv->adapter->fw_ready = 1; + return 0; +} + + +/* Send commands or data packets to the card */ +static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) +{ + int ret = -1; + + lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb); + + switch (type) { + case MVMS_DAT: + priv->dnld_sent = DNLD_CMD_SENT; + if_cs_send_data(priv, buf, nb); + ret = 0; + break; + case MVMS_CMD: + ret = if_cs_send_cmd(priv, buf, nb); + break; + default: + lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type); + } + + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + +static int if_cs_get_int_status(wlan_private *priv, u8 *ireg) +{ + struct if_cs_card *card = (struct if_cs_card *)priv->card; + //wlan_adapter *adapter = priv->adapter; + int ret = 0; + u16 int_cause; + u8 *cmdbuf; + *ireg = 0; + + lbs_deb_enter(LBS_DEB_CS); + + if (priv->adapter->surpriseremoved) + goto out; + + int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK; + if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause); + + *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK; + if_cs_enable_ints(card); + + if (!*ireg) + goto sbi_get_int_status_exit; + +sbi_get_int_status_exit: + + /* is there a data packet for us? */ + if (*ireg & IF_CS_C_S_RX_UPLD_RDY) { + struct sk_buff *skb = if_cs_receive_data(priv); + libertas_process_rxed_packet(priv, skb); + *ireg &= ~IF_CS_C_S_RX_UPLD_RDY; + } + + if (*ireg & IF_CS_C_S_TX_DNLD_RDY) { + priv->dnld_sent = DNLD_RES_RECEIVED; + } + + /* Card has a command result for us */ + if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) { + spin_lock(&priv->adapter->driver_lock); + if (!priv->adapter->cur_cmd) { + cmdbuf = priv->upld_buf; + priv->adapter->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY; + } else { + cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; + } + + ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len); + spin_unlock(&priv->adapter->driver_lock); + if (ret < 0) + lbs_pr_err("could not receive cmd from card\n"); + } + +out: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->adapter->hisregcpy); + return ret; +} + + +static int if_cs_read_event_cause(wlan_private *priv) +{ + lbs_deb_enter(LBS_DEB_CS); + + priv->adapter->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5; + if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT); + + return 0; +} + + + +/********************************************************************/ +/* Card Services */ +/********************************************************************/ + +/* + * After a card is removed, if_cs_release() will unregister the + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void if_cs_release(struct pcmcia_device *p_dev) +{ + struct if_cs_card *card = p_dev->priv; + + lbs_deb_enter(LBS_DEB_CS); + + pcmcia_disable_device(p_dev); + free_irq(p_dev->irq.AssignedIRQ, card); + if (card->iobase) + ioport_unmap(card->iobase); + + lbs_deb_leave(LBS_DEB_CS); +} + + +/* + * This creates an "instance" of the driver, allocating local data + * structures for one device. The device is registered with Card + * Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a card + * insertion event. + */ +static int if_cs_probe(struct pcmcia_device *p_dev) +{ + int ret = -ENOMEM; + wlan_private *priv; + struct if_cs_card *card; + /* CIS parsing */ + tuple_t tuple; + cisparse_t parse; + cistpl_cftable_entry_t *cfg = &parse.cftable_entry; + cistpl_io_t *io = &cfg->io; + u_char buf[64]; + + lbs_deb_enter(LBS_DEB_CS); + + card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); + if (!card) { + lbs_pr_err("error in kzalloc\n"); + goto out; + } + card->p_dev = p_dev; + p_dev->priv = card; + + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; + p_dev->irq.Handler = NULL; + p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + + p_dev->conf.Attributes = 0; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 || + (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 || + (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0) + { + lbs_pr_err("error in pcmcia_get_first_tuple etc\n"); + goto out1; + } + + p_dev->conf.ConfigIndex = cfg->index; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1) { + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + } + + /* IO window settings */ + if (cfg->io.nwin != 1) { + lbs_pr_err("wrong CIS (check number of IO windows)\n"); + ret = -ENODEV; + goto out1; + } + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + + /* This reserves IO space but doesn't actually enable it */ + ret = pcmcia_request_io(p_dev, &p_dev->io); + if (ret) { + lbs_pr_err("error in pcmcia_request_io\n"); + goto out1; + } + + /* + * Allocate an interrupt line. Note that this does not assign + * a handler to the interrupt, unless the 'Handler' member of + * the irq structure is initialized. + */ + if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) { + ret = pcmcia_request_irq(p_dev, &p_dev->irq); + if (ret) { + lbs_pr_err("error in pcmcia_request_irq\n"); + goto out1; + } + } + + /* Initialize io access */ + card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1); + if (!card->iobase) { + lbs_pr_err("error in ioport_map\n"); + ret = -EIO; + goto out1; + } + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping, and putting the + * card and host interface into "Memory and IO" mode. + */ + ret = pcmcia_request_configuration(p_dev, &p_dev->conf); + if (ret) { + lbs_pr_err("error in pcmcia_request_configuration\n"); + goto out2; + } + + /* Finally, report what we've done */ + lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n", + p_dev->irq.AssignedIRQ, p_dev->io.BasePort1, + p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1); + + if_cs_enable_ints(card); + + /* Load the firmware early, before calling into libertas.ko */ + ret = if_cs_prog_helper(card); + if (ret == 0) + ret = if_cs_prog_real(card); + if (ret) + goto out2; + + /* Make this card known to the libertas driver */ + priv = libertas_add_card(card, &p_dev->dev); + if (!priv) { + ret = -ENOMEM; + goto out2; + } + + /* Store pointers to our call-back functions */ + priv->card = card; + priv->hw_register_dev = if_cs_register_dev; + priv->hw_unregister_dev = if_cs_unregister_dev; + priv->hw_prog_firmware = if_cs_prog_firmware; + priv->hw_host_to_card = if_cs_host_to_card; + priv->hw_get_int_status = if_cs_get_int_status; + priv->hw_read_event_cause = if_cs_read_event_cause; + + /* Now actually get the IRQ */ + ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt, + IRQF_SHARED, DRV_NAME, card); + if (ret) { + lbs_pr_err("error in request_irq\n"); + goto out3; + } + + /* And finally bring the card up */ + if (libertas_activate_card(priv) != 0) { + lbs_pr_err("could not activate card\n"); + goto out3; + } + + ret = 0; + goto out; + +out3: + libertas_remove_card(priv); +out2: + ioport_unmap(card->iobase); +out1: + pcmcia_disable_device(p_dev); +out: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + +/* + * This deletes a driver "instance". The device is de-registered with + * Card Services. If it has been released, all local data structures + * are freed. Otherwise, the structures will be freed when the device + * is released. + */ +static void if_cs_detach(struct pcmcia_device *p_dev) +{ + struct if_cs_card *card = p_dev->priv; + + lbs_deb_enter(LBS_DEB_CS); + + libertas_remove_card(card->priv); + if_cs_release(p_dev); + kfree(card); + + lbs_deb_leave(LBS_DEB_CS); +} + + + +/********************************************************************/ +/* Module initialization */ +/********************************************************************/ + +static struct pcmcia_device_id if_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); + + +static struct pcmcia_driver libertas_driver = { + .owner = THIS_MODULE, + .drv = { + .name = DRV_NAME, + }, + .probe = if_cs_probe, + .remove = if_cs_detach, + .id_table = if_cs_ids, +}; + + +static int __init if_cs_init(void) +{ + int ret; + + lbs_deb_enter(LBS_DEB_CS); + ret = pcmcia_register_driver(&libertas_driver); + lbs_deb_leave(LBS_DEB_CS); + return ret; +} + + +static void __exit if_cs_exit(void) +{ + lbs_deb_enter(LBS_DEB_CS); + pcmcia_unregister_driver(&libertas_driver); + lbs_deb_leave(LBS_DEB_CS); +} + + +module_init(if_cs_init); +module_exit(if_cs_exit); From 4d4ce1ad02f02e593086fabdad69953ecbd99d9c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:04:28 -0400 Subject: [PATCH 1258/2804] [PATCH] libertas: remove unused adapter->prev_XXXX variables There were just used in some debug output, but nowhere else. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 9 --------- drivers/net/wireless/libertas/dev.h | 4 ---- 2 files changed, 13 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bf672f51f163..8e99c2de1835 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -65,18 +65,9 @@ void libertas_mac_event_disconnected(wlan_private * priv) escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), adapter->curbssparams.ssid_len); - lbs_deb_cmd("previous SSID '%s', length %u\n", - escape_essid(adapter->prev_ssid, adapter->prev_ssid_len), - adapter->prev_ssid_len); adapter->connect_status = LIBERTAS_DISCONNECTED; - /* Save previous SSID and BSSID for possible reassociation */ - memcpy(&adapter->prev_ssid, &adapter->curbssparams.ssid, - IW_ESSID_MAX_SIZE); - adapter->prev_ssid_len = adapter->curbssparams.ssid_len; - memcpy(adapter->prev_bssid, adapter->curbssparams.bssid, ETH_ALEN); - /* Clear out associated SSID and BSSID since connection is * no longer valid. */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 7c565cbf8cc4..7c0ee0f9184c 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -257,10 +257,6 @@ struct _wlan_adapter { /* IW_MODE_* */ u8 mode; - u8 prev_ssid[IW_ESSID_MAX_SIZE + 1]; - u8 prev_ssid_len; - u8 prev_bssid[ETH_ALEN]; - /* Scan results list */ struct list_head network_list; struct list_head network_free_list; From fdde7084e033263f48d26d5b24ecf626aed29b5b Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:05:08 -0400 Subject: [PATCH 1259/2804] [PATCH] libertas: remove adapter->{rx,tx}antenna There was nowhere any code that used the values of those variables. This patch also removes two static functions that are now unused. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 25 ------------------------- drivers/net/wireless/libertas/cmdresp.c | 24 ------------------------ drivers/net/wireless/libertas/dev.h | 6 ------ drivers/net/wireless/libertas/main.c | 2 -- 4 files changed, 57 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index d3402e1b760b..2a5defe011e7 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -570,26 +570,6 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; - - lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_RF_ANTENNA); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + - S_DS_GEN); - - rant->action = cpu_to_le16(cmd_action); - if ((cmd_action == CMD_ACT_SET_RX) || (cmd_action == CMD_ACT_SET_TX)) { - rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf)); - } - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, struct cmd_ds_command *cmd, u16 cmd_action) @@ -1252,11 +1232,6 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); break; - case CMD_802_11_RF_ANTENNA: - ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr, - cmd_action, pdata_buf); - break; - case CMD_802_11_DATA_RATE: ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); break; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 8e99c2de1835..affb1eeb6a5e 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -383,27 +383,6 @@ static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, return 0; } -static int wlan_ret_802_11_rf_antenna(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant; - wlan_adapter *adapter = priv->adapter; - u16 action = le16_to_cpu(pAntenna->action); - - lbs_deb_enter(LBS_DEB_CMD); - if (action == CMD_ACT_GET_RX) - adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode); - - if (action == CMD_ACT_GET_TX) - adapter->txantennamode = le16_to_cpu(pAntenna->antennamode); - - lbs_deb_cmd("RF_ANT_RESP: action 0x%x, mode 0x%04x\n", - action, le16_to_cpu(pAntenna->antennamode)); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, struct cmd_ds_command *resp) { @@ -620,9 +599,6 @@ static inline int handle_cmd_response(u16 respcmd, spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET(CMD_802_11_RF_ANTENNA): - ret = wlan_ret_802_11_rf_antenna(priv, resp); - break; case CMD_RET(CMD_MAC_MULTICAST_ADR): case CMD_RET(CMD_MAC_CONTROL): diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 7c0ee0f9184c..765c0c4f641a 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -284,9 +284,6 @@ struct _wlan_adapter { /** control G rates */ u8 adhoc_grate_enabled; - u32 txantenna; - u32 rxantenna; - u32 fragthsd; u32 rtsthsd; @@ -337,9 +334,6 @@ struct _wlan_adapter { u8 wpa_ie[MAX_WPA_IE_LEN]; u8 wpa_ie_len; - u16 rxantennamode; - u16 txantennamode; - /** Requested Signal Strength*/ u16 bcn_avg_factor; u16 data_avg_factor; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 1b6b09d5f973..5b4a1343559b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1049,8 +1049,6 @@ static void wlan_init_adapter(wlan_private * priv) CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; adapter->radioon = RADIO_ON; - adapter->txantenna = RF_ANTENNA_2; - adapter->rxantenna = RF_ANTENNA_AUTO; adapter->auto_rate = 1; adapter->cur_rate = 0; From 6e22a855b27ddc0725c134cc428ee668e56ac9f8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:05:32 -0400 Subject: [PATCH 1260/2804] [PATCH] libertas: remove adapter->prescan The value 1 was assigned to it and there was nowhere any code that would have changed that to 0. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 6 ++---- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 5fdc96f289b8..ffeec2fa60ae 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -57,10 +57,8 @@ static int assoc_helper_essid(wlan_private *priv, lbs_deb_assoc("New SSID requested: '%s'\n", escape_essid(assoc_req->ssid, assoc_req->ssid_len)); if (assoc_req->mode == IW_MODE_INFRA) { - if (adapter->prescan) { - libertas_send_specific_ssid_scan(priv, assoc_req->ssid, - assoc_req->ssid_len, 0); - } + libertas_send_specific_ssid_scan(priv, assoc_req->ssid, + assoc_req->ssid_len, 0); bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid, assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 765c0c4f641a..83876a3c41ce 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -288,7 +288,6 @@ struct _wlan_adapter { u32 rtsthsd; u16 listeninterval; - u16 prescan; u8 txretrycount; /** Tx-related variables (for single packet tx) */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 5b4a1343559b..e354ebbca4b0 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1037,8 +1037,6 @@ static void wlan_init_adapter(wlan_private * priv) mutex_init(&adapter->lock); - adapter->prescan = 1; - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; From e2aa334bee4ae9fe27f26b0732c0443d2f11a8af Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:05:53 -0400 Subject: [PATCH 1261/2804] [PATCH] libertas: remove adapter->scanprobes The variable was initialized to 0 and nowhere else to anything different. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 2 -- drivers/net/wireless/libertas/scan.c | 5 ++--- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 83876a3c41ce..1dcfb05f5446 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -375,7 +375,6 @@ struct _wlan_adapter { struct wlan_offset_value offsetvalue; struct cmd_ds_802_11_get_log logmsg; - u16 scanprobes; u32 pkttxctrl; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e354ebbca4b0..1d439cd3f436 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -998,8 +998,6 @@ static void wlan_init_adapter(wlan_private * priv) wlan_adapter *adapter = priv->adapter; int i; - adapter->scanprobes = 0; - adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index f471157c02df..7e4b0ab108dc 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -416,8 +416,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, scanmode); /* Set the number of probes to send, use adapter setting if unset */ - numprobes = (puserscanin->numprobes ? puserscanin->numprobes : - adapter->scanprobes); + numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0; /* * Set the BSSID filter to the incoming configuration, @@ -450,7 +449,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, } } else { pscancfgout->bsstype = adapter->scanmode; - numprobes = adapter->scanprobes; + numprobes = 0; } /* If the input config or adapter has the number of Probes set, add tlv */ From fcff0e0856351b201016cd9267cadcf6a8e988d5 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:06:11 -0400 Subject: [PATCH 1262/2804] [PATCH] libertas: remove adapter->pkttxctrl The variable was initialized to 0 and nowhere else changed, so basically the per-packet TX control wasn't used. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/main.c | 1 - drivers/net/wireless/libertas/tx.c | 5 ----- 3 files changed, 8 deletions(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 1dcfb05f5446..aad92ded730e 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -376,8 +376,6 @@ struct _wlan_adapter { struct cmd_ds_802_11_get_log logmsg; - u32 pkttxctrl; - u16 txrate; u32 linkmode; u32 radiomode; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 1d439cd3f436..da418dbe8865 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1067,7 +1067,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->intcounter = 0; adapter->currenttxskb = NULL; - adapter->pkttxctrl = 0; memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); adapter->tx_queue_idx = 0; diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 56d84027ec2b..bb6e17506a41 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -58,7 +58,6 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) */ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) { - wlan_adapter *adapter = priv->adapter; int ret = 0; struct txpd localtxpd; struct txpd *plocaltxpd = &localtxpd; @@ -86,9 +85,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) /* offset of actual data */ plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); - /* TxCtrl set by user or default */ - plocaltxpd->tx_control = cpu_to_le32(adapter->pkttxctrl); - p802x_hdr = skb->data; if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { @@ -99,7 +95,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate); if (new_rate != 0) { /* use new tx_control[4:0] */ - new_rate |= (adapter->pkttxctrl & ~0x1f); plocaltxpd->tx_control = cpu_to_le32(new_rate); } From b20c520763a6fe1aabde27f6ba017a67f22f90d5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:06:54 -0400 Subject: [PATCH 1263/2804] [PATCH] libertas: fix WEXT quality reporting Found by Ronak and others at Marvell. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index e8c0629f9a4b..7d14f9c2aff6 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -949,7 +949,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure); /* Calculate quality */ - priv->wstats.qual.qual = max(quality, (u32)100); + priv->wstats.qual.qual = min_t(u32, quality, 100); priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; stats_valid = 1; From cad9d9b17a4ab80da1593de004a1163b359de268 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:07:15 -0400 Subject: [PATCH 1264/2804] [PATCH] libertas: remove adapter->txrate The value of txrate was only set by a CMD_802_11_TX_RATE_QUERY command, but there was no code in the driver that ever issued this command. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 7 ------- drivers/net/wireless/libertas/cmdresp.c | 3 --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/wext.c | 2 +- 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 2a5defe011e7..0da013f3b0d8 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1368,13 +1368,6 @@ int libertas_prepare_and_send_command(wlan_private * priv, S_DS_GEN); ret = 0; break; - case CMD_802_11_TX_RATE_QUERY: - cmdptr->command = cpu_to_le16(CMD_802_11_TX_RATE_QUERY); - cmdptr->size = cpu_to_le16(sizeof(struct cmd_tx_rate_query) + - S_DS_GEN); - adapter->txrate = 0; - ret = 0; - break; default: lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index affb1eeb6a5e..e91d819555eb 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -702,9 +702,6 @@ static inline int handle_cmd_response(u16 respcmd, memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh, sizeof(resp->params.mesh)); break; - case CMD_RET(CMD_802_11_TX_RATE_QUERY): - priv->adapter->txrate = resp->params.txrate.txrate; - break; default: lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", resp->command); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index aad92ded730e..9e18f012333c 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -376,7 +376,6 @@ struct _wlan_adapter { struct cmd_ds_802_11_get_log logmsg; - u16 txrate; u32 linkmode; u32 radiomode; u8 fw_ready; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 7d14f9c2aff6..1fb0f91e538a 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -949,7 +949,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure); /* Calculate quality */ - priv->wstats.qual.qual = min_t(u32, quality, 100); + priv->wstats.qual.qual = min_t(u8, quality, 100); priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; stats_valid = 1; From caef47a0dc2b17ea6fb0119d3678b4b21ae70daa Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:07:56 -0400 Subject: [PATCH 1265/2804] [PATCH] libertas: remove adapter->rxpd_rate No code uses the contents of this variable, so it can go. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 1 - drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/rx.c | 2 -- 3 files changed, 4 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index e91d819555eb..7aec0d4e20f9 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -60,7 +60,6 @@ void libertas_mac_event_disconnected(wlan_private * priv) memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); adapter->nextSNRNF = 0; adapter->numSNRNF = 0; - adapter->rxpd_rate = 0; lbs_deb_cmd("current SSID '%s', length %u\n", escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 9e18f012333c..850518e9cbcb 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -343,7 +343,6 @@ struct _wlan_adapter { u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; u16 nextSNRNF; u16 numSNRNF; - u16 rxpd_rate; u8 radioon; u32 preamble; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 25d45c646d71..2473931f8151 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -117,8 +117,6 @@ static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd) adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; wlan_save_rawSNRNF(priv, p_rx_pd); - adapter->rxpd_rate = p_rx_pd->rx_rate; - adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE; adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE; lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n", From a783f1ee5b112a0258762877ec7c1ce8810f3cd8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:08:24 -0400 Subject: [PATCH 1266/2804] [PATCH] libertas: remove adapter->{data,bcn}_avg_factor Those two variables were initialized with some default values, but there is no code that would ever change them. So we could use as well the defaults directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/main.c | 3 --- drivers/net/wireless/libertas/rx.c | 4 ++-- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 0da013f3b0d8..72e76e4ec7a9 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -671,7 +671,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RSSI); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); - cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor); + cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); /* reset Beacon SNR/NF/RSSI values */ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 850518e9cbcb..76234000e5bc 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -334,8 +334,6 @@ struct _wlan_adapter { u8 wpa_ie_len; /** Requested Signal Strength*/ - u16 bcn_avg_factor; - u16 data_avg_factor; u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index da418dbe8865..6ba3fa498e99 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -998,9 +998,6 @@ static void wlan_init_adapter(wlan_private * priv) wlan_adapter *adapter = priv->adapter; int i; - adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; - adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; - /* ATIM params */ adapter->atimwindow = 0; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 2473931f8151..83a7765fd23c 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -85,12 +85,12 @@ static u8 wlan_getavgnf(wlan_private * priv) static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd) { wlan_adapter *adapter = priv->adapter; - if (adapter->numSNRNF < adapter->data_avg_factor) + if (adapter->numSNRNF < DEFAULT_DATA_AVG_FACTOR) adapter->numSNRNF++; adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr; adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf; adapter->nextSNRNF++; - if (adapter->nextSNRNF >= adapter->data_avg_factor) + if (adapter->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR) adapter->nextSNRNF = 0; return; } From 97605c3eb3dee943a45584be92c46be1305b3ef5 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:09:15 -0400 Subject: [PATCH 1267/2804] [PATCH] libertas: remove adapter->nullpktinterval No code ever initialized this variable, so it was 0 because of kzalloc(). But no other code changes it, making it rather useless. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 3 +-- drivers/net/wireless/libertas/dev.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 72e76e4ec7a9..f5d4971f13a0 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -73,8 +73,7 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, psm->locallisteninterval = cpu_to_le16(adapter->locallisteninterval); - psm->nullpktinterval = - cpu_to_le16(adapter->nullpktinterval); + psm->nullpktinterval = 0; psm->multipledtim = cpu_to_le16(priv->adapter->multipledtim); break; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 76234000e5bc..6e78e315a8b3 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -313,7 +313,6 @@ struct _wlan_adapter { struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; u16 locallisteninterval; - u16 nullpktinterval; struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; From 252cf0d10f76d3edcd808d462dcfbd544875a0be Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:09:34 -0400 Subject: [PATCH 1268/2804] [PATCH] libertas: remove adapter->locallisteninterval locallisteninterval was initialized with 0, but there is no code that changes it, rendering it rather useless. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 +----- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index f5d4971f13a0..276d981e7d3d 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -56,7 +56,6 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, u16 cmd_action) { struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); @@ -68,11 +67,8 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, switch (cmd_action) { case CMD_SUBCMD_ENTER_PS: lbs_deb_cmd("PS command:" "SubCode- Enter PS\n"); - lbs_deb_cmd("locallisteninterval %d\n", - adapter->locallisteninterval); - psm->locallisteninterval = - cpu_to_le16(adapter->locallisteninterval); + psm->locallisteninterval = 0; psm->nullpktinterval = 0; psm->multipledtim = cpu_to_le16(priv->adapter->multipledtim); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 6e78e315a8b3..cf4ed5d01458 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -312,7 +312,6 @@ struct _wlan_adapter { u8 needtowakeup; struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; - u16 locallisteninterval; struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 6ba3fa498e99..c35605acf820 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1059,7 +1059,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->psstate = PS_STATE_FULL_POWER; adapter->needtowakeup = 0; - adapter->locallisteninterval = 0; /* default value in firmware will be used */ adapter->intcounter = 0; From 56c4656e84d068ecc4da670799216e5b2aaee50e Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:09:49 -0400 Subject: [PATCH 1269/2804] [PATCH] libertas: remove adapter->multipledtim multipledtim was initialized with MRVDRV_DEFAULT_MULTIPLE_DTIM and then kept at that value, so we could use that define directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 276d981e7d3d..517489a06063 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -71,7 +71,7 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, psm->locallisteninterval = 0; psm->nullpktinterval = 0; psm->multipledtim = - cpu_to_le16(priv->adapter->multipledtim); + cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM); break; case CMD_SUBCMD_EXIT_PS: diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index cf4ed5d01458..0f383e3f6f06 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -307,7 +307,6 @@ struct _wlan_adapter { u16 psmode; /* Wlan802_11PowermodeCAM=disable Wlan802_11PowermodeMAX_PSP=enable */ - u16 multipledtim; u32 psstate; u8 needtowakeup; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index c35605acf820..df06d40ffdea 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1053,7 +1053,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; adapter->psmode = WLAN802_11POWERMODECAM; - adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; From ae596ce2f77d1542fe44ea483bd0ca7f61baeccd Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:10:05 -0400 Subject: [PATCH 1270/2804] [PATCH] libertas: remove adapter->atimwindow This varaible was initialized with 0 but there is no code that would ever change it's value. So it can go away. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/join.c | 2 +- drivers/net/wireless/libertas/main.c | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 0f383e3f6f06..693058ad0239 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -303,7 +303,6 @@ struct _wlan_adapter { /** POWER MANAGEMENT AND PnP SUPPORT */ u8 surpriseremoved; - u16 atimwindow; u16 psmode; /* Wlan802_11PowermodeCAM=disable Wlan802_11PowermodeMAX_PSP=enable */ diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 08034917d4b5..0bded0c91495 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -518,7 +518,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; - adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow); + adhs->ssparamset.ibssparamset.atimwindow = 0; /* set capability info */ tmpcap = WLAN_CAPABILITY_IBSS; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index df06d40ffdea..d227e453f984 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -998,9 +998,6 @@ static void wlan_init_adapter(wlan_private * priv) wlan_adapter *adapter = priv->adapter; int i; - /* ATIM params */ - adapter->atimwindow = 0; - adapter->connect_status = LIBERTAS_DISCONNECTED; memset(adapter->current_addr, 0xff, ETH_ALEN); From 956deb867a97ac137c164a5d2d12b0c82fb6776d Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:10:41 -0400 Subject: [PATCH 1271/2804] [PATCH] libertas: remove adapter->regiontableindex The value was computed, but then never used. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 2 -- drivers/net/wireless/libertas/dev.h | 1 - 2 files changed, 3 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 7aec0d4e20f9..53671e96b043 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -179,7 +179,6 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { /* use the region code to search for the index */ if (adapter->regioncode == libertas_region_code_to_index[i]) { - adapter->regiontableindex = (u16) i; break; } } @@ -187,7 +186,6 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, /* if it's unidentified region code, use the default (USA) */ if (i >= MRVDRV_MAX_REGION_CODE) { adapter->regioncode = 0x10; - adapter->regiontableindex = 0; lbs_pr_info("unidentified region code; using the default (USA)\n"); } diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 693058ad0239..16e7ec11425b 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -298,7 +298,6 @@ struct _wlan_adapter { u16 currentpacketfilter; u32 connect_status; u16 regioncode; - u16 regiontableindex; u16 txpowerlevel; /** POWER MANAGEMENT AND PnP SUPPORT */ From 0aabc0a5d5657df254255c9049a97cc96229bcba Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:10:59 -0400 Subject: [PATCH 1272/2804] [PATCH] libertas: remove adapter->listeninterval listeninterval was initialized with MRVDRV_DEFAULT_LISTEN_INTERVAL, but there exists that would ever change it. So we can use this define directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/join.c | 2 +- drivers/net/wireless/libertas/main.c | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 16e7ec11425b..4738afa61e33 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -287,7 +287,6 @@ struct _wlan_adapter { u32 fragthsd; u32 rtsthsd; - u16 listeninterval; u8 txretrycount; /** Tx-related variables (for single packet tx) */ diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 0bded0c91495..e335a7e4adaa 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -369,7 +369,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, pos += sizeof(passo->peerstaaddr); /* set the listen interval */ - passo->listeninterval = cpu_to_le16(adapter->listeninterval); + passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); pos += sizeof(passo->capability); pos += sizeof(passo->listeninterval); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index d227e453f984..d3316e413465 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1051,8 +1051,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->psmode = WLAN802_11POWERMODECAM; - adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; - adapter->psstate = PS_STATE_FULL_POWER; adapter->needtowakeup = 0; From 85c93e5189b7402b4f9f4324c284bb91e8e8fb85 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:11:19 -0400 Subject: [PATCH 1273/2804] [PATCH] libertas: remove adapter->adhoc_grate_enabled The variable was initialized with 0 (false). There is no code that would ever change it, so we can use the false-patch directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/join.c | 9 ++------- drivers/net/wireless/libertas/main.c | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 4738afa61e33..90e9405903ba 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -281,8 +281,6 @@ struct _wlan_adapter { u16 enablehwauto; u16 ratebitmap; - /** control G rates */ - u8 adhoc_grate_enabled; u32 fragthsd; u32 rtsthsd; diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index e335a7e4adaa..95c21bae60f5 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -534,13 +534,8 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); memset(adhs->rates, 0, sizeof(adhs->rates)); - if (adapter->adhoc_grate_enabled) { - ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates)); - memcpy(adhs->rates, libertas_bg_rates, ratesize); - } else { - ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b)); - memcpy(adhs->rates, adhoc_rates_b, ratesize); - } + ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b)); + memcpy(adhs->rates, adhoc_rates_b, ratesize); /* Copy the ad-hoc creating rates into Current BSS state structure */ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index d3316e413465..ab8dcbf5bfc9 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1042,7 +1042,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->auto_rate = 1; adapter->cur_rate = 0; - adapter->adhoc_grate_enabled = 0; adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; From 2c85103da3c88a06a7c01eece709482d85eff07f Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:11:38 -0400 Subject: [PATCH 1274/2804] [PATCH] libertas: remove adapter->beaconperiod beaconperiod was initialized with MRVDRV_BEACON_INTERVAL, but there is no code that would ever change it's value. We can use the define directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/join.c | 2 +- drivers/net/wireless/libertas/main.c | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 90e9405903ba..602a93e88925 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -265,7 +265,6 @@ struct _wlan_adapter { u8 scantype; u32 scanmode; - u16 beaconperiod; u8 adhoccreate; /** capability Info used in Association, start, join */ diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 95c21bae60f5..c16d1f625d1b 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -496,7 +496,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, /* set the BSS type */ adhs->bsstype = CMD_BSS_TYPE_IBSS; adapter->mode = IW_MODE_ADHOC; - adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod); + adhs->beaconperiod = cpu_to_le16(MRVDRV_BEACON_INTERVAL); /* set Physical param set */ #define DS_PARA_IE_ID 3 diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ab8dcbf5bfc9..1c8760ca8644 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1043,8 +1043,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->auto_rate = 1; adapter->cur_rate = 0; - adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; - // set default capabilities adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; From d65ead886a193682f88b07aaf11d46127735a2b5 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:12:12 -0400 Subject: [PATCH 1275/2804] [PATCH] libertas: remove adapter->scanmode scanmode was initialized with CMD_BSS_TYPE_ANY, but there is no code that ever can store another value there, so it can go away. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 3 --- drivers/net/wireless/libertas/scan.c | 6 ++---- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 602a93e88925..a33c523d0e98 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -263,7 +263,6 @@ struct _wlan_adapter { struct bss_descriptor *networks; u8 scantype; - u32 scanmode; u8 adhoccreate; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 1c8760ca8644..7845cc346af0 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1004,9 +1004,6 @@ static void wlan_init_adapter(wlan_private * priv) /* scan type */ adapter->scantype = CMD_SCAN_TYPE_ACTIVE; - /* scan mode */ - adapter->scanmode = CMD_BSS_TYPE_ANY; - /* 802.11 specific */ adapter->secinfo.wep_enabled = 0; for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 7e4b0ab108dc..33ee459315a9 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -361,7 +361,6 @@ wlan_scan_setup_scan_config(wlan_private * priv, u8 * pfilteredscan, u8 * pscancurrentonly) { - wlan_adapter *adapter = priv->adapter; struct mrvlietypes_numprobes *pnumprobestlv; struct mrvlietypes_ssidparamset *pssidtlv; struct wlan_scan_cmd_config * pscancfgout = NULL; @@ -412,8 +411,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, /* Set the bss type scan filter, use adapter setting if unset */ pscancfgout->bsstype = - (puserscanin->bsstype ? puserscanin->bsstype : adapter-> - scanmode); + puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY; /* Set the number of probes to send, use adapter setting if unset */ numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0; @@ -448,7 +446,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, *pfilteredscan = 1; } } else { - pscancfgout->bsstype = adapter->scanmode; + pscancfgout->bsstype = CMD_BSS_TYPE_ANY; numprobes = 0; } From 4f2fdaaf0e4209bff3b18dc14c915b61f5fa5cd2 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:12:27 -0400 Subject: [PATCH 1276/2804] [PATCH] libertas: remove adapter->scantype scantype was initialized with CMD_SCAN_TYPE_ACTIVE, but there is no code that would ever change it, so we can use that variable directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/main.c | 3 --- drivers/net/wireless/libertas/scan.c | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index a33c523d0e98..f6b1402509f5 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -262,8 +262,6 @@ struct _wlan_adapter { struct list_head network_free_list; struct bss_descriptor *networks; - u8 scantype; - u8 adhoccreate; /** capability Info used in Association, start, join */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 7845cc346af0..9ccc9524153b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1001,9 +1001,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->connect_status = LIBERTAS_DISCONNECTED; memset(adapter->current_addr, 0xff, ETH_ALEN); - /* scan type */ - adapter->scantype = CMD_SCAN_TYPE_ACTIVE; - /* 802.11 specific */ adapter->secinfo.wep_enabled = 0; for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 33ee459315a9..4f621a6ec976 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -252,7 +252,7 @@ static void wlan_scan_create_channel_list(wlan_private * priv, * be changed to passive on a per channel basis if restricted by * regulatory requirements (11d or 11h) */ - scantype = adapter->scantype; + scantype = CMD_SCAN_TYPE_ACTIVE; for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { if (priv->adapter->enable11d && From a2235ed40210081e51bec4bb1be64e4b3511501e Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:12:45 -0400 Subject: [PATCH 1277/2804] [PATCH] libertas: remove bss_descriptior->networktsf This value was parsed out, but then nowhere used ... except in some debugfs output. I can't imagine anyone wanting to use this value for anything real (as no other driver exports it), so bye-bye. Along this, made the columns of /sys/kernel/debug/libertas_wireless/*/getscantable align again. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 7 ++- drivers/net/wireless/libertas/scan.c | 69 ------------------------- drivers/net/wireless/libertas/scan.h | 4 +- 3 files changed, 5 insertions(+), 75 deletions(-) diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 4b9533a66511..63e747ac49d0 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -66,7 +66,7 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, - "# | ch | ss | bssid | cap | TSF | Qual | SSID \n"); + "# | ch | rssi | bssid | cap | Qual | SSID \n"); mutex_lock(&priv->adapter->lock); list_for_each_entry (iter_bss, &priv->adapter->network_list, list) { @@ -75,15 +75,14 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %03ld | " MAC_FMT " |", + "%02u| %03d | %04ld | " MAC_FMT " |", numscansdone, iter_bss->channel, iter_bss->rssi, MAC_ARG(iter_bss->bssid)); pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", ibss ? 'A' : 'I', privacy ? 'P' : ' ', spectrum_mgmt ? 'S' : ' '); - pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf); - pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi)); + pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", escape_essid(iter_bss->ssid, iter_bss->ssid_len)); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 4f621a6ec976..aea2e90b5558 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -836,58 +836,6 @@ out: return ret; } -/** - * @brief Inspect the scan response buffer for pointers to expected TLVs - * - * TLVs can be included at the end of the scan response BSS information. - * Parse the data in the buffer for pointers to TLVs that can potentially - * be passed back in the response - * - * @param ptlv Pointer to the start of the TLV buffer to parse - * @param tlvbufsize size of the TLV buffer - * @param ptsftlv Output parameter: Pointer to the TSF TLV if found - * - * @return void - */ -static -void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, - int tlvbufsize, - struct mrvlietypes_tsftimestamp ** ptsftlv) -{ - struct mrvlietypes_data *pcurrenttlv; - int tlvbufleft; - u16 tlvtype; - u16 tlvlen; - - pcurrenttlv = ptlv; - tlvbufleft = tlvbufsize; - *ptsftlv = NULL; - - lbs_deb_scan("SCAN_RESP: tlvbufsize = %d\n", tlvbufsize); - lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); - - while (tlvbufleft >= sizeof(struct mrvlietypesheader)) { - tlvtype = le16_to_cpu(pcurrenttlv->header.type); - tlvlen = le16_to_cpu(pcurrenttlv->header.len); - - switch (tlvtype) { - case TLV_TYPE_TSFTIMESTAMP: - *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv; - break; - - default: - lbs_deb_scan("SCAN_RESP: Unhandled TLV = %d\n", - tlvtype); - /* Give up, this seems corrupted */ - return; - } /* switch */ - - tlvbufleft -= (sizeof(ptlv->header) + tlvlen); - pcurrenttlv = - (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen); - } /* while */ -} - /** * @brief Interpret a BSS scan response returned from the firmware * @@ -1684,8 +1632,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) { wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_scan_rsp *pscan; - struct mrvlietypes_data *ptlv; - struct mrvlietypes_tsftimestamp *ptsftlv; struct bss_descriptor * iter_bss; struct bss_descriptor * safe; u8 *pbssinfo; @@ -1734,11 +1680,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) + sizeof(pscan->nr_sets) + S_DS_GEN); - ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft); - - /* Search the TLV buffer space in the scan response for any valid TLVs */ - wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv); - /* * Process each scan response returned (pscan->nr_sets). Save * the information in the newbssentry and then insert into the @@ -1791,16 +1732,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) new.bssid[0], new.bssid[1], new.bssid[2], new.bssid[3], new.bssid[4], new.bssid[5]); - /* - * If the TSF TLV was appended to the scan results, save the - * this entries TSF value in the networktsf field. The - * networktsf is the firmware's TSF value at the time the - * beacon or probe response was received. - */ - if (ptsftlv) { - new.networktsf = le64_to_cpup(&ptsftlv->tsftable[idx]); - } - /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); } diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index def0db5c4e61..28decf391531 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -151,7 +151,9 @@ struct bss_descriptor { u32 atimwindow; + /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ u8 mode; + /* zero-terminated array of supported data rates */ u8 rates[MAX_RATES + 1]; @@ -161,8 +163,6 @@ struct bss_descriptor { union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; - u64 networktsf; //!< TSF timestamp from the current firmware TSF - struct ieeetypes_countryinfofullset countryinfo; u8 wpa_ie[MAX_WPA_IE_LEN]; From bee093d6132569eee13b2c45058b550c9544a5b8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:13:00 -0400 Subject: [PATCH 1278/2804] [PATCH] libertas: remove bss_descriptor->timestamp Noone used this variable. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/scan.c | 1 - drivers/net/wireless/libertas/scan.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index aea2e90b5558..5c730b9d956c 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -903,7 +903,6 @@ static int libertas_process_bss(struct bss_descriptor * bss, pos++; /* time stamp is 8 bytes long */ - bss->timestamp = le64_to_cpup((void *) pos); pos += 8; /* beacon interval is 2 bytes long */ diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 28decf391531..9bb1a435c28a 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -157,7 +157,6 @@ struct bss_descriptor { /* zero-terminated array of supported data rates */ u8 rates[MAX_RATES + 1]; - __le64 timestamp; //!< TSF value included in the beacon/probe response unsigned long last_scanned; union ieeetypes_phyparamset phyparamset; From 9556d2120ceecc158b324fa01e30704ff9f42ae3 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:14:07 -0400 Subject: [PATCH 1279/2804] [PATCH] libertas: fix two debug statements in cmdresp.c Purely cosmetic: this moves an lbs_deb_enter() to the proper place and changes an erraneous lbs_deb_enter_args() into lbs_deb_leave_args() Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 53671e96b043..93bf63bad0f6 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -867,12 +867,12 @@ int libertas_process_event(wlan_private * priv) wlan_adapter *adapter = priv->adapter; u32 eventcause; + lbs_deb_enter(LBS_DEB_CMD); + spin_lock_irq(&adapter->driver_lock); eventcause = adapter->eventcause; spin_unlock_irq(&adapter->driver_lock); - lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("event cause 0x%x\n", eventcause); switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { @@ -988,6 +988,6 @@ int libertas_process_event(wlan_private * priv) adapter->eventcause = 0; spin_unlock_irq(&adapter->driver_lock); - lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } From 0edef215e405fef3c6569511a9aebeeb3f6cd799 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:14:29 -0400 Subject: [PATCH 1280/2804] [PATCH] libertas: send association events on adhoc reassociation Send association event to userspace when reassociating to the same ad-hoc network, because it's still an association. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index c16d1f625d1b..0ebf2f8acbf1 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -209,15 +209,26 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso bss->ssid_len); /* check if the requested SSID is already joined */ - if (adapter->curbssparams.ssid_len + if ( adapter->curbssparams.ssid_len && !libertas_ssid_cmp(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len, bss->ssid, bss->ssid_len) - && (adapter->mode == IW_MODE_ADHOC)) { - lbs_deb_join( - "ADHOC_J_CMD: New ad-hoc SSID is the same as current, " - "not attempting to re-join"); - return -1; + && (adapter->mode == IW_MODE_ADHOC) + && (adapter->connect_status == LIBERTAS_CONNECTED)) { + union iwreq_data wrqu; + + lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as " + "current, not attempting to re-join"); + + /* Send the re-association event though, because the association + * request really was successful, even if just a null-op. + */ + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, + ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + goto out; } /* Use shortpreamble only when both creator and card supports @@ -242,6 +253,7 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso 0, CMD_OPTION_WAITFORRSP, OID_802_11_SSID, assoc_req); +out: return ret; } From 00af0157e0a603e2a2ce0896179f2dd43f0f28ab Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:14:56 -0400 Subject: [PATCH 1281/2804] [PATCH] libertas: push mesh beacon bit to userspace in scan results Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/scan.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 5c730b9d956c..8d4e1ee27395 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1334,6 +1334,8 @@ out: return ret; } +#define MAX_CUSTOM_LEN 64 + static inline char *libertas_translate_scan(wlan_private *priv, char *start, char *stop, struct bss_descriptor *bss) @@ -1467,6 +1469,18 @@ static inline char *libertas_translate_scan(wlan_private *priv, start = iwe_stream_add_point(start, stop, &iwe, buf); } + if (bss->mesh) { + char custom[MAX_CUSTOM_LEN]; + char *p = custom; + + iwe.cmd = IWEVCUSTOM; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + "mesh-type: olpc"); + iwe.u.data.length = p - custom; + if (iwe.u.data.length) + start = iwe_stream_add_point(start, stop, &iwe, custom); + } + return start; } From b37e5842f5ab66f8d0533ee62ffe35c26ae800a3 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 13:15:40 -0400 Subject: [PATCH 1282/2804] [PATCH] libertas: revert CAPINFO_MASK to its original value CAPINFO_MASK changed on commits 981f187b and a091095b. Reverting to the original value. Also move CAPINFO_MASK into the sole user, join.c. CAPINFO_MASK should be in host CPU byte order; capability is converted to device byte order elsewhere. This fixes OLPC ticket #2161 Signed-off-by: Luis Carlos Cobo Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 4 ++++ drivers/net/wireless/libertas/types.h | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 0ebf2f8acbf1..ccb0df1967fb 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -20,6 +20,10 @@ /* Supported rates for ad-hoc B mode */ static u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; +/* The firmware needs certain bits masked out of the beacon-derviced capability + * field when associating/joining to BSSs. + */ +#define CAPINFO_MASK (~(0xda00)) /** * @brief This function finds common rates between rate1 and card rates. diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 2df352db1557..a43a5f63c879 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -7,8 +7,6 @@ #include #include -#define CAPINFO_MASK (~(0x00da)) - struct ieeetypes_cfparamset { u8 elementid; u8 len; From d21b31fd53626f9c1d14fc676793dbe86b44d1c6 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 13:16:02 -0400 Subject: [PATCH 1283/2804] [PATCH] libertas: keep mesh autostart enabled while asleep After loading the firmware, mesh autostart will be disabled. After that, the user will still be able to enable or disable it at will. On suspend, it will be always activated and later on resume it will go back to the state it had before going to sleep. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/if_usb.c | 26 ++++++++++++++++++++++++++ drivers/net/wireless/libertas/main.c | 23 ++++++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f6b1402509f5..397c5fca0ff5 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -103,6 +103,7 @@ struct _wlan_private { int open; int mesh_open; int infra_open; + int mesh_autostart_enabled; char name[DEV_NAME_LEN]; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 5efdeac6e208..670e1d23c043 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -990,6 +990,19 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) if (priv->adapter->psstate != PS_STATE_FULL_POWER) return -1; + if (priv->mesh_dev && !priv->mesh_autostart_enabled) { + /* Mesh autostart must be activated while sleeping + * On resume it will go back to the current state + */ + struct cmd_ds_mesh_access mesh_access; + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(1); + libertas_prepare_and_send_command(priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + } + netif_device_detach(cardp->eth_dev); netif_device_detach(priv->mesh_dev); @@ -1017,6 +1030,19 @@ static int if_usb_resume(struct usb_interface *intf) netif_device_attach(cardp->eth_dev); netif_device_attach(priv->mesh_dev); + if (priv->mesh_dev && !priv->mesh_autostart_enabled) { + /* Mesh autostart was activated while sleeping + * Disable it if appropriate + */ + struct cmd_ds_mesh_access mesh_access; + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(0); + libertas_prepare_and_send_command(priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + } + lbs_deb_leave(LBS_DEB_USB); return 0; } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 9ccc9524153b..a3a17caae439 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -271,15 +271,20 @@ static ssize_t libertas_autostart_enabled_set(struct device * dev, { struct cmd_ds_mesh_access mesh_access; uint32_t datum; + wlan_private * priv = (to_net_dev(dev))->priv; + int ret; memset(&mesh_access, 0, sizeof(mesh_access)); sscanf(buf, "%d", &datum); mesh_access.data[0] = cpu_to_le32(datum); - libertas_prepare_and_send_command((to_net_dev(dev))->priv, + ret = libertas_prepare_and_send_command(priv, CMD_MESH_ACCESS, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + if (ret == 0) + priv->mesh_autostart_enabled = datum ? 1 : 0; + return strlen(buf); } @@ -853,6 +858,7 @@ static int wlan_setup_station_hw(wlan_private * priv) { int ret = -1; wlan_adapter *adapter = priv->adapter; + struct cmd_ds_mesh_access mesh_access; lbs_deb_enter(LBS_DEB_FW); @@ -889,6 +895,21 @@ static int wlan_setup_station_hw(wlan_private * priv) goto done; } + /* Disable mesh autostart */ + if (priv->mesh_dev) { + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(0); + ret = libertas_prepare_and_send_command(priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + if (ret) { + ret = -1; + goto done; + } + priv->mesh_autostart_enabled = 0; + } + ret = 0; done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); From 9483f03150cbfa1f706355b7f9d218d6086c6fce Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Thu, 2 Aug 2007 13:16:30 -0400 Subject: [PATCH 1284/2804] [PATCH] libertas: fix a few wext abuses... o SIOCGIWNAME is not designed to return the version number of the driver. On the other hand, you are free to abuse SIOCGIWNICKN for that purpose. o Don't attempt to fix the WE19/WE20 transition in the driver, because your fixes are bogus, and redundant with the code in the kernel (you may endup with +2, you can't read 32 char ESSID...). o In SIOCSIWTXPOW, if you specified in iwrange that you want dBm, you should only get dBm, which allow to reduce code bloat. Signed-off-by: Jean Tourrilhes Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 120 ++++++--------------------- 1 file changed, 27 insertions(+), 93 deletions(-) diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 1fb0f91e538a..15395bf0a2ac 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -21,52 +21,6 @@ #include "assoc.h" -/** - * @brief Convert mw value to dbm value - * - * @param mw the value of mw - * @return the value of dbm - */ -static int mw_to_dbm(int mw) -{ - if (mw < 2) - return 0; - else if (mw < 3) - return 3; - else if (mw < 4) - return 5; - else if (mw < 6) - return 7; - else if (mw < 7) - return 8; - else if (mw < 8) - return 9; - else if (mw < 10) - return 10; - else if (mw < 13) - return 11; - else if (mw < 16) - return 12; - else if (mw < 20) - return 13; - else if (mw < 25) - return 14; - else if (mw < 32) - return 15; - else if (mw < 40) - return 16; - else if (mw < 50) - return 17; - else if (mw < 63) - return 18; - else if (mw < 79) - return 19; - else if (mw < 100) - return 20; - else - return 21; -} - /** * @brief Find the channel frequency power info with specific channel * @@ -199,28 +153,11 @@ static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates) static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, char *cwrq, char *extra) { - const char *cp; - char comm[6] = { "COMM-" }; - char mrvl[6] = { "MRVL-" }; - int cnt; lbs_deb_enter(LBS_DEB_WEXT); - strcpy(cwrq, mrvl); - - cp = strstr(libertas_driver_version, comm); - if (cp == libertas_driver_version) //skip leading "COMM-" - cp = libertas_driver_version + strlen(comm); - else - cp = libertas_driver_version; - - cnt = strlen(mrvl); - cwrq += cnt; - while (cnt < 16 && (*cp != '-')) { - *cwrq++ = toupper(*cp++); - cnt++; - } - *cwrq = '\0'; + /* We could add support for 802.11n here as needed. Jean II */ + snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g"); lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -300,29 +237,37 @@ static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + const char *cp; + char comm[6] = { "COMM-" }; + char mrvl[6] = { "MRVL-" }; + int cnt; lbs_deb_enter(LBS_DEB_WEXT); /* - * Get the Nick Name saved + * Nick Name is not used internally in this mode, + * therefore return something useful instead. Jean II */ - mutex_lock(&adapter->lock); - strncpy(extra, adapter->nodename, 16); - mutex_unlock(&adapter->lock); + strcpy(extra, mrvl); - extra[16] = '\0'; + cp = strstr(libertas_driver_version, comm); + if (cp == libertas_driver_version) //skip leading "COMM-" + cp = libertas_driver_version + strlen(comm); + else + cp = libertas_driver_version; - /* - * If none, we may want to get the one that was set - */ + cnt = strlen(mrvl); + extra += cnt; + while (cnt < 16 && (*cp != '-')) { + *extra++ = toupper(*cp++); + cnt++; + } /* * Push it out ! */ - dwrq->length = strlen(extra) + 1; + dwrq->length = cnt; lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -341,12 +286,12 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, if (adapter->connect_status == LIBERTAS_CONNECTED) { strncpy(extra, "Mesh", 12); extra[12] = '\0'; - dwrq->length = strlen(extra) + 1; + dwrq->length = strlen(extra); } else { extra[0] = '\0'; - dwrq->length = 1 ; + dwrq->length = 0; } lbs_deb_leave(LBS_DEB_WEXT); @@ -1897,8 +1842,10 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, wlan_radio_ioctl(priv, RADIO_ON); + /* Userspace check in iwrange if it should use dBm or mW, + * therefore this should never happen... Jean II */ if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { - dbm = (u16) mw_to_dbm(vwrq->value); + return -EOPNOTSUPP; } else dbm = (u16) vwrq->value; @@ -1946,12 +1893,7 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, * If none, we may want to get the one that was set */ - /* To make the driver backward compatible with WPA supplicant v0.2.4 */ - if (dwrq->length == 32) /* check with WPA supplicant buffer size */ - dwrq->length = min_t(size_t, adapter->curbssparams.ssid_len, - IW_ESSID_MAX_SIZE); - else - dwrq->length = adapter->curbssparams.ssid_len + 1; + dwrq->length = adapter->curbssparams.ssid_len; dwrq->flags = 1; /* active */ @@ -1972,14 +1914,6 @@ static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - /* - * WE-20 and earlier NULL pad the end of the SSID and increment - * SSID length so it can be used like a string. WE-21 and later don't, - * but some userspace tools aren't able to cope with the change. - */ - if ((in_ssid_len > 0) && (extra[in_ssid_len - 1] == '\0')) - in_ssid_len--; - /* Check the size of the string */ if (in_ssid_len > IW_ESSID_MAX_SIZE) { ret = -E2BIG; From 965f8bbc6c92233600b176f4c80299f6766df9bd Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 13:16:55 -0400 Subject: [PATCH 1285/2804] [PATCH] libertas: monitor mode support for OLPC firmware Driver support for the monitor mode support that will be available in the next OLPC 'bleeding edge' Marvell firmware release (most likely, 5.110.16.p2). To activate monitor mode, echo mode > /sys/class/net/{ethX,mshX}/device/libertas_rtap where mode is the hex mask that specifies which frames to sniff (in short, 0x1 for data, 0x2 for all management but beacons, 0x4 for beacons). Any non zero mode will activate the monitor mode, inhibiting transmission in ethX and mshX interfaces and routing all the incoming traffic to a new rtapX interface that will output the packets in 802.11+radiotap headers format. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 25 ++++ drivers/net/wireless/libertas/dev.h | 7 +- drivers/net/wireless/libertas/host.h | 2 + drivers/net/wireless/libertas/hostcmd.h | 6 + drivers/net/wireless/libertas/if_usb.c | 2 + drivers/net/wireless/libertas/main.c | 153 +++++++++++++++++++++++- drivers/net/wireless/libertas/rx.c | 49 ++++---- drivers/net/wireless/libertas/tx.c | 8 +- drivers/net/wireless/libertas/wext.h | 5 +- 9 files changed, 217 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 517489a06063..cd3bddb243b1 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -565,6 +565,26 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, return 0; } +static int wlan_cmd_802_11_monitor_mode(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor; + + cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) + + S_DS_GEN); + + monitor->action = cpu_to_le16(cmd_action); + if (cmd_action == CMD_ACT_SET) { + monitor->mode = + cpu_to_le16((u16) (*(u32 *) pdata_buf)); + } + + return 0; +} + static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, struct cmd_ds_command *cmd, u16 cmd_action) @@ -1239,6 +1259,11 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); break; + case CMD_802_11_MONITOR_MODE: + ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr, + cmd_action, pdata_buf); + break; + case CMD_802_11_AD_HOC_JOIN: ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); break; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 397c5fca0ff5..5697fec0cb1d 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -112,7 +112,9 @@ struct _wlan_private { struct net_device *dev; struct net_device_stats stats; - struct net_device *mesh_dev ; /* Virtual device */ + struct net_device *mesh_dev; /* Virtual device */ + struct net_device *rtap_net_dev; + struct ieee80211_device *ieee; struct iw_statistics wstats; struct wlan_mesh_stats mstats; @@ -362,8 +364,7 @@ struct _wlan_adapter { struct cmd_ds_802_11_get_log logmsg; - u32 linkmode; - u32 radiomode; + u32 monitormode; u8 fw_ready; u8 last_scanned_channel; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index c6b44c831594..4ccdbf9c473a 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -110,6 +110,8 @@ #define CMD_FWT_ACCESS 0x0095 +#define CMD_802_11_MONITOR_MODE 0x0098 + #define CMD_MESH_ACCESS 0x009b /* For the IEEE Power Save */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 44cf39c8d1b8..52884eaf2edd 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -405,6 +405,11 @@ struct cmd_ds_802_11_rf_antenna { }; +struct cmd_ds_802_11_monitor_mode { + u16 action; + u16 mode; +}; + struct cmd_ds_802_11_ps_mode { __le16 action; __le16 nullpktinterval; @@ -623,6 +628,7 @@ struct cmd_ds_command { struct cmd_ds_802_11_snmp_mib smib; struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; + struct cmd_ds_802_11_monitor_mode monitor; struct cmd_ds_802_11_data_rate drate; struct cmd_ds_802_11_rate_adapt_rateset rateset; struct cmd_ds_mac_multicast_adr madr; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 670e1d23c043..d28802fb244b 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -208,6 +208,8 @@ static int if_usb_probe(struct usb_interface *intf, if (!(priv = libertas_add_card(cardp, &udev->dev))) goto dealloc; + udev->dev.driver_data = priv; + if (libertas_add_mesh(priv, &udev->dev)) goto err_add_mesh; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a3a17caae439..9a46339ce47e 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -21,6 +21,7 @@ #include "wext.h" #include "debugfs.h" #include "assoc.h" +#include "join.h" #define DRIVER_RELEASE_VERSION "322.p1" const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION @@ -246,6 +247,66 @@ static ssize_t libertas_anycast_set(struct device * dev, return strlen(buf); } +int libertas_add_rtap(wlan_private *priv); +void libertas_remove_rtap(wlan_private *priv); + +/** + * Get function for sysfs attribute rtap + */ +static ssize_t libertas_rtap_get(struct device * dev, + struct device_attribute *attr, char * buf) +{ + wlan_private *priv = (wlan_private *) dev->driver_data; + wlan_adapter *adapter = priv->adapter; + return snprintf(buf, 5, "0x%X\n", adapter->monitormode); +} + +/** + * Set function for sysfs attribute rtap + */ +static ssize_t libertas_rtap_set(struct device * dev, + struct device_attribute *attr, const char * buf, size_t count) +{ + int monitor_mode; + wlan_private *priv = (wlan_private *) dev->driver_data; + wlan_adapter *adapter = priv->adapter; + + sscanf(buf, "%x", &monitor_mode); + if (monitor_mode != WLAN_MONITOR_OFF) { + if(adapter->monitormode == monitor_mode) + return strlen(buf); + if (adapter->monitormode == WLAN_MONITOR_OFF) { + if (adapter->mode == IW_MODE_INFRA) + libertas_send_deauthentication(priv); + else if (adapter->mode == IW_MODE_ADHOC) + libertas_stop_adhoc_network(priv); + libertas_add_rtap(priv); + } + adapter->monitormode = monitor_mode; + } + + else { + if(adapter->monitormode == WLAN_MONITOR_OFF) + return strlen(buf); + adapter->monitormode = WLAN_MONITOR_OFF; + libertas_remove_rtap(priv); + netif_wake_queue(priv->dev); + netif_wake_queue(priv->mesh_dev); + } + + libertas_prepare_and_send_command(priv, + CMD_802_11_MONITOR_MODE, CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode); + return strlen(buf); +} + +/** + * libertas_rtap attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/libertas-rtap) + */ +static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get, + libertas_rtap_set ); + /** * anycast_mask attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/anycast_mask) @@ -480,6 +541,10 @@ static int libertas_mesh_pre_start_xmit(struct sk_buff *skb, int ret; lbs_deb_enter(LBS_DEB_MESH); + if(priv->adapter->monitormode != WLAN_MONITOR_OFF) { + netif_stop_queue(dev); + return -EOPNOTSUPP; + } SET_MESH_FRAME(skb); @@ -494,10 +559,16 @@ static int libertas_mesh_pre_start_xmit(struct sk_buff *skb, */ static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) { + wlan_private *priv = dev->priv; int ret; lbs_deb_enter(LBS_DEB_NET); + if(priv->adapter->monitormode != WLAN_MONITOR_OFF) { + netif_stop_queue(dev); + return -EOPNOTSUPP; + } + UNSET_MESH_FRAME(skb); ret = libertas_hard_start_xmit(skb, dev); @@ -517,7 +588,7 @@ static void libertas_tx_timeout(struct net_device *dev) dev->trans_start = jiffies; if (priv->adapter->currenttxskb) { - if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { /* If we are here, we have not received feedback from the previous packet. Assume TX_FAIL and move on. */ priv->adapter->eventcause = 0x01000000; @@ -1169,6 +1240,9 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) spin_lock_init(&priv->adapter->driver_lock); init_waitqueue_head(&priv->adapter->cmd_pending); priv->adapter->nr_cmd_pending = 0; + priv->rtap_net_dev = NULL; + if (device_create_file(dmdev, &dev_attr_libertas_rtap)) + goto err_kzalloc; goto done; err_kzalloc: @@ -1333,6 +1407,7 @@ int libertas_remove_card(wlan_private *priv) lbs_deb_enter(LBS_DEB_NET); + libertas_remove_rtap(priv); if (!priv) goto out; @@ -1342,6 +1417,7 @@ int libertas_remove_card(wlan_private *priv) goto out; dev = priv->dev; + device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); @@ -1537,6 +1613,81 @@ static void libertas_exit_module(void) lbs_deb_leave(LBS_DEB_MAIN); } +/* + * rtap interface support fuctions + */ + +static int libertas_rtap_open(struct net_device *dev) +{ + netif_carrier_off(dev); + netif_stop_queue(dev); + return 0; +} + +static int libertas_rtap_stop(struct net_device *dev) +{ + return 0; +} + +static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + netif_stop_queue(dev); + return -EOPNOTSUPP; +} + +static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev) +{ + wlan_private *priv = dev->priv; + return &priv->ieee->stats; +} + + +void libertas_remove_rtap(wlan_private *priv) +{ + if (priv->rtap_net_dev == NULL) + return; + unregister_netdev(priv->rtap_net_dev); + free_ieee80211(priv->rtap_net_dev); + priv->rtap_net_dev = NULL; +} + +int libertas_add_rtap(wlan_private *priv) +{ + int rc = 0; + + if (priv->rtap_net_dev) + return -EPERM; + + priv->rtap_net_dev = alloc_ieee80211(0); + if (priv->rtap_net_dev == NULL) + return -ENOMEM; + + + priv->ieee = netdev_priv(priv->rtap_net_dev); + + strcpy(priv->rtap_net_dev->name, "rtap%d"); + + priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP; + priv->rtap_net_dev->open = libertas_rtap_open; + priv->rtap_net_dev->stop = libertas_rtap_stop; + priv->rtap_net_dev->get_stats = libertas_rtap_get_stats; + priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit; + priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list; + priv->rtap_net_dev->priv = priv; + + priv->ieee->iw_mode = IW_MODE_MONITOR; + + rc = register_netdev(priv->rtap_net_dev); + if (rc) { + free_ieee80211(priv->rtap_net_dev); + priv->rtap_net_dev = NULL; + return rc; + } + + return 0; +} + + module_init(libertas_init_module); module_exit(libertas_exit_module); diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 83a7765fd23c..09def943b910 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -138,12 +138,15 @@ void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb) { lbs_deb_rx("skb->data %p\n", skb->data); - if (priv->mesh_dev && IS_MESH_FRAME(skb)) - skb->protocol = eth_type_trans(skb, priv->mesh_dev); - else - skb->protocol = eth_type_trans(skb, priv->dev); + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { + skb->protocol = eth_type_trans(skb, priv->rtap_net_dev); + } else { + if (priv->mesh_dev && IS_MESH_FRAME(skb)) + skb->protocol = eth_type_trans(skb, priv->mesh_dev); + else + skb->protocol = eth_type_trans(skb, priv->dev); + } skb->ip_summed = CHECKSUM_UNNECESSARY; - netif_rx(skb); } @@ -170,7 +173,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) lbs_deb_enter(LBS_DEB_RX); - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) return process_rxed_802_11_packet(priv, skb); p_rx_pkt = (struct rxpackethdr *) skb->data; @@ -290,21 +293,22 @@ static u8 convert_mv_rate_to_radiotap(u8 rate) return 11; case 3: /* 11 Mbps */ return 22; - case 4: /* 6 Mbps */ + /* case 4: reserved */ + case 5: /* 6 Mbps */ return 12; - case 5: /* 9 Mbps */ + case 6: /* 9 Mbps */ return 18; - case 6: /* 12 Mbps */ + case 7: /* 12 Mbps */ return 24; - case 7: /* 18 Mbps */ + case 8: /* 18 Mbps */ return 36; - case 8: /* 24 Mbps */ + case 9: /* 24 Mbps */ return 48; - case 9: /* 36 Mbps */ + case 10: /* 36 Mbps */ return 72; - case 10: /* 48 Mbps */ + case 11: /* 48 Mbps */ return 96; - case 11: /* 54 Mbps */ + case 12: /* 54 Mbps */ return 108; } lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate); @@ -355,14 +359,13 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); /* create the exported radio header */ - switch (priv->adapter->radiomode) { - case WLAN_RADIOMODE_NONE: + if(priv->adapter->monitormode == WLAN_MONITOR_OFF) { /* no radio header */ /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); - break; + } - case WLAN_RADIOMODE_RADIOTAP: + else { /* radiotap header */ radiotap_hdr.hdr.it_version = 0; /* XXX must check this value for pad */ @@ -400,16 +403,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); - break; - - default: - /* unknown header */ - lbs_pr_alert("Unknown radiomode %i\n", - priv->adapter->radiomode); - /* don't export any header */ - /* chop the rxpd */ - skb_pull(skb, sizeof(struct rxpd)); - break; } /* Take the data rate from the rxpd structure diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index bb6e17506a41..fbec06c10dd7 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -86,7 +86,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); p802x_hdr = skb->data; - if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { /* locate radiotap header */ pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data; @@ -106,7 +106,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) } /* copy destination address from 802.3 or 802.11 header */ - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); else memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); @@ -144,7 +144,7 @@ done: priv->stats.tx_errors++; } - if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + if (!ret && priv->adapter->monitormode != WLAN_MONITOR_OFF) { /* Keep the skb to echo it back once Tx feedback is received from FW */ skb_orphan(skb); @@ -252,7 +252,7 @@ void libertas_send_tx_feedback(wlan_private * priv) int txfail; int try_count; - if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP || + if (adapter->monitormode == WLAN_MONITOR_OFF || adapter->currenttxskb == NULL) return; diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 5b0bbc99a21e..6aa444c7de8d 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -15,10 +15,7 @@ struct wlan_ioctl_regrdwr { u32 value; }; -#define WLAN_LINKMODE_802_3 0 -#define WLAN_LINKMODE_802_11 2 -#define WLAN_RADIOMODE_NONE 0 -#define WLAN_RADIOMODE_RADIOTAP 2 +#define WLAN_MONITOR_OFF 0 extern struct iw_handler_def libertas_handler_def; extern struct iw_handler_def mesh_handler_def; From 5707708111ca6c4e9a1160acffdc98a98d95e462 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:17:41 -0400 Subject: [PATCH 1286/2804] [PATCH] libertas: fix assignment of WEP key type keytype is a u8 Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index cd3bddb243b1..257d6443f6c7 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -181,15 +181,13 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, switch (pkey->len) { case KEY_LEN_WEP_40: - wep->keytype[i] = - cpu_to_le16(CMD_TYPE_WEP_40_BIT); + wep->keytype[i] = (u8)CMD_TYPE_WEP_40_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); break; case KEY_LEN_WEP_104: - wep->keytype[i] = - cpu_to_le16(CMD_TYPE_WEP_104_BIT); + wep->keytype[i] = (u8)CMD_TYPE_WEP_104_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); From b031ac10264fa9b805d84b4a440407ac950390cf Mon Sep 17 00:00:00 2001 From: Eugene Teo Date: Thu, 2 Aug 2007 13:18:07 -0400 Subject: [PATCH 1287/2804] [PATCH] drivers/net/wireless/libertas/cmd.c: fix adapter->driver_lock dereference adapter is NULL if cmdnode is not. Signed-off-by: Eugene Teo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 257d6443f6c7..72e8e27a6fb7 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -958,7 +958,7 @@ static int DownloadcommandToStation(wlan_private * priv, unsigned long flags; struct cmd_ds_command *cmdptr; wlan_adapter *adapter = priv->adapter; - int ret = 0; + int ret = -1; u16 cmdsize; u16 command; @@ -966,12 +966,6 @@ static int DownloadcommandToStation(wlan_private * priv, if (!adapter || !cmdnode) { lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n"); - if (cmdnode) { - spin_lock_irqsave(&adapter->driver_lock, flags); - __libertas_cleanup_and_insert_cmd(priv, cmdnode); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - } - ret = -1; goto done; } @@ -982,7 +976,6 @@ static int DownloadcommandToStation(wlan_private * priv, lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n"); __libertas_cleanup_and_insert_cmd(priv, cmdnode); spin_unlock_irqrestore(&adapter->driver_lock, flags); - ret = -1; goto done; } @@ -1008,7 +1001,6 @@ static int DownloadcommandToStation(wlan_private * priv, __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->cur_cmd = NULL; spin_unlock_irqrestore(&adapter->driver_lock, flags); - ret = -1; goto done; } From 2afc0c5d71a3dec6d35f3a234ed986d635ef41ad Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:19:04 -0400 Subject: [PATCH 1288/2804] [PATCH] libertas: push WEXT scan requests to a work queue Push WEXT scan requests to a workqueue and have each partial scan queue the next part, then only report results when the complete scan has finished. Full scans don't go through the work queue. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.h | 2 +- drivers/net/wireless/libertas/dev.h | 3 +- drivers/net/wireless/libertas/main.c | 10 +- drivers/net/wireless/libertas/scan.c | 157 +++++++++++++++----------- drivers/net/wireless/libertas/scan.h | 2 + 5 files changed, 100 insertions(+), 74 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 5e9c31f0932b..e09b7490abbd 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -17,7 +17,7 @@ static inline void wlan_postpone_association_work(wlan_private *priv) if (priv->adapter->surpriseremoved) return; cancel_delayed_work(&priv->assoc_work); - queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY); + queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY); } static inline void wlan_cancel_association_work(wlan_private *priv) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 5697fec0cb1d..762c4792774c 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -148,9 +148,10 @@ struct _wlan_private { /** thread to service interrupts */ struct task_struct *main_thread; wait_queue_head_t waitq; + struct workqueue_struct *work_thread; + struct delayed_work scan_work; struct delayed_work assoc_work; - struct workqueue_struct *assoc_thread; struct work_struct sync_channel; /** Hardware access */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 9a46339ce47e..bcd845060d4a 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1269,9 +1269,10 @@ int libertas_activate_card(wlan_private *priv) goto done; } - priv->assoc_thread = - create_singlethread_workqueue("libertas_assoc"); + priv->work_thread = create_singlethread_workqueue("libertas_worker"); INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); + INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); + INIT_WORK(&priv->sync_channel, libertas_sync_channel); /* @@ -1305,7 +1306,7 @@ int libertas_activate_card(wlan_private *priv) err_init_fw: priv->hw_unregister_dev(priv); err_registerdev: - destroy_workqueue(priv->assoc_thread); + destroy_workqueue(priv->work_thread); /* Stop the thread servicing the interrupts */ wake_up_interruptible(&priv->waitq); kthread_stop(priv->main_thread); @@ -1426,8 +1427,9 @@ int libertas_remove_card(wlan_private *priv) unregister_netdev(dev); + cancel_delayed_work(&priv->scan_work); cancel_delayed_work(&priv->assoc_work); - destroy_workqueue(priv->assoc_thread); + destroy_workqueue(priv->work_thread); if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { adapter->psmode = WLAN802_11POWERMODECAM; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8d4e1ee27395..e2e9ebcd8340 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -314,6 +314,16 @@ static void wlan_scan_create_channel_list(wlan_private * priv, } } + +/* Delayed partial scan worker */ +void libertas_scan_worker(struct work_struct *work) +{ + wlan_private *priv = container_of(work, wlan_private, scan_work.work); + + wlan_scan_networks(priv, NULL, 0); +} + + /** * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds * @@ -408,7 +418,6 @@ wlan_scan_setup_scan_config(wlan_private * priv, *pscancurrentonly = 0; if (puserscanin) { - /* Set the bss type scan filter, use adapter setting if unset */ pscancfgout->bsstype = puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY; @@ -468,59 +477,57 @@ wlan_scan_setup_scan_config(wlan_private * priv, */ *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; - if (puserscanin && puserscanin->chanlist[0].channumber) { - - lbs_deb_scan("Scan: Using supplied channel list\n"); - - for (chanidx = 0; - chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX - && puserscanin->chanlist[chanidx].channumber; chanidx++) { - - channel = puserscanin->chanlist[chanidx].channumber; - (pscanchanlist + chanidx)->channumber = channel; - - radiotype = puserscanin->chanlist[chanidx].radiotype; - (pscanchanlist + chanidx)->radiotype = radiotype; - - scantype = puserscanin->chanlist[chanidx].scantype; - - if (scantype == CMD_SCAN_TYPE_PASSIVE) { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 1; - } else { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 0; - } - - if (puserscanin->chanlist[chanidx].scantime) { - scandur = - puserscanin->chanlist[chanidx].scantime; - } else { - if (scantype == CMD_SCAN_TYPE_PASSIVE) { - scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; - } else { - scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; - } - } - - (pscanchanlist + chanidx)->minscantime = - cpu_to_le16(scandur); - (pscanchanlist + chanidx)->maxscantime = - cpu_to_le16(scandur); - } - - /* Check if we are only scanning the current channel */ - if ((chanidx == 1) && (puserscanin->chanlist[0].channumber - == - priv->adapter->curbssparams.channel)) { - *pscancurrentonly = 1; - lbs_deb_scan("Scan: Scanning current channel only"); - } - - } else { + if (!puserscanin || !puserscanin->chanlist[0].channumber) { + /* Create a default channel scan list */ lbs_deb_scan("Scan: Creating full region channel list\n"); wlan_scan_create_channel_list(priv, pscanchanlist, *pfilteredscan); + goto out; + } + + lbs_deb_scan("Scan: Using supplied channel list\n"); + for (chanidx = 0; + chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX + && puserscanin->chanlist[chanidx].channumber; chanidx++) { + + channel = puserscanin->chanlist[chanidx].channumber; + (pscanchanlist + chanidx)->channumber = channel; + + radiotype = puserscanin->chanlist[chanidx].radiotype; + (pscanchanlist + chanidx)->radiotype = radiotype; + + scantype = puserscanin->chanlist[chanidx].scantype; + + if (scantype == CMD_SCAN_TYPE_PASSIVE) { + (pscanchanlist + + chanidx)->chanscanmode.passivescan = 1; + } else { + (pscanchanlist + + chanidx)->chanscanmode.passivescan = 0; + } + + if (puserscanin->chanlist[chanidx].scantime) { + scandur = puserscanin->chanlist[chanidx].scantime; + } else { + if (scantype == CMD_SCAN_TYPE_PASSIVE) { + scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; + } else { + scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; + } + } + + (pscanchanlist + chanidx)->minscantime = + cpu_to_le16(scandur); + (pscanchanlist + chanidx)->maxscantime = + cpu_to_le16(scandur); + } + + /* Check if we are only scanning the current channel */ + if ((chanidx == 1) && + (puserscanin->chanlist[0].channumber == + priv->adapter->curbssparams.channel)) { + *pscancurrentonly = 1; + lbs_deb_scan("Scan: Scanning current channel only"); } out: @@ -604,12 +611,12 @@ static int wlan_scan_channel_list(wlan_private * priv, while (tlvidx < maxchanperscan && ptmpchan->channumber && !doneearly && scanned < 2) { - lbs_deb_scan( - "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n", - ptmpchan->channumber, ptmpchan->radiotype, - ptmpchan->chanscanmode.passivescan, - ptmpchan->chanscanmode.disablechanfilt, - ptmpchan->maxscantime); + lbs_deb_scan("Scan: Chan(%3d), Radio(%d), mode(%d,%d), " + "Dur(%d)\n", + ptmpchan->channumber, ptmpchan->radiotype, + ptmpchan->chanscanmode.passivescan, + ptmpchan->chanscanmode.disablechanfilt, + ptmpchan->maxscantime); /* Copy the current channel TLV to the command being prepared */ memcpy(pchantlvout->chanscanparam + tlvidx, @@ -678,9 +685,18 @@ static int wlan_scan_channel_list(wlan_private * priv, done: priv->adapter->last_scanned_channel = ptmpchan->channumber; - /* Tell userspace the scan table has been updated */ - memset(&wrqu, 0, sizeof(union iwreq_data)); - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); + if (priv->adapter->last_scanned_channel) { + /* Schedule the next part of the partial scan */ + if (!full_scan && !priv->adapter->surpriseremoved) { + cancel_delayed_work(&priv->scan_work); + queue_delayed_work(priv->work_thread, &priv->scan_work, + msecs_to_jiffies(300)); + } + } else { + /* All done, tell userspace the scan table has been updated */ + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); + } lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; @@ -747,8 +763,8 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, * @return 0 or < 0 if error */ int wlan_scan_networks(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin, - int full_scan) + const struct wlan_ioctl_user_scan_cfg * puserscanin, + int full_scan) { wlan_adapter * adapter = priv->adapter; struct mrvlietypes_chanlistparamset *pchantlvout; @@ -763,7 +779,13 @@ int wlan_scan_networks(wlan_private * priv, int i = 0; #endif - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); + + /* Cancel any partial outstanding partial scans if this scan + * is a full scan. + */ + if (full_scan && delayed_work_pending(&priv->scan_work)) + cancel_delayed_work(&priv->scan_work); scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); @@ -1289,7 +1311,10 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_SCAN); - wlan_scan_networks(priv, NULL, 0); + if (!delayed_work_pending(&priv->scan_work)) { + queue_delayed_work(priv->work_thread, &priv->scan_work, + msecs_to_jiffies(50)); + } if (adapter->surpriseremoved) return -1; @@ -1508,10 +1533,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_ASSOC); - /* If we've got an uncompleted scan, schedule the next part */ - if (!adapter->nr_cmd_pending && adapter->last_scanned_channel) - wlan_scan_networks(priv, NULL, 0); - /* Update RSSI if current BSS is a locally created ad-hoc BSS */ if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 9bb1a435c28a..c29c031bef8c 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -210,4 +210,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra); +void libertas_scan_worker(struct work_struct *work); + #endif /* _WLAN_SCAN_H */ From 63f0023bc34073bea8452a4770540c954f98208f Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 13:19:24 -0400 Subject: [PATCH 1289/2804] [PATCH] libertas: pass boot2 version to firmware Boot2 version used to be hardcoded in the uploaded firmware, this patch preserves the boot2 version before uploading firmware and sends it to the firmware again on resume. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 15 +++++++++++++++ drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/host.h | 2 ++ drivers/net/wireless/libertas/hostcmd.h | 6 ++++++ drivers/net/wireless/libertas/if_usb.c | 1 + drivers/net/wireless/libertas/main.c | 4 ++++ 6 files changed, 29 insertions(+) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 72e8e27a6fb7..98092b995352 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -901,6 +901,17 @@ static int wlan_cmd_mesh_access(wlan_private * priv, return 0; } +static int wlan_cmd_set_boot2_ver(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_set_boot2_ver *boot2_ver = &cmd->params.boot2_ver; + cmd->command = cpu_to_le16(CMD_SET_BOOT2_VER); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_set_boot2_ver) + S_DS_GEN); + boot2_ver->version = priv->boot2_version; + return 0; +} + void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail) { unsigned long flags; @@ -1372,6 +1383,10 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); break; + case CMD_SET_BOOT2_VER: + ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf); + break; + case CMD_GET_TSF: cmdptr->command = cpu_to_le16(CMD_GET_TSF); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) + diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 762c4792774c..a3c94d7388ab 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -104,6 +104,7 @@ struct _wlan_private { int mesh_open; int infra_open; int mesh_autostart_enabled; + __le16 boot2_version; char name[DEV_NAME_LEN]; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 4ccdbf9c473a..68fa11b3a2dc 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -114,6 +114,8 @@ #define CMD_MESH_ACCESS 0x009b +#define CMD_SET_BOOT2_VER 0x00a5 + /* For the IEEE Power Save */ #define CMD_SUBCMD_ENTER_PS 0x0030 #define CMD_SUBCMD_EXIT_PS 0x0031 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 52884eaf2edd..e1045dc02cce 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -410,6 +410,11 @@ struct cmd_ds_802_11_monitor_mode { u16 mode; }; +struct cmd_ds_set_boot2_ver { + u16 action; + u16 version; +}; + struct cmd_ds_802_11_ps_mode { __le16 action; __le16 nullpktinterval; @@ -660,6 +665,7 @@ struct cmd_ds_command { struct cmd_ds_bt_access bt; struct cmd_ds_fwt_access fwt; struct cmd_ds_mesh_access mesh; + struct cmd_ds_set_boot2_ver boot2_ver; struct cmd_ds_get_tsf gettsf; struct cmd_ds_802_11_subscribe_event subscribe_event; } params; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index d28802fb244b..53d479688ff9 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -219,6 +219,7 @@ static int if_usb_probe(struct usb_interface *intf, priv->hw_host_to_card = if_usb_host_to_card; priv->hw_get_int_status = if_usb_get_int_status; priv->hw_read_event_cause = if_usb_read_event_cause; + priv->boot2_version = udev->descriptor.bcdDevice; if (libertas_activate_card(priv)) goto err_activate_card; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index bcd845060d4a..e20cd4e9ffc1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -981,6 +981,10 @@ static int wlan_setup_station_hw(wlan_private * priv) priv->mesh_autostart_enabled = 0; } + /* Set the boot2 version in firmware */ + ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); + ret = 0; done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); From 81173e34d454c353d9f0a53760609f3b9d30a311 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:19:56 -0400 Subject: [PATCH 1290/2804] [PATCH] libertas: fix misspelling in debug message Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index ffeec2fa60ae..3131afcf4590 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -622,7 +622,7 @@ void libertas_association_worker(struct work_struct *work) } if (adapter->connect_status != LIBERTAS_CONNECTED) { - lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, " + lbs_deb_assoc("ASSOC: association attempt unsuccessful, " "not connected.\n"); success = 0; } From 5612c0140ac58b51209a24c8fd6a92ceb472aabe Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:20:12 -0400 Subject: [PATCH 1291/2804] [PATCH] libertas: ignore spurious mesh autostart events Don't trust the firmware to always send them at the right time, ignore them when the driver thinks mesh autostart is disabled. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 93bf63bad0f6..c43b2725e5bc 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -968,6 +968,11 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_MESH_AUTO_STARTED: + /* Ignore spurious autostart events if autostart is disabled */ + if (!priv->mesh_autostart_enabled) { + lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); + break; + } lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); adapter->connect_status = LIBERTAS_CONNECTED; if (priv->mesh_open == 1) { From c7fdf26995d5d6ebf1c3314ad001b9a4983c3f04 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:20:29 -0400 Subject: [PATCH 1292/2804] [PATCH] libertas: better descriptions for association errors Describe the association response status code the firmware returns, based on mail to libertas-dev from Ronak. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 55 +++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index ccb0df1967fb..ce49d3f25613 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -700,6 +700,7 @@ int libertas_ret_80211_associate(wlan_private * priv, union iwreq_data wrqu; struct ieeetypes_assocrsp *passocrsp; struct bss_descriptor * bss; + u16 status_code; lbs_deb_enter(LBS_DEB_JOIN); @@ -712,12 +713,56 @@ int libertas_ret_80211_associate(wlan_private * priv, passocrsp = (struct ieeetypes_assocrsp *) & resp->params; - if (le16_to_cpu(passocrsp->statuscode)) { + /* + * Older FW versions map the IEEE 802.11 Status Code in the association + * response to the following values returned in passocrsp->statuscode: + * + * IEEE Status Code Marvell Status Code + * 0 -> 0x0000 ASSOC_RESULT_SUCCESS + * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * others -> 0x0003 ASSOC_RESULT_REFUSED + * + * Other response codes: + * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) + * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for + * association response from the AP) + */ + + status_code = le16_to_cpu(passocrsp->statuscode); + switch (status_code) { + case 0x00: + lbs_deb_join("ASSOC_RESP: Association succeeded\n"); + break; + case 0x01: + lbs_deb_join("ASSOC_RESP: Association failed; invalid " + "parameters (status code %d)\n", status_code); + break; + case 0x02: + lbs_deb_join("ASSOC_RESP: Association failed; internal timer " + "expired while waiting for the AP (status code %d)" + "\n", status_code); + break; + case 0x03: + lbs_deb_join("ASSOC_RESP: Association failed; association " + "was refused by the AP (status code %d)\n", + status_code); + break; + case 0x04: + lbs_deb_join("ASSOC_RESP: Association failed; authentication " + "was refused by the AP (status code %d)\n", + status_code); + break; + default: + lbs_deb_join("ASSOC_RESP: Association failed; reason unknown " + "(status code %d)\n", status_code); + break; + } + + if (status_code) { libertas_mac_event_disconnected(priv); - - lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n", - le16_to_cpu(passocrsp->statuscode)); - ret = -1; goto done; } From 8362cd413e8116306fafbaf414f0419db0595142 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 3 Aug 2007 09:40:55 -0400 Subject: [PATCH 1293/2804] [PATCH] libertas: fix sparse-reported problems A few fields being converted to the wrong sized type, and a few missed endian conversions. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 2 +- drivers/net/wireless/libertas/cmdresp.c | 4 ++-- drivers/net/wireless/libertas/debugfs.c | 2 +- drivers/net/wireless/libertas/if_usb.c | 30 +++++++++++-------------- drivers/net/wireless/libertas/rx.c | 4 ++-- drivers/net/wireless/libertas/wext.c | 8 +++---- 6 files changed, 23 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 8b366ef2fe95..9cf0211de67f 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -543,7 +543,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, nr_subband * sizeof(struct ieeetypes_subbandset)); cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + - domain->header.len + + le16_to_cpu(domain->header.len) + sizeof(struct mrvlietypesheader) + S_DS_GEN); } else { diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index c43b2725e5bc..4c36e63ae7b0 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -812,8 +812,8 @@ int libertas_process_rx_command(wlan_private * priv) if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) { /* Copy the response back to response buffer */ - memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size); - + memcpy(adapter->cur_cmd->pdata_buf, resp, + le16_to_cpu(resp->size)); adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD; } diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 63e747ac49d0..6d95148e8725 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -510,7 +510,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) return 0; } - if (pcmdptr->command != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) { + if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 53d479688ff9..364eae374b93 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -639,11 +639,13 @@ static void if_usb_receive(struct urb *urb) int recvlength = urb->actual_length; u8 *recvbuff = NULL; - u32 recvtype; + u32 recvtype = 0; lbs_deb_enter(LBS_DEB_USB); if (recvlength) { + __le32 tmp; + if (urb->status) { lbs_deb_usbd(&cardp->udev->dev, "URB status is failed\n"); @@ -652,18 +654,14 @@ static void if_usb_receive(struct urb *urb) } recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; - memcpy(&recvtype, recvbuff, sizeof(u32)); + memcpy(&tmp, recvbuff, sizeof(u32)); + recvtype = le32_to_cpu(tmp); lbs_deb_usbd(&cardp->udev->dev, - "Recv length = 0x%x\n", recvlength); - lbs_deb_usbd(&cardp->udev->dev, - "Receive type = 0x%X\n", recvtype); - recvtype = le32_to_cpu(recvtype); - lbs_deb_usbd(&cardp->udev->dev, - "Receive type after = 0x%X\n", recvtype); + "Recv length = 0x%x, Recv type = 0x%X\n", + recvlength, recvtype); } else if (urb->status) goto rx_exit; - switch (recvtype) { case CMD_TYPE_DATA: process_cmdtypedata(recvlength, skb, cardp, priv); @@ -691,6 +689,8 @@ static void if_usb_receive(struct urb *urb) spin_unlock(&priv->adapter->driver_lock); goto rx_exit; default: + lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n", + recvtype); kfree_skb(skb); break; } @@ -711,21 +711,19 @@ rx_exit: */ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb) { - int ret = -1; - u32 tmp; struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type); lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb); if (type == MVMS_CMD) { - tmp = cpu_to_le32(CMD_TYPE_REQUEST); + __le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST); priv->dnld_sent = DNLD_CMD_SENT; memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, MESSAGE_HEADER_LEN); } else { - tmp = cpu_to_le32(CMD_TYPE_DATA); + __le32 tmp = cpu_to_le32(CMD_TYPE_DATA); priv->dnld_sent = DNLD_DATA_SENT; memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, MESSAGE_HEADER_LEN); @@ -733,10 +731,8 @@ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 n memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); - ret = - usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); - - return ret; + return usb_tx_block(priv, cardp->bulk_out_buffer, + nb + MESSAGE_HEADER_LEN); } /* called with adapter->driver_lock held */ diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 09def943b910..0420e5b9ff9b 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -370,8 +370,8 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) radiotap_hdr.hdr.it_version = 0; /* XXX must check this value for pad */ radiotap_hdr.hdr.it_pad = 0; - radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr); - radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT; + radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); + radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); /* unknown values */ radiotap_hdr.flags = 0; radiotap_hdr.chan_freq = 0; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 15395bf0a2ac..3f628223bc6c 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -872,7 +872,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) /* Quality by TX errors */ priv->wstats.discard.retries = priv->stats.tx_errors; - tx_retries = le16_to_cpu(adapter->logmsg.retry); + tx_retries = le32_to_cpu(adapter->logmsg.retry); if (tx_retries > 75) tx_qual = (90 - tx_retries) * POOR / 15; @@ -888,10 +888,10 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; quality = min(quality, tx_qual); - priv->wstats.discard.code = le16_to_cpu(adapter->logmsg.wepundecryptable); - priv->wstats.discard.fragment = le16_to_cpu(adapter->logmsg.rxfrag); + priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable); + priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag); priv->wstats.discard.retries = tx_retries; - priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure); + priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure); /* Calculate quality */ priv->wstats.qual.qual = min_t(u8, quality, 100); From 7856a541ad83e84d260abb652c39299972ba310c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 3 Aug 2007 09:43:03 -0400 Subject: [PATCH 1294/2804] [PATCH] libertas: bump driver version Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e20cd4e9ffc1..f0213eca680b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -23,7 +23,7 @@ #include "assoc.h" #include "join.h" -#define DRIVER_RELEASE_VERSION "322.p1" +#define DRIVER_RELEASE_VERSION "323.p0" const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION #ifdef DEBUG "-dbg" From af096046f63a065b692018cd4b8f5e7525c3e56a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 24 Jul 2007 01:30:36 -0400 Subject: [PATCH 1295/2804] [netdrvr] skfp: remove a bunch of dead code The driver has not compiled in anything except PCI support for many years (see drivers/net/skfp/Makefile). This driver is also unmaintained for many years, so arguments for keeping the cross-OS, cross-bus (ISA, EISA, MCA) code do not exist. Signed-off-by: Jeff Garzik --- drivers/net/skfp/drvfbi.c | 693 +----------------------------- drivers/net/skfp/h/mbuf.h | 4 - drivers/net/skfp/h/skfbi.h | 783 +--------------------------------- drivers/net/skfp/h/skfbiinc.h | 26 -- drivers/net/skfp/h/targethw.h | 33 +- drivers/net/skfp/hwt.c | 42 +- 6 files changed, 8 insertions(+), 1573 deletions(-) diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c index 4fe624b0dd25..be2ee6519ef2 100644 --- a/drivers/net/skfp/drvfbi.c +++ b/drivers/net/skfp/drvfbi.c @@ -43,25 +43,6 @@ static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ; /* * valid configuration values are: */ -#ifdef ISA -const int opt_ints[] = {8, 3, 4, 5, 9, 10, 11, 12, 15} ; -const int opt_iops[] = {8, - 0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340}; -const int opt_dmas[] = {4, 3, 5, 6, 7} ; -const int opt_eproms[] = {15, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, - 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ; -#endif -#ifdef EISA -const int opt_ints[] = {5, 9, 10, 11} ; -const int opt_dmas[] = {0, 5, 6, 7} ; -const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, - 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ; -#endif - -#ifdef MCA -int opt_ints[] = {3, 11, 10, 9} ; /* FM1 */ -int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ; -#endif /* MCA */ /* * xPOS_ID:xxxx @@ -78,17 +59,9 @@ int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ; */ #ifndef MULT_OEM #ifndef OEM_CONCEPT -#ifndef MCA const u_char oem_id[] = "xPOS_ID:xxxx" ; -#else -const u_char oem_id[] = "xPOSID1:xxxx" ; /* FM1 card id. */ -#endif #else /* OEM_CONCEPT */ -#ifndef MCA const u_char oem_id[] = OEM_ID ; -#else -const u_char oem_id[] = OEM_ID1 ; /* FM1 card id. */ -#endif /* MCA */ #endif /* OEM_CONCEPT */ #define ID_BYTE0 8 #define OEMID(smc,i) oem_id[ID_BYTE0 + i] @@ -109,23 +82,6 @@ extern int AIX_vpdReadByte() ; /* Prototype of a local function. */ static void smt_stop_watchdog(struct s_smc *smc); -#ifdef MCA -static int read_card_id() ; -static void DisableSlotAccess() ; -static void EnableSlotAccess() ; -#ifdef AIX -extern int attach_POS_addr() ; -extern int detach_POS_addr() ; -extern u_char read_POS() ; -extern void write_POS() ; -extern int AIX_vpdReadByte() ; -#else -#define read_POS(smc,a1,a2) ((u_char) inp(a1)) -#define write_POS(smc,a1,a2,a3) outp((a1),(a3)) -#endif -#endif /* MCA */ - - /* * FDDI card reset */ @@ -139,51 +95,6 @@ static void card_start(struct s_smc *smc) smt_stop_watchdog(smc) ; -#ifdef ISA - outpw(CSR_A,0) ; /* reset for all chips */ - for (i = 10 ; i ; i--) /* delay for PLC's */ - (void)inpw(ISR_A) ; - OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ; - /* counter 2, mode 2 */ - OUT_82c54_TIMER(2,97) ; /* LSB */ - OUT_82c54_TIMER(2,0) ; /* MSB ( 15.6 us ) */ - outpw(CSR_A,CS_CRESET) ; -#endif -#ifdef EISA - outpw(CSR_A,0) ; /* reset for all chips */ - for (i = 10 ; i ; i--) /* delay for PLC's */ - (void)inpw(ISR_A) ; - outpw(CSR_A,CS_CRESET) ; - smc->hw.led = (2<<6) ; - outpw(CSR_A,CS_CRESET | smc->hw.led) ; -#endif -#ifdef MCA - outp(ADDR(CARD_DIS),0) ; /* reset for all chips */ - for (i = 10 ; i ; i--) /* delay for PLC's */ - (void)inpw(ISR_A) ; - outp(ADDR(CARD_EN),0) ; - /* first I/O after reset must not be a access to FORMAC or PLC */ - - /* - * bus timeout (MCA) - */ - OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ; - /* counter 2, mode 3 */ - OUT_82c54_TIMER(2,(2*24)) ; /* 3.9 us * 2 square wave */ - OUT_82c54_TIMER(2,0) ; /* MSB */ - - /* POS 102 indicated an activ Check Line or Buss Error monitoring */ - if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) { - outp(ADDR(IRQ_CHCK_EN),0) ; - } - - if (!((i = inpw(CSR_A)) & CS_SAS)) { - if (!(i & CS_BYSTAT)) { - outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */ - } - } - outpw(LEDR_A,LED_1) ; /* yellow */ -#endif /* MCA */ #ifdef PCI /* * make sure no transfer activity is pending @@ -253,15 +164,7 @@ void card_stop(struct s_smc *smc) { smt_stop_watchdog(smc) ; smc->hw.mac_ring_is_up = 0 ; /* ring down */ -#ifdef ISA - outpw(CSR_A,0) ; /* reset for all chips */ -#endif -#ifdef EISA - outpw(CSR_A,0) ; /* reset for all chips */ -#endif -#ifdef MCA - outp(ADDR(CARD_DIS),0) ; /* reset for all chips */ -#endif + #ifdef PCI /* * make sure no transfer activity is pending @@ -284,60 +187,6 @@ void mac1_irq(struct s_smc *smc, u_short stu, u_short stl) { int restart_tx = 0 ; again: -#ifndef PCI -#ifndef ISA -/* - * FORMAC+ bug modified the queue pointer if many read/write accesses happens!? - */ - if (stl & (FM_SPCEPDS | /* parit/coding err. syn.q.*/ - FM_SPCEPDA0 | /* parit/coding err. a.q.0 */ - FM_SPCEPDA1 | /* parit/coding err. a.q.1 */ - FM_SPCEPDA2)) { /* parit/coding err. a.q.2 */ - SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ; - } - if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/ - FM_STBURA0 | /* tx buffer underrun a.q.0 */ - FM_STBURA1 | /* tx buffer underrun a.q.1 */ - FM_STBURA2)) { /* tx buffer underrun a.q.2 */ - SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ; - } -#endif - if ( (stu & (FM_SXMTABT | /* transmit abort */ -#ifdef SYNC - FM_STXABRS | /* syn. tx abort */ -#endif /* SYNC */ - FM_STXABRA0)) || /* asyn. tx abort */ - (stl & (FM_SQLCKS | /* lock for syn. q. */ - FM_SQLCKA0)) ) { /* lock for asyn. q. */ - formac_tx_restart(smc) ; /* init tx */ - restart_tx = 1 ; - stu = inpw(FM_A(FM_ST1U)) ; - stl = inpw(FM_A(FM_ST1L)) ; - stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ; - if (stu || stl) - goto again ; - } - -#ifndef SYNC - if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */ - FM_STEFRMA0)) { /* end of frame asyn tx */ - /* free tx_queue */ - smc->hw.n_a_send = 0 ; - if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) { - start_next_send(smc); - } - restart_tx = 1 ; - } -#else /* SYNC */ - if (stu & (FM_STEFRMA0 | /* end of asyn tx */ - FM_STEFRMS)) { /* end of sync tx */ - restart_tx = 1 ; - } -#endif /* SYNC */ - if (restart_tx) - llc_restart_tx(smc) ; -} -#else /* PCI */ /* * parity error: note encoding error is not possible in tag mode @@ -378,7 +227,7 @@ again: if (restart_tx) llc_restart_tx(smc) ; } -#endif /* PCI */ + /* * interrupt source= plc1 * this function is called in nwfbisr.asm @@ -387,10 +236,6 @@ void plc1_irq(struct s_smc *smc) { u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ; -#if (defined(ISA) || defined(EISA)) - /* reset PLC Int. bits */ - outpw(PLC1_I,inpw(PLC1_I)) ; -#endif plc_irq(smc,PB,st) ; } @@ -402,10 +247,6 @@ void plc2_irq(struct s_smc *smc) { u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ; -#if (defined(ISA) || defined(EISA)) - /* reset PLC Int. bits */ - outpw(PLC2_I,inpw(PLC2_I)) ; -#endif plc_irq(smc,PA,st) ; } @@ -446,43 +287,15 @@ void read_address(struct s_smc *smc, u_char *mac_addr) char PmdType ; int i ; -#if (defined(ISA) || defined(MCA)) - for (i = 0; i < 4 ;i++) { /* read mac address from board */ - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inpw(PR_A(i+SA_MAC))); - } - for (i = 4; i < 6; i++) { - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF))); - } -#endif -#ifdef EISA - /* - * Note: We get trouble on an Alpha machine if we make a inpw() - * instead of inp() - */ - for (i = 0; i < 4 ;i++) { /* read mac address from board */ - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inp(PR_A(i+SA_MAC))); - } - for (i = 4; i < 6; i++) { - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF))); - } -#endif #ifdef PCI for (i = 0; i < 6; i++) { /* read mac address from board */ smc->hw.fddi_phys_addr.a[i] = bitrev8(inp(ADDR(B2_MAC_0+i))); } #endif -#ifndef PCI - ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ; - PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ; -#else + ConnectorType = inp(ADDR(B2_CONN_TYP)) ; PmdType = inp(ADDR(B2_PMD_TYP)) ; -#endif smc->y[PA].pmd_type[PMD_SK_CONN] = smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ; @@ -512,20 +325,12 @@ void init_board(struct s_smc *smc, u_char *mac_addr) card_start(smc) ; read_address(smc,mac_addr) ; -#ifndef PCI - if (inpw(CSR_A) & CS_SAS) -#else if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL)) -#endif smc->s.sas = SMT_SAS ; /* Single att. station */ else smc->s.sas = SMT_DAS ; /* Dual att. station */ -#ifndef PCI - if (inpw(CSR_A) & CS_BYSTAT) -#else if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST)) -#endif smc->mib.fddiSMTBypassPresent = 0 ; /* without opt. bypass */ else @@ -538,42 +343,12 @@ void init_board(struct s_smc *smc, u_char *mac_addr) */ void sm_pm_bypass_req(struct s_smc *smc, int mode) { -#if (defined(ISA) || defined(EISA)) - int csra_v ; -#endif - DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ? "BP_INSERT" : "BP_DEINSERT",0) ; if (smc->s.sas != SMT_DAS) return ; -#if (defined(ISA) || defined(EISA)) - - csra_v = inpw(CSR_A) & ~CS_BYPASS ; -#ifdef EISA - csra_v |= smc->hw.led ; -#endif - - switch(mode) { - case BP_INSERT : - outpw(CSR_A,csra_v | CS_BYPASS) ; - break ; - case BP_DEINSERT : - outpw(CSR_A,csra_v) ; - break ; - } -#endif /* ISA / EISA */ -#ifdef MCA - switch(mode) { - case BP_INSERT : - outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */ - break ; - case BP_DEINSERT : - outp(ADDR(BYPASS(STAT_BYP)),0) ; /* bypass station */ - break ; - } -#endif #ifdef PCI switch(mode) { case BP_INSERT : @@ -591,31 +366,14 @@ void sm_pm_bypass_req(struct s_smc *smc, int mode) */ int sm_pm_bypass_present(struct s_smc *smc) { -#ifndef PCI - return( (inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ; -#else return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ; -#endif } void plc_clear_irq(struct s_smc *smc, int p) { SK_UNUSED(p) ; -#if (defined(ISA) || defined(EISA)) - switch (p) { - case PA : - /* reset PLC Int. bits */ - outpw(PLC2_I,inpw(PLC2_I)) ; - break ; - case PB : - /* reset PLC Int. bits */ - outpw(PLC1_I,inpw(PLC1_I)) ; - break ; - } -#else SK_UNUSED(smc) ; -#endif } @@ -645,51 +403,6 @@ static void led_indication(struct s_smc *smc, int led_event) phy = &smc->y[PB] ; mib_b = phy->mib ; -#ifdef EISA - /* Ring up = yellow led OFF*/ - if (led_event == LED_Y_ON) { - smc->hw.led |= CS_LED_1 ; - } - else if (led_event == LED_Y_OFF) { - smc->hw.led &= ~CS_LED_1 ; - } - else { - /* Link at Port A or B = green led ON */ - if (mib_a->fddiPORTPCMState == PC8_ACTIVE || - mib_b->fddiPORTPCMState == PC8_ACTIVE) { - smc->hw.led |= CS_LED_0 ; - } - else { - smc->hw.led &= ~CS_LED_0 ; - } - } -#endif -#ifdef MCA - led_state = inpw(LEDR_A) ; - - /* Ring up = yellow led OFF*/ - if (led_event == LED_Y_ON) { - led_state |= LED_1 ; - } - else if (led_event == LED_Y_OFF) { - led_state &= ~LED_1 ; - } - else { - led_state &= ~(LED_2|LED_0) ; - - /* Link at Port A = green led A ON */ - if (mib_a->fddiPORTPCMState == PC8_ACTIVE) { - led_state |= LED_2 ; - } - - /* Link at Port B/S = green led B ON */ - if (mib_b->fddiPORTPCMState == PC8_ACTIVE) { - led_state |= LED_0 ; - } - } - - outpw(LEDR_A, led_state) ; -#endif /* MCA */ #ifdef PCI led_state = 0 ; @@ -824,406 +537,6 @@ int set_oi_id_def(struct s_smc *smc) } #endif /* MULT_OEM */ - -#ifdef MCA -/************************ - * - * BEGIN_MANUAL_ENTRY() - * - * exist_board - * - * Check if an MCA board is present in the specified slot. - * - * int exist_board( - * struct s_smc *smc, - * int slot) ; - * In - * smc - A pointer to the SMT Context struct. - * - * slot - The number of the slot to inspect. - * Out - * 0 = No adapter present. - * 1 = Found FM1 adapter. - * - * Pseudo - * Read MCA ID - * for all valid OEM_IDs - * compare with ID read - * if equal, return 1 - * return(0 - * - * Note - * The smc pointer must be valid now. - * - * END_MANUAL_ENTRY() - * - ************************/ -#define LONG_CARD_ID(lo, hi) ((((hi) & 0xff) << 8) | ((lo) & 0xff)) -int exist_board(struct s_smc *smc, int slot) -{ -#ifdef MULT_OEM - SK_LOC_DECL(u_char,id[2]) ; - int idi ; -#endif /* MULT_OEM */ - - /* No longer valid. */ - if (smc == NULL) - return(0) ; - -#ifndef MULT_OEM - if (read_card_id(smc, slot) - == LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1))) - return (1) ; /* Found FM adapter. */ - -#else /* MULT_OEM */ - idi = read_card_id(smc, slot) ; - id[0] = idi & 0xff ; - id[1] = idi >> 8 ; - - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; - for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { - if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) - continue ; - - if (is_equal_num(&id[0],&OEMID(smc,0),2)) - return (1) ; - } -#endif /* MULT_OEM */ - return (0) ; /* No adapter found. */ -} - -/************************ - * - * read_card_id - * - * Read the MCA card id from the specified slot. - * In - * smc - A pointer to the SMT Context struct. - * CAVEAT: This pointer may be NULL and *must not* be used within this - * function. It's only purpose is for drivers that need some information - * for the inp() and outp() macros. - * - * slot - The number of the slot for which the card id is returned. - * Out - * Returns the card id read from the specified slot. If an illegal slot - * number is specified, the function returns zero. - * - ************************/ -static int read_card_id(struct s_smc *smc, int slot) -/* struct s_smc *smc ; Do not use. */ -{ - int card_id ; - - SK_UNUSED(smc) ; /* Make LINT happy. */ - if ((slot < 1) || (slot > 15)) /* max 16 slots, 0 = motherboard */ - return (0) ; /* Illegal slot number specified. */ - - EnableSlotAccess(smc, slot) ; - - card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) | - (read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ; - - DisableSlotAccess(smc) ; - - return (card_id) ; -} - -/************************ - * - * BEGIN_MANUAL_ENTRY() - * - * get_board_para - * - * Get adapter configuration information. Fill all board specific - * parameters within the 'smc' structure. - * - * int get_board_para( - * struct s_smc *smc, - * int slot) ; - * In - * smc - A pointer to the SMT Context struct, to which this function will - * write some adapter configuration data. - * - * slot - The number of the slot, in which the adapter is installed. - * Out - * 0 = No adapter present. - * 1 = Ok. - * 2 = Adapter present, but card enable bit not set. - * - * END_MANUAL_ENTRY() - * - ************************/ -int get_board_para(struct s_smc *smc, int slot) -{ - int val ; - int i ; - - /* Check if adapter present & get type of adapter. */ - switch (exist_board(smc, slot)) { - case 0: /* Adapter not present. */ - return (0) ; - case 1: /* FM Rev. 1 */ - smc->hw.rev = FM1_REV ; - smc->hw.VFullRead = 0x0a ; - smc->hw.VFullWrite = 0x05 ; - smc->hw.DmaWriteExtraBytes = 8 ; /* 2 extra words. */ - break ; - } - smc->hw.slot = slot ; - - EnableSlotAccess(smc, slot) ; - - if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) { - DisableSlotAccess(smc) ; - return (2) ; /* Card enable bit not set. */ - } - - val = read_POS(smc,POS_104, slot - 1) ; /* I/O, IRQ */ - -#ifndef MEM_MAPPED_IO /* is defined by the operating system */ - i = val & POS_IOSEL ; /* I/O base addr. (0x0200 .. 0xfe00) */ - smc->hw.iop = (i + 1) * 0x0400 - 0x200 ; -#endif - i = ((val & POS_IRQSEL) >> 6) & 0x03 ; /* IRQ <0, 1> */ - smc->hw.irq = opt_ints[i] ; - - /* FPROM base addr. */ - i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ; - smc->hw.eprom = opt_eproms[i] ; - - DisableSlotAccess(smc) ; - - /* before this, the smc->hw.iop must be set !!! */ - smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ; - - return (1) ; -} - -/* Enable access to specified MCA slot. */ -static void EnableSlotAccess(struct s_smc *smc, int slot) -{ - SK_UNUSED(slot) ; - -#ifndef AIX - SK_UNUSED(smc) ; - - /* System mode. */ - outp(POS_SYS_SETUP, POS_SYSTEM) ; - - /* Select slot. */ - outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ; -#else - attach_POS_addr (smc) ; -#endif -} - -/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */ -static void DisableSlotAccess(struct s_smc *smc) -{ -#ifndef AIX - SK_UNUSED(smc) ; - - outp(POS_CHANNEL_POS, 0) ; -#else - detach_POS_addr (smc) ; -#endif -} -#endif /* MCA */ - -#ifdef EISA -#ifndef MEM_MAPPED_IO -#define SADDR(slot) (((slot)<<12)&0xf000) -#else /* MEM_MAPPED_IO */ -#define SADDR(slot) (smc->hw.iop) -#endif /* MEM_MAPPED_IO */ - -/************************ - * - * BEGIN_MANUAL_ENTRY() - * - * exist_board - * - * Check if an EISA board is present in the specified slot. - * - * int exist_board( - * struct s_smc *smc, - * int slot) ; - * In - * smc - A pointer to the SMT Context struct. - * - * slot - The number of the slot to inspect. - * Out - * 0 = No adapter present. - * 1 = Found adapter. - * - * Pseudo - * Read EISA ID - * for all valid OEM_IDs - * compare with ID read - * if equal, return 1 - * return(0 - * - * Note - * The smc pointer must be valid now. - * - ************************/ -int exist_board(struct s_smc *smc, int slot) -{ - int i ; -#ifdef MULT_OEM - SK_LOC_DECL(u_char,id[4]) ; -#endif /* MULT_OEM */ - - /* No longer valid. */ - if (smc == NULL) - return(0); - - SK_UNUSED(slot) ; - -#ifndef MULT_OEM - for (i = 0 ; i < 4 ; i++) { - if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i)) - return(0) ; - } - return(1) ; -#else /* MULT_OEM */ - for (i = 0 ; i < 4 ; i++) - id[i] = inp(SADDR(slot)+PRA(i)) ; - - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; - - for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { - if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) - continue ; - - if (is_equal_num(&id[0],&OEMID(smc,0),4)) - return (1) ; - } - return (0) ; /* No adapter found. */ -#endif /* MULT_OEM */ -} - - -int get_board_para(struct s_smc *smc, int slot) -{ - int i ; - - if (!exist_board(smc,slot)) - return(0) ; - - smc->hw.slot = slot ; -#ifndef MEM_MAPPED_IO /* if defined by the operating system */ - smc->hw.iop = SADDR(slot) ; -#endif - - if (!(inp(C0_A(0))&CFG_CARD_EN)) { - return(2) ; /* CFG_CARD_EN bit not set! */ - } - - smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ; - smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ; - - if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f) - smc->hw.eprom = opt_eproms[i] ; - else - smc->hw.eprom = 0 ; - - smc->hw.DmaWriteExtraBytes = 8 ; - - return(1) ; -} -#endif /* EISA */ - -#ifdef ISA -#ifndef MULT_OEM -const u_char sklogo[6] = SKLOGO_STR ; -#define SIZE_SKLOGO(smc) sizeof(sklogo) -#define SKLOGO(smc,i) sklogo[i] -#else /* MULT_OEM */ -#define SIZE_SKLOGO(smc) smc->hw.oem_id->oi_logo_len -#define SKLOGO(smc,i) smc->hw.oem_id->oi_logo[i] -#endif /* MULT_OEM */ - - -int exist_board(struct s_smc *smc, HW_PTR port) -{ - int i ; -#ifdef MULT_OEM - int bytes_read ; - u_char board_logo[15] ; - SK_LOC_DECL(u_char,id[4]) ; -#endif /* MULT_OEM */ - - /* No longer valid. */ - if (smc == NULL) - return(0); - - SK_UNUSED(smc) ; -#ifndef MULT_OEM - for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) { - if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) { - return(0) ; - } - } - - /* check MAC address (S&K or other) */ - for (i = 0 ; i < 3 ; i++) { - if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i)) - return(0) ; - } - return(1) ; -#else /* MULT_OEM */ - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; - board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ; - bytes_read = 1 ; - - for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { - if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) - continue ; - - /* Test all read bytes with current OEM_entry */ - /* for (i=0; (ihw.iop) -#define ADDRS(smc,a) ((a)+(smc)->hw.iop) -#endif - -/* - * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)}) + * FDDI-Fx (x := {I(SA), P(CI)}) * address calculation & function defines */ -#ifdef EISA - -/* - * Configuration PROM: !! all 8-Bit IO's !! - * |<- MAC-Address ->| - * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/ - * val: |PROD_ID0..3| | free | |00|00|5A|40| |nn|mm|00|00| - * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/ - * IO- ^ ^ ^ ^ ^ - * port 0C80 0C83 0C88 0C90 0C98 - * | \ - * | \ - * | \______________________________________________ - * EISA Expansion Board Product ID: \ - * BIT: |7 6 5 4 3 2 1 0| \ - * | PROD_ID0 | PROD_ID1 | PROD_ID2 | PROD_ID3 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |0| MAN_C0 | MAN_C1 | MAN_C2 | PROD1 | PROD0 | REV1 | REV0 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ^=reserved | product numb. | revision numb | - * MAN_Cx = compressed manufacterer code (x:=0..2) - * ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!) - */ - -#ifndef MULT_OEM -#ifndef OEM_CONCEPT -#define MAN_C0 ('S'-0x40) -#define MAN_C1 ('K'-0x40) -#define MAN_C2 ('D'-0x40) -#define PROD_ID0 (u_char)((MAN_C0<<2) | (MAN_C1>>3)) -#define PROD_ID1 (u_char)(((MAN_C1<<5) & 0xff) | MAN_C2) -#define PROD_ID2 (u_char)(1) /* prod. nr. */ -#define PROD_ID3 (u_char)(0) /* rev. nr. */ - -#ifndef OEM_USER_DATA -#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata" -#endif -#else /* OEM_CONCEPT */ - -/* MAN_C(0|1|2) no longer present (ra). */ -#define PROD_ID0 (u_char)OEM_PROD_ID0 -#define PROD_ID1 (u_char)OEM_PROD_ID1 -#define PROD_ID2 (u_char)OEM_PROD_ID2 -#define PROD_ID3 (u_char)OEM_PROD_ID3 -#endif /* OEM_CONCEPT */ - -#define SKLOGO PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3 -#endif /* MULT_OEM */ - -#define SADDRL (0) /* start address SKLOGO */ -#define SA_MAC (0x10) /* start addr. MAC_AD within the PROM */ -#define PRA_OFF (4) -#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ - -#define SKFDDI_PSZ 32 /* address PROM size */ - -/* - * address transmission from logical to physical offset address on board - */ -#define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */ -#define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */ -#define P2A(a) (0x0840|((a)<<1)) /* PLC2 (r/w) */ -#define TIA(a) (0x0880|((a)<<1)) /* Timer (r/w) */ -#define PRA(a) (0x0c80| (a)) /* configuration PROM */ -#define C0A(a) (0x0c84| (a)) /* config. RAM */ -#define C1A(a) (0x0ca0| (a)) /* IRQ-, DMA-nr., EPROM type */ -#define C2A(a) (0x0ca4| (a)) /* EPROM and PAGE selector */ - -#define CONF C0A(0) /* config RAM (card enable bit port) */ -#define PGRA C2A(0) /* Flash page register */ -#define CDID PRA(0) /* Card ID I/O port addr. offset */ - - -/* - * physical address offset + slot specific IO-Port base address - */ -#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */ -#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */ -#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */ -#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */ -#define PR_A(a) (PRA(a)+smc->hw.iop) /* config. PROM */ -#define C0_A(a) (C0A(a)+smc->hw.iop) /* config. RAM */ -#define C1_A(a) (C1A(a)+smc->hw.iop) /* config. RAM */ -#define C2_A(a) (C2A(a)+smc->hw.iop) /* config. RAM */ - - -#define CSRA 0x0008 /* control/status register address (r/w) */ -#define ISRA 0x0008 /* int. source register address (upper 8Bits) */ -#define PLC1I 0x001a /* clear PLC1 interrupt (write only) */ -#define PLC2I 0x0020 /* clear PLC2 interrupt (write only) */ -#define CSFA 0x001c /* control/status FIFO BUSY flags (read only) */ -#define RQAA 0x001c /* Request reg. (write only) */ -#define WCTA 0x001e /* word counter (r/w) */ -#define FFLAG 0x005e /* FLAG/V_FULL (FIFO almost full, write only)*/ - -#define CSR_A (CSRA+smc->hw.iop) /* control/status register address (r/w) */ -#ifdef UNIX -#define CSR_AS(smc) (CSRA+(smc)->hw.iop) /* control/status register address (r/w) */ -#endif -#define ISR_A (ISRA+smc->hw.iop) /* int. source register address (upper 8Bits) */ -#define PLC1_I (PLC1I+smc->hw.iop) /* clear PLC1 internupt (write only) */ -#define PLC2_I (PLC2I+smc->hw.iop) /* clear PLC2 interrupt (write only) */ -#define CSF_A (CSFA+smc->hw.iop) /* control/status FIFO BUSY flags (r/w) */ -#define RQA_A (RQAA+smc->hw.iop) /* Request reg. (write only) */ -#define WCT_A (WCTA+smc->hw.iop) /* word counter (r/w) */ -#define FFLAG_A (FFLAG+smc->hw.iop) /* FLAG/V_FULL (FIFO almost full, write only)*/ - -/* - * control/status register CSRA bits - */ -/* write */ -#define CS_CRESET 0x01 /* Card reset (0=reset) */ -#define CS_RESET_FIFO 0x02 /* FIFO reset (0=reset) */ -#define CS_IMSK 0x04 /* enable IRQ (1=enable, 0=disable) */ -#define CS_EN_IRQ_TC 0x08 /* enable IRQ from transfer counter */ -#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/ -#define CS_LED_0 0x40 /* switch LED 0 */ -#define CS_LED_1 0x80 /* switch LED 1 */ -/* read */ -#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */ -#define CS_SAS 0x80 /* single attachement station (=1) */ - -/* - * control/status register CSFA bits (FIFO) - */ -#define CSF_MUX0 0x01 -#define CSF_MUX1 0x02 -#define CSF_HSREQ0 0x04 -#define CSF_HSREQ1 0x08 -#define CSF_HSREQ2 0x10 -#define CSF_BUSY_DMA 0x40 -#define CSF_BUSY_FIFO 0x80 - -/* - * Interrupt source register ISRA (upper 8 data bits) read only & low activ. - */ -#define IS_MINTR1 0x0100 /* FORMAC ST1U/L & ~IMSK1U/L*/ -#define IS_MINTR2 0x0200 /* FORMAC ST2U/L & ~IMSK2U/L*/ -#define IS_PLINT1 0x0400 /* PLC1 */ -#define IS_PLINT2 0x0800 /* PLC2 */ -#define IS_TIMINT 0x1000 /* Timer 82C54-2 */ -#define IS_TC 0x2000 /* transf. counter */ - -#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC) - -/* - * CONFIG<0> RAM (C0_A()) - */ -#define CFG_CARD_EN 0x01 /* card enable */ - -/* - * CONFIG<1> RAM (C1_A()) - */ -#define CFG_IRQ_SEL 0x03 /* IRQ select (4 nr.) */ -#define CFG_IRQ_TT 0x04 /* IRQ trigger type (LEVEL/EDGE) */ -#define CFG_DRQ_SEL 0x18 /* DMA requ. (4 nr.) */ -#define CFG_BOOT_EN 0x20 /* 0=BOOT-, 1=Application Software */ -#define CFG_PROG_EN 0x40 /* V_Prog for FLASH_PROM (1=on) */ - -/* - * CONFIG<2> RAM (C2_A()) - */ -#define CFG_EPROM_SEL 0x0f /* FPROM start address selection */ -#define CFG_PAGE 0xf0 /* FPROM page selection */ - - -#define READ_PROM(a) ((u_char)inp(a)) -#define GET_PAGE(i) outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE)) -#define FPROM_SW() (inp(C1_A(0)) & CFG_BOOT_EN) - -#define MAX_PAGES 16 /* 16 pages */ -#define MAX_FADDR 0x2000 /* 8K per page */ -#define VPP_ON() outp(C1_A(0),inp(C1_A(0)) | CFG_PROG_EN) -#define VPP_OFF() outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN) - -#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA) -#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO) -#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO)) -#define BUS_CHECK() - -#ifdef UNISYS -/* For UNISYS use another macro with drv_usecewait function */ -#define CHECK_DMA() {u_long k = 1000000; \ - while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \ - if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } -#else -#define CHECK_DMA() {u_long k = 1000000 ;\ - while (k && (DMA_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } -#endif - -#define CHECK_FIFO() {u_long k = 1000000 ;\ - while (k && (FIFO_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; } - -#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\ - while (k && (DMA_FIFO_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; } - -#define GET_ISR() ~inpw(ISR_A) -#define CHECK_ISR() ~inpw(ISR_A) - -#ifndef UNIX -#ifndef WINNT -#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&\ - (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led) -#else /* WINNT */ -#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A)&\ - (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led) -#endif /* WINNT */ -#else /* UNIX */ -#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\ - (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led) -#endif - -#ifndef UNIX -#define STI_FBI() outpw(CSR_A,(inpw(CSR_A)&\ - (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led) -#else -#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\ - (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led) -#endif - -/* EISA DMA Controller */ -#define DMA_WRITE_SINGLE_MASK_BIT_M 0x0a /* Master DMA Controller */ -#define DMA_WRITE_SINGLE_MASK_BIT_S 0xd4 /* Slave DMA Controller */ -#define DMA_CLEAR_BYTE_POINTER_M 0x0c -#define DMA_CLEAR_BYTE_POINTER_S 0xd8 - -#endif /* EISA */ - -#ifdef MCA - -/* - * POS Register: !! all I/O's are 8-Bit !! - */ -#define POS_SYS_SETUP 0x94 /* system setup register */ -#define POS_SYSTEM 0xff /* system mode */ - -#define POS_CHANNEL_POS 0x96 /* register slot ID */ -#define POS_CHANNEL_BIT 0x08 /* mask for -"- */ - -#define POS_BASE 0x100 /* POS base address */ -#define POS_ID_LOW POS_BASE /* card ID low */ -#define POS_ID_HIGH (POS_BASE+1) /* card ID high */ -#define POS_102 (POS_BASE+2) /* card en., arbitration level .. */ -#define POS_103 (POS_BASE+3) /* FPROM addr, page */ -#define POS_104 (POS_BASE+4) /* I/O, IRQ */ -#define POS_105 (POS_BASE+5) /* POS_CHCK */ -#define POS_106 (POS_BASE+6) /* to read VPD */ -#define POS_107 (POS_BASE+7) /* added without function */ - -/* FM1 card IDs */ -#define FM1_CARD_ID0 0x83 -#define FM1_CARD_ID1 0 - -#define FM1_IBM_ID0 0x9c -#define FM1_IBM_ID1 0x8f - - -/* FM2 card IDs */ -#define FM2_CARD_ID0 0xab -#define FM2_CARD_ID1 0 - -#define FM2_IBM_ID0 0x7e -#define FM2_IBM_ID1 0x8f - -/* Board revision. */ -#define FM1_REV 0 -#define FM2_REV 1 - -#define MAX_SLOT 8 - -/* - * POS_102 - */ -#define POS_CARD_EN 0x01 /* card enable =1 */ -#define POS_SDAT_EN 0x02 /* enable 32-bit streaming data mode */ -#define POS_EN_CHKINT 0x04 /* enable int. from check line asserted */ -#define POS_EN_BUS_ERR 0x08 /* enable int. on invalid busmaster transf. */ -#define POS_FAIRNESS 0x10 /* fairnes on =1 */ -/* attention: arbitration level used with bit 0 POS 105 */ -#define POS_LARBIT 0xe0 /* arbitration level (0,0,0)->level = 0x8 - (1,1,1)->level = 0xf */ -/* - * POS_103 - */ -#define POS_PAGE 0x07 /* FPROM page selection */ -#define POS_BOOT_EN 0x08 /* boot PROM enable =1 */ -#define POS_MSEL 0x70 /* memory start address for FPROM mapping */ -#define PROG_EN 0x80 /* FM1: Vpp prog on/off */ -#define POS_SDR 0x80 /* FM2: Streaming data bit */ - -/* - * POS_104 - */ -#define POS_IOSEL 0x3f /* selected I/O base address */ -#define POS_IRQSEL 0xc0 /* selected interrupt */ - -/* - * POS_105 - */ -#define POS_CHCK 0x80 -#define POS_SYNC_ERR 0x20 /* FM2: synchronous error reporting */ -#define POS_PAR_DATA 0x10 /* FM2: data parity enable bit */ -#define POS_PAR_ADDR 0x08 /* FM2: address parity enable bit */ -#define POS_IRQHSEL 0x02 /* FM2: Highest bit for IRQ_selection */ -#define POS_HARBIT 0x01 /* Highest bit in Bus arbitration selection */ - -#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ -#define PRA_OFF (0) -#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ - -/* - * address transmission from logical to physical offset address on board - */ -#define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */ -#define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */ -#define P1(a) (0x0080|((a)<<1)) /* PLC1 (r/w) */ -#define TI(a) (0x0060|((a)<<1)) /* Timer (r/w) */ -#define PR(a) (0x0040|((a)<<1)) /* configuration PROM */ -#define CS(a) (0x0020| (a)) /* control/status */ -#define FF(a) (0x0010|((a)<<1)) /* FIFO ASIC */ -#define CT(a) (0x0000|((a)<<1)) /* counter */ - -/* - * counter - */ -#define ACLA CT(0) /* address counter low */ -#define ACHA CT(1) /* address counter high */ -#define BCN CT(2) /* byte counter */ -#define MUX CT(3) /* MUX-register */ -#define WCN CT(0x08) /* word counter */ -#define FFLG CT(0x09) /* FIFO Flags */ - -/* - * test/control register (FM2 only) - */ -#define CNT_TST 0x018 /* Counter test control register */ -#define CNT_STP 0x01a /* Counter test step reg. (8 Bit) */ - -/* - * CS register (read only) - */ -#define CSRA CS(0) /* control/status register address */ -#define CSFA CS(2) /* control/status FIFO BUSY ... */ -#define ISRA CS(4) /* first int. source register address */ -#define ISR2 CS(6) /* second int. source register address */ -#define LEDR CS(0x0c) /* LED register r/w */ -#define CSIL CS(0x10) /* I/O mapped POS_ID_low (100) */ -#define CSIH CS(0x12) /* - " - POS_ID_HIGH (101) */ -#define CSA CS(0x14) /* - " - POS_102 */ -#define CSM CS(0x0e) /* - " - POS_103 */ -#define CSM_FM1 CS(0x16) /* - " - POS_103 (copy in FM1) */ -#define CSI CS(0x18) /* - " - POS_104 */ -#define CSS CS(0x1a) /* - " - POS_105 */ -#define CSP_06 CS(0x1c) /* - " - POS_106 */ -#define WDOG_ST 0x1c /* Watchdog status (FM2 only) */ -#define WDOG_EN 0x1c /* Watchdog enabling (FM2 only, 8Bit) */ -#define WDOG_DIS 0x1e /* Watchdog disabling (FM2 only, 8Bit) */ - -#define PGRA CSM /* Flash page register */ - - -#define WCTA FF(0) /* word counter */ -#define FFLAG FF(1) /* FLAG/V_FULL (FIFO almost full, write only)*/ - -/* - * Timer register (FM2 only) - */ -#define RTM_CNT 0x28 /* RTM Counter */ -#define TI_DIV 0x60 /* Timer Prescaler */ -#define TI_CH1 0x62 /* Timer channel 1 counter */ -#define TI_STOP 0x64 /* Stop timer on channel 1 */ -#define TI_STRT 0x66 /* Start timer on channel 1 */ -#define TI_INI2 0x68 /* Timer: Bus master preemption */ -#define TI_CNT2 0x6a /* Timer */ -#define TI_INI3 0x6c /* Timer: Streaming data */ -#define TI_CNT3 0x6e /* Timer */ -#define WDOG_LO 0x70 /* Watchdog counter low */ -#define WDOG_HI 0x72 /* Watchdog counter high */ -#define RTM_PRE 0x74 /* restr. token prescaler */ -#define RTM_TIM 0x76 /* restr. token timer */ - -/* - * Recommended Timeout values (for FM2 timer only) - */ -#define TOUT_BM_PRE 188 /* 3.76 usec */ -#define TOUT_S_DAT 374 /* 7.48 usec */ - -/* - * CS register (write only) - */ -#define HSR(p) CS(0x18|(p)) /* Host request register */ - -#define RTM_PUT 0x36 /* restr. token counter write */ -#define RTM_GET 0x28 /* - " - clear */ -#define RTM_CLEAR 0x34 /* - " - read */ - -/* - * BCN Bit definitions - */ -#define BCN_BUSY 0x8000 /* DMA Busy flag */ -#define BCN_AZERO 0x4000 /* Almost zero flag (BCN < 4) */ -#define BCN_STREAM 0x2000 /* Allow streaming data (BCN >= 8) */ - -/* - * WCN Bit definitions - */ -#define WCN_ZERO 0x2000 /* Zero flag (counted to zero) */ -#define WCN_AZERO 0x1000 /* Almost zero flag (BCN < 4) */ - -/* - * CNT_TST Bit definitions - */ -#define CNT_MODE 0x01 /* Go into test mode */ -#define CNT_D32 0x02 /* 16/32 BIT test mode */ - -/* - * FIFO Flag FIFO Flags/Vfull register - */ -#define FF_VFULL 0x003f /* V_full value mask */ -#define FFLG_FULL 0x2000 /* FULL flag */ -#define FFLG_A_FULL 0x1000 /* Almost full flag */ -#define FFLG_VFULL 0x0800 /* V_full Flag */ -#define FFLG_A_EMP 0x0400 /* almost empty flag */ -#define FFLG_EMP 0x0200 /* empty flag */ -#define FFLG_T_EMP 0x0100 /* totally empty flag */ - -/* - * WDOG Watchdog status register - */ -#define WDOG_ALM 0x01 /* Watchdog alarm Bit */ -#define WDOG_ACT 0x02 /* Watchdog active Bit */ - -/* - * CS(0) CONTROLS - */ -#define CS_CRESET 0x0001 -#define FIFO_RST 0x0002 -#define CS_IMSK 0x0004 -#define EN_IRQ_CHCK 0x0008 -#define EN_IRQ_TOKEN 0x0010 -#define EN_IRQ_TC 0x0020 -#define TOKEN_STATUS 0x0040 -#define RTM_CHANGE 0x0080 - -#define CS_SAS 0x0100 -#define CS_BYSTAT 0x0200 /* bypass connected (0=conn.) */ -#define CS_BYPASS 0x0400 /* bypass on/off indication */ - -/* - * CS(2) FIFOSTAT - */ -#define HSREQ 0x0007 -#define BIGDIR 0x0008 -#define CSF_BUSY_FIFO 0x0010 -#define CSF_BUSY_DMA 0x0020 -#define SLOT_32 0x0040 - -#define LED_0 0x0001 -#define LED_1 0x0002 -#define LED_2 0x0100 - -#define MAX_PAGES 8 /* pages */ -#define MAX_FADDR 0x4000 /* 16K per page */ - -/* - * IRQ = ISRA || ISR2 ; - * - * ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ; - * ISR2 = IRQ_TC_EN && IS_TC ; - * - * IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) || - * (IRQ_EN_TOKEN && IS_TOKEN) ; - * IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ; - */ -/* - * ISRA !!! activ high !!! - */ -#define IS_MINTR1 0x0001 /* FORMAC ST1U/L & ~IMSK1U/L*/ -#define IS_MINTR2 0x0002 /* FORMAC ST2U/L & ~IMSK2U/L*/ -#define IS_PLINT1 0x0004 /* PLC1 */ -#define IS_PLINT2 0x0008 /* PLC2 */ -#define IS_TIMINT 0x0010 /* Timer 82C54-2 */ -#define IS_TOKEN 0x0020 /* restrictet token monitoring */ -#define IS_CHCK_L 0x0040 /* check line asserted */ -#define IS_BUSERR 0x0080 /* bus error */ -/* - * ISR2 - */ -#define IS_TC 0x0001 /* terminal count irq */ -#define IS_SFDBKRTN 0x0002 /* selected feedback return */ -#define IS_D16 0x0004 /* DS16 */ -#define IS_D32 0x0008 /* DS32 */ -#define IS_DPEI 0x0010 /* Data Parity Indication */ - -#define ALL_IRSR 0x00ff - -#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */ -#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */ -#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */ -#define TI_A(a) ADDR(TI(a)) /* Timer (r/w) FM1 only! */ -#define PR_A(a) ADDR(PR(a)) /* config. PROM */ -#define CS_A(a) ADDR(CS(a)) /* control/status */ - -#define ISR1_A ADDR(ISRA) /* first int. source register address */ -#define ISR2_A ADDR(ISR2) /* second -"- */ -#define CSR_A ADDR(CSRA) /* control/status register address */ -#define CSF_A ADDR(CSFA) /* control/status FIFO BUSY flags (r/w) */ - -#define CSIL_A ADDR(CSIL) /* I/O mapped POS_ID_low (102) */ -#define CSIH_A ADDR(CSIH) /* - " - POS_ID_HIGH (101) */ -#define CSA_A ADDR(CSA) /* - " - POS_102 */ -#define CSI_A ADDR(CSI) /* - " - POS_104 */ -#define CSM_A ADDR(CSM) /* - " - POS_103 */ -#define CSM_FM1_A ADDR(CSM_FM1) /* - " - POS_103 (2nd copy, FM1) */ -#define CSP_06_A ADDR(CSP_06) /* - " - POS_106 */ - -#define WCT_A ADDR(WCTA) /* word counter (r/w) */ -#define FFLAG_A ADDR(FFLAG) /* FLAG/V_FULL (FIFO almost full, write only)*/ - -#define ACL_A ADDR(ACLA) /* address counter low */ -#define ACH_A ADDR(ACHA) /* address counter high */ -#define BCN_A ADDR(BCN) /* byte counter */ -#define MUX_A ADDR(MUX) /* MUX-register */ - -#define ISR_A ADDR(ISRA) /* Interrupt Source Register */ -#define FIFO_RESET_A ADDR(FIFO_RESET) /* reset the FIFO */ -#define FIFO_EN_A ADDR(FIFO_EN) /* enable the FIFO */ - -#define WDOG_EN_A ADDR(WDOG_EN) /* reset and start the WDOG */ -#define WDOG_DIS_A ADDR(WDOG_DIS) /* disable the WDOG */ -/* - * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A) - */ -#define HSR_A(p) ADDR(HSR(p)) /* Host request register */ - -#define STAT_BYP 0 /* bypass station */ -#define STAT_INS 2 /* insert station */ -#define BYPASS(o) CS(0x10|(o)) /* o=STAT_BYP || STAT_INS */ - -#define IRQ_TC_EN CS(0x0b) /* enable/disable IRQ on TC */ -#define IRQ_TC_DIS CS(0x0a) -#define IRQ_TOKEN_EN CS(9) /* enable/disable IRQ on restr. Token */ -#define IRQ_TOKEN_DIS CS(8) -#define IRQ_CHCK_EN CS(7) /* -"- IRQ after CHCK line */ -#define IRQ_CHCK_DIS CS(6) -#define IRQ_OTH_EN CS(5) /* -"- other IRQ's */ -#define IRQ_OTH_DIS CS(4) -#define FIFO_EN CS(3) /* disable (reset), enable FIFO */ -#define FIFO_RESET CS(2) -#define CARD_EN CS(1) /* disable (reset), enable card */ -#define CARD_DIS CS(0) - -#define LEDR_A ADDR(LEDR) /* D0=green, D1=yellow, D8=L2 */ -#define PAGE_RG_A ADDR(CSM) /* D<2..0> */ -#define IRQ_CHCK_EN_A ADDR(IRQ_CHCK_EN) -#define IRQ_CHCK_DIS_A ADDR(IRQ_CHCK_DIS) - -#define GET_PAGE(bank) outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\ - (~POS_PAGE)) |(int) (bank)) -#define VPP_ON() if (smc->hw.rev == FM1_REV) { \ - outpw(PAGE_RG_A, \ - (inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \ - } -#define VPP_OFF() if (smc->hw.rev == FM1_REV) { \ - outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \ - } - -#define SKFDDI_PSZ 16 /* address PROM size */ - -#define READ_PROM(a) ((u_char)inp(a)) - -#define GET_ISR() ~inpw(ISR1_A) -#ifndef TCI -#define CHECK_ISR() ~inpw(ISR1_A) -#define CHECK_ISR_SMP(iop) ~inpw((iop)+ISRA) -#else -#define CHECK_ISR() (~inpw(ISR1_A) | ~inpw(ISR2_A)) -#define CHECK_ISR_SMP(iop) (~inpw((iop)+ISRA) | ~inpw((iop)+ISR2)) -#endif - -#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA) -#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO) -#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO)) -#define BUS_CHECK() { int i ; \ - if ((i = GET_ISR()) & IS_BUSERR) \ - SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \ - if (i & IS_CHCK_L) \ - SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \ - } - -#define CHECK_DMA() { u_long k = 10000 ; \ - while (k && (DMA_BUSY())) { \ - k-- ; \ - BUS_CHECK() ; \ - } \ - if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } - -#define CHECK_FIFO() {u_long k = 1000000 ;\ - while (k && (FIFO_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; } - -#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\ - while (k && (DMA_FIFO_BUSY())) { \ - k-- ;\ - BUS_CHECK() ; \ - } \ - if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; } - -#ifndef UNIX -#define CLI_FBI() outp(ADDR(IRQ_OTH_DIS),0) -#else -#define CLI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_DIS),0) -#endif - -#ifndef TCI -#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) -#else -#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) ;\ - outp((iop)+IRQ_TC_DIS,0) -#endif - -#ifndef UNIX -#define STI_FBI() outp(ADDR(IRQ_OTH_EN),0) -#else -#define STI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_EN),0) -#endif - -/* - * Terminal count primitives - */ -#define CLI_TCI(smc) outp(ADDRS((smc),IRQ_TC_DIS),0) -#define STI_TCI(smc) outp(ADDRS((smc),IRQ_TC_EN),0) -#define CHECK_TC(smc,k) {(k) = 10000 ;\ - while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; } - -#endif /* MCA */ - -#ifdef ISA - -/* - * address transmission from logic NPADDR6-0 to physical offset address on board - */ -#define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */ -#define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/ -#define P1A(a) (0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC1 (r/w) */ -#define P2A(a) (0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC2 (r/w) */ -#define TIA(a) (0x6000|(((a)&0x03)<<1)) /* Timer (r/w) */ - -#define ISRA 0x0000 /* int. source register address (read only) */ -#define ACLA 0x0000 /* address counter low address (write only) */ -#define ACHA 0x0002 /* address counter high address (write only) */ -#define TRCA 0x0004 /* transfer counter address (write only) */ -#define PGRA 0x0006 /* page register address (write only) */ -#define RQAA 0x2000 /* Request reg. (write only) */ -#define CSRA 0x3000 /* control/status register address (r/w) */ - -/* - * physical address offset + IO-Port base address - */ -#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */ -#define PR_A(a) (PRA(a)+smc->hw.iop) /* PROM (read only)*/ -#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */ -#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */ -#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */ - -#define ISR_A (0x0000+smc->hw.iop) /* int. source register address (read only) */ -#define ACL_A (0x0000+smc->hw.iop) /* address counter low address (write only) */ -#define ACH_A (0x0002+smc->hw.iop) /* address counter high address (write only)*/ -#define TRC_A (0x0004+smc->hw.iop) /* transfer counter address (write only) */ -#define PGR_A (0x0006+smc->hw.iop) /* page register address (write only) */ -#define RQA_A (0x2000+smc->hw.iop) /* Request reg. (write only) */ -#define CSR_A (0x3000+smc->hw.iop) /* control/status register address (r/w) */ -#ifdef UNIX -#define CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */ -#endif -#define PLC1_I (0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */ -#define PLC2_I (0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */ - -#ifndef MULT_OEM -#ifndef OEM_CONCEPT -#define SKLOGO_STR "SKFDDI" -#else /* OEM_CONCEPT */ -#define SKLOGO_STR OEM_FDDI_LOGO -#endif /* OEM_CONCEPT */ -#endif /* MULT_OEM */ -#define SADDRL (24) /* start address SKLOGO */ -#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ -#define PRA_OFF (0) -#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ - -#define CDID (PRA(SADDRL)) /* Card ID int/O port addr. offset */ -#define NEXT_CDID ((PRA(SADDRL+1)) - CDID) - -#define SKFDDI_PSZ 32 /* address PROM size */ - -#define READ_PROM(a) ((u_char)inpw(a)) -#define GET_PAGE(i) outpw(PGR_A,(int)(i)) - -#define MAX_PAGES 16 /* 16 pages */ -#define MAX_FADDR 0x2000 /* 8K per page */ -#define VPP_OFF() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS))) -#define VPP_ON() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \ - CS_VPPSW) - -/* - * control/status register CSRA bits (log. addr: 0x3000) - */ -/* write */ -#define CS_CRESET 0x01 /* Card reset (0=reset) */ -#define CS_IMSK 0x02 /* enable IRQ (1=enable, 0=disable) */ -#define CS_RESINT1 0x04 /* PLINT1 reset */ -#define CS_VPPSW 0x10 /* 12V power switch (0=off, 1=on) */ -#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/ -#define CS_RESINT2 0x40 /* PLINT2 reset */ -/* read */ -#define CS_BUSY 0x04 /* master transfer activ (=1) */ -#define CS_SW_EPROM 0x08 /* 0=Application Soft. 1=BOOT-EPROM */ -#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */ -#define CS_SAS 0x80 /* single attachement station (=1) */ - -/* - * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ. - */ -#define IS_MINTR1 0x01 /* FORMAC ST1U/L && ~IMSK1U/L*/ -#define IS_MINTR2 0x02 /* FORMAC ST2U/L && ~IMSK2U/L*/ -#define IS_PLINT1 0x04 /* PLC1 */ -#define IS_PLINT2 0x08 /* PLC2 */ -#define IS_TIMINT 0x10 /* Timer 82C54-2 */ - -#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT) - -#define FPROM_SW() (inpw(CSR_A)&CS_SW_EPROM) -#define DMA_BUSY() (inpw(CSR_A)&CS_BUSY) -#define CHECK_FIFO() -#define BUS_CHECK() - -/* - * set Host Request register (wr.) - */ -#define SET_HRQ(qup) outpw(RQA_A+((qup)<<1),0) - -#ifndef UNIX -#ifndef WINNT -#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW))) -#else -#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A) & \ - (CS_CRESET|CS_BYPASS|CS_VPPSW))) -#endif -#else -#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \ - (CS_CRESET|CS_BYPASS|CS_VPPSW))) -#endif - -#ifndef UNIX -#define STI_FBI() outpw(CSR_A,(inpw(CSR_A) & \ - (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK) -#else -#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \ - (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK) -#endif - -#define CHECK_DMA() {unsigned k = 10000 ;\ - while (k && (DMA_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } - -#define GET_ISR() ~inpw(ISR_A) - -#endif /* ISA */ - /*--------------------------------------------------------------------------*/ #ifdef PCI diff --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/skfp/h/skfbiinc.h index 79d55ad2cd2a..ac2d7192f1ca 100644 --- a/drivers/net/skfp/h/skfbiinc.h +++ b/drivers/net/skfp/h/skfbiinc.h @@ -22,32 +22,6 @@ */ #define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1) -#ifdef ISA -#define DMA_BUSY_CHECK CSRA -#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT) -#define HRQR (RQAA+(RQ_RRQ<<1)) -#define HRQW (RQAA+(RQ_WA2<<1)) -#define HRQA0 (RQAA+(RQ_WA0<<1)) -#define HRQSQ (RQAA+(RQ_WSQ<<1)) -#endif - -#ifdef EISA -#define DMA_BUSY_CHECK CSRA -#define DMA_HIGH_WORD 0x0400 -#define DMA_MASK_M 0x0a -#define DMA_MODE_M 0x0b -#define DMA_BYTE_PTR_M 0x0c -#define DMA_MASK_S 0x0d4 -#define DMA_MODE_S 0x0d6 -#define DMA_BYTE_PTR_S 0x0d8 -#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC) -#endif /* EISA */ - -#ifdef MCA -#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ - IS_CHCK_L | IS_BUSERR) -#endif - #ifdef PCI #define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ diff --git a/drivers/net/skfp/h/targethw.h b/drivers/net/skfp/h/targethw.h index 22c4923241d3..626dc7263591 100644 --- a/drivers/net/skfp/h/targethw.h +++ b/drivers/net/skfp/h/targethw.h @@ -53,11 +53,6 @@ struct s_oem_ids { u_char oi_sub_id[4] ; /* sub id bytes, representation as */ /* defined by hardware, */ #endif -#ifdef ISA - u_char oi_logo_len ; /* the length of the adapter logo */ - u_char oi_logo[6] ; /* the adapter logo */ - u_char oi_reserved1 ; -#endif /* ISA */ } ; #endif /* MULT_OEM */ @@ -70,43 +65,17 @@ struct s_smt_hw { short dma ; /* DMA channel */ short irq ; /* IRQ level */ short eprom ; /* FLASH prom */ -#ifndef PCI - short DmaWriteExtraBytes ; /* add bytes for DMA write */ -#endif #ifndef SYNC u_short n_a_send ; /* pending send requests */ #endif -#if (defined(EISA) || defined(MCA) || defined(PCI)) +#if defined(PCI) short slot ; /* slot number */ short max_slots ; /* maximum number of slots */ -#endif - -#if (defined(PCI) || defined(MCA)) short wdog_used ; /* TRUE if the watch dog is used */ #endif -#ifdef MCA - short slot_32 ; /* 32bit slot (1) or 16bit slot (0) */ - short rev ; /* Board revision (FMx_REV). */ - short VFullRead ; /* V_full value for DMA read */ - short VFullWrite ; /* V_full value for DMA write */ -#endif - -#ifdef EISA - short led ; /* LED for FE card */ - - short dma_rmode ; /* read mode */ - short dma_wmode ; /* write mode */ - short dma_emode ; /* extend mode */ - - /* DMA controller channel dependent io addresses */ - u_short dma_base_word_count ; - u_short dma_base_address ; - u_short dma_base_address_page ; -#endif - #ifdef PCI u_short pci_handle ; /* handle to access the BIOS func */ u_long is_imask ; /* int maske for the int source reg */ diff --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c index e01f8a0f35c6..053151468f93 100644 --- a/drivers/net/skfp/hwt.c +++ b/drivers/net/skfp/hwt.c @@ -77,25 +77,10 @@ void hwt_start(struct s_smc *smc, u_long time) */ if (!cnt) cnt++ ; -#ifndef PCI - /* - * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0 - * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT) - */ - OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ - OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */ - OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */ - /* - * start timer by switching counter 0 to mode 3 - * T0 resolution 16 us (CLK0=0.16us) - */ - OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */ - OUT_82c54_TIMER(0,100) ; /* LSB */ - OUT_82c54_TIMER(0,0) ; /* MSB */ -#else /* PCI */ + outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */ outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */ -#endif /* PCI */ + smc->hw.timer_activ = TRUE ; } @@ -115,15 +100,8 @@ void hwt_start(struct s_smc *smc, u_long time) ************************/ void hwt_stop(struct s_smc *smc) { -#ifndef PCI - /* stop counter 0 by switching to mode 0 */ - OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */ - OUT_82c54_TIMER(0,0) ; /* LSB */ - OUT_82c54_TIMER(0,0) ; /* MSB */ -#else /* PCI */ outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; -#endif /* PCI */ smc->hw.timer_activ = FALSE ; } @@ -168,11 +146,6 @@ void hwt_init(struct s_smc *smc) void hwt_restart(struct s_smc *smc) { hwt_stop(smc) ; -#ifndef PCI - OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ - OUT_82c54_TIMER(1,1 ) ; /* LSB */ - OUT_82c54_TIMER(1,0 ) ; /* MSB */ -#endif } /************************ @@ -191,21 +164,12 @@ void hwt_restart(struct s_smc *smc) u_long hwt_read(struct s_smc *smc) { u_short tr ; -#ifndef PCI - u_short is ; -#else u_long is ; -#endif if (smc->hw.timer_activ) { hwt_stop(smc) ; -#ifndef PCI - OUT_82c54_TIMER(3,1<<6) ; /* latch command */ - tr = IN_82c54_TIMER(1) & 0xff ; - tr += (IN_82c54_TIMER(1) & 0xff)<<8 ; -#else /* PCI */ tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; -#endif /* PCI */ + is = GET_ISR() ; /* Check if timer expired (or wraparound). */ if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) { From eda105317fece79fa7e8478214ff7450f5a3f9dd Mon Sep 17 00:00:00 2001 From: Yoann Padioleau Date: Mon, 23 Jul 2007 15:18:21 +0200 Subject: [PATCH 1296/2804] dev->priv to netdev_priv(dev), drivers/net/tokenring/ Replacing accesses to dev->priv to netdev_priv(dev). The replacment is safe when netdev_priv is used to access a private structure that is right next to the net_device structure in memory. Cf http://groups.google.com/group/comp.os.linux.development.system/browse_thread/thread/de19321bcd94dbb8/0d74a4adcd6177bd This is the case when the net_device structure was allocated with a call to alloc_netdev or one of its derivative. Here is an excerpt of the semantic patch that performs the transformation @ rule1 @ type T; struct net_device *dev; @@ dev = ( alloc_netdev | alloc_etherdev | alloc_trdev ) (sizeof(T), ...) @ rule1bis @ struct net_device *dev; expression E; @@ dev->priv = E @ rule2 depends on rule1 && !rule1bis @ struct net_device *dev; type rule1.T; @@ - (T*) dev->priv + netdev_priv(dev) PS: I have performed the same transformation on the whole kernel and it affects around 70 files, most of them in drivers/net/. Should I split my patch for each subnet directories ? (wireless/, wan/, etc) Thanks to Thomas Surrel for helping me refining my semantic patch. Signed-off-by: Yoann Padioleau 3c359.c | 58 +++++++++++++++++++++++++++++----------------------------- ibmtr.c | 38 +++++++++++++++++++------------------- lanstreamer.c | 32 ++++++++++++++++---------------- madgemc.c | 4 ++-- olympic.c | 36 ++++++++++++++++++------------------ tmspci.c | 4 ++-- 6 files changed, 86 insertions(+), 86 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/tokenring/3c359.c | 58 ++++++++++++++--------------- drivers/net/tokenring/ibmtr.c | 38 +++++++++---------- drivers/net/tokenring/lanstreamer.c | 32 ++++++++-------- drivers/net/tokenring/madgemc.c | 4 +- drivers/net/tokenring/olympic.c | 36 +++++++++--------- drivers/net/tokenring/tmspci.c | 4 +- 6 files changed, 86 insertions(+), 86 deletions(-) diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 9f1b6ab9c228..6612db8ec215 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -156,7 +156,7 @@ static void print_rx_state(struct net_device *dev) ; static void print_tx_state(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); struct xl_tx_desc *txd ; u8 __iomem *xl_mmio = xl_priv->xl_mmio ; int i ; @@ -179,7 +179,7 @@ static void print_tx_state(struct net_device *dev) static void print_rx_state(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); struct xl_rx_desc *rxd ; u8 __iomem *xl_mmio = xl_priv->xl_mmio ; int i ; @@ -213,7 +213,7 @@ static void print_rx_state(struct net_device *dev) static u16 xl_ee_read(struct net_device *dev, int ee_addr) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; /* Wait for EEProm to not be busy */ @@ -245,7 +245,7 @@ static u16 xl_ee_read(struct net_device *dev, int ee_addr) static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; /* Wait for EEProm to not be busy */ @@ -305,11 +305,11 @@ static int __devinit xl_probe(struct pci_dev *pdev, pci_release_regions(pdev) ; return -ENOMEM ; } - xl_priv = dev->priv ; + xl_priv = netdev_priv(dev); #if XL_DEBUG printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n", - pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ; + pdev, dev, netdev_priv(dev), (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start); #endif dev->irq=pdev->irq; @@ -365,7 +365,7 @@ static int __devinit xl_probe(struct pci_dev *pdev, static int __devinit xl_init(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); printk(KERN_INFO "%s \n", version); printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n", @@ -385,7 +385,7 @@ static int __devinit xl_init(struct net_device *dev) static int xl_hw_reset(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; unsigned long t ; u16 i ; @@ -568,7 +568,7 @@ static int xl_hw_reset(struct net_device *dev) static int xl_open(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; u8 i ; u16 hwaddr[3] ; /* Should be u8[6] but we get word return values */ @@ -726,7 +726,7 @@ static int xl_open(struct net_device *dev) static int xl_open_hw(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; u16 vsoff ; char ver_str[33]; @@ -875,7 +875,7 @@ static int xl_open_hw(struct net_device *dev) static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */ { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); int prev_ring_loc ; prev_ring_loc = (xl_priv->rx_ring_tail + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1); @@ -890,7 +890,7 @@ static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on static void xl_rx(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; struct sk_buff *skb, *skb2 ; int frame_length = 0, copy_len = 0 ; @@ -997,7 +997,7 @@ static void xl_rx(struct net_device *dev) static void xl_reset(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; unsigned long t; @@ -1020,7 +1020,7 @@ static void xl_reset(struct net_device *dev) static void xl_freemem(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv ; + struct xl_private *xl_priv=netdev_priv(dev); int i ; for (i=0;ipriv; + struct xl_private *xl_priv =netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u16 intstatus, macstatus ; @@ -1171,7 +1171,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id) static int xl_xmit(struct sk_buff *skb, struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); struct xl_tx_desc *txd ; int tx_head, tx_tail, tx_prev ; unsigned long flags ; @@ -1232,7 +1232,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) static void xl_dn_comp(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; struct xl_tx_desc *txd ; @@ -1268,7 +1268,7 @@ static void xl_dn_comp(struct net_device *dev) static int xl_close(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; unsigned long t ; @@ -1366,7 +1366,7 @@ static int xl_close(struct net_device *dev) static void xl_set_rx_mode(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); struct dev_mc_list *dmi ; unsigned char dev_mc_address[4] ; u16 options ; @@ -1407,7 +1407,7 @@ static void xl_set_rx_mode(struct net_device *dev) static void xl_srb_bh(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u8 srb_cmd, ret_code ; int i ; @@ -1476,14 +1476,14 @@ static void xl_srb_bh(struct net_device *dev) static struct net_device_stats * xl_get_stats(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); return (struct net_device_stats *) &xl_priv->xl_stats; } static int xl_set_mac_address (struct net_device *dev, void *addr) { struct sockaddr *saddr = addr ; - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); if (netif_running(dev)) { printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; @@ -1504,7 +1504,7 @@ static int xl_set_mac_address (struct net_device *dev, void *addr) static void xl_arb_cmd(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u8 arb_cmd ; u16 lan_status, lan_status_diff ; @@ -1632,7 +1632,7 @@ static void xl_arb_cmd(struct net_device *dev) static void xl_asb_cmd(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; if (xl_priv->asb_queued == 1) @@ -1663,7 +1663,7 @@ static void xl_asb_cmd(struct net_device *dev) */ static void xl_asb_bh(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u8 ret_code ; @@ -1691,7 +1691,7 @@ static void xl_asb_bh(struct net_device *dev) static void xl_srb_cmd(struct net_device *dev, int srb_cmd) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; switch (srb_cmd) { @@ -1748,7 +1748,7 @@ static void xl_srb_cmd(struct net_device *dev, int srb_cmd) static void xl_wait_misr_flags(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; int i ; @@ -1773,7 +1773,7 @@ static void xl_wait_misr_flags(struct net_device *dev) static int xl_change_mtu(struct net_device *dev, int mtu) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv; + struct xl_private *xl_priv = netdev_priv(dev); u16 max_mtu ; if (xl_priv->xl_ring_speed == 4) @@ -1795,7 +1795,7 @@ static int xl_change_mtu(struct net_device *dev, int mtu) static void __devexit xl_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); unregister_netdev(dev); iounmap(xl_priv->xl_mmio) ; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 1e8958ee2d0a..51409698fe25 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -327,7 +327,7 @@ static void ibmtr_cleanup_card(struct net_device *dev) release_region(dev->base_addr, IBMTR_IO_EXTENT); { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); iounmap(ti->mmio); iounmap(ti->sram_virt); } @@ -384,7 +384,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0; void __iomem * t_mmio = NULL; - struct tok_info *ti = dev->priv; + struct tok_info *ti = netdev_priv(dev); void __iomem *cd_chanid; unsigned char *tchanid, ctemp; #ifndef PCMCIA @@ -823,7 +823,7 @@ static unsigned char __devinit get_sram_size(struct tok_info *adapt_info) static int __devinit trdev_init(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); SET_PAGE(ti->srb_page); ti->open_failure = NO ; @@ -846,7 +846,7 @@ static int tok_init_card(struct net_device *dev) unsigned long i; PIOaddr = dev->base_addr; - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); /* Special processing for first interrupt after reset */ ti->do_tok_int = FIRST_INT; /* Reset adapter */ @@ -868,7 +868,7 @@ static int tok_init_card(struct net_device *dev) /*****************************************************************************/ static int tok_open(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); int i; /*the case we were left in a failure state during a previous open */ @@ -927,7 +927,7 @@ static void tok_open_adapter(unsigned long dev_addr) struct tok_info *ti; int i; - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); SET_PAGE(ti->init_srb_page); writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); for (i = 0; i < sizeof(struct dir_open_adapter); i++) @@ -962,7 +962,7 @@ static void tok_open_adapter(unsigned long dev_addr) static void open_sap(unsigned char type, struct net_device *dev) { int i; - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); SET_PAGE(ti->srb_page); for (i = 0; i < sizeof(struct dlc_open_sap); i++) @@ -986,7 +986,7 @@ static void open_sap(unsigned char type, struct net_device *dev) static void tok_set_multicast_list(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); struct dev_mc_list *mclist; unsigned char address[4]; @@ -1029,7 +1029,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) { struct tok_info *ti; unsigned long flags; - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); netif_stop_queue(dev); @@ -1051,7 +1051,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) static int tok_close(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); /* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */ /* unloading the module from memory, and then if a timer pops, ouch */ @@ -1094,7 +1094,7 @@ static void __iomem *map_address(struct tok_info *ti, unsigned index, __u8 *page static void dir_open_adapter (struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); unsigned char ret_code; __u16 err; @@ -1179,7 +1179,7 @@ static irqreturn_t tok_interrupt(int irq, void *dev_id) #if TR_VERBOSE DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq); #endif - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); if (ti->sram_phys & 1) return IRQ_NONE; /* PCMCIA card extraction flag */ spin_lock(&(ti->lock)); @@ -1498,7 +1498,7 @@ static void initial_tok_int(struct net_device *dev) struct tok_info *ti; unsigned char init_status; /*BMS 12/2000*/ - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); ti->do_tok_int = NOT_FIRST; @@ -1560,7 +1560,7 @@ static void initial_tok_int(struct net_device *dev) static void tr_tx(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data; unsigned int hdr_len; __u32 dhb=0,dhb_base; @@ -1674,7 +1674,7 @@ static void tr_tx(struct net_device *dev) static void tr_rx(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); __u32 rbuffer; void __iomem *rbuf, *rbufdata, *llc; __u8 rbuffer_page = 0; @@ -1846,7 +1846,7 @@ static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) void tok_rerun(unsigned long dev_addr){ struct net_device *dev = (struct net_device *)dev_addr; - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); if ( ti->open_action == RESTART){ ti->do_tok_int = FIRST_INT; @@ -1868,7 +1868,7 @@ static void ibmtr_readlog(struct net_device *dev) { struct tok_info *ti; - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); ti->readlog_pending = 0; SET_PAGE(ti->srb_page); @@ -1891,7 +1891,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev) { struct tok_info *toki; - toki = (struct tok_info *) dev->priv; + toki = netdev_priv(dev); return (struct net_device_stats *) &toki->tr_stats; } @@ -1899,7 +1899,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev) static int ibmtr_change_mtu(struct net_device *dev, int mtu) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); if (ti->ring_speed == 16 && mtu > ti->maxmtu16) return -EINVAL; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index fc4495581f96..49c4270ef5f7 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -246,7 +246,7 @@ static int __devinit streamer_init_one(struct pci_dev *pdev, } SET_MODULE_OWNER(dev); - streamer_priv = dev->priv; + streamer_priv = netdev_priv(dev); #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS @@ -405,7 +405,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev) return; } - streamer_priv=dev->priv; + streamer_priv=netdev_priv(dev); if (streamer_priv == NULL) { printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n"); return; @@ -449,7 +449,7 @@ static int streamer_reset(struct net_device *dev) struct sk_buff *skb = NULL; __u16 misr; - streamer_priv = (struct streamer_private *) dev->priv; + streamer_priv = netdev_priv(dev); streamer_mmio = streamer_priv->streamer_mmio; writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL); @@ -588,7 +588,7 @@ static int streamer_reset(struct net_device *dev) static int streamer_open(struct net_device *dev) { - struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; + struct streamer_private *streamer_priv = netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; unsigned long flags; char open_error[255]; @@ -905,7 +905,7 @@ static int streamer_open(struct net_device *dev) static void streamer_rx(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; struct streamer_rx_desc *rx_desc; int rx_ring_last_received, length, frame_length, buffer_cnt = 0; @@ -1030,7 +1030,7 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; __u16 sisr; __u16 misr; @@ -1153,7 +1153,7 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id) static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; unsigned long flags ; @@ -1204,7 +1204,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) static int streamer_close(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; unsigned long flags; int i; @@ -1270,7 +1270,7 @@ static int streamer_close(struct net_device *dev) static void streamer_set_rx_mode(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; __u8 options = 0; struct dev_mc_list *dmi; @@ -1329,7 +1329,7 @@ static void streamer_set_rx_mode(struct net_device *dev) static void streamer_srb_bh(struct net_device *dev) { - struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; + struct streamer_private *streamer_priv = netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; __u16 srb_word; @@ -1494,14 +1494,14 @@ static void streamer_srb_bh(struct net_device *dev) static struct net_device_stats *streamer_get_stats(struct net_device *dev) { struct streamer_private *streamer_priv; - streamer_priv = (struct streamer_private *) dev->priv; + streamer_priv = netdev_priv(dev); return (struct net_device_stats *) &streamer_priv->streamer_stats; } static int streamer_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *saddr = addr; - struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; + struct streamer_private *streamer_priv = netdev_priv(dev); if (netif_running(dev)) { @@ -1526,7 +1526,7 @@ static int streamer_set_mac_address(struct net_device *dev, void *addr) static void streamer_arb_cmd(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; __u8 header_len; __u16 frame_len, buffer_len; @@ -1741,7 +1741,7 @@ drop_frame: static void streamer_asb_bh(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; if (streamer_priv->asb_queued == 1) @@ -1785,7 +1785,7 @@ static void streamer_asb_bh(struct net_device *dev) static int streamer_change_mtu(struct net_device *dev, int mtu) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u16 max_mtu; if (streamer_priv->streamer_ring_speed == 4) @@ -1849,7 +1849,7 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset, static int sprintf_info(char *buffer, struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; struct streamer_adapter_addr_table sat; struct streamer_parameters_table spt; diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index f8f4d74f01f1..9eafc2e25abc 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -690,7 +690,7 @@ static int madgemc_close(struct net_device *dev) static int madgemc_mcaproc(char *buf, int slot, void *d) { struct net_device *dev = (struct net_device *)d; - struct net_local *tp = dev->priv; + struct net_local *tp = netdev_priv(dev); struct card_info *curcard = tp->tmspriv; int len = 0; @@ -736,7 +736,7 @@ static int __devexit madgemc_remove(struct device *device) BUG_ON(!dev); - tp = dev->priv; + tp = netdev_priv(dev); card = tp->tmspriv; kfree(card); tp->tmspriv = NULL; diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index c323101a895b..b57f65b2591a 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -220,14 +220,14 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device goto op_release_dev; } - olympic_priv = dev->priv ; + olympic_priv = netdev_priv(dev) ; spin_lock_init(&olympic_priv->olympic_lock) ; init_waitqueue_head(&olympic_priv->srb_wait); init_waitqueue_head(&olympic_priv->trb_wait); #if OLYMPIC_DEBUG - printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, dev->priv); + printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, netdev_priv(dev)); #endif dev->irq=pdev->irq; dev->base_addr=pci_resource_start(pdev, 0); @@ -298,7 +298,7 @@ static int __devinit olympic_init(struct net_device *dev) unsigned long t; unsigned int uaa_addr; - olympic_priv=(struct olympic_private *)dev->priv; + olympic_priv=netdev_priv(dev); olympic_mmio=olympic_priv->olympic_mmio; printk("%s \n", version); @@ -436,7 +436,7 @@ static int __devinit olympic_init(struct net_device *dev) static int olympic_open(struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; unsigned long flags, t; int i, open_finished = 1 ; @@ -756,7 +756,7 @@ out: */ static void olympic_rx(struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; struct olympic_rx_status *rx_status; struct olympic_rx_desc *rx_desc ; @@ -898,7 +898,7 @@ static void olympic_rx(struct net_device *dev) static void olympic_freemem(struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); int i; for(i=0;ipriv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; u32 sisr; u8 __iomem *adapter_check_area ; @@ -1047,7 +1047,7 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id) static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; unsigned long flags ; @@ -1078,7 +1078,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) static int olympic_close(struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*srb; unsigned long t,flags; @@ -1148,7 +1148,7 @@ static int olympic_close(struct net_device *dev) static void olympic_set_rx_mode(struct net_device *dev) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + struct olympic_private *olympic_priv = netdev_priv(dev); u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; u8 options = 0; u8 __iomem *srb; @@ -1216,7 +1216,7 @@ static void olympic_set_rx_mode(struct net_device *dev) static void olympic_srb_bh(struct net_device *dev) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + struct olympic_private *olympic_priv = netdev_priv(dev); u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; u8 __iomem *srb; @@ -1362,14 +1362,14 @@ static void olympic_srb_bh(struct net_device *dev) static struct net_device_stats * olympic_get_stats(struct net_device *dev) { struct olympic_private *olympic_priv ; - olympic_priv=(struct olympic_private *) dev->priv; + olympic_priv=netdev_priv(dev); return (struct net_device_stats *) &olympic_priv->olympic_stats; } static int olympic_set_mac_address (struct net_device *dev, void *addr) { struct sockaddr *saddr = addr ; - struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; + struct olympic_private *olympic_priv = netdev_priv(dev); if (netif_running(dev)) { printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; @@ -1390,7 +1390,7 @@ static int olympic_set_mac_address (struct net_device *dev, void *addr) static void olympic_arb_cmd(struct net_device *dev) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; + struct olympic_private *olympic_priv = netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; u8 __iomem *arb_block, *asb_block, *srb ; u8 header_len ; @@ -1576,7 +1576,7 @@ drop_frame: static void olympic_asb_bh(struct net_device *dev) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + struct olympic_private *olympic_priv = netdev_priv(dev); u8 __iomem *arb_block, *asb_block ; arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; @@ -1616,7 +1616,7 @@ static void olympic_asb_bh(struct net_device *dev) static int olympic_change_mtu(struct net_device *dev, int mtu) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; + struct olympic_private *olympic_priv = netdev_priv(dev); u16 max_mtu ; if (olympic_priv->olympic_ring_speed == 4) @@ -1638,7 +1638,7 @@ static int olympic_change_mtu(struct net_device *dev, int mtu) static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { struct net_device *dev = (struct net_device *)data ; - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; int size = 0 ; @@ -1749,7 +1749,7 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt static void __devexit olympic_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev) ; - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); if (olympic_priv->olympic_network_monitor) { char proc_name[20] ; diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index 3b2f00b9b7bd..aec75c930c21 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -149,7 +149,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic goto err_out_irq; } - tp = dev->priv; + tp = netdev_priv(dev); tp->setnselout = tms_pci_setnselout_pins; tp->sifreadb = tms_pci_sifreadb; @@ -210,7 +210,7 @@ static void tms_pci_read_eeprom(struct net_device *dev) static unsigned short tms_pci_setnselout_pins(struct net_device *dev) { unsigned short val = 0; - struct net_local *tp = dev->priv; + struct net_local *tp = netdev_priv(dev); struct card_info *cardinfo = tp->tmspriv; if(tp->DataRate == SPEED_4) From c54f5c240239fb8391a3b541f916764dd496f2e6 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Wed, 18 Jul 2007 15:24:49 +0800 Subject: [PATCH 1297/2804] drivers/net/cxgb3: removed several unneeded zero initilization Cc: linux-bugs@chelsio.com Signed-off-by: Denis Cheng Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 5db7d4e27ec0..57fc199e0614 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -793,7 +793,7 @@ release_tpsram: */ static int cxgb_up(struct adapter *adap) { - int err = 0; + int err; int must_load; if (!(adap->flags & FULL_INIT_DONE)) { @@ -907,7 +907,7 @@ static int offload_open(struct net_device *dev) struct adapter *adapter = pi->adapter; struct t3cdev *tdev = dev2t3cdev(dev); int adap_up = adapter->open_device_map & PORT_MASK; - int err = 0; + int err; if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) return 0; @@ -1566,7 +1566,7 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct adapter *adapter = pi->adapter; u32 aligned_offset, aligned_len, *p; u8 *buf; - int err = 0; + int err; if (eeprom->magic != EEPROM_MAGIC) return -EINVAL; From bbfb86c5776ff481d246fcd5d8deb67701e05c00 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 25 Jul 2007 12:31:57 +0100 Subject: [PATCH 1298/2804] IOC3: Switch hw checksumming to ethtool configurable. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 20 ------------------ drivers/net/ioc3-eth.c | 48 ++++++++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 10ed28ef3566..734f8403c806 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -486,26 +486,6 @@ config SGI_IOC3_ETH the Ethernet-HOWTO, available from . -config SGI_IOC3_ETH_HW_RX_CSUM - bool "Receive hardware checksums" - depends on SGI_IOC3_ETH && INET - default y - help - The SGI IOC3 network adapter supports TCP and UDP checksums in - hardware to offload processing of these checksums from the CPU. At - the moment only acceleration of IPv4 is supported. This option - enables offloading for checksums on receive. If unsure, say Y. - -config SGI_IOC3_ETH_HW_TX_CSUM - bool "Transmit hardware checksums" - depends on SGI_IOC3_ETH && INET - default y - help - The SGI IOC3 network adapter supports TCP and UDP checksums in - hardware to offload processing of these checksums from the CPU. At - the moment only acceleration of IPv4 is supported. This option - enables offloading for checksums on transmit. If unsure, say Y. - config MIPS_SIM_NET tristate "MIPS simulator Network device" depends on MIPS_SIM diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 0834ef0eddb4..c030030e5863 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -5,7 +5,7 @@ * * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card. * - * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle + * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc. * * References: @@ -62,12 +62,7 @@ #include #include #include -#include -#include -#include -#include #include -#include #include /* @@ -95,6 +90,9 @@ struct ioc3_private { u32 emcr, ehar_h, ehar_l; spinlock_t ioc3_lock; struct mii_if_info mii; + unsigned long flags; +#define IOC3_FLAG_RX_CHECKSUMS 1 + struct pci_dev *pdev; /* Members used by autonegotiation */ @@ -521,8 +519,6 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev) return &ip->stats; } -#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM - static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) { struct ethhdr *eh = eth_hdr(skb); @@ -590,7 +586,6 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) if (csum == 0xffff) skb->ip_summed = CHECKSUM_UNNECESSARY; } -#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */ static inline void ioc3_rx(struct ioc3_private *ip) { @@ -625,9 +620,9 @@ static inline void ioc3_rx(struct ioc3_private *ip) goto next; } -#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM - ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len); -#endif + if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS)) + ioc3_tcpudp_checksum(skb, + w0 & ERXBUF_IPCKSUM_MASK, len); netif_rx(skb); @@ -1338,9 +1333,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->set_multicast_list = ioc3_set_multicast_list; dev->set_mac_address = ioc3_set_mac_address; dev->ethtool_ops = &ioc3_ethtool_ops; -#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM dev->features = NETIF_F_IP_CSUM; -#endif sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); @@ -1430,7 +1423,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) uint32_t w0 = 0; int produce; -#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM /* * IOC3 has a fairly simple minded checksumming hardware which simply * adds up the 1's complement checksum for the entire packet and @@ -1478,7 +1470,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT); } -#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */ spin_lock_irq(&ip->ioc3_lock); @@ -1633,12 +1624,37 @@ static u32 ioc3_get_link(struct net_device *dev) return rc; } +static u32 ioc3_get_rx_csum(struct net_device *dev) +{ + struct ioc3_private *ip = netdev_priv(dev); + + return ip->flags & IOC3_FLAG_RX_CHECKSUMS; +} + +static int ioc3_set_rx_csum(struct net_device *dev, u32 data) +{ + struct ioc3_private *ip = netdev_priv(dev); + + spin_lock_bh(&ip->ioc3_lock); + if (data) + ip->flags |= IOC3_FLAG_RX_CHECKSUMS; + else + ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS; + spin_unlock_bh(&ip->ioc3_lock); + + return 0; +} + static const struct ethtool_ops ioc3_ethtool_ops = { .get_drvinfo = ioc3_get_drvinfo, .get_settings = ioc3_get_settings, .set_settings = ioc3_set_settings, .nway_reset = ioc3_nway_reset, .get_link = ioc3_get_link, + .get_rx_csum = ioc3_get_rx_csum, + .set_rx_csum = ioc3_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum }; static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) From a967b14035c5efe4c92623dde3776ffc7a79118c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 2 Aug 2007 16:31:25 -0400 Subject: [PATCH 1299/2804] drivers/net/skfp: Remove dead code referencing pci_find_device() Signed-off-by: Jeff Garzik --- drivers/net/skfp/drvfbi.c | 40 -------------------------------------- drivers/net/skfp/h/skfbi.h | 5 ----- 2 files changed, 45 deletions(-) diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c index be2ee6519ef2..c77cc14b3227 100644 --- a/drivers/net/skfp/drvfbi.c +++ b/drivers/net/skfp/drvfbi.c @@ -537,46 +537,6 @@ int set_oi_id_def(struct s_smc *smc) } #endif /* MULT_OEM */ -#ifdef PCI -#ifdef USE_BIOS_FUN -int exist_board(struct s_smc *smc, int slot) -{ - u_short dev_id ; - u_short ven_id ; - int found ; - int i ; - - found = FALSE ; /* make sure we returned with adatper not found*/ - /* if an empty oemids.h was included */ - -#ifdef MULT_OEM - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; - for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { - if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) - continue ; -#endif - ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ; - dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ; - for (i = 0; i < slot; i++) { - if (pci_find_device(i,&smc->hw.pci_handle, - dev_id,ven_id) != 0) { - - found = FALSE ; - } else { - found = TRUE ; - } - } - if (found) { - return(1) ; /* adapter was found */ - } -#ifdef MULT_OEM - } -#endif - return(0) ; /* adapter was not found */ -} -#endif /* PCI */ -#endif /* USE_BIOS_FUNC */ - void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr) { int i ; diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h index d25c9f849842..c1ba26c06d73 100644 --- a/drivers/net/skfp/h/skfbi.h +++ b/drivers/net/skfp/h/skfbi.h @@ -15,11 +15,6 @@ #ifndef _SKFBI_H_ #define _SKFBI_H_ -#ifdef SYNC -#define exist_board_far exist_board -#define get_board_para_far get_board_para -#endif - /* * FDDI-Fx (x := {I(SA), P(CI)}) * address calculation & function defines From c477f3348abb5f6fb8b627cfdb1d7ae4b8fe613b Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 23:58:36 +0200 Subject: [PATCH 1300/2804] drivers/net/sb1250-mac.c: kmalloc + memset conversion to kcalloc Signed-off-by: Mariusz Kozlowski drivers/net/sb1250-mac.c | 76286 -> 76199 (-87 bytes) drivers/net/sb1250-mac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 53845ebb649f..b6cafac97200 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -780,10 +780,8 @@ static void sbdma_initctx(sbmacdma_t *d, * And context table */ - d->sbdma_ctxtable = (struct sk_buff **) - kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL); - - memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *)); + d->sbdma_ctxtable = kcalloc(d->sbdma_maxdescr, + sizeof(struct sk_buff *), GFP_KERNEL); #ifdef CONFIG_SBMAC_COALESCE /* From ae94607d19028f9805e82da8975c66d3858fcfd8 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 1 Aug 2007 00:11:50 +0200 Subject: [PATCH 1301/2804] drivers/net/via-velocity.c: mostly kmalloc + memset conversion to kcalloc Signed-off-by: Mariusz Kozlowski drivers/net/via-velocity.c | 88263 -> 88120 (-143 bytes) drivers/net/via-velocity.o | 254264 -> 253828 (-436 bytes) drivers/net/via-velocity.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/via-velocity.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 93574add4063..a4729bc385f4 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1071,14 +1071,12 @@ static int velocity_rx_refill(struct velocity_info *vptr) static int velocity_init_rd_ring(struct velocity_info *vptr) { - int ret = -ENOMEM; - unsigned int rsize = sizeof(struct velocity_rd_info) * - vptr->options.numrx; + int ret; - vptr->rd_info = kmalloc(rsize, GFP_KERNEL); - if(vptr->rd_info == NULL) - goto out; - memset(vptr->rd_info, 0, rsize); + vptr->rd_info = kcalloc(vptr->options.numrx, + sizeof(struct velocity_rd_info), GFP_KERNEL); + if (!vptr->rd_info) + return -ENOMEM; vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0; @@ -1088,7 +1086,7 @@ static int velocity_init_rd_ring(struct velocity_info *vptr) "%s: failed to allocate RX buffer.\n", vptr->dev->name); velocity_free_rd_ring(vptr); } -out: + return ret; } @@ -1142,21 +1140,19 @@ static int velocity_init_td_ring(struct velocity_info *vptr) dma_addr_t curr; struct tx_desc *td; struct velocity_td_info *td_info; - unsigned int tsize = sizeof(struct velocity_td_info) * - vptr->options.numtx; /* Init the TD ring entries */ for (j = 0; j < vptr->num_txq; j++) { curr = vptr->td_pool_dma[j]; - vptr->td_infos[j] = kmalloc(tsize, GFP_KERNEL); - if(vptr->td_infos[j] == NULL) - { + vptr->td_infos[j] = kcalloc(vptr->options.numtx, + sizeof(struct velocity_td_info), + GFP_KERNEL); + if (!vptr->td_infos[j]) { while(--j >= 0) kfree(vptr->td_infos[j]); return -ENOMEM; } - memset(vptr->td_infos[j], 0, tsize); for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) { td = &(vptr->td_rings[j][i]); From 6cc92cddb13a7874dcd7751c84b0e61738815077 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 8 Aug 2007 02:16:04 -0400 Subject: [PATCH 1302/2804] [netdrvr] 8139cp, 8139too: convert to generic DMA Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 31 +++++++++++++++++-------------- drivers/net/8139too.c | 20 ++++++++++---------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 7f18ca23d9f8..2dec3d6ae01a 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -562,7 +562,7 @@ rx_status_loop: skb_reserve(new_skb, RX_OFFSET); - pci_unmap_single(cp->pdev, mapping, + dma_unmap_single(&cp->pdev->dev, mapping, buflen, PCI_DMA_FROMDEVICE); /* Handle checksum offloading for incoming packets. */ @@ -573,7 +573,7 @@ rx_status_loop: skb_put(skb, len); - mapping = pci_map_single(cp->pdev, new_skb->data, buflen, + mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen, PCI_DMA_FROMDEVICE); cp->rx_skb[rx_tail] = new_skb; @@ -701,7 +701,7 @@ static void cp_tx (struct cp_private *cp) skb = cp->tx_skb[tx_tail]; BUG_ON(!skb); - pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr), + dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr), le32_to_cpu(txd->opts1) & 0xffff, PCI_DMA_TODEVICE); @@ -779,7 +779,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) dma_addr_t mapping; len = skb->len; - mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE); + mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE); CP_VLAN_TX_TAG(txd, vlan_tag); txd->addr = cpu_to_le64(mapping); wmb(); @@ -815,7 +815,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) */ first_eor = eor; first_len = skb_headlen(skb); - first_mapping = pci_map_single(cp->pdev, skb->data, + first_mapping = dma_map_single(&cp->pdev->dev, skb->data, first_len, PCI_DMA_TODEVICE); cp->tx_skb[entry] = skb; entry = NEXT_TX(entry); @@ -827,7 +827,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) dma_addr_t mapping; len = this_frag->size; - mapping = pci_map_single(cp->pdev, + mapping = dma_map_single(&cp->pdev->dev, ((void *) page_address(this_frag->page) + this_frag->page_offset), len, PCI_DMA_TODEVICE); @@ -1066,8 +1066,8 @@ static int cp_refill_rx (struct cp_private *cp) skb_reserve(skb, RX_OFFSET); - mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz, - PCI_DMA_FROMDEVICE); + mapping = dma_map_single(&cp->pdev->dev, skb->data, + cp->rx_buf_sz, PCI_DMA_FROMDEVICE); cp->rx_skb[i] = skb; cp->rx_ring[i].opts2 = 0; @@ -1107,7 +1107,8 @@ static int cp_alloc_rings (struct cp_private *cp) { void *mem; - mem = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma); + mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES, + &cp->ring_dma, GFP_KERNEL); if (!mem) return -ENOMEM; @@ -1125,7 +1126,7 @@ static void cp_clean_rings (struct cp_private *cp) for (i = 0; i < CP_RX_RING_SIZE; i++) { if (cp->rx_skb[i]) { desc = cp->rx_ring + i; - pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr), + dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr), cp->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(cp->rx_skb[i]); } @@ -1136,7 +1137,7 @@ static void cp_clean_rings (struct cp_private *cp) struct sk_buff *skb = cp->tx_skb[i]; desc = cp->tx_ring + i; - pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr), + dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr), le32_to_cpu(desc->opts1) & 0xffff, PCI_DMA_TODEVICE); if (le32_to_cpu(desc->opts1) & LastFrag) @@ -1155,7 +1156,8 @@ static void cp_clean_rings (struct cp_private *cp) static void cp_free_rings (struct cp_private *cp) { cp_clean_rings(cp); - pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma); + dma_free_coherent(&cp->pdev->dev, CP_RING_BYTES, cp->rx_ring, + cp->ring_dma); cp->rx_ring = NULL; cp->tx_ring = NULL; } @@ -1519,7 +1521,8 @@ static void cp_get_ethtool_stats (struct net_device *dev, dma_addr_t dma; int i; - nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma); + nic_stats = dma_alloc_coherent(&cp->pdev->dev, sizeof(*nic_stats), + &dma, GFP_KERNEL); if (!nic_stats) return; @@ -1554,7 +1557,7 @@ static void cp_get_ethtool_stats (struct net_device *dev, tmp_stats[i++] = cp->cp_stats.rx_frags; BUG_ON(i != CP_NUM_STATS); - pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma); + dma_free_coherent(&cp->pdev->dev, sizeof(*nic_stats), nic_stats, dma); } static const struct ethtool_ops cp_ethtool_ops = { diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 20af6baecfcb..76d3048a1a63 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1316,18 +1316,18 @@ static int rtl8139_open (struct net_device *dev) if (retval) return retval; - tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN, - &tp->tx_bufs_dma); - tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN, - &tp->rx_ring_dma); + tp->tx_bufs = dma_alloc_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN, + &tp->tx_bufs_dma, GFP_KERNEL); + tp->rx_ring = dma_alloc_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN, + &tp->rx_ring_dma, GFP_KERNEL); if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { free_irq(dev->irq, dev); if (tp->tx_bufs) - pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, + dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN, tp->tx_bufs, tp->tx_bufs_dma); if (tp->rx_ring) - pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, + dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN, tp->rx_ring, tp->rx_ring_dma); return -ENOMEM; @@ -2246,10 +2246,10 @@ static int rtl8139_close (struct net_device *dev) rtl8139_tx_clear (tp); - pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, - tp->rx_ring, tp->rx_ring_dma); - pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, - tp->tx_bufs, tp->tx_bufs_dma); + dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN, + tp->rx_ring, tp->rx_ring_dma); + dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN, + tp->tx_bufs, tp->tx_bufs_dma); tp->rx_ring = NULL; tp->tx_bufs = NULL; From 28006c65a74403a8c4a1846aa7f08981e0d0b44a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 15 Sep 2007 12:36:46 -0700 Subject: [PATCH 1303/2804] [8139too]: tab-align enums and structs; remove dead code * (main change) tab-align hardware register value enums, and hw struct * MMIO_FLUSH_AUDIT_COMPLETE has been defined to 1 for a while. Remove the code activated when it is set to zero. Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/8139too.c | 334 +++++++++++++++++++++--------------------- 1 file changed, 164 insertions(+), 170 deletions(-) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 76d3048a1a63..7ba470ee2175 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -291,198 +291,197 @@ static struct { /* Symbolic offsets to registers. */ enum RTL8139_registers { - MAC0 = 0, /* Ethernet hardware address. */ - MAR0 = 8, /* Multicast filter. */ - TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ - RxBuf = 0x30, - ChipCmd = 0x37, - RxBufPtr = 0x38, - RxBufAddr = 0x3A, - IntrMask = 0x3C, - IntrStatus = 0x3E, - TxConfig = 0x40, - RxConfig = 0x44, - Timer = 0x48, /* A general-purpose counter. */ - RxMissed = 0x4C, /* 24 bits valid, write clears. */ - Cfg9346 = 0x50, - Config0 = 0x51, - Config1 = 0x52, - FlashReg = 0x54, - MediaStatus = 0x58, - Config3 = 0x59, - Config4 = 0x5A, /* absent on RTL-8139A */ - HltClk = 0x5B, - MultiIntr = 0x5C, - TxSummary = 0x60, - BasicModeCtrl = 0x62, - BasicModeStatus = 0x64, - NWayAdvert = 0x66, - NWayLPAR = 0x68, - NWayExpansion = 0x6A, + MAC0 = 0, /* Ethernet hardware address. */ + MAR0 = 8, /* Multicast filter. */ + TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ + TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ + RxBuf = 0x30, + ChipCmd = 0x37, + RxBufPtr = 0x38, + RxBufAddr = 0x3A, + IntrMask = 0x3C, + IntrStatus = 0x3E, + TxConfig = 0x40, + RxConfig = 0x44, + Timer = 0x48, /* A general-purpose counter. */ + RxMissed = 0x4C, /* 24 bits valid, write clears. */ + Cfg9346 = 0x50, + Config0 = 0x51, + Config1 = 0x52, + FlashReg = 0x54, + MediaStatus = 0x58, + Config3 = 0x59, + Config4 = 0x5A, /* absent on RTL-8139A */ + HltClk = 0x5B, + MultiIntr = 0x5C, + TxSummary = 0x60, + BasicModeCtrl = 0x62, + BasicModeStatus = 0x64, + NWayAdvert = 0x66, + NWayLPAR = 0x68, + NWayExpansion = 0x6A, /* Undocumented registers, but required for proper operation. */ - FIFOTMS = 0x70, /* FIFO Control and test. */ - CSCR = 0x74, /* Chip Status and Configuration Register. */ - PARA78 = 0x78, - PARA7c = 0x7c, /* Magic transceiver parameter register. */ - Config5 = 0xD8, /* absent on RTL-8139A */ + FIFOTMS = 0x70, /* FIFO Control and test. */ + CSCR = 0x74, /* Chip Status and Configuration Register. */ + PARA78 = 0x78, + PARA7c = 0x7c, /* Magic transceiver parameter register. */ + Config5 = 0xD8, /* absent on RTL-8139A */ }; enum ClearBitMasks { - MultiIntrClear = 0xF000, - ChipCmdClear = 0xE2, - Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), + MultiIntrClear = 0xF000, + ChipCmdClear = 0xE2, + Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), }; enum ChipCmdBits { - CmdReset = 0x10, - CmdRxEnb = 0x08, - CmdTxEnb = 0x04, - RxBufEmpty = 0x01, + CmdReset = 0x10, + CmdRxEnb = 0x08, + CmdTxEnb = 0x04, + RxBufEmpty = 0x01, }; /* Interrupt register bits, using my own meaningful names. */ enum IntrStatusBits { - PCIErr = 0x8000, - PCSTimeout = 0x4000, - RxFIFOOver = 0x40, - RxUnderrun = 0x20, - RxOverflow = 0x10, - TxErr = 0x08, - TxOK = 0x04, - RxErr = 0x02, - RxOK = 0x01, + PCIErr = 0x8000, + PCSTimeout = 0x4000, + RxFIFOOver = 0x40, + RxUnderrun = 0x20, + RxOverflow = 0x10, + TxErr = 0x08, + TxOK = 0x04, + RxErr = 0x02, + RxOK = 0x01, - RxAckBits = RxFIFOOver | RxOverflow | RxOK, + RxAckBits = RxFIFOOver | RxOverflow | RxOK, }; enum TxStatusBits { - TxHostOwns = 0x2000, - TxUnderrun = 0x4000, - TxStatOK = 0x8000, - TxOutOfWindow = 0x20000000, - TxAborted = 0x40000000, - TxCarrierLost = 0x80000000, + TxHostOwns = 0x2000, + TxUnderrun = 0x4000, + TxStatOK = 0x8000, + TxOutOfWindow = 0x20000000, + TxAborted = 0x40000000, + TxCarrierLost = 0x80000000, }; enum RxStatusBits { - RxMulticast = 0x8000, - RxPhysical = 0x4000, - RxBroadcast = 0x2000, - RxBadSymbol = 0x0020, - RxRunt = 0x0010, - RxTooLong = 0x0008, - RxCRCErr = 0x0004, - RxBadAlign = 0x0002, - RxStatusOK = 0x0001, + RxMulticast = 0x8000, + RxPhysical = 0x4000, + RxBroadcast = 0x2000, + RxBadSymbol = 0x0020, + RxRunt = 0x0010, + RxTooLong = 0x0008, + RxCRCErr = 0x0004, + RxBadAlign = 0x0002, + RxStatusOK = 0x0001, }; /* Bits in RxConfig. */ enum rx_mode_bits { - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0x08, - AcceptMulticast = 0x04, - AcceptMyPhys = 0x02, - AcceptAllPhys = 0x01, + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0x08, + AcceptMulticast = 0x04, + AcceptMyPhys = 0x02, + AcceptAllPhys = 0x01, }; /* Bits in TxConfig. */ enum tx_config_bits { - /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */ - TxIFGShift = 24, - TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */ - TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */ - TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */ - TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */ + TxIFGShift = 24, + TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */ + TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */ + TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */ + TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */ - TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ - TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ - TxClearAbt = (1 << 0), /* Clear abort (WO) */ - TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */ - TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */ + TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ + TxCRC = (1 << 16), /* DISABLE Tx pkt CRC append */ + TxClearAbt = (1 << 0), /* Clear abort (WO) */ + TxDMAShift = 8, /* DMA burst value (0-7) is shifted X many bits */ + TxRetryShift = 4, /* TXRR value (0-15) is shifted X many bits */ - TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ + TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ }; /* Bits in Config1 */ enum Config1Bits { - Cfg1_PM_Enable = 0x01, - Cfg1_VPD_Enable = 0x02, - Cfg1_PIO = 0x04, - Cfg1_MMIO = 0x08, - LWAKE = 0x10, /* not on 8139, 8139A */ + Cfg1_PM_Enable = 0x01, + Cfg1_VPD_Enable = 0x02, + Cfg1_PIO = 0x04, + Cfg1_MMIO = 0x08, + LWAKE = 0x10, /* not on 8139, 8139A */ Cfg1_Driver_Load = 0x20, - Cfg1_LED0 = 0x40, - Cfg1_LED1 = 0x80, - SLEEP = (1 << 1), /* only on 8139, 8139A */ - PWRDN = (1 << 0), /* only on 8139, 8139A */ + Cfg1_LED0 = 0x40, + Cfg1_LED1 = 0x80, + SLEEP = (1 << 1), /* only on 8139, 8139A */ + PWRDN = (1 << 0), /* only on 8139, 8139A */ }; /* Bits in Config3 */ enum Config3Bits { - Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */ - Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */ - Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */ - Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */ - Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */ - Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */ - Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */ - Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */ + Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */ + Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */ + Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */ + Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */ + Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */ + Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */ + Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */ + Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */ }; /* Bits in Config4 */ enum Config4Bits { - LWPTN = (1 << 2), /* not on 8139, 8139A */ + LWPTN = (1 << 2), /* not on 8139, 8139A */ }; /* Bits in Config5 */ enum Config5Bits { - Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */ - Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */ - Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */ - Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */ - Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */ - Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */ - Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */ + Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */ + Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */ + Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */ + Cfg5_FIFOAddrPtr= (1 << 3), /* Realtek internal SRAM testing */ + Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */ + Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */ + Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */ }; enum RxConfigBits { /* rx fifo threshold */ - RxCfgFIFOShift = 13, - RxCfgFIFONone = (7 << RxCfgFIFOShift), + RxCfgFIFOShift = 13, + RxCfgFIFONone = (7 << RxCfgFIFOShift), /* Max DMA burst */ - RxCfgDMAShift = 8, + RxCfgDMAShift = 8, RxCfgDMAUnlimited = (7 << RxCfgDMAShift), /* rx ring buffer length */ - RxCfgRcv8K = 0, - RxCfgRcv16K = (1 << 11), - RxCfgRcv32K = (1 << 12), - RxCfgRcv64K = (1 << 11) | (1 << 12), + RxCfgRcv8K = 0, + RxCfgRcv16K = (1 << 11), + RxCfgRcv32K = (1 << 12), + RxCfgRcv64K = (1 << 11) | (1 << 12), /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */ - RxNoWrap = (1 << 7), + RxNoWrap = (1 << 7), }; /* Twister tuning parameters from RealTek. Completely undocumented, but required to tune bad links on some boards. */ enum CSCRBits { - CSCR_LinkOKBit = 0x0400, - CSCR_LinkChangeBit = 0x0800, - CSCR_LinkStatusBits = 0x0f000, - CSCR_LinkDownOffCmd = 0x003c0, - CSCR_LinkDownCmd = 0x0f3c0, + CSCR_LinkOKBit = 0x0400, + CSCR_LinkChangeBit = 0x0800, + CSCR_LinkStatusBits = 0x0f000, + CSCR_LinkDownOffCmd = 0x003c0, + CSCR_LinkDownCmd = 0x0f3c0, }; enum Cfg9346Bits { - Cfg9346_Lock = 0x00, - Cfg9346_Unlock = 0xC0, + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xC0, }; typedef enum { - CH_8139 = 0, + CH_8139 = 0, CH_8139_K, CH_8139A, CH_8139A_G, @@ -495,8 +494,8 @@ typedef enum { } chip_t; enum chip_flags { - HasHltClk = (1 << 0), - HasLWake = (1 << 1), + HasHltClk = (1 << 0), + HasLWake = (1 << 1), }; #define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \ @@ -569,38 +568,46 @@ struct rtl_extra_stats { }; struct rtl8139_private { - void __iomem *mmio_addr; - int drv_flags; - struct pci_dev *pci_dev; - u32 msg_enable; - struct napi_struct napi; - struct net_device *dev; - struct net_device_stats stats; - unsigned char *rx_ring; - unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ - unsigned int tx_flag; - unsigned long cur_tx; - unsigned long dirty_tx; - unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ - unsigned char *tx_bufs; /* Tx bounce buffer region. */ - dma_addr_t rx_ring_dma; - dma_addr_t tx_bufs_dma; - signed char phys[4]; /* MII device addresses. */ - char twistie, twist_row, twist_col; /* Twister tune state. */ - unsigned int watchdog_fired : 1; - unsigned int default_port : 4; /* Last dev->if_port value. */ - unsigned int have_thread : 1; - spinlock_t lock; - spinlock_t rx_lock; - chip_t chipset; - u32 rx_config; - struct rtl_extra_stats xstats; + void __iomem *mmio_addr; + int drv_flags; + struct pci_dev *pci_dev; + u32 msg_enable; + struct napi_struct napi; + struct net_device *dev; + struct net_device_stats stats; - struct delayed_work thread; + unsigned char *rx_ring; + unsigned int cur_rx; /* RX buf index of next pkt */ + dma_addr_t rx_ring_dma; - struct mii_if_info mii; - unsigned int regs_len; - unsigned long fifo_copy_timeout; + unsigned int tx_flag; + unsigned long cur_tx; + unsigned long dirty_tx; + unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ + unsigned char *tx_bufs; /* Tx bounce buffer region. */ + dma_addr_t tx_bufs_dma; + + signed char phys[4]; /* MII device addresses. */ + + /* Twister tune state. */ + char twistie, twist_row, twist_col; + + unsigned int watchdog_fired : 1; + unsigned int default_port : 4; /* Last dev->if_port value. */ + unsigned int have_thread : 1; + + spinlock_t lock; + spinlock_t rx_lock; + + chip_t chipset; + u32 rx_config; + struct rtl_extra_stats xstats; + + struct delayed_work thread; + + struct mii_if_info mii; + unsigned int regs_len; + unsigned long fifo_copy_timeout; }; MODULE_AUTHOR ("Jeff Garzik "); @@ -648,24 +655,11 @@ static const struct ethtool_ops rtl8139_ethtool_ops; #define RTL_W16_F(reg, val16) do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0) #define RTL_W32_F(reg, val32) do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0) - -#define MMIO_FLUSH_AUDIT_COMPLETE 1 -#if MMIO_FLUSH_AUDIT_COMPLETE - /* write MMIO register */ #define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg)) #define RTL_W16(reg, val16) iowrite16 ((val16), ioaddr + (reg)) #define RTL_W32(reg, val32) iowrite32 ((val32), ioaddr + (reg)) -#else - -/* write MMIO register, then flush */ -#define RTL_W8 RTL_W8_F -#define RTL_W16 RTL_W16_F -#define RTL_W32 RTL_W32_F - -#endif /* MMIO_FLUSH_AUDIT_COMPLETE */ - /* read MMIO register */ #define RTL_R8(reg) ioread8 (ioaddr + (reg)) #define RTL_R16(reg) ioread16 (ioaddr + (reg)) From 8abc4d5b84f23edccf405aa591aae7d9b967e8d2 Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Sat, 15 Sep 2007 13:11:34 -0700 Subject: [PATCH 1304/2804] [S2IO]: Making MSIX as default intr_type - Making MSIX as default intr_type - Driver will test MSI-X by issuing test MSI-X vector and if fails it will fallback to INTA Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/s2io-regs.h | 2 +- drivers/net/s2io.c | 93 ++++++++++++++++++++++++++++++++++++++++- drivers/net/s2io.h | 6 +++ 3 files changed, 98 insertions(+), 3 deletions(-) diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index cfa267914476..83e3e47a9e3d 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -220,7 +220,7 @@ struct XENA_dev_config { u64 scheduled_int_ctrl; #define SCHED_INT_CTRL_TIMER_EN BIT(0) #define SCHED_INT_CTRL_ONE_SHOT BIT(1) -#define SCHED_INT_CTRL_INT2MSI TBD +#define SCHED_INT_CTRL_INT2MSI(val) vBIT(val,10,6) #define SCHED_INT_PERIOD TBD u64 txreqtimeout; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index dd012322cdbe..588938204e20 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -37,7 +37,7 @@ * tx_fifo_len: This too is an array of 8. Each element defines the number of * Tx descriptors that can be associated with each corresponding FIFO. * intr_type: This defines the type of interrupt. The values can be 0(INTA), - * 2(MSI_X). Default value is '0(INTA)' + * 2(MSI_X). Default value is '2(MSI_X)' * lro: Specifies whether to enable Large Receive Offload (LRO) or not. * Possible values '1' for enable '0' for disable. Default is '0' * lro_max_pkts: This parameter defines maximum number of packets can be @@ -428,7 +428,7 @@ S2IO_PARM_INT(l3l4hdr_size, 128); /* Frequency of Rx desc syncs expressed as power of 2 */ S2IO_PARM_INT(rxsync_frequency, 3); /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ -S2IO_PARM_INT(intr_type, 0); +S2IO_PARM_INT(intr_type, 2); /* Large receive offload feature */ S2IO_PARM_INT(lro, 0); /* Max pkts to be aggregated by LRO at one time. If not specified, @@ -3773,6 +3773,59 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) return 0; } +/* Handle software interrupt used during MSI(X) test */ +static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id) +{ + struct s2io_nic *sp = dev_id; + + sp->msi_detected = 1; + wake_up(&sp->msi_wait); + + return IRQ_HANDLED; +} + +/* Test interrupt path by forcing a a software IRQ */ +static int __devinit s2io_test_msi(struct s2io_nic *sp) +{ + struct pci_dev *pdev = sp->pdev; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + int err; + u64 val64, saved64; + + err = request_irq(sp->entries[1].vector, s2io_test_intr, 0, + 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); + return err; + } + + init_waitqueue_head (&sp->msi_wait); + sp->msi_detected = 0; + + saved64 = val64 = readq(&bar0->scheduled_int_ctrl); + val64 |= SCHED_INT_CTRL_ONE_SHOT; + val64 |= SCHED_INT_CTRL_TIMER_EN; + val64 |= SCHED_INT_CTRL_INT2MSI(1); + writeq(val64, &bar0->scheduled_int_ctrl); + + wait_event_timeout(sp->msi_wait, sp->msi_detected, HZ/10); + + 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)); + + err = -EOPNOTSUPP; + } + + free_irq(sp->entries[1].vector, sp); + + writeq(saved64, &bar0->scheduled_int_ctrl); + + return err; +} /* ********************************************************* * * Functions defined below concern the OS part of the driver * * ********************************************************* */ @@ -3803,6 +3856,42 @@ static int s2io_open(struct net_device *dev) napi_enable(&sp->napi); + if (sp->intr_type == MSI_X) { + int ret = s2io_enable_msi_x(sp); + + if (!ret) { + u16 msi_control; + + ret = s2io_test_msi(sp); + + /* rollback MSI-X, will re-enable during add_isr() */ + kfree(sp->entries); + sp->mac_control.stats_info->sw_stat.mem_freed += + (MAX_REQUESTED_MSI_X * + sizeof(struct msix_entry)); + kfree(sp->s2io_entries); + sp->mac_control.stats_info->sw_stat.mem_freed += + (MAX_REQUESTED_MSI_X * + sizeof(struct s2io_msix_entry)); + sp->entries = NULL; + sp->s2io_entries = NULL; + + pci_read_config_word(sp->pdev, 0x42, &msi_control); + msi_control &= 0xFFFE; /* Disable MSI */ + pci_write_config_word(sp->pdev, 0x42, msi_control); + + pci_disable_msix(sp->pdev); + + } + if (ret) { + + DBG_PRINT(ERR_DBG, + "%s: MSI-X requested but failed to enable\n", + dev->name); + sp->intr_type = INTA; + } + } + /* Initialize H/W and enable interrupts */ err = s2io_card_up(sp); if (err) { diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 420fefb99188..62398fab2e96 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -412,6 +412,10 @@ struct config_param { struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ u64 tx_intr_type; +#define INTA 0 +#define MSI_X 2 + u8 intr_type; + /* Specifies if Tx Intr is UTILZ or PER_LIST type. */ /* Rx Side */ @@ -862,6 +866,8 @@ struct s2io_nic { struct vlan_group *vlgrp; #define MSIX_FLG 0xA5 struct msix_entry *entries; + int msi_detected; + wait_queue_head_t msi_wait; struct s2io_msix_entry *s2io_entries; char desc[MAX_REQUESTED_MSI_X][25]; From c77dd43e77c530a12a466865805d2068ede96860 Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Mon, 6 Aug 2007 05:36:28 -0400 Subject: [PATCH 1305/2804] S2IO: Fixes in MSIX related code. - Calling store_xmsi_data to store the MSI-X datas during initialization in s2io-init_nic function - Disabling NAPI when MSI-X is enabled - Freeing sp->entries and sp->s2io_entries in s2io_rem_isr Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 19 +++++++++++++++++++ drivers/net/s2io.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 588938204e20..e7b432c508f9 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3892,6 +3892,12 @@ static int s2io_open(struct net_device *dev) } } + /* NAPI doesn't work well with MSI(X) */ + if (sp->intr_type != INTA) { + if(sp->config.napi) + sp->config.napi = 0; + } + /* Initialize H/W and enable interrupts */ err = s2io_card_up(sp); if (err) { @@ -6471,6 +6477,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) { int cnt = 0; struct net_device *dev = sp->dev; + struct swStat *stats = &sp->mac_control.stats_info->sw_stat; if (sp->intr_type == MSI_X) { int i; @@ -6483,6 +6490,16 @@ static void s2io_rem_isr(struct s2io_nic * sp) free_irq(vector, arg); } + + kfree(sp->entries); + stats->mem_freed += + (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); + kfree(sp->s2io_entries); + stats->mem_freed += + (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); + sp->entries = NULL; + sp->s2io_entries = NULL; + pci_read_config_word(sp->pdev, 0x42, &msi_control); msi_control &= 0xFFFE; /* Disable MSI */ pci_write_config_word(sp->pdev, 0x42, msi_control); @@ -7377,6 +7394,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->addr_len = ETH_ALEN; memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); + /* 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); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 62398fab2e96..724948d217b6 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -415,6 +415,7 @@ struct config_param { #define INTA 0 #define MSI_X 2 u8 intr_type; + u8 napi; /* Specifies if Tx Intr is UTILZ or PER_LIST type. */ From 92c487996dfc01c6c1f7c660d076037a3a01a6ae Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Mon, 6 Aug 2007 05:38:19 -0400 Subject: [PATCH 1306/2804] S2IO: Fixed Link LED issue when MSI-X is enabled -Fixed Link LED issue when MSI-X is enabled. Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index e7b432c508f9..e7431c58da49 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.25.1" +#define DRV_VERSION "2.0.26.1" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -6201,13 +6201,10 @@ static void s2io_set_link(struct work_struct *work) netif_stop_queue(dev); } } - val64 = readq(&bar0->adapter_status); - if (!LINK_IS_UP(val64)) { - DBG_PRINT(ERR_DBG, "%s:", dev->name); - DBG_PRINT(ERR_DBG, " Link down after enabling "); - DBG_PRINT(ERR_DBG, "device \n"); - } else - s2io_link(nic, LINK_UP); + val64 = readq(&bar0->adapter_control); + val64 |= ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); + s2io_link(nic, LINK_UP); } else { if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, subid)) { @@ -6216,6 +6213,10 @@ static void s2io_set_link(struct work_struct *work) writeq(val64, &bar0->gpio_control); val64 = readq(&bar0->gpio_control); } + /* turn off LED */ + val64 = readq(&bar0->adapter_control); + val64 = val64 &(~ADAPTER_LED_ON); + writeq(val64, &bar0->adapter_control); s2io_link(nic, LINK_DOWN); } clear_bit(0, &(nic->link_state)); From 2808d2e83f9b48c2f68930b6746fed8efabc41e9 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Aug 2007 13:20:26 +0200 Subject: [PATCH 1307/2804] net/tulip/xircom_cb.c: remove superfulous priv assignment Unpatched version does sth like this: dev = alloc_etherdev(... private = netdev_priv(dev); ... dev->priv = private; which doesn't make much sense (does it?) because this is done in alloc_netdev() already. struct net_device *alloc_netdev(... { ... if (sizeof_priv) dev->priv = netdev_priv(dev); This patch removes superfluous code. Signed-off-by: Mariusz Kozlowski drivers/net/tulip/xircom_cb.c | 32853 -> 32831 (-22 bytes) drivers/net/tulip/xircom_cb.o | 123984 -> 123984 (0 bytes) drivers/net/tulip/xircom_cb.c | 1 - 1 file changed, 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/net/tulip/xircom_cb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 16a54e6b8d4f..4b239dcbef74 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -271,7 +271,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ dev->hard_start_xmit = &xircom_start_xmit; dev->stop = &xircom_close; dev->get_stats = &xircom_get_stats; - dev->priv = private; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &xircom_poll_controller; #endif From 10096974adb6d62b9f8cf65c266632ea73040936 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 14 Aug 2007 01:24:56 -0400 Subject: [PATCH 1308/2804] [netdrvr] ns83820: add ethtool media support Split out from patch authored by Dan Faerch . Signed-off-by: Jeff Garzik --- drivers/net/ns83820.c | 151 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 3 deletions(-) diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index ea80e6cb3dec..6e65d61a3fe0 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1,4 +1,4 @@ -#define VERSION "0.22" +#define VERSION "0.23" /* ns83820.c by Benjamin LaHaise with contributions. * * Questions/comments/discussion to linux-ns83820@kvack.org. @@ -1247,6 +1247,149 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev) return &dev->stats; } +/* Let ethtool retrieve info */ +static int ns83820_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct ns83820 *dev = PRIV(ndev); + u32 cfg, tanar, tbicr; + int have_optical = 0; + int fullduplex = 0; + + /* + * Here's the list of available ethtool commands from other drivers: + * cmd->advertising = + * cmd->speed = + * cmd->duplex = + * cmd->port = 0; + * cmd->phy_address = + * cmd->transceiver = 0; + * cmd->autoneg = + * cmd->maxtxpkt = 0; + * cmd->maxrxpkt = 0; + */ + + /* read current configuration */ + cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; + tanar = readl(dev->base + TANAR); + tbicr = readl(dev->base + TBICR); + + if (dev->CFG_cache & CFG_TBI_EN) { + /* we have an optical interface */ + have_optical = 1; + fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0; + + } else { + /* We have copper */ + fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0; + } + + cmd->supported = SUPPORTED_Autoneg; + + /* we have optical interface */ + if (dev->CFG_cache & CFG_TBI_EN) { + cmd->supported |= SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE; + cmd->port = PORT_FIBRE; + } /* TODO: else copper related support */ + + cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF; + switch (cfg / CFG_SPDSTS0 & 3) { + case 2: + cmd->speed = SPEED_1000; + break; + case 1: + cmd->speed = SPEED_100; + break; + default: + cmd->speed = SPEED_10; + break; + } + cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0; + return 0; +} + +/* Let ethool change settings*/ +static int ns83820_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct ns83820 *dev = PRIV(ndev); + u32 cfg, tanar; + int have_optical = 0; + int fullduplex = 0; + + /* read current configuration */ + cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; + tanar = readl(dev->base + TANAR); + + if (dev->CFG_cache & CFG_TBI_EN) { + /* we have optical */ + have_optical = 1; + fullduplex = (tanar & TANAR_FULL_DUP); + + } else { + /* we have copper */ + fullduplex = cfg & CFG_DUPSTS; + } + + spin_lock_irq(&dev->misc_lock); + spin_lock(&dev->tx_lock); + + /* Set duplex */ + if (cmd->duplex != fullduplex) { + if (have_optical) { + /*set full duplex*/ + if (cmd->duplex == DUPLEX_FULL) { + /* force full duplex */ + writel(readl(dev->base + TXCFG) + | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP, + dev->base + TXCFG); + writel(readl(dev->base + RXCFG) | RXCFG_RX_FD, + dev->base + RXCFG); + /* Light up full duplex LED */ + writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT, + dev->base + GPIOR); + } else { + /*TODO: set half duplex */ + } + + } else { + /*we have copper*/ + /* TODO: Set duplex for copper cards */ + } + printk(KERN_INFO "%s: Duplex set via ethtool\n", + ndev->name); + } + + /* Set autonegotiation */ + if (1) { + if (cmd->autoneg == AUTONEG_ENABLE) { + /* restart auto negotiation */ + writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN, + dev->base + TBICR); + writel(TBICR_MR_AN_ENABLE, dev->base + TBICR); + dev->linkstate = LINK_AUTONEGOTIATE; + + printk(KERN_INFO "%s: autoneg enabled via ethtool\n", + ndev->name); + } else { + /* disable auto negotiation */ + writel(0x00000000, dev->base + TBICR); + } + + printk(KERN_INFO "%s: autoneg %s via ethtool\n", ndev->name, + cmd->autoneg ? "ENABLED" : "DISABLED"); + } + + phy_intr(ndev); + spin_unlock(&dev->tx_lock); + spin_unlock_irq(&dev->misc_lock); + + return 0; +} +/* end ethtool get/set support -df */ + static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { struct ns83820 *dev = PRIV(ndev); @@ -1263,8 +1406,10 @@ static u32 ns83820_get_link(struct net_device *ndev) } static const struct ethtool_ops ops = { - .get_drvinfo = ns83820_get_drvinfo, - .get_link = ns83820_get_link + .get_settings = ns83820_get_settings, + .set_settings = ns83820_set_settings, + .get_drvinfo = ns83820_get_drvinfo, + .get_link = ns83820_get_link }; /* this function is called in irq context from the ISR */ From bf1e9a080d7766bd65b8d8eb837ecde8b03dcc31 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 10 Aug 2007 14:05:20 -0700 Subject: [PATCH 1309/2804] Clean up duplicate includes in drivers/net/ This patch cleans up duplicate includes in drivers/net/ Signed-off-by: Jesper Juhl Acked-by: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/atl1/atl1_main.c | 1 - drivers/net/bfin_mac.c | 5 ----- drivers/net/bonding/bond_sysfs.c | 1 - drivers/net/fs_enet/fs_enet-main.c | 2 -- drivers/net/gianfar.h | 1 - drivers/net/gianfar_ethtool.c | 1 - drivers/net/irda/kingsun-sir.c | 1 - drivers/net/irda/mcs7780.c | 1 - drivers/net/mipsnet.c | 1 - drivers/net/netxen/netxen_nic_main.c | 1 - drivers/net/qla3xxx.c | 1 - drivers/net/tsi108_eth.c | 1 - drivers/net/wireless/ipw2200.h | 1 - drivers/net/wireless/zd1211rw/zd_def.h | 1 - 14 files changed, 19 deletions(-) diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index f23e13c8f9a6..469ff95be559 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -76,7 +76,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 2bb97d464689..3354c534335d 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -47,15 +47,10 @@ #include #include #include - #include #include #include - #include -#include -#include -#include #include #include diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 8289e27a360a..a771853219da 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index c509cb13222d..5dc89d507e66 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -38,8 +38,6 @@ #include #include -#include - #include #include #include diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index b8714e00482d..c16cc8b946a9 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -45,7 +45,6 @@ #include #include #include -#include #include #include "gianfar_mii.h" diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 7b411c1514db..2470903fbc74 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index 4e5101a45c3c..a4adb74cccd2 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -66,7 +66,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 0de867288a47..bfc57525bd6a 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 9853c74f6bbf..c0f5ad38fb17 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index a10bbefbdadd..af16553e18b3 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -39,7 +39,6 @@ #include "netxen_nic_phan_reg.h" #include -#include #include MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index bf9f8f64ba67..e39232320e34 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index b3069ee34bd2..a1d305b9b12a 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 626a240a87d8..9c973b96bb42 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -45,7 +45,6 @@ #include #include -#include #include #include diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h index deb99d1eaa77..505b4d7dd0e2 100644 --- a/drivers/net/wireless/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zd1211rw/zd_def.h @@ -21,7 +21,6 @@ #include #include #include -#include typedef u16 __nocast zd_addr_t; From acb2cc8b20d6cb9e65c1e442d59a2449d8774157 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Sat, 15 Sep 2007 13:14:05 -0700 Subject: [PATCH 1310/2804] [PATCH] drivers/net: remove superfluous memset This patch covers something like this: dev = alloc_*dev(... ... priv = netdev_priv(dev); memset(priv, 0, sizeof(*priv)); The memset() here is superfluous. alloc_netdev() uses kzalloc() to allocate needed memory so there is no need to zero the priv region twice. Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/fs_enet/fs_enet-main.c | 1 - drivers/net/myri10ge/myri10ge.c | 1 - drivers/net/netxen/netxen_nic_main.c | 1 - drivers/net/sunlance.c | 1 - drivers/net/usb/pegasus.c | 1 - drivers/net/usb/rtl8150.c | 1 - 6 files changed, 6 deletions(-) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 5dc89d507e66..2812b524edae 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -956,7 +956,6 @@ static struct net_device *fs_init_instance(struct device *dev, SET_MODULE_OWNER(ndev); fep = netdev_priv(ndev); - memset(fep, 0, privsize); /* clear everything */ fep->dev = dev; dev_set_drvdata(dev, ndev); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 48b23c592406..6dc28b824935 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2956,7 +2956,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_NETDEV_DEV(netdev, &pdev->dev); mgp = netdev_priv(netdev); - memset(mgp, 0, sizeof(*mgp)); mgp->dev = netdev; netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index af16553e18b3..dcd66a6b4904 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -329,7 +329,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_NETDEV_DEV(netdev, &pdev->dev); adapter = netdev->priv; - memset(adapter, 0 , sizeof(struct netxen_adapter)); adapter->ahw.pdev = pdev; adapter->ahw.pci_func = pci_func_id; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 68e4f660367d..e94b752f9f34 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1335,7 +1335,6 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, return -ENOMEM; lp = netdev_priv(dev); - memset(lp, 0, sizeof(*lp)); if (sparc_lance_debug && version_printed++ == 0) printk (KERN_INFO "%s", version); diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 04cba6bf3d54..06838928ef47 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1306,7 +1306,6 @@ static int pegasus_probe(struct usb_interface *intf, } pegasus = netdev_priv(net); - memset(pegasus, 0, sizeof (struct pegasus)); pegasus->dev_index = dev_index; init_waitqueue_head(&pegasus->ctrl_wait); diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index fa598f0340cf..3b3a57ea2676 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -905,7 +905,6 @@ static int rtl8150_probe(struct usb_interface *intf, } dev = netdev_priv(netdev); - memset(dev, 0, sizeof(rtl8150_t)); dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); if (!dev->intr_buff) { From b1c9e0f7806d1f627f534fd0f83f235087496f7a Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Fri, 10 Aug 2007 23:29:33 -0700 Subject: [PATCH 1311/2804] cxgb3 - MAC workaround update Update the MAC workaround to deal with switches that do not honor pause frames. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/xgmac.c | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 2129210a67c1..1746003eb46a 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -507,6 +507,7 @@ struct cmac { unsigned int tx_xcnt; u64 tx_mcnt; unsigned int rx_xcnt; + unsigned int rx_ocnt; u64 rx_mcnt; unsigned int toggle_cnt; unsigned int txen; diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index c302b1a30cba..1d1c3919ab66 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -437,12 +437,13 @@ int t3_mac_enable(struct cmac *mac, int which) struct mac_stats *s = &mac->stats; if (which & MAC_DIRECTION_TX) { - t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); + t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx); mac->tx_mcnt = s->tx_frames; mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, @@ -454,6 +455,7 @@ int t3_mac_enable(struct cmac *mac, int which) mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_RX_SPI4_SOP_EOP_CNT + oft))); + mac->rx_ocnt = s->rx_fifo_ovfl; mac->txen = F_TXEN; mac->toggle_cnt = 0; } @@ -464,24 +466,19 @@ int t3_mac_enable(struct cmac *mac, int which) int t3_mac_disable(struct cmac *mac, int which) { - int idx = macidx(mac); struct adapter *adap = mac->adapter; - int val; if (which & MAC_DIRECTION_TX) { t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f); - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); - t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); mac->txen = 0; } if (which & MAC_DIRECTION_RX) { + int val = F_MAC_RESET_; + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, F_PCS_RESET_, 0); msleep(100); t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); - val = F_MAC_RESET_; if (is_10G(adap)) val |= F_PCS_RESET_; else if (uses_xaui(adap)) @@ -541,11 +538,14 @@ int t3b2_mac_watchdog_task(struct cmac *mac) } rxcheck: - if (rx_mcnt != mac->rx_mcnt) + if (rx_mcnt != mac->rx_mcnt) { rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_RX_SPI4_SOP_EOP_CNT + - mac->offset))); - else + mac->offset))) + + (s->rx_fifo_ovfl - + mac->rx_ocnt); + mac->rx_ocnt = s->rx_fifo_ovfl; + } else goto out; if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && From c821d55c67213e96e6e0feb7418746a25fea6e4d Mon Sep 17 00:00:00 2001 From: Surya Prabhakar N Date: Mon, 13 Aug 2007 15:43:30 +0530 Subject: [PATCH 1312/2804] drivers/net/tokenring/3c359.c Hi, Replacing kmalloc with kzalloc and cleaning up memset in drivers/net/tokenring/3c359.c Signed-off-by: Surya Prabhakar Signed-off-by: Jeff Garzik --- drivers/net/tokenring/3c359.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 6612db8ec215..f4251d35599d 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -641,14 +641,14 @@ static int xl_open(struct net_device *dev) * Now to set up the Rx and Tx buffer structures */ /* These MUST be on 8 byte boundaries */ - xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ; + xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL); if (xl_priv->xl_tx_ring == NULL) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n", dev->name); free_irq(dev->irq,dev); return -ENOMEM; } - xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ; + xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL); if (xl_priv->xl_tx_ring == NULL) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n", dev->name); @@ -656,8 +656,6 @@ static int xl_open(struct net_device *dev) kfree(xl_priv->xl_tx_ring); return -ENOMEM; } - memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ; - memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ; /* Setup Rx Ring */ for (i=0 ; i < XL_RX_RING_SIZE ; i++) { From 2d6d749d124d93bd03982467f515b1b88f4c1e44 Mon Sep 17 00:00:00 2001 From: Richard Knutsson Date: Tue, 14 Aug 2007 02:07:09 +0200 Subject: [PATCH 1313/2804] drivers/net/tokenring: Convert to generic boolean Convert to generic boolean Signed-off-by: Richard Knutsson Signed-off-by: Jeff Garzik --- drivers/net/tokenring/ibmtr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 51409698fe25..65e21eb7e685 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -116,9 +116,6 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */ #define ENABLE_PAGING 1 #endif -#define FALSE 0 -#define TRUE (!FALSE) - /* changes the output format of driver initialization */ #define TR_VERBOSE 0 @@ -1542,7 +1539,7 @@ static void initial_tok_int(struct net_device *dev) ti->ring_speed = init_status & 0x01 ? 16 : 4; DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n", ti->ring_speed, (unsigned int)dev->mem_start); - ti->auto_speedsave=readb(ti->init_srb+INIT_STATUS_2_OFST)&4?TRUE:FALSE; + ti->auto_speedsave = (readb(ti->init_srb+INIT_STATUS_2_OFST) & 4) != 0; if (ti->open_mode == MANUAL) wake_up(&ti->wait_for_reset); else tok_open_adapter((unsigned long)dev); From df570f93337ddb46f1e30dd167c27b5fdcec637b Mon Sep 17 00:00:00 2001 From: Richard Knutsson Date: Tue, 14 Aug 2007 01:49:40 +0200 Subject: [PATCH 1314/2804] drivers/net/3c505: Convert to generic boolean Convert to generic boolean Signed-off-by: Richard Knutsson Signed-off-by: Jeff Garzik --- drivers/net/3c505.c | 67 ++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index e985a85a5623..acede307c05d 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -167,21 +167,6 @@ static int elp_debug; * 3 = messages when interrupts received */ -/***************************************************************** - * - * useful macros - * - *****************************************************************/ - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - - /***************************************************************** * * List of I/O-addresses we try to auto-sense @@ -270,7 +255,7 @@ static inline void set_hsf(struct net_device *dev, int hsf) spin_unlock_irqrestore(&adapter->lock, flags); } -static int start_receive(struct net_device *, pcb_struct *); +static bool start_receive(struct net_device *, pcb_struct *); static inline void adapter_reset(struct net_device *dev) { @@ -328,28 +313,28 @@ static inline void check_3c505_dma(struct net_device *dev) } /* Primitive functions used by send_pcb() */ -static inline unsigned int send_pcb_slow(unsigned int base_addr, unsigned char byte) +static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte) { unsigned long timeout; outb_command(byte, base_addr); for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) { if (inb_status(base_addr) & HCRE) - return FALSE; + return false; } printk(KERN_WARNING "3c505: send_pcb_slow timed out\n"); - return TRUE; + return true; } -static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char byte) +static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte) { unsigned int timeout; outb_command(byte, base_addr); for (timeout = 0; timeout < 40000; timeout++) { if (inb_status(base_addr) & HCRE) - return FALSE; + return false; } printk(KERN_WARNING "3c505: send_pcb_fast timed out\n"); - return TRUE; + return true; } /* Check to see if the receiver needs restarting, and kick it if so */ @@ -386,7 +371,7 @@ static inline void prime_rx(struct net_device *dev) * timeout is reduced to 500us). */ -static int send_pcb(struct net_device *dev, pcb_struct * pcb) +static bool send_pcb(struct net_device *dev, pcb_struct * pcb) { int i; unsigned long timeout; @@ -396,14 +381,14 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb) check_3c505_dma(dev); if (adapter->dmaing && adapter->current_dma.direction == 0) - return FALSE; + return false; /* Avoid contention */ if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) { if (elp_debug >= 3) { printk(KERN_DEBUG "%s: send_pcb entered while threaded\n", dev->name); } - return FALSE; + return false; } /* * load each byte into the command register and @@ -435,7 +420,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb) switch (GET_ASF(dev->base_addr)) { case ASF_PCB_ACK: adapter->send_pcb_semaphore = 0; - return TRUE; + return true; case ASF_PCB_NAK: #ifdef ELP_DEBUG @@ -453,7 +438,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb) spin_unlock_irqrestore(&adapter->lock, flags); abort: adapter->send_pcb_semaphore = 0; - return FALSE; + return false; } @@ -470,7 +455,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb) * *****************************************************************/ -static int receive_pcb(struct net_device *dev, pcb_struct * pcb) +static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) { int i, j; int total_length; @@ -487,7 +472,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) { TIMEOUT_MSG(__LINE__); - return FALSE; + return false; } pcb->command = inb_command(dev->base_addr); @@ -497,14 +482,14 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) if (time_after_eq(jiffies, timeout)) { TIMEOUT_MSG(__LINE__); printk(KERN_INFO "%s: status %02x\n", dev->name, stat); - return FALSE; + return false; } pcb->length = inb_command(dev->base_addr); if (pcb->length > MAX_PCB_DATA) { INVALID_PCB_MSG(pcb->length); adapter_reset(dev); - return FALSE; + return false; } /* read the data */ spin_lock_irqsave(&adapter->lock, flags); @@ -519,7 +504,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) spin_unlock_irqrestore(&adapter->lock, flags); if (j >= 20000) { TIMEOUT_MSG(__LINE__); - return FALSE; + return false; } /* woops, the last "data" byte was really the length! */ total_length = pcb->data.raw[--i]; @@ -529,7 +514,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) if (elp_debug >= 2) printk(KERN_WARNING "%s: mangled PCB received\n", dev->name); set_hsf(dev, HSF_PCB_NAK); - return FALSE; + return false; } if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) { @@ -538,14 +523,14 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) set_hsf(dev, HSF_PCB_NAK); printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name); pcb->command = 0; - return TRUE; + return true; } else { pcb->command = 0xff; } } } set_hsf(dev, HSF_PCB_ACK); - return TRUE; + return true; } /****************************************************** @@ -555,9 +540,9 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) * ******************************************************/ -static int start_receive(struct net_device *dev, pcb_struct * tx_pcb) +static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb) { - int status; + bool status; elp_device *adapter = dev->priv; if (elp_debug >= 3) @@ -984,7 +969,7 @@ static int elp_open(struct net_device *dev) * ******************************************************/ -static int send_packet(struct net_device *dev, struct sk_buff *skb) +static bool send_packet(struct net_device *dev, struct sk_buff *skb) { elp_device *adapter = dev->priv; unsigned long target; @@ -998,7 +983,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb) if (test_and_set_bit(0, (void *) &adapter->busy)) { if (elp_debug >= 2) printk(KERN_DEBUG "%s: transmit blocked\n", dev->name); - return FALSE; + return false; } adapter->stats.tx_bytes += nlen; @@ -1015,7 +1000,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb) if (!send_pcb(dev, &adapter->tx_pcb)) { adapter->busy = 0; - return FALSE; + return false; } /* if this happens, we die */ if (test_and_set_bit(0, (void *) &adapter->dmaing)) @@ -1047,7 +1032,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb) if (elp_debug >= 3) printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name); - return TRUE; + return true; } /* From 5dcddfae63bd26da0f11a8e40f0ae555b5ac624e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 7 Aug 2007 14:56:42 -0700 Subject: [PATCH 1315/2804] xen-netfront: remove dead code This patch removes some residual dead code left over from removing the "flip" receive mode. This patch doesn't change the generated output at all, since gcc already realized it was dead. This resolves the "regression" reported by Adrian. Signed-off-by: Jeremy Fitzhardinge Cc: Adrian Bunk Cc: Michal Piotrowski Signed-off-by: Jeff Garzik --- drivers/net/xen-netfront.c | 37 ++----------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 70e551c19e3a..b4de126825e4 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -214,11 +214,9 @@ static void xennet_alloc_rx_buffers(struct net_device *dev) struct page *page; int i, batch_target, notify; RING_IDX req_prod = np->rx.req_prod_pvt; - struct xen_memory_reservation reservation; grant_ref_t ref; unsigned long pfn; void *vaddr; - int nr_flips; struct xen_netif_rx_request *req; if (unlikely(!netif_carrier_ok(dev))) @@ -268,7 +266,7 @@ no_skb: np->rx_target = np->rx_max_target; refill: - for (nr_flips = i = 0; ; i++) { + for (i = 0; ; i++) { skb = __skb_dequeue(&np->rx_batch); if (skb == NULL) break; @@ -297,38 +295,7 @@ no_skb: req->gref = ref; } - if (nr_flips != 0) { - reservation.extent_start = np->rx_pfn_array; - reservation.nr_extents = nr_flips; - reservation.extent_order = 0; - reservation.address_bits = 0; - reservation.domid = DOMID_SELF; - - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* After all PTEs have been zapped, flush the TLB. */ - np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = - UVMF_TLB_FLUSH|UVMF_ALL; - - /* Give away a batch of pages. */ - np->rx_mcl[i].op = __HYPERVISOR_memory_op; - np->rx_mcl[i].args[0] = XENMEM_decrease_reservation; - np->rx_mcl[i].args[1] = (unsigned long)&reservation; - - /* Zap PTEs and give away pages in one big - * multicall. */ - (void)HYPERVISOR_multicall(np->rx_mcl, i+1); - - /* Check return status of HYPERVISOR_memory_op(). */ - if (unlikely(np->rx_mcl[i].result != i)) - panic("Unable to reduce memory reservation\n"); - } else { - if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, - &reservation) != i) - panic("Unable to reduce memory reservation\n"); - } - } else { - wmb(); /* barrier so backend seens requests */ - } + wmb(); /* barrier so backend seens requests */ /* Above is a suitable barrier to ensure backend will see requests. */ np->rx.req_prod_pvt = req_prod + i; From ffe143741f9e0fc3731fe6fe977a2273da4837bd Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Mon, 6 Aug 2007 01:23:54 +0100 Subject: [PATCH 1316/2804] [PATCH] zd1211rw: removed noisy debug messages While developing the driver we added a lot of debug messages for setting hardware registers. These messages make the reading of the log files difficult and are of no use anymore. This patch removes those messages in zd_chip.c. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index c39f1984b84d..7e3c0625129b 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -500,8 +500,6 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip) return r; } - dev_dbg_f(zd_chip_dev(chip), - "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS); tmp &= ~UNLOCK_PHY_REGS; r = zd_iowrite32_locked(chip, tmp, CR_REG1); @@ -523,8 +521,6 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip) return r; } - dev_dbg_f(zd_chip_dev(chip), - "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS); tmp |= UNLOCK_PHY_REGS; r = zd_iowrite32_locked(chip, tmp, CR_REG1); @@ -841,8 +837,6 @@ static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) s->atim_wnd_period = values[0]; s->pre_tbtt = values[1]; s->beacon_interval = values[2]; - dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n", - s->atim_wnd_period, s->pre_tbtt, s->beacon_interval); return 0; } @@ -864,9 +858,6 @@ static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) reqs[2].addr = CR_BCN_INTERVAL; reqs[2].value = s->beacon_interval; - dev_dbg_f(zd_chip_dev(chip), - "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt, - s->beacon_interval); return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); } @@ -1160,16 +1151,12 @@ out: static int update_pwr_int(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_int_values[channel - 1]; - dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n", - channel, value); return zd_iowrite16_locked(chip, value, CR31); } static int update_pwr_cal(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_cal_values[channel-1]; - dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n", - channel, value); return zd_iowrite16_locked(chip, value, CR68); } @@ -1184,9 +1171,6 @@ static int update_ofdm_cal(struct zd_chip *chip, u8 channel) ioreqs[2].addr = CR65; ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; - dev_dbg_f(zd_chip_dev(chip), - "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n", - channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } @@ -1638,7 +1622,5 @@ int zd_chip_set_multicast_hash(struct zd_chip *chip, { CR_GROUP_HASH_P2, hash->high }, }; - dev_dbg_f(zd_chip_dev(chip), "hash l 0x%08x h 0x%08x\n", - ioreqs[0].value, ioreqs[1].value); return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs)); } From 8e97afe56984237af2115368ca0a5c525049cbd2 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 6 Aug 2007 01:24:19 +0100 Subject: [PATCH 1317/2804] [PATCH] zd1211rw: Add ID for Sitecom WL-162 Tested by Giuseppe Lippolis zd1211b chip 0cde:001a v4810 high 00-60-b3 AL2230_RF pa0 g--NS Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index a9c339ef116a..6e2c41eb50c5 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -74,6 +74,7 @@ static struct usb_device_id usb_ids[] = { { 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 }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, From 64f222cce2605420470d7a1f678783bdc2754af6 Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Mon, 6 Aug 2007 01:24:31 +0100 Subject: [PATCH 1318/2804] [PATCH] zd1211rw: consistent handling of ZD1211 specific rates As pointed out by Daniel Drake, the zd1211rw driver used several different rate values and names throughout the driver. He has written a patch to change it and tweaked it after some pretty wild ideas from my side. But the discussion helped me to understand the problem better and I think I have nailed it down with this patch. A zd-rate will consist from now on of a four-bit "pure" rate value and a modulation type flag as used in the ZD1211 control set used for packet transmission. This is consistent with the usage in the zd_rates table. If possible these zd-rates should be used in the code. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.c | 51 +++++----- drivers/net/wireless/zd1211rw/zd_ieee80211.h | 43 +++++---- drivers/net/wireless/zd1211rw/zd_mac.c | 99 ++++++-------------- drivers/net/wireless/zd1211rw/zd_mac.h | 63 +++++++++---- 4 files changed, 125 insertions(+), 131 deletions(-) diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 7e3c0625129b..495904218b1b 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -1009,19 +1009,19 @@ int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, u32 value = 0; /* Modulation bit */ - if (ZD_CS_TYPE(rts_rate) == ZD_CS_OFDM) + if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM) rts_mod = ZD_RX_OFDM; dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n", rts_rate, preamble); - value |= rts_rate << RTSCTS_SH_RTS_RATE; + value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE; value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE; value |= preamble << RTSCTS_SH_RTS_PMB_TYPE; value |= preamble << RTSCTS_SH_CTS_PMB_TYPE; /* We always send 11M self-CTS messages, like the vendor driver. */ - value |= ZD_CCK_RATE_11M << RTSCTS_SH_CTS_RATE; + value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE; value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE; return zd_iowrite32_locked(chip, value, CR_RTS_CTS_RATE); @@ -1328,7 +1328,7 @@ int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates) return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL); } -static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) +static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size) { static const u16 constants[] = { 715, 655, 585, 540, 470, 410, 360, 315, @@ -1342,7 +1342,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) /* It seems that their quality parameter is somehow per signal * and is now transferred per bit. */ - switch (rate) { + switch (zd_rate) { case ZD_OFDM_RATE_6M: case ZD_OFDM_RATE_12M: case ZD_OFDM_RATE_24M: @@ -1369,7 +1369,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) break; } - switch (rate) { + switch (zd_rate) { case ZD_OFDM_RATE_6M: case ZD_OFDM_RATE_9M: i += 3; @@ -1393,11 +1393,11 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) return i; } -static int ofdm_qual_percent(u8 status_quality, u8 rate, unsigned int size) +static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size) { int r; - r = ofdm_qual_db(status_quality, rate, size); + r = ofdm_qual_db(status_quality, zd_rate, size); ZD_ASSERT(r >= 0); if (r < 0) r = 0; @@ -1458,12 +1458,17 @@ static int cck_qual_percent(u8 status_quality) return r <= 100 ? r : 100; } +static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame) +{ + return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame); +} + u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, const struct rx_status *status) { return (status->frame_status&ZD_RX_OFDM) ? ofdm_qual_percent(status->signal_quality_ofdm, - zd_ofdm_plcp_header_rate(rx_frame), + zd_rate_from_ofdm_plcp_header(rx_frame), size) : cck_qual_percent(status->signal_quality_cck); } @@ -1479,32 +1484,32 @@ u8 zd_rx_strength_percent(u8 rssi) u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status) { static const u16 ofdm_rates[] = { - [ZD_OFDM_RATE_6M] = 60, - [ZD_OFDM_RATE_9M] = 90, - [ZD_OFDM_RATE_12M] = 120, - [ZD_OFDM_RATE_18M] = 180, - [ZD_OFDM_RATE_24M] = 240, - [ZD_OFDM_RATE_36M] = 360, - [ZD_OFDM_RATE_48M] = 480, - [ZD_OFDM_RATE_54M] = 540, + [ZD_OFDM_PLCP_RATE_6M] = 60, + [ZD_OFDM_PLCP_RATE_9M] = 90, + [ZD_OFDM_PLCP_RATE_12M] = 120, + [ZD_OFDM_PLCP_RATE_18M] = 180, + [ZD_OFDM_PLCP_RATE_24M] = 240, + [ZD_OFDM_PLCP_RATE_36M] = 360, + [ZD_OFDM_PLCP_RATE_48M] = 480, + [ZD_OFDM_PLCP_RATE_54M] = 540, }; u16 rate; if (status->frame_status & ZD_RX_OFDM) { + /* Deals with PLCP OFDM rate (not zd_rates) */ u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame); rate = ofdm_rates[ofdm_rate & 0xf]; } else { - u8 cck_rate = zd_cck_plcp_header_rate(rx_frame); - switch (cck_rate) { - case ZD_CCK_SIGNAL_1M: + switch (zd_cck_plcp_header_signal(rx_frame)) { + case ZD_CCK_PLCP_SIGNAL_1M: rate = 10; break; - case ZD_CCK_SIGNAL_2M: + case ZD_CCK_PLCP_SIGNAL_2M: rate = 20; break; - case ZD_CCK_SIGNAL_5M5: + case ZD_CCK_PLCP_SIGNAL_5M5: rate = 55; break; - case ZD_CCK_SIGNAL_11M: + case ZD_CCK_PLCP_SIGNAL_11M: rate = 110; break; default: diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h index c4f36d39642b..fbf6491dce7e 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h @@ -43,21 +43,25 @@ struct ofdm_plcp_header { __le16 service; } __attribute__((packed)); -static inline u8 zd_ofdm_plcp_header_rate( - const struct ofdm_plcp_header *header) +static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header) { return header->prefix[0] & 0xf; } -/* These are referred to as zd_rates */ -#define ZD_OFDM_RATE_6M 0xb -#define ZD_OFDM_RATE_9M 0xf -#define ZD_OFDM_RATE_12M 0xa -#define ZD_OFDM_RATE_18M 0xe -#define ZD_OFDM_RATE_24M 0x9 -#define ZD_OFDM_RATE_36M 0xd -#define ZD_OFDM_RATE_48M 0x8 -#define ZD_OFDM_RATE_54M 0xc +/* The following defines give the encoding of the 4-bit rate field in the + * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to + * define the zd-rate values for OFDM. + * + * See the struct zd_ctrlset definition in zd_mac.h. + */ +#define ZD_OFDM_PLCP_RATE_6M 0xb +#define ZD_OFDM_PLCP_RATE_9M 0xf +#define ZD_OFDM_PLCP_RATE_12M 0xa +#define ZD_OFDM_PLCP_RATE_18M 0xe +#define ZD_OFDM_PLCP_RATE_24M 0x9 +#define ZD_OFDM_PLCP_RATE_36M 0xd +#define ZD_OFDM_PLCP_RATE_48M 0x8 +#define ZD_OFDM_PLCP_RATE_54M 0xc struct cck_plcp_header { u8 signal; @@ -66,15 +70,22 @@ struct cck_plcp_header { __le16 crc16; } __attribute__((packed)); -static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header) +static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header) { return header->signal; } -#define ZD_CCK_SIGNAL_1M 0x0a -#define ZD_CCK_SIGNAL_2M 0x14 -#define ZD_CCK_SIGNAL_5M5 0x37 -#define ZD_CCK_SIGNAL_11M 0x6e +/* These defines give the encodings of the signal field in the 802.11b PLCP + * header. The signal field gives the bit rate of the following packet. Even + * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s + * rate to stay consistent with Zydas and our use of the term. + * + * Notify that these values are *not* used in the zd-rates. + */ +#define ZD_CCK_PLCP_SIGNAL_1M 0x0a +#define ZD_CCK_PLCP_SIGNAL_2M 0x14 +#define ZD_CCK_PLCP_SIGNAL_5M5 0x37 +#define ZD_CCK_PLCP_SIGNAL_11M 0x6e enum ieee80211_std { IEEE80211B = 0x01, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 7ec1fcf37fc3..451308d7095d 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -610,28 +610,6 @@ u8 zd_mac_get_channel(struct zd_mac *mac) return channel; } -/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */ -static u8 zd_rate_typed(u8 zd_rate) -{ - static const u8 typed_rates[16] = { - [ZD_CCK_RATE_1M] = ZD_CS_CCK|ZD_CCK_RATE_1M, - [ZD_CCK_RATE_2M] = ZD_CS_CCK|ZD_CCK_RATE_2M, - [ZD_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CCK_RATE_5_5M, - [ZD_CCK_RATE_11M] = ZD_CS_CCK|ZD_CCK_RATE_11M, - [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M, - [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M, - [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M, - [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M, - [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M, - [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M, - [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M, - [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M, - }; - - ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f); - return typed_rates[zd_rate & ZD_CS_RATE_MASK]; -} - int zd_mac_set_mode(struct zd_mac *mac, u32 mode) { struct ieee80211_device *ieee; @@ -739,25 +717,30 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range) static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) { + /* ZD_PURE_RATE() must be used to remove the modulation type flag of + * the zd-rate values. */ static const u8 rate_divisor[] = { - [ZD_CCK_RATE_1M] = 1, - [ZD_CCK_RATE_2M] = 2, - [ZD_CCK_RATE_5_5M] = 11, /* bits must be doubled */ - [ZD_CCK_RATE_11M] = 11, - [ZD_OFDM_RATE_6M] = 6, - [ZD_OFDM_RATE_9M] = 9, - [ZD_OFDM_RATE_12M] = 12, - [ZD_OFDM_RATE_18M] = 18, - [ZD_OFDM_RATE_24M] = 24, - [ZD_OFDM_RATE_36M] = 36, - [ZD_OFDM_RATE_48M] = 48, - [ZD_OFDM_RATE_54M] = 54, + [ZD_PURE_RATE(ZD_CCK_RATE_1M)] = 1, + [ZD_PURE_RATE(ZD_CCK_RATE_2M)] = 2, + + /* bits must be doubled */ + [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11, + + [ZD_PURE_RATE(ZD_CCK_RATE_11M)] = 11, + [ZD_PURE_RATE(ZD_OFDM_RATE_6M)] = 6, + [ZD_PURE_RATE(ZD_OFDM_RATE_9M)] = 9, + [ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12, + [ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18, + [ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24, + [ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36, + [ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48, + [ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54, }; u32 bits = (u32)tx_length * 8; u32 divisor; - divisor = rate_divisor[zd_rate]; + divisor = rate_divisor[ZD_PURE_RATE(zd_rate)]; if (divisor == 0) return -EINVAL; @@ -780,52 +763,24 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) return bits/divisor; } -enum { - R2M_SHORT_PREAMBLE = 0x01, - R2M_11A = 0x02, -}; - -static u8 zd_rate_to_modulation(u8 zd_rate, int flags) -{ - u8 modulation; - - modulation = zd_rate_typed(zd_rate); - if (flags & R2M_SHORT_PREAMBLE) { - switch (ZD_CS_RATE(modulation)) { - case ZD_CCK_RATE_2M: - case ZD_CCK_RATE_5_5M: - case ZD_CCK_RATE_11M: - modulation |= ZD_CS_CCK_PREA_SHORT; - return modulation; - } - } - if (flags & R2M_11A) { - if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM) - modulation |= ZD_CS_OFDM_MODE_11A; - } - return modulation; -} - static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs, struct ieee80211_hdr_4addr *hdr) { struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); - u8 rate, zd_rate; + u8 rate; int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; int is_multicast = is_multicast_ether_addr(hdr->addr1); int short_preamble = ieee80211softmac_short_preamble_ok(softmac, is_multicast, is_mgt); - int flags = 0; - /* FIXME: 802.11a? */ rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt); + cs->modulation = rate_to_zd_rate(rate); - if (short_preamble) - flags |= R2M_SHORT_PREAMBLE; - - zd_rate = rate_to_zd_rate(rate); - cs->modulation = zd_rate_to_modulation(zd_rate, flags); + /* Set short preamble bit when appropriate */ + if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK + && cs->modulation != ZD_CCK_RATE_1M) + cs->modulation |= ZD_CCK_PREA_SHORT; } static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, @@ -864,7 +819,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control |= ZD_CS_RTS; /* Use CTS-to-self protection if required */ - if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM && + if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM && ieee80211softmac_protection_needed(softmac)) { /* FIXME: avoid sending RTS *and* self-CTS, is that correct? */ cs->control &= ~ZD_CS_RTS; @@ -925,7 +880,7 @@ static int fill_ctrlset(struct zd_mac *mac, * - see line 53 of zdinlinef.h */ cs->service = 0; - r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation), + r = zd_calc_tx_length_us(&cs->service, ZD_RATE(cs->modulation), le16_to_cpu(cs->tx_length)); if (r < 0) return r; @@ -934,7 +889,7 @@ static int fill_ctrlset(struct zd_mac *mac, if (next_frag_len == 0) { cs->next_frame_length = 0; } else { - r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation), + r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation), next_frag_len); if (r < 0) return r; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 9f9344eb50f9..1b15bde3ff60 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -40,28 +40,51 @@ struct zd_ctrlset { #define ZD_CS_RESERVED_SIZE 25 -/* zd_crtlset field modulation */ -#define ZD_CS_RATE_MASK 0x0f -#define ZD_CS_TYPE_MASK 0x10 -#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK) -#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK) - -#define ZD_CS_CCK 0x00 -#define ZD_CS_OFDM 0x10 - -/* These are referred to as zd_rates */ -#define ZD_CCK_RATE_1M 0x00 -#define ZD_CCK_RATE_2M 0x01 -#define ZD_CCK_RATE_5_5M 0x02 -#define ZD_CCK_RATE_11M 0x03 -/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*. +/* The field modulation of struct zd_ctrlset controls the bit rate, the use + * of short or long preambles in 802.11b (CCK mode) or the use of 802.11a or + * 802.11g in OFDM mode. + * + * The term zd-rate is used for the combination of the modulation type flag + * and the "pure" rate value. */ +#define ZD_PURE_RATE_MASK 0x0f +#define ZD_MODULATION_TYPE_MASK 0x10 +#define ZD_RATE_MASK (ZD_PURE_RATE_MASK|ZD_MODULATION_TYPE_MASK) +#define ZD_PURE_RATE(modulation) ((modulation) & ZD_PURE_RATE_MASK) +#define ZD_MODULATION_TYPE(modulation) ((modulation) & ZD_MODULATION_TYPE_MASK) +#define ZD_RATE(modulation) ((modulation) & ZD_RATE_MASK) -/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */ -#define ZD_CS_CCK_PREA_LONG 0x00 -#define ZD_CS_CCK_PREA_SHORT 0x20 -#define ZD_CS_OFDM_MODE_11G 0x00 -#define ZD_CS_OFDM_MODE_11A 0x20 +/* The two possible modulation types. Notify that 802.11b doesn't use the CCK + * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain + * consistent with uses the term at other places. + */ +#define ZD_CCK 0x00 +#define ZD_OFDM 0x10 + +/* The ZD1211 firmware uses proprietary encodings of the 802.11b (CCK) rates. + * For OFDM the PLCP rate encodings are used. We combine these "pure" rates + * with the modulation type flag and call the resulting values zd-rates. + */ +#define ZD_CCK_RATE_1M (ZD_CCK|0x00) +#define ZD_CCK_RATE_2M (ZD_CCK|0x01) +#define ZD_CCK_RATE_5_5M (ZD_CCK|0x02) +#define ZD_CCK_RATE_11M (ZD_CCK|0x03) +#define ZD_OFDM_RATE_6M (ZD_OFDM|ZD_OFDM_PLCP_RATE_6M) +#define ZD_OFDM_RATE_9M (ZD_OFDM|ZD_OFDM_PLCP_RATE_9M) +#define ZD_OFDM_RATE_12M (ZD_OFDM|ZD_OFDM_PLCP_RATE_12M) +#define ZD_OFDM_RATE_18M (ZD_OFDM|ZD_OFDM_PLCP_RATE_18M) +#define ZD_OFDM_RATE_24M (ZD_OFDM|ZD_OFDM_PLCP_RATE_24M) +#define ZD_OFDM_RATE_36M (ZD_OFDM|ZD_OFDM_PLCP_RATE_36M) +#define ZD_OFDM_RATE_48M (ZD_OFDM|ZD_OFDM_PLCP_RATE_48M) +#define ZD_OFDM_RATE_54M (ZD_OFDM|ZD_OFDM_PLCP_RATE_54M) + +/* The bit 5 of the zd_ctrlset modulation field controls the preamble in CCK + * mode or the 802.11a/802.11g selection in OFDM mode. + */ +#define ZD_CCK_PREA_LONG 0x00 +#define ZD_CCK_PREA_SHORT 0x20 +#define ZD_OFDM_MODE_11G 0x00 +#define ZD_OFDM_MODE_11A 0x20 /* zd_ctrlset control field */ #define ZD_CS_NEED_RANDOM_BACKOFF 0x01 From 475fed1e22e58508cf50c882db68c7b29842d4d5 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 6 Aug 2007 02:25:18 +0100 Subject: [PATCH 1319/2804] [PATCH] zd1211rw: Add ID for ZyXEL M-202 XtremeMIMO Tested by Nathen Meyers FCC ID: SI5WUB221Z zd1211b chip 0586:340a v4810 high 00-13-49 AL2230_RF pa0 ----S Despite the product name, I'm pretty sure this isn't a MIMO device. It appears just to be a normal ZD1211B and we have never heard of these devices having more than 1 RF. I guess they named this product this way to make it appear that it fits in with the rest of their XtremeMIMO product range. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 6e2c41eb50c5..e49628b7d4ce 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -75,6 +75,7 @@ static struct usb_device_id usb_ids[] = { { 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 }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, From 7563a0b4b5c28b9695f7136fa0ef0cc4cbe1b0c6 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 7 Aug 2007 00:50:22 +0200 Subject: [PATCH 1320/2804] [PATCH] drivers/net/wireless/wl3501_cs.c: remove redundant memset Signed-off-by: Mariusz Kozlowski Signed-off-by: John W. Linville --- drivers/net/wireless/wl3501_cs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 72f3d97e7cb4..732b59f19892 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1841,7 +1841,6 @@ static int wl3501_get_encode(struct net_device *dev, tocopy = min_t(u8, len_keys, wrqu->encoding.length); tocopy = min_t(u8, tocopy, 100); wrqu->encoding.length = tocopy; - memset(extra, 0, tocopy); memcpy(extra, keys, tocopy); out: return rc; From b1b1907dceadddc7d7317f8ae85a5efec44125d8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Aug 2007 11:10:45 -0400 Subject: [PATCH 1321/2804] [PATCH] libertas: fix inadvertant removal of bits from commit 831441862956fffa17b9801db37e6ea1650b0f69 Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index f0213eca680b..ce1c18ee6280 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -768,6 +768,7 @@ static int libertas_thread(void *data) init_waitqueue_entry(&wait, current); + set_freezable(); for (;;) { lbs_deb_thread( "main-thread 111: intcounter=%d " "currenttxskb=%p dnld_sent=%d\n", From 954ee164f4f4598afc172c0ec3865d0352e55a0b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Aug 2007 11:43:25 -0400 Subject: [PATCH 1322/2804] [PATCH] libertas: reorganize and simplify init sequence This patch moves all firmware load responsibility into the interface-specific code and gets rid of the firmware pointer in the generic card structure. It also removes 3 fairly unecessary callbacks: hw_register_dev, hw_unregister_dev, and hw_prog_firmware. It also makes the init sequence from interface probe functions more logical, as there are paired add/remove and start/stop calls into generic libertas code. Because the USB driver code uses the same TX URB callback for both firmware upload (where the generic libertas structure isn't initialized yet) and for normal operation (where it is), some bits of USB code have to deal with 'priv' being NULL. All USB firmware upload bits have been changed to not require 'priv' at all, but simply the USB card structure. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/decl.h | 3 +- drivers/net/wireless/libertas/dev.h | 4 - drivers/net/wireless/libertas/if_cs.c | 54 +-- drivers/net/wireless/libertas/if_usb.c | 373 +++++++++----------- drivers/net/wireless/libertas/if_usb.h | 4 +- drivers/net/wireless/libertas/main.c | 463 ++++++++++--------------- 6 files changed, 367 insertions(+), 534 deletions(-) diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 095edf6a4c29..87fea9d5b90a 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -72,8 +72,9 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no); wlan_private *libertas_add_card(void *card, struct device *dmdev); -int libertas_activate_card(wlan_private *priv); int libertas_remove_card(wlan_private *priv); +int libertas_start_card(wlan_private *priv); +int libertas_stop_card(wlan_private *priv); int libertas_add_mesh(wlan_private *priv, struct device *dev); void libertas_remove_mesh(wlan_private *priv); int libertas_reset_device(wlan_private *priv); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index a3c94d7388ab..1fb807aa91b9 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -143,7 +143,6 @@ struct _wlan_private { all other bits reserved 0 */ u8 dnld_sent; - const struct firmware *firmware; struct device *hotplug_device; /** thread to service interrupts */ @@ -156,9 +155,6 @@ struct _wlan_private { struct work_struct sync_channel; /** Hardware access */ - int (*hw_register_dev) (wlan_private * priv); - int (*hw_unregister_dev) (wlan_private *); - int (*hw_prog_firmware) (wlan_private *); int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb); int (*hw_get_int_status) (wlan_private * priv, u8 *); int (*hw_read_event_cause) (wlan_private *); diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 888f023a74e1..4dffc5cc0d1a 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -608,51 +608,6 @@ done: /* Callback functions for libertas.ko */ /********************************************************************/ -static int if_cs_register_dev(wlan_private *priv) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - - lbs_deb_enter(LBS_DEB_CS); - - card->priv = priv; - - return 0; -} - - -static int if_cs_unregister_dev(wlan_private *priv) -{ - lbs_deb_enter(LBS_DEB_CS); - - /* - * Nothing special here. Because the device's power gets turned off - * anyway, there's no need to send a RESET command like in if_usb.c - */ - - return 0; -} - - -/* - * This callback is a dummy. The reason is that the USB code needs - * to have various things set up in order to be able to download the - * firmware. That's not needed in our case. - * - * On the contrary, if libertas_add_card() has been called and we're - * then later called via libertas_activate_card(), but without a valid - * firmware, then it's quite tedious to tear down the half-installed - * card. Therefore, we download the firmware before calling adding/ - * activating the card in the first place. If that doesn't work, we - * won't call into libertas.ko at all. - */ - -static int if_cs_prog_firmware(wlan_private *priv) -{ - priv->adapter->fw_ready = 1; - return 0; -} - - /* Send commands or data packets to the card */ static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) { @@ -902,14 +857,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev) } /* Store pointers to our call-back functions */ + card->priv = priv; priv->card = card; - priv->hw_register_dev = if_cs_register_dev; - priv->hw_unregister_dev = if_cs_unregister_dev; - priv->hw_prog_firmware = if_cs_prog_firmware; priv->hw_host_to_card = if_cs_host_to_card; priv->hw_get_int_status = if_cs_get_int_status; priv->hw_read_event_cause = if_cs_read_event_cause; + priv->adapter->fw_ready = 1; + /* Now actually get the IRQ */ ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt, IRQF_SHARED, DRV_NAME, card); @@ -919,7 +874,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) } /* And finally bring the card up */ - if (libertas_activate_card(priv) != 0) { + if (libertas_start_card(priv) != 0) { lbs_pr_err("could not activate card\n"); goto out3; } @@ -951,6 +906,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) lbs_deb_enter(LBS_DEB_CS); + libertas_stop_card(card->priv); libertas_remove_card(card->priv); if_cs_release(p_dev); kfree(card); diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 364eae374b93..105a00a7025d 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -45,14 +45,14 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); static void if_usb_receive(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb); -static int if_usb_register_dev(wlan_private * priv); -static int if_usb_unregister_dev(wlan_private *); -static int if_usb_prog_firmware(wlan_private *); +static int if_usb_prog_firmware(struct usb_card_rec *cardp); static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); static int if_usb_get_int_status(wlan_private * priv, u8 *); static int if_usb_read_event_cause(wlan_private *); -static int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); +static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb); static void if_usb_free(struct usb_card_rec *cardp); +static int if_usb_submit_rx_urb(struct usb_card_rec *cardp); +static int if_usb_reset_device(struct usb_card_rec *cardp); /** * @brief call back function to handle the status of the URB @@ -61,29 +61,40 @@ static void if_usb_free(struct usb_card_rec *cardp); */ static void if_usb_write_bulk_callback(struct urb *urb) { - wlan_private *priv = (wlan_private *) (urb->context); - wlan_adapter *adapter = priv->adapter; - struct net_device *dev = priv->dev; + struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context; /* handle the transmission complete validations */ - if (urb->status != 0) { - /* print the failure status number for debug */ - lbs_pr_info("URB in failure status: %d\n", urb->status); - } else { + if (urb->status == 0) { + wlan_private *priv = cardp->priv; + /* lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n"); lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n", urb->actual_length); */ - priv->dnld_sent = DNLD_RES_RECEIVED; - /* Wake main thread if commands are pending */ - if (!adapter->cur_cmd) - wake_up_interruptible(&priv->waitq); - if ((adapter->connect_status == LIBERTAS_CONNECTED)) { - netif_wake_queue(dev); - netif_wake_queue(priv->mesh_dev); + + /* Used for both firmware TX and regular TX. priv isn't + * valid at firmware load time. + */ + if (priv) { + wlan_adapter *adapter = priv->adapter; + struct net_device *dev = priv->dev; + + priv->dnld_sent = DNLD_RES_RECEIVED; + + /* Wake main thread if commands are pending */ + if (!adapter->cur_cmd) + wake_up_interruptible(&priv->waitq); + + if ((adapter->connect_status == LIBERTAS_CONNECTED)) { + netif_wake_queue(dev); + netif_wake_queue(priv->mesh_dev); + } } + } else { + /* print the failure status number for debug */ + lbs_pr_info("URB in failure status: %d\n", urb->status); } return; @@ -205,24 +216,35 @@ static int if_usb_probe(struct usb_interface *intf, } } - if (!(priv = libertas_add_card(cardp, &udev->dev))) - goto dealloc; + /* Upload firmware */ + cardp->rinfo.cardp = cardp; + if (if_usb_prog_firmware(cardp)) { + lbs_deb_usbd(&udev->dev, "FW upload failed"); + goto err_prog_firmware; + } - udev->dev.driver_data = priv; + if (!(priv = libertas_add_card(cardp, &udev->dev))) + goto err_prog_firmware; + + cardp->priv = priv; if (libertas_add_mesh(priv, &udev->dev)) goto err_add_mesh; - priv->hw_register_dev = if_usb_register_dev; - priv->hw_unregister_dev = if_usb_unregister_dev; - priv->hw_prog_firmware = if_usb_prog_firmware; + cardp->eth_dev = priv->dev; + priv->hw_host_to_card = if_usb_host_to_card; priv->hw_get_int_status = if_usb_get_int_status; priv->hw_read_event_cause = if_usb_read_event_cause; priv->boot2_version = udev->descriptor.bcdDevice; - if (libertas_activate_card(priv)) - goto err_activate_card; + /* Delay 200 ms to waiting for the FW ready */ + if_usb_submit_rx_urb(cardp); + msleep_interruptible(200); + priv->adapter->fw_ready = 1; + + if (libertas_start_card(priv)) + goto err_start_card; list_add_tail(&cardp->list, &usb_devices); @@ -231,11 +253,12 @@ static int if_usb_probe(struct usb_interface *intf, return 0; -err_activate_card: +err_start_card: libertas_remove_mesh(priv); err_add_mesh: - free_netdev(priv->dev); - kfree(priv->adapter); + libertas_remove_card(priv); +err_prog_firmware: + if_usb_reset_device(cardp); dealloc: if_usb_free(cardp); @@ -252,21 +275,22 @@ static void if_usb_disconnect(struct usb_interface *intf) { struct usb_card_rec *cardp = usb_get_intfdata(intf); wlan_private *priv = (wlan_private *) cardp->priv; - wlan_adapter *adapter = NULL; - adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_MAIN); - /* - * Update Surprise removed to TRUE - */ - adapter->surpriseremoved = 1; + /* Update Surprise removed to TRUE */ + cardp->surprise_removed = 1; list_del(&cardp->list); - /* card is removed and we can call wlan_remove_card */ - lbs_deb_usbd(&cardp->udev->dev, "call remove card\n"); - libertas_remove_mesh(priv); - libertas_remove_card(priv); + if (priv) { + wlan_adapter *adapter = priv->adapter; + + adapter->surpriseremoved = 1; + libertas_stop_card(priv); + libertas_remove_mesh(priv); + libertas_remove_card(priv); + } /* Unlink and free urb */ if_usb_free(cardp); @@ -274,7 +298,7 @@ static void if_usb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); - return; + lbs_deb_leave(LBS_DEB_MAIN); } /** @@ -282,12 +306,11 @@ static void if_usb_disconnect(struct usb_interface *intf) * @param priv pointer to wlan_private * @return 0 */ -static int if_prog_firmware(wlan_private * priv) +static int if_prog_firmware(struct usb_card_rec *cardp) { - struct usb_card_rec *cardp = priv->card; struct FWData *fwdata; struct fwheader *fwheader; - u8 *firmware = priv->firmware->data; + u8 *firmware = cardp->fw->data; fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); @@ -335,7 +358,7 @@ static int if_prog_firmware(wlan_private * priv) cardp->totalbytes); */ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); - usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); + usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); } else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) { /* @@ -345,7 +368,7 @@ static int if_prog_firmware(wlan_private * priv) "Donwloading FW JUMP BLOCK\n"); */ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); - usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); + usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); cardp->fwfinalblk = 1; } @@ -360,10 +383,10 @@ static int if_prog_firmware(wlan_private * priv) return 0; } -static int if_usb_reset_device(wlan_private *priv) +static int if_usb_reset_device(struct usb_card_rec *cardp) { int ret; - struct usb_card_rec *cardp = priv->card; + wlan_private * priv = cardp->priv; lbs_deb_enter(LBS_DEB_USB); @@ -371,7 +394,7 @@ static int if_usb_reset_device(wlan_private *priv) * command to the firmware. */ ret = usb_reset_device(cardp->udev); - if (!ret) { + if (!ret && priv) { msleep(10); ret = libertas_reset_device(priv); msleep(10); @@ -389,14 +412,12 @@ static int if_usb_reset_device(wlan_private *priv) * @param nb data length * @return 0 or -1 */ -static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) +static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb) { - /* pointer to card structure */ - struct usb_card_rec *cardp = priv->card; int ret = -1; /* check if device is removed */ - if (priv->adapter->surpriseremoved) { + if (cardp->surprise_removed) { lbs_deb_usbd(&cardp->udev->dev, "Device removed\n"); goto tx_ret; } @@ -404,7 +425,7 @@ static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, usb_sndbulkpipe(cardp->udev, cardp->bulk_out_endpointAddr), - payload, nb, if_usb_write_bulk_callback, priv); + payload, nb, if_usb_write_bulk_callback, cardp); cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; @@ -421,11 +442,9 @@ tx_ret: return ret; } -static int __if_usb_submit_rx_urb(wlan_private * priv, - void (*callbackfn) - (struct urb *urb)) +static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp, + void (*callbackfn)(struct urb *urb)) { - struct usb_card_rec *cardp = priv->card; struct sk_buff *skb; struct read_cb_info *rinfo = &cardp->rinfo; int ret = -1; @@ -461,22 +480,21 @@ rx_ret: return ret; } -static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv) +static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp) { - return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload); + return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); } -static inline int if_usb_submit_rx_urb(wlan_private * priv) +static int if_usb_submit_rx_urb(struct usb_card_rec *cardp) { - return __if_usb_submit_rx_urb(priv, &if_usb_receive); + return __if_usb_submit_rx_urb(cardp, &if_usb_receive); } static void if_usb_receive_fwload(struct urb *urb) { struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; - wlan_private *priv = rinfo->priv; struct sk_buff *skb = rinfo->skb; - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; + struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp; struct fwsyncheader *syncfwheader; struct bootcmdrespStr bootcmdresp; @@ -492,7 +510,7 @@ static void if_usb_receive_fwload(struct urb *urb) sizeof(bootcmdresp)); if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { kfree_skb(skb); - if_usb_submit_rx_urb_fwload(priv); + if_usb_submit_rx_urb_fwload(cardp); cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, "Received valid boot command response\n"); @@ -516,7 +534,7 @@ static void if_usb_receive_fwload(struct urb *urb) "Received valid boot command response\n"); } kfree_skb(skb); - if_usb_submit_rx_urb_fwload(priv); + if_usb_submit_rx_urb_fwload(cardp); return; } @@ -552,9 +570,9 @@ static void if_usb_receive_fwload(struct urb *urb) goto exit; } - if_prog_firmware(priv); + if_prog_firmware(cardp); - if_usb_submit_rx_urb_fwload(priv); + if_usb_submit_rx_urb_fwload(cardp); exit: kfree(syncfwheader); @@ -633,9 +651,9 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, static void if_usb_receive(struct urb *urb) { struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; - wlan_private *priv = rinfo->priv; struct sk_buff *skb = rinfo->skb; - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; + struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp; + wlan_private * priv = cardp->priv; int recvlength = urb->actual_length; u8 *recvbuff = NULL; @@ -696,7 +714,7 @@ static void if_usb_receive(struct urb *urb) } setup_for_next: - if_usb_submit_rx_urb(priv); + if_usb_submit_rx_urb(cardp); rx_exit: lbs_deb_leave(LBS_DEB_USB); } @@ -731,7 +749,7 @@ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 n memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); - return usb_tx_block(priv, cardp->bulk_out_buffer, + return usb_tx_block(cardp, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); } @@ -751,46 +769,10 @@ static int if_usb_get_int_status(wlan_private * priv, u8 * ireg) static int if_usb_read_event_cause(wlan_private * priv) { struct usb_card_rec *cardp = priv->card; + priv->adapter->eventcause = cardp->usb_event_cause; /* Re-submit rx urb here to avoid event lost issue */ - if_usb_submit_rx_urb(priv); - return 0; -} - -static int if_usb_unregister_dev(wlan_private * priv) -{ - int ret = 0; - - /* Need to send a Reset command to device before USB resources freed - * and wlan_remove_card() called, then device can handle FW download - * again. - */ - if (priv) - libertas_reset_device(priv); - - return ret; -} - - -/** - * @brief This function register usb device and initialize parameter - * @param priv pointer to wlan_private - * @return 0 or -1 - */ -static int if_usb_register_dev(wlan_private * priv) -{ - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; - - lbs_deb_enter(LBS_DEB_USB); - - cardp->priv = priv; - cardp->eth_dev = priv->dev; - priv->hotplug_device = &(cardp->udev->dev); - - lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n", - cardp->udev); - - lbs_deb_leave(LBS_DEB_USB); + if_usb_submit_rx_urb(cardp); return 0; } @@ -800,10 +782,9 @@ static int if_usb_register_dev(wlan_private * priv) * 2:Boot from FW in EEPROM * @return 0 */ -static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) +static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue) { - struct usb_card_rec *cardp = priv->card; - struct bootcmdstr sbootcmd; + struct bootcmdstr sbootcmd; int i; /* Prepare command */ @@ -814,96 +795,12 @@ static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); /* Issue command */ - usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); + usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); return 0; } -static int if_usb_do_prog_firmware(wlan_private * priv) -{ - struct usb_card_rec *cardp = priv->card; - int i = 0; - static int reset_count = 10; - int ret = 0; - - lbs_deb_enter(LBS_DEB_USB); - - cardp->rinfo.priv = priv; - -restart: - if (if_usb_submit_rx_urb_fwload(priv) < 0) { - lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); - ret = -1; - goto done; - } - - cardp->bootcmdresp = 0; - do { - int j = 0; - i++; - /* Issue Boot command = 1, Boot from Download-FW */ - if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); - /* wait for command response */ - do { - j++; - msleep_interruptible(100); - } while (cardp->bootcmdresp == 0 && j < 10); - } while (cardp->bootcmdresp == 0 && i < 5); - - if (cardp->bootcmdresp == 0) { - if (--reset_count >= 0) { - if_usb_reset_device(priv); - goto restart; - } - return -1; - } - - i = 0; - priv->adapter->fw_ready = 0; - - cardp->totalbytes = 0; - cardp->fwlastblksent = 0; - cardp->CRC_OK = 1; - cardp->fwdnldover = 0; - cardp->fwseqnum = -1; - cardp->totalbytes = 0; - cardp->fwfinalblk = 0; - - if_prog_firmware(priv); - - do { - lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); - i++; - msleep_interruptible(100); - if (priv->adapter->surpriseremoved || i >= 20) - break; - } while (!cardp->fwdnldover); - - if (!cardp->fwdnldover) { - lbs_pr_info("failed to load fw, resetting device!\n"); - if (--reset_count >= 0) { - if_usb_reset_device(priv); - goto restart; - } - - lbs_pr_info("FW download failure, time = %d ms\n", i * 100); - ret = -1; - goto done; - } - - if_usb_submit_rx_urb(priv); - - /* Delay 200 ms to waiting for the FW ready */ - msleep_interruptible(200); - - priv->adapter->fw_ready = 1; - -done: - lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); - return ret; -} - /** * @brief This function checks the validity of Boot2/FW image. * @@ -952,28 +849,90 @@ static int check_fwfile_format(u8 *data, u32 totlen) } -static int if_usb_prog_firmware(wlan_private *priv) +static int if_usb_prog_firmware(struct usb_card_rec *cardp) { - int ret = -1; + int i = 0; + static int reset_count = 10; + int ret = 0; - lbs_deb_enter(LBS_DEB_FW); + lbs_deb_enter(LBS_DEB_USB); - if ((ret = request_firmware(&priv->firmware, libertas_fw_name, - priv->hotplug_device)) < 0) { + if ((ret = request_firmware(&cardp->fw, libertas_fw_name, + &cardp->udev->dev)) < 0) { lbs_pr_err("request_firmware() failed with %#x\n", ret); lbs_pr_err("firmware %s not found\n", libertas_fw_name); goto done; } - if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) { - release_firmware(priv->firmware); - goto done; + if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) + goto release_fw; + +restart: + if (if_usb_submit_rx_urb_fwload(cardp) < 0) { + lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); + ret = -1; + goto release_fw; } - ret = if_usb_do_prog_firmware(priv); + cardp->bootcmdresp = 0; + do { + int j = 0; + i++; + /* Issue Boot command = 1, Boot from Download-FW */ + if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); + /* wait for command response */ + do { + j++; + msleep_interruptible(100); + } while (cardp->bootcmdresp == 0 && j < 10); + } while (cardp->bootcmdresp == 0 && i < 5); + + if (cardp->bootcmdresp == 0) { + if (--reset_count >= 0) { + if_usb_reset_device(cardp); + goto restart; + } + return -1; + } + + i = 0; + + cardp->totalbytes = 0; + cardp->fwlastblksent = 0; + cardp->CRC_OK = 1; + cardp->fwdnldover = 0; + cardp->fwseqnum = -1; + cardp->totalbytes = 0; + cardp->fwfinalblk = 0; + + if_prog_firmware(cardp); + + do { + lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); + i++; + msleep_interruptible(100); + if (cardp->surprise_removed || i >= 20) + break; + } while (!cardp->fwdnldover); + + if (!cardp->fwdnldover) { + lbs_pr_info("failed to load fw, resetting device!\n"); + if (--reset_count >= 0) { + if_usb_reset_device(cardp); + goto restart; + } + + lbs_pr_info("FW download failure, time = %d ms\n", i * 100); + ret = -1; + goto release_fw; + } + +release_fw: + release_firmware(cardp->fw); + cardp->fw = NULL; - release_firmware(priv->firmware); done: + lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 8b3b4f1e47f6..e07a10ed28b5 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -38,7 +38,7 @@ struct bootcmdrespStr /* read callback private data */ struct read_cb_info { - wlan_private *priv; + struct usb_card_rec *cardp; struct sk_buff *skb; }; @@ -58,6 +58,7 @@ struct usb_card_rec { int bulk_out_size; u8 bulk_out_endpointAddr; + const struct firmware *fw; u8 CRC_OK; u32 fwseqnum; u32 lastseqnum; @@ -65,6 +66,7 @@ struct usb_card_rec { u32 fwlastblksent; u8 fwdnldover; u8 fwfinalblk; + u8 surprise_removed; u32 usb_event_cause; u8 usb_int_cause; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ce1c18ee6280..6304bd97d399 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -791,7 +791,6 @@ static int libertas_thread(void *data) } else spin_unlock_irq(&adapter->driver_lock); - lbs_deb_thread( "main-thread 222 (waking up): intcounter=%d currenttxskb=%p " "dnld_sent=%d\n", adapter->intcounter, @@ -926,7 +925,7 @@ static int libertas_thread(void *data) * @param priv A pointer to wlan_private structure * @return 0 or -1 */ -static int wlan_setup_station_hw(wlan_private * priv) +static int wlan_setup_firmware(wlan_private * priv) { int ret = -1; wlan_adapter *adapter = priv->adapter; @@ -934,14 +933,6 @@ static int wlan_setup_station_hw(wlan_private * priv) lbs_deb_enter(LBS_DEB_FW); - ret = priv->hw_prog_firmware(priv); - - if (ret) { - lbs_deb_fw("bootloader in invalid state\n"); - ret = -1; - goto done; - } - /* * Read MAC address from HW */ @@ -992,8 +983,6 @@ done: return ret; } -static void command_timer_fn(unsigned long data); - /** * This function handles the timeout of command sending. * It will re-send the same command again. @@ -1035,6 +1024,76 @@ static void command_timer_fn(unsigned long data) return; } +static int libertas_init_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + size_t bufsize; + int i, ret = 0; + + /* Allocate buffer to store the BSSID list */ + bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); + adapter->networks = kzalloc(bufsize, GFP_KERNEL); + if (!adapter->networks) { + lbs_pr_err("Out of memory allocating beacons\n"); + ret = -1; + goto out; + } + + /* Initialize scan result lists */ + INIT_LIST_HEAD(&adapter->network_free_list); + INIT_LIST_HEAD(&adapter->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + list_add_tail(&adapter->networks[i].list, + &adapter->network_free_list); + } + + adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); + adapter->libertas_ps_confirm_sleep.command = + cpu_to_le16(CMD_802_11_PS_MODE); + adapter->libertas_ps_confirm_sleep.size = + cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); + adapter->libertas_ps_confirm_sleep.action = + cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); + + memset(adapter->current_addr, 0xff, ETH_ALEN); + + adapter->connect_status = LIBERTAS_DISCONNECTED; + adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + adapter->mode = IW_MODE_INFRA; + adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; + adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; + adapter->radioon = RADIO_ON; + adapter->auto_rate = 1; + adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; + adapter->psmode = WLAN802_11POWERMODECAM; + adapter->psstate = PS_STATE_FULL_POWER; + + mutex_init(&adapter->lock); + + memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); + adapter->tx_queue_idx = 0; + spin_lock_init(&adapter->txqueue_lock); + + setup_timer(&adapter->command_timer, command_timer_fn, + (unsigned long)priv); + + INIT_LIST_HEAD(&adapter->cmdfreeq); + INIT_LIST_HEAD(&adapter->cmdpendingq); + + spin_lock_init(&adapter->driver_lock); + init_waitqueue_head(&adapter->cmd_pending); + adapter->nr_cmd_pending = 0; + + /* Allocate the command buffers */ + if (libertas_allocate_cmd_buffer(priv)) { + lbs_pr_err("Out of memory allocating command buffers\n"); + ret = -1; + } + +out: + return ret; +} + static void libertas_free_adapter(wlan_private * priv) { wlan_adapter *adapter = priv->adapter; @@ -1060,132 +1119,6 @@ static void libertas_free_adapter(wlan_private * priv) priv->adapter = NULL; } -static int wlan_allocate_adapter(wlan_private * priv) -{ - size_t bufsize; - wlan_adapter *adapter = priv->adapter; - - /* Allocate buffer to store the BSSID list */ - bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); - adapter->networks = kzalloc(bufsize, GFP_KERNEL); - if (!adapter->networks) { - lbs_pr_err("Out of memory allocating beacons\n"); - libertas_free_adapter(priv); - return -ENOMEM; - } - - /* Allocate the command buffers */ - libertas_allocate_cmd_buffer(priv); - - memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); - adapter->libertas_ps_confirm_sleep.command = - cpu_to_le16(CMD_802_11_PS_MODE); - adapter->libertas_ps_confirm_sleep.size = - cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.result = 0; - adapter->libertas_ps_confirm_sleep.action = - cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); - - return 0; -} - -static void wlan_init_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int i; - - adapter->connect_status = LIBERTAS_DISCONNECTED; - memset(adapter->current_addr, 0xff, ETH_ALEN); - - /* 802.11 specific */ - adapter->secinfo.wep_enabled = 0; - for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); - i++) - memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); - adapter->wep_tx_keyidx = 0; - adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; - adapter->mode = IW_MODE_INFRA; - - adapter->pending_assoc_req = NULL; - adapter->in_progress_assoc_req = NULL; - - /* Initialize scan result lists */ - INIT_LIST_HEAD(&adapter->network_free_list); - INIT_LIST_HEAD(&adapter->network_list); - for (i = 0; i < MAX_NETWORK_COUNT; i++) { - list_add_tail(&adapter->networks[i].list, - &adapter->network_free_list); - } - - mutex_init(&adapter->lock); - - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); - adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; - - /* PnP and power profile */ - adapter->surpriseremoved = 0; - - adapter->currentpacketfilter = - CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - - adapter->radioon = RADIO_ON; - - adapter->auto_rate = 1; - adapter->cur_rate = 0; - - // set default capabilities - adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; - - adapter->psmode = WLAN802_11POWERMODECAM; - - adapter->psstate = PS_STATE_FULL_POWER; - adapter->needtowakeup = 0; - - adapter->intcounter = 0; - - adapter->currenttxskb = NULL; - - memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); - adapter->tx_queue_idx = 0; - spin_lock_init(&adapter->txqueue_lock); - - return; -} - -static int libertas_init_fw(wlan_private * priv) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; - - lbs_deb_enter(LBS_DEB_FW); - - /* Allocate adapter structure */ - if ((ret = wlan_allocate_adapter(priv)) != 0) - goto done; - - /* init adapter structure */ - wlan_init_adapter(priv); - - /* init timer etc. */ - setup_timer(&adapter->command_timer, command_timer_fn, - (unsigned long)priv); - - /* download fimrware etc. */ - if ((ret = wlan_setup_station_hw(priv)) != 0) { - del_timer_sync(&adapter->command_timer); - goto done; - } - - /* init 802.11d */ - libertas_init_11d(priv); - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); - return ret; -} - /** * @brief This function adds the card. it will probe the * card, allocate the wlan_priv and initialize the device. @@ -1203,9 +1136,9 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) /* Allocate an Ethernet device and register it */ if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { lbs_pr_err("init ethX device failed\n"); - return NULL; + goto done; } - priv = dev->priv; + dmdev->driver_data = priv = dev->priv; /* allocate buffer for wlan_adapter */ if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) { @@ -1213,10 +1146,16 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) goto err_kzalloc; } + if (libertas_init_adapter(priv)) { + lbs_pr_err("failed to initialize adapter structure.\n"); + goto err_init_adapter; + } + priv->dev = dev; priv->card = card; priv->mesh_open = 0; priv->infra_open = 0; + priv->hotplug_device = dmdev; SET_MODULE_OWNER(dev); @@ -1239,87 +1178,144 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) SET_NETDEV_DEV(dev, dmdev); - INIT_LIST_HEAD(&priv->adapter->cmdfreeq); - INIT_LIST_HEAD(&priv->adapter->cmdpendingq); - - spin_lock_init(&priv->adapter->driver_lock); - init_waitqueue_head(&priv->adapter->cmd_pending); - priv->adapter->nr_cmd_pending = 0; priv->rtap_net_dev = NULL; if (device_create_file(dmdev, &dev_attr_libertas_rtap)) - goto err_kzalloc; - goto done; - -err_kzalloc: - free_netdev(dev); - priv = NULL; -done: - lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv); - return priv; -} -EXPORT_SYMBOL_GPL(libertas_add_card); - -int libertas_activate_card(wlan_private *priv) -{ - struct net_device *dev = priv->dev; - int ret = -1; - - lbs_deb_enter(LBS_DEB_MAIN); + goto err_init_adapter; lbs_deb_thread("Starting main thread...\n"); init_waitqueue_head(&priv->waitq); priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); if (IS_ERR(priv->main_thread)) { lbs_deb_thread("Error creating main thread.\n"); - goto done; + goto err_kthread_run; } priv->work_thread = create_singlethread_workqueue("libertas_worker"); INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); - INIT_WORK(&priv->sync_channel, libertas_sync_channel); - /* - * Register the device. Fillup the private data structure with - * relevant information from the card and request for the required - * IRQ. - */ - if (priv->hw_register_dev(priv) < 0) { - lbs_pr_err("failed to register WLAN device\n"); - goto err_registerdev; + goto done; + +err_kthread_run: + device_remove_file(dmdev, &dev_attr_libertas_rtap); + +err_init_adapter: + libertas_free_adapter(priv); + +err_kzalloc: + free_netdev(dev); + priv = NULL; + +done: + lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv); + return priv; +} +EXPORT_SYMBOL_GPL(libertas_add_card); + + +int libertas_remove_card(wlan_private *priv) +{ + wlan_adapter *adapter = priv->adapter; + struct net_device *dev = priv->dev; + union iwreq_data wrqu; + + lbs_deb_enter(LBS_DEB_MAIN); + + libertas_remove_rtap(priv); + + dev = priv->dev; + device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); + + cancel_delayed_work(&priv->scan_work); + cancel_delayed_work(&priv->assoc_work); + destroy_workqueue(priv->work_thread); + + if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { + adapter->psmode = WLAN802_11POWERMODECAM; + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } - /* init FW and HW */ - if (libertas_init_fw(priv)) { - lbs_pr_err("firmware init failed\n"); - goto err_registerdev; - } + memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + /* Stop the thread servicing the interrupts */ + adapter->surpriseremoved = 1; + kthread_stop(priv->main_thread); + + libertas_free_adapter(priv); + + priv->dev = NULL; + free_netdev(dev); + + lbs_deb_leave(LBS_DEB_MAIN); + return 0; +} +EXPORT_SYMBOL_GPL(libertas_remove_card); + + +int libertas_start_card(wlan_private *priv) +{ + struct net_device *dev = priv->dev; + int ret = -1; + + lbs_deb_enter(LBS_DEB_MAIN); + + /* poke the firmware */ + ret = wlan_setup_firmware(priv); + if (ret) + goto done; + + /* init 802.11d */ + libertas_init_11d(priv); if (register_netdev(dev)) { lbs_pr_err("cannot register ethX device\n"); - goto err_init_fw; + goto done; } - lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); - libertas_debugfs_init_one(priv, dev); - ret = 0; - goto done; + lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); + + ret = 0; -err_init_fw: - priv->hw_unregister_dev(priv); -err_registerdev: - destroy_workqueue(priv->work_thread); - /* Stop the thread servicing the interrupts */ - wake_up_interruptible(&priv->waitq); - kthread_stop(priv->main_thread); done: - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_activate_card); +EXPORT_SYMBOL_GPL(libertas_start_card); + + +int libertas_stop_card(wlan_private *priv) +{ + struct net_device *dev = priv->dev; + int ret = -1; + struct cmd_ctrl_node *cmdnode; + unsigned long flags; + + lbs_deb_enter(LBS_DEB_MAIN); + + netif_stop_queue(priv->dev); + netif_carrier_off(priv->dev); + + libertas_debugfs_remove_one(priv); + + /* Flush pending command nodes */ + spin_lock_irqsave(&priv->adapter->driver_lock, flags); + list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { + cmdnode->cmdwaitqwoken = 1; + wake_up_interruptible(&cmdnode->cmdwait_q); + } + spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); + + unregister_netdev(dev); + + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(libertas_stop_card); /** @@ -1389,89 +1385,12 @@ done: } EXPORT_SYMBOL_GPL(libertas_add_mesh); -static void wake_pending_cmdnodes(wlan_private *priv) -{ - struct cmd_ctrl_node *cmdnode; - unsigned long flags; - - lbs_deb_enter(LBS_DEB_HOST); - - spin_lock_irqsave(&priv->adapter->driver_lock, flags); - list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { - cmdnode->cmdwaitqwoken = 1; - wake_up_interruptible(&cmdnode->cmdwait_q); - } - spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); -} - - -int libertas_remove_card(wlan_private *priv) -{ - wlan_adapter *adapter; - struct net_device *dev; - union iwreq_data wrqu; - - lbs_deb_enter(LBS_DEB_NET); - - libertas_remove_rtap(priv); - if (!priv) - goto out; - - adapter = priv->adapter; - - if (!adapter) - goto out; - - dev = priv->dev; - device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); - - netif_stop_queue(priv->dev); - netif_carrier_off(priv->dev); - - wake_pending_cmdnodes(priv); - - unregister_netdev(dev); - - cancel_delayed_work(&priv->scan_work); - cancel_delayed_work(&priv->assoc_work); - destroy_workqueue(priv->work_thread); - - if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { - adapter->psmode = WLAN802_11POWERMODECAM; - libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); - } - - memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - adapter->surpriseremoved = 1; - - /* Stop the thread servicing the interrupts */ - kthread_stop(priv->main_thread); - - libertas_debugfs_remove_one(priv); - - lbs_deb_net("free adapter\n"); - libertas_free_adapter(priv); - - lbs_deb_net("unregister finish\n"); - - priv->dev = NULL; - free_netdev(dev); - -out: - lbs_deb_leave(LBS_DEB_NET); - return 0; -} -EXPORT_SYMBOL_GPL(libertas_remove_card); - void libertas_remove_mesh(wlan_private *priv) { struct net_device *mesh_dev; - lbs_deb_enter(LBS_DEB_NET); + lbs_deb_enter(LBS_DEB_MAIN); if (!priv) goto out; @@ -1488,7 +1407,7 @@ void libertas_remove_mesh(wlan_private *priv) free_netdev(mesh_dev); out: - lbs_deb_leave(LBS_DEB_NET); + lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(libertas_remove_mesh); From 64f104e89b2b30107a21c5f05c3e2ffa6291e129 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Aug 2007 11:45:16 -0400 Subject: [PATCH 1323/2804] [PATCH] libertas: don't stomp on interface-specific private data Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 6304bd97d399..3feddcc750ed 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -256,7 +256,7 @@ void libertas_remove_rtap(wlan_private *priv); static ssize_t libertas_rtap_get(struct device * dev, struct device_attribute *attr, char * buf) { - wlan_private *priv = (wlan_private *) dev->driver_data; + wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv; wlan_adapter *adapter = priv->adapter; return snprintf(buf, 5, "0x%X\n", adapter->monitormode); } @@ -268,7 +268,7 @@ static ssize_t libertas_rtap_set(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { int monitor_mode; - wlan_private *priv = (wlan_private *) dev->driver_data; + wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv; wlan_adapter *adapter = priv->adapter; sscanf(buf, "%x", &monitor_mode); @@ -1138,7 +1138,7 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) lbs_pr_err("init ethX device failed\n"); goto done; } - dmdev->driver_data = priv = dev->priv; + priv = dev->priv; /* allocate buffer for wlan_adapter */ if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) { From b6e99dd6e2c5262e3c2b976d1d5f2c9405433d9a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Aug 2007 12:22:15 -0400 Subject: [PATCH 1324/2804] [PATCH] libertas: send reset command directly instead of calling libertas_reset_device Ensures that any platform specific code that might live in libertas_reset_device (for example, OLPC tells the EC to do a GPIO-toggled reset of the wireless from libertas_reset_device) isn't called. Could be handled better by interface-specific callbacks and a flag for "other hardware reset". Signed-off-by: Dan Williams Signed-off-by: Marcelo Tosatti Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 105a00a7025d..8a3c70e54075 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -1044,8 +1044,10 @@ static void if_usb_exit_module(void) lbs_deb_enter(LBS_DEB_MAIN); - list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) - libertas_reset_device((wlan_private *) cardp->priv); + list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) { + libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET, + CMD_ACT_HALT, 0, 0, NULL); + } /* API unregisters the driver from USB subsystem */ usb_deregister(&if_usb_driver); From 794760f750655d987499d7a5034519afc84af63b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Aug 2007 12:24:42 -0400 Subject: [PATCH 1325/2804] [PATCH] libertas: properly end commands on hardware failure Make sure that errors reported by the hardware layer is properly handled. Otherwise commands tend to get stuck in limbo. Signed-off-by: Pierre Ossman Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 98092b995352..33dbed09fc72 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1009,7 +1009,9 @@ static int DownloadcommandToStation(wlan_private * priv, if (ret != 0) { lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n"); spin_lock_irqsave(&adapter->driver_lock, flags); + adapter->cur_cmd_retcode = ret; __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); + adapter->nr_cmd_pending--; adapter->cur_cmd = NULL; spin_unlock_irqrestore(&adapter->driver_lock, flags); goto done; From 70500f5443be1b27ea2c9ab71ce9dc2250af7b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Va=C5=A1ut?= Date: Mon, 20 Aug 2007 12:55:41 -0400 Subject: [PATCH 1326/2804] [PATCH] libertas: region code values specified as 8bit This patch strips away possible mess in regioncode (eg. on my card - 88W8305 chipset - I get 0x3031 instead of expected 0x0031 and as a result the driver defaults to USA region which is obviously incorrect). Following patch fixes the issue. Signed-off-by: Marek Vasut Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 4c36e63ae7b0..d64ad87db459 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -174,7 +174,11 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", hwspec->hwifversion, hwspec->version); - adapter->regioncode = le16_to_cpu(hwspec->regioncode); + /* Clamp region code to 8-bit since FW spec indicates that it should + * only ever be 8-bit, even though the field size is 16-bit. Some firmware + * returns non-zero high 8 bits here. + */ + adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF; for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { /* use the region code to search for the index */ From 4b04f19625dcf43171b0b8d53be050a8f144c43d Mon Sep 17 00:00:00 2001 From: Brajesh Dave Date: Mon, 20 Aug 2007 13:09:13 -0400 Subject: [PATCH 1327/2804] [PATCH] libertas: advertise 11g ad-hoc rates Advertise support for 802.11g bitrates when starting adhoc networks, not just 802.11b bitrates. Signed-off-by: Brajesh Dave Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index ce49d3f25613..72f81208bf25 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -550,8 +550,8 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); memset(adhs->rates, 0, sizeof(adhs->rates)); - ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b)); - memcpy(adhs->rates, adhoc_rates_b, ratesize); + ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates)); + memcpy(adhs->rates, libertas_bg_rates, ratesize); /* Copy the ad-hoc creating rates into Current BSS state structure */ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); From 655b4d16ac5e551e5c8dac5812156edfd87bf822 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 11:48:16 -0400 Subject: [PATCH 1328/2804] [PATCH] net: Kill some unneeded allocation return value casts in libertas kmalloc() and friends return void*, no need to cast it. Signed-off-by: Jesper Juhl Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 2 +- drivers/net/wireless/libertas/ethtool.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 6d95148e8725..816f42e4f5b4 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -1838,7 +1838,7 @@ static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf, char *p2; struct debug_data *d = (struct debug_data *)f->private_data; - pdata = (char *)kmalloc(cnt, GFP_KERNEL); + pdata = kmalloc(cnt, GFP_KERNEL); if (pdata == NULL) return 0; diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index ec99cb825871..d793d843f7d5 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -60,8 +60,7 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev, // mutex_lock(&priv->mutex); - adapter->prdeeprom = - (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); + adapter->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); if (!adapter->prdeeprom) return -ENOMEM; memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl)); From 4ecd41bd0ff5dfcb4f2c59d980f9196c160882be Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Aug 2007 02:15:45 -0700 Subject: [PATCH 1329/2804] [PATCH] libertas: printk warning fixes drivers/net/wireless/libertas/if_cs.c: In function 'if_cs_prog_helper': drivers/net/wireless/libertas/if_cs.c:462: warning: format '%d' expects type 'int', but argument 3 has type 'size_t' drivers/net/wireless/libertas/if_cs.c: In function 'if_cs_prog_real': drivers/net/wireless/libertas/if_cs.c:538: warning: format '%d' expects type 'int', but argument 3 has type 'size_t' Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 4dffc5cc0d1a..09c87df5c2fd 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -459,7 +459,7 @@ static int if_cs_prog_helper(struct if_cs_card *card) ret = -ENODEV; goto done; } - lbs_deb_cs("helper size %d\n", fw->size); + lbs_deb_cs("helper size %td\n", fw->size); /* "Set the 5 bytes of the helper image to 0" */ /* Not needed, this contains an ARM branch instruction */ @@ -535,7 +535,7 @@ static int if_cs_prog_real(struct if_cs_card *card) ret = -ENODEV; goto done; } - lbs_deb_cs("fw size %d\n", fw->size); + lbs_deb_cs("fw size %td\n", fw->size); ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); if (ret < 0) { From cbdb9e43d1fc50cfa509b1006e7252dc4ea53aa0 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 28 Aug 2007 17:35:02 -0400 Subject: [PATCH 1330/2804] [PATCH] libertas: remove unused adhoc_rates_b definition Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 72f81208bf25..0ad1362b14e2 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -17,9 +17,6 @@ #include "dev.h" #include "assoc.h" -/* Supported rates for ad-hoc B mode */ -static u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; - /* The firmware needs certain bits masked out of the beacon-derviced capability * field when associating/joining to BSSs. */ From bc7f75fa97884d41efbfde1397b621fefb2550b4 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 17 Sep 2007 12:30:59 -0700 Subject: [PATCH 1331/2804] [E1000E]: New pci-express e1000 driver (currently for ICH9 devices only) This driver implements support for the ICH9 on-board LAN ethernet device. The device is similar to ICH8. The driver encompasses code to support 82571/2/3, es2lan and ICH8 devices as well, but those device IDs are disabled and will be "lifted" from the e1000 driver over one at a time once this driver receives some more live time. Changes to the last snapshot posted are exclusively in the internal hardware API organization. Many thanks to Jeff Garzik for jumping in and getting this organized with a keen eye on the future layout. [ Integrated napi_struct patch from Auke as well... -DaveM ] Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/Kconfig | 23 + drivers/net/Makefile | 1 + drivers/net/e1000e/82571.c | 1351 +++++++++++ drivers/net/e1000e/Makefile | 37 + drivers/net/e1000e/defines.h | 739 ++++++ drivers/net/e1000e/e1000.h | 514 ++++ drivers/net/e1000e/es2lan.c | 1232 ++++++++++ drivers/net/e1000e/ethtool.c | 1774 ++++++++++++++ drivers/net/e1000e/hw.h | 864 +++++++ drivers/net/e1000e/ich8lan.c | 2225 +++++++++++++++++ drivers/net/e1000e/lib.c | 2487 +++++++++++++++++++ drivers/net/e1000e/netdev.c | 4441 ++++++++++++++++++++++++++++++++++ drivers/net/e1000e/param.c | 382 +++ drivers/net/e1000e/phy.c | 1773 ++++++++++++++ 14 files changed, 17843 insertions(+) create mode 100644 drivers/net/e1000e/82571.c create mode 100644 drivers/net/e1000e/Makefile create mode 100644 drivers/net/e1000e/defines.h create mode 100644 drivers/net/e1000e/e1000.h create mode 100644 drivers/net/e1000e/es2lan.c create mode 100644 drivers/net/e1000e/ethtool.c create mode 100644 drivers/net/e1000e/hw.h create mode 100644 drivers/net/e1000e/ich8lan.c create mode 100644 drivers/net/e1000e/lib.c create mode 100644 drivers/net/e1000e/netdev.c create mode 100644 drivers/net/e1000e/param.c create mode 100644 drivers/net/e1000e/phy.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 734f8403c806..502dd0eb8809 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2055,6 +2055,29 @@ config E1000_DISABLE_PACKET_SPLIT If in doubt, say N. +config E1000E + tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" + depends on PCI + ---help--- + This driver supports the PCI-Express Intel(R) PRO/1000 gigabit + ethernet family of adapters. For PCI or PCI-X e1000 adapters, + use the regular e1000 driver For more information on how to + identify your adapter, go to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here and read + . The module + will be called e1000e. + source "drivers/net/ixp2000/Kconfig" config MYRI_SBUS diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d6f7302ab72d..0d2b4bee587c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_E1000) += e1000/ +obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_CHELSIO_T1) += chelsio/ diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c new file mode 100644 index 000000000000..cf70522fc851 --- /dev/null +++ b/drivers/net/e1000e/82571.c @@ -0,0 +1,1351 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * 82571EB Gigabit Ethernet Controller + * 82571EB Gigabit Ethernet Controller (Fiber) + * 82572EI Gigabit Ethernet Controller (Copper) + * 82572EI Gigabit Ethernet Controller (Fiber) + * 82572EI Gigabit Ethernet Controller + * 82573V Gigabit Ethernet Controller (Copper) + * 82573E Gigabit Ethernet Controller (Copper) + * 82573L Gigabit Ethernet Controller + */ + +#include +#include +#include + +#include "e1000.h" + +#define ID_LED_RESERVED_F746 0xF746 +#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_OFF1_ON2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) + +#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 + +static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); +static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); +static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); +static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); +static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw); +static s32 e1000_setup_link_82571(struct e1000_hw *hw); +static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); + +/** + * e1000_init_phy_params_82571 - Init PHY func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + + if (hw->media_type != e1000_media_type_copper) { + phy->type = e1000_phy_none; + return 0; + } + + phy->addr = 1; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->reset_delay_us = 100; + + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + phy->type = e1000_phy_igp_2; + break; + case e1000_82573: + phy->type = e1000_phy_m88; + break; + default: + return -E1000_ERR_PHY; + break; + } + + /* This can only be done after all function pointers are setup. */ + ret_val = e1000_get_phy_id_82571(hw); + + /* Verify phy id */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + if (phy->id != IGP01E1000_I_PHY_ID) + return -E1000_ERR_PHY; + break; + case e1000_82573: + if (phy->id != M88E1111_I_PHY_ID) + return -E1000_ERR_PHY; + break; + default: + return -E1000_ERR_PHY; + break; + } + + return 0; +} + +/** + * e1000_init_nvm_params_82571 - Init NVM func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + u16 size; + + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + + switch (hw->mac.type) { + case e1000_82573: + if (((eecd >> 15) & 0x3) == 0x3) { + nvm->type = e1000_nvm_flash_hw; + nvm->word_size = 2048; + /* Autonomous Flash update bit must be cleared due + * to Flash update issue. + */ + eecd &= ~E1000_EECD_AUPDEN; + ew32(EECD, eecd); + break; + } + /* Fall Through */ + default: + nvm->type = e1000_nvm_eeprom_spi; + size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); + /* Added to a constant, "size" becomes the left-shift value + * for setting word_size. + */ + size += NVM_WORD_SIZE_BASE_SHIFT; + nvm->word_size = 1 << size; + break; + } + + return 0; +} + +/** + * e1000_init_mac_params_82571 - Init MAC func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct e1000_mac_operations *func = &mac->ops; + + /* Set media type */ + switch (adapter->pdev->device) { + case E1000_DEV_ID_82571EB_FIBER: + case E1000_DEV_ID_82572EI_FIBER: + case E1000_DEV_ID_82571EB_QUAD_FIBER: + hw->media_type = e1000_media_type_fiber; + break; + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82572EI_SERDES: + hw->media_type = e1000_media_type_internal_serdes; + break; + default: + hw->media_type = e1000_media_type_copper; + break; + } + + /* Set mta register count */ + mac->mta_reg_count = 128; + /* Set rar entry count */ + mac->rar_entry_count = E1000_RAR_ENTRIES; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = + (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0; + + /* check for link */ + switch (hw->media_type) { + case e1000_media_type_copper: + func->setup_physical_interface = e1000_setup_copper_link_82571; + func->check_for_link = e1000e_check_for_copper_link; + func->get_link_up_info = e1000e_get_speed_and_duplex_copper; + break; + case e1000_media_type_fiber: + func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571; + func->check_for_link = e1000e_check_for_fiber_link; + func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes; + break; + case e1000_media_type_internal_serdes: + func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571; + func->check_for_link = e1000e_check_for_serdes_link; + func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes; + break; + default: + return -E1000_ERR_CONFIG; + break; + } + + return 0; +} + +static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + static int global_quad_port_a; /* global port a indication */ + struct pci_dev *pdev = adapter->pdev; + u16 eeprom_data = 0; + int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1; + s32 rc; + + rc = e1000_init_mac_params_82571(adapter); + if (rc) + return rc; + + rc = e1000_init_nvm_params_82571(hw); + if (rc) + return rc; + + rc = e1000_init_phy_params_82571(hw); + if (rc) + return rc; + + /* tag quad port adapters first, it's used below */ + switch (pdev->device) { + case E1000_DEV_ID_82571EB_QUAD_COPPER: + case E1000_DEV_ID_82571EB_QUAD_FIBER: + case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: + adapter->flags |= FLAG_IS_QUAD_PORT; + /* mark the first port */ + if (global_quad_port_a == 0) + adapter->flags |= FLAG_IS_QUAD_PORT_A; + /* Reset for multiple quad port adapters */ + global_quad_port_a++; + if (global_quad_port_a == 4) + global_quad_port_a = 0; + break; + default: + break; + } + + switch (adapter->hw.mac.type) { + case e1000_82571: + /* these dual ports don't have WoL on port B at all */ + if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) || + (pdev->device == E1000_DEV_ID_82571EB_SERDES) || + (pdev->device == E1000_DEV_ID_82571EB_COPPER)) && + (is_port_b)) + adapter->flags &= ~FLAG_HAS_WOL; + /* quad ports only support WoL on port A */ + if (adapter->flags & FLAG_IS_QUAD_PORT && + (!adapter->flags & FLAG_IS_QUAD_PORT_A)) + adapter->flags &= ~FLAG_HAS_WOL; + break; + + case e1000_82573: + if (pdev->device == E1000_DEV_ID_82573L) { + e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, + &eeprom_data); + if (eeprom_data & NVM_WORD1A_ASPM_MASK) + adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + } + break; + default: + break; + } + + return 0; +} + +/** + * e1000_get_phy_id_82571 - Retrieve the PHY ID and revision + * @hw: pointer to the HW structure + * + * Reads the PHY registers and stores the PHY ID and possibly the PHY + * revision in the hardware structure. + **/ +static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + /* The 82571 firmware may still be configuring the PHY. + * In this case, we cannot access the PHY until the + * configuration is done. So we explicitly set the + * PHY ID. */ + phy->id = IGP01E1000_I_PHY_ID; + break; + case e1000_82573: + return e1000e_get_phy_id(hw); + break; + default: + return -E1000_ERR_PHY; + break; + } + + return 0; +} + +/** + * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) +{ + u32 swsm; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (er32(SWSM) & E1000_SWSM_SWESMBI) + break; + + udelay(50); + } + + if (i == timeout) { + /* Release semaphores */ + e1000e_put_hw_semaphore(hw); + hw_dbg(hw, "Driver can't access the NVM\n"); + return -E1000_ERR_NVM; + } + + return 0; +} + +/** + * e1000_put_hw_semaphore_82571 - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) +{ + u32 swsm; + + swsm = er32(SWSM); + + swsm &= ~E1000_SWSM_SWESMBI; + + ew32(SWSM, swsm); +} + +/** + * e1000_acquire_nvm_82571 - Request for access to the EEPROM + * @hw: pointer to the HW structure + * + * To gain access to the EEPROM, first we must obtain a hardware semaphore. + * Then for non-82573 hardware, set the EEPROM access request bit and wait + * for EEPROM access grant bit. If the access grant bit is not set, release + * hardware semaphore. + **/ +static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) +{ + s32 ret_val; + + ret_val = e1000_get_hw_semaphore_82571(hw); + if (ret_val) + return ret_val; + + if (hw->mac.type != e1000_82573) + ret_val = e1000e_acquire_nvm(hw); + + if (ret_val) + e1000_put_hw_semaphore_82571(hw); + + return ret_val; +} + +/** + * e1000_release_nvm_82571 - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit. + **/ +static void e1000_release_nvm_82571(struct e1000_hw *hw) +{ + e1000e_release_nvm(hw); + e1000_put_hw_semaphore_82571(hw); +} + +/** + * e1000_write_nvm_82571 - Write to EEPROM using appropriate interface + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * For non-82573 silicon, write data to EEPROM at offset using SPI interface. + * + * If e1000e_update_nvm_checksum is not called after this function, the + * EEPROM will most likley contain an invalid checksum. + **/ +static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 ret_val; + + switch (hw->mac.type) { + case e1000_82573: + ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data); + break; + case e1000_82571: + case e1000_82572: + ret_val = e1000e_write_nvm_spi(hw, offset, words, data); + break; + default: + ret_val = -E1000_ERR_NVM; + break; + } + + return ret_val; +} + +/** + * e1000_update_nvm_checksum_82571 - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + **/ +static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) +{ + u32 eecd; + s32 ret_val; + u16 i; + + ret_val = e1000e_update_nvm_checksum_generic(hw); + if (ret_val) + return ret_val; + + /* If our nvm is an EEPROM, then we're done + * otherwise, commit the checksum to the flash NVM. */ + if (hw->nvm.type != e1000_nvm_flash_hw) + return ret_val; + + /* Check for pending operations. */ + for (i = 0; i < E1000_FLASH_UPDATES; i++) { + msleep(1); + if ((er32(EECD) & E1000_EECD_FLUPD) == 0) + break; + } + + if (i == E1000_FLASH_UPDATES) + return -E1000_ERR_NVM; + + /* Reset the firmware if using STM opcode. */ + if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) { + /* The enabling of and the actual reset must be done + * in two write cycles. + */ + ew32(HICR, E1000_HICR_FW_RESET_ENABLE); + e1e_flush(); + ew32(HICR, E1000_HICR_FW_RESET); + } + + /* Commit the write to flash */ + eecd = er32(EECD) | E1000_EECD_FLUPD; + ew32(EECD, eecd); + + for (i = 0; i < E1000_FLASH_UPDATES; i++) { + msleep(1); + if ((er32(EECD) & E1000_EECD_FLUPD) == 0) + break; + } + + if (i == E1000_FLASH_UPDATES) + return -E1000_ERR_NVM; + + return 0; +} + +/** + * e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw) +{ + if (hw->nvm.type == e1000_nvm_flash_hw) + e1000_fix_nvm_checksum_82571(hw); + + return e1000e_validate_nvm_checksum_generic(hw); +} + +/** + * e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * After checking for invalid values, poll the EEPROM to ensure the previous + * command has completed before trying to write the next word. After write + * poll for completion. + * + * If e1000e_update_nvm_checksum is not called after this function, the + * EEPROM will most likley contain an invalid checksum. + **/ +static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i; + u32 eewr = 0; + s32 ret_val = 0; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + for (i = 0; i < words; i++) { + eewr = (data[i] << E1000_NVM_RW_REG_DATA) | + ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | + E1000_NVM_RW_REG_START; + + ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); + if (ret_val) + break; + + ew32(EEWR, eewr); + + ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); + if (ret_val) + break; + } + + return ret_val; +} + +/** + * e1000_get_cfg_done_82571 - Poll for configuration done + * @hw: pointer to the HW structure + * + * Reads the management control register for the config done bit to be set. + **/ +static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw) +{ + s32 timeout = PHY_CFG_TIMEOUT; + + while (timeout) { + if (er32(EEMNGCTL) & + E1000_NVM_CFG_DONE_PORT_0) + break; + msleep(1); + timeout--; + } + if (!timeout) { + hw_dbg(hw, "MNG configuration cycle has not completed.\n"); + return -E1000_ERR_RESET; + } + + return 0; +} + +/** + * e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: TRUE to enable LPLU, FALSE to disable + * + * Sets the LPLU D0 state according to the active flag. When activating LPLU + * this function also disables smart speed and vice versa. LPLU will not be + * activated unless the device autonegotiation advertisement meets standards + * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function + * pointer entry point only called by PHY setup routines. + **/ +static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data); + if (ret_val) + return ret_val; + + if (active) { + data |= IGP02E1000_PM_D0_LPLU; + ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); + if (ret_val) + return ret_val; + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data); + if (ret_val) + return ret_val; + } else { + data &= ~IGP02E1000_PM_D0_LPLU; + ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } + } + + return 0; +} + +/** + * e1000_reset_hw_82571 - Reset hardware + * @hw: pointer to the HW structure + * + * This resets the hardware into a known state. This is a + * function pointer entry point called by the api module. + **/ +static s32 e1000_reset_hw_82571(struct e1000_hw *hw) +{ + u32 ctrl; + u32 extcnf_ctrl; + u32 ctrl_ext; + u32 icr; + s32 ret_val; + u16 i = 0; + + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000e_disable_pcie_master(hw); + if (ret_val) + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + + hw_dbg(hw, "Masking off all interrupts\n"); + ew32(IMC, 0xffffffff); + + ew32(RCTL, 0); + ew32(TCTL, E1000_TCTL_PSP); + e1e_flush(); + + msleep(10); + + /* Must acquire the MDIO ownership before MAC reset. + * Ownership defaults to firmware after a reset. */ + if (hw->mac.type == e1000_82573) { + extcnf_ctrl = er32(EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + do { + ew32(EXTCNF_CTRL, extcnf_ctrl); + extcnf_ctrl = er32(EXTCNF_CTRL); + + if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) + break; + + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + msleep(2); + i++; + } while (i < MDIO_OWNERSHIP_TIMEOUT); + } + + ctrl = er32(CTRL); + + hw_dbg(hw, "Issuing a global reset to MAC\n"); + ew32(CTRL, ctrl | E1000_CTRL_RST); + + if (hw->nvm.type == e1000_nvm_flash_hw) { + udelay(10); + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); + } + + ret_val = e1000e_get_auto_rd_done(hw); + if (ret_val) + /* We don't want to continue accessing MAC registers. */ + return ret_val; + + /* Phy configuration from NVM just starts after EECD_AUTO_RD is set. + * Need to wait for Phy configuration completion before accessing + * NVM and Phy. + */ + if (hw->mac.type == e1000_82573) + msleep(25); + + /* Clear any pending interrupt events. */ + ew32(IMC, 0xffffffff); + icr = er32(ICR); + + return 0; +} + +/** + * e1000_init_hw_82571 - Initialize hardware + * @hw: pointer to the HW structure + * + * This inits the hardware readying it for operation. + **/ +static s32 e1000_init_hw_82571(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 reg_data; + s32 ret_val; + u16 i; + u16 rar_count = mac->rar_entry_count; + + e1000_initialize_hw_bits_82571(hw); + + /* Initialize identification LED */ + ret_val = e1000e_id_led_init(hw); + if (ret_val) { + hw_dbg(hw, "Error initializing identification LED\n"); + return ret_val; + } + + /* Disabling VLAN filtering */ + hw_dbg(hw, "Initializing the IEEE VLAN\n"); + e1000e_clear_vfta(hw); + + /* Setup the receive address. */ + /* If, however, a locally administered address was assigned to the + * 82571, we must reserve a RAR for it to work around an issue where + * resetting one port will reload the MAC on the other port. + */ + if (e1000e_get_laa_state_82571(hw)) + rar_count--; + e1000e_init_rx_addrs(hw, rar_count); + + /* Zero out the Multicast HASH table */ + hw_dbg(hw, "Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = e1000_setup_link_82571(hw); + + /* Set the transmit descriptor write-back policy */ + reg_data = er32(TXDCTL); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | + E1000_TXDCTL_COUNT_DESC; + ew32(TXDCTL, reg_data); + + /* ...for both queues. */ + if (mac->type != e1000_82573) { + reg_data = er32(TXDCTL1); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | + E1000_TXDCTL_COUNT_DESC; + ew32(TXDCTL1, reg_data); + } else { + e1000e_enable_tx_pkt_filtering(hw); + reg_data = er32(GCR); + reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; + ew32(GCR, reg_data); + } + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_82571(hw); + + return ret_val; +} + +/** + * e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits + * @hw: pointer to the HW structure + * + * Initializes required hardware-dependent bits needed for normal operation. + **/ +static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) +{ + u32 reg; + + /* Transmit Descriptor Control 0 */ + reg = er32(TXDCTL); + reg |= (1 << 22); + ew32(TXDCTL, reg); + + /* Transmit Descriptor Control 1 */ + reg = er32(TXDCTL1); + reg |= (1 << 22); + ew32(TXDCTL1, reg); + + /* Transmit Arbitration Control 0 */ + reg = er32(TARC0); + reg &= ~(0xF << 27); /* 30:27 */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26); + break; + default: + break; + } + ew32(TARC0, reg); + + /* Transmit Arbitration Control 1 */ + reg = er32(TARC1); + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + reg &= ~((1 << 29) | (1 << 30)); + reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26); + if (er32(TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + ew32(TARC1, reg); + break; + default: + break; + } + + /* Device Control */ + if (hw->mac.type == e1000_82573) { + reg = er32(CTRL); + reg &= ~(1 << 29); + ew32(CTRL, reg); + } + + /* Extended Device Control */ + if (hw->mac.type == e1000_82573) { + reg = er32(CTRL_EXT); + reg &= ~(1 << 23); + reg |= (1 << 22); + ew32(CTRL_EXT, reg); + } +} + +/** + * e1000e_clear_vfta - Clear VLAN filter table + * @hw: pointer to the HW structure + * + * Clears the register array which contains the VLAN filter table by + * setting all the values to 0. + **/ +void e1000e_clear_vfta(struct e1000_hw *hw) +{ + u32 offset; + u32 vfta_value = 0; + u32 vfta_offset = 0; + u32 vfta_bit_in_reg = 0; + + if (hw->mac.type == e1000_82573) { + if (hw->mng_cookie.vlan_id != 0) { + /* The VFTA is a 4096b bit-field, each identifying + * a single VLAN ID. The following operations + * determine which 32b entry (i.e. offset) into the + * array we want to set the VLAN ID (i.e. bit) of + * the manageability unit. + */ + vfta_offset = (hw->mng_cookie.vlan_id >> + E1000_VFTA_ENTRY_SHIFT) & + E1000_VFTA_ENTRY_MASK; + vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & + E1000_VFTA_ENTRY_BIT_SHIFT_MASK); + } + } + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + /* If the offset we want to clear is the same offset of the + * manageability VLAN ID, then clear all bits except that of + * the manageability unit. + */ + vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value); + e1e_flush(); + } +} + +/** + * e1000_mc_addr_list_update_82571 - 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. + **/ +static void e1000_mc_addr_list_update_82571(struct e1000_hw *hw, + u8 *mc_addr_list, + u32 mc_addr_count, + u32 rar_used_count, + u32 rar_count) +{ + if (e1000e_get_laa_state_82571(hw)) + rar_count--; + + e1000e_mc_addr_list_update_generic(hw, mc_addr_list, mc_addr_count, + rar_used_count, rar_count); +} + +/** + * e1000_setup_link_82571 - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +static s32 e1000_setup_link_82571(struct e1000_hw *hw) +{ + /* 82573 does not have a word in the NVM to determine + * the default flow control setting, so we explicitly + * set it to full. + */ + if (hw->mac.type == e1000_82573) + hw->mac.fc = e1000_fc_full; + + return e1000e_setup_link(hw); +} + +/** + * e1000_setup_copper_link_82571 - Configure copper link settings + * @hw: pointer to the HW structure + * + * Configures the link for auto-neg or forced speed and duplex. Then we check + * for link, once link is established calls to configure collision distance + * and flow control are called. + **/ +static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw) +{ + u32 ctrl; + u32 led_ctrl; + s32 ret_val; + + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ew32(CTRL, ctrl); + + switch (hw->phy.type) { + case e1000_phy_m88: + ret_val = e1000e_copper_link_setup_m88(hw); + break; + case e1000_phy_igp_2: + ret_val = e1000e_copper_link_setup_igp(hw); + /* Setup activity LED */ + led_ctrl = er32(LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); + ew32(LEDCTL, led_ctrl); + break; + default: + return -E1000_ERR_PHY; + break; + } + + if (ret_val) + return ret_val; + + ret_val = e1000e_setup_copper_link(hw); + + return ret_val; +} + +/** + * e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes + * @hw: pointer to the HW structure + * + * Configures collision distance and flow control for fiber and serdes links. + * Upon successful setup, poll for link. + **/ +static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) +{ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + /* If SerDes loopback mode is entered, there is no form + * of reset to take the adapter out of that mode. So we + * have to explicitly take the adapter out of loopback + * mode. This prevents drivers from twidling their thumbs + * if another tool failed to take it out of loopback mode. + */ + ew32(SCTL, + E1000_SCTL_DISABLE_SERDES_LOOPBACK); + break; + default: + break; + } + + return e1000e_setup_fiber_serdes_link(hw); +} + +/** + * e1000_valid_led_default_82571 - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + + if (hw->mac.type == e1000_82573 && + *data == ID_LED_RESERVED_F746) + *data = ID_LED_DEFAULT_82573; + else if (*data == ID_LED_RESERVED_0000 || + *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; + + return 0; +} + +/** + * e1000e_get_laa_state_82571 - Get locally administered address state + * @hw: pointer to the HW structure + * + * Retrieve and return the current locally administed address state. + **/ +bool e1000e_get_laa_state_82571(struct e1000_hw *hw) +{ + if (hw->mac.type != e1000_82571) + return 0; + + return hw->dev_spec.e82571.laa_is_present; +} + +/** + * e1000e_set_laa_state_82571 - Set locally administered address state + * @hw: pointer to the HW structure + * @state: enable/disable locally administered address + * + * Enable/Disable the current locally administed address state. + **/ +void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state) +{ + if (hw->mac.type != e1000_82571) + return; + + hw->dev_spec.e82571.laa_is_present = state; + + /* If workaround is activated... */ + if (state) + /* Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed, the actual LAA is in one of the RARs and no + * incoming packets directed to this port are dropped. + * Eventually the LAA will be in RAR[0] and RAR[14]. + */ + e1000e_rar_set(hw, hw->mac.addr, hw->mac.rar_entry_count - 1); +} + +/** + * e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum + * @hw: pointer to the HW structure + * + * Verifies that the EEPROM has completed the update. After updating the + * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If + * the checksum fix is not implemented, we need to set the bit and update + * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect, + * we need to return bad checksum. + **/ +static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + s32 ret_val; + u16 data; + + if (nvm->type != e1000_nvm_flash_hw) + return 0; + + /* Check bit 4 of word 10h. If it is 0, firmware is done updating + * 10h-12h. Checksum may need to be fixed. + */ + ret_val = e1000_read_nvm(hw, 0x10, 1, &data); + if (ret_val) + return ret_val; + + if (!(data & 0x10)) { + /* Read 0x23 and check bit 15. This bit is a 1 + * when the checksum has already been fixed. If + * the checksum is still wrong and this bit is a + * 1, we need to return bad checksum. Otherwise, + * we need to set this bit to a 1 and update the + * checksum. + */ + ret_val = e1000_read_nvm(hw, 0x23, 1, &data); + if (ret_val) + return ret_val; + + if (!(data & 0x8000)) { + data |= 0x8000; + ret_val = e1000_write_nvm(hw, 0x23, 1, &data); + if (ret_val) + return ret_val; + ret_val = e1000e_update_nvm_checksum(hw); + } + } + + return 0; +} + +/** + * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters + * @hw: pointer to the HW structure + * + * Clears the hardware counters by reading the counter registers. + **/ +static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw) +{ + u32 temp; + + e1000e_clear_hw_cntrs_base(hw); + + temp = er32(PRC64); + temp = er32(PRC127); + temp = er32(PRC255); + temp = er32(PRC511); + temp = er32(PRC1023); + temp = er32(PRC1522); + temp = er32(PTC64); + temp = er32(PTC127); + temp = er32(PTC255); + temp = er32(PTC511); + temp = er32(PTC1023); + temp = er32(PTC1522); + + temp = er32(ALGNERRC); + temp = er32(RXERRC); + temp = er32(TNCRS); + temp = er32(CEXTERR); + temp = er32(TSCTC); + temp = er32(TSCTFC); + + temp = er32(MGTPRC); + temp = er32(MGTPDC); + temp = er32(MGTPTC); + + temp = er32(IAC); + temp = er32(ICRXOC); + + temp = er32(ICRXPTC); + temp = er32(ICRXATC); + temp = er32(ICTXPTC); + temp = er32(ICTXATC); + temp = er32(ICTXQEC); + temp = er32(ICTXQMTC); + temp = er32(ICRXDMTC); +} + +static struct e1000_mac_operations e82571_mac_ops = { + .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + /* .check_for_link: media type dependent */ + .cleanup_led = e1000e_cleanup_led_generic, + .clear_hw_cntrs = e1000_clear_hw_cntrs_82571, + .get_bus_info = e1000e_get_bus_info_pcie, + /* .get_link_up_info: media type dependent */ + .led_on = e1000e_led_on_generic, + .led_off = e1000e_led_off_generic, + .mc_addr_list_update = e1000_mc_addr_list_update_82571, + .reset_hw = e1000_reset_hw_82571, + .init_hw = e1000_init_hw_82571, + .setup_link = e1000_setup_link_82571, + /* .setup_physical_interface: media type dependent */ +}; + +static struct e1000_phy_operations e82_phy_ops_igp = { + .acquire_phy = e1000_get_hw_semaphore_82571, + .check_reset_block = e1000e_check_reset_block_generic, + .commit_phy = NULL, + .force_speed_duplex = e1000e_phy_force_speed_duplex_igp, + .get_cfg_done = e1000_get_cfg_done_82571, + .get_cable_length = e1000e_get_cable_length_igp_2, + .get_phy_info = e1000e_get_phy_info_igp, + .read_phy_reg = e1000e_read_phy_reg_igp, + .release_phy = e1000_put_hw_semaphore_82571, + .reset_phy = e1000e_phy_hw_reset_generic, + .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, + .set_d3_lplu_state = e1000e_set_d3_lplu_state, + .write_phy_reg = e1000e_write_phy_reg_igp, +}; + +static struct e1000_phy_operations e82_phy_ops_m88 = { + .acquire_phy = e1000_get_hw_semaphore_82571, + .check_reset_block = e1000e_check_reset_block_generic, + .commit_phy = e1000e_phy_sw_reset, + .force_speed_duplex = e1000e_phy_force_speed_duplex_m88, + .get_cfg_done = e1000e_get_cfg_done, + .get_cable_length = e1000e_get_cable_length_m88, + .get_phy_info = e1000e_get_phy_info_m88, + .read_phy_reg = e1000e_read_phy_reg_m88, + .release_phy = e1000_put_hw_semaphore_82571, + .reset_phy = e1000e_phy_hw_reset_generic, + .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, + .set_d3_lplu_state = e1000e_set_d3_lplu_state, + .write_phy_reg = e1000e_write_phy_reg_m88, +}; + +static struct e1000_nvm_operations e82571_nvm_ops = { + .acquire_nvm = e1000_acquire_nvm_82571, + .read_nvm = e1000e_read_nvm_spi, + .release_nvm = e1000_release_nvm_82571, + .update_nvm = e1000_update_nvm_checksum_82571, + .valid_led_default = e1000_valid_led_default_82571, + .validate_nvm = e1000_validate_nvm_checksum_82571, + .write_nvm = e1000_write_nvm_82571, +}; + +static struct e1000_nvm_operations e82573_nvm_ops = { + .acquire_nvm = e1000_acquire_nvm_82571, + .read_nvm = e1000e_read_nvm_eerd, + .release_nvm = e1000_release_nvm_82571, + .update_nvm = e1000_update_nvm_checksum_82571, + .valid_led_default = e1000_valid_led_default_82571, + .validate_nvm = e1000_validate_nvm_checksum_82571, + .write_nvm = e1000_write_nvm_82571, +}; + +struct e1000_info e1000_82571_info = { + .mac = e1000_82571, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_STATS_PTC_PRC + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_STATS_ICR_ICT + | FLAG_HAS_SMART_POWER_DOWN + | FLAG_RESET_OVERWRITES_LAA /* errata */ + | FLAG_TARC_SPEED_MODE_BIT /* errata */ + | FLAG_APME_CHECK_PORT_B, + .pba = 38, + .get_invariants = e1000_get_invariants_82571, + .mac_ops = &e82571_mac_ops, + .phy_ops = &e82_phy_ops_igp, + .nvm_ops = &e82571_nvm_ops, +}; + +struct e1000_info e1000_82572_info = { + .mac = e1000_82572, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_STATS_PTC_PRC + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_STATS_ICR_ICT + | FLAG_TARC_SPEED_MODE_BIT, /* errata */ + .pba = 38, + .get_invariants = e1000_get_invariants_82571, + .mac_ops = &e82571_mac_ops, + .phy_ops = &e82_phy_ops_igp, + .nvm_ops = &e82571_nvm_ops, +}; + +struct e1000_info e1000_82573_info = { + .mac = e1000_82573, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_STATS_PTC_PRC + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_STATS_ICR_ICT + | FLAG_HAS_SMART_POWER_DOWN + | FLAG_HAS_AMT + | FLAG_HAS_ASPM + | FLAG_HAS_ERT + | FLAG_HAS_SWSM_ON_LOAD, + .pba = 20, + .get_invariants = e1000_get_invariants_82571, + .mac_ops = &e82571_mac_ops, + .phy_ops = &e82_phy_ops_m88, + .nvm_ops = &e82573_nvm_ops, +}; + diff --git a/drivers/net/e1000e/Makefile b/drivers/net/e1000e/Makefile new file mode 100644 index 000000000000..650f866e7ac2 --- /dev/null +++ b/drivers/net/e1000e/Makefile @@ -0,0 +1,37 @@ +################################################################################ +# +# Intel PRO/1000 Linux driver +# Copyright(c) 1999 - 2007 Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full GNU General Public License is included in this distribution in +# the file called "COPYING". +# +# Contact Information: +# Linux NICS +# e1000-devel Mailing List +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +# +################################################################################ + +# +# Makefile for the Intel(R) PRO/1000 ethernet driver +# + +obj-$(CONFIG_E1000E) += e1000e.o + +e1000e-objs := 82571.o ich8lan.o es2lan.o \ + lib.o phy.o param.o ethtool.o netdev.o + diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h new file mode 100644 index 000000000000..b32ed45b4b34 --- /dev/null +++ b/drivers/net/e1000e/defines.h @@ -0,0 +1,739 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_DEFINES_H_ +#define _E1000_DEFINES_H_ + +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define REQ_RX_DESCRIPTOR_MULTIPLE 8 + +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ + +/* Wake Up Filter Control */ +#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ + +/* Extended Device Control */ +#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ +#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ +#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ +#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ +#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ + +/* Receive Decriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ + +#define E1000_RXDEXT_STATERR_CE 0x01000000 +#define E1000_RXDEXT_STATERR_SE 0x02000000 +#define E1000_RXDEXT_STATERR_SEQ 0x04000000 +#define E1000_RXDEXT_STATERR_CXE 0x10000000 +#define E1000_RXDEXT_STATERR_RXE 0x80000000 + +/* mask to determine if packets should be dropped due to frame errors */ +#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ + E1000_RXD_ERR_CE | \ + E1000_RXD_ERR_SE | \ + E1000_RXD_ERR_SEQ | \ + E1000_RXD_ERR_CXE | \ + E1000_RXD_ERR_RXE) + +/* Same mask, but for extended and packet split descriptors */ +#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ + E1000_RXDEXT_STATERR_CE | \ + E1000_RXDEXT_STATERR_SE | \ + E1000_RXDEXT_STATERR_SEQ | \ + E1000_RXDEXT_STATERR_CXE | \ + E1000_RXDEXT_STATERR_RXE) + +#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 + +/* Management Control */ +#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ +#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ +#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ +#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address + * filtering */ +#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host + * memory */ + +/* Receive Control */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ + +/* Use byte values for the following shift parameters + * Usage: + * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & + * E1000_PSRCTL_BSIZE0_MASK) | + * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & + * E1000_PSRCTL_BSIZE1_MASK) | + * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & + * E1000_PSRCTL_BSIZE2_MASK) | + * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; + * E1000_PSRCTL_BSIZE3_MASK)) + * where value0 = [128..16256], default=256 + * value1 = [1024..64512], default=4096 + * value2 = [0..64512], default=4096 + * value3 = [0..64512], default=0 + */ + +#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F +#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 +#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 +#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 + +#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ +#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ +#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ +#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ + +/* SWFW_SYNC Definitions */ +#define E1000_SWFW_EEP_SM 0x1 +#define E1000_SWFW_PHY0_SM 0x2 +#define E1000_SWFW_PHY1_SM 0x4 + +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ + +/* Bit definitions for the Management Data IO (MDIO) and Management Data + * Clock (MDC) pins in the Device Control Register. + */ + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_SHIFT 2 +#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ +#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ + +/* Constants used to intrepret the masked PCI-X bus speed. */ + +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ +#define ADVERTISE_1000_FULL 0x0020 + +/* 1000/H is not supported, nor spec-compliant. */ +#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) +#define E1000_ALL_NOT_GIG ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL) +#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL) +#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL) +#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF) + +#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX + +/* LED Control */ +#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F +#define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_IVRT 0x00000040 +#define E1000_LEDCTL_LED0_BLINK 0x00000080 + +#define E1000_LEDCTL_MODE_LED_ON 0xE +#define E1000_LEDCTL_MODE_LED_OFF 0xF + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Transmit Control */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ + +/* Transmit Arbitration Count */ + +/* SerDes Control */ +#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 + +/* Receive Checksum Control */ +#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ +#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ + +/* Header split receive */ +#define E1000_RFCTL_EXTEN 0x00008000 +#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 +#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 + +/* Collision related configuration parameters */ +#define E1000_COLLISION_THRESHOLD 15 +#define E1000_CT_SHIFT 4 +#define E1000_COLLISION_DISTANCE 63 +#define E1000_COLD_SHIFT 12 + +/* Default values for the transmit IPG register */ +#define DEFAULT_82543_TIPG_IPGT_COPPER 8 + +#define E1000_TIPG_IPGT_MASK 0x000003FF + +#define DEFAULT_82543_TIPG_IPGR1 8 +#define E1000_TIPG_IPGR1_SHIFT 10 + +#define DEFAULT_82543_TIPG_IPGR2 6 +#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 +#define E1000_TIPG_IPGR2_SHIFT 20 + +#define MAX_JUMBO_FRAME_SIZE 0x3F00 + +/* Extended Configuration Control and Size */ +#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 +#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16 + +#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 +#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 +#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 +#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 + +#define E1000_KABGTXD_BGSQLBIAS 0x00050000 + +/* PBA constants */ +#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */ +#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ + +#define E1000_PBS_16K E1000_PBA_16K + +#define IFS_MAX 80 +#define IFS_MIN 40 +#define IFS_RATIO 4 +#define IFS_STEP 10 +#define MIN_NUM_XMITS 1000 + +/* SW Semaphore Register */ +#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXT0 = Receiver Timer Interrupt (ring 0) + * o TXDW = Transmit Descriptor Written Back + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + * o LSC = Link Status Change + */ +#define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC) + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ + +/* Interrupt Cause Set */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ + +/* Transmit Descriptor Control */ +#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ +#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */ +#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ +#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */ +#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc. + still to be processed. */ + +/* Flow Control Constants */ +#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 +#define FLOW_CONTROL_TYPE 0x8808 + +/* 802.1q VLAN Packet Size */ +#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + +/* Receive Address */ +/* Number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. + * Technically, we have 16 spots. However, we reserve one of these spots + * (RAR[15]) for our directed address used by controllers with + * manageability enabled, allowing us room for 15 multicast addresses. + */ +#define E1000_RAR_ENTRIES 15 +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Error Codes */ +#define E1000_ERR_NVM 1 +#define E1000_ERR_PHY 2 +#define E1000_ERR_CONFIG 3 +#define E1000_ERR_PARAM 4 +#define E1000_ERR_MAC_INIT 5 +#define E1000_ERR_PHY_TYPE 6 +#define E1000_ERR_RESET 9 +#define E1000_ERR_MASTER_REQUESTS_PENDING 10 +#define E1000_ERR_HOST_INTERFACE_COMMAND 11 +#define E1000_BLK_PHY_RESET 12 +#define E1000_ERR_SWFW_SYNC 13 +#define E1000_NOT_IMPLEMENTED 14 + +/* Loop limit on how long we wait for auto-negotiation to complete */ +#define FIBER_LINK_UP_LIMIT 50 +#define COPPER_LINK_UP_LIMIT 10 +#define PHY_AUTO_NEG_LIMIT 45 +#define PHY_FORCE_LIMIT 20 +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define MASTER_DISABLE_TIMEOUT 800 +/* Number of milliseconds we wait for PHY configuration done after MAC reset */ +#define PHY_CFG_TIMEOUT 100 +/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */ +#define MDIO_OWNERSHIP_TIMEOUT 10 +/* Number of milliseconds for NVM auto read done after MAC reset. */ +#define AUTO_READ_DONE_TIMEOUT 10 + +/* Flow Control */ +#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +/* Transmit Configuration Word */ +#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ +#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ +#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ +#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ +#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ + +/* Receive Configuration Word */ +#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ +#define E1000_RXCW_C 0x20000000 /* Receive config */ +#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ + +/* PCI Express Control */ +#define E1000_GCR_RXD_NO_SNOOP 0x00000001 +#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 +#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 +#define E1000_GCR_TXD_NO_SNOOP 0x00000008 +#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 +#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 + +#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ + E1000_GCR_RXDSCW_NO_SNOOP | \ + E1000_GCR_RXDSCR_NO_SNOOP | \ + E1000_GCR_TXD_NO_SNOOP | \ + E1000_GCR_TXDSCW_NO_SNOOP | \ + E1000_GCR_TXDSCR_NO_SNOOP) + +/* PHY Control Register */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ + +/* Autoneg Expansion Register */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ + +/* 1000BASE-T Status Register */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ + + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CONTROL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ + +/* NVM Control */ +#define E1000_EECD_SK 0x00000001 /* NVM Clock */ +#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* NVM Data In */ +#define E1000_EECD_DO 0x00000008 /* NVM Data Out */ +#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ +#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ +#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ +#define E1000_EECD_ADDR_BITS 0x00000400 /* NVM Addressing bits based on type + * (0-small, 1-large) */ +#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ +#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ +#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ +#define E1000_EECD_SIZE_EX_SHIFT 11 +#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ +#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ +#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ + +#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */ +#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ +#define E1000_NVM_RW_REG_START 1 /* Start operation */ +#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ +#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */ +#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */ +#define E1000_FLASH_UPDATES 2000 + +/* NVM Word Offsets */ +#define NVM_ID_LED_SETTINGS 0x0004 +#define NVM_INIT_CONTROL2_REG 0x000F +#define NVM_INIT_CONTROL3_PORT_B 0x0014 +#define NVM_INIT_3GIO_3 0x001A +#define NVM_INIT_CONTROL3_PORT_A 0x0024 +#define NVM_CFG 0x0012 +#define NVM_CHECKSUM_REG 0x003F + +#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */ +#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */ + +/* Mask bits for fields in Word 0x0f of the NVM */ +#define NVM_WORD0F_PAUSE_MASK 0x3000 +#define NVM_WORD0F_PAUSE 0x1000 +#define NVM_WORD0F_ASM_DIR 0x2000 + +/* Mask bits for fields in Word 0x1a of the NVM */ +#define NVM_WORD1A_ASPM_MASK 0x000C + +/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ +#define NVM_SUM 0xBABA + +/* PBA (printed board assembly) number words */ +#define NVM_PBA_OFFSET_0 8 +#define NVM_PBA_OFFSET_1 9 + +#define NVM_WORD_SIZE_BASE_SHIFT 6 + +/* NVM Commands - SPI */ +#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ +#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */ +#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */ +#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ +#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */ +#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */ + +/* SPI NVM Status Register */ +#define NVM_STATUS_RDY_SPI 0x01 + +/* Word definitions for ID LED Settings */ +#define ID_LED_RESERVED_0000 0x0000 +#define ID_LED_RESERVED_FFFF 0xFFFF +#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ + (ID_LED_OFF1_OFF2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) +#define ID_LED_DEF1_DEF2 0x1 +#define ID_LED_DEF1_ON2 0x2 +#define ID_LED_DEF1_OFF2 0x3 +#define ID_LED_ON1_DEF2 0x4 +#define ID_LED_ON1_ON2 0x5 +#define ID_LED_ON1_OFF2 0x6 +#define ID_LED_OFF1_DEF2 0x7 +#define ID_LED_OFF1_ON2 0x8 +#define ID_LED_OFF1_OFF2 0x9 + +#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF +#define IGP_ACTIVITY_LED_ENABLE 0x0300 +#define IGP_LED3_MODE 0x07000000 + +/* PCI/PCI-X/PCI-EX Config space */ +#define PCI_HEADER_TYPE_REGISTER 0x0E +#define PCIE_LINK_STATUS 0x12 + +#define PCI_HEADER_TYPE_MULTIFUNC 0x80 +#define PCIE_LINK_WIDTH_MASK 0x3F0 +#define PCIE_LINK_WIDTH_SHIFT 4 + +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ +#define MAX_PHY_MULTI_PAGE_REG 0xF + +/* Bit definitions for valid PHY IDs. */ +/* I = Integrated + * E = External + */ +#define M88E1000_E_PHY_ID 0x01410C50 +#define M88E1000_I_PHY_ID 0x01410C30 +#define M88E1011_I_PHY_ID 0x01410C20 +#define IGP01E1000_I_PHY_ID 0x02A80380 +#define M88E1111_I_PHY_ID 0x01410CC0 +#define GG82563_E_PHY_ID 0x01410CA0 +#define IGP03E1000_E_PHY_ID 0x02A80390 +#define IFE_E_PHY_ID 0x02A80330 +#define IFE_PLUS_E_PHY_ID 0x02A80320 +#define IFE_C_E_PHY_ID 0x02A80310 + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ + +#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ +#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ + +/* M88E1000 PHY Specific Control Register */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ + /* Manual MDI configuration */ +#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, + * 100BASE-TX/10BASE-T: + * MDI Mode + */ +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled + * all speeds. + */ + /* 1=Enable Extended 10BASE-T distance + * (Lower 10BASE-T RX Threshold) + * 0=Normal 10BASE-T RX Threshold */ + /* 1=5-Bit interface in 100BASE-TX + * 0=MII interface in 100BASE-TX */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ + +/* M88E1000 PHY Specific Status Register */ +#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ +#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ +#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; + * 3=110-140M;4=>140M */ +#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 + +/* Number of times we will attempt to autonegotiate before downshifting if we + * are the master */ +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 +/* Number of times we will attempt to autonegotiate before downshifting if we + * are the slave */ +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300 +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 +#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ + +/* M88EC018 Rev 2 specific DownShift settings */ +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 + +/* Bits... + * 15-5: page + * 4-0: register offset + */ +#define GG82563_PAGE_SHIFT 5 +#define GG82563_REG(page, reg) \ + (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) +#define GG82563_MIN_ALT_REG 30 + +/* GG82563 Specific Registers */ +#define GG82563_PHY_SPEC_CTRL \ + GG82563_REG(0, 16) /* PHY Specific Control */ +#define GG82563_PHY_PAGE_SELECT \ + GG82563_REG(0, 22) /* Page Select */ +#define GG82563_PHY_SPEC_CTRL_2 \ + GG82563_REG(0, 26) /* PHY Specific Control 2 */ +#define GG82563_PHY_PAGE_SELECT_ALT \ + GG82563_REG(0, 29) /* Alternate Page Select */ + +#define GG82563_PHY_MAC_SPEC_CTRL \ + GG82563_REG(2, 21) /* MAC Specific Control Register */ + +#define GG82563_PHY_DSP_DISTANCE \ + GG82563_REG(5, 26) /* DSP Distance */ + +/* Page 193 - Port Control Registers */ +#define GG82563_PHY_KMRN_MODE_CTRL \ + GG82563_REG(193, 16) /* Kumeran Mode Control */ +#define GG82563_PHY_PWR_MGMT_CTRL \ + GG82563_REG(193, 20) /* Power Management Control */ + +/* Page 194 - KMRN Registers */ +#define GG82563_PHY_INBAND_CTRL \ + GG82563_REG(194, 18) /* Inband Control */ + +/* MDI Control */ +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_ERROR 0x40000000 + +/* SerDes Control */ +#define E1000_GEN_POLL_TIMEOUT 640 + +#endif /* _E1000_DEFINES_H_ */ diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h new file mode 100644 index 000000000000..d2499bb07c13 --- /dev/null +++ b/drivers/net/e1000e/e1000.h @@ -0,0 +1,514 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* Linux PRO/1000 Ethernet Driver main header file */ + +#ifndef _E1000_H_ +#define _E1000_H_ + +#include +#include +#include +#include +#include + +#include "hw.h" + +struct e1000_info; + +#define ndev_printk(level, netdev, format, arg...) \ + printk(level "%s: %s: " format, (netdev)->dev.parent->bus_id, \ + (netdev)->name, ## arg) + +#ifdef DEBUG +#define ndev_dbg(netdev, format, arg...) \ + ndev_printk(KERN_DEBUG , netdev, format, ## arg) +#else +#define ndev_dbg(netdev, format, arg...) do { (void)(netdev); } while (0) +#endif + +#define ndev_err(netdev, format, arg...) \ + ndev_printk(KERN_ERR , netdev, format, ## arg) +#define ndev_info(netdev, format, arg...) \ + ndev_printk(KERN_INFO , netdev, format, ## arg) +#define ndev_warn(netdev, format, arg...) \ + ndev_printk(KERN_WARNING , netdev, format, ## arg) +#define ndev_notice(netdev, format, arg...) \ + ndev_printk(KERN_NOTICE , netdev, format, ## arg) + + +/* TX/RX descriptor defines */ +#define E1000_DEFAULT_TXD 256 +#define E1000_MAX_TXD 4096 +#define E1000_MIN_TXD 80 + +#define E1000_DEFAULT_RXD 256 +#define E1000_MAX_RXD 4096 +#define E1000_MIN_RXD 80 + +/* Early Receive defines */ +#define E1000_ERT_2048 0x100 + +#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ + +/* How many Tx Descriptors do we need to call netif_wake_queue ? */ +/* How many Rx Buffers do we bundle into one write to the hardware ? */ +#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +#define AUTO_ALL_MODES 0 +#define E1000_EEPROM_APME 0x0400 + +#define E1000_MNG_VLAN_NONE (-1) + +/* Number of packet split data buffers (not including the header buffer) */ +#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) + +enum e1000_boards { + board_82571, + board_82572, + board_82573, + board_80003es2lan, + board_ich8lan, + board_ich9lan, +}; + +struct e1000_queue_stats { + u64 packets; + u64 bytes; +}; + +struct e1000_ps_page { + struct page *page; + u64 dma; /* must be u64 - written to hw */ +}; + +/* + * wrappers around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct e1000_buffer { + dma_addr_t dma; + struct sk_buff *skb; + union { + /* TX */ + struct { + unsigned long time_stamp; + u16 length; + u16 next_to_watch; + }; + /* RX */ + struct page *page; + }; + +}; + +struct e1000_ring { + void *desc; /* pointer to ring memory */ + dma_addr_t dma; /* phys address of ring */ + unsigned int size; /* length of ring in bytes */ + unsigned int count; /* number of desc. in ring */ + + u16 next_to_use; + u16 next_to_clean; + + u16 head; + u16 tail; + + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; + + /* arrays of page information for packet split */ + struct e1000_ps_page *ps_pages; + struct sk_buff *rx_skb_top; + + struct e1000_queue_stats stats; +}; + +/* board specific private data structure */ +struct e1000_adapter { + struct timer_list watchdog_timer; + struct timer_list phy_info_timer; + struct timer_list blink_timer; + + struct work_struct reset_task; + struct work_struct watchdog_task; + + const struct e1000_info *ei; + + struct vlan_group *vlgrp; + u32 bd_number; + u32 rx_buffer_len; + u16 mng_vlan_id; + u16 link_speed; + u16 link_duplex; + + spinlock_t tx_queue_lock; /* prevent concurrent tail updates */ + + /* this is still needed for 82571 and above */ + atomic_t irq_sem; + + /* track device up/down/testing state */ + unsigned long state; + + /* Interrupt Throttle Rate */ + u32 itr; + u32 itr_setting; + u16 tx_itr; + u16 rx_itr; + + /* + * TX + */ + struct e1000_ring *tx_ring /* One per active queue */ + ____cacheline_aligned_in_smp; + + struct napi_struct napi; + + unsigned long tx_queue_len; + unsigned int restart_queue; + u32 txd_cmd; + + bool detect_tx_hung; + u8 tx_timeout_factor; + + u32 tx_int_delay; + u32 tx_abs_int_delay; + + unsigned int total_tx_bytes; + unsigned int total_tx_packets; + unsigned int total_rx_bytes; + unsigned int total_rx_packets; + + /* TX stats */ + u64 tpt_old; + u64 colc_old; + u64 gotcl_old; + u32 gotcl; + u32 tx_timeout_count; + u32 tx_fifo_head; + u32 tx_head_addr; + u32 tx_fifo_size; + u32 tx_dma_failed; + + /* + * RX + */ + bool (*clean_rx) (struct e1000_adapter *adapter, + int *work_done, int work_to_do) + ____cacheline_aligned_in_smp; + void (*alloc_rx_buf) (struct e1000_adapter *adapter, + int cleaned_count); + struct e1000_ring *rx_ring; + + u32 rx_int_delay; + u32 rx_abs_int_delay; + + /* RX stats */ + u64 hw_csum_err; + u64 hw_csum_good; + u64 rx_hdr_split; + u64 gorcl_old; + u32 gorcl; + u32 alloc_rx_buff_failed; + u32 rx_dma_failed; + + unsigned int rx_ps_pages; + u16 rx_ps_bsize0; + + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + spinlock_t stats_lock; /* prevent concurrent stats updates */ + + /* structs defined in e1000_hw.h */ + struct e1000_hw hw; + + struct e1000_hw_stats stats; + struct e1000_phy_info phy_info; + struct e1000_phy_stats phy_stats; + + struct e1000_ring test_tx_ring; + struct e1000_ring test_rx_ring; + u32 test_icr; + + u32 msg_enable; + + u32 eeprom_wol; + u32 wol; + u32 pba; + + u8 fc_autoneg; + + unsigned long led_status; + + unsigned int flags; +}; + +struct e1000_info { + enum e1000_mac_type mac; + unsigned int flags; + u32 pba; + s32 (*get_invariants)(struct e1000_adapter *); + struct e1000_mac_operations *mac_ops; + struct e1000_phy_operations *phy_ops; + struct e1000_nvm_operations *nvm_ops; +}; + +/* hardware capability, feature, and workaround flags */ +#define FLAG_HAS_AMT (1 << 0) +#define FLAG_HAS_FLASH (1 << 1) +#define FLAG_HAS_HW_VLAN_FILTER (1 << 2) +#define FLAG_HAS_WOL (1 << 3) +#define FLAG_HAS_ERT (1 << 4) +#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) +#define FLAG_HAS_SWSM_ON_LOAD (1 << 6) +#define FLAG_HAS_JUMBO_FRAMES (1 << 7) +#define FLAG_HAS_ASPM (1 << 8) +#define FLAG_HAS_STATS_ICR_ICT (1 << 9) +#define FLAG_HAS_STATS_PTC_PRC (1 << 10) +#define FLAG_HAS_SMART_POWER_DOWN (1 << 11) +#define FLAG_IS_QUAD_PORT_A (1 << 12) +#define FLAG_IS_QUAD_PORT (1 << 13) +#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN (1 << 14) +#define FLAG_APME_IN_WUC (1 << 15) +#define FLAG_APME_IN_CTRL3 (1 << 16) +#define FLAG_APME_CHECK_PORT_B (1 << 17) +#define FLAG_DISABLE_FC_PAUSE_TIME (1 << 18) +#define FLAG_NO_WAKE_UCAST (1 << 19) +#define FLAG_MNG_PT_ENABLED (1 << 20) +#define FLAG_RESET_OVERWRITES_LAA (1 << 21) +#define FLAG_TARC_SPEED_MODE_BIT (1 << 22) +#define FLAG_TARC_SET_BIT_ZERO (1 << 23) +#define FLAG_RX_NEEDS_RESTART (1 << 24) +#define FLAG_LSC_GIG_SPEED_DROP (1 << 25) +#define FLAG_SMART_POWER_DOWN (1 << 26) +#define FLAG_MSI_ENABLED (1 << 27) +#define FLAG_RX_CSUM_ENABLED (1 << 28) +#define FLAG_TSO_FORCE (1 << 29) + +#define E1000_RX_DESC_PS(R, i) \ + (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) +#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) +#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) +#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) +#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc) + +enum e1000_state_t { + __E1000_TESTING, + __E1000_RESETTING, + __E1000_DOWN +}; + +enum latency_range { + lowest_latency = 0, + low_latency = 1, + bulk_latency = 2, + latency_invalid = 255 +}; + +extern char e1000e_driver_name[]; +extern const char e1000e_driver_version[]; + +extern void e1000e_check_options(struct e1000_adapter *adapter); +extern void e1000e_set_ethtool_ops(struct net_device *netdev); + +extern int e1000e_up(struct e1000_adapter *adapter); +extern void e1000e_down(struct e1000_adapter *adapter); +extern void e1000e_reinit_locked(struct e1000_adapter *adapter); +extern void e1000e_reset(struct e1000_adapter *adapter); +extern void e1000e_power_up_phy(struct e1000_adapter *adapter); +extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter); +extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter); +extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); +extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); +extern void e1000e_update_stats(struct e1000_adapter *adapter); + +extern unsigned int copybreak; + +extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw); + +extern struct e1000_info e1000_82571_info; +extern struct e1000_info e1000_82572_info; +extern struct e1000_info e1000_82573_info; +extern struct e1000_info e1000_ich8_info; +extern struct e1000_info e1000_ich9_info; +extern struct e1000_info e1000_es2_info; + +extern s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num); + +extern s32 e1000e_commit_phy(struct e1000_hw *hw); + +extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw); + +extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw); +extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state); + +extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, + bool state); +extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); +extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); + +extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw); +extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); +extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw); +extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); +extern s32 e1000e_led_on_generic(struct e1000_hw *hw); +extern s32 e1000e_led_off_generic(struct e1000_hw *hw); +extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw); +extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex); +extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex); +extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw); +extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw); +extern s32 e1000e_id_led_init(struct e1000_hw *hw); +extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw); +extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw); +extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw); +extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw); +extern s32 e1000e_setup_link(struct e1000_hw *hw); +extern void e1000e_clear_vfta(struct e1000_hw *hw); +extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); +extern void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count); +extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); +extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw); +extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop); +extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw); +extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data); +extern void e1000e_config_collision_dist(struct e1000_hw *hw); +extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); +extern s32 e1000e_force_mac_fc(struct e1000_hw *hw); +extern s32 e1000e_blink_led(struct e1000_hw *hw); +extern void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value); +extern void e1000e_reset_adaptive(struct e1000_hw *hw); +extern void e1000e_update_adaptive(struct e1000_hw *hw); + +extern s32 e1000e_setup_copper_link(struct e1000_hw *hw); +extern s32 e1000e_get_phy_id(struct e1000_hw *hw); +extern void e1000e_put_hw_semaphore(struct e1000_hw *hw); +extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw); +extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw); +extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw); +extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw); +extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw); +extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active); +extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); +extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw); +extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw); +extern s32 e1000e_get_cfg_done(struct e1000_hw *hw); +extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw); +extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw); +extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); +extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id); +extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); +extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data); +extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, + u32 usec_interval, bool *success); +extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); +extern s32 e1000e_check_downshift(struct e1000_hw *hw); + +static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) +{ + return hw->phy.ops.reset_phy(hw); +} + +static inline s32 e1000_check_reset_block(struct e1000_hw *hw) +{ + return hw->phy.ops.check_reset_block(hw); +} + +static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return hw->phy.ops.read_phy_reg(hw, offset, data); +} + +static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data) +{ + return hw->phy.ops.write_phy_reg(hw, offset, data); +} + +static inline s32 e1000_get_cable_length(struct e1000_hw *hw) +{ + return hw->phy.ops.get_cable_length(hw); +} + +extern s32 e1000e_acquire_nvm(struct e1000_hw *hw); +extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw); +extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); +extern s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw); +extern void e1000e_release_nvm(struct e1000_hw *hw); +extern void e1000e_reload_nvm(struct e1000_hw *hw); +extern s32 e1000e_read_mac_addr(struct e1000_hw *hw); + +static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw) +{ + return hw->nvm.ops.validate_nvm(hw); +} + +static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw) +{ + return hw->nvm.ops.update_nvm(hw); +} + +static inline s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + return hw->nvm.ops.read_nvm(hw, offset, words, data); +} + +static inline s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + return hw->nvm.ops.write_nvm(hw, offset, words, data); +} + +static inline s32 e1000_get_phy_info(struct e1000_hw *hw) +{ + return hw->phy.ops.get_phy_info(hw); +} + +extern bool e1000e_check_mng_mode(struct e1000_hw *hw); +extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw); +extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length); + +static inline u32 __er32(struct e1000_hw *hw, unsigned long reg) +{ + return readl(hw->hw_addr + reg); +} + +static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val) +{ + writel(val, hw->hw_addr + reg); +} + +#endif /* _E1000_H_ */ diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c new file mode 100644 index 000000000000..88657adf965f --- /dev/null +++ b/drivers/net/e1000e/es2lan.c @@ -0,0 +1,1232 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * 80003ES2LAN Gigabit Ethernet Controller (Copper) + * 80003ES2LAN Gigabit Ethernet Controller (Serdes) + */ + +#include +#include +#include +#include + +#include "e1000.h" + +#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00 +#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02 +#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10 + +#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008 +#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800 +#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010 + +#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004 +#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 + +#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ +#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 + +#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8 +#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9 + +/* GG82563 PHY Specific Status Register (Page 0, Register 16 */ +#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disab. */ +#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060 +#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */ +#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */ +#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */ + +/* PHY Specific Control Register 2 (Page 0, Register 26) */ +#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 + /* 1=Reverse Auto-Negotiation */ + +/* MAC Specific Control Register (Page 2, Register 21) */ +/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */ +#define GG82563_MSCR_TX_CLK_MASK 0x0007 +#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004 +#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005 +#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007 + +#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */ + +/* DSP Distance Register (Page 5, Register 26) */ +#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M + 1 = 50-80M + 2 = 80-110M + 3 = 110-140M + 4 = >140M */ + +/* Kumeran Mode Control Register (Page 193, Register 16) */ +#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 + +/* Power Management Control Register (Page 193, Register 20) */ +#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 + /* 1=Enable SERDES Electrical Idle */ + +/* In-Band Control Register (Page 194, Register 18) */ +#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */ + +/* A table for the GG82563 cable length where the range is defined + * with a lower bound at "index" and the upper bound at + * "index + 5". + */ +static const u16 e1000_gg82563_cable_length_table[] = + { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF }; + +static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw); +static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); +static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); +static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw); +static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw); +static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw); +static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex); + +/** + * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + + if (hw->media_type != e1000_media_type_copper) { + phy->type = e1000_phy_none; + return 0; + } + + phy->addr = 1; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->reset_delay_us = 100; + phy->type = e1000_phy_gg82563; + + /* This can only be done after all function pointers are setup. */ + ret_val = e1000e_get_phy_id(hw); + + /* Verify phy id */ + if (phy->id != GG82563_E_PHY_ID) + return -E1000_ERR_PHY; + + return ret_val; +} + +/** + * e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + u16 size; + + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + + nvm->type = e1000_nvm_eeprom_spi; + + size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); + + /* Added to a constant, "size" becomes the left-shift value + * for setting word_size. + */ + size += NVM_WORD_SIZE_BASE_SHIFT; + nvm->word_size = 1 << size; + + return 0; +} + +/** + * e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct e1000_mac_operations *func = &mac->ops; + + /* Set media type */ + switch (adapter->pdev->device) { + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: + hw->media_type = e1000_media_type_internal_serdes; + break; + default: + hw->media_type = e1000_media_type_copper; + break; + } + + /* Set mta register count */ + mac->mta_reg_count = 128; + /* Set rar entry count */ + mac->rar_entry_count = E1000_RAR_ENTRIES; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = + (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0; + + /* check for link */ + switch (hw->media_type) { + case e1000_media_type_copper: + func->setup_physical_interface = e1000_setup_copper_link_80003es2lan; + func->check_for_link = e1000e_check_for_copper_link; + break; + case e1000_media_type_fiber: + func->setup_physical_interface = e1000e_setup_fiber_serdes_link; + func->check_for_link = e1000e_check_for_fiber_link; + break; + case e1000_media_type_internal_serdes: + func->setup_physical_interface = e1000e_setup_fiber_serdes_link; + func->check_for_link = e1000e_check_for_serdes_link; + break; + default: + return -E1000_ERR_CONFIG; + break; + } + + return 0; +} + +static s32 e1000_get_invariants_80003es2lan(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + s32 rc; + + rc = e1000_init_mac_params_80003es2lan(adapter); + if (rc) + return rc; + + rc = e1000_init_nvm_params_80003es2lan(hw); + if (rc) + return rc; + + rc = e1000_init_phy_params_80003es2lan(hw); + if (rc) + return rc; + + return 0; +} + +/** + * e1000_acquire_phy_80003es2lan - Acquire rights to access PHY + * @hw: pointer to the HW structure + * + * A wrapper to acquire access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + **/ +static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; + + return e1000_acquire_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_release_phy_80003es2lan - Release rights to access PHY + * @hw: pointer to the HW structure + * + * A wrapper to release access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + **/ +static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; + e1000_release_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM + * @hw: pointer to the HW structure + * + * Acquire the semaphore to access the EEPROM. This is a function + * pointer entry point called by the api module. + **/ +static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val; + + ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); + if (ret_val) + return ret_val; + + ret_val = e1000e_acquire_nvm(hw); + + if (ret_val) + e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); + + return ret_val; +} + +/** + * e1000_release_nvm_80003es2lan - Relinquish rights to access NVM + * @hw: pointer to the HW structure + * + * Release the semaphore used to access the EEPROM. This is a + * function pointer entry point called by the api module. + **/ +static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw) +{ + e1000e_release_nvm(hw); + e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); +} + +/** + * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Acquire the SW/FW semaphore to access the PHY or NVM. The mask + * will also specify which port we're acquiring the lock for. + **/ +static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + u32 swmask = mask; + u32 fwmask = mask << 16; + s32 i = 0; + s32 timeout = 200; + + while (i < timeout) { + if (e1000e_get_hw_semaphore(hw)) + return -E1000_ERR_SWFW_SYNC; + + swfw_sync = er32(SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) + break; + + /* Firmware currently using resource (fwmask) + * or other software thread using resource (swmask) */ + e1000e_put_hw_semaphore(hw); + mdelay(5); + i++; + } + + if (i == timeout) { + hw_dbg(hw, + "Driver can't access resource, SW_FW_SYNC timeout.\n"); + return -E1000_ERR_SWFW_SYNC; + } + + swfw_sync |= swmask; + ew32(SW_FW_SYNC, swfw_sync); + + e1000e_put_hw_semaphore(hw); + + return 0; +} + +/** + * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Release the SW/FW semaphore used to access the PHY or NVM. The mask + * will also specify which port we're releasing the lock for. + **/ +static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + + while (e1000e_get_hw_semaphore(hw) != 0); + /* Empty */ + + swfw_sync = er32(SW_FW_SYNC); + swfw_sync &= ~mask; + ew32(SW_FW_SYNC, swfw_sync); + + e1000e_put_hw_semaphore(hw); +} + +/** + * e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @data: pointer to the data returned from the operation + * + * Read the GG82563 PHY register. This is a function pointer entry + * point called by the api module. + **/ +static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, + u32 offset, u16 *data) +{ + s32 ret_val; + u32 page_select; + u16 temp; + + /* Select Configuration Page */ + if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) + page_select = GG82563_PHY_PAGE_SELECT; + else + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + page_select = GG82563_PHY_PAGE_SELECT_ALT; + + temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); + ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp); + if (ret_val) + return ret_val; + + /* The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + udelay(200); + + /* ...and verify the command was successful. */ + ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp); + + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { + ret_val = -E1000_ERR_PHY; + return ret_val; + } + + udelay(200); + + ret_val = e1000e_read_phy_reg_m88(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + udelay(200); + + return ret_val; +} + +/** + * e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @data: value to write to the register + * + * Write to the GG82563 PHY register. This is a function pointer entry + * point called by the api module. + **/ +static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, + u32 offset, u16 data) +{ + s32 ret_val; + u32 page_select; + u16 temp; + + /* Select Configuration Page */ + if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) + page_select = GG82563_PHY_PAGE_SELECT; + else + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + page_select = GG82563_PHY_PAGE_SELECT_ALT; + + temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); + ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp); + if (ret_val) + return ret_val; + + + /* The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + udelay(200); + + /* ...and verify the command was successful. */ + ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp); + + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) + return -E1000_ERR_PHY; + + udelay(200); + + ret_val = e1000e_write_phy_reg_m88(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + udelay(200); + + return ret_val; +} + +/** + * e1000_write_nvm_80003es2lan - Write to ESB2 NVM + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @words: number of words to write + * @data: buffer of data to write to the NVM + * + * Write "words" of data to the ESB2 NVM. This is a function + * pointer entry point called by the api module. + **/ +static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data) +{ + return e1000e_write_nvm_spi(hw, offset, words, data); +} + +/** + * e1000_get_cfg_done_80003es2lan - Wait for configuration to complete + * @hw: pointer to the HW structure + * + * Wait a specific amount of time for manageability processes to complete. + * This is a function pointer entry point called by the phy module. + **/ +static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw) +{ + s32 timeout = PHY_CFG_TIMEOUT; + u32 mask = E1000_NVM_CFG_DONE_PORT_0; + + if (hw->bus.func == 1) + mask = E1000_NVM_CFG_DONE_PORT_1; + + while (timeout) { + if (er32(EEMNGCTL) & mask) + break; + msleep(1); + timeout--; + } + if (!timeout) { + hw_dbg(hw, "MNG configuration cycle has not completed.\n"); + return -E1000_ERR_RESET; + } + + return 0; +} + +/** + * e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex + * @hw: pointer to the HW structure + * + * Force the speed and duplex settings onto the PHY. This is a + * function pointer entry point called by the phy module. + **/ +static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val; + u16 phy_data; + bool link; + + /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO; + ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + hw_dbg(hw, "GG82563 PSCR: %X\n", phy_data); + + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + /* Reset the phy to commit changes. */ + phy_data |= MII_CR_RESET; + + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); + if (ret_val) + return ret_val; + + udelay(1); + + if (hw->phy.wait_for_link) { + hw_dbg(hw, "Waiting for forced speed/duplex link " + "on GG82563 phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + return ret_val; + + if (!link) { + /* We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = e1000e_phy_reset_dsp(hw); + if (ret_val) + return ret_val; + } + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + return ret_val; + } + + ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + /* Resetting the phy means we need to verify the TX_CLK corresponds + * to the link speed. 10Mbps -> 2.5MHz, else 25MHz. + */ + phy_data &= ~GG82563_MSCR_TX_CLK_MASK; + if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED) + phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5; + else + phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25; + + /* In addition, we must re-enable CRS on Tx for both half and full + * duplex. + */ + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data); + + return ret_val; +} + +/** + * e1000_get_cable_length_80003es2lan - Set approximate cable length + * @hw: pointer to the HW structure + * + * Find the approximate cable length as measured by the GG82563 PHY. + * This is a function pointer entry point called by the phy module. + **/ +static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + u16 index; + + ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data); + if (ret_val) + return ret_val; + + index = phy_data & GG82563_DSPD_CABLE_LENGTH; + phy->min_cable_length = e1000_gg82563_cable_length_table[index]; + phy->max_cable_length = e1000_gg82563_cable_length_table[index+5]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + + return 0; +} + +/** + * e1000_get_link_up_info_80003es2lan - Report speed and duplex + * @hw: pointer to the HW structure + * @speed: pointer to speed buffer + * @duplex: pointer to duplex buffer + * + * Retrieve the current speed and duplex configuration. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + s32 ret_val; + + if (hw->media_type == e1000_media_type_copper) { + ret_val = e1000e_get_speed_and_duplex_copper(hw, + speed, + duplex); + if (ret_val) + return ret_val; + if (*speed == SPEED_1000) + ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw); + else + ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, + *duplex); + } else { + ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw, + speed, + duplex); + } + + return ret_val; +} + +/** + * e1000_reset_hw_80003es2lan - Reset the ESB2 controller + * @hw: pointer to the HW structure + * + * Perform a global reset to the ESB2 controller. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) +{ + u32 ctrl; + u32 icr; + s32 ret_val; + + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000e_disable_pcie_master(hw); + if (ret_val) + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + + hw_dbg(hw, "Masking off all interrupts\n"); + ew32(IMC, 0xffffffff); + + ew32(RCTL, 0); + ew32(TCTL, E1000_TCTL_PSP); + e1e_flush(); + + msleep(10); + + ctrl = er32(CTRL); + + hw_dbg(hw, "Issuing a global reset to MAC\n"); + ew32(CTRL, ctrl | E1000_CTRL_RST); + + ret_val = e1000e_get_auto_rd_done(hw); + if (ret_val) + /* We don't want to continue accessing MAC registers. */ + return ret_val; + + /* Clear any pending interrupt events. */ + ew32(IMC, 0xffffffff); + icr = er32(ICR); + + return 0; +} + +/** + * e1000_init_hw_80003es2lan - Initialize the ESB2 controller + * @hw: pointer to the HW structure + * + * Initialize the hw bits, LED, VFTA, MTA, link and hw counters. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 reg_data; + s32 ret_val; + u16 i; + + e1000_initialize_hw_bits_80003es2lan(hw); + + /* Initialize identification LED */ + ret_val = e1000e_id_led_init(hw); + if (ret_val) { + hw_dbg(hw, "Error initializing identification LED\n"); + return ret_val; + } + + /* Disabling VLAN filtering */ + hw_dbg(hw, "Initializing the IEEE VLAN\n"); + e1000e_clear_vfta(hw); + + /* Setup the receive address. */ + e1000e_init_rx_addrs(hw, mac->rar_entry_count); + + /* Zero out the Multicast HASH table */ + hw_dbg(hw, "Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = e1000e_setup_link(hw); + + /* Set the transmit descriptor write-back policy */ + reg_data = er32(TXDCTL); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; + ew32(TXDCTL, reg_data); + + /* ...for both queues. */ + reg_data = er32(TXDCTL1); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; + ew32(TXDCTL1, reg_data); + + /* Enable retransmit on late collisions */ + reg_data = er32(TCTL); + reg_data |= E1000_TCTL_RTLC; + ew32(TCTL, reg_data); + + /* Configure Gigabit Carry Extend Padding */ + reg_data = er32(TCTL_EXT); + reg_data &= ~E1000_TCTL_EXT_GCEX_MASK; + reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN; + ew32(TCTL_EXT, reg_data); + + /* Configure Transmit Inter-Packet Gap */ + reg_data = er32(TIPG); + reg_data &= ~E1000_TIPG_IPGT_MASK; + reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; + ew32(TIPG, reg_data); + + reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001); + reg_data &= ~0x00100000; + E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_80003es2lan(hw); + + return ret_val; +} + +/** + * e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2 + * @hw: pointer to the HW structure + * + * Initializes required hardware-dependent bits needed for normal operation. + **/ +static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw) +{ + u32 reg; + + /* Transmit Descriptor Control 0 */ + reg = er32(TXDCTL); + reg |= (1 << 22); + ew32(TXDCTL, reg); + + /* Transmit Descriptor Control 1 */ + reg = er32(TXDCTL1); + reg |= (1 << 22); + ew32(TXDCTL1, reg); + + /* Transmit Arbitration Control 0 */ + reg = er32(TARC0); + reg &= ~(0xF << 27); /* 30:27 */ + if (hw->media_type != e1000_media_type_copper) + reg &= ~(1 << 20); + ew32(TARC0, reg); + + /* Transmit Arbitration Control 1 */ + reg = er32(TARC1); + if (er32(TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + ew32(TARC1, reg); +} + +/** + * e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link + * @hw: pointer to the HW structure + * + * Setup some GG82563 PHY registers for obtaining link + **/ +static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u32 ctrl_ext; + u16 data; + + ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, + &data); + if (ret_val) + return ret_val; + + data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ + data |= GG82563_MSCR_TX_CLK_1000MBPS_25; + + ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, + data); + if (ret_val) + return ret_val; + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data); + if (ret_val) + return ret_val; + + data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; + + switch (phy->mdix) { + case 1: + data |= GG82563_PSCR_CROSSOVER_MODE_MDI; + break; + case 2: + data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; + break; + case 0: + default: + data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + if (phy->disable_polarity_correction) + data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + + ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data); + if (ret_val) + return ret_val; + + /* SW Reset the PHY so all changes take effect */ + ret_val = e1000e_commit_phy(hw); + if (ret_val) { + hw_dbg(hw, "Error Resetting the PHY\n"); + return ret_val; + } + + /* Bypass RX and TX FIFO's */ + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, + E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS | + E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data); + if (ret_val) + return ret_val; + + data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; + ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data); + if (ret_val) + return ret_val; + + ctrl_ext = er32(CTRL_EXT); + ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK); + ew32(CTRL_EXT, ctrl_ext); + + ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data); + if (ret_val) + return ret_val; + + /* Do not init these registers when the HW is in IAMT mode, since the + * firmware will have already initialized them. We only initialize + * them if the HW is not in IAMT mode. + */ + if (!e1000e_check_mng_mode(hw)) { + /* Enable Electrical Idle on the PHY */ + data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; + ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL, data); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data); + if (ret_val) + return ret_val; + + data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data); + if (ret_val) + return ret_val; + } + + /* Workaround: Disable padding in Kumeran interface in the MAC + * and in the PHY to avoid CRC errors. + */ + ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data); + if (ret_val) + return ret_val; + + data |= GG82563_ICR_DIS_PADDING; + ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data); + if (ret_val) + return ret_val; + + return 0; +} + +/** + * e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2 + * @hw: pointer to the HW structure + * + * Essentially a wrapper for setting up all things "copper" related. + * This is a function pointer entry point called by the mac module. + **/ +static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val; + u16 reg_data; + + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ew32(CTRL, ctrl); + + /* Set the mac to wait the maximum time between each + * iteration and increase the max iterations when + * polling the phy; this fixes erroneous timeouts at 10Mbps. */ + ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); + if (ret_val) + return ret_val; + ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); + if (ret_val) + return ret_val; + reg_data |= 0x3F; + ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); + if (ret_val) + return ret_val; + ret_val = e1000e_read_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, + ®_data); + if (ret_val) + return ret_val; + reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING; + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, + reg_data); + if (ret_val) + return ret_val; + + ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw); + if (ret_val) + return ret_val; + + ret_val = e1000e_setup_copper_link(hw); + + return 0; +} + +/** + * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation + * @hw: pointer to the HW structure + * @duplex: current duplex setting + * + * Configure the KMRN interface by applying last minute quirks for + * 10/100 operation. + **/ +static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) +{ + s32 ret_val; + u32 tipg; + u16 reg_data; + + reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = er32(TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN; + ew32(TIPG, tipg); + + ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); + if (ret_val) + return ret_val; + + if (duplex == HALF_DUPLEX) + reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; + else + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + + ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + + return 0; +} + +/** + * e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation + * @hw: pointer to the HW structure + * + * Configure the KMRN interface by applying last minute quirks for + * gigabit operation. + **/ +static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val; + u16 reg_data; + u32 tipg; + + reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = er32(TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; + ew32(TIPG, tipg); + + ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); + if (ret_val) + return ret_val; + + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + + return ret_val; +} + +/** + * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters + * @hw: pointer to the HW structure + * + * Clears the hardware counters by reading the counter registers. + **/ +static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) +{ + u32 temp; + + e1000e_clear_hw_cntrs_base(hw); + + temp = er32(PRC64); + temp = er32(PRC127); + temp = er32(PRC255); + temp = er32(PRC511); + temp = er32(PRC1023); + temp = er32(PRC1522); + temp = er32(PTC64); + temp = er32(PTC127); + temp = er32(PTC255); + temp = er32(PTC511); + temp = er32(PTC1023); + temp = er32(PTC1522); + + temp = er32(ALGNERRC); + temp = er32(RXERRC); + temp = er32(TNCRS); + temp = er32(CEXTERR); + temp = er32(TSCTC); + temp = er32(TSCTFC); + + temp = er32(MGTPRC); + temp = er32(MGTPDC); + temp = er32(MGTPTC); + + temp = er32(IAC); + temp = er32(ICRXOC); + + temp = er32(ICRXPTC); + temp = er32(ICRXATC); + temp = er32(ICTXPTC); + temp = er32(ICTXATC); + temp = er32(ICTXQEC); + temp = er32(ICTXQMTC); + temp = er32(ICRXDMTC); +} + +static struct e1000_mac_operations es2_mac_ops = { + .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + /* check_for_link dependent on media type */ + .cleanup_led = e1000e_cleanup_led_generic, + .clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan, + .get_bus_info = e1000e_get_bus_info_pcie, + .get_link_up_info = e1000_get_link_up_info_80003es2lan, + .led_on = e1000e_led_on_generic, + .led_off = e1000e_led_off_generic, + .mc_addr_list_update = e1000e_mc_addr_list_update_generic, + .reset_hw = e1000_reset_hw_80003es2lan, + .init_hw = e1000_init_hw_80003es2lan, + .setup_link = e1000e_setup_link, + /* setup_physical_interface dependent on media type */ +}; + +static struct e1000_phy_operations es2_phy_ops = { + .acquire_phy = e1000_acquire_phy_80003es2lan, + .check_reset_block = e1000e_check_reset_block_generic, + .commit_phy = e1000e_phy_sw_reset, + .force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan, + .get_cfg_done = e1000_get_cfg_done_80003es2lan, + .get_cable_length = e1000_get_cable_length_80003es2lan, + .get_phy_info = e1000e_get_phy_info_m88, + .read_phy_reg = e1000_read_phy_reg_gg82563_80003es2lan, + .release_phy = e1000_release_phy_80003es2lan, + .reset_phy = e1000e_phy_hw_reset_generic, + .set_d0_lplu_state = NULL, + .set_d3_lplu_state = e1000e_set_d3_lplu_state, + .write_phy_reg = e1000_write_phy_reg_gg82563_80003es2lan, +}; + +static struct e1000_nvm_operations es2_nvm_ops = { + .acquire_nvm = e1000_acquire_nvm_80003es2lan, + .read_nvm = e1000e_read_nvm_eerd, + .release_nvm = e1000_release_nvm_80003es2lan, + .update_nvm = e1000e_update_nvm_checksum_generic, + .valid_led_default = e1000e_valid_led_default, + .validate_nvm = e1000e_validate_nvm_checksum_generic, + .write_nvm = e1000_write_nvm_80003es2lan, +}; + +struct e1000_info e1000_es2_info = { + .mac = e1000_80003es2lan, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_STATS_PTC_PRC + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_STATS_ICR_ICT + | FLAG_RX_NEEDS_RESTART /* errata */ + | FLAG_TARC_SET_BIT_ZERO /* errata */ + | FLAG_APME_CHECK_PORT_B + | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ + | FLAG_TIPG_MEDIUM_FOR_80003ESLAN, + .pba = 38, + .get_invariants = e1000_get_invariants_80003es2lan, + .mac_ops = &es2_mac_ops, + .phy_ops = &es2_phy_ops, + .nvm_ops = &es2_nvm_ops, +}; + diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c new file mode 100644 index 000000000000..0e80406bfbd7 --- /dev/null +++ b/drivers/net/e1000e/ethtool.c @@ -0,0 +1,1774 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* ethtool support for e1000 */ + +#include +#include +#include +#include + +#include "e1000.h" + +struct e1000_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ + offsetof(struct e1000_adapter, m) +static const struct e1000_stats e1000_gstrings_stats[] = { + { "rx_packets", E1000_STAT(stats.gprc) }, + { "tx_packets", E1000_STAT(stats.gptc) }, + { "rx_bytes", E1000_STAT(stats.gorcl) }, + { "tx_bytes", E1000_STAT(stats.gotcl) }, + { "rx_broadcast", E1000_STAT(stats.bprc) }, + { "tx_broadcast", E1000_STAT(stats.bptc) }, + { "rx_multicast", E1000_STAT(stats.mprc) }, + { "tx_multicast", E1000_STAT(stats.mptc) }, + { "rx_errors", E1000_STAT(net_stats.rx_errors) }, + { "tx_errors", E1000_STAT(net_stats.tx_errors) }, + { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, + { "multicast", E1000_STAT(stats.mprc) }, + { "collisions", E1000_STAT(stats.colc) }, + { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) }, + { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, + { "rx_crc_errors", E1000_STAT(stats.crcerrs) }, + { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, + { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, + { "rx_missed_errors", E1000_STAT(stats.mpc) }, + { "tx_aborted_errors", E1000_STAT(stats.ecol) }, + { "tx_carrier_errors", E1000_STAT(stats.tncrs) }, + { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) }, + { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) }, + { "tx_window_errors", E1000_STAT(stats.latecol) }, + { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, + { "tx_deferred_ok", E1000_STAT(stats.dc) }, + { "tx_single_coll_ok", E1000_STAT(stats.scc) }, + { "tx_multi_coll_ok", E1000_STAT(stats.mcc) }, + { "tx_timeout_count", E1000_STAT(tx_timeout_count) }, + { "tx_restart_queue", E1000_STAT(restart_queue) }, + { "rx_long_length_errors", E1000_STAT(stats.roc) }, + { "rx_short_length_errors", E1000_STAT(stats.ruc) }, + { "rx_align_errors", E1000_STAT(stats.algnerrc) }, + { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) }, + { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) }, + { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) }, + { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, + { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, + { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, + { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, + { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, + { "rx_header_split", E1000_STAT(rx_hdr_split) }, + { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, + { "tx_smbus", E1000_STAT(stats.mgptc) }, + { "rx_smbus", E1000_STAT(stats.mgprc) }, + { "dropped_smbus", E1000_STAT(stats.mgpdc) }, + { "rx_dma_failed", E1000_STAT(rx_dma_failed) }, + { "tx_dma_failed", E1000_STAT(tx_dma_failed) }, +}; + +#define E1000_GLOBAL_STATS_LEN \ + sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN) +static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN + +static int e1000_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (hw->media_type == e1000_media_type_copper) { + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP); + if (hw->phy.type == e1000_phy_ife) + ecmd->supported &= ~SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_TP; + + if (hw->mac.autoneg == 1) { + ecmd->advertising |= ADVERTISED_Autoneg; + /* the e1000 autoneg seems to match ethtool nicely */ + ecmd->advertising |= hw->phy.autoneg_advertised; + } + + ecmd->port = PORT_TP; + ecmd->phy_address = hw->phy.addr; + ecmd->transceiver = XCVR_INTERNAL; + + } else { + ecmd->supported = (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg); + + ecmd->advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE | + ADVERTISED_Autoneg); + + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; + } + + if (er32(STATUS) & E1000_STATUS_LU) { + + adapter->hw.mac.ops.get_link_up_info(hw, &adapter->link_speed, + &adapter->link_duplex); + ecmd->speed = adapter->link_speed; + + /* unfortunately FULL_DUPLEX != DUPLEX_FULL + * and HALF_DUPLEX != DUPLEX_HALF */ + + if (adapter->link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) || + hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + return 0; +} + +static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +{ + struct e1000_mac_info *mac = &adapter->hw.mac; + + mac->autoneg = 0; + + /* Fiber NICs only allow 1000 gbps Full duplex */ + if ((adapter->hw.media_type == e1000_media_type_fiber) && + spddplx != (SPEED_1000 + DUPLEX_FULL)) { + ndev_err(adapter->netdev, "Unsupported Speed/Duplex " + "configuration\n"); + return -EINVAL; + } + + switch (spddplx) { + case SPEED_10 + DUPLEX_HALF: + mac->forced_speed_duplex = ADVERTISE_10_HALF; + break; + case SPEED_10 + DUPLEX_FULL: + mac->forced_speed_duplex = ADVERTISE_10_FULL; + break; + case SPEED_100 + DUPLEX_HALF: + mac->forced_speed_duplex = ADVERTISE_100_HALF; + break; + case SPEED_100 + DUPLEX_FULL: + mac->forced_speed_duplex = ADVERTISE_100_FULL; + break; + case SPEED_1000 + DUPLEX_FULL: + mac->autoneg = 1; + adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + DUPLEX_HALF: /* not supported */ + default: + ndev_err(adapter->netdev, "Unsupported Speed/Duplex " + "configuration\n"); + return -EINVAL; + } + return 0; +} + +static int e1000_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + /* When SoL/IDER sessions are active, autoneg/speed/duplex + * cannot be changed */ + if (e1000_check_reset_block(hw)) { + ndev_err(netdev, "Cannot change link " + "characteristics when SoL/IDER is active.\n"); + return -EINVAL; + } + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (ecmd->autoneg == AUTONEG_ENABLE) { + hw->mac.autoneg = 1; + if (hw->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; + ecmd->advertising = hw->phy.autoneg_advertised; + } else { + if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + clear_bit(__E1000_RESETTING, &adapter->state); + return -EINVAL; + } + } + + /* reset the link */ + + if (netif_running(adapter->netdev)) { + e1000e_down(adapter); + e1000e_up(adapter); + } else { + e1000e_reset(adapter); + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return 0; +} + +static void e1000_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + pause->autoneg = + (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + + if (hw->mac.fc == e1000_fc_rx_pause) { + pause->rx_pause = 1; + } else if (hw->mac.fc == e1000_fc_tx_pause) { + pause->tx_pause = 1; + } else if (hw->mac.fc == e1000_fc_full) { + pause->rx_pause = 1; + pause->tx_pause = 1; + } +} + +static int e1000_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int retval = 0; + + adapter->fc_autoneg = pause->autoneg; + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (pause->rx_pause && pause->tx_pause) + hw->mac.fc = e1000_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->mac.fc = e1000_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->mac.fc = e1000_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->mac.fc = e1000_fc_none; + + hw->mac.original_fc = hw->mac.fc; + + if (adapter->fc_autoneg == AUTONEG_ENABLE) { + if (netif_running(adapter->netdev)) { + e1000e_down(adapter); + e1000e_up(adapter); + } else { + e1000e_reset(adapter); + } + } else { + retval = ((hw->media_type == e1000_media_type_fiber) ? + hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw)); + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return retval; +} + +static u32 e1000_get_rx_csum(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return (adapter->flags & FLAG_RX_CSUM_ENABLED); +} + +static int e1000_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (data) + adapter->flags |= FLAG_RX_CSUM_ENABLED; + else + adapter->flags &= ~FLAG_RX_CSUM_ENABLED; + + if (netif_running(netdev)) + e1000e_reinit_locked(adapter); + else + e1000e_reset(adapter); + return 0; +} + +static u32 e1000_get_tx_csum(struct net_device *netdev) +{ + return ((netdev->features & NETIF_F_HW_CSUM) != 0); +} + +static int e1000_set_tx_csum(struct net_device *netdev, u32 data) +{ + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; +} + +static int e1000_set_tso(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (data) { + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + } else { + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + } + + ndev_info(netdev, "TSO is %s\n", + data ? "Enabled" : "Disabled"); + adapter->flags |= FLAG_TSO_FORCE; + return 0; +} + +static u32 e1000_get_msglevel(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return adapter->msg_enable; +} + +static void e1000_set_msglevel(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + adapter->msg_enable = data; +} + +static int e1000_get_regs_len(struct net_device *netdev) +{ +#define E1000_REGS_LEN 32 /* overestimate */ + return E1000_REGS_LEN * sizeof(u32); +} + +static void e1000_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u16 phy_data; + u8 revision_id; + + memset(p, 0, E1000_REGS_LEN * sizeof(u32)); + + pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id); + + regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device; + + regs_buff[0] = er32(CTRL); + regs_buff[1] = er32(STATUS); + + regs_buff[2] = er32(RCTL); + regs_buff[3] = er32(RDLEN); + regs_buff[4] = er32(RDH); + regs_buff[5] = er32(RDT); + regs_buff[6] = er32(RDTR); + + regs_buff[7] = er32(TCTL); + regs_buff[8] = er32(TDLEN); + regs_buff[9] = er32(TDH); + regs_buff[10] = er32(TDT); + regs_buff[11] = er32(TIDV); + + regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */ + if (hw->phy.type == e1000_phy_m88) { + e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + regs_buff[13] = (u32)phy_data; /* cable length */ + regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + regs_buff[17] = (u32)phy_data; /* extended 10bt distance */ + regs_buff[18] = regs_buff[13]; /* cable polarity */ + regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[20] = regs_buff[17]; /* polarity correction */ + /* phy receive errors */ + regs_buff[22] = adapter->phy_stats.receive_errors; + regs_buff[23] = regs_buff[13]; /* mdix mode */ + } + regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */ + e1e_rphy(hw, PHY_1000T_STATUS, &phy_data); + regs_buff[24] = (u32)phy_data; /* phy local receiver status */ + regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ +} + +static int e1000_get_eeprom_len(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return adapter->hw.nvm.word_size * 2; +} + +static int e1000_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u16 *eeprom_buff; + int first_word; + int last_word; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = adapter->pdev->vendor | (adapter->pdev->device << 16); + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + + eeprom_buff = kmalloc(sizeof(u16) * + (last_word - first_word + 1), GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + if (hw->nvm.type == e1000_nvm_eeprom_spi) { + ret_val = e1000_read_nvm(hw, first_word, + last_word - first_word + 1, + eeprom_buff); + } else { + for (i = 0; i < last_word - first_word + 1; i++) { + ret_val = e1000_read_nvm(hw, first_word + i, 1, + &eeprom_buff[i]); + if (ret_val) + break; + } + } + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); + kfree(eeprom_buff); + + return ret_val; +} + +static int e1000_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u16 *eeprom_buff; + void *ptr; + int max_len; + int first_word; + int last_word; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EOPNOTSUPP; + + if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16))) + return -EFAULT; + + max_len = hw->nvm.word_size * 2; + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + eeprom_buff = kmalloc(max_len, GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + ptr = (void *)eeprom_buff; + + if (eeprom->offset & 1) { + /* need read/modify/write of first changed EEPROM word */ + /* only the second byte of the word is being modified */ + ret_val = e1000_read_nvm(hw, first_word, 1, &eeprom_buff[0]); + ptr++; + } + if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) + /* need read/modify/write of last changed EEPROM word */ + /* only the first byte of the word is being modified */ + ret_val = e1000_read_nvm(hw, last_word, 1, + &eeprom_buff[last_word - first_word]); + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(ptr, bytes, eeprom->len); + + for (i = 0; i < last_word - first_word + 1; i++) + eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); + + ret_val = e1000_write_nvm(hw, first_word, + last_word - first_word + 1, eeprom_buff); + + /* Update the checksum over the first part of the EEPROM if needed + * and flush shadow RAM for 82573 controllers */ + if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) || + (hw->mac.type == e1000_82573))) + e1000e_update_nvm_checksum(hw); + + kfree(eeprom_buff); + return ret_val; +} + +static void e1000_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + char firmware_version[32]; + u16 eeprom_data; + + strncpy(drvinfo->driver, e1000e_driver_name, 32); + strncpy(drvinfo->version, e1000e_driver_version, 32); + + /* EEPROM image version # is reported as firmware version # for + * PCI-E controllers */ + e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data); + sprintf(firmware_version, "%d.%d-%d", + (eeprom_data & 0xF000) >> 12, + (eeprom_data & 0x0FF0) >> 4, + eeprom_data & 0x000F); + + strncpy(drvinfo->fw_version, firmware_version, 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->n_stats = E1000_STATS_LEN; + drvinfo->testinfo_len = E1000_TEST_LEN; + drvinfo->regdump_len = e1000_get_regs_len(netdev); + drvinfo->eedump_len = e1000_get_eeprom_len(netdev); +} + +static void e1000_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_ring *rx_ring = adapter->rx_ring; + + ring->rx_max_pending = E1000_MAX_RXD; + ring->tx_max_pending = E1000_MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rx_ring->count; + ring->tx_pending = tx_ring->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int e1000_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_ring *tx_ring, *tx_old; + struct e1000_ring *rx_ring, *rx_old; + int err; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (netif_running(adapter->netdev)) + e1000e_down(adapter); + + tx_old = adapter->tx_ring; + rx_old = adapter->rx_ring; + + err = -ENOMEM; + tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!tx_ring) + goto err_alloc_tx; + + rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!rx_ring) + goto err_alloc_rx; + + adapter->tx_ring = tx_ring; + adapter->rx_ring = rx_ring; + + rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD); + rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD)); + rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); + + tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD); + tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD)); + tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); + + if (netif_running(adapter->netdev)) { + /* Try to get new resources before deleting old */ + err = e1000e_setup_rx_resources(adapter); + if (err) + goto err_setup_rx; + err = e1000e_setup_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* save the new, restore the old in order to free it, + * then restore the new back again */ + adapter->rx_ring = rx_old; + adapter->tx_ring = tx_old; + e1000e_free_rx_resources(adapter); + e1000e_free_tx_resources(adapter); + kfree(tx_old); + kfree(rx_old); + adapter->rx_ring = rx_ring; + adapter->tx_ring = tx_ring; + err = e1000e_up(adapter); + if (err) + goto err_setup; + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return 0; +err_setup_tx: + e1000e_free_rx_resources(adapter); +err_setup_rx: + adapter->rx_ring = rx_old; + adapter->tx_ring = tx_old; + kfree(rx_ring); +err_alloc_rx: + kfree(tx_ring); +err_alloc_tx: + e1000e_up(adapter); +err_setup: + clear_bit(__E1000_RESETTING, &adapter->state); + return err; +} + +#define REG_PATTERN_TEST(R, M, W) REG_PATTERN_TEST_ARRAY(R, 0, M, W) +#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, writeable) \ +{ \ + u32 _pat; \ + u32 _value; \ + u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ + for (_pat = 0; _pat < ARRAY_SIZE(_test); _pat++) { \ + E1000_WRITE_REG_ARRAY(hw, reg, offset, \ + (_test[_pat] & writeable)); \ + _value = E1000_READ_REG_ARRAY(hw, reg, offset); \ + if (_value != (_test[_pat] & writeable & mask)) { \ + ndev_err(netdev, "pattern test reg %04X " \ + "failed: got 0x%08X expected 0x%08X\n", \ + reg + offset, \ + value, (_test[_pat] & writeable & mask)); \ + *data = reg; \ + return 1; \ + } \ + } \ +} + +#define REG_SET_AND_CHECK(R, M, W) \ +{ \ + u32 _value; \ + __ew32(hw, R, W & M); \ + _value = __er32(hw, R); \ + if ((W & M) != (_value & M)) { \ + ndev_err(netdev, "set/check reg %04X test failed: " \ + "got 0x%08X expected 0x%08X\n", R, (_value & M), \ + (W & M)); \ + *data = R; \ + return 1; \ + } \ +} + +static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &adapter->hw.mac; + struct net_device *netdev = adapter->netdev; + u32 value; + u32 before; + u32 after; + u32 i; + u32 toggle; + + /* The status register is Read Only, so a write should fail. + * Some bits that get toggled are ignored. + */ + switch (mac->type) { + /* there are several bits on newer hardware that are r/w */ + case e1000_82571: + case e1000_82572: + case e1000_80003es2lan: + toggle = 0x7FFFF3FF; + break; + case e1000_82573: + case e1000_ich8lan: + case e1000_ich9lan: + toggle = 0x7FFFF033; + break; + default: + toggle = 0xFFFFF833; + break; + } + + before = er32(STATUS); + value = (er32(STATUS) & toggle); + ew32(STATUS, toggle); + after = er32(STATUS) & toggle; + if (value != after) { + ndev_err(netdev, "failed STATUS register test got: " + "0x%08X expected: 0x%08X\n", after, value); + *data = 1; + return 1; + } + /* restore previous status */ + ew32(STATUS, before); + + if ((mac->type != e1000_ich8lan) && + (mac->type != e1000_ich9lan)) { + REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF); + } + + REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDBAH, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDLEN, 0x000FFF80, 0x000FFFFF); + REG_PATTERN_TEST(E1000_RDH, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_RDT, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8); + REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF); + REG_PATTERN_TEST(E1000_TDBAH, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TDLEN, 0x000FFF80, 0x000FFFFF); + + REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000); + + before = (((mac->type == e1000_ich8lan) || + (mac->type == e1000_ich9lan)) ? 0x06C3B33E : 0x06DFB3FE); + REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB); + REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000); + + REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x01FFFFFF); + REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFF000, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TXCW, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFF000, 0xFFFFFFFF); + + for (i = 0; i < mac->mta_reg_count; i++) + REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); + + *data = 0; + return 0; +} + +static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data) +{ + u16 temp; + u16 checksum = 0; + u16 i; + + *data = 0; + /* Read and add up the contents of the EEPROM */ + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) { + *data = 1; + break; + } + checksum += temp; + } + + /* If Checksum is not Correct return error else test passed */ + if ((checksum != (u16) NVM_SUM) && !(*data)) + *data = 2; + + return *data; +} + +static irqreturn_t e1000_test_intr(int irq, void *data) +{ + struct net_device *netdev = (struct net_device *) data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + adapter->test_icr |= er32(ICR); + + return IRQ_HANDLED; +} + +static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 mask; + u32 shared_int = 1; + u32 irq = adapter->pdev->irq; + int i; + + *data = 0; + + /* NOTE: we don't test MSI interrupts here, yet */ + /* Hook up test interrupt handler just for this test */ + if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, + netdev)) { + shared_int = 0; + } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, + netdev->name, netdev)) { + *data = 1; + return -1; + } + ndev_info(netdev, "testing %s interrupt\n", + (shared_int ? "shared" : "unshared")); + + /* Disable all the interrupts */ + ew32(IMC, 0xFFFFFFFF); + msleep(10); + + /* Test each interrupt */ + for (i = 0; i < 10; i++) { + + if (((adapter->hw.mac.type == e1000_ich8lan) || + (adapter->hw.mac.type == e1000_ich9lan)) && i == 8) + continue; + + /* Interrupt to test */ + mask = 1 << i; + + if (!shared_int) { + /* Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMC, mask); + ew32(ICS, mask); + msleep(10); + + if (adapter->test_icr & mask) { + *data = 3; + break; + } + } + + /* Enable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was not posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMS, mask); + ew32(ICS, mask); + msleep(10); + + if (!(adapter->test_icr & mask)) { + *data = 4; + break; + } + + if (!shared_int) { + /* Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMC, ~mask & 0x00007FFF); + ew32(ICS, ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr) { + *data = 5; + break; + } + } + } + + /* Disable all the interrupts */ + ew32(IMC, 0xFFFFFFFF); + msleep(10); + + /* Unhook test interrupt handler */ + free_irq(irq, netdev); + + return *data; +} + +static void e1000_free_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i; + + if (tx_ring->desc && tx_ring->buffer_info) { + for (i = 0; i < tx_ring->count; i++) { + if (tx_ring->buffer_info[i].dma) + pci_unmap_single(pdev, + tx_ring->buffer_info[i].dma, + tx_ring->buffer_info[i].length, + PCI_DMA_TODEVICE); + if (tx_ring->buffer_info[i].skb) + dev_kfree_skb(tx_ring->buffer_info[i].skb); + } + } + + if (rx_ring->desc && rx_ring->buffer_info) { + for (i = 0; i < rx_ring->count; i++) { + if (rx_ring->buffer_info[i].dma) + pci_unmap_single(pdev, + rx_ring->buffer_info[i].dma, + 2048, PCI_DMA_FROMDEVICE); + if (rx_ring->buffer_info[i].skb) + dev_kfree_skb(rx_ring->buffer_info[i].skb); + } + } + + if (tx_ring->desc) { + dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; + } + if (rx_ring->desc) { + dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; + } + + kfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + kfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; +} + +static int e1000_setup_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + int size; + int i; + int ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + if (!tx_ring->count) + tx_ring->count = E1000_DEFAULT_TXD; + + size = tx_ring->count * sizeof(struct e1000_buffer); + tx_ring->buffer_info = kmalloc(size, GFP_KERNEL); + if (!tx_ring->buffer_info) { + ret_val = 1; + goto err_nomem; + } + memset(tx_ring->buffer_info, 0, size); + + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size, + &tx_ring->dma, GFP_KERNEL); + if (!tx_ring->desc) { + ret_val = 2; + goto err_nomem; + } + memset(tx_ring->desc, 0, tx_ring->size); + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + ew32(TDBAL, + ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); + ew32(TDBAH, ((u64) tx_ring->dma >> 32)); + ew32(TDLEN, + tx_ring->count * sizeof(struct e1000_tx_desc)); + ew32(TDH, 0); + ew32(TDT, 0); + ew32(TCTL, + E1000_TCTL_PSP | E1000_TCTL_EN | + E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | + E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); + + for (i = 0; i < tx_ring->count; i++) { + struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i); + struct sk_buff *skb; + unsigned int skb_size = 1024; + + skb = alloc_skb(skb_size, GFP_KERNEL); + if (!skb) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, skb_size); + tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[i].length = skb->len; + tx_ring->buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(tx_ring->buffer_info[i].dma)) { + ret_val = 4; + goto err_nomem; + } + tx_desc->buffer_addr = cpu_to_le64( + tx_ring->buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(skb->len); + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS | + E1000_TXD_CMD_RPS); + tx_desc->upper.data = 0; + } + + /* Setup Rx descriptor ring and Rx buffers */ + + if (!rx_ring->count) + rx_ring->count = E1000_DEFAULT_RXD; + + size = rx_ring->count * sizeof(struct e1000_buffer); + rx_ring->buffer_info = kmalloc(size, GFP_KERNEL); + if (!rx_ring->buffer_info) { + ret_val = 5; + goto err_nomem; + } + memset(rx_ring->buffer_info, 0, size); + + rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc); + rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size, + &rx_ring->dma, GFP_KERNEL); + if (!rx_ring->desc) { + ret_val = 6; + goto err_nomem; + } + memset(rx_ring->desc, 0, rx_ring->size); + rx_ring->next_to_use = 0; + rx_ring->next_to_clean = 0; + + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF)); + ew32(RDBAH, ((u64) rx_ring->dma >> 32)); + ew32(RDLEN, rx_ring->size); + ew32(RDH, 0); + ew32(RDT, 0); + rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + ew32(RCTL, rctl); + + for (i = 0; i < rx_ring->count; i++) { + struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i); + struct sk_buff *skb; + + skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL); + if (!skb) { + ret_val = 7; + goto err_nomem; + } + skb_reserve(skb, NET_IP_ALIGN); + rx_ring->buffer_info[i].skb = skb; + rx_ring->buffer_info[i].dma = + pci_map_single(pdev, skb->data, 2048, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(rx_ring->buffer_info[i].dma)) { + ret_val = 8; + goto err_nomem; + } + rx_desc->buffer_addr = + cpu_to_le64(rx_ring->buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + +err_nomem: + e1000_free_desc_rings(adapter); + return ret_val; +} + +static void e1000_phy_disable_receiver(struct e1000_adapter *adapter) +{ + /* Write out to PHY registers 29 and 30 to disable the Receiver. */ + e1e_wphy(&adapter->hw, 29, 0x001F); + e1e_wphy(&adapter->hw, 30, 0x8FFC); + e1e_wphy(&adapter->hw, 29, 0x001A); + e1e_wphy(&adapter->hw, 30, 0x8FF0); +} + +static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_reg = 0; + u32 stat_reg = 0; + + adapter->hw.mac.autoneg = 0; + + if (adapter->hw.phy.type == e1000_phy_m88) { + /* Auto-MDI/MDIX Off */ + e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); + /* reset to update Auto-MDI/MDIX */ + e1e_wphy(hw, PHY_CONTROL, 0x9140); + /* autoneg off */ + e1e_wphy(hw, PHY_CONTROL, 0x8140); + } else if (adapter->hw.phy.type == e1000_phy_gg82563) + e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC); + + ctrl_reg = er32(CTRL); + + if (adapter->hw.phy.type == e1000_phy_ife) { + /* force 100, set loopback */ + e1e_wphy(hw, PHY_CONTROL, 0x6100); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_100 |/* Force Speed to 100 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + } else { + /* force 1000, set loopback */ + e1e_wphy(hw, PHY_CONTROL, 0x4140); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg = er32(CTRL); + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + } + + if (adapter->hw.media_type == e1000_media_type_copper && + adapter->hw.phy.type == e1000_phy_m88) { + ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ + } else { + /* Set the ILOS bit on the fiber Nic if half duplex link is + * detected. */ + stat_reg = er32(STATUS); + if ((stat_reg & E1000_STATUS_FD) == 0) + ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); + } + + ew32(CTRL, ctrl_reg); + + /* Disable the receiver on the PHY so when a cable is plugged in, the + * PHY does not begin to autoneg when a cable is reconnected to the NIC. + */ + if (adapter->hw.phy.type == e1000_phy_m88) + e1000_phy_disable_receiver(adapter); + + udelay(500); + + return 0; +} + +static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl = er32(CTRL); + int link = 0; + + /* special requirements for 82571/82572 fiber adapters */ + + /* jump through hoops to make sure link is up because serdes + * link is hardwired up */ + ctrl |= E1000_CTRL_SLU; + ew32(CTRL, ctrl); + + /* disable autoneg */ + ctrl = er32(TXCW); + ctrl &= ~(1 << 31); + ew32(TXCW, ctrl); + + link = (er32(STATUS) & E1000_STATUS_LU); + + if (!link) { + /* set invert loss of signal */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_ILOS; + ew32(CTRL, ctrl); + } + + /* special write to serdes control register to enable SerDes analog + * loopback */ +#define E1000_SERDES_LB_ON 0x410 + ew32(SCTL, E1000_SERDES_LB_ON); + msleep(10); + + return 0; +} + +/* only call this for fiber/serdes connections to es2lan */ +static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrlext = er32(CTRL_EXT); + u32 ctrl = er32(CTRL); + + /* save CTRL_EXT to restore later, reuse an empty variable (unused + on mac_type 80003es2lan) */ + adapter->tx_fifo_head = ctrlext; + + /* clear the serdes mode bits, putting the device into mac loopback */ + ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; + ew32(CTRL_EXT, ctrlext); + + /* force speed to 1000/FD, link up */ + ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | + E1000_CTRL_SPD_1000 | E1000_CTRL_FD); + ew32(CTRL, ctrl); + + /* set mac loopback */ + ctrl = er32(RCTL); + ctrl |= E1000_RCTL_LBM_MAC; + ew32(RCTL, ctrl); + + /* set testing mode parameters (no need to reset later) */ +#define KMRNCTRLSTA_OPMODE (0x1F << 16) +#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582 + ew32(KMRNCTRLSTA, + (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII)); + + return 0; +} + +static int e1000_setup_loopback_test(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) { + switch (hw->mac.type) { + case e1000_80003es2lan: + return e1000_set_es2lan_mac_loopback(adapter); + break; + case e1000_82571: + case e1000_82572: + return e1000_set_82571_fiber_loopback(adapter); + break; + default: + rctl = er32(RCTL); + rctl |= E1000_RCTL_LBM_TCVR; + ew32(RCTL, rctl); + return 0; + } + } else if (hw->media_type == e1000_media_type_copper) { + return e1000_integrated_phy_loopback(adapter); + } + + return 7; +} + +static void e1000_loopback_cleanup(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + u16 phy_reg; + + rctl = er32(RCTL); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); + ew32(RCTL, rctl); + + switch (hw->mac.type) { + case e1000_80003es2lan: + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) { + /* restore CTRL_EXT, stealing space from tx_fifo_head */ + ew32(CTRL_EXT, + adapter->tx_fifo_head); + adapter->tx_fifo_head = 0; + } + /* fall through */ + case e1000_82571: + case e1000_82572: + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) { +#define E1000_SERDES_LB_OFF 0x400 + ew32(SCTL, E1000_SERDES_LB_OFF); + msleep(10); + break; + } + /* Fall Through */ + default: + hw->mac.autoneg = 1; + if (hw->phy.type == e1000_phy_gg82563) + e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180); + e1e_rphy(hw, PHY_CONTROL, &phy_reg); + if (phy_reg & MII_CR_LOOPBACK) { + phy_reg &= ~MII_CR_LOOPBACK; + e1e_wphy(hw, PHY_CONTROL, phy_reg); + e1000e_commit_phy(hw); + } + break; + } +} + +static void e1000_create_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size &= ~1; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int e1000_check_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + frame_size &= ~1; + if (*(skb->data + 3) == 0xFF) + if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) + return 0; + return 13; +} + +static int e1000_run_loopback_test(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_hw *hw = &adapter->hw; + int i, j, k, l; + int lc; + int good_cnt; + int ret_val = 0; + unsigned long time; + + ew32(RDT, rx_ring->count - 1); + + /* Calculate the loop count based on the largest descriptor ring + * The idea is to wrap the largest ring a number of times using 64 + * send/receive pairs during each loop + */ + + if (rx_ring->count <= tx_ring->count) + lc = ((tx_ring->count / 64) * 2) + 1; + else + lc = ((rx_ring->count / 64) * 2) + 1; + + k = 0; + l = 0; + for (j = 0; j <= lc; j++) { /* loop count loop */ + for (i = 0; i < 64; i++) { /* send the packets */ + e1000_create_lbtest_frame( + tx_ring->buffer_info[i].skb, 1024); + pci_dma_sync_single_for_device(pdev, + tx_ring->buffer_info[k].dma, + tx_ring->buffer_info[k].length, + PCI_DMA_TODEVICE); + k++; + if (k == tx_ring->count) + k = 0; + } + ew32(TDT, k); + msleep(200); + time = jiffies; /* set the start time for the receive */ + good_cnt = 0; + do { /* receive the sent packets */ + pci_dma_sync_single_for_cpu(pdev, + rx_ring->buffer_info[l].dma, 2048, + PCI_DMA_FROMDEVICE); + + ret_val = e1000_check_lbtest_frame( + rx_ring->buffer_info[l].skb, 1024); + if (!ret_val) + good_cnt++; + l++; + if (l == rx_ring->count) + l = 0; + /* time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's + * exceeded, break and error off + */ + } while ((good_cnt < 64) && !time_after(jiffies, time + 20)); + if (good_cnt != 64) { + ret_val = 13; /* ret_val is the same as mis-compare */ + break; + } + if (jiffies >= (time + 2)) { + ret_val = 14; /* error code for time out error */ + break; + } + } /* end loop count loop */ + return ret_val; +} + +static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data) +{ + /* PHY loopback cannot be performed if SoL/IDER + * sessions are active */ + if (e1000_check_reset_block(&adapter->hw)) { + ndev_err(adapter->netdev, "Cannot do PHY loopback test " + "when SoL/IDER is active.\n"); + *data = 0; + goto out; + } + + *data = e1000_setup_desc_rings(adapter); + if (data) + goto out; + + *data = e1000_setup_loopback_test(adapter); + if (data) + goto err_loopback; + + *data = e1000_run_loopback_test(adapter); + e1000_loopback_cleanup(adapter); + +err_loopback: + e1000_free_desc_rings(adapter); +out: + return *data; +} + +static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + + *data = 0; + if (hw->media_type == e1000_media_type_internal_serdes) { + int i = 0; + hw->mac.serdes_has_link = 0; + + /* On some blade server designs, link establishment + * could take as long as 2-3 minutes */ + do { + hw->mac.ops.check_for_link(hw); + if (hw->mac.serdes_has_link) + return *data; + msleep(20); + } while (i++ < 3750); + + *data = 1; + } else { + hw->mac.ops.check_for_link(hw); + if (hw->mac.autoneg) + msleep(4000); + + if (!(er32(STATUS) & + E1000_STATUS_LU)) + *data = 1; + } + return *data; +} + +static int e1000_diag_test_count(struct net_device *netdev) +{ + return E1000_TEST_LEN; +} + +static void e1000_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + u16 autoneg_advertised; + u8 forced_speed_duplex; + u8 autoneg; + bool if_running = netif_running(netdev); + + set_bit(__E1000_TESTING, &adapter->state); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + /* save speed, duplex, autoneg settings */ + autoneg_advertised = adapter->hw.phy.autoneg_advertised; + forced_speed_duplex = adapter->hw.mac.forced_speed_duplex; + autoneg = adapter->hw.mac.autoneg; + + ndev_info(netdev, "offline testing starting\n"); + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if (e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if (if_running) + /* indicate we're in test mode */ + dev_close(netdev); + else + e1000e_reset(adapter); + + if (e1000_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000e_reset(adapter); + if (e1000_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000e_reset(adapter); + if (e1000_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000e_reset(adapter); + /* make sure the phy is powered up */ + e1000e_power_up_phy(adapter); + if (e1000_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* restore speed, duplex, autoneg settings */ + adapter->hw.phy.autoneg_advertised = autoneg_advertised; + adapter->hw.mac.forced_speed_duplex = forced_speed_duplex; + adapter->hw.mac.autoneg = autoneg; + + /* force this routine to wait until autoneg complete/timeout */ + adapter->hw.phy.wait_for_link = 1; + e1000e_reset(adapter); + adapter->hw.phy.wait_for_link = 0; + + clear_bit(__E1000_TESTING, &adapter->state); + if (if_running) + dev_open(netdev); + } else { + ndev_info(netdev, "online testing starting\n"); + /* Online tests */ + if (e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Online tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + clear_bit(__E1000_TESTING, &adapter->state); + } + msleep_interruptible(4 * 1000); +} + +static void e1000_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + wol->supported = 0; + wol->wolopts = 0; + + if (!(adapter->flags & FLAG_HAS_WOL)) + return; + + wol->supported = WAKE_UCAST | WAKE_MCAST | + WAKE_BCAST | WAKE_MAGIC; + + /* apply any specific unsupported masks here */ + if (adapter->flags & FLAG_NO_WAKE_UCAST) { + wol->supported &= ~WAKE_UCAST; + + if (adapter->wol & E1000_WUFC_EX) + ndev_err(netdev, "Interface does not support " + "directed (unicast) frame wake-up packets\n"); + } + + if (adapter->wol & E1000_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & E1000_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & E1000_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & E1000_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; +} + +static int e1000_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + + if (!(adapter->flags & FLAG_HAS_WOL)) + return wol->wolopts ? -EOPNOTSUPP : 0; + + /* these settings will always override what we currently have */ + adapter->wol = 0; + + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= E1000_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= E1000_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= E1000_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= E1000_WUFC_MAG; + + return 0; +} + +/* toggle LED 4 times per second = 2 "blinks" per second */ +#define E1000_ID_INTERVAL (HZ/4) + +/* bit defines for adapter->led_status */ +#define E1000_LED_ON 0 + +static void e1000_led_blink_callback(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) + adapter->hw.mac.ops.led_off(&adapter->hw); + else + adapter->hw.mac.ops.led_on(&adapter->hw); + + mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); +} + +static int e1000_phys_id(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + + if (adapter->hw.phy.type == e1000_phy_ife) { + if (!adapter->blink_timer.function) { + init_timer(&adapter->blink_timer); + adapter->blink_timer.function = + e1000_led_blink_callback; + adapter->blink_timer.data = (unsigned long) adapter; + } + mod_timer(&adapter->blink_timer, jiffies); + msleep_interruptible(data * 1000); + del_timer_sync(&adapter->blink_timer); + e1e_wphy(&adapter->hw, + IFE_PHY_SPECIAL_CONTROL_LED, 0); + } else { + e1000e_blink_led(&adapter->hw); + msleep_interruptible(data * 1000); + } + + adapter->hw.mac.ops.led_off(&adapter->hw); + clear_bit(E1000_LED_ON, &adapter->led_status); + adapter->hw.mac.ops.cleanup_led(&adapter->hw); + + return 0; +} + +static int e1000_nway_reset(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + if (netif_running(netdev)) + e1000e_reinit_locked(adapter); + return 0; +} + +static int e1000_get_stats_count(struct net_device *netdev) +{ + return E1000_STATS_LEN; +} + +static void e1000_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, + u64 *data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + int i; + + e1000e_update_stats(adapter); + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } +} + +static void e1000_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *e1000_gstrings_test, + E1000_TEST_LEN*ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + memcpy(p, e1000_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static const struct ethtool_ops e1000_ethtool_ops = { + .get_settings = e1000_get_settings, + .set_settings = e1000_set_settings, + .get_drvinfo = e1000_get_drvinfo, + .get_regs_len = e1000_get_regs_len, + .get_regs = e1000_get_regs, + .get_wol = e1000_get_wol, + .set_wol = e1000_set_wol, + .get_msglevel = e1000_get_msglevel, + .set_msglevel = e1000_set_msglevel, + .nway_reset = e1000_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = e1000_get_eeprom_len, + .get_eeprom = e1000_get_eeprom, + .set_eeprom = e1000_set_eeprom, + .get_ringparam = e1000_get_ringparam, + .set_ringparam = e1000_set_ringparam, + .get_pauseparam = e1000_get_pauseparam, + .set_pauseparam = e1000_set_pauseparam, + .get_rx_csum = e1000_get_rx_csum, + .set_rx_csum = e1000_set_rx_csum, + .get_tx_csum = e1000_get_tx_csum, + .set_tx_csum = e1000_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = e1000_set_tso, + .self_test_count = e1000_diag_test_count, + .self_test = e1000_diag_test, + .get_strings = e1000_get_strings, + .phys_id = e1000_phys_id, + .get_stats_count = e1000_get_stats_count, + .get_ethtool_stats = e1000_get_ethtool_stats, +}; + +void e1000e_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops); +} diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h new file mode 100644 index 000000000000..848217a38259 --- /dev/null +++ b/drivers/net/e1000e/hw.h @@ -0,0 +1,864 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_HW_H_ +#define _E1000_HW_H_ + +#include + +struct e1000_hw; +struct e1000_adapter; + +#include "defines.h" + +#define er32(reg) __er32(hw, E1000_##reg) +#define ew32(reg,val) __ew32(hw, E1000_##reg, (val)) +#define e1e_flush() er32(STATUS) + +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \ + (writel((value), ((a)->hw_addr + reg + ((offset) << 2)))) + +#define E1000_READ_REG_ARRAY(a, reg, offset) \ + (readl((a)->hw_addr + reg + ((offset) << 2))) + +enum e1e_registers { + E1000_CTRL = 0x00000, /* Device Control - RW */ + E1000_STATUS = 0x00008, /* Device Status - RO */ + E1000_EECD = 0x00010, /* EEPROM/Flash Control - RW */ + E1000_EERD = 0x00014, /* EEPROM Read - RW */ + E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */ + E1000_FLA = 0x0001C, /* Flash Access - RW */ + E1000_MDIC = 0x00020, /* MDI Control - RW */ + E1000_SCTL = 0x00024, /* SerDes Control - RW */ + E1000_FCAL = 0x00028, /* Flow Control Address Low - RW */ + E1000_FCAH = 0x0002C, /* Flow Control Address High -RW */ + E1000_FEXTNVM = 0x00028, /* Future Extended NVM - RW */ + E1000_FCT = 0x00030, /* Flow Control Type - RW */ + E1000_VET = 0x00038, /* VLAN Ether Type - RW */ + E1000_ICR = 0x000C0, /* Interrupt Cause Read - R/clr */ + E1000_ITR = 0x000C4, /* Interrupt Throttling Rate - RW */ + E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */ + E1000_IMS = 0x000D0, /* Interrupt Mask Set - RW */ + E1000_IMC = 0x000D8, /* Interrupt Mask Clear - WO */ + E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */ + E1000_RCTL = 0x00100, /* RX Control - RW */ + E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */ + E1000_TXCW = 0x00178, /* TX Configuration Word - RW */ + E1000_RXCW = 0x00180, /* RX Configuration Word - RO */ + E1000_TCTL = 0x00400, /* TX Control - RW */ + E1000_TCTL_EXT = 0x00404, /* Extended TX Control - RW */ + E1000_TIPG = 0x00410, /* TX Inter-packet gap -RW */ + E1000_AIT = 0x00458, /* Adaptive Interframe Spacing Throttle - RW */ + E1000_LEDCTL = 0x00E00, /* LED Control - RW */ + E1000_EXTCNF_CTRL = 0x00F00, /* Extended Configuration Control */ + E1000_EXTCNF_SIZE = 0x00F08, /* Extended Configuration Size */ + E1000_PHY_CTRL = 0x00F10, /* PHY Control Register in CSR */ + E1000_PBA = 0x01000, /* Packet Buffer Allocation - RW */ + E1000_PBS = 0x01008, /* Packet Buffer Size */ + E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */ + E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */ + E1000_FLOP = 0x0103C, /* FLASH Opcode Register */ + E1000_ERT = 0x02008, /* Early Rx Threshold - RW */ + E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */ + E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */ + E1000_PSRCTL = 0x02170, /* Packet Split Receive Control - RW */ + E1000_RDBAL = 0x02800, /* RX Descriptor Base Address Low - RW */ + E1000_RDBAH = 0x02804, /* RX Descriptor Base Address High - RW */ + E1000_RDLEN = 0x02808, /* RX Descriptor Length - RW */ + E1000_RDH = 0x02810, /* RX Descriptor Head - RW */ + E1000_RDT = 0x02818, /* RX Descriptor Tail - RW */ + E1000_RDTR = 0x02820, /* RX Delay Timer - RW */ + E1000_RADV = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */ + +/* Convenience macros + * + * Note: "_n" is the queue number of the register to be written to. + * + * Example usage: + * E1000_RDBAL_REG(current_rx_queue) + * + */ +#define E1000_RDBAL_REG(_n) (E1000_RDBAL + (_n << 8)) + E1000_KABGTXD = 0x03004, /* AFE Band Gap Transmit Ref Data */ + E1000_TDBAL = 0x03800, /* TX Descriptor Base Address Low - RW */ + E1000_TDBAH = 0x03804, /* TX Descriptor Base Address High - RW */ + E1000_TDLEN = 0x03808, /* TX Descriptor Length - RW */ + E1000_TDH = 0x03810, /* TX Descriptor Head - RW */ + E1000_TDT = 0x03818, /* TX Descriptor Tail - RW */ + E1000_TIDV = 0x03820, /* TX Interrupt Delay Value - RW */ + E1000_TXDCTL = 0x03828, /* TX Descriptor Control - RW */ + E1000_TADV = 0x0382C, /* TX Interrupt Absolute Delay Val - RW */ + E1000_TARC0 = 0x03840, /* TX Arbitration Count (0) */ + E1000_TXDCTL1 = 0x03928, /* TX Descriptor Control (1) - RW */ + E1000_TARC1 = 0x03940, /* TX Arbitration Count (1) */ + E1000_CRCERRS = 0x04000, /* CRC Error Count - R/clr */ + E1000_ALGNERRC = 0x04004, /* Alignment Error Count - R/clr */ + E1000_SYMERRS = 0x04008, /* Symbol Error Count - R/clr */ + E1000_RXERRC = 0x0400C, /* Receive Error Count - R/clr */ + E1000_MPC = 0x04010, /* Missed Packet Count - R/clr */ + E1000_SCC = 0x04014, /* Single Collision Count - R/clr */ + E1000_ECOL = 0x04018, /* Excessive Collision Count - R/clr */ + E1000_MCC = 0x0401C, /* Multiple Collision Count - R/clr */ + E1000_LATECOL = 0x04020, /* Late Collision Count - R/clr */ + E1000_COLC = 0x04028, /* Collision Count - R/clr */ + E1000_DC = 0x04030, /* Defer Count - R/clr */ + E1000_TNCRS = 0x04034, /* TX-No CRS - R/clr */ + E1000_SEC = 0x04038, /* Sequence Error Count - R/clr */ + E1000_CEXTERR = 0x0403C, /* Carrier Extension Error Count - R/clr */ + E1000_RLEC = 0x04040, /* Receive Length Error Count - R/clr */ + E1000_XONRXC = 0x04048, /* XON RX Count - R/clr */ + E1000_XONTXC = 0x0404C, /* XON TX Count - R/clr */ + E1000_XOFFRXC = 0x04050, /* XOFF RX Count - R/clr */ + E1000_XOFFTXC = 0x04054, /* XOFF TX Count - R/clr */ + E1000_FCRUC = 0x04058, /* Flow Control RX Unsupported Count- R/clr */ + E1000_PRC64 = 0x0405C, /* Packets RX (64 bytes) - R/clr */ + E1000_PRC127 = 0x04060, /* Packets RX (65-127 bytes) - R/clr */ + E1000_PRC255 = 0x04064, /* Packets RX (128-255 bytes) - R/clr */ + E1000_PRC511 = 0x04068, /* Packets RX (255-511 bytes) - R/clr */ + E1000_PRC1023 = 0x0406C, /* Packets RX (512-1023 bytes) - R/clr */ + E1000_PRC1522 = 0x04070, /* Packets RX (1024-1522 bytes) - R/clr */ + E1000_GPRC = 0x04074, /* Good Packets RX Count - R/clr */ + E1000_BPRC = 0x04078, /* Broadcast Packets RX Count - R/clr */ + E1000_MPRC = 0x0407C, /* Multicast Packets RX Count - R/clr */ + E1000_GPTC = 0x04080, /* Good Packets TX Count - R/clr */ + E1000_GORCL = 0x04088, /* Good Octets RX Count Low - R/clr */ + E1000_GORCH = 0x0408C, /* Good Octets RX Count High - R/clr */ + E1000_GOTCL = 0x04090, /* Good Octets TX Count Low - R/clr */ + E1000_GOTCH = 0x04094, /* Good Octets TX Count High - R/clr */ + E1000_RNBC = 0x040A0, /* RX No Buffers Count - R/clr */ + E1000_RUC = 0x040A4, /* RX Undersize Count - R/clr */ + E1000_RFC = 0x040A8, /* RX Fragment Count - R/clr */ + E1000_ROC = 0x040AC, /* RX Oversize Count - R/clr */ + E1000_RJC = 0x040B0, /* RX Jabber Count - R/clr */ + E1000_MGTPRC = 0x040B4, /* Management Packets RX Count - R/clr */ + E1000_MGTPDC = 0x040B8, /* Management Packets Dropped Count - R/clr */ + E1000_MGTPTC = 0x040BC, /* Management Packets TX Count - R/clr */ + E1000_TORL = 0x040C0, /* Total Octets RX Low - R/clr */ + E1000_TORH = 0x040C4, /* Total Octets RX High - R/clr */ + E1000_TOTL = 0x040C8, /* Total Octets TX Low - R/clr */ + E1000_TOTH = 0x040CC, /* Total Octets TX High - R/clr */ + E1000_TPR = 0x040D0, /* Total Packets RX - R/clr */ + E1000_TPT = 0x040D4, /* Total Packets TX - R/clr */ + E1000_PTC64 = 0x040D8, /* Packets TX (64 bytes) - R/clr */ + E1000_PTC127 = 0x040DC, /* Packets TX (65-127 bytes) - R/clr */ + E1000_PTC255 = 0x040E0, /* Packets TX (128-255 bytes) - R/clr */ + E1000_PTC511 = 0x040E4, /* Packets TX (256-511 bytes) - R/clr */ + E1000_PTC1023 = 0x040E8, /* Packets TX (512-1023 bytes) - R/clr */ + E1000_PTC1522 = 0x040EC, /* Packets TX (1024-1522 Bytes) - R/clr */ + E1000_MPTC = 0x040F0, /* Multicast Packets TX Count - R/clr */ + E1000_BPTC = 0x040F4, /* Broadcast Packets TX Count - R/clr */ + E1000_TSCTC = 0x040F8, /* TCP Segmentation Context TX - R/clr */ + E1000_TSCTFC = 0x040FC, /* TCP Segmentation Context TX Fail - R/clr */ + E1000_IAC = 0x04100, /* Interrupt Assertion Count */ + E1000_ICRXPTC = 0x04104, /* Irq Cause Rx Packet Timer Expire Count */ + E1000_ICRXATC = 0x04108, /* Irq Cause Rx Abs Timer Expire Count */ + E1000_ICTXPTC = 0x0410C, /* Irq Cause Tx Packet Timer Expire Count */ + E1000_ICTXATC = 0x04110, /* Irq Cause Tx Abs Timer Expire Count */ + E1000_ICTXQEC = 0x04118, /* Irq Cause Tx Queue Empty Count */ + E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */ + E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */ + E1000_ICRXOC = 0x04124, /* Irq Cause Receiver Overrun Count */ + E1000_RXCSUM = 0x05000, /* RX Checksum Control - RW */ + E1000_RFCTL = 0x05008, /* Receive Filter Control*/ + E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */ + E1000_RA = 0x05400, /* Receive Address - RW Array */ + E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */ + E1000_WUC = 0x05800, /* Wakeup Control - RW */ + E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */ + E1000_WUS = 0x05810, /* Wakeup Status - RO */ + E1000_MANC = 0x05820, /* Management Control - RW */ + E1000_FFLT = 0x05F00, /* Flexible Filter Length Table - RW Array */ + E1000_HOST_IF = 0x08800, /* Host Interface */ + + E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */ + E1000_MANC2H = 0x05860, /* Management Control To Host - RW */ + E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */ + E1000_GCR = 0x05B00, /* PCI-Ex Control */ + E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ + E1000_SWSM = 0x05B50, /* SW Semaphore */ + E1000_FWSM = 0x05B54, /* FW Semaphore */ + E1000_HICR = 0x08F00, /* Host Inteface Control */ +}; + +/* RSS registers */ + +/* IGP01E1000 Specific Registers */ +#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ +#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */ +#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */ +#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */ +#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */ +#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ + +#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 +#define IGP01E1000_PHY_POLARITY_MASK 0x0078 + +#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 +#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */ + +#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 + +#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */ +#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ +#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ + +#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 + +#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 +#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_SPEED_MASK 0xC000 +#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 + +#define IGP02E1000_PHY_CHANNEL_NUM 4 +#define IGP02E1000_PHY_AGC_A 0x11B1 +#define IGP02E1000_PHY_AGC_B 0x12B1 +#define IGP02E1000_PHY_AGC_C 0x14B1 +#define IGP02E1000_PHY_AGC_D 0x18B1 + +#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */ +#define IGP02E1000_AGC_LENGTH_MASK 0x7F +#define IGP02E1000_AGC_RANGE 15 + +/* manage.c */ +#define E1000_VFTA_ENTRY_SHIFT 5 +#define E1000_VFTA_ENTRY_MASK 0x7F +#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F + +#define E1000_HICR_EN 0x01 /* Enable bit - RO */ +#define E1000_HICR_C 0x02 /* Driver sets this bit when done + * to put command in RAM */ +#define E1000_HICR_FW_RESET_ENABLE 0x40 +#define E1000_HICR_FW_RESET 0x80 + +#define E1000_FWSM_MODE_MASK 0xE +#define E1000_FWSM_MODE_SHIFT 1 + +#define E1000_MNG_IAMT_MODE 0x3 +#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 +#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 +#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 +#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64 +#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1 +#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 + +/* nvm.c */ +#define E1000_STM_OPCODE 0xDB00 + +#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 +#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 +#define E1000_KMRNCTRLSTA_REN 0x00200000 +#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ +#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ + +#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 +#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ +#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */ +#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */ + +/* IFE PHY Extended Status Control */ +#define IFE_PESC_POLARITY_REVERSED 0x0100 + +/* IFE PHY Special Control */ +#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 +#define IFE_PSC_FORCE_POLARITY 0x0020 + +/* IFE PHY Special Control and LED Control */ +#define IFE_PSCL_PROBE_MODE 0x0020 +#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ +#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ + +/* IFE PHY MDIX Control */ +#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ +#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */ +#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */ + +#define E1000_CABLE_LENGTH_UNDEFINED 0xFF + +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 +#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F +#define E1000_DEV_ID_82572EI 0x10B9 +#define E1000_DEV_ID_82573E 0x108B +#define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A + +#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 +#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 +#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA +#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB + +#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 +#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A +#define E1000_DEV_ID_ICH8_IGP_C 0x104B +#define E1000_DEV_ID_ICH8_IFE 0x104C +#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4 +#define E1000_DEV_ID_ICH8_IFE_G 0x10C5 +#define E1000_DEV_ID_ICH8_IGP_M 0x104D +#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD +#define E1000_DEV_ID_ICH9_IGP_C 0x294C +#define E1000_DEV_ID_ICH9_IFE 0x10C0 +#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3 +#define E1000_DEV_ID_ICH9_IFE_G 0x10C2 + +#define E1000_FUNC_1 1 + +enum e1000_mac_type { + e1000_82571, + e1000_82572, + e1000_82573, + e1000_80003es2lan, + e1000_ich8lan, + e1000_ich9lan, +}; + +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_num_media_types +}; + +enum e1000_nvm_type { + e1000_nvm_unknown = 0, + e1000_nvm_none, + e1000_nvm_eeprom_spi, + e1000_nvm_flash_hw, + e1000_nvm_flash_sw +}; + +enum e1000_nvm_override { + e1000_nvm_override_none = 0, + e1000_nvm_override_spi_small, + e1000_nvm_override_spi_large +}; + +enum e1000_phy_type { + e1000_phy_unknown = 0, + e1000_phy_none, + e1000_phy_m88, + e1000_phy_igp, + e1000_phy_igp_2, + e1000_phy_gg82563, + e1000_phy_igp_3, + e1000_phy_ife, +}; + +enum e1000_bus_width { + e1000_bus_width_unknown = 0, + e1000_bus_width_pcie_x1, + e1000_bus_width_pcie_x2, + e1000_bus_width_pcie_x4 = 4, + e1000_bus_width_32, + e1000_bus_width_64, + e1000_bus_width_reserved +}; + +enum e1000_1000t_rx_status { + e1000_1000t_rx_status_not_ok = 0, + e1000_1000t_rx_status_ok, + e1000_1000t_rx_status_undefined = 0xFF +}; + +enum e1000_rev_polarity{ + e1000_rev_polarity_normal = 0, + e1000_rev_polarity_reversed, + e1000_rev_polarity_undefined = 0xFF +}; + +enum e1000_fc_mode { + e1000_fc_none = 0, + e1000_fc_rx_pause, + e1000_fc_tx_pause, + e1000_fc_full, + e1000_fc_default = 0xFF +}; + +enum e1000_ms_type { + e1000_ms_hw_default = 0, + e1000_ms_force_master, + e1000_ms_force_slave, + e1000_ms_auto +}; + +enum e1000_smart_speed { + e1000_smart_speed_default = 0, + e1000_smart_speed_on, + e1000_smart_speed_off +}; + +/* Receive Descriptor */ +struct e1000_rx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + u16 length; /* Length of data DMAed into data buffer */ + u16 csum; /* Packet checksum */ + u8 status; /* Descriptor status */ + u8 errors; /* Descriptor Errors */ + u16 special; +}; + +/* Receive Descriptor - Extended */ +union e1000_rx_desc_extended { + struct { + u64 buffer_addr; + u64 reserved; + } read; + struct { + struct { + u32 mrq; /* Multiple Rx Queues */ + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length; + u16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +#define MAX_PS_BUFFERS 4 +/* Receive Descriptor - Packet Split */ +union e1000_rx_desc_packet_split { + struct { + /* one buffer for protocol header(s), three data buffers */ + u64 buffer_addr[MAX_PS_BUFFERS]; + } read; + struct { + struct { + u32 mrq; /* Multiple Rx Queues */ + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length0; /* length of buffer 0 */ + u16 vlan; /* VLAN tag */ + } middle; + struct { + u16 header_status; + u16 length[3]; /* length of buffers 1-3 */ + } upper; + u64 reserved; + } wb; /* writeback */ +}; + +/* Transmit Descriptor */ +struct e1000_tx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 cso; /* Checksum offset */ + u8 cmd; /* Descriptor control */ + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 css; /* Checksum start */ + u16 special; + } fields; + } upper; +}; + +/* Offload Context Descriptor */ +struct e1000_context_desc { + union { + u32 ip_config; + struct { + u8 ipcss; /* IP checksum start */ + u8 ipcso; /* IP checksum offset */ + u16 ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + u32 tcp_config; + struct { + u8 tucss; /* TCP checksum start */ + u8 tucso; /* TCP checksum offset */ + u16 tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + u32 cmd_and_length; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 hdr_len; /* Header length */ + u16 mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct e1000_data_desc { + u64 buffer_addr; /* Address of the descriptor's buffer address */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 typ_len_ext; + u8 cmd; + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 popts; /* Packet Options */ + u16 special; /* */ + } fields; + } upper; +}; + +/* Statistics counters collected by the MAC */ +struct e1000_hw_stats { + u64 crcerrs; + u64 algnerrc; + u64 symerrs; + u64 rxerrc; + u64 mpc; + u64 scc; + u64 ecol; + u64 mcc; + u64 latecol; + u64 colc; + u64 dc; + u64 tncrs; + u64 sec; + u64 cexterr; + u64 rlec; + u64 xonrxc; + u64 xontxc; + u64 xoffrxc; + u64 xofftxc; + u64 fcruc; + u64 prc64; + u64 prc127; + u64 prc255; + u64 prc511; + u64 prc1023; + u64 prc1522; + u64 gprc; + u64 bprc; + u64 mprc; + u64 gptc; + u64 gorcl; + u64 gorch; + u64 gotcl; + u64 gotch; + u64 rnbc; + u64 ruc; + u64 rfc; + u64 roc; + u64 rjc; + u64 mgprc; + u64 mgpdc; + u64 mgptc; + u64 torl; + u64 torh; + u64 totl; + u64 toth; + u64 tpr; + u64 tpt; + u64 ptc64; + u64 ptc127; + u64 ptc255; + u64 ptc511; + u64 ptc1023; + u64 ptc1522; + u64 mptc; + u64 bptc; + u64 tsctc; + u64 tsctfc; + u64 iac; + u64 icrxptc; + u64 icrxatc; + u64 ictxptc; + u64 ictxatc; + u64 ictxqec; + u64 ictxqmtc; + u64 icrxdmtc; + u64 icrxoc; +}; + +struct e1000_phy_stats { + u32 idle_errors; + u32 receive_errors; +}; + +struct e1000_host_mng_dhcp_cookie { + u32 signature; + u8 status; + u8 reserved0; + u16 vlan_id; + u32 reserved1; + u16 reserved2; + u8 reserved3; + u8 checksum; +}; + +/* Host Interface "Rev 1" */ +struct e1000_host_command_header { + u8 command_id; + u8 command_length; + u8 command_options; + u8 checksum; +}; + +#define E1000_HI_MAX_DATA_LENGTH 252 +struct e1000_host_command_info { + struct e1000_host_command_header command_header; + u8 command_data[E1000_HI_MAX_DATA_LENGTH]; +}; + +/* Host Interface "Rev 2" */ +struct e1000_host_mng_command_header { + u8 command_id; + u8 checksum; + u16 reserved1; + u16 reserved2; + u16 command_length; +}; + +#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 +struct e1000_host_mng_command_info { + struct e1000_host_mng_command_header command_header; + u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; +}; + +/* Function pointers and static data for the MAC. */ +struct e1000_mac_operations { + u32 mng_mode_enab; + + s32 (*check_for_link)(struct e1000_hw *); + s32 (*cleanup_led)(struct e1000_hw *); + void (*clear_hw_cntrs)(struct e1000_hw *); + s32 (*get_bus_info)(struct e1000_hw *); + s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); + s32 (*led_on)(struct e1000_hw *); + s32 (*led_off)(struct e1000_hw *); + void (*mc_addr_list_update)(struct e1000_hw *, u8 *, u32, u32, + u32); + s32 (*reset_hw)(struct e1000_hw *); + s32 (*init_hw)(struct e1000_hw *); + s32 (*setup_link)(struct e1000_hw *); + s32 (*setup_physical_interface)(struct e1000_hw *); +}; + +/* Function pointers for the PHY. */ +struct e1000_phy_operations { + s32 (*acquire_phy)(struct e1000_hw *); + s32 (*check_reset_block)(struct e1000_hw *); + s32 (*commit_phy)(struct e1000_hw *); + s32 (*force_speed_duplex)(struct e1000_hw *); + s32 (*get_cfg_done)(struct e1000_hw *hw); + s32 (*get_cable_length)(struct e1000_hw *); + s32 (*get_phy_info)(struct e1000_hw *); + s32 (*read_phy_reg)(struct e1000_hw *, u32, u16 *); + void (*release_phy)(struct e1000_hw *); + s32 (*reset_phy)(struct e1000_hw *); + s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); + s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); + s32 (*write_phy_reg)(struct e1000_hw *, u32, u16); +}; + +/* Function pointers for the NVM. */ +struct e1000_nvm_operations { + s32 (*acquire_nvm)(struct e1000_hw *); + s32 (*read_nvm)(struct e1000_hw *, u16, u16, u16 *); + void (*release_nvm)(struct e1000_hw *); + s32 (*update_nvm)(struct e1000_hw *); + s32 (*valid_led_default)(struct e1000_hw *, u16 *); + s32 (*validate_nvm)(struct e1000_hw *); + s32 (*write_nvm)(struct e1000_hw *, u16, u16, u16 *); +}; + +struct e1000_mac_info { + struct e1000_mac_operations ops; + + u8 addr[6]; + u8 perm_addr[6]; + + enum e1000_mac_type type; + enum e1000_fc_mode fc; + enum e1000_fc_mode original_fc; + + u32 collision_delta; + u32 ledctl_default; + u32 ledctl_mode1; + u32 ledctl_mode2; + u32 max_frame_size; + u32 mc_filter_type; + u32 min_frame_size; + u32 tx_packet_delta; + u32 txcw; + + u16 current_ifs_val; + u16 ifs_max_val; + u16 ifs_min_val; + u16 ifs_ratio; + u16 ifs_step_size; + u16 mta_reg_count; + u16 rar_entry_count; + u16 fc_high_water; + u16 fc_low_water; + u16 fc_pause_time; + + u8 forced_speed_duplex; + + bool arc_subsystem_valid; + bool autoneg; + bool autoneg_failed; + bool get_link_status; + bool in_ifs_mode; + bool serdes_has_link; + bool tx_pkt_filtering; +}; + +struct e1000_phy_info { + struct e1000_phy_operations ops; + + enum e1000_phy_type type; + + enum e1000_1000t_rx_status local_rx; + enum e1000_1000t_rx_status remote_rx; + enum e1000_ms_type ms_type; + enum e1000_ms_type original_ms_type; + enum e1000_rev_polarity cable_polarity; + enum e1000_smart_speed smart_speed; + + u32 addr; + u32 id; + u32 reset_delay_us; /* in usec */ + u32 revision; + + u16 autoneg_advertised; + u16 autoneg_mask; + u16 cable_length; + u16 max_cable_length; + u16 min_cable_length; + + u8 mdix; + + bool disable_polarity_correction; + bool is_mdix; + bool polarity_correction; + bool speed_downgraded; + bool wait_for_link; +}; + +struct e1000_nvm_info { + struct e1000_nvm_operations ops; + + enum e1000_nvm_type type; + enum e1000_nvm_override override; + + u32 flash_bank_size; + u32 flash_base_addr; + + u16 word_size; + u16 delay_usec; + u16 address_bits; + u16 opcode_bits; + u16 page_size; +}; + +struct e1000_bus_info { + enum e1000_bus_width width; + + u16 func; +}; + +struct e1000_dev_spec_82571 { + bool laa_is_present; +}; + +struct e1000_shadow_ram { + u16 value; + bool modified; +}; + +#define E1000_ICH8_SHADOW_RAM_WORDS 2048 + +struct e1000_dev_spec_ich8lan { + bool kmrn_lock_loss_workaround_enabled; + struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS]; +}; + +struct e1000_hw { + struct e1000_adapter *adapter; + + u8 __iomem *hw_addr; + u8 __iomem *flash_address; + + struct e1000_mac_info mac; + struct e1000_phy_info phy; + struct e1000_nvm_info nvm; + struct e1000_bus_info bus; + struct e1000_host_mng_dhcp_cookie mng_cookie; + + union { + struct e1000_dev_spec_82571 e82571; + struct e1000_dev_spec_ich8lan ich8lan; + } dev_spec; + + enum e1000_media_type media_type; +}; + +#ifdef DEBUG +#define hw_dbg(hw, format, arg...) \ + printk(KERN_DEBUG, "%s: " format, e1000_get_hw_dev_name(hw), ##arg); +#else +static inline int __attribute__ ((format (printf, 2, 3))) +hw_dbg(struct e1000_hw *hw, const char *format, ...) +{ + return 0; +} +#endif + +#endif diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c new file mode 100644 index 000000000000..8f8139de1f48 --- /dev/null +++ b/drivers/net/e1000e/ich8lan.c @@ -0,0 +1,2225 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * 82562G-2 10/100 Network Connection + * 82562GT 10/100 Network Connection + * 82562GT-2 10/100 Network Connection + * 82562V 10/100 Network Connection + * 82562V-2 10/100 Network Connection + * 82566DC-2 Gigabit Network Connection + * 82566DC Gigabit Network Connection + * 82566DM-2 Gigabit Network Connection + * 82566DM Gigabit Network Connection + * 82566MC Gigabit Network Connection + * 82566MM Gigabit Network Connection + */ + +#include +#include +#include +#include + +#include "e1000.h" + +#define ICH_FLASH_GFPREG 0x0000 +#define ICH_FLASH_HSFSTS 0x0004 +#define ICH_FLASH_HSFCTL 0x0006 +#define ICH_FLASH_FADDR 0x0008 +#define ICH_FLASH_FDATA0 0x0010 + +#define ICH_FLASH_READ_COMMAND_TIMEOUT 500 +#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500 +#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 3000000 +#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF +#define ICH_FLASH_CYCLE_REPEAT_COUNT 10 + +#define ICH_CYCLE_READ 0 +#define ICH_CYCLE_WRITE 2 +#define ICH_CYCLE_ERASE 3 + +#define FLASH_GFPREG_BASE_MASK 0x1FFF +#define FLASH_SECTOR_ADDR_SHIFT 12 + +#define ICH_FLASH_SEG_SIZE_256 256 +#define ICH_FLASH_SEG_SIZE_4K 4096 +#define ICH_FLASH_SEG_SIZE_8K 8192 +#define ICH_FLASH_SEG_SIZE_64K 65536 + + +#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */ + +#define E1000_ICH_MNG_IAMT_MODE 0x2 + +#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_DEF1_OFF2 << 8) | \ + (ID_LED_DEF1_ON2 << 4) | \ + (ID_LED_DEF1_DEF2)) + +#define E1000_ICH_NVM_SIG_WORD 0x13 +#define E1000_ICH_NVM_SIG_MASK 0xC000 + +#define E1000_ICH8_LAN_INIT_TIMEOUT 1500 + +#define E1000_FEXTNVM_SW_CONFIG 1 +#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */ + +#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL + +#define E1000_ICH_RAR_ENTRIES 7 + +#define PHY_PAGE_SHIFT 5 +#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ + ((reg) & MAX_PHY_REG_ADDRESS)) +#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */ +#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */ + +#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 +#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300 +#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 + +/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ +/* Offset 04h HSFSTS */ +union ich8_hws_flash_status { + struct ich8_hsfsts { + u16 flcdone :1; /* bit 0 Flash Cycle Done */ + u16 flcerr :1; /* bit 1 Flash Cycle Error */ + u16 dael :1; /* bit 2 Direct Access error Log */ + u16 berasesz :2; /* bit 4:3 Sector Erase Size */ + u16 flcinprog :1; /* bit 5 flash cycle in Progress */ + u16 reserved1 :2; /* bit 13:6 Reserved */ + u16 reserved2 :6; /* bit 13:6 Reserved */ + u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */ + u16 flockdn :1; /* bit 15 Flash Config Lock-Down */ + } hsf_status; + u16 regval; +}; + +/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ +/* Offset 06h FLCTL */ +union ich8_hws_flash_ctrl { + struct ich8_hsflctl { + u16 flcgo :1; /* 0 Flash Cycle Go */ + u16 flcycle :2; /* 2:1 Flash Cycle */ + u16 reserved :5; /* 7:3 Reserved */ + u16 fldbcount :2; /* 9:8 Flash Data Byte Count */ + u16 flockdn :6; /* 15:10 Reserved */ + } hsf_ctrl; + u16 regval; +}; + +/* ICH Flash Region Access Permissions */ +union ich8_hws_flash_regacc { + struct ich8_flracc { + u32 grra :8; /* 0:7 GbE region Read Access */ + u32 grwa :8; /* 8:15 GbE region Write Access */ + u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */ + u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */ + } hsf_flregacc; + u16 regval; +}; + +static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); +static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); +static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); +static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw); +static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); +static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8 byte); +static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, + u16 *data); +static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 *data); +static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); +static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); + +static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) +{ + return readw(hw->flash_address + reg); +} + +static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg) +{ + return readl(hw->flash_address + reg); +} + +static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val) +{ + writew(val, hw->flash_address + reg); +} + +static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) +{ + writel(val, hw->flash_address + reg); +} + +#define er16flash(reg) __er16flash(hw, (reg)) +#define er32flash(reg) __er32flash(hw, (reg)) +#define ew16flash(reg,val) __ew16flash(hw, (reg), (val)) +#define ew32flash(reg,val) __ew32flash(hw, (reg), (val)) + +/** + * e1000_init_phy_params_ich8lan - Initialize PHY function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific PHY parameters and function pointers. + **/ +static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 i = 0; + + phy->addr = 1; + phy->reset_delay_us = 100; + + phy->id = 0; + while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) && + (i++ < 100)) { + msleep(1); + ret_val = e1000e_get_phy_id(hw); + if (ret_val) + return ret_val; + } + + /* Verify phy id */ + switch (phy->id) { + case IGP03E1000_E_PHY_ID: + phy->type = e1000_phy_igp_3; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + break; + case IFE_E_PHY_ID: + case IFE_PLUS_E_PHY_ID: + case IFE_C_E_PHY_ID: + phy->type = e1000_phy_ife; + phy->autoneg_mask = E1000_ALL_NOT_GIG; + break; + default: + return -E1000_ERR_PHY; + break; + } + + return 0; +} + +/** + * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific NVM parameters and function + * pointers. + **/ +static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 gfpreg; + u32 sector_base_addr; + u32 sector_end_addr; + u16 i; + + /* Can't read flash registers if the register set isn't mapped. + */ + if (!hw->flash_address) { + hw_dbg(hw, "ERROR: Flash registers not mapped\n"); + return -E1000_ERR_CONFIG; + } + + nvm->type = e1000_nvm_flash_sw; + + gfpreg = er32flash(ICH_FLASH_GFPREG); + + /* sector_X_addr is a "sector"-aligned address (4096 bytes) + * Add 1 to sector_end_addr since this sector is included in + * the overall size. */ + sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; + sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; + + /* flash_base_addr is byte-aligned */ + nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; + + /* find total size of the NVM, then cut in half since the total + * size represents two separate NVM banks. */ + nvm->flash_bank_size = (sector_end_addr - sector_base_addr) + << FLASH_SECTOR_ADDR_SHIFT; + nvm->flash_bank_size /= 2; + /* Adjust to word count */ + nvm->flash_bank_size /= sizeof(u16); + + nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS; + + /* Clear shadow ram */ + for (i = 0; i < nvm->word_size; i++) { + dev_spec->shadow_ram[i].modified = 0; + dev_spec->shadow_ram[i].value = 0xFFFF; + } + + return 0; +} + +/** + * e1000_init_mac_params_ich8lan - Initialize MAC function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific MAC parameters and function + * pointers. + **/ +static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + + /* Set media type function pointer */ + hw->media_type = e1000_media_type_copper; + + /* Set mta register count */ + mac->mta_reg_count = 32; + /* Set rar entry count */ + mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; + if (mac->type == e1000_ich8lan) + mac->rar_entry_count--; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = 1; + + /* Enable PCS Lock-loss workaround for ICH8 */ + if (mac->type == e1000_ich8lan) + e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1); + + return 0; +} + +static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + s32 rc; + + rc = e1000_init_mac_params_ich8lan(adapter); + if (rc) + return rc; + + rc = e1000_init_nvm_params_ich8lan(hw); + if (rc) + return rc; + + rc = e1000_init_phy_params_ich8lan(hw); + if (rc) + return rc; + + if ((adapter->hw.mac.type == e1000_ich8lan) && + (adapter->hw.phy.type == e1000_phy_igp_3)) + adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; + + return 0; +} + +/** + * e1000_acquire_swflag_ich8lan - Acquire software control flag + * @hw: pointer to the HW structure + * + * Acquires the software control flag for performing NVM and PHY + * operations. This is a function pointer entry point only called by + * read/write routines for the PHY and NVM parts. + **/ +static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) +{ + u32 extcnf_ctrl; + u32 timeout = PHY_CFG_TIMEOUT; + + while (timeout) { + extcnf_ctrl = er32(EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + ew32(EXTCNF_CTRL, extcnf_ctrl); + + extcnf_ctrl = er32(EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + mdelay(1); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "FW or HW has locked the resource for too long.\n"); + return -E1000_ERR_CONFIG; + } + + return 0; +} + +/** + * e1000_release_swflag_ich8lan - Release software control flag + * @hw: pointer to the HW structure + * + * Releases the software control flag for performing NVM and PHY operations. + * This is a function pointer entry point only called by read/write + * routines for the PHY and NVM parts. + **/ +static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) +{ + u32 extcnf_ctrl; + + extcnf_ctrl = er32(EXTCNF_CTRL); + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + ew32(EXTCNF_CTRL, extcnf_ctrl); +} + +/** + * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * + * Checks if firmware is blocking the reset of the PHY. + * This is a function pointer entry point only called by + * reset routines. + **/ +static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) +{ + u32 fwsm; + + fwsm = er32(FWSM); + + return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET; +} + +/** + * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex + * @hw: pointer to the HW structure + * + * Forces the speed and duplex settings of the PHY. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + if (phy->type != e1000_phy_ife) { + ret_val = e1000e_phy_force_speed_duplex_igp(hw); + return ret_val; + } + + ret_val = e1e_rphy(hw, PHY_CONTROL, &data); + if (ret_val) + return ret_val; + + e1000e_phy_force_speed_duplex_setup(hw, &data); + + ret_val = e1e_wphy(hw, PHY_CONTROL, data); + if (ret_val) + return ret_val; + + /* Disable MDI-X support for 10/100 */ + ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + return ret_val; + + data &= ~IFE_PMC_AUTO_MDIX; + data &= ~IFE_PMC_FORCE_MDIX; + + ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data); + if (ret_val) + return ret_val; + + hw_dbg(hw, "IFE PMC: %X\n", data); + + udelay(1); + + if (phy->wait_for_link) { + hw_dbg(hw, "Waiting for forced speed/duplex link on IFE phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + return ret_val; + + if (!link) + hw_dbg(hw, "Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + return ret_val; + } + + return 0; +} + +/** + * e1000_phy_hw_reset_ich8lan - Performs a PHY reset + * @hw: pointer to the HW structure + * + * Resets the PHY + * This is a function pointer entry point called by drivers + * or other shared routines. + **/ +static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i; + u32 data, cnf_size, cnf_base_addr, sw_cfg_mask; + s32 ret_val; + u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT; + u16 word_addr, reg_data, reg_addr, phy_page = 0; + + ret_val = e1000e_phy_hw_reset_generic(hw); + if (ret_val) + return ret_val; + + /* Initialize the PHY from the NVM on ICH platforms. This + * is needed due to an issue where the NVM configuration is + * not properly autoloaded after power transitions. + * Therefore, after each PHY reset, we will load the + * configuration data out of the NVM manually. + */ + if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { + struct e1000_adapter *adapter = hw->adapter; + + /* Check if SW needs configure the PHY */ + if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) || + (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M)) + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; + else + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; + + data = er32(FEXTNVM); + if (!(data & sw_cfg_mask)) + return 0; + + /* Wait for basic configuration completes before proceeding*/ + do { + data = er32(STATUS); + data &= E1000_STATUS_LAN_INIT_DONE; + udelay(100); + } while ((!data) && --loop); + + /* If basic configuration is incomplete before the above loop + * count reaches 0, loading the configuration from NVM will + * leave the PHY in a bad state possibly resulting in no link. + */ + if (loop == 0) { + hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n"); + } + + /* Clear the Init Done bit for the next init event */ + data = er32(STATUS); + data &= ~E1000_STATUS_LAN_INIT_DONE; + ew32(STATUS, data); + + /* Make sure HW does not configure LCD from PHY + * extended configuration before SW configuration */ + data = er32(EXTCNF_CTRL); + if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) + return 0; + + cnf_size = er32(EXTCNF_SIZE); + cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; + cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; + if (!cnf_size) + return 0; + + cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; + cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; + + /* Configure LCD from extended configuration + * region. */ + + /* cnf_base_addr is in DWORD */ + word_addr = (u16)(cnf_base_addr << 1); + + for (i = 0; i < cnf_size; i++) { + ret_val = e1000_read_nvm(hw, + (word_addr + i * 2), + 1, + ®_data); + if (ret_val) + return ret_val; + + ret_val = e1000_read_nvm(hw, + (word_addr + i * 2 + 1), + 1, + ®_addr); + if (ret_val) + return ret_val; + + /* Save off the PHY page for future writes. */ + if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { + phy_page = reg_data; + continue; + } + + reg_addr |= phy_page; + + ret_val = e1e_wphy(hw, (u32)reg_addr, reg_data); + if (ret_val) + return ret_val; + } + } + + return 0; +} + +/** + * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states + * @hw: pointer to the HW structure + * + * Populates "phy" structure with various feature states. + * This function is only called by other family-specific + * routines. + **/ +static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } + + ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data); + if (ret_val) + return ret_val; + phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE)); + + if (phy->polarity_correction) { + ret_val = e1000_check_polarity_ife_ich8lan(hw); + if (ret_val) + return ret_val; + } else { + /* Polarity is forced */ + phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + } + + ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + return ret_val; + + phy->is_mdix = (data & IFE_PMC_MDIX_STATUS); + + /* The following parameters are undefined for 10/100 operation. */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + + return 0; +} + +/** + * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info + * @hw: pointer to the HW structure + * + * Wrapper for calling the get_phy_info routines for the appropriate phy type. + * This is a function pointer entry point called by drivers + * or other shared routines. + **/ +static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) +{ + switch (hw->phy.type) { + case e1000_phy_ife: + return e1000_get_phy_info_ife_ich8lan(hw); + break; + case e1000_phy_igp_3: + return e1000e_get_phy_info_igp(hw); + break; + default: + break; + } + + return -E1000_ERR_PHY_TYPE; +} + +/** + * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY + * @hw: pointer to the HW structure + * + * Polarity is determined on the polarity reveral feature being enabled. + * This function is only called by other family-specific + * routines. + **/ +static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + /* Polarity is determined based on the reversal feature + * being enabled. + */ + if (phy->polarity_correction) { + offset = IFE_PHY_EXTENDED_STATUS_CONTROL; + mask = IFE_PESC_POLARITY_REVERSED; + } else { + offset = IFE_PHY_SPECIAL_CONTROL; + mask = IFE_PSC_FORCE_POLARITY; + } + + ret_val = e1e_rphy(hw, offset, &phy_data); + + if (!ret_val) + phy->cable_polarity = (phy_data & mask) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: TRUE to enable LPLU, FALSE to disable + * + * Sets the LPLU D0 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 phy_ctrl; + s32 ret_val = 0; + u16 data; + + if (phy->type != e1000_phy_igp_3) + return ret_val; + + phy_ctrl = er32(PHY_CTRL); + + if (active) { + phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; + ew32(PHY_CTRL, phy_ctrl); + + /* Call gig speed drop workaround on LPLU before accessing + * any PHY registers */ + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3)) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data); + if (ret_val) + return ret_val; + } else { + phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; + ew32(PHY_CTRL, phy_ctrl); + + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } + } + + return 0; +} + +/** + * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state + * @hw: pointer to the HW structure + * @active: TRUE to enable LPLU, FALSE to disable + * + * Sets the LPLU D3 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 phy_ctrl; + s32 ret_val; + u16 data; + + phy_ctrl = er32(PHY_CTRL); + + if (!active) { + phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; + ew32(PHY_CTRL, phy_ctrl); + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = e1e_rphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = e1e_rphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; + ew32(PHY_CTRL, phy_ctrl); + + /* Call gig speed drop workaround on LPLU before accessing + * any PHY registers */ + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3)) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = e1e_rphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + } + + return 0; +} + +/** + * e1000_read_nvm_ich8lan - Read word(s) from the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the word(s) to read. + * @words: Size of data to read in words + * @data: Pointer to the word(s) to read at offset. + * + * Reads a word(s) from the NVM using the flash access registers. + **/ +static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 act_offset; + s32 ret_val; + u16 i, word; + + if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + ret_val = e1000_acquire_swflag_ich8lan(hw); + if (ret_val) + return ret_val; + + /* Start with the bank offset, then add the relative offset. */ + act_offset = (er32(EECD) & E1000_EECD_SEC1VAL) + ? nvm->flash_bank_size + : 0; + act_offset += offset; + + for (i = 0; i < words; i++) { + if ((dev_spec->shadow_ram) && + (dev_spec->shadow_ram[offset+i].modified)) { + data[i] = dev_spec->shadow_ram[offset+i].value; + } else { + ret_val = e1000_read_flash_word_ich8lan(hw, + act_offset + i, + &word); + if (ret_val) + break; + data[i] = word; + } + } + + e1000_release_swflag_ich8lan(hw); + + return ret_val; +} + +/** + * e1000_flash_cycle_init_ich8lan - Initialize flash + * @hw: pointer to the HW structure + * + * This function does initial flash setup so that a new read/write/erase cycle + * can be started. + **/ +static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) +{ + union ich8_hws_flash_status hsfsts; + s32 ret_val = -E1000_ERR_NVM; + s32 i = 0; + + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + + /* Check if the flash descriptor is valid */ + if (hsfsts.hsf_status.fldesvalid == 0) { + hw_dbg(hw, "Flash descriptor invalid. " + "SW Sequencing must be used."); + return -E1000_ERR_NVM; + } + + /* Clear FCERR and DAEL in hw status by writing 1 */ + hsfsts.hsf_status.flcerr = 1; + hsfsts.hsf_status.dael = 1; + + ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); + + /* Either we should have a hardware SPI cycle in progress + * bit to check against, in order to start a new cycle or + * FDONE bit should be changed in the hardware so that it + * is 1 after harware reset, which can then be used as an + * indication whether a cycle is in progress or has been + * completed. + */ + + if (hsfsts.hsf_status.flcinprog == 0) { + /* There is no cycle running at present, + * so we can start a cycle */ + /* Begin by setting Flash Cycle Done. */ + hsfsts.hsf_status.flcdone = 1; + ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); + ret_val = 0; + } else { + /* otherwise poll for sometime so the current + * cycle has a chance to end before giving up. */ + for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { + hsfsts.regval = __er16flash(hw, ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcinprog == 0) { + ret_val = 0; + break; + } + udelay(1); + } + if (ret_val == 0) { + /* Successful in waiting for previous cycle to timeout, + * now set the Flash Cycle Done. */ + hsfsts.hsf_status.flcdone = 1; + ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); + } else { + hw_dbg(hw, "Flash controller busy, cannot get access"); + } + } + + return ret_val; +} + +/** + * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) + * @hw: pointer to the HW structure + * @timeout: maximum time to wait for completion + * + * This function starts a flash cycle and waits for its completion. + **/ +static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) +{ + union ich8_hws_flash_ctrl hsflctl; + union ich8_hws_flash_status hsfsts; + s32 ret_val = -E1000_ERR_NVM; + u32 i = 0; + + /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ + hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcgo = 1; + ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); + + /* wait till FDONE bit is set to 1 */ + do { + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcdone == 1) + break; + udelay(1); + } while (i++ < timeout); + + if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) + return 0; + + return ret_val; +} + +/** + * e1000_read_flash_word_ich8lan - Read word from flash + * @hw: pointer to the HW structure + * @offset: offset to data location + * @data: pointer to the location for storing the data + * + * Reads the flash word at offset into data. Offset is converted + * to bytes before read. + **/ +static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, + u16 *data) +{ + /* Must convert offset into bytes. */ + offset <<= 1; + + return e1000_read_flash_data_ich8lan(hw, offset, 2, data); +} + +/** + * e1000_read_flash_data_ich8lan - Read byte or word from NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the byte or word to read. + * @size: Size of data to read, 1=byte 2=word + * @data: Pointer to the word to store the value read. + * + * Reads a byte or word from the NVM using the flash access registers. + **/ +static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 *data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + u32 flash_data = 0; + s32 ret_val = -E1000_ERR_NVM; + u8 count = 0; + + if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) + return -E1000_ERR_NVM; + + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + + hw->nvm.flash_base_addr; + + do { + udelay(1); + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val != 0) + break; + + hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size - 1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; + ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); + + ew32flash(ICH_FLASH_FADDR, flash_linear_addr); + + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_READ_COMMAND_TIMEOUT); + + /* Check if FCERR is set to 1, if set to 1, clear it + * and try the whole sequence a few more times, else + * read in (shift in) the Flash Data0, the order is + * least significant byte first msb to lsb */ + if (ret_val == 0) { + flash_data = er32flash(ICH_FLASH_FDATA0); + if (size == 1) { + *data = (u8)(flash_data & 0x000000FF); + } else if (size == 2) { + *data = (u16)(flash_data & 0x0000FFFF); + } + break; + } else { + /* If we've gotten here, then things are probably + * completely hosed, but if the error condition is + * detected, it won't hurt to give it another try... + * ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + hw_dbg(hw, "Timeout error - flash cycle " + "did not complete."); + break; + } + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + + return ret_val; +} + +/** + * e1000_write_nvm_ich8lan - Write word(s) to the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the word(s) to write. + * @words: Size of data to write in words + * @data: Pointer to the word(s) to write at offset. + * + * Writes a byte or word to the NVM using the flash access registers. + **/ +static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + s32 ret_val; + u16 i; + + if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + ret_val = e1000_acquire_swflag_ich8lan(hw); + if (ret_val) + return ret_val; + + for (i = 0; i < words; i++) { + dev_spec->shadow_ram[offset+i].modified = 1; + dev_spec->shadow_ram[offset+i].value = data[i]; + } + + e1000_release_swflag_ich8lan(hw); + + return 0; +} + +/** + * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM + * @hw: pointer to the HW structure + * + * The NVM checksum is updated by calling the generic update_nvm_checksum, + * which writes the checksum to the shadow ram. The changes in the shadow + * ram are then committed to the EEPROM by processing each bank at a time + * checking for the modified bit and writing only the pending changes. + * After a succesful commit, the shadow ram is cleared and is ready for + * future writes. + **/ +static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 i, act_offset, new_bank_offset, old_bank_offset; + s32 ret_val; + u16 data; + + ret_val = e1000e_update_nvm_checksum_generic(hw); + if (ret_val) + return ret_val;; + + if (nvm->type != e1000_nvm_flash_sw) + return ret_val;; + + ret_val = e1000_acquire_swflag_ich8lan(hw); + if (ret_val) + return ret_val;; + + /* We're writing to the opposite bank so if we're on bank 1, + * write to bank 0 etc. We also need to erase the segment that + * is going to be written */ + if (!(er32(EECD) & E1000_EECD_SEC1VAL)) { + new_bank_offset = nvm->flash_bank_size; + old_bank_offset = 0; + e1000_erase_flash_bank_ich8lan(hw, 1); + } else { + old_bank_offset = nvm->flash_bank_size; + new_bank_offset = 0; + e1000_erase_flash_bank_ich8lan(hw, 0); + } + + for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { + /* Determine whether to write the value stored + * in the other NVM bank or a modified value stored + * in the shadow RAM */ + if (dev_spec->shadow_ram[i].modified) { + data = dev_spec->shadow_ram[i].value; + } else { + e1000_read_flash_word_ich8lan(hw, + i + old_bank_offset, + &data); + } + + /* If the word is 0x13, then make sure the signature bits + * (15:14) are 11b until the commit has completed. + * This will allow us to write 10b which indicates the + * signature is valid. We want to do this after the write + * has completed so that we don't mark the segment valid + * while the write is still in progress */ + if (i == E1000_ICH_NVM_SIG_WORD) + data |= E1000_ICH_NVM_SIG_MASK; + + /* Convert offset to bytes. */ + act_offset = (i + new_bank_offset) << 1; + + udelay(100); + /* Write the bytes to the new bank. */ + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset, + (u8)data); + if (ret_val) + break; + + udelay(100); + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset + 1, + (u8)(data >> 8)); + if (ret_val) + break; + } + + /* Don't bother writing the segment valid bits if sector + * programming failed. */ + if (ret_val) { + hw_dbg(hw, "Flash commit failed.\n"); + e1000_release_swflag_ich8lan(hw); + return ret_val; + } + + /* Finally validate the new segment by setting bit 15:14 + * to 10b in word 0x13 , this can be done without an + * erase as well since these bits are 11 to start with + * and we need to change bit 14 to 0b */ + act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; + e1000_read_flash_word_ich8lan(hw, act_offset, &data); + data &= 0xBFFF; + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset * 2 + 1, + (u8)(data >> 8)); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + return ret_val; + } + + /* And invalidate the previously valid segment by setting + * its signature word (0x13) high_byte to 0b. This can be + * done without an erase because flash erase sets all bits + * to 1's. We can write 1's to 0's without an erase */ + act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + return ret_val; + } + + /* Great! Everything worked, we can now clear the cached entries. */ + for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { + dev_spec->shadow_ram[i].modified = 0; + dev_spec->shadow_ram[i].value = 0xFFFF; + } + + e1000_release_swflag_ich8lan(hw); + + /* Reload the EEPROM, or else modifications will not appear + * until after the next adapter reset. + */ + e1000e_reload_nvm(hw); + msleep(10); + + return ret_val; +} + +/** + * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. + * If the bit is 0, that the EEPROM had been modified, but the checksum was not + * calculated, in which case we need to calculate the checksum and set bit 6. + **/ +static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val; + u16 data; + + /* Read 0x19 and check bit 6. If this bit is 0, the checksum + * needs to be fixed. This bit is an indication that the NVM + * was prepared by OEM software and did not calculate the + * checksum...a likely scenario. + */ + ret_val = e1000_read_nvm(hw, 0x19, 1, &data); + if (ret_val) + return ret_val; + + if ((data & 0x40) == 0) { + data |= 0x40; + ret_val = e1000_write_nvm(hw, 0x19, 1, &data); + if (ret_val) + return ret_val; + ret_val = e1000e_update_nvm_checksum(hw); + if (ret_val) + return ret_val; + } + + return e1000e_validate_nvm_checksum_generic(hw); +} + +/** + * e1000_write_flash_data_ich8lan - Writes bytes to the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the byte/word to read. + * @size: Size of data to read, 1=byte 2=word + * @data: The byte(s) to write to the NVM. + * + * Writes one/two bytes to the NVM using the flash access registers. + **/ +static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + u32 flash_data = 0; + s32 ret_val; + u8 count = 0; + + if (size < 1 || size > 2 || data > size * 0xff || + offset > ICH_FLASH_LINEAR_ADDR_MASK) + return -E1000_ERR_NVM; + + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + + hw->nvm.flash_base_addr; + + do { + udelay(1); + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val) + break; + + hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size -1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; + ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); + + ew32flash(ICH_FLASH_FADDR, flash_linear_addr); + + if (size == 1) + flash_data = (u32)data & 0x00FF; + else + flash_data = (u32)data; + + ew32flash(ICH_FLASH_FDATA0, flash_data); + + /* check if FCERR is set to 1 , if set to 1, clear it + * and try the whole sequence a few more times else done */ + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_WRITE_COMMAND_TIMEOUT); + if (!ret_val) + break; + + /* If we're here, then things are most likely + * completely hosed, but if the error condition + * is detected, it won't hurt to give it another + * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) + /* Repeat for some time before giving up. */ + continue; + if (hsfsts.hsf_status.flcdone == 0) { + hw_dbg(hw, "Timeout error - flash cycle " + "did not complete."); + break; + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + + return ret_val; +} + +/** + * e1000_write_flash_byte_ich8lan - Write a single byte to NVM + * @hw: pointer to the HW structure + * @offset: The index of the byte to read. + * @data: The byte to write to the NVM. + * + * Writes a single byte to the NVM using the flash access registers. + **/ +static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, + u8 data) +{ + u16 word = (u16)data; + + return e1000_write_flash_data_ich8lan(hw, offset, 1, word); +} + +/** + * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM + * @hw: pointer to the HW structure + * @offset: The offset of the byte to write. + * @byte: The byte to write to the NVM. + * + * Writes a single byte to the NVM using the flash access registers. + * Goes through a retry algorithm before giving up. + **/ +static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8 byte) +{ + s32 ret_val; + u16 program_retries; + + ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); + if (!ret_val) + return ret_val; + + for (program_retries = 0; program_retries < 100; program_retries++) { + hw_dbg(hw, "Retrying Byte %2.2X at offset %u\n", byte, offset); + udelay(100); + ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); + if (!ret_val) + break; + } + if (program_retries == 100) + return -E1000_ERR_NVM; + + return 0; +} + +/** + * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM + * @hw: pointer to the HW structure + * @bank: 0 for first bank, 1 for second bank, etc. + * + * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. + * bank N is 4096 * N + flash_reg_addr. + **/ +static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + /* bank size is in 16bit words - adjust to bytes */ + u32 flash_bank_size = nvm->flash_bank_size * 2; + s32 ret_val; + s32 count = 0; + s32 iteration; + s32 sector_size; + s32 j; + + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + + /* Determine HW Sector size: Read BERASE bits of hw flash status + * register */ + /* 00: The Hw sector is 256 bytes, hence we need to erase 16 + * consecutive sectors. The start index for the nth Hw sector + * can be calculated as = bank * 4096 + n * 256 + * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. + * The start index for the nth Hw sector can be calculated + * as = bank * 4096 + * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 + * (ich9 only, otherwise error condition) + * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 + */ + switch (hsfsts.hsf_status.berasesz) { + case 0: + /* Hw sector size 256 */ + sector_size = ICH_FLASH_SEG_SIZE_256; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; + break; + case 1: + sector_size = ICH_FLASH_SEG_SIZE_4K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K; + break; + case 2: + if (hw->mac.type == e1000_ich9lan) { + sector_size = ICH_FLASH_SEG_SIZE_8K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K; + } else { + return -E1000_ERR_NVM; + } + break; + case 3: + sector_size = ICH_FLASH_SEG_SIZE_64K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K; + break; + default: + return -E1000_ERR_NVM; + } + + /* Start with the base address, then add the sector offset. */ + flash_linear_addr = hw->nvm.flash_base_addr; + flash_linear_addr += (bank) ? (sector_size * iteration) : 0; + + for (j = 0; j < iteration ; j++) { + do { + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val) + return ret_val; + + /* Write a value 11 (block Erase) in Flash + * Cycle field in hw flash control */ + hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; + ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); + + /* Write the last 24 bits of an index within the + * block into Flash Linear address field in Flash + * Address. + */ + flash_linear_addr += (j * sector_size); + ew32flash(ICH_FLASH_FADDR, flash_linear_addr); + + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_ERASE_COMMAND_TIMEOUT); + if (ret_val == 0) + break; + + /* Check if FCERR is set to 1. If 1, + * clear it and try the whole sequence + * a few more times else Done */ + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) + /* repeat for some time before + * giving up */ + continue; + else if (hsfsts.hsf_status.flcdone == 0) + return ret_val; + } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); + } + + return 0; +} + +/** + * e1000_valid_led_default_ich8lan - Set the default LED settings + * @hw: pointer to the HW structure + * @data: Pointer to the LED settings + * + * Reads the LED default settings from the NVM to data. If the NVM LED + * settings is all 0's or F's, set the LED default to a valid LED default + * setting. + **/ +static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + + if (*data == ID_LED_RESERVED_0000 || + *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT_ICH8LAN; + + return 0; +} + +/** + * e1000_get_bus_info_ich8lan - Get/Set the bus type and width + * @hw: pointer to the HW structure + * + * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability + * register, so the the bus width is hard coded. + **/ +static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + s32 ret_val; + + ret_val = e1000e_get_bus_info_pcie(hw); + + /* ICH devices are "PCI Express"-ish. They have + * a configuration space, but do not contain + * PCI Express Capability registers, so bus width + * must be hardcoded. + */ + if (bus->width == e1000_bus_width_unknown) + bus->width = e1000_bus_width_pcie_x1; + + return ret_val; +} + +/** + * e1000_reset_hw_ich8lan - Reset the hardware + * @hw: pointer to the HW structure + * + * Does a full reset of the hardware which includes a reset of the PHY and + * MAC. + **/ +static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) +{ + u32 ctrl, icr, kab; + s32 ret_val; + + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000e_disable_pcie_master(hw); + if (ret_val) { + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + } + + hw_dbg(hw, "Masking off all interrupts\n"); + ew32(IMC, 0xffffffff); + + /* Disable the Transmit and Receive units. Then delay to allow + * any pending transactions to complete before we hit the MAC + * with the global reset. + */ + ew32(RCTL, 0); + ew32(TCTL, E1000_TCTL_PSP); + e1e_flush(); + + msleep(10); + + /* Workaround for ICH8 bit corruption issue in FIFO memory */ + if (hw->mac.type == e1000_ich8lan) { + /* Set Tx and Rx buffer allocation to 8k apiece. */ + ew32(PBA, E1000_PBA_8K); + /* Set Packet Buffer Size to 16k. */ + ew32(PBS, E1000_PBS_16K); + } + + ctrl = er32(CTRL); + + if (!e1000_check_reset_block(hw)) { + /* PHY HW reset requires MAC CORE reset at the same + * time to make sure the interface between MAC and the + * external PHY is reset. + */ + ctrl |= E1000_CTRL_PHY_RST; + } + ret_val = e1000_acquire_swflag_ich8lan(hw); + hw_dbg(hw, "Issuing a global reset to ich8lan"); + ew32(CTRL, (ctrl | E1000_CTRL_RST)); + msleep(20); + + ret_val = e1000e_get_auto_rd_done(hw); + if (ret_val) { + /* + * When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + hw_dbg(hw, "Auto Read Done did not complete\n"); + } + + ew32(IMC, 0xffffffff); + icr = er32(ICR); + + kab = er32(KABGTXD); + kab |= E1000_KABGTXD_BGSQLBIAS; + ew32(KABGTXD, kab); + + return ret_val; +} + +/** + * e1000_init_hw_ich8lan - Initialize the hardware + * @hw: pointer to the HW structure + * + * Prepares the hardware for transmit and receive by doing the following: + * - initialize hardware bits + * - initialize LED identification + * - setup receive address registers + * - setup flow control + * - setup transmit discriptors + * - clear statistics + **/ +static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl_ext, txdctl, snoop; + s32 ret_val; + u16 i; + + e1000_initialize_hw_bits_ich8lan(hw); + + /* Initialize identification LED */ + ret_val = e1000e_id_led_init(hw); + if (ret_val) { + hw_dbg(hw, "Error initializing identification LED\n"); + return ret_val; + } + + /* Setup the receive address. */ + e1000e_init_rx_addrs(hw, mac->rar_entry_count); + + /* Zero out the Multicast HASH table */ + hw_dbg(hw, "Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = e1000_setup_link_ich8lan(hw); + + /* Set the transmit descriptor write-back policy for both queues */ + txdctl = er32(TXDCTL); + txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB; + txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | + E1000_TXDCTL_MAX_TX_DESC_PREFETCH; + ew32(TXDCTL, txdctl); + txdctl = er32(TXDCTL1); + txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB; + txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | + E1000_TXDCTL_MAX_TX_DESC_PREFETCH; + ew32(TXDCTL1, txdctl); + + /* ICH8 has opposite polarity of no_snoop bits. + * By default, we should use snoop behavior. */ + if (mac->type == e1000_ich8lan) + snoop = PCIE_ICH8_SNOOP_ALL; + else + snoop = (u32) ~(PCIE_NO_SNOOP_ALL); + e1000e_set_pcie_no_snoop(hw, snoop); + + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_RO_DIS; + ew32(CTRL_EXT, ctrl_ext); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_ich8lan(hw); + + return 0; +} +/** + * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits + * @hw: pointer to the HW structure + * + * Sets/Clears required hardware bits necessary for correctly setting up the + * hardware for transmit and receive. + **/ +static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) +{ + u32 reg; + + /* Extended Device Control */ + reg = er32(CTRL_EXT); + reg |= (1 << 22); + ew32(CTRL_EXT, reg); + + /* Transmit Descriptor Control 0 */ + reg = er32(TXDCTL); + reg |= (1 << 22); + ew32(TXDCTL, reg); + + /* Transmit Descriptor Control 1 */ + reg = er32(TXDCTL1); + reg |= (1 << 22); + ew32(TXDCTL1, reg); + + /* Transmit Arbitration Control 0 */ + reg = er32(TARC0); + if (hw->mac.type == e1000_ich8lan) + reg |= (1 << 28) | (1 << 29); + reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); + ew32(TARC0, reg); + + /* Transmit Arbitration Control 1 */ + reg = er32(TARC1); + if (er32(TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + reg |= (1 << 24) | (1 << 26) | (1 << 30); + ew32(TARC1, reg); + + /* Device Status */ + if (hw->mac.type == e1000_ich8lan) { + reg = er32(STATUS); + reg &= ~(1 << 31); + ew32(STATUS, reg); + } +} + +/** + * e1000_setup_link_ich8lan - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + + if (e1000_check_reset_block(hw)) + return 0; + + /* ICH parts do not have a word in the NVM to determine + * the default flow control setting, so we explicitly + * set it to full. + */ + if (mac->fc == e1000_fc_default) + mac->fc = e1000_fc_full; + + mac->original_fc = mac->fc; + + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc); + + /* Continue to configure the copper link. */ + ret_val = e1000_setup_copper_link_ich8lan(hw); + if (ret_val) + return ret_val; + + ew32(FCTTV, mac->fc_pause_time); + + return e1000e_set_fc_watermarks(hw); +} + +/** + * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface + * @hw: pointer to the HW structure + * + * Configures the kumeran interface to the PHY to wait the appropriate time + * when polling the PHY, then call the generic setup_copper_link to finish + * configuring the copper link. + **/ +static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val; + u16 reg_data; + + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ew32(CTRL, ctrl); + + /* Set the mac to wait the maximum time between each iteration + * and increase the max iterations when polling the phy; + * this fixes erroneous timeouts at 10Mbps. */ + ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); + if (ret_val) + return ret_val; + ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); + if (ret_val) + return ret_val; + reg_data |= 0x3F; + ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); + if (ret_val) + return ret_val; + + if (hw->phy.type == e1000_phy_igp_3) { + ret_val = e1000e_copper_link_setup_igp(hw); + if (ret_val) + return ret_val; + } + + return e1000e_setup_copper_link(hw); +} + +/** + * e1000_get_link_up_info_ich8lan - Get current link speed and duplex + * @hw: pointer to the HW structure + * @speed: pointer to store current link speed + * @duplex: pointer to store the current link duplex + * + * Calls the generic get_speed_and_duplex to retreive the current link + * information and then calls the Kumeran lock loss workaround for links at + * gigabit speeds. + **/ +static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + s32 ret_val; + + ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex); + if (ret_val) + return ret_val; + + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3) && + (*speed == SPEED_1000)) { + ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); + } + + return ret_val; +} + +/** + * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround + * @hw: pointer to the HW structure + * + * Work-around for 82566 Kumeran PCS lock loss: + * On link status change (i.e. PCI reset, speed change) and link is up and + * speed is gigabit- + * 0) if workaround is optionally disabled do nothing + * 1) wait 1ms for Kumeran link to come up + * 2) check Kumeran Diagnostic register PCS lock loss bit + * 3) if not set the link is locked (all is good), otherwise... + * 4) reset the PHY + * 5) repeat up to 10 times + * Note: this is only called for IGP3 copper when speed is 1gb. + **/ +static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) +{ + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 phy_ctrl; + s32 ret_val; + u16 i, data; + bool link; + + if (!dev_spec->kmrn_lock_loss_workaround_enabled) + return 0; + + /* Make sure link is up before proceeding. If not just return. + * Attempting this while link is negotiating fouled up link + * stability */ + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (!link) + return 0; + + for (i = 0; i < 10; i++) { + /* read once to clear */ + ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); + if (ret_val) + return ret_val; + /* and again to get new status */ + ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); + if (ret_val) + return ret_val; + + /* check for PCS lock */ + if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) + return 0; + + /* Issue PHY reset */ + e1000_phy_hw_reset(hw); + mdelay(5); + } + /* Disable GigE link negotiation */ + phy_ctrl = er32(PHY_CTRL); + phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + ew32(PHY_CTRL, phy_ctrl); + + /* Call gig speed drop workaround on Giga disable before accessing + * any PHY registers */ + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* unable to acquire PCS lock */ + return -E1000_ERR_PHY; +} + +/** + * e1000_set_kmrn_lock_loss_workaound_ich8lan - Set Kumeran workaround state + * @hw: pointer to the HW structure + * @state: boolean value used to set the current Kumaran workaround state + * + * If ICH8, set the current Kumeran workaround state (enabled - TRUE + * /disabled - FALSE). + **/ +void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, + bool state) +{ + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + + if (hw->mac.type != e1000_ich8lan) { + hw_dbg(hw, "Workaround applies to ICH8 only.\n"); + return; + } + + dev_spec->kmrn_lock_loss_workaround_enabled = state; +} + +/** + * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 + * @hw: pointer to the HW structure + * + * Workaround for 82566 power-down on D3 entry: + * 1) disable gigabit link + * 2) write VR power-down enable + * 3) read it back + * Continue if successful, else issue LCD reset and repeat + **/ +void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) +{ + u32 reg; + u16 data; + u8 retry = 0; + + if (hw->phy.type != e1000_phy_igp_3) + return; + + /* Try the workaround twice (if needed) */ + do { + /* Disable link */ + reg = er32(PHY_CTRL); + reg |= (E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + ew32(PHY_CTRL, reg); + + /* Call gig speed drop workaround on Giga disable before + * accessing any PHY registers */ + if (hw->mac.type == e1000_ich8lan) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* Write VR power-down enable */ + e1e_rphy(hw, IGP3_VR_CTRL, &data); + data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; + e1e_wphy(hw, IGP3_VR_CTRL, data | IGP3_VR_CTRL_MODE_SHUTDOWN); + + /* Read it back and test */ + e1e_rphy(hw, IGP3_VR_CTRL, &data); + data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; + if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) + break; + + /* Issue PHY reset and repeat at most one more time */ + reg = er32(CTRL); + ew32(CTRL, reg | E1000_CTRL_PHY_RST); + retry++; + } while (retry); +} + +/** + * e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working + * @hw: pointer to the HW structure + * + * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), + * LPLU, Giga disable, MDIC PHY reset): + * 1) Set Kumeran Near-end loopback + * 2) Clear Kumeran Near-end loopback + * Should only be called for ICH8[m] devices with IGP_3 Phy. + **/ +void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val; + u16 reg_data; + + if ((hw->mac.type != e1000_ich8lan) || + (hw->phy.type != e1000_phy_igp_3)) + return; + + ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, + ®_data); + if (ret_val) + return; + reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; + ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, + reg_data); + if (ret_val) + return; + reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; + ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, + reg_data); +} + +/** + * e1000_cleanup_led_ich8lan - Restore the default LED operation + * @hw: pointer to the HW structure + * + * Return the LED back to the default configuration. + **/ +static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) +{ + if (hw->phy.type == e1000_phy_ife) + return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); + + ew32(LEDCTL, hw->mac.ledctl_default); + return 0; +} + +/** + * e1000_led_on_ich8lan - Turn LED's on + * @hw: pointer to the HW structure + * + * Turn on the LED's. + **/ +static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) +{ + if (hw->phy.type == e1000_phy_ife) + return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); + + ew32(LEDCTL, hw->mac.ledctl_mode2); + return 0; +} + +/** + * e1000_led_off_ich8lan - Turn LED's off + * @hw: pointer to the HW structure + * + * Turn off the LED's. + **/ +static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) +{ + if (hw->phy.type == e1000_phy_ife) + return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); + + ew32(LEDCTL, hw->mac.ledctl_mode1); + return 0; +} + +/** + * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters + * @hw: pointer to the HW structure + * + * Clears hardware counters specific to the silicon family and calls + * clear_hw_cntrs_generic to clear all general purpose counters. + **/ +static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) +{ + u32 temp; + + e1000e_clear_hw_cntrs_base(hw); + + temp = er32(ALGNERRC); + temp = er32(RXERRC); + temp = er32(TNCRS); + temp = er32(CEXTERR); + temp = er32(TSCTC); + temp = er32(TSCTFC); + + temp = er32(MGTPRC); + temp = er32(MGTPDC); + temp = er32(MGTPTC); + + temp = er32(IAC); + temp = er32(ICRXOC); + +} + +static struct e1000_mac_operations ich8_mac_ops = { + .mng_mode_enab = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + .check_for_link = e1000e_check_for_copper_link, + .cleanup_led = e1000_cleanup_led_ich8lan, + .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, + .get_bus_info = e1000_get_bus_info_ich8lan, + .get_link_up_info = e1000_get_link_up_info_ich8lan, + .led_on = e1000_led_on_ich8lan, + .led_off = e1000_led_off_ich8lan, + .mc_addr_list_update = e1000e_mc_addr_list_update_generic, + .reset_hw = e1000_reset_hw_ich8lan, + .init_hw = e1000_init_hw_ich8lan, + .setup_link = e1000_setup_link_ich8lan, + .setup_physical_interface= e1000_setup_copper_link_ich8lan, +}; + +static struct e1000_phy_operations ich8_phy_ops = { + .acquire_phy = e1000_acquire_swflag_ich8lan, + .check_reset_block = e1000_check_reset_block_ich8lan, + .commit_phy = NULL, + .force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan, + .get_cfg_done = e1000e_get_cfg_done, + .get_cable_length = e1000e_get_cable_length_igp_2, + .get_phy_info = e1000_get_phy_info_ich8lan, + .read_phy_reg = e1000e_read_phy_reg_igp, + .release_phy = e1000_release_swflag_ich8lan, + .reset_phy = e1000_phy_hw_reset_ich8lan, + .set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan, + .set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan, + .write_phy_reg = e1000e_write_phy_reg_igp, +}; + +static struct e1000_nvm_operations ich8_nvm_ops = { + .acquire_nvm = e1000_acquire_swflag_ich8lan, + .read_nvm = e1000_read_nvm_ich8lan, + .release_nvm = e1000_release_swflag_ich8lan, + .update_nvm = e1000_update_nvm_checksum_ich8lan, + .valid_led_default = e1000_valid_led_default_ich8lan, + .validate_nvm = e1000_validate_nvm_checksum_ich8lan, + .write_nvm = e1000_write_nvm_ich8lan, +}; + +struct e1000_info e1000_ich8_info = { + .mac = e1000_ich8lan, + .flags = FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_FLASH + | FLAG_APME_IN_WUC, + .pba = 8, + .get_invariants = e1000_get_invariants_ich8lan, + .mac_ops = &ich8_mac_ops, + .phy_ops = &ich8_phy_ops, + .nvm_ops = &ich8_nvm_ops, +}; + +struct e1000_info e1000_ich9_info = { + .mac = e1000_ich9lan, + .flags = FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_ERT + | FLAG_HAS_FLASH + | FLAG_APME_IN_WUC, + .pba = 10, + .get_invariants = e1000_get_invariants_ich8lan, + .mac_ops = &ich8_mac_ops, + .phy_ops = &ich8_phy_ops, + .nvm_ops = &ich8_nvm_ops, +}; + diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c new file mode 100644 index 000000000000..3bbfe605e111 --- /dev/null +++ b/drivers/net/e1000e/lib.c @@ -0,0 +1,2487 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include + +#include "e1000.h" + +enum e1000_mng_mode { + e1000_mng_mode_none = 0, + e1000_mng_mode_asf, + e1000_mng_mode_pt, + e1000_mng_mode_ipmi, + e1000_mng_mode_host_if_only +}; + +#define E1000_FACTPS_MNGCG 0x20000000 + +#define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management + * Technology signature */ + +/** + * e1000e_get_bus_info_pcie - Get PCIe bus information + * @hw: pointer to the HW structure + * + * Determines and stores the system bus information for a particular + * network interface. The following bus information is determined and stored: + * bus speed, bus width, type (PCIe), and PCIe function. + **/ +s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + struct e1000_adapter *adapter = hw->adapter; + u32 status; + u16 pcie_link_status, pci_header_type, cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) { + bus->width = e1000_bus_width_unknown; + } else { + pci_read_config_word(adapter->pdev, + cap_offset + PCIE_LINK_STATUS, + &pcie_link_status); + bus->width = (enum e1000_bus_width)((pcie_link_status & + PCIE_LINK_WIDTH_MASK) >> + PCIE_LINK_WIDTH_SHIFT); + } + + pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER, + &pci_header_type); + if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { + status = er32(STATUS); + bus->func = (status & E1000_STATUS_FUNC_MASK) + >> E1000_STATUS_FUNC_SHIFT; + } else { + bus->func = 0; + } + + return 0; +} + +/** + * e1000e_write_vfta - Write value to VLAN filter table + * @hw: pointer to the HW structure + * @offset: register offset in VLAN filter table + * @value: register value written to VLAN filter table + * + * Writes value at the given offset in the register array which stores + * the VLAN filter table. + **/ +void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) +{ + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); + e1e_flush(); +} + +/** + * e1000e_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 e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) +{ + u32 i; + + /* Setup the receive address */ + hw_dbg(hw, "Programming MAC Address into RAR[0]\n"); + + e1000e_rar_set(hw, hw->mac.addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1); + for (i = 1; i < rar_count; i++) { + E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0); + e1e_flush(); + E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0); + e1e_flush(); + } +} + +/** + * e1000e_rar_set - Set receive address register + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address array register at index to the address passed + * in by addr. + **/ +void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) +{ + u32 rar_low, rar_high; + + /* HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((u32) addr[0] | + ((u32) addr[1] << 8) | + ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); + + rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); + + rar_high |= E1000_RAH_AV; + + E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low); + E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high); +} + +/** + * e1000_mta_set - Set multicast filter table address + * @hw: pointer to the HW structure + * @hash_value: determines the MTA register and bit to set + * + * The multicast table address is a register array of 32-bit registers. + * The hash_value is used to determine what register the bit is in, the + * current value is read, the new bit is OR'd in and the new value is + * written back into the register. + **/ +static void e1000_mta_set(struct e1000_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg, mta; + + /* The MTA is a register array of 32-bit registers. It is + * treated like an array of (32*mta_reg_count) 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 (hw->mac.mta_reg_count - 1) serves as a + * mask to bits 31:5 of the hash value which gives us the + * register we're modifying. The hash bit within that register + * is determined by the lower 5 bits of the hash value. + */ + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); + + mta |= (1 << hash_bit); + + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); + e1e_flush(); +} + +/** + * e1000_hash_mc_addr - Generate a multicast hash value + * @hw: pointer to the HW structure + * @mc_addr: pointer to a multicast address + * + * Generates a multicast address hash value which is used to determine + * the multicast filter table array address and new table value. See + * e1000_mta_set_generic() + **/ +static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) +{ + u32 hash_value, hash_mask; + u8 bit_shift = 0; + + /* Register count multiplied by bits per register */ + hash_mask = (hw->mac.mta_reg_count * 32) - 1; + + /* For a mc_filter_type of 0, bit_shift is the number of left-shifts + * where 0xFF would still fall within the hash mask. */ + while (hash_mask >> bit_shift != 0xFF) + bit_shift++; + + /* The portion of the address that is used for the hash table + * is determined by the mc_filter_type setting. + * The algorithm is such that there is a total of 8 bits of shifting. + * The bit_shift for a mc_filter_type of 0 represents the number of + * left-shifts where the MSB of mc_addr[5] would still fall within + * the hash_mask. Case 0 does this exactly. Since there are a total + * of 8 bits of shifting, then mc_addr[4] will shift right the + * remaining number of bits. Thus 8 - bit_shift. The rest of the + * cases are a variation of this algorithm...essentially raising the + * number of bits to shift mc_addr[5] left, while still keeping the + * 8-bit shifting total. + */ + /* For example, given the following Destination MAC Address and an + * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), + * we can see that the bit_shift for case 0 is 4. These are the hash + * values resulting from each mc_filter_type... + * [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB + * + * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 + * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 + * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 + * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 + */ + switch (hw->mac.mc_filter_type) { + default: + case 0: + break; + case 1: + bit_shift += 1; + break; + case 2: + bit_shift += 2; + break; + case 3: + bit_shift += 4; + break; + } + + hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | + (((u16) mc_addr[5]) << bit_shift))); + + return hash_value; +} + +/** + * e1000e_mc_addr_list_update_generic - 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 e1000e_mc_addr_list_update_generic(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count) +{ + u32 hash_value; + u32 i; + + /* 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) { + e1000e_rar_set(hw, mc_addr_list, i); + mc_addr_count--; + mc_addr_list += ETH_ALEN; + } else { + E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0); + e1e_flush(); + E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0); + e1e_flush(); + } + } + + /* Clear the old settings from the MTA */ + hw_dbg(hw, "Clearing MTA\n"); + for (i = 0; i < hw->mac.mta_reg_count; i++) { + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + e1e_flush(); + } + + /* Load any remaining multicast addresses into the hash table. */ + for (; mc_addr_count > 0; mc_addr_count--) { + hash_value = e1000_hash_mc_addr(hw, mc_addr_list); + hw_dbg(hw, "Hash value = 0x%03X\n", hash_value); + e1000_mta_set(hw, hash_value); + mc_addr_list += ETH_ALEN; + } +} + +/** + * e1000e_clear_hw_cntrs_base - Clear base hardware counters + * @hw: pointer to the HW structure + * + * Clears the base hardware counters by reading the counter registers. + **/ +void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw) +{ + u32 temp; + + temp = er32(CRCERRS); + temp = er32(SYMERRS); + temp = er32(MPC); + temp = er32(SCC); + temp = er32(ECOL); + temp = er32(MCC); + temp = er32(LATECOL); + temp = er32(COLC); + temp = er32(DC); + temp = er32(SEC); + temp = er32(RLEC); + temp = er32(XONRXC); + temp = er32(XONTXC); + temp = er32(XOFFRXC); + temp = er32(XOFFTXC); + temp = er32(FCRUC); + temp = er32(GPRC); + temp = er32(BPRC); + temp = er32(MPRC); + temp = er32(GPTC); + temp = er32(GORCL); + temp = er32(GORCH); + temp = er32(GOTCL); + temp = er32(GOTCH); + temp = er32(RNBC); + temp = er32(RUC); + temp = er32(RFC); + temp = er32(ROC); + temp = er32(RJC); + temp = er32(TORL); + temp = er32(TORH); + temp = er32(TOTL); + temp = er32(TOTH); + temp = er32(TPR); + temp = er32(TPT); + temp = er32(MPTC); + temp = er32(BPTC); +} + +/** + * e1000e_check_for_copper_link - Check for link (Copper) + * @hw: pointer to the HW structure + * + * Checks to see of the link status of the hardware has changed. If a + * change in link status has been detected, then we read the PHY registers + * to get the current speed/duplex if link exists. + **/ +s32 e1000e_check_for_copper_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + bool link; + + /* We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The + * get_link_status flag is set upon receiving a Link Status + * Change or Rx Sequence Error interrupt. + */ + if (!mac->get_link_status) + return 0; + + /* First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + + if (!link) + return ret_val; /* No link detected */ + + mac->get_link_status = 0; + + /* Check if there was DownShift, must be checked + * immediately after link-up */ + e1000e_check_downshift(hw); + + /* If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) { + ret_val = -E1000_ERR_CONFIG; + return ret_val; + } + + /* Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to + * configure Collision Distance in the MAC. + */ + e1000e_config_collision_dist(hw); + + /* Configure Flow Control now that Auto-Neg has completed. + * First, we need to restore the desired flow control + * settings because we may have had to re-autoneg with a + * different link partner. + */ + ret_val = e1000e_config_fc_after_link_up(hw); + if (ret_val) { + hw_dbg(hw, "Error configuring flow control\n"); + } + + return ret_val; +} + +/** + * e1000e_check_for_fiber_link - Check for link (Fiber) + * @hw: pointer to the HW structure + * + * Checks for link up on the hardware. If link is not up and we have + * a signal, then we need to force link up. + **/ +s32 e1000e_check_for_fiber_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 rxcw; + u32 ctrl; + u32 status; + s32 ret_val; + + ctrl = er32(CTRL); + status = er32(STATUS); + rxcw = er32(RXCW); + + /* If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate), the cable is plugged in (we have signal), + * and our link partner is not trying to auto-negotiate with us (we + * are receiving idles or data), we need to force link up. We also + * need to give auto-negotiation time to complete, in case the cable + * was just plugged in. The autoneg_failed flag does this. + */ + /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ + if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) && + (!(rxcw & E1000_RXCW_C))) { + if (mac->autoneg_failed == 0) { + mac->autoneg_failed = 1; + return 0; + } + hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n"); + + /* Disable auto-negotiation in the TXCW register */ + ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl = er32(CTRL); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); + ew32(CTRL, ctrl); + + /* Configure Flow Control after forcing link up. */ + ret_val = e1000e_config_fc_after_link_up(hw); + if (ret_val) { + hw_dbg(hw, "Error configuring flow control\n"); + return ret_val; + } + } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { + /* If we are forcing link and we are receiving /C/ ordered + * sets, re-enable auto-negotiation in the TXCW register + * and disable forced link in the Device Control register + * in an attempt to auto-negotiate with our link partner. + */ + hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n"); + ew32(TXCW, mac->txcw); + ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); + + mac->serdes_has_link = 1; + } + + return 0; +} + +/** + * e1000e_check_for_serdes_link - Check for link (Serdes) + * @hw: pointer to the HW structure + * + * Checks for link up on the hardware. If link is not up and we have + * a signal, then we need to force link up. + **/ +s32 e1000e_check_for_serdes_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 rxcw; + u32 ctrl; + u32 status; + s32 ret_val; + + ctrl = er32(CTRL); + status = er32(STATUS); + rxcw = er32(RXCW); + + /* If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate), and our link partner is not trying to + * auto-negotiate with us (we are receiving idles or data), + * we need to force link up. We also need to give auto-negotiation + * time to complete. + */ + /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ + if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) { + if (mac->autoneg_failed == 0) { + mac->autoneg_failed = 1; + return 0; + } + hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n"); + + /* Disable auto-negotiation in the TXCW register */ + ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl = er32(CTRL); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); + ew32(CTRL, ctrl); + + /* Configure Flow Control after forcing link up. */ + ret_val = e1000e_config_fc_after_link_up(hw); + if (ret_val) { + hw_dbg(hw, "Error configuring flow control\n"); + return ret_val; + } + } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { + /* If we are forcing link and we are receiving /C/ ordered + * sets, re-enable auto-negotiation in the TXCW register + * and disable forced link in the Device Control register + * in an attempt to auto-negotiate with our link partner. + */ + hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n"); + ew32(TXCW, mac->txcw); + ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); + + mac->serdes_has_link = 1; + } else if (!(E1000_TXCW_ANE & er32(TXCW))) { + /* If we force link for non-auto-negotiation switch, check + * link status based on MAC synchronization for internal + * serdes media type. + */ + /* SYNCH bit and IV bit are sticky. */ + udelay(10); + if (E1000_RXCW_SYNCH & er32(RXCW)) { + if (!(rxcw & E1000_RXCW_IV)) { + mac->serdes_has_link = 1; + hw_dbg(hw, "SERDES: Link is up.\n"); + } + } else { + mac->serdes_has_link = 0; + hw_dbg(hw, "SERDES: Link is down.\n"); + } + } + + if (E1000_TXCW_ANE & er32(TXCW)) { + status = er32(STATUS); + mac->serdes_has_link = (status & E1000_STATUS_LU); + } + + return 0; +} + +/** + * e1000_set_default_fc_generic - Set flow control default values + * @hw: pointer to the HW structure + * + * Read the EEPROM for the default values for flow control and store the + * values. + **/ +static s32 e1000_set_default_fc_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + u16 nvm_data; + + if (mac->fc != e1000_fc_default) + return 0; + + /* Read and store word 0x0F of the EEPROM. This word contains bits + * that determine the hardware's default PAUSE (flow control) mode, + * a bit that determines whether the HW defaults to enabling or + * disabling auto-negotiation, and the direction of the + * SW defined pins. If there is no SW over-ride of the flow + * control setting, then the variable hw->fc will + * be initialized based on a value in the EEPROM. + */ + ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data); + + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + + if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) + mac->fc = e1000_fc_none; + else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == + NVM_WORD0F_ASM_DIR) + mac->fc = e1000_fc_tx_pause; + else + mac->fc = e1000_fc_full; + + return 0; +} + +/** + * e1000e_setup_link - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +s32 e1000e_setup_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + + /* In the case of the phy reset being blocked, we already have a link. + * We do not need to set it up again. + */ + if (e1000_check_reset_block(hw)) + return 0; + + ret_val = e1000_set_default_fc_generic(hw); + if (ret_val) + return ret_val; + + /* 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. + */ + mac->original_fc = mac->fc; + + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc); + + /* Call the necessary media_type subroutine to configure the link. */ + ret_val = mac->ops.setup_physical_interface(hw); + if (ret_val) + return ret_val; + + /* Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + hw_dbg(hw, "Initializing the Flow Control address, type and timer regs\n"); + ew32(FCT, FLOW_CONTROL_TYPE); + ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH); + ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW); + + ew32(FCTTV, mac->fc_pause_time); + + return e1000e_set_fc_watermarks(hw); +} + +/** + * e1000_commit_fc_settings_generic - Configure flow control + * @hw: pointer to the HW structure + * + * Write the flow control settings to the Transmit Config Word Register (TXCW) + * base on the flow control settings in e1000_mac_info. + **/ +static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 txcw; + + /* Check for a software override of the flow control settings, and + * setup the device accordingly. If auto-negotiation is enabled, then + * software will have to set the "PAUSE" bits to the correct value in + * the Transmit Config Word Register (TXCW) and re-start auto- + * negotiation. However, if auto-negotiation is disabled, then + * software will have to manually configure the two flow control enable + * bits in the CTRL register. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but we + * do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + */ + switch (mac->fc) { + case e1000_fc_none: + /* Flow control completely disabled by a software over-ride. */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); + break; + case e1000_fc_rx_pause: + /* RX Flow control is enabled and TX Flow control is disabled + * by a software over-ride. Since there really isn't a way to + * advertise that we are capable of RX Pause ONLY, we will + * advertise that we support both symmetric and asymmetric RX + * PAUSE. Later, we will disable the adapter's ability to send + * PAUSE frames. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + case e1000_fc_tx_pause: + /* TX Flow control is enabled, and RX Flow control is disabled, + * by a software over-ride. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); + break; + case e1000_fc_full: + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + return -E1000_ERR_CONFIG; + break; + } + + ew32(TXCW, txcw); + mac->txcw = txcw; + + return 0; +} + +/** + * e1000_poll_fiber_serdes_link_generic - Poll for link up + * @hw: pointer to the HW structure + * + * Polls for link up by reading the status register, if link fails to come + * up with auto-negotiation, then the link is forced if a signal is detected. + **/ +static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 i, status; + s32 ret_val; + + /* If we have a signal (the cable is plugged in, or assumed true for + * serdes media) then poll for a "Link-Up" indication in the Device + * Status Register. Time-out if a link isn't seen in 500 milliseconds + * seconds (Auto-negotiation should complete in less than 500 + * milliseconds even if the other end is doing it in SW). + */ + for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { + msleep(10); + status = er32(STATUS); + if (status & E1000_STATUS_LU) + break; + } + if (i == FIBER_LINK_UP_LIMIT) { + hw_dbg(hw, "Never got a valid link from auto-neg!!!\n"); + mac->autoneg_failed = 1; + /* AutoNeg failed to achieve a link, so we'll call + * mac->check_for_link. This routine will force the + * link up if we detect a signal. This will allow us to + * communicate with non-autonegotiating link partners. + */ + ret_val = mac->ops.check_for_link(hw); + if (ret_val) { + hw_dbg(hw, "Error while checking for link\n"); + return ret_val; + } + mac->autoneg_failed = 0; + } else { + mac->autoneg_failed = 0; + hw_dbg(hw, "Valid Link Found\n"); + } + + return 0; +} + +/** + * e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes + * @hw: pointer to the HW structure + * + * Configures collision distance and flow control for fiber and serdes + * links. Upon successful setup, poll for link. + **/ +s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val; + + ctrl = er32(CTRL); + + /* Take the link out of reset */ + ctrl &= ~E1000_CTRL_LRST; + + e1000e_config_collision_dist(hw); + + ret_val = e1000_commit_fc_settings_generic(hw); + if (ret_val) + return ret_val; + + /* Since auto-negotiation is enabled, take the link out of reset (the + * link will be in reset, because we previously reset the chip). This + * will restart auto-negotiation. If auto-negotiation is successful + * then the link-up status bit will be set and the flow control enable + * bits (RFCE and TFCE) will be set according to their negotiated value. + */ + hw_dbg(hw, "Auto-negotiation enabled\n"); + + ew32(CTRL, ctrl); + e1e_flush(); + msleep(1); + + /* For these adapters, the SW defineable pin 1 is set when the optics + * detect a signal. If we have a signal, then poll for a "Link-Up" + * indication. + */ + if (hw->media_type == e1000_media_type_internal_serdes || + (er32(CTRL) & E1000_CTRL_SWDPIN1)) { + ret_val = e1000_poll_fiber_serdes_link_generic(hw); + } else { + hw_dbg(hw, "No signal detected\n"); + } + + return 0; +} + +/** + * e1000e_config_collision_dist - Configure collision distance + * @hw: pointer to the HW structure + * + * Configures the collision distance to the default value and is used + * during link setup. Currently no func pointer exists and all + * implementations are handled in the generic version of this function. + **/ +void e1000e_config_collision_dist(struct e1000_hw *hw) +{ + u32 tctl; + + tctl = er32(TCTL); + + tctl &= ~E1000_TCTL_COLD; + tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; + + ew32(TCTL, tctl); + e1e_flush(); +} + +/** + * e1000e_set_fc_watermarks - Set flow control high/low watermarks + * @hw: pointer to the HW structure + * + * Sets the flow control high/low threshold (watermark) registers. If + * flow control XON frame transmission is enabled, then set XON frame + * tansmission as well. + **/ +s32 e1000e_set_fc_watermarks(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 fcrtl = 0, fcrth = 0; + + /* Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames is not enabled, then these + * registers will be set to 0. + */ + if (mac->fc & 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 + * XON frames. + */ + fcrtl = mac->fc_low_water; + fcrtl |= E1000_FCRTL_XONE; + fcrth = mac->fc_high_water; + } + ew32(FCRTL, fcrtl); + ew32(FCRTH, fcrth); + + return 0; +} + +/** + * e1000e_force_mac_fc - Force the MAC's flow control settings + * @hw: pointer to the HW structure + * + * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the + * device control register to reflect the adapter settings. TFCE and RFCE + * need to be explicitly set by software when a copper PHY is used because + * autonegotiation is managed by the PHY rather than the MAC. Software must + * also configure these bits when link is forced on a fiber connection. + **/ +s32 e1000e_force_mac_fc(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl; + + ctrl = er32(CTRL); + + /* Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "mac->fc" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ + hw_dbg(hw, "mac->fc = %u\n", mac->fc); + + switch (mac->fc) { + case e1000_fc_none: + ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; + case e1000_fc_rx_pause: + ctrl &= (~E1000_CTRL_TFCE); + ctrl |= E1000_CTRL_RFCE; + break; + case e1000_fc_tx_pause: + ctrl &= (~E1000_CTRL_RFCE); + ctrl |= E1000_CTRL_TFCE; + break; + case e1000_fc_full: + ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + return -E1000_ERR_CONFIG; + } + + ew32(CTRL, ctrl); + + return 0; +} + +/** + * e1000e_config_fc_after_link_up - Configures flow control after link + * @hw: pointer to the HW structure + * + * Checks the status of auto-negotiation after link up to ensure that the + * speed and duplex were not forced. If the link needed to be forced, then + * flow control needs to be forced also. If auto-negotiation is enabled + * and did not fail, then we configure flow control based on our link + * partner. + **/ +s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val = 0; + u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; + u16 speed, duplex; + + /* Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if (mac->autoneg_failed) { + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) + ret_val = e1000e_force_mac_fc(hw); + } else { + if (hw->media_type == e1000_media_type_copper) + ret_val = e1000e_force_mac_fc(hw); + } + + if (ret_val) { + hw_dbg(hw, "Error forcing flow control settings\n"); + return ret_val; + } + + /* Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if ((hw->media_type == e1000_media_type_copper) && mac->autoneg) { + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg); + if (ret_val) + return ret_val; + ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg); + if (ret_val) + return ret_val; + + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { + hw_dbg(hw, "Copper PHY and Auto Neg " + "has not completed.\n"); + return ret_val; + } + + /* The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement + * Register (Address 4) and the Auto_Negotiation Base + * Page Ability Register (Address 5) to determine how + * flow control was negotiated. + */ + ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg); + if (ret_val) + return ret_val; + ret_val = e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg); + if (ret_val) + return ret_val; + + /* Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | e1000_fc_none + * 0 | 1 | 0 | DC | e1000_fc_none + * 0 | 1 | 1 | 0 | e1000_fc_none + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 1 | 0 | 0 | DC | e1000_fc_none + * 1 | DC | 1 | DC | e1000_fc_full + * 1 | 1 | 0 | 0 | e1000_fc_none + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + /* Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | E1000_fc_full + * + */ + if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (mac->original_fc == e1000_fc_full) { + mac->fc = e1000_fc_full; + hw_dbg(hw, "Flow Control = FULL.\r\n"); + } else { + mac->fc = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = " + "RX PAUSE frames only.\r\n"); + } + } + /* For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * + */ + else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (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)) { + mac->fc = e1000_fc_tx_pause; + hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n"); + } + /* For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (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)) { + mac->fc = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n"); + } + /* Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if ((mac->original_fc == e1000_fc_none) || + (mac->original_fc == e1000_fc_tx_pause)) { + mac->fc = e1000_fc_none; + hw_dbg(hw, "Flow Control = NONE.\r\n"); + } else { + mac->fc = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n"); + } + + /* Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex); + if (ret_val) { + hw_dbg(hw, "Error getting link speed and duplex\n"); + return ret_val; + } + + if (duplex == HALF_DUPLEX) + mac->fc = e1000_fc_none; + + /* Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + ret_val = e1000e_force_mac_fc(hw); + if (ret_val) { + hw_dbg(hw, "Error forcing flow control settings\n"); + return ret_val; + } + } + + return 0; +} + +/** + * e1000e_get_speed_and_duplex_copper - Retreive current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Read the status register for the current speed/duplex and store the current + * speed and duplex for copper connections. + **/ +s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex) +{ + u32 status; + + status = er32(STATUS); + if (status & E1000_STATUS_SPEED_1000) { + *speed = SPEED_1000; + hw_dbg(hw, "1000 Mbs, "); + } else if (status & E1000_STATUS_SPEED_100) { + *speed = SPEED_100; + hw_dbg(hw, "100 Mbs, "); + } else { + *speed = SPEED_10; + hw_dbg(hw, "10 Mbs, "); + } + + if (status & E1000_STATUS_FD) { + *duplex = FULL_DUPLEX; + hw_dbg(hw, "Full Duplex\n"); + } else { + *duplex = HALF_DUPLEX; + hw_dbg(hw, "Half Duplex\n"); + } + + return 0; +} + +/** + * e1000e_get_speed_and_duplex_fiber_serdes - Retreive current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Sets the speed and duplex to gigabit full duplex (the only possible option) + * for fiber/serdes links. + **/ +s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex) +{ + *speed = SPEED_1000; + *duplex = FULL_DUPLEX; + + return 0; +} + +/** + * e1000e_get_hw_semaphore - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +s32 e1000e_get_hw_semaphore(struct e1000_hw *hw) +{ + u32 swsm; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + /* Get the SW semaphore */ + while (i < timeout) { + swsm = er32(SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + udelay(50); + i++; + } + + if (i == timeout) { + hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); + return -E1000_ERR_NVM; + } + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (er32(SWSM) & E1000_SWSM_SWESMBI) + break; + + udelay(50); + } + + if (i == timeout) { + /* Release semaphores */ + e1000e_put_hw_semaphore(hw); + hw_dbg(hw, "Driver can't access the NVM\n"); + return -E1000_ERR_NVM; + } + + return 0; +} + +/** + * e1000e_put_hw_semaphore - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +void e1000e_put_hw_semaphore(struct e1000_hw *hw) +{ + u32 swsm; + + swsm = er32(SWSM); + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + ew32(SWSM, swsm); +} + +/** + * e1000e_get_auto_rd_done - Check for auto read completion + * @hw: pointer to the HW structure + * + * Check EEPROM for Auto Read done bit. + **/ +s32 e1000e_get_auto_rd_done(struct e1000_hw *hw) +{ + s32 i = 0; + + while (i < AUTO_READ_DONE_TIMEOUT) { + if (er32(EECD) & E1000_EECD_AUTO_RD) + break; + msleep(1); + i++; + } + + if (i == AUTO_READ_DONE_TIMEOUT) { + hw_dbg(hw, "Auto read by HW from NVM has not completed.\n"); + return -E1000_ERR_RESET; + } + + return 0; +} + +/** + * e1000e_valid_led_default - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + + if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; + + return 0; +} + +/** + * e1000e_id_led_init - + * @hw: pointer to the HW structure + * + **/ +s32 e1000e_id_led_init(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + const u32 ledctl_mask = 0x000000FF; + const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; + const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; + u16 data, i, temp; + const u16 led_mask = 0x0F; + + ret_val = hw->nvm.ops.valid_led_default(hw, &data); + if (ret_val) + return ret_val; + + mac->ledctl_default = er32(LEDCTL); + mac->ledctl_mode1 = mac->ledctl_default; + mac->ledctl_mode2 = mac->ledctl_default; + + for (i = 0; i < 4; i++) { + temp = (data >> (i << 2)) & led_mask; + switch (temp) { + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: + mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode1 |= ledctl_on << (i << 3); + break; + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode1 |= ledctl_off << (i << 3); + break; + default: + /* Do nothing */ + break; + } + switch (temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: + mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode2 |= ledctl_on << (i << 3); + break; + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode2 |= ledctl_off << (i << 3); + break; + default: + /* Do nothing */ + break; + } + } + + return 0; +} + +/** + * e1000e_cleanup_led_generic - Set LED config to default operation + * @hw: pointer to the HW structure + * + * Remove the current LED configuration and set the LED configuration + * to the default value, saved from the EEPROM. + **/ +s32 e1000e_cleanup_led_generic(struct e1000_hw *hw) +{ + ew32(LEDCTL, hw->mac.ledctl_default); + return 0; +} + +/** + * e1000e_blink_led - Blink LED + * @hw: pointer to the HW structure + * + * Blink the led's which are set to be on. + **/ +s32 e1000e_blink_led(struct e1000_hw *hw) +{ + u32 ledctl_blink = 0; + u32 i; + + if (hw->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)); + } + + ew32(LEDCTL, ledctl_blink); + + return 0; +} + +/** + * e1000e_led_on_generic - Turn LED on + * @hw: pointer to the HW structure + * + * Turn LED on. + **/ +s32 e1000e_led_on_generic(struct e1000_hw *hw) +{ + u32 ctrl; + + switch (hw->media_type) { + case e1000_media_type_fiber: + ctrl = er32(CTRL); + ctrl &= ~E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + ew32(CTRL, ctrl); + break; + case e1000_media_type_copper: + ew32(LEDCTL, hw->mac.ledctl_mode2); + break; + default: + break; + } + + return 0; +} + +/** + * e1000e_led_off_generic - Turn LED off + * @hw: pointer to the HW structure + * + * Turn LED off. + **/ +s32 e1000e_led_off_generic(struct e1000_hw *hw) +{ + u32 ctrl; + + switch (hw->media_type) { + case e1000_media_type_fiber: + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + ew32(CTRL, ctrl); + break; + case e1000_media_type_copper: + ew32(LEDCTL, hw->mac.ledctl_mode1); + break; + default: + break; + } + + return 0; +} + +/** + * e1000e_set_pcie_no_snoop - Set PCI-express capabilities + * @hw: pointer to the HW structure + * @no_snoop: bitmap of snoop events + * + * Set the PCI-express register to snoop for events enabled in 'no_snoop'. + **/ +void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop) +{ + u32 gcr; + + if (no_snoop) { + gcr = er32(GCR); + gcr &= ~(PCIE_NO_SNOOP_ALL); + gcr |= no_snoop; + ew32(GCR, gcr); + } +} + +/** + * e1000e_disable_pcie_master - Disables PCI-express master access + * @hw: pointer to the HW structure + * + * Returns 0 if successful, else returns -10 + * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued + * the master requests to be disabled. + * + * Disables PCI-Express master access and verifies there are no pending + * requests. + **/ +s32 e1000e_disable_pcie_master(struct e1000_hw *hw) +{ + u32 ctrl; + s32 timeout = MASTER_DISABLE_TIMEOUT; + + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; + ew32(CTRL, ctrl); + + while (timeout) { + if (!(er32(STATUS) & + E1000_STATUS_GIO_MASTER_ENABLE)) + break; + udelay(100); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "Master requests are pending.\n"); + return -E1000_ERR_MASTER_REQUESTS_PENDING; + } + + return 0; +} + +/** + * e1000e_reset_adaptive - Reset Adaptive Interframe Spacing + * @hw: pointer to the HW structure + * + * Reset the Adaptive Interframe Spacing throttle to default values. + **/ +void e1000e_reset_adaptive(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + + mac->current_ifs_val = 0; + mac->ifs_min_val = IFS_MIN; + mac->ifs_max_val = IFS_MAX; + mac->ifs_step_size = IFS_STEP; + mac->ifs_ratio = IFS_RATIO; + + mac->in_ifs_mode = 0; + ew32(AIT, 0); +} + +/** + * e1000e_update_adaptive - Update Adaptive Interframe Spacing + * @hw: pointer to the HW structure + * + * Update the Adaptive Interframe Spacing Throttle value based on the + * time between transmitted packets and time between collisions. + **/ +void e1000e_update_adaptive(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + + if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) { + if (mac->tx_packet_delta > MIN_NUM_XMITS) { + mac->in_ifs_mode = 1; + if (mac->current_ifs_val < mac->ifs_max_val) { + if (!mac->current_ifs_val) + mac->current_ifs_val = mac->ifs_min_val; + else + mac->current_ifs_val += + mac->ifs_step_size; + ew32(AIT, + mac->current_ifs_val); + } + } + } else { + if (mac->in_ifs_mode && + (mac->tx_packet_delta <= MIN_NUM_XMITS)) { + mac->current_ifs_val = 0; + mac->in_ifs_mode = 0; + ew32(AIT, 0); + } + } +} + +/** + * e1000_raise_eec_clk - Raise EEPROM clock + * @hw: pointer to the HW structure + * @eecd: pointer to the EEPROM + * + * Enable/Raise the EEPROM clock bit. + **/ +static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) +{ + *eecd = *eecd | E1000_EECD_SK; + ew32(EECD, *eecd); + e1e_flush(); + udelay(hw->nvm.delay_usec); +} + +/** + * e1000_lower_eec_clk - Lower EEPROM clock + * @hw: pointer to the HW structure + * @eecd: pointer to the EEPROM + * + * Clear/Lower the EEPROM clock bit. + **/ +static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) +{ + *eecd = *eecd & ~E1000_EECD_SK; + ew32(EECD, *eecd); + e1e_flush(); + udelay(hw->nvm.delay_usec); +} + +/** + * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM + * @hw: pointer to the HW structure + * @data: data to send to the EEPROM + * @count: number of bits to shift out + * + * We need to shift 'count' bits out to the EEPROM. So, the value in the + * "data" parameter will be shifted out to the EEPROM one bit at a time. + * In order to do this, "data" must be broken down into bits. + **/ +static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + u32 mask; + + mask = 0x01 << (count - 1); + if (nvm->type == e1000_nvm_eeprom_spi) + eecd |= E1000_EECD_DO; + + do { + eecd &= ~E1000_EECD_DI; + + if (data & mask) + eecd |= E1000_EECD_DI; + + ew32(EECD, eecd); + e1e_flush(); + + udelay(nvm->delay_usec); + + e1000_raise_eec_clk(hw, &eecd); + e1000_lower_eec_clk(hw, &eecd); + + mask >>= 1; + } while (mask); + + eecd &= ~E1000_EECD_DI; + ew32(EECD, eecd); +} + +/** + * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM + * @hw: pointer to the HW structure + * @count: number of bits to shift in + * + * In order to read a register from the EEPROM, we need to shift 'count' bits + * in from the EEPROM. Bits are "shifted in" by raising the clock input to + * the EEPROM (setting the SK bit), and then reading the value of the data out + * "DO" bit. During this "shifting in" process the data in "DI" bit should + * always be clear. + **/ +static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count) +{ + u32 eecd; + u32 i; + u16 data; + + eecd = er32(EECD); + + eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); + data = 0; + + for (i = 0; i < count; i++) { + data <<= 1; + e1000_raise_eec_clk(hw, &eecd); + + eecd = er32(EECD); + + eecd &= ~E1000_EECD_DI; + if (eecd & E1000_EECD_DO) + data |= 1; + + e1000_lower_eec_clk(hw, &eecd); + } + + return data; +} + +/** + * e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion + * @hw: pointer to the HW structure + * @ee_reg: EEPROM flag for polling + * + * Polls the EEPROM status bit for either read or write completion based + * upon the value of 'ee_reg'. + **/ +s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) +{ + u32 attempts = 100000; + u32 i, reg = 0; + + for (i = 0; i < attempts; i++) { + if (ee_reg == E1000_NVM_POLL_READ) + reg = er32(EERD); + else + reg = er32(EEWR); + + if (reg & E1000_NVM_RW_REG_DONE) + return 0; + + udelay(5); + } + + return -E1000_ERR_NVM; +} + +/** + * e1000e_acquire_nvm - Generic request for access to EEPROM + * @hw: pointer to the HW structure + * + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -E1000_ERR_NVM (-1). + **/ +s32 e1000e_acquire_nvm(struct e1000_hw *hw) +{ + u32 eecd = er32(EECD); + s32 timeout = E1000_NVM_GRANT_ATTEMPTS; + + ew32(EECD, eecd | E1000_EECD_REQ); + eecd = er32(EECD); + + while (timeout) { + if (eecd & E1000_EECD_GNT) + break; + udelay(5); + eecd = er32(EECD); + timeout--; + } + + if (!timeout) { + eecd &= ~E1000_EECD_REQ; + ew32(EECD, eecd); + hw_dbg(hw, "Could not acquire NVM grant\n"); + return -E1000_ERR_NVM; + } + + return 0; +} + +/** + * e1000_standby_nvm - Return EEPROM to standby state + * @hw: pointer to the HW structure + * + * Return the EEPROM to a standby state. + **/ +static void e1000_standby_nvm(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + + if (nvm->type == e1000_nvm_eeprom_spi) { + /* Toggle CS to flush commands */ + eecd |= E1000_EECD_CS; + ew32(EECD, eecd); + e1e_flush(); + udelay(nvm->delay_usec); + eecd &= ~E1000_EECD_CS; + ew32(EECD, eecd); + e1e_flush(); + udelay(nvm->delay_usec); + } +} + +/** + * e1000_stop_nvm - Terminate EEPROM command + * @hw: pointer to the HW structure + * + * Terminates the current command by inverting the EEPROM's chip select pin. + **/ +static void e1000_stop_nvm(struct e1000_hw *hw) +{ + u32 eecd; + + eecd = er32(EECD); + if (hw->nvm.type == e1000_nvm_eeprom_spi) { + /* Pull CS high */ + eecd |= E1000_EECD_CS; + e1000_lower_eec_clk(hw, &eecd); + } +} + +/** + * e1000e_release_nvm - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit. + **/ +void e1000e_release_nvm(struct e1000_hw *hw) +{ + u32 eecd; + + e1000_stop_nvm(hw); + + eecd = er32(EECD); + eecd &= ~E1000_EECD_REQ; + ew32(EECD, eecd); +} + +/** + * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write + * @hw: pointer to the HW structure + * + * Setups the EEPROM for reading and writing. + **/ +static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + u16 timeout = 0; + u8 spi_stat_reg; + + if (nvm->type == e1000_nvm_eeprom_spi) { + /* Clear SK and CS */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + ew32(EECD, eecd); + udelay(1); + timeout = NVM_MAX_RETRY_SPI; + + /* Read "Status Register" repeatedly until the LSB is cleared. + * The EEPROM will signal that the command has been completed + * by clearing bit 0 of the internal status register. If it's + * not cleared within 'timeout', then error out. */ + while (timeout) { + e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI, + hw->nvm.opcode_bits); + spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8); + if (!(spi_stat_reg & NVM_STATUS_RDY_SPI)) + break; + + udelay(5); + e1000_standby_nvm(hw); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "SPI NVM Status error\n"); + return -E1000_ERR_NVM; + } + } + + return 0; +} + +/** + * e1000e_read_nvm_spi - Read EEPROM's using SPI + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM. + **/ +s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i = 0; + s32 ret_val; + u16 word_in; + u8 read_opcode = NVM_READ_OPCODE_SPI; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + ret_val = nvm->ops.acquire_nvm(hw); + if (ret_val) + return ret_val; + + ret_val = e1000_ready_nvm_eeprom(hw); + if (ret_val) { + nvm->ops.release_nvm(hw); + return ret_val; + } + + e1000_standby_nvm(hw); + + if ((nvm->address_bits == 8) && (offset >= 128)) + read_opcode |= NVM_A8_OPCODE_SPI; + + /* Send the READ command (opcode + addr) */ + e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); + e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits); + + /* Read the data. SPI NVMs increment the address with each byte + * read and will roll over if reading beyond the end. This allows + * us to read the whole NVM from any offset */ + for (i = 0; i < words; i++) { + word_in = e1000_shift_in_eec_bits(hw, 16); + data[i] = (word_in >> 8) | (word_in << 8); + } + + nvm->ops.release_nvm(hw); + return 0; +} + +/** + * e1000e_read_nvm_eerd - Reads EEPROM using EERD register + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i, eerd = 0; + s32 ret_val = 0; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + for (i = 0; i < words; i++) { + eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + + E1000_NVM_RW_REG_START; + + ew32(EERD, eerd); + ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); + if (ret_val) + break; + + data[i] = (er32(EERD) >> + E1000_NVM_RW_REG_DATA); + } + + return ret_val; +} + +/** + * e1000e_write_nvm_spi - Write to EEPROM using SPI + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * Writes data to EEPROM at offset using SPI interface. + * + * If e1000e_update_nvm_checksum is not called after this function , the + * EEPROM will most likley contain an invalid checksum. + **/ +s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + s32 ret_val; + u16 widx = 0; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + ret_val = nvm->ops.acquire_nvm(hw); + if (ret_val) + return ret_val; + + msleep(10); + + while (widx < words) { + u8 write_opcode = NVM_WRITE_OPCODE_SPI; + + ret_val = e1000_ready_nvm_eeprom(hw); + if (ret_val) { + nvm->ops.release_nvm(hw); + return ret_val; + } + + e1000_standby_nvm(hw); + + /* Send the WRITE ENABLE command (8 bit opcode) */ + e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, + nvm->opcode_bits); + + e1000_standby_nvm(hw); + + /* Some SPI eeproms use the 8th address bit embedded in the + * opcode */ + if ((nvm->address_bits == 8) && (offset >= 128)) + write_opcode |= NVM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); + e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), + nvm->address_bits); + + /* Loop to allow for up to whole page write of eeprom */ + while (widx < words) { + u16 word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); + e1000_shift_out_eec_bits(hw, word_out, 16); + widx++; + + if ((((offset + widx) * 2) % nvm->page_size) == 0) { + e1000_standby_nvm(hw); + break; + } + } + } + + msleep(10); + return 0; +} + +/** + * e1000e_read_mac_addr - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the EEPROM and stores the value. + * Since devices with two ports use the same EEPROM, we increment the + * last bit in the MAC address for the second port. + **/ +s32 e1000e_read_mac_addr(struct e1000_hw *hw) +{ + s32 ret_val; + u16 offset, nvm_data, i; + + for (i = 0; i < ETH_ALEN; i += 2) { + offset = i >> 1; + ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); + hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); + } + + /* Flip last bit of mac address if we're on second port */ + if (hw->bus.func == E1000_FUNC_1) + hw->mac.perm_addr[5] ^= 1; + + for (i = 0; i < ETH_ALEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i]; + + return 0; +} + +/** + * e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw) +{ + s32 ret_val; + u16 checksum = 0; + u16 i, nvm_data; + + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + ret_val = e1000_read_nvm(hw, i, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + checksum += nvm_data; + } + + if (checksum != (u16) NVM_SUM) { + hw_dbg(hw, "NVM Checksum Invalid\n"); + return -E1000_ERR_NVM; + } + + return 0; +} + +/** + * e1000e_update_nvm_checksum_generic - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + **/ +s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw) +{ + s32 ret_val; + u16 checksum = 0; + u16 i, nvm_data; + + for (i = 0; i < NVM_CHECKSUM_REG; i++) { + ret_val = e1000_read_nvm(hw, i, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error while updating checksum.\n"); + return ret_val; + } + checksum += nvm_data; + } + checksum = (u16) NVM_SUM - checksum; + ret_val = e1000_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum); + if (ret_val) + hw_dbg(hw, "NVM Write Error while updating checksum.\n"); + + return ret_val; +} + +/** + * e1000e_reload_nvm - Reloads EEPROM + * @hw: pointer to the HW structure + * + * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the + * extended control register. + **/ +void e1000e_reload_nvm(struct e1000_hw *hw) +{ + u32 ctrl_ext; + + udelay(10); + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); +} + +/** + * e1000_calculate_checksum - Calculate checksum for buffer + * @buffer: pointer to EEPROM + * @length: size of EEPROM to calculate a checksum for + * + * Calculates the checksum for some buffer on a specified length. The + * checksum calculated is returned. + **/ +static u8 e1000_calculate_checksum(u8 *buffer, u32 length) +{ + u32 i; + u8 sum = 0; + + if (!buffer) + return 0; + + for (i = 0; i < length; i++) + sum += buffer[i]; + + return (u8) (0 - sum); +} + +/** + * e1000_mng_enable_host_if - Checks host interface is enabled + * @hw: pointer to the HW structure + * + * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND + * + * This function checks whether the HOST IF is enabled for command operaton + * and also checks whether the previous command is completed. It busy waits + * in case of previous command is not completed. + **/ +static s32 e1000_mng_enable_host_if(struct e1000_hw *hw) +{ + u32 hicr; + u8 i; + + /* Check that the host interface is enabled. */ + hicr = er32(HICR); + if ((hicr & E1000_HICR_EN) == 0) { + hw_dbg(hw, "E1000_HOST_EN bit disabled.\n"); + return -E1000_ERR_HOST_INTERFACE_COMMAND; + } + /* check the previous command is completed */ + for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { + hicr = er32(HICR); + if (!(hicr & E1000_HICR_C)) + break; + mdelay(1); + } + + if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { + hw_dbg(hw, "Previous command timeout failed .\n"); + return -E1000_ERR_HOST_INTERFACE_COMMAND; + } + + return 0; +} + +/** + * e1000e_check_mng_mode - check managament mode + * @hw: pointer to the HW structure + * + * Reads the firmware semaphore register and returns true (>0) if + * manageability is enabled, else false (0). + **/ +bool e1000e_check_mng_mode(struct e1000_hw *hw) +{ + u32 fwsm = er32(FWSM); + + return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab; +} + +/** + * e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX + * @hw: pointer to the HW structure + * + * Enables packet filtering on transmit packets if manageability is enabled + * and host interface is enabled. + **/ +bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw) +{ + struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; + u32 *buffer = (u32 *)&hw->mng_cookie; + u32 offset; + s32 ret_val, hdr_csum, csum; + u8 i, len; + + /* No manageability, no filtering */ + if (!e1000e_check_mng_mode(hw)) { + hw->mac.tx_pkt_filtering = 0; + return 0; + } + + /* If we can't read from the host interface for whatever + * reason, disable filtering. + */ + ret_val = e1000_mng_enable_host_if(hw); + if (ret_val != 0) { + hw->mac.tx_pkt_filtering = 0; + return ret_val; + } + + /* Read in the header. Length and offset are in dwords. */ + len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; + offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; + for (i = 0; i < len; i++) + *(buffer + i) = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset + i); + hdr_csum = hdr->checksum; + hdr->checksum = 0; + csum = e1000_calculate_checksum((u8 *)hdr, + E1000_MNG_DHCP_COOKIE_LENGTH); + /* If either the checksums or signature don't match, then + * the cookie area isn't considered valid, in which case we + * take the safe route of assuming Tx filtering is enabled. + */ + if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) { + hw->mac.tx_pkt_filtering = 1; + return 1; + } + + /* Cookie area is valid, make the final check for filtering. */ + if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) { + hw->mac.tx_pkt_filtering = 0; + return 0; + } + + hw->mac.tx_pkt_filtering = 1; + return 1; +} + +/** + * e1000_mng_write_cmd_header - Writes manageability command header + * @hw: pointer to the HW structure + * @hdr: pointer to the host interface command header + * + * Writes the command header after does the checksum calculation. + **/ +static s32 e1000_mng_write_cmd_header(struct e1000_hw *hw, + struct e1000_host_mng_command_header *hdr) +{ + u16 i, length = sizeof(struct e1000_host_mng_command_header); + + /* Write the whole command header structure with new checksum. */ + + hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); + + length >>= 2; + /* Write the relevant command block into the ram area. */ + for (i = 0; i < length; i++) { + E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, i, + *((u32 *) hdr + i)); + e1e_flush(); + } + + return 0; +} + +/** + * e1000_mng_host_if_write - Writes to the manageability host interface + * @hw: pointer to the HW structure + * @buffer: pointer to the host interface buffer + * @length: size of the buffer + * @offset: location in the buffer to write to + * @sum: sum of the data (not checksum) + * + * This function writes the buffer content at the offset given on the host if. + * It also does alignment considerations to do the writes in most efficient + * way. Also fills up the sum of the buffer in *buffer parameter. + **/ +static s32 e1000_mng_host_if_write(struct e1000_hw *hw, u8 *buffer, + u16 length, u16 offset, u8 *sum) +{ + u8 *tmp; + u8 *bufptr = buffer; + u32 data = 0; + u16 remaining, i, j, prev_bytes; + + /* sum = only sum of the data and it is not checksum */ + + if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) + return -E1000_ERR_PARAM; + + tmp = (u8 *)&data; + prev_bytes = offset & 0x3; + offset >>= 2; + + if (prev_bytes) { + data = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset); + for (j = prev_bytes; j < sizeof(u32); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset, data); + length -= j - prev_bytes; + offset++; + } + + remaining = length & 0x3; + length -= remaining; + + /* Calculate length in DWORDs */ + length >>= 2; + + /* The device driver writes the relevant command block into the + * ram area. */ + for (i = 0; i < length; i++) { + for (j = 0; j < sizeof(u32); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + + E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data); + } + if (remaining) { + for (j = 0; j < sizeof(u32); j++) { + if (j < remaining) + *(tmp + j) = *bufptr++; + else + *(tmp + j) = 0; + + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data); + } + + return 0; +} + +/** + * e1000e_mng_write_dhcp_info - Writes DHCP info to host interface + * @hw: pointer to the HW structure + * @buffer: pointer to the host interface + * @length: size of the buffer + * + * Writes the DHCP information to the host interface. + **/ +s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length) +{ + struct e1000_host_mng_command_header hdr; + s32 ret_val; + u32 hicr; + + hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; + hdr.command_length = length; + hdr.reserved1 = 0; + hdr.reserved2 = 0; + hdr.checksum = 0; + + /* Enable the host interface */ + ret_val = e1000_mng_enable_host_if(hw); + if (ret_val) + return ret_val; + + /* Populate the host interface with the contents of "buffer". */ + ret_val = e1000_mng_host_if_write(hw, buffer, length, + sizeof(hdr), &(hdr.checksum)); + if (ret_val) + return ret_val; + + /* Write the manageability command header */ + ret_val = e1000_mng_write_cmd_header(hw, &hdr); + if (ret_val) + return ret_val; + + /* Tell the ARC a new command is pending. */ + hicr = er32(HICR); + ew32(HICR, hicr | E1000_HICR_C); + + return 0; +} + +/** + * e1000e_enable_mng_pass_thru - Enable processing of ARP's + * @hw: pointer to the HW structure + * + * Verifies the hardware needs to allow ARPs to be processed by the host. + **/ +bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw) +{ + u32 manc; + u32 fwsm, factps; + bool ret_val = 0; + + manc = er32(MANC); + + if (!(manc & E1000_MANC_RCV_TCO_EN) || + !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + return ret_val; + + if (hw->mac.arc_subsystem_valid) { + fwsm = er32(FWSM); + factps = er32(FACTPS); + + if (!(factps & E1000_FACTPS_MNGCG) && + ((fwsm & E1000_FWSM_MODE_MASK) == + (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { + ret_val = 1; + return ret_val; + } + } else { + if ((manc & E1000_MANC_SMBUS_EN) && + !(manc & E1000_MANC_ASF_EN)) { + ret_val = 1; + return ret_val; + } + } + + return ret_val; +} + +s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num) +{ + s32 ret_val; + u16 nvm_data; + + ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *part_num = (u32)(nvm_data << 16); + + ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *part_num |= nvm_data; + + return 0; +} diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c new file mode 100644 index 000000000000..eeb40ccbcb22 --- /dev/null +++ b/drivers/net/e1000e/netdev.c @@ -0,0 +1,4441 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "e1000.h" + +#define DRV_VERSION "0.2.0" +char e1000e_driver_name[] = "e1000e"; +const char e1000e_driver_version[] = DRV_VERSION; + +static const struct e1000_info *e1000_info_tbl[] = { + [board_82571] = &e1000_82571_info, + [board_82572] = &e1000_82572_info, + [board_82573] = &e1000_82573_info, + [board_80003es2lan] = &e1000_es2_info, + [board_ich8lan] = &e1000_ich8_info, + [board_ich9lan] = &e1000_ich9_info, +}; + +#ifdef DEBUG +/** + * e1000_get_hw_dev_name - return device name string + * used by hardware layer to print debugging information + **/ +char *e1000e_get_hw_dev_name(struct e1000_hw *hw) +{ + struct e1000_adapter *adapter = hw->back; + struct net_device *netdev = adapter->netdev; + return netdev->name; +} +#endif + +/** + * e1000_desc_unused - calculate if we have unused descriptors + **/ +static int e1000_desc_unused(struct e1000_ring *ring) +{ + if (ring->next_to_clean > ring->next_to_use) + return ring->next_to_clean - ring->next_to_use - 1; + + return ring->count + ring->next_to_clean - ring->next_to_use - 1; +} + +/** + * 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, + struct net_device *netdev, + struct sk_buff *skb, + u8 status, u16 vlan) +{ + skb->protocol = eth_type_trans(skb, netdev); + + if (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); + + netdev->last_rx = jiffies; +} + +/** + * e1000_rx_checksum - Receive Checksum Offload for 82543 + * @adapter: board private structure + * @status_err: receive descriptor status and error fields + * @csum: receive descriptor csum field + * @sk_buff: socket buffer with received data + **/ +static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, + u32 csum, struct sk_buff *skb) +{ + u16 status = (u16)status_err; + u8 errors = (u8)(status_err >> 24); + skb->ip_summed = CHECKSUM_NONE; + + /* Ignore Checksum bit is set */ + if (status & E1000_RXD_STAT_IXSM) + return; + /* TCP/UDP checksum error bit is set */ + if (errors & E1000_RXD_ERR_TCPE) { + /* let the stack verify checksum errors */ + adapter->hw_csum_err++; + return; + } + + /* TCP/UDP Checksum has not been calculated */ + if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) + return; + + /* It must be a TCP or UDP packet with a valid checksum */ + if (status & E1000_RXD_STAT_TCPCS) { + /* TCP checksum is good */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + /* IP fragment with UDP payload */ + /* Hardware complements the payload checksum, so we undo it + * and then put the value in host order for further stack use. + */ + csum = ntohl(csum ^ 0xFFFF); + skb->csum = csum; + skb->ip_summed = CHECKSUM_COMPLETE; + } + adapter->hw_csum_good++; +} + +/** + * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended + * @adapter: address of board private structure + **/ +static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = adapter->rx_buffer_len + 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 map_skb; + } + + skb = netdev_alloc_skb(netdev, bufsz); + if (!skb) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* 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; +map_skb: + buffer_info->dma = pci_map_single(pdev, skb->data, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&pdev->dev, "RX DMA map failed\n"); + adapter->rx_dma_failed++; + break; + } + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (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->tail); + } +} + +/** + * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split + * @adapter: address of board private structure + **/ +static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union e1000_rx_desc_packet_split *rx_desc; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct sk_buff *skb; + unsigned int i, j; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS) + + j]; + if (j < adapter->rx_ps_pages) { + if (!ps_page->page) { + ps_page->page = alloc_page(GFP_ATOMIC); + if (!ps_page->page) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + ps_page->dma = pci_map_page(pdev, + ps_page->page, + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error( + ps_page->dma)) { + dev_err(&adapter->pdev->dev, + "RX DMA page map failed\n"); + adapter->rx_dma_failed++; + goto no_buffers; + } + } + /* + * Refresh the desc even if buffer_addrs + * didn't change because each write-back + * erases this info. + */ + rx_desc->read.buffer_addr[j+1] = + cpu_to_le64(ps_page->dma); + } else { + rx_desc->read.buffer_addr[j+1] = ~0; + } + } + + skb = netdev_alloc_skb(netdev, + adapter->rx_ps_bsize0 + NET_IP_ALIGN); + + if (!skb) { + adapter->alloc_rx_buff_failed++; + break; + } + + /* 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->dma = pci_map_single(pdev, skb->data, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&pdev->dev, "RX DMA map failed\n"); + adapter->rx_dma_failed++; + /* cleanup skb */ + dev_kfree_skb_any(skb); + buffer_info->skb = NULL; + break; + } + + rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma); + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + +no_buffers: + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + + if (!(i--)) + 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(); + /* Hardware increments by 16 bytes, but packet split + * descriptors are 32 bytes...so we increment tail + * twice as much. + */ + writel(i<<1, adapter->hw.hw_addr + rx_ring->tail); + } +} + +/** + * e1000_alloc_rx_buffers_jumbo - Replace used jumbo receive buffers + * + * @adapter: address of board private structure + * @cleaned_count: number of buffers to allocate this pass + **/ +static void e1000_alloc_rx_buffers_jumbo(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + 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 (!skb) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* 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; +check_page: + /* allocate a new page if necessary */ + if (!buffer_info->page) { + buffer_info->page = alloc_page(GFP_ATOMIC); + if (!buffer_info->page) { + adapter->alloc_rx_buff_failed++; + break; + } + } + + if (!buffer_info->dma) + buffer_info->dma = pci_map_page(pdev, + buffer_info->page, 0, + PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&adapter->pdev->dev, "RX DMA page map failed\n"); + adapter->rx_dma_failed++; + break; + } + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (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->tail); + } +} + +/** + * e1000_clean_rx_irq - Send received data up the network stack; legacy + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = 0; + 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; + + prefetch(skb->data - NET_IP_ALIGN); + + i++; + 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 = 1; + cleaned_count++; + pci_unmap_single(pdev, + buffer_info->dma, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* !EOP means multiple descriptors were used to store a single + * packet, also make sure the frame isn't just CRC only */ + if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { + /* All receives must fit into a single buffer */ + ndev_dbg(netdev, "%s: Receive packet consumed " + "multiple buffers\n", netdev->name); + /* recycle */ + buffer_info->skb = skb; + goto next_desc; + } + + if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + /* recycle */ + buffer_info->skb = skb; + goto next_desc; + } + + /* adjust length to remove Ethernet CRC */ + length -= 4; + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += length; + total_rx_packets++; + + /* code added for copybreak, this should improve + * performance for small packets with large amounts + * of reassembly being done in the stack */ + if (length < copybreak) { + struct sk_buff *new_skb = + netdev_alloc_skb(netdev, length + NET_IP_ALIGN); + if (new_skb) { + skb_reserve(new_skb, NET_IP_ALIGN); + memcpy(new_skb->data - NET_IP_ALIGN, + skb->data - NET_IP_ALIGN, + length + NET_IP_ALIGN); + /* save the skb in buffer_info as good */ + buffer_info->skb = skb; + skb = new_skb; + } + /* else just continue with the old one */ + } + /* end copybreak code */ + skb_put(skb, length); + + /* Receive Checksum Offload */ + e1000_rx_checksum(adapter, + (u32)(status) | + ((u32)(rx_desc->errors) << 24), + le16_to_cpu(rx_desc->csum), skb); + + e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= E1000_RX_BUFFER_WRITE) { + adapter->alloc_rx_buf(adapter, 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, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + return cleaned; +} + +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; +} + +static void e1000_put_txbuf(struct e1000_adapter *adapter, + struct e1000_buffer *buffer_info) +{ + if (buffer_info->dma) { + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { + dev_kfree_skb_any(buffer_info->skb); + buffer_info->skb = NULL; + } +} + +static void e1000_print_tx_hang(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + unsigned int i = tx_ring->next_to_clean; + unsigned int eop = tx_ring->buffer_info[i].next_to_watch; + struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop); + struct net_device *netdev = adapter->netdev; + + /* detected Tx unit hang */ + ndev_err(netdev, + "Detected Tx Unit Hang:\n" + " TDH <%x>\n" + " TDT <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "buffer_info[next_to_clean]:\n" + " time_stamp <%lx>\n" + " next_to_watch <%x>\n" + " jiffies <%lx>\n" + " next_to_watch.status <%x>\n", + readl(adapter->hw.hw_addr + tx_ring->head), + readl(adapter->hw.hw_addr + tx_ring->tail), + tx_ring->next_to_use, + tx_ring->next_to_clean, + tx_ring->buffer_info[eop].time_stamp, + eop, + jiffies, + eop_desc->upper.fields.status); +} + +/** + * e1000_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_tx_desc *tx_desc, *eop_desc; + struct e1000_buffer *buffer_info; + unsigned int i, eop; + unsigned int count = 0; + bool cleaned = 0; + unsigned int total_tx_bytes = 0, total_tx_packets = 0; + + i = tx_ring->next_to_clean; + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); + + while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + for (cleaned = 0; !cleaned; ) { + tx_desc = E1000_TX_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; + cleaned = (i == eop); + + if (cleaned) { + struct sk_buff *skb = buffer_info->skb; + unsigned int segs, bytecount; + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + + skb->len; + total_tx_packets += segs; + total_tx_bytes += bytecount; + } + + e1000_put_txbuf(adapter, buffer_info); + tx_desc->upper.data = 0; + + i++; + if (i == tx_ring->count) + i = 0; + } + + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); +#define E1000_TX_WEIGHT 64 + /* weight of a sort for tx, to avoid endless transmit cleanup */ + if (count++ == E1000_TX_WEIGHT) + break; + } + + tx_ring->next_to_clean = i; + +#define TX_WAKE_THRESHOLD 32 + if (cleaned && netif_carrier_ok(netdev) && + e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) { + /* Make sure that anybody stopping the queue after this + * sees the new next_to_clean. + */ + smp_mb(); + + if (netif_queue_stopped(netdev) && + !(test_bit(__E1000_DOWN, &adapter->state))) { + netif_wake_queue(netdev); + ++adapter->restart_queue; + } + } + + if (adapter->detect_tx_hung) { + /* Detect a transmit hang in hardware, this serializes the + * check with the clearing of time_stamp and movement of i */ + adapter->detect_tx_hung = 0; + if (tx_ring->buffer_info[eop].dma && + time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + + (adapter->tx_timeout_factor * HZ)) + && !(er32(STATUS) & + E1000_STATUS_TXOFF)) { + e1000_print_tx_hang(adapter); + netif_stop_queue(netdev); + } + } + adapter->total_tx_bytes += total_tx_bytes; + adapter->total_tx_packets += total_tx_packets; + return cleaned; +} + +/** + * e1000_clean_rx_irq_jumbo - Send received data up the network stack; legacy + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +static bool e1000_clean_rx_irq_jumbo(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = 0; + 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; + + i++; + 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 = 1; + cleaned_count++; + pci_unmap_page(pdev, + buffer_info->dma, + PAGE_SIZE, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* errors is only valid for DD + EOP descriptors */ + if ((status & E1000_RXD_STAT_EOP) && + (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { + /* 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)) { + ndev_err(netdev, "__pskb_pull_tail failed.\n"); + dev_kfree_skb(skb); + goto next_desc; + } + + e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= E1000_RX_BUFFER_WRITE) { + adapter->alloc_rx_buf(adapter, 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, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + return cleaned; +} + +/** + * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +{ + union e1000_rx_desc_packet_split *rx_desc, *next_rxd; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info, *next_buffer; + struct e1000_ps_page *ps_page; + struct sk_buff *skb; + unsigned int i, j; + u32 length, staterr; + int cleaned_count = 0; + bool cleaned = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.middle.status_error); + buffer_info = &rx_ring->buffer_info[i]; + + while (staterr & E1000_RXD_STAT_DD) { + if (*work_done >= work_to_do) + break; + (*work_done)++; + skb = buffer_info->skb; + + /* in the packet split case this is header only */ + prefetch(skb->data - NET_IP_ALIGN); + + i++; + if (i == rx_ring->count) + i = 0; + next_rxd = E1000_RX_DESC_PS(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = 1; + cleaned_count++; + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + if (!(staterr & E1000_RXD_STAT_EOP)) { + ndev_dbg(netdev, "%s: Packet Split buffers didn't pick " + "up the full packet\n", netdev->name); + dev_kfree_skb_irq(skb); + goto next_desc; + } + + if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) { + dev_kfree_skb_irq(skb); + goto next_desc; + } + + length = le16_to_cpu(rx_desc->wb.middle.length0); + + if (!length) { + ndev_dbg(netdev, "%s: Last part of the packet spanning" + " multiple descriptors\n", netdev->name); + dev_kfree_skb_irq(skb); + goto next_desc; + } + + /* Good Receive */ + skb_put(skb, length); + + { + /* this looks ugly, but it seems compiler issues make it + more efficient than reusing j */ + int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]); + + /* page alloc/put takes too long and effects small packet + * throughput, so unsplit small packets and save the alloc/put*/ + if (l1 && (l1 <= copybreak) && + ((length + l1) <= adapter->rx_ps_bsize0)) { + u8 *vaddr; + + ps_page = &rx_ring->ps_pages[i * PS_PAGE_BUFFERS]; + + /* there is no documentation about how to call + * kmap_atomic, so we can't hold the mapping + * very long */ + pci_dma_sync_single_for_cpu(pdev, ps_page->dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + vaddr = kmap_atomic(ps_page->page, KM_SKB_DATA_SOFTIRQ); + memcpy(skb_tail_pointer(skb), vaddr, l1); + kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); + pci_dma_sync_single_for_device(pdev, ps_page->dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + /* remove the CRC */ + l1 -= 4; + skb_put(skb, l1); + goto copydone; + } /* if */ + } + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + length = le16_to_cpu(rx_desc->wb.upper.length[j]); + if (!length) + break; + + ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS) + j]; + pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + ps_page->dma = 0; + skb_fill_page_desc(skb, j, ps_page->page, 0, length); + ps_page->page = NULL; + skb->len += length; + skb->data_len += length; + skb->truesize += length; + } + + /* strip the ethernet crc, problem is we're using pages now so + * this whole operation can get a little cpu intensive */ + pskb_trim(skb, skb->len - 4); + +copydone: + total_rx_bytes += skb->len; + total_rx_packets++; + + e1000_rx_checksum(adapter, staterr, le16_to_cpu( + rx_desc->wb.lower.hi_dword.csum_ip.csum), skb); + + if (rx_desc->wb.upper.header_status & + cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP)) + adapter->rx_hdr_split++; + + e1000_receive_skb(adapter, netdev, skb, + staterr, rx_desc->wb.middle.vlan); + +next_desc: + rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF); + buffer_info->skb = NULL; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= E1000_RX_BUFFER_WRITE) { + adapter->alloc_rx_buf(adapter, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + + staterr = le32_to_cpu(rx_desc->wb.middle.status_error); + } + rx_ring->next_to_clean = i; + + cleaned_count = e1000_desc_unused(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + return cleaned; +} + +/** + * e1000_clean_rx_ring - Free Rx Buffers per Queue + * @adapter: board private structure + **/ +static void e1000_clean_rx_ring(struct e1000_adapter *adapter) +{ + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i, j; + + /* 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) { + if (adapter->clean_rx == e1000_clean_rx_irq) + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + else if (adapter->clean_rx == e1000_clean_rx_irq_jumbo) + pci_unmap_page(pdev, buffer_info->dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + else if (adapter->clean_rx == e1000_clean_rx_irq_ps) + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_bsize0, + 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; + } + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS) + + j]; + if (!ps_page->page) + break; + pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + ps_page->dma = 0; + put_page(ps_page->page); + ps_page->page = 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); + size = sizeof(struct e1000_ps_page) + * (rx_ring->count * PS_PAGE_BUFFERS); + memset(rx_ring->ps_pages, 0, size); + + /* Zero out the descriptor ring */ + memset(rx_ring->desc, 0, rx_ring->size); + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + writel(0, adapter->hw.hw_addr + rx_ring->head); + writel(0, adapter->hw.hw_addr + rx_ring->tail); +} + +/** + * e1000_intr_msi - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t e1000_intr_msi(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 icr = er32(ICR); + + /* read ICR disables interrupts using IAM, so keep up with our + * enable/disable accounting */ + atomic_inc(&adapter->irq_sem); + + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->mac.get_link_status = 1; + /* ICH8 workaround-- Call gig speed drop workaround on cable + * disconnect (LSC) before accessing any PHY registers */ + if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && + (!(er32(STATUS) & E1000_STATUS_LU))) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* 80003ES2LAN workaround-- For packet buffer work-around on + * link down event; disable receives here in the ISR and reset + * adapter in watchdog */ + if (netif_carrier_ok(netdev) && + adapter->flags & FLAG_RX_NEEDS_RESTART) { + /* disable receives */ + u32 rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + } + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; + __netif_rx_schedule(netdev, &adapter->napi); + } else { + atomic_dec(&adapter->irq_sem); + } + + return IRQ_HANDLED; +} + +/** + * e1000_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t e1000_intr(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + u32 rctl, icr = er32(ICR); + if (!icr) + return IRQ_NONE; /* Not our interrupt */ + + /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is + * not set, then the adapter didn't send an interrupt */ + if (!(icr & E1000_ICR_INT_ASSERTED)) + return IRQ_NONE; + + /* Interrupt Auto-Mask...upon reading ICR, + * interrupts are masked. No need for the + * IMC write, but it does mean we should + * account for it ASAP. */ + atomic_inc(&adapter->irq_sem); + + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->mac.get_link_status = 1; + /* ICH8 workaround-- Call gig speed drop workaround on cable + * disconnect (LSC) before accessing any PHY registers */ + if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && + (!(er32(STATUS) & E1000_STATUS_LU))) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* 80003ES2LAN workaround-- + * For packet buffer work-around on link down event; + * disable receives here in the ISR and + * reset adapter in watchdog + */ + if (netif_carrier_ok(netdev) && + (adapter->flags & FLAG_RX_NEEDS_RESTART)) { + /* disable receives */ + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + } + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; + __netif_rx_schedule(netdev, &adapter->napi); + } else { + atomic_dec(&adapter->irq_sem); + } + + return IRQ_HANDLED; +} + +static int e1000_request_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + void (*handler) = &e1000_intr; + int irq_flags = IRQF_SHARED; + int err; + + err = pci_enable_msi(adapter->pdev); + if (err) { + ndev_warn(netdev, + "Unable to allocate MSI interrupt Error: %d\n", err); + } else { + adapter->flags |= FLAG_MSI_ENABLED; + handler = &e1000_intr_msi; + irq_flags = 0; + } + + err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name, + netdev); + if (err) { + if (adapter->flags & FLAG_MSI_ENABLED) + pci_disable_msi(adapter->pdev); + ndev_err(netdev, + "Unable to allocate interrupt Error: %d\n", err); + } + + return err; +} + +static void e1000_free_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + free_irq(adapter->pdev->irq, netdev); + if (adapter->flags & FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~FLAG_MSI_ENABLED; + } +} + +/** + * e1000_irq_disable - Mask off interrupt generation on the NIC + **/ +static void e1000_irq_disable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + atomic_inc(&adapter->irq_sem); + ew32(IMC, ~0); + e1e_flush(); + synchronize_irq(adapter->pdev->irq); +} + +/** + * e1000_irq_enable - Enable default interrupt generation settings + **/ +static void e1000_irq_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (atomic_dec_and_test(&adapter->irq_sem)) { + ew32(IMS, IMS_ENABLE_MASK); + e1e_flush(); + } +} + +/** + * e1000_get_hw_control - get control of the h/w from f/w + * @adapter: address of board private structure + * + * e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that + * the driver is loaded. For AMT version (only with 82573) + * of the f/w this means that the network i/f is open. + **/ +static void e1000_get_hw_control(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext; + u32 swsm; + + /* Let firmware know the driver has taken over */ + if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD); + } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { + ctrl_ext = er32(CTRL_EXT); + ew32(CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + } +} + +/** + * e1000_release_hw_control - release control of the h/w to f/w + * @adapter: address of board private structure + * + * e1000_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that the + * driver is no longer loaded. For AMT version (only with 82573) i + * of the f/w this means that the network i/f is closed. + * + **/ +static void e1000_release_hw_control(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext; + u32 swsm; + + /* Let firmware taken over control of h/w */ + if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { + swsm = er32(SWSM); + ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD); + } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { + ctrl_ext = er32(CTRL_EXT); + ew32(CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + } +} + +static void e1000_release_manageability(struct e1000_adapter *adapter) +{ + if (adapter->flags & FLAG_MNG_PT_ENABLED) { + struct e1000_hw *hw = &adapter->hw; + + u32 manc = er32(MANC); + + /* re-enable hardware interception of ARP */ + manc |= E1000_MANC_ARP_EN; + manc &= ~E1000_MANC_EN_MNG2HOST; + + /* don't explicitly have to mess with MANC2H since + * MANC has an enable disable that gates MANC2H */ + ew32(MANC, manc); + } +} + +/** + * @e1000_alloc_ring - allocate memory for a ring structure + **/ +static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, + struct e1000_ring *ring) +{ + struct pci_dev *pdev = adapter->pdev; + + ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, + GFP_KERNEL); + if (!ring->desc) + return -ENOMEM; + + return 0; +} + +/** + * e1000e_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * + * Return 0 on success, negative on failure + **/ +int e1000e_setup_tx_resources(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + int err = -ENOMEM, size; + + size = sizeof(struct e1000_buffer) * tx_ring->count; + tx_ring->buffer_info = vmalloc(size); + if (!tx_ring->buffer_info) + goto err; + memset(tx_ring->buffer_info, 0, size); + + /* round up to nearest 4K */ + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + + err = e1000_alloc_ring_dma(adapter, tx_ring); + if (err) + goto err; + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + spin_lock_init(&adapter->tx_queue_lock); + + return 0; +err: + vfree(tx_ring->buffer_info); + ndev_err(adapter->netdev, + "Unable to allocate memory for the transmit descriptor ring\n"); + return err; +} + +/** + * e1000e_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: board private structure + * + * Returns 0 on success, negative on failure + **/ +int e1000e_setup_rx_resources(struct e1000_adapter *adapter) +{ + struct e1000_ring *rx_ring = adapter->rx_ring; + int size, desc_len, err = -ENOMEM; + + size = sizeof(struct e1000_buffer) * rx_ring->count; + rx_ring->buffer_info = vmalloc(size); + if (!rx_ring->buffer_info) + goto err; + memset(rx_ring->buffer_info, 0, size); + + rx_ring->ps_pages = kcalloc(rx_ring->count * PS_PAGE_BUFFERS, + sizeof(struct e1000_ps_page), + GFP_KERNEL); + if (!rx_ring->ps_pages) + goto err; + + desc_len = sizeof(union e1000_rx_desc_packet_split); + + /* Round up to nearest 4K */ + rx_ring->size = rx_ring->count * desc_len; + rx_ring->size = ALIGN(rx_ring->size, 4096); + + err = e1000_alloc_ring_dma(adapter, rx_ring); + if (err) + goto err; + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + rx_ring->rx_skb_top = NULL; + + return 0; +err: + vfree(rx_ring->buffer_info); + kfree(rx_ring->ps_pages); + ndev_err(adapter->netdev, + "Unable to allocate memory for the transmit descriptor ring\n"); + return err; +} + +/** + * e1000_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + **/ +static void e1000_clean_tx_ring(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_buffer *buffer_info; + unsigned long size; + unsigned int i; + + for (i = 0; i < tx_ring->count; i++) { + buffer_info = &tx_ring->buffer_info[i]; + e1000_put_txbuf(adapter, buffer_info); + } + + size = sizeof(struct e1000_buffer) * tx_ring->count; + memset(tx_ring->buffer_info, 0, size); + + memset(tx_ring->desc, 0, tx_ring->size); + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + writel(0, adapter->hw.hw_addr + tx_ring->head); + writel(0, adapter->hw.hw_addr + tx_ring->tail); +} + +/** + * e1000e_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * + * Free all transmit software resources + **/ +void e1000e_free_tx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *tx_ring = adapter->tx_ring; + + e1000_clean_tx_ring(adapter); + + vfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + + dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; +} + +/** + * e1000e_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * + * Free all receive software resources + **/ + +void e1000e_free_rx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + + e1000_clean_rx_ring(adapter); + + vfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; + + kfree(rx_ring->ps_pages); + rx_ring->ps_pages = NULL; + + dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; +} + +/** + * e1000_update_itr - update the dynamic ITR value based on statistics + * Stores a new ITR value based on packets and byte + * counts during the last interrupt. The advantage of per interrupt + * computation is faster updates and more accurate ITR for the current + * traffic pattern. Constants in this function were computed + * based on theoretical maximum wire speed and thresholds were set based + * on testing data as well as attempting to minimize response time + * while increasing bulk throughput. + * this functionality is controlled by the InterruptThrottleRate module + * parameter (see e1000_param.c) + * @adapter: pointer to adapter + * @itr_setting: current adapter->itr + * @packets: the number of packets during this measurement interval + * @bytes: the number of bytes during this measurement interval + **/ +static unsigned int e1000_update_itr(struct e1000_adapter *adapter, + u16 itr_setting, int packets, + int bytes) +{ + unsigned int retval = itr_setting; + + if (packets == 0) + goto update_itr_done; + + switch (itr_setting) { + case lowest_latency: + /* handle TSO and jumbo frames */ + if (bytes/packets > 8000) + retval = bulk_latency; + else if ((packets < 5) && (bytes > 512)) { + retval = low_latency; + } + break; + case low_latency: /* 50 usec aka 20000 ints/s */ + if (bytes > 10000) { + /* this if handles the TSO accounting */ + if (bytes/packets > 8000) { + retval = bulk_latency; + } else if ((packets < 10) || ((bytes/packets) > 1200)) { + retval = bulk_latency; + } else if ((packets > 35)) { + retval = lowest_latency; + } + } else if (bytes/packets > 2000) { + retval = bulk_latency; + } else if (packets <= 2 && bytes < 512) { + retval = lowest_latency; + } + break; + case bulk_latency: /* 250 usec aka 4000 ints/s */ + if (bytes > 25000) { + if (packets > 35) { + retval = low_latency; + } + } else if (bytes < 6000) { + retval = low_latency; + } + break; + } + +update_itr_done: + return retval; +} + +static void e1000_set_itr(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u16 current_itr; + u32 new_itr = adapter->itr; + + /* for non-gigabit speeds, just fix the interrupt rate at 4000 */ + if (adapter->link_speed != SPEED_1000) { + current_itr = 0; + new_itr = 4000; + goto set_itr_now; + } + + adapter->tx_itr = e1000_update_itr(adapter, + adapter->tx_itr, + adapter->total_tx_packets, + adapter->total_tx_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency) + adapter->tx_itr = low_latency; + + adapter->rx_itr = e1000_update_itr(adapter, + adapter->rx_itr, + adapter->total_rx_packets, + adapter->total_rx_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency) + adapter->rx_itr = low_latency; + + current_itr = max(adapter->rx_itr, adapter->tx_itr); + + switch (current_itr) { + /* counts and packets in update_itr are dependent on these numbers */ + case lowest_latency: + new_itr = 70000; + break; + case low_latency: + new_itr = 20000; /* aka hwitr = ~200 */ + break; + case bulk_latency: + new_itr = 4000; + break; + default: + break; + } + +set_itr_now: + if (new_itr != adapter->itr) { + /* this attempts to bias the interrupt rate towards Bulk + * by adding intermediate steps when interrupt rate is + * increasing */ + new_itr = new_itr > adapter->itr ? + min(adapter->itr + (new_itr >> 2), new_itr) : + new_itr; + adapter->itr = new_itr; + ew32(ITR, 1000000000 / (new_itr * 256)); + } +} + +/** + * e1000_clean - NAPI Rx polling callback + * @adapter: board private structure + **/ +static int e1000_clean(struct napi_struct *napi, int budget) +{ + struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); + struct net_device *poll_dev = adapter->netdev; + int tx_cleaned = 0, work_done = 0; + + /* Must NOT use netdev_priv macro here. */ + adapter = poll_dev->priv; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(poll_dev)) + goto quit_polling; + + /* e1000_clean is called per-cpu. This lock protects + * tx_ring from being cleaned by multiple cpus + * simultaneously. A failure obtaining the lock means + * tx_ring is currently being cleaned anyway. */ + if (spin_trylock(&adapter->tx_queue_lock)) { + tx_cleaned = e1000_clean_tx_irq(adapter); + spin_unlock(&adapter->tx_queue_lock); + } + + adapter->clean_rx(adapter, &work_done, budget); + + /* If no Tx and not enough Rx work done, exit the polling mode */ + if ((!tx_cleaned && (work_done < budget)) || + !netif_running(poll_dev)) { +quit_polling: + if (adapter->itr_setting & 3) + e1000_set_itr(adapter); + netif_rx_complete(poll_dev, napi); + e1000_irq_enable(adapter); + } + + return work_done; +} + +static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 vfta, index; + + /* don't update vlan cookie if already programmed */ + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + (vid == adapter->mng_vlan_id)) + return; + /* add VID to filter table */ + index = (vid >> 5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); + vfta |= (1 << (vid & 0x1F)); + e1000e_write_vfta(hw, index, vfta); +} + +static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 vfta, index; + + e1000_irq_disable(adapter); + vlan_group_set_device(adapter->vlgrp, vid, NULL); + e1000_irq_enable(adapter); + + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + (vid == adapter->mng_vlan_id)) { + /* release control to f/w */ + e1000_release_hw_control(adapter); + return; + } + + /* remove VID from filter table */ + index = (vid >> 5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); + vfta &= ~(1 << (vid & 0x1F)); + e1000e_write_vfta(hw, index, vfta); +} + +static void e1000_update_mng_vlan(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 vid = adapter->hw.mng_cookie.vlan_id; + u16 old_vid = adapter->mng_vlan_id; + + if (!adapter->vlgrp) + return; + + if (!vlan_group_get_device(adapter->vlgrp, vid)) { + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { + e1000_vlan_rx_add_vid(netdev, vid); + adapter->mng_vlan_id = vid; + } + + if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && + (vid != old_vid) && + !vlan_group_get_device(adapter->vlgrp, old_vid)) + e1000_vlan_rx_kill_vid(netdev, old_vid); + } else { + adapter->mng_vlan_id = vid; + } +} + + +static void e1000_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, rctl; + + e1000_irq_disable(adapter); + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_VME; + ew32(CTRL, ctrl); + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* enable VLAN receive filtering */ + rctl = er32(RCTL); + rctl |= E1000_RCTL_VFE; + rctl &= ~E1000_RCTL_CFIEN; + ew32(RCTL, rctl); + e1000_update_mng_vlan(adapter); + } + } else { + /* disable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl &= ~E1000_CTRL_VME; + ew32(CTRL, ctrl); + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* disable VLAN 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, + adapter->mng_vlan_id); + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + } + } + } + + e1000_irq_enable(adapter); +} + +static void e1000_restore_vlan(struct e1000_adapter *adapter) +{ + u16 vid; + + e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); + + if (!adapter->vlgrp) + return; + + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) + continue; + e1000_vlan_rx_add_vid(adapter->netdev, vid); + } +} + +static void e1000_init_manageability(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 manc, manc2h; + + if (!(adapter->flags & FLAG_MNG_PT_ENABLED)) + return; + + manc = er32(MANC); + + /* disable hardware interception of ARP */ + manc &= ~(E1000_MANC_ARP_EN); + + /* enable receiving management packets to the host. this will probably + * generate destination unreachable messages from the host OS, but + * the packets will be handled on SMBUS */ + manc |= E1000_MANC_EN_MNG2HOST; + manc2h = er32(MANC2H); +#define E1000_MNG2HOST_PORT_623 (1 << 5) +#define E1000_MNG2HOST_PORT_664 (1 << 6) + manc2h |= E1000_MNG2HOST_PORT_623; + manc2h |= E1000_MNG2HOST_PORT_664; + ew32(MANC2H, manc2h); + ew32(MANC, manc); +} + +/** + * e1000_configure_tx - Configure 8254x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ +static void e1000_configure_tx(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *tx_ring = adapter->tx_ring; + u64 tdba; + u32 tdlen, tctl, tipg, tarc; + u32 ipgr1, ipgr2; + + /* Setup the HW Tx Head and Tail descriptor pointers */ + tdba = tx_ring->dma; + tdlen = tx_ring->count * sizeof(struct e1000_tx_desc); + ew32(TDBAL, (tdba & DMA_32BIT_MASK)); + ew32(TDBAH, (tdba >> 32)); + ew32(TDLEN, tdlen); + ew32(TDH, 0); + ew32(TDT, 0); + tx_ring->head = E1000_TDH; + tx_ring->tail = E1000_TDT; + + /* Set the default values for the Tx Inter Packet Gap timer */ + tipg = DEFAULT_82543_TIPG_IPGT_COPPER; /* 8 */ + ipgr1 = DEFAULT_82543_TIPG_IPGR1; /* 8 */ + ipgr2 = DEFAULT_82543_TIPG_IPGR2; /* 6 */ + + if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN) + ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /* 7 */ + + tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT; + ew32(TIPG, tipg); + + /* Set the Tx Interrupt Delay register */ + ew32(TIDV, adapter->tx_int_delay); + /* tx irq moderation */ + ew32(TADV, adapter->tx_abs_int_delay); + + /* Program the Transmit Control Register */ + tctl = er32(TCTL); + tctl &= ~E1000_TCTL_CT; + tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + + if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) { + tarc = er32(TARC0); + /* set the speed mode bit, we'll clear it if we're not at + * gigabit link later */ +#define SPEED_MODE_BIT (1 << 21) + tarc |= SPEED_MODE_BIT; + ew32(TARC0, tarc); + } + + /* errata: program both queues to unweighted RR */ + if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) { + tarc = er32(TARC0); + tarc |= 1; + ew32(TARC0, tarc); + tarc = er32(TARC1); + tarc |= 1; + ew32(TARC1, tarc); + } + + e1000e_config_collision_dist(hw); + + /* Setup Transmit Descriptor Settings for eop descriptor */ + adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; + + /* only set IDE if we are delaying interrupts using the timers */ + if (adapter->tx_int_delay) + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + + /* enable Report Status bit */ + adapter->txd_cmd |= E1000_TXD_CMD_RS; + + ew32(TCTL, tctl); + + adapter->tx_queue_len = adapter->netdev->tx_queue_len; +} + +/** + * e1000_setup_rctl - configure the receive control registers + * @adapter: Board private structure + **/ +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) +static void e1000_setup_rctl(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl, rfctl; + u32 psrctl = 0; + u32 pages = 0; + + /* Program MC offset vector base */ + rctl = er32(RCTL); + rctl &= ~(3 << E1000_RCTL_MO_SHIFT); + rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + + /* Do not Store bad packets */ + rctl &= ~E1000_RCTL_SBP; + + /* Enable Long Packet receive */ + if (adapter->netdev->mtu <= ETH_DATA_LEN) + rctl &= ~E1000_RCTL_LPE; + else + rctl |= E1000_RCTL_LPE; + + /* Setup buffer sizes */ + rctl &= ~E1000_RCTL_SZ_4096; + rctl |= E1000_RCTL_BSEX; + switch (adapter->rx_buffer_len) { + case 256: + rctl |= E1000_RCTL_SZ_256; + rctl &= ~E1000_RCTL_BSEX; + break; + case 512: + rctl |= E1000_RCTL_SZ_512; + rctl &= ~E1000_RCTL_BSEX; + break; + case 1024: + rctl |= E1000_RCTL_SZ_1024; + rctl &= ~E1000_RCTL_BSEX; + break; + case 2048: + default: + rctl |= E1000_RCTL_SZ_2048; + rctl &= ~E1000_RCTL_BSEX; + break; + case 4096: + rctl |= E1000_RCTL_SZ_4096; + break; + case 8192: + rctl |= E1000_RCTL_SZ_8192; + break; + case 16384: + rctl |= E1000_RCTL_SZ_16384; + break; + } + + /* + * 82571 and greater support packet-split where the protocol + * header is placed in skb->data and the packet data is + * placed in pages hanging off of skb_shinfo(skb)->nr_frags. + * In the case of a non-split, skb->data is linearly filled, + * followed by the page buffers. Therefore, skb->data is + * sized to hold the largest protocol header. + * + * allocations using alloc_page take too long for regular MTU + * so only enable packet split for jumbo frames + * + * Using pages when the page size is greater than 16k wastes + * a lot of memory, since we allocate 3 pages at all times + * per packet. + */ + adapter->rx_ps_pages = 0; + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + if ((pages <= 3) && (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE)) + adapter->rx_ps_pages = pages; + + if (adapter->rx_ps_pages) { + /* Configure extra packet-split registers */ + rfctl = er32(RFCTL); + rfctl |= E1000_RFCTL_EXTEN; + /* disable packet split support for IPv6 extension headers, + * because some malformed IPv6 headers can hang the RX */ + rfctl |= (E1000_RFCTL_IPV6_EX_DIS | + E1000_RFCTL_NEW_IPV6_EXT_DIS); + + ew32(RFCTL, rfctl); + + /* disable the stripping of CRC because it breaks + * BMC firmware connected over SMBUS */ + rctl |= E1000_RCTL_DTYP_PS /* | E1000_RCTL_SECRC */; + + psrctl |= adapter->rx_ps_bsize0 >> + E1000_PSRCTL_BSIZE0_SHIFT; + + switch (adapter->rx_ps_pages) { + case 3: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE3_SHIFT; + case 2: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE2_SHIFT; + case 1: + psrctl |= PAGE_SIZE >> + E1000_PSRCTL_BSIZE1_SHIFT; + break; + } + + ew32(PSRCTL, psrctl); + } + + ew32(RCTL, rctl); +} + +/** + * e1000_configure_rx - Configure Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ +static void e1000_configure_rx(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *rx_ring = adapter->rx_ring; + u64 rdba; + u32 rdlen, rctl, rxcsum, ctrl_ext; + + if (adapter->rx_ps_pages) { + /* this is a 32 byte descriptor */ + rdlen = rx_ring->count * + sizeof(union e1000_rx_desc_packet_split); + adapter->clean_rx = e1000_clean_rx_irq_ps; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; + } else if (adapter->netdev->mtu > ETH_FRAME_LEN + VLAN_HLEN + 4) { + rdlen = rx_ring->count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq_jumbo; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers_jumbo; + } else { + rdlen = rx_ring->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); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + e1e_flush(); + msleep(10); + + /* set the Receive Delay Timer Register */ + ew32(RDTR, adapter->rx_int_delay); + + /* irq moderation */ + ew32(RADV, adapter->rx_abs_int_delay); + if (adapter->itr_setting != 0) + ew32(ITR, + 1000000000 / (adapter->itr * 256)); + + ctrl_ext = er32(CTRL_EXT); + /* Reset delay timers after every interrupt */ + ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR; + /* Auto-Mask interrupts upon ICR access */ + ctrl_ext |= E1000_CTRL_EXT_IAME; + ew32(IAM, 0xffffffff); + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + rdba = rx_ring->dma; + ew32(RDBAL, (rdba & DMA_32BIT_MASK)); + ew32(RDBAH, (rdba >> 32)); + ew32(RDLEN, rdlen); + ew32(RDH, 0); + ew32(RDT, 0); + rx_ring->head = E1000_RDH; + rx_ring->tail = E1000_RDT; + + /* Enable Receive Checksum Offload for TCP and UDP */ + rxcsum = er32(RXCSUM); + if (adapter->flags & FLAG_RX_CSUM_ENABLED) { + rxcsum |= E1000_RXCSUM_TUOFL; + + /* IPv4 payload checksum for UDP fragments must be + * used in conjunction with packet-split. */ + if (adapter->rx_ps_pages) + rxcsum |= E1000_RXCSUM_IPPCSE; + } else { + rxcsum &= ~E1000_RXCSUM_TUOFL; + /* no need to clear IPPCSE as it defaults to 0 */ + } + ew32(RXCSUM, rxcsum); + + /* Enable early receives on supported devices, only takes effect when + * packet size is equal or larger than the specified value (in 8 byte + * units), e.g. using jumbo frames when setting to E1000_ERT_2048 */ + if ((adapter->flags & FLAG_HAS_ERT) && + (adapter->netdev->mtu > ETH_DATA_LEN)) + ew32(ERT, E1000_ERT_2048); + + /* Enable Receives */ + ew32(RCTL, rctl); +} + +/** + * e1000_mc_addr_list_update - 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. Currently no func pointer + * exists and all implementations are handled in the generic version of this + * function. + **/ +static void e1000_mc_addr_list_update(struct e1000_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, u32 rar_used_count, + u32 rar_count) +{ + hw->mac.ops.mc_addr_list_update(hw, mc_addr_list, mc_addr_count, + rar_used_count, rar_count); +} + +/** + * e1000_set_multi - 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, + * promiscuous mode, and all-multi behavior. + **/ +static void e1000_set_multi(struct net_device *netdev) +{ + struct e1000_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; + u32 rctl; + int i; + + /* Check for Promiscuous and All Multicast modes */ + + rctl = er32(RCTL); + + if (netdev->flags & IFF_PROMISC) { + rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + } else if (netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else { + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + } + + ew32(RCTL, rctl); + + if (netdev->mc_count) { + mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC); + if (!mta_list) + return; + + /* prepare a packed array of only addresses. */ + mc_ptr = netdev->mc_list; + + for (i = 0; i < netdev->mc_count; i++) { + if (!mc_ptr) + break; + memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, + ETH_ALEN); + mc_ptr = mc_ptr->next; + } + + e1000_mc_addr_list_update(hw, mta_list, i, 1, + mac->rar_entry_count); + kfree(mta_list); + } else { + /* + * if we're called from probe, we might not have + * anything to do here, so clear out the list + */ + e1000_mc_addr_list_update(hw, NULL, 0, 1, + mac->rar_entry_count); + } +} + +/** + * e1000_configure - configure the hardware for RX and TX + * @adapter: private board structure + **/ +static void e1000_configure(struct e1000_adapter *adapter) +{ + e1000_set_multi(adapter->netdev); + + e1000_restore_vlan(adapter); + e1000_init_manageability(adapter); + + e1000_configure_tx(adapter); + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + adapter->alloc_rx_buf(adapter, + e1000_desc_unused(adapter->rx_ring)); +} + +/** + * e1000e_power_up_phy - restore link in case the phy was powered down + * @adapter: address of board private structure + * + * The phy may be powered down to save power and turn off link when the + * driver is unloaded and wake on lan is not enabled (among others) + * *** this routine MUST be followed by a call to e1000e_reset *** + **/ +void e1000e_power_up_phy(struct e1000_adapter *adapter) +{ + u16 mii_reg = 0; + + /* Just clear the power down bit to wake the phy back up */ + if (adapter->hw.media_type == e1000_media_type_copper) { + /* according to the manual, the phy will retain its + * settings across a power-down/up cycle */ + e1e_rphy(&adapter->hw, PHY_CONTROL, &mii_reg); + mii_reg &= ~MII_CR_POWER_DOWN; + e1e_wphy(&adapter->hw, PHY_CONTROL, mii_reg); + } + + adapter->hw.mac.ops.setup_link(&adapter->hw); +} + +/** + * e1000_power_down_phy - Power down the PHY + * + * Power down the PHY so no link is implied when interface is down + * The PHY cannot be powered down is management or WoL is active + */ +static void e1000_power_down_phy(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u16 mii_reg; + + /* WoL is enabled */ + if (!adapter->wol) + return; + + /* non-copper PHY? */ + if (adapter->hw.media_type != e1000_media_type_copper) + return; + + /* reset is blocked because of a SoL/IDER session */ + if (e1000e_check_mng_mode(hw) || + e1000_check_reset_block(hw)) + return; + + /* managebility (AMT) is enabled */ + if (er32(MANC) & E1000_MANC_SMBUS_EN) + return; + + /* power down the PHY */ + e1e_rphy(hw, PHY_CONTROL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + e1e_wphy(hw, PHY_CONTROL, mii_reg); + mdelay(1); +} + +/** + * e1000e_reset - bring the hardware into a known good state + * + * This function boots the hardware and enables some settings that + * require a configuration cycle of the hardware - those cannot be + * set/changed during runtime. After reset the device needs to be + * properly configured for rx, tx etc. + */ +void e1000e_reset(struct e1000_adapter *adapter) +{ + struct e1000_mac_info *mac = &adapter->hw.mac; + struct e1000_hw *hw = &adapter->hw; + u32 tx_space, min_tx_space, min_rx_space; + u16 hwm; + + if (mac->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) { + /* To maintain wire speed transmits, the Tx FIFO should be + * 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 accommodate at least + * one full receive packet and is similarly rounded up and + * expressed in KB. */ + adapter->pba = er32(PBA); + /* upper 16 bits has Tx packet buffer allocation size in KB */ + tx_space = adapter->pba >> 16; + /* lower 16 bits has Rx packet buffer allocation size in KB */ + adapter->pba &= 0xffff; + /* 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 = (mac->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 = mac->max_frame_size; + min_rx_space = ALIGN(min_rx_space, 1024); + min_rx_space >>= 10; + + /* If current Tx allocation is less than the min Tx FIFO size, + * and the min Tx FIFO size is less than the current Rx FIFO + * allocation, take space away from current Rx allocation */ + if (tx_space < min_tx_space && + ((min_tx_space - tx_space) < adapter->pba)) { + adapter->pba -= - (min_tx_space - tx_space); + + /* if short on rx space, rx wins and must trump tx + * adjustment or use Early Receive if available */ + if ((adapter->pba < min_rx_space) && + (!(adapter->flags & FLAG_HAS_ERT))) + /* ERT enabled in e1000_configure_rx */ + adapter->pba = min_rx_space; + } + } + + ew32(PBA, adapter->pba); + + /* 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 */ + if (adapter->flags & FLAG_HAS_ERT) + hwm = min(((adapter->pba << 10) * 9 / 10), + ((adapter->pba << 10) - (E1000_ERT_2048 << 3))); + else + hwm = min(((adapter->pba << 10) * 9 / 10), + ((adapter->pba << 10) - mac->max_frame_size)); + + mac->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */ + mac->fc_low_water = mac->fc_high_water - 8; + + if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME) + mac->fc_pause_time = 0xFFFF; + else + mac->fc_pause_time = E1000_FC_PAUSE_TIME; + mac->fc = mac->original_fc; + + /* Allow time for pending master requests to run */ + mac->ops.reset_hw(hw); + ew32(WUC, 0); + + if (mac->ops.init_hw(hw)) + ndev_err(adapter->netdev, "Hardware Error\n"); + + e1000_update_mng_vlan(adapter); + + /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ + ew32(VET, ETH_P_8021Q); + + e1000e_reset_adaptive(hw); + e1000_get_phy_info(hw); + + if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) { + u16 phy_data = 0; + /* speed up time to link by disabling smart power down, ignore + * the return value of this function because there is nothing + * different we would do if it failed */ + e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); + phy_data &= ~IGP02E1000_PM_SPD; + e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); + } + + e1000_release_manageability(adapter); +} + +int e1000e_up(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + /* hardware has been reset, we need to reload some things */ + e1000_configure(adapter); + + clear_bit(__E1000_DOWN, &adapter->state); + + napi_enable(&adapter->napi); + e1000_irq_enable(adapter); + + /* fire a link change interrupt to start the watchdog */ + ew32(ICS, E1000_ICS_LSC); + return 0; +} + +void e1000e_down(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 tctl, rctl; + + /* signal that we're down so the interrupt handler does not + * reschedule our watchdog timer */ + set_bit(__E1000_DOWN, &adapter->state); + + /* disable receives in the hardware */ + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + /* flush and sleep below */ + + netif_stop_queue(netdev); + + /* disable transmits in the hardware */ + tctl = er32(TCTL); + tctl &= ~E1000_TCTL_EN; + ew32(TCTL, tctl); + /* flush both disables and wait for them to finish */ + e1e_flush(); + msleep(10); + + napi_disable(&adapter->napi); + e1000_irq_disable(adapter); + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + netdev->tx_queue_len = adapter->tx_queue_len; + netif_carrier_off(netdev); + adapter->link_speed = 0; + adapter->link_duplex = 0; + + e1000e_reset(adapter); + e1000_clean_tx_ring(adapter); + e1000_clean_rx_ring(adapter); + + /* + * TODO: for power management, we could drop the link and + * pci_disable_device here. + */ +} + +void e1000e_reinit_locked(struct e1000_adapter *adapter) +{ + might_sleep(); + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + e1000e_down(adapter); + e1000e_up(adapter); + clear_bit(__E1000_RESETTING, &adapter->state); +} + +/** + * e1000_sw_init - Initialize general software structures (struct e1000_adapter) + * @adapter: board private structure to initialize + * + * e1000_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ +static int __devinit e1000_sw_init(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + + adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN; + adapter->rx_ps_bsize0 = 128; + hw->mac.max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + hw->mac.min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + + adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!adapter->tx_ring) + goto err; + + adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!adapter->rx_ring) + goto err; + + spin_lock_init(&adapter->tx_queue_lock); + + /* Explicitly disable IRQ since the NIC can be in any state. */ + atomic_set(&adapter->irq_sem, 0); + e1000_irq_disable(adapter); + + spin_lock_init(&adapter->stats_lock); + + set_bit(__E1000_DOWN, &adapter->state); + return 0; + +err: + ndev_err(netdev, "Unable to allocate memory for queues\n"); + kfree(adapter->rx_ring); + kfree(adapter->tx_ring); + return -ENOMEM; +} + +/** + * e1000_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int e1000_open(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int err; + + /* disallow open during test */ + if (test_bit(__E1000_TESTING, &adapter->state)) + return -EBUSY; + + /* allocate transmit descriptors */ + err = e1000e_setup_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* allocate receive descriptors */ + err = e1000e_setup_rx_resources(adapter); + if (err) + goto err_setup_rx; + + e1000e_power_up_phy(adapter); + + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN)) + e1000_update_mng_vlan(adapter); + + /* If AMT is enabled, let the firmware know that the network + * interface is now open */ + if ((adapter->flags & FLAG_HAS_AMT) && + e1000e_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + + /* before we allocate an interrupt, we must be ready to handle it. + * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt + * as soon as we call pci_request_irq, so we have to setup our + * clean_rx handler before we do so. */ + e1000_configure(adapter); + + err = e1000_request_irq(adapter); + if (err) + goto err_req_irq; + + /* From here on the code is the same as e1000e_up() */ + clear_bit(__E1000_DOWN, &adapter->state); + + napi_enable(&adapter->napi); + + e1000_irq_enable(adapter); + + /* fire a link status change interrupt to start the watchdog */ + ew32(ICS, E1000_ICS_LSC); + + return 0; + +err_req_irq: + e1000_release_hw_control(adapter); + e1000_power_down_phy(adapter); + e1000e_free_rx_resources(adapter); +err_setup_rx: + e1000e_free_tx_resources(adapter); +err_setup_tx: + e1000e_reset(adapter); + + return err; +} + +/** + * e1000_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int e1000_close(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); + e1000e_down(adapter); + e1000_power_down_phy(adapter); + e1000_free_irq(adapter); + + e1000e_free_tx_resources(adapter); + e1000e_free_rx_resources(adapter); + + /* kill manageability vlan ID if supported, but not if a vlan with + * the same ID is registered on the host OS (let 8021q kill it) */ + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + !(adapter->vlgrp && + vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) + e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + + /* If AMT is enabled, let the firmware know that the network + * interface is now closed */ + if ((adapter->flags & FLAG_HAS_AMT) && + e1000e_check_mng_mode(&adapter->hw)) + e1000_release_hw_control(adapter); + + return 0; +} +/** + * e1000_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int e1000_set_mac(struct net_device *netdev, void *p) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); + + e1000e_rar_set(&adapter->hw, adapter->hw.mac.addr, 0); + + if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) { + /* activate the work around */ + e1000e_set_laa_state_82571(&adapter->hw, 1); + + /* Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed (in e1000_watchdog), the actual LAA is in one + * of the RARs and no incoming packets directed to this port + * are dropped. Eventually the LAA will be in RAR[0] and + * RAR[14] */ + e1000e_rar_set(&adapter->hw, + adapter->hw.mac.addr, + adapter->hw.mac.rar_entry_count - 1); + } + + return 0; +} + +/* Need to wait a few seconds after link up to get diagnostic information from + * the phy */ +static void e1000_update_phy_info(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + e1000_get_phy_info(&adapter->hw); +} + +/** + * e1000e_update_stats - Update the board statistics counters + * @adapter: board private structure + **/ +void e1000e_update_stats(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + unsigned long irq_flags; + u16 phy_tmp; + +#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF + + /* + * Prevent stats update while adapter is being reset, or if the pci + * connection is down. + */ + if (adapter->link_speed == 0) + return; + if (pci_channel_offline(pdev)) + return; + + spin_lock_irqsave(&adapter->stats_lock, irq_flags); + + /* these counters are modified from e1000_adjust_tbi_stats, + * called from the interrupt context, so they must only + * be written while holding adapter->stats_lock + */ + + adapter->stats.crcerrs += er32(CRCERRS); + adapter->stats.gprc += er32(GPRC); + adapter->stats.gorcl += er32(GORCL); + adapter->stats.gorch += er32(GORCH); + adapter->stats.bprc += er32(BPRC); + adapter->stats.mprc += er32(MPRC); + adapter->stats.roc += er32(ROC); + + if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) { + adapter->stats.prc64 += er32(PRC64); + adapter->stats.prc127 += er32(PRC127); + adapter->stats.prc255 += er32(PRC255); + adapter->stats.prc511 += er32(PRC511); + adapter->stats.prc1023 += er32(PRC1023); + adapter->stats.prc1522 += er32(PRC1522); + adapter->stats.symerrs += er32(SYMERRS); + adapter->stats.sec += er32(SEC); + } + + adapter->stats.mpc += er32(MPC); + adapter->stats.scc += er32(SCC); + adapter->stats.ecol += er32(ECOL); + adapter->stats.mcc += er32(MCC); + adapter->stats.latecol += er32(LATECOL); + adapter->stats.dc += er32(DC); + adapter->stats.rlec += er32(RLEC); + adapter->stats.xonrxc += er32(XONRXC); + adapter->stats.xontxc += er32(XONTXC); + adapter->stats.xoffrxc += er32(XOFFRXC); + adapter->stats.xofftxc += er32(XOFFTXC); + adapter->stats.fcruc += er32(FCRUC); + adapter->stats.gptc += er32(GPTC); + adapter->stats.gotcl += er32(GOTCL); + adapter->stats.gotch += er32(GOTCH); + adapter->stats.rnbc += er32(RNBC); + adapter->stats.ruc += er32(RUC); + adapter->stats.rfc += er32(RFC); + adapter->stats.rjc += er32(RJC); + adapter->stats.torl += er32(TORL); + adapter->stats.torh += er32(TORH); + adapter->stats.totl += er32(TOTL); + adapter->stats.toth += er32(TOTH); + adapter->stats.tpr += er32(TPR); + + if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) { + adapter->stats.ptc64 += er32(PTC64); + adapter->stats.ptc127 += er32(PTC127); + adapter->stats.ptc255 += er32(PTC255); + adapter->stats.ptc511 += er32(PTC511); + adapter->stats.ptc1023 += er32(PTC1023); + adapter->stats.ptc1522 += er32(PTC1522); + } + + adapter->stats.mptc += er32(MPTC); + adapter->stats.bptc += er32(BPTC); + + /* used for adaptive IFS */ + + hw->mac.tx_packet_delta = er32(TPT); + adapter->stats.tpt += hw->mac.tx_packet_delta; + hw->mac.collision_delta = er32(COLC); + adapter->stats.colc += hw->mac.collision_delta; + + adapter->stats.algnerrc += er32(ALGNERRC); + adapter->stats.rxerrc += er32(RXERRC); + adapter->stats.tncrs += er32(TNCRS); + adapter->stats.cexterr += er32(CEXTERR); + adapter->stats.tsctc += er32(TSCTC); + adapter->stats.tsctfc += er32(TSCTFC); + + adapter->stats.iac += er32(IAC); + + if (adapter->flags & FLAG_HAS_STATS_ICR_ICT) { + adapter->stats.icrxoc += er32(ICRXOC); + adapter->stats.icrxptc += er32(ICRXPTC); + adapter->stats.icrxatc += er32(ICRXATC); + adapter->stats.ictxptc += er32(ICTXPTC); + adapter->stats.ictxatc += er32(ICTXATC); + adapter->stats.ictxqec += er32(ICTXQEC); + adapter->stats.ictxqmtc += er32(ICTXQMTC); + adapter->stats.icrxdmtc += er32(ICRXDMTC); + } + + /* Fill out the OS statistics structure */ + adapter->net_stats.rx_packets = adapter->stats.gprc; + adapter->net_stats.tx_packets = adapter->stats.gptc; + adapter->net_stats.rx_bytes = adapter->stats.gorcl; + adapter->net_stats.tx_bytes = adapter->stats.gotcl; + adapter->net_stats.multicast = adapter->stats.mprc; + adapter->net_stats.collisions = adapter->stats.colc; + + /* Rx Errors */ + + /* RLEC on some newer hardware can be incorrect so build + * our own version based on RUC and ROC */ + adapter->net_stats.rx_errors = adapter->stats.rxerrc + + adapter->stats.crcerrs + adapter->stats.algnerrc + + adapter->stats.ruc + adapter->stats.roc + + adapter->stats.cexterr; + adapter->net_stats.rx_length_errors = adapter->stats.ruc + + adapter->stats.roc; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc; + + /* Tx Errors */ + adapter->net_stats.tx_errors = adapter->stats.ecol + + adapter->stats.latecol; + adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; + adapter->net_stats.tx_window_errors = adapter->stats.latecol; + adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs; + + /* Tx Dropped needs to be maintained elsewhere */ + + /* Phy Stats */ + if (hw->media_type == e1000_media_type_copper) { + if ((adapter->link_speed == SPEED_1000) && + (!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) { + phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; + adapter->phy_stats.idle_errors += phy_tmp; + } + } + + /* Management Stats */ + adapter->stats.mgptc += er32(MGTPTC); + adapter->stats.mgprc += er32(MGTPRC); + adapter->stats.mgpdc += er32(MGTPDC); + + spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); +} + +static void e1000_print_link_info(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 ctrl = er32(CTRL); + + ndev_info(netdev, + "Link is Up %d Mbps %s, Flow Control: %s\n", + adapter->link_speed, + (adapter->link_duplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex", + ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ? + "RX/TX" : + ((ctrl & E1000_CTRL_RFCE) ? "RX" : + ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); +} + +/** + * e1000_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void e1000_watchdog(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + /* Do the rest outside of interrupt context */ + schedule_work(&adapter->watchdog_task); + + /* TODO: make this use queue_delayed_work() */ +} + +static void e1000_watchdog_task(struct work_struct *work) +{ + struct e1000_adapter *adapter = container_of(work, + struct e1000_adapter, watchdog_task); + + struct net_device *netdev = adapter->netdev; + struct e1000_mac_info *mac = &adapter->hw.mac; + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_hw *hw = &adapter->hw; + u32 link, tctl; + s32 ret_val; + int tx_pending = 0; + + if ((netif_carrier_ok(netdev)) && + (er32(STATUS) & E1000_STATUS_LU)) + goto link_up; + + ret_val = mac->ops.check_for_link(hw); + if ((ret_val == E1000_ERR_PHY) && + (adapter->hw.phy.type == e1000_phy_igp_3) && + (er32(CTRL) & + E1000_PHY_CTRL_GBE_DISABLE)) { + /* See e1000_kmrn_lock_loss_workaround_ich8lan() */ + ndev_info(netdev, + "Gigabit has been disabled, downgrading speed\n"); + } + + if ((e1000e_enable_tx_pkt_filtering(hw)) && + (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id)) + e1000_update_mng_vlan(adapter); + + if ((adapter->hw.media_type == e1000_media_type_internal_serdes) && + !(er32(TXCW) & E1000_TXCW_ANE)) + link = adapter->hw.mac.serdes_has_link; + else + link = er32(STATUS) & E1000_STATUS_LU; + + if (link) { + if (!netif_carrier_ok(netdev)) { + bool txb2b = 1; + mac->ops.get_link_up_info(&adapter->hw, + &adapter->link_speed, + &adapter->link_duplex); + e1000_print_link_info(adapter); + /* tweak tx_queue_len according to speed/duplex + * and adjust the timeout factor */ + netdev->tx_queue_len = adapter->tx_queue_len; + adapter->tx_timeout_factor = 1; + switch (adapter->link_speed) { + case SPEED_10: + txb2b = 0; + netdev->tx_queue_len = 10; + adapter->tx_timeout_factor = 14; + break; + case SPEED_100: + txb2b = 0; + netdev->tx_queue_len = 100; + /* maybe add some timeout factor ? */ + break; + } + + /* workaround: re-program speed mode bit after + * link-up event */ + if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) && + !txb2b) { + u32 tarc0; + tarc0 = er32(TARC0); + tarc0 &= ~SPEED_MODE_BIT; + ew32(TARC0, tarc0); + } + + /* disable TSO for pcie and 10/100 speeds, to avoid + * some hardware issues */ + if (!(adapter->flags & FLAG_TSO_FORCE)) { + switch (adapter->link_speed) { + case SPEED_10: + case SPEED_100: + ndev_info(netdev, + "10/100 speed: disabling TSO\n"); + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + break; + case SPEED_1000: + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + break; + default: + /* oops */ + break; + } + } + + /* enable transmits in the hardware, need to do this + * after setting TARC0 */ + tctl = er32(TCTL); + tctl |= E1000_TCTL_EN; + ew32(TCTL, tctl); + + netif_carrier_on(netdev); + netif_wake_queue(netdev); + + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->phy_info_timer, + round_jiffies(jiffies + 2 * HZ)); + } else { + /* make sure the receive unit is started */ + if (adapter->flags & FLAG_RX_NEEDS_RESTART) { + u32 rctl = er32(RCTL); + ew32(RCTL, rctl | + E1000_RCTL_EN); + } + } + } else { + if (netif_carrier_ok(netdev)) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + ndev_info(netdev, "Link is Down\n"); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->phy_info_timer, + round_jiffies(jiffies + 2 * HZ)); + + if (adapter->flags & FLAG_RX_NEEDS_RESTART) + schedule_work(&adapter->reset_task); + } + } + +link_up: + e1000e_update_stats(adapter); + + mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; + adapter->tpt_old = adapter->stats.tpt; + mac->collision_delta = adapter->stats.colc - adapter->colc_old; + adapter->colc_old = adapter->stats.colc; + + adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; + adapter->gorcl_old = adapter->stats.gorcl; + adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; + adapter->gotcl_old = adapter->stats.gotcl; + + e1000e_update_adaptive(&adapter->hw); + + if (!netif_carrier_ok(netdev)) { + tx_pending = (e1000_desc_unused(tx_ring) + 1 < + tx_ring->count); + if (tx_pending) { + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); + } + } + + /* Cause software interrupt to ensure rx ring is cleaned */ + ew32(ICS, E1000_ICS_RXDMT0); + + /* Force detection of hung controller every watchdog period */ + adapter->detect_tx_hung = 1; + + /* With 82571 controllers, LAA may be overwritten due to controller + * reset from the other port. Set the appropriate LAA in RAR[0] */ + if (e1000e_get_laa_state_82571(hw)) + e1000e_rar_set(hw, adapter->hw.mac.addr, 0); + + /* Reset the timer */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 2 * HZ)); +} + +#define E1000_TX_FLAGS_CSUM 0x00000001 +#define E1000_TX_FLAGS_VLAN 0x00000002 +#define E1000_TX_FLAGS_TSO 0x00000004 +#define E1000_TX_FLAGS_IPV4 0x00000008 +#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 +#define E1000_TX_FLAGS_VLAN_SHIFT 16 + +static int e1000_tso(struct e1000_adapter *adapter, + struct sk_buff *skb) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_context_desc *context_desc; + struct e1000_buffer *buffer_info; + unsigned int i; + u32 cmd_length = 0; + u16 ipcse = 0, tucse, mss; + u8 ipcss, ipcso, tucss, tucso, hdr_len; + int err; + + if (skb_is_gso(skb)) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) + return err; + } + + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + mss = skb_shinfo(skb)->gso_size; + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *iph = ip_hdr(skb); + iph->tot_len = 0; + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + cmd_length = E1000_TXD_CMD_IP; + ipcse = skb_transport_offset(skb) - 1; + } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); + ipcse = 0; + } + ipcss = skb_network_offset(skb); + ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data; + tucss = skb_transport_offset(skb); + tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data; + tucse = 0; + + cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | + E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); + + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; + + context_desc->lower_setup.ip_fields.ipcss = ipcss; + context_desc->lower_setup.ip_fields.ipcso = ipcso; + context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse); + context_desc->upper_setup.tcp_fields.tucss = tucss; + context_desc->upper_setup.tcp_fields.tucso = tucso; + context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); + context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); + context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; + context_desc->cmd_and_length = cpu_to_le32(cmd_length); + + buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return 1; + } + + return 0; +} + +static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_context_desc *context_desc; + struct e1000_buffer *buffer_info; + unsigned int i; + u8 css; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + css = skb_transport_offset(skb); + + i = tx_ring->next_to_use; + buffer_info = &tx_ring->buffer_info[i]; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + + context_desc->lower_setup.ip_config = 0; + context_desc->upper_setup.tcp_fields.tucss = css; + context_desc->upper_setup.tcp_fields.tucso = + css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucse = 0; + context_desc->tcp_seg_setup.data = 0; + context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); + + buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return 1; + } + + return 0; +} + +#define E1000_MAX_PER_TXD 8192 +#define E1000_MAX_TXD_PWR 12 + +static int e1000_tx_map(struct e1000_adapter *adapter, + struct sk_buff *skb, unsigned int first, + unsigned int max_per_txd, unsigned int nr_frags, + unsigned int mss) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_buffer *buffer_info; + unsigned int len = skb->len - skb->data_len; + unsigned int offset = 0, size, count = 0, i; + unsigned int f; + + i = tx_ring->next_to_use; + + while (len) { + buffer_info = &tx_ring->buffer_info[i]; + size = min(len, max_per_txd); + + /* Workaround for premature desc write-backs + * in TSO mode. Append 4-byte sentinel desc */ + if (mss && !nr_frags && size == len && size > 8) + size -= 4; + + buffer_info->length = size; + /* set time_stamp *before* dma to help avoid a possible race */ + buffer_info->time_stamp = jiffies; + buffer_info->dma = + pci_map_single(adapter->pdev, + skb->data + offset, + size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); + adapter->tx_dma_failed++; + return -1; + } + buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + offset = frag->page_offset; + + while (len) { + buffer_info = &tx_ring->buffer_info[i]; + size = min(len, max_per_txd); + /* Workaround for premature desc write-backs + * in TSO mode. Append 4-byte sentinel desc */ + if (mss && f == (nr_frags-1) && size == len && size > 8) + size -= 4; + + buffer_info->length = size; + buffer_info->time_stamp = jiffies; + buffer_info->dma = + pci_map_page(adapter->pdev, + frag->page, + offset, + size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&adapter->pdev->dev, + "TX DMA page map failed\n"); + adapter->tx_dma_failed++; + return -1; + } + + buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + + i++; + if (i == tx_ring->count) + i = 0; + } + } + + if (i == 0) + i = tx_ring->count - 1; + else + i--; + + tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[first].next_to_watch = i; + + return count; +} + +static void e1000_tx_queue(struct e1000_adapter *adapter, + int tx_flags, int count) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_tx_desc *tx_desc = NULL; + struct e1000_buffer *buffer_info; + u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; + unsigned int i; + + if (tx_flags & E1000_TX_FLAGS_TSO) { + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | + E1000_TXD_CMD_TSE; + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + + if (tx_flags & E1000_TX_FLAGS_IPV4) + txd_upper |= E1000_TXD_POPTS_IXSM << 8; + } + + if (tx_flags & E1000_TX_FLAGS_CSUM) { + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + } + + if (tx_flags & E1000_TX_FLAGS_VLAN) { + txd_lower |= E1000_TXD_CMD_VLE; + txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); + } + + i = tx_ring->next_to_use; + + while (count--) { + buffer_info = &tx_ring->buffer_info[i]; + tx_desc = E1000_TX_DESC(*tx_ring, i); + tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + tx_desc->lower.data = + cpu_to_le32(txd_lower | buffer_info->length); + tx_desc->upper.data = cpu_to_le32(txd_upper); + + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); + + /* 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(); + + tx_ring->next_to_use = i; + writel(i, adapter->hw.hw_addr + tx_ring->tail); + /* we need this if more than one processor can write to our tail + * at a time, it synchronizes IO on IA64/Altix systems */ + mmiowb(); +} + +#define MINIMUM_DHCP_PACKET_SIZE 282 +static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter, + struct sk_buff *skb) +{ + struct e1000_hw *hw = &adapter->hw; + u16 length, offset; + + if (vlan_tx_tag_present(skb)) { + if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) + && (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN))) + return 0; + } + + if (skb->len <= MINIMUM_DHCP_PACKET_SIZE) + return 0; + + if (((struct ethhdr *) skb->data)->h_proto != htons(ETH_P_IP)) + return 0; + + { + const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14); + struct udphdr *udp; + + if (ip->protocol != IPPROTO_UDP) + return 0; + + udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2)); + if (ntohs(udp->dest) != 67) + return 0; + + offset = (u8 *)udp + 8 - skb->data; + length = skb->len - offset; + return e1000e_mng_write_dhcp_info(hw, (u8 *)udp + 8, length); + } + + return 0; +} + +static int __e1000_maybe_stop_tx(struct net_device *netdev, int size) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + netif_stop_queue(netdev); + /* Herbert's original patch had: + * smp_mb__after_netif_stop_queue(); + * but since that doesn't exist yet, just open code it. */ + smp_mb(); + + /* We need to check again in a case another CPU has just + * made room available. */ + if (e1000_desc_unused(adapter->tx_ring) < size) + return -EBUSY; + + /* A reprieve! */ + netif_start_queue(netdev); + ++adapter->restart_queue; + return 0; +} + +static int e1000_maybe_stop_tx(struct net_device *netdev, int size) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (e1000_desc_unused(adapter->tx_ring) >= size) + return 0; + return __e1000_maybe_stop_tx(netdev, size); +} + +#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) +static int 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; + unsigned int first; + unsigned int max_per_txd = E1000_MAX_PER_TXD; + unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; + unsigned int tx_flags = 0; + unsigned int len = skb->len; + unsigned long irq_flags; + unsigned int nr_frags = 0; + unsigned int mss = 0; + int count = 0; + int tso; + unsigned int f; + len -= skb->data_len; + + if (test_bit(__E1000_DOWN, &adapter->state)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (skb->len <= 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + mss = skb_shinfo(skb)->gso_size; + /* The controller does a simple calculation to + * make sure there is enough room in the FIFO before + * initiating the DMA for each buffer. The calc is: + * 4 = ceil(buffer len/mss). To make sure we don't + * overrun the FIFO, adjust the max buffer len if mss + * drops. */ + if (mss) { + u8 hdr_len; + max_per_txd = min(mss << 2, max_per_txd); + max_txd_pwr = fls(max_per_txd) - 1; + + /* TSO Workaround for 82571/2/3 Controllers -- if skb->data + * points to just header, pull a few bytes of payload from + * frags into skb->data */ + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { + unsigned int pull_size; + + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + ndev_err(netdev, + "__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + len = skb->len - skb->data_len; + } + } + + /* reserve a descriptor for the offload context */ + if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL)) + count++; + count++; + + count += TXD_USE_COUNT(len, max_txd_pwr); + + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, + max_txd_pwr); + + if (adapter->hw.mac.tx_pkt_filtering) + e1000_transfer_dhcp_info(adapter, skb); + + if (!spin_trylock_irqsave(&adapter->tx_queue_lock, irq_flags)) + /* Collision - tell upper layer to requeue */ + return NETDEV_TX_LOCKED; + + /* need: count + 2 desc gap to keep tail from touching + * head, otherwise try next time */ + if (e1000_maybe_stop_tx(netdev, count + 2)) { + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); + return NETDEV_TX_BUSY; + } + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= E1000_TX_FLAGS_VLAN; + tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); + } + + first = tx_ring->next_to_use; + + tso = e1000_tso(adapter, skb); + if (tso < 0) { + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); + return NETDEV_TX_OK; + } + + if (tso) + tx_flags |= E1000_TX_FLAGS_TSO; + else if (e1000_tx_csum(adapter, skb)) + tx_flags |= E1000_TX_FLAGS_CSUM; + + /* Old method was to assume IPv4 packet by default if TSO was enabled. + * 82571 hardware supports TSO capabilities for IPv6 as well... + * no longer assume, we must. */ + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= E1000_TX_FLAGS_IPV4; + + count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); + if (count < 0) { + /* handle pci_map_single() error in e1000_tx_map */ + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); + return NETDEV_TX_BUSY; + } + + e1000_tx_queue(adapter, tx_flags, count); + + netdev->trans_start = jiffies; + + /* Make sure there is space in the ring for the next send. */ + e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); + + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); + return NETDEV_TX_OK; +} + +/** + * e1000_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void e1000_tx_timeout(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* Do the reset outside of interrupt context */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); +} + +static void e1000_reset_task(struct work_struct *work) +{ + struct e1000_adapter *adapter; + adapter = container_of(work, struct e1000_adapter, reset_task); + + e1000e_reinit_locked(adapter); +} + +/** + * e1000_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ +static struct net_device_stats *e1000_get_stats(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* only return the current stats */ + return &adapter->net_stats; +} + +/** + * e1000_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ +static int e1000_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + + if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || + (max_frame > MAX_JUMBO_FRAME_SIZE)) { + ndev_err(netdev, "Invalid MTU setting\n"); + return -EINVAL; + } + + /* Jumbo frame size limits */ + if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { + if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { + ndev_err(netdev, "Jumbo Frames not supported.\n"); + return -EINVAL; + } + if (adapter->hw.phy.type == e1000_phy_ife) { + ndev_err(netdev, "Jumbo Frames not supported.\n"); + return -EINVAL; + } + } + +#define MAX_STD_JUMBO_FRAME_SIZE 9234 + if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { + ndev_err(netdev, "MTU > 9216 not supported.\n"); + return -EINVAL; + } + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + /* e1000e_down has a dependency on max_frame_size */ + adapter->hw.mac.max_frame_size = max_frame; + if (netif_running(netdev)) + e1000e_down(adapter); + + /* 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 + * however with the new *_jumbo* routines, jumbo receives will use + * fragmented skbs */ + + if (max_frame <= 256) + adapter->rx_buffer_len = 256; + else if (max_frame <= 512) + adapter->rx_buffer_len = 512; + else if (max_frame <= 1024) + adapter->rx_buffer_len = 1024; + else if (max_frame <= 2048) + adapter->rx_buffer_len = 2048; + else + adapter->rx_buffer_len = 4096; + + /* adjust allocation if LPE protects us, and we aren't using SBP */ + if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) || + (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)) + adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + + ETH_FCS_LEN ; + + ndev_info(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); + netdev->mtu = new_mtu; + + if (netif_running(netdev)) + e1000e_up(adapter); + else + e1000e_reset(adapter); + + clear_bit(__E1000_RESETTING, &adapter->state); + + return 0; +} + +static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, + int cmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct mii_ioctl_data *data = if_mii(ifr); + unsigned long irq_flags; + + if (adapter->hw.media_type != e1000_media_type_copper) + return -EOPNOTSUPP; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = adapter->hw.phy.addr; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + spin_lock_irqsave(&adapter->stats_lock, irq_flags); + if (e1e_rphy(&adapter->hw, data->reg_num & 0x1F, + &data->val_out)) { + spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); + return -EIO; + } + spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); + break; + case SIOCSMIIREG: + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return e1000_mii_ioctl(netdev, ifr, cmd); + default: + return -EOPNOTSUPP; + } +} + +static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, ctrl_ext, rctl, status; + u32 wufc = adapter->wol; + int retval = 0; + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); + e1000e_down(adapter); + e1000_free_irq(adapter); + } + + retval = pci_save_state(pdev); + if (retval) + return retval; + + status = er32(STATUS); + if (status & E1000_STATUS_LU) + wufc &= ~E1000_WUFC_LNKC; + + if (wufc) { + e1000_setup_rctl(adapter); + e1000_set_multi(netdev); + + /* turn on all-multi mode if wake on multicast is enabled */ + if (wufc & E1000_WUFC_MC) { + rctl = er32(RCTL); + rctl |= E1000_RCTL_MPE; + ew32(RCTL, rctl); + } + + ctrl = er32(CTRL); + /* advertise wake from D3Cold */ + #define E1000_CTRL_ADVD3WUC 0x00100000 + /* phy power management enable */ + #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 + ctrl |= E1000_CTRL_ADVD3WUC | + E1000_CTRL_EN_PHY_PWR_MGMT; + ew32(CTRL, ctrl); + + if (adapter->hw.media_type == e1000_media_type_fiber || + adapter->hw.media_type == e1000_media_type_internal_serdes) { + /* keep the laser running in D3 */ + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA; + ew32(CTRL_EXT, ctrl_ext); + } + + /* Allow time for pending master requests to run */ + e1000e_disable_pcie_master(&adapter->hw); + + ew32(WUC, E1000_WUC_PME_EN); + ew32(WUFC, wufc); + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + ew32(WUC, 0); + ew32(WUFC, 0); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } + + e1000_release_manageability(adapter); + + /* make sure adapter isn't asleep if manageability is enabled */ + if (adapter->flags & FLAG_MNG_PT_ENABLED) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } + + if (adapter->hw.phy.type == e1000_phy_igp_3) + e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); + + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. */ + e1000_release_hw_control(adapter); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +#ifdef CONFIG_PM +static int e1000_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, + "Cannot enable PCI device from suspend\n"); + return err; + } + + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + if (netif_running(netdev)) { + err = e1000_request_irq(adapter); + if (err) + return err; + } + + e1000e_power_up_phy(adapter); + e1000e_reset(adapter); + ew32(WUS, ~0); + + e1000_init_manageability(adapter); + + if (netif_running(netdev)) + e1000e_up(adapter); + + netif_device_attach(netdev); + + /* If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. */ + if (!(adapter->flags & FLAG_HAS_AMT) || !e1000e_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + + return 0; +} +#endif + +static void e1000_shutdown(struct pci_dev *pdev) +{ + e1000_suspend(pdev, PMSG_SUSPEND); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void e1000_netpoll(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + disable_irq(adapter->pdev->irq); + e1000_intr(adapter->pdev->irq, netdev); + + e1000_clean_tx_irq(adapter); + + enable_irq(adapter->pdev->irq); +} +#endif + +/** + * e1000_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + + netif_device_detach(netdev); + + if (netif_running(netdev)) + e1000e_down(adapter); + pci_disable_device(pdev); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * e1000_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. Implementation + * resembles the first-half of the e1000_resume routine. + */ +static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + e1000e_reset(adapter); + ew32(WUS, ~0); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * e1000_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. Implementation resembles the + * second-half of the e1000_resume routine. + */ +static void e1000_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + + e1000_init_manageability(adapter); + + if (netif_running(netdev)) { + if (e1000e_up(adapter)) { + dev_err(&pdev->dev, + "can't bring device back up after reset\n"); + return; + } + } + + netif_device_attach(netdev); + + /* If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. */ + if (!(adapter->flags & FLAG_HAS_AMT) || + !e1000e_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + +} + +static void e1000_print_device_info(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 part_num; + + /* print bus type/speed/width info */ + ndev_info(netdev, "(PCI Express:2.5GB/s:%s) " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + /* bus width */ + ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : + "Width x1"), + /* MAC address */ + netdev->dev_addr[0], netdev->dev_addr[1], + netdev->dev_addr[2], netdev->dev_addr[3], + netdev->dev_addr[4], netdev->dev_addr[5]); + ndev_info(netdev, "Intel(R) PRO/%s Network Connection\n", + (hw->phy.type == e1000_phy_ife) + ? "10/100" : "1000"); + e1000e_read_part_num(hw, &part_num); + ndev_info(netdev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n", + hw->mac.type, hw->phy.type, + (part_num >> 8), (part_num & 0xff)); +} + +/** + * e1000_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in e1000_pci_tbl + * + * Returns 0 on success, negative on failure + * + * e1000_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +static int __devinit e1000_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct e1000_adapter *adapter; + struct e1000_hw *hw; + const struct e1000_info *ei = e1000_info_tbl[ent->driver_data]; + unsigned long mmio_start, mmio_len; + unsigned long flash_start, flash_len; + + static int cards_found; + int i, err, pci_using_dac; + u16 eeprom_data = 0; + u16 eeprom_apme_mask = E1000_EEPROM_APME; + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_using_dac = 0; + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) { + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + err = pci_set_consistent_dma_mask(pdev, + DMA_32BIT_MASK); + if (err) { + dev_err(&pdev->dev, "No usable DMA " + "configuration, aborting\n"); + goto err_dma; + } + } + } + + err = pci_request_regions(pdev, e1000e_driver_name); + if (err) + goto err_pci_reg; + + pci_set_master(pdev); + + err = -ENOMEM; + netdev = alloc_etherdev(sizeof(struct e1000_adapter)); + if (!netdev) + goto err_alloc_etherdev; + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + hw = &adapter->hw; + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->ei = ei; + adapter->pba = ei->pba; + adapter->flags = ei->flags; + adapter->hw.adapter = adapter; + adapter->hw.mac.type = ei->mac; + adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + + err = -EIO; + adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); + if (!adapter->hw.hw_addr) + goto err_ioremap; + + if ((adapter->flags & FLAG_HAS_FLASH) && + (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { + flash_start = pci_resource_start(pdev, 1); + flash_len = pci_resource_len(pdev, 1); + adapter->hw.flash_address = ioremap(flash_start, flash_len); + if (!adapter->hw.flash_address) + goto err_flashmap; + } + + /* construct the net_device struct */ + netdev->open = &e1000_open; + netdev->stop = &e1000_close; + netdev->hard_start_xmit = &e1000_xmit_frame; + netdev->get_stats = &e1000_get_stats; + netdev->set_multicast_list = &e1000_set_multi; + netdev->set_mac_address = &e1000_set_mac; + netdev->change_mtu = &e1000_change_mtu; + netdev->do_ioctl = &e1000_ioctl; + e1000e_set_ethtool_ops(netdev); + netdev->tx_timeout = &e1000_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); + netdev->vlan_rx_register = e1000_vlan_rx_register; + netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e1000_netpoll; +#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len; + + adapter->bd_number = cards_found++; + + /* setup adapter struct */ + err = e1000_sw_init(adapter); + if (err) + goto err_sw_init; + + err = -EIO; + + memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); + memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops)); + memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops)); + + err = ei->get_invariants(adapter); + if (err) + goto err_hw_init; + + hw->mac.ops.get_bus_info(&adapter->hw); + + adapter->hw.phy.wait_for_link = 0; + + /* Copper options */ + if (adapter->hw.media_type == e1000_media_type_copper) { + adapter->hw.phy.mdix = AUTO_ALL_MODES; + adapter->hw.phy.disable_polarity_correction = 0; + adapter->hw.phy.ms_type = e1000_ms_hw_default; + } + + if (e1000_check_reset_block(&adapter->hw)) + ndev_info(netdev, + "PHY reset is blocked due to SOL/IDER session.\n"); + + netdev->features = NETIF_F_SG | + NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX; + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) + netdev->features |= NETIF_F_HW_VLAN_FILTER; + + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + /* We should not be using LLTX anymore, but we are still TX faster with + * it. */ + netdev->features |= NETIF_F_LLTX; + + if (e1000e_enable_mng_pass_thru(&adapter->hw)) + adapter->flags |= FLAG_MNG_PT_ENABLED; + + /* before reading the NVM, reset the controller to + * put the device in a known good starting state */ + adapter->hw.mac.ops.reset_hw(&adapter->hw); + + /* + * systems with ASPM and others may see the checksum fail on the first + * attempt. Let's give it a few tries + */ + for (i = 0;; i++) { + if (e1000_validate_nvm_checksum(&adapter->hw) >= 0) + break; + if (i == 2) { + ndev_err(netdev, "The NVM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } + } + + /* copy the MAC address out of the NVM */ + if (e1000e_read_mac_addr(&adapter->hw)) + ndev_err(netdev, "NVM Read Error while reading MAC address\n"); + + memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len); + memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->perm_addr)) { + ndev_err(netdev, "Invalid MAC Address: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + netdev->perm_addr[0], netdev->perm_addr[1], + netdev->perm_addr[2], netdev->perm_addr[3], + netdev->perm_addr[4], netdev->perm_addr[5]); + err = -EIO; + goto err_eeprom; + } + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &e1000_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + + init_timer(&adapter->phy_info_timer); + adapter->phy_info_timer.function = &e1000_update_phy_info; + adapter->phy_info_timer.data = (unsigned long) adapter; + + INIT_WORK(&adapter->reset_task, e1000_reset_task); + INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); + + e1000e_check_options(adapter); + + /* Initialize link parameters. User can change them with ethtool */ + adapter->hw.mac.autoneg = 1; + adapter->hw.mac.original_fc = e1000_fc_default; + adapter->hw.mac.fc = e1000_fc_default; + adapter->hw.phy.autoneg_advertised = 0x2f; + + /* ring size defaults */ + adapter->rx_ring->count = 256; + adapter->tx_ring->count = 256; + + /* + * Initial Wake on LAN setting - If APM wake is enabled in + * the EEPROM, enable the ACPI Magic Packet filter + */ + if (adapter->flags & FLAG_APME_IN_WUC) { + /* APME bit in EEPROM is mapped to WUC.APME */ + eeprom_data = er32(WUC); + eeprom_apme_mask = E1000_WUC_APME; + } else if (adapter->flags & FLAG_APME_IN_CTRL3) { + if (adapter->flags & FLAG_APME_CHECK_PORT_B && + (adapter->hw.bus.func == 1)) + e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); + else + e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); + } + + /* fetch WoL from EEPROM */ + if (eeprom_data & eeprom_apme_mask) + adapter->eeprom_wol |= E1000_WUFC_MAG; + + /* + * now that we have the eeprom settings, apply the special cases + * where the eeprom may be wrong or the board simply won't support + * wake on lan on a particular port + */ + if (!(adapter->flags & FLAG_HAS_WOL)) + adapter->eeprom_wol = 0; + + /* initialize the wol settings based on the eeprom settings */ + adapter->wol = adapter->eeprom_wol; + + /* reset the hardware with the new settings */ + e1000e_reset(adapter); + + /* If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. */ + if (!(adapter->flags & FLAG_HAS_AMT) || + !e1000e_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + + /* tell the stack to leave us alone until e1000_open() is called */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + e1000_print_device_info(adapter); + + return 0; + +err_register: +err_hw_init: + e1000_release_hw_control(adapter); +err_eeprom: + if (!e1000_check_reset_block(&adapter->hw)) + e1000_phy_hw_reset(&adapter->hw); + + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); + +err_flashmap: + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +err_sw_init: + iounmap(adapter->hw.hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * e1000_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * e1000_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit e1000_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* flush_scheduled work may reschedule our watchdog task, so + * explicitly disable watchdog tasks from being rescheduled */ + set_bit(__E1000_DOWN, &adapter->state); + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + flush_scheduled_work(); + + e1000_release_manageability(adapter); + + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. */ + e1000_release_hw_control(adapter); + + unregister_netdev(netdev); + + if (!e1000_check_reset_block(&adapter->hw)) + e1000_phy_hw_reset(&adapter->hw); + + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + + iounmap(adapter->hw.hw_addr); + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); + pci_release_regions(pdev); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +/* PCI Error Recovery (ERS) */ +static struct pci_error_handlers e1000_err_handler = { + .error_detected = e1000_io_error_detected, + .slot_reset = e1000_io_slot_reset, + .resume = e1000_io_resume, +}; + +static struct pci_device_id e1000_pci_tbl[] = { + /* + * Support for 82571/2/3, es2lan and ich8 will be phased in + * stepwise. + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan }, + */ + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan }, + + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); + +/* PCI Device API Driver */ +static struct pci_driver e1000_driver = { + .name = e1000e_driver_name, + .id_table = e1000_pci_tbl, + .probe = e1000_probe, + .remove = __devexit_p(e1000_remove), +#ifdef CONFIG_PM + /* Power Managment Hooks */ + .suspend = e1000_suspend, + .resume = e1000_resume, +#endif + .shutdown = e1000_shutdown, + .err_handler = &e1000_err_handler +}; + +/** + * e1000_init_module - Driver Registration Routine + * + * e1000_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ +static int __init e1000_init_module(void) +{ + int ret; + printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n", + e1000e_driver_name, e1000e_driver_version); + printk(KERN_INFO "%s: Copyright (c) 1999-2007 Intel Corporation.\n", + e1000e_driver_name); + ret = pci_register_driver(&e1000_driver); + + return ret; +} +module_init(e1000_init_module); + +/** + * e1000_exit_module - Driver Exit Cleanup Routine + * + * e1000_exit_module is called just before the driver is removed + * from memory. + **/ +static void __exit e1000_exit_module(void) +{ + pci_unregister_driver(&e1000_driver); +} +module_exit(e1000_exit_module); + + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +/* e1000_main.c */ diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c new file mode 100644 index 000000000000..e4e655efb23c --- /dev/null +++ b/drivers/net/e1000e/param.c @@ -0,0 +1,382 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include + +#include "e1000.h" + +/* This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ + +#define E1000_MAX_NIC 32 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +#define COPYBREAK_DEFAULT 256 +unsigned int copybreak = COPYBREAK_DEFAULT; +module_param(copybreak, uint, 0644); +MODULE_PARM_DESC(copybreak, + "Maximum size of packet that is copied to a new buffer on receive"); + +/* All parameters are treated the same, as an integer array of values. + * This macro just reduces the need to repeat the same declaration code + * over and over (plus this helps to avoid typo bugs). + */ + +#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } +#define E1000_PARAM(X, desc) \ + static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \ + static int num_##X; \ + module_param_array_named(X, X, int, &num_##X, 0); \ + MODULE_PARM_DESC(X, desc); + + +/* Transmit Interrupt Delay in units of 1.024 microseconds + * Tx interrupt delay needs to typically be set to something non zero + * + * Valid Range: 0-65535 + */ +E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay"); +#define DEFAULT_TIDV 8 +#define MAX_TXDELAY 0xFFFF +#define MIN_TXDELAY 0 + +/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + */ +E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay"); +#define DEFAULT_TADV 32 +#define MAX_TXABSDELAY 0xFFFF +#define MIN_TXABSDELAY 0 + +/* Receive Interrupt Delay in units of 1.024 microseconds + * hardware will likely hang if you set this to anything but zero. + * + * Valid Range: 0-65535 + */ +E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); +#define DEFAULT_RDTR 0 +#define MAX_RXDELAY 0xFFFF +#define MIN_RXDELAY 0 + +/* Receive Absolute Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + */ +E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); +#define DEFAULT_RADV 8 +#define MAX_RXABSDELAY 0xFFFF +#define MIN_RXABSDELAY 0 + +/* Interrupt Throttle Rate (interrupts/sec) + * + * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative) + */ +E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); +#define DEFAULT_ITR 3 +#define MAX_ITR 100000 +#define MIN_ITR 100 + +/* Enable Smart Power Down of the PHY + * + * Valid Range: 0, 1 + * + * Default Value: 0 (disabled) + */ +E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); + +/* Enable Kumeran Lock Loss workaround + * + * Valid Range: 0, 1 + * + * Default Value: 1 (enabled) + */ +E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); + +struct e1000_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct e1000_opt_list { int i; char *str; } *p; + } l; + } arg; +}; + +static int __devinit e1000_validate_option(int *value, + struct e1000_option *opt, + struct e1000_adapter *adapter) +{ + if (*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + ndev_info(adapter->netdev, "%s Enabled\n", opt->name); + return 0; + case OPTION_DISABLED: + ndev_info(adapter->netdev, "%s Disabled\n", opt->name); + return 0; + } + break; + case range_option: + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + ndev_info(adapter->netdev, + "%s set to %i\n", opt->name, *value); + return 0; + } + break; + case list_option: { + int i; + struct e1000_opt_list *ent; + + for (i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if (*value == ent->i) { + if (ent->str[0] != '\0') + ndev_info(adapter->netdev, "%s\n", + ent->str); + return 0; + } + } + } + break; + default: + BUG(); + } + + ndev_info(adapter->netdev, "Invalid %s value specified (%i) %s\n", + opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +/** + * e1000e_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line parameters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + **/ +void __devinit e1000e_check_options(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + int bd = adapter->bd_number; + + if (bd >= E1000_MAX_NIC) { + ndev_notice(netdev, + "Warning: no configuration for board #%i\n", bd); + ndev_notice(netdev, "Using defaults for all values\n"); + } + + { /* Transmit Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Transmit Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_TIDV), + .def = DEFAULT_TIDV, + .arg = { .r = { .min = MIN_TXDELAY, + .max = MAX_TXDELAY } } + }; + + if (num_TxIntDelay > bd) { + adapter->tx_int_delay = TxIntDelay[bd]; + e1000_validate_option(&adapter->tx_int_delay, &opt, + adapter); + } else { + adapter->tx_int_delay = opt.def; + } + } + { /* Transmit Absolute Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Transmit Absolute Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_TADV), + .def = DEFAULT_TADV, + .arg = { .r = { .min = MIN_TXABSDELAY, + .max = MAX_TXABSDELAY } } + }; + + if (num_TxAbsIntDelay > bd) { + adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; + e1000_validate_option(&adapter->tx_abs_int_delay, &opt, + adapter); + } else { + adapter->tx_abs_int_delay = opt.def; + } + } + { /* Receive Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Receive Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_RDTR), + .def = DEFAULT_RDTR, + .arg = { .r = { .min = MIN_RXDELAY, + .max = MAX_RXDELAY } } + }; + + /* modify min and default if 82573 for slow ping w/a, + * a value greater than 8 needs to be set for RDTR */ + if (adapter->flags & FLAG_HAS_ASPM) { + opt.def = 32; + opt.arg.r.min = 8; + } + + if (num_RxIntDelay > bd) { + adapter->rx_int_delay = RxIntDelay[bd]; + e1000_validate_option(&adapter->rx_int_delay, &opt, + adapter); + } else { + adapter->rx_int_delay = opt.def; + } + } + { /* Receive Absolute Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Receive Absolute Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_RADV), + .def = DEFAULT_RADV, + .arg = { .r = { .min = MIN_RXABSDELAY, + .max = MAX_RXABSDELAY } } + }; + + if (num_RxAbsIntDelay > bd) { + adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; + e1000_validate_option(&adapter->rx_abs_int_delay, &opt, + adapter); + } else { + adapter->rx_abs_int_delay = opt.def; + } + } + { /* Interrupt Throttling Rate */ + struct e1000_option opt = { + .type = range_option, + .name = "Interrupt Throttling Rate (ints/sec)", + .err = "using default of " + __MODULE_STRING(DEFAULT_ITR), + .def = DEFAULT_ITR, + .arg = { .r = { .min = MIN_ITR, + .max = MAX_ITR } } + }; + + if (num_InterruptThrottleRate > bd) { + adapter->itr = InterruptThrottleRate[bd]; + switch (adapter->itr) { + case 0: + ndev_info(netdev, "%s turned off\n", + opt.name); + break; + case 1: + ndev_info(netdev, + "%s set to dynamic mode\n", + opt.name); + adapter->itr_setting = adapter->itr; + adapter->itr = 20000; + break; + case 3: + ndev_info(netdev, + "%s set to dynamic conservative mode\n", + opt.name); + adapter->itr_setting = adapter->itr; + adapter->itr = 20000; + break; + default: + e1000_validate_option(&adapter->itr, &opt, + adapter); + /* + * save the setting, because the dynamic bits + * change itr. clear the lower two bits + * because they are used as control + */ + adapter->itr_setting = adapter->itr & ~3; + break; + } + } else { + adapter->itr_setting = opt.def; + adapter->itr = 20000; + } + } + { /* Smart Power Down */ + struct e1000_option opt = { + .type = enable_option, + .name = "PHY Smart Power Down", + .err = "defaulting to Disabled", + .def = OPTION_DISABLED + }; + + if (num_SmartPowerDownEnable > bd) { + int spd = SmartPowerDownEnable[bd]; + e1000_validate_option(&spd, &opt, adapter); + if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) + && spd) + adapter->flags |= FLAG_SMART_POWER_DOWN; + } + } + { /* Kumeran Lock Loss Workaround */ + struct e1000_option opt = { + .type = enable_option, + .name = "Kumeran Lock Loss Workaround", + .err = "defaulting to Enabled", + .def = OPTION_ENABLED + }; + + if (num_KumeranLockLoss > bd) { + int kmrn_lock_loss = KumeranLockLoss[bd]; + e1000_validate_option(&kmrn_lock_loss, &opt, adapter); + if (hw->mac.type == e1000_ich8lan) + e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, + kmrn_lock_loss); + } else { + if (hw->mac.type == e1000_ich8lan) + e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, + opt.def); + } + } +} diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c new file mode 100644 index 000000000000..793231810ae0 --- /dev/null +++ b/drivers/net/e1000e/phy.c @@ -0,0 +1,1773 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include + +#include "e1000.h" + +static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw); +static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw); +static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active); +static s32 e1000_wait_autoneg(struct e1000_hw *hw); + +/* Cable length tables */ +static const u16 e1000_m88_cable_length_table[] = + { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; + +static const u16 e1000_igp_2_cable_length_table[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3, + 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, 6, 10, 14, 18, 22, + 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, 21, 26, 31, 35, 40, + 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, 40, 45, 51, 56, 61, + 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, 60, 66, 72, 77, 82, + 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95, + 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121, + 124}; +#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ + (sizeof(e1000_igp_2_cable_length_table) / \ + sizeof(e1000_igp_2_cable_length_table[0])) + +/** + * e1000e_check_reset_block_generic - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * + * Read the PHY management control register and check whether a PHY reset + * is blocked. If a reset is not blocked return 0, otherwise + * return E1000_BLK_PHY_RESET (12). + **/ +s32 e1000e_check_reset_block_generic(struct e1000_hw *hw) +{ + u32 manc; + + manc = er32(MANC); + + return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? + E1000_BLK_PHY_RESET : 0; +} + +/** + * e1000e_get_phy_id - Retrieve the PHY ID and revision + * @hw: pointer to the HW structure + * + * Reads the PHY registers and stores the PHY ID and possibly the PHY + * revision in the hardware structure. + **/ +s32 e1000e_get_phy_id(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_id; + + ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); + if (ret_val) + return ret_val; + + phy->id = (u32)(phy_id << 16); + udelay(20); + ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); + if (ret_val) + return ret_val; + + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + + return 0; +} + +/** + * e1000e_phy_reset_dsp - Reset PHY DSP + * @hw: pointer to the HW structure + * + * Reset the digital signal processor. + **/ +s32 e1000e_phy_reset_dsp(struct e1000_hw *hw) +{ + s32 ret_val; + + ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); + if (ret_val) + return ret_val; + + return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0); +} + +/** + * e1000_read_phy_reg_mdic - Read MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the MDI control regsiter in the PHY at offset and stores the + * information read to data. + **/ +static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + + if (offset > MAX_PHY_REG_ADDRESS) { + hw_dbg(hw, "PHY Address %d is out of range\n", offset); + return -E1000_ERR_PARAM; + } + + /* Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = ((offset << E1000_MDIC_REG_SHIFT) | + (phy->addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_READ)); + + ew32(MDIC, mdic); + + /* Poll the ready bit to see if the MDI read completed */ + for (i = 0; i < 64; i++) { + udelay(50); + mdic = er32(MDIC); + if (mdic & E1000_MDIC_READY) + break; + } + if (!(mdic & E1000_MDIC_READY)) { + hw_dbg(hw, "MDI Read did not complete\n"); + return -E1000_ERR_PHY; + } + if (mdic & E1000_MDIC_ERROR) { + hw_dbg(hw, "MDI Error\n"); + return -E1000_ERR_PHY; + } + *data = (u16) mdic; + + return 0; +} + +/** + * e1000_write_phy_reg_mdic - Write MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write to register at offset + * + * Writes data to MDI control register in the PHY at offset. + **/ +static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + + if (offset > MAX_PHY_REG_ADDRESS) { + hw_dbg(hw, "PHY Address %d is out of range\n", offset); + return -E1000_ERR_PARAM; + } + + /* Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = (((u32)data) | + (offset << E1000_MDIC_REG_SHIFT) | + (phy->addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_WRITE)); + + ew32(MDIC, mdic); + + /* Poll the ready bit to see if the MDI read completed */ + for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) { + udelay(5); + mdic = er32(MDIC); + if (mdic & E1000_MDIC_READY) + break; + } + if (!(mdic & E1000_MDIC_READY)) { + hw_dbg(hw, "MDI Write did not complete\n"); + return -E1000_ERR_PHY; + } + + return 0; +} + +/** + * e1000e_read_phy_reg_m88 - Read m88 PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_write_phy_reg_m88 - Write m88 PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_read_phy_reg_igp - Read igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (u16)offset); + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + } + + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_write_phy_reg_igp - Write igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (u16)offset); + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + } + + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_read_kmrn_reg - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary. Then reads the PHY register at offset + * using the kumeran interface. The information retrieved is stored in data. + * Release any acquired semaphores before exiting. + **/ +s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data) +{ + u32 kmrnctrlsta; + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; + ew32(KMRNCTRLSTA, kmrnctrlsta); + + udelay(2); + + kmrnctrlsta = er32(KMRNCTRLSTA); + *data = (u16)kmrnctrlsta; + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_write_kmrn_reg - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary. Then write the data to PHY register + * at the offset using the kumeran interface. Release any acquired semaphores + * before exiting. + **/ +s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) +{ + u32 kmrnctrlsta; + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | data; + ew32(KMRNCTRLSTA, kmrnctrlsta); + + udelay(2); + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock + * and downshift values are set also. + **/ +s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (phy->mdix) { + case 1: + phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_data |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_data |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; + if (phy->disable_polarity_correction == 1) + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; + + ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + if (phy->revision < 4) { + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if ((phy->revision == 2) && + (phy->id == M88E1111_I_PHY_ID)) { + /* 82573L PHY - set the downshift counter to 5x. */ + phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK; + phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; + } else { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + } + ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + } + + /* Commit the changes. */ + ret_val = e1000e_commit_phy(hw); + if (ret_val) + hw_dbg(hw, "Error committing the PHY changes\n"); + + return ret_val; +} + +/** + * e1000e_copper_link_setup_igp - Setup igp PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for + * igp PHY's. + **/ +s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = e1000_phy_hw_reset(hw); + if (ret_val) { + hw_dbg(hw, "Error resetting the PHY.\n"); + return ret_val; + } + + /* Wait 15ms for MAC to configure PHY from NVM settings. */ + msleep(15); + + /* disable lplu d0 during driver init */ + ret_val = e1000_set_d0_lplu_state(hw, 0); + if (ret_val) { + hw_dbg(hw, "Error Disabling LPLU D0\n"); + return ret_val; + } + /* Configure mdi-mdix settings */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCR_AUTO_MDIX; + + switch (phy->mdix) { + case 1: + data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 2: + data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 0: + default: + data |= IGP01E1000_PSCR_AUTO_MDIX; + break; + } + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data); + if (ret_val) + return ret_val; + + /* set auto-master slave resolution settings */ + if (hw->mac.autoneg) { + /* when autonegotiation advertisement is only 1000Mbps then we + * should disable SmartSpeed and enable Auto MasterSlave + * resolution as hardware default. */ + if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { + /* Disable SmartSpeed */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + + /* Set auto Master/Slave resolution process */ + ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data); + if (ret_val) + return ret_val; + + data &= ~CR_1000T_MS_ENABLE; + ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data); + if (ret_val) + return ret_val; + } + + ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data); + if (ret_val) + return ret_val; + + /* load defaults for future use */ + phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? + ((data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : + e1000_ms_force_slave) : + e1000_ms_auto; + + switch (phy->ms_type) { + case e1000_ms_force_master: + data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + data |= CR_1000T_MS_ENABLE; + data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + data &= ~CR_1000T_MS_ENABLE; + default: + break; + } + ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data); + } + + return ret_val; +} + +/** + * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation + * @hw: pointer to the HW structure + * + * Reads the MII auto-neg advertisement register and/or the 1000T control + * register and if the PHY is already setup for auto-negotiation, then + * return successful. Otherwise, setup advertisement and flow control to + * the appropriate values for the wanted auto-negotiation. + **/ +static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg = 0; + + phy->autoneg_advertised &= phy->autoneg_mask; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + } + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | + NWAY_AR_100TX_HD_CAPS | + NWAY_AR_10T_FD_CAPS | + NWAY_AR_10T_HD_CAPS); + mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); + + hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_HALF) { + hw_dbg(hw, "Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_FULL) { + hw_dbg(hw, "Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_HALF) { + hw_dbg(hw, "Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_FULL) { + hw_dbg(hw, "Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if (phy->autoneg_advertised & ADVERTISE_1000_HALF) + hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n"); + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { + hw_dbg(hw, "Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- + * negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (hw->mac.fc) { + case e1000_fc_none: + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_rx_pause: + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * (in e1000e_config_fc_after_link_up) we will disable the + * hw's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_tx_pause: + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case e1000_fc_full: + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = -E1000_ERR_CONFIG; + return ret_val; + } + + ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + } + + return ret_val; +} + +/** + * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link + * @hw: pointer to the HW structure + * + * Performs initial bounds checking on autoneg advertisement parameter, then + * configure to advertise the full capability. Setup the PHY to autoneg + * and restart the negotiation process between the link partner. If + * wait_for_link, then wait for autoneg to complete before exiting. + **/ +static s32 e1000_copper_link_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_ctrl; + + /* Perform some bounds checking on the autoneg advertisement + * parameter. + */ + phy->autoneg_advertised &= phy->autoneg_mask; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if (phy->autoneg_advertised == 0) + phy->autoneg_advertised = phy->autoneg_mask; + + hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n"); + ret_val = e1000_phy_setup_autoneg(hw); + if (ret_val) { + hw_dbg(hw, "Error Setting up Auto-Negotiation\n"); + return ret_val; + } + hw_dbg(hw, "Restarting Auto-Neg\n"); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + return ret_val; + + phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + return ret_val; + + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if (phy->wait_for_link) { + ret_val = e1000_wait_autoneg(hw); + if (ret_val) { + hw_dbg(hw, "Error while waiting for " + "autoneg to complete\n"); + return ret_val; + } + } + + hw->mac.get_link_status = 1; + + return ret_val; +} + +/** + * e1000e_setup_copper_link - Configure copper link settings + * @hw: pointer to the HW structure + * + * Calls the appropriate function to configure the link for auto-neg or forced + * speed and duplex. Then we check for link, once link is established calls + * to configure collision distance and flow control are called. If link is + * not established, we return -E1000_ERR_PHY (-2). + **/ +s32 e1000e_setup_copper_link(struct e1000_hw *hw) +{ + s32 ret_val; + bool link; + + if (hw->mac.autoneg) { + /* Setup autoneg and flow control advertisement and perform + * autonegotiation. */ + ret_val = e1000_copper_link_autoneg(hw); + if (ret_val) + return ret_val; + } else { + /* PHY will be set to 10H, 10F, 100H or 100F + * depending on user settings. */ + hw_dbg(hw, "Forcing Speed and Duplex\n"); + ret_val = e1000_phy_force_speed_duplex(hw); + if (ret_val) { + hw_dbg(hw, "Error Forcing Speed and Duplex\n"); + return ret_val; + } + } + + /* Check link status. Wait up to 100 microseconds for link to become + * valid. + */ + ret_val = e1000e_phy_has_link_generic(hw, + COPPER_LINK_UP_LIMIT, + 10, + &link); + if (ret_val) + return ret_val; + + if (link) { + hw_dbg(hw, "Valid link established!!!\n"); + e1000e_config_collision_dist(hw); + ret_val = e1000e_config_fc_after_link_up(hw); + } else { + hw_dbg(hw, "Unable to establish link!!!\n"); + } + + return ret_val; +} + +/** + * e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Waits for link and returns + * successful if link up is successful, else -E1000_ERR_PHY (-2). + **/ +s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); + if (ret_val) + return ret_val; + + /* Clear Auto-Crossover to force MDI manually. IGP requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; + phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); + if (ret_val) + return ret_val; + + hw_dbg(hw, "IGP PSCR: %X\n", phy_data); + + udelay(1); + + if (phy->wait_for_link) { + hw_dbg(hw, "Waiting for forced speed/duplex link on IGP phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + return ret_val; + + if (!link) + hw_dbg(hw, "Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + return ret_val; + } + + return ret_val; +} + +/** + * e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Resets the PHY to commit the + * changes. If time expires while waiting for link up, we reset the DSP. + * After reset, TX_CLK and CRS on TX must be set. Return successful upon + * successful completion, else return corresponding error code. + **/ +s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data); + + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + /* Reset the phy to commit changes. */ + phy_data |= MII_CR_RESET; + + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); + if (ret_val) + return ret_val; + + udelay(1); + + if (phy->wait_for_link) { + hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + return ret_val; + + if (!link) { + /* We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT, 0x001d); + if (ret_val) + return ret_val; + ret_val = e1000e_phy_reset_dsp(hw); + if (ret_val) + return ret_val; + } + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + return ret_val; + } + + ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + /* Resetting the phy means we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock from + * the reset value of 2.5MHz. + */ + phy_data |= M88E1000_EPSCR_TX_CLK_25; + ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + /* In addition, we must re-enable CRS on Tx for both half and full + * duplex. + */ + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + + return ret_val; +} + +/** + * e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex + * @hw: pointer to the HW structure + * @phy_ctrl: pointer to current value of PHY_CONTROL + * + * Forces speed and duplex on the PHY by doing the following: disable flow + * control, force speed/duplex on the MAC, disable auto speed detection, + * disable auto-negotiation, configure duplex, configure speed, configure + * the collision distance, write configuration to CTRL register. The + * caller must write to the PHY_CONTROL register for these settings to + * take affect. + **/ +void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl; + + /* Turn off flow control when forcing speed/duplex */ + mac->fc = e1000_fc_none; + + /* Force speed/duplex on the mac */ + ctrl = er32(CTRL); + ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl &= ~E1000_CTRL_SPD_SEL; + + /* Disable Auto Speed Detection */ + ctrl &= ~E1000_CTRL_ASDE; + + /* Disable autoneg on the phy */ + *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; + + /* Forcing Full or Half Duplex? */ + if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { + ctrl &= ~E1000_CTRL_FD; + *phy_ctrl &= ~MII_CR_FULL_DUPLEX; + hw_dbg(hw, "Half Duplex\n"); + } else { + ctrl |= E1000_CTRL_FD; + *phy_ctrl |= MII_CR_FULL_DUPLEX; + hw_dbg(hw, "Full Duplex\n"); + } + + /* Forcing 10mb or 100mb? */ + if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { + ctrl |= E1000_CTRL_SPD_100; + *phy_ctrl |= MII_CR_SPEED_100; + *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + hw_dbg(hw, "Forcing 100mb\n"); + } else { + ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + *phy_ctrl |= MII_CR_SPEED_10; + *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + hw_dbg(hw, "Forcing 10mb\n"); + } + + e1000e_config_collision_dist(hw); + + ew32(CTRL, ctrl); +} + +/** + * e1000e_set_d3_lplu_state - Sets low power link up state for D3 + * @hw: pointer to the HW structure + * @active: boolean used to enable/disable lplu + * + * Success returns 0, Failure returns 1 + * + * The low power link up (lplu) state is set to the power management level D3 + * and SmartSpeed is disabled when active is true, else clear lplu for D3 + * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU + * is used during Dx states where the power conservation is most important. + * During driver activity, SmartSpeed should be enabled so performance is + * maintained. + **/ +s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data); + if (ret_val) + return ret_val; + + if (!active) { + data &= ~IGP02E1000_PM_D3_LPLU; + ret_val = e1e_wphy(hw, + IGP02E1000_PHY_POWER_MGMT, + data); + if (ret_val) + return ret_val; + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + data |= IGP02E1000_PM_D3_LPLU; + ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); + if (ret_val) + return ret_val; + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data); + } + + return ret_val; +} + +/** + * e1000e_check_downshift - Checks whether a downshift in speed occured + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns 1 + * + * A downshift is detected by querying the PHY link health. + **/ +s32 e1000e_check_downshift(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + switch (phy->type) { + case e1000_phy_m88: + case e1000_phy_gg82563: + offset = M88E1000_PHY_SPEC_STATUS; + mask = M88E1000_PSSR_DOWNSHIFT; + break; + case e1000_phy_igp_2: + case e1000_phy_igp_3: + offset = IGP01E1000_PHY_LINK_HEALTH; + mask = IGP01E1000_PLHR_SS_DOWNGRADE; + break; + default: + /* speed downshift not supported */ + phy->speed_downgraded = 0; + return 0; + } + + ret_val = e1e_rphy(hw, offset, &phy_data); + + if (!ret_val) + phy->speed_downgraded = (phy_data & mask); + + return ret_val; +} + +/** + * e1000_check_polarity_m88 - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY specific status register. + **/ +static s32 e1000_check_polarity_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data); + + if (!ret_val) + phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_check_polarity_igp - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY port status register, and the + * current speed (since there is no polarity at 100Mbps). + **/ +static s32 e1000_check_polarity_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data, offset, mask; + + /* Polarity is determined based on the speed of + * our connection. */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data); + if (ret_val) + return ret_val; + + if ((data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + offset = IGP01E1000_PHY_PCS_INIT_REG; + mask = IGP01E1000_PHY_POLARITY_MASK; + } else { + /* This really only applies to 10Mbps since + * there is no polarity for 100Mbps (always 0). + */ + offset = IGP01E1000_PHY_PORT_STATUS; + mask = IGP01E1000_PSSR_POLARITY_REVERSED; + } + + ret_val = e1e_rphy(hw, offset, &data); + + if (!ret_val) + phy->cable_polarity = (data & mask) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_wait_autoneg - Wait for auto-neg compeletion + * @hw: pointer to the HW structure + * + * Waits for auto-negotiation to complete or for the auto-negotiation time + * limit to expire, which ever happens first. + **/ +static s32 e1000_wait_autoneg(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 i, phy_status; + + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { + ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_AUTONEG_COMPLETE) + break; + msleep(100); + } + + /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation + * has completed. + */ + return ret_val; +} + +/** + * e1000e_phy_has_link_generic - Polls PHY for link + * @hw: pointer to the HW structure + * @iterations: number of times to poll for link + * @usec_interval: delay between polling attempts + * @success: pointer to whether polling was successful or not + * + * Polls the PHY status register for link, 'iterations' number of times. + **/ +s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, + u32 usec_interval, bool *success) +{ + s32 ret_val = 0; + u16 i, phy_status; + + for (i = 0; i < iterations; i++) { + /* Some PHYs require the PHY_STATUS register to be read + * twice due to the link bit being sticky. No harm doing + * it across the board. + */ + ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_LINK_STATUS) + break; + if (usec_interval >= 1000) + mdelay(usec_interval/1000); + else + udelay(usec_interval); + } + + *success = (i < iterations); + + return ret_val; +} + +/** + * e1000e_get_cable_length_m88 - Determine cable length for m88 PHY + * @hw: pointer to the HW structure + * + * Reads the PHY specific status register to retrieve the cable length + * information. The cable length is determined by averaging the minimum and + * maximum values to get the "average" cable length. The m88 PHY has four + * possible cable length values, which are: + * Register Value Cable Length + * 0 < 50 meters + * 1 50 - 80 meters + * 2 80 - 110 meters + * 3 110 - 140 meters + * 4 > 140 meters + **/ +s32 e1000e_get_cable_length_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, index; + + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + if (ret_val) + return ret_val; + + index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT; + phy->min_cable_length = e1000_m88_cable_length_table[index]; + phy->max_cable_length = e1000_m88_cable_length_table[index+1]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + + return ret_val; +} + +/** + * e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY + * @hw: pointer to the HW structure + * + * The automatic gain control (agc) normalizes the amplitude of the + * received signal, adjusting for the attenuation produced by the + * cable. By reading the AGC registers, which reperesent the + * cobination of course and fine gain value, the value can be put + * into a lookup table to obtain the approximate cable length + * for each channel. + **/ +s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, i, agc_value = 0; + u16 cur_agc_index, max_agc_index = 0; + u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; + u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = + {IGP02E1000_PHY_AGC_A, + IGP02E1000_PHY_AGC_B, + IGP02E1000_PHY_AGC_C, + IGP02E1000_PHY_AGC_D}; + + /* Read the AGC registers for all channels */ + for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { + ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data); + if (ret_val) + return ret_val; + + /* Getting bits 15:9, which represent the combination of + * course and fine gain values. The result is a number + * that can be put into the lookup table to obtain the + * approximate cable length. */ + cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Array index bound check. */ + if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || + (cur_agc_index == 0)) + return -E1000_ERR_PHY; + + /* Remove min & max AGC values from calculation. */ + if (e1000_igp_2_cable_length_table[min_agc_index] > + e1000_igp_2_cable_length_table[cur_agc_index]) + min_agc_index = cur_agc_index; + if (e1000_igp_2_cable_length_table[max_agc_index] < + e1000_igp_2_cable_length_table[cur_agc_index]) + max_agc_index = cur_agc_index; + + agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; + } + + agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + + e1000_igp_2_cable_length_table[max_agc_index]); + agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); + + /* Calculate cable length with the error range of +/- 10 meters. */ + phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? + (agc_value - IGP02E1000_AGC_RANGE) : 0; + phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + + return ret_val; +} + +/** + * e1000e_get_phy_info_m88 - Retrieve PHY information + * @hw: pointer to the HW structure + * + * Valid for only copper links. Read the PHY status register (sticky read) + * to verify that link is up. Read the PHY special control register to + * determine the polarity and 10base-T extended distance. Read the PHY + * special status register to determine MDI/MDIx and current speed. If + * speed is 1000, then determine cable length, local and remote receiver. + **/ +s32 e1000e_get_phy_info_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + if (hw->media_type != e1000_media_type_copper) { + hw_dbg(hw, "Phy info is only valid for copper media\n"); + return -E1000_ERR_CONFIG; + } + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } + + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy->polarity_correction = (phy_data & + M88E1000_PSCR_POLARITY_REVERSAL); + + ret_val = e1000_check_polarity_m88(hw); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + if (ret_val) + return ret_val; + + phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX); + + if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { + ret_val = e1000_get_cable_length(hw); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data); + if (ret_val) + return ret_val; + + phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + /* Set values to "undefined" */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + + return ret_val; +} + +/** + * e1000e_get_phy_info_igp - Retrieve igp PHY information + * @hw: pointer to the HW structure + * + * Read PHY status to determine if link is up. If link is up, then + * set/determine 10base-T extended distance and polarity correction. Read + * PHY port status to determine MDI/MDIx and speed. Based on the speed, + * determine on the cable length, local and remote receiver. + **/ +s32 e1000e_get_phy_info_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } + + phy->polarity_correction = 1; + + ret_val = e1000_check_polarity_igp(hw); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data); + if (ret_val) + return ret_val; + + phy->is_mdix = (data & IGP01E1000_PSSR_MDIX); + + if ((data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + ret_val = e1000_get_cable_length(hw); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data); + if (ret_val) + return ret_val; + + phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + + return ret_val; +} + +/** + * e1000e_phy_sw_reset - PHY software reset + * @hw: pointer to the HW structure + * + * Does a software reset of the PHY by reading the PHY control register and + * setting/write the control register reset bit to the PHY. + **/ +s32 e1000e_phy_sw_reset(struct e1000_hw *hw) +{ + s32 ret_val; + u16 phy_ctrl; + + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + return ret_val; + + phy_ctrl |= MII_CR_RESET; + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + return ret_val; + + udelay(1); + + return ret_val; +} + +/** + * e1000e_phy_hw_reset_generic - PHY hardware reset + * @hw: pointer to the HW structure + * + * Verify the reset block is not blocking us from resetting. Acquire + * semaphore (if necessary) and read/set/write the device control reset + * bit in the PHY. Wait the appropriate delay time for the device to + * reset and relase the semaphore (if necessary). + **/ +s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u32 ctrl; + + ret_val = e1000_check_reset_block(hw); + if (ret_val) + return 0; + + ret_val = phy->ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + ctrl = er32(CTRL); + ew32(CTRL, ctrl | E1000_CTRL_PHY_RST); + e1e_flush(); + + udelay(phy->reset_delay_us); + + ew32(CTRL, ctrl); + e1e_flush(); + + udelay(150); + + phy->ops.release_phy(hw); + + return e1000_get_phy_cfg_done(hw); +} + +/** + * e1000e_get_cfg_done - Generic configuration done + * @hw: pointer to the HW structure + * + * Generic function to wait 10 milli-seconds for configuration to complete + * and return success. + **/ +s32 e1000e_get_cfg_done(struct e1000_hw *hw) +{ + mdelay(10); + return 0; +} + +/* Internal function pointers */ + +/** + * e1000_get_phy_cfg_done - Generic PHY configuration done + * @hw: pointer to the HW structure + * + * Return success if silicon family did not implement a family specific + * get_cfg_done function. + **/ +static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw) +{ + if (hw->phy.ops.get_cfg_done) + return hw->phy.ops.get_cfg_done(hw); + + return 0; +} + +/** + * e1000_phy_force_speed_duplex - Generic force PHY speed/duplex + * @hw: pointer to the HW structure + * + * When the silicon family has not implemented a forced speed/duplex + * function for the PHY, simply return 0. + **/ +static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw) +{ + if (hw->phy.ops.force_speed_duplex) + return hw->phy.ops.force_speed_duplex(hw); + + return 0; +} + +/** + * e1000e_get_phy_type_from_id - Get PHY type from id + * @phy_id: phy_id read from the phy + * + * Returns the phy type from the id. + **/ +enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) +{ + enum e1000_phy_type phy_type = e1000_phy_unknown; + + switch (phy_id) { + case M88E1000_I_PHY_ID: + case M88E1000_E_PHY_ID: + case M88E1111_I_PHY_ID: + case M88E1011_I_PHY_ID: + phy_type = e1000_phy_m88; + break; + case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ + phy_type = e1000_phy_igp_2; + break; + case GG82563_E_PHY_ID: + phy_type = e1000_phy_gg82563; + break; + case IGP03E1000_E_PHY_ID: + phy_type = e1000_phy_igp_3; + break; + case IFE_E_PHY_ID: + case IFE_PLUS_E_PHY_ID: + case IFE_C_E_PHY_ID: + phy_type = e1000_phy_ife; + break; + default: + phy_type = e1000_phy_unknown; + break; + } + return phy_type; +} + +/** + * e1000e_commit_phy - Soft PHY reset + * @hw: pointer to the HW structure + * + * Performs a soft PHY reset on those that apply. This is a function pointer + * entry point called by drivers. + **/ +s32 e1000e_commit_phy(struct e1000_hw *hw) +{ + if (hw->phy.ops.commit_phy) + return hw->phy.ops.commit_phy(hw); + + return 0; +} + +/** + * e1000_set_d0_lplu_state - Sets low power link up state for D0 + * @hw: pointer to the HW structure + * @active: boolean used to enable/disable lplu + * + * Success returns 0, Failure returns 1 + * + * The low power link up (lplu) state is set to the power management level D0 + * and SmartSpeed is disabled when active is true, else clear lplu for D0 + * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU + * is used during Dx states where the power conservation is most important. + * During driver activity, SmartSpeed should be enabled so performance is + * maintained. This is a function pointer entry point called by drivers. + **/ +static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active) +{ + if (hw->phy.ops.set_d0_lplu_state) + return hw->phy.ops.set_d0_lplu_state(hw, active); + + return 0; +} From a11a6544c0bf6c0871f2379ad0c5ad0210691e73 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 3 Aug 2007 13:52:19 +0200 Subject: [PATCH 1332/2804] support for USB autosuspend in the asix driver this implements support for USB autosuspend in the asix USB ethernet driver. Signed-off-by: Oliver Neukum Signed-off-by: Jeff Garzik --- drivers/net/usb/asix.c | 1 + drivers/net/usb/usbnet.c | 30 +++++++++++++++++++++++++----- drivers/net/usb/usbnet.h | 1 + 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 6d95cacd5284..61daa096de66 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -1474,6 +1474,7 @@ static struct usb_driver asix_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .disconnect = usbnet_disconnect, + .supports_autosuspend = 1, }; static int __init asix_init(void) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 37bf4f2c0a44..3034d1aea376 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -590,6 +590,7 @@ static int usbnet_stop (struct net_device *net) dev->flags = 0; del_timer_sync (&dev->delay); tasklet_kill (&dev->bh); + usb_autopm_put_interface(dev->intf); return 0; } @@ -603,9 +604,19 @@ static int usbnet_stop (struct net_device *net) static int usbnet_open (struct net_device *net) { struct usbnet *dev = netdev_priv(net); - int retval = 0; + int retval; struct driver_info *info = dev->driver_info; + if ((retval = usb_autopm_get_interface(dev->intf)) < 0) { + if (netif_msg_ifup (dev)) + devinfo (dev, + "resumption fail (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + goto done_nopm; + } + // put into "known safe" state if (info->reset && (retval = info->reset (dev)) < 0) { if (netif_msg_ifup (dev)) @@ -659,7 +670,10 @@ static int usbnet_open (struct net_device *net) // delay posting reads until we're fully open tasklet_schedule (&dev->bh); + return retval; done: + usb_autopm_put_interface(dev->intf); +done_nopm: return retval; } @@ -1143,6 +1157,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev = netdev_priv(net); dev->udev = xdev; + dev->intf = udev; dev->driver_info = info; dev->driver_name = name; dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV @@ -1267,12 +1282,18 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) struct usbnet *dev = usb_get_intfdata(intf); if (!dev->suspend_count++) { - /* accelerate emptying of the rx and queues, to avoid + /* + * accelerate emptying of the rx and queues, to avoid * having everything error out. */ netif_device_detach (dev->net); (void) unlink_urbs (dev, &dev->rxq); (void) unlink_urbs (dev, &dev->txq); + /* + * reattach so runtime management can use and + * wake the device + */ + netif_device_attach (dev->net); } return 0; } @@ -1282,10 +1303,9 @@ int usbnet_resume (struct usb_interface *intf) { struct usbnet *dev = usb_get_intfdata(intf); - if (!--dev->suspend_count) { - netif_device_attach (dev->net); + if (!--dev->suspend_count) tasklet_schedule (&dev->bh); - } + return 0; } EXPORT_SYMBOL_GPL(usbnet_resume); diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h index a6c5820767de..1fae4347e831 100644 --- a/drivers/net/usb/usbnet.h +++ b/drivers/net/usb/usbnet.h @@ -28,6 +28,7 @@ struct usbnet { /* housekeeping */ struct usb_device *udev; + struct usb_interface *intf; struct driver_info *driver_info; const char *driver_name; wait_queue_head_t *wait; From 917270c6ed7a99d4300ce57508246813ea8613b0 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Sun, 26 Aug 2007 21:22:32 -0700 Subject: [PATCH 1333/2804] pcnet32: add suspend and resume capability Add suspend and resume capability to the driver. Tested both to ram and to disk on x86_64 platform. Signed-off-by: Don Fry Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index a9973490dba9..db87429b956f 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -23,11 +23,11 @@ #define DRV_NAME "pcnet32" #ifdef CONFIG_PCNET32_NAPI -#define DRV_VERSION "1.33-NAPI" +#define DRV_VERSION "1.34-NAPI" #else -#define DRV_VERSION "1.33" +#define DRV_VERSION "1.34" #endif -#define DRV_RELDATE "27.Jun.2006" +#define DRV_RELDATE "14.Aug.2007" #define PFX DRV_NAME ": " static const char *const version = @@ -2955,6 +2955,33 @@ static void pcnet32_watchdog(struct net_device *dev) mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); } +static int pcnet32_pm_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (netif_running(dev)) { + netif_device_detach(dev); + pcnet32_close(dev); + } + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int pcnet32_pm_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (netif_running(dev)) { + pcnet32_open(dev); + netif_device_attach(dev); + } + return 0; +} + static void __devexit pcnet32_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -2978,6 +3005,8 @@ static struct pci_driver pcnet32_driver = { .probe = pcnet32_probe_pci, .remove = __devexit_p(pcnet32_remove_one), .id_table = pcnet32_pci_tbl, + .suspend = pcnet32_pm_suspend, + .resume = pcnet32_pm_resume, }; /* An additional parameter that may be passed in... */ From b6aec32a7774a398c4a194ad6b6392528b5a7a5b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 14 Aug 2007 20:09:02 +0200 Subject: [PATCH 1334/2804] uli526x: Add suspend and resume routines (updated) Add suspend/resume support to the uli526x network driver (tested on x86_64, with 'Ethernet controller: ALi Corporation M5263 Ethernet Controller, rev 40'). This patch is based on the suspend/resume code in the tg3 driver. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jeff Garzik --- drivers/net/tulip/uli526x.c | 108 ++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 6 deletions(-) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index ca2548eb7d63..e26ce44561c4 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -1110,19 +1110,15 @@ static void uli526x_timer(unsigned long data) /* - * Dynamic reset the ULI526X board * Stop ULI526X board * Free Tx/Rx allocated memory - * Reset ULI526X board - * Re-initialize ULI526X board + * Init system variable */ -static void uli526x_dynamic_reset(struct net_device *dev) +static void uli526x_reset_prepare(struct net_device *dev) { struct uli526x_board_info *db = netdev_priv(dev); - ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0); - /* Sopt MAC controller */ db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */ update_cr6(db->cr6_data, dev->base_addr); @@ -1141,6 +1137,22 @@ static void uli526x_dynamic_reset(struct net_device *dev) db->link_failed = 1; db->init=1; db->wait_reset = 0; +} + + +/* + * Dynamic reset the ULI526X board + * Stop ULI526X board + * Free Tx/Rx allocated memory + * Reset ULI526X board + * Re-initialize ULI526X board + */ + +static void uli526x_dynamic_reset(struct net_device *dev) +{ + ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0); + + uli526x_reset_prepare(dev); /* Re-initialize ULI526X board */ uli526x_init(dev); @@ -1150,6 +1162,88 @@ static void uli526x_dynamic_reset(struct net_device *dev) } +#ifdef CONFIG_PM + +/* + * Suspend the interface. + */ + +static int uli526x_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + pci_power_t power_state; + int err; + + ULI526X_DBUG(0, "uli526x_suspend", 0); + + if (!netdev_priv(dev)) + return 0; + + pci_save_state(pdev); + + if (!netif_running(dev)) + return 0; + + netif_device_detach(dev); + uli526x_reset_prepare(dev); + + power_state = pci_choose_state(pdev, state); + pci_enable_wake(pdev, power_state, 0); + err = pci_set_power_state(pdev, power_state); + if (err) { + netif_device_attach(dev); + /* Re-initialize ULI526X board */ + uli526x_init(dev); + /* Restart upper layer interface */ + netif_wake_queue(dev); + } + + return err; +} + +/* + * Resume the interface. + */ + +static int uli526x_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + int err; + + ULI526X_DBUG(0, "uli526x_resume", 0); + + if (!netdev_priv(dev)) + return 0; + + pci_restore_state(pdev); + + if (!netif_running(dev)) + return 0; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) { + printk(KERN_WARNING "%s: Could not put device into D0\n", + dev->name); + return err; + } + + netif_device_attach(dev); + /* Re-initialize ULI526X board */ + uli526x_init(dev); + /* Restart upper layer interface */ + netif_wake_queue(dev); + + return 0; +} + +#else /* !CONFIG_PM */ + +#define uli526x_suspend NULL +#define uli526x_resume NULL + +#endif /* !CONFIG_PM */ + + /* * free all allocated rx buffer */ @@ -1689,6 +1783,8 @@ static struct pci_driver uli526x_driver = { .id_table = uli526x_pci_tbl, .probe = uli526x_init_one, .remove = __devexit_p(uli526x_remove_one), + .suspend = uli526x_suspend, + .resume = uli526x_resume, }; MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw"); From df950828b0ee51ff63c49c67d561bfd3d6096788 Mon Sep 17 00:00:00 2001 From: Komuro Date: Mon, 13 Aug 2007 09:45:41 +0900 Subject: [PATCH 1335/2804] dl2k: add Sundance/Tamarack TC902x Gigabit Ethernet Adapter support Actually, D-Link modified the VendorID/ProductID of the TC902x. The TC902x is the original chipset. Signed-off-by: Komuro Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 7 ++++--- drivers/net/dl2k.c | 23 +++++++++++++++-------- drivers/net/dl2k.h | 1 + 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 502dd0eb8809..eeac2f49aae3 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1995,14 +1995,15 @@ config ACENIC_OMIT_TIGON_I The safe and default value for this is N. config DL2K - tristate "D-Link DL2000-based Gigabit Ethernet support" + tristate "DL2000/TC902x-based Gigabit Ethernet support" depends on PCI select CRC32 help - This driver supports D-Link 2000-based gigabit ethernet cards, which - includes + This driver supports DL2000/TC902x-based Gigabit ethernet cards, + which includes D-Link DGE-550T Gigabit Ethernet Adapter. D-Link DL2000-based Gigabit Ethernet Adapter. + Sundance/Tamarack TC902x Gigabit Ethernet Adapter. To compile this driver as a module, choose M here: the module will be called dl2k. diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 04e3710c9082..ca21a1888ffa 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -10,9 +10,9 @@ (at your option) any later version. */ -#define DRV_NAME "D-Link DL2000-based linux driver" -#define DRV_VERSION "v1.18" -#define DRV_RELDATE "2006/06/27" +#define DRV_NAME "DL2000/TC902x-based linux driver" +#define DRV_VERSION "v1.19" +#define DRV_RELDATE "2007/08/12" #include "dl2k.h" #include @@ -339,17 +339,24 @@ parse_eeprom (struct net_device *dev) #ifdef MEM_MAPPING ioaddr = dev->base_addr; #endif - /* Check CRC */ - crc = ~ether_crc_le (256 - 4, sromdata); - if (psrom->crc != crc) { - printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name); - return -1; + if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) { /* D-Link Only */ + /* Check CRC */ + crc = ~ether_crc_le (256 - 4, sromdata); + if (psrom->crc != crc) { + printk (KERN_ERR "%s: EEPROM data CRC error.\n", + dev->name); + return -1; + } } /* Set MAC address */ for (i = 0; i < 6; i++) dev->dev_addr[i] = psrom->mac_addr[i]; + if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) { + return 0; + } + /* Parse Software Information Block */ i = 0x30; psib = (u8 *) sromdata; diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index e443065a452e..5b801775f42d 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -692,6 +692,7 @@ struct netdev_private { static const struct pci_device_id rio_pci_tbl[] = { {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, }, + {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, }, { } }; MODULE_DEVICE_TABLE (pci, rio_pci_tbl); From f4ff28720f45354573dcf4e0eb5a2dc5452cb3e1 Mon Sep 17 00:00:00 2001 From: Brian King Date: Sat, 15 Sep 2007 13:36:07 -0700 Subject: [PATCH 1336/2804] ibmveth: Enable TCP checksum offload This patchset enables TCP checksum offload support for IPV4 on ibmveth. This completely eliminates the generation and checking of the checksum for packets that are completely virtual and never touch a physical network. A simple TCP_STREAM netperf run on a virtual network with maximum mtu set yielded a ~30% increase in throughput. This feature is enabled by default on systems that support it, but can be disabled with a module option. Signed-off-by: Brian King Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/ibmveth.c | 53 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/ibmveth.h | 41 +++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0c35d72f5f8d..9353890dcda0 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -132,6 +134,11 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length); } +static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter) +{ + return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].csum_good); +} + /* setup the initial settings for a buffer pool */ static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active) { @@ -695,6 +702,24 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) desc[0].fields.length, DMA_TO_DEVICE); desc[0].fields.valid = 1; + if (skb->ip_summed == CHECKSUM_PARTIAL && + ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { + ibmveth_error_printk("tx: failed to checksum packet\n"); + tx_dropped++; + goto out; + } + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; + + desc[0].fields.no_csum = 1; + desc[0].fields.csum_good = 1; + + /* Need to zero out the checksum */ + buf[0] = 0; + buf[1] = 0; + } + if(dma_mapping_error(desc[0].fields.address)) { ibmveth_error_printk("tx: unable to map initial fragment\n"); tx_map_failed++; @@ -713,6 +738,10 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) frag->size, DMA_TO_DEVICE); desc[curfrag+1].fields.length = frag->size; desc[curfrag+1].fields.valid = 1; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + desc[curfrag+1].fields.no_csum = 1; + desc[curfrag+1].fields.csum_good = 1; + } if(dma_mapping_error(desc[curfrag+1].fields.address)) { ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); @@ -801,7 +830,11 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) } else { int length = ibmveth_rxq_frame_length(adapter); int offset = ibmveth_rxq_frame_offset(adapter); + int csum_good = ibmveth_rxq_csum_good(adapter); + skb = ibmveth_rxq_get_buffer(adapter); + if (csum_good) + skb->ip_summed = CHECKSUM_UNNECESSARY; ibmveth_rxq_harvest_buffer(adapter); @@ -962,8 +995,10 @@ static void ibmveth_poll_controller(struct net_device *dev) static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { int rc, i; + long ret; struct net_device *netdev; struct ibmveth_adapter *adapter; + union ibmveth_illan_attributes set_attr, ret_attr; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; @@ -1057,6 +1092,24 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ibmveth_debug_printk("registering netdev...\n"); + ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr.desc); + + if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && + !ret_attr.fields.trunk_priority && + ret_attr.fields.csum_offload_padded_pkt_support) { + set_attr.desc = 0; + set_attr.fields.tcp_csum_offload_ipv4 = 1; + + ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, + &ret_attr.desc); + + if (ret == H_SUCCESS) + netdev->features |= NETIF_F_IP_CSUM; + else + ret = h_illan_attributes(dev->unit_address, set_attr.desc, + 0, &ret_attr.desc); + } + rc = register_netdev(netdev); if(rc) { diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index e05694126f85..3f10f0f4447a 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -67,6 +67,21 @@ static inline long h_send_logical_lan(unsigned long unit_address, return rc; } +static inline long h_illan_attributes(unsigned long unit_address, + unsigned long reset_mask, unsigned long set_mask, + unsigned long *ret_attributes) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address, + reset_mask, set_mask); + + *ret_attributes = retbuf[0]; + + return rc; +} + #define h_multicast_ctrl(ua, cmd, mac) \ plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac) @@ -142,7 +157,9 @@ struct ibmveth_adapter { struct ibmveth_buf_desc_fields { u32 valid : 1; u32 toggle : 1; - u32 reserved : 6; + u32 reserved : 4; + u32 no_csum : 1; + u32 csum_good : 1; u32 length : 24; u32 address; }; @@ -152,10 +169,30 @@ union ibmveth_buf_desc { struct ibmveth_buf_desc_fields fields; }; +struct ibmveth_illan_attributes_fields { + u32 reserved; + u32 reserved2 : 18; + u32 csum_offload_padded_pkt_support : 1; + u32 reserved3 : 1; + u32 trunk_priority : 4; + u32 reserved4 : 5; + u32 tcp_csum_offload_ipv6 : 1; + u32 tcp_csum_offload_ipv4 : 1; + u32 active_trunk : 1; +}; + +union ibmveth_illan_attributes { + u64 desc; + struct ibmveth_illan_attributes_fields fields; +}; + struct ibmveth_rx_q_entry { u16 toggle : 1; u16 valid : 1; - u16 reserved : 14; + u16 reserved : 4; + u16 no_csum : 1; + u16 csum_good : 1; + u16 reserved2 : 8; u16 offset; u32 length; u64 correlator; From 5fc7e01cb77132f96e171a37f9f792270b1603f6 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:31 -0500 Subject: [PATCH 1337/2804] ibmveth: Implement ethtool hooks to enable/disable checksum offload This patch adds the appropriate ethtool hooks to allow for enabling/disabling of hypervisor assisted checksum offload for TCP. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 125 +++++++++++++++++++++++++++++++++++++++++- drivers/net/ibmveth.h | 1 + 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 9353890dcda0..9c16928e20ed 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -652,12 +652,132 @@ static u32 netdev_get_link(struct net_device *dev) { return 1; } +static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = dev->priv; + + if (data) + adapter->rx_csum = 1; + else { + /* + * Since the ibmveth firmware interface does not have the concept of + * separate tx/rx checksum offload enable, if rx checksum is disabled + * we also have to disable tx checksum offload. Once we disable rx + * checksum offload, we are no longer allowed to send tx buffers that + * are not properly checksummed. + */ + adapter->rx_csum = 0; + dev->features &= ~NETIF_F_IP_CSUM; + } +} + +static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = dev->priv; + + if (data) { + dev->features |= NETIF_F_IP_CSUM; + adapter->rx_csum = 1; + } else + dev->features &= ~NETIF_F_IP_CSUM; +} + +static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, + void (*done) (struct net_device *, u32)) +{ + struct ibmveth_adapter *adapter = dev->priv; + union ibmveth_illan_attributes set_attr, clr_attr, ret_attr; + long ret; + int rc1 = 0, rc2 = 0; + int restart = 0; + + if (netif_running(dev)) { + restart = 1; + adapter->pool_config = 1; + ibmveth_close(dev); + adapter->pool_config = 0; + } + + set_attr.desc = 0; + clr_attr.desc = 0; + + if (data) + set_attr.fields.tcp_csum_offload_ipv4 = 1; + else + clr_attr.fields.tcp_csum_offload_ipv4 = 1; + + ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr.desc); + + if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && + !ret_attr.fields.trunk_priority && + ret_attr.fields.csum_offload_padded_pkt_support) { + ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr.desc, + set_attr.desc, &ret_attr.desc); + + if (ret != H_SUCCESS) { + rc1 = -EIO; + ibmveth_error_printk("unable to change checksum offload settings." + " %d rc=%ld\n", data, ret); + + ret = h_illan_attributes(adapter->vdev->unit_address, + set_attr.desc, clr_attr.desc, &ret_attr.desc); + } else + done(dev, data); + } else { + rc1 = -EIO; + ibmveth_error_printk("unable to change checksum offload settings." + " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr.desc); + } + + if (restart) + rc2 = ibmveth_open(dev); + + return rc1 ? rc1 : rc2; +} + +static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = dev->priv; + + if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum)) + return 0; + + return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags); +} + +static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = dev->priv; + int rc = 0; + + if (data && (dev->features & NETIF_F_IP_CSUM)) + return 0; + if (!data && !(dev->features & NETIF_F_IP_CSUM)) + return 0; + + if (data && !adapter->rx_csum) + rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags); + else + ibmveth_set_tx_csum_flags(dev, data); + + return rc; +} + +static u32 ibmveth_get_rx_csum(struct net_device *dev) +{ + struct ibmveth_adapter *adapter = dev->priv; + return adapter->rx_csum; +} + static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .get_link = netdev_get_link, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ibmveth_set_tx_csum, + .get_rx_csum = ibmveth_get_rx_csum, + .set_rx_csum = ibmveth_set_rx_csum, }; static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1103,9 +1223,10 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, &ret_attr.desc); - if (ret == H_SUCCESS) + if (ret == H_SUCCESS) { + adapter->rx_csum = 1; netdev->features |= NETIF_F_IP_CSUM; - else + } else ret = h_illan_attributes(dev->unit_address, set_attr.desc, 0, &ret_attr.desc); } diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 3f10f0f4447a..43b068d9a558 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -138,6 +138,7 @@ struct ibmveth_adapter { struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; struct ibmveth_rx_q rx_queue; int pool_config; + int rx_csum; /* adapter specific stats */ u64 replenish_task_cycles; From 80e536770c2fcb8d2b7be9f5a36b85c36fd5943a Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:37 -0500 Subject: [PATCH 1338/2804] ibmveth: Add ethtool TSO handlers Add handlers for get_tso and get_ufo to prevent errors being printed by ethtool. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 9c16928e20ed..9bf0f92d3a50 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -778,6 +778,8 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_tx_csum = ibmveth_set_tx_csum, .get_rx_csum = ibmveth_get_rx_csum, .set_rx_csum = ibmveth_set_rx_csum, + .get_tso = ethtool_op_get_tso, + .get_ufo = ethtool_op_get_ufo, }; static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) From ddbb4de9672097da2c0f19c6ebca0ebb5672e9b8 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:43 -0500 Subject: [PATCH 1339/2804] ibmveth: Add ethtool driver stats hooks Add ethtool hooks to ibmveth to retrieve driver statistics. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 9bf0f92d3a50..40cb00e37df6 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -113,6 +113,28 @@ MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(ibmveth_driver_version); +struct ibmveth_stat { + char name[ETH_GSTRING_LEN]; + int offset; +}; + +#define IBMVETH_STAT_OFF(stat) offsetof(struct ibmveth_adapter, stat) +#define IBMVETH_GET_STAT(a, off) *((u64 *)(((unsigned long)(a)) + off)) + +struct ibmveth_stat ibmveth_stats[] = { + { "replenish_task_cycles", IBMVETH_STAT_OFF(replenish_task_cycles) }, + { "replenish_no_mem", IBMVETH_STAT_OFF(replenish_no_mem) }, + { "replenish_add_buff_failure", IBMVETH_STAT_OFF(replenish_add_buff_failure) }, + { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) }, + { "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) }, + { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) }, + { "tx_multidesc_send", IBMVETH_STAT_OFF(tx_multidesc_send) }, + { "tx_linearized", IBMVETH_STAT_OFF(tx_linearized) }, + { "tx_linearize_failed", IBMVETH_STAT_OFF(tx_linearize_failed) }, + { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) }, + { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }, +}; + /* simple methods of getting data from the current rxq entry */ static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter) { @@ -769,6 +791,32 @@ static u32 ibmveth_get_rx_csum(struct net_device *dev) return adapter->rx_csum; } +static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + int i; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++, data += ETH_GSTRING_LEN) + memcpy(data, ibmveth_stats[i].name, ETH_GSTRING_LEN); +} + +static int ibmveth_get_stats_count(struct net_device *dev) +{ + return ARRAY_SIZE(ibmveth_stats); +} + +static void ibmveth_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + int i; + struct ibmveth_adapter *adapter = dev->priv; + + for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++) + data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset); +} + static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, @@ -780,6 +828,9 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_rx_csum = ibmveth_set_rx_csum, .get_tso = ethtool_op_get_tso, .get_ufo = ethtool_op_get_ufo, + .get_strings = ibmveth_get_strings, + .get_stats_count = ibmveth_get_stats_count, + .get_ethtool_stats = ibmveth_get_ethtool_stats, }; static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) From 3449a2ab31681420515e242920e755262b4f41e9 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:49 -0500 Subject: [PATCH 1340/2804] ibmveth: Remove dead frag processing code Removes dead frag processing code from ibmveth. Since NETIF_F_SG was not set, this code was never executed. Also, since the ibmveth interface can only handle 6 fragments, core networking code would need to be modified in order to efficiently enable this support. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 100 +++++++----------------------------------- drivers/net/ibmveth.h | 5 --- 2 files changed, 17 insertions(+), 88 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 40cb00e37df6..f6be7b29c845 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -28,7 +28,6 @@ /**************************************************************************/ /* TODO: - - remove frag processing code - no longer needed - add support for sysfs - possibly remove procfs support */ @@ -128,9 +127,6 @@ struct ibmveth_stat ibmveth_stats[] = { { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) }, { "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) }, { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) }, - { "tx_multidesc_send", IBMVETH_STAT_OFF(tx_multidesc_send) }, - { "tx_linearized", IBMVETH_STAT_OFF(tx_linearized) }, - { "tx_linearize_failed", IBMVETH_STAT_OFF(tx_linearize_failed) }, { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) }, { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }, }; @@ -843,9 +839,8 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; - union ibmveth_buf_desc desc[IbmVethMaxSendFrags]; + union ibmveth_buf_desc desc; unsigned long lpar_rc; - int nfrags = 0, curfrag; unsigned long correlator; unsigned long flags; unsigned int retry_count; @@ -855,25 +850,11 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int tx_send_failed = 0; unsigned int tx_map_failed = 0; - - if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) { - tx_dropped++; - goto out; - } - - memset(&desc, 0, sizeof(desc)); - - /* nfrags = number of frags after the initial fragment */ - nfrags = skb_shinfo(skb)->nr_frags; - - if(nfrags) - adapter->tx_multidesc_send++; - - /* map the initial fragment */ - desc[0].fields.length = nfrags ? skb->len - skb->data_len : skb->len; - desc[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data, - desc[0].fields.length, DMA_TO_DEVICE); - desc[0].fields.valid = 1; + desc.desc = 0; + desc.fields.length = skb->len; + desc.fields.address = dma_map_single(&adapter->vdev->dev, skb->data, + desc.fields.length, DMA_TO_DEVICE); + desc.fields.valid = 1; if (skb->ip_summed == CHECKSUM_PARTIAL && ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { @@ -885,75 +866,34 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (skb->ip_summed == CHECKSUM_PARTIAL) { unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; - desc[0].fields.no_csum = 1; - desc[0].fields.csum_good = 1; + desc.fields.no_csum = 1; + desc.fields.csum_good = 1; /* Need to zero out the checksum */ buf[0] = 0; buf[1] = 0; } - if(dma_mapping_error(desc[0].fields.address)) { - ibmveth_error_printk("tx: unable to map initial fragment\n"); + if (dma_mapping_error(desc.fields.address)) { + ibmveth_error_printk("tx: unable to map xmit buffer\n"); tx_map_failed++; tx_dropped++; goto out; } - curfrag = nfrags; - - /* map fragments past the initial portion if there are any */ - while(curfrag--) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[curfrag]; - desc[curfrag+1].fields.address - = dma_map_single(&adapter->vdev->dev, - page_address(frag->page) + frag->page_offset, - frag->size, DMA_TO_DEVICE); - desc[curfrag+1].fields.length = frag->size; - desc[curfrag+1].fields.valid = 1; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - desc[curfrag+1].fields.no_csum = 1; - desc[curfrag+1].fields.csum_good = 1; - } - - if(dma_mapping_error(desc[curfrag+1].fields.address)) { - ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); - tx_map_failed++; - tx_dropped++; - /* Free all the mappings we just created */ - while(curfrag < nfrags) { - dma_unmap_single(&adapter->vdev->dev, - desc[curfrag+1].fields.address, - desc[curfrag+1].fields.length, - DMA_TO_DEVICE); - curfrag++; - } - goto out; - } - } - /* send the frame. Arbitrarily set retrycount to 1024 */ correlator = 0; retry_count = 1024; do { lpar_rc = h_send_logical_lan(adapter->vdev->unit_address, - desc[0].desc, - desc[1].desc, - desc[2].desc, - desc[3].desc, - desc[4].desc, - desc[5].desc, - correlator, - &correlator); + desc.desc, 0, 0, 0, 0, 0, + correlator, &correlator); } while ((lpar_rc == H_BUSY) && (retry_count--)); if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) { - int i; ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc); - for(i = 0; i < 6; i++) { - ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i, - desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address); - } + ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n", + desc.fields.valid, desc.fields.length, desc.fields.address); tx_send_failed++; tx_dropped++; } else { @@ -962,11 +902,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; } - do { - dma_unmap_single(&adapter->vdev->dev, - desc[nfrags].fields.address, - desc[nfrags].fields.length, DMA_TO_DEVICE); - } while(--nfrags >= 0); + dma_unmap_single(&adapter->vdev->dev, desc.fields.address, + desc.fields.length, DMA_TO_DEVICE); out: spin_lock_irqsave(&adapter->stats_lock, flags); adapter->stats.tx_dropped += tx_dropped; @@ -1366,10 +1303,7 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v) firmware_mac[3], firmware_mac[4], firmware_mac[5]); seq_printf(seq, "\nAdapter Statistics:\n"); - seq_printf(seq, " TX: skbuffs linearized: %ld\n", adapter->tx_linearized); - seq_printf(seq, " multi-descriptor sends: %ld\n", adapter->tx_multidesc_send); - seq_printf(seq, " skb_linearize failures: %ld\n", adapter->tx_linearize_failed); - seq_printf(seq, " vio_map_single failres: %ld\n", adapter->tx_map_failed); + seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed); seq_printf(seq, " send failures: %ld\n", adapter->tx_send_failed); seq_printf(seq, " RX: replenish task cycles: %ld\n", adapter->replenish_task_cycles); seq_printf(seq, " alloc_skb_failures: %ld\n", adapter->replenish_no_mem); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 43b068d9a558..30f9fc67b0c8 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -25,8 +25,6 @@ #ifndef _IBMVETH_H #define _IBMVETH_H -#define IbmVethMaxSendFrags 6 - /* constants for H_MULTICAST_CTRL */ #define IbmVethMcastReceptionModifyBit 0x80000UL #define IbmVethMcastReceptionEnableBit 0x20000UL @@ -147,9 +145,6 @@ struct ibmveth_adapter { u64 replenish_add_buff_success; u64 rx_invalid_buffer; u64 rx_no_buffer; - u64 tx_multidesc_send; - u64 tx_linearized; - u64 tx_linearize_failed; u64 tx_map_failed; u64 tx_send_failed; spinlock_t stats_lock; From 79ef4a4dd44cd4f9942975b0f625bd01549a2aa9 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:56 -0500 Subject: [PATCH 1341/2804] ibmveth: Remove use of bitfields Removes the use of bitfields from the ibmveth driver. This results in slightly smaller object code. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 90 +++++++++++++++++++++---------------------- drivers/net/ibmveth.h | 56 +++++++++++---------------- 2 files changed, 68 insertions(+), 78 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index f6be7b29c845..2dff9f2800cd 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -132,19 +132,29 @@ struct ibmveth_stat ibmveth_stats[] = { }; /* simple methods of getting data from the current rxq entry */ +static inline u32 ibmveth_rxq_flags(struct ibmveth_adapter *adapter) +{ + return adapter->rx_queue.queue_addr[adapter->rx_queue.index].flags_off; +} + +static inline int ibmveth_rxq_toggle(struct ibmveth_adapter *adapter) +{ + return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >> IBMVETH_RXQ_TOGGLE_SHIFT; +} + static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter) { - return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].toggle == adapter->rx_queue.toggle); + return (ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle); } static inline int ibmveth_rxq_buffer_valid(struct ibmveth_adapter *adapter) { - return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].valid); + return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID); } static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter) { - return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].offset); + return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK); } static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) @@ -154,7 +164,7 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter) { - return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].csum_good); + return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD); } /* setup the initial settings for a buffer pool */ @@ -254,9 +264,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc correlator = ((u64)pool->index << 32) | index; *(u64*)skb->data = correlator; - desc.desc = 0; - desc.fields.valid = 1; - desc.fields.length = pool->buff_size; + desc.fields.flags_len = IBMVETH_BUF_VALID | pool->buff_size; desc.fields.address = dma_addr; lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); @@ -397,9 +405,8 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) return; } - desc.desc = 0; - desc.fields.valid = 1; - desc.fields.length = adapter->rx_buff_pool[pool].buff_size; + desc.fields.flags_len = IBMVETH_BUF_VALID | + adapter->rx_buff_pool[pool].buff_size; desc.fields.address = adapter->rx_buff_pool[pool].dma_addr[index]; lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); @@ -555,9 +562,7 @@ static int ibmveth_open(struct net_device *netdev) memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); mac_address = mac_address >> 16; - rxq_desc.desc = 0; - rxq_desc.fields.valid = 1; - rxq_desc.fields.length = adapter->rx_queue.queue_len; + rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len; rxq_desc.fields.address = adapter->rx_queue.queue_dma; ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr); @@ -704,7 +709,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, void (*done) (struct net_device *, u32)) { struct ibmveth_adapter *adapter = dev->priv; - union ibmveth_illan_attributes set_attr, clr_attr, ret_attr; + u64 set_attr, clr_attr, ret_attr; long ret; int rc1 = 0, rc2 = 0; int restart = 0; @@ -716,21 +721,21 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, adapter->pool_config = 0; } - set_attr.desc = 0; - clr_attr.desc = 0; + set_attr = 0; + clr_attr = 0; if (data) - set_attr.fields.tcp_csum_offload_ipv4 = 1; + set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; else - clr_attr.fields.tcp_csum_offload_ipv4 = 1; + clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; - ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr.desc); + ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); - if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && - !ret_attr.fields.trunk_priority && - ret_attr.fields.csum_offload_padded_pkt_support) { - ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr.desc, - set_attr.desc, &ret_attr.desc); + if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) && + !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) && + (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) { + ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr, + set_attr, &ret_attr); if (ret != H_SUCCESS) { rc1 = -EIO; @@ -738,13 +743,13 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, " %d rc=%ld\n", data, ret); ret = h_illan_attributes(adapter->vdev->unit_address, - set_attr.desc, clr_attr.desc, &ret_attr.desc); + set_attr, clr_attr, &ret_attr); } else done(dev, data); } else { rc1 = -EIO; ibmveth_error_printk("unable to change checksum offload settings." - " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr.desc); + " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr); } if (restart) @@ -850,11 +855,9 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int tx_send_failed = 0; unsigned int tx_map_failed = 0; - desc.desc = 0; - desc.fields.length = skb->len; + desc.fields.flags_len = IBMVETH_BUF_VALID | skb->len; desc.fields.address = dma_map_single(&adapter->vdev->dev, skb->data, - desc.fields.length, DMA_TO_DEVICE); - desc.fields.valid = 1; + skb->len, DMA_TO_DEVICE); if (skb->ip_summed == CHECKSUM_PARTIAL && ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { @@ -866,8 +869,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (skb->ip_summed == CHECKSUM_PARTIAL) { unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; - desc.fields.no_csum = 1; - desc.fields.csum_good = 1; + desc.fields.flags_len |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD); /* Need to zero out the checksum */ buf[0] = 0; @@ -893,7 +895,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) { ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc); ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n", - desc.fields.valid, desc.fields.length, desc.fields.address); + (desc.fields.flags_len & IBMVETH_BUF_VALID) ? 1 : 0, + skb->len, desc.fields.address); tx_send_failed++; tx_dropped++; } else { @@ -903,7 +906,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) } dma_unmap_single(&adapter->vdev->dev, desc.fields.address, - desc.fields.length, DMA_TO_DEVICE); + skb->len, DMA_TO_DEVICE); out: spin_lock_irqsave(&adapter->stats_lock, flags); adapter->stats.tx_dropped += tx_dropped; @@ -1108,7 +1111,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ long ret; struct net_device *netdev; struct ibmveth_adapter *adapter; - union ibmveth_illan_attributes set_attr, ret_attr; + u64 set_attr, ret_attr; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; @@ -1202,23 +1205,20 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ibmveth_debug_printk("registering netdev...\n"); - ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr.desc); + ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr); - if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && - !ret_attr.fields.trunk_priority && - ret_attr.fields.csum_offload_padded_pkt_support) { - set_attr.desc = 0; - set_attr.fields.tcp_csum_offload_ipv4 = 1; + if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) && + !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) && + (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) { + set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; - ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, - &ret_attr.desc); + ret = h_illan_attributes(dev->unit_address, 0, set_attr, &ret_attr); if (ret == H_SUCCESS) { adapter->rx_csum = 1; netdev->features |= NETIF_F_IP_CSUM; } else - ret = h_illan_attributes(dev->unit_address, set_attr.desc, - 0, &ret_attr.desc); + ret = h_illan_attributes(dev->unit_address, set_attr, 0, &ret_attr); } rc = register_netdev(netdev); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 30f9fc67b0c8..41f61cd18852 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -39,6 +39,12 @@ #define IbmVethMcastRemoveFilter 0x2UL #define IbmVethMcastClearFilterTable 0x3UL +#define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000ULL +#define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00ULL +#define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004ULL +#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002ULL +#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001ULL + /* hcall macros */ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac) @@ -151,13 +157,13 @@ struct ibmveth_adapter { }; struct ibmveth_buf_desc_fields { - u32 valid : 1; - u32 toggle : 1; - u32 reserved : 4; - u32 no_csum : 1; - u32 csum_good : 1; - u32 length : 24; - u32 address; + u32 flags_len; +#define IBMVETH_BUF_VALID 0x80000000 +#define IBMVETH_BUF_TOGGLE 0x40000000 +#define IBMVETH_BUF_NO_CSUM 0x02000000 +#define IBMVETH_BUF_CSUM_GOOD 0x01000000 +#define IBMVETH_BUF_LEN_MASK 0x00FFFFFF + u32 address; }; union ibmveth_buf_desc { @@ -165,33 +171,17 @@ union ibmveth_buf_desc { struct ibmveth_buf_desc_fields fields; }; -struct ibmveth_illan_attributes_fields { - u32 reserved; - u32 reserved2 : 18; - u32 csum_offload_padded_pkt_support : 1; - u32 reserved3 : 1; - u32 trunk_priority : 4; - u32 reserved4 : 5; - u32 tcp_csum_offload_ipv6 : 1; - u32 tcp_csum_offload_ipv4 : 1; - u32 active_trunk : 1; -}; - -union ibmveth_illan_attributes { - u64 desc; - struct ibmveth_illan_attributes_fields fields; -}; - struct ibmveth_rx_q_entry { - u16 toggle : 1; - u16 valid : 1; - u16 reserved : 4; - u16 no_csum : 1; - u16 csum_good : 1; - u16 reserved2 : 8; - u16 offset; - u32 length; - u64 correlator; + u32 flags_off; +#define IBMVETH_RXQ_TOGGLE 0x80000000 +#define IBMVETH_RXQ_TOGGLE_SHIFT 31 +#define IBMVETH_RXQ_VALID 0x40000000 +#define IBMVETH_RXQ_NO_CSUM 0x02000000 +#define IBMVETH_RXQ_CSUM_GOOD 0x01000000 +#define IBMVETH_RXQ_OFF_MASK 0x0000FFFF + + u32 length; + u64 correlator; }; #endif /* _IBMVETH_H */ From c8303d10daeacb5dd7714d99f03e15cc6b91a71e Mon Sep 17 00:00:00 2001 From: Mark Hindley Date: Thu, 16 Aug 2007 11:28:40 +0100 Subject: [PATCH 1342/2804] 3c59x: check return of pci_enable_device() Check return of pci_enable_device in vortex_up(). Also modify vortex_up to return error to callers. Handle failure of vortex_up in vortex_open and vortex_resume. Signed-off-by: Mark Hindley Signed-off-by: Jeff Garzik --- drivers/net/3c59x.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index a8c0f436cdd2..29e558913eb5 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -705,7 +705,7 @@ static struct { static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, int chip_idx, int card_idx); -static void vortex_up(struct net_device *dev); +static int vortex_up(struct net_device *dev); static void vortex_down(struct net_device *dev, int final); static int vortex_open(struct net_device *dev); static void mdio_sync(void __iomem *ioaddr, int bits); @@ -841,8 +841,11 @@ static int vortex_resume(struct pci_dev *pdev) return -EBUSY; } if (netif_running(dev)) { - vortex_up(dev); - netif_device_attach(dev); + err = vortex_up(dev); + if (err) + return err; + else + netif_device_attach(dev); } } return 0; @@ -1484,19 +1487,24 @@ static void vortex_check_media(struct net_device *dev, unsigned int init) } } -static void +static int vortex_up(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; unsigned int config; - int i, mii_reg1, mii_reg5; + int i, mii_reg1, mii_reg5, err; if (VORTEX_PCI(vp)) { pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */ if (vp->pm_state_valid) pci_restore_state(VORTEX_PCI(vp)); - pci_enable_device(VORTEX_PCI(vp)); + err = pci_enable_device(VORTEX_PCI(vp)); + if (err) { + printk(KERN_WARNING "%s: Could not enable device \n", + dev->name); + goto err_out; + } } /* Before initializing select the active media port. */ @@ -1661,6 +1669,8 @@ vortex_up(struct net_device *dev) if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ iowrite32(0x8000, vp->cb_fn_base + 4); netif_start_queue (dev); +err_out: + return err; } static int @@ -1674,7 +1684,7 @@ vortex_open(struct net_device *dev) if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) { printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); - goto out; + goto err; } if (vp->full_bus_master_rx) { /* Boomerang bus master. */ @@ -1703,20 +1713,22 @@ vortex_open(struct net_device *dev) } } retval = -ENOMEM; - goto out_free_irq; + goto err_free_irq; } /* Wrap the ring. */ vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); } - vortex_up(dev); - return 0; + retval = vortex_up(dev); + if (!retval) + goto out; -out_free_irq: +err_free_irq: free_irq(dev->irq, dev); -out: +err: if (vortex_debug > 1) printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval); +out: return retval; } From 52b810d3055f0a49472d05500c6fea5aeabd01a6 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:05 -0700 Subject: [PATCH 1343/2804] cxgb3 - Update rx coalescing length Reduce Rx coalescing length to 12288 Large bursts from the adapter to the host create back pressure on the chip. Reducing the burst size avoids the issue. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 1746003eb46a..d6c77607a114 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -104,7 +104,7 @@ enum { PROTO_SRAM_LINES = 128, /* size of TP sram */ }; -#define MAX_RX_COALESCING_LEN 16224U +#define MAX_RX_COALESCING_LEN 12288U enum { PAUSE_RX = 1 << 0, From 6e3f03b72c1e11e19ea233a411a782f7231ba13f Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:10 -0700 Subject: [PATCH 1344/2804] cxgb3 - SGE doorbell overflow warning Log doorbell Fifo overflow Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/regs.h | 8 ++++++++ drivers/net/cxgb3/sge.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index aa80313c922e..282427877ea9 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -172,6 +172,14 @@ #define A_SG_INT_CAUSE 0x5c +#define S_HIPIODRBDROPERR 11 +#define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR) +#define F_HIPIODRBDROPERR V_HIPIODRBDROPERR(1U) + +#define S_LOPIODRBDROPERR 10 +#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR) +#define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U) + #define S_RSPQDISABLED 3 #define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) #define F_RSPQDISABLED V_RSPQDISABLED(1U) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 069c1aca8a6b..9233bbba9e91 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -2458,6 +2458,10 @@ void t3_sge_err_intr_handler(struct adapter *adapter) "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff); } + if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) + CH_ALERT(adapter, "SGE dropped %s priority doorbell\n", + status & F_HIPIODRBDROPERR ? "high" : "lo"); + t3_write_reg(adapter, A_SG_INT_CAUSE, status); if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED)) t3_fatal_err(adapter); From 27186dc325c3bbb937a27a2467cefd64e2505158 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:15 -0700 Subject: [PATCH 1345/2804] cxgb3 - use immediate data for offload Tx Send small TX_DATA work requests as immediate data even when there are fragments. this avoids doing multiple DMAs for small fragmented packets. The driver already implements this optimization for small contiguous packets. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/sge.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 9233bbba9e91..540ce5fa1d32 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1179,8 +1179,8 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) * * Writes a packet as immediate data into a Tx descriptor. The packet * contains a work request at its beginning. We must write the packet - * carefully so the SGE doesn't read accidentally before it's written in - * its entirety. + * carefully so the SGE doesn't read it accidentally before it's written + * in its entirety. */ static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, unsigned int len, unsigned int gen) @@ -1188,7 +1188,11 @@ static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, struct work_request_hdr *from = (struct work_request_hdr *)skb->data; struct work_request_hdr *to = (struct work_request_hdr *)d; - memcpy(&to[1], &from[1], len - sizeof(*from)); + if (likely(!skb->data_len)) + memcpy(&to[1], &from[1], len - sizeof(*from)); + else + skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from)); + to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | V_WR_BCNTLFLT(len & 7)); wmb(); @@ -1258,7 +1262,7 @@ static inline void reclaim_completed_tx_imm(struct sge_txq *q) static inline int immediate(const struct sk_buff *skb) { - return skb->len <= WR_LEN && !skb->data_len; + return skb->len <= WR_LEN; } /** @@ -1464,12 +1468,13 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, */ static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) { - unsigned int flits, cnt = skb_shinfo(skb)->nr_frags; + unsigned int flits, cnt; - if (skb->len <= WR_LEN && cnt == 0) + if (skb->len <= WR_LEN) return 1; /* packet fits as immediate data */ flits = skb_transport_offset(skb) / 8; /* headers */ + cnt = skb_shinfo(skb)->nr_frags; if (skb->tail != skb->transport_header) cnt++; return flits_to_desc(flits + sgl_len(cnt)); From e22bb45d772b5e5c850a6223c2a3245f520de641 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:21 -0700 Subject: [PATCH 1346/2804] cxgb3 - Expose HW memory page info A HW issue requires limiting the receive window size to 23 pages of internal memory. These pages can be configured to different sizes, thus the RDMA driver needs to know the page size to enforce the upper limit. Also assign explicit enum values. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_ctl_defs.h | 48 ++++++++++++++++++------------ drivers/net/cxgb3/cxgb3_offload.c | 7 +++++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h index 2095ddacff78..6c4f32066919 100644 --- a/drivers/net/cxgb3/cxgb3_ctl_defs.h +++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h @@ -33,27 +33,29 @@ #define _CXGB3_OFFLOAD_CTL_DEFS_H enum { - GET_MAX_OUTSTANDING_WR, - GET_TX_MAX_CHUNK, - GET_TID_RANGE, - GET_STID_RANGE, - GET_RTBL_RANGE, - GET_L2T_CAPACITY, - GET_MTUS, - GET_WR_LEN, - GET_IFF_FROM_MAC, - GET_DDP_PARAMS, - GET_PORTS, + GET_MAX_OUTSTANDING_WR = 0, + GET_TX_MAX_CHUNK = 1, + GET_TID_RANGE = 2, + GET_STID_RANGE = 3, + GET_RTBL_RANGE = 4, + GET_L2T_CAPACITY = 5, + GET_MTUS = 6, + GET_WR_LEN = 7, + GET_IFF_FROM_MAC = 8, + GET_DDP_PARAMS = 9, + GET_PORTS = 10, - ULP_ISCSI_GET_PARAMS, - ULP_ISCSI_SET_PARAMS, + ULP_ISCSI_GET_PARAMS = 11, + ULP_ISCSI_SET_PARAMS = 12, - RDMA_GET_PARAMS, - RDMA_CQ_OP, - RDMA_CQ_SETUP, - RDMA_CQ_DISABLE, - RDMA_CTRL_QP_SETUP, - RDMA_GET_MEM, + RDMA_GET_PARAMS = 13, + RDMA_CQ_OP = 14, + RDMA_CQ_SETUP = 15, + RDMA_CQ_DISABLE = 16, + RDMA_CTRL_QP_SETUP = 17, + RDMA_GET_MEM = 18, + + GET_RX_PAGE_INFO = 50, }; /* @@ -161,4 +163,12 @@ struct rdma_ctrlqp_setup { unsigned long long base_addr; unsigned int size; }; + +/* + * Offload TX/RX page information. + */ +struct ofld_page_info { + unsigned int page_size; /* Page size, should be a power of 2 */ + unsigned int num; /* Number of pages */ +}; #endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */ diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index bdff7baeb59d..bac9214170ae 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -317,6 +317,8 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) struct iff_mac *iffmacp; struct ddp_params *ddpp; struct adap_ports *ports; + struct ofld_page_info *rx_page_info; + struct tp_params *tp = &adapter->params.tp; int i; switch (req) { @@ -382,6 +384,11 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) if (!offload_running(adapter)) return -EAGAIN; return cxgb_rdma_ctl(adapter, req, data); + case GET_RX_PAGE_INFO: + rx_page_info = data; + rx_page_info->page_size = tp->rx_pg_size; + rx_page_info->num = tp->rx_num_pgs; + break; default: return -EOPNOTSUPP; } From c9a6ce500d78932c43361eae28c3de81b3660c77 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:26 -0700 Subject: [PATCH 1347/2804] cxgb3 - tighten checks on TID values Enforce validity checks on connection ids Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_defs.h | 20 ++++++++++++++++++-- drivers/net/cxgb3/cxgb3_offload.c | 28 +++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h index 483a594210a7..45e92164c260 100644 --- a/drivers/net/cxgb3/cxgb3_defs.h +++ b/drivers/net/cxgb3/cxgb3_defs.h @@ -79,9 +79,17 @@ static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t, static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t, unsigned int tid) { + union listen_entry *e; + if (tid < t->stid_base || tid >= t->stid_base + t->nstids) return NULL; - return &(stid2entry(t, tid)->t3c_tid); + + e = stid2entry(t, tid); + if ((void *)e->next >= (void *)t->tid_tab && + (void *)e->next < (void *)&t->atid_tab[t->natids]) + return NULL; + + return &e->t3c_tid; } /* @@ -90,9 +98,17 @@ static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t, static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t, unsigned int tid) { + union active_open_entry *e; + if (tid < t->atid_base || tid >= t->atid_base + t->natids) return NULL; - return &(atid2entry(t, tid)->t3c_tid); + + e = atid2entry(t, tid); + if ((void *)e->next >= (void *)t->tid_tab && + (void *)e->next < (void *)&t->atid_tab[t->natids]) + return NULL; + + return &e->t3c_tid; } int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index bac9214170ae..1c8eec38bde3 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -57,7 +57,7 @@ static DEFINE_RWLOCK(adapter_list_lock); static LIST_HEAD(adapter_list); static const unsigned int MAX_ATIDS = 64 * 1024; -static const unsigned int ATID_BASE = 0x100000; +static const unsigned int ATID_BASE = 0x10000; static inline int offload_activated(struct t3cdev *tdev) { @@ -694,10 +694,19 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb) { struct cpl_pass_accept_req *req = cplhdr(skb); unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct tid_info *t = &(T3C_DATA(dev))->tid_maps; struct t3c_tid_entry *t3c_tid; + unsigned int tid = GET_TID(req); - t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); - if (t3c_tid->ctx && t3c_tid->client->handlers && + if (unlikely(tid >= t->ntids)) { + printk("%s: passive open TID %u too large\n", + dev->name, tid); + t3_fatal_err(tdev2adap(dev)); + return CPL_RET_BUF_DONE; + } + + t3c_tid = lookup_stid(t, stid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) { return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ] (dev, skb, t3c_tid->ctx); @@ -779,16 +788,25 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) { struct cpl_act_establish *req = cplhdr(skb); unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct tid_info *t = &(T3C_DATA(dev))->tid_maps; struct t3c_tid_entry *t3c_tid; + unsigned int tid = GET_TID(req); - t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); + if (unlikely(tid >= t->ntids)) { + printk("%s: active establish TID %u too large\n", + dev->name, tid); + t3_fatal_err(tdev2adap(dev)); + return CPL_RET_BUF_DONE; + } + + t3c_tid = lookup_atid(t, atid); if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] (dev, skb, t3c_tid->ctx); } else { printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", - dev->name, CPL_PASS_ACCEPT_REQ); + dev->name, CPL_ACT_ESTABLISH); return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; } } From c64c2eaeaaf04f9c8a303508f804ba256435d79f Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:31 -0700 Subject: [PATCH 1348/2804] cxgb3 - Fatal error update Stop the MAC when a fatal error is detected. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 57fc199e0614..c00f2df05bcc 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -2297,6 +2297,10 @@ void t3_fatal_err(struct adapter *adapter) if (adapter->flags & FULL_INIT_DONE) { t3_sge_stop(adapter); + t3_write_reg(adapter, A_XGM_TX_CTRL, 0); + t3_write_reg(adapter, A_XGM_RX_CTRL, 0); + t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0); + t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0); t3_intr_disable(adapter); } CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); From 167cdf5fbc64ab8f4eae2cd6d9d0892478d569d7 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:36 -0700 Subject: [PATCH 1349/2804] cxgb3 - log adapter serial number Log HW serial number when cxgb3 module is loaded. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 2 ++ drivers/net/cxgb3/cxgb3_main.c | 6 ++++-- drivers/net/cxgb3/t3_hw.c | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index d6c77607a114..510e93f90b91 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -97,6 +97,7 @@ enum { MAX_NPORTS = 2, /* max # of ports */ MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */ EEPROMSIZE = 8192, /* Serial EEPROM size */ + SERNUM_LEN = 16, /* Serial # length */ RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */ TCB_SIZE = 128, /* TCB size */ NMTUS = 16, /* size of MTU table */ @@ -391,6 +392,7 @@ struct vpd_params { unsigned int uclk; unsigned int mdc; unsigned int mem_timing; + u8 sn[SERNUM_LEN + 1]; u8 eth_base[6]; u8 port_type[MAX_NPORTS]; unsigned short xauicfg[2]; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index c00f2df05bcc..3ee465dd0b08 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -2360,10 +2360,12 @@ static void __devinit print_port_info(struct adapter *adap, (adap->flags & USING_MSIX) ? " MSI-X" : (adap->flags & USING_MSI) ? " MSI" : ""); if (adap->name == dev->name && adap->params.vpd.mclk) - printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n", + printk(KERN_INFO + "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n", adap->name, t3_mc7_size(&adap->cm) >> 20, t3_mc7_size(&adap->pmtx) >> 20, - t3_mc7_size(&adap->pmrx) >> 20); + t3_mc7_size(&adap->pmrx) >> 20, + adap->params.vpd.sn); } } diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index b02d15daf5d9..3f7f06b6ee65 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -505,7 +505,7 @@ struct t3_vpd { u8 vpdr_len[2]; VPD_ENTRY(pn, 16); /* part number */ VPD_ENTRY(ec, 16); /* EC level */ - VPD_ENTRY(sn, 16); /* serial number */ + VPD_ENTRY(sn, SERNUM_LEN); /* serial number */ VPD_ENTRY(na, 12); /* MAC address base */ VPD_ENTRY(cclk, 6); /* core clock */ VPD_ENTRY(mclk, 6); /* mem clock */ @@ -648,6 +648,7 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10); p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10); p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10); + memcpy(p->sn, vpd.sn_data, SERNUM_LEN); /* Old eeproms didn't have port information */ if (adapter->params.rev == 0 && !vpd.port0_data[0]) { From 3f61e4278c8489c1d026a45b0903cd4230d1ec07 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:41 -0700 Subject: [PATCH 1350/2804] cxgb3 - Update internal memory management Set PM1 internal memory to round robin mode It balances access to this internal memory for multiport adapters. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/regs.h | 2 ++ drivers/net/cxgb3/t3_hw.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index 282427877ea9..5e1bc0dec5f1 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -1326,6 +1326,7 @@ #define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT) #define A_PM1_RX_CFG 0x5c0 +#define A_PM1_RX_MODE 0x5c4 #define A_PM1_RX_INT_ENABLE 0x5d8 @@ -1394,6 +1395,7 @@ #define A_PM1_RX_INT_CAUSE 0x5dc #define A_PM1_TX_CFG 0x5e0 +#define A_PM1_TX_MODE 0x5e4 #define A_PM1_TX_INT_ENABLE 0x5f8 diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 3f7f06b6ee65..e958bbe30623 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3223,6 +3223,8 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params) t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN); t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); + t3_write_reg(adapter, A_PM1_RX_MODE, 0); + t3_write_reg(adapter, A_PM1_TX_MODE, 0); init_hw_for_avail_ports(adapter, adapter->params.nports); t3_sge_init(adapter, &adapter->params.sge); From 5b296bc9e1e5570ce60262e62af066f70180cb99 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 29 Aug 2007 12:58:11 -0700 Subject: [PATCH 1351/2804] sky2: use debugfs rename Use debugfs rename to handle device neame changes. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 58 ++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a0d75b0f3798..d10af8ed93df 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3841,42 +3841,34 @@ static int sky2_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = ptr; + struct sky2_port *sky2 = netdev_priv(dev); - if (dev->open == sky2_up) { - struct sky2_port *sky2 = netdev_priv(dev); + if (dev->open != sky2_up || !sky2_debug) + return NOTIFY_DONE; - switch(event) { - case NETDEV_CHANGENAME: - if (!netif_running(dev)) - break; - /* fallthrough */ - case NETDEV_DOWN: - case NETDEV_GOING_DOWN: - if (sky2->debugfs) { - printk(KERN_DEBUG PFX "%s: remove debugfs\n", - dev->name); - debugfs_remove(sky2->debugfs); - sky2->debugfs = NULL; - } - - if (event != NETDEV_CHANGENAME) - break; - /* fallthrough for changename */ - case NETDEV_UP: - if (sky2_debug) { - struct dentry *d; - d = debugfs_create_file(dev->name, S_IRUGO, - sky2_debug, dev, - &sky2_debug_fops); - if (d == NULL || IS_ERR(d)) - printk(KERN_INFO PFX - "%s: debugfs create failed\n", - dev->name); - else - sky2->debugfs = d; - } - break; + switch(event) { + case NETDEV_CHANGENAME: + if (sky2->debugfs) { + sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs, + sky2_debug, dev->name); } + break; + + case NETDEV_GOING_DOWN: + if (sky2->debugfs) { + printk(KERN_DEBUG PFX "%s: remove debugfs\n", + dev->name); + debugfs_remove(sky2->debugfs); + sky2->debugfs = NULL; + } + break; + + case NETDEV_UP: + sky2->debugfs = debugfs_create_file(dev->name, S_IRUGO, + sky2_debug, dev, + &sky2_debug_fops); + if (IS_ERR(sky2->debugfs)) + sky2->debugfs = NULL; } return NOTIFY_DONE; From efcf6e2febbfe5b2ab497421e2f7f188e1741cf9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 29 Aug 2007 12:58:12 -0700 Subject: [PATCH 1352/2804] sky2: document GPHY_CTRL bits Add documentation of GPHY_CTRL register bits even if driver is not using them (yet). Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index f18f8752118e..3d4f1903d62c 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1850,6 +1850,28 @@ enum { /* GPHY_CTRL 32 bit GPHY Control Reg (YUKON only) */ enum { + GPC_TX_PAUSE = 1<<30, /* Tx pause enabled (ro) */ + GPC_RX_PAUSE = 1<<29, /* Rx pause enabled (ro) */ + GPC_SPEED = 3<<27, /* PHY speed (ro) */ + GPC_LINK = 1<<26, /* Link up (ro) */ + GPC_DUPLEX = 1<<25, /* Duplex (ro) */ + GPC_CLOCK = 1<<24, /* 125Mhz clock stable (ro) */ + + GPC_PDOWN = 1<<23, /* Internal regulator 2.5 power down */ + GPC_TSTMODE = 1<<22, /* Test mode */ + GPC_REG18 = 1<<21, /* Reg18 Power down */ + GPC_REG12SEL = 3<<19, /* Reg12 power setting */ + GPC_REG18SEL = 3<<17, /* Reg18 power setting */ + GPC_SPILOCK = 1<<16, /* SPI lock (ASF) */ + + GPC_LEDMUX = 3<<14, /* LED Mux */ + GPC_INTPOL = 1<<13, /* Interrupt polarity */ + GPC_DETECT = 1<<12, /* Energy detect */ + GPC_1000HD = 1<<11, /* Enable 1000Mbit HD */ + GPC_SLAVE = 1<<10, /* Slave mode */ + GPC_PAUSE = 1<<9, /* Pause enable */ + GPC_LEDCTL = 3<<6, /* GPHY Leds */ + GPC_RST_CLR = 1<<1, /* Clear GPHY Reset */ GPC_RST_SET = 1<<0, /* Set GPHY Reset */ }; From 8c4c00f3710f9e5653ed465e88271664f3163930 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 29 Aug 2007 12:58:13 -0700 Subject: [PATCH 1353/2804] sky2: dont restrict config space access Take out the code that protects driver from accessing the PCI config space. We are old enough to run with scissors now. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d10af8ed93df..77bfcf0dda3b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -610,7 +610,6 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) onoff = !onoff; - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); if (onoff) /* Turn off phy power saving */ @@ -620,7 +619,6 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) sky2_pci_write32(hw, PCI_DEV_REG1, reg1); sky2_pci_read32(hw, PCI_DEV_REG1); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); udelay(100); } @@ -688,11 +686,9 @@ static void sky2_wol_init(struct sky2_port *sky2) sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); /* Turn on legacy PCI-Express PME mode */ - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); reg1 |= PCI_Y2_PME_LEGACY; sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); @@ -2438,10 +2434,8 @@ static void sky2_hw_intr(struct sky2_hw *hw) dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n", pci_err); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write16(hw, PCI_STATUS, pci_err | PCI_STATUS_ERROR_BITS); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } if (status & Y2_IS_PCI_EXP) { @@ -2455,11 +2449,8 @@ static void sky2_hw_intr(struct sky2_hw *hw) pex_err); /* clear the interrupt */ - sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); - sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - if (pex_err & PEX_FATAL_ERRORS) { u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); hwmsk &= ~Y2_IS_PCI_EXP; @@ -2804,7 +2795,6 @@ static void sky2_reset(struct sky2_hw *hw) /* clear PCI errors, if any */ status = sky2_pci_read16(hw, PCI_STATUS); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write16(hw, PCI_STATUS, status | PCI_STATUS_ERROR_BITS); @@ -2827,8 +2817,6 @@ static void sky2_reset(struct sky2_hw *hw) | GMC_BYP_RETR_ON); } - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - /* Clear I2C IRQ noise */ sky2_write32(hw, B2_I2C_IRQ, 1); From 555382cbfc6d2187b53888190755e56f52308cd6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 29 Aug 2007 12:58:14 -0700 Subject: [PATCH 1354/2804] sky2: advanced error reporting Use the kernel interfaces for advanced error reporting. This should be cleaner and clear up errors on boot. For those systems with busted BIOS's that don't correctly support mmconfig, advanced error reporting will be disabled. The PCI registers for advanced error reporting start at 0x100 which is too large to be accessed by legacy functions. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 47 ++++++++++++++++++++++++++-------------------- drivers/net/sky2.h | 41 ---------------------------------------- 2 files changed, 27 insertions(+), 61 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 77bfcf0dda3b..b81d81746c2c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -2421,7 +2422,11 @@ static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status) static void sky2_hw_intr(struct sky2_hw *hw) { + struct pci_dev *pdev = hw->pdev; u32 status = sky2_read32(hw, B0_HWE_ISRC); + u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); + + status &= hwmsk; if (status & Y2_IS_TIST_OV) sky2_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ); @@ -2431,7 +2436,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) pci_err = sky2_pci_read16(hw, PCI_STATUS); if (net_ratelimit()) - dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n", + dev_err(&pdev->dev, "PCI hardware error (0x%x)\n", pci_err); sky2_pci_write16(hw, PCI_STATUS, @@ -2440,22 +2445,13 @@ static void sky2_hw_intr(struct sky2_hw *hw) if (status & Y2_IS_PCI_EXP) { /* PCI-Express uncorrectable Error occurred */ - u32 pex_err; - - pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT); + int pos = pci_find_aer_capability(hw->pdev); + u32 err; + pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_STATUS, &err); if (net_ratelimit()) - dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n", - pex_err); - - /* clear the interrupt */ - sky2_pci_write32(hw, PEX_UNC_ERR_STAT, - 0xffffffffUL); - if (pex_err & PEX_FATAL_ERRORS) { - u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); - hwmsk &= ~Y2_IS_PCI_EXP; - sky2_write32(hw, B0_HWE_IMSK, hwmsk); - } + dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err); + pci_cleanup_aer_uncorrect_error_status(pdev); } if (status & Y2_HWE_L1_MASK) @@ -2775,8 +2771,10 @@ static int __devinit sky2_init(struct sky2_hw *hw) static void sky2_reset(struct sky2_hw *hw) { + struct pci_dev *pdev = hw->pdev; u16 status; - int i; + int i, cap; + u32 hwe_mask = Y2_HWE_ALL_MASK; /* disable ASF */ if (hw->chip_id == CHIP_ID_YUKON_EX) { @@ -2800,10 +2798,19 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_MRST_CLR); - /* clear any PEX errors */ - if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) - sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); + cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (cap) { + /* Check for advanced error reporting */ + pci_cleanup_aer_uncorrect_error_status(pdev); + pci_cleanup_aer_correct_error_status(pdev); + /* If error bit is stuck on ignore it */ + if (sky2_read32(hw, B0_HWE_ISRC) & Y2_IS_PCI_EXP) + dev_info(&pdev->dev, "ignoring stuck error report bit\n"); + + else if (pci_enable_pcie_error_reporting(pdev)) + hwe_mask |= Y2_IS_PCI_EXP; + } sky2_power_on(hw); @@ -2855,7 +2862,7 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53); } - sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK); + sky2_write32(hw, B0_HWE_IMSK, hwe_mask); for (i = 0; i < hw->ports; i++) sky2_gmac_reset(hw, i); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 3d4f1903d62c..6f5e162709b6 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -18,14 +18,6 @@ enum { PCI_CFG_REG_1 = 0x94, }; -enum { - PEX_DEV_CAP = 0xe4, - PEX_DEV_CTRL = 0xe8, - PEX_DEV_STA = 0xea, - PEX_LNK_STAT = 0xf2, - PEX_UNC_ERR_STAT= 0x104, -}; - /* Yukon-2 */ enum pci_dev_reg_1 { PCI_Y2_PIG_ENA = 1<<31, /* Enable Plug-in-Go (YUKON-2) */ @@ -151,38 +143,6 @@ enum pci_cfg_reg1 { PCI_STATUS_REC_TARGET_ABORT | \ PCI_STATUS_PARITY) -enum pex_dev_ctrl { - PEX_DC_MAX_RRS_MSK = 7<<12, /* Bit 14..12: Max. Read Request Size */ - PEX_DC_EN_NO_SNOOP = 1<<11,/* Enable No Snoop */ - PEX_DC_EN_AUX_POW = 1<<10,/* Enable AUX Power */ - PEX_DC_EN_PHANTOM = 1<<9, /* Enable Phantom Functions */ - PEX_DC_EN_EXT_TAG = 1<<8, /* Enable Extended Tag Field */ - PEX_DC_MAX_PLS_MSK = 7<<5, /* Bit 7.. 5: Max. Payload Size Mask */ - PEX_DC_EN_REL_ORD = 1<<4, /* Enable Relaxed Ordering */ - PEX_DC_EN_UNS_RQ_RP = 1<<3, /* Enable Unsupported Request Reporting */ - PEX_DC_EN_FAT_ER_RP = 1<<2, /* Enable Fatal Error Reporting */ - PEX_DC_EN_NFA_ER_RP = 1<<1, /* Enable Non-Fatal Error Reporting */ - PEX_DC_EN_COR_ER_RP = 1<<0, /* Enable Correctable Error Reporting */ -}; -#define PEX_DC_MAX_RD_RQ_SIZE(x) (((x)<<12) & PEX_DC_MAX_RRS_MSK) - -/* PEX_UNC_ERR_STAT PEX Uncorrectable Errors Status Register (Yukon-2) */ -enum pex_err { - PEX_UNSUP_REQ = 1<<20, /* Unsupported Request Error */ - - PEX_MALFOR_TLP = 1<<18, /* Malformed TLP */ - - PEX_UNEXP_COMP = 1<<16, /* Unexpected Completion */ - - PEX_COMP_TO = 1<<14, /* Completion Timeout */ - PEX_FLOW_CTRL_P = 1<<13, /* Flow Control Protocol Error */ - PEX_POIS_TLP = 1<<12, /* Poisoned TLP */ - - PEX_DATA_LINK_P = 1<<4, /* Data Link Protocol Error */ - PEX_FATAL_ERRORS= (PEX_MALFOR_TLP | PEX_FLOW_CTRL_P | PEX_DATA_LINK_P), -}; - - enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, @@ -419,7 +379,6 @@ enum { Y2_IS_PAR_RX2 | Y2_IS_TCP_TXS2| Y2_IS_TCP_TXA2, Y2_HWE_ALL_MASK = Y2_IS_TIST_OV | Y2_IS_MST_ERR | Y2_IS_IRQ_STAT | - Y2_IS_PCI_EXP | Y2_HWE_L1_MASK | Y2_HWE_L2_MASK, }; From 167f53d05fccb47b6eeadac7f6705b3f2f042d03 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 25 Sep 2007 19:01:02 -0700 Subject: [PATCH 1355/2804] sky2: use pci_config access functions Use the PCI layer config access functions. The driver was using the memory mapped window in device, to workaround issues accessing the advanced error reporting registers. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/sky2.c | 93 +++++++++++++++++++++++++--------------------- drivers/net/sky2.h | 21 ----------- 2 files changed, 51 insertions(+), 63 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b81d81746c2c..941a60882526 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -223,21 +223,22 @@ static void sky2_power_on(struct sky2_hw *hw) sky2_write8(hw, B2_Y2_CLK_GATE, 0); if (hw->flags & SKY2_HW_ADV_POWER_CTL) { + struct pci_dev *pdev = hw->pdev; u32 reg; - sky2_pci_write32(hw, PCI_DEV_REG3, 0); + pci_write_config_dword(pdev, PCI_DEV_REG3, 0); - reg = sky2_pci_read32(hw, PCI_DEV_REG4); + pci_read_config_dword(pdev, PCI_DEV_REG4, ®); /* set all bits to 0 except bits 15..12 and 8 */ reg &= P_ASPM_CONTROL_MSK; - sky2_pci_write32(hw, PCI_DEV_REG4, reg); + pci_write_config_dword(pdev, PCI_DEV_REG4, reg); - reg = sky2_pci_read32(hw, PCI_DEV_REG5); + pci_read_config_dword(pdev, PCI_DEV_REG5, ®); /* set all bits to 0 except bits 28 & 27 */ reg &= P_CTL_TIM_VMAIN_AV_MSK; - sky2_pci_write32(hw, PCI_DEV_REG5, reg); + pci_write_config_dword(pdev, PCI_DEV_REG5, reg); - sky2_pci_write32(hw, PCI_CFG_REG_1, 0); + pci_write_config_dword(pdev, PCI_CFG_REG_1, 0); /* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */ reg = sky2_read32(hw, B2_GP_IO); @@ -603,6 +604,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) { + struct pci_dev *pdev = hw->pdev; u32 reg1; static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; @@ -611,15 +613,16 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) onoff = !onoff; - reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); if (onoff) /* Turn off phy power saving */ reg1 &= ~phy_power[port]; else reg1 |= phy_power[port]; - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - sky2_pci_read32(hw, PCI_DEV_REG1); + pci_write_config_dword(pdev, PCI_DEV_REG1, reg1); + pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); + udelay(100); } @@ -687,9 +690,9 @@ static void sky2_wol_init(struct sky2_port *sky2) sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); /* Turn on legacy PCI-Express PME mode */ - reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + pci_read_config_dword(hw->pdev, PCI_DEV_REG1, ®1); reg1 |= PCI_Y2_PME_LEGACY; - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1); /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); @@ -1306,9 +1309,9 @@ static int sky2_up(struct net_device *dev) struct sky2_port *osky2 = netdev_priv(otherdev); u16 cmd; - cmd = sky2_pci_read16(hw, cap + PCI_X_CMD); + pci_read_config_word(hw->pdev, cap + PCI_X_CMD, &cmd); cmd &= ~PCI_X_CMD_MAX_SPLIT; - sky2_pci_write16(hw, cap + PCI_X_CMD, cmd); + pci_write_config_word(hw->pdev, cap + PCI_X_CMD, cmd); sky2->rx_csum = 0; osky2->rx_csum = 0; @@ -2434,13 +2437,13 @@ static void sky2_hw_intr(struct sky2_hw *hw) if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) { u16 pci_err; - pci_err = sky2_pci_read16(hw, PCI_STATUS); + pci_read_config_word(pdev, PCI_STATUS, &pci_err); if (net_ratelimit()) dev_err(&pdev->dev, "PCI hardware error (0x%x)\n", pci_err); - sky2_pci_write16(hw, PCI_STATUS, - pci_err | PCI_STATUS_ERROR_BITS); + pci_write_config_word(pdev, PCI_STATUS, + pci_err | PCI_STATUS_ERROR_BITS); } if (status & Y2_IS_PCI_EXP) { @@ -2694,10 +2697,13 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) static int __devinit sky2_init(struct sky2_hw *hw) { + int rc; u8 t8; - /* Enable all clocks */ - sky2_pci_write32(hw, PCI_DEV_REG3, 0); + /* Enable all clocks and check for bad PCI access */ + rc = pci_write_config_dword(hw->pdev, PCI_DEV_REG3, 0); + if (rc) + return rc; sky2_write8(hw, B0_CTST, CS_RST_CLR); @@ -2791,10 +2797,9 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_RST_CLR); /* clear PCI errors, if any */ - status = sky2_pci_read16(hw, PCI_STATUS); - - sky2_pci_write16(hw, PCI_STATUS, status | PCI_STATUS_ERROR_BITS); - + pci_read_config_word(pdev, PCI_STATUS, &status); + status |= PCI_STATUS_ERROR_BITS; + pci_write_config_word(pdev, PCI_STATUS, status); sky2_write8(hw, B0_CTST, CS_MRST_CLR); @@ -3606,26 +3611,31 @@ static int sky2_get_eeprom_len(struct net_device *dev) struct sky2_port *sky2 = netdev_priv(dev); u16 reg2; - reg2 = sky2_pci_read32(sky2->hw, PCI_DEV_REG2); + pci_read_config_word(sky2->hw->pdev, PCI_DEV_REG2, ®2); return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); } -static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset) +static u32 sky2_vpd_read(struct pci_dev *pdev, int cap, u16 offset) { - sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset); + u32 val; - while (!(sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F)) - cpu_relax(); - return sky2_pci_read32(hw, cap + PCI_VPD_DATA); + pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset); + + do { + pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); + } while (!(offset & PCI_VPD_ADDR_F)); + + pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val); + return val; } -static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val) +static void sky2_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val) { - sky2_pci_write32(hw, cap + PCI_VPD_DATA, val); - sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F); + pci_write_config_word(pdev, cap + PCI_VPD_DATA, val); + pci_write_config_dword(pdev, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F); do { - cpu_relax(); - } while (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F); + pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); + } while (offset & PCI_VPD_ADDR_F); } static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, @@ -3642,7 +3652,7 @@ static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom eeprom->magic = SKY2_EEPROM_MAGIC; while (length > 0) { - u32 val = sky2_vpd_read(sky2->hw, cap, offset); + u32 val = sky2_vpd_read(sky2->hw->pdev, cap, offset); int n = min_t(int, length, sizeof(val)); memcpy(data, &val, n); @@ -3672,10 +3682,10 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom int n = min_t(int, length, sizeof(val)); if (n < sizeof(val)) - val = sky2_vpd_read(sky2->hw, cap, offset); + val = sky2_vpd_read(sky2->hw->pdev, cap, offset); memcpy(&val, data, n); - sky2_vpd_write(sky2->hw, cap, offset, val); + sky2_vpd_write(sky2->hw->pdev, cap, offset, val); length -= n; data += n; @@ -4116,15 +4126,14 @@ static int __devinit sky2_probe(struct pci_dev *pdev, */ { u32 reg; - reg = sky2_pci_read32(hw, PCI_DEV_REG2); + pci_read_config_dword(pdev,PCI_DEV_REG2, ®); reg &= ~PCI_REV_DESC; - sky2_pci_write32(hw, PCI_DEV_REG2, reg); + pci_write_config_dword(pdev, PCI_DEV_REG2, reg); } #endif /* ring for status responses */ - hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES, - &hw->st_dma); + hw->st_le = pci_alloc_consistent(pdev, STATUS_LE_BYTES, &hw->st_dma); if (!hw->st_le) goto err_out_iounmap; @@ -4201,7 +4210,7 @@ err_out_free_netdev: free_netdev(dev); err_out_free_pci: sky2_write8(hw, B0_CTST, CS_RST_SET); - pci_free_consistent(hw->pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); + pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); err_out_iounmap: iounmap(hw->regs); err_out_free_hw: @@ -4312,7 +4321,7 @@ static int sky2_resume(struct pci_dev *pdev) if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_FE_P) - sky2_pci_write32(hw, PCI_DEV_REG3, 0); + pci_write_config_dword(pdev, PCI_DEV_REG3, 0); sky2_reset(hw); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 6f5e162709b6..f4a3c2f403e5 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2129,25 +2129,4 @@ static inline void gma_set_addr(struct sky2_hw *hw, unsigned port, unsigned reg, gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8)); gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8)); } - -/* PCI config space access */ -static inline u32 sky2_pci_read32(const struct sky2_hw *hw, unsigned reg) -{ - return sky2_read32(hw, Y2_CFG_SPC + reg); -} - -static inline u16 sky2_pci_read16(const struct sky2_hw *hw, unsigned reg) -{ - return sky2_read16(hw, Y2_CFG_SPC + reg); -} - -static inline void sky2_pci_write32(struct sky2_hw *hw, unsigned reg, u32 val) -{ - sky2_write32(hw, Y2_CFG_SPC + reg, val); -} - -static inline void sky2_pci_write16(struct sky2_hw *hw, unsigned reg, u16 val) -{ - sky2_write16(hw, Y2_CFG_SPC + reg, val); -} #endif From ced13330bb687780ce1d46f5404521cc0ea40481 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sat, 25 Aug 2007 20:32:59 +0200 Subject: [PATCH 1356/2804] bmac: add simple ethtool support for network manager NetworkManager will not start dhcpd on an interface unless it reports link-up state via ethtool. Signed-off-by: Olaf Hering Signed-off-by: Jeff Garzik --- drivers/net/bmac.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 9b8d7d9dbe86..1eb95b603004 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1246,6 +1247,17 @@ static void bmac_reset_and_enable(struct net_device *dev) } spin_unlock_irqrestore(&bp->lock, flags); } +static void bmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct bmac_data *bp = netdev_priv(dev); + strcpy(info->driver, "bmac"); + strcpy(info->bus_info, bp->mdev->ofdev.dev.bus_id); +} + +static const struct ethtool_ops bmac_ethtool_ops = { + .get_drvinfo = bmac_get_drvinfo, + .get_link = ethtool_op_get_link, +}; static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match) { @@ -1311,6 +1323,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i dev->open = bmac_open; dev->stop = bmac_close; + dev->ethtool_ops = &bmac_ethtool_ops; dev->hard_start_xmit = bmac_output; dev->get_stats = bmac_stats; dev->set_multicast_list = bmac_set_multicast; From a85b94222d8b95e184941183f28b06b637cc4dee Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 15 Sep 2007 13:40:59 -0700 Subject: [PATCH 1357/2804] pasemi_mac: Abstract out register access Abstract out the PCI config read/write accesses into reg read/write ones, still calling the pci accessors on the back end. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 195 ++++++++++++++++++++------------------- 1 file changed, 101 insertions(+), 94 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index e63cc335a4ba..c3a0fc64de0c 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -81,6 +81,48 @@ MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); static struct pasdma_status *dma_status; +static unsigned int read_iob_reg(struct pasemi_mac *mac, unsigned int reg) +{ + unsigned int val; + + pci_read_config_dword(mac->iob_pdev, reg, &val); + return val; +} + +static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, + unsigned int val) +{ + pci_write_config_dword(mac->iob_pdev, reg, val); +} + +static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg) +{ + unsigned int val; + + pci_read_config_dword(mac->pdev, reg, &val); + return val; +} + +static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg, + unsigned int val) +{ + pci_write_config_dword(mac->pdev, reg, val); +} + +static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg) +{ + unsigned int val; + + pci_read_config_dword(mac->dma_pdev, reg, &val); + return val; +} + +static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg, + unsigned int val) +{ + pci_write_config_dword(mac->dma_pdev, reg, val); +} + static int pasemi_get_mac_addr(struct pasemi_mac *mac) { struct pci_dev *pdev = mac->pdev; @@ -166,22 +208,21 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id), - PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma)); + write_dma_reg(mac, PAS_DMA_RXCHAN_BASEL(chan_id), PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id), - PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | - PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); + write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id), + PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | + PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id), - PAS_DMA_RXCHAN_CFG_HBU(1)); + write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), + PAS_DMA_RXCHAN_CFG_HBU(1)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if), - PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); + write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if), + PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if), - PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | - PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); + write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if), + PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | + PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); ring->next_to_fill = 0; ring->next_to_clean = 0; @@ -233,18 +274,18 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id), - PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); + write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id), + PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val); + write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id), - PAS_DMA_TXCHAN_CFG_TY_IFACE | - PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | - PAS_DMA_TXCHAN_CFG_UP | - PAS_DMA_TXCHAN_CFG_WT(2)); + write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), + PAS_DMA_TXCHAN_CFG_TY_IFACE | + PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | + PAS_DMA_TXCHAN_CFG_UP | + PAS_DMA_TXCHAN_CFG_WT(2)); ring->next_to_use = 0; ring->next_to_clean = 0; @@ -383,12 +424,8 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) wmb(); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_INCR(mac->dma_rxch), - limit - count); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_INCR(mac->dma_if), - limit - count); + write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), limit - count); + write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), limit - count); mac->rx->next_to_fill += limit - count; } @@ -404,9 +441,7 @@ static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) reg = PAS_IOB_DMA_RXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_RXCH_RESET_PINTC; - pci_write_config_dword(mac->iob_pdev, - PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), - reg); + write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); } static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) @@ -418,8 +453,7 @@ static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC; - pci_write_config_dword(mac->iob_pdev, - PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); + write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); } @@ -574,8 +608,6 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) * all others. */ - pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), ®); - reg = 0; if (*mac->rx_status & PAS_STATUS_SOFT) reg |= PAS_IOB_DMA_RXCH_RESET_SINTC; @@ -586,9 +618,7 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) netif_rx_schedule(dev, &mac->napi); - pci_write_config_dword(mac->iob_pdev, - PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); - + write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); return IRQ_HANDLED; } @@ -613,9 +643,7 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) if (*mac->tx_status & PAS_STATUS_ERROR) reg |= PAS_IOB_DMA_TXCH_RESET_DINTC; - pci_write_config_dword(mac->iob_pdev, - PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), - reg); + write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); return IRQ_HANDLED; } @@ -641,7 +669,7 @@ static void pasemi_adjust_link(struct net_device *dev) } else netif_carrier_on(dev); - pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); + flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M | PAS_MAC_CFG_PCFG_TSR_M); @@ -673,7 +701,7 @@ static void pasemi_adjust_link(struct net_device *dev) mac->link = mac->phydev->link; if (new_flags != flags) - pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags); + write_mac_reg(mac, PAS_MAC_CFG_PCFG, new_flags); if (msg && netif_msg_link(mac)) printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n", @@ -736,39 +764,37 @@ static int pasemi_mac_open(struct net_device *dev) int ret; /* enable rx section */ - pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD, - PAS_DMA_COM_RXCMD_EN); + write_dma_reg(mac, PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN); /* enable tx section */ - pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD, - PAS_DMA_COM_TXCMD_EN); + write_dma_reg(mac, PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) | PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) | PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12); - pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags); + write_mac_reg(mac, PAS_MAC_CFG_TXP, flags); flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; - pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), - PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); + write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), + PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); - pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), - PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); + write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), + PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); /* Clear out any residual packet count state from firmware */ pasemi_mac_restart_rx_intr(mac); pasemi_mac_restart_tx_intr(mac); /* 0xffffff is max value, about 16ms */ - pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, - PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); + write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); - pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); + write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); ret = pasemi_mac_setup_rx_resources(dev); if (ret) @@ -778,25 +804,22 @@ static int pasemi_mac_open(struct net_device *dev) if (ret) goto out_tx_resources; - pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL, - PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) | - PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch)); + write_mac_reg(mac, PAS_MAC_IPC_CHNL, + PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) | + PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch)); /* enable rx if */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - PAS_DMA_RXINT_RCMDSTA_EN); + write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), + PAS_DMA_RXINT_RCMDSTA_EN); /* enable rx channel */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), - PAS_DMA_RXCHAN_CCMDSTA_EN | - PAS_DMA_RXCHAN_CCMDSTA_DU); + write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), + PAS_DMA_RXCHAN_CCMDSTA_EN | + PAS_DMA_RXCHAN_CCMDSTA_DU); /* enable tx channel */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - PAS_DMA_TXCHAN_TCMDSTA_EN); + write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), + PAS_DMA_TXCHAN_TCMDSTA_EN); pasemi_mac_replenish_rx_ring(dev); @@ -876,20 +899,12 @@ static int pasemi_mac_close(struct net_device *dev) pasemi_mac_clean_rx(mac, RX_RING_SIZE); /* Disable interface */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - PAS_DMA_TXCHAN_TCMDSTA_ST); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - PAS_DMA_RXINT_RCMDSTA_ST); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), - PAS_DMA_RXCHAN_CCMDSTA_ST); + write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_ST); + write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), PAS_DMA_RXINT_RCMDSTA_ST); + write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST); for (retries = 0; retries < MAX_RETRIES; retries++) { - pci_read_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - &stat); + stat = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) break; cond_resched(); @@ -899,9 +914,7 @@ static int pasemi_mac_close(struct net_device *dev) dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - pci_read_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), - &stat); + stat = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) break; cond_resched(); @@ -911,9 +924,7 @@ static int pasemi_mac_close(struct net_device *dev) dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - pci_read_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - &stat); + stat = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) break; cond_resched(); @@ -926,12 +937,9 @@ static int pasemi_mac_close(struct net_device *dev) * stopping, since you can't disable when active. */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); + write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0); + write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0); + write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); free_irq(mac->tx_irq, dev); free_irq(mac->rx_irq, dev); @@ -1012,8 +1020,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&txring->lock, flags); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1); + write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1); return NETDEV_TX_OK; @@ -1036,7 +1043,7 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); unsigned int flags; - pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); + flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); /* Set promiscuous */ if (dev->flags & IFF_PROMISC) @@ -1044,7 +1051,7 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev) else flags &= ~PAS_MAC_CFG_PCFG_PR; - pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); + write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); } From b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 15 Sep 2007 13:44:07 -0700 Subject: [PATCH 1358/2804] pasemi_mac: Stop using the pci config space accessors for register read/writes Move away from using the pci config access functions for simple register access. Our device has all of the registers in the config space (hey, from the hardware point of view it looks reasonable :-), so we need to somehow get to it. Newer firmwares have it in the device tree such that we can just get it and ioremap it there (in case it ever moves in future products). For now, provide a hardcoded fallback for older firmwares. [ Resolved napi_struct conflicts... -DaveM ] Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 132 +++++++++++++++++++++++++++------------ drivers/net/pasemi_mac.h | 3 + 2 files changed, 94 insertions(+), 41 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c3a0fc64de0c..be311e9404b4 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -83,44 +83,35 @@ static struct pasdma_status *dma_status; static unsigned int read_iob_reg(struct pasemi_mac *mac, unsigned int reg) { - unsigned int val; - - pci_read_config_dword(mac->iob_pdev, reg, &val); - return val; + return in_le32(mac->iob_regs+reg); } static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { - pci_write_config_dword(mac->iob_pdev, reg, val); + out_le32(mac->iob_regs+reg, val); } static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg) { - unsigned int val; - - pci_read_config_dword(mac->pdev, reg, &val); - return val; + return in_le32(mac->regs+reg); } static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { - pci_write_config_dword(mac->pdev, reg, val); + out_le32(mac->regs+reg, val); } static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg) { - unsigned int val; - - pci_read_config_dword(mac->dma_pdev, reg, &val); - return val; + return in_le32(mac->dma_regs+reg); } static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { - pci_write_config_dword(mac->dma_pdev, reg, val); + out_le32(mac->dma_regs+reg, val); } static int pasemi_get_mac_addr(struct pasemi_mac *mac) @@ -585,7 +576,6 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) } mac->tx->next_to_clean += count; spin_unlock_irqrestore(&mac->tx->lock, flags); - netif_wake_queue(mac->netdev); return count; @@ -1071,6 +1061,73 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) return pkts; } +static void __iomem * __devinit map_onedev(struct pci_dev *p, int index) +{ + struct device_node *dn; + void __iomem *ret; + + dn = pci_device_to_OF_node(p); + if (!dn) + goto fallback; + + ret = of_iomap(dn, index); + if (!ret) + goto fallback; + + return ret; +fallback: + /* This is hardcoded and ugly, but we have some firmware versions + * that don't provide the register space in the device tree. Luckily + * they are at well-known locations so we can just do the math here. + */ + return ioremap(0xe0000000 + (p->devfn << 12), 0x2000); +} + +static int __devinit pasemi_mac_map_regs(struct pasemi_mac *mac) +{ + struct resource res; + struct device_node *dn; + int err; + + mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); + if (!mac->dma_pdev) { + dev_err(&mac->pdev->dev, "Can't find DMA Controller\n"); + return -ENODEV; + } + + mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); + if (!mac->iob_pdev) { + dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n"); + return -ENODEV; + } + + mac->regs = map_onedev(mac->pdev, 0); + mac->dma_regs = map_onedev(mac->dma_pdev, 0); + mac->iob_regs = map_onedev(mac->iob_pdev, 0); + + if (!mac->regs || !mac->dma_regs || !mac->iob_regs) { + dev_err(&mac->pdev->dev, "Can't map registers\n"); + return -ENODEV; + } + + /* The dma status structure is located in the I/O bridge, and + * is cache coherent. + */ + if (!dma_status) { + dn = pci_device_to_OF_node(mac->iob_pdev); + if (dn) + err = of_address_to_resource(dn, 1, &res); + if (!dn || err) { + /* Fallback for old firmware */ + res.start = 0xfd800000; + res.end = res.start + 0x1000; + } + dma_status = __ioremap(res.start, res.end-res.start, 0); + } + + return 0; +} + static int __devinit pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1099,26 +1156,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mac->pdev = pdev; mac->netdev = dev; - mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); dev->features = NETIF_F_HW_CSUM; - if (!mac->dma_pdev) { - dev_err(&pdev->dev, "Can't find DMA Controller\n"); - err = -ENODEV; - goto out_free_netdev; - } - - mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); - - if (!mac->iob_pdev) { - dev_err(&pdev->dev, "Can't find I/O Bridge\n"); - err = -ENODEV; - goto out_put_dma_pdev; - } - /* These should come out of the device tree eventually */ mac->dma_txch = index; mac->dma_rxch = index; @@ -1157,12 +1199,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->get_stats = pasemi_mac_get_stats; dev->set_multicast_list = pasemi_mac_set_rx_mode; - /* The dma status structure is located in the I/O bridge, and - * is cache coherent. - */ - if (!dma_status) - /* XXXOJN This should come from the device tree */ - dma_status = __ioremap(0xfd800000, 0x1000, 0); + err = pasemi_mac_map_regs(mac); + if (err) + goto out; mac->rx_status = &dma_status->rx_sta[mac->dma_rxch]; mac->tx_status = &dma_status->tx_sta[mac->dma_txch]; @@ -1189,10 +1228,17 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; out: - pci_dev_put(mac->iob_pdev); -out_put_dma_pdev: - pci_dev_put(mac->dma_pdev); -out_free_netdev: + if (mac->iob_pdev) + pci_dev_put(mac->iob_pdev); + if (mac->dma_pdev) + pci_dev_put(mac->dma_pdev); + if (mac->dma_regs) + iounmap(mac->dma_regs); + if (mac->iob_regs) + iounmap(mac->iob_regs); + if (mac->regs) + iounmap(mac->regs); + free_netdev(dev); out_disable_device: pci_disable_device(pdev); @@ -1216,6 +1262,10 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev) pci_dev_put(mac->dma_pdev); pci_dev_put(mac->iob_pdev); + iounmap(mac->regs); + iounmap(mac->dma_regs); + iounmap(mac->iob_regs); + pci_set_drvdata(pdev, NULL); free_netdev(netdev); } diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 85d3b7856e5f..ef443640c768 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -52,6 +52,9 @@ struct pasemi_mac_rxring { struct pasemi_mac { struct net_device *netdev; + void __iomem *regs; + void __iomem *dma_regs; + void __iomem *iob_regs; struct pci_dev *pdev; struct pci_dev *dma_pdev; struct pci_dev *iob_pdev; From c0efd52b8b1951c20878208fdcbab0468f816804 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:12:52 -0500 Subject: [PATCH 1359/2804] pasemi_mac: Enable L2 caching of packet headers Enable settings to target l2 for the first few cachelines of the packet, since we'll access them to get to the various headers. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 5 ++++- drivers/net/pasemi_mac.h | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index be311e9404b4..46d5c0eef784 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -206,7 +206,7 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), - PAS_DMA_RXCHAN_CFG_HBU(1)); + PAS_DMA_RXCHAN_CFG_HBU(2)); write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if), PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); @@ -215,6 +215,9 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); + write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), + PAS_DMA_RXINT_CFG_DHL(2)); + ring->next_to_fill = 0; ring->next_to_clean = 0; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index ef443640c768..fbbc17a31db7 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -219,6 +219,14 @@ enum { #define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000 #define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000 #define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17 +#define PAS_DMA_RXINT_CFG(i) (0x204+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_CFG_DHL_M 0x07000000 +#define PAS_DMA_RXINT_CFG_DHL_S 24 +#define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ + PAS_DMA_RXINT_CFG_DHL_M) +#define PAS_DMA_RXINT_CFG_WIF 0x00000002 +#define PAS_DMA_RXINT_CFG_WIL 0x00000001 + #define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE) #define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff #define PAS_DMA_RXINT_INCR_INCR_S 0 From 73344863e426a3c56c7f3ac80fc6f1d4cb10460b Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:12:55 -0500 Subject: [PATCH 1360/2804] pasemi_mac: Fix memcpy amount for short receives Fix up memcpy for short receives. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 46d5c0eef784..0d80b9d48c26 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -506,9 +506,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN); if (new_skb) { skb_reserve(new_skb, NET_IP_ALIGN); - memcpy(new_skb->data - NET_IP_ALIGN, - skb->data - NET_IP_ALIGN, - len + NET_IP_ALIGN); + memcpy(new_skb->data, skb->data, len); /* save the skb in buffer_info as good */ skb = new_skb; } From 26fcfa95aef980cab4ff1ea55979c30e772dd0dd Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:12:59 -0500 Subject: [PATCH 1361/2804] pasemi_mac: RX performance tweaks Various RX performance tweaks, do some explicit prefetching of packet data, etc. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 0d80b9d48c26..f71a6864cdc2 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -471,6 +471,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) rmb(); dp = &RX_DESC(mac, n); + prefetchw(dp); macrx = dp->macrx; if (!(macrx & XCT_MACRX_O)) @@ -492,8 +493,10 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) if (info->dma == dma) break; } + prefetchw(info); skb = info->skb; + prefetchw(skb); info->dma = 0; pci_unmap_single(mac->dma_pdev, dma, skb->len, @@ -516,9 +519,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) skb_put(skb, len); - skb->protocol = eth_type_trans(skb, mac->netdev); - - if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) { + if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) { skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = (macrx & XCT_MACRX_CSUM_M) >> XCT_MACRX_CSUM_S; @@ -528,6 +529,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) mac->stats.rx_bytes += len; mac->stats.rx_packets++; + skb->protocol = eth_type_trans(skb, mac->netdev); netif_receive_skb(skb); dp->ptr = 0; @@ -559,7 +561,7 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) for (i = start; i < mac->tx->next_to_use; i++) { dp = &TX_DESC(mac, i); - if (!dp || (dp->mactx & XCT_MACTX_O)) + if (unlikely(dp->mactx & XCT_MACTX_O)) break; count++; @@ -948,7 +950,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) struct pasemi_mac_txring *txring; struct pasemi_mac_buffer *info; struct pas_dma_xct_descr *dp; - u64 dflags; + u64 dflags, mactx, ptr; dma_addr_t map; int flags; @@ -976,6 +978,9 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) if (dma_mapping_error(map)) return NETDEV_TX_BUSY; + mactx = dflags | XCT_MACTX_LLEN(skb->len); + ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map); + txring = mac->tx; spin_lock_irqsave(&txring->lock, flags); @@ -996,12 +1001,11 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - dp = &TX_DESC(mac, txring->next_to_use); info = &TX_DESC_INFO(mac, txring->next_to_use); - dp->mactx = dflags | XCT_MACTX_LLEN(skb->len); - dp->ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map); + dp->mactx = mactx; + dp->ptr = ptr; info->dma = map; info->skb = skb; From 02df6cfa09c2ccebe685bfd54a708e1f50b00a81 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:13:03 -0500 Subject: [PATCH 1362/2804] pasemi_mac: Batch up TX buffer frees Postpone pci unmap and skb free of the transmitted buffers to outside of the tx ring lock, batching them up 32 at a time. Also increase the count threshold to 128. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index f71a6864cdc2..4836d405cd5d 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -551,37 +551,56 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) int i; struct pasemi_mac_buffer *info; struct pas_dma_xct_descr *dp; - int start, count; + unsigned int start, count, limit; + unsigned int total_count; int flags; + struct sk_buff *skbs[32]; + dma_addr_t dmas[32]; + total_count = 0; +restart: spin_lock_irqsave(&mac->tx->lock, flags); start = mac->tx->next_to_clean; + limit = min(mac->tx->next_to_use, start+32); + count = 0; - for (i = start; i < mac->tx->next_to_use; i++) { + for (i = start; i < limit; i++) { dp = &TX_DESC(mac, i); + if (unlikely(dp->mactx & XCT_MACTX_O)) + /* Not yet transmitted */ break; - count++; - info = &TX_DESC_INFO(mac, i); - - pci_unmap_single(mac->dma_pdev, info->dma, - info->skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(info->skb); + skbs[count] = info->skb; + dmas[count] = info->dma; info->skb = NULL; info->dma = 0; dp->mactx = 0; dp->ptr = 0; + + count++; } mac->tx->next_to_clean += count; spin_unlock_irqrestore(&mac->tx->lock, flags); netif_wake_queue(mac->netdev); - return count; + for (i = 0; i < count; i++) { + pci_unmap_single(mac->dma_pdev, dmas[i], + skbs[i]->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skbs[i]); + } + + total_count += count; + + /* If the batch was full, try to clean more */ + if (count == 32) + goto restart; + + return total_count; } @@ -777,7 +796,7 @@ static int pasemi_mac_open(struct net_device *dev) PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), - PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); + PAS_IOB_DMA_TXCH_CFG_CNTTH(128)); /* Clear out any residual packet count state from firmware */ pasemi_mac_restart_rx_intr(mac); From 021fa22e01d3d0425d3d15df48f523b69a3a11c4 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:13:11 -0500 Subject: [PATCH 1363/2804] pasemi_mac: Fix TX ring wrap checking The old logic didn't detect full (tx) ring cases properly, causing overruns and general badness. Clean it up a bit and abstract out the ring size checks, always making sure to leave 1 slot open. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 25 ++++++++++++++----------- drivers/net/pasemi_mac.h | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 4836d405cd5d..dc710a0826b2 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -69,6 +69,10 @@ #define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)]) #define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)]) +#define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ + & ((ring)->size - 1)) +#define RING_AVAIL(ring) ((ring->size) - RING_USED(ring)) + #define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ MODULE_LICENSE("GPL"); @@ -174,6 +178,7 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) spin_lock_init(&ring->lock); + ring->size = RX_RING_SIZE; ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * RX_RING_SIZE, GFP_KERNEL); @@ -253,6 +258,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) spin_lock_init(&ring->lock); + ring->size = TX_RING_SIZE; ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * TX_RING_SIZE, GFP_KERNEL); if (!ring->desc_info) @@ -281,7 +287,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) PAS_DMA_TXCHAN_CFG_UP | PAS_DMA_TXCHAN_CFG_WT(2)); - ring->next_to_use = 0; + ring->next_to_fill = 0; ring->next_to_clean = 0; snprintf(ring->irq_name, sizeof(ring->irq_name), @@ -376,9 +382,7 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) int start = mac->rx->next_to_fill; unsigned int limit, count; - limit = (mac->rx->next_to_clean + RX_RING_SIZE - - mac->rx->next_to_fill) & (RX_RING_SIZE - 1); - + limit = RING_AVAIL(mac->rx); /* Check to see if we're doing first-time setup */ if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) limit = RX_RING_SIZE; @@ -562,7 +566,7 @@ restart: spin_lock_irqsave(&mac->tx->lock, flags); start = mac->tx->next_to_clean; - limit = min(mac->tx->next_to_use, start+32); + limit = min(mac->tx->next_to_fill, start+32); count = 0; @@ -1004,14 +1008,13 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&txring->lock, flags); - if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) { + if (RING_AVAIL(txring) <= 1) { spin_unlock_irqrestore(&txring->lock, flags); pasemi_mac_clean_tx(mac); pasemi_mac_restart_tx_intr(mac); spin_lock_irqsave(&txring->lock, flags); - if (txring->next_to_clean - txring->next_to_use == - TX_RING_SIZE) { + if (RING_AVAIL(txring) <= 1) { /* Still no room -- stop the queue and wait for tx * intr when there's room. */ @@ -1020,15 +1023,15 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - dp = &TX_DESC(mac, txring->next_to_use); - info = &TX_DESC_INFO(mac, txring->next_to_use); + dp = &TX_DESC(mac, txring->next_to_fill); + info = &TX_DESC_INFO(mac, txring->next_to_fill); dp->mactx = mactx; dp->ptr = ptr; info->dma = map; info->skb = skb; - txring->next_to_use++; + txring->next_to_fill++; mac->stats.tx_packets++; mac->stats.tx_bytes += skb->len; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index fbbc17a31db7..c5b0adbc182e 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -31,7 +31,7 @@ struct pasemi_mac_txring { struct pas_dma_xct_descr *desc; dma_addr_t dma; unsigned int size; - unsigned int next_to_use; + unsigned int next_to_fill; unsigned int next_to_clean; struct pasemi_mac_buffer *desc_info; char irq_name[10]; /* "eth%d tx" */ From 38bf3184e8c4b8cd4285a24b6f69a300b32f0062 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:13:24 -0500 Subject: [PATCH 1364/2804] pasemi_mac: Fix RX checksum flags RX side flag to use is CHECKSUM_UNNECESSARY, not CHECKSUM_COMPLETE. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index dc710a0826b2..0bfdd79de6cf 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -524,7 +524,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) skb_put(skb, len); if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) { - skb->ip_summed = CHECKSUM_COMPLETE; + skb->ip_summed = CHECKSUM_UNNECESSARY; skb->csum = (macrx & XCT_MACRX_CSUM_M) >> XCT_MACRX_CSUM_S; } else From 6fba848a9a4bbe03f61b22bf0e4063d7ed4c561a Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 15 Sep 2007 13:51:11 -0700 Subject: [PATCH 1365/2804] pasemi_mac: Enable LLTX Enable LLTX on pasemi_mac: we're already doing sufficient locking in the driver to enable it. [ Resolved merge conflicts with napi_struct changes... -DaveM ] Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 0bfdd79de6cf..916a76e28a87 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1186,7 +1186,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); - dev->features = NETIF_F_HW_CSUM; + dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX; /* These should come out of the device tree eventually */ mac->dma_txch = index; From 829185e97fba67ededd3eb025147bafcc0ca7557 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 15 Sep 2007 13:53:19 -0700 Subject: [PATCH 1366/2804] pasemi_mac: Clean TX ring in poll Unfortunately there's no timeout for how long a packet can sit on the TX ring after completion before an interrupt is generated, and we want to have a threshold that's larger than one packet per interrupt. So we have to have a timer that occasionally cleans the TX ring even though there hasn't been an interrupt. Instead of setting up a dedicated timer for this, just clean it in the NAPI poll routine instead. [ Resolved conflicts with napi_struct changes... -DaveM ] Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 916a76e28a87..48c117038fef 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1078,6 +1078,7 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) struct net_device *dev = mac->netdev; int pkts; + pasemi_mac_clean_tx(mac); pkts = pasemi_mac_clean_rx(mac, budget); if (pkts < budget) { /* all done, no more packets present */ From 173261ed37e7a98cedfcc808eb07eeceee66e078 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 31 Aug 2007 22:22:32 +0900 Subject: [PATCH 1367/2804] PS3: changed the way to handle tx skbs The PS3 virtual network device requires a vlan tag in the sending packet to select the destination device, ethernet port or wireless. As the vlan tag field is in the middle of the passed data, we should insert it into the packet data. To avoid copying much of the packet data, the driver used two tx descriptors for one tx skb; one descriptor was for sending a small static buffer which contained vlan tag and copied header (two mac addresses), one was for the residual data after the vlan field. This patch changes the way to insert the vlan tag. By changing netdev->hard_header_len, we can make the headroom for moving mac address fields in the skb buffer. Then we can send one tx skb with one tx descriptor. This also gives us a tx throughut gain of approx. 20% according to netperf results. Signed-off-by: Masakazu Mokuno CC: Geoff Levand Signed-off-by: Jeff Garzik --- drivers/net/ps3_gelic_net.c | 140 ++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 77 deletions(-) diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 92561c0450bc..31c3092e66af 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -351,19 +351,13 @@ static int gelic_net_alloc_rx_skbs(struct gelic_net_card *card) static void gelic_net_release_tx_descr(struct gelic_net_card *card, struct gelic_net_descr *descr) { - struct sk_buff *skb; + struct sk_buff *skb = descr->skb; + BUG_ON(!(descr->data_status & (1 << GELIC_NET_TXDESC_TAIL))); - if (descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)) { - /* 2nd descriptor */ - skb = descr->skb; - dma_unmap_single(ctodev(card), descr->buf_addr, skb->len, - DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - } else { - dma_unmap_single(ctodev(card), descr->buf_addr, - descr->buf_size, DMA_TO_DEVICE); - } + dma_unmap_single(ctodev(card), descr->buf_addr, skb->len, + DMA_TO_DEVICE); + dev_kfree_skb_any(skb); descr->buf_addr = 0; descr->buf_size = 0; @@ -426,7 +420,7 @@ static void gelic_net_release_tx_chain(struct gelic_net_card *card, int stop) release ++; } out: - if (!stop && (2 < release)) + if (!stop && release) netif_wake_queue(card->netdev); } @@ -593,13 +587,10 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card) { if (!card->tx_chain.head) return NULL; - /* see if we can two consecutive free descrs */ + /* see if the next descriptor is free */ if (card->tx_chain.tail != card->tx_chain.head->next && gelic_net_get_descr_status(card->tx_chain.head) == - GELIC_NET_DESCR_NOT_IN_USE && - card->tx_chain.tail != card->tx_chain.head->next->next && - gelic_net_get_descr_status(card->tx_chain.head->next) == - GELIC_NET_DESCR_NOT_IN_USE ) + GELIC_NET_DESCR_NOT_IN_USE) return card->tx_chain.head; else return NULL; @@ -610,44 +601,66 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card) * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field * @descr: descriptor structure to fill out * @skb: packet to consider - * @middle: middle of frame * * fills out the command and status field of the descriptor structure, * depending on hardware checksum settings. This function assumes a wmb() * has executed before. */ static void gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr, - struct sk_buff *skb, int middle) + struct sk_buff *skb) { - u32 eofr; - - if (middle) - eofr = 0; - else - eofr = GELIC_NET_DMAC_CMDSTAT_END_FRAME; - if (skb->ip_summed != CHECKSUM_PARTIAL) - descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | eofr; + descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | + GELIC_NET_DMAC_CMDSTAT_END_FRAME; else { /* is packet ip? * if yes: tcp? udp? */ if (skb->protocol == htons(ETH_P_IP)) { if (ip_hdr(skb)->protocol == IPPROTO_TCP) descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_TCPCS | eofr; + GELIC_NET_DMAC_CMDSTAT_TCPCS | + GELIC_NET_DMAC_CMDSTAT_END_FRAME; + else if (ip_hdr(skb)->protocol == IPPROTO_UDP) descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_UDPCS | eofr; + GELIC_NET_DMAC_CMDSTAT_UDPCS | + GELIC_NET_DMAC_CMDSTAT_END_FRAME; else /* * the stack should checksum non-tcp and non-udp * packets on his own: NETIF_F_IP_CSUM */ descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_NOCS | eofr; + GELIC_NET_DMAC_CMDSTAT_NOCS | + GELIC_NET_DMAC_CMDSTAT_END_FRAME; } } } +static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb, + unsigned short tag) +{ + struct vlan_ethhdr *veth; + static unsigned int c; + + if (skb_headroom(skb) < VLAN_HLEN) { + struct sk_buff *sk_tmp = skb; + pr_debug("%s: hd=%d c=%ud\n", __func__, skb_headroom(skb), c); + skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); + if (!skb) + return NULL; + dev_kfree_skb_any(sk_tmp); + } + veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); + + /* Move the mac addresses to the top of buffer */ + memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN); + + veth->h_vlan_proto = __constant_htons(ETH_P_8021Q); + veth->h_vlan_TCI = htons(tag); + + return skb; +} + /** * gelic_net_prepare_tx_descr_v - get dma address of skb_data * @card: card structure @@ -661,65 +674,35 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card, struct gelic_net_descr *descr, struct sk_buff *skb) { - dma_addr_t buf[2]; - unsigned int vlan_len; - struct gelic_net_descr *sec_descr = descr->next; + dma_addr_t buf; - if (skb->len < GELIC_NET_VLAN_POS) - return -EINVAL; - - vlan_len = GELIC_NET_VLAN_POS; - memcpy(&descr->vlan, skb->data, vlan_len); if (card->vlan_index != -1) { - /* internal vlan tag used */ - descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/ - descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]); - vlan_len += VLAN_HLEN; /* added for above two lines */ + struct sk_buff *skb_tmp; + skb_tmp = gelic_put_vlan_tag(skb, + card->vlan_id[card->vlan_index]); + if (!skb_tmp) + return -ENOMEM; + skb = skb_tmp; } - /* map data area */ - buf[0] = dma_map_single(ctodev(card), &descr->vlan, - vlan_len, DMA_TO_DEVICE); + buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE); - if (!buf[0]) { - dev_err(ctodev(card), - "dma map 1 failed (%p, %i). Dropping packet\n", - skb->data, vlan_len); - return -ENOMEM; - } - - buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS, - skb->len - GELIC_NET_VLAN_POS, - DMA_TO_DEVICE); - - if (!buf[1]) { + if (!buf) { dev_err(ctodev(card), "dma map 2 failed (%p, %i). Dropping packet\n", - skb->data + GELIC_NET_VLAN_POS, - skb->len - GELIC_NET_VLAN_POS); - dma_unmap_single(ctodev(card), buf[0], vlan_len, - DMA_TO_DEVICE); + skb->data, skb->len); return -ENOMEM; } - /* first descr */ - descr->buf_addr = buf[0]; - descr->buf_size = vlan_len; - descr->skb = NULL; /* not used */ + descr->buf_addr = buf; + descr->buf_size = skb->len; + descr->skb = skb; descr->data_status = 0; - descr->next_descr_addr = descr->next->bus_addr; - gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */ - - /* second descr */ - sec_descr->buf_addr = buf[1]; - sec_descr->buf_size = skb->len - GELIC_NET_VLAN_POS; - sec_descr->skb = skb; - sec_descr->data_status = 0; - sec_descr->next_descr_addr = 0; /* terminate hw descr */ - gelic_net_set_txdescr_cmdstat(sec_descr, skb, 0); + descr->next_descr_addr = 0; /* terminate hw descr */ + gelic_net_set_txdescr_cmdstat(descr, skb); /* bump free descriptor pointer */ - card->tx_chain.head = sec_descr->next; + card->tx_chain.head = descr->next; return 0; } @@ -1425,8 +1408,11 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) dev_dbg(ctodev(card), "vlan_id:%d, %lx\n", i, v1); } } - if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) + + if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) { card->vlan_index = GELIC_NET_VLAN_WIRED - 1; + netdev->hard_header_len += VLAN_HLEN; + } status = register_netdev(netdev); if (status) { From dc029ad97f267cbd1c2e978a443eb5ae93a55328 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 31 Aug 2007 22:25:09 +0900 Subject: [PATCH 1368/2804] PS3: Remove the workaround no longer needed Removed the workaround that was needed for PS3 firmware versions prior to the first release. Signed-off-by: Masakazu Mokuno CC: Geoff Levand Signed-off-by: Jeff Garzik --- drivers/net/ps3_gelic_net.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 31c3092e66af..93c2c39a4a49 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -716,25 +716,17 @@ static int gelic_net_kick_txdma(struct gelic_net_card *card, struct gelic_net_descr *descr) { int status = 0; - int count = 10; if (card->tx_dma_progress) return 0; if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) { card->tx_dma_progress = 1; - /* sometimes we need retry here */ - while (count--) { - status = lv1_net_start_tx_dma(bus_id(card), - dev_id(card), - descr->bus_addr, 0); - if (!status) - break; - } - if (!count) + status = lv1_net_start_tx_dma(bus_id(card), dev_id(card), + descr->bus_addr, 0); + if (status) dev_info(ctodev(card), "lv1_net_start_txdma failed," \ - "status=%d %#lx\n", - status, card->irq_status); + "status=%d\n", status); } return status; } From 9a799d71034c4e2b168740c8a8530591011313d5 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Sat, 15 Sep 2007 14:07:45 -0700 Subject: [PATCH 1369/2804] ixgbe: driver for Intel(R) 82598 PCI-Express 10GbE adapters (v4) This patch adds support for the Intel 82598 PCI-Express 10GbE chipset. Devices will be available on the market soon. This version of the driver is largely the same as the last release: * Driver uses a single RX and single TX queue, each using 1 MSI-X irq vector. * Driver runs in NAPI mode only * Driver is largely multiqueue-ready (TM) Changes since 20070803: * removed wrappers for hardware functions * incorporated e1000e-style HW api reorganization code * sparse/checkpatch cleanups, namespace cleanups * driver prints out extra debugging information at load time identifying adapter board number, mac, phy types * removed ixgbe_api.c, ixgbe_api.h, ixgbe_osdep.h * driver update to 1.1.18 * removed ixgbe.txt which contained no useful info anymore [ Integrated napi_struct changes from Auke as well... -DaveM ] Signed-off-by: Auke Kok Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- MAINTAINERS | 10 +- drivers/net/Kconfig | 27 +- drivers/net/Makefile | 1 + drivers/net/ixgbe/Makefile | 36 + drivers/net/ixgbe/ixgbe.h | 259 +++ drivers/net/ixgbe/ixgbe_82598.c | 589 ++++++ drivers/net/ixgbe/ixgbe_common.c | 1175 ++++++++++++ drivers/net/ixgbe/ixgbe_common.h | 86 + drivers/net/ixgbe/ixgbe_ethtool.c | 943 ++++++++++ drivers/net/ixgbe/ixgbe_main.c | 2873 +++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_phy.c | 494 +++++ drivers/net/ixgbe/ixgbe_phy.h | 50 + drivers/net/ixgbe/ixgbe_type.h | 1332 +++++++++++++ 13 files changed, 7867 insertions(+), 8 deletions(-) create mode 100644 drivers/net/ixgbe/Makefile create mode 100644 drivers/net/ixgbe/ixgbe.h create mode 100644 drivers/net/ixgbe/ixgbe_82598.c create mode 100644 drivers/net/ixgbe/ixgbe_common.c create mode 100644 drivers/net/ixgbe/ixgbe_common.h create mode 100644 drivers/net/ixgbe/ixgbe_ethtool.c create mode 100644 drivers/net/ixgbe/ixgbe_main.c create mode 100644 drivers/net/ixgbe/ixgbe_phy.c create mode 100644 drivers/net/ixgbe/ixgbe_phy.h create mode 100644 drivers/net/ixgbe/ixgbe_type.h diff --git a/MAINTAINERS b/MAINTAINERS index e0861f7e1ccf..c35eb125e1ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2030,16 +2030,14 @@ W: http://sourceforge.net/projects/e1000/ S: Supported INTEL PRO/10GbE SUPPORT -P: Jeff Kirsher -M: jeffrey.t.kirsher@intel.com P: Ayyappan Veeraiyan M: ayyappan.veeraiyan@intel.com -P: John Ronciak -M: john.ronciak@intel.com -P: Jesse Brandeburg -M: jesse.brandeburg@intel.com P: Auke Kok M: auke-jan.h.kok@intel.com +P: Jesse Brandeburg +M: jesse.brandeburg@intel.com +P: John Ronciak +M: john.ronciak@intel.com L: e1000-devel@lists.sourceforge.net W: http://sourceforge.net/projects/e1000/ S: Supported diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index eeac2f49aae3..76db0bc9452d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2518,12 +2518,35 @@ config EHEA To compile the driver as a module, choose M here. The module will be called ehea. +config IXGBE + tristate "Intel(R) 10GbE PCI Express adapters support" + depends on PCI + ---help--- + This driver supports Intel(R) 10GbE PCI Express family of + adapters. For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here and read + . The module + will be called ixgbe. + config IXGB tristate "Intel(R) PRO/10GbE support" depends on PCI ---help--- - This driver supports Intel(R) PRO/10GbE family of - adapters. For more information on how to identify your adapter, go + This driver supports Intel(R) PRO/10GbE family of adapters for + PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver + instead. For more information on how to identify your adapter, go to the Adapter & Driver ID Guide at: diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 0d2b4bee587c..c23ffdbe2599 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ +obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile new file mode 100644 index 000000000000..ccd83d9f579e --- /dev/null +++ b/drivers/net/ixgbe/Makefile @@ -0,0 +1,36 @@ +################################################################################ +# +# Intel 10 Gigabit PCI Express Linux driver +# Copyright(c) 1999 - 2007 Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full GNU General Public License is included in this distribution in +# the file called "COPYING". +# +# Contact Information: +# Linux NICS +# e1000-devel Mailing List +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +# +################################################################################ + +# +# Makefile for the Intel(R) 10GbE PCI Express ethernet driver +# + +obj-$(CONFIG_IXGBE) += ixgbe.o + +ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ + ixgbe_82598.o ixgbe_phy.o diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h new file mode 100644 index 000000000000..c160a7d91e21 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe.h @@ -0,0 +1,259 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_H_ +#define _IXGBE_H_ + +#include +#include +#include + +#include "ixgbe_type.h" +#include "ixgbe_common.h" + + +#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args) + +#define PFX "ixgbe: " +#define DPRINTK(nlevel, klevel, fmt, args...) \ + ((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \ + printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \ + __FUNCTION__ , ## args))) + +/* TX/RX descriptor defines */ +#define IXGBE_DEFAULT_TXD 1024 +#define IXGBE_MAX_TXD 4096 +#define IXGBE_MIN_TXD 64 + +#define IXGBE_DEFAULT_RXD 1024 +#define IXGBE_MAX_RXD 4096 +#define IXGBE_MIN_RXD 64 + +#define IXGBE_DEFAULT_RXQ 1 +#define IXGBE_MAX_RXQ 1 +#define IXGBE_MIN_RXQ 1 + +#define IXGBE_DEFAULT_ITR_RX_USECS 125 /* 8k irqs/sec */ +#define IXGBE_DEFAULT_ITR_TX_USECS 250 /* 4k irqs/sec */ +#define IXGBE_MIN_ITR_USECS 100 /* 500k irqs/sec */ +#define IXGBE_MAX_ITR_USECS 10000 /* 100 irqs/sec */ + +/* flow control */ +#define IXGBE_DEFAULT_FCRTL 0x10000 +#define IXGBE_MIN_FCRTL 0 +#define IXGBE_MAX_FCRTL 0x7FF80 +#define IXGBE_DEFAULT_FCRTH 0x20000 +#define IXGBE_MIN_FCRTH 0 +#define IXGBE_MAX_FCRTH 0x7FFF0 +#define IXGBE_DEFAULT_FCPAUSE 0x6800 /* may be too long */ +#define IXGBE_MIN_FCPAUSE 0 +#define IXGBE_MAX_FCPAUSE 0xFFFF + +/* Supported Rx Buffer Sizes */ +#define IXGBE_RXBUFFER_64 64 /* Used for packet split */ +#define IXGBE_RXBUFFER_128 128 /* Used for packet split */ +#define IXGBE_RXBUFFER_256 256 /* Used for packet split */ +#define IXGBE_RXBUFFER_2048 2048 + +#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256 + +#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) + +/* How many Tx Descriptors do we need to call netif_wake_queue? */ +#define IXGBE_TX_QUEUE_WAKE 16 + +/* How many Rx Buffers do we bundle into one write to the hardware ? */ +#define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +#define IXGBE_TX_FLAGS_CSUM (u32)(1) +#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1) +#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) +#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) +#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 +#define IXGBE_TX_FLAGS_VLAN_SHIFT 16 + +/* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer */ +struct ixgbe_tx_buffer { + struct sk_buff *skb; + dma_addr_t dma; + unsigned long time_stamp; + u16 length; + u16 next_to_watch; +}; + +struct ixgbe_rx_buffer { + struct sk_buff *skb; + dma_addr_t dma; + struct page *page; + dma_addr_t page_dma; +}; + +struct ixgbe_queue_stats { + u64 packets; + u64 bytes; +}; + +struct ixgbe_ring { + struct ixgbe_adapter *adapter; /* backlink */ + void *desc; /* descriptor ring memory */ + dma_addr_t dma; /* phys. address of descriptor ring */ + unsigned int size; /* length in bytes */ + unsigned int count; /* amount of descriptors */ + unsigned int next_to_use; + unsigned int next_to_clean; + + union { + struct ixgbe_tx_buffer *tx_buffer_info; + struct ixgbe_rx_buffer *rx_buffer_info; + }; + + u16 head; + u16 tail; + + /* To protect race between sender and clean_tx_irq */ + spinlock_t tx_lock; + + struct ixgbe_queue_stats stats; + + u32 eims_value; + u16 itr_register; + + char name[IFNAMSIZ + 5]; + u16 work_limit; /* max work per interrupt */ +}; + +/* Helper macros to switch between ints/sec and what the register uses. + * And yes, it's the same math going both ways. + */ +#define EITR_INTS_PER_SEC_TO_REG(_eitr) \ + ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 0) +#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG + +#define IXGBE_DESC_UNUSED(R) \ + ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ + (R)->next_to_clean - (R)->next_to_use - 1) + +#define IXGBE_RX_DESC_ADV(R, i) \ + (&(((union ixgbe_adv_rx_desc *)((R).desc))[i])) +#define IXGBE_TX_DESC_ADV(R, i) \ + (&(((union ixgbe_adv_tx_desc *)((R).desc))[i])) +#define IXGBE_TX_CTXTDESC_ADV(R, i) \ + (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) + +#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 + +/* board specific private data structure */ +struct ixgbe_adapter { + struct timer_list watchdog_timer; + struct vlan_group *vlgrp; + u16 bd_number; + u16 rx_buf_len; + atomic_t irq_sem; + struct work_struct reset_task; + + /* TX */ + struct ixgbe_ring *tx_ring; /* One per active queue */ + struct napi_struct napi; + u64 restart_queue; + u64 lsc_int; + u64 hw_tso_ctxt; + u64 hw_tso6_ctxt; + u32 tx_timeout_count; + bool detect_tx_hung; + + /* RX */ + struct ixgbe_ring *rx_ring; /* One per active queue */ + u64 hw_csum_tx_good; + u64 hw_csum_rx_error; + u64 hw_csum_rx_good; + u64 non_eop_descs; + int num_tx_queues; + int num_rx_queues; + struct msix_entry *msix_entries; + + u64 rx_hdr_split; + u32 alloc_rx_page_failed; + u32 alloc_rx_buff_failed; + + u32 flags; +#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) +#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 1) +#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 2) +#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3) +#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4) + + /* Interrupt Throttle Rate */ + u32 rx_eitr; + u32 tx_eitr; + + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + + /* structs defined in ixgbe_hw.h */ + struct ixgbe_hw hw; + u16 msg_enable; + struct ixgbe_hw_stats stats; + char lsc_name[IFNAMSIZ + 5]; + + unsigned long state; + u64 tx_busy; +}; + +enum ixbge_state_t { + __IXGBE_TESTING, + __IXGBE_RESETTING, + __IXGBE_DOWN +}; + +enum ixgbe_boards { + board_82598AF, + board_82598EB, + board_82598AT, +}; + +extern struct ixgbe_info ixgbe_82598AF_info; +extern struct ixgbe_info ixgbe_82598EB_info; +extern struct ixgbe_info ixgbe_82598AT_info; + +extern char ixgbe_driver_name[]; +extern char ixgbe_driver_version[]; + +extern int ixgbe_up(struct ixgbe_adapter *adapter); +extern void ixgbe_down(struct ixgbe_adapter *adapter); +extern void ixgbe_reset(struct ixgbe_adapter *adapter); +extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); +extern void ixgbe_set_ethtool_ops(struct net_device *netdev); +extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rxdr); +extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *txdr); + +#endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c new file mode 100644 index 000000000000..00ee20125ca9 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -0,0 +1,589 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include + +#include "ixgbe_type.h" +#include "ixgbe_common.h" +#include "ixgbe_phy.h" + +#define IXGBE_82598_MAX_TX_QUEUES 32 +#define IXGBE_82598_MAX_RX_QUEUES 64 +#define IXGBE_82598_RAR_ENTRIES 16 + +static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw); +static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, + bool *autoneg); +static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, + u32 *speed, bool *autoneg); +static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw); +static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw); +static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, + bool *link_up); +static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed, + bool autoneg, + bool autoneg_wait_to_complete); +static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw); +static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed, + bool *link_up); +static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, + bool autoneg, + bool autoneg_wait_to_complete); +static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw); + + +static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) +{ + hw->mac.num_rx_queues = IXGBE_82598_MAX_TX_QUEUES; + hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES; + hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES; + + return 0; +} + +/** + * ixgbe_get_link_settings_82598 - Determines default link settings + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + * + * Determines the default link settings by reading the AUTOC register. + **/ +static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, + bool *autoneg) +{ + s32 status = 0; + s32 autoc_reg; + + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + if (hw->mac.link_settings_loaded) { + autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE; + autoc_reg &= ~IXGBE_AUTOC_LMS_MASK; + autoc_reg |= hw->mac.link_attach_type; + autoc_reg |= hw->mac.link_mode_select; + } + + switch (autoc_reg & IXGBE_AUTOC_LMS_MASK) { + case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: + *speed = IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = false; + break; + + case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: + *speed = IXGBE_LINK_SPEED_10GB_FULL; + *autoneg = false; + break; + + case IXGBE_AUTOC_LMS_1G_AN: + *speed = IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = true; + break; + + case IXGBE_AUTOC_LMS_KX4_AN: + case IXGBE_AUTOC_LMS_KX4_AN_1G_AN: + *speed = IXGBE_LINK_SPEED_UNKNOWN; + if (autoc_reg & IXGBE_AUTOC_KX4_SUPP) + *speed |= IXGBE_LINK_SPEED_10GB_FULL; + if (autoc_reg & IXGBE_AUTOC_KX_SUPP) + *speed |= IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = true; + break; + + default: + status = IXGBE_ERR_LINK_SETUP; + break; + } + + return status; +} + +/** + * ixgbe_get_copper_link_settings_82598 - Determines default link settings + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + * + * Determines the default link settings by reading the AUTOC register. + **/ +static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, + u32 *speed, bool *autoneg) +{ + s32 status = IXGBE_ERR_LINK_SETUP; + u16 speed_ability; + + *speed = 0; + *autoneg = true; + + status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &speed_ability); + + if (status == 0) { + if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) + *speed |= IXGBE_LINK_SPEED_10GB_FULL; + if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) + *speed |= IXGBE_LINK_SPEED_1GB_FULL; + } + + return status; +} + +/** + * ixgbe_get_media_type_82598 - Determines media type + * @hw: pointer to hardware structure + * + * Returns the media type (fiber, copper, backplane) + **/ +static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) +{ + enum ixgbe_media_type media_type; + + /* Media type for I82598 is based on device ID */ + switch (hw->device_id) { + case IXGBE_DEV_ID_82598AF_DUAL_PORT: + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598EB_CX4: + media_type = ixgbe_media_type_fiber; + break; + case IXGBE_DEV_ID_82598AT_DUAL_PORT: + media_type = ixgbe_media_type_copper; + break; + default: + media_type = ixgbe_media_type_unknown; + break; + } + + return media_type; +} + +/** + * ixgbe_setup_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) +{ + u32 autoc_reg; + u32 links_reg; + u32 i; + s32 status = 0; + + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + if (hw->mac.link_settings_loaded) { + autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE; + autoc_reg &= ~IXGBE_AUTOC_LMS_MASK; + autoc_reg |= hw->mac.link_attach_type; + autoc_reg |= hw->mac.link_mode_select; + + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + msleep(50); + } + + /* Restart link */ + autoc_reg |= IXGBE_AUTOC_AN_RESTART; + 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 (hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN || + hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) { + links_reg = 0; /* Just in case Autoneg time = 0 */ + for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) { + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + if (links_reg & IXGBE_LINKS_KX_AN_COMP) + break; + msleep(100); + } + if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) { + status = IXGBE_ERR_AUTONEG_NOT_COMPLETE; + hw_dbg(hw, + "Autonegotiation did not complete.\n"); + } + } + } + + /* + * 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.type = hw->fc.original_type; + ixgbe_setup_fc(hw, 0); + + /* Add delay to filter out noises during initial link setup */ + msleep(50); + + return status; +} + +/** + * ixgbe_check_mac_link_82598 - Get link/speed status + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: true is link is up, false otherwise + * + * Reads the links register to determine if link is up and the current speed + **/ +static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, + bool *link_up) +{ + u32 links_reg; + + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + + if (links_reg & IXGBE_LINKS_UP) + *link_up = true; + else + *link_up = false; + + if (links_reg & IXGBE_LINKS_SPEED) + *speed = IXGBE_LINK_SPEED_10GB_FULL; + else + *speed = IXGBE_LINK_SPEED_1GB_FULL; + + return 0; +} + +/** + * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: true if auto-negotiation enabled + * @autoneg_wait_to_complete: true if waiting is needed to complete + * + * Set the link speed in the AUTOC register and restarts link. + **/ +static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, + u32 speed, bool autoneg, + bool autoneg_wait_to_complete) +{ + s32 status = 0; + + /* If speed is 10G, then check for CX4 or XAUI. */ + if ((speed == IXGBE_LINK_SPEED_10GB_FULL) && + (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; + else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN; + else if (autoneg) { + /* BX mode - Autonegotiate 1G */ + if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD)) + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN; + else /* KX/KX4 mode */ + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN_1G_AN; + } else { + status = IXGBE_ERR_LINK_SETUP; + } + + if (status == 0) { + hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete; + + hw->mac.link_settings_loaded = true; + /* + * 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 + */ + hw->phy.ops.setup(hw); + } + + return status; +} + + +/** + * 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; + u32 speed = 0; + bool link_up = false; + + /* Set up MAC */ + hw->phy.ops.setup(hw); + + /* Restart autonegotiation on PHY */ + status = hw->phy.ops.setup(hw); + + /* Synchronize MAC to PHY speed */ + if (status == 0) + status = hw->phy.ops.check(hw, &speed, &link_up); + + return status; +} + +/** + * ixgbe_check_copper_link_82598 - Syncs MAC & PHY link settings + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: true if link is up, false otherwise + * + * Reads the mac link, phy link, and synchronizes the MAC to PHY. + **/ +static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed, + bool *link_up) +{ + s32 status; + u32 phy_speed = 0; + bool phy_link = false; + + /* This is the speed and link the MAC is set at */ + hw->phy.ops.check(hw, speed, link_up); + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + status = hw->phy.ops.check(hw, &phy_speed, &phy_link); + + if ((status == 0) && (phy_link)) { + /* + * Check current link status of the MACs link's register + * matches that of the speed in the PHY register + */ + if (*speed != phy_speed) { + /* + * The copper PHY requires 82598 attach type to be XAUI + * for 10G and BX for 1G + */ + hw->mac.link_attach_type = + (IXGBE_AUTOC_10G_XAUI | IXGBE_AUTOC_1G_BX); + + /* Synchronize the MAC speed to the PHY speed */ + status = hw->phy.ops.setup_speed(hw, phy_speed, false, + false); + if (status == 0) + hw->phy.ops.check(hw, speed, link_up); + else + status = IXGBE_ERR_LINK_SETUP; + } + } else { + *link_up = phy_link; + } + + return status; +} + +/** + * ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: true if autonegotiation enabled + * @autoneg_wait_to_complete: true if waiting is needed to complete + * + * 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, u32 speed, + bool autoneg, + bool autoneg_wait_to_complete) +{ + s32 status; + bool link_up = 0; + + /* Setup the PHY according to input speed */ + status = hw->phy.ops.setup_speed(hw, speed, autoneg, + autoneg_wait_to_complete); + + /* Synchronize MAC to PHY speed */ + if (status == 0) + status = hw->phy.ops.check(hw, &speed, &link_up); + + return status; +} + +/** + * ixgbe_reset_hw_82598 - Performs hardware reset + * @hw: pointer to hardware structure + * + * Resets the hardware by reseting the transmit and receive units, masks and + * clears all interrupts, performing a PHY reset, and performing a link (MAC) + * reset. + **/ +static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) +{ + s32 status = 0; + u32 ctrl; + u32 gheccr; + u32 i; + u32 autoc; + u8 analog_val; + + /* Call adapter stop to disable tx/rx and clear interrupts */ + ixgbe_stop_adapter(hw); + + /* + * Power up the Atlas TX lanes if they are currently powered down. + * Atlas TX lanes are powered down for MAC loopback tests, but + * they are not automatically restored on reset. + */ + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); + if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) { + /* Enable TX Atlas so packets can be transmitted again */ + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN; + ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val); + + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL; + ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val); + + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL; + ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val); + + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL; + ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val); + } + + /* Reset PHY */ + ixgbe_reset_phy(hw); + + /* + * Prevent the PCI-E bus from from hanging by disabling PCI-E master + * access and verify no pending requests before reset + */ + if (ixgbe_disable_pcie_master(hw) != 0) { + status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + } + + /* + * Issue global reset to the MAC. This needs to be a SW reset. + * If link reset is used, it might reset the MAC when mng is using it + */ + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST)); + IXGBE_WRITE_FLUSH(hw); + + /* Poll for reset bit to self-clear indicating reset is complete */ + for (i = 0; i < 10; i++) { + udelay(1); + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + if (!(ctrl & IXGBE_CTRL_RST)) + break; + } + if (ctrl & IXGBE_CTRL_RST) { + status = IXGBE_ERR_RESET_FAILED; + hw_dbg(hw, "Reset polling failed to complete.\n"); + } + + msleep(50); + + gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR); + gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6)); + IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr); + + /* + * AUTOC register which stores link settings gets cleared + * and reloaded from EEPROM after reset. We need to restore + * our stored value from init in case SW changed the attach + * type or speed. If this is the first time and link settings + * have not been stored, store default settings from AUTOC. + */ + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + if (hw->mac.link_settings_loaded) { + autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE); + autoc &= ~(IXGBE_AUTOC_LMS_MASK); + autoc |= hw->mac.link_attach_type; + autoc |= hw->mac.link_mode_select; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); + } else { + hw->mac.link_attach_type = + (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE); + hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK); + hw->mac.link_settings_loaded = true; + } + + /* Store the permanent mac address */ + ixgbe_get_mac_addr(hw, hw->mac.perm_addr); + + return status; +} + +static struct ixgbe_mac_operations mac_ops_82598 = { + .reset = &ixgbe_reset_hw_82598, + .get_media_type = &ixgbe_get_media_type_82598, +}; + +static struct ixgbe_phy_operations phy_ops_82598EB = { + .setup = &ixgbe_setup_copper_link_82598, + .check = &ixgbe_check_copper_link_82598, + .setup_speed = &ixgbe_setup_copper_link_speed_82598, + .get_settings = &ixgbe_get_copper_link_settings_82598, +}; + +struct ixgbe_info ixgbe_82598EB_info = { + .mac = ixgbe_mac_82598EB, + .get_invariants = &ixgbe_get_invariants_82598, + .mac_ops = &mac_ops_82598, + .phy_ops = &phy_ops_82598EB, +}; + +static struct ixgbe_phy_operations phy_ops_82598AT = { + .setup = &ixgbe_setup_tnx_phy_link, + .check = &ixgbe_check_tnx_phy_link, + .setup_speed = &ixgbe_setup_tnx_phy_link_speed, + .get_settings = &ixgbe_get_copper_link_settings_82598, +}; + +struct ixgbe_info ixgbe_82598AT_info = { + .mac = ixgbe_mac_82598EB, + .get_invariants = &ixgbe_get_invariants_82598, + .mac_ops = &mac_ops_82598, + .phy_ops = &phy_ops_82598AT, +}; + +static struct ixgbe_phy_operations phy_ops_82598AF = { + .setup = &ixgbe_setup_mac_link_82598, + .check = &ixgbe_check_mac_link_82598, + .setup_speed = &ixgbe_setup_mac_link_speed_82598, + .get_settings = &ixgbe_get_link_settings_82598, +}; + +struct ixgbe_info ixgbe_82598AF_info = { + .mac = ixgbe_mac_82598EB, + .get_invariants = &ixgbe_get_invariants_82598, + .mac_ops = &mac_ops_82598, + .phy_ops = &phy_ops_82598AF, +}; + diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c new file mode 100644 index 000000000000..512e3b22ed08 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -0,0 +1,1175 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include + +#include "ixgbe_common.h" +#include "ixgbe_phy.h" + +static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw); + +static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw); +static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw); +static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw); +static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw); + +static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw); +static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw); +static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); +static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr); + +/** + * ixgbe_start_hw - Prepare hardware for TX/RX + * @hw: pointer to hardware structure + * + * Starts the hardware by filling the bus info structure and media type, clears + * all on chip counters, initializes receive address registers, multicast + * table, VLAN filter table, calls routine to set up link and flow control + * settings, and leaves transmit and receive units disabled and uninitialized + **/ +s32 ixgbe_start_hw(struct ixgbe_hw *hw) +{ + u32 ctrl_ext; + + /* Set the media type */ + hw->phy.media_type = hw->mac.ops.get_media_type(hw); + + /* Identify the PHY */ + ixgbe_identify_phy(hw); + + /* + * Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table + */ + ixgbe_init_rx_addrs(hw); + + /* Clear the VLAN filter table */ + ixgbe_clear_vfta(hw); + + /* Set up link */ + hw->phy.ops.setup(hw); + + /* Clear statistics registers */ + ixgbe_clear_hw_cntrs(hw); + + /* Set No Snoop Disable */ + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + + /* Clear adapter stopped flag */ + hw->adapter_stopped = false; + + return 0; +} + +/** + * ixgbe_init_hw - Generic hardware initialization + * @hw: pointer to hardware structure + * + * Initialize the hardware by reseting the hardware, filling the bus info + * structure and media type, clears all on chip counters, initializes receive + * address registers, multicast table, VLAN filter table, calls routine to set + * up link and flow control settings, and leaves transmit and receive units + * disabled and uninitialized + **/ +s32 ixgbe_init_hw(struct ixgbe_hw *hw) +{ + /* Reset the hardware */ + hw->mac.ops.reset(hw); + + /* Start the HW */ + ixgbe_start_hw(hw); + + return 0; +} + +/** + * ixgbe_clear_hw_cntrs - Generic clear hardware counters + * @hw: pointer to hardware structure + * + * Clears all hardware statistics counters by reading them from the hardware + * Statistics counters are clear on read. + **/ +static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw) +{ + u16 i = 0; + + IXGBE_READ_REG(hw, IXGBE_CRCERRS); + IXGBE_READ_REG(hw, IXGBE_ILLERRC); + IXGBE_READ_REG(hw, IXGBE_ERRBC); + IXGBE_READ_REG(hw, IXGBE_MSPDC); + for (i = 0; i < 8; i++) + IXGBE_READ_REG(hw, IXGBE_MPC(i)); + + IXGBE_READ_REG(hw, IXGBE_MLFC); + IXGBE_READ_REG(hw, IXGBE_MRFC); + IXGBE_READ_REG(hw, IXGBE_RLEC); + IXGBE_READ_REG(hw, IXGBE_LXONTXC); + IXGBE_READ_REG(hw, IXGBE_LXONRXC); + IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + + for (i = 0; i < 8; i++) { + IXGBE_READ_REG(hw, IXGBE_PXONTXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXONRXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i)); + } + + IXGBE_READ_REG(hw, IXGBE_PRC64); + IXGBE_READ_REG(hw, IXGBE_PRC127); + IXGBE_READ_REG(hw, IXGBE_PRC255); + IXGBE_READ_REG(hw, IXGBE_PRC511); + IXGBE_READ_REG(hw, IXGBE_PRC1023); + IXGBE_READ_REG(hw, IXGBE_PRC1522); + IXGBE_READ_REG(hw, IXGBE_GPRC); + IXGBE_READ_REG(hw, IXGBE_BPRC); + IXGBE_READ_REG(hw, IXGBE_MPRC); + IXGBE_READ_REG(hw, IXGBE_GPTC); + IXGBE_READ_REG(hw, IXGBE_GORCL); + IXGBE_READ_REG(hw, IXGBE_GORCH); + IXGBE_READ_REG(hw, IXGBE_GOTCL); + IXGBE_READ_REG(hw, IXGBE_GOTCH); + for (i = 0; i < 8; i++) + IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + IXGBE_READ_REG(hw, IXGBE_RUC); + IXGBE_READ_REG(hw, IXGBE_RFC); + IXGBE_READ_REG(hw, IXGBE_ROC); + IXGBE_READ_REG(hw, IXGBE_RJC); + IXGBE_READ_REG(hw, IXGBE_MNGPRC); + IXGBE_READ_REG(hw, IXGBE_MNGPDC); + IXGBE_READ_REG(hw, IXGBE_MNGPTC); + IXGBE_READ_REG(hw, IXGBE_TORL); + IXGBE_READ_REG(hw, IXGBE_TORH); + IXGBE_READ_REG(hw, IXGBE_TPR); + IXGBE_READ_REG(hw, IXGBE_TPT); + IXGBE_READ_REG(hw, IXGBE_PTC64); + IXGBE_READ_REG(hw, IXGBE_PTC127); + IXGBE_READ_REG(hw, IXGBE_PTC255); + IXGBE_READ_REG(hw, IXGBE_PTC511); + IXGBE_READ_REG(hw, IXGBE_PTC1023); + IXGBE_READ_REG(hw, IXGBE_PTC1522); + IXGBE_READ_REG(hw, IXGBE_MPTC); + IXGBE_READ_REG(hw, IXGBE_BPTC); + for (i = 0; i < 16; i++) { + IXGBE_READ_REG(hw, IXGBE_QPRC(i)); + IXGBE_READ_REG(hw, IXGBE_QBRC(i)); + IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + IXGBE_READ_REG(hw, IXGBE_QBTC(i)); + } + + return 0; +} + +/** + * ixgbe_get_mac_addr - Generic get MAC address + * @hw: pointer to hardware structure + * @mac_addr: Adapter MAC address + * + * Reads the adapter's MAC address from first Receive Address Register (RAR0) + * A reset of the adapter must be performed prior to calling this function + * in order for the MAC address to have been loaded from the EEPROM into RAR0 + **/ +s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr) +{ + u32 rar_high; + u32 rar_low; + u16 i; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(0)); + rar_low = IXGBE_READ_REG(hw, IXGBE_RAL(0)); + + for (i = 0; i < 4; i++) + mac_addr[i] = (u8)(rar_low >> (i*8)); + + for (i = 0; i < 2; i++) + mac_addr[i+4] = (u8)(rar_high >> (i*8)); + + return 0; +} + +s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num) +{ + s32 ret_val; + u16 data; + + ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM0_PTR, &data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *part_num = (u32)(data << 16); + + ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM1_PTR, &data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *part_num |= data; + + return 0; +} + +/** + * ixgbe_stop_adapter - Generic stop TX/RX units + * @hw: pointer to hardware structure + * + * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts, + * disables transmit and receive units. The adapter_stopped flag is used by + * the shared code and drivers to determine if the adapter is in a stopped + * state and should not touch the hardware. + **/ +s32 ixgbe_stop_adapter(struct ixgbe_hw *hw) +{ + u32 number_of_queues; + u32 reg_val; + u16 i; + + /* + * Set the adapter_stopped flag so other driver functions stop touching + * the hardware + */ + hw->adapter_stopped = true; + + /* Disable the receive unit */ + reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + reg_val &= ~(IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); + msleep(2); + + /* Clear interrupt mask to stop from interrupts being generated */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK); + + /* Clear any pending interrupts */ + IXGBE_READ_REG(hw, IXGBE_EICR); + + /* Disable the transmit unit. Each queue must be disabled. */ + number_of_queues = hw->mac.num_tx_queues; + for (i = 0; i < number_of_queues; i++) { + reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); + if (reg_val & IXGBE_TXDCTL_ENABLE) { + reg_val &= ~IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), reg_val); + } + } + + return 0; +} + +/** + * ixgbe_led_on - Turns on the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn on + **/ +s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index) +{ + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* To turn on the LED, set mode to ON. */ + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + + return 0; +} + +/** + * ixgbe_led_off - Turns off the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn off + **/ +s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index) +{ + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* To turn off the LED, set mode to OFF. */ + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + + return 0; +} + + +/** + * ixgbe_init_eeprom - Initialize EEPROM params + * @hw: pointer to hardware structure + * + * Initializes the EEPROM parameters ixgbe_eeprom_info within the + * ixgbe_hw struct in order to set up EEPROM access. + **/ +s32 ixgbe_init_eeprom(struct ixgbe_hw *hw) +{ + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + u32 eec; + u16 eeprom_size; + + if (eeprom->type == ixgbe_eeprom_uninitialized) { + eeprom->type = ixgbe_eeprom_none; + + /* + * Check for EEPROM present first. + * If not present leave as none + */ + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + if (eec & IXGBE_EEC_PRES) { + eeprom->type = ixgbe_eeprom_spi; + + /* + * SPI EEPROM is assumed here. This code would need to + * change if a future EEPROM is not SPI. + */ + eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >> + IXGBE_EEC_SIZE_SHIFT); + eeprom->word_size = 1 << (eeprom_size + + IXGBE_EEPROM_WORD_SIZE_SHIFT); + } + + if (eec & IXGBE_EEC_ADDR_SIZE) + eeprom->address_bits = 16; + else + eeprom->address_bits = 8; + hw_dbg(hw, "Eeprom params: type = %d, size = %d, address bits: " + "%d\n", eeprom->type, eeprom->word_size, + eeprom->address_bits); + } + + return 0; +} + +/** + * ixgbe_read_eeprom - Read EEPROM word using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data) +{ + u32 eerd; + s32 status; + + eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) + + IXGBE_EEPROM_READ_REG_START; + + IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); + status = ixgbe_poll_eeprom_eerd_done(hw); + + if (status == 0) + *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >> + IXGBE_EEPROM_READ_REG_DATA); + else + hw_dbg(hw, "Eeprom read timed out\n"); + + return status; +} + +/** + * ixgbe_poll_eeprom_eerd_done - Poll EERD status + * @hw: pointer to hardware structure + * + * Polls the status bit (bit 1) of the EERD to determine when the read is done. + **/ +static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw) +{ + u32 i; + u32 reg; + s32 status = IXGBE_ERR_EEPROM; + + for (i = 0; i < IXGBE_EERD_ATTEMPTS; i++) { + reg = IXGBE_READ_REG(hw, IXGBE_EERD); + if (reg & IXGBE_EEPROM_READ_REG_DONE) { + status = 0; + break; + } + udelay(5); + } + return status; +} + +/** + * ixgbe_get_eeprom_semaphore - Get hardware semaphore + * @hw: pointer to hardware structure + * + * Sets the hardware semaphores so EEPROM access can occur for bit-bang method + **/ +static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_EEPROM; + u32 timeout; + u32 i; + u32 swsm; + + /* Set timeout value based on size of EEPROM */ + timeout = hw->eeprom.word_size + 1; + + /* Get SMBI software semaphore between device drivers first */ + for (i = 0; i < timeout; i++) { + /* + * If the SMBI bit is 0 when we read it, then the bit will be + * set and we have the semaphore + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (!(swsm & IXGBE_SWSM_SMBI)) { + status = 0; + break; + } + msleep(1); + } + + /* Now get the semaphore between SW/FW through the SWESMBI bit */ + if (status == 0) { + for (i = 0; i < timeout; i++) { + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + + /* Set the SW EEPROM semaphore bit to request access */ + swsm |= IXGBE_SWSM_SWESMBI; + IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); + + /* + * If we set the bit successfully then we got the + * semaphore. + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (swsm & IXGBE_SWSM_SWESMBI) + break; + + udelay(50); + } + + /* + * Release semaphores and return error if SW EEPROM semaphore + * was not granted because we don't have access to the EEPROM + */ + if (i >= timeout) { + hw_dbg(hw, "Driver can't access the Eeprom - Semaphore " + "not granted.\n"); + ixgbe_release_eeprom_semaphore(hw); + status = IXGBE_ERR_EEPROM; + } + } + + return status; +} + +/** + * ixgbe_release_eeprom_semaphore - Release hardware semaphore + * @hw: pointer to hardware structure + * + * This function clears hardware semaphore bits. + **/ +static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw) +{ + u32 swsm; + + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + + /* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */ + swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI); + IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); +} + +/** + * ixgbe_calc_eeprom_checksum - Calculates and returns the checksum + * @hw: pointer to hardware structure + **/ +static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw) +{ + u16 i; + u16 j; + u16 checksum = 0; + u16 length = 0; + u16 pointer = 0; + u16 word = 0; + + /* Include 0x0-0x3F in the checksum */ + for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { + if (ixgbe_read_eeprom(hw, i, &word) != 0) { + hw_dbg(hw, "EEPROM read failed\n"); + break; + } + checksum += word; + } + + /* Include all data from pointers except for the fw pointer */ + for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) { + ixgbe_read_eeprom(hw, i, &pointer); + + /* Make sure the pointer seems valid */ + if (pointer != 0xFFFF && pointer != 0) { + ixgbe_read_eeprom(hw, pointer, &length); + + if (length != 0xFFFF && length != 0) { + for (j = pointer+1; j <= pointer+length; j++) { + ixgbe_read_eeprom(hw, j, &word); + checksum += word; + } + } + } + } + + checksum = (u16)IXGBE_EEPROM_SUM - checksum; + + return checksum; +} + +/** + * ixgbe_validate_eeprom_checksum - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum_val: calculated checksum + * + * Performs checksum calculation and validates the EEPROM checksum. If the + * caller does not need checksum_val, the value can be NULL. + **/ +s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val) +{ + s32 status; + u16 checksum; + u16 read_checksum = 0; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + status = ixgbe_read_eeprom(hw, 0, &checksum); + + if (status == 0) { + checksum = ixgbe_calc_eeprom_checksum(hw); + + ixgbe_read_eeprom(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); + + /* + * Verify read checksum from EEPROM is the same as + * calculated checksum + */ + if (read_checksum != checksum) + status = IXGBE_ERR_EEPROM_CHECKSUM; + + /* If the user cares, return the calculated checksum */ + if (checksum_val) + *checksum_val = checksum; + } else { + hw_dbg(hw, "EEPROM read failed\n"); + } + + return status; +} + +/** + * ixgbe_validate_mac_addr - Validate MAC address + * @mac_addr: pointer to MAC address. + * + * Tests a MAC address to ensure it is a valid Individual Address + **/ +s32 ixgbe_validate_mac_addr(u8 *mac_addr) +{ + s32 status = 0; + + /* Make sure it is not a multicast address */ + if (IXGBE_IS_MULTICAST(mac_addr)) + status = IXGBE_ERR_INVALID_MAC_ADDR; + /* Not a broadcast address */ + else if (IXGBE_IS_BROADCAST(mac_addr)) + status = IXGBE_ERR_INVALID_MAC_ADDR; + /* Reject the zero address */ + else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 && + mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) + status = IXGBE_ERR_INVALID_MAC_ADDR; + + return status; +} + +/** + * ixgbe_set_rar - Set RX address register + * @hw: pointer to hardware structure + * @addr: Address to put into receive address register + * @index: Receive address register to write + * @vind: Vind to set RAR to + * @enable_addr: set flag that address is active + * + * Puts an ethernet address into a receive address register. + **/ +s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind, + u32 enable_addr) +{ + u32 rar_low, rar_high; + + /* + * HW expects these in little endian so we reverse the byte order from + * network order (big endian) to little endian + */ + rar_low = ((u32)addr[0] | + ((u32)addr[1] << 8) | + ((u32)addr[2] << 16) | + ((u32)addr[3] << 24)); + + rar_high = ((u32)addr[4] | + ((u32)addr[5] << 8) | + ((vind << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK)); + + if (enable_addr != 0) + rar_high |= IXGBE_RAH_AV; + + IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + + return 0; +} + +/** + * ixgbe_init_rx_addrs - Initializes receive address filters. + * @hw: pointer to hardware structure + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive addresss registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + **/ +static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw) +{ + u32 i; + u32 rar_entries = hw->mac.num_rx_addrs; + + /* + * If the current mac address is valid, assume it is a software override + * to the permanent address. + * Otherwise, use the permanent address from the eeprom. + */ + if (ixgbe_validate_mac_addr(hw->mac.addr) == + IXGBE_ERR_INVALID_MAC_ADDR) { + /* Get the MAC address from the RAR0 for later reference */ + ixgbe_get_mac_addr(hw, hw->mac.addr); + + hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ", + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); + hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], + hw->mac.addr[4], hw->mac.addr[5]); + } else { + /* Setup the receive address. */ + hw_dbg(hw, "Overriding MAC Address in RAR[0]\n"); + hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ", + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); + hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], + hw->mac.addr[4], hw->mac.addr[5]); + + ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + } + + hw->addr_ctrl.rar_used_count = 1; + + /* Zero out the other receive addresses. */ + hw_dbg(hw, "Clearing RAR[1-15]\n"); + for (i = 1; i < rar_entries; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + } + + /* Clear the MTA */ + hw->addr_ctrl.mc_addr_in_rar_count = 0; + hw->addr_ctrl.mta_in_use = 0; + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); + + hw_dbg(hw, " Clearing MTA\n"); + for (i = 0; i < IXGBE_MC_TBL_SIZE; i++) + IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + + return 0; +} + +/** + * ixgbe_mta_vector - Determines bit-vector in multicast table to set + * @hw: pointer to hardware structure + * @mc_addr: the multicast address + * + * Extracts the 12 bits, from a multicast address, to determine which + * bit-vector to set in the multicast table. The hardware uses 12 bits, from + * incoming rx multicast addresses, to determine the bit-vector to check in + * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set + * by the MO field of the MCSTCTRL. The MO field is set during initalization + * to mc_filter_type. + **/ +static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 vector = 0; + + switch (hw->mac.mc_filter_type) { + case 0: /* use bits [47:36] of the address */ + vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); + break; + case 1: /* use bits [46:35] of the address */ + vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); + break; + case 2: /* use bits [45:34] of the address */ + vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); + break; + case 3: /* use bits [43:32] of the address */ + vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); + break; + default: /* Invalid mc_filter_type */ + hw_dbg(hw, "MC filter type param set incorrectly\n"); + break; + } + + /* vector can only be 12-bits or boundary will be exceeded */ + vector &= 0xFFF; + return vector; +} + +/** + * ixgbe_set_mta - Set bit-vector in multicast table + * @hw: pointer to hardware structure + * @hash_value: Multicast address hash value + * + * Sets the bit-vector in the multicast table. + **/ +static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 vector; + u32 vector_bit; + u32 vector_reg; + u32 mta_reg; + + hw->addr_ctrl.mta_in_use++; + + vector = ixgbe_mta_vector(hw, mc_addr); + hw_dbg(hw, " bit-vector = 0x%03X\n", vector); + + /* + * 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[vector_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 vector value and + * the bit within that register are determined by the lower 5 bits of + * the value. + */ + vector_reg = (vector >> 5) & 0x7F; + vector_bit = vector & 0x1F; + mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg)); + mta_reg |= (1 << vector_bit); + IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); +} + +/** + * ixgbe_add_mc_addr - Adds a multicast address. + * @hw: pointer to hardware structure + * @mc_addr: new multicast address + * + * Adds it to unused receive address register or to the multicast table. + **/ +static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 rar_entries = hw->mac.num_rx_addrs; + + hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n", + mc_addr[0], mc_addr[1], mc_addr[2], + mc_addr[3], mc_addr[4], mc_addr[5]); + + /* + * Place this multicast address in the RAR if there is room, + * else put it in the MTA + */ + if (hw->addr_ctrl.rar_used_count < rar_entries) { + ixgbe_set_rar(hw, hw->addr_ctrl.rar_used_count, + mc_addr, 0, IXGBE_RAH_AV); + hw_dbg(hw, "Added a multicast address to RAR[%d]\n", + hw->addr_ctrl.rar_used_count); + hw->addr_ctrl.rar_used_count++; + hw->addr_ctrl.mc_addr_in_rar_count++; + } else { + ixgbe_set_mta(hw, mc_addr); + } + + hw_dbg(hw, "ixgbe_add_mc_addr Complete\n"); +} + +/** + * ixgbe_update_mc_addr_list - Updates MAC list of multicast addresses + * @hw: pointer to hardware structure + * @mc_addr_list: the list of new multicast addresses + * @mc_addr_count: number of addresses + * @pad: number of bytes between addresses in the list + * + * The given list replaces any existing list. Clears the MC addrs from receive + * address registers and the multicast table. Uses unsed receive address + * registers for the first multicast addresses, and hashes the rest into the + * multicast table. + **/ +s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, u32 pad) +{ + u32 i; + u32 rar_entries = hw->mac.num_rx_addrs; + + /* + * Set the new number of MC addresses that we are being requested to + * use. + */ + hw->addr_ctrl.num_mc_addrs = mc_addr_count; + hw->addr_ctrl.rar_used_count -= hw->addr_ctrl.mc_addr_in_rar_count; + hw->addr_ctrl.mc_addr_in_rar_count = 0; + hw->addr_ctrl.mta_in_use = 0; + + /* Zero out the other receive addresses. */ + hw_dbg(hw, "Clearing RAR[1-15]\n"); + for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + } + + /* Clear the MTA */ + hw_dbg(hw, " Clearing MTA\n"); + for (i = 0; i < IXGBE_MC_TBL_SIZE; i++) + IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + + /* Add the new addresses */ + for (i = 0; i < mc_addr_count; i++) { + hw_dbg(hw, " Adding the multicast addresses:\n"); + ixgbe_add_mc_addr(hw, mc_addr_list + + (i * (IXGBE_ETH_LENGTH_OF_ADDRESS + pad))); + } + + /* Enable mta */ + if (hw->addr_ctrl.mta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, + IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); + + hw_dbg(hw, "ixgbe_update_mc_addr_list Complete\n"); + return 0; +} + +/** + * ixgbe_clear_vfta - Clear VLAN filter table + * @hw: pointer to hardware structure + * + * Clears the VLAN filer table, and the VMDq index associated with the filter + **/ +static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw) +{ + u32 offset; + u32 vlanbyte; + + for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0); + + for (vlanbyte = 0; vlanbyte < 4; vlanbyte++) + for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++) + IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset), + 0); + + return 0; +} + +/** + * ixgbe_set_vfta - Set VLAN filter table + * @hw: pointer to hardware structure + * @vlan: VLAN id to write to VLAN filter + * @vind: VMDq output index that maps queue to VLAN id in VFTA + * @vlan_on: boolean flag to turn on/off VLAN in VFTA + * + * Turn on/off specified VLAN in the VLAN filter table. + **/ +s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) +{ + u32 VftaIndex; + u32 BitOffset; + u32 VftaReg; + u32 VftaByte; + + /* Determine 32-bit word position in array */ + VftaIndex = (vlan >> 5) & 0x7F; /* upper seven bits */ + + /* Determine the location of the (VMD) queue index */ + VftaByte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */ + BitOffset = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */ + + /* Set the nibble for VMD queue index */ + VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex)); + VftaReg &= (~(0x0F << BitOffset)); + VftaReg |= (vind << BitOffset); + IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg); + + /* Determine the location of the bit for this VLAN id */ + BitOffset = vlan & 0x1F; /* lower five bits */ + + VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex)); + if (vlan_on) + /* Turn on this VLAN id */ + VftaReg |= (1 << BitOffset); + else + /* Turn off this VLAN id */ + VftaReg &= ~(1 << BitOffset); + IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg); + + return 0; +} + +/** + * ixgbe_setup_fc - Configure flow control settings + * @hw: pointer to hardware structure + * @packetbuf_num: packet buffer number (0-7) + * + * Configures the flow control settings based on SW configuration. + * This function is used for 802.3x flow control configuration only. + **/ +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) +{ + u32 frctl_reg; + u32 rmcs_reg; + + if (packetbuf_num < 0 || packetbuf_num > 7) + hw_dbg(hw, "Invalid packet buffer number [%d], expected range" + "is 0-7\n", packetbuf_num); + + frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); + frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); + + rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X); + + /* + * 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.type = hw->fc.original_type; + + /* + * The possible values of the "flow_control" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames but not + * send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but we do not + * support receiving pause frames) + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.type) { + case ixgbe_fc_none: + break; + case ixgbe_fc_rx_pause: + /* + * RX Flow control is enabled, + * and TX Flow control is disabled. + */ + frctl_reg |= IXGBE_FCTRL_RFCE; + break; + case ixgbe_fc_tx_pause: + /* + * TX Flow control is enabled, and RX Flow control is disabled, + * by a software over-ride. + */ + rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; + break; + case ixgbe_fc_full: + /* + * Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + frctl_reg |= IXGBE_FCTRL_RFCE; + rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; + break; + default: + /* We should never get here. The value should be 0-3. */ + hw_dbg(hw, "Flow control param set incorrectly\n"); + break; + } + + /* Enable 802.3x based flow control settings. */ + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg); + IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); + + /* + * We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of + * XON frames. + */ + if (hw->fc.type & ixgbe_fc_tx_pause) { + if (hw->fc.send_xon) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), + (hw->fc.low_water | IXGBE_FCRTL_XONE)); + } else { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), + hw->fc.low_water); + } + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), + (hw->fc.high_water)|IXGBE_FCRTH_FCEN); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time); + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); + + return 0; +} + +/** + * ixgbe_disable_pcie_master - Disable PCI-express master access + * @hw: pointer to hardware structure + * + * Disables PCI-Express master access and verifies there are no pending + * requests. IXGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable + * bit hasn't caused the master requests to be disabled, else 0 + * is returned signifying master requests disabled. + **/ +s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) +{ + u32 ctrl; + s32 i; + s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + ctrl |= IXGBE_CTRL_GIO_DIS; + IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); + + for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { + if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) { + status = 0; + break; + } + udelay(100); + } + + return status; +} + + +/** + * ixgbe_acquire_swfw_sync - Aquire SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify wich semaphore to acquire + * + * Aquires the SWFW semaphore throught the GSSR register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ +s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) +{ + u32 gssr; + u32 swmask = mask; + u32 fwmask = mask << 5; + s32 timeout = 200; + + while (timeout) { + if (ixgbe_get_eeprom_semaphore(hw)) + return -IXGBE_ERR_SWFW_SYNC; + + gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); + if (!(gssr & (fwmask | swmask))) + break; + + /* + * Firmware currently using resource (fwmask) or other software + * thread currently using resource (swmask) + */ + ixgbe_release_eeprom_semaphore(hw); + msleep(5); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "Driver can't access resource, GSSR timeout.\n"); + return -IXGBE_ERR_SWFW_SYNC; + } + + gssr |= swmask; + IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); + + ixgbe_release_eeprom_semaphore(hw); + return 0; +} + +/** + * ixgbe_release_swfw_sync - Release SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify wich semaphore to release + * + * Releases the SWFW semaphore throught the GSSR register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ +void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask) +{ + u32 gssr; + u32 swmask = mask; + + ixgbe_get_eeprom_semaphore(hw); + + gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); + gssr &= ~swmask; + IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); + + ixgbe_release_eeprom_semaphore(hw); +} + +/** + * ixgbe_read_analog_reg8- Reads 8 bit 82598 Atlas analog register + * @hw: pointer to hardware structure + * @reg: analog register to read + * @val: read value + * + * Performs write operation to analog register specified. + **/ +s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val) +{ + u32 atlas_ctl; + + IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, + IXGBE_ATLASCTL_WRITE_CMD | (reg << 8)); + IXGBE_WRITE_FLUSH(hw); + udelay(10); + atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); + *val = (u8)atlas_ctl; + + return 0; +} + +/** + * ixgbe_write_analog_reg8- Writes 8 bit Atlas analog register + * @hw: pointer to hardware structure + * @reg: atlas register to write + * @val: value to write + * + * Performs write operation to Atlas analog register specified. + **/ +s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val) +{ + u32 atlas_ctl; + + atlas_ctl = (reg << 8) | val; + IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl); + IXGBE_WRITE_FLUSH(hw); + udelay(10); + + return 0; +} + diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h new file mode 100644 index 000000000000..de6ddd5d04ad --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -0,0 +1,86 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_COMMON_H_ +#define _IXGBE_COMMON_H_ + +#include "ixgbe_type.h" + +s32 ixgbe_init_hw(struct ixgbe_hw *hw); +s32 ixgbe_start_hw(struct ixgbe_hw *hw); +s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr); +s32 ixgbe_stop_adapter(struct ixgbe_hw *hw); +s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num); + +s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index); +s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index); + +s32 ixgbe_init_eeprom(struct ixgbe_hw *hw); +s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val); + +s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind, + u32 enable_addr); +s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, u32 pad); +s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); +s32 ixgbe_validate_mac_addr(u8 *mac_addr); + +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num); + +s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask); +void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask); +s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw); + +s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val); +s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val); + +#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) + +#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg)) + +#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\ + writel((value), ((a)->hw_addr + (reg) + ((offset) << 2)))) + +#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\ + readl((a)->hw_addr + (reg) + ((offset) << 2))) + +#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS) + +#ifdef DEBUG +#define hw_dbg(hw, format, arg...) \ +printk(KERN_DEBUG, "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg); +#else +static inline int __attribute__ ((format (printf, 2, 3))) +hw_dbg(struct ixgbe_hw *hw, const char *format, ...) +{ + return 0; +} +#endif + +#endif /* IXGBE_COMMON */ diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c new file mode 100644 index 000000000000..43a2a46e2874 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -0,0 +1,943 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* ethtool support for ixgbe */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ixgbe.h" + + +#define IXGBE_ALL_RAR_ENTRIES 16 + +struct ixgbe_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \ + offsetof(struct ixgbe_adapter, m) +static struct ixgbe_stats ixgbe_gstrings_stats[] = { + {"rx_packets", IXGBE_STAT(net_stats.rx_packets)}, + {"tx_packets", IXGBE_STAT(net_stats.tx_packets)}, + {"rx_bytes", IXGBE_STAT(net_stats.rx_bytes)}, + {"tx_bytes", IXGBE_STAT(net_stats.tx_bytes)}, + {"lsc_int", IXGBE_STAT(lsc_int)}, + {"tx_busy", IXGBE_STAT(tx_busy)}, + {"non_eop_descs", IXGBE_STAT(non_eop_descs)}, + {"rx_errors", IXGBE_STAT(net_stats.rx_errors)}, + {"tx_errors", IXGBE_STAT(net_stats.tx_errors)}, + {"rx_dropped", IXGBE_STAT(net_stats.rx_dropped)}, + {"tx_dropped", IXGBE_STAT(net_stats.tx_dropped)}, + {"multicast", IXGBE_STAT(net_stats.multicast)}, + {"broadcast", IXGBE_STAT(stats.bprc)}, + {"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) }, + {"collisions", IXGBE_STAT(net_stats.collisions)}, + {"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)}, + {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)}, + {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)}, + {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)}, + {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)}, + {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)}, + {"tx_carrier_errors", IXGBE_STAT(net_stats.tx_carrier_errors)}, + {"tx_fifo_errors", IXGBE_STAT(net_stats.tx_fifo_errors)}, + {"tx_heartbeat_errors", IXGBE_STAT(net_stats.tx_heartbeat_errors)}, + {"tx_timeout_count", IXGBE_STAT(tx_timeout_count)}, + {"tx_restart_queue", IXGBE_STAT(restart_queue)}, + {"rx_long_length_errors", IXGBE_STAT(stats.roc)}, + {"rx_short_length_errors", IXGBE_STAT(stats.ruc)}, + {"tx_tcp4_seg_ctxt", IXGBE_STAT(hw_tso_ctxt)}, + {"tx_tcp6_seg_ctxt", IXGBE_STAT(hw_tso6_ctxt)}, + {"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)}, + {"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)}, + {"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)}, + {"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)}, + {"rx_csum_offload_good", IXGBE_STAT(hw_csum_rx_good)}, + {"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)}, + {"tx_csum_offload_ctxt", IXGBE_STAT(hw_csum_tx_good)}, + {"rx_header_split", IXGBE_STAT(rx_hdr_split)}, + {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, + {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, +}; + +#define IXGBE_QUEUE_STATS_LEN \ + ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ + ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ + (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) +#define IXGBE_GLOBAL_STATS_LEN \ + sizeof(ixgbe_gstrings_stats) / sizeof(struct ixgbe_stats) +#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) + +static int ixgbe_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; + + if (netif_carrier_ok(adapter->netdev)) { + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = AUTONEG_DISABLE; + return 0; +} + +static int ixgbe_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (ecmd->autoneg == AUTONEG_ENABLE || + ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) + return -EINVAL; + + if (netif_running(adapter->netdev)) { + ixgbe_down(adapter); + ixgbe_reset(adapter); + ixgbe_up(adapter); + } else { + ixgbe_reset(adapter); + } + + return 0; +} + +static void ixgbe_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + + pause->autoneg = AUTONEG_DISABLE; + + if (hw->fc.type == ixgbe_fc_rx_pause) { + pause->rx_pause = 1; + } else if (hw->fc.type == ixgbe_fc_tx_pause) { + pause->tx_pause = 1; + } else if (hw->fc.type == ixgbe_fc_full) { + pause->rx_pause = 1; + pause->tx_pause = 1; + } +} + +static int ixgbe_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + + if (pause->autoneg == AUTONEG_ENABLE) + return -EINVAL; + + if (pause->rx_pause && pause->tx_pause) + hw->fc.type = ixgbe_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.type = ixgbe_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.type = ixgbe_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.type = ixgbe_fc_none; + + hw->fc.original_type = hw->fc.type; + + if (netif_running(adapter->netdev)) { + ixgbe_down(adapter); + ixgbe_up(adapter); + } else { + ixgbe_reset(adapter); + } + + return 0; +} + +static u32 ixgbe_get_rx_csum(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + return (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED); +} + +static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + if (data) + adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED; + else + adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED; + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_up(adapter); + } else { + ixgbe_reset(adapter); + } + + return 0; +} + +static u32 ixgbe_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_HW_CSUM) != 0; +} + +static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data) +{ + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; +} + +static int ixgbe_set_tso(struct net_device *netdev, u32 data) +{ + + if (data) { + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + } else { + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + } + return 0; +} + +static u32 ixgbe_get_msglevel(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + return adapter->msg_enable; +} + +static void ixgbe_set_msglevel(struct net_device *netdev, u32 data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + adapter->msg_enable = data; +} + +static int ixgbe_get_regs_len(struct net_device *netdev) +{ +#define IXGBE_REGS_LEN 1128 + return IXGBE_REGS_LEN * sizeof(u32); +} + +#define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_ + +static void ixgbe_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u8 i; + + memset(p, 0, IXGBE_REGS_LEN * sizeof(u32)); + + regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id; + + /* General Registers */ + regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL); + regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS); + regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP); + regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP); + regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER); + regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER); + + /* NVM Register */ + regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC); + regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD); + regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA); + regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL); + regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA); + regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL); + regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA); + regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT); + regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP); + regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC); + + /* Interrupt */ + regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR); + regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS); + regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS); + regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC); + regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC); + regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM); + regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0)); + regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0)); + regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT); + regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA); + regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL); + regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE); + + /* Flow Control */ + regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP); + regs_buff[31] = IXGBE_READ_REG(hw, IXGBE_FCTTV(0)); + regs_buff[32] = IXGBE_READ_REG(hw, IXGBE_FCTTV(1)); + regs_buff[33] = IXGBE_READ_REG(hw, IXGBE_FCTTV(2)); + regs_buff[34] = IXGBE_READ_REG(hw, IXGBE_FCTTV(3)); + for (i = 0; i < 8; i++) + regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i)); + for (i = 0; i < 8; i++) + regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i)); + regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV); + regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS); + + /* Receive DMA */ + for (i = 0; i < 64; i++) + regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i)); + for (i = 0; i < 64; i++) + regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i)); + for (i = 0; i < 64; i++) + regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i)); + for (i = 0; i < 64; i++) + regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i)); + for (i = 0; i < 64; i++) + regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i)); + for (i = 0; i < 64; i++) + regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); + for (i = 0; i < 16; i++) + regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); + for (i = 0; i < 16; i++) + regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); + regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + for (i = 0; i < 8; i++) + regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)); + regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN); + + /* Receive */ + regs_buff[480] = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + regs_buff[481] = IXGBE_READ_REG(hw, IXGBE_RFCTL); + for (i = 0; i < 16; i++) + regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i)); + for (i = 0; i < 16; i++) + regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i)); + regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE); + regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL); + regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL); + regs_buff[518] = IXGBE_READ_REG(hw, IXGBE_MRQC); + regs_buff[519] = IXGBE_READ_REG(hw, IXGBE_VMD_CTL); + for (i = 0; i < 8; i++) + regs_buff[520 + i] = IXGBE_READ_REG(hw, IXGBE_IMIR(i)); + for (i = 0; i < 8; i++) + regs_buff[528 + i] = IXGBE_READ_REG(hw, IXGBE_IMIREXT(i)); + regs_buff[536] = IXGBE_READ_REG(hw, IXGBE_IMIRVP); + + /* Transmit */ + for (i = 0; i < 32; i++) + regs_buff[537 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i)); + for (i = 0; i < 32; i++) + regs_buff[569 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i)); + for (i = 0; i < 32; i++) + regs_buff[601 + i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i)); + for (i = 0; i < 32; i++) + regs_buff[633 + i] = IXGBE_READ_REG(hw, IXGBE_TDH(i)); + for (i = 0; i < 32; i++) + regs_buff[665 + i] = IXGBE_READ_REG(hw, IXGBE_TDT(i)); + for (i = 0; i < 32; i++) + regs_buff[697 + i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); + for (i = 0; i < 32; i++) + regs_buff[729 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAL(i)); + for (i = 0; i < 32; i++) + regs_buff[761 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAH(i)); + regs_buff[793] = IXGBE_READ_REG(hw, IXGBE_DTXCTL); + for (i = 0; i < 16; i++) + regs_buff[794 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + regs_buff[810] = IXGBE_READ_REG(hw, IXGBE_TIPG); + for (i = 0; i < 8; i++) + regs_buff[811 + i] = IXGBE_READ_REG(hw, IXGBE_TXPBSIZE(i)); + regs_buff[819] = IXGBE_READ_REG(hw, IXGBE_MNGTXMAP); + + /* Wake Up */ + regs_buff[820] = IXGBE_READ_REG(hw, IXGBE_WUC); + regs_buff[821] = IXGBE_READ_REG(hw, IXGBE_WUFC); + regs_buff[822] = IXGBE_READ_REG(hw, IXGBE_WUS); + regs_buff[823] = IXGBE_READ_REG(hw, IXGBE_IPAV); + regs_buff[824] = IXGBE_READ_REG(hw, IXGBE_IP4AT); + regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT); + regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL); + regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM); + regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT); + + /* DCE */ + regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS); + regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS); + regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS); + regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR); + for (i = 0; i < 8; i++) + regs_buff[833 + i] = IXGBE_READ_REG(hw, IXGBE_RT2CR(i)); + for (i = 0; i < 8; i++) + regs_buff[841 + i] = IXGBE_READ_REG(hw, IXGBE_RT2SR(i)); + for (i = 0; i < 8; i++) + regs_buff[849 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i)); + for (i = 0; i < 8; i++) + regs_buff[857 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i)); + for (i = 0; i < 8; i++) + regs_buff[865 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i)); + for (i = 0; i < 8; i++) + regs_buff[873 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i)); + + /* Statistics */ + regs_buff[881] = IXGBE_GET_STAT(adapter, crcerrs); + regs_buff[882] = IXGBE_GET_STAT(adapter, illerrc); + regs_buff[883] = IXGBE_GET_STAT(adapter, errbc); + regs_buff[884] = IXGBE_GET_STAT(adapter, mspdc); + for (i = 0; i < 8; i++) + regs_buff[885 + i] = IXGBE_GET_STAT(adapter, mpc[i]); + regs_buff[893] = IXGBE_GET_STAT(adapter, mlfc); + regs_buff[894] = IXGBE_GET_STAT(adapter, mrfc); + regs_buff[895] = IXGBE_GET_STAT(adapter, rlec); + regs_buff[896] = IXGBE_GET_STAT(adapter, lxontxc); + regs_buff[897] = IXGBE_GET_STAT(adapter, lxonrxc); + regs_buff[898] = IXGBE_GET_STAT(adapter, lxofftxc); + regs_buff[899] = IXGBE_GET_STAT(adapter, lxoffrxc); + for (i = 0; i < 8; i++) + regs_buff[900 + i] = IXGBE_GET_STAT(adapter, pxontxc[i]); + for (i = 0; i < 8; i++) + regs_buff[908 + i] = IXGBE_GET_STAT(adapter, pxonrxc[i]); + for (i = 0; i < 8; i++) + regs_buff[916 + i] = IXGBE_GET_STAT(adapter, pxofftxc[i]); + for (i = 0; i < 8; i++) + regs_buff[924 + i] = IXGBE_GET_STAT(adapter, pxoffrxc[i]); + regs_buff[932] = IXGBE_GET_STAT(adapter, prc64); + regs_buff[933] = IXGBE_GET_STAT(adapter, prc127); + regs_buff[934] = IXGBE_GET_STAT(adapter, prc255); + regs_buff[935] = IXGBE_GET_STAT(adapter, prc511); + regs_buff[936] = IXGBE_GET_STAT(adapter, prc1023); + regs_buff[937] = IXGBE_GET_STAT(adapter, prc1522); + regs_buff[938] = IXGBE_GET_STAT(adapter, gprc); + regs_buff[939] = IXGBE_GET_STAT(adapter, bprc); + regs_buff[940] = IXGBE_GET_STAT(adapter, mprc); + regs_buff[941] = IXGBE_GET_STAT(adapter, gptc); + regs_buff[942] = IXGBE_GET_STAT(adapter, gorc); + regs_buff[944] = IXGBE_GET_STAT(adapter, gotc); + for (i = 0; i < 8; i++) + regs_buff[946 + i] = IXGBE_GET_STAT(adapter, rnbc[i]); + regs_buff[954] = IXGBE_GET_STAT(adapter, ruc); + regs_buff[955] = IXGBE_GET_STAT(adapter, rfc); + regs_buff[956] = IXGBE_GET_STAT(adapter, roc); + regs_buff[957] = IXGBE_GET_STAT(adapter, rjc); + regs_buff[958] = IXGBE_GET_STAT(adapter, mngprc); + regs_buff[959] = IXGBE_GET_STAT(adapter, mngpdc); + regs_buff[960] = IXGBE_GET_STAT(adapter, mngptc); + regs_buff[961] = IXGBE_GET_STAT(adapter, tor); + regs_buff[963] = IXGBE_GET_STAT(adapter, tpr); + regs_buff[964] = IXGBE_GET_STAT(adapter, tpt); + regs_buff[965] = IXGBE_GET_STAT(adapter, ptc64); + regs_buff[966] = IXGBE_GET_STAT(adapter, ptc127); + regs_buff[967] = IXGBE_GET_STAT(adapter, ptc255); + regs_buff[968] = IXGBE_GET_STAT(adapter, ptc511); + regs_buff[969] = IXGBE_GET_STAT(adapter, ptc1023); + regs_buff[970] = IXGBE_GET_STAT(adapter, ptc1522); + regs_buff[971] = IXGBE_GET_STAT(adapter, mptc); + regs_buff[972] = IXGBE_GET_STAT(adapter, bptc); + regs_buff[973] = IXGBE_GET_STAT(adapter, xec); + for (i = 0; i < 16; i++) + regs_buff[974 + i] = IXGBE_GET_STAT(adapter, qprc[i]); + for (i = 0; i < 16; i++) + regs_buff[990 + i] = IXGBE_GET_STAT(adapter, qptc[i]); + for (i = 0; i < 16; i++) + regs_buff[1006 + i] = IXGBE_GET_STAT(adapter, qbrc[i]); + for (i = 0; i < 16; i++) + regs_buff[1022 + i] = IXGBE_GET_STAT(adapter, qbtc[i]); + + /* MAC */ + regs_buff[1038] = IXGBE_READ_REG(hw, IXGBE_PCS1GCFIG); + regs_buff[1039] = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); + regs_buff[1040] = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); + regs_buff[1041] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG0); + regs_buff[1042] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG1); + regs_buff[1043] = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + regs_buff[1044] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); + regs_buff[1045] = IXGBE_READ_REG(hw, IXGBE_PCS1GANNP); + regs_buff[1046] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLPNP); + regs_buff[1047] = IXGBE_READ_REG(hw, IXGBE_HLREG0); + regs_buff[1048] = IXGBE_READ_REG(hw, IXGBE_HLREG1); + regs_buff[1049] = IXGBE_READ_REG(hw, IXGBE_PAP); + regs_buff[1050] = IXGBE_READ_REG(hw, IXGBE_MACA); + regs_buff[1051] = IXGBE_READ_REG(hw, IXGBE_APAE); + regs_buff[1052] = IXGBE_READ_REG(hw, IXGBE_ARD); + regs_buff[1053] = IXGBE_READ_REG(hw, IXGBE_AIS); + regs_buff[1054] = IXGBE_READ_REG(hw, IXGBE_MSCA); + regs_buff[1055] = IXGBE_READ_REG(hw, IXGBE_MSRWD); + regs_buff[1056] = IXGBE_READ_REG(hw, IXGBE_MLADD); + regs_buff[1057] = IXGBE_READ_REG(hw, IXGBE_MHADD); + regs_buff[1058] = IXGBE_READ_REG(hw, IXGBE_TREG); + regs_buff[1059] = IXGBE_READ_REG(hw, IXGBE_PCSS1); + regs_buff[1060] = IXGBE_READ_REG(hw, IXGBE_PCSS2); + regs_buff[1061] = IXGBE_READ_REG(hw, IXGBE_XPCSS); + regs_buff[1062] = IXGBE_READ_REG(hw, IXGBE_SERDESC); + regs_buff[1063] = IXGBE_READ_REG(hw, IXGBE_MACS); + regs_buff[1064] = IXGBE_READ_REG(hw, IXGBE_AUTOC); + regs_buff[1065] = IXGBE_READ_REG(hw, IXGBE_LINKS); + regs_buff[1066] = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + regs_buff[1067] = IXGBE_READ_REG(hw, IXGBE_AUTOC3); + regs_buff[1068] = IXGBE_READ_REG(hw, IXGBE_ANLP1); + regs_buff[1069] = IXGBE_READ_REG(hw, IXGBE_ANLP2); + regs_buff[1070] = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); + + /* Diagnostic */ + regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL); + for (i = 0; i < 8; i++) + regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i)); + regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN); + regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0); + regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1); + regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2); + regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3); + regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE); + regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL); + for (i = 0; i < 8; i++) + regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i)); + regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN); + regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0); + regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1); + regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2); + regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3); + regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE); + regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL); + regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0); + regs_buff[1103] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA1); + regs_buff[1104] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA2); + regs_buff[1105] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA3); + regs_buff[1106] = IXGBE_READ_REG(hw, IXGBE_RXBUFCTRL); + regs_buff[1107] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA0); + regs_buff[1108] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA1); + regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2); + regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3); + for (i = 0; i < 8; i++) + regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i)); + regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL); + regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1); + regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2); + regs_buff[1122] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO1); + regs_buff[1123] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO2); + regs_buff[1124] = IXGBE_READ_REG(hw, IXGBE_MDFTS); + regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL); + regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC); + regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC); +} + +static int ixgbe_get_eeprom_len(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + return adapter->hw.eeprom.word_size * 2; +} + +static int ixgbe_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u16 *eeprom_buff; + int first_word, last_word, eeprom_len; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = hw->vendor_id | (hw->device_id << 16); + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + eeprom_len = last_word - first_word + 1; + + eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + for (i = 0; i < eeprom_len; i++) { + if ((ret_val = ixgbe_read_eeprom(hw, first_word + i, + &eeprom_buff[i]))) + break; + } + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < eeprom_len; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); + kfree(eeprom_buff); + + return ret_val; +} + +static void ixgbe_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + strncpy(drvinfo->driver, ixgbe_driver_name, 32); + strncpy(drvinfo->version, ixgbe_driver_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->n_stats = IXGBE_STATS_LEN; + drvinfo->regdump_len = ixgbe_get_regs_len(netdev); +} + +static void ixgbe_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_ring *tx_ring = adapter->tx_ring; + struct ixgbe_ring *rx_ring = adapter->rx_ring; + + ring->rx_max_pending = IXGBE_MAX_RXD; + ring->tx_max_pending = IXGBE_MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rx_ring->count; + ring->tx_pending = tx_ring->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int ixgbe_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_tx_buffer *old_buf; + struct ixgbe_rx_buffer *old_rx_buf; + void *old_desc; + int i, err; + u32 new_rx_count, new_tx_count, old_size; + dma_addr_t old_dma; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + new_rx_count = max(ring->rx_pending, (u32)IXGBE_MIN_RXD); + new_rx_count = min(new_rx_count, (u32)IXGBE_MAX_RXD); + new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE); + + new_tx_count = max(ring->tx_pending, (u32)IXGBE_MIN_TXD); + new_tx_count = min(new_tx_count, (u32)IXGBE_MAX_TXD); + new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE); + + if ((new_tx_count == adapter->tx_ring->count) && + (new_rx_count == adapter->rx_ring->count)) { + /* nothing to do */ + return 0; + } + + if (netif_running(adapter->netdev)) + ixgbe_down(adapter); + + /* + * We can't just free everything and then setup again, + * because the ISRs in MSI-X mode get passed pointers + * to the tx and rx ring structs. + */ + if (new_tx_count != adapter->tx_ring->count) { + for (i = 0; i < adapter->num_tx_queues; i++) { + /* Save existing descriptor ring */ + old_buf = adapter->tx_ring[i].tx_buffer_info; + old_desc = adapter->tx_ring[i].desc; + old_size = adapter->tx_ring[i].size; + old_dma = adapter->tx_ring[i].dma; + /* Try to allocate a new one */ + adapter->tx_ring[i].tx_buffer_info = NULL; + adapter->tx_ring[i].desc = NULL; + adapter->tx_ring[i].count = new_tx_count; + err = ixgbe_setup_tx_resources(adapter, + &adapter->tx_ring[i]); + if (err) { + /* Restore the old one so at least + the adapter still works, even if + we failed the request */ + adapter->tx_ring[i].tx_buffer_info = old_buf; + adapter->tx_ring[i].desc = old_desc; + adapter->tx_ring[i].size = old_size; + adapter->tx_ring[i].dma = old_dma; + goto err_setup; + } + /* Free the old buffer manually */ + vfree(old_buf); + pci_free_consistent(adapter->pdev, old_size, + old_desc, old_dma); + } + } + + if (new_rx_count != adapter->rx_ring->count) { + for (i = 0; i < adapter->num_rx_queues; i++) { + + old_rx_buf = adapter->rx_ring[i].rx_buffer_info; + old_desc = adapter->rx_ring[i].desc; + old_size = adapter->rx_ring[i].size; + old_dma = adapter->rx_ring[i].dma; + + adapter->rx_ring[i].rx_buffer_info = NULL; + adapter->rx_ring[i].desc = NULL; + adapter->rx_ring[i].dma = 0; + adapter->rx_ring[i].count = new_rx_count; + err = ixgbe_setup_rx_resources(adapter, + &adapter->rx_ring[i]); + if (err) { + adapter->rx_ring[i].rx_buffer_info = old_rx_buf; + adapter->rx_ring[i].desc = old_desc; + adapter->rx_ring[i].size = old_size; + adapter->rx_ring[i].dma = old_dma; + goto err_setup; + } + + vfree(old_rx_buf); + pci_free_consistent(adapter->pdev, old_size, old_desc, + old_dma); + } + } + + err = 0; +err_setup: + if (netif_running(adapter->netdev)) + ixgbe_up(adapter); + + return err; +} + +static int ixgbe_get_stats_count(struct net_device *netdev) +{ + return IXGBE_STATS_LEN; +} + +static void ixgbe_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u64 *queue_stat; + int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64); + int j, k; + int i; + + ixgbe_update_stats(adapter); + for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset; + data[i] = (ixgbe_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + for (j = 0; j < adapter->num_tx_queues; j++) { + queue_stat = (u64 *)&adapter->tx_ring[j].stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } + for (j = 0; j < adapter->num_rx_queues; j++) { + queue_stat = (u64 *)&adapter->rx_ring[j].stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } +} + +static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { + memcpy(p, ixgbe_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < adapter->num_tx_queues; i++) { + sprintf(p, "tx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "tx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < adapter->num_rx_queues; i++) { + sprintf(p, "rx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "rx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } +/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ + break; + } +} + + +static void ixgbe_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + + return; +} + +static int ixgbe_nway_reset(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_reset(adapter); + ixgbe_up(adapter); + } + + return 0; +} + +static int ixgbe_phys_id(struct net_device *netdev, u32 data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL); + u32 i; + + if (!data || data > 300) + data = 300; + + for (i = 0; i < (data * 1000); i += 400) { + ixgbe_led_on(&adapter->hw, IXGBE_LED_ON); + msleep_interruptible(200); + ixgbe_led_off(&adapter->hw, IXGBE_LED_ON); + msleep_interruptible(200); + } + + /* Restore LED settings */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg); + + return 0; +} + +static int ixgbe_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (adapter->rx_eitr == 0) + ec->rx_coalesce_usecs = 0; + else + ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr; + + if (adapter->tx_eitr == 0) + ec->tx_coalesce_usecs = 0; + else + ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr; + + ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit; + return 0; +} + +static int ixgbe_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) || + ((ec->rx_coalesce_usecs > 0) && + (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS))) + return -EINVAL; + if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) || + ((ec->tx_coalesce_usecs > 0) && + (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS))) + return -EINVAL; + + /* convert to rate of irq's per second */ + if (ec->rx_coalesce_usecs == 0) + adapter->rx_eitr = 0; + else + adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs); + + if (ec->tx_coalesce_usecs == 0) + adapter->tx_eitr = 0; + else + adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs); + + if (ec->tx_max_coalesced_frames_irq) + adapter->tx_ring[0].work_limit = + ec->tx_max_coalesced_frames_irq; + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_up(adapter); + } + + return 0; +} + + +static struct ethtool_ops ixgbe_ethtool_ops = { + .get_settings = ixgbe_get_settings, + .set_settings = ixgbe_set_settings, + .get_drvinfo = ixgbe_get_drvinfo, + .get_regs_len = ixgbe_get_regs_len, + .get_regs = ixgbe_get_regs, + .get_wol = ixgbe_get_wol, + .nway_reset = ixgbe_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = ixgbe_get_eeprom_len, + .get_eeprom = ixgbe_get_eeprom, + .get_ringparam = ixgbe_get_ringparam, + .set_ringparam = ixgbe_set_ringparam, + .get_pauseparam = ixgbe_get_pauseparam, + .set_pauseparam = ixgbe_set_pauseparam, + .get_rx_csum = ixgbe_get_rx_csum, + .set_rx_csum = ixgbe_set_rx_csum, + .get_tx_csum = ixgbe_get_tx_csum, + .set_tx_csum = ixgbe_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_msglevel = ixgbe_get_msglevel, + .set_msglevel = ixgbe_set_msglevel, + .get_tso = ethtool_op_get_tso, + .set_tso = ixgbe_set_tso, + .get_strings = ixgbe_get_strings, + .phys_id = ixgbe_phys_id, + .get_stats_count = ixgbe_get_stats_count, + .get_ethtool_stats = ixgbe_get_ethtool_stats, + .get_coalesce = ixgbe_get_coalesce, + .set_coalesce = ixgbe_set_coalesce, +}; + +void ixgbe_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops); +} diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c new file mode 100644 index 000000000000..a08a46224c28 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -0,0 +1,2873 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ixgbe.h" +#include "ixgbe_common.h" + +char ixgbe_driver_name[] = "ixgbe"; +static char ixgbe_driver_string[] = + "Intel(R) 10 Gigabit PCI Express Network Driver"; + +#define DRV_VERSION "1.1.18" +char ixgbe_driver_version[] = DRV_VERSION; +static char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation."; + +static const struct ixgbe_info *ixgbe_info_tbl[] = { + [board_82598AF] = &ixgbe_82598AF_info, + [board_82598EB] = &ixgbe_82598EB_info, + [board_82598AT] = &ixgbe_82598AT_info, +}; + +/* ixgbe_pci_tbl - PCI Device ID Table + * + * Wildcard entries (PCI_ANY_ID) should come last + * Last entry must be all 0s + * + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, + * Class, Class Mask, private data (not used) } + */ +static struct pci_device_id ixgbe_pci_tbl[] = { + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT), + board_82598AF }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), + board_82598AF }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT_DUAL_PORT), + board_82598AT }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), + board_82598EB }, + + /* required last entry */ + {0, } +}; +MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl); + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +#define DEFAULT_DEBUG_LEVEL_SHIFT 3 + + +#ifdef DEBUG +/** + * ixgbe_get_hw_dev_name - return device name string + * used by hardware layer to print debugging information + **/ +char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw) +{ + struct ixgbe_adapter *adapter = hw->back; + struct net_device *netdev = adapter->netdev; + return netdev->name; +} +#endif + +static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry, + u8 msix_vector) +{ + u32 ivar, index; + + msix_vector |= IXGBE_IVAR_ALLOC_VAL; + index = (int_alloc_entry >> 2) & 0x1F; + ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR(index)); + ivar &= ~(0xFF << (8 * (int_alloc_entry & 0x3))); + ivar |= (msix_vector << (8 * (int_alloc_entry & 0x3))); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); +} + +static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, + struct ixgbe_tx_buffer + *tx_buffer_info) +{ + if (tx_buffer_info->dma) { + pci_unmap_page(adapter->pdev, + tx_buffer_info->dma, + tx_buffer_info->length, PCI_DMA_TODEVICE); + tx_buffer_info->dma = 0; + } + if (tx_buffer_info->skb) { + dev_kfree_skb_any(tx_buffer_info->skb); + tx_buffer_info->skb = NULL; + } + /* tx_buffer_info must be completely set up in the transmit path */ +} + +static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, + unsigned int eop, + union ixgbe_adv_tx_desc *eop_desc) +{ + /* Detect a transmit hang in hardware, this serializes the + * check with the clearing of time_stamp and movement of i */ + adapter->detect_tx_hung = false; + if (tx_ring->tx_buffer_info[eop].dma && + time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) && + !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) { + /* detected Tx unit hang */ + DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" + " TDH <%x>\n" + " TDT <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "tx_buffer_info[next_to_clean]\n" + " time_stamp <%lx>\n" + " next_to_watch <%x>\n" + " jiffies <%lx>\n" + " next_to_watch.status <%x>\n", + readl(adapter->hw.hw_addr + tx_ring->head), + readl(adapter->hw.hw_addr + tx_ring->tail), + tx_ring->next_to_use, + tx_ring->next_to_clean, + tx_ring->tx_buffer_info[eop].time_stamp, + eop, jiffies, eop_desc->wb.status); + return true; + } + + return false; +} + +/** + * ixgbe_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + **/ +static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) +{ + struct net_device *netdev = adapter->netdev; + union ixgbe_adv_tx_desc *tx_desc, *eop_desc; + struct ixgbe_tx_buffer *tx_buffer_info; + unsigned int i, eop; + bool cleaned = false; + int count = 0; + + i = tx_ring->next_to_clean; + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); + while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) { + for (cleaned = false; !cleaned;) { + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + cleaned = (i == eop); + + tx_ring->stats.bytes += tx_buffer_info->length; + ixgbe_unmap_and_free_tx_resource(adapter, + tx_buffer_info); + tx_desc->wb.status = 0; + + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_ring->stats.packets++; + + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); + + /* weight of a sort for tx, avoid endless transmit cleanup */ + if (count++ >= tx_ring->work_limit) + break; + } + + tx_ring->next_to_clean = i; + +#define TX_WAKE_THRESHOLD 32 + spin_lock(&tx_ring->tx_lock); + + if (cleaned && netif_carrier_ok(netdev) && + (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) && + !test_bit(__IXGBE_DOWN, &adapter->state)) + netif_wake_queue(netdev); + + spin_unlock(&tx_ring->tx_lock); + + if (adapter->detect_tx_hung) + if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc)) + netif_stop_queue(netdev); + + if (count >= tx_ring->work_limit) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value); + + return cleaned; +} + +/** + * ixgbe_receive_skb - Send a completed packet up the stack + * @adapter: board private structure + * @skb: packet to send up + * @is_vlan: packet has a VLAN tag + * @tag: VLAN tag from descriptor + **/ +static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, + struct sk_buff *skb, bool is_vlan, + u16 tag) +{ + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { + if (adapter->vlgrp && is_vlan) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); + else + netif_receive_skb(skb); + } else { + + if (adapter->vlgrp && is_vlan) + vlan_hwaccel_rx(skb, adapter->vlgrp, tag); + else + netif_rx(skb); + } +} + +static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, + u32 status_err, + struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + /* Ignore Checksum bit is set */ + if ((status_err & IXGBE_RXD_STAT_IXSM) || + !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) + return; + /* TCP/UDP checksum error bit is set */ + if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) { + /* let the stack verify checksum errors */ + adapter->hw_csum_rx_error++; + return; + } + /* It must be a TCP or UDP packet with a valid checksum */ + if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_rx_good++; +} + +/** + * ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split + * @adapter: address of board private structure + **/ +static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union ixgbe_adv_rx_desc *rx_desc; + struct ixgbe_rx_buffer *rx_buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = adapter->rx_buf_len + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + + while (cleaned_count--) { + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + + if (!rx_buffer_info->page && + (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) { + rx_buffer_info->page = alloc_page(GFP_ATOMIC); + if (!rx_buffer_info->page) { + adapter->alloc_rx_page_failed++; + goto no_buffers; + } + rx_buffer_info->page_dma = + pci_map_page(pdev, rx_buffer_info->page, + 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); + } + + if (!rx_buffer_info->skb) { + skb = netdev_alloc_skb(netdev, bufsz); + + if (!skb) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + + /* + * 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); + + rx_buffer_info->skb = skb; + rx_buffer_info->dma = pci_map_single(pdev, skb->data, + bufsz, + PCI_DMA_FROMDEVICE); + } + /* Refresh the desc even if buffer_addrs didn't change because + * each write-back erases this info. */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + rx_desc->read.pkt_addr = + cpu_to_le64(rx_buffer_info->page_dma); + rx_desc->read.hdr_addr = + cpu_to_le64(rx_buffer_info->dma); + } else { + rx_desc->read.pkt_addr = + cpu_to_le64(rx_buffer_info->dma); + } + + i++; + if (i == rx_ring->count) + i = 0; + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + } +no_buffers: + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (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->tail); + } +} + +static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring, + int *work_done, int work_to_do) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union ixgbe_adv_rx_desc *rx_desc, *next_rxd; + struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer; + struct sk_buff *skb; + unsigned int i; + u32 upper_len, len, staterr; + u16 hdr_info, vlan_tag; + bool is_vlan, cleaned = false; + int cleaned_count = 0; + + i = rx_ring->next_to_clean; + upper_len = 0; + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + is_vlan = (staterr & IXGBE_RXD_STAT_VP); + vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); + + while (staterr & IXGBE_RXD_STAT_DD) { + if (*work_done >= work_to_do) + break; + (*work_done)++; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + hdr_info = + le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info); + len = + ((hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >> + IXGBE_RXDADV_HDRBUFLEN_SHIFT); + if (hdr_info & IXGBE_RXDADV_SPH) + adapter->rx_hdr_split++; + if (len > IXGBE_RX_HDR_SIZE) + len = IXGBE_RX_HDR_SIZE; + upper_len = le16_to_cpu(rx_desc->wb.upper.length); + } else + len = le16_to_cpu(rx_desc->wb.upper.length); + + cleaned = true; + skb = rx_buffer_info->skb; + prefetch(skb->data - NET_IP_ALIGN); + rx_buffer_info->skb = NULL; + + if (len && !skb_shinfo(skb)->nr_frags) { + pci_unmap_single(pdev, rx_buffer_info->dma, + adapter->rx_buf_len + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); + skb_put(skb, len); + } + + if (upper_len) { + pci_unmap_page(pdev, rx_buffer_info->page_dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, + rx_buffer_info->page, 0, upper_len); + rx_buffer_info->page = NULL; + + skb->len += upper_len; + skb->data_len += upper_len; + skb->truesize += upper_len; + } + + i++; + if (i == rx_ring->count) + i = 0; + next_buffer = &rx_ring->rx_buffer_info[i]; + + next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i); + prefetch(next_rxd); + + cleaned_count++; + if (staterr & IXGBE_RXD_STAT_EOP) { + rx_ring->stats.packets++; + rx_ring->stats.bytes += skb->len; + } else { + rx_buffer_info->skb = next_buffer->skb; + rx_buffer_info->dma = next_buffer->dma; + next_buffer->skb = skb; + adapter->non_eop_descs++; + goto next_desc; + } + + if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) { + dev_kfree_skb_irq(skb); + goto next_desc; + } + + ixgbe_rx_checksum(adapter, staterr, skb); + skb->protocol = eth_type_trans(skb, netdev); + ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag); + netdev->last_rx = jiffies; + +next_desc: + rx_desc->wb.upper.status_error = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) { + ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + rx_buffer_info = next_buffer; + + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + is_vlan = (staterr & IXGBE_RXD_STAT_VP); + vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); + } + + rx_ring->next_to_clean = i; + cleaned_count = IXGBE_DESC_UNUSED(rx_ring); + + if (cleaned_count) + ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); + + return cleaned; +} + +#define IXGBE_MAX_INTR 10 +/** + * ixgbe_configure_msix - Configure MSI-X hardware + * @adapter: board private structure + * + * ixgbe_configure_msix sets up the hardware to properly generate MSI-X + * interrupts. + **/ +static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) +{ + int i, vector = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), + IXGBE_MSIX_VECTOR(vector)); + writel(EITR_INTS_PER_SEC_TO_REG(adapter->tx_eitr), + adapter->hw.hw_addr + adapter->tx_ring[i].itr_register); + vector++; + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(i), + IXGBE_MSIX_VECTOR(vector)); + writel(EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr), + adapter->hw.hw_addr + adapter->rx_ring[i].itr_register); + vector++; + } + + vector = adapter->num_tx_queues + adapter->num_rx_queues; + ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, + IXGBE_MSIX_VECTOR(vector)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(vector), 1950); +} + +static irqreturn_t ixgbe_msix_lsc(int irq, void *data) +{ + struct net_device *netdev = data; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + + if (eicr & IXGBE_EICR_LSC) { + adapter->lsc_int++; + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies); + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + + return IRQ_HANDLED; +} + +static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) +{ + struct ixgbe_ring *txr = data; + struct ixgbe_adapter *adapter = txr->adapter; + + ixgbe_clean_tx_irq(adapter, txr); + + return IRQ_HANDLED; +} + +static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) +{ + struct ixgbe_ring *rxr = data; + struct ixgbe_adapter *adapter = rxr->adapter; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->eims_value); + netif_rx_schedule(adapter->netdev, &adapter->napi); + return IRQ_HANDLED; +} + +static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) +{ + struct ixgbe_adapter *adapter = container_of(napi, + struct ixgbe_adapter, napi); + struct net_device *netdev = adapter->netdev; + int work_done = 0; + struct ixgbe_ring *rxr = adapter->rx_ring; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(netdev)) + goto quit_polling; + + ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget); + + /* If no Tx and not enough Rx work done, exit the polling mode */ + if ((work_done < budget) || !netif_running(netdev)) { +quit_polling: + netif_rx_complete(netdev, napi); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, + rxr->eims_value); + } + + return work_done; +} + +/** + * ixgbe_setup_msix - Initialize MSI-X interrupts + * + * ixgbe_setup_msix allocates MSI-X vectors and requests + * interrutps from the kernel. + **/ +static int ixgbe_setup_msix(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i, int_vector = 0, err = 0; + int max_msix_count; + + /* +1 for the LSC interrupt */ + max_msix_count = adapter->num_rx_queues + adapter->num_tx_queues + 1; + adapter->msix_entries = kcalloc(max_msix_count, + sizeof(struct msix_entry), GFP_KERNEL); + if (!adapter->msix_entries) + return -ENOMEM; + + for (i = 0; i < max_msix_count; i++) + adapter->msix_entries[i].entry = i; + + err = pci_enable_msix(adapter->pdev, adapter->msix_entries, + max_msix_count); + if (err) + goto out; + + for (i = 0; i < adapter->num_tx_queues; i++) { + sprintf(adapter->tx_ring[i].name, "%s-tx%d", netdev->name, i); + err = request_irq(adapter->msix_entries[int_vector].vector, + &ixgbe_msix_clean_tx, + 0, + adapter->tx_ring[i].name, + &(adapter->tx_ring[i])); + if (err) { + DPRINTK(PROBE, ERR, + "request_irq failed for MSIX interrupt " + "Error: %d\n", err); + goto release_irqs; + } + adapter->tx_ring[i].eims_value = + (1 << IXGBE_MSIX_VECTOR(int_vector)); + adapter->tx_ring[i].itr_register = IXGBE_EITR(int_vector); + int_vector++; + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + if (strlen(netdev->name) < (IFNAMSIZ - 5)) + sprintf(adapter->rx_ring[i].name, + "%s-rx%d", netdev->name, i); + else + memcpy(adapter->rx_ring[i].name, + netdev->name, IFNAMSIZ); + err = request_irq(adapter->msix_entries[int_vector].vector, + &ixgbe_msix_clean_rx, 0, + adapter->rx_ring[i].name, + &(adapter->rx_ring[i])); + if (err) { + DPRINTK(PROBE, ERR, + "request_irq failed for MSIX interrupt " + "Error: %d\n", err); + goto release_irqs; + } + + adapter->rx_ring[i].eims_value = + (1 << IXGBE_MSIX_VECTOR(int_vector)); + adapter->rx_ring[i].itr_register = IXGBE_EITR(int_vector); + int_vector++; + } + + sprintf(adapter->lsc_name, "%s-lsc", netdev->name); + err = request_irq(adapter->msix_entries[int_vector].vector, + &ixgbe_msix_lsc, 0, adapter->lsc_name, netdev); + if (err) { + DPRINTK(PROBE, ERR, + "request_irq for msix_lsc failed: %d\n", err); + goto release_irqs; + } + + /* FIXME: implement netif_napi_remove() instead */ + adapter->napi.poll = ixgbe_clean_rxonly; + adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; + return 0; + +release_irqs: + int_vector--; + for (; int_vector >= adapter->num_tx_queues; int_vector--) + free_irq(adapter->msix_entries[int_vector].vector, + &(adapter->rx_ring[int_vector - + adapter->num_tx_queues])); + + for (; int_vector >= 0; int_vector--) + free_irq(adapter->msix_entries[int_vector].vector, + &(adapter->tx_ring[int_vector])); +out: + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; + return err; +} + +/** + * ixgbe_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + **/ +static irqreturn_t ixgbe_intr(int irq, void *data) +{ + struct net_device *netdev = data; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr; + + eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + + if (!eicr) + return IRQ_NONE; /* Not our interrupt */ + + if (eicr & IXGBE_EICR_LSC) { + adapter->lsc_int++; + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies); + } + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + /* Disable interrupts and register for poll. The flush of the + * posted write is intentionally left out. */ + atomic_inc(&adapter->irq_sem); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); + __netif_rx_schedule(netdev, &adapter->napi); + } + + return IRQ_HANDLED; +} + +/** + * ixgbe_request_irq - initialize interrupts + * @adapter: board private structure + * + * Attempts to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +static int ixgbe_request_irq(struct ixgbe_adapter *adapter, u32 *num_rx_queues) +{ + struct net_device *netdev = adapter->netdev; + int flags, err; + irqreturn_t(*handler) (int, void *) = &ixgbe_intr; + + flags = IRQF_SHARED; + + err = ixgbe_setup_msix(adapter); + if (!err) + goto request_done; + + /* + * if we can't do MSI-X, fall through and try MSI + * No need to reallocate memory since we're decreasing the number of + * queues. We just won't use the other ones, also it is freed correctly + * on ixgbe_remove. + */ + *num_rx_queues = 1; + + /* do MSI */ + err = pci_enable_msi(adapter->pdev); + if (!err) { + adapter->flags |= IXGBE_FLAG_MSI_ENABLED; + flags &= ~IRQF_SHARED; + handler = &ixgbe_intr; + } + + err = request_irq(adapter->pdev->irq, handler, flags, + netdev->name, netdev); + if (err) + DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err); + +request_done: + return err; +} + +static void ixgbe_free_irq(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + free_irq(adapter->msix_entries[i].vector, + &(adapter->tx_ring[i])); + for (i = 0; i < adapter->num_rx_queues; i++) + free_irq(adapter->msix_entries[i + + adapter->num_tx_queues].vector, + &(adapter->rx_ring[i])); + i = adapter->num_rx_queues + adapter->num_tx_queues; + free_irq(adapter->msix_entries[i].vector, netdev); + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; + return; + } + + free_irq(adapter->pdev->irq, netdev); + if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED; + } +} + +/** + * ixgbe_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ +static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); + IXGBE_WRITE_FLUSH(&adapter->hw); + synchronize_irq(adapter->pdev->irq); +} + +/** + * ixgbe_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ +static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) +{ + if (atomic_dec_and_test(&adapter->irq_sem)) { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, + (IXGBE_EIMS_ENABLE_MASK & + ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC))); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, + IXGBE_EIMS_ENABLE_MASK); + IXGBE_WRITE_FLUSH(&adapter->hw); + } +} + +/** + * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts + * + **/ +static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter) +{ + int i; + struct ixgbe_hw *hw = &adapter->hw; + + if (adapter->rx_eitr) + IXGBE_WRITE_REG(hw, IXGBE_EITR(0), + EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr)); + + /* for re-triggering the interrupt in non-NAPI mode */ + adapter->rx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0)); + adapter->tx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0)); + + ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0); + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), i); +} + +/** + * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ +static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) +{ + u64 tdba; + struct ixgbe_hw *hw = &adapter->hw; + u32 i, tdlen; + + /* Setup the HW Tx Head and Tail descriptor pointers */ + for (i = 0; i < adapter->num_tx_queues; i++) { + tdba = adapter->tx_ring[i].dma; + tdlen = adapter->tx_ring[i].count * + sizeof(union ixgbe_adv_tx_desc); + IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), (tdba & DMA_32BIT_MASK)); + IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), tdlen); + IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0); + adapter->tx_ring[i].head = IXGBE_TDH(i); + adapter->tx_ring[i].tail = IXGBE_TDT(i); + } + + IXGBE_WRITE_REG(hw, IXGBE_TIPG, IXGBE_TIPG_FIBER_DEFAULT); +} + +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) + +#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 +/** + * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ +static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) +{ + u64 rdba; + struct ixgbe_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + u32 rdlen, rxctrl, rxcsum; + u32 random[10]; + u32 reta, mrqc; + int i; + u32 fctrl, hlreg0; + u32 srrctl; + u32 pages; + + /* Decide whether to use packet split mode or not */ + if (netdev->mtu > ETH_DATA_LEN) + adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; + else + adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; + + /* Set the RX buffer length according to the mode */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + adapter->rx_buf_len = IXGBE_RX_HDR_SIZE; + } else { + if (netdev->mtu <= ETH_DATA_LEN) + adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; + else + adapter->rx_buf_len = ALIGN(max_frame, 1024); + } + + fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + fctrl |= IXGBE_FCTRL_BAM; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); + + hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); + if (adapter->netdev->mtu <= ETH_DATA_LEN) + hlreg0 &= ~IXGBE_HLREG0_JUMBOEN; + else + hlreg0 |= IXGBE_HLREG0_JUMBOEN; + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); + + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + + srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0)); + srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; + srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; + srrctl |= ((IXGBE_RX_HDR_SIZE << + IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & + IXGBE_SRRCTL_BSIZEHDR_MASK); + } else { + srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; + + if (adapter->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) + srrctl |= + IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + else + srrctl |= + adapter->rx_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl); + + rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); + /* disable receives while setting up the descriptors */ + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + for (i = 0; i < adapter->num_rx_queues; i++) { + rdba = adapter->rx_ring[i].dma; + IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & DMA_32BIT_MASK)); + IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), rdlen); + IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); + adapter->rx_ring[i].head = IXGBE_RDH(i); + adapter->rx_ring[i].tail = IXGBE_RDT(i); + } + + if (adapter->num_rx_queues > 1) { + /* Random 40bytes used as random key in RSS hash function */ + get_random_bytes(&random[0], 40); + + switch (adapter->num_rx_queues) { + case 8: + case 4: + /* Bits [3:0] in each byte refers the Rx queue no */ + reta = 0x00010203; + break; + case 2: + reta = 0x00010001; + break; + default: + reta = 0x00000000; + break; + } + + /* Fill out redirection table */ + for (i = 0; i < 32; i++) { + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i, reta); + if (adapter->num_rx_queues > 4) { + i++; + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i, + 0x04050607); + } + } + + /* Fill out hash function seeds */ + for (i = 0; i < 10; i++) + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RSSRK(0), i, random[i]); + + mrqc = IXGBE_MRQC_RSSEN + /* Perform hash on these packet types */ + | IXGBE_MRQC_RSS_FIELD_IPV4 + | IXGBE_MRQC_RSS_FIELD_IPV4_TCP + | IXGBE_MRQC_RSS_FIELD_IPV4_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX + | IXGBE_MRQC_RSS_FIELD_IPV6 + | IXGBE_MRQC_RSS_FIELD_IPV6_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; + IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); + + /* Multiqueue and packet checksumming are mutually exclusive. */ + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + rxcsum |= IXGBE_RXCSUM_PCSD; + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); + } else { + /* Enable Receive Checksum Offload for TCP and UDP */ + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + if (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED) { + /* Enable IPv4 payload checksum for UDP fragments + * Must be used in conjunction with packet-split. */ + rxcsum |= IXGBE_RXCSUM_IPPCSE; + } else { + /* don't need to clear IPPCSE as it defaults to 0 */ + } + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); + } + /* Enable Receives */ + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl); + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); +} + +static void ixgbe_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 ctrl; + + ixgbe_irq_disable(adapter); + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); + ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE; + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); + } + + ixgbe_irq_enable(adapter); +} + +static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + /* add VID to filter table */ + ixgbe_set_vfta(&adapter->hw, vid, 0, true); +} + +static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + ixgbe_irq_disable(adapter); + vlan_group_set_device(adapter->vlgrp, vid, NULL); + ixgbe_irq_enable(adapter); + + /* remove VID from filter table */ + ixgbe_set_vfta(&adapter->hw, vid, 0, false); +} + +static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter) +{ + ixgbe_vlan_rx_register(adapter->netdev, adapter->vlgrp); + + if (adapter->vlgrp) { + u16 vid; + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) + continue; + ixgbe_vlan_rx_add_vid(adapter->netdev, vid); + } + } +} + +/** + * ixgbe_set_multi - 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, + * promiscuous mode, and all-multi behavior. + **/ +static void ixgbe_set_multi(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + struct dev_mc_list *mc_ptr; + u8 *mta_list; + u32 fctrl; + int i; + + /* Check for Promiscuous and All Multicast modes */ + + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + + if (netdev->flags & IFF_PROMISC) { + fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + } else if (netdev->flags & IFF_ALLMULTI) { + fctrl |= IXGBE_FCTRL_MPE; + fctrl &= ~IXGBE_FCTRL_UPE; + } else { + fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + + if (netdev->mc_count) { + mta_list = kcalloc(netdev->mc_count, ETH_ALEN, GFP_ATOMIC); + if (!mta_list) + return; + + /* Shared function expects packed array of only addresses. */ + mc_ptr = netdev->mc_list; + + for (i = 0; i < netdev->mc_count; i++) { + if (!mc_ptr) + break; + memcpy(mta_list + (i * ETH_ALEN), mc_ptr->dmi_addr, + ETH_ALEN); + mc_ptr = mc_ptr->next; + } + + ixgbe_update_mc_addr_list(hw, mta_list, i, 0); + kfree(mta_list); + } else { + ixgbe_update_mc_addr_list(hw, NULL, 0, 0); + } + +} + +static void ixgbe_configure(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i; + + ixgbe_set_multi(netdev); + + ixgbe_restore_vlan(adapter); + + ixgbe_configure_tx(adapter); + ixgbe_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i], + (adapter->rx_ring[i].count - 1)); +} + +static int ixgbe_up_complete(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i; + u32 gpie = 0; + struct ixgbe_hw *hw = &adapter->hw; + u32 txdctl, rxdctl, mhadd; + int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + + if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED | + IXGBE_FLAG_MSI_ENABLED)) { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME | + IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD); + } else { + /* MSI only */ + gpie = (IXGBE_GPIE_EIAME | + IXGBE_GPIE_PBA_SUPPORT); + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_GPIE, gpie); + gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE); + } + + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); + + if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) { + mhadd &= ~IXGBE_MHADD_MFS_MASK; + mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT; + + IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); + } + + for (i = 0; i < adapter->num_tx_queues; i++) { + txdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(i)); + txdctl |= IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(i), txdctl); + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + rxdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(i)); + rxdctl |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(i), rxdctl); + } + /* enable all receives */ + rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxdctl); + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) + ixgbe_configure_msix(adapter); + else + ixgbe_configure_msi_and_legacy(adapter); + + clear_bit(__IXGBE_DOWN, &adapter->state); + napi_enable(&adapter->napi); + ixgbe_irq_enable(adapter); + + /* bring the link up in the watchdog, this could race with our first + * link up interrupt but shouldn't be a problem */ + mod_timer(&adapter->watchdog_timer, jiffies); + return 0; +} + +int ixgbe_up(struct ixgbe_adapter *adapter) +{ + /* hardware has been reset, we need to reload some things */ + ixgbe_configure(adapter); + + return ixgbe_up_complete(adapter); +} + +void ixgbe_reset(struct ixgbe_adapter *adapter) +{ + if (ixgbe_init_hw(&adapter->hw)) + DPRINTK(PROBE, ERR, "Hardware Error\n"); + + /* reprogram the RAR[0] in case user changed it. */ + ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); + +} + +#ifdef CONFIG_PM +static int ixgbe_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 err, num_rx_queues = adapter->num_rx_queues; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "ixgbe: Cannot enable PCI device from " \ + "suspend\n"); + return err; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + if (netif_running(netdev)) { + err = ixgbe_request_irq(adapter, &num_rx_queues); + if (err) + return err; + } + + ixgbe_reset(adapter); + + if (netif_running(netdev)) + ixgbe_up(adapter); + + netif_device_attach(netdev); + + return 0; +} +#endif + +/** + * ixgbe_clean_rx_ring - Free Rx Buffers per Queue + * @adapter: board private structure + * @rx_ring: ring to free buffers from + **/ +static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Rx ring sk_buffs */ + + for (i = 0; i < rx_ring->count; i++) { + struct ixgbe_rx_buffer *rx_buffer_info; + + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + if (rx_buffer_info->dma) { + pci_unmap_single(pdev, rx_buffer_info->dma, + adapter->rx_buf_len, + PCI_DMA_FROMDEVICE); + rx_buffer_info->dma = 0; + } + if (rx_buffer_info->skb) { + dev_kfree_skb(rx_buffer_info->skb); + rx_buffer_info->skb = NULL; + } + if (!rx_buffer_info->page) + continue; + pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; + + put_page(rx_buffer_info->page); + rx_buffer_info->page = NULL; + } + + size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; + memset(rx_ring->rx_buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(rx_ring->desc, 0, rx_ring->size); + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + writel(0, adapter->hw.hw_addr + rx_ring->head); + writel(0, adapter->hw.hw_addr + rx_ring->tail); +} + +/** + * ixgbe_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + * @tx_ring: ring to be cleaned + **/ +static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) +{ + struct ixgbe_tx_buffer *tx_buffer_info; + unsigned long size; + unsigned int i; + + /* Free all the Tx ring sk_buffs */ + + for (i = 0; i < tx_ring->count; i++) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info); + } + + size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count; + memset(tx_ring->tx_buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(tx_ring->desc, 0, tx_ring->size); + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + writel(0, adapter->hw.hw_addr + tx_ring->head); + writel(0, adapter->hw.hw_addr + tx_ring->tail); +} + +/** + * ixgbe_clean_all_tx_rings - Free Tx Buffers for all queues + * @adapter: board private structure + **/ +static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbe_clean_tx_ring(adapter, &adapter->tx_ring[i]); +} + +/** + * ixgbe_clean_all_rx_rings - Free Rx Buffers for all queues + * @adapter: board private structure + **/ +static void ixgbe_clean_all_rx_rings(struct ixgbe_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_clean_rx_ring(adapter, &adapter->rx_ring[i]); +} + +void ixgbe_down(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u32 rxctrl; + + /* signal that we are down to the interrupt handler */ + set_bit(__IXGBE_DOWN, &adapter->state); + + /* disable receives */ + rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, + rxctrl & ~IXGBE_RXCTRL_RXEN); + + netif_tx_disable(netdev); + + /* disable transmits in the hardware */ + + /* flush both disables */ + IXGBE_WRITE_FLUSH(&adapter->hw); + msleep(10); + + ixgbe_irq_disable(adapter); + + napi_disable(&adapter->napi); + del_timer_sync(&adapter->watchdog_timer); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + ixgbe_reset(adapter); + ixgbe_clean_all_tx_rings(adapter); + ixgbe_clean_all_rx_rings(adapter); + +} + +static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_PM + int retval = 0; +#endif + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_free_irq(adapter); + } + +#ifdef CONFIG_PM + retval = pci_save_state(pdev); + if (retval) + return retval; +#endif + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static void ixgbe_shutdown(struct pci_dev *pdev) +{ + ixgbe_suspend(pdev, PMSG_SUSPEND); +} + +/** + * ixgbe_clean - NAPI Rx polling callback + * @adapter: board private structure + **/ +static int ixgbe_clean(struct napi_struct *napi, int budget) +{ + struct ixgbe_adapter *adapter = container_of(napi, + struct ixgbe_adapter, napi); + struct net_device *netdev = adapter->netdev; + int tx_cleaned = 0, work_done = 0; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(adapter->netdev)) + goto quit_polling; + + /* In non-MSIX case, there is no multi-Tx/Rx queue */ + tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring); + ixgbe_clean_rx_irq(adapter, &adapter->rx_ring[0], &work_done, + budget); + + /* If no Tx and not enough Rx work done, exit the polling mode */ + if ((!tx_cleaned && (work_done < budget)) || + !netif_running(adapter->netdev)) { +quit_polling: + netif_rx_complete(netdev, napi); + ixgbe_irq_enable(adapter); + } + + return work_done; +} + +/** + * ixgbe_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void ixgbe_tx_timeout(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->reset_task); +} + +static void ixgbe_reset_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter; + adapter = container_of(work, struct ixgbe_adapter, reset_task); + + adapter->tx_timeout_count++; + + ixgbe_down(adapter); + ixgbe_up(adapter); +} + +/** + * ixgbe_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + * + * We allocate one ring per queue at run-time since we don't know the + * number of queues at compile-time. The polling_netdev array is + * intended for Multiqueue, but should work fine with a single queue. + **/ +static int __devinit ixgbe_alloc_queues(struct ixgbe_adapter *adapter) +{ + int i; + + adapter->tx_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!adapter->tx_ring) + return -ENOMEM; + + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].count = IXGBE_DEFAULT_TXD; + + adapter->rx_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + return -ENOMEM; + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + adapter->rx_ring[i].adapter = adapter; + adapter->rx_ring[i].itr_register = IXGBE_EITR(i); + adapter->rx_ring[i].count = IXGBE_DEFAULT_RXD; + } + + return 0; +} + +/** + * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) + * @adapter: board private structure to initialize + * + * ixgbe_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ +static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + + /* default flow control settings */ + hw->fc.original_type = ixgbe_fc_full; + hw->fc.type = ixgbe_fc_full; + + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; + if (hw->mac.ops.reset(hw)) { + dev_err(&pdev->dev, "HW Init failed\n"); + return -EIO; + } + if (hw->phy.ops.setup_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true, + false)) { + dev_err(&pdev->dev, "Link Speed setup failed\n"); + return -EIO; + } + + /* initialize eeprom parameters */ + if (ixgbe_init_eeprom(hw)) { + dev_err(&pdev->dev, "EEPROM initialization failed\n"); + return -EIO; + } + + /* Set the default values */ + adapter->num_rx_queues = IXGBE_DEFAULT_RXQ; + adapter->num_tx_queues = 1; + adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED; + + if (ixgbe_alloc_queues(adapter)) { + dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + + atomic_set(&adapter->irq_sem, 1); + set_bit(__IXGBE_DOWN, &adapter->state); + + return 0; +} + +/** + * ixgbe_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * @txdr: tx descriptor ring (for a specific queue) to setup + * + * Return 0 on success, negative on failure + **/ +int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *txdr) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct ixgbe_tx_buffer) * txdr->count; + txdr->tx_buffer_info = vmalloc(size); + if (!txdr->tx_buffer_info) { + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the transmit descriptor ring\n"); + return -ENOMEM; + } + memset(txdr->tx_buffer_info, 0, size); + + /* round up to nearest 4K */ + txdr->size = txdr->count * sizeof(union ixgbe_adv_tx_desc); + txdr->size = ALIGN(txdr->size, 4096); + + txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); + if (!txdr->desc) { + vfree(txdr->tx_buffer_info); + DPRINTK(PROBE, ERR, + "Memory allocation failed for the tx desc ring\n"); + return -ENOMEM; + } + + txdr->adapter = adapter; + txdr->next_to_use = 0; + txdr->next_to_clean = 0; + txdr->work_limit = txdr->count; + spin_lock_init(&txdr->tx_lock); + + return 0; +} + +/** + * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: board private structure + * @rxdr: rx descriptor ring (for a specific queue) to setup + * + * Returns 0 on success, negative on failure + **/ +int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rxdr) +{ + struct pci_dev *pdev = adapter->pdev; + int size, desc_len; + + size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; + rxdr->rx_buffer_info = vmalloc(size); + if (!rxdr->rx_buffer_info) { + DPRINTK(PROBE, ERR, + "vmalloc allocation failed for the rx desc ring\n"); + return -ENOMEM; + } + memset(rxdr->rx_buffer_info, 0, size); + + desc_len = sizeof(union ixgbe_adv_rx_desc); + + /* Round up to nearest 4K */ + rxdr->size = rxdr->count * desc_len; + rxdr->size = ALIGN(rxdr->size, 4096); + + rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); + + if (!rxdr->desc) { + DPRINTK(PROBE, ERR, + "Memory allocation failed for the rx desc ring\n"); + vfree(rxdr->rx_buffer_info); + return -ENOMEM; + } + + rxdr->next_to_clean = 0; + rxdr->next_to_use = 0; + rxdr->adapter = adapter; + + return 0; +} + +/** + * ixgbe_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * @tx_ring: Tx descriptor ring for a specific queue + * + * Free all transmit software resources + **/ +static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + ixgbe_clean_tx_ring(adapter, tx_ring); + + vfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); + + tx_ring->desc = NULL; +} + +/** + * ixgbe_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + **/ +static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); +} + +/** + * ixgbe_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * @rx_ring: ring to clean the resources from + * + * Free all receive software resources + **/ +static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + ixgbe_clean_rx_ring(adapter, rx_ring); + + vfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); + + rx_ring->desc = NULL; +} + +/** + * ixgbe_free_all_rx_resources - Free Rx Resources for All Queues + * @adapter: board private structure + * + * Free all receive software resources + **/ +static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); +} + +/** + * ixgbe_setup_all_tx_resources - wrapper to allocate Tx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ +static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Tx Queue %u failed\n", i); + break; + } + } + + return err; +} + +/** + * ixgbe_setup_all_rx_resources - wrapper to allocate Rx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Rx Queue %u failed\n", i); + break; + } + } + + return err; +} + +/** + * ixgbe_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ +static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + + if ((max_frame < (ETH_ZLEN + ETH_FCS_LEN)) || + (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE)) + return -EINVAL; + + netdev->mtu = new_mtu; + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_up(adapter); + } + + return 0; +} + +/** + * ixgbe_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int ixgbe_open(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int err; + u32 ctrl_ext; + u32 num_rx_queues = adapter->num_rx_queues; + + /* Let firmware know the driver has taken over */ + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, + ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD); + +try_intr_reinit: + /* allocate transmit descriptors */ + err = ixgbe_setup_all_tx_resources(adapter); + if (err) + goto err_setup_tx; + + if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { + num_rx_queues = 1; + adapter->num_rx_queues = num_rx_queues; + } + + /* allocate receive descriptors */ + err = ixgbe_setup_all_rx_resources(adapter); + if (err) + goto err_setup_rx; + + ixgbe_configure(adapter); + + err = ixgbe_request_irq(adapter, &num_rx_queues); + if (err) + goto err_req_irq; + + /* ixgbe_request might have reduced num_rx_queues */ + if (num_rx_queues < adapter->num_rx_queues) { + /* We didn't get MSI-X, so we need to release everything, + * set our Rx queue count to num_rx_queues, and redo the + * whole init process. + */ + ixgbe_free_irq(adapter); + if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED; + } + ixgbe_free_all_rx_resources(adapter); + ixgbe_free_all_tx_resources(adapter); + adapter->num_rx_queues = num_rx_queues; + + /* Reset the hardware, and start over. */ + ixgbe_reset(adapter); + + goto try_intr_reinit; + } + + err = ixgbe_up_complete(adapter); + if (err) + goto err_up; + + return 0; + +err_up: + ixgbe_free_irq(adapter); +err_req_irq: + ixgbe_free_all_rx_resources(adapter); +err_setup_rx: + ixgbe_free_all_tx_resources(adapter); +err_setup_tx: + ixgbe_reset(adapter); + + return err; +} + +/** + * ixgbe_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int ixgbe_close(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 ctrl_ext; + + ixgbe_down(adapter); + ixgbe_free_irq(adapter); + + ixgbe_free_all_tx_resources(adapter); + ixgbe_free_all_rx_resources(adapter); + + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, + ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD); + + return 0; +} + +/** + * ixgbe_update_stats - Update the board statistics counters. + * @adapter: board private structure + **/ +void ixgbe_update_stats(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u64 good_rx, missed_rx, bprc; + + adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); + good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC); + missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7)); + adapter->stats.gprc += (good_rx - missed_rx); + + adapter->stats.mpc[0] += missed_rx; + adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); + bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); + adapter->stats.bprc += bprc; + adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); + adapter->stats.mprc -= bprc; + adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC); + adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); + adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); + adapter->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); + adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); + adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); + adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); + + adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); + adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); + adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC); + adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); + adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); + adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); + adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0)); + adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); + adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); + adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); + adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH); + adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); + adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); + adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); + adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); + adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); + adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); + adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); + adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); + adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); + + /* Fill out the OS statistics structure */ + adapter->net_stats.rx_packets = adapter->stats.gprc; + adapter->net_stats.tx_packets = adapter->stats.gptc; + adapter->net_stats.rx_bytes = adapter->stats.gorc; + adapter->net_stats.tx_bytes = adapter->stats.gotc; + adapter->net_stats.multicast = adapter->stats.mprc; + + /* Rx Errors */ + adapter->net_stats.rx_errors = adapter->stats.crcerrs + + adapter->stats.rlec; + adapter->net_stats.rx_dropped = 0; + adapter->net_stats.rx_length_errors = adapter->stats.rlec; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0]; + +} + +/** + * ixgbe_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void ixgbe_watchdog(unsigned long data) +{ + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; + struct net_device *netdev = adapter->netdev; + bool link_up; + u32 link_speed = 0; + + adapter->hw.phy.ops.check(&adapter->hw, &(link_speed), &link_up); + + if (link_up) { + if (!netif_carrier_ok(netdev)) { + u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS); +#define FLOW_RX (frctl & IXGBE_FCTRL_RFCE) +#define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X) + DPRINTK(LINK, INFO, "NIC Link is Up %s, " + "Flow Control: %s\n", + (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? + "10 Gbps" : + (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? + "1 Gpbs" : "unknown speed")), + ((FLOW_RX && FLOW_TX) ? "RX/TX" : + (FLOW_RX ? "RX" : + (FLOW_TX ? "TX" : "None")))); + + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } else { + /* Force detection of hung controller */ + adapter->detect_tx_hung = true; + } + } else { + if (netif_carrier_ok(netdev)) { + DPRINTK(LINK, INFO, "NIC Link is Down\n"); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + + ixgbe_update_stats(adapter); + + /* Reset the timer */ + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 2 * HZ)); +} + +#define IXGBE_MAX_TXD_PWR 14 +#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) + +/* Tx Descriptors needed, worst case */ +#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \ + (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) +#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ + MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ + +static int ixgbe_tso(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, struct sk_buff *skb, + u32 tx_flags, u8 *hdr_len) +{ + struct ixgbe_adv_tx_context_desc *context_desc; + unsigned int i; + int err; + struct ixgbe_tx_buffer *tx_buffer_info; + u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; + u32 mss_l4len_idx = 0, l4len; + *hdr_len = 0; + + if (skb_is_gso(skb)) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) + return err; + } + l4len = tcp_hdrlen(skb); + *hdr_len += l4len; + + if (skb->protocol == ntohs(ETH_P_IP)) { + struct iphdr *iph = ip_hdr(skb); + iph->tot_len = 0; + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + adapter->hw_tso_ctxt++; + } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); + adapter->hw_tso6_ctxt++; + } + + i = tx_ring->next_to_use; + + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i); + + /* VLAN MACLEN IPLEN */ + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + vlan_macip_lens |= + (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + vlan_macip_lens |= ((skb_network_offset(skb)) << + IXGBE_ADVTXD_MACLEN_SHIFT); + *hdr_len += skb_network_offset(skb); + vlan_macip_lens |= + (skb_transport_header(skb) - skb_network_header(skb)); + *hdr_len += + (skb_transport_header(skb) - skb_network_header(skb)); + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = 0; + + /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ + type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | + IXGBE_ADVTXD_DTYP_CTXT); + + if (skb->protocol == ntohs(ETH_P_IP)) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); + + /* MSS L4LEN IDX */ + mss_l4len_idx |= + (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT); + mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT); + context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); + + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return true; + } + return false; +} + +static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, + struct sk_buff *skb, u32 tx_flags) +{ + struct ixgbe_adv_tx_context_desc *context_desc; + unsigned int i; + struct ixgbe_tx_buffer *tx_buffer_info; + u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; + + if (skb->ip_summed == CHECKSUM_PARTIAL || + (tx_flags & IXGBE_TX_FLAGS_VLAN)) { + i = tx_ring->next_to_use; + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i); + + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + vlan_macip_lens |= + (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + vlan_macip_lens |= (skb_network_offset(skb) << + IXGBE_ADVTXD_MACLEN_SHIFT); + if (skb->ip_summed == CHECKSUM_PARTIAL) + vlan_macip_lens |= (skb_transport_header(skb) - + skb_network_header(skb)); + + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = 0; + + type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | + IXGBE_ADVTXD_DTYP_CTXT); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb->protocol == ntohs(ETH_P_IP)) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + + if (skb->sk->sk_protocol == IPPROTO_TCP) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + } + + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); + context_desc->mss_l4len_idx = 0; + + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + adapter->hw_csum_tx_good++; + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return true; + } + return false; +} + +static int ixgbe_tx_map(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, + struct sk_buff *skb, unsigned int first) +{ + struct ixgbe_tx_buffer *tx_buffer_info; + unsigned int len = skb->len; + unsigned int offset = 0, size, count = 0, i; + unsigned int nr_frags = skb_shinfo(skb)->nr_frags; + unsigned int f; + + len -= skb->data_len; + + i = tx_ring->next_to_use; + + while (len) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); + + tx_buffer_info->length = size; + tx_buffer_info->dma = pci_map_single(adapter->pdev, + skb->data + offset, + size, PCI_DMA_TODEVICE); + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + offset = frag->page_offset; + + while (len) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); + + tx_buffer_info->length = size; + tx_buffer_info->dma = pci_map_page(adapter->pdev, + frag->page, + offset, + size, PCI_DMA_TODEVICE); + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + } + if (i == 0) + i = tx_ring->count - 1; + else + i = i - 1; + tx_ring->tx_buffer_info[i].skb = skb; + tx_ring->tx_buffer_info[first].next_to_watch = i; + + return count; +} + +static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, + int tx_flags, int count, u32 paylen, u8 hdr_len) +{ + union ixgbe_adv_tx_desc *tx_desc = NULL; + struct ixgbe_tx_buffer *tx_buffer_info; + u32 olinfo_status = 0, cmd_type_len = 0; + unsigned int i; + u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS; + + cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA; + + cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT; + + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; + + if (tx_flags & IXGBE_TX_FLAGS_TSO) { + cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + + olinfo_status |= IXGBE_TXD_POPTS_TXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + if (tx_flags & IXGBE_TX_FLAGS_IPV4) + olinfo_status |= IXGBE_TXD_POPTS_IXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + } else if (tx_flags & IXGBE_TX_FLAGS_CSUM) + olinfo_status |= IXGBE_TXD_POPTS_TXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT); + + i = tx_ring->next_to_use; + while (count--) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); + tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma); + tx_desc->read.cmd_type_len = + cpu_to_le32(cmd_type_len | tx_buffer_info->length); + tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); + + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd); + + /* + * 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(); + + tx_ring->next_to_use = i; + writel(i, adapter->hw.hw_addr + tx_ring->tail); +} + +static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_ring *tx_ring; + unsigned int len = skb->len; + unsigned int first; + unsigned int tx_flags = 0; + unsigned long flags = 0; + u8 hdr_len; + int tso; + unsigned int mss = 0; + int count = 0; + unsigned int f; + unsigned int nr_frags = skb_shinfo(skb)->nr_frags; + len -= skb->data_len; + + tx_ring = adapter->tx_ring; + + if (skb->len <= 0) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + mss = skb_shinfo(skb)->gso_size; + + if (mss) + count++; + else if (skb->ip_summed == CHECKSUM_PARTIAL) + count++; + + count += TXD_USE_COUNT(len); + for (f = 0; f < nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); + + spin_lock_irqsave(&tx_ring->tx_lock, flags); + if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) { + adapter->tx_busy++; + netif_stop_queue(netdev); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + return NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= IXGBE_TX_FLAGS_VLAN; + tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT); + } + + if (skb->protocol == ntohs(ETH_P_IP)) + tx_flags |= IXGBE_TX_FLAGS_IPV4; + first = tx_ring->next_to_use; + tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); + if (tso < 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (tso) + tx_flags |= IXGBE_TX_FLAGS_TSO; + else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && + (skb->ip_summed == CHECKSUM_PARTIAL)) + tx_flags |= IXGBE_TX_FLAGS_CSUM; + + ixgbe_tx_queue(adapter, tx_ring, tx_flags, + ixgbe_tx_map(adapter, tx_ring, skb, first), + skb->len, hdr_len); + + netdev->trans_start = jiffies; + + spin_lock_irqsave(&tx_ring->tx_lock, flags); + /* Make sure there is space in the ring for the next send. */ + if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED) + netif_stop_queue(netdev); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + + return NETDEV_TX_OK; +} + +/** + * ixgbe_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ +static struct net_device_stats *ixgbe_get_stats(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + /* only return the current stats */ + return &adapter->net_stats; +} + +/** + * ixgbe_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int ixgbe_set_mac(struct net_device *netdev, void *p) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); + + ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void ixgbe_netpoll(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + disable_irq(adapter->pdev->irq); + adapter->flags |= IXGBE_FLAG_IN_NETPOLL; + ixgbe_intr(adapter->pdev->irq, netdev); + adapter->flags &= ~IXGBE_FLAG_IN_NETPOLL; + enable_irq(adapter->pdev->irq); +} +#endif + +/** + * ixgbe_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in ixgbe_pci_tbl + * + * Returns 0 on success, negative on failure + * + * ixgbe_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +static int __devinit ixgbe_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct ixgbe_adapter *adapter = NULL; + struct ixgbe_hw *hw; + const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data]; + unsigned long mmio_start, mmio_len; + static int cards_found; + int i, err, pci_using_dac; + u16 link_status, link_speed, link_width; + u32 part_num; + + err = pci_enable_device(pdev); + if (err) + return err; + + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && + !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + dev_err(&pdev->dev, "No usable DMA " + "configuration, aborting\n"); + goto err_dma; + } + } + pci_using_dac = 0; + } + + err = pci_request_regions(pdev, ixgbe_driver_name); + if (err) { + dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err); + goto err_pci_reg; + } + + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct ixgbe_adapter)); + if (!netdev) { + err = -ENOMEM; + goto err_alloc_etherdev; + } + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + + adapter->netdev = netdev; + adapter->pdev = pdev; + hw = &adapter->hw; + hw->back = adapter; + adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + + hw->hw_addr = ioremap(mmio_start, mmio_len); + if (!hw->hw_addr) { + err = -EIO; + goto err_ioremap; + } + + for (i = 1; i <= 5; i++) { + if (pci_resource_len(pdev, i) == 0) + continue; + } + + netdev->open = &ixgbe_open; + netdev->stop = &ixgbe_close; + netdev->hard_start_xmit = &ixgbe_xmit_frame; + netdev->get_stats = &ixgbe_get_stats; + netdev->set_multicast_list = &ixgbe_set_multi; + netdev->set_mac_address = &ixgbe_set_mac; + netdev->change_mtu = &ixgbe_change_mtu; + ixgbe_set_ethtool_ops(netdev); + netdev->tx_timeout = &ixgbe_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netif_napi_add(netdev, &adapter->napi, ixgbe_clean, 64); + netdev->vlan_rx_register = ixgbe_vlan_rx_register; + netdev->vlan_rx_add_vid = ixgbe_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = ixgbe_netpoll; +#endif + strcpy(netdev->name, pci_name(pdev)); + + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len; + + adapter->bd_number = cards_found; + + /* PCI config space info */ + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->revision_id = pdev->revision; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; + + /* Setup hw api */ + memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops)); + memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); + + err = ii->get_invariants(hw); + if (err) + goto err_hw_init; + + /* setup the private structure */ + err = ixgbe_sw_init(adapter); + if (err) + goto err_sw_init; + + netdev->features = NETIF_F_SG | + NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; + + netdev->features |= NETIF_F_TSO; + + netdev->features |= NETIF_F_TSO6; + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + + /* make sure the EEPROM is good */ + if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { + dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } + + memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len); + memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len); + + if (ixgbe_validate_mac_addr(netdev->dev_addr)) { + err = -EIO; + goto err_eeprom; + } + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &ixgbe_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + + INIT_WORK(&adapter->reset_task, ixgbe_reset_task); + + /* initialize default flow control settings */ + hw->fc.original_type = ixgbe_fc_full; + hw->fc.type = ixgbe_fc_full; + hw->fc.high_water = IXGBE_DEFAULT_FCRTH; + hw->fc.low_water = IXGBE_DEFAULT_FCRTL; + hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; + + /* Interrupt Throttle Rate */ + adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS); + adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS); + + /* print bus type/speed/width info */ + pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status); + link_speed = link_status & IXGBE_PCI_LINK_SPEED; + link_width = link_status & IXGBE_PCI_LINK_WIDTH; + dev_info(&pdev->dev, "(PCI Express:%s:%s) " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" : + (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" : + "Unknown"), + ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" : + (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" : + (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" : + (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" : + "Unknown"), + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + ixgbe_read_part_num(hw, &part_num); + dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n", + hw->mac.type, hw->phy.type, + (part_num >> 8), (part_num & 0xff)); + + /* reset the hardware with the new settings */ + ixgbe_start_hw(hw); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + + dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n"); + cards_found++; + return 0; + +err_register: +err_hw_init: +err_sw_init: +err_eeprom: + iounmap(hw->hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * ixgbe_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * ixgbe_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit ixgbe_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + set_bit(__IXGBE_DOWN, &adapter->state); + del_timer_sync(&adapter->watchdog_timer); + + flush_scheduled_work(); + + unregister_netdev(netdev); + + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + + iounmap(adapter->hw.hw_addr); + pci_release_regions(pdev); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +/** + * ixgbe_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev->priv; + + netif_device_detach(netdev); + + if (netif_running(netdev)) + ixgbe_down(adapter); + pci_disable_device(pdev); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * ixgbe_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev->priv; + + if (pci_enable_device(pdev)) { + DPRINTK(PROBE, ERR, + "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + ixgbe_reset(adapter); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * ixgbe_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void ixgbe_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev->priv; + + if (netif_running(netdev)) { + if (ixgbe_up(adapter)) { + DPRINTK(PROBE, INFO, "ixgbe_up failed after reset\n"); + return; + } + } + + netif_device_attach(netdev); + +} + +static struct pci_error_handlers ixgbe_err_handler = { + .error_detected = ixgbe_io_error_detected, + .slot_reset = ixgbe_io_slot_reset, + .resume = ixgbe_io_resume, +}; + +static struct pci_driver ixgbe_driver = { + .name = ixgbe_driver_name, + .id_table = ixgbe_pci_tbl, + .probe = ixgbe_probe, + .remove = __devexit_p(ixgbe_remove), +#ifdef CONFIG_PM + .suspend = ixgbe_suspend, + .resume = ixgbe_resume, +#endif + .shutdown = ixgbe_shutdown, + .err_handler = &ixgbe_err_handler +}; + +/** + * ixgbe_init_module - Driver Registration Routine + * + * ixgbe_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ +static int __init ixgbe_init_module(void) +{ + int ret; + printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name, + ixgbe_driver_string, ixgbe_driver_version); + + printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright); + + ret = pci_register_driver(&ixgbe_driver); + return ret; +} +module_init(ixgbe_init_module); + +/** + * ixgbe_exit_module - Driver Exit Cleanup Routine + * + * ixgbe_exit_module is called just before the driver is removed + * from memory. + **/ +static void __exit ixgbe_exit_module(void) +{ + pci_unregister_driver(&ixgbe_driver); +} +module_exit(ixgbe_exit_module); + +/* ixgbe_main.c */ diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c new file mode 100644 index 000000000000..8002931ae823 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -0,0 +1,494 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include + +#include "ixgbe_common.h" +#include "ixgbe_phy.h" + +static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); +static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); +static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr); +static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data); + +/** + * ixgbe_identify_phy - Get physical layer module + * @hw: pointer to hardware structure + * + * Determines the physical layer module found on the current adapter. + **/ +s32 ixgbe_identify_phy(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + u32 phy_addr; + + for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { + if (ixgbe_validate_phy_addr(hw, phy_addr)) { + hw->phy.addr = phy_addr; + ixgbe_get_phy_id(hw); + hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); + status = 0; + break; + } + } + return status; +} + +/** + * ixgbe_validate_phy_addr - Determines phy address is valid + * @hw: pointer to hardware structure + * + **/ +static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr) +{ + u16 phy_id = 0; + bool valid = false; + + hw->phy.addr = phy_addr; + ixgbe_read_phy_reg(hw, + IXGBE_MDIO_PHY_ID_HIGH, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id); + + if (phy_id != 0xFFFF && phy_id != 0x0) + valid = true; + + return valid; +} + +/** + * ixgbe_get_phy_id - Get the phy type + * @hw: pointer to hardware structure + * + **/ +static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) +{ + u32 status; + u16 phy_id_high = 0; + u16 phy_id_low = 0; + + status = ixgbe_read_phy_reg(hw, + IXGBE_MDIO_PHY_ID_HIGH, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id_high); + + if (status == 0) { + hw->phy.id = (u32)(phy_id_high << 16); + status = ixgbe_read_phy_reg(hw, + IXGBE_MDIO_PHY_ID_LOW, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id_low); + hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); + hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); + } + + return status; +} + +/** + * ixgbe_get_phy_type_from_id - Get the phy type + * @hw: pointer to hardware structure + * + **/ +static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) +{ + enum ixgbe_phy_type phy_type; + + switch (phy_id) { + case TN1010_PHY_ID: + phy_type = ixgbe_phy_tn; + break; + case QT2022_PHY_ID: + phy_type = ixgbe_phy_qt; + break; + default: + phy_type = ixgbe_phy_unknown; + break; + } + + return phy_type; +} + +/** + * ixgbe_reset_phy - Performs a PHY reset + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reset_phy(struct ixgbe_hw *hw) +{ + /* + * Perform soft PHY reset to the PHY_XS. + * This will cause a soft reset to the PHY + */ + return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, + IXGBE_MDIO_PHY_XS_RESET); +} + +/** + * ixgbe_read_phy_reg - Reads a value from a specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit address of PHY register to read + * @phy_data: Pointer to read data from PHY register + **/ +s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data) +{ + u32 command; + u32 i; + u32 timeout = 10; + u32 data; + s32 status = 0; + u16 gssr; + + if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) + gssr = IXGBE_GSSR_PHY1_SM; + else + gssr = IXGBE_GSSR_PHY0_SM; + + if (ixgbe_acquire_swfw_sync(hw, gssr) != 0) + status = IXGBE_ERR_SWFW_SYNC; + + if (status == 0) { + /* Setup and write the address cycle command */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < timeout; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + hw_dbg(hw, "PHY address command did not complete.\n"); + status = IXGBE_ERR_PHY; + } + + if (status == 0) { + /* + * Address cycle complete, setup and write the read + * command + */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle + * completed. The MDI Command bit will clear when the + * operation is complete + */ + for (i = 0; i < timeout; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + hw_dbg(hw, + "PHY read command didn't complete\n"); + status = IXGBE_ERR_PHY; + } else { + /* + * Read operation is complete. Get the data + * from MSRWD + */ + data = IXGBE_READ_REG(hw, IXGBE_MSRWD); + data >>= IXGBE_MSRWD_READ_DATA_SHIFT; + *phy_data = (u16)(data); + } + } + + ixgbe_release_swfw_sync(hw, gssr); + } + return status; +} + +/** + * ixgbe_write_phy_reg - Writes a value to specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 5 bit device type + * @phy_data: Data to write to the PHY register + **/ +static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data) +{ + u32 command; + u32 i; + u32 timeout = 10; + s32 status = 0; + u16 gssr; + + if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) + gssr = IXGBE_GSSR_PHY1_SM; + else + gssr = IXGBE_GSSR_PHY0_SM; + + if (ixgbe_acquire_swfw_sync(hw, gssr) != 0) + status = IXGBE_ERR_SWFW_SYNC; + + if (status == 0) { + /* Put the data in the MDI single read and write data register*/ + IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); + + /* Setup and write the address cycle command */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < timeout; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { + hw_dbg(hw, "PHY address cmd didn't complete\n"); + break; + } + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) + status = IXGBE_ERR_PHY; + + if (status == 0) { + /* + * Address cycle complete, setup and write the write + * command + */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle + * completed. The MDI Command bit will clear when the + * operation is complete + */ + for (i = 0; i < timeout; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { + hw_dbg(hw, "PHY write command did not " + "complete.\n"); + break; + } + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) + status = IXGBE_ERR_PHY; + } + + ixgbe_release_swfw_sync(hw, gssr); + } + + return status; +} + +/** + * ixgbe_setup_tnx_phy_link - Set and restart autoneg + * @hw: pointer to hardware structure + * + * Restart autonegotiation and PHY and waits for completion. + **/ +s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_NOT_IMPLEMENTED; + u32 time_out; + u32 max_time_out = 10; + u16 autoneg_speed_selection_register = 0x10; + u16 autoneg_restart_mask = 0x0200; + u16 autoneg_complete_mask = 0x0020; + u16 autoneg_reg = 0; + + /* + * Set advertisement settings in PHY based on autoneg_advertised + * settings. If autoneg_advertised = 0, then advertise default values + * txn devices cannot be "forced" to a autoneg 10G and fail. But can + * for a 1G. + */ + ixgbe_read_phy_reg(hw, + autoneg_speed_selection_register, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + + if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL) + autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */ + else + autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */ + + ixgbe_write_phy_reg(hw, + autoneg_speed_selection_register, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + autoneg_reg); + + + /* Restart PHY autonegotiation and wait for completion */ + ixgbe_read_phy_reg(hw, + IXGBE_MDIO_AUTO_NEG_CONTROL, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + + autoneg_reg |= autoneg_restart_mask; + + ixgbe_write_phy_reg(hw, + IXGBE_MDIO_AUTO_NEG_CONTROL, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + autoneg_reg); + + /* Wait for autonegotiation to finish */ + for (time_out = 0; time_out < max_time_out; time_out++) { + udelay(10); + /* Restart PHY autonegotiation and wait for completion */ + status = ixgbe_read_phy_reg(hw, + IXGBE_MDIO_AUTO_NEG_STATUS, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + + autoneg_reg &= autoneg_complete_mask; + if (autoneg_reg == autoneg_complete_mask) { + status = 0; + break; + } + } + + if (time_out == max_time_out) + status = IXGBE_ERR_LINK_SETUP; + + return status; +} + +/** + * ixgbe_check_tnx_phy_link - Determine link and speed status + * @hw: pointer to hardware structure + * + * Reads the VS1 register to determine if link is up and the current speed for + * the PHY. + **/ +s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, + bool *link_up) +{ + s32 status = 0; + u32 time_out; + u32 max_time_out = 10; + u16 phy_link = 0; + u16 phy_speed = 0; + u16 phy_data = 0; + + /* Initialize speed and link to default case */ + *link_up = false; + *speed = IXGBE_LINK_SPEED_10GB_FULL; + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + for (time_out = 0; time_out < max_time_out; time_out++) { + udelay(10); + if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { + *link_up = true; + if (phy_speed == + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) + *speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + } else { + status = ixgbe_read_phy_reg(hw, + IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + &phy_data); + phy_link = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; + phy_speed = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; + } + } + + return status; +} + +/** + * ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: true if autonegotiation enabled + **/ +s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, + bool autoneg, + bool autoneg_wait_to_complete) +{ + /* + * Clear autoneg_advertised and set new values 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; + + /* Setup link based on the new speed settings */ + ixgbe_setup_tnx_phy_link(hw); + + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h new file mode 100644 index 000000000000..199e8f670f3a --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -0,0 +1,50 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_PHY_H_ +#define _IXGBE_PHY_H_ + +#include "ixgbe_type.h" + +s32 ixgbe_init_shared_code_phy(struct ixgbe_hw *hw); +s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw); +s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); +s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, + bool autoneg_wait_to_complete); +s32 ixgbe_identify_phy(struct ixgbe_hw *hw); +s32 ixgbe_reset_phy(struct ixgbe_hw *hw); +s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data); + +/* PHY specific */ +s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw); +s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); +s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, + bool autoneg_wait_to_complete); + +#endif /* _IXGBE_PHY_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h new file mode 100644 index 000000000000..fdcde16a2a99 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -0,0 +1,1332 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_TYPE_H_ +#define _IXGBE_TYPE_H_ + +#include + +/* Vendor ID */ +#define IXGBE_INTEL_VENDOR_ID 0x8086 + +/* Device IDs */ +#define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 +#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 +#define IXGBE_DEV_ID_82598AT_DUAL_PORT 0x10C8 +#define IXGBE_DEV_ID_82598EB_CX4 0x10DD + +/* General Registers */ +#define IXGBE_CTRL 0x00000 +#define IXGBE_STATUS 0x00008 +#define IXGBE_CTRL_EXT 0x00018 +#define IXGBE_ESDP 0x00020 +#define IXGBE_EODSDP 0x00028 +#define IXGBE_LEDCTL 0x00200 +#define IXGBE_FRTIMER 0x00048 +#define IXGBE_TCPTIMER 0x0004C + +/* NVM Registers */ +#define IXGBE_EEC 0x10010 +#define IXGBE_EERD 0x10014 +#define IXGBE_FLA 0x1001C +#define IXGBE_EEMNGCTL 0x10110 +#define IXGBE_EEMNGDATA 0x10114 +#define IXGBE_FLMNGCTL 0x10118 +#define IXGBE_FLMNGDATA 0x1011C +#define IXGBE_FLMNGCNT 0x10120 +#define IXGBE_FLOP 0x1013C +#define IXGBE_GRC 0x10200 + +/* Interrupt Registers */ +#define IXGBE_EICR 0x00800 +#define IXGBE_EICS 0x00808 +#define IXGBE_EIMS 0x00880 +#define IXGBE_EIMC 0x00888 +#define IXGBE_EIAC 0x00810 +#define IXGBE_EIAM 0x00890 +#define IXGBE_EITR(_i) (0x00820 + ((_i) * 4)) /* 0x820-0x86c */ +#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */ +#define IXGBE_MSIXT 0x00000 /* MSI-X Table. 0x0000 - 0x01C */ +#define IXGBE_MSIXPBA 0x02000 /* MSI-X Pending bit array */ +#define IXGBE_PBACL 0x11068 +#define IXGBE_GPIE 0x00898 + +/* Flow Control Registers */ +#define IXGBE_PFCTOP 0x03008 +#define IXGBE_FCTTV(_i) (0x03200 + ((_i) * 4)) /* 4 of these (0-3) */ +#define IXGBE_FCRTL(_i) (0x03220 + ((_i) * 8)) /* 8 of these (0-7) */ +#define IXGBE_FCRTH(_i) (0x03260 + ((_i) * 8)) /* 8 of these (0-7) */ +#define IXGBE_FCRTV 0x032A0 +#define IXGBE_TFCS 0x0CE00 + +/* Receive DMA Registers */ +#define IXGBE_RDBAL(_i) (0x01000 + ((_i) * 0x40)) /* 64 of each (0-63)*/ +#define IXGBE_RDBAH(_i) (0x01004 + ((_i) * 0x40)) +#define IXGBE_RDLEN(_i) (0x01008 + ((_i) * 0x40)) +#define IXGBE_RDH(_i) (0x01010 + ((_i) * 0x40)) +#define IXGBE_RDT(_i) (0x01018 + ((_i) * 0x40)) +#define IXGBE_RXDCTL(_i) (0x01028 + ((_i) * 0x40)) +#define IXGBE_RSCCTL(_i) (0x0102C + ((_i) * 0x40)) +#define IXGBE_SRRCTL(_i) (0x02100 + ((_i) * 4)) + /* array of 16 (0x02100-0x0213C) */ +#define IXGBE_DCA_RXCTRL(_i) (0x02200 + ((_i) * 4)) + /* array of 16 (0x02200-0x0223C) */ +#define IXGBE_RDRXCTL 0x02F00 +#define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4)) + /* 8 of these 0x03C00 - 0x03C1C */ +#define IXGBE_RXCTRL 0x03000 +#define IXGBE_DROPEN 0x03D04 +#define IXGBE_RXPBSIZE_SHIFT 10 + +/* Receive Registers */ +#define IXGBE_RXCSUM 0x05000 +#define IXGBE_RFCTL 0x05008 +#define IXGBE_MTA(_i) (0x05200 + ((_i) * 4)) + /* Multicast Table Array - 128 entries */ +#define IXGBE_RAL(_i) (0x05400 + ((_i) * 8)) /* 16 of these (0-15) */ +#define IXGBE_RAH(_i) (0x05404 + ((_i) * 8)) /* 16 of these (0-15) */ +#define IXGBE_PSRTYPE 0x05480 + /* 0x5480-0x54BC Packet split receive type */ +#define IXGBE_VFTA(_i) (0x0A000 + ((_i) * 4)) + /* array of 4096 1-bit vlan filters */ +#define IXGBE_VFTAVIND(_j, _i) (0x0A200 + ((_j) * 0x200) + ((_i) * 4)) + /*array of 4096 4-bit vlan vmdq indicies */ +#define IXGBE_FCTRL 0x05080 +#define IXGBE_VLNCTRL 0x05088 +#define IXGBE_MCSTCTRL 0x05090 +#define IXGBE_MRQC 0x05818 +#define IXGBE_VMD_CTL 0x0581C +#define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_IMIRVP 0x05AC0 +#define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ +#define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ + +/* Transmit DMA registers */ +#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40))/* 32 of these (0-31)*/ +#define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40)) +#define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40)) +#define IXGBE_TDH(_i) (0x06010 + ((_i) * 0x40)) +#define IXGBE_TDT(_i) (0x06018 + ((_i) * 0x40)) +#define IXGBE_TXDCTL(_i) (0x06028 + ((_i) * 0x40)) +#define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40)) +#define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40)) +#define IXGBE_DTXCTL 0x07E00 +#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) + /* there are 16 of these (0-15) */ +#define IXGBE_TIPG 0x0CB00 +#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) *0x04)) + /* there are 8 of these */ +#define IXGBE_MNGTXMAP 0x0CD10 +#define IXGBE_TIPG_FIBER_DEFAULT 3 +#define IXGBE_TXPBSIZE_SHIFT 10 + +/* Wake up registers */ +#define IXGBE_WUC 0x05800 +#define IXGBE_WUFC 0x05808 +#define IXGBE_WUS 0x05810 +#define IXGBE_IPAV 0x05838 +#define IXGBE_IP4AT 0x05840 /* IPv4 table 0x5840-0x5858 */ +#define IXGBE_IP6AT 0x05880 /* IPv6 table 0x5880-0x588F */ +#define IXGBE_WUPL 0x05900 +#define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ +#define IXGBE_FHFT 0x09000 /* Flex host filter table 9000-93FC */ + +/* Music registers */ +#define IXGBE_RMCS 0x03D00 +#define IXGBE_DPMCS 0x07F40 +#define IXGBE_PDPMCS 0x0CD00 +#define IXGBE_RUPPBMR 0x050A0 +#define IXGBE_RT2CR(_i) (0x03C20 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_RT2SR(_i) (0x03C40 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_TDTQ2TCCR(_i) (0x0602C + ((_i) * 0x40)) /* 8 of these (0-7) */ +#define IXGBE_TDTQ2TCSR(_i) (0x0622C + ((_i) * 0x40)) /* 8 of these (0-7) */ +#define IXGBE_TDPT2TCCR(_i) (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_TDPT2TCSR(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */ + +/* Stats registers */ +#define IXGBE_CRCERRS 0x04000 +#define IXGBE_ILLERRC 0x04004 +#define IXGBE_ERRBC 0x04008 +#define IXGBE_MSPDC 0x04010 +#define IXGBE_MPC(_i) (0x03FA0 + ((_i) * 4)) /* 8 of these 3FA0-3FBC*/ +#define IXGBE_MLFC 0x04034 +#define IXGBE_MRFC 0x04038 +#define IXGBE_RLEC 0x04040 +#define IXGBE_LXONTXC 0x03F60 +#define IXGBE_LXONRXC 0x0CF60 +#define IXGBE_LXOFFTXC 0x03F68 +#define IXGBE_LXOFFRXC 0x0CF68 +#define IXGBE_PXONTXC(_i) (0x03F00 + ((_i) * 4)) /* 8 of these 3F00-3F1C*/ +#define IXGBE_PXONRXC(_i) (0x0CF00 + ((_i) * 4)) /* 8 of these CF00-CF1C*/ +#define IXGBE_PXOFFTXC(_i) (0x03F20 + ((_i) * 4)) /* 8 of these 3F20-3F3C*/ +#define IXGBE_PXOFFRXC(_i) (0x0CF20 + ((_i) * 4)) /* 8 of these CF20-CF3C*/ +#define IXGBE_PRC64 0x0405C +#define IXGBE_PRC127 0x04060 +#define IXGBE_PRC255 0x04064 +#define IXGBE_PRC511 0x04068 +#define IXGBE_PRC1023 0x0406C +#define IXGBE_PRC1522 0x04070 +#define IXGBE_GPRC 0x04074 +#define IXGBE_BPRC 0x04078 +#define IXGBE_MPRC 0x0407C +#define IXGBE_GPTC 0x04080 +#define IXGBE_GORCL 0x04088 +#define IXGBE_GORCH 0x0408C +#define IXGBE_GOTCL 0x04090 +#define IXGBE_GOTCH 0x04094 +#define IXGBE_RNBC(_i) (0x03FC0 + ((_i) * 4)) /* 8 of these 3FC0-3FDC*/ +#define IXGBE_RUC 0x040A4 +#define IXGBE_RFC 0x040A8 +#define IXGBE_ROC 0x040AC +#define IXGBE_RJC 0x040B0 +#define IXGBE_MNGPRC 0x040B4 +#define IXGBE_MNGPDC 0x040B8 +#define IXGBE_MNGPTC 0x0CF90 +#define IXGBE_TORL 0x040C0 +#define IXGBE_TORH 0x040C4 +#define IXGBE_TPR 0x040D0 +#define IXGBE_TPT 0x040D4 +#define IXGBE_PTC64 0x040D8 +#define IXGBE_PTC127 0x040DC +#define IXGBE_PTC255 0x040E0 +#define IXGBE_PTC511 0x040E4 +#define IXGBE_PTC1023 0x040E8 +#define IXGBE_PTC1522 0x040EC +#define IXGBE_MPTC 0x040F0 +#define IXGBE_BPTC 0x040F4 +#define IXGBE_XEC 0x04120 + +#define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */ +#define IXGBE_TQSMR(_i) (0x07300 + ((_i) * 4)) /* 8 of these */ + +#define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QBRC(_i) (0x01034 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QBTC(_i) (0x06034 + ((_i) * 0x40)) /* 16 of these */ + +/* Management */ +#define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MFUTP(_i) (0x05030 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MANC 0x05820 +#define IXGBE_MFVAL 0x05824 +#define IXGBE_MANC2H 0x05860 +#define IXGBE_MDEF(_i) (0x05890 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MIPAF 0x058B0 +#define IXGBE_MMAL(_i) (0x05910 + ((_i) * 8)) /* 4 of these (0-3) */ +#define IXGBE_MMAH(_i) (0x05914 + ((_i) * 8)) /* 4 of these (0-3) */ +#define IXGBE_FTFT 0x09400 /* 0x9400-0x97FC */ + +/* ARC Subsystem registers */ +#define IXGBE_HICR 0x15F00 +#define IXGBE_FWSTS 0x15F0C +#define IXGBE_HSMC0R 0x15F04 +#define IXGBE_HSMC1R 0x15F08 +#define IXGBE_SWSR 0x15F10 +#define IXGBE_HFDR 0x15FE8 +#define IXGBE_FLEX_MNG 0x15800 /* 0x15800 - 0x15EFC */ + +/* PCI-E registers */ +#define IXGBE_GCR 0x11000 +#define IXGBE_GTV 0x11004 +#define IXGBE_FUNCTAG 0x11008 +#define IXGBE_GLT 0x1100C +#define IXGBE_GSCL_1 0x11010 +#define IXGBE_GSCL_2 0x11014 +#define IXGBE_GSCL_3 0x11018 +#define IXGBE_GSCL_4 0x1101C +#define IXGBE_GSCN_0 0x11020 +#define IXGBE_GSCN_1 0x11024 +#define IXGBE_GSCN_2 0x11028 +#define IXGBE_GSCN_3 0x1102C +#define IXGBE_FACTPS 0x10150 +#define IXGBE_PCIEANACTL 0x11040 +#define IXGBE_SWSM 0x10140 +#define IXGBE_FWSM 0x10148 +#define IXGBE_GSSR 0x10160 +#define IXGBE_MREVID 0x11064 +#define IXGBE_DCA_ID 0x11070 +#define IXGBE_DCA_CTRL 0x11074 + +/* Diagnostic Registers */ +#define IXGBE_RDSTATCTL 0x02C20 +#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */ +#define IXGBE_RDHMPN 0x02F08 +#define IXGBE_RIC_DW0 0x02F10 +#define IXGBE_RIC_DW1 0x02F14 +#define IXGBE_RIC_DW2 0x02F18 +#define IXGBE_RIC_DW3 0x02F1C +#define IXGBE_RDPROBE 0x02F20 +#define IXGBE_TDSTATCTL 0x07C20 +#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */ +#define IXGBE_TDHMPN 0x07F08 +#define IXGBE_TIC_DW0 0x07F10 +#define IXGBE_TIC_DW1 0x07F14 +#define IXGBE_TIC_DW2 0x07F18 +#define IXGBE_TIC_DW3 0x07F1C +#define IXGBE_TDPROBE 0x07F20 +#define IXGBE_TXBUFCTRL 0x0C600 +#define IXGBE_TXBUFDATA0 0x0C610 +#define IXGBE_TXBUFDATA1 0x0C614 +#define IXGBE_TXBUFDATA2 0x0C618 +#define IXGBE_TXBUFDATA3 0x0C61C +#define IXGBE_RXBUFCTRL 0x03600 +#define IXGBE_RXBUFDATA0 0x03610 +#define IXGBE_RXBUFDATA1 0x03614 +#define IXGBE_RXBUFDATA2 0x03618 +#define IXGBE_RXBUFDATA3 0x0361C +#define IXGBE_PCIE_DIAG(_i) (0x11090 + ((_i) * 4)) /* 8 of these */ +#define IXGBE_RFVAL 0x050A4 +#define IXGBE_MDFTC1 0x042B8 +#define IXGBE_MDFTC2 0x042C0 +#define IXGBE_MDFTFIFO1 0x042C4 +#define IXGBE_MDFTFIFO2 0x042C8 +#define IXGBE_MDFTS 0x042CC +#define IXGBE_RXDATAWRPTR(_i) (0x03700 + ((_i) * 4)) /* 8 of these 3700-370C*/ +#define IXGBE_RXDESCWRPTR(_i) (0x03710 + ((_i) * 4)) /* 8 of these 3710-371C*/ +#define IXGBE_RXDATARDPTR(_i) (0x03720 + ((_i) * 4)) /* 8 of these 3720-372C*/ +#define IXGBE_RXDESCRDPTR(_i) (0x03730 + ((_i) * 4)) /* 8 of these 3730-373C*/ +#define IXGBE_TXDATAWRPTR(_i) (0x0C700 + ((_i) * 4)) /* 8 of these C700-C70C*/ +#define IXGBE_TXDESCWRPTR(_i) (0x0C710 + ((_i) * 4)) /* 8 of these C710-C71C*/ +#define IXGBE_TXDATARDPTR(_i) (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/ +#define IXGBE_TXDESCRDPTR(_i) (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/ +#define IXGBE_PCIEECCCTL 0x1106C +#define IXGBE_PBTXECC 0x0C300 +#define IXGBE_PBRXECC 0x03300 +#define IXGBE_GHECCR 0x110B0 + +/* MAC Registers */ +#define IXGBE_PCS1GCFIG 0x04200 +#define IXGBE_PCS1GLCTL 0x04208 +#define IXGBE_PCS1GLSTA 0x0420C +#define IXGBE_PCS1GDBG0 0x04210 +#define IXGBE_PCS1GDBG1 0x04214 +#define IXGBE_PCS1GANA 0x04218 +#define IXGBE_PCS1GANLP 0x0421C +#define IXGBE_PCS1GANNP 0x04220 +#define IXGBE_PCS1GANLPNP 0x04224 +#define IXGBE_HLREG0 0x04240 +#define IXGBE_HLREG1 0x04244 +#define IXGBE_PAP 0x04248 +#define IXGBE_MACA 0x0424C +#define IXGBE_APAE 0x04250 +#define IXGBE_ARD 0x04254 +#define IXGBE_AIS 0x04258 +#define IXGBE_MSCA 0x0425C +#define IXGBE_MSRWD 0x04260 +#define IXGBE_MLADD 0x04264 +#define IXGBE_MHADD 0x04268 +#define IXGBE_TREG 0x0426C +#define IXGBE_PCSS1 0x04288 +#define IXGBE_PCSS2 0x0428C +#define IXGBE_XPCSS 0x04290 +#define IXGBE_SERDESC 0x04298 +#define IXGBE_MACS 0x0429C +#define IXGBE_AUTOC 0x042A0 +#define IXGBE_LINKS 0x042A4 +#define IXGBE_AUTOC2 0x042A8 +#define IXGBE_AUTOC3 0x042AC +#define IXGBE_ANLP1 0x042B0 +#define IXGBE_ANLP2 0x042B4 +#define IXGBE_ATLASCTL 0x04800 + +/* RSCCTL Bit Masks */ +#define IXGBE_RSCCTL_RSCEN 0x01 +#define IXGBE_RSCCTL_MAXDESC_1 0x00 +#define IXGBE_RSCCTL_MAXDESC_4 0x04 +#define IXGBE_RSCCTL_MAXDESC_8 0x08 +#define IXGBE_RSCCTL_MAXDESC_16 0x0C + +/* CTRL Bit Masks */ +#define IXGBE_CTRL_GIO_DIS 0x00000004 /* Global IO Master Disable bit */ +#define IXGBE_CTRL_LNK_RST 0x00000008 /* Link Reset. Resets everything. */ +#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */ + +/* FACTPS */ +#define IXGBE_FACTPS_LFS 0x40000000 /* LAN Function Select */ + +/* MHADD Bit Masks */ +#define IXGBE_MHADD_MFS_MASK 0xFFFF0000 +#define IXGBE_MHADD_MFS_SHIFT 16 + +/* Extended Device Control */ +#define IXGBE_CTRL_EXT_NS_DIS 0x00010000 /* No Snoop disable */ +#define IXGBE_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ +#define IXGBE_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ + +/* Direct Cache Access (DCA) definitions */ +#define IXGBE_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */ +#define IXGBE_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */ + +#define IXGBE_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */ +#define IXGBE_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */ + +#define IXGBE_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */ +#define IXGBE_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */ +#define IXGBE_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */ +#define IXGBE_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */ + +#define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */ +#define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */ +#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */ +#define IXGBE_DCA_MAX_QUEUES_82598 16 /* DCA regs only on 16 queues */ + +/* MSCA Bit Masks */ +#define IXGBE_MSCA_NP_ADDR_MASK 0x0000FFFF /* MDI Address (new protocol) */ +#define IXGBE_MSCA_NP_ADDR_SHIFT 0 +#define IXGBE_MSCA_DEV_TYPE_MASK 0x001F0000 /* Device Type (new protocol) */ +#define IXGBE_MSCA_DEV_TYPE_SHIFT 16 /* Register Address (old protocol */ +#define IXGBE_MSCA_PHY_ADDR_MASK 0x03E00000 /* PHY Address mask */ +#define IXGBE_MSCA_PHY_ADDR_SHIFT 21 /* PHY Address shift*/ +#define IXGBE_MSCA_OP_CODE_MASK 0x0C000000 /* OP CODE mask */ +#define IXGBE_MSCA_OP_CODE_SHIFT 26 /* OP CODE shift */ +#define IXGBE_MSCA_ADDR_CYCLE 0x00000000 /* OP CODE 00 (addr cycle) */ +#define IXGBE_MSCA_WRITE 0x04000000 /* OP CODE 01 (write) */ +#define IXGBE_MSCA_READ 0x08000000 /* OP CODE 10 (read) */ +#define IXGBE_MSCA_READ_AUTOINC 0x0C000000 /* OP CODE 11 (read, auto inc)*/ +#define IXGBE_MSCA_ST_CODE_MASK 0x30000000 /* ST Code mask */ +#define IXGBE_MSCA_ST_CODE_SHIFT 28 /* ST Code shift */ +#define IXGBE_MSCA_NEW_PROTOCOL 0x00000000 /* ST CODE 00 (new protocol) */ +#define IXGBE_MSCA_OLD_PROTOCOL 0x10000000 /* ST CODE 01 (old protocol) */ +#define IXGBE_MSCA_MDI_COMMAND 0x40000000 /* Initiate MDI command */ +#define IXGBE_MSCA_MDI_IN_PROG_EN 0x80000000 /* MDI in progress enable */ + +/* MSRWD bit masks */ +#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF +#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0 +#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000 +#define IXGBE_MSRWD_READ_DATA_SHIFT 16 + +/* Atlas registers */ +#define IXGBE_ATLAS_PDN_LPBK 0x24 +#define IXGBE_ATLAS_PDN_10G 0xB +#define IXGBE_ATLAS_PDN_1G 0xC +#define IXGBE_ATLAS_PDN_AN 0xD + +/* Atlas bit masks */ +#define IXGBE_ATLASCTL_WRITE_CMD 0x00010000 +#define IXGBE_ATLAS_PDN_TX_REG_EN 0x10 +#define IXGBE_ATLAS_PDN_TX_10G_QL_ALL 0xF0 +#define IXGBE_ATLAS_PDN_TX_1G_QL_ALL 0xF0 +#define IXGBE_ATLAS_PDN_TX_AN_QL_ALL 0xF0 + +/* Device Type definitions for new protocol MDIO commands */ +#define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1 +#define IXGBE_MDIO_PCS_DEV_TYPE 0x3 +#define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 +#define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ + +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL 0x0 /* VS1 Control Reg */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS 0x1 /* VS1 Status Reg */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS 0x0008 /* 1 = Link Up */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS 0x0010 /* 0 - 10G, 1 - 1G */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_10G_SPEED 0x0018 +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_1G_SPEED 0x0010 + +#define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */ +#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */ +#define IXGBE_MDIO_PHY_XS_CONTROL 0x0 /* PHY_XS Control Reg */ +#define IXGBE_MDIO_PHY_XS_RESET 0x8000 /* PHY_XS Reset */ +#define IXGBE_MDIO_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/ +#define IXGBE_MDIO_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/ +#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Abilty Reg */ +#define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */ +#define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */ + +#define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0 +#define IXGBE_MAX_PHY_ADDR 32 + +/* PHY IDs*/ +#define TN1010_PHY_ID 0x00A19410 +#define QT2022_PHY_ID 0x0043A400 + +/* General purpose Interrupt Enable */ +#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */ +#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */ +#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ +#define IXGBE_GPIE_EIAME 0x40000000 +#define IXGBE_GPIE_PBA_SUPPORT 0x80000000 + +/* Transmit Flow Control status */ +#define IXGBE_TFCS_TXOFF 0x00000001 +#define IXGBE_TFCS_TXOFF0 0x00000100 +#define IXGBE_TFCS_TXOFF1 0x00000200 +#define IXGBE_TFCS_TXOFF2 0x00000400 +#define IXGBE_TFCS_TXOFF3 0x00000800 +#define IXGBE_TFCS_TXOFF4 0x00001000 +#define IXGBE_TFCS_TXOFF5 0x00002000 +#define IXGBE_TFCS_TXOFF6 0x00004000 +#define IXGBE_TFCS_TXOFF7 0x00008000 + +/* TCP Timer */ +#define IXGBE_TCPTIMER_KS 0x00000100 +#define IXGBE_TCPTIMER_COUNT_ENABLE 0x00000200 +#define IXGBE_TCPTIMER_COUNT_FINISH 0x00000400 +#define IXGBE_TCPTIMER_LOOP 0x00000800 +#define IXGBE_TCPTIMER_DURATION_MASK 0x000000FF + +/* HLREG0 Bit Masks */ +#define IXGBE_HLREG0_TXCRCEN 0x00000001 /* bit 0 */ +#define IXGBE_HLREG0_RXCRCSTRP 0x00000002 /* bit 1 */ +#define IXGBE_HLREG0_JUMBOEN 0x00000004 /* bit 2 */ +#define IXGBE_HLREG0_TXPADEN 0x00000400 /* bit 10 */ +#define IXGBE_HLREG0_TXPAUSEEN 0x00001000 /* bit 12 */ +#define IXGBE_HLREG0_RXPAUSEEN 0x00004000 /* bit 14 */ +#define IXGBE_HLREG0_LPBK 0x00008000 /* bit 15 */ +#define IXGBE_HLREG0_MDCSPD 0x00010000 /* bit 16 */ +#define IXGBE_HLREG0_CONTMDC 0x00020000 /* bit 17 */ +#define IXGBE_HLREG0_CTRLFLTR 0x00040000 /* bit 18 */ +#define IXGBE_HLREG0_PREPEND 0x00F00000 /* bits 20-23 */ +#define IXGBE_HLREG0_PRIPAUSEEN 0x01000000 /* bit 24 */ +#define IXGBE_HLREG0_RXPAUSERECDA 0x06000000 /* bits 25-26 */ +#define IXGBE_HLREG0_RXLNGTHERREN 0x08000000 /* bit 27 */ +#define IXGBE_HLREG0_RXPADSTRIPEN 0x10000000 /* bit 28 */ + +/* VMD_CTL bitmasks */ +#define IXGBE_VMD_CTL_VMDQ_EN 0x00000001 +#define IXGBE_VMD_CTL_VMDQ_FILTER 0x00000002 + +/* RDHMPN and TDHMPN bitmasks */ +#define IXGBE_RDHMPN_RDICADDR 0x007FF800 +#define IXGBE_RDHMPN_RDICRDREQ 0x00800000 +#define IXGBE_RDHMPN_RDICADDR_SHIFT 11 +#define IXGBE_TDHMPN_TDICADDR 0x003FF800 +#define IXGBE_TDHMPN_TDICRDREQ 0x00800000 +#define IXGBE_TDHMPN_TDICADDR_SHIFT 11 + +/* Receive Checksum Control */ +#define IXGBE_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ +#define IXGBE_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ + +/* FCRTL Bit Masks */ +#define IXGBE_FCRTL_XONE 0x80000000 /* bit 31, XON enable */ +#define IXGBE_FCRTH_FCEN 0x80000000 /* Rx Flow control enable */ + +/* PAP bit masks*/ +#define IXGBE_PAP_TXPAUSECNT_MASK 0x0000FFFF /* Pause counter mask */ + +/* RMCS Bit Masks */ +#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recylce Mode enable */ +/* Receive Arbitration Control: 0 Round Robin, 1 DFP */ +#define IXGBE_RMCS_RAC 0x00000004 +#define IXGBE_RMCS_DFP IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */ +#define IXGBE_RMCS_TFCE_802_3X 0x00000008 /* Tx Priority flow control ena */ +#define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */ +#define IXGBE_RMCS_ARBDIS 0x00000040 /* Arbitration disable bit */ + +/* Interrupt register bitmasks */ + +/* Extended Interrupt Cause Read */ +#define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */ +#define IXGBE_EICR_LSC 0x00100000 /* Link Status Change */ +#define IXGBE_EICR_MNG 0x00400000 /* Managability Event Interrupt */ +#define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */ +#define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */ +#define IXGBE_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ +#define IXGBE_EICR_OTHER 0x80000000 /* Interrupt Cause Active */ + +/* Extended Interrupt Cause Set */ +#define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */ +#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */ +#define IXGBE_EICS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +/* Extended Interrupt Mask Set */ +#define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EIMS_DHER IXGBE_EICR_DHER /* Descr Handler Error */ +#define IXGBE_EIMS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +/* Extended Interrupt Mask Clear */ +#define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Error */ +#define IXGBE_EIMC_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +#define IXGBE_EIMS_ENABLE_MASK (\ + IXGBE_EIMS_RTX_QUEUE | \ + IXGBE_EIMS_LSC | \ + IXGBE_EIMS_TCP_TIMER | \ + IXGBE_EIMS_OTHER) + +/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */ +#define IXGBE_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */ +#define IXGBE_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */ +#define IXGBE_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */ +#define IXGBE_IMIREXT_CTRL_URG 0x00002000 /* Check URG bit in header */ +#define IXGBE_IMIREXT_CTRL_ACK 0x00004000 /* Check ACK bit in header */ +#define IXGBE_IMIREXT_CTRL_PSH 0x00008000 /* Check PSH bit in header */ +#define IXGBE_IMIREXT_CTRL_RST 0x00010000 /* Check RST bit in header */ +#define IXGBE_IMIREXT_CTRL_SYN 0x00020000 /* Check SYN bit in header */ +#define IXGBE_IMIREXT_CTRL_FIN 0x00040000 /* Check FIN bit in header */ +#define IXGBE_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of control bits */ + +/* Interrupt clear mask */ +#define IXGBE_IRQ_CLEAR_MASK 0xFFFFFFFF + +/* Interrupt Vector Allocation Registers */ +#define IXGBE_IVAR_REG_NUM 25 +#define IXGBE_IVAR_TXRX_ENTRY 96 +#define IXGBE_IVAR_RX_ENTRY 64 +#define IXGBE_IVAR_RX_QUEUE(_i) (0 + (_i)) +#define IXGBE_IVAR_TX_QUEUE(_i) (64 + (_i)) +#define IXGBE_IVAR_TX_ENTRY 32 + +#define IXGBE_IVAR_TCP_TIMER_INDEX 96 /* 0 based index */ +#define IXGBE_IVAR_OTHER_CAUSES_INDEX 97 /* 0 based index */ + +#define IXGBE_MSIX_VECTOR(_i) (0 + (_i)) + +#define IXGBE_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */ + +/* VLAN Control Bit Masks */ +#define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ +#define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */ +#define IXGBE_VLNCTRL_CFIEN 0x20000000 /* bit 29 */ +#define IXGBE_VLNCTRL_VFE 0x40000000 /* bit 30 */ +#define IXGBE_VLNCTRL_VME 0x80000000 /* bit 31 */ + +#define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */ + +/* STATUS Bit Masks */ +#define IXGBE_STATUS_LAN_ID 0x0000000C /* LAN ID */ +#define IXGBE_STATUS_GIO 0x00080000 /* GIO Master Enable Status */ + +#define IXGBE_STATUS_LAN_ID_0 0x00000000 /* LAN ID 0 */ +#define IXGBE_STATUS_LAN_ID_1 0x00000004 /* LAN ID 1 */ + +/* ESDP Bit Masks */ +#define IXGBE_ESDP_SDP4 0x00000001 /* SDP4 Data Value */ +#define IXGBE_ESDP_SDP5 0x00000002 /* SDP5 Data Value */ +#define IXGBE_ESDP_SDP4_DIR 0x00000004 /* SDP4 IO direction */ +#define IXGBE_ESDP_SDP5_DIR 0x00000008 /* SDP5 IO direction */ + +/* LEDCTL Bit Masks */ +#define IXGBE_LED_IVRT_BASE 0x00000040 +#define IXGBE_LED_BLINK_BASE 0x00000080 +#define IXGBE_LED_MODE_MASK_BASE 0x0000000F +#define IXGBE_LED_OFFSET(_base, _i) (_base << (8 * (_i))) +#define IXGBE_LED_MODE_SHIFT(_i) (8*(_i)) +#define IXGBE_LED_IVRT(_i) IXGBE_LED_OFFSET(IXGBE_LED_IVRT_BASE, _i) +#define IXGBE_LED_BLINK(_i) IXGBE_LED_OFFSET(IXGBE_LED_BLINK_BASE, _i) +#define IXGBE_LED_MODE_MASK(_i) IXGBE_LED_OFFSET(IXGBE_LED_MODE_MASK_BASE, _i) + +/* LED modes */ +#define IXGBE_LED_LINK_UP 0x0 +#define IXGBE_LED_LINK_10G 0x1 +#define IXGBE_LED_MAC 0x2 +#define IXGBE_LED_FILTER 0x3 +#define IXGBE_LED_LINK_ACTIVE 0x4 +#define IXGBE_LED_LINK_1G 0x5 +#define IXGBE_LED_ON 0xE +#define IXGBE_LED_OFF 0xF + +/* AUTOC Bit Masks */ +#define IXGBE_AUTOC_KX4_SUPP 0x80000000 +#define IXGBE_AUTOC_KX_SUPP 0x40000000 +#define IXGBE_AUTOC_PAUSE 0x30000000 +#define IXGBE_AUTOC_RF 0x08000000 +#define IXGBE_AUTOC_PD_TMR 0x06000000 +#define IXGBE_AUTOC_AN_RX_LOOSE 0x01000000 +#define IXGBE_AUTOC_AN_RX_DRIFT 0x00800000 +#define IXGBE_AUTOC_AN_RX_ALIGN 0x007C0000 +#define IXGBE_AUTOC_AN_RESTART 0x00001000 +#define IXGBE_AUTOC_FLU 0x00000001 +#define IXGBE_AUTOC_LMS_SHIFT 13 +#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) + +#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200 +#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180 +#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7 +#define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9 +#define IXGBE_AUTOC_10G_XAUI (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_10G_KX4 (0x1 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_10G_CX4 (0x2 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_1G_BX (0x0 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_1G_KX (0x1 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT) + +/* LINKS Bit Masks */ +#define IXGBE_LINKS_KX_AN_COMP 0x80000000 +#define IXGBE_LINKS_UP 0x40000000 +#define IXGBE_LINKS_SPEED 0x20000000 +#define IXGBE_LINKS_MODE 0x18000000 +#define IXGBE_LINKS_RX_MODE 0x06000000 +#define IXGBE_LINKS_TX_MODE 0x01800000 +#define IXGBE_LINKS_XGXS_EN 0x00400000 +#define IXGBE_LINKS_PCS_1G_EN 0x00200000 +#define IXGBE_LINKS_1G_AN_EN 0x00100000 +#define IXGBE_LINKS_KX_AN_IDLE 0x00080000 +#define IXGBE_LINKS_1G_SYNC 0x00040000 +#define IXGBE_LINKS_10G_ALIGN 0x00020000 +#define IXGBE_LINKS_10G_LANE_SYNC 0x00017000 +#define IXGBE_LINKS_TL_FAULT 0x00001000 +#define IXGBE_LINKS_SIGNAL 0x00000F00 + +#define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ + +/* SW Semaphore Register bitmasks */ +#define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define IXGBE_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ + +/* GSSR definitions */ +#define IXGBE_GSSR_EEP_SM 0x0001 +#define IXGBE_GSSR_PHY0_SM 0x0002 +#define IXGBE_GSSR_PHY1_SM 0x0004 +#define IXGBE_GSSR_MAC_CSR_SM 0x0008 +#define IXGBE_GSSR_FLASH_SM 0x0010 + +/* EEC Register */ +#define IXGBE_EEC_SK 0x00000001 /* EEPROM Clock */ +#define IXGBE_EEC_CS 0x00000002 /* EEPROM Chip Select */ +#define IXGBE_EEC_DI 0x00000004 /* EEPROM Data In */ +#define IXGBE_EEC_DO 0x00000008 /* EEPROM Data Out */ +#define IXGBE_EEC_FWE_MASK 0x00000030 /* FLASH Write Enable */ +#define IXGBE_EEC_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define IXGBE_EEC_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define IXGBE_EEC_FWE_SHIFT 4 +#define IXGBE_EEC_REQ 0x00000040 /* EEPROM Access Request */ +#define IXGBE_EEC_GNT 0x00000080 /* EEPROM Access Grant */ +#define IXGBE_EEC_PRES 0x00000100 /* EEPROM Present */ +#define IXGBE_EEC_ARD 0x00000200 /* EEPROM Auto Read Done */ +/* EEPROM Addressing bits based on type (0-small, 1-large) */ +#define IXGBE_EEC_ADDR_SIZE 0x00000400 +#define IXGBE_EEC_SIZE 0x00007800 /* EEPROM Size */ + +#define IXGBE_EEC_SIZE_SHIFT 11 +#define IXGBE_EEPROM_WORD_SIZE_SHIFT 6 +#define IXGBE_EEPROM_OPCODE_BITS 8 + +/* Checksum and EEPROM pointers */ +#define IXGBE_EEPROM_CHECKSUM 0x3F +#define IXGBE_EEPROM_SUM 0xBABA +#define IXGBE_PCIE_ANALOG_PTR 0x03 +#define IXGBE_ATLAS0_CONFIG_PTR 0x04 +#define IXGBE_ATLAS1_CONFIG_PTR 0x05 +#define IXGBE_PCIE_GENERAL_PTR 0x06 +#define IXGBE_PCIE_CONFIG0_PTR 0x07 +#define IXGBE_PCIE_CONFIG1_PTR 0x08 +#define IXGBE_CORE0_PTR 0x09 +#define IXGBE_CORE1_PTR 0x0A +#define IXGBE_MAC0_PTR 0x0B +#define IXGBE_MAC1_PTR 0x0C +#define IXGBE_CSR0_CONFIG_PTR 0x0D +#define IXGBE_CSR1_CONFIG_PTR 0x0E +#define IXGBE_FW_PTR 0x0F +#define IXGBE_PBANUM0_PTR 0x15 +#define IXGBE_PBANUM1_PTR 0x16 + +/* EEPROM Commands - SPI */ +#define IXGBE_EEPROM_MAX_RETRY_SPI 5000 /* Max wait 5ms for RDY signal */ +#define IXGBE_EEPROM_STATUS_RDY_SPI 0x01 +#define IXGBE_EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */ +#define IXGBE_EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */ +#define IXGBE_EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = addr bit-8 */ +#define IXGBE_EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Ena latch */ +/* EEPROM reset Write Enbale latch */ +#define IXGBE_EEPROM_WRDI_OPCODE_SPI 0x04 +#define IXGBE_EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status reg */ +#define IXGBE_EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status reg */ +#define IXGBE_EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */ +#define IXGBE_EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */ +#define IXGBE_EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */ + +/* EEPROM Read Register */ +#define IXGBE_EEPROM_READ_REG_DATA 16 /* data offset in EEPROM read reg */ +#define IXGBE_EEPROM_READ_REG_DONE 2 /* Offset to READ done bit */ +#define IXGBE_EEPROM_READ_REG_START 1 /* First bit to start operation */ +#define IXGBE_EEPROM_READ_ADDR_SHIFT 2 /* Shift to the address bits */ + +#define IXGBE_ETH_LENGTH_OF_ADDRESS 6 + +#ifndef IXGBE_EEPROM_GRANT_ATTEMPTS +#define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ +#endif + +#ifndef IXGBE_EERD_ATTEMPTS +/* Number of 5 microseconds we wait for EERD read to complete */ +#define IXGBE_EERD_ATTEMPTS 100000 +#endif + +/* PCI Bus Info */ +#define IXGBE_PCI_LINK_STATUS 0xB2 +#define IXGBE_PCI_LINK_WIDTH 0x3F0 +#define IXGBE_PCI_LINK_WIDTH_1 0x10 +#define IXGBE_PCI_LINK_WIDTH_2 0x20 +#define IXGBE_PCI_LINK_WIDTH_4 0x40 +#define IXGBE_PCI_LINK_WIDTH_8 0x80 +#define IXGBE_PCI_LINK_SPEED 0xF +#define IXGBE_PCI_LINK_SPEED_2500 0x1 +#define IXGBE_PCI_LINK_SPEED_5000 0x2 + +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800 + +/* PHY Types */ +#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 + +/* Check whether address is multicast. This is little-endian specific check.*/ +#define IXGBE_IS_MULTICAST(Address) \ + (bool)(((u8 *)(Address))[0] & ((u8)0x01)) + +/* Check whether an address is broadcast. */ +#define IXGBE_IS_BROADCAST(Address) \ + ((((u8 *)(Address))[0] == ((u8)0xff)) && \ + (((u8 *)(Address))[1] == ((u8)0xff))) + +/* RAH */ +#define IXGBE_RAH_VIND_MASK 0x003C0000 +#define IXGBE_RAH_VIND_SHIFT 18 +#define IXGBE_RAH_AV 0x80000000 + +/* Filters */ +#define IXGBE_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ +#define IXGBE_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + +/* Header split receive */ +#define IXGBE_RFCTL_ISCSI_DIS 0x00000001 +#define IXGBE_RFCTL_ISCSI_DWC_MASK 0x0000003E +#define IXGBE_RFCTL_ISCSI_DWC_SHIFT 1 +#define IXGBE_RFCTL_NFSW_DIS 0x00000040 +#define IXGBE_RFCTL_NFSR_DIS 0x00000080 +#define IXGBE_RFCTL_NFS_VER_MASK 0x00000300 +#define IXGBE_RFCTL_NFS_VER_SHIFT 8 +#define IXGBE_RFCTL_NFS_VER_2 0 +#define IXGBE_RFCTL_NFS_VER_3 1 +#define IXGBE_RFCTL_NFS_VER_4 2 +#define IXGBE_RFCTL_IPV6_DIS 0x00000400 +#define IXGBE_RFCTL_IPV6_XSUM_DIS 0x00000800 +#define IXGBE_RFCTL_IPFRSP_DIS 0x00004000 +#define IXGBE_RFCTL_IPV6_EX_DIS 0x00010000 +#define IXGBE_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 + +/* Transmit Config masks */ +#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */ +#define IXGBE_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */ +/* Enable short packet padding to 64 bytes */ +#define IXGBE_TX_PAD_ENABLE 0x00000400 +#define IXGBE_JUMBO_FRAME_ENABLE 0x00000004 /* Allow jumbo frames */ +/* This allows for 16K packets + 4k for vlan */ +#define IXGBE_MAX_FRAME_SZ 0x40040000 + +#define IXGBE_TDWBAL_HEAD_WB_ENABLE 0x1 /* Tx head write-back enable */ +#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq. # write-back enable */ + +/* Receive Config masks */ +#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ +#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */ +#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */ + +#define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */ +#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/ +#define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */ +#define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */ +#define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */ +#define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */ +/* Receive Priority Flow Control Enbale */ +#define IXGBE_FCTRL_RPFCE 0x00004000 +#define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */ + +/* Multiple Receive Queue Control */ +#define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */ +#define IXGBE_MRQC_RSS_FIELD_MASK 0xFFFF0000 +#define IXGBE_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define IXGBE_MRQC_RSS_FIELD_IPV4 0x00020000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 0x00040000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX 0x00080000 +#define IXGBE_MRQC_RSS_FIELD_IPV6 0x00100000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 +#define IXGBE_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 0x01000000 + +#define IXGBE_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define IXGBE_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define IXGBE_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define IXGBE_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define IXGBE_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define IXGBE_TXD_CMD_RS 0x08000000 /* Report Status */ +#define IXGBE_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define IXGBE_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */ + +/* Receive Descriptor bit definitions */ +#define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IXGBE_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ +#define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */ +#define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ +#define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */ +#define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ +#define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ +#define IXGBE_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ +#define IXGBE_RXD_ERR_CE 0x01 /* CRC Error */ +#define IXGBE_RXD_ERR_LE 0x02 /* Length Error */ +#define IXGBE_RXD_ERR_PE 0x08 /* Packet Error */ +#define IXGBE_RXD_ERR_OSE 0x10 /* Oversize Error */ +#define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */ +#define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */ +#define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ +#define IXGBE_RXDADV_HBO 0x00800000 +#define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */ +#define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */ +#define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */ +#define IXGBE_RXDADV_ERR_OSE 0x10000000 /* Oversize Error */ +#define IXGBE_RXDADV_ERR_USE 0x20000000 /* Undersize Error */ +#define IXGBE_RXDADV_ERR_TCPE 0x40000000 /* TCP/UDP Checksum Error */ +#define IXGBE_RXDADV_ERR_IPE 0x80000000 /* IP Checksum Error */ +#define IXGBE_RXD_VLAN_ID_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define IXGBE_RXD_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define IXGBE_RXD_PRI_SHIFT 13 +#define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define IXGBE_RXD_CFI_SHIFT 12 + +/* SRRCTL bit definitions */ +#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ +#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F +#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00 +#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000 +#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 + +#define IXGBE_RXDPS_HDRSTAT_HDRSP 0x00008000 +#define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF + +#define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F +#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0 +#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0 +#define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5 +#define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000 +#define IXGBE_RXDADV_SPH 0x8000 + +/* RSS Hash results */ +#define IXGBE_RXDADV_RSSTYPE_NONE 0x00000000 +#define IXGBE_RXDADV_RSSTYPE_IPV4_TCP 0x00000001 +#define IXGBE_RXDADV_RSSTYPE_IPV4 0x00000002 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP 0x00000003 +#define IXGBE_RXDADV_RSSTYPE_IPV6_EX 0x00000004 +#define IXGBE_RXDADV_RSSTYPE_IPV6 0x00000005 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006 +#define IXGBE_RXDADV_RSSTYPE_IPV4_UDP 0x00000007 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP 0x00000008 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009 + +/* RSS Packet Types as indicated in the receive descriptor. */ +#define IXGBE_RXDADV_PKTTYPE_NONE 0x00000000 +#define IXGBE_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPv4 hdr present */ +#define IXGBE_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPv4 hdr + extensions */ +#define IXGBE_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPv6 hdr present */ +#define IXGBE_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPv6 hdr + extensions */ +#define IXGBE_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ + +/* Masks to determine if packets should be dropped due to frame errors */ +#define IXGBE_RXD_ERR_FRAME_ERR_MASK (\ + IXGBE_RXD_ERR_CE | \ + IXGBE_RXD_ERR_LE | \ + IXGBE_RXD_ERR_PE | \ + IXGBE_RXD_ERR_OSE | \ + IXGBE_RXD_ERR_USE) + +#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK (\ + IXGBE_RXDADV_ERR_CE | \ + IXGBE_RXDADV_ERR_LE | \ + IXGBE_RXDADV_ERR_PE | \ + IXGBE_RXDADV_ERR_OSE | \ + IXGBE_RXDADV_ERR_USE) + +/* Multicast bit mask */ +#define IXGBE_MCSTCTRL_MFE 0x4 + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE 8 +#define IXGBE_REQ_TX_BUFFER_GRANULARITY 1024 + +/* Vlan-specific macros */ +#define IXGBE_RX_DESC_SPECIAL_VLAN_MASK 0x0FFF /* VLAN ID in lower 12 bits */ +#define IXGBE_RX_DESC_SPECIAL_PRI_MASK 0xE000 /* Priority in upper 3 bits */ +#define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */ +#define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT + +/* Transmit Descriptor - Legacy */ +struct ixgbe_legacy_tx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 cso; /* Checksum offset */ + u8 cmd; /* Descriptor control */ + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 css; /* Checksum start */ + u16 vlan; + } fields; + } upper; +}; + +/* Transmit Descriptor - Advanced */ +union ixgbe_adv_tx_desc { + struct { + u64 buffer_addr; /* Address of descriptor's data buf */ + u32 cmd_type_len; + u32 olinfo_status; + } read; + struct { + u64 rsvd; /* Reserved */ + u32 nxtseq_seed; + u32 status; + } wb; +}; + +/* Receive Descriptor - Legacy */ +struct ixgbe_legacy_rx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + u16 length; /* Length of data DMAed into data buffer */ + u16 csum; /* Packet checksum */ + u8 status; /* Descriptor status */ + u8 errors; /* Descriptor Errors */ + u16 vlan; +}; + +/* Receive Descriptor - Advanced */ +union ixgbe_adv_rx_desc { + struct { + u64 pkt_addr; /* Packet buffer address */ + u64 hdr_addr; /* Header buffer address */ + } read; + struct { + struct { + struct { + u16 pkt_info; /* RSS type, Packet type */ + u16 hdr_info; /* Split Header, header len */ + } lo_dword; + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length; /* Packet length */ + u16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +/* Context descriptors */ +struct ixgbe_adv_tx_context_desc { + u32 vlan_macip_lens; + u32 seqnum_seed; + u32 type_tucmd_mlhl; + u32 mss_l4len_idx; +}; + +/* Adv Transmit Descriptor Config Masks */ +#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buffer length(bytes) */ +#define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */ +#define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */ +#define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ +#define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */ +#define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */ +#define IXGBE_ADVTXD_DCMD_RDMA 0x04000000 /* RDMA */ +#define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */ +#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */ +#define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */ +#define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */ +#define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ +#define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */ +#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */ +#define IXGBE_ADVTXD_STAT_RSV 0x0000000C /* STA Reserved */ +#define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */ +#define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */ +#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \ + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \ + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_POPTS_EOM 0x00000400 /* Enable L bit-RDMA DDP hdr */ +#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/ +#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */ +#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ +#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ +#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ +#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ +#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ +#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */ +#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ +#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ + +/* Link speed */ +#define IXGBE_LINK_SPEED_UNKNOWN 0 +#define IXGBE_LINK_SPEED_100_FULL 0x0008 +#define IXGBE_LINK_SPEED_1GB_FULL 0x0020 +#define IXGBE_LINK_SPEED_10GB_FULL 0x0080 + + +enum ixgbe_eeprom_type { + ixgbe_eeprom_uninitialized = 0, + ixgbe_eeprom_spi, + ixgbe_eeprom_none /* No NVM support */ +}; + +enum ixgbe_mac_type { + ixgbe_mac_unknown = 0, + ixgbe_mac_82598EB, + ixgbe_num_macs +}; + +enum ixgbe_phy_type { + ixgbe_phy_unknown = 0, + ixgbe_phy_tn, + ixgbe_phy_qt, + ixgbe_phy_xaui +}; + +enum ixgbe_media_type { + ixgbe_media_type_unknown = 0, + ixgbe_media_type_fiber, + ixgbe_media_type_copper, + ixgbe_media_type_backplane +}; + +/* Flow Control Settings */ +enum ixgbe_fc_type { + ixgbe_fc_none = 0, + ixgbe_fc_rx_pause, + ixgbe_fc_tx_pause, + ixgbe_fc_full, + ixgbe_fc_default +}; + +struct ixgbe_addr_filter_info { + u32 num_mc_addrs; + u32 rar_used_count; + u32 mc_addr_in_rar_count; + u32 mta_in_use; +}; + +/* Flow control parameters */ +struct ixgbe_fc_info { + u32 high_water; /* Flow Control High-water */ + u32 low_water; /* Flow Control Low-water */ + u16 pause_time; /* Flow Control Pause timer */ + bool send_xon; /* Flow control send XON */ + bool strict_ieee; /* Strict IEEE mode */ + enum ixgbe_fc_type type; /* Type of flow control */ + enum ixgbe_fc_type original_type; +}; + +/* Statistics counters collected by the MAC */ +struct ixgbe_hw_stats { + u64 crcerrs; + u64 illerrc; + u64 errbc; + u64 mspdc; + u64 mpctotal; + u64 mpc[8]; + u64 mlfc; + u64 mrfc; + u64 rlec; + u64 lxontxc; + u64 lxonrxc; + u64 lxofftxc; + u64 lxoffrxc; + u64 pxontxc[8]; + u64 pxonrxc[8]; + u64 pxofftxc[8]; + u64 pxoffrxc[8]; + u64 prc64; + u64 prc127; + u64 prc255; + u64 prc511; + u64 prc1023; + u64 prc1522; + u64 gprc; + u64 bprc; + u64 mprc; + u64 gptc; + u64 gorc; + u64 gotc; + u64 rnbc[8]; + u64 ruc; + u64 rfc; + u64 roc; + u64 rjc; + u64 mngprc; + u64 mngpdc; + u64 mngptc; + u64 tor; + u64 tpr; + u64 tpt; + u64 ptc64; + u64 ptc127; + u64 ptc255; + u64 ptc511; + u64 ptc1023; + u64 ptc1522; + u64 mptc; + u64 bptc; + u64 xec; + u64 rqsmr[16]; + u64 tqsmr[8]; + u64 qprc[16]; + u64 qptc[16]; + u64 qbrc[16]; + u64 qbtc[16]; +}; + +/* forward declaration */ +struct ixgbe_hw; + +struct ixgbe_mac_operations { + s32 (*reset)(struct ixgbe_hw *); + enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); +}; + +struct ixgbe_phy_operations { + s32 (*setup)(struct ixgbe_hw *); + s32 (*check)(struct ixgbe_hw *, u32 *, bool *); + s32 (*setup_speed)(struct ixgbe_hw *, u32, bool, bool); + s32 (*get_settings)(struct ixgbe_hw *, u32 *, bool *); +}; + +struct ixgbe_mac_info { + struct ixgbe_mac_operations ops; + enum ixgbe_mac_type type; + u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + s32 mc_filter_type; + u32 num_rx_queues; + u32 num_tx_queues; + u32 num_rx_addrs; + u32 link_attach_type; + u32 link_mode_select; + bool link_settings_loaded; +}; + + +struct ixgbe_eeprom_info { + enum ixgbe_eeprom_type type; + u16 word_size; + u16 address_bits; +}; + +struct ixgbe_phy_info { + struct ixgbe_phy_operations ops; + + enum ixgbe_phy_type type; + u32 addr; + u32 id; + u32 revision; + enum ixgbe_media_type media_type; + u32 autoneg_advertised; + bool autoneg_wait_to_complete; +}; + +struct ixgbe_info { + enum ixgbe_mac_type mac; + s32 (*get_invariants)(struct ixgbe_hw *); + struct ixgbe_mac_operations *mac_ops; + struct ixgbe_phy_operations *phy_ops; +}; + +struct ixgbe_hw { + u8 __iomem *hw_addr; + void *back; + struct ixgbe_mac_info mac; + struct ixgbe_addr_filter_info addr_ctrl; + struct ixgbe_fc_info fc; + struct ixgbe_phy_info phy; + struct ixgbe_eeprom_info eeprom; + u16 device_id; + u16 vendor_id; + u16 subsystem_device_id; + u16 subsystem_vendor_id; + u8 revision_id; + bool adapter_stopped; +}; + +/* Error Codes */ +#define IXGBE_ERR_EEPROM -1 +#define IXGBE_ERR_EEPROM_CHECKSUM -2 +#define IXGBE_ERR_PHY -3 +#define IXGBE_ERR_CONFIG -4 +#define IXGBE_ERR_PARAM -5 +#define IXGBE_ERR_MAC_TYPE -6 +#define IXGBE_ERR_UNKNOWN_PHY -7 +#define IXGBE_ERR_LINK_SETUP -8 +#define IXGBE_ERR_ADAPTER_STOPPED -9 +#define IXGBE_ERR_INVALID_MAC_ADDR -10 +#define IXGBE_ERR_DEVICE_NOT_SUPPORTED -11 +#define IXGBE_ERR_MASTER_REQUESTS_PENDING -12 +#define IXGBE_ERR_INVALID_LINK_SETTINGS -13 +#define IXGBE_ERR_AUTONEG_NOT_COMPLETE -14 +#define IXGBE_ERR_RESET_FAILED -15 +#define IXGBE_ERR_SWFW_SYNC -16 +#define IXGBE_ERR_PHY_ADDR_INVALID -17 +#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF + +#endif /* _IXGBE_TYPE_H_ */ From 34c6417b7087a4818e7dca2e5d66c3361cee80a1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 6 Sep 2007 11:51:37 -0700 Subject: [PATCH 1370/2804] e100: timer power saving Since E100 timer is 2HZ, use rounding to make timer occur on the correct boundary. Signed-off-by: Stephen Hemminger Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e100.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index e25f5ec2b279..10907f158bac 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1605,7 +1605,8 @@ static void e100_watchdog(unsigned long data) else nic->flags &= ~ich_10h_workaround; - mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); + mod_timer(&nic->watchdog, + round_jiffies(jiffies + E100_WATCHDOG_PERIOD)); } static void e100_xmit_prepare(struct nic *nic, struct cb *cb, From a5a3b4601bfa3c7671944067d4e4b04bf647e6d9 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:09 -0700 Subject: [PATCH 1371/2804] cxgb3 - Firmware update Update firmware version. Allow the driver to be up and running with older FW image Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 2 +- drivers/net/cxgb3/cxgb3_main.c | 9 +++++---- drivers/net/cxgb3/t3_hw.c | 20 +++++++++++++++----- drivers/net/cxgb3/version.h | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 510e93f90b91..ada5e4b89cd8 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -690,7 +690,7 @@ int t3_read_flash(struct adapter *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented); int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size); int t3_get_fw_version(struct adapter *adapter, u32 *vers); -int t3_check_fw_version(struct adapter *adapter); +int t3_check_fw_version(struct adapter *adapter, int *must_load); int t3_init_hw(struct adapter *adapter, u32 fw_params); void mac_prep(struct cmac *mac, struct adapter *adapter, int index); void early_hw_init(struct adapter *adapter, const struct adapter_info *ai); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 3ee465dd0b08..8f1d602a883a 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -797,11 +797,12 @@ static int cxgb_up(struct adapter *adap) int must_load; if (!(adap->flags & FULL_INIT_DONE)) { - err = t3_check_fw_version(adap); - if (err == -EINVAL) + err = t3_check_fw_version(adap, &must_load); + if (err == -EINVAL) { err = upgrade_fw(adap); - if (err) - goto out; + if (err && must_load) + goto out; + } err = t3_check_tpsram_version(adap, &must_load); if (err == -EINVAL) { diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index e958bbe30623..2b49b96a6fdb 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -960,16 +960,18 @@ int t3_get_fw_version(struct adapter *adapter, u32 *vers) /** * t3_check_fw_version - check if the FW is compatible with this driver * @adapter: the adapter - * + * @must_load: set to 1 if loading a new FW image is required + * Checks if an adapter's FW is compatible with the driver. Returns 0 * if the versions are compatible, a negative error otherwise. */ -int t3_check_fw_version(struct adapter *adapter) +int t3_check_fw_version(struct adapter *adapter, int *must_load) { int ret; u32 vers; unsigned int type, major, minor; + *must_load = 1; ret = t3_get_fw_version(adapter, &vers); if (ret) return ret; @@ -982,9 +984,17 @@ int t3_check_fw_version(struct adapter *adapter) minor == FW_VERSION_MINOR) return 0; - CH_ERR(adapter, "found wrong FW version(%u.%u), " - "driver needs version %u.%u\n", major, minor, - FW_VERSION_MAJOR, FW_VERSION_MINOR); + if (major != FW_VERSION_MAJOR) + CH_ERR(adapter, "found wrong FW version(%u.%u), " + "driver needs version %u.%u\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); + else { + *must_load = 0; + CH_WARN(adapter, "found wrong FW minor version(%u.%u), " + "driver compiled for version %u.%u\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); + } + return -EINVAL; } diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index eb508bf8022a..ef1c6339c806 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -39,6 +39,6 @@ /* Firmware version */ #define FW_VERSION_MAJOR 4 -#define FW_VERSION_MINOR 3 +#define FW_VERSION_MINOR 6 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ From 3eea3337a08a2ed2addac1551a9d446f2c16acd5 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:15 -0700 Subject: [PATCH 1372/2804] cxgb3 - log and clear PEX errors Clear pciE PEX errors late at module load time. Log details when PEX errors occur. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/t3_hw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 2b49b96a6fdb..cdcfc132e37d 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -1358,6 +1358,10 @@ static void pcie_intr_handler(struct adapter *adapter) {0} }; + if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR) + CH_ALERT(adapter, "PEX error code 0x%x\n", + t3_read_reg(adapter, A_PCIE_PEX_ERR)); + if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, pcie_intr_info, adapter->irq_stats)) t3_fatal_err(adapter); @@ -1809,6 +1813,8 @@ void t3_intr_clear(struct adapter *adapter) for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); + if (is_pcie(adapter)) + t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff); t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ } From b4687ff753c2c5c330989efed7cdf1a6bc6b512e Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:20 -0700 Subject: [PATCH 1373/2804] cxgb3 - remove false positive in xgmac workaround Qualify toggling of xgmac tx enable with not getting pause frames, we might not make forward progress because the peer is sending lots of pause frames. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/xgmac.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index ada5e4b89cd8..7e9e43d1074e 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -513,6 +513,7 @@ struct cmac { u64 rx_mcnt; unsigned int toggle_cnt; unsigned int txen; + u64 rx_pause; struct mac_stats stats; }; diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index 1d1c3919ab66..ff9e9dcbd87d 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -452,6 +452,7 @@ int t3_mac_enable(struct cmac *mac, int which) A_XGM_TX_SPI4_SOP_EOP_CNT + oft))); mac->rx_mcnt = s->rx_frames; + mac->rx_pause = s->rx_pause; mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_RX_SPI4_SOP_EOP_CNT + oft))); @@ -504,7 +505,7 @@ int t3b2_mac_watchdog_task(struct cmac *mac) tx_xcnt = 1; /* By default tx_xcnt is making progress */ tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */ rx_xcnt = 1; /* By default rx_xcnt is making progress */ - if (tx_mcnt == mac->tx_mcnt) { + if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_TX_SPI4_SOP_EOP_CNT + mac->offset))); @@ -560,6 +561,7 @@ out: mac->tx_mcnt = s->tx_frames; mac->rx_xcnt = rx_xcnt; mac->rx_mcnt = s->rx_frames; + mac->rx_pause = s->rx_pause; if (status == 1) { t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ From 1c17ae8af93bed203d9760702882e9f747a51912 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:25 -0700 Subject: [PATCH 1374/2804] cxgb3 - Set the CQ_ERR bit in CQ contexts. The cxgb3 driver is incorrectly configuring the HW CQ context for CQ's that use overflow-avoidance. Namely the RDMA control CQ. This results in a bad DMA from the device to bus address 0. The solution is to set the CQ_ERR bit in the context for these types of CQs. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/sge_defs.h | 4 ++++ drivers/net/cxgb3/t3_hw.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h index 514869e26a76..29b6c800b238 100644 --- a/drivers/net/cxgb3/sge_defs.h +++ b/drivers/net/cxgb3/sge_defs.h @@ -106,6 +106,10 @@ #define V_CQ_GEN(x) ((x) << S_CQ_GEN) #define F_CQ_GEN V_CQ_GEN(1U) +#define S_CQ_ERR 30 +#define V_CQ_ERR(x) ((x) << S_CQ_ERR) +#define F_CQ_ERR V_CQ_ERR(1U) + #define S_CQ_OVERFLOW_MODE 31 #define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE) #define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index cdcfc132e37d..bff1d028a96b 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -2046,7 +2046,8 @@ int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, base_addr >>= 32; t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) | - V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode)); + V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) | + V_CQ_ERR(ovfl_mode)); t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | V_CQ_CREDIT_THRES(credit_thres)); return t3_sge_write_context(adapter, id, F_CQ); From bb9366af7b4addb27156585baccadc4b6d30f223 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:30 -0700 Subject: [PATCH 1375/2804] cxgb3 - CQ context operations time out too soon. Currently, the driver only tries up to 5 times (5us) to get the results of a CQ context operation. Testing has shown the chip can take as much as 50us to return the response on SG_CONTEXT_CMD operations. So we up the retry count to 100 to cover high loads. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/t3_hw.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index bff1d028a96b..058329321440 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -1870,6 +1870,8 @@ void t3_port_intr_clear(struct adapter *adapter, int idx) phy->ops->intr_clear(phy); } +#define SG_CONTEXT_CMD_ATTEMPTS 100 + /** * t3_sge_write_context - write an SGE context * @adapter: the adapter @@ -1889,7 +1891,7 @@ static int t3_sge_write_context(struct adapter *adapter, unsigned int id, t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2075,7 +2077,7 @@ int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable) t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2099,7 +2101,7 @@ int t3_sge_disable_fl(struct adapter *adapter, unsigned int id) t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2123,7 +2125,7 @@ int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id) t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2147,7 +2149,7 @@ int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id) t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2172,7 +2174,7 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | V_CONTEXT(id) | F_CQ); if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1, &val)) + 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val)) return -EIO; if (op >= 2 && op < 7) { @@ -2182,7 +2184,8 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, - F_CONTEXT_CMD_BUSY, 0, 5, 1)) + F_CONTEXT_CMD_BUSY, 0, + SG_CONTEXT_CMD_ATTEMPTS, 1)) return -EIO; return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); } @@ -2208,7 +2211,7 @@ static int t3_sge_read_context(unsigned int type, struct adapter *adapter, t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id)); if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0, - 5, 1)) + SG_CONTEXT_CMD_ATTEMPTS, 1)) return -EIO; data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0); data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1); From 1aafee265723818d903766212015b6116885bc6f Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:36 -0700 Subject: [PATCH 1376/2804] cxgb3 - Add T3C rev add driver recognition for T3C rev board. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/cxgb3_main.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 7e9e43d1074e..d3f276c2c01d 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -438,6 +438,7 @@ enum { /* chip revisions */ T3_REV_A = 0, T3_REV_B = 2, T3_REV_B2 = 3, + T3_REV_C = 4, }; struct trace_params { diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 8f1d602a883a..a6723ae79bdd 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -733,6 +733,9 @@ static inline char t3rev2char(struct adapter *adapter) case T3_REV_B2: rev = 'b'; break; + case T3_REV_C: + rev = 'c'; + break; } return rev; } From dc67369573eee33a4b1220d416cb7dd3501dccbc Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:41 -0700 Subject: [PATCH 1377/2804] cxgb3 - Update engine microcode version The new microcode engine version is set to 1.1.0 Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index d3f276c2c01d..3e5b0db7784e 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -127,8 +127,8 @@ enum { /* adapter interrupt-maintained statistics */ enum { TP_VERSION_MAJOR = 1, - TP_VERSION_MINOR = 0, - TP_VERSION_MICRO = 44 + TP_VERSION_MINOR = 1, + TP_VERSION_MICRO = 0 }; #define S_TP_VERSION_MAJOR 16 From 99cd149efe824cf27c5d34506002a0fbfa831c0f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 4 Sep 2007 14:41:01 +0100 Subject: [PATCH 1378/2804] sgiseeq: replace use of dma_cache_wback_inv The sgiseeq driver is one of the few remaining users of the ancient cache banging DMA API. Replaced with the modern days DMA API. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik --- drivers/net/sgiseeq.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 0fb74cb51c4b..eb67b024e413 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -75,6 +75,7 @@ struct sgiseeq_init_block { /* Note the name ;-) */ struct sgiseeq_private { struct sgiseeq_init_block *srings; + dma_addr_t srings_dma; /* Ptrs to the descriptors in uncached space. */ struct sgiseeq_rx_desc *rx_desc; @@ -643,13 +644,20 @@ static int __init sgiseeq_probe(struct platform_device *pdev) sp = netdev_priv(dev); /* Make private data page aligned */ - sr = (struct sgiseeq_init_block *) get_zeroed_page(GFP_KERNEL); + sr = dma_alloc_coherent(&pdev->dev, sizeof(*sp->srings), + &sp->srings_dma, GFP_KERNEL); if (!sr) { printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n"); err = -ENOMEM; goto err_out_free_dev; } sp->srings = sr; + sp->rx_desc = sp->srings->rxvector; + sp->tx_desc = sp->srings->txvector; + + /* A couple calculations now, saves many cycles later. */ + setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); + setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); memcpy(dev->dev_addr, pd->mac, ETH_ALEN); @@ -662,19 +670,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev) sp->name = sgiseeqstr; sp->mode = SEEQ_RCMD_RBCAST; - sp->rx_desc = (struct sgiseeq_rx_desc *) - CKSEG1ADDR(ALIGNED(&sp->srings->rxvector[0])); - dma_cache_wback_inv((unsigned long)&sp->srings->rxvector, - sizeof(sp->srings->rxvector)); - sp->tx_desc = (struct sgiseeq_tx_desc *) - CKSEG1ADDR(ALIGNED(&sp->srings->txvector[0])); - dma_cache_wback_inv((unsigned long)&sp->srings->txvector, - sizeof(sp->srings->txvector)); - - /* A couple calculations now, saves many cycles later. */ - setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); - setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); - /* Setup PIO and DMA transfer timing */ sp->hregs->pconfig = 0x161; sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | @@ -732,7 +727,8 @@ static int __exit sgiseeq_remove(struct platform_device *pdev) struct sgiseeq_private *sp = netdev_priv(dev); unregister_netdev(dev); - free_page((unsigned long) sp->srings); + dma_free_coherent(&pdev->dev, sizeof(*sp->srings), sp->srings, + sp->srings_dma); free_netdev(dev); platform_set_drvdata(pdev, NULL); From ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Sat, 8 Sep 2007 21:46:49 +0200 Subject: [PATCH 1379/2804] remove setup of platform device from jazzsonic.c remove setup platform device from jazzsonic, which is done in arch code now Signed-off-by: Thomas Bogendoerfer Signed-off-by: Jeff Garzik --- drivers/net/jazzsonic.c | 61 +++++------------------------------------ 1 file changed, 7 insertions(+), 54 deletions(-) diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 75f6f441e876..b71e6633f42d 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -45,7 +45,6 @@ #include static char jazz_sonic_string[] = "jazzsonic"; -static struct platform_device *jazz_sonic_device; #define SONIC_MEM_SIZE 0x100 @@ -69,14 +68,6 @@ static unsigned int sonic_debug = SONIC_DEBUG; static unsigned int sonic_debug = 1; #endif -/* - * Base address and interrupt of the SONIC controller on JAZZ boards - */ -static struct { - unsigned int port; - unsigned int irq; -} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}}; - /* * We cannot use station (ethernet) address prefixes to detect the * sonic controller since these are board manufacturer depended. @@ -215,13 +206,12 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; + struct resource *res; int err = 0; int i; - /* - * Don't probe if we're not running on a Jazz board. - */ - if (mips_machgroup != MACH_GROUP_JAZZ) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) return -ENODEV; dev = alloc_etherdev(sizeof(struct sonic_local)); @@ -235,20 +225,9 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) netdev_boot_setup_check(dev); - if (dev->base_addr >= KSEG0) { /* Check a single specified location. */ - err = sonic_probe1(dev); - } else if (dev->base_addr != 0) { /* Don't probe at all. */ - err = -ENXIO; - } else { - for (i = 0; sonic_portlist[i].port; i++) { - dev->base_addr = sonic_portlist[i].port; - dev->irq = sonic_portlist[i].irq; - if (sonic_probe1(dev) == 0) - break; - } - if (!sonic_portlist[i].port) - err = -ENODEV; - } + dev->base_addr = res->start; + dev->irq = platform_get_irq(pdev, 0); + err = sonic_probe1(dev); if (err) goto out; err = register_netdev(dev); @@ -303,38 +282,12 @@ static struct platform_driver jazz_sonic_driver = { static int __init jazz_sonic_init_module(void) { - int err; - - if ((err = platform_driver_register(&jazz_sonic_driver))) { - printk(KERN_ERR "Driver registration failed\n"); - return err; - } - - jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0); - if (!jazz_sonic_device) - goto out_unregister; - - if (platform_device_add(jazz_sonic_device)) { - platform_device_put(jazz_sonic_device); - jazz_sonic_device = NULL; - } - - return 0; - -out_unregister: - platform_driver_unregister(&jazz_sonic_driver); - - return -ENOMEM; + return platform_driver_register(&jazz_sonic_driver); } static void __exit jazz_sonic_cleanup_module(void) { platform_driver_unregister(&jazz_sonic_driver); - - if (jazz_sonic_device) { - platform_device_unregister(jazz_sonic_device); - jazz_sonic_device = NULL; - } } module_init(jazz_sonic_init_module); From 9caab4587b8320c54fc666a6c820e966e6403aea Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Thu, 6 Sep 2007 06:21:54 -0400 Subject: [PATCH 1380/2804] S2io: Enable all the error and alarm indications - Added support to unmask entire set of device errors and alarams. Alarm interrupts are generated for a myriad of purposes, ranging from illegal operations or requests to internal state machine errors and uncorrectable data corruption errors. In several cases the adapter can recover gracefully from unexpected events; however, in some cases, a device reset may be necessary. This patch handles alarms generated by all the blocks within the device. The adapter generates the following types of alarms: 1. Link state transitions (local/remote fault) or other link-related problems. 2. Problems with any device peripherals, including the EEPROM, FLASH, etc. 3. Correctable ECC errors (single-bit errors) on internal data structures or frame data. 4. Uncorrectable ECC errors (multi-bit errors) on internal data structures or frame data. 5. State machine errors, which indicate that internal control structures have become corrupted. 6. PCI related errors, including parity errors or illegal transactions. 7. Other unexpected events. - Implemented Jeff's review comments to use do_s2io_write_bits function to avoid duplicate codes. Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io-regs.h | 116 +++++++++++++++++-- drivers/net/s2io.c | 246 ++++++++++++++++++++++++++++------------ drivers/net/s2io.h | 1 + 3 files changed, 278 insertions(+), 85 deletions(-) diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 83e3e47a9e3d..aef66e2d98d2 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -325,33 +325,66 @@ struct XENA_dev_config { #define TXDMA_TPA_INT BIT(5) #define TXDMA_SM_INT BIT(6) u64 pfc_err_reg; +#define PFC_ECC_SG_ERR BIT(7) +#define PFC_ECC_DB_ERR BIT(15) +#define PFC_SM_ERR_ALARM BIT(23) +#define PFC_MISC_0_ERR BIT(31) +#define PFC_MISC_1_ERR BIT(32) +#define PFC_PCIX_ERR BIT(39) u64 pfc_err_mask; u64 pfc_err_alarm; u64 tda_err_reg; +#define TDA_Fn_ECC_SG_ERR vBIT(0xff,0,8) +#define TDA_Fn_ECC_DB_ERR vBIT(0xff,8,8) +#define TDA_SM0_ERR_ALARM BIT(22) +#define TDA_SM1_ERR_ALARM BIT(23) +#define TDA_PCIX_ERR BIT(39) u64 tda_err_mask; u64 tda_err_alarm; u64 pcc_err_reg; -#define PCC_FB_ECC_DB_ERR vBIT(0xFF, 16, 8) +#define PCC_FB_ECC_SG_ERR vBIT(0xFF,0,8) +#define PCC_TXB_ECC_SG_ERR vBIT(0xFF,8,8) +#define PCC_FB_ECC_DB_ERR vBIT(0xFF,16, 8) +#define PCC_TXB_ECC_DB_ERR vBIT(0xff,24,8) +#define PCC_SM_ERR_ALARM vBIT(0xff,32,8) +#define PCC_WR_ERR_ALARM vBIT(0xff,40,8) +#define PCC_N_SERR vBIT(0xff,48,8) +#define PCC_6_COF_OV_ERR BIT(56) +#define PCC_7_COF_OV_ERR BIT(57) +#define PCC_6_LSO_OV_ERR BIT(58) +#define PCC_7_LSO_OV_ERR BIT(59) #define PCC_ENABLE_FOUR vBIT(0x0F,0,8) - u64 pcc_err_mask; u64 pcc_err_alarm; u64 tti_err_reg; +#define TTI_ECC_SG_ERR BIT(7) +#define TTI_ECC_DB_ERR BIT(15) +#define TTI_SM_ERR_ALARM BIT(23) u64 tti_err_mask; u64 tti_err_alarm; u64 lso_err_reg; +#define LSO6_SEND_OFLOW BIT(12) +#define LSO7_SEND_OFLOW BIT(13) +#define LSO6_ABORT BIT(14) +#define LSO7_ABORT BIT(15) +#define LSO6_SM_ERR_ALARM BIT(22) +#define LSO7_SM_ERR_ALARM BIT(23) u64 lso_err_mask; u64 lso_err_alarm; u64 tpa_err_reg; +#define TPA_TX_FRM_DROP BIT(7) +#define TPA_SM_ERR_ALARM BIT(23) + u64 tpa_err_mask; u64 tpa_err_alarm; u64 sm_err_reg; +#define SM_SM_ERR_ALARM BIT(15) u64 sm_err_mask; u64 sm_err_alarm; @@ -450,22 +483,52 @@ struct XENA_dev_config { #define RXDMA_INT_RTI_INT_M BIT(3) u64 rda_err_reg; +#define RDA_RXDn_ECC_SG_ERR vBIT(0xFF,0,8) +#define RDA_RXDn_ECC_DB_ERR vBIT(0xFF,8,8) +#define RDA_FRM_ECC_SG_ERR BIT(23) +#define RDA_FRM_ECC_DB_N_AERR BIT(31) +#define RDA_SM1_ERR_ALARM BIT(38) +#define RDA_SM0_ERR_ALARM BIT(39) +#define RDA_MISC_ERR BIT(47) +#define RDA_PCIX_ERR BIT(55) +#define RDA_RXD_ECC_DB_SERR BIT(63) u64 rda_err_mask; u64 rda_err_alarm; u64 rc_err_reg; +#define RC_PRCn_ECC_SG_ERR vBIT(0xFF,0,8) +#define RC_PRCn_ECC_DB_ERR vBIT(0xFF,8,8) +#define RC_FTC_ECC_SG_ERR BIT(23) +#define RC_FTC_ECC_DB_ERR BIT(31) +#define RC_PRCn_SM_ERR_ALARM vBIT(0xFF,32,8) +#define RC_FTC_SM_ERR_ALARM BIT(47) +#define RC_RDA_FAIL_WR_Rn vBIT(0xFF,48,8) u64 rc_err_mask; u64 rc_err_alarm; u64 prc_pcix_err_reg; +#define PRC_PCI_AB_RD_Rn vBIT(0xFF,0,8) +#define PRC_PCI_DP_RD_Rn vBIT(0xFF,8,8) +#define PRC_PCI_AB_WR_Rn vBIT(0xFF,16,8) +#define PRC_PCI_DP_WR_Rn vBIT(0xFF,24,8) +#define PRC_PCI_AB_F_WR_Rn vBIT(0xFF,32,8) +#define PRC_PCI_DP_F_WR_Rn vBIT(0xFF,40,8) u64 prc_pcix_err_mask; u64 prc_pcix_err_alarm; u64 rpa_err_reg; +#define RPA_ECC_SG_ERR BIT(7) +#define RPA_ECC_DB_ERR BIT(15) +#define RPA_FLUSH_REQUEST BIT(22) +#define RPA_SM_ERR_ALARM BIT(23) +#define RPA_CREDIT_ERR BIT(31) u64 rpa_err_mask; u64 rpa_err_alarm; u64 rti_err_reg; +#define RTI_ECC_SG_ERR BIT(7) +#define RTI_ECC_DB_ERR BIT(15) +#define RTI_SM_ERR_ALARM BIT(23) u64 rti_err_mask; u64 rti_err_alarm; @@ -582,17 +645,43 @@ struct XENA_dev_config { #define MAC_INT_STATUS_RMAC_INT BIT(1) u64 mac_tmac_err_reg; -#define TMAC_ERR_REG_TMAC_ECC_DB_ERR BIT(15) -#define TMAC_ERR_REG_TMAC_TX_BUF_OVRN BIT(23) -#define TMAC_ERR_REG_TMAC_TX_CRI_ERR BIT(31) +#define TMAC_ECC_SG_ERR BIT(7) +#define TMAC_ECC_DB_ERR BIT(15) +#define TMAC_TX_BUF_OVRN BIT(23) +#define TMAC_TX_CRI_ERR BIT(31) +#define TMAC_TX_SM_ERR BIT(39) +#define TMAC_DESC_ECC_SG_ERR BIT(47) +#define TMAC_DESC_ECC_DB_ERR BIT(55) + u64 mac_tmac_err_mask; u64 mac_tmac_err_alarm; u64 mac_rmac_err_reg; -#define RMAC_ERR_REG_RX_BUFF_OVRN BIT(0) -#define RMAC_ERR_REG_RTS_ECC_DB_ERR BIT(14) -#define RMAC_ERR_REG_ECC_DB_ERR BIT(15) -#define RMAC_LINK_STATE_CHANGE_INT BIT(31) +#define RMAC_RX_BUFF_OVRN BIT(0) +#define RMAC_FRM_RCVD_INT BIT(1) +#define RMAC_UNUSED_INT BIT(2) +#define RMAC_RTS_PNUM_ECC_SG_ERR BIT(5) +#define RMAC_RTS_DS_ECC_SG_ERR BIT(6) +#define RMAC_RD_BUF_ECC_SG_ERR BIT(7) +#define RMAC_RTH_MAP_ECC_SG_ERR BIT(8) +#define RMAC_RTH_SPDM_ECC_SG_ERR BIT(9) +#define RMAC_RTS_VID_ECC_SG_ERR BIT(10) +#define RMAC_DA_SHADOW_ECC_SG_ERR BIT(11) +#define RMAC_RTS_PNUM_ECC_DB_ERR BIT(13) +#define RMAC_RTS_DS_ECC_DB_ERR BIT(14) +#define RMAC_RD_BUF_ECC_DB_ERR BIT(15) +#define RMAC_RTH_MAP_ECC_DB_ERR BIT(16) +#define RMAC_RTH_SPDM_ECC_DB_ERR BIT(17) +#define RMAC_RTS_VID_ECC_DB_ERR BIT(18) +#define RMAC_DA_SHADOW_ECC_DB_ERR BIT(19) +#define RMAC_LINK_STATE_CHANGE_INT BIT(31) +#define RMAC_RX_SM_ERR BIT(39) +#define RMAC_SINGLE_ECC_ERR (BIT(5) | BIT(6) | BIT(7) |\ + BIT(8) | BIT(9) | BIT(10)|\ + BIT(11)) +#define RMAC_DOUBLE_ECC_ERR (BIT(13) | BIT(14) | BIT(15) |\ + BIT(16) | BIT(17) | BIT(18)|\ + BIT(19)) u64 mac_rmac_err_mask; u64 mac_rmac_err_alarm; @@ -750,6 +839,7 @@ struct XENA_dev_config { BIT(17) | BIT(19)) #define MC_ERR_REG_ECC_ALL_DBL (BIT(10) | BIT(11) | BIT(12) |\ BIT(13) | BIT(18) | BIT(20)) +#define PLL_LOCK_N BIT(39) u64 mc_err_mask; u64 mc_err_alarm; @@ -823,11 +913,17 @@ struct XENA_dev_config { #define XGXS_INT_MASK_RXGXS BIT(1) u64 xgxs_txgxs_err_reg; -#define TXGXS_ECC_DB_ERR BIT(15) +#define TXGXS_ECC_SG_ERR BIT(7) +#define TXGXS_ECC_DB_ERR BIT(15) +#define TXGXS_ESTORE_UFLOW BIT(31) +#define TXGXS_TX_SM_ERR BIT(39) + u64 xgxs_txgxs_err_mask; u64 xgxs_txgxs_err_alarm; u64 xgxs_rxgxs_err_reg; +#define RXGXS_ESTORE_OFLOW BIT(7) +#define RXGXS_RX_SM_ERR BIT(39) u64 xgxs_rxgxs_err_mask; u64 xgxs_rxgxs_err_alarm; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index e7431c58da49..63473027b463 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -892,8 +892,9 @@ static void free_shared_mem(struct s2io_nic *nic) k++; } kfree(mac_control->rings[i].ba[j]); - nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) * - (rxd_count[nic->rxd_mode] + 1)); + nic->mac_control.stats_info->sw_stat.mem_freed += + (sizeof(struct buffAdd) * + (rxd_count[nic->rxd_mode] + 1)); } kfree(mac_control->rings[i].ba); nic->mac_control.stats_info->sw_stat.mem_freed += @@ -1731,7 +1732,150 @@ static int s2io_link_fault_indication(struct s2io_nic *nic) else return MAC_RMAC_ERR_TIMER; } +/** + * do_s2io_write_bits - update alarm bits in alarm register + * @value: alarm bits + * @flag: interrupt status + * @addr: address value + * Description: update alarm bits in alarm register + * Return Value: + * NONE. + */ +static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr) +{ + u64 temp64; + temp64 = readq(addr); + + if(flag == ENABLE_INTRS) + temp64 &= ~((u64) value); + else + temp64 |= ((u64) value); + writeq(temp64, addr); +} + +void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) +{ + struct XENA_dev_config __iomem *bar0 = nic->bar0; + register u64 gen_int_mask = 0; + + 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); + + 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); + + 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); + + 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); + + do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR | + 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); + + do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP, + 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); + 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); + } + + if (mask & TX_XGXS_INTR) { + gen_int_mask |= TXXGXS_INT_M; + do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag, + &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); + } + + 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); + 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); + 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); + do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR | + 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); + do_s2io_write_bits(RTI_SM_ERR_ALARM | + 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); + do_s2io_write_bits(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | + RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR | + RMAC_DOUBLE_ECC_ERR | + RMAC_LINK_STATE_CHANGE_INT, + flag, &bar0->mac_rmac_err_mask); + } + + if (mask & RX_XGXS_INTR) + { + gen_int_mask |= RXXGXS_INT_M; + do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag, + &bar0->xgxs_int_mask); + do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag, + &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_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG | + 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, @@ -1746,17 +1890,16 @@ static int s2io_link_fault_indication(struct s2io_nic *nic) static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) { struct XENA_dev_config __iomem *bar0 = nic->bar0; - register u64 val64 = 0, temp64 = 0; + register u64 temp64 = 0, intr_mask = 0; + + intr_mask = nic->general_int_mask; /* Top level interrupt classification */ /* PIC Interrupts */ - if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) { + if (mask & TX_PIC_INTR) { /* Enable PIC Intrs in the general intr mask register */ - val64 = TXPIC_INT_M; + intr_mask |= TXPIC_INT_M; if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); /* * If Hercules adapter enable GPIO otherwise * disable all PCIX, Flash, MDIO, IIC and GPIO @@ -1765,64 +1908,25 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) */ if (s2io_link_fault_indication(nic) == LINK_UP_DOWN_INTERRUPT ) { - temp64 = readq(&bar0->pic_int_mask); - temp64 &= ~((u64) PIC_INT_GPIO); - writeq(temp64, &bar0->pic_int_mask); - temp64 = readq(&bar0->gpio_int_mask); - temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP); - writeq(temp64, &bar0->gpio_int_mask); - } else { + do_s2io_write_bits(PIC_INT_GPIO, flag, + &bar0->pic_int_mask); + do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag, + &bar0->gpio_int_mask); + } else writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); - } - /* - * No MSI Support is available presently, so TTI and - * RTI interrupts are also disabled. - */ } else if (flag == DISABLE_INTRS) { /* * Disable PIC Intrs in the general * intr mask register */ writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - - /* MAC Interrupts */ - /* Enabling/Disabling MAC interrupts */ - if (mask & (TX_MAC_INTR | RX_MAC_INTR)) { - val64 = TXMAC_INT_M | RXMAC_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * All MAC block error interrupts are disabled for now - * TODO - */ - } else if (flag == DISABLE_INTRS) { - /* - * Disable MAC Intrs in the general intr mask register - */ - writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask); - writeq(DISABLE_ALL_INTRS, - &bar0->mac_rmac_err_mask); - - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); } } /* Tx traffic interrupts */ if (mask & TX_TRAFFIC_INTR) { - val64 = TXTRAFFIC_INT_M; + intr_mask |= TXTRAFFIC_INT_M; if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); /* * Enable all the Tx side interrupts * writing 0 Enables all 64 TX interrupt levels @@ -1834,19 +1938,13 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) * register. */ writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); } } /* Rx traffic interrupts */ if (mask & RX_TRAFFIC_INTR) { - val64 = RXTRAFFIC_INT_M; + intr_mask |= RXTRAFFIC_INT_M; if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); /* writing 0 Enables all 8 RX interrupt levels */ writeq(0x0, &bar0->rx_traffic_mask); } else if (flag == DISABLE_INTRS) { @@ -1855,11 +1953,17 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) * register. */ writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); } } + + temp64 = readq(&bar0->general_int_mask); + if (flag == ENABLE_INTRS) + temp64 &= ~((u64) intr_mask); + else + temp64 = DISABLE_ALL_INTRS; + writeq(temp64, &bar0->general_int_mask); + + nic->general_int_mask = readq(&bar0->general_int_mask); } /** @@ -2062,14 +2166,6 @@ static int start_nic(struct s2io_nic *nic) val64 &= ~ADAPTER_ECC_EN; writeq(val64, &bar0->adapter_control); - /* - * Clearing any possible Link state change interrupts that - * could have popped up just before Enabling the card. - */ - val64 = readq(&bar0->mac_rmac_err_reg); - if (val64) - writeq(val64, &bar0->mac_rmac_err_reg); - /* * Verify if the device is ready to be enabled, if so enable * it. @@ -2223,9 +2319,9 @@ static void stop_nic(struct s2io_nic *nic) config = &nic->config; /* Disable all interrupts */ + en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS); interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; - interruptible |= TX_PIC_INTR | RX_PIC_INTR; - interruptible |= TX_MAC_INTR | RX_MAC_INTR; + interruptible |= TX_PIC_INTR; en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS); /* Clearing Adapter_En bit of ADAPTER_CONTROL Register */ @@ -6666,12 +6762,12 @@ static int s2io_card_up(struct s2io_nic * sp) tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev); /* Enable select interrupts */ + en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS); if (sp->intr_type != INTA) en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS); else { interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; - interruptible |= TX_PIC_INTR | RX_PIC_INTR; - interruptible |= TX_MAC_INTR | RX_MAC_INTR; + interruptible |= TX_PIC_INTR; en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS); } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 724948d217b6..b9654dfeb877 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -893,6 +893,7 @@ struct s2io_nic { spinlock_t rx_lock; atomic_t isr_cnt; + u64 general_int_mask; u64 *ufo_in_band_v; #define VPD_STRING_LEN 80 u8 product_name[VPD_STRING_LEN]; From 8116f3cf4a2a5a4fa2335e6f32023ac50506698f Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Mon, 17 Sep 2007 13:05:35 -0700 Subject: [PATCH 1381/2804] [S2IO]: Handle and monitor all of the device errors and alarms - Added support to poll entire set of device errors and alarams. - A note on how device errors and alarms are handled: - The adapter will automatically recover from uncorrectable ECC errors. Packets containing corrupted data will be dropped (not transmitted) or tagged as invalid before being passed to the host. - The adapter cannot recover from any internal state machine errors. A state machine error requires a device reset. - Any internal error that could potentially result in .store trampling. (undesirable PCI behaviour)is tagged as a "serious error". In such cases the adapter will give up its ability to be a bus master. In this situation the host will still be able to read internal device registers in order to generate an error report. A device reset is necessary to return to normal operation. - In the event of a pcix data parity error, the adapter will automatically disable itself. Adapter_En will automatically transition from '1' to '0' and the adapter will enter its clean-up routine. Once the device has achieved quiescence, an adapter reset should be performed. - Replaced alarm_intr_handler() with s2io_handle_errors(). - Added statistic counters to monitor the alarms. [ Fix warnings wrt. do_s2io_chk_alarm_bit(), Callers pass in an "unsigned long long *" but the function takes a "u64 *" which is different on many 64-bit platforms. -DaveM ] Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 469 ++++++++++++++++++++++++++++++++------------- drivers/net/s2io.h | 24 ++- 2 files changed, 357 insertions(+), 136 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 63473027b463..182643ff81e5 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -263,7 +263,14 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { {"serious_err_cnt"}, {"soft_reset_cnt"}, {"fifo_full_cnt"}, - {"ring_full_cnt"}, + {"ring_0_full_cnt"}, + {"ring_1_full_cnt"}, + {"ring_2_full_cnt"}, + {"ring_3_full_cnt"}, + {"ring_4_full_cnt"}, + {"ring_5_full_cnt"}, + {"ring_6_full_cnt"}, + {"ring_7_full_cnt"}, ("alarm_transceiver_temp_high"), ("alarm_transceiver_temp_low"), ("alarm_laser_bias_current_high"), @@ -303,7 +310,24 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { ("rx_tcode_fcs_err_cnt"), ("rx_tcode_buf_size_err_cnt"), ("rx_tcode_rxd_corrupt_cnt"), - ("rx_tcode_unkn_err_cnt") + ("rx_tcode_unkn_err_cnt"), + {"tda_err_cnt"}, + {"pfc_err_cnt"}, + {"pcc_err_cnt"}, + {"tti_err_cnt"}, + {"tpa_err_cnt"}, + {"sm_err_cnt"}, + {"lso_err_cnt"}, + {"mac_tmac_err_cnt"}, + {"mac_rmac_err_cnt"}, + {"xgxs_txgxs_err_cnt"}, + {"xgxs_rxgxs_err_cnt"}, + {"rc_err_cnt"}, + {"prc_pcix_err_cnt"}, + {"rpa_err_cnt"}, + {"rda_err_cnt"}, + {"rti_err_cnt"}, + {"mc_err_cnt"} }; #define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN @@ -1732,6 +1756,7 @@ static int s2io_link_fault_indication(struct s2io_nic *nic) else return MAC_RMAC_ERR_TIMER; } + /** * do_s2io_write_bits - update alarm bits in alarm register * @value: alarm bits @@ -3251,135 +3276,6 @@ static void s2io_updt_xpak_counter(struct net_device *dev) stat_info->xpak_stat.warn_laser_output_power_low++; } -/** - * alarm_intr_handler - Alarm Interrrupt handler - * @nic: device private variable - * Description: If the interrupt was neither because of Rx packet or Tx - * complete, this function is called. If the interrupt was to indicate - * a loss of link, the OSM link status handler is invoked for any other - * alarm interrupt the block that raised the interrupt is displayed - * and a H/W reset is issued. - * Return Value: - * NONE -*/ - -static void alarm_intr_handler(struct s2io_nic *nic) -{ - struct net_device *dev = (struct net_device *) nic->dev; - struct XENA_dev_config __iomem *bar0 = nic->bar0; - register u64 val64 = 0, err_reg = 0; - u64 cnt; - int i; - if (atomic_read(&nic->card_state) == CARD_DOWN) - return; - if (pci_channel_offline(nic->pdev)) - return; - nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0; - /* Handling the XPAK counters update */ - if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) { - /* waiting for an hour */ - nic->mac_control.stats_info->xpak_stat.xpak_timer_count++; - } else { - s2io_updt_xpak_counter(dev); - /* reset the count to zero */ - nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0; - } - - /* Handling link status change error Intr */ - if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { - err_reg = readq(&bar0->mac_rmac_err_reg); - writeq(err_reg, &bar0->mac_rmac_err_reg); - if (err_reg & RMAC_LINK_STATE_CHANGE_INT) { - schedule_work(&nic->set_link_task); - } - } - - /* Handling Ecc errors */ - val64 = readq(&bar0->mc_err_reg); - writeq(val64, &bar0->mc_err_reg); - if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) { - if (val64 & MC_ERR_REG_ECC_ALL_DBL) { - nic->mac_control.stats_info->sw_stat. - double_ecc_errs++; - DBG_PRINT(INIT_DBG, "%s: Device indicates ", - dev->name); - DBG_PRINT(INIT_DBG, "double ECC error!!\n"); - if (nic->device_type != XFRAME_II_DEVICE) { - /* Reset XframeI only if critical error */ - if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | - MC_ERR_REG_MIRI_ECC_DB_ERR_1)) { - netif_stop_queue(dev); - schedule_work(&nic->rst_timer_task); - nic->mac_control.stats_info->sw_stat. - soft_reset_cnt++; - } - } - } else { - nic->mac_control.stats_info->sw_stat. - single_ecc_errs++; - } - } - - /* In case of a serious error, the device will be Reset. */ - val64 = readq(&bar0->serr_source); - if (val64 & SERR_SOURCE_ANY) { - nic->mac_control.stats_info->sw_stat.serious_err_cnt++; - DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name); - DBG_PRINT(ERR_DBG, "serious error %llx!!\n", - (unsigned long long)val64); - netif_stop_queue(dev); - schedule_work(&nic->rst_timer_task); - nic->mac_control.stats_info->sw_stat.soft_reset_cnt++; - } - - /* - * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC - * Error occurs, the adapter will be recycled by disabling the - * adapter enable bit and enabling it again after the device - * becomes Quiescent. - */ - val64 = readq(&bar0->pcc_err_reg); - writeq(val64, &bar0->pcc_err_reg); - if (val64 & PCC_FB_ECC_DB_ERR) { - u64 ac = readq(&bar0->adapter_control); - ac &= ~(ADAPTER_CNTL_EN); - writeq(ac, &bar0->adapter_control); - ac = readq(&bar0->adapter_control); - schedule_work(&nic->set_link_task); - } - /* Check for data parity error */ - val64 = readq(&bar0->pic_int_status); - if (val64 & PIC_INT_GPIO) { - val64 = readq(&bar0->gpio_int_reg); - if (val64 & GPIO_INT_REG_DP_ERR_INT) { - nic->mac_control.stats_info->sw_stat.parity_err_cnt++; - schedule_work(&nic->rst_timer_task); - nic->mac_control.stats_info->sw_stat.soft_reset_cnt++; - } - } - - /* Check for ring full counter */ - if (nic->device_type & XFRAME_II_DEVICE) { - val64 = readq(&bar0->ring_bump_counter1); - for (i=0; i<4; i++) { - cnt = ( val64 & vBIT(0xFFFF,(i*16),16)); - cnt >>= 64 - ((i+1)*16); - nic->mac_control.stats_info->sw_stat.ring_full_cnt - += cnt; - } - - val64 = readq(&bar0->ring_bump_counter2); - for (i=0; i<4; i++) { - cnt = ( val64 & vBIT(0xFFFF,(i*16),16)); - cnt >>= 64 - ((i+1)*16); - nic->mac_control.stats_info->sw_stat.ring_full_cnt - += cnt; - } - } - - /* Other type of interrupts are not being handled now, TODO */ -} - /** * wait_for_cmd_complete - waits for a command to complete. * @sp : private member of the device structure, which is a pointer to the @@ -4246,8 +4142,9 @@ static void s2io_alarm_handle(unsigned long data) { struct s2io_nic *sp = (struct s2io_nic *)data; + struct net_device *dev = sp->dev; - alarm_intr_handler(sp); + s2io_handle_errors(dev); mod_timer(&sp->alarm_timer, jiffies + HZ / 2); } @@ -4365,6 +4262,292 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) val64 = readq(&bar0->gpio_int_mask); } +/** + * do_s2io_chk_alarm_bit - Check for alarm and incrment the counter + * @value: alarm bits + * @addr: address value + * @cnt: counter variable + * Description: Check for alarm and increment the counter + * Return Value: + * 1 - if alarm bit set + * 0 - if alarm bit is not set + */ +int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, + unsigned long long *cnt) +{ + u64 val64; + val64 = readq(addr); + if ( val64 & value ) { + writeq(val64, addr); + (*cnt)++; + return 1; + } + return 0; + +} + +/** + * s2io_handle_errors - Xframe error indication handler + * @nic: device private variable + * Description: Handle alarms such as loss of link, single or + * double ECC errors, critical and serious errors. + * Return Value: + * NONE + */ +static void s2io_handle_errors(void * dev_id) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + u64 temp64 = 0,val64=0; + int i = 0; + + struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat; + struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat; + + if (unlikely(atomic_read(&sp->card_state) == CARD_DOWN)) + return; + + if (pci_channel_offline(sp->pdev)) + return; + + memset(&sw_stat->ring_full_cnt, 0, + sizeof(sw_stat->ring_full_cnt)); + + /* Handling the XPAK counters update */ + if(stats->xpak_timer_count < 72000) { + /* waiting for an hour */ + stats->xpak_timer_count++; + } else { + s2io_updt_xpak_counter(dev); + /* reset the count to zero */ + stats->xpak_timer_count = 0; + } + + /* Handling link status change error Intr */ + if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) { + val64 = readq(&bar0->mac_rmac_err_reg); + writeq(val64, &bar0->mac_rmac_err_reg); + if (val64 & RMAC_LINK_STATE_CHANGE_INT) + schedule_work(&sp->set_link_task); + } + + /* 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)) + 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)) + 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)); + 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)); + temp64 >>= 64 - ((i+1)*16); + 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)) + goto reset; + 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)) + goto reset; + do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR, + &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)) + 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); + } + + /*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)) + goto reset; + do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR, + &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)) + goto reset; + do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, + &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)) + goto reset; + 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)) + 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)) + 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); + } + + 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)) + 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); + } + + 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)) + 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)) + 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); + } + + 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)) + goto reset; + do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, + &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)) + 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); + } + + 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)) + goto reset; + do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, + &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)) + 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); + } + + 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)) + 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)) + goto reset; + + /* Handling Ecc errors */ + if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) { + writeq(val64, &bar0->mc_err_reg); + if (val64 & MC_ERR_REG_ECC_ALL_DBL) { + sw_stat->double_ecc_errs++; + if (sp->device_type != XFRAME_II_DEVICE) { + /* + * 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; + } + } else + sw_stat->single_ecc_errs++; + } + } + return; + +reset: + netif_stop_queue(dev); + schedule_work(&sp->rst_timer_task); + sw_stat->soft_reset_cnt++; + return; +} + /** * s2io_isr - ISR handler of the device . * @irq: the irq of the device. @@ -5754,7 +5937,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 * tmp_stats) { - int i = 0; + int i = 0, k; struct s2io_nic *sp = dev->priv; struct stat_block *stat_info = sp->mac_control.stats_info; @@ -5949,7 +6132,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev, 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++] = stat_info->sw_stat.ring_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; @@ -6006,6 +6190,23 @@ static void s2io_get_ethtool_stats(struct net_device *dev, 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; } static int s2io_ethtool_get_regs_len(struct net_device *dev) diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index b9654dfeb877..1e2e72d6aad2 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -91,7 +91,7 @@ struct swStat { unsigned long long serious_err_cnt; unsigned long long soft_reset_cnt; unsigned long long fifo_full_cnt; - unsigned long long ring_full_cnt; + unsigned long long ring_full_cnt[8]; /* LRO statistics */ unsigned long long clubbed_frms_cnt; unsigned long long sending_both; @@ -126,6 +126,26 @@ struct swStat { unsigned long long rx_buf_size_err_cnt; unsigned long long rx_rxd_corrupt_cnt; unsigned long long rx_unkn_err_cnt; + + /* Error/alarm statistics*/ + unsigned long long tda_err_cnt; + unsigned long long pfc_err_cnt; + unsigned long long pcc_err_cnt; + unsigned long long tti_err_cnt; + unsigned long long lso_err_cnt; + unsigned long long tpa_err_cnt; + unsigned long long sm_err_cnt; + unsigned long long mac_tmac_err_cnt; + unsigned long long mac_rmac_err_cnt; + unsigned long long xgxs_txgxs_err_cnt; + unsigned long long xgxs_rxgxs_err_cnt; + unsigned long long rc_err_cnt; + unsigned long long prc_pcix_err_cnt; + unsigned long long rpa_err_cnt; + unsigned long long rda_err_cnt; + unsigned long long rti_err_cnt; + unsigned long long mc_err_cnt; + }; /* Xpak releated alarm and warnings */ @@ -1018,7 +1038,7 @@ static void free_shared_mem(struct s2io_nic *sp); static int init_nic(struct s2io_nic *nic); static void rx_intr_handler(struct ring_info *ring_data); static void tx_intr_handler(struct fifo_info *fifo_data); -static void alarm_intr_handler(struct s2io_nic *sp); +static void s2io_handle_errors(void * dev_id); static int s2io_starter(void); static void s2io_closer(void); From eaae7f72304f2cd095e68ab39629c0f32815dcf2 Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Sat, 15 Sep 2007 14:14:22 -0700 Subject: [PATCH 1382/2804] S2io: Cleanup - removed unused variable intr_type - Removed the unused variable, intr_type, in device private structure. [ Resolve conflicts with napi_struct changes... -DaveM ] Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/s2io.c | 34 +++++++++++++++++----------------- drivers/net/s2io.h | 5 ----- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 182643ff81e5..2ee2a2b4b272 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1611,7 +1611,7 @@ static int init_nic(struct s2io_nic *nic) val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | RTI_DATA2_MEM_RX_UFC_B(0x2) ; - if (nic->intr_type == MSI_X) + if (nic->config.intr_type == MSI_X) val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ RTI_DATA2_MEM_RX_UFC_D(0x40)); else @@ -1749,7 +1749,7 @@ static int init_nic(struct s2io_nic *nic) static int s2io_link_fault_indication(struct s2io_nic *nic) { - if (nic->intr_type != INTA) + if (nic->config.intr_type != INTA) return MAC_RMAC_ERR_TIMER; if (nic->device_type == XFRAME_II_DEVICE) return LINK_UP_DOWN_INTERRUPT; @@ -3549,7 +3549,7 @@ static int s2io_set_swapper(struct s2io_nic * sp) SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); - if (sp->intr_type == INTA) + if (sp->config.intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #else @@ -3572,7 +3572,7 @@ static int s2io_set_swapper(struct s2io_nic * sp) SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); - if (sp->intr_type == INTA) + if (sp->config.intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #endif @@ -3848,7 +3848,7 @@ static int s2io_open(struct net_device *dev) napi_enable(&sp->napi); - if (sp->intr_type == MSI_X) { + if (sp->config.intr_type == MSI_X) { int ret = s2io_enable_msi_x(sp); if (!ret) { @@ -3880,12 +3880,12 @@ static int s2io_open(struct net_device *dev) DBG_PRINT(ERR_DBG, "%s: MSI-X requested but failed to enable\n", dev->name); - sp->intr_type = INTA; + sp->config.intr_type = INTA; } } /* NAPI doesn't work well with MSI(X) */ - if (sp->intr_type != INTA) { + if (sp->config.intr_type != INTA) { if(sp->config.napi) sp->config.napi = 0; } @@ -3910,7 +3910,7 @@ static int s2io_open(struct net_device *dev) hw_init_failed: napi_disable(&sp->napi); - if (sp->intr_type == MSI_X) { + if (sp->config.intr_type == MSI_X) { if (sp->entries) { kfree(sp->entries); sp->mac_control.stats_info->sw_stat.mem_freed @@ -6697,18 +6697,18 @@ static int s2io_add_isr(struct s2io_nic * sp) struct net_device *dev = sp->dev; int err = 0; - if (sp->intr_type == MSI_X) + if (sp->config.intr_type == MSI_X) ret = s2io_enable_msi_x(sp); if (ret) { DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name); - sp->intr_type = INTA; + sp->config.intr_type = INTA; } /* 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 */ - if (sp->intr_type == MSI_X) { + if (sp->config.intr_type == MSI_X) { int i, msix_tx_cnt=0,msix_rx_cnt=0; for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) { @@ -6760,7 +6760,7 @@ static int s2io_add_isr(struct s2io_nic * sp) printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt); printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt); } - if (sp->intr_type == INTA) { + if (sp->config.intr_type == INTA) { err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED, sp->name, dev); if (err) { @@ -6777,7 +6777,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) struct net_device *dev = sp->dev; struct swStat *stats = &sp->mac_control.stats_info->sw_stat; - if (sp->intr_type == MSI_X) { + if (sp->config.intr_type == MSI_X) { int i; u16 msi_control; @@ -6950,7 +6950,7 @@ static int s2io_card_up(struct s2io_nic * sp) /* Add interrupt service routine */ if (s2io_add_isr(sp) != 0) { - if (sp->intr_type == MSI_X) + if (sp->config.intr_type == MSI_X) s2io_rem_isr(sp); s2io_reset(sp); free_rx_buffers(sp); @@ -6964,7 +6964,7 @@ static int s2io_card_up(struct s2io_nic * sp) /* Enable select interrupts */ en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS); - if (sp->intr_type != INTA) + if (sp->config.intr_type != INTA) en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS); else { interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; @@ -7491,7 +7491,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (rx_ring_mode == 2) sp->rxd_mode = RXD_MODE_3B; - sp->intr_type = dev_intr_type; + sp->config.intr_type = dev_intr_type; if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || (pdev->device == PCI_DEVICE_ID_HERC_UNI)) @@ -7770,7 +7770,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (napi) DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); - switch(sp->intr_type) { + switch(sp->config.intr_type) { case INTA: DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); break; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 1e2e72d6aad2..c01abc1d89af 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -906,11 +906,6 @@ struct s2io_nic { unsigned long sending_both; u8 lro; u16 lro_max_aggr_per_sess; - -#define INTA 0 -#define MSI_X 2 - u8 intr_type; - spinlock_t rx_lock; atomic_t isr_cnt; u64 general_int_mask; From 92b84437a6cddf5dc00ab179e38d2baa2264d46a Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Thu, 6 Sep 2007 06:51:14 -0400 Subject: [PATCH 1383/2804] S2io: Check for device state before handling traffic - Added check to return from the traffic handling function, if the card status is DOWN. - Implemented Jeff's comments on incorrect return value in s2io_poll function. Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 56 +++++++++++++++++++++++++++++++--------------- drivers/net/s2io.h | 12 ++++++---- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2ee2a2b4b272..d167bc0ae951 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -130,6 +130,11 @@ static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring) return 0; } +static inline int is_s2io_card_up(const struct s2io_nic * sp) +{ + return test_bit(__S2IO_STATE_CARD_UP, &sp->state); +} + /* Ethtool related variables and Macros. */ static char s2io_gstrings[][ETH_GSTRING_LEN] = { "Register test\t(offline)", @@ -2711,6 +2716,12 @@ static int s2io_poll(struct napi_struct *napi, int budget) int i; atomic_inc(&nic->isr_cnt); + + if (!is_s2io_card_up(nic)) { + atomic_dec(&nic->isr_cnt); + return 0; + } + mac_control = &nic->mac_control; config = &nic->config; @@ -2837,12 +2848,6 @@ static void rx_intr_handler(struct ring_info *ring_data) struct RxD3* rxdp3; spin_lock(&nic->rx_lock); - if (atomic_read(&nic->card_state) == CARD_DOWN) { - DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n", - __FUNCTION__, dev->name); - spin_unlock(&nic->rx_lock); - return; - } get_info = ring_data->rx_curr_get_info; get_block = get_info.block_index; @@ -3990,7 +3995,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } spin_lock_irqsave(&sp->tx_lock, flags); - if (atomic_read(&sp->card_state) == CARD_DOWN) { + if (!is_s2io_card_up(sp)) { DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", dev->name); spin_unlock_irqrestore(&sp->tx_lock, flags); @@ -4184,6 +4189,11 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) atomic_inc(&sp->isr_cnt); + if (!is_s2io_card_up(sp)) { + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } + rx_intr_handler(ring); s2io_chk_rx_buffers(sp, ring->ring_no); @@ -4197,6 +4207,12 @@ static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) struct s2io_nic *sp = fifo->nic; atomic_inc(&sp->isr_cnt); + + if (!is_s2io_card_up(sp)) { + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } + tx_intr_handler(fifo); atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; @@ -4305,7 +4321,7 @@ static void s2io_handle_errors(void * dev_id) struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat; struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat; - if (unlikely(atomic_read(&sp->card_state) == CARD_DOWN)) + if (!is_s2io_card_up(sp)) return; if (pci_channel_offline(sp->pdev)) @@ -4576,6 +4592,12 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) return IRQ_NONE; atomic_inc(&sp->isr_cnt); + + if (!is_s2io_card_up(sp)) { + atomic_dec(&sp->isr_cnt); + return IRQ_NONE; + } + mac_control = &sp->mac_control; config = &sp->config; @@ -4664,7 +4686,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) u64 val64; int cnt = 0; - if (atomic_read(&sp->card_state) == CARD_UP) { + if (is_s2io_card_up(sp)) { /* Apprx 30us on a 133 MHz bus */ val64 = SET_UPDT_CLICKS(10) | STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN; @@ -6460,7 +6482,7 @@ static void s2io_set_link(struct work_struct *work) if (!netif_running(dev)) goto out_unlock; - if (test_and_set_bit(0, &(nic->link_state))) { + if (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(nic->state))) { /* The card is being reset, no point doing anything */ goto out_unlock; } @@ -6516,7 +6538,7 @@ static void s2io_set_link(struct work_struct *work) writeq(val64, &bar0->adapter_control); s2io_link(nic, LINK_DOWN); } - clear_bit(0, &(nic->link_state)); + clear_bit(__S2IO_STATE_LINK_TASK, &(nic->state)); out_unlock: rtnl_unlock(); @@ -6825,10 +6847,10 @@ 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(0, &(sp->link_state))) { + while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) { msleep(50); } - atomic_set(&sp->card_state, CARD_DOWN); + clear_bit(__S2IO_STATE_CARD_UP, &sp->state); /* disable Tx and Rx traffic on the NIC */ if (do_io) @@ -6879,7 +6901,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) free_rx_buffers(sp); spin_unlock_irqrestore(&sp->rx_lock, flags); - clear_bit(0, &(sp->link_state)); + clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state)); } static void s2io_card_down(struct s2io_nic * sp) @@ -6972,8 +6994,7 @@ static int s2io_card_up(struct s2io_nic * sp) en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS); } - - atomic_set(&sp->card_state, CARD_UP); + set_bit(__S2IO_STATE_CARD_UP, &sp->state); return 0; } @@ -7701,9 +7722,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) * Initialize the tasklet status and link state flags * and the card state parameter */ - atomic_set(&(sp->card_state), 0); sp->tasklet_status = 0; - sp->link_state = 0; + sp->state = 0; /* Initialize spinlocks */ spin_lock_init(&sp->tx_lock); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index c01abc1d89af..33e812ea7d18 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -802,6 +802,13 @@ struct lro { u8 saw_ts; }; +/* These flags represent the devices temporary state */ +enum s2io_device_state_t +{ + __S2IO_STATE_LINK_TASK=0, + __S2IO_STATE_CARD_UP +}; + /* Structure representing one instance of the NIC */ struct s2io_nic { int rxd_mode; @@ -880,10 +887,6 @@ struct s2io_nic { int task_flag; unsigned long long start_time; -#define CARD_DOWN 1 -#define CARD_UP 2 - atomic_t card_state; - volatile unsigned long link_state; struct vlan_group *vlgrp; #define MSIX_FLG 0xA5 struct msix_entry *entries; @@ -906,6 +909,7 @@ struct s2io_nic { unsigned long sending_both; u8 lro; u16 lro_max_aggr_per_sess; + volatile unsigned long state; spinlock_t rx_lock; atomic_t isr_cnt; u64 general_int_mask; From 596c5c97431eab8465739c169401ea611127b9ad Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Sat, 15 Sep 2007 14:24:03 -0700 Subject: [PATCH 1384/2804] S2io: code Optimization of isr function - Code Optimization of s2io_isr function. - Isr check using per device napi variable instead of driver global. - Reduced from 3 to 1 if condition before check for processing packet receive packets. - Implemented Jeff's comment to use synchronize_irq. Removed the isr_cnt variable as it became redundant. - One time de assert the interrupts by writing all F's to the general_int_mask register instead of de asserting by clearing the source of interrupts with multiple writes which causes loss of interrupts (race conditions). It is entirely possible that before the driver has a chance to mask the asserted alarm bit, another alarm/traffic interrupt bit gets asserted as well. In this case Herc will keep the INTA line asserted and the bridge will not send a new Assert_INTA message upstream. [ Resolved conflicts due to napi_struct changes... -DaveM ] Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/s2io.c | 161 ++++++++++++++++++--------------------------- drivers/net/s2io.h | 1 - 2 files changed, 63 insertions(+), 99 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index d167bc0ae951..ac6b9b93c025 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.1" +#define DRV_VERSION "2.0.26.2" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -2715,12 +2715,8 @@ static int s2io_poll(struct napi_struct *napi, int budget) struct XENA_dev_config __iomem *bar0 = nic->bar0; int i; - atomic_inc(&nic->isr_cnt); - - if (!is_s2io_card_up(nic)) { - atomic_dec(&nic->isr_cnt); + if (!is_s2io_card_up(nic)) return 0; - } mac_control = &nic->mac_control; config = &nic->config; @@ -2752,7 +2748,6 @@ static int s2io_poll(struct napi_struct *napi, int budget) /* Re enable the Rx interrupts. */ writeq(0x0, &bar0->rx_traffic_mask); readl(&bar0->rx_traffic_mask); - atomic_dec(&nic->isr_cnt); return pkt_cnt; no_rx: @@ -2763,7 +2758,6 @@ no_rx: break; } } - atomic_dec(&nic->isr_cnt); return pkt_cnt; } @@ -2791,7 +2785,6 @@ static void s2io_netpoll(struct net_device *dev) disable_irq(dev->irq); - atomic_inc(&nic->isr_cnt); mac_control = &nic->mac_control; config = &nic->config; @@ -2816,7 +2809,6 @@ static void s2io_netpoll(struct net_device *dev) break; } } - atomic_dec(&nic->isr_cnt); enable_irq(dev->irq); return; } @@ -4187,17 +4179,12 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) struct ring_info *ring = (struct ring_info *)dev_id; struct s2io_nic *sp = ring->nic; - atomic_inc(&sp->isr_cnt); - - if (!is_s2io_card_up(sp)) { - atomic_dec(&sp->isr_cnt); + if (!is_s2io_card_up(sp)) return IRQ_HANDLED; - } rx_intr_handler(ring); s2io_chk_rx_buffers(sp, ring->ring_no); - atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } @@ -4206,15 +4193,10 @@ static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) struct fifo_info *fifo = (struct fifo_info *)dev_id; struct s2io_nic *sp = fifo->nic; - atomic_inc(&sp->isr_cnt); - - if (!is_s2io_card_up(sp)) { - atomic_dec(&sp->isr_cnt); + if (!is_s2io_card_up(sp)) return IRQ_HANDLED; - } tx_intr_handler(fifo); - atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } static void s2io_txpic_intr_handle(struct s2io_nic *sp) @@ -4591,12 +4573,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (pci_channel_offline(sp->pdev)) return IRQ_NONE; - atomic_inc(&sp->isr_cnt); - - if (!is_s2io_card_up(sp)) { - atomic_dec(&sp->isr_cnt); + if (!is_s2io_card_up(sp)) return IRQ_NONE; - } mac_control = &sp->mac_control; config = &sp->config; @@ -4607,73 +4585,75 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) * 1. Rx of packet. * 2. Tx complete. * 3. Link down. - * 4. Error in any functional blocks of the NIC. */ reason = readq(&bar0->general_int_status); - if (!reason) { - /* The interrupt was not raised by us. */ - atomic_dec(&sp->isr_cnt); - return IRQ_NONE; - } - else if (unlikely(reason == S2IO_MINUS_ONE) ) { - /* Disable device and get out */ - atomic_dec(&sp->isr_cnt); - return IRQ_NONE; + if (unlikely(reason == S2IO_MINUS_ONE) ) { + /* Nothing much can be done. Get out */ + return IRQ_HANDLED; } - if (napi) { - if (reason & GEN_INTR_RXTRAFFIC) { - if (likely (netif_rx_schedule_prep(dev, &sp->napi))) { - __netif_rx_schedule(dev, &sp->napi); - writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); + if (reason & (GEN_INTR_RXTRAFFIC | + GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC)) + { + writeq(S2IO_MINUS_ONE, &bar0->general_int_mask); + + if (config->napi) { + if (reason & GEN_INTR_RXTRAFFIC) { + if (likely(netif_rx_schedule_prep(dev, + &sp->napi))) { + __netif_rx_schedule(dev, &sp->napi); + writeq(S2IO_MINUS_ONE, + &bar0->rx_traffic_mask); + } else + writeq(S2IO_MINUS_ONE, + &bar0->rx_traffic_int); } - else + } else { + /* + * rx_traffic_int reg is an R1 register, writing all 1's + * will ensure that the actual interrupt causing bit + * get's cleared and hence a read can be avoided. + */ + 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]); } - } else { + /* - * Rx handler is called by default, without checking for the - * cause of interrupt. - * rx_traffic_int reg is an R1 register, writing all 1's + * tx_traffic_int reg is an R1 register, writing all 1's * will ensure that the actual interrupt causing bit get's * cleared and hence a read can be avoided. */ - if (reason & GEN_INTR_RXTRAFFIC) - writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); + if (reason & GEN_INTR_TXTRAFFIC) + writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); - for (i = 0; i < config->rx_ring_num; i++) { - rx_intr_handler(&mac_control->rings[i]); + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&mac_control->fifos[i]); + + if (reason & GEN_INTR_TXPIC) + s2io_txpic_intr_handle(sp); + + /* + * 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, i); } + writeq(sp->general_int_mask, &bar0->general_int_mask); + readl(&bar0->general_int_status); + + return IRQ_HANDLED; + + } + else if (!reason) { + /* The interrupt was not raised by us */ + return IRQ_NONE; } - /* - * tx_traffic_int reg is an R1 register, writing all 1's - * will ensure that the actual interrupt causing bit get's - * cleared and hence a read can be avoided. - */ - if (reason & GEN_INTR_TXTRAFFIC) - writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); - - for (i = 0; i < config->tx_fifo_num; i++) - tx_intr_handler(&mac_control->fifos[i]); - - if (reason & GEN_INTR_TXPIC) - s2io_txpic_intr_handle(sp); - /* - * If the Rx buffer count is below the panic threshold then - * reallocate the buffers from the interrupt handler itself, - * else schedule a tasklet to reallocate the buffers. - */ - if (!napi) { - for (i = 0; i < config->rx_ring_num; i++) - s2io_chk_rx_buffers(sp, i); - } - - writeq(0, &bar0->general_int_mask); - readl(&bar0->general_int_status); - - atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } @@ -6795,7 +6775,6 @@ static int s2io_add_isr(struct s2io_nic * sp) } static void s2io_rem_isr(struct s2io_nic * sp) { - int cnt = 0; struct net_device *dev = sp->dev; struct swStat *stats = &sp->mac_control.stats_info->sw_stat; @@ -6808,6 +6787,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) int vector = sp->entries[i].vector; void *arg = sp->s2io_entries[i].arg; + synchronize_irq(vector); free_irq(vector, arg); } @@ -6826,16 +6806,9 @@ static void s2io_rem_isr(struct s2io_nic * sp) pci_disable_msix(sp->pdev); } else { + synchronize_irq(sp->pdev->irq); free_irq(sp->pdev->irq, dev); } - /* Waiting till all Interrupt handlers are complete */ - cnt = 0; - do { - msleep(10); - if (!atomic_read(&sp->isr_cnt)) - break; - cnt++; - } while(cnt < 5); } static void do_s2io_card_down(struct s2io_nic * sp, int do_io) @@ -7365,19 +7338,12 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) if (*dev_intr_type != INTA) napi = 0; -#ifndef CONFIG_PCI_MSI - if (*dev_intr_type != INTA) { - DBG_PRINT(ERR_DBG, "s2io: This kernel does not support" - "MSI/MSI-X. Defaulting to INTA\n"); - *dev_intr_type = INTA; - } -#else if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) { DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. " "Defaulting to INTA\n"); *dev_intr_type = INTA; } -#endif + if ((*dev_intr_type == MSI_X) && ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { @@ -7535,6 +7501,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) mac_control = &sp->mac_control; config = &sp->config; + config->napi = napi; + /* Tx side parameters. */ config->tx_fifo_num = tx_fifo_num; for (i = 0; i < MAX_TX_FIFOS; i++) { @@ -7582,9 +7550,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) for (i = 0; i < config->rx_ring_num; i++) atomic_set(&sp->rx_bufs_left[i], 0); - /* Initialize the number of ISRs currently running */ - atomic_set(&sp->isr_cnt, 0); - /* 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", diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 33e812ea7d18..1a70cf02c915 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -911,7 +911,6 @@ struct s2io_nic { u16 lro_max_aggr_per_sess; volatile unsigned long state; spinlock_t rx_lock; - atomic_t isr_cnt; u64 general_int_mask; u64 *ufo_in_band_v; #define VPD_STRING_LEN 80 From 10d024c1b2fd58af8362670d7d6e5ae52fc33353 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 17 Sep 2007 13:11:17 -0700 Subject: [PATCH 1385/2804] [NET]: Nuke SET_MODULE_OWNER macro. It's been a useless no-op for long enough in 2.6 so I figured it's time to remove it. The number of people that could object because they're maintaining unified 2.4 and 2.6 drivers is probably rather small. [ Handled drivers added by netdev tree and some missed IRDA cases... -DaveM ] Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/ieee1394/eth1394.c | 1 - drivers/infiniband/hw/amso1100/c2.c | 1 - drivers/infiniband/hw/amso1100/c2_provider.c | 1 - drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 -- drivers/message/fusion/mptlan.c | 2 -- drivers/net/3c501.c | 2 -- drivers/net/3c503.c | 2 -- drivers/net/3c505.c | 2 -- drivers/net/3c507.c | 2 -- drivers/net/3c509.c | 6 ------ drivers/net/3c515.c | 2 -- drivers/net/3c523.c | 1 - drivers/net/3c527.c | 2 -- drivers/net/3c59x.c | 1 - drivers/net/8139cp.c | 1 - drivers/net/8139too.c | 1 - drivers/net/82596.c | 1 - drivers/net/a2065.c | 1 - drivers/net/ac3200.c | 2 -- drivers/net/acenic.c | 1 - drivers/net/amd8111e.c | 1 - drivers/net/apne.c | 1 - drivers/net/appletalk/cops.c | 2 -- drivers/net/appletalk/ipddp.c | 1 - drivers/net/appletalk/ltpc.c | 2 -- drivers/net/arcnet/com90io.c | 2 -- drivers/net/ariadne.c | 1 - drivers/net/arm/at91_ether.c | 1 - drivers/net/arm/ether1.c | 1 - drivers/net/arm/ether3.c | 1 - drivers/net/arm/etherh.c | 1 - drivers/net/at1700.c | 2 -- drivers/net/atarilance.c | 1 - drivers/net/atl1/atl1_main.c | 1 - drivers/net/atp.c | 1 - drivers/net/b44.c | 1 - drivers/net/bfin_mac.c | 1 - drivers/net/bmac.c | 1 - drivers/net/bnx2.c | 1 - drivers/net/bonding/bond_main.c | 2 -- drivers/net/cassini.c | 1 - drivers/net/chelsio/cxgb2.c | 1 - drivers/net/cs89x0.c | 1 - drivers/net/cxgb3/cxgb3_main.c | 1 - drivers/net/de600.c | 1 - drivers/net/de620.c | 2 -- drivers/net/defxx.c | 1 - drivers/net/dgrs.c | 2 -- drivers/net/dl2k.c | 1 - drivers/net/dm9000.c | 1 - drivers/net/dummy.c | 1 - drivers/net/e100.c | 1 - drivers/net/e1000/e1000_main.c | 1 - drivers/net/e1000e/netdev.c | 1 - drivers/net/e2100.c | 2 -- drivers/net/eepro.c | 4 ---- drivers/net/eepro100.c | 1 - drivers/net/eexpress.c | 2 -- drivers/net/ehea/ehea_main.c | 2 -- drivers/net/epic100.c | 1 - drivers/net/eql.c | 2 -- drivers/net/es3210.c | 2 -- drivers/net/eth16i.c | 2 -- drivers/net/ewrk3.c | 1 - drivers/net/fealnx.c | 1 - drivers/net/fec_8xx/fec_main.c | 1 - drivers/net/forcedeth.c | 1 - drivers/net/fs_enet/fs_enet-main.c | 1 - drivers/net/gianfar.c | 1 - drivers/net/hamachi.c | 1 - drivers/net/hamradio/6pack.c | 2 -- drivers/net/hp-plus.c | 2 -- drivers/net/hp.c | 2 -- drivers/net/hp100.c | 5 ----- drivers/net/hydra.c | 1 - drivers/net/ibm_emac/ibm_emac_core.c | 1 - drivers/net/ibmlana.c | 2 -- drivers/net/ibmveth.c | 4 ---- drivers/net/ifb.c | 1 - drivers/net/ioc3-eth.c | 1 - drivers/net/irda/ali-ircc.c | 4 ---- drivers/net/irda/donauboe.c | 1 - drivers/net/irda/irda-usb.c | 1 - drivers/net/irda/irport.c | 2 -- drivers/net/irda/kingsun-sir.c | 1 - drivers/net/irda/ks959-sir.c | 1 - drivers/net/irda/ksdazzle-sir.c | 1 - drivers/net/irda/mcs7780.c | 2 -- drivers/net/irda/nsc-ircc.c | 1 - drivers/net/irda/sir_dev.c | 2 -- drivers/net/irda/smsc-ircc2.c | 2 -- drivers/net/irda/stir4200.c | 1 - drivers/net/irda/via-ircc.c | 3 --- drivers/net/irda/vlsi_ir.c | 2 -- drivers/net/irda/w83977af_ir.c | 3 --- drivers/net/isa-skeleton.c | 2 -- drivers/net/ixgb/ixgb_main.c | 1 - drivers/net/ixgbe/ixgbe_main.c | 1 - drivers/net/ixp2000/enp2611.c | 1 - drivers/net/jazzsonic.c | 1 - drivers/net/lance.c | 1 - drivers/net/lguest_net.c | 2 -- drivers/net/lne390.c | 2 -- drivers/net/mac8390.c | 2 -- drivers/net/mac89x0.c | 2 -- drivers/net/macb.c | 1 - drivers/net/mace.c | 1 - drivers/net/macmace.c | 1 - drivers/net/macsonic.c | 1 - drivers/net/mv643xx_eth.c | 1 - drivers/net/mvme147.c | 2 -- drivers/net/myri_sbus.c | 1 - drivers/net/natsemi.c | 1 - drivers/net/ne-h8300.c | 2 -- drivers/net/ne.c | 2 -- drivers/net/ne2.c | 2 -- drivers/net/ne2k-pci.c | 1 - drivers/net/ne3210.c | 1 - drivers/net/netx-eth.c | 1 - drivers/net/netxen/netxen_nic_main.c | 1 - drivers/net/ni5010.c | 2 -- drivers/net/ni52.c | 2 -- drivers/net/ni65.c | 1 - drivers/net/ns83820.c | 1 - drivers/net/pasemi_mac.c | 1 - drivers/net/pci-skeleton.c | 1 - drivers/net/pcmcia/3c589_cs.c | 1 - drivers/net/pcmcia/axnet_cs.c | 3 --- drivers/net/pcmcia/fmvj18x_cs.c | 1 - drivers/net/pcmcia/nmclan_cs.c | 1 - drivers/net/pcmcia/pcnet_cs.c | 1 - drivers/net/pcmcia/smc91c92_cs.c | 1 - drivers/net/pcmcia/xirc2ps_cs.c | 1 - drivers/net/pcnet32.c | 1 - drivers/net/plip.c | 1 - drivers/net/ps3_gelic_net.c | 1 - drivers/net/qla3xxx.c | 1 - drivers/net/r8169.c | 1 - drivers/net/rionet.c | 2 -- drivers/net/rrunner.c | 1 - drivers/net/s2io.c | 1 - drivers/net/sb1000.c | 1 - drivers/net/shaper.c | 2 -- drivers/net/sis190.c | 1 - drivers/net/sis900.c | 1 - drivers/net/sk98lin/skge.c | 1 - drivers/net/skfp/skfddi.c | 1 - drivers/net/skge.c | 1 - drivers/net/sky2.c | 1 - drivers/net/slip.c | 2 -- drivers/net/smc-mca.c | 1 - drivers/net/smc-ultra.c | 2 -- drivers/net/smc-ultra32.c | 2 -- drivers/net/smc911x.c | 1 - drivers/net/smc9194.c | 2 -- drivers/net/smc91x.c | 1 - drivers/net/spider_net.c | 1 - drivers/net/starfire.c | 1 - drivers/net/stnic.c | 1 - drivers/net/sun3_82586.c | 1 - drivers/net/sun3lance.c | 1 - drivers/net/sunbmac.c | 1 - drivers/net/sundance.c | 1 - drivers/net/sungem.c | 1 - drivers/net/sunhme.c | 2 -- drivers/net/sunlance.c | 1 - drivers/net/sunqe.c | 1 - drivers/net/tc35815.c | 1 - drivers/net/tg3.c | 1 - drivers/net/tlan.c | 1 - drivers/net/tokenring/3c359.c | 1 - drivers/net/tokenring/abyss.c | 2 -- drivers/net/tokenring/lanstreamer.c | 1 - drivers/net/tokenring/madgemc.c | 1 - drivers/net/tokenring/olympic.c | 1 - drivers/net/tokenring/proteon.c | 1 - drivers/net/tokenring/skisa.c | 1 - drivers/net/tokenring/smctr.c | 2 -- drivers/net/tokenring/tmspci.c | 1 - drivers/net/tsi108_eth.c | 1 - drivers/net/tulip/de2104x.c | 1 - drivers/net/tulip/de4x5.c | 1 - drivers/net/tulip/dmfe.c | 1 - drivers/net/tulip/tulip_core.c | 1 - drivers/net/tulip/uli526x.c | 1 - drivers/net/tulip/winbond-840.c | 1 - drivers/net/tulip/xircom_cb.c | 1 - drivers/net/tulip/xircom_tulip_cb.c | 1 - drivers/net/tun.c | 1 - drivers/net/typhoon.c | 1 - drivers/net/ucc_geth.c | 1 - drivers/net/usb/kaweth.c | 2 -- drivers/net/usb/pegasus.c | 1 - drivers/net/usb/rtl8150.c | 1 - drivers/net/usb/usbnet.c | 1 - drivers/net/via-rhine.c | 1 - drivers/net/via-velocity.c | 1 - drivers/net/wan/c101.c | 1 - drivers/net/wan/cycx_x25.c | 1 - drivers/net/wan/dscc4.c | 1 - drivers/net/wan/hostess_sv11.c | 2 -- drivers/net/wan/lapbether.c | 1 - drivers/net/wan/lmc/lmc_main.c | 1 - drivers/net/wan/n2.c | 1 - drivers/net/wan/pc300too.c | 1 - drivers/net/wan/pci200syn.c | 1 - drivers/net/wan/sbni.c | 2 -- drivers/net/wan/sdla.c | 1 - drivers/net/wan/wanxl.c | 1 - drivers/net/wd.c | 2 -- drivers/net/wireless/airo.c | 1 - drivers/net/wireless/airport.c | 1 - drivers/net/wireless/arlan-main.c | 2 -- drivers/net/wireless/atmel.c | 1 - drivers/net/wireless/bcm43xx/bcm43xx_main.c | 1 - drivers/net/wireless/ipw2100.c | 2 -- drivers/net/wireless/ipw2200.c | 1 - drivers/net/wireless/libertas/main.c | 4 ---- drivers/net/wireless/netwave_cs.c | 1 - drivers/net/wireless/orinoco_cs.c | 1 - drivers/net/wireless/orinoco_nortel.c | 1 - drivers/net/wireless/orinoco_pci.c | 1 - drivers/net/wireless/orinoco_plx.c | 1 - drivers/net/wireless/orinoco_tmd.c | 1 - drivers/net/wireless/prism54/islpci_dev.c | 1 - drivers/net/wireless/ray_cs.c | 1 - drivers/net/wireless/spectrum_cs.c | 1 - drivers/net/wireless/strip.c | 2 -- drivers/net/wireless/wavelan.c | 1 - drivers/net/wireless/wavelan_cs.c | 1 - drivers/net/wireless/wl3501_cs.c | 2 -- drivers/net/wireless/zd1211rw/zd_netdev.c | 1 - drivers/net/xen-netfront.c | 1 - drivers/net/yellowfin.c | 1 - drivers/net/znet.c | 2 -- drivers/net/zorro8390.c | 1 - drivers/s390/net/claw.c | 1 - drivers/s390/net/ctcmain.c | 1 - drivers/s390/net/lcs.c | 1 - drivers/s390/net/netiucv.c | 1 - drivers/s390/net/qeth_main.c | 1 - drivers/usb/gadget/ether.c | 1 - include/linux/netdevice.h | 1 - net/8021q/vlan.c | 2 -- net/bridge/br_device.c | 1 - net/ipv4/ip_gre.c | 1 - net/ipv4/ipip.c | 2 -- net/ipv6/ip6_tunnel.c | 1 - net/ipv6/sit.c | 1 - net/irda/irlan/irlan_eth.c | 2 -- net/sched/sch_teql.c | 1 - 251 files changed, 341 deletions(-) diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 3a9d7e2d4de6..33b80817d68c 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -598,7 +598,6 @@ static void ether1394_add_host(struct hpsb_host *host) goto out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &host->device); priv = netdev_priv(dev); diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index 0aecea67f3e6..f283a9f0c23b 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -886,7 +886,6 @@ static struct net_device *c2_devinit(struct c2_dev *c2dev, return NULL; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev); netdev->open = c2_up; diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 997cf1530762..7a6cece6ea9d 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -715,7 +715,6 @@ static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu) static void setup(struct net_device *netdev) { - SET_MODULE_OWNER(netdev); netdev->open = c2_pseudo_up; netdev->stop = c2_pseudo_down; netdev->hard_start_xmit = c2_pseudo_xmit_frame; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index a59ff07ec3cd..b1c3d6cd8eba 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -978,8 +978,6 @@ static void ipoib_setup(struct net_device *dev) netif_carrier_off(dev); - SET_MODULE_OWNER(dev); - priv->dev = dev; spin_lock_init(&priv->lock); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 01fc397fdd97..3da4c37846ec 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -1427,8 +1427,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) dlprintk((KERN_INFO MYNAM ": Finished registering dev " "and setting initial values\n")); - SET_MODULE_OWNER(dev); - if (register_netdev(dev) != 0) { free_netdev(dev); dev = NULL; diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 4bee99ba7dbb..98e0bc4628a2 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -174,8 +174,6 @@ struct net_device * __init el1_probe(int unit) mem_start = dev->mem_start & 7; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = el1_probe1(dev, io); } else if (io != 0) { diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index bc7e906571d3..f9e7ffbcb772 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -95,8 +95,6 @@ static int __init do_el2_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return el2_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index acede307c05d..c05bb3fc57a2 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1387,8 +1387,6 @@ static int __init elplus_setup(struct net_device *dev) unsigned long cookie = 0; int err = -ENODEV; - SET_MODULE_OWNER(dev); - /* * setup adapter structure */ diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index eed4299dc426..fac6edff2b8b 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -327,8 +327,6 @@ struct net_device * __init el16_probe(int unit) mem_start = dev->mem_start & 15; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) /* Check a single specified location. */ err = el16_probe1(dev, io); else if (io != 0) diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 127f60841b10..7466987d8451 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -432,7 +432,6 @@ __again: return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &idev->dev); pnp_cards++; @@ -524,8 +523,6 @@ no_pnp: if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); - netdev_boot_setup_check(dev); /* Set passed-in IRQ or I/O Addr. */ @@ -644,7 +641,6 @@ static int __init el3_mca_probe(struct device *device) return -ENOMEM; } - SET_MODULE_OWNER(dev); netdev_boot_setup_check(dev); memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); @@ -704,8 +700,6 @@ static int __init el3_eisa_probe (struct device *device) return -ENOMEM; } - SET_MODULE_OWNER(dev); - netdev_boot_setup_check(dev); memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 290166d5e7d1..38a2ebea9b45 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -501,8 +501,6 @@ static struct net_device *corkscrew_scan(int unit) netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); - #ifdef __ISAPNP__ if(nopnp == 1) goto no_pnp; diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index ab18343e58ef..10852b2a40ab 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -423,7 +423,6 @@ static int __init do_elmc_probe(struct net_device *dev) int retval; struct priv *pr = dev->priv; - SET_MODULE_OWNER(dev); if (MCA_bus == 0) { return -ENODEV; } diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index c7b571be20e0..5b5f44cdfc1d 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -257,8 +257,6 @@ struct net_device *__init mc32_probe(int unit) if (unit >= 0) sprintf(dev->name, "eth%d", unit); - SET_MODULE_OWNER(dev); - /* Do not check any supplied i/o locations. POS registers usually don't fail :) */ diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 29e558913eb5..ad0f6a729d29 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1036,7 +1036,6 @@ static int __devinit vortex_probe1(struct device *gendev, printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); goto out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gendev); vp = netdev_priv(dev); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 2dec3d6ae01a..30310ed9f75f 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1845,7 +1845,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev = alloc_etherdev(sizeof(struct cp_private)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); cp = netdev_priv(dev); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 7ba470ee2175..28c1aaf1fe1d 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -766,7 +766,6 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, dev_err(&pdev->dev, "Unable to alloc new net device\n"); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); diff --git a/drivers/net/82596.c b/drivers/net/82596.c index d915837193cc..43dffdca708f 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1234,7 +1234,6 @@ struct net_device * __init i82596_probe(int unit) DEB(DEB_PROBE,printk(KERN_INFO "%s", version)); /* The 82596-specific entries in the device structure. */ - SET_MODULE_OWNER(dev); dev->open = i596_open; dev->stop = i596_close; dev->hard_start_xmit = i596_start_xmit; diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index a45de6975bfe..fa0c6cb3d798 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -746,7 +746,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z, return -ENOMEM; } - SET_MODULE_OWNER(dev); priv = netdev_priv(dev); r1->name = dev->name; diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 644c408515df..65b2de56ed22 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -103,8 +103,6 @@ static int __init do_ac3200_probe(struct net_device *dev) int irq = dev->irq; int mem_start = dev->mem_start; - SET_MODULE_OWNER(dev); - if (ioaddr > 0x1ff) /* Check a single specified location. */ return ac_probe1(ioaddr, dev); else if (ioaddr > 0) /* Don't probe at all. */ diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 62e660a79387..ca00f41e4d85 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -465,7 +465,6 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); ap = dev->priv; diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index cf06fc067e92..afb60a5927ae 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1982,7 +1982,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, goto err_free_reg; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); #if AMD8111E_VLAN_TAG_USED diff --git a/drivers/net/apne.c b/drivers/net/apne.c index 954191119d35..b073810f9fd8 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -148,7 +148,6 @@ struct net_device * __init apne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); /* disable pcmcia irq for readtuple */ pcmcia_disable_irq(); diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index da6ffa8cd81e..c4b560d42a67 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -235,8 +235,6 @@ struct net_device * __init cops_probe(int unit) base_addr = dev->base_addr = io; } - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) { /* Check a single specified location. */ err = cops_probe1(dev, base_addr); } else if (base_addr != 0) { /* Don't probe at all. */ diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index f22e46dfd770..56cb96794026 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -65,7 +65,6 @@ static struct net_device * __init ipddp_init(void) if (!dev) return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); strcpy(dev->name, "ipddp%d"); if (version_printed++ == 0) diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index 6a6cbd331a16..cb4744e56905 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -1046,8 +1046,6 @@ struct net_device * __init ltpc_probe(void) if (!dev) goto out; - SET_MODULE_OWNER(dev); - /* probe for the I/O port address */ if (io != 0x240 && request_region(0x220,8,"ltpc")) { diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 1f0302735416..6599f1046c7b 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -398,8 +398,6 @@ static int __init com90io_init(void) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); - dev->base_addr = io; dev->irq = irq; if (dev->irq == 2) diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index bc5a38a6705f..2c020a36177e 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -183,7 +183,6 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, return -ENOMEM; } - SET_MODULE_OWNER(dev); priv = netdev_priv(dev); r1->name = dev->name; diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index ef2cc80256a3..619810a01e5b 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -986,7 +986,6 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add dev->base_addr = AT91_VA_BASE_EMAC; dev->irq = AT91RM9200_ID_EMAC; - SET_MODULE_OWNER(dev); /* Install the interrupt handler */ if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) { diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index 80f33b6d5713..6ec8a587c1d2 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -1009,7 +1009,6 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) goto release; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &ec->dev); dev->irq = ec->irq; diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 3805506a3ab8..4a914748c0e4 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -789,7 +789,6 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) goto release; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &ec->dev); priv(dev)->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 0d37d9d1fd78..5d093b3ddcd4 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -661,7 +661,6 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) goto release; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &ec->dev); dev->open = etherh_open; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index bed8e0ebaf19..d20148e69fa1 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -225,8 +225,6 @@ struct net_device * __init at1700_probe(int unit) dev->irq = irq; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = at1700_probe1(dev, io); } else if (io != 0) { /* Don't probe at all. */ diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index dfa8b9ba4c80..97cca505cf90 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -390,7 +390,6 @@ struct net_device * __init atarilance_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) { diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 469ff95be559..e1a9223d0c18 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -2234,7 +2234,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev, err = -ENOMEM; goto err_alloc_etherdev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 82d78ff8399b..6020d5ec38b9 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -299,7 +299,6 @@ static int __init atp_probe1(long ioaddr) dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); /* Find the IRQ used by triggering an interrupt. */ write_reg_byte(ioaddr, CMR2, 0x01); /* No accept mode, IRQ out. */ diff --git a/drivers/net/b44.c b/drivers/net/b44.c index b92b3e25c42a..6d193705a3bc 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2151,7 +2151,6 @@ static int __devinit b44_init_one(struct pci_dev *pdev, goto err_out_free_res; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev,&pdev->dev); /* No interesting netdevice features in this card... */ diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 3354c534335d..e5bbcbe8de5f 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -941,7 +941,6 @@ static int bfin_mac_probe(struct platform_device *pdev) return -ENOMEM; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); platform_set_drvdata(pdev, ndev); diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 1eb95b603004..ee157f5a5dbc 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1291,7 +1291,6 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i } bp = netdev_priv(dev); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); macio_set_drvdata(mdev, dev); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index ab028ad04235..61debba873ac 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6474,7 +6474,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) u32 reg; u64 dma_mask, persist_dma_mask; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); bp = netdev_priv(dev); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 559fe9437e0b..88ff72ac9b0a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4674,8 +4674,6 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond goto out_netdev; } - SET_MODULE_OWNER(bond_dev); - res = register_netdevice(bond_dev); if (res < 0) { goto out_bond; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 13f14df21e6e..f44f3d2a4b4e 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4900,7 +4900,6 @@ static int __devinit cas_init_one(struct pci_dev *pdev, err = -ENOMEM; goto err_out_disable_pdev; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); err = pci_request_regions(pdev, dev->name); diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 593736c7550d..884aa0cd0006 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -1036,7 +1036,6 @@ static int __devinit init_one(struct pci_dev *pdev, goto out_free_dev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); if (!adapter) { diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 9774bb1b3e80..2b4c92193912 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -517,7 +517,6 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) int eeprom_buff[CHKSUM_LEN]; int retval; - SET_MODULE_OWNER(dev); /* Initialize the device structure. */ if (!modular) { memset(lp, 0, sizeof(*lp)); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index a6723ae79bdd..19937498589d 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -2465,7 +2465,6 @@ static int __devinit init_one(struct pci_dev *pdev, goto out_free_dev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); adapter->port[i] = netdev; diff --git a/drivers/net/de600.c b/drivers/net/de600.c index dae97b860daa..5dd0d9c0eac9 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -394,7 +394,6 @@ static struct net_device * __init de600_probe(void) if (!dev) return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); if (!request_region(DE600_IO, 3, "de600")) { printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); diff --git a/drivers/net/de620.c b/drivers/net/de620.c index dc4892426174..a92c207b8839 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -823,8 +823,6 @@ struct net_device * __init de620_probe(int unit) if (!dev) goto out; - SET_MODULE_OWNER(dev); - spin_lock_init(&de620_lock); /* diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 9c8e3f9f5e58..b07613e61f53 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -539,7 +539,6 @@ static int __devinit dfx_register(struct device *bdev) goto err_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, bdev); bp = netdev_priv(dev); diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index df62c0232f36..ddedb76303d5 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1272,7 +1272,6 @@ dgrs_found_device( priv->chan = 1; priv->devtbl[0] = dev; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, pdev); ret = dgrs_probe1(dev); @@ -1320,7 +1319,6 @@ dgrs_found_device( if (ret) goto fail; - SET_MODULE_OWNER(devN); SET_NETDEV_DEV(dev, pdev); ret = register_netdev(devN); diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index ca21a1888ffa..12486e13b85b 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -116,7 +116,6 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) err = -ENOMEM; goto err_out_res; } - SET_MODULE_OWNER (dev); SET_NETDEV_DEV(dev, &pdev->dev); #ifdef MEM_MAPPING diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 738aa5906514..857eb366bb11 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -416,7 +416,6 @@ dm9000_probe(struct platform_device *pdev) return -ENOMEM; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); PRINTK2("dm9000_probe()"); diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 756a6bcb038d..84e14f397d9a 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -71,7 +71,6 @@ static void dummy_setup(struct net_device *dev) dev->change_mtu = NULL; dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; - SET_MODULE_OWNER(dev); random_ether_addr(dev->dev_addr); } diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 10907f158bac..f9aa13e04ada 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2604,7 +2604,6 @@ static int __devinit e100_probe(struct pci_dev *pdev, goto err_out_free_res; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); if (use_io) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 723568d6e44a..7befb706ad55 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -897,7 +897,6 @@ e1000_probe(struct pci_dev *pdev, if (!netdev) goto err_alloc_etherdev; - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index eeb40ccbcb22..885d9467f40d 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4040,7 +4040,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, if (!netdev) goto err_alloc_etherdev; - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index b2b0a96218ca..6390f51ea6fb 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -124,8 +124,6 @@ static int __init do_e2100_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return e21_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 47680237f783..6eb84f14c88d 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -537,8 +537,6 @@ static int __init do_eepro_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - #ifdef PnPWakeup /* XXXX for multiple cards should this only be run once? */ @@ -594,8 +592,6 @@ struct net_device * __init eepro_probe(int unit) if (!dev) return ERR_PTR(-ENODEV); - SET_MODULE_OWNER(dev); - sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 3c54014acece..f8b69ceb2be6 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -635,7 +635,6 @@ static int __devinit speedo_found1(struct pci_dev *pdev, return -1; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (dev->mem_start > 0) diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 7934ea37f944..6c91bfa72bb2 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -341,8 +341,6 @@ static int __init do_express_probe(struct net_device *dev) int dev_irq = dev->irq; int err; - SET_MODULE_OWNER(dev); - dev->if_port = 0xff; /* not set */ #ifdef CONFIG_MCA_LEGACY diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index b8e00391a5e3..62d6c1e5f9d3 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2710,8 +2710,6 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, SET_NETDEV_DEV(dev, port_dev); /* initialize net_device structure */ - SET_MODULE_OWNER(dev); - memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN); dev->open = ehea_open; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index f8446e373bdd..122ffd2f0822 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -352,7 +352,6 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev_err(&pdev->dev, "no memory for eth device\n"); goto err_out_free_res; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); #ifdef USE_IO_OPS diff --git a/drivers/net/eql.c b/drivers/net/eql.c index f1cc66dcbdfd..7266f6dbdd95 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -167,8 +167,6 @@ static void __init eql_setup(struct net_device *dev) { equalizer_t *eql = netdev_priv(dev); - SET_MODULE_OWNER(dev); - init_timer(&eql->timer); eql->timer.data = (unsigned long) eql; eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL; diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 822e5bfd1a71..238fa8aff02d 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -130,8 +130,6 @@ static int __init do_es_probe(struct net_device *dev) int irq = dev->irq; int mem_start = dev->mem_start; - SET_MODULE_OWNER(dev); - if (ioaddr > 0x1ff) /* Check a single specified location. */ return es_probe1(dev, ioaddr); else if (ioaddr > 0) /* Don't probe at all. */ diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 04abf59e5007..0e3b33717cac 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -436,8 +436,6 @@ static int __init do_eth16i_probe(struct net_device *dev) int ioaddr; int base_addr = dev->base_addr; - SET_MODULE_OWNER(dev); - if(eth16i_debug > 4) printk(KERN_DEBUG "Probing started for %s\n", cardname); diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index cb0792c187ba..6a5d0436e89e 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -356,7 +356,6 @@ struct net_device * __init ewrk3_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); err = ewrk3_probe1(dev, dev->base_addr, dev->irq); if (err) diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index ff9f177d7157..e9353072a96d 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -527,7 +527,6 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, err = -ENOMEM; goto err_out_unmap; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* read ethernet id */ diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index 6348fb93ca9c..6f214ab12fff 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -1103,7 +1103,6 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi, err = -ENOMEM; goto err; } - SET_MODULE_OWNER(dev); fep = netdev_priv(dev); fep->dev = dev; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 24c1294614f2..050a8f14eda8 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -5004,7 +5004,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->dev = dev; np->pci_dev = pci_dev; spin_lock_init(&np->lock); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pci_dev->dev); init_timer(&np->oom_kick); diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 2812b524edae..f6789a8db8cd 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -953,7 +953,6 @@ static struct net_device *fs_init_instance(struct device *dev, err = -ENOMEM; goto err; } - SET_MODULE_OWNER(ndev); fep = netdev_priv(ndev); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index bd2de325bbdd..002f8baaab2d 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -254,7 +254,6 @@ static int gfar_probe(struct platform_device *pdev) /* Set the dev->base_addr to the gfar reg region */ dev->base_addr = (unsigned long) (priv->regs); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* Fill in the dev structure */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 15254dc7876a..da12b3db023f 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -613,7 +613,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, if (!dev) goto err_out_iounmap; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); #ifdef TX_CHECKSUM diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 760d04a671f9..0a847326a5e4 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -345,8 +345,6 @@ static void sp_setup(struct net_device *dev) memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); - SET_MODULE_OWNER(dev); - dev->flags = 0; } diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 99a36cc3f8df..8d4f810fa288 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -122,8 +122,6 @@ static int __init do_hpp_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return hpp_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 635b13c2e2aa..1f11126de354 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -86,8 +86,6 @@ static int __init do_hp_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return hp_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 8caa591c5649..406d6525e222 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -404,8 +404,6 @@ struct net_device * __init hp100_probe(int unit) if (!dev) return ERR_PTR(-ENODEV); - SET_MODULE_OWNER(dev); - #ifdef HP100_DEBUG_B hp100_outw(0x4200, TRACE); printk("hp100: %s: probe\n", dev->name); @@ -2843,7 +2841,6 @@ static int __init hp100_eisa_probe (struct device *gendev) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &edev->dev); err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL); @@ -2896,7 +2893,6 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev, goto out0; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); pci_read_config_word(pdev, PCI_COMMAND, &pci_command); @@ -2993,7 +2989,6 @@ static int __init hp100_isa_init(void) return -ENOMEM; } - SET_MODULE_OWNER(dev); err = hp100_isa_probe(dev, hp100_port[i]); if (!err) diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index f970bfbb9db2..31300a9dd965 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -112,7 +112,6 @@ static int __devinit hydra_init(struct zorro_dev *z) dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); for(j = 0; j < ETHER_ADDR_LEN; j++) dev->dev_addr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j)); diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index f752e5fc65ba..354616b0b57b 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1962,7 +1962,6 @@ static int __init emac_probe(struct ocp_device *ocpdev) dev->ndev = ndev; dev->ldev = &ocpdev->dev; dev->def = ocpdev->def; - SET_MODULE_OWNER(ndev); /* Find MAL device we are connected to */ maldev = diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index fe85d6fcba33..67d82fa7659d 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -907,8 +907,6 @@ static int ibmlana_probe(struct net_device *dev) ibmlana_priv *priv; ibmlana_medium medium; - SET_MODULE_OWNER(dev); - /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) return -ENODEV; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 2dff9f2800cd..db908c40dbe1 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1142,8 +1142,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ if(!netdev) return -ENOMEM; - SET_MODULE_OWNER(netdev); - adapter = netdev->priv; dev->dev.driver_data = netdev; @@ -1258,7 +1256,6 @@ static void ibmveth_proc_register_driver(void) { ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net); if (ibmveth_proc_dir) { - SET_MODULE_OWNER(ibmveth_proc_dir); } } @@ -1356,7 +1353,6 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) } else { entry->data = (void *) adapter; entry->proc_fops = &ibmveth_proc_fops; - SET_MODULE_OWNER(entry); } } return; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index b06c6db4383a..448e618b6974 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -152,7 +152,6 @@ static void ifb_setup(struct net_device *dev) dev->change_mtu = NULL; dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; - SET_MODULE_OWNER(dev); random_ether_addr(dev->dev_addr); } diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index c030030e5863..05d2bc15144e 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1273,7 +1273,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_free; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); ip = netdev_priv(dev); diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index f9c889c0dd07..9f584521304a 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -360,10 +360,6 @@ static int ali_ircc_open(int i, chipio_t *info) self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; self->tx_fifo.tail = self->tx_buff.head; - - /* Keep track of module usage */ - SET_MODULE_OWNER(dev); - /* Override the network functions we need to use */ dev->hard_start_xmit = ali_ircc_sir_hard_xmit; dev->open = ali_ircc_net_open; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 3ca47bf6dfec..3e5eca1aa987 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1660,7 +1660,6 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) } #endif - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pci_dev->dev); dev->hard_start_xmit = toshoboe_hard_xmit; dev->open = toshoboe_net_open; diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 3b0fd83fa266..c6355c00fd7a 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1635,7 +1635,6 @@ static int irda_usb_probe(struct usb_interface *intf, if (!net) goto err_out; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); self = net->priv; self->netdev = net; diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 20732458f5ac..c79caa5d3d71 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -175,8 +175,6 @@ irport_open(int i, unsigned int iobase, unsigned int irq) self->tx_buff.data = self->tx_buff.head; self->netdev = dev; - /* Keep track of module usage */ - SET_MODULE_OWNER(dev); /* May be overridden by piggyback drivers */ self->interrupt = irport_interrupt; diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index a4adb74cccd2..648e54b3f00e 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -487,7 +487,6 @@ static int kingsun_probe(struct usb_interface *intf, if(!net) goto err_out1; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); kingsun = netdev_priv(net); kingsun->irlap = NULL; diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index 407afba1a597..8c257a51341a 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -697,7 +697,6 @@ static int ks959_probe(struct usb_interface *intf, if (!net) goto err_out1; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); kingsun = netdev_priv(net); kingsun->netdev = net; diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 12b0e7a15bef..af60f2435a38 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -628,7 +628,6 @@ static int ksdazzle_probe(struct usb_interface *intf, if (!net) goto err_out1; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); kingsun = netdev_priv(net); kingsun->netdev = net; diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index bfc57525bd6a..808939b9f8fb 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -898,8 +898,6 @@ static int mcs_probe(struct usb_interface *intf, IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum); - /* what is it realy for? */ - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &intf->dev); ret = usb_reset_configuration(udev); diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index d96c89751a71..12b9378c587f 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -437,7 +437,6 @@ static int __init nsc_ircc_open(chipio_t *info) self->tx_fifo.tail = self->tx_buff.head; /* Override the network functions we need to use */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = nsc_ircc_hard_xmit_sir; dev->open = nsc_ircc_net_open; dev->stop = nsc_ircc_net_close; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 9d6c8f391b2d..bbe4e094c424 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -913,8 +913,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n dev->drv = drv; dev->netdev = ndev; - SET_MODULE_OWNER(ndev); - /* Override the network functions we need to use */ ndev->hard_start_xmit = sirdev_hard_xmit; ndev->open = sirdev_open; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 36ab98386be0..029fdde2a4d3 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -519,8 +519,6 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u goto err_out1; } - SET_MODULE_OWNER(dev); - dev->hard_start_xmit = smsc_ircc_hard_xmit_sir; #if SMSC_IRCC2_C_NET_TIMEOUT dev->tx_timeout = smsc_ircc_timeout; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 755aa444a4dd..1afaee0fa7e0 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -1034,7 +1034,6 @@ static int stir_probe(struct usb_interface *intf, if(!net) goto err_out1; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); stir = netdev_priv(net); stir->netdev = net; diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index ff5358574d0a..126ec7c8680e 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -429,9 +429,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; self->tx_fifo.tail = self->tx_buff.head; - /* Keep track of module usage */ - SET_MODULE_OWNER(dev); - /* Override the network functions we need to use */ dev->hard_start_xmit = via_ircc_hard_xmit_sir; dev->open = via_ircc_net_open; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 0538ca9ce058..acd082a96a4f 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1584,8 +1584,6 @@ static int vlsi_irda_init(struct net_device *ndev) vlsi_irda_dev_t *idev = ndev->priv; struct pci_dev *pdev = idev->pdev; - SET_MODULE_OWNER(ndev); - ndev->irq = pdev->irq; ndev->base_addr = pci_resource_start(pdev,0); diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 5182e800cc18..9fd2451b0fb2 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -232,9 +232,6 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq, self->rx_buff.data = self->rx_buff.head; self->netdev = dev; - /* Keep track of module usage */ - SET_MODULE_OWNER(dev); - /* Override the network functions we need to use */ dev->hard_start_xmit = w83977af_hard_xmit; dev->open = w83977af_net_open; diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 0343f12d2ffb..54178111eec5 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -133,8 +133,6 @@ static int __init do_netcard_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return netcard_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index e3f27c67fb28..d444de58ba34 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -382,7 +382,6 @@ ixgb_probe(struct pci_dev *pdev, goto err_alloc_etherdev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a08a46224c28..b75f1c6efc42 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2548,7 +2548,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, goto err_alloc_etherdev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c index d3f4235c585d..b02a981c87a8 100644 --- a/drivers/net/ixp2000/enp2611.c +++ b/drivers/net/ixp2000/enp2611.c @@ -210,7 +210,6 @@ static int __init enp2611_init_module(void) return -ENOMEM; } - SET_MODULE_OWNER(nds[i]); nds[i]->get_stats = enp2611_get_stats; pm3386_init_port(i); pm3386_get_mac(i, nds[i]->dev_addr); diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index b71e6633f42d..13847a3e43e5 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -221,7 +221,6 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) lp = netdev_priv(dev); lp->device = &pdev->dev; SET_NETDEV_DEV(dev, &pdev->dev); - SET_MODULE_OWNER(dev); netdev_boot_setup_check(dev); diff --git a/drivers/net/lance.c b/drivers/net/lance.c index a4e5fab12628..7b17212d687e 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -521,7 +521,6 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int /* We can't allocate dev->priv from alloc_etherdev() because it must a ISA DMA-able region. */ - SET_MODULE_OWNER(dev); chipname = chip_table[lance_version].name; printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c index cab57911a80e..7f34c92bcd86 100644 --- a/drivers/net/lguest_net.c +++ b/drivers/net/lguest_net.c @@ -460,8 +460,6 @@ static int lguestnet_probe(struct lguest_device *lgdev) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); - /* Ethernet defaults with some changes */ ether_setup(dev); dev->set_mac_address = NULL; diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 0a08d0c4e7b4..2dd396983213 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -111,8 +111,6 @@ static int __init do_lne390_probe(struct net_device *dev) int mem_start = dev->mem_start; int ret; - SET_MODULE_OWNER(dev); - if (ioaddr > 0x1ff) { /* Check a single specified location. */ if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME)) return -EBUSY; diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 90b0c3ed4bb6..9e700749bb31 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -313,8 +313,6 @@ struct net_device * __init mac8390_probe(int unit) if (unit >= 0) sprintf(dev->name, "eth%d", unit); - SET_MODULE_OWNER(dev); - while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { /* Have we seen it already? */ if (slots & (1<board->slot)) diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 62c1c6262feb..f6f3fdfe41db 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -191,8 +191,6 @@ struct net_device * __init mac89x0_probe(int unit) netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); - if (once_is_enough) goto out; once_is_enough = 1; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 74c3f7a7ae4a..c6707580c305 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1085,7 +1085,6 @@ static int __devinit macb_probe(struct platform_device *pdev) goto err_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* TODO: Actually, we have some interesting features... */ diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 52b9332810c5..de3b002e9a4c 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -143,7 +143,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i rc = -ENOMEM; goto err_release; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); mp = dev->priv; diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 9a343b965975..5d2daa248873 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -210,7 +210,6 @@ static int __devinit mace_probe(struct platform_device *pdev) mp->device = &pdev->dev; SET_NETDEV_DEV(dev, &pdev->dev); - SET_MODULE_OWNER(dev); dev->base_addr = (u32)MACE_BASE; mp->mace = (volatile struct mace *) MACE_BASE; diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index e9ecdbf352ae..a55a8399344c 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -576,7 +576,6 @@ static int __init mac_sonic_probe(struct platform_device *pdev) lp = netdev_priv(dev); lp->device = &pdev->dev; SET_NETDEV_DEV(dev, &pdev->dev); - SET_MODULE_OWNER(dev); /* This will catch fatal stuff like -ENOMEM as well as success */ err = mac_onboard_sonic_probe(dev); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 702eba549161..6317bba9587c 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1425,7 +1425,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) mv643xx_eth_update_pscr(dev, &cmd); mv643xx_set_settings(dev, &cmd); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); err = register_netdev(dev); if (err) diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index e246d00bba6d..837ad0f2b05d 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -79,8 +79,6 @@ struct net_device * __init mvme147lance_probe(int unit) if (unit >= 0) sprintf(dev->name, "eth%d", unit); - SET_MODULE_OWNER(dev); - /* Fill the dev fields */ dev->base_addr = (unsigned long)MVME147_LANCE_BASE; dev->open = &m147lance_open; diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 13444da93273..331b76c49561 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -908,7 +908,6 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) if (version_printed++ == 0) printk(version); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &sdev->ofdev.dev); mp = (struct myri_eth *) dev->priv; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 43cfa4b3e294..5ee4e8795d23 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -837,7 +837,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev = alloc_etherdev(sizeof (struct netdev_private)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); i = pci_request_regions(pdev, DRV_NAME); diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 38fd525f0f13..a0f35361fbec 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -149,8 +149,6 @@ static int __init do_ne_probe(struct net_device *dev) { unsigned int base_addr = dev->base_addr; - SET_MODULE_OWNER(dev); - /* First check any supplied i/o locations. User knows best. */ if (base_addr > 0x1ff) /* Check a single specified location. */ return ne_probe1(dev, base_addr); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index c9f74bf5f491..c81befc3a7ae 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -191,8 +191,6 @@ static int __init do_ne_probe(struct net_device *dev) int orig_irq = dev->irq; #endif - SET_MODULE_OWNER(dev); - /* First check any supplied i/o locations. User knows best. */ if (base_addr > 0x1ff) /* Check a single specified location. */ return ne_probe1(dev, base_addr); diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 089b5bb702fc..d1a4b8d7122a 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -251,8 +251,6 @@ static int __init do_ne2_probe(struct net_device *dev) int i; int adapter_found = 0; - SET_MODULE_OWNER(dev); - /* Do not check any supplied i/o locations. POS registers usually don't fail :) */ diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index f81d9398d605..230a0f1e03fb 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -265,7 +265,6 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, dev_err(&pdev->dev, "cannot allocate ethernet device\n"); goto err_out_free_res; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* Reset card. Who knows what dain-bramaged state it was left in. */ diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 1a6fed76d4cc..b1bf8331e872 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -106,7 +106,6 @@ static int __init ne3210_eisa_probe (struct device *device) return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, device); device->driver_data = dev; ioaddr = edev->base_addr; diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 2b8da0a54998..6fee405d8403 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -390,7 +390,6 @@ static int netx_eth_drv_probe(struct platform_device *pdev) ret = -ENOMEM; goto exit; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); platform_set_drvdata(pdev, ndev); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index dcd66a6b4904..1b165a8c74f3 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -325,7 +325,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_res; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); adapter = netdev->priv; diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 22a3b3dc7d89..cc1d09a21c0c 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -135,8 +135,6 @@ struct net_device * __init ni5010_probe(int unit) PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = ni5010_probe1(dev, io); } else if (io != 0) { /* Don't probe at all. */ diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 5e7999db2096..6b3384a24f07 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -382,8 +382,6 @@ struct net_device * __init ni52_probe(int unit) memend = dev->mem_end; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = ni52_probe1(dev, io); } else if (io > 0) { /* Don't probe at all. */ diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 4ef5fe345191..097685245112 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -550,7 +550,6 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr) } dev->base_addr = ioaddr; - SET_MODULE_OWNER(dev); dev->open = ni65_open; dev->stop = ni65_close; dev->hard_start_xmit = ni65_send_packet; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 6e65d61a3fe0..de495b697294 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1988,7 +1988,6 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ spin_lock_init(&dev->misc_lock); dev->pci_dev = pci_dev; - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pci_dev->dev); INIT_WORK(&dev->tq_refill, queue_refill); diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 48c117038fef..723685ee57aa 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1176,7 +1176,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_disable_device; } - SET_MODULE_OWNER(dev); pci_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 3cdbe118200b..a4b16484a5f7 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -604,7 +604,6 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = dev->priv; diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 503f2685fb73..2136c80c0581 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -197,7 +197,6 @@ static int tc589_probe(struct pcmcia_device *link) link->conf.ConfigIndex = 1; /* The EL3-specific entries in the device structure. */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &el3_start_xmit; dev->set_config = &el3_config; dev->get_stats = &el3_get_stats; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 50dff1b81d34..a9db59d2a2f1 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1728,9 +1728,6 @@ static void axdev_setup(struct net_device *dev) if (ei_debug > 1) printk(version_8390); - SET_MODULE_OWNER(dev); - - ei_local = (struct ei_device *)netdev_priv(dev); spin_lock_init(&ei_local->page_lock); diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 85d5f2ca4bb5..7f29e95a0644 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -259,7 +259,6 @@ static int fmvj18x_probe(struct pcmcia_device *link) link->conf.IntType = INT_MEMORY_AND_IO; /* The FMVJ18x specific entries in the device structure. */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &fjn_start_xmit; dev->set_config = &fjn_config; dev->get_stats = &fjn_get_stats; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 997c2d0c83bb..1bb2ffa294de 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -474,7 +474,6 @@ static int nmclan_probe(struct pcmcia_device *link) lp->tx_free_frames=AM2150_MAX_TX_FRAMES; - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &mace_start_xmit; dev->set_config = &mace_config; dev->get_stats = &mace_get_stats; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 63de89e93b70..49857c1b5067 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -259,7 +259,6 @@ static int pcnet_probe(struct pcmcia_device *link) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - SET_MODULE_OWNER(dev); dev->open = &pcnet_open; dev->stop = &pcnet_close; dev->set_config = &set_config; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index af6728cb49c3..b25f1985d03e 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -336,7 +336,6 @@ static int smc91c92_probe(struct pcmcia_device *link) link->conf.IntType = INT_MEMORY_AND_IO; /* The SMC91c92-specific entries in the device structure. */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &smc_start_xmit; dev->get_stats = &smc_get_stats; dev->set_config = &s9k_config; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 258d6f396186..d5c2d2c8c852 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -580,7 +580,6 @@ xirc2ps_probe(struct pcmcia_device *link) link->irq.Instance = dev; /* Fill in card specific entries */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &do_start_xmit; dev->set_config = &do_config; dev->get_stats = &do_get_stats; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index db87429b956f..724d90bd1feb 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1822,7 +1822,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) spin_lock_init(&lp->lock); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); lp->name = chipname; lp->shared_irq = shared; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 8754cf3356b0..2cfab4b36654 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -1278,7 +1278,6 @@ static void plip_attach (struct parport *port) strcpy(dev->name, name); - SET_MODULE_OWNER(dev); dev->irq = port->irq; dev->base_addr = port->base; if (port->irq == -1) { diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 93c2c39a4a49..f375bbbd6604 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1349,7 +1349,6 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) int status; u64 v1, v2; - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &card->dev->core); spin_lock_init(&card->tx_dma_lock); diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index e39232320e34..309199bb7d12 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -4011,7 +4011,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, goto err_out_free_regions; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); pci_set_drvdata(pdev, ndev); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 3f2306e3f517..b8809a8ef204 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1506,7 +1506,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); tp->dev = dev; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index df6b73872fdb..25a9dd821aa2 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -471,8 +471,6 @@ static int rionet_setup_netdev(struct rio_mport *mport) ndev->features = NETIF_F_LLTX; SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); - SET_MODULE_OWNER(ndev); - spin_lock_init(&rnet->lock); spin_lock_init(&rnet->tx_lock); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 5c2e41fac6d2..41f877d482c7 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -109,7 +109,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev, rrpriv = netdev_priv(dev); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_request_regions(pdev, "rrunner")) { diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index ac6b9b93c025..f77049b34e16 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -7463,7 +7463,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) pci_set_master(pdev); pci_set_drvdata(pdev, dev); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* Private member variable initialized to s2io NIC structure */ diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 1de3eec1a792..aeaa75f549e6 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -189,7 +189,6 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id) */ dev->flags = IFF_POINTOPOINT|IFF_NOARP; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (sb1000_debug > 0) diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 3773b3858bd4..b56721a68a85 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -533,8 +533,6 @@ static void __init shaper_setup(struct net_device *dev) * Set up the shaper. */ - SET_MODULE_OWNER(dev); - shaper_init_priv(dev); dev->open = shaper_open; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 038ccfbafdd1..e810ae942cd6 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1421,7 +1421,6 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) goto err_out_0; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 7c6e4808399a..e1930c3ee75d 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -430,7 +430,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, net_dev = alloc_etherdev(sizeof(struct sis900_private)); if (!net_dev) return -ENOMEM; - SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pci_dev->dev); /* We do a request_region() to register /proc/ioports info. */ diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 7dc9c9ebf5e7..20890e44f99a 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -4877,7 +4877,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, goto out_free_netdev; } - SET_MODULE_OWNER(dev); dev->open = &SkGeOpen; dev->stop = &SkGeClose; dev->hard_start_xmit = &SkGeXmit; diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index a7ef6c8b7721..ca508708229d 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -262,7 +262,6 @@ static int skfp_init_one(struct pci_dev *pdev, dev->do_ioctl = &skfp_ioctl; dev->header_cache_update = NULL; /* not supported */ - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* Initialize board structure with bus-specific info */ diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 0bf46ed4e684..47a144d000d5 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3549,7 +3549,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, return NULL; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &hw->pdev->dev); dev->open = skge_up; dev->stop = skge_down; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 941a60882526..1b9e5f40ddee 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3924,7 +3924,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, return NULL; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &hw->pdev->dev); dev->irq = hw->pdev->irq; dev->open = sky2_up; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 3fd4735006f5..335b7cc80eba 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -639,8 +639,6 @@ static void sl_setup(struct net_device *dev) dev->addr_len = 0; dev->tx_queue_len = 10; - SET_MODULE_OWNER(dev); - /* New-style flags. */ dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST; } diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index ae1ae343beed..3b43fa8fd088 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -264,7 +264,6 @@ static int __init ultramca_probe(struct device *gen_dev) if(!dev) return -ENODEV; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gen_dev); mca_device_set_name(mca_dev, smc_mca_adapter_names[adapter]); mca_device_set_claim(mca_dev, 1); diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index a52b22d7db65..d02bd7bc1bae 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -142,8 +142,6 @@ static int __init do_ultra_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &ultra_poll; #endif diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index 88a30e56c64c..043a5002029c 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -132,8 +132,6 @@ struct net_device * __init ultra32_probe(int unit) netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); - irq = dev->irq; /* EISA spec allows for up to 16 slots, but 8 is typical. */ diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index db43e42bee35..5f03e44ad135 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -2181,7 +2181,6 @@ static int smc911x_drv_probe(struct platform_device *pdev) ret = -ENOMEM; goto release_1; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); ndev->dma = (unsigned char)-1; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 36c1ebadbf20..0a79516d196e 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -744,8 +744,6 @@ struct net_device * __init smc_init(int unit) irq = dev->irq; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = smc_probe(dev, io); } else if (io != 0) { /* Don't probe at all. */ diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 01cc3c742c38..c5837ab5c96b 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -2212,7 +2212,6 @@ static int smc_drv_probe(struct platform_device *pdev) ret = -ENOMEM; goto out_release_io; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); ndev->dma = (unsigned char)-1; diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 6d8f2bb7e0f9..edc736eb3b86 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -2324,7 +2324,6 @@ spider_net_setup_netdev(struct spider_net_card *card) struct sockaddr addr; const u8 *mac; - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &card->pdev->dev); pci_set_drvdata(card->pdev, netdev); diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 3b9336c34206..5785429ca0e2 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -719,7 +719,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, printk(KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); irq = pdev->irq; diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c index e6f90427160c..b65be5d70fec 100644 --- a/drivers/net/stnic.c +++ b/drivers/net/stnic.c @@ -112,7 +112,6 @@ static int __init stnic_probe(void) dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_get_node_addr (stnic_eadr); diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index b77ab6e8fd35..9b2a7f7bb258 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -311,7 +311,6 @@ struct net_device * __init sun3_82586_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); dev->irq = IE_IRQ; dev->base_addr = ioaddr; diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index f1548c033327..c67632dcac49 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -274,7 +274,6 @@ struct net_device * __init sun3lance_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); if (!lance_probe(dev)) goto out; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index b3e0158def4f..4ba3e4857e90 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1087,7 +1087,6 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) dev = alloc_etherdev(sizeof(struct bigmac)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (version_printed++ == 0) printk(KERN_INFO "%s", version); diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index a8f2af8f778a..3c553dcc2b9d 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -485,7 +485,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_request_regions(pdev, DRV_NAME)) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index bf821e96f7b2..869ac44c51f3 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -3023,7 +3023,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, err = -ENOMEM; goto err_disable_device; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); gp = dev->priv; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 8b35f13318ea..170580c13127 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2680,7 +2680,6 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe dev = alloc_etherdev(sizeof(struct happy_meal)); if (!dev) goto err_out; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &sdev->ofdev.dev); if (hme_version_printed++ == 0) @@ -3022,7 +3021,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, err = -ENOMEM; if (!dev) goto err_out; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (hme_version_printed++ == 0) diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index e94b752f9f34..17d66c1185cd 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1457,7 +1457,6 @@ no_link_test: lp->dregs = NULL; lp->dev = dev; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &sdev->ofdev.dev); dev->open = &lance_open; dev->stop = &lance_close; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 1b65ae8a1c7c..b5c2974fd625 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -898,7 +898,6 @@ static int __init qec_ether_init(struct sbus_dev *sdev) /* Stop this QE. */ qe_stop(qe); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &sdev->ofdev.dev); dev->open = qe_open; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index b5e0dff67230..df8237360f58 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -685,7 +685,6 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, dev_err(&pdev->dev, "unable to alloc new ethernet\n"); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); lp = dev->priv; lp->dev = dev; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index cbfa4df09592..369a172a04aa 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11826,7 +11826,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_free_res; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); #if TG3_VLAN_TAG_USED diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 74eb12107e68..c99ce74a7aff 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -556,7 +556,6 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_regions; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); priv = netdev_priv(dev); diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index f4251d35599d..88d03c085d54 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -344,7 +344,6 @@ static int __devinit xl_probe(struct pci_dev *pdev, dev->set_multicast_list=&xl_set_rx_mode; dev->get_stats=&xl_get_stats ; dev->set_mac_address=&xl_set_mac_address ; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); pci_set_drvdata(pdev,dev) ; diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 1bdd3beefbe5..22fad5112406 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -116,8 +116,6 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); - if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) { ret = -EBUSY; goto err_out_trdev; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 49c4270ef5f7..f114fb729f54 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -245,7 +245,6 @@ static int __devinit streamer_init_one(struct pci_dev *pdev, return -ENOMEM; } - SET_MODULE_OWNER(dev); streamer_priv = netdev_priv(dev); #if STREAMER_NETWORK_MONITOR diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 9eafc2e25abc..d0ce2ce675d5 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -168,7 +168,6 @@ static int __devinit madgemc_probe(struct device *device) goto getout; } - SET_MODULE_OWNER(dev); dev->dma = 0; card = kmalloc(sizeof(struct card_info), GFP_KERNEL); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index b57f65b2591a..a149d5e2965c 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -261,7 +261,6 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device dev->set_multicast_list=&olympic_set_rx_mode; dev->get_stats=&olympic_get_stats ; dev->set_mac_address=&olympic_set_mac_address ; - SET_MODULE_OWNER(dev) ; SET_NETDEV_DEV(dev, &pdev->dev); pci_set_drvdata(pdev,dev) ; diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index cb7dbb63c9d9..85d156dea033 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -126,7 +126,6 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (dev->base_addr) /* probe specific location */ err = proteon_probe1(dev, dev->base_addr); else { diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index 33afea31d87b..ecbddc80a2a5 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -143,7 +143,6 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (dev->base_addr) /* probe specific location */ err = sk_isa_probe1(dev, dev->base_addr); else { diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index f83bb5cb0d3d..93da3a36cde8 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -3583,8 +3583,6 @@ struct net_device __init *smctr_probe(int unit) if (!dev) return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); - if (unit >= 0) { sprintf(dev->name, "tr%d", unit); netdev_boot_setup_check(dev); diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index aec75c930c21..ecdd8511a67b 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -115,7 +115,6 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic dev = alloc_trdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) { ret = -EBUSY; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index a1d305b9b12a..fe3225df0d32 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -1607,7 +1607,6 @@ tsi108_init_one(struct platform_device *pdev) */ dev->features = NETIF_F_HIGHDMA; - SET_MODULE_OWNER(dev); spin_lock_init(&data->txlock); spin_lock_init(&data->misclock); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index d380e0b3f05a..bd04e93908ef 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1944,7 +1944,6 @@ static int __devinit de_init_one (struct pci_dev *pdev, if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); dev->open = de_open; dev->stop = de_close; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 09902891a6e6..ba7f47c2dcff 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1261,7 +1261,6 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) } /* The DE4X5-specific entries in the device structure. */ - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gendev); dev->open = &de4x5_open; dev->hard_start_xmit = &de4x5_queue_pkt; diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index dab74feb44bc..e2596e9ab1d7 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -372,7 +372,6 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*db)); if (dev == NULL) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 7040a59fa3c9..66977aaa7176 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1345,7 +1345,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) { printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, " diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index e26ce44561c4..2b7257d97c32 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -268,7 +268,6 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*db)); if (dev == NULL) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 5824f6a35495..396f8455cd32 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -370,7 +370,6 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_request_regions(pdev, DRV_NAME)) diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 4b239dcbef74..de8c92083e92 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -252,7 +252,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ goto tx_buf_fail; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c index fc439f333350..c3f8e303c6c7 100644 --- a/drivers/net/tulip/xircom_tulip_cb.c +++ b/drivers/net/tulip/xircom_tulip_cb.c @@ -547,7 +547,6 @@ static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_devi printk (KERN_ERR DRV_NAME "%d: cannot alloc etherdev, aborting\n", board_idx); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); dev->base_addr = ioaddr; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 691d264fbb6f..8b3ec335385c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -435,7 +435,6 @@ static void tun_setup(struct net_device *dev) tun->owner = -1; tun->group = -1; - SET_MODULE_OWNER(dev); dev->open = tun_net_open; dev->hard_start_xmit = tun_net_xmit; dev->stop = tun_net_close; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 0377b8b64c78..84d99fc77891 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -2332,7 +2332,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) err = -ENOMEM; goto error_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); err = pci_enable_device(pdev); diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 72f617bf2520..8da41229594a 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3957,7 +3957,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma /* Set the dev->base_addr to the gfar reg region */ dev->base_addr = (unsigned long)(ug_info->uf_info.regs); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, device); /* Fill in the dev structure */ diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 524dc5f5e46d..58a53a641754 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -1152,8 +1152,6 @@ err_fw: INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); - SET_MODULE_OWNER(netdev); - usb_set_intfdata(intf, kaweth); #if 0 diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 06838928ef47..432a2f054468 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1321,7 +1321,6 @@ static int pegasus_probe(struct usb_interface *intf, pegasus->intf = intf; pegasus->usb = dev; pegasus->net = net; - SET_MODULE_OWNER(net); net->open = pegasus_open; net->stop = pegasus_close; net->watchdog_timeo = PEGASUS_TX_TIMEOUT; diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 3b3a57ea2676..33cbc306226c 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -917,7 +917,6 @@ static int rtl8150_probe(struct usb_interface *intf, dev->udev = udev; dev->netdev = netdev; - SET_MODULE_OWNER(netdev); netdev->open = rtl8150_open; netdev->stop = rtl8150_close; netdev->do_ioctl = rtl8150_ioctl; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 3034d1aea376..3542ca5fb0fa 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1173,7 +1173,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) init_timer (&dev->delay); mutex_init (&dev->phy_mutex); - SET_MODULE_OWNER (net); dev->net = net; strcpy (net->name, "usb%d"); memcpy (net->dev_addr, node_id, sizeof node_id); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 7a5899059c44..987f5b937e3c 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -702,7 +702,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, printk(KERN_ERR "alloc_etherdev failed\n"); goto err_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); rp = netdev_priv(dev); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index a4729bc385f4..511a74c6e78b 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -712,7 +712,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi /* Chain it all together */ - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); vptr = netdev_priv(dev); diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index 8ead774d14c8..c4c8eab8574f 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -363,7 +363,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) hdlc = dev_to_hdlc(dev); spin_lock_init(&card->lock); - SET_MODULE_OWNER(dev); dev->irq = irq; dev->mem_start = winbase; dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1; diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index a8af28b273d3..46e053106d4d 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -508,7 +508,6 @@ static int cycx_netdevice_init(struct net_device *dev) /* Set transmit buffer queue length */ dev->tx_queue_len = 10; - SET_MODULE_OWNER(dev); /* Initialize socket buffers */ cycx_x25_set_chan_state(dev, WAN_DISCONNECTED); diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 50d2f9108dca..33dc713b5301 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -925,7 +925,6 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr) d->do_ioctl = dscc4_ioctl; d->tx_timeout = dscc4_tx_timeout; d->watchdog_timeo = TX_TIMEOUT; - SET_MODULE_OWNER(d); SET_NETDEV_DEV(d, &pdev->dev); dpriv->dev_id = i; diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index bf5f8d9b5c83..83dbc924fcb5 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -241,8 +241,6 @@ static struct sv11_device *sv11_init(int iobase, int irq) if(!sv->netdev.dev) goto fail2; - SET_MODULE_OWNER(sv->netdev.dev); - dev=&sv->sync; /* diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 699b93406dfb..36e683ccae5e 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -329,7 +329,6 @@ static void lapbeth_setup(struct net_device *dev) dev->hard_header_len = 3; dev->mtu = 1000; dev->addr_len = 0; - SET_MODULE_OWNER(dev); } /* diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index ae132c1c5459..5ea877221f46 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -883,7 +883,6 @@ static int __devinit lmc_init_one(struct pci_dev *pdev, dev->base_addr = pci_resource_start(pdev, 0); dev->irq = pdev->irq; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index cbdf0b748bde..0a566b0daacb 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -459,7 +459,6 @@ static int __init n2_run(unsigned long io, unsigned long irq, port->log_node = 1; spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); dev->irq = irq; dev->mem_start = winbase; dev->mem_end = winbase + USE_WINDOWSIZE - 1; diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index 6353cb5c658d..bf1b01590429 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -468,7 +468,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, port->phy_node = i; spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); dev->irq = card->irq; dev->mem_start = ramphys; dev->mem_end = ramphys + ramsize - 1; diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index 092e51d89036..b595b64e7538 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -415,7 +415,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, port->phy_node = i; spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); dev->irq = card->irq; dev->mem_start = ramphys; dev->mem_end = ramphys + ramsize - 1; diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 8d7e01e8f56f..76db40d200d8 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -216,8 +216,6 @@ static void __init sbni_devsetup(struct net_device *dev) dev->get_stats = &sbni_get_stats; dev->set_multicast_list = &set_multicast_list; dev->do_ioctl = &sbni_ioctl; - - SET_MODULE_OWNER( dev ); } int __init sbni_probe(int unit) diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 792e588d7d61..b39a541b2509 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -1603,7 +1603,6 @@ static void setup_sdla(struct net_device *dev) netdev_boot_setup_check(dev); - SET_MODULE_OWNER(dev); dev->flags = 0; dev->type = 0xFFFF; dev->hard_header_len = 0; diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 3c78f9856380..8e320b76ae0e 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -779,7 +779,6 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, port->dev = dev; hdlc = dev_to_hdlc(dev); spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); dev->tx_queue_len = 50; dev->do_ioctl = wanxl_ioctl; dev->open = wanxl_open; diff --git a/drivers/net/wd.c b/drivers/net/wd.c index a0326818ff2f..cef365881ac2 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -93,8 +93,6 @@ static int __init do_wd_probe(struct net_device *dev) int mem_start = dev->mem_start; int mem_end = dev->mem_end; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) { /* Check a user specified location. */ r = request_region(base_addr, WD_IO_EXTENT, "wd-probe"); if ( r == NULL) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index a152797b951a..80ae75999536 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2870,7 +2870,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, dev->base_addr = port; SET_NETDEV_DEV(dev, dmdev); - SET_MODULE_OWNER(dev); reset_card (dev, 1); msleep(400); diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 7d5b8c2cc614..6f7eb9f59223 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -197,7 +197,6 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) return -EBUSY; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); macio_set_drvdata(mdev, dev); diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index 498e8486d125..3eaaab0ba0cc 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1792,8 +1792,6 @@ struct net_device * __init arlan_probe(int unit) if (!dev) return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); - if (unit >= 0) { sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 51a7db53afa5..47dbdf95ea6f 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1603,7 +1603,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); - SET_MODULE_OWNER(dev); return dev; err_out_res: diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index dfbd01eaaf34..e038d072398d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -4092,7 +4092,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, goto out; } /* initialize the net_device struct */ - SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pdev->dev); net_dev->open = bcm43xx_net_open; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 8990585bd228..12a6887cb9f1 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -6239,8 +6239,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, IPW_DEBUG_INFO("Attempting to register device...\n"); - SET_MODULE_OWNER(dev); - printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2100 Network Connection\n"); diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 61497c467467..afad8bb7e334 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -11625,7 +11625,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_destroy_workqueue; } - SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pdev->dev); mutex_lock(&priv->mutex); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 3feddcc750ed..cb0359df355e 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1157,8 +1157,6 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) priv->infra_open = 0; priv->hotplug_device = dmdev; - SET_MODULE_OWNER(dev); - /* Setup the OS Interface to our functions */ dev->open = libertas_open; dev->hard_start_xmit = libertas_pre_start_xmit; @@ -1340,8 +1338,6 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) mesh_dev->priv = priv; priv->mesh_dev = mesh_dev; - SET_MODULE_OWNER(mesh_dev); - mesh_dev->open = libertas_mesh_open; mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit; mesh_dev->stop = libertas_mesh_close; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 45b00e13ab2b..389fdd313c7e 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -412,7 +412,6 @@ static int netwave_probe(struct pcmcia_device *link) spin_lock_init(&priv->spinlock); /* Netwave specific entries in the device structure */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &netwave_start_xmit; dev->get_stats = &netwave_get_stats; dev->set_multicast_list = &set_multicast_list; diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index d1e502236b2a..8b7f5768a103 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -313,7 +313,6 @@ orinoco_cs_config(struct pcmcia_device *link) /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; dev->irq = link->irq.AssignedIRQ; - SET_MODULE_OWNER(dev); card->node.major = card->node.minor = 0; SET_NETDEV_DEV(dev, &handle_to_dev(link)); diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index eaf3d13b851c..35ec5fcf81a6 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c @@ -193,7 +193,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 97a8b4ff32bd..2547d5dac0d3 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -148,7 +148,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, priv = netdev_priv(dev); card = priv->card; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 31162ac25a92..98fe165337d1 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -232,7 +232,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index b9c54d8fceb9..df493185a4af 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -134,7 +134,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, priv = netdev_priv(dev); card = priv->card; card->bridge_io = bridge_io; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 084795355b74..219dd651dc41 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -808,7 +808,6 @@ islpci_setup(struct pci_dev *pdev) if (!ndev) return ndev; - SET_MODULE_OWNER(ndev); pci_set_drvdata(pdev, ndev); #if defined(SET_NETDEV_DEV) SET_NETDEV_DEV(ndev, &pdev->dev); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 1d9dbf830015..1b0e9707049a 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -356,7 +356,6 @@ static int ray_probe(struct pcmcia_device *p_dev) dev->set_multicast_list = &set_multicast_list; DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n"); - SET_MODULE_OWNER(dev); dev->init = &ray_dev_init; dev->open = &ray_open; dev->stop = &ray_dev_close; diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index af70460f008a..98df9bc7836a 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -782,7 +782,6 @@ spectrum_cs_config(struct pcmcia_device *link) /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; dev->irq = link->irq.AssignedIRQ; - SET_MODULE_OWNER(dev); card->node.major = card->node.minor = 0; /* Reset card and download firmware */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index c49d5a1f94a2..404cd1512312 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -2508,8 +2508,6 @@ static void strip_dev_setup(struct net_device *dev) * Finish setting up the DEVICE info. */ - SET_MODULE_OWNER(dev); - dev->trans_start = 0; dev->last_rx = 0; dev->tx_queue_len = 30; /* Drop after 30 frames queued */ diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 1cf090d60edc..b876bf65935b 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -4177,7 +4177,6 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) /* Init spinlock */ spin_lock_init(&lp->spinlock); - SET_MODULE_OWNER(dev); dev->open = wavelan_open; dev->stop = wavelan_close; dev->hard_start_xmit = wavelan_packet_xmit; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 5740d4d4267c..1cc5180ab1e7 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4577,7 +4577,6 @@ wavelan_probe(struct pcmcia_device *p_dev) lp->dev = dev; /* wavelan NET3 callbacks */ - SET_MODULE_OWNER(dev); dev->open = &wavelan_open; dev->stop = &wavelan_close; dev->hard_start_xmit = &wavelan_packet_xmit; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 732b59f19892..cfde68cff94c 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -2003,8 +2003,6 @@ static int wl3501_config(struct pcmcia_device *link) goto failed; } - SET_MODULE_OWNER(dev); - this = netdev_priv(dev); /* * At this point, the dev_node_t structure(s) should be initialized and diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c index 8bda48de31ef..047cab3d87df 100644 --- a/drivers/net/wireless/zd1211rw/zd_netdev.c +++ b/drivers/net/wireless/zd1211rw/zd_netdev.c @@ -233,7 +233,6 @@ struct net_device *zd_netdev_alloc(struct usb_interface *intf) return NULL; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &intf->dev); dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index b4de126825e4..8eeb068dc4a6 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1176,7 +1176,6 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->features = NETIF_F_IP_CSUM; SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &dev->dev); np->netdev = netdev; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 870c5393c21a..29e96950be65 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -392,7 +392,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, printk (KERN_ERR PFX "cannot allocate ethernet device\n"); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); np = netdev_priv(dev); diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 4032e9f6f9b0..dcd4e1b136b5 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -388,8 +388,6 @@ static int __init znet_probe (void) if (!dev) return -ENOMEM; - SET_MODULE_OWNER (dev); - znet = dev->priv; netinfo = (struct netidblk *)p; diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index d85e2ea0b6af..a45f9952a3f7 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -125,7 +125,6 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) { free_netdev(dev); return -EBUSY; diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 023455a0b34a..399695f7b1af 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -3891,7 +3891,6 @@ claw_init_netdevice(struct net_device * dev) dev->type = ARPHRD_SLIP; dev->tx_queue_len = 1300; dev->flags = IFF_POINTOPOINT | IFF_NOARP; - SET_MODULE_OWNER(dev); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__); #endif diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 92e8a37b5022..449937233732 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -2823,7 +2823,6 @@ ctc_init_netdevice(struct net_device * dev, int alloc_device, dev->type = ARPHRD_SLIP; dev->tx_queue_len = 100; dev->flags = IFF_POINTOPOINT | IFF_NOARP; - SET_MODULE_OWNER(dev); return dev; } diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 08a994fdd1a4..e4b11afbbc9f 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -2145,7 +2145,6 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) card->dev->stop = lcs_stop_device; card->dev->hard_start_xmit = lcs_start_xmit; card->dev->get_stats = lcs_getstats; - SET_MODULE_OWNER(dev); memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH); #ifdef CONFIG_IP_MULTICAST if (!lcs_check_multicast_support(card)) diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 268889474339..4d18d6419ddc 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1904,7 +1904,6 @@ static void netiucv_setup_netdevice(struct net_device *dev) dev->type = ARPHRD_SLIP; dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT; dev->flags = IFF_POINTOPOINT | IFF_NOARP; - SET_MODULE_OWNER(dev); } /** diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index f3e6fbeb2123..8c46978e0afa 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -6649,7 +6649,6 @@ qeth_netdev_init(struct net_device *dev) dev->mtu = card->info.initial_mtu; if (card->info.type != QETH_CARD_TYPE_OSN) SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops); - SET_MODULE_OWNER(dev); return 0; } diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 593e23507b1a..f70055473a00 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2484,7 +2484,6 @@ autoconf_fail: /* network device setup */ dev->net = net; - SET_MODULE_OWNER (net); strcpy (net->name, "usb%d"); dev->cdc = cdc; dev->zlp = zlp; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 625240ce27f1..de387c5400b3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -702,7 +702,6 @@ static inline void *netdev_priv(const struct net_device *dev) return dev->priv; } -#define SET_MODULE_OWNER(dev) do { } while (0) /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. */ diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index a9ced0a6f4c0..4d003e391754 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -350,8 +350,6 @@ static int vlan_dev_init(struct net_device *dev) void vlan_setup(struct net_device *new_dev) { - SET_MODULE_OWNER(new_dev); - ether_setup(new_dev); /* new_dev->ifindex = 0; it will be set when added to diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 99292e8e1d0f..f803e39eee28 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -171,7 +171,6 @@ void br_dev_setup(struct net_device *dev) dev->set_multicast_list = br_dev_set_multicast_list; dev->change_mtu = br_change_mtu; dev->destructor = free_netdev; - SET_MODULE_OWNER(dev); SET_ETHTOOL_OPS(dev, &br_ethtool_ops); dev->stop = br_dev_stop; dev->tx_queue_len = 0; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 3106225c5e50..ffa9f1c9dcbb 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1132,7 +1132,6 @@ static int ipgre_close(struct net_device *dev) static void ipgre_tunnel_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->uninit = ipgre_tunnel_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ipgre_tunnel_xmit; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 652bd86e33a3..5cd5bbe1379a 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -237,7 +237,6 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c return NULL; nt = netdev_priv(dev); - SET_MODULE_OWNER(dev); dev->init = ipip_tunnel_init; nt->parms = *parms; @@ -775,7 +774,6 @@ static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu) static void ipip_tunnel_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->uninit = ipip_tunnel_uninit; dev->hard_start_xmit = ipip_tunnel_xmit; dev->get_stats = ipip_tunnel_get_stats; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 937625e577c1..2320cc27ff9e 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1313,7 +1313,6 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) static void ip6_tnl_dev_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->uninit = ip6_tnl_dev_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ip6_tnl_xmit; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index e79f419b1731..466657a9a8bd 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -714,7 +714,6 @@ static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) static void ipip6_tunnel_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->uninit = ipip6_tunnel_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ipip6_tunnel_xmit; diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index c421521c0a99..340f04a36b02 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -60,8 +60,6 @@ static void irlan_eth_setup(struct net_device *dev) dev->set_multicast_list = irlan_eth_set_multicast_list; dev->destructor = free_netdev; - SET_MODULE_OWNER(dev); - ether_setup(dev); /* diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 0968184ea6be..146f453d7378 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -432,7 +432,6 @@ static __init void teql_master_setup(struct net_device *dev) dev->tx_queue_len = 100; dev->flags = IFF_NOARP; dev->hard_header_len = LL_MAX_HEADER; - SET_MODULE_OWNER(dev); } static LIST_HEAD(master_dev_list); From ff8ac60948ba819b89e9c87083e8050fc2f89999 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Sun, 2 Sep 2007 18:30:18 +0800 Subject: [PATCH 1386/2804] drivers/net/: all drivers/net/ cleanup with ARRAY_SIZE Signed-off-by: Denis Cheng Signed-off-by: Jeff Garzik --- drivers/net/apne.c | 2 +- drivers/net/arm/am79c961a.c | 2 +- drivers/net/atarilance.c | 2 +- drivers/net/atl1/atl1_hw.c | 2 +- drivers/net/bnx2.c | 2 +- drivers/net/cs89x0.c | 6 +++--- drivers/net/e1000/e1000_ethtool.c | 3 +-- drivers/net/fec_8xx/fec_mii.c | 5 ++--- drivers/net/ibm_emac/ibm_emac_debug.c | 8 ++++---- drivers/net/irda/actisys-sir.c | 2 +- drivers/net/ixgb/ixgb_ethtool.c | 3 +-- drivers/net/lp486e.c | 4 +--- drivers/net/mv643xx_eth.c | 3 +-- drivers/net/ne-h8300.c | 2 +- drivers/net/ne.c | 2 +- drivers/net/ne2.c | 2 +- drivers/net/ne2k-pci.c | 2 +- drivers/net/netxen/netxen_nic.h | 2 +- drivers/net/netxen/netxen_nic_hw.c | 2 +- drivers/net/pcmcia/axnet_cs.c | 2 +- drivers/net/pcmcia/pcnet_cs.c | 4 ++-- drivers/net/phy/phy.c | 2 +- drivers/net/skfp/smt.c | 2 +- drivers/net/skfp/srf.c | 4 ++-- drivers/net/tulip/de4x5.c | 6 +++--- drivers/net/wireless/airo.c | 6 +++--- drivers/net/wireless/hostap/hostap_ioctl.c | 6 +++--- drivers/net/wireless/ipw2100.c | 7 +++---- drivers/net/wireless/libertas/main.c | 14 +++++++------- drivers/net/wireless/libertas/wext.c | 4 ++-- drivers/net/wireless/netwave_cs.c | 6 +++--- drivers/net/wireless/prism54/isl_ioctl.c | 7 +++---- drivers/net/wireless/ray_cs.c | 6 +++--- drivers/net/wireless/wavelan.c | 6 +++--- drivers/net/wireless/wavelan_cs.c | 6 +++--- drivers/net/wireless/wl3501_cs.c | 2 +- drivers/net/zorro8390.c | 2 +- 37 files changed, 70 insertions(+), 78 deletions(-) diff --git a/drivers/net/apne.c b/drivers/net/apne.c index b073810f9fd8..b5a974a964c2 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -246,7 +246,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) {0x00, NE_EN0_RSARHI}, {E8390_RREAD+E8390_START, NE_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) { + for (i = 0; i < ARRAY_SIZE(program_seq); i++) { outb(program_seq[i].value, ioaddr + program_seq[i].offset); } diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 2143eeb7a2b0..77964556776e 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -414,7 +414,7 @@ static void am79c961_setmulticastlist (struct net_device *dev) /* * Update the multicast hash table */ - for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++) + for (i = 0; i < ARRAY_SIZE(multi_hash); i++) write_rreg(dev->base_addr, i + LADRL, multi_hash[i]); /* diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 97cca505cf90..17b9dbf7bd68 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -263,7 +263,7 @@ struct lance_addr { (highest byte stripped) */ }; -#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list)) +#define N_LANCE_ADDR ARRAY_SIZE(lance_addr_list) /* Definitions for the Lance */ diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c index ef886bdeac13..9d3bd22e3a82 100644 --- a/drivers/net/atl1/atl1_hw.c +++ b/drivers/net/atl1/atl1_hw.c @@ -603,7 +603,7 @@ static struct atl1_spi_flash_dev flash_table[] = { static void atl1_init_flash_opcode(struct atl1_hw *hw) { - if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0])) + if (hw->flash_vendor >= ARRAY_SIZE(flash_table)) hw->flash_vendor = 0; /* ATMEL */ /* Init OP table */ diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 61debba873ac..f1e7204f78c9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3492,7 +3492,7 @@ bnx2_init_nvram(struct bnx2 *bp) /* Determine the selected interface. */ val = REG_RD(bp, BNX2_NVM_CFG1); - entry_count = sizeof(flash_table) / sizeof(struct flash_spec); + entry_count = ARRAY_SIZE(flash_table); if (val & 0x40000000) { diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 2b4c92193912..4cf82cf5ac10 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -805,7 +805,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) i = cs8900_irq_map[0]; #else /* Translate the IRQ using the IRQ mapping table. */ - if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) + if (i >= ARRAY_SIZE(cs8900_irq_map)) printk("\ncs89x0: invalid ISA interrupt number %d\n", i); else i = cs8900_irq_map[i]; @@ -1246,11 +1246,11 @@ write_irq(struct net_device *dev, int chip_type, int irq) if (chip_type == CS8900) { /* Search the mapping table for the corresponding IRQ pin. */ - for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++) + for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++) if (cs8900_irq_map[i] == irq) break; /* Not found */ - if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) + if (i == ARRAY_SIZE(cs8900_irq_map)) i = 3; writereg(dev, PP_CS8900_ISAINT, i); } else { diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 9ecc3adcf6c1..76d16aaf05b6 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -106,8 +106,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { }; #define E1000_QUEUE_STATS_LEN 0 -#define E1000_GLOBAL_STATS_LEN \ - sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) #define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN) static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c index b3fa0d6a159c..e8e10a02d202 100644 --- a/drivers/net/fec_8xx/fec_mii.c +++ b/drivers/net/fec_8xx/fec_mii.c @@ -308,12 +308,11 @@ int fec_mii_phy_id_detect(struct net_device *dev) return -1; } - for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]); - i++, phy++) + for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) if (phy->id == (phy_hwid >> 4) || phy->id == 0) break; - if (i >= sizeof(phy_info) / sizeof(phy_info[0])) { + if (i >= ARRAY_SIZE(phy_info)) { printk(KERN_ERR DRV_MODULE_NAME ": %s PHY id 0x%08x is not supported!\n", dev->name, phy_hwid); diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c index 92f970d402df..1f70906cfb98 100644 --- a/drivers/net/ibm_emac/ibm_emac_debug.c +++ b/drivers/net/ibm_emac/ibm_emac_debug.c @@ -132,7 +132,7 @@ void emac_dbg_register(int idx, struct ocp_enet_private *dev) { unsigned long flags; - if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) { + if (idx >= ARRAY_SIZE(__emacs)) { printk(KERN_WARNING "invalid index %d when registering EMAC for debugging\n", idx); @@ -148,7 +148,7 @@ void mal_dbg_register(int idx, struct ibm_ocp_mal *mal) { unsigned long flags; - if (idx >= sizeof(__mals) / sizeof(__mals[0])) { + if (idx >= ARRAY_SIZE(__mals)) { printk(KERN_WARNING "invalid index %d when registering MAL for debugging\n", idx); @@ -167,11 +167,11 @@ void emac_dbg_dump_all(void) local_irq_save(flags); - for (i = 0; i < sizeof(__mals) / sizeof(__mals[0]); ++i) + for (i = 0; i < ARRAY_SIZE(__mals); ++i) if (__mals[i]) emac_mal_dump(__mals[i]); - for (i = 0; i < sizeof(__emacs) / sizeof(__emacs[0]); ++i) + for (i = 0; i < ARRAY_SIZE(__emacs); ++i) if (__emacs[i]) emac_mac_dump(i, __emacs[i]); diff --git a/drivers/net/irda/actisys-sir.c b/drivers/net/irda/actisys-sir.c index 9715ab5572e9..ccf6ec548a64 100644 --- a/drivers/net/irda/actisys-sir.c +++ b/drivers/net/irda/actisys-sir.c @@ -67,7 +67,7 @@ static int actisys_reset(struct sir_dev *); /* Note : the 220L doesn't support 38400, but we will fix that below */ static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 }; -#define MAX_SPEEDS (sizeof(baud_rates)/sizeof(baud_rates[0])) +#define MAX_SPEEDS ARRAY_SIZE(baud_rates) static struct dongle_driver act220l = { .owner = THIS_MODULE, diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 0413cd95eda7..21d35bc53906 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -94,8 +94,7 @@ static struct ixgb_stats ixgb_gstrings_stats[] = { {"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)} }; -#define IXGB_STATS_LEN \ - sizeof(ixgb_gstrings_stats) / sizeof(struct ixgb_stats) +#define IXGB_STATS_LEN ARRAY_SIZE(ixgb_gstrings_stats) static int ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 5fc18da1873d..408ae6eb6a8b 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -515,8 +515,6 @@ CLEAR_INT(void) { outb(0, IOADDR+8); } -#define SIZE(x) (sizeof(x)/sizeof((x)[0])) - #if 0 /* selftest or dump */ static void @@ -532,7 +530,7 @@ i596_port_do(struct net_device *dev, int portcmd, char *cmdname) { mdelay(30); /* random, unmotivated */ printk("lp486e i82596 %s result:\n", cmdname); - for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--) + for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--) ; for (i = 0; i < m; i++) { printk(" %04x", lp->dump.dump[i]); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 6317bba9587c..2a808e265a3e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2680,8 +2680,7 @@ static const struct mv643xx_stats mv643xx_gstrings_stats[] = { { "late_collision", MV643XX_STAT(mib_counters.late_collision) }, }; -#define MV643XX_STATS_LEN \ - sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats) +#define MV643XX_STATS_LEN ARRAY_SIZE(mv643xx_gstrings_stats) static void mv643xx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index a0f35361fbec..2b85d1b53344 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -257,7 +257,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) {E8390_RREAD+E8390_START, E8390_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); } diff --git a/drivers/net/ne.c b/drivers/net/ne.c index c81befc3a7ae..27d87985bb63 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -375,7 +375,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) {E8390_RREAD+E8390_START, E8390_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); } diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index d1a4b8d7122a..f73073b1218a 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -430,7 +430,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) {E8390_RREAD+E8390_START, E8390_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, base_addr + program_seq[i].offset); diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 230a0f1e03fb..7ec362b2e3e5 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -307,7 +307,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, {0x00, EN0_RSARHI}, {E8390_RREAD+E8390_START, E8390_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb(program_seq[i].value, ioaddr + program_seq[i].offset); } diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index aaa34939485b..7bbd5d14175f 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1119,7 +1119,7 @@ static const struct netxen_brdinfo netxen_boards[] = { {NETXEN_BRDTYPE_P2_SB31_2G, 2, "Dual Gb"}, }; -#define NUM_SUPPORTED_BOARDS (sizeof(netxen_boards)/sizeof(struct netxen_brdinfo)) +#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(netxen_boards) static inline void get_brd_port_by_type(u32 type, int *ports) { diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index a7b8d7f23259..2c19b8df98fa 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -569,7 +569,7 @@ int netxen_is_flash_supported(struct netxen_adapter *adapter) /* if the flash size less than 4Mb, make huge war cry and die */ for (j = 1; j < 4; j++) { addr = j * NETXEN_NIC_WINDOW_MARGIN; - for (i = 0; i < (sizeof(locs) / sizeof(locs[0])); i++) { + for (i = 0; i < ARRAY_SIZE(locs); i++) { if (netxen_rom_fast_read(adapter, locs[i], &val01) == 0 && netxen_rom_fast_read(adapter, (addr + locs[i]), &val02) == 0) { diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index a9db59d2a2f1..28eea206766d 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -232,7 +232,7 @@ static int get_prom(struct pcmcia_device *link) axnet_reset_8390(dev); mdelay(10); - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); for (i = 0; i < 6; i += 2) { diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 49857c1b5067..8ce251cd3209 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -207,7 +207,7 @@ static hw_info_t hw_info[] = { { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 } }; -#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) +#define NR_INFO ARRAY_SIZE(hw_info) static hw_info_t default_info = { 0, 0, 0, 0, 0 }; static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII }; @@ -374,7 +374,7 @@ static hw_info_t *get_prom(struct pcmcia_device *link) pcnet_reset_8390(dev); mdelay(10); - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); for (i = 0; i < 32; i++) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index cb230f44d6fc..17c1e1555d80 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -204,7 +204,7 @@ static const struct phy_setting settings[] = { }, }; -#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) +#define MAX_NUM_SETTINGS ARRAY_SIZE(settings) /** * phy_find_setting - find a PHY settings array entry that matches speed & duplex diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c index 75afc1f07ba0..ced2c8f76be7 100644 --- a/drivers/net/skfp/smt.c +++ b/drivers/net/skfp/smt.c @@ -1654,7 +1654,7 @@ static const struct smt_pdef { { SMT_P4053, 0, SWAP_SMT_P4053 } , } ; -#define N_SMT_PLEN (sizeof(smt_pdef)/sizeof(smt_pdef[0])) +#define N_SMT_PLEN ARRAY_SIZE(smt_pdef) int smt_check_para(struct s_smc *smc, struct smt_header *sm, const u_short list[]) diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c index 16573aca8b62..6caf713b744c 100644 --- a/drivers/net/skfp/srf.c +++ b/drivers/net/skfp/srf.c @@ -43,7 +43,7 @@ static void clear_reported(struct s_smc *smc); static void smt_send_srf(struct s_smc *smc); static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index); -#define MAX_EVCS (sizeof(smc->evcs)/sizeof(smc->evcs[0])) +#define MAX_EVCS ARRAY_SIZE(smc->evcs) struct evc_init { u_char code ; @@ -67,7 +67,7 @@ static const struct evc_init evc_inits[] = { { SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } , } ; -#define MAX_INIT_EVC (sizeof(evc_inits)/sizeof(evc_inits[0])) +#define MAX_INIT_EVC ARRAY_SIZE(evc_inits) void smt_init_evc(struct s_smc *smc) { diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index ba7f47c2dcff..ee4215ca63f0 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -3945,7 +3945,7 @@ create_packet(struct net_device *dev, char *frame, int len) static int EISA_signature(char *name, struct device *device) { - int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *); + int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures); struct eisa_device *edev; *name = '\0'; @@ -3966,7 +3966,7 @@ EISA_signature(char *name, struct device *device) static int PCI_signature(char *name, struct de4x5_private *lp) { - int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *); + int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures); if (lp->chipset == DC21040) { strcpy(name, "DE434/5"); @@ -5072,7 +5072,7 @@ mii_get_phy(struct net_device *dev) { struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table); + int i, j, k, n, limit=ARRAY_SIZE(phy_info); int id; lp->active = 0; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 80ae75999536..7d717c4d9845 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -7578,9 +7578,9 @@ static const iw_handler airo_private_handler[] = static const struct iw_handler_def airo_handler_def = { - .num_standard = sizeof(airo_handler)/sizeof(iw_handler), - .num_private = sizeof(airo_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(airo_handler), + .num_private = ARRAY_SIZE(airo_private_handler), + .num_private_args = ARRAY_SIZE(airo_private_args), .standard = airo_handler, .private = airo_private_handler, .private_args = airo_private_args, diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index d58ac84f4e9e..730b3541e325 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -3976,9 +3976,9 @@ static const iw_handler prism2_private_handler[] = const struct iw_handler_def hostap_iw_handler_def = { - .num_standard = sizeof(prism2_handler) / sizeof(iw_handler), - .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler), - .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(prism2_handler), + .num_private = ARRAY_SIZE(prism2_private_handler), + .num_private_args = ARRAY_SIZE(prism2_priv), .standard = (iw_handler *) prism2_handler, .private = (iw_handler *) prism2_private_handler, .private_args = (struct iw_priv_args *) prism2_priv, diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 12a6887cb9f1..b3c07b93afce 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -8277,10 +8277,9 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) static struct iw_handler_def ipw2100_wx_handler_def = { .standard = ipw2100_wx_handlers, - .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler), - .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler), - .num_private_args = sizeof(ipw2100_private_args) / - sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(ipw2100_wx_handlers), + .num_private = ARRAY_SIZE(ipw2100_private_handler), + .num_private_args = ARRAY_SIZE(ipw2100_private_args), .private = (iw_handler *) ipw2100_private_handler, .private_args = (struct iw_priv_args *)ipw2100_private_args, .get_wireless_stats = ipw2100_wx_wireless_stats, diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index cb0359df355e..a54171af7b97 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -123,28 +123,28 @@ struct region_cfp_table { static struct region_cfp_table region_cfp_table[] = { {0x10, /*US FCC */ channel_freq_power_US_BG, - sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_US_BG), } , {0x20, /*CANADA IC */ channel_freq_power_US_BG, - sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_US_BG), } , {0x30, /*EU*/ channel_freq_power_EU_BG, - sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_EU_BG), } , {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, - sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_SPN_BG), } , {0x32, /*FRANCE*/ channel_freq_power_FR_BG, - sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_FR_BG), } , {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, - sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_JPN_BG), } , /*Add new region here */ @@ -1422,7 +1422,7 @@ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *c lbs_deb_enter(LBS_DEB_MAIN); - end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table); + end = ARRAY_SIZE(region_cfp_table); for (i = 0; i < end ; i++) { lbs_deb_main("region_cfp_table[i].region=%d\n", diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 3f628223bc6c..f8036efd7294 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -2149,13 +2149,13 @@ static const iw_handler mesh_wlan_handler[] = { (iw_handler) NULL, /* SIOCSIWPMKSA */ }; struct iw_handler_def libertas_handler_def = { - .num_standard = sizeof(wlan_handler) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(wlan_handler), .standard = (iw_handler *) wlan_handler, .get_wireless_stats = wlan_get_wireless_stats, }; struct iw_handler_def mesh_handler_def = { - .num_standard = sizeof(mesh_wlan_handler) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(mesh_wlan_handler), .standard = (iw_handler *) mesh_wlan_handler, .get_wireless_stats = wlan_get_wireless_stats, }; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 389fdd313c7e..d8a59afa7178 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -709,9 +709,9 @@ static const iw_handler netwave_private_handler[] = static const struct iw_handler_def netwave_handler_def = { - .num_standard = sizeof(netwave_handler)/sizeof(iw_handler), - .num_private = sizeof(netwave_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(netwave_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(netwave_handler), + .num_private = ARRAY_SIZE(netwave_private_handler), + .num_private_args = ARRAY_SIZE(netwave_private_args), .standard = (iw_handler *) netwave_handler, .private = (iw_handler *) netwave_private_handler, .private_args = (struct iw_priv_args *) netwave_private_args, diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index f1066614dc31..77ea13bf0c02 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -3239,10 +3239,9 @@ static const iw_handler prism54_private_handler[] = { }; const struct iw_handler_def prism54_handler_def = { - .num_standard = sizeof (prism54_handler) / sizeof (iw_handler), - .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler), - .num_private_args = - sizeof (prism54_private_args) / sizeof (struct iw_priv_args), + .num_standard = ARRAY_SIZE(prism54_handler), + .num_private = ARRAY_SIZE(prism54_private_handler), + .num_private_args = ARRAY_SIZE(prism54_private_args), .standard = (iw_handler *) prism54_handler, .private = (iw_handler *) prism54_private_handler, .private_args = (struct iw_priv_args *) prism54_private_args, diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 1b0e9707049a..429bca8d0b5f 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1567,9 +1567,9 @@ static const struct iw_priv_args ray_private_args[] = { static const struct iw_handler_def ray_handler_def = { - .num_standard = sizeof(ray_handler)/sizeof(iw_handler), - .num_private = sizeof(ray_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(ray_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(ray_handler), + .num_private = ARRAY_SIZE(ray_private_handler), + .num_private_args = ARRAY_SIZE(ray_private_args), .standard = ray_handler, .private = ray_private_handler, .private_args = ray_private_args, diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index b876bf65935b..33ed9fe95f3d 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2400,9 +2400,9 @@ static const struct iw_priv_args wavelan_private_args[] = { static const struct iw_handler_def wavelan_handler_def = { - .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler), - .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(wavelan_handler), + .num_private = ARRAY_SIZE(wavelan_private_handler), + .num_private_args = ARRAY_SIZE(wavelan_private_args), .standard = wavelan_handler, .private = wavelan_private_handler, .private_args = wavelan_private_args, diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 1cc5180ab1e7..9b7f44957869 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -2719,9 +2719,9 @@ static const iw_handler wavelan_private_handler[] = static const struct iw_handler_def wavelan_handler_def = { - .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler), - .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(wavelan_handler), + .num_private = ARRAY_SIZE(wavelan_private_handler), + .num_private_args = ARRAY_SIZE(wavelan_private_args), .standard = wavelan_handler, .private = wavelan_private_handler, .private_args = wavelan_private_args, diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index cfde68cff94c..2690f291e3f7 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1893,7 +1893,7 @@ static const iw_handler wl3501_handler[] = { }; static const struct iw_handler_def wl3501_handler_def = { - .num_standard = sizeof(wl3501_handler) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(wl3501_handler), .standard = (iw_handler *)wl3501_handler, .get_wireless_stats = wl3501_get_wireless_stats, }; diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index a45f9952a3f7..fb215eb6dcf3 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -190,7 +190,7 @@ static int __devinit zorro8390_init(struct net_device *dev, {0x00, NE_EN0_RSARHI}, {E8390_RREAD+E8390_START, NE_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) { + for (i = 0; i < ARRAY_SIZE(program_seq); i++) { z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset); } } From 09f75cd7bf13720738e6a196cc0107ce9a5bd5a0 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 17:41:50 -0700 Subject: [PATCH 1387/2804] [NET] drivers/net: statistics cleanup #1 -- save memory and shrink code We now have struct net_device_stats embedded in struct net_device, and the default ->get_stats() hook does the obvious thing for us. Run through drivers/net/* and remove the driver-local storage of statistics, and driver-local ->get_stats() hook where applicable. This was just the low-hanging fruit in drivers/net; plenty more drivers remain to be updated. [ Resolved conflicts with napi_struct changes and fix sunqe build regression... -DaveM ] Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/3c501.c | 41 ++++----------- drivers/net/3c501.h | 2 - drivers/net/3c507.c | 52 +++++++----------- drivers/net/7990.c | 47 +++++++---------- drivers/net/7990.h | 2 - drivers/net/82596.c | 65 ++++++++++------------- drivers/net/a2065.c | 51 ++++++++---------- drivers/net/at1700.c | 39 +++++--------- drivers/net/atarilance.c | 58 +++++++------------- drivers/net/atp.c | 49 +++++++---------- drivers/net/au1000_eth.c | 23 ++------ drivers/net/au1000_eth.h | 1 - drivers/net/bfin_mac.c | 25 ++------- drivers/net/bfin_mac.h | 2 - drivers/net/bmac.c | 46 +++++++--------- drivers/net/de600.c | 15 ++---- drivers/net/de600.h | 1 - drivers/net/de620.c | 26 +++------ drivers/net/declance.c | 52 ++++++++---------- drivers/net/depca.c | 42 ++++++--------- drivers/net/dgrs.c | 24 ++------- drivers/net/dm9000.c | 29 +++------- drivers/net/e100.c | 23 ++++---- drivers/net/eepro.c | 47 ++++++----------- drivers/net/eexpress.c | 56 ++++++++------------ drivers/net/eql.c | 12 +---- drivers/net/eth16i.c | 49 +++++++---------- drivers/net/ewrk3.c | 37 +++++-------- drivers/net/fec.c | 50 +++++++----------- drivers/net/gianfar.c | 40 ++++++-------- drivers/net/hplance.c | 1 - drivers/net/ibmlana.c | 37 +++++-------- drivers/net/ibmlana.h | 1 - drivers/net/ibmveth.c | 18 ++----- drivers/net/ifb.c | 20 +------ drivers/net/iseries_veth.c | 23 ++------ drivers/net/lib82596.c | 64 ++++++++++------------ drivers/net/lp486e.c | 56 ++++++++------------ drivers/net/mace.c | 59 +++++++++------------ drivers/net/macmace.c | 49 +++++++---------- drivers/net/meth.c | 28 ++++------ drivers/net/mipsnet.c | 26 +++------ drivers/net/mv643xx_eth.c | 25 ++------- drivers/net/myri_sbus.c | 20 +++---- drivers/net/myri_sbus.h | 1 - drivers/net/netx-eth.c | 18 ++----- drivers/net/ni5010.c | 47 +++++------------ drivers/net/pasemi_mac.c | 17 ++---- drivers/net/pasemi_mac.h | 1 - drivers/net/pci-skeleton.c | 74 ++++++++------------------ drivers/net/plip.c | 32 ++++------- drivers/net/qla3xxx.c | 23 +++----- drivers/net/qla3xxx.h | 1 - drivers/net/rionet.c | 20 +++---- drivers/net/rrunner.c | 31 ++++------- drivers/net/rrunner.h | 2 - drivers/net/saa9730.c | 91 +++++++++++++++----------------- drivers/net/saa9730.h | 1 - drivers/net/sb1000.c | 19 ++----- drivers/net/sb1250-mac.c | 39 ++++---------- drivers/net/seeq8005.c | 33 ++++-------- drivers/net/sgiseeq.c | 39 +++++--------- drivers/net/shaper.c | 15 ++---- drivers/net/sis190.c | 19 ++----- drivers/net/sis900.c | 56 +++++++------------- drivers/net/smc911x.c | 77 ++++++++++----------------- drivers/net/smc9194.c | 59 ++++++--------------- drivers/net/smc91x.c | 69 +++++++++--------------- drivers/net/spider_net.c | 49 ++++++----------- drivers/net/spider_net.h | 1 - drivers/net/sun3lance.c | 53 +++++++------------ drivers/net/sunlance.c | 87 ++++++++++++++---------------- drivers/net/sunqe.c | 105 +++++++++++++++++-------------------- drivers/net/sunqe.h | 1 - drivers/net/tun.c | 23 +++----- drivers/net/ucc_geth.c | 27 ++++------ drivers/net/ucc_geth.h | 1 - drivers/net/xen-netfront.c | 27 +++------- drivers/net/yellowfin.c | 63 +++++++++------------- drivers/net/znet.c | 50 +++++++----------- include/linux/if_eql.h | 1 - include/linux/if_shaper.h | 1 - include/linux/if_tun.h | 1 - 83 files changed, 946 insertions(+), 1761 deletions(-) diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 98e0bc4628a2..be71868d1513 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -315,7 +315,6 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) dev->tx_timeout = &el_timeout; dev->watchdog_timeo = HZ; dev->stop = &el1_close; - dev->get_stats = &el1_get_stats; dev->set_multicast_list = &set_multicast_list; dev->ethtool_ops = &netdev_ethtool_ops; return 0; @@ -374,7 +373,7 @@ static void el_timeout(struct net_device *dev) if (el_debug) printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); - lp->stats.tx_errors++; + dev->stats.tx_errors++; outb(TX_NORM, TX_CMD); outb(RX_NORM, RX_CMD); outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */ @@ -441,7 +440,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->tx_pkt_start = gp_start; lp->collisions = 0; - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* * Command mode with status cleared should [in theory] @@ -588,7 +587,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) printk (KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name); outb(AX_SYS, AX_CMD); lp->txing = 0; - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; netif_wake_queue(dev); } else if (txsr & TX_COLLISION) @@ -606,7 +605,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) outb(AX_SYS, AX_CMD); outw(lp->tx_pkt_start, GP_LOW); outb(AX_XMIT, AX_CMD); - lp->stats.collisions++; + dev->stats.collisions++; spin_unlock(&lp->lock); goto out; } @@ -615,7 +614,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) /* * It worked.. we will now fall through and receive */ - lp->stats.tx_packets++; + dev->stats.tx_packets++; if (el_debug > 6) printk(KERN_DEBUG " Tx succeeded %s\n", (txsr & TX_RDY) ? "." : "but tx is busy!"); @@ -640,10 +639,10 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) * Just reading rx_status fixes most errors. */ if (rxsr & RX_MISSED) - lp->stats.rx_missed_errors++; + dev->stats.rx_missed_errors++; else if (rxsr & RX_RUNT) { /* Handled to avoid board lock-up. */ - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (el_debug > 5) printk(KERN_DEBUG " runt.\n"); } @@ -694,7 +693,6 @@ out: static void el_receive(struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int pkt_len; struct sk_buff *skb; @@ -708,7 +706,7 @@ static void el_receive(struct net_device *dev) { if (el_debug) printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len); - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; return; } @@ -727,7 +725,7 @@ static void el_receive(struct net_device *dev) if (skb == NULL) { printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } else @@ -742,8 +740,8 @@ static void el_receive(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes+=pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes+=pkt_len; } return; } @@ -810,23 +808,6 @@ static int el1_close(struct net_device *dev) return 0; } -/** - * el1_get_stats: - * @dev: The card to get the statistics for - * - * In smarter devices this function is needed to pull statistics off the - * board itself. The 3c501 has no hardware statistics. We maintain them all - * so they are by definition always up to date. - * - * Returns the statistics for the card from the card private data - */ - -static struct net_device_stats *el1_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - return &lp->stats; -} - /** * set_multicast_list: * @dev: The device to adjust diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h index c56a2c62f7de..cfec64efff78 100644 --- a/drivers/net/3c501.h +++ b/drivers/net/3c501.h @@ -11,7 +11,6 @@ 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); static int el1_close(struct net_device *dev); -static struct net_device_stats *el1_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static const struct ethtool_ops netdev_ethtool_ops; @@ -29,7 +28,6 @@ static int el_debug = EL_DEBUG; struct net_local { - struct net_device_stats stats; int tx_pkt_start; /* The length of the current Tx packet. */ int collisions; /* Tx collisions this packet */ int loading; /* Spot buffer load collisions */ diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index fac6edff2b8b..3d06271c3a8b 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -118,7 +118,6 @@ enum commands { /* Information that need to be kept for each board. */ struct net_local { - struct net_device_stats stats; int last_restart; ushort rx_head; ushort rx_tail; @@ -289,7 +288,6 @@ static int 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); -static struct net_device_stats *el16_get_stats(struct net_device *dev); static void el16_tx_timeout (struct net_device *dev); static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad); @@ -455,7 +453,6 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) dev->open = el16_open; dev->stop = el16_close; dev->hard_start_xmit = el16_send_packet; - dev->get_stats = el16_get_stats; dev->tx_timeout = el16_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->ethtool_ops = &netdev_ethtool_ops; @@ -489,7 +486,7 @@ static void el16_tx_timeout (struct net_device *dev) readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ - if (lp->last_restart == lp->stats.tx_packets) { + if (lp->last_restart == dev->stats.tx_packets) { if (net_debug > 1) printk ("Resetting board.\n"); /* Completely reset the adaptor. */ @@ -501,7 +498,7 @@ static void el16_tx_timeout (struct net_device *dev) printk ("Kicking board.\n"); writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD); outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */ - lp->last_restart = lp->stats.tx_packets; + lp->last_restart = dev->stats.tx_packets; } dev->trans_start = jiffies; netif_wake_queue (dev); @@ -520,7 +517,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave (&lp->lock, flags); - lp->stats.tx_bytes += length; + dev->stats.tx_bytes += length; /* Disable the 82586's input to the interrupt line. */ outb (0x80, ioaddr + MISC_CTRL); @@ -579,14 +576,14 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) } /* Tx unsuccessful or some interesting status bit set. */ if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) { - lp->stats.tx_errors++; - if (tx_status & 0x0600) lp->stats.tx_carrier_errors++; - if (tx_status & 0x0100) lp->stats.tx_fifo_errors++; - if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++; - if (tx_status & 0x0020) lp->stats.tx_aborted_errors++; - lp->stats.collisions += tx_status & 0xf; + dev->stats.tx_errors++; + if (tx_status & 0x0600) dev->stats.tx_carrier_errors++; + if (tx_status & 0x0100) dev->stats.tx_fifo_errors++; + if (!(tx_status & 0x0040)) dev->stats.tx_heartbeat_errors++; + if (tx_status & 0x0020) dev->stats.tx_aborted_errors++; + dev->stats.collisions += tx_status & 0xf; } - lp->stats.tx_packets++; + dev->stats.tx_packets++; if (net_debug > 5) printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); lp->tx_reap += TX_BUF_SIZE; @@ -665,17 +662,6 @@ static int el16_close(struct net_device *dev) return 0; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *el16_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - /* ToDo: decide if there are any useful statistics from the SCB. */ - - return &lp->stats; -} - /* Initialize the Rx-block list. */ static void init_rx_bufs(struct net_device *dev) { @@ -852,12 +838,12 @@ static void el16_rx(struct net_device *dev) pkt_len); } else if ((frame_status & 0x2000) == 0) { /* Frame Rxed, but with error. */ - lp->stats.rx_errors++; - if (frame_status & 0x0800) lp->stats.rx_crc_errors++; - if (frame_status & 0x0400) lp->stats.rx_frame_errors++; - if (frame_status & 0x0200) lp->stats.rx_fifo_errors++; - if (frame_status & 0x0100) lp->stats.rx_over_errors++; - if (frame_status & 0x0080) lp->stats.rx_length_errors++; + dev->stats.rx_errors++; + if (frame_status & 0x0800) dev->stats.rx_crc_errors++; + if (frame_status & 0x0400) dev->stats.rx_frame_errors++; + if (frame_status & 0x0200) dev->stats.rx_fifo_errors++; + if (frame_status & 0x0100) dev->stats.rx_over_errors++; + if (frame_status & 0x0080) dev->stats.rx_length_errors++; } else { /* Malloc up new buffer. */ struct sk_buff *skb; @@ -866,7 +852,7 @@ static void el16_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -878,8 +864,8 @@ static void el16_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } /* Clear the status word and set End-of-List on the rx frame. */ diff --git a/drivers/net/7990.c b/drivers/net/7990.c index e89ace109a5d..224e0bff1ae0 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -305,18 +305,18 @@ static int lance_rx (struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; continue; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) dev->stats.rx_over_errors++; + if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { len = (rd->mblength & 0xfff) - 4; skb = dev_alloc_skb (len+2); @@ -324,7 +324,7 @@ static int lance_rx (struct net_device *dev) if (skb == 0) { printk ("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask; @@ -339,8 +339,8 @@ static int lance_rx (struct net_device *dev) skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } /* Return the packet to the pool */ @@ -377,12 +377,12 @@ static int lance_tx (struct net_device *dev) if (td->tmd1_bits & LE_T1_ERR) { status = td->misc; - lp->stats.tx_errors++; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk("%s: Carrier Lost, trying %s\n", @@ -400,7 +400,7 @@ static int lance_tx (struct net_device *dev) /* buffer errors and underflows turn off the transmitter */ /* Restart the adapter */ if (status & (LE_T3_BUF|LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); @@ -420,13 +420,13 @@ static int lance_tx (struct net_device *dev) /* One collision before packet was sent. */ if (td->tmd1_bits & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (td->tmd1_bits & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = (j + 1) & lp->tx_ring_mod_mask; @@ -471,9 +471,9 @@ lance_interrupt (int irq, void *dev_id) /* Log misc errors. */ if (csr0 & LE_C0_BABL) - lp->stats.tx_errors++; /* Tx babble. */ + dev->stats.tx_errors++; /* Tx babble. */ if (csr0 & LE_C0_MISS) - lp->stats.rx_errors++; /* Missed a Rx frame. */ + dev->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & LE_C0_MERR) { printk("%s: Bus master arbitration failure, status %4.4x.\n", dev->name, csr0); @@ -589,13 +589,6 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) return 0; } -struct net_device_stats *lance_get_stats (struct net_device *dev) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - /* taken from the depca driver via a2065.c */ static void lance_load_multicast (struct net_device *dev) { diff --git a/drivers/net/7990.h b/drivers/net/7990.h index b1212b5ed92f..0a5837b96421 100644 --- a/drivers/net/7990.h +++ b/drivers/net/7990.h @@ -111,7 +111,6 @@ struct lance_private int lance_log_rx_bufs, lance_log_tx_bufs; int rx_ring_mod_mask, tx_ring_mod_mask; - struct net_device_stats stats; int tpe; /* TPE is selected */ int auto_select; /* cable-selection is by carrier */ unsigned short busmaster_regval; @@ -246,7 +245,6 @@ struct lance_private extern int lance_open(struct net_device *dev); extern int lance_close (struct net_device *dev); extern int lance_start_xmit (struct sk_buff *skb, struct net_device *dev); -extern struct net_device_stats *lance_get_stats (struct net_device *dev); extern void lance_set_multicast (struct net_device *dev); extern void lance_tx_timeout(struct net_device *dev); #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 43dffdca708f..6b03416731de 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -326,7 +326,6 @@ struct i596_private { struct i596_cmd *cmd_head; int cmd_backlog; unsigned long last_cmd; - struct net_device_stats stats; struct i596_rfd rfds[RX_RING_SIZE]; struct i596_rbd rbds[RX_RING_SIZE]; struct tx_cmd tx_cmds[TX_RING_SIZE]; @@ -360,7 +359,6 @@ static int i596_open(struct net_device *dev); static int 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 struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); static void i596_tx_timeout (struct net_device *dev); static void print_eth(unsigned char *buf, char *str); @@ -828,7 +826,7 @@ memory_squeeze: if (skb == NULL) { /* XXX tulip.c can defer packets here!! */ printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { if (!rx_in_place) { @@ -844,28 +842,28 @@ memory_squeeze: #endif netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes+=pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes+=pkt_len; } } else { DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n", dev->name, rfd->stat)); - lp->stats.rx_errors++; + dev->stats.rx_errors++; if ((rfd->stat) & 0x0001) - lp->stats.collisions++; + dev->stats.collisions++; if ((rfd->stat) & 0x0080) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if ((rfd->stat) & 0x0100) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if ((rfd->stat) & 0x0200) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if ((rfd->stat) & 0x0400) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if ((rfd->stat) & 0x0800) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if ((rfd->stat) & 0x1000) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } /* Clear the buffer descriptor count and EOF + F flags */ @@ -916,8 +914,8 @@ static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) dev_kfree_skb(skb); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; ptr->v_next = ptr->b_next = I596_NULL; tx_cmd->cmd.command = 0; /* Mark as free */ @@ -1038,10 +1036,10 @@ static void i596_tx_timeout (struct net_device *dev) DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n", dev->name)); - lp->stats.tx_errors++; + dev->stats.tx_errors++; /* Try to restart the adaptor */ - if (lp->last_restart == lp->stats.tx_packets) { + if (lp->last_restart == dev->stats.tx_packets) { DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n")); /* Shutdown and restart */ i596_reset (dev, lp, ioaddr); @@ -1050,7 +1048,7 @@ static void i596_tx_timeout (struct net_device *dev) DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n")); lp->scb.command = CUC_START | RX_START; CA (dev); - lp->last_restart = lp->stats.tx_packets; + lp->last_restart = dev->stats.tx_packets; } dev->trans_start = jiffies; @@ -1082,7 +1080,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tx_cmd->cmd.command) { printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n", dev->name); - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); } else { @@ -1107,8 +1105,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued")); i596_add_cmd(dev, &tx_cmd->cmd); - lp->stats.tx_packets++; - lp->stats.tx_bytes += length; + dev->stats.tx_packets++; + dev->stats.tx_bytes += length; } netif_start_queue(dev); @@ -1237,7 +1235,6 @@ struct net_device * __init i82596_probe(int unit) dev->open = i596_open; dev->stop = i596_close; dev->hard_start_xmit = i596_start_xmit; - dev->get_stats = i596_get_stats; dev->set_multicast_list = set_multicast_list; dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1343,17 +1340,17 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) if ((ptr->status) & STAT_OK) { DEB(DEB_TXADDR,print_eth(skb->data, "tx-done")); } else { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if ((ptr->status) & 0x0020) - lp->stats.collisions++; + dev->stats.collisions++; if (!((ptr->status) & 0x0040)) - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if ((ptr->status) & 0x0400) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if ((ptr->status) & 0x0800) - lp->stats.collisions++; + dev->stats.collisions++; if ((ptr->status) & 0x1000) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } dev_kfree_skb_irq(skb); @@ -1408,8 +1405,8 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) if (netif_running(dev)) { DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status)); ack_cmd |= RX_START; - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; rebuild_rx_bufs(dev); } } @@ -1492,14 +1489,6 @@ static int i596_close(struct net_device *dev) return 0; } -static struct net_device_stats * - i596_get_stats(struct net_device *dev) -{ - struct i596_private *lp = dev->priv; - - return &lp->stats; -} - /* * Set or clear the multicast filter for this adaptor. */ diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index fa0c6cb3d798..77773ce52eff 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -119,7 +119,6 @@ struct lance_private { int lance_log_rx_bufs, lance_log_tx_bufs; int rx_ring_mod_mask, tx_ring_mod_mask; - struct net_device_stats stats; int tpe; /* cable-selection is TPE */ int auto_select; /* cable-selection by carrier */ unsigned short busmaster_regval; @@ -294,18 +293,18 @@ static int lance_rx (struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; continue; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) dev->stats.rx_over_errors++; + if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { len = (rd->mblength & 0xfff) - 4; skb = dev_alloc_skb (len+2); @@ -313,7 +312,7 @@ static int lance_rx (struct net_device *dev) if (skb == 0) { printk(KERN_WARNING "%s: Memory squeeze, " "deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask; @@ -328,8 +327,8 @@ static int lance_rx (struct net_device *dev) skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } /* Return the packet to the pool */ @@ -364,12 +363,12 @@ static int lance_tx (struct net_device *dev) if (td->tmd1_bits & LE_T1_ERR) { status = td->misc; - lp->stats.tx_errors++; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk(KERN_ERR "%s: Carrier Lost, " @@ -388,7 +387,7 @@ static int lance_tx (struct net_device *dev) /* buffer errors and underflows turn off the transmitter */ /* Restart the adapter */ if (status & (LE_T3_BUF|LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, " "restarting\n", dev->name); @@ -408,13 +407,13 @@ static int lance_tx (struct net_device *dev) /* One collision before packet was sent. */ if (td->tmd1_bits & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (td->tmd1_bits & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = (j + 1) & lp->tx_ring_mod_mask; @@ -459,9 +458,9 @@ static irqreturn_t lance_interrupt (int irq, void *dev_id) /* Log misc errors. */ if (csr0 & LE_C0_BABL) - lp->stats.tx_errors++; /* Tx babble. */ + dev->stats.tx_errors++; /* Tx babble. */ if (csr0 & LE_C0_MISS) - lp->stats.rx_errors++; /* Missed a Rx frame. */ + dev->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & LE_C0_MERR) { printk(KERN_ERR "%s: Bus master arbitration failure, status " "%4.4x.\n", dev->name, csr0); @@ -606,7 +605,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) /* Now, give the packet to the lance */ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask; - lp->stats.tx_bytes += skblen; + dev->stats.tx_bytes += skblen; if (TX_BUFFS_AVAIL <= 0) netif_stop_queue(dev); @@ -621,13 +620,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) return status; } -static struct net_device_stats *lance_get_stats (struct net_device *dev) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - /* taken from the depca driver */ static void lance_load_multicast (struct net_device *dev) { @@ -782,7 +774,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z, dev->hard_start_xmit = &lance_start_xmit; dev->tx_timeout = &lance_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index d20148e69fa1..a124fdb2bce6 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -109,7 +109,6 @@ typedef unsigned char uchar; /* Information that need to be kept for each board. */ struct net_local { - struct net_device_stats stats; spinlock_t lock; unsigned char mc_filter[8]; uint jumpered:1; /* Set iff the board has jumper config. */ @@ -164,7 +163,6 @@ static int 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); -static struct net_device_stats *net_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static void net_tx_timeout (struct net_device *dev); @@ -456,7 +454,6 @@ found: dev->open = net_open; dev->stop = net_close; dev->hard_start_xmit = net_send_packet; - dev->get_stats = net_get_stats; dev->set_multicast_list = &set_rx_mode; dev->tx_timeout = net_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -571,7 +568,7 @@ static void net_tx_timeout (struct net_device *dev) dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE), inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START), inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL)); - lp->stats.tx_errors++; + dev->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ outw(0xffff, ioaddr + MODE24); outw (0xffff, ioaddr + TX_STATUS); @@ -691,10 +688,10 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) printk("%s: 16 Collision occur during Txing.\n", dev->name); /* Cancel sending a packet. */ outb(0x03, ioaddr + COL16CNTL); - lp->stats.collisions++; + dev->stats.collisions++; } if (status & 0x82) { - lp->stats.tx_packets++; + dev->stats.tx_packets++; /* The Tx queue has any packets and is not being transferred a packet from the host, start transmitting. */ @@ -719,7 +716,6 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) static void net_rx(struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 5; @@ -738,11 +734,11 @@ net_rx(struct net_device *dev) #endif if ((status & 0xF0) != 0x20) { /* There was an error. */ - lp->stats.rx_errors++; - if (status & 0x08) lp->stats.rx_length_errors++; - if (status & 0x04) lp->stats.rx_frame_errors++; - if (status & 0x02) lp->stats.rx_crc_errors++; - if (status & 0x01) lp->stats.rx_over_errors++; + dev->stats.rx_errors++; + if (status & 0x08) dev->stats.rx_length_errors++; + if (status & 0x04) dev->stats.rx_frame_errors++; + if (status & 0x02) dev->stats.rx_crc_errors++; + if (status & 0x01) dev->stats.rx_over_errors++; } else { /* Malloc up new buffer. */ struct sk_buff *skb; @@ -753,7 +749,7 @@ net_rx(struct net_device *dev) /* Prime the FIFO and then flush the packet. */ inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT); outb(0x05, ioaddr + RX_CTRL); - lp->stats.rx_errors++; + dev->stats.rx_errors++; break; } skb = dev_alloc_skb(pkt_len+3); @@ -763,7 +759,7 @@ net_rx(struct net_device *dev) /* Prime the FIFO and then flush the packet. */ inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT); outb(0x05, ioaddr + RX_CTRL); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } skb_reserve(skb,2); @@ -772,8 +768,8 @@ net_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } if (--boguscount <= 0) break; @@ -822,17 +818,6 @@ static int net_close(struct net_device *dev) return 0; } -/* Get the current statistics. - This may be called with the card open or closed. - There are no on-chip counters, so this function is trivial. -*/ -static struct net_device_stats * -net_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - return &lp->stats; -} - /* Set the multicast/promiscuous mode for this adaptor. */ diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 17b9dbf7bd68..8bf548e1cb4e 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -224,7 +224,6 @@ struct lance_private { int dirty_tx; /* Ring entries to be freed. */ /* copy function */ void *(*memcpy_f)( void *, const void *, size_t ); - struct net_device_stats stats; /* This must be long for set_bit() */ long tx_full; spinlock_t devlock; @@ -347,7 +346,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); static irqreturn_t lance_interrupt( int irq, void *dev_id ); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); -static struct net_device_stats *lance_get_stats( struct net_device *dev ); static void set_multicast_list( struct net_device *dev ); static int lance_set_mac_address( struct net_device *dev, void *addr ); static void lance_tx_timeout (struct net_device *dev); @@ -631,7 +629,6 @@ static unsigned long __init lance_probe1( struct net_device *dev, dev->open = &lance_open; dev->hard_start_xmit = &lance_start_xmit; dev->stop = &lance_close; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = &lance_set_mac_address; @@ -639,13 +636,6 @@ static unsigned long __init lance_probe1( struct net_device *dev, dev->tx_timeout = lance_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - -#if 0 - dev->start = 0; -#endif - - memset( &lp->stats, 0, sizeof(lp->stats) ); - return( 1 ); } @@ -753,7 +743,7 @@ static void lance_tx_timeout (struct net_device *dev) * little endian mode. */ REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); - lp->stats.tx_errors++; + dev->stats.tx_errors++; #ifndef final_version { int i; DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n", @@ -841,7 +831,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) head->misc = 0; lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; dev_kfree_skb( skb ); lp->cur_tx++; while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { @@ -912,13 +902,13 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) if (status & TMD1_ERR) { /* There was an major error, log it. */ int err_status = MEM->tx_head[entry].misc; - lp->stats.tx_errors++; - if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++; - if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++; - if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (err_status & TMD3_RTRY) dev->stats.tx_aborted_errors++; + if (err_status & TMD3_LCAR) dev->stats.tx_carrier_errors++; + if (err_status & TMD3_LCOL) dev->stats.tx_window_errors++; if (err_status & TMD3_UFLO) { /* Ackk! On FIFO errors the Tx unit is turned off! */ - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; /* Remove this verbosity later! */ DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n", dev->name, csr0 )); @@ -927,8 +917,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) } } else { if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF)) - lp->stats.collisions++; - lp->stats.tx_packets++; + dev->stats.collisions++; + dev->stats.tx_packets++; } /* XXX MSch: free skb?? */ @@ -955,8 +945,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) } /* Log misc errors. */ - if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */ - if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */ + if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & CSR0_MERR) { DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), " "status %04x.\n", dev->name, csr0 )); @@ -997,11 +987,11 @@ static int lance_rx( struct net_device *dev ) buffers it's possible for a jabber packet to use two buffers, with only the last correctly noting the error. */ if (status & RMD1_ENP) /* Only count a general error at the */ - lp->stats.rx_errors++; /* end of a packet.*/ - if (status & RMD1_FRAM) lp->stats.rx_frame_errors++; - if (status & RMD1_OFLO) lp->stats.rx_over_errors++; - if (status & RMD1_CRC) lp->stats.rx_crc_errors++; - if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; /* end of a packet.*/ + if (status & RMD1_FRAM) dev->stats.rx_frame_errors++; + if (status & RMD1_OFLO) dev->stats.rx_over_errors++; + if (status & RMD1_CRC) dev->stats.rx_crc_errors++; + if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++; head->flag &= (RMD1_ENP|RMD1_STP); } else { /* Malloc up new buffer, compatible with net-3. */ @@ -1010,7 +1000,7 @@ static int lance_rx( struct net_device *dev ) if (pkt_len < 60) { printk( "%s: Runt packet!\n", dev->name ); - lp->stats.rx_errors++; + dev->stats.rx_errors++; } else { skb = dev_alloc_skb( pkt_len+2 ); @@ -1023,7 +1013,7 @@ static int lance_rx( struct net_device *dev ) break; if (i > RX_RING_SIZE - 2) { - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; head->flag |= RMD1_OWN_CHIP; lp->cur_rx++; } @@ -1052,8 +1042,8 @@ static int lance_rx( struct net_device *dev ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } } @@ -1090,14 +1080,6 @@ static int lance_close( struct net_device *dev ) } -static struct net_device_stats *lance_get_stats( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; - - return &lp->stats; -} - - /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 6020d5ec38b9..cec2e3672cd0 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -171,7 +171,6 @@ static char mux_8012[] = { 0xff, 0xf7, 0xff, 0xfb, 0xf3, 0xfb, 0xff, 0xf7,}; struct net_local { spinlock_t lock; struct net_device *next_module; - struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ int saved_tx_size; @@ -205,7 +204,6 @@ 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); static int net_close(struct net_device *dev); -static struct net_device_stats *net_get_stats(struct net_device *dev); static void set_rx_mode_8002(struct net_device *dev); static void set_rx_mode_8012(struct net_device *dev); static void tx_timeout(struct net_device *dev); @@ -348,7 +346,6 @@ static int __init atp_probe1(long ioaddr) dev->open = net_open; dev->stop = net_close; dev->hard_start_xmit = atp_send_packet; - dev->get_stats = net_get_stats; dev->set_multicast_list = lp->chip_type == RTL8002 ? &set_rx_mode_8002 : &set_rx_mode_8012; dev->tx_timeout = tx_timeout; @@ -538,18 +535,17 @@ static void write_packet(long ioaddr, int length, unsigned char *packet, int pad static void tx_timeout(struct net_device *dev) { - struct net_local *np = netdev_priv(dev); long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name, inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem" : "IRQ conflict"); - np->stats.tx_errors++; + dev->stats.tx_errors++; /* Try to restart the adapter. */ hardware_init(dev); dev->trans_start = jiffies; netif_wake_queue(dev); - np->stats.tx_errors++; + dev->stats.tx_errors++; } static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) @@ -629,7 +625,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) /* We acknowledged the normal Rx interrupt, so if the interrupt is still outstanding we must have a Rx error. */ if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */ - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; /* Set to no-accept mode long enough to remove a packet. */ write_reg_high(ioaddr, CMR2, CMR2h_OFF); net_rx(dev); @@ -649,9 +645,9 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) and reinitialize the adapter. */ write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK); if (status & (ISR_TxErr<<3)) { - lp->stats.collisions++; + dev->stats.collisions++; if (++lp->re_tx > 15) { - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; hardware_init(dev); break; } @@ -660,7 +656,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit); } else { /* Finish up the transmit. */ - lp->stats.tx_packets++; + dev->stats.tx_packets++; lp->pac_cnt_in_tx_buf--; if ( lp->saved_tx_size) { trigger_send(ioaddr, lp->saved_tx_size); @@ -678,7 +674,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) "%ld jiffies status %02x CMR1 %02x.\n", dev->name, num_tx_since_rx, jiffies - dev->last_rx, status, (read_nibble(ioaddr, CMR1) >> 3) & 15); - lp->stats.rx_missed_errors++; + dev->stats.rx_missed_errors++; hardware_init(dev); num_tx_since_rx = 0; break; @@ -735,13 +731,13 @@ static void atp_timed_checker(unsigned long data) struct net_local *lp = netdev_priv(atp_timed_dev); write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); if (i == 2) - lp->stats.tx_errors++; + dev->stats.tx_errors++; else if (i == 3) - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; else if (i == 4) - lp->stats.collisions++; + dev->stats.collisions++; else - lp->stats.rx_errors++; + dev->stats.rx_errors++; } #endif } @@ -765,14 +761,14 @@ static void net_rx(struct net_device *dev) printk(KERN_DEBUG " rx_count %04x %04x %04x %04x..", rx_head.pad, rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr); if ((rx_head.rx_status & 0x77) != 0x01) { - lp->stats.rx_errors++; - if (rx_head.rx_status & 0x0004) lp->stats.rx_frame_errors++; - else if (rx_head.rx_status & 0x0002) lp->stats.rx_crc_errors++; + dev->stats.rx_errors++; + if (rx_head.rx_status & 0x0004) dev->stats.rx_frame_errors++; + else if (rx_head.rx_status & 0x0002) dev->stats.rx_crc_errors++; if (net_debug > 3) printk(KERN_DEBUG "%s: Unknown ATP Rx error %04x.\n", dev->name, rx_head.rx_status); if (rx_head.rx_status & 0x0020) { - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; write_reg_high(ioaddr, CMR1, CMR1h_TxENABLE); write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); } else if (rx_head.rx_status & 0x0050) @@ -787,7 +783,7 @@ static void net_rx(struct net_device *dev) if (skb == NULL) { printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; goto done; } @@ -796,8 +792,8 @@ static void net_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } done: write_reg(ioaddr, CMR1, CMR1_NextPkt); @@ -849,15 +845,6 @@ net_close(struct net_device *dev) return 0; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats * -net_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - return &lp->stats; -} - /* * Set or clear the multicast filter for this adapter. */ diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index e86b3691765b..b46c5d8a77bd 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -90,7 +90,6 @@ static int au1000_rx(struct net_device *); static irqreturn_t au1000_interrupt(int, void *); static void au1000_tx_timeout(struct net_device *); static void set_rx_mode(struct net_device *); -static struct net_device_stats *au1000_get_stats(struct net_device *); static int au1000_ioctl(struct net_device *, struct ifreq *, int); static int mdio_read(struct net_device *, int, int); static void mdio_write(struct net_device *, int, int, u16); @@ -772,7 +771,6 @@ static struct net_device * au1000_probe(int port_num) dev->open = au1000_open; dev->hard_start_xmit = au1000_tx; dev->stop = au1000_close; - dev->get_stats = au1000_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &au1000_ioctl; SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops); @@ -1038,7 +1036,7 @@ static void __exit au1000_cleanup_module(void) static void update_tx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - struct net_device_stats *ps = &aup->stats; + struct net_device_stats *ps = &dev->stats; if (status & TX_FRAME_ABORTED) { if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) { @@ -1094,7 +1092,7 @@ static void au1000_tx_ack(struct net_device *dev) static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - struct net_device_stats *ps = &aup->stats; + struct net_device_stats *ps = &dev->stats; volatile tx_dma_t *ptxd; u32 buff_stat; db_dest_t *pDB; @@ -1148,7 +1146,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) static inline void update_rx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - struct net_device_stats *ps = &aup->stats; + struct net_device_stats *ps = &dev->stats; ps->rx_packets++; if (status & RX_MCAST_FRAME) @@ -1201,7 +1199,7 @@ static int au1000_rx(struct net_device *dev) printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); - aup->stats.rx_dropped++; + dev->stats.rx_dropped++; continue; } skb_reserve(skb, 2); /* 16 byte IP header align */ @@ -1324,18 +1322,5 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd); } -static struct net_device_stats *au1000_get_stats(struct net_device *dev) -{ - struct au1000_private *aup = (struct au1000_private *) dev->priv; - - if (au1000_debug > 4) - printk("%s: au1000_get_stats: dev=%p\n", dev->name, dev); - - if (netif_device_present(dev)) { - return &aup->stats; - } - return 0; -} - module_init(au1000_init_module); module_exit(au1000_cleanup_module); diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h index 52fe00dd6d24..f3baeaa12854 100644 --- a/drivers/net/au1000_eth.h +++ b/drivers/net/au1000_eth.h @@ -115,6 +115,5 @@ struct au1000_private { u32 vaddr; /* virtual address of rx/tx buffers */ dma_addr_t dma_addr; /* dma address of rx/tx buffers */ - struct net_device_stats stats; spinlock_t lock; /* Serialise access to device */ }; diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index e5bbcbe8de5f..cebe55440e13 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -579,8 +579,8 @@ out: adjust_tx_list(); current_tx_ptr = current_tx_ptr->next; dev->trans_start = jiffies; - lp->stats.tx_packets++; - lp->stats.tx_bytes += (skb->len); + dev->stats.tx_packets++; + dev->stats.tx_bytes += (skb->len); return 0; } @@ -596,7 +596,7 @@ static void bf537mac_rx(struct net_device *dev) if (!new_skb) { printk(KERN_NOTICE DRV_NAME ": rx: low on mem - packet dropped\n"); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; goto out; } /* reserve 2 bytes for RXDWA padding */ @@ -618,8 +618,8 @@ static void bf537mac_rx(struct net_device *dev) #endif netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; current_rx_ptr->status.status_word = 0x00000000; current_rx_ptr = current_rx_ptr->next; @@ -732,20 +732,6 @@ static void bf537mac_timeout(struct net_device *dev) netif_wake_queue(dev); } -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats *bf537mac_query_statistics(struct net_device - *dev) -{ - struct bf537mac_local *lp = netdev_priv(dev); - - pr_debug("%s: %s\n", dev->name, __FUNCTION__); - - return &lp->stats; -} - /* * This routine will, depending on the values passed to it, * either make it accept multicast packets, go into @@ -891,7 +877,6 @@ static int __init bf537mac_probe(struct net_device *dev) dev->stop = bf537mac_close; dev->hard_start_xmit = bf537mac_hard_start_xmit; dev->tx_timeout = bf537mac_timeout; - dev->get_stats = bf537mac_query_statistics; dev->set_multicast_list = bf537mac_set_multicast_list; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = bf537mac_poll; diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h index af87189b85fa..b82724692283 100644 --- a/drivers/net/bfin_mac.h +++ b/drivers/net/bfin_mac.h @@ -104,8 +104,6 @@ struct bf537mac_local { * can find out semi-useless statistics of how well the card is * performing */ - struct net_device_stats stats; - int version; int FlowEnabled; /* record if data flow is active */ diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index ee157f5a5dbc..2761441f6644 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -75,7 +75,6 @@ struct bmac_data { int tx_fill; int tx_empty; unsigned char tx_fullup; - struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; int sleeping; @@ -145,7 +144,6 @@ static unsigned char *bmac_emergency_rxbuf; static int bmac_open(struct net_device *dev); static int bmac_close(struct net_device *dev); static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *bmac_stats(struct net_device *dev); static void bmac_set_multicast(struct net_device *dev); static void bmac_reset_and_enable(struct net_device *dev); static void bmac_start_chip(struct net_device *dev); @@ -668,7 +666,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev) bp->tx_bufs[bp->tx_fill] = skb; bp->tx_fill = i; - bp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; dbdma_continue(td); @@ -707,8 +705,8 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) nb = RX_BUFLEN - residual - 2; if (nb < (ETHERMINPACKET - ETHERCRC)) { skb = NULL; - bp->stats.rx_length_errors++; - bp->stats.rx_errors++; + dev->stats.rx_length_errors++; + dev->stats.rx_errors++; } else { skb = bp->rx_bufs[i]; bp->rx_bufs[i] = NULL; @@ -719,10 +717,10 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - ++bp->stats.rx_packets; - bp->stats.rx_bytes += nb; + ++dev->stats.rx_packets; + dev->stats.rx_bytes += nb; } else { - ++bp->stats.rx_dropped; + ++dev->stats.rx_dropped; } dev->last_rx = jiffies; if ((skb = bp->rx_bufs[i]) == NULL) { @@ -785,7 +783,7 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id) } if (bp->tx_bufs[bp->tx_empty]) { - ++bp->stats.tx_packets; + ++dev->stats.tx_packets; dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]); } bp->tx_bufs[bp->tx_empty] = NULL; @@ -807,13 +805,6 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id) return IRQ_HANDLED; } -static struct net_device_stats *bmac_stats(struct net_device *dev) -{ - struct bmac_data *p = netdev_priv(dev); - - return &p->stats; -} - #ifndef SUNHME_MULTICAST /* Real fast bit-reversal algorithm, 6-bit values */ static int reverse6[64] = { @@ -1080,17 +1071,17 @@ static irqreturn_t bmac_misc_intr(int irq, void *dev_id) } /* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */ /* bmac_txdma_intr_inner(irq, dev_id); */ - /* if (status & FrameReceived) bp->stats.rx_dropped++; */ - if (status & RxErrorMask) bp->stats.rx_errors++; - if (status & RxCRCCntExp) bp->stats.rx_crc_errors++; - if (status & RxLenCntExp) bp->stats.rx_length_errors++; - if (status & RxOverFlow) bp->stats.rx_over_errors++; - if (status & RxAlignCntExp) bp->stats.rx_frame_errors++; + /* if (status & FrameReceived) dev->stats.rx_dropped++; */ + if (status & RxErrorMask) dev->stats.rx_errors++; + if (status & RxCRCCntExp) dev->stats.rx_crc_errors++; + if (status & RxLenCntExp) dev->stats.rx_length_errors++; + if (status & RxOverFlow) dev->stats.rx_over_errors++; + if (status & RxAlignCntExp) dev->stats.rx_frame_errors++; - /* if (status & FrameSent) bp->stats.tx_dropped++; */ - if (status & TxErrorMask) bp->stats.tx_errors++; - if (status & TxUnderrun) bp->stats.tx_fifo_errors++; - if (status & TxNormalCollExp) bp->stats.collisions++; + /* if (status & FrameSent) dev->stats.tx_dropped++; */ + if (status & TxErrorMask) dev->stats.tx_errors++; + if (status & TxUnderrun) dev->stats.tx_fifo_errors++; + if (status & TxNormalCollExp) dev->stats.collisions++; return IRQ_HANDLED; } @@ -1324,7 +1315,6 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i dev->stop = bmac_close; dev->ethtool_ops = &bmac_ethtool_ops; dev->hard_start_xmit = bmac_output; - dev->get_stats = bmac_stats; dev->set_multicast_list = bmac_set_multicast; dev->set_mac_address = bmac_set_address; @@ -1542,7 +1532,7 @@ static void bmac_tx_timeout(unsigned long data) XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n", bp->tx_empty, bp->tx_fill, bp->tx_fullup)); i = bp->tx_empty; - ++bp->stats.tx_errors; + ++dev->stats.tx_errors; if (i != bp->tx_fill) { dev_kfree_skb(bp->tx_bufs[i]); bp->tx_bufs[i] = NULL; diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 5dd0d9c0eac9..421c2ca49711 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -154,11 +154,6 @@ static int de600_close(struct net_device *dev) return 0; } -static struct net_device_stats *get_stats(struct net_device *dev) -{ - return (struct net_device_stats *)(dev->priv); -} - static inline void trigger_interrupt(struct net_device *dev) { de600_put_command(FLIP_IRQ); @@ -308,7 +303,7 @@ static int de600_tx_intr(struct net_device *dev, int irq_status) if (!(irq_status & TX_FAILED16)) { tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES; ++free_tx_pages; - ((struct net_device_stats *)(dev->priv))->tx_packets++; + dev->stats.tx_packets++; netif_wake_queue(dev); } @@ -375,8 +370,8 @@ static void de600_rx_intr(struct net_device *dev) /* update stats */ dev->last_rx = jiffies; - ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */ - ((struct net_device_stats *)(dev->priv))->rx_bytes += size; /* count all received bytes */ + dev->stats.rx_packets++; /* count all receives */ + dev->stats.rx_bytes += size; /* count all received bytes */ /* * If any worth-while packets have been received, netif_rx() @@ -390,7 +385,7 @@ static struct net_device * __init de600_probe(void) struct net_device *dev; int err; - dev = alloc_etherdev(sizeof(struct net_device_stats)); + dev = alloc_etherdev(0); if (!dev) return ERR_PTR(-ENOMEM); @@ -448,8 +443,6 @@ static struct net_device * __init de600_probe(void) printk(":%02X",dev->dev_addr[i]); printk("\n"); - dev->get_stats = get_stats; - dev->open = de600_open; dev->stop = de600_close; dev->hard_start_xmit = &de600_start_xmit; diff --git a/drivers/net/de600.h b/drivers/net/de600.h index 1288e48ba704..e80ecbabcf4e 100644 --- a/drivers/net/de600.h +++ b/drivers/net/de600.h @@ -121,7 +121,6 @@ static u8 de600_read_byte(unsigned char type, struct net_device *dev); /* Put in the device structure. */ static int de600_open(struct net_device *dev); static int de600_close(struct net_device *dev); -static struct net_device_stats *get_stats(struct net_device *dev); static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev); /* Dispatch from interrupts. */ diff --git a/drivers/net/de620.c b/drivers/net/de620.c index a92c207b8839..4b93902906ba 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -216,7 +216,6 @@ MODULE_PARM_DESC(de620_debug, "DE-620 debug level (0-2)"); /* Put in the device structure. */ static int de620_open(struct net_device *); static int de620_close(struct net_device *); -static struct net_device_stats *get_stats(struct net_device *); static void de620_set_multicast_list(struct net_device *); static int de620_start_xmit(struct sk_buff *, struct net_device *); @@ -478,16 +477,6 @@ static int de620_close(struct net_device *dev) return 0; } -/********************************************* - * - * Return current statistics - * - */ -static struct net_device_stats *get_stats(struct net_device *dev) -{ - return (struct net_device_stats *)(dev->priv); -} - /********************************************* * * Set or clear the multicast filter for this adaptor. @@ -579,7 +568,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) if(!(using_txbuf == (TXBF0 | TXBF1))) netif_wake_queue(dev); - ((struct net_device_stats *)(dev->priv))->tx_packets++; + dev->stats.tx_packets++; spin_unlock_irqrestore(&de620_lock, flags); dev_kfree_skb (skb); return 0; @@ -660,7 +649,7 @@ static int de620_rx_intr(struct net_device *dev) /* You win some, you lose some. And sometimes plenty... */ adapter_init(dev); netif_wake_queue(dev); - ((struct net_device_stats *)(dev->priv))->rx_over_errors++; + dev->stats.rx_over_errors++; return 0; } @@ -680,7 +669,7 @@ static int de620_rx_intr(struct net_device *dev) next_rx_page = header_buf.Rx_NextPage; /* at least a try... */ de620_send_command(dev, W_DUMMY); de620_set_register(dev, W_NPRF, next_rx_page); - ((struct net_device_stats *)(dev->priv))->rx_over_errors++; + dev->stats.rx_over_errors++; return 0; } next_rx_page = pagelink; @@ -693,7 +682,7 @@ static int de620_rx_intr(struct net_device *dev) skb = dev_alloc_skb(size+2); if (skb == NULL) { /* Yeah, but no place to put it... */ printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size); - ((struct net_device_stats *)(dev->priv))->rx_dropped++; + dev->stats.rx_dropped++; } else { /* Yep! Go get it! */ skb_reserve(skb,2); /* Align */ @@ -706,8 +695,8 @@ static int de620_rx_intr(struct net_device *dev) netif_rx(skb); /* deliver it "upstairs" */ dev->last_rx = jiffies; /* count all receives */ - ((struct net_device_stats *)(dev->priv))->rx_packets++; - ((struct net_device_stats *)(dev->priv))->rx_bytes += size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += size; } } @@ -819,7 +808,7 @@ struct net_device * __init de620_probe(int unit) int err = -ENOMEM; int i; - dev = alloc_etherdev(sizeof(struct net_device_stats)); + dev = alloc_etherdev(0); if (!dev) goto out; @@ -879,7 +868,6 @@ struct net_device * __init de620_probe(int unit) else printk(" UTP)\n"); - dev->get_stats = get_stats; dev->open = de620_open; dev->stop = de620_close; dev->hard_start_xmit = de620_start_xmit; diff --git a/drivers/net/declance.c b/drivers/net/declance.c index b2577f40124e..7e7ac3330e60 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -258,8 +258,6 @@ struct lance_private { int rx_new, tx_new; int rx_old, tx_old; - struct net_device_stats stats; - unsigned short busmaster_regval; struct timer_list multicast_timer; @@ -583,22 +581,22 @@ static int lance_rx(struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ if (bits & LE_R1_BUF) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (bits & LE_R1_CRC) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (bits & LE_R1_OFL) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (bits & LE_R1_FRA) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (bits & LE_R1_EOP) - lp->stats.rx_errors++; + dev->stats.rx_errors++; } else { len = (*rds_ptr(rd, mblength, lp->type) & 0xfff) - 4; skb = dev_alloc_skb(len + 2); @@ -606,7 +604,7 @@ static int lance_rx(struct net_device *dev) if (skb == 0) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; *rds_ptr(rd, mblength, lp->type) = 0; *rds_ptr(rd, rmd1, lp->type) = ((lp->rx_buf_ptr_lnc[entry] >> 16) & @@ -614,7 +612,7 @@ static int lance_rx(struct net_device *dev) lp->rx_new = (entry + 1) & RX_RING_MOD_MASK; return 0; } - lp->stats.rx_bytes += len; + dev->stats.rx_bytes += len; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ @@ -625,7 +623,7 @@ static int lance_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } /* Return the packet to the pool */ @@ -660,14 +658,14 @@ static void lance_tx(struct net_device *dev) if (*tds_ptr(td, tmd1, lp->type) & LE_T1_ERR) { status = *tds_ptr(td, misc, lp->type); - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (status & LE_T3_RTY) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (status & LE_T3_LCOL) - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; printk("%s: Carrier Lost\n", dev->name); /* Stop the lance */ writereg(&ll->rap, LE_CSR0); @@ -681,7 +679,7 @@ static void lance_tx(struct net_device *dev) * transmitter, restart the adapter. */ if (status & (LE_T3_BUF | LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); @@ -702,13 +700,13 @@ static void lance_tx(struct net_device *dev) /* One collision before packet was sent. */ if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = (j + 1) & TX_RING_MOD_MASK; } @@ -754,10 +752,10 @@ static irqreturn_t lance_interrupt(const int irq, void *dev_id) lance_tx(dev); if (csr0 & LE_C0_BABL) - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (csr0 & LE_C0_MISS) - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (csr0 & LE_C0_MERR) { printk("%s: Memory error, status %04x\n", dev->name, csr0); @@ -912,7 +910,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) len = ETH_ZLEN; } - lp->stats.tx_bytes += len; + dev->stats.tx_bytes += len; entry = lp->tx_new; *lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len); @@ -938,13 +936,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *lance_get_stats(struct net_device *dev) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - static void lance_load_multicast(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); @@ -1244,7 +1235,6 @@ static int __init dec_lance_probe(struct device *bdev, const int type) dev->hard_start_xmit = &lance_start_xmit; dev->tx_timeout = &lance_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; /* lp->ll is the location of the registers for lance card */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 183497020bfc..28fa2bdc8c79 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -485,7 +485,6 @@ struct depca_private { /* Kernel-only (not device) fields */ int rx_new, tx_new; /* The next free ring entry */ int rx_old, tx_old; /* The ring entries to be free()ed. */ - struct net_device_stats stats; spinlock_t lock; struct { /* Private stats counters */ u32 bins[DEPCA_PKT_STAT_SZ]; @@ -522,7 +521,6 @@ 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); static void depca_tx_timeout(struct net_device *dev); -static struct net_device_stats *depca_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); /* @@ -801,7 +799,6 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) dev->open = &depca_open; dev->hard_start_xmit = &depca_start_xmit; dev->stop = &depca_close; - dev->get_stats = &depca_get_stats; dev->set_multicast_list = &set_multicast_list; dev->do_ioctl = &depca_ioctl; dev->tx_timeout = depca_tx_timeout; @@ -1026,15 +1023,15 @@ static int depca_rx(struct net_device *dev) } if (status & R_ENP) { /* Valid frame status */ if (status & R_ERR) { /* There was an error. */ - lp->stats.rx_errors++; /* Update the error stats. */ + dev->stats.rx_errors++; /* Update the error stats. */ if (status & R_FRAM) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & R_OFLO) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (status & R_CRC) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (status & R_BUFF) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } else { short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4; struct sk_buff *skb; @@ -1063,8 +1060,8 @@ static int depca_rx(struct net_device *dev) ** Update stats */ dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) { if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) { lp->pktStats.bins[i]++; @@ -1087,7 +1084,7 @@ static int depca_rx(struct net_device *dev) } } else { printk("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ + dev->stats.rx_dropped++; /* Really, deferred. */ break; } } @@ -1125,24 +1122,24 @@ static int depca_tx(struct net_device *dev) break; } else if (status & T_ERR) { /* An error occurred. */ status = readl(&lp->tx_ring[entry].misc); - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (status & TMD3_RTRY) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (status & TMD3_LCAR) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (status & TMD3_LCOL) - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (status & TMD3_UFLO) - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & (TMD3_BUFF | TMD3_UFLO)) { /* Trigger an immediate send demand. */ outw(CSR0, DEPCA_ADDR); outw(INEA | TDMD, DEPCA_DATA); } } else if (status & (T_MORE | T_ONE)) { - lp->stats.collisions++; + dev->stats.collisions++; } else { - lp->stats.tx_packets++; + dev->stats.tx_packets++; } /* Update all the pointers */ @@ -1234,15 +1231,6 @@ static int InitRestartDepca(struct net_device *dev) return status; } -static struct net_device_stats *depca_get_stats(struct net_device *dev) -{ - struct depca_private *lp = (struct depca_private *) dev->priv; - - /* Null body since there is no framing error counter */ - - return &lp->stats; -} - /* ** Set or clear the multicast filter for this adaptor. */ diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index ddedb76303d5..a9ef79da3dc7 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -193,11 +193,6 @@ static int dgrs_nicmode; */ typedef struct { - /* - * Stuff for generic ethercard I/F - */ - struct net_device_stats stats; - /* * DGRS specific data */ @@ -499,7 +494,7 @@ dgrs_rcv_frame( if ((skb = dev_alloc_skb(len+5)) == NULL) { printk("%s: dev_alloc_skb failed for rcv buffer\n", devN->name); - ++privN->stats.rx_dropped; + ++dev0->stats.rx_dropped; /* discarding the frame */ goto out; } @@ -667,8 +662,8 @@ again: skb->protocol = eth_type_trans(skb, devN); netif_rx(skb); devN->last_rx = jiffies; - ++privN->stats.rx_packets; - privN->stats.rx_bytes += len; + ++devN->stats.rx_packets; + devN->stats.rx_bytes += len; out: cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK; @@ -776,7 +771,7 @@ frame_done: priv0->rfdp->status = I596_RFD_C | I596_RFD_OK; priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next); - ++privN->stats.tx_packets; + ++devN->stats.tx_packets; dev_kfree_skb (skb); return (0); @@ -805,16 +800,6 @@ static int dgrs_close( struct net_device *dev ) return (0); } -/* - * Get statistics - */ -static struct net_device_stats *dgrs_get_stats( struct net_device *dev ) -{ - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - - return (&priv->stats); -} - /* * Set multicast list and/or promiscuous mode */ @@ -1213,7 +1198,6 @@ dgrs_probe1(struct net_device *dev) */ dev->open = &dgrs_open; dev->stop = &dgrs_close; - dev->get_stats = &dgrs_get_stats; dev->hard_start_xmit = &dgrs_start_xmit; dev->set_multicast_list = &dgrs_set_multicast_list; dev->do_ioctl = &dgrs_ioctl; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 857eb366bb11..f691ef61b2d3 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -148,7 +148,6 @@ typedef struct board_info { struct resource *irq_res; struct timer_list timer; - struct net_device_stats stats; unsigned char srom[128]; spinlock_t lock; @@ -166,8 +165,6 @@ static int dm9000_stop(struct net_device *); static void dm9000_timer(unsigned long); static void dm9000_init_dm9000(struct net_device *); -static struct net_device_stats *dm9000_get_stats(struct net_device *); - static irqreturn_t dm9000_interrupt(int, void *); static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg); @@ -558,7 +555,6 @@ dm9000_probe(struct platform_device *pdev) ndev->tx_timeout = &dm9000_timeout; ndev->watchdog_timeo = msecs_to_jiffies(watchdog); ndev->stop = &dm9000_stop; - ndev->get_stats = &dm9000_get_stats; ndev->set_multicast_list = &dm9000_hash_table; #ifdef CONFIG_NET_POLL_CONTROLLER ndev->poll_controller = &dm9000_poll_controller; @@ -713,7 +709,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) writeb(DM9000_MWCMD, db->io_addr); (db->outblk)(db->io_data, skb->data, skb->len); - db->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; db->tx_pkt_cnt++; /* TX control: First packet immediately send, second packet queue */ @@ -790,7 +786,7 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db) if (tx_status & (NSR_TX2END | NSR_TX1END)) { /* One packet sent complete */ db->tx_pkt_cnt--; - db->stats.tx_packets++; + dev->stats.tx_packets++; /* Queue packet check & send */ if (db->tx_pkt_cnt > 0) { @@ -851,17 +847,6 @@ dm9000_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* - * Get statistics from driver. - */ -static struct net_device_stats * -dm9000_get_stats(struct net_device *dev) -{ - board_info_t *db = (board_info_t *) dev->priv; - return &db->stats; -} - - /* * A periodic timer routine * Dynamic media sense, allocated Rx buffer... @@ -939,15 +924,15 @@ dm9000_rx(struct net_device *dev) GoodPacket = false; if (rxhdr.RxStatus & 0x100) { PRINTK1("fifo error\n"); - db->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } if (rxhdr.RxStatus & 0x200) { PRINTK1("crc error\n"); - db->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } if (rxhdr.RxStatus & 0x8000) { PRINTK1("length error\n"); - db->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } } @@ -960,12 +945,12 @@ dm9000_rx(struct net_device *dev) /* Read received packet from RX SRAM */ (db->inblk)(db->io_data, rdptr, RxLen); - db->stats.rx_bytes += RxLen; + dev->stats.rx_bytes += RxLen; /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - db->stats.rx_packets++; + dev->stats.rx_packets++; } else { /* need to dump the packet's data */ diff --git a/drivers/net/e100.c b/drivers/net/e100.c index f9aa13e04ada..99126564f1a0 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -558,7 +558,6 @@ struct nic { enum mac mac; enum phy phy; struct params params; - struct net_device_stats net_stats; struct timer_list watchdog; struct timer_list blink_timer; struct mii_if_info mii; @@ -1483,7 +1482,8 @@ static void e100_set_multicast_list(struct net_device *netdev) static void e100_update_stats(struct nic *nic) { - struct net_device_stats *ns = &nic->net_stats; + struct net_device *dev = nic->netdev; + struct net_device_stats *ns = &dev->stats; struct stats *s = &nic->mem->stats; u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause : (nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames : @@ -1661,6 +1661,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) static int e100_tx_clean(struct nic *nic) { + struct net_device *dev = nic->netdev; struct cb *cb; int tx_cleaned = 0; @@ -1675,8 +1676,8 @@ static int e100_tx_clean(struct nic *nic) cb->status); if(likely(cb->skb != NULL)) { - nic->net_stats.tx_packets++; - nic->net_stats.tx_bytes += cb->skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += cb->skb->len; pci_unmap_single(nic->pdev, le32_to_cpu(cb->u.tcb.tbd.buf_addr), @@ -1807,6 +1808,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) static int e100_rx_indicate(struct nic *nic, struct rx *rx, unsigned int *work_done, unsigned int work_to_do) { + struct net_device *dev = nic->netdev; struct sk_buff *skb = rx->skb; struct rfd *rfd = (struct rfd *)skb->data; u16 rfd_status, actual_size; @@ -1851,8 +1853,8 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, nic->rx_over_length_errors++; dev_kfree_skb_any(skb); } else { - nic->net_stats.rx_packets++; - nic->net_stats.rx_bytes += actual_size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += actual_size; nic->netdev->last_rx = jiffies; netif_receive_skb(skb); if(work_done) @@ -2015,12 +2017,6 @@ static void e100_netpoll(struct net_device *netdev) } #endif -static struct net_device_stats *e100_get_stats(struct net_device *netdev) -{ - struct nic *nic = netdev_priv(netdev); - return &nic->net_stats; -} - static int e100_set_mac_address(struct net_device *netdev, void *p) { struct nic *nic = netdev_priv(netdev); @@ -2457,7 +2453,7 @@ static void e100_get_ethtool_stats(struct net_device *netdev, int i; for(i = 0; i < E100_NET_STATS_LEN; i++) - data[i] = ((unsigned long *)&nic->net_stats)[i]; + data[i] = ((unsigned long *)&netdev->stats)[i]; data[i++] = nic->tx_deferred; data[i++] = nic->tx_single_collisions; @@ -2562,7 +2558,6 @@ static int __devinit e100_probe(struct pci_dev *pdev, netdev->open = e100_open; netdev->stop = e100_close; netdev->hard_start_xmit = e100_xmit_frame; - netdev->get_stats = e100_get_stats; netdev->set_multicast_list = e100_set_multicast_list; netdev->set_mac_address = e100_set_mac_address; netdev->change_mtu = e100_change_mtu; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 6eb84f14c88d..54811f6f766d 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -192,7 +192,6 @@ static unsigned int net_debug = NET_DEBUG; /* Information that need to be kept for each board. */ struct eepro_local { - struct net_device_stats stats; unsigned rx_start; unsigned tx_start; /* start of the transmit chain */ int tx_last; /* pointer to last packet in the transmit chain */ @@ -315,7 +314,6 @@ 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); static int eepro_close(struct net_device *dev); -static struct net_device_stats *eepro_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void eepro_tx_timeout (struct net_device *dev); @@ -514,7 +512,7 @@ buffer (transmit-buffer = 32K - receive-buffer). /* a complete sel reset */ #define eepro_complete_selreset(ioaddr) { \ - lp->stats.tx_errors++;\ + dev->stats.tx_errors++;\ eepro_sel_reset(ioaddr);\ lp->tx_end = \ lp->xmt_lower_limit;\ @@ -856,7 +854,6 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe) dev->open = eepro_open; dev->stop = eepro_close; dev->hard_start_xmit = eepro_send_packet; - dev->get_stats = eepro_get_stats; dev->set_multicast_list = &set_multicast_list; dev->tx_timeout = eepro_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1154,9 +1151,9 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) if (hardware_send_packet(dev, buf, length)) /* we won't wake queue here because we're out of space */ - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; else { - lp->stats.tx_bytes+=skb->len; + dev->stats.tx_bytes+=skb->len; dev->trans_start = jiffies; netif_wake_queue(dev); } @@ -1166,7 +1163,7 @@ static int eepro_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. */ - /* lp->stats.tx_aborted_errors++; */ + /* dev->stats.tx_aborted_errors++; */ if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name); @@ -1273,16 +1270,6 @@ static int eepro_close(struct net_device *dev) return 0; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats * -eepro_get_stats(struct net_device *dev) -{ - struct eepro_local *lp = netdev_priv(dev); - - return &lp->stats; -} - /* Set or clear the multicast filter for this adaptor. */ static void @@ -1575,12 +1562,12 @@ eepro_rx(struct net_device *dev) /* Malloc up new buffer. */ struct sk_buff *skb; - lp->stats.rx_bytes+=rcv_size; + dev->stats.rx_bytes+=rcv_size; rcv_size &= 0x3fff; skb = dev_alloc_skb(rcv_size+5); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; rcv_car = lp->rx_start + RCV_HEADER + rcv_size; lp->rx_start = rcv_next_frame; outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG); @@ -1602,28 +1589,28 @@ eepro_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } else { /* Not sure will ever reach here, I set the 595 to discard bad received frames */ - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (rcv_status & 0x0100) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; else if (rcv_status & 0x0400) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; else if (rcv_status & 0x0800) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n", dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size); } if (rcv_status & 0x1000) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; rcv_car = lp->rx_start + RCV_HEADER + rcv_size; lp->rx_start = rcv_next_frame; @@ -1666,11 +1653,11 @@ eepro_transmit_interrupt(struct net_device *dev) netif_wake_queue (dev); if (xmt_status & TX_OK) - lp->stats.tx_packets++; + dev->stats.tx_packets++; else { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (xmt_status & 0x0400) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; printk(KERN_DEBUG "%s: carrier error\n", dev->name); printk(KERN_DEBUG "%s: XMT status = %#x\n", @@ -1684,11 +1671,11 @@ eepro_transmit_interrupt(struct net_device *dev) } } if (xmt_status & 0x000f) { - lp->stats.collisions += (xmt_status & 0x000f); + dev->stats.collisions += (xmt_status & 0x000f); } if ((xmt_status & 0x0040) == 0x0) { - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; } } } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 6c91bfa72bb2..9c85e50014b4 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -135,7 +135,6 @@ struct net_local { - struct net_device_stats stats; unsigned long last_tx; /* jiffies when last transmit started */ unsigned long init_time; /* jiffies when eexp_hw_init586 called */ unsigned short rx_first; /* first rx buf, same as RX_BUF_START */ @@ -247,7 +246,6 @@ 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 struct net_device_stats *eexp_stats(struct net_device *dev); static int eexp_xmit(struct sk_buff *buf, struct net_device *dev); static irqreturn_t eexp_irq(int irq, void *dev_addr); @@ -532,17 +530,6 @@ static int eexp_close(struct net_device *dev) return 0; } -/* - * Return interface stats - */ - -static struct net_device_stats *eexp_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - return &lp->stats; -} - /* * This gets called when a higher level thinks we are broken. Check that * nothing has become jammed in the CU. @@ -646,7 +633,7 @@ static void eexp_timeout(struct net_device *dev) printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name, (SCB_complete(status)?"lost interrupt": "board on fire")); - lp->stats.tx_errors++; + dev->stats.tx_errors++; lp->last_tx = jiffies; if (!SCB_complete(status)) { scb_command(dev, SCB_CUabort); @@ -694,7 +681,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) { unsigned short *data = (unsigned short *)buf->data; - lp->stats.tx_bytes += length; + dev->stats.tx_bytes += length; eexp_hw_tx_pio(dev,data,length); } @@ -843,7 +830,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info) outw(rbd+8, ioaddr+READ_PTR); printk("[%04x]\n", inw(ioaddr+DATAPORT)); #endif - lp->stats.rx_errors++; + dev->stats.rx_errors++; #if 1 eexp_hw_rxinit(dev); #else @@ -952,17 +939,17 @@ static void eexp_hw_rx_pio(struct net_device *dev) } else if (!FD_OK(status)) { - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (FD_CRC(status)) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (FD_Align(status)) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (FD_Resrc(status)) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (FD_DMA(status)) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (FD_Short(status)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else { @@ -972,7 +959,7 @@ static void eexp_hw_rx_pio(struct net_device *dev) if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } skb_reserve(skb, 2); @@ -981,8 +968,8 @@ static void eexp_hw_rx_pio(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } outw(rx_block, ioaddr+WRITE_PTR); outw(0, ioaddr+DATAPORT); @@ -1053,7 +1040,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf, outw(0xFFFF, ioaddr+SIGNAL_CA); } - lp->stats.tx_packets++; + dev->stats.tx_packets++; lp->last_tx = jiffies; } @@ -1180,7 +1167,6 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr) dev->open = eexp_open; dev->stop = eexp_close; dev->hard_start_xmit = eexp_xmit; - dev->get_stats = eexp_stats; dev->set_multicast_list = &eexp_set_multicast; dev->tx_timeout = eexp_timeout; dev->watchdog_timeo = 2*HZ; @@ -1263,35 +1249,35 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev) else { lp->last_tx_restart = 0; - lp->stats.collisions += Stat_NoColl(status); + dev->stats.collisions += Stat_NoColl(status); if (!Stat_OK(status)) { char *whatsup = NULL; - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (Stat_Abort(status)) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (Stat_TNoCar(status)) { whatsup = "aborted, no carrier"; - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; } if (Stat_TNoCTS(status)) { whatsup = "aborted, lost CTS"; - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; } if (Stat_TNoDMA(status)) { whatsup = "FIFO underran"; - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } if (Stat_TXColl(status)) { whatsup = "aborted, too many collisions"; - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } if (whatsup) printk(KERN_INFO "%s: transmit %s\n", dev->name, whatsup); } else - lp->stats.tx_packets++; + dev->stats.tx_packets++; } if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) lp->tx_reap = tx_block = TX_BUF_START; diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 7266f6dbdd95..18f1364d3d5b 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -128,7 +128,6 @@ 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 struct net_device_stats *eql_get_stats(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) @@ -180,7 +179,6 @@ static void __init eql_setup(struct net_device *dev) dev->stop = eql_close; dev->do_ioctl = eql_ioctl; dev->hard_start_xmit = eql_slave_xmit; - dev->get_stats = eql_get_stats; /* * Now we undo some of the things that eth_setup does @@ -337,9 +335,9 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) skb->priority = 1; slave->bytes_queued += skb->len; dev_queue_xmit(skb); - eql->stats.tx_packets++; + dev->stats.tx_packets++; } else { - eql->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); } @@ -348,12 +346,6 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats * eql_get_stats(struct net_device *dev) -{ - equalizer_t *eql = netdev_priv(dev); - return &eql->stats; -} - /* * Private ioctl functions */ diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 0e3b33717cac..243fc6b354b5 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -380,7 +380,6 @@ static unsigned int eth16i_debug = ETH16I_DEBUG; /* Information for each board */ struct eth16i_local { - struct net_device_stats stats; unsigned char tx_started; unsigned char tx_buf_busy; unsigned short tx_queue; /* Number of packets in transmit buffer */ @@ -426,8 +425,6 @@ static int eth16i_set_irq(struct net_device *dev); static ushort eth16i_parse_mediatype(const char* s); #endif -static struct net_device_stats *eth16i_get_stats(struct net_device *dev); - static char cardname[] __initdata = "ICL EtherTeam 16i/32"; static int __init do_eth16i_probe(struct net_device *dev) @@ -557,7 +554,6 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr) dev->open = eth16i_open; dev->stop = eth16i_close; dev->hard_start_xmit = eth16i_tx; - dev->get_stats = eth16i_get_stats; dev->set_multicast_list = eth16i_multicast; dev->tx_timeout = eth16i_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1045,7 +1041,7 @@ static void eth16i_timeout(struct net_device *dev) printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len); printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started); } - lp->stats.tx_errors++; + dev->stats.tx_errors++; eth16i_reset(dev); dev->trans_start = jiffies; outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); @@ -1130,7 +1126,6 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) static void eth16i_rx(struct net_device *dev) { - struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = MAX_RX_LOOP; @@ -1149,16 +1144,16 @@ static void eth16i_rx(struct net_device *dev) inb(ioaddr + RECEIVE_MODE_REG), status); if( !(status & PKT_GOOD) ) { - lp->stats.rx_errors++; + dev->stats.rx_errors++; if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) { - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; eth16i_reset(dev); return; } else { eth16i_skip_packet(dev); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } } else { /* Ok so now we should have a good packet */ @@ -1169,7 +1164,7 @@ static void eth16i_rx(struct net_device *dev) printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n", dev->name, pkt_len); eth16i_skip_packet(dev); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -1212,8 +1207,8 @@ static void eth16i_rx(struct net_device *dev) } netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } /* else */ @@ -1250,32 +1245,32 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id) if( status & 0x7f00 ) { - lp->stats.rx_errors++; + dev->stats.rx_errors++; if(status & (BUS_RD_ERR << 8) ) printk(KERN_WARNING "%s: Bus read error.\n",dev->name); - if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++; - if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++; - if(status & (CRC_ERR << 8) ) lp->stats.rx_crc_errors++; - if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++; + if(status & (SHORT_PKT_ERR << 8) ) dev->stats.rx_length_errors++; + if(status & (ALIGN_ERR << 8) ) dev->stats.rx_frame_errors++; + if(status & (CRC_ERR << 8) ) dev->stats.rx_crc_errors++; + if(status & (RX_BUF_OVERFLOW << 8) ) dev->stats.rx_over_errors++; } if( status & 0x001a) { - lp->stats.tx_errors++; + dev->stats.tx_errors++; - if(status & CR_LOST) lp->stats.tx_carrier_errors++; - if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++; + if(status & CR_LOST) dev->stats.tx_carrier_errors++; + if(status & TX_JABBER_ERR) dev->stats.tx_window_errors++; #if 0 if(status & COLLISION) { - lp->stats.collisions += + dev->stats.collisions += ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4); } #endif if(status & COLLISIONS_16) { if(lp->col_16 < MAX_COL_16) { lp->col_16++; - lp->stats.collisions++; + dev->stats.collisions++; /* Resume transmitting, skip failed packet */ outb(0x02, ioaddr + COL_16_REG); } @@ -1288,8 +1283,8 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id) if( status & 0x00ff ) { /* Let's check the transmit status reg */ if(status & TX_DONE) { /* The transmit has been done */ - lp->stats.tx_packets = lp->tx_buffered_packets; - lp->stats.tx_bytes += lp->tx_buffered_bytes; + dev->stats.tx_packets = lp->tx_buffered_packets; + dev->stats.tx_bytes += lp->tx_buffered_bytes; lp->col_16 = 0; if(lp->tx_queue) { /* Is there still packets ? */ @@ -1369,12 +1364,6 @@ static void eth16i_multicast(struct net_device *dev) } } -static struct net_device_stats *eth16i_get_stats(struct net_device *dev) -{ - struct eth16i_local *lp = netdev_priv(dev); - return &lp->stats; -} - static void eth16i_select_regbank(unsigned char banknbr, int ioaddr) { unsigned char data; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 6a5d0436e89e..142aa225d89e 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -275,7 +275,6 @@ struct ewrk3_private { u_long shmem_base; /* Shared memory start address */ void __iomem *shmem; u_long shmem_length; /* Shared memory window length */ - struct net_device_stats stats; /* Public stats */ struct ewrk3_stats pktStats; /* Private stats counters */ u_char irq_mask; /* Adapter IRQ mask bits */ u_char mPage; /* Maximum 2kB Page number */ @@ -302,7 +301,6 @@ static int ewrk3_open(struct net_device *dev); static int 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 struct net_device_stats *ewrk3_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops ethtool_ops_203; @@ -611,7 +609,6 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) dev->open = ewrk3_open; dev->hard_start_xmit = ewrk3_queue_pkt; dev->stop = ewrk3_close; - dev->get_stats = ewrk3_get_stats; dev->set_multicast_list = set_multicast_list; dev->do_ioctl = ewrk3_ioctl; if (lp->adapter_name[4] == '3') @@ -863,7 +860,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) ENABLE_IRQs; spin_unlock_irq (&lp->hw_lock); - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb (skb); @@ -980,13 +977,13 @@ static int ewrk3_rx(struct net_device *dev) } if (!(rx_status & R_ROK)) { /* There was an error. */ - lp->stats.rx_errors++; /* Update the error stats. */ + dev->stats.rx_errors++; /* Update the error stats. */ if (rx_status & R_DBE) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rx_status & R_CRC) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rx_status & R_PLL) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } else { struct sk_buff *skb; @@ -1037,11 +1034,11 @@ static int ewrk3_rx(struct net_device *dev) ** Update stats */ dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } else { printk("%s: Insufficient memory; nuking packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ + dev->stats.rx_dropped++; /* Really, deferred. */ break; } } @@ -1071,11 +1068,11 @@ static int ewrk3_tx(struct net_device *dev) while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */ if (tx_status & T_VSTS) { /* The status is valid */ if (tx_status & T_TXE) { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & T_NCL) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tx_status & T_LCL) - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (tx_status & T_CTU) { if ((tx_status & T_COLL) ^ T_XUR) { lp->pktStats.tx_underruns++; @@ -1084,13 +1081,13 @@ static int ewrk3_tx(struct net_device *dev) } } else if (tx_status & T_COLL) { if ((tx_status & T_COLL) ^ T_XCOLL) { - lp->stats.collisions++; + dev->stats.collisions++; } else { lp->pktStats.excessive_collisions++; } } } else { - lp->stats.tx_packets++; + dev->stats.tx_packets++; } } } @@ -1133,14 +1130,6 @@ static int ewrk3_close(struct net_device *dev) return 0; } -static struct net_device_stats *ewrk3_get_stats(struct net_device *dev) -{ - struct ewrk3_private *lp = netdev_priv(dev); - - /* Null body since there is no framing error counter */ - return &lp->stats; -} - /* ** Set or clear the multicast filter for this adapter. */ diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 4e8df910c00d..4419c3cee995 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -204,7 +204,6 @@ struct fec_enet_private { cbd_t *tx_bd_base; cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ cbd_t *dirty_tx; /* The ring entries to be free()ed. */ - struct net_device_stats stats; uint tx_full; spinlock_t lock; @@ -234,7 +233,6 @@ static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); -static struct net_device_stats *fec_enet_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void fec_restart(struct net_device *dev, int duplex); static void fec_stop(struct net_device *dev); @@ -359,7 +357,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) */ fep->tx_skbuff[fep->skb_cur] = skb; - fep->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; /* Push the data cache so the CPM does not get stale memory @@ -409,7 +407,7 @@ fec_timeout(struct net_device *dev) struct fec_enet_private *fep = netdev_priv(dev); printk("%s: transmit timed out.\n", dev->name); - fep->stats.tx_errors++; + dev->stats.tx_errors++; #ifndef final_version { int i; @@ -511,19 +509,19 @@ fec_enet_tx(struct net_device *dev) if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { - fep->stats.tx_errors++; + dev->stats.tx_errors++; if (status & BD_ENET_TX_HB) /* No heartbeat */ - fep->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (status & BD_ENET_TX_LC) /* Late collision */ - fep->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (status & BD_ENET_TX_RL) /* Retrans limit */ - fep->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (status & BD_ENET_TX_UN) /* Underrun */ - fep->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & BD_ENET_TX_CSL) /* Carrier lost */ - fep->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; } else { - fep->stats.tx_packets++; + dev->stats.tx_packets++; } #ifndef final_version @@ -534,7 +532,7 @@ fec_enet_tx(struct net_device *dev) * but we eventually sent the packet OK. */ if (status & BD_ENET_TX_DEF) - fep->stats.collisions++; + dev->stats.collisions++; /* Free the sk buffer associated with this last transmit. */ @@ -607,17 +605,17 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { /* Check for errors. */ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - fep->stats.rx_errors++; + dev->stats.rx_errors++; if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { /* Frame too long or too short. */ - fep->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } if (status & BD_ENET_RX_NO) /* Frame alignment */ - fep->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & BD_ENET_RX_CR) /* CRC Error */ - fep->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (status & BD_ENET_RX_OV) /* FIFO overrun */ - fep->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } /* Report late collisions as a frame error. @@ -625,16 +623,16 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { * have in the buffer. So, just drop this frame on the floor. */ if (status & BD_ENET_RX_CL) { - fep->stats.rx_errors++; - fep->stats.rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; goto rx_processing_done; } /* Process the incoming frame. */ - fep->stats.rx_packets++; + dev->stats.rx_packets++; pkt_len = bdp->cbd_datlen; - fep->stats.rx_bytes += pkt_len; + dev->stats.rx_bytes += pkt_len; data = (__u8*)__va(bdp->cbd_bufaddr); /* This does 16 byte alignment, exactly what we need. @@ -646,7 +644,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); - fep->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { skb_put(skb,pkt_len-4); /* Make room */ skb_copy_to_linear_data(skb, data, pkt_len-4); @@ -2220,13 +2218,6 @@ fec_enet_close(struct net_device *dev) return 0; } -static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - return &fep->stats; -} - /* Set or clear the multicast filter for this adaptor. * Skeleton taken from sunlance driver. * The CPM Ethernet implementation allows Multicast as well as individual @@ -2462,7 +2453,6 @@ int __init fec_enet_init(struct net_device *dev) dev->tx_timeout = fec_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = fec_enet_close; - dev->get_stats = fec_enet_get_stats; dev->set_multicast_list = set_multicast_list; for (i=0; ipoll_controller = gfar_netpoll; #endif dev->stop = gfar_close; - dev->get_stats = gfar_get_stats; dev->change_mtu = gfar_change_mtu; dev->mtu = 1500; dev->set_multicast_list = gfar_set_multi; @@ -1013,7 +1011,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; /* Update transmit stats */ - priv->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* Lock priv now */ spin_lock_irqsave(&priv->txlock, flags); @@ -1086,7 +1084,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) if (txbdp == priv->dirty_tx) { netif_stop_queue(dev); - priv->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } /* Update the current txbd to the next one */ @@ -1119,14 +1117,6 @@ static int gfar_close(struct net_device *dev) return 0; } -/* returns a net_device_stats structure pointer */ -static struct net_device_stats * gfar_get_stats(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - - return &(priv->stats); -} - /* Changes the mac address if the controller is not running. */ int gfar_set_mac_address(struct net_device *dev) { @@ -1238,7 +1228,7 @@ static void gfar_timeout(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - priv->stats.tx_errors++; + dev->stats.tx_errors++; if (dev->flags & IFF_UP) { stop_gfar(dev); @@ -1268,12 +1258,12 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) break; - priv->stats.tx_packets++; + dev->stats.tx_packets++; /* Deferred means some collisions occurred during transmit, */ /* but we eventually sent the packet. */ if (bdp->status & TXBD_DEF) - priv->stats.collisions++; + dev->stats.collisions++; /* Free the sk buffer associated with this TxBD */ dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); @@ -1345,7 +1335,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) static inline void count_errors(unsigned short status, struct gfar_private *priv) { - struct net_device_stats *stats = &priv->stats; + struct net_device_stats *stats = &dev->stats; struct gfar_extra_stats *estats = &priv->extra_stats; /* If the packet was truncated, none of the other errors @@ -1470,7 +1460,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, if (NULL == skb) { if (netif_msg_rx_err(priv)) printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; priv->extra_stats.rx_skbmissing++; } else { int ret; @@ -1528,7 +1518,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) (RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET | RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) { /* Increment the number of packets */ - priv->stats.rx_packets++; + dev->stats.rx_packets++; howmany++; /* Remove the FCS from the packet length */ @@ -1536,7 +1526,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) gfar_process_frame(dev, skb, pkt_len); - priv->stats.rx_bytes += pkt_len; + dev->stats.rx_bytes += pkt_len; } else { count_errors(bdp->status, priv); @@ -1916,17 +1906,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id) /* Update the error counters */ if (events & IEVENT_TXE) { - priv->stats.tx_errors++; + dev->stats.tx_errors++; if (events & IEVENT_LC) - priv->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (events & IEVENT_CRL) - priv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (events & IEVENT_XFUN) { if (netif_msg_tx_err(priv)) printk(KERN_DEBUG "%s: TX FIFO underrun, " "packet dropped.\n", dev->name); - priv->stats.tx_dropped++; + dev->stats.tx_dropped++; priv->extra_stats.tx_underrun++; /* Reactivate the Tx Queues */ @@ -1936,7 +1926,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) printk(KERN_DEBUG "%s: Transmit Error\n", dev->name); } if (events & IEVENT_BSY) { - priv->stats.rx_errors++; + dev->stats.rx_errors++; priv->extra_stats.rx_bsy++; gfar_receive(irq, dev_id); @@ -1951,7 +1941,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) dev->name, gfar_read(&priv->regs->rstat)); } if (events & IEVENT_BABR) { - priv->stats.rx_errors++; + dev->stats.rx_errors++; priv->extra_stats.rx_babr++; if (netif_msg_rx_err(priv)) diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index c991cb82ff22..be6e5bc7c881 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -141,7 +141,6 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d) dev->poll_controller = lance_poll; #endif dev->hard_start_xmit = &lance_start_xmit; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 67d82fa7659d..eebf39acf586 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -591,7 +591,7 @@ static void irqrx_handler(struct net_device *dev) skb = dev_alloc_skb(rda.length + 2); if (skb == NULL) - priv->stat.rx_dropped++; + dev->stats.rx_dropped++; else { /* copy out data */ @@ -606,8 +606,8 @@ static void irqrx_handler(struct net_device *dev) /* bookkeeping */ dev->last_rx = jiffies; - priv->stat.rx_packets++; - priv->stat.rx_bytes += rda.length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += rda.length; /* pass to the upper layers */ netif_rx(skb); @@ -617,11 +617,11 @@ static void irqrx_handler(struct net_device *dev) /* otherwise check error status bits and increase statistics */ else { - priv->stat.rx_errors++; + dev->stats.rx_errors++; if (rda.status & RCREG_FAER) - priv->stat.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rda.status & RCREG_CRCR) - priv->stat.rx_crc_errors++; + dev->stats.rx_crc_errors++; } /* descriptor processed, will become new last descriptor in queue */ @@ -656,8 +656,8 @@ static void irqtx_handler(struct net_device *dev) memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); /* update statistics */ - priv->stat.tx_packets++; - priv->stat.tx_bytes += tda.length; + dev->stats.tx_packets++; + dev->stats.tx_bytes += tda.length; /* update our pointers */ priv->txused[priv->currtxdescr] = 0; @@ -680,15 +680,15 @@ static void irqtxerr_handler(struct net_device *dev) memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); /* update statistics */ - priv->stat.tx_errors++; + dev->stats.tx_errors++; if (tda.status & (TCREG_NCRS | TCREG_CRSL)) - priv->stat.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tda.status & TCREG_EXC) - priv->stat.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (tda.status & TCREG_OWC) - priv->stat.tx_window_errors++; + dev->stats.tx_window_errors++; if (tda.status & TCREG_FU) - priv->stat.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; /* update our pointers */ priv->txused[priv->currtxdescr] = 0; @@ -824,7 +824,7 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) if (priv->txusedcnt >= TXBUFCNT) { retval = -EIO; - priv->stat.tx_dropped++; + dev->stats.tx_dropped++; goto tx_done; } @@ -876,14 +876,6 @@ tx_done: return retval; } -/* return pointer to Ethernet statistics */ - -static struct net_device_stats *ibmlana_stats(struct net_device *dev) -{ - ibmlana_priv *priv = netdev_priv(dev); - return &priv->stat; -} - /* switch receiver mode. */ static void ibmlana_set_multicast_list(struct net_device *dev) @@ -978,7 +970,6 @@ static int ibmlana_probe(struct net_device *dev) dev->stop = ibmlana_close; dev->hard_start_xmit = ibmlana_tx; dev->do_ioctl = NULL; - dev->get_stats = ibmlana_stats; dev->set_multicast_list = ibmlana_set_multicast_list; dev->flags |= IFF_MULTICAST; diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h index 6b58bab9e308..aa3ddbdee4bb 100644 --- a/drivers/net/ibmlana.h +++ b/drivers/net/ibmlana.h @@ -26,7 +26,6 @@ typedef enum { typedef struct { unsigned int slot; /* MCA-Slot-# */ - struct net_device_stats stat; /* packet statistics */ int realirq; /* memorizes actual IRQ, even when currently not allocated */ ibmlana_medium medium; /* physical cannector */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index db908c40dbe1..bdbf3dead4e2 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -87,7 +87,6 @@ static int ibmveth_close(struct net_device *dev); static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int ibmveth_poll(struct napi_struct *napi, int budget); static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *ibmveth_get_stats(struct net_device *dev); static void ibmveth_set_multicast_list(struct net_device *dev); static int ibmveth_change_mtu(struct net_device *dev, int new_mtu); static void ibmveth_proc_register_driver(void); @@ -909,9 +908,9 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) skb->len, DMA_TO_DEVICE); out: spin_lock_irqsave(&adapter->stats_lock, flags); - adapter->stats.tx_dropped += tx_dropped; - adapter->stats.tx_bytes += tx_bytes; - adapter->stats.tx_packets += tx_packets; + netdev->stats.tx_dropped += tx_dropped; + netdev->stats.tx_bytes += tx_bytes; + netdev->stats.tx_packets += tx_packets; adapter->tx_send_failed += tx_send_failed; adapter->tx_map_failed += tx_map_failed; spin_unlock_irqrestore(&adapter->stats_lock, flags); @@ -957,8 +956,8 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) netif_receive_skb(skb); /* send it up */ - adapter->stats.rx_packets++; - adapter->stats.rx_bytes += length; + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += length; frames_processed++; netdev->last_rx = jiffies; } @@ -1003,12 +1002,6 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; } -static struct net_device_stats *ibmveth_get_stats(struct net_device *dev) -{ - struct ibmveth_adapter *adapter = dev->priv; - return &adapter->stats; -} - static void ibmveth_set_multicast_list(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; @@ -1170,7 +1163,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->open = ibmveth_open; netdev->stop = ibmveth_close; netdev->hard_start_xmit = ibmveth_start_xmit; - netdev->get_stats = ibmveth_get_stats; netdev->set_multicast_list = ibmveth_set_multicast_list; netdev->do_ioctl = ibmveth_ioctl; netdev->ethtool_ops = &netdev_ethtool_ops; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 448e618b6974..15949d3df17e 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -40,7 +40,6 @@ #define TX_Q_LIMIT 32 struct ifb_private { - struct net_device_stats stats; struct tasklet_struct ifb_tasklet; int tasklet_pending; /* mostly debug stats leave in for now */ @@ -61,7 +60,6 @@ static int numifbs = 2; static void ri_tasklet(unsigned long dev); static int ifb_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *ifb_get_stats(struct net_device *dev); static int ifb_open(struct net_device *dev); static int ifb_close(struct net_device *dev); @@ -70,7 +68,7 @@ static void ri_tasklet(unsigned long dev) struct net_device *_dev = (struct net_device *)dev; struct ifb_private *dp = netdev_priv(_dev); - struct net_device_stats *stats = &dp->stats; + struct net_device_stats *stats = &_dev->stats; struct sk_buff *skb; dp->st_task_enter++; @@ -140,7 +138,6 @@ resched: static void ifb_setup(struct net_device *dev) { /* Initialize the device structure. */ - dev->get_stats = ifb_get_stats; dev->hard_start_xmit = ifb_xmit; dev->open = &ifb_open; dev->stop = &ifb_close; @@ -158,7 +155,7 @@ static void ifb_setup(struct net_device *dev) static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); - struct net_device_stats *stats = &dp->stats; + struct net_device_stats *stats = &dev->stats; int ret = 0; u32 from = G_TC_FROM(skb->tc_verd); @@ -185,19 +182,6 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) return ret; } -static struct net_device_stats *ifb_get_stats(struct net_device *dev) -{ - struct ifb_private *dp = netdev_priv(dev); - struct net_device_stats *stats = &dp->stats; - - pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n", - dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter, - dp->st_rx2tx_tran, dp->st_rxq_notenter, dp->st_rx_frm_egr, - dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch); - - return stats; -} - static int ifb_close(struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 0433c41f9029..97bd9dc2e52e 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -196,7 +196,6 @@ struct veth_lpar_connection { struct veth_port { struct device *dev; - struct net_device_stats stats; u64 mac_addr; HvLpIndexMap lpar_map; @@ -936,9 +935,6 @@ static void veth_release_connection(struct kobject *kobj) static int veth_open(struct net_device *dev) { - struct veth_port *port = (struct veth_port *) dev->priv; - - memset(&port->stats, 0, sizeof (port->stats)); netif_start_queue(dev); return 0; } @@ -949,13 +945,6 @@ static int veth_close(struct net_device *dev) return 0; } -static struct net_device_stats *veth_get_stats(struct net_device *dev) -{ - struct veth_port *port = (struct veth_port *) dev->priv; - - return &port->stats; -} - static int veth_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < 68) || (new_mtu > VETH_MAX_MTU)) @@ -1084,7 +1073,6 @@ static struct net_device * __init veth_probe_one(int vlan, dev->open = veth_open; dev->hard_start_xmit = veth_start_xmit; dev->stop = veth_close; - dev->get_stats = veth_get_stats; dev->change_mtu = veth_change_mtu; dev->set_mac_address = NULL; dev->set_multicast_list = veth_set_multicast_list; @@ -1183,7 +1171,6 @@ static void veth_transmit_to_many(struct sk_buff *skb, HvLpIndexMap lpmask, struct net_device *dev) { - struct veth_port *port = (struct veth_port *) dev->priv; int i, success, error; success = error = 0; @@ -1199,11 +1186,11 @@ static void veth_transmit_to_many(struct sk_buff *skb, } if (error) - port->stats.tx_errors++; + dev->stats.tx_errors++; if (success) { - port->stats.tx_packets++; - port->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; } } @@ -1541,8 +1528,8 @@ static void veth_receive(struct veth_lpar_connection *cnx, skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); /* send it up */ - port->stats.rx_packets++; - port->stats.rx_bytes += length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += length; } while (startchunk += nchunks, startchunk < VETH_MAX_FRAMES_PER_MSG); /* Ack it */ diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 5884f5bd04a4..afa4638052a2 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -322,7 +322,6 @@ struct i596_private { struct i596_cmd *cmd_head; int cmd_backlog; u32 last_cmd; - struct net_device_stats stats; int next_tx_cmd; int options; spinlock_t lock; /* serialize access to chip */ @@ -352,7 +351,6 @@ static int i596_open(struct net_device *dev); static int 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 struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); static void i596_tx_timeout (struct net_device *dev); static void print_eth(unsigned char *buf, char *str); @@ -725,7 +723,7 @@ memory_squeeze: printk(KERN_ERR "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { if (!rx_in_place) { /* 16 byte align the data fields */ @@ -742,28 +740,28 @@ memory_squeeze: skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } } else { DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n", dev->name, rfd->stat)); - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (rfd->stat & SWAP16(0x0100)) - lp->stats.collisions++; + dev->stats.collisions++; if (rfd->stat & SWAP16(0x8000)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (rfd->stat & SWAP16(0x0001)) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (rfd->stat & SWAP16(0x0002)) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (rfd->stat & SWAP16(0x0004)) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rfd->stat & SWAP16(0x0008)) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rfd->stat & SWAP16(0x0010)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } /* Clear the buffer descriptor count and EOF + F flags */ @@ -821,8 +819,8 @@ static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private dev_kfree_skb(skb); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; ptr->v_next = NULL; ptr->b_next = I596_NULL; @@ -951,10 +949,10 @@ static void i596_tx_timeout (struct net_device *dev) "%s: transmit timed out, status resetting.\n", dev->name)); - lp->stats.tx_errors++; + dev->stats.tx_errors++; /* Try to restart the adaptor */ - if (lp->last_restart == lp->stats.tx_packets) { + if (lp->last_restart == dev->stats.tx_packets) { DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n")); /* Shutdown and restart */ i596_reset (dev, lp); @@ -964,7 +962,7 @@ static void i596_tx_timeout (struct net_device *dev) lp->dma->scb.command = SWAP16(CUC_START | RX_START); DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb)); ca (dev); - lp->last_restart = lp->stats.tx_packets; + lp->last_restart = dev->stats.tx_packets; } dev->trans_start = jiffies; @@ -999,7 +997,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: xmit ring full, dropping packet.\n", dev->name)); - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); } else { @@ -1025,8 +1023,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd)); i596_add_cmd(dev, &tx_cmd->cmd); - lp->stats.tx_packets++; - lp->stats.tx_bytes += length; + dev->stats.tx_packets++; + dev->stats.tx_bytes += length; } netif_start_queue(dev); @@ -1076,7 +1074,6 @@ static int __devinit i82596_probe(struct net_device *dev) dev->open = i596_open; dev->stop = i596_close; dev->hard_start_xmit = i596_start_xmit; - dev->get_stats = i596_get_stats; dev->set_multicast_list = set_multicast_list; dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1197,17 +1194,17 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) DEB(DEB_TXADDR, print_eth(skb->data, "tx-done")); } else { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (ptr->status & SWAP16(0x0020)) - lp->stats.collisions++; + dev->stats.collisions++; if (!(ptr->status & SWAP16(0x0040))) - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (ptr->status & SWAP16(0x0400)) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (ptr->status & SWAP16(0x0800)) - lp->stats.collisions++; + dev->stats.collisions++; if (ptr->status & SWAP16(0x1000)) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } dma_unmap_single(dev->dev.parent, tx_cmd->dma_addr, @@ -1292,8 +1289,8 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status)); ack_cmd |= RX_START; - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; rebuild_rx_bufs(dev); } } @@ -1346,13 +1343,6 @@ static int i596_close(struct net_device *dev) return 0; } -static struct net_device_stats *i596_get_stats(struct net_device *dev) -{ - struct i596_private *lp = netdev_priv(dev); - - return &lp->stats; -} - /* * Set or clear the multicast filter for this adaptor. */ diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 408ae6eb6a8b..c5095ecd8b11 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -350,7 +350,6 @@ struct i596_private { /* aligned to a 16-byte boundary */ struct i596_cmd *cmd_head; int cmd_backlog; unsigned long last_cmd; - struct net_device_stats stats; spinlock_t cmd_lock; }; @@ -381,7 +380,6 @@ static int i596_open(struct net_device *dev); static int 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 struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); static void print_eth(char *); static void set_multicast_list(struct net_device *dev); @@ -670,7 +668,7 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, if (skb == NULL) { printk ("%s: i596_rx Memory squeeze, " "dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return 1; } @@ -679,27 +677,27 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } else { #if 0 printk("Frame reception error status %04x\n", rfd->stat); #endif - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (rfd->stat & RFD_COLLISION) - lp->stats.collisions++; + dev->stats.collisions++; if (rfd->stat & RFD_SHORT_FRAME_ERR) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (rfd->stat & RFD_DMA_ERR) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (rfd->stat & RFD_NOBUFS_ERR) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (rfd->stat & RFD_ALIGN_ERR) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rfd->stat & RFD_CRC_ERR) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rfd->stat & RFD_LENGTH_ERR) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } rfd->stat = rfd->count = 0; return 0; @@ -755,8 +753,8 @@ i596_cleanup_cmd(struct net_device *dev) { dev_kfree_skb_any(tx_cmd_tbd->skb); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; cmd->pa_next = I596_NULL; kfree((unsigned char *)tx_cmd); @@ -867,7 +865,6 @@ static int i596_open(struct net_device *dev) } static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct i596_private *lp = dev->priv; struct tx_cmd *tx_cmd; short length; @@ -884,7 +881,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC); if (tx_cmd == NULL) { printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name); - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb (skb); } else { struct i596_tbd *tx_cmd_tbd; @@ -907,7 +904,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { i596_add_cmd (dev, (struct i596_cmd *) tx_cmd); - lp->stats.tx_packets++; + dev->stats.tx_packets++; } return 0; @@ -920,10 +917,10 @@ i596_tx_timeout (struct net_device *dev) { /* Transmitter timeout, serious problems. */ printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name); - lp->stats.tx_errors++; + dev->stats.tx_errors++; /* Try to restart the adaptor */ - if (lp->last_restart == lp->stats.tx_packets) { + if (lp->last_restart == dev->stats.tx_packets) { printk ("Resetting board.\n"); /* Shutdown and restart */ @@ -933,7 +930,7 @@ i596_tx_timeout (struct net_device *dev) { printk ("Kicking board.\n"); lp->scb.command = (CUC_START | RX_START); CA(); - lp->last_restart = lp->stats.tx_packets; + lp->last_restart = dev->stats.tx_packets; } netif_wake_queue(dev); } @@ -1021,7 +1018,6 @@ static int __init lp486e_probe(struct net_device *dev) { dev->open = &i596_open; dev->stop = &i596_close; dev->hard_start_xmit = &i596_start_xmit; - dev->get_stats = &i596_get_stats; dev->set_multicast_list = &set_multicast_list; dev->watchdog_timeo = 5*HZ; dev->tx_timeout = i596_tx_timeout; @@ -1078,20 +1074,20 @@ i596_handle_CU_completion(struct net_device *dev, if (i596_debug) print_eth(pa_to_va(tx_cmd_tbd->pa_data)); } else { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (i596_debug) printk("transmission failure:%04x\n", cmd->status); if (cmd->status & 0x0020) - lp->stats.collisions++; + dev->stats.collisions++; if (!(cmd->status & 0x0040)) - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (cmd->status & 0x0400) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (cmd->status & 0x0800) - lp->stats.collisions++; + dev->stats.collisions++; if (cmd->status & 0x1000) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } dev_kfree_skb_irq(tx_cmd_tbd->skb); @@ -1242,12 +1238,6 @@ static int i596_close(struct net_device *dev) { return 0; } -static struct net_device_stats * i596_get_stats(struct net_device *dev) { - struct i596_private *lp = dev->priv; - - return &lp->stats; -} - /* * Set or clear the multicast filter for this adaptor. */ diff --git a/drivers/net/mace.c b/drivers/net/mace.c index de3b002e9a4c..ee132b1e09b0 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -57,7 +57,6 @@ struct mace_data { unsigned char tx_fullup; unsigned char tx_active; unsigned char tx_bad_runt; - struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; int port_aaui; @@ -78,7 +77,6 @@ struct mace_data { static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *mace_stats(struct net_device *dev); static void mace_set_multicast(struct net_device *dev); static void mace_reset(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); @@ -188,7 +186,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1); mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1; - memset(&mp->stats, 0, sizeof(mp->stats)); memset((char *) mp->tx_cmds, 0, (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); init_timer(&mp->tx_timeout); @@ -213,7 +210,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i dev->open = mace_open; dev->stop = mace_close; dev->hard_start_xmit = mace_xmit_start; - dev->get_stats = mace_stats; dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; @@ -584,13 +580,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *mace_stats(struct net_device *dev) -{ - struct mace_data *p = (struct mace_data *) dev->priv; - - return &p->stats; -} - static void mace_set_multicast(struct net_device *dev) { struct mace_data *mp = (struct mace_data *) dev->priv; @@ -644,19 +633,19 @@ static void mace_set_multicast(struct net_device *dev) spin_unlock_irqrestore(&mp->lock, flags); } -static void mace_handle_misc_intrs(struct mace_data *mp, int intr) +static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_device *dev) { volatile struct mace __iomem *mb = mp->mace; static int mace_babbles, mace_jabbers; if (intr & MPCO) - mp->stats.rx_missed_errors += 256; - mp->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */ + dev->stats.rx_missed_errors += 256; + dev->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */ if (intr & RNTPCO) - mp->stats.rx_length_errors += 256; - mp->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */ + dev->stats.rx_length_errors += 256; + dev->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */ if (intr & CERR) - ++mp->stats.tx_heartbeat_errors; + ++dev->stats.tx_heartbeat_errors; if (intr & BABBLE) if (mace_babbles++ < 4) printk(KERN_DEBUG "mace: babbling transmitter\n"); @@ -680,7 +669,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) spin_lock_irqsave(&mp->lock, flags); intr = in_8(&mb->ir); /* read interrupt register */ in_8(&mb->xmtrc); /* get retries */ - mace_handle_misc_intrs(mp, intr); + mace_handle_misc_intrs(mp, intr, dev); i = mp->tx_empty; while (in_8(&mb->pr) & XMTSV) { @@ -693,7 +682,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) */ intr = in_8(&mb->ir); if (intr != 0) - mace_handle_misc_intrs(mp, intr); + mace_handle_misc_intrs(mp, intr, dev); if (mp->tx_bad_runt) { fs = in_8(&mb->xmtfs); mp->tx_bad_runt = 0; @@ -767,14 +756,14 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) } /* Update stats */ if (fs & (UFLO|LCOL|LCAR|RTRY)) { - ++mp->stats.tx_errors; + ++dev->stats.tx_errors; if (fs & LCAR) - ++mp->stats.tx_carrier_errors; + ++dev->stats.tx_carrier_errors; if (fs & (UFLO|LCOL|RTRY)) - ++mp->stats.tx_aborted_errors; + ++dev->stats.tx_aborted_errors; } else { - mp->stats.tx_bytes += mp->tx_bufs[i]->len; - ++mp->stats.tx_packets; + dev->stats.tx_bytes += mp->tx_bufs[i]->len; + ++dev->stats.tx_packets; } dev_kfree_skb_irq(mp->tx_bufs[i]); --mp->tx_active; @@ -828,7 +817,7 @@ static void mace_tx_timeout(unsigned long data) goto out; /* update various counters */ - mace_handle_misc_intrs(mp, in_8(&mb->ir)); + mace_handle_misc_intrs(mp, in_8(&mb->ir), dev); cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty; @@ -848,7 +837,7 @@ static void mace_tx_timeout(unsigned long data) /* fix up the transmit side */ i = mp->tx_empty; mp->tx_active = 0; - ++mp->stats.tx_errors; + ++dev->stats.tx_errors; if (mp->tx_bad_runt) { mp->tx_bad_runt = 0; } else if (i != mp->tx_fill) { @@ -916,18 +905,18 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) /* got a packet, have a look at it */ skb = mp->rx_bufs[i]; if (skb == 0) { - ++mp->stats.rx_dropped; + ++dev->stats.rx_dropped; } else if (nb > 8) { data = skb->data; frame_status = (data[nb-3] << 8) + data[nb-4]; if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) { - ++mp->stats.rx_errors; + ++dev->stats.rx_errors; if (frame_status & RS_OFLO) - ++mp->stats.rx_over_errors; + ++dev->stats.rx_over_errors; if (frame_status & RS_FRAMERR) - ++mp->stats.rx_frame_errors; + ++dev->stats.rx_frame_errors; if (frame_status & RS_FCSERR) - ++mp->stats.rx_crc_errors; + ++dev->stats.rx_crc_errors; } else { /* Mace feature AUTO_STRIP_RCV is on by default, dropping the * FCS on frames with 802.3 headers. This means that Ethernet @@ -939,15 +928,15 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) nb -= 8; skb_put(skb, nb); skb->protocol = eth_type_trans(skb, dev); - mp->stats.rx_bytes += skb->len; + dev->stats.rx_bytes += skb->len; netif_rx(skb); dev->last_rx = jiffies; mp->rx_bufs[i] = NULL; - ++mp->stats.rx_packets; + ++dev->stats.rx_packets; } } else { - ++mp->stats.rx_errors; - ++mp->stats.rx_length_errors; + ++dev->stats.rx_errors; + ++dev->stats.rx_length_errors; } /* advance to next */ diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 5d2daa248873..57f7c1a2c1d7 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -65,7 +65,6 @@ struct mace_data { unsigned char *rx_ring; dma_addr_t rx_ring_phys; int dma_intr; - struct net_device_stats stats; int rx_slot, rx_tail; int tx_slot, tx_sloti, tx_count; int chipid; @@ -92,7 +91,6 @@ struct mace_frame { static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *mace_stats(struct net_device *dev); static void mace_set_multicast(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); static void mace_reset(struct net_device *dev); @@ -242,14 +240,11 @@ static int __devinit mace_probe(struct platform_device *pdev) return -ENODEV; } - memset(&mp->stats, 0, sizeof(mp->stats)); - dev->open = mace_open; dev->stop = mace_close; dev->hard_start_xmit = mace_xmit_start; dev->tx_timeout = mace_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->get_stats = mace_stats; dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; @@ -472,8 +467,8 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) mp->tx_count--; local_irq_restore(flags); - mp->stats.tx_packets++; - mp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* We need to copy into our xmit buffer to take care of alignment and caching issues */ skb_copy_from_linear_data(skb, mp->tx_ring, skb->len); @@ -492,12 +487,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static struct net_device_stats *mace_stats(struct net_device *dev) -{ - struct mace_data *mp = netdev_priv(dev); - return &mp->stats; -} - static void mace_set_multicast(struct net_device *dev) { struct mace_data *mp = netdev_priv(dev); @@ -555,13 +544,13 @@ static void mace_handle_misc_intrs(struct mace_data *mp, int intr) static int mace_babbles, mace_jabbers; if (intr & MPCO) - mp->stats.rx_missed_errors += 256; - mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ + dev->stats.rx_missed_errors += 256; + dev->stats.rx_missed_errors += mb->mpc; /* reading clears it */ if (intr & RNTPCO) - mp->stats.rx_length_errors += 256; - mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ + dev->stats.rx_length_errors += 256; + dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */ if (intr & CERR) - ++mp->stats.tx_heartbeat_errors; + ++dev->stats.tx_heartbeat_errors; if (intr & BABBLE) if (mace_babbles++ < 4) printk(KERN_DEBUG "macmace: babbling transmitter\n"); @@ -600,14 +589,14 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) } /* Update stats */ if (fs & (UFLO|LCOL|LCAR|RTRY)) { - ++mp->stats.tx_errors; + ++dev->stats.tx_errors; if (fs & LCAR) - ++mp->stats.tx_carrier_errors; + ++dev->stats.tx_carrier_errors; else if (fs & (UFLO|LCOL|RTRY)) { - ++mp->stats.tx_aborted_errors; + ++dev->stats.tx_aborted_errors; if (mb->xmtfs & UFLO) { printk(KERN_ERR "%s: DMA underrun.\n", dev->name); - mp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; mace_txdma_reset(dev); } } @@ -661,23 +650,23 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) unsigned int frame_status = mf->rcvsts; if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) { - mp->stats.rx_errors++; + dev->stats.rx_errors++; if (frame_status & RS_OFLO) { printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name); - mp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } if (frame_status & RS_CLSN) - mp->stats.collisions++; + dev->stats.collisions++; if (frame_status & RS_FRAMERR) - mp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (frame_status & RS_FCSERR) - mp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } else { unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 ); skb = dev_alloc_skb(frame_length + 2); if (!skb) { - mp->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } skb_reserve(skb, 2); @@ -686,8 +675,8 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - mp->stats.rx_packets++; - mp->stats.rx_bytes += frame_length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += frame_length; } } diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 32bed6bc6c06..fe5b6c372072 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -66,7 +66,6 @@ module_param(timeout, int, 0); * packets in and out, so there is place for a packet */ struct meth_private { - struct net_device_stats stats; /* in-memory copy of MAC Control register */ unsigned long mac_ctrl; /* in-memory copy of DMA Control register */ @@ -401,15 +400,15 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) printk(KERN_DEBUG "%s: bogus packet size: %ld, status=%#2lx.\n", dev->name, priv->rx_write, priv->rx_ring[priv->rx_write]->status.raw); - priv->stats.rx_errors++; - priv->stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; skb = priv->rx_skbs[priv->rx_write]; } else { skb = alloc_skb(METH_RX_BUFF_SIZE, GFP_ATOMIC); if (!skb) { /* Ouch! No memory! Drop packet on the floor */ DPRINTK("No mem: dropping packet\n"); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; skb = priv->rx_skbs[priv->rx_write]; } else { struct sk_buff *skb_c = priv->rx_skbs[priv->rx_write]; @@ -421,13 +420,13 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) priv->rx_skbs[priv->rx_write] = skb; skb_c->protocol = eth_type_trans(skb_c, dev); dev->last_rx = jiffies; - priv->stats.rx_packets++; - priv->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; netif_rx(skb_c); } } } else { - priv->stats.rx_errors++; + dev->stats.rx_errors++; skb=priv->rx_skbs[priv->rx_write]; #if MFE_DEBUG>0 printk(KERN_WARNING "meth: RX error: status=0x%016lx\n",status); @@ -490,10 +489,10 @@ static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status) #endif if (status & METH_TX_ST_DONE) { if (status & METH_TX_ST_SUCCESS){ - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; } else { - priv->stats.tx_errors++; + dev->stats.tx_errors++; #if MFE_DEBUG>=1 DPRINTK("TX error: status=%016lx <",status); if(status & METH_TX_ST_SUCCESS) @@ -734,7 +733,7 @@ static void meth_tx_timeout(struct net_device *dev) /* Try to reset the interface. */ meth_reset(dev); - priv->stats.tx_errors++; + dev->stats.tx_errors++; /* Clear all rings */ meth_free_tx_ring(priv); @@ -773,12 +772,6 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) /* * Return statistics to the caller */ -static struct net_device_stats *meth_stats(struct net_device *dev) -{ - struct meth_private *priv = netdev_priv(dev); - return &priv->stats; -} - /* * The init function. */ @@ -796,7 +789,6 @@ static int __init meth_probe(struct platform_device *pdev) dev->stop = meth_release; dev->hard_start_xmit = meth_tx; dev->do_ioctl = meth_ioctl; - dev->get_stats = meth_stats; #ifdef HAVE_TX_TIMEOUT dev->tx_timeout = meth_tx_timeout; dev->watchdog_timeo = timeout; diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index c0f5ad38fb17..d593175ab6f0 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -21,10 +21,6 @@ #define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field)) -struct mipsnet_priv { - struct net_device_stats stats; -}; - static char mipsnet_string[] = "mipsnet"; /* @@ -49,7 +45,6 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev, { int count_to_go = skb->len; char *buf_ptr = skb->data; - struct mipsnet_priv *mp = netdev_priv(dev); pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n", dev->name, __FUNCTION__, skb->len); @@ -63,8 +58,8 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev, outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); } - mp->stats.tx_packets++; - mp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; return skb->len; } @@ -87,10 +82,9 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) { struct sk_buff *skb; size_t len = count; - struct mipsnet_priv *mp = netdev_priv(dev); if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { - mp->stats.rx_dropped++; + dev->stats.rx_dropped++; return -ENOMEM; } @@ -105,8 +99,8 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) dev->name, __FUNCTION__); netif_rx(skb); - mp->stats.rx_packets++; - mp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; return count; } @@ -203,13 +197,6 @@ static int mipsnet_close(struct net_device *dev) return 0; } -static struct net_device_stats *mipsnet_get_stats(struct net_device *dev) -{ - struct mipsnet_priv *mp = netdev_priv(dev); - - return &mp->stats; -} - static void mipsnet_set_mclist(struct net_device *dev) { // we don't do anything @@ -221,7 +208,7 @@ static int __init mipsnet_probe(struct device *dev) struct net_device *netdev; int err; - netdev = alloc_etherdev(sizeof(struct mipsnet_priv)); + netdev = alloc_etherdev(0); if (!netdev) { err = -ENOMEM; goto out; @@ -232,7 +219,6 @@ static int __init mipsnet_probe(struct device *dev) netdev->open = mipsnet_open; netdev->stop = mipsnet_close; netdev->hard_start_xmit = mipsnet_xmit; - netdev->get_stats = mipsnet_get_stats; netdev->set_multicast_list = mipsnet_set_mclist; /* diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 2a808e265a3e..35781616eb23 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -63,7 +63,6 @@ static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num); static int mv643xx_eth_open(struct net_device *); static int mv643xx_eth_stop(struct net_device *); static int mv643xx_eth_change_mtu(struct net_device *, int); -static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *); static void eth_port_init_mac_tables(unsigned int eth_port_num); #ifdef MV643XX_NAPI static int mv643xx_poll(struct napi_struct *napi, int budget); @@ -341,7 +340,7 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force) if (cmd_sts & ETH_ERROR_SUMMARY) { printk("%s: Error in TX\n", dev->name); - mp->stats.tx_errors++; + dev->stats.tx_errors++; } spin_unlock_irqrestore(&mp->lock, flags); @@ -388,7 +387,7 @@ static void mv643xx_eth_free_all_tx_descs(struct net_device *dev) static int mv643xx_eth_receive_queue(struct net_device *dev, int budget) { struct mv643xx_private *mp = netdev_priv(dev); - struct net_device_stats *stats = &mp->stats; + struct net_device_stats *stats = &dev->stats; unsigned int received_packets = 0; struct sk_buff *skb; struct pkt_info pkt_info; @@ -1192,7 +1191,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); - struct net_device_stats *stats = &mp->stats; + struct net_device_stats *stats = &dev->stats; unsigned long flags; BUG_ON(netif_queue_stopped(dev)); @@ -1228,23 +1227,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; /* success */ } -/* - * mv643xx_eth_get_stats - * - * Returns a pointer to the interface statistics. - * - * Input : dev - a pointer to the required interface - * - * Output : a pointer to the interface's statistics - */ - -static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) -{ - struct mv643xx_private *mp = netdev_priv(dev); - - return &mp->stats; -} - #ifdef CONFIG_NET_POLL_CONTROLLER static void mv643xx_netpoll(struct net_device *netdev) { @@ -1339,7 +1321,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->open = mv643xx_eth_open; dev->stop = mv643xx_eth_stop; dev->hard_start_xmit = mv643xx_eth_start_xmit; - dev->get_stats = mv643xx_eth_get_stats; dev->set_mac_address = mv643xx_eth_set_mac_address; dev->set_multicast_list = mv643xx_eth_set_rx_mode; diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 331b76c49561..35c4c598c8d2 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -353,7 +353,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev) sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE); dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; - mp->enet_stats.tx_packets++; + dev->stats.tx_packets++; entry = NEXT_TX(entry); } mp->tx_old = entry; @@ -434,20 +434,20 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); - mp->enet_stats.rx_errors++; + dev->stats.rx_errors++; if (len < (ETH_HLEN + MYRI_PAD_LEN)) { DRX(("BAD_LENGTH] ")); - mp->enet_stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else { DRX(("NO_PADDING] ")); - mp->enet_stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; } /* Return it to the LANAI. */ drop_it: drops++; DRX(("DROP ")); - mp->enet_stats.rx_dropped++; + dev->stats.rx_dropped++; sbus_dma_sync_single_for_device(mp->myri_sdev, sbus_readl(&rxd->myri_scatters[0].addr), RX_ALLOC_SIZE, @@ -527,8 +527,8 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) netif_rx(skb); dev->last_rx = jiffies; - mp->enet_stats.rx_packets++; - mp->enet_stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; next: DRX(("NEXT\n")); entry = NEXT_RX(entry); @@ -596,7 +596,7 @@ static void myri_tx_timeout(struct net_device *dev) printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); - mp->enet_stats.tx_errors++; + dev->stats.tx_errors++; myri_init(mp, 0); netif_wake_queue(dev); } @@ -806,9 +806,6 @@ static int myri_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static struct net_device_stats *myri_get_stats(struct net_device *dev) -{ return &(((struct myri_eth *)dev->priv)->enet_stats); } - static void myri_set_multicast(struct net_device *dev) { /* Do nothing, all MyriCOM nodes transmit multicast frames @@ -1060,7 +1057,6 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) dev->hard_start_xmit = &myri_start_xmit; dev->tx_timeout = &myri_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &myri_get_stats; dev->set_multicast_list = &myri_set_multicast; dev->irq = sdev->irqs[0]; diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 2f69ef7cdccb..5d93fcc95d55 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -280,7 +280,6 @@ struct myri_eth { void __iomem *lregs; /* Quick ptr to LANAI regs. */ struct sk_buff *rx_skbs[RX_RING_SIZE+1];/* RX skb's */ struct sk_buff *tx_skbs[TX_RING_SIZE]; /* TX skb's */ - struct net_device_stats enet_stats; /* Interface stats. */ /* These are less frequently accessed. */ void __iomem *regs; /* MyriCOM register space. */ diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 6fee405d8403..eb0aff787dfd 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -97,7 +97,6 @@ struct netx_eth_priv { void __iomem *sram_base, *xpec_base, *xmac_base; int id; - struct net_device_stats stats; struct mii_if_info mii; u32 msg_enable; struct xc *xc; @@ -129,8 +128,8 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) FIFO_PTR_FRAMELEN(len)); ndev->trans_start = jiffies; - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; netif_stop_queue(ndev); spin_unlock_irq(&priv->lock); @@ -156,7 +155,7 @@ static void netx_eth_receive(struct net_device *ndev) if (unlikely(skb == NULL)) { printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", ndev->name); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -170,8 +169,8 @@ static void netx_eth_receive(struct net_device *ndev) ndev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); - priv->stats.rx_packets++; - priv->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } static irqreturn_t @@ -210,12 +209,6 @@ netx_eth_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev) -{ - struct netx_eth_priv *priv = netdev_priv(ndev); - return &priv->stats; -} - static int netx_eth_open(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); @@ -323,7 +316,6 @@ static int netx_eth_enable(struct net_device *ndev) ndev->hard_start_xmit = netx_eth_hard_start_xmit; ndev->tx_timeout = netx_eth_timeout; ndev->watchdog_timeo = msecs_to_jiffies(5000); - ndev->get_stats = netx_eth_query_statistics; ndev->set_multicast_list = netx_eth_set_multicast_list; priv->msg_enable = NETIF_MSG_LINK; diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index cc1d09a21c0c..1dc74a78afa6 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -89,7 +89,6 @@ static unsigned int ports[] __initdata = /* Information that needs to be kept for each board. */ struct ni5010_local { - struct net_device_stats stats; int o_pkt_size; spinlock_t lock; }; @@ -103,7 +102,6 @@ static irqreturn_t ni5010_interrupt(int irq, void *dev_id); static void ni5010_rx(struct net_device *dev); static void ni5010_timeout(struct net_device *dev); static int ni5010_close(struct net_device *dev); -static struct net_device_stats *ni5010_get_stats(struct net_device *dev); static void ni5010_set_multicast_list(struct net_device *dev); static void reset_receiver(struct net_device *dev); @@ -334,7 +332,6 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) dev->open = ni5010_open; dev->stop = ni5010_close; dev->hard_start_xmit = ni5010_send_packet; - dev->get_stats = ni5010_get_stats; dev->set_multicast_list = ni5010_set_multicast_list; dev->tx_timeout = ni5010_timeout; dev->watchdog_timeo = HZ/20; @@ -532,11 +529,11 @@ static void ni5010_rx(struct net_device *dev) if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) { PRINTK((KERN_INFO "%s: receive error.\n", dev->name)); - lp->stats.rx_errors++; - if (rcv_stat & RS_RUNT) lp->stats.rx_length_errors++; - if (rcv_stat & RS_ALIGN) lp->stats.rx_frame_errors++; - if (rcv_stat & RS_CRC_ERR) lp->stats.rx_crc_errors++; - if (rcv_stat & RS_OFLW) lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++; + if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++; + if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++; + if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++; outb(0xff, EDLC_RCLR); /* Clear the interrupt */ return; } @@ -547,8 +544,8 @@ static void ni5010_rx(struct net_device *dev) if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) { PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n", dev->name, i_pkt_size)); - lp->stats.rx_errors++; - lp->stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; return; } @@ -556,7 +553,7 @@ static void ni5010_rx(struct net_device *dev) skb = dev_alloc_skb(i_pkt_size + 3); if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -573,8 +570,8 @@ static void ni5010_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += i_pkt_size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += i_pkt_size; PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n", dev->name, i_pkt_size)); @@ -602,14 +599,14 @@ static int process_xmt_interrupt(struct net_device *dev) /* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */ outb(MM_EN_XMT | MM_MUX, IE_MMODE); outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */ - lp->stats.collisions++; + dev->stats.collisions++; return 1; } /* FIXME: handle other xmt error conditions */ - lp->stats.tx_packets++; - lp->stats.tx_bytes += lp->o_pkt_size; + dev->stats.tx_packets++; + dev->stats.tx_bytes += lp->o_pkt_size; netif_wake_queue(dev); PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n", @@ -638,24 +635,6 @@ static int ni5010_close(struct net_device *dev) } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *ni5010_get_stats(struct net_device *dev) -{ - struct ni5010_local *lp = netdev_priv(dev); - - PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name)); - - if (NI5010_DEBUG) ni5010_show_registers(dev); - - /* cli(); */ - /* Update the statistics from the device registers. */ - /* We do this in the interrupt handler */ - /* sti(); */ - - return &lp->stats; -} - /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 723685ee57aa..f310d94443a0 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -530,8 +530,8 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } else skb->ip_summed = CHECKSUM_NONE; - mac->stats.rx_bytes += len; - mac->stats.rx_packets++; + mac->netdev->stats.rx_bytes += len; + mac->netdev->stats.rx_packets++; skb->protocol = eth_type_trans(skb, mac->netdev); netif_receive_skb(skb); @@ -1032,8 +1032,8 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) info->skb = skb; txring->next_to_fill++; - mac->stats.tx_packets++; - mac->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; spin_unlock_irqrestore(&txring->lock, flags); @@ -1047,14 +1047,6 @@ out_err: return NETDEV_TX_BUSY; } -static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev) -{ - struct pasemi_mac *mac = netdev_priv(dev); - - return &mac->stats; -} - - static void pasemi_mac_set_rx_mode(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); @@ -1223,7 +1215,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->open = pasemi_mac_open; dev->stop = pasemi_mac_close; dev->hard_start_xmit = pasemi_mac_start_tx; - dev->get_stats = pasemi_mac_get_stats; dev->set_multicast_list = pasemi_mac_set_rx_mode; err = pasemi_mac_map_regs(mac); diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index c5b0adbc182e..c52cfcb6c4ca 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -60,7 +60,6 @@ struct pasemi_mac { struct pci_dev *iob_pdev; struct phy_device *phydev; struct napi_struct napi; - struct net_device_stats stats; /* Pointer to the cacheable per-channel status registers */ u64 *rx_status; diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index a4b16484a5f7..7dace63fb6e6 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -457,7 +457,6 @@ struct netdrv_private { void *mmio_addr; int drv_flags; struct pci_dev *pci_dev; - struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ @@ -505,7 +504,6 @@ static int netdrv_start_xmit (struct sk_buff *skb, static irqreturn_t netdrv_interrupt (int irq, void *dev_instance); static int netdrv_close (struct net_device *dev); static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *netdrv_get_stats (struct net_device *dev); static void netdrv_set_rx_mode (struct net_device *dev); static void netdrv_hw_start (struct net_device *dev); @@ -775,7 +773,6 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, dev->open = netdrv_open; dev->hard_start_xmit = netdrv_start_xmit; dev->stop = netdrv_close; - dev->get_stats = netdrv_get_stats; dev->set_multicast_list = netdrv_set_rx_mode; dev->do_ioctl = netdrv_ioctl; dev->tx_timeout = netdrv_tx_timeout; @@ -1276,7 +1273,7 @@ static void netdrv_tx_clear (struct netdrv_private *tp) if (rp->skb) { dev_kfree_skb (rp->skb); rp->skb = NULL; - tp->stats.tx_dropped++; + dev->stats.tx_dropped++; } } } @@ -1389,25 +1386,25 @@ static void netdrv_tx_interrupt (struct net_device *dev, /* There was an major error, log it. */ DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); - tp->stats.tx_errors++; + dev->stats.tx_errors++; if (txstatus & TxAborted) { - tp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; NETDRV_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); } if (txstatus & TxCarrierLost) - tp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (txstatus & TxOutOfWindow) - tp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } else { if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ if (tp->tx_flag < 0x00300000) tp->tx_flag += 0x00020000; - tp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } - tp->stats.collisions += (txstatus >> 24) & 15; - tp->stats.tx_bytes += txstatus & 0x7ff; - tp->stats.tx_packets++; + dev->stats.collisions += (txstatus >> 24) & 15; + dev->stats.tx_bytes += txstatus & 0x7ff; + dev->stats.tx_packets++; } /* Free the original skb. */ @@ -1460,13 +1457,13 @@ static void netdrv_rx_err (u32 rx_status, struct net_device *dev, dev->name, rx_status); /* A.C.: The chip hangs here. */ } - tp->stats.rx_errors++; + dev->stats.rx_errors++; if (rx_status & (RxBadSymbol | RxBadAlign)) - tp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rx_status & (RxRunt | RxTooLong)) - tp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (rx_status & RxCRCErr) - tp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; /* Reset the receiver, based on RealTek recommendation. (Bug?) */ tp->cur_rx = 0; @@ -1572,13 +1569,13 @@ static void netdrv_rx_interrupt (struct net_device *dev, skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; + dev->stats.rx_bytes += pkt_size; + dev->stats.rx_packets++; } else { printk (KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - tp->stats.rx_dropped++; + dev->stats.rx_dropped++; } cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; @@ -1607,7 +1604,7 @@ static void netdrv_weird_interrupt (struct net_device *dev, assert (ioaddr != NULL); /* Update the error count. */ - tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed); + dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed); NETDRV_W32 (RxMissed, 0); if ((status & RxUnderrun) && link_changed && @@ -1628,14 +1625,14 @@ static void netdrv_weird_interrupt (struct net_device *dev, /* XXX along with netdrv_rx_err, are we double-counting errors? */ if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) - tp->stats.rx_errors++; + dev->stats.rx_errors++; if (status & (PCSTimeout)) - tp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & (RxUnderrun | RxFIFOOver)) - tp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (status & RxOverflow) { - tp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; tp->cur_rx = NETDRV_R16 (RxBufAddr) % RX_BUF_LEN; NETDRV_W16_F (RxBufPtr, tp->cur_rx - 16); } @@ -1739,7 +1736,7 @@ static int netdrv_close (struct net_device *dev) NETDRV_W16 (IntrMask, 0x0000); /* Update the error counts. */ - tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed); + dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed); NETDRV_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); @@ -1806,31 +1803,6 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) return rc; } - -static struct net_device_stats *netdrv_get_stats (struct net_device *dev) -{ - struct netdrv_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - - DPRINTK ("ENTER\n"); - - assert (tp != NULL); - - if (netif_running(dev)) { - unsigned long flags; - - spin_lock_irqsave (&tp->lock, flags); - - tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed); - NETDRV_W32 (RxMissed, 0); - - spin_unlock_irqrestore (&tp->lock, flags); - } - - DPRINTK ("EXIT\n"); - return &tp->stats; -} - /* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */ @@ -1908,7 +1880,7 @@ static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state) NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear)); /* Update the error counts. */ - tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed); + dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed); NETDRV_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 2cfab4b36654..c17d9ac9ff30 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -154,7 +154,6 @@ static int plip_hard_header_cache(struct neighbour *neigh, struct hh_cache *hh); static int plip_open(struct net_device *dev); static int plip_close(struct net_device *dev); -static struct net_device_stats *plip_get_stats(struct net_device *dev); static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int plip_preempt(void *handle); static void plip_wakeup(void *handle); @@ -206,7 +205,6 @@ struct plip_local { }; struct net_local { - struct net_device_stats enet_stats; struct net_device *dev; struct work_struct immediate; struct delayed_work deferred; @@ -285,7 +283,6 @@ plip_init_netdev(struct net_device *dev) dev->hard_start_xmit = plip_tx_packet; dev->open = plip_open; dev->stop = plip_close; - dev->get_stats = plip_get_stats; dev->do_ioctl = plip_ioctl; dev->header_cache_update = NULL; dev->tx_queue_len = 10; @@ -430,8 +427,8 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, dev->name, snd->state, c0); } else error = HS_TIMEOUT; - nl->enet_stats.tx_errors++; - nl->enet_stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; } else if (nl->connection == PLIP_CN_RECEIVE) { if (rcv->state == PLIP_PK_TRIGGER) { /* Transmission was interrupted. */ @@ -448,7 +445,7 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n", dev->name, rcv->state, c0); } - nl->enet_stats.rx_dropped++; + dev->stats.rx_dropped++; } rcv->state = PLIP_PK_DONE; if (rcv->skb) { @@ -661,7 +658,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, &rcv->nibble, &rcv->data)) return TIMEOUT; if (rcv->data != rcv->checksum) { - nl->enet_stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (net_debug) printk(KERN_DEBUG "%s: checksum error\n", dev->name); return ERROR; @@ -673,8 +670,8 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, rcv->skb->protocol=plip_type_trans(rcv->skb, dev); netif_rx(rcv->skb); dev->last_rx = jiffies; - nl->enet_stats.rx_bytes += rcv->length.h; - nl->enet_stats.rx_packets++; + dev->stats.rx_bytes += rcv->length.h; + dev->stats.rx_packets++; rcv->skb = NULL; if (net_debug > 2) printk(KERN_DEBUG "%s: receive end\n", dev->name); @@ -776,7 +773,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, if (nl->connection == PLIP_CN_RECEIVE) { spin_unlock_irq(&nl->lock); /* Interrupted. */ - nl->enet_stats.collisions++; + dev->stats.collisions++; return OK; } c0 = read_status(dev); @@ -792,7 +789,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, {enable,disable}_irq *counts* them. -- AV */ ENABLE(dev->irq); - nl->enet_stats.collisions++; + dev->stats.collisions++; return OK; } disable_parport_interrupts (dev); @@ -840,9 +837,9 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, &snd->nibble, snd->checksum)) return TIMEOUT; - nl->enet_stats.tx_bytes += snd->skb->len; + dev->stats.tx_bytes += snd->skb->len; dev_kfree_skb(snd->skb); - nl->enet_stats.tx_packets++; + dev->stats.tx_packets++; snd->state = PLIP_PK_DONE; case PLIP_PK_DONE: @@ -1199,15 +1196,6 @@ plip_wakeup(void *handle) return; } -static struct net_device_stats * -plip_get_stats(struct net_device *dev) -{ - struct net_local *nl = netdev_priv(dev); - struct net_device_stats *r = &nl->enet_stats; - - return r; -} - static int plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 309199bb7d12..97c6ed07dd15 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2053,7 +2053,7 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) { printk(KERN_ERR "Frame too short to be legal, frame not sent.\n"); - qdev->stats.tx_errors++; + qdev->ndev->stats.tx_errors++; retval = -EIO; goto frame_not_sent; } @@ -2061,7 +2061,7 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, if(tx_cb->seg_count == 0) { printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id); - qdev->stats.tx_errors++; + qdev->ndev->stats.tx_errors++; retval = -EIO; goto invalid_seg_count; } @@ -2080,8 +2080,8 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, PCI_DMA_TODEVICE); } } - qdev->stats.tx_packets++; - qdev->stats.tx_bytes += tx_cb->skb->len; + qdev->ndev->stats.tx_packets++; + qdev->ndev->stats.tx_bytes += tx_cb->skb->len; frame_not_sent: dev_kfree_skb_irq(tx_cb->skb); @@ -2140,8 +2140,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, lrg_buf_cb2 = ql_get_lbuf(qdev); skb = lrg_buf_cb2->skb; - qdev->stats.rx_packets++; - qdev->stats.rx_bytes += length; + qdev->ndev->stats.rx_packets++; + qdev->ndev->stats.rx_bytes += length; skb_put(skb, length); pci_unmap_single(qdev->pdev, @@ -2225,8 +2225,8 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, skb2->protocol = eth_type_trans(skb2, qdev->ndev); netif_receive_skb(skb2); - qdev->stats.rx_packets++; - qdev->stats.rx_bytes += length; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += length; ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; @@ -3753,12 +3753,6 @@ static int ql3xxx_open(struct net_device *ndev) return (ql_adapter_up(qdev)); } -static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev) -{ - struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv; - return &qdev->stats; -} - static void ql3xxx_set_multicast_list(struct net_device *ndev) { /* @@ -4048,7 +4042,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, ndev->open = ql3xxx_open; ndev->hard_start_xmit = ql3xxx_send; ndev->stop = ql3xxx_close; - ndev->get_stats = ql3xxx_get_stats; ndev->set_multicast_list = ql3xxx_set_multicast_list; SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops); ndev->set_mac_address = ql3xxx_set_mac_address; diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index aa2216f0d7b8..483840f7fc10 100755 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -1283,7 +1283,6 @@ struct ql3_adapter { u32 update_ob_opcode; /* Opcode to use for updating NCB */ u32 mb_bit_mask; /* MA Bits mask to use on transmission */ u32 numPorts; - struct net_device_stats stats; struct workqueue_struct *workqueue; struct delayed_work reset_work; struct delayed_work tx_timeout_work; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 25a9dd821aa2..d43dcf3ed5a9 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -53,7 +53,6 @@ struct rionet_private { struct rio_mport *mport; struct sk_buff *rx_skb[RIONET_RX_RING_SIZE]; struct sk_buff *tx_skb[RIONET_TX_RING_SIZE]; - struct net_device_stats stats; int rx_slot; int tx_slot; int tx_cnt; @@ -91,12 +90,6 @@ static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; #define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001) #define RIONET_GET_DESTID(x) (*(u16 *)(x + 4)) -static struct net_device_stats *rionet_stats(struct net_device *ndev) -{ - struct rionet_private *rnet = ndev->priv; - return &rnet->stats; -} - static int rionet_rx_clean(struct net_device *ndev) { int i; @@ -120,15 +113,15 @@ static int rionet_rx_clean(struct net_device *ndev) error = netif_rx(rnet->rx_skb[i]); if (error == NET_RX_DROP) { - rnet->stats.rx_dropped++; + 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); - rnet->stats.rx_errors++; + ndev->stats.rx_errors++; } else { - rnet->stats.rx_packets++; - rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE; } } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot); @@ -163,8 +156,8 @@ static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); rnet->tx_skb[rnet->tx_slot] = skb; - rnet->stats.tx_packets++; - rnet->stats.tx_bytes += skb->len; + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; if (++rnet->tx_cnt == RIONET_TX_RING_SIZE) netif_stop_queue(ndev); @@ -466,7 +459,6 @@ static int rionet_setup_netdev(struct rio_mport *mport) ndev->open = &rionet_open; ndev->hard_start_xmit = &rionet_start_xmit; ndev->stop = &rionet_close; - ndev->get_stats = &rionet_stats; ndev->mtu = RIO_MAX_MSG_SIZE - 14; ndev->features = NETIF_F_LLTX; SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 41f877d482c7..03facba05259 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -126,7 +126,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev, dev->open = &rr_open; dev->hard_start_xmit = &rr_start_xmit; dev->stop = &rr_close; - dev->get_stats = &rr_get_stats; dev->do_ioctl = &rr_ioctl; dev->base_addr = pci_resource_start(pdev, 0); @@ -808,7 +807,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) case E_CON_REJ: printk(KERN_WARNING "%s: Connection rejected\n", dev->name); - rrpriv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; break; case E_CON_TMOUT: printk(KERN_WARNING "%s: Connection timeout\n", @@ -817,7 +816,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) case E_DISC_ERR: printk(KERN_WARNING "%s: HIPPI disconnect error\n", dev->name); - rrpriv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; break; case E_INT_PRTY: printk(KERN_ERR "%s: HIPPI Internal Parity error\n", @@ -833,7 +832,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) case E_TX_LINK_DROP: printk(KERN_WARNING "%s: Link lost during transmit\n", dev->name); - rrpriv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); wmb(); @@ -973,7 +972,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) printk("len %x, mode %x\n", pkt_len, desc->mode); #endif if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){ - rrpriv->stats.rx_dropped++; + dev->stats.rx_dropped++; goto defer; } @@ -986,7 +985,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL){ printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len); - rrpriv->stats.rx_dropped++; + dev->stats.rx_dropped++; goto defer; } else { pci_dma_sync_single_for_cpu(rrpriv->pci_dev, @@ -1024,7 +1023,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) } else { printk("%s: Out of memory, deferring " "packet\n", dev->name); - rrpriv->stats.rx_dropped++; + dev->stats.rx_dropped++; goto defer; } } @@ -1033,8 +1032,8 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) netif_rx(skb); /* send it up */ dev->last_rx = jiffies; - rrpriv->stats.rx_packets++; - rrpriv->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } defer: desc->mode = 0; @@ -1102,8 +1101,8 @@ static irqreturn_t rr_interrupt(int irq, void *dev_id) desc = &(rrpriv->tx_ring[txcon]); skb = rrpriv->tx_skbuff[txcon]; - rrpriv->stats.tx_packets++; - rrpriv->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, skb->len, @@ -1491,16 +1490,6 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) } -static struct net_device_stats *rr_get_stats(struct net_device *dev) -{ - struct rr_private *rrpriv; - - rrpriv = netdev_priv(dev); - - return(&rrpriv->stats); -} - - /* * Read the firmware out of the EEPROM and put it into the SRAM * (or from user space - later) diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h index 9f3e050c4dc6..6a79825bc8cf 100644 --- a/drivers/net/rrunner.h +++ b/drivers/net/rrunner.h @@ -819,7 +819,6 @@ struct rr_private u32 tx_full; u32 fw_rev; volatile short fw_running; - struct net_device_stats stats; struct pci_dev *pci_dev; }; @@ -834,7 +833,6 @@ 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 int rr_close(struct net_device *dev); -static struct net_device_stats *rr_get_stats(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, unsigned long offset, diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index 7dae4d404978..14361e885415 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c @@ -151,30 +151,30 @@ static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp) printk("lp->lan_saa9730_regs->CamData = %x\n", readl(&lp->lan_saa9730_regs->CamData)); } - printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets); - printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors); - printk("lp->stats.tx_aborted_errors = %lx\n", - lp->stats.tx_aborted_errors); - printk("lp->stats.tx_window_errors = %lx\n", - lp->stats.tx_window_errors); - printk("lp->stats.tx_carrier_errors = %lx\n", - lp->stats.tx_carrier_errors); - printk("lp->stats.tx_fifo_errors = %lx\n", - lp->stats.tx_fifo_errors); - printk("lp->stats.tx_heartbeat_errors = %lx\n", - lp->stats.tx_heartbeat_errors); - printk("lp->stats.collisions = %lx\n", lp->stats.collisions); + printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets); + printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors); + printk("dev->stats.tx_aborted_errors = %lx\n", + dev->stats.tx_aborted_errors); + printk("dev->stats.tx_window_errors = %lx\n", + dev->stats.tx_window_errors); + printk("dev->stats.tx_carrier_errors = %lx\n", + dev->stats.tx_carrier_errors); + printk("dev->stats.tx_fifo_errors = %lx\n", + dev->stats.tx_fifo_errors); + printk("dev->stats.tx_heartbeat_errors = %lx\n", + dev->stats.tx_heartbeat_errors); + printk("dev->stats.collisions = %lx\n", dev->stats.collisions); - printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets); - printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors); - printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped); - printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors); - printk("lp->stats.rx_frame_errors = %lx\n", - lp->stats.rx_frame_errors); - printk("lp->stats.rx_fifo_errors = %lx\n", - lp->stats.rx_fifo_errors); - printk("lp->stats.rx_length_errors = %lx\n", - lp->stats.rx_length_errors); + printk("dev->stats.rx_packets = %lx\n", dev->stats.rx_packets); + printk("dev->stats.rx_errors = %lx\n", dev->stats.rx_errors); + printk("dev->stats.rx_dropped = %lx\n", dev->stats.rx_dropped); + printk("dev->stats.rx_crc_errors = %lx\n", dev->stats.rx_crc_errors); + printk("dev->stats.rx_frame_errors = %lx\n", + dev->stats.rx_frame_errors); + printk("dev->stats.rx_fifo_errors = %lx\n", + dev->stats.rx_fifo_errors); + printk("dev->stats.rx_length_errors = %lx\n", + dev->stats.rx_length_errors); printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n", readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr)); @@ -605,24 +605,24 @@ static int lan_saa9730_tx(struct net_device *dev) printk("lan_saa9730_tx: tx error = %x\n", tx_status); - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (tx_status & (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (tx_status & (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tx_status & (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (tx_status & (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; - lp->stats.collisions += + dev->stats.collisions += tx_status & TX_STATUS_TX_COLL_MSK; } @@ -684,10 +684,10 @@ static int lan_saa9730_rx(struct net_device *dev) printk ("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { - lp->stats.rx_bytes += len; - lp->stats.rx_packets++; + dev->stats.rx_bytes += len; + dev->stats.rx_packets++; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ skb_copy_to_linear_data(skb, @@ -704,19 +704,19 @@ static int lan_saa9730_rx(struct net_device *dev) ("lan_saa9730_rx: We got an error packet = %x\n", rx_status); - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (rx_status & (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rx_status & (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF)) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rx_status & (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (rx_status & (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } /* Indicate we have processed the buffer. */ @@ -853,7 +853,7 @@ static void lan_saa9730_tx_timeout(struct net_device *dev) struct lan_saa9730_private *lp = netdev_priv(dev); /* Transmitter timeout, serious problems */ - lp->stats.tx_errors++; + dev->stats.tx_errors++; printk("%s: transmit timed out, reset\n", dev->name); /*show_saa9730_regs(lp); */ lan_saa9730_restart(lp); @@ -886,8 +886,8 @@ static int lan_saa9730_start_xmit(struct sk_buff *skb, return -1; } - lp->stats.tx_bytes += len; - lp->stats.tx_packets++; + dev->stats.tx_bytes += len; + dev->stats.tx_packets++; dev->trans_start = jiffies; netif_wake_queue(dev); @@ -919,14 +919,6 @@ static int lan_saa9730_close(struct net_device *dev) return 0; } -static struct net_device_stats *lan_saa9730_get_stats(struct net_device - *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - - return &lp->stats; -} - static void lan_saa9730_set_multicast(struct net_device *dev) { struct lan_saa9730_private *lp = netdev_priv(dev); @@ -1040,7 +1032,6 @@ static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev, dev->open = lan_saa9730_open; dev->hard_start_xmit = lan_saa9730_start_xmit; dev->stop = lan_saa9730_close; - dev->get_stats = lan_saa9730_get_stats; dev->set_multicast_list = lan_saa9730_set_multicast; dev->tx_timeout = lan_saa9730_tx_timeout; dev->watchdog_timeo = (HZ >> 1); diff --git a/drivers/net/saa9730.h b/drivers/net/saa9730.h index f656f2f40bb8..010a120ea938 100644 --- a/drivers/net/saa9730.h +++ b/drivers/net/saa9730.h @@ -378,7 +378,6 @@ struct lan_saa9730_private { unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6]; - struct net_device_stats stats; spinlock_t lock; }; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index aeaa75f549e6..487f9d2ac5b4 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -76,7 +76,6 @@ struct sb1000_private { unsigned char rx_session_id[NPIDS]; unsigned char rx_frame_id[NPIDS]; unsigned char rx_pkt_type[NPIDS]; - struct net_device_stats stats; }; /* prototypes for Linux interface */ @@ -85,7 +84,6 @@ 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 irqreturn_t sb1000_interrupt(int irq, void *dev_id); -static struct net_device_stats *sb1000_stats(struct net_device *dev); static int sb1000_close(struct net_device *dev); @@ -199,7 +197,6 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id) dev->do_ioctl = sb1000_dev_ioctl; dev->hard_start_xmit = sb1000_start_xmit; dev->stop = sb1000_close; - dev->get_stats = sb1000_stats; /* hardware address is 0:0:serial_number */ dev->dev_addr[2] = serial_number >> 24 & 0xff; @@ -739,7 +736,7 @@ sb1000_rx(struct net_device *dev) unsigned int skbsize; struct sk_buff *skb; struct sb1000_private *lp = netdev_priv(dev); - struct net_device_stats *stats = &lp->stats; + struct net_device_stats *stats = &dev->stats; /* SB1000 frame constants */ const int FrameSize = FRAMESIZE; @@ -1002,11 +999,11 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGCMSTATS: /* get statistics */ - stats[0] = lp->stats.rx_bytes; + stats[0] = dev->stats.rx_bytes; stats[1] = lp->rx_frames; - stats[2] = lp->stats.rx_packets; - stats[3] = lp->stats.rx_errors; - stats[4] = lp->stats.rx_dropped; + stats[2] = dev->stats.rx_packets; + stats[3] = dev->stats.rx_errors; + stats[4] = dev->stats.rx_dropped; if(copy_to_user(ifr->ifr_data, stats, sizeof(stats))) return -EFAULT; status = 0; @@ -1132,12 +1129,6 @@ static irqreturn_t sb1000_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct net_device_stats *sb1000_stats(struct net_device *dev) -{ - struct sb1000_private *lp = netdev_priv(dev); - return &lp->stats; -} - static int sb1000_close(struct net_device *dev) { int i; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index b6cafac97200..76e7ee9a6cbc 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -241,7 +241,6 @@ struct sbmac_softc { struct napi_struct napi; spinlock_t sbm_lock; /* spin lock */ struct timer_list sbm_timer; /* for monitoring MII */ - struct net_device_stats sbm_stats; int sbm_devflags; /* current device flags */ int sbm_phy_oldbmsr; @@ -317,7 +316,6 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc static int sbmac_open(struct net_device *dev); static void sbmac_timer(unsigned long data); static void sbmac_tx_timeout (struct net_device *dev); -static struct net_device_stats *sbmac_get_stats(struct net_device *dev); static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); @@ -1190,6 +1188,7 @@ static void sbmac_netpoll(struct net_device *netdev) static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll) { + struct net_device *dev = sc->sbm_dev; int curidx; int hwidx; sbdmadscr_t *dsc; @@ -1202,7 +1201,7 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, again: /* Check if the HW dropped any frames */ - sc->sbm_stats.rx_fifo_errors + dev->stats.rx_fifo_errors += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff; __raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost); @@ -1261,7 +1260,7 @@ again: if (unlikely (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS)) { - sc->sbm_stats.rx_dropped++; + dev->stats.rx_dropped++; sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ /* No point in continuing at the moment */ printk(KERN_ERR "dropped packet (1)\n"); @@ -1297,13 +1296,13 @@ again: dropped = netif_rx(sb); if (dropped == NET_RX_DROP) { - sc->sbm_stats.rx_dropped++; + dev->stats.rx_dropped++; d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); goto done; } else { - sc->sbm_stats.rx_bytes += len; - sc->sbm_stats.rx_packets++; + dev->stats.rx_bytes += len; + dev->stats.rx_packets++; } } } else { @@ -1311,7 +1310,7 @@ again: * Packet was mangled somehow. Just drop it and * put it back on the receive ring. */ - sc->sbm_stats.rx_errors++; + dev->stats.rx_errors++; sbdma_add_rcvbuffer(d,sb); } @@ -1351,6 +1350,7 @@ done: static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) { + struct net_device *dev = sc->sbm_dev; int curidx; int hwidx; sbdmadscr_t *dsc; @@ -1401,8 +1401,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) * Stats */ - sc->sbm_stats.tx_bytes += sb->len; - sc->sbm_stats.tx_packets++; + dev->stats.tx_bytes += sb->len; + dev->stats.tx_packets++; /* * for transmits, we just free buffers. @@ -2457,7 +2457,6 @@ static int sbmac_init(struct net_device *dev, int idx) dev->open = sbmac_open; dev->hard_start_xmit = sbmac_start_tx; dev->stop = sbmac_close; - dev->get_stats = sbmac_get_stats; dev->set_multicast_list = sbmac_set_rx_mode; dev->do_ioctl = sbmac_mii_ioctl; dev->tx_timeout = sbmac_tx_timeout; @@ -2748,7 +2747,7 @@ static void sbmac_tx_timeout (struct net_device *dev) dev->trans_start = jiffies; - sc->sbm_stats.tx_errors++; + dev->stats.tx_errors++; spin_unlock_irq (&sc->sbm_lock); @@ -2758,22 +2757,6 @@ static void sbmac_tx_timeout (struct net_device *dev) -static struct net_device_stats *sbmac_get_stats(struct net_device *dev) -{ - struct sbmac_softc *sc = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&sc->sbm_lock, flags); - - /* XXX update other stats here */ - - spin_unlock_irqrestore(&sc->sbm_lock, flags); - - return &sc->sbm_stats; -} - - - static void sbmac_set_rx_mode(struct net_device *dev) { unsigned long flags; diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 4bce7c4f373c..8ef94028cba5 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -67,7 +67,6 @@ static unsigned int net_debug = NET_DEBUG; /* Information that need to be kept for each board. */ struct net_local { - struct net_device_stats stats; unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */ long open_time; /* Useless example local info. */ }; @@ -86,7 +85,6 @@ static int 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); -static struct net_device_stats *seeq8005_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); /* Example routines you must write ;->. */ @@ -338,7 +336,6 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) dev->hard_start_xmit = seeq8005_send_packet; dev->tx_timeout = seeq8005_timeout; dev->watchdog_timeo = HZ/20; - dev->get_stats = seeq8005_get_stats; dev->set_multicast_list = set_multicast_list; dev->flags &= ~IFF_MULTICAST; @@ -391,7 +388,6 @@ static void seeq8005_timeout(struct net_device *dev) static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); short length = skb->len; unsigned char *buf; @@ -407,7 +403,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; - lp->stats.tx_bytes += length; + dev->stats.tx_bytes += length; dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ @@ -463,7 +459,7 @@ static irqreturn_t seeq8005_interrupt(int irq, void *dev_id) if (status & SEEQSTAT_TX_INT) { handled = 1; outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); - lp->stats.tx_packets++; + dev->stats.tx_packets++; netif_wake_queue(dev); /* Inform upper layers. */ } if (status & SEEQSTAT_RX_INT) { @@ -531,11 +527,11 @@ static void seeq8005_rx(struct net_device *dev) } if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */ - lp->stats.rx_errors++; - if (pkt_hdr & SEEQPKTS_SHORT) lp->stats.rx_frame_errors++; - if (pkt_hdr & SEEQPKTS_DRIB) lp->stats.rx_frame_errors++; - if (pkt_hdr & SEEQPKTS_OVERSIZE) lp->stats.rx_over_errors++; - if (pkt_hdr & SEEQPKTS_CRC_ERR) lp->stats.rx_crc_errors++; + dev->stats.rx_errors++; + if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++; + if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++; + if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++; + if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++; /* skip over this packet */ outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA); @@ -547,7 +543,7 @@ static void seeq8005_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } skb_reserve(skb, 2); /* align data on 16 byte */ @@ -567,8 +563,8 @@ static void seeq8005_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN)); @@ -599,15 +595,6 @@ static int seeq8005_close(struct net_device *dev) } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *seeq8005_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - return &lp->stats; -} - /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index eb67b024e413..5189ef066884 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -93,8 +93,6 @@ struct sgiseeq_private { unsigned char control; unsigned char mode; - struct net_device_stats stats; - spinlock_t tx_lock; }; @@ -267,18 +265,17 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, return 0; } -static inline void record_rx_errors(struct sgiseeq_private *sp, - unsigned char status) +static void record_rx_errors(struct net_device *dev, unsigned char status) { if (status & SEEQ_RSTAT_OVERF || status & SEEQ_RSTAT_SFRAME) - sp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (status & SEEQ_RSTAT_CERROR) - sp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (status & SEEQ_RSTAT_DERROR) - sp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & SEEQ_RSTAT_REOF) - sp->stats.rx_errors++; + dev->stats.rx_errors++; } static inline void rx_maybe_restart(struct sgiseeq_private *sp, @@ -328,8 +325,8 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) { netif_rx(skb); dev->last_rx = jiffies; - sp->stats.rx_packets++; - sp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } else { /* Silently drop my own packets */ dev_kfree_skb_irq(skb); @@ -337,10 +334,10 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp } else { printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", dev->name); - sp->stats.rx_dropped++; + dev->stats.rx_dropped++; } } else { - record_rx_errors(sp, pkt_status); + record_rx_errors(dev, pkt_status); } /* Return the entry to the ring pool. */ @@ -392,11 +389,11 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) { /* Oops, HPC detected some sort of error. */ if (status & SEEQ_TSTAT_R16) - sp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (status & SEEQ_TSTAT_UFLOW) - sp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & SEEQ_TSTAT_LCLS) - sp->stats.collisions++; + dev->stats.collisions++; } /* Ack 'em... */ @@ -412,7 +409,7 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp } break; } - sp->stats.tx_packets++; + dev->stats.tx_packets++; sp->tx_old = NEXT_TX(sp->tx_old); td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE); td->tdma.cntinfo |= HPCDMA_EOX; @@ -516,7 +513,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Setup... */ skblen = skb->len; len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; - sp->stats.tx_bytes += len; + dev->stats.tx_bytes += len; entry = sp->tx_new; td = &sp->tx_desc[entry]; @@ -569,13 +566,6 @@ static void timeout(struct net_device *dev) netif_wake_queue(dev); } -static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev) -{ - struct sgiseeq_private *sp = netdev_priv(dev); - - return &sp->stats; -} - static void sgiseeq_set_multicast(struct net_device *dev) { struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; @@ -694,7 +684,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev) dev->hard_start_xmit = sgiseeq_start_xmit; dev->tx_timeout = timeout; dev->watchdog_timeo = (200 * HZ) / 1000; - dev->get_stats = sgiseeq_get_stats; dev->set_multicast_list = sgiseeq_set_multicast; dev->set_mac_address = sgiseeq_set_mac_address; dev->irq = irq; diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index b56721a68a85..315feba7dacc 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -171,7 +171,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) */ if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) { dev_kfree_skb(skb); - shaper->stats.tx_dropped++; + dev->stats.tx_dropped++; } else skb_queue_tail(&shaper->sendq, skb); } @@ -182,7 +182,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) { ptr=skb_dequeue(&shaper->sendq); dev_kfree_skb(ptr); - shaper->stats.collisions++; + dev->stats.collisions++; } shaper_kick(shaper); spin_unlock(&shaper->lock); @@ -207,8 +207,8 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb) shaper->dev->name,newskb->priority); dev_queue_xmit(newskb); - shaper->stats.tx_bytes += skb->len; - shaper->stats.tx_packets++; + shaper->dev->stats.tx_bytes += skb->len; + shaper->dev->stats.tx_packets++; if(sh_debug) printk("Kicked new frame out.\n"); @@ -330,12 +330,6 @@ static int shaper_close(struct net_device *dev) * ARP and other resolutions and not before. */ -static struct net_device_stats *shaper_get_stats(struct net_device *dev) -{ - struct shaper *sh=dev->priv; - return &sh->stats; -} - static int shaper_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { @@ -538,7 +532,6 @@ static void __init shaper_setup(struct net_device *dev) dev->open = shaper_open; dev->stop = shaper_close; dev->hard_start_xmit = shaper_start_xmit; - dev->get_stats = shaper_get_stats; dev->set_multicast_list = NULL; /* diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index e810ae942cd6..808141b46585 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -270,7 +270,6 @@ struct sis190_private { void __iomem *mmio_addr; struct pci_dev *pci_dev; struct net_device *dev; - struct net_device_stats stats; spinlock_t lock; u32 rx_buf_sz; u32 cur_rx; @@ -569,7 +568,7 @@ static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats) static int sis190_rx_interrupt(struct net_device *dev, struct sis190_private *tp, void __iomem *ioaddr) { - struct net_device_stats *stats = &tp->stats; + struct net_device_stats *stats = &dev->stats; u32 rx_left, cur_rx = tp->cur_rx; u32 delta, count; @@ -683,8 +682,8 @@ static void sis190_tx_interrupt(struct net_device *dev, skb = tp->Tx_skbuff[entry]; - tp->stats.tx_packets++; - tp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; sis190_unmap_tx_skb(tp->pci_dev, skb, txd); tp->Tx_skbuff[entry] = NULL; @@ -1080,7 +1079,7 @@ static void sis190_tx_clear(struct sis190_private *tp) tp->Tx_skbuff[i] = NULL; dev_kfree_skb(skb); - tp->stats.tx_dropped++; + tp->dev->stats.tx_dropped++; } tp->cur_tx = tp->dirty_tx = 0; } @@ -1143,7 +1142,7 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len < ETH_ZLEN)) { if (skb_padto(skb, ETH_ZLEN)) { - tp->stats.tx_dropped++; + dev->stats.tx_dropped++; goto out; } len = ETH_ZLEN; @@ -1196,13 +1195,6 @@ out: return NETDEV_TX_OK; } -static struct net_device_stats *sis190_get_stats(struct net_device *dev) -{ - struct sis190_private *tp = netdev_priv(dev); - - return &tp->stats; -} - static void sis190_free_phy(struct list_head *first_phy) { struct sis190_phy *cur, *next; @@ -1795,7 +1787,6 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, dev->open = sis190_open; dev->stop = sis190_close; dev->do_ioctl = sis190_ioctl; - dev->get_stats = sis190_get_stats; dev->tx_timeout = sis190_tx_timeout; dev->watchdog_timeo = SIS190_TX_TIMEOUT; dev->hard_start_xmit = sis190_start_xmit; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index e1930c3ee75d..5da8e671324d 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -158,7 +158,6 @@ typedef struct _BufferDesc { } BufferDesc; struct sis900_private { - struct net_device_stats stats; struct pci_dev * pci_dev; spinlock_t lock; @@ -221,7 +220,6 @@ static void sis900_finish_xmit (struct net_device *net_dev); static irqreturn_t sis900_interrupt(int irq, void *dev_instance); static int sis900_close(struct net_device *net_dev); static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd); -static struct net_device_stats *sis900_get_stats(struct net_device *net_dev); static u16 sis900_mcast_bitnr(u8 *addr, u8 revision); static void set_rx_mode(struct net_device *net_dev); static void sis900_reset(struct net_device *net_dev); @@ -466,7 +464,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, net_dev->open = &sis900_open; net_dev->hard_start_xmit = &sis900_start_xmit; net_dev->stop = &sis900_close; - net_dev->get_stats = &sis900_get_stats; net_dev->set_config = &sis900_set_config; net_dev->set_multicast_list = &set_rx_mode; net_dev->do_ioctl = &mii_ioctl; @@ -1542,7 +1539,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) sis_priv->tx_skbuff[i] = NULL; sis_priv->tx_ring[i].cmdsts = 0; sis_priv->tx_ring[i].bufptr = 0; - sis_priv->stats.tx_dropped++; + net_dev->stats.tx_dropped++; } } sis_priv->tx_full = 0; @@ -1739,15 +1736,15 @@ static int sis900_rx(struct net_device *net_dev) printk(KERN_DEBUG "%s: Corrupted packet " "received, buffer status = 0x%8.8x/%d.\n", net_dev->name, rx_status, data_size); - sis_priv->stats.rx_errors++; + net_dev->stats.rx_errors++; if (rx_status & OVERRUN) - sis_priv->stats.rx_over_errors++; + net_dev->stats.rx_over_errors++; if (rx_status & (TOOLONG|RUNT)) - sis_priv->stats.rx_length_errors++; + net_dev->stats.rx_length_errors++; if (rx_status & (RXISERR | FAERR)) - sis_priv->stats.rx_frame_errors++; + net_dev->stats.rx_frame_errors++; if (rx_status & CRCERR) - sis_priv->stats.rx_crc_errors++; + net_dev->stats.rx_crc_errors++; /* reset buffer descriptor state */ sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; } else { @@ -1768,7 +1765,7 @@ static int sis900_rx(struct net_device *net_dev) * in the rx ring */ skb = sis_priv->rx_skbuff[entry]; - sis_priv->stats.rx_dropped++; + net_dev->stats.rx_dropped++; goto refill_rx_ring; } @@ -1793,10 +1790,10 @@ static int sis900_rx(struct net_device *net_dev) /* some network statistics */ if ((rx_status & BCAST) == MCAST) - sis_priv->stats.multicast++; + net_dev->stats.multicast++; net_dev->last_rx = jiffies; - sis_priv->stats.rx_bytes += rx_size; - sis_priv->stats.rx_packets++; + net_dev->stats.rx_bytes += rx_size; + net_dev->stats.rx_packets++; sis_priv->dirty_rx++; refill_rx_ring: sis_priv->rx_skbuff[entry] = skb; @@ -1827,7 +1824,7 @@ refill_rx_ring: printk(KERN_INFO "%s: Memory squeeze," "deferring packet.\n", net_dev->name); - sis_priv->stats.rx_dropped++; + net_dev->stats.rx_dropped++; break; } sis_priv->rx_skbuff[entry] = skb; @@ -1878,20 +1875,20 @@ static void sis900_finish_xmit (struct net_device *net_dev) printk(KERN_DEBUG "%s: Transmit " "error, Tx status %8.8x.\n", net_dev->name, tx_status); - sis_priv->stats.tx_errors++; + net_dev->stats.tx_errors++; if (tx_status & UNDERRUN) - sis_priv->stats.tx_fifo_errors++; + net_dev->stats.tx_fifo_errors++; if (tx_status & ABORT) - sis_priv->stats.tx_aborted_errors++; + net_dev->stats.tx_aborted_errors++; if (tx_status & NOCARRIER) - sis_priv->stats.tx_carrier_errors++; + net_dev->stats.tx_carrier_errors++; if (tx_status & OWCOLL) - sis_priv->stats.tx_window_errors++; + net_dev->stats.tx_window_errors++; } else { /* packet successfully transmitted */ - sis_priv->stats.collisions += (tx_status & COLCNT) >> 16; - sis_priv->stats.tx_bytes += tx_status & DSIZE; - sis_priv->stats.tx_packets++; + net_dev->stats.collisions += (tx_status & COLCNT) >> 16; + net_dev->stats.tx_bytes += tx_status & DSIZE; + net_dev->stats.tx_packets++; } /* Free the original skb. */ skb = sis_priv->tx_skbuff[entry]; @@ -2137,21 +2134,6 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) } } -/** - * sis900_get_stats - Get sis900 read/write statistics - * @net_dev: the net device to get statistics for - * - * get tx/rx statistics for sis900 - */ - -static struct net_device_stats * -sis900_get_stats(struct net_device *net_dev) -{ - struct sis900_private *sis_priv = net_dev->priv; - - return &sis_priv->stats; -} - /** * sis900_set_config - Set media type by net_device.set_config * @dev: the net device for media type change diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 5f03e44ad135..c0276c04dece 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -115,13 +115,6 @@ struct smc911x_local { */ struct sk_buff *pending_tx_skb; - /* - * these are things that the kernel wants me to keep, so users - * can find out semi-useless statistics of how well the card is - * performing - */ - struct net_device_stats stats; - /* version/revision of the SMC911x chip */ u16 version; u16 revision; @@ -315,8 +308,8 @@ static void smc911x_reset(struct net_device *dev) if (lp->pending_tx_skb != NULL) { dev_kfree_skb (lp->pending_tx_skb); lp->pending_tx_skb = NULL; - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; } } @@ -449,14 +442,14 @@ static inline void smc911x_rcv(struct net_device *dev) pkt_len = (status & RX_STS_PKT_LEN_) >> 16; if (status & RX_STS_ES_) { /* Deal with a bad packet */ - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (status & RX_STS_CRC_ERR_) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; else { if (status & RX_STS_LEN_ERR_) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & RX_STS_MCAST_) - lp->stats.multicast++; + dev->stats.multicast++; } /* Remove the bad packet data from the RX FIFO */ smc911x_drop_pkt(dev); @@ -467,7 +460,7 @@ static inline void smc911x_rcv(struct net_device *dev) if (unlikely(skb == NULL)) { PRINTK( "%s: Low memory, rcvd packet dropped.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; smc911x_drop_pkt(dev); return; } @@ -503,8 +496,8 @@ static inline void smc911x_rcv(struct net_device *dev) dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len-4; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len-4; #endif } } @@ -616,8 +609,8 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("%s: No Tx free space %d < %d\n", dev->name, free, skb->len); lp->pending_tx_skb = NULL; - lp->stats.tx_errors++; - lp->stats.tx_dropped++; + dev->stats.tx_errors++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -667,8 +660,8 @@ static void smc911x_tx(struct net_device *dev) dev->name, (SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16); tx_status = SMC_GET_TX_STS_FIFO(); - lp->stats.tx_packets++; - lp->stats.tx_bytes+=tx_status>>16; + dev->stats.tx_packets++; + dev->stats.tx_bytes+=tx_status>>16; DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n", dev->name, (tx_status & 0xffff0000) >> 16, tx_status & 0x0000ffff); @@ -676,22 +669,22 @@ static void smc911x_tx(struct net_device *dev) * full-duplex mode */ if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx && !(tx_status & 0x00000306))) { - lp->stats.tx_errors++; + dev->stats.tx_errors++; } if (tx_status & TX_STS_MANY_COLL_) { - lp->stats.collisions+=16; - lp->stats.tx_aborted_errors++; + dev->stats.collisions+=16; + dev->stats.tx_aborted_errors++; } else { - lp->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3; + dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3; } /* carrier error only has meaning for half-duplex communication */ if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) && !lp->ctl_rfduplx) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; } if (tx_status & TX_STS_LATE_COLL_) { - lp->stats.collisions++; - lp->stats.tx_aborted_errors++; + dev->stats.collisions++; + dev->stats.tx_aborted_errors++; } } } @@ -1121,11 +1114,11 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) /* Handle various error conditions */ if (status & INT_STS_RXE_) { SMC_ACK_INT(INT_STS_RXE_); - lp->stats.rx_errors++; + dev->stats.rx_errors++; } if (status & INT_STS_RXDFH_INT_) { SMC_ACK_INT(INT_STS_RXDFH_INT_); - lp->stats.rx_dropped+=SMC_GET_RX_DROP(); + dev->stats.rx_dropped+=SMC_GET_RX_DROP(); } /* Undocumented interrupt-what is the right thing to do here? */ if (status & INT_STS_RXDF_INT_) { @@ -1140,8 +1133,8 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) cr &= ~MAC_CR_RXEN_; SMC_SET_MAC_CR(cr); DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name); - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; } SMC_ACK_INT(INT_STS_RDFL_); } @@ -1152,8 +1145,8 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) SMC_SET_MAC_CR(cr); rx_overrun=1; DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name); - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; } SMC_ACK_INT(INT_STS_RDFO_); } @@ -1307,8 +1300,8 @@ smc911x_rx_dma_irq(int dma, void *data) dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; spin_lock_irqsave(&lp->lock, flags); pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16; @@ -1567,19 +1560,6 @@ static int smc911x_close(struct net_device *dev) return 0; } -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats *smc911x_query_statistics(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); - - - return &lp->stats; -} - /* * Ethtool support */ @@ -2056,7 +2036,6 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) dev->hard_start_xmit = smc911x_hard_start_xmit; dev->tx_timeout = smc911x_timeout; dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->get_stats = smc911x_query_statistics; dev->set_multicast_list = smc911x_set_multicast_list; dev->ethtool_ops = &smc911x_ethtool_ops; #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 0a79516d196e..5b6748e3ea0e 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -190,13 +190,6 @@ static struct devlist smc_devlist[] __initdata = { /* store this information for the driver.. */ struct smc_local { - /* - these are things that the kernel wants me to keep, so users - can find out semi-useless statistics of how well the card is - performing - */ - struct net_device_stats stats; - /* If I have to wait until memory is available to send a packet, I will store the skbuff here, until I get the @@ -248,12 +241,6 @@ static void smc_timeout(struct net_device *dev); */ static int smc_close(struct net_device *dev); -/* - . This routine allows the proc file system to query the driver's - . statistics. -*/ -static struct net_device_stats * smc_query_statistics( struct net_device *dev); - /* . Finally, a call to set promiscuous mode ( for TCPDUMP and related . programs ) and multicast modes. @@ -514,7 +501,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de if ( lp->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); return 1; } @@ -1065,7 +1052,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) dev->hard_start_xmit = smc_wait_to_send_packet; dev->tx_timeout = smc_timeout; dev->watchdog_timeo = HZ/20; - dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; return 0; @@ -1199,7 +1185,6 @@ static void smc_timeout(struct net_device *dev) */ static void smc_rcv(struct net_device *dev) { - struct smc_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int packet_number; word status; @@ -1243,13 +1228,13 @@ static void smc_rcv(struct net_device *dev) /* set multicast stats */ if ( status & RS_MULTICAST ) - lp->stats.multicast++; + dev->stats.multicast++; skb = dev_alloc_skb( packet_length + 5); if ( skb == NULL ) { printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n"); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; goto done; } @@ -1289,16 +1274,16 @@ static void smc_rcv(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev ); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += packet_length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += packet_length; } else { /* error ... */ - lp->stats.rx_errors++; + dev->stats.rx_errors++; - if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++; + if ( status & RS_ALGNERR ) dev->stats.rx_frame_errors++; if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) - lp->stats.rx_length_errors++; - if ( status & RS_BADCRC) lp->stats.rx_crc_errors++; + dev->stats.rx_length_errors++; + if ( status & RS_BADCRC) dev->stats.rx_crc_errors++; } done: @@ -1346,12 +1331,12 @@ static void smc_tx( struct net_device * dev ) tx_status = inw( ioaddr + DATA_1 ); PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status )); - lp->stats.tx_errors++; - if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++; + dev->stats.tx_errors++; + if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++; if ( tx_status & TS_LATCOL ) { printk(KERN_DEBUG CARDNAME ": Late collision occurred on last xmit.\n"); - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } #if 0 if ( tx_status & TS_16COL ) { ... } @@ -1446,10 +1431,10 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id) SMC_SELECT_BANK( 0 ); card_stats = inw( ioaddr + COUNTER ); /* single collisions */ - lp->stats.collisions += card_stats & 0xF; + dev->stats.collisions += card_stats & 0xF; card_stats >>= 4; /* multiple collisions */ - lp->stats.collisions += card_stats & 0xF; + dev->stats.collisions += card_stats & 0xF; /* these are for when linux supports these statistics */ @@ -1458,7 +1443,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id) ": TX_BUFFER_EMPTY handled\n")); outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); mask &= ~IM_TX_EMPTY_INT; - lp->stats.tx_packets += lp->packets_waiting; + dev->stats.tx_packets += lp->packets_waiting; lp->packets_waiting = 0; } else if (status & IM_ALLOC_INT ) { @@ -1477,8 +1462,8 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id) PRINTK2((CARDNAME": Handoff done successfully.\n")); } else if (status & IM_RX_OVRN_INT ) { - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); } else if (status & IM_EPH_INT ) { PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n")); @@ -1521,16 +1506,6 @@ static int smc_close(struct net_device *dev) return 0; } -/*------------------------------------------------------------ - . Get the current statistics. - . This may be called with the card open or closed. - .-------------------------------------------------------------*/ -static struct net_device_stats* smc_query_statistics(struct net_device *dev) { - struct smc_local *lp = netdev_priv(dev); - - return &lp->stats; -} - /*----------------------------------------------------------- . smc_set_multicast_list . diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index c5837ab5c96b..fe28d277f21a 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -183,13 +183,6 @@ struct smc_local { struct sk_buff *pending_tx_skb; struct tasklet_struct tx_task; - /* - * these are things that the kernel wants me to keep, so users - * can find out semi-useless statistics of how well the card is - * performing - */ - struct net_device_stats stats; - /* version/revision of the SMC91x chip */ int version; @@ -332,8 +325,8 @@ static void smc_reset(struct net_device *dev) /* free any pending tx skb */ if (pending_skb) { dev_kfree_skb(pending_skb); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; } /* @@ -512,13 +505,13 @@ static inline void smc_rcv(struct net_device *dev) } SMC_WAIT_MMU_BUSY(); SMC_SET_MMU_CMD(MC_RELEASE); - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (status & RS_ALGNERR) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & (RS_TOOSHORT | RS_TOOLONG)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & RS_BADCRC) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } else { struct sk_buff *skb; unsigned char *data; @@ -526,7 +519,7 @@ static inline void smc_rcv(struct net_device *dev) /* set multicast stats */ if (status & RS_MULTICAST) - lp->stats.multicast++; + dev->stats.multicast++; /* * Actual payload is packet_len - 6 (or 5 if odd byte). @@ -542,7 +535,7 @@ static inline void smc_rcv(struct net_device *dev) dev->name); SMC_WAIT_MMU_BUSY(); SMC_SET_MMU_CMD(MC_RELEASE); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -570,8 +563,8 @@ static inline void smc_rcv(struct net_device *dev) dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += data_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += data_len; } } @@ -644,8 +637,8 @@ static void smc_hardware_send_pkt(unsigned long data) packet_no = SMC_GET_AR(); if (unlikely(packet_no & AR_FAILED)) { printk("%s: Memory allocation failed.\n", dev->name); - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; + dev->stats.tx_errors++; + dev->stats.tx_fifo_errors++; smc_special_unlock(&lp->lock); goto done; } @@ -688,8 +681,8 @@ static void smc_hardware_send_pkt(unsigned long data) smc_special_unlock(&lp->lock); dev->trans_start = jiffies; - lp->stats.tx_packets++; - lp->stats.tx_bytes += len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += len; SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT); @@ -729,8 +722,8 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) numPages = ((skb->len & ~1) + (6 - 1)) >> 8; if (unlikely(numPages > 7)) { printk("%s: Far too big packet error.\n", dev->name); - lp->stats.tx_errors++; - lp->stats.tx_dropped++; + dev->stats.tx_errors++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -803,17 +796,17 @@ static void smc_tx(struct net_device *dev) dev->name, tx_status, packet_no); if (!(tx_status & ES_TX_SUC)) - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & ES_LOSTCARR) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tx_status & (ES_LATCOL | ES_16COL)) { PRINTK("%s: %s occurred on last xmit\n", dev->name, (tx_status & ES_LATCOL) ? "late collision" : "too many collisions"); - lp->stats.tx_window_errors++; - if (!(lp->stats.tx_window_errors & 63) && net_ratelimit()) { + dev->stats.tx_window_errors++; + if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) { printk(KERN_INFO "%s: unexpectedly large number of " "bad collisions. Please check duplex " "setting.\n", dev->name); @@ -1347,19 +1340,19 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) SMC_SELECT_BANK(2); /* single collisions */ - lp->stats.collisions += card_stats & 0xF; + dev->stats.collisions += card_stats & 0xF; card_stats >>= 4; /* multiple collisions */ - lp->stats.collisions += card_stats & 0xF; + dev->stats.collisions += card_stats & 0xF; } else if (status & IM_RX_OVRN_INT) { DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name, ({ int eph_st; SMC_SELECT_BANK(0); eph_st = SMC_GET_EPH_STATUS(); SMC_SELECT_BANK(2); eph_st; }) ); SMC_ACK_INT(IM_RX_OVRN_INT); - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; } else if (status & IM_EPH_INT) { smc_eph_interrupt(dev); } else if (status & IM_MDINT) { @@ -1627,19 +1620,6 @@ static int smc_close(struct net_device *dev) return 0; } -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats *smc_query_statistics(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); - - return &lp->stats; -} - /* * Ethtool support */ @@ -1965,7 +1945,6 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) dev->hard_start_xmit = smc_hard_start_xmit; dev->tx_timeout = smc_timeout; dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; dev->ethtool_ops = &smc_ethtool_ops; #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index edc736eb3b86..fab055ffcc90 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -795,6 +795,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) static int spider_net_release_tx_chain(struct spider_net_card *card, int brutal) { + struct net_device *dev = card->netdev; struct spider_net_descr_chain *chain = &card->tx_chain; struct spider_net_descr *descr; struct spider_net_hw_descr *hwdescr; @@ -815,8 +816,8 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) status = spider_net_get_descr_status(hwdescr); switch (status) { case SPIDER_NET_DESCR_COMPLETE: - card->netdev_stats.tx_packets++; - card->netdev_stats.tx_bytes += descr->skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += descr->skb->len; break; case SPIDER_NET_DESCR_CARDOWNED: @@ -835,11 +836,11 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) if (netif_msg_tx_err(card)) dev_err(&card->netdev->dev, "forcing end of tx descriptor " "with status x%02x\n", status); - card->netdev_stats.tx_errors++; + dev->stats.tx_errors++; break; default: - card->netdev_stats.tx_dropped++; + dev->stats.tx_dropped++; if (!brutal) { spin_unlock_irqrestore(&chain->lock, flags); return 1; @@ -919,7 +920,7 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) spider_net_release_tx_chain(card, 0); if (spider_net_prepare_tx_descr(card, skb) != 0) { - card->netdev_stats.tx_dropped++; + netdev->stats.tx_dropped++; netif_stop_queue(netdev); return NETDEV_TX_BUSY; } @@ -979,16 +980,12 @@ static void spider_net_pass_skb_up(struct spider_net_descr *descr, struct spider_net_card *card) { - struct spider_net_hw_descr *hwdescr= descr->hwdescr; - struct sk_buff *skb; - struct net_device *netdev; - u32 data_status, data_error; + struct spider_net_hw_descr *hwdescr = descr->hwdescr; + struct sk_buff *skb = descr->skb; + struct net_device *netdev = card->netdev; + u32 data_status = hwdescr->data_status; + u32 data_error = hwdescr->data_error; - data_status = hwdescr->data_status; - data_error = hwdescr->data_error; - netdev = card->netdev; - - skb = descr->skb; skb_put(skb, hwdescr->valid_size); /* the card seems to add 2 bytes of junk in front @@ -1015,8 +1012,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, } /* update netdevice statistics */ - card->netdev_stats.rx_packets++; - card->netdev_stats.rx_bytes += skb->len; + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += skb->len; /* pass skb up to stack */ netif_receive_skb(skb); @@ -1184,6 +1181,7 @@ static int spider_net_resync_tail_ptr(struct spider_net_card *card) static int spider_net_decode_one_descr(struct spider_net_card *card) { + struct net_device *dev = card->netdev; struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr = chain->tail; struct spider_net_hw_descr *hwdescr = descr->hwdescr; @@ -1210,9 +1208,9 @@ spider_net_decode_one_descr(struct spider_net_card *card) (status == SPIDER_NET_DESCR_PROTECTION_ERROR) || (status == SPIDER_NET_DESCR_FORCE_END) ) { if (netif_msg_rx_err(card)) - dev_err(&card->netdev->dev, + dev_err(&dev->dev, "dropping RX descriptor with state %d\n", status); - card->netdev_stats.rx_dropped++; + dev->stats.rx_dropped++; goto bad_desc; } @@ -1314,20 +1312,6 @@ static int spider_net_poll(struct napi_struct *napi, int budget) return packets_done; } -/** - * spider_net_get_stats - get interface statistics - * @netdev: interface device structure - * - * returns the interface statistics residing in the spider_net_card struct - */ -static struct net_device_stats * -spider_net_get_stats(struct net_device *netdev) -{ - struct spider_net_card *card = netdev_priv(netdev); - struct net_device_stats *stats = &card->netdev_stats; - return stats; -} - /** * spider_net_change_mtu - changes the MTU of an interface * @netdev: interface device structure @@ -2290,7 +2274,6 @@ spider_net_setup_netdev_ops(struct net_device *netdev) netdev->open = &spider_net_open; netdev->stop = &spider_net_stop; netdev->hard_start_xmit = &spider_net_xmit; - netdev->get_stats = &spider_net_get_stats; netdev->set_multicast_list = &spider_net_set_multi; netdev->set_mac_address = &spider_net_set_mac; netdev->change_mtu = &spider_net_change_mtu; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index a2fcdebc3790..a897beee7d5d 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -487,7 +487,6 @@ struct spider_net_card { /* for ethtool */ int msg_enable; - struct net_device_stats netdev_stats; struct spider_net_extra_stats spider_stats; struct spider_net_options options; diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index c67632dcac49..f8fbc0492706 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -152,7 +152,6 @@ struct lance_private { struct lance_memory *mem; int new_rx, new_tx; /* The next free ring entry */ int old_tx, old_rx; /* ring entry to be processed */ - struct net_device_stats stats; /* These two must be longs for set_bit() */ long tx_full; long lock; @@ -241,7 +240,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); static irqreturn_t lance_interrupt( int irq, void *dev_id); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); -static struct net_device_stats *lance_get_stats( struct net_device *dev ); static void set_multicast_list( struct net_device *dev ); /************************* End of Prototypes **************************/ @@ -401,15 +399,12 @@ static int __init lance_probe( struct net_device *dev) dev->open = &lance_open; dev->hard_start_xmit = &lance_start_xmit; dev->stop = &lance_close; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = NULL; // KLUDGE -- REMOVE ME set_bit(__LINK_STATE_PRESENT, &dev->state); - memset( &lp->stats, 0, sizeof(lp->stats) ); - return 1; } @@ -534,7 +529,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) * little endian mode. */ REGA(CSR3) = CSR3_BSWP; - lp->stats.tx_errors++; + dev->stats.tx_errors++; if(lance_debug >= 2) { int i; @@ -634,7 +629,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK; - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* Trigger an immediate send poll. */ REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT; @@ -712,12 +707,12 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id) if (head->flag & TMD1_ERR) { int status = head->misc; - lp->stats.tx_errors++; - if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++; - if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++; - if (status & TMD3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & TMD3_RTRY) dev->stats.tx_aborted_errors++; + if (status & TMD3_LCAR) dev->stats.tx_carrier_errors++; + if (status & TMD3_LCOL) dev->stats.tx_window_errors++; if (status & (TMD3_UFLO | TMD3_BUFF)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk("%s: Tx FIFO error\n", dev->name); REGA(CSR0) = CSR0_STOP; @@ -730,9 +725,9 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id) head->flag &= ~(TMD1_ENP | TMD1_STP); if(head->flag & (TMD1_ONE | TMD1_MORE)) - lp->stats.collisions++; + dev->stats.collisions++; - lp->stats.tx_packets++; + dev->stats.tx_packets++; DPRINTK(3, ("cleared tx ring %d\n", old_tx)); } old_tx = (old_tx +1) & TX_RING_MOD_MASK; @@ -752,8 +747,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id) lance_rx( dev ); /* Log misc errors. */ - if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */ - if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */ + if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & CSR0_MERR) { DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), " "status %04x.\n", dev->name, csr0 )); @@ -799,11 +794,11 @@ static int lance_rx( struct net_device *dev ) full-sized buffers it's possible for a jabber packet to use two buffers, with only the last correctly noting the error. */ if (status & RMD1_ENP) /* Only count a general error at the */ - lp->stats.rx_errors++; /* end of a packet.*/ - if (status & RMD1_FRAM) lp->stats.rx_frame_errors++; - if (status & RMD1_OFLO) lp->stats.rx_over_errors++; - if (status & RMD1_CRC) lp->stats.rx_crc_errors++; - if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; /* end of a packet.*/ + if (status & RMD1_FRAM) dev->stats.rx_frame_errors++; + if (status & RMD1_OFLO) dev->stats.rx_over_errors++; + if (status & RMD1_CRC) dev->stats.rx_crc_errors++; + if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++; head->flag &= (RMD1_ENP|RMD1_STP); } else { /* Malloc up new buffer, compatible with net-3. */ @@ -813,7 +808,7 @@ static int lance_rx( struct net_device *dev ) if (pkt_len < 60) { printk( "%s: Runt packet!\n", dev->name ); - lp->stats.rx_errors++; + dev->stats.rx_errors++; } else { skb = dev_alloc_skb( pkt_len+2 ); @@ -821,7 +816,7 @@ static int lance_rx( struct net_device *dev ) DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n", dev->name )); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; head->msg_length = 0; head->flag |= RMD1_OWN_CHIP; lp->new_rx = (lp->new_rx+1) & @@ -859,8 +854,8 @@ static int lance_rx( struct net_device *dev ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } } @@ -897,14 +892,6 @@ static int lance_close( struct net_device *dev ) } -static struct net_device_stats *lance_get_stats( struct net_device *dev ) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - - /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 17d66c1185cd..7bf5c90b7749 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -248,7 +248,6 @@ struct lance_private { int rx_new, tx_new; int rx_old, tx_old; - struct net_device_stats stats; struct sbus_dma *ledma; /* If set this points to ledma */ char tpe; /* cable-selection is TPE */ char auto_select; /* cable-selection by carrier */ @@ -519,17 +518,17 @@ static void lance_rx_dvma(struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) dev->stats.rx_over_errors++; + if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { len = (rd->mblength & 0xfff) - 4; skb = dev_alloc_skb(len + 2); @@ -537,14 +536,14 @@ static void lance_rx_dvma(struct net_device *dev) if (skb == NULL) { printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = RX_NEXT(entry); return; } - lp->stats.rx_bytes += len; + dev->stats.rx_bytes += len; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ @@ -554,7 +553,7 @@ static void lance_rx_dvma(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } /* Return the packet to the pool */ @@ -586,12 +585,12 @@ static void lance_tx_dvma(struct net_device *dev) if (bits & LE_T1_ERR) { u16 status = td->misc; - lp->stats.tx_errors++; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n", @@ -608,7 +607,7 @@ static void lance_tx_dvma(struct net_device *dev) * transmitter, restart the adapter. */ if (status & (LE_T3_BUF|LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); @@ -626,13 +625,13 @@ static void lance_tx_dvma(struct net_device *dev) /* One collision before packet was sent. */ if (bits & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (bits & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = TX_NEXT(j); @@ -692,17 +691,17 @@ static void lance_rx_pio(struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) dev->stats.rx_over_errors++; + if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { len = (sbus_readw(&rd->mblength) & 0xfff) - 4; skb = dev_alloc_skb(len + 2); @@ -710,14 +709,14 @@ static void lance_rx_pio(struct net_device *dev) if (skb == NULL) { printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; sbus_writew(0, &rd->mblength); sbus_writeb(LE_R1_OWN, &rd->rmd1_bits); lp->rx_new = RX_NEXT(entry); return; } - lp->stats.rx_bytes += len; + dev->stats.rx_bytes += len; skb_reserve (skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ @@ -725,7 +724,7 @@ static void lance_rx_pio(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } /* Return the packet to the pool */ @@ -757,12 +756,12 @@ static void lance_tx_pio(struct net_device *dev) if (bits & LE_T1_ERR) { u16 status = sbus_readw(&td->misc); - lp->stats.tx_errors++; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n", @@ -779,7 +778,7 @@ static void lance_tx_pio(struct net_device *dev) * transmitter, restart the adapter. */ if (status & (LE_T3_BUF|LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); @@ -797,13 +796,13 @@ static void lance_tx_pio(struct net_device *dev) /* One collision before packet was sent. */ if (bits & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (bits & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = TX_NEXT(j); @@ -844,10 +843,10 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) lp->tx(dev); if (csr0 & LE_C0_BABL) - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (csr0 & LE_C0_MISS) - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (csr0 & LE_C0_MERR) { if (lp->dregs) { @@ -1127,7 +1126,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irq(&lp->lock); - lp->stats.tx_bytes += len; + dev->stats.tx_bytes += len; entry = lp->tx_new & TX_RING_MOD_MASK; if (lp->pio_buffer) { @@ -1170,13 +1169,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *lance_get_stats(struct net_device *dev) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - /* taken from the depca driver */ static void lance_load_multicast(struct net_device *dev) { @@ -1463,7 +1455,6 @@ no_link_test: dev->hard_start_xmit = &lance_start_xmit; dev->tx_timeout = &lance_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->ethtool_ops = &sparc_lance_ethtool_ops; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index b5c2974fd625..ff23c6489efd 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -260,31 +260,31 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status) if (qe_status & CREG_STAT_EDEFER) { printk(KERN_ERR "%s: Excessive transmit defers.\n", dev->name); - qep->net_stats.tx_errors++; + dev->stats.tx_errors++; } if (qe_status & CREG_STAT_CLOSS) { printk(KERN_ERR "%s: Carrier lost, link down?\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.tx_carrier_errors++; + dev->stats.tx_errors++; + dev->stats.tx_carrier_errors++; } if (qe_status & CREG_STAT_ERETRIES) { printk(KERN_ERR "%s: Excessive transmit retries (more than 16).\n", dev->name); - qep->net_stats.tx_errors++; + dev->stats.tx_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_LCOLL) { printk(KERN_ERR "%s: Late transmit collision.\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.collisions++; + dev->stats.tx_errors++; + dev->stats.collisions++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_FUFLOW) { printk(KERN_ERR "%s: Transmit fifo underflow, driver bug.\n", dev->name); - qep->net_stats.tx_errors++; + dev->stats.tx_errors++; mace_hwbug_workaround = 1; } @@ -297,104 +297,104 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status) } if (qe_status & CREG_STAT_CCOFLOW) { - qep->net_stats.tx_errors += 256; - qep->net_stats.collisions += 256; + dev->stats.tx_errors += 256; + dev->stats.collisions += 256; } if (qe_status & CREG_STAT_TXDERROR) { printk(KERN_ERR "%s: Transmit descriptor is bogus, driver bug.\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_TXLERR) { printk(KERN_ERR "%s: Transmit late error.\n", dev->name); - qep->net_stats.tx_errors++; + dev->stats.tx_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_TXPERR) { printk(KERN_ERR "%s: Transmit DMA parity error.\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_TXSERR) { printk(KERN_ERR "%s: Transmit DMA sbus error ack.\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_RCCOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.collisions += 256; + dev->stats.rx_errors += 256; + dev->stats.collisions += 256; } if (qe_status & CREG_STAT_RUOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.rx_over_errors += 256; + dev->stats.rx_errors += 256; + dev->stats.rx_over_errors += 256; } if (qe_status & CREG_STAT_MCOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.rx_missed_errors += 256; + dev->stats.rx_errors += 256; + dev->stats.rx_missed_errors += 256; } if (qe_status & CREG_STAT_RXFOFLOW) { printk(KERN_ERR "%s: Receive fifo overflow.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_over_errors++; + dev->stats.rx_errors++; + dev->stats.rx_over_errors++; } if (qe_status & CREG_STAT_RLCOLL) { printk(KERN_ERR "%s: Late receive collision.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.collisions++; + dev->stats.rx_errors++; + dev->stats.collisions++; } if (qe_status & CREG_STAT_FCOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.rx_frame_errors += 256; + dev->stats.rx_errors += 256; + dev->stats.rx_frame_errors += 256; } if (qe_status & CREG_STAT_CECOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.rx_crc_errors += 256; + dev->stats.rx_errors += 256; + dev->stats.rx_crc_errors += 256; } if (qe_status & CREG_STAT_RXDROP) { printk(KERN_ERR "%s: Receive packet dropped.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_dropped++; - qep->net_stats.rx_missed_errors++; + dev->stats.rx_errors++; + dev->stats.rx_dropped++; + dev->stats.rx_missed_errors++; } if (qe_status & CREG_STAT_RXSMALL) { printk(KERN_ERR "%s: Receive buffer too small, driver bug.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; } if (qe_status & CREG_STAT_RXLERR) { printk(KERN_ERR "%s: Receive late error.\n", dev->name); - qep->net_stats.rx_errors++; + dev->stats.rx_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_RXPERR) { printk(KERN_ERR "%s: Receive DMA parity error.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_missed_errors++; + dev->stats.rx_errors++; + dev->stats.rx_missed_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_RXSERR) { printk(KERN_ERR "%s: Receive DMA sbus error ack.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_missed_errors++; + dev->stats.rx_errors++; + dev->stats.rx_missed_errors++; mace_hwbug_workaround = 1; } @@ -409,6 +409,7 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status) static void qe_rx(struct sunqe *qep) { struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0]; + struct net_device *dev = qep->dev; struct qe_rxd *this; struct sunqe_buffers *qbufs = qep->buffers; __u32 qbufs_dvma = qep->buffers_dvma; @@ -428,14 +429,14 @@ static void qe_rx(struct sunqe *qep) /* Check for errors. */ if (len < ETH_ZLEN) { - qep->net_stats.rx_errors++; - qep->net_stats.rx_length_errors++; - qep->net_stats.rx_dropped++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + dev->stats.rx_dropped++; } else { skb = dev_alloc_skb(len + 2); if (skb == NULL) { drops++; - qep->net_stats.rx_dropped++; + dev->stats.rx_dropped++; } else { skb_reserve(skb, 2); skb_put(skb, len); @@ -444,8 +445,8 @@ static void qe_rx(struct sunqe *qep) skb->protocol = eth_type_trans(skb, qep->dev); netif_rx(skb); qep->dev->last_rx = jiffies; - qep->net_stats.rx_packets++; - qep->net_stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } } end_rxd->rx_addr = this_qbuf_dvma; @@ -603,8 +604,8 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; sbus_writel(CREG_CTRL_TWAKEUP, qep->qcregs + CREG_CTRL); - qep->net_stats.tx_packets++; - qep->net_stats.tx_bytes += len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += len; if (TX_BUFFS_AVAIL(qep) <= 0) { /* Halt the net queue and enable tx interrupts. @@ -622,13 +623,6 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *qe_get_stats(struct net_device *dev) -{ - struct sunqe *qep = (struct sunqe *) dev->priv; - - return &qep->net_stats; -} - static void qe_set_multicast(struct net_device *dev) { struct sunqe *qep = (struct sunqe *) dev->priv; @@ -903,7 +897,6 @@ static int __init qec_ether_init(struct sbus_dev *sdev) dev->open = qe_open; dev->stop = qe_close; dev->hard_start_xmit = qe_start_xmit; - dev->get_stats = qe_get_stats; dev->set_multicast_list = qe_set_multicast; dev->tx_timeout = qe_tx_timeout; dev->watchdog_timeo = 5*HZ; diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h index af34f36111ed..347c8ddc1592 100644 --- a/drivers/net/sunqe.h +++ b/drivers/net/sunqe.h @@ -342,7 +342,6 @@ struct sunqe { __u32 buffers_dvma; /* DVMA visible address. */ struct sunqec *parent; u8 mconfig; /* Base MACE mconfig value */ - struct net_device_stats net_stats; /* Statistical counters */ struct sbus_dev *qe_sdev; /* QE's SBUS device struct */ struct net_device *dev; /* QE's netdevice struct */ int channel; /* Who am I? */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8b3ec335385c..d279151f065d 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -110,7 +110,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) /* We won't see all dropped packets individually, so overrun * error is more appropriate. */ - tun->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } else { /* Single queue mode. * Driver handles dropping of all packets itself. */ @@ -129,7 +129,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) return 0; drop: - tun->stats.tx_dropped++; + dev->stats.tx_dropped++; kfree_skb(skb); return 0; } @@ -172,12 +172,6 @@ tun_net_mclist(struct net_device *dev) } } -static struct net_device_stats *tun_net_stats(struct net_device *dev) -{ - struct tun_struct *tun = netdev_priv(dev); - return &tun->stats; -} - /* Initialize net device. */ static void tun_net_init(struct net_device *dev) { @@ -250,14 +244,14 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, align = NET_IP_ALIGN; if (!(skb = alloc_skb(len + align, GFP_KERNEL))) { - tun->stats.rx_dropped++; + tun->dev->stats.rx_dropped++; return -ENOMEM; } if (align) skb_reserve(skb, align); if (memcpy_fromiovec(skb_put(skb, len), iv, len)) { - tun->stats.rx_dropped++; + tun->dev->stats.rx_dropped++; kfree_skb(skb); return -EFAULT; } @@ -279,8 +273,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, netif_rx_ni(skb); tun->dev->last_rx = jiffies; - tun->stats.rx_packets++; - tun->stats.rx_bytes += len; + tun->dev->stats.rx_packets++; + tun->dev->stats.rx_bytes += len; return count; } @@ -336,8 +330,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, skb_copy_datagram_iovec(skb, 0, iv, len); total += len; - tun->stats.tx_packets++; - tun->stats.tx_bytes += len; + tun->dev->stats.tx_packets++; + tun->dev->stats.tx_bytes += len; return total; } @@ -438,7 +432,6 @@ static void tun_setup(struct net_device *dev) dev->open = tun_net_open; dev->hard_start_xmit = tun_net_xmit; dev->stop = tun_net_close; - dev->get_stats = tun_net_stats; dev->ethtool_ops = &tun_ethtool_ops; dev->destructor = free_netdev; } diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 8da41229594a..9667dac383f0 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3350,14 +3350,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) return 0; } -/* returns a net_device_stats structure pointer */ -static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev) -{ - struct ucc_geth_private *ugeth = netdev_priv(dev); - - return &(ugeth->stats); -} - /* ucc_geth_timeout gets called when a packet has not been * transmitted after a set amount of time. * For now, assume that clearing out all the structures, and @@ -3368,7 +3360,7 @@ static void ucc_geth_timeout(struct net_device *dev) ugeth_vdbg("%s: IN", __FUNCTION__); - ugeth->stats.tx_errors++; + dev->stats.tx_errors++; ugeth_dump_regs(ugeth); @@ -3396,7 +3388,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irq(&ugeth->lock); - ugeth->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* Start from the next BD that should be filled */ bd = ugeth->txBd[txQ]; @@ -3488,9 +3480,9 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit dev_kfree_skb_any(skb); ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL; - ugeth->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { - ugeth->stats.rx_packets++; + dev->stats.rx_packets++; howmany++; /* Prep the skb for the packet */ @@ -3499,7 +3491,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit /* Tell the skb what kind of packet this is */ skb->protocol = eth_type_trans(skb, ugeth->dev); - ugeth->stats.rx_bytes += length; + dev->stats.rx_bytes += length; /* Send the packet up the stack */ #ifdef CONFIG_UGETH_NAPI netif_receive_skb(skb); @@ -3514,7 +3506,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit if (!skb) { if (netif_msg_rx_err(ugeth)) ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); - ugeth->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -3556,7 +3548,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0)) break; - ugeth->stats.tx_packets++; + dev->stats.tx_packets++; /* Free the sk buffer associated with this TxBD */ dev_kfree_skb_irq(ugeth-> @@ -3673,10 +3665,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* Errors and other events */ if (ucce & UCCE_OTHER) { if (ucce & UCCE_BSY) { - ugeth->stats.rx_errors++; + dev->stats.rx_errors++; } if (ucce & UCCE_TXE) { - ugeth->stats.tx_errors++; + dev->stats.tx_errors++; } } @@ -3969,7 +3961,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); #endif /* CONFIG_UGETH_NAPI */ dev->stop = ucc_geth_close; - dev->get_stats = ucc_geth_get_stats; // dev->change_mtu = ucc_geth_change_mtu; dev->mtu = 1500; dev->set_multicast_list = ucc_geth_set_multi; diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 0579ba081aa5..aaeb94877987 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1185,7 +1185,6 @@ struct ucc_geth_private { struct ucc_fast_private *uccf; struct net_device *dev; struct napi_struct napi; - struct net_device_stats stats; /* linux network statistics */ struct ucc_geth *ug_regs; struct ucc_geth_init_pram *p_init_enet_param_shadow; struct ucc_geth_exf_global_pram *p_exf_glbl_param; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8eeb068dc4a6..78e344ae7051 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -73,7 +73,6 @@ struct netfront_info { struct net_device *netdev; struct napi_struct napi; - struct net_device_stats stats; struct xen_netif_tx_front_ring tx; struct xen_netif_rx_front_ring rx; @@ -309,8 +308,6 @@ static int xennet_open(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); - memset(&np->stats, 0, sizeof(np->stats)); - napi_enable(&np->napi); spin_lock_bh(&np->rx_lock); @@ -537,8 +534,8 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) if (notify) notify_remote_via_irq(np->netdev->irq); - np->stats.tx_bytes += skb->len; - np->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; /* Note: It is not safe to access skb after xennet_tx_buf_gc()! */ xennet_tx_buf_gc(dev); @@ -551,7 +548,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; drop: - np->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -564,12 +561,6 @@ static int xennet_close(struct net_device *dev) return 0; } -static struct net_device_stats *xennet_get_stats(struct net_device *dev) -{ - struct netfront_info *np = netdev_priv(dev); - return &np->stats; -} - static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb, grant_ref_t ref) { @@ -804,9 +795,8 @@ out: } static int handle_incoming_queue(struct net_device *dev, - struct sk_buff_head *rxq) + struct sk_buff_head *rxq) { - struct netfront_info *np = netdev_priv(dev); int packets_dropped = 0; struct sk_buff *skb; @@ -828,13 +818,13 @@ static int handle_incoming_queue(struct net_device *dev, if (skb_checksum_setup(skb)) { kfree_skb(skb); packets_dropped++; - np->stats.rx_errors++; + dev->stats.rx_errors++; continue; } } - np->stats.rx_packets++; - np->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; /* Pass it up. */ netif_receive_skb(skb); @@ -887,7 +877,7 @@ static int xennet_poll(struct napi_struct *napi, int budget) err: while ((skb = __skb_dequeue(&tmpq))) __skb_queue_tail(&errq, skb); - np->stats.rx_errors++; + dev->stats.rx_errors++; i = np->rx.rsp_cons; continue; } @@ -1169,7 +1159,6 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->open = xennet_open; netdev->hard_start_xmit = xennet_start_xmit; netdev->stop = xennet_close; - netdev->get_stats = xennet_get_stats; netif_napi_add(netdev, &np->napi, xennet_poll, 64); netdev->uninit = xennet_uninit; netdev->change_mtu = xennet_change_mtu; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 29e96950be65..709623e1c611 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -318,7 +318,6 @@ struct yellowfin_private { dma_addr_t tx_status_dma; struct timer_list timer; /* Media selection timer. */ - struct net_device_stats stats; /* Frequently used and paired value: keep adjacent for cache effect. */ int chip_id, drv_flags; struct pci_dev *pci_dev; @@ -353,7 +352,6 @@ 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); static int yellowfin_close(struct net_device *dev); -static struct net_device_stats *yellowfin_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static const struct ethtool_ops ethtool_ops; @@ -469,7 +467,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, dev->open = &yellowfin_open; dev->hard_start_xmit = &yellowfin_start_xmit; dev->stop = &yellowfin_close; - dev->get_stats = &yellowfin_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &netdev_ioctl; SET_ETHTOOL_OPS(dev, ðtool_ops); @@ -717,7 +714,7 @@ static void yellowfin_tx_timeout(struct net_device *dev) netif_wake_queue (dev); /* Typical path */ dev->trans_start = jiffies; - yp->stats.tx_errors++; + dev->stats.tx_errors++; } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ @@ -923,8 +920,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) if (yp->tx_ring[entry].result_status == 0) break; skb = yp->tx_skbuff[entry]; - yp->stats.tx_packets++; - yp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* Free the original skb. */ pci_unmap_single(yp->pci_dev, yp->tx_ring[entry].addr, skb->len, PCI_DMA_TODEVICE); @@ -968,20 +965,20 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n", dev->name, tx_errs); #endif - yp->stats.tx_errors++; - if (tx_errs & 0xF800) yp->stats.tx_aborted_errors++; - if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++; - if (tx_errs & 0x2000) yp->stats.tx_window_errors++; - if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++; + dev->stats.tx_errors++; + if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++; + if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++; + if (tx_errs & 0x2000) dev->stats.tx_window_errors++; + if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++; } else { #ifndef final_version if (yellowfin_debug > 4) printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n", dev->name, tx_errs); #endif - yp->stats.tx_bytes += skb->len; - yp->stats.collisions += tx_errs & 15; - yp->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->stats.collisions += tx_errs & 15; + dev->stats.tx_packets++; } /* Free the original skb. */ pci_unmap_single(yp->pci_dev, @@ -1076,26 +1073,26 @@ static int yellowfin_rx(struct net_device *dev) if (data_size != 0) printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers," " status %4.4x, data_size %d!\n", dev->name, desc_status, data_size); - yp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) { /* There was a error. */ if (yellowfin_debug > 3) printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n", frame_status); - yp->stats.rx_errors++; - if (frame_status & 0x0060) yp->stats.rx_length_errors++; - if (frame_status & 0x0008) yp->stats.rx_frame_errors++; - if (frame_status & 0x0010) yp->stats.rx_crc_errors++; - if (frame_status < 0) yp->stats.rx_dropped++; + dev->stats.rx_errors++; + if (frame_status & 0x0060) dev->stats.rx_length_errors++; + if (frame_status & 0x0008) dev->stats.rx_frame_errors++; + if (frame_status & 0x0010) dev->stats.rx_crc_errors++; + if (frame_status < 0) dev->stats.rx_dropped++; } else if ( !(yp->drv_flags & IsGigabit) && ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) { u8 status1 = buf_addr[data_size-2]; u8 status2 = buf_addr[data_size-1]; - yp->stats.rx_errors++; - if (status1 & 0xC0) yp->stats.rx_length_errors++; - if (status2 & 0x03) yp->stats.rx_frame_errors++; - if (status2 & 0x04) yp->stats.rx_crc_errors++; - if (status2 & 0x80) yp->stats.rx_dropped++; + dev->stats.rx_errors++; + if (status1 & 0xC0) dev->stats.rx_length_errors++; + if (status2 & 0x03) dev->stats.rx_frame_errors++; + if (status2 & 0x04) dev->stats.rx_crc_errors++; + if (status2 & 0x80) dev->stats.rx_dropped++; #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ } else if ((yp->flags & HasMACAddrBug) && memcmp(le32_to_cpu(yp->rx_ring_dma + @@ -1145,8 +1142,8 @@ static int yellowfin_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - yp->stats.rx_packets++; - yp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } entry = (++yp->cur_rx) % RX_RING_SIZE; } @@ -1180,15 +1177,13 @@ static int yellowfin_rx(struct net_device *dev) static void yellowfin_error(struct net_device *dev, int intr_status) { - struct yellowfin_private *yp = netdev_priv(dev); - printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Hmmmmm, it's not clear what to do here. */ if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) - yp->stats.tx_errors++; + dev->stats.tx_errors++; if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) - yp->stats.rx_errors++; + dev->stats.rx_errors++; } static int yellowfin_close(struct net_device *dev) @@ -1280,12 +1275,6 @@ static int yellowfin_close(struct net_device *dev) return 0; } -static struct net_device_stats *yellowfin_get_stats(struct net_device *dev) -{ - struct yellowfin_private *yp = netdev_priv(dev); - return &yp->stats; -} - /* Set or clear the multicast filter for this adaptor. */ static void set_rx_mode(struct net_device *dev) diff --git a/drivers/net/znet.c b/drivers/net/znet.c index dcd4e1b136b5..43712c7b9ecf 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -128,7 +128,6 @@ MODULE_LICENSE("GPL"); struct znet_private { int rx_dma, tx_dma; - struct net_device_stats stats; spinlock_t lock; short sia_base, sia_size, io_size; struct i82593_conf_block i593_init; @@ -161,7 +160,6 @@ static int 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); -static struct net_device_stats *net_get_stats(struct net_device *dev); static void hardware_init(struct net_device *dev); static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset); static void znet_tx_timeout (struct net_device *dev); @@ -445,7 +443,6 @@ static int __init znet_probe (void) dev->open = &znet_open; dev->hard_start_xmit = &znet_send_packet; dev->stop = &znet_close; - dev->get_stats = net_get_stats; dev->set_multicast_list = &znet_set_multicast_list; dev->tx_timeout = znet_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -564,7 +561,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) ushort *tx_link = znet->tx_cur - 1; ushort rnd_len = (length + 1)>>1; - znet->stats.tx_bytes+=length; + dev->stats.tx_bytes+=length; if (znet->tx_cur >= znet->tx_end) znet->tx_cur = znet->tx_start; @@ -639,20 +636,20 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id) tx_status = inw(ioaddr); /* It's undocumented, but tx_status seems to match the i82586. */ if (tx_status & TX_OK) { - znet->stats.tx_packets++; - znet->stats.collisions += tx_status & TX_NCOL_MASK; + dev->stats.tx_packets++; + dev->stats.collisions += tx_status & TX_NCOL_MASK; } else { if (tx_status & (TX_LOST_CTS | TX_LOST_CRS)) - znet->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tx_status & TX_UND_RUN) - znet->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (!(tx_status & TX_HRT_BEAT)) - znet->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (tx_status & TX_MAX_COL) - znet->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; /* ...and the catch-all. */ if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) - znet->stats.tx_errors++; + dev->stats.tx_errors++; /* Transceiver may be stuck if cable * was removed while emiting a @@ -748,19 +745,19 @@ static void znet_rx(struct net_device *dev) this_rfp_ptr[-3]<<1); /* Once again we must assume that the i82586 docs apply. */ if ( ! (status & RX_RCV_OK)) { /* There was an error. */ - znet->stats.rx_errors++; - if (status & RX_CRC_ERR) znet->stats.rx_crc_errors++; - if (status & RX_ALG_ERR) znet->stats.rx_frame_errors++; + dev->stats.rx_errors++; + if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++; + if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++; #if 0 - if (status & 0x0200) znet->stats.rx_over_errors++; /* Wrong. */ - if (status & 0x0100) znet->stats.rx_fifo_errors++; + if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */ + if (status & 0x0100) dev->stats.rx_fifo_errors++; #else /* maz : Wild guess... */ - if (status & RX_OVRRUN) znet->stats.rx_over_errors++; + if (status & RX_OVRRUN) dev->stats.rx_over_errors++; #endif - if (status & RX_SRT_FRM) znet->stats.rx_length_errors++; + if (status & RX_SRT_FRM) dev->stats.rx_length_errors++; } else if (pkt_len > 1536) { - znet->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else { /* Malloc up new buffer. */ struct sk_buff *skb; @@ -769,7 +766,7 @@ static void znet_rx(struct net_device *dev) if (skb == NULL) { if (znet_debug) printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - znet->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -789,8 +786,8 @@ static void znet_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - znet->stats.rx_packets++; - znet->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } znet->rx_cur = this_rfp_ptr; if (znet->rx_cur >= znet->rx_end) @@ -827,15 +824,6 @@ static int znet_close(struct net_device *dev) return 0; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *net_get_stats(struct net_device *dev) -{ - struct znet_private *znet = dev->priv; - - return &znet->stats; -} - static void show_dma(struct net_device *dev) { short ioaddr = dev->base_addr; diff --git a/include/linux/if_eql.h b/include/linux/if_eql.h index b68752fdc5c4..79c4f268410d 100644 --- a/include/linux/if_eql.h +++ b/include/linux/if_eql.h @@ -58,7 +58,6 @@ typedef struct equalizer { slave_queue_t queue; int min_slaves; int max_slaves; - struct net_device_stats stats; struct timer_list timer; } equalizer_t; diff --git a/include/linux/if_shaper.h b/include/linux/if_shaper.h index 68c896a36a34..51574743aa1b 100644 --- a/include/linux/if_shaper.h +++ b/include/linux/if_shaper.h @@ -24,7 +24,6 @@ struct shaper unsigned long recovery; /* Time we can next clock a packet out on an empty queue */ spinlock_t lock; - struct net_device_stats stats; struct net_device *dev; int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev); diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 42eb6945b93e..33e489d5bb33 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -42,7 +42,6 @@ struct tun_struct { struct sk_buff_head readq; struct net_device *dev; - struct net_device_stats stats; struct fasync_struct *fasync; From 88d3aafdae5c5e1d2dd9489a5c8a24e29d335f2e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 15 Sep 2007 14:41:06 -0700 Subject: [PATCH 1388/2804] [ETHTOOL] Provide default behaviors for a few ethtool sub-ioctls For the operations get-tx-csum get-sg get-tso get-ufo the default ethtool_op_xxx behavior is fine for all drivers, so we permit op==NULL to imply the default behavior. This provides a more uniform behavior across all drivers, eliminating ethtool(8) "ioctl not supported" errors on older drivers that had not been updated for the latest sub-ioctls. The ethtool_op_xxx() functions are left exported, in case anyone wishes to call them directly from a driver-private implementation -- a not-uncommon case. Should an ethtool_op_xxx() helper remain unused for a while, except by net/core/ethtool.c, we can un-export it at a later date. [ Resolved conflicts with set/get value ethtool patch... -DaveM ] Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/8139cp.c | 3 --- drivers/net/atl1/atl1_ethtool.c | 3 --- drivers/net/bnx2.c | 3 --- drivers/net/bonding/bond_main.c | 4 ---- drivers/net/chelsio/cxgb2.c | 3 --- drivers/net/cxgb3/cxgb3_main.c | 3 --- drivers/net/e1000/e1000_ethtool.c | 2 -- drivers/net/ehea/ehea_ethtool.c | 3 --- drivers/net/epic100.c | 2 -- drivers/net/fealnx.c | 2 -- drivers/net/fec_8xx/fec_main.c | 2 -- drivers/net/forcedeth.c | 3 --- drivers/net/fs_enet/fs_enet-main.c | 2 -- drivers/net/ibm_emac/ibm_emac_core.c | 2 -- drivers/net/ibmveth.c | 6 +----- drivers/net/ixgb/ixgb_ethtool.c | 2 -- drivers/net/loopback.c | 1 - drivers/net/macvlan.c | 4 ---- drivers/net/mv643xx_eth.c | 1 - drivers/net/myri10ge/myri10ge.c | 3 --- drivers/net/ne2k-pci.c | 2 -- drivers/net/netxen/netxen_nic_ethtool.c | 3 --- drivers/net/pcnet32.c | 3 --- drivers/net/r8169.c | 3 --- drivers/net/s2io.c | 3 --- drivers/net/sc92031.c | 4 ---- drivers/net/skge.c | 2 -- drivers/net/sky2.c | 3 --- drivers/net/spider_net_ethtool.c | 1 - drivers/net/tg3.c | 3 --- drivers/net/tulip/de2104x.c | 2 -- drivers/net/tulip/winbond-840.c | 2 -- drivers/net/typhoon.c | 3 --- drivers/net/ucc_geth_ethtool.c | 2 -- drivers/net/via-rhine.c | 2 -- drivers/net/xen-netfront.c | 3 --- net/bridge/br_device.c | 3 --- net/core/ethtool.c | 16 ++++++++++++---- 38 files changed, 13 insertions(+), 101 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 30310ed9f75f..58fad1b2f72e 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1572,11 +1572,8 @@ static const struct ethtool_ops cp_ethtool_ops = { .set_msglevel = cp_set_msglevel, .get_rx_csum = cp_get_rx_csum, .set_rx_csum = cp_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_regs = cp_get_regs, .get_wol = cp_get_wol, diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c index 1f616c5c1473..53353b60a9c8 100644 --- a/drivers/net/atl1/atl1_ethtool.c +++ b/drivers/net/atl1/atl1_ethtool.c @@ -489,15 +489,12 @@ const struct ethtool_ops atl1_ethtool_ops = { .get_pauseparam = atl1_get_pauseparam, .set_pauseparam = atl1_set_pauseparam, .get_rx_csum = atl1_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_hw_csum, .get_link = ethtool_op_get_link, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_strings = atl1_get_strings, .nway_reset = atl1_nway_reset, .get_ethtool_stats = atl1_get_ethtool_stats, .get_stats_count = atl1_get_stats_count, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index f1e7204f78c9..5ee805b3e0e6 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6257,11 +6257,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_pauseparam = bnx2_set_pauseparam, .get_rx_csum = bnx2_get_rx_csum, .set_rx_csum = bnx2_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = bnx2_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = bnx2_set_tso, .self_test_count = bnx2_self_test_count, .self_test = bnx2_self_test, diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 88ff72ac9b0a..ea58144c220e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4202,10 +4202,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev, } static const struct ethtool_ops bond_ethtool_ops = { - .get_tx_csum = ethtool_op_get_tx_csum, - .get_tso = ethtool_op_get_tso, - .get_ufo = ethtool_op_get_ufo, - .get_sg = ethtool_op_get_sg, .get_drvinfo = bond_ethtool_get_drvinfo, }; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 884aa0cd0006..7029f13d008d 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -794,9 +794,7 @@ static const struct ethtool_ops t1_ethtool_ops = { .set_pauseparam = set_pauseparam, .get_rx_csum = get_rx_csum, .set_rx_csum = set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, @@ -804,7 +802,6 @@ static const struct ethtool_ops t1_ethtool_ops = { .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, - .get_tso = ethtool_op_get_tso, .set_tso = set_tso, }; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 19937498589d..04633ea55202 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1634,9 +1634,7 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .set_pauseparam = set_pauseparam, .get_rx_csum = get_rx_csum, .set_rx_csum = set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, @@ -1647,7 +1645,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .get_regs_len = get_regs_len, .get_regs = get_regs, .get_wol = get_wol, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 76d16aaf05b6..e6c4a3bb9e4c 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1965,9 +1965,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_rx_csum = e1000_set_rx_csum, .get_tx_csum = e1000_get_tx_csum, .set_tx_csum = e1000_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = e1000_set_tso, .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 29ef7a98f8be..6498455bf97c 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -262,9 +262,6 @@ const struct ethtool_ops ehea_ethtool_ops = { .get_msglevel = ehea_get_msglevel, .set_msglevel = ehea_set_msglevel, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_strings = ehea_get_strings, .get_stats_count = ehea_get_stats_count, diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 122ffd2f0822..5ac56f20003d 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1494,8 +1494,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .begin = ethtool_begin, .complete = ethtool_complete }; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index e9353072a96d..402b071d8d53 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1891,8 +1891,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, }; static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index 6f214ab12fff..8d2904fa5789 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -1041,9 +1041,7 @@ static const struct ethtool_ops fec_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = fec_get_msglevel, .set_msglevel = fec_set_msglevel, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_regs = fec_get_regs, }; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 050a8f14eda8..be744573b1c2 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4710,7 +4710,6 @@ static const struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, - .get_tso = ethtool_op_get_tso, .set_tso = nv_set_tso, .get_ringparam = nv_get_ringparam, .set_ringparam = nv_set_ringparam, @@ -4718,9 +4717,7 @@ static const struct ethtool_ops ops = { .set_pauseparam = nv_set_pauseparam, .get_rx_csum = nv_get_rx_csum, .set_rx_csum = nv_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = nv_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = nv_set_sg, .get_strings = nv_get_strings, .get_stats_count = nv_get_stats_count, diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f6789a8db8cd..f9079599dd22 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -907,9 +907,7 @@ static const struct ethtool_ops fs_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = fs_get_msglevel, .set_msglevel = fs_set_msglevel, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_regs = fs_get_regs, }; diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 354616b0b57b..d7da56b105cb 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1900,8 +1900,6 @@ static const struct ethtool_ops emac_ethtool_ops = { .get_ethtool_stats = emac_ethtool_get_ethtool_stats, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, }; static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index bdbf3dead4e2..0636883449fc 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -821,15 +821,11 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .get_link = netdev_get_link, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ibmveth_set_tx_csum, .get_rx_csum = ibmveth_get_rx_csum, .set_rx_csum = ibmveth_set_rx_csum, - .get_tso = ethtool_op_get_tso, - .get_ufo = ethtool_op_get_ufo, .get_strings = ibmveth_get_strings, - .get_stats_count = ibmveth_get_stats_count, + .get_stats_count = ibmveth_get_stats_count, .get_ethtool_stats = ibmveth_get_ethtool_stats, }; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 21d35bc53906..181b59dc1ac3 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -713,11 +713,9 @@ static const struct ethtool_ops ixgb_ethtool_ops = { .set_rx_csum = ixgb_set_rx_csum, .get_tx_csum = ixgb_get_tx_csum, .set_tx_csum = ixgb_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_msglevel = ixgb_get_msglevel, .set_msglevel = ixgb_set_msglevel, - .get_tso = ethtool_op_get_tso, .set_tso = ixgb_set_tso, .get_strings = ixgb_get_strings, .phys_id = ixgb_phys_id, diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index a328da72833c..0e2252fd71ab 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -192,7 +192,6 @@ static u32 always_on(struct net_device *dev) static const struct ethtool_ops loopback_ethtool_ops = { .get_link = always_on, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_tx_csum = always_on, .get_sg = always_on, diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 2de073da182c..2f6cdaa88729 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -282,10 +282,6 @@ static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, .get_rx_csum = macvlan_ethtool_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_tso = ethtool_op_get_tso, - .get_ufo = ethtool_op_get_ufo, - .get_sg = ethtool_op_get_sg, .get_drvinfo = macvlan_ethtool_get_drvinfo, }; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 35781616eb23..34df02cfdbe7 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2735,7 +2735,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = { .set_settings = mv643xx_set_settings, .get_drvinfo = mv643xx_get_drvinfo, .get_link = mv643xx_eth_get_link, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 6dc28b824935..2f8864e70ca9 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1499,11 +1499,8 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .get_ringparam = myri10ge_get_ringparam, .get_rx_csum = myri10ge_get_rx_csum, .set_rx_csum = myri10ge_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_link = ethtool_op_get_link, .get_strings = myri10ge_get_strings, diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 7ec362b2e3e5..a5879672903e 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -635,8 +635,6 @@ static void ne2k_pci_get_drvinfo(struct net_device *dev, static const struct ethtool_ops ne2k_pci_ethtool_ops = { .get_drvinfo = ne2k_pci_get_drvinfo, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, }; static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index a6138b474b4a..08c76b343663 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -744,11 +744,8 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_ringparam = netxen_nic_get_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .self_test_count = netxen_nic_diag_test_count, .self_test = netxen_nic_diag_test, diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 724d90bd1feb..4840ddea71ac 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1509,9 +1509,6 @@ static const struct ethtool_ops pcnet32_ethtool_ops = { .get_link = pcnet32_get_link, .get_ringparam = pcnet32_get_ringparam, .set_ringparam = pcnet32_set_ringparam, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .get_strings = pcnet32_get_strings, .self_test_count = pcnet32_self_test_count, .self_test = pcnet32_ethtool_test, diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b8809a8ef204..06a1a6f2d17b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1061,11 +1061,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .set_msglevel = rtl8169_set_msglevel, .get_rx_csum = rtl8169_get_rx_csum, .set_rx_csum = rtl8169_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_regs = rtl8169_get_regs, .get_wol = rtl8169_get_wol, diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index f77049b34e16..a285dd734a03 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -6326,13 +6326,10 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_pauseparam = s2io_ethtool_setpause_data, .get_rx_csum = s2io_ethtool_get_rx_csum, .set_rx_csum = s2io_ethtool_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = s2io_ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = s2io_ethtool_op_get_tso, .set_tso = s2io_ethtool_op_set_tso, - .get_ufo = ethtool_op_get_ufo, .set_ufo = ethtool_op_set_ufo, .self_test_count = s2io_ethtool_self_test_count, .self_test = s2io_ethtool_test, diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 872cb1cc9c41..02c472ecbe55 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1396,13 +1396,9 @@ static struct ethtool_ops sc92031_ethtool_ops = { .set_wol = sc92031_ethtool_set_wol, .nway_reset = sc92031_ethtool_nway_reset, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .get_strings = sc92031_ethtool_get_strings, .get_stats_count = sc92031_ethtool_get_stats_count, .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, - .get_ufo = ethtool_op_get_ufo, }; static int __devinit sc92031_probe(struct pci_dev *pdev, diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 47a144d000d5..cac499f84131 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -811,9 +811,7 @@ static const struct ethtool_ops skge_ethtool_ops = { .set_pauseparam = skge_set_pauseparam, .get_coalesce = skge_get_coalesce, .set_coalesce = skge_set_coalesce, - .get_sg = ethtool_op_get_sg, .set_sg = skge_set_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = skge_set_tx_csum, .get_rx_csum = skge_get_rx_csum, .set_rx_csum = skge_set_rx_csum, diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1b9e5f40ddee..b8c15f881eba 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3710,11 +3710,8 @@ static const struct ethtool_ops sky2_ethtool_ops = { .get_eeprom_len = sky2_get_eeprom_len, .get_eeprom = sky2_get_eeprom, .set_eeprom = sky2_set_eeprom, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = sky2_set_tx_csum, - .get_tso = ethtool_op_get_tso, .set_tso = sky2_set_tso, .get_rx_csum = sky2_get_rx_csum, .set_rx_csum = sky2_set_rx_csum, diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index d940474e024a..1460d5006d1c 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -188,7 +188,6 @@ const struct ethtool_ops spider_net_ethtool_ops = { .nway_reset = spider_net_ethtool_nway_reset, .get_rx_csum = spider_net_ethtool_get_rx_csum, .set_rx_csum = spider_net_ethtool_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, .get_ringparam = spider_net_ethtool_get_ringparam, .get_strings = spider_net_get_strings, diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 369a172a04aa..1b860e0817f6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9278,11 +9278,8 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_pauseparam = tg3_set_pauseparam, .get_rx_csum = tg3_get_rx_csum, .set_rx_csum = tg3_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = tg3_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = tg3_set_tso, .self_test_count = tg3_get_test_count, .self_test = tg3_self_test, diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index bd04e93908ef..ba3d0e5574a4 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1670,8 +1670,6 @@ static void de_get_regs(struct net_device *dev, struct ethtool_regs *regs, static const struct ethtool_ops de_ethtool_ops = { .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, .get_drvinfo = de_get_drvinfo, .get_regs_len = de_get_regs_len, .get_settings = de_get_settings, diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 396f8455cd32..e00833fadc0b 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1451,8 +1451,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 84d99fc77891..c6d8513ecad6 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1236,11 +1236,8 @@ static const struct ethtool_ops typhoon_ethtool_ops = { .set_wol = typhoon_set_wol, .get_link = ethtool_op_get_link, .get_rx_csum = typhoon_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_ringparam = typhoon_get_ringparam, }; diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 64bef7c12365..73aa677a4a3e 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -373,9 +373,7 @@ static const struct ethtool_ops uec_ethtool_ops = { .set_ringparam = uec_set_ringparam, .get_pauseparam = uec_get_pauseparam, .set_pauseparam = uec_set_pauseparam, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .get_stats_count = uec_get_stats_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 987f5b937e3c..d55c4fdff489 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1813,8 +1813,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_msglevel = netdev_set_msglevel, .get_wol = rhine_get_wol, .set_wol = rhine_set_wol, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 78e344ae7051..f464b82c7d5f 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1617,11 +1617,8 @@ static void backend_changed(struct xenbus_device *dev, static struct ethtool_ops xennet_ethtool_ops = { - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = xennet_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = xennet_set_tso, .get_link = ethtool_op_get_link, }; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index f803e39eee28..c07bac5e3e10 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -150,11 +150,8 @@ static int br_set_tx_csum(struct net_device *dev, u32 data) static struct ethtool_ops br_ethtool_ops = { .get_drvinfo = br_getinfo, .get_link = ethtool_op_get_link, - .get_sg = ethtool_op_get_sg, .set_sg = br_set_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = br_set_tx_csum, - .get_tso = ethtool_op_get_tso, .set_tso = br_set_tso, }; diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 0d0b13cc1dd3..1163eb2256d0 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -893,21 +893,27 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) break; case ETHTOOL_GTXCSUM: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_tx_csum); + (dev->ethtool_ops->get_tx_csum ? + dev->ethtool_ops->get_tx_csum : + ethtool_op_get_tx_csum)); break; case ETHTOOL_STXCSUM: rc = ethtool_set_tx_csum(dev, useraddr); break; case ETHTOOL_GSG: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_sg); + (dev->ethtool_ops->get_sg ? + dev->ethtool_ops->get_sg : + ethtool_op_get_sg)); break; case ETHTOOL_SSG: rc = ethtool_set_sg(dev, useraddr); break; case ETHTOOL_GTSO: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_tso); + (dev->ethtool_ops->get_tso ? + dev->ethtool_ops->get_tso : + ethtool_op_get_tso)); break; case ETHTOOL_STSO: rc = ethtool_set_tso(dev, useraddr); @@ -929,7 +935,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) break; case ETHTOOL_GUFO: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_ufo); + (dev->ethtool_ops->get_ufo ? + dev->ethtool_ops->get_ufo : + ethtool_op_get_ufo)); break; case ETHTOOL_SUFO: rc = ethtool_set_ufo(dev, useraddr); From 63d804eade298208037045ab6728c933f2b6c27d Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Sat, 15 Sep 2007 21:45:13 -0700 Subject: [PATCH 1389/2804] [CIPSO]: remove duplicated code in the cipso_v4_*_getattr() functions The bulk of the CIPSO option parsing/processing in the cipso_v4_sock_getattr() and cipso_v4_skb_getattr() functions are identical, the only real difference being where the functions obtain the CIPSO option itself. This patch creates a new function, cipso_v4_getattr(), which contains the common CIPSO option parsing/processing code and modifies the existing functions to call this new helper function. Signed-off-by: Paul Moore Signed-off-by: David S. Miller --- net/ipv4/cipso_ipv4.c | 133 ++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 82 deletions(-) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index ab56a052ce31..805a78e6ed55 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1830,6 +1830,51 @@ socket_setattr_failure: return ret_val; } +/** + * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions + * @cipso: the CIPSO v4 option + * @secattr: the security attributes + * + * Description: + * Inspect @cipso and return the security attributes in @secattr. Returns zero + * on success and negative values on failure. + * + */ +static int cipso_v4_getattr(const unsigned char *cipso, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val = -ENOMSG; + u32 doi; + struct cipso_v4_doi *doi_def; + + if (cipso_v4_cache_check(cipso, cipso[1], secattr) == 0) + return 0; + + doi = ntohl(get_unaligned((__be32 *)&cipso[2])); + rcu_read_lock(); + doi_def = cipso_v4_doi_search(doi); + if (doi_def == NULL) + goto getattr_return; + /* XXX - This code assumes only one tag per CIPSO option which isn't + * really a good assumption to make but since we only support the MAC + * tags right now it is a safe assumption. */ + switch (cipso[6]) { + case CIPSO_V4_TAG_RBITMAP: + ret_val = cipso_v4_parsetag_rbm(doi_def, &cipso[6], secattr); + break; + case CIPSO_V4_TAG_ENUM: + ret_val = cipso_v4_parsetag_enum(doi_def, &cipso[6], secattr); + break; + case CIPSO_V4_TAG_RANGE: + ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr); + break; + } + +getattr_return: + rcu_read_unlock(); + return ret_val; +} + /** * cipso_v4_sock_getattr - Get the security attributes from a sock * @sk: the sock @@ -1844,52 +1889,14 @@ socket_setattr_failure: */ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) { - int ret_val = -ENOMSG; - struct inet_sock *sk_inet; - unsigned char *cipso_ptr; - u32 doi; - struct cipso_v4_doi *doi_def; + struct ip_options *opt; - sk_inet = inet_sk(sk); - if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0) + opt = inet_sk(sk)->opt; + if (opt == NULL || opt->cipso == 0) return -ENOMSG; - cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso - - sizeof(struct iphdr); - ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr); - if (ret_val == 0) - return ret_val; - doi = ntohl(get_unaligned((__be32 *)&cipso_ptr[2])); - rcu_read_lock(); - doi_def = cipso_v4_doi_search(doi); - if (doi_def == NULL) { - rcu_read_unlock(); - return -ENOMSG; - } - - /* XXX - This code assumes only one tag per CIPSO option which isn't - * really a good assumption to make but since we only support the MAC - * tags right now it is a safe assumption. */ - switch (cipso_ptr[6]) { - case CIPSO_V4_TAG_RBITMAP: - ret_val = cipso_v4_parsetag_rbm(doi_def, - &cipso_ptr[6], - secattr); - break; - case CIPSO_V4_TAG_ENUM: - ret_val = cipso_v4_parsetag_enum(doi_def, - &cipso_ptr[6], - secattr); - break; - case CIPSO_V4_TAG_RANGE: - ret_val = cipso_v4_parsetag_rng(doi_def, - &cipso_ptr[6], - secattr); - break; - } - rcu_read_unlock(); - - return ret_val; + return cipso_v4_getattr(opt->__data + opt->cipso - sizeof(struct iphdr), + secattr); } /** @@ -1905,45 +1912,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) int cipso_v4_skbuff_getattr(const struct sk_buff *skb, struct netlbl_lsm_secattr *secattr) { - int ret_val = -ENOMSG; - unsigned char *cipso_ptr; - u32 doi; - struct cipso_v4_doi *doi_def; - - cipso_ptr = CIPSO_V4_OPTPTR(skb); - if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) - return 0; - - doi = ntohl(get_unaligned((__be32 *)&cipso_ptr[2])); - rcu_read_lock(); - doi_def = cipso_v4_doi_search(doi); - if (doi_def == NULL) - goto skbuff_getattr_return; - - /* XXX - This code assumes only one tag per CIPSO option which isn't - * really a good assumption to make but since we only support the MAC - * tags right now it is a safe assumption. */ - switch (cipso_ptr[6]) { - case CIPSO_V4_TAG_RBITMAP: - ret_val = cipso_v4_parsetag_rbm(doi_def, - &cipso_ptr[6], - secattr); - break; - case CIPSO_V4_TAG_ENUM: - ret_val = cipso_v4_parsetag_enum(doi_def, - &cipso_ptr[6], - secattr); - break; - case CIPSO_V4_TAG_RANGE: - ret_val = cipso_v4_parsetag_rng(doi_def, - &cipso_ptr[6], - secattr); - break; - } - -skbuff_getattr_return: - rcu_read_unlock(); - return ret_val; + return cipso_v4_getattr(CIPSO_V4_OPTPTR(skb), secattr); } /* From 0b69d4bd263c75b3e2ec94f1c72f338b84be817e Mon Sep 17 00:00:00 2001 From: Milan Kocian Date: Sat, 15 Sep 2007 21:48:27 -0700 Subject: [PATCH 1390/2804] [IPV6]: Remove redundant RTM_DELLINK message. Remove useless message. We get the right message from another subsystem. Signed-off-by: Milan Kocian Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ee55be975407..a68c626567f2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2495,9 +2495,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) else ipv6_mc_down(idev); - /* Step 5: netlink notification of this interface */ idev->tstamp = jiffies; - inet6_ifinfo_notify(RTM_DELLINK, idev); /* Shot the device (if unregistered) */ From 4885a50476b95fa0f4caad179a80783508c2fe86 Mon Sep 17 00:00:00 2001 From: Ed Swierk Date: Sun, 16 Sep 2007 12:21:38 -0700 Subject: [PATCH 1391/2804] [TAP]: Configurable interface MTU. Signed-off-by: David S. Miller --- drivers/net/tun.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d279151f065d..d8b8e68ef70b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -172,6 +172,18 @@ tun_net_mclist(struct net_device *dev) } } +#define MIN_MTU 68 +#define MAX_MTU 65535 + +static int +tun_net_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + /* Initialize net device. */ static void tun_net_init(struct net_device *dev) { @@ -183,6 +195,7 @@ static void tun_net_init(struct net_device *dev) dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = 1500; + dev->change_mtu = tun_net_change_mtu; /* Zero header length */ dev->type = ARPHRD_NONE; @@ -195,6 +208,7 @@ static void tun_net_init(struct net_device *dev) dev->set_multicast_list = tun_net_mclist; ether_setup(dev); + dev->change_mtu = tun_net_change_mtu; /* random address already created for us by tun_set_iff, use it */ memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) ); From 22dd74950172dc8979576e2bef3b439f20ef0b05 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sun, 16 Sep 2007 14:40:49 -0700 Subject: [PATCH 1392/2804] [NET]: migrate HARD_TX_LOCK to header file HARD_TX_LOCK micro is a nice aggregation that could be used in other spots. move it to netdevice.h Also makes sure the previously superflous cpu arguement is used. Thanks to DaveM for the suggestions. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/netdevice.h | 21 +++++++++++++++++++-- net/core/dev.c | 12 ------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index de387c5400b3..96964fb7478b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1265,10 +1265,15 @@ static inline void netif_rx_complete(struct net_device *dev, * * Get network device transmit lock */ -static inline void netif_tx_lock(struct net_device *dev) +static inline void __netif_tx_lock(struct net_device *dev, int cpu) { spin_lock(&dev->_xmit_lock); - dev->xmit_lock_owner = smp_processor_id(); + dev->xmit_lock_owner = cpu; +} + +static inline void netif_tx_lock(struct net_device *dev) +{ + __netif_tx_lock(dev, smp_processor_id()); } static inline void netif_tx_lock_bh(struct net_device *dev) @@ -1297,6 +1302,18 @@ static inline void netif_tx_unlock_bh(struct net_device *dev) spin_unlock_bh(&dev->_xmit_lock); } +#define HARD_TX_LOCK(dev, cpu) { \ + if ((dev->features & NETIF_F_LLTX) == 0) { \ + __netif_tx_lock(dev, cpu); \ + } \ +} + +#define HARD_TX_UNLOCK(dev) { \ + if ((dev->features & NETIF_F_LLTX) == 0) { \ + netif_tx_unlock(dev); \ + } \ +} + static inline void netif_tx_disable(struct net_device *dev) { netif_tx_lock_bh(dev); diff --git a/net/core/dev.c b/net/core/dev.c index 666c112efb55..e9a6d93a194f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1574,18 +1574,6 @@ out_kfree_skb: return 0; } -#define HARD_TX_LOCK(dev, cpu) { \ - if ((dev->features & NETIF_F_LLTX) == 0) { \ - netif_tx_lock(dev); \ - } \ -} - -#define HARD_TX_UNLOCK(dev) { \ - if ((dev->features & NETIF_F_LLTX) == 0) { \ - netif_tx_unlock(dev); \ - } \ -} - /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit From ad7379d49458a863c520a73a3c36441c572f850e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 16 Sep 2007 15:33:32 -0700 Subject: [PATCH 1393/2804] [NET]: Fix the prototype of call_netdevice_notifiers. This replaces the void * parameter with a struct net_device * which is what is actually required. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- net/core/dev.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 96964fb7478b..cf89ce677e41 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -792,7 +792,7 @@ extern void free_netdev(struct net_device *dev); extern void synchronize_net(void); extern int register_netdevice_notifier(struct notifier_block *nb); extern int unregister_netdevice_notifier(struct notifier_block *nb); -extern int call_netdevice_notifiers(unsigned long val, void *v); +extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev); extern struct net_device *dev_get_by_index(struct net *net, int ifindex); extern struct net_device *__dev_get_by_index(struct net *net, int ifindex); extern int dev_restart(struct net_device *dev); diff --git a/net/core/dev.c b/net/core/dev.c index e9a6d93a194f..b517d36e653e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1206,9 +1206,9 @@ int unregister_netdevice_notifier(struct notifier_block *nb) * are as for raw_notifier_call_chain(). */ -int call_netdevice_notifiers(unsigned long val, void *v) +int call_netdevice_notifiers(unsigned long val, struct net_device *dev) { - return raw_notifier_call_chain(&netdev_chain, val, v); + return raw_notifier_call_chain(&netdev_chain, val, dev); } /* When > 0 there are consumers of rx skb time stamps */ From 30d97d35851f40fd1c108d1b8904aca3c38d0126 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 16 Sep 2007 15:40:33 -0700 Subject: [PATCH 1394/2804] [NETNS]: Consolidate hashes creation in netdev_init() The dev_name_hash and the dev_index_hash are now booth kmalloc-ed (and each element is properly initialized as usually) so I think it's worth consolidating this code making it look nicer (and saving 28 bytes of .text section ;) ) Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/core/dev.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index b517d36e653e..cc105ff67db5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4268,32 +4268,39 @@ int netdev_compute_features(unsigned long all, unsigned long one) } EXPORT_SYMBOL(netdev_compute_features); +static struct hlist_head *netdev_create_hash(void) +{ + int i; + struct hlist_head *hash; + + hash = kmalloc(sizeof(*hash) * NETDEV_HASHENTRIES, GFP_KERNEL); + if (hash != NULL) + for (i = 0; i < NETDEV_HASHENTRIES; i++) + INIT_HLIST_HEAD(&hash[i]); + + return hash; +} + /* Initialize per network namespace state */ static int netdev_init(struct net *net) { - int i; INIT_LIST_HEAD(&net->dev_base_head); rwlock_init(&dev_base_lock); - net->dev_name_head = kmalloc( - sizeof(*net->dev_name_head)*NETDEV_HASHENTRIES, GFP_KERNEL); - if (!net->dev_name_head) - return -ENOMEM; + net->dev_name_head = netdev_create_hash(); + if (net->dev_name_head == NULL) + goto err_name; - net->dev_index_head = kmalloc( - sizeof(*net->dev_index_head)*NETDEV_HASHENTRIES, GFP_KERNEL); - if (!net->dev_index_head) { - kfree(net->dev_name_head); - return -ENOMEM; - } - - for (i = 0; i < NETDEV_HASHENTRIES; i++) - INIT_HLIST_HEAD(&net->dev_name_head[i]); - - for (i = 0; i < NETDEV_HASHENTRIES; i++) - INIT_HLIST_HEAD(&net->dev_index_head[i]); + net->dev_index_head = netdev_create_hash(); + if (net->dev_index_head == NULL) + goto err_idx; return 0; + +err_idx: + kfree(net->dev_name_head); +err_name: + return -ENOMEM; } static void netdev_exit(struct net *net) From 056925ab3145713e5e83cf8e05ae6fb2f4ace41e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 16 Sep 2007 15:42:43 -0700 Subject: [PATCH 1395/2804] [NET]: Cleanup calling netdev notifiers. The call_netdev_notifiers routine can successfully be used in the net/core_dev.c itself. This will save 6 lines of code and 62 ;) bytes of .text section. 62 is rather small, but I have one more patch saving ~30 bytes from netns code (sent to Eric), so altogether they can save some more noticeable amount. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/core/dev.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index cc105ff67db5..080d32c4034f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -906,7 +906,7 @@ rollback: hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); write_unlock_bh(&dev_base_lock); - ret = raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); + ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev); ret = notifier_to_errno(ret); if (ret) { @@ -932,7 +932,7 @@ rollback: */ void netdev_features_change(struct net_device *dev) { - raw_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); + call_netdevice_notifiers(NETDEV_FEAT_CHANGE, dev); } EXPORT_SYMBOL(netdev_features_change); @@ -947,8 +947,7 @@ EXPORT_SYMBOL(netdev_features_change); void netdev_state_change(struct net_device *dev) { if (dev->flags & IFF_UP) { - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGE, dev); + call_netdevice_notifiers(NETDEV_CHANGE, dev); rtmsg_ifinfo(RTM_NEWLINK, dev, 0); } } @@ -1044,7 +1043,7 @@ int dev_open(struct net_device *dev) /* * ... and announce new interface. */ - raw_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); + call_netdevice_notifiers(NETDEV_UP, dev); } return ret; } @@ -1069,7 +1068,7 @@ int dev_close(struct net_device *dev) * Tell people we are going down, so that they can * prepare to death, when device is still operating. */ - raw_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); + call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); dev_deactivate(dev); @@ -1102,7 +1101,7 @@ int dev_close(struct net_device *dev) /* * Tell people we are down */ - raw_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); + call_netdevice_notifiers(NETDEV_DOWN, dev); return 0; } @@ -3031,8 +3030,7 @@ 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 | IFF_VOLATILE))) - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGE, dev); + call_netdevice_notifiers(NETDEV_CHANGE, dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { int inc = (flags & IFF_PROMISC) ? +1 : -1; @@ -3078,8 +3076,7 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) else dev->mtu = new_mtu; if (!err && dev->flags & IFF_UP) - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGEMTU, dev); + call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); return err; } @@ -3095,8 +3092,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) return -ENODEV; err = dev->set_mac_address(dev, sa); if (!err) - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGEADDR, dev); + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); return err; } @@ -3152,8 +3148,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGEADDR, dev); + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); return 0; case SIOCGIFMAP: @@ -3597,7 +3592,7 @@ int register_netdevice(struct net_device *dev) list_netdevice(dev); /* Notify protocols, that a new device appeared. */ - ret = raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); + ret = call_netdevice_notifiers(NETDEV_REGISTER, dev); ret = notifier_to_errno(ret); if (ret) unregister_netdevice(dev); @@ -3668,8 +3663,7 @@ static void netdev_wait_allrefs(struct net_device *dev) rtnl_lock(); /* Rebroadcast unregister notification */ - raw_notifier_call_chain(&netdev_chain, - NETDEV_UNREGISTER, dev); + call_netdevice_notifiers(NETDEV_UNREGISTER, dev); if (test_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { @@ -3914,7 +3908,7 @@ void unregister_netdevice(struct net_device *dev) /* Notify protocols, that we are about to destroy this device. They should clean all the things. */ - raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); + call_netdevice_notifiers(NETDEV_UNREGISTER, dev); /* * Flush the unicast and multicast chains From 76c72d4f44ec5fb7f88eda8a0d3aa30922c891d1 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sun, 16 Sep 2007 15:44:27 -0700 Subject: [PATCH 1396/2804] [IPV4/IPV6/DECNET]: Small cleanup for fib rules. This patch slightly cleanups FIB rules framework. rules_list as a pointer on struct fib_rules_ops is useless. It is always assigned with a static per/subsystem list in IPv4, IPv6 and DecNet. Signed-off-by: Denis V. Lunev Acked-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- include/net/fib_rules.h | 2 +- net/core/fib_rules.c | 22 +++++++++++----------- net/decnet/dn_rules.c | 13 ++++++------- net/ipv4/fib_rules.c | 16 +++++++--------- net/ipv6/fib6_rules.c | 8 +++----- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 83e41dd15ccd..017aebd90683 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -65,7 +65,7 @@ struct fib_rules_ops int nlgroup; const struct nla_policy *policy; - struct list_head *rules_list; + struct list_head rules_list; struct module *owner; }; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 1ba71baf87ef..13de6f53f098 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -84,7 +84,7 @@ static void cleanup_ops(struct fib_rules_ops *ops) { struct fib_rule *rule, *tmp; - list_for_each_entry_safe(rule, tmp, ops->rules_list, list) { + list_for_each_entry_safe(rule, tmp, &ops->rules_list, list) { list_del_rcu(&rule->list); fib_rule_put(rule); } @@ -139,7 +139,7 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, rcu_read_lock(); - list_for_each_entry_rcu(rule, ops->rules_list, list) { + list_for_each_entry_rcu(rule, &ops->rules_list, list) { jumped: if (!fib_rule_match(rule, ops, fl, flags)) continue; @@ -271,7 +271,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) if (rule->target <= rule->pref) goto errout_free; - list_for_each_entry(r, ops->rules_list, list) { + list_for_each_entry(r, &ops->rules_list, list) { if (r->pref == rule->target) { rule->ctarget = r; break; @@ -287,7 +287,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) if (err < 0) goto errout_free; - list_for_each_entry(r, ops->rules_list, list) { + list_for_each_entry(r, &ops->rules_list, list) { if (r->pref > rule->pref) break; last = r; @@ -300,7 +300,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) * There are unresolved goto rules in the list, check if * any of them are pointing to this new rule. */ - list_for_each_entry(r, ops->rules_list, list) { + list_for_each_entry(r, &ops->rules_list, list) { if (r->action == FR_ACT_GOTO && r->target == rule->pref) { BUG_ON(r->ctarget != NULL); @@ -320,7 +320,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) if (last) list_add_rcu(&rule->list, &last->list); else - list_add_rcu(&rule->list, ops->rules_list); + list_add_rcu(&rule->list, &ops->rules_list); notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid); flush_route_cache(ops); @@ -359,7 +359,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) if (err < 0) goto errout; - list_for_each_entry(rule, ops->rules_list, list) { + list_for_each_entry(rule, &ops->rules_list, list) { if (frh->action && (frh->action != rule->action)) continue; @@ -402,7 +402,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) * actually been added. */ if (ops->nr_goto_rules > 0) { - list_for_each_entry(tmp, ops->rules_list, list) { + list_for_each_entry(tmp, &ops->rules_list, list) { if (tmp->ctarget == rule) { rcu_assign_pointer(tmp->ctarget, NULL); ops->unresolved_rules++; @@ -498,7 +498,7 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb, int idx = 0; struct fib_rule *rule; - list_for_each_entry(rule, ops->rules_list, list) { + list_for_each_entry(rule, &ops->rules_list, list) { if (idx < cb->args[1]) goto skip; @@ -608,12 +608,12 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event, switch (event) { case NETDEV_REGISTER: list_for_each_entry(ops, &rules_ops, list) - attach_rules(ops->rules_list, dev); + attach_rules(&ops->rules_list, dev); break; case NETDEV_UNREGISTER: list_for_each_entry(ops, &rules_ops, list) - detach_rules(ops->rules_list, dev); + detach_rules(&ops->rules_list, dev); break; } diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 84ff3dd37070..ddd3f04f0919 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -57,8 +57,6 @@ static struct dn_fib_rule default_rule = { }, }; -static LIST_HEAD(dn_fib_rules); - int dn_fib_lookup(struct flowi *flp, struct dn_fib_res *res) { @@ -228,9 +226,9 @@ static u32 dn_fib_rule_default_pref(void) struct list_head *pos; struct fib_rule *rule; - if (!list_empty(&dn_fib_rules)) { - pos = dn_fib_rules.next; - if (pos->next != &dn_fib_rules) { + if (!list_empty(&dn_fib_rules_ops.rules_list)) { + pos = dn_fib_rules_ops.rules_list.next; + if (pos->next != &dn_fib_rules_ops.rules_list) { rule = list_entry(pos->next, struct fib_rule, list); if (rule->pref) return rule->pref - 1; @@ -258,13 +256,14 @@ static struct fib_rules_ops dn_fib_rules_ops = { .flush_cache = dn_fib_rule_flush_cache, .nlgroup = RTNLGRP_DECnet_RULE, .policy = dn_fib_rule_policy, - .rules_list = &dn_fib_rules, + .rules_list = LIST_HEAD_INIT(dn_fib_rules_ops.rules_list), .owner = THIS_MODULE, }; void __init dn_fib_rules_init(void) { - list_add_tail(&default_rule.common.list, &dn_fib_rules); + list_add_tail(&default_rule.common.list, + &dn_fib_rules_ops.rules_list); fib_rules_register(&dn_fib_rules_ops); } diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 2a947840210e..f16839c6a721 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -76,8 +76,6 @@ static struct fib4_rule local_rule = { }, }; -static LIST_HEAD(fib4_rules); - #ifdef CONFIG_NET_CLS_ROUTE u32 fib_rules_tclass(struct fib_result *res) { @@ -279,9 +277,9 @@ static u32 fib4_rule_default_pref(void) struct list_head *pos; struct fib_rule *rule; - if (!list_empty(&fib4_rules)) { - pos = fib4_rules.next; - if (pos->next != &fib4_rules) { + if (!list_empty(&fib4_rules_ops.rules_list)) { + pos = fib4_rules_ops.rules_list.next; + if (pos->next != &fib4_rules_ops.rules_list) { rule = list_entry(pos->next, struct fib_rule, list); if (rule->pref) return rule->pref - 1; @@ -317,15 +315,15 @@ static struct fib_rules_ops fib4_rules_ops = { .flush_cache = fib4_rule_flush_cache, .nlgroup = RTNLGRP_IPV4_RULE, .policy = fib4_rule_policy, - .rules_list = &fib4_rules, + .rules_list = LIST_HEAD_INIT(fib4_rules_ops.rules_list), .owner = THIS_MODULE, }; void __init fib4_rules_init(void) { - list_add_tail(&local_rule.common.list, &fib4_rules); - list_add_tail(&main_rule.common.list, &fib4_rules); - list_add_tail(&default_rule.common.list, &fib4_rules); + list_add_tail(&local_rule.common.list, &fib4_rules_ops.rules_list); + list_add_tail(&main_rule.common.list, &fib4_rules_ops.rules_list); + list_add_tail(&default_rule.common.list, &fib4_rules_ops.rules_list); fib_rules_register(&fib4_rules_ops); } diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 53b3998a486c..706622af206f 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -50,8 +50,6 @@ static struct fib6_rule local_rule = { }, }; -static LIST_HEAD(fib6_rules); - struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, pol_lookup_t lookup) { @@ -268,14 +266,14 @@ static struct fib_rules_ops fib6_rules_ops = { .nlmsg_payload = fib6_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV6_RULE, .policy = fib6_rule_policy, - .rules_list = &fib6_rules, + .rules_list = LIST_HEAD_INIT(fib6_rules_ops.rules_list), .owner = THIS_MODULE, }; void __init fib6_rules_init(void) { - list_add_tail(&local_rule.common.list, &fib6_rules); - list_add_tail(&main_rule.common.list, &fib6_rules); + list_add_tail(&local_rule.common.list, &fib6_rules_ops.rules_list); + list_add_tail(&main_rule.common.list, &fib6_rules_ops.rules_list); fib_rules_register(&fib6_rules_ops); } From 131a47e31ab1a9defd50ff16b04008ab94c21c0d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sun, 16 Sep 2007 15:53:56 -0700 Subject: [PATCH 1397/2804] [SCTP]: Implement the Supported Extensions Parameter SCTP Supported Extenions parameter is specified in Section 4.2.7 of the ADD-IP draft (soon to be RFC). The parameter is encoded as: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Parameter Type = 0x8008 | Parameter Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | CHUNK TYPE 1 | CHUNK TYPE 2 | CHUNK TYPE 3 | CHUNK TYPE 4 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | .... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | CHUNK TYPE N | PAD | PAD | PAD | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ It contains a list of chunks that a particular SCTP extension uses. Current extensions supported are Partial Reliability (FWD-TSN) and ADD-IP (ASCONF and ASCONF-ACK). When implementing new extensions (AUTH, PKT-DROP, etc..), new chunks need to be added to this parameter. Parameter processing would be modified to negotiate support for these new features. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/linux/sctp.h | 9 ++++ include/net/sctp/structs.h | 1 + net/sctp/sm_make_chunk.c | 91 +++++++++++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/include/linux/sctp.h b/include/linux/sctp.h index d70df61a029f..f4d717b72ddd 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -180,6 +180,9 @@ typedef enum { SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), + /* Add-IP: Supported Extensions, Section 4.2 */ + SCTP_PARAM_SUPPORTED_EXT = __constant_htons(0x8008), + /* PR-SCTP Sec 3.1 */ SCTP_PARAM_FWD_TSN_SUPPORT = __constant_htons(0xc000), @@ -296,6 +299,12 @@ typedef struct sctp_adaptation_ind_param { __be32 adaptation_ind; } __attribute__((packed)) sctp_adaptation_ind_param_t; +/* ADDIP Section 4.2.7 Supported Extensions Parameter */ +typedef struct sctp_supported_ext_param { + struct sctp_paramhdr param_hdr; + __u8 chunks[0]; +} __attribute__((packed)) sctp_supported_ext_param_t; + /* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): * The INIT ACK chunk is used to acknowledge the initiation of an SCTP * association. diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 67c91d01b635..b4812a2d3bb0 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -440,6 +440,7 @@ union sctp_params { struct sctp_ipv6addr_param *v6; union sctp_addr_param *addr; struct sctp_adaptation_ind_param *aind; + struct sctp_supported_ext_param *ext; }; /* RFC 2960. Section 3.3.5 Heartbeat. diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index d84e575f7409..71cc204a9ea5 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -179,6 +179,9 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, sctp_supported_addrs_param_t sat; __be16 types[2]; sctp_adaptation_ind_param_t aiparam; + sctp_supported_ext_param_t ext_param; + int num_ext = 0; + __u8 extensions[3]; /* RFC 2960 3.3.2 Initiation (INIT) (1) * @@ -202,11 +205,31 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); chunksize += sizeof(ecap_param); - if (sctp_prsctp_enable) + if (sctp_prsctp_enable) { chunksize += sizeof(prsctp_param); + extensions[num_ext] = SCTP_CID_FWD_TSN; + num_ext += 1; + } + /* ADDIP: Section 4.2.7: + * An implementation supporting this extension [ADDIP] MUST list + * the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and + * INIT-ACK parameters. + * XXX: We don't support AUTH just yet, so don't list it. AUTH + * support should add it. + */ + if (sctp_addip_enable) { + extensions[num_ext] = SCTP_CID_ASCONF; + extensions[num_ext+1] = SCTP_CID_ASCONF_ACK; + num_ext += 2; + } + chunksize += sizeof(aiparam); chunksize += vparam_len; + /* If we have any extensions to report, account for that */ + if (num_ext) + chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; + /* RFC 2960 3.3.2 Initiation (INIT) (1) * * Note 3: An INIT chunk MUST NOT contain more than one Host @@ -241,12 +264,27 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, sctp_addto_chunk(retval, num_types * sizeof(__u16), &types); sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); + + /* Add the supported extensions paramter. Be nice and add this + * fist before addiding the parameters for the extensions themselves + */ + if (num_ext) { + ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT; + ext_param.param_hdr.length = + htons(sizeof(sctp_supported_ext_param_t) + num_ext); + sctp_addto_chunk(retval, sizeof(sctp_supported_ext_param_t), + &ext_param); + sctp_addto_chunk(retval, num_ext, extensions); + } + if (sctp_prsctp_enable) sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); + aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND; aiparam.param_hdr.length = htons(sizeof(aiparam)); aiparam.adaptation_ind = htonl(sp->adaptation_ind); sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); + nodata: kfree(addrs.v); return retval; @@ -264,6 +302,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, int cookie_len; size_t chunksize; sctp_adaptation_ind_param_t aiparam; + sctp_supported_ext_param_t ext_param; + int num_ext = 0; + __u8 extensions[3]; retval = NULL; @@ -294,9 +335,19 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, chunksize += sizeof(ecap_param); /* Tell peer that we'll do PR-SCTP only if peer advertised. */ - if (asoc->peer.prsctp_capable) + if (asoc->peer.prsctp_capable) { chunksize += sizeof(prsctp_param); + extensions[num_ext] = SCTP_CID_FWD_TSN; + num_ext += 1; + } + if (sctp_addip_enable) { + extensions[num_ext] = SCTP_CID_ASCONF; + extensions[num_ext+1] = SCTP_CID_ASCONF_ACK; + num_ext += 2; + } + + chunksize += sizeof(ext_param) + num_ext; chunksize += sizeof(aiparam); /* Now allocate and fill out the chunk. */ @@ -314,6 +365,14 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, sctp_addto_chunk(retval, cookie_len, cookie); if (asoc->peer.ecn_capable) sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); + if (num_ext) { + ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT; + ext_param.param_hdr.length = + htons(sizeof(sctp_supported_ext_param_t) + num_ext); + sctp_addto_chunk(retval, sizeof(sctp_supported_ext_param_t), + &ext_param); + sctp_addto_chunk(retval, num_ext, extensions); + } if (asoc->peer.prsctp_capable) sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); @@ -1664,6 +1723,28 @@ static int sctp_process_hn_param(const struct sctp_association *asoc, return 0; } +static void sctp_process_ext_param(struct sctp_association *asoc, + union sctp_params param) +{ + __u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t); + int i; + + for (i = 0; i < num_ext; i++) { + switch (param.ext->chunks[i]) { + case SCTP_CID_FWD_TSN: + if (sctp_prsctp_enable && + !asoc->peer.prsctp_capable) + asoc->peer.prsctp_capable = 1; + break; + case SCTP_CID_ASCONF: + case SCTP_CID_ASCONF_ACK: + /* don't need to do anything for ASCONF */ + default: + break; + } + } +} + /* RFC 3.2.1 & the Implementers Guide 2.2. * * The Parameter Types are encoded such that the @@ -1780,11 +1861,13 @@ static int sctp_verify_param(const struct sctp_association *asoc, case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: case SCTP_PARAM_ECN_CAPABLE: case SCTP_PARAM_ADAPTATION_LAYER_IND: + case SCTP_PARAM_SUPPORTED_EXT: break; case SCTP_PARAM_HOST_NAME_ADDRESS: /* Tell the peer, we won't support this param. */ return sctp_process_hn_param(asoc, param, chunk, err_chunk); + case SCTP_PARAM_FWD_TSN_SUPPORT: if (sctp_prsctp_enable) break; @@ -2129,6 +2212,10 @@ static int sctp_process_param(struct sctp_association *asoc, asoc->peer.adaptation_ind = param.aind->adaptation_ind; break; + case SCTP_PARAM_SUPPORTED_EXT: + sctp_process_ext_param(asoc, param); + break; + case SCTP_PARAM_FWD_TSN_SUPPORT: if (sctp_prsctp_enable) { asoc->peer.prsctp_capable = 1; From 007e3936bdaaa012483c9fe06ca71c272458c710 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sun, 16 Sep 2007 16:04:37 -0700 Subject: [PATCH 1398/2804] [SCTP]: Move sysctl_sctp_[rw]mem definitions to protocol.c The sctp_[rw]mem definitions should really be in protocol.c since that is where they are initialized. This also allows one to build a kernel without sysctl support. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/protocol.c | 6 +++--- net/sctp/sysctl.c | 11 +++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 54edcd978f75..3ec8b12b6da4 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -84,9 +84,9 @@ static struct sctp_af *sctp_af_v6_specific; struct kmem_cache *sctp_chunk_cachep __read_mostly; struct kmem_cache *sctp_bucket_cachep __read_mostly; -extern int sysctl_sctp_mem[3]; -extern int sysctl_sctp_rmem[3]; -extern int sysctl_sctp_wmem[3]; +int sysctl_sctp_mem[3]; +int sysctl_sctp_rmem[3]; +int sysctl_sctp_wmem[3]; /* Return the address of the control sock. */ struct sock *sctp_get_ctl_sock(void) diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index ba75ef4669e3..39b10ee2f017 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -52,14 +52,9 @@ static int int_max = INT_MAX; static long sack_timer_min = 1; static long sack_timer_max = 500; -int sysctl_sctp_mem[3]; -int sysctl_sctp_rmem[3]; -int sysctl_sctp_wmem[3]; - -/* - * per assoc memory limitationf for sends - */ -int sysctl_sctp_wmem[3]; +extern int sysctl_sctp_mem[3]; +extern int sysctl_sctp_rmem[3]; +extern int sysctl_sctp_wmem[3]; static ctl_table sctp_table[] = { { From 0cfad07555312468296ea3bbbcdf99038f58678b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 16 Sep 2007 16:24:44 -0700 Subject: [PATCH 1399/2804] [NETLINK]: Avoid pointer in netlink_run_queue I was looking at Patrick's fix to inet_diag and it occured to me that we're using a pointer argument to return values unnecessarily in netlink_run_queue. Changing it to return the value will allow the compiler to generate better code since the value won't have to be memory-backed. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/netlink.h | 2 +- net/core/rtnetlink.c | 2 +- net/ipv4/inet_diag.c | 2 +- net/netfilter/nfnetlink.c | 2 +- net/netlink/af_netlink.c | 18 ++++++++++-------- net/netlink/genetlink.c | 2 +- net/xfrm/xfrm_user.c | 2 +- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 695e613a207b..83113dfcbd04 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -220,7 +220,7 @@ struct nl_info { u32 pid; }; -extern void netlink_run_queue(struct sock *sk, unsigned int *qlen, +extern unsigned int netlink_run_queue(struct sock *sk, unsigned int qlen, int (*cb)(struct sk_buff *, struct nlmsghdr *)); extern int nlmsg_notify(struct sock *sk, struct sk_buff *skb, diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1b9c32d79917..739fbad15c6a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1320,7 +1320,7 @@ static void rtnetlink_rcv(struct sock *sk, int len) do { mutex_lock(&rtnl_mutex); - netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg); + qlen = netlink_run_queue(sk, qlen, &rtnetlink_rcv_msg); mutex_unlock(&rtnl_mutex); netdev_run_todo(); diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 031cc4856b49..b04a6ee5a9a1 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -845,7 +845,7 @@ static void inet_diag_rcv(struct sock *sk, int len) do { mutex_lock(&inet_diag_mutex); - netlink_run_queue(sk, &qlen, &inet_diag_rcv_msg); + qlen = netlink_run_queue(sk, qlen, &inet_diag_rcv_msg); mutex_unlock(&inet_diag_mutex); } while (qlen); } diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index fa974e8e0ce6..4aa56e7ff156 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -248,7 +248,7 @@ static void nfnetlink_rcv(struct sock *sk, int len) do { if (nfnl_trylock()) return; - netlink_run_queue(sk, &qlen, nfnetlink_rcv_msg); + qlen = netlink_run_queue(sk, qlen, nfnetlink_rcv_msg); __nfnl_unlock(); } while (qlen); } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index dc9f8c2ab1d5..c68888b25756 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1629,7 +1629,7 @@ skip: /** * nelink_run_queue - Process netlink receive queue. * @sk: Netlink socket containing the queue - * @qlen: Place to store queue length upon entry + * @qlen: Initial queue length * @cb: Callback function invoked for each netlink message found * * Processes as much as there was in the queue upon entry and invokes @@ -1639,35 +1639,37 @@ skip: * returns with a qlen != 0. * * qlen must be initialized to 0 before the initial entry, afterwards - * the function may be called repeatedly until qlen reaches 0. + * the function may be called repeatedly until the returned qlen is 0. * * The callback function may return -EINTR to signal that processing * of netlink messages shall be interrupted. In this case the message * currently being processed will NOT be requeued onto the receive * queue. */ -void netlink_run_queue(struct sock *sk, unsigned int *qlen, - int (*cb)(struct sk_buff *, struct nlmsghdr *)) +unsigned int netlink_run_queue(struct sock *sk, unsigned int qlen, + int (*cb)(struct sk_buff *, struct nlmsghdr *)) { struct sk_buff *skb; - if (!*qlen || *qlen > skb_queue_len(&sk->sk_receive_queue)) - *qlen = skb_queue_len(&sk->sk_receive_queue); + if (!qlen || qlen > skb_queue_len(&sk->sk_receive_queue)) + qlen = skb_queue_len(&sk->sk_receive_queue); - for (; *qlen; (*qlen)--) { + for (; qlen; qlen--) { skb = skb_dequeue(&sk->sk_receive_queue); if (netlink_rcv_skb(skb, cb)) { if (skb->len) skb_queue_head(&sk->sk_receive_queue, skb); else { kfree_skb(skb); - (*qlen)--; + qlen--; } break; } kfree_skb(skb); } + + return qlen; } /** diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index af8fe26815fa..07ef5d204a0f 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -485,7 +485,7 @@ static void genl_rcv(struct sock *sk, int len) do { if (genl_trylock()) return; - netlink_run_queue(sk, &qlen, genl_rcv_msg); + qlen = netlink_run_queue(sk, qlen, genl_rcv_msg); genl_unlock(); } while (qlen && genl_sock && genl_sock->sk_receive_queue.qlen); } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 1f8e7c22ddbd..8e10e9098a83 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1887,7 +1887,7 @@ static void xfrm_netlink_rcv(struct sock *sk, int len) do { mutex_lock(&xfrm_cfg_mutex); - netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); + qlen = netlink_run_queue(sk, qlen, &xfrm_user_rcv_msg); mutex_unlock(&xfrm_cfg_mutex); } while (qlen); From 52886051ffdc087a4f7f11540395fd64040101ad Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 16 Sep 2007 16:32:11 -0700 Subject: [PATCH 1400/2804] [SKBUFF]: Fix up csum_start when head room changes Thanks for noticing the bug where csum_start is not updated when the head room changes. This patch fixes that. It also moves the csum/ip_summed copying into copy_skb_header so that skb_copy_expand gets it too. I've checked its callers and no one should be upset by this. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/core/skbuff.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 35021eb3ed07..944189d96323 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -472,6 +472,9 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #ifdef CONFIG_INET new->sp = secpath_get(old->sp); #endif + new->csum_start = old->csum_start; + new->csum_offset = old->csum_offset; + new->ip_summed = old->ip_summed; new->transport_header = old->transport_header; new->network_header = old->network_header; new->mac_header = old->mac_header; @@ -545,8 +548,6 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask) skb_reserve(n, headerlen); /* Set the tail pointer and length */ skb_put(n, skb->len); - n->csum = skb->csum; - n->ip_summed = skb->ip_summed; if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len)) BUG(); @@ -589,8 +590,6 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask) skb_put(n, skb_headlen(skb)); /* Copy the bytes */ skb_copy_from_linear_data(skb, n->data, n->len); - n->csum = skb->csum; - n->ip_summed = skb->ip_summed; n->truesize += skb->data_len; n->data_len = skb->data_len; @@ -686,6 +685,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, skb->transport_header += off; skb->network_header += off; skb->mac_header += off; + skb->csum_start += off; skb->cloned = 0; skb->hdr_len = 0; skb->nohdr = 0; @@ -734,9 +734,6 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom) * * You must pass %GFP_ATOMIC as the allocation priority if this function * is called from an interrupt. - * - * BUG ALERT: ip_summed is not copied. Why does this work? Is it used - * only by netfilter in the cases when checksum is recalculated? --ANK */ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom, int newtailroom, @@ -749,7 +746,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, gfp_mask); int oldheadroom = skb_headroom(skb); int head_copy_len, head_copy_off; - int off = 0; + int off; if (!n) return NULL; @@ -773,12 +770,13 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, copy_skb_header(n, skb); -#ifdef NET_SKBUFF_DATA_USES_OFFSET off = newheadroom - oldheadroom; -#endif + n->csum_start += off; +#ifdef NET_SKBUFF_DATA_USES_OFFSET n->transport_header += off; n->network_header += off; n->mac_header += off; +#endif return n; } From 99406c885ab27c369fa4a1b15c4a5a5ad0d61fcd Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Sun, 16 Sep 2007 16:34:39 -0700 Subject: [PATCH 1401/2804] [NETLINK]: use the macro min(x,y) provided by instead Signed-off-by: Denis Cheng Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c68888b25756..bca93e19bf40 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1969,7 +1969,7 @@ static int __init netlink_proto_init(void) order = get_bitmask_order(max) - 1 + PAGE_SHIFT; max = (1UL << order) / sizeof(struct hlist_head); - order = get_bitmask_order(max > UINT_MAX ? UINT_MAX : max) - 1; + order = get_bitmask_order(min(max, (unsigned long)UINT_MAX)) - 1; for (i = 0; i < MAX_LINKS; i++) { struct nl_pid_hash *hash = &nl_table[i].hash; From 26ff5ddc5ab11e37ab3db469f24324e0ef1d6f63 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Sun, 16 Sep 2007 16:36:02 -0700 Subject: [PATCH 1402/2804] [NETLINK]: the temp variable name max is ambiguous with the macro max provided by , so changed its name to a more proper one: limit Signed-off-by: Denis Cheng Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index bca93e19bf40..46eb5ea1fbd7 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1949,7 +1949,7 @@ static int __init netlink_proto_init(void) { struct sk_buff *dummy_skb; int i; - unsigned long max; + unsigned long limit; unsigned int order; int err = proto_register(&netlink_proto, 0); @@ -1963,13 +1963,13 @@ static int __init netlink_proto_init(void) goto panic; if (num_physpages >= (128 * 1024)) - max = num_physpages >> (21 - PAGE_SHIFT); + limit = num_physpages >> (21 - PAGE_SHIFT); else - max = num_physpages >> (23 - PAGE_SHIFT); + limit = num_physpages >> (23 - PAGE_SHIFT); - order = get_bitmask_order(max) - 1 + PAGE_SHIFT; - max = (1UL << order) / sizeof(struct hlist_head); - order = get_bitmask_order(min(max, (unsigned long)UINT_MAX)) - 1; + order = get_bitmask_order(limit) - 1 + PAGE_SHIFT; + limit = (1UL << order) / sizeof(struct hlist_head); + order = get_bitmask_order(min(limit, (unsigned long)UINT_MAX)) - 1; for (i = 0; i < MAX_LINKS; i++) { struct nl_pid_hash *hash = &nl_table[i].hash; From c40f6fff401f693f627d3d44ef7663b993943517 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Sun, 16 Sep 2007 16:39:25 -0700 Subject: [PATCH 1403/2804] [IPV4] af_inet.c: use ARRAY_SIZE macro from kernel.h instead Signed-off-by: Denis Cheng Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 110a19edacc8..e594a2c89661 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -942,7 +942,7 @@ static struct inet_protosw inetsw_array[] = } }; -#define INETSW_ARRAY_LEN (sizeof(inetsw_array) / sizeof(struct inet_protosw)) +#define INETSW_ARRAY_LEN ARRAY_SIZE(inetsw_array) void inet_register_protosw(struct inet_protosw *p) { From 8b14a536701b50559a0d69d5d593323f550db4e9 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Sun, 16 Sep 2007 16:41:29 -0700 Subject: [PATCH 1404/2804] [NET]: all net/ cleanup with ARRAY_SIZE Signed-off-by: Denis Cheng --- net/atm/proc.c | 2 +- net/decnet/dn_dev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/atm/proc.c b/net/atm/proc.c index 3a6be64b0512..5d9d5ffba145 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -176,7 +176,7 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) seq_printf(seq, "%3d %3d %5d %-3s %7d %-5s %7d %-6s", vcc->dev->number,vcc->vpi,vcc->vci, - vcc->qos.aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" : + vcc->qos.aal >= ARRAY_SIZE(aal_name) ? "err" : aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr, class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr, class_name[vcc->qos.txtp.traffic_class]); diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index ddfd2aff44d8..fa24614b5a37 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -150,7 +150,7 @@ static struct dn_dev_parms dn_dev_list[] = { } }; -#define DN_DEV_LIST_SIZE (sizeof(dn_dev_list)/sizeof(struct dn_dev_parms)) +#define DN_DEV_LIST_SIZE ARRAY_SIZE(dn_dev_list) #define DN_DEV_PARMS_OFFSET(x) ((int) ((char *) &((struct dn_dev_parms *)0)->x)) From 14878f75abd5bf1d38becb405801cd491ee215dc Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Sun, 16 Sep 2007 16:52:35 -0700 Subject: [PATCH 1405/2804] [IPV6]: Add ICMPMsgStats MIB (RFC 4293) [rev 2] Background: RFC 4293 deprecates existing individual, named ICMP type counters to be replaced with the ICMPMsgStatsTable. This table includes entries for both IPv4 and IPv6, and requires counting of all ICMP types, whether or not the machine implements the type. These patches "remove" (but not really) the existing counters, and replace them with the ICMPMsgStats tables for v4 and v6. It includes the named counters in the /proc places they were, but gets the values for them from the new tables. It also counts packets generated from raw socket output (e.g., OutEchoes, MLD queries, RA's from radvd, etc). Changes: 1) create icmpmsg_statistics mib 2) create icmpv6msg_statistics mib 3) modify existing counters to use these 4) modify /proc/net/snmp to add "IcmpMsg" with all ICMP types listed by number for easy SNMP parsing 5) modify /proc/net/snmp printing for "Icmp" to get the named data from new counters. [new to 2nd revision] 6) support per-interface ICMP stats 7) use common macro for per-device stat macros Signed-off-by: David L Stevens Signed-off-by: David S. Miller --- include/linux/snmp.h | 27 +------------ include/net/if_inet6.h | 1 + include/net/ipv6.h | 69 +++++++++++++++---------------- include/net/snmp.h | 6 +++ net/ipv6/addrconf.c | 7 ++++ net/ipv6/af_inet6.c | 5 +++ net/ipv6/icmp.c | 12 ++---- net/ipv6/ip6_output.c | 7 ++++ net/ipv6/mcast.c | 12 +++--- net/ipv6/ndisc.c | 21 +++++----- net/ipv6/proc.c | 92 ++++++++++++++++++++++++++---------------- 11 files changed, 136 insertions(+), 123 deletions(-) diff --git a/include/linux/snmp.h b/include/linux/snmp.h index d24c55473821..86977e31548a 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -91,35 +91,12 @@ enum ICMP6_MIB_NUM = 0, ICMP6_MIB_INMSGS, /* InMsgs */ ICMP6_MIB_INERRORS, /* InErrors */ - ICMP6_MIB_INDESTUNREACHS, /* InDestUnreachs */ - ICMP6_MIB_INPKTTOOBIGS, /* InPktTooBigs */ - ICMP6_MIB_INTIMEEXCDS, /* InTimeExcds */ - ICMP6_MIB_INPARMPROBLEMS, /* InParmProblems */ - ICMP6_MIB_INECHOS, /* InEchos */ - ICMP6_MIB_INECHOREPLIES, /* InEchoReplies */ - ICMP6_MIB_INGROUPMEMBQUERIES, /* InGroupMembQueries */ - ICMP6_MIB_INGROUPMEMBRESPONSES, /* InGroupMembResponses */ - ICMP6_MIB_INGROUPMEMBREDUCTIONS, /* InGroupMembReductions */ - ICMP6_MIB_INROUTERSOLICITS, /* InRouterSolicits */ - ICMP6_MIB_INROUTERADVERTISEMENTS, /* InRouterAdvertisements */ - ICMP6_MIB_INNEIGHBORSOLICITS, /* InNeighborSolicits */ - ICMP6_MIB_INNEIGHBORADVERTISEMENTS, /* InNeighborAdvertisements */ - ICMP6_MIB_INREDIRECTS, /* InRedirects */ ICMP6_MIB_OUTMSGS, /* OutMsgs */ - ICMP6_MIB_OUTDESTUNREACHS, /* OutDestUnreachs */ - ICMP6_MIB_OUTPKTTOOBIGS, /* OutPktTooBigs */ - ICMP6_MIB_OUTTIMEEXCDS, /* OutTimeExcds */ - ICMP6_MIB_OUTPARMPROBLEMS, /* OutParmProblems */ - ICMP6_MIB_OUTECHOREPLIES, /* OutEchoReplies */ - ICMP6_MIB_OUTROUTERSOLICITS, /* OutRouterSolicits */ - ICMP6_MIB_OUTNEIGHBORSOLICITS, /* OutNeighborSolicits */ - ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS, /* OutNeighborAdvertisements */ - ICMP6_MIB_OUTREDIRECTS, /* OutRedirects */ - ICMP6_MIB_OUTGROUPMEMBRESPONSES, /* OutGroupMembResponses */ - ICMP6_MIB_OUTGROUPMEMBREDUCTIONS, /* OutGroupMembReductions */ __ICMP6_MIB_MAX }; +#define __ICMP6MSG_MIB_MAX 512 /* Out+In for all 8-bit ICMPv6 types */ + /* tcp mib definitions */ /* * RFC 1213: MIB-II TCP group diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 3ec7d07346d6..448eccb20638 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -154,6 +154,7 @@ struct ipv6_devstat { struct proc_dir_entry *proc_dir_entry; DEFINE_SNMP_STAT(struct ipstats_mib, ipv6); DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6); + DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg); }; struct inet6_dev diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9573c8d19153..31b3f1b45a2b 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -112,45 +112,28 @@ struct frag_hdr { extern int sysctl_ipv6_bindv6only; extern int sysctl_mld_max_msf; +#define _DEVINC(statname, modifier, idev, field) \ +({ \ + struct inet6_dev *_idev = (idev); \ + if (likely(_idev != NULL)) \ + SNMP_INC_STATS##modifier((_idev)->stats.statname, (field)); \ + SNMP_INC_STATS##modifier(statname##_statistics, (field)); \ +}) + /* MIBs */ DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics); -#define IP6_INC_STATS(idev,field) ({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - SNMP_INC_STATS(_idev->stats.ipv6, field); \ - SNMP_INC_STATS(ipv6_statistics, field); \ -}) -#define IP6_INC_STATS_BH(idev,field) ({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - SNMP_INC_STATS_BH(_idev->stats.ipv6, field); \ - SNMP_INC_STATS_BH(ipv6_statistics, field); \ -}) -#define IP6_INC_STATS_USER(idev,field) ({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - SNMP_INC_STATS_USER(_idev->stats.ipv6, field); \ - SNMP_INC_STATS_USER(ipv6_statistics, field); \ -}) + +#define IP6_INC_STATS(idev,field) _DEVINC(ipv6, , idev, field) +#define IP6_INC_STATS_BH(idev,field) _DEVINC(ipv6, _BH, idev, field) +#define IP6_INC_STATS_USER(idev,field) _DEVINC(ipv6, _USER, idev, field) + DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); -#define ICMP6_INC_STATS(idev, field) ({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - SNMP_INC_STATS(idev->stats.icmpv6, field); \ - SNMP_INC_STATS(icmpv6_statistics, field); \ -}) -#define ICMP6_INC_STATS_BH(idev, field) ({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - SNMP_INC_STATS_BH((_idev)->stats.icmpv6, field); \ - SNMP_INC_STATS_BH(icmpv6_statistics, field); \ -}) -#define ICMP6_INC_STATS_USER(idev, field) ({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - SNMP_INC_STATS_USER(_idev->stats.icmpv6, field); \ - SNMP_INC_STATS_USER(icmpv6_statistics, field); \ -}) +DECLARE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics); + +#define ICMP6_INC_STATS(idev, field) _DEVINC(icmpv6, , idev, field) +#define ICMP6_INC_STATS_BH(idev, field) _DEVINC(icmpv6, _BH, idev, field) +#define ICMP6_INC_STATS_USER(idev, field) _DEVINC(icmpv6, _USER, idev, field) + #define ICMP6_INC_STATS_OFFSET_BH(idev, field, offset) ({ \ struct inet6_dev *_idev = idev; \ __typeof__(offset) _offset = (offset); \ @@ -158,6 +141,20 @@ DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); SNMP_INC_STATS_OFFSET_BH(_idev->stats.icmpv6, field, _offset); \ SNMP_INC_STATS_OFFSET_BH(icmpv6_statistics, field, _offset); \ }) + +#define ICMP6MSGOUT_INC_STATS(idev, field) \ + _DEVINC(icmpv6msg, , idev, field +256) +#define ICMP6MSGOUT_INC_STATS_BH(idev, field) \ + _DEVINC(icmpv6msg, _BH, idev, field +256) +#define ICMP6MSGOUT_INC_STATS_USER(idev, field) \ + _DEVINC(icmpv6msg, _USER, idev, field +256) +#define ICMP6MSGIN_INC_STATS(idev, field) \ + _DEVINC(icmpv6msg, , idev, field) +#define ICMP6MSGIN_INC_STATS_BH(idev, field) \ + _DEVINC(icmpv6msg, _BH, idev, field) +#define ICMP6MSGIN_INC_STATS_USER(idev, field) \ + _DEVINC(icmpv6msg, _USER, idev, field) + DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); #define UDP6_INC_STATS_BH(field, is_udplite) do { \ diff --git a/include/net/snmp.h b/include/net/snmp.h index 464970e39ec0..a566e11d2f98 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -88,6 +88,12 @@ struct icmpv6_mib { unsigned long mibs[ICMP6_MIB_MAX]; } __SNMP_MIB_ALIGN__; +#define ICMP6MSG_MIB_MAX __ICMP6MSG_MIB_MAX +struct icmpv6msg_mib { + unsigned long mibs[ICMP6MSG_MIB_MAX]; +} __SNMP_MIB_ALIGN__; + + /* TCP */ #define TCP_MIB_MAX __TCP_MIB_MAX struct tcp_mib { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a68c626567f2..9c2e94f1c637 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -261,9 +261,15 @@ static int snmp6_alloc_dev(struct inet6_dev *idev) sizeof(struct icmpv6_mib), __alignof__(struct icmpv6_mib)) < 0) goto err_icmp; + if (snmp_mib_init((void **)idev->stats.icmpv6msg, + sizeof(struct icmpv6msg_mib), + __alignof__(struct icmpv6msg_mib)) < 0) + goto err_icmpmsg; return 0; +err_icmpmsg: + snmp_mib_free((void **)idev->stats.icmpv6); err_icmp: snmp_mib_free((void **)idev->stats.ipv6); err_ip: @@ -272,6 +278,7 @@ err_ip: static int snmp6_free_dev(struct inet6_dev *idev) { + snmp_mib_free((void **)idev->stats.icmpv6msg); snmp_mib_free((void **)idev->stats.icmpv6); snmp_mib_free((void **)idev->stats.ipv6); return 0; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e5c5aad44bb1..bc929381fa46 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -719,6 +719,9 @@ static int __init init_ipv6_mibs(void) if (snmp_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib), __alignof__(struct icmpv6_mib)) < 0) goto err_icmp_mib; + if (snmp_mib_init((void **)icmpv6msg_statistics, + sizeof (struct icmpv6msg_mib), __alignof__(struct icmpv6_mib)) < 0) + goto err_icmpmsg_mib; if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), __alignof__(struct udp_mib)) < 0) goto err_udp_mib; @@ -730,6 +733,8 @@ static int __init init_ipv6_mibs(void) err_udplite_mib: snmp_mib_free((void **)udp_stats_in6); err_udp_mib: + snmp_mib_free((void **)icmpv6msg_statistics); +err_icmpmsg_mib: snmp_mib_free((void **)icmpv6_statistics); err_icmp_mib: snmp_mib_free((void **)ipv6_statistics); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 6a6714d154ed..47b8ce232e84 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -69,6 +69,8 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly; EXPORT_SYMBOL(icmpv6_statistics); +DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics) __read_mostly; +EXPORT_SYMBOL(icmpv6msg_statistics); /* * The ICMP socket(s). This is the most convenient way to flow control @@ -456,8 +458,6 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, } err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr)); - if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) - ICMP6_INC_STATS_OFFSET_BH(idev, ICMP6_MIB_OUTDESTUNREACHS, type - ICMPV6_DEST_UNREACH); ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); out_put: @@ -547,9 +547,6 @@ static void icmpv6_echo_reply(struct sk_buff *skb) } err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, skb->len + sizeof(struct icmp6hdr)); - ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTECHOREPLIES); - ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); - out_put: if (likely(idev != NULL)) in6_dev_put(idev); @@ -656,10 +653,7 @@ static int icmpv6_rcv(struct sk_buff **pskb) type = hdr->icmp6_type; - if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) - ICMP6_INC_STATS_OFFSET_BH(idev, ICMP6_MIB_INDESTUNREACHS, type - ICMPV6_DEST_UNREACH); - else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT) - ICMP6_INC_STATS_OFFSET_BH(idev, ICMP6_MIB_INECHOS, type - ICMPV6_ECHO_REQUEST); + ICMP6MSGIN_INC_STATS_BH(idev, type); switch (type) { case ICMPV6_ECHO_REQUEST: diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e46d4683eab0..011082ed921a 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1399,6 +1399,13 @@ int ip6_push_pending_frames(struct sock *sk) skb->dst = dst_clone(&rt->u.dst); IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); + if (proto == IPPROTO_ICMPV6) { + struct inet6_dev *idev = ip6_dst_idev(skb->dst); + + ICMP6MSGOUT_INC_STATS_BH(idev, icmp6_hdr(skb)->icmp6_type); + ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); + } + err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); if (err) { if (err > 0) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index e2ab43c989d4..86d908b1caea 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1479,10 +1479,11 @@ static void mld_sendpack(struct sk_buff *skb) err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev, mld_dev_queue_xmit); if (!err) { - ICMP6_INC_STATS(idev,ICMP6_MIB_OUTMSGS); - IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS); + ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT); + ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTMCASTPKTS); } else - IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTDISCARDS); if (likely(idev != NULL)) in6_dev_put(idev); @@ -1822,10 +1823,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev, mld_dev_queue_xmit); if (!err) { - if (type == ICMPV6_MGM_REDUCTION) - ICMP6_INC_STATS(idev, ICMP6_MIB_OUTGROUPMEMBREDUCTIONS); - else - ICMP6_INC_STATS(idev, ICMP6_MIB_OUTGROUPMEMBRESPONSES); + ICMP6MSGOUT_INC_STATS(idev, type); ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS); } else diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index d2d44dc22f19..7ea5a502ca08 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -431,7 +431,7 @@ static void __ndisc_send(struct net_device *dev, struct neighbour *neigh, struct in6_addr *daddr, struct in6_addr *saddr, struct icmp6hdr *icmp6h, struct in6_addr *target, - int llinfo, int icmp6_mib_outnd) + int llinfo) { struct flowi fl; struct dst_entry *dst; @@ -441,9 +441,11 @@ static void __ndisc_send(struct net_device *dev, struct inet6_dev *idev; int len; int err; - u8 *opt; + u8 *opt, type; - ndisc_flow_init(&fl, icmp6h->icmp6_type, saddr, daddr, + type = icmp6h->icmp6_type; + + ndisc_flow_init(&fl, type, saddr, daddr, dev->ifindex); dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); @@ -504,7 +506,7 @@ static void __ndisc_send(struct net_device *dev, err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); if (!err) { - ICMP6_INC_STATS(idev, icmp6_mib_outnd); + ICMP6MSGOUT_INC_STATS(idev, type); ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); } @@ -542,8 +544,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, __ndisc_send(dev, neigh, daddr, src_addr, &icmp6h, solicited_addr, - inc_opt ? ND_OPT_TARGET_LL_ADDR : 0, - ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS); + inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); } void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, @@ -564,8 +565,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, __ndisc_send(dev, neigh, daddr, saddr, &icmp6h, solicit, - !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0, - ICMP6_MIB_OUTNEIGHBORSOLICITS); + !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); } void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, @@ -599,8 +599,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, #endif __ndisc_send(dev, NULL, daddr, saddr, &icmp6h, NULL, - send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0, - ICMP6_MIB_OUTROUTERSOLICITS); + send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); } @@ -1455,7 +1454,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, buff, NULL, dst->dev, dst_output); if (!err) { - ICMP6_INC_STATS(idev, ICMP6_MIB_OUTREDIRECTS); + ICMP6MSGOUT_INC_STATS(idev, NDISC_REDIRECT); ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index a712a2289484..db945018579e 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -86,47 +86,33 @@ static struct snmp_mib snmp6_ipstats_list[] = { }; static struct snmp_mib snmp6_icmp6_list[] = { -/* icmpv6 mib according to RFC 2466 - - Exceptions: {In|Out}AdminProhibs are removed, because I see - no good reasons to account them separately - of another dest.unreachs. - OutErrs is zero identically. - OutEchos too. - OutRouterAdvertisements too. - OutGroupMembQueries too. - */ +/* icmpv6 mib according to RFC 2466 */ SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS), SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS), - SNMP_MIB_ITEM("Icmp6InDestUnreachs", ICMP6_MIB_INDESTUNREACHS), - SNMP_MIB_ITEM("Icmp6InPktTooBigs", ICMP6_MIB_INPKTTOOBIGS), - SNMP_MIB_ITEM("Icmp6InTimeExcds", ICMP6_MIB_INTIMEEXCDS), - SNMP_MIB_ITEM("Icmp6InParmProblems", ICMP6_MIB_INPARMPROBLEMS), - SNMP_MIB_ITEM("Icmp6InEchos", ICMP6_MIB_INECHOS), - SNMP_MIB_ITEM("Icmp6InEchoReplies", ICMP6_MIB_INECHOREPLIES), - SNMP_MIB_ITEM("Icmp6InGroupMembQueries", ICMP6_MIB_INGROUPMEMBQUERIES), - SNMP_MIB_ITEM("Icmp6InGroupMembResponses", ICMP6_MIB_INGROUPMEMBRESPONSES), - SNMP_MIB_ITEM("Icmp6InGroupMembReductions", ICMP6_MIB_INGROUPMEMBREDUCTIONS), - SNMP_MIB_ITEM("Icmp6InRouterSolicits", ICMP6_MIB_INROUTERSOLICITS), - SNMP_MIB_ITEM("Icmp6InRouterAdvertisements", ICMP6_MIB_INROUTERADVERTISEMENTS), - SNMP_MIB_ITEM("Icmp6InNeighborSolicits", ICMP6_MIB_INNEIGHBORSOLICITS), - SNMP_MIB_ITEM("Icmp6InNeighborAdvertisements", ICMP6_MIB_INNEIGHBORADVERTISEMENTS), - SNMP_MIB_ITEM("Icmp6InRedirects", ICMP6_MIB_INREDIRECTS), SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS), - SNMP_MIB_ITEM("Icmp6OutDestUnreachs", ICMP6_MIB_OUTDESTUNREACHS), - SNMP_MIB_ITEM("Icmp6OutPktTooBigs", ICMP6_MIB_OUTPKTTOOBIGS), - SNMP_MIB_ITEM("Icmp6OutTimeExcds", ICMP6_MIB_OUTTIMEEXCDS), - SNMP_MIB_ITEM("Icmp6OutParmProblems", ICMP6_MIB_OUTPARMPROBLEMS), - SNMP_MIB_ITEM("Icmp6OutEchoReplies", ICMP6_MIB_OUTECHOREPLIES), - SNMP_MIB_ITEM("Icmp6OutRouterSolicits", ICMP6_MIB_OUTROUTERSOLICITS), - SNMP_MIB_ITEM("Icmp6OutNeighborSolicits", ICMP6_MIB_OUTNEIGHBORSOLICITS), - SNMP_MIB_ITEM("Icmp6OutNeighborAdvertisements", ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS), - SNMP_MIB_ITEM("Icmp6OutRedirects", ICMP6_MIB_OUTREDIRECTS), - SNMP_MIB_ITEM("Icmp6OutGroupMembResponses", ICMP6_MIB_OUTGROUPMEMBRESPONSES), - SNMP_MIB_ITEM("Icmp6OutGroupMembReductions", ICMP6_MIB_OUTGROUPMEMBREDUCTIONS), SNMP_MIB_SENTINEL }; +/* RFC 4293 v6 ICMPMsgStatsTable; named items for RFC 2466 compatibility */ +static char *icmp6type2name[256] = { + [ICMPV6_DEST_UNREACH] = "DestUnreachs", + [ICMPV6_PKT_TOOBIG] = "PktTooBigs", + [ICMPV6_TIME_EXCEED] = "TimeExcds", + [ICMPV6_PARAMPROB] = "ParmProblems", + [ICMPV6_ECHO_REQUEST] = "EchoRequest", + [ICMPV6_ECHO_REPLY] = "EchoReplies", + [ICMPV6_MGM_QUERY] = "GroupMembQueries", + [ICMPV6_MGM_REPORT] = "GroupMembResponses", + [ICMPV6_MGM_REDUCTION] = "GroupMembReductions", + [ICMPV6_MLD2_REPORT] = "MLDv2Reports", + [NDISC_ROUTER_ADVERTISEMENT] = "RouterAdvertisements", + [NDISC_ROUTER_SOLICITATION] = "RouterSolicits", + [NDISC_NEIGHBOUR_ADVERTISEMENT] = "NeighborAdvertisements", + [NDISC_NEIGHBOUR_SOLICITATION] = "NeighborSolicits", + [NDISC_REDIRECT] = "NeighborRedirects", +}; + + static struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS), SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), @@ -143,6 +129,40 @@ static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_SENTINEL }; +static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) +{ + static char name[32]; + int i; + + /* print by name -- deprecated items */ + for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { + int icmptype; + char *p; + + icmptype = i & 0xff; + p = icmp6type2name[icmptype]; + if (!p) /* don't print un-named types here */ + continue; + (void) snprintf(name, sizeof(name)-1, "Icmp6%s%s", + i & 0x100 ? "Out" : "In", p); + seq_printf(seq, "%-32s\t%lu\n", name, + snmp_fold_field(mib, i)); + } + + /* print by number (nonzero only) - ICMPMsgStat format */ + for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { + unsigned long val; + + val = snmp_fold_field(mib, i); + if (!val) + continue; + (void) snprintf(name, sizeof(name)-1, "Icmp6%sType%u", + i & 0x100 ? "Out" : "In", i & 0xff); + seq_printf(seq, "%-32s\t%lu\n", name, val); + } + return; +} + static inline void snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist) { @@ -160,9 +180,11 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipstats_list); snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list); + snmp6_seq_show_icmpv6msg(seq, (void **)idev->stats.icmpv6msg); } else { snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list); snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); + snmp6_seq_show_icmpv6msg(seq, (void **)icmpv6msg_statistics); snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); } From 96793b482540f3a26e2188eaf75cb56b7829d3e3 Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Mon, 17 Sep 2007 09:57:33 -0700 Subject: [PATCH 1406/2804] [IPV4]: Add ICMPMsgStats MIB (RFC 4293) Background: RFC 4293 deprecates existing individual, named ICMP type counters to be replaced with the ICMPMsgStatsTable. This table includes entries for both IPv4 and IPv6, and requires counting of all ICMP types, whether or not the machine implements the type. These patches "remove" (but not really) the existing counters, and replace them with the ICMPMsgStats tables for v4 and v6. It includes the named counters in the /proc places they were, but gets the values for them from the new tables. It also counts packets generated from raw socket output (e.g., OutEchoes, MLD queries, RA's from radvd, etc). Changes: 1) create icmpmsg_statistics mib 2) create icmpv6msg_statistics mib 3) modify existing counters to use these 4) modify /proc/net/snmp to add "IcmpMsg" with all ICMP types listed by number for easy SNMP parsing 5) modify /proc/net/snmp printing for "Icmp" to get the named data from new counters. Signed-off-by: David L Stevens Signed-off-by: David S. Miller --- include/linux/snmp.h | 2 + include/net/icmp.h | 8 +++ include/net/snmp.h | 5 ++ net/ipv4/af_inet.c | 6 +++ net/ipv4/icmp.c | 53 +++---------------- net/ipv4/ip_output.c | 4 ++ net/ipv4/proc.c | 120 ++++++++++++++++++++++++++++++++----------- net/ipv4/raw.c | 3 ++ 8 files changed, 123 insertions(+), 78 deletions(-) diff --git a/include/linux/snmp.h b/include/linux/snmp.h index 86977e31548a..d8fd3ec4148a 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -82,6 +82,8 @@ enum __ICMP_MIB_MAX }; +#define __ICMPMSG_MIB_MAX 512 /* Out+In for all 8-bit ICMP types */ + /* icmp6 mib definitions */ /* * RFC 2466: ICMPv6-MIB diff --git a/include/net/icmp.h b/include/net/icmp.h index dc09474efcf3..9f7ef3c8baef 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -30,9 +30,16 @@ struct icmp_err { extern struct icmp_err icmp_err_convert[]; DECLARE_SNMP_STAT(struct icmp_mib, icmp_statistics); +DECLARE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics); #define ICMP_INC_STATS(field) SNMP_INC_STATS(icmp_statistics, field) #define ICMP_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmp_statistics, field) #define ICMP_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmp_statistics, field) +#define ICMPMSGOUT_INC_STATS(field) SNMP_INC_STATS(icmpmsg_statistics, field+256) +#define ICMPMSGOUT_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpmsg_statistics, field+256) +#define ICMPMSGOUT_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field+256) +#define ICMPMSGIN_INC_STATS(field) SNMP_INC_STATS(icmpmsg_statistics, field) +#define ICMPMSGIN_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmpmsg_statistics, field) +#define ICMPMSGIN_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmpmsg_statistics, field) struct dst_entry; struct net_proto_family; @@ -42,6 +49,7 @@ extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info); extern int icmp_rcv(struct sk_buff *skb); extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern void icmp_init(struct net_proto_family *ops); +extern void icmp_out_count(unsigned char type); /* Move into dst.h ? */ extern int xrlim_allow(struct dst_entry *dst, int timeout); diff --git a/include/net/snmp.h b/include/net/snmp.h index a566e11d2f98..ea206bff0dc4 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -82,6 +82,11 @@ struct icmp_mib { unsigned long mibs[ICMP_MIB_MAX]; } __SNMP_MIB_ALIGN__; +#define ICMPMSG_MIB_MAX __ICMPMSG_MIB_MAX +struct icmpmsg_mib { + unsigned long mibs[ICMPMSG_MIB_MAX]; +} __SNMP_MIB_ALIGN__; + /* ICMP6 (IPv6-ICMP) */ #define ICMP6_MIB_MAX __ICMP6_MIB_MAX struct icmpv6_mib { diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index e594a2c89661..621b128897d7 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1302,6 +1302,10 @@ static int __init init_ipv4_mibs(void) sizeof(struct icmp_mib), __alignof__(struct icmp_mib)) < 0) goto err_icmp_mib; + if (snmp_mib_init((void **)icmpmsg_statistics, + sizeof(struct icmpmsg_mib), + __alignof__(struct icmpmsg_mib)) < 0) + goto err_icmpmsg_mib; if (snmp_mib_init((void **)tcp_statistics, sizeof(struct tcp_mib), __alignof__(struct tcp_mib)) < 0) @@ -1324,6 +1328,8 @@ err_udplite_mib: err_udp_mib: snmp_mib_free((void **)tcp_statistics); err_tcp_mib: + snmp_mib_free((void **)icmpmsg_statistics); +err_icmpmsg_mib: snmp_mib_free((void **)icmp_statistics); err_icmp_mib: snmp_mib_free((void **)ip_statistics); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 68a22670f597..272c69e106e9 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -115,6 +115,7 @@ struct icmp_bxm { * Statistics */ DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics) __read_mostly; +DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics) __read_mostly; /* An array of errno for error messages from dest unreach. */ /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */ @@ -214,8 +215,6 @@ int sysctl_icmp_errors_use_inbound_ifaddr __read_mostly; */ struct icmp_control { - int output_entry; /* Field for increment on output */ - int input_entry; /* Field for increment on input */ void (*handler)(struct sk_buff *skb); short error; /* This ICMP is classed as an error message */ }; @@ -316,12 +315,10 @@ out: /* * Maintain the counters used in the SNMP statistics for outgoing ICMP */ -static void icmp_out_count(int type) +void icmp_out_count(unsigned char type) { - if (type <= NR_ICMP_TYPES) { - ICMP_INC_STATS(icmp_pointers[type].output_entry); - ICMP_INC_STATS(ICMP_MIB_OUTMSGS); - } + ICMPMSGOUT_INC_STATS(type); + ICMP_INC_STATS(ICMP_MIB_OUTMSGS); } /* @@ -390,7 +387,6 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) return; icmp_param->data.icmph.checksum = 0; - icmp_out_count(icmp_param->data.icmph.type); inet->tos = ip_hdr(skb)->tos; daddr = ipc.addr = rt->rt_src; @@ -952,6 +948,7 @@ int icmp_rcv(struct sk_buff *skb) icmph = icmp_hdr(skb); + ICMPMSGIN_INC_STATS_BH(icmph->type); /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * @@ -986,7 +983,6 @@ int icmp_rcv(struct sk_buff *skb) } } - ICMP_INC_STATS_BH(icmp_pointers[icmph->type].input_entry); icmp_pointers[icmph->type].handler(skb); drop: @@ -1002,109 +998,71 @@ error: */ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { [ICMP_ECHOREPLY] = { - .output_entry = ICMP_MIB_OUTECHOREPS, - .input_entry = ICMP_MIB_INECHOREPS, .handler = icmp_discard, }, [1] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_INERRORS, .handler = icmp_discard, .error = 1, }, [2] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_INERRORS, .handler = icmp_discard, .error = 1, }, [ICMP_DEST_UNREACH] = { - .output_entry = ICMP_MIB_OUTDESTUNREACHS, - .input_entry = ICMP_MIB_INDESTUNREACHS, .handler = icmp_unreach, .error = 1, }, [ICMP_SOURCE_QUENCH] = { - .output_entry = ICMP_MIB_OUTSRCQUENCHS, - .input_entry = ICMP_MIB_INSRCQUENCHS, .handler = icmp_unreach, .error = 1, }, [ICMP_REDIRECT] = { - .output_entry = ICMP_MIB_OUTREDIRECTS, - .input_entry = ICMP_MIB_INREDIRECTS, .handler = icmp_redirect, .error = 1, }, [6] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_INERRORS, .handler = icmp_discard, .error = 1, }, [7] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_INERRORS, .handler = icmp_discard, .error = 1, }, [ICMP_ECHO] = { - .output_entry = ICMP_MIB_OUTECHOS, - .input_entry = ICMP_MIB_INECHOS, .handler = icmp_echo, }, [9] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_INERRORS, .handler = icmp_discard, .error = 1, }, [10] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_INERRORS, .handler = icmp_discard, .error = 1, }, [ICMP_TIME_EXCEEDED] = { - .output_entry = ICMP_MIB_OUTTIMEEXCDS, - .input_entry = ICMP_MIB_INTIMEEXCDS, .handler = icmp_unreach, .error = 1, }, [ICMP_PARAMETERPROB] = { - .output_entry = ICMP_MIB_OUTPARMPROBS, - .input_entry = ICMP_MIB_INPARMPROBS, .handler = icmp_unreach, .error = 1, }, [ICMP_TIMESTAMP] = { - .output_entry = ICMP_MIB_OUTTIMESTAMPS, - .input_entry = ICMP_MIB_INTIMESTAMPS, .handler = icmp_timestamp, }, [ICMP_TIMESTAMPREPLY] = { - .output_entry = ICMP_MIB_OUTTIMESTAMPREPS, - .input_entry = ICMP_MIB_INTIMESTAMPREPS, .handler = icmp_discard, }, [ICMP_INFO_REQUEST] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_DUMMY, .handler = icmp_discard, }, [ICMP_INFO_REPLY] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_DUMMY, .handler = icmp_discard, }, [ICMP_ADDRESS] = { - .output_entry = ICMP_MIB_OUTADDRMASKS, - .input_entry = ICMP_MIB_INADDRMASKS, .handler = icmp_address, }, [ICMP_ADDRESSREPLY] = { - .output_entry = ICMP_MIB_OUTADDRMASKREPS, - .input_entry = ICMP_MIB_INADDRMASKREPS, .handler = icmp_address_reply, }, }; @@ -1146,4 +1104,5 @@ void __init icmp_init(struct net_proto_family *ops) EXPORT_SYMBOL(icmp_err_convert); EXPORT_SYMBOL(icmp_send); EXPORT_SYMBOL(icmp_statistics); +EXPORT_SYMBOL(icmpmsg_statistics); EXPORT_SYMBOL(xrlim_allow); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 0f1d7beacf78..77f67b7cb9bf 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1261,6 +1261,10 @@ int ip_push_pending_frames(struct sock *sk) skb->priority = sk->sk_priority; skb->dst = dst_clone(&rt->u.dst); + if (iph->protocol == IPPROTO_ICMP) + icmp_out_count(((struct icmphdr *) + skb_transport_header(skb))->type); + /* Netfilter gets whole the not fragmented skb. */ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 95a8f8f2de71..2015148b41a8 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -124,33 +124,30 @@ static const struct snmp_mib snmp4_ipextstats_list[] = { static const struct snmp_mib snmp4_icmp_list[] = { SNMP_MIB_ITEM("InMsgs", ICMP_MIB_INMSGS), SNMP_MIB_ITEM("InErrors", ICMP_MIB_INERRORS), - SNMP_MIB_ITEM("InDestUnreachs", ICMP_MIB_INDESTUNREACHS), - SNMP_MIB_ITEM("InTimeExcds", ICMP_MIB_INTIMEEXCDS), - SNMP_MIB_ITEM("InParmProbs", ICMP_MIB_INPARMPROBS), - SNMP_MIB_ITEM("InSrcQuenchs", ICMP_MIB_INSRCQUENCHS), - SNMP_MIB_ITEM("InRedirects", ICMP_MIB_INREDIRECTS), - SNMP_MIB_ITEM("InEchos", ICMP_MIB_INECHOS), - SNMP_MIB_ITEM("InEchoReps", ICMP_MIB_INECHOREPS), - SNMP_MIB_ITEM("InTimestamps", ICMP_MIB_INTIMESTAMPS), - SNMP_MIB_ITEM("InTimestampReps", ICMP_MIB_INTIMESTAMPREPS), - SNMP_MIB_ITEM("InAddrMasks", ICMP_MIB_INADDRMASKS), - SNMP_MIB_ITEM("InAddrMaskReps", ICMP_MIB_INADDRMASKREPS), SNMP_MIB_ITEM("OutMsgs", ICMP_MIB_OUTMSGS), SNMP_MIB_ITEM("OutErrors", ICMP_MIB_OUTERRORS), - SNMP_MIB_ITEM("OutDestUnreachs", ICMP_MIB_OUTDESTUNREACHS), - SNMP_MIB_ITEM("OutTimeExcds", ICMP_MIB_OUTTIMEEXCDS), - SNMP_MIB_ITEM("OutParmProbs", ICMP_MIB_OUTPARMPROBS), - SNMP_MIB_ITEM("OutSrcQuenchs", ICMP_MIB_OUTSRCQUENCHS), - SNMP_MIB_ITEM("OutRedirects", ICMP_MIB_OUTREDIRECTS), - SNMP_MIB_ITEM("OutEchos", ICMP_MIB_OUTECHOS), - SNMP_MIB_ITEM("OutEchoReps", ICMP_MIB_OUTECHOREPS), - SNMP_MIB_ITEM("OutTimestamps", ICMP_MIB_OUTTIMESTAMPS), - SNMP_MIB_ITEM("OutTimestampReps", ICMP_MIB_OUTTIMESTAMPREPS), - SNMP_MIB_ITEM("OutAddrMasks", ICMP_MIB_OUTADDRMASKS), - SNMP_MIB_ITEM("OutAddrMaskReps", ICMP_MIB_OUTADDRMASKREPS), SNMP_MIB_SENTINEL }; +static struct { + char *name; + int index; +} icmpmibmap[] = { + { "DestUnreachs", ICMP_DEST_UNREACH }, + { "TimeExcds", ICMP_TIME_EXCEEDED }, + { "ParmProbs", ICMP_PARAMETERPROB }, + { "SrcQuenchs", ICMP_SOURCE_QUENCH }, + { "Redirects", ICMP_REDIRECT }, + { "Echos", ICMP_ECHO }, + { "EchoReps", ICMP_ECHOREPLY }, + { "Timestamps", ICMP_TIMESTAMP }, + { "TimestampReps", ICMP_TIMESTAMPREPLY }, + { "AddrMasks", ICMP_ADDRESS }, + { "AddrMaskReps", ICMP_ADDRESSREPLY }, + { 0, 0 } +}; + + static const struct snmp_mib snmp4_tcp_list[] = { SNMP_MIB_ITEM("RtoAlgorithm", TCP_MIB_RTOALGORITHM), SNMP_MIB_ITEM("RtoMin", TCP_MIB_RTOMIN), @@ -251,6 +248,72 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_SENTINEL }; +static void icmpmsg_put(struct seq_file *seq) +{ +#define PERLINE 16 + + int j, i, count; + static int out[PERLINE]; + + count = 0; + for (i = 0; i < ICMPMSG_MIB_MAX; i++) { + + if (snmp_fold_field((void **) icmpmsg_statistics, i)) + out[count++] = i; + if (count < PERLINE) + continue; + + seq_printf(seq, "\nIcmpMsg:"); + for (j = 0; j < PERLINE; ++j) + seq_printf(seq, " %sType%u", i & 0x100 ? "Out" : "In", + i & 0xff); + seq_printf(seq, "\nIcmpMsg: "); + for (j = 0; j < PERLINE; ++j) + seq_printf(seq, " %lu", + snmp_fold_field((void **) icmpmsg_statistics, + out[j])); + seq_putc(seq, '\n'); + } + if (count) { + seq_printf(seq, "\nIcmpMsg:"); + for (j = 0; j < count; ++j) + seq_printf(seq, " %sType%u", out[j] & 0x100 ? "Out" : + "In", out[j] & 0xff); + seq_printf(seq, "\nIcmpMsg:"); + for (j = 0; j < count; ++j) + seq_printf(seq, " %lu", snmp_fold_field((void **) + icmpmsg_statistics, out[j])); + } + +#undef PERLINE +} + +static void icmp_put(struct seq_file *seq) +{ + int i; + + seq_puts(seq, "\nIcmp: InMsgs InErrors"); + for (i=0; icmpmibmap[i].name != NULL; i++) + seq_printf(seq, " In%s", icmpmibmap[i].name); + seq_printf(seq, " OutMsgs OutErrors"); + for (i=0; icmpmibmap[i].name != NULL; i++) + seq_printf(seq, " Out%s", icmpmibmap[i].name); + seq_printf(seq, "\nIcmp: %lu %lu", + snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INMSGS), + snmp_fold_field((void **) icmp_statistics, ICMP_MIB_INERRORS)); + for (i=0; icmpmibmap[i].name != NULL; i++) + seq_printf(seq, " %lu", + snmp_fold_field((void **) icmpmsg_statistics, + icmpmibmap[i].index)); + seq_printf(seq, " %lu %lu", + snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTMSGS), + snmp_fold_field((void **) icmp_statistics, ICMP_MIB_OUTERRORS)); + for (i=0; icmpmibmap[i].name != NULL; i++) + seq_printf(seq, " %lu", + snmp_fold_field((void **) icmpmsg_statistics, + icmpmibmap[i].index)); +} + /* * Called from the PROCfs module. This outputs /proc/net/snmp. */ @@ -271,15 +334,8 @@ static int snmp_seq_show(struct seq_file *seq, void *v) snmp_fold_field((void **)ip_statistics, snmp4_ipstats_list[i].entry)); - seq_puts(seq, "\nIcmp:"); - for (i = 0; snmp4_icmp_list[i].name != NULL; i++) - seq_printf(seq, " %s", snmp4_icmp_list[i].name); - - seq_puts(seq, "\nIcmp:"); - for (i = 0; snmp4_icmp_list[i].name != NULL; i++) - seq_printf(seq, " %lu", - snmp_fold_field((void **)icmp_statistics, - snmp4_icmp_list[i].entry)); + icmp_put(seq); /* RFC 2011 compatibility */ + icmpmsg_put(seq); seq_puts(seq, "\nTcp:"); for (i = 0; snmp4_tcp_list[i].name != NULL; i++) @@ -336,6 +392,8 @@ static const struct file_operations snmp_seq_fops = { .release = single_release, }; + + /* * Output /proc/net/netstat */ diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 216e01b0f44a..07070c7067f3 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -314,6 +314,9 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } + if (iph->protocol == IPPROTO_ICMP) + icmp_out_count(((struct icmphdr *) + skb_transport_header(skb))->type); err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); From f7b0e93ba1a484700bd1b0e36bdaddaf4eb51b0b Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sun, 16 Sep 2007 19:26:06 -0700 Subject: [PATCH 1407/2804] [SCTP]: protocol definitions for SCTP-AUTH implementation Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/linux/sctp.h | 100 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/include/linux/sctp.h b/include/linux/sctp.h index f4d717b72ddd..5eb38cc0e5a4 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -102,6 +102,9 @@ typedef enum { SCTP_CID_ECN_CWR = 13, SCTP_CID_SHUTDOWN_COMPLETE = 14, + /* AUTH Extension Section 4.1 */ + SCTP_CID_AUTH = 0x0F, + /* PR-SCTP Sec 3.2 */ SCTP_CID_FWD_TSN = 0xC0, @@ -180,6 +183,11 @@ typedef enum { SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), + /* AUTH Extension Section 3 */ + SCTP_PARAM_RANDOM = __constant_htons(0x8002), + SCTP_PARAM_CHUNKS = __constant_htons(0x8003), + SCTP_PARAM_HMAC_ALGO = __constant_htons(0x8004), + /* Add-IP: Supported Extensions, Section 4.2 */ SCTP_PARAM_SUPPORTED_EXT = __constant_htons(0x8008), @@ -305,6 +313,24 @@ typedef struct sctp_supported_ext_param { __u8 chunks[0]; } __attribute__((packed)) sctp_supported_ext_param_t; +/* AUTH Section 3.1 Random */ +typedef struct sctp_random_param { + sctp_paramhdr_t param_hdr; + __u8 random_val[0]; +} __attribute__((packed)) sctp_random_param_t; + +/* AUTH Section 3.2 Chunk List */ +typedef struct sctp_chunks_param { + sctp_paramhdr_t param_hdr; + __u8 chunks[0]; +} __attribute__((packed)) sctp_chunks_param_t; + +/* AUTH Section 3.3 HMAC Algorithm */ +typedef struct sctp_hmac_algo_param { + sctp_paramhdr_t param_hdr; + __be16 hmac_ids[0]; +} __attribute__((packed)) sctp_hmac_algo_param_t; + /* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): * The INIT ACK chunk is used to acknowledge the initiation of an SCTP * association. @@ -471,7 +497,19 @@ typedef enum { SCTP_ERROR_RSRC_LOW = __constant_htons(0x0101), SCTP_ERROR_DEL_SRC_IP = __constant_htons(0x0102), SCTP_ERROR_ASCONF_ACK = __constant_htons(0x0103), - SCTP_ERROR_REQ_REFUSED = __constant_htons(0x0104) + SCTP_ERROR_REQ_REFUSED = __constant_htons(0x0104), + + /* AUTH Section 4. New Error Cause + * + * This section defines a new error cause that will be sent if an AUTH + * chunk is received with an unsupported HMAC identifier. + * illustrates the new error cause. + * + * Cause Code Error Cause Name + * -------------------------------------------------------------- + * 0x0105 Unsupported HMAC Identifier + */ + SCTP_ERROR_UNSUP_HMAC = __constant_htons(0x0105) } sctp_error_t; @@ -609,4 +647,64 @@ typedef struct sctp_addip_chunk { sctp_addiphdr_t addip_hdr; } __attribute__((packed)) sctp_addip_chunk_t; +/* AUTH + * Section 4.1 Authentication Chunk (AUTH) + * + * This chunk is used to hold the result of the HMAC calculation. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 0x0F | Flags=0 | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Shared Key Identifier | HMAC Identifier | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * \ HMAC / + * / \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Type: 1 byte (unsigned integer) + * This value MUST be set to 0x0F for all AUTH-chunks. + * + * Flags: 1 byte (unsigned integer) + * Set to zero on transmit and ignored on receipt. + * + * Length: 2 bytes (unsigned integer) + * This value holds the length of the HMAC in bytes plus 8. + * + * Shared Key Identifier: 2 bytes (unsigned integer) + * This value describes which endpoint pair shared key is used. + * + * HMAC Identifier: 2 bytes (unsigned integer) + * This value describes which message digest is being used. Table 2 + * shows the currently defined values. + * + * The following Table 2 shows the currently defined values for HMAC + * identifiers. + * + * +-----------------+--------------------------+ + * | HMAC Identifier | Message Digest Algorithm | + * +-----------------+--------------------------+ + * | 0 | Reserved | + * | 1 | SHA-1 defined in [8] | + * | 2 | Reserved | + * | 3 | SHA-256 defined in [8] | + * +-----------------+--------------------------+ + * + * + * HMAC: n bytes (unsigned integer) This hold the result of the HMAC + * calculation. + */ +typedef struct sctp_authhdr { + __be16 shkey_id; + __be16 hmac_id; + __u8 hmac[0]; +} __attribute__((packed)) sctp_authhdr_t; + +typedef struct sctp_auth_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_authhdr_t auth_hdr; +} __attribute__((packed)) sctp_auth_chunk_t; + #endif /* __LINUX_SCTP_H__ */ From 1f485649f52929d9937b346a920a522a7363e202 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 9 Oct 2007 01:15:59 -0700 Subject: [PATCH 1408/2804] [SCTP]: Implement SCTP-AUTH internals This patch implements the internals operations of the AUTH, such as key computation and storage. It also adds necessary variables to the SCTP data structures. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/auth.h | 112 ++++++ include/net/sctp/constants.h | 49 ++- include/net/sctp/sctp.h | 1 + include/net/sctp/structs.h | 73 +++- net/sctp/Makefile | 3 +- net/sctp/auth.c | 745 +++++++++++++++++++++++++++++++++++ net/sctp/objcnt.c | 2 + 7 files changed, 977 insertions(+), 8 deletions(-) create mode 100644 include/net/sctp/auth.h create mode 100644 net/sctp/auth.c diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h new file mode 100644 index 000000000000..10c8010552ff --- /dev/null +++ b/include/net/sctp/auth.h @@ -0,0 +1,112 @@ +/* SCTP kernel reference Implementation + * (C) Copyright 2007 Hewlett-Packard Development Company, L.P. + * + * This file is part of the SCTP kernel reference Implementation + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Vlad Yasevich + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_auth_h__ +#define __sctp_auth_h__ + +#include +#include + +struct sctp_endpoint; +struct sctp_association; +struct sctp_authkey; + +/* + * Define a generic struct that will hold all the info + * necessary for an HMAC transform + */ +struct sctp_hmac { + __u16 hmac_id; /* one of the above ids */ + char *hmac_name; /* name for loading */ + __u16 hmac_len; /* length of the signature */ +}; + +/* This is generic structure that containst authentication bytes used + * as keying material. It's a what is referred to as byte-vector all + * over SCTP-AUTH + */ +struct sctp_auth_bytes { + atomic_t refcnt; + __u32 len; + __u8 data[]; +}; + +/* Definition for a shared key, weather endpoint or association */ +struct sctp_shared_key { + struct list_head key_list; + __u16 key_id; + struct sctp_auth_bytes *key; +}; + +#define key_for_each(__key, __list_head) \ + list_for_each_entry(__key, __list_head, key_list) + +#define key_for_each_safe(__key, __tmp, __list_head) \ + list_for_each_entry_safe(__key, __tmp, __list_head, key_list) + +static inline void sctp_auth_key_hold(struct sctp_auth_bytes *key) +{ + if (!key) + return; + + atomic_inc(&key->refcnt); +} + +void sctp_auth_key_put(struct sctp_auth_bytes *key); +struct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp); +void sctp_auth_shkey_free(struct sctp_shared_key *sh_key); +void sctp_auth_destroy_keys(struct list_head *keys); +int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp); +struct sctp_shared_key *sctp_auth_get_shkey( + const struct sctp_association *asoc, + __u16 key_id); +int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, + struct sctp_association *asoc, + gfp_t gfp); +int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp); +void sctp_auth_destroy_hmacs(struct crypto_hash *auth_hmacs[]); +struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id); +struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc); +void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, + struct sctp_hmac_algo_param *hmacs); +int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, + __u16 hmac_id); +int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc); +int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc); +void sctp_auth_calculate_hmac(const struct sctp_association *asoc, + struct sk_buff *skb, + struct sctp_auth_chunk *auth, gfp_t gfp); +#endif diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index bb37724495a5..777118f06dba 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -64,12 +64,18 @@ enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM }; #define SCTP_CID_MAX SCTP_CID_ASCONF_ACK #define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1) -#define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNKTYPES + 2) #define SCTP_NUM_ADDIP_CHUNK_TYPES 2 #define SCTP_NUM_PRSCTP_CHUNK_TYPES 1 +#define SCTP_NUM_AUTH_CHUNK_TYPES 1 + +#define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNK_TYPES + \ + SCTP_NUM_ADDIP_CHUNK_TYPES +\ + SCTP_NUM_PRSCTP_CHUNK_TYPES +\ + SCTP_NUM_AUTH_CHUNK_TYPES) + /* These are the different flavours of event. */ typedef enum { @@ -409,4 +415,45 @@ typedef enum { SCTP_LOWER_CWND_INACTIVE, } sctp_lower_cwnd_t; + +/* SCTP-AUTH Necessary constants */ + +/* SCTP-AUTH, Section 3.3 + * + * The following Table 2 shows the currently defined values for HMAC + * identifiers. + * + * +-----------------+--------------------------+ + * | HMAC Identifier | Message Digest Algorithm | + * +-----------------+--------------------------+ + * | 0 | Reserved | + * | 1 | SHA-1 defined in [8] | + * | 2 | Reserved | + * | 3 | SHA-256 defined in [8] | + * +-----------------+--------------------------+ + */ +enum { + SCTP_AUTH_HMAC_ID_RESERVED_0, + SCTP_AUTH_HMAC_ID_SHA1, + SCTP_AUTH_HMAC_ID_RESERVED_2, + SCTP_AUTH_HMAC_ID_SHA256 +}; + +#define SCTP_AUTH_HMAC_ID_MAX SCTP_AUTH_HMAC_ID_SHA256 +#define SCTP_AUTH_NUM_HMACS (SCTP_AUTH_HMAC_ID_SHA256 + 1) +#define SCTP_SHA1_SIG_SIZE 20 +#define SCTP_SHA256_SIG_SIZE 32 + +/* SCTP-AUTH, Section 3.2 + * The chunk types for INIT, INIT-ACK, SHUTDOWN-COMPLETE and AUTH chunks + * MUST NOT be listed in the CHUNKS parameter + */ +#define SCTP_NUM_NOAUTH_CHUNKS 4 +#define SCTP_AUTH_MAX_CHUNKS (SCTP_NUM_CHUNK_TYPES - SCTP_NUM_NOAUTH_CHUNKS) + +/* SCTP-AUTH Section 6.1 + * The RANDOM parameter MUST contain a 32 byte random number. + */ +#define SCTP_AUTH_RANDOM_LENGTH 32 + #endif /* __sctp_constants_h__ */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index d5a1ddc7483f..119f5a1ed499 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -341,6 +341,7 @@ extern atomic_t sctp_dbg_objcnt_bind_bucket; extern atomic_t sctp_dbg_objcnt_addr; extern atomic_t sctp_dbg_objcnt_ssnmap; extern atomic_t sctp_dbg_objcnt_datamsg; +extern atomic_t sctp_dbg_objcnt_keys; /* Macros to atomically increment/decrement objcnt counters. */ #define SCTP_DBG_OBJCNT_INC(name) \ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index b4812a2d3bb0..18b06afacea0 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -64,6 +64,7 @@ #include /* We need sk_buff_head. */ #include /* We need tq_struct. */ #include /* We need sctp* header structs. */ +#include /* We need auth specific structs */ /* A convenience structure for handling sockaddr structures. * We should wean ourselves off this. @@ -216,6 +217,9 @@ extern struct sctp_globals { /* Flag to indicate if PR-SCTP is enabled. */ int prsctp_enable; + + /* Flag to idicate if SCTP-AUTH is enabled */ + int auth_enable; } sctp_globals; #define sctp_rto_initial (sctp_globals.rto_initial) @@ -248,6 +252,7 @@ extern struct sctp_globals { #define sctp_local_addr_lock (sctp_globals.addr_list_lock) #define sctp_addip_enable (sctp_globals.addip_enable) #define sctp_prsctp_enable (sctp_globals.prsctp_enable) +#define sctp_auth_enable (sctp_globals.auth_enable) /* SCTP Socket type: UDP or TCP style. */ typedef enum { @@ -397,6 +402,9 @@ struct sctp_cookie { __u32 adaptation_ind; + __u8 auth_random[sizeof(sctp_paramhdr_t) + SCTP_AUTH_RANDOM_LENGTH]; + __u8 auth_hmacs[SCTP_AUTH_NUM_HMACS + 2]; + __u8 auth_chunks[sizeof(sctp_paramhdr_t) + SCTP_AUTH_MAX_CHUNKS]; /* This is a shim for my peer's INIT packet, followed by * a copy of the raw address list of the association. @@ -441,6 +449,9 @@ union sctp_params { union sctp_addr_param *addr; struct sctp_adaptation_ind_param *aind; struct sctp_supported_ext_param *ext; + struct sctp_random_param *random; + struct sctp_chunks_param *chunks; + struct sctp_hmac_algo_param *hmac_algo; }; /* RFC 2960. Section 3.3.5 Heartbeat. @@ -679,6 +690,7 @@ struct sctp_chunk { struct sctp_errhdr *err_hdr; struct sctp_addiphdr *addip_hdr; struct sctp_fwdtsn_hdr *fwdtsn_hdr; + struct sctp_authhdr *auth_hdr; } subh; __u8 *chunk_end; @@ -724,6 +736,7 @@ struct sctp_chunk { __s8 fast_retransmit; /* Is this chunk fast retransmitted? */ __u8 tsn_missing_report; /* Data chunk missing counter. */ __u8 data_accepted; /* At least 1 chunk in this packet accepted */ + __u8 auth; /* IN: was auth'ed | OUT: needs auth */ }; void sctp_chunk_hold(struct sctp_chunk *); @@ -773,16 +786,22 @@ struct sctp_packet { */ struct sctp_transport *transport; - /* This packet contains a COOKIE-ECHO chunk. */ - char has_cookie_echo; + /* pointer to the auth chunk for this packet */ + struct sctp_chunk *auth; - /* This packet containsa SACK chunk. */ - char has_sack; + /* 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; /* SCTP cannot fragment this packet. So let ip fragment it. */ - char ipfragok; + __u8 ipfragok; - int malloced; + __u8 malloced; }; struct sctp_packet *sctp_packet_init(struct sctp_packet *, @@ -1291,6 +1310,21 @@ struct sctp_endpoint { /* rcvbuf acct. policy. */ __u32 rcvbuf_policy; + + /* SCTP AUTH: array of the HMACs that will be allocated + * we need this per association so that we don't serialize + */ + struct crypto_hash **auth_hmacs; + + /* SCTP-AUTH: hmacs for the endpoint encoded into parameter */ + struct sctp_hmac_algo_param *auth_hmacs_list; + + /* SCTP-AUTH: chunks to authenticate encoded into parameter */ + struct sctp_chunks_param *auth_chunk_list; + + /* SCTP-AUTH: endpoint shared keys */ + struct list_head endpoint_shared_keys; + __u16 active_key_id; }; /* Recover the outter endpoint structure. */ @@ -1497,6 +1531,7 @@ struct sctp_association { __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? */ __u32 adaptation_ind; /* Adaptation Code point. */ @@ -1514,6 +1549,14 @@ struct sctp_association { * Initial TSN Value minus 1 */ __u32 addip_serial; + + /* SCTP-AUTH: We need to know pears random number, hmac list + * and authenticated chunk list. All that is part of the + * cookie and these are just pointers to those locations + */ + sctp_random_param_t *peer_random; + sctp_chunks_param_t *peer_chunks; + sctp_hmac_algo_param_t *peer_hmacs; } peer; /* State : A state variable indicating what state the @@ -1797,6 +1840,24 @@ struct sctp_association { */ __u32 addip_serial; + /* SCTP AUTH: list of the endpoint shared keys. These + * keys are provided out of band by the user applicaton + * and can't change during the lifetime of the association + */ + struct list_head endpoint_shared_keys; + + /* SCTP AUTH: + * The current generated assocaition shared key (secret) + */ + struct sctp_auth_bytes *asoc_shared_key; + + /* SCTP AUTH: hmac id of the first peer requested algorithm + * that we support. + */ + __u16 default_hmac_id; + + __u16 active_key_id; + /* Need to send an ECNE Chunk? */ char need_ecne; diff --git a/net/sctp/Makefile b/net/sctp/Makefile index 70c828bbe444..1da7204d9b42 100644 --- a/net/sctp/Makefile +++ b/net/sctp/Makefile @@ -9,7 +9,8 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ transport.o chunk.o sm_make_chunk.o ulpevent.o \ inqueue.o outqueue.o ulpqueue.o command.o \ tsnmap.o bind_addr.o socket.o primitive.o \ - output.o input.o debug.o ssnmap.o proc.o crc32c.o + output.o input.o debug.o ssnmap.o proc.o crc32c.o \ + auth.o sctp-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o sctp-$(CONFIG_SYSCTL) += sysctl.o diff --git a/net/sctp/auth.c b/net/sctp/auth.c new file mode 100644 index 000000000000..2a29409a38d9 --- /dev/null +++ b/net/sctp/auth.c @@ -0,0 +1,745 @@ +/* SCTP kernel reference Implementation + * (C) Copyright 2007 Hewlett-Packard Development Company, L.P. + * + * This file is part of the SCTP kernel reference Implementation + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Vlad Yasevich + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include + +static struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = { + { + /* id 0 is reserved. as all 0 */ + .hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_0, + }, + { + .hmac_id = SCTP_AUTH_HMAC_ID_SHA1, + .hmac_name="hmac(sha1)", + .hmac_len = SCTP_SHA1_SIG_SIZE, + }, + { + /* id 2 is reserved as well */ + .hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_2, + }, + { + .hmac_id = SCTP_AUTH_HMAC_ID_SHA256, + .hmac_name="hmac(sha256)", + .hmac_len = SCTP_SHA256_SIG_SIZE, + } +}; + + +void sctp_auth_key_put(struct sctp_auth_bytes *key) +{ + if (!key) + return; + + if (atomic_dec_and_test(&key->refcnt)) { + kfree(key); + SCTP_DBG_OBJCNT_DEC(keys); + } +} + +/* Create a new key structure of a given length */ +static struct sctp_auth_bytes *sctp_auth_create_key(__u32 key_len, gfp_t gfp) +{ + struct sctp_auth_bytes *key; + + /* Allocate the shared key */ + key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); + if (!key) + return NULL; + + key->len = key_len; + atomic_set(&key->refcnt, 1); + SCTP_DBG_OBJCNT_INC(keys); + + return key; +} + +/* Create a new shared key container with a give key id */ +struct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp) +{ + struct sctp_shared_key *new; + + /* Allocate the shared key container */ + new = kzalloc(sizeof(struct sctp_shared_key), gfp); + if (!new) + return NULL; + + INIT_LIST_HEAD(&new->key_list); + new->key_id = key_id; + + return new; +} + +/* Free the shared key stucture */ +void sctp_auth_shkey_free(struct sctp_shared_key *sh_key) +{ + BUG_ON(!list_empty(&sh_key->key_list)); + sctp_auth_key_put(sh_key->key); + sh_key->key = NULL; + kfree(sh_key); +} + +/* Destory the entire key list. This is done during the + * associon and endpoint free process. + */ +void sctp_auth_destroy_keys(struct list_head *keys) +{ + struct sctp_shared_key *ep_key; + struct sctp_shared_key *tmp; + + if (list_empty(keys)) + return; + + key_for_each_safe(ep_key, tmp, keys) { + list_del_init(&ep_key->key_list); + sctp_auth_shkey_free(ep_key); + } +} + +/* Compare two byte vectors as numbers. Return values + * are: + * 0 - vectors are equal + * < 0 - vector 1 is smaller then vector2 + * > 0 - vector 1 is greater then vector2 + * + * Algorithm is: + * This is performed by selecting the numerically smaller key vector... + * If the key vectors are equal as numbers but differ in length ... + * the shorter vector is considered smaller + * + * Examples (with small values): + * 000123456789 > 123456789 (first number is longer) + * 000123456789 < 234567891 (second number is larger numerically) + * 123456789 > 2345678 (first number is both larger & longer) + */ +static int sctp_auth_compare_vectors(struct sctp_auth_bytes *vector1, + struct sctp_auth_bytes *vector2) +{ + int diff; + int i; + const __u8 *longer; + + diff = vector1->len - vector2->len; + if (diff) { + longer = (diff > 0) ? vector1->data : vector2->data; + + /* Check to see if the longer number is + * lead-zero padded. If it is not, it + * is automatically larger numerically. + */ + for (i = 0; i < abs(diff); i++ ) { + if (longer[i] != 0) + return diff; + } + } + + /* lengths are the same, compare numbers */ + return memcmp(vector1->data, vector2->data, vector1->len); +} + +/* + * Create a key vector as described in SCTP-AUTH, Section 6.1 + * The RANDOM parameter, the CHUNKS parameter and the HMAC-ALGO + * parameter sent by each endpoint are concatenated as byte vectors. + * These parameters include the parameter type, parameter length, and + * the parameter value, but padding is omitted; all padding MUST be + * removed from this concatenation before proceeding with further + * computation of keys. Parameters which were not sent are simply + * omitted from the concatenation process. The resulting two vectors + * are called the two key vectors. + */ +static struct sctp_auth_bytes *sctp_auth_make_key_vector( + sctp_random_param_t *random, + sctp_chunks_param_t *chunks, + sctp_hmac_algo_param_t *hmacs, + gfp_t gfp) +{ + struct sctp_auth_bytes *new; + __u32 len; + __u32 offset = 0; + + len = ntohs(random->param_hdr.length) + ntohs(hmacs->param_hdr.length); + if (chunks) + len += ntohs(chunks->param_hdr.length); + + new = kmalloc(sizeof(struct sctp_auth_bytes) + len, gfp); + if (!new) + return NULL; + + new->len = len; + + memcpy(new->data, random, ntohs(random->param_hdr.length)); + offset += ntohs(random->param_hdr.length); + + if (chunks) { + memcpy(new->data + offset, chunks, + ntohs(chunks->param_hdr.length)); + offset += ntohs(chunks->param_hdr.length); + } + + memcpy(new->data + offset, hmacs, ntohs(hmacs->param_hdr.length)); + + return new; +} + + +/* Make a key vector based on our local parameters */ +struct sctp_auth_bytes *sctp_auth_make_local_vector( + const struct sctp_association *asoc, + gfp_t gfp) +{ + return sctp_auth_make_key_vector( + (sctp_random_param_t*)asoc->c.auth_random, + (sctp_chunks_param_t*)asoc->c.auth_chunks, + (sctp_hmac_algo_param_t*)asoc->c.auth_hmacs, + gfp); +} + +/* Make a key vector based on peer's parameters */ +struct sctp_auth_bytes *sctp_auth_make_peer_vector( + const struct sctp_association *asoc, + gfp_t gfp) +{ + return sctp_auth_make_key_vector(asoc->peer.peer_random, + asoc->peer.peer_chunks, + asoc->peer.peer_hmacs, + gfp); +} + + +/* Set the value of the association shared key base on the parameters + * given. The algorithm is: + * From the endpoint pair shared keys and the key vectors the + * association shared keys are computed. This is performed by selecting + * the numerically smaller key vector and concatenating it to the + * endpoint pair shared key, and then concatenating the numerically + * larger key vector to that. The result of the concatenation is the + * association shared key. + */ +static struct sctp_auth_bytes *sctp_auth_asoc_set_secret( + struct sctp_shared_key *ep_key, + struct sctp_auth_bytes *first_vector, + struct sctp_auth_bytes *last_vector, + gfp_t gfp) +{ + struct sctp_auth_bytes *secret; + __u32 offset = 0; + __u32 auth_len; + + auth_len = first_vector->len + last_vector->len; + if (ep_key->key) + auth_len += ep_key->key->len; + + secret = sctp_auth_create_key(auth_len, gfp); + if (!secret) + return NULL; + + if (ep_key->key) { + memcpy(secret->data, ep_key->key->data, ep_key->key->len); + offset += ep_key->key->len; + } + + memcpy(secret->data + offset, first_vector->data, first_vector->len); + offset += first_vector->len; + + memcpy(secret->data + offset, last_vector->data, last_vector->len); + + return secret; +} + +/* Create an association shared key. Follow the algorithm + * described in SCTP-AUTH, Section 6.1 + */ +static struct sctp_auth_bytes *sctp_auth_asoc_create_secret( + const struct sctp_association *asoc, + struct sctp_shared_key *ep_key, + gfp_t gfp) +{ + struct sctp_auth_bytes *local_key_vector; + struct sctp_auth_bytes *peer_key_vector; + struct sctp_auth_bytes *first_vector, + *last_vector; + struct sctp_auth_bytes *secret = NULL; + int cmp; + + + /* Now we need to build the key vectors + * SCTP-AUTH , Section 6.1 + * The RANDOM parameter, the CHUNKS parameter and the HMAC-ALGO + * parameter sent by each endpoint are concatenated as byte vectors. + * These parameters include the parameter type, parameter length, and + * the parameter value, but padding is omitted; all padding MUST be + * removed from this concatenation before proceeding with further + * computation of keys. Parameters which were not sent are simply + * omitted from the concatenation process. The resulting two vectors + * are called the two key vectors. + */ + + local_key_vector = sctp_auth_make_local_vector(asoc, gfp); + peer_key_vector = sctp_auth_make_peer_vector(asoc, gfp); + + if (!peer_key_vector || !local_key_vector) + goto out; + + /* Figure out the order in wich the key_vectors will be + * added to the endpoint shared key. + * SCTP-AUTH, Section 6.1: + * This is performed by selecting the numerically smaller key + * vector and concatenating it to the endpoint pair shared + * key, and then concatenating the numerically larger key + * vector to that. If the key vectors are equal as numbers + * but differ in length, then the concatenation order is the + * endpoint shared key, followed by the shorter key vector, + * followed by the longer key vector. Otherwise, the key + * vectors are identical, and may be concatenated to the + * endpoint pair key in any order. + */ + cmp = sctp_auth_compare_vectors(local_key_vector, + peer_key_vector); + if (cmp < 0) { + first_vector = local_key_vector; + last_vector = peer_key_vector; + } else { + first_vector = peer_key_vector; + last_vector = local_key_vector; + } + + secret = sctp_auth_asoc_set_secret(ep_key, first_vector, last_vector, + gfp); +out: + kfree(local_key_vector); + kfree(peer_key_vector); + + return secret; +} + +/* + * Populate the association overlay list with the list + * from the endpoint. + */ +int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, + struct sctp_association *asoc, + gfp_t gfp) +{ + struct sctp_shared_key *sh_key; + struct sctp_shared_key *new; + + BUG_ON(!list_empty(&asoc->endpoint_shared_keys)); + + key_for_each(sh_key, &ep->endpoint_shared_keys) { + new = sctp_auth_shkey_create(sh_key->key_id, gfp); + if (!new) + goto nomem; + + new->key = sh_key->key; + sctp_auth_key_hold(new->key); + list_add(&new->key_list, &asoc->endpoint_shared_keys); + } + + return 0; + +nomem: + sctp_auth_destroy_keys(&asoc->endpoint_shared_keys); + return -ENOMEM; +} + + +/* Public interface to creat the association shared key. + * See code above for the algorithm. + */ +int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp) +{ + struct sctp_auth_bytes *secret; + struct sctp_shared_key *ep_key; + + /* If we don't support AUTH, or peer is not capable + * we don't need to do anything. + */ + if (!sctp_auth_enable || !asoc->peer.auth_capable) + return 0; + + /* If the key_id is non-zero and we couldn't find an + * endpoint pair shared key, we can't compute the + * secret. + * For key_id 0, endpoint pair shared key is a NULL key. + */ + ep_key = sctp_auth_get_shkey(asoc, asoc->active_key_id); + BUG_ON(!ep_key); + + secret = sctp_auth_asoc_create_secret(asoc, ep_key, gfp); + if (!secret) + return -ENOMEM; + + sctp_auth_key_put(asoc->asoc_shared_key); + asoc->asoc_shared_key = secret; + + return 0; +} + + +/* Find the endpoint pair shared key based on the key_id */ +struct sctp_shared_key *sctp_auth_get_shkey( + const struct sctp_association *asoc, + __u16 key_id) +{ + struct sctp_shared_key *key = NULL; + + /* First search associations set of endpoint pair shared keys */ + key_for_each(key, &asoc->endpoint_shared_keys) { + if (key->key_id == key_id) + break; + } + + return key; +} + +/* + * Initialize all the possible digest transforms that we can use. Right now + * now, the supported digests are SHA1 and SHA256. We do this here once + * because of the restrictiong that transforms may only be allocated in + * user context. This forces us to pre-allocated all possible transforms + * at the endpoint init time. + */ +int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp) +{ + struct crypto_hash *tfm = NULL; + __u16 id; + + /* if the transforms are already allocted, we are done */ + if (!sctp_auth_enable) { + ep->auth_hmacs = NULL; + return 0; + } + + if (ep->auth_hmacs) + return 0; + + /* Allocated the array of pointers to transorms */ + ep->auth_hmacs = kzalloc( + sizeof(struct crypto_hash *) * SCTP_AUTH_NUM_HMACS, + gfp); + if (!ep->auth_hmacs) + return -ENOMEM; + + for (id = 0; id < SCTP_AUTH_NUM_HMACS; id++) { + + /* See is we support the id. Supported IDs have name and + * length fields set, so that we can allocated and use + * them. We can safely just check for name, for without the + * name, we can't allocate the TFM. + */ + if (!sctp_hmac_list[id].hmac_name) + continue; + + /* If this TFM has been allocated, we are all set */ + if (ep->auth_hmacs[id]) + continue; + + /* Allocate the ID */ + tfm = crypto_alloc_hash(sctp_hmac_list[id].hmac_name, 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) + goto out_err; + + ep->auth_hmacs[id] = tfm; + } + + return 0; + +out_err: + /* Clean up any successfull allocations */ + sctp_auth_destroy_hmacs(ep->auth_hmacs); + return -ENOMEM; +} + +/* Destroy the hmac tfm array */ +void sctp_auth_destroy_hmacs(struct crypto_hash *auth_hmacs[]) +{ + int i; + + if (!auth_hmacs) + return; + + for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++) + { + if (auth_hmacs[i]) + crypto_free_hash(auth_hmacs[i]); + } + kfree(auth_hmacs); +} + + +struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id) +{ + return &sctp_hmac_list[hmac_id]; +} + +/* Get an hmac description information that we can use to build + * the AUTH chunk + */ +struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc) +{ + struct sctp_hmac_algo_param *hmacs; + __u16 n_elt; + __u16 id = 0; + int i; + + /* If we have a default entry, use it */ + if (asoc->default_hmac_id) + return &sctp_hmac_list[asoc->default_hmac_id]; + + /* Since we do not have a default entry, find the first entry + * we support and return that. Do not cache that id. + */ + hmacs = asoc->peer.peer_hmacs; + if (!hmacs) + return NULL; + + n_elt = (ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t)) >> 1; + for (i = 0; i < n_elt; i++) { + id = ntohs(hmacs->hmac_ids[i]); + + /* Check the id is in the supported range */ + if (id > SCTP_AUTH_HMAC_ID_MAX) + continue; + + /* See is we support the id. Supported IDs have name and + * length fields set, so that we can allocated and use + * them. We can safely just check for name, for without the + * name, we can't allocate the TFM. + */ + if (!sctp_hmac_list[id].hmac_name) + continue; + + break; + } + + if (id == 0) + return NULL; + + return &sctp_hmac_list[id]; +} + +static int __sctp_auth_find_hmacid(__u16 *hmacs, int n_elts, __u16 hmac_id) +{ + int found = 0; + int i; + + for (i = 0; i < n_elts; i++) { + if (hmac_id == hmacs[i]) { + found = 1; + break; + } + } + + return found; +} + +/* See if the HMAC_ID is one that we claim as supported */ +int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, + __u16 hmac_id) +{ + struct sctp_hmac_algo_param *hmacs; + __u16 n_elt; + + if (!asoc) + return 0; + + hmacs = (struct sctp_hmac_algo_param *)asoc->c.auth_hmacs; + n_elt = (ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t)) >> 1; + + return __sctp_auth_find_hmacid(hmacs->hmac_ids, n_elt, hmac_id); +} + + +/* Cache the default HMAC id. This to follow this text from SCTP-AUTH: + * Section 6.1: + * The receiver of a HMAC-ALGO parameter SHOULD use the first listed + * algorithm it supports. + */ +void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, + struct sctp_hmac_algo_param *hmacs) +{ + struct sctp_endpoint *ep; + __u16 id; + int i; + int n_params; + + /* if the default id is already set, use it */ + if (asoc->default_hmac_id) + return; + + n_params = (ntohs(hmacs->param_hdr.length) + - sizeof(sctp_paramhdr_t)) >> 1; + ep = asoc->ep; + for (i = 0; i < n_params; i++) { + id = ntohs(hmacs->hmac_ids[i]); + + /* Check the id is in the supported range */ + if (id > SCTP_AUTH_HMAC_ID_MAX) + continue; + + /* If this TFM has been allocated, use this id */ + if (ep->auth_hmacs[id]) { + asoc->default_hmac_id = id; + break; + } + } +} + + +/* Check to see if the given chunk is supposed to be authenticated */ +static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param) +{ + unsigned short len; + int found = 0; + int i; + + if (!param) + return 0; + + len = ntohs(param->param_hdr.length) - sizeof(sctp_paramhdr_t); + + /* SCTP-AUTH, Section 3.2 + * The chunk types for INIT, INIT-ACK, SHUTDOWN-COMPLETE and AUTH + * chunks MUST NOT be listed in the CHUNKS parameter. However, if + * a CHUNKS parameter is received then the types for INIT, INIT-ACK, + * SHUTDOWN-COMPLETE and AUTH chunks MUST be ignored. + */ + for (i = 0; !found && i < len; i++) { + switch (param->chunks[i]) { + case SCTP_CID_INIT: + case SCTP_CID_INIT_ACK: + case SCTP_CID_SHUTDOWN_COMPLETE: + case SCTP_CID_AUTH: + break; + + default: + if (param->chunks[i] == chunk) + found = 1; + break; + } + } + + return found; +} + +/* Check if peer requested that this chunk is authenticated */ +int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc) +{ + if (!sctp_auth_enable || !asoc || !asoc->peer.auth_capable) + return 0; + + return __sctp_auth_cid(chunk, asoc->peer.peer_chunks); +} + +/* Check if we requested that peer authenticate this chunk. */ +int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc) +{ + if (!sctp_auth_enable || !asoc) + return 0; + + return __sctp_auth_cid(chunk, + (struct sctp_chunks_param *)asoc->c.auth_chunks); +} + +/* SCTP-AUTH: Section 6.2: + * The sender MUST calculate the MAC as described in RFC2104 [2] using + * the hash function H as described by the MAC Identifier and the shared + * association key K based on the endpoint pair shared key described by + * the shared key identifier. The 'data' used for the computation of + * the AUTH-chunk is given by the AUTH chunk with its HMAC field set to + * zero (as shown in Figure 6) followed by all chunks that are placed + * after the AUTH chunk in the SCTP packet. + */ +void sctp_auth_calculate_hmac(const struct sctp_association *asoc, + struct sk_buff *skb, + struct sctp_auth_chunk *auth, + gfp_t gfp) +{ + struct scatterlist sg; + struct hash_desc desc; + struct sctp_auth_bytes *asoc_key; + __u16 key_id, hmac_id; + __u8 *digest; + unsigned char *end; + int free_key = 0; + + /* Extract the info we need: + * - hmac id + * - key id + */ + key_id = ntohs(auth->auth_hdr.shkey_id); + hmac_id = ntohs(auth->auth_hdr.hmac_id); + + if (key_id == asoc->active_key_id) + asoc_key = asoc->asoc_shared_key; + else { + struct sctp_shared_key *ep_key; + + ep_key = sctp_auth_get_shkey(asoc, key_id); + if (!ep_key) + return; + + asoc_key = sctp_auth_asoc_create_secret(asoc, ep_key, gfp); + if (!asoc_key) + return; + + free_key = 1; + } + + /* set up scatter list */ + end = skb_tail_pointer(skb); + sg.page = virt_to_page(auth); + sg.offset = (unsigned long)(auth) % PAGE_SIZE; + sg.length = end - (unsigned char *)auth; + + desc.tfm = asoc->ep->auth_hmacs[hmac_id]; + desc.flags = 0; + + digest = auth->auth_hdr.hmac; + if (crypto_hash_setkey(desc.tfm, &asoc_key->data[0], asoc_key->len)) + goto free; + + crypto_hash_digest(&desc, &sg, sg.length, digest); + +free: + if (free_key) + sctp_auth_key_put(asoc_key); +} diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c index fcfb9d806de1..2cf6ad6ff8ce 100644 --- a/net/sctp/objcnt.c +++ b/net/sctp/objcnt.c @@ -58,6 +58,7 @@ SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(addr); SCTP_DBG_OBJCNT(ssnmap); SCTP_DBG_OBJCNT(datamsg); +SCTP_DBG_OBJCNT(keys); /* An array to make it easy to pretty print the debug information * to the proc fs. @@ -73,6 +74,7 @@ static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { SCTP_DBG_OBJCNT_ENTRY(addr), SCTP_DBG_OBJCNT_ENTRY(ssnmap), SCTP_DBG_OBJCNT_ENTRY(datamsg), + SCTP_DBG_OBJCNT_ENTRY(keys), }; /* Callback from procfs to read out objcount information. From a29a5bd4f5c3e8ba2e89688feab8b01c44f1654f Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sun, 16 Sep 2007 19:31:35 -0700 Subject: [PATCH 1409/2804] [SCTP]: Implement SCTP-AUTH initializations. The patch initializes AUTH related members of the generic SCTP structures and provides a way to enable/disable auth extension. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/associola.c | 34 +++++++++++++++++ net/sctp/endpointola.c | 83 ++++++++++++++++++++++++++++++++++++++++++ net/sctp/output.c | 4 ++ net/sctp/protocol.c | 3 ++ net/sctp/sysctl.c | 9 +++++ 5 files changed, 133 insertions(+) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 9bad8ba0feda..ee4b212e66b1 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -74,6 +74,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a { struct sctp_sock *sp; int i; + sctp_paramhdr_t *p; + int err; /* Retrieve the SCTP per socket area. */ sp = sctp_sk((struct sock *)sk); @@ -298,6 +300,30 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->default_timetolive = sp->default_timetolive; asoc->default_rcv_context = sp->default_rcv_context; + /* AUTH related initializations */ + INIT_LIST_HEAD(&asoc->endpoint_shared_keys); + err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); + if (err) + goto fail_init; + + asoc->active_key_id = ep->active_key_id; + asoc->asoc_shared_key = NULL; + + asoc->default_hmac_id = 0; + /* Save the hmacs and chunks list into this association */ + if (ep->auth_hmacs_list) + memcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list, + ntohs(ep->auth_hmacs_list->param_hdr.length)); + if (ep->auth_chunk_list) + memcpy(asoc->c.auth_chunks, ep->auth_chunk_list, + ntohs(ep->auth_chunk_list->param_hdr.length)); + + /* Get the AUTH random number for this association */ + p = (sctp_paramhdr_t *)asoc->c.auth_random; + p->type = SCTP_PARAM_RANDOM; + p->length = htons(sizeof(sctp_paramhdr_t) + SCTP_AUTH_RANDOM_LENGTH); + get_random_bytes(p+1, SCTP_AUTH_RANDOM_LENGTH); + return asoc; fail_init: @@ -407,6 +433,12 @@ void sctp_association_free(struct sctp_association *asoc) if (asoc->addip_last_asconf) sctp_chunk_free(asoc->addip_last_asconf); + /* AUTH - Free the endpoint shared keys */ + sctp_auth_destroy_keys(&asoc->endpoint_shared_keys); + + /* AUTH - Free the association shared key */ + sctp_auth_key_put(asoc->asoc_shared_key); + sctp_association_put(asoc); } @@ -1112,6 +1144,8 @@ void sctp_assoc_update(struct sctp_association *asoc, sctp_assoc_set_id(asoc, GFP_ATOMIC); } } + + /* SCTP-AUTH: XXX something needs to be done here*/ } /* Update the retran path for sending a retransmitted packet. diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 22371185efb6..c8d5023606a5 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -69,12 +69,56 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, struct sock *sk, gfp_t gfp) { + struct sctp_hmac_algo_param *auth_hmacs = NULL; + struct sctp_chunks_param *auth_chunks = NULL; + struct sctp_shared_key *null_key; + int err; + memset(ep, 0, sizeof(struct sctp_endpoint)); ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp); if (!ep->digest) return NULL; + if (sctp_auth_enable) { + /* Allocate space for HMACS and CHUNKS authentication + * variables. There are arrays that we encode directly + * into parameters to make the rest of the operations easier. + */ + auth_hmacs = kzalloc(sizeof(sctp_hmac_algo_param_t) + + sizeof(__u16) * SCTP_AUTH_NUM_HMACS, gfp); + if (!auth_hmacs) + goto nomem; + + auth_chunks = kzalloc(sizeof(sctp_chunks_param_t) + + SCTP_NUM_CHUNK_TYPES, gfp); + if (!auth_chunks) + goto nomem; + + /* Initialize the HMACS parameter. + * SCTP-AUTH: Section 3.3 + * Every endpoint supporting SCTP chunk authentication MUST + * support the HMAC based on the SHA-1 algorithm. + */ + auth_hmacs->param_hdr.type = SCTP_PARAM_HMAC_ALGO; + auth_hmacs->param_hdr.length = + htons(sizeof(sctp_paramhdr_t) + 2); + auth_hmacs->hmac_ids[0] = htons(SCTP_AUTH_HMAC_ID_SHA1); + + /* Initialize the CHUNKS parameter */ + auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; + + /* If the Add-IP functionality is enabled, we must + * authenticate, ASCONF and ASCONF-ACK chunks + */ + if (sctp_addip_enable) { + auth_chunks->chunks[0] = SCTP_CID_ASCONF; + auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK; + auth_chunks->param_hdr.length = + htons(sizeof(sctp_paramhdr_t) + 2); + } + } + /* Initialize the base structure. */ /* What type of endpoint are we? */ ep->base.type = SCTP_EP_TYPE_SOCKET; @@ -114,7 +158,36 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ep->last_key = ep->current_key = 0; ep->key_changed_at = jiffies; + /* SCTP-AUTH extensions*/ + INIT_LIST_HEAD(&ep->endpoint_shared_keys); + null_key = sctp_auth_shkey_create(0, GFP_KERNEL); + if (!null_key) + goto nomem; + + list_add(&null_key->key_list, &ep->endpoint_shared_keys); + + /* Allocate and initialize transorms arrays for suported HMACs. */ + err = sctp_auth_init_hmacs(ep, gfp); + if (err) + goto nomem_hmacs; + + /* Add the null key to the endpoint shared keys list and + * set the hmcas and chunks pointers. + */ + ep->auth_hmacs_list = auth_hmacs; + ep->auth_chunk_list = auth_chunks; + return ep; + +nomem_hmacs: + sctp_auth_destroy_keys(&ep->endpoint_shared_keys); +nomem: + /* Free all allocations */ + kfree(auth_hmacs); + kfree(auth_chunks); + kfree(ep->digest); + return NULL; + } /* Create a sctp_endpoint with all that boring stuff initialized. @@ -187,6 +260,16 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) /* Free the digest buffer */ kfree(ep->digest); + /* SCTP-AUTH: Free up AUTH releated data such as shared keys + * chunks and hmacs arrays that were allocated + */ + sctp_auth_destroy_keys(&ep->endpoint_shared_keys); + kfree(ep->auth_hmacs_list); + kfree(ep->auth_chunk_list); + + /* AUTH - Free any allocated HMAC transform containers */ + sctp_auth_destroy_hmacs(ep->auth_hmacs); + /* Cleanup. */ sctp_inq_free(&ep->base.inqueue); sctp_bind_addr_free(&ep->base.bind_addr); diff --git a/net/sctp/output.c b/net/sctp/output.c index d85543def754..49b9f5f031a4 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -79,7 +79,9 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, packet->vtag = vtag; packet->has_cookie_echo = 0; packet->has_sack = 0; + packet->has_auth = 0; packet->ipfragok = 0; + packet->auth = NULL; if (ecn_capable && sctp_packet_empty(packet)) { chunk = sctp_get_ecne_prepend(packet->transport->asoc); @@ -121,8 +123,10 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, packet->vtag = 0; packet->has_cookie_echo = 0; packet->has_sack = 0; + packet->has_auth = 0; packet->ipfragok = 0; packet->malloced = 0; + packet->auth = NULL; return packet; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 3ec8b12b6da4..4e6b59e8b695 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1185,6 +1185,9 @@ SCTP_STATIC __init int sctp_init(void) /* Enable PR-SCTP by default. */ sctp_prsctp_enable = 1; + /* Disable AUTH by default. */ + sctp_auth_enable = 0; + sctp_sysctl_register(); INIT_LIST_HEAD(&sctp_address_families); diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 39b10ee2f017..0669778e4335 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -254,6 +254,15 @@ static ctl_table sctp_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "auth_enable", + .data = &sctp_auth_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, { .ctl_name = 0 } }; From 730fc3d05cd4ba4c9ce2de91f3d43349e95dbbf5 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sun, 16 Sep 2007 19:32:11 -0700 Subject: [PATCH 1410/2804] [SCTP]: Implete SCTP-AUTH parameter processing Implement processing for the CHUNKS, RANDOM, and HMAC parameters and deal with how this parameters are effected by association restarts. In particular, during unexpeted INIT processing, we need to reply with parameters from the original INIT chunk. Also, after restart, we need to update the old association with new peer parameters and change the association shared keys. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/command.h | 1 + net/sctp/associola.c | 21 ++++- net/sctp/sm_make_chunk.c | 162 ++++++++++++++++++++++++++++++++++++- net/sctp/sm_sideeffect.c | 5 ++ net/sctp/sm_statefuns.c | 35 ++++++++ 5 files changed, 220 insertions(+), 4 deletions(-) diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index f56c8d695a82..b8733364557f 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -102,6 +102,7 @@ typedef enum { SCTP_CMD_SET_SK_ERR, /* Set sk_err */ SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */ SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */ + SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */ SCTP_CMD_LAST } sctp_verb_t; diff --git a/net/sctp/associola.c b/net/sctp/associola.c index ee4b212e66b1..3bdd8dcb76a7 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -415,6 +415,9 @@ void sctp_association_free(struct sctp_association *asoc) /* Free peer's cached cookie. */ kfree(asoc->peer.cookie); + kfree(asoc->peer.peer_random); + kfree(asoc->peer.peer_chunks); + kfree(asoc->peer.peer_hmacs); /* Release the transport structures. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { @@ -1145,7 +1148,23 @@ void sctp_assoc_update(struct sctp_association *asoc, } } - /* SCTP-AUTH: XXX something needs to be done here*/ + /* SCTP-AUTH: Save the peer parameters from the new assocaitions + * and also move the association shared keys over + */ + kfree(asoc->peer.peer_random); + asoc->peer.peer_random = new->peer.peer_random; + new->peer.peer_random = NULL; + + kfree(asoc->peer.peer_chunks); + asoc->peer.peer_chunks = new->peer.peer_chunks; + new->peer.peer_chunks = NULL; + + kfree(asoc->peer.peer_hmacs); + asoc->peer.peer_hmacs = new->peer.peer_hmacs; + new->peer.peer_hmacs = NULL; + + sctp_auth_key_put(asoc->asoc_shared_key); + sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC); } /* Update the retran path for sending a retransmitted packet. diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 71cc204a9ea5..4c02875786ac 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -182,6 +182,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, sctp_supported_ext_param_t ext_param; int num_ext = 0; __u8 extensions[3]; + sctp_paramhdr_t *auth_chunks = NULL, + *auth_hmacs = NULL; /* RFC 2960 3.3.2 Initiation (INIT) (1) * @@ -214,8 +216,6 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, * An implementation supporting this extension [ADDIP] MUST list * the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and * INIT-ACK parameters. - * XXX: We don't support AUTH just yet, so don't list it. AUTH - * support should add it. */ if (sctp_addip_enable) { extensions[num_ext] = SCTP_CID_ASCONF; @@ -226,6 +226,29 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, chunksize += sizeof(aiparam); chunksize += vparam_len; + /* Account for AUTH related parameters */ + if (sctp_auth_enable) { + /* Add random parameter length*/ + chunksize += sizeof(asoc->c.auth_random); + + /* Add HMACS parameter length if any were defined */ + auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; + if (auth_hmacs->length) + chunksize += ntohs(auth_hmacs->length); + else + auth_hmacs = NULL; + + /* Add CHUNKS parameter length */ + auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; + if (auth_chunks->length) + chunksize += ntohs(auth_chunks->length); + else + auth_hmacs = NULL; + + extensions[num_ext] = SCTP_CID_AUTH; + num_ext += 1; + } + /* If we have any extensions to report, account for that */ if (num_ext) chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; @@ -285,6 +308,17 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, aiparam.adaptation_ind = htonl(sp->adaptation_ind); sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); + /* Add SCTP-AUTH chunks to the parameter list */ + if (sctp_auth_enable) { + sctp_addto_chunk(retval, sizeof(asoc->c.auth_random), + asoc->c.auth_random); + if (auth_hmacs) + sctp_addto_chunk(retval, ntohs(auth_hmacs->length), + auth_hmacs); + if (auth_chunks) + sctp_addto_chunk(retval, ntohs(auth_chunks->length), + auth_chunks); + } nodata: kfree(addrs.v); return retval; @@ -305,6 +339,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, sctp_supported_ext_param_t ext_param; int num_ext = 0; __u8 extensions[3]; + sctp_paramhdr_t *auth_chunks = NULL, + *auth_hmacs = NULL, + *auth_random = NULL; retval = NULL; @@ -350,6 +387,26 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, chunksize += sizeof(ext_param) + num_ext; chunksize += sizeof(aiparam); + if (asoc->peer.auth_capable) { + auth_random = (sctp_paramhdr_t *)asoc->c.auth_random; + chunksize += ntohs(auth_random->length); + + auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; + if (auth_hmacs->length) + chunksize += ntohs(auth_hmacs->length); + else + auth_hmacs = NULL; + + auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; + if (auth_chunks->length) + chunksize += ntohs(auth_chunks->length); + else + auth_chunks = NULL; + + extensions[num_ext] = SCTP_CID_AUTH; + num_ext += 1; + } + /* Now allocate and fill out the chunk. */ retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); if (!retval) @@ -381,6 +438,17 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind); sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); + if (asoc->peer.auth_capable) { + sctp_addto_chunk(retval, ntohs(auth_random->length), + auth_random); + if (auth_hmacs) + sctp_addto_chunk(retval, ntohs(auth_hmacs->length), + auth_hmacs); + if (auth_chunks) + sctp_addto_chunk(retval, ntohs(auth_chunks->length), + auth_chunks); + } + /* We need to remove the const qualifier at this point. */ retval->asoc = (struct sctp_association *) asoc; @@ -1736,6 +1804,12 @@ static void sctp_process_ext_param(struct sctp_association *asoc, !asoc->peer.prsctp_capable) asoc->peer.prsctp_capable = 1; break; + case SCTP_CID_AUTH: + /* if the peer reports AUTH, assume that he + * supports AUTH. + */ + asoc->peer.auth_capable = 1; + break; case SCTP_CID_ASCONF: case SCTP_CID_ASCONF_ACK: /* don't need to do anything for ASCONF */ @@ -1871,7 +1945,42 @@ static int sctp_verify_param(const struct sctp_association *asoc, case SCTP_PARAM_FWD_TSN_SUPPORT: if (sctp_prsctp_enable) break; + goto fallthrough; + + case SCTP_PARAM_RANDOM: + if (!sctp_auth_enable) + goto fallthrough; + + /* SCTP-AUTH: Secion 6.1 + * If the random number is not 32 byte long the association + * MUST be aborted. The ABORT chunk SHOULD contain the error + * cause 'Protocol Violation'. + */ + if (SCTP_AUTH_RANDOM_LENGTH != + ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) + return sctp_process_inv_paramlength(asoc, param.p, + chunk, err_chunk); + break; + + case SCTP_PARAM_CHUNKS: + if (!sctp_auth_enable) + goto fallthrough; + + /* SCTP-AUTH: Section 3.2 + * The CHUNKS parameter MUST be included once in the INIT or + * INIT-ACK chunk if the sender wants to receive authenticated + * chunks. Its maximum length is 260 bytes. + */ + if (260 < ntohs(param.p->length)) + return sctp_process_inv_paramlength(asoc, param.p, + chunk, err_chunk); + break; + + case SCTP_PARAM_HMAC_ALGO: + if (!sctp_auth_enable) + break; /* Fall Through */ +fallthrough: default: SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", ntohs(param.p->type), cid); @@ -1976,13 +2085,19 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, } /* Process the initialization parameters. */ - sctp_walk_params(param, peer_init, init_hdr.params) { if (!sctp_process_param(asoc, param, peer_addr, gfp)) goto clean_up; } + /* AUTH: After processing the parameters, make sure that we + * have all the required info to potentially do authentications. + */ + if (asoc->peer.auth_capable && (!asoc->peer.peer_random || + !asoc->peer.peer_hmacs)) + asoc->peer.auth_capable = 0; + /* Walk list of transports, removing transports in the UNKNOWN state. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); @@ -2222,6 +2337,47 @@ static int sctp_process_param(struct sctp_association *asoc, break; } /* Fall Through */ + goto fall_through; + + case SCTP_PARAM_RANDOM: + if (!sctp_auth_enable) + goto fall_through; + + /* Save peer's random parameter */ + asoc->peer.peer_random = kmemdup(param.p, + ntohs(param.p->length), gfp); + if (!asoc->peer.peer_random) { + retval = 0; + break; + } + break; + + case SCTP_PARAM_HMAC_ALGO: + if (!sctp_auth_enable) + goto fall_through; + + /* Save peer's HMAC list */ + asoc->peer.peer_hmacs = kmemdup(param.p, + ntohs(param.p->length), gfp); + if (!asoc->peer.peer_hmacs) { + retval = 0; + break; + } + + /* Set the default HMAC the peer requested*/ + sctp_auth_asoc_set_default_hmac(asoc, param.hmac_algo); + break; + + case SCTP_PARAM_CHUNKS: + if (!sctp_auth_enable) + goto fall_through; + + asoc->peer.peer_chunks = kmemdup(param.p, + ntohs(param.p->length), gfp); + if (!asoc->peer.peer_chunks) + retval = 0; + break; +fall_through: default: /* Any unrecognized parameters should have been caught * and handled by sctp_verify_param() which should be diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 8d7890083493..bbdc938da86f 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1524,6 +1524,11 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, sctp_cmd_adaptation_ind(commands, asoc); break; + case SCTP_CMD_ASSOC_SHKEY: + error = sctp_auth_asoc_init_active_key(asoc, + GFP_ATOMIC); + 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 ec0328b1cdb1..385486360fe9 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -549,6 +549,11 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_COOKIE_ECHOED)); + /* SCTP-AUTH: genereate the assocition shared keys so that + * we can potentially signe the COOKIE-ECHO. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_SHKEY, SCTP_NULL()); + /* 5.1 C) "A" shall then send the State Cookie received in the * INIT ACK chunk in a COOKIE ECHO chunk, ... */ @@ -686,6 +691,14 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, peer_init, GFP_ATOMIC)) goto nomem_init; + /* SCTP-AUTH: Now that we've populate required fields in + * sctp_process_init, set up the assocaition shared keys as + * necessary so that we can potentially authenticate the ACK + */ + error = sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC); + if (error) + goto nomem_init; + repl = sctp_make_cookie_ack(new_asoc, chunk); if (!repl) goto nomem_init; @@ -1247,6 +1260,26 @@ static void sctp_tietags_populate(struct sctp_association *new_asoc, new_asoc->c.initial_tsn = asoc->c.initial_tsn; } +static void sctp_auth_params_populate(struct sctp_association *new_asoc, + const struct sctp_association *asoc) +{ + /* Only perform this if AUTH extension is enabled */ + if (!sctp_auth_enable) + return; + + /* We need to provide the same parameter information as + * was in the original INIT. This means that we need to copy + * the HMACS, CHUNKS, and RANDOM parameter from the original + * assocaition. + */ + memcpy(new_asoc->c.auth_random, asoc->c.auth_random, + sizeof(asoc->c.auth_random)); + memcpy(new_asoc->c.auth_hmacs, asoc->c.auth_hmacs, + sizeof(asoc->c.auth_hmacs)); + memcpy(new_asoc->c.auth_chunks, asoc->c.auth_chunks, + sizeof(asoc->c.auth_chunks)); +} + /* * Compare vtag/tietag values to determine unexpected COOKIE-ECHO * handling action. @@ -1404,6 +1437,8 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( sctp_tietags_populate(new_asoc, asoc); + sctp_auth_params_populate(new_asoc, asoc); + /* B) "Z" shall respond immediately with an INIT ACK chunk. */ /* If there are errors need to be reported for unknown parameters, From 4cd57c8078fae0a4b1bf421191e94626d0cba92a Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sun, 16 Sep 2007 19:32:45 -0700 Subject: [PATCH 1411/2804] [SCTP]: Enable the sending of the AUTH chunk. SCTP-AUTH, Section 6.2: Endpoints MUST send all requested chunks authenticated where this has been requested by the peer. The other chunks MAY be sent authenticated or not. If endpoint pair shared keys are used, one of them MUST be selected for authentication. To send chunks in an authenticated way, the sender MUST include these chunks after an AUTH chunk. This means that a sender MUST bundle chunks in order to authenticate them. If the endpoint has no endpoint pair shared key for the peer, it MUST use Shared Key Identifier 0 with an empty endpoint pair shared key. If there are multiple endpoint shared keys the sender selects one and uses the corresponding Shared Key Identifier Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/sm.h | 1 + include/net/sctp/structs.h | 3 + net/sctp/chunk.c | 12 ++++ net/sctp/output.c | 133 +++++++++++++++++++++++++++++-------- net/sctp/sm_make_chunk.c | 39 +++++++++++ 5 files changed, 160 insertions(+), 28 deletions(-) diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index e8e3a64eb322..148cdb4b9606 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -256,6 +256,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, __u32 new_cum_tsn, size_t nstreams, struct sctp_fwdtsn_skip *skiplist); +struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc); void sctp_chunk_assign_tsn(struct sctp_chunk *); void sctp_chunk_assign_ssn(struct sctp_chunk *); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 18b06afacea0..31841c3a7fe8 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -798,6 +798,9 @@ struct sctp_packet { /* 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; diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 77fb7b06a9c4..619d0f2dee51 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -194,6 +194,18 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, 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. + */ + if (sctp_auth_send_cid(SCTP_CID_DATA, asoc)) { + struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc); + + if (hmac_desc) + max -= WORD_ROUND(sizeof(sctp_auth_chunk_t) + + hmac_desc->hmac_len); + } + whole = 0; first_len = max; diff --git a/net/sctp/output.c b/net/sctp/output.c index 49b9f5f031a4..847639d542c0 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -80,6 +80,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, packet->has_cookie_echo = 0; packet->has_sack = 0; packet->has_auth = 0; + packet->has_data = 0; packet->ipfragok = 0; packet->auth = NULL; @@ -124,6 +125,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, 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; @@ -185,6 +187,39 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, return retval; } +/* Try to bundle an auth chunk into the packet. */ +static sctp_xmit_t sctp_packet_bundle_auth(struct sctp_packet *pkt, + struct sctp_chunk *chunk) +{ + struct sctp_association *asoc = pkt->transport->asoc; + struct sctp_chunk *auth; + sctp_xmit_t retval = SCTP_XMIT_OK; + + /* if we don't have an association, we can't do authentication */ + if (!asoc) + return retval; + + /* 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) + return retval; + + /* if the peer did not request this chunk to be authenticated, + * don't do it + */ + if (!chunk->auth) + return retval; + + auth = sctp_make_auth(asoc); + if (!auth) + return retval; + + retval = sctp_packet_append_chunk(pkt, auth); + + return retval; +} + /* Try to bundle a SACK with the packet. */ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt, struct sctp_chunk *chunk) @@ -231,12 +266,17 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet, chunk); - retval = sctp_packet_bundle_sack(packet, chunk); - psize = packet->size; - + /* Try to bundle AUTH chunk */ + retval = sctp_packet_bundle_auth(packet, chunk); if (retval != SCTP_XMIT_OK) goto finish; + /* Try to bundle SACK chunk */ + retval = sctp_packet_bundle_sack(packet, chunk); + if (retval != SCTP_XMIT_OK) + goto finish; + + psize = packet->size; pmtu = ((packet->transport->asoc) ? (packet->transport->asoc->pathmtu) : (packet->transport->pathmtu)); @@ -245,10 +285,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, /* Decide if we need to fragment or resubmit later. */ if (too_big) { - /* Both control chunks and data chunks with TSNs are - * non-fragmentable. + /* 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)) { + 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 @@ -270,16 +316,31 @@ append: /* DATA is a special case since we must examine both rwnd and cwnd * before we send DATA. */ - if (sctp_chunk_is_data(chunk)) { + switch (chunk->chunk_hdr->type) { + case SCTP_CID_DATA: retval = sctp_packet_append_data(packet, chunk); /* Disallow SACK bundling after DATA. */ packet->has_sack = 1; + /* Disallow AUTH bundling after DATA */ + packet->has_auth = 1; + /* Let it be knows that packet has DATA in it */ + packet->has_data = 1; if (SCTP_XMIT_OK != retval) goto finish; - } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) + break; + case SCTP_CID_COOKIE_ECHO: packet->has_cookie_echo = 1; - else if (SCTP_CID_SACK == chunk->chunk_hdr->type) + break; + + case SCTP_CID_SACK: packet->has_sack = 1; + break; + + case SCTP_CID_AUTH: + packet->has_auth = 1; + packet->auth = chunk; + break; + } /* It is OK to send this chunk. */ list_add_tail(&chunk->list, &packet->chunk_list); @@ -307,6 +368,8 @@ int sctp_packet_transmit(struct sctp_packet *packet) int padding; /* How much padding do we need? */ __u8 has_data = 0; struct dst_entry *dst = tp->dst; + unsigned char *auth = NULL; /* pointer to auth in skb data */ + __u32 cksum_buf_len = sizeof(struct sctphdr); SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); @@ -360,16 +423,6 @@ int sctp_packet_transmit(struct sctp_packet *packet) sh->vtag = htonl(packet->vtag); sh->checksum = 0; - /* 2) Calculate the Adler-32 checksum of the whole packet, - * including the SCTP common header and all the - * chunks. - * - * Note: Adler-32 is no longer applicable, as has been replaced - * by CRC32-C as described in . - */ - if (!(dst->dev->features & NETIF_F_NO_CSUM)) - crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr)); - /** * 6.10 Bundling * @@ -420,14 +473,16 @@ int sctp_packet_transmit(struct sctp_packet *packet) if (padding) memset(skb_put(chunk->skb, padding), 0, padding); - if (dst->dev->features & NETIF_F_NO_CSUM) - memcpy(skb_put(nskb, chunk->skb->len), + /* if this is the auth chunk that we are adding, + * store pointer where it will be added and put + * the auth into the packet. + */ + if (chunk == packet->auth) + auth = skb_tail_pointer(nskb); + + cksum_buf_len += chunk->skb->len; + memcpy(skb_put(nskb, chunk->skb->len), chunk->skb->data, chunk->skb->len); - else - crc32 = sctp_update_copy_cksum(skb_put(nskb, - chunk->skb->len), - chunk->skb->data, - chunk->skb->len, crc32); SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n", "*** Chunk", chunk, @@ -449,9 +504,31 @@ int sctp_packet_transmit(struct sctp_packet *packet) sctp_chunk_free(chunk); } - /* Perform final transformation on checksum. */ - if (!(dst->dev->features & NETIF_F_NO_CSUM)) + /* SCTP-AUTH, Section 6.2 + * The sender MUST calculate the MAC as described in RFC2104 [2] + * using the hash function H as described by the MAC Identifier and + * the shared association key K based on the endpoint pair shared key + * described by the shared key identifier. The 'data' used for the + * computation of the AUTH-chunk is given by the AUTH chunk with its + * HMAC field set to zero (as shown in Figure 6) followed by all + * chunks that are placed after the AUTH chunk in the SCTP packet. + */ + if (auth) + sctp_auth_calculate_hmac(asoc, nskb, + (struct sctp_auth_chunk *)auth, + GFP_ATOMIC); + + /* 2) Calculate the Adler-32 checksum of the whole packet, + * including the SCTP common header and all the + * chunks. + * + * Note: Adler-32 is no longer applicable, as has been replaced + * by CRC32-C as described in . + */ + if (!(dst->dev->features & NETIF_F_NO_CSUM)) { + crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); crc32 = sctp_end_cksum(crc32); + } /* 3) Put the resultant value into the checksum field in the * common header, and leave the rest of the bits unchanged. diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 4c02875786ac..fa2ba543183d 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1111,6 +1111,41 @@ nodata: return retval; } +struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc) +{ + struct sctp_chunk *retval; + struct sctp_hmac *hmac_desc; + struct sctp_authhdr auth_hdr; + __u8 *hmac; + + /* Get the first hmac that the peer told us to use */ + hmac_desc = sctp_auth_asoc_get_hmac(asoc); + if (unlikely(!hmac_desc)) + return NULL; + + retval = sctp_make_chunk(asoc, SCTP_CID_AUTH, 0, + hmac_desc->hmac_len + sizeof(sctp_authhdr_t)); + if (!retval) + return NULL; + + auth_hdr.hmac_id = htons(hmac_desc->hmac_id); + auth_hdr.shkey_id = htons(asoc->active_key_id); + + retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(sctp_authhdr_t), + &auth_hdr); + + hmac = skb_put(retval->skb, hmac_desc->hmac_len); + memset(hmac, 0, hmac_desc->hmac_len); + + /* Adjust the chunk header to include the empty MAC */ + retval->chunk_hdr->length = + htons(ntohs(retval->chunk_hdr->length) + hmac_desc->hmac_len); + retval->chunk_end = skb_tail_pointer(retval->skb); + + return retval; +} + + /******************************************************************** * 2nd Level Abstractions ********************************************************************/ @@ -1225,6 +1260,10 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, retval->chunk_hdr = chunk_hdr; retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(struct sctp_chunkhdr); + /* Determine if the chunk needs to be authenticated */ + if (sctp_auth_send_cid(type, asoc)) + retval->auth = 1; + /* Set the skb to the belonging sock for accounting. */ skb->sk = sk; From bbd0d59809f923ea2b540cbd781b32110e249f6e Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 3 Oct 2007 17:51:34 -0700 Subject: [PATCH 1412/2804] [SCTP]: Implement the receive and verification of AUTH chunk This patch implements the receive path needed to process authenticated chunks. Add ability to process the AUTH chunk and handle edge cases for authenticated COOKIE-ECHO as well. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/constants.h | 4 +- include/net/sctp/sm.h | 1 + include/net/sctp/structs.h | 8 ++ net/sctp/associola.c | 10 ++ net/sctp/endpointola.c | 29 +++++ net/sctp/input.c | 65 +++++++++-- net/sctp/inqueue.c | 19 +++ net/sctp/sm_statefuns.c | 218 ++++++++++++++++++++++++++++++++++- net/sctp/sm_statetable.c | 33 ++++++ 9 files changed, 374 insertions(+), 13 deletions(-) diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 777118f06dba..da8354e8e33c 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -183,7 +183,9 @@ typedef enum { SCTP_IERROR_NO_DATA, SCTP_IERROR_BAD_STREAM, SCTP_IERROR_BAD_PORTS, - + SCTP_IERROR_AUTH_BAD_HMAC, + SCTP_IERROR_AUTH_BAD_KEYID, + SCTP_IERROR_PROTO_VIOLATION, } sctp_ierror_t; diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 148cdb4b9606..bf2f5ed69c15 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -143,6 +143,7 @@ sctp_state_fn_t sctp_sf_do_asconf_ack; sctp_state_fn_t sctp_sf_do_9_2_reshutack; sctp_state_fn_t sctp_sf_eat_fwd_tsn; sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast; +sctp_state_fn_t sctp_sf_eat_auth; /* Prototypes for primitive event state functions. */ sctp_state_fn_t sctp_sf_do_prm_asoc; diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 31841c3a7fe8..47e54f8e2b65 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -724,6 +724,13 @@ struct sctp_chunk { */ struct sctp_transport *transport; + /* SCTP-AUTH: For the special case inbound processing of COOKIE-ECHO + * we need save a pointer to the AUTH chunk, since the SCTP-AUTH + * spec violates the principle premis that all chunks are processed + * in order. + */ + struct sk_buff *auth_chunk; + __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ __u8 resent; /* Has this chunk ever been retransmitted. */ __u8 has_tsn; /* Does this chunk have a TSN yet? */ @@ -1067,6 +1074,7 @@ void sctp_inq_init(struct sctp_inq *); void sctp_inq_free(struct sctp_inq *); void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); +struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *); void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t); /* This is the structure we use to hold outbound chunks. You push diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 3bdd8dcb76a7..03158e3665da 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1011,6 +1011,16 @@ static void sctp_assoc_bh_rcv(struct work_struct *work) state = asoc->state; subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); + /* SCTP-AUTH, Section 6.3: + * The receiver has a list of chunk types which it expects + * to be received only after an AUTH-chunk. This list has + * been sent to the peer during the association setup. It + * MUST silently discard these chunks if they are not placed + * after an AUTH chunk in the packet. + */ + if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth) + continue; + /* Remember where the last DATA chunk came from so we * know where to send the SACK. */ diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index c8d5023606a5..2d2d81ef4a69 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -400,6 +400,7 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) sctp_subtype_t subtype; sctp_state_t state; int error = 0; + int first_time = 1; /* is this the first time through the looop */ if (ep->base.dead) return; @@ -411,6 +412,29 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) while (NULL != (chunk = sctp_inq_pop(inqueue))) { subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); + /* If the first chunk in the packet is AUTH, do special + * processing specified in Section 6.3 of SCTP-AUTH spec + */ + if (first_time && (subtype.chunk == SCTP_CID_AUTH)) { + struct sctp_chunkhdr *next_hdr; + + next_hdr = sctp_inq_peek(inqueue); + if (!next_hdr) + goto normal; + + /* If the next chunk is COOKIE-ECHO, skip the AUTH + * chunk while saving a pointer to it so we can do + * Authentication later (during cookie-echo + * processing). + */ + if (next_hdr->type == SCTP_CID_COOKIE_ECHO) { + chunk->auth_chunk = skb_clone(chunk->skb, + GFP_ATOMIC); + chunk->auth = 1; + continue; + } + } +normal: /* We might have grown an association since last we * looked, so try again. * @@ -426,6 +450,8 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) } state = asoc ? asoc->state : SCTP_STATE_CLOSED; + if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth) + continue; /* Remember where the last DATA chunk came from so we * know where to send the SACK. @@ -449,5 +475,8 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) */ if (!sctp_sk(sk)->ep) break; + + if (first_time) + first_time = 0; } } diff --git a/net/sctp/input.c b/net/sctp/input.c index f9a0c9276e3b..86503e7fa21e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -911,15 +911,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, ch = (sctp_chunkhdr_t *) skb->data; - /* If this is INIT/INIT-ACK look inside the chunk too. */ - switch (ch->type) { - case SCTP_CID_INIT: - case SCTP_CID_INIT_ACK: - break; - default: - return NULL; - } - /* The code below will attempt to walk the chunk and extract * parameter information. Before we do that, we need to verify * that the chunk length doesn't cause overflow. Otherwise, we'll @@ -964,6 +955,60 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, return NULL; } +/* SCTP-AUTH, Section 6.3: +* If the receiver does not find a STCB for a packet containing an AUTH +* chunk as the first chunk and not a COOKIE-ECHO chunk as the second +* chunk, it MUST use the chunks after the AUTH chunk to look up an existing +* association. +* +* This means that any chunks that can help us identify the association need +* to be looked at to find this assocation. +* +* TODO: The only chunk currently defined that can do that is ASCONF, but we +* don't support that functionality yet. +*/ +static struct sctp_association *__sctp_rcv_auth_lookup(struct sk_buff *skb, + const union sctp_addr *paddr, + const union sctp_addr *laddr, + struct sctp_transport **transportp) +{ + /* XXX - walk through the chunks looking for something that can + * help us find the association. INIT, and INIT-ACK are not permitted. + * That leaves ASCONF, but we don't support that yet. + */ + return NULL; +} + +/* + * There are circumstances when we need to look inside the SCTP packet + * for information to help us find the association. Examples + * include looking inside of INIT/INIT-ACK chunks or after the AUTH + * chunks. + */ +static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, + const union sctp_addr *paddr, + const union sctp_addr *laddr, + struct sctp_transport **transportp) +{ + sctp_chunkhdr_t *ch; + + ch = (sctp_chunkhdr_t *) skb->data; + + /* If this is INIT/INIT-ACK look inside the chunk too. */ + switch (ch->type) { + case SCTP_CID_INIT: + case SCTP_CID_INIT_ACK: + return __sctp_rcv_init_lookup(skb, laddr, transportp); + break; + + case SCTP_CID_AUTH: + return __sctp_rcv_auth_lookup(skb, paddr, laddr, transportp); + break; + } + + return NULL; +} + /* Lookup an association for an inbound skb. */ static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, const union sctp_addr *paddr, @@ -979,7 +1024,7 @@ static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, * parameters within the INIT or INIT-ACK. */ if (!asoc) - asoc = __sctp_rcv_init_lookup(skb, laddr, transportp); + asoc = __sctp_rcv_lookup_harder(skb, paddr, laddr, transportp); return asoc; } diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index e4ea7fdf36ed..f10fe7fbf24c 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -100,6 +100,25 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) q->immediate.func(&q->immediate); } +/* Peek at the next chunk on the inqeue. */ +struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue) +{ + struct sctp_chunk *chunk; + sctp_chunkhdr_t *ch = NULL; + + chunk = queue->in_progress; + /* If there is no more chunks in this packet, say so */ + if (chunk->singleton || + chunk->end_of_packet || + chunk->pdiscard) + return NULL; + + ch = (sctp_chunkhdr_t *)chunk->chunk_end; + + return ch; +} + + /* Extract a chunk from an SCTP inqueue. * * WARNING: If you need to put the chunk on another queue, you need to diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 385486360fe9..5aef4aafdfdc 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -138,6 +138,11 @@ static sctp_disposition_t sctp_sf_violation_chunk( void *arg, sctp_cmd_seq_t *commands); +static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + struct sctp_chunk *chunk); + /* Small helper function that checks if the chunk length * is of the appropriate length. The 'required_length' argument * is set to be the size of a specific chunk we are testing. @@ -495,8 +500,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, &err_chunk)) { - SCTP_INC_STATS(SCTP_MIB_ABORTEDS); - /* This chunk contains fatal error. It is to be discarded. * Send an ABORT, with causes if there is any. */ @@ -521,6 +524,22 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); error = SCTP_ERROR_INV_PARAM; } + + /* SCTP-AUTH, Section 6.3: + * It should be noted that if the receiver wants to tear + * down an association in an authenticated way only, the + * handling of malformed packets should not result in + * tearing down the association. + * + * This means that if we only want to abort associations + * in an authenticated way (i.e AUTH+ABORT), then we + * can't destory this association just becuase the packet + * was malformed. + */ + if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc)) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + SCTP_INC_STATS(SCTP_MIB_ABORTEDS); return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, asoc, chunk->transport); } @@ -699,6 +718,36 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, if (error) goto nomem_init; + /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo + * is supposed to be authenticated and we have to do delayed + * authentication. We've just recreated the association using + * the information in the cookie and now it's much easier to + * do the authentication. + */ + if (chunk->auth_chunk) { + struct sctp_chunk auth; + sctp_ierror_t ret; + + /* set-up our fake chunk so that we can process it */ + auth.skb = chunk->auth_chunk; + auth.asoc = chunk->asoc; + auth.sctp_hdr = chunk->sctp_hdr; + auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk, + sizeof(sctp_chunkhdr_t)); + skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t)); + auth.transport = chunk->transport; + + ret = sctp_sf_authenticate(ep, new_asoc, type, &auth); + + /* We can now safely free the auth_chunk clone */ + kfree_skb(chunk->auth_chunk); + + if (ret != SCTP_IERROR_NO_ERROR) { + sctp_association_free(new_asoc); + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + } + repl = sctp_make_cookie_ack(new_asoc, chunk); if (!repl) goto nomem_init; @@ -3652,6 +3701,156 @@ gen_shutdown: return SCTP_DISPOSITION_CONSUME; } +/* + * SCTP-AUTH Section 6.3 Receving authenticated chukns + * + * The receiver MUST use the HMAC algorithm indicated in the HMAC + * Identifier field. If this algorithm was not specified by the + * receiver in the HMAC-ALGO parameter in the INIT or INIT-ACK chunk + * during association setup, the AUTH chunk and all chunks after it MUST + * be discarded and an ERROR chunk SHOULD be sent with the error cause + * defined in Section 4.1. + * + * If an endpoint with no shared key receives a Shared Key Identifier + * other than 0, it MUST silently discard all authenticated chunks. If + * the endpoint has at least one endpoint pair shared key for the peer, + * it MUST use the key specified by the Shared Key Identifier if a + * key has been configured for that Shared Key Identifier. If no + * endpoint pair shared key has been configured for that Shared Key + * Identifier, all authenticated chunks MUST be silently discarded. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * The return value is the disposition of the chunk. + */ +static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + struct sctp_chunk *chunk) +{ + struct sctp_authhdr *auth_hdr; + struct sctp_hmac *hmac; + unsigned int sig_len; + __u16 key_id; + __u8 *save_digest; + __u8 *digest; + + /* Pull in the auth header, so we can do some more verification */ + auth_hdr = (struct sctp_authhdr *)chunk->skb->data; + chunk->subh.auth_hdr = auth_hdr; + skb_pull(chunk->skb, sizeof(struct sctp_authhdr)); + + /* Make sure that we suport the HMAC algorithm from the auth + * chunk. + */ + if (!sctp_auth_asoc_verify_hmac_id(asoc, auth_hdr->hmac_id)) + return SCTP_IERROR_AUTH_BAD_HMAC; + + /* Make sure that the provided shared key identifier has been + * configured + */ + key_id = ntohs(auth_hdr->shkey_id); + if (key_id != asoc->active_key_id && !sctp_auth_get_shkey(asoc, key_id)) + return SCTP_IERROR_AUTH_BAD_KEYID; + + + /* Make sure that the length of the signature matches what + * we expect. + */ + sig_len = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_auth_chunk_t); + hmac = sctp_auth_get_hmac(ntohs(auth_hdr->hmac_id)); + if (sig_len != hmac->hmac_len) + return SCTP_IERROR_PROTO_VIOLATION; + + /* Now that we've done validation checks, we can compute and + * verify the hmac. The steps involved are: + * 1. Save the digest from the chunk. + * 2. Zero out the digest in the chunk. + * 3. Compute the new digest + * 4. Compare saved and new digests. + */ + digest = auth_hdr->hmac; + skb_pull(chunk->skb, sig_len); + + save_digest = kmemdup(digest, sig_len, GFP_ATOMIC); + if (!save_digest) + goto nomem; + + memset(digest, 0, sig_len); + + sctp_auth_calculate_hmac(asoc, chunk->skb, + (struct sctp_auth_chunk *)chunk->chunk_hdr, + GFP_ATOMIC); + + /* Discard the packet if the digests do not match */ + if (memcmp(save_digest, digest, sig_len)) { + kfree(save_digest); + return SCTP_IERROR_BAD_SIG; + } + + kfree(save_digest); + chunk->auth = 1; + + return SCTP_IERROR_NO_ERROR; +nomem: + return SCTP_IERROR_NOMEM; +} + +sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_authhdr *auth_hdr; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *err_chunk; + sctp_ierror_t error; + + if (!sctp_vtag_verify(chunk, asoc)) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + SCTP_NULL()); + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + /* Make sure that the AUTH chunk has valid length. */ + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_auth_chunk))) + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); + + auth_hdr = (struct sctp_authhdr *)chunk->skb->data; + error = sctp_sf_authenticate(ep, asoc, type, chunk); + switch (error) { + case SCTP_IERROR_AUTH_BAD_HMAC: + /* Generate the ERROR chunk and discard the rest + * of the packet + */ + err_chunk = sctp_make_op_error(asoc, chunk, + SCTP_ERROR_UNSUP_HMAC, + &auth_hdr->hmac_id, + sizeof(__u16)); + if (err_chunk) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err_chunk)); + } + /* Fall Through */ + case SCTP_IERROR_AUTH_BAD_KEYID: + case SCTP_IERROR_BAD_SIG: + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + break; + case SCTP_IERROR_PROTO_VIOLATION: + return sctp_sf_violation_chunklen(ep, asoc, type, arg, + commands); + break; + case SCTP_IERROR_NOMEM: + return SCTP_DISPOSITION_NOMEM; + default: + break; + } + + return SCTP_DISPOSITION_CONSUME; +} + /* * Process an unknown chunk. * @@ -3857,6 +4056,20 @@ static sctp_disposition_t sctp_sf_abort_violation( if (!abort) goto nomem; + /* SCTP-AUTH, Section 6.3: + * It should be noted that if the receiver wants to tear + * down an association in an authenticated way only, the + * handling of malformed packets should not result in + * tearing down the association. + * + * This means that if we only want to abort associations + * in an authenticated way (i.e AUTH+ABORT), then we + * can't destory this association just becuase the packet + * was malformed. + */ + if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc)) + goto discard; + if (asoc) { sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); @@ -3894,6 +4107,7 @@ static sctp_disposition_t sctp_sf_abort_violation( SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); } +discard: sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); SCTP_INC_STATS(SCTP_MIB_ABORTEDS); diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index ddb0ba3974b0..a93a4bc8f68f 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -523,6 +523,34 @@ static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUN TYPE_SCTP_FWD_TSN, }; /*state_fn_t prsctp_chunk_event_table[][] */ +#define TYPE_SCTP_AUTH { \ + /* SCTP_STATE_EMPTY */ \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ + /* SCTP_STATE_CLOSED */ \ + TYPE_SCTP_FUNC(sctp_sf_ootb), \ + /* SCTP_STATE_COOKIE_WAIT */ \ + TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ + /* SCTP_STATE_ESTABLISHED */ \ + TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ +} /* TYPE_SCTP_AUTH */ + +/* The primary index for this table is the chunk type. + * The secondary index for this table is the state. + */ +static const sctp_sm_table_entry_t auth_chunk_event_table[SCTP_NUM_AUTH_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_AUTH, +}; /*state_fn_t auth_chunk_event_table[][] */ + static const sctp_sm_table_entry_t chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { /* SCTP_STATE_EMPTY */ @@ -976,5 +1004,10 @@ static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, return &addip_chunk_event_table[1][state]; } + if (sctp_auth_enable) { + if (cid == SCTP_CID_AUTH) + return &auth_chunk_event_table[0][state]; + } + return &chunk_event_table_unknown[state]; } From 65b07e5d0d09c77e98050b5f0146ead29e5add32 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sun, 16 Sep 2007 19:34:00 -0700 Subject: [PATCH 1413/2804] [SCTP]: API updates to suport SCTP-AUTH extensions. Add SCTP-AUTH API. The API implemented here was agreed to between implementors at the 9th SCTP Interop. It will be documented in the next revision of the SCTP socket API spec. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/auth.h | 16 ++ include/net/sctp/ulpevent.h | 4 + include/net/sctp/user.h | 90 +++++++++++ net/sctp/auth.c | 193 +++++++++++++++++++++++ net/sctp/sm_statefuns.c | 13 ++ net/sctp/socket.c | 304 ++++++++++++++++++++++++++++++++++++ net/sctp/ulpevent.c | 37 +++++ 7 files changed, 657 insertions(+) diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h index 10c8010552ff..4945954a16af 100644 --- a/include/net/sctp/auth.h +++ b/include/net/sctp/auth.h @@ -43,6 +43,7 @@ struct sctp_endpoint; struct sctp_association; struct sctp_authkey; +struct sctp_hmacalgo; /* * Define a generic struct that will hold all the info @@ -109,4 +110,19 @@ int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc); void sctp_auth_calculate_hmac(const struct sctp_association *asoc, struct sk_buff *skb, struct sctp_auth_chunk *auth, gfp_t gfp); + +/* API Helpers */ +int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id); +int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, + struct sctp_hmacalgo *hmacs); +int sctp_auth_set_key(struct sctp_endpoint *ep, + struct sctp_association *asoc, + struct sctp_authkey *auth_key); +int sctp_auth_set_active_key(struct sctp_endpoint *ep, + struct sctp_association *asoc, + __u16 key_id); +int sctp_auth_del_key_id(struct sctp_endpoint *ep, + struct sctp_association *asoc, + __u16 key_id); + #endif diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index de88ed5b0ba6..922a151eb93c 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -128,6 +128,10 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, struct sctp_chunk *chunk, gfp_t gfp); +struct sctp_ulpevent *sctp_ulpevent_make_authkey( + const struct sctp_association *asoc, __u16 key_id, + __u32 indication, gfp_t gfp); + void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, struct msghdr *); __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 6d2b57758cca..00848b641f59 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -103,6 +103,21 @@ enum sctp_optname { #define SCTP_PARTIAL_DELIVERY_POINT SCTP_PARTIAL_DELIVERY_POINT SCTP_MAX_BURST, /* Set/Get max burst */ #define SCTP_MAX_BURST SCTP_MAX_BURST + SCTP_AUTH_CHUNK, /* Set only: add a chunk type to authenticat */ +#define SCTP_AUTH_CHUNK SCTP_AUTH_CHUNK + SCTP_HMAC_IDENT, +#define SCTP_HMAC_IDENT SCTP_HMAC_IDENT + SCTP_AUTH_KEY, +#define SCTP_AUTH_KEY SCTP_AUTH_KEY + SCTP_AUTH_ACTIVE_KEY, +#define SCTP_AUTH_ACTIVE_KEY SCTP_AUTH_ACTIVE_KEY + SCTP_AUTH_DELETE_KEY, +#define SCTP_AUTH_DELETE_KEY SCTP_AUTH_DELETE_KEY + SCTP_PEER_AUTH_CHUNKS, /* Read only */ +#define SCTP_PEER_AUTH_CHUNKS SCTP_PEER_AUTH_CHUNKS + SCTP_LOCAL_AUTH_CHUNKS, /* Read only */ +#define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS + /* Internal Socket Options. Some of the sctp library functions are * implemented using these socket options. @@ -370,6 +385,19 @@ struct sctp_pdapi_event { enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, }; +struct sctp_authkey_event { + __u16 auth_type; + __u16 auth_flags; + __u32 auth_length; + __u16 auth_keynumber; + __u16 auth_altkeynumber; + __u32 auth_indication; + sctp_assoc_t auth_assoc_id; +}; + +enum { SCTP_AUTH_NEWKEY = 0, }; + + /* * Described in Section 7.3 * Ancillary Data and Notification Interest Options @@ -405,6 +433,7 @@ union sctp_notification { struct sctp_shutdown_event sn_shutdown_event; struct sctp_adaptation_event sn_adaptation_event; struct sctp_pdapi_event sn_pdapi_event; + struct sctp_authkey_event sn_authkey_event; }; /* Section 5.3.1 @@ -421,6 +450,7 @@ enum sctp_sn_type { SCTP_SHUTDOWN_EVENT, SCTP_PARTIAL_DELIVERY_EVENT, SCTP_ADAPTATION_INDICATION, + SCTP_AUTHENTICATION_EVENT, }; /* Notification error codes used to fill up the error fields in some @@ -539,6 +569,54 @@ struct sctp_paddrparams { __u32 spp_flags; } __attribute__((packed, aligned(4))); +/* + * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) + * + * This set option adds a chunk type that the user is requesting to be + * received only in an authenticated way. Changes to the list of chunks + * will only effect future associations on the socket. + */ +struct sctp_authchunk { + __u8 sauth_chunk; +}; + +/* + * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) + * + * This option gets or sets the list of HMAC algorithms that the local + * endpoint requires the peer to use. +*/ +struct sctp_hmacalgo { + __u16 shmac_num_idents; + __u16 shmac_idents[]; +}; + +/* + * 7.1.20. Set a shared key (SCTP_AUTH_KEY) + * + * This option will set a shared secret key which is used to build an + * association shared key. + */ +struct sctp_authkey { + sctp_assoc_t sca_assoc_id; + __u16 sca_keynumber; + __u16 sca_keylen; + __u8 sca_key[]; +}; + +/* + * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) + * + * This option will get or set the active shared key to be used to build + * the association shared key. + */ + +struct sctp_authkeyid { + sctp_assoc_t scact_assoc_id; + __u16 scact_keynumber; +}; + + /* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) * * This options will get or set the delayed ack timer. The time is set @@ -607,6 +685,18 @@ struct sctp_status { struct sctp_paddrinfo sstat_primary; }; +/* + * 7.2.3. Get the list of chunks the peer requires to be authenticated + * (SCTP_PEER_AUTH_CHUNKS) + * + * This option gets a list of chunks for a specified association that + * the peer requires to be received authenticated only. + */ +struct sctp_authchunks { + sctp_assoc_t gauth_assoc_id; + uint8_t gauth_chunks[]; +}; + /* * 8.3, 8.5 get all peer/local addresses in an association. * This parameter struct is used by SCTP_GET_PEER_ADDRS and diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 2a29409a38d9..781810724714 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -743,3 +743,196 @@ free: if (free_key) sctp_auth_key_put(asoc_key); } + +/* API Helpers */ + +/* Add a chunk to the endpoint authenticated chunk list */ +int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id) +{ + struct sctp_chunks_param *p = ep->auth_chunk_list; + __u16 nchunks; + __u16 param_len; + + /* If this chunk is already specified, we are done */ + if (__sctp_auth_cid(chunk_id, p)) + return 0; + + /* Check if we can add this chunk to the array */ + param_len = ntohs(p->param_hdr.length); + nchunks = param_len - sizeof(sctp_paramhdr_t); + if (nchunks == SCTP_NUM_CHUNK_TYPES) + return -EINVAL; + + p->chunks[nchunks] = chunk_id; + p->param_hdr.length = htons(param_len + 1); + return 0; +} + +/* Add hmac identifires to the endpoint list of supported hmac ids */ +int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, + struct sctp_hmacalgo *hmacs) +{ + int has_sha1 = 0; + __u16 id; + int i; + + /* Scan the list looking for unsupported id. Also make sure that + * SHA1 is specified. + */ + for (i = 0; i < hmacs->shmac_num_idents; i++) { + id = hmacs->shmac_idents[i]; + + if (SCTP_AUTH_HMAC_ID_SHA1 == id) + has_sha1 = 1; + + if (!sctp_hmac_list[id].hmac_name) + return -EOPNOTSUPP; + } + + if (!has_sha1) + return -EINVAL; + + memcpy(ep->auth_hmacs_list->hmac_ids, &hmacs->shmac_idents[0], + hmacs->shmac_num_idents * sizeof(__u16)); + ep->auth_hmacs_list->param_hdr.length = htons(sizeof(sctp_paramhdr_t) + + hmacs->shmac_num_idents * sizeof(__u16)); + return 0; +} + +/* Set a new shared key on either endpoint or association. If the + * the key with a same ID already exists, replace the key (remove the + * old key and add a new one). + */ +int sctp_auth_set_key(struct sctp_endpoint *ep, + struct sctp_association *asoc, + struct sctp_authkey *auth_key) +{ + struct sctp_shared_key *cur_key = NULL; + struct sctp_auth_bytes *key; + struct list_head *sh_keys; + int replace = 0; + + /* Try to find the given key id to see if + * we are doing a replace, or adding a new key + */ + if (asoc) + sh_keys = &asoc->endpoint_shared_keys; + else + sh_keys = &ep->endpoint_shared_keys; + + key_for_each(cur_key, sh_keys) { + if (cur_key->key_id == auth_key->sca_keynumber) { + replace = 1; + break; + } + } + + /* If we are not replacing a key id, we need to allocate + * a shared key. + */ + if (!replace) { + cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber, + GFP_KERNEL); + if (!cur_key) + return -ENOMEM; + } + + /* Create a new key data based on the info passed in */ + key = sctp_auth_create_key(auth_key->sca_keylen, GFP_KERNEL); + if (!key) + goto nomem; + + memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylen); + + /* If we are replacing, remove the old keys data from the + * key id. If we are adding new key id, add it to the + * list. + */ + if (replace) + sctp_auth_key_put(cur_key->key); + else + list_add(&cur_key->key_list, sh_keys); + + cur_key->key = key; + sctp_auth_key_hold(key); + + return 0; +nomem: + if (!replace) + sctp_auth_shkey_free(cur_key); + + return -ENOMEM; +} + +int sctp_auth_set_active_key(struct sctp_endpoint *ep, + struct sctp_association *asoc, + __u16 key_id) +{ + struct sctp_shared_key *key; + struct list_head *sh_keys; + int found = 0; + + /* The key identifier MUST correst to an existing key */ + if (asoc) + sh_keys = &asoc->endpoint_shared_keys; + else + sh_keys = &ep->endpoint_shared_keys; + + key_for_each(key, sh_keys) { + if (key->key_id == key_id) { + found = 1; + break; + } + } + + if (!found) + return -EINVAL; + + if (asoc) { + asoc->active_key_id = key_id; + sctp_auth_asoc_init_active_key(asoc, GFP_KERNEL); + } else + ep->active_key_id = key_id; + + return 0; +} + +int sctp_auth_del_key_id(struct sctp_endpoint *ep, + struct sctp_association *asoc, + __u16 key_id) +{ + struct sctp_shared_key *key; + struct list_head *sh_keys; + int found = 0; + + /* The key identifier MUST NOT be the current active key + * The key identifier MUST correst to an existing key + */ + if (asoc) { + if (asoc->active_key_id == key_id) + return -EINVAL; + + sh_keys = &asoc->endpoint_shared_keys; + } else { + if (ep->active_key_id == key_id) + return -EINVAL; + + sh_keys = &ep->endpoint_shared_keys; + } + + key_for_each(key, sh_keys) { + if (key->key_id == key_id) { + found = 1; + break; + } + } + + if (!found) + return -EINVAL; + + /* Delete the shared key */ + list_del_init(&key->key_list); + sctp_auth_shkey_free(key); + + return 0; +} diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 5aef4aafdfdc..f01b408508ff 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3848,6 +3848,19 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep, break; } + if (asoc->active_key_id != ntohs(auth_hdr->shkey_id)) { + struct sctp_ulpevent *ev; + + ev = sctp_ulpevent_make_authkey(asoc, ntohs(auth_hdr->shkey_id), + SCTP_AUTH_NEWKEY, GFP_ATOMIC); + + if (!ev) + return -ENOMEM; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } + return SCTP_DISPOSITION_CONSUME; } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 7738915011a0..f3e1a9c811ad 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2946,6 +2946,164 @@ static int sctp_setsockopt_maxburst(struct sock *sk, return 0; } +/* + * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) + * + * This set option adds a chunk type that the user is requesting to be + * received only in an authenticated way. Changes to the list of chunks + * will only effect future associations on the socket. + */ +static int sctp_setsockopt_auth_chunk(struct sock *sk, + char __user *optval, + int optlen) +{ + struct sctp_authchunk val; + + if (optlen != sizeof(struct sctp_authchunk)) + return -EINVAL; + if (copy_from_user(&val, optval, optlen)) + return -EFAULT; + + switch (val.sauth_chunk) { + case SCTP_CID_INIT: + case SCTP_CID_INIT_ACK: + case SCTP_CID_SHUTDOWN_COMPLETE: + case SCTP_CID_AUTH: + return -EINVAL; + } + + /* add this chunk id to the endpoint */ + return sctp_auth_ep_add_chunkid(sctp_sk(sk)->ep, val.sauth_chunk); +} + +/* + * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) + * + * This option gets or sets the list of HMAC algorithms that the local + * endpoint requires the peer to use. + */ +static int sctp_setsockopt_hmac_ident(struct sock *sk, + char __user *optval, + int optlen) +{ + struct sctp_hmacalgo *hmacs; + int err; + + if (optlen < sizeof(struct sctp_hmacalgo)) + return -EINVAL; + + hmacs = kmalloc(optlen, GFP_KERNEL); + if (!hmacs) + return -ENOMEM; + + if (copy_from_user(hmacs, optval, optlen)) { + err = -EFAULT; + goto out; + } + + if (hmacs->shmac_num_idents == 0 || + hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) { + err = -EINVAL; + goto out; + } + + err = sctp_auth_ep_set_hmacs(sctp_sk(sk)->ep, hmacs); +out: + kfree(hmacs); + return err; +} + +/* + * 7.1.20. Set a shared key (SCTP_AUTH_KEY) + * + * This option will set a shared secret key which is used to build an + * association shared key. + */ +static int sctp_setsockopt_auth_key(struct sock *sk, + char __user *optval, + int optlen) +{ + struct sctp_authkey *authkey; + struct sctp_association *asoc; + int ret; + + if (optlen <= sizeof(struct sctp_authkey)) + return -EINVAL; + + authkey = kmalloc(optlen, GFP_KERNEL); + if (!authkey) + return -ENOMEM; + + if (copy_from_user(authkey, optval, optlen)) { + ret = -EFAULT; + goto out; + } + + asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); + if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { + ret = -EINVAL; + goto out; + } + + ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey); +out: + kfree(authkey); + return ret; +} + +/* + * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) + * + * This option will get or set the active shared key to be used to build + * the association shared key. + */ +static int sctp_setsockopt_active_key(struct sock *sk, + char __user *optval, + int optlen) +{ + struct sctp_authkeyid val; + struct sctp_association *asoc; + + if (optlen != sizeof(struct sctp_authkeyid)) + return -EINVAL; + if (copy_from_user(&val, optval, optlen)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, val.scact_assoc_id); + if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + return sctp_auth_set_active_key(sctp_sk(sk)->ep, asoc, + val.scact_keynumber); +} + +/* + * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY) + * + * This set option will delete a shared secret key from use. + */ +static int sctp_setsockopt_del_key(struct sock *sk, + char __user *optval, + int optlen) +{ + struct sctp_authkeyid val; + struct sctp_association *asoc; + + if (optlen != sizeof(struct sctp_authkeyid)) + return -EINVAL; + if (copy_from_user(&val, optval, optlen)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, val.scact_assoc_id); + if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + return sctp_auth_del_key_id(sctp_sk(sk)->ep, asoc, + val.scact_keynumber); + +} + + /* API 6.2 setsockopt(), getsockopt() * * Applications use setsockopt() and getsockopt() to set or retrieve @@ -3069,6 +3227,21 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, case SCTP_MAX_BURST: retval = sctp_setsockopt_maxburst(sk, optval, optlen); break; + case SCTP_AUTH_CHUNK: + retval = sctp_setsockopt_auth_chunk(sk, optval, optlen); + break; + case SCTP_HMAC_IDENT: + retval = sctp_setsockopt_hmac_ident(sk, optval, optlen); + break; + case SCTP_AUTH_KEY: + retval = sctp_setsockopt_auth_key(sk, optval, optlen); + break; + case SCTP_AUTH_ACTIVE_KEY: + retval = sctp_setsockopt_active_key(sk, optval, optlen); + break; + case SCTP_AUTH_DELETE_KEY: + retval = sctp_setsockopt_del_key(sk, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -4840,6 +5013,118 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len, return -ENOTSUPP; } +static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + struct sctp_hmac_algo_param *hmacs; + __u16 param_len; + + hmacs = sctp_sk(sk)->ep->auth_hmacs_list; + param_len = ntohs(hmacs->param_hdr.length); + + if (len < param_len) + return -EINVAL; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, hmacs->hmac_ids, len)) + return -EFAULT; + + return 0; +} + +static int sctp_getsockopt_active_key(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + struct sctp_authkeyid val; + struct sctp_association *asoc; + + if (len < sizeof(struct sctp_authkeyid)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) + return -EFAULT; + + asoc = sctp_id2assoc(sk, val.scact_assoc_id); + if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + if (asoc) + val.scact_keynumber = asoc->active_key_id; + else + val.scact_keynumber = sctp_sk(sk)->ep->active_key_id; + + return 0; +} + +static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + struct sctp_authchunks val; + struct sctp_association *asoc; + struct sctp_chunks_param *ch; + char __user *to; + + if (len <= sizeof(struct sctp_authchunks)) + return -EINVAL; + + if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) + return -EFAULT; + + to = val.gauth_chunks; + asoc = sctp_id2assoc(sk, val.gauth_assoc_id); + if (!asoc) + return -EINVAL; + + ch = asoc->peer.peer_chunks; + + /* See if the user provided enough room for all the data */ + if (len < ntohs(ch->param_hdr.length)) + return -EINVAL; + + len = ntohs(ch->param_hdr.length); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(to, ch->chunks, len)) + return -EFAULT; + + return 0; +} + +static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + struct sctp_authchunks val; + struct sctp_association *asoc; + struct sctp_chunks_param *ch; + char __user *to; + + if (len <= sizeof(struct sctp_authchunks)) + return -EINVAL; + + if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) + return -EFAULT; + + to = val.gauth_chunks; + asoc = sctp_id2assoc(sk, val.gauth_assoc_id); + if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + if (asoc) + ch = (struct sctp_chunks_param*)asoc->c.auth_chunks; + else + ch = sctp_sk(sk)->ep->auth_chunk_list; + + if (len < ntohs(ch->param_hdr.length)) + return -EINVAL; + + len = ntohs(ch->param_hdr.length); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(to, ch->chunks, len)) + return -EFAULT; + + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -4963,6 +5248,25 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_MAX_BURST: retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); break; + case SCTP_AUTH_KEY: + case SCTP_AUTH_CHUNK: + case SCTP_AUTH_DELETE_KEY: + retval = -EOPNOTSUPP; + break; + case SCTP_HMAC_IDENT: + retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen); + break; + case SCTP_AUTH_ACTIVE_KEY: + retval = sctp_getsockopt_active_key(sk, len, optval, optlen); + break; + case SCTP_PEER_AUTH_CHUNKS: + retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval, + optlen); + break; + case SCTP_LOCAL_AUTH_CHUNKS: + retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, + optlen); + break; default: retval = -ENOPROTOOPT; break; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 5dc094b9732d..2c17c7efad46 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -813,6 +813,43 @@ fail: return NULL; } +struct sctp_ulpevent *sctp_ulpevent_make_authkey( + const struct sctp_association *asoc, __u16 key_id, + __u32 indication, gfp_t gfp) +{ + struct sctp_ulpevent *event; + struct sctp_authkey_event *ak; + struct sk_buff *skb; + + event = sctp_ulpevent_new(sizeof(struct sctp_authkey_event), + MSG_NOTIFICATION, gfp); + if (!event) + goto fail; + + skb = sctp_event2skb(event); + ak = (struct sctp_authkey_event *) + skb_put(skb, sizeof(struct sctp_authkey_event)); + + ak->auth_type = SCTP_AUTHENTICATION_EVENT; + ak->auth_flags = 0; + ak->auth_length = sizeof(struct sctp_authkey_event); + + ak->auth_keynumber = key_id; + ak->auth_altkeynumber = 0; + ak->auth_indication = indication; + + /* + * The association id field, holds the identifier for the association. + */ + sctp_ulpevent_set_owner(event, asoc); + ak->auth_assoc_id = sctp_assoc2id(asoc); + + return event; +fail: + return NULL; +} + + /* Return the notification type, assuming this is a notification * event. */ From 6b2f9cb64db2d2460da17900bf54266030cc24f1 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sun, 16 Sep 2007 19:35:39 -0700 Subject: [PATCH 1414/2804] [SCTP]: Tie ADD-IP and AUTH functionality as required by spec. ADD-IP spec requires AUTH. It is, in fact, dangerous without AUTH. So, disable ADD-IP functionality if the peer claims to support ADD-IP, but not AUTH. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 1 + net/sctp/sm_make_chunk.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 47e54f8e2b65..448f713a0205 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1543,6 +1543,7 @@ struct sctp_association { __u8 asconf_capable; /* Does peer support ADDIP? */ __u8 prsctp_capable; /* Can peer do PR-SCTP? */ __u8 auth_capable; /* Is peer doing SCTP-AUTH? */ + __u8 addip_capable; /* Can peer do ADD-IP */ __u32 adaptation_ind; /* Adaptation Code point. */ diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index fa2ba543183d..f983a369d4e2 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1851,7 +1851,8 @@ static void sctp_process_ext_param(struct sctp_association *asoc, break; case SCTP_CID_ASCONF: case SCTP_CID_ASCONF_ACK: - /* don't need to do anything for ASCONF */ + asoc->peer.addip_capable = 1; + break; default: break; } @@ -2137,6 +2138,16 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, !asoc->peer.peer_hmacs)) asoc->peer.auth_capable = 0; + + /* If the peer claims support for ADD-IP without support + * for AUTH, disable support for ADD-IP. + */ + if (asoc->peer.addip_capable && !asoc->peer.auth_capable) { + asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP | + SCTP_PARAM_DEL_IP | + SCTP_PARAM_SET_PRIMARY); + } + /* Walk list of transports, removing transports in the UNKNOWN state. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); From 1202d6ff356cc66dc8d2b85546eb4f187f9e1f25 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Mon, 17 Sep 2007 17:13:55 -0700 Subject: [PATCH 1415/2804] [IPG]: add IP1000A driver to kernel tree Signed-off-by: Jesse Huang Signed-off-by: Stefan Lippers-Hollmann Signed-off-by: Francois Romieu Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- MAINTAINERS | 10 + drivers/net/Kconfig | 9 + drivers/net/Makefile | 1 + drivers/net/ipg.c | 2326 +++++++++++++++++++++++++++++++++++++++ drivers/net/ipg.h | 856 ++++++++++++++ include/linux/pci_ids.h | 2 + 6 files changed, 3204 insertions(+) create mode 100644 drivers/net/ipg.c create mode 100644 drivers/net/ipg.h diff --git a/MAINTAINERS b/MAINTAINERS index c35eb125e1ca..27cd503cf0e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2081,6 +2081,16 @@ P: Juanjo Ciarlante M: jjciarla@raiz.uncu.edu.ar S: Maintained +IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER +P: Francois Romieu +M: romieu@fr.zoreil.com +P: Sorbica Shieh +M: sorbica@icplus.com.tw +P: Jesse Huang +M: jesse@icplus.com.tw +L: netdev@vger.kernel.org +S: Maintained + IPATH DRIVER: P: Arthur Jones M: infinipath@qlogic.com diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 76db0bc9452d..63ab05b5a87a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -165,6 +165,15 @@ config NET_SB1000 If you don't have this card, of course say N. +config IP1000 + tristate "IP1000 Gigabit Ethernet support" + depends on PCI && EXPERIMENTAL + ---help--- + This driver supports IP1000 gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called ipg. This is recommended. + source "drivers/net/arcnet/Kconfig" source "drivers/net/phy/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c23ffdbe2599..2098647080a0 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGB) += ixgb/ +obj-$(CONFIG_IP1000) += ipg.o obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ obj-$(CONFIG_EHEA) += ehea/ diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c new file mode 100644 index 000000000000..dfdc96fcadec --- /dev/null +++ b/drivers/net/ipg.c @@ -0,0 +1,2326 @@ +/* + * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter + * + * Copyright (C) 2003, 2007 IC Plus Corp + * + * Original Author: + * + * Craig Rich + * Sundance Technology, Inc. + * www.sundanceti.com + * craig_rich@sundanceti.com + * + * Current Maintainer: + * + * Sorbica Shieh. + * http://www.icplus.com.tw + * sorbica@icplus.com.tw + * + * Jesse Huang + * http://www.icplus.com.tw + * jesse@icplus.com.tw + */ +#include +#include +#include +#include + +#define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH) +#define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH) +#define IPG_RESET_MASK \ + (IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \ + IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \ + IPG_AC_AUTO_INIT) + +#define ipg_w32(val32,reg) iowrite32((val32), ioaddr + (reg)) +#define ipg_w16(val16,reg) iowrite16((val16), ioaddr + (reg)) +#define ipg_w8(val8,reg) iowrite8((val8), ioaddr + (reg)) + +#define ipg_r32(reg) ioread32(ioaddr + (reg)) +#define ipg_r16(reg) ioread16(ioaddr + (reg)) +#define ipg_r8(reg) ioread8(ioaddr + (reg)) + +#define JUMBO_FRAME_4k_ONLY +enum { + netdev_io_size = 128 +}; + +#include "ipg.h" +#define DRV_NAME "ipg" + +MODULE_AUTHOR("IC Plus Corp. 2003"); +MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver " + DrvVer); +MODULE_LICENSE("GPL"); + +static const char *ipg_brand_name[] = { + "IC PLUS IP1000 1000/100/10 based NIC", + "Sundance Technology ST2021 based NIC", + "Tamarack Microelectronics TC9020/9021 based NIC", + "Tamarack Microelectronics TC9020/9021 based NIC", + "D-Link NIC", + "D-Link NIC IP1000A" +}; + +static struct pci_device_id ipg_pci_tbl[] __devinitdata = { + { PCI_VDEVICE(SUNDANCE, 0x1023), 0 }, + { PCI_VDEVICE(SUNDANCE, 0x2021), 1 }, + { PCI_VDEVICE(SUNDANCE, 0x1021), 2 }, + { PCI_VDEVICE(DLINK, 0x9021), 3 }, + { PCI_VDEVICE(DLINK, 0x4000), 4 }, + { PCI_VDEVICE(DLINK, 0x4020), 5 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, ipg_pci_tbl); + +static inline void __iomem *ipg_ioaddr(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + return sp->ioaddr; +} + +#ifdef IPG_DEBUG +static void ipg_dump_rfdlist(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + u32 offset; + + IPG_DEBUG_MSG("_dump_rfdlist\n"); + + printk(KERN_INFO "rx_current = %2.2x\n", sp->rx_current); + printk(KERN_INFO "rx_dirty = %2.2x\n", sp->rx_dirty); + printk(KERN_INFO "RFDList start address = %16.16lx\n", + (unsigned long) sp->rxd_map); + printk(KERN_INFO "RFDListPtr register = %8.8x%8.8x\n", + ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0)); + + for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { + offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd; + printk(KERN_INFO "%2.2x %4.4x RFDNextPtr = %16.16lx\n", i, + offset, (unsigned long) sp->rxd[i].next_desc); + offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd; + printk(KERN_INFO "%2.2x %4.4x RFS = %16.16lx\n", i, + offset, (unsigned long) sp->rxd[i].rfs); + offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd; + printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i, + offset, (unsigned long) sp->rxd[i].frag_info); + } +} + +static void ipg_dump_tfdlist(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + u32 offset; + + IPG_DEBUG_MSG("_dump_tfdlist\n"); + + printk(KERN_INFO "tx_current = %2.2x\n", sp->tx_current); + printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty); + printk(KERN_INFO "TFDList start address = %16.16lx\n", + (unsigned long) sp->txd_map); + printk(KERN_INFO "TFDListPtr register = %8.8x%8.8x\n", + ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0)); + + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { + offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd; + printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i, + offset, (unsigned long) sp->txd[i].next_desc); + + offset = (u32) &sp->txd[i].tfc - (u32) sp->txd; + printk(KERN_INFO "%2.2x %4.4x TFC = %16.16lx\n", i, + offset, (unsigned long) sp->txd[i].tfc); + offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd; + printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i, + offset, (unsigned long) sp->txd[i].frag_info); + } +} +#endif + +static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data) +{ + ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL); + ndelay(IPG_PC_PHYCTRLWAIT_NS); +} + +static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data) +{ + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data); + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data); +} + +static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity) +{ + phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR; + + ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity); +} + +static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity) +{ + ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR | + phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL); +} + +static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity) +{ + u16 bit_data; + + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity); + + bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1; + + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity); + + return bit_data; +} + +/* + * Read a register from the Physical Layer device located + * on the IPG NIC, using the IPG PHYCTRL register. + */ +static int mdio_read(struct net_device * dev, int phy_id, int phy_reg) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + /* + * The GMII mangement frame structure for a read is as follows: + * + * |Preamble|st|op|phyad|regad|ta| data |idle| + * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z | + * + * <32 1s> = 32 consecutive logic 1 values + * A = bit of Physical Layer device address (MSB first) + * R = bit of register address (MSB first) + * z = High impedance state + * D = bit of read data (MSB first) + * + * Transmission order is 'Preamble' field first, bits transmitted + * left to right (first to last). + */ + struct { + u32 field; + unsigned int len; + } p[] = { + { GMII_PREAMBLE, 32 }, /* Preamble */ + { GMII_ST, 2 }, /* ST */ + { GMII_READ, 2 }, /* OP */ + { phy_id, 5 }, /* PHYAD */ + { phy_reg, 5 }, /* REGAD */ + { 0x0000, 2 }, /* TA */ + { 0x0000, 16 }, /* DATA */ + { 0x0000, 1 } /* IDLE */ + }; + unsigned int i, j; + u8 polarity, data; + + polarity = ipg_r8(PHY_CTRL); + polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY); + + /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */ + for (j = 0; j < 5; j++) { + for (i = 0; i < p[j].len; i++) { + /* For each variable length field, the MSB must be + * transmitted first. Rotate through the field bits, + * starting with the MSB, and move each bit into the + * the 1st (2^1) bit position (this is the bit position + * corresponding to the MgmtData bit of the PhyCtrl + * register for the IPG). + * + * Example: ST = 01; + * + * First write a '0' to bit 1 of the PhyCtrl + * register, then write a '1' to bit 1 of the + * PhyCtrl register. + * + * To do this, right shift the MSB of ST by the value: + * [field length - 1 - #ST bits already written] + * then left shift this result by 1. + */ + data = (p[j].field >> (p[j].len - 1 - i)) << 1; + data &= IPG_PC_MGMTDATA; + data |= polarity | IPG_PC_MGMTDIR; + + ipg_drive_phy_ctl_low_high(ioaddr, data); + } + } + + send_three_state(ioaddr, polarity); + + read_phy_bit(ioaddr, polarity); + + /* + * For a read cycle, the bits for the next two fields (TA and + * DATA) are driven by the PHY (the IPG reads these bits). + */ + for (i = 0; i < p[6].len; i++) { + p[6].field |= + (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i)); + } + + send_three_state(ioaddr, polarity); + send_three_state(ioaddr, polarity); + send_three_state(ioaddr, polarity); + send_end(ioaddr, polarity); + + /* Return the value of the DATA field. */ + return p[6].field; +} + +/* + * Write to a register from the Physical Layer device located + * on the IPG NIC, using the IPG PHYCTRL register. + */ +static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + /* + * The GMII mangement frame structure for a read is as follows: + * + * |Preamble|st|op|phyad|regad|ta| data |idle| + * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z | + * + * <32 1s> = 32 consecutive logic 1 values + * A = bit of Physical Layer device address (MSB first) + * R = bit of register address (MSB first) + * z = High impedance state + * D = bit of write data (MSB first) + * + * Transmission order is 'Preamble' field first, bits transmitted + * left to right (first to last). + */ + struct { + u32 field; + unsigned int len; + } p[] = { + { GMII_PREAMBLE, 32 }, /* Preamble */ + { GMII_ST, 2 }, /* ST */ + { GMII_WRITE, 2 }, /* OP */ + { phy_id, 5 }, /* PHYAD */ + { phy_reg, 5 }, /* REGAD */ + { 0x0002, 2 }, /* TA */ + { val & 0xffff, 16 }, /* DATA */ + { 0x0000, 1 } /* IDLE */ + }; + unsigned int i, j; + u8 polarity, data; + + polarity = ipg_r8(PHY_CTRL); + polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY); + + /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */ + for (j = 0; j < 7; j++) { + for (i = 0; i < p[j].len; i++) { + /* For each variable length field, the MSB must be + * transmitted first. Rotate through the field bits, + * starting with the MSB, and move each bit into the + * the 1st (2^1) bit position (this is the bit position + * corresponding to the MgmtData bit of the PhyCtrl + * register for the IPG). + * + * Example: ST = 01; + * + * First write a '0' to bit 1 of the PhyCtrl + * register, then write a '1' to bit 1 of the + * PhyCtrl register. + * + * To do this, right shift the MSB of ST by the value: + * [field length - 1 - #ST bits already written] + * then left shift this result by 1. + */ + data = (p[j].field >> (p[j].len - 1 - i)) << 1; + data &= IPG_PC_MGMTDATA; + data |= polarity | IPG_PC_MGMTDIR; + + ipg_drive_phy_ctl_low_high(ioaddr, data); + } + } + + /* The last cycle is a tri-state, so read from the PHY. */ + for (j = 7; j < 8; j++) { + for (i = 0; i < p[j].len; i++) { + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity); + + p[j].field |= ((ipg_r8(PHY_CTRL) & + IPG_PC_MGMTDATA) >> 1) << (p[j].len - 1 - i); + + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity); + } + } +} + +/* Set LED_Mode JES20040127EEPROM */ +static void ipg_set_led_mode(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + u32 mode; + + mode = ipg_r32(ASIC_CTRL); + mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED); + + if ((sp->LED_Mode & 0x03) > 1) + mode |= IPG_AC_LED_MODE_BIT_1; /* Write Asic Control Bit 29 */ + + if ((sp->LED_Mode & 0x01) == 1) + mode |= IPG_AC_LED_MODE; /* Write Asic Control Bit 14 */ + + if ((sp->LED_Mode & 0x08) == 8) + mode |= IPG_AC_LED_SPEED; /* Write Asic Control Bit 27 */ + + ipg_w32(mode, ASIC_CTRL); +} + +/* Set PHYSet JES20040127EEPROM */ +static void ipg_set_phy_set(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + int physet; + + physet = ipg_r8(PHY_SET); + physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET); + physet |= ((sp->LED_Mode & 0x70) >> 4); + ipg_w8(physet, PHY_SET); +} + +static int ipg_reset(struct net_device *dev, u32 resetflags) +{ + /* Assert functional resets via the IPG AsicCtrl + * register as specified by the 'resetflags' input + * parameter. + */ + void __iomem *ioaddr = ipg_ioaddr(dev); //JES20040127EEPROM: + unsigned int timeout_count = 0; + + IPG_DEBUG_MSG("_reset\n"); + + ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL); + + /* Delay added to account for problem with 10Mbps reset. */ + mdelay(IPG_AC_RESETWAIT); + + while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) { + mdelay(IPG_AC_RESETWAIT); + if (++timeout_count > IPG_AC_RESET_TIMEOUT) + return -ETIME; + } + /* Set LED Mode in Asic Control JES20040127EEPROM */ + ipg_set_led_mode(dev); + + /* Set PHYSet Register Value JES20040127EEPROM */ + ipg_set_phy_set(dev); + return 0; +} + +/* Find the GMII PHY address. */ +static int ipg_find_phyaddr(struct net_device *dev) +{ + unsigned int phyaddr, i; + + for (i = 0; i < 32; i++) { + u32 status; + + /* Search for the correct PHY address among 32 possible. */ + phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32; + + /* 10/22/03 Grace change verify from GMII_PHY_STATUS to + GMII_PHY_ID1 + */ + + status = mdio_read(dev, phyaddr, MII_BMSR); + + if ((status != 0xFFFF) && (status != 0)) + return phyaddr; + } + + return 0x1f; +} + +/* + * Configure IPG based on result of IEEE 802.3 PHY + * auto-negotiation. + */ +static int ipg_config_autoneg(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int txflowcontrol; + unsigned int rxflowcontrol; + unsigned int fullduplex; + unsigned int gig; + u32 mac_ctrl_val; + u32 asicctrl; + u8 phyctrl; + + IPG_DEBUG_MSG("_config_autoneg\n"); + + asicctrl = ipg_r32(ASIC_CTRL); + phyctrl = ipg_r8(PHY_CTRL); + mac_ctrl_val = ipg_r32(MAC_CTRL); + + /* Set flags for use in resolving auto-negotation, assuming + * non-1000Mbps, half duplex, no flow control. + */ + fullduplex = 0; + txflowcontrol = 0; + rxflowcontrol = 0; + gig = 0; + + /* To accomodate a problem in 10Mbps operation, + * set a global flag if PHY running in 10Mbps mode. + */ + sp->tenmbpsmode = 0; + + printk(KERN_INFO "%s: Link speed = ", dev->name); + + /* Determine actual speed of operation. */ + switch (phyctrl & IPG_PC_LINK_SPEED) { + case IPG_PC_LINK_SPEED_10MBPS: + printk("10Mbps.\n"); + printk(KERN_INFO "%s: 10Mbps operational mode enabled.\n", + dev->name); + sp->tenmbpsmode = 1; + break; + case IPG_PC_LINK_SPEED_100MBPS: + printk("100Mbps.\n"); + break; + case IPG_PC_LINK_SPEED_1000MBPS: + printk("1000Mbps.\n"); + gig = 1; + break; + default: + printk("undefined!\n"); + return 0; + } + + if (phyctrl & IPG_PC_DUPLEX_STATUS) { + fullduplex = 1; + txflowcontrol = 1; + rxflowcontrol = 1; + } + + /* Configure full duplex, and flow control. */ + if (fullduplex == 1) { + /* Configure IPG for full duplex operation. */ + printk(KERN_INFO "%s: setting full duplex, ", dev->name); + + mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD; + + if (txflowcontrol == 1) { + printk("TX flow control"); + mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE; + } else { + printk("no TX flow control"); + mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE; + } + + if (rxflowcontrol == 1) { + printk(", RX flow control."); + mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE; + } else { + printk(", no RX flow control."); + mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE; + } + + printk("\n"); + } else { + /* Configure IPG for half duplex operation. */ + printk(KERN_INFO "%s: setting half duplex, " + "no TX flow control, no RX flow control.\n", dev->name); + + mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD & + ~IPG_MC_TX_FLOW_CONTROL_ENABLE & + ~IPG_MC_RX_FLOW_CONTROL_ENABLE; + } + ipg_w32(mac_ctrl_val, MAC_CTRL); + return 0; +} + +/* Determine and configure multicast operation and set + * receive mode for IPG. + */ +static void ipg_nic_set_multicast_list(struct net_device *dev) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + struct dev_mc_list *mc_list_ptr; + unsigned int hashindex; + u32 hashtable[2]; + u8 receivemode; + + IPG_DEBUG_MSG("_nic_set_multicast_list\n"); + + receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST; + + if (dev->flags & IFF_PROMISC) { + /* NIC to be configured in promiscuous mode. */ + receivemode = IPG_RM_RECEIVEALLFRAMES; + } else if ((dev->flags & IFF_ALLMULTI) || + (dev->flags & IFF_MULTICAST & + (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) { + /* NIC to be configured to receive all multicast + * frames. */ + receivemode |= IPG_RM_RECEIVEMULTICAST; + } else if (dev->flags & IFF_MULTICAST & (dev->mc_count > 0)) { + /* NIC to be configured to receive selected + * multicast addresses. */ + receivemode |= IPG_RM_RECEIVEMULTICASTHASH; + } + + /* Calculate the bits to set for the 64 bit, IPG HASHTABLE. + * The IPG applies a cyclic-redundancy-check (the same CRC + * used to calculate the frame data FCS) to the destination + * address all incoming multicast frames whose destination + * address has the multicast bit set. The least significant + * 6 bits of the CRC result are used as an addressing index + * into the hash table. If the value of the bit addressed by + * this index is a 1, the frame is passed to the host system. + */ + + /* Clear hashtable. */ + hashtable[0] = 0x00000000; + hashtable[1] = 0x00000000; + + /* Cycle through all multicast addresses to filter. */ + for (mc_list_ptr = dev->mc_list; + mc_list_ptr != NULL; mc_list_ptr = mc_list_ptr->next) { + /* Calculate CRC result for each multicast address. */ + hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr, + ETH_ALEN); + + /* Use only the least significant 6 bits. */ + hashindex = hashindex & 0x3F; + + /* Within "hashtable", set bit number "hashindex" + * to a logic 1. + */ + set_bit(hashindex, (void *)hashtable); + } + + /* Write the value of the hashtable, to the 4, 16 bit + * HASHTABLE IPG registers. + */ + ipg_w32(hashtable[0], HASHTABLE_0); + ipg_w32(hashtable[1], HASHTABLE_1); + + ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE); + + IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE)); +} + +static int ipg_io_config(struct net_device *dev) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + u32 origmacctrl; + u32 restoremacctrl; + + IPG_DEBUG_MSG("_io_config\n"); + + origmacctrl = ipg_r32(MAC_CTRL); + + restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE; + + /* Based on compilation option, determine if FCS is to be + * stripped on receive frames by IPG. + */ + if (!IPG_STRIP_FCS_ON_RX) + restoremacctrl |= IPG_MC_RCV_FCS; + + /* Determine if transmitter and/or receiver are + * enabled so we may restore MACCTRL correctly. + */ + if (origmacctrl & IPG_MC_TX_ENABLED) + restoremacctrl |= IPG_MC_TX_ENABLE; + + if (origmacctrl & IPG_MC_RX_ENABLED) + restoremacctrl |= IPG_MC_RX_ENABLE; + + /* Transmitter and receiver must be disabled before setting + * IFSSelect. + */ + ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) & + IPG_MC_RSVD_MASK, MAC_CTRL); + + /* Now that transmitter and receiver are disabled, write + * to IFSSelect. + */ + ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL); + + /* Set RECEIVEMODE register. */ + ipg_nic_set_multicast_list(dev); + + ipg_w16(IPG_MAX_RXFRAME_SIZE, MAX_FRAME_SIZE); + + ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE, RX_DMA_POLL_PERIOD); + ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH); + ipg_w8(IPG_RXDMABURSTTHRESH_VALUE, RX_DMA_BURST_THRESH); + ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE, TX_DMA_POLL_PERIOD); + ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH); + ipg_w8(IPG_TXDMABURSTTHRESH_VALUE, TX_DMA_BURST_THRESH); + ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE | + IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED | + IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT | + IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE); + ipg_w16(IPG_FLOWONTHRESH_VALUE, FLOW_ON_THRESH); + ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH); + + /* IPG multi-frag frame bug workaround. + * Per silicon revision B3 eratta. + */ + ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL); + + /* IPG TX poll now bug workaround. + * Per silicon revision B3 eratta. + */ + ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL); + + /* IPG RX poll now bug workaround. + * Per silicon revision B3 eratta. + */ + ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL); + + /* Now restore MACCTRL to original setting. */ + ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL); + + /* Disable unused RMON statistics. */ + ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK); + + /* Disable unused MIB statistics. */ + ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD | + IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES | + IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES | + IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK | + IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS | + IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK); + + return 0; +} + +/* + * Create a receive buffer within system memory and update + * NIC private structure appropriately. + */ +static int ipg_get_rxbuff(struct net_device *dev, int entry) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + struct ipg_rx *rxfd = sp->rxd + entry; + struct sk_buff *skb; + u64 rxfragsize; + + IPG_DEBUG_MSG("_get_rxbuff\n"); + + skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN); + if (!skb) { + sp->RxBuff[entry] = NULL; + return -ENOMEM; + } + + /* Adjust the data start location within the buffer to + * align IP address field to a 16 byte boundary. + */ + skb_reserve(skb, NET_IP_ALIGN); + + /* Associate the receive buffer with the IPG NIC. */ + skb->dev = dev; + + /* Save the address of the sk_buff structure. */ + sp->RxBuff[entry] = skb; + + rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, + sp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + + /* Set the RFD fragment length. */ + rxfragsize = IPG_RXFRAG_SIZE; + rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN); + + return 0; +} + +static int init_rfdlist(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + + IPG_DEBUG_MSG("_init_rfdlist\n"); + + for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { + struct ipg_rx *rxfd = sp->rxd + i; + + if (sp->RxBuff[i]) { + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + IPG_DEV_KFREE_SKB(sp->RxBuff[i]); + sp->RxBuff[i] = NULL; + } + + /* Clear out the RFS field. */ + rxfd->rfs = 0x0000000000000000; + + if (ipg_get_rxbuff(dev, i) < 0) { + /* + * A receive buffer was not ready, break the + * RFD list here. + */ + IPG_DEBUG_MSG("Cannot allocate Rx buffer.\n"); + + /* Just in case we cannot allocate a single RFD. + * Should not occur. + */ + if (i == 0) { + printk(KERN_ERR "%s: No memory available" + " for RFD list.\n", dev->name); + return -ENOMEM; + } + } + + rxfd->next_desc = cpu_to_le64(sp->rxd_map + + sizeof(struct ipg_rx)*(i + 1)); + } + sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map); + + sp->rx_current = 0; + sp->rx_dirty = 0; + + /* Write the location of the RFDList to the IPG. */ + ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0); + ipg_w32(0x00000000, RFD_LIST_PTR_1); + + return 0; +} + +static void init_tfdlist(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + + IPG_DEBUG_MSG("_init_tfdlist\n"); + + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { + struct ipg_tx *txfd = sp->txd + i; + + txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); + + if (sp->TxBuff[i]) { + IPG_DEV_KFREE_SKB(sp->TxBuff[i]); + sp->TxBuff[i] = NULL; + } + + txfd->next_desc = cpu_to_le64(sp->txd_map + + sizeof(struct ipg_tx)*(i + 1)); + } + sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map); + + sp->tx_current = 0; + sp->tx_dirty = 0; + + /* Write the location of the TFDList to the IPG. */ + IPG_DDEBUG_MSG("Starting TFDListPtr = %8.8x\n", + (u32) sp->txd_map); + ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0); + ipg_w32(0x00000000, TFD_LIST_PTR_1); + + sp->ResetCurrentTFD = 1; +} + +/* + * Free all transmit buffers which have already been transfered + * via DMA to the IPG. + */ +static void ipg_nic_txfree(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + const unsigned int curr = ipg_r32(TFD_LIST_PTR_0) - + (sp->txd_map / sizeof(struct ipg_tx)) - 1; + unsigned int released, pending; + + IPG_DEBUG_MSG("_nic_txfree\n"); + + pending = sp->tx_current - sp->tx_dirty; + + for (released = 0; released < pending; released++) { + unsigned int dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH; + struct sk_buff *skb = sp->TxBuff[dirty]; + struct ipg_tx *txfd = sp->txd + dirty; + + IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc); + + /* Look at each TFD's TFC field beginning + * at the last freed TFD up to the current TFD. + * If the TFDDone bit is set, free the associated + * buffer. + */ + if (dirty == curr) + break; + + /* Setup TFDDONE for compatible issue. */ + txfd->tfc |= cpu_to_le64(IPG_TFC_TFDDONE); + + /* Free the transmit buffer. */ + if (skb) { + pci_unmap_single(sp->pdev, + le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN), + skb->len, PCI_DMA_TODEVICE); + + IPG_DEV_KFREE_SKB(skb); + + sp->TxBuff[dirty] = NULL; + } + } + + sp->tx_dirty += released; + + if (netif_queue_stopped(dev) && + (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) { + netif_wake_queue(dev); + } +} + +static void ipg_tx_timeout(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + + ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK | + IPG_AC_FIFO); + + spin_lock_irq(&sp->lock); + + /* Re-configure after DMA reset. */ + if (ipg_io_config(dev) < 0) { + printk(KERN_INFO "%s: Error during re-configuration.\n", + dev->name); + } + + init_tfdlist(dev); + + spin_unlock_irq(&sp->lock); + + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK, + MAC_CTRL); +} + +/* + * For TxComplete interrupts, free all transmit + * buffers which have already been transfered via DMA + * to the IPG. + */ +static void ipg_nic_txcleanup(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + + IPG_DEBUG_MSG("_nic_txcleanup\n"); + + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { + /* Reading the TXSTATUS register clears the + * TX_COMPLETE interrupt. + */ + u32 txstatusdword = ipg_r32(TX_STATUS); + + IPG_DEBUG_MSG("TxStatus = %8.8x\n", txstatusdword); + + /* Check for Transmit errors. Error bits only valid if + * TX_COMPLETE bit in the TXSTATUS register is a 1. + */ + if (!(txstatusdword & IPG_TS_TX_COMPLETE)) + break; + + /* If in 10Mbps mode, indicate transmit is ready. */ + if (sp->tenmbpsmode) { + netif_wake_queue(dev); + } + + /* Transmit error, increment stat counters. */ + if (txstatusdword & IPG_TS_TX_ERROR) { + IPG_DEBUG_MSG("Transmit error.\n"); + sp->stats.tx_errors++; + } + + /* Late collision, re-enable transmitter. */ + if (txstatusdword & IPG_TS_LATE_COLLISION) { + IPG_DEBUG_MSG("Late collision on transmit.\n"); + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & + IPG_MC_RSVD_MASK, MAC_CTRL); + } + + /* Maximum collisions, re-enable transmitter. */ + if (txstatusdword & IPG_TS_TX_MAX_COLL) { + IPG_DEBUG_MSG("Maximum collisions on transmit.\n"); + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & + IPG_MC_RSVD_MASK, MAC_CTRL); + } + + /* Transmit underrun, reset and re-enable + * transmitter. + */ + if (txstatusdword & IPG_TS_TX_UNDERRUN) { + IPG_DEBUG_MSG("Transmitter underrun.\n"); + sp->stats.tx_fifo_errors++; + ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | + IPG_AC_NETWORK | IPG_AC_FIFO); + + /* Re-configure after DMA reset. */ + if (ipg_io_config(dev) < 0) { + printk(KERN_INFO + "%s: Error during re-configuration.\n", + dev->name); + } + init_tfdlist(dev); + + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & + IPG_MC_RSVD_MASK, MAC_CTRL); + } + } + + ipg_nic_txfree(dev); +} + +/* Provides statistical information about the IPG NIC. */ +struct net_device_stats *ipg_nic_get_stats(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + u16 temp1; + u16 temp2; + + IPG_DEBUG_MSG("_nic_get_stats\n"); + + /* Check to see if the NIC has been initialized via nic_open, + * before trying to read statistic registers. + */ + if (!test_bit(__LINK_STATE_START, &dev->state)) + return &sp->stats; + + sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK); + sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK); + sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK); + sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK); + temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS); + sp->stats.rx_errors += temp1; + sp->stats.rx_missed_errors += temp1; + temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) + + ipg_r32(IPG_LATECOLLISIONS); + temp2 = ipg_r16(IPG_CARRIERSENSEERRORS); + sp->stats.collisions += temp1; + sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS); + sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) + + ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2; + sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK); + + /* detailed tx_errors */ + sp->stats.tx_carrier_errors += temp2; + + /* detailed rx_errors */ + sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) + + ipg_r16(IPG_FRAMETOOLONGERRRORS); + sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS); + + /* Unutilized IPG statistic registers. */ + ipg_r32(IPG_MCSTFRAMESRCVDOK); + + return &sp->stats; +} + +/* Restore used receive buffers. */ +static int ipg_nic_rxrestore(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + const unsigned int curr = sp->rx_current; + unsigned int dirty = sp->rx_dirty; + + IPG_DEBUG_MSG("_nic_rxrestore\n"); + + for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) { + unsigned int entry = dirty % IPG_RFDLIST_LENGTH; + + /* rx_copybreak may poke hole here and there. */ + if (sp->RxBuff[entry]) + continue; + + /* Generate a new receive buffer to replace the + * current buffer (which will be released by the + * Linux system). + */ + if (ipg_get_rxbuff(dev, entry) < 0) { + IPG_DEBUG_MSG("Cannot allocate new Rx buffer.\n"); + + break; + } + + /* Reset the RFS field. */ + sp->rxd[entry].rfs = 0x0000000000000000; + } + sp->rx_dirty = dirty; + + return 0; +} + +#ifdef JUMBO_FRAME + +/* use jumboindex and jumbosize to control jumbo frame status + initial status is jumboindex=-1 and jumbosize=0 + 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done. + 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving + 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump + previous receiving and need to continue dumping the current one +*/ +enum { + NormalPacket, + ErrorPacket +}; + +enum { + Frame_NoStart_NoEnd = 0, + Frame_WithStart = 1, + Frame_WithEnd = 10, + Frame_WithStart_WithEnd = 11 +}; + +inline void ipg_nic_rx_free_skb(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; + + if (sp->RxBuff[entry]) { + struct ipg_rx *rxfd = sp->rxd + entry; + + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); + sp->RxBuff[entry] = NULL; + } +} + +inline int ipg_nic_rx_check_frame_type(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH); + int type = Frame_NoStart_NoEnd; + + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) + type += Frame_WithStart; + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND) + type += Frame_WithEnd; + return type; +} + +inline int ipg_nic_rx_check_error(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; + struct ipg_rx *rxfd = sp->rxd + entry; + + if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & + (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | + IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | + IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) { + IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n", + (unsigned long) rxfd->rfs); + + /* Increment general receive error statistic. */ + sp->stats.rx_errors++; + + /* Increment detailed receive error statistics. */ + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { + IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); + + sp->stats.rx_fifo_errors++; + } + + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { + IPG_DEBUG_MSG("RX runt occured.\n"); + sp->stats.rx_length_errors++; + } + + /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME, + * error count handled by a IPG statistic register. + */ + + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { + IPG_DEBUG_MSG("RX alignment error occured.\n"); + sp->stats.rx_frame_errors++; + } + + /* Do nothing for IPG_RFS_RXFCSERROR, error count + * handled by a IPG statistic register. + */ + + /* Free the memory associated with the RX + * buffer since it is erroneous and we will + * not pass it to higher layer processes. + */ + if (sp->RxBuff[entry]) { + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + + IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); + sp->RxBuff[entry] = NULL; + } + return ErrorPacket; + } + return NormalPacket; +} + +static void ipg_nic_rx_with_start_and_end(struct net_device *dev, + struct ipg_nic_private *sp, + struct ipg_rx *rxfd, unsigned entry) +{ + struct SJumbo *jumbo = &sp->Jumbo; + struct sk_buff *skb; + int framelen; + + if (jumbo->FoundStart) { + IPG_DEV_KFREE_SKB(jumbo->skb); + jumbo->FoundStart = 0; + jumbo->CurrentSize = 0; + jumbo->skb = NULL; + } + + // 1: found error, 0 no error + if (ipg_nic_rx_check_error(dev) != NormalPacket) + return; + + skb = sp->RxBuff[entry]; + if (!skb) + return; + + // accept this frame and send to upper layer + framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; + if (framelen > IPG_RXFRAG_SIZE) + framelen = IPG_RXFRAG_SIZE; + + skb_put(skb, framelen); + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + dev->last_rx = jiffies; + sp->RxBuff[entry] = NULL; +} + +static void ipg_nic_rx_with_start(struct net_device *dev, + struct ipg_nic_private *sp, + struct ipg_rx *rxfd, unsigned entry) +{ + struct SJumbo *jumbo = &sp->Jumbo; + struct pci_dev *pdev = sp->pdev; + struct sk_buff *skb; + + // 1: found error, 0 no error + if (ipg_nic_rx_check_error(dev) != NormalPacket) + return; + + // accept this frame and send to upper layer + skb = sp->RxBuff[entry]; + if (!skb) + return; + + if (jumbo->FoundStart) + IPG_DEV_KFREE_SKB(jumbo->skb); + + pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + + skb_put(skb, IPG_RXFRAG_SIZE); + + jumbo->FoundStart = 1; + jumbo->CurrentSize = IPG_RXFRAG_SIZE; + jumbo->skb = skb; + + sp->RxBuff[entry] = NULL; + dev->last_rx = jiffies; +} + +static void ipg_nic_rx_with_end(struct net_device *dev, + struct ipg_nic_private *sp, + struct ipg_rx *rxfd, unsigned entry) +{ + struct SJumbo *jumbo = &sp->Jumbo; + + //1: found error, 0 no error + if (ipg_nic_rx_check_error(dev) == NormalPacket) { + struct sk_buff *skb = sp->RxBuff[entry]; + + if (!skb) + return; + + if (jumbo->FoundStart) { + int framelen, endframelen; + + framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; + + endframeLen = framelen - jumbo->CurrentSize; + /* + if (framelen > IPG_RXFRAG_SIZE) + framelen=IPG_RXFRAG_SIZE; + */ + if (framelen > IPG_RXSUPPORT_SIZE) + IPG_DEV_KFREE_SKB(jumbo->skb); + else { + memcpy(skb_put(jumbo->skb, endframeLen), + skb->data, endframeLen); + + jumbo->skb->protocol = + eth_type_trans(jumbo->skb, dev); + + jumbo->skb->ip_summed = CHECKSUM_NONE; + netif_rx(jumbo->skb); + } + } + + dev->last_rx = jiffies; + jumbo->FoundStart = 0; + jumbo->CurrentSize = 0; + jumbo->skb = NULL; + + ipg_nic_rx_free_skb(dev); + } else { + IPG_DEV_KFREE_SKB(jumbo->skb); + jumbo->FoundStart = 0; + jumbo->CurrentSize = 0; + jumbo->skb = NULL; + } +} + +static void ipg_nic_rx_no_start_no_end(struct net_device *dev, + struct ipg_nic_private *sp, + struct ipg_rx *rxfd, unsigned entry) +{ + struct SJumbo *jumbo = &sp->Jumbo; + + //1: found error, 0 no error + if (ipg_nic_rx_check_error(dev) == NormalPacket) { + struct sk_buff *skb = sp->RxBuff[entry]; + + if (skb) { + if (jumbo->FoundStart) { + jumbo->CurrentSize += IPG_RXFRAG_SIZE; + if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) { + memcpy(skb_put(jumbo->skb, + IPG_RXFRAG_SIZE), + skb->data, IPG_RXFRAG_SIZE); + } + } + dev->last_rx = jiffies; + ipg_nic_rx_free_skb(dev); + } + } else { + IPG_DEV_KFREE_SKB(jumbo->skb); + jumbo->FoundStart = 0; + jumbo->CurrentSize = 0; + jumbo->skb = NULL; + } +} + +static int ipg_nic_rx(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + unsigned int curr = sp->rx_current; + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + + IPG_DEBUG_MSG("_nic_rx\n"); + + for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { + unsigned int entry = curr % IPG_RFDLIST_LENGTH; + struct ipg_rx *rxfd = sp->rxd + entry; + + if (!(rxfd->rfs & le64_to_cpu(IPG_RFS_RFDDONE))) + break; + + switch (ipg_nic_rx_check_frame_type(dev)) { + case Frame_WithStart_WithEnd: + ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry); + break; + case Frame_WithStart: + ipg_nic_rx_with_start(dev, tp, rxfd, entry); + break; + case Frame_WithEnd: + ipg_nic_rx_with_end(dev, tp, rxfd, entry); + break; + case Frame_NoStart_NoEnd: + ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry); + break; + } + } + + sp->rx_current = curr; + + if (i == IPG_MAXRFDPROCESS_COUNT) { + /* There are more RFDs to process, however the + * allocated amount of RFD processing time has + * expired. Assert Interrupt Requested to make + * sure we come back to process the remaining RFDs. + */ + ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); + } + + ipg_nic_rxrestore(dev); + + return 0; +} + +#else +static int ipg_nic_rx(struct net_device *dev) +{ + /* Transfer received Ethernet frames to higher network layers. */ + struct ipg_nic_private *sp = netdev_priv(dev); + unsigned int curr = sp->rx_current; + void __iomem *ioaddr = sp->ioaddr; + struct ipg_rx *rxfd; + unsigned int i; + + IPG_DEBUG_MSG("_nic_rx\n"); + +#define __RFS_MASK \ + cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND) + + for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { + unsigned int entry = curr % IPG_RFDLIST_LENGTH; + struct sk_buff *skb = sp->RxBuff[entry]; + unsigned int framelen; + + rxfd = sp->rxd + entry; + + if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb) + break; + + /* Get received frame length. */ + framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; + + /* Check for jumbo frame arrival with too small + * RXFRAG_SIZE. + */ + if (framelen > IPG_RXFRAG_SIZE) { + IPG_DEBUG_MSG + ("RFS FrameLen > allocated fragment size.\n"); + + framelen = IPG_RXFRAG_SIZE; + } + + if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs & + (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | + IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | + IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))))) { + + IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n", + (unsigned long int) rxfd->rfs); + + /* Increment general receive error statistic. */ + sp->stats.rx_errors++; + + /* Increment detailed receive error statistics. */ + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFIFOOVERRUN)) { + IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); + sp->stats.rx_fifo_errors++; + } + + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXRUNTFRAME)) { + IPG_DEBUG_MSG("RX runt occured.\n"); + sp->stats.rx_length_errors++; + } + + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXOVERSIZEDFRAME)) ; + /* Do nothing, error count handled by a IPG + * statistic register. + */ + + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXALIGNMENTERROR)) { + IPG_DEBUG_MSG("RX alignment error occured.\n"); + sp->stats.rx_frame_errors++; + } + + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFCSERROR)) ; + /* Do nothing, error count handled by a IPG + * statistic register. + */ + + /* Free the memory associated with the RX + * buffer since it is erroneous and we will + * not pass it to higher layer processes. + */ + if (skb) { + u64 info = rxfd->frag_info; + + pci_unmap_single(sp->pdev, + le64_to_cpu(info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + + IPG_DEV_KFREE_SKB(skb); + } + } else { + + /* Adjust the new buffer length to accomodate the size + * of the received frame. + */ + skb_put(skb, framelen); + + /* Set the buffer's protocol field to Ethernet. */ + skb->protocol = eth_type_trans(skb, dev); + + /* If the frame contains an IP/TCP/UDP frame, + * determine if upper layer must check IP/TCP/UDP + * checksums. + * + * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM + * VERIFICATION FOR SILICON REVISIONS B3 + * AND EARLIER! + * + if ((le64_to_cpu(rxfd->rfs & + (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED | + IPG_RFS_IPDETECTED))) && + !(le64_to_cpu(rxfd->rfs & + (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR | + IPG_RFS_IPERROR)))) { + * Indicate IP checksums were performed + * by the IPG. + * + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + */ + { + /* The IPG encountered an error with (or + * there were no) IP/TCP/UDP checksums. + * This may or may not indicate an invalid + * IP/TCP/UDP frame was received. Let the + * upper layer decide. + */ + skb->ip_summed = CHECKSUM_NONE; + } + + /* Hand off frame for higher layer processing. + * The function netif_rx() releases the sk_buff + * when processing completes. + */ + netif_rx(skb); + + /* Record frame receive time (jiffies = Linux + * kernel current time stamp). + */ + dev->last_rx = jiffies; + } + + /* Assure RX buffer is not reused by IPG. */ + sp->RxBuff[entry] = NULL; + } + + /* + * If there are more RFDs to proces and the allocated amount of RFD + * processing time has expired, assert Interrupt Requested to make + * sure we come back to process the remaining RFDs. + */ + if (i == IPG_MAXRFDPROCESS_COUNT) + ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); + +#ifdef IPG_DEBUG + /* Check if the RFD list contained no receive frame data. */ + if (!i) + sp->EmptyRFDListCount++; +#endif + while ((le64_to_cpu(rxfd->rfs & IPG_RFS_RFDDONE)) && + !((le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMESTART)) && + (le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMEEND)))) { + unsigned int entry = curr++ % IPG_RFDLIST_LENGTH; + + rxfd = sp->rxd + entry; + + IPG_DEBUG_MSG("Frame requires multiple RFDs.\n"); + + /* An unexpected event, additional code needed to handle + * properly. So for the time being, just disregard the + * frame. + */ + + /* Free the memory associated with the RX + * buffer since it is erroneous and we will + * not pass it to higher layer processes. + */ + if (sp->RxBuff[entry]) { + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); + } + + /* Assure RX buffer is not reused by IPG. */ + sp->RxBuff[entry] = NULL; + } + + sp->rx_current = curr; + + /* Check to see if there are a minimum number of used + * RFDs before restoring any (should improve performance.) + */ + if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE) + ipg_nic_rxrestore(dev); + + return 0; +} +#endif + +static void ipg_reset_after_host_error(struct work_struct *work) +{ + struct ipg_nic_private *sp = + container_of(work, struct ipg_nic_private, task.work); + struct net_device *dev = sp->dev; + + IPG_DDEBUG_MSG("DMACtrl = %8.8x\n", ioread32(sp->ioaddr + IPG_DMACTRL)); + + /* + * Acknowledge HostError interrupt by resetting + * IPG DMA and HOST. + */ + ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); + + init_rfdlist(dev); + init_tfdlist(dev); + + if (ipg_io_config(dev) < 0) { + printk(KERN_INFO "%s: Cannot recover from PCI error.\n", + dev->name); + schedule_delayed_work(&sp->task, HZ); + } +} + +static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst) +{ + struct net_device *dev = dev_inst; + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int handled = 0; + u16 status; + + IPG_DEBUG_MSG("_interrupt_handler\n"); + +#ifdef JUMBO_FRAME + ipg_nic_rxrestore(dev); +#endif + /* Get interrupt source information, and acknowledge + * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly, + * IntRequested, MacControlFrame, LinkEvent) interrupts + * if issued. Also, all IPG interrupts are disabled by + * reading IntStatusAck. + */ + status = ipg_r16(INT_STATUS_ACK); + + IPG_DEBUG_MSG("IntStatusAck = %4.4x\n", status); + + /* Shared IRQ of remove event. */ + if (!(status & IPG_IS_RSVD_MASK)) + goto out_enable; + + handled = 1; + + if (unlikely(!netif_running(dev))) + goto out; + + spin_lock(&sp->lock); + + /* If RFDListEnd interrupt, restore all used RFDs. */ + if (status & IPG_IS_RFD_LIST_END) { + IPG_DEBUG_MSG("RFDListEnd Interrupt.\n"); + + /* The RFD list end indicates an RFD was encountered + * with a 0 NextPtr, or with an RFDDone bit set to 1 + * (indicating the RFD is not read for use by the + * IPG.) Try to restore all RFDs. + */ + ipg_nic_rxrestore(dev); + +#ifdef IPG_DEBUG + /* Increment the RFDlistendCount counter. */ + sp->RFDlistendCount++; +#endif + } + + /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or + * IntRequested interrupt, process received frames. */ + if ((status & IPG_IS_RX_DMA_PRIORITY) || + (status & IPG_IS_RFD_LIST_END) || + (status & IPG_IS_RX_DMA_COMPLETE) || + (status & IPG_IS_INT_REQUESTED)) { +#ifdef IPG_DEBUG + /* Increment the RFD list checked counter if interrupted + * only to check the RFD list. */ + if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END | + IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) & + (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE | + IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE | + IPG_IS_UPDATE_STATS))) + sp->RFDListCheckedCount++; +#endif + + ipg_nic_rx(dev); + } + + /* If TxDMAComplete interrupt, free used TFDs. */ + if (status & IPG_IS_TX_DMA_COMPLETE) + ipg_nic_txfree(dev); + + /* TxComplete interrupts indicate one of numerous actions. + * Determine what action to take based on TXSTATUS register. + */ + if (status & IPG_IS_TX_COMPLETE) + ipg_nic_txcleanup(dev); + + /* If UpdateStats interrupt, update Linux Ethernet statistics */ + if (status & IPG_IS_UPDATE_STATS) + ipg_nic_get_stats(dev); + + /* If HostError interrupt, reset IPG. */ + if (status & IPG_IS_HOST_ERROR) { + IPG_DDEBUG_MSG("HostError Interrupt\n"); + + schedule_delayed_work(&sp->task, 0); + } + + /* If LinkEvent interrupt, resolve autonegotiation. */ + if (status & IPG_IS_LINK_EVENT) { + if (ipg_config_autoneg(dev) < 0) + printk(KERN_INFO "%s: Auto-negotiation error.\n", + dev->name); + } + + /* If MACCtrlFrame interrupt, do nothing. */ + if (status & IPG_IS_MAC_CTRL_FRAME) + IPG_DEBUG_MSG("MACCtrlFrame interrupt.\n"); + + /* If RxComplete interrupt, do nothing. */ + if (status & IPG_IS_RX_COMPLETE) + IPG_DEBUG_MSG("RxComplete interrupt.\n"); + + /* If RxEarly interrupt, do nothing. */ + if (status & IPG_IS_RX_EARLY) + IPG_DEBUG_MSG("RxEarly interrupt.\n"); + +out_enable: + /* Re-enable IPG interrupts. */ + ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE | + IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE | + IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE); + + spin_unlock(&sp->lock); +out: + return IRQ_RETVAL(handled); +} + +static void ipg_rx_clear(struct ipg_nic_private *sp) +{ + unsigned int i; + + for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { + if (sp->RxBuff[i]) { + struct ipg_rx *rxfd = sp->rxd + i; + + IPG_DEV_KFREE_SKB(sp->RxBuff[i]); + sp->RxBuff[i] = NULL; + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + } + } +} + +static void ipg_tx_clear(struct ipg_nic_private *sp) +{ + unsigned int i; + + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { + if (sp->TxBuff[i]) { + struct ipg_tx *txfd = sp->txd + i; + + pci_unmap_single(sp->pdev, + le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN), + sp->TxBuff[i]->len, PCI_DMA_TODEVICE); + + IPG_DEV_KFREE_SKB(sp->TxBuff[i]); + + sp->TxBuff[i] = NULL; + } + } +} + +static int ipg_nic_open(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + struct pci_dev *pdev = sp->pdev; + int rc; + + IPG_DEBUG_MSG("_nic_open\n"); + + sp->rx_buf_sz = IPG_RXSUPPORT_SIZE; + + /* Check for interrupt line conflicts, and request interrupt + * line for IPG. + * + * IMPORTANT: Disable IPG interrupts prior to registering + * IRQ. + */ + ipg_w16(0x0000, INT_ENABLE); + + /* Register the interrupt line to be used by the IPG within + * the Linux system. + */ + rc = request_irq(pdev->irq, &ipg_interrupt_handler, IRQF_SHARED, + dev->name, dev); + if (rc < 0) { + printk(KERN_INFO "%s: Error when requesting interrupt.\n", + dev->name); + goto out; + } + + dev->irq = pdev->irq; + + rc = -ENOMEM; + + sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES, + &sp->rxd_map, GFP_KERNEL); + if (!sp->rxd) + goto err_free_irq_0; + + sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES, + &sp->txd_map, GFP_KERNEL); + if (!sp->txd) + goto err_free_rx_1; + + rc = init_rfdlist(dev); + if (rc < 0) { + printk(KERN_INFO "%s: Error during configuration.\n", + dev->name); + goto err_free_tx_2; + } + + init_tfdlist(dev); + + rc = ipg_io_config(dev); + if (rc < 0) { + printk(KERN_INFO "%s: Error during configuration.\n", + dev->name); + goto err_release_tfdlist_3; + } + + /* Resolve autonegotiation. */ + if (ipg_config_autoneg(dev) < 0) + printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name); + +#ifdef JUMBO_FRAME + /* initialize JUMBO Frame control variable */ + sp->Jumbo.FoundStart = 0; + sp->Jumbo.CurrentSize = 0; + sp->Jumbo.skb = 0; + dev->mtu = IPG_TXFRAG_SIZE; +#endif + + /* Enable transmit and receive operation of the IPG. */ + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) & + IPG_MC_RSVD_MASK, MAC_CTRL); + + netif_start_queue(dev); +out: + return rc; + +err_release_tfdlist_3: + ipg_tx_clear(sp); + ipg_rx_clear(sp); +err_free_tx_2: + dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map); +err_free_rx_1: + dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map); +err_free_irq_0: + free_irq(pdev->irq, dev); + goto out; +} + +static int ipg_nic_stop(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + struct pci_dev *pdev = sp->pdev; + + IPG_DEBUG_MSG("_nic_stop\n"); + + netif_stop_queue(dev); + + IPG_DDEBUG_MSG("RFDlistendCount = %i\n", sp->RFDlistendCount); + IPG_DDEBUG_MSG("RFDListCheckedCount = %i\n", sp->rxdCheckedCount); + IPG_DDEBUG_MSG("EmptyRFDListCount = %i\n", sp->EmptyRFDListCount); + IPG_DUMPTFDLIST(dev); + + do { + (void) ipg_r16(INT_STATUS_ACK); + + ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); + + synchronize_irq(pdev->irq); + } while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK); + + ipg_rx_clear(sp); + + ipg_tx_clear(sp); + + pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map); + pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map); + + free_irq(pdev->irq, dev); + + return 0; +} + +static int 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; + unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH; + unsigned long flags; + struct ipg_tx *txfd; + + IPG_DDEBUG_MSG("_nic_hard_start_xmit\n"); + + /* If in 10Mbps mode, stop the transmit queue so + * no more transmit frames are accepted. + */ + if (sp->tenmbpsmode) + netif_stop_queue(dev); + + if (sp->ResetCurrentTFD) { + sp->ResetCurrentTFD = 0; + entry = 0; + } + + txfd = sp->txd + entry; + + sp->TxBuff[entry] = skb; + + /* Clear all TFC fields, except TFDDONE. */ + txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); + + /* Specify the TFC field within the TFD. */ + txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED | + (IPG_TFC_FRAMEID & cpu_to_le64(sp->tx_current)) | + (IPG_TFC_FRAGCOUNT & (1 << 24))); + + /* Request TxComplete interrupts at an interval defined + * by the constant IPG_FRAMESBETWEENTXCOMPLETES. + * Request TxComplete interrupt for every frame + * if in 10Mbps mode to accomodate problem with 10Mbps + * processing. + */ + if (sp->tenmbpsmode) + txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE); + else if (!((sp->tx_current - sp->tx_dirty + 1) > + IPG_FRAMESBETWEENTXDMACOMPLETES)) { + txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE); + } + /* Based on compilation option, determine if FCS is to be + * appended to transmit frame by IPG. + */ + if (!(IPG_APPEND_FCS_ON_TX)) + txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE); + + /* Based on compilation option, determine if IP, TCP and/or + * UDP checksums are to be added to transmit frame by IPG. + */ + if (IPG_ADD_IPCHECKSUM_ON_TX) + txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE); + + if (IPG_ADD_TCPCHECKSUM_ON_TX) + txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE); + + if (IPG_ADD_UDPCHECKSUM_ON_TX) + txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE); + + /* Based on compilation option, determine if VLAN tag info is to be + * inserted into transmit frame by IPG. + */ + if (IPG_INSERT_MANUAL_VLAN_TAG) { + txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT | + ((u64) IPG_MANUAL_VLAN_VID << 32) | + ((u64) IPG_MANUAL_VLAN_CFI << 44) | + ((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45)); + } + + /* The fragment start location within system memory is defined + * by the sk_buff structure's data field. The physical address + * of this location within the system's virtual memory space + * is determined using the IPG_HOST2BUS_MAP function. + */ + txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE)); + + /* The length of the fragment within system memory is defined by + * the sk_buff structure's len field. + */ + txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN & + ((u64) (skb->len & 0xffff) << 48)); + + /* Clear the TFDDone bit last to indicate the TFD is ready + * for transfer to the IPG. + */ + txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE); + + spin_lock_irqsave(&sp->lock, flags); + + sp->tx_current++; + + mmiowb(); + + ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL); + + if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH)) + netif_wake_queue(dev); + + spin_unlock_irqrestore(&sp->lock, flags); + + return NETDEV_TX_OK; +} + +static void ipg_set_phy_default_param(unsigned char rev, + struct net_device *dev, int phy_address) +{ + unsigned short length; + unsigned char revision; + unsigned short *phy_param; + unsigned short address, value; + + phy_param = &DefaultPhyParam[0]; + length = *phy_param & 0x00FF; + revision = (unsigned char)((*phy_param) >> 8); + phy_param++; + while (length != 0) { + if (rev == revision) { + while (length > 1) { + address = *phy_param; + value = *(phy_param + 1); + phy_param += 2; + mdio_write(dev, phy_address, address, value); + length -= 4; + } + break; + } else { + phy_param += length / 2; + length = *phy_param & 0x00FF; + revision = (unsigned char)((*phy_param) >> 8); + phy_param++; + } + } +} + +/* JES20040127EEPROM */ +static int read_eeprom(struct net_device *dev, int eep_addr) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + unsigned int i; + int ret = 0; + u16 value; + + value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff); + ipg_w16(value, EEPROM_CTRL); + + for (i = 0; i < 1000; i++) { + u16 data; + + mdelay(10); + data = ipg_r16(EEPROM_CTRL); + if (!(data & IPG_EC_EEPROM_BUSY)) { + ret = ipg_r16(EEPROM_DATA); + break; + } + } + return ret; +} + +static void ipg_init_mii(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + struct mii_if_info *mii_if = &sp->mii_if; + int phyaddr; + + mii_if->dev = dev; + mii_if->mdio_read = mdio_read; + mii_if->mdio_write = mdio_write; + mii_if->phy_id_mask = 0x1f; + mii_if->reg_num_mask = 0x1f; + + mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev); + + if (phyaddr != 0x1f) { + u16 mii_phyctrl, mii_1000cr; + u8 revisionid = 0; + + mii_1000cr = mdio_read(dev, phyaddr, MII_CTRL1000); + mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF | + GMII_PHY_1000BASETCONTROL_PreferMaster; + mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr); + + mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR); + + /* Set default phyparam */ + pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid); + ipg_set_phy_default_param(revisionid, dev, phyaddr); + + /* Reset PHY */ + mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART; + mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl); + + } +} + +static int ipg_hw_init(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + int rc; + + /* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */ + /* Read LED Mode Configuration from EEPROM */ + sp->LED_Mode = read_eeprom(dev, 6); + + /* Reset all functions within the IPG. Do not assert + * RST_OUT as not compatible with some PHYs. + */ + rc = ipg_reset(dev, IPG_RESET_MASK); + if (rc < 0) + goto out; + + ipg_init_mii(dev); + + /* Read MAC Address from EEPROM */ + for (i = 0; i < 3; i++) + sp->station_addr[i] = read_eeprom(dev, 16 + i); + + for (i = 0; i < 3; i++) + ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i); + + /* Set station address in ethernet_device structure. */ + dev->dev_addr[0] = ipg_r16(STATION_ADDRESS_0) & 0x00ff; + dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8; + dev->dev_addr[2] = ipg_r16(STATION_ADDRESS_1) & 0x00ff; + dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8; + dev->dev_addr[4] = ipg_r16(STATION_ADDRESS_2) & 0x00ff; + dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8; +out: + return rc; +} + +static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + int rc; + + mutex_lock(&sp->mii_mutex); + rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL); + mutex_unlock(&sp->mii_mutex); + + return rc; +} + +static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu) +{ + /* Function to accomodate changes to Maximum Transfer Unit + * (or MTU) of IPG NIC. Cannot use default function since + * the default will not allow for MTU > 1500 bytes. + */ + + IPG_DEBUG_MSG("_nic_change_mtu\n"); + + /* Check that the new MTU value is between 68 (14 byte header, 46 + * byte payload, 4 byte FCS) and IPG_MAX_RXFRAME_SIZE, which + * corresponds to the MAXFRAMESIZE register in the IPG. + */ + if ((new_mtu < 68) || (new_mtu > IPG_MAX_RXFRAME_SIZE)) + return -EINVAL; + + dev->mtu = new_mtu; + + return 0; +} + +static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + int rc; + + mutex_lock(&sp->mii_mutex); + rc = mii_ethtool_gset(&sp->mii_if, cmd); + mutex_unlock(&sp->mii_mutex); + + return rc; +} + +static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + int rc; + + mutex_lock(&sp->mii_mutex); + rc = mii_ethtool_sset(&sp->mii_if, cmd); + mutex_unlock(&sp->mii_mutex); + + return rc; +} + +static int ipg_nway_reset(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + int rc; + + mutex_lock(&sp->mii_mutex); + rc = mii_nway_restart(&sp->mii_if); + mutex_unlock(&sp->mii_mutex); + + return rc; +} + +static struct ethtool_ops ipg_ethtool_ops = { + .get_settings = ipg_get_settings, + .set_settings = ipg_set_settings, + .nway_reset = ipg_nway_reset, +}; + +static void ipg_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct ipg_nic_private *sp = netdev_priv(dev); + + IPG_DEBUG_MSG("_remove\n"); + + /* Un-register Ethernet device. */ + unregister_netdev(dev); + + pci_iounmap(pdev, sp->ioaddr); + + pci_release_regions(pdev); + + free_netdev(dev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int __devinit ipg_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned int i = id->driver_data; + struct ipg_nic_private *sp; + struct net_device *dev; + void __iomem *ioaddr; + int rc; + + rc = pci_enable_device(pdev); + if (rc < 0) + goto out; + + printk(KERN_INFO "%s: %s\n", pci_name(pdev), ipg_brand_name[i]); + + pci_set_master(pdev); + + rc = pci_set_dma_mask(pdev, DMA_40BIT_MASK); + if (rc < 0) { + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc < 0) { + printk(KERN_ERR "%s: DMA config failed.\n", + pci_name(pdev)); + goto err_disable_0; + } + } + + /* + * Initialize net device. + */ + dev = alloc_etherdev(sizeof(struct ipg_nic_private)); + if (!dev) { + printk(KERN_ERR "%s: alloc_etherdev failed\n", pci_name(pdev)); + rc = -ENOMEM; + goto err_disable_0; + } + + sp = netdev_priv(dev); + spin_lock_init(&sp->lock); + mutex_init(&sp->mii_mutex); + + /* Declare IPG NIC functions for Ethernet device methods. + */ + dev->open = &ipg_nic_open; + dev->stop = &ipg_nic_stop; + dev->hard_start_xmit = &ipg_nic_hard_start_xmit; + dev->get_stats = &ipg_nic_get_stats; + dev->set_multicast_list = &ipg_nic_set_multicast_list; + dev->do_ioctl = ipg_ioctl; + dev->tx_timeout = ipg_tx_timeout; + dev->change_mtu = &ipg_nic_change_mtu; + + SET_NETDEV_DEV(dev, &pdev->dev); + SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops); + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_free_dev_1; + + ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); + if (!ioaddr) { + printk(KERN_ERR "%s cannot map MMIO\n", pci_name(pdev)); + rc = -EIO; + goto err_release_regions_2; + } + + /* Save the pointer to the PCI device information. */ + sp->ioaddr = ioaddr; + sp->pdev = pdev; + sp->dev = dev; + + INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error); + + pci_set_drvdata(pdev, dev); + + rc = ipg_hw_init(dev); + if (rc < 0) + goto err_unmap_3; + + rc = register_netdev(dev); + if (rc < 0) + goto err_unmap_3; + + printk(KERN_INFO "Ethernet device registered as: %s\n", dev->name); +out: + return rc; + +err_unmap_3: + pci_iounmap(pdev, ioaddr); +err_release_regions_2: + pci_release_regions(pdev); +err_free_dev_1: + free_netdev(dev); +err_disable_0: + pci_disable_device(pdev); + goto out; +} + +static struct pci_driver ipg_pci_driver = { + .name = IPG_DRIVER_NAME, + .id_table = ipg_pci_tbl, + .probe = ipg_probe, + .remove = __devexit_p(ipg_remove), +}; + +static int __init ipg_init_module(void) +{ + return pci_register_driver(&ipg_pci_driver); +} + +static void __exit ipg_exit_module(void) +{ + pci_unregister_driver(&ipg_pci_driver); +} + +module_init(ipg_init_module); +module_exit(ipg_exit_module); diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h new file mode 100644 index 000000000000..1952d0dfd314 --- /dev/null +++ b/drivers/net/ipg.h @@ -0,0 +1,856 @@ +/* + * + * ipg.h + * + * Include file for Gigabit Ethernet device driver for Network + * Interface Cards (NICs) utilizing the Tamarack Microelectronics + * Inc. IPG Gigabit or Triple Speed Ethernet Media Access + * Controller. + * + * Craig Rich + * Sundance Technology, Inc. + * 1485 Saratoga Avenue + * Suite 200 + * San Jose, CA 95129 + * 408 873 4117 + * www.sundanceti.com + * craig_rich@sundanceti.com + */ +#ifndef __LINUX_IPG_H +#define __LINUX_IPG_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include */ + +#define DrvVer "2.09d" + +#define IPG_DEV_KFREE_SKB(skb) dev_kfree_skb_irq(skb) + +/* + * Constants + */ + +/* GMII based PHY IDs */ +#define NS 0x2000 +#define MARVELL 0x0141 +#define ICPLUS_PHY 0x243 + +/* NIC Physical Layer Device MII register fields. */ +#define MII_PHY_SELECTOR_IEEE8023 0x0001 +#define MII_PHY_TECHABILITYFIELD 0x1FE0 + +/* GMII_PHY_1000 need to set to prefer master */ +#define GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400 + +/* NIC Physical Layer Device GMII constants. */ +#define GMII_PREAMBLE 0xFFFFFFFF +#define GMII_ST 0x1 +#define GMII_READ 0x2 +#define GMII_WRITE 0x1 +#define GMII_TA_READ_MASK 0x1 +#define GMII_TA_WRITE 0x2 + +/* I/O register offsets. */ +enum ipg_regs { + DMA_CTRL = 0x00, + RX_DMA_STATUS = 0x08, // Unused + reserved + TFD_LIST_PTR_0 = 0x10, + TFD_LIST_PTR_1 = 0x14, + TX_DMA_BURST_THRESH = 0x18, + TX_DMA_URGENT_THRESH = 0x19, + TX_DMA_POLL_PERIOD = 0x1a, + RFD_LIST_PTR_0 = 0x1c, + RFD_LIST_PTR_1 = 0x20, + RX_DMA_BURST_THRESH = 0x24, + RX_DMA_URGENT_THRESH = 0x25, + RX_DMA_POLL_PERIOD = 0x26, + DEBUG_CTRL = 0x2c, + ASIC_CTRL = 0x30, + FIFO_CTRL = 0x38, // Unused + FLOW_OFF_THRESH = 0x3c, + FLOW_ON_THRESH = 0x3e, + EEPROM_DATA = 0x48, + EEPROM_CTRL = 0x4a, + EXPROM_ADDR = 0x4c, // Unused + EXPROM_DATA = 0x50, // Unused + WAKE_EVENT = 0x51, // Unused + COUNTDOWN = 0x54, // Unused + INT_STATUS_ACK = 0x5a, + INT_ENABLE = 0x5c, + INT_STATUS = 0x5e, // Unused + TX_STATUS = 0x60, + MAC_CTRL = 0x6c, + VLAN_TAG = 0x70, // Unused + PHY_SET = 0x75, // JES20040127EEPROM + PHY_CTRL = 0x76, + STATION_ADDRESS_0 = 0x78, + STATION_ADDRESS_1 = 0x7a, + STATION_ADDRESS_2 = 0x7c, + MAX_FRAME_SIZE = 0x86, + RECEIVE_MODE = 0x88, + HASHTABLE_0 = 0x8c, + HASHTABLE_1 = 0x90, + RMON_STATISTICS_MASK = 0x98, + STATISTICS_MASK = 0x9c, + RX_JUMBO_FRAMES = 0xbc, // Unused + TCP_CHECKSUM_ERRORS = 0xc0, // Unused + IP_CHECKSUM_ERRORS = 0xc2, // Unused + UDP_CHECKSUM_ERRORS = 0xc4, // Unused + TX_JUMBO_FRAMES = 0xf4 // Unused +}; + +/* Ethernet MIB statistic register offsets. */ +#define IPG_OCTETRCVOK 0xA8 +#define IPG_MCSTOCTETRCVDOK 0xAC +#define IPG_BCSTOCTETRCVOK 0xB0 +#define IPG_FRAMESRCVDOK 0xB4 +#define IPG_MCSTFRAMESRCVDOK 0xB8 +#define IPG_BCSTFRAMESRCVDOK 0xBE +#define IPG_MACCONTROLFRAMESRCVD 0xC6 +#define IPG_FRAMETOOLONGERRRORS 0xC8 +#define IPG_INRANGELENGTHERRORS 0xCA +#define IPG_FRAMECHECKSEQERRORS 0xCC +#define IPG_FRAMESLOSTRXERRORS 0xCE +#define IPG_OCTETXMTOK 0xD0 +#define IPG_MCSTOCTETXMTOK 0xD4 +#define IPG_BCSTOCTETXMTOK 0xD8 +#define IPG_FRAMESXMTDOK 0xDC +#define IPG_MCSTFRAMESXMTDOK 0xE0 +#define IPG_FRAMESWDEFERREDXMT 0xE4 +#define IPG_LATECOLLISIONS 0xE8 +#define IPG_MULTICOLFRAMES 0xEC +#define IPG_SINGLECOLFRAMES 0xF0 +#define IPG_BCSTFRAMESXMTDOK 0xF6 +#define IPG_CARRIERSENSEERRORS 0xF8 +#define IPG_MACCONTROLFRAMESXMTDOK 0xFA +#define IPG_FRAMESABORTXSCOLLS 0xFC +#define IPG_FRAMESWEXDEFERRAL 0xFE + +/* RMON statistic register offsets. */ +#define IPG_ETHERSTATSCOLLISIONS 0x100 +#define IPG_ETHERSTATSOCTETSTRANSMIT 0x104 +#define IPG_ETHERSTATSPKTSTRANSMIT 0x108 +#define IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT 0x10C +#define IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT 0x110 +#define IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT 0x114 +#define IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT 0x118 +#define IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT 0x11C +#define IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT 0x120 +#define IPG_ETHERSTATSCRCALIGNERRORS 0x124 +#define IPG_ETHERSTATSUNDERSIZEPKTS 0x128 +#define IPG_ETHERSTATSFRAGMENTS 0x12C +#define IPG_ETHERSTATSJABBERS 0x130 +#define IPG_ETHERSTATSOCTETS 0x134 +#define IPG_ETHERSTATSPKTS 0x138 +#define IPG_ETHERSTATSPKTS64OCTESTS 0x13C +#define IPG_ETHERSTATSPKTS65TO127OCTESTS 0x140 +#define IPG_ETHERSTATSPKTS128TO255OCTESTS 0x144 +#define IPG_ETHERSTATSPKTS256TO511OCTESTS 0x148 +#define IPG_ETHERSTATSPKTS512TO1023OCTESTS 0x14C +#define IPG_ETHERSTATSPKTS1024TO1518OCTESTS 0x150 + +/* RMON statistic register equivalents. */ +#define IPG_ETHERSTATSMULTICASTPKTSTRANSMIT 0xE0 +#define IPG_ETHERSTATSBROADCASTPKTSTRANSMIT 0xF6 +#define IPG_ETHERSTATSMULTICASTPKTS 0xB8 +#define IPG_ETHERSTATSBROADCASTPKTS 0xBE +#define IPG_ETHERSTATSOVERSIZEPKTS 0xC8 +#define IPG_ETHERSTATSDROPEVENTS 0xCE + +/* Serial EEPROM offsets */ +#define IPG_EEPROM_CONFIGPARAM 0x00 +#define IPG_EEPROM_ASICCTRL 0x01 +#define IPG_EEPROM_SUBSYSTEMVENDORID 0x02 +#define IPG_EEPROM_SUBSYSTEMID 0x03 +#define IPG_EEPROM_STATIONADDRESS0 0x10 +#define IPG_EEPROM_STATIONADDRESS1 0x11 +#define IPG_EEPROM_STATIONADDRESS2 0x12 + +/* Register & data structure bit masks */ + +/* PCI register masks. */ + +/* IOBaseAddress */ +#define IPG_PIB_RSVD_MASK 0xFFFFFE01 +#define IPG_PIB_IOBASEADDRESS 0xFFFFFF00 +#define IPG_PIB_IOBASEADDRIND 0x00000001 + +/* MemBaseAddress */ +#define IPG_PMB_RSVD_MASK 0xFFFFFE07 +#define IPG_PMB_MEMBASEADDRIND 0x00000001 +#define IPG_PMB_MEMMAPTYPE 0x00000006 +#define IPG_PMB_MEMMAPTYPE0 0x00000002 +#define IPG_PMB_MEMMAPTYPE1 0x00000004 +#define IPG_PMB_MEMBASEADDRESS 0xFFFFFE00 + +/* ConfigStatus */ +#define IPG_CS_RSVD_MASK 0xFFB0 +#define IPG_CS_CAPABILITIES 0x0010 +#define IPG_CS_66MHZCAPABLE 0x0020 +#define IPG_CS_FASTBACK2BACK 0x0080 +#define IPG_CS_DATAPARITYREPORTED 0x0100 +#define IPG_CS_DEVSELTIMING 0x0600 +#define IPG_CS_SIGNALEDTARGETABORT 0x0800 +#define IPG_CS_RECEIVEDTARGETABORT 0x1000 +#define IPG_CS_RECEIVEDMASTERABORT 0x2000 +#define IPG_CS_SIGNALEDSYSTEMERROR 0x4000 +#define IPG_CS_DETECTEDPARITYERROR 0x8000 + +/* TFD data structure masks. */ + +/* TFDList, TFC */ +#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFF +#define IPG_TFC_FRAMEID 0x000000000000FFFF +#define IPG_TFC_WORDALIGN 0x0000000000030000 +#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000 +#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000 +#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000 +#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000 +#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000 +#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000 +#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000 +#define IPG_TFC_TXINDICATE 0x0000000000400000 +#define IPG_TFC_TXDMAINDICATE 0x0000000000800000 +#define IPG_TFC_FRAGCOUNT 0x000000000F000000 +#define IPG_TFC_VLANTAGINSERT 0x0000000010000000 +#define IPG_TFC_TFDDONE 0x0000000080000000 +#define IPG_TFC_VID 0x00000FFF00000000 +#define IPG_TFC_CFI 0x0000100000000000 +#define IPG_TFC_USERPRIORITY 0x0000E00000000000 + +/* TFDList, FragInfo */ +#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFF +#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFF +#define IPG_TFI_FRAGLEN 0xFFFF000000000000LL + +/* RFD data structure masks. */ + +/* RFDList, RFS */ +#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFF +#define IPG_RFS_RXFRAMELEN 0x000000000000FFFF +#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000 +#define IPG_RFS_RXRUNTFRAME 0x0000000000020000 +#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000 +#define IPG_RFS_RXFCSERROR 0x0000000000080000 +#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000 +#define IPG_RFS_RXLENGTHERROR 0x0000000000200000 +#define IPG_RFS_VLANDETECTED 0x0000000000400000 +#define IPG_RFS_TCPDETECTED 0x0000000000800000 +#define IPG_RFS_TCPERROR 0x0000000001000000 +#define IPG_RFS_UDPDETECTED 0x0000000002000000 +#define IPG_RFS_UDPERROR 0x0000000004000000 +#define IPG_RFS_IPDETECTED 0x0000000008000000 +#define IPG_RFS_IPERROR 0x0000000010000000 +#define IPG_RFS_FRAMESTART 0x0000000020000000 +#define IPG_RFS_FRAMEEND 0x0000000040000000 +#define IPG_RFS_RFDDONE 0x0000000080000000 +#define IPG_RFS_TCI 0x0000FFFF00000000 + +/* RFDList, FragInfo */ +#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFF +#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFF +#define IPG_RFI_FRAGLEN 0xFFFF000000000000LL + +/* I/O Register masks. */ + +/* RMON Statistics Mask */ +#define IPG_RZ_ALL 0x0FFFFFFF + +/* Statistics Mask */ +#define IPG_SM_ALL 0x0FFFFFFF +#define IPG_SM_OCTETRCVOK_FRAMESRCVDOK 0x00000001 +#define IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK 0x00000002 +#define IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK 0x00000004 +#define IPG_SM_RXJUMBOFRAMES 0x00000008 +#define IPG_SM_TCPCHECKSUMERRORS 0x00000010 +#define IPG_SM_IPCHECKSUMERRORS 0x00000020 +#define IPG_SM_UDPCHECKSUMERRORS 0x00000040 +#define IPG_SM_MACCONTROLFRAMESRCVD 0x00000080 +#define IPG_SM_FRAMESTOOLONGERRORS 0x00000100 +#define IPG_SM_INRANGELENGTHERRORS 0x00000200 +#define IPG_SM_FRAMECHECKSEQERRORS 0x00000400 +#define IPG_SM_FRAMESLOSTRXERRORS 0x00000800 +#define IPG_SM_OCTETXMTOK_FRAMESXMTOK 0x00001000 +#define IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK 0x00002000 +#define IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK 0x00004000 +#define IPG_SM_FRAMESWDEFERREDXMT 0x00008000 +#define IPG_SM_LATECOLLISIONS 0x00010000 +#define IPG_SM_MULTICOLFRAMES 0x00020000 +#define IPG_SM_SINGLECOLFRAMES 0x00040000 +#define IPG_SM_TXJUMBOFRAMES 0x00080000 +#define IPG_SM_CARRIERSENSEERRORS 0x00100000 +#define IPG_SM_MACCONTROLFRAMESXMTD 0x00200000 +#define IPG_SM_FRAMESABORTXSCOLLS 0x00400000 +#define IPG_SM_FRAMESWEXDEFERAL 0x00800000 + +/* Countdown */ +#define IPG_CD_RSVD_MASK 0x0700FFFF +#define IPG_CD_COUNT 0x0000FFFF +#define IPG_CD_COUNTDOWNSPEED 0x01000000 +#define IPG_CD_COUNTDOWNMODE 0x02000000 +#define IPG_CD_COUNTINTENABLED 0x04000000 + +/* TxDMABurstThresh */ +#define IPG_TB_RSVD_MASK 0xFF + +/* TxDMAUrgentThresh */ +#define IPG_TU_RSVD_MASK 0xFF + +/* TxDMAPollPeriod */ +#define IPG_TP_RSVD_MASK 0xFF + +/* RxDMAUrgentThresh */ +#define IPG_RU_RSVD_MASK 0xFF + +/* RxDMAPollPeriod */ +#define IPG_RP_RSVD_MASK 0xFF + +/* ReceiveMode */ +#define IPG_RM_RSVD_MASK 0x3F +#define IPG_RM_RECEIVEUNICAST 0x01 +#define IPG_RM_RECEIVEMULTICAST 0x02 +#define IPG_RM_RECEIVEBROADCAST 0x04 +#define IPG_RM_RECEIVEALLFRAMES 0x08 +#define IPG_RM_RECEIVEMULTICASTHASH 0x10 +#define IPG_RM_RECEIVEIPMULTICAST 0x20 + +/* PhySet JES20040127EEPROM*/ +#define IPG_PS_MEM_LENB9B 0x01 +#define IPG_PS_MEM_LEN9 0x02 +#define IPG_PS_NON_COMPDET 0x04 + +/* PhyCtrl */ +#define IPG_PC_RSVD_MASK 0xFF +#define IPG_PC_MGMTCLK_LO 0x00 +#define IPG_PC_MGMTCLK_HI 0x01 +#define IPG_PC_MGMTCLK 0x01 +#define IPG_PC_MGMTDATA 0x02 +#define IPG_PC_MGMTDIR 0x04 +#define IPG_PC_DUPLEX_POLARITY 0x08 +#define IPG_PC_DUPLEX_STATUS 0x10 +#define IPG_PC_LINK_POLARITY 0x20 +#define IPG_PC_LINK_SPEED 0xC0 +#define IPG_PC_LINK_SPEED_10MBPS 0x40 +#define IPG_PC_LINK_SPEED_100MBPS 0x80 +#define IPG_PC_LINK_SPEED_1000MBPS 0xC0 + +/* DMACtrl */ +#define IPG_DC_RSVD_MASK 0xC07D9818 +#define IPG_DC_RX_DMA_COMPLETE 0x00000008 +#define IPG_DC_RX_DMA_POLL_NOW 0x00000010 +#define IPG_DC_TX_DMA_COMPLETE 0x00000800 +#define IPG_DC_TX_DMA_POLL_NOW 0x00001000 +#define IPG_DC_TX_DMA_IN_PROG 0x00008000 +#define IPG_DC_RX_EARLY_DISABLE 0x00010000 +#define IPG_DC_MWI_DISABLE 0x00040000 +#define IPG_DC_TX_WRITE_BACK_DISABLE 0x00080000 +#define IPG_DC_TX_BURST_LIMIT 0x00700000 +#define IPG_DC_TARGET_ABORT 0x40000000 +#define IPG_DC_MASTER_ABORT 0x80000000 + +/* ASICCtrl */ +#define IPG_AC_RSVD_MASK 0x07FFEFF2 +#define IPG_AC_EXP_ROM_SIZE 0x00000002 +#define IPG_AC_PHY_SPEED10 0x00000010 +#define IPG_AC_PHY_SPEED100 0x00000020 +#define IPG_AC_PHY_SPEED1000 0x00000040 +#define IPG_AC_PHY_MEDIA 0x00000080 +#define IPG_AC_FORCED_CFG 0x00000700 +#define IPG_AC_D3RESETDISABLE 0x00000800 +#define IPG_AC_SPEED_UP_MODE 0x00002000 +#define IPG_AC_LED_MODE 0x00004000 +#define IPG_AC_RST_OUT_POLARITY 0x00008000 +#define IPG_AC_GLOBAL_RESET 0x00010000 +#define IPG_AC_RX_RESET 0x00020000 +#define IPG_AC_TX_RESET 0x00040000 +#define IPG_AC_DMA 0x00080000 +#define IPG_AC_FIFO 0x00100000 +#define IPG_AC_NETWORK 0x00200000 +#define IPG_AC_HOST 0x00400000 +#define IPG_AC_AUTO_INIT 0x00800000 +#define IPG_AC_RST_OUT 0x01000000 +#define IPG_AC_INT_REQUEST 0x02000000 +#define IPG_AC_RESET_BUSY 0x04000000 +#define IPG_AC_LED_SPEED 0x08000000 //JES20040127EEPROM +#define IPG_AC_LED_MODE_BIT_1 0x20000000 //JES20040127EEPROM + +/* EepromCtrl */ +#define IPG_EC_RSVD_MASK 0x83FF +#define IPG_EC_EEPROM_ADDR 0x00FF +#define IPG_EC_EEPROM_OPCODE 0x0300 +#define IPG_EC_EEPROM_SUBCOMMAD 0x0000 +#define IPG_EC_EEPROM_WRITEOPCODE 0x0100 +#define IPG_EC_EEPROM_READOPCODE 0x0200 +#define IPG_EC_EEPROM_ERASEOPCODE 0x0300 +#define IPG_EC_EEPROM_BUSY 0x8000 + +/* FIFOCtrl */ +#define IPG_FC_RSVD_MASK 0xC001 +#define IPG_FC_RAM_TEST_MODE 0x0001 +#define IPG_FC_TRANSMITTING 0x4000 +#define IPG_FC_RECEIVING 0x8000 + +/* TxStatus */ +#define IPG_TS_RSVD_MASK 0xFFFF00DD +#define IPG_TS_TX_ERROR 0x00000001 +#define IPG_TS_LATE_COLLISION 0x00000004 +#define IPG_TS_TX_MAX_COLL 0x00000008 +#define IPG_TS_TX_UNDERRUN 0x00000010 +#define IPG_TS_TX_IND_REQD 0x00000040 +#define IPG_TS_TX_COMPLETE 0x00000080 +#define IPG_TS_TX_FRAMEID 0xFFFF0000 + +/* WakeEvent */ +#define IPG_WE_WAKE_PKT_ENABLE 0x01 +#define IPG_WE_MAGIC_PKT_ENABLE 0x02 +#define IPG_WE_LINK_EVT_ENABLE 0x04 +#define IPG_WE_WAKE_POLARITY 0x08 +#define IPG_WE_WAKE_PKT_EVT 0x10 +#define IPG_WE_MAGIC_PKT_EVT 0x20 +#define IPG_WE_LINK_EVT 0x40 +#define IPG_WE_WOL_ENABLE 0x80 + +/* IntEnable */ +#define IPG_IE_RSVD_MASK 0x1FFE +#define IPG_IE_HOST_ERROR 0x0002 +#define IPG_IE_TX_COMPLETE 0x0004 +#define IPG_IE_MAC_CTRL_FRAME 0x0008 +#define IPG_IE_RX_COMPLETE 0x0010 +#define IPG_IE_RX_EARLY 0x0020 +#define IPG_IE_INT_REQUESTED 0x0040 +#define IPG_IE_UPDATE_STATS 0x0080 +#define IPG_IE_LINK_EVENT 0x0100 +#define IPG_IE_TX_DMA_COMPLETE 0x0200 +#define IPG_IE_RX_DMA_COMPLETE 0x0400 +#define IPG_IE_RFD_LIST_END 0x0800 +#define IPG_IE_RX_DMA_PRIORITY 0x1000 + +/* IntStatus */ +#define IPG_IS_RSVD_MASK 0x1FFF +#define IPG_IS_INTERRUPT_STATUS 0x0001 +#define IPG_IS_HOST_ERROR 0x0002 +#define IPG_IS_TX_COMPLETE 0x0004 +#define IPG_IS_MAC_CTRL_FRAME 0x0008 +#define IPG_IS_RX_COMPLETE 0x0010 +#define IPG_IS_RX_EARLY 0x0020 +#define IPG_IS_INT_REQUESTED 0x0040 +#define IPG_IS_UPDATE_STATS 0x0080 +#define IPG_IS_LINK_EVENT 0x0100 +#define IPG_IS_TX_DMA_COMPLETE 0x0200 +#define IPG_IS_RX_DMA_COMPLETE 0x0400 +#define IPG_IS_RFD_LIST_END 0x0800 +#define IPG_IS_RX_DMA_PRIORITY 0x1000 + +/* MACCtrl */ +#define IPG_MC_RSVD_MASK 0x7FE33FA3 +#define IPG_MC_IFS_SELECT 0x00000003 +#define IPG_MC_IFS_4352BIT 0x00000003 +#define IPG_MC_IFS_1792BIT 0x00000002 +#define IPG_MC_IFS_1024BIT 0x00000001 +#define IPG_MC_IFS_96BIT 0x00000000 +#define IPG_MC_DUPLEX_SELECT 0x00000020 +#define IPG_MC_DUPLEX_SELECT_FD 0x00000020 +#define IPG_MC_DUPLEX_SELECT_HD 0x00000000 +#define IPG_MC_TX_FLOW_CONTROL_ENABLE 0x00000080 +#define IPG_MC_RX_FLOW_CONTROL_ENABLE 0x00000100 +#define IPG_MC_RCV_FCS 0x00000200 +#define IPG_MC_FIFO_LOOPBACK 0x00000400 +#define IPG_MC_MAC_LOOPBACK 0x00000800 +#define IPG_MC_AUTO_VLAN_TAGGING 0x00001000 +#define IPG_MC_AUTO_VLAN_UNTAGGING 0x00002000 +#define IPG_MC_COLLISION_DETECT 0x00010000 +#define IPG_MC_CARRIER_SENSE 0x00020000 +#define IPG_MC_STATISTICS_ENABLE 0x00200000 +#define IPG_MC_STATISTICS_DISABLE 0x00400000 +#define IPG_MC_STATISTICS_ENABLED 0x00800000 +#define IPG_MC_TX_ENABLE 0x01000000 +#define IPG_MC_TX_DISABLE 0x02000000 +#define IPG_MC_TX_ENABLED 0x04000000 +#define IPG_MC_RX_ENABLE 0x08000000 +#define IPG_MC_RX_DISABLE 0x10000000 +#define IPG_MC_RX_ENABLED 0x20000000 +#define IPG_MC_PAUSED 0x40000000 + +/* + * Tune + */ + +/* Miscellaneous Constants. */ +#define TRUE 1 +#define FALSE 0 + +/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */ +#define IPG_APPEND_FCS_ON_TX TRUE + +/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */ +#define IPG_STRIP_FCS_ON_RX TRUE + +/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with + * Ethernet errors. + */ +#define IPG_DROP_ON_RX_ETH_ERRORS TRUE + +/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually + * (via TFC). + */ +#define IPG_INSERT_MANUAL_VLAN_TAG FALSE + +/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */ +#define IPG_ADD_IPCHECKSUM_ON_TX FALSE + +/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX. + * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. + */ +#define IPG_ADD_TCPCHECKSUM_ON_TX FALSE + +/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX. + * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. + */ +#define IPG_ADD_UDPCHECKSUM_ON_TX FALSE + +/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx + * constants as desired. + */ +#define IPG_MANUAL_VLAN_VID 0xABC +#define IPG_MANUAL_VLAN_CFI 0x1 +#define IPG_MANUAL_VLAN_USERPRIORITY 0x5 + +#define IPG_IO_REG_RANGE 0xFF +#define IPG_MEM_REG_RANGE 0x154 +#define IPG_DRIVER_NAME "Sundance Technology IPG Triple-Speed Ethernet" +#define IPG_NIC_PHY_ADDRESS 0x01 +#define IPG_DMALIST_ALIGN_PAD 0x07 +#define IPG_MULTICAST_HASHTABLE_SIZE 0x40 + +/* Number of miliseconds to wait after issuing a software reset. + * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation. + */ +#define IPG_AC_RESETWAIT 0x05 + +/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */ +#define IPG_AC_RESET_TIMEOUT 0x0A + +/* Minimum number of nanoseconds used to toggle MDC clock during + * MII/GMII register access. + */ +#define IPG_PC_PHYCTRLWAIT_NS 200 + +#define IPG_TFDLIST_LENGTH 0x100 + +/* Number of frames between TxDMAComplete interrupt. + * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH + */ +#define IPG_FRAMESBETWEENTXDMACOMPLETES 0x1 + +#ifdef JUMBO_FRAME + +# ifdef JUMBO_FRAME_SIZE_2K +# define JUMBO_FRAME_SIZE 2048 +# define __IPG_RXFRAG_SIZE 2048 +# else +# ifdef JUMBO_FRAME_SIZE_3K +# define JUMBO_FRAME_SIZE 3072 +# define __IPG_RXFRAG_SIZE 3072 +# else +# ifdef JUMBO_FRAME_SIZE_4K +# define JUMBO_FRAME_SIZE 4096 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_5K +# define JUMBO_FRAME_SIZE 5120 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_6K +# define JUMBO_FRAME_SIZE 6144 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_7K +# define JUMBO_FRAME_SIZE 7168 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_8K +# define JUMBO_FRAME_SIZE 8192 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_9K +# define JUMBO_FRAME_SIZE 9216 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_10K +# define JUMBO_FRAME_SIZE 10240 +# define __IPG_RXFRAG_SIZE 4088 +# else +# define JUMBO_FRAME_SIZE 4096 +# endif +# endif +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif + +/* Size of allocated received buffers. Nominally 0x0600. + * Define larger if expecting jumbo frames. + */ +#ifdef JUMBO_FRAME +//IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash +#define IPG_TXFRAG_SIZE JUMBO_FRAME_SIZE +#endif + +/* Size of allocated received buffers. Nominally 0x0600. + * Define larger if expecting jumbo frames. + */ +#ifdef JUMBO_FRAME +//4088=4096-8 +#define IPG_RXFRAG_SIZE __IPG_RXFRAG_SIZE +#define IPG_RXSUPPORT_SIZE IPG_MAX_RXFRAME_SIZE +#else +#define IPG_RXFRAG_SIZE 0x0600 +#define IPG_RXSUPPORT_SIZE IPG_RXFRAG_SIZE +#endif + +/* IPG_MAX_RXFRAME_SIZE <= IPG_RXFRAG_SIZE */ +#ifdef JUMBO_FRAME +#define IPG_MAX_RXFRAME_SIZE JUMBO_FRAME_SIZE +#else +#define IPG_MAX_RXFRAME_SIZE 0x0600 +#endif + +#define IPG_RFDLIST_LENGTH 0x100 + +/* Maximum number of RFDs to process per interrupt. + * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH + */ +#define IPG_MAXRFDPROCESS_COUNT 0x80 + +/* Minimum margin between last freed RFD, and current RFD. + * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH + */ +#define IPG_MINUSEDRFDSTOFREE 0x80 + +/* specify the jumbo frame maximum size + * per unit is 0x600 (the RxBuffer size that one RFD can carry) + */ +#define MAX_JUMBOSIZE 0x8 // max is 12K + +/* Key register values loaded at driver start up. */ + +/* TXDMAPollPeriod is specified in 320ns increments. + * + * Value Time + * --------------------- + * 0x00-0x01 320ns + * 0x03 ~1us + * 0x1F ~10us + * 0xFF ~82us + */ +#define IPG_TXDMAPOLLPERIOD_VALUE 0x26 + +/* TxDMAUrgentThresh specifies the minimum amount of + * data in the transmit FIFO before asserting an + * urgent transmit DMA request. + * + * Value Min TxFIFO occupied space before urgent TX request + * --------------------------------------------------------------- + * 0x00-0x04 128 bytes (1024 bits) + * 0x27 1248 bytes (~10000 bits) + * 0x30 1536 bytes (12288 bits) + * 0xFF 8192 bytes (65535 bits) + */ +#define IPG_TXDMAURGENTTHRESH_VALUE 0x04 + +/* TxDMABurstThresh specifies the minimum amount of + * free space in the transmit FIFO before asserting an + * transmit DMA request. + * + * Value Min TxFIFO free space before TX request + * ---------------------------------------------------- + * 0x00-0x08 256 bytes + * 0x30 1536 bytes + * 0xFF 8192 bytes + */ +#define IPG_TXDMABURSTTHRESH_VALUE 0x30 + +/* RXDMAPollPeriod is specified in 320ns increments. + * + * Value Time + * --------------------- + * 0x00-0x01 320ns + * 0x03 ~1us + * 0x1F ~10us + * 0xFF ~82us + */ +#define IPG_RXDMAPOLLPERIOD_VALUE 0x01 + +/* RxDMAUrgentThresh specifies the minimum amount of + * free space within the receive FIFO before asserting + * a urgent receive DMA request. + * + * Value Min RxFIFO free space before urgent RX request + * --------------------------------------------------------------- + * 0x00-0x04 128 bytes (1024 bits) + * 0x27 1248 bytes (~10000 bits) + * 0x30 1536 bytes (12288 bits) + * 0xFF 8192 bytes (65535 bits) + */ +#define IPG_RXDMAURGENTTHRESH_VALUE 0x30 + +/* RxDMABurstThresh specifies the minimum amount of + * occupied space within the receive FIFO before asserting + * a receive DMA request. + * + * Value Min TxFIFO free space before TX request + * ---------------------------------------------------- + * 0x00-0x08 256 bytes + * 0x30 1536 bytes + * 0xFF 8192 bytes + */ +#define IPG_RXDMABURSTTHRESH_VALUE 0x30 + +/* FlowOnThresh specifies the maximum amount of occupied + * space in the receive FIFO before a PAUSE frame with + * maximum pause time transmitted. + * + * Value Max RxFIFO occupied space before PAUSE + * --------------------------------------------------- + * 0x0000 0 bytes + * 0x0740 29,696 bytes + * 0x07FF 32,752 bytes + */ +#define IPG_FLOWONTHRESH_VALUE 0x0740 + +/* FlowOffThresh specifies the minimum amount of occupied + * space in the receive FIFO before a PAUSE frame with + * zero pause time is transmitted. + * + * Value Max RxFIFO occupied space before PAUSE + * --------------------------------------------------- + * 0x0000 0 bytes + * 0x00BF 3056 bytes + * 0x07FF 32,752 bytes + */ +#define IPG_FLOWOFFTHRESH_VALUE 0x00BF + +/* + * Miscellaneous macros. + */ + +/* Marco for printing debug statements. +# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " ## args) */ +#ifdef IPG_DEBUG +# define IPG_DEBUG_MSG(args...) +# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args) +# define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args) +# define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args) +#else +# define IPG_DEBUG_MSG(args...) +# define IPG_DDEBUG_MSG(args...) +# define IPG_DUMPRFDLIST(args) +# define IPG_DUMPTFDLIST(args) +#endif + +/* + * End miscellaneous macros. + */ + +/* Transmit Frame Descriptor. The IPG supports 15 fragments, + * however Linux requires only a single fragment. Note, each + * TFD field is 64 bits wide. + */ +struct ipg_tx { + u64 next_desc; + u64 tfc; + u64 frag_info; +}; + +/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide. + */ +struct ipg_rx { + u64 next_desc; + u64 rfs; + u64 frag_info; +}; + +struct SJumbo { + int FoundStart; + int CurrentSize; + struct sk_buff *skb; +}; +/* Structure of IPG NIC specific data. */ +struct ipg_nic_private { + void __iomem *ioaddr; + struct ipg_tx *txd; + struct ipg_rx *rxd; + dma_addr_t txd_map; + dma_addr_t rxd_map; + struct sk_buff *TxBuff[IPG_TFDLIST_LENGTH]; + struct sk_buff *RxBuff[IPG_RFDLIST_LENGTH]; + unsigned int tx_current; + unsigned int tx_dirty; + unsigned int rx_current; + unsigned int rx_dirty; +// Add by Grace 2005/05/19 +#ifdef JUMBO_FRAME + struct SJumbo Jumbo; +#endif + unsigned int rx_buf_sz; + struct pci_dev *pdev; + struct net_device *dev; + struct net_device_stats stats; + spinlock_t lock; + int tenmbpsmode; + + /*Jesse20040128EEPROM_VALUE */ + u16 LED_Mode; + u16 station_addr[3]; /* Station Address in EEPROM Reg 0x10..0x12 */ + + struct mutex mii_mutex; + struct mii_if_info mii_if; + int ResetCurrentTFD; +#ifdef IPG_DEBUG + int RFDlistendCount; + int RFDListCheckedCount; + int EmptyRFDListCount; +#endif + struct delayed_work task; +}; + +//variable record -- index by leading revision/length +//Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN +unsigned short DefaultPhyParam[] = { + // 11/12/03 IP1000A v1-3 rev=0x40 + /*-------------------------------------------------------------------------- + (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2, + 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6, + 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700, + --------------------------------------------------------------------------*/ + // 12/17/03 IP1000A v1-4 rev=0x40 + (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, + 0x0000, + 30, 0x005e, 9, 0x0700, + // 01/09/04 IP1000A v1-5 rev=0x41 + (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, + 0x0000, + 30, 0x005e, 9, 0x0700, + 0x0000 +}; + +#endif /* __LINUX_IPG_H */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 55f307ffbf96..c9c24ddf9c7b 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1841,6 +1841,8 @@ #define PCI_VENDOR_ID_ABOCOM 0x13D1 #define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1 +#define PCI_VENDOR_ID_SUNDANCE 0x13f0 + #define PCI_VENDOR_ID_CMEDIA 0x13f6 #define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100 #define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101 From 1a348ccc1047a00507e554826775a3d81f7f3437 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Mon, 17 Sep 2007 18:50:36 -0700 Subject: [PATCH 1416/2804] [NET]: Add Tehuti network driver. [ Ported to napi_struct changes... -DaveM ] Signed-off-by: David S. Miller --- MAINTAINERS | 8 + drivers/net/Kconfig | 6 + drivers/net/Makefile | 1 + drivers/net/tehuti.c | 2508 +++++++++ drivers/net/tehuti.h | 564 ++ drivers/net/tehuti_fw.h | 10712 ++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 5 + 7 files changed, 13804 insertions(+) create mode 100644 drivers/net/tehuti.c create mode 100644 drivers/net/tehuti.h create mode 100644 drivers/net/tehuti_fw.h diff --git a/MAINTAINERS b/MAINTAINERS index 27cd503cf0e4..3f07d5ff85f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3630,6 +3630,14 @@ M: hlhung3i@gmail.com W: http://tcp-lp-mod.sourceforge.net/ S: Maintained +TEHUTI ETHERNET DRIVER +P: Alexander Indenbaum +M: baum@tehutinetworks.net +P: Andy Gospodarek +M: andy@greyhouse.net +L: netdev@vger.kernel.org +S: Supported + TI FLASH MEDIA INTERFACE DRIVER P: Alex Dubov M: oakad@yahoo.com diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 63ab05b5a87a..fd284a93c9dd 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2661,6 +2661,12 @@ config MLX4_DEBUG debug_level module parameter (which can also be set after the driver is loaded through sysfs). +config TEHUTI + tristate "Tehuti Networks 10G Ethernet" + depends on PCI + help + Tehuti Networks 10G Ethernet NIC + endif # NETDEV_10000 source "drivers/net/tokenring/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 2098647080a0..2ab33e8b9159 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_ATL1) += atl1/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o +obj-$(CONFIG_TEHUTI) += tehuti.o gianfar_driver-objs := gianfar.o \ gianfar_ethtool.o \ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c new file mode 100644 index 000000000000..248343177356 --- /dev/null +++ b/drivers/net/tehuti.c @@ -0,0 +1,2508 @@ +/* + * Tehuti Networks(R) Network Driver + * ethtool interface implementation + * Copyright (C) 2007 Tehuti Networks Ltd. 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. + */ + +/* + * RX HW/SW interaction overview + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * There are 2 types of RX communication channels betwean driver and NIC. + * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming + * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds + * info about buffer's location, size and ID. An ID field is used to identify a + * buffer when it's returned with data via RXD Fifo (see below) + * 2) RX Data Fifo - RXD - holds descriptors of full buffers. This Fifo is + * filled by HW and is readen by SW. Each descriptor holds status and ID. + * HW pops descriptor from RXF Fifo, stores ID, fills buffer with incoming data, + * via dma moves it into host memory, builds new RXD descriptor with same ID, + * pushes it into RXD Fifo and raises interrupt to indicate new RX data. + * + * Current NIC configuration (registers + firmware) makes NIC use 2 RXF Fifos. + * One holds 1.5K packets and another - 26K packets. Depending on incoming + * packet size, HW desides on a RXF Fifo to pop buffer from. When packet is + * filled with data, HW builds new RXD descriptor for it and push it into single + * RXD Fifo. + * + * RX SW Data Structures + * ~~~~~~~~~~~~~~~~~~~~~ + * skb db - used to keep track of all skbs owned by SW and their dma addresses. + * For RX case, ownership lasts from allocating new empty skb for RXF until + * accepting full skb from RXD and passing it to OS. Each RXF Fifo has its own + * skb db. Implemented as array with bitmask. + * fifo - keeps info about fifo's size and location, relevant HW registers, + * usage and skb db. Each RXD and RXF Fifo has its own fifo structure. + * Implemented as simple struct. + * + * RX SW Execution Flow + * ~~~~~~~~~~~~~~~~~~~~ + * Upon initialization (ifconfig up) driver creates RX fifos and initializes + * relevant registers. At the end of init phase, driver enables interrupts. + * NIC sees that there is no RXF buffers and raises + * RD_INTR interrupt, isr fills skbs and Rx begins. + * Driver has two receive operation modes: + * NAPI - interrupt-driven mixed with polling + * interrupt-driven only + * + * Interrupt-driven only flow is following. When buffer is ready, HW raises + * interrupt and isr is called. isr collects all available packets + * (bdx_rx_receive), refills skbs (bdx_rx_alloc_skbs) and exit. + + * Rx buffer allocation note + * ~~~~~~~~~~~~~~~~~~~~~~~~~ + * Driver cares to feed such amount of RxF descriptors that respective amount of + * RxD descriptors can not fill entire RxD fifo. The main reason is lack of + * overflow check in Bordeaux for RxD fifo free/used size. + * FIXME: this is NOT fully implemented, more work should be done + * + */ + +#include "tehuti.h" +#include "tehuti_fw.h" + +static struct pci_device_id __devinitdata bdx_pci_tbl[] = { + {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0} +}; + +MODULE_DEVICE_TABLE(pci, bdx_pci_tbl); + +/* Definitions needed by ISR or NAPI functions */ +static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f); +static void bdx_tx_cleanup(struct bdx_priv *priv); +static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget); + +/* Definitions needed by FW loading */ +static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size); + +/* Definitions needed by hw_start */ +static int bdx_tx_init(struct bdx_priv *priv); +static int bdx_rx_init(struct bdx_priv *priv); + +/* Definitions needed by bdx_close */ +static void bdx_rx_free(struct bdx_priv *priv); +static void bdx_tx_free(struct bdx_priv *priv); + +/* Definitions needed by bdx_probe */ +static void bdx_ethtool_ops(struct net_device *netdev); + +/************************************************************************* + * Print Info * + *************************************************************************/ + +static void print_hw_id(struct pci_dev *pdev) +{ + struct pci_nic *nic = pci_get_drvdata(pdev); + u16 pci_link_status = 0; + u16 pci_ctrl = 0; + + pci_read_config_word(pdev, PCI_LINK_STATUS_REG, &pci_link_status); + pci_read_config_word(pdev, PCI_DEV_CTRL_REG, &pci_ctrl); + + printk(KERN_INFO "tehuti: %s%s\n", BDX_NIC_NAME, + nic->port_num == 1 ? "" : ", 2-Port"); + printk(KERN_INFO + "tehuti: srom 0x%x fpga %d build %u lane# %d" + " max_pl 0x%x mrrs 0x%x\n", + readl(nic->regs + SROM_VER), readl(nic->regs + FPGA_VER) & 0xFFF, + readl(nic->regs + FPGA_SEED), + GET_LINK_STATUS_LANES(pci_link_status), + GET_DEV_CTRL_MAXPL(pci_ctrl), GET_DEV_CTRL_MRRS(pci_ctrl)); +} + +static void print_fw_id(struct pci_nic *nic) +{ + printk(KERN_INFO "tehuti: fw 0x%x\n", readl(nic->regs + FW_VER)); +} + +static void print_eth_id(struct net_device *ndev) +{ + printk(KERN_INFO "%s: %s, Port %c\n", ndev->name, BDX_NIC_NAME, + (ndev->if_port == 0) ? 'A' : 'B'); + +} + +/************************************************************************* + * Code * + *************************************************************************/ + +#define bdx_enable_interrupts(priv) \ + do { WRITE_REG(priv, regIMR, IR_RUN); } while (0) +#define bdx_disable_interrupts(priv) \ + do { WRITE_REG(priv, regIMR, 0); } while (0) + +/* bdx_fifo_init + * create TX/RX descriptor fifo for host-NIC communication. + * 1K extra space is allocated at the end of the fifo to simplify + * processing of descriptors that wraps around fifo's end + * @priv - NIC private structure + * @f - fifo to initialize + * @fsz_type - fifo size type: 0-4KB, 1-8KB, 2-16KB, 3-32KB + * @reg_XXX - offsets of registers relative to base address + * + * Returns 0 on success, negative value on failure + * + */ +static int +bdx_fifo_init(struct bdx_priv *priv, struct fifo *f, int fsz_type, + u16 reg_CFG0, u16 reg_CFG1, u16 reg_RPTR, u16 reg_WPTR) +{ + u16 memsz = FIFO_SIZE * (1 << fsz_type); + + memset(f, 0, sizeof(struct fifo)); + /* pci_alloc_consistent gives us 4k-aligned memory */ + f->va = pci_alloc_consistent(priv->pdev, + memsz + FIFO_EXTRA_SPACE, &f->da); + if (!f->va) { + ERR("pci_alloc_consistent failed\n"); + RET(-ENOMEM); + } + f->reg_CFG0 = reg_CFG0; + f->reg_CFG1 = reg_CFG1; + f->reg_RPTR = reg_RPTR; + f->reg_WPTR = reg_WPTR; + f->rptr = 0; + f->wptr = 0; + f->memsz = memsz; + f->size_mask = memsz - 1; + WRITE_REG(priv, reg_CFG0, (u32) ((f->da & TX_RX_CFG0_BASE) | fsz_type)); + WRITE_REG(priv, reg_CFG1, H32_64(f->da)); + + RET(0); +} + +/* bdx_fifo_free - free all resources used by fifo + * @priv - NIC private structure + * @f - fifo to release + */ +static void bdx_fifo_free(struct bdx_priv *priv, struct fifo *f) +{ + ENTER; + if (f->va) { + pci_free_consistent(priv->pdev, + f->memsz + FIFO_EXTRA_SPACE, f->va, f->da); + f->va = NULL; + } + RET(); +} + +/* + * bdx_link_changed - notifies OS about hw link state. + * @bdx_priv - hw adapter structure + */ +static void bdx_link_changed(struct bdx_priv *priv) +{ + u32 link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT; + + if (!link) { + if (netif_carrier_ok(priv->ndev)) { + netif_stop_queue(priv->ndev); + netif_carrier_off(priv->ndev); + ERR("%s: Link Down\n", priv->ndev->name); + } + } else { + if (!netif_carrier_ok(priv->ndev)) { + netif_wake_queue(priv->ndev); + netif_carrier_on(priv->ndev); + ERR("%s: Link Up\n", priv->ndev->name); + } + } +} + +static void bdx_isr_extra(struct bdx_priv *priv, u32 isr) +{ + if (isr & IR_RX_FREE_0) { + bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0); + DBG("RX_FREE_0\n"); + } + + if (isr & IR_LNKCHG0) + bdx_link_changed(priv); + + if (isr & IR_PCIE_LINK) + ERR("%s: PCI-E Link Fault\n", priv->ndev->name); + + if (isr & IR_PCIE_TOUT) + ERR("%s: PCI-E Time Out\n", priv->ndev->name); + +} + +/* bdx_isr - Interrupt Service Routine for Bordeaux NIC + * @irq - interrupt number + * @ndev - network device + * @regs - CPU registers + * + * Return IRQ_NONE if it was not our interrupt, IRQ_HANDLED - otherwise + * + * It reads ISR register to know interrupt reasons, and proceed them one by one. + * Reasons of interest are: + * RX_DESC - new packet has arrived and RXD fifo holds its descriptor + * RX_FREE - number of free Rx buffers in RXF fifo gets low + * TX_FREE - packet was transmited and RXF fifo holds its descriptor + */ + +static irqreturn_t bdx_isr_napi(int irq, void *dev) +{ + struct net_device *ndev = dev; + struct bdx_priv *priv = ndev->priv; + u32 isr; + + ENTER; + isr = (READ_REG(priv, regISR) & IR_RUN); + if (unlikely(!isr)) { + bdx_enable_interrupts(priv); + return IRQ_NONE; /* Not our interrupt */ + } + + if (isr & IR_EXTRA) + bdx_isr_extra(priv, isr); + + if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) { + if (likely(netif_rx_schedule_prep(ndev, &priv->napi))) { + __netif_rx_schedule(ndev, &priv->napi); + RET(IRQ_HANDLED); + } else { + /* NOTE: we get here if intr has slipped into window + * between these lines in bdx_poll: + * bdx_enable_interrupts(priv); + * return 0; + * currently intrs are disabled (since we read ISR), + * and we have failed to register next poll. + * so we read the regs to trigger chip + * and allow further interupts. */ + READ_REG(priv, regTXF_WPTR_0); + READ_REG(priv, regRXD_WPTR_0); + } + } + + bdx_enable_interrupts(priv); + RET(IRQ_HANDLED); +} + +static int bdx_poll(struct napi_struct *napi, int budget) +{ + struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi); + struct net_device *dev = priv->ndev; + int work_done; + + ENTER; + bdx_tx_cleanup(priv); + work_done = bdx_rx_receive(priv, &priv->rxd_fifo0, budget); + if ((work_done < budget) || + (priv->napi_stop++ >= 30)) { + DBG("rx poll is done. backing to isr-driven\n"); + + /* from time to time we exit to let NAPI layer release + * device lock and allow waiting tasks (eg rmmod) to advance) */ + priv->napi_stop = 0; + + netif_rx_complete(dev, napi); + bdx_enable_interrupts(priv); + } + return work_done; +} + +/* bdx_fw_load - loads firmware to NIC + * @priv - NIC private structure + * Firmware is loaded via TXD fifo, so it must be initialized first. + * Firware must be loaded once per NIC not per PCI device provided by NIC (NIC + * can have few of them). So all drivers use semaphore register to choose one + * that will actually load FW to NIC. + */ + +static int bdx_fw_load(struct bdx_priv *priv) +{ + int master, i; + + ENTER; + master = READ_REG(priv, regINIT_SEMAPHORE); + if (!READ_REG(priv, regINIT_STATUS) && master) { + bdx_tx_push_desc_safe(priv, s_firmLoad, sizeof(s_firmLoad)); + mdelay(100); + } + for (i = 0; i < 200; i++) { + if (READ_REG(priv, regINIT_STATUS)) + break; + mdelay(2); + } + if (master) + WRITE_REG(priv, regINIT_SEMAPHORE, 1); + + if (i == 200) { + ERR("%s: firmware loading failed\n", priv->ndev->name); + DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n", + READ_REG(priv, regVPC), + READ_REG(priv, regVIC), READ_REG(priv, regINIT_STATUS), i); + RET(-EIO); + } else { + DBG("%s: firmware loading success\n", priv->ndev->name); + RET(0); + } +} + +static void bdx_restore_mac(struct net_device *ndev, struct bdx_priv *priv) +{ + u32 val; + + ENTER; + DBG("mac0=%x mac1=%x mac2=%x\n", + READ_REG(priv, regUNC_MAC0_A), + READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A)); + + val = (ndev->dev_addr[0] << 8) | (ndev->dev_addr[1]); + WRITE_REG(priv, regUNC_MAC2_A, val); + val = (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]); + WRITE_REG(priv, regUNC_MAC1_A, val); + val = (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]); + WRITE_REG(priv, regUNC_MAC0_A, val); + + DBG("mac0=%x mac1=%x mac2=%x\n", + READ_REG(priv, regUNC_MAC0_A), + READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A)); + RET(); +} + +/* bdx_hw_start - inits registers and starts HW's Rx and Tx engines + * @priv - NIC private structure + */ +static int bdx_hw_start(struct bdx_priv *priv) +{ + int rc = -EIO; + struct net_device *ndev = priv->ndev; + + ENTER; + bdx_link_changed(priv); + + /* 10G overall max length (vlan, eth&ip header, ip payload, crc) */ + WRITE_REG(priv, regFRM_LENGTH, 0X3FE0); + WRITE_REG(priv, regPAUSE_QUANT, 0x96); + WRITE_REG(priv, regRX_FIFO_SECTION, 0x800010); + WRITE_REG(priv, regTX_FIFO_SECTION, 0xE00010); + WRITE_REG(priv, regRX_FULLNESS, 0); + WRITE_REG(priv, regTX_FULLNESS, 0); + WRITE_REG(priv, regCTRLST, + regCTRLST_BASE | regCTRLST_RX_ENA | regCTRLST_TX_ENA); + + WRITE_REG(priv, regVGLB, 0); + WRITE_REG(priv, regMAX_FRAME_A, + priv->rxf_fifo0.m.pktsz & MAX_FRAME_AB_VAL); + + DBG("RDINTCM=%08x\n", priv->rdintcm); /*NOTE: test script uses this */ + WRITE_REG(priv, regRDINTCM0, priv->rdintcm); + WRITE_REG(priv, regRDINTCM2, 0); /*cpu_to_le32(rcm.val)); */ + + DBG("TDINTCM=%08x\n", priv->tdintcm); /*NOTE: test script uses this */ + WRITE_REG(priv, regTDINTCM0, priv->tdintcm); /* old val = 0x300064 */ + + /* Enable timer interrupt once in 2 secs. */ + /*WRITE_REG(priv, regGTMR0, ((GTMR_SEC * 2) & GTMR_DATA)); */ + bdx_restore_mac(priv->ndev, priv); + + WRITE_REG(priv, regGMAC_RXF_A, GMAC_RX_FILTER_OSEN | + GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB); + +#define BDX_IRQ_TYPE ((priv->nic->irq_type == IRQ_MSI)?0:IRQF_SHARED) + if ((rc = request_irq(priv->pdev->irq, &bdx_isr_napi, BDX_IRQ_TYPE, + ndev->name, ndev))) + goto err_irq; + bdx_enable_interrupts(priv); + + RET(0); + +err_irq: + RET(rc); +} + +static void bdx_hw_stop(struct bdx_priv *priv) +{ + ENTER; + bdx_disable_interrupts(priv); + free_irq(priv->pdev->irq, priv->ndev); + + netif_carrier_off(priv->ndev); + netif_stop_queue(priv->ndev); + + RET(); +} + +static int bdx_hw_reset_direct(void __iomem *regs) +{ + u32 val, i; + ENTER; + + /* reset sequences: read, write 1, read, write 0 */ + val = readl(regs + regCLKPLL); + writel((val | CLKPLL_SFTRST) + 0x8, regs + regCLKPLL); + udelay(50); + val = readl(regs + regCLKPLL); + writel(val & ~CLKPLL_SFTRST, regs + regCLKPLL); + + /* check that the PLLs are locked and reset ended */ + for (i = 0; i < 70; i++, mdelay(10)) + if ((readl(regs + regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) { + /* do any PCI-E read transaction */ + readl(regs + regRXD_CFG0_0); + return 0; + } + ERR("tehuti: HW reset failed\n"); + return 1; /* failure */ +} + +static int bdx_hw_reset(struct bdx_priv *priv) +{ + u32 val, i; + ENTER; + + if (priv->port == 0) { + /* reset sequences: read, write 1, read, write 0 */ + val = READ_REG(priv, regCLKPLL); + WRITE_REG(priv, regCLKPLL, (val | CLKPLL_SFTRST) + 0x8); + udelay(50); + val = READ_REG(priv, regCLKPLL); + WRITE_REG(priv, regCLKPLL, val & ~CLKPLL_SFTRST); + } + /* check that the PLLs are locked and reset ended */ + for (i = 0; i < 70; i++, mdelay(10)) + if ((READ_REG(priv, regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) { + /* do any PCI-E read transaction */ + READ_REG(priv, regRXD_CFG0_0); + return 0; + } + ERR("tehuti: HW reset failed\n"); + return 1; /* failure */ +} + +static int bdx_sw_reset(struct bdx_priv *priv) +{ + int i; + + ENTER; + /* 1. load MAC (obsolete) */ + /* 2. disable Rx (and Tx) */ + WRITE_REG(priv, regGMAC_RXF_A, 0); + mdelay(100); + /* 3. disable port */ + WRITE_REG(priv, regDIS_PORT, 1); + /* 4. disable queue */ + WRITE_REG(priv, regDIS_QU, 1); + /* 5. wait until hw is disabled */ + for (i = 0; i < 50; i++) { + if (READ_REG(priv, regRST_PORT) & 1) + break; + mdelay(10); + } + if (i == 50) + ERR("%s: SW reset timeout. continuing anyway\n", + priv->ndev->name); + + /* 6. disable intrs */ + WRITE_REG(priv, regRDINTCM0, 0); + WRITE_REG(priv, regTDINTCM0, 0); + WRITE_REG(priv, regIMR, 0); + READ_REG(priv, regISR); + + /* 7. reset queue */ + WRITE_REG(priv, regRST_QU, 1); + /* 8. reset port */ + WRITE_REG(priv, regRST_PORT, 1); + /* 9. zero all read and write pointers */ + for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) + DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR); + for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) + WRITE_REG(priv, i, 0); + /* 10. unseet port disable */ + WRITE_REG(priv, regDIS_PORT, 0); + /* 11. unset queue disable */ + WRITE_REG(priv, regDIS_QU, 0); + /* 12. unset queue reset */ + WRITE_REG(priv, regRST_QU, 0); + /* 13. unset port reset */ + WRITE_REG(priv, regRST_PORT, 0); + /* 14. enable Rx */ + /* skiped. will be done later */ + /* 15. save MAC (obsolete) */ + for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) + DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR); + + RET(0); +} + +/* bdx_reset - performs right type of reset depending on hw type */ +static int bdx_reset(struct bdx_priv *priv) +{ + ENTER; + RET((priv->pdev->device == 0x3009) + ? bdx_hw_reset(priv) + : bdx_sw_reset(priv)); +} + +/** + * bdx_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int bdx_close(struct net_device *ndev) +{ + struct bdx_priv *priv = NULL; + + ENTER; + priv = ndev->priv; + + napi_disable(&priv->napi); + + bdx_reset(priv); + bdx_hw_stop(priv); + bdx_rx_free(priv); + bdx_tx_free(priv); + RET(0); +} + +/** + * bdx_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int bdx_open(struct net_device *ndev) +{ + struct bdx_priv *priv; + int rc; + + ENTER; + priv = ndev->priv; + bdx_reset(priv); + if (netif_running(ndev)) + netif_stop_queue(priv->ndev); + + if ((rc = bdx_tx_init(priv))) + goto err; + + if ((rc = bdx_rx_init(priv))) + goto err; + + if ((rc = bdx_fw_load(priv))) + goto err; + + bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0); + + if ((rc = bdx_hw_start(priv))) + goto err; + + napi_enable(&priv->napi); + + print_fw_id(priv->nic); + + RET(0); + +err: + bdx_close(ndev); + RET(rc); +} + +static void __init bdx_firmware_endianess(void) +{ + int i; + for (i = 0; i < sizeof(s_firmLoad) / sizeof(u32); i++) + s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]); +} + +static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + struct bdx_priv *priv = ndev->priv; + u32 data[3]; + int error; + + ENTER; + + DBG("jiffies=%ld cmd=%d\n", jiffies, cmd); + if (cmd != SIOCDEVPRIVATE) { + error = copy_from_user(data, ifr->ifr_data, sizeof(data)); + if (error) { + ERR("cant copy from user\n"); + RET(error); + } + DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); + } + + switch (data[0]) { + + case BDX_OP_READ: + data[2] = READ_REG(priv, data[1]); + DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2], + data[2]); + error = copy_to_user(ifr->ifr_data, data, sizeof(data)); + if (error) + RET(error); + break; + + case BDX_OP_WRITE: + WRITE_REG(priv, data[1], data[2]); + DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]); + break; + + default: + RET(-EOPNOTSUPP); + } + return 0; +} + +static int bdx_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + ENTER; + if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) + RET(bdx_ioctl_priv(ndev, ifr, cmd)); + else + RET(-EOPNOTSUPP); +} + +/* + * __bdx_vlan_rx_vid - private helper for adding/killing VLAN vid + * by passing VLAN filter table to hardware + * @ndev network device + * @vid VLAN vid + * @op add or kill operation + */ +static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable) +{ + struct bdx_priv *priv = ndev->priv; + u32 reg, bit, val; + + ENTER; + DBG2("vid=%d value=%d\n", (int)vid, enable); + if (unlikely(vid >= 4096)) { + ERR("tehuti: invalid VID: %u (> 4096)\n", vid); + RET(); + } + reg = regVLAN_0 + (vid / 32) * 4; + bit = 1 << vid % 32; + val = READ_REG(priv, reg); + DBG2("reg=%x, val=%x, bit=%d\n", reg, val, bit); + if (enable) + val |= bit; + else + val &= ~bit; + DBG2("new val %x\n", val); + WRITE_REG(priv, reg, val); + RET(); +} + +/* + * bdx_vlan_rx_add_vid - kernel hook for adding VLAN vid to hw filtering table + * @ndev network device + * @vid VLAN vid to add + */ +static void bdx_vlan_rx_add_vid(struct net_device *ndev, uint16_t vid) +{ + __bdx_vlan_rx_vid(ndev, vid, 1); +} + +/* + * bdx_vlan_rx_kill_vid - kernel hook for killing VLAN vid in hw filtering table + * @ndev network device + * @vid VLAN vid to kill + */ +static void bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid) +{ + __bdx_vlan_rx_vid(ndev, vid, 0); +} + +/* + * bdx_vlan_rx_register - kernel hook for adding VLAN group + * @ndev network device + * @grp VLAN group + */ +static void +bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp) +{ + struct bdx_priv *priv = ndev->priv; + + ENTER; + DBG("device='%s', group='%p'\n", ndev->name, grp); + priv->vlgrp = grp; + RET(); +} + +/** + * bdx_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + */ +static int bdx_change_mtu(struct net_device *ndev, int new_mtu) +{ + BDX_ASSERT(ndev == 0); + ENTER; + + if (new_mtu == ndev->mtu) + RET(0); + + /* enforce minimum frame size */ + if (new_mtu < ETH_ZLEN) { + ERR("%s: %s mtu %d is less then minimal %d\n", + BDX_DRV_NAME, ndev->name, new_mtu, ETH_ZLEN); + RET(-EINVAL); + } + + ndev->mtu = new_mtu; + if (netif_running(ndev)) { + bdx_close(ndev); + bdx_open(ndev); + } + RET(0); +} + +static void bdx_setmulti(struct net_device *ndev) +{ + struct bdx_priv *priv = ndev->priv; + + u32 rxf_val = + GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN; + int i; + + ENTER; + /* IMF - imperfect (hash) rx multicat filter */ + /* PMF - perfect rx multicat filter */ + + /* FIXME: RXE(OFF) */ + if (ndev->flags & IFF_PROMISC) { + rxf_val |= GMAC_RX_FILTER_PRM; + } else if (ndev->flags & IFF_ALLMULTI) { + /* set IMF to accept all multicast frmaes */ + for (i = 0; i < MAC_MCST_HASH_NUM; i++) + WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0); + } else if (ndev->mc_count) { + u8 hash; + struct dev_mc_list *mclist; + u32 reg, val; + + /* set IMF to deny all multicast frames */ + for (i = 0; i < MAC_MCST_HASH_NUM; i++) + WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, 0); + /* set PMF to deny all multicast frames */ + for (i = 0; i < MAC_MCST_NUM; i++) { + WRITE_REG(priv, regRX_MAC_MCST0 + i * 8, 0); + WRITE_REG(priv, regRX_MAC_MCST1 + i * 8, 0); + } + + /* use PMF to accept first MAC_MCST_NUM (15) addresses */ + /* TBD: sort addreses and write them in ascending order + * into RX_MAC_MCST regs. we skip this phase now and accept ALL + * multicast frames throu IMF */ + mclist = ndev->mc_list; + + /* accept the rest of addresses throu IMF */ + for (; mclist; mclist = mclist->next) { + hash = 0; + for (i = 0; i < ETH_ALEN; i++) + hash ^= mclist->dmi_addr[i]; + reg = regRX_MCST_HASH0 + ((hash >> 5) << 2); + val = READ_REG(priv, reg); + val |= (1 << (hash % 32)); + WRITE_REG(priv, reg, val); + } + + } else { + DBG("only own mac %d\n", ndev->mc_count); + rxf_val |= GMAC_RX_FILTER_AB; + } + WRITE_REG(priv, regGMAC_RXF_A, rxf_val); + /* enable RX */ + /* FIXME: RXE(ON) */ + RET(); +} + +static int bdx_set_mac(struct net_device *ndev, void *p) +{ + struct bdx_priv *priv = ndev->priv; + struct sockaddr *addr = p; + + ENTER; + /* + if (netif_running(dev)) + return -EBUSY + */ + memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + bdx_restore_mac(ndev, priv); + RET(0); +} + +static int bdx_read_mac(struct bdx_priv *priv) +{ + u16 macAddress[3], i; + ENTER; + + macAddress[2] = READ_REG(priv, regUNC_MAC0_A); + macAddress[2] = READ_REG(priv, regUNC_MAC0_A); + macAddress[1] = READ_REG(priv, regUNC_MAC1_A); + macAddress[1] = READ_REG(priv, regUNC_MAC1_A); + macAddress[0] = READ_REG(priv, regUNC_MAC2_A); + macAddress[0] = READ_REG(priv, regUNC_MAC2_A); + for (i = 0; i < 3; i++) { + priv->ndev->dev_addr[i * 2 + 1] = macAddress[i]; + priv->ndev->dev_addr[i * 2] = macAddress[i] >> 8; + } + RET(0); +} + +static u64 bdx_read_l2stat(struct bdx_priv *priv, int reg) +{ + u64 val; + + val = READ_REG(priv, reg); + val |= ((u64) READ_REG(priv, reg + 8)) << 32; + return val; +} + +/*Do the statistics-update work*/ +static void bdx_update_stats(struct bdx_priv *priv) +{ + struct bdx_stats *stats = &priv->hw_stats; + u64 *stats_vector = (u64 *) stats; + int i; + int addr; + + /*Fill HW structure */ + addr = 0x7200; + /*First 12 statistics - 0x7200 - 0x72B0 */ + for (i = 0; i < 12; i++) { + stats_vector[i] = bdx_read_l2stat(priv, addr); + addr += 0x10; + } + BDX_ASSERT(addr != 0x72C0); + /* 0x72C0-0x72E0 RSRV */ + addr = 0x72F0; + for (; i < 16; i++) { + stats_vector[i] = bdx_read_l2stat(priv, addr); + addr += 0x10; + } + BDX_ASSERT(addr != 0x7330); + /* 0x7330-0x7360 RSRV */ + addr = 0x7370; + for (; i < 19; i++) { + stats_vector[i] = bdx_read_l2stat(priv, addr); + addr += 0x10; + } + BDX_ASSERT(addr != 0x73A0); + /* 0x73A0-0x73B0 RSRV */ + addr = 0x73C0; + for (; i < 23; i++) { + stats_vector[i] = bdx_read_l2stat(priv, addr); + addr += 0x10; + } + BDX_ASSERT(addr != 0x7400); + BDX_ASSERT((sizeof(struct bdx_stats) / sizeof(u64)) != i); +} + +static struct net_device_stats *bdx_get_stats(struct net_device *ndev) +{ + struct bdx_priv *priv = ndev->priv; + struct net_device_stats *net_stat = &priv->net_stats; + return net_stat; +} + +static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len, + u16 rxd_vlan); +static void print_rxfd(struct rxf_desc *rxfd); + +/************************************************************************* + * Rx DB * + *************************************************************************/ + +static void bdx_rxdb_destroy(struct rxdb *db) +{ + if (db) + vfree(db); +} + +static struct rxdb *bdx_rxdb_create(int nelem) +{ + struct rxdb *db; + int i; + + db = vmalloc(sizeof(struct rxdb) + + (nelem * sizeof(int)) + + (nelem * sizeof(struct rx_map))); + if (likely(db != NULL)) { + db->stack = (int *)(db + 1); + db->elems = (void *)(db->stack + nelem); + db->nelem = nelem; + db->top = nelem; + for (i = 0; i < nelem; i++) + db->stack[i] = nelem - i - 1; /* to make first allocs + close to db struct*/ + } + + return db; +} + +static inline int bdx_rxdb_alloc_elem(struct rxdb *db) +{ + BDX_ASSERT(db->top <= 0); + return db->stack[--(db->top)]; +} + +static inline void *bdx_rxdb_addr_elem(struct rxdb *db, int n) +{ + BDX_ASSERT((n < 0) || (n >= db->nelem)); + return db->elems + n; +} + +static inline int bdx_rxdb_available(struct rxdb *db) +{ + return db->top; +} + +static inline void bdx_rxdb_free_elem(struct rxdb *db, int n) +{ + BDX_ASSERT((n >= db->nelem) || (n < 0)); + db->stack[(db->top)++] = n; +} + +/************************************************************************* + * Rx Init * + *************************************************************************/ + +/* bdx_rx_init - initialize RX all related HW and SW resources + * @priv - NIC private structure + * + * Returns 0 on success, negative value on failure + * + * It creates rxf and rxd fifos, update relevant HW registers, preallocate + * skb for rx. It assumes that Rx is desabled in HW + * funcs are grouped for better cache usage + * + * RxD fifo is smaller then RxF fifo by design. Upon high load, RxD will be + * filled and packets will be dropped by nic without getting into host or + * cousing interrupt. Anyway, in that condition, host has no chance to proccess + * all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles + */ + +/* TBD: ensure proper packet size */ + +static int bdx_rx_init(struct bdx_priv *priv) +{ + ENTER; + BDX_ASSERT(priv == 0); + if (bdx_fifo_init(priv, &priv->rxd_fifo0.m, priv->rxd_size, + regRXD_CFG0_0, regRXD_CFG1_0, + regRXD_RPTR_0, regRXD_WPTR_0)) + goto err_mem; + if (bdx_fifo_init(priv, &priv->rxf_fifo0.m, priv->rxf_size, + regRXF_CFG0_0, regRXF_CFG1_0, + regRXF_RPTR_0, regRXF_WPTR_0)) + goto err_mem; + if (! + (priv->rxdb = + bdx_rxdb_create(priv->rxf_fifo0.m.memsz / + sizeof(struct rxf_desc)))) + goto err_mem; + + priv->rxf_fifo0.m.pktsz = priv->ndev->mtu + VLAN_ETH_HLEN; + return 0; + +err_mem: + ERR("%s: %s: Rx init failed\n", BDX_DRV_NAME, priv->ndev->name); + return -ENOMEM; +} + +/* bdx_rx_free_skbs - frees and unmaps all skbs allocated for the fifo + * @priv - NIC private structure + * @f - RXF fifo + */ +static void bdx_rx_free_skbs(struct bdx_priv *priv, struct rxf_fifo *f) +{ + struct rx_map *dm; + struct rxdb *db = priv->rxdb; + u16 i; + + ENTER; + DBG("total=%d free=%d busy=%d\n", db->nelem, bdx_rxdb_available(db), + db->nelem - bdx_rxdb_available(db)); + while (bdx_rxdb_available(db) > 0) { + i = bdx_rxdb_alloc_elem(db); + dm = bdx_rxdb_addr_elem(db, i); + dm->dma = 0; + } + for (i = 0; i < db->nelem; i++) { + dm = bdx_rxdb_addr_elem(db, i); + if (dm->dma) { + pci_unmap_single(priv->pdev, + dm->dma, f->m.pktsz, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(dm->skb); + } + } +} + +/* bdx_rx_free - release all Rx resources + * @priv - NIC private structure + * It assumes that Rx is desabled in HW + */ +static void bdx_rx_free(struct bdx_priv *priv) +{ + ENTER; + if (priv->rxdb) { + bdx_rx_free_skbs(priv, &priv->rxf_fifo0); + bdx_rxdb_destroy(priv->rxdb); + priv->rxdb = NULL; + } + bdx_fifo_free(priv, &priv->rxf_fifo0.m); + bdx_fifo_free(priv, &priv->rxd_fifo0.m); + + RET(); +} + +/************************************************************************* + * Rx Engine * + *************************************************************************/ + +/* bdx_rx_alloc_skbs - fill rxf fifo with new skbs + * @priv - nic's private structure + * @f - RXF fifo that needs skbs + * It allocates skbs, build rxf descs and push it (rxf descr) into rxf fifo. + * skb's virtual and physical addresses are stored in skb db. + * To calculate free space, func uses cached values of RPTR and WPTR + * When needed, it also updates RPTR and WPTR. + */ + +/* TBD: do not update WPTR if no desc were written */ + +static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f) +{ + struct sk_buff *skb; + struct rxf_desc *rxfd; + struct rx_map *dm; + int dno, delta, idx; + struct rxdb *db = priv->rxdb; + + ENTER; + dno = bdx_rxdb_available(db) - 1; + while (dno > 0) { + if (!(skb = dev_alloc_skb(f->m.pktsz + NET_IP_ALIGN))) { + ERR("NO MEM: dev_alloc_skb failed\n"); + break; + } + skb->dev = priv->ndev; + skb_reserve(skb, NET_IP_ALIGN); + + idx = bdx_rxdb_alloc_elem(db); + dm = bdx_rxdb_addr_elem(db, idx); + dm->dma = pci_map_single(priv->pdev, + skb->data, f->m.pktsz, + PCI_DMA_FROMDEVICE); + dm->skb = skb; + rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr); + rxfd->info = CPU_CHIP_SWAP32(0x10003); /* INFO=1 BC=3 */ + rxfd->va_lo = idx; + rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma)); + rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma)); + rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz); + print_rxfd(rxfd); + + f->m.wptr += sizeof(struct rxf_desc); + delta = f->m.wptr - f->m.memsz; + if (unlikely(delta >= 0)) { + f->m.wptr = delta; + if (delta > 0) { + memcpy(f->m.va, f->m.va + f->m.memsz, delta); + DBG("wrapped descriptor\n"); + } + } + dno--; + } + /*TBD: to do - delayed rxf wptr like in txd */ + WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); + RET(); +} + +static inline void +NETIF_RX_MUX(struct bdx_priv *priv, u32 rxd_val1, u16 rxd_vlan, + struct sk_buff *skb) +{ + ENTER; + DBG("rxdd->flags.bits.vtag=%d vlgrp=%p\n", GET_RXD_VTAG(rxd_val1), + priv->vlgrp); + if (priv->vlgrp && GET_RXD_VTAG(rxd_val1)) { + DBG("%s: vlan rcv vlan '%x' vtag '%x', device name '%s'\n", + priv->ndev->name, + GET_RXD_VLAN_ID(rxd_vlan), + GET_RXD_VTAG(rxd_val1), + vlan_group_get_device(priv->vlgrp, + GET_RXD_VLAN_ID(rxd_vlan))->name); + /* NAPI variant of receive functions */ + vlan_hwaccel_receive_skb(skb, priv->vlgrp, + GET_RXD_VLAN_ID(rxd_vlan)); + } else { + netif_receive_skb(skb); + } +} + +static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd) +{ + struct rxf_desc *rxfd; + struct rx_map *dm; + struct rxf_fifo *f; + struct rxdb *db; + struct sk_buff *skb; + int delta; + + ENTER; + DBG("priv=%p rxdd=%p\n", priv, rxdd); + f = &priv->rxf_fifo0; + db = priv->rxdb; + DBG("db=%p f=%p\n", db, f); + dm = bdx_rxdb_addr_elem(db, rxdd->va_lo); + DBG("dm=%p\n", dm); + skb = dm->skb; + rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr); + rxfd->info = CPU_CHIP_SWAP32(0x10003); /* INFO=1 BC=3 */ + rxfd->va_lo = rxdd->va_lo; + rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma)); + rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma)); + rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz); + print_rxfd(rxfd); + + f->m.wptr += sizeof(struct rxf_desc); + delta = f->m.wptr - f->m.memsz; + if (unlikely(delta >= 0)) { + f->m.wptr = delta; + if (delta > 0) { + memcpy(f->m.va, f->m.va + f->m.memsz, delta); + DBG("wrapped descriptor\n"); + } + } + RET(); +} + +/* bdx_rx_receive - recieves full packets from RXD fifo and pass them to OS + * NOTE: a special treatment is given to non-continous descriptors + * that start near the end, wraps around and continue at the beginning. a second + * part is copied right after the first, and then descriptor is interpreted as + * normal. fifo has an extra space to allow such operations + * @priv - nic's private structure + * @f - RXF fifo that needs skbs + */ + +/* TBD: replace memcpy func call by explicite inline asm */ + +static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget) +{ + struct sk_buff *skb, *skb2; + struct rxd_desc *rxdd; + struct rx_map *dm; + struct rxf_fifo *rxf_fifo; + int tmp_len, size; + int done = 0; + int max_done = BDX_MAX_RX_DONE; + struct rxdb *db = NULL; + /* Unmarshalled descriptor - copy of descriptor in host order */ + u32 rxd_val1; + u16 len; + u16 rxd_vlan; + + ENTER; + max_done = budget; + + priv->ndev->last_rx = jiffies; + f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_WR_PTR; + + size = f->m.wptr - f->m.rptr; + if (size < 0) + size = f->m.memsz + size; /* size is negative :-) */ + + while (size > 0) { + + rxdd = (struct rxd_desc *)(f->m.va + f->m.rptr); + rxd_val1 = CPU_CHIP_SWAP32(rxdd->rxd_val1); + + len = CPU_CHIP_SWAP16(rxdd->len); + + rxd_vlan = CPU_CHIP_SWAP16(rxdd->rxd_vlan); + + print_rxdd(rxdd, rxd_val1, len, rxd_vlan); + + tmp_len = GET_RXD_BC(rxd_val1) << 3; + BDX_ASSERT(tmp_len <= 0); + size -= tmp_len; + if (size < 0) /* test for partially arrived descriptor */ + break; + + f->m.rptr += tmp_len; + + tmp_len = f->m.rptr - f->m.memsz; + if (unlikely(tmp_len >= 0)) { + f->m.rptr = tmp_len; + if (tmp_len > 0) { + DBG("wrapped desc rptr=%d tmp_len=%d\n", + f->m.rptr, tmp_len); + memcpy(f->m.va + f->m.memsz, f->m.va, tmp_len); + } + } + + if (unlikely(GET_RXD_ERR(rxd_val1))) { + DBG("rxd_err = 0x%x\n", GET_RXD_ERR(rxd_val1)); + priv->net_stats.rx_errors++; + bdx_recycle_skb(priv, rxdd); + continue; + } + + rxf_fifo = &priv->rxf_fifo0; + db = priv->rxdb; + dm = bdx_rxdb_addr_elem(db, rxdd->va_lo); + skb = dm->skb; + + if (len < BDX_COPYBREAK && + (skb2 = dev_alloc_skb(len + NET_IP_ALIGN))) { + skb_reserve(skb2, NET_IP_ALIGN); + /*skb_put(skb2, len); */ + pci_dma_sync_single_for_cpu(priv->pdev, + dm->dma, rxf_fifo->m.pktsz, + PCI_DMA_FROMDEVICE); + memcpy(skb2->data, skb->data, len); + bdx_recycle_skb(priv, rxdd); + skb = skb2; + } else { + pci_unmap_single(priv->pdev, + dm->dma, rxf_fifo->m.pktsz, + PCI_DMA_FROMDEVICE); + bdx_rxdb_free_elem(db, rxdd->va_lo); + } + + priv->net_stats.rx_bytes += len; + + skb_put(skb, len); + skb->dev = priv->ndev; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->protocol = eth_type_trans(skb, priv->ndev); + + /* Non-IP packets aren't checksum-offloaded */ + if (GET_RXD_PKT_ID(rxd_val1) == 0) + skb->ip_summed = CHECKSUM_NONE; + + NETIF_RX_MUX(priv, rxd_val1, rxd_vlan, skb); + + if (++done >= max_done) + break; + } + + priv->net_stats.rx_packets += done; + + /* FIXME: do smth to minimize pci accesses */ + WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR); + + bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0); + + RET(done); +} + +/************************************************************************* + * Debug / Temprorary Code * + *************************************************************************/ +static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len, + u16 rxd_vlan) +{ + DBG("ERROR: rxdd bc %d rxfq %d to %d type %d err %d rxp %d " + "pkt_id %d vtag %d len %d vlan_id %d cfi %d prio %d " + "va_lo %d va_hi %d\n", + GET_RXD_BC(rxd_val1), GET_RXD_RXFQ(rxd_val1), GET_RXD_TO(rxd_val1), + GET_RXD_TYPE(rxd_val1), GET_RXD_ERR(rxd_val1), + GET_RXD_RXP(rxd_val1), GET_RXD_PKT_ID(rxd_val1), + GET_RXD_VTAG(rxd_val1), len, GET_RXD_VLAN_ID(rxd_vlan), + GET_RXD_CFI(rxd_vlan), GET_RXD_PRIO(rxd_vlan), rxdd->va_lo, + rxdd->va_hi); +} + +static void print_rxfd(struct rxf_desc *rxfd) +{ + DBG("=== RxF desc CHIP ORDER/ENDIANESS =============\n" + "info 0x%x va_lo %u pa_lo 0x%x pa_hi 0x%x len 0x%x\n", + rxfd->info, rxfd->va_lo, rxfd->pa_lo, rxfd->pa_hi, rxfd->len); +} + +/* + * TX HW/SW interaction overview + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * There are 2 types of TX communication channels betwean driver and NIC. + * 1) TX Free Fifo - TXF - holds ack descriptors for sent packets + * 2) TX Data Fifo - TXD - holds descriptors of full buffers. + * + * Currently NIC supports TSO, checksuming and gather DMA + * UFO and IP fragmentation is on the way + * + * RX SW Data Structures + * ~~~~~~~~~~~~~~~~~~~~~ + * txdb - used to keep track of all skbs owned by SW and their dma addresses. + * For TX case, ownership lasts from geting packet via hard_xmit and until HW + * acknowledges sent by TXF descriptors. + * Implemented as cyclic buffer. + * fifo - keeps info about fifo's size and location, relevant HW registers, + * usage and skb db. Each RXD and RXF Fifo has its own fifo structure. + * Implemented as simple struct. + * + * TX SW Execution Flow + * ~~~~~~~~~~~~~~~~~~~~ + * OS calls driver's hard_xmit method with packet to sent. + * Driver creates DMA mappings, builds TXD descriptors and kicks HW + * by updating TXD WPTR. + * When packet is sent, HW write us TXF descriptor and SW frees original skb. + * To prevent TXD fifo overflow without reading HW registers every time, + * SW deploys "tx level" technique. + * Upon strart up, tx level is initialized to TXD fifo length. + * For every sent packet, SW gets its TXD descriptor sizei + * (from precalculated array) and substructs it from tx level. + * The size is also stored in txdb. When TXF ack arrives, SW fetch size of + * original TXD descriptor from txdb and adds it to tx level. + * When Tx level drops under some predefined treshhold, the driver + * stops the TX queue. When TX level rises above that level, + * the tx queue is enabled again. + * + * This technique avoids eccessive reading of RPTR and WPTR registers. + * As our benchmarks shows, it adds 1.5 Gbit/sec to NIS's throuput. + */ + +/************************************************************************* + * Tx DB * + *************************************************************************/ +static inline int bdx_tx_db_size(struct txdb *db) +{ + int taken = db->wptr - db->rptr; + if (taken < 0) + taken = db->size + 1 + taken; /* (size + 1) equals memsz */ + + return db->size - taken; +} + +/* __bdx_tx_ptr_next - helper function, increment read/write pointer + wrap + * @d - tx data base + * @ptr - read or write pointer + */ +static inline void __bdx_tx_db_ptr_next(struct txdb *db, struct tx_map **pptr) +{ + BDX_ASSERT(db == NULL || pptr == NULL); /* sanity */ + + BDX_ASSERT(*pptr != db->rptr && /* expect either read */ + *pptr != db->wptr); /* or write pointer */ + + BDX_ASSERT(*pptr < db->start || /* pointer has to be */ + *pptr >= db->end); /* in range */ + + ++*pptr; + if (unlikely(*pptr == db->end)) + *pptr = db->start; +} + +/* bdx_tx_db_inc_rptr - increment read pointer + * @d - tx data base + */ +static inline void bdx_tx_db_inc_rptr(struct txdb *db) +{ + BDX_ASSERT(db->rptr == db->wptr); /* can't read from empty db */ + __bdx_tx_db_ptr_next(db, &db->rptr); +} + +/* bdx_tx_db_inc_rptr - increment write pointer + * @d - tx data base + */ +static inline void bdx_tx_db_inc_wptr(struct txdb *db) +{ + __bdx_tx_db_ptr_next(db, &db->wptr); + BDX_ASSERT(db->rptr == db->wptr); /* we can not get empty db as + a result of write */ +} + +/* bdx_tx_db_init - creates and initializes tx db + * @d - tx data base + * @sz_type - size of tx fifo + * Returns 0 on success, error code otherwise + */ +static int bdx_tx_db_init(struct txdb *d, int sz_type) +{ + int memsz = FIFO_SIZE * (1 << (sz_type + 1)); + + d->start = vmalloc(memsz); + if (!d->start) + return -ENOMEM; + + /* + * In order to differentiate between db is empty and db is full + * states at least one element should always be empty in order to + * avoid rptr == wptr which means db is empty + */ + d->size = memsz / sizeof(struct tx_map) - 1; + d->end = d->start + d->size + 1; /* just after last element */ + + /* all dbs are created equally empty */ + d->rptr = d->start; + d->wptr = d->start; + + return 0; +} + +/* bdx_tx_db_close - closes tx db and frees all memory + * @d - tx data base + */ +static void bdx_tx_db_close(struct txdb *d) +{ + BDX_ASSERT(d == NULL); + + if (d->start) { + vfree(d->start); + d->start = NULL; + } +} + +/************************************************************************* + * Tx Engine * + *************************************************************************/ + +/* sizes of tx desc (including padding if needed) as function + * of skb's frag number */ +static struct { + u16 bytes; + u16 qwords; /* qword = 64 bit */ +} txd_sizes[MAX_SKB_FRAGS + 1]; + +/* txdb_map_skb - creates and stores dma mappings for skb's data blocks + * @priv - NIC private structure + * @skb - socket buffer to map + * + * It makes dma mappings for skb's data blocks and writes them to PBL of + * new tx descriptor. It also stores them in the tx db, so they could be + * unmaped after data was sent. It is reponsibility of a caller to make + * sure that there is enough space in the tx db. Last element holds pointer + * to skb itself and marked with zero length + */ +static inline void +bdx_tx_map_skb(struct bdx_priv *priv, struct sk_buff *skb, + struct txd_desc *txdd) +{ + struct txdb *db = &priv->txdb; + struct pbl *pbl = &txdd->pbl[0]; + int nr_frags = skb_shinfo(skb)->nr_frags; + int i; + + db->wptr->len = skb->len - skb->data_len; + db->wptr->addr.dma = pci_map_single(priv->pdev, skb->data, + db->wptr->len, PCI_DMA_TODEVICE); + pbl->len = CPU_CHIP_SWAP32(db->wptr->len); + pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma)); + pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma)); + DBG("=== pbl len: 0x%x ================\n", pbl->len); + DBG("=== pbl pa_lo: 0x%x ================\n", pbl->pa_lo); + DBG("=== pbl pa_hi: 0x%x ================\n", pbl->pa_hi); + bdx_tx_db_inc_wptr(db); + + for (i = 0; i < nr_frags; i++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[i]; + db->wptr->len = frag->size; + db->wptr->addr.dma = + pci_map_page(priv->pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + + pbl++; + pbl->len = CPU_CHIP_SWAP32(db->wptr->len); + pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma)); + pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma)); + bdx_tx_db_inc_wptr(db); + } + + /* add skb clean up info. */ + db->wptr->len = -txd_sizes[nr_frags].bytes; + db->wptr->addr.skb = skb; + bdx_tx_db_inc_wptr(db); +} + +/* init_txd_sizes - precalculate sizes of descriptors for skbs up to 16 frags + * number of frags is used as index to fetch correct descriptors size, + * instead of calculating it each time */ +static void __init init_txd_sizes(void) +{ + int i, lwords; + + /* 7 - is number of lwords in txd with one phys buffer + * 3 - is number of lwords used for every additional phys buffer */ + for (i = 0; i < MAX_SKB_FRAGS + 1; i++) { + lwords = 7 + (i * 3); + if (lwords & 1) + lwords++; /* pad it with 1 lword */ + txd_sizes[i].qwords = lwords >> 1; + txd_sizes[i].bytes = lwords << 2; + } +} + +/* bdx_tx_init - initialize all Tx related stuff. + * Namely, TXD and TXF fifos, database etc */ +static int bdx_tx_init(struct bdx_priv *priv) +{ + if (bdx_fifo_init(priv, &priv->txd_fifo0.m, priv->txd_size, + regTXD_CFG0_0, + regTXD_CFG1_0, regTXD_RPTR_0, regTXD_WPTR_0)) + goto err_mem; + if (bdx_fifo_init(priv, &priv->txf_fifo0.m, priv->txf_size, + regTXF_CFG0_0, + regTXF_CFG1_0, regTXF_RPTR_0, regTXF_WPTR_0)) + goto err_mem; + + /* The TX db has to keep mappings for all packets sent (on TxD) + * and not yet reclaimed (on TxF) */ + if (bdx_tx_db_init(&priv->txdb, max(priv->txd_size, priv->txf_size))) + goto err_mem; + + priv->tx_level = BDX_MAX_TX_LEVEL; +#ifdef BDX_DELAY_WPTR + priv->tx_update_mark = priv->tx_level - 1024; +#endif + return 0; + +err_mem: + ERR("tehuti: %s: Tx init failed\n", priv->ndev->name); + return -ENOMEM; +} + +/* + * bdx_tx_space - calculates avalable space in TX fifo + * @priv - NIC private structure + * Returns avaliable space in TX fifo in bytes + */ +static inline int bdx_tx_space(struct bdx_priv *priv) +{ + struct txd_fifo *f = &priv->txd_fifo0; + int fsize; + + f->m.rptr = READ_REG(priv, f->m.reg_RPTR) & TXF_WPTR_WR_PTR; + fsize = f->m.rptr - f->m.wptr; + if (fsize <= 0) + fsize = f->m.memsz + fsize; + return (fsize); +} + +/* bdx_tx_transmit - send packet to NIC + * @skb - packet to send + * ndev - network device assigned to NIC + * Return codes: + * o NETDEV_TX_OK everything ok. + * o NETDEV_TX_BUSY Cannot transmit packet, try later + * Usually a bug, means queue start/stop flow control is broken in + * 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) +{ + struct bdx_priv *priv = ndev->priv; + struct txd_fifo *f = &priv->txd_fifo0; + int txd_checksum = 7; /* full checksum */ + int txd_lgsnd = 0; + int txd_vlan_id = 0; + int txd_vtag = 0; + int txd_mss = 0; + + int nr_frags = skb_shinfo(skb)->nr_frags; + struct txd_desc *txdd; + int len; + unsigned long flags; + + ENTER; + local_irq_save(flags); + if (!spin_trylock(&priv->tx_lock)) { + local_irq_restore(flags); + DBG("%s[%s]: TX locked, returning NETDEV_TX_LOCKED\n", + BDX_DRV_NAME, ndev->name); + return NETDEV_TX_LOCKED; + } + + /* build tx descriptor */ + BDX_ASSERT(f->m.wptr >= f->m.memsz); /* started with valid wptr */ + txdd = (struct txd_desc *)(f->m.va + f->m.wptr); + if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) + txd_checksum = 0; + + if (skb_shinfo(skb)->gso_size) { + txd_mss = skb_shinfo(skb)->gso_size; + txd_lgsnd = 1; + DBG("skb %p skb len %d gso size = %d\n", skb, skb->len, + txd_mss); + } + + if (vlan_tx_tag_present(skb)) { + /*Cut VLAN ID to 12 bits */ + txd_vlan_id = vlan_tx_tag_get(skb) & BITS_MASK(12); + txd_vtag = 1; + } + + txdd->length = CPU_CHIP_SWAP16(skb->len); + txdd->mss = CPU_CHIP_SWAP16(txd_mss); + txdd->txd_val1 = + CPU_CHIP_SWAP32(TXD_W1_VAL + (txd_sizes[nr_frags].qwords, txd_checksum, txd_vtag, + txd_lgsnd, txd_vlan_id)); + DBG("=== TxD desc =====================\n"); + DBG("=== w1: 0x%x ================\n", txdd->txd_val1); + DBG("=== w2: mss 0x%x len 0x%x\n", txdd->mss, txdd->length); + + bdx_tx_map_skb(priv, skb, txdd); + + /* increment TXD write pointer. In case of + fifo wrapping copy reminder of the descriptor + to the beginning */ + f->m.wptr += txd_sizes[nr_frags].bytes; + len = f->m.wptr - f->m.memsz; + if (unlikely(len >= 0)) { + f->m.wptr = len; + if (len > 0) { + BDX_ASSERT(len > f->m.memsz); + memcpy(f->m.va, f->m.va + f->m.memsz, len); + } + } + BDX_ASSERT(f->m.wptr >= f->m.memsz); /* finished with valid wptr */ + + priv->tx_level -= txd_sizes[nr_frags].bytes; + BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL); +#ifdef BDX_DELAY_WPTR + if (priv->tx_level > priv->tx_update_mark) { + /* Force memory writes to complete before letting h/w + know there are new descriptors to fetch. + (might be needed on platforms like IA64) + wmb(); */ + WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); + } else { + if (priv->tx_noupd++ > BDX_NO_UPD_PACKETS) { + priv->tx_noupd = 0; + WRITE_REG(priv, f->m.reg_WPTR, + f->m.wptr & TXF_WPTR_WR_PTR); + } + } +#else + /* Force memory writes to complete before letting h/w + know there are new descriptors to fetch. + (might be needed on platforms like IA64) + wmb(); */ + WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); + +#endif + ndev->trans_start = jiffies; + + priv->net_stats.tx_packets++; + priv->net_stats.tx_bytes += skb->len; + + if (priv->tx_level < BDX_MIN_TX_LEVEL) { + DBG("%s: %s: TX Q STOP level %d\n", + BDX_DRV_NAME, ndev->name, priv->tx_level); + netif_stop_queue(ndev); + } + + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_OK; +} + +/* bdx_tx_cleanup - clean TXF fifo, run in the context of IRQ. + * @priv - bdx adapter + * It scans TXF fifo for descriptors, frees DMA mappings and reports to OS + * that those packets were sent + */ +static void bdx_tx_cleanup(struct bdx_priv *priv) +{ + struct txf_fifo *f = &priv->txf_fifo0; + struct txdb *db = &priv->txdb; + int tx_level = 0; + + ENTER; + f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_MASK; + BDX_ASSERT(f->m.rptr >= f->m.memsz); /* started with valid rptr */ + + while (f->m.wptr != f->m.rptr) { + f->m.rptr += BDX_TXF_DESC_SZ; + f->m.rptr &= f->m.size_mask; + + /* unmap all the fragments */ + /* first has to come tx_maps containing dma */ + BDX_ASSERT(db->rptr->len == 0); + do { + BDX_ASSERT(db->rptr->addr.dma == 0); + pci_unmap_page(priv->pdev, db->rptr->addr.dma, + db->rptr->len, PCI_DMA_TODEVICE); + bdx_tx_db_inc_rptr(db); + } while (db->rptr->len > 0); + tx_level -= db->rptr->len; /* '-' koz len is negative */ + + /* now should come skb pointer - free it */ + BDX_ASSERT(db->rptr->addr.skb == 0); + dev_kfree_skb_irq(db->rptr->addr.skb); + bdx_tx_db_inc_rptr(db); + } + + /* let h/w know which TXF descriptors were cleaned */ + BDX_ASSERT((f->m.wptr & TXF_WPTR_WR_PTR) >= f->m.memsz); + WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR); + + /* We reclaimed resources, so in case the Q is stopped by xmit callback, + * we resume the transmition and use tx_lock to synchronize with xmit.*/ + spin_lock(&priv->tx_lock); + priv->tx_level += tx_level; + BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL); +#ifdef BDX_DELAY_WPTR + if (priv->tx_noupd) { + priv->tx_noupd = 0; + WRITE_REG(priv, priv->txd_fifo0.m.reg_WPTR, + priv->txd_fifo0.m.wptr & TXF_WPTR_WR_PTR); + } +#endif + + if (unlikely(netif_queue_stopped(priv->ndev) + && netif_carrier_ok(priv->ndev) + && (priv->tx_level >= BDX_MIN_TX_LEVEL))) { + DBG("%s: %s: TX Q WAKE level %d\n", + BDX_DRV_NAME, priv->ndev->name, priv->tx_level); + netif_wake_queue(priv->ndev); + } + spin_unlock(&priv->tx_lock); +} + +/* bdx_tx_free_skbs - frees all skbs from TXD fifo. + * It gets called when OS stops this dev, eg upon "ifconfig down" or rmmod + */ +static void bdx_tx_free_skbs(struct bdx_priv *priv) +{ + struct txdb *db = &priv->txdb; + + ENTER; + while (db->rptr != db->wptr) { + if (likely(db->rptr->len)) + pci_unmap_page(priv->pdev, db->rptr->addr.dma, + db->rptr->len, PCI_DMA_TODEVICE); + else + dev_kfree_skb(db->rptr->addr.skb); + bdx_tx_db_inc_rptr(db); + } + RET(); +} + +/* bdx_tx_free - frees all Tx resources */ +static void bdx_tx_free(struct bdx_priv *priv) +{ + ENTER; + bdx_tx_free_skbs(priv); + bdx_fifo_free(priv, &priv->txd_fifo0.m); + bdx_fifo_free(priv, &priv->txf_fifo0.m); + bdx_tx_db_close(&priv->txdb); +} + +/* bdx_tx_push_desc - push descriptor to TxD fifo + * @priv - NIC private structure + * @data - desc's data + * @size - desc's size + * + * Pushes desc to TxD fifo and overlaps it if needed. + * NOTE: this func does not check for available space. this is responsibility + * of the caller. Neither does it check that data size is smaller then + * fifo size. + */ +static void bdx_tx_push_desc(struct bdx_priv *priv, void *data, int size) +{ + struct txd_fifo *f = &priv->txd_fifo0; + int i = f->m.memsz - f->m.wptr; + + if (size == 0) + return; + + if (i > size) { + memcpy(f->m.va + f->m.wptr, data, size); + f->m.wptr += size; + } else { + memcpy(f->m.va + f->m.wptr, data, i); + f->m.wptr = size - i; + memcpy(f->m.va, data + i, f->m.wptr); + } + WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); +} + +/* bdx_tx_push_desc_safe - push descriptor to TxD fifo in a safe way + * @priv - NIC private structure + * @data - desc's data + * @size - desc's size + * + * NOTE: this func does check for available space and, if neccessary, waits for + * NIC to read existing data before writing new one. + */ +static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size) +{ + int timer = 0; + ENTER; + + while (size > 0) { + /* we substruct 8 because when fifo is full rptr == wptr + which also means that fifo is empty, we can understand + the difference, but could hw do the same ??? :) */ + int avail = bdx_tx_space(priv) - 8; + if (avail <= 0) { + if (timer++ > 300) { /* prevent endless loop */ + DBG("timeout while writing desc to TxD fifo\n"); + break; + } + udelay(50); /* give hw a chance to clean fifo */ + continue; + } + avail = MIN(avail, size); + DBG("about to push %d bytes starting %p size %d\n", avail, + data, size); + bdx_tx_push_desc(priv, data, avail); + size -= avail; + data += avail; + } + RET(); +} + +/** + * bdx_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in bdx_pci_tbl + * + * Returns 0 on success, negative on failure + * + * bdx_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + * + * functions and their order used as explained in + * /usr/src/linux/Documentation/DMA-{API,mapping}.txt + * + */ + +/* TBD: netif_msg should be checked and implemented. I disable it for now */ +static int __devinit +bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *ndev; + struct bdx_priv *priv; + int err, pci_using_dac, port; + unsigned long pciaddr; + u32 regionSize; + struct pci_nic *nic; + + ENTER; + + nic = vmalloc(sizeof(*nic)); + if (!nic) + RET(-ENOMEM); + + /************** pci *****************/ + if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */ + RET(err); /* it's not a problem though */ + + if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && + !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { + pci_using_dac = 1; + } else { + if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || + (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { + printk(KERN_ERR "tehuti: No usable DMA configuration" + ", aborting\n"); + goto err_dma; + } + pci_using_dac = 0; + } + + if ((err = pci_request_regions(pdev, BDX_DRV_NAME))) + goto err_dma; + + pci_set_master(pdev); + + pciaddr = pci_resource_start(pdev, 0); + if (!pciaddr) { + err = -EIO; + ERR("tehuti: no MMIO resource\n"); + goto err_out_res; + } + if ((regionSize = pci_resource_len(pdev, 0)) < BDX_REGS_SIZE) { + err = -EIO; + ERR("tehuti: MMIO resource (%x) too small\n", regionSize); + goto err_out_res; + } + + nic->regs = ioremap(pciaddr, regionSize); + if (!nic->regs) { + err = -EIO; + ERR("tehuti: ioremap failed\n"); + goto err_out_res; + } + + if (pdev->irq < 2) { + err = -EIO; + ERR("tehuti: invalid irq (%d)\n", pdev->irq); + goto err_out_iomap; + } + pci_set_drvdata(pdev, nic); + + if (pdev->device == 0x3014) + nic->port_num = 2; + else + nic->port_num = 1; + + print_hw_id(pdev); + + bdx_hw_reset_direct(nic->regs); + + nic->irq_type = IRQ_INTX; +#ifdef BDX_MSI + if ((readl(nic->regs + FPGA_VER) & 0xFFF) >= 378) { + if ((err = pci_enable_msi(pdev))) + ERR("Tehuti: Can't eneble msi. error is %d\n", err); + else + nic->irq_type = IRQ_MSI; + } else + DBG("HW does not support MSI\n"); +#endif + + /************** netdev **************/ + for (port = 0; port < nic->port_num; port++) { + if (!(ndev = alloc_etherdev(sizeof(struct bdx_priv)))) { + err = -ENOMEM; + printk(KERN_ERR "tehuti: alloc_etherdev failed\n"); + goto err_out_iomap; + } + + ndev->open = bdx_open; + ndev->stop = bdx_close; + ndev->hard_start_xmit = bdx_tx_transmit; + ndev->do_ioctl = bdx_ioctl; + ndev->set_multicast_list = bdx_setmulti; + ndev->get_stats = bdx_get_stats; + ndev->change_mtu = bdx_change_mtu; + ndev->set_mac_address = bdx_set_mac; + ndev->tx_queue_len = BDX_NDEV_TXQ_LEN; + ndev->vlan_rx_register = bdx_vlan_rx_register; + ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid; + ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid; + + bdx_ethtool_ops(ndev); /* ethtool interface */ + + /* these fields are used for info purposes only + * so we can have them same for all ports of the board */ + ndev->if_port = port; + ndev->base_addr = pciaddr; + ndev->mem_start = pciaddr; + ndev->mem_end = pciaddr + regionSize; + ndev->irq = pdev->irq; + ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO + | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER + /*| NETIF_F_FRAGLIST */ + ; + + if (pci_using_dac) + ndev->features |= NETIF_F_HIGHDMA; + + /************** priv ****************/ + priv = nic->priv[port] = ndev->priv; + + memset(priv, 0, sizeof(struct bdx_priv)); + priv->pBdxRegs = nic->regs + port * 0x8000; + priv->port = port; + priv->pdev = pdev; + priv->ndev = ndev; + priv->nic = nic; + priv->msg_enable = BDX_DEF_MSG_ENABLE; + + netif_napi_add(ndev, &priv->napi, bdx_poll, 64); + + if ((readl(nic->regs + FPGA_VER) & 0xFFF) == 308) { + DBG("HW statistics not supported\n"); + priv->stats_flag = 0; + } else { + priv->stats_flag = 1; + } + + /* Initialize fifo sizes. */ + priv->txd_size = 2; + priv->txf_size = 2; + priv->rxd_size = 2; + priv->rxf_size = 3; + + /* Initialize the initial coalescing registers. */ + priv->rdintcm = INT_REG_VAL(0x20, 1, 4, 12); + priv->tdintcm = INT_REG_VAL(0x20, 1, 0, 12); + + /* ndev->xmit_lock spinlock is not used. + * Private priv->tx_lock is used for synchronization + * between transmit and TX irq cleanup. In addition + * set multicast list callback has to use priv->tx_lock. + */ +#ifdef BDX_LLTX + ndev->features |= NETIF_F_LLTX; +#endif + spin_lock_init(&priv->tx_lock); + + /*bdx_hw_reset(priv); */ + if (bdx_read_mac(priv)) { + printk(KERN_ERR "tehuti: load MAC address failed\n"); + goto err_out_iomap; + } + SET_NETDEV_DEV(ndev, &pdev->dev); + if ((err = register_netdev(ndev))) { + printk(KERN_ERR "tehuti: register_netdev failed\n"); + goto err_out_free; + } + netif_carrier_off(ndev); + netif_stop_queue(ndev); + + print_eth_id(ndev); + } + RET(0); + +err_out_free: + free_netdev(ndev); +err_out_iomap: + iounmap(nic->regs); +err_out_res: + pci_release_regions(pdev); +err_dma: + pci_disable_device(pdev); + vfree(nic); + + RET(err); +} + +/****************** Ethtool interface *********************/ +/* get strings for tests */ +static const char + bdx_test_names[][ETH_GSTRING_LEN] = { + "No tests defined" +}; + +/* get strings for statistics counters */ +static const char + bdx_stat_names[][ETH_GSTRING_LEN] = { + "InUCast", /* 0x7200 */ + "InMCast", /* 0x7210 */ + "InBCast", /* 0x7220 */ + "InPkts", /* 0x7230 */ + "InErrors", /* 0x7240 */ + "InDropped", /* 0x7250 */ + "FrameTooLong", /* 0x7260 */ + "FrameSequenceErrors", /* 0x7270 */ + "InVLAN", /* 0x7280 */ + "InDroppedDFE", /* 0x7290 */ + "InDroppedIntFull", /* 0x72A0 */ + "InFrameAlignErrors", /* 0x72B0 */ + + /* 0x72C0-0x72E0 RSRV */ + + "OutUCast", /* 0x72F0 */ + "OutMCast", /* 0x7300 */ + "OutBCast", /* 0x7310 */ + "OutPkts", /* 0x7320 */ + + /* 0x7330-0x7360 RSRV */ + + "OutVLAN", /* 0x7370 */ + "InUCastOctects", /* 0x7380 */ + "OutUCastOctects", /* 0x7390 */ + + /* 0x73A0-0x73B0 RSRV */ + + "InBCastOctects", /* 0x73C0 */ + "OutBCastOctects", /* 0x73D0 */ + "InOctects", /* 0x73E0 */ + "OutOctects", /* 0x73F0 */ +}; + +/* + * bdx_get_settings - get device-specific settings + * @netdev + * @ecmd + */ +static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + u32 rdintcm; + u32 tdintcm; + struct bdx_priv *priv = netdev->priv; + + rdintcm = priv->rdintcm; + tdintcm = priv->tdintcm; + + ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; /* what does it mean? */ + ecmd->autoneg = AUTONEG_DISABLE; + + /* PCK_TH measures in multiples of FIFO bytes + We translate to packets */ + ecmd->maxtxpkt = + ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ); + ecmd->maxrxpkt = + ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc)); + + return 0; +} + +/* + * bdx_get_drvinfo - report driver information + * @netdev + * @drvinfo + */ +static void +bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) +{ + struct bdx_priv *priv = netdev->priv; + + strncat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver)); + strncat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version)); + strncat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strncat(drvinfo->bus_info, pci_name(priv->pdev), + sizeof(drvinfo->bus_info)); + + drvinfo->n_stats = ((priv->stats_flag) ? + (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) : 0); + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +/* + * bdx_get_rx_csum - report whether receive checksums are turned on or off + * @netdev + */ +static u32 bdx_get_rx_csum(struct net_device *netdev) +{ + return 1; /* always on */ +} + +/* + * bdx_get_tx_csum - report whether transmit checksums are turned on or off + * @netdev + */ +static u32 bdx_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_IP_CSUM) != 0; +} + +/* + * bdx_get_coalesce - get interrupt coalescing parameters + * @netdev + * @ecoal + */ +static int +bdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) +{ + u32 rdintcm; + u32 tdintcm; + struct bdx_priv *priv = netdev->priv; + + rdintcm = priv->rdintcm; + tdintcm = priv->tdintcm; + + /* PCK_TH measures in multiples of FIFO bytes + We translate to packets */ + ecoal->rx_coalesce_usecs = GET_INT_COAL(rdintcm) * INT_COAL_MULT; + ecoal->rx_max_coalesced_frames = + ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc)); + + ecoal->tx_coalesce_usecs = GET_INT_COAL(tdintcm) * INT_COAL_MULT; + ecoal->tx_max_coalesced_frames = + ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ); + + /* adaptive parameters ignored */ + return 0; +} + +/* + * bdx_set_coalesce - set interrupt coalescing parameters + * @netdev + * @ecoal + */ +static int +bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) +{ + u32 rdintcm; + u32 tdintcm; + struct bdx_priv *priv = netdev->priv; + int rx_coal; + int tx_coal; + int rx_max_coal; + int tx_max_coal; + + /* Check for valid input */ + rx_coal = ecoal->rx_coalesce_usecs / INT_COAL_MULT; + tx_coal = ecoal->tx_coalesce_usecs / INT_COAL_MULT; + rx_max_coal = ecoal->rx_max_coalesced_frames; + tx_max_coal = ecoal->tx_max_coalesced_frames; + + /* Translate from packets to multiples of FIFO bytes */ + rx_max_coal = + (((rx_max_coal * sizeof(struct rxf_desc)) + PCK_TH_MULT - 1) + / PCK_TH_MULT); + tx_max_coal = + (((tx_max_coal * BDX_TXF_DESC_SZ) + PCK_TH_MULT - 1) + / PCK_TH_MULT); + + if ((rx_coal > 0x7FFF) || (tx_coal > 0x7FFF) + || (rx_max_coal > 0xF) || (tx_max_coal > 0xF)) + return -EINVAL; + + rdintcm = INT_REG_VAL(rx_coal, GET_INT_COAL_RC(priv->rdintcm), + GET_RXF_TH(priv->rdintcm), rx_max_coal); + tdintcm = INT_REG_VAL(tx_coal, GET_INT_COAL_RC(priv->tdintcm), 0, + tx_max_coal); + + priv->rdintcm = rdintcm; + priv->tdintcm = tdintcm; + + WRITE_REG(priv, regRDINTCM0, rdintcm); + WRITE_REG(priv, regTDINTCM0, tdintcm); + + return 0; +} + +/* Convert RX fifo size to number of pending packets */ +static inline int bdx_rx_fifo_size_to_packets(int rx_size) +{ + return ((FIFO_SIZE * (1 << rx_size)) / sizeof(struct rxf_desc)); +} + +/* Convert TX fifo size to number of pending packets */ +static inline int bdx_tx_fifo_size_to_packets(int tx_size) +{ + return ((FIFO_SIZE * (1 << tx_size)) / BDX_TXF_DESC_SZ); +} + +/* + * bdx_get_ringparam - report ring sizes + * @netdev + * @ring + */ +static void +bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) +{ + struct bdx_priv *priv = netdev->priv; + + /*max_pending - the maximum-sized FIFO we allow */ + ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3); + ring->tx_max_pending = bdx_tx_fifo_size_to_packets(3); + ring->rx_pending = bdx_rx_fifo_size_to_packets(priv->rxf_size); + ring->tx_pending = bdx_tx_fifo_size_to_packets(priv->txd_size); +} + +/* + * bdx_set_ringparam - set ring sizes + * @netdev + * @ring + */ +static int +bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) +{ + struct bdx_priv *priv = netdev->priv; + int rx_size = 0; + int tx_size = 0; + + for (; rx_size < 4; rx_size++) { + if (bdx_rx_fifo_size_to_packets(rx_size) >= ring->rx_pending) + break; + } + if (rx_size == 4) + rx_size = 3; + + for (; tx_size < 4; tx_size++) { + if (bdx_tx_fifo_size_to_packets(tx_size) >= ring->tx_pending) + break; + } + if (tx_size == 4) + tx_size = 3; + + /*Is there anything to do? */ + if ((rx_size == priv->rxf_size) + && (tx_size == priv->txd_size)) + return 0; + + priv->rxf_size = rx_size; + if (rx_size > 1) + priv->rxd_size = rx_size - 1; + else + priv->rxd_size = rx_size; + + priv->txf_size = priv->txd_size = tx_size; + + if (netif_running(netdev)) { + bdx_close(netdev); + bdx_open(netdev); + } + return 0; +} + +/* + * bdx_get_strings - return a set of strings that describe the requested objects + * @netdev + * @data + */ +static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *bdx_test_names, sizeof(bdx_test_names)); + break; + case ETH_SS_STATS: + memcpy(data, *bdx_stat_names, sizeof(bdx_stat_names)); + break; + } +} + +/* + * bdx_get_stats_count - return number of 64bit statistics counters + * @netdev + */ +static int bdx_get_stats_count(struct net_device *netdev) +{ + struct bdx_priv *priv = netdev->priv; + BDX_ASSERT(sizeof(bdx_stat_names) / ETH_GSTRING_LEN + != sizeof(struct bdx_stats) / sizeof(u64)); + return ((priv->stats_flag) ? (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) + : 0); +} + +/* + * bdx_get_ethtool_stats - return device's hardware L2 statistics + * @netdev + * @stats + * @data + */ +static void bdx_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct bdx_priv *priv = netdev->priv; + + if (priv->stats_flag) { + + /* Update stats from HW */ + bdx_update_stats(priv); + + /* Copy data to user buffer */ + memcpy(data, &priv->hw_stats, sizeof(priv->hw_stats)); + } +} + +/* + * bdx_ethtool_ops - ethtool interface implementation + * @netdev + */ +static void bdx_ethtool_ops(struct net_device *netdev) +{ + static struct ethtool_ops bdx_ethtool_ops = { + .get_settings = bdx_get_settings, + .get_drvinfo = bdx_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_coalesce = bdx_get_coalesce, + .set_coalesce = bdx_set_coalesce, + .get_ringparam = bdx_get_ringparam, + .set_ringparam = bdx_set_ringparam, + .get_rx_csum = bdx_get_rx_csum, + .get_tx_csum = bdx_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .get_tso = ethtool_op_get_tso, + .get_strings = bdx_get_strings, + .get_stats_count = bdx_get_stats_count, + .get_ethtool_stats = bdx_get_ethtool_stats, + }; + + SET_ETHTOOL_OPS(netdev, &bdx_ethtool_ops); +} + +/** + * bdx_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * bdx_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit bdx_remove(struct pci_dev *pdev) +{ + struct pci_nic *nic = pci_get_drvdata(pdev); + struct net_device *ndev; + int port; + + for (port = 0; port < nic->port_num; port++) { + ndev = nic->priv[port]->ndev; + unregister_netdev(ndev); + free_netdev(ndev); + } + + /*bdx_hw_reset_direct(nic->regs); */ +#ifdef BDX_MSI + if (nic->irq_type == IRQ_MSI) + pci_disable_msi(pdev); +#endif + + iounmap(nic->regs); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + vfree(nic); + + RET(); +} + +static struct pci_driver bdx_pci_driver = { + .name = BDX_DRV_NAME, + .id_table = bdx_pci_tbl, + .probe = bdx_probe, + .remove = __devexit_p(bdx_remove), +}; + +/* + * print_driver_id - print parameters of the driver build + */ +static void __init print_driver_id(void) +{ + printk(KERN_INFO "%s: %s, %s\n", BDX_DRV_NAME, BDX_DRV_DESC, + BDX_DRV_VERSION); + printk(KERN_INFO "%s: Options: hw_csum %s\n", BDX_DRV_NAME, + BDX_MSI_STRING); +} + +static int __init bdx_module_init(void) +{ + ENTER; + bdx_firmware_endianess(); + init_txd_sizes(); + print_driver_id(); + RET(pci_register_driver(&bdx_pci_driver)); +} + +module_init(bdx_module_init); + +static void __exit bdx_module_exit(void) +{ + ENTER; + pci_unregister_driver(&bdx_pci_driver); + RET(); +} + +module_exit(bdx_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(BDX_DRV_DESC); diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h new file mode 100644 index 000000000000..efd170f451b4 --- /dev/null +++ b/drivers/net/tehuti.h @@ -0,0 +1,564 @@ +/* + * Tehuti Networks(R) Network Driver + * Copyright (C) 2007 Tehuti Networks Ltd. 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. + */ + +#ifndef _TEHUTI_H +#define _TEHUTI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Compile Time Switches */ +/* start */ +#define BDX_TSO +#define BDX_LLTX +#define BDX_DELAY_WPTR +/* #define BDX_MSI */ +/* end */ + +#if !defined CONFIG_PCI_MSI +# undef BDX_MSI +#endif + +#define BDX_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK) + +/* ioctl ops */ +#define BDX_OP_READ 1 +#define BDX_OP_WRITE 2 + +/* RX copy break size */ +#define BDX_COPYBREAK 257 + +#define DRIVER_AUTHOR "Tehuti Networks(R)" +#define BDX_DRV_DESC "Tehuti Networks(R) Network Driver" +#define BDX_DRV_NAME "tehuti" +#define BDX_NIC_NAME "Tehuti 10 Giga TOE SmartNIC" +#define BDX_NIC2PORT_NAME "Tehuti 2-Port 10 Giga TOE SmartNIC" +#define BDX_DRV_VERSION "7.29.3" + +#ifdef BDX_MSI +# define BDX_MSI_STRING "msi " +#else +# define BDX_MSI_STRING "" +#endif + +/* netdev tx queue len for Luxor. default value is, btw, 1000 + * ifcontig eth1 txqueuelen 3000 - to change it at runtime */ +#define BDX_NDEV_TXQ_LEN 3000 + +#define FIFO_SIZE 4096 +#define FIFO_EXTRA_SPACE 1024 + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +#if BITS_PER_LONG == 64 +# define H32_64(x) (u32) ((u64)(x) >> 32) +# define L32_64(x) (u32) ((u64)(x) & 0xffffffff) +#elif BITS_PER_LONG == 32 +# define H32_64(x) 0 +# define L32_64(x) ((u32) (x)) +#else /* BITS_PER_LONG == ?? */ +# error BITS_PER_LONG is undefined. Must be 64 or 32 +#endif /* BITS_PER_LONG */ + +#ifdef __BIG_ENDIAN +# define CPU_CHIP_SWAP32(x) swab32(x) +# define CPU_CHIP_SWAP16(x) swab16(x) +#else +# define CPU_CHIP_SWAP32(x) (x) +# define CPU_CHIP_SWAP16(x) (x) +#endif + +#define READ_REG(pp, reg) readl(pp->pBdxRegs + reg) +#define WRITE_REG(pp, reg, val) writel(val, pp->pBdxRegs + reg) + +#ifndef DMA_64BIT_MASK +# define DMA_64BIT_MASK 0xffffffffffffffffULL +#endif + +#ifndef DMA_32BIT_MASK +# define DMA_32BIT_MASK 0x00000000ffffffffULL +#endif + +#ifndef NET_IP_ALIGN +# define NET_IP_ALIGN 2 +#endif + +#ifndef NETDEV_TX_OK +# define NETDEV_TX_OK 0 +#endif + +#define LUXOR_MAX_PORT 2 +#define BDX_MAX_RX_DONE 150 +#define BDX_TXF_DESC_SZ 16 +#define BDX_MAX_TX_LEVEL (priv->txd_fifo0.m.memsz - 16) +#define BDX_MIN_TX_LEVEL 256 +#define BDX_NO_UPD_PACKETS 40 + +struct pci_nic { + int port_num; + void __iomem *regs; + int irq_type; + struct bdx_priv *priv[LUXOR_MAX_PORT]; +}; + +enum { IRQ_INTX, IRQ_MSI, IRQ_MSIX }; + +#define PCK_TH_MULT 128 +#define INT_COAL_MULT 2 + +#define BITS_MASK(nbits) ((1<>nshift)&BITS_MASK(nbits)) +#define BITS_SHIFT_MASK(nbits, nshift) (BITS_MASK(nbits)< Date: Tue, 18 Sep 2007 13:20:41 -0700 Subject: [PATCH 1417/2804] [NETNS]: Cleanup list walking in setup_net and cleanup_net I proposed introducing a list_for_each_entry_continue_reverse macro to be used in setup_net() when unrolling the failed ->init callback. Here is the macro and some more cleanup in the setup_net() itself to remove one variable from the stack :) The same thing is for the cleanup_net() - the existing list_for_each_entry_reverse() is used. Minor, but the code looks nicer. Signed-off-by: Pavel Emelyanov Acked-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/linux/list.h | 14 ++++++++++++++ net/core/net_namespace.c | 12 ++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/linux/list.h b/include/linux/list.h index f29fc9c1a964..ad9dcb9e3375 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -524,6 +524,20 @@ static inline void list_splice_init_rcu(struct list_head *list, prefetch(pos->member.next), &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + /** * list_for_each_entry_from - iterate over list of given type from the current point * @pos: the type * to use as a loop cursor. diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 1fc513c4c79e..0e6cb02d7b77 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -56,7 +56,6 @@ static void net_free(struct net *net) static void cleanup_net(struct work_struct *work) { struct pernet_operations *ops; - struct list_head *ptr; struct net *net; net = container_of(work, struct net, work); @@ -69,8 +68,7 @@ static void cleanup_net(struct work_struct *work) net_unlock(); /* Run all of the network namespace exit methods */ - list_for_each_prev(ptr, &pernet_list) { - ops = list_entry(ptr, struct pernet_operations, list); + list_for_each_entry_reverse(ops, &pernet_list, list) { if (ops->exit) ops->exit(net); } @@ -102,7 +100,6 @@ static int setup_net(struct net *net) { /* Must be called with net_mutex held */ struct pernet_operations *ops; - struct list_head *ptr; int error; memset(net, 0, sizeof(struct net)); @@ -110,8 +107,7 @@ static int setup_net(struct net *net) atomic_set(&net->use_count, 0); error = 0; - list_for_each(ptr, &pernet_list) { - ops = list_entry(ptr, struct pernet_operations, list); + list_for_each_entry(ops, &pernet_list, list) { if (ops->init) { error = ops->init(net); if (error < 0) @@ -120,12 +116,12 @@ static int setup_net(struct net *net) } out: return error; + out_undo: /* Walk through the list backwards calling the exit functions * for the pernet modules whose init functions did not fail. */ - for (ptr = ptr->prev; ptr != &pernet_list; ptr = ptr->prev) { - ops = list_entry(ptr, struct pernet_operations, list); + list_for_each_entry_continue_reverse(ops, &pernet_list, list) { if (ops->exit) ops->exit(net); } From 5ee3afba88f5a79d0bff07ddd87af45919259f91 Mon Sep 17 00:00:00 2001 From: Rick Jones Date: Tue, 18 Sep 2007 13:26:31 -0700 Subject: [PATCH 1418/2804] [TCP]: Return useful listenq info in tcp_info and INET_DIAG_INFO. Return some useful information such as the maximum listen backlog and the current listen backlog in the tcp_info structure and INET_DIAG_INFO. Signed-off-by: Rick Jones Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 9 +++++++-- net/ipv4/tcp_diag.c | 8 +++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 18c64c74f6d5..4f322003835d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2031,8 +2031,13 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) info->tcpi_snd_mss = tp->mss_cache; info->tcpi_rcv_mss = icsk->icsk_ack.rcv_mss; - info->tcpi_unacked = tp->packets_out; - info->tcpi_sacked = tp->sacked_out; + if (sk->sk_state == TCP_LISTEN) { + info->tcpi_unacked = sk->sk_ack_backlog; + info->tcpi_sacked = sk->sk_max_ack_backlog; + } else { + info->tcpi_unacked = tp->packets_out; + info->tcpi_sacked = tp->sacked_out; + } info->tcpi_lost = tp->lost_out; info->tcpi_retrans = tp->retrans_out; info->tcpi_fackets = tp->fackets_out; diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 57c5f0b10e6c..3904d2158a92 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -25,11 +25,13 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, const struct tcp_sock *tp = tcp_sk(sk); struct tcp_info *info = _info; - if (sk->sk_state == TCP_LISTEN) + if (sk->sk_state == TCP_LISTEN) { r->idiag_rqueue = sk->sk_ack_backlog; - else + r->idiag_wqueue = sk->sk_max_ack_backlog; + } else { r->idiag_rqueue = tp->rcv_nxt - tp->copied_seq; - r->idiag_wqueue = tp->write_seq - tp->snd_una; + r->idiag_wqueue = tp->write_seq - tp->snd_una; + } if (info != NULL) tcp_get_info(sk, info); } From 61e115a56d1aafd6e6a8a9fee8ac099a6128ac7b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 18 Sep 2007 15:12:50 -0400 Subject: [PATCH 1419/2804] [SSB]: add Sonics Silicon Backplane bus support SSB is an SoC bus used in a number of embedded devices. The most well-known of these devices is probably the Linksys WRT54G, but there are others as well. The bus is also used internally on the BCM43xx and BCM44xx devices from Broadcom. This patch also includes support for SSB ID tables in modules, so that SSB drivers can be loaded automatically. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 6 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/ssb/Kconfig | 117 +++ drivers/ssb/Makefile | 18 + drivers/ssb/b43_pci_bridge.c | 46 + drivers/ssb/driver_chipcommon.c | 446 ++++++++ drivers/ssb/driver_extif.c | 129 +++ drivers/ssb/driver_mipscore.c | 223 ++++ drivers/ssb/driver_pcicore.c | 576 ++++++++++ drivers/ssb/main.c | 1162 +++++++++++++++++++++ drivers/ssb/pci.c | 740 +++++++++++++ drivers/ssb/pcihost_wrapper.c | 104 ++ drivers/ssb/pcmcia.c | 271 +++++ drivers/ssb/scan.c | 413 ++++++++ drivers/ssb/ssb_private.h | 136 +++ include/linux/mod_devicetable.h | 15 + include/linux/ssb/ssb.h | 424 ++++++++ include/linux/ssb/ssb_driver_chipcommon.h | 396 +++++++ include/linux/ssb/ssb_driver_extif.h | 204 ++++ include/linux/ssb/ssb_driver_mips.h | 46 + include/linux/ssb/ssb_driver_pci.h | 106 ++ include/linux/ssb/ssb_regs.h | 292 ++++++ scripts/mod/file2alias.c | 19 + 24 files changed, 5892 insertions(+) create mode 100644 drivers/ssb/Kconfig create mode 100644 drivers/ssb/Makefile create mode 100644 drivers/ssb/b43_pci_bridge.c create mode 100644 drivers/ssb/driver_chipcommon.c create mode 100644 drivers/ssb/driver_extif.c create mode 100644 drivers/ssb/driver_mipscore.c create mode 100644 drivers/ssb/driver_pcicore.c create mode 100644 drivers/ssb/main.c create mode 100644 drivers/ssb/pci.c create mode 100644 drivers/ssb/pcihost_wrapper.c create mode 100644 drivers/ssb/pcmcia.c create mode 100644 drivers/ssb/scan.c create mode 100644 drivers/ssb/ssb_private.h create mode 100644 include/linux/ssb/ssb.h create mode 100644 include/linux/ssb/ssb_driver_chipcommon.h create mode 100644 include/linux/ssb/ssb_driver_extif.h create mode 100644 include/linux/ssb/ssb_driver_mips.h create mode 100644 include/linux/ssb/ssb_driver_pci.h create mode 100644 include/linux/ssb/ssb_regs.h diff --git a/MAINTAINERS b/MAINTAINERS index 3f07d5ff85f1..7524cd802da3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3446,6 +3446,12 @@ M: tsbogend@alpha.franken.de L: netdev@vger.kernel.org S: Maintained +SONICS SILICON BACKPLANE DRIVER (SSB) +P: Michael Buesch +M: mb@bu3sch.de +L: netdev@vger.kernel.org +S: Maintained + SONY VAIO CONTROL DEVICE DRIVER P: Mattia Dongili M: malattia@linux.it diff --git a/drivers/Kconfig b/drivers/Kconfig index 3e1c442deff9..7bdae47d6b91 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -58,6 +58,8 @@ source "drivers/power/Kconfig" source "drivers/hwmon/Kconfig" +source "drivers/ssb/Kconfig" + source "drivers/mfd/Kconfig" source "drivers/media/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index f0878b2ec55e..a168eacdcd9c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -88,3 +88,4 @@ obj-$(CONFIG_DMA_ENGINE) += dma/ obj-$(CONFIG_HID) += hid/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ +obj-$(CONFIG_SSB) += ssb/ diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig new file mode 100644 index 000000000000..b4a5e5e9d9fc --- /dev/null +++ b/drivers/ssb/Kconfig @@ -0,0 +1,117 @@ +menu "Sonics Silicon Backplane" + +config SSB_POSSIBLE + bool + depends on HAS_IOMEM + default y + +config SSB + tristate "Sonics Silicon Backplane support" + depends on SSB_POSSIBLE + help + Support for the Sonics Silicon Backplane bus. + You only need to enable this option, if you are + configuring a kernel for an embedded system with + this bus. + It will be auto-selected if needed in other + environments. + + The module will be called ssb. + + If unsure, say N. + +config SSB_PCIHOST_POSSIBLE + bool + depends on SSB && PCI + default y + +config SSB_PCIHOST + bool "Support for SSB on PCI-bus host" + depends on SSB_PCIHOST_POSSIBLE + default y + help + Support for a Sonics Silicon Backplane on top + of a PCI device. + + If unsure, say Y + +config SSB_PCMCIAHOST_POSSIBLE + bool + depends on SSB && PCMCIA && EXPERIMENTAL + default y + +config SSB_PCMCIAHOST + bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)" + depends on SSB_PCMCIAHOST_POSSIBLE + help + Support for a Sonics Silicon Backplane on top + of a PCMCIA device. + + If unsure, say N + +config SSB_SILENT + bool "No SSB kernel messages" + depends on SSB && EMBEDDED + help + This option turns off all Sonics Silicon Backplane printks. + Note that you won't be able to identify problems, once + messages are turned off. + This might only be desired for production kernels on + embedded devices to reduce the kernel size. + + Say N + +config SSB_DEBUG + bool "SSB debugging" + depends on SSB && !SSB_SILENT + help + This turns on additional runtime checks and debugging + messages. Turn this on for SSB troubleshooting. + + If unsure, say N + +config SSB_SERIAL + bool + depends on SSB + # ChipCommon and ExtIf serial support routines. + +config SSB_DRIVER_PCICORE_POSSIBLE + bool + depends on SSB_PCIHOST + default y + +config SSB_DRIVER_PCICORE + bool "SSB PCI core driver" + depends on SSB_DRIVER_PCICORE_POSSIBLE + help + Driver for the Sonics Silicon Backplane attached + Broadcom PCI core. + + If unsure, say Y + +config SSB_PCICORE_HOSTMODE + bool "Hostmode support for SSB PCI core (EXPERIMENTAL)" + depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL + help + PCIcore hostmode operation (external PCI bus). + +config SSB_DRIVER_MIPS + bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)" + depends on SSB && MIPS && EXPERIMENTAL + select SSB_SERIAL + help + Driver for the Sonics Silicon Backplane attached + Broadcom MIPS core. + + If unsure, say N + +config SSB_DRIVER_EXTIF + bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)" + depends on SSB_DRIVER_MIPS && EXPERIMENTAL + help + Driver for the Sonics Silicon Backplane attached + Broadcom EXTIF core. + + If unsure, say N + +endmenu diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile new file mode 100644 index 000000000000..7be397595805 --- /dev/null +++ b/drivers/ssb/Makefile @@ -0,0 +1,18 @@ +# core +ssb-y += main.o scan.o + +# host support +ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o +ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o + +# built-in drivers +ssb-y += driver_chipcommon.o +ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o +ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o +ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o + +# b43 pci-ssb-bridge driver +# Not strictly a part of SSB, but kept here for convenience +ssb-$(CONFIG_SSB_PCIHOST) += b43_pci_bridge.o + +obj-$(CONFIG_SSB) += ssb.o diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c new file mode 100644 index 000000000000..fa3bd292f5f7 --- /dev/null +++ b/drivers/ssb/b43_pci_bridge.c @@ -0,0 +1,46 @@ +/* + * Broadcom 43xx PCI-SSB bridge module + * + * This technically is a seperate PCI driver module, but + * because of its small size we include it in the SSB core + * instead of creating a standalone module. + * + * Copyright 2007 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include + + +static const struct pci_device_id b43_pci_bridge_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl); + +static struct pci_driver b43_pci_bridge_driver = { + .name = "b43-pci-bridge", + .id_table = b43_pci_bridge_tbl, +}; + + +int __init b43_pci_ssb_bridge_init(void) +{ + return ssb_pcihost_register(&b43_pci_bridge_driver); +} + +void __exit b43_pci_ssb_bridge_exit(void) +{ + ssb_pcihost_unregister(&b43_pci_bridge_driver); +} diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c new file mode 100644 index 000000000000..a890544e8fba --- /dev/null +++ b/drivers/ssb/driver_chipcommon.c @@ -0,0 +1,446 @@ +/* + * Sonics Silicon Backplane + * Broadcom ChipCommon core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include + +#include "ssb_private.h" + + +/* Clock sources */ +enum ssb_clksrc { + /* PCI clock */ + SSB_CHIPCO_CLKSRC_PCI, + /* Crystal slow clock oscillator */ + SSB_CHIPCO_CLKSRC_XTALOS, + /* Low power oscillator */ + SSB_CHIPCO_CLKSRC_LOPWROS, +}; + + +static inline u32 chipco_read32(struct ssb_chipcommon *cc, + u16 offset) +{ + return ssb_read32(cc->dev, offset); +} + +static inline void chipco_write32(struct ssb_chipcommon *cc, + u16 offset, + u32 value) +{ + ssb_write32(cc->dev, offset, value); +} + +static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, + u32 mask, u32 value) +{ + value &= mask; + value |= chipco_read32(cc, offset) & ~mask; + chipco_write32(cc, offset, value); +} + +void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, + enum ssb_clkmode mode) +{ + struct ssb_device *ccdev = cc->dev; + struct ssb_bus *bus; + u32 tmp; + + if (!ccdev) + return; + bus = ccdev->bus; + /* chipcommon cores prior to rev6 don't support dynamic clock control */ + if (ccdev->id.revision < 6) + return; + /* chipcommon cores rev10 are a whole new ball game */ + if (ccdev->id.revision >= 10) + return; + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) + return; + + switch (mode) { + case SSB_CLKMODE_SLOW: + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + break; + case SSB_CLKMODE_FAST: + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + break; + case SSB_CLKMODE_DYNAMIC: + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) + tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + + /* for dynamic control, we have to release our xtal_pu "force on" */ + if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); + break; + default: + SSB_WARN_ON(1); + } +} + +/* Get the Slow Clock Source */ +static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + u32 uninitialized_var(tmp); + + if (cc->dev->id.revision < 6) { + if (bus->bustype == SSB_BUSTYPE_SSB || + bus->bustype == SSB_BUSTYPE_PCMCIA) + return SSB_CHIPCO_CLKSRC_XTALOS; + if (bus->bustype == SSB_BUSTYPE_PCI) { + pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp); + if (tmp & 0x10) + return SSB_CHIPCO_CLKSRC_PCI; + return SSB_CHIPCO_CLKSRC_XTALOS; + } + } + if (cc->dev->id.revision < 10) { + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= 0x7; + if (tmp == 0) + return SSB_CHIPCO_CLKSRC_LOPWROS; + if (tmp == 1) + return SSB_CHIPCO_CLKSRC_XTALOS; + if (tmp == 2) + return SSB_CHIPCO_CLKSRC_PCI; + } + + return SSB_CHIPCO_CLKSRC_XTALOS; +} + +/* Get maximum or minimum (depending on get_max flag) slowclock frequency. */ +static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max) +{ + int uninitialized_var(limit); + enum ssb_clksrc clocksrc; + int divisor = 1; + u32 tmp; + + clocksrc = chipco_pctl_get_slowclksrc(cc); + if (cc->dev->id.revision < 6) { + switch (clocksrc) { + case SSB_CHIPCO_CLKSRC_PCI: + divisor = 64; + break; + case SSB_CHIPCO_CLKSRC_XTALOS: + divisor = 32; + break; + default: + SSB_WARN_ON(1); + } + } else if (cc->dev->id.revision < 10) { + switch (clocksrc) { + case SSB_CHIPCO_CLKSRC_LOPWROS: + break; + case SSB_CHIPCO_CLKSRC_XTALOS: + case SSB_CHIPCO_CLKSRC_PCI: + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + divisor = (tmp >> 16) + 1; + divisor *= 4; + break; + } + } else { + tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL); + divisor = (tmp >> 16) + 1; + divisor *= 4; + } + + switch (clocksrc) { + case SSB_CHIPCO_CLKSRC_LOPWROS: + if (get_max) + limit = 43000; + else + limit = 25000; + break; + case SSB_CHIPCO_CLKSRC_XTALOS: + if (get_max) + limit = 20200000; + else + limit = 19800000; + break; + case SSB_CHIPCO_CLKSRC_PCI: + if (get_max) + limit = 34000000; + else + limit = 25000000; + break; + } + limit /= divisor; + + return limit; +} + +static void chipco_powercontrol_init(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + + if (bus->chip_id == 0x4321) { + if (bus->chip_rev == 0) + chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4); + else if (bus->chip_rev == 1) + chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4); + } + + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) + return; + + if (cc->dev->id.revision >= 10) { + /* Set Idle Power clock rate to 1Mhz */ + chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, + (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & + 0x0000FFFF) | 0x00040000); + } else { + int maxfreq; + + maxfreq = chipco_pctl_clockfreqlimit(cc, 1); + chipco_write32(cc, SSB_CHIPCO_PLLONDELAY, + (maxfreq * 150 + 999999) / 1000000); + chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY, + (maxfreq * 15 + 999999) / 1000000); + } +} + +static void calc_fast_powerup_delay(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + int minfreq; + unsigned int tmp; + u32 pll_on_delay; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return; + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) + return; + + minfreq = chipco_pctl_clockfreqlimit(cc, 0); + pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY); + tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; + SSB_WARN_ON(tmp & ~0xFFFF); + + cc->fast_pwrup_delay = tmp; +} + +void ssb_chipcommon_init(struct ssb_chipcommon *cc) +{ + if (!cc->dev) + return; /* We don't have a ChipCommon */ + chipco_powercontrol_init(cc); + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); + calc_fast_powerup_delay(cc); +} + +void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state) +{ + if (!cc->dev) + return; + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); +} + +void ssb_chipco_resume(struct ssb_chipcommon *cc) +{ + if (!cc->dev) + return; + chipco_powercontrol_init(cc); + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); +} + +/* Get the processor clock */ +void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) +{ + *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); + *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + switch (*plltype) { + case SSB_PLLTYPE_2: + case SSB_PLLTYPE_4: + case SSB_PLLTYPE_6: + case SSB_PLLTYPE_7: + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); + break; + case SSB_PLLTYPE_3: + /* 5350 uses m2 to control mips */ + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); + break; + default: + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); + break; + } +} + +/* Get the bus clock */ +void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) +{ + *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); + *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + switch (*plltype) { + case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); + break; + case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ + if (cc->dev->bus->chip_id != 0x5365) { + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); + break; + } + /* Fallthough */ + default: + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); + } +} + +void ssb_chipco_timing_init(struct ssb_chipcommon *cc, + unsigned long ns) +{ + struct ssb_device *dev = cc->dev; + struct ssb_bus *bus = dev->bus; + u32 tmp; + + /* set register for external IO to control LED. */ + chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11); + tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ + tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */ + tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */ + chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ + + /* Set timing for the flash */ + tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */ + tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */ + tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */ + if ((bus->chip_id == 0x5365) || + (dev->id.revision < 9)) + chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp); + if ((bus->chip_id == 0x5365) || + (dev->id.revision < 9) || + ((bus->chip_id == 0x5350) && (bus->chip_rev == 0))) + chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp); + + if (bus->chip_id == 0x5350) { + /* Enable EXTIF */ + tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ + tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */ + tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */ + tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */ + chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ + } +} + +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ +void +ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) +{ + /* instant NMI */ + chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); +} + +u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) +{ + return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; +} + +void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); +} + +void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); +} + +#ifdef CONFIG_SSB_SERIAL +int ssb_chipco_serial_init(struct ssb_chipcommon *cc, + struct ssb_serial_port *ports) +{ + struct ssb_bus *bus = cc->dev->bus; + int nr_ports = 0; + u32 plltype; + unsigned int irq; + u32 baud_base, div; + u32 i, n; + + plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + irq = ssb_mips_irq(cc->dev); + + if (plltype == SSB_PLLTYPE_1) { + /* PLL clock */ + baud_base = ssb_calc_clock_rate(plltype, + chipco_read32(cc, SSB_CHIPCO_CLOCK_N), + chipco_read32(cc, SSB_CHIPCO_CLOCK_M2)); + div = 1; + } else { + if (cc->dev->id.revision >= 11) { + /* Fixed ALP clock */ + baud_base = 20000000; + div = 1; + /* Set the override bit so we don't divide it */ + chipco_write32(cc, SSB_CHIPCO_CORECTL, + SSB_CHIPCO_CORECTL_UARTCLK0); + } else if (cc->dev->id.revision >= 3) { + /* Internal backplane clock */ + baud_base = ssb_clockspeed(bus); + div = chipco_read32(cc, SSB_CHIPCO_CLKDIV) + & SSB_CHIPCO_CLKDIV_UART; + } else { + /* Fixed internal backplane clock */ + baud_base = 88000000; + div = 48; + } + + /* Clock source depends on strapping if UartClkOverride is unset */ + if ((cc->dev->id.revision > 0) && + !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) { + if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) == + SSB_CHIPCO_CAP_UARTCLK_INT) { + /* Internal divided backplane clock */ + baud_base /= div; + } else { + /* Assume external clock of 1.8432 MHz */ + baud_base = 1843200; + } + } + } + + /* Determine the registers of the UARTs */ + n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART); + for (i = 0; i < n; i++) { + void __iomem *cc_mmio; + void __iomem *uart_regs; + + cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE); + uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA; + /* Offset changed at after rev 0 */ + if (cc->dev->id.revision == 0) + uart_regs += (i * 8); + else + uart_regs += (i * 256); + + nr_ports++; + ports[i].regs = uart_regs; + ports[i].irq = irq; + ports[i].baud_base = baud_base; + ports[i].reg_shift = 0; + } + + return nr_ports; +} +#endif /* CONFIG_SSB_SERIAL */ diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c new file mode 100644 index 000000000000..fe55eb8b038a --- /dev/null +++ b/drivers/ssb/driver_extif.c @@ -0,0 +1,129 @@ +/* + * Sonics Silicon Backplane + * Broadcom EXTIF core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * Copyright 2006, 2007, Felix Fietkau + * Copyright 2007, Aurelien Jarno + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include + +#include "ssb_private.h" + + +static inline u32 extif_read32(struct ssb_extif *extif, u16 offset) +{ + return ssb_read32(extif->dev, offset); +} + +static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value) +{ + ssb_write32(extif->dev, offset, value); +} + +static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset, + u32 mask, u32 value) +{ + value &= mask; + value |= extif_read32(extif, offset) & ~mask; + extif_write32(extif, offset, value); +} + +#ifdef CONFIG_SSB_SERIAL +static bool serial_exists(u8 *regs) +{ + u8 save_mcr, msr = 0; + + if (regs) { + save_mcr = regs[UART_MCR]; + regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS); + msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI + | UART_MSR_CTS | UART_MSR_DSR); + regs[UART_MCR] = save_mcr; + } + return (msr == (UART_MSR_DCD | UART_MSR_CTS)); +} + +int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports) +{ + u32 i, nr_ports = 0; + + /* Disable GPIO interrupt initially */ + extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0); + extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0); + + for (i = 0; i < 2; i++) { + void __iomem *uart_regs; + + uart_regs = ioremap_nocache(SSB_EUART, 16); + if (uart_regs) { + uart_regs += (i * 8); + + if (serial_exists(uart_regs) && ports) { + extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2); + + nr_ports++; + ports[i].regs = uart_regs; + ports[i].irq = 2; + ports[i].baud_base = 13500000; + ports[i].reg_shift = 0; + } + iounmap(uart_regs); + } + } + return nr_ports; +} +#endif /* CONFIG_SSB_SERIAL */ + +void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) +{ + u32 tmp; + + /* Initialize extif so we can get to the LEDs and external UART */ + extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN); + + /* Set timing for the flash */ + tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; + tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; + tmp |= DIV_ROUND_UP(120, ns); + extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); + + /* Set programmable interface timing for external uart */ + tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; + tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; + tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; + tmp |= DIV_ROUND_UP(120, ns); + extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); +} + +void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *pll_type, u32 *n, u32 *m) +{ + *pll_type = SSB_PLLTYPE_1; + *n = extif_read32(extif, SSB_EXTIF_CLOCK_N); + *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); +} + +u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) +{ + return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; +} + +void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) +{ + return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), + mask, value); +} + +void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) +{ + return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), + mask, value); +} + diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c new file mode 100644 index 000000000000..ab8691a32580 --- /dev/null +++ b/drivers/ssb/driver_mipscore.c @@ -0,0 +1,223 @@ +/* + * Sonics Silicon Backplane + * Broadcom MIPS core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include + +#include +#include +#include +#include + +#include "ssb_private.h" + + +static inline u32 mips_read32(struct ssb_mipscore *mcore, + u16 offset) +{ + return ssb_read32(mcore->dev, offset); +} + +static inline void mips_write32(struct ssb_mipscore *mcore, + u16 offset, + u32 value) +{ + ssb_write32(mcore->dev, offset, value); +} + +static const u32 ipsflag_irq_mask[] = { + 0, + SSB_IPSFLAG_IRQ1, + SSB_IPSFLAG_IRQ2, + SSB_IPSFLAG_IRQ3, + SSB_IPSFLAG_IRQ4, +}; + +static const u32 ipsflag_irq_shift[] = { + 0, + SSB_IPSFLAG_IRQ1_SHIFT, + SSB_IPSFLAG_IRQ2_SHIFT, + SSB_IPSFLAG_IRQ3_SHIFT, + SSB_IPSFLAG_IRQ4_SHIFT, +}; + +static inline u32 ssb_irqflag(struct ssb_device *dev) +{ + return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG; +} + +/* Get the MIPS IRQ assignment for a specified device. + * If unassigned, 0 is returned. + */ +unsigned int ssb_mips_irq(struct ssb_device *dev) +{ + struct ssb_bus *bus = dev->bus; + u32 irqflag; + u32 ipsflag; + u32 tmp; + unsigned int irq; + + irqflag = ssb_irqflag(dev); + ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG); + for (irq = 1; irq <= 4; irq++) { + tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]); + if (tmp == irqflag) + break; + } + if (irq == 5) + irq = 0; + + return irq; +} + +static void clear_irq(struct ssb_bus *bus, unsigned int irq) +{ + struct ssb_device *dev = bus->mipscore.dev; + + /* Clear the IRQ in the MIPScore backplane registers */ + if (irq == 0) { + ssb_write32(dev, SSB_INTVEC, 0); + } else { + ssb_write32(dev, SSB_IPSFLAG, + ssb_read32(dev, SSB_IPSFLAG) | + ipsflag_irq_mask[irq]); + } +} + +static void set_irq(struct ssb_device *dev, unsigned int irq) +{ + unsigned int oldirq = ssb_mips_irq(dev); + struct ssb_bus *bus = dev->bus; + struct ssb_device *mdev = bus->mipscore.dev; + u32 irqflag = ssb_irqflag(dev); + + dev->irq = irq + 2; + + ssb_dprintk(KERN_INFO PFX + "set_irq: core 0x%04x, irq %d => %d\n", + dev->id.coreid, oldirq, irq); + /* clear the old irq */ + if (oldirq == 0) + ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))); + else + clear_irq(bus, oldirq); + + /* assign the new one */ + if (irq == 0) + ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))); + + irqflag <<= ipsflag_irq_shift[irq]; + irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]); + ssb_write32(mdev, SSB_IPSFLAG, irqflag); +} + +static void ssb_mips_serial_init(struct ssb_mipscore *mcore) +{ + struct ssb_bus *bus = mcore->dev->bus; + + if (bus->extif.dev) + mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); + else if (bus->chipco.dev) + mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports); + else + mcore->nr_serial_ports = 0; +} + +static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) +{ + struct ssb_bus *bus = mcore->dev->bus; + + mcore->flash_buswidth = 2; + if (bus->chipco.dev) { + mcore->flash_window = 0x1c000000; + mcore->flash_window_size = 0x02000000; + if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) + & SSB_CHIPCO_CFG_DS16) == 0) + mcore->flash_buswidth = 1; + } else { + mcore->flash_window = 0x1fc00000; + mcore->flash_window_size = 0x00400000; + } +} + +u32 ssb_cpu_clock(struct ssb_mipscore *mcore) +{ + struct ssb_bus *bus = mcore->dev->bus; + u32 pll_type, n, m, rate = 0; + + if (bus->extif.dev) { + ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); + } else if (bus->chipco.dev) { + ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); + } else + return 0; + + if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { + rate = 200000000; + } else { + rate = ssb_calc_clock_rate(pll_type, n, m); + } + + if (pll_type == SSB_PLLTYPE_6) { + rate *= 2; + } + + return rate; +} + +void ssb_mipscore_init(struct ssb_mipscore *mcore) +{ + struct ssb_bus *bus = mcore->dev->bus; + struct ssb_device *dev; + unsigned long hz, ns; + unsigned int irq, i; + + if (!mcore->dev) + return; /* We don't have a MIPS core */ + + ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n"); + + hz = ssb_clockspeed(bus); + if (!hz) + hz = 100000000; + ns = 1000000000 / hz; + + if (bus->extif.dev) + ssb_extif_timing_init(&bus->extif, ns); + else if (bus->chipco.dev) + ssb_chipco_timing_init(&bus->chipco, ns); + + /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ + for (irq = 2, i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + dev->irq = ssb_mips_irq(dev) + 2; + switch (dev->id.coreid) { + case SSB_DEV_USB11_HOST: + /* shouldn't need a separate irq line for non-4710, most of them have a proper + * external usb controller on the pci */ + if ((bus->chip_id == 0x4710) && (irq <= 4)) { + set_irq(dev, irq++); + break; + } + /* fallthrough */ + case SSB_DEV_PCI: + case SSB_DEV_ETHERNET: + case SSB_DEV_80211: + case SSB_DEV_USB20_HOST: + /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ + if (irq <= 4) { + set_irq(dev, irq++); + break; + } + } + } + + ssb_mips_serial_init(mcore); + ssb_mips_flash_detect(mcore); +} diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c new file mode 100644 index 000000000000..2faaa906d5d6 --- /dev/null +++ b/drivers/ssb/driver_pcicore.c @@ -0,0 +1,576 @@ +/* + * Sonics Silicon Backplane + * Broadcom PCI-core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include + +#include "ssb_private.h" + + +static inline +u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) +{ + return ssb_read32(pc->dev, offset); +} + +static inline +void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value) +{ + ssb_write32(pc->dev, offset, value); +} + +/************************************************** + * Code for hostmode operation. + **************************************************/ + +#ifdef CONFIG_SSB_PCICORE_HOSTMODE + +#include +/* Probe a 32bit value on the bus and catch bus exceptions. + * Returns nonzero on a bus exception. + * This is MIPS specific */ +#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr))) + +/* Assume one-hot slot wiring */ +#define SSB_PCI_SLOT_MAX 16 + +/* Global lock is OK, as we won't have more than one extpci anyway. */ +static DEFINE_SPINLOCK(cfgspace_lock); +/* Core to access the external PCI config space. Can only have one. */ +static struct ssb_pcicore *extpci_core; + +static u32 ssb_pcicore_pcibus_iobase = 0x100; +static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; + +int pcibios_plat_dev_init(struct pci_dev *d) +{ + struct resource *res; + int pos, size; + u32 *base; + + ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", + pci_name(d)); + + /* Fix up resource bases */ + for (pos = 0; pos < 6; pos++) { + res = &d->resource[pos]; + if (res->flags & IORESOURCE_IO) + base = &ssb_pcicore_pcibus_iobase; + else + base = &ssb_pcicore_pcibus_membase; + if (res->end) { + size = res->end - res->start + 1; + if (*base & (size - 1)) + *base = (*base + size) & ~(size - 1); + res->start = *base; + res->end = res->start + size - 1; + *base += size; + pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); + } + /* Fix up PCI bridge BAR0 only */ + if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) + break; + } + /* Fix up interrupt lines */ + d->irq = ssb_mips_irq(extpci_core->dev) + 2; + pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); + + return 0; +} + +static void __init ssb_fixup_pcibridge(struct pci_dev *dev) +{ + if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) + return; + + ssb_printk(KERN_INFO "PCI: fixing up bridge\n"); + + /* Enable PCI bridge bus mastering and memory space */ + pci_set_master(dev); + pcibios_enable_device(dev, ~0); + + /* Enable PCI bridge BAR1 prefetch and burst */ + pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); + + /* Make sure our latency is high enough to handle the devices behind us */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); +} +DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return ssb_mips_irq(extpci_core->dev) + 2; +} + +static u32 get_cfgspace_addr(struct ssb_pcicore *pc, + unsigned int bus, unsigned int dev, + unsigned int func, unsigned int off) +{ + u32 addr = 0; + u32 tmp; + + if (unlikely(pc->cardbusmode && dev > 1)) + goto out; + if (bus == 0) { + /* Type 0 transaction */ + if (unlikely(dev >= SSB_PCI_SLOT_MAX)) + goto out; + /* Slide the window */ + tmp = SSB_PCICORE_SBTOPCI_CFG0; + tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK); + pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp); + /* Calculate the address */ + addr = SSB_PCI_CFG; + addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK); + addr |= (func << 8); + addr |= (off & ~3); + } else { + /* Type 1 transaction */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, + SSB_PCICORE_SBTOPCI_CFG1); + /* Calculate the address */ + addr = SSB_PCI_CFG; + addr |= (bus << 16); + addr |= (dev << 11); + addr |= (func << 8); + addr |= (off & ~3); + } +out: + return addr; +} + +static int ssb_extpci_read_config(struct ssb_pcicore *pc, + unsigned int bus, unsigned int dev, + unsigned int func, unsigned int off, + void *buf, int len) +{ + int err = -EINVAL; + u32 addr, val; + void __iomem *mmio; + + SSB_WARN_ON(!pc->hostmode); + if (unlikely(len != 1 && len != 2 && len != 4)) + goto out; + addr = get_cfgspace_addr(pc, bus, dev, func, off); + if (unlikely(!addr)) + goto out; + err = -ENOMEM; + mmio = ioremap_nocache(addr, len); + if (!mmio) + goto out; + + if (mips_busprobe32(val, mmio)) { + val = 0xffffffff; + goto unmap; + } + + val = readl(mmio); + val >>= (8 * (off & 3)); + + switch (len) { + case 1: + *((u8 *)buf) = (u8)val; + break; + case 2: + *((u16 *)buf) = (u16)val; + break; + case 4: + *((u32 *)buf) = (u32)val; + break; + } + err = 0; +unmap: + iounmap(mmio); +out: + return err; +} + +static int ssb_extpci_write_config(struct ssb_pcicore *pc, + unsigned int bus, unsigned int dev, + unsigned int func, unsigned int off, + const void *buf, int len) +{ + int err = -EINVAL; + u32 addr, val = 0; + void __iomem *mmio; + + SSB_WARN_ON(!pc->hostmode); + if (unlikely(len != 1 && len != 2 && len != 4)) + goto out; + addr = get_cfgspace_addr(pc, bus, dev, func, off); + if (unlikely(!addr)) + goto out; + err = -ENOMEM; + mmio = ioremap_nocache(addr, len); + if (!mmio) + goto out; + + if (mips_busprobe32(val, mmio)) { + val = 0xffffffff; + goto unmap; + } + + switch (len) { + case 1: + val = readl(mmio); + val &= ~(0xFF << (8 * (off & 3))); + val |= *((const u8 *)buf) << (8 * (off & 3)); + break; + case 2: + val = readl(mmio); + val &= ~(0xFFFF << (8 * (off & 3))); + val |= *((const u16 *)buf) << (8 * (off & 3)); + break; + case 4: + val = *((const u32 *)buf); + break; + } + writel(val, mmio); + + err = 0; +unmap: + iounmap(mmio); +out: + return err; +} + +static int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 *val) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&cfgspace_lock, flags); + err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), reg, val, size); + spin_unlock_irqrestore(&cfgspace_lock, flags); + + return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; +} + +static int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 val) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&cfgspace_lock, flags); + err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), reg, &val, size); + spin_unlock_irqrestore(&cfgspace_lock, flags); + + return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ssb_pcicore_pciops = { + .read = ssb_pcicore_read_config, + .write = ssb_pcicore_write_config, +}; + +static struct resource ssb_pcicore_mem_resource = { + .name = "SSB PCIcore external memory", + .start = SSB_PCI_DMA, + .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource ssb_pcicore_io_resource = { + .name = "SSB PCIcore external I/O", + .start = 0x100, + .end = 0x7FF, + .flags = IORESOURCE_IO, +}; + +static struct pci_controller ssb_pcicore_controller = { + .pci_ops = &ssb_pcicore_pciops, + .io_resource = &ssb_pcicore_io_resource, + .mem_resource = &ssb_pcicore_mem_resource, + .mem_offset = 0x24000000, +}; + +static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) +{ + u32 val; + + if (WARN_ON(extpci_core)) + return; + extpci_core = pc; + + ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n"); + /* Reset devices on the external PCI bus */ + val = SSB_PCICORE_CTL_RST_OE; + val |= SSB_PCICORE_CTL_CLK_OE; + pcicore_write32(pc, SSB_PCICORE_CTL, val); + val |= SSB_PCICORE_CTL_CLK; /* Clock on */ + pcicore_write32(pc, SSB_PCICORE_CTL, val); + udelay(150); /* Assertion time demanded by the PCI standard */ + val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ + pcicore_write32(pc, SSB_PCICORE_CTL, val); + val = SSB_PCICORE_ARBCTL_INTERN; + pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); + udelay(1); /* Assertion time demanded by the PCI standard */ + + /*TODO cardbus mode */ + + /* 64MB I/O window */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI0, + SSB_PCICORE_SBTOPCI_IO); + /* 64MB config space */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, + SSB_PCICORE_SBTOPCI_CFG0); + /* 1GB memory window */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, + SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA); + + /* Enable PCI bridge BAR0 prefetch and burst */ + val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); + /* Clear error conditions */ + val = 0; + ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2); + + /* Enable PCI interrupts */ + pcicore_write32(pc, SSB_PCICORE_IMASK, + SSB_PCICORE_IMASK_INTA); + + /* Ok, ready to run, register it to the system. + * The following needs change, if we want to port hostmode + * to non-MIPS platform. */ + set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); + /* Give some time to the PCI controller to configure itself with the new + * values. Not waiting at this point causes crashes of the machine. */ + mdelay(10); + register_pci_controller(&ssb_pcicore_controller); +} + +static int pcicore_is_in_hostmode(struct ssb_pcicore *pc) +{ + struct ssb_bus *bus = pc->dev->bus; + u16 chipid_top; + u32 tmp; + + chipid_top = (bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && + chipid_top != 0x5300) + return 0; + + if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI) + return 0; + + /* The 200-pin BCM4712 package does not bond out PCI. Even when + * PCI is bonded out, some boards may leave the pins floating. */ + if (bus->chip_id == 0x4712) { + if (bus->chip_package == SSB_CHIPPACK_BCM4712S) + return 0; + if (bus->chip_package == SSB_CHIPPACK_BCM4712M) + return 0; + } + if (bus->chip_id == 0x5350) + return 0; + + return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE))); +} +#endif /* CONFIG_SSB_PCICORE_HOSTMODE */ + + +/************************************************** + * Generic and Clientmode operation code. + **************************************************/ + +static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) +{ + /* Disable PCI interrupts. */ + ssb_write32(pc->dev, SSB_INTVEC, 0); +} + +void ssb_pcicore_init(struct ssb_pcicore *pc) +{ + struct ssb_device *dev = pc->dev; + struct ssb_bus *bus; + + if (!dev) + return; + bus = dev->bus; + if (!ssb_device_is_enabled(dev)) + ssb_device_enable(dev, 0); + +#ifdef CONFIG_SSB_PCICORE_HOSTMODE + pc->hostmode = pcicore_is_in_hostmode(pc); + if (pc->hostmode) + ssb_pcicore_init_hostmode(pc); +#endif /* CONFIG_SSB_PCICORE_HOSTMODE */ + if (!pc->hostmode) + ssb_pcicore_init_clientmode(pc); +} + +static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) +{ + pcicore_write32(pc, 0x130, address); + return pcicore_read32(pc, 0x134); +} + +static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data) +{ + pcicore_write32(pc, 0x130, address); + pcicore_write32(pc, 0x134, data); +} + +static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, + u8 address, u16 data) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + u32 v; + int i; + + v = 0x80; /* Enable Preamble Sequence */ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ + v |= (u32)device << 22; + v |= (u32)address << 18; + v |= data; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); + for (i = 0; i < 10; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; + msleep(1); + } + pcicore_write32(pc, mdio_control, 0); +} + +static void ssb_broadcast_value(struct ssb_device *dev, + u32 address, u32 data) +{ + /* This is used for both, PCI and ChipCommon core, so be careful. */ + BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); + BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); + + ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address); + ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */ + ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data); + ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */ +} + +static void ssb_commit_settings(struct ssb_bus *bus) +{ + struct ssb_device *dev; + + dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; + if (WARN_ON(!dev)) + return; + /* This forces an update of the cached registers. */ + ssb_broadcast_value(dev, 0xFD8, 0); +} + +int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev) +{ + struct ssb_device *pdev = pc->dev; + struct ssb_bus *bus; + int err = 0; + u32 tmp; + + might_sleep(); + + if (!pdev) + goto out; + bus = pdev->bus; + + /* Enable interrupts for this device. */ + if (bus->host_pci && + ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) { + u32 coremask; + + /* Calculate the "coremask" for the device. */ + coremask = (1 << dev->core_index); + + err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp); + if (err) + goto out; + tmp |= coremask << 8; + err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp); + if (err) + goto out; + } else { + u32 intvec; + + intvec = ssb_read32(pdev, SSB_INTVEC); + if ((bus->chip_id & 0xFF00) == 0x4400) { + /* Workaround: On the BCM44XX the BPFLAG routing + * bit is wrong. Use a hardcoded constant. */ + intvec |= 0x00000002; + } else { + tmp = ssb_read32(dev, SSB_TPSFLAG); + tmp &= SSB_TPSFLAG_BPFLAG; + intvec |= tmp; + } + ssb_write32(pdev, SSB_INTVEC, intvec); + } + + /* Setup PCIcore operation. */ + if (pc->setup_done) + goto out; + if (pdev->id.coreid == SSB_DEV_PCI) { + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_PREF; + tmp |= SSB_PCICORE_SBTOPCI_BURST; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + + if (pdev->id.revision < 5) { + tmp = ssb_read32(pdev, SSB_IMCFGLO); + tmp &= ~SSB_IMCFGLO_SERTO; + tmp |= 2; + tmp &= ~SSB_IMCFGLO_REQTO; + tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; + ssb_write32(pdev, SSB_IMCFGLO, tmp); + ssb_commit_settings(bus); + } else if (pdev->id.revision >= 11) { + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_MRM; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + } + } else { + WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); + //TODO: Better make defines for all these magic PCIE values. + if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { + /* TLP Workaround register. */ + tmp = ssb_pcie_read(pc, 0x4); + tmp |= 0x8; + ssb_pcie_write(pc, 0x4, tmp); + } + if (pdev->id.revision == 0) { + const u8 serdes_rx_device = 0x1F; + + ssb_pcie_mdio_write(pc, serdes_rx_device, + 2 /* Timer */, 0x8128); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 6 /* CDR */, 0x0100); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 7 /* CDR BW */, 0x1466); + } else if (pdev->id.revision == 1) { + /* DLLP Link Control register. */ + tmp = ssb_pcie_read(pc, 0x100); + tmp |= 0x40; + ssb_pcie_write(pc, 0x100, tmp); + } + } + pc->setup_done = 1; +out: + return err; +} +EXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable); diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c new file mode 100644 index 000000000000..74d5182db4b2 --- /dev/null +++ b/drivers/ssb/main.c @@ -0,0 +1,1162 @@ +/* + * Sonics Silicon Backplane + * Subsystem core + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "ssb_private.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +MODULE_DESCRIPTION("Sonics Silicon Backplane driver"); +MODULE_LICENSE("GPL"); + + +/* Temporary list of yet-to-be-attached buses */ +static LIST_HEAD(attach_queue); +/* List if running buses */ +static LIST_HEAD(buses); +/* Software ID counter */ +static unsigned int next_busnumber; +/* buses_mutes locks the two buslists and the next_busnumber. + * Don't lock this directly, but use ssb_buses_[un]lock() below. */ +static DEFINE_MUTEX(buses_mutex); + +/* There are differences in the codeflow, if the bus is + * initialized from early boot, as various needed services + * are not available early. This is a mechanism to delay + * these initializations to after early boot has finished. + * It's also used to avoid mutex locking, as that's not + * available and needed early. */ +static bool ssb_is_early_boot = 1; + +static void ssb_buses_lock(void); +static void ssb_buses_unlock(void); + + +#ifdef CONFIG_SSB_PCIHOST +struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev) +{ + struct ssb_bus *bus; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + if (bus->bustype == SSB_BUSTYPE_PCI && + bus->host_pci == pdev) + goto found; + } + bus = NULL; +found: + ssb_buses_unlock(); + + return bus; +} +#endif /* CONFIG_SSB_PCIHOST */ + +static struct ssb_device *ssb_device_get(struct ssb_device *dev) +{ + if (dev) + get_device(dev->dev); + return dev; +} + +static void ssb_device_put(struct ssb_device *dev) +{ + if (dev) + put_device(dev->dev); +} + +static int ssb_bus_resume(struct ssb_bus *bus) +{ + int err; + + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + err = ssb_pcmcia_init(bus); + if (err) { + /* No need to disable XTAL, as we don't have one on PCMCIA. */ + return err; + } + ssb_chipco_resume(&bus->chipco); + + return 0; +} + +static int ssb_device_resume(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv; + struct ssb_bus *bus; + int err = 0; + + bus = ssb_dev->bus; + if (bus->suspend_cnt == bus->nr_devices) { + err = ssb_bus_resume(bus); + if (err) + return err; + } + bus->suspend_cnt--; + if (dev->driver) { + ssb_drv = drv_to_ssb_drv(dev->driver); + if (ssb_drv && ssb_drv->resume) + err = ssb_drv->resume(ssb_dev); + if (err) + goto out; + } +out: + return err; +} + +static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) +{ + ssb_chipco_suspend(&bus->chipco, state); + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + + /* Reset HW state information in memory, so that HW is + * completely reinitialized on resume. */ + bus->mapped_device = NULL; +#ifdef CONFIG_SSB_DRIVER_PCICORE + bus->pcicore.setup_done = 0; +#endif +#ifdef CONFIG_SSB_DEBUG + bus->powered_up = 0; +#endif +} + +static int ssb_device_suspend(struct device *dev, pm_message_t state) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv; + struct ssb_bus *bus; + int err = 0; + + if (dev->driver) { + ssb_drv = drv_to_ssb_drv(dev->driver); + if (ssb_drv && ssb_drv->suspend) + err = ssb_drv->suspend(ssb_dev, state); + if (err) + goto out; + } + + bus = ssb_dev->bus; + bus->suspend_cnt++; + if (bus->suspend_cnt == bus->nr_devices) { + /* All devices suspended. Shutdown the bus. */ + ssb_bus_suspend(bus, state); + } + +out: + return err; +} + +#ifdef CONFIG_SSB_PCIHOST +int ssb_devices_freeze(struct ssb_bus *bus) +{ + struct ssb_device *dev; + struct ssb_driver *drv; + int err = 0; + int i; + pm_message_t state = PMSG_FREEZE; + + /* First check that we are capable to freeze all devices. */ + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (!drv) + continue; + if (!drv->suspend) { + /* Nope, can't suspend this one. */ + return -EOPNOTSUPP; + } + } + /* Now suspend all devices */ + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (!drv) + continue; + err = drv->suspend(dev, state); + if (err) { + ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n", + dev->dev->bus_id); + goto err_unwind; + } + } + + return 0; +err_unwind: + for (i--; i >= 0; i--) { + dev = &(bus->devices[i]); + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (!drv) + continue; + if (drv->resume) + drv->resume(dev); + } + return err; +} + +int ssb_devices_thaw(struct ssb_bus *bus) +{ + struct ssb_device *dev; + struct ssb_driver *drv; + int err; + int i; + + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (!drv) + continue; + if (SSB_WARN_ON(!drv->resume)) + continue; + err = drv->resume(dev); + if (err) { + ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", + dev->dev->bus_id); + } + } + + return 0; +} +#endif /* CONFIG_SSB_PCIHOST */ + +static void ssb_device_shutdown(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv; + + if (!dev->driver) + return; + ssb_drv = drv_to_ssb_drv(dev->driver); + if (ssb_drv && ssb_drv->shutdown) + ssb_drv->shutdown(ssb_dev); +} + +static int ssb_device_remove(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver); + + if (ssb_drv && ssb_drv->remove) + ssb_drv->remove(ssb_dev); + ssb_device_put(ssb_dev); + + return 0; +} + +static int ssb_device_probe(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver); + int err = 0; + + ssb_device_get(ssb_dev); + if (ssb_drv && ssb_drv->probe) + err = ssb_drv->probe(ssb_dev, &ssb_dev->id); + if (err) + ssb_device_put(ssb_dev); + + return err; +} + +static int ssb_match_devid(const struct ssb_device_id *tabid, + const struct ssb_device_id *devid) +{ + if ((tabid->vendor != devid->vendor) && + tabid->vendor != SSB_ANY_VENDOR) + return 0; + if ((tabid->coreid != devid->coreid) && + tabid->coreid != SSB_ANY_ID) + return 0; + if ((tabid->revision != devid->revision) && + tabid->revision != SSB_ANY_REV) + return 0; + return 1; +} + +static int ssb_bus_match(struct device *dev, struct device_driver *drv) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv = drv_to_ssb_drv(drv); + const struct ssb_device_id *id; + + for (id = ssb_drv->id_table; + id->vendor || id->coreid || id->revision; + id++) { + if (ssb_match_devid(id, &ssb_dev->id)) + return 1; /* found */ + } + + return 0; +} + +static int ssb_device_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + int ret, i = 0, length = 0; + + if (!dev) + return -ENODEV; + + ret = add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MODALIAS=ssb:v%04Xid%04Xrev%02X", + ssb_dev->id.vendor, ssb_dev->id.coreid, + ssb_dev->id.revision); + envp[i] = NULL; + + return ret; +} + +static struct bus_type ssb_bustype = { + .name = "ssb", + .match = ssb_bus_match, + .probe = ssb_device_probe, + .remove = ssb_device_remove, + .shutdown = ssb_device_shutdown, + .suspend = ssb_device_suspend, + .resume = ssb_device_resume, + .uevent = ssb_device_uevent, +}; + +static void ssb_buses_lock(void) +{ + /* See the comment at the ssb_is_early_boot definition */ + if (!ssb_is_early_boot) + mutex_lock(&buses_mutex); +} + +static void ssb_buses_unlock(void) +{ + /* See the comment at the ssb_is_early_boot definition */ + if (!ssb_is_early_boot) + mutex_unlock(&buses_mutex); +} + +static void ssb_devices_unregister(struct ssb_bus *bus) +{ + struct ssb_device *sdev; + int i; + + for (i = bus->nr_devices - 1; i >= 0; i--) { + sdev = &(bus->devices[i]); + if (sdev->dev) + device_unregister(sdev->dev); + } +} + +void ssb_bus_unregister(struct ssb_bus *bus) +{ + ssb_buses_lock(); + ssb_devices_unregister(bus); + list_del(&bus->list); + ssb_buses_unlock(); + + /* ssb_pcmcia_exit(bus); */ + ssb_pci_exit(bus); + ssb_iounmap(bus); +} +EXPORT_SYMBOL(ssb_bus_unregister); + +static void ssb_release_dev(struct device *dev) +{ + struct __ssb_dev_wrapper *devwrap; + + devwrap = container_of(dev, struct __ssb_dev_wrapper, dev); + kfree(devwrap); +} + +static int ssb_devices_register(struct ssb_bus *bus) +{ + struct ssb_device *sdev; + struct device *dev; + struct __ssb_dev_wrapper *devwrap; + int i, err = 0; + int dev_idx = 0; + + for (i = 0; i < bus->nr_devices; i++) { + sdev = &(bus->devices[i]); + + /* We don't register SSB-system devices to the kernel, + * as the drivers for them are built into SSB. */ + switch (sdev->id.coreid) { + case SSB_DEV_CHIPCOMMON: + case SSB_DEV_PCI: + case SSB_DEV_PCIE: + case SSB_DEV_PCMCIA: + case SSB_DEV_MIPS: + case SSB_DEV_MIPS_3302: + case SSB_DEV_EXTIF: + continue; + } + + devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL); + if (!devwrap) { + ssb_printk(KERN_ERR PFX + "Could not allocate device\n"); + err = -ENOMEM; + goto error; + } + dev = &devwrap->dev; + devwrap->sdev = sdev; + + dev->release = ssb_release_dev; + dev->bus = &ssb_bustype; + snprintf(dev->bus_id, sizeof(dev->bus_id), + "ssb%u:%d", bus->busnumber, dev_idx); + + switch (bus->bustype) { + case SSB_BUSTYPE_PCI: +#ifdef CONFIG_SSB_PCIHOST + sdev->irq = bus->host_pci->irq; + dev->parent = &bus->host_pci->dev; +#endif + break; + case SSB_BUSTYPE_PCMCIA: +#ifdef CONFIG_SSB_PCMCIAHOST + dev->parent = &bus->host_pcmcia->dev; +#endif + break; + case SSB_BUSTYPE_SSB: + break; + } + + sdev->dev = dev; + err = device_register(dev); + if (err) { + ssb_printk(KERN_ERR PFX + "Could not register %s\n", + dev->bus_id); + /* Set dev to NULL to not unregister + * dev on error unwinding. */ + sdev->dev = NULL; + kfree(devwrap); + goto error; + } + dev_idx++; + } + + return 0; +error: + /* Unwind the already registered devices. */ + ssb_devices_unregister(bus); + return err; +} + +/* Needs ssb_buses_lock() */ +static int ssb_attach_queued_buses(void) +{ + struct ssb_bus *bus, *n; + int err = 0; + int drop_them_all = 0; + + list_for_each_entry_safe(bus, n, &attach_queue, list) { + if (drop_them_all) { + list_del(&bus->list); + continue; + } + /* Can't init the PCIcore in ssb_bus_register(), as that + * is too early in boot for embedded systems + * (no udelay() available). So do it here in attach stage. + */ + err = ssb_bus_powerup(bus, 0); + if (err) + goto error; + ssb_pcicore_init(&bus->pcicore); + ssb_bus_may_powerdown(bus); + + err = ssb_devices_register(bus); +error: + if (err) { + drop_them_all = 1; + list_del(&bus->list); + continue; + } + list_move_tail(&bus->list, &buses); + } + + return err; +} + +static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + return readw(bus->mmio + offset); +} + +static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + return readl(bus->mmio + offset); +} + +static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + writew(value, bus->mmio + offset); +} + +static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + writel(value, bus->mmio + offset); +} + +/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ +static const struct ssb_bus_ops ssb_ssb_ops = { + .read16 = ssb_ssb_read16, + .read32 = ssb_ssb_read32, + .write16 = ssb_ssb_write16, + .write32 = ssb_ssb_write32, +}; + +static int ssb_fetch_invariants(struct ssb_bus *bus, + ssb_invariants_func_t get_invariants) +{ + struct ssb_init_invariants iv; + int err; + + memset(&iv, 0, sizeof(iv)); + err = get_invariants(bus, &iv); + if (err) + goto out; + memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo)); + memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom)); +out: + return err; +} + +static int ssb_bus_register(struct ssb_bus *bus, + ssb_invariants_func_t get_invariants, + unsigned long baseaddr) +{ + int err; + + spin_lock_init(&bus->bar_lock); + INIT_LIST_HEAD(&bus->list); + + /* Powerup the bus */ + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + if (err) + goto out; + ssb_buses_lock(); + bus->busnumber = next_busnumber; + /* Scan for devices (cores) */ + err = ssb_bus_scan(bus, baseaddr); + if (err) + goto err_disable_xtal; + + /* Init PCI-host device (if any) */ + err = ssb_pci_init(bus); + if (err) + goto err_unmap; + /* Init PCMCIA-host device (if any) */ + err = ssb_pcmcia_init(bus); + if (err) + goto err_pci_exit; + + /* Initialize basic system devices (if available) */ + err = ssb_bus_powerup(bus, 0); + if (err) + goto err_pcmcia_exit; + ssb_chipcommon_init(&bus->chipco); + ssb_mipscore_init(&bus->mipscore); + err = ssb_fetch_invariants(bus, get_invariants); + if (err) { + ssb_bus_may_powerdown(bus); + goto err_pcmcia_exit; + } + ssb_bus_may_powerdown(bus); + + /* Queue it for attach. + * See the comment at the ssb_is_early_boot definition. */ + list_add_tail(&bus->list, &attach_queue); + if (!ssb_is_early_boot) { + /* This is not early boot, so we must attach the bus now */ + err = ssb_attach_queued_buses(); + if (err) + goto err_dequeue; + } + next_busnumber++; + ssb_buses_unlock(); + +out: + return err; + +err_dequeue: + list_del(&bus->list); +err_pcmcia_exit: +/* ssb_pcmcia_exit(bus); */ +err_pci_exit: + ssb_pci_exit(bus); +err_unmap: + ssb_iounmap(bus); +err_disable_xtal: + ssb_buses_unlock(); + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + return err; +} + +#ifdef CONFIG_SSB_PCIHOST +int ssb_bus_pcibus_register(struct ssb_bus *bus, + struct pci_dev *host_pci) +{ + int err; + + bus->bustype = SSB_BUSTYPE_PCI; + bus->host_pci = host_pci; + bus->ops = &ssb_pci_ops; + + err = ssb_bus_register(bus, ssb_pci_get_invariants, 0); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "PCI device %s\n", host_pci->dev.bus_id); + } + + return err; +} +EXPORT_SYMBOL(ssb_bus_pcibus_register); +#endif /* CONFIG_SSB_PCIHOST */ + +#ifdef CONFIG_SSB_PCMCIAHOST +int ssb_bus_pcmciabus_register(struct ssb_bus *bus, + struct pcmcia_device *pcmcia_dev, + unsigned long baseaddr) +{ + int err; + + bus->bustype = SSB_BUSTYPE_PCMCIA; + bus->host_pcmcia = pcmcia_dev; + bus->ops = &ssb_pcmcia_ops; + + err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "PCMCIA device %s\n", pcmcia_dev->devname); + } + + return err; +} +EXPORT_SYMBOL(ssb_bus_pcmciabus_register); +#endif /* CONFIG_SSB_PCMCIAHOST */ + +int ssb_bus_ssbbus_register(struct ssb_bus *bus, + unsigned long baseaddr, + ssb_invariants_func_t get_invariants) +{ + int err; + + bus->bustype = SSB_BUSTYPE_SSB; + bus->ops = &ssb_ssb_ops; + + err = ssb_bus_register(bus, get_invariants, baseaddr); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at " + "address 0x%08lX\n", baseaddr); + } + + return err; +} + +int __ssb_driver_register(struct ssb_driver *drv, struct module *owner) +{ + drv->drv.name = drv->name; + drv->drv.bus = &ssb_bustype; + drv->drv.owner = owner; + + return driver_register(&drv->drv); +} +EXPORT_SYMBOL(__ssb_driver_register); + +void ssb_driver_unregister(struct ssb_driver *drv) +{ + driver_unregister(&drv->drv); +} +EXPORT_SYMBOL(ssb_driver_unregister); + +void ssb_set_devtypedata(struct ssb_device *dev, void *data) +{ + struct ssb_bus *bus = dev->bus; + struct ssb_device *ent; + int i; + + for (i = 0; i < bus->nr_devices; i++) { + ent = &(bus->devices[i]); + if (ent->id.vendor != dev->id.vendor) + continue; + if (ent->id.coreid != dev->id.coreid) + continue; + + ent->devtypedata = data; + } +} +EXPORT_SYMBOL(ssb_set_devtypedata); + +static u32 clkfactor_f6_resolve(u32 v) +{ + /* map the magic values */ + switch (v) { + case SSB_CHIPCO_CLK_F6_2: + return 2; + case SSB_CHIPCO_CLK_F6_3: + return 3; + case SSB_CHIPCO_CLK_F6_4: + return 4; + case SSB_CHIPCO_CLK_F6_5: + return 5; + case SSB_CHIPCO_CLK_F6_6: + return 6; + case SSB_CHIPCO_CLK_F6_7: + return 7; + } + return 0; +} + +/* Calculate the speed the backplane would run at a given set of clockcontrol values */ +u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m) +{ + u32 n1, n2, clock, m1, m2, m3, mc; + + n1 = (n & SSB_CHIPCO_CLK_N1); + n2 = ((n & SSB_CHIPCO_CLK_N2) >> SSB_CHIPCO_CLK_N2_SHIFT); + + switch (plltype) { + case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ + if (m & SSB_CHIPCO_CLK_T6_MMASK) + return SSB_CHIPCO_CLK_T6_M0; + return SSB_CHIPCO_CLK_T6_M1; + case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ + case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ + case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ + case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ + n1 = clkfactor_f6_resolve(n1); + n2 += SSB_CHIPCO_CLK_F5_BIAS; + break; + case SSB_PLLTYPE_2: /* 48Mhz, 4 dividers */ + n1 += SSB_CHIPCO_CLK_T2_BIAS; + n2 += SSB_CHIPCO_CLK_T2_BIAS; + SSB_WARN_ON(!((n1 >= 2) && (n1 <= 7))); + SSB_WARN_ON(!((n2 >= 5) && (n2 <= 23))); + break; + case SSB_PLLTYPE_5: /* 25Mhz, 4 dividers */ + return 100000000; + default: + SSB_WARN_ON(1); + } + + switch (plltype) { + case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ + case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ + clock = SSB_CHIPCO_CLK_BASE2 * n1 * n2; + break; + default: + clock = SSB_CHIPCO_CLK_BASE1 * n1 * n2; + } + if (!clock) + return 0; + + m1 = (m & SSB_CHIPCO_CLK_M1); + m2 = ((m & SSB_CHIPCO_CLK_M2) >> SSB_CHIPCO_CLK_M2_SHIFT); + m3 = ((m & SSB_CHIPCO_CLK_M3) >> SSB_CHIPCO_CLK_M3_SHIFT); + mc = ((m & SSB_CHIPCO_CLK_MC) >> SSB_CHIPCO_CLK_MC_SHIFT); + + switch (plltype) { + case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ + case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ + case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ + case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ + m1 = clkfactor_f6_resolve(m1); + if ((plltype == SSB_PLLTYPE_1) || + (plltype == SSB_PLLTYPE_3)) + m2 += SSB_CHIPCO_CLK_F5_BIAS; + else + m2 = clkfactor_f6_resolve(m2); + m3 = clkfactor_f6_resolve(m3); + + switch (mc) { + case SSB_CHIPCO_CLK_MC_BYPASS: + return clock; + case SSB_CHIPCO_CLK_MC_M1: + return (clock / m1); + case SSB_CHIPCO_CLK_MC_M1M2: + return (clock / (m1 * m2)); + case SSB_CHIPCO_CLK_MC_M1M2M3: + return (clock / (m1 * m2 * m3)); + case SSB_CHIPCO_CLK_MC_M1M3: + return (clock / (m1 * m3)); + } + return 0; + case SSB_PLLTYPE_2: + m1 += SSB_CHIPCO_CLK_T2_BIAS; + m2 += SSB_CHIPCO_CLK_T2M2_BIAS; + m3 += SSB_CHIPCO_CLK_T2_BIAS; + SSB_WARN_ON(!((m1 >= 2) && (m1 <= 7))); + SSB_WARN_ON(!((m2 >= 3) && (m2 <= 10))); + SSB_WARN_ON(!((m3 >= 2) && (m3 <= 7))); + + if (!(mc & SSB_CHIPCO_CLK_T2MC_M1BYP)) + clock /= m1; + if (!(mc & SSB_CHIPCO_CLK_T2MC_M2BYP)) + clock /= m2; + if (!(mc & SSB_CHIPCO_CLK_T2MC_M3BYP)) + clock /= m3; + return clock; + default: + SSB_WARN_ON(1); + } + return 0; +} + +/* Get the current speed the backplane is running at */ +u32 ssb_clockspeed(struct ssb_bus *bus) +{ + u32 rate; + u32 plltype; + u32 clkctl_n, clkctl_m; + + if (ssb_extif_available(&bus->extif)) + ssb_extif_get_clockcontrol(&bus->extif, &plltype, + &clkctl_n, &clkctl_m); + else if (bus->chipco.dev) + ssb_chipco_get_clockcontrol(&bus->chipco, &plltype, + &clkctl_n, &clkctl_m); + else + return 0; + + if (bus->chip_id == 0x5365) { + rate = 100000000; + } else { + rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m); + if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */ + rate /= 2; + } + + return rate; +} +EXPORT_SYMBOL(ssb_clockspeed); + +static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) +{ + /* The REJECT bit changed position in TMSLOW between + * Backplane revisions. */ + switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) { + case SSB_IDLOW_SSBREV_22: + return SSB_TMSLOW_REJECT_22; + case SSB_IDLOW_SSBREV_23: + return SSB_TMSLOW_REJECT_23; + default: + WARN_ON(1); + } + return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); +} + +int ssb_device_is_enabled(struct ssb_device *dev) +{ + u32 val; + u32 reject; + + reject = ssb_tmslow_reject_bitmask(dev); + val = ssb_read32(dev, SSB_TMSLOW); + val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject; + + return (val == SSB_TMSLOW_CLOCK); +} +EXPORT_SYMBOL(ssb_device_is_enabled); + +static void ssb_flush_tmslow(struct ssb_device *dev) +{ + /* Make _really_ sure the device has finished the TMSLOW + * register write transaction, as we risk running into + * a machine check exception otherwise. + * Do this by reading the register back to commit the + * PCI write and delay an additional usec for the device + * to react to the change. */ + ssb_read32(dev, SSB_TMSLOW); + udelay(1); +} + +void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags) +{ + u32 val; + + ssb_device_disable(dev, core_specific_flags); + ssb_write32(dev, SSB_TMSLOW, + SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK | + SSB_TMSLOW_FGC | core_specific_flags); + ssb_flush_tmslow(dev); + + /* Clear SERR if set. This is a hw bug workaround. */ + if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_SERR) + ssb_write32(dev, SSB_TMSHIGH, 0); + + val = ssb_read32(dev, SSB_IMSTATE); + if (val & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) { + val &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO); + ssb_write32(dev, SSB_IMSTATE, val); + } + + ssb_write32(dev, SSB_TMSLOW, + SSB_TMSLOW_CLOCK | SSB_TMSLOW_FGC | + core_specific_flags); + ssb_flush_tmslow(dev); + + ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK | + core_specific_flags); + ssb_flush_tmslow(dev); +} +EXPORT_SYMBOL(ssb_device_enable); + +/* Wait for a bit in a register to get set or unset. + * timeout is in units of ten-microseconds */ +static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask, + int timeout, int set) +{ + int i; + u32 val; + + for (i = 0; i < timeout; i++) { + val = ssb_read32(dev, reg); + if (set) { + if (val & bitmask) + return 0; + } else { + if (!(val & bitmask)) + return 0; + } + udelay(10); + } + printk(KERN_ERR PFX "Timeout waiting for bitmask %08X on " + "register %04X to %s.\n", + bitmask, reg, (set ? "set" : "clear")); + + return -ETIMEDOUT; +} + +void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags) +{ + u32 reject; + + if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET) + return; + + reject = ssb_tmslow_reject_bitmask(dev); + ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK); + ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1); + ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0); + ssb_write32(dev, SSB_TMSLOW, + SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | + reject | SSB_TMSLOW_RESET | + core_specific_flags); + ssb_flush_tmslow(dev); + + ssb_write32(dev, SSB_TMSLOW, + reject | SSB_TMSLOW_RESET | + core_specific_flags); + ssb_flush_tmslow(dev); +} +EXPORT_SYMBOL(ssb_device_disable); + +u32 ssb_dma_translation(struct ssb_device *dev) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_SSB: + return 0; + case SSB_BUSTYPE_PCI: + case SSB_BUSTYPE_PCMCIA: + return SSB_PCI_DMA; + } + return 0; +} +EXPORT_SYMBOL(ssb_dma_translation); + +int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask) +{ + struct device *dev = ssb_dev->dev; + +#ifdef CONFIG_SSB_PCIHOST + if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI && + !dma_supported(dev, mask)) + return -EIO; +#endif + dev->coherent_dma_mask = mask; + dev->dma_mask = &dev->coherent_dma_mask; + + return 0; +} +EXPORT_SYMBOL(ssb_dma_set_mask); + +int ssb_bus_may_powerdown(struct ssb_bus *bus) +{ + struct ssb_chipcommon *cc; + int err = 0; + + /* On buses where more than one core may be working + * at a time, we must not powerdown stuff if there are + * still cores that may want to run. */ + if (bus->bustype == SSB_BUSTYPE_SSB) + goto out; + + cc = &bus->chipco; + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + if (err) + goto error; +out: +#ifdef CONFIG_SSB_DEBUG + bus->powered_up = 0; +#endif + return err; +error: + ssb_printk(KERN_ERR PFX "Bus powerdown failed\n"); + goto out; +} +EXPORT_SYMBOL(ssb_bus_may_powerdown); + +int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) +{ + struct ssb_chipcommon *cc; + int err; + enum ssb_clkmode mode; + + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + if (err) + goto error; + cc = &bus->chipco; + mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; + ssb_chipco_set_clockmode(cc, mode); + +#ifdef CONFIG_SSB_DEBUG + bus->powered_up = 1; +#endif + return 0; +error: + ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); + return err; +} +EXPORT_SYMBOL(ssb_bus_powerup); + +u32 ssb_admatch_base(u32 adm) +{ + u32 base = 0; + + switch (adm & SSB_ADM_TYPE) { + case SSB_ADM_TYPE0: + base = (adm & SSB_ADM_BASE0); + break; + case SSB_ADM_TYPE1: + SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ + base = (adm & SSB_ADM_BASE1); + break; + case SSB_ADM_TYPE2: + SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ + base = (adm & SSB_ADM_BASE2); + break; + default: + SSB_WARN_ON(1); + } + + return base; +} +EXPORT_SYMBOL(ssb_admatch_base); + +u32 ssb_admatch_size(u32 adm) +{ + u32 size = 0; + + switch (adm & SSB_ADM_TYPE) { + case SSB_ADM_TYPE0: + size = ((adm & SSB_ADM_SZ0) >> SSB_ADM_SZ0_SHIFT); + break; + case SSB_ADM_TYPE1: + SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ + size = ((adm & SSB_ADM_SZ1) >> SSB_ADM_SZ1_SHIFT); + break; + case SSB_ADM_TYPE2: + SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ + size = ((adm & SSB_ADM_SZ2) >> SSB_ADM_SZ2_SHIFT); + break; + default: + SSB_WARN_ON(1); + } + size = (1 << (size + 1)); + + return size; +} +EXPORT_SYMBOL(ssb_admatch_size); + +static int __init ssb_modinit(void) +{ + int err; + + /* See the comment at the ssb_is_early_boot definition */ + ssb_is_early_boot = 0; + err = bus_register(&ssb_bustype); + if (err) + return err; + + /* Maybe we already registered some buses at early boot. + * Check for this and attach them + */ + ssb_buses_lock(); + err = ssb_attach_queued_buses(); + ssb_buses_unlock(); + if (err) + bus_unregister(&ssb_bustype); + + err = b43_pci_ssb_bridge_init(); + if (err) { + ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " + "initialization failed"); + /* don't fail SSB init because of this */ + err = 0; + } + + return err; +} +subsys_initcall(ssb_modinit); + +static void __exit ssb_modexit(void) +{ + b43_pci_ssb_bridge_exit(); + bus_unregister(&ssb_bustype); +} +module_exit(ssb_modexit) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c new file mode 100644 index 000000000000..3d23ca4befe3 --- /dev/null +++ b/drivers/ssb/pci.c @@ -0,0 +1,740 @@ +/* + * Sonics Silicon Backplane PCI-Hostbus related functions. + * + * Copyright (C) 2005-2006 Michael Buesch + * Copyright (C) 2005 Martin Langer + * Copyright (C) 2005 Stefano Brivio + * Copyright (C) 2005 Danny van Dyk + * Copyright (C) 2005 Andreas Jaggi + * + * Derived from the Broadcom 4400 device driver. + * Copyright (C) 2002 David S. Miller (davem@redhat.com) + * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) + * Copyright (C) 2006 Broadcom Corporation. + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include +#include + +#include "ssb_private.h" + + +/* Define the following to 1 to enable a printk on each coreswitch. */ +#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0 + + +/* Lowlevel coreswitching */ +int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx) +{ + int err; + int attempts = 0; + u32 cur_core; + + while (1) { + err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN, + (coreidx * SSB_CORE_SIZE) + + SSB_ENUM_BASE); + if (err) + goto error; + err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN, + &cur_core); + if (err) + goto error; + cur_core = (cur_core - SSB_ENUM_BASE) + / SSB_CORE_SIZE; + if (cur_core == coreidx) + break; + + if (attempts++ > SSB_BAR0_MAX_RETRIES) + goto error; + udelay(10); + } + return 0; +error: + ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); + return -ENODEV; +} + +int ssb_pci_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + int err; + unsigned long flags; + +#if SSB_VERBOSE_PCICORESWITCH_DEBUG + ssb_printk(KERN_INFO PFX + "Switching to %s core, index %d\n", + ssb_core_name(dev->id.coreid), + dev->core_index); +#endif + + spin_lock_irqsave(&bus->bar_lock, flags); + err = ssb_pci_switch_coreidx(bus, dev->core_index); + if (!err) + bus->mapped_device = dev; + spin_unlock_irqrestore(&bus->bar_lock, flags); + + return err; +} + +/* Enable/disable the on board crystal oscillator and/or PLL. */ +int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on) +{ + int err; + u32 in, out, outenable; + u16 pci_status; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return 0; + + err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in); + if (err) + goto err_pci; + err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out); + if (err) + goto err_pci; + err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable); + if (err) + goto err_pci; + + outenable |= what; + + if (turn_on) { + /* Avoid glitching the clock if GPRS is already using it. + * We can't actually read the state of the PLLPD so we infer it + * by the value of XTAL_PU which *is* readable via gpioin. + */ + if (!(in & SSB_GPIO_XTAL)) { + if (what & SSB_GPIO_XTAL) { + /* Turn the crystal on */ + out |= SSB_GPIO_XTAL; + if (what & SSB_GPIO_PLL) + out |= SSB_GPIO_PLL; + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); + if (err) + goto err_pci; + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, + outenable); + if (err) + goto err_pci; + msleep(1); + } + if (what & SSB_GPIO_PLL) { + /* Turn the PLL on */ + out &= ~SSB_GPIO_PLL; + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); + if (err) + goto err_pci; + msleep(5); + } + } + + err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status); + if (err) + goto err_pci; + pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT; + err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status); + if (err) + goto err_pci; + } else { + if (what & SSB_GPIO_XTAL) { + /* Turn the crystal off */ + out &= ~SSB_GPIO_XTAL; + } + if (what & SSB_GPIO_PLL) { + /* Turn the PLL off */ + out |= SSB_GPIO_PLL; + } + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); + if (err) + goto err_pci; + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable); + if (err) + goto err_pci; + } + +out: + return err; + +err_pci: + printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n"); + err = -EBUSY; + goto out; +} + +/* 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) \ + out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) + +static inline u8 ssb_crc8(u8 crc, u8 data) +{ + /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */ + static const u8 t[] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, + }; + return t[crc ^ data]; +} + +static u8 ssb_sprom_crc(const u16 *sprom) +{ + int word; + u8 crc = 0xFF; + + for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) { + crc = ssb_crc8(crc, sprom[word] & 0x00FF); + crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8); + } + crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF); + crc ^= 0xFF; + + return crc; +} + +static int sprom_check_crc(const u16 *sprom) +{ + u8 crc; + u8 expected_crc; + u16 tmp; + + crc = ssb_sprom_crc(sprom); + tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC; + expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; + if (crc != expected_crc) + return -EPROTO; + + return 0; +} + +static void sprom_do_read(struct ssb_bus *bus, u16 *sprom) +{ + int i; + + for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) + sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2)); +} + +static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) +{ + struct pci_dev *pdev = bus->host_pci; + int i, err; + u32 spromctl; + + ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); + err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl |= SSB_SPROMCTL_WE; + err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + ssb_printk(KERN_NOTICE PFX "[ 0%%"); + msleep(500); + for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { + if (i == SSB_SPROMSIZE_WORDS / 4) + ssb_printk("25%%"); + else if (i == SSB_SPROMSIZE_WORDS / 2) + ssb_printk("50%%"); + else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3) + ssb_printk("75%%"); + else if (i % 2) + ssb_printk("."); + writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2)); + mmiowb(); + msleep(20); + } + err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl &= ~SSB_SPROMCTL_WE; + err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + msleep(500); + ssb_printk("100%% ]\n"); + ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); + + return 0; +err_ctlreg: + ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + return err; +} + +static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) +{ + int i; + u16 v; + + SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0); + SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0); + SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0); + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; + *(((u16 *)out->il0mac) + i) = cpu_to_be16(v); + } + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM1_ET0MAC) + i]; + *(((u16 *)out->et0mac) + i) = cpu_to_be16(v); + } + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM1_ET1MAC) + i]; + *(((u16 *)out->et1mac) + i) = cpu_to_be16(v); + } + SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); + SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, + SSB_SPROM1_ETHPHY_ET1A_SHIFT); + SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); + SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); + SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); + SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, + SSB_SPROM1_BINF_CCODE_SHIFT); + SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, + SSB_SPROM1_BINF_ANTA_SHIFT); + SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, + SSB_SPROM1_BINF_ANTBG_SHIFT); + SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); + SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); + SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0); + SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0); + SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0); + SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0); + SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1, + SSB_SPROM1_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3, + SSB_SPROM1_GPIOB_P3_SHIFT); + SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, + SSB_SPROM1_MAXPWR_A_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0); + SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, + SSB_SPROM1_ITSSI_A_SHIFT); + SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); + SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); + SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0); + SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG, + SSB_SPROM1_AGAIN_BG_SHIFT); + for (i = 0; i < 4; i++) { + v = in[SPOFF(SSB_SPROM1_OEM) + i]; + *(((u16 *)out->oem) + i) = cpu_to_le16(v); + } +} + +static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in) +{ + int i; + u16 v; + + SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); + SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); + SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, + SSB_SPROM2_MAXP_A_LO_SHIFT); + SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); + SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); + SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); + SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); + SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); + SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); + SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); + for (i = 0; i < 4; i++) { + v = in[SPOFF(SSB_SPROM2_CCODE) + i]; + *(((u16 *)out->country_str) + i) = cpu_to_le16(v); + } +} + +static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in) +{ + out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8; + out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8; + out->ofdmapo <<= 16; + out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8; + out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8; + + out->ofdmalpo = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8; + out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8; + out->ofdmalpo <<= 16; + out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8; + out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8; + + out->ofdmahpo = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8; + out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8; + out->ofdmahpo <<= 16; + out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8; + out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8; + + SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON, + SSB_SPROM3_GPIOLDC_ON_SHIFT); + SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF, + SSB_SPROM3_GPIOLDC_OFF_SHIFT); + SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0); + SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M, + SSB_SPROM3_CCKPO_2M_SHIFT); + SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M, + SSB_SPROM3_CCKPO_55M_SHIFT); + SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M, + SSB_SPROM3_CCKPO_11M_SHIFT); + + out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8; + out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8; + out->ofdmgpo <<= 16; + out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8; + out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8; +} + +static int sprom_extract(struct ssb_bus *bus, + struct ssb_sprom *out, const u16 *in) +{ + memset(out, 0, sizeof(*out)); + + SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0); + SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC, + SSB_SPROM_REVISION_CRC_SHIFT); + + if ((bus->chip_id & 0xFF00) == 0x4400) { + /* Workaround: The BCM44XX chip has a stupid revision + * number stored in the SPROM. + * Always extract r1. */ + sprom_extract_r1(&out->r1, in); + } else { + if (out->revision == 0) + goto unsupported; + if (out->revision >= 1 && out->revision <= 3) + sprom_extract_r1(&out->r1, in); + if (out->revision >= 2 && out->revision <= 3) + sprom_extract_r2(&out->r2, in); + if (out->revision == 3) + sprom_extract_r3(&out->r3, in); + if (out->revision >= 4) + goto unsupported; + } + + return 0; +unsupported: + ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d " + "detected. Will extract v1\n", out->revision); + sprom_extract_r1(&out->r1, in); + return 0; +} + +static int ssb_pci_sprom_get(struct ssb_bus *bus, + struct ssb_sprom *sprom) +{ + int err = -ENOMEM; + u16 *buf; + + buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + if (!buf) + goto out; + sprom_do_read(bus, buf); + err = sprom_check_crc(buf); + if (err) { + ssb_printk(KERN_WARNING PFX + "WARNING: Invalid SPROM CRC (corrupt SPROM)\n"); + } + err = sprom_extract(bus, sprom, buf); + + kfree(buf); +out: + return err; +} + +static void ssb_pci_get_boardinfo(struct ssb_bus *bus, + struct ssb_boardinfo *bi) +{ + pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID, + &bi->vendor); + pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID, + &bi->type); + pci_read_config_word(bus->host_pci, PCI_REVISION_ID, + &bi->rev); +} + +int ssb_pci_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + int err; + + err = ssb_pci_sprom_get(bus, &iv->sprom); + if (err) + goto out; + ssb_pci_get_boardinfo(bus, &iv->boardinfo); + +out: + return err; +} + +#ifdef CONFIG_SSB_DEBUG +static int ssb_pci_assert_buspower(struct ssb_bus *bus) +{ + if (likely(bus->powered_up)) + return 0; + + printk(KERN_ERR PFX "FATAL ERROR: Bus powered down " + "while accessing PCI MMIO space\n"); + if (bus->power_warn_count <= 10) { + bus->power_warn_count++; + dump_stack(); + } + + return -ENODEV; +} +#else /* DEBUG */ +static inline int ssb_pci_assert_buspower(struct ssb_bus *bus) +{ + return 0; +} +#endif /* DEBUG */ + +static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return 0xFFFF; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return 0xFFFF; + } + return readw(bus->mmio + offset); +} + +static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return 0xFFFFFFFF; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return 0xFFFFFFFF; + } + return readl(bus->mmio + offset); +} + +static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return; + } + writew(value, bus->mmio + offset); +} + +static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return; + } + writel(value, bus->mmio + offset); +} + +/* Not "static", as it's used in main.c */ +const struct ssb_bus_ops ssb_pci_ops = { + .read16 = ssb_pci_read16, + .read32 = ssb_pci_read32, + .write16 = ssb_pci_write16, + .write32 = ssb_pci_write32, +}; + +static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) +{ + int i, pos = 0; + + for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { + pos += snprintf(buf + pos, buf_len - pos - 1, + "%04X", swab16(sprom[i]) & 0xFFFF); + } + pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); + + return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, size_t len) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + + if (len < SSB_SPROMSIZE_BYTES * 2) + return -EINVAL; + + while (cnt < SSB_SPROMSIZE_WORDS) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + return 0; +} + +static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); + struct ssb_bus *bus; + u16 *sprom; + int err = -ENODEV; + ssize_t count = 0; + + bus = ssb_pci_dev_to_bus(pdev); + if (!bus) + goto out; + err = -ENOMEM; + sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + if (!sprom) + goto out; + + /* Use interruptible locking, as the SPROM write might + * be holding the lock for several seconds. So allow userspace + * to cancel operation. */ + err = -ERESTARTSYS; + if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) + goto out_kfree; + sprom_do_read(bus, sprom); + mutex_unlock(&bus->pci_sprom_mutex); + + count = sprom2hex(sprom, buf, PAGE_SIZE); + err = 0; + +out_kfree: + kfree(sprom); +out: + return err ? err : count; +} + +static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); + struct ssb_bus *bus; + u16 *sprom; + int res = 0, err = -ENODEV; + + bus = ssb_pci_dev_to_bus(pdev); + if (!bus) + goto out; + err = -ENOMEM; + sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + if (!sprom) + goto out; + err = hex2sprom(sprom, buf, count); + if (err) { + err = -EINVAL; + goto out_kfree; + } + err = sprom_check_crc(sprom); + if (err) { + err = -EINVAL; + goto out_kfree; + } + + /* Use interruptible locking, as the SPROM write might + * be holding the lock for several seconds. So allow userspace + * to cancel operation. */ + err = -ERESTARTSYS; + if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) + goto out_kfree; + err = ssb_devices_freeze(bus); + if (err == -EOPNOTSUPP) { + ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. " + "No suspend support. Is CONFIG_PM enabled?\n"); + goto out_unlock; + } + if (err) { + ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); + goto out_unlock; + } + res = sprom_do_write(bus, sprom); + err = ssb_devices_thaw(bus); + if (err) + ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); +out_unlock: + mutex_unlock(&bus->pci_sprom_mutex); +out_kfree: + kfree(sprom); +out: + if (res) + return res; + return err ? err : count; +} + +static DEVICE_ATTR(ssb_sprom, 0600, + ssb_pci_attr_sprom_show, + ssb_pci_attr_sprom_store); + +void ssb_pci_exit(struct ssb_bus *bus) +{ + struct pci_dev *pdev; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return; + + pdev = bus->host_pci; + device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); +} + +int ssb_pci_init(struct ssb_bus *bus) +{ + struct pci_dev *pdev; + int err; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return 0; + + pdev = bus->host_pci; + mutex_init(&bus->pci_sprom_mutex); + err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); + if (err) + goto out; + +out: + return err; +} diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c new file mode 100644 index 000000000000..82a10abef640 --- /dev/null +++ b/drivers/ssb/pcihost_wrapper.c @@ -0,0 +1,104 @@ +/* + * Sonics Silicon Backplane + * PCI Hostdevice wrapper + * + * Copyright (c) 2005 Martin Langer + * Copyright (c) 2005 Stefano Brivio + * Copyright (c) 2005 Danny van Dyk + * Copyright (c) 2005 Andreas Jaggi + * Copyright (c) 2005-2007 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include + + +#ifdef CONFIG_PM +static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) +{ + pci_save_state(dev); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + + return 0; +} + +static int ssb_pcihost_resume(struct pci_dev *dev) +{ + int err; + + pci_set_power_state(dev, 0); + err = pci_enable_device(dev); + if (err) + return err; + pci_restore_state(dev); + + return 0; +} +#else /* CONFIG_PM */ +# define ssb_pcihost_suspend NULL +# define ssb_pcihost_resume NULL +#endif /* CONFIG_PM */ + +static int ssb_pcihost_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct ssb_bus *ssb; + int err = -ENOMEM; + const char *name; + + ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); + if (!ssb) + goto out; + err = pci_enable_device(dev); + if (err) + goto err_kfree_ssb; + name = dev->dev.bus_id; + if (dev->driver && dev->driver->name) + name = dev->driver->name; + err = pci_request_regions(dev, name); + if (err) + goto err_pci_disable; + pci_set_master(dev); + + err = ssb_bus_pcibus_register(ssb, dev); + if (err) + goto err_pci_release_regions; + + pci_set_drvdata(dev, ssb); + +out: + return err; + +err_pci_release_regions: + pci_release_regions(dev); +err_pci_disable: + pci_disable_device(dev); +err_kfree_ssb: + kfree(ssb); + return err; +} + +static void ssb_pcihost_remove(struct pci_dev *dev) +{ + struct ssb_bus *ssb = pci_get_drvdata(dev); + + ssb_bus_unregister(ssb); + pci_release_regions(dev); + pci_disable_device(dev); + kfree(ssb); + pci_set_drvdata(dev, NULL); +} + +int ssb_pcihost_register(struct pci_driver *driver) +{ + driver->probe = ssb_pcihost_probe; + driver->remove = ssb_pcihost_remove; + driver->suspend = ssb_pcihost_suspend; + driver->resume = ssb_pcihost_resume; + + return pci_register_driver(driver); +} +EXPORT_SYMBOL(ssb_pcihost_register); diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c new file mode 100644 index 000000000000..7c773603b402 --- /dev/null +++ b/drivers/ssb/pcmcia.c @@ -0,0 +1,271 @@ +/* + * Sonics Silicon Backplane + * PCMCIA-Hostbus related functions + * + * Copyright 2006 Johannes Berg + * Copyright 2007 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ssb_private.h" + + +/* Define the following to 1 to enable a printk on each coreswitch. */ +#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0 + + +int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx) +{ + struct pcmcia_device *pdev = bus->host_pcmcia; + int err; + int attempts = 0; + u32 cur_core; + conf_reg_t reg; + u32 addr; + u32 read_addr; + + addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; + while (1) { + reg.Action = CS_WRITE; + reg.Offset = 0x2E; + reg.Value = (addr & 0x0000F000) >> 12; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + reg.Offset = 0x30; + reg.Value = (addr & 0x00FF0000) >> 16; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + reg.Offset = 0x32; + reg.Value = (addr & 0xFF000000) >> 24; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + + read_addr = 0; + + reg.Action = CS_READ; + reg.Offset = 0x2E; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + read_addr |= (reg.Value & 0xF) << 12; + reg.Offset = 0x30; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + read_addr |= reg.Value << 16; + reg.Offset = 0x32; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + read_addr |= reg.Value << 24; + + cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE; + if (cur_core == coreidx) + break; + + if (attempts++ > SSB_BAR0_MAX_RETRIES) + goto error; + udelay(10); + } + + return 0; +error: + ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); + return -ENODEV; +} + +int ssb_pcmcia_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + int err; + unsigned long flags; + +#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG + ssb_printk(KERN_INFO PFX + "Switching to %s core, index %d\n", + ssb_core_name(dev->id.coreid), + dev->core_index); +#endif + + spin_lock_irqsave(&bus->bar_lock, flags); + err = ssb_pcmcia_switch_coreidx(bus, dev->core_index); + if (!err) + bus->mapped_device = dev; + spin_unlock_irqrestore(&bus->bar_lock, flags); + + return err; +} + +int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) +{ + int attempts = 0; + unsigned long flags; + conf_reg_t reg; + int res, err = 0; + + SSB_WARN_ON((seg != 0) && (seg != 1)); + reg.Offset = 0x34; + reg.Function = 0; + spin_lock_irqsave(&bus->bar_lock, flags); + while (1) { + reg.Action = CS_WRITE; + reg.Value = seg; + res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (unlikely(res != CS_SUCCESS)) + goto error; + reg.Value = 0xFF; + reg.Action = CS_READ; + res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (unlikely(res != CS_SUCCESS)) + goto error; + + if (reg.Value == seg) + break; + + if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES)) + goto error; + udelay(10); + } + bus->mapped_pcmcia_seg = seg; +out_unlock: + spin_unlock_irqrestore(&bus->bar_lock, flags); + return err; +error: + ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n"); + err = -ENODEV; + goto out_unlock; +} + +/* These are the main device register access functions. + * do_select_core is inline to have the likely hotpath inline. + * All unlikely codepaths are out-of-line. */ +static inline int do_select_core(struct ssb_bus *bus, + struct ssb_device *dev, + u16 *offset) +{ + int err; + u8 need_seg = (*offset >= 0x800) ? 1 : 0; + + if (unlikely(dev != bus->mapped_device)) { + err = ssb_pcmcia_switch_core(bus, dev); + if (unlikely(err)) + return err; + } + if (unlikely(need_seg != bus->mapped_pcmcia_seg)) { + err = ssb_pcmcia_switch_segment(bus, need_seg); + if (unlikely(err)) + return err; + } + if (need_seg == 1) + *offset -= 0x800; + + return 0; +} + +static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u16 x; + + if (unlikely(do_select_core(bus, dev, &offset))) + return 0xFFFF; + x = readw(bus->mmio + offset); + + return x; +} + +static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u32 x; + + if (unlikely(do_select_core(bus, dev, &offset))) + return 0xFFFFFFFF; + x = readl(bus->mmio + offset); + + return x; +} + +static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(do_select_core(bus, dev, &offset))) + return; + writew(value, bus->mmio + offset); +} + +static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(do_select_core(bus, dev, &offset))) + return; + readw(bus->mmio + offset); + writew(value >> 16, bus->mmio + offset + 2); + readw(bus->mmio + offset); + writew(value, bus->mmio + offset); +} + +/* Not "static", as it's used in main.c */ +const struct ssb_bus_ops ssb_pcmcia_ops = { + .read16 = ssb_pcmcia_read16, + .read32 = ssb_pcmcia_read32, + .write16 = ssb_pcmcia_write16, + .write32 = ssb_pcmcia_write32, +}; + +int ssb_pcmcia_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + //TODO + return 0; +} + +int ssb_pcmcia_init(struct ssb_bus *bus) +{ + conf_reg_t reg; + int err; + + if (bus->bustype != SSB_BUSTYPE_PCMCIA) + return 0; + + /* Switch segment to a known state and sync + * bus->mapped_pcmcia_seg with hardware state. */ + ssb_pcmcia_switch_segment(bus, 0); + + /* Init IRQ routing */ + reg.Action = CS_READ; + reg.Function = 0; + if (bus->chip_id == 0x4306) + reg.Offset = 0x00; + else + reg.Offset = 0x80; + err = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (err != CS_SUCCESS) + goto error; + reg.Action = CS_WRITE; + reg.Value |= 0x04 | 0x01; + err = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (err != CS_SUCCESS) + goto error; + + return 0; +error: + return -ENODEV; +} diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c new file mode 100644 index 000000000000..96258c60919d --- /dev/null +++ b/drivers/ssb/scan.c @@ -0,0 +1,413 @@ +/* + * Sonics Silicon Backplane + * Bus scanning + * + * Copyright (C) 2005-2007 Michael Buesch + * Copyright (C) 2005 Martin Langer + * Copyright (C) 2005 Stefano Brivio + * Copyright (C) 2005 Danny van Dyk + * Copyright (C) 2005 Andreas Jaggi + * Copyright (C) 2006 Broadcom Corporation. + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ssb_private.h" + + +const char *ssb_core_name(u16 coreid) +{ + switch (coreid) { + case SSB_DEV_CHIPCOMMON: + return "ChipCommon"; + case SSB_DEV_ILINE20: + return "ILine 20"; + case SSB_DEV_SDRAM: + return "SDRAM"; + case SSB_DEV_PCI: + return "PCI"; + case SSB_DEV_MIPS: + return "MIPS"; + case SSB_DEV_ETHERNET: + return "Fast Ethernet"; + case SSB_DEV_V90: + return "V90"; + case SSB_DEV_USB11_HOSTDEV: + return "USB 1.1 Hostdev"; + case SSB_DEV_ADSL: + return "ADSL"; + case SSB_DEV_ILINE100: + return "ILine 100"; + case SSB_DEV_IPSEC: + return "IPSEC"; + case SSB_DEV_PCMCIA: + return "PCMCIA"; + case SSB_DEV_INTERNAL_MEM: + return "Internal Memory"; + case SSB_DEV_MEMC_SDRAM: + return "MEMC SDRAM"; + case SSB_DEV_EXTIF: + return "EXTIF"; + case SSB_DEV_80211: + return "IEEE 802.11"; + case SSB_DEV_MIPS_3302: + return "MIPS 3302"; + case SSB_DEV_USB11_HOST: + return "USB 1.1 Host"; + case SSB_DEV_USB11_DEV: + return "USB 1.1 Device"; + case SSB_DEV_USB20_HOST: + return "USB 2.0 Host"; + case SSB_DEV_USB20_DEV: + return "USB 2.0 Device"; + case SSB_DEV_SDIO_HOST: + return "SDIO Host"; + case SSB_DEV_ROBOSWITCH: + return "Roboswitch"; + case SSB_DEV_PARA_ATA: + return "PATA"; + case SSB_DEV_SATA_XORDMA: + return "SATA XOR-DMA"; + case SSB_DEV_ETHERNET_GBIT: + return "GBit Ethernet"; + case SSB_DEV_PCIE: + return "PCI-E"; + case SSB_DEV_MIMO_PHY: + return "MIMO PHY"; + case SSB_DEV_SRAM_CTRLR: + return "SRAM Controller"; + case SSB_DEV_MINI_MACPHY: + return "Mini MACPHY"; + case SSB_DEV_ARM_1176: + return "ARM 1176"; + case SSB_DEV_ARM_7TDMI: + return "ARM 7TDMI"; + } + return "UNKNOWN"; +} + +static u16 pcidev_to_chipid(struct pci_dev *pci_dev) +{ + u16 chipid_fallback = 0; + + switch (pci_dev->device) { + case 0x4301: + chipid_fallback = 0x4301; + break; + case 0x4305 ... 0x4307: + chipid_fallback = 0x4307; + break; + case 0x4403: + chipid_fallback = 0x4402; + break; + case 0x4610 ... 0x4615: + chipid_fallback = 0x4610; + break; + case 0x4710 ... 0x4715: + chipid_fallback = 0x4710; + break; + case 0x4320 ... 0x4325: + chipid_fallback = 0x4309; + break; + case PCI_DEVICE_ID_BCM4401: + case PCI_DEVICE_ID_BCM4401B0: + case PCI_DEVICE_ID_BCM4401B1: + chipid_fallback = 0x4401; + break; + default: + ssb_printk(KERN_ERR PFX + "PCI-ID not in fallback list\n"); + } + + return chipid_fallback; +} + +static u8 chipid_to_nrcores(u16 chipid) +{ + switch (chipid) { + case 0x5365: + return 7; + case 0x4306: + return 6; + case 0x4310: + return 8; + case 0x4307: + case 0x4301: + return 5; + case 0x4401: + case 0x4402: + return 3; + case 0x4710: + case 0x4610: + case 0x4704: + return 9; + default: + ssb_printk(KERN_ERR PFX + "CHIPID not in nrcores fallback list\n"); + } + + return 1; +} + +static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx, + u16 offset) +{ + switch (bus->bustype) { + case SSB_BUSTYPE_SSB: + offset += current_coreidx * SSB_CORE_SIZE; + break; + case SSB_BUSTYPE_PCI: + break; + case SSB_BUSTYPE_PCMCIA: + if (offset >= 0x800) { + ssb_pcmcia_switch_segment(bus, 1); + offset -= 0x800; + } else + ssb_pcmcia_switch_segment(bus, 0); + break; + } + return readl(bus->mmio + offset); +} + +static int scan_switchcore(struct ssb_bus *bus, u8 coreidx) +{ + switch (bus->bustype) { + case SSB_BUSTYPE_SSB: + break; + case SSB_BUSTYPE_PCI: + return ssb_pci_switch_coreidx(bus, coreidx); + case SSB_BUSTYPE_PCMCIA: + return ssb_pcmcia_switch_coreidx(bus, coreidx); + } + return 0; +} + +void ssb_iounmap(struct ssb_bus *bus) +{ + switch (bus->bustype) { + case SSB_BUSTYPE_SSB: + case SSB_BUSTYPE_PCMCIA: + iounmap(bus->mmio); + break; + case SSB_BUSTYPE_PCI: +#ifdef CONFIG_SSB_PCIHOST + pci_iounmap(bus->host_pci, bus->mmio); +#else + SSB_BUG_ON(1); /* Can't reach this code. */ +#endif + break; + } + bus->mmio = NULL; + bus->mapped_device = NULL; +} + +static void __iomem *ssb_ioremap(struct ssb_bus *bus, + unsigned long baseaddr) +{ + void __iomem *mmio = NULL; + + switch (bus->bustype) { + case SSB_BUSTYPE_SSB: + /* Only map the first core for now. */ + /* fallthrough... */ + case SSB_BUSTYPE_PCMCIA: + mmio = ioremap(baseaddr, SSB_CORE_SIZE); + break; + case SSB_BUSTYPE_PCI: +#ifdef CONFIG_SSB_PCIHOST + mmio = pci_iomap(bus->host_pci, 0, ~0UL); +#else + SSB_BUG_ON(1); /* Can't reach this code. */ +#endif + break; + } + + return mmio; +} + +static int we_support_multiple_80211_cores(struct ssb_bus *bus) +{ + /* More than one 802.11 core is only supported by special chips. + * There are chips with two 802.11 cores, but with dangling + * pins on the second core. Be careful and reject them here. + */ + +#ifdef CONFIG_SSB_PCIHOST + if (bus->bustype == SSB_BUSTYPE_PCI) { + if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM && + bus->host_pci->device == 0x4324) + return 1; + } +#endif /* CONFIG_SSB_PCIHOST */ + return 0; +} + +int ssb_bus_scan(struct ssb_bus *bus, + unsigned long baseaddr) +{ + int err = -ENOMEM; + void __iomem *mmio; + u32 idhi, cc, rev, tmp; + int dev_i, i; + struct ssb_device *dev; + int nr_80211_cores = 0; + + mmio = ssb_ioremap(bus, baseaddr); + if (!mmio) + goto out; + bus->mmio = mmio; + + err = scan_switchcore(bus, 0); /* Switch to first core */ + if (err) + goto err_unmap; + + idhi = scan_read32(bus, 0, SSB_IDHIGH); + cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; + rev = (idhi & SSB_IDHIGH_RCLO); + rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT; + + bus->nr_devices = 0; + if (cc == SSB_DEV_CHIPCOMMON) { + tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID); + + bus->chip_id = (tmp & SSB_CHIPCO_IDMASK); + bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >> + SSB_CHIPCO_REVSHIFT; + bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >> + SSB_CHIPCO_PACKSHIFT; + if (rev >= 4) { + bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >> + SSB_CHIPCO_NRCORESSHIFT; + } + tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP); + bus->chipco.capabilities = tmp; + } else { + if (bus->bustype == SSB_BUSTYPE_PCI) { + bus->chip_id = pcidev_to_chipid(bus->host_pci); + pci_read_config_word(bus->host_pci, PCI_REVISION_ID, + &bus->chip_rev); + bus->chip_package = 0; + } else { + bus->chip_id = 0x4710; + bus->chip_rev = 0; + bus->chip_package = 0; + } + } + if (!bus->nr_devices) + bus->nr_devices = chipid_to_nrcores(bus->chip_id); + if (bus->nr_devices > ARRAY_SIZE(bus->devices)) { + ssb_printk(KERN_ERR PFX + "More than %d ssb cores found (%d)\n", + SSB_MAX_NR_CORES, bus->nr_devices); + goto err_unmap; + } + if (bus->bustype == SSB_BUSTYPE_SSB) { + /* Now that we know the number of cores, + * remap the whole IO space for all cores. + */ + err = -ENOMEM; + iounmap(mmio); + mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices); + if (!mmio) + goto out; + bus->mmio = mmio; + } + + /* Fetch basic information about each core/device */ + for (i = 0, dev_i = 0; i < bus->nr_devices; i++) { + err = scan_switchcore(bus, i); + if (err) + goto err_unmap; + dev = &(bus->devices[dev_i]); + + idhi = scan_read32(bus, i, SSB_IDHIGH); + dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; + dev->id.revision = (idhi & SSB_IDHIGH_RCLO); + dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT; + dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT; + dev->core_index = i; + dev->bus = bus; + dev->ops = bus->ops; + + ssb_dprintk(KERN_INFO PFX + "Core %d found: %s " + "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n", + i, ssb_core_name(dev->id.coreid), + dev->id.coreid, dev->id.revision, dev->id.vendor); + + switch (dev->id.coreid) { + case SSB_DEV_80211: + nr_80211_cores++; + if (nr_80211_cores > 1) { + if (!we_support_multiple_80211_cores(bus)) { + ssb_dprintk(KERN_INFO PFX "Ignoring additional " + "802.11 core\n"); + continue; + } + } + break; + case SSB_DEV_EXTIF: +#ifdef CONFIG_SSB_DRIVER_EXTIF + if (bus->extif.dev) { + ssb_printk(KERN_WARNING PFX + "WARNING: Multiple EXTIFs found\n"); + break; + } + bus->extif.dev = dev; +#endif /* CONFIG_SSB_DRIVER_EXTIF */ + break; + case SSB_DEV_CHIPCOMMON: + if (bus->chipco.dev) { + ssb_printk(KERN_WARNING PFX + "WARNING: Multiple ChipCommon found\n"); + break; + } + bus->chipco.dev = dev; + break; + case SSB_DEV_MIPS: + case SSB_DEV_MIPS_3302: +#ifdef CONFIG_SSB_DRIVER_MIPS + if (bus->mipscore.dev) { + ssb_printk(KERN_WARNING PFX + "WARNING: Multiple MIPS cores found\n"); + break; + } + bus->mipscore.dev = dev; +#endif /* CONFIG_SSB_DRIVER_MIPS */ + break; + case SSB_DEV_PCI: + case SSB_DEV_PCIE: +#ifdef CONFIG_SSB_DRIVER_PCICORE + if (bus->pcicore.dev) { + ssb_printk(KERN_WARNING PFX + "WARNING: Multiple PCI(E) cores found\n"); + break; + } + bus->pcicore.dev = dev; +#endif /* CONFIG_SSB_DRIVER_PCICORE */ + break; + default: + break; + } + + dev_i++; + } + bus->nr_devices = dev_i; + + err = 0; +out: + return err; +err_unmap: + ssb_iounmap(bus); + goto out; +} diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h new file mode 100644 index 000000000000..a789364264a6 --- /dev/null +++ b/drivers/ssb/ssb_private.h @@ -0,0 +1,136 @@ +#ifndef LINUX_SSB_PRIVATE_H_ +#define LINUX_SSB_PRIVATE_H_ + +#include +#include + + +#define PFX "ssb: " + +#ifdef CONFIG_SSB_SILENT +# define ssb_printk(fmt, x...) do { /* nothing */ } while (0) +#else +# define ssb_printk printk +#endif /* CONFIG_SSB_SILENT */ + +/* dprintk: Debugging printk; vanishes for non-debug compilation */ +#ifdef CONFIG_SSB_DEBUG +# define ssb_dprintk(fmt, x...) ssb_printk(fmt , ##x) +#else +# define ssb_dprintk(fmt, x...) do { /* nothing */ } while (0) +#endif + +#ifdef CONFIG_SSB_DEBUG +# define SSB_WARN_ON(x) WARN_ON(x) +# define SSB_BUG_ON(x) BUG_ON(x) +#else +static inline int __ssb_do_nothing(int x) { return x; } +# define SSB_WARN_ON(x) __ssb_do_nothing(unlikely(!!(x))) +# define SSB_BUG_ON(x) __ssb_do_nothing(unlikely(!!(x))) +#endif + + +/* pci.c */ +#ifdef CONFIG_SSB_PCIHOST +extern int ssb_pci_switch_core(struct ssb_bus *bus, + struct ssb_device *dev); +extern int ssb_pci_switch_coreidx(struct ssb_bus *bus, + u8 coreidx); +extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what, + int turn_on); +extern int ssb_pci_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv); +extern void ssb_pci_exit(struct ssb_bus *bus); +extern int ssb_pci_init(struct ssb_bus *bus); +extern const struct ssb_bus_ops ssb_pci_ops; + +#else /* CONFIG_SSB_PCIHOST */ + +static inline int ssb_pci_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + return 0; +} +static inline int ssb_pci_switch_coreidx(struct ssb_bus *bus, + u8 coreidx) +{ + return 0; +} +static inline int ssb_pci_xtal(struct ssb_bus *bus, u32 what, + int turn_on) +{ + return 0; +} +static inline void ssb_pci_exit(struct ssb_bus *bus) +{ +} +static inline int ssb_pci_init(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_PCIHOST */ + + +/* pcmcia.c */ +#ifdef CONFIG_SSB_PCMCIAHOST +extern int ssb_pcmcia_switch_core(struct ssb_bus *bus, + struct ssb_device *dev); +extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx); +extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, + u8 seg); +extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv); +extern int ssb_pcmcia_init(struct ssb_bus *bus); +extern const struct ssb_bus_ops ssb_pcmcia_ops; +#else /* CONFIG_SSB_PCMCIAHOST */ +static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + return 0; +} +static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx) +{ + return 0; +} +static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, + u8 seg) +{ + return 0; +} +static inline int ssb_pcmcia_init(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_PCMCIAHOST */ + + +/* scan.c */ +extern const char *ssb_core_name(u16 coreid); +extern int ssb_bus_scan(struct ssb_bus *bus, + unsigned long baseaddr); +extern void ssb_iounmap(struct ssb_bus *ssb); + + +/* core.c */ +extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); +extern int ssb_devices_freeze(struct ssb_bus *bus); +extern int ssb_devices_thaw(struct ssb_bus *bus); +extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); + +/* b43_pci_bridge.c */ +#ifdef CONFIG_SSB_PCIHOST +extern int __init b43_pci_ssb_bridge_init(void); +extern void __exit b43_pci_ssb_bridge_exit(void); +#else /* CONFIG_SSB_PCIHOST */ +static inline int b43_pci_ssb_bridge_init(void) +{ + return 0; +} +static inline void b43_pci_ssb_bridge_exit(void) +{ +} +#endif /* CONFIG_SSB_PCIHOST */ + +#endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 4dc5fa8be781..0c522e6b0917 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -340,4 +340,19 @@ struct parisc_device_id { #define PA_HVERSION_ANY_ID 0xffff #define PA_SVERSION_ANY_ID 0xffffffff +/* SSB core, see drivers/ssb/ */ +struct ssb_device_id { + __u16 vendor; + __u16 coreid; + __u8 revision; +}; +#define SSB_DEVICE(_vendor, _coreid, _revision) \ + { .vendor = _vendor, .coreid = _coreid, .revision = _revision, } +#define SSB_DEVTABLE_END \ + { 0, }, + +#define SSB_ANY_VENDOR 0xFFFF +#define SSB_ANY_ID 0xFFFF +#define SSB_ANY_REV 0xFF + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h new file mode 100644 index 000000000000..2b5c312c4960 --- /dev/null +++ b/include/linux/ssb/ssb.h @@ -0,0 +1,424 @@ +#ifndef LINUX_SSB_H_ +#define LINUX_SSB_H_ + +#include +#include +#include +#include +#include +#include + +#include + + +struct pcmcia_device; +struct ssb_bus; +struct ssb_driver; + + +struct ssb_sprom_r1 { + u16 pci_spid; /* Subsystem Product ID for PCI */ + u16 pci_svid; /* Subsystem Vendor ID for PCI */ + u16 pci_pid; /* Product ID for PCI */ + u8 il0mac[6]; /* MAC address for 802.11b/g */ + u8 et0mac[6]; /* MAC address for Ethernet */ + u8 et1mac[6]; /* MAC address for 802.11a */ + u8 et0phyaddr:5; /* MII address for enet0 */ + u8 et1phyaddr:5; /* MII address for enet1 */ + u8 et0mdcport:1; /* MDIO for enet0 */ + u8 et1mdcport:1; /* MDIO for enet1 */ + u8 board_rev; /* Board revision */ + u8 country_code:4; /* Country Code */ + u8 antenna_a:2; /* Antenna 0/1 available for A-PHY */ + u8 antenna_bg:2; /* Antenna 0/1 available for B-PHY and G-PHY */ + u16 pa0b0; + u16 pa0b1; + u16 pa0b2; + u16 pa1b0; + u16 pa1b1; + u16 pa1b2; + 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 Power Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_bg; /* B/G-PHY Power 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) */ + u8 antenna_gain_a; /* A-PHY Antenna gain (in dBm Q5.2) */ + u8 antenna_gain_bg; /* B/G-PHY Antenna gain (in dBm Q5.2) */ + u8 oem[8]; /* OEM string (rev 1 only) */ +}; + +struct ssb_sprom_r2 { + u16 boardflags_hi; /* Boardflags (high 16 bits) */ + u8 maxpwr_a_lo; /* A-PHY Max Power Low */ + u8 maxpwr_a_hi; /* A-PHY Max Power High */ + u16 pa1lob0; /* A-PHY PA Low Settings */ + u16 pa1lob1; /* A-PHY PA Low Settings */ + u16 pa1lob2; /* A-PHY PA Low Settings */ + u16 pa1hib0; /* A-PHY PA High Settings */ + u16 pa1hib1; /* A-PHY PA High Settings */ + u16 pa1hib2; /* A-PHY PA High Settings */ + u8 ofdm_pwr_off; /* OFDM Power Offset from CCK Level */ + u8 country_str[2]; /* Two char Country Code */ +}; + +struct ssb_sprom_r3 { + u32 ofdmapo; /* A-PHY OFDM Mid Power Offset */ + u32 ofdmalpo; /* A-PHY OFDM Low Power Offset */ + u32 ofdmahpo; /* A-PHY OFDM High Power Offset */ + u8 gpioldc_on_cnt; /* GPIO LED Powersave Duty Cycle ON count */ + u8 gpioldc_off_cnt; /* GPIO LED Powersave Duty Cycle OFF count */ + u8 cckpo_1M:4; /* CCK Power Offset for Rate 1M */ + u8 cckpo_2M:4; /* CCK Power Offset for Rate 2M */ + u8 cckpo_55M:4; /* CCK Power Offset for Rate 5.5M */ + u8 cckpo_11M:4; /* CCK Power Offset for Rate 11M */ + u32 ofdmgpo; /* G-PHY OFDM Power Offset */ +}; + +struct ssb_sprom_r4 { + /* TODO */ +}; + +struct ssb_sprom { + u8 revision; + u8 crc; + /* The valid r# fields are selected by the "revision". + * Revision 3 and lower inherit from lower revisions. + */ + union { + struct { + struct ssb_sprom_r1 r1; + struct ssb_sprom_r2 r2; + struct ssb_sprom_r3 r3; + }; + struct ssb_sprom_r4 r4; + }; +}; + +/* Information about the PCB the circuitry is soldered on. */ +struct ssb_boardinfo { + u16 vendor; + u16 type; + u16 rev; +}; + + +struct ssb_device; +/* Lowlevel read/write operations on the device MMIO. + * Internal, don't use that outside of ssb. */ +struct ssb_bus_ops { + u16 (*read16)(struct ssb_device *dev, u16 offset); + u32 (*read32)(struct ssb_device *dev, u16 offset); + void (*write16)(struct ssb_device *dev, u16 offset, u16 value); + void (*write32)(struct ssb_device *dev, u16 offset, u32 value); +}; + + +/* Core-ID values. */ +#define SSB_DEV_CHIPCOMMON 0x800 +#define SSB_DEV_ILINE20 0x801 +#define SSB_DEV_SDRAM 0x803 +#define SSB_DEV_PCI 0x804 +#define SSB_DEV_MIPS 0x805 +#define SSB_DEV_ETHERNET 0x806 +#define SSB_DEV_V90 0x807 +#define SSB_DEV_USB11_HOSTDEV 0x808 +#define SSB_DEV_ADSL 0x809 +#define SSB_DEV_ILINE100 0x80A +#define SSB_DEV_IPSEC 0x80B +#define SSB_DEV_PCMCIA 0x80D +#define SSB_DEV_INTERNAL_MEM 0x80E +#define SSB_DEV_MEMC_SDRAM 0x80F +#define SSB_DEV_EXTIF 0x811 +#define SSB_DEV_80211 0x812 +#define SSB_DEV_MIPS_3302 0x816 +#define SSB_DEV_USB11_HOST 0x817 +#define SSB_DEV_USB11_DEV 0x818 +#define SSB_DEV_USB20_HOST 0x819 +#define SSB_DEV_USB20_DEV 0x81A +#define SSB_DEV_SDIO_HOST 0x81B +#define SSB_DEV_ROBOSWITCH 0x81C +#define SSB_DEV_PARA_ATA 0x81D +#define SSB_DEV_SATA_XORDMA 0x81E +#define SSB_DEV_ETHERNET_GBIT 0x81F +#define SSB_DEV_PCIE 0x820 +#define SSB_DEV_MIMO_PHY 0x821 +#define SSB_DEV_SRAM_CTRLR 0x822 +#define SSB_DEV_MINI_MACPHY 0x823 +#define SSB_DEV_ARM_1176 0x824 +#define SSB_DEV_ARM_7TDMI 0x825 + +/* Vendor-ID values */ +#define SSB_VENDOR_BROADCOM 0x4243 + +/* Some kernel subsystems poke with dev->drvdata, so we must use the + * following ugly workaround to get from struct device to struct ssb_device */ +struct __ssb_dev_wrapper { + struct device dev; + struct ssb_device *sdev; +}; + +struct ssb_device { + /* Having a copy of the ops pointer in each dev struct + * is an optimization. */ + const struct ssb_bus_ops *ops; + + struct device *dev; + struct ssb_bus *bus; + struct ssb_device_id id; + + u8 core_index; + unsigned int irq; + + /* Internal-only stuff follows. */ + void *drvdata; /* Per-device data */ + void *devtypedata; /* Per-devicetype (eg 802.11) data */ +}; + +/* Go from struct device to struct ssb_device. */ +static inline +struct ssb_device * dev_to_ssb_dev(struct device *dev) +{ + struct __ssb_dev_wrapper *wrap; + wrap = container_of(dev, struct __ssb_dev_wrapper, dev); + return wrap->sdev; +} + +/* Device specific user data */ +static inline +void ssb_set_drvdata(struct ssb_device *dev, void *data) +{ + dev->drvdata = data; +} +static inline +void * ssb_get_drvdata(struct ssb_device *dev) +{ + return dev->drvdata; +} + +/* Devicetype specific user data. This is per device-type (not per device) */ +void ssb_set_devtypedata(struct ssb_device *dev, void *data); +static inline +void * ssb_get_devtypedata(struct ssb_device *dev) +{ + return dev->devtypedata; +} + + +struct ssb_driver { + const char *name; + const struct ssb_device_id *id_table; + + int (*probe)(struct ssb_device *dev, const struct ssb_device_id *id); + void (*remove)(struct ssb_device *dev); + int (*suspend)(struct ssb_device *dev, pm_message_t state); + int (*resume)(struct ssb_device *dev); + void (*shutdown)(struct ssb_device *dev); + + struct device_driver drv; +}; +#define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv) + +extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner); +static inline int ssb_driver_register(struct ssb_driver *drv) +{ + return __ssb_driver_register(drv, THIS_MODULE); +} +extern void ssb_driver_unregister(struct ssb_driver *drv); + + + + +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 */ +}; + +/* board_vendor */ +#define SSB_BOARDVENDOR_BCM 0x14E4 /* Broadcom */ +#define SSB_BOARDVENDOR_DELL 0x1028 /* Dell */ +#define SSB_BOARDVENDOR_HP 0x0E11 /* HP */ +/* board_type */ +#define SSB_BOARD_BCM94306MP 0x0418 +#define SSB_BOARD_BCM4309G 0x0421 +#define SSB_BOARD_BCM4306CB 0x0417 +#define SSB_BOARD_BCM4309MP 0x040C +#define SSB_BOARD_MP4318 0x044A +#define SSB_BOARD_BU4306 0x0416 +#define SSB_BOARD_BU4309 0x040A +/* chip_package */ +#define SSB_CHIPPACK_BCM4712S 1 /* Small 200pin 4712 */ +#define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */ +#define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */ + +#include +#include +#include +#include + +struct ssb_bus { + /* The MMIO area. */ + void __iomem *mmio; + + const struct ssb_bus_ops *ops; + + /* 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; + /* Lock for core and segment switching. */ + spinlock_t bar_lock; + + /* The bus this backplane is running on. */ + enum ssb_bustype bustype; + /* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */ + struct pci_dev *host_pci; + /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */ + struct pcmcia_device *host_pcmcia; + +#ifdef CONFIG_SSB_PCIHOST + /* Mutex to protect the SPROM writing. */ + struct mutex pci_sprom_mutex; +#endif + + /* ID information about the Chip. */ + u16 chip_id; + u16 chip_rev; + u8 chip_package; + + /* List of devices (cores) on the backplane. */ + struct ssb_device devices[SSB_MAX_NR_CORES]; + u8 nr_devices; + + /* Reference count. Number of suspended devices. */ + u8 suspend_cnt; + + /* Software ID number for this bus. */ + unsigned int busnumber; + + /* The ChipCommon device (if available). */ + struct ssb_chipcommon chipco; + /* The PCI-core device (if available). */ + struct ssb_pcicore pcicore; + /* The MIPS-core device (if available). */ + struct ssb_mipscore mipscore; + /* The EXTif-core device (if available). */ + struct ssb_extif extif; + + /* The following structure elements are not available in early + * SSB initialization. Though, they are available for regular + * registered drivers at any stage. So be careful when + * using them in the ssb core code. */ + + /* ID information about the PCB. */ + struct ssb_boardinfo boardinfo; + /* Contents of the SPROM. */ + struct ssb_sprom sprom; + + /* Internal-only stuff follows. Do not touch. */ + struct list_head list; +#ifdef CONFIG_SSB_DEBUG + /* Is the bus already powered up? */ + bool powered_up; + int power_warn_count; +#endif /* DEBUG */ +}; + +/* The initialization-invariants. */ +struct ssb_init_invariants { + struct ssb_boardinfo boardinfo; + struct ssb_sprom sprom; +}; +/* Type of function to fetch the invariants. */ +typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus, + struct ssb_init_invariants *iv); + +/* Register a SSB system bus. get_invariants() is called after the + * basic system devices are initialized. + * The invariants are usually fetched from some NVRAM. + * Put the invariants into the struct pointed to by iv. */ +extern int ssb_bus_ssbbus_register(struct ssb_bus *bus, + unsigned long baseaddr, + ssb_invariants_func_t get_invariants); +#ifdef CONFIG_SSB_PCIHOST +extern int ssb_bus_pcibus_register(struct ssb_bus *bus, + struct pci_dev *host_pci); +#endif /* CONFIG_SSB_PCIHOST */ +#ifdef CONFIG_SSB_PCMCIAHOST +extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, + struct pcmcia_device *pcmcia_dev, + unsigned long baseaddr); +#endif /* CONFIG_SSB_PCMCIAHOST */ + +extern void ssb_bus_unregister(struct ssb_bus *bus); + +extern u32 ssb_clockspeed(struct ssb_bus *bus); + +/* Is the device enabled in hardware? */ +int ssb_device_is_enabled(struct ssb_device *dev); +/* Enable a device and pass device-specific SSB_TMSLOW flags. + * If no device-specific flags are available, use 0. */ +void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags); +/* Disable a device in hardware and pass SSB_TMSLOW flags (if any). */ +void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags); + + +/* Device MMIO register read/write functions. */ +static inline u16 ssb_read16(struct ssb_device *dev, u16 offset) +{ + return dev->ops->read16(dev, offset); +} +static inline u32 ssb_read32(struct ssb_device *dev, u16 offset) +{ + return dev->ops->read32(dev, offset); +} +static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + dev->ops->write16(dev, offset, value); +} +static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + dev->ops->write32(dev, offset, value); +} + + +/* Translation (routing) bits that need to be ORed to DMA + * addresses before they are given to a device. */ +extern u32 ssb_dma_translation(struct ssb_device *dev); +#define SSB_DMA_TRANSLATION_MASK 0xC0000000 +#define SSB_DMA_TRANSLATION_SHIFT 30 + +extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask); + + +#ifdef CONFIG_SSB_PCIHOST +/* PCI-host wrapper driver */ +extern int ssb_pcihost_register(struct pci_driver *driver); +static inline void ssb_pcihost_unregister(struct pci_driver *driver) +{ + pci_unregister_driver(driver); +} +#endif /* CONFIG_SSB_PCIHOST */ + + +/* If a driver is shutdown or suspended, call this to signal + * that the bus may be completely powered down. SSB will decide, + * if it's really time to power down the bus, based on if there + * are other devices that want to run. */ +extern int ssb_bus_may_powerdown(struct ssb_bus *bus); +/* Before initializing and enabling a device, call this to power-up the bus. + * If you want to allow use of dynamic-power-control, pass the flag. + * Otherwise static always-on powercontrol will be used. */ +extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl); + + +/* Various helper functions */ +extern u32 ssb_admatch_base(u32 adm); +extern u32 ssb_admatch_size(u32 adm); + + +#endif /* LINUX_SSB_H_ */ diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h new file mode 100644 index 000000000000..4cb995494662 --- /dev/null +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -0,0 +1,396 @@ +#ifndef LINUX_SSB_CHIPCO_H_ +#define LINUX_SSB_CHIPCO_H_ + +/* SonicsSiliconBackplane CHIPCOMMON core hardware definitions + * + * The chipcommon core provides chip identification, SB control, + * jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer, + * gpio interface, extbus, and support for serial and parallel flashes. + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, Michael Buesch + * + * Licensed under the GPL version 2. See COPYING for details. + */ + +/** ChipCommon core registers. **/ + +#define SSB_CHIPCO_CHIPID 0x0000 +#define SSB_CHIPCO_IDMASK 0x0000FFFF +#define SSB_CHIPCO_REVMASK 0x000F0000 +#define SSB_CHIPCO_REVSHIFT 16 +#define SSB_CHIPCO_PACKMASK 0x00F00000 +#define SSB_CHIPCO_PACKSHIFT 20 +#define SSB_CHIPCO_NRCORESMASK 0x0F000000 +#define SSB_CHIPCO_NRCORESSHIFT 24 +#define SSB_CHIPCO_CAP 0x0004 /* Capabilities */ +#define SSB_CHIPCO_CAP_NRUART 0x00000003 /* # of UARTs */ +#define SSB_CHIPCO_CAP_MIPSEB 0x00000004 /* MIPS in BigEndian Mode */ +#define SSB_CHIPCO_CAP_UARTCLK 0x00000018 /* UART clock select */ +#define SSB_CHIPCO_CAP_UARTCLK_INT 0x00000008 /* UARTs are driven by internal divided clock */ +#define SSB_CHIPCO_CAP_UARTGPIO 0x00000020 /* UARTs on GPIO 15-12 */ +#define SSB_CHIPCO_CAP_EXTBUS 0x000000C0 /* External buses present */ +#define SSB_CHIPCO_CAP_FLASHT 0x00000700 /* Flash Type */ +#define SSB_CHIPCO_FLASHT_NONE 0x00000000 /* No flash */ +#define SSB_CHIPCO_FLASHT_STSER 0x00000100 /* ST serial flash */ +#define SSB_CHIPCO_FLASHT_ATSER 0x00000200 /* Atmel serial flash */ +#define SSB_CHIPCO_FLASHT_PARA 0x00000700 /* Parallel flash */ +#define SSB_CHIPCO_CAP_PLLT 0x00038000 /* PLL Type */ +#define SSB_PLLTYPE_NONE 0x00000000 +#define SSB_PLLTYPE_1 0x00010000 /* 48Mhz base, 3 dividers */ +#define SSB_PLLTYPE_2 0x00020000 /* 48Mhz, 4 dividers */ +#define SSB_PLLTYPE_3 0x00030000 /* 25Mhz, 2 dividers */ +#define SSB_PLLTYPE_4 0x00008000 /* 48Mhz, 4 dividers */ +#define SSB_PLLTYPE_5 0x00018000 /* 25Mhz, 4 dividers */ +#define SSB_PLLTYPE_6 0x00028000 /* 100/200 or 120/240 only */ +#define SSB_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */ +#define SSB_CHIPCO_CAP_PCTL 0x00040000 /* Power Control */ +#define SSB_CHIPCO_CAP_OTPS 0x00380000 /* OTP size */ +#define SSB_CHIPCO_CAP_OTPS_SHIFT 19 +#define SSB_CHIPCO_CAP_OTPS_BASE 5 +#define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */ +#define SSB_CHIPCO_CAP_BROM 0x00800000 /* Internal boot ROM active */ +#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */ +#define SSB_CHIPCO_CORECTL 0x0008 +#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ +#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define SSB_CHIPCO_BIST 0x000C +#define SSB_CHIPCO_OTPS 0x0010 /* OTP status */ +#define SSB_CHIPCO_OTPS_PROGFAIL 0x80000000 +#define SSB_CHIPCO_OTPS_PROTECT 0x00000007 +#define SSB_CHIPCO_OTPS_HW_PROTECT 0x00000001 +#define SSB_CHIPCO_OTPS_SW_PROTECT 0x00000002 +#define SSB_CHIPCO_OTPS_CID_PROTECT 0x00000004 +#define SSB_CHIPCO_OTPC 0x0014 /* OTP control */ +#define SSB_CHIPCO_OTPC_RECWAIT 0xFF000000 +#define SSB_CHIPCO_OTPC_PROGWAIT 0x00FFFF00 +#define SSB_CHIPCO_OTPC_PRW_SHIFT 8 +#define SSB_CHIPCO_OTPC_MAXFAIL 0x00000038 +#define SSB_CHIPCO_OTPC_VSEL 0x00000006 +#define SSB_CHIPCO_OTPC_SELVL 0x00000001 +#define SSB_CHIPCO_OTPP 0x0018 /* OTP prog */ +#define SSB_CHIPCO_OTPP_COL 0x000000FF +#define SSB_CHIPCO_OTPP_ROW 0x0000FF00 +#define SSB_CHIPCO_OTPP_ROW_SHIFT 8 +#define SSB_CHIPCO_OTPP_READERR 0x10000000 +#define SSB_CHIPCO_OTPP_VALUE 0x20000000 +#define SSB_CHIPCO_OTPP_READ 0x40000000 +#define SSB_CHIPCO_OTPP_START 0x80000000 +#define SSB_CHIPCO_OTPP_BUSY 0x80000000 +#define SSB_CHIPCO_IRQSTAT 0x0020 +#define SSB_CHIPCO_IRQMASK 0x0024 +#define SSB_CHIPCO_IRQ_GPIO 0x00000001 /* gpio intr */ +#define SSB_CHIPCO_IRQ_EXT 0x00000002 /* ro: ext intr pin (corerev >= 3) */ +#define SSB_CHIPCO_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */ +#define SSB_CHIPCO_CHIPCTL 0x0028 /* Rev >= 11 only */ +#define SSB_CHIPCO_CHIPSTAT 0x002C /* Rev >= 11 only */ +#define SSB_CHIPCO_JCMD 0x0030 /* Rev >= 10 only */ +#define SSB_CHIPCO_JCMD_START 0x80000000 +#define SSB_CHIPCO_JCMD_BUSY 0x80000000 +#define SSB_CHIPCO_JCMD_PAUSE 0x40000000 +#define SSB_CHIPCO_JCMD0_ACC_MASK 0x0000F000 +#define SSB_CHIPCO_JCMD0_ACC_IRDR 0x00000000 +#define SSB_CHIPCO_JCMD0_ACC_DR 0x00001000 +#define SSB_CHIPCO_JCMD0_ACC_IR 0x00002000 +#define SSB_CHIPCO_JCMD0_ACC_RESET 0x00003000 +#define SSB_CHIPCO_JCMD0_ACC_IRPDR 0x00004000 +#define SSB_CHIPCO_JCMD0_ACC_PDR 0x00005000 +#define SSB_CHIPCO_JCMD0_IRW_MASK 0x00000F00 +#define SSB_CHIPCO_JCMD_ACC_MASK 0x000F0000 /* Changes for corerev 11 */ +#define SSB_CHIPCO_JCMD_ACC_IRDR 0x00000000 +#define SSB_CHIPCO_JCMD_ACC_DR 0x00010000 +#define SSB_CHIPCO_JCMD_ACC_IR 0x00020000 +#define SSB_CHIPCO_JCMD_ACC_RESET 0x00030000 +#define SSB_CHIPCO_JCMD_ACC_IRPDR 0x00040000 +#define SSB_CHIPCO_JCMD_ACC_PDR 0x00050000 +#define SSB_CHIPCO_JCMD_IRW_MASK 0x00001F00 +#define SSB_CHIPCO_JCMD_IRW_SHIFT 8 +#define SSB_CHIPCO_JCMD_DRW_MASK 0x0000003F +#define SSB_CHIPCO_JIR 0x0034 /* Rev >= 10 only */ +#define SSB_CHIPCO_JDR 0x0038 /* Rev >= 10 only */ +#define SSB_CHIPCO_JCTL 0x003C /* Rev >= 10 only */ +#define SSB_CHIPCO_JCTL_FORCE_CLK 4 /* Force clock */ +#define SSB_CHIPCO_JCTL_EXT_EN 2 /* Enable external targets */ +#define SSB_CHIPCO_JCTL_EN 1 /* Enable Jtag master */ +#define SSB_CHIPCO_FLASHCTL 0x0040 +#define SSB_CHIPCO_FLASHCTL_START 0x80000000 +#define SSB_CHIPCO_FLASHCTL_BUSY SSB_CHIPCO_FLASHCTL_START +#define SSB_CHIPCO_FLASHADDR 0x0044 +#define SSB_CHIPCO_FLASHDATA 0x0048 +#define SSB_CHIPCO_BCAST_ADDR 0x0050 +#define SSB_CHIPCO_BCAST_DATA 0x0054 +#define SSB_CHIPCO_GPIOIN 0x0060 +#define SSB_CHIPCO_GPIOOUT 0x0064 +#define SSB_CHIPCO_GPIOOUTEN 0x0068 +#define SSB_CHIPCO_GPIOCTL 0x006C +#define SSB_CHIPCO_GPIOPOL 0x0070 +#define SSB_CHIPCO_GPIOIRQ 0x0074 +#define SSB_CHIPCO_WATCHDOG 0x0080 +#define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ +#define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16 +#define SSB_CHIPCO_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ +#define SSB_CHIPCO_CLOCK_N 0x0090 +#define SSB_CHIPCO_CLOCK_SB 0x0094 +#define SSB_CHIPCO_CLOCK_PCI 0x0098 +#define SSB_CHIPCO_CLOCK_M2 0x009C +#define SSB_CHIPCO_CLOCK_MIPS 0x00A0 +#define SSB_CHIPCO_CLKDIV 0x00A4 /* Rev >= 3 only */ +#define SSB_CHIPCO_CLKDIV_SFLASH 0x0F000000 +#define SSB_CHIPCO_CLKDIV_SFLASH_SHIFT 24 +#define SSB_CHIPCO_CLKDIV_OTP 0x000F0000 +#define SSB_CHIPCO_CLKDIV_OTP_SHIFT 16 +#define SSB_CHIPCO_CLKDIV_JTAG 0x00000F00 +#define SSB_CHIPCO_CLKDIV_JTAG_SHIFT 8 +#define SSB_CHIPCO_CLKDIV_UART 0x000000FF +#define SSB_CHIPCO_PLLONDELAY 0x00B0 /* Rev >= 4 only */ +#define SSB_CHIPCO_FREFSELDELAY 0x00B4 /* Rev >= 4 only */ +#define SSB_CHIPCO_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC 0x00000007 /* slow clock source mask */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC_LPO 0x00000000 /* source of slow clock is LPO */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL 0x00000001 /* source of slow clock is crystal */ +#define SSB_CHIPCO_SLOECLKCTL_SRC_PCI 0x00000002 /* source of slow clock is PCI */ +#define SSB_CHIPCO_SLOWCLKCTL_LPOFREQ 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define SSB_CHIPCO_SLOWCLKCTL_LPOPD 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */ +#define SSB_CHIPCO_SLOWCLKCTL_FSLOW 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */ +#define SSB_CHIPCO_SLOWCLKCTL_IPLL 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */ +#define SSB_CHIPCO_SLOWCLKCTL_ENXTAL 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */ +#define SSB_CHIPCO_SLOWCLKCTL_XTALPU 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ +#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV 0xFFFF0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV_SHIFT 16 +#define SSB_CHIPCO_SYSCLKCTL 0x00C0 /* Rev >= 3 only */ +#define SSB_CHIPCO_SYSCLKCTL_IDLPEN 0x00000001 /* ILPen: Enable Idle Low Power */ +#define SSB_CHIPCO_SYSCLKCTL_ALPEN 0x00000002 /* ALPen: Enable Active Low Power */ +#define SSB_CHIPCO_SYSCLKCTL_PLLEN 0x00000004 /* ForcePLLOn */ +#define SSB_CHIPCO_SYSCLKCTL_FORCEALP 0x00000008 /* Force ALP (or HT if ALPen is not set */ +#define SSB_CHIPCO_SYSCLKCTL_FORCEHT 0x00000010 /* Force HT */ +#define SSB_CHIPCO_SYSCLKCTL_CLKDIV 0xFFFF0000 /* ClkDiv (ILP = 1/(4+divisor)) */ +#define SSB_CHIPCO_SYSCLKCTL_CLKDIV_SHIFT 16 +#define SSB_CHIPCO_CLKSTSTR 0x00C4 /* Rev >= 3 only */ +#define SSB_CHIPCO_PCMCIA_CFG 0x0100 +#define SSB_CHIPCO_PCMCIA_MEMWAIT 0x0104 +#define SSB_CHIPCO_PCMCIA_ATTRWAIT 0x0108 +#define SSB_CHIPCO_PCMCIA_IOWAIT 0x010C +#define SSB_CHIPCO_IDE_CFG 0x0110 +#define SSB_CHIPCO_IDE_MEMWAIT 0x0114 +#define SSB_CHIPCO_IDE_ATTRWAIT 0x0118 +#define SSB_CHIPCO_IDE_IOWAIT 0x011C +#define SSB_CHIPCO_PROG_CFG 0x0120 +#define SSB_CHIPCO_PROG_WAITCNT 0x0124 +#define SSB_CHIPCO_FLASH_CFG 0x0128 +#define SSB_CHIPCO_FLASH_WAITCNT 0x012C +#define SSB_CHIPCO_UART0_DATA 0x0300 +#define SSB_CHIPCO_UART0_IMR 0x0304 +#define SSB_CHIPCO_UART0_FCR 0x0308 +#define SSB_CHIPCO_UART0_LCR 0x030C +#define SSB_CHIPCO_UART0_MCR 0x0310 +#define SSB_CHIPCO_UART0_LSR 0x0314 +#define SSB_CHIPCO_UART0_MSR 0x0318 +#define SSB_CHIPCO_UART0_SCRATCH 0x031C +#define SSB_CHIPCO_UART1_DATA 0x0400 +#define SSB_CHIPCO_UART1_IMR 0x0404 +#define SSB_CHIPCO_UART1_FCR 0x0408 +#define SSB_CHIPCO_UART1_LCR 0x040C +#define SSB_CHIPCO_UART1_MCR 0x0410 +#define SSB_CHIPCO_UART1_LSR 0x0414 +#define SSB_CHIPCO_UART1_MSR 0x0418 +#define SSB_CHIPCO_UART1_SCRATCH 0x041C + + + +/** Clockcontrol masks and values **/ + +/* SSB_CHIPCO_CLOCK_N */ +#define SSB_CHIPCO_CLK_N1 0x0000003F /* n1 control */ +#define SSB_CHIPCO_CLK_N2 0x00003F00 /* n2 control */ +#define SSB_CHIPCO_CLK_N2_SHIFT 8 +#define SSB_CHIPCO_CLK_PLLC 0x000F0000 /* pll control */ +#define SSB_CHIPCO_CLK_PLLC_SHIFT 16 + +/* SSB_CHIPCO_CLOCK_SB/PCI/UART */ +#define SSB_CHIPCO_CLK_M1 0x0000003F /* m1 control */ +#define SSB_CHIPCO_CLK_M2 0x00003F00 /* m2 control */ +#define SSB_CHIPCO_CLK_M2_SHIFT 8 +#define SSB_CHIPCO_CLK_M3 0x003F0000 /* m3 control */ +#define SSB_CHIPCO_CLK_M3_SHIFT 16 +#define SSB_CHIPCO_CLK_MC 0x1F000000 /* mux control */ +#define SSB_CHIPCO_CLK_MC_SHIFT 24 + +/* N3M Clock control magic field values */ +#define SSB_CHIPCO_CLK_F6_2 0x02 /* A factor of 2 in */ +#define SSB_CHIPCO_CLK_F6_3 0x03 /* 6-bit fields like */ +#define SSB_CHIPCO_CLK_F6_4 0x05 /* N1, M1 or M3 */ +#define SSB_CHIPCO_CLK_F6_5 0x09 +#define SSB_CHIPCO_CLK_F6_6 0x11 +#define SSB_CHIPCO_CLK_F6_7 0x21 + +#define SSB_CHIPCO_CLK_F5_BIAS 5 /* 5-bit fields get this added */ + +#define SSB_CHIPCO_CLK_MC_BYPASS 0x08 +#define SSB_CHIPCO_CLK_MC_M1 0x04 +#define SSB_CHIPCO_CLK_MC_M1M2 0x02 +#define SSB_CHIPCO_CLK_MC_M1M2M3 0x01 +#define SSB_CHIPCO_CLK_MC_M1M3 0x11 + +/* Type 2 Clock control magic field values */ +#define SSB_CHIPCO_CLK_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ +#define SSB_CHIPCO_CLK_T2M2_BIAS 3 /* m2 bias */ + +#define SSB_CHIPCO_CLK_T2MC_M1BYP 1 +#define SSB_CHIPCO_CLK_T2MC_M2BYP 2 +#define SSB_CHIPCO_CLK_T2MC_M3BYP 4 + +/* Type 6 Clock control magic field values */ +#define SSB_CHIPCO_CLK_T6_MMASK 1 /* bits of interest in m */ +#define SSB_CHIPCO_CLK_T6_M0 120000000 /* sb clock for m = 0 */ +#define SSB_CHIPCO_CLK_T6_M1 100000000 /* sb clock for m = 1 */ +#define SSB_CHIPCO_CLK_SB2MIPS_T6(sb) (2 * (sb)) + +/* Common clock base */ +#define SSB_CHIPCO_CLK_BASE1 24000000 /* Half the clock freq */ +#define SSB_CHIPCO_CLK_BASE2 12500000 /* Alternate crystal on some PLL's */ + +/* Clock control values for 200Mhz in 5350 */ +#define SSB_CHIPCO_CLK_5350_N 0x0311 +#define SSB_CHIPCO_CLK_5350_M 0x04020009 + + +/** Bits in the config registers **/ + +#define SSB_CHIPCO_CFG_EN 0x0001 /* Enable */ +#define SSB_CHIPCO_CFG_EXTM 0x000E /* Extif Mode */ +#define SSB_CHIPCO_CFG_EXTM_ASYNC 0x0002 /* Async/Parallel flash */ +#define SSB_CHIPCO_CFG_EXTM_SYNC 0x0004 /* Synchronous */ +#define SSB_CHIPCO_CFG_EXTM_PCMCIA 0x0008 /* PCMCIA */ +#define SSB_CHIPCO_CFG_EXTM_IDE 0x000A /* IDE */ +#define SSB_CHIPCO_CFG_DS16 0x0010 /* Data size, 0=8bit, 1=16bit */ +#define SSB_CHIPCO_CFG_CLKDIV 0x0060 /* Sync: Clock divisor */ +#define SSB_CHIPCO_CFG_CLKEN 0x0080 /* Sync: Clock enable */ +#define SSB_CHIPCO_CFG_BSTRO 0x0100 /* Sync: Size/Bytestrobe */ + + +/** Flash-specific control/status values */ + +/* flashcontrol opcodes for ST flashes */ +#define SSB_CHIPCO_FLASHCTL_ST_WREN 0x0006 /* Write Enable */ +#define SSB_CHIPCO_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */ +#define SSB_CHIPCO_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */ +#define SSB_CHIPCO_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */ +#define SSB_CHIPCO_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */ +#define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */ +#define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */ +#define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */ +#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */ +#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */ + +/* Status register bits for ST flashes */ +#define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */ +#define SSB_CHIPCO_FLASHSTA_ST_WEL 0x02 /* Write Enable Latch */ +#define SSB_CHIPCO_FLASHSTA_ST_BP 0x1C /* Block Protect */ +#define SSB_CHIPCO_FLASHSTA_ST_BP_SHIFT 2 +#define SSB_CHIPCO_FLASHSTA_ST_SRWD 0x80 /* Status Register Write Disable */ + +/* flashcontrol opcodes for Atmel flashes */ +#define SSB_CHIPCO_FLASHCTL_AT_READ 0x07E8 +#define SSB_CHIPCO_FLASHCTL_AT_PAGE_READ 0x07D2 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_READ /* FIXME */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_READ /* FIXME */ +#define SSB_CHIPCO_FLASHCTL_AT_STATUS 0x01D7 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE 0x0384 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRITE 0x0387 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_ERASE_PRGM 0x0283 /* Erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_ERASE_PRGM 0x0286 /* Erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM 0x0288 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_PROGRAM 0x0289 +#define SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE 0x0281 +#define SSB_CHIPCO_FLASHCTL_AT_BLOCK_ERASE 0x0250 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRER_PRGM 0x0382 /* Write erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRER_PRGM 0x0385 /* Write erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD 0x0253 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_LOAD 0x0255 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_COMPARE 0x0260 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_COMPARE 0x0261 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_REPROGRAM 0x0258 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_REPROGRAM 0x0259 + +/* Status register bits for Atmel flashes */ +#define SSB_CHIPCO_FLASHSTA_AT_READY 0x80 +#define SSB_CHIPCO_FLASHSTA_AT_MISMATCH 0x40 +#define SSB_CHIPCO_FLASHSTA_AT_ID 0x38 +#define SSB_CHIPCO_FLASHSTA_AT_ID_SHIFT 3 + + +/** OTP **/ + +/* OTP regions */ +#define SSB_CHIPCO_OTP_HW_REGION SSB_CHIPCO_OTPS_HW_PROTECT +#define SSB_CHIPCO_OTP_SW_REGION SSB_CHIPCO_OTPS_SW_PROTECT +#define SSB_CHIPCO_OTP_CID_REGION SSB_CHIPCO_OTPS_CID_PROTECT + +/* OTP regions (Byte offsets from otp size) */ +#define SSB_CHIPCO_OTP_SWLIM_OFF (-8) +#define SSB_CHIPCO_OTP_CIDBASE_OFF 0 +#define SSB_CHIPCO_OTP_CIDLIM_OFF 8 + +/* Predefined OTP words (Word offset from otp size) */ +#define SSB_CHIPCO_OTP_BOUNDARY_OFF (-4) +#define SSB_CHIPCO_OTP_HWSIGN_OFF (-3) +#define SSB_CHIPCO_OTP_SWSIGN_OFF (-2) +#define SSB_CHIPCO_OTP_CIDSIGN_OFF (-1) + +#define SSB_CHIPCO_OTP_CID_OFF 0 +#define SSB_CHIPCO_OTP_PKG_OFF 1 +#define SSB_CHIPCO_OTP_FID_OFF 2 +#define SSB_CHIPCO_OTP_RSV_OFF 3 +#define SSB_CHIPCO_OTP_LIM_OFF 4 + +#define SSB_CHIPCO_OTP_SIGNATURE 0x578A +#define SSB_CHIPCO_OTP_MAGIC 0x4E56 + + +struct ssb_device; +struct ssb_serial_port; + +struct ssb_chipcommon { + struct ssb_device *dev; + u32 capabilities; + /* Fast Powerup Delay constant */ + u16 fast_pwrup_delay; +}; + +extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); + +#include +extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); +extern void ssb_chipco_resume(struct ssb_chipcommon *cc); + +extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); +extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); +extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc, + unsigned long ns_per_cycle); + +enum ssb_clkmode { + SSB_CLKMODE_SLOW, + SSB_CLKMODE_FAST, + SSB_CLKMODE_DYNAMIC, +}; + +extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, + enum ssb_clkmode mode); + +extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, + u32 ticks); + +u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask); + +void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value); + +void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value); + +#ifdef CONFIG_SSB_SERIAL +extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, + struct ssb_serial_port *ports); +#endif /* CONFIG_SSB_SERIAL */ + +#endif /* LINUX_SSB_CHIPCO_H_ */ diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h new file mode 100644 index 000000000000..a9164357b5ae --- /dev/null +++ b/include/linux/ssb/ssb_driver_extif.h @@ -0,0 +1,204 @@ +/* + * Hardware-specific External Interface I/O core definitions + * for the BCM47xx family of SiliconBackplane-based chips. + * + * The External Interface core supports a total of three external chip selects + * supporting external interfaces. One of the external chip selects is + * used for Flash, one is used for PCMCIA, and the other may be + * programmed to support either a synchronous interface or an + * asynchronous interface. The asynchronous interface can be used to + * support external devices such as UARTs and the BCM2019 Bluetooth + * baseband processor. + * The external interface core also contains 2 on-chip 16550 UARTs, clock + * frequency control, a watchdog interrupt timer, and a GPIO interface. + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, Michael Buesch + * + * Licensed under the GPL version 2. See COPYING for details. + */ +#ifndef LINUX_SSB_EXTIFCORE_H_ +#define LINUX_SSB_EXTIFCORE_H_ + +/* external interface address space */ +#define SSB_EXTIF_PCMCIA_MEMBASE(x) (x) +#define SSB_EXTIF_PCMCIA_IOBASE(x) ((x) + 0x100000) +#define SSB_EXTIF_PCMCIA_CFGBASE(x) ((x) + 0x200000) +#define SSB_EXTIF_CFGIF_BASE(x) ((x) + 0x800000) +#define SSB_EXTIF_FLASH_BASE(x) ((x) + 0xc00000) + +#define SSB_EXTIF_NR_GPIOOUT 5 +/* GPIO NOTE: + * The multiple instances of output and output enable registers + * are present to allow driver software for multiple cores to control + * gpio outputs without needing to share a single register pair. + * Use the following helper macro to get a register offset value. + */ +#define SSB_EXTIF_GPIO_OUT(index) ({ \ + BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \ + SSB_EXTIF_GPIO_OUT_BASE + ((index) * 8); \ + }) +#define SSB_EXTIF_GPIO_OUTEN(index) ({ \ + BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \ + SSB_EXTIF_GPIO_OUTEN_BASE + ((index) * 8); \ + }) + +/** EXTIF core registers **/ + +#define SSB_EXTIF_CTL 0x0000 +#define SSB_EXTIF_CTL_UARTEN (1 << 0) /* UART enable */ +#define SSB_EXTIF_EXTSTAT 0x0004 +#define SSB_EXTIF_EXTSTAT_EMODE (1 << 0) /* Endian mode (ro) */ +#define SSB_EXTIF_EXTSTAT_EIRQPIN (1 << 1) /* External interrupt pin (ro) */ +#define SSB_EXTIF_EXTSTAT_GPIOIRQPIN (1 << 2) /* GPIO interrupt pin (ro) */ +#define SSB_EXTIF_PCMCIA_CFG 0x0010 +#define SSB_EXTIF_PCMCIA_MEMWAIT 0x0014 +#define SSB_EXTIF_PCMCIA_ATTRWAIT 0x0018 +#define SSB_EXTIF_PCMCIA_IOWAIT 0x001C +#define SSB_EXTIF_PROG_CFG 0x0020 +#define SSB_EXTIF_PROG_WAITCNT 0x0024 +#define SSB_EXTIF_FLASH_CFG 0x0028 +#define SSB_EXTIF_FLASH_WAITCNT 0x002C +#define SSB_EXTIF_WATCHDOG 0x0040 +#define SSB_EXTIF_CLOCK_N 0x0044 +#define SSB_EXTIF_CLOCK_SB 0x0048 +#define SSB_EXTIF_CLOCK_PCI 0x004C +#define SSB_EXTIF_CLOCK_MII 0x0050 +#define SSB_EXTIF_GPIO_IN 0x0060 +#define SSB_EXTIF_GPIO_OUT_BASE 0x0064 +#define SSB_EXTIF_GPIO_OUTEN_BASE 0x0068 +#define SSB_EXTIF_EJTAG_OUTEN 0x0090 +#define SSB_EXTIF_GPIO_INTPOL 0x0094 +#define SSB_EXTIF_GPIO_INTMASK 0x0098 +#define SSB_EXTIF_UART_DATA 0x0300 +#define SSB_EXTIF_UART_TIMER 0x0310 +#define SSB_EXTIF_UART_FCR 0x0320 +#define SSB_EXTIF_UART_LCR 0x0330 +#define SSB_EXTIF_UART_MCR 0x0340 +#define SSB_EXTIF_UART_LSR 0x0350 +#define SSB_EXTIF_UART_MSR 0x0360 +#define SSB_EXTIF_UART_SCRATCH 0x0370 + + + + +/* pcmcia/prog/flash_config */ +#define SSB_EXTCFG_EN (1 << 0) /* enable */ +#define SSB_EXTCFG_MODE 0xE /* mode */ +#define SSB_EXTCFG_MODE_SHIFT 1 +#define SSB_EXTCFG_MODE_FLASH 0x0 /* flash/asynchronous mode */ +#define SSB_EXTCFG_MODE_SYNC 0x2 /* synchronous mode */ +#define SSB_EXTCFG_MODE_PCMCIA 0x4 /* pcmcia mode */ +#define SSB_EXTCFG_DS16 (1 << 4) /* destsize: 0=8bit, 1=16bit */ +#define SSB_EXTCFG_BSWAP (1 << 5) /* byteswap */ +#define SSB_EXTCFG_CLKDIV 0xC0 /* clock divider */ +#define SSB_EXTCFG_CLKDIV_SHIFT 6 +#define SSB_EXTCFG_CLKDIV_2 0x0 /* backplane/2 */ +#define SSB_EXTCFG_CLKDIV_3 0x40 /* backplane/3 */ +#define SSB_EXTCFG_CLKDIV_4 0x80 /* backplane/4 */ +#define SSB_EXTCFG_CLKEN (1 << 8) /* clock enable */ +#define SSB_EXTCFG_STROBE (1 << 9) /* size/bytestrobe (synch only) */ + +/* pcmcia_memwait */ +#define SSB_PCMCIA_MEMW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_MEMW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_MEMW_1_SHIFT 8 +#define SSB_PCMCIA_MEMW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_MEMW_2_SHIFT 16 +#define SSB_PCMCIA_MEMW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_MEMW_3_SHIFT 24 + +/* pcmcia_attrwait */ +#define SSB_PCMCIA_ATTW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_ATTW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_ATTW_1_SHIFT 8 +#define SSB_PCMCIA_ATTW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_ATTW_2_SHIFT 16 +#define SSB_PCMCIA_ATTW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_ATTW_3_SHIFT 24 + +/* pcmcia_iowait */ +#define SSB_PCMCIA_IOW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_IOW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_IOW_1_SHIFT 8 +#define SSB_PCMCIA_IOW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_IOW_2_SHIFT 16 +#define SSB_PCMCIA_IOW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_IOW_3_SHIFT 24 + +/* prog_waitcount */ +#define SSB_PROG_WCNT_0 0x0000001F /* waitcount0 */ +#define SSB_PROG_WCNT_1 0x00001F00 /* waitcount1 */ +#define SSB_PROG_WCNT_1_SHIFT 8 +#define SSB_PROG_WCNT_2 0x001F0000 /* waitcount2 */ +#define SSB_PROG_WCNT_2_SHIFT 16 +#define SSB_PROG_WCNT_3 0x1F000000 /* waitcount3 */ +#define SSB_PROG_WCNT_3_SHIFT 24 + +#define SSB_PROG_W0 0x0000000C +#define SSB_PROG_W1 0x00000A00 +#define SSB_PROG_W2 0x00020000 +#define SSB_PROG_W3 0x01000000 + +/* flash_waitcount */ +#define SSB_FLASH_WCNT_0 0x0000001F /* waitcount0 */ +#define SSB_FLASH_WCNT_1 0x00001F00 /* waitcount1 */ +#define SSB_FLASH_WCNT_1_SHIFT 8 +#define SSB_FLASH_WCNT_2 0x001F0000 /* waitcount2 */ +#define SSB_FLASH_WCNT_2_SHIFT 16 +#define SSB_FLASH_WCNT_3 0x1F000000 /* waitcount3 */ +#define SSB_FLASH_WCNT_3_SHIFT 24 + +/* watchdog */ +#define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ + + + +#ifdef CONFIG_SSB_DRIVER_EXTIF + +struct ssb_extif { + struct ssb_device *dev; +}; + +static inline bool ssb_extif_available(struct ssb_extif *extif) +{ + return (extif->dev != NULL); +} + +extern void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *plltype, u32 *n, u32 *m); + +extern void ssb_extif_timing_init(struct ssb_extif *extif, + unsigned long ns); + +u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask); + +void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value); + +void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value); + +#ifdef CONFIG_SSB_SERIAL +extern int ssb_extif_serial_init(struct ssb_extif *extif, + struct ssb_serial_port *ports); +#endif /* CONFIG_SSB_SERIAL */ + + +#else /* CONFIG_SSB_DRIVER_EXTIF */ +/* extif disabled */ + +struct ssb_extif { +}; + +static inline bool ssb_extif_available(struct ssb_extif *extif) +{ + return 0; +} + +static inline +void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *plltype, u32 *n, u32 *m) +{ +} + +#endif /* CONFIG_SSB_DRIVER_EXTIF */ +#endif /* LINUX_SSB_EXTIFCORE_H_ */ diff --git a/include/linux/ssb/ssb_driver_mips.h b/include/linux/ssb/ssb_driver_mips.h new file mode 100644 index 000000000000..5f44e9740cd2 --- /dev/null +++ b/include/linux/ssb/ssb_driver_mips.h @@ -0,0 +1,46 @@ +#ifndef LINUX_SSB_MIPSCORE_H_ +#define LINUX_SSB_MIPSCORE_H_ + +#ifdef CONFIG_SSB_DRIVER_MIPS + +struct ssb_device; + +struct ssb_serial_port { + void *regs; + unsigned long clockspeed; + unsigned int irq; + unsigned int baud_base; + unsigned int reg_shift; +}; + + +struct ssb_mipscore { + struct ssb_device *dev; + + int nr_serial_ports; + struct ssb_serial_port serial_ports[4]; + + u8 flash_buswidth; + u32 flash_window; + u32 flash_window_size; +}; + +extern void ssb_mipscore_init(struct ssb_mipscore *mcore); +extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore); + +extern unsigned int ssb_mips_irq(struct ssb_device *dev); + + +#else /* CONFIG_SSB_DRIVER_MIPS */ + +struct ssb_mipscore { +}; + +static inline +void ssb_mipscore_init(struct ssb_mipscore *mcore) +{ +} + +#endif /* CONFIG_SSB_DRIVER_MIPS */ + +#endif /* LINUX_SSB_MIPSCORE_H_ */ diff --git a/include/linux/ssb/ssb_driver_pci.h b/include/linux/ssb/ssb_driver_pci.h new file mode 100644 index 000000000000..9cfffb7b1a27 --- /dev/null +++ b/include/linux/ssb/ssb_driver_pci.h @@ -0,0 +1,106 @@ +#ifndef LINUX_SSB_PCICORE_H_ +#define LINUX_SSB_PCICORE_H_ + +#ifdef CONFIG_SSB_DRIVER_PCICORE + +/* PCI core registers. */ +#define SSB_PCICORE_CTL 0x0000 /* PCI Control */ +#define SSB_PCICORE_CTL_RST_OE 0x00000001 /* PCI_RESET Output Enable */ +#define SSB_PCICORE_CTL_RST 0x00000002 /* PCI_RESET driven out to pin */ +#define SSB_PCICORE_CTL_CLK_OE 0x00000004 /* Clock gate Output Enable */ +#define SSB_PCICORE_CTL_CLK 0x00000008 /* Gate for clock driven out to pin */ +#define SSB_PCICORE_ARBCTL 0x0010 /* PCI Arbiter Control */ +#define SSB_PCICORE_ARBCTL_INTERN 0x00000001 /* Use internal arbiter */ +#define SSB_PCICORE_ARBCTL_EXTERN 0x00000002 /* Use external arbiter */ +#define SSB_PCICORE_ARBCTL_PARKID 0x00000006 /* Mask, selects which agent is parked on an idle bus */ +#define SSB_PCICORE_ARBCTL_PARKID_LAST 0x00000000 /* Last requestor */ +#define SSB_PCICORE_ARBCTL_PARKID_4710 0x00000002 /* 4710 */ +#define SSB_PCICORE_ARBCTL_PARKID_EXT0 0x00000004 /* External requestor 0 */ +#define SSB_PCICORE_ARBCTL_PARKID_EXT1 0x00000006 /* External requestor 1 */ +#define SSB_PCICORE_ISTAT 0x0020 /* Interrupt status */ +#define SSB_PCICORE_ISTAT_INTA 0x00000001 /* PCI INTA# */ +#define SSB_PCICORE_ISTAT_INTB 0x00000002 /* PCI INTB# */ +#define SSB_PCICORE_ISTAT_SERR 0x00000004 /* PCI SERR# (write to clear) */ +#define SSB_PCICORE_ISTAT_PERR 0x00000008 /* PCI PERR# (write to clear) */ +#define SSB_PCICORE_ISTAT_PME 0x00000010 /* PCI PME# */ +#define SSB_PCICORE_IMASK 0x0024 /* Interrupt mask */ +#define SSB_PCICORE_IMASK_INTA 0x00000001 /* PCI INTA# */ +#define SSB_PCICORE_IMASK_INTB 0x00000002 /* PCI INTB# */ +#define SSB_PCICORE_IMASK_SERR 0x00000004 /* PCI SERR# */ +#define SSB_PCICORE_IMASK_PERR 0x00000008 /* PCI PERR# */ +#define SSB_PCICORE_IMASK_PME 0x00000010 /* PCI PME# */ +#define SSB_PCICORE_MBOX 0x0028 /* Backplane to PCI Mailbox */ +#define SSB_PCICORE_MBOX_F0_0 0x00000100 /* PCI function 0, INT 0 */ +#define SSB_PCICORE_MBOX_F0_1 0x00000200 /* PCI function 0, INT 1 */ +#define SSB_PCICORE_MBOX_F1_0 0x00000400 /* PCI function 1, INT 0 */ +#define SSB_PCICORE_MBOX_F1_1 0x00000800 /* PCI function 1, INT 1 */ +#define SSB_PCICORE_MBOX_F2_0 0x00001000 /* PCI function 2, INT 0 */ +#define SSB_PCICORE_MBOX_F2_1 0x00002000 /* PCI function 2, INT 1 */ +#define SSB_PCICORE_MBOX_F3_0 0x00004000 /* PCI function 3, INT 0 */ +#define SSB_PCICORE_MBOX_F3_1 0x00008000 /* PCI function 3, INT 1 */ +#define SSB_PCICORE_BCAST_ADDR 0x0050 /* Backplane Broadcast Address */ +#define SSB_PCICORE_BCAST_ADDR_MASK 0x000000FF +#define SSB_PCICORE_BCAST_DATA 0x0054 /* Backplane Broadcast Data */ +#define SSB_PCICORE_GPIO_IN 0x0060 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_OUT 0x0064 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_ENABLE 0x0068 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_CTL 0x006C /* rev >= 2 only */ +#define SSB_PCICORE_SBTOPCI0 0x0100 /* Backplane to PCI translation 0 (sbtopci0) */ +#define SSB_PCICORE_SBTOPCI0_MASK 0xFC000000 +#define SSB_PCICORE_SBTOPCI1 0x0104 /* Backplane to PCI translation 1 (sbtopci1) */ +#define SSB_PCICORE_SBTOPCI1_MASK 0xFC000000 +#define SSB_PCICORE_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */ +#define SSB_PCICORE_SBTOPCI2_MASK 0xC0000000 + +/* SBtoPCIx */ +#define SSB_PCICORE_SBTOPCI_MEM 0x00000000 +#define SSB_PCICORE_SBTOPCI_IO 0x00000001 +#define SSB_PCICORE_SBTOPCI_CFG0 0x00000002 +#define SSB_PCICORE_SBTOPCI_CFG1 0x00000003 +#define SSB_PCICORE_SBTOPCI_PREF 0x00000004 /* Prefetch enable */ +#define SSB_PCICORE_SBTOPCI_BURST 0x00000008 /* Burst enable */ +#define SSB_PCICORE_SBTOPCI_MRM 0x00000020 /* Memory Read Multiple */ +#define SSB_PCICORE_SBTOPCI_RC 0x00000030 /* Read Command mask (rev >= 11) */ +#define SSB_PCICORE_SBTOPCI_RC_READ 0x00000000 /* Memory read */ +#define SSB_PCICORE_SBTOPCI_RC_READL 0x00000010 /* Memory read line */ +#define SSB_PCICORE_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */ + + +/* PCIcore specific boardflags */ +#define SSB_PCICORE_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ + + +struct ssb_pcicore { + struct ssb_device *dev; + u8 setup_done:1; + u8 hostmode:1; + u8 cardbusmode:1; +}; + +extern void ssb_pcicore_init(struct ssb_pcicore *pc); + +/* Enable IRQ routing for a specific device */ +extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev); + + +#else /* CONFIG_SSB_DRIVER_PCICORE */ + + +struct ssb_pcicore { +}; + +static inline +void ssb_pcicore_init(struct ssb_pcicore *pc) +{ +} + +static inline +int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev) +{ + return 0; +} + +#endif /* CONFIG_SSB_DRIVER_PCICORE */ +#endif /* LINUX_SSB_PCICORE_H_ */ diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h new file mode 100644 index 000000000000..47c7c71a5acf --- /dev/null +++ b/include/linux/ssb/ssb_regs.h @@ -0,0 +1,292 @@ +#ifndef LINUX_SSB_REGS_H_ +#define LINUX_SSB_REGS_H_ + + +/* SiliconBackplane Address Map. + * All regions may not exist on all chips. + */ +#define SSB_SDRAM_BASE 0x00000000U /* Physical SDRAM */ +#define SSB_PCI_MEM 0x08000000U /* Host Mode sb2pcitranslation0 (64 MB) */ +#define SSB_PCI_CFG 0x0c000000U /* Host Mode sb2pcitranslation1 (64 MB) */ +#define SSB_SDRAM_SWAPPED 0x10000000U /* Byteswapped Physical SDRAM */ +#define SSB_ENUM_BASE 0x18000000U /* Enumeration space base */ +#define SSB_ENUM_LIMIT 0x18010000U /* Enumeration space limit */ + +#define SSB_FLASH2 0x1c000000U /* Flash Region 2 (region 1 shadowed here) */ +#define SSB_FLASH2_SZ 0x02000000U /* Size of Flash Region 2 */ + +#define SSB_EXTIF_BASE 0x1f000000U /* External Interface region base address */ +#define SSB_FLASH1 0x1fc00000U /* Flash Region 1 */ +#define SSB_FLASH1_SZ 0x00400000U /* Size of Flash Region 1 */ + +#define SSB_PCI_DMA 0x40000000U /* Client Mode sb2pcitranslation2 (1 GB) */ +#define SSB_PCI_DMA_SZ 0x40000000U /* Client Mode sb2pcitranslation2 size in bytes */ +#define SSB_PCIE_DMA_L32 0x00000000U /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), low 32 bits */ +#define SSB_PCIE_DMA_H32 0x80000000U /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */ +#define SSB_EUART (SSB_EXTIF_BASE + 0x00800000) +#define SSB_LED (SSB_EXTIF_BASE + 0x00900000) + + +/* Enumeration space constants */ +#define SSB_CORE_SIZE 0x1000 /* Size of a core MMIO area */ +#define SSB_MAX_NR_CORES ((SSB_ENUM_LIMIT - SSB_ENUM_BASE) / SSB_CORE_SIZE) + + +/* mips address */ +#define SSB_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */ + + +/* SSB PCI config space registers. */ +#define SSB_PMCSR 0x44 +#define SSB_PE 0x100 +#define SSB_BAR0_WIN 0x80 /* Backplane address space 0 */ +#define SSB_BAR1_WIN 0x84 /* Backplane address space 1 */ +#define SSB_SPROMCTL 0x88 /* SPROM control */ +#define SSB_SPROMCTL_WE 0x10 /* SPROM write enable */ +#define SSB_BAR1_CONTROL 0x8c /* Address space 1 burst control */ +#define SSB_PCI_IRQS 0x90 /* PCI interrupts */ +#define SSB_PCI_IRQMASK 0x94 /* PCI IRQ control and mask (pcirev >= 6 only) */ +#define SSB_BACKPLANE_IRQS 0x98 /* Backplane Interrupts */ +#define SSB_GPIO_IN 0xB0 /* GPIO Input (pcirev >= 3 only) */ +#define SSB_GPIO_OUT 0xB4 /* GPIO Output (pcirev >= 3 only) */ +#define SSB_GPIO_OUT_ENABLE 0xB8 /* GPIO Output Enable/Disable (pcirev >= 3 only) */ +#define SSB_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ +#define SSB_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ +#define SSB_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */ +#define SSB_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */ + + +#define SSB_BAR0_MAX_RETRIES 50 + +/* Silicon backplane configuration register definitions */ +#define SSB_IPSFLAG 0x0F08 +#define SSB_IPSFLAG_IRQ1 0x0000003F /* which sbflags get routed to mips interrupt 1 */ +#define SSB_IPSFLAG_IRQ1_SHIFT 0 +#define SSB_IPSFLAG_IRQ2 0x00003F00 /* which sbflags get routed to mips interrupt 2 */ +#define SSB_IPSFLAG_IRQ2_SHIFT 8 +#define SSB_IPSFLAG_IRQ3 0x003F0000 /* which sbflags get routed to mips interrupt 3 */ +#define SSB_IPSFLAG_IRQ3_SHIFT 16 +#define SSB_IPSFLAG_IRQ4 0x3F000000 /* which sbflags get routed to mips interrupt 4 */ +#define SSB_IPSFLAG_IRQ4_SHIFT 24 +#define SSB_TPSFLAG 0x0F18 +#define SSB_TPSFLAG_BPFLAG 0x0000003F /* Backplane flag # */ +#define SSB_TPSFLAG_ALWAYSIRQ 0x00000040 /* IRQ is always sent on the Backplane */ +#define SSB_TMERRLOGA 0x0F48 +#define SSB_TMERRLOG 0x0F50 +#define SSB_ADMATCH3 0x0F60 +#define SSB_ADMATCH2 0x0F68 +#define SSB_ADMATCH1 0x0F70 +#define SSB_IMSTATE 0x0F90 /* SB Initiator Agent State */ +#define SSB_IMSTATE_PC 0x0000000f /* Pipe Count */ +#define SSB_IMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ +#define SSB_IMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */ +#define SSB_IMSTATE_AP_TS 0x00000010 /* Use timeslices only */ +#define SSB_IMSTATE_AP_TK 0x00000020 /* Use token only */ +#define SSB_IMSTATE_AP_RSV 0x00000030 /* Reserved */ +#define SSB_IMSTATE_IBE 0x00020000 /* In Band Error */ +#define SSB_IMSTATE_TO 0x00040000 /* Timeout */ +#define SSB_INTVEC 0x0F94 /* SB Interrupt Mask */ +#define SSB_INTVEC_PCI 0x00000001 /* Enable interrupts for PCI */ +#define SSB_INTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */ +#define SSB_INTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */ +#define SSB_INTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */ +#define SSB_INTVEC_USB 0x00000010 /* Enable interrupts for usb */ +#define SSB_INTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */ +#define SSB_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ +#define SSB_TMSLOW 0x0F98 /* SB Target State Low */ +#define SSB_TMSLOW_RESET 0x00000001 /* Reset */ +#define SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */ +#define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */ +#define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */ +#define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ +#define SSB_TMSLOW_PE 0x40000000 /* Power Management Enable */ +#define SSB_TMSLOW_BE 0x80000000 /* BIST Enable */ +#define SSB_TMSHIGH 0x0F9C /* SB Target State High */ +#define SSB_TMSHIGH_SERR 0x00000001 /* S-error */ +#define SSB_TMSHIGH_INT 0x00000002 /* Interrupt */ +#define SSB_TMSHIGH_BUSY 0x00000004 /* Busy */ +#define SSB_TMSHIGH_TO 0x00000020 /* Timeout. Backplane rev >= 2.3 only */ +#define SSB_TMSHIGH_COREFL 0x1FFF0000 /* Core specific flags */ +#define SSB_TMSHIGH_COREFL_SHIFT 16 +#define SSB_TMSHIGH_DMA64 0x10000000 /* 64bit DMA supported */ +#define SSB_TMSHIGH_GCR 0x20000000 /* Gated Clock Request */ +#define SSB_TMSHIGH_BISTF 0x40000000 /* BIST Failed */ +#define SSB_TMSHIGH_BISTD 0x80000000 /* BIST Done */ +#define SSB_BWA0 0x0FA0 +#define SSB_IMCFGLO 0x0FA8 +#define SSB_IMCFGLO_SERTO 0x00000007 /* Service timeout */ +#define SSB_IMCFGLO_REQTO 0x00000070 /* Request timeout */ +#define SSB_IMCFGLO_REQTO_SHIFT 4 +#define SSB_IMCFGLO_CONNID 0x00FF0000 /* Connection ID */ +#define SSB_IMCFGLO_CONNID_SHIFT 16 +#define SSB_IMCFGHI 0x0FAC +#define SSB_ADMATCH0 0x0FB0 +#define SSB_TMCFGLO 0x0FB8 +#define SSB_TMCFGHI 0x0FBC +#define SSB_BCONFIG 0x0FC0 +#define SSB_BSTATE 0x0FC8 +#define SSB_ACTCFG 0x0FD8 +#define SSB_FLAGST 0x0FE8 +#define SSB_IDLOW 0x0FF8 +#define SSB_IDLOW_CFGSP 0x00000003 /* Config Space */ +#define SSB_IDLOW_ADDRNGE 0x00000038 /* Address Ranges supported */ +#define SSB_IDLOW_ADDRNGE_SHIFT 3 +#define SSB_IDLOW_SYNC 0x00000040 +#define SSB_IDLOW_INITIATOR 0x00000080 +#define SSB_IDLOW_MIBL 0x00000F00 /* Minimum Backplane latency */ +#define SSB_IDLOW_MIBL_SHIFT 8 +#define SSB_IDLOW_MABL 0x0000F000 /* Maximum Backplane latency */ +#define SSB_IDLOW_MABL_SHIFT 12 +#define SSB_IDLOW_TIF 0x00010000 /* This Initiator is first */ +#define SSB_IDLOW_CCW 0x000C0000 /* Cycle counter width */ +#define SSB_IDLOW_CCW_SHIFT 18 +#define SSB_IDLOW_TPT 0x00F00000 /* Target ports */ +#define SSB_IDLOW_TPT_SHIFT 20 +#define SSB_IDLOW_INITP 0x0F000000 /* Initiator ports */ +#define SSB_IDLOW_INITP_SHIFT 24 +#define SSB_IDLOW_SSBREV 0xF0000000 /* Sonics Backplane Revision code */ +#define SSB_IDLOW_SSBREV_22 0x00000000 /* <= 2.2 */ +#define SSB_IDLOW_SSBREV_23 0x10000000 /* 2.3 */ +#define SSB_IDHIGH 0x0FFC /* SB Identification High */ +#define SSB_IDHIGH_RCLO 0x0000000F /* Revision Code (low part) */ +#define SSB_IDHIGH_CC 0x00008FF0 /* Core Code */ +#define SSB_IDHIGH_CC_SHIFT 4 +#define SSB_IDHIGH_RCHI 0x00007000 /* Revision Code (high part) */ +#define SSB_IDHIGH_RCHI_SHIFT 8 /* yes, shift 8 is right */ +#define SSB_IDHIGH_VC 0xFFFF0000 /* Vendor Code */ +#define SSB_IDHIGH_VC_SHIFT 16 + +/* SPROM shadow area. If not otherwise noted, fields are + * two bytes wide. Note that the SPROM can _only_ be read + * in two-byte quantinies. + */ +#define SSB_SPROMSIZE_WORDS 64 +#define SSB_SPROMSIZE_BYTES (SSB_SPROMSIZE_WORDS * sizeof(u16)) +#define SSB_SPROM_BASE 0x1000 +#define SSB_SPROM_REVISION 0x107E +#define SSB_SPROM_REVISION_REV 0x00FF /* SPROM Revision number */ +#define SSB_SPROM_REVISION_CRC 0xFF00 /* SPROM CRC8 value */ +#define SSB_SPROM_REVISION_CRC_SHIFT 8 +/* SPROM Revision 1 */ +#define SSB_SPROM1_SPID 0x1004 /* Subsystem Product ID for PCI */ +#define SSB_SPROM1_SVID 0x1006 /* Subsystem Vendor ID for PCI */ +#define SSB_SPROM1_PID 0x1008 /* Product ID for PCI */ +#define SSB_SPROM1_IL0MAC 0x1048 /* 6 bytes MAC address for 802.11b/g */ +#define SSB_SPROM1_ET0MAC 0x104E /* 6 bytes MAC address for Ethernet */ +#define SSB_SPROM1_ET1MAC 0x1054 /* 6 bytes MAC address for 802.11a */ +#define SSB_SPROM1_ETHPHY 0x105A /* Ethernet PHY settings */ +#define SSB_SPROM1_ETHPHY_ET0A 0x001F /* MII Address for enet0 */ +#define SSB_SPROM1_ETHPHY_ET1A 0x03E0 /* MII Address for enet1 */ +#define SSB_SPROM1_ETHPHY_ET1A_SHIFT 5 +#define SSB_SPROM1_ETHPHY_ET0M (1<<14) /* MDIO for enet0 */ +#define SSB_SPROM1_ETHPHY_ET1M (1<<15) /* MDIO for enet1 */ +#define SSB_SPROM1_BINF 0x105C /* Board info */ +#define SSB_SPROM1_BINF_BREV 0x00FF /* Board Revision */ +#define SSB_SPROM1_BINF_CCODE 0x0F00 /* Country Code */ +#define SSB_SPROM1_BINF_CCODE_SHIFT 8 +#define SSB_SPROM1_BINF_ANTA 0x3000 /* Available A-PHY antennas */ +#define SSB_SPROM1_BINF_ANTA_SHIFT 12 +#define SSB_SPROM1_BINF_ANTBG 0xC000 /* Available B-PHY antennas */ +#define SSB_SPROM1_BINF_ANTBG_SHIFT 14 +#define SSB_SPROM1_PA0B0 0x105E +#define SSB_SPROM1_PA0B1 0x1060 +#define SSB_SPROM1_PA0B2 0x1062 +#define SSB_SPROM1_GPIOA 0x1064 /* General Purpose IO pins 0 and 1 */ +#define SSB_SPROM1_GPIOA_P0 0x00FF /* Pin 0 */ +#define SSB_SPROM1_GPIOA_P1 0xFF00 /* Pin 1 */ +#define SSB_SPROM1_GPIOA_P1_SHIFT 8 +#define SSB_SPROM1_GPIOB 0x1066 /* General Purpuse IO pins 2 and 3 */ +#define SSB_SPROM1_GPIOB_P2 0x00FF /* Pin 2 */ +#define SSB_SPROM1_GPIOB_P3 0xFF00 /* Pin 3 */ +#define SSB_SPROM1_GPIOB_P3_SHIFT 8 +#define SSB_SPROM1_MAXPWR 0x1068 /* Power Amplifier Max Power */ +#define SSB_SPROM1_MAXPWR_BG 0x00FF /* B-PHY and G-PHY (in dBm Q5.2) */ +#define SSB_SPROM1_MAXPWR_A 0xFF00 /* A-PHY (in dBm Q5.2) */ +#define SSB_SPROM1_MAXPWR_A_SHIFT 8 +#define SSB_SPROM1_PA1B0 0x106A +#define SSB_SPROM1_PA1B1 0x106C +#define SSB_SPROM1_PA1B2 0x106E +#define SSB_SPROM1_ITSSI 0x1070 /* Idle TSSI Target */ +#define SSB_SPROM1_ITSSI_BG 0x00FF /* B-PHY and G-PHY*/ +#define SSB_SPROM1_ITSSI_A 0xFF00 /* A-PHY */ +#define SSB_SPROM1_ITSSI_A_SHIFT 8 +#define SSB_SPROM1_BFLLO 0x1072 /* Boardflags (low 16 bits) */ +#define SSB_SPROM1_AGAIN 0x1074 /* Antenna Gain (in dBm Q5.2) */ +#define SSB_SPROM1_AGAIN_A 0x00FF /* A-PHY */ +#define SSB_SPROM1_AGAIN_BG 0xFF00 /* B-PHY and G-PHY */ +#define SSB_SPROM1_AGAIN_BG_SHIFT 8 +#define SSB_SPROM1_OEM 0x1076 /* 8 bytes OEM string (rev 1 only) */ +/* SPROM Revision 2 (inherits from rev 1) */ +#define SSB_SPROM2_BFLHI 0x1038 /* Boardflags (high 16 bits) */ +#define SSB_SPROM2_MAXP_A 0x103A /* A-PHY Max Power */ +#define SSB_SPROM2_MAXP_A_HI 0x00FF /* Max Power High */ +#define SSB_SPROM2_MAXP_A_LO 0xFF00 /* Max Power Low */ +#define SSB_SPROM2_MAXP_A_LO_SHIFT 8 +#define SSB_SPROM2_PA1LOB0 0x103C /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1LOB1 0x103E /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1LOB2 0x1040 /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1HIB0 0x1042 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_PA1HIB1 0x1044 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_PA1HIB2 0x1046 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_OPO 0x1078 /* OFDM Power Offset from CCK Level */ +#define SSB_SPROM2_OPO_VALUE 0x00FF +#define SSB_SPROM2_OPO_UNUSED 0xFF00 +#define SSB_SPROM2_CCODE 0x107C /* Two char Country Code */ +/* SPROM Revision 3 (inherits from rev 2) */ +#define SSB_SPROM3_OFDMAPO 0x102C /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_OFDMALPO 0x1030 /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_OFDMAHPO 0x1034 /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_GPIOLDC 0x1042 /* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */ +#define SSB_SPROM3_GPIOLDC_OFF 0x0000FF00 /* Off Count */ +#define SSB_SPROM3_GPIOLDC_OFF_SHIFT 8 +#define SSB_SPROM3_GPIOLDC_ON 0x00FF0000 /* On Count */ +#define SSB_SPROM3_GPIOLDC_ON_SHIFT 16 +#define SSB_SPROM3_CCKPO 0x1078 /* CCK Power Offset */ +#define SSB_SPROM3_CCKPO_1M 0x000F /* 1M Rate PO */ +#define SSB_SPROM3_CCKPO_2M 0x00F0 /* 2M Rate PO */ +#define SSB_SPROM3_CCKPO_2M_SHIFT 4 +#define SSB_SPROM3_CCKPO_55M 0x0F00 /* 5.5M Rate PO */ +#define SSB_SPROM3_CCKPO_55M_SHIFT 8 +#define SSB_SPROM3_CCKPO_11M 0xF000 /* 11M Rate PO */ +#define SSB_SPROM3_CCKPO_11M_SHIFT 12 +#define SSB_SPROM3_OFDMGPO 0x107A /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */ + +/* Values for SSB_SPROM1_BINF_CCODE */ +enum { + SSB_SPROM1CCODE_WORLD = 0, + SSB_SPROM1CCODE_THAILAND, + SSB_SPROM1CCODE_ISRAEL, + SSB_SPROM1CCODE_JORDAN, + SSB_SPROM1CCODE_CHINA, + SSB_SPROM1CCODE_JAPAN, + SSB_SPROM1CCODE_USA_CANADA_ANZ, + SSB_SPROM1CCODE_EUROPE, + SSB_SPROM1CCODE_USA_LOW, + SSB_SPROM1CCODE_JAPAN_HIGH, + SSB_SPROM1CCODE_ALL, + SSB_SPROM1CCODE_NONE, +}; + +/* Address-Match values and masks (SSB_ADMATCHxxx) */ +#define SSB_ADM_TYPE 0x00000003 /* Address type */ +#define SSB_ADM_TYPE0 0 +#define SSB_ADM_TYPE1 1 +#define SSB_ADM_TYPE2 2 +#define SSB_ADM_AD64 0x00000004 +#define SSB_ADM_SZ0 0x000000F8 /* Type0 size */ +#define SSB_ADM_SZ0_SHIFT 3 +#define SSB_ADM_SZ1 0x000001F8 /* Type1 size */ +#define SSB_ADM_SZ1_SHIFT 3 +#define SSB_ADM_SZ2 0x000001F8 /* Type2 size */ +#define SSB_ADM_SZ2_SHIFT 3 +#define SSB_ADM_EN 0x00000400 /* Enable */ +#define SSB_ADM_NEG 0x00000800 /* Negative decode */ +#define SSB_ADM_BASE0 0xFFFFFF00 /* Type0 base address */ +#define SSB_ADM_BASE0_SHIFT 8 +#define SSB_ADM_BASE1 0xFFFFF000 /* Type1 base address for the core */ +#define SSB_ADM_BASE1_SHIFT 12 +#define SSB_ADM_BASE2 0xFFFF0000 /* Type2 base address for the core */ +#define SSB_ADM_BASE2_SHIFT 16 + + +#endif /* LINUX_SSB_REGS_H_ */ diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 8a09021d8c59..895ba3ac6208 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -484,6 +484,21 @@ static int do_parisc_entry(const char *filename, struct parisc_device_id *id, return 1; } +/* Looks like: ssb:vNidNrevN. */ +static int do_ssb_entry(const char *filename, + struct ssb_device_id *id, char *alias) +{ + id->vendor = TO_NATIVE(id->vendor); + id->coreid = TO_NATIVE(id->coreid); + id->revision = TO_NATIVE(id->revision); + + strcpy(alias, "ssb:"); + ADD(alias, "v", id->vendor != SSB_ANY_VENDOR, id->vendor); + ADD(alias, "id", id->coreid != SSB_ANY_ID, id->coreid); + ADD(alias, "rev", id->revision != SSB_ANY_REV, id->revision); + return 1; +} + /* Ignore any prefix, eg. v850 prepends _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -599,6 +614,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct parisc_device_id), "parisc", do_parisc_entry, mod); + else if (sym_is(symname, "__mod_ssb_device_table")) + do_table(symval, sym->st_size, + sizeof(struct ssb_device_id), "ssb", + do_ssb_entry, mod); } /* Now add out buffered information to the generated C source */ From e4d6b7951812d98417feb10784e400e253caf633 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 18 Sep 2007 15:39:42 -0400 Subject: [PATCH 1420/2804] [B43]: add mac80211-based driver for modern BCM43xx devices Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 9 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/b43/Kconfig | 119 + drivers/net/wireless/b43/Makefile | 17 + drivers/net/wireless/b43/b43.h | 845 ++++++ drivers/net/wireless/b43/debugfs.c | 654 +++++ drivers/net/wireless/b43/debugfs.h | 89 + drivers/net/wireless/b43/dma.c | 1494 ++++++++++ drivers/net/wireless/b43/dma.h | 337 +++ drivers/net/wireless/b43/leds.c | 299 ++ drivers/net/wireless/b43/leds.h | 55 + drivers/net/wireless/b43/lo.c | 1261 ++++++++ drivers/net/wireless/b43/lo.h | 112 + drivers/net/wireless/b43/main.c | 4091 ++++++++++++++++++++++++++ drivers/net/wireless/b43/main.h | 142 + drivers/net/wireless/b43/pcmcia.c | 157 + drivers/net/wireless/b43/pcmcia.h | 20 + drivers/net/wireless/b43/phy.c | 4351 ++++++++++++++++++++++++++++ drivers/net/wireless/b43/phy.h | 297 ++ drivers/net/wireless/b43/pio.c | 650 +++++ drivers/net/wireless/b43/pio.h | 153 + drivers/net/wireless/b43/sysfs.c | 235 ++ drivers/net/wireless/b43/sysfs.h | 9 + drivers/net/wireless/b43/tables.c | 375 +++ drivers/net/wireless/b43/tables.h | 28 + drivers/net/wireless/b43/xmit.c | 648 +++++ drivers/net/wireless/b43/xmit.h | 250 ++ 28 files changed, 16699 insertions(+) create mode 100644 drivers/net/wireless/b43/Kconfig create mode 100644 drivers/net/wireless/b43/Makefile create mode 100644 drivers/net/wireless/b43/b43.h create mode 100644 drivers/net/wireless/b43/debugfs.c create mode 100644 drivers/net/wireless/b43/debugfs.h create mode 100644 drivers/net/wireless/b43/dma.c create mode 100644 drivers/net/wireless/b43/dma.h create mode 100644 drivers/net/wireless/b43/leds.c create mode 100644 drivers/net/wireless/b43/leds.h create mode 100644 drivers/net/wireless/b43/lo.c create mode 100644 drivers/net/wireless/b43/lo.h create mode 100644 drivers/net/wireless/b43/main.c create mode 100644 drivers/net/wireless/b43/main.h create mode 100644 drivers/net/wireless/b43/pcmcia.c create mode 100644 drivers/net/wireless/b43/pcmcia.h create mode 100644 drivers/net/wireless/b43/phy.c create mode 100644 drivers/net/wireless/b43/phy.h create mode 100644 drivers/net/wireless/b43/pio.c create mode 100644 drivers/net/wireless/b43/pio.h create mode 100644 drivers/net/wireless/b43/sysfs.c create mode 100644 drivers/net/wireless/b43/sysfs.h create mode 100644 drivers/net/wireless/b43/tables.c create mode 100644 drivers/net/wireless/b43/tables.h create mode 100644 drivers/net/wireless/b43/xmit.c create mode 100644 drivers/net/wireless/b43/xmit.h diff --git a/MAINTAINERS b/MAINTAINERS index 7524cd802da3..e6589c3b69c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -795,6 +795,15 @@ L: linux-hams@vger.kernel.org W: http://www.baycom.org/~tom/ham/ham.html S: Maintained +B43 WIRELESS DRIVER +P: Michael Buesch +M: mb@bu3sch.de +P: Stefano Brivio +M: st3@riseup.net +L: linux-wireless@vger.kernel.org +W: http://bcm43xx.berlios.de/ +S: Maintained + BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION) P: Larry Finger M: Larry.Finger@lwfinger.net diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8d1541bbe257..7bed87e63da2 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -579,6 +579,7 @@ config ADM8211 source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" +source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index e9bffdae0a04..765dbbcf54be 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_BCM43XX) += bcm43xx/ +obj-$(CONFIG_B43) += b43/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ # 16-bit wireless PCMCIA client drivers diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig new file mode 100644 index 000000000000..4620119891f2 --- /dev/null +++ b/drivers/net/wireless/b43/Kconfig @@ -0,0 +1,119 @@ +config B43 + tristate "Broadcom 43xx wireless support (mac80211 stack)" + depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 + select SSB + select FW_LOADER + select HW_RANDOM + ---help--- + b43 is a driver for the Broadcom 43xx series wireless devices. + + Check "lspci" for something like + "Broadcom Corporation BCM43XX 802.11 Wireless LAN Controller" + to determine whether you own such a device. + + This driver supports the new BCM43xx IEEE 802.11G devices, but not + the old IEEE 802.11B devices. Old devices are supported by + the b43legacy driver. + Note that this has nothing to do with the standard that your AccessPoint + supports (A, B, G or a combination). + IEEE 802.11G devices can talk to IEEE 802.11B AccessPoints. + + It is safe to include both b43 and b43legacy as the underlying glue + layer will automatically load the correct version for your device. + + This driver uses V4 firmware, which must be installed separately using + b43-fwcutter. + + This driver can be built as a module (recommended) that will be called "b43". + If unsure, say M. + +# Auto-select SSB PCI-HOST support, if possible +config B43_PCI_AUTOSELECT + bool + depends on B43 && SSB_PCIHOST_POSSIBLE + select SSB_PCIHOST + default y + +# Auto-select SSB PCICORE driver, if possible +config B43_PCICORE_AUTOSELECT + bool + depends on B43 && SSB_DRIVER_PCICORE_POSSIBLE + select SSB_DRIVER_PCICORE + default y + +config B43_PCMCIA + bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)" + depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL + select SSB_PCMCIAHOST + ---help--- + Broadcom 43xx PCMCIA device support. + + Support for 16bit PCMCIA devices. + Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA + devices, but 32bit CardBUS devices. CardBUS devices are supported + out of the box by b43. + + With this config option you can drive b43 cards in + CompactFlash formfactor in a PCMCIA adaptor. + CF b43 cards can sometimes be found in handheld PCs. + + It's safe to select Y here, even if you don't have a B43 PCMCIA device. + + If unsure, say N. + +config B43_DEBUG + bool "Broadcom 43xx debugging" + depends on B43 + ---help--- + Broadcom 43xx debugging messages. + + Say Y, if you want to find out why the driver does not + work for you. + +config B43_DMA + bool + depends on B43 +config B43_PIO + bool + depends on B43 + +choice + prompt "Broadcom 43xx data transfer mode" + depends on B43 + default B43_DMA_AND_PIO_MODE + +config B43_DMA_AND_PIO_MODE + bool "DMA + PIO" + select B43_DMA + select B43_PIO + ---help--- + Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) + data transfer modes. + The actually used mode is selectable through the module + parameter "pio". If the module parameter is pio=0, DMA is used. + Otherwise PIO is used. DMA is default. + + If unsure, choose this option. + +config B43_DMA_MODE + bool "DMA (Direct Memory Access) only" + select B43_DMA + ---help--- + Only include Direct Memory Access (DMA). + This reduces the size of the driver module, by omitting the PIO code. + +config B43_PIO_MODE + bool "PIO (Programmed I/O) only" + select B43_PIO + ---help--- + Only include Programmed I/O (PIO). + This reduces the size of the driver module, by omitting the DMA code. + Please note that PIO transfers are slow (compared to DMA). + + Also note that not all devices of the 43xx series support PIO. + The 4306 (Apple Airport Extreme and others) supports PIO, while + the 4318 is known to _not_ support PIO. + + Only use PIO, if DMA does not work for you. + +endchoice diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile new file mode 100644 index 000000000000..370935b84c5e --- /dev/null +++ b/drivers/net/wireless/b43/Makefile @@ -0,0 +1,17 @@ +# b43 core +b43-y += main.o +b43-y += tables.o +b43-y += phy.o +b43-y += sysfs.o +b43-y += leds.o +b43-y += xmit.o +b43-y += lo.o +# b43 PCMCIA support +b43-$(CONFIG_B43_PCMCIA) += pcmcia.o +# b43 debugging +b43-$(CONFIG_B43_DEBUG) += debugfs.o +# b43 DMA and PIO +b43-$(CONFIG_B43_DMA) += dma.o +b43-$(CONFIG_B43_PIO) += pio.o + +obj-$(CONFIG_B43) += b43.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h new file mode 100644 index 000000000000..270a2112de2a --- /dev/null +++ b/drivers/net/wireless/b43/b43.h @@ -0,0 +1,845 @@ +#ifndef B43_H_ +#define B43_H_ + +#include +#include +#include +#include +#include +#include + +#include "debugfs.h" +#include "leds.h" +#include "lo.h" +#include "phy.h" + +#ifdef CONFIG_B43_DEBUG +# define B43_DEBUG 1 +#else +# define B43_DEBUG 0 +#endif + +#define B43_RX_MAX_SSI 60 + +/* MMIO offsets */ +#define B43_MMIO_DMA0_REASON 0x20 +#define B43_MMIO_DMA0_IRQ_MASK 0x24 +#define B43_MMIO_DMA1_REASON 0x28 +#define B43_MMIO_DMA1_IRQ_MASK 0x2C +#define B43_MMIO_DMA2_REASON 0x30 +#define B43_MMIO_DMA2_IRQ_MASK 0x34 +#define B43_MMIO_DMA3_REASON 0x38 +#define B43_MMIO_DMA3_IRQ_MASK 0x3C +#define B43_MMIO_DMA4_REASON 0x40 +#define B43_MMIO_DMA4_IRQ_MASK 0x44 +#define B43_MMIO_DMA5_REASON 0x48 +#define B43_MMIO_DMA5_IRQ_MASK 0x4C +#define B43_MMIO_MACCTL 0x120 +#define B43_MMIO_STATUS2_BITFIELD 0x124 +#define B43_MMIO_GEN_IRQ_REASON 0x128 +#define B43_MMIO_GEN_IRQ_MASK 0x12C +#define B43_MMIO_RAM_CONTROL 0x130 +#define B43_MMIO_RAM_DATA 0x134 +#define B43_MMIO_PS_STATUS 0x140 +#define B43_MMIO_RADIO_HWENABLED_HI 0x158 +#define B43_MMIO_SHM_CONTROL 0x160 +#define B43_MMIO_SHM_DATA 0x164 +#define B43_MMIO_SHM_DATA_UNALIGNED 0x166 +#define B43_MMIO_XMITSTAT_0 0x170 +#define B43_MMIO_XMITSTAT_1 0x174 +#define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ +#define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ + +/* 32-bit DMA */ +#define B43_MMIO_DMA32_BASE0 0x200 +#define B43_MMIO_DMA32_BASE1 0x220 +#define B43_MMIO_DMA32_BASE2 0x240 +#define B43_MMIO_DMA32_BASE3 0x260 +#define B43_MMIO_DMA32_BASE4 0x280 +#define B43_MMIO_DMA32_BASE5 0x2A0 +/* 64-bit DMA */ +#define B43_MMIO_DMA64_BASE0 0x200 +#define B43_MMIO_DMA64_BASE1 0x240 +#define B43_MMIO_DMA64_BASE2 0x280 +#define B43_MMIO_DMA64_BASE3 0x2C0 +#define B43_MMIO_DMA64_BASE4 0x300 +#define B43_MMIO_DMA64_BASE5 0x340 +/* PIO */ +#define B43_MMIO_PIO1_BASE 0x300 +#define B43_MMIO_PIO2_BASE 0x310 +#define B43_MMIO_PIO3_BASE 0x320 +#define B43_MMIO_PIO4_BASE 0x330 + +#define B43_MMIO_PHY_VER 0x3E0 +#define B43_MMIO_PHY_RADIO 0x3E2 +#define B43_MMIO_PHY0 0x3E6 +#define B43_MMIO_ANTENNA 0x3E8 +#define B43_MMIO_CHANNEL 0x3F0 +#define B43_MMIO_CHANNEL_EXT 0x3F4 +#define B43_MMIO_RADIO_CONTROL 0x3F6 +#define B43_MMIO_RADIO_DATA_HIGH 0x3F8 +#define B43_MMIO_RADIO_DATA_LOW 0x3FA +#define B43_MMIO_PHY_CONTROL 0x3FC +#define B43_MMIO_PHY_DATA 0x3FE +#define B43_MMIO_MACFILTER_CONTROL 0x420 +#define B43_MMIO_MACFILTER_DATA 0x422 +#define B43_MMIO_RCMTA_COUNT 0x43C +#define B43_MMIO_RADIO_HWENABLED_LO 0x49A +#define B43_MMIO_GPIO_CONTROL 0x49C +#define B43_MMIO_GPIO_MASK 0x49E +#define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */ +#define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */ +#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ +#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ +#define B43_MMIO_RNG 0x65A +#define B43_MMIO_POWERUP_DELAY 0x6A8 + +/* SPROM boardflags_lo values */ +#define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ +#define B43_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ +#define B43_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */ +#define B43_BFL_RSSI 0x0008 /* software calculates nrssi slope. */ +#define B43_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */ +#define B43_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */ +#define B43_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */ +#define B43_BFL_ENETADM 0x0080 /* has ADMtek switch */ +#define B43_BFL_ENETVLAN 0x0100 /* can do vlan */ +#define B43_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ +#define B43_BFL_NOPCI 0x0400 /* leaves PCI floating */ +#define B43_BFL_FEM 0x0800 /* supports the Front End Module */ +#define B43_BFL_EXTLNA 0x1000 /* has an external LNA */ +#define B43_BFL_HGPA 0x2000 /* had high gain PA */ +#define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ +#define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ + +/* GPIO register offset, in both ChipCommon and PCI core. */ +#define B43_GPIO_CONTROL 0x6c + +/* SHM Routing */ +enum { + B43_SHM_UCODE, /* Microcode memory */ + B43_SHM_SHARED, /* Shared memory */ + B43_SHM_SCRATCH, /* Scratch memory */ + B43_SHM_HW, /* Internal hardware register */ + B43_SHM_RCMTA, /* Receive match transmitter address (rev >= 5 only) */ +}; +/* SHM Routing modifiers */ +#define B43_SHM_AUTOINC_R 0x0200 /* Auto-increment address on read */ +#define B43_SHM_AUTOINC_W 0x0100 /* Auto-increment address on write */ +#define B43_SHM_AUTOINC_RW (B43_SHM_AUTOINC_R | \ + B43_SHM_AUTOINC_W) + +/* Misc SHM_SHARED offsets */ +#define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */ +#define B43_SHM_SH_PCTLWDPOS 0x0008 +#define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */ +#define B43_SHM_SH_PHYVER 0x0050 /* PHY version */ +#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */ +#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ +#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */ +#define B43_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */ +#define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */ +#define B43_SHM_SH_RADAR 0x0066 /* Radar register */ +#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */ +#define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */ +#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ +#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */ +#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ +/* SHM_SHARED TX FIFO variables */ +#define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */ +#define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */ +#define B43_SHM_SH_SIZE45 0x009C /* TX FIFO size for FIFO 4 and 5 */ +#define B43_SHM_SH_SIZE67 0x009E /* TX FIFO size for FIFO 6 and 7 */ +/* SHM_SHARED background noise */ +#define B43_SHM_SH_JSSI0 0x0088 /* Measure JSSI 0 */ +#define B43_SHM_SH_JSSI1 0x008A /* Measure JSSI 1 */ +#define B43_SHM_SH_JSSIAUX 0x008C /* Measure JSSI AUX */ +/* SHM_SHARED crypto engine */ +#define B43_SHM_SH_DEFAULTIV 0x003C /* Default IV location */ +#define B43_SHM_SH_NRRXTRANS 0x003E /* # of soft RX transmitter addresses (max 8) */ +#define B43_SHM_SH_KTP 0x0056 /* Key table pointer */ +#define B43_SHM_SH_TKIPTSCTTAK 0x0318 +#define B43_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block (v4 firmware) */ +#define B43_SHM_SH_PSM 0x05F4 /* PSM transmitter address match block (rev < 5) */ +/* SHM_SHARED WME variables */ +#define B43_SHM_SH_EDCFSTAT 0x000E /* EDCF status */ +#define B43_SHM_SH_TXFCUR 0x0030 /* TXF current index */ +#define B43_SHM_SH_EDCFQ 0x0240 /* EDCF Q info */ +/* SHM_SHARED powersave mode related */ +#define B43_SHM_SH_SLOTT 0x0010 /* Slot time */ +#define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */ +#define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */ +/* SHM_SHARED beacon variables */ +#define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */ +#define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */ +#define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */ +#define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */ +#define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */ +#define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */ +#define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */ +/* SHM_SHARED ACK/CTS control */ +#define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */ +/* SHM_SHARED probe response variables */ +#define B43_SHM_SH_PRSSID 0x0160 /* Probe Response SSID */ +#define B43_SHM_SH_PRSSIDLEN 0x0048 /* Probe Response SSID length */ +#define B43_SHM_SH_PRTLEN 0x004A /* Probe Response template length */ +#define B43_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */ +#define B43_SHM_SH_PRPHYCTL 0x0188 /* Probe Response PHY TX control word */ +/* SHM_SHARED rate tables */ +#define B43_SHM_SH_OFDMDIRECT 0x01C0 /* Pointer to OFDM direct map */ +#define B43_SHM_SH_OFDMBASIC 0x01E0 /* Pointer to OFDM basic rate map */ +#define B43_SHM_SH_CCKDIRECT 0x0200 /* Pointer to CCK direct map */ +#define B43_SHM_SH_CCKBASIC 0x0220 /* Pointer to CCK basic rate map */ +/* SHM_SHARED microcode soft registers */ +#define B43_SHM_SH_UCODEREV 0x0000 /* Microcode revision */ +#define B43_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */ +#define B43_SHM_SH_UCODEDATE 0x0004 /* Microcode date */ +#define B43_SHM_SH_UCODETIME 0x0006 /* Microcode time */ +#define B43_SHM_SH_UCODESTAT 0x0040 /* Microcode debug status code */ +#define B43_SHM_SH_UCODESTAT_INVALID 0 +#define B43_SHM_SH_UCODESTAT_INIT 1 +#define B43_SHM_SH_UCODESTAT_ACTIVE 2 +#define B43_SHM_SH_UCODESTAT_SUSP 3 /* suspended */ +#define B43_SHM_SH_UCODESTAT_SLEEP 4 /* asleep (PS) */ +#define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */ +#define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */ +#define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */ + +/* SHM_SCRATCH offsets */ +#define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */ +#define B43_SHM_SC_MAXCONT 0x0004 /* Maximum contention window */ +#define B43_SHM_SC_CURCONT 0x0005 /* Current contention window */ +#define B43_SHM_SC_SRLIMIT 0x0006 /* Short retry count limit */ +#define B43_SHM_SC_LRLIMIT 0x0007 /* Long retry count limit */ +#define B43_SHM_SC_DTIMC 0x0008 /* Current DTIM count */ +#define B43_SHM_SC_BTL0LEN 0x0015 /* Beacon 0 template length */ +#define B43_SHM_SC_BTL1LEN 0x0016 /* Beacon 1 template length */ +#define B43_SHM_SC_SCFB 0x0017 /* Short frame transmit count threshold for rate fallback */ +#define B43_SHM_SC_LCFB 0x0018 /* Long frame transmit count threshold for rate fallback */ + +/* Hardware Radio Enable masks */ +#define B43_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16) +#define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4) + +/* HostFlags. See b43_hf_read/write() */ +#define B43_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */ +#define B43_HF_SYMW 0x00000002 /* G-PHY SYM workaround */ +#define B43_HF_RXPULLW 0x00000004 /* RX pullup workaround */ +#define B43_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */ +#define B43_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */ +#define B43_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */ +#define B43_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */ +#define B43_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */ +#define B43_HF_EDCF 0x00000100 /* on if WME and MAC suspended */ +#define B43_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */ +#define B43_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */ +#define B43_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */ +#define B43_HF_2060W 0x00001000 /* 2060 radio workaround */ +#define B43_HF_RADARW 0x00002000 /* Radar workaround */ +#define B43_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */ +#define B43_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */ +#define B43_HF_FWKUP 0x00020000 /* Fast wake-up ucode */ +#define B43_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */ +#define B43_HF_PCISCW 0x00080000 /* PCI slow clock workaround */ +#define B43_HF_4318TSSI 0x00200000 /* 4318 TSSI */ +#define B43_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */ +#define B43_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */ +#define B43_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */ +#define B43_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */ +#define B43_HF_SKCFPUP 0x04000000 /* Skip CFP update */ + +/* MacFilter offsets. */ +#define B43_MACFILTER_SELF 0x0000 +#define B43_MACFILTER_BSSID 0x0003 + +/* PowerControl */ +#define B43_PCTL_IN 0xB0 +#define B43_PCTL_OUT 0xB4 +#define B43_PCTL_OUTENABLE 0xB8 +#define B43_PCTL_XTAL_POWERUP 0x40 +#define B43_PCTL_PLL_POWERDOWN 0x80 + +/* PowerControl Clock Modes */ +#define B43_PCTL_CLK_FAST 0x00 +#define B43_PCTL_CLK_SLOW 0x01 +#define B43_PCTL_CLK_DYNAMIC 0x02 + +#define B43_PCTL_FORCE_SLOW 0x0800 +#define B43_PCTL_FORCE_PLL 0x1000 +#define B43_PCTL_DYN_XTAL 0x2000 + +/* PHYVersioning */ +#define B43_PHYTYPE_A 0x00 +#define B43_PHYTYPE_B 0x01 +#define B43_PHYTYPE_G 0x02 + +/* PHYRegisters */ +#define B43_PHY_ILT_A_CTRL 0x0072 +#define B43_PHY_ILT_A_DATA1 0x0073 +#define B43_PHY_ILT_A_DATA2 0x0074 +#define B43_PHY_G_LO_CONTROL 0x0810 +#define B43_PHY_ILT_G_CTRL 0x0472 +#define B43_PHY_ILT_G_DATA1 0x0473 +#define B43_PHY_ILT_G_DATA2 0x0474 +#define B43_PHY_A_PCTL 0x007B +#define B43_PHY_G_PCTL 0x0029 +#define B43_PHY_A_CRS 0x0029 +#define B43_PHY_RADIO_BITFIELD 0x0401 +#define B43_PHY_G_CRS 0x0429 +#define B43_PHY_NRSSILT_CTRL 0x0803 +#define B43_PHY_NRSSILT_DATA 0x0804 + +/* RadioRegisters */ +#define B43_RADIOCTL_ID 0x01 + +/* MAC Control bitfield */ +#define B43_MACCTL_ENABLED 0x00000001 /* MAC Enabled */ +#define B43_MACCTL_PSM_RUN 0x00000002 /* Run Microcode */ +#define B43_MACCTL_PSM_JMP0 0x00000004 /* Microcode jump to 0 */ +#define B43_MACCTL_SHM_ENABLED 0x00000100 /* SHM Enabled */ +#define B43_MACCTL_SHM_UPPER 0x00000200 /* SHM Upper */ +#define B43_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */ +#define B43_MACCTL_PSM_DBG 0x00002000 /* Microcode debugging enabled */ +#define B43_MACCTL_GPOUTSMSK 0x0000C000 /* GPOUT Select Mask */ +#define B43_MACCTL_BE 0x00010000 /* Big Endian mode */ +#define B43_MACCTL_INFRA 0x00020000 /* Infrastructure mode */ +#define B43_MACCTL_AP 0x00040000 /* AccessPoint mode */ +#define B43_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */ +#define B43_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */ +#define B43_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */ +#define B43_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */ +#define B43_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */ +#define B43_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */ +#define B43_MACCTL_HWPS 0x02000000 /* Hardware Power Saving */ +#define B43_MACCTL_AWAKE 0x04000000 /* Device is awake */ +#define B43_MACCTL_CLOSEDNET 0x08000000 /* Closed net (no SSID bcast) */ +#define B43_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */ +#define B43_MACCTL_DISCTXSTAT 0x20000000 /* Discard TX status */ +#define B43_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */ +#define B43_MACCTL_GMODE 0x80000000 /* G Mode */ + +/* 802.11 core specific TM State Low flags */ +#define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */ +#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */ +#define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */ +#define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */ +#define B43_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */ + +/* 802.11 core specific TM State High flags */ +#define B43_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5) */ +#define B43_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */ +#define B43_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */ + +/* Generic-Interrupt reasons. */ +#define B43_IRQ_MAC_SUSPENDED 0x00000001 +#define B43_IRQ_BEACON 0x00000002 +#define B43_IRQ_TBTT_INDI 0x00000004 +#define B43_IRQ_BEACON_TX_OK 0x00000008 +#define B43_IRQ_BEACON_CANCEL 0x00000010 +#define B43_IRQ_ATIM_END 0x00000020 +#define B43_IRQ_PMQ 0x00000040 +#define B43_IRQ_PIO_WORKAROUND 0x00000100 +#define B43_IRQ_MAC_TXERR 0x00000200 +#define B43_IRQ_PHY_TXERR 0x00000800 +#define B43_IRQ_PMEVENT 0x00001000 +#define B43_IRQ_TIMER0 0x00002000 +#define B43_IRQ_TIMER1 0x00004000 +#define B43_IRQ_DMA 0x00008000 +#define B43_IRQ_TXFIFO_FLUSH_OK 0x00010000 +#define B43_IRQ_CCA_MEASURE_OK 0x00020000 +#define B43_IRQ_NOISESAMPLE_OK 0x00040000 +#define B43_IRQ_UCODE_DEBUG 0x08000000 +#define B43_IRQ_RFKILL 0x10000000 +#define B43_IRQ_TX_OK 0x20000000 +#define B43_IRQ_PHY_G_CHANGED 0x40000000 +#define B43_IRQ_TIMEOUT 0x80000000 + +#define B43_IRQ_ALL 0xFFFFFFFF +#define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \ + B43_IRQ_BEACON | \ + B43_IRQ_TBTT_INDI | \ + B43_IRQ_ATIM_END | \ + B43_IRQ_PMQ | \ + B43_IRQ_MAC_TXERR | \ + B43_IRQ_PHY_TXERR | \ + B43_IRQ_DMA | \ + B43_IRQ_TXFIFO_FLUSH_OK | \ + B43_IRQ_NOISESAMPLE_OK | \ + B43_IRQ_UCODE_DEBUG | \ + B43_IRQ_RFKILL | \ + B43_IRQ_TX_OK) + +/* Device specific rate values. + * The actual values defined here are (rate_in_mbps * 2). + * Some code depends on this. Don't change it. */ +#define B43_CCK_RATE_1MB 0x02 +#define B43_CCK_RATE_2MB 0x04 +#define B43_CCK_RATE_5MB 0x0B +#define B43_CCK_RATE_11MB 0x16 +#define B43_OFDM_RATE_6MB 0x0C +#define B43_OFDM_RATE_9MB 0x12 +#define B43_OFDM_RATE_12MB 0x18 +#define B43_OFDM_RATE_18MB 0x24 +#define B43_OFDM_RATE_24MB 0x30 +#define B43_OFDM_RATE_36MB 0x48 +#define B43_OFDM_RATE_48MB 0x60 +#define B43_OFDM_RATE_54MB 0x6C +/* Convert a b43 rate value to a rate in 100kbps */ +#define B43_RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) + +#define B43_DEFAULT_SHORT_RETRY_LIMIT 7 +#define B43_DEFAULT_LONG_RETRY_LIMIT 4 + +/* Max size of a security key */ +#define B43_SEC_KEYSIZE 16 +/* Security algorithms. */ +enum { + B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ + B43_SEC_ALGO_WEP40, + B43_SEC_ALGO_TKIP, + B43_SEC_ALGO_AES, + B43_SEC_ALGO_WEP104, + B43_SEC_ALGO_AES_LEGACY, +}; + +struct b43_dmaring; +struct b43_pioqueue; + +/* The firmware file header */ +#define B43_FW_TYPE_UCODE 'u' +#define B43_FW_TYPE_PCM 'p' +#define B43_FW_TYPE_IV 'i' +struct b43_fw_header { + /* File type */ + u8 type; + /* File format version */ + u8 ver; + u8 __padding[2]; + /* Size of the data. For ucode and PCM this is in bytes. + * For IV this is number-of-ivs. */ + __be32 size; +} __attribute__((__packed__)); + +/* Initial Value file format */ +#define B43_IV_OFFSET_MASK 0x7FFF +#define B43_IV_32BIT 0x8000 +struct b43_iv { + __be16 offset_size; + union { + __be16 d16; + __be32 d32; + } data __attribute__((__packed__)); +} __attribute__((__packed__)); + + +#define B43_PHYMODE(phytype) (1 << (phytype)) +#define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A) +#define B43_PHYMODE_B B43_PHYMODE(B43_PHYTYPE_B) +#define B43_PHYMODE_G B43_PHYMODE(B43_PHYTYPE_G) + +struct b43_phy { + /* Possible PHYMODEs on this PHY */ + u8 possible_phymodes; + /* GMODE bit enabled? */ + bool gmode; + /* Possible ieee80211 subsystem hwmodes for this PHY. + * Which mode is selected, depends on thr GMODE enabled bit */ +#define B43_MAX_PHYHWMODES 2 + struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES]; + + /* Analog Type */ + u8 analog; + /* B43_PHYTYPE_ */ + u8 type; + /* PHY revision number. */ + u8 rev; + + /* Radio versioning */ + u16 radio_manuf; /* Radio manufacturer */ + u16 radio_ver; /* Radio version */ + u8 radio_rev; /* Radio revision */ + + bool radio_on; /* Radio switched on/off */ + bool locked; /* Only used in b43_phy_{un}lock() */ + bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ + + /* ACI (adjacent channel interference) flags. */ + bool aci_enable; + bool aci_wlan_automatic; + bool aci_hw_rssi; + + u16 minlowsig[2]; + u16 minlowsigpos[2]; + + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi; + + /* LocalOscillator control values. */ + struct b43_txpower_lo_control *lo_control; + /* Values from b43_calc_loopback_gain() */ + s16 max_lb_gain; /* Maximum Loopback gain in hdB */ + s16 trsw_rx_gain; /* TRSW RX gain in hdB */ + s16 lna_lod_gain; /* LNA lod */ + s16 lna_gain; /* LNA */ + s16 pga_gain; /* PGA */ + + /* PHY lock for core.rev < 3 + * This lock is only used by b43_phy_{un}lock() + */ + spinlock_t lock; + + /* Desired TX power level (in dBm). + * This is set by the user and adjusted in b43_phy_xmitpower(). */ + u8 power_level; + /* A-PHY TX Power control value. */ + u16 txpwr_offset; + + /* Current TX power level attenuation control values */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + u8 tx_control; /* B43_TXCTL_XXX */ +#ifdef CONFIG_B43_DEBUG + bool manual_txpower_control; /* Manual TX-power control enabled? */ +#endif + /* Hardware Power Control enabled? */ + bool hardware_power_control; + + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define B43_INTERFSTACK_SIZE 26 + u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure + + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + /* current channel */ + u8 channel; + + u16 lofcal; + + u16 initval; //FIXME rename? +}; + +/* Data structures for DMA transmission, per 80211 core. */ +struct b43_dma { + struct b43_dmaring *tx_ring0; + struct b43_dmaring *tx_ring1; + struct b43_dmaring *tx_ring2; + struct b43_dmaring *tx_ring3; + struct b43_dmaring *tx_ring4; + struct b43_dmaring *tx_ring5; + + struct b43_dmaring *rx_ring0; + struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */ +}; + +/* Data structures for PIO transmission, per 80211 core. */ +struct b43_pio { + struct b43_pioqueue *queue0; + struct b43_pioqueue *queue1; + struct b43_pioqueue *queue2; + struct b43_pioqueue *queue3; +}; + +/* Context information for a noise calculation (Link Quality). */ +struct b43_noise_calculation { + u8 channel_at_start; + bool calculation_running; + u8 nr_samples; + s8 samples[8][4]; +}; + +struct b43_stats { + u8 link_noise; + /* Store the last TX/RX times here for updating the leds. */ + unsigned long last_tx; + unsigned long last_rx; +}; + +struct b43_key { + /* If keyconf is NULL, this key is disabled. + * keyconf is a cookie. Don't derefenrence it outside of the set_key + * path, because b43 doesn't own it. */ + struct ieee80211_key_conf *keyconf; + u8 algorithm; +}; + +struct b43_wldev; + +/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ +struct b43_wl { + /* Pointer to the active wireless device on this chip */ + struct b43_wldev *current_dev; + /* Pointer to the ieee80211 hardware data structure */ + struct ieee80211_hw *hw; + + spinlock_t irq_lock; + struct mutex mutex; + spinlock_t leds_lock; + + /* We can only have one operating interface (802.11 core) + * at a time. General information about this interface follows. + */ + + /* Opaque ID of the operating interface (!= monitor + * interface) from the ieee80211 subsystem. + * Do not modify. + */ + int if_id; + /* The MAC address of the operating interface. */ + u8 mac_addr[ETH_ALEN]; + /* Current BSSID */ + u8 bssid[ETH_ALEN]; + /* Interface type. (IEEE80211_IF_TYPE_XXX) */ + int if_type; + /* Counter of active monitor interfaces. */ + int monitor; + /* Is the card operating in AP, STA or IBSS mode? */ + bool operating; + /* Promisc mode active? + * Note that (monitor != 0) implies promisc. + */ + bool promisc; + /* Stats about the wireless interface */ + struct ieee80211_low_level_stats ieee_stats; + + struct hwrng rng; + u8 rng_initialized; + char rng_name[30 + 1]; + + /* List of all wireless devices on this chip */ + struct list_head devlist; + u8 nr_devs; +}; + +/* Pointers to the firmware data and meta information about it. */ +struct b43_firmware { + /* Microcode */ + const struct firmware *ucode; + /* PCM code */ + const struct firmware *pcm; + /* Initial MMIO values for the firmware */ + const struct firmware *initvals; + /* Initial MMIO values for the firmware, band-specific */ + const struct firmware *initvals_band; + /* Firmware revision */ + u16 rev; + /* Firmware patchlevel */ + u16 patch; +}; + +/* Device (802.11 core) initialization status. */ +enum { + B43_STAT_UNINIT = 0, /* Uninitialized. */ + B43_STAT_INITIALIZED = 1, /* Initialized, but not started, yet. */ + B43_STAT_STARTED = 2, /* Up and running. */ +}; +#define b43_status(wldev) atomic_read(&(wldev)->__init_status) +#define b43_set_status(wldev, stat) do { \ + atomic_set(&(wldev)->__init_status, (stat)); \ + 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; + struct b43_wl *wl; + + /* The device initialization status. + * Use b43_status() to query. */ + atomic_t __init_status; + /* Saved init status for handling suspend. */ + int suspend_init_status; + + bool __using_pio; /* Internal, use b43_using_pio(). */ + bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ + bool reg124_set_0x4; /* Some variable to keep track of IRQ stuff. */ + bool short_preamble; /* TRUE, if short preamble is enabled. */ + bool short_slot; /* TRUE, if short slot timing is enabled. */ + bool radio_hw_enable; /* saved state of radio hardware enabled state */ + + /* PHY/Radio device. */ + struct b43_phy phy; + union { + /* DMA engines. */ + struct b43_dma dma; + /* PIO engines. */ + struct b43_pio pio; + }; + + /* Various statistics about the physical device. */ + struct b43_stats stats; + +#define B43_NR_LEDS 4 + struct b43_led leds[B43_NR_LEDS]; + + /* Reason code of the last interrupt. */ + u32 irq_reason; + u32 dma_reason[6]; + /* saved irq enable/disable state bitfield. */ + u32 irq_savedstate; + /* 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; + + struct work_struct restart_work; + + /* encryption/decryption */ + u16 ktp; /* Key table pointer */ + u8 max_nr_keys; + struct b43_key key[58]; + + /* Cached beacon template while uploading the template. */ + struct sk_buff *cached_beacon; + + /* Firmware data */ + struct b43_firmware fw; + + /* Devicelist in struct b43_wl (all 802.11 cores) */ + struct list_head list; + + /* Debugging stuff follows. */ +#ifdef CONFIG_B43_DEBUG + struct b43_dfsentry *dfsentry; +#endif +}; + +static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) +{ + return hw->priv; +} + +/* Helper function, which returns a boolean. + * TRUE, if PIO is used; FALSE, if DMA is used. + */ +#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO) +static inline int b43_using_pio(struct b43_wldev *dev) +{ + return dev->__using_pio; +} +#elif defined(CONFIG_B43_DMA) +static inline int b43_using_pio(struct b43_wldev *dev) +{ + return 0; +} +#elif defined(CONFIG_B43_PIO) +static inline int b43_using_pio(struct b43_wldev *dev) +{ + return 1; +} +#else +# error "Using neither DMA nor PIO? Confused..." +#endif + +static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + return ssb_get_drvdata(ssb_dev); +} + +/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ +static inline int b43_is_mode(struct b43_wl *wl, int type) +{ + if (type == IEEE80211_IF_TYPE_MNTR) + return !!(wl->monitor); + return (wl->operating && wl->if_type == type); +} + +static inline u16 b43_read16(struct b43_wldev *dev, u16 offset) +{ + return ssb_read16(dev->dev, offset); +} + +static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value) +{ + ssb_write16(dev->dev, offset, value); +} + +static inline u32 b43_read32(struct b43_wldev *dev, u16 offset) +{ + return ssb_read32(dev->dev, offset); +} + +static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value) +{ + ssb_write32(dev->dev, offset, value); +} + +/* Message printing */ +void b43info(struct b43_wl *wl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); +void b43err(struct b43_wl *wl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); +void b43warn(struct b43_wl *wl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); +#if B43_DEBUG +void b43dbg(struct b43_wl *wl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); +#else /* DEBUG */ +# define b43dbg(wl, fmt...) do { /* nothing */ } while (0) +#endif /* DEBUG */ + +/* A WARN_ON variant that vanishes when b43 debugging is disabled. + * This _also_ evaluates the arg with debugging disabled. */ +#if B43_DEBUG +# define B43_WARN_ON(x) WARN_ON(x) +#else +static inline bool __b43_warn_on_dummy(bool x) { return x; } +# define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x))) +#endif + +/** Limit a value between two limits */ +#ifdef limit_value +# undef limit_value +#endif +#define limit_value(value, min, max) \ + ({ \ + typeof(value) __value = (value); \ + typeof(value) __min = (min); \ + typeof(value) __max = (max); \ + if (__value < __min) \ + __value = __min; \ + else if (__value > __max) \ + __value = __max; \ + __value; \ + }) + +/* Convert an integer to a Q5.2 value */ +#define INT_TO_Q52(i) ((i) << 2) +/* Convert a Q5.2 value to an integer (precision loss!) */ +#define Q52_TO_INT(q52) ((q52) >> 2) +/* Macros for printing a value in Q5.2 format */ +#define Q52_FMT "%u.%u" +#define Q52_ARG(q52) Q52_TO_INT(q52), ((((q52) & 0x3) * 100) / 4) + +#endif /* B43_H_ */ diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c new file mode 100644 index 000000000000..f82e3ef9bd73 --- /dev/null +++ b/drivers/net/wireless/b43/debugfs.c @@ -0,0 +1,654 @@ +/* + + Broadcom B43 wireless driver + + debugfs driver debugging code + + Copyright (c) 2005-2007 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "b43.h" +#include "main.h" +#include "debugfs.h" +#include "dma.h" +#include "pio.h" +#include "xmit.h" + + +/* The root directory. */ +struct dentry *rootdir; + +struct b43_debugfs_fops { + ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize); + int (*write)(struct b43_wldev *dev, const char *buf, size_t count); + 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 +struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev, + const struct b43_debugfs_fops *dfops) +{ + void *p; + + p = dev->dfsentry; + p += dfops->file_struct_offset; + + return p; +} + + +#define fappend(fmt, x...) \ + do { \ + if (bufsize - count) \ + count += snprintf(buf + count, \ + bufsize - count, \ + fmt , ##x); \ + else \ + printk(KERN_ERR "b43: fappend overflow\n"); \ + } while (0) + + +/* wl->irq_lock is locked */ +ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + u64 tsf; + + b43_tsf_read(dev, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); + + return count; +} + +/* wl->irq_lock is locked */ +int tsf_write_file(struct b43_wldev *dev, const char *buf, size_t count) +{ + u64 tsf; + + if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) + return -EINVAL; + b43_tsf_write(dev, tsf); + + return 0; +} + +/* wl->irq_lock is locked */ +ssize_t ucode_regs_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + int i; + + for (i = 0; i < 64; i++) { + fappend("r%d = 0x%04x\n", i, + b43_shm_read16(dev, B43_SHM_SCRATCH, i)); + } + + return count; +} + +/* wl->irq_lock is locked */ +ssize_t shm_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + int i; + u16 tmp; + __le16 *le16buf = (__le16 *)buf; + + for (i = 0; i < 0x1000; i++) { + if (bufsize <= 0) + break; + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i); + le16buf[i] = cpu_to_le16(tmp); + count += sizeof(tmp); + bufsize -= sizeof(tmp); + } + + return count; +} + +ssize_t txstat_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + 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; + } + fappend("b43 TX status reports:\n\n" + "index | cookie | seq | phy_stat | frame_count | " + "rts_count | supp_reason | pm_indicated | " + "intermediate | for_ampdu | acked\n" "---\n"); + i = log->end + 1; + idx = 0; + while (1) { + if (i == B43_NR_LOGGED_TXSTATUS) + i = 0; + stat = &(log->log[i]); + if (stat->cookie) { + fappend("%03d | " + "0x%04X | 0x%04X | 0x%02X | " + "0x%X | 0x%X | " + "%u | %u | " + "%u | %u | %u\n", + idx, + stat->cookie, stat->seq, stat->phy_stat, + stat->frame_count, stat->rts_count, + stat->supp_reason, stat->pm_indicated, + stat->intermediate, stat->for_ampdu, + stat->acked); + idx++; + } + if (i == log->end) + break; + i++; + } +out_unlock: + spin_unlock_irqrestore(&log->lock, flags); + + return count; +} + +ssize_t txpower_g_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + + if (dev->phy.type != B43_PHYTYPE_G) { + fappend("Device is not a G-PHY\n"); + goto out; + } + fappend("Control: %s\n", dev->phy.manual_txpower_control ? + "MANUAL" : "AUTOMATIC"); + fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att); + fappend("Radio attenuation: %u\n", dev->phy.rfatt.att); + fappend("TX Mixer Gain: %s\n", + (dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF"); + fappend("PA Gain 2dB: %s\n", + (dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF"); + fappend("PA Gain 3dB: %s\n", + (dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF"); + fappend("\n\n"); + fappend("You can write to this file:\n"); + fappend("Writing \"auto\" enables automatic txpower control.\n"); + fappend + ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" " + "enables manual txpower control.\n"); + fappend("Example: 5 4 0 0 1\n"); + fappend("Enables manual control with Baseband attenuation 5, " + "Radio attenuation 4, No TX Mixer Gain, " + "No PA Gain 2dB, With PA Gain 3dB.\n"); +out: + return count; +} + +int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long phy_flags; + int err = 0; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if (dev->phy.type != B43_PHYTYPE_G) { + err = -ENODEV; + goto out_unlock; + } + if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { + /* Automatic control */ + dev->phy.manual_txpower_control = 0; + b43_phy_xmitpower(dev); + } else { + int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; + /* Manual control */ + if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, + &txmix, &pa2db, &pa3db) != 5) { + err = -EINVAL; + goto out_unlock; + } + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + dev->phy.manual_txpower_control = 1; + dev->phy.bbatt.att = bbatt; + dev->phy.rfatt.att = rfatt; + dev->phy.tx_control = 0; + if (txmix) + dev->phy.tx_control |= B43_TXCTL_TXMIX; + if (pa2db) + dev->phy.tx_control |= B43_TXCTL_PA2DB; + if (pa3db) + dev->phy.tx_control |= B43_TXCTL_PA3DB; + b43_phy_lock(dev, phy_flags); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &dev->phy.bbatt, + &dev->phy.rfatt, dev->phy.tx_control); + b43_radio_unlock(dev); + b43_phy_unlock(dev, phy_flags); + } +out_unlock: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + + return err; +} + +/* wl->irq_lock is locked */ +int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) +{ + int err = 0; + + if (count > 0 && buf[0] == '1') { + b43_controller_restart(dev, "manually restarted"); + } else + err = -EINVAL; + + return err; +} + +static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, + struct b43_loctl table[B43_NR_BB][B43_NR_RF]) +{ + unsigned int i, j; + struct b43_loctl *ctl; + + for (i = 0; i < B43_NR_BB; i++) { + for (j = 0; j < B43_NR_RF; j++) { + ctl = &(table[i][j]); + fappend("(bbatt %2u, rfatt %2u) -> " + "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n", + i, j, ctl->i, ctl->q, + ctl->used, + b43_loctl_is_calibrated(ctl)); + } + } + + return count; +} + +ssize_t loctls_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + struct b43_txpower_lo_control *lo; + int i, err = 0; + + if (dev->phy.type != B43_PHYTYPE_G) { + fappend("Device is not a G-PHY\n"); + err = -ENODEV; + goto out; + } + lo = dev->phy.lo_control; + fappend("-- Local Oscillator calibration data --\n\n"); + fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n", + lo->lo_measured, + lo->rebuild, + dev->phy.hardware_power_control); + fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n", + lo->tx_bias, lo->tx_magn); + fappend("Power Vector: 0x%08X%08X\n", + (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL)); + fappend("\nControl table WITH PADMIX:\n"); + count = append_lo_table(count, buf, bufsize, lo->with_padmix); + fappend("\nControl table WITHOUT PADMIX:\n"); + count = append_lo_table(count, buf, bufsize, lo->no_padmix); + fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n"); + for (i = 0; i < lo->rfatt_list.len; i++) { + fappend("%u(%d), ", + lo->rfatt_list.list[i].att, + lo->rfatt_list.list[i].with_padmix); + } + fappend("\n"); + fappend("\nUsed Baseband attenuation values:\n"); + for (i = 0; i < lo->bbatt_list.len; i++) { + fappend("%u, ", + lo->bbatt_list.list[i].att); + } + fappend("\n"); + +out: + return err ? err : count; +} + +#undef fappend + +static int b43_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct b43_wldev *dev; + struct b43_debugfs_fops *dfops; + struct b43_dfs_file *dfile; + ssize_t ret; + char *buf; + const size_t bufsize = 1024 * 128; + const size_t buforder = get_order(bufsize); + int err = 0; + + if (!count) + return 0; + dev = file->private_data; + if (!dev) + return -ENODEV; + + mutex_lock(&dev->wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + dfops = container_of(file->f_op, struct b43_debugfs_fops, fops); + if (!dfops->read) { + err = -ENOSYS; + goto out_unlock; + } + dfile = fops_to_dfs_file(dev, dfops); + + if (!dfile->buffer) { + buf = (char *)__get_free_pages(GFP_KERNEL, buforder); + if (!buf) { + err = -ENOMEM; + 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); + if (ret <= 0) { + free_pages((unsigned long)buf, buforder); + err = ret; + goto out_unlock; + } + dfile->data_len = ret; + dfile->buffer = buf; + } + + ret = simple_read_from_buffer(userbuf, count, ppos, + dfile->buffer, + dfile->data_len); + if (*ppos >= dfile->data_len) { + free_pages((unsigned long)dfile->buffer, buforder); + dfile->buffer = NULL; + dfile->data_len = 0; + } +out_unlock: + mutex_unlock(&dev->wl->mutex); + + return err ? err : ret; +} + +static ssize_t b43_debugfs_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct b43_wldev *dev; + struct b43_debugfs_fops *dfops; + char *buf; + int err = 0; + + if (!count) + return 0; + if (count > PAGE_SIZE) + return -E2BIG; + dev = file->private_data; + if (!dev) + return -ENODEV; + + mutex_lock(&dev->wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + dfops = container_of(file->f_op, struct b43_debugfs_fops, fops); + if (!dfops->write) { + err = -ENOSYS; + goto out_unlock; + } + + buf = (char *)get_zeroed_page(GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out_unlock; + } + if (copy_from_user(buf, userbuf, count)) { + 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); + if (err) + goto out_freepage; + +out_freepage: + free_page((unsigned long)buf); +out_unlock: + mutex_unlock(&dev->wl->mutex); + + return err ? err : count; +} + + +#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ + static struct b43_debugfs_fops fops_##name = { \ + .read = _read, \ + .write = _write, \ + .fops = { \ + .open = b43_debugfs_open, \ + .read = b43_debugfs_read, \ + .write = b43_debugfs_write, \ + }, \ + .file_struct_offset = offsetof(struct b43_dfsentry, \ + file_##name), \ + .take_irqlock = _take_irqlock, \ + } + +B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); +B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1); +B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1); +B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); +B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0); +B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); +B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); + + +int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) +{ + return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]); +} + +static void b43_remove_dynamic_debug(struct b43_wldev *dev) +{ + struct b43_dfsentry *e = dev->dfsentry; + int i; + + for (i = 0; i < __B43_NR_DYNDBG; i++) + debugfs_remove(e->dyn_debug_dentries[i]); +} + +static void b43_add_dynamic_debug(struct b43_wldev *dev) +{ + struct b43_dfsentry *e = dev->dfsentry; + struct dentry *d; + +#define add_dyn_dbg(name, id, initstate) do { \ + e->dyn_debug[id] = (initstate); \ + d = debugfs_create_bool(name, 0600, e->subdir, \ + &(e->dyn_debug[id])); \ + if (!IS_ERR(d)) \ + e->dyn_debug_dentries[id] = d; \ + } while (0) + + add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0); + add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0); + add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0); + add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0); + add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); + +#undef add_dyn_dbg +} + +void b43_debugfs_add_device(struct b43_wldev *dev) +{ + struct b43_dfsentry *e; + struct b43_txstatus_log *log; + char devdir[16]; + + B43_WARN_ON(!dev); + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { + b43err(dev->wl, "debugfs: add device OOM\n"); + return; + } + e->dev = dev; + log = &e->txstatlog; + log->log = kcalloc(B43_NR_LOGGED_TXSTATUS, + sizeof(struct b43_txstatus), GFP_KERNEL); + if (!log->log) { + b43err(dev->wl, "debugfs: add device txstatus OOM\n"); + kfree(e); + return; + } + log->end = -1; + spin_lock_init(&log->lock); + + dev->dfsentry = e; + + snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy)); + e->subdir = debugfs_create_dir(devdir, rootdir); + if (!e->subdir || IS_ERR(e->subdir)) { + if (e->subdir == ERR_PTR(-ENODEV)) { + b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not " + "enabled in kernel config\n"); + } else { + b43err(dev->wl, "debugfs: cannot create %s directory\n", + devdir); + } + dev->dfsentry = NULL; + kfree(log->log); + kfree(e); + return; + } + +#define ADD_FILE(name, mode) \ + do { \ + struct dentry *d; \ + d = debugfs_create_file(__stringify(name), \ + mode, e->subdir, dev, \ + &fops_##name.fops); \ + e->file_##name.dentry = NULL; \ + if (!IS_ERR(d)) \ + e->file_##name.dentry = d; \ + } while (0) + + + ADD_FILE(tsf, 0600); + ADD_FILE(ucode_regs, 0400); + ADD_FILE(shm, 0400); + ADD_FILE(txstat, 0400); + ADD_FILE(txpower_g, 0600); + ADD_FILE(restart, 0200); + ADD_FILE(loctls, 0400); + +#undef ADD_FILE + + b43_add_dynamic_debug(dev); +} + +void b43_debugfs_remove_device(struct b43_wldev *dev) +{ + struct b43_dfsentry *e; + + if (!dev) + return; + e = dev->dfsentry; + if (!e) + return; + b43_remove_dynamic_debug(dev); + + debugfs_remove(e->file_tsf.dentry); + debugfs_remove(e->file_ucode_regs.dentry); + debugfs_remove(e->file_shm.dentry); + debugfs_remove(e->file_txstat.dentry); + debugfs_remove(e->file_txpower_g.dentry); + debugfs_remove(e->file_restart.dentry); + debugfs_remove(e->file_loctls.dentry); + + debugfs_remove(e->subdir); + kfree(e->txstatlog.log); + kfree(e); +} + +void b43_debugfs_log_txstat(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + struct b43_dfsentry *e = dev->dfsentry; + struct b43_txstatus_log *log; + struct b43_txstatus *cur; + int i; + + if (!e) + return; + log = &e->txstatlog; + B43_WARN_ON(!irqs_disabled()); + spin_lock(&log->lock); + 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) +{ + rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR(rootdir)) + rootdir = NULL; +} + +void b43_debugfs_exit(void) +{ + debugfs_remove(rootdir); +} diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h new file mode 100644 index 000000000000..6eebe858db5a --- /dev/null +++ b/drivers/net/wireless/b43/debugfs.h @@ -0,0 +1,89 @@ +#ifndef B43_DEBUGFS_H_ +#define B43_DEBUGFS_H_ + +struct b43_wldev; +struct b43_txstatus; + +enum b43_dyndbg { /* Dynamic debugging features */ + B43_DBG_XMITPOWER, + B43_DBG_DMAOVERFLOW, + B43_DBG_DMAVERBOSE, + B43_DBG_PWORK_FAST, + B43_DBG_PWORK_STOP, + __B43_NR_DYNDBG, +}; + +#ifdef CONFIG_B43_DEBUG + +struct dentry; + +#define B43_NR_LOGGED_TXSTATUS 100 + +struct b43_txstatus_log { + struct b43_txstatus *log; + int end; + spinlock_t lock; +}; + +struct b43_dfs_file { + struct dentry *dentry; + char *buffer; + size_t data_len; +}; + +struct b43_dfsentry { + struct b43_wldev *dev; + struct dentry *subdir; + + struct b43_dfs_file file_tsf; + struct b43_dfs_file file_ucode_regs; + struct b43_dfs_file file_shm; + struct b43_dfs_file file_txstat; + struct b43_dfs_file file_txpower_g; + struct b43_dfs_file file_restart; + struct b43_dfs_file file_loctls; + + struct b43_txstatus_log txstatlog; + + /* Enabled/Disabled list for the dynamic debugging features. */ + u32 dyn_debug[__B43_NR_DYNDBG]; + /* Dentries for the dynamic debugging entries. */ + struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG]; +}; + +int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature); + +void b43_debugfs_init(void); +void b43_debugfs_exit(void); +void b43_debugfs_add_device(struct b43_wldev *dev); +void b43_debugfs_remove_device(struct b43_wldev *dev); +void b43_debugfs_log_txstat(struct b43_wldev *dev, + const struct b43_txstatus *status); + +#else /* CONFIG_B43_DEBUG */ + +static inline int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) +{ + return 0; +} + +static inline void b43_debugfs_init(void) +{ +} +static inline void b43_debugfs_exit(void) +{ +} +static inline void b43_debugfs_add_device(struct b43_wldev *dev) +{ +} +static inline void b43_debugfs_remove_device(struct b43_wldev *dev) +{ +} +static inline void b43_debugfs_log_txstat(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ +} + +#endif /* CONFIG_B43_DEBUG */ + +#endif /* B43_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c new file mode 100644 index 000000000000..5e8f8ac0f1dd --- /dev/null +++ b/drivers/net/wireless/b43/dma.c @@ -0,0 +1,1494 @@ +/* + + Broadcom B43 wireless driver + + DMA ringbuffer and descriptor allocation/management + + Copyright (c) 2005, 2006 Michael Buesch + + Some code in this file is derived from the b44.c driver + Copyright (C) 2002 David S. Miller + Copyright (C) Pekka Pietikainen + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "dma.h" +#include "main.h" +#include "debugfs.h" +#include "xmit.h" + +#include +#include +#include +#include + +/* 32bit DMA ops. */ +static +struct b43_dmadesc_generic *op32_idx2desc(struct b43_dmaring *ring, + int slot, + struct b43_dmadesc_meta **meta) +{ + struct b43_dmadesc32 *desc; + + *meta = &(ring->meta[slot]); + desc = ring->descbase; + desc = &(desc[slot]); + + return (struct b43_dmadesc_generic *)desc; +} + +static void op32_fill_descriptor(struct b43_dmaring *ring, + struct b43_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq) +{ + struct b43_dmadesc32 *descbase = ring->descbase; + int slot; + u32 ctl; + u32 addr; + u32 addrext; + + slot = (int)(&(desc->dma32) - descbase); + B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + + addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK); + addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + addr |= ssb_dma_translation(ring->dev->dev); + ctl = (bufsize - ring->frameoffset) + & B43_DMA32_DCTL_BYTECNT; + if (slot == ring->nr_slots - 1) + ctl |= B43_DMA32_DCTL_DTABLEEND; + if (start) + ctl |= B43_DMA32_DCTL_FRAMESTART; + if (end) + ctl |= B43_DMA32_DCTL_FRAMEEND; + if (irq) + ctl |= B43_DMA32_DCTL_IRQ; + ctl |= (addrext << B43_DMA32_DCTL_ADDREXT_SHIFT) + & B43_DMA32_DCTL_ADDREXT_MASK; + + desc->dma32.control = cpu_to_le32(ctl); + desc->dma32.address = cpu_to_le32(addr); +} + +static void op32_poke_tx(struct b43_dmaring *ring, int slot) +{ + b43_dma_write(ring, B43_DMA32_TXINDEX, + (u32) (slot * sizeof(struct b43_dmadesc32))); +} + +static void op32_tx_suspend(struct b43_dmaring *ring) +{ + b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL) + | B43_DMA32_TXSUSPEND); +} + +static void op32_tx_resume(struct b43_dmaring *ring) +{ + b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL) + & ~B43_DMA32_TXSUSPEND); +} + +static int op32_get_current_rxslot(struct b43_dmaring *ring) +{ + u32 val; + + val = b43_dma_read(ring, B43_DMA32_RXSTATUS); + val &= B43_DMA32_RXDPTR; + + return (val / sizeof(struct b43_dmadesc32)); +} + +static void op32_set_current_rxslot(struct b43_dmaring *ring, int slot) +{ + b43_dma_write(ring, B43_DMA32_RXINDEX, + (u32) (slot * sizeof(struct b43_dmadesc32))); +} + +static const struct b43_dma_ops dma32_ops = { + .idx2desc = op32_idx2desc, + .fill_descriptor = op32_fill_descriptor, + .poke_tx = op32_poke_tx, + .tx_suspend = op32_tx_suspend, + .tx_resume = op32_tx_resume, + .get_current_rxslot = op32_get_current_rxslot, + .set_current_rxslot = op32_set_current_rxslot, +}; + +/* 64bit DMA ops. */ +static +struct b43_dmadesc_generic *op64_idx2desc(struct b43_dmaring *ring, + int slot, + struct b43_dmadesc_meta **meta) +{ + struct b43_dmadesc64 *desc; + + *meta = &(ring->meta[slot]); + desc = ring->descbase; + desc = &(desc[slot]); + + return (struct b43_dmadesc_generic *)desc; +} + +static void op64_fill_descriptor(struct b43_dmaring *ring, + struct b43_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq) +{ + struct b43_dmadesc64 *descbase = ring->descbase; + int slot; + u32 ctl0 = 0, ctl1 = 0; + u32 addrlo, addrhi; + u32 addrext; + + slot = (int)(&(desc->dma64) - descbase); + B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + + addrlo = (u32) (dmaaddr & 0xFFFFFFFF); + addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); + addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + addrhi |= ssb_dma_translation(ring->dev->dev); + if (slot == ring->nr_slots - 1) + ctl0 |= B43_DMA64_DCTL0_DTABLEEND; + if (start) + ctl0 |= B43_DMA64_DCTL0_FRAMESTART; + if (end) + ctl0 |= B43_DMA64_DCTL0_FRAMEEND; + if (irq) + ctl0 |= B43_DMA64_DCTL0_IRQ; + ctl1 |= (bufsize - ring->frameoffset) + & B43_DMA64_DCTL1_BYTECNT; + ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT) + & B43_DMA64_DCTL1_ADDREXT_MASK; + + desc->dma64.control0 = cpu_to_le32(ctl0); + desc->dma64.control1 = cpu_to_le32(ctl1); + desc->dma64.address_low = cpu_to_le32(addrlo); + desc->dma64.address_high = cpu_to_le32(addrhi); +} + +static void op64_poke_tx(struct b43_dmaring *ring, int slot) +{ + b43_dma_write(ring, B43_DMA64_TXINDEX, + (u32) (slot * sizeof(struct b43_dmadesc64))); +} + +static void op64_tx_suspend(struct b43_dmaring *ring) +{ + b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL) + | B43_DMA64_TXSUSPEND); +} + +static void op64_tx_resume(struct b43_dmaring *ring) +{ + b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL) + & ~B43_DMA64_TXSUSPEND); +} + +static int op64_get_current_rxslot(struct b43_dmaring *ring) +{ + u32 val; + + val = b43_dma_read(ring, B43_DMA64_RXSTATUS); + val &= B43_DMA64_RXSTATDPTR; + + return (val / sizeof(struct b43_dmadesc64)); +} + +static void op64_set_current_rxslot(struct b43_dmaring *ring, int slot) +{ + b43_dma_write(ring, B43_DMA64_RXINDEX, + (u32) (slot * sizeof(struct b43_dmadesc64))); +} + +static const struct b43_dma_ops dma64_ops = { + .idx2desc = op64_idx2desc, + .fill_descriptor = op64_fill_descriptor, + .poke_tx = op64_poke_tx, + .tx_suspend = op64_tx_suspend, + .tx_resume = op64_tx_resume, + .get_current_rxslot = op64_get_current_rxslot, + .set_current_rxslot = op64_set_current_rxslot, +}; + +static inline int free_slots(struct b43_dmaring *ring) +{ + return (ring->nr_slots - ring->used_slots); +} + +static inline int next_slot(struct b43_dmaring *ring, int slot) +{ + B43_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1)); + if (slot == ring->nr_slots - 1) + return 0; + return slot + 1; +} + +static inline int prev_slot(struct b43_dmaring *ring, int slot) +{ + B43_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1)); + if (slot == 0) + return ring->nr_slots - 1; + return slot - 1; +} + +#ifdef CONFIG_B43_DEBUG +static void update_max_used_slots(struct b43_dmaring *ring, + int current_used_slots) +{ + if (current_used_slots <= ring->max_used_slots) + return; + ring->max_used_slots = current_used_slots; + if (b43_debug(ring->dev, B43_DBG_DMAVERBOSE)) { + b43dbg(ring->dev->wl, + "max_used_slots increased to %d on %s ring %d\n", + ring->max_used_slots, + ring->tx ? "TX" : "RX", ring->index); + } +} +#else +static inline + void update_max_used_slots(struct b43_dmaring *ring, int current_used_slots) +{ +} +#endif /* DEBUG */ + +/* Request a slot for usage. */ +static inline int request_slot(struct b43_dmaring *ring) +{ + int slot; + + B43_WARN_ON(!ring->tx); + B43_WARN_ON(ring->stopped); + B43_WARN_ON(free_slots(ring) == 0); + + slot = next_slot(ring, ring->current_slot); + ring->current_slot = slot; + ring->used_slots++; + + update_max_used_slots(ring, ring->used_slots); + + return slot; +} + +/* Mac80211-queue to b43-ring mapping */ +static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, + int queue_priority) +{ + struct b43_dmaring *ring; + +/*FIXME: For now we always run on TX-ring-1 */ + return dev->dma.tx_ring1; + + /* 0 = highest priority */ + switch (queue_priority) { + default: + B43_WARN_ON(1); + /* fallthrough */ + case 0: + ring = dev->dma.tx_ring3; + break; + case 1: + ring = dev->dma.tx_ring2; + break; + case 2: + ring = dev->dma.tx_ring1; + break; + case 3: + ring = dev->dma.tx_ring0; + break; + case 4: + ring = dev->dma.tx_ring4; + break; + case 5: + ring = dev->dma.tx_ring5; + break; + } + + return ring; +} + +/* Bcm43xx-ring to mac80211-queue mapping */ +static inline int txring_to_priority(struct b43_dmaring *ring) +{ + static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, }; + +/*FIXME: have only one queue, for now */ + return 0; + + return idx_to_prio[ring->index]; +} + +u16 b43_dmacontroller_base(int dma64bit, int controller_idx) +{ + static const u16 map64[] = { + B43_MMIO_DMA64_BASE0, + B43_MMIO_DMA64_BASE1, + B43_MMIO_DMA64_BASE2, + B43_MMIO_DMA64_BASE3, + B43_MMIO_DMA64_BASE4, + B43_MMIO_DMA64_BASE5, + }; + static const u16 map32[] = { + B43_MMIO_DMA32_BASE0, + B43_MMIO_DMA32_BASE1, + B43_MMIO_DMA32_BASE2, + B43_MMIO_DMA32_BASE3, + B43_MMIO_DMA32_BASE4, + B43_MMIO_DMA32_BASE5, + }; + + if (dma64bit) { + B43_WARN_ON(!(controller_idx >= 0 && + controller_idx < ARRAY_SIZE(map64))); + return map64[controller_idx]; + } + B43_WARN_ON(!(controller_idx >= 0 && + controller_idx < ARRAY_SIZE(map32))); + return map32[controller_idx]; +} + +static inline + dma_addr_t map_descbuffer(struct b43_dmaring *ring, + unsigned char *buf, size_t len, int tx) +{ + dma_addr_t dmaaddr; + + if (tx) { + dmaaddr = dma_map_single(ring->dev->dev->dev, + buf, len, DMA_TO_DEVICE); + } else { + dmaaddr = dma_map_single(ring->dev->dev->dev, + buf, len, DMA_FROM_DEVICE); + } + + return dmaaddr; +} + +static inline + void unmap_descbuffer(struct b43_dmaring *ring, + dma_addr_t addr, size_t len, int tx) +{ + if (tx) { + dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE); + } else { + dma_unmap_single(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); + } +} + +static inline + void sync_descbuffer_for_cpu(struct b43_dmaring *ring, + dma_addr_t addr, size_t len) +{ + B43_WARN_ON(ring->tx); + dma_sync_single_for_cpu(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline + void sync_descbuffer_for_device(struct b43_dmaring *ring, + dma_addr_t addr, size_t len) +{ + B43_WARN_ON(ring->tx); + dma_sync_single_for_device(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline + void free_descriptor_buffer(struct b43_dmaring *ring, + struct b43_dmadesc_meta *meta) +{ + if (meta->skb) { + dev_kfree_skb_any(meta->skb); + meta->skb = NULL; + } +} + +static int alloc_ringmemory(struct b43_dmaring *ring) +{ + struct device *dev = ring->dev->dev->dev; + + ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); + if (!ring->descbase) { + b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); + return -ENOMEM; + } + memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE); + + return 0; +} + +static void free_ringmemory(struct b43_dmaring *ring) +{ + struct device *dev = ring->dev->dev->dev; + + dma_free_coherent(dev, B43_DMA_RINGMEMSIZE, + ring->descbase, ring->dmabase); +} + +/* Reset the RX DMA channel */ +int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) +{ + int i; + u32 value; + u16 offset; + + might_sleep(); + + offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL; + b43_write32(dev, mmio_base + offset, 0); + for (i = 0; i < 10; i++) { + offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS; + value = b43_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43_DMA64_RXSTAT; + if (value == B43_DMA64_RXSTAT_DISABLED) { + i = -1; + break; + } + } else { + value &= B43_DMA32_RXSTATE; + if (value == B43_DMA32_RXSTAT_DISABLED) { + i = -1; + break; + } + } + msleep(1); + } + if (i != -1) { + b43err(dev->wl, "DMA RX reset timed out\n"); + return -ENODEV; + } + + return 0; +} + +/* Reset the RX DMA channel */ +int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) +{ + int i; + u32 value; + u16 offset; + + might_sleep(); + + for (i = 0; i < 10; i++) { + offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS; + value = b43_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43_DMA64_TXSTAT; + if (value == B43_DMA64_TXSTAT_DISABLED || + value == B43_DMA64_TXSTAT_IDLEWAIT || + value == B43_DMA64_TXSTAT_STOPPED) + break; + } else { + value &= B43_DMA32_TXSTATE; + if (value == B43_DMA32_TXSTAT_DISABLED || + value == B43_DMA32_TXSTAT_IDLEWAIT || + value == B43_DMA32_TXSTAT_STOPPED) + break; + } + msleep(1); + } + offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL; + b43_write32(dev, mmio_base + offset, 0); + for (i = 0; i < 10; i++) { + offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS; + value = b43_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43_DMA64_TXSTAT; + if (value == B43_DMA64_TXSTAT_DISABLED) { + i = -1; + break; + } + } else { + value &= B43_DMA32_TXSTATE; + if (value == B43_DMA32_TXSTAT_DISABLED) { + i = -1; + break; + } + } + msleep(1); + } + if (i != -1) { + b43err(dev->wl, "DMA TX reset timed out\n"); + return -ENODEV; + } + /* ensure the reset is completed. */ + msleep(1); + + return 0; +} + +static int setup_rx_descbuffer(struct b43_dmaring *ring, + struct b43_dmadesc_generic *desc, + struct b43_dmadesc_meta *meta, gfp_t gfp_flags) +{ + struct b43_rxhdr_fw4 *rxhdr; + struct b43_hwtxstatus *txstat; + dma_addr_t dmaaddr; + struct sk_buff *skb; + + B43_WARN_ON(ring->tx); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); + if (dma_mapping_error(dmaaddr)) { + /* ugh. try to realloc in zone_dma */ + gfp_flags |= GFP_DMA; + + dev_kfree_skb_any(skb); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, + ring->rx_buffersize, 0); + } + + if (dma_mapping_error(dmaaddr)) { + dev_kfree_skb_any(skb); + return -EIO; + } + + meta->skb = skb; + meta->dmaaddr = dmaaddr; + ring->ops->fill_descriptor(ring, desc, dmaaddr, + ring->rx_buffersize, 0, 0, 0); + + rxhdr = (struct b43_rxhdr_fw4 *)(skb->data); + rxhdr->frame_len = 0; + txstat = (struct b43_hwtxstatus *)(skb->data); + txstat->cookie = 0; + + return 0; +} + +/* Allocate the initial descbuffers. + * This is used for an RX ring only. + */ +static int alloc_initial_descbuffers(struct b43_dmaring *ring) +{ + int i, err = -ENOMEM; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + + err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); + if (err) { + b43err(ring->dev->wl, + "Failed to allocate initial descbuffers\n"); + goto err_unwind; + } + } + mb(); + ring->used_slots = ring->nr_slots; + err = 0; + out: + return err; + + err_unwind: + for (i--; i >= 0; i--) { + desc = ring->ops->idx2desc(ring, i, &meta); + + unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb(meta->skb); + } + goto out; +} + +/* Do initial setup of the DMA controller. + * Reset the controller, write the ring busaddress + * and switch the "enable" bit on. + */ +static int dmacontroller_setup(struct b43_dmaring *ring) +{ + int err = 0; + u32 value; + u32 addrext; + u32 trans = ssb_dma_translation(ring->dev->dev); + + if (ring->tx) { + if (ring->dma64) { + u64 ringbase = (u64) (ring->dmabase); + + addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43_DMA64_TXENABLE; + value |= (addrext << B43_DMA64_TXADDREXT_SHIFT) + & B43_DMA64_TXADDREXT_MASK; + b43_dma_write(ring, B43_DMA64_TXCTL, value); + b43_dma_write(ring, B43_DMA64_TXRINGLO, + (ringbase & 0xFFFFFFFF)); + b43_dma_write(ring, B43_DMA64_TXRINGHI, + ((ringbase >> 32) & + ~SSB_DMA_TRANSLATION_MASK) + | trans); + } else { + u32 ringbase = (u32) (ring->dmabase); + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43_DMA32_TXENABLE; + value |= (addrext << B43_DMA32_TXADDREXT_SHIFT) + & B43_DMA32_TXADDREXT_MASK; + b43_dma_write(ring, B43_DMA32_TXCTL, value); + b43_dma_write(ring, B43_DMA32_TXRING, + (ringbase & ~SSB_DMA_TRANSLATION_MASK) + | trans); + } + } else { + err = alloc_initial_descbuffers(ring); + if (err) + goto out; + if (ring->dma64) { + u64 ringbase = (u64) (ring->dmabase); + + addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT); + value |= B43_DMA64_RXENABLE; + value |= (addrext << B43_DMA64_RXADDREXT_SHIFT) + & B43_DMA64_RXADDREXT_MASK; + b43_dma_write(ring, B43_DMA64_RXCTL, value); + b43_dma_write(ring, B43_DMA64_RXRINGLO, + (ringbase & 0xFFFFFFFF)); + b43_dma_write(ring, B43_DMA64_RXRINGHI, + ((ringbase >> 32) & + ~SSB_DMA_TRANSLATION_MASK) + | trans); + b43_dma_write(ring, B43_DMA64_RXINDEX, 200); + } else { + u32 ringbase = (u32) (ring->dmabase); + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT); + value |= B43_DMA32_RXENABLE; + value |= (addrext << B43_DMA32_RXADDREXT_SHIFT) + & B43_DMA32_RXADDREXT_MASK; + b43_dma_write(ring, B43_DMA32_RXCTL, value); + b43_dma_write(ring, B43_DMA32_RXRING, + (ringbase & ~SSB_DMA_TRANSLATION_MASK) + | trans); + b43_dma_write(ring, B43_DMA32_RXINDEX, 200); + } + } + + out: + return err; +} + +/* Shutdown the DMA controller. */ +static void dmacontroller_cleanup(struct b43_dmaring *ring) +{ + if (ring->tx) { + b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base, + ring->dma64); + if (ring->dma64) { + b43_dma_write(ring, B43_DMA64_TXRINGLO, 0); + b43_dma_write(ring, B43_DMA64_TXRINGHI, 0); + } else + b43_dma_write(ring, B43_DMA32_TXRING, 0); + } else { + b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base, + ring->dma64); + if (ring->dma64) { + b43_dma_write(ring, B43_DMA64_RXRINGLO, 0); + b43_dma_write(ring, B43_DMA64_RXRINGHI, 0); + } else + b43_dma_write(ring, B43_DMA32_RXRING, 0); + } +} + +static void free_all_descbuffers(struct b43_dmaring *ring) +{ + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + int i; + + if (!ring->used_slots) + return; + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + + if (!meta->skb) { + B43_WARN_ON(!ring->tx); + continue; + } + if (ring->tx) { + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + } else { + unmap_descbuffer(ring, meta->dmaaddr, + ring->rx_buffersize, 0); + } + free_descriptor_buffer(ring, meta); + } +} + +static u64 supported_dma_mask(struct b43_wldev *dev) +{ + u32 tmp; + u16 mmio_base; + + tmp = b43_read32(dev, SSB_TMSHIGH); + if (tmp & SSB_TMSHIGH_DMA64) + return DMA_64BIT_MASK; + mmio_base = b43_dmacontroller_base(0, 0); + b43_write32(dev, mmio_base + B43_DMA32_TXCTL, B43_DMA32_TXADDREXT_MASK); + tmp = b43_read32(dev, mmio_base + B43_DMA32_TXCTL); + if (tmp & B43_DMA32_TXADDREXT_MASK) + return DMA_32BIT_MASK; + + return DMA_30BIT_MASK; +} + +/* Main initialization function. */ +static +struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, + int controller_index, + int for_tx, int dma64) +{ + struct b43_dmaring *ring; + int err; + int nr_slots; + dma_addr_t dma_test; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out; + + nr_slots = B43_RXRING_SLOTS; + if (for_tx) + nr_slots = B43_TXRING_SLOTS; + + ring->meta = kcalloc(nr_slots, sizeof(struct b43_dmadesc_meta), + GFP_KERNEL); + if (!ring->meta) + goto err_kfree_ring; + if (for_tx) { + ring->txhdr_cache = kcalloc(nr_slots, + sizeof(struct b43_txhdr_fw4), + GFP_KERNEL); + if (!ring->txhdr_cache) + goto err_kfree_meta; + + /* test for ability to dma to txhdr_cache */ + dma_test = dma_map_single(dev->dev->dev, + ring->txhdr_cache, + sizeof(struct b43_txhdr_fw4), + DMA_TO_DEVICE); + + if (dma_mapping_error(dma_test)) { + /* ugh realloc */ + kfree(ring->txhdr_cache); + ring->txhdr_cache = kcalloc(nr_slots, + sizeof(struct + b43_txhdr_fw4), + GFP_KERNEL | GFP_DMA); + if (!ring->txhdr_cache) + goto err_kfree_meta; + + dma_test = dma_map_single(dev->dev->dev, + ring->txhdr_cache, + sizeof(struct b43_txhdr_fw4), + DMA_TO_DEVICE); + + if (dma_mapping_error(dma_test)) + goto err_kfree_txhdr_cache; + } + + dma_unmap_single(dev->dev->dev, + dma_test, sizeof(struct b43_txhdr_fw4), + DMA_TO_DEVICE); + } + + ring->dev = dev; + ring->nr_slots = nr_slots; + ring->mmio_base = b43_dmacontroller_base(dma64, controller_index); + ring->index = controller_index; + ring->dma64 = !!dma64; + if (dma64) + ring->ops = &dma64_ops; + else + ring->ops = &dma32_ops; + if (for_tx) { + ring->tx = 1; + ring->current_slot = -1; + } else { + if (ring->index == 0) { + ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE; + ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET; + } else if (ring->index == 3) { + ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE; + ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET; + } else + B43_WARN_ON(1); + } + spin_lock_init(&ring->lock); +#ifdef CONFIG_B43_DEBUG + ring->last_injected_overflow = jiffies; +#endif + + err = alloc_ringmemory(ring); + if (err) + goto err_kfree_txhdr_cache; + err = dmacontroller_setup(ring); + if (err) + goto err_free_ringmemory; + + out: + return ring; + + err_free_ringmemory: + free_ringmemory(ring); + err_kfree_txhdr_cache: + kfree(ring->txhdr_cache); + err_kfree_meta: + kfree(ring->meta); + err_kfree_ring: + kfree(ring); + ring = NULL; + goto out; +} + +/* Main cleanup function. */ +static void b43_destroy_dmaring(struct b43_dmaring *ring) +{ + if (!ring) + return; + + b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n", + (ring->dma64) ? "64" : "32", + ring->mmio_base, + (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots); + /* Device IRQs are disabled prior entering this function, + * so no need to take care of concurrency with rx handler stuff. + */ + dmacontroller_cleanup(ring); + free_all_descbuffers(ring); + free_ringmemory(ring); + + kfree(ring->txhdr_cache); + kfree(ring->meta); + kfree(ring); +} + +void b43_dma_free(struct b43_wldev *dev) +{ + struct b43_dma *dma; + + if (b43_using_pio(dev)) + return; + dma = &dev->dma; + + b43_destroy_dmaring(dma->rx_ring3); + dma->rx_ring3 = NULL; + b43_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + + b43_destroy_dmaring(dma->tx_ring5); + dma->tx_ring5 = NULL; + b43_destroy_dmaring(dma->tx_ring4); + dma->tx_ring4 = NULL; + b43_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + b43_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + b43_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + b43_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; +} + +int b43_dma_init(struct b43_wldev *dev) +{ + struct b43_dma *dma = &dev->dma; + struct b43_dmaring *ring; + int err; + u64 dmamask; + int dma64 = 0; + + dmamask = supported_dma_mask(dev); + if (dmamask == DMA_64BIT_MASK) + dma64 = 1; + + err = ssb_dma_set_mask(dev->dev, dmamask); + if (err) { +#ifdef B43_PIO + b43warn(dev->wl, "DMA for this device not supported. " + "Falling back to PIO\n"); + dev->__using_pio = 1; + return -EAGAIN; +#else + b43err(dev->wl, "DMA for this device not supported and " + "no PIO support compiled in\n"); + return -EOPNOTSUPP; +#endif + } + + err = -ENOMEM; + /* setup TX DMA channels. */ + ring = b43_setup_dmaring(dev, 0, 1, dma64); + if (!ring) + goto out; + dma->tx_ring0 = ring; + + ring = b43_setup_dmaring(dev, 1, 1, dma64); + if (!ring) + goto err_destroy_tx0; + dma->tx_ring1 = ring; + + ring = b43_setup_dmaring(dev, 2, 1, dma64); + if (!ring) + goto err_destroy_tx1; + dma->tx_ring2 = ring; + + ring = b43_setup_dmaring(dev, 3, 1, dma64); + if (!ring) + goto err_destroy_tx2; + dma->tx_ring3 = ring; + + ring = b43_setup_dmaring(dev, 4, 1, dma64); + if (!ring) + goto err_destroy_tx3; + dma->tx_ring4 = ring; + + ring = b43_setup_dmaring(dev, 5, 1, dma64); + if (!ring) + goto err_destroy_tx4; + dma->tx_ring5 = ring; + + /* setup RX DMA channels. */ + ring = b43_setup_dmaring(dev, 0, 0, dma64); + if (!ring) + goto err_destroy_tx5; + dma->rx_ring0 = ring; + + if (dev->dev->id.revision < 5) { + ring = b43_setup_dmaring(dev, 3, 0, dma64); + if (!ring) + goto err_destroy_rx0; + dma->rx_ring3 = ring; + } + + b43dbg(dev->wl, "%d-bit DMA initialized\n", + (dmamask == DMA_64BIT_MASK) ? 64 : + (dmamask == DMA_32BIT_MASK) ? 32 : 30); + err = 0; + out: + return err; + + err_destroy_rx0: + b43_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + err_destroy_tx5: + b43_destroy_dmaring(dma->tx_ring5); + dma->tx_ring5 = NULL; + err_destroy_tx4: + b43_destroy_dmaring(dma->tx_ring4); + dma->tx_ring4 = NULL; + err_destroy_tx3: + b43_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + err_destroy_tx2: + b43_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + err_destroy_tx1: + b43_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + err_destroy_tx0: + b43_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; + goto out; +} + +/* Generate a cookie for the TX header. */ +static u16 generate_cookie(struct b43_dmaring *ring, int slot) +{ + u16 cookie = 0x1000; + + /* Use the upper 4 bits of the cookie as + * DMA controller ID and store the slot number + * in the lower 12 bits. + * Note that the cookie must never be 0, as this + * is a special value used in RX path. + */ + switch (ring->index) { + case 0: + cookie = 0xA000; + break; + case 1: + cookie = 0xB000; + break; + case 2: + cookie = 0xC000; + break; + case 3: + cookie = 0xD000; + break; + case 4: + cookie = 0xE000; + break; + case 5: + cookie = 0xF000; + break; + } + B43_WARN_ON(slot & ~0x0FFF); + cookie |= (u16) slot; + + return cookie; +} + +/* Inspect a cookie and find out to which controller/slot it belongs. */ +static +struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) +{ + struct b43_dma *dma = &dev->dma; + struct b43_dmaring *ring = NULL; + + switch (cookie & 0xF000) { + case 0xA000: + ring = dma->tx_ring0; + break; + case 0xB000: + ring = dma->tx_ring1; + break; + case 0xC000: + ring = dma->tx_ring2; + break; + case 0xD000: + ring = dma->tx_ring3; + break; + case 0xE000: + ring = dma->tx_ring4; + break; + case 0xF000: + ring = dma->tx_ring5; + break; + default: + B43_WARN_ON(1); + } + *slot = (cookie & 0x0FFF); + B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots)); + + return ring; +} + +static int dma_tx_fragment(struct b43_dmaring *ring, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + const struct b43_dma_ops *ops = ring->ops; + u8 *header; + int slot; + int err; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + struct b43_dmadesc_meta *meta_hdr; + struct sk_buff *bounce_skb; + +#define SLOTS_PER_PACKET 2 + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + + /* Get a slot for the header. */ + slot = request_slot(ring); + desc = ops->idx2desc(ring, slot, &meta_hdr); + memset(meta_hdr, 0, sizeof(*meta_hdr)); + + header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]); + b43_generate_txhdr(ring->dev, header, + skb->data, skb->len, ctl, + generate_cookie(ring, slot)); + + meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, + sizeof(struct b43_txhdr_fw4), 1); + if (dma_mapping_error(meta_hdr->dmaaddr)) + return -EIO; + ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, + sizeof(struct b43_txhdr_fw4), 1, 0, 0); + + /* Get a slot for the payload. */ + slot = request_slot(ring); + desc = ops->idx2desc(ring, slot, &meta); + memset(meta, 0, sizeof(*meta)); + + memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); + meta->skb = skb; + meta->is_last_fragment = 1; + + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + /* create a bounce buffer in zone_dma on mapping failure. */ + if (dma_mapping_error(meta->dmaaddr)) { + bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); + if (!bounce_skb) { + err = -ENOMEM; + goto out_unmap_hdr; + } + + memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + dev_kfree_skb_any(skb); + skb = bounce_skb; + meta->skb = skb; + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (dma_mapping_error(meta->dmaaddr)) { + err = -EIO; + goto out_free_bounce; + } + } + + ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); + + /* Now transfer the whole frame. */ + wmb(); + ops->poke_tx(ring, next_slot(ring, slot)); + return 0; + + out_free_bounce: + dev_kfree_skb_any(skb); + out_unmap_hdr: + unmap_descbuffer(ring, meta_hdr->dmaaddr, + sizeof(struct b43_txhdr_fw4), 1); + return err; +} + +static inline int should_inject_overflow(struct b43_dmaring *ring) +{ +#ifdef CONFIG_B43_DEBUG + if (unlikely(b43_debug(ring->dev, B43_DBG_DMAOVERFLOW))) { + /* Check if we should inject another ringbuffer overflow + * to test handling of this situation in the stack. */ + unsigned long next_overflow; + + next_overflow = ring->last_injected_overflow + HZ; + if (time_after(jiffies, next_overflow)) { + ring->last_injected_overflow = jiffies; + b43dbg(ring->dev->wl, + "Injecting TX ring overflow on " + "DMA controller %d\n", ring->index); + return 1; + } + } +#endif /* CONFIG_B43_DEBUG */ + return 0; +} + +int b43_dma_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct b43_dmaring *ring; + int err = 0; + unsigned long flags; + + ring = priority_to_txring(dev, ctl->queue); + spin_lock_irqsave(&ring->lock, flags); + B43_WARN_ON(!ring->tx); + if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { + b43warn(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. */ + B43_WARN_ON(ring->stopped); + + err = dma_tx_fragment(ring, skb, ctl); + if (unlikely(err)) { + b43err(dev->wl, "DMA tx mapping failure\n"); + goto out_unlock; + } + ring->nr_tx_packets++; + if ((free_slots(ring) < SLOTS_PER_PACKET) || + should_inject_overflow(ring)) { + /* This TX ring is full. */ + ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); + ring->stopped = 1; + if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { + b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); + } + } + out_unlock: + spin_unlock_irqrestore(&ring->lock, flags); + + return err; +} + +void b43_dma_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + const struct b43_dma_ops *ops; + struct b43_dmaring *ring; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + int slot; + + ring = parse_cookie(dev, status->cookie, &slot); + if (unlikely(!ring)) + return; + B43_WARN_ON(!irqs_disabled()); + spin_lock(&ring->lock); + + B43_WARN_ON(!ring->tx); + ops = ring->ops; + while (1) { + B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + desc = ops->idx2desc(ring, slot, &meta); + + if (meta->skb) + unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, + 1); + else + unmap_descbuffer(ring, meta->dmaaddr, + sizeof(struct b43_txhdr_fw4), 1); + + if (meta->is_last_fragment) { + B43_WARN_ON(!meta->skb); + /* Call back to inform the ieee80211 subsystem about the + * status of the transmission. + * Some fields of txstat are already filled in dma_tx(). + */ + if (status->acked) { + meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; + } else { + if (!(meta->txstat.control.flags + & IEEE80211_TXCTL_NO_ACK)) + meta->txstat.excessive_retries = 1; + } + if (status->frame_count == 0) { + /* The frame was not transmitted at all. */ + meta->txstat.retry_count = 0; + } else + meta->txstat.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, + &(meta->txstat)); + /* skb is freed by ieee80211_tx_status_irqsafe() */ + meta->skb = NULL; + } else { + /* No need to call free_descriptor_buffer here, as + * this is only the txhdr, which is not allocated. + */ + B43_WARN_ON(meta->skb); + } + + /* Everything unmapped and free'd. So it's not used anymore. */ + ring->used_slots--; + + if (meta->is_last_fragment) + break; + slot = next_slot(ring, slot); + } + dev->stats.last_tx = jiffies; + if (ring->stopped) { + B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); + ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); + ring->stopped = 0; + if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { + b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); + } + } + + spin_unlock(&ring->lock); +} + +void b43_dma_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + const int nr_queues = dev->wl->hw->queues; + struct b43_dmaring *ring; + struct ieee80211_tx_queue_stats_data *data; + unsigned long flags; + int i; + + for (i = 0; i < nr_queues; i++) { + data = &(stats->data[i]); + ring = priority_to_txring(dev, i); + + spin_lock_irqsave(&ring->lock, flags); + data->len = ring->used_slots / SLOTS_PER_PACKET; + data->limit = ring->nr_slots / SLOTS_PER_PACKET; + data->count = ring->nr_tx_packets; + spin_unlock_irqrestore(&ring->lock, flags); + } +} + +static void dma_rx(struct b43_dmaring *ring, int *slot) +{ + const struct b43_dma_ops *ops = ring->ops; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + struct b43_rxhdr_fw4 *rxhdr; + struct sk_buff *skb; + u16 len; + int err; + dma_addr_t dmaaddr; + + desc = ops->idx2desc(ring, *slot, &meta); + + sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); + skb = meta->skb; + + if (ring->index == 3) { + /* We received an xmit status. */ + struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data; + int i = 0; + + while (hw->cookie == 0) { + if (i > 100) + break; + i++; + udelay(2); + barrier(); + } + b43_handle_hwtxstatus(ring->dev, hw); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + + return; + } + rxhdr = (struct b43_rxhdr_fw4 *)skb->data; + len = le16_to_cpu(rxhdr->frame_len); + if (len == 0) { + int i = 0; + + do { + udelay(2); + barrier(); + len = le16_to_cpu(rxhdr->frame_len); + } while (len == 0 && i++ < 5); + if (unlikely(len == 0)) { + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + goto drop; + } + } + if (unlikely(len > ring->rx_buffersize)) { + /* The data did not fit into one descriptor buffer + * and is split over multiple buffers. + * This should never happen, as we try to allocate buffers + * big enough. So simply ignore this packet. + */ + int cnt = 0; + s32 tmp = len; + + while (1) { + desc = ops->idx2desc(ring, *slot, &meta); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + *slot = next_slot(ring, *slot); + cnt++; + tmp -= ring->rx_buffersize; + if (tmp <= 0) + break; + } + b43err(ring->dev->wl, "DMA RX buffer too small " + "(len: %u, buffer: %u, nr-dropped: %d)\n", + len, ring->rx_buffersize, cnt); + goto drop; + } + + dmaaddr = meta->dmaaddr; + err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); + if (unlikely(err)) { + b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n"); + sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize); + goto drop; + } + + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + skb_put(skb, len + ring->frameoffset); + skb_pull(skb, ring->frameoffset); + + b43_rx(ring->dev, skb, rxhdr); + drop: + return; +} + +void b43_dma_rx(struct b43_dmaring *ring) +{ + const struct b43_dma_ops *ops = ring->ops; + int slot, current_slot; + int used_slots = 0; + + B43_WARN_ON(ring->tx); + current_slot = ops->get_current_rxslot(ring); + B43_WARN_ON(!(current_slot >= 0 && current_slot < ring->nr_slots)); + + slot = ring->current_slot; + for (; slot != current_slot; slot = next_slot(ring, slot)) { + dma_rx(ring, &slot); + update_max_used_slots(ring, ++used_slots); + } + ops->set_current_rxslot(ring, slot); + ring->current_slot = slot; +} + +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) +{ + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); + b43_dma_tx_suspend_ring(dev->dma.tx_ring0); + b43_dma_tx_suspend_ring(dev->dma.tx_ring1); + b43_dma_tx_suspend_ring(dev->dma.tx_ring2); + b43_dma_tx_suspend_ring(dev->dma.tx_ring3); + b43_dma_tx_suspend_ring(dev->dma.tx_ring4); + b43_dma_tx_suspend_ring(dev->dma.tx_ring5); +} + +void b43_dma_tx_resume(struct b43_wldev *dev) +{ + b43_dma_tx_resume_ring(dev->dma.tx_ring5); + b43_dma_tx_resume_ring(dev->dma.tx_ring4); + b43_dma_tx_resume_ring(dev->dma.tx_ring3); + b43_dma_tx_resume_ring(dev->dma.tx_ring2); + b43_dma_tx_resume_ring(dev->dma.tx_ring1); + b43_dma_tx_resume_ring(dev->dma.tx_ring0); + b43_power_saving_ctl_bits(dev, 0); +} diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h new file mode 100644 index 000000000000..3eed185be725 --- /dev/null +++ b/drivers/net/wireless/b43/dma.h @@ -0,0 +1,337 @@ +#ifndef B43_DMA_H_ +#define B43_DMA_H_ + +#include +#include +#include +#include +#include + +#include "b43.h" + +/* DMA-Interrupt reasons. */ +#define B43_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ + | (1 << 14) | (1 << 15)) +#define B43_DMAIRQ_NONFATALMASK (1 << 13) +#define B43_DMAIRQ_RX_DONE (1 << 16) + +/*** 32-bit DMA Engine. ***/ + +/* 32-bit DMA controller registers. */ +#define B43_DMA32_TXCTL 0x00 +#define B43_DMA32_TXENABLE 0x00000001 +#define B43_DMA32_TXSUSPEND 0x00000002 +#define B43_DMA32_TXLOOPBACK 0x00000004 +#define B43_DMA32_TXFLUSH 0x00000010 +#define B43_DMA32_TXADDREXT_MASK 0x00030000 +#define B43_DMA32_TXADDREXT_SHIFT 16 +#define B43_DMA32_TXRING 0x04 +#define B43_DMA32_TXINDEX 0x08 +#define B43_DMA32_TXSTATUS 0x0C +#define B43_DMA32_TXDPTR 0x00000FFF +#define B43_DMA32_TXSTATE 0x0000F000 +#define B43_DMA32_TXSTAT_DISABLED 0x00000000 +#define B43_DMA32_TXSTAT_ACTIVE 0x00001000 +#define B43_DMA32_TXSTAT_IDLEWAIT 0x00002000 +#define B43_DMA32_TXSTAT_STOPPED 0x00003000 +#define B43_DMA32_TXSTAT_SUSP 0x00004000 +#define B43_DMA32_TXERROR 0x000F0000 +#define B43_DMA32_TXERR_NOERR 0x00000000 +#define B43_DMA32_TXERR_PROT 0x00010000 +#define B43_DMA32_TXERR_UNDERRUN 0x00020000 +#define B43_DMA32_TXERR_BUFREAD 0x00030000 +#define B43_DMA32_TXERR_DESCREAD 0x00040000 +#define B43_DMA32_TXACTIVE 0xFFF00000 +#define B43_DMA32_RXCTL 0x10 +#define B43_DMA32_RXENABLE 0x00000001 +#define B43_DMA32_RXFROFF_MASK 0x000000FE +#define B43_DMA32_RXFROFF_SHIFT 1 +#define B43_DMA32_RXDIRECTFIFO 0x00000100 +#define B43_DMA32_RXADDREXT_MASK 0x00030000 +#define B43_DMA32_RXADDREXT_SHIFT 16 +#define B43_DMA32_RXRING 0x14 +#define B43_DMA32_RXINDEX 0x18 +#define B43_DMA32_RXSTATUS 0x1C +#define B43_DMA32_RXDPTR 0x00000FFF +#define B43_DMA32_RXSTATE 0x0000F000 +#define B43_DMA32_RXSTAT_DISABLED 0x00000000 +#define B43_DMA32_RXSTAT_ACTIVE 0x00001000 +#define B43_DMA32_RXSTAT_IDLEWAIT 0x00002000 +#define B43_DMA32_RXSTAT_STOPPED 0x00003000 +#define B43_DMA32_RXERROR 0x000F0000 +#define B43_DMA32_RXERR_NOERR 0x00000000 +#define B43_DMA32_RXERR_PROT 0x00010000 +#define B43_DMA32_RXERR_OVERFLOW 0x00020000 +#define B43_DMA32_RXERR_BUFWRITE 0x00030000 +#define B43_DMA32_RXERR_DESCREAD 0x00040000 +#define B43_DMA32_RXACTIVE 0xFFF00000 + +/* 32-bit DMA descriptor. */ +struct b43_dmadesc32 { + __le32 control; + __le32 address; +} __attribute__ ((__packed__)); +#define B43_DMA32_DCTL_BYTECNT 0x00001FFF +#define B43_DMA32_DCTL_ADDREXT_MASK 0x00030000 +#define B43_DMA32_DCTL_ADDREXT_SHIFT 16 +#define B43_DMA32_DCTL_DTABLEEND 0x10000000 +#define B43_DMA32_DCTL_IRQ 0x20000000 +#define B43_DMA32_DCTL_FRAMEEND 0x40000000 +#define B43_DMA32_DCTL_FRAMESTART 0x80000000 + +/*** 64-bit DMA Engine. ***/ + +/* 64-bit DMA controller registers. */ +#define B43_DMA64_TXCTL 0x00 +#define B43_DMA64_TXENABLE 0x00000001 +#define B43_DMA64_TXSUSPEND 0x00000002 +#define B43_DMA64_TXLOOPBACK 0x00000004 +#define B43_DMA64_TXFLUSH 0x00000010 +#define B43_DMA64_TXADDREXT_MASK 0x00030000 +#define B43_DMA64_TXADDREXT_SHIFT 16 +#define B43_DMA64_TXINDEX 0x04 +#define B43_DMA64_TXRINGLO 0x08 +#define B43_DMA64_TXRINGHI 0x0C +#define B43_DMA64_TXSTATUS 0x10 +#define B43_DMA64_TXSTATDPTR 0x00001FFF +#define B43_DMA64_TXSTAT 0xF0000000 +#define B43_DMA64_TXSTAT_DISABLED 0x00000000 +#define B43_DMA64_TXSTAT_ACTIVE 0x10000000 +#define B43_DMA64_TXSTAT_IDLEWAIT 0x20000000 +#define B43_DMA64_TXSTAT_STOPPED 0x30000000 +#define B43_DMA64_TXSTAT_SUSP 0x40000000 +#define B43_DMA64_TXERROR 0x14 +#define B43_DMA64_TXERRDPTR 0x0001FFFF +#define B43_DMA64_TXERR 0xF0000000 +#define B43_DMA64_TXERR_NOERR 0x00000000 +#define B43_DMA64_TXERR_PROT 0x10000000 +#define B43_DMA64_TXERR_UNDERRUN 0x20000000 +#define B43_DMA64_TXERR_TRANSFER 0x30000000 +#define B43_DMA64_TXERR_DESCREAD 0x40000000 +#define B43_DMA64_TXERR_CORE 0x50000000 +#define B43_DMA64_RXCTL 0x20 +#define B43_DMA64_RXENABLE 0x00000001 +#define B43_DMA64_RXFROFF_MASK 0x000000FE +#define B43_DMA64_RXFROFF_SHIFT 1 +#define B43_DMA64_RXDIRECTFIFO 0x00000100 +#define B43_DMA64_RXADDREXT_MASK 0x00030000 +#define B43_DMA64_RXADDREXT_SHIFT 16 +#define B43_DMA64_RXINDEX 0x24 +#define B43_DMA64_RXRINGLO 0x28 +#define B43_DMA64_RXRINGHI 0x2C +#define B43_DMA64_RXSTATUS 0x30 +#define B43_DMA64_RXSTATDPTR 0x00001FFF +#define B43_DMA64_RXSTAT 0xF0000000 +#define B43_DMA64_RXSTAT_DISABLED 0x00000000 +#define B43_DMA64_RXSTAT_ACTIVE 0x10000000 +#define B43_DMA64_RXSTAT_IDLEWAIT 0x20000000 +#define B43_DMA64_RXSTAT_STOPPED 0x30000000 +#define B43_DMA64_RXSTAT_SUSP 0x40000000 +#define B43_DMA64_RXERROR 0x34 +#define B43_DMA64_RXERRDPTR 0x0001FFFF +#define B43_DMA64_RXERR 0xF0000000 +#define B43_DMA64_RXERR_NOERR 0x00000000 +#define B43_DMA64_RXERR_PROT 0x10000000 +#define B43_DMA64_RXERR_UNDERRUN 0x20000000 +#define B43_DMA64_RXERR_TRANSFER 0x30000000 +#define B43_DMA64_RXERR_DESCREAD 0x40000000 +#define B43_DMA64_RXERR_CORE 0x50000000 + +/* 64-bit DMA descriptor. */ +struct b43_dmadesc64 { + __le32 control0; + __le32 control1; + __le32 address_low; + __le32 address_high; +} __attribute__ ((__packed__)); +#define B43_DMA64_DCTL0_DTABLEEND 0x10000000 +#define B43_DMA64_DCTL0_IRQ 0x20000000 +#define B43_DMA64_DCTL0_FRAMEEND 0x40000000 +#define B43_DMA64_DCTL0_FRAMESTART 0x80000000 +#define B43_DMA64_DCTL1_BYTECNT 0x00001FFF +#define B43_DMA64_DCTL1_ADDREXT_MASK 0x00030000 +#define B43_DMA64_DCTL1_ADDREXT_SHIFT 16 + +struct b43_dmadesc_generic { + union { + struct b43_dmadesc32 dma32; + struct b43_dmadesc64 dma64; + } __attribute__ ((__packed__)); +} __attribute__ ((__packed__)); + +/* Misc DMA constants */ +#define B43_DMA_RINGMEMSIZE PAGE_SIZE +#define B43_DMA0_RX_FRAMEOFFSET 30 +#define B43_DMA3_RX_FRAMEOFFSET 0 + +/* DMA engine tuning knobs */ +#define B43_TXRING_SLOTS 128 +#define B43_RXRING_SLOTS 64 +#define B43_DMA0_RX_BUFFERSIZE (2304 + 100) +#define B43_DMA3_RX_BUFFERSIZE 16 + +#ifdef CONFIG_B43_DMA + +struct sk_buff; +struct b43_private; +struct b43_txstatus; + +struct b43_dmadesc_meta { + /* The kernel DMA-able buffer. */ + struct sk_buff *skb; + /* DMA base bus-address of the descriptor buffer. */ + dma_addr_t dmaaddr; + /* ieee80211 TX status. Only used once per 802.11 frag. */ + bool is_last_fragment; + struct ieee80211_tx_status txstat; +}; + +struct b43_dmaring; + +/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */ +struct b43_dma_ops { + struct b43_dmadesc_generic *(*idx2desc) (struct b43_dmaring * ring, + int slot, + struct b43_dmadesc_meta ** + meta); + void (*fill_descriptor) (struct b43_dmaring * ring, + struct b43_dmadesc_generic * desc, + dma_addr_t dmaaddr, u16 bufsize, int start, + int end, int irq); + void (*poke_tx) (struct b43_dmaring * ring, int slot); + void (*tx_suspend) (struct b43_dmaring * ring); + void (*tx_resume) (struct b43_dmaring * ring); + int (*get_current_rxslot) (struct b43_dmaring * ring); + void (*set_current_rxslot) (struct b43_dmaring * ring, int slot); +}; + +struct b43_dmaring { + /* Lowlevel DMA ops. */ + const struct b43_dma_ops *ops; + /* Kernel virtual base address of the ring memory. */ + void *descbase; + /* Meta data about all descriptors. */ + struct b43_dmadesc_meta *meta; + /* Cache of TX headers for each slot. + * This is to avoid an allocation on each TX. + * This is NULL for an RX ring. + */ + u8 *txhdr_cache; + /* (Unadjusted) DMA base bus-address of the ring memory. */ + dma_addr_t dmabase; + /* Number of descriptor slots in the ring. */ + int nr_slots; + /* Number of used descriptor slots. */ + int used_slots; + /* Currently used slot in the ring. */ + int current_slot; + /* Total number of packets sent. Statistics only. */ + unsigned int nr_tx_packets; + /* Frameoffset in octets. */ + u32 frameoffset; + /* Descriptor buffer size. */ + u16 rx_buffersize; + /* The MMIO base register of the DMA controller. */ + u16 mmio_base; + /* DMA controller index number (0-5). */ + int index; + /* Boolean. Is this a TX ring? */ + bool tx; + /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */ + bool dma64; + /* Boolean. Is this ring stopped at ieee80211 level? */ + bool stopped; + /* Lock, only used for TX. */ + spinlock_t lock; + struct b43_wldev *dev; +#ifdef CONFIG_B43_DEBUG + /* Maximum number of used slots. */ + int max_used_slots; + /* Last time we injected a ring overflow. */ + unsigned long last_injected_overflow; +#endif /* CONFIG_B43_DEBUG */ +}; + +static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) +{ + return b43_read32(ring->dev, ring->mmio_base + offset); +} + +static inline + void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value) +{ + b43_write32(ring->dev, ring->mmio_base + offset, value); +} + +int b43_dma_init(struct b43_wldev *dev); +void b43_dma_free(struct b43_wldev *dev); + +int b43_dmacontroller_rx_reset(struct b43_wldev *dev, + u16 dmacontroller_mmio_base, int dma64); +int b43_dmacontroller_tx_reset(struct b43_wldev *dev, + u16 dmacontroller_mmio_base, int dma64); + +u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx); + +void b43_dma_tx_suspend(struct b43_wldev *dev); +void b43_dma_tx_resume(struct b43_wldev *dev); + +void b43_dma_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats); + +int b43_dma_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl); +void b43_dma_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status); + +void b43_dma_rx(struct b43_dmaring *ring); + +#else /* CONFIG_B43_DMA */ + +static inline int b43_dma_init(struct b43_wldev *dev) +{ + return 0; +} +static inline void b43_dma_free(struct b43_wldev *dev) +{ +} +static inline + int b43_dmacontroller_rx_reset(struct b43_wldev *dev, + u16 dmacontroller_mmio_base, int dma64) +{ + return 0; +} +static inline + int b43_dmacontroller_tx_reset(struct b43_wldev *dev, + u16 dmacontroller_mmio_base, int dma64) +{ + return 0; +} +static inline + void b43_dma_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline + int b43_dma_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline + void b43_dma_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ +} +static inline void b43_dma_rx(struct b43_dmaring *ring) +{ +} +static inline void b43_dma_tx_suspend(struct b43_wldev *dev) +{ +} +static inline void b43_dma_tx_resume(struct b43_wldev *dev) +{ +} + +#endif /* CONFIG_B43_DMA */ +#endif /* B43_DMA_H_ */ diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c new file mode 100644 index 000000000000..535f960412d7 --- /dev/null +++ b/drivers/net/wireless/b43/leds.c @@ -0,0 +1,299 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "leds.h" +#include "main.h" + +static void b43_led_changestate(struct b43_led *led) +{ + struct b43_wldev *dev = led->dev; + const int index = b43_led_index(led); + const u16 mask = (1 << index); + u16 ledctl; + + B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); + B43_WARN_ON(!led->blink_interval); + ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); +} + +static void b43_led_blink(unsigned long d) +{ + struct b43_led *led = (struct b43_led *)d; + struct b43_wldev *dev = led->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + if (led->blink_interval) { + b43_led_changestate(led); + mod_timer(&led->blink_timer, jiffies + led->blink_interval); + } + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} + +static void b43_led_blink_start(struct b43_led *led, unsigned long interval) +{ + if (led->blink_interval) + return; + led->blink_interval = interval; + b43_led_changestate(led); + led->blink_timer.expires = jiffies + interval; + add_timer(&led->blink_timer); +} + +static void b43_led_blink_stop(struct b43_led *led, int sync) +{ + struct b43_wldev *dev = led->dev; + const int index = b43_led_index(led); + u16 ledctl; + + if (!led->blink_interval) + return; + if (unlikely(sync)) + del_timer_sync(&led->blink_timer); + else + del_timer(&led->blink_timer); + led->blink_interval = 0; + + /* Make sure the LED is turned off. */ + B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); + ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + if (led->activelow) + ledctl |= (1 << index); + else + ledctl &= ~(1 << index); + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); +} + +static void b43_led_init_hardcoded(struct b43_wldev *dev, + struct b43_led *led, int led_index) +{ + struct ssb_bus *bus = dev->dev->bus; + + /* This function is called, if the behaviour (and activelow) + * information for a LED is missing in the SPROM. + * We hardcode the behaviour values for various devices here. + * Note that the B43_LED_TEST_XXX behaviour values can + * be used to figure out which led is mapped to which index. + */ + + switch (led_index) { + case 0: + led->behaviour = B43_LED_ACTIVITY; + led->activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = B43_LED_RADIO_ALL; + break; + case 1: + led->behaviour = B43_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + led->behaviour = B43_LED_ASSOC; + break; + case 2: + led->behaviour = B43_LED_RADIO_A; + break; + case 3: + led->behaviour = B43_LED_OFF; + break; + default: + B43_WARN_ON(1); + } +} + +int b43_leds_init(struct b43_wldev *dev) +{ + struct b43_led *led; + u8 sprom[4]; + int i; + + sprom[0] = dev->dev->bus->sprom.r1.gpio0; + sprom[1] = dev->dev->bus->sprom.r1.gpio1; + sprom[2] = dev->dev->bus->sprom.r1.gpio2; + sprom[3] = dev->dev->bus->sprom.r1.gpio3; + + for (i = 0; i < B43_NR_LEDS; i++) { + led = &(dev->leds[i]); + led->dev = dev; + setup_timer(&led->blink_timer, + b43_led_blink, (unsigned long)led); + + if (sprom[i] == 0xFF) { + b43_led_init_hardcoded(dev, led, i); + } else { + led->behaviour = sprom[i] & B43_LED_BEHAVIOUR; + led->activelow = !!(sprom[i] & B43_LED_ACTIVELOW); + } + } + + return 0; +} + +void b43_leds_exit(struct b43_wldev *dev) +{ + struct b43_led *led; + int i; + + for (i = 0; i < B43_NR_LEDS; i++) { + led = &(dev->leds[i]); + b43_led_blink_stop(led, 1); + } + b43_leds_switch_all(dev, 0); +} + +void b43_leds_update(struct b43_wldev *dev, int activity) +{ + struct b43_led *led; + struct b43_phy *phy = &dev->phy; + const int transferring = + (jiffies - dev->stats.last_tx) < B43_LED_XFER_THRES; + int i, turn_on; + unsigned long interval = 0; + u16 ledctl; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + for (i = 0; i < B43_NR_LEDS; i++) { + led = &(dev->leds[i]); + + turn_on = 0; + switch (led->behaviour) { + case B43_LED_INACTIVE: + continue; + case B43_LED_OFF: + break; + case B43_LED_ON: + turn_on = 1; + break; + case B43_LED_ACTIVITY: + turn_on = activity; + break; + case B43_LED_RADIO_ALL: + turn_on = phy->radio_on && b43_is_hw_radio_enabled(dev); + break; + case B43_LED_RADIO_A: + turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) + && phy->type == B43_PHYTYPE_A); + break; + case B43_LED_RADIO_B: + turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) + && (phy->type == B43_PHYTYPE_B + || phy->type == B43_PHYTYPE_G)); + break; + case B43_LED_MODE_BG: + if (phy->type == B43_PHYTYPE_G + && b43_is_hw_radio_enabled(dev) + && 1 /*FIXME: using G rates. */ ) + turn_on = 1; + break; + case B43_LED_TRANSFER: + if (transferring) + b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); + else + b43_led_blink_stop(led, 0); + continue; + case B43_LED_APTRANSFER: + if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + if (transferring) { + interval = B43_LEDBLINK_FAST; + turn_on = 1; + } + } else { + turn_on = 1; + if (0 /*TODO: not assoc */ ) + interval = B43_LEDBLINK_SLOW; + else if (transferring) + interval = B43_LEDBLINK_FAST; + else + turn_on = 0; + } + if (turn_on) + b43_led_blink_start(led, interval); + else + b43_led_blink_stop(led, 0); + continue; + case B43_LED_WEIRD: + //TODO + break; + case B43_LED_ASSOC: + if (1 /*dev->softmac->associated */ ) + turn_on = 1; + break; +#ifdef CONFIG_B43_DEBUG + case B43_LED_TEST_BLINKSLOW: + b43_led_blink_start(led, B43_LEDBLINK_SLOW); + continue; + case B43_LED_TEST_BLINKMEDIUM: + b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); + continue; + case B43_LED_TEST_BLINKFAST: + b43_led_blink_start(led, B43_LEDBLINK_FAST); + continue; +#endif /* CONFIG_B43_DEBUG */ + default: + B43_WARN_ON(1); + }; + + if (led->activelow) + turn_on = !turn_on; + if (turn_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} + +void b43_leds_switch_all(struct b43_wldev *dev, int on) +{ + struct b43_led *led; + u16 ledctl; + int i; + int bit_on; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + for (i = 0; i < B43_NR_LEDS; i++) { + led = &(dev->leds[i]); + if (led->behaviour == B43_LED_INACTIVE) + continue; + if (on) + bit_on = led->activelow ? 0 : 1; + else + bit_on = led->activelow ? 1 : 0; + if (bit_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h new file mode 100644 index 000000000000..36b46cfda220 --- /dev/null +++ b/drivers/net/wireless/b43/leds.h @@ -0,0 +1,55 @@ +#ifndef B43_LEDS_H_ +#define B43_LEDS_H_ + +#include +#include + +struct b43_led { + u8 behaviour:7; + u8 activelow:1; + + struct b43_wldev *dev; + struct timer_list blink_timer; + unsigned long blink_interval; +}; +#define b43_led_index(led) ((int)((led) - (led)->dev->leds)) + +/* Delay between state changes when blinking in jiffies */ +#define B43_LEDBLINK_SLOW (HZ / 1) +#define B43_LEDBLINK_MEDIUM (HZ / 4) +#define B43_LEDBLINK_FAST (HZ / 8) + +#define B43_LED_XFER_THRES (HZ / 100) + +#define B43_LED_BEHAVIOUR 0x7F +#define B43_LED_ACTIVELOW 0x80 +enum { /* LED behaviour values */ + B43_LED_OFF, + B43_LED_ON, + B43_LED_ACTIVITY, + B43_LED_RADIO_ALL, + B43_LED_RADIO_A, + B43_LED_RADIO_B, + B43_LED_MODE_BG, + B43_LED_TRANSFER, + B43_LED_APTRANSFER, + B43_LED_WEIRD, //FIXME + B43_LED_ASSOC, + B43_LED_INACTIVE, + + /* Behaviour values for testing. + * With these values it is easier to figure out + * the real behaviour of leds, in case the SPROM + * is missing information. + */ + B43_LED_TEST_BLINKSLOW, + B43_LED_TEST_BLINKMEDIUM, + B43_LED_TEST_BLINKFAST, +}; + +int b43_leds_init(struct b43_wldev *dev); +void b43_leds_exit(struct b43_wldev *dev); +void b43_leds_update(struct b43_wldev *dev, int activity); +void b43_leds_switch_all(struct b43_wldev *dev, int on); + +#endif /* B43_LEDS_H_ */ diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c new file mode 100644 index 000000000000..b14a1753a0d7 --- /dev/null +++ b/drivers/net/wireless/b43/lo.c @@ -0,0 +1,1261 @@ +/* + + Broadcom B43 wireless driver + + G PHY LO (LocalOscillator) Measuring and Control routines + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005, 2006 Stefano Brivio + Copyright (c) 2005-2007 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "lo.h" +#include "phy.h" +#include "main.h" + +#include +#include + + +/* Define to 1 to always calibrate all possible LO control pairs. + * This is a workaround until we fix the partial LO calibration optimization. */ +#define B43_CALIB_ALL_LOCTLS 1 + + +/* Write the LocalOscillator Control (adjust) value-pair. */ +static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) +{ + struct b43_phy *phy = &dev->phy; + u16 value; + u16 reg; + + if (B43_DEBUG) { + if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { + b43dbg(dev->wl, "Invalid LO control pair " + "(I: %d, Q: %d)\n", control->i, control->q); + dump_stack(); + return; + } + } + + value = (u8) (control->q); + value |= ((u8) (control->i)) << 8; + + reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL; + b43_phy_write(dev, reg, value); +} + +static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt, + const struct b43_bbatt *bbatt, + struct b43_wldev *dev) +{ + int err = 0; + + /* Check the attenuation values against the LO control array sizes. */ + if (unlikely(rfatt->att >= B43_NR_RF)) { + b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att); + err = -EINVAL; + } + if (unlikely(bbatt->att >= B43_NR_BB)) { + b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att); + err = -EINVAL; + } + + return err; +} + +#if !B43_CALIB_ALL_LOCTLS +static +struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev, + const struct b43_rfatt *rfatt, + const struct b43_bbatt *bbatt) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + + if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) + return &(lo->no_padmix[0][0]); /* Just prevent a crash */ + return &(lo->no_padmix[bbatt->att][rfatt->att]); +} +#endif /* !B43_CALIB_ALL_LOCTLS */ + +struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, + const struct b43_rfatt *rfatt, + const struct b43_bbatt *bbatt) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + + if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) + return &(lo->no_padmix[0][0]); /* Just prevent a crash */ + if (rfatt->with_padmix) + return &(lo->with_padmix[bbatt->att][rfatt->att]); + return &(lo->no_padmix[bbatt->att][rfatt->att]); +} + +/* Call a function for every possible LO control value-pair. */ +static void b43_call_for_each_loctl(struct b43_wldev *dev, + void (*func) (struct b43_wldev *, + struct b43_loctl *)) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *ctl = phy->lo_control; + int i, j; + + for (i = 0; i < B43_NR_BB; i++) { + for (j = 0; j < B43_NR_RF; j++) + func(dev, &(ctl->with_padmix[i][j])); + } + for (i = 0; i < B43_NR_BB; i++) { + for (j = 0; j < B43_NR_RF; j++) + func(dev, &(ctl->no_padmix[i][j])); + } +} + +static u16 lo_b_r15_loop(struct b43_wldev *dev) +{ + int i; + u16 ret = 0; + + for (i = 0; i < 10; i++) { + b43_phy_write(dev, 0x0015, 0xAFA0); + udelay(1); + b43_phy_write(dev, 0x0015, 0xEFA0); + udelay(10); + b43_phy_write(dev, 0x0015, 0xFFA0); + udelay(40); + ret += b43_phy_read(dev, 0x002C); + } + + return ret; +} + +void b43_lo_b_measure(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 regstack[12] = { 0 }; + u16 mls; + u16 fval; + int i, j; + + regstack[0] = b43_phy_read(dev, 0x0015); + regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0; + + if (phy->radio_ver == 0x2053) { + regstack[2] = b43_phy_read(dev, 0x000A); + regstack[3] = b43_phy_read(dev, 0x002A); + regstack[4] = b43_phy_read(dev, 0x0035); + regstack[5] = b43_phy_read(dev, 0x0003); + regstack[6] = b43_phy_read(dev, 0x0001); + regstack[7] = b43_phy_read(dev, 0x0030); + + regstack[8] = b43_radio_read16(dev, 0x0043); + regstack[9] = b43_radio_read16(dev, 0x007A); + regstack[10] = b43_read16(dev, 0x03EC); + regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0; + + b43_phy_write(dev, 0x0030, 0x00FF); + b43_write16(dev, 0x03EC, 0x3F3F); + b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); + b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); + } + b43_phy_write(dev, 0x0015, 0xB000); + b43_phy_write(dev, 0x002B, 0x0004); + + if (phy->radio_ver == 0x2053) { + b43_phy_write(dev, 0x002B, 0x0203); + b43_phy_write(dev, 0x002A, 0x08A3); + } + + phy->minlowsig[0] = 0xFFFF; + + for (i = 0; i < 4; i++) { + b43_radio_write16(dev, 0x0052, regstack[1] | i); + lo_b_r15_loop(dev); + } + for (i = 0; i < 10; i++) { + b43_radio_write16(dev, 0x0052, regstack[1] | i); + mls = lo_b_r15_loop(dev) / 10; + if (mls < phy->minlowsig[0]) { + phy->minlowsig[0] = mls; + phy->minlowsigpos[0] = i; + } + } + b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]); + + phy->minlowsig[1] = 0xFFFF; + + for (i = -4; i < 5; i += 2) { + for (j = -4; j < 5; j += 2) { + if (j < 0) + fval = (0x0100 * i) + j + 0x0100; + else + fval = (0x0100 * i) + j; + b43_phy_write(dev, 0x002F, fval); + mls = lo_b_r15_loop(dev) / 10; + if (mls < phy->minlowsig[1]) { + phy->minlowsig[1] = mls; + phy->minlowsigpos[1] = fval; + } + } + } + phy->minlowsigpos[1] += 0x0101; + + b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]); + if (phy->radio_ver == 0x2053) { + b43_phy_write(dev, 0x000A, regstack[2]); + b43_phy_write(dev, 0x002A, regstack[3]); + b43_phy_write(dev, 0x0035, regstack[4]); + b43_phy_write(dev, 0x0003, regstack[5]); + b43_phy_write(dev, 0x0001, regstack[6]); + b43_phy_write(dev, 0x0030, regstack[7]); + + b43_radio_write16(dev, 0x0043, regstack[8]); + b43_radio_write16(dev, 0x007A, regstack[9]); + + b43_radio_write16(dev, 0x0052, + (b43_radio_read16(dev, 0x0052) & 0x000F) + | regstack[11]); + + b43_write16(dev, 0x03EC, regstack[10]); + } + b43_phy_write(dev, 0x0015, regstack[0]); +} + +static u16 lo_measure_feedthrough(struct b43_wldev *dev, + u16 lna, u16 pga, u16 trsw_rx) +{ + struct b43_phy *phy = &dev->phy; + u16 rfover; + u16 feedthrough; + + if (phy->gmode) { + lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT; + pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT; + + B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA); + B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA); +/*FIXME This assertion fails B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX | + B43_PHY_RFOVERVAL_BW)); +*/ + trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW); + + /* Construct the RF Override Value */ + rfover = B43_PHY_RFOVERVAL_UNK; + rfover |= pga; + rfover |= lna; + rfover |= trsw_rx; + if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) && + phy->rev > 6) + rfover |= B43_PHY_RFOVERVAL_EXTLNA; + + b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); + udelay(10); + rfover |= B43_PHY_RFOVERVAL_BW_LBW; + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); + udelay(10); + rfover |= B43_PHY_RFOVERVAL_BW_LPF; + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); + udelay(10); + b43_phy_write(dev, B43_PHY_PGACTL, 0xF300); + } else { + pga |= B43_PHY_PGACTL_UNKNOWN; + b43_phy_write(dev, B43_PHY_PGACTL, pga); + udelay(10); + pga |= B43_PHY_PGACTL_LOWBANDW; + b43_phy_write(dev, B43_PHY_PGACTL, pga); + udelay(10); + pga |= B43_PHY_PGACTL_LPF; + b43_phy_write(dev, B43_PHY_PGACTL, pga); + } + udelay(21); + feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + + /* This is a good place to check if we need to relax a bit, + * as this is the main function called regularly + * in the LO calibration. */ + cond_resched(); + + return feedthrough; +} + +/* TXCTL Register and Value Table. + * Returns the "TXCTL Register". + * "value" is the "TXCTL Value". + * "pad_mix_gain" is the PAD Mixer Gain. + */ +static u16 lo_txctl_register_table(struct b43_wldev *dev, + u16 * value, u16 * pad_mix_gain) +{ + struct b43_phy *phy = &dev->phy; + u16 reg, v, padmix; + + if (phy->type == B43_PHYTYPE_B) { + v = 0x30; + if (phy->radio_rev <= 5) { + reg = 0x43; + padmix = 0; + } else { + reg = 0x52; + padmix = 5; + } + } else { + if (phy->rev >= 2 && phy->radio_rev == 8) { + reg = 0x43; + v = 0x10; + padmix = 2; + } else { + reg = 0x52; + v = 0x30; + padmix = 5; + } + } + if (value) + *value = v; + if (pad_mix_gain) + *pad_mix_gain = padmix; + + return reg; +} + +static void lo_measure_txctl_values(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 reg, mask; + u16 trsw_rx, pga; + u16 radio_pctl_reg; + + static const u8 tx_bias_values[] = { + 0x09, 0x08, 0x0A, 0x01, 0x00, + 0x02, 0x05, 0x04, 0x06, + }; + static const u8 tx_magn_values[] = { + 0x70, 0x40, + }; + + if (!has_loopback_gain(phy)) { + radio_pctl_reg = 6; + trsw_rx = 2; + pga = 0; + } else { + int lb_gain; /* Loopback gain (in dB) */ + + trsw_rx = 0; + lb_gain = phy->max_lb_gain / 2; + if (lb_gain > 10) { + radio_pctl_reg = 0; + pga = abs(10 - lb_gain) / 6; + pga = limit_value(pga, 0, 15); + } else { + int cmp_val; + int tmp; + + pga = 0; + cmp_val = 0x24; + if ((phy->rev >= 2) && + (phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) + cmp_val = 0x3C; + tmp = lb_gain; + if ((10 - lb_gain) < cmp_val) + tmp = (10 - lb_gain); + if (tmp < 0) + tmp += 6; + else + tmp += 3; + cmp_val /= 4; + tmp /= 4; + if (tmp >= cmp_val) + radio_pctl_reg = cmp_val; + else + radio_pctl_reg = tmp; + } + } + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | radio_pctl_reg); + b43_phy_set_baseband_attenuation(dev, 2); + + reg = lo_txctl_register_table(dev, &mask, NULL); + mask = ~mask; + b43_radio_write16(dev, reg, b43_radio_read16(dev, reg) + & mask); + + if (has_tx_magnification(phy)) { + int i, j; + int feedthrough; + int min_feedth = 0xFFFF; + u8 tx_magn, tx_bias; + + for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) { + tx_magn = tx_magn_values[i]; + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) + & 0xFF0F) | tx_magn); + for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) { + tx_bias = tx_bias_values[j]; + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) + & 0xFFF0) | tx_bias); + feedthrough = + lo_measure_feedthrough(dev, 0, pga, + trsw_rx); + if (feedthrough < min_feedth) { + lo->tx_bias = tx_bias; + lo->tx_magn = tx_magn; + min_feedth = feedthrough; + } + if (lo->tx_bias == 0) + break; + } + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) + & 0xFF00) | lo->tx_bias | lo-> + tx_magn); + } + } else { + lo->tx_magn = 0; + lo->tx_bias = 0; + b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52) + & 0xFFF0); /* TX bias == 0 */ + } +} + +static void lo_read_power_vector(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 i; + u64 tmp; + u64 power_vector = 0; + int rf_offset, bb_offset; + struct b43_loctl *loctl; + + for (i = 0; i < 8; i += 2) { + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); + /* Clear the top byte. We get holes in the bitmap... */ + tmp &= 0xFF; + power_vector |= (tmp << (i * 8)); + /* Clear the vector on the device. */ + b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); + } + + if (power_vector) + lo->power_vector = power_vector; + power_vector = lo->power_vector; + + for (i = 0; i < 64; i++) { + if (power_vector & ((u64) 1ULL << i)) { + /* Now figure out which b43_loctl corresponds + * to this bit. + */ + rf_offset = i / lo->rfatt_list.len; + bb_offset = i % lo->rfatt_list.len; //FIXME? + loctl = + b43_get_lo_g_ctl(dev, + &lo->rfatt_list.list[rf_offset], + &lo->bbatt_list.list[bb_offset]); + /* And mark it as "used", as the device told us + * through the bitmap it is using it. + */ + loctl->used = 1; + } + } +} + +/* 802.11/LO/GPHY/MeasuringGains */ +static void lo_measure_gain_values(struct b43_wldev *dev, + s16 max_rx_gain, int use_trsw_rx) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + + if (max_rx_gain < 0) + max_rx_gain = 0; + + if (has_loopback_gain(phy)) { + int trsw_rx = 0; + int trsw_rx_gain; + + if (use_trsw_rx) { + trsw_rx_gain = phy->trsw_rx_gain / 2; + if (max_rx_gain >= trsw_rx_gain) { + trsw_rx_gain = max_rx_gain - trsw_rx_gain; + trsw_rx = 0x20; + } + } else + trsw_rx_gain = max_rx_gain; + if (trsw_rx_gain < 9) { + phy->lna_lod_gain = 0; + } else { + phy->lna_lod_gain = 1; + trsw_rx_gain -= 8; + } + trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D); + phy->pga_gain = trsw_rx_gain / 3; + if (phy->pga_gain >= 5) { + phy->pga_gain -= 5; + phy->lna_gain = 2; + } else + phy->lna_gain = 0; + } else { + phy->lna_gain = 0; + phy->trsw_rx_gain = 0x20; + if (max_rx_gain >= 0x14) { + phy->lna_lod_gain = 1; + phy->pga_gain = 2; + } else if (max_rx_gain >= 0x12) { + phy->lna_lod_gain = 1; + phy->pga_gain = 1; + } else if (max_rx_gain >= 0xF) { + phy->lna_lod_gain = 1; + phy->pga_gain = 0; + } else { + phy->lna_lod_gain = 0; + phy->pga_gain = 0; + } + } + + tmp = b43_radio_read16(dev, 0x7A); + if (phy->lna_lod_gain == 0) + tmp &= ~0x0008; + else + tmp |= 0x0008; + b43_radio_write16(dev, 0x7A, tmp); +} + +struct lo_g_saved_values { + u8 old_channel; + + /* Core registers */ + u16 reg_3F4; + u16 reg_3E2; + + /* PHY registers */ + u16 phy_lo_mask; + u16 phy_extg_01; + u16 phy_dacctl_hwpctl; + u16 phy_dacctl; + u16 phy_base_14; + u16 phy_hpwr_tssictl; + u16 phy_analogover; + u16 phy_analogoverval; + u16 phy_rfover; + u16 phy_rfoverval; + u16 phy_classctl; + u16 phy_base_3E; + u16 phy_crs0; + u16 phy_pgactl; + u16 phy_base_2A; + u16 phy_syncctl; + u16 phy_base_30; + u16 phy_base_06; + + /* Radio registers */ + u16 radio_43; + u16 radio_7A; + u16 radio_52; +}; + +static void lo_measure_setup(struct b43_wldev *dev, + struct lo_g_saved_values *sav) +{ + struct ssb_sprom *sprom = &dev->dev->bus->sprom; + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 tmp; + + if (b43_has_hardware_pctl(phy)) { + sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); + sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); + sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); + sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14)); + sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL); + + b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, + b43_phy_read(dev, B43_PHY_HPWR_TSSICTL) + | 0x100); + b43_phy_write(dev, B43_PHY_EXTG(0x01), + b43_phy_read(dev, B43_PHY_EXTG(0x01)) + | 0x40); + b43_phy_write(dev, B43_PHY_DACCTL, + b43_phy_read(dev, B43_PHY_DACCTL) + | 0x40); + b43_phy_write(dev, B43_PHY_BASE(0x14), + b43_phy_read(dev, B43_PHY_BASE(0x14)) + | 0x200); + } + if (phy->type == B43_PHYTYPE_B && + phy->radio_ver == 0x2050 && phy->radio_rev < 6) { + b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410); + b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820); + } + if (!lo->rebuild && b43_has_hardware_pctl(phy)) + lo_read_power_vector(dev); + if (phy->rev >= 2) { + sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); + sav->phy_analogoverval = + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); + sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); + sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E)); + sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); + + b43_phy_write(dev, B43_PHY_CLASSCTL, + b43_phy_read(dev, B43_PHY_CLASSCTL) + & 0xFFFC); + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) + | 0x0003); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) + & 0xFFFC); + if (phy->type == B43_PHYTYPE_G) { + if ((phy->rev >= 7) && + (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + b43_phy_write(dev, B43_PHY_RFOVER, 0x933); + } else { + b43_phy_write(dev, B43_PHY_RFOVER, 0x133); + } + } else { + b43_phy_write(dev, B43_PHY_RFOVER, 0); + } + b43_phy_write(dev, B43_PHY_BASE(0x3E), 0); + } + sav->reg_3F4 = b43_read16(dev, 0x3F4); + sav->reg_3E2 = b43_read16(dev, 0x3E2); + sav->radio_43 = b43_radio_read16(dev, 0x43); + sav->radio_7A = b43_radio_read16(dev, 0x7A); + sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); + sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A)); + sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); + sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL); + + if (!has_tx_magnification(phy)) { + sav->radio_52 = b43_radio_read16(dev, 0x52); + sav->radio_52 &= 0x00F0; + } + if (phy->type == B43_PHYTYPE_B) { + sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30)); + sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06)); + b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF); + b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F); + } else { + b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) + | 0x8000); + } + b43_write16(dev, 0x3F4, b43_read16(dev, 0x3F4) + & 0xF000); + + tmp = + (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E); + b43_phy_write(dev, tmp, 0x007F); + + tmp = sav->phy_syncctl; + b43_phy_write(dev, B43_PHY_SYNCCTL, tmp & 0xFF7F); + tmp = sav->radio_7A; + b43_radio_write16(dev, 0x007A, tmp & 0xFFF0); + + b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3); + if (phy->type == B43_PHYTYPE_G || + (phy->type == B43_PHYTYPE_B && + phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) { + b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003); + } else + b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802); + if (phy->rev >= 2) + b43_dummy_transmission(dev); + b43_radio_selectchannel(dev, 6, 0); + b43_radio_read16(dev, 0x51); /* dummy read */ + if (phy->type == B43_PHYTYPE_G) + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0); + if (lo->rebuild) + lo_measure_txctl_values(dev); + if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); + } else { + if (phy->type == B43_PHYTYPE_B) + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); + } +} + +static void lo_measure_restore(struct b43_wldev *dev, + struct lo_g_saved_values *sav) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 tmp; + + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); + tmp = (phy->pga_gain << 8); + b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0); + udelay(5); + b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2); + udelay(2); + b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3); + } else { + tmp = (phy->pga_gain | 0xEFA0); + b43_phy_write(dev, B43_PHY_PGACTL, tmp); + } + if (b43_has_hardware_pctl(phy)) { + b43_gphy_dc_lt_init(dev); + } else { + if (lo->rebuild) + b43_lo_g_adjust_to(dev, 3, 2, 0); + else + b43_lo_g_adjust(dev); + } + if (phy->type == B43_PHYTYPE_G) { + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078); + else + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078); + if (phy->rev >= 2) + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202); + else + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101); + } + b43_write16(dev, 0x3F4, sav->reg_3F4); + b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl); + b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A); + b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl); + b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl); + b43_radio_write16(dev, 0x43, sav->radio_43); + b43_radio_write16(dev, 0x7A, sav->radio_7A); + if (!has_tx_magnification(phy)) { + tmp = sav->radio_52; + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & 0xFF0F) | tmp); + } + b43_write16(dev, 0x3E2, sav->reg_3E2); + if (phy->type == B43_PHYTYPE_B && + phy->radio_ver == 0x2050 && phy->radio_rev <= 5) { + b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30); + b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06); + } + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + sav->phy_analogoverval); + b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl); + b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval); + b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E); + b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); + } + if (b43_has_hardware_pctl(phy)) { + tmp = (sav->phy_lo_mask & 0xBFFF); + b43_phy_write(dev, B43_PHY_LO_MASK, tmp); + b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); + b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl); + b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14); + b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); + } + b43_radio_selectchannel(dev, sav->old_channel, 1); +} + +struct b43_lo_g_statemachine { + int current_state; + int nr_measured; + int state_val_multiplier; + u16 lowest_feedth; + struct b43_loctl min_loctl; +}; + +/* Loop over each possible value in this state. */ +static int lo_probe_possible_loctls(struct b43_wldev *dev, + struct b43_loctl *probe_loctl, + struct b43_lo_g_statemachine *d) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_loctl test_loctl; + struct b43_loctl orig_loctl; + struct b43_loctl prev_loctl = { + .i = -100, + .q = -100, + }; + int i; + int begin, end; + int found_lower = 0; + u16 feedth; + + static const struct b43_loctl modifiers[] = { + {.i = 1,.q = 1,}, + {.i = 1,.q = 0,}, + {.i = 1,.q = -1,}, + {.i = 0,.q = -1,}, + {.i = -1,.q = -1,}, + {.i = -1,.q = 0,}, + {.i = -1,.q = 1,}, + {.i = 0,.q = 1,}, + }; + + if (d->current_state == 0) { + begin = 1; + end = 8; + } else if (d->current_state % 2 == 0) { + begin = d->current_state - 1; + end = d->current_state + 1; + } else { + begin = d->current_state - 2; + end = d->current_state + 2; + } + if (begin < 1) + begin += 8; + if (end > 8) + end -= 8; + + memcpy(&orig_loctl, probe_loctl, sizeof(struct b43_loctl)); + i = begin; + d->current_state = i; + while (1) { + B43_WARN_ON(!(i >= 1 && i <= 8)); + memcpy(&test_loctl, &orig_loctl, sizeof(struct b43_loctl)); + test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier; + test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier; + if ((test_loctl.i != prev_loctl.i || + test_loctl.q != prev_loctl.q) && + (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) { + b43_lo_write(dev, &test_loctl); + feedth = lo_measure_feedthrough(dev, phy->lna_gain, + phy->pga_gain, + phy->trsw_rx_gain); + if (feedth < d->lowest_feedth) { + memcpy(probe_loctl, &test_loctl, + sizeof(struct b43_loctl)); + found_lower = 1; + d->lowest_feedth = feedth; + if ((d->nr_measured < 2) && + (!has_loopback_gain(phy) || lo->rebuild)) + break; + } + } + memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl)); + if (i == end) + break; + if (i == 8) + i = 1; + else + i++; + d->current_state = i; + } + + return found_lower; +} + +static void lo_probe_loctls_statemachine(struct b43_wldev *dev, + struct b43_loctl *loctl, + int *max_rx_gain) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_lo_g_statemachine d; + u16 feedth; + int found_lower; + struct b43_loctl probe_loctl; + int max_repeat = 1, repeat_cnt = 0; + + d.nr_measured = 0; + d.state_val_multiplier = 1; + if (has_loopback_gain(phy) && !lo->rebuild) + d.state_val_multiplier = 3; + + memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); + if (has_loopback_gain(phy) && lo->rebuild) + max_repeat = 4; + do { + b43_lo_write(dev, &d.min_loctl); + feedth = lo_measure_feedthrough(dev, phy->lna_gain, + phy->pga_gain, + phy->trsw_rx_gain); + if (!lo->rebuild && feedth < 0x258) { + if (feedth >= 0x12C) + *max_rx_gain += 6; + else + *max_rx_gain += 3; + feedth = lo_measure_feedthrough(dev, phy->lna_gain, + phy->pga_gain, + phy->trsw_rx_gain); + } + d.lowest_feedth = feedth; + + d.current_state = 0; + do { + B43_WARN_ON(! + (d.current_state >= 0 + && d.current_state <= 8)); + memcpy(&probe_loctl, &d.min_loctl, + sizeof(struct b43_loctl)); + found_lower = + lo_probe_possible_loctls(dev, &probe_loctl, &d); + if (!found_lower) + break; + if ((probe_loctl.i == d.min_loctl.i) && + (probe_loctl.q == d.min_loctl.q)) + break; + memcpy(&d.min_loctl, &probe_loctl, + sizeof(struct b43_loctl)); + d.nr_measured++; + } while (d.nr_measured < 24); + memcpy(loctl, &d.min_loctl, sizeof(struct b43_loctl)); + + if (has_loopback_gain(phy)) { + if (d.lowest_feedth > 0x1194) + *max_rx_gain -= 6; + else if (d.lowest_feedth < 0x5DC) + *max_rx_gain += 3; + if (repeat_cnt == 0) { + if (d.lowest_feedth <= 0x5DC) { + d.state_val_multiplier = 1; + repeat_cnt++; + } else + d.state_val_multiplier = 2; + } else if (repeat_cnt == 2) + d.state_val_multiplier = 1; + } + lo_measure_gain_values(dev, *max_rx_gain, + has_loopback_gain(phy)); + } while (++repeat_cnt < max_repeat); +} + +#if B43_CALIB_ALL_LOCTLS +static const struct b43_rfatt b43_full_rfatt_list_items[] = { + { .att = 0, .with_padmix = 0, }, + { .att = 1, .with_padmix = 0, }, + { .att = 2, .with_padmix = 0, }, + { .att = 3, .with_padmix = 0, }, + { .att = 4, .with_padmix = 0, }, + { .att = 5, .with_padmix = 0, }, + { .att = 6, .with_padmix = 0, }, + { .att = 7, .with_padmix = 0, }, + { .att = 8, .with_padmix = 0, }, + { .att = 9, .with_padmix = 0, }, + { .att = 10, .with_padmix = 0, }, + { .att = 11, .with_padmix = 0, }, + { .att = 12, .with_padmix = 0, }, + { .att = 13, .with_padmix = 0, }, + { .att = 14, .with_padmix = 0, }, + { .att = 15, .with_padmix = 0, }, + { .att = 0, .with_padmix = 1, }, + { .att = 1, .with_padmix = 1, }, + { .att = 2, .with_padmix = 1, }, + { .att = 3, .with_padmix = 1, }, + { .att = 4, .with_padmix = 1, }, + { .att = 5, .with_padmix = 1, }, + { .att = 6, .with_padmix = 1, }, + { .att = 7, .with_padmix = 1, }, + { .att = 8, .with_padmix = 1, }, + { .att = 9, .with_padmix = 1, }, + { .att = 10, .with_padmix = 1, }, + { .att = 11, .with_padmix = 1, }, + { .att = 12, .with_padmix = 1, }, + { .att = 13, .with_padmix = 1, }, + { .att = 14, .with_padmix = 1, }, + { .att = 15, .with_padmix = 1, }, +}; +static const struct b43_rfatt_list b43_full_rfatt_list = { + .list = b43_full_rfatt_list_items, + .len = ARRAY_SIZE(b43_full_rfatt_list_items), +}; + +static const struct b43_bbatt b43_full_bbatt_list_items[] = { + { .att = 0, }, + { .att = 1, }, + { .att = 2, }, + { .att = 3, }, + { .att = 4, }, + { .att = 5, }, + { .att = 6, }, + { .att = 7, }, + { .att = 8, }, + { .att = 9, }, + { .att = 10, }, + { .att = 11, }, +}; +static const struct b43_bbatt_list b43_full_bbatt_list = { + .list = b43_full_bbatt_list_items, + .len = ARRAY_SIZE(b43_full_bbatt_list_items), +}; +#endif /* B43_CALIB_ALL_LOCTLS */ + +static void lo_measure(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_loctl loctl = { + .i = 0, + .q = 0, + }; + struct b43_loctl *ploctl; + int max_rx_gain; + int rfidx, bbidx; + const struct b43_bbatt_list *bbatt_list; + const struct b43_rfatt_list *rfatt_list; + + /* Values from the "TXCTL Register and Value Table" */ + u16 txctl_reg; + u16 txctl_value; + u16 pad_mix_gain; + + bbatt_list = &lo->bbatt_list; + rfatt_list = &lo->rfatt_list; +#if B43_CALIB_ALL_LOCTLS + bbatt_list = &b43_full_bbatt_list; + rfatt_list = &b43_full_rfatt_list; +#endif + + txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); + + for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) { + + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | + rfatt_list->list[rfidx].att); + b43_radio_write16(dev, txctl_reg, + (b43_radio_read16(dev, txctl_reg) + & ~txctl_value) + | (rfatt_list->list[rfidx].with_padmix ? + txctl_value : 0)); + + for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) { + if (lo->rebuild) { +#if B43_CALIB_ALL_LOCTLS + ploctl = b43_get_lo_g_ctl(dev, + &rfatt_list->list[rfidx], + &bbatt_list->list[bbidx]); +#else + ploctl = b43_get_lo_g_ctl_nopadmix(dev, + &rfatt_list-> + list[rfidx], + &bbatt_list-> + list[bbidx]); +#endif + } else { + ploctl = b43_get_lo_g_ctl(dev, + &rfatt_list->list[rfidx], + &bbatt_list->list[bbidx]); + if (!ploctl->used) + continue; + } + memcpy(&loctl, ploctl, sizeof(loctl)); + loctl.i = 0; + loctl.q = 0; + + max_rx_gain = rfatt_list->list[rfidx].att * 2; + max_rx_gain += bbatt_list->list[bbidx].att / 2; + if (rfatt_list->list[rfidx].with_padmix) + max_rx_gain -= pad_mix_gain; + if (has_loopback_gain(phy)) + max_rx_gain += phy->max_lb_gain; + lo_measure_gain_values(dev, max_rx_gain, + has_loopback_gain(phy)); + + b43_phy_set_baseband_attenuation(dev, + bbatt_list->list[bbidx].att); + lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); + if (phy->type == B43_PHYTYPE_B) { + loctl.i++; + loctl.q++; + } + b43_loctl_set_calibrated(&loctl, 1); + memcpy(ploctl, &loctl, sizeof(loctl)); + } + } +} + +#if B43_DEBUG +static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control) +{ + const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT); + int i = control->i; + int q = control->q; + + if (b43_loctl_is_calibrated(control)) { + if ((abs(i) > 16) || (abs(q) > 16)) + goto error; + } else { + if (control->used) + goto error; + if (dev->phy.lo_control->rebuild) { + control->i = 0; + control->q = 0; + if ((i != B43_LOCTL_POISON) || + (q != B43_LOCTL_POISON)) + goto error; + } + } + if (is_initializing && control->used) + goto error; + + return; +error: + b43err(dev->wl, "LO control pair validation failed " + "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n", + i, q, control->used, + b43_loctl_is_calibrated(control), + is_initializing); +} + +static void validate_all_loctls(struct b43_wldev *dev) +{ + b43_call_for_each_loctl(dev, do_validate_loctl); +} + +static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control) +{ + if (dev->phy.lo_control->rebuild || + control->used) { + b43_loctl_set_calibrated(control, 0); + control->i = B43_LOCTL_POISON; + control->q = B43_LOCTL_POISON; + } +} + +static void reset_all_loctl_calibration_states(struct b43_wldev *dev) +{ + b43_call_for_each_loctl(dev, do_reset_calib); +} + +#else /* B43_DEBUG */ +static inline void validate_all_loctls(struct b43_wldev *dev) { } +static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { } +#endif /* B43_DEBUG */ + +void b43_lo_g_measure(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct lo_g_saved_values uninitialized_var(sav); + + B43_WARN_ON((phy->type != B43_PHYTYPE_B) && + (phy->type != B43_PHYTYPE_G)); + + sav.old_channel = phy->channel; + lo_measure_setup(dev, &sav); + reset_all_loctl_calibration_states(dev); + lo_measure(dev); + lo_measure_restore(dev, &sav); + + validate_all_loctls(dev); + + phy->lo_control->lo_measured = 1; + phy->lo_control->rebuild = 0; +} + +#if B43_DEBUG +static void validate_loctl_calibration(struct b43_wldev *dev, + struct b43_loctl *loctl, + struct b43_rfatt *rfatt, + struct b43_bbatt *bbatt) +{ + if (b43_loctl_is_calibrated(loctl)) + return; + if (!dev->phy.lo_control->lo_measured) { + /* On init we set the attenuation values before we + * calibrated the LO. I guess that's OK. */ + return; + } + b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated " + "control pair: rfatt=%u,%spadmix bbatt=%u\n", + rfatt->att, + (rfatt->with_padmix) ? "" : "no-", + bbatt->att); +} +#else +static inline void validate_loctl_calibration(struct b43_wldev *dev, + struct b43_loctl *loctl, + struct b43_rfatt *rfatt, + struct b43_bbatt *bbatt) +{ +} +#endif + +static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf, + u8 tx_control) +{ + if (tx_control & B43_TXCTL_TXMIX) { + if (rf->att < 5) + rf->att = 4; + } +} + +void b43_lo_g_adjust(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_rfatt rf; + struct b43_loctl *loctl; + + memcpy(&rf, &phy->rfatt, sizeof(rf)); + fixup_rfatt_for_txcontrol(&rf, phy->tx_control); + + loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt); + validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt); + b43_lo_write(dev, loctl); +} + +void b43_lo_g_adjust_to(struct b43_wldev *dev, + u16 rfatt, u16 bbatt, u16 tx_control) +{ + struct b43_rfatt rf; + struct b43_bbatt bb; + struct b43_loctl *loctl; + + memset(&rf, 0, sizeof(rf)); + memset(&bb, 0, sizeof(bb)); + rf.att = rfatt; + bb.att = bbatt; + fixup_rfatt_for_txcontrol(&rf, tx_control); + loctl = b43_get_lo_g_ctl(dev, &rf, &bb); + validate_loctl_calibration(dev, loctl, &rf, &bb); + b43_lo_write(dev, loctl); +} + +static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control) +{ + control->used = 0; +} + +void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + + b43_call_for_each_loctl(dev, do_mark_unused); + lo->rebuild = 1; +} + +void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_rfatt rf; + + memcpy(&rf, &phy->rfatt, sizeof(rf)); + fixup_rfatt_for_txcontrol(&rf, phy->tx_control); + + b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1; +} diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h new file mode 100644 index 000000000000..455615d1f8c6 --- /dev/null +++ b/drivers/net/wireless/b43/lo.h @@ -0,0 +1,112 @@ +#ifndef B43_LO_H_ +#define B43_LO_H_ + +#include "phy.h" + +struct b43_wldev; + +/* Local Oscillator control value-pair. */ +struct b43_loctl { + /* Control values. */ + s8 i; + s8 q; + /* "Used by hardware" flag. */ + bool used; +#ifdef CONFIG_B43_DEBUG + /* Is this lo-control-array entry calibrated? */ + bool calibrated; +#endif +}; + +/* Debugging: Poison value for i and q values. */ +#define B43_LOCTL_POISON 111 + +/* loctl->calibrated debugging mechanism */ +#ifdef CONFIG_B43_DEBUG +static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, + bool calibrated) +{ + loctl->calibrated = calibrated; +} +static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) +{ + return loctl->calibrated; +} +#else +static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, + bool calibrated) +{ +} +static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) +{ + return 1; +} +#endif + +/* TX Power LO Control Array. + * Value-pairs to adjust the LocalOscillator are stored + * in this structure. + * There are two different set of values. One for "Flag is Set" + * and one for "Flag is Unset". + * By "Flag" the flag in struct b43_rfatt is meant. + * The Value arrays are two-dimensional. The first index + * is the baseband attenuation and the second index + * is the radio attenuation. + * Use b43_get_lo_g_ctl() to retrieve a value from the lists. + */ +struct b43_txpower_lo_control { +#define B43_NR_BB 12 +#define B43_NR_RF 16 + /* LO Control values, with PAD Mixer */ + struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF]; + /* LO Control values, without PAD Mixer */ + struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF]; + + /* Flag to indicate a complete rebuild of the two tables above + * to the LO measuring code. */ + bool rebuild; + + /* Lists of valid RF and BB attenuation values for this device. */ + struct b43_rfatt_list rfatt_list; + struct b43_bbatt_list bbatt_list; + + /* Current TX Bias value */ + u8 tx_bias; + /* Current TX Magnification Value (if used by the device) */ + u8 tx_magn; + + /* GPHY LO is measured. */ + bool lo_measured; + + /* Saved device PowerVector */ + u64 power_vector; +}; + +/* Measure the BPHY Local Oscillator. */ +void b43_lo_b_measure(struct b43_wldev *dev); +/* Measure the BPHY/GPHY Local Oscillator. */ +void b43_lo_g_measure(struct b43_wldev *dev); + +/* Adjust the Local Oscillator to the saved attenuation + * and txctl values. + */ +void b43_lo_g_adjust(struct b43_wldev *dev); +/* Adjust to specific values. */ +void b43_lo_g_adjust_to(struct b43_wldev *dev, + u16 rfatt, u16 bbatt, u16 tx_control); + +/* Mark all possible b43_lo_g_ctl as "unused" */ +void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev); +/* Mark the b43_lo_g_ctl corresponding to the current + * attenuation values as used. + */ +void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev); + +/* Get a reference to a LO Control value pair in the + * TX Power LO Control Array. + */ +struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, + const struct b43_rfatt *rfatt, + const struct b43_bbatt *bbatt); + +#endif /* B43_LO_H_ */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c new file mode 100644 index 000000000000..184ebe3ed738 --- /dev/null +++ b/drivers/net/wireless/b43/main.c @@ -0,0 +1,4091 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer + Copyright (c) 2005 Stefano Brivio + Copyright (c) 2005, 2006 Michael Buesch + Copyright (c) 2005 Danny van Dyk + Copyright (c) 2005 Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b43.h" +#include "main.h" +#include "debugfs.h" +#include "phy.h" +#include "dma.h" +#include "pio.h" +#include "sysfs.h" +#include "xmit.h" +#include "sysfs.h" +#include "lo.h" +#include "pcmcia.h" + +MODULE_DESCRIPTION("Broadcom B43 wireless driver"); +MODULE_AUTHOR("Martin Langer"); +MODULE_AUTHOR("Stefano Brivio"); +MODULE_AUTHOR("Michael Buesch"); +MODULE_LICENSE("GPL"); + +extern char *nvram_get(char *name); + +#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO) +static int modparam_pio; +module_param_named(pio, modparam_pio, int, 0444); +MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); +#elif defined(CONFIG_B43_DMA) +# define modparam_pio 0 +#elif defined(CONFIG_B43_PIO) +# define modparam_pio 1 +#endif + +static int modparam_bad_frames_preempt; +module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); +MODULE_PARM_DESC(bad_frames_preempt, + "enable(1) / disable(0) Bad Frames Preemption"); + +static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT; +module_param_named(short_retry, modparam_short_retry, int, 0444); +MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); + +static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT; +module_param_named(long_retry, modparam_long_retry, int, 0444); +MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); + +static int modparam_noleds; +module_param_named(noleds, modparam_noleds, int, 0444); +MODULE_PARM_DESC(noleds, "Turn off all LED activity"); + +static char modparam_fwpostfix[16]; +module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); +MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); + +static int modparam_mon_keep_bad; +module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); +MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); + +static int modparam_mon_keep_badplcp; +module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); +MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); + +static int modparam_hwpctl; +module_param_named(hwpctl, modparam_hwpctl, int, 0444); +MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)"); + +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +static const struct ssb_device_id b43_ssb_tbl[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), + SSB_DEVTABLE_END +}; + +MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl); + +/* Channel and ratetables are shared for all devices. + * They can't be const, because ieee80211 puts some precalculated + * data in there. This data is the same for all devices, so we don't + * get concurrency issues */ +#define RATETAB_ENT(_rateid, _flags) \ + { \ + .rate = B43_RATE_TO_BASE100KBPS(_rateid), \ + .val = (_rateid), \ + .val2 = (_rateid), \ + .flags = (_flags), \ + } +static struct ieee80211_rate __b43_ratetable[] = { + RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK), + RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), +}; + +#define b43_a_ratetable (__b43_ratetable + 4) +#define b43_a_ratetable_size 8 +#define b43_b_ratetable (__b43_ratetable + 0) +#define b43_b_ratetable_size 4 +#define b43_g_ratetable (__b43_ratetable + 0) +#define b43_g_ratetable_size 12 + +#define CHANTAB_ENT(_chanid, _freq) \ + { \ + .chan = (_chanid), \ + .freq = (_freq), \ + .val = (_chanid), \ + .flag = IEEE80211_CHAN_W_SCAN | \ + IEEE80211_CHAN_W_ACTIVE_SCAN | \ + IEEE80211_CHAN_W_IBSS, \ + .power_level = 0xFF, \ + .antenna_max = 0xFF, \ + } +static struct ieee80211_channel b43_bg_chantable[] = { + CHANTAB_ENT(1, 2412), + CHANTAB_ENT(2, 2417), + CHANTAB_ENT(3, 2422), + CHANTAB_ENT(4, 2427), + CHANTAB_ENT(5, 2432), + CHANTAB_ENT(6, 2437), + CHANTAB_ENT(7, 2442), + CHANTAB_ENT(8, 2447), + CHANTAB_ENT(9, 2452), + CHANTAB_ENT(10, 2457), + CHANTAB_ENT(11, 2462), + CHANTAB_ENT(12, 2467), + CHANTAB_ENT(13, 2472), + CHANTAB_ENT(14, 2484), +}; + +#define b43_bg_chantable_size ARRAY_SIZE(b43_bg_chantable) +static struct ieee80211_channel b43_a_chantable[] = { + CHANTAB_ENT(36, 5180), + CHANTAB_ENT(40, 5200), + CHANTAB_ENT(44, 5220), + CHANTAB_ENT(48, 5240), + CHANTAB_ENT(52, 5260), + CHANTAB_ENT(56, 5280), + CHANTAB_ENT(60, 5300), + CHANTAB_ENT(64, 5320), + CHANTAB_ENT(149, 5745), + CHANTAB_ENT(153, 5765), + CHANTAB_ENT(157, 5785), + CHANTAB_ENT(161, 5805), + CHANTAB_ENT(165, 5825), +}; + +#define b43_a_chantable_size ARRAY_SIZE(b43_a_chantable) + +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 int b43_wireless_core_start(struct b43_wldev *dev); + +static int b43_ratelimit(struct b43_wl *wl) +{ + if (!wl || !wl->current_dev) + return 1; + if (b43_status(wl->current_dev) < B43_STAT_STARTED) + return 1; + /* We are up and running. + * Ratelimit the messages to avoid DoS over the net. */ + return net_ratelimit(); +} + +void b43info(struct b43_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_INFO "b43-%s: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +void b43err(struct b43_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_ERR "b43-%s ERROR: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +void b43warn(struct b43_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_WARNING "b43-%s warning: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +#if B43_DEBUG +void b43dbg(struct b43_wl *wl, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "b43-%s debug: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} +#endif /* DEBUG */ + +static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val) +{ + u32 macctl; + + B43_WARN_ON(offset % 4 != 0); + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + if (macctl & B43_MACCTL_BE) + val = swab32(val); + + b43_write32(dev, B43_MMIO_RAM_CONTROL, offset); + mmiowb(); + b43_write32(dev, B43_MMIO_RAM_DATA, val); +} + +static inline + void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset) +{ + u32 control; + + /* "offset" is the WORD offset. */ + + control = routing; + control <<= 16; + control |= offset; + b43_write32(dev, B43_MMIO_SHM_CONTROL, control); +} + +u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) +{ + u32 ret; + + if (routing == B43_SHM_SHARED) { + B43_WARN_ON(offset & 0x0001); + if (offset & 0x0003) { + /* 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); + + return ret; + } + offset >>= 2; + } + b43_shm_control_word(dev, routing, offset); + ret = b43_read32(dev, B43_MMIO_SHM_DATA); + + return ret; +} + +u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) +{ + u16 ret; + + if (routing == B43_SHM_SHARED) { + B43_WARN_ON(offset & 0x0001); + if (offset & 0x0003) { + /* Unaligned access */ + b43_shm_control_word(dev, routing, offset >> 2); + ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); + + return ret; + } + offset >>= 2; + } + b43_shm_control_word(dev, routing, offset); + ret = b43_read16(dev, B43_MMIO_SHM_DATA); + + return ret; +} + +void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +{ + if (routing == B43_SHM_SHARED) { + B43_WARN_ON(offset & 0x0001); + if (offset & 0x0003) { + /* Unaligned access */ + b43_shm_control_word(dev, routing, offset >> 2); + mmiowb(); + b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, + (value >> 16) & 0xffff); + mmiowb(); + b43_shm_control_word(dev, routing, (offset >> 2) + 1); + mmiowb(); + b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); + return; + } + offset >>= 2; + } + b43_shm_control_word(dev, routing, offset); + mmiowb(); + b43_write32(dev, B43_MMIO_SHM_DATA, 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); + if (offset & 0x0003) { + /* Unaligned access */ + b43_shm_control_word(dev, routing, offset >> 2); + mmiowb(); + b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value); + return; + } + offset >>= 2; + } + b43_shm_control_word(dev, routing, offset); + mmiowb(); + b43_write16(dev, B43_MMIO_SHM_DATA, value); +} + +/* Read HostFlags */ +u32 b43_hf_read(struct b43_wldev * dev) +{ + u32 ret; + + ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI); + ret <<= 16; + ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO); + + return ret; +} + +/* Write HostFlags */ +void b43_hf_write(struct b43_wldev *dev, u32 value) +{ + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF)); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16)); +} + +void b43_tsf_read(struct b43_wldev *dev, u64 * tsf) +{ + /* We need to be careful. As we read the TSF from multiple + * registers, we should take care of register overflows. + * In theory, the whole tsf read process should be atomic. + * We try to be atomic here, by restaring the read process, + * if any of the high registers changed (overflew). + */ + if (dev->dev->id.revision >= 3) { + u32 low, high, high2; + + do { + high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH); + low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW); + high2 = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH); + } while (unlikely(high != high2)); + + *tsf = high; + *tsf <<= 32; + *tsf |= low; + } else { + u64 tmp; + u16 v0, v1, v2, v3; + u16 test1, test2, test3; + + do { + v3 = b43_read16(dev, B43_MMIO_TSF_3); + v2 = b43_read16(dev, B43_MMIO_TSF_2); + v1 = b43_read16(dev, B43_MMIO_TSF_1); + v0 = b43_read16(dev, B43_MMIO_TSF_0); + + test3 = b43_read16(dev, B43_MMIO_TSF_3); + test2 = b43_read16(dev, B43_MMIO_TSF_2); + test1 = b43_read16(dev, B43_MMIO_TSF_1); + } while (v3 != test3 || v2 != test2 || v1 != test1); + + *tsf = v3; + *tsf <<= 48; + tmp = v2; + tmp <<= 32; + *tsf |= tmp; + tmp = v1; + tmp <<= 16; + *tsf |= tmp; + *tsf |= v0; + } +} + +static void b43_time_lock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl |= B43_MACCTL_TBTTHOLD; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write */ + b43_read32(dev, B43_MMIO_MACCTL); +} + +static void b43_time_unlock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_TBTTHOLD; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write */ + b43_read32(dev, B43_MMIO_MACCTL); +} + +static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf) +{ + /* Be careful with the in-progress timer. + * First zero out the low register, so we have a full + * register-overflow duration to complete the operation. + */ + if (dev->dev->id.revision >= 3) { + u32 lo = (tsf & 0x00000000FFFFFFFFULL); + u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; + + b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, 0); + mmiowb(); + b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, hi); + mmiowb(); + b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, lo); + } else { + u16 v0 = (tsf & 0x000000000000FFFFULL); + u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; + u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; + u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; + + b43_write16(dev, B43_MMIO_TSF_0, 0); + mmiowb(); + b43_write16(dev, B43_MMIO_TSF_3, v3); + mmiowb(); + b43_write16(dev, B43_MMIO_TSF_2, v2); + mmiowb(); + b43_write16(dev, B43_MMIO_TSF_1, v1); + mmiowb(); + b43_write16(dev, B43_MMIO_TSF_0, v0); + } +} + +void b43_tsf_write(struct b43_wldev *dev, u64 tsf) +{ + b43_time_lock(dev); + b43_tsf_write_locked(dev, tsf); + b43_time_unlock(dev); +} + +static +void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac) +{ + static const u8 zero_addr[ETH_ALEN] = { 0 }; + u16 data; + + if (!mac) + mac = zero_addr; + + offset |= 0x0020; + b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset); + + data = mac[0]; + data |= mac[1] << 8; + b43_write16(dev, B43_MMIO_MACFILTER_DATA, data); + data = mac[2]; + data |= mac[3] << 8; + b43_write16(dev, B43_MMIO_MACFILTER_DATA, data); + data = mac[4]; + data |= mac[5] << 8; + b43_write16(dev, B43_MMIO_MACFILTER_DATA, data); +} + +static void b43_write_mac_bssid_templates(struct b43_wldev *dev) +{ + const u8 *mac; + const u8 *bssid; + u8 mac_bssid[ETH_ALEN * 2]; + int i; + u32 tmp; + + bssid = dev->wl->bssid; + mac = dev->wl->mac_addr; + + b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid); + + memcpy(mac_bssid, mac, ETH_ALEN); + memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); + + /* Write our MAC address and BSSID to template ram */ + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) { + tmp = (u32) (mac_bssid[i + 0]); + tmp |= (u32) (mac_bssid[i + 1]) << 8; + tmp |= (u32) (mac_bssid[i + 2]) << 16; + tmp |= (u32) (mac_bssid[i + 3]) << 24; + b43_ram_write(dev, 0x20 + i, tmp); + } +} + +static void b43_upload_card_macaddress(struct b43_wldev *dev, + const u8 * mac_addr) +{ + if (mac_addr) + memcpy(dev->wl->mac_addr, mac_addr, ETH_ALEN); + else + memset(dev->wl->mac_addr, 0, ETH_ALEN); + b43_write_mac_bssid_templates(dev); + b43_macfilter_set(dev, B43_MACFILTER_SELF, mac_addr); +} + +static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) +{ + /* slot_time is in usec. */ + if (dev->phy.type != B43_PHYTYPE_G) + return; + b43_write16(dev, 0x684, 510 + slot_time); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time); +} + +static void b43_short_slot_timing_enable(struct b43_wldev *dev) +{ + b43_set_slot_time(dev, 9); + dev->short_slot = 1; +} + +static void b43_short_slot_timing_disable(struct b43_wldev *dev) +{ + b43_set_slot_time(dev, 20); + dev->short_slot = 0; +} + +/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask) +{ + u32 old_mask; + + old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask); + + return old_mask; +} + +/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask) +{ + u32 old_mask; + + old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask); + + return old_mask; +} + +/* 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-specs.sipsolutions.net/DummyTransmission + */ +void b43_dummy_transmission(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + unsigned int i, max_loop; + u16 value; + u32 buffer[5] = { + 0x00000000, + 0x00D40000, + 0x00000000, + 0x01000000, + 0x00000000, + }; + + switch (phy->type) { + case B43_PHYTYPE_A: + max_loop = 0x1E; + buffer[0] = 0x000201CC; + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + max_loop = 0xFA; + buffer[0] = 0x000B846E; + break; + default: + B43_WARN_ON(1); + return; + } + + 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); + b43_write16(dev, 0x050C, value); + 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 (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) + b43_radio_write16(dev, 0x0051, 0x0017); + for (i = 0x00; i < max_loop; i++) { + value = b43_read16(dev, 0x050E); + if (value & 0x0080) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = b43_read16(dev, 0x050E); + if (value & 0x0400) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = b43_read16(dev, 0x0690); + if (!(value & 0x0100)) + break; + udelay(10); + } + if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) + b43_radio_write16(dev, 0x0051, 0x0037); +} + +static void key_write(struct b43_wldev *dev, + u8 index, u8 algorithm, const u8 * key) +{ + unsigned int i; + u32 offset; + u16 value; + u16 kidx; + + /* Key index/algo block */ + kidx = b43_kidx_to_fw(dev, index); + value = ((kidx << 4) | algorithm); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value); + + /* Write the key to the Key Table Pointer offset */ + offset = dev->ktp + (index * B43_SEC_KEYSIZE); + for (i = 0; i < B43_SEC_KEYSIZE; i += 2) { + value = key[i]; + value |= (u16) (key[i + 1]) << 8; + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value); + } +} + +static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr) +{ + u32 addrtmp[2] = { 0, 0, }; + u8 per_sta_keys_start = 8; + + if (b43_new_kidx_api(dev)) + per_sta_keys_start = 4; + + B43_WARN_ON(index < per_sta_keys_start); + /* We have two default TX keys and possibly two 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; + + if (addr) { + addrtmp[0] = addr[0]; + addrtmp[0] |= ((u32) (addr[1]) << 8); + addrtmp[0] |= ((u32) (addr[2]) << 16); + addrtmp[0] |= ((u32) (addr[3]) << 24); + addrtmp[1] = addr[4]; + 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]); + } + } +} + +static void do_key_write(struct b43_wldev *dev, + u8 index, u8 algorithm, + const u8 * key, size_t key_len, const u8 * mac_addr) +{ + u8 buf[B43_SEC_KEYSIZE] = { 0, }; + u8 per_sta_keys_start = 8; + + if (b43_new_kidx_api(dev)) + per_sta_keys_start = 4; + + B43_WARN_ON(index >= dev->max_nr_keys); + B43_WARN_ON(key_len > B43_SEC_KEYSIZE); + + if (index >= per_sta_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) + keymac_write(dev, index, mac_addr); + + dev->key[index].algorithm = algorithm; +} + +static int b43_key_write(struct b43_wldev *dev, + int index, u8 algorithm, + const u8 * key, size_t key_len, + const u8 * mac_addr, + struct ieee80211_key_conf *keyconf) +{ + int i; + int sta_keys_start; + + if (key_len > B43_SEC_KEYSIZE) + return -EINVAL; + for (i = 0; i < dev->max_nr_keys; i++) { + /* Check that we don't already have this key. */ + B43_WARN_ON(dev->key[i].keyconf == keyconf); + } + if (index < 0) { + /* Either pairwise key or address is 00:00:00:00:00:00 + * for transmit-only keys. Search the index. */ + if (b43_new_kidx_api(dev)) + sta_keys_start = 4; + else + sta_keys_start = 8; + for (i = sta_keys_start; i < dev->max_nr_keys; i++) { + if (!dev->key[i].keyconf) { + /* found empty */ + index = i; + break; + } + } + if (index < 0) { + b43err(dev->wl, "Out of hardware key memory\n"); + return -ENOSPC; + } + } else + B43_WARN_ON(index > 3); + + do_key_write(dev, index, algorithm, key, key_len, mac_addr); + if ((index <= 3) && !b43_new_kidx_api(dev)) { + /* Default RX key */ + B43_WARN_ON(mac_addr); + do_key_write(dev, index + 4, algorithm, key, key_len, NULL); + } + keyconf->hw_key_idx = index; + dev->key[index].keyconf = keyconf; + + return 0; +} + +static int b43_key_clear(struct b43_wldev *dev, int index) +{ + if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys))) + return -EINVAL; + do_key_write(dev, index, B43_SEC_ALGO_NONE, + NULL, B43_SEC_KEYSIZE, NULL); + if ((index <= 3) && !b43_new_kidx_api(dev)) { + do_key_write(dev, index + 4, B43_SEC_ALGO_NONE, + NULL, B43_SEC_KEYSIZE, NULL); + } + dev->key[index].keyconf = NULL; + + return 0; +} + +static void b43_clear_keys(struct b43_wldev *dev) +{ + int i; + + for (i = 0; i < dev->max_nr_keys; i++) + b43_key_clear(dev, i); +} + +void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) +{ + u32 macctl; + u16 ucstat; + bool hwps; + bool awake; + int i; + + B43_WARN_ON((ps_flags & B43_PS_ENABLED) && + (ps_flags & B43_PS_DISABLED)); + B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP)); + + if (ps_flags & B43_PS_ENABLED) { + hwps = 1; + } else if (ps_flags & B43_PS_DISABLED) { + hwps = 0; + } else { + //TODO: If powersave is not off and FIXME is not set and we are not in adhoc + // and thus is not an AP and we are associated, set bit 25 + } + if (ps_flags & B43_PS_AWAKE) { + awake = 1; + } else if (ps_flags & B43_PS_ASLEEP) { + awake = 0; + } else { + //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, + // or we are associated, or FIXME, or the latest PS-Poll packet sent was + // successful, set bit26 + } + +/* FIXME: For now we force awake-on and hwps-off */ + hwps = 0; + awake = 1; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + if (hwps) + macctl |= B43_MACCTL_HWPS; + else + macctl &= ~B43_MACCTL_HWPS; + if (awake) + macctl |= B43_MACCTL_AWAKE; + else + macctl &= ~B43_MACCTL_AWAKE; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit write */ + b43_read32(dev, B43_MMIO_MACCTL); + if (awake && dev->dev->id.revision >= 5) { + /* Wait for the microcode to wake up. */ + for (i = 0; i < 100; i++) { + ucstat = b43_shm_read16(dev, B43_SHM_SHARED, + B43_SHM_SH_UCODESTAT); + if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP) + break; + udelay(10); + } + } +} + +/* Turn the Analog ON/OFF */ +static void b43_switch_analog(struct b43_wldev *dev, int on) +{ + b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); +} + +void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) +{ + u32 tmslow; + u32 macctl; + + flags |= B43_TMSLOW_PHYCLKEN; + flags |= B43_TMSLOW_PHYRESET; + ssb_device_enable(dev->dev, flags); + msleep(2); /* Wait for the PLL to turn on. */ + + /* Now take the PHY out of Reset again */ + tmslow = ssb_read32(dev->dev, SSB_TMSLOW); + tmslow |= SSB_TMSLOW_FGC; + tmslow &= ~B43_TMSLOW_PHYRESET; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ + msleep(1); + tmslow &= ~SSB_TMSLOW_FGC; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ + msleep(1); + + /* Turn Analog ON */ + b43_switch_analog(dev, 1); + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_GMODE; + if (flags & B43_TMSLOW_GMODE) + macctl |= B43_MACCTL_GMODE; + macctl |= B43_MACCTL_IHR_ENABLED; + b43_write32(dev, B43_MMIO_MACCTL, macctl); +} + +static void handle_irq_transmit_status(struct b43_wldev *dev) +{ + u32 v0, v1; + u16 tmp; + struct b43_txstatus stat; + + while (1) { + v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0); + if (!(v0 & 0x00000001)) + break; + v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1); + + stat.cookie = (v0 >> 16); + stat.seq = (v1 & 0x0000FFFF); + stat.phy_stat = ((v1 & 0x00FF0000) >> 16); + tmp = (v0 & 0x0000FFFF); + stat.frame_count = ((tmp & 0xF000) >> 12); + stat.rts_count = ((tmp & 0x0F00) >> 8); + stat.supp_reason = ((tmp & 0x001C) >> 2); + stat.pm_indicated = !!(tmp & 0x0080); + stat.intermediate = !!(tmp & 0x0040); + stat.for_ampdu = !!(tmp & 0x0020); + stat.acked = !!(tmp & 0x0002); + + b43_handle_txstatus(dev, &stat); + } +} + +static void drain_txstatus_queue(struct b43_wldev *dev) +{ + u32 dummy; + + if (dev->dev->id.revision < 5) + return; + /* Read all entries from the microcode TXstatus FIFO + * and throw them away. + */ + while (1) { + dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0); + if (!(dummy & 0x00000001)) + break; + dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1); + } +} + +static u32 b43_jssi_read(struct b43_wldev *dev) +{ + u32 val = 0; + + val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A); + val <<= 16; + val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088); + + return val; +} + +static void b43_jssi_write(struct b43_wldev *dev, u32 jssi) +{ + b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF)); + b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16); +} + +static void b43_generate_noise_sample(struct b43_wldev *dev) +{ + b43_jssi_write(dev, 0x7F7F7F7F); + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, + b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) + | (1 << 4)); + B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel); +} + +static void b43_calculate_link_quality(struct b43_wldev *dev) +{ + /* Top half of Link Quality calculation. */ + + if (dev->noisecalc.calculation_running) + return; + dev->noisecalc.channel_at_start = dev->phy.channel; + dev->noisecalc.calculation_running = 1; + dev->noisecalc.nr_samples = 0; + + b43_generate_noise_sample(dev); +} + +static void handle_irq_noise(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + u8 noise[4]; + u8 i, j; + s32 average; + + /* Bottom half of Link Quality calculation. */ + + B43_WARN_ON(!dev->noisecalc.calculation_running); + if (dev->noisecalc.channel_at_start != phy->channel) + goto drop_calculation; + *((u32 *) noise) = cpu_to_le32(b43_jssi_read(dev)); + if (noise[0] == 0x7F || noise[1] == 0x7F || + noise[2] == 0x7F || noise[3] == 0x7F) + goto generate_new; + + /* Get the noise samples. */ + B43_WARN_ON(dev->noisecalc.nr_samples >= 8); + i = dev->noisecalc.nr_samples; + noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; + dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; + dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; + dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]]; + dev->noisecalc.nr_samples++; + if (dev->noisecalc.nr_samples == 8) { + /* Calculate the Link Quality by the noise samples. */ + average = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 4; j++) + average += dev->noisecalc.samples[i][j]; + } + average /= (8 * 4); + average *= 125; + average += 64; + average /= 128; + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C); + tmp = (tmp / 128) & 0x1F; + if (tmp >= 8) + average += 2; + else + average -= 25; + if (tmp == 8) + average -= 72; + else + average -= 48; + + dev->stats.link_noise = average; + drop_calculation: + dev->noisecalc.calculation_running = 0; + return; + } + generate_new: + b43_generate_noise_sample(dev); +} + +static void handle_irq_tbtt_indication(struct b43_wldev *dev) +{ + if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + ///TODO: PS TBTT + } else { + if (1 /*FIXME: the last PSpoll frame was sent successfully */ ) + b43_power_saving_ctl_bits(dev, 0); + } + dev->reg124_set_0x4 = 0; + if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + dev->reg124_set_0x4 = 1; +} + +static void handle_irq_atim_end(struct b43_wldev *dev) +{ + if (!dev->reg124_set_0x4 /*FIXME rename this variable */ ) + return; + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, + b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) + | 0x4); +} + +static void handle_irq_pmq(struct b43_wldev *dev) +{ + u32 tmp; + + //TODO: AP mode. + + while (1) { + tmp = b43_read32(dev, B43_MMIO_PS_STATUS); + if (!(tmp & 0x00000008)) + break; + } + /* 16bit write is odd, but correct. */ + b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002); +} + +static void b43_write_template_common(struct b43_wldev *dev, + const u8 * data, u16 size, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + u32 i, tmp; + struct b43_plcp_hdr4 plcp; + + plcp.data = 0; + b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data)); + ram_offset += sizeof(u32); + /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet. + * So leave the first two bytes of the next write blank. + */ + tmp = (u32) (data[0]) << 16; + tmp |= (u32) (data[1]) << 24; + b43_ram_write(dev, ram_offset, tmp); + ram_offset += sizeof(u32); + for (i = 2; i < size; i += sizeof(u32)) { + tmp = (u32) (data[i + 0]); + if (i + 1 < size) + tmp |= (u32) (data[i + 1]) << 8; + if (i + 2 < size) + tmp |= (u32) (data[i + 2]) << 16; + if (i + 3 < size) + tmp |= (u32) (data[i + 3]) << 24; + b43_ram_write(dev, ram_offset + i - 2, tmp); + } + b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset, + size + sizeof(struct b43_plcp_hdr6)); +} + +static void b43_write_beacon_template(struct b43_wldev *dev, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + int len; + const u8 *data; + + B43_WARN_ON(!dev->cached_beacon); + len = min((size_t) dev->cached_beacon->len, + 0x200 - sizeof(struct b43_plcp_hdr6)); + data = (const u8 *)(dev->cached_beacon->data); + b43_write_template_common(dev, data, + len, ram_offset, shm_size_offset, rate); +} + +static void b43_write_probe_resp_plcp(struct b43_wldev *dev, + u16 shm_offset, u16 size, u8 rate) +{ + struct b43_plcp_hdr4 plcp; + u32 tmp; + __le16 dur; + + plcp.data = 0; + b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + dur = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, size, + B43_RATE_TO_BASE100KBPS(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 u8 *b43_generate_probe_resp(struct b43_wldev *dev, + u16 * dest_size, u8 rate) +{ + const u8 *src_data; + u8 *dest_data; + u16 src_size, elem_size, src_pos, dest_pos; + __le16 dur; + struct ieee80211_hdr *hdr; + + B43_WARN_ON(!dev->cached_beacon); + src_size = dev->cached_beacon->len; + src_data = (const u8 *)dev->cached_beacon->data; + + if (unlikely(src_size < 0x24)) { + b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n"); + return NULL; + } + + dest_data = kmalloc(src_size, GFP_ATOMIC); + if (unlikely(!dest_data)) + return NULL; + + /* 0x24 is offset of first variable-len Information-Element + * in beacon frame. + */ + memcpy(dest_data, src_data, 0x24); + src_pos = dest_pos = 0x24; + for (; src_pos < src_size - 2; src_pos += elem_size) { + elem_size = src_data[src_pos + 1] + 2; + if (src_data[src_pos] != 0x05) { /* TIM */ + 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->if_id, *dest_size, + B43_RATE_TO_BASE100KBPS(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, u8 rate) +{ + u8 *probe_resp_data; + u16 size; + + B43_WARN_ON(!dev->cached_beacon); + size = dev->cached_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 + */ + b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB); + b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB); + b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB); + b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB); + + 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); + kfree(probe_resp_data); +} + +static int b43_refresh_cached_beacon(struct b43_wldev *dev, + struct sk_buff *beacon) +{ + if (dev->cached_beacon) + kfree_skb(dev->cached_beacon); + dev->cached_beacon = beacon; + + return 0; +} + +static void b43_update_templates(struct b43_wldev *dev) +{ + u32 status; + + B43_WARN_ON(!dev->cached_beacon); + + b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); + b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); + b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB); + + status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); + status |= 0x03; + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); +} + +static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon) +{ + int err; + + err = b43_refresh_cached_beacon(dev, beacon); + if (unlikely(err)) + return; + b43_update_templates(dev); +} + +static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) +{ + u32 tmp; + u16 i, len; + + len = min((u16) ssid_len, (u16) 0x100); + for (i = 0; i < len; i += sizeof(u32)) { + tmp = (u32) (ssid[i + 0]); + if (i + 1 < len) + tmp |= (u32) (ssid[i + 1]) << 8; + if (i + 2 < len) + tmp |= (u32) (ssid[i + 2]) << 16; + if (i + 3 < len) + tmp |= (u32) (ssid[i + 3]) << 24; + b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp); + } + b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len); +} + +static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) +{ + b43_time_lock(dev); + if (dev->dev->id.revision >= 3) { + b43_write32(dev, 0x188, (beacon_int << 16)); + } else { + b43_write16(dev, 0x606, (beacon_int >> 6)); + b43_write16(dev, 0x610, beacon_int); + } + b43_time_unlock(dev); +} + +static void handle_irq_beacon(struct b43_wldev *dev) +{ + u32 status; + + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + return; + + dev->irq_savedstate &= ~B43_IRQ_BEACON; + status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); + + if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { + /* ACK beacon IRQ. */ + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); + dev->irq_savedstate |= B43_IRQ_BEACON; + if (dev->cached_beacon) + kfree_skb(dev->cached_beacon); + dev->cached_beacon = NULL; + return; + } + if (!(status & 0x1)) { + b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); + status |= 0x1; + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); + } + if (!(status & 0x2)) { + b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); + status |= 0x2; + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); + } +} + +static void handle_irq_ucode_debug(struct b43_wldev *dev) +{ + //TODO +} + +/* Interrupt handler bottom-half */ +static void b43_interrupt_tasklet(struct b43_wldev *dev) +{ + u32 reason; + u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; + u32 merged_dma_reason = 0; + int i, activity = 0; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED); + + reason = dev->irq_reason; + for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { + dma_reason[i] = dev->dma_reason[i]; + merged_dma_reason |= dma_reason[i]; + } + + if (unlikely(reason & B43_IRQ_MAC_TXERR)) + b43err(dev->wl, "MAC transmission error\n"); + + if (unlikely(reason & B43_IRQ_PHY_TXERR)) + b43err(dev->wl, "PHY transmission error\n"); + + if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK | + B43_DMAIRQ_NONFATALMASK))) { + if (merged_dma_reason & B43_DMAIRQ_FATALMASK) { + b43err(dev->wl, "Fatal DMA error: " + "0x%08X, 0x%08X, 0x%08X, " + "0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + 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) { + b43err(dev->wl, "DMA error: " + "0x%08X, 0x%08X, 0x%08X, " + "0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3], + dma_reason[4], dma_reason[5]); + } + } + + if (unlikely(reason & B43_IRQ_UCODE_DEBUG)) + handle_irq_ucode_debug(dev); + if (reason & B43_IRQ_TBTT_INDI) + handle_irq_tbtt_indication(dev); + if (reason & B43_IRQ_ATIM_END) + handle_irq_atim_end(dev); + if (reason & B43_IRQ_BEACON) + handle_irq_beacon(dev); + if (reason & B43_IRQ_PMQ) + handle_irq_pmq(dev); + if (reason & B43_IRQ_TXFIFO_FLUSH_OK) ; + /*TODO*/ if (reason & B43_IRQ_NOISESAMPLE_OK) + handle_irq_noise(dev); + + /* Check the DMA reason registers for received data. */ + if (dma_reason[0] & B43_DMAIRQ_RX_DONE) { + if (b43_using_pio(dev)) + b43_pio_rx(dev->pio.queue0); + else + b43_dma_rx(dev->dma.rx_ring0); + /* We intentionally don't set "activity" to 1, here. */ + } + B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); + B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); + if (dma_reason[3] & B43_DMAIRQ_RX_DONE) { + if (b43_using_pio(dev)) + b43_pio_rx(dev->pio.queue3); + else + b43_dma_rx(dev->dma.rx_ring3); + activity = 1; + } + B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); + B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); + + if (reason & B43_IRQ_TX_OK) { + handle_irq_transmit_status(dev); + activity = 1; + //TODO: In AP mode, this also causes sending of powersave responses. + } + + if (!modparam_noleds) + b43_leds_update(dev, activity); + b43_interrupt_enable(dev, dev->irq_savedstate); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); +} + +static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx) +{ + u16 rxctl; + + rxctl = b43_read16(dev, base + B43_PIO_RXCTL); + if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE) + dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE; + else + dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE; +} + +static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) +{ + if (b43_using_pio(dev) && + (dev->dev->id.revision < 3) && + (!(reason & B43_IRQ_PIO_WORKAROUND))) { + /* Apply a PIO specific workaround to the dma_reasons */ + pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0); + pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1); + pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2); + pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3); + } + + 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]); + b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); +} + +/* Interrupt handler top-half */ +static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) +{ + irqreturn_t ret = IRQ_NONE; + struct b43_wldev *dev = dev_id; + u32 reason; + + if (!dev) + return IRQ_NONE; + + spin_lock(&dev->wl->irq_lock); + + if (b43_status(dev) < B43_STAT_STARTED) + goto out; + reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + if (reason == 0xffffffff) /* shared IRQ */ + goto out; + ret = IRQ_HANDLED; + reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + if (!reason) + goto out; + + dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) + & 0x0001DC00; + dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON) + & 0x0000DC00; + dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON) + & 0x0000DC00; + dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON) + & 0x0001DC00; + dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON) + & 0x0000DC00; + dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON) + & 0x0000DC00; + + b43_interrupt_ack(dev, reason); + /* disable all IRQs. They are enabled again in the bottom half. */ + dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + /* save the reason code and call our bottom half. */ + dev->irq_reason = reason; + tasklet_schedule(&dev->isr_tasklet); + out: + mmiowb(); + spin_unlock(&dev->wl->irq_lock); + + return ret; +} + +static void b43_release_firmware(struct b43_wldev *dev) +{ + release_firmware(dev->fw.ucode); + dev->fw.ucode = NULL; + release_firmware(dev->fw.pcm); + dev->fw.pcm = NULL; + release_firmware(dev->fw.initvals); + dev->fw.initvals = NULL; + release_firmware(dev->fw.initvals_band); + dev->fw.initvals_band = NULL; +} + +static void b43_print_fw_helptext(struct b43_wl *wl) +{ + b43err(wl, "You must go to " + "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware " + "and download the correct firmware (version 4).\n"); +} + +static int do_request_fw(struct b43_wldev *dev, + const char *name, + const struct firmware **fw) +{ + const size_t plen = sizeof(modparam_fwpostfix) + 32; + char path[plen]; + struct b43_fw_header *hdr; + u32 size; + int err; + + if (!name) + return 0; + + snprintf(path, ARRAY_SIZE(path), + "b43%s/%s.fw", + modparam_fwpostfix, name); + err = request_firmware(fw, path, dev->dev->dev); + if (err) { + b43err(dev->wl, "Firmware file \"%s\" not found " + "or load failed.\n", path); + return err; + } + if ((*fw)->size < sizeof(struct b43_fw_header)) + goto err_format; + hdr = (struct b43_fw_header *)((*fw)->data); + switch (hdr->type) { + case B43_FW_TYPE_UCODE: + case B43_FW_TYPE_PCM: + size = be32_to_cpu(hdr->size); + if (size != (*fw)->size - sizeof(struct b43_fw_header)) + goto err_format; + /* fallthrough */ + case B43_FW_TYPE_IV: + if (hdr->ver != 1) + goto err_format; + break; + default: + goto err_format; + } + + return err; + +err_format: + b43err(dev->wl, "Firmware file \"%s\" format error.\n", path); + return -EPROTO; +} + +static int b43_request_firmware(struct b43_wldev *dev) +{ + struct b43_firmware *fw = &dev->fw; + const u8 rev = dev->dev->id.revision; + const char *filename; + u32 tmshigh; + int err; + + tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + if (!fw->ucode) { + if ((rev >= 5) && (rev <= 10)) + filename = "ucode5"; + else if ((rev >= 11) && (rev <= 12)) + filename = "ucode11"; + else if (rev >= 13) + filename = "ucode13"; + else + goto err_no_ucode; + err = do_request_fw(dev, filename, &fw->ucode); + if (err) + goto err_load; + } + if (!fw->pcm) { + if ((rev >= 5) && (rev <= 10)) + filename = "pcm5"; + else if (rev >= 11) + filename = NULL; + else + goto err_no_pcm; + err = do_request_fw(dev, filename, &fw->pcm); + if (err) + goto err_load; + } + if (!fw->initvals) { + switch (dev->phy.type) { + case B43_PHYTYPE_A: + if ((rev >= 5) && (rev <= 10)) { + if (tmshigh & B43_TMSHIGH_GPHY) + filename = "a0g1initvals5"; + else + filename = "a0g0initvals5"; + } else + goto err_no_initvals; + break; + case B43_PHYTYPE_G: + if ((rev >= 5) && (rev <= 10)) + filename = "b0g0initvals5"; + else if (rev >= 13) + filename = "lp0initvals13"; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; + } + err = do_request_fw(dev, filename, &fw->initvals); + if (err) + goto err_load; + } + if (!fw->initvals_band) { + switch (dev->phy.type) { + case B43_PHYTYPE_A: + if ((rev >= 5) && (rev <= 10)) { + if (tmshigh & B43_TMSHIGH_GPHY) + filename = "a0g1bsinitvals5"; + else + filename = "a0g0bsinitvals5"; + } else if (rev >= 11) + filename = NULL; + else + goto err_no_initvals; + break; + case B43_PHYTYPE_G: + if ((rev >= 5) && (rev <= 10)) + filename = "b0g0bsinitvals5"; + else if (rev >= 11) + filename = NULL; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; + } + err = do_request_fw(dev, filename, &fw->initvals_band); + if (err) + goto err_load; + } + + return 0; + +err_load: + b43_print_fw_helptext(dev->wl); + goto error; + +err_no_ucode: + err = -ENODEV; + b43err(dev->wl, "No microcode available for core rev %u\n", rev); + goto error; + +err_no_pcm: + err = -ENODEV; + b43err(dev->wl, "No PCM available for core rev %u\n", rev); + goto error; + +err_no_initvals: + err = -ENODEV; + b43err(dev->wl, "No Initial Values firmware file for PHY %u, " + "core rev %u\n", dev->phy.type, rev); + goto error; + +error: + b43_release_firmware(dev); + return err; +} + +static int b43_upload_microcode(struct b43_wldev *dev) +{ + const size_t hdr_len = sizeof(struct b43_fw_header); + const __be32 *data; + unsigned int i, len; + u16 fwrev, fwpatch, fwdate, fwtime; + u32 tmp; + int err = 0; + + /* Upload Microcode. */ + data = (__be32 *) (dev->fw.ucode->data + hdr_len); + len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); + b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000); + for (i = 0; i < len; i++) { + b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); + udelay(10); + } + + if (dev->fw.pcm) { + /* Upload PCM data. */ + data = (__be32 *) (dev->fw.pcm->data + hdr_len); + len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); + b43_shm_control_word(dev, B43_SHM_HW, 0x01EA); + b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000); + /* No need for autoinc bit in SHM_HW */ + b43_shm_control_word(dev, B43_SHM_HW, 0x01EB); + for (i = 0; i < len; i++) { + b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); + udelay(10); + } + } + + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL); + b43_write32(dev, B43_MMIO_MACCTL, + B43_MACCTL_PSM_RUN | + B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA); + + /* Wait for the microcode to load and respond */ + i = 0; + while (1) { + tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + if (tmp == B43_IRQ_MAC_SUSPENDED) + break; + i++; + if (i >= 50) { + b43err(dev->wl, "Microcode not responding\n"); + b43_print_fw_helptext(dev->wl); + err = -ENODEV; + goto out; + } + udelay(10); + } + b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */ + + /* Get and check the revisions. */ + fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV); + fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH); + fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE); + fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME); + + if (fwrev <= 0x128) { + b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from " + "binary drivers older than version 4.x is unsupported. " + "You must upgrade your firmware files.\n"); + b43_print_fw_helptext(dev->wl); + b43_write32(dev, B43_MMIO_MACCTL, 0); + err = -EOPNOTSUPP; + goto out; + } + b43dbg(dev->wl, "Loading firmware version %u.%u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", + fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + + dev->fw.rev = fwrev; + dev->fw.patch = fwpatch; + + out: + return err; +} + +static int b43_write_initvals(struct b43_wldev *dev, + const struct b43_iv *ivals, + size_t count, + size_t array_size) +{ + const struct b43_iv *iv; + u16 offset; + size_t i; + bool bit32; + + BUILD_BUG_ON(sizeof(struct b43_iv) != 6); + iv = ivals; + for (i = 0; i < count; i++) { + if (array_size < sizeof(iv->offset_size)) + goto err_format; + array_size -= sizeof(iv->offset_size); + offset = be16_to_cpu(iv->offset_size); + bit32 = !!(offset & B43_IV_32BIT); + offset &= B43_IV_OFFSET_MASK; + if (offset >= 0x1000) + goto err_format; + if (bit32) { + u32 value; + + if (array_size < sizeof(iv->data.d32)) + goto err_format; + array_size -= sizeof(iv->data.d32); + + value = be32_to_cpu(get_unaligned(&iv->data.d32)); + b43_write32(dev, offset, value); + + iv = (const struct b43_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be32)); + } else { + u16 value; + + if (array_size < sizeof(iv->data.d16)) + goto err_format; + array_size -= sizeof(iv->data.d16); + + value = be16_to_cpu(iv->data.d16); + b43_write16(dev, offset, value); + + iv = (const struct b43_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be16)); + } + } + if (array_size) + goto err_format; + + return 0; + +err_format: + b43err(dev->wl, "Initial Values Firmware file-format error.\n"); + b43_print_fw_helptext(dev->wl); + + return -EPROTO; +} + +static int b43_upload_initvals(struct b43_wldev *dev) +{ + const size_t hdr_len = sizeof(struct b43_fw_header); + const struct b43_fw_header *hdr; + struct b43_firmware *fw = &dev->fw; + const struct b43_iv *ivals; + size_t count; + int err; + + hdr = (const struct b43_fw_header *)(fw->initvals->data); + ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43_write_initvals(dev, ivals, count, + fw->initvals->size - hdr_len); + if (err) + goto out; + if (fw->initvals_band) { + hdr = (const struct b43_fw_header *)(fw->initvals_band->data); + ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43_write_initvals(dev, ivals, count, + fw->initvals_band->size - hdr_len); + if (err) + goto out; + } +out: + + return err; +} + +/* Initialize the GPIOs + * http://bcm-specs.sipsolutions.net/GPIO + */ +static int b43_gpio_init(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + u32 mask, set; + + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_GPOUTSMSK); + + b43_leds_switch_all(dev, 0); + b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) + | 0x000F); + + mask = 0x0000001F; + set = 0x0000000F; + if (dev->dev->bus->chip_id == 0x4301) { + mask |= 0x0060; + set |= 0x0060; + } + if (0 /* FIXME: conditional unknown */ ) { + b43_write16(dev, B43_MMIO_GPIO_MASK, + b43_read16(dev, B43_MMIO_GPIO_MASK) + | 0x0100); + mask |= 0x0180; + set |= 0x0180; + } + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) { + b43_write16(dev, B43_MMIO_GPIO_MASK, + b43_read16(dev, B43_MMIO_GPIO_MASK) + | 0x0200); + mask |= 0x0200; + set |= 0x0200; + } + if (dev->dev->id.revision >= 2) + mask |= 0x0010; /* FIXME: This is redundant. */ + +#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; +#endif + gpiodev = bus->chipco.dev ? : pcidev; + if (!gpiodev) + return 0; + ssb_write32(gpiodev, B43_GPIO_CONTROL, + (ssb_read32(gpiodev, B43_GPIO_CONTROL) + & mask) | set); + + return 0; +} + +/* Turn off all GPIO stuff. Call this on module unload, for example. */ +static void b43_gpio_cleanup(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + +#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; +#endif + gpiodev = bus->chipco.dev ? : pcidev; + if (!gpiodev) + return; + ssb_write32(gpiodev, B43_GPIO_CONTROL, 0); +} + +/* http://bcm-specs.sipsolutions.net/EnableMac */ +void b43_mac_enable(struct b43_wldev *dev) +{ + dev->mac_suspended--; + B43_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + b43_write32(dev, B43_MMIO_MACCTL, + b43_read32(dev, B43_MMIO_MACCTL) + | B43_MACCTL_ENABLED); + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, + B43_IRQ_MAC_SUSPENDED); + /* Commit writes */ + b43_read32(dev, B43_MMIO_MACCTL); + b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + b43_power_saving_ctl_bits(dev, 0); + } +} + +/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +void b43_mac_suspend(struct b43_wldev *dev) +{ + int i; + u32 tmp; + + B43_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); + b43_write32(dev, B43_MMIO_MACCTL, + b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_ENABLED); + /* force pci to flush the write */ + b43_read32(dev, B43_MMIO_MACCTL); + for (i = 10000; i; i--) { + tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + if (tmp & B43_IRQ_MAC_SUSPENDED) + goto out; + udelay(1); + } + b43err(dev->wl, "MAC suspend failed\n"); + } + out: + dev->mac_suspended++; +} + +static void b43_adjust_opmode(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + u32 ctl; + u16 cfp_pretbtt; + + ctl = b43_read32(dev, B43_MMIO_MACCTL); + /* Reset status to STA infrastructure mode. */ + ctl &= ~B43_MACCTL_AP; + ctl &= ~B43_MACCTL_KEEP_CTL; + ctl &= ~B43_MACCTL_KEEP_BADPLCP; + ctl &= ~B43_MACCTL_KEEP_BAD; + ctl &= ~B43_MACCTL_PROMISC; + ctl |= B43_MACCTL_INFRA; + + if (wl->operating) { + switch (wl->if_type) { + case IEEE80211_IF_TYPE_AP: + ctl |= B43_MACCTL_AP; + break; + case IEEE80211_IF_TYPE_IBSS: + ctl &= ~B43_MACCTL_INFRA; + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_WDS: + break; + default: + B43_WARN_ON(1); + } + } + if (wl->monitor) { + ctl |= B43_MACCTL_KEEP_CTL; + if (modparam_mon_keep_bad) + ctl |= B43_MACCTL_KEEP_BAD; + if (modparam_mon_keep_badplcp) + ctl |= B43_MACCTL_KEEP_BADPLCP; + } + if (wl->promisc) + ctl |= B43_MACCTL_PROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter + * doesn't work properly, so always run promisc in filter + * it in software. */ + if (dev->dev->id.revision <= 4) + ctl |= B43_MACCTL_PROMISC; + + b43_write32(dev, B43_MMIO_MACCTL, ctl); + + cfp_pretbtt = 2; + if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) { + if (dev->dev->bus->chip_id == 0x4306 && + dev->dev->bus->chip_rev == 3) + cfp_pretbtt = 100; + else + cfp_pretbtt = 50; + } + b43_write16(dev, 0x612, cfp_pretbtt); +} + +static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm) +{ + u16 offset; + + if (is_ofdm) { + offset = 0x480; + offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; + } else { + offset = 0x4C0; + offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2; + } + b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20, + b43_shm_read16(dev, B43_SHM_SHARED, offset)); +} + +static void b43_rate_memory_init(struct b43_wldev *dev) +{ + switch (dev->phy.type) { + case B43_PHYTYPE_A: + case B43_PHYTYPE_G: + 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); + b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1); + if (dev->phy.type == B43_PHYTYPE_A) + break; + /* fallthrough */ + case B43_PHYTYPE_B: + b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0); + b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0); + b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0); + b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0); + break; + default: + B43_WARN_ON(1); + } +} + +/* Set the TX-Antenna for management frames sent by firmware. */ +static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) +{ + u16 ant = 0; + u16 tmp; + + switch (antenna) { + case B43_ANTENNA0: + ant |= B43_TX4_PHY_ANT0; + break; + case B43_ANTENNA1: + ant |= B43_TX4_PHY_ANT1; + break; + case B43_ANTENNA_AUTO: + ant |= B43_TX4_PHY_ANTLAST; + break; + default: + B43_WARN_ON(1); + } + + /* FIXME We also need to set the other flags of the PHY control field somewhere. */ + + /* For Beacons */ + tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); + tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp); + /* For ACK/CTS */ + tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL); + tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp); + /* For Probe Resposes */ + tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL); + tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); +} + +/* This is the opposite of b43_chip_init() */ +static void b43_chip_exit(struct b43_wldev *dev) +{ + b43_radio_turn_off(dev); + if (!modparam_noleds) + b43_leds_exit(dev); + b43_gpio_cleanup(dev); + /* firmware is released later */ +} + +/* Initialize the chip + * http://bcm-specs.sipsolutions.net/ChipInit + */ +static int b43_chip_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int err, tmp; + u32 value32; + u16 value16; + + b43_write32(dev, B43_MMIO_MACCTL, + B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED); + + err = b43_request_firmware(dev); + if (err) + goto out; + err = b43_upload_microcode(dev); + if (err) + goto out; /* firmware is released later */ + + err = b43_gpio_init(dev); + if (err) + goto out; /* firmware is released later */ + err = b43_upload_initvals(dev); + if (err) + goto err_gpio_cleanup; + b43_radio_turn_on(dev); + dev->radio_hw_enable = b43_is_hw_radio_enabled(dev); + b43dbg(dev->wl, "Radio %s by hardware\n", + (dev->radio_hw_enable == 0) ? "disabled" : "enabled"); + + b43_write16(dev, 0x03E6, 0x0000); + err = b43_phy_init(dev); + if (err) + goto err_radio_off; + + /* Select initial Interference Mitigation. */ + tmp = phy->interfmode; + phy->interfmode = B43_INTERFMODE_NONE; + b43_radio_set_interference_mitigation(dev, tmp); + + b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT); + b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT); + + if (phy->type == B43_PHYTYPE_B) { + value16 = b43_read16(dev, 0x005E); + value16 |= 0x0004; + b43_write16(dev, 0x005E, value16); + } + b43_write32(dev, 0x0100, 0x01000000); + if (dev->dev->id.revision < 5) + b43_write32(dev, 0x010C, 0x01000000); + + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_INFRA); + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + | B43_MACCTL_INFRA); + /* Let beacons come through */ + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + | B43_MACCTL_BEACPROMISC); + + if (b43_using_pio(dev)) { + b43_write32(dev, 0x0210, 0x00000100); + b43_write32(dev, 0x0230, 0x00000100); + b43_write32(dev, 0x0250, 0x00000100); + b43_write32(dev, 0x0270, 0x00000100); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000); + } + + /* Probe Response Timeout value */ + /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ + b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000); + + /* Initially set the wireless operation mode. */ + b43_adjust_opmode(dev); + + if (dev->dev->id.revision < 3) { + b43_write16(dev, 0x060E, 0x0000); + b43_write16(dev, 0x0610, 0x8000); + b43_write16(dev, 0x0604, 0x0000); + b43_write16(dev, 0x0606, 0x0200); + } else { + b43_write32(dev, 0x0188, 0x80000000); + b43_write32(dev, 0x018C, 0x02000000); + } + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000); + b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00); + b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00); + b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00); + b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00); + b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00); + b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00); + + value32 = ssb_read32(dev->dev, SSB_TMSLOW); + value32 |= 0x00100000; + ssb_write32(dev->dev, SSB_TMSLOW, value32); + + b43_write16(dev, B43_MMIO_POWERUP_DELAY, + dev->dev->bus->chipco.fast_pwrup_delay); + + err = 0; + b43dbg(dev->wl, "Chip initialized\n"); + out: + return err; + + err_radio_off: + b43_radio_turn_off(dev); + err_gpio_cleanup: + b43_gpio_cleanup(dev); + goto out; +} + +static void b43_periodic_every120sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->type != B43_PHYTYPE_G || phy->rev < 2) + return; + + b43_mac_suspend(dev); + b43_lo_g_measure(dev); + b43_mac_enable(dev); + if (b43_has_hardware_pctl(phy)) + b43_lo_g_ctl_mark_all_unused(dev); +} + +static void b43_periodic_every60sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(phy)) + b43_lo_g_ctl_mark_all_unused(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + b43_mac_suspend(dev); + b43_calc_nrssi_slope(dev); + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { + u8 old_chan = phy->channel; + + /* VCO Calibration */ + if (old_chan >= 8) + b43_radio_selectchannel(dev, 1, 0); + else + b43_radio_selectchannel(dev, 13, 0); + b43_radio_selectchannel(dev, old_chan, 0); + } + b43_mac_enable(dev); + } +} + +static void b43_periodic_every30sec(struct b43_wldev *dev) +{ + /* Update device statistics. */ + b43_calculate_link_quality(dev); +} + +static void b43_periodic_every15sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->type == B43_PHYTYPE_G) { + //TODO: update_aci_moving_average + if (phy->aci_enable && phy->aci_wlan_automatic) { + b43_mac_suspend(dev); + if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) { + if (0 /*TODO: bunch of conditions */ ) { + b43_radio_set_interference_mitigation + (dev, B43_INTERFMODE_MANUALWLAN); + } + } else if (1 /*TODO*/) { + /* + if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) { + b43_radio_set_interference_mitigation(dev, + B43_INTERFMODE_NONE); + } + */ + } + b43_mac_enable(dev); + } else if (phy->interfmode == B43_INTERFMODE_NONWLAN && + phy->rev == 1) { + //TODO: implement rev1 workaround + } + } + b43_phy_xmitpower(dev); //FIXME: unless scanning? + //TODO for APHY (temperature?) +} + +static void b43_periodic_every1sec(struct b43_wldev *dev) +{ + int radio_hw_enable; + + /* check if radio hardware enabled status changed */ + radio_hw_enable = b43_is_hw_radio_enabled(dev); + if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { + dev->radio_hw_enable = radio_hw_enable; + b43dbg(dev->wl, "Radio hardware status changed to %s\n", + (radio_hw_enable == 0) ? "disabled" : "enabled"); + b43_leds_update(dev, 0); + } +} + +static void do_periodic_work(struct b43_wldev *dev) +{ + unsigned int state; + + state = dev->periodic_state; + if (state % 120 == 0) + b43_periodic_every120sec(dev); + if (state % 60 == 0) + b43_periodic_every60sec(dev); + if (state % 30 == 0) + b43_periodic_every30sec(dev); + if (state % 15 == 0) + b43_periodic_every15sec(dev); + b43_periodic_every1sec(dev); +} + +/* Estimate a "Badness" value based on the periodic work + * state-machine state. "Badness" is worse (bigger), if the + * periodic work will take longer. + */ +static int estimate_periodic_work_badness(unsigned int state) +{ + int badness = 0; + + if (state % 120 == 0) /* every 120 sec */ + badness += 10; + if (state % 60 == 0) /* every 60 sec */ + badness += 5; + if (state % 30 == 0) /* every 30 sec */ + badness += 1; + if (state % 15 == 0) /* every 15 sec */ + badness += 1; + +#define BADNESS_LIMIT 4 + return badness; +} + +static void b43_periodic_work_handler(struct work_struct *work) +{ + struct b43_wldev *dev = + container_of(work, struct b43_wldev, periodic_work.work); + unsigned long flags, delay; + u32 savedirqs = 0; + int badness; + + mutex_lock(&dev->wl->mutex); + + if (unlikely(b43_status(dev) != B43_STAT_STARTED)) + goto out; + if (b43_debug(dev, B43_DBG_PWORK_STOP)) + goto out_requeue; + + badness = estimate_periodic_work_badness(dev->periodic_state); + if (badness > BADNESS_LIMIT) { + spin_lock_irqsave(&dev->wl->irq_lock, flags); + /* Suspend TX as we don't want to transmit packets while + * we recalibrate the hardware. */ + b43_tx_suspend(dev); + savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); + /* Periodic work will take a long time, so we want it to + * be preemtible and release the spinlock. */ + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + b43_synchronize_irq(dev); + + do_periodic_work(dev); + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + b43_interrupt_enable(dev, savedirqs); + b43_tx_resume(dev); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } else { + /* Take the global driver lock. This will lock any operation. */ + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + do_periodic_work(dev); + + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } + dev->periodic_state++; + out_requeue: + if (b43_debug(dev, B43_DBG_PWORK_FAST)) + delay = msecs_to_jiffies(50); + else + delay = round_jiffies(HZ); + queue_delayed_work(dev->wl->hw->workqueue, &dev->periodic_work, delay); + out: + mutex_unlock(&dev->wl->mutex); +} + +static void b43_periodic_tasks_setup(struct b43_wldev *dev) +{ + struct delayed_work *work = &dev->periodic_work; + + dev->periodic_state = 0; + INIT_DELAYED_WORK(work, b43_periodic_work_handler); + queue_delayed_work(dev->wl->hw->workqueue, work, 0); +} + +/* Validate access to the chip (SHM) */ +static int b43_validate_chipaccess(struct b43_wldev *dev) +{ + u32 value; + u32 shm_backup; + + shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); + b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA); + if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) + goto error; + b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); + if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55) + goto error; + b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup); + + value = b43_read32(dev, B43_MMIO_MACCTL); + if ((value | B43_MACCTL_GMODE) != + (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED)) + goto error; + + value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + if (value) + goto error; + + return 0; + error: + b43err(dev->wl, "Failed to validate the chipaccess\n"); + return -ENODEV; +} + +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); + } + b43_clear_keys(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. */ + + 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)); +} + +static void b43_rng_exit(struct b43_wl *wl) +{ + if (wl->rng_initialized) + hwrng_unregister(&wl->rng); +} + +static int b43_rng_init(struct b43_wl *wl) +{ + int err; + + snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), + "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); + wl->rng.name = wl->rng_name; + wl->rng.data_read = b43_rng_read; + wl->rng.priv = (unsigned long)wl; + wl->rng_initialized = 1; + err = hwrng_register(&wl->rng); + if (err) { + wl->rng_initialized = 0; + b43err(wl, "Failed to register the random " + "number generator (%d)\n", err); + } + + return err; +} + +static int b43_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + int err = -ENODEV; + unsigned long flags; + + if (unlikely(!dev)) + goto out; + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) + goto out; + /* DMA-TX is done without a global lock. */ + if (b43_using_pio(dev)) { + spin_lock_irqsave(&wl->irq_lock, flags); + err = b43_pio_tx(dev, skb, ctl); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } else + err = b43_dma_tx(dev, skb, ctl); + out: + if (unlikely(err)) + return NETDEV_TX_BUSY; + return NETDEV_TX_OK; +} + +static int b43_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) +{ + return 0; +} + +static int b43_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; + int err = -ENODEV; + + if (!dev) + goto out; + spin_lock_irqsave(&wl->irq_lock, flags); + if (likely(b43_status(dev) >= B43_STAT_STARTED)) { + if (b43_using_pio(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: + return err; +} + +static int b43_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); + memcpy(stats, &wl->ieee_stats, sizeof(*stats)); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + +static const char *phymode_to_string(unsigned int phymode) +{ + switch (phymode) { + case B43_PHYMODE_A: + return "A"; + case B43_PHYMODE_B: + return "B"; + case B43_PHYMODE_G: + return "G"; + default: + B43_WARN_ON(1); + } + return ""; +} + +static int find_wldev_for_phymode(struct b43_wl *wl, + unsigned int phymode, + struct b43_wldev **dev, bool * gmode) +{ + struct b43_wldev *d; + + list_for_each_entry(d, &wl->devlist, list) { + if (d->phy.possible_phymodes & phymode) { + /* Ok, this device supports the PHY-mode. + * Now figure out how the gmode bit has to be + * set to support it. */ + if (phymode == B43_PHYMODE_A) + *gmode = 0; + else + *gmode = 1; + *dev = d; + + return 0; + } + } + + return -ESRCH; +} + +static void b43_put_phy_into_reset(struct b43_wldev *dev) +{ + struct ssb_device *sdev = dev->dev; + u32 tmslow; + + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmslow &= ~B43_TMSLOW_GMODE; + tmslow |= B43_TMSLOW_PHYRESET; + tmslow |= SSB_TMSLOW_FGC; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + msleep(1); + + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmslow &= ~SSB_TMSLOW_FGC; + tmslow |= B43_TMSLOW_PHYRESET; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + msleep(1); +} + +/* Expects wl->mutex locked */ +static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) +{ + struct b43_wldev *up_dev; + struct b43_wldev *down_dev; + int err; + bool gmode = 0; + int prev_status; + + err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode); + if (err) { + b43err(wl, "Could not find a device for %s-PHY mode\n", + phymode_to_string(new_mode)); + return err; + } + if ((up_dev == wl->current_dev) && + (!!wl->current_dev->phy.gmode == !!gmode)) { + /* This device is already running. */ + return 0; + } + b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n", + phymode_to_string(new_mode)); + down_dev = wl->current_dev; + + prev_status = b43_status(down_dev); + /* Shutdown the currently running core. */ + if (prev_status >= B43_STAT_STARTED) + b43_wireless_core_stop(down_dev); + if (prev_status >= B43_STAT_INITIALIZED) + b43_wireless_core_exit(down_dev); + + if (down_dev != up_dev) { + /* We switch to a different core, so we put PHY into + * RESET on the old core. */ + b43_put_phy_into_reset(down_dev); + } + + /* Now start the new core. */ + up_dev->phy.gmode = gmode; + if (prev_status >= B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(up_dev); + if (err) { + b43err(wl, "Fatal: Could not initialize device for " + "newly selected %s-PHY mode\n", + phymode_to_string(new_mode)); + goto init_failure; + } + } + if (prev_status >= B43_STAT_STARTED) { + err = b43_wireless_core_start(up_dev); + if (err) { + b43err(wl, "Fatal: Coult not start device for " + "newly selected %s-PHY mode\n", + phymode_to_string(new_mode)); + b43_wireless_core_exit(up_dev); + goto init_failure; + } + } + B43_WARN_ON(b43_status(up_dev) != prev_status); + + wl->current_dev = up_dev; + + return 0; + init_failure: + /* Whoops, failed to init the new core. No core is operating now. */ + wl->current_dev = NULL; + return err; +} + +static int b43_antenna_from_ieee80211(u8 antenna) +{ + switch (antenna) { + case 0: /* default/diversity */ + return B43_ANTENNA_DEFAULT; + case 1: /* Antenna 0 */ + return B43_ANTENNA0; + case 2: /* Antenna 1 */ + return B43_ANTENNA1; + default: + return B43_ANTENNA_DEFAULT; + } +} + +static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + struct b43_phy *phy; + unsigned long flags; + unsigned int new_phymode = 0xFFFF; + int antenna_tx; + int antenna_rx; + int err = 0; + u32 savedirqs; + + antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx); + antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx); + + mutex_lock(&wl->mutex); + + /* Switch the PHY mode (if necessary). */ + switch (conf->phymode) { + case MODE_IEEE80211A: + new_phymode = B43_PHYMODE_A; + break; + case MODE_IEEE80211B: + new_phymode = B43_PHYMODE_B; + break; + case MODE_IEEE80211G: + new_phymode = B43_PHYMODE_G; + break; + default: + B43_WARN_ON(1); + } + err = b43_switch_phymode(wl, new_phymode); + if (err) + goto out_unlock_mutex; + dev = wl->current_dev; + phy = &dev->phy; + + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ + spin_lock_irqsave(&wl->irq_lock, flags); + if (b43_status(dev) < B43_STAT_STARTED) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43_synchronize_irq(dev); + + /* Switch to the requested channel. + * The firmware takes care of races with the TX handler. */ + if (conf->channel_val != phy->channel) + b43_radio_selectchannel(dev, conf->channel_val, 0); + + /* Enable/Disable ShortSlot timing. */ + if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != + dev->short_slot) { + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) + b43_short_slot_timing_enable(dev); + else + b43_short_slot_timing_disable(dev); + } + + /* Adjust the desired TX power level. */ + if (conf->power_level != 0) { + if (conf->power_level != phy->power_level) { + phy->power_level = conf->power_level; + b43_phy_xmitpower(dev); + } + } + + /* Antennas for RX and management frame TX. */ + b43_mgmtframe_txantenna(dev, antenna_tx); + b43_set_rx_antenna(dev, antenna_rx); + + /* Update templates for AP mode. */ + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + b43_set_beacon_int(dev, conf->beacon_int); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_interrupt_enable(dev, savedirqs); + mmiowb(); + spin_unlock_irqrestore(&wl->irq_lock, flags); + out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return err; +} + +static int b43_dev_set_key(struct ieee80211_hw *hw, + set_key_cmd cmd, const u8 *local_addr, + const u8 *addr, struct ieee80211_key_conf *key) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + u8 algorithm; + u8 index; + int err = -EINVAL; + + if (modparam_nohwcrypt) + return -ENOSPC; /* User disabled HW-crypto */ + + if (!dev) + return -ENODEV; + switch (key->alg) { + case ALG_NONE: + algorithm = B43_SEC_ALGO_NONE; + break; + case ALG_WEP: + if (key->keylen == 5) + algorithm = B43_SEC_ALGO_WEP40; + else + algorithm = B43_SEC_ALGO_WEP104; + break; + case ALG_TKIP: + algorithm = B43_SEC_ALGO_TKIP; + break; + case ALG_CCMP: + algorithm = B43_SEC_ALGO_AES; + break; + default: + B43_WARN_ON(1); + goto out; + } + + index = (u8) (key->keyidx); + if (index > 3) + goto out; + + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + switch (cmd) { + case SET_KEY: + if (algorithm == B43_SEC_ALGO_TKIP) { + /* FIXME: No TKIP hardware encryption for now. */ + err = -EOPNOTSUPP; + goto out_unlock; + } + + if (is_broadcast_ether_addr(addr)) { + /* addr is FF:FF:FF:FF:FF:FF for default keys */ + err = b43_key_write(dev, index, algorithm, + key->key, key->keylen, NULL, key); + } else { + /* + * either pairwise key or address is 00:00:00:00:00:00 + * for transmit-only keys + */ + err = b43_key_write(dev, -1, algorithm, + key->key, key->keylen, addr, key); + } + if (err) + goto out_unlock; + + if (algorithm == B43_SEC_ALGO_WEP40 || + algorithm == B43_SEC_ALGO_WEP104) { + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS); + } else { + b43_hf_write(dev, + b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); + } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + case DISABLE_KEY: { + err = b43_key_clear(dev, key->hw_key_idx); + if (err) + goto out_unlock; + break; + } + default: + B43_WARN_ON(1); + } +out_unlock: + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); +out: + if (!err) { + b43dbg(wl, "%s hardware based encryption for keyidx: %d, " + "mac: " MAC_FMT "\n", + cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, + MAC_ARG(addr)); + } + return err; +} + +static void b43_set_multicast_list(struct ieee80211_hw *hw, + unsigned short netflags, int mc_count) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + + if (!dev) + return; + spin_lock_irqsave(&wl->irq_lock, flags); + if (wl->promisc != !!(netflags & IFF_PROMISC)) { + wl->promisc = !!(netflags & IFF_PROMISC); + if (b43_status(dev) >= B43_STAT_INITIALIZED) + b43_adjust_opmode(dev); + } + spin_unlock_irqrestore(&wl->irq_lock, flags); +} + +static int b43_config_interface(struct ieee80211_hw *hw, + int if_id, struct ieee80211_if_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + + if (!dev) + return -ENODEV; + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + if (conf->type != IEEE80211_IF_TYPE_MNTR) { + B43_WARN_ON(wl->if_id != if_id); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + if (b43_status(dev) >= B43_STAT_INITIALIZED) { + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + b43_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->beacon) + b43_refresh_templates(dev, conf->beacon); + } + b43_write_mac_bssid_templates(dev); + } + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + + return 0; +} + +/* Locking: wl->mutex */ +static void b43_wireless_core_stop(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + unsigned long flags; + + if (b43_status(dev) < B43_STAT_STARTED) + return; + b43_set_status(dev, B43_STAT_INITIALIZED); + + 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); + mutex_lock(&wl->mutex); + + ieee80211_stop_queues(wl->hw); //FIXME this could cause a deadlock, as mac80211 seems buggy. + + /* Disable and sync interrupts. */ + spin_lock_irqsave(&wl->irq_lock, flags); + dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43_synchronize_irq(dev); + + b43_mac_suspend(dev); + free_irq(dev->dev->irq, dev); + b43dbg(wl, "Wireless interface stopped\n"); +} + +/* Locking: wl->mutex */ +static int b43_wireless_core_start(struct b43_wldev *dev) +{ + int err; + + 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); + if (err) { + b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); + goto out; + } + + /* We are ready to run. */ + b43_set_status(dev, B43_STAT_STARTED); + + /* Start data flow (TX/RX). */ + b43_mac_enable(dev); + b43_interrupt_enable(dev, dev->irq_savedstate); + ieee80211_start_queues(dev->wl->hw); + + /* Start maintainance work */ + b43_periodic_tasks_setup(dev); + + b43dbg(dev->wl, "Wireless interface started\n"); + out: + return err; +} + +/* Get PHY and RADIO versioning numbers */ +static int b43_phy_versioning(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u32 tmp; + u8 analog_type; + u8 phy_type; + u8 phy_rev; + u16 radio_manuf; + u16 radio_ver; + u16 radio_rev; + int unsupported = 0; + + /* Get PHY versioning */ + tmp = b43_read16(dev, B43_MMIO_PHY_VER); + analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT; + phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT; + phy_rev = (tmp & B43_PHYVER_VERSION); + switch (phy_type) { + case B43_PHYTYPE_A: + if (phy_rev >= 4) + unsupported = 1; + break; + case B43_PHYTYPE_B: + if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 + && phy_rev != 7) + unsupported = 1; + break; + case B43_PHYTYPE_G: + if (phy_rev > 8) + unsupported = 1; + break; + default: + unsupported = 1; + }; + if (unsupported) { + b43err(dev->wl, "FOUND UNSUPPORTED PHY " + "(Analog %u, Type %u, Revision %u)\n", + analog_type, phy_type, phy_rev); + return -EOPNOTSUPP; + } + b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n", + analog_type, phy_type, phy_rev); + + /* Get RADIO versioning */ + if (dev->dev->bus->chip_id == 0x4317) { + if (dev->dev->bus->chip_rev == 0) + tmp = 0x3205017F; + else if (dev->dev->bus->chip_rev == 1) + tmp = 0x4205017F; + else + tmp = 0x5205017F; + } else { + b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); + tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH); + tmp <<= 16; + b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); + tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); + } + radio_manuf = (tmp & 0x00000FFF); + radio_ver = (tmp & 0x0FFFF000) >> 12; + radio_rev = (tmp & 0xF0000000) >> 28; + switch (phy_type) { + case B43_PHYTYPE_A: + if (radio_ver != 0x2060) + unsupported = 1; + if (radio_rev != 1) + unsupported = 1; + if (radio_manuf != 0x17F) + unsupported = 1; + break; + case B43_PHYTYPE_B: + if ((radio_ver & 0xFFF0) != 0x2050) + unsupported = 1; + break; + case B43_PHYTYPE_G: + if (radio_ver != 0x2050) + unsupported = 1; + break; + default: + B43_WARN_ON(1); + } + if (unsupported) { + b43err(dev->wl, "FOUND UNSUPPORTED RADIO " + "(Manuf 0x%X, Version 0x%X, Revision %u)\n", + radio_manuf, radio_ver, radio_rev); + return -EOPNOTSUPP; + } + b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n", + radio_manuf, radio_ver, radio_rev); + + phy->radio_manuf = radio_manuf; + phy->radio_ver = radio_ver; + phy->radio_rev = radio_rev; + + phy->analog = analog_type; + phy->type = phy_type; + phy->rev = phy_rev; + + return 0; +} + +static void setup_struct_phy_for_init(struct b43_wldev *dev, + struct b43_phy *phy) +{ + struct b43_txpower_lo_control *lo; + int i; + + memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); + memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); + + /* Flags */ + phy->locked = 0; + + phy->aci_enable = 0; + phy->aci_wlan_automatic = 0; + phy->aci_hw_rssi = 0; + + lo = phy->lo_control; + if (lo) { + memset(lo, 0, sizeof(*(phy->lo_control))); + lo->rebuild = 1; + lo->tx_bias = 0xFF; + } + phy->max_lb_gain = 0; + phy->trsw_rx_gain = 0; + phy->txpwr_offset = 0; + + /* NRSSI */ + phy->nrssislope = 0; + for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) + phy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) + phy->nrssi_lt[i] = i; + + phy->lofcal = 0xFFFF; + phy->initval = 0xFFFF; + + spin_lock_init(&phy->lock); + phy->interfmode = B43_INTERFMODE_NONE; + phy->channel = 0xFF; + + phy->hardware_power_control = !!modparam_hwpctl; +} + +static void setup_struct_wldev_for_init(struct b43_wldev *dev) +{ + /* Flags */ + dev->reg124_set_0x4 = 0; + + /* Stats */ + memset(&dev->stats, 0, sizeof(dev->stats)); + + setup_struct_phy_for_init(dev, &dev->phy); + + /* IRQ related flags */ + dev->irq_reason = 0; + memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); + dev->irq_savedstate = B43_IRQ_MASKTEMPLATE; + + dev->mac_suspended = 1; + + /* Noise calculation context */ + memset(&dev->noisecalc, 0, sizeof(dev->noisecalc)); +} + +static void b43_bluetooth_coext_enable(struct b43_wldev *dev) +{ + struct ssb_sprom *sprom = &dev->dev->bus->sprom; + u32 hf; + + if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST)) + return; + if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode) + return; + + hf = b43_hf_read(dev); + if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD) + hf |= B43_HF_BTCOEXALT; + else + hf |= B43_HF_BTCOEX; + b43_hf_write(dev, hf); + //TODO +} + +static void b43_bluetooth_coext_disable(struct b43_wldev *dev) +{ //TODO +} + +static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) +{ +#ifdef CONFIG_SSB_DRIVER_PCICORE + struct ssb_bus *bus = dev->dev->bus; + u32 tmp; + + if (bus->pcicore.dev && + bus->pcicore.dev->id.coreid == SSB_DEV_PCI && + 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 |= 0x32; + break; + case SSB_BUSTYPE_SSB: + tmp |= 0x53; + break; + } + ssb_write32(dev->dev, SSB_IMCFGLO, tmp); + } +#endif /* CONFIG_SSB_DRIVER_PCICORE */ +} + +/* Shutdown a wireless core */ +/* Locking: wl->mutex */ +static void b43_wireless_core_exit(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); + if (b43_status(dev) != B43_STAT_INITIALIZED) + return; + b43_set_status(dev, B43_STAT_UNINIT); + + b43_rng_exit(dev->wl); + b43_pio_free(dev); + b43_dma_free(dev); + b43_chip_exit(dev); + b43_radio_turn_off(dev); + b43_switch_analog(dev, 0); + if (phy->dyn_tssi_tbl) + kfree(phy->tssi2dbm); + kfree(phy->lo_control); + phy->lo_control = NULL; + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(dev->dev->bus); +} + +/* Initialize a wireless core */ +static int b43_wireless_core_init(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct ssb_bus *bus = dev->dev->bus; + struct ssb_sprom *sprom = &bus->sprom; + struct b43_phy *phy = &dev->phy; + int err; + u32 hf, tmp; + + B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); + + err = ssb_bus_powerup(bus, 0); + if (err) + goto out; + if (!ssb_device_is_enabled(dev->dev)) { + tmp = phy->gmode ? B43_TMSLOW_GMODE : 0; + b43_wireless_core_reset(dev, tmp); + } + + if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) { + phy->lo_control = + kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL); + if (!phy->lo_control) { + err = -ENOMEM; + goto err_busdown; + } + } + setup_struct_wldev_for_init(dev); + + err = b43_phy_init_tssi2dbm_table(dev); + if (err) + goto err_kfree_lo_control; + + /* Enable IRQ routing to this device. */ + ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); + + b43_imcfglo_timeouts_workaround(dev); + b43_bluetooth_coext_disable(dev); + b43_phy_early_init(dev); + err = b43_chip_init(dev); + if (err) + goto err_kfree_tssitbl; + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_WLCOREREV, dev->dev->id.revision); + hf = b43_hf_read(dev); + if (phy->type == B43_PHYTYPE_G) { + hf |= B43_HF_SYMW; + if (phy->rev == 1) + hf |= B43_HF_GDCW; + if (sprom->r1.boardflags_lo & B43_BFL_PACTRL) + hf |= B43_HF_OFDMPABOOST; + } else if (phy->type == B43_PHYTYPE_B) { + hf |= B43_HF_SYMW; + if (phy->rev >= 2 && phy->radio_ver == 0x2050) + hf &= ~B43_HF_GDCW; + } + b43_hf_write(dev, hf); + + /* Short/Long Retry Limit. + * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. + */ + tmp = limit_value(modparam_short_retry, 0, 0xF); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp); + tmp = limit_value(modparam_long_retry, 0, 0xF); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp); + + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2); + + /* Disable sending probe responses from firmware. + * Setting the MaxTime to one usec will always trigger + * a timeout, so we never send any probe resp. + * A timeout of zero is infinite. */ + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1); + + b43_rate_memory_init(dev); + + /* Minimum Contention Window */ + if (phy->type == B43_PHYTYPE_B) { + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F); + } else { + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF); + } + /* Maximum Contention Window */ + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); + + do { + if (b43_using_pio(dev)) { + err = b43_pio_init(dev); + } else { + err = b43_dma_init(dev); + if (!err) + b43_qos_init(dev); + } + } while (err == -EAGAIN); + if (err) + goto err_chip_exit; + +//FIXME +#if 1 + b43_write16(dev, 0x0612, 0x0050); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0416, 0x0050); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0414, 0x01F4); +#endif + + b43_bluetooth_coext_enable(dev); + + ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ + memset(wl->bssid, 0, ETH_ALEN); + b43_upload_card_macaddress(dev, NULL); + b43_security_init(dev); + b43_rng_init(wl); + + b43_set_status(dev, B43_STAT_INITIALIZED); + + out: + return err; + + err_chip_exit: + b43_chip_exit(dev); + err_kfree_tssitbl: + if (phy->dyn_tssi_tbl) + kfree(phy->tssi2dbm); + err_kfree_lo_control: + kfree(phy->lo_control); + phy->lo_control = NULL; + err_busdown: + ssb_bus_may_powerdown(bus); + B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); + return err; +} + +static int b43_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + unsigned long flags; + int err = -EOPNOTSUPP; + int did_init = 0; + + mutex_lock(&wl->mutex); + if ((conf->type != IEEE80211_IF_TYPE_MNTR) && wl->operating) + goto out_mutex_unlock; + + b43dbg(wl, "Adding Interface type %d\n", conf->type); + + dev = wl->current_dev; + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(dev); + if (err) + goto out_mutex_unlock; + did_init = 1; + } + if (b43_status(dev) < B43_STAT_STARTED) { + err = b43_wireless_core_start(dev); + if (err) { + if (did_init) + b43_wireless_core_exit(dev); + goto out_mutex_unlock; + } + } + + spin_lock_irqsave(&wl->irq_lock, flags); + switch (conf->type) { + case IEEE80211_IF_TYPE_MNTR: + wl->monitor++; + break; + default: + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + b43_upload_card_macaddress(dev, conf->mac_addr); + } + b43_adjust_opmode(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + err = 0; + out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static void b43_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + unsigned long flags; + + b43dbg(wl, "Removing Interface type %d\n", conf->type); + + mutex_lock(&wl->mutex); + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + wl->monitor--; + B43_WARN_ON(wl->monitor < 0); + } else { + B43_WARN_ON(!wl->operating); + wl->operating = 0; + } + + dev = wl->current_dev; + if (!wl->operating && wl->monitor == 0) { + /* No interface left. */ + if (b43_status(dev) >= B43_STAT_STARTED) + b43_wireless_core_stop(dev); + b43_wireless_core_exit(dev); + } else { + /* Just monitor interfaces left. */ + spin_lock_irqsave(&wl->irq_lock, flags); + b43_adjust_opmode(dev); + if (!wl->operating) + b43_upload_card_macaddress(dev, NULL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } + mutex_unlock(&wl->mutex); +} + +static const struct ieee80211_ops b43_hw_ops = { + .tx = b43_tx, + .conf_tx = b43_conf_tx, + .add_interface = b43_add_interface, + .remove_interface = b43_remove_interface, + .config = b43_dev_config, + .config_interface = b43_config_interface, + .set_multicast_list = b43_set_multicast_list, + .set_key = b43_dev_set_key, + .get_stats = b43_get_stats, + .get_tx_stats = b43_get_tx_stats, +}; + +/* Hard-reset the chip. Do not call this directly. + * Use b43_controller_restart() + */ +static void b43_chip_reset(struct work_struct *work) +{ + struct b43_wldev *dev = + container_of(work, struct b43_wldev, restart_work); + struct b43_wl *wl = dev->wl; + int err = 0; + int prev_status; + + mutex_lock(&wl->mutex); + + 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_INITIALIZED) + b43_wireless_core_exit(dev); + + /* ...and up again. */ + if (prev_status >= B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(dev); + if (err) + goto out; + } + if (prev_status >= B43_STAT_STARTED) { + err = b43_wireless_core_start(dev); + if (err) { + b43_wireless_core_exit(dev); + goto out; + } + } + out: + mutex_unlock(&wl->mutex); + if (err) + b43err(wl, "Controller restart FAILED\n"); + else + b43info(wl, "Controller restarted\n"); +} + +static int b43_setup_modes(struct b43_wldev *dev, + int have_aphy, int have_bphy, int have_gphy) +{ + struct ieee80211_hw *hw = dev->wl->hw; + struct ieee80211_hw_mode *mode; + struct b43_phy *phy = &dev->phy; + int cnt = 0; + int err; + +/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */ + have_aphy = 0; + + phy->possible_phymodes = 0; + for (; 1; cnt++) { + if (have_aphy) { + B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211A; + mode->num_channels = b43_a_chantable_size; + mode->channels = b43_a_chantable; + mode->num_rates = b43_a_ratetable_size; + mode->rates = b43_a_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43_PHYMODE_A; + have_aphy = 0; + continue; + } + if (have_bphy) { + B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211B; + mode->num_channels = b43_bg_chantable_size; + mode->channels = b43_bg_chantable; + mode->num_rates = b43_b_ratetable_size; + mode->rates = b43_b_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43_PHYMODE_B; + have_bphy = 0; + continue; + } + if (have_gphy) { + B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211G; + mode->num_channels = b43_bg_chantable_size; + mode->channels = b43_bg_chantable; + mode->num_rates = b43_g_ratetable_size; + mode->rates = b43_g_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43_PHYMODE_G; + have_gphy = 0; + continue; + } + break; + } + + return 0; +} + +static void b43_wireless_core_detach(struct b43_wldev *dev) +{ + /* We release firmware that late to not be required to re-request + * is all the time when we reinit the core. */ + b43_release_firmware(dev); +} + +static int b43_wireless_core_attach(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct ssb_bus *bus = dev->dev->bus; + struct pci_dev *pdev = bus->host_pci; + int err; + int have_aphy = 0, have_bphy = 0, have_gphy = 0; + u32 tmp; + + /* Do NOT do any device initialization here. + * Do it in wireless_core_init() instead. + * This function is for gathering basic information about the HW, only. + * Also some structs may be set up here. But most likely you want to have + * that in core_init(), too. + */ + + err = ssb_bus_powerup(bus, 0); + if (err) { + b43err(wl, "Bus powerup failed\n"); + goto out; + } + /* Get the PHY type. */ + if (dev->dev->id.revision >= 5) { + u32 tmshigh; + + tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + have_aphy = !!(tmshigh & B43_TMSHIGH_APHY); + have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY); + if (!have_aphy && !have_gphy) + have_bphy = 1; + } else if (dev->dev->id.revision == 4) { + have_gphy = 1; + have_aphy = 1; + } else + have_bphy = 1; + + /* Initialize LEDs structs. */ + err = b43_leds_init(dev); + if (err) + goto err_powerdown; + + dev->phy.gmode = (have_gphy || have_bphy); + tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; + b43_wireless_core_reset(dev, tmp); + + err = b43_phy_versioning(dev); + if (err) + goto err_leds_exit; + /* Check if this device supports multiband. */ + if (!pdev || + (pdev->device != 0x4312 && + pdev->device != 0x4319 && pdev->device != 0x4324)) { + /* No multiband support. */ + have_aphy = 0; + have_bphy = 0; + have_gphy = 0; + switch (dev->phy.type) { + case B43_PHYTYPE_A: + have_aphy = 1; + break; + case B43_PHYTYPE_B: + have_bphy = 1; + break; + case B43_PHYTYPE_G: + have_gphy = 1; + break; + default: + B43_WARN_ON(1); + } + } + dev->phy.gmode = (have_gphy || have_bphy); + tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; + b43_wireless_core_reset(dev, tmp); + + err = b43_validate_chipaccess(dev); + if (err) + goto err_leds_exit; + err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy); + if (err) + goto err_leds_exit; + + /* Now set some default "current_dev" */ + if (!wl->current_dev) + wl->current_dev = dev; + INIT_WORK(&dev->restart_work, b43_chip_reset); + + b43_radio_turn_off(dev); + b43_switch_analog(dev, 0); + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); + +out: + return err; + +err_leds_exit: + b43_leds_exit(dev); +err_powerdown: + ssb_bus_may_powerdown(bus); + return err; +} + +static void b43_one_core_detach(struct ssb_device *dev) +{ + struct b43_wldev *wldev; + struct b43_wl *wl; + + wldev = ssb_get_drvdata(dev); + wl = wldev->wl; + cancel_work_sync(&wldev->restart_work); + b43_debugfs_remove_device(wldev); + b43_wireless_core_detach(wldev); + list_del(&wldev->list); + wl->nr_devs--; + ssb_set_drvdata(dev, NULL); + kfree(wldev); +} + +static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) +{ + struct b43_wldev *wldev; + struct pci_dev *pdev; + int err = -ENOMEM; + + if (!list_empty(&wl->devlist)) { + /* We are not the first core on this chip. */ + pdev = dev->bus->host_pci; + /* Only special chips support more than one wireless + * core, although some of the other chips have more than + * one wireless core as well. Check for this and + * bail out early. + */ + if (!pdev || + ((pdev->device != 0x4321) && + (pdev->device != 0x4313) && (pdev->device != 0x431A))) { + b43dbg(wl, "Ignoring unconnected 802.11 core\n"); + return -ENODEV; + } + } + + wldev = kzalloc(sizeof(*wldev), GFP_KERNEL); + if (!wldev) + goto out; + + wldev->dev = dev; + 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); + if (modparam_pio) + wldev->__using_pio = 1; + INIT_LIST_HEAD(&wldev->list); + + err = b43_wireless_core_attach(wldev); + if (err) + goto err_kfree_wldev; + + list_add(&wldev->list, &wl->devlist); + wl->nr_devs++; + ssb_set_drvdata(dev, wldev); + b43_debugfs_add_device(wldev); + + out: + return err; + + err_kfree_wldev: + kfree(wldev); + return err; +} + +static void b43_sprom_fixup(struct ssb_bus *bus) +{ + /* boardflags workarounds */ + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && + bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) + bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && + bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) + bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL; + + /* Handle case when gain is not set in sprom */ + if (bus->sprom.r1.antenna_gain_a == 0xFF) + bus->sprom.r1.antenna_gain_a = 2; + if (bus->sprom.r1.antenna_gain_bg == 0xFF) + bus->sprom.r1.antenna_gain_bg = 2; + + /* Convert Antennagain values to Q5.2 */ + bus->sprom.r1.antenna_gain_a <<= 2; + bus->sprom.r1.antenna_gain_bg <<= 2; +} + +static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl) +{ + struct ieee80211_hw *hw = wl->hw; + + ssb_set_devtypedata(dev, NULL); + ieee80211_free_hw(hw); +} + +static int b43_wireless_init(struct ssb_device *dev) +{ + struct ssb_sprom *sprom = &dev->bus->sprom; + struct ieee80211_hw *hw; + struct b43_wl *wl; + int err = -ENOMEM; + + b43_sprom_fixup(dev->bus); + + hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops); + if (!hw) { + b43err(NULL, "Could not allocate ieee80211 device\n"); + goto out; + } + + /* fill hw info */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_MONITOR_DURING_OPER; + hw->max_signal = 100; + hw->max_rssi = -110; + hw->max_noise = -110; + hw->queues = 1; /* FIXME: hardware has more queues */ + SET_IEEE80211_DEV(hw, dev->dev); + if (is_valid_ether_addr(sprom->r1.et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + else + SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + + /* Get and initialize struct b43_wl */ + wl = hw_to_b43_wl(hw); + memset(wl, 0, sizeof(*wl)); + wl->hw = hw; + spin_lock_init(&wl->irq_lock); + spin_lock_init(&wl->leds_lock); + mutex_init(&wl->mutex); + INIT_LIST_HEAD(&wl->devlist); + + ssb_set_devtypedata(dev, wl); + b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); + err = 0; + out: + return err; +} + +static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id) +{ + struct b43_wl *wl; + int err; + int first = 0; + + wl = ssb_get_devtypedata(dev); + if (!wl) { + /* Probing the first core. Must setup common struct b43_wl */ + first = 1; + err = b43_wireless_init(dev); + if (err) + goto out; + wl = ssb_get_devtypedata(dev); + B43_WARN_ON(!wl); + } + err = b43_one_core_attach(dev, wl); + if (err) + goto err_wireless_exit; + + if (first) { + err = ieee80211_register_hw(wl->hw); + if (err) + goto err_one_core_detach; + } + + out: + return err; + + err_one_core_detach: + b43_one_core_detach(dev); + err_wireless_exit: + if (first) + b43_wireless_exit(dev, wl); + return err; +} + +static void b43_remove(struct ssb_device *dev) +{ + struct b43_wl *wl = ssb_get_devtypedata(dev); + struct b43_wldev *wldev = ssb_get_drvdata(dev); + + B43_WARN_ON(!wl); + if (wl->current_dev == wldev) + ieee80211_unregister_hw(wl->hw); + + b43_one_core_detach(dev); + + if (list_empty(&wl->devlist)) { + /* Last core on the chip unregistered. + * We can destroy common struct b43_wl. + */ + b43_wireless_exit(dev, wl); + } +} + +/* Perform a hardware reset. This can be called from any context. */ +void b43_controller_restart(struct b43_wldev *dev, const char *reason) +{ + /* Must avoid requeueing, if we are in shutdown. */ + 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); +} + +#ifdef CONFIG_PM + +static int b43_suspend(struct ssb_device *dev, pm_message_t state) +{ + struct b43_wldev *wldev = ssb_get_drvdata(dev); + struct b43_wl *wl = wldev->wl; + + b43dbg(wl, "Suspending...\n"); + + mutex_lock(&wl->mutex); + 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) + b43_wireless_core_exit(wldev); + mutex_unlock(&wl->mutex); + + b43dbg(wl, "Device suspended.\n"); + + return 0; +} + +static int b43_resume(struct ssb_device *dev) +{ + struct b43_wldev *wldev = ssb_get_drvdata(dev); + struct b43_wl *wl = wldev->wl; + int err = 0; + + b43dbg(wl, "Resuming...\n"); + + mutex_lock(&wl->mutex); + if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(wldev); + if (err) { + b43err(wl, "Resume failed at core init\n"); + goto out; + } + } + if (wldev->suspend_init_status >= B43_STAT_STARTED) { + err = b43_wireless_core_start(wldev); + if (err) { + b43_wireless_core_exit(wldev); + b43err(wl, "Resume failed at core start\n"); + goto out; + } + } + mutex_unlock(&wl->mutex); + + b43dbg(wl, "Device resumed.\n"); + out: + return err; +} + +#else /* CONFIG_PM */ +# define b43_suspend NULL +# define b43_resume NULL +#endif /* CONFIG_PM */ + +static struct ssb_driver b43_ssb_driver = { + .name = KBUILD_MODNAME, + .id_table = b43_ssb_tbl, + .probe = b43_probe, + .remove = b43_remove, + .suspend = b43_suspend, + .resume = b43_resume, +}; + +static int __init b43_init(void) +{ + int err; + + b43_debugfs_init(); + err = b43_pcmcia_init(); + if (err) + goto err_dfs_exit; + err = ssb_driver_register(&b43_ssb_driver); + if (err) + goto err_pcmcia_exit; + + return err; + +err_pcmcia_exit: + b43_pcmcia_exit(); +err_dfs_exit: + b43_debugfs_exit(); + return err; +} + +static void __exit b43_exit(void) +{ + ssb_driver_unregister(&b43_ssb_driver); + b43_pcmcia_exit(); + b43_debugfs_exit(); +} + +module_init(b43_init) +module_exit(b43_exit) diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h new file mode 100644 index 000000000000..bd8fcf72dc5d --- /dev/null +++ b/drivers/net/wireless/b43/main.h @@ -0,0 +1,142 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43_MAIN_H_ +#define B43_MAIN_H_ + +#include "b43.h" + +#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] +#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) +/* Magic helper macro to pad structures. Ignore those above. It's magic. */ +#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) + +/* Lightweight function to convert a frequency (in Mhz) to a channel number. */ +static inline u8 b43_freq_to_channel_a(int freq) +{ + return ((freq - 5000) / 5); +} +static inline u8 b43_freq_to_channel_bg(int freq) +{ + u8 channel; + + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; + + return channel; +} +static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq) +{ + if (dev->phy.type == B43_PHYTYPE_A) + return b43_freq_to_channel_a(freq); + return b43_freq_to_channel_bg(freq); +} + +/* Lightweight function to convert a channel number to a frequency (in Mhz). */ +static inline int b43_channel_to_freq_a(u8 channel) +{ + return (5000 + (5 * channel)); +} +static inline int b43_channel_to_freq_bg(u8 channel) +{ + int freq; + + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); + + return freq; +} +static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel) +{ + if (dev->phy.type == B43_PHYTYPE_A) + return b43_channel_to_freq_a(channel); + return b43_channel_to_freq_bg(channel); +} + +static inline int b43_is_cck_rate(int rate) +{ + return (rate == B43_CCK_RATE_1MB || + rate == B43_CCK_RATE_2MB || + rate == B43_CCK_RATE_5MB || rate == B43_CCK_RATE_11MB); +} + +static inline int b43_is_ofdm_rate(int rate) +{ + return !b43_is_cck_rate(rate); +} + +static inline int b43_is_hw_radio_enabled(struct b43_wldev *dev) +{ + /* function to return state of hardware enable of radio + * returns 0 if radio disabled, 1 if radio enabled + */ + struct b43_phy *phy = &dev->phy; + + if (phy->rev >= 3) + return ((b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) + & B43_MMIO_RADIO_HWENABLED_HI_MASK) + == 0) ? 1 : 0; + else + return ((b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) + & B43_MMIO_RADIO_HWENABLED_LO_MASK) + == 0) ? 0 : 1; +} + +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); +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_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); + +u32 b43_hf_read(struct b43_wldev *dev); +void b43_hf_write(struct b43_wldev *dev, u32 value); + +void b43_dummy_transmission(struct b43_wldev *dev); + +void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags); + +void b43_mac_suspend(struct b43_wldev *dev); +void b43_mac_enable(struct b43_wldev *dev); + +void b43_controller_restart(struct b43_wldev *dev, const char *reason); + +#define B43_PS_ENABLED (1 << 0) /* Force enable hardware power saving */ +#define B43_PS_DISABLED (1 << 1) /* Force disable hardware power saving */ +#define B43_PS_AWAKE (1 << 2) /* Force device awake */ +#define B43_PS_ASLEEP (1 << 3) /* Force device asleep */ +void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); + +#endif /* B43_MAIN_H_ */ diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c new file mode 100644 index 000000000000..3e75a8a12c96 --- /dev/null +++ b/drivers/net/wireless/b43/pcmcia.c @@ -0,0 +1,157 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2007 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include +#include +#include +#include +#include +#include + +static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = { + PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), + PCMCIA_DEVICE_NULL, +}; + +MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl); + +#ifdef CONFIG_PM +static int b43_pcmcia_suspend(struct pcmcia_device *dev) +{ + //TODO + return 0; +} + +static int b43_pcmcia_resume(struct pcmcia_device *dev) +{ + //TODO + return 0; +} +#else /* CONFIG_PM */ +# define b43_pcmcia_suspend NULL +# define b43_pcmcia_resume NULL +#endif /* CONFIG_PM */ + +static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) +{ + struct ssb_bus *ssb; + win_req_t win; + memreq_t mem; + tuple_t tuple; + cisparse_t parse; + int err = -ENOMEM; + int res; + unsigned char buf[64]; + + ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); + if (!ssb) + goto out; + + err = -ENODEV; + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + res = pcmcia_get_first_tuple(dev, &tuple); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + res = pcmcia_get_tuple_data(dev, &tuple); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + res = pcmcia_parse_tuple(dev, &tuple, &parse); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + + dev->conf.ConfigBase = parse.config.base; + dev->conf.Present = parse.config.rmask[0]; + + dev->io.BasePort2 = 0; + dev->io.NumPorts2 = 0; + dev->io.Attributes2 = 0; + + win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; + win.Base = 0; + win.Size = SSB_CORE_SIZE; + win.AccessSpeed = 1000; + res = pcmcia_request_window(&dev, &win, &dev->win); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + + mem.CardOffset = 0; + mem.Page = 0; + res = pcmcia_map_mem_page(dev->win, &mem); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + + res = pcmcia_request_configuration(dev, &dev->conf); + if (res != CS_SUCCESS) + goto err_disable; + + err = ssb_bus_pcmciabus_register(ssb, dev, win.Base); + dev->priv = ssb; + + out: + return err; + err_disable: + pcmcia_disable_device(dev); + err_kfree_ssb: + kfree(ssb); + return err; +} + +static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev) +{ + struct ssb_bus *ssb = dev->priv; + + ssb_bus_unregister(ssb); + pcmcia_release_window(dev->win); + pcmcia_disable_device(dev); + kfree(ssb); + dev->priv = NULL; +} + +static struct pcmcia_driver b43_pcmcia_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "b43-pcmcia", + }, + .id_table = b43_pcmcia_tbl, + .probe = b43_pcmcia_probe, + .remove = b43_pcmcia_remove, + .suspend = b43_pcmcia_suspend, + .resume = b43_pcmcia_resume, +}; + +int b43_pcmcia_init(void) +{ + return pcmcia_register_driver(&b43_pcmcia_driver); +} + +void b43_pcmcia_exit(void) +{ + pcmcia_unregister_driver(&b43_pcmcia_driver); +} diff --git a/drivers/net/wireless/b43/pcmcia.h b/drivers/net/wireless/b43/pcmcia.h new file mode 100644 index 000000000000..85f120a67cbe --- /dev/null +++ b/drivers/net/wireless/b43/pcmcia.h @@ -0,0 +1,20 @@ +#ifndef B43_PCMCIA_H_ +#define B43_PCMCIA_H_ + +#ifdef CONFIG_B43_PCMCIA + +int b43_pcmcia_init(void); +void b43_pcmcia_exit(void); + +#else /* CONFIG_B43_PCMCIA */ + +static inline int b43_pcmcia_init(void) +{ + return 0; +} +static inline void b43_pcmcia_exit(void) +{ +} + +#endif /* CONFIG_B43_PCMCIA */ +#endif /* B43_PCMCIA_H_ */ diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c new file mode 100644 index 000000000000..3282893021b0 --- /dev/null +++ b/drivers/net/wireless/b43/phy.c @@ -0,0 +1,4351 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005, 2006 Stefano Brivio + Copyright (c) 2005, 2006 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include + +#include "b43.h" +#include "phy.h" +#include "main.h" +#include "tables.h" +#include "lo.h" + +static const s8 b43_tssi2dbm_b_table[] = { + 0x4D, 0x4C, 0x4B, 0x4A, + 0x4A, 0x49, 0x48, 0x47, + 0x47, 0x46, 0x45, 0x45, + 0x44, 0x43, 0x42, 0x42, + 0x41, 0x40, 0x3F, 0x3E, + 0x3D, 0x3C, 0x3B, 0x3A, + 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x32, 0x31, + 0x30, 0x2F, 0x2D, 0x2C, + 0x2B, 0x29, 0x28, 0x26, + 0x25, 0x23, 0x21, 0x1F, + 0x1D, 0x1A, 0x17, 0x14, + 0x10, 0x0C, 0x06, 0x00, + -7, -7, -7, -7, + -7, -7, -7, -7, + -7, -7, -7, -7, +}; + +static const s8 b43_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +const u8 b43_radio_channel_codes_bg[] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, +}; + +static void b43_phy_initg(struct b43_wldev *dev); + +/* Reverse the bits of a 4bit value. + * Example: 1101 is flipped 1011 + */ +static u16 flip_4bit(u16 value) +{ + u16 flipped = 0x0000; + + B43_WARN_ON(value & ~0x000F); + + flipped |= (value & 0x0001) << 3; + flipped |= (value & 0x0002) << 1; + flipped |= (value & 0x0004) >> 1; + flipped |= (value & 0x0008) >> 3; + + return flipped; +} + +static void generate_rfatt_list(struct b43_wldev *dev, + struct b43_rfatt_list *list) +{ + struct b43_phy *phy = &dev->phy; + + /* APHY.rev < 5 || GPHY.rev < 6 */ + static const struct b43_rfatt rfatt_0[] = { + {.att = 3,.with_padmix = 0,}, + {.att = 1,.with_padmix = 0,}, + {.att = 5,.with_padmix = 0,}, + {.att = 7,.with_padmix = 0,}, + {.att = 9,.with_padmix = 0,}, + {.att = 2,.with_padmix = 0,}, + {.att = 0,.with_padmix = 0,}, + {.att = 4,.with_padmix = 0,}, + {.att = 6,.with_padmix = 0,}, + {.att = 8,.with_padmix = 0,}, + {.att = 1,.with_padmix = 1,}, + {.att = 2,.with_padmix = 1,}, + {.att = 3,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + }; + /* Radio.rev == 8 && Radio.version == 0x2050 */ + static const struct b43_rfatt rfatt_1[] = { + {.att = 2,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + {.att = 6,.with_padmix = 1,}, + {.att = 8,.with_padmix = 1,}, + {.att = 10,.with_padmix = 1,}, + {.att = 12,.with_padmix = 1,}, + {.att = 14,.with_padmix = 1,}, + }; + /* Otherwise */ + static const struct b43_rfatt rfatt_2[] = { + {.att = 0,.with_padmix = 1,}, + {.att = 2,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + {.att = 6,.with_padmix = 1,}, + {.att = 8,.with_padmix = 1,}, + {.att = 9,.with_padmix = 1,}, + {.att = 9,.with_padmix = 1,}, + }; + + if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) || + (phy->type == B43_PHYTYPE_G && phy->rev < 6)) { + /* Software pctl */ + list->list = rfatt_0; + list->len = ARRAY_SIZE(rfatt_0); + list->min_val = 0; + list->max_val = 9; + return; + } + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + /* Hardware pctl */ + list->list = rfatt_1; + list->len = ARRAY_SIZE(rfatt_1); + list->min_val = 2; + list->max_val = 14; + return; + } + /* Hardware pctl */ + list->list = rfatt_2; + list->len = ARRAY_SIZE(rfatt_2); + list->min_val = 0; + list->max_val = 9; +} + +static void generate_bbatt_list(struct b43_wldev *dev, + struct b43_bbatt_list *list) +{ + static const struct b43_bbatt bbatt_0[] = { + {.att = 0,}, + {.att = 1,}, + {.att = 2,}, + {.att = 3,}, + {.att = 4,}, + {.att = 5,}, + {.att = 6,}, + {.att = 7,}, + {.att = 8,}, + }; + + list->list = bbatt_0; + list->len = ARRAY_SIZE(bbatt_0); + list->min_val = 0; + list->max_val = 8; +} + +bool b43_has_hardware_pctl(struct b43_phy *phy) +{ + if (!phy->hardware_power_control) + return 0; + switch (phy->type) { + case B43_PHYTYPE_A: + if (phy->rev >= 5) + return 1; + break; + case B43_PHYTYPE_G: + if (phy->rev >= 6) + return 1; + break; + default: + B43_WARN_ON(1); + } + return 0; +} + +static void b43_shm_clear_tssi(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + switch (phy->type) { + case B43_PHYTYPE_A: + b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F); + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F); + break; + } +} + +void b43_raw_phy_lock(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + B43_WARN_ON(!irqs_disabled()); + + /* We had a check for MACCTL==0 here, but I think that doesn't + * make sense, as MACCTL is never 0 when this is called. + * --mb */ + B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0); + + if (dev->dev->id.revision < 3) { + b43_mac_suspend(dev); + spin_lock(&phy->lock); + } else { + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); + } + phy->locked = 1; +} + +void b43_raw_phy_unlock(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + B43_WARN_ON(!irqs_disabled()); + if (dev->dev->id.revision < 3) { + if (phy->locked) { + spin_unlock(&phy->lock); + b43_mac_enable(dev); + } + } else { + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, 0); + } + phy->locked = 0; +} + +/* Different PHYs require different register routing flags. + * This adjusts (and does sanity checks on) the routing flags. + */ +static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy, + u16 offset, struct b43_wldev *dev) +{ + if (phy->type == B43_PHYTYPE_A) { + /* OFDM registers are base-registers for the A-PHY. */ + offset &= ~B43_PHYROUTE_OFDM_GPHY; + } + if (offset & B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + if (phy->type != B43_PHYTYPE_G) { + b43dbg(dev->wl, "EXT-G PHY access at " + "0x%04X on %u type PHY\n", offset, phy->type); + } + } + + return offset; +} + +u16 b43_phy_read(struct b43_wldev * dev, u16 offset) +{ + struct b43_phy *phy = &dev->phy; + + offset = adjust_phyreg_for_phytype(phy, offset, dev); + b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val) +{ + struct b43_phy *phy = &dev->phy; + + offset = adjust_phyreg_for_phytype(phy, offset, dev); + b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); + mmiowb(); + b43_write16(dev, B43_MMIO_PHY_DATA, val); +} + +static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower); + +/* Adjust the transmission power output (G-PHY) */ +void b43_set_txpower_g(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt, u8 tx_control) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 bb, rf; + u16 tx_bias, tx_magn; + + bb = bbatt->att; + rf = rfatt->att; + tx_bias = lo->tx_bias; + tx_magn = lo->tx_magn; + if (unlikely(tx_bias == 0xFF)) + tx_bias = 0; + + /* Save the values for later */ + phy->tx_control = tx_control; + memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); + memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); + + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " + "rfatt(%u), tx_control(0x%02X), " + "tx_bias(0x%02X), tx_magn(0x%02X)\n", + bb, rf, tx_control, tx_bias, tx_magn); + } + + b43_phy_set_baseband_attenuation(dev, bb); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, + (rf & 0x000F) | (tx_control & 0x0070)); + } else { + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | (rf & 0x000F)); + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & ~0x0070) | (tx_control & + 0x0070)); + } + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, tx_magn | tx_bias); + } else { + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & 0xFFF0) | (tx_bias & 0x000F)); + } + if (phy->type == B43_PHYTYPE_G) + b43_lo_g_adjust(dev); +} + +static void default_baseband_attenuation(struct b43_wldev *dev, + struct b43_bbatt *bb) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) + bb->att = 0; + else + bb->att = 2; +} + +static void default_radio_attenuation(struct b43_wldev *dev, + struct b43_rfatt *rf) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + rf->with_padmix = 0; + + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G) { + if (bus->boardinfo.rev < 0x43) { + rf->att = 2; + return; + } else if (bus->boardinfo.rev < 0x51) { + rf->att = 3; + return; + } + } + + if (phy->type == B43_PHYTYPE_A) { + rf->att = 0x60; + return; + } + + switch (phy->radio_ver) { + case 0x2053: + switch (phy->radio_rev) { + case 1: + rf->att = 6; + return; + } + break; + case 0x2050: + switch (phy->radio_rev) { + case 0: + rf->att = 5; + return; + case 1: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 3; + else + rf->att = 1; + } else { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 7; + else + rf->att = 6; + } + return; + case 2: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 5; + else if (bus->chip_id == 0x4320) + rf->att = 4; + else + rf->att = 3; + } else + rf->att = 6; + return; + case 3: + rf->att = 5; + return; + case 4: + case 5: + rf->att = 1; + return; + case 6: + case 7: + rf->att = 5; + return; + case 8: + rf->att = 0xA; + rf->with_padmix = 1; + return; + case 9: + default: + rf->att = 5; + return; + } + } + rf->att = 5; +} + +static u16 default_tx_control(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver != 0x2050) + return 0; + if (phy->radio_rev == 1) + return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX; + if (phy->radio_rev < 6) + return B43_TXCTL_PA2DB; + if (phy->radio_rev == 8) + return B43_TXCTL_TXMIX; + return 0; +} + +/* This func is called "PHY calibrate" in the specs... */ +void b43_phy_early_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + + default_baseband_attenuation(dev, &phy->bbatt); + default_radio_attenuation(dev, &phy->rfatt); + phy->tx_control = (default_tx_control(dev) << 4); + + /* Commit previous writes */ + b43_read32(dev, B43_MMIO_MACCTL); + + if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) { + generate_rfatt_list(dev, &lo->rfatt_list); + generate_bbatt_list(dev, &lo->bbatt_list); + } + if (phy->type == B43_PHYTYPE_G && phy->rev == 1) { + /* Workaround: Temporarly disable gmode through the early init + * phase, as the gmode stuff is not needed for phy rev 1 */ + phy->gmode = 0; + b43_wireless_core_reset(dev, 0); + b43_phy_initg(dev); + phy->gmode = 1; + b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); + } +} + +/* GPHY_TSSI_Power_Lookup_Table_Init */ +static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int i; + u16 value; + + for (i = 0; i < 32; i++) + b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]); + for (i = 32; i < 64; i++) + b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]); + for (i = 0; i < 64; i += 2) { + value = (u16) phy->tssi2dbm[i]; + value |= ((u16) phy->tssi2dbm[i + 1]) << 8; + b43_phy_write(dev, 0x380 + (i / 2), value); + } +} + +/* GPHY_Gain_Lookup_Table_Init */ +static void b43_gphy_gain_lt_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 nr_written = 0; + u16 tmp; + u8 rf, bb; + + if (!lo->lo_measured) { + b43_phy_write(dev, 0x3FF, 0); + return; + } + + for (rf = 0; rf < lo->rfatt_list.len; rf++) { + for (bb = 0; bb < lo->bbatt_list.len; bb++) { + if (nr_written >= 0x40) + return; + tmp = lo->bbatt_list.list[bb].att; + tmp <<= 8; + if (phy->radio_rev == 8) + tmp |= 0x50; + else + tmp |= 0x40; + tmp |= lo->rfatt_list.list[rf].att; + b43_phy_write(dev, 0x3C0 + nr_written, tmp); + nr_written++; + } + } +} + +/* GPHY_DC_Lookup_Table */ +void b43_gphy_dc_lt_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_loctl *loctl0; + struct b43_loctl *loctl1; + int i; + int rf_offset, bb_offset; + u16 tmp; + + for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) { + rf_offset = i / lo->rfatt_list.len; + bb_offset = i % lo->rfatt_list.len; + + loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset], + &lo->bbatt_list.list[bb_offset]); + if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) { + rf_offset = (i + 1) / lo->rfatt_list.len; + bb_offset = (i + 1) % lo->rfatt_list.len; + + loctl1 = + b43_get_lo_g_ctl(dev, + &lo->rfatt_list.list[rf_offset], + &lo->bbatt_list.list[bb_offset]); + } else + loctl1 = loctl0; + + tmp = ((u16) loctl0->q & 0xF); + tmp |= ((u16) loctl0->i & 0xF) << 4; + tmp |= ((u16) loctl1->q & 0xF) << 8; + tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME? + b43_phy_write(dev, 0x3A0 + (i / 2), tmp); + } +} + +static void hardware_pctl_init_aphy(struct b43_wldev *dev) +{ + //TODO +} + +static void hardware_pctl_init_gphy(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) + | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); + b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) + | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); + b43_gphy_tssi_power_lt_init(dev); + b43_gphy_gain_lt_init(dev); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); + b43_phy_write(dev, 0x0014, 0x0000); + + B43_WARN_ON(phy->rev < 6); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + | 0x0800); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + & 0xFEFF); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) + & 0xFFBF); + + b43_gphy_dc_lt_init(dev); +} + +/* HardwarePowerControl init for A and G PHY */ +static void b43_hardware_pctl_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(phy)) { + /* No hardware power control */ + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL); + return; + } + /* Init the hwpctl related hardware */ + switch (phy->type) { + case B43_PHYTYPE_A: + hardware_pctl_init_aphy(dev); + break; + case B43_PHYTYPE_G: + hardware_pctl_init_gphy(dev); + break; + default: + B43_WARN_ON(1); + } + /* Enable hardware pctl in firmware. */ + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); +} + +static void b43_hardware_pctl_early_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(phy)) { + b43_phy_write(dev, 0x047A, 0xC111); + return; + } + + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); + b43_phy_write(dev, 0x002F, 0x0202); + b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); + b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + | 0x8000); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + } else { + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0200); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + & 0x7FFF); + b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) + & 0xFFFE); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + } +} + +/* Intialize B/G PHY power control + * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + */ +static void b43_phy_init_pctl(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_rfatt old_rfatt; + struct b43_bbatt old_bbatt; + u8 old_tx_control = 0; + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; + + b43_phy_write(dev, 0x0028, 0x8018); + + /* This does something with the Analog... */ + b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0) + & 0xFFDF); + + if (phy->type == B43_PHYTYPE_G && !phy->gmode) + return; + b43_hardware_pctl_early_init(dev); + if (phy->cur_idle_tssi == 0) { + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + (b43_radio_read16(dev, 0x0076) + & 0x00F7) | 0x0084); + } else { + struct b43_rfatt rfatt; + struct b43_bbatt bbatt; + + memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt)); + memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt)); + old_tx_control = phy->tx_control; + + bbatt.att = 11; + if (phy->radio_rev == 8) { + rfatt.att = 15; + rfatt.with_padmix = 1; + } else { + rfatt.att = 9; + rfatt.with_padmix = 0; + } + b43_set_txpower_g(dev, &bbatt, &rfatt, 0); + } + b43_dummy_transmission(dev); + phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); + if (B43_DEBUG) { + /* Current-Idle-TSSI sanity check. */ + if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) { + b43dbg(dev->wl, + "!WARNING! Idle-TSSI phy->cur_idle_tssi " + "measuring failed. (cur=%d, tgt=%d). Disabling TX power " + "adjustment.\n", phy->cur_idle_tssi, + phy->tgt_idle_tssi); + phy->cur_idle_tssi = 0; + } + } + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + b43_radio_read16(dev, 0x0076) + & 0xFF7B); + } else { + b43_set_txpower_g(dev, &old_bbatt, + &old_rfatt, old_tx_control); + } + } + b43_hardware_pctl_init(dev); + b43_shm_clear_tssi(dev); +} + +static void b43_phy_agcsetup(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 offset = 0x0000; + + if (phy->rev == 1) + offset = 0x4C00; + + b43_ofdmtab_write16(dev, offset, 0, 0x00FE); + b43_ofdmtab_write16(dev, offset, 1, 0x000D); + b43_ofdmtab_write16(dev, offset, 2, 0x0013); + b43_ofdmtab_write16(dev, offset, 3, 0x0019); + + if (phy->rev == 1) { + b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710); + b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83); + b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83); + b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D); + b43_phy_write(dev, 0x0455, 0x0004); + } + + b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5) + & 0x00FF) | 0x5700); + b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A) + & 0xFF80) | 0x000F); + b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A) + & 0xC07F) | 0x2B80); + b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0300); + + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) + | 0x0008); + + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xFFF0) | 0x0008); + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xF0FF) | 0x0600); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0700); + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0100); + + if (phy->rev == 1) { + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x0007); + } + + b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488) + & 0xFF00) | 0x001C); + b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488) + & 0xC0FF) | 0x0200); + b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496) + & 0xFF00) | 0x001C); + b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489) + & 0xFF00) | 0x0020); + b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489) + & 0xC0FF) | 0x0200); + b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482) + & 0xFF00) | 0x002E); + b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496) + & 0x00FF) | 0x1A00); + b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481) + & 0xFF00) | 0x0028); + b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481) + & 0x00FF) | 0x2C00); + + if (phy->rev == 1) { + b43_phy_write(dev, 0x0430, 0x092B); + b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B) + & 0xFFE1) | 0x0002); + } else { + b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B) + & 0xFFE1); + b43_phy_write(dev, 0x041F, 0x287A); + b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420) + & 0xFFF0) | 0x0004); + } + + if (phy->rev >= 6) { + b43_phy_write(dev, 0x0422, 0x287A); + b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420) + & 0x0FFF) | 0x3000); + } + + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0x8080) | 0x7874); + b43_phy_write(dev, 0x048E, 0x1C00); + + offset = 0x0800; + if (phy->rev == 1) { + offset = 0x5400; + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0600); + b43_phy_write(dev, 0x048B, 0x005E); + b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) + & 0xFF00) | 0x001E); + b43_phy_write(dev, 0x048D, 0x0002); + } + b43_ofdmtab_write16(dev, offset, 0, 0x00); + b43_ofdmtab_write16(dev, offset, 1, 0x07); + b43_ofdmtab_write16(dev, offset, 2, 0x10); + b43_ofdmtab_write16(dev, offset, 3, 0x1C); + + if (phy->rev >= 6) { + b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426) + & 0xFFFC); + b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426) + & 0xEFFF); + } +} + +static void b43_phy_setupg(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + u16 i; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + if (phy->rev == 1) { + b43_phy_write(dev, 0x0406, 0x4F19); + b43_phy_write(dev, B43_PHY_G_CRS, + (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) | + 0x0340); + b43_phy_write(dev, 0x042C, 0x005A); + b43_phy_write(dev, 0x0427, 0x001A); + + for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) + b43_ofdmtab_write16(dev, 0x5800, i, + b43_tab_finefreqg[i]); + for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]); + for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) + b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]); + } else { + /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ + b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654); + + if (phy->rev == 2) { + b43_phy_write(dev, 0x04C0, 0x1861); + b43_phy_write(dev, 0x04C1, 0x0271); + } else if (phy->rev > 2) { + b43_phy_write(dev, 0x04C0, 0x0098); + b43_phy_write(dev, 0x04C1, 0x0070); + b43_phy_write(dev, 0x04C9, 0x0080); + } + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800); + + for (i = 0; i < 64; i++) + b43_ofdmtab_write16(dev, 0x4000, i, i); + for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]); + } + + if (phy->rev <= 2) + for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1400, i, + b43_tab_noisescaleg1[i]); + else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200)) + for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1400, i, + b43_tab_noisescaleg3[i]); + else + for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1400, i, + b43_tab_noisescaleg2[i]); + + if (phy->rev == 2) + for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) + b43_ofdmtab_write16(dev, 0x5000, i, + b43_tab_sigmasqr1[i]); + else if ((phy->rev > 2) && (phy->rev <= 8)) + for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) + b43_ofdmtab_write16(dev, 0x5000, i, + b43_tab_sigmasqr2[i]); + + if (phy->rev == 1) { + for (i = 0; i < B43_TAB_RETARD_SIZE; i++) + b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]); + for (i = 4; i < 20; i++) + b43_ofdmtab_write16(dev, 0x5400, i, 0x0020); + b43_phy_agcsetup(dev); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306) && + (bus->boardinfo.rev == 0x17)) + return; + + b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002); + b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001); + } else { + for (i = 0; i < 0x20; i++) + b43_ofdmtab_write16(dev, 0x1000, i, 0x0820); + b43_phy_agcsetup(dev); + b43_phy_read(dev, 0x0400); /* dummy read */ + b43_phy_write(dev, 0x0403, 0x1000); + b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); + b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306) && + (bus->boardinfo.rev == 0x17)) + return; + + b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002); + b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001); + } +} + +/* Initialize the noisescaletable for APHY */ +static void b43_phy_init_noisescaletbl(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int i; + + for (i = 0; i < 12; i++) { + if (phy->rev == 2) + b43_ofdmtab_write16(dev, 0x1400, i, 0x6767); + else + b43_ofdmtab_write16(dev, 0x1400, i, 0x2323); + } + if (phy->rev == 2) + b43_ofdmtab_write16(dev, 0x1400, i, 0x6700); + else + b43_ofdmtab_write16(dev, 0x1400, i, 0x2300); + for (i = 0; i < 11; i++) { + if (phy->rev == 2) + b43_ofdmtab_write16(dev, 0x1400, i, 0x6767); + else + b43_ofdmtab_write16(dev, 0x1400, i, 0x2323); + } + if (phy->rev == 2) + b43_ofdmtab_write16(dev, 0x1400, i, 0x0067); + else + b43_ofdmtab_write16(dev, 0x1400, i, 0x0023); +} + +static void b43_phy_setupa(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 i; + + B43_WARN_ON(phy->type != B43_PHYTYPE_A); + switch (phy->rev) { + case 2: + b43_phy_write(dev, 0x008E, 0x3800); + b43_phy_write(dev, 0x0035, 0x03FF); + b43_phy_write(dev, 0x0036, 0x0400); + + b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051); + + b43_phy_write(dev, 0x001C, 0x0FF9); + b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F); + b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF); + b43_radio_write16(dev, 0x0002, 0x07BF); + + b43_phy_write(dev, 0x0024, 0x4680); + b43_phy_write(dev, 0x0020, 0x0003); + b43_phy_write(dev, 0x001D, 0x0F40); + b43_phy_write(dev, 0x001F, 0x1C00); + + b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A) + & 0x00FF) | 0x0400); + b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) + & 0xFBFF); + b43_phy_write(dev, 0x008E, 0x58C1); + + b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F); + b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F); + b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A); + b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030); + b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A); + + b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013); + b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013); + b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013); + b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015); + b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015); + b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019); + + b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003); + b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003); + b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007); + + for (i = 0; i < 16; i++) + b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F); + + b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044); + b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201); + b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040); + b43_ofdmtab_write16(dev, 0x3001, 0, + (b43_ofdmtab_read16(dev, 0x3001, 0) & + 0x0010) | 0x0008); + + for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++) + b43_ofdmtab_write16(dev, 0x5800, i, + b43_tab_finefreqa[i]); + for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]); + for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) + b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]); + b43_phy_init_noisescaletbl(dev); + for (i = 0; i < B43_TAB_RETARD_SIZE; i++) + b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]); + break; + case 3: + for (i = 0; i < 64; i++) + b43_ofdmtab_write16(dev, 0x4000, i, i); + + b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051); + + b43_phy_write(dev, 0x001C, 0x0FF9); + b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F); + b43_radio_write16(dev, 0x0002, 0x07BF); + + b43_phy_write(dev, 0x0024, 0x4680); + b43_phy_write(dev, 0x0020, 0x0003); + b43_phy_write(dev, 0x001D, 0x0F40); + b43_phy_write(dev, 0x001F, 0x1C00); + b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A) + & 0x00FF) | 0x0400); + + b43_ofdmtab_write16(dev, 0x3000, 1, + (b43_ofdmtab_read16(dev, 0x3000, 1) + & 0x0010) | 0x0008); + for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) { + b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]); + } + b43_phy_init_noisescaletbl(dev); + for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) { + b43_ofdmtab_write16(dev, 0x5000, i, + b43_tab_sigmasqr1[i]); + } + + b43_phy_write(dev, 0x0003, 0x1808); + + b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F); + b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F); + b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A); + b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030); + b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A); + + b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015); + b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015); + b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019); + + b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003); + b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003); + b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007); + + b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); + b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); + break; + default: + B43_WARN_ON(1); + } +} + +/* Initialize APHY. This is also called for the GPHY in some cases. */ +static void b43_phy_inita(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + u16 tval; + + might_sleep(); + + if (phy->type == B43_PHYTYPE_A) { + b43_phy_setupa(dev); + } else { + b43_phy_setupg(dev); + if (phy->gmode && + (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)) + b43_phy_write(dev, 0x046E, 0x03CF); + return; + } + + b43_phy_write(dev, B43_PHY_A_CRS, + (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340); + b43_phy_write(dev, 0x0034, 0x0001); + + //TODO: RSSI AGC + b43_phy_write(dev, B43_PHY_A_CRS, + b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14)); + b43_radio_init2060(dev); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + ((bus->boardinfo.type == SSB_BOARD_BU4306) || + (bus->boardinfo.type == SSB_BOARD_BU4309))) { + if (phy->lofcal == 0xFFFF) { + //TODO: LOF Cal + b43_radio_set_tx_iq(dev); + } else + b43_radio_write16(dev, 0x001E, phy->lofcal); + } + + b43_phy_write(dev, 0x007A, 0xF111); + + if (phy->cur_idle_tssi == 0) { + b43_radio_write16(dev, 0x0019, 0x0000); + b43_radio_write16(dev, 0x0017, 0x0020); + + tval = b43_ofdmtab_read16(dev, 0x3001, 0); + if (phy->rev == 1) { + b43_ofdmtab_write16(dev, 0x3001, 0, + (b43_ofdmtab_read16(dev, 0x3001, 0) + & 0xFF87) + | 0x0058); + } else { + b43_ofdmtab_write16(dev, 0x3001, 0, + (b43_ofdmtab_read16(dev, 0x3001, 0) + & 0xFFC3) + | 0x002C); + } + b43_dummy_transmission(dev); + phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL); + b43_ofdmtab_write16(dev, 0x3001, 0, tval); + + b43_radio_set_txpower_a(dev, 0x0018); + } + b43_shm_clear_tssi(dev); +} + +static void b43_phy_initb2(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 offset, val; + + b43_write16(dev, 0x03EC, 0x3F22); + b43_phy_write(dev, 0x0020, 0x301C); + b43_phy_write(dev, 0x0026, 0x0000); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_phy_write(dev, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + b43_phy_write(dev, 0x03E4, 0x3000); + if (phy->channel == 0xFF) + b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0); + else + b43_radio_selectchannel(dev, phy->channel, 0); + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + b43_radio_write16(dev, 0x007A, 0x000F); + b43_phy_write(dev, 0x0038, 0x0677); + b43_radio_init2050(dev); + } + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + b43_phy_write(dev, 0x0032, 0x00CC); + b43_phy_write(dev, 0x0035, 0x07C2); + b43_lo_b_measure(dev); + b43_phy_write(dev, 0x0026, 0xCC00); + if (phy->radio_ver != 0x2050) + b43_phy_write(dev, 0x0026, 0xCE00); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000); + b43_phy_write(dev, 0x002A, 0x88A3); + if (phy->radio_ver != 0x2050) + b43_phy_write(dev, 0x002A, 0x88C2); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); + b43_phy_init_pctl(dev); +} + +static void b43_phy_initb4(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 offset, val; + + b43_write16(dev, 0x03EC, 0x3F22); + b43_phy_write(dev, 0x0020, 0x301C); + b43_phy_write(dev, 0x0026, 0x0000); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_phy_write(dev, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + b43_phy_write(dev, 0x03E4, 0x3000); + if (phy->channel == 0xFF) + b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0); + else + b43_radio_selectchannel(dev, phy->channel, 0); + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + b43_radio_write16(dev, 0x007A, 0x000F); + b43_phy_write(dev, 0x0038, 0x0677); + b43_radio_init2050(dev); + } + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0032, 0x00E0); + b43_phy_write(dev, 0x0035, 0x07C2); + + b43_lo_b_measure(dev); + + b43_phy_write(dev, 0x0026, 0xCC00); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0026, 0xCE00); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100); + b43_phy_write(dev, 0x002A, 0x88A3); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x002A, 0x88C2); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + b43_calc_nrssi_slope(dev); + b43_calc_nrssi_threshold(dev); + } + b43_phy_init_pctl(dev); +} + +static void b43_phy_initb5(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + u16 offset, value; + u8 old_channel; + + if (phy->analog == 1) { + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) + | 0x0050); + } + if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type != SSB_BOARD_BU4306)) { + value = 0x2120; + for (offset = 0x00A8; offset < 0x00C7; offset++) { + b43_phy_write(dev, offset, value); + value += 0x202; + } + } + b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) + | 0x0700); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0038, 0x0667); + + if (phy->gmode || phy->rev >= 2) { + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) + | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) + | 0x0004); + } + b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); + + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + + b43_phy_write(dev, 0x001C, 0x186A); + + b43_phy_write(dev, 0x0013, + (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); + b43_phy_write(dev, 0x0035, + (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); + b43_phy_write(dev, 0x005D, + (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); + } + + if (dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | (1 << 11)); + } + + if (phy->analog == 1) { + b43_phy_write(dev, 0x0026, 0xCE00); + b43_phy_write(dev, 0x0021, 0x3763); + b43_phy_write(dev, 0x0022, 0x1BC3); + b43_phy_write(dev, 0x0023, 0x06F9); + b43_phy_write(dev, 0x0024, 0x037E); + } else + b43_phy_write(dev, 0x0026, 0xCC00); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_write16(dev, 0x03EC, 0x3F22); + + if (phy->analog == 1) + b43_phy_write(dev, 0x0020, 0x3E1C); + else + b43_phy_write(dev, 0x0020, 0x301C); + + if (phy->analog == 0) + b43_write16(dev, 0x03E4, 0x3000); + + old_channel = phy->channel; + /* Force to channel 7, even if not supported. */ + b43_radio_selectchannel(dev, 7, 0); + + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + } + + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); + + b43_radio_selectchannel(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + b43_phy_write(dev, 0x002A, 0x88A3); + + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); + + if (phy->radio_ver == 0x2050) + b43_radio_write16(dev, 0x005D, 0x000D); + + b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); +} + +static void b43_phy_initb6(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 offset, val; + u8 old_channel; + + b43_phy_write(dev, 0x003E, 0x817A); + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) | 0x0058)); + if (phy->radio_rev == 4 || phy->radio_rev == 5) { + b43_radio_write16(dev, 0x51, 0x37); + b43_radio_write16(dev, 0x52, 0x70); + b43_radio_write16(dev, 0x53, 0xB3); + b43_radio_write16(dev, 0x54, 0x9B); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x88); + b43_radio_write16(dev, 0x5D, 0x88); + b43_radio_write16(dev, 0x5E, 0x88); + b43_radio_write16(dev, 0x7D, 0x88); + b43_hf_write(dev, b43_hf_read(dev) + | B43_HF_TSSIRPSMW); + } + B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */ + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x51, 0); + b43_radio_write16(dev, 0x52, 0x40); + b43_radio_write16(dev, 0x53, 0xB7); + b43_radio_write16(dev, 0x54, 0x98); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x6B); + b43_radio_write16(dev, 0x5C, 0x0F); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) { + b43_radio_write16(dev, 0x5D, 0xFA); + b43_radio_write16(dev, 0x5E, 0xD8); + } else { + b43_radio_write16(dev, 0x5D, 0xF5); + b43_radio_write16(dev, 0x5E, 0xB8); + } + b43_radio_write16(dev, 0x0073, 0x0003); + b43_radio_write16(dev, 0x007D, 0x00A8); + b43_radio_write16(dev, 0x007C, 0x0001); + b43_radio_write16(dev, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + b43_phy_write(dev, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == B43_PHYTYPE_G) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + b43_phy_write(dev, 0x5B, 0); + b43_phy_write(dev, 0x5C, 0); + } + + old_channel = phy->channel; + if (old_channel >= 8) + b43_radio_selectchannel(dev, 1, 0); + else + b43_radio_selectchannel(dev, 13, 0); + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + udelay(40); + if (phy->radio_rev < 6 || phy->radio_rev == 8) { + b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C) + | 0x0002)); + b43_radio_write16(dev, 0x50, 0x20); + } + if (phy->radio_rev <= 2) { + b43_radio_write16(dev, 0x7C, 0x20); + b43_radio_write16(dev, 0x5A, 0x70); + b43_radio_write16(dev, 0x5B, 0x7B); + b43_radio_write16(dev, 0x5C, 0xB0); + } + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); + + b43_radio_selectchannel(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0200); + if (phy->radio_rev >= 6) + b43_phy_write(dev, 0x2A, 0x88C2); + else + b43_phy_write(dev, 0x2A, 0x8AC0); + b43_phy_write(dev, 0x0038, 0x0668); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); + if (phy->radio_rev <= 5) { + b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) + & 0xFF80) | 0x0003); + } + if (phy->radio_rev <= 2) + b43_radio_write16(dev, 0x005D, 0x000D); + + if (phy->analog == 4) { + b43_write16(dev, 0x3E4, 9); + b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) + & 0x0FFF); + } else { + b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) + | 0x0004); + } + if (phy->type == B43_PHYTYPE_B) { + b43_write16(dev, 0x03E6, 0x8140); + b43_phy_write(dev, 0x0016, 0x0410); + b43_phy_write(dev, 0x0017, 0x0820); + b43_phy_write(dev, 0x0062, 0x0007); + b43_radio_init2050(dev); + b43_lo_g_measure(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + b43_calc_nrssi_slope(dev); + b43_calc_nrssi_threshold(dev); + } + b43_phy_init_pctl(dev); + } else if (phy->type == B43_PHYTYPE_G) + b43_write16(dev, 0x03E6, 0x0); +} + +static void b43_calc_loopback_gain(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 backup_phy[16] = { 0 }; + u16 backup_radio[3]; + u16 backup_bband; + u16 i, j, loop_i_max; + u16 trsw_rx; + u16 loop1_outer_done, loop1_inner_done; + + backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0); + backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); + backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER); + backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); + backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + } + backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A)); + backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59)); + backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58)); + backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A)); + backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03)); + backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); + backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); + backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B)); + backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); + backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + backup_bband = phy->bbatt.att; + backup_radio[0] = b43_radio_read16(dev, 0x52); + backup_radio[1] = b43_radio_read16(dev, 0x43); + backup_radio[2] = b43_radio_read16(dev, 0x7A); + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, + b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFE); + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFD); + } + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xFFCF) | 0x10); + + b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780); + b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + + b43_phy_write(dev, B43_PHY_BASE(0x0A), + b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFB); + } + b43_phy_write(dev, B43_PHY_BASE(0x03), + (b43_phy_read(dev, B43_PHY_BASE(0x03)) + & 0xFF9F) | 0x40); + + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x000F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x9); + } + b43_phy_set_baseband_attenuation(dev, 11); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + + b43_phy_write(dev, B43_PHY_BASE(0x2B), + (b43_phy_read(dev, B43_PHY_BASE(0x2B)) + & 0xFFC0) | 0x01); + b43_phy_write(dev, B43_PHY_BASE(0x2B), + (b43_phy_read(dev, B43_PHY_BASE(0x2B)) + & 0xC0FF) | 0x800); + + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); + + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) { + if (phy->rev >= 7) { + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) + | 0x0800); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x8000); + } + } + b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) + & 0x00F7); + + j = 0; + loop_i_max = (phy->radio_rev == 8) ? 15 : 9; + for (i = 0; i < loop_i_max; i++) { + for (j = 0; j < 16; j++) { + b43_radio_write16(dev, 0x43, i); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop1; + } + } + exit_loop1: + loop1_outer_done = i; + loop1_inner_done = j; + if (j >= 8) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x30); + trsw_rx = 0x1B; + for (j = j - 8; j < 16; j++) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + trsw_rx -= 3; + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop2; + } + } else + trsw_rx = 0x18; + exit_loop2: + + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); + } + b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]); + b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]); + b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]); + b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]); + b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]); + b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); + b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); + b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]); + b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); + + b43_phy_set_baseband_attenuation(dev, backup_bband); + + b43_radio_write16(dev, 0x52, backup_radio[0]); + b43_radio_write16(dev, 0x43, backup_radio[1]); + b43_radio_write16(dev, 0x7A, backup_radio[2]); + + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003); + udelay(10); + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]); + b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]); + b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]); + + phy->max_lb_gain = + ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11; + phy->trsw_rx_gain = trsw_rx * 2; +} + +static void b43_phy_initg(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + + if (phy->rev == 1) + b43_phy_initb5(dev); + else + b43_phy_initb6(dev); + + if (phy->rev >= 2 || phy->gmode) + b43_phy_inita(dev); + + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_ANALOGOVER, 0); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0); + } + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_RFOVER, 0); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->rev > 5) { + b43_phy_write(dev, B43_PHY_RFOVER, 0x400); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->gmode || phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM); + tmp &= B43_PHYVER_VERSION; + if (tmp == 3 || tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); + } + if (tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xCC), + (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) + & 0x00FF) | 0x1F00); + } + } + if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) + b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); + if (phy->radio_rev == 8) { + b43_phy_write(dev, B43_PHY_EXTG(0x01), + b43_phy_read(dev, B43_PHY_EXTG(0x01)) + | 0x80); + b43_phy_write(dev, B43_PHY_OFDM(0x3E), + b43_phy_read(dev, B43_PHY_OFDM(0x3E)) + | 0x4); + } + if (has_loopback_gain(phy)) + b43_calc_loopback_gain(dev); + + if (phy->radio_rev != 8) { + if (phy->initval == 0xFFFF) + phy->initval = b43_radio_init2050(dev); + else + b43_radio_write16(dev, 0x0078, phy->initval); + } + if (phy->lo_control->tx_bias == 0xFF) { + b43_lo_g_measure(dev); + } else { + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFF00) + | phy->lo_control->tx_bias | phy-> + lo_control->tx_magn); + } else { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFFF0) + | phy->lo_control->tx_bias); + } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_BASE(0x36), + (b43_phy_read(dev, B43_PHY_BASE(0x36)) + & 0x0FFF) | (phy->lo_control-> + tx_bias << 12)); + } + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075); + else + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F); + if (phy->rev < 2) + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101); + else + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202); + } + if (phy->gmode || phy->rev >= 2) { + b43_lo_g_adjust(dev); + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); + } + + if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the limit_value() in nrssi_hw_update()) + */ + b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? + b43_calc_nrssi_threshold(dev); + } else if (phy->gmode || phy->rev >= 2) { + if (phy->nrssi[0] == -1000) { + B43_WARN_ON(phy->nrssi[1] != -1000); + b43_calc_nrssi_slope(dev); + } else + b43_calc_nrssi_threshold(dev); + } + if (phy->radio_rev == 8) + b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230); + b43_phy_init_pctl(dev); + /* FIXME: The spec says in the following if, the 0 should be replaced + 'if OFDM may not be used in the current locale' + but OFDM is legal everywhere */ + if ((dev->dev->bus->chip_id == 0x4306 + && dev->dev->bus->chip_package == 2) || 0) { + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0xBFFF); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), + b43_phy_read(dev, B43_PHY_OFDM(0xC3)) + & 0x7FFF); + } +} + +/* Set the baseband attenuation value on chip. */ +void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->analog == 0) { + b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0) + & 0xFFF0) | + baseband_attenuation); + } else if (phy->analog > 1) { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFFC3) | (baseband_attenuation << 2)); + } else { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFF87) | (baseband_attenuation << 3)); + } +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) +{ + struct b43_phy *phy = &dev->phy; + s8 dbm = 0; + s32 tmp; + + tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi); + + switch (phy->type) { + case B43_PHYTYPE_A: + tmp += 0x80; + tmp = limit_value(tmp, 0x00, 0xFF); + dbm = phy->tssi2dbm[tmp]; + //TODO: There's a FIXME on the specs + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + tmp = limit_value(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + B43_WARN_ON(1); + } + + return dbm; +} + +void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt) +{ + int rfatt = *_rfatt; + int bbatt = *_bbatt; + struct b43_txpower_lo_control *lo = dev->phy.lo_control; + + /* Get baseband and radio attenuation values into their permitted ranges. + * Radio attenuation affects power level 4 times as much as baseband. */ + + /* Range constants */ + const int rf_min = lo->rfatt_list.min_val; + const int rf_max = lo->rfatt_list.max_val; + const int bb_min = lo->bbatt_list.min_val; + const int bb_max = lo->bbatt_list.max_val; + + while (1) { + if (rfatt > rf_max && bbatt > bb_max - 4) + break; /* Can not get it into ranges */ + if (rfatt < rf_min && bbatt < bb_min + 4) + break; /* Can not get it into ranges */ + if (bbatt > bb_max && rfatt > rf_max - 1) + break; /* Can not get it into ranges */ + if (bbatt < bb_min && rfatt < rf_min + 1) + break; /* Can not get it into ranges */ + + if (bbatt > bb_max) { + bbatt -= 4; + rfatt += 1; + continue; + } + if (bbatt < bb_min) { + bbatt += 4; + rfatt -= 1; + continue; + } + if (rfatt > rf_max) { + rfatt -= 1; + bbatt += 4; + continue; + } + if (rfatt < rf_min) { + rfatt += 1; + bbatt -= 4; + continue; + } + break; + } + + *_rfatt = limit_value(rfatt, rf_min, rf_max); + *_bbatt = limit_value(bbatt, bb_min, bb_max); +} + +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void b43_phy_xmitpower(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + if (phy->cur_idle_tssi == 0) + return; + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; +#ifdef CONFIG_B43_DEBUG + if (phy->manual_txpower_control) + return; +#endif + + switch (phy->type) { + case B43_PHYTYPE_A:{ + + //TODO: Nothing for A PHYs yet :-/ + + break; + } + case B43_PHYTYPE_B: + case B43_PHYTYPE_G:{ + u16 tmp; + s8 v0, v1, v2, v3; + s8 average; + int max_pwr; + int desired_pwr, estimated_pwr, pwr_adjust; + int rfatt_delta, bbatt_delta; + int rfatt, bbatt; + u8 tx_control; + unsigned long phylock_flags; + + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); + v0 = (s8) (tmp & 0x00FF); + v1 = (s8) ((tmp & 0xFF00) >> 8); + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); + v2 = (s8) (tmp & 0x00FF); + v3 = (s8) ((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F + || v3 == 0x7F) { + tmp = + b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); + v0 = (s8) (tmp & 0x00FF); + v1 = (s8) ((tmp & 0xFF00) >> 8); + tmp = + b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); + v2 = (s8) (tmp & 0x00FF); + v3 = (s8) ((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F + || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + b43_shm_clear_tssi(dev); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp + && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & + 0x8)) + average -= 13; + + estimated_pwr = + b43_phy_estimate_power_out(dev, average); + + max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; + if ((dev->dev->bus->sprom.r1. + boardflags_lo & B43_BFL_PACTRL) + && (phy->type == B43_PHYTYPE_G)) + max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = 60; /* fake it */ + dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + } + + /*TODO: + max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ + + /* Get desired power (in Q5.2) */ + desired_pwr = INT_TO_Q52(phy->power_level); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = limit_value(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "Current TX power output: " Q52_FMT + " dBm, " "Desired TX power output: " + Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr)); + } + + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; + + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; + + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; + + /* So do we finally need to adjust something? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) { + b43_lo_g_ctl_mark_cur_used(dev); + return; + } + + /* Calculate the new attenuation values. */ + bbatt = phy->bbatt.att; + bbatt += bbatt_delta; + rfatt = phy->rfatt.att; + rfatt += rfatt_delta; + + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + tx_control = phy->tx_control; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (rfatt <= 1) { + if (tx_control == 0) { + tx_control = + B43_TXCTL_PA2DB | + B43_TXCTL_TXMIX; + rfatt += 2; + bbatt += 2; + } else if (dev->dev->bus->sprom.r1. + boardflags_lo & + B43_BFL_PACTRL) { + bbatt += 4 * (rfatt - 2); + rfatt = 2; + } + } else if (rfatt > 4 && tx_control) { + tx_control = 0; + if (bbatt < 3) { + rfatt -= 3; + bbatt += 2; + } else { + rfatt -= 2; + bbatt -= 2; + } + } + } + /* Save the control values */ + phy->tx_control = tx_control; + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + phy->rfatt.att = rfatt; + phy->bbatt.att = bbatt; + + /* Adjust the hardware */ + b43_phy_lock(dev, phylock_flags); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, + phy->tx_control); + b43_lo_g_ctl_mark_cur_used(dev); + b43_radio_unlock(dev); + b43_phy_unlock(dev, phylock_flags); + break; + } + default: + B43_WARN_ON(1); + } +} + +static inline s32 b43_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num / den; + else + return (num + den / 2) / den; +} + +static inline + s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1, m2, f = 256, q, delta; + s8 i = 0; + + m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43_tssi2dbm_ad(f * 4096 - + b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + s16 pab0, pab1, pab2; + u8 idx; + s8 *dyn_tssi2dbm; + + if (phy->type == B43_PHYTYPE_A) { + pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0); + pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1); + pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2); + } else { + pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2); + } + + if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_b_table; + return 0; + } + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if (phy->type == B43_PHYTYPE_A) { + if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 && + (s8) dev->dev->bus->sprom.r1.itssi_a != -1) + phy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.r1.itssi_a); + else + phy->tgt_idle_tssi = 62; + } else { + if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.r1.itssi_bg != -1) + phy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.r1.itssi_bg); + else + phy->tgt_idle_tssi = 62; + } + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + b43err(dev->wl, "Could not allocate memory" + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (b43_tssi2dbm_entry + (dyn_tssi2dbm, idx, pab0, pab1, pab2)) { + phy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(dyn_tssi2dbm); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + switch (phy->type) { + case B43_PHYTYPE_A: + /* APHY needs a generated table. */ + phy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; + case B43_PHYTYPE_B: + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_b_table; + break; + case B43_PHYTYPE_G: + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_g_table; + break; + } + } + + return 0; +} + +int b43_phy_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int err = -ENODEV; + + switch (phy->type) { + case B43_PHYTYPE_A: + if (phy->rev == 2 || phy->rev == 3) { + b43_phy_inita(dev); + err = 0; + } + break; + case B43_PHYTYPE_B: + switch (phy->rev) { + case 2: + b43_phy_initb2(dev); + err = 0; + break; + case 4: + b43_phy_initb4(dev); + err = 0; + break; + case 5: + b43_phy_initb5(dev); + err = 0; + break; + case 6: + b43_phy_initb6(dev); + err = 0; + break; + } + break; + case B43_PHYTYPE_G: + b43_phy_initg(dev); + err = 0; + break; + } + if (err) + b43err(dev->wl, "Unknown PHYTYPE found\n"); + + return err; +} + +void b43_set_rx_antenna(struct b43_wldev *dev, int antenna) +{ + struct b43_phy *phy = &dev->phy; + u32 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); + + switch (phy->type) { + case B43_PHYTYPE_A: + case B43_PHYTYPE_G: + tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + + if (autodiv) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + if (antenna == B43_ANTENNA_AUTO0) + tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; + else + tmp |= B43_PHY_ANTDWELL_AUTODIV1; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } + if (phy->type == B43_PHYTYPE_G) { + 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 (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 >= 6) + b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); + } else { + 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); + } 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); + } + } + } + break; + case B43_PHYTYPE_B: + tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp); + break; + default: + B43_WARN_ON(1); + } + + hf |= B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); +} + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_bg(u8 channel) +{ + B43_WARN_ON(!(channel >= 1 && channel <= 14)); + + return b43_radio_channel_codes_bg[channel - 1]; +} + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_a(u8 channel) +{ + B43_WARN_ON(channel > 200); + + return (5000 + 5 * channel); +} + +void b43_radio_lock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl |= B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write and wait for the device + * to exit any radio register access. */ + b43_read32(dev, B43_MMIO_MACCTL); + udelay(10); +} + +void b43_radio_unlock(struct b43_wldev *dev) +{ + u32 macctl; + + /* Commit any write */ + b43_read16(dev, B43_MMIO_PHY_VER); + /* unlock */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); +} + +u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) +{ + struct b43_phy *phy = &dev->phy; + + switch (phy->type) { + case B43_PHYTYPE_A: + offset |= 0x0040; + break; + case B43_PHYTYPE_B: + if (phy->radio_ver == 0x2053) { + if (offset < 0x70) + offset += 0x80; + else if (offset < 0x80) + offset += 0x70; + } else if (phy->radio_ver == 0x2050) { + offset |= 0x80; + } else + B43_WARN_ON(1); + break; + case B43_PHYTYPE_G: + offset |= 0x80; + break; + } + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val) +{ + b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); + mmiowb(); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val); +} + +static void b43_set_all_gains(struct b43_wldev *dev, + s16 first, s16 second, s16 third) +{ + struct b43_phy *phy = &dev->phy; + u16 i; + u16 start = 0x08, end = 0x18; + u16 tmp; + u16 table; + + if (phy->rev <= 1) { + start = 0x10; + end = 0x20; + } + + table = B43_OFDMTAB_GAINX; + if (phy->rev <= 1) + table = B43_OFDMTAB_GAINX_R1; + for (i = 0; i < 4; i++) + b43_ofdmtab_write16(dev, table, i, first); + + for (i = start; i < end; i++) + b43_ofdmtab_write16(dev, table, i, second); + + if (third != -1) { + tmp = ((u16) third << 14) | ((u16) third << 6); + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp); + } + b43_dummy_transmission(dev); +} + +static void b43_set_original_gains(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 i, tmp; + u16 table; + u16 start = 0x0008, end = 0x0018; + + if (phy->rev <= 1) { + start = 0x0010; + end = 0x0020; + } + + table = B43_OFDMTAB_GAINX; + if (phy->rev <= 1) + table = B43_OFDMTAB_GAINX_R1; + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + b43_ofdmtab_write16(dev, table, i, tmp); + } + + for (i = start; i < end; i++) + b43_ofdmtab_write16(dev, table, i, i - start); + + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000); + b43_dummy_transmission(dev); +} + +/* Synthetic PU workaround */ +static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + + might_sleep(); + + if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { + /* We do not need the workaround. */ + return; + } + + if (channel <= 10) { + b43_write16(dev, B43_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1)); + } + msleep(1); + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); +} + +u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + u8 ret = 0; + u16 saved, rssi, temp; + int i, j = 0; + + saved = b43_phy_read(dev, 0x0403); + b43_radio_selectchannel(dev, channel, 0); + b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); + if (phy->aci_hw_rssi) + rssi = b43_phy_read(dev, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0; i < 100; i++) { + temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + b43_phy_write(dev, 0x0403, saved); + + return ret; +} + +u8 b43_radio_aci_scan(struct b43_wldev * dev) +{ + struct b43_phy *phy = &dev->phy; + u8 ret[13]; + unsigned int channel = phy->channel; + unsigned int i, j, start, end; + unsigned long phylock_flags; + + if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + b43_phy_lock(dev, phylock_flags); + b43_radio_lock(dev); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_set_all_gains(dev, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i - 1] = b43_radio_aci_detect(dev, i); + } + b43_radio_selectchannel(dev, channel, 0); + b43_phy_write(dev, 0x0802, + (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); + b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + b43_set_original_gains(dev); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + b43_radio_unlock(dev); + b43_phy_unlock(dev, phylock_flags); + + return ret[channel - 1]; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) +{ + b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); + mmiowb(); + b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) +{ + u16 val; + + b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); + val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA); + + return (s16) val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = b43_nrssi_hw_read(dev, i); + tmp -= val; + tmp = limit_value(tmp, -32, 31); + b43_nrssi_hw_write(dev, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_mem_update(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + s16 i, delta; + s32 tmp; + + delta = 0x1F - phy->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * phy->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = limit_value(tmp, 0, 0x3F); + phy->nrssi_lt[i] = tmp; + } +} + +static void b43_calc_nrssi_offset(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = b43_phy_read(dev, 0x0001); + backup[1] = b43_phy_read(dev, 0x0811); + backup[2] = b43_phy_read(dev, 0x0812); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup[3] = b43_phy_read(dev, 0x0814); + backup[4] = b43_phy_read(dev, 0x0815); + } + backup[5] = b43_phy_read(dev, 0x005A); + backup[6] = b43_phy_read(dev, 0x0059); + backup[7] = b43_phy_read(dev, 0x0058); + backup[8] = b43_phy_read(dev, 0x000A); + backup[9] = b43_phy_read(dev, 0x0003); + backup[10] = b43_radio_read16(dev, 0x007A); + backup[11] = b43_radio_read16(dev, 0x0043); + + b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF); + b43_phy_write(dev, 0x0001, + (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000); + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = b43_phy_read(dev, 0x002E); + backup[13] = b43_phy_read(dev, 0x002F); + backup[14] = b43_phy_read(dev, 0x080F); + backup[15] = b43_phy_read(dev, 0x0810); + backup[16] = b43_phy_read(dev, 0x0801); + backup[17] = b43_phy_read(dev, 0x0060); + backup[18] = b43_phy_read(dev, 0x0014); + backup[19] = b43_phy_read(dev, 0x0478); + + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, 0x002F, 0); + b43_phy_write(dev, 0x080F, 0); + b43_phy_write(dev, 0x0810, 0); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200); + } + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070); + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + b43_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = + (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, + b43_phy_read(dev, 0x0814) | 0x0001); + b43_phy_write(dev, 0x0815, + b43_phy_read(dev, 0x0815) & 0xFFFE); + } + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C); + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030); + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + if (phy->rev == 0) { + b43_phy_write(dev, 0x0003, 0x0122); + } else { + b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A) + | 0x2000); + } + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, + b43_phy_read(dev, 0x0814) | 0x0004); + b43_phy_write(dev, 0x0815, + b43_phy_read(dev, 0x0815) & 0xFFFB); + } + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F) + | 0x0040); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_set_all_gains(dev, 3, 0, 1); + b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + b43_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = + (s16) ((b43_phy_read(dev, 0x047F) >> 8) & + 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + b43_radio_write16(dev, 0x007B, saved); + + if (phy->rev >= 6) { + b43_phy_write(dev, 0x002E, backup[12]); + b43_phy_write(dev, 0x002F, backup[13]); + b43_phy_write(dev, 0x080F, backup[14]); + b43_phy_write(dev, 0x0810, backup[15]); + } + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, backup[3]); + b43_phy_write(dev, 0x0815, backup[4]); + } + b43_phy_write(dev, 0x005A, backup[5]); + b43_phy_write(dev, 0x0059, backup[6]); + b43_phy_write(dev, 0x0058, backup[7]); + b43_phy_write(dev, 0x000A, backup[8]); + b43_phy_write(dev, 0x0003, backup[9]); + b43_radio_write16(dev, 0x0043, backup[11]); + b43_radio_write16(dev, 0x007A, backup[10]); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2); + b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000); + b43_set_original_gains(dev); + if (phy->rev >= 6) { + b43_phy_write(dev, 0x0801, backup[16]); + b43_phy_write(dev, 0x0060, backup[17]); + b43_phy_write(dev, 0x0014, backup[18]); + b43_phy_write(dev, 0x0478, backup[19]); + } + b43_phy_write(dev, 0x0001, backup[0]); + b43_phy_write(dev, 0x0812, backup[2]); + b43_phy_write(dev, 0x0811, backup[1]); +} + +void b43_calc_nrssi_slope(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0, nrssi1; + + switch (phy->type) { + case B43_PHYTYPE_B: + backup[0] = b43_radio_read16(dev, 0x007A); + backup[1] = b43_radio_read16(dev, 0x0052); + backup[2] = b43_radio_read16(dev, 0x0043); + backup[3] = b43_phy_read(dev, 0x0030); + backup[4] = b43_phy_read(dev, 0x0026); + backup[5] = b43_phy_read(dev, 0x0015); + backup[6] = b43_phy_read(dev, 0x002A); + backup[7] = b43_phy_read(dev, 0x0020); + backup[8] = b43_phy_read(dev, 0x005A); + backup[9] = b43_phy_read(dev, 0x0059); + backup[10] = b43_phy_read(dev, 0x0058); + backup[11] = b43_read16(dev, 0x03E2); + backup[12] = b43_read16(dev, 0x03E6); + backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); + + tmp = b43_radio_read16(dev, 0x007A); + tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; + b43_radio_write16(dev, 0x007A, tmp); + b43_phy_write(dev, 0x0030, 0x00FF); + b43_write16(dev, 0x03EC, 0x7F7F); + b43_phy_write(dev, 0x0026, 0x0000); + b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020); + b43_phy_write(dev, 0x002A, 0x08A3); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0080); + + nrssi0 = (s16) b43_phy_read(dev, 0x0027); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev >= 2) { + b43_write16(dev, 0x03E6, 0x0040); + } else if (phy->rev == 0) { + b43_write16(dev, 0x03E6, 0x0122); + } else { + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, + B43_MMIO_CHANNEL_EXT) & 0x2000); + } + b43_phy_write(dev, 0x0020, 0x3F3F); + b43_phy_write(dev, 0x0015, 0xF330); + b43_radio_write16(dev, 0x005A, 0x0060); + b43_radio_write16(dev, 0x0043, + b43_radio_read16(dev, 0x0043) & 0x00F0); + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + udelay(20); + + nrssi1 = (s16) b43_phy_read(dev, 0x0027); + b43_phy_write(dev, 0x0030, backup[3]); + b43_radio_write16(dev, 0x007A, backup[0]); + b43_write16(dev, 0x03E2, backup[11]); + b43_phy_write(dev, 0x0026, backup[4]); + b43_phy_write(dev, 0x0015, backup[5]); + b43_phy_write(dev, 0x002A, backup[6]); + b43_synth_pu_workaround(dev, phy->channel); + if (phy->rev != 0) + b43_write16(dev, 0x03F4, backup[13]); + + b43_phy_write(dev, 0x0020, backup[7]); + b43_phy_write(dev, 0x005A, backup[8]); + b43_phy_write(dev, 0x0059, backup[9]); + b43_phy_write(dev, 0x0058, backup[10]); + b43_radio_write16(dev, 0x0052, backup[1]); + b43_radio_write16(dev, 0x0043, backup[2]); + + if (nrssi0 == nrssi1) + phy->nrssislope = 0x00010000; + else + phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + + if (nrssi0 <= -4) { + phy->nrssi[0] = nrssi0; + phy->nrssi[1] = nrssi1; + } + break; + case B43_PHYTYPE_G: + if (phy->radio_rev >= 9) + return; + if (phy->radio_rev == 8) + b43_calc_nrssi_offset(dev); + + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + backup[7] = b43_read16(dev, 0x03E2); + b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); + backup[0] = b43_radio_read16(dev, 0x007A); + backup[1] = b43_radio_read16(dev, 0x0052); + backup[2] = b43_radio_read16(dev, 0x0043); + backup[3] = b43_phy_read(dev, 0x0015); + backup[4] = b43_phy_read(dev, 0x005A); + backup[5] = b43_phy_read(dev, 0x0059); + backup[6] = b43_phy_read(dev, 0x0058); + backup[8] = b43_read16(dev, 0x03E6); + backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = b43_phy_read(dev, 0x002E); + backup[11] = b43_phy_read(dev, 0x002F); + backup[12] = b43_phy_read(dev, 0x080F); + backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL); + backup[14] = b43_phy_read(dev, 0x0801); + backup[15] = b43_phy_read(dev, 0x0060); + backup[16] = b43_phy_read(dev, 0x0014); + backup[17] = b43_phy_read(dev, 0x0478); + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: + case 6: + case 7: + b43_phy_write(dev, 0x0478, + b43_phy_read(dev, 0x0478) + | 0x0100); + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + | 0x0040); + break; + case 3: + case 5: + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + & 0xFFBF); + break; + } + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) + | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) + | 0x0200); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0070); + b43_set_all_gains(dev, 0, 8, 0); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x00F7); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0030); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0010); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(20); + + nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + } + + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | 0x2000); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_phy_write(dev, 0x0015, 0xF330); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0020); + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0020); + } + + b43_set_all_gains(dev, 3, 0, 1); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x0043, 0x001F); + } else { + tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F; + b43_radio_write16(dev, 0x0052, tmp | 0x0060); + tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0; + b43_radio_write16(dev, 0x0043, tmp | 0x0009); + } + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + phy->nrssislope = 0x00010000; + else + phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + phy->nrssi[0] = nrssi1; + phy->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + b43_phy_write(dev, 0x002E, backup[10]); + b43_phy_write(dev, 0x002F, backup[11]); + b43_phy_write(dev, 0x080F, backup[12]); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); + } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + b43_phy_read(dev, 0x0812) & 0xFFCF); + b43_phy_write(dev, 0x0811, + b43_phy_read(dev, 0x0811) & 0xFFCF); + } + + b43_radio_write16(dev, 0x007A, backup[0]); + b43_radio_write16(dev, 0x0052, backup[1]); + b43_radio_write16(dev, 0x0043, backup[2]); + b43_write16(dev, 0x03E2, backup[7]); + b43_write16(dev, 0x03E6, backup[8]); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]); + b43_phy_write(dev, 0x0015, backup[3]); + b43_phy_write(dev, 0x005A, backup[4]); + b43_phy_write(dev, 0x0059, backup[5]); + b43_phy_write(dev, 0x0058, backup[6]); + b43_synth_pu_workaround(dev, phy->channel); + b43_phy_write(dev, 0x0802, + b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); + b43_set_original_gains(dev); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + if (phy->rev >= 3) { + b43_phy_write(dev, 0x0801, backup[14]); + b43_phy_write(dev, 0x0060, backup[15]); + b43_phy_write(dev, 0x0014, backup[16]); + b43_phy_write(dev, 0x0478, backup[17]); + } + b43_nrssi_mem_update(dev); + b43_calc_nrssi_threshold(dev); + break; + default: + B43_WARN_ON(1); + } +} + +void b43_calc_nrssi_threshold(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + s32 threshold; + s32 a, b; + s16 tmp16; + u16 tmp_u16; + + switch (phy->type) { + case B43_PHYTYPE_B:{ + if (phy->radio_ver != 0x2050) + return; + if (! + (dev->dev->bus->sprom.r1. + boardflags_lo & B43_BFL_RSSI)) + return; + + if (phy->radio_rev >= 6) { + threshold = + (phy->nrssi[1] - phy->nrssi[0]) * 32; + threshold += 20 * (phy->nrssi[0] + 1); + threshold /= 40; + } else + threshold = phy->nrssi[1] - 5; + + threshold = limit_value(threshold, 0, 0x3E); + b43_phy_read(dev, 0x0020); /* dummy read */ + b43_phy_write(dev, 0x0020, + (((u16) threshold) << 8) | 0x001C); + + if (phy->radio_rev >= 6) { + b43_phy_write(dev, 0x0087, 0x0E0D); + b43_phy_write(dev, 0x0086, 0x0C0B); + b43_phy_write(dev, 0x0085, 0x0A09); + b43_phy_write(dev, 0x0084, 0x0808); + b43_phy_write(dev, 0x0083, 0x0808); + b43_phy_write(dev, 0x0082, 0x0604); + b43_phy_write(dev, 0x0081, 0x0302); + b43_phy_write(dev, 0x0080, 0x0100); + } + break; + } + case B43_PHYTYPE_G: + if (!phy->gmode || + !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) { + tmp16 = b43_nrssi_hw_read(dev, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x09EB); + } else { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x0AED); + } + } else { + if (phy->interfmode == B43_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!phy->aci_wlan_automatic && phy->aci_enable) { + a = 0x13; + b = 0x12; + } else { + a = 0xE; + b = 0x11; + } + + a = a * (phy->nrssi[1] - phy->nrssi[0]); + a += (phy->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; + a = limit_value(a, -31, 31); + + b = b * (phy->nrssi[1] - phy->nrssi[0]); + b += (phy->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; + b = limit_value(b, -31, 31); + + tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; + tmp_u16 |= ((u32) b & 0x0000003F); + tmp_u16 |= (((u32) a & 0x0000003F) << 6); + b43_phy_write(dev, 0x048A, tmp_u16); + } + break; + default: + B43_WARN_ON(1); + } +} + +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 * _stackptr, size_t * stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + B43_WARN_ON(offset & 0xF000); + B43_WARN_ON(id & 0xF0); + *stackptr = offset; + *stackptr |= ((u32) id) << 12; + *stackptr |= ((u32) value) << 16; + (*stackidx)++; + B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE); +} + +static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset) +{ + size_t i; + + B43_WARN_ON(offset & 0xF000); + B43_WARN_ON(id & 0xF0); + for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00000FFF) != offset) + continue; + if (((*stackptr & 0x0000F000) >> 12) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + B43_WARN_ON(1); + + return 0; +} + +#define phy_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + b43_phy_read(dev, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + b43_phy_write(dev, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + b43_radio_read16(dev, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + b43_radio_write16(dev, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ofdmtab_stacksave(table, offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset)|(table), \ + b43_ofdmtab_read16(dev, (table), (offset))); \ + } while (0) +#define ofdmtab_stackrestore(table, offset) \ + do { \ + b43_ofdmtab_write16(dev, (table), (offset), \ + _stack_restore(stack, 0x3, \ + (offset)|(table))); \ + } while (0) + +static void +b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp, flipped; + size_t stackidx = 0; + u32 *stack = phy->interfstack; + + switch (mode) { + case B43_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43_phy_write(dev, 0x042B, + b43_phy_read(dev, 0x042B) | 0x0800); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, + B43_PHY_G_CRS) & ~0x4000); + break; + } + radio_stacksave(0x0078); + tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = flip_4bit(flipped); + flipped = (flipped << 1) | 0x0020; + b43_radio_write16(dev, 0x0078, flipped); + + b43_calc_nrssi_threshold(dev); + + phy_stacksave(0x0406); + b43_phy_write(dev, 0x0406, 0x7E28); + + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800); + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | 0x1000); + + phy_stacksave(0x04A0); + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008); + phy_stacksave(0x04A1); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605); + phy_stacksave(0x04A2); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204); + phy_stacksave(0x04A8); + b43_phy_write(dev, 0x04A8, + (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803); + phy_stacksave(0x04AB); + b43_phy_write(dev, 0x04AB, + (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605); + + phy_stacksave(0x04A7); + b43_phy_write(dev, 0x04A7, 0x0002); + phy_stacksave(0x04A3); + b43_phy_write(dev, 0x04A3, 0x287A); + phy_stacksave(0x04A9); + b43_phy_write(dev, 0x04A9, 0x2027); + phy_stacksave(0x0493); + b43_phy_write(dev, 0x0493, 0x32F5); + phy_stacksave(0x04AA); + b43_phy_write(dev, 0x04AA, 0x2027); + phy_stacksave(0x04AC); + b43_phy_write(dev, 0x04AC, 0x32F5); + break; + case B43_INTERFMODE_MANUALWLAN: + if (b43_phy_read(dev, 0x0033) & 0x0800) + break; + + phy->aci_enable = 1; + + phy_stacksave(B43_PHY_RADIO_BITFIELD); + phy_stacksave(B43_PHY_G_CRS); + if (phy->rev < 2) { + phy_stacksave(0x0406); + } else { + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); + } + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ofdmtab_stacksave(0x1A00, 0x2); + ofdmtab_stacksave(0x1A00, 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); + + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) + & ~0x1000); + b43_phy_write(dev, B43_PHY_G_CRS, + (b43_phy_read(dev, B43_PHY_G_CRS) + & 0xFFFC) | 0x0002); + + b43_phy_write(dev, 0x0033, 0x0800); + b43_phy_write(dev, 0x04A3, 0x2027); + b43_phy_write(dev, 0x04A9, 0x1CA8); + b43_phy_write(dev, 0x0493, 0x287A); + b43_phy_write(dev, 0x04AA, 0x1CA8); + b43_phy_write(dev, 0x04AC, 0x287A); + + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xFFC0) | 0x001A); + b43_phy_write(dev, 0x04A7, 0x000D); + + if (phy->rev < 2) { + b43_phy_write(dev, 0x0406, 0xFF0D); + } else if (phy->rev == 2) { + b43_phy_write(dev, 0x04C0, 0xFFFF); + b43_phy_write(dev, 0x04C1, 0x00A9); + } else { + b43_phy_write(dev, 0x04C0, 0x00C1); + b43_phy_write(dev, 0x04C1, 0x0059); + } + + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xC0FF) | 0x1800); + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xFFC0) | 0x0015); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xCFFF) | 0x1000); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xF0FF) | 0x0A00); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xCFFF) | 0x1000); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0800); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xFFCF) | 0x0010); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xFFF0) | 0x0005); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xFFCF) | 0x0010); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xFFF0) | 0x0006); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0800); + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0500); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x000B); + + if (phy->rev >= 3) { + b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) + & ~0x8000); + b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415) + & 0x8000) | 0x36D8); + b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416) + & 0x8000) | 0x36D8); + b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417) + & 0xFE00) | 0x016D); + } else { + b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) + | 0x1000); + b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A) + & 0x9FFF) | 0x2000); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW); + } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) + | 0x0800); + } + b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE) + & 0xFF00) | 0x007F); + b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F); + b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F); + b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD) + & 0x00FF); + } + b43_calc_nrssi_slope(dev); + break; + default: + B43_WARN_ON(1); + } +} + +static void +b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + u32 *stack = phy->interfstack; + + switch (mode) { + case B43_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43_phy_write(dev, 0x042B, + b43_phy_read(dev, 0x042B) & ~0x0800); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, + B43_PHY_G_CRS) | 0x4000); + break; + } + radio_stackrestore(0x0078); + b43_calc_nrssi_threshold(dev); + phy_stackrestore(0x0406); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800); + if (!dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + } + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + break; + case B43_INTERFMODE_MANUALWLAN: + if (!(b43_phy_read(dev, 0x0033) & 0x0800)) + break; + + phy->aci_enable = 0; + + phy_stackrestore(B43_PHY_RADIO_BITFIELD); + phy_stackrestore(B43_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ofdmtab_stackrestore(0x1A00, 0x2); + ofdmtab_stackrestore(0x1A00, 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x048A); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW); + b43_calc_nrssi_slope(dev); + break; + default: + B43_WARN_ON(1); + } +} + +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ofdmtab_stacksave +#undef ofdmtab_stackrestore + +int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + int currentmode; + + if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode)) + return -ENODEV; + + phy->aci_wlan_automatic = 0; + switch (mode) { + case B43_INTERFMODE_AUTOWLAN: + phy->aci_wlan_automatic = 1; + if (phy->aci_enable) + mode = B43_INTERFMODE_MANUALWLAN; + else + mode = B43_INTERFMODE_NONE; + break; + case B43_INTERFMODE_NONE: + case B43_INTERFMODE_NONWLAN: + case B43_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = phy->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != B43_INTERFMODE_NONE) + b43_radio_interference_mitigation_disable(dev, currentmode); + + if (mode == B43_INTERFMODE_NONE) { + phy->aci_enable = 0; + phy->aci_hw_rssi = 0; + } else + b43_radio_interference_mitigation_enable(dev, mode); + phy->interfmode = mode; + + return 0; +} + +static u16 b43_radio_core_calibration_value(struct b43_wldev *dev) +{ + u16 reg, index, ret; + + static const u8 rcc_table[] = { + 0x02, 0x03, 0x01, 0x0F, + 0x06, 0x07, 0x05, 0x0F, + 0x0A, 0x0B, 0x09, 0x0F, + 0x0E, 0x0F, 0x0D, 0x0F, + }; + + reg = b43_radio_read16(dev, 0x60); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) +static u16 radio2050_rfover_val(struct b43_wldev *dev, + u16 phy_register, unsigned int lpd) +{ + struct b43_phy *phy = &dev->phy; + struct ssb_sprom *sprom = &(dev->dev->bus->sprom); + + if (!phy->gmode) + return 0; + + if (has_loopback_gain(phy)) { + int max_lb_gain = phy->max_lb_gain; + u16 extlna; + u16 i; + + if (phy->radio_rev == 8) + max_lb_gain += 0x3E; + else + max_lb_gain += 0x26; + if (max_lb_gain >= 0x46) { + extlna = 0x3000; + max_lb_gain -= 0x46; + } else if (max_lb_gain >= 0x3A) { + extlna = 0x1000; + max_lb_gain -= 0x3A; + } else if (max_lb_gain >= 0x2E) { + extlna = 0x2000; + max_lb_gain -= 0x2E; + } else { + extlna = 0; + max_lb_gain -= 0x10; + } + + for (i = 0; i < 16; i++) { + max_lb_gain -= (i * 6); + if (max_lb_gain < 6) + break; + } + + if ((phy->rev < 7) || + !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + if (phy_register == B43_PHY_RFOVER) { + return 0x1B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + extlna |= (i << 8); + switch (lpd) { + case LPD(0, 1, 1): + return 0x0F92; + case LPD(0, 0, 1): + case LPD(1, 0, 1): + return (0x0092 | extlna); + case LPD(1, 0, 0): + return (0x0093 | extlna); + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } else { + if (phy_register == B43_PHY_RFOVER) { + return 0x9B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + if (extlna) + extlna |= 0x8000; + extlna |= (i << 8); + switch (lpd) { + case LPD(0, 1, 1): + return 0x8F92; + case LPD(0, 0, 1): + return (0x8092 | extlna); + case LPD(1, 0, 1): + return (0x2092 | extlna); + case LPD(1, 0, 0): + return (0x2093 | extlna); + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } + } else { + if ((phy->rev < 7) || + !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + if (phy_register == B43_PHY_RFOVER) { + return 0x1B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x0FB2; + case LPD(0, 0, 1): + return 0x00B2; + case LPD(1, 0, 1): + return 0x30B2; + case LPD(1, 0, 0): + return 0x30B3; + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } else { + if (phy_register == B43_PHY_RFOVER) { + return 0x9B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x8FB2; + case LPD(0, 0, 1): + return 0x80B2; + case LPD(1, 0, 1): + return 0x20B2; + case LPD(1, 0, 0): + return 0x20B3; + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } + } + return 0; +} + +struct init2050_saved_values { + /* Core registers */ + u16 reg_3EC; + u16 reg_3E6; + u16 reg_3F4; + /* Radio registers */ + u16 radio_43; + u16 radio_51; + u16 radio_52; + /* PHY registers */ + u16 phy_pgactl; + u16 phy_base_5A; + u16 phy_base_59; + u16 phy_base_58; + u16 phy_base_30; + u16 phy_rfover; + u16 phy_rfoverval; + u16 phy_analogover; + u16 phy_analogoverval; + u16 phy_crs0; + u16 phy_classctl; + u16 phy_lo_mask; + u16 phy_lo_ctl; + u16 phy_syncctl; +}; + +u16 b43_radio_init2050(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct init2050_saved_values sav; + u16 rcc; + u16 radio78; + u16 ret; + u16 i, j; + u32 tmp1 = 0, tmp2 = 0; + + memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */ + + sav.radio_43 = b43_radio_read16(dev, 0x43); + sav.radio_51 = b43_radio_read16(dev, 0x51); + sav.radio_52 = b43_radio_read16(dev, 0x52); + sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); + sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A)); + sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59)); + sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58)); + + if (phy->type == B43_PHYTYPE_B) { + sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30)); + sav.reg_3EC = b43_read16(dev, 0x3EC); + + b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF); + b43_write16(dev, 0x3EC, 0x3F3F); + } else if (phy->gmode || phy->rev >= 2) { + sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); + sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); + sav.phy_analogoverval = + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); + sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); + + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) + | 0x0003); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) + & 0xFFFC); + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_CLASSCTL, + b43_phy_read(dev, B43_PHY_CLASSCTL) + & 0xFFFC); + if (has_loopback_gain(phy)) { + sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); + sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + } + + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 1, 1))); + b43_phy_write(dev, B43_PHY_RFOVER, + radio2050_rfover_val(dev, B43_PHY_RFOVER, 0)); + } + b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); + + sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); + b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL) + & 0xFF7F); + sav.reg_3E6 = b43_read16(dev, 0x3E6); + sav.reg_3F4 = b43_read16(dev, 0x3F4); + + if (phy->analog == 0) { + b43_write16(dev, 0x03E6, 0x0122); + } else { + if (phy->analog >= 2) { + b43_phy_write(dev, B43_PHY_BASE(0x03), + (b43_phy_read(dev, B43_PHY_BASE(0x03)) + & 0xFFBF) | 0x40); + } + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000)); + } + + rcc = b43_radio_core_calibration_value(dev); + + if (phy->type == B43_PHYTYPE_B) + b43_radio_write16(dev, 0x78, 0x26); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 1, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF); + b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0); + b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51) + | 0x0004); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x1F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x0009); + } + b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480); + b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 0))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); + udelay(20); + tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + } + udelay(10); + + b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + tmp1++; + tmp1 >>= 9; + + for (i = 0; i < 16; i++) { + radio78 = ((flip_4bit(i) << 1) | 0x20); + b43_radio_write16(dev, 0x78, radio78); + udelay(10); + for (j = 0; j < 16; j++) { + b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80); + b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 0))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); + udelay(10); + tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl); + b43_radio_write16(dev, 0x51, sav.radio_51); + b43_radio_write16(dev, 0x52, sav.radio_52); + b43_radio_write16(dev, 0x43, sav.radio_43); + b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A); + b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59); + b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58); + b43_write16(dev, 0x3E6, sav.reg_3E6); + if (phy->analog != 0) + b43_write16(dev, 0x3F4, sav.reg_3F4); + b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl); + b43_synth_pu_workaround(dev, phy->channel); + if (phy->type == B43_PHYTYPE_B) { + b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30); + b43_write16(dev, 0x3EC, sav.reg_3EC); + } else if (phy->gmode) { + b43_write16(dev, B43_MMIO_PHY_RADIO, + b43_read16(dev, B43_MMIO_PHY_RADIO) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval); + b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + sav.phy_analogoverval); + b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0); + b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl); + if (has_loopback_gain(phy)) { + b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask); + b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl); + } + } + if (i > 15) + ret = radio78; + else + ret = rcc; + + return ret; +} + +void b43_radio_init2060(struct b43_wldev *dev) +{ + int err; + + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_radio_write16(dev, 0x0009, 0x0040); + b43_radio_write16(dev, 0x0005, 0x00AA); + b43_radio_write16(dev, 0x0032, 0x008F); + b43_radio_write16(dev, 0x0006, 0x008F); + b43_radio_write16(dev, 0x0034, 0x008F); + b43_radio_write16(dev, 0x002C, 0x0007); + b43_radio_write16(dev, 0x0082, 0x0080); + b43_radio_write16(dev, 0x0080, 0x0000); + b43_radio_write16(dev, 0x003F, 0x00DA); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); + b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); + b43_phy_write(dev, 0x0063, 0xDDC6); + b43_phy_write(dev, 0x0069, 0x07BE); + b43_phy_write(dev, 0x006A, 0x0000); + + err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0); + B43_WARN_ON(err); + + msleep(1); +} + +static inline u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void b43_radio_set_tx_iq(struct b43_wldev *dev) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = b43_radio_read16(dev, 0x001E); + int i, j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] << 4 | data_low[j])) { + b43_phy_write(dev, 0x0069, + (i - j) << 8 | 0x00C0); + return; + } + } + } +} + +int b43_radio_selectchannel(struct b43_wldev *dev, + u8 channel, int synthetic_pu_workaround) +{ + struct b43_phy *phy = &dev->phy; + u16 r8, tmp; + u16 freq; + u16 channelcookie; + + /* First we set the channel radio code to prevent the + * firmware from sending ghost packets. + */ + channelcookie = channel; + if (phy->type == B43_PHYTYPE_A) + channelcookie |= 0x100; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); + + if (phy->type == B43_PHYTYPE_A) { + if (channel > 200) + return -EINVAL; + freq = channel2freq_a(channel); + + r8 = b43_radio_read16(dev, 0x0008); + b43_write16(dev, 0x03F0, freq); + b43_radio_write16(dev, 0x0008, r8); + + //TODO: write max channel TX power? to Radio 0x2D + tmp = b43_radio_read16(dev, 0x002E); + tmp &= 0x0080; + //TODO: OR tmp with the Power out estimation for this channel? + b43_radio_write16(dev, 0x002E, tmp); + + if (freq >= 4920 && freq <= 5500) { + /* + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; + * = (freq * 0.025862069 + */ + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) + & 0x000F) | (r8 << 4)); + b43_radio_write16(dev, 0x002A, (r8 << 4)); + b43_radio_write16(dev, 0x002B, (r8 << 4)); + b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) + & 0x00F0) | (r8 << 4)); + b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) + & 0xFF0F) | 0x00B0); + b43_radio_write16(dev, 0x0035, 0x00AA); + b43_radio_write16(dev, 0x0036, 0x0085); + b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) + & 0xFF20) | + freq_r3A_value(freq)); + b43_radio_write16(dev, 0x003D, + b43_radio_read16(dev, 0x003D) & 0x00FF); + b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) + & 0xFF7F) | 0x0080); + b43_radio_write16(dev, 0x0035, + b43_radio_read16(dev, 0x0035) & 0xFFEF); + b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) + & 0xFFEF) | 0x0010); + b43_radio_set_tx_iq(dev); + //TODO: TSSI2dbm workaround + b43_phy_xmitpower(dev); //FIXME correct? + } else { + if ((channel < 1) || (channel > 14)) + return -EINVAL; + + if (synthetic_pu_workaround) + b43_synth_pu_workaround(dev, channel); + + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); + + if (channel == 14) { + if (dev->dev->bus->sprom.r1.country_code == + SSB_SPROM1CCODE_JAPAN) + b43_hf_write(dev, + b43_hf_read(dev) & ~B43_HF_ACPR); + else + b43_hf_write(dev, + b43_hf_read(dev) | B43_HF_ACPR); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | (1 << 11)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + & 0xF7BF); + } + } + + phy->channel = channel; + /* Wait for the radio to tune to the channel and stabilize. */ + msleep(8); + + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ +static u16 b43_get_txgain_base_band(u16 txpower) +{ + u16 ret; + + B43_WARN_ON(txpower > 63); + + if (txpower >= 54) + ret = 2; + else if (txpower >= 49) + ret = 4; + else if (txpower >= 44) + ret = 5; + else + ret = 6; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ +static u16 b43_get_txgain_freq_power_amp(u16 txpower) +{ + u16 ret; + + B43_WARN_ON(txpower > 63); + + if (txpower >= 32) + ret = 0; + else if (txpower >= 25) + ret = 1; + else if (txpower >= 20) + ret = 2; + else if (txpower >= 12) + ret = 3; + else + ret = 4; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ +static u16 b43_get_txgain_dac(u16 txpower) +{ + u16 ret; + + B43_WARN_ON(txpower > 63); + + if (txpower >= 54) + ret = txpower - 53; + else if (txpower >= 49) + ret = txpower - 42; + else if (txpower >= 44) + ret = txpower - 37; + else if (txpower >= 32) + ret = txpower - 32; + else if (txpower >= 25) + ret = txpower - 20; + else if (txpower >= 20) + ret = txpower - 13; + else if (txpower >= 12) + ret = txpower - 8; + else + ret = txpower; + + return ret; +} + +static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower) +{ + struct b43_phy *phy = &dev->phy; + u16 pamp, base, dac, t; + + txpower = limit_value(txpower, 0, 63); + + pamp = b43_get_txgain_freq_power_amp(txpower); + pamp <<= 5; + pamp &= 0x00E0; + b43_phy_write(dev, 0x0019, pamp); + + base = b43_get_txgain_base_band(txpower); + base &= 0x000F; + b43_phy_write(dev, 0x0017, base | 0x0020); + + t = b43_ofdmtab_read16(dev, 0x3000, 1); + t &= 0x0007; + + dac = b43_get_txgain_dac(txpower); + dac <<= 3; + dac |= t; + + b43_ofdmtab_write16(dev, 0x3000, 1, dac); + + phy->txpwr_offset = txpower; + + //TODO: FuncPlaceholder (Adjust BB loft cancel) +} + +void b43_radio_turn_on(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int err; + + might_sleep(); + + if (phy->radio_on) + return; + + switch (phy->type) { + case B43_PHYTYPE_A: + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7); + b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7); + b43_radio_init2060(dev); + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + b43_phy_write(dev, 0x0015, 0x8000); + b43_phy_write(dev, 0x0015, 0xCC00); + b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); + err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1); + B43_WARN_ON(err); + break; + default: + B43_WARN_ON(1); + } + phy->radio_on = 1; + b43dbg(dev->wl, "Radio turned on\n"); +} + +void b43_radio_turn_off(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->type == B43_PHYTYPE_A) { + b43_radio_write16(dev, 0x0004, 0x00FF); + b43_radio_write16(dev, 0x0005, 0x00FB); + b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); + b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); + } + if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) { + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x008C); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) & 0xFF73); + } else + b43_phy_write(dev, 0x0015, 0xAA00); + phy->radio_on = 0; + b43dbg(dev->wl, "Radio turned off\n"); +} diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h new file mode 100644 index 000000000000..d1f623cb9b34 --- /dev/null +++ b/drivers/net/wireless/b43/phy.h @@ -0,0 +1,297 @@ +#ifndef B43_PHY_H_ +#define B43_PHY_H_ + +#include + +struct b43_wldev; +struct b43_phy; + +/*** PHY Registers ***/ + +/* Routing */ +#define B43_PHYROUTE_OFDM_GPHY 0x400 +#define B43_PHYROUTE_EXT_GPHY 0x800 + +/* Base registers. */ +#define B43_PHY_BASE(reg) (reg) +/* OFDM (A) registers of a G-PHY */ +#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) +/* Extended G-PHY registers */ +#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) + +/* OFDM (A) PHY Registers */ +#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */ +#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */ +#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ +#define B43_PHY_BBANDCFG_RXANT_SHIFT 7 +#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ +#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 */ +#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ +#define B43_PHY_CRS0 B43_PHY_OFDM(0x29) +#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ +#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ +#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ +#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */ +#define B43_PHY_LMS B43_PHY_OFDM(0x55) +#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ +#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ +#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ +#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ +#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ +#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ +#define B43_PHY_OTABLENR_SHIFT 10 +#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ +#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ +#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ +#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ +#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ +#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */ +#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */ +#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0) +#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1) +#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) +#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) +#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) +#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ +#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) +#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) +#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) +#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ +#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ +#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */ +#define B43_PHY_CRSTHRES2_R1 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */ +#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ +#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ +#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ + +/* CCK (B) PHY Registers */ +#define B43_PHY_VERSION_CCK B43_PHY_BASE(0x00) /* Versioning register for B-PHY */ +#define B43_PHY_CCKBBANDCFG B43_PHY_BASE(0x01) /* Contains antenna 0/1 control bit */ +#define B43_PHY_PGACTL B43_PHY_BASE(0x15) /* PGA control */ +#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ +#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ +#define B43_PHY_PGACTL_UNKNOWN 0xEFA0 +#define B43_PHY_FBCTL1 B43_PHY_BASE(0x18) /* Frequency bandwidth control 1 */ +#define B43_PHY_ITSSI B43_PHY_BASE(0x29) /* Idle TSSI */ +#define B43_PHY_LO_LEAKAGE B43_PHY_BASE(0x2D) /* Measured LO leakage */ +#define B43_PHY_ENERGY B43_PHY_BASE(0x33) /* Energy */ +#define B43_PHY_SYNCCTL B43_PHY_BASE(0x35) +#define B43_PHY_FBCTL2 B43_PHY_BASE(0x38) /* Frequency bandwidth control 2 */ +#define B43_PHY_DACCTL B43_PHY_BASE(0x60) /* DAC control */ +#define B43_PHY_RCCALOVER B43_PHY_BASE(0x78) /* RC calibration override */ + +/* Extended G-PHY Registers */ +#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ +#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */ +#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ +#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ +#define B43_PHY_GTABNR_SHIFT 10 +#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */ +#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */ +#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */ +#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */ +#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */ +#define B43_PHY_RFOVERVAL_EXTLNA 0x8000 +#define B43_PHY_RFOVERVAL_LNA 0x7000 +#define B43_PHY_RFOVERVAL_LNA_SHIFT 12 +#define B43_PHY_RFOVERVAL_PGA 0x0F00 +#define B43_PHY_RFOVERVAL_PGA_SHIFT 8 +#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */ +#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0 +#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */ +#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */ +#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */ +#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */ +#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */ + +/*** OFDM table numbers ***/ +#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset)) +#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename +#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4) +#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0) +#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3) +#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0) +#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0) +#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0) +#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0) +#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0) +#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0) +#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) +#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) +#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) +//TODO +#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) +#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) +//TODO +#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) +#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO rename +#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 1) +#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) +#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0) +#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0) +#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0) + +u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, + u16 offset, u16 value); +u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, + u16 offset, u32 value); + +/*** G-PHY table numbers */ +#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset)) +#define B43_GTAB_NRSSI B43_GTAB(0x00, 0) +#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120) +#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298) + +u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement +void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement + +#define B43_DEFAULT_CHANNEL_A 36 +#define B43_DEFAULT_CHANNEL_BG 6 + +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_ANTENNA_AUTO = B43_ANTENNA_AUTO0, + B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, +}; + +enum { + B43_INTERFMODE_NONE, + B43_INTERFMODE_NONWLAN, + B43_INTERFMODE_MANUALWLAN, + B43_INTERFMODE_AUTOWLAN, +}; + +/* Masks for the different PHY versioning registers. */ +#define B43_PHYVER_ANALOG 0xF000 +#define B43_PHYVER_ANALOG_SHIFT 12 +#define B43_PHYVER_TYPE 0x0F00 +#define B43_PHYVER_TYPE_SHIFT 8 +#define B43_PHYVER_VERSION 0x00FF + +void b43_raw_phy_lock(struct b43_wldev *dev); +#define b43_phy_lock(dev, flags) \ + do { \ + local_irq_save(flags); \ + b43_raw_phy_lock(dev); \ + } while (0) +void b43_raw_phy_unlock(struct b43_wldev *dev); +#define b43_phy_unlock(dev, flags) \ + do { \ + b43_raw_phy_unlock(dev); \ + local_irq_restore(flags); \ + } while (0) + +u16 b43_phy_read(struct b43_wldev *dev, u16 offset); +void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val); + +int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev); + +void b43_phy_early_init(struct b43_wldev *dev); +int b43_phy_init(struct b43_wldev *dev); + +void b43_set_rx_antenna(struct b43_wldev *dev, int antenna); + +void b43_phy_xmitpower(struct b43_wldev *dev); +void b43_gphy_dc_lt_init(struct b43_wldev *dev); + +/* Returns the boolean whether the board has HardwarePowerControl */ +bool b43_has_hardware_pctl(struct b43_phy *phy); +/* Returns the boolean whether "TX Magnification" is enabled. */ +#define has_tx_magnification(phy) \ + (((phy)->rev >= 2) && \ + ((phy)->radio_ver == 0x2050) && \ + ((phy)->radio_rev == 8)) +/* Card uses the loopback gain stuff */ +#define has_loopback_gain(phy) \ + (((phy)->rev > 1) || ((phy)->gmode)) + +/* Radio Attenuation (RF Attenuation) */ +struct b43_rfatt { + u8 att; /* Attenuation value */ + bool with_padmix; /* Flag, PAD Mixer enabled. */ +}; +struct b43_rfatt_list { + /* Attenuation values list */ + const struct b43_rfatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* Baseband Attenuation */ +struct b43_bbatt { + u8 att; /* Attenuation value */ +}; +struct b43_bbatt_list { + /* Attenuation values list */ + const struct b43_bbatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* tx_control bits. */ +#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ +#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ +#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ + +/* Write BasebandAttenuation value to the device. */ +void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation); + +extern const u8 b43_radio_channel_codes_bg[]; + +void b43_radio_lock(struct b43_wldev *dev); +void b43_radio_unlock(struct b43_wldev *dev); + +u16 b43_radio_read16(struct b43_wldev *dev, u16 offset); +void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val); + +u16 b43_radio_init2050(struct b43_wldev *dev); +void b43_radio_init2060(struct b43_wldev *dev); + +void b43_radio_turn_on(struct b43_wldev *dev); +void b43_radio_turn_off(struct b43_wldev *dev); + +int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel, + int synthetic_pu_workaround); + +u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel); +u8 b43_radio_aci_scan(struct b43_wldev *dev); + +int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode); + +void b43_calc_nrssi_slope(struct b43_wldev *dev); +void b43_calc_nrssi_threshold(struct b43_wldev *dev); +s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset); +void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val); +void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val); +void b43_nrssi_mem_update(struct b43_wldev *dev); + +void b43_radio_set_tx_iq(struct b43_wldev *dev); +u16 b43_radio_calibrationvalue(struct b43_wldev *dev); + +void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt); + +void b43_set_txpower_g(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt, u8 tx_control); + +#endif /* B43_PHY_H_ */ diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c new file mode 100644 index 000000000000..4ac91fdd356e --- /dev/null +++ b/drivers/net/wireless/b43/pio.c @@ -0,0 +1,650 @@ +/* + + Broadcom B43 wireless driver + + PIO Transmission + + Copyright (c) 2005 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "pio.h" +#include "main.h" +#include "xmit.h" + +#include + +static void tx_start(struct b43_pioqueue *queue) +{ + b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT); +} + +static void tx_octet(struct b43_pioqueue *queue, u8 octet) +{ + if (queue->need_workarounds) { + b43_pio_write(queue, B43_PIO_TXDATA, octet); + b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO); + } else { + b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO); + b43_pio_write(queue, B43_PIO_TXDATA, octet); + } +} + +static u16 tx_get_next_word(const u8 * txhdr, + const u8 * packet, + size_t txhdr_size, unsigned int *pos) +{ + const u8 *source; + unsigned int i = *pos; + u16 ret; + + if (i < txhdr_size) { + source = txhdr; + } else { + source = packet; + i -= txhdr_size; + } + ret = le16_to_cpu(*((u16 *) (source + i))); + *pos += 2; + + return ret; +} + +static void tx_data(struct b43_pioqueue *queue, + u8 * txhdr, const u8 * packet, unsigned int octets) +{ + u16 data; + unsigned int i = 0; + + if (queue->need_workarounds) { + data = tx_get_next_word(txhdr, packet, + sizeof(struct b43_txhdr_fw4), &i); + b43_pio_write(queue, B43_PIO_TXDATA, data); + } + b43_pio_write(queue, B43_PIO_TXCTL, + B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI); + while (i < octets - 1) { + data = tx_get_next_word(txhdr, packet, + sizeof(struct b43_txhdr_fw4), &i); + b43_pio_write(queue, B43_PIO_TXDATA, data); + } + if (octets % 2) + tx_octet(queue, + packet[octets - sizeof(struct b43_txhdr_fw4) - 1]); +} + +static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb) +{ + if (queue->need_workarounds) { + b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]); + b43_pio_write(queue, B43_PIO_TXCTL, + B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE); + } else { + b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE); + } +} + +static u16 generate_cookie(struct b43_pioqueue *queue, + struct b43_pio_txpacket *packet) +{ + u16 cookie = 0x0000; + int packetindex; + + /* We use the upper 4 bits for the PIO + * controller ID and the lower 12 bits + * for the packet index (in the cache). + */ + switch (queue->mmio_base) { + case B43_MMIO_PIO1_BASE: + break; + case B43_MMIO_PIO2_BASE: + cookie = 0x1000; + break; + case B43_MMIO_PIO3_BASE: + cookie = 0x2000; + break; + case B43_MMIO_PIO4_BASE: + cookie = 0x3000; + break; + default: + B43_WARN_ON(1); + } + packetindex = pio_txpacket_getindex(packet); + B43_WARN_ON(packetindex & ~0x0FFF); + cookie |= (u16) packetindex; + + return cookie; +} + +static +struct b43_pioqueue *parse_cookie(struct b43_wldev *dev, + u16 cookie, struct b43_pio_txpacket **packet) +{ + struct b43_pio *pio = &dev->pio; + struct b43_pioqueue *queue = NULL; + int packetindex; + + switch (cookie & 0xF000) { + case 0x0000: + queue = pio->queue0; + break; + case 0x1000: + queue = pio->queue1; + break; + case 0x2000: + queue = pio->queue2; + break; + case 0x3000: + queue = pio->queue3; + break; + default: + B43_WARN_ON(1); + } + packetindex = (cookie & 0x0FFF); + B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS)); + *packet = &(queue->tx_packets_cache[packetindex]); + + return queue; +} + +union txhdr_union { + struct b43_txhdr_fw4 txhdr_fw4; +}; + +static void pio_tx_write_fragment(struct b43_pioqueue *queue, + struct sk_buff *skb, + struct b43_pio_txpacket *packet, + size_t txhdr_size) +{ + union txhdr_union txhdr_data; + u8 *txhdr = NULL; + unsigned int octets; + + txhdr = (u8 *) (&txhdr_data.txhdr_fw4); + + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + b43_generate_txhdr(queue->dev, + txhdr, skb->data, skb->len, + &packet->txstat.control, + generate_cookie(queue, packet)); + + tx_start(queue); + octets = skb->len + txhdr_size; + if (queue->need_workarounds) + octets--; + tx_data(queue, txhdr, (u8 *) skb->data, octets); + tx_complete(queue, skb); +} + +static void free_txpacket(struct b43_pio_txpacket *packet) +{ + struct b43_pioqueue *queue = packet->queue; + + if (packet->skb) + dev_kfree_skb_any(packet->skb); + list_move(&packet->list, &queue->txfree); + queue->nr_txfree++; +} + +static int pio_tx_packet(struct b43_pio_txpacket *packet) +{ + struct b43_pioqueue *queue = packet->queue; + struct sk_buff *skb = packet->skb; + u16 octets; + + octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4); + if (queue->tx_devq_size < octets) { + b43warn(queue->dev->wl, "PIO queue too small. " + "Dropping packet.\n"); + /* Drop it silently (return success) */ + free_txpacket(packet); + return 0; + } + B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS); + B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size); + /* Check if there is sufficient free space on the device + * TX queue. If not, return and let the TX tasklet + * retry later. + */ + if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS) + return -EBUSY; + if (queue->tx_devq_used + octets > queue->tx_devq_size) + return -EBUSY; + /* Now poke the device. */ + pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4)); + + /* Account for the packet size. + * (We must not overflow the device TX queue) + */ + queue->tx_devq_packets++; + queue->tx_devq_used += octets; + + /* Transmission started, everything ok, move the + * packet to the txrunning list. + */ + list_move_tail(&packet->list, &queue->txrunning); + + return 0; +} + +static void tx_tasklet(unsigned long d) +{ + struct b43_pioqueue *queue = (struct b43_pioqueue *)d; + struct b43_wldev *dev = queue->dev; + unsigned long flags; + struct b43_pio_txpacket *packet, *tmp_packet; + int err; + u16 txctl; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if (queue->tx_frozen) + goto out_unlock; + txctl = b43_pio_read(queue, B43_PIO_TXCTL); + if (txctl & B43_PIO_TXCTL_SUSPEND) + goto out_unlock; + + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { + /* Try to transmit the packet. This can fail, if + * the device queue is full. In case of failure, the + * packet is left in the txqueue. + * If transmission succeed, the packet is moved to txrunning. + * If it is impossible to transmit the packet, it + * is dropped. + */ + err = pio_tx_packet(packet); + if (err) + break; + } + out_unlock: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); +} + +static void setup_txqueues(struct b43_pioqueue *queue) +{ + struct b43_pio_txpacket *packet; + int i; + + queue->nr_txfree = B43_PIO_MAXTXPACKETS; + for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) { + packet = &(queue->tx_packets_cache[i]); + + packet->queue = queue; + INIT_LIST_HEAD(&packet->list); + + list_add(&packet->list, &queue->txfree); + } +} + +static +struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev, + u16 pio_mmio_base) +{ + struct b43_pioqueue *queue; + u16 qsize; + + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + goto out; + + queue->dev = dev; + queue->mmio_base = pio_mmio_base; + queue->need_workarounds = (dev->dev->id.revision < 3); + + INIT_LIST_HEAD(&queue->txfree); + INIT_LIST_HEAD(&queue->txqueue); + INIT_LIST_HEAD(&queue->txrunning); + tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue); + + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_BE); + + qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE); + if (qsize == 0) { + b43err(dev->wl, "This card does not support PIO " + "operation mode. Please use DMA mode " + "(module parameter pio=0).\n"); + goto err_freequeue; + } + if (qsize <= B43_PIO_TXQADJUST) { + b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize); + goto err_freequeue; + } + qsize -= B43_PIO_TXQADJUST; + queue->tx_devq_size = qsize; + + setup_txqueues(queue); + + out: + return queue; + + err_freequeue: + kfree(queue); + queue = NULL; + goto out; +} + +static void cancel_transfers(struct b43_pioqueue *queue) +{ + struct b43_pio_txpacket *packet, *tmp_packet; + + tasklet_disable(&queue->txtask); + + list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) + free_txpacket(packet); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) + free_txpacket(packet); +} + +static void b43_destroy_pioqueue(struct b43_pioqueue *queue) +{ + if (!queue) + return; + + cancel_transfers(queue); + kfree(queue); +} + +void b43_pio_free(struct b43_wldev *dev) +{ + struct b43_pio *pio; + + if (!b43_using_pio(dev)) + return; + pio = &dev->pio; + + b43_destroy_pioqueue(pio->queue3); + pio->queue3 = NULL; + b43_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + b43_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + b43_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; +} + +int b43_pio_init(struct b43_wldev *dev) +{ + struct b43_pio *pio = &dev->pio; + struct b43_pioqueue *queue; + int err = -ENOMEM; + + queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE); + if (!queue) + goto out; + pio->queue0 = queue; + + queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE); + if (!queue) + goto err_destroy0; + pio->queue1 = queue; + + queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE); + if (!queue) + goto err_destroy1; + pio->queue2 = queue; + + queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE); + if (!queue) + goto err_destroy2; + pio->queue3 = queue; + + if (dev->dev->id.revision < 3) + dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND; + + b43dbg(dev->wl, "PIO initialized\n"); + err = 0; + out: + return err; + + err_destroy2: + b43_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + err_destroy1: + b43_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + err_destroy0: + b43_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; + goto out; +} + +int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct b43_pioqueue *queue = dev->pio.queue1; + struct b43_pio_txpacket *packet; + + B43_WARN_ON(queue->tx_suspended); + B43_WARN_ON(list_empty(&queue->txfree)); + + packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list); + packet->skb = skb; + + memset(&packet->txstat, 0, sizeof(packet->txstat)); + memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); + + list_move_tail(&packet->list, &queue->txqueue); + queue->nr_txfree--; + queue->nr_tx_packets++; + B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS); + + tasklet_schedule(&queue->txtask); + + return 0; +} + +void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + struct b43_pioqueue *queue; + struct b43_pio_txpacket *packet; + + queue = parse_cookie(dev, status->cookie, &packet); + if (B43_WARN_ON(!queue)) + return; + + queue->tx_devq_packets--; + queue->tx_devq_used -= + (packet->skb->len + sizeof(struct b43_txhdr_fw4)); + + if (status->acked) { + packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; + } else { + if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK)) + packet->txstat.excessive_retries = 1; + } + if (status->frame_count == 0) { + /* The frame was not transmitted at all. */ + packet->txstat.retry_count = 0; + } else + packet->txstat.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, + &(packet->txstat)); + packet->skb = NULL; + + free_txpacket(packet); + /* If there are packets on the txqueue, poke the tasklet + * to transmit them. + */ + if (!list_empty(&queue->txqueue)) + tasklet_schedule(&queue->txtask); +} + +void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43_pio *pio = &dev->pio; + struct b43_pioqueue *queue; + struct ieee80211_tx_queue_stats_data *data; + + queue = pio->queue1; + data = &(stats->data[0]); + data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree; + data->limit = B43_PIO_MAXTXPACKETS; + data->count = queue->nr_tx_packets; +} + +static void pio_rx_error(struct b43_pioqueue *queue, + int clear_buffers, const char *error) +{ + int i; + + b43err(queue->dev->wl, "PIO RX error: %s\n", error); + b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY); + if (clear_buffers) { + B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE); + for (i = 0; i < 15; i++) { + /* Dummy read. */ + b43_pio_read(queue, B43_PIO_RXDATA); + } + } +} + +void b43_pio_rx(struct b43_pioqueue *queue) +{ + u16 preamble[21] = { 0 }; + struct b43_rxhdr_fw4 *rxhdr; + u16 tmp, len, macstat; + int i, preamble_readwords; + struct sk_buff *skb; + + tmp = b43_pio_read(queue, B43_PIO_RXCTL); + if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE)) + return; + b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE); + + for (i = 0; i < 10; i++) { + tmp = b43_pio_read(queue, B43_PIO_RXCTL); + if (tmp & B43_PIO_RXCTL_READY) + goto data_ready; + udelay(10); + } + b43dbg(queue->dev->wl, "PIO RX timed out\n"); + return; + data_ready: + + len = b43_pio_read(queue, B43_PIO_RXDATA); + if (unlikely(len > 0x700)) { + pio_rx_error(queue, 0, "len > 0x700"); + return; + } + if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) { + pio_rx_error(queue, 0, "len == 0"); + return; + } + preamble[0] = cpu_to_le16(len); + if (queue->mmio_base == B43_MMIO_PIO4_BASE) + preamble_readwords = 14 / sizeof(u16); + else + preamble_readwords = 18 / sizeof(u16); + for (i = 0; i < preamble_readwords; i++) { + tmp = b43_pio_read(queue, B43_PIO_RXDATA); + preamble[i + 1] = cpu_to_le16(tmp); + } + rxhdr = (struct b43_rxhdr_fw4 *)preamble; + macstat = le16_to_cpu(rxhdr->mac_status); + if (macstat & B43_RX_MAC_FCSERR) { + pio_rx_error(queue, + (queue->mmio_base == B43_MMIO_PIO1_BASE), + "Frame FCS error"); + return; + } + if (queue->mmio_base == B43_MMIO_PIO4_BASE) { + /* We received an xmit status. */ + struct b43_hwtxstatus *hw; + + hw = (struct b43_hwtxstatus *)(preamble + 1); + b43_handle_hwtxstatus(queue->dev, hw); + + return; + } + + skb = dev_alloc_skb(len); + if (unlikely(!skb)) { + pio_rx_error(queue, 1, "OOM"); + return; + } + skb_put(skb, len); + for (i = 0; i < len - 1; i += 2) { + tmp = b43_pio_read(queue, B43_PIO_RXDATA); + *((u16 *) (skb->data + i)) = cpu_to_le16(tmp); + } + if (len % 2) { + tmp = b43_pio_read(queue, B43_PIO_RXDATA); + skb->data[len - 1] = (tmp & 0x00FF); +/* The specs say the following is required, but + * it is wrong and corrupts the PLCP. If we don't do + * this, the PLCP seems to be correct. So ifdef it out for now. + */ +#if 0 + if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME) + skb->data[2] = (tmp & 0xFF00) >> 8; + else + skb->data[0] = (tmp & 0xFF00) >> 8; +#endif + } + b43_rx(queue->dev, skb, rxhdr); +} + +void b43_pio_tx_suspend(struct b43_pioqueue *queue) +{ + b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE); + b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) + | B43_PIO_TXCTL_SUSPEND); +} + +void b43_pio_tx_resume(struct b43_pioqueue *queue) +{ + b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) + & ~B43_PIO_TXCTL_SUSPEND); + b43_power_saving_ctl_bits(queue->dev, 0); + tasklet_schedule(&queue->txtask); +} + +void b43_pio_freeze_txqueues(struct b43_wldev *dev) +{ + struct b43_pio *pio; + + B43_WARN_ON(!b43_using_pio(dev)); + pio = &dev->pio; + pio->queue0->tx_frozen = 1; + pio->queue1->tx_frozen = 1; + pio->queue2->tx_frozen = 1; + pio->queue3->tx_frozen = 1; +} + +void b43_pio_thaw_txqueues(struct b43_wldev *dev) +{ + struct b43_pio *pio; + + B43_WARN_ON(!b43_using_pio(dev)); + pio = &dev->pio; + pio->queue0->tx_frozen = 0; + pio->queue1->tx_frozen = 0; + pio->queue2->tx_frozen = 0; + pio->queue3->tx_frozen = 0; + if (!list_empty(&pio->queue0->txqueue)) + tasklet_schedule(&pio->queue0->txtask); + if (!list_empty(&pio->queue1->txqueue)) + tasklet_schedule(&pio->queue1->txtask); + if (!list_empty(&pio->queue2->txqueue)) + tasklet_schedule(&pio->queue2->txtask); + if (!list_empty(&pio->queue3->txqueue)) + tasklet_schedule(&pio->queue3->txtask); +} diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h new file mode 100644 index 000000000000..46d6d2ea9b5f --- /dev/null +++ b/drivers/net/wireless/b43/pio.h @@ -0,0 +1,153 @@ +#ifndef B43_PIO_H_ +#define B43_PIO_H_ + +#include "b43.h" + +#include +#include +#include + +#define B43_PIO_TXCTL 0x00 +#define B43_PIO_TXDATA 0x02 +#define B43_PIO_TXQBUFSIZE 0x04 +#define B43_PIO_RXCTL 0x08 +#define B43_PIO_RXDATA 0x0A + +#define B43_PIO_TXCTL_WRITELO (1 << 0) +#define B43_PIO_TXCTL_WRITEHI (1 << 1) +#define B43_PIO_TXCTL_COMPLETE (1 << 2) +#define B43_PIO_TXCTL_INIT (1 << 3) +#define B43_PIO_TXCTL_SUSPEND (1 << 7) + +#define B43_PIO_RXCTL_DATAAVAILABLE (1 << 0) +#define B43_PIO_RXCTL_READY (1 << 1) + +/* PIO constants */ +#define B43_PIO_MAXTXDEVQPACKETS 31 +#define B43_PIO_TXQADJUST 80 + +/* PIO tuning knobs */ +#define B43_PIO_MAXTXPACKETS 256 + +#ifdef CONFIG_B43_PIO + +struct b43_pioqueue; +struct b43_xmitstatus; + +struct b43_pio_txpacket { + struct b43_pioqueue *queue; + struct sk_buff *skb; + struct ieee80211_tx_status txstat; + struct list_head list; +}; + +#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) + +struct b43_pioqueue { + struct b43_wldev *dev; + u16 mmio_base; + + bool tx_suspended; + bool tx_frozen; + bool need_workarounds; /* Workarounds needed for core.rev < 3 */ + + /* Adjusted size of the device internal TX buffer. */ + u16 tx_devq_size; + /* Used octets of the device internal TX buffer. */ + u16 tx_devq_used; + /* Used packet slots in the device internal TX buffer. */ + u8 tx_devq_packets; + /* Packets from the txfree list can + * be taken on incoming TX requests. + */ + struct list_head txfree; + unsigned int nr_txfree; + /* Packets on the txqueue are queued, + * but not completely written to the chip, yet. + */ + struct list_head txqueue; + /* Packets on the txrunning queue are completely + * posted to the device. We are waiting for the txstatus. + */ + struct list_head txrunning; + /* Total number or packets sent. + * (This counter can obviously wrap). + */ + unsigned int nr_tx_packets; + struct tasklet_struct txtask; + struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS]; +}; + +static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset) +{ + return b43_read16(queue->dev, queue->mmio_base + offset); +} + +static inline + void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value) +{ + b43_write16(queue->dev, queue->mmio_base + offset, value); + mmiowb(); +} + +int b43_pio_init(struct b43_wldev *dev); +void b43_pio_free(struct b43_wldev *dev); + +int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl); +void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status); +void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats); +void b43_pio_rx(struct b43_pioqueue *queue); + +/* Suspend TX queue in hardware. */ +void b43_pio_tx_suspend(struct b43_pioqueue *queue); +void b43_pio_tx_resume(struct b43_pioqueue *queue); +/* Suspend (freeze) the TX tasklet (software level). */ +void b43_pio_freeze_txqueues(struct b43_wldev *dev); +void b43_pio_thaw_txqueues(struct b43_wldev *dev); + +#else /* CONFIG_B43_PIO */ + +static inline int b43_pio_init(struct b43_wldev *dev) +{ + return 0; +} +static inline void b43_pio_free(struct b43_wldev *dev) +{ +} +static inline + int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline + void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ +} +static inline + void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline void b43_pio_rx(struct b43_pioqueue *queue) +{ +} +static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue) +{ +} +static inline void b43_pio_tx_resume(struct b43_pioqueue *queue) +{ +} +static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev) +{ +} +static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev) +{ +} + +#endif /* CONFIG_B43_PIO */ +#endif /* B43_PIO_H_ */ diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c new file mode 100644 index 000000000000..fcb777383e70 --- /dev/null +++ b/drivers/net/wireless/b43/sysfs.c @@ -0,0 +1,235 @@ +/* + + Broadcom B43 wireless driver + + SYSFS support routines + + Copyright (c) 2006 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "sysfs.h" +#include "main.h" +#include "phy.h" + +#include + +#define GENERIC_FILESIZE 64 + +static int get_integer(const char *buf, size_t count) +{ + char tmp[10 + 1] = { 0 }; + int ret = -EINVAL; + + if (count == 0) + goto out; + count = min(count, (size_t) 10); + memcpy(tmp, buf, count); + ret = simple_strtol(tmp, NULL, 10); + out: + return ret; +} + +static int get_boolean(const char *buf, size_t count) +{ + if (count != 0) { + if (buf[0] == '1') + return 1; + if (buf[0] == '0') + return 0; + if (count >= 4 && memcmp(buf, "true", 4) == 0) + return 1; + if (count >= 5 && memcmp(buf, "false", 5) == 0) + return 0; + if (count >= 3 && memcmp(buf, "yes", 3) == 0) + return 1; + if (count >= 2 && memcmp(buf, "no", 2) == 0) + return 0; + if (count >= 2 && memcmp(buf, "on", 2) == 0) + return 1; + if (count >= 3 && memcmp(buf, "off", 3) == 0) + return 0; + } + return -EINVAL; +} + +static ssize_t b43_attr_interfmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct b43_wldev *wldev = dev_to_b43_wldev(dev); + ssize_t count = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&wldev->wl->mutex); + + switch (wldev->phy.interfmode) { + case B43_INTERFMODE_NONE: + count = + snprintf(buf, PAGE_SIZE, + "0 (No Interference Mitigation)\n"); + break; + case B43_INTERFMODE_NONWLAN: + count = + snprintf(buf, PAGE_SIZE, + "1 (Non-WLAN Interference Mitigation)\n"); + break; + case B43_INTERFMODE_MANUALWLAN: + count = + snprintf(buf, PAGE_SIZE, + "2 (WLAN Interference Mitigation)\n"); + break; + default: + B43_WARN_ON(1); + } + + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static ssize_t b43_attr_interfmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct b43_wldev *wldev = dev_to_b43_wldev(dev); + unsigned long flags; + int err; + int mode; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mode = get_integer(buf, count); + switch (mode) { + case 0: + mode = B43_INTERFMODE_NONE; + break; + case 1: + mode = B43_INTERFMODE_NONWLAN; + break; + case 2: + mode = B43_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = B43_INTERFMODE_AUTOWLAN; + break; + default: + return -EINVAL; + } + + mutex_lock(&wldev->wl->mutex); + spin_lock_irqsave(&wldev->wl->irq_lock, flags); + + err = b43_radio_set_interference_mitigation(wldev, mode); + if (err) { + b43err(wldev->wl, "Interference Mitigation not " + "supported by device\n"); + } + mmiowb(); + spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); + mutex_unlock(&wldev->wl->mutex); + + return err ? err : count; +} + +static DEVICE_ATTR(interference, 0644, + b43_attr_interfmode_show, b43_attr_interfmode_store); + +static ssize_t b43_attr_preamble_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct b43_wldev *wldev = dev_to_b43_wldev(dev); + ssize_t count; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&wldev->wl->mutex); + + if (wldev->short_preamble) + count = + snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); + else + count = + snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); + + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static ssize_t b43_attr_preamble_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct b43_wldev *wldev = dev_to_b43_wldev(dev); + unsigned long flags; + int value; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + value = get_boolean(buf, count); + if (value < 0) + return value; + mutex_lock(&wldev->wl->mutex); + spin_lock_irqsave(&wldev->wl->irq_lock, flags); + + wldev->short_preamble = !!value; + + spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static DEVICE_ATTR(shortpreamble, 0644, + b43_attr_preamble_show, b43_attr_preamble_store); + +int b43_sysfs_register(struct b43_wldev *wldev) +{ + struct device *dev = wldev->dev->dev; + int err; + + B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED); + + err = device_create_file(dev, &dev_attr_interference); + if (err) + goto out; + err = device_create_file(dev, &dev_attr_shortpreamble); + if (err) + goto err_remove_interfmode; + + out: + return err; + err_remove_interfmode: + device_remove_file(dev, &dev_attr_interference); + goto out; +} + +void b43_sysfs_unregister(struct b43_wldev *wldev) +{ + struct device *dev = wldev->dev->dev; + + device_remove_file(dev, &dev_attr_shortpreamble); + device_remove_file(dev, &dev_attr_interference); +} diff --git a/drivers/net/wireless/b43/sysfs.h b/drivers/net/wireless/b43/sysfs.h new file mode 100644 index 000000000000..12bda9ef1a85 --- /dev/null +++ b/drivers/net/wireless/b43/sysfs.h @@ -0,0 +1,9 @@ +#ifndef B43_SYSFS_H_ +#define B43_SYSFS_H_ + +struct b43_wldev; + +int b43_sysfs_register(struct b43_wldev *dev); +void b43_sysfs_unregister(struct b43_wldev *dev); + +#endif /* B43_SYSFS_H_ */ diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c new file mode 100644 index 000000000000..15a87183a572 --- /dev/null +++ b/drivers/net/wireless/b43/tables.c @@ -0,0 +1,375 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005 Stefano Brivio + Copyright (c) 2006, 2006 Michael Buesch + Copyright (c) 2005 Danny van Dyk + Copyright (c) 2005 Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "tables.h" +#include "phy.h" + +const u32 b43_tab_rotor[] = { + 0xFEB93FFD, 0xFEC63FFD, /* 0 */ + 0xFED23FFD, 0xFEDF3FFD, + 0xFEEC3FFE, 0xFEF83FFE, + 0xFF053FFE, 0xFF113FFE, + 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ + 0xFF373FFF, 0xFF443FFF, + 0xFF503FFF, 0xFF5D3FFF, + 0xFF693FFF, 0xFF763FFF, + 0xFF824000, 0xFF8F4000, /* 16 */ + 0xFF9B4000, 0xFFA84000, + 0xFFB54000, 0xFFC14000, + 0xFFCE4000, 0xFFDA4000, + 0xFFE74000, 0xFFF34000, /* 24 */ + 0x00004000, 0x000D4000, + 0x00194000, 0x00264000, + 0x00324000, 0x003F4000, + 0x004B4000, 0x00584000, /* 32 */ + 0x00654000, 0x00714000, + 0x007E4000, 0x008A3FFF, + 0x00973FFF, 0x00A33FFF, + 0x00B03FFF, 0x00BC3FFF, /* 40 */ + 0x00C93FFF, 0x00D63FFF, + 0x00E23FFE, 0x00EF3FFE, + 0x00FB3FFE, 0x01083FFE, + 0x01143FFE, 0x01213FFD, /* 48 */ + 0x012E3FFD, 0x013A3FFD, + 0x01473FFD, +}; + +const u32 b43_tab_retard[] = { + 0xDB93CB87, 0xD666CF64, /* 0 */ + 0xD1FDD358, 0xCDA6D826, + 0xCA38DD9F, 0xC729E2B4, + 0xC469E88E, 0xC26AEE2B, + 0xC0DEF46C, 0xC073FA62, /* 8 */ + 0xC01D00D5, 0xC0760743, + 0xC1560D1E, 0xC2E51369, + 0xC4ED18FF, 0xC7AC1ED7, + 0xCB2823B2, 0xCEFA28D9, /* 16 */ + 0xD2F62D3F, 0xD7BB3197, + 0xDCE53568, 0xE1FE3875, + 0xE7D13B35, 0xED663D35, + 0xF39B3EC4, 0xF98E3FA7, /* 24 */ + 0x00004000, 0x06723FA7, + 0x0C653EC4, 0x129A3D35, + 0x182F3B35, 0x1E023875, + 0x231B3568, 0x28453197, /* 32 */ + 0x2D0A2D3F, 0x310628D9, + 0x34D823B2, 0x38541ED7, + 0x3B1318FF, 0x3D1B1369, + 0x3EAA0D1E, 0x3F8A0743, /* 40 */ + 0x3FE300D5, 0x3F8DFA62, + 0x3F22F46C, 0x3D96EE2B, + 0x3B97E88E, 0x38D7E2B4, + 0x35C8DD9F, 0x325AD826, /* 48 */ + 0x2E03D358, 0x299ACF64, + 0x246DCB87, +}; + +const u16 b43_tab_finefreqa[] = { + 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ + 0x0202, 0x0282, 0x0302, 0x0382, + 0x0402, 0x0482, 0x0502, 0x0582, + 0x05E2, 0x0662, 0x06E2, 0x0762, + 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ + 0x09C2, 0x0A22, 0x0AA2, 0x0B02, + 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, + 0x0D42, 0x0DA2, 0x0E02, 0x0E62, + 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ + 0x1062, 0x10C2, 0x1122, 0x1182, + 0x11E2, 0x1242, 0x12A2, 0x12E2, + 0x1342, 0x13A2, 0x1402, 0x1442, + 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ + 0x15E2, 0x1622, 0x1662, 0x16C1, + 0x1701, 0x1741, 0x1781, 0x17E1, + 0x1821, 0x1861, 0x18A1, 0x18E1, + 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ + 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, + 0x1B01, 0x1B41, 0x1B81, 0x1BA1, + 0x1BE1, 0x1C21, 0x1C41, 0x1C81, + 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ + 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, + 0x1E21, 0x1E61, 0x1E81, 0x1EA1, + 0x1EE1, 0x1F01, 0x1F21, 0x1F41, + 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ + 0x2001, 0x2041, 0x2061, 0x2081, + 0x20A1, 0x20C1, 0x20E1, 0x2101, + 0x2121, 0x2141, 0x2161, 0x2181, + 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ + 0x2221, 0x2241, 0x2261, 0x2281, + 0x22A1, 0x22C1, 0x22C1, 0x22E1, + 0x2301, 0x2321, 0x2341, 0x2361, + 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ + 0x23E1, 0x23E1, 0x2401, 0x2421, + 0x2441, 0x2441, 0x2461, 0x2481, + 0x2481, 0x24A1, 0x24C1, 0x24C1, + 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ + 0x2541, 0x2541, 0x2561, 0x2561, + 0x2581, 0x25A1, 0x25A1, 0x25C1, + 0x25C1, 0x25E1, 0x2601, 0x2601, + 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ + 0x2661, 0x2661, 0x2681, 0x2681, + 0x26A1, 0x26A1, 0x26C1, 0x26C1, + 0x26E1, 0x26E1, 0x2701, 0x2701, + 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ + 0x2760, 0x2760, 0x2780, 0x2780, + 0x2780, 0x27A0, 0x27A0, 0x27C0, + 0x27C0, 0x27E0, 0x27E0, 0x27E0, + 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ + 0x2820, 0x2840, 0x2840, 0x2840, + 0x2860, 0x2860, 0x2880, 0x2880, + 0x2880, 0x28A0, 0x28A0, 0x28A0, + 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ + 0x28E0, 0x28E0, 0x2900, 0x2900, + 0x2900, 0x2920, 0x2920, 0x2920, + 0x2940, 0x2940, 0x2940, 0x2960, + 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ + 0x2980, 0x2980, 0x29A0, 0x29A0, + 0x29A0, 0x29A0, 0x29C0, 0x29C0, + 0x29C0, 0x29E0, 0x29E0, 0x29E0, + 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ + 0x2A00, 0x2A20, 0x2A20, 0x2A20, + 0x2A20, 0x2A40, 0x2A40, 0x2A40, + 0x2A40, 0x2A60, 0x2A60, 0x2A60, +}; + +const u16 b43_tab_finefreqg[] = { + 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ + 0x05A9, 0x0669, 0x0709, 0x0789, + 0x0829, 0x08A9, 0x0929, 0x0989, + 0x0A09, 0x0A69, 0x0AC9, 0x0B29, + 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ + 0x0D09, 0x0D69, 0x0DA9, 0x0E09, + 0x0E69, 0x0EA9, 0x0F09, 0x0F49, + 0x0FA9, 0x0FE9, 0x1029, 0x1089, + 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ + 0x11E9, 0x1229, 0x1289, 0x12C9, + 0x1309, 0x1349, 0x1389, 0x13C9, + 0x1409, 0x1449, 0x14A9, 0x14E9, + 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ + 0x1629, 0x1669, 0x16A9, 0x16E8, + 0x1728, 0x1768, 0x17A8, 0x17E8, + 0x1828, 0x1868, 0x18A8, 0x18E8, + 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ + 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, + 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, + 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, + 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ + 0x1E48, 0x1E88, 0x1EC8, 0x1F08, + 0x1F48, 0x1F88, 0x1FE8, 0x2028, + 0x2068, 0x20A8, 0x2108, 0x2148, + 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ + 0x22C8, 0x2308, 0x2348, 0x23A8, + 0x23E8, 0x2448, 0x24A8, 0x24E8, + 0x2548, 0x25A8, 0x2608, 0x2668, + 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ + 0x2847, 0x28C7, 0x2947, 0x29A7, + 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, + 0x2CA7, 0x2D67, 0x2E47, 0x2F67, + 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ + 0x3806, 0x38A6, 0x3946, 0x39E6, + 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, + 0x3C45, 0x3CA5, 0x3D05, 0x3D85, + 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ + 0x3F45, 0x3FA5, 0x4005, 0x4045, + 0x40A5, 0x40E5, 0x4145, 0x4185, + 0x41E5, 0x4225, 0x4265, 0x42C5, + 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ + 0x4424, 0x4464, 0x44C4, 0x4504, + 0x4544, 0x4584, 0x45C4, 0x4604, + 0x4644, 0x46A4, 0x46E4, 0x4724, + 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ + 0x4864, 0x48A4, 0x48E4, 0x4924, + 0x4964, 0x49A4, 0x49E4, 0x4A24, + 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, + 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ + 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, + 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, + 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, + 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ + 0x5083, 0x50C3, 0x5103, 0x5143, + 0x5183, 0x51E2, 0x5222, 0x5262, + 0x52A2, 0x52E2, 0x5342, 0x5382, + 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ + 0x5502, 0x5542, 0x55A2, 0x55E2, + 0x5642, 0x5682, 0x56E2, 0x5722, + 0x5782, 0x57E1, 0x5841, 0x58A1, + 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ + 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, + 0x5C61, 0x5D01, 0x5D80, 0x5E20, + 0x5EE0, 0x5FA0, 0x6080, 0x61C0, +}; + +const u16 b43_tab_noisea2[] = { + 0x0001, 0x0001, 0x0001, 0xFFFE, + 0xFFFE, 0x3FFF, 0x1000, 0x0393, +}; + +const u16 b43_tab_noisea3[] = { + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, +}; + +const u16 b43_tab_noiseg1[] = { + 0x013C, 0x01F5, 0x031A, 0x0631, + 0x0001, 0x0001, 0x0001, 0x0001, +}; + +const u16 b43_tab_noiseg2[] = { + 0x5484, 0x3C40, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +const u16 b43_tab_noisescaleg1[] = { + 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ + 0x2F2D, 0x2A2A, 0x2527, 0x1F21, + 0x1A1D, 0x1719, 0x1616, 0x1414, + 0x1414, 0x1400, 0x1414, 0x1614, + 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ + 0x2A27, 0x2F2A, 0x332D, 0x3B35, + 0x5140, 0x6C62, 0x0077, +}; + +const u16 b43_tab_noisescaleg2[] = { + 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, + 0x969B, 0x9195, 0x8F8F, 0x8A8A, + 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, + 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ + 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, + 0xCBC0, 0xD8D4, 0x00DD, +}; + +const u16 b43_tab_noisescaleg3[] = { + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0x00A4, +}; + +const u16 b43_tab_sigmasqr1[] = { + 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ + 0x0067, 0x0063, 0x005E, 0x0059, + 0x0054, 0x0050, 0x004B, 0x0046, + 0x0042, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x0000, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x0042, 0x0046, 0x004B, 0x0050, + 0x0054, 0x0059, 0x005E, 0x0063, + 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ + 0x007A, +}; + +const u16 b43_tab_sigmasqr2[] = { + 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ + 0x00D6, 0x00D4, 0x00D2, 0x00CF, + 0x00CD, 0x00CA, 0x00C7, 0x00C4, + 0x00C1, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x0000, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00C1, 0x00C4, 0x00C7, 0x00CA, + 0x00CD, 0x00CF, 0x00D2, 0x00D4, + 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ + 0x00DE, +}; + +static inline void assert_sizes(void) +{ + BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor)); + BUILD_BUG_ON(B43_TAB_RETARD_SIZE != ARRAY_SIZE(b43_tab_retard)); + BUILD_BUG_ON(B43_TAB_FINEFREQA_SIZE != ARRAY_SIZE(b43_tab_finefreqa)); + BUILD_BUG_ON(B43_TAB_FINEFREQG_SIZE != ARRAY_SIZE(b43_tab_finefreqg)); + BUILD_BUG_ON(B43_TAB_NOISEA2_SIZE != ARRAY_SIZE(b43_tab_noisea2)); + BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3)); + BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1)); + BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2)); + BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + ARRAY_SIZE(b43_tab_noisescaleg1)); + BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + ARRAY_SIZE(b43_tab_noisescaleg2)); + BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + ARRAY_SIZE(b43_tab_noisescaleg3)); + BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1)); + BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2)); +} + +u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) +{ + assert_sizes(); + + b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + return b43_phy_read(dev, B43_PHY_OTABLEI); +} + +void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, + u16 offset, u16 value) +{ + b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + b43_phy_write(dev, B43_PHY_OTABLEI, value); +} + +u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) +{ + u32 ret; + + b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + ret = b43_phy_read(dev, B43_PHY_OTABLEQ); + ret <<= 16; + ret |= b43_phy_read(dev, B43_PHY_OTABLEI); + + return ret; +} + +void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, + u16 offset, u32 value) +{ + b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + b43_phy_write(dev, B43_PHY_OTABLEI, value); + b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16)); +} + +u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset) +{ + b43_phy_write(dev, B43_PHY_GTABCTL, table + offset); + return b43_phy_read(dev, B43_PHY_GTABDATA); +} + +void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value) +{ + b43_phy_write(dev, B43_PHY_GTABCTL, table + offset); + b43_phy_write(dev, B43_PHY_GTABDATA, value); +} diff --git a/drivers/net/wireless/b43/tables.h b/drivers/net/wireless/b43/tables.h new file mode 100644 index 000000000000..64635d7b518c --- /dev/null +++ b/drivers/net/wireless/b43/tables.h @@ -0,0 +1,28 @@ +#ifndef B43_TABLES_H_ +#define B43_TABLES_H_ + +#define B43_TAB_ROTOR_SIZE 53 +extern const u32 b43_tab_rotor[]; +#define B43_TAB_RETARD_SIZE 53 +extern const u32 b43_tab_retard[]; +#define B43_TAB_FINEFREQA_SIZE 256 +extern const u16 b43_tab_finefreqa[]; +#define B43_TAB_FINEFREQG_SIZE 256 +extern const u16 b43_tab_finefreqg[]; +#define B43_TAB_NOISEA2_SIZE 8 +extern const u16 b43_tab_noisea2[]; +#define B43_TAB_NOISEA3_SIZE 8 +extern const u16 b43_tab_noisea3[]; +#define B43_TAB_NOISEG1_SIZE 8 +extern const u16 b43_tab_noiseg1[]; +#define B43_TAB_NOISEG2_SIZE 8 +extern const u16 b43_tab_noiseg2[]; +#define B43_TAB_NOISESCALEG_SIZE 27 +extern const u16 b43_tab_noisescaleg1[]; +extern const u16 b43_tab_noisescaleg2[]; +extern const u16 b43_tab_noisescaleg3[]; +#define B43_TAB_SIGMASQR_SIZE 53 +extern const u16 b43_tab_sigmasqr1[]; +extern const u16 b43_tab_sigmasqr2[]; + +#endif /* B43_TABLES_H_ */ diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c new file mode 100644 index 000000000000..e6174b6f11fb --- /dev/null +++ b/drivers/net/wireless/b43/xmit.c @@ -0,0 +1,648 @@ +/* + + Broadcom B43 wireless driver + + Transmission (TX/RX) related functions. + + Copyright (C) 2005 Martin Langer + Copyright (C) 2005 Stefano Brivio + Copyright (C) 2005, 2006 Michael Buesch + Copyright (C) 2005 Danny van Dyk + Copyright (C) 2005 Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "xmit.h" +#include "phy.h" +#include "dma.h" +#include "pio.h" + +/* Extract the bitrate out of a CCK PLCP header. */ +static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp) +{ + switch (plcp->raw[0]) { + case 0x0A: + return B43_CCK_RATE_1MB; + case 0x14: + return B43_CCK_RATE_2MB; + case 0x37: + return B43_CCK_RATE_5MB; + case 0x6E: + return B43_CCK_RATE_11MB; + } + B43_WARN_ON(1); + return 0; +} + +/* Extract the bitrate out of an OFDM PLCP header. */ +static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp) +{ + switch (plcp->raw[0] & 0xF) { + case 0xB: + return B43_OFDM_RATE_6MB; + case 0xF: + return B43_OFDM_RATE_9MB; + case 0xA: + return B43_OFDM_RATE_12MB; + case 0xE: + return B43_OFDM_RATE_18MB; + case 0x9: + return B43_OFDM_RATE_24MB; + case 0xD: + return B43_OFDM_RATE_36MB; + case 0x8: + return B43_OFDM_RATE_48MB; + case 0xC: + return B43_OFDM_RATE_54MB; + } + B43_WARN_ON(1); + return 0; +} + +u8 b43_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case B43_CCK_RATE_1MB: + return 0x0A; + case B43_CCK_RATE_2MB: + return 0x14; + case B43_CCK_RATE_5MB: + return 0x37; + case B43_CCK_RATE_11MB: + return 0x6E; + } + B43_WARN_ON(1); + return 0; +} + +u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case B43_OFDM_RATE_6MB: + return 0xB; + case B43_OFDM_RATE_9MB: + return 0xF; + case B43_OFDM_RATE_12MB: + return 0xA; + case B43_OFDM_RATE_18MB: + return 0xE; + case B43_OFDM_RATE_24MB: + return 0x9; + case B43_OFDM_RATE_36MB: + return 0xD; + case B43_OFDM_RATE_48MB: + return 0x8; + case B43_OFDM_RATE_54MB: + return 0xC; + } + B43_WARN_ON(1); + return 0; +} + +void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + if (b43_is_ofdm_rate(bitrate)) { + *data = b43_plcp_get_ratecode_ofdm(bitrate); + B43_WARN_ON(octets & 0xF000); + *data |= (octets << 5); + *data = cpu_to_le32(*data); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == B43_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) { + raw[1] = 0x84; + } else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = b43_plcp_get_ratecode_cck(bitrate); + } +} + +static u8 b43_calc_fallback_rate(u8 bitrate) +{ + switch (bitrate) { + case B43_CCK_RATE_1MB: + return B43_CCK_RATE_1MB; + case B43_CCK_RATE_2MB: + return B43_CCK_RATE_1MB; + case B43_CCK_RATE_5MB: + return B43_CCK_RATE_2MB; + case B43_CCK_RATE_11MB: + return B43_CCK_RATE_5MB; + case B43_OFDM_RATE_6MB: + return B43_CCK_RATE_5MB; + case B43_OFDM_RATE_9MB: + return B43_OFDM_RATE_6MB; + case B43_OFDM_RATE_12MB: + return B43_OFDM_RATE_9MB; + case B43_OFDM_RATE_18MB: + return B43_OFDM_RATE_12MB; + case B43_OFDM_RATE_24MB: + return B43_OFDM_RATE_18MB; + case B43_OFDM_RATE_36MB: + return B43_OFDM_RATE_24MB; + case B43_OFDM_RATE_48MB: + return B43_OFDM_RATE_36MB; + case B43_OFDM_RATE_54MB: + return B43_OFDM_RATE_48MB; + } + B43_WARN_ON(1); + return 0; +} + +static void generate_txhdr_fw4(struct b43_wldev *dev, + struct b43_txhdr_fw4 *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) +{ + const struct b43_phy *phy = &dev->phy; + const struct ieee80211_hdr *wlhdr = + (const struct ieee80211_hdr *)fragment_data; + int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + u16 fctl = le16_to_cpu(wlhdr->frame_control); + u8 rate, rate_fb; + int rate_ofdm, rate_fb_ofdm; + unsigned int plcp_fragment_len; + u32 mac_ctl = 0; + u16 phy_ctl = 0; + u8 extra_ft = 0; + + memset(txhdr, 0, sizeof(*txhdr)); + + rate = txctl->tx_rate; + rate_ofdm = b43_is_ofdm_rate(rate); + rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; + rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); + + if (rate_ofdm) + txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate); + else + txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate); + txhdr->mac_frame_ctl = wlhdr->frame_control; + memcpy(txhdr->tx_receiver, wlhdr->addr1, 6); + + /* Calculate duration for fallback rate */ + if ((rate_fb == rate) || + (wlhdr->duration_id & cpu_to_le16(0x8000)) || + (wlhdr->duration_id == cpu_to_le16(0))) { + /* If the fallback rate equals the normal rate or the + * dur_id field contains an AID, CFP magic or 0, + * use the original dur_id field. */ + txhdr->dur_fb = wlhdr->duration_id; + } else { + int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb); + txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, + fragment_len, + fbrate_base100kbps); + } + + plcp_fragment_len = fragment_len + FCS_LEN; + if (use_encryption) { + u8 key_idx = (u16) (txctl->key_idx); + struct b43_key *key; + int wlhdr_len; + size_t iv_len; + + B43_WARN_ON(key_idx >= dev->max_nr_keys); + key = &(dev->key[key_idx]); + B43_WARN_ON(!key->keyconf); + + /* Hardware appends ICV. */ + plcp_fragment_len += txctl->icv_len; + + key_idx = b43_kidx_to_fw(dev, key_idx); + mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) & + B43_TX4_MAC_KEYIDX; + mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) & + B43_TX4_MAC_KEYALG; + wlhdr_len = ieee80211_get_hdrlen(fctl); + iv_len = min((size_t) txctl->iv_len, + ARRAY_SIZE(txhdr->iv)); + memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + } + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp), + plcp_fragment_len, rate); + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb), + plcp_fragment_len, rate_fb); + + /* Extra Frame Types */ + if (rate_fb_ofdm) + extra_ft |= B43_TX4_EFT_FBOFDM; + + /* Set channel radio code. Note that the micrcode ORs 0x100 to + * this value before comparing it to the value in SHM, if this + * is a 5Ghz packet. + */ + txhdr->chan_radio_code = phy->channel; + + /* PHY TX Control word */ + if (rate_ofdm) + phy_ctl |= B43_TX4_PHY_OFDM; + if (dev->short_preamble) + phy_ctl |= B43_TX4_PHY_SHORTPRMBL; + switch (txctl->antenna_sel_tx) { + case 0: + phy_ctl |= B43_TX4_PHY_ANTLAST; + break; + case 1: + phy_ctl |= B43_TX4_PHY_ANT0; + break; + case 2: + phy_ctl |= B43_TX4_PHY_ANT1; + break; + default: + B43_WARN_ON(1); + } + + /* MAC control */ + if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + mac_ctl |= B43_TX4_MAC_ACK; + if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) + mac_ctl |= B43_TX4_MAC_HWSEQ; + if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + mac_ctl |= B43_TX4_MAC_STMSDU; + if (phy->type == B43_PHYTYPE_A) + mac_ctl |= B43_TX4_MAC_5GHZ; + + /* Generate the RTS or CTS-to-self frame */ + if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || + (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + unsigned int len; + struct ieee80211_hdr *hdr; + int rts_rate, rts_rate_fb; + int rts_rate_ofdm, rts_rate_fb_ofdm; + + rts_rate = txctl->rts_cts_rate; + rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); + rts_rate_fb = b43_calc_fallback_rate(rts_rate); + rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); + + if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id, + fragment_data, fragment_len, + txctl, + (struct ieee80211_cts *)(txhdr-> + rts_frame)); + mac_ctl |= B43_TX4_MAC_SENDCTS; + len = sizeof(struct ieee80211_cts); + } else { + ieee80211_rts_get(dev->wl->hw, dev->wl->if_id, + fragment_data, fragment_len, txctl, + (struct ieee80211_rts *)(txhdr-> + rts_frame)); + mac_ctl |= B43_TX4_MAC_SENDRTS; + len = sizeof(struct ieee80211_rts); + } + len += FCS_LEN; + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> + rts_plcp), len, + rts_rate); + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> + rts_plcp_fb), + len, rts_rate_fb); + hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); + txhdr->rts_dur_fb = hdr->duration_id; + if (rts_rate_ofdm) { + extra_ft |= B43_TX4_EFT_RTSOFDM; + txhdr->phy_rate_rts = + b43_plcp_get_ratecode_ofdm(rts_rate); + } else + txhdr->phy_rate_rts = + b43_plcp_get_ratecode_cck(rts_rate); + if (rts_rate_fb_ofdm) + extra_ft |= B43_TX4_EFT_RTSFBOFDM; + mac_ctl |= B43_TX4_MAC_LONGFRAME; + } + + /* Magic cookie */ + txhdr->cookie = cpu_to_le16(cookie); + + /* Apply the bitfields */ + txhdr->mac_ctl = cpu_to_le32(mac_ctl); + txhdr->phy_ctl = cpu_to_le16(phy_ctl); + txhdr->extra_ft = extra_ft; +} + +void b43_generate_txhdr(struct b43_wldev *dev, + u8 * txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, u16 cookie) +{ + generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr, + fragment_data, fragment_len, txctl, cookie); +} + +static s8 b43_rssi_postprocess(struct b43_wldev *dev, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) +{ + struct b43_phy *phy = &dev->phy; + s32 tmp; + + switch (phy->radio_ver) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (dev->dev->bus->sprom.r1. + boardflags_lo & B43_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = phy->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (phy->type == B43_PHYTYPE_G && adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8) tmp; +} + +//TODO +#if 0 +static s8 b43_rssinoise_postprocess(struct b43_wldev *dev, u8 in_rssi) +{ + struct b43_phy *phy = &dev->phy; + s8 ret; + + if (phy->type == B43_PHYTYPE_A) { + //TODO: Incomplete specs. + ret = 0; + } else + ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1); + + return ret; +} +#endif + +void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) +{ + struct ieee80211_rx_status status; + struct b43_plcp_hdr6 *plcp; + struct ieee80211_hdr *wlhdr; + const struct b43_rxhdr_fw4 *rxhdr = _rxhdr; + u16 fctl; + u16 phystat0, phystat3, chanstat, mactime; + u32 macstat; + u16 chanid; + u8 jssi; + int padding; + + memset(&status, 0, sizeof(status)); + + /* Get metadata about the frame from the header. */ + phystat0 = le16_to_cpu(rxhdr->phy_status0); + phystat3 = le16_to_cpu(rxhdr->phy_status3); + jssi = rxhdr->jssi; + macstat = le32_to_cpu(rxhdr->mac_status); + mactime = le16_to_cpu(rxhdr->mac_time); + chanstat = le16_to_cpu(rxhdr->channel); + + if (macstat & B43_RX_MAC_FCSERR) + dev->wl->ieee_stats.dot11FCSErrorCount++; + if (macstat & B43_RX_MAC_DECERR) { + /* Decryption with the given key failed. + * Drop the packet. We also won't be able to decrypt it with + * the key in software. */ + goto drop; + } + + /* Skip PLCP and padding */ + padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0; + if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) { + b43dbg(dev->wl, "RX: Packet size underrun (1)\n"); + goto drop; + } + plcp = (struct b43_plcp_hdr6 *)(skb->data + padding); + skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding); + /* The skb contains the Wireless Header + payload data now */ + if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */ + FCS_LEN))) { + b43dbg(dev->wl, "RX: Packet size underrun (2)\n"); + goto drop; + } + wlhdr = (struct ieee80211_hdr *)(skb->data); + fctl = le16_to_cpu(wlhdr->frame_control); + skb_trim(skb, skb->len - FCS_LEN); + + if (macstat & B43_RX_MAC_DEC) { + unsigned int keyidx; + int wlhdr_len; + + keyidx = ((macstat & B43_RX_MAC_KEYIDX) + >> B43_RX_MAC_KEYIDX_SHIFT); + /* We must adjust the key index here. We want the "physical" + * key index, but the ucode passed it slightly different. + */ + keyidx = b43_kidx_to_raw(dev, keyidx); + B43_WARN_ON(keyidx >= dev->max_nr_keys); + + if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { + wlhdr_len = ieee80211_get_hdrlen(fctl); + if (unlikely(skb->len < (wlhdr_len + 3))) { + b43dbg(dev->wl, + "RX: Packet size underrun (3)\n"); + goto drop; + } + status.flag |= RX_FLAG_DECRYPTED; + } + } + + status.ssi = b43_rssi_postprocess(dev, jssi, + (phystat0 & B43_RX_PHYST0_OFDM), + (phystat0 & B43_RX_PHYST0_GAINCTL), + (phystat3 & B43_RX_PHYST3_TRSTATE)); + status.noise = dev->stats.link_noise; + /* the next line looks wrong, but is what mac80211 wants */ + status.signal = (jssi * 100) / B43_RX_MAX_SSI; + if (phystat0 & B43_RX_PHYST0_OFDM) + status.rate = b43_plcp_get_bitrate_ofdm(plcp); + else + status.rate = b43_plcp_get_bitrate_cck(plcp); + status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); + status.mactime = mactime; + + chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; + switch (chanstat & B43_RX_CHAN_PHYTYPE) { + case B43_PHYTYPE_A: + status.phymode = MODE_IEEE80211A; + status.freq = chanid; + status.channel = b43_freq_to_channel_a(chanid); + break; + case B43_PHYTYPE_B: + status.phymode = MODE_IEEE80211B; + status.freq = chanid + 2400; + status.channel = b43_freq_to_channel_bg(chanid + 2400); + break; + case B43_PHYTYPE_G: + status.phymode = MODE_IEEE80211G; + status.freq = chanid + 2400; + status.channel = b43_freq_to_channel_bg(chanid + 2400); + break; + default: + B43_WARN_ON(1); + } + + dev->stats.last_rx = jiffies; + ieee80211_rx_irqsafe(dev->wl->hw, skb, &status); + + return; +drop: + b43dbg(dev->wl, "RX: Packet dropped\n"); + dev_kfree_skb_any(skb); +} + +void b43_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + b43_debugfs_log_txstat(dev, status); + + if (status->intermediate) + return; + if (status->for_ampdu) + return; + if (!status->acked) + dev->wl->ieee_stats.dot11ACKFailureCount++; + if (status->rts_count) { + if (status->rts_count == 0xF) //FIXME + dev->wl->ieee_stats.dot11RTSFailureCount++; + else + dev->wl->ieee_stats.dot11RTSSuccessCount++; + } + + if (b43_using_pio(dev)) + b43_pio_handle_txstatus(dev, status); + else + b43_dma_handle_txstatus(dev, status); +} + +/* Handle TX status report as received through DMA/PIO queues */ +void b43_handle_hwtxstatus(struct b43_wldev *dev, + const struct b43_hwtxstatus *hw) +{ + struct b43_txstatus status; + u8 tmp; + + status.cookie = le16_to_cpu(hw->cookie); + status.seq = le16_to_cpu(hw->seq); + status.phy_stat = hw->phy_stat; + tmp = hw->count; + status.frame_count = (tmp >> 4); + status.rts_count = (tmp & 0x0F); + tmp = hw->flags; + status.supp_reason = ((tmp & 0x1C) >> 2); + status.pm_indicated = !!(tmp & 0x80); + status.intermediate = !!(tmp & 0x40); + status.for_ampdu = !!(tmp & 0x20); + status.acked = !!(tmp & 0x02); + + b43_handle_txstatus(dev, &status); +} + +/* Stop any TX operation on the device (suspend the hardware queues) */ +void b43_tx_suspend(struct b43_wldev *dev) +{ + if (b43_using_pio(dev)) + b43_pio_freeze_txqueues(dev); + else + b43_dma_tx_suspend(dev); +} + +/* Resume any TX operation on the device (resume the hardware queues) */ +void b43_tx_resume(struct b43_wldev *dev) +{ + if (b43_using_pio(dev)) + b43_pio_thaw_txqueues(dev); + else + b43_dma_tx_resume(dev); +} + +#if 0 +static void upload_qos_parms(struct b43_wldev *dev, + const u16 * parms, u16 offset) +{ + int i; + + for (i = 0; i < B43_NR_QOSPARMS; i++) { + b43_shm_write16(dev, B43_SHM_SHARED, + offset + (i * 2), parms[i]); + } +} +#endif + +/* Initialize the QoS parameters */ +void b43_qos_init(struct b43_wldev *dev) +{ + /* FIXME: This function must probably be called from the mac80211 + * config callback. */ + return; + + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); + //FIXME kill magic + b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4); + + /*TODO: We might need some stack support here to get the values. */ +} diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h new file mode 100644 index 000000000000..03bddd251618 --- /dev/null +++ b/drivers/net/wireless/b43/xmit.h @@ -0,0 +1,250 @@ +#ifndef B43_XMIT_H_ +#define B43_XMIT_H_ + +#include "main.h" + +#define _b43_declare_plcp_hdr(size) \ + struct b43_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct b43_plcp_hdr4 */ +_b43_declare_plcp_hdr(4); +/* struct b43_plcp_hdr6 */ +_b43_declare_plcp_hdr(6); + +#undef _b43_declare_plcp_hdr + +/* TX header for v4 firmware */ +struct b43_txhdr_fw4 { + __le32 mac_ctl; /* MAC TX control */ + __le16 mac_frame_ctl; /* Copy of the FrameControl field */ + __le16 tx_fes_time_norm; /* TX FES Time Normal */ + __le16 phy_ctl; /* PHY TX control */ + __le16 phy_ctl_0; /* Unused */ + __le16 phy_ctl_1; /* Unused */ + __le16 phy_ctl_rts_0; /* Unused */ + __le16 phy_ctl_rts_1; /* Unused */ + __u8 phy_rate; /* PHY rate */ + __u8 phy_rate_rts; /* PHY rate for RTS/CTS */ + __u8 extra_ft; /* Extra Frame Types */ + __u8 chan_radio_code; /* Channel Radio Code */ + __u8 iv[16]; /* Encryption IV */ + __u8 tx_receiver[6]; /* TX Frame Receiver address */ + __le16 tx_fes_time_fb; /* TX FES Time Fallback */ + struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */ + __le16 rts_dur_fb; /* RTS fallback duration */ + struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */ + __le16 dur_fb; /* Fallback duration */ + __le16 mm_dur_time; /* Unused */ + __le16 mm_dur_time_fb; /* Unused */ + __le32 time_stamp; /* Timestamp */ + PAD_BYTES(2); + __le16 cookie; /* TX frame cookie */ + __le16 tx_status; /* TX status */ + struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */ + __u8 rts_frame[16]; /* The RTS frame (if used) */ + PAD_BYTES(2); + struct b43_plcp_hdr6 plcp; /* Main PLCP */ +} __attribute__ ((__packed__)); + +/* MAC TX control */ +#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */ +#define B43_TX4_MAC_KEYIDX_SHIFT 20 +#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */ +#define B43_TX4_MAC_KEYALG_SHIFT 16 +#define B43_TX4_MAC_LIFETIME 0x00001000 +#define B43_TX4_MAC_FRAMEBURST 0x00000800 +#define B43_TX4_MAC_SENDCTS 0x00000400 +#define B43_TX4_MAC_AMPDU 0x00000300 +#define B43_TX4_MAC_AMPDU_SHIFT 8 +#define B43_TX4_MAC_5GHZ 0x00000080 +#define B43_TX4_MAC_IGNPMQ 0x00000020 +#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */ +#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */ +#define B43_TX4_MAC_SENDRTS 0x00000004 +#define B43_TX4_MAC_LONGFRAME 0x00000002 +#define B43_TX4_MAC_ACK 0x00000001 + +/* Extra Frame Types */ +#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */ +#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */ +#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ + +/* PHY TX control word */ +#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ +#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ +#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */ +#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ +#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */ +#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */ + +void b43_generate_txhdr(struct b43_wldev *dev, + u8 * txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, u16 cookie); + +/* Transmit Status */ +struct b43_txstatus { + u16 cookie; /* The cookie from the txhdr */ + u16 seq; /* Sequence number */ + u8 phy_stat; /* PHY TX status */ + u8 frame_count; /* Frame transmit count */ + u8 rts_count; /* RTS transmit count */ + u8 supp_reason; /* Suppression reason */ + /* flags */ + u8 pm_indicated; /* PM mode indicated to AP */ + u8 intermediate; /* Intermediate status notification (not final) */ + u8 for_ampdu; /* Status is for an AMPDU (afterburner) */ + u8 acked; /* Wireless ACK received */ +}; + +/* txstatus supp_reason values */ +enum { + B43_TXST_SUPP_NONE, /* Not suppressed */ + B43_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */ + B43_TXST_SUPP_FLUSH, /* Suppressed due to flush request */ + B43_TXST_SUPP_PREV, /* Previous fragment failed */ + B43_TXST_SUPP_CHAN, /* Channel mismatch */ + B43_TXST_SUPP_LIFE, /* Lifetime expired */ + B43_TXST_SUPP_UNDER, /* Buffer underflow */ + B43_TXST_SUPP_ABNACK, /* Afterburner NACK */ +}; + +/* Transmit Status as received through DMA/PIO on old chips */ +struct b43_hwtxstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 count; + PAD_BYTES(2); + __le16 seq; + u8 phy_stat; + PAD_BYTES(1); +} __attribute__ ((__packed__)); + +/* Receive header for v4 firmware. */ +struct b43_rxhdr_fw4 { + __le16 frame_len; /* Frame length */ + PAD_BYTES(2); + __le16 phy_status0; /* PHY RX Status 0 */ + __u8 jssi; /* PHY RX Status 1: JSSI */ + __u8 sig_qual; /* PHY RX Status 1: Signal Quality */ + __le16 phy_status2; /* PHY RX Status 2 */ + __le16 phy_status3; /* PHY RX Status 3 */ + __le32 mac_status; /* MAC RX status */ + __le16 mac_time; + __le16 channel; +} __attribute__ ((__packed__)); + +/* PHY RX Status 0 */ +#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */ +#define B43_RX_PHYST0_PLCPHCF 0x0200 +#define B43_RX_PHYST0_PLCPFV 0x0100 +#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */ +#define B43_RX_PHYST0_LCRS 0x0040 +#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */ +#define B43_RX_PHYST0_UNSRATE 0x0010 +#define B43_RX_PHYST0_CLIP 0x000C +#define B43_RX_PHYST0_CLIP_SHIFT 2 +#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */ +#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */ +#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */ +#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */ +#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */ + +/* PHY RX Status 2 */ +#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */ +#define B43_RX_PHYST2_LNAG_SHIFT 14 +#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */ +#define B43_RX_PHYST2_PNAG_SHIFT 10 +#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */ + +/* PHY RX Status 3 */ +#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */ +#define B43_RX_PHYST3_DIGG_SHIFT 11 +#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */ + +/* MAC RX Status */ +#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */ +#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */ +#define B43_RX_MAC_KEYIDX_SHIFT 5 +#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */ +#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */ +#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */ +#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */ +#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */ + +/* RX channel */ +#define B43_RX_CHAN_GAIN 0xFC00 /* Gain */ +#define B43_RX_CHAN_GAIN_SHIFT 10 +#define B43_RX_CHAN_ID 0x03FC /* Channel ID */ +#define B43_RX_CHAN_ID_SHIFT 2 +#define B43_RX_CHAN_PHYTYPE 0x0003 /* PHY type */ + +u8 b43_plcp_get_ratecode_cck(const u8 bitrate); +u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate); + +void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate); + +void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); + +void b43_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status); + +void b43_handle_hwtxstatus(struct b43_wldev *dev, + const struct b43_hwtxstatus *hw); + +void b43_tx_suspend(struct b43_wldev *dev); +void b43_tx_resume(struct b43_wldev *dev); + +#define B43_NR_QOSPARMS 22 +enum { + B43_QOSPARM_TXOP = 0, + B43_QOSPARM_CWMIN, + B43_QOSPARM_CWMAX, + B43_QOSPARM_CWCUR, + B43_QOSPARM_AIFS, + B43_QOSPARM_BSLOTS, + B43_QOSPARM_REGGAP, + B43_QOSPARM_STATUS, +}; +void b43_qos_init(struct b43_wldev *dev); + +/* Helper functions for converting the key-table index from "firmware-format" + * to "raw-format" and back. The firmware API changed for this at some revision. + * We need to account for that here. */ +static inline int b43_new_kidx_api(struct b43_wldev *dev) +{ + /* FIXME: Not sure the change was at rev 351 */ + return (dev->fw.rev >= 351); +} +static inline u8 b43_kidx_to_fw(struct b43_wldev *dev, u8 raw_kidx) +{ + u8 firmware_kidx; + if (b43_new_kidx_api(dev)) { + firmware_kidx = raw_kidx; + } else { + if (raw_kidx >= 4) /* Is per STA key? */ + firmware_kidx = raw_kidx - 4; + else + firmware_kidx = raw_kidx; /* TX default key */ + } + return firmware_kidx; +} +static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx) +{ + u8 raw_kidx; + if (b43_new_kidx_api(dev)) + raw_kidx = firmware_kidx; + else + raw_kidx = firmware_kidx + 4; /* RX default keys or per STA keys */ + return raw_kidx; +} + +#endif /* B43_XMIT_H_ */ From 75388acd0cd827dc1498043daa7d1c760902cd67 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 25 Sep 2007 16:46:54 -0700 Subject: [PATCH 1421/2804] [B43LEGACY]: add mac80211-based driver for legacy BCM43xx devices Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 7 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/b43legacy/Kconfig | 89 + drivers/net/wireless/b43legacy/Makefile | 14 + drivers/net/wireless/b43legacy/b43legacy.h | 829 +++++ drivers/net/wireless/b43legacy/debugfs.c | 505 +++ drivers/net/wireless/b43legacy/debugfs.h | 89 + drivers/net/wireless/b43legacy/dma.c | 1565 ++++++++ drivers/net/wireless/b43legacy/dma.h | 367 ++ drivers/net/wireless/b43legacy/ilt.c | 336 ++ drivers/net/wireless/b43legacy/ilt.h | 34 + drivers/net/wireless/b43legacy/leds.c | 302 ++ drivers/net/wireless/b43legacy/leds.h | 56 + drivers/net/wireless/b43legacy/main.c | 3805 ++++++++++++++++++++ drivers/net/wireless/b43legacy/main.h | 147 + drivers/net/wireless/b43legacy/phy.c | 2265 ++++++++++++ drivers/net/wireless/b43legacy/phy.h | 219 ++ drivers/net/wireless/b43legacy/pio.c | 668 ++++ drivers/net/wireless/b43legacy/pio.h | 172 + drivers/net/wireless/b43legacy/radio.c | 2131 +++++++++++ drivers/net/wireless/b43legacy/radio.h | 98 + drivers/net/wireless/b43legacy/sysfs.c | 238 ++ drivers/net/wireless/b43legacy/sysfs.h | 9 + drivers/net/wireless/b43legacy/xmit.c | 642 ++++ drivers/net/wireless/b43legacy/xmit.h | 259 ++ 26 files changed, 14848 insertions(+) create mode 100644 drivers/net/wireless/b43legacy/Kconfig create mode 100644 drivers/net/wireless/b43legacy/Makefile create mode 100644 drivers/net/wireless/b43legacy/b43legacy.h create mode 100644 drivers/net/wireless/b43legacy/debugfs.c create mode 100644 drivers/net/wireless/b43legacy/debugfs.h create mode 100644 drivers/net/wireless/b43legacy/dma.c create mode 100644 drivers/net/wireless/b43legacy/dma.h create mode 100644 drivers/net/wireless/b43legacy/ilt.c create mode 100644 drivers/net/wireless/b43legacy/ilt.h create mode 100644 drivers/net/wireless/b43legacy/leds.c create mode 100644 drivers/net/wireless/b43legacy/leds.h create mode 100644 drivers/net/wireless/b43legacy/main.c create mode 100644 drivers/net/wireless/b43legacy/main.h create mode 100644 drivers/net/wireless/b43legacy/phy.c create mode 100644 drivers/net/wireless/b43legacy/phy.h create mode 100644 drivers/net/wireless/b43legacy/pio.c create mode 100644 drivers/net/wireless/b43legacy/pio.h create mode 100644 drivers/net/wireless/b43legacy/radio.c create mode 100644 drivers/net/wireless/b43legacy/radio.h create mode 100644 drivers/net/wireless/b43legacy/sysfs.c create mode 100644 drivers/net/wireless/b43legacy/sysfs.h create mode 100644 drivers/net/wireless/b43legacy/xmit.c create mode 100644 drivers/net/wireless/b43legacy/xmit.h diff --git a/MAINTAINERS b/MAINTAINERS index e6589c3b69c2..ef9402807de0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -804,6 +804,13 @@ L: linux-wireless@vger.kernel.org W: http://bcm43xx.berlios.de/ S: Maintained +B43LEGACY WIRELESS DRIVER +P: Larry Finger +M: Larry.Finger@lwfinger.net +L: linux-wireless@vger.kernel.org +W: http://bcm43xx.berlios.de/ +S: Maintained + BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION) P: Larry Finger M: Larry.Finger@lwfinger.net diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7bed87e63da2..c2102653b2a9 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -580,6 +580,7 @@ config ADM8211 source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/b43/Kconfig" +source "drivers/net/wireless/b43legacy/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 765dbbcf54be..d8dd907e4999 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_BCM43XX) += bcm43xx/ obj-$(CONFIG_B43) += b43/ +obj-$(CONFIG_B43LEGACY) += b43legacy/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ # 16-bit wireless PCMCIA client drivers diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig new file mode 100644 index 000000000000..7e23ec23fc98 --- /dev/null +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -0,0 +1,89 @@ +config B43LEGACY + tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)" + depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 + select SSB + select FW_LOADER + select HW_RANDOM + ---help--- + b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and + BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the + Linksys WPC54G V1 PCMCIA devices. + + Newer 802.11g and 802.11a devices need b43. + + It is safe to include both b43 and b43legacy as the underlying glue + layer will automatically load the correct version for your device. + + This driver uses V3 firmware, which must be installed separately using + b43-fwcutter. + + This driver can be built as a module (recommended) that will be + called "b43legacy". If unsure, say M. + +# Auto-select SSB PCI-HOST support, if possible +config B43LEGACY_PCI_AUTOSELECT + bool + depends on B43LEGACY && SSB_PCIHOST_POSSIBLE + select SSB_PCIHOST + default y + +# Auto-select SSB PCICORE driver, if possible +config B43LEGACY_PCICORE_AUTOSELECT + bool + depends on B43LEGACY && SSB_DRIVER_PCICORE_POSSIBLE + select SSB_DRIVER_PCICORE + default y + +config B43LEGACY_DEBUG + bool "Broadcom 43xx-legacy debugging" + depends on B43LEGACY + default y + ---help--- + Say Y, because this information will help you get the driver running. + This option generates a minimum of log output. + +config B43LEGACY_DMA + bool + depends on B43LEGACY + +config B43LEGACY_PIO + bool + depends on B43LEGACY + +choice + prompt "Broadcom 43xx-legacy data transfer mode" + depends on B43LEGACY + default B43LEGACY_DMA_AND_PIO_MODE + +config B43LEGACY_DMA_AND_PIO_MODE + bool "DMA + PIO" + select B43LEGACY_DMA + select B43LEGACY_PIO + ---help--- + Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) + data transfer modes. The mode actually used is selectable through + the module parameter "pio". With pio=0 as a module parameter, the + default DMA is used, otherwise PIO is used. + + If unsure, choose this option. + +config B43LEGACY_DMA_MODE + bool "DMA (Direct Memory Access) only" + select B43LEGACY_DMA + ---help--- + Only include Direct Memory Access (DMA). + This reduces the size of the driver module, by omitting the PIO code. + +config B43LEGACY_PIO_MODE + bool "PIO (Programmed I/O) only" + select B43LEGACY_PIO + ---help--- + Only include Programmed I/O (PIO). + This reduces the size of the driver module, by omitting the DMA code. + Please note that PIO transfers are slow (compared to DMA). + + Also note that not all devices of the b43legacy series support PIO. + + You should use PIO only if DMA does not work for you. + +endchoice diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile new file mode 100644 index 000000000000..ec3a2482bbad --- /dev/null +++ b/drivers/net/wireless/b43legacy/Makefile @@ -0,0 +1,14 @@ +obj-$(CONFIG_B43LEGACY) += b43legacy.o +b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o + +b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o +b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o + +b43legacy-objs := main.o \ + ilt.o \ + leds.o \ + phy.o \ + radio.o \ + sysfs.o \ + xmit.o \ + $(b43legacy-obj-y) diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h new file mode 100644 index 000000000000..34a6277051a1 --- /dev/null +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -0,0 +1,829 @@ +#ifndef B43legacy_H_ +#define B43legacy_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "debugfs.h" +#include "leds.h" +#include "phy.h" + + +#define B43legacy_IRQWAIT_MAX_RETRIES 100 + +#define B43legacy_RX_MAX_SSI 60 /* best guess at max ssi */ + +/* MMIO offsets */ +#define B43legacy_MMIO_DMA0_REASON 0x20 +#define B43legacy_MMIO_DMA0_IRQ_MASK 0x24 +#define B43legacy_MMIO_DMA1_REASON 0x28 +#define B43legacy_MMIO_DMA1_IRQ_MASK 0x2C +#define B43legacy_MMIO_DMA2_REASON 0x30 +#define B43legacy_MMIO_DMA2_IRQ_MASK 0x34 +#define B43legacy_MMIO_DMA3_REASON 0x38 +#define B43legacy_MMIO_DMA3_IRQ_MASK 0x3C +#define B43legacy_MMIO_DMA4_REASON 0x40 +#define B43legacy_MMIO_DMA4_IRQ_MASK 0x44 +#define B43legacy_MMIO_DMA5_REASON 0x48 +#define B43legacy_MMIO_DMA5_IRQ_MASK 0x4C +#define B43legacy_MMIO_MACCTL 0x120 +#define B43legacy_MMIO_STATUS_BITFIELD 0x120 +#define B43legacy_MMIO_STATUS2_BITFIELD 0x124 +#define B43legacy_MMIO_GEN_IRQ_REASON 0x128 +#define B43legacy_MMIO_GEN_IRQ_MASK 0x12C +#define B43legacy_MMIO_RAM_CONTROL 0x130 +#define B43legacy_MMIO_RAM_DATA 0x134 +#define B43legacy_MMIO_PS_STATUS 0x140 +#define B43legacy_MMIO_RADIO_HWENABLED_HI 0x158 +#define B43legacy_MMIO_SHM_CONTROL 0x160 +#define B43legacy_MMIO_SHM_DATA 0x164 +#define B43legacy_MMIO_SHM_DATA_UNALIGNED 0x166 +#define B43legacy_MMIO_XMITSTAT_0 0x170 +#define B43legacy_MMIO_XMITSTAT_1 0x174 +#define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ +#define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ + +/* 32-bit DMA */ +#define B43legacy_MMIO_DMA32_BASE0 0x200 +#define B43legacy_MMIO_DMA32_BASE1 0x220 +#define B43legacy_MMIO_DMA32_BASE2 0x240 +#define B43legacy_MMIO_DMA32_BASE3 0x260 +#define B43legacy_MMIO_DMA32_BASE4 0x280 +#define B43legacy_MMIO_DMA32_BASE5 0x2A0 +/* 64-bit DMA */ +#define B43legacy_MMIO_DMA64_BASE0 0x200 +#define B43legacy_MMIO_DMA64_BASE1 0x240 +#define B43legacy_MMIO_DMA64_BASE2 0x280 +#define B43legacy_MMIO_DMA64_BASE3 0x2C0 +#define B43legacy_MMIO_DMA64_BASE4 0x300 +#define B43legacy_MMIO_DMA64_BASE5 0x340 +/* PIO */ +#define B43legacy_MMIO_PIO1_BASE 0x300 +#define B43legacy_MMIO_PIO2_BASE 0x310 +#define B43legacy_MMIO_PIO3_BASE 0x320 +#define B43legacy_MMIO_PIO4_BASE 0x330 + +#define B43legacy_MMIO_PHY_VER 0x3E0 +#define B43legacy_MMIO_PHY_RADIO 0x3E2 +#define B43legacy_MMIO_PHY0 0x3E6 +#define B43legacy_MMIO_ANTENNA 0x3E8 +#define B43legacy_MMIO_CHANNEL 0x3F0 +#define B43legacy_MMIO_CHANNEL_EXT 0x3F4 +#define B43legacy_MMIO_RADIO_CONTROL 0x3F6 +#define B43legacy_MMIO_RADIO_DATA_HIGH 0x3F8 +#define B43legacy_MMIO_RADIO_DATA_LOW 0x3FA +#define B43legacy_MMIO_PHY_CONTROL 0x3FC +#define B43legacy_MMIO_PHY_DATA 0x3FE +#define B43legacy_MMIO_MACFILTER_CONTROL 0x420 +#define B43legacy_MMIO_MACFILTER_DATA 0x422 +#define B43legacy_MMIO_RCMTA_COUNT 0x43C /* Receive Match Transmitter Addr */ +#define B43legacy_MMIO_RADIO_HWENABLED_LO 0x49A +#define B43legacy_MMIO_GPIO_CONTROL 0x49C +#define B43legacy_MMIO_GPIO_MASK 0x49E +#define B43legacy_MMIO_TSF_0 0x632 /* core rev < 3 only */ +#define B43legacy_MMIO_TSF_1 0x634 /* core rev < 3 only */ +#define B43legacy_MMIO_TSF_2 0x636 /* core rev < 3 only */ +#define B43legacy_MMIO_TSF_3 0x638 /* core rev < 3 only */ +#define B43legacy_MMIO_RNG 0x65A +#define B43legacy_MMIO_POWERUP_DELAY 0x6A8 + +/* SPROM boardflags_lo values */ +#define B43legacy_BFL_PACTRL 0x0002 +#define B43legacy_BFL_RSSI 0x0008 +#define B43legacy_BFL_EXTLNA 0x1000 + +/* GPIO register offset, in both ChipCommon and PCI core. */ +#define B43legacy_GPIO_CONTROL 0x6c + +/* SHM Routing */ +#define B43legacy_SHM_SHARED 0x0001 +#define B43legacy_SHM_WIRELESS 0x0002 +#define B43legacy_SHM_HW 0x0004 +#define B43legacy_SHM_UCODE 0x0300 + +/* SHM Routing modifiers */ +#define B43legacy_SHM_AUTOINC_R 0x0200 /* Read Auto-increment */ +#define B43legacy_SHM_AUTOINC_W 0x0100 /* Write Auto-increment */ +#define B43legacy_SHM_AUTOINC_RW (B43legacy_SHM_AUTOINC_R | \ + B43legacy_SHM_AUTOINC_W) + +/* Misc SHM_SHARED offsets */ +#define B43legacy_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */ +#define B43legacy_SHM_SH_HOSTFLO 0x005E /* Hostflags ucode opts (low) */ +#define B43legacy_SHM_SH_HOSTFHI 0x0060 /* Hostflags ucode opts (high) */ +/* SHM_SHARED crypto engine */ +#define B43legacy_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block */ +/* SHM_SHARED beacon variables */ +#define B43legacy_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word */ +/* SHM_SHARED ACK/CTS control */ +#define B43legacy_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word */ +/* SHM_SHARED probe response variables */ +#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */ +#define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */ +/* SHM_SHARED rate tables */ +/* SHM_SHARED microcode soft registers */ +#define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */ +#define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */ +#define B43legacy_SHM_SH_UCODEDATE 0x0004 /* Microcode date */ +#define B43legacy_SHM_SH_UCODETIME 0x0006 /* Microcode time */ + +#define B43legacy_UCODEFLAGS_OFFSET 0x005E + +/* Hardware Radio Enable masks */ +#define B43legacy_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16) +#define B43legacy_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4) + +/* HostFlags. See b43legacy_hf_read/write() */ +#define B43legacy_HF_SYMW 0x00000002 /* G-PHY SYM workaround */ +#define B43legacy_HF_GDCW 0x00000020 /* G-PHY DV cancel filter */ +#define B43legacy_HF_OFDMPABOOST 0x00000040 /* Enable PA boost OFDM */ +#define B43legacy_HF_EDCF 0x00000100 /* on if WME/MAC suspended */ + +/* MacFilter offsets. */ +#define B43legacy_MACFILTER_SELF 0x0000 +#define B43legacy_MACFILTER_BSSID 0x0003 +#define B43legacy_MACFILTER_MAC 0x0010 + +/* PHYVersioning */ +#define B43legacy_PHYTYPE_B 0x01 +#define B43legacy_PHYTYPE_G 0x02 + +/* PHYRegisters */ +#define B43legacy_PHY_G_LO_CONTROL 0x0810 +#define B43legacy_PHY_ILT_G_CTRL 0x0472 +#define B43legacy_PHY_ILT_G_DATA1 0x0473 +#define B43legacy_PHY_ILT_G_DATA2 0x0474 +#define B43legacy_PHY_G_PCTL 0x0029 +#define B43legacy_PHY_RADIO_BITFIELD 0x0401 +#define B43legacy_PHY_G_CRS 0x0429 +#define B43legacy_PHY_NRSSILT_CTRL 0x0803 +#define B43legacy_PHY_NRSSILT_DATA 0x0804 + +/* RadioRegisters */ +#define B43legacy_RADIOCTL_ID 0x01 + +/* MAC Control bitfield */ +#define B43legacy_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */ +#define B43legacy_MACCTL_INFRA 0x00020000 /* Infrastructure mode */ +#define B43legacy_MACCTL_AP 0x00040000 /* AccessPoint mode */ +#define B43legacy_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep bad PLCP frames */ +#define B43legacy_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */ +#define B43legacy_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */ +#define B43legacy_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */ +#define B43legacy_MACCTL_GMODE 0x80000000 /* G Mode */ + +/* StatusBitField */ +#define B43legacy_SBF_MAC_ENABLED 0x00000001 +#define B43legacy_SBF_CORE_READY 0x00000004 +#define B43legacy_SBF_400 0x00000400 /*FIXME: fix name*/ +#define B43legacy_SBF_XFER_REG_BYTESWAP 0x00010000 +#define B43legacy_SBF_MODE_NOTADHOC 0x00020000 +#define B43legacy_SBF_MODE_AP 0x00040000 +#define B43legacy_SBF_RADIOREG_LOCK 0x00080000 +#define B43legacy_SBF_MODE_MONITOR 0x00400000 +#define B43legacy_SBF_MODE_PROMISC 0x01000000 +#define B43legacy_SBF_PS1 0x02000000 +#define B43legacy_SBF_PS2 0x04000000 +#define B43legacy_SBF_NO_SSID_BCAST 0x08000000 +#define B43legacy_SBF_TIME_UPDATE 0x10000000 + +/* 802.11 core specific TM State Low flags */ +#define B43legacy_TMSLOW_GMODE 0x20000000 /* G Mode Enable */ +#define B43legacy_TMSLOW_PLLREFSEL 0x00200000 /* PLL Freq Ref Select */ +#define B43legacy_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Ctrl Enbl */ +#define B43legacy_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */ +#define B43legacy_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */ + +/* 802.11 core specific TM State High flags */ +#define B43legacy_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available */ +#define B43legacy_TMSHIGH_GPHY 0x00010000 /* G-PHY avail (rev >= 5) */ + +#define B43legacy_UCODEFLAG_AUTODIV 0x0001 + +/* Generic-Interrupt reasons. */ +#define B43legacy_IRQ_MAC_SUSPENDED 0x00000001 +#define B43legacy_IRQ_BEACON 0x00000002 +#define B43legacy_IRQ_TBTT_INDI 0x00000004 /* Target Beacon Transmit Time */ +#define B43legacy_IRQ_BEACON_TX_OK 0x00000008 +#define B43legacy_IRQ_BEACON_CANCEL 0x00000010 +#define B43legacy_IRQ_ATIM_END 0x00000020 +#define B43legacy_IRQ_PMQ 0x00000040 +#define B43legacy_IRQ_PIO_WORKAROUND 0x00000100 +#define B43legacy_IRQ_MAC_TXERR 0x00000200 +#define B43legacy_IRQ_PHY_TXERR 0x00000800 +#define B43legacy_IRQ_PMEVENT 0x00001000 +#define B43legacy_IRQ_TIMER0 0x00002000 +#define B43legacy_IRQ_TIMER1 0x00004000 +#define B43legacy_IRQ_DMA 0x00008000 +#define B43legacy_IRQ_TXFIFO_FLUSH_OK 0x00010000 +#define B43legacy_IRQ_CCA_MEASURE_OK 0x00020000 +#define B43legacy_IRQ_NOISESAMPLE_OK 0x00040000 +#define B43legacy_IRQ_UCODE_DEBUG 0x08000000 +#define B43legacy_IRQ_RFKILL 0x10000000 +#define B43legacy_IRQ_TX_OK 0x20000000 +#define B43legacy_IRQ_PHY_G_CHANGED 0x40000000 +#define B43legacy_IRQ_TIMEOUT 0x80000000 + +#define B43legacy_IRQ_ALL 0xFFFFFFFF +#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \ + B43legacy_IRQ_BEACON | \ + B43legacy_IRQ_TBTT_INDI | \ + B43legacy_IRQ_ATIM_END | \ + B43legacy_IRQ_PMQ | \ + B43legacy_IRQ_MAC_TXERR | \ + B43legacy_IRQ_PHY_TXERR | \ + B43legacy_IRQ_DMA | \ + B43legacy_IRQ_TXFIFO_FLUSH_OK | \ + B43legacy_IRQ_NOISESAMPLE_OK | \ + B43legacy_IRQ_UCODE_DEBUG | \ + B43legacy_IRQ_RFKILL | \ + B43legacy_IRQ_TX_OK) + +/* Device specific rate values. + * The actual values defined here are (rate_in_mbps * 2). + * Some code depends on this. Don't change it. */ +#define B43legacy_CCK_RATE_1MB 2 +#define B43legacy_CCK_RATE_2MB 4 +#define B43legacy_CCK_RATE_5MB 11 +#define B43legacy_CCK_RATE_11MB 22 +#define B43legacy_OFDM_RATE_6MB 12 +#define B43legacy_OFDM_RATE_9MB 18 +#define B43legacy_OFDM_RATE_12MB 24 +#define B43legacy_OFDM_RATE_18MB 36 +#define B43legacy_OFDM_RATE_24MB 48 +#define B43legacy_OFDM_RATE_36MB 72 +#define B43legacy_OFDM_RATE_48MB 96 +#define B43legacy_OFDM_RATE_54MB 108 +/* Convert a b43legacy rate value to a rate in 100kbps */ +#define B43legacy_RATE_TO_100KBPS(rate) (((rate) * 10) / 2) + + +#define B43legacy_DEFAULT_SHORT_RETRY_LIMIT 7 +#define B43legacy_DEFAULT_LONG_RETRY_LIMIT 4 + +/* Max size of a security key */ +#define B43legacy_SEC_KEYSIZE 16 +/* Security algorithms. */ +enum { + B43legacy_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ + B43legacy_SEC_ALGO_WEP40, + B43legacy_SEC_ALGO_TKIP, + B43legacy_SEC_ALGO_AES, + B43legacy_SEC_ALGO_WEP104, + B43legacy_SEC_ALGO_AES_LEGACY, +}; + +/* Core Information Registers */ +#define B43legacy_CIR_BASE 0xf00 +#define B43legacy_CIR_SBTPSFLAG (B43legacy_CIR_BASE + 0x18) +#define B43legacy_CIR_SBIMSTATE (B43legacy_CIR_BASE + 0x90) +#define B43legacy_CIR_SBINTVEC (B43legacy_CIR_BASE + 0x94) +#define B43legacy_CIR_SBTMSTATELOW (B43legacy_CIR_BASE + 0x98) +#define B43legacy_CIR_SBTMSTATEHIGH (B43legacy_CIR_BASE + 0x9c) +#define B43legacy_CIR_SBIMCONFIGLOW (B43legacy_CIR_BASE + 0xa8) +#define B43legacy_CIR_SB_ID_HI (B43legacy_CIR_BASE + 0xfc) + +/* sbtmstatehigh state flags */ +#define B43legacy_SBTMSTATEHIGH_SERROR 0x00000001 +#define B43legacy_SBTMSTATEHIGH_BUSY 0x00000004 +#define B43legacy_SBTMSTATEHIGH_TIMEOUT 0x00000020 +#define B43legacy_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000 +#define B43legacy_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000 +#define B43legacy_SBTMSTATEHIGH_DMA64BIT 0x10000000 +#define B43legacy_SBTMSTATEHIGH_GATEDCLK 0x20000000 +#define B43legacy_SBTMSTATEHIGH_BISTFAILED 0x40000000 +#define B43legacy_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000 + +/* sbimstate flags */ +#define B43legacy_SBIMSTATE_IB_ERROR 0x20000 +#define B43legacy_SBIMSTATE_TIMEOUT 0x40000 + +#define PFX KBUILD_MODNAME ": " +#ifdef assert +# undef assert +#endif +#ifdef CONFIG_B43LEGACY_DEBUG +# define B43legacy_WARN_ON(expr) \ + do { \ + if (unlikely((expr))) { \ + printk(KERN_INFO PFX "Test (%s) failed at:" \ + " %s:%d:%s()\n", \ + #expr, __FILE__, \ + __LINE__, __FUNCTION__); \ + } \ + } while (0) +# define B43legacy_BUG_ON(expr) \ + do { \ + if (unlikely((expr))) { \ + printk(KERN_INFO PFX "Test (%s) failed\n", \ + #expr); \ + BUG_ON(expr); \ + } \ + } while (0) +# define B43legacy_DEBUG 1 +#else +# define B43legacy_WARN_ON(x) do { /* nothing */ } while (0) +# define B43legacy_BUG_ON(x) do { /* nothing */ } while (0) +# define B43legacy_DEBUG 0 +#endif + + +struct net_device; +struct pci_dev; +struct b43legacy_dmaring; +struct b43legacy_pioqueue; + +/* The firmware file header */ +#define B43legacy_FW_TYPE_UCODE 'u' +#define B43legacy_FW_TYPE_PCM 'p' +#define B43legacy_FW_TYPE_IV 'i' +struct b43legacy_fw_header { + /* File type */ + u8 type; + /* File format version */ + u8 ver; + u8 __padding[2]; + /* Size of the data. For ucode and PCM this is in bytes. + * For IV this is number-of-ivs. */ + __be32 size; +} __attribute__((__packed__)); + +/* Initial Value file format */ +#define B43legacy_IV_OFFSET_MASK 0x7FFF +#define B43legacy_IV_32BIT 0x8000 +struct b43legacy_iv { + __be16 offset_size; + union { + __be16 d16; + __be32 d32; + } data __attribute__((__packed__)); +} __attribute__((__packed__)); + +#define B43legacy_PHYMODE(phytype) (1 << (phytype)) +#define B43legacy_PHYMODE_B B43legacy_PHYMODE \ + ((B43legacy_PHYTYPE_B)) +#define B43legacy_PHYMODE_G B43legacy_PHYMODE \ + ((B43legacy_PHYTYPE_G)) + +/* Value pair to measure the LocalOscillator. */ +struct b43legacy_lopair { + s8 low; + s8 high; + u8 used:1; +}; +#define B43legacy_LO_COUNT (14*4) + +struct b43legacy_phy { + /* Possible PHYMODEs on this PHY */ + u8 possible_phymodes; + /* GMODE bit enabled in MACCTL? */ + bool gmode; + /* Possible ieee80211 subsystem hwmodes for this PHY. + * Which mode is selected, depends on thr GMODE enabled bit */ +#define B43legacy_MAX_PHYHWMODES 2 + struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES]; + + /* Analog Type */ + u8 analog; + /* B43legacy_PHYTYPE_ */ + u8 type; + /* PHY revision number. */ + u8 rev; + + u16 antenna_diversity; + u16 savedpctlreg; + /* Radio versioning */ + u16 radio_manuf; /* Radio manufacturer */ + u16 radio_ver; /* Radio version */ + u8 calibrated:1; + u8 radio_rev; /* Radio revision */ + + bool radio_on; /* Radio switched on/off */ + bool locked; /* Only used in b43legacy_phy_{un}lock() */ + bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ + + /* ACI (adjacent channel interference) flags. */ + bool aci_enable; + bool aci_wlan_automatic; + bool aci_hw_rssi; + + u16 minlowsig[2]; + u16 minlowsigpos[2]; + + /* LO Measurement Data. + * Use b43legacy_get_lopair() to get a value. + */ + struct b43legacy_lopair *_lo_pairs; + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* idle TSSI value */ + s8 idle_tssi; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi; + + /* LocalOscillator control values. */ + struct b43legacy_txpower_lo_control *lo_control; + /* Values from b43legacy_calc_loopback_gain() */ + s16 max_lb_gain; /* Maximum Loopback gain in hdB */ + s16 trsw_rx_gain; /* TRSW RX gain in hdB */ + s16 lna_lod_gain; /* LNA lod */ + s16 lna_gain; /* LNA */ + s16 pga_gain; /* PGA */ + + /* PHY lock for core.rev < 3 + * This lock is only used by b43legacy_phy_{un}lock() + */ + spinlock_t lock; + + /* Desired TX power level (in dBm). This is set by the user and + * adjusted in b43legacy_phy_xmitpower(). */ + u8 power_level; + + /* Values from b43legacy_calc_loopback_gain() */ + u16 loopback_gain[2]; + + /* TX Power control values. */ + /* B/G PHY */ + struct { + /* Current Radio Attenuation for TXpower recalculation. */ + u16 rfatt; + /* Current Baseband Attenuation for TXpower recalculation. */ + u16 bbatt; + /* Current TXpower control value for TXpower recalculation. */ + u16 txctl1; + u16 txctl2; + }; + /* A PHY */ + struct { + u16 txpwr_offset; + }; + +#ifdef CONFIG_B43LEGACY_DEBUG + bool manual_txpower_control; /* Manual TX-power control enabled? */ +#endif + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define B43legacy_INTERFSTACK_SIZE 26 + u32 interfstack[B43legacy_INTERFSTACK_SIZE]; + + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + /* current channel */ + u8 channel; + + u16 lofcal; + + u16 initval; +}; + +/* Data structures for DMA transmission, per 80211 core. */ +struct b43legacy_dma { + struct b43legacy_dmaring *tx_ring0; + struct b43legacy_dmaring *tx_ring1; + struct b43legacy_dmaring *tx_ring2; + struct b43legacy_dmaring *tx_ring3; + struct b43legacy_dmaring *tx_ring4; + struct b43legacy_dmaring *tx_ring5; + + struct b43legacy_dmaring *rx_ring0; + struct b43legacy_dmaring *rx_ring3; /* only on core.rev < 5 */ +}; + +/* Data structures for PIO transmission, per 80211 core. */ +struct b43legacy_pio { + struct b43legacy_pioqueue *queue0; + struct b43legacy_pioqueue *queue1; + struct b43legacy_pioqueue *queue2; + struct b43legacy_pioqueue *queue3; +}; + +/* Context information for a noise calculation (Link Quality). */ +struct b43legacy_noise_calculation { + u8 channel_at_start; + bool calculation_running; + u8 nr_samples; + s8 samples[8][4]; +}; + +struct b43legacy_stats { + u8 link_noise; + /* Store the last TX/RX times here for updating the leds. */ + unsigned long last_tx; + unsigned long last_rx; +}; + +struct b43legacy_key { + void *keyconf; + bool enabled; + u8 algorithm; +}; + +struct b43legacy_wldev; + +/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */ +struct b43legacy_wl { + /* Pointer to the active wireless device on this chip */ + struct b43legacy_wldev *current_dev; + /* Pointer to the ieee80211 hardware data structure */ + struct ieee80211_hw *hw; + + spinlock_t irq_lock; /* locks IRQ */ + struct mutex mutex; /* locks wireless core state */ + spinlock_t leds_lock; /* lock for leds */ + + /* We can only have one operating interface (802.11 core) + * at a time. General information about this interface follows. + */ + + /* Opaque ID of the operating interface (!= monitor + * interface) from the ieee80211 subsystem. + * Do not modify. + */ + int if_id; + /* MAC address (can be NULL). */ + const u8 *mac_addr; + /* Current BSSID (can be NULL). */ + const u8 *bssid; + /* Interface type. (IEEE80211_IF_TYPE_XXX) */ + int if_type; + /* Counter of active monitor interfaces. */ + int monitor; + /* Is the card operating in AP, STA or IBSS mode? */ + bool operating; + /* Promisc mode active? + * Note that (monitor != 0) implies promisc. + */ + bool promisc; + /* Stats about the wireless interface */ + struct ieee80211_low_level_stats ieee_stats; + + struct hwrng rng; + u8 rng_initialized; + char rng_name[30 + 1]; + + /* List of all wireless devices on this chip */ + struct list_head devlist; + u8 nr_devs; +}; + +/* Pointers to the firmware data and meta information about it. */ +struct b43legacy_firmware { + /* Microcode */ + const struct firmware *ucode; + /* PCM code */ + const struct firmware *pcm; + /* Initial MMIO values for the firmware */ + const struct firmware *initvals; + /* Initial MMIO values for the firmware, band-specific */ + const struct firmware *initvals_band; + /* Firmware revision */ + u16 rev; + /* Firmware patchlevel */ + u16 patch; +}; + +/* Device (802.11 core) initialization status. */ +enum { + B43legacy_STAT_UNINIT = 0, /* Uninitialized. */ + B43legacy_STAT_INITIALIZED = 1, /* Initialized, not yet started. */ + B43legacy_STAT_STARTED = 2, /* Up and running. */ +}; +#define b43legacy_status(wldev) atomic_read(&(wldev)->__init_status) +#define b43legacy_set_status(wldev, stat) do { \ + atomic_set(&(wldev)->__init_status, (stat)); \ + smp_wmb(); \ + } while (0) + +/* *** --- HOW LOCKING WORKS IN B43legacy --- *** + * + * 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 b43legacy_wldev { + struct ssb_device *dev; + struct b43legacy_wl *wl; + + /* The device initialization status. + * Use b43legacy_status() to query. */ + atomic_t __init_status; + /* Saved init status for handling suspend. */ + int suspend_init_status; + + bool __using_pio; /* Using pio rather than dma. */ + bool bad_frames_preempt;/* Use "Bad Frames Preemption". */ + bool reg124_set_0x4; /* Variable to keep track of IRQ. */ + bool short_preamble; /* TRUE if using short preamble. */ + bool short_slot; /* TRUE if using short slot timing. */ + bool radio_hw_enable; /* State of radio hardware enable bit. */ + + /* PHY/Radio device. */ + struct b43legacy_phy phy; + union { + /* DMA engines. */ + struct b43legacy_dma dma; + /* PIO engines. */ + struct b43legacy_pio pio; + }; + + /* Various statistics about the physical device. */ + struct b43legacy_stats stats; + +#define B43legacy_NR_LEDS 4 + struct b43legacy_led leds[B43legacy_NR_LEDS]; + + /* Reason code of the last interrupt. */ + u32 irq_reason; + u32 dma_reason[6]; + /* saved irq enable/disable state bitfield. */ + u32 irq_savedstate; + /* Link Quality calculation context. */ + struct b43legacy_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; + + struct work_struct restart_work; + + /* encryption/decryption */ + u16 ktp; /* Key table pointer */ + u8 max_nr_keys; + struct b43legacy_key key[58]; + + /* Cached beacon template while uploading the template. */ + struct sk_buff *cached_beacon; + + /* Firmware data */ + struct b43legacy_firmware fw; + + /* Devicelist in struct b43legacy_wl (all 802.11 cores) */ + struct list_head list; + + /* Debugging stuff follows. */ +#ifdef CONFIG_B43LEGACY_DEBUG + struct b43legacy_dfsentry *dfsentry; +#endif +}; + + +static inline +struct b43legacy_wl *hw_to_b43legacy_wl(struct ieee80211_hw *hw) +{ + return hw->priv; +} + +/* Helper function, which returns a boolean. + * TRUE, if PIO is used; FALSE, if DMA is used. + */ +#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) +static inline +int b43legacy_using_pio(struct b43legacy_wldev *dev) +{ + return dev->__using_pio; +} +#elif defined(CONFIG_B43LEGACY_DMA) +static inline +int b43legacy_using_pio(struct b43legacy_wldev *dev) +{ + return 0; +} +#elif defined(CONFIG_B43LEGACY_PIO) +static inline +int b43legacy_using_pio(struct b43legacy_wldev *dev) +{ + return 1; +} +#else +# error "Using neither DMA nor PIO? Confused..." +#endif + + +static inline +struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + return ssb_get_drvdata(ssb_dev); +} + +/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ +static inline +int b43legacy_is_mode(struct b43legacy_wl *wl, int type) +{ + if (type == IEEE80211_IF_TYPE_MNTR) + return !!(wl->monitor); + return (wl->operating && + wl->if_type == type); +} + +static inline +bool is_bcm_board_vendor(struct b43legacy_wldev *dev) +{ + return (dev->dev->bus->boardinfo.vendor == PCI_VENDOR_ID_BROADCOM); +} + +static inline +u16 b43legacy_read16(struct b43legacy_wldev *dev, u16 offset) +{ + return ssb_read16(dev->dev, offset); +} + +static inline +void b43legacy_write16(struct b43legacy_wldev *dev, u16 offset, u16 value) +{ + ssb_write16(dev->dev, offset, value); +} + +static inline +u32 b43legacy_read32(struct b43legacy_wldev *dev, u16 offset) +{ + return ssb_read32(dev->dev, offset); +} + +static inline +void b43legacy_write32(struct b43legacy_wldev *dev, u16 offset, u32 value) +{ + ssb_write32(dev->dev, offset, value); +} + +static inline +struct b43legacy_lopair *b43legacy_get_lopair(struct b43legacy_phy *phy, + u16 radio_attenuation, + u16 baseband_attenuation) +{ + return phy->_lo_pairs + (radio_attenuation + + 14 * (baseband_attenuation / 2)); +} + + + +/* Message printing */ +void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#if B43legacy_DEBUG +void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#else /* DEBUG */ +# define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0) +#endif /* DEBUG */ + + +/** Limit a value between two limits */ +#ifdef limit_value +# undef limit_value +#endif +#define limit_value(value, min, max) \ + ({ \ + typeof(value) __value = (value); \ + typeof(value) __min = (min); \ + typeof(value) __max = (max); \ + if (__value < __min) \ + __value = __min; \ + else if (__value > __max) \ + __value = __max; \ + __value; \ + }) + +/* Macros for printing a value in Q5.2 format */ +#define Q52_FMT "%u.%u" +#define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4) + +#endif /* B43legacy_H_ */ diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c new file mode 100644 index 000000000000..eefa6fb79685 --- /dev/null +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -0,0 +1,505 @@ +/* + + Broadcom B43legacy wireless driver + + debugfs driver debugging code + + Copyright (c) 2005-2007 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "b43legacy.h" +#include "main.h" +#include "debugfs.h" +#include "dma.h" +#include "pio.h" +#include "xmit.h" + + +/* The root directory. */ +static struct dentry *rootdir; + +struct b43legacy_debugfs_fops { + ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize); + int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count); + struct file_operations fops; + /* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */ + size_t file_struct_offset; + /* Take wl->irq_lock before calling read/write? */ + bool take_irqlock; +}; + +static inline +struct b43legacy_dfs_file * fops_to_dfs_file(struct b43legacy_wldev *dev, + const struct b43legacy_debugfs_fops *dfops) +{ + void *p; + + p = dev->dfsentry; + p += dfops->file_struct_offset; + + return p; +} + + +#define fappend(fmt, x...) \ + do { \ + if (bufsize - count) \ + count += snprintf(buf + count, \ + bufsize - count, \ + fmt , ##x); \ + else \ + printk(KERN_ERR "b43legacy: fappend overflow\n"); \ + } while (0) + + +/* wl->irq_lock is locked */ +static ssize_t tsf_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + u64 tsf; + + b43legacy_tsf_read(dev, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); + + return count; +} + +/* wl->irq_lock is locked */ +static int tsf_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count) +{ + u64 tsf; + + if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) + return -EINVAL; + b43legacy_tsf_write(dev, tsf); + + return 0; +} + +/* wl->irq_lock is locked */ +static ssize_t ucode_regs_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + int i; + + for (i = 0; i < 64; i++) { + fappend("r%d = 0x%04x\n", i, + b43legacy_shm_read16(dev, B43legacy_SHM_WIRELESS, i)); + } + + return count; +} + +/* wl->irq_lock is locked */ +static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + int i; + u16 tmp; + __le16 *le16buf = (__le16 *)buf; + + for (i = 0; i < 0x1000; i++) { + if (bufsize <= 0) + break; + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i); + le16buf[i] = cpu_to_le16(tmp); + count += sizeof(tmp); + bufsize -= sizeof(tmp); + } + + return count; +} + +static ssize_t txstat_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize) +{ + struct b43legacy_txstatus_log *log = &dev->dfsentry->txstatlog; + ssize_t count = 0; + unsigned long flags; + int i, idx; + struct b43legacy_txstatus *stat; + + spin_lock_irqsave(&log->lock, flags); + if (log->end < 0) { + fappend("Nothing transmitted, yet\n"); + goto out_unlock; + } + fappend("b43legacy TX status reports:\n\n" + "index | cookie | seq | phy_stat | frame_count | " + "rts_count | supp_reason | pm_indicated | " + "intermediate | for_ampdu | acked\n" "---\n"); + i = log->end + 1; + idx = 0; + while (1) { + if (i == B43legacy_NR_LOGGED_TXSTATUS) + i = 0; + stat = &(log->log[i]); + if (stat->cookie) { + fappend("%03d | " + "0x%04X | 0x%04X | 0x%02X | " + "0x%X | 0x%X | " + "%u | %u | " + "%u | %u | %u\n", + idx, + stat->cookie, stat->seq, stat->phy_stat, + stat->frame_count, stat->rts_count, + stat->supp_reason, stat->pm_indicated, + stat->intermediate, stat->for_ampdu, + stat->acked); + idx++; + } + if (i == log->end) + break; + i++; + } +out_unlock: + spin_unlock_irqrestore(&log->lock, flags); + + return count; +} + +/* wl->irq_lock is locked */ +static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count) +{ + int err = 0; + + if (count > 0 && buf[0] == '1') { + b43legacy_controller_restart(dev, "manually restarted"); + } else + err = -EINVAL; + + return err; +} + +#undef fappend + +static int b43legacy_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct b43legacy_wldev *dev; + struct b43legacy_debugfs_fops *dfops; + struct b43legacy_dfs_file *dfile; + ssize_t ret = 0; + char *buf; + const size_t bufsize = 1024 * 128; + const size_t buforder = get_order(bufsize); + int err = 0; + + if (!count) + return 0; + dev = file->private_data; + if (!dev) + return -ENODEV; + + mutex_lock(&dev->wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops); + if (!dfops->read) { + err = -ENOSYS; + goto out_unlock; + } + dfile = fops_to_dfs_file(dev, dfops); + + if (!dfile->buffer) { + buf = (char *)__get_free_pages(GFP_KERNEL, buforder); + if (!buf) { + err = -ENOMEM; + 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); + if (ret <= 0) { + free_pages((unsigned long)buf, buforder); + err = ret; + goto out_unlock; + } + dfile->data_len = ret; + dfile->buffer = buf; + } + + ret = simple_read_from_buffer(userbuf, count, ppos, + dfile->buffer, + dfile->data_len); + if (*ppos >= dfile->data_len) { + free_pages((unsigned long)dfile->buffer, buforder); + dfile->buffer = NULL; + dfile->data_len = 0; + } +out_unlock: + mutex_unlock(&dev->wl->mutex); + + return err ? err : ret; +} + +static ssize_t b43legacy_debugfs_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct b43legacy_wldev *dev; + struct b43legacy_debugfs_fops *dfops; + char *buf; + int err = 0; + + if (!count) + return 0; + if (count > PAGE_SIZE) + return -E2BIG; + dev = file->private_data; + if (!dev) + return -ENODEV; + + mutex_lock(&dev->wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops); + if (!dfops->write) { + err = -ENOSYS; + goto out_unlock; + } + + buf = (char *)get_zeroed_page(GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out_unlock; + } + if (copy_from_user(buf, userbuf, count)) { + 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); + if (err) + goto out_freepage; + +out_freepage: + free_page((unsigned long)buf); +out_unlock: + mutex_unlock(&dev->wl->mutex); + + return err ? err : count; +} + + +#define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ + static struct b43legacy_debugfs_fops fops_##name = { \ + .read = _read, \ + .write = _write, \ + .fops = { \ + .open = b43legacy_debugfs_open, \ + .read = b43legacy_debugfs_read, \ + .write = b43legacy_debugfs_write, \ + }, \ + .file_struct_offset = offsetof(struct b43legacy_dfsentry, \ + file_##name), \ + .take_irqlock = _take_irqlock, \ + } + +B43legacy_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); +B43legacy_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1); +B43legacy_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1); +B43legacy_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); +B43legacy_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); + + +int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature) +{ + return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]); +} + +static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev) +{ + struct b43legacy_dfsentry *e = dev->dfsentry; + int i; + + for (i = 0; i < __B43legacy_NR_DYNDBG; i++) + debugfs_remove(e->dyn_debug_dentries[i]); +} + +static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev) +{ + struct b43legacy_dfsentry *e = dev->dfsentry; + struct dentry *d; + +#define add_dyn_dbg(name, id, initstate) do { \ + e->dyn_debug[id] = (initstate); \ + d = debugfs_create_bool(name, 0600, e->subdir, \ + &(e->dyn_debug[id])); \ + if (!IS_ERR(d)) \ + e->dyn_debug_dentries[id] = d; \ + } while (0) + + add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, 0); + add_dyn_dbg("debug_dmaoverflow", B43legacy_DBG_DMAOVERFLOW, 0); + add_dyn_dbg("debug_dmaverbose", B43legacy_DBG_DMAVERBOSE, 0); + add_dyn_dbg("debug_pwork_fast", B43legacy_DBG_PWORK_FAST, 0); + add_dyn_dbg("debug_pwork_stop", B43legacy_DBG_PWORK_STOP, 0); + +#undef add_dyn_dbg +} + +void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) +{ + struct b43legacy_dfsentry *e; + struct b43legacy_txstatus_log *log; + char devdir[16]; + + B43legacy_WARN_ON(!dev); + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { + b43legacyerr(dev->wl, "debugfs: add device OOM\n"); + return; + } + e->dev = dev; + log = &e->txstatlog; + log->log = kcalloc(B43legacy_NR_LOGGED_TXSTATUS, + sizeof(struct b43legacy_txstatus), GFP_KERNEL); + if (!log->log) { + b43legacyerr(dev->wl, "debugfs: add device txstatus OOM\n"); + kfree(e); + return; + } + log->end = -1; + spin_lock_init(&log->lock); + + dev->dfsentry = e; + + snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy)); + e->subdir = debugfs_create_dir(devdir, rootdir); + if (!e->subdir || IS_ERR(e->subdir)) { + if (e->subdir == ERR_PTR(-ENODEV)) { + b43legacydbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not " + "enabled in kernel config\n"); + } else { + b43legacyerr(dev->wl, "debugfs: cannot create %s directory\n", + devdir); + } + dev->dfsentry = NULL; + kfree(log->log); + kfree(e); + return; + } + +#define ADD_FILE(name, mode) \ + do { \ + struct dentry *d; \ + d = debugfs_create_file(__stringify(name), \ + mode, e->subdir, dev, \ + &fops_##name.fops); \ + e->file_##name.dentry = NULL; \ + if (!IS_ERR(d)) \ + e->file_##name.dentry = d; \ + } while (0) + + + ADD_FILE(tsf, 0600); + ADD_FILE(ucode_regs, 0400); + ADD_FILE(shm, 0400); + ADD_FILE(txstat, 0400); + ADD_FILE(restart, 0200); + +#undef ADD_FILE + + b43legacy_add_dynamic_debug(dev); +} + +void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) +{ + struct b43legacy_dfsentry *e; + + if (!dev) + return; + e = dev->dfsentry; + if (!e) + return; + b43legacy_remove_dynamic_debug(dev); + + debugfs_remove(e->file_tsf.dentry); + debugfs_remove(e->file_ucode_regs.dentry); + debugfs_remove(e->file_shm.dentry); + debugfs_remove(e->file_txstat.dentry); + debugfs_remove(e->file_restart.dentry); + + debugfs_remove(e->subdir); + kfree(e->txstatlog.log); + kfree(e); +} + +void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ + struct b43legacy_dfsentry *e = dev->dfsentry; + struct b43legacy_txstatus_log *log; + struct b43legacy_txstatus *cur; + int i; + + if (!e) + return; + log = &e->txstatlog; + B43legacy_WARN_ON(!irqs_disabled()); + spin_lock(&log->lock); + i = log->end + 1; + if (i == B43legacy_NR_LOGGED_TXSTATUS) + i = 0; + log->end = i; + cur = &(log->log[i]); + memcpy(cur, status, sizeof(*cur)); + spin_unlock(&log->lock); +} + +void b43legacy_debugfs_init(void) +{ + rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR(rootdir)) + rootdir = NULL; +} + +void b43legacy_debugfs_exit(void) +{ + debugfs_remove(rootdir); +} diff --git a/drivers/net/wireless/b43legacy/debugfs.h b/drivers/net/wireless/b43legacy/debugfs.h new file mode 100644 index 000000000000..ae3b0d0fa849 --- /dev/null +++ b/drivers/net/wireless/b43legacy/debugfs.h @@ -0,0 +1,89 @@ +#ifndef B43legacy_DEBUGFS_H_ +#define B43legacy_DEBUGFS_H_ + +struct b43legacy_wldev; +struct b43legacy_txstatus; + +enum b43legacy_dyndbg { /* Dynamic debugging features */ + B43legacy_DBG_XMITPOWER, + B43legacy_DBG_DMAOVERFLOW, + B43legacy_DBG_DMAVERBOSE, + B43legacy_DBG_PWORK_FAST, + B43legacy_DBG_PWORK_STOP, + __B43legacy_NR_DYNDBG, +}; + + +#ifdef CONFIG_B43LEGACY_DEBUG + +struct dentry; + +#define B43legacy_NR_LOGGED_TXSTATUS 100 + +struct b43legacy_txstatus_log { + struct b43legacy_txstatus *log; + int end; + spinlock_t lock; /* lock for debugging */ +}; + +struct b43legacy_dfs_file { + struct dentry *dentry; + char *buffer; + size_t data_len; +}; + +struct b43legacy_dfsentry { + struct b43legacy_wldev *dev; + struct dentry *subdir; + + struct b43legacy_dfs_file file_tsf; + struct b43legacy_dfs_file file_ucode_regs; + struct b43legacy_dfs_file file_shm; + struct b43legacy_dfs_file file_txstat; + struct b43legacy_dfs_file file_txpower_g; + struct b43legacy_dfs_file file_restart; + struct b43legacy_dfs_file file_loctls; + + struct b43legacy_txstatus_log txstatlog; + + /* Enabled/Disabled list for the dynamic debugging features. */ + u32 dyn_debug[__B43legacy_NR_DYNDBG]; + /* Dentries for the dynamic debugging entries. */ + struct dentry *dyn_debug_dentries[__B43legacy_NR_DYNDBG]; +}; + +int b43legacy_debug(struct b43legacy_wldev *dev, + enum b43legacy_dyndbg feature); + +void b43legacy_debugfs_init(void); +void b43legacy_debugfs_exit(void); +void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev); +void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev); +void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status); + +#else /* CONFIG_B43LEGACY_DEBUG*/ + +static inline +int b43legacy_debug(struct b43legacy_wldev *dev, + enum b43legacy_dyndbg feature) +{ + return 0; +} + +static inline +void b43legacy_debugfs_init(void) { } +static inline +void b43legacy_debugfs_exit(void) { } +static inline +void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) { } +static inline +void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) { } +static inline +void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) + { } + +#endif /* CONFIG_B43LEGACY_DEBUG*/ + +#endif /* B43legacy_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c new file mode 100644 index 000000000000..8cb3dc4c4745 --- /dev/null +++ b/drivers/net/wireless/b43legacy/dma.c @@ -0,0 +1,1565 @@ +/* + + Broadcom B43legacy wireless driver + + DMA ringbuffer and descriptor allocation/management + + Copyright (c) 2005, 2006 Michael Buesch + + Some code in this file is derived from the b44.c driver + Copyright (C) 2002 David S. Miller + Copyright (C) Pekka Pietikainen + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43legacy.h" +#include "dma.h" +#include "main.h" +#include "debugfs.h" +#include "xmit.h" + +#include +#include +#include +#include +#include + +/* 32bit DMA ops. */ +static +struct b43legacy_dmadesc_generic *op32_idx2desc( + struct b43legacy_dmaring *ring, + int slot, + struct b43legacy_dmadesc_meta **meta) +{ + struct b43legacy_dmadesc32 *desc; + + *meta = &(ring->meta[slot]); + desc = ring->descbase; + desc = &(desc[slot]); + + return (struct b43legacy_dmadesc_generic *)desc; +} + +static void op32_fill_descriptor(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq) +{ + struct b43legacy_dmadesc32 *descbase = ring->descbase; + int slot; + u32 ctl; + u32 addr; + u32 addrext; + + slot = (int)(&(desc->dma32) - descbase); + B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + + addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK); + addrext = (u32)(dmaaddr & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + addr |= ssb_dma_translation(ring->dev->dev); + ctl = (bufsize - ring->frameoffset) + & B43legacy_DMA32_DCTL_BYTECNT; + if (slot == ring->nr_slots - 1) + ctl |= B43legacy_DMA32_DCTL_DTABLEEND; + if (start) + ctl |= B43legacy_DMA32_DCTL_FRAMESTART; + if (end) + ctl |= B43legacy_DMA32_DCTL_FRAMEEND; + if (irq) + ctl |= B43legacy_DMA32_DCTL_IRQ; + ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT) + & B43legacy_DMA32_DCTL_ADDREXT_MASK; + + desc->dma32.control = cpu_to_le32(ctl); + desc->dma32.address = cpu_to_le32(addr); +} + +static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot) +{ + b43legacy_dma_write(ring, B43legacy_DMA32_TXINDEX, + (u32)(slot * sizeof(struct b43legacy_dmadesc32))); +} + +static void op32_tx_suspend(struct b43legacy_dmaring *ring) +{ + b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, + b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL) + | B43legacy_DMA32_TXSUSPEND); +} + +static void op32_tx_resume(struct b43legacy_dmaring *ring) +{ + b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, + b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL) + & ~B43legacy_DMA32_TXSUSPEND); +} + +static int op32_get_current_rxslot(struct b43legacy_dmaring *ring) +{ + u32 val; + + val = b43legacy_dma_read(ring, B43legacy_DMA32_RXSTATUS); + val &= B43legacy_DMA32_RXDPTR; + + return (val / sizeof(struct b43legacy_dmadesc32)); +} + +static void op32_set_current_rxslot(struct b43legacy_dmaring *ring, + int slot) +{ + b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, + (u32)(slot * sizeof(struct b43legacy_dmadesc32))); +} + +static const struct b43legacy_dma_ops dma32_ops = { + .idx2desc = op32_idx2desc, + .fill_descriptor = op32_fill_descriptor, + .poke_tx = op32_poke_tx, + .tx_suspend = op32_tx_suspend, + .tx_resume = op32_tx_resume, + .get_current_rxslot = op32_get_current_rxslot, + .set_current_rxslot = op32_set_current_rxslot, +}; + +/* 64bit DMA ops. */ +static +struct b43legacy_dmadesc_generic *op64_idx2desc( + struct b43legacy_dmaring *ring, + int slot, + struct b43legacy_dmadesc_meta + **meta) +{ + struct b43legacy_dmadesc64 *desc; + + *meta = &(ring->meta[slot]); + desc = ring->descbase; + desc = &(desc[slot]); + + return (struct b43legacy_dmadesc_generic *)desc; +} + +static void op64_fill_descriptor(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq) +{ + struct b43legacy_dmadesc64 *descbase = ring->descbase; + int slot; + u32 ctl0 = 0; + u32 ctl1 = 0; + u32 addrlo; + u32 addrhi; + u32 addrext; + + slot = (int)(&(desc->dma64) - descbase); + B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + + addrlo = (u32)(dmaaddr & 0xFFFFFFFF); + addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); + addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + addrhi |= ssb_dma_translation(ring->dev->dev); + if (slot == ring->nr_slots - 1) + ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND; + if (start) + ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART; + if (end) + ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND; + if (irq) + ctl0 |= B43legacy_DMA64_DCTL0_IRQ; + ctl1 |= (bufsize - ring->frameoffset) + & B43legacy_DMA64_DCTL1_BYTECNT; + ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT) + & B43legacy_DMA64_DCTL1_ADDREXT_MASK; + + desc->dma64.control0 = cpu_to_le32(ctl0); + desc->dma64.control1 = cpu_to_le32(ctl1); + desc->dma64.address_low = cpu_to_le32(addrlo); + desc->dma64.address_high = cpu_to_le32(addrhi); +} + +static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot) +{ + b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX, + (u32)(slot * sizeof(struct b43legacy_dmadesc64))); +} + +static void op64_tx_suspend(struct b43legacy_dmaring *ring) +{ + b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, + b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) + | B43legacy_DMA64_TXSUSPEND); +} + +static void op64_tx_resume(struct b43legacy_dmaring *ring) +{ + b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, + b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) + & ~B43legacy_DMA64_TXSUSPEND); +} + +static int op64_get_current_rxslot(struct b43legacy_dmaring *ring) +{ + u32 val; + + val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS); + val &= B43legacy_DMA64_RXSTATDPTR; + + return (val / sizeof(struct b43legacy_dmadesc64)); +} + +static void op64_set_current_rxslot(struct b43legacy_dmaring *ring, + int slot) +{ + b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, + (u32)(slot * sizeof(struct b43legacy_dmadesc64))); +} + +static const struct b43legacy_dma_ops dma64_ops = { + .idx2desc = op64_idx2desc, + .fill_descriptor = op64_fill_descriptor, + .poke_tx = op64_poke_tx, + .tx_suspend = op64_tx_suspend, + .tx_resume = op64_tx_resume, + .get_current_rxslot = op64_get_current_rxslot, + .set_current_rxslot = op64_set_current_rxslot, +}; + + +static inline int free_slots(struct b43legacy_dmaring *ring) +{ + return (ring->nr_slots - ring->used_slots); +} + +static inline int next_slot(struct b43legacy_dmaring *ring, int slot) +{ + B43legacy_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1)); + if (slot == ring->nr_slots - 1) + return 0; + return slot + 1; +} + +static inline int prev_slot(struct b43legacy_dmaring *ring, int slot) +{ + B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1)); + if (slot == 0) + return ring->nr_slots - 1; + return slot - 1; +} + +#ifdef CONFIG_B43LEGACY_DEBUG +static void update_max_used_slots(struct b43legacy_dmaring *ring, + int current_used_slots) +{ + if (current_used_slots <= ring->max_used_slots) + return; + ring->max_used_slots = current_used_slots; + if (b43legacy_debug(ring->dev, B43legacy_DBG_DMAVERBOSE)) + b43legacydbg(ring->dev->wl, + "max_used_slots increased to %d on %s ring %d\n", + ring->max_used_slots, + ring->tx ? "TX" : "RX", + ring->index); +} +#else +static inline +void update_max_used_slots(struct b43legacy_dmaring *ring, + int current_used_slots) +{ } +#endif /* DEBUG */ + +/* Request a slot for usage. */ +static inline +int request_slot(struct b43legacy_dmaring *ring) +{ + int slot; + + B43legacy_WARN_ON(!ring->tx); + B43legacy_WARN_ON(ring->stopped); + B43legacy_WARN_ON(free_slots(ring) == 0); + + slot = next_slot(ring, ring->current_slot); + ring->current_slot = slot; + ring->used_slots++; + + update_max_used_slots(ring, ring->used_slots); + + return slot; +} + +/* Mac80211-queue to b43legacy-ring mapping */ +static struct b43legacy_dmaring *priority_to_txring( + struct b43legacy_wldev *dev, + int queue_priority) +{ + struct b43legacy_dmaring *ring; + +/*FIXME: For now we always run on TX-ring-1 */ +return dev->dma.tx_ring1; + + /* 0 = highest priority */ + switch (queue_priority) { + default: + B43legacy_WARN_ON(1); + /* fallthrough */ + case 0: + ring = dev->dma.tx_ring3; + break; + case 1: + ring = dev->dma.tx_ring2; + break; + case 2: + ring = dev->dma.tx_ring1; + break; + case 3: + ring = dev->dma.tx_ring0; + break; + case 4: + ring = dev->dma.tx_ring4; + break; + case 5: + ring = dev->dma.tx_ring5; + break; + } + + return ring; +} + +/* Bcm4301-ring to mac80211-queue mapping */ +static inline int txring_to_priority(struct b43legacy_dmaring *ring) +{ + static const u8 idx_to_prio[] = + { 3, 2, 1, 0, 4, 5, }; + +/*FIXME: have only one queue, for now */ +return 0; + + return idx_to_prio[ring->index]; +} + + +u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx) +{ + static const u16 map64[] = { + B43legacy_MMIO_DMA64_BASE0, + B43legacy_MMIO_DMA64_BASE1, + B43legacy_MMIO_DMA64_BASE2, + B43legacy_MMIO_DMA64_BASE3, + B43legacy_MMIO_DMA64_BASE4, + B43legacy_MMIO_DMA64_BASE5, + }; + static const u16 map32[] = { + B43legacy_MMIO_DMA32_BASE0, + B43legacy_MMIO_DMA32_BASE1, + B43legacy_MMIO_DMA32_BASE2, + B43legacy_MMIO_DMA32_BASE3, + B43legacy_MMIO_DMA32_BASE4, + B43legacy_MMIO_DMA32_BASE5, + }; + + if (dma64bit) { + B43legacy_WARN_ON(!(controller_idx >= 0 && + controller_idx < ARRAY_SIZE(map64))); + return map64[controller_idx]; + } + B43legacy_WARN_ON(!(controller_idx >= 0 && + controller_idx < ARRAY_SIZE(map32))); + return map32[controller_idx]; +} + +static inline +dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring, + unsigned char *buf, + size_t len, + int tx) +{ + dma_addr_t dmaaddr; + + if (tx) + dmaaddr = dma_map_single(ring->dev->dev->dev, + buf, len, + DMA_TO_DEVICE); + else + dmaaddr = dma_map_single(ring->dev->dev->dev, + buf, len, + DMA_FROM_DEVICE); + + return dmaaddr; +} + +static inline +void unmap_descbuffer(struct b43legacy_dmaring *ring, + dma_addr_t addr, + size_t len, + int tx) +{ + if (tx) + dma_unmap_single(ring->dev->dev->dev, + addr, len, + DMA_TO_DEVICE); + else + dma_unmap_single(ring->dev->dev->dev, + addr, len, + DMA_FROM_DEVICE); +} + +static inline +void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + B43legacy_WARN_ON(ring->tx); + + dma_sync_single_for_cpu(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void sync_descbuffer_for_device(struct b43legacy_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + B43legacy_WARN_ON(ring->tx); + + dma_sync_single_for_device(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void free_descriptor_buffer(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_meta *meta, + int irq_context) +{ + if (meta->skb) { + if (irq_context) + dev_kfree_skb_irq(meta->skb); + else + dev_kfree_skb(meta->skb); + meta->skb = NULL; + } +} + +static int alloc_ringmemory(struct b43legacy_dmaring *ring) +{ + struct device *dev = ring->dev->dev->dev; + + ring->descbase = dma_alloc_coherent(dev, B43legacy_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); + if (!ring->descbase) { + b43legacyerr(ring->dev->wl, "DMA ringmemory allocation" + " failed\n"); + return -ENOMEM; + } + memset(ring->descbase, 0, B43legacy_DMA_RINGMEMSIZE); + + return 0; +} + +static void free_ringmemory(struct b43legacy_dmaring *ring) +{ + struct device *dev = ring->dev->dev->dev; + + dma_free_coherent(dev, B43legacy_DMA_RINGMEMSIZE, + ring->descbase, ring->dmabase); +} + +/* Reset the RX DMA channel */ +int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, + u16 mmio_base, int dma64) +{ + int i; + u32 value; + u16 offset; + + might_sleep(); + + offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL; + b43legacy_write32(dev, mmio_base + offset, 0); + for (i = 0; i < 10; i++) { + offset = dma64 ? B43legacy_DMA64_RXSTATUS : + B43legacy_DMA32_RXSTATUS; + value = b43legacy_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43legacy_DMA64_RXSTAT; + if (value == B43legacy_DMA64_RXSTAT_DISABLED) { + i = -1; + break; + } + } else { + value &= B43legacy_DMA32_RXSTATE; + if (value == B43legacy_DMA32_RXSTAT_DISABLED) { + i = -1; + break; + } + } + msleep(1); + } + if (i != -1) { + b43legacyerr(dev->wl, "DMA RX reset timed out\n"); + return -ENODEV; + } + + return 0; +} + +/* Reset the RX DMA channel */ +int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, + u16 mmio_base, int dma64) +{ + int i; + u32 value; + u16 offset; + + might_sleep(); + + for (i = 0; i < 10; i++) { + offset = dma64 ? B43legacy_DMA64_TXSTATUS : + B43legacy_DMA32_TXSTATUS; + value = b43legacy_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43legacy_DMA64_TXSTAT; + if (value == B43legacy_DMA64_TXSTAT_DISABLED || + value == B43legacy_DMA64_TXSTAT_IDLEWAIT || + value == B43legacy_DMA64_TXSTAT_STOPPED) + break; + } else { + value &= B43legacy_DMA32_TXSTATE; + if (value == B43legacy_DMA32_TXSTAT_DISABLED || + value == B43legacy_DMA32_TXSTAT_IDLEWAIT || + value == B43legacy_DMA32_TXSTAT_STOPPED) + break; + } + msleep(1); + } + offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL; + b43legacy_write32(dev, mmio_base + offset, 0); + for (i = 0; i < 10; i++) { + offset = dma64 ? B43legacy_DMA64_TXSTATUS : + B43legacy_DMA32_TXSTATUS; + value = b43legacy_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43legacy_DMA64_TXSTAT; + if (value == B43legacy_DMA64_TXSTAT_DISABLED) { + i = -1; + break; + } + } else { + value &= B43legacy_DMA32_TXSTATE; + if (value == B43legacy_DMA32_TXSTAT_DISABLED) { + i = -1; + break; + } + } + msleep(1); + } + if (i != -1) { + b43legacyerr(dev->wl, "DMA TX reset timed out\n"); + return -ENODEV; + } + /* ensure the reset is completed. */ + msleep(1); + + return 0; +} + +static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_generic *desc, + struct b43legacy_dmadesc_meta *meta, + gfp_t gfp_flags) +{ + struct b43legacy_rxhdr_fw3 *rxhdr; + struct b43legacy_hwtxstatus *txstat; + dma_addr_t dmaaddr; + struct sk_buff *skb; + + B43legacy_WARN_ON(ring->tx); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, + ring->rx_buffersize, 0); + if (dma_mapping_error(dmaaddr)) { + /* ugh. try to realloc in zone_dma */ + gfp_flags |= GFP_DMA; + + dev_kfree_skb_any(skb); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, + ring->rx_buffersize, 0); + } + + if (dma_mapping_error(dmaaddr)) { + dev_kfree_skb_any(skb); + return -EIO; + } + + meta->skb = skb; + meta->dmaaddr = dmaaddr; + ring->ops->fill_descriptor(ring, desc, dmaaddr, + ring->rx_buffersize, 0, 0, 0); + + rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data); + rxhdr->frame_len = 0; + txstat = (struct b43legacy_hwtxstatus *)(skb->data); + txstat->cookie = 0; + + return 0; +} + +/* Allocate the initial descbuffers. + * This is used for an RX ring only. + */ +static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring) +{ + int i; + int err = -ENOMEM; + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + + err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); + if (err) { + b43legacyerr(ring->dev->wl, + "Failed to allocate initial descbuffers\n"); + goto err_unwind; + } + } + mb(); /* all descbuffer setup before next line */ + ring->used_slots = ring->nr_slots; + err = 0; +out: + return err; + +err_unwind: + for (i--; i >= 0; i--) { + desc = ring->ops->idx2desc(ring, i, &meta); + + unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb(meta->skb); + } + goto out; +} + +/* Do initial setup of the DMA controller. + * Reset the controller, write the ring busaddress + * and switch the "enable" bit on. + */ +static int dmacontroller_setup(struct b43legacy_dmaring *ring) +{ + int err = 0; + u32 value; + u32 addrext; + u32 trans = ssb_dma_translation(ring->dev->dev); + + if (ring->tx) { + if (ring->dma64) { + u64 ringbase = (u64)(ring->dmabase); + + addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43legacy_DMA64_TXENABLE; + value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT) + & B43legacy_DMA64_TXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, + value); + b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, + (ringbase & 0xFFFFFFFF)); + b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, + ((ringbase >> 32) + & ~SSB_DMA_TRANSLATION_MASK) + | trans); + } else { + u32 ringbase = (u32)(ring->dmabase); + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43legacy_DMA32_TXENABLE; + value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT) + & B43legacy_DMA32_TXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, + value); + b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, + (ringbase & + ~SSB_DMA_TRANSLATION_MASK) + | trans); + } + } else { + err = alloc_initial_descbuffers(ring); + if (err) + goto out; + if (ring->dma64) { + u64 ringbase = (u64)(ring->dmabase); + + addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << + B43legacy_DMA64_RXFROFF_SHIFT); + value |= B43legacy_DMA64_RXENABLE; + value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT) + & B43legacy_DMA64_RXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL, + value); + b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, + (ringbase & 0xFFFFFFFF)); + b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, + ((ringbase >> 32) & + ~SSB_DMA_TRANSLATION_MASK) | + trans); + b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, + 200); + } else { + u32 ringbase = (u32)(ring->dmabase); + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << + B43legacy_DMA32_RXFROFF_SHIFT); + value |= B43legacy_DMA32_RXENABLE; + value |= (addrext << + B43legacy_DMA32_RXADDREXT_SHIFT) + & B43legacy_DMA32_RXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, + value); + b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, + (ringbase & + ~SSB_DMA_TRANSLATION_MASK) + | trans); + b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, + 200); + } + } + +out: + return err; +} + +/* Shutdown the DMA controller. */ +static void dmacontroller_cleanup(struct b43legacy_dmaring *ring) +{ + if (ring->tx) { + b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base, + ring->dma64); + if (ring->dma64) { + b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0); + b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0); + } else + b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0); + } else { + b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base, + ring->dma64); + if (ring->dma64) { + b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0); + b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0); + } else + b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0); + } +} + +static void free_all_descbuffers(struct b43legacy_dmaring *ring) +{ + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + int i; + + if (!ring->used_slots) + return; + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + + if (!meta->skb) { + B43legacy_WARN_ON(!ring->tx); + continue; + } + if (ring->tx) + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + else + unmap_descbuffer(ring, meta->dmaaddr, + ring->rx_buffersize, 0); + free_descriptor_buffer(ring, meta, 0); + } +} + +static u64 supported_dma_mask(struct b43legacy_wldev *dev) +{ + u32 tmp; + u16 mmio_base; + + tmp = b43legacy_read32(dev, SSB_TMSHIGH); + if (tmp & SSB_TMSHIGH_DMA64) + return DMA_64BIT_MASK; + mmio_base = b43legacy_dmacontroller_base(0, 0); + b43legacy_write32(dev, + mmio_base + B43legacy_DMA32_TXCTL, + B43legacy_DMA32_TXADDREXT_MASK); + tmp = b43legacy_read32(dev, mmio_base + + B43legacy_DMA32_TXCTL); + if (tmp & B43legacy_DMA32_TXADDREXT_MASK) + return DMA_32BIT_MASK; + + return DMA_30BIT_MASK; +} + +/* Main initialization function. */ +static +struct b43legacy_dmaring *b43legacy_setup_dmaring( + struct b43legacy_wldev *dev, + int controller_index, + int for_tx, + int dma64) +{ + struct b43legacy_dmaring *ring; + int err; + int nr_slots; + dma_addr_t dma_test; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out; + + nr_slots = B43legacy_RXRING_SLOTS; + if (for_tx) + nr_slots = B43legacy_TXRING_SLOTS; + + ring->meta = kcalloc(nr_slots, sizeof(struct b43legacy_dmadesc_meta), + GFP_KERNEL); + if (!ring->meta) + goto err_kfree_ring; + if (for_tx) { + ring->txhdr_cache = kcalloc(nr_slots, + sizeof(struct b43legacy_txhdr_fw3), + GFP_KERNEL); + if (!ring->txhdr_cache) + goto err_kfree_meta; + + /* test for ability to dma to txhdr_cache */ + dma_test = dma_map_single(dev->dev->dev, + ring->txhdr_cache, + sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); + + if (dma_mapping_error(dma_test)) { + /* ugh realloc */ + kfree(ring->txhdr_cache); + ring->txhdr_cache = kcalloc(nr_slots, + sizeof(struct b43legacy_txhdr_fw3), + GFP_KERNEL | GFP_DMA); + if (!ring->txhdr_cache) + goto err_kfree_meta; + + dma_test = dma_map_single(dev->dev->dev, + ring->txhdr_cache, + sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); + + if (dma_mapping_error(dma_test)) + goto err_kfree_txhdr_cache; + } + + dma_unmap_single(dev->dev->dev, + dma_test, sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); + } + + ring->dev = dev; + ring->nr_slots = nr_slots; + ring->mmio_base = b43legacy_dmacontroller_base(dma64, + controller_index); + ring->index = controller_index; + ring->dma64 = !!dma64; + if (dma64) + ring->ops = &dma64_ops; + else + ring->ops = &dma32_ops; + if (for_tx) { + ring->tx = 1; + ring->current_slot = -1; + } else { + if (ring->index == 0) { + ring->rx_buffersize = B43legacy_DMA0_RX_BUFFERSIZE; + ring->frameoffset = B43legacy_DMA0_RX_FRAMEOFFSET; + } else if (ring->index == 3) { + ring->rx_buffersize = B43legacy_DMA3_RX_BUFFERSIZE; + ring->frameoffset = B43legacy_DMA3_RX_FRAMEOFFSET; + } else + B43legacy_WARN_ON(1); + } + spin_lock_init(&ring->lock); +#ifdef CONFIG_B43LEGACY_DEBUG + ring->last_injected_overflow = jiffies; +#endif + + err = alloc_ringmemory(ring); + if (err) + goto err_kfree_txhdr_cache; + err = dmacontroller_setup(ring); + if (err) + goto err_free_ringmemory; + +out: + return ring; + +err_free_ringmemory: + free_ringmemory(ring); +err_kfree_txhdr_cache: + kfree(ring->txhdr_cache); +err_kfree_meta: + kfree(ring->meta); +err_kfree_ring: + kfree(ring); + ring = NULL; + goto out; +} + +/* Main cleanup function. */ +static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring) +{ + if (!ring) + return; + + b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:" + " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base, + (ring->tx) ? "TX" : "RX", + ring->max_used_slots, ring->nr_slots); + /* Device IRQs are disabled prior entering this function, + * so no need to take care of concurrency with rx handler stuff. + */ + dmacontroller_cleanup(ring); + free_all_descbuffers(ring); + free_ringmemory(ring); + + kfree(ring->txhdr_cache); + kfree(ring->meta); + kfree(ring); +} + +void b43legacy_dma_free(struct b43legacy_wldev *dev) +{ + struct b43legacy_dma *dma; + + if (b43legacy_using_pio(dev)) + return; + dma = &dev->dma; + + b43legacy_destroy_dmaring(dma->rx_ring3); + dma->rx_ring3 = NULL; + b43legacy_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + + b43legacy_destroy_dmaring(dma->tx_ring5); + dma->tx_ring5 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring4); + dma->tx_ring4 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; +} + +int b43legacy_dma_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_dma *dma = &dev->dma; + struct b43legacy_dmaring *ring; + int err; + u64 dmamask; + int dma64 = 0; + + dmamask = supported_dma_mask(dev); + if (dmamask == DMA_64BIT_MASK) + dma64 = 1; + + err = ssb_dma_set_mask(dev->dev, dmamask); + if (err) { +#ifdef BCM43XX_PIO + b43legacywarn(dev->wl, "DMA for this device not supported. " + "Falling back to PIO\n"); + dev->__using_pio = 1; + return -EAGAIN; +#else + b43legacyerr(dev->wl, "DMA for this device not supported and " + "no PIO support compiled in\n"); + return -EOPNOTSUPP; +#endif + } + + err = -ENOMEM; + /* setup TX DMA channels. */ + ring = b43legacy_setup_dmaring(dev, 0, 1, dma64); + if (!ring) + goto out; + dma->tx_ring0 = ring; + + ring = b43legacy_setup_dmaring(dev, 1, 1, dma64); + if (!ring) + goto err_destroy_tx0; + dma->tx_ring1 = ring; + + ring = b43legacy_setup_dmaring(dev, 2, 1, dma64); + if (!ring) + goto err_destroy_tx1; + dma->tx_ring2 = ring; + + ring = b43legacy_setup_dmaring(dev, 3, 1, dma64); + if (!ring) + goto err_destroy_tx2; + dma->tx_ring3 = ring; + + ring = b43legacy_setup_dmaring(dev, 4, 1, dma64); + if (!ring) + goto err_destroy_tx3; + dma->tx_ring4 = ring; + + ring = b43legacy_setup_dmaring(dev, 5, 1, dma64); + if (!ring) + goto err_destroy_tx4; + dma->tx_ring5 = ring; + + /* setup RX DMA channels. */ + ring = b43legacy_setup_dmaring(dev, 0, 0, dma64); + if (!ring) + goto err_destroy_tx5; + dma->rx_ring0 = ring; + + if (dev->dev->id.revision < 5) { + ring = b43legacy_setup_dmaring(dev, 3, 0, dma64); + if (!ring) + goto err_destroy_rx0; + dma->rx_ring3 = ring; + } + + b43legacydbg(dev->wl, "%d-bit DMA initialized\n", + (dmamask == DMA_64BIT_MASK) ? 64 : + (dmamask == DMA_32BIT_MASK) ? 32 : 30); + err = 0; +out: + return err; + +err_destroy_rx0: + b43legacy_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; +err_destroy_tx5: + b43legacy_destroy_dmaring(dma->tx_ring5); + dma->tx_ring5 = NULL; +err_destroy_tx4: + b43legacy_destroy_dmaring(dma->tx_ring4); + dma->tx_ring4 = NULL; +err_destroy_tx3: + b43legacy_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; +err_destroy_tx2: + b43legacy_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; +err_destroy_tx1: + b43legacy_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; +err_destroy_tx0: + b43legacy_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; + goto out; +} + +/* Generate a cookie for the TX header. */ +static u16 generate_cookie(struct b43legacy_dmaring *ring, + int slot) +{ + u16 cookie = 0x1000; + + /* Use the upper 4 bits of the cookie as + * DMA controller ID and store the slot number + * in the lower 12 bits. + * Note that the cookie must never be 0, as this + * is a special value used in RX path. + */ + switch (ring->index) { + case 0: + cookie = 0xA000; + break; + case 1: + cookie = 0xB000; + break; + case 2: + cookie = 0xC000; + break; + case 3: + cookie = 0xD000; + break; + case 4: + cookie = 0xE000; + break; + case 5: + cookie = 0xF000; + break; + } + B43legacy_WARN_ON(!(((u16)slot & 0xF000) == 0x0000)); + cookie |= (u16)slot; + + return cookie; +} + +/* Inspect a cookie and find out to which controller/slot it belongs. */ +static +struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev, + u16 cookie, int *slot) +{ + struct b43legacy_dma *dma = &dev->dma; + struct b43legacy_dmaring *ring = NULL; + + switch (cookie & 0xF000) { + case 0xA000: + ring = dma->tx_ring0; + break; + case 0xB000: + ring = dma->tx_ring1; + break; + case 0xC000: + ring = dma->tx_ring2; + break; + case 0xD000: + ring = dma->tx_ring3; + break; + case 0xE000: + ring = dma->tx_ring4; + break; + case 0xF000: + ring = dma->tx_ring5; + break; + default: + B43legacy_WARN_ON(1); + } + *slot = (cookie & 0x0FFF); + B43legacy_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots)); + + return ring; +} + +static int dma_tx_fragment(struct b43legacy_dmaring *ring, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + const struct b43legacy_dma_ops *ops = ring->ops; + u8 *header; + int slot; + int err; + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + struct b43legacy_dmadesc_meta *meta_hdr; + struct sk_buff *bounce_skb; + +#define SLOTS_PER_PACKET 2 + B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); + + /* Get a slot for the header. */ + slot = request_slot(ring); + desc = ops->idx2desc(ring, slot, &meta_hdr); + memset(meta_hdr, 0, sizeof(*meta_hdr)); + + header = &(ring->txhdr_cache[slot * sizeof( + struct b43legacy_txhdr_fw3)]); + b43legacy_generate_txhdr(ring->dev, header, + skb->data, skb->len, ctl, + generate_cookie(ring, slot)); + + meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, + sizeof(struct b43legacy_txhdr_fw3), 1); + if (dma_mapping_error(meta_hdr->dmaaddr)) + return -EIO; + ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, + sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0); + + /* Get a slot for the payload. */ + slot = request_slot(ring); + desc = ops->idx2desc(ring, slot, &meta); + memset(meta, 0, sizeof(*meta)); + + memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); + meta->skb = skb; + meta->is_last_fragment = 1; + + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + /* create a bounce buffer in zone_dma on mapping failure. */ + if (dma_mapping_error(meta->dmaaddr)) { + bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); + if (!bounce_skb) { + err = -ENOMEM; + goto out_unmap_hdr; + } + + memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + dev_kfree_skb_any(skb); + skb = bounce_skb; + meta->skb = skb; + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (dma_mapping_error(meta->dmaaddr)) { + err = -EIO; + goto out_free_bounce; + } + } + + ops->fill_descriptor(ring, desc, meta->dmaaddr, + skb->len, 0, 1, 1); + + wmb(); /* previous stuff MUST be done */ + /* Now transfer the whole frame. */ + ops->poke_tx(ring, next_slot(ring, slot)); + return 0; + +out_free_bounce: + dev_kfree_skb_any(skb); +out_unmap_hdr: + unmap_descbuffer(ring, meta_hdr->dmaaddr, + sizeof(struct b43legacy_txhdr_fw3), 1); + return err; +} + +static inline +int should_inject_overflow(struct b43legacy_dmaring *ring) +{ +#ifdef CONFIG_B43LEGACY_DEBUG + if (unlikely(b43legacy_debug(ring->dev, + B43legacy_DBG_DMAOVERFLOW))) { + /* Check if we should inject another ringbuffer overflow + * to test handling of this situation in the stack. */ + unsigned long next_overflow; + + next_overflow = ring->last_injected_overflow + HZ; + if (time_after(jiffies, next_overflow)) { + ring->last_injected_overflow = jiffies; + b43legacydbg(ring->dev->wl, + "Injecting TX ring overflow on " + "DMA controller %d\n", ring->index); + return 1; + } + } +#endif /* CONFIG_B43LEGACY_DEBUG */ + return 0; +} + +int b43legacy_dma_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct b43legacy_dmaring *ring; + int err = 0; + unsigned long flags; + + ring = priority_to_txring(dev, ctl->queue); + 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"); + 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, ctl); + if (unlikely(err)) { + b43legacyerr(dev->wl, "DMA tx mapping failure\n"); + goto out_unlock; + } + ring->nr_tx_packets++; + if ((free_slots(ring) < SLOTS_PER_PACKET) || + should_inject_overflow(ring)) { + /* This TX ring is full. */ + ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); + ring->stopped = 1; + if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) + b43legacydbg(dev->wl, "Stopped TX ring %d\n", + ring->index); + } +out_unlock: + spin_unlock_irqrestore(&ring->lock, flags); + + return err; +} + +void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ + const struct b43legacy_dma_ops *ops; + struct b43legacy_dmaring *ring; + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + int slot; + + ring = parse_cookie(dev, status->cookie, &slot); + if (unlikely(!ring)) + return; + B43legacy_WARN_ON(!irqs_disabled()); + spin_lock(&ring->lock); + + B43legacy_WARN_ON(!ring->tx); + ops = ring->ops; + while (1) { + B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + desc = ops->idx2desc(ring, slot, &meta); + + if (meta->skb) + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + else + unmap_descbuffer(ring, meta->dmaaddr, + sizeof(struct b43legacy_txhdr_fw3), + 1); + + if (meta->is_last_fragment) { + B43legacy_WARN_ON(!meta->skb); + /* Call back to inform the ieee80211 subsystem about the + * status of the transmission. + * Some fields of txstat are already filled in dma_tx(). + */ + if (status->acked) { + meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; + } else { + if (!(meta->txstat.control.flags + & IEEE80211_TXCTL_NO_ACK)) + meta->txstat.excessive_retries = 1; + } + if (status->frame_count == 0) { + /* The frame was not transmitted at all. */ + meta->txstat.retry_count = 0; + } else + meta->txstat.retry_count = status->frame_count + - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, + &(meta->txstat)); + /* skb is freed by ieee80211_tx_status_irqsafe() */ + meta->skb = NULL; + } else { + /* No need to call free_descriptor_buffer here, as + * this is only the txhdr, which is not allocated. + */ + B43legacy_WARN_ON(meta->skb != NULL); + } + + /* Everything unmapped and free'd. So it's not used anymore. */ + ring->used_slots--; + + if (meta->is_last_fragment) + break; + slot = next_slot(ring, slot); + } + dev->stats.last_tx = jiffies; + if (ring->stopped) { + B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); + ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); + ring->stopped = 0; + if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) + b43legacydbg(dev->wl, "Woke up TX ring %d\n", + ring->index); + } + + spin_unlock(&ring->lock); +} + +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + const int nr_queues = dev->wl->hw->queues; + struct b43legacy_dmaring *ring; + struct ieee80211_tx_queue_stats_data *data; + unsigned long flags; + int i; + + for (i = 0; i < nr_queues; i++) { + data = &(stats->data[i]); + ring = priority_to_txring(dev, i); + + spin_lock_irqsave(&ring->lock, flags); + data->len = ring->used_slots / SLOTS_PER_PACKET; + data->limit = ring->nr_slots / SLOTS_PER_PACKET; + data->count = ring->nr_tx_packets; + spin_unlock_irqrestore(&ring->lock, flags); + } +} + +static void dma_rx(struct b43legacy_dmaring *ring, + int *slot) +{ + const struct b43legacy_dma_ops *ops = ring->ops; + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + struct b43legacy_rxhdr_fw3 *rxhdr; + struct sk_buff *skb; + u16 len; + int err; + dma_addr_t dmaaddr; + + desc = ops->idx2desc(ring, *slot, &meta); + + sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); + skb = meta->skb; + + if (ring->index == 3) { + /* We received an xmit status. */ + struct b43legacy_hwtxstatus *hw = + (struct b43legacy_hwtxstatus *)skb->data; + int i = 0; + + while (hw->cookie == 0) { + if (i > 100) + break; + i++; + udelay(2); + barrier(); + } + b43legacy_handle_hwtxstatus(ring->dev, hw); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + + return; + } + rxhdr = (struct b43legacy_rxhdr_fw3 *)skb->data; + len = le16_to_cpu(rxhdr->frame_len); + if (len == 0) { + int i = 0; + + do { + udelay(2); + barrier(); + len = le16_to_cpu(rxhdr->frame_len); + } while (len == 0 && i++ < 5); + if (unlikely(len == 0)) { + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + goto drop; + } + } + if (unlikely(len > ring->rx_buffersize)) { + /* The data did not fit into one descriptor buffer + * and is split over multiple buffers. + * This should never happen, as we try to allocate buffers + * big enough. So simply ignore this packet. + */ + int cnt = 0; + s32 tmp = len; + + while (1) { + desc = ops->idx2desc(ring, *slot, &meta); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + *slot = next_slot(ring, *slot); + cnt++; + tmp -= ring->rx_buffersize; + if (tmp <= 0) + break; + } + b43legacyerr(ring->dev->wl, "DMA RX buffer too small " + "(len: %u, buffer: %u, nr-dropped: %d)\n", + len, ring->rx_buffersize, cnt); + goto drop; + } + + dmaaddr = meta->dmaaddr; + err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); + if (unlikely(err)) { + b43legacydbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer()" + " failed\n"); + sync_descbuffer_for_device(ring, dmaaddr, + ring->rx_buffersize); + goto drop; + } + + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + skb_put(skb, len + ring->frameoffset); + skb_pull(skb, ring->frameoffset); + + b43legacy_rx(ring->dev, skb, rxhdr); +drop: + return; +} + +void b43legacy_dma_rx(struct b43legacy_dmaring *ring) +{ + const struct b43legacy_dma_ops *ops = ring->ops; + int slot; + int current_slot; + int used_slots = 0; + + B43legacy_WARN_ON(ring->tx); + current_slot = ops->get_current_rxslot(ring); + B43legacy_WARN_ON(!(current_slot >= 0 && current_slot < + ring->nr_slots)); + + slot = ring->current_slot; + for (; slot != current_slot; slot = next_slot(ring, slot)) { + dma_rx(ring, &slot); + update_max_used_slots(ring, ++used_slots); + } + ops->set_current_rxslot(ring, slot); + ring->current_slot = slot; +} + +static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring) +{ + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + B43legacy_WARN_ON(!ring->tx); + ring->ops->tx_suspend(ring); + spin_unlock_irqrestore(&ring->lock, flags); +} + +static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring) +{ + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + B43legacy_WARN_ON(!ring->tx); + ring->ops->tx_resume(ring); + spin_unlock_irqrestore(&ring->lock, flags); +} + +void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev) +{ + b43legacy_power_saving_ctl_bits(dev, -1, 1); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring0); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring1); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring2); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring3); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring4); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring5); +} + +void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev) +{ + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring5); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring4); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring3); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring2); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring1); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring0); + b43legacy_power_saving_ctl_bits(dev, -1, -1); +} diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h new file mode 100644 index 000000000000..26f6ab08de75 --- /dev/null +++ b/drivers/net/wireless/b43legacy/dma.h @@ -0,0 +1,367 @@ +#ifndef B43legacy_DMA_H_ +#define B43legacy_DMA_H_ + +#include +#include +#include +#include +#include + +#include "b43legacy.h" + + +/* DMA-Interrupt reasons. */ +#define B43legacy_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ + | (1 << 14) | (1 << 15)) +#define B43legacy_DMAIRQ_NONFATALMASK (1 << 13) +#define B43legacy_DMAIRQ_RX_DONE (1 << 16) + + +/*** 32-bit DMA Engine. ***/ + +/* 32-bit DMA controller registers. */ +#define B43legacy_DMA32_TXCTL 0x00 +#define B43legacy_DMA32_TXENABLE 0x00000001 +#define B43legacy_DMA32_TXSUSPEND 0x00000002 +#define B43legacy_DMA32_TXLOOPBACK 0x00000004 +#define B43legacy_DMA32_TXFLUSH 0x00000010 +#define B43legacy_DMA32_TXADDREXT_MASK 0x00030000 +#define B43legacy_DMA32_TXADDREXT_SHIFT 16 +#define B43legacy_DMA32_TXRING 0x04 +#define B43legacy_DMA32_TXINDEX 0x08 +#define B43legacy_DMA32_TXSTATUS 0x0C +#define B43legacy_DMA32_TXDPTR 0x00000FFF +#define B43legacy_DMA32_TXSTATE 0x0000F000 +#define B43legacy_DMA32_TXSTAT_DISABLED 0x00000000 +#define B43legacy_DMA32_TXSTAT_ACTIVE 0x00001000 +#define B43legacy_DMA32_TXSTAT_IDLEWAIT 0x00002000 +#define B43legacy_DMA32_TXSTAT_STOPPED 0x00003000 +#define B43legacy_DMA32_TXSTAT_SUSP 0x00004000 +#define B43legacy_DMA32_TXERROR 0x000F0000 +#define B43legacy_DMA32_TXERR_NOERR 0x00000000 +#define B43legacy_DMA32_TXERR_PROT 0x00010000 +#define B43legacy_DMA32_TXERR_UNDERRUN 0x00020000 +#define B43legacy_DMA32_TXERR_BUFREAD 0x00030000 +#define B43legacy_DMA32_TXERR_DESCREAD 0x00040000 +#define B43legacy_DMA32_TXACTIVE 0xFFF00000 +#define B43legacy_DMA32_RXCTL 0x10 +#define B43legacy_DMA32_RXENABLE 0x00000001 +#define B43legacy_DMA32_RXFROFF_MASK 0x000000FE +#define B43legacy_DMA32_RXFROFF_SHIFT 1 +#define B43legacy_DMA32_RXDIRECTFIFO 0x00000100 +#define B43legacy_DMA32_RXADDREXT_MASK 0x00030000 +#define B43legacy_DMA32_RXADDREXT_SHIFT 16 +#define B43legacy_DMA32_RXRING 0x14 +#define B43legacy_DMA32_RXINDEX 0x18 +#define B43legacy_DMA32_RXSTATUS 0x1C +#define B43legacy_DMA32_RXDPTR 0x00000FFF +#define B43legacy_DMA32_RXSTATE 0x0000F000 +#define B43legacy_DMA32_RXSTAT_DISABLED 0x00000000 +#define B43legacy_DMA32_RXSTAT_ACTIVE 0x00001000 +#define B43legacy_DMA32_RXSTAT_IDLEWAIT 0x00002000 +#define B43legacy_DMA32_RXSTAT_STOPPED 0x00003000 +#define B43legacy_DMA32_RXERROR 0x000F0000 +#define B43legacy_DMA32_RXERR_NOERR 0x00000000 +#define B43legacy_DMA32_RXERR_PROT 0x00010000 +#define B43legacy_DMA32_RXERR_OVERFLOW 0x00020000 +#define B43legacy_DMA32_RXERR_BUFWRITE 0x00030000 +#define B43legacy_DMA32_RXERR_DESCREAD 0x00040000 +#define B43legacy_DMA32_RXACTIVE 0xFFF00000 + +/* 32-bit DMA descriptor. */ +struct b43legacy_dmadesc32 { + __le32 control; + __le32 address; +} __attribute__((__packed__)); +#define B43legacy_DMA32_DCTL_BYTECNT 0x00001FFF +#define B43legacy_DMA32_DCTL_ADDREXT_MASK 0x00030000 +#define B43legacy_DMA32_DCTL_ADDREXT_SHIFT 16 +#define B43legacy_DMA32_DCTL_DTABLEEND 0x10000000 +#define B43legacy_DMA32_DCTL_IRQ 0x20000000 +#define B43legacy_DMA32_DCTL_FRAMEEND 0x40000000 +#define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000 + + + +/*** 64-bit DMA Engine. ***/ + +/* 64-bit DMA controller registers. */ +#define B43legacy_DMA64_TXCTL 0x00 +#define B43legacy_DMA64_TXENABLE 0x00000001 +#define B43legacy_DMA64_TXSUSPEND 0x00000002 +#define B43legacy_DMA64_TXLOOPBACK 0x00000004 +#define B43legacy_DMA64_TXFLUSH 0x00000010 +#define B43legacy_DMA64_TXADDREXT_MASK 0x00030000 +#define B43legacy_DMA64_TXADDREXT_SHIFT 16 +#define B43legacy_DMA64_TXINDEX 0x04 +#define B43legacy_DMA64_TXRINGLO 0x08 +#define B43legacy_DMA64_TXRINGHI 0x0C +#define B43legacy_DMA64_TXSTATUS 0x10 +#define B43legacy_DMA64_TXSTATDPTR 0x00001FFF +#define B43legacy_DMA64_TXSTAT 0xF0000000 +#define B43legacy_DMA64_TXSTAT_DISABLED 0x00000000 +#define B43legacy_DMA64_TXSTAT_ACTIVE 0x10000000 +#define B43legacy_DMA64_TXSTAT_IDLEWAIT 0x20000000 +#define B43legacy_DMA64_TXSTAT_STOPPED 0x30000000 +#define B43legacy_DMA64_TXSTAT_SUSP 0x40000000 +#define B43legacy_DMA64_TXERROR 0x14 +#define B43legacy_DMA64_TXERRDPTR 0x0001FFFF +#define B43legacy_DMA64_TXERR 0xF0000000 +#define B43legacy_DMA64_TXERR_NOERR 0x00000000 +#define B43legacy_DMA64_TXERR_PROT 0x10000000 +#define B43legacy_DMA64_TXERR_UNDERRUN 0x20000000 +#define B43legacy_DMA64_TXERR_TRANSFER 0x30000000 +#define B43legacy_DMA64_TXERR_DESCREAD 0x40000000 +#define B43legacy_DMA64_TXERR_CORE 0x50000000 +#define B43legacy_DMA64_RXCTL 0x20 +#define B43legacy_DMA64_RXENABLE 0x00000001 +#define B43legacy_DMA64_RXFROFF_MASK 0x000000FE +#define B43legacy_DMA64_RXFROFF_SHIFT 1 +#define B43legacy_DMA64_RXDIRECTFIFO 0x00000100 +#define B43legacy_DMA64_RXADDREXT_MASK 0x00030000 +#define B43legacy_DMA64_RXADDREXT_SHIFT 16 +#define B43legacy_DMA64_RXINDEX 0x24 +#define B43legacy_DMA64_RXRINGLO 0x28 +#define B43legacy_DMA64_RXRINGHI 0x2C +#define B43legacy_DMA64_RXSTATUS 0x30 +#define B43legacy_DMA64_RXSTATDPTR 0x00001FFF +#define B43legacy_DMA64_RXSTAT 0xF0000000 +#define B43legacy_DMA64_RXSTAT_DISABLED 0x00000000 +#define B43legacy_DMA64_RXSTAT_ACTIVE 0x10000000 +#define B43legacy_DMA64_RXSTAT_IDLEWAIT 0x20000000 +#define B43legacy_DMA64_RXSTAT_STOPPED 0x30000000 +#define B43legacy_DMA64_RXSTAT_SUSP 0x40000000 +#define B43legacy_DMA64_RXERROR 0x34 +#define B43legacy_DMA64_RXERRDPTR 0x0001FFFF +#define B43legacy_DMA64_RXERR 0xF0000000 +#define B43legacy_DMA64_RXERR_NOERR 0x00000000 +#define B43legacy_DMA64_RXERR_PROT 0x10000000 +#define B43legacy_DMA64_RXERR_UNDERRUN 0x20000000 +#define B43legacy_DMA64_RXERR_TRANSFER 0x30000000 +#define B43legacy_DMA64_RXERR_DESCREAD 0x40000000 +#define B43legacy_DMA64_RXERR_CORE 0x50000000 + +/* 64-bit DMA descriptor. */ +struct b43legacy_dmadesc64 { + __le32 control0; + __le32 control1; + __le32 address_low; + __le32 address_high; +} __attribute__((__packed__)); +#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000 +#define B43legacy_DMA64_DCTL0_IRQ 0x20000000 +#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000 +#define B43legacy_DMA64_DCTL0_FRAMESTART 0x80000000 +#define B43legacy_DMA64_DCTL1_BYTECNT 0x00001FFF +#define B43legacy_DMA64_DCTL1_ADDREXT_MASK 0x00030000 +#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT 16 + + + +struct b43legacy_dmadesc_generic { + union { + struct b43legacy_dmadesc32 dma32; + struct b43legacy_dmadesc64 dma64; + } __attribute__((__packed__)); +} __attribute__((__packed__)); + + +/* Misc DMA constants */ +#define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE +#define B43legacy_DMA0_RX_FRAMEOFFSET 30 +#define B43legacy_DMA3_RX_FRAMEOFFSET 0 + + +/* DMA engine tuning knobs */ +#define B43legacy_TXRING_SLOTS 128 +#define B43legacy_RXRING_SLOTS 64 +#define B43legacy_DMA0_RX_BUFFERSIZE (2304 + 100) +#define B43legacy_DMA3_RX_BUFFERSIZE 16 + + + +#ifdef CONFIG_B43LEGACY_DMA + + +struct sk_buff; +struct b43legacy_private; +struct b43legacy_txstatus; + + +struct b43legacy_dmadesc_meta { + /* The kernel DMA-able buffer. */ + struct sk_buff *skb; + /* DMA base bus-address of the descriptor buffer. */ + dma_addr_t dmaaddr; + /* ieee80211 TX status. Only used once per 802.11 frag. */ + bool is_last_fragment; + struct ieee80211_tx_status txstat; +}; + +struct b43legacy_dmaring; + +/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */ +struct b43legacy_dma_ops { + struct b43legacy_dmadesc_generic * (*idx2desc) + (struct b43legacy_dmaring *ring, + int slot, + struct b43legacy_dmadesc_meta + **meta); + void (*fill_descriptor)(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq); + void (*poke_tx)(struct b43legacy_dmaring *ring, int slot); + void (*tx_suspend)(struct b43legacy_dmaring *ring); + void (*tx_resume)(struct b43legacy_dmaring *ring); + int (*get_current_rxslot)(struct b43legacy_dmaring *ring); + void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot); +}; + +struct b43legacy_dmaring { + /* Lowlevel DMA ops. */ + const struct b43legacy_dma_ops *ops; + /* Kernel virtual base address of the ring memory. */ + void *descbase; + /* Meta data about all descriptors. */ + struct b43legacy_dmadesc_meta *meta; + /* Cache of TX headers for each slot. + * This is to avoid an allocation on each TX. + * This is NULL for an RX ring. + */ + u8 *txhdr_cache; + /* (Unadjusted) DMA base bus-address of the ring memory. */ + dma_addr_t dmabase; + /* Number of descriptor slots in the ring. */ + int nr_slots; + /* Number of used descriptor slots. */ + int used_slots; + /* Currently used slot in the ring. */ + int current_slot; + /* Total number of packets sent. Statistics only. */ + unsigned int nr_tx_packets; + /* Frameoffset in octets. */ + u32 frameoffset; + /* Descriptor buffer size. */ + u16 rx_buffersize; + /* The MMIO base register of the DMA controller. */ + u16 mmio_base; + /* DMA controller index number (0-5). */ + int index; + /* Boolean. Is this a TX ring? */ + bool tx; + /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */ + bool dma64; + /* Boolean. Is this ring stopped at ieee80211 level? */ + bool stopped; + /* Lock, only used for TX. */ + spinlock_t lock; + struct b43legacy_wldev *dev; +#ifdef CONFIG_B43LEGACY_DEBUG + /* Maximum number of used slots. */ + int max_used_slots; + /* Last time we injected a ring overflow. */ + unsigned long last_injected_overflow; +#endif /* CONFIG_B43LEGACY_DEBUG*/ +}; + + +static inline +u32 b43legacy_dma_read(struct b43legacy_dmaring *ring, + u16 offset) +{ + return b43legacy_read32(ring->dev, ring->mmio_base + offset); +} + +static inline +void b43legacy_dma_write(struct b43legacy_dmaring *ring, + u16 offset, u32 value) +{ + b43legacy_write32(ring->dev, ring->mmio_base + offset, value); +} + + +int b43legacy_dma_init(struct b43legacy_wldev *dev); +void b43legacy_dma_free(struct b43legacy_wldev *dev); + +int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, + u16 dmacontroller_mmio_base, + int dma64); +int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, + u16 dmacontroller_mmio_base, + int dma64); + +u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx); + +void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev); +void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev); + +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats); + +int b43legacy_dma_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl); +void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status); + +void b43legacy_dma_rx(struct b43legacy_dmaring *ring); + +#else /* CONFIG_B43LEGACY_DMA */ + + +static inline +int b43legacy_dma_init(struct b43legacy_wldev *dev) +{ + return 0; +} +static inline +void b43legacy_dma_free(struct b43legacy_wldev *dev) +{ +} +static inline +int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, + u16 dmacontroller_mmio_base, + int dma64) +{ + return 0; +} +static inline +int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, + u16 dmacontroller_mmio_base, + int dma64) +{ + return 0; +} +static inline +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline +int b43legacy_dma_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline +void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ +} +static inline +void b43legacy_dma_rx(struct b43legacy_dmaring *ring) +{ +} +static inline +void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev) +{ +} +static inline +void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev) +{ +} + +#endif /* CONFIG_B43LEGACY_DMA */ +#endif /* B43legacy_DMA_H_ */ diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c new file mode 100644 index 000000000000..247fc780ffdb --- /dev/null +++ b/drivers/net/wireless/b43legacy/ilt.c @@ -0,0 +1,336 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43legacy.h" +#include "ilt.h" +#include "phy.h" + + +/**** Initial Internal Lookup Tables ****/ + +const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE] = { + 0xFEB93FFD, 0xFEC63FFD, /* 0 */ + 0xFED23FFD, 0xFEDF3FFD, + 0xFEEC3FFE, 0xFEF83FFE, + 0xFF053FFE, 0xFF113FFE, + 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ + 0xFF373FFF, 0xFF443FFF, + 0xFF503FFF, 0xFF5D3FFF, + 0xFF693FFF, 0xFF763FFF, + 0xFF824000, 0xFF8F4000, /* 16 */ + 0xFF9B4000, 0xFFA84000, + 0xFFB54000, 0xFFC14000, + 0xFFCE4000, 0xFFDA4000, + 0xFFE74000, 0xFFF34000, /* 24 */ + 0x00004000, 0x000D4000, + 0x00194000, 0x00264000, + 0x00324000, 0x003F4000, + 0x004B4000, 0x00584000, /* 32 */ + 0x00654000, 0x00714000, + 0x007E4000, 0x008A3FFF, + 0x00973FFF, 0x00A33FFF, + 0x00B03FFF, 0x00BC3FFF, /* 40 */ + 0x00C93FFF, 0x00D63FFF, + 0x00E23FFE, 0x00EF3FFE, + 0x00FB3FFE, 0x01083FFE, + 0x01143FFE, 0x01213FFD, /* 48 */ + 0x012E3FFD, 0x013A3FFD, + 0x01473FFD, +}; + +const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE] = { + 0xDB93CB87, 0xD666CF64, /* 0 */ + 0xD1FDD358, 0xCDA6D826, + 0xCA38DD9F, 0xC729E2B4, + 0xC469E88E, 0xC26AEE2B, + 0xC0DEF46C, 0xC073FA62, /* 8 */ + 0xC01D00D5, 0xC0760743, + 0xC1560D1E, 0xC2E51369, + 0xC4ED18FF, 0xC7AC1ED7, + 0xCB2823B2, 0xCEFA28D9, /* 16 */ + 0xD2F62D3F, 0xD7BB3197, + 0xDCE53568, 0xE1FE3875, + 0xE7D13B35, 0xED663D35, + 0xF39B3EC4, 0xF98E3FA7, /* 24 */ + 0x00004000, 0x06723FA7, + 0x0C653EC4, 0x129A3D35, + 0x182F3B35, 0x1E023875, + 0x231B3568, 0x28453197, /* 32 */ + 0x2D0A2D3F, 0x310628D9, + 0x34D823B2, 0x38541ED7, + 0x3B1318FF, 0x3D1B1369, + 0x3EAA0D1E, 0x3F8A0743, /* 40 */ + 0x3FE300D5, 0x3F8DFA62, + 0x3F22F46C, 0x3D96EE2B, + 0x3B97E88E, 0x38D7E2B4, + 0x35C8DD9F, 0x325AD826, /* 48 */ + 0x2E03D358, 0x299ACF64, + 0x246DCB87, +}; + +const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE] = { + 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ + 0x0202, 0x0282, 0x0302, 0x0382, + 0x0402, 0x0482, 0x0502, 0x0582, + 0x05E2, 0x0662, 0x06E2, 0x0762, + 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ + 0x09C2, 0x0A22, 0x0AA2, 0x0B02, + 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, + 0x0D42, 0x0DA2, 0x0E02, 0x0E62, + 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ + 0x1062, 0x10C2, 0x1122, 0x1182, + 0x11E2, 0x1242, 0x12A2, 0x12E2, + 0x1342, 0x13A2, 0x1402, 0x1442, + 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ + 0x15E2, 0x1622, 0x1662, 0x16C1, + 0x1701, 0x1741, 0x1781, 0x17E1, + 0x1821, 0x1861, 0x18A1, 0x18E1, + 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ + 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, + 0x1B01, 0x1B41, 0x1B81, 0x1BA1, + 0x1BE1, 0x1C21, 0x1C41, 0x1C81, + 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ + 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, + 0x1E21, 0x1E61, 0x1E81, 0x1EA1, + 0x1EE1, 0x1F01, 0x1F21, 0x1F41, + 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ + 0x2001, 0x2041, 0x2061, 0x2081, + 0x20A1, 0x20C1, 0x20E1, 0x2101, + 0x2121, 0x2141, 0x2161, 0x2181, + 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ + 0x2221, 0x2241, 0x2261, 0x2281, + 0x22A1, 0x22C1, 0x22C1, 0x22E1, + 0x2301, 0x2321, 0x2341, 0x2361, + 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ + 0x23E1, 0x23E1, 0x2401, 0x2421, + 0x2441, 0x2441, 0x2461, 0x2481, + 0x2481, 0x24A1, 0x24C1, 0x24C1, + 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ + 0x2541, 0x2541, 0x2561, 0x2561, + 0x2581, 0x25A1, 0x25A1, 0x25C1, + 0x25C1, 0x25E1, 0x2601, 0x2601, + 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ + 0x2661, 0x2661, 0x2681, 0x2681, + 0x26A1, 0x26A1, 0x26C1, 0x26C1, + 0x26E1, 0x26E1, 0x2701, 0x2701, + 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ + 0x2760, 0x2760, 0x2780, 0x2780, + 0x2780, 0x27A0, 0x27A0, 0x27C0, + 0x27C0, 0x27E0, 0x27E0, 0x27E0, + 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ + 0x2820, 0x2840, 0x2840, 0x2840, + 0x2860, 0x2860, 0x2880, 0x2880, + 0x2880, 0x28A0, 0x28A0, 0x28A0, + 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ + 0x28E0, 0x28E0, 0x2900, 0x2900, + 0x2900, 0x2920, 0x2920, 0x2920, + 0x2940, 0x2940, 0x2940, 0x2960, + 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ + 0x2980, 0x2980, 0x29A0, 0x29A0, + 0x29A0, 0x29A0, 0x29C0, 0x29C0, + 0x29C0, 0x29E0, 0x29E0, 0x29E0, + 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ + 0x2A00, 0x2A20, 0x2A20, 0x2A20, + 0x2A20, 0x2A40, 0x2A40, 0x2A40, + 0x2A40, 0x2A60, 0x2A60, 0x2A60, +}; + +const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE] = { + 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ + 0x05A9, 0x0669, 0x0709, 0x0789, + 0x0829, 0x08A9, 0x0929, 0x0989, + 0x0A09, 0x0A69, 0x0AC9, 0x0B29, + 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ + 0x0D09, 0x0D69, 0x0DA9, 0x0E09, + 0x0E69, 0x0EA9, 0x0F09, 0x0F49, + 0x0FA9, 0x0FE9, 0x1029, 0x1089, + 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ + 0x11E9, 0x1229, 0x1289, 0x12C9, + 0x1309, 0x1349, 0x1389, 0x13C9, + 0x1409, 0x1449, 0x14A9, 0x14E9, + 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ + 0x1629, 0x1669, 0x16A9, 0x16E8, + 0x1728, 0x1768, 0x17A8, 0x17E8, + 0x1828, 0x1868, 0x18A8, 0x18E8, + 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ + 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, + 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, + 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, + 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ + 0x1E48, 0x1E88, 0x1EC8, 0x1F08, + 0x1F48, 0x1F88, 0x1FE8, 0x2028, + 0x2068, 0x20A8, 0x2108, 0x2148, + 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ + 0x22C8, 0x2308, 0x2348, 0x23A8, + 0x23E8, 0x2448, 0x24A8, 0x24E8, + 0x2548, 0x25A8, 0x2608, 0x2668, + 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ + 0x2847, 0x28C7, 0x2947, 0x29A7, + 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, + 0x2CA7, 0x2D67, 0x2E47, 0x2F67, + 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ + 0x3806, 0x38A6, 0x3946, 0x39E6, + 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, + 0x3C45, 0x3CA5, 0x3D05, 0x3D85, + 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ + 0x3F45, 0x3FA5, 0x4005, 0x4045, + 0x40A5, 0x40E5, 0x4145, 0x4185, + 0x41E5, 0x4225, 0x4265, 0x42C5, + 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ + 0x4424, 0x4464, 0x44C4, 0x4504, + 0x4544, 0x4584, 0x45C4, 0x4604, + 0x4644, 0x46A4, 0x46E4, 0x4724, + 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ + 0x4864, 0x48A4, 0x48E4, 0x4924, + 0x4964, 0x49A4, 0x49E4, 0x4A24, + 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, + 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ + 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, + 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, + 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, + 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ + 0x5083, 0x50C3, 0x5103, 0x5143, + 0x5183, 0x51E2, 0x5222, 0x5262, + 0x52A2, 0x52E2, 0x5342, 0x5382, + 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ + 0x5502, 0x5542, 0x55A2, 0x55E2, + 0x5642, 0x5682, 0x56E2, 0x5722, + 0x5782, 0x57E1, 0x5841, 0x58A1, + 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ + 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, + 0x5C61, 0x5D01, 0x5D80, 0x5E20, + 0x5EE0, 0x5FA0, 0x6080, 0x61C0, +}; + +const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE] = { + 0x0001, 0x0001, 0x0001, 0xFFFE, + 0xFFFE, 0x3FFF, 0x1000, 0x0393, +}; + +const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE] = { + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, +}; + +const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE] = { + 0x013C, 0x01F5, 0x031A, 0x0631, + 0x0001, 0x0001, 0x0001, 0x0001, +}; + +const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE] = { + 0x5484, 0x3C40, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE] = { + 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ + 0x2F2D, 0x2A2A, 0x2527, 0x1F21, + 0x1A1D, 0x1719, 0x1616, 0x1414, + 0x1414, 0x1400, 0x1414, 0x1614, + 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ + 0x2A27, 0x2F2A, 0x332D, 0x3B35, + 0x5140, 0x6C62, 0x0077, +}; + +const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE] = { + 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, + 0x969B, 0x9195, 0x8F8F, 0x8A8A, + 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, + 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ + 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, + 0xCBC0, 0xD8D4, 0x00DD, +}; + +const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE] = { + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0x00A4, +}; + +const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE] = { + 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ + 0x0067, 0x0063, 0x005E, 0x0059, + 0x0054, 0x0050, 0x004B, 0x0046, + 0x0042, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x0000, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x0042, 0x0046, 0x004B, 0x0050, + 0x0054, 0x0059, 0x005E, 0x0063, + 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ + 0x007A, +}; + +const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE] = { + 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ + 0x00D6, 0x00D4, 0x00D2, 0x00CF, + 0x00CD, 0x00CA, 0x00C7, 0x00C4, + 0x00C1, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x0000, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00C1, 0x00C4, 0x00C7, 0x00CA, + 0x00CD, 0x00CF, 0x00D2, 0x00D4, + 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ + 0x00DE, +}; + +/**** Helper functions to access the device Internal Lookup Tables ****/ + +void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val) +{ + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset); + mmiowb(); + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1, val); +} + +void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset, u32 val) +{ + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset); + mmiowb(); + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA2, + (val & 0xFFFF0000) >> 16); + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1, + val & 0x0000FFFF); +} + +u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset) +{ + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset); + return b43legacy_phy_read(dev, B43legacy_PHY_ILT_G_DATA1); +} diff --git a/drivers/net/wireless/b43legacy/ilt.h b/drivers/net/wireless/b43legacy/ilt.h new file mode 100644 index 000000000000..48bcf37eccb8 --- /dev/null +++ b/drivers/net/wireless/b43legacy/ilt.h @@ -0,0 +1,34 @@ +#ifndef B43legacy_ILT_H_ +#define B43legacy_ILT_H_ + +#define B43legacy_ILT_ROTOR_SIZE 53 +extern const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE]; +#define B43legacy_ILT_RETARD_SIZE 53 +extern const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE]; +#define B43legacy_ILT_FINEFREQA_SIZE 256 +extern const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE]; +#define B43legacy_ILT_FINEFREQG_SIZE 256 +extern const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE]; +#define B43legacy_ILT_NOISEA2_SIZE 8 +extern const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE]; +#define B43legacy_ILT_NOISEA3_SIZE 8 +extern const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE]; +#define B43legacy_ILT_NOISEG1_SIZE 8 +extern const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE]; +#define B43legacy_ILT_NOISEG2_SIZE 8 +extern const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE]; +#define B43legacy_ILT_NOISESCALEG_SIZE 27 +extern const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE]; +extern const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE]; +extern const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE]; +#define B43legacy_ILT_SIGMASQR_SIZE 53 +extern const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE]; +extern const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE]; + + +void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val); +void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset, + u32 val); +u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset); + +#endif /* B43legacy_ILT_H_ */ diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c new file mode 100644 index 000000000000..498912ddeddb --- /dev/null +++ b/drivers/net/wireless/b43legacy/leds.c @@ -0,0 +1,302 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + Copyright (c) 2007 Larry Finger + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "leds.h" +#include "b43legacy.h" +#include "main.h" + +static void b43legacy_led_changestate(struct b43legacy_led *led) +{ + struct b43legacy_wldev *dev = led->dev; + const int index = led->index; + u16 ledctl; + + B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); + B43legacy_WARN_ON(!led->blink_interval); + ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + ledctl ^= (1 << index); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); +} + +static void b43legacy_led_blink(unsigned long d) +{ + struct b43legacy_led *led = (struct b43legacy_led *)d; + struct b43legacy_wldev *dev = led->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + if (led->blink_interval) { + b43legacy_led_changestate(led); + mod_timer(&led->blink_timer, jiffies + led->blink_interval); + } + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} + +static void b43legacy_led_blink_start(struct b43legacy_led *led, + unsigned long interval) +{ + if (led->blink_interval) + return; + led->blink_interval = interval; + b43legacy_led_changestate(led); + led->blink_timer.expires = jiffies + interval; + add_timer(&led->blink_timer); +} + +static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync) +{ + struct b43legacy_wldev *dev = led->dev; + const int index = led->index; + u16 ledctl; + + if (!led->blink_interval) + return; + if (unlikely(sync)) + del_timer_sync(&led->blink_timer); + else + del_timer(&led->blink_timer); + led->blink_interval = 0; + + /* Make sure the LED is turned off. */ + B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); + ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + if (led->activelow) + ledctl |= (1 << index); + else + ledctl &= ~(1 << index); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); +} + +static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev, + struct b43legacy_led *led, + int led_index) +{ + struct ssb_bus *bus = dev->dev->bus; + + /* This function is called, if the behaviour (and activelow) + * information for a LED is missing in the SPROM. + * We hardcode the behaviour values for various devices here. + * Note that the B43legacy_LED_TEST_XXX behaviour values can + * be used to figure out which led is mapped to which index. + */ + + switch (led_index) { + case 0: + led->behaviour = B43legacy_LED_ACTIVITY; + led->activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = B43legacy_LED_RADIO_ALL; + break; + case 1: + led->behaviour = B43legacy_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + led->behaviour = B43legacy_LED_ASSOC; + break; + case 2: + led->behaviour = B43legacy_LED_RADIO_A; + break; + case 3: + led->behaviour = B43legacy_LED_OFF; + break; + default: + B43legacy_BUG_ON(1); + } +} + +int b43legacy_leds_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_led *led; + u8 sprom[4]; + int i; + + sprom[0] = dev->dev->bus->sprom.r1.gpio0; + sprom[1] = dev->dev->bus->sprom.r1.gpio1; + sprom[2] = dev->dev->bus->sprom.r1.gpio2; + sprom[3] = dev->dev->bus->sprom.r1.gpio3; + + for (i = 0; i < B43legacy_NR_LEDS; i++) { + led = &(dev->leds[i]); + led->index = i; + led->dev = dev; + setup_timer(&led->blink_timer, + b43legacy_led_blink, + (unsigned long)led); + + if (sprom[i] == 0xFF) + b43legacy_led_init_hardcoded(dev, led, i); + else { + led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR; + led->activelow = !!(sprom[i] & + B43legacy_LED_ACTIVELOW); + } + } + + return 0; +} + +void b43legacy_leds_exit(struct b43legacy_wldev *dev) +{ + struct b43legacy_led *led; + int i; + + for (i = 0; i < B43legacy_NR_LEDS; i++) { + led = &(dev->leds[i]); + b43legacy_led_blink_stop(led, 1); + } + b43legacy_leds_switch_all(dev, 0); +} + +void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) +{ + struct b43legacy_led *led; + struct b43legacy_phy *phy = &dev->phy; + const int transferring = (jiffies - dev->stats.last_tx) + < B43legacy_LED_XFER_THRES; + int i; + int turn_on; + unsigned long interval = 0; + u16 ledctl; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + for (i = 0; i < B43legacy_NR_LEDS; i++) { + led = &(dev->leds[i]); + + turn_on = 0; + switch (led->behaviour) { + case B43legacy_LED_INACTIVE: + continue; + case B43legacy_LED_OFF: + break; + case B43legacy_LED_ON: + turn_on = 1; + break; + case B43legacy_LED_ACTIVITY: + turn_on = activity; + break; + case B43legacy_LED_RADIO_ALL: + turn_on = phy->radio_on && + b43legacy_is_hw_radio_enabled(dev); + break; + case B43legacy_LED_RADIO_A: + break; + case B43legacy_LED_RADIO_B: + turn_on = (phy->radio_on && + b43legacy_is_hw_radio_enabled(dev) && + (phy->type == B43legacy_PHYTYPE_B || + phy->type == B43legacy_PHYTYPE_G)); + break; + case B43legacy_LED_MODE_BG: + if (phy->type == B43legacy_PHYTYPE_G && + b43legacy_is_hw_radio_enabled(dev)) + turn_on = 1; + break; + case B43legacy_LED_TRANSFER: + if (transferring) + b43legacy_led_blink_start(led, + B43legacy_LEDBLINK_MEDIUM); + else + b43legacy_led_blink_stop(led, 0); + continue; + case B43legacy_LED_APTRANSFER: + if (b43legacy_is_mode(dev->wl, + IEEE80211_IF_TYPE_AP)) { + if (transferring) { + interval = B43legacy_LEDBLINK_FAST; + turn_on = 1; + } + } else { + turn_on = 1; + if (transferring) + interval = B43legacy_LEDBLINK_FAST; + else + turn_on = 0; + } + if (turn_on) + b43legacy_led_blink_start(led, interval); + else + b43legacy_led_blink_stop(led, 0); + continue; + case B43legacy_LED_WEIRD: + break; + case B43legacy_LED_ASSOC: + turn_on = 1; +#ifdef CONFIG_B43LEGACY_DEBUG + case B43legacy_LED_TEST_BLINKSLOW: + b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW); + continue; + case B43legacy_LED_TEST_BLINKMEDIUM: + b43legacy_led_blink_start(led, + B43legacy_LEDBLINK_MEDIUM); + continue; + case B43legacy_LED_TEST_BLINKFAST: + b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST); + continue; +#endif /* CONFIG_B43LEGACY_DEBUG */ + default: + B43legacy_BUG_ON(1); + }; + + if (led->activelow) + turn_on = !turn_on; + if (turn_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} + +void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on) +{ + struct b43legacy_led *led; + u16 ledctl; + int i; + int bit_on; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + for (i = 0; i < B43legacy_NR_LEDS; i++) { + led = &(dev->leds[i]); + if (led->behaviour == B43legacy_LED_INACTIVE) + continue; + if (on) + bit_on = led->activelow ? 0 : 1; + else + bit_on = led->activelow ? 1 : 0; + if (bit_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h new file mode 100644 index 000000000000..b989f503e684 --- /dev/null +++ b/drivers/net/wireless/b43legacy/leds.h @@ -0,0 +1,56 @@ +#ifndef B43legacy_LEDS_H_ +#define B43legacy_LEDS_H_ + +#include +#include + + +struct b43legacy_led { + u8 behaviour; + bool activelow; + /* Index in the "leds" array in b43legacy_wldev */ + u8 index; + struct b43legacy_wldev *dev; + struct timer_list blink_timer; + unsigned long blink_interval; +}; + +/* Delay between state changes when blinking in jiffies */ +#define B43legacy_LEDBLINK_SLOW (HZ / 1) +#define B43legacy_LEDBLINK_MEDIUM (HZ / 4) +#define B43legacy_LEDBLINK_FAST (HZ / 8) + +#define B43legacy_LED_XFER_THRES (HZ / 100) + +#define B43legacy_LED_BEHAVIOUR 0x7F +#define B43legacy_LED_ACTIVELOW 0x80 +enum { /* LED behaviour values */ + B43legacy_LED_OFF, + B43legacy_LED_ON, + B43legacy_LED_ACTIVITY, + B43legacy_LED_RADIO_ALL, + B43legacy_LED_RADIO_A, + B43legacy_LED_RADIO_B, + B43legacy_LED_MODE_BG, + B43legacy_LED_TRANSFER, + B43legacy_LED_APTRANSFER, + B43legacy_LED_WEIRD, + B43legacy_LED_ASSOC, + B43legacy_LED_INACTIVE, + + /* Behaviour values for testing. + * With these values it is easier to figure out + * the real behaviour of leds, in case the SPROM + * is missing information. + */ + B43legacy_LED_TEST_BLINKSLOW, + B43legacy_LED_TEST_BLINKMEDIUM, + B43legacy_LED_TEST_BLINKFAST, +}; + +int b43legacy_leds_init(struct b43legacy_wldev *dev); +void b43legacy_leds_exit(struct b43legacy_wldev *dev); +void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity); +void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on); + +#endif /* B43legacy_LEDS_H_ */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c new file mode 100644 index 000000000000..ac4831adb574 --- /dev/null +++ b/drivers/net/wireless/b43legacy/main.c @@ -0,0 +1,3805 @@ +/* + * + * Broadcom B43legacy wireless driver + * + * Copyright (c) 2005 Martin Langer + * Copyright (c) 2005 Stefano Brivio + * Copyright (c) 2005, 2006 Michael Buesch + * Copyright (c) 2005 Danny van Dyk + * Copyright (c) 2005 Andreas Jaggi + * Copyright (c) 2007 Larry Finger + * + * Some parts of the code in this file are derived from the ipw2200 + * driver Copyright(c) 2003 - 2004 Intel Corporation. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b43legacy.h" +#include "main.h" +#include "debugfs.h" +#include "phy.h" +#include "dma.h" +#include "pio.h" +#include "sysfs.h" +#include "xmit.h" +#include "radio.h" + + +MODULE_DESCRIPTION("Broadcom B43legacy wireless driver"); +MODULE_AUTHOR("Martin Langer"); +MODULE_AUTHOR("Stefano Brivio"); +MODULE_AUTHOR("Michael Buesch"); +MODULE_LICENSE("GPL"); + +#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) +static int modparam_pio; +module_param_named(pio, modparam_pio, int, 0444); +MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); +#elif defined(CONFIG_B43LEGACY_DMA) +# define modparam_pio 0 +#elif defined(CONFIG_B43LEGACY_PIO) +# define modparam_pio 1 +#endif + +static int modparam_bad_frames_preempt; +module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); +MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames" + " Preemption"); + +static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT; +module_param_named(short_retry, modparam_short_retry, int, 0444); +MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); + +static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT; +module_param_named(long_retry, modparam_long_retry, int, 0444); +MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); + +static int modparam_noleds; +module_param_named(noleds, modparam_noleds, int, 0444); +MODULE_PARM_DESC(noleds, "Turn off all LED activity"); + +static char modparam_fwpostfix[16]; +module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); +MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); + +static int modparam_mon_keep_bad; +module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); +MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); + +static int modparam_mon_keep_badplcp; +module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); +MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); + +/* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */ +static const struct ssb_device_id b43legacy_ssb_tbl[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl); + + +/* Channel and ratetables are shared for all devices. + * They can't be const, because ieee80211 puts some precalculated + * data in there. This data is the same for all devices, so we don't + * get concurrency issues */ +#define RATETAB_ENT(_rateid, _flags) \ + { \ + .rate = B43legacy_RATE_TO_100KBPS(_rateid), \ + .val = (_rateid), \ + .val2 = (_rateid), \ + .flags = (_flags), \ + } +static struct ieee80211_rate __b43legacy_ratetable[] = { + RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK), + RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), +}; +#define b43legacy_a_ratetable (__b43legacy_ratetable + 4) +#define b43legacy_a_ratetable_size 8 +#define b43legacy_b_ratetable (__b43legacy_ratetable + 0) +#define b43legacy_b_ratetable_size 4 +#define b43legacy_g_ratetable (__b43legacy_ratetable + 0) +#define b43legacy_g_ratetable_size 12 + +#define CHANTAB_ENT(_chanid, _freq) \ + { \ + .chan = (_chanid), \ + .freq = (_freq), \ + .val = (_chanid), \ + .flag = IEEE80211_CHAN_W_SCAN | \ + IEEE80211_CHAN_W_ACTIVE_SCAN | \ + IEEE80211_CHAN_W_IBSS, \ + .power_level = 0x0A, \ + .antenna_max = 0xFF, \ + } +static struct ieee80211_channel b43legacy_bg_chantable[] = { + CHANTAB_ENT(1, 2412), + CHANTAB_ENT(2, 2417), + CHANTAB_ENT(3, 2422), + CHANTAB_ENT(4, 2427), + CHANTAB_ENT(5, 2432), + CHANTAB_ENT(6, 2437), + CHANTAB_ENT(7, 2442), + CHANTAB_ENT(8, 2447), + CHANTAB_ENT(9, 2452), + CHANTAB_ENT(10, 2457), + CHANTAB_ENT(11, 2462), + CHANTAB_ENT(12, 2467), + CHANTAB_ENT(13, 2472), + CHANTAB_ENT(14, 2484), +}; +#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable) + +static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev); +static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev); +static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev); +static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev); + + +static int b43legacy_ratelimit(struct b43legacy_wl *wl) +{ + if (!wl || !wl->current_dev) + return 1; + if (b43legacy_status(wl->current_dev) < B43legacy_STAT_STARTED) + return 1; + /* We are up and running. + * Ratelimit the messages to avoid DoS over the net. */ + return net_ratelimit(); +} + +void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43legacy_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_INFO "b43legacy-%s: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43legacy_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_ERR "b43legacy-%s ERROR: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43legacy_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_WARNING "b43legacy-%s warning: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +#if B43legacy_DEBUG +void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "b43legacy-%s debug: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} +#endif /* DEBUG */ + +static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset, + u32 val) +{ + u32 status; + + B43legacy_WARN_ON(offset % 4 != 0); + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + if (status & B43legacy_SBF_XFER_REG_BYTESWAP) + val = swab32(val); + + b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset); + mmiowb(); + b43legacy_write32(dev, B43legacy_MMIO_RAM_DATA, val); +} + +static inline +void b43legacy_shm_control_word(struct b43legacy_wldev *dev, + u16 routing, u16 offset) +{ + u32 control; + + /* "offset" is the WORD offset. */ + + control = routing; + control <<= 16; + control |= offset; + b43legacy_write32(dev, B43legacy_MMIO_SHM_CONTROL, control); +} + +u32 b43legacy_shm_read32(struct b43legacy_wldev *dev, + u16 routing, u16 offset) +{ + u32 ret; + + if (routing == B43legacy_SHM_SHARED) { + B43legacy_WARN_ON((offset & 0x0001) != 0); + if (offset & 0x0003) { + /* Unaligned access */ + b43legacy_shm_control_word(dev, routing, offset >> 2); + ret = b43legacy_read16(dev, + B43legacy_MMIO_SHM_DATA_UNALIGNED); + ret <<= 16; + b43legacy_shm_control_word(dev, routing, + (offset >> 2) + 1); + ret |= b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA); + + return ret; + } + offset >>= 2; + } + b43legacy_shm_control_word(dev, routing, offset); + ret = b43legacy_read32(dev, B43legacy_MMIO_SHM_DATA); + + return ret; +} + +u16 b43legacy_shm_read16(struct b43legacy_wldev *dev, + u16 routing, u16 offset) +{ + u16 ret; + + if (routing == B43legacy_SHM_SHARED) { + B43legacy_WARN_ON((offset & 0x0001) != 0); + if (offset & 0x0003) { + /* Unaligned access */ + b43legacy_shm_control_word(dev, routing, offset >> 2); + ret = b43legacy_read16(dev, + B43legacy_MMIO_SHM_DATA_UNALIGNED); + + return ret; + } + offset >>= 2; + } + b43legacy_shm_control_word(dev, routing, offset); + ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA); + + return ret; +} + +void b43legacy_shm_write32(struct b43legacy_wldev *dev, + u16 routing, u16 offset, + u32 value) +{ + if (routing == B43legacy_SHM_SHARED) { + B43legacy_WARN_ON((offset & 0x0001) != 0); + if (offset & 0x0003) { + /* Unaligned access */ + b43legacy_shm_control_word(dev, routing, offset >> 2); + mmiowb(); + b43legacy_write16(dev, + B43legacy_MMIO_SHM_DATA_UNALIGNED, + (value >> 16) & 0xffff); + mmiowb(); + b43legacy_shm_control_word(dev, routing, + (offset >> 2) + 1); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, + value & 0xffff); + return; + } + offset >>= 2; + } + b43legacy_shm_control_word(dev, routing, offset); + mmiowb(); + b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, value); +} + +void b43legacy_shm_write16(struct b43legacy_wldev *dev, u16 routing, u16 offset, + u16 value) +{ + if (routing == B43legacy_SHM_SHARED) { + B43legacy_WARN_ON((offset & 0x0001) != 0); + if (offset & 0x0003) { + /* Unaligned access */ + b43legacy_shm_control_word(dev, routing, offset >> 2); + mmiowb(); + b43legacy_write16(dev, + B43legacy_MMIO_SHM_DATA_UNALIGNED, + value); + return; + } + offset >>= 2; + } + b43legacy_shm_control_word(dev, routing, offset); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, value); +} + +/* Read HostFlags */ +u32 b43legacy_hf_read(struct b43legacy_wldev *dev) +{ + u32 ret; + + ret = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_HOSTFHI); + ret <<= 16; + ret |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_HOSTFLO); + + return ret; +} + +/* Write HostFlags */ +void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value) +{ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_HOSTFLO, + (value & 0x0000FFFF)); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_HOSTFHI, + ((value & 0xFFFF0000) >> 16)); +} + +void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf) +{ + /* We need to be careful. As we read the TSF from multiple + * registers, we should take care of register overflows. + * In theory, the whole tsf read process should be atomic. + * We try to be atomic here, by restaring the read process, + * if any of the high registers changed (overflew). + */ + if (dev->dev->id.revision >= 3) { + u32 low; + u32 high; + u32 high2; + + do { + high = b43legacy_read32(dev, + B43legacy_MMIO_REV3PLUS_TSF_HIGH); + low = b43legacy_read32(dev, + B43legacy_MMIO_REV3PLUS_TSF_LOW); + high2 = b43legacy_read32(dev, + B43legacy_MMIO_REV3PLUS_TSF_HIGH); + } while (unlikely(high != high2)); + + *tsf = high; + *tsf <<= 32; + *tsf |= low; + } else { + u64 tmp; + u16 v0; + u16 v1; + u16 v2; + u16 v3; + u16 test1; + u16 test2; + u16 test3; + + do { + v3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3); + v2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2); + v1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1); + v0 = b43legacy_read16(dev, B43legacy_MMIO_TSF_0); + + test3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3); + test2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2); + test1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1); + } while (v3 != test3 || v2 != test2 || v1 != test1); + + *tsf = v3; + *tsf <<= 48; + tmp = v2; + tmp <<= 32; + *tsf |= tmp; + tmp = v1; + tmp <<= 16; + *tsf |= tmp; + *tsf |= v0; + } +} + +static void b43legacy_time_lock(struct b43legacy_wldev *dev) +{ + u32 status; + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + status |= B43legacy_SBF_TIME_UPDATE; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); + mmiowb(); +} + +static void b43legacy_time_unlock(struct b43legacy_wldev *dev) +{ + u32 status; + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + status &= ~B43legacy_SBF_TIME_UPDATE; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); +} + +static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf) +{ + /* Be careful with the in-progress timer. + * First zero out the low register, so we have a full + * register-overflow duration to complete the operation. + */ + if (dev->dev->id.revision >= 3) { + u32 lo = (tsf & 0x00000000FFFFFFFFULL); + u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; + + b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW, 0); + mmiowb(); + b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_HIGH, + hi); + mmiowb(); + b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW, + lo); + } else { + u16 v0 = (tsf & 0x000000000000FFFFULL); + u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; + u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; + u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; + + b43legacy_write16(dev, B43legacy_MMIO_TSF_0, 0); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_TSF_3, v3); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_TSF_2, v2); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_TSF_1, v1); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_TSF_0, v0); + } +} + +void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf) +{ + b43legacy_time_lock(dev); + b43legacy_tsf_write_locked(dev, tsf); + b43legacy_time_unlock(dev); +} + +static +void b43legacy_macfilter_set(struct b43legacy_wldev *dev, + u16 offset, const u8 *mac) +{ + static const u8 zero_addr[ETH_ALEN] = { 0 }; + u16 data; + + if (!mac) + mac = zero_addr; + + offset |= 0x0020; + b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_CONTROL, offset); + + data = mac[0]; + data |= mac[1] << 8; + b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data); + data = mac[2]; + data |= mac[3] << 8; + b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data); + data = mac[4]; + data |= mac[5] << 8; + b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data); +} + +static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev) +{ + static const u8 zero_addr[ETH_ALEN] = { 0 }; + const u8 *mac = dev->wl->mac_addr; + const u8 *bssid = dev->wl->bssid; + u8 mac_bssid[ETH_ALEN * 2]; + int i; + u32 tmp; + + if (!bssid) + bssid = zero_addr; + if (!mac) + mac = zero_addr; + + b43legacy_macfilter_set(dev, B43legacy_MACFILTER_BSSID, bssid); + + memcpy(mac_bssid, mac, ETH_ALEN); + memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); + + /* Write our MAC address and BSSID to template ram */ + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) { + tmp = (u32)(mac_bssid[i + 0]); + tmp |= (u32)(mac_bssid[i + 1]) << 8; + tmp |= (u32)(mac_bssid[i + 2]) << 16; + tmp |= (u32)(mac_bssid[i + 3]) << 24; + b43legacy_ram_write(dev, 0x20 + i, tmp); + b43legacy_ram_write(dev, 0x78 + i, tmp); + b43legacy_ram_write(dev, 0x478 + i, tmp); + } +} + +static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev, + const u8 *mac_addr) +{ + dev->wl->mac_addr = mac_addr; + b43legacy_write_mac_bssid_templates(dev); + b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, mac_addr); +} + +static void b43legacy_set_slot_time(struct b43legacy_wldev *dev, + u16 slot_time) +{ + /* slot_time is in usec. */ + if (dev->phy.type != B43legacy_PHYTYPE_G) + return; + b43legacy_write16(dev, 0x684, 510 + slot_time); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0010, + slot_time); +} + +static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev) +{ + b43legacy_set_slot_time(dev, 9); + dev->short_slot = 1; +} + +static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev) +{ + b43legacy_set_slot_time(dev, 20); + dev->short_slot = 0; +} + +/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev, + u32 mask) +{ + u32 old_mask; + + old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask | + mask); + + return old_mask; +} + +/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev, + u32 mask) +{ + u32 old_mask; + + old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask); + + return old_mask; +} + +/* 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 b43legacy_synchronize_irq(struct b43legacy_wldev *dev) +{ + synchronize_irq(dev->dev->irq); + tasklet_kill(&dev->isr_tasklet); +} + +/* DummyTransmission function, as documented on + * http://bcm-specs.sipsolutions.net/DummyTransmission + */ +void b43legacy_dummy_transmission(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + unsigned int i; + unsigned int max_loop; + u16 value; + u32 buffer[5] = { + 0x00000000, + 0x00D40000, + 0x00000000, + 0x01000000, + 0x00000000, + }; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + max_loop = 0xFA; + buffer[0] = 0x000B846E; + break; + default: + B43legacy_BUG_ON(1); + return; + } + + for (i = 0; i < 5; i++) + b43legacy_ram_write(dev, i * 4, buffer[i]); + + /* dummy read follows */ + b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + + b43legacy_write16(dev, 0x0568, 0x0000); + b43legacy_write16(dev, 0x07C0, 0x0000); + b43legacy_write16(dev, 0x050C, 0x0000); + b43legacy_write16(dev, 0x0508, 0x0000); + b43legacy_write16(dev, 0x050A, 0x0000); + b43legacy_write16(dev, 0x054C, 0x0000); + b43legacy_write16(dev, 0x056A, 0x0014); + b43legacy_write16(dev, 0x0568, 0x0826); + b43legacy_write16(dev, 0x0500, 0x0000); + b43legacy_write16(dev, 0x0502, 0x0030); + + if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) + b43legacy_radio_write16(dev, 0x0051, 0x0017); + for (i = 0x00; i < max_loop; i++) { + value = b43legacy_read16(dev, 0x050E); + if (value & 0x0080) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = b43legacy_read16(dev, 0x050E); + if (value & 0x0400) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = b43legacy_read16(dev, 0x0690); + if (!(value & 0x0100)) + break; + udelay(10); + } + if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) + b43legacy_radio_write16(dev, 0x0051, 0x0037); +} + +/* Turn the Analog ON/OFF */ +static void b43legacy_switch_analog(struct b43legacy_wldev *dev, int on) +{ + b43legacy_write16(dev, B43legacy_MMIO_PHY0, on ? 0 : 0xF4); +} + +void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags) +{ + u32 tmslow; + u32 macctl; + + flags |= B43legacy_TMSLOW_PHYCLKEN; + flags |= B43legacy_TMSLOW_PHYRESET; + ssb_device_enable(dev->dev, flags); + msleep(2); /* Wait for the PLL to turn on. */ + + /* Now take the PHY out of Reset again */ + tmslow = ssb_read32(dev->dev, SSB_TMSLOW); + tmslow |= SSB_TMSLOW_FGC; + tmslow &= ~B43legacy_TMSLOW_PHYRESET; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ + msleep(1); + tmslow &= ~SSB_TMSLOW_FGC; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ + msleep(1); + + /* Turn Analog ON */ + b43legacy_switch_analog(dev, 1); + + macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); + macctl &= ~B43legacy_MACCTL_GMODE; + if (flags & B43legacy_TMSLOW_GMODE) { + macctl |= B43legacy_MACCTL_GMODE; + dev->phy.gmode = 1; + } else + dev->phy.gmode = 0; + macctl |= B43legacy_MACCTL_IHR_ENABLED; + b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl); +} + +static void handle_irq_transmit_status(struct b43legacy_wldev *dev) +{ + u32 v0; + u32 v1; + u16 tmp; + struct b43legacy_txstatus stat; + + while (1) { + v0 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0); + if (!(v0 & 0x00000001)) + break; + v1 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1); + + stat.cookie = (v0 >> 16); + stat.seq = (v1 & 0x0000FFFF); + stat.phy_stat = ((v1 & 0x00FF0000) >> 16); + tmp = (v0 & 0x0000FFFF); + stat.frame_count = ((tmp & 0xF000) >> 12); + stat.rts_count = ((tmp & 0x0F00) >> 8); + stat.supp_reason = ((tmp & 0x001C) >> 2); + stat.pm_indicated = !!(tmp & 0x0080); + stat.intermediate = !!(tmp & 0x0040); + stat.for_ampdu = !!(tmp & 0x0020); + stat.acked = !!(tmp & 0x0002); + + b43legacy_handle_txstatus(dev, &stat); + } +} + +static void drain_txstatus_queue(struct b43legacy_wldev *dev) +{ + u32 dummy; + + if (dev->dev->id.revision < 5) + return; + /* Read all entries from the microcode TXstatus FIFO + * and throw them away. + */ + while (1) { + dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0); + if (!(dummy & 0x00000001)) + break; + dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1); + } +} + +static u32 b43legacy_jssi_read(struct b43legacy_wldev *dev) +{ + u32 val = 0; + + val = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x40A); + val <<= 16; + val |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x408); + + return val; +} + +static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi) +{ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x408, + (jssi & 0x0000FFFF)); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x40A, + (jssi & 0xFFFF0000) >> 16); +} + +static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev) +{ + b43legacy_jssi_write(dev, 0x7F7F7F7F); + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, + b43legacy_read32(dev, + B43legacy_MMIO_STATUS2_BITFIELD) + | (1 << 4)); + B43legacy_WARN_ON(dev->noisecalc.channel_at_start != + dev->phy.channel); +} + +static void b43legacy_calculate_link_quality(struct b43legacy_wldev *dev) +{ + /* Top half of Link Quality calculation. */ + + if (dev->noisecalc.calculation_running) + return; + dev->noisecalc.channel_at_start = dev->phy.channel; + dev->noisecalc.calculation_running = 1; + dev->noisecalc.nr_samples = 0; + + b43legacy_generate_noise_sample(dev); +} + +static void handle_irq_noise(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 tmp; + u8 noise[4]; + u8 i; + u8 j; + s32 average; + + /* Bottom half of Link Quality calculation. */ + + B43legacy_WARN_ON(!dev->noisecalc.calculation_running); + if (dev->noisecalc.channel_at_start != phy->channel) + goto drop_calculation; + *((__le32 *)noise) = cpu_to_le32(b43legacy_jssi_read(dev)); + if (noise[0] == 0x7F || noise[1] == 0x7F || + noise[2] == 0x7F || noise[3] == 0x7F) + goto generate_new; + + /* Get the noise samples. */ + B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8); + i = dev->noisecalc.nr_samples; + noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; + dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; + dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; + dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]]; + dev->noisecalc.nr_samples++; + if (dev->noisecalc.nr_samples == 8) { + /* Calculate the Link Quality by the noise samples. */ + average = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 4; j++) + average += dev->noisecalc.samples[i][j]; + } + average /= (8 * 4); + average *= 125; + average += 64; + average /= 128; + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + 0x40C); + tmp = (tmp / 128) & 0x1F; + if (tmp >= 8) + average += 2; + else + average -= 25; + if (tmp == 8) + average -= 72; + else + average -= 48; + + dev->stats.link_noise = average; +drop_calculation: + dev->noisecalc.calculation_running = 0; + return; + } +generate_new: + b43legacy_generate_noise_sample(dev); +} + +static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev) +{ + if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + /* TODO: PS TBTT */ + } else { + if (1/*FIXME: the last PSpoll frame was sent successfully */) + b43legacy_power_saving_ctl_bits(dev, -1, -1); + } + dev->reg124_set_0x4 = 0; + if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + dev->reg124_set_0x4 = 1; +} + +static void handle_irq_atim_end(struct b43legacy_wldev *dev) +{ + if (!dev->reg124_set_0x4) /*FIXME rename this variable*/ + return; + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, + b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD) + | 0x4); +} + +static void handle_irq_pmq(struct b43legacy_wldev *dev) +{ + u32 tmp; + + /* TODO: AP mode. */ + + while (1) { + tmp = b43legacy_read32(dev, B43legacy_MMIO_PS_STATUS); + if (!(tmp & 0x00000008)) + break; + } + /* 16bit write is odd, but correct. */ + b43legacy_write16(dev, B43legacy_MMIO_PS_STATUS, 0x0002); +} + +static void b43legacy_write_template_common(struct b43legacy_wldev *dev, + const u8 *data, u16 size, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + u32 i; + u32 tmp; + struct b43legacy_plcp_hdr4 plcp; + + plcp.data = 0; + b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43legacy_ram_write(dev, ram_offset, le32_to_cpu(plcp.data)); + ram_offset += sizeof(u32); + /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet. + * So leave the first two bytes of the next write blank. + */ + tmp = (u32)(data[0]) << 16; + tmp |= (u32)(data[1]) << 24; + b43legacy_ram_write(dev, ram_offset, tmp); + ram_offset += sizeof(u32); + for (i = 2; i < size; i += sizeof(u32)) { + tmp = (u32)(data[i + 0]); + if (i + 1 < size) + tmp |= (u32)(data[i + 1]) << 8; + if (i + 2 < size) + tmp |= (u32)(data[i + 2]) << 16; + if (i + 3 < size) + tmp |= (u32)(data[i + 3]) << 24; + b43legacy_ram_write(dev, ram_offset + i - 2, tmp); + } + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_size_offset, + size + sizeof(struct b43legacy_plcp_hdr6)); +} + +static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + int len; + const u8 *data; + + B43legacy_WARN_ON(!dev->cached_beacon); + len = min((size_t)dev->cached_beacon->len, + 0x200 - sizeof(struct b43legacy_plcp_hdr6)); + data = (const u8 *)(dev->cached_beacon->data); + b43legacy_write_template_common(dev, data, + len, ram_offset, + shm_size_offset, rate); +} + +static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, + u16 shm_offset, u16 size, + u8 rate) +{ + struct b43legacy_plcp_hdr4 plcp; + u32 tmp; + __le16 dur; + + plcp.data = 0; + b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + dur = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, + size, + B43legacy_RATE_TO_100KBPS(rate)); + /* Write PLCP in two parts and timing for packet transfer */ + tmp = le32_to_cpu(plcp.data); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset, + tmp & 0xFFFF); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 2, + tmp >> 16); + b43legacy_shm_write16(dev, B43legacy_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 u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, + u16 *dest_size, u8 rate) +{ + const u8 *src_data; + u8 *dest_data; + u16 src_size; + u16 elem_size; + u16 src_pos; + u16 dest_pos; + __le16 dur; + struct ieee80211_hdr *hdr; + + B43legacy_WARN_ON(!dev->cached_beacon); + src_size = dev->cached_beacon->len; + src_data = (const u8 *)dev->cached_beacon->data; + + if (unlikely(src_size < 0x24)) { + b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: " + "invalid beacon\n"); + return NULL; + } + + dest_data = kmalloc(src_size, GFP_ATOMIC); + if (unlikely(!dest_data)) + return NULL; + + /* 0x24 is offset of first variable-len Information-Element + * in beacon frame. + */ + memcpy(dest_data, src_data, 0x24); + src_pos = 0x24; + dest_pos = 0x24; + for (; src_pos < src_size - 2; src_pos += elem_size) { + elem_size = src_data[src_pos + 1] + 2; + if (src_data[src_pos] != 0x05) { /* TIM */ + 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->if_id, + *dest_size, + B43legacy_RATE_TO_100KBPS(rate)); + hdr->duration_id = dur; + + return dest_data; +} + +static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + u8 *probe_resp_data; + u16 size; + + B43legacy_WARN_ON(!dev->cached_beacon); + size = dev->cached_beacon->len; + probe_resp_data = b43legacy_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 + */ + b43legacy_write_probe_resp_plcp(dev, 0x31A, size, + B43legacy_CCK_RATE_1MB); + b43legacy_write_probe_resp_plcp(dev, 0x32C, size, + B43legacy_CCK_RATE_2MB); + b43legacy_write_probe_resp_plcp(dev, 0x33E, size, + B43legacy_CCK_RATE_5MB); + b43legacy_write_probe_resp_plcp(dev, 0x350, size, + B43legacy_CCK_RATE_11MB); + + size = min((size_t)size, + 0x200 - sizeof(struct b43legacy_plcp_hdr6)); + b43legacy_write_template_common(dev, probe_resp_data, + size, ram_offset, + shm_size_offset, rate); + kfree(probe_resp_data); +} + +static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev, + struct sk_buff *beacon) +{ + if (dev->cached_beacon) + kfree_skb(dev->cached_beacon); + dev->cached_beacon = beacon; + + return 0; +} + +static void b43legacy_update_templates(struct b43legacy_wldev *dev) +{ + u32 status; + + B43legacy_WARN_ON(!dev->cached_beacon); + + b43legacy_write_beacon_template(dev, 0x68, 0x18, + B43legacy_CCK_RATE_1MB); + b43legacy_write_beacon_template(dev, 0x468, 0x1A, + B43legacy_CCK_RATE_1MB); + b43legacy_write_probe_resp_template(dev, 0x268, 0x4A, + B43legacy_CCK_RATE_11MB); + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD); + status |= 0x03; + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status); +} + +static void b43legacy_refresh_templates(struct b43legacy_wldev *dev, + struct sk_buff *beacon) +{ + int err; + + err = b43legacy_refresh_cached_beacon(dev, beacon); + if (unlikely(err)) + return; + b43legacy_update_templates(dev); +} + +static void b43legacy_set_ssid(struct b43legacy_wldev *dev, + const u8 *ssid, u8 ssid_len) +{ + u32 tmp; + u16 i; + u16 len; + + len = min((u16)ssid_len, (u16)0x100); + for (i = 0; i < len; i += sizeof(u32)) { + tmp = (u32)(ssid[i + 0]); + if (i + 1 < len) + tmp |= (u32)(ssid[i + 1]) << 8; + if (i + 2 < len) + tmp |= (u32)(ssid[i + 2]) << 16; + if (i + 3 < len) + tmp |= (u32)(ssid[i + 3]) << 24; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + 0x380 + i, tmp); + } + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + 0x48, len); +} + +static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, + u16 beacon_int) +{ + b43legacy_time_lock(dev); + if (dev->dev->id.revision >= 3) + b43legacy_write32(dev, 0x188, (beacon_int << 16)); + else { + b43legacy_write16(dev, 0x606, (beacon_int >> 6)); + b43legacy_write16(dev, 0x610, beacon_int); + } + b43legacy_time_unlock(dev); +} + +static void handle_irq_beacon(struct b43legacy_wldev *dev) +{ + u32 status; + + if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + return; + + dev->irq_savedstate &= ~B43legacy_IRQ_BEACON; + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD); + + if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { + /* ACK beacon IRQ. */ + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, + B43legacy_IRQ_BEACON); + dev->irq_savedstate |= B43legacy_IRQ_BEACON; + if (dev->cached_beacon) + kfree_skb(dev->cached_beacon); + dev->cached_beacon = NULL; + return; + } + if (!(status & 0x1)) { + b43legacy_write_beacon_template(dev, 0x68, 0x18, + B43legacy_CCK_RATE_1MB); + status |= 0x1; + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, + status); + } + if (!(status & 0x2)) { + b43legacy_write_beacon_template(dev, 0x468, 0x1A, + B43legacy_CCK_RATE_1MB); + status |= 0x2; + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, + status); + } +} + +static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) +{ +} + +/* Interrupt handler bottom-half */ +static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) +{ + u32 reason; + u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; + u32 merged_dma_reason = 0; + int i; + int activity = 0; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + B43legacy_WARN_ON(b43legacy_status(dev) < + B43legacy_STAT_INITIALIZED); + + reason = dev->irq_reason; + for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { + dma_reason[i] = dev->dma_reason[i]; + merged_dma_reason |= dma_reason[i]; + } + + if (unlikely(reason & B43legacy_IRQ_MAC_TXERR)) + b43legacyerr(dev->wl, "MAC transmission error\n"); + + if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) + b43legacyerr(dev->wl, "PHY transmission error\n"); + + if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK | + B43legacy_DMAIRQ_NONFATALMASK))) { + if (merged_dma_reason & B43legacy_DMAIRQ_FATALMASK) { + b43legacyerr(dev->wl, "Fatal DMA error: " + "0x%08X, 0x%08X, 0x%08X, " + "0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3], + dma_reason[4], dma_reason[5]); + b43legacy_controller_restart(dev, "DMA error"); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + return; + } + if (merged_dma_reason & B43legacy_DMAIRQ_NONFATALMASK) + b43legacyerr(dev->wl, "DMA error: " + "0x%08X, 0x%08X, 0x%08X, " + "0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3], + dma_reason[4], dma_reason[5]); + } + + if (unlikely(reason & B43legacy_IRQ_UCODE_DEBUG)) + handle_irq_ucode_debug(dev); + if (reason & B43legacy_IRQ_TBTT_INDI) + handle_irq_tbtt_indication(dev); + if (reason & B43legacy_IRQ_ATIM_END) + handle_irq_atim_end(dev); + if (reason & B43legacy_IRQ_BEACON) + handle_irq_beacon(dev); + if (reason & B43legacy_IRQ_PMQ) + handle_irq_pmq(dev); + if (reason & B43legacy_IRQ_TXFIFO_FLUSH_OK) + ;/*TODO*/ + if (reason & B43legacy_IRQ_NOISESAMPLE_OK) + handle_irq_noise(dev); + + /* Check the DMA reason registers for received data. */ + if (dma_reason[0] & B43legacy_DMAIRQ_RX_DONE) { + if (b43legacy_using_pio(dev)) + b43legacy_pio_rx(dev->pio.queue0); + else + b43legacy_dma_rx(dev->dma.rx_ring0); + /* We intentionally don't set "activity" to 1, here. */ + } + B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE); + B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE); + if (dma_reason[3] & B43legacy_DMAIRQ_RX_DONE) { + if (b43legacy_using_pio(dev)) + b43legacy_pio_rx(dev->pio.queue3); + else + b43legacy_dma_rx(dev->dma.rx_ring3); + activity = 1; + } + B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE); + B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE); + + if (reason & B43legacy_IRQ_TX_OK) { + handle_irq_transmit_status(dev); + activity = 1; + /* TODO: In AP mode, this also causes sending of powersave + responses. */ + } + + if (!modparam_noleds) + b43legacy_leds_update(dev, activity); + b43legacy_interrupt_enable(dev, dev->irq_savedstate); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); +} + +static void pio_irq_workaround(struct b43legacy_wldev *dev, + u16 base, int queueidx) +{ + u16 rxctl; + + rxctl = b43legacy_read16(dev, base + B43legacy_PIO_RXCTL); + if (rxctl & B43legacy_PIO_RXCTL_DATAAVAILABLE) + dev->dma_reason[queueidx] |= B43legacy_DMAIRQ_RX_DONE; + else + dev->dma_reason[queueidx] &= ~B43legacy_DMAIRQ_RX_DONE; +} + +static void b43legacy_interrupt_ack(struct b43legacy_wldev *dev, u32 reason) +{ + if (b43legacy_using_pio(dev) && + (dev->dev->id.revision < 3) && + (!(reason & B43legacy_IRQ_PIO_WORKAROUND))) { + /* Apply a PIO specific workaround to the dma_reasons */ + pio_irq_workaround(dev, B43legacy_MMIO_PIO1_BASE, 0); + pio_irq_workaround(dev, B43legacy_MMIO_PIO2_BASE, 1); + pio_irq_workaround(dev, B43legacy_MMIO_PIO3_BASE, 2); + pio_irq_workaround(dev, B43legacy_MMIO_PIO4_BASE, 3); + } + + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, reason); + + b43legacy_write32(dev, B43legacy_MMIO_DMA0_REASON, + dev->dma_reason[0]); + b43legacy_write32(dev, B43legacy_MMIO_DMA1_REASON, + dev->dma_reason[1]); + b43legacy_write32(dev, B43legacy_MMIO_DMA2_REASON, + dev->dma_reason[2]); + b43legacy_write32(dev, B43legacy_MMIO_DMA3_REASON, + dev->dma_reason[3]); + b43legacy_write32(dev, B43legacy_MMIO_DMA4_REASON, + dev->dma_reason[4]); + b43legacy_write32(dev, B43legacy_MMIO_DMA5_REASON, + dev->dma_reason[5]); +} + +/* Interrupt handler top-half */ +static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id) +{ + irqreturn_t ret = IRQ_NONE; + struct b43legacy_wldev *dev = dev_id; + u32 reason; + + if (!dev) + return IRQ_NONE; + + spin_lock(&dev->wl->irq_lock); + + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) + goto out; + reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + if (reason == 0xffffffff) /* shared IRQ */ + goto out; + ret = IRQ_HANDLED; + reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + if (!reason) + goto out; + + dev->dma_reason[0] = b43legacy_read32(dev, + B43legacy_MMIO_DMA0_REASON) + & 0x0001DC00; + dev->dma_reason[1] = b43legacy_read32(dev, + B43legacy_MMIO_DMA1_REASON) + & 0x0000DC00; + dev->dma_reason[2] = b43legacy_read32(dev, + B43legacy_MMIO_DMA2_REASON) + & 0x0000DC00; + dev->dma_reason[3] = b43legacy_read32(dev, + B43legacy_MMIO_DMA3_REASON) + & 0x0001DC00; + dev->dma_reason[4] = b43legacy_read32(dev, + B43legacy_MMIO_DMA4_REASON) + & 0x0000DC00; + dev->dma_reason[5] = b43legacy_read32(dev, + B43legacy_MMIO_DMA5_REASON) + & 0x0000DC00; + + b43legacy_interrupt_ack(dev, reason); + /* disable all IRQs. They are enabled again in the bottom half. */ + dev->irq_savedstate = b43legacy_interrupt_disable(dev, + B43legacy_IRQ_ALL); + /* save the reason code and call our bottom half. */ + dev->irq_reason = reason; + tasklet_schedule(&dev->isr_tasklet); +out: + mmiowb(); + spin_unlock(&dev->wl->irq_lock); + + return ret; +} + +static void b43legacy_release_firmware(struct b43legacy_wldev *dev) +{ + release_firmware(dev->fw.ucode); + dev->fw.ucode = NULL; + release_firmware(dev->fw.pcm); + dev->fw.pcm = NULL; + release_firmware(dev->fw.initvals); + dev->fw.initvals = NULL; + release_firmware(dev->fw.initvals_band); + dev->fw.initvals_band = NULL; +} + +static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl) +{ + b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/" + "Drivers/bcm43xx#devicefirmware " + "and download the correct firmware (version 3).\n"); +} + +static int do_request_fw(struct b43legacy_wldev *dev, + const char *name, + const struct firmware **fw) +{ + char path[sizeof(modparam_fwpostfix) + 32]; + struct b43legacy_fw_header *hdr; + u32 size; + int err; + + if (!name) + return 0; + + snprintf(path, ARRAY_SIZE(path), + "b43legacy%s/%s.fw", + modparam_fwpostfix, name); + err = request_firmware(fw, path, dev->dev->dev); + if (err) { + b43legacyerr(dev->wl, "Firmware file \"%s\" not found " + "or load failed.\n", path); + return err; + } + if ((*fw)->size < sizeof(struct b43legacy_fw_header)) + goto err_format; + hdr = (struct b43legacy_fw_header *)((*fw)->data); + switch (hdr->type) { + case B43legacy_FW_TYPE_UCODE: + case B43legacy_FW_TYPE_PCM: + size = be32_to_cpu(hdr->size); + if (size != (*fw)->size - sizeof(struct b43legacy_fw_header)) + goto err_format; + /* fallthrough */ + case B43legacy_FW_TYPE_IV: + if (hdr->ver != 1) + goto err_format; + break; + default: + goto err_format; + } + + return err; + +err_format: + b43legacyerr(dev->wl, "Firmware file \"%s\" format error.\n", path); + return -EPROTO; +} + +static int b43legacy_request_firmware(struct b43legacy_wldev *dev) +{ + struct b43legacy_firmware *fw = &dev->fw; + const u8 rev = dev->dev->id.revision; + const char *filename; + u32 tmshigh; + int err; + + tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + if (!fw->ucode) { + if (rev == 2) + filename = "ucode2"; + else if (rev == 4) + filename = "ucode4"; + else + filename = "ucode5"; + err = do_request_fw(dev, filename, &fw->ucode); + if (err) + goto err_load; + } + if (!fw->pcm) { + if (rev < 5) + filename = "pcm4"; + else + filename = "pcm5"; + err = do_request_fw(dev, filename, &fw->pcm); + if (err) + goto err_load; + } + if (!fw->initvals) { + switch (dev->phy.type) { + case B43legacy_PHYTYPE_G: + if ((rev >= 5) && (rev <= 10)) + filename = "b0g0initvals5"; + else if (rev == 2 || rev == 4) + filename = "b0g0initvals2"; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; + } + err = do_request_fw(dev, filename, &fw->initvals); + if (err) + goto err_load; + } + if (!fw->initvals_band) { + switch (dev->phy.type) { + case B43legacy_PHYTYPE_G: + if ((rev >= 5) && (rev <= 10)) + filename = "b0g0bsinitvals5"; + else if (rev >= 11) + filename = NULL; + else if (rev == 2 || rev == 4) + filename = NULL; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; + } + err = do_request_fw(dev, filename, &fw->initvals_band); + if (err) + goto err_load; + } + + return 0; + +err_load: + b43legacy_print_fw_helptext(dev->wl); + goto error; + +err_no_initvals: + err = -ENODEV; + b43legacyerr(dev->wl, "No Initial Values firmware file for PHY %u, " + "core rev %u\n", dev->phy.type, rev); + goto error; + +error: + b43legacy_release_firmware(dev); + return err; +} + +static int b43legacy_upload_microcode(struct b43legacy_wldev *dev) +{ + const size_t hdr_len = sizeof(struct b43legacy_fw_header); + const __be32 *data; + unsigned int i; + unsigned int len; + u16 fwrev; + u16 fwpatch; + u16 fwdate; + u16 fwtime; + u32 tmp; + int err = 0; + + /* Upload Microcode. */ + data = (__be32 *) (dev->fw.ucode->data + hdr_len); + len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); + b43legacy_shm_control_word(dev, + B43legacy_SHM_UCODE | + B43legacy_SHM_AUTOINC_W, + 0x0000); + for (i = 0; i < len; i++) { + b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + + if (dev->fw.pcm) { + /* Upload PCM data. */ + data = (__be32 *) (dev->fw.pcm->data + hdr_len); + len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); + b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EA); + b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, 0x00004000); + /* No need for autoinc bit in SHM_HW */ + b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EB); + for (i = 0; i < len; i++) { + b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + } + + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, + B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402); + + /* Wait for the microcode to load and respond */ + i = 0; + while (1) { + tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + if (tmp == B43legacy_IRQ_MAC_SUSPENDED) + break; + i++; + if (i >= B43legacy_IRQWAIT_MAX_RETRIES) { + b43legacyerr(dev->wl, "Microcode not responding\n"); + b43legacy_print_fw_helptext(dev->wl); + err = -ENODEV; + goto out; + } + udelay(10); + } + /* dummy read follows */ + b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + + /* Get and check the revisions. */ + fwrev = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_UCODEREV); + fwpatch = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_UCODEPATCH); + fwdate = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_UCODEDATE); + fwtime = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_UCODETIME); + + if (fwrev > 0x128) { + b43legacyerr(dev->wl, "YOU ARE TRYING TO LOAD V4 FIRMWARE." + " Only firmware from binary drivers version 3.x" + " is supported. You must change your firmware" + " files.\n"); + b43legacy_print_fw_helptext(dev->wl); + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0); + err = -EOPNOTSUPP; + goto out; + } + b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + + dev->fw.rev = fwrev; + dev->fw.patch = fwpatch; + +out: + return err; +} + +static int b43legacy_write_initvals(struct b43legacy_wldev *dev, + const struct b43legacy_iv *ivals, + size_t count, + size_t array_size) +{ + const struct b43legacy_iv *iv; + u16 offset; + size_t i; + bool bit32; + + BUILD_BUG_ON(sizeof(struct b43legacy_iv) != 6); + iv = ivals; + for (i = 0; i < count; i++) { + if (array_size < sizeof(iv->offset_size)) + goto err_format; + array_size -= sizeof(iv->offset_size); + offset = be16_to_cpu(iv->offset_size); + bit32 = !!(offset & B43legacy_IV_32BIT); + offset &= B43legacy_IV_OFFSET_MASK; + if (offset >= 0x1000) + goto err_format; + if (bit32) { + u32 value; + + if (array_size < sizeof(iv->data.d32)) + goto err_format; + array_size -= sizeof(iv->data.d32); + + value = be32_to_cpu(get_unaligned(&iv->data.d32)); + b43legacy_write32(dev, offset, value); + + iv = (const struct b43legacy_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be32)); + } else { + u16 value; + + if (array_size < sizeof(iv->data.d16)) + goto err_format; + array_size -= sizeof(iv->data.d16); + + value = be16_to_cpu(iv->data.d16); + b43legacy_write16(dev, offset, value); + + iv = (const struct b43legacy_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be16)); + } + } + if (array_size) + goto err_format; + + return 0; + +err_format: + b43legacyerr(dev->wl, "Initial Values Firmware file-format error.\n"); + b43legacy_print_fw_helptext(dev->wl); + + return -EPROTO; +} + +static int b43legacy_upload_initvals(struct b43legacy_wldev *dev) +{ + const size_t hdr_len = sizeof(struct b43legacy_fw_header); + const struct b43legacy_fw_header *hdr; + struct b43legacy_firmware *fw = &dev->fw; + const struct b43legacy_iv *ivals; + size_t count; + int err; + + hdr = (const struct b43legacy_fw_header *)(fw->initvals->data); + ivals = (const struct b43legacy_iv *)(fw->initvals->data + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43legacy_write_initvals(dev, ivals, count, + fw->initvals->size - hdr_len); + if (err) + goto out; + if (fw->initvals_band) { + hdr = (const struct b43legacy_fw_header *) + (fw->initvals_band->data); + ivals = (const struct b43legacy_iv *)(fw->initvals_band->data + + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43legacy_write_initvals(dev, ivals, count, + fw->initvals_band->size - hdr_len); + if (err) + goto out; + } +out: + + return err; +} + +/* Initialize the GPIOs + * http://bcm-specs.sipsolutions.net/GPIO + */ +static int b43legacy_gpio_init(struct b43legacy_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + u32 mask; + u32 set; + + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, + b43legacy_read32(dev, + B43legacy_MMIO_STATUS_BITFIELD) + & 0xFFFF3FFF); + + b43legacy_leds_switch_all(dev, 0); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, + b43legacy_read16(dev, + B43legacy_MMIO_GPIO_MASK) + | 0x000F); + + mask = 0x0000001F; + set = 0x0000000F; + if (dev->dev->bus->chip_id == 0x4301) { + mask |= 0x0060; + set |= 0x0060; + } + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) { + b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, + b43legacy_read16(dev, + B43legacy_MMIO_GPIO_MASK) + | 0x0200); + mask |= 0x0200; + set |= 0x0200; + } + if (dev->dev->id.revision >= 2) + mask |= 0x0010; /* FIXME: This is redundant. */ + +#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; +#endif + gpiodev = bus->chipco.dev ? : pcidev; + if (!gpiodev) + return 0; + ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, + (ssb_read32(gpiodev, B43legacy_GPIO_CONTROL) + & mask) | set); + + return 0; +} + +/* Turn off all GPIO stuff. Call this on module unload, for example. */ +static void b43legacy_gpio_cleanup(struct b43legacy_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + +#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; +#endif + gpiodev = bus->chipco.dev ? : pcidev; + if (!gpiodev) + return; + ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, 0); +} + +/* http://bcm-specs.sipsolutions.net/EnableMac */ +void b43legacy_mac_enable(struct b43legacy_wldev *dev) +{ + dev->mac_suspended--; + B43legacy_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, + b43legacy_read32(dev, + B43legacy_MMIO_STATUS_BITFIELD) + | B43legacy_SBF_MAC_ENABLED); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, + B43legacy_IRQ_MAC_SUSPENDED); + /* the next two are dummy reads */ + b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + b43legacy_power_saving_ctl_bits(dev, -1, -1); + } +} + +/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +void b43legacy_mac_suspend(struct b43legacy_wldev *dev) +{ + int i; + u32 tmp; + + B43legacy_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + b43legacy_power_saving_ctl_bits(dev, -1, 1); + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, + b43legacy_read32(dev, + B43legacy_MMIO_STATUS_BITFIELD) + & ~B43legacy_SBF_MAC_ENABLED); + b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + for (i = 10000; i; i--) { + tmp = b43legacy_read32(dev, + B43legacy_MMIO_GEN_IRQ_REASON); + if (tmp & B43legacy_IRQ_MAC_SUSPENDED) + goto out; + udelay(1); + } + b43legacyerr(dev->wl, "MAC suspend failed\n"); + } +out: + dev->mac_suspended++; +} + +static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + u32 ctl; + u16 cfp_pretbtt; + + ctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); + /* Reset status to STA infrastructure mode. */ + ctl &= ~B43legacy_MACCTL_AP; + ctl &= ~B43legacy_MACCTL_KEEP_CTL; + ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP; + ctl &= ~B43legacy_MACCTL_KEEP_BAD; + ctl &= ~B43legacy_MACCTL_PROMISC; + ctl |= B43legacy_MACCTL_INFRA; + + if (wl->operating) { + switch (wl->if_type) { + case IEEE80211_IF_TYPE_AP: + ctl |= B43legacy_MACCTL_AP; + break; + case IEEE80211_IF_TYPE_IBSS: + ctl &= ~B43legacy_MACCTL_INFRA; + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_WDS: + break; + default: + b43legacyerr(wl, "Improper value of %d for" + " wl->if_type\n", wl->if_type); + } + } + if (wl->monitor) { + ctl |= B43legacy_MACCTL_KEEP_CTL; + if (modparam_mon_keep_bad) + ctl |= B43legacy_MACCTL_KEEP_BAD; + if (modparam_mon_keep_badplcp) + ctl |= B43legacy_MACCTL_KEEP_BADPLCP; + } + if (wl->promisc) + ctl |= B43legacy_MACCTL_PROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter + * doesn't work properly, so always run promisc in filter + * it in software. */ + if (dev->dev->id.revision <= 4) + ctl |= B43legacy_MACCTL_PROMISC; + + b43legacy_write32(dev, B43legacy_MMIO_MACCTL, ctl); + + cfp_pretbtt = 2; + if ((ctl & B43legacy_MACCTL_INFRA) && + !(ctl & B43legacy_MACCTL_AP)) { + if (dev->dev->bus->chip_id == 0x4306 && + dev->dev->bus->chip_rev == 3) + cfp_pretbtt = 100; + else + cfp_pretbtt = 50; + } + b43legacy_write16(dev, 0x612, cfp_pretbtt); +} + +static void b43legacy_rate_memory_write(struct b43legacy_wldev *dev, + u16 rate, + int is_ofdm) +{ + u16 offset; + + if (is_ofdm) { + offset = 0x480; + offset += (b43legacy_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; + } else { + offset = 0x4C0; + offset += (b43legacy_plcp_get_ratecode_cck(rate) & 0x000F) * 2; + } + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, offset + 0x20, + b43legacy_shm_read16(dev, + B43legacy_SHM_SHARED, offset)); +} + +static void b43legacy_rate_memory_init(struct b43legacy_wldev *dev) +{ + switch (dev->phy.type) { + case B43legacy_PHYTYPE_G: + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_6MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_12MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_18MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_24MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_36MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_48MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_54MB, 1); + /* fallthrough */ + case B43legacy_PHYTYPE_B: + b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_1MB, 0); + b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_2MB, 0); + b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_5MB, 0); + b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_11MB, 0); + break; + default: + B43legacy_BUG_ON(1); + } +} + +/* Set the TX-Antenna for management frames sent by firmware. */ +static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev, + int antenna) +{ + u16 ant = 0; + u16 tmp; + + switch (antenna) { + case B43legacy_ANTENNA0: + ant |= B43legacy_TX4_PHY_ANT0; + break; + case B43legacy_ANTENNA1: + ant |= B43legacy_TX4_PHY_ANT1; + break; + case B43legacy_ANTENNA_AUTO: + ant |= B43legacy_TX4_PHY_ANTLAST; + break; + default: + B43legacy_BUG_ON(1); + } + + /* FIXME We also need to set the other flags of the PHY control + * field somewhere. */ + + /* For Beacons */ + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_BEACPHYCTL); + tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_BEACPHYCTL, tmp); + /* For ACK/CTS */ + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_ACKCTSPHYCTL); + tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_ACKCTSPHYCTL, tmp); + /* For Probe Resposes */ + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_PRPHYCTL); + tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_PRPHYCTL, tmp); +} + +/* This is the opposite of b43legacy_chip_init() */ +static void b43legacy_chip_exit(struct b43legacy_wldev *dev) +{ + b43legacy_radio_turn_off(dev); + if (!modparam_noleds) + b43legacy_leds_exit(dev); + b43legacy_gpio_cleanup(dev); + /* firmware is released later */ +} + +/* Initialize the chip + * http://bcm-specs.sipsolutions.net/ChipInit + */ +static int b43legacy_chip_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + int err; + int tmp; + u32 value32; + u16 value16; + + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, + B43legacy_SBF_CORE_READY + | B43legacy_SBF_400); + + err = b43legacy_request_firmware(dev); + if (err) + goto out; + err = b43legacy_upload_microcode(dev); + if (err) + goto out; /* firmware is released later */ + + err = b43legacy_gpio_init(dev); + if (err) + goto out; /* firmware is released later */ + err = b43legacy_upload_initvals(dev); + if (err) + goto err_gpio_cleanup; + b43legacy_radio_turn_on(dev); + dev->radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); + b43legacyinfo(dev->wl, "Radio %s by hardware\n", + (dev->radio_hw_enable == 0) ? "disabled" : "enabled"); + + b43legacy_write16(dev, 0x03E6, 0x0000); + err = b43legacy_phy_init(dev); + if (err) + goto err_radio_off; + + /* Select initial Interference Mitigation. */ + tmp = phy->interfmode; + phy->interfmode = B43legacy_INTERFMODE_NONE; + b43legacy_radio_set_interference_mitigation(dev, tmp); + + b43legacy_phy_set_antenna_diversity(dev); + b43legacy_mgmtframe_txantenna(dev, B43legacy_ANTENNA_DEFAULT); + + if (phy->type == B43legacy_PHYTYPE_B) { + value16 = b43legacy_read16(dev, 0x005E); + value16 |= 0x0004; + b43legacy_write16(dev, 0x005E, value16); + } + b43legacy_write32(dev, 0x0100, 0x01000000); + if (dev->dev->id.revision < 5) + b43legacy_write32(dev, 0x010C, 0x01000000); + + value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + value32 &= ~B43legacy_SBF_MODE_NOTADHOC; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); + value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + value32 |= B43legacy_SBF_MODE_NOTADHOC; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); + + value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + value32 |= 0x100000; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); + + if (b43legacy_using_pio(dev)) { + b43legacy_write32(dev, 0x0210, 0x00000100); + b43legacy_write32(dev, 0x0230, 0x00000100); + b43legacy_write32(dev, 0x0250, 0x00000100); + b43legacy_write32(dev, 0x0270, 0x00000100); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0034, + 0x0000); + } + + /* Probe Response Timeout value */ + /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0074, 0x0000); + + /* Initially set the wireless operation mode. */ + b43legacy_adjust_opmode(dev); + + if (dev->dev->id.revision < 3) { + b43legacy_write16(dev, 0x060E, 0x0000); + b43legacy_write16(dev, 0x0610, 0x8000); + b43legacy_write16(dev, 0x0604, 0x0000); + b43legacy_write16(dev, 0x0606, 0x0200); + } else { + b43legacy_write32(dev, 0x0188, 0x80000000); + b43legacy_write32(dev, 0x018C, 0x02000000); + } + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, 0x00004000); + b43legacy_write32(dev, B43legacy_MMIO_DMA0_IRQ_MASK, 0x0001DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA1_IRQ_MASK, 0x0000DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA2_IRQ_MASK, 0x0000DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA3_IRQ_MASK, 0x0001DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA4_IRQ_MASK, 0x0000DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00); + + value32 = ssb_read32(dev->dev, SSB_TMSLOW); + value32 |= 0x00100000; + ssb_write32(dev->dev, SSB_TMSLOW, value32); + + b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY, + dev->dev->bus->chipco.fast_pwrup_delay); + + B43legacy_WARN_ON(err != 0); + b43legacydbg(dev->wl, "Chip initialized\n"); +out: + return err; + +err_radio_off: + b43legacy_radio_turn_off(dev); +err_gpio_cleanup: + b43legacy_gpio_cleanup(dev); + goto out; +} + +static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->type != B43legacy_PHYTYPE_G || phy->rev < 2) + return; + + b43legacy_mac_suspend(dev); + b43legacy_phy_lo_g_measure(dev); + b43legacy_mac_enable(dev); +} + +static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev) +{ + b43legacy_phy_lo_mark_all_unused(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + b43legacy_mac_suspend(dev); + b43legacy_calc_nrssi_slope(dev); + b43legacy_mac_enable(dev); + } +} + +static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev) +{ + /* Update device statistics. */ + b43legacy_calculate_link_quality(dev); +} + +static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev) +{ + b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */ +} + +static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) +{ + int radio_hw_enable; + + /* check if radio hardware enabled status changed */ + radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { + dev->radio_hw_enable = radio_hw_enable; + b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n", + (radio_hw_enable == 0) ? "disabled" : "enabled"); + b43legacy_leds_update(dev, 0); + } +} + +static void do_periodic_work(struct b43legacy_wldev *dev) +{ + unsigned int state; + + state = dev->periodic_state; + if (state % 120 == 0) + b43legacy_periodic_every120sec(dev); + if (state % 60 == 0) + b43legacy_periodic_every60sec(dev); + if (state % 30 == 0) + b43legacy_periodic_every30sec(dev); + if (state % 15 == 0) + b43legacy_periodic_every15sec(dev); + b43legacy_periodic_every1sec(dev); +} + +/* Estimate a "Badness" value based on the periodic work + * state-machine state. "Badness" is worse (bigger), if the + * periodic work will take longer. + */ +static int estimate_periodic_work_badness(unsigned int state) +{ + int badness = 0; + + if (state % 120 == 0) /* every 120 sec */ + badness += 10; + if (state % 60 == 0) /* every 60 sec */ + badness += 5; + if (state % 30 == 0) /* every 30 sec */ + badness += 1; + if (state % 15 == 0) /* every 15 sec */ + badness += 1; + +#define BADNESS_LIMIT 4 + return badness; +} + +static void b43legacy_periodic_work_handler(struct work_struct *work) +{ + struct b43legacy_wldev *dev = + container_of(work, struct b43legacy_wldev, + periodic_work.work); + unsigned long flags; + unsigned long delay; + u32 savedirqs = 0; + int badness; + + mutex_lock(&dev->wl->mutex); + + if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED)) + goto out; + if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP)) + goto out_requeue; + + badness = estimate_periodic_work_badness(dev->periodic_state); + if (badness > BADNESS_LIMIT) { + spin_lock_irqsave(&dev->wl->irq_lock, flags); + /* Suspend TX as we don't want to transmit packets while + * we recalibrate the hardware. */ + b43legacy_tx_suspend(dev); + savedirqs = b43legacy_interrupt_disable(dev, + B43legacy_IRQ_ALL); + /* Periodic work will take a long time, so we want it to + * be preemtible and release the spinlock. */ + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + do_periodic_work(dev); + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + b43legacy_interrupt_enable(dev, savedirqs); + b43legacy_tx_resume(dev); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } else { + /* Take the global driver lock. This will lock any operation. */ + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + do_periodic_work(dev); + + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } + dev->periodic_state++; +out_requeue: + if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST)) + delay = msecs_to_jiffies(50); + else + delay = round_jiffies(HZ); + queue_delayed_work(dev->wl->hw->workqueue, + &dev->periodic_work, delay); +out: + mutex_unlock(&dev->wl->mutex); +} + +static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev) +{ + struct delayed_work *work = &dev->periodic_work; + + dev->periodic_state = 0; + INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler); + queue_delayed_work(dev->wl->hw->workqueue, work, 0); +} + +/* Validate access to the chip (SHM) */ +static int b43legacy_validate_chipaccess(struct b43legacy_wldev *dev) +{ + u32 value; + u32 shm_backup; + + shm_backup = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0); + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0xAA5555AA); + if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) != + 0xAA5555AA) + goto error; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0x55AAAA55); + if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) != + 0x55AAAA55) + goto error; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, shm_backup); + + value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); + if ((value | B43legacy_MACCTL_GMODE) != + (B43legacy_MACCTL_GMODE | B43legacy_MACCTL_IHR_ENABLED)) + goto error; + + value = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + if (value) + goto error; + + return 0; +error: + b43legacyerr(dev->wl, "Failed to validate the chipaccess\n"); + return -ENODEV; +} + +static void b43legacy_security_init(struct b43legacy_wldev *dev) +{ + dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20; + B43legacy_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key)); + dev->ktp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + 0x0056); + /* 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 */ + b43legacy_write16(dev, B43legacy_MMIO_RCMTA_COUNT, + dev->max_nr_keys - 8); +} + +static int b43legacy_rng_read(struct hwrng *rng, u32 *data) +{ + struct b43legacy_wl *wl = (struct b43legacy_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. */ + + spin_lock_irqsave(&wl->irq_lock, flags); + *data = b43legacy_read16(wl->current_dev, B43legacy_MMIO_RNG); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return (sizeof(u16)); +} + +static void b43legacy_rng_exit(struct b43legacy_wl *wl) +{ + if (wl->rng_initialized) + hwrng_unregister(&wl->rng); +} + +static int b43legacy_rng_init(struct b43legacy_wl *wl) +{ + int err; + + snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), + "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); + wl->rng.name = wl->rng_name; + wl->rng.data_read = b43legacy_rng_read; + wl->rng.priv = (unsigned long)wl; + wl->rng_initialized = 1; + err = hwrng_register(&wl->rng); + if (err) { + wl->rng_initialized = 0; + b43legacyerr(wl, "Failed to register the random " + "number generator (%d)\n", err); + } + + return err; +} + +static int b43legacy_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + int err = -ENODEV; + unsigned long flags; + + if (unlikely(!dev)) + goto out; + if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED)) + goto out; + /* DMA-TX is done without a global lock. */ + if (b43legacy_using_pio(dev)) { + spin_lock_irqsave(&wl->irq_lock, flags); + err = b43legacy_pio_tx(dev, skb, ctl); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } else + err = b43legacy_dma_tx(dev, skb, ctl); +out: + if (unlikely(err)) + return NETDEV_TX_BUSY; + return NETDEV_TX_OK; +} + +static int b43legacy_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) +{ + return 0; +} + +static int b43legacy_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + int err = -ENODEV; + + if (!dev) + goto out; + spin_lock_irqsave(&wl->irq_lock, flags); + if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) { + if (b43legacy_using_pio(dev)) + b43legacy_pio_get_tx_stats(dev, stats); + else + b43legacy_dma_get_tx_stats(dev, stats); + err = 0; + } + spin_unlock_irqrestore(&wl->irq_lock, flags); +out: + return err; +} + +static int b43legacy_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + unsigned long flags; + + spin_lock_irqsave(&wl->irq_lock, flags); + memcpy(stats, &wl->ieee_stats, sizeof(*stats)); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + +static const char *phymode_to_string(unsigned int phymode) +{ + switch (phymode) { + case B43legacy_PHYMODE_B: + return "B"; + case B43legacy_PHYMODE_G: + return "G"; + default: + B43legacy_BUG_ON(1); + } + return ""; +} + +static int find_wldev_for_phymode(struct b43legacy_wl *wl, + unsigned int phymode, + struct b43legacy_wldev **dev, + bool *gmode) +{ + struct b43legacy_wldev *d; + + list_for_each_entry(d, &wl->devlist, list) { + if (d->phy.possible_phymodes & phymode) { + /* Ok, this device supports the PHY-mode. + * Set the gmode bit. */ + *gmode = 1; + *dev = d; + + return 0; + } + } + + return -ESRCH; +} + +static void b43legacy_put_phy_into_reset(struct b43legacy_wldev *dev) +{ + struct ssb_device *sdev = dev->dev; + u32 tmslow; + + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmslow &= ~B43legacy_TMSLOW_GMODE; + tmslow |= B43legacy_TMSLOW_PHYRESET; + tmslow |= SSB_TMSLOW_FGC; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + msleep(1); + + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmslow &= ~SSB_TMSLOW_FGC; + tmslow |= B43legacy_TMSLOW_PHYRESET; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + msleep(1); +} + +/* Expects wl->mutex locked */ +static int b43legacy_switch_phymode(struct b43legacy_wl *wl, + unsigned int new_mode) +{ + struct b43legacy_wldev *up_dev; + struct b43legacy_wldev *down_dev; + int err; + bool gmode = 0; + int prev_status; + + err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode); + if (err) { + b43legacyerr(wl, "Could not find a device for %s-PHY mode\n", + phymode_to_string(new_mode)); + return err; + } + if ((up_dev == wl->current_dev) && + (!!wl->current_dev->phy.gmode == !!gmode)) + /* This device is already running. */ + return 0; + b43legacydbg(wl, "Reconfiguring PHYmode to %s-PHY\n", + phymode_to_string(new_mode)); + down_dev = wl->current_dev; + + prev_status = b43legacy_status(down_dev); + /* Shutdown the currently running core. */ + if (prev_status >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(down_dev); + if (prev_status >= B43legacy_STAT_INITIALIZED) + b43legacy_wireless_core_exit(down_dev); + + if (down_dev != up_dev) + /* We switch to a different core, so we put PHY into + * RESET on the old core. */ + b43legacy_put_phy_into_reset(down_dev); + + /* Now start the new core. */ + up_dev->phy.gmode = gmode; + if (prev_status >= B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(up_dev); + if (err) { + b43legacyerr(wl, "Fatal: Could not initialize device" + " for newly selected %s-PHY mode\n", + phymode_to_string(new_mode)); + goto init_failure; + } + } + if (prev_status >= B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(up_dev); + if (err) { + b43legacyerr(wl, "Fatal: Coult not start device for " + "newly selected %s-PHY mode\n", + phymode_to_string(new_mode)); + b43legacy_wireless_core_exit(up_dev); + goto init_failure; + } + } + B43legacy_WARN_ON(b43legacy_status(up_dev) != prev_status); + + b43legacy_shm_write32(up_dev, B43legacy_SHM_SHARED, 0x003E, 0); + + wl->current_dev = up_dev; + + return 0; +init_failure: + /* Whoops, failed to init the new core. No core is operating now. */ + wl->current_dev = NULL; + return err; +} + +static int b43legacy_antenna_from_ieee80211(u8 antenna) +{ + switch (antenna) { + case 0: /* default/diversity */ + return B43legacy_ANTENNA_DEFAULT; + case 1: /* Antenna 0 */ + return B43legacy_ANTENNA0; + case 2: /* Antenna 1 */ + return B43legacy_ANTENNA1; + default: + return B43legacy_ANTENNA_DEFAULT; + } +} + +static int b43legacy_dev_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + struct b43legacy_phy *phy; + unsigned long flags; + unsigned int new_phymode = 0xFFFF; + int antenna_tx; + int antenna_rx; + int err = 0; + u32 savedirqs; + + antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx); + antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx); + + mutex_lock(&wl->mutex); + + /* Switch the PHY mode (if necessary). */ + switch (conf->phymode) { + case MODE_IEEE80211B: + new_phymode = B43legacy_PHYMODE_B; + break; + case MODE_IEEE80211G: + new_phymode = B43legacy_PHYMODE_G; + break; + default: + B43legacy_WARN_ON(1); + } + err = b43legacy_switch_phymode(wl, new_phymode); + if (err) + goto out_unlock_mutex; + dev = wl->current_dev; + phy = &dev->phy; + + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ + spin_lock_irqsave(&wl->irq_lock, flags); + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + /* Switch to the requested channel. + * The firmware takes care of races with the TX handler. */ + if (conf->channel_val != phy->channel) + b43legacy_radio_selectchannel(dev, conf->channel_val, 0); + + /* Enable/Disable ShortSlot timing. */ + if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) + != dev->short_slot) { + B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G); + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) + b43legacy_short_slot_timing_enable(dev); + else + b43legacy_short_slot_timing_disable(dev); + } + + /* Adjust the desired TX power level. */ + if (conf->power_level != 0) { + if (conf->power_level != phy->power_level) { + phy->power_level = conf->power_level; + b43legacy_phy_xmitpower(dev); + } + } + + /* Antennas for RX and management frame TX. */ + b43legacy_mgmtframe_txantenna(dev, antenna_tx); + + /* Update templates for AP mode. */ + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + b43legacy_set_beacon_int(dev, conf->beacon_int); + + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_interrupt_enable(dev, savedirqs); + mmiowb(); + spin_unlock_irqrestore(&wl->irq_lock, flags); +out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return err; +} + +static int b43legacy_dev_set_key(struct ieee80211_hw *hw, + set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + int err = -EOPNOTSUPP; + + if (!dev) + return -ENODEV; + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = -ENODEV; + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + b43legacydbg(wl, "Using software based encryption for " + "mac: " MAC_FMT "\n", MAC_ARG(addr)); + return err; +} + +static void b43legacy_set_multicast_list(struct ieee80211_hw *hw, + unsigned short netflags, + int mc_count) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + + if (!dev) + return; + spin_lock_irqsave(&wl->irq_lock, flags); + if (wl->promisc != !!(netflags & IFF_PROMISC)) { + wl->promisc = !!(netflags & IFF_PROMISC); + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) + b43legacy_adjust_opmode(dev); + } + spin_unlock_irqrestore(&wl->irq_lock, flags); +} + +static int b43legacy_config_interface(struct ieee80211_hw *hw, + int if_id, + struct ieee80211_if_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + + if (!dev) + return -ENODEV; + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + if (conf->type != IEEE80211_IF_TYPE_MNTR) { + B43legacy_WARN_ON(wl->if_id != if_id); + wl->bssid = conf->bssid; + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43legacy_WARN_ON(conf->type != + IEEE80211_IF_TYPE_AP); + b43legacy_set_ssid(dev, conf->ssid, + conf->ssid_len); + if (conf->beacon) + b43legacy_refresh_templates(dev, + conf->beacon); + } + b43legacy_write_mac_bssid_templates(dev); + } + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + + return 0; +} + +/* Locking: wl->mutex */ +static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + unsigned long flags; + + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) + return; + b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); + + 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); + mutex_lock(&wl->mutex); + + ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */ + + /* Disable and sync interrupts. */ + spin_lock_irqsave(&wl->irq_lock, flags); + dev->irq_savedstate = b43legacy_interrupt_disable(dev, + B43legacy_IRQ_ALL); + b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */ + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + b43legacy_mac_suspend(dev); + free_irq(dev->dev->irq, dev); + b43legacydbg(wl, "Wireless interface stopped\n"); +} + +/* Locking: wl->mutex */ +static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) +{ + int err; + + B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_INITIALIZED); + + drain_txstatus_queue(dev); + err = request_irq(dev->dev->irq, b43legacy_interrupt_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (err) { + b43legacyerr(dev->wl, "Cannot request IRQ-%d\n", + dev->dev->irq); + goto out; + } + /* We are ready to run. */ + b43legacy_set_status(dev, B43legacy_STAT_STARTED); + + /* Start data flow (TX/RX) */ + b43legacy_mac_enable(dev); + b43legacy_interrupt_enable(dev, dev->irq_savedstate); + ieee80211_start_queues(dev->wl->hw); + + /* Start maintenance work */ + b43legacy_periodic_tasks_setup(dev); + + b43legacydbg(dev->wl, "Wireless interface started\n"); +out: + return err; +} + +/* Get PHY and RADIO versioning numbers */ +static int b43legacy_phy_versioning(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u32 tmp; + u8 analog_type; + u8 phy_type; + u8 phy_rev; + u16 radio_manuf; + u16 radio_ver; + u16 radio_rev; + int unsupported = 0; + + /* Get PHY versioning */ + tmp = b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); + analog_type = (tmp & B43legacy_PHYVER_ANALOG) + >> B43legacy_PHYVER_ANALOG_SHIFT; + phy_type = (tmp & B43legacy_PHYVER_TYPE) >> B43legacy_PHYVER_TYPE_SHIFT; + phy_rev = (tmp & B43legacy_PHYVER_VERSION); + switch (phy_type) { + case B43legacy_PHYTYPE_B: + if (phy_rev != 2 && phy_rev != 4 + && phy_rev != 6 && phy_rev != 7) + unsupported = 1; + break; + case B43legacy_PHYTYPE_G: + if (phy_rev > 8) + unsupported = 1; + break; + default: + unsupported = 1; + }; + if (unsupported) { + b43legacyerr(dev->wl, "FOUND UNSUPPORTED PHY " + "(Analog %u, Type %u, Revision %u)\n", + analog_type, phy_type, phy_rev); + return -EOPNOTSUPP; + } + b43legacydbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n", + analog_type, phy_type, phy_rev); + + + /* Get RADIO versioning */ + if (dev->dev->bus->chip_id == 0x4317) { + if (dev->dev->bus->chip_rev == 0) + tmp = 0x3205017F; + else if (dev->dev->bus->chip_rev == 1) + tmp = 0x4205017F; + else + tmp = 0x5205017F; + } else { + b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, + B43legacy_RADIOCTL_ID); + tmp = b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_HIGH); + tmp <<= 16; + b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, + B43legacy_RADIOCTL_ID); + tmp |= b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW); + } + radio_manuf = (tmp & 0x00000FFF); + radio_ver = (tmp & 0x0FFFF000) >> 12; + radio_rev = (tmp & 0xF0000000) >> 28; + switch (phy_type) { + case B43legacy_PHYTYPE_B: + if ((radio_ver & 0xFFF0) != 0x2050) + unsupported = 1; + break; + case B43legacy_PHYTYPE_G: + if (radio_ver != 0x2050) + unsupported = 1; + break; + default: + B43legacy_BUG_ON(1); + } + if (unsupported) { + b43legacyerr(dev->wl, "FOUND UNSUPPORTED RADIO " + "(Manuf 0x%X, Version 0x%X, Revision %u)\n", + radio_manuf, radio_ver, radio_rev); + return -EOPNOTSUPP; + } + b43legacydbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X," + " Revision %u\n", radio_manuf, radio_ver, radio_rev); + + + phy->radio_manuf = radio_manuf; + phy->radio_ver = radio_ver; + phy->radio_rev = radio_rev; + + phy->analog = analog_type; + phy->type = phy_type; + phy->rev = phy_rev; + + return 0; +} + +static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, + struct b43legacy_phy *phy) +{ + struct b43legacy_lopair *lo; + int i; + + memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); + memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); + + /* Flags */ + phy->locked = 0; + + phy->savedpctlreg = 0xFFFF; + phy->aci_enable = 0; + phy->aci_wlan_automatic = 0; + phy->aci_hw_rssi = 0; + + lo = phy->_lo_pairs; + if (lo) + memset(lo, 0, sizeof(struct b43legacy_lopair) * + B43legacy_LO_COUNT); + phy->max_lb_gain = 0; + phy->trsw_rx_gain = 0; + + /* Set default attenuation values. */ + phy->bbatt = b43legacy_default_baseband_attenuation(dev); + phy->rfatt = b43legacy_default_radio_attenuation(dev); + phy->txctl1 = b43legacy_default_txctl1(dev); + phy->txpwr_offset = 0; + + /* NRSSI */ + phy->nrssislope = 0; + for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) + phy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) + phy->nrssi_lt[i] = i; + + phy->lofcal = 0xFFFF; + phy->initval = 0xFFFF; + + spin_lock_init(&phy->lock); + phy->interfmode = B43legacy_INTERFMODE_NONE; + phy->channel = 0xFF; +} + +static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) +{ + /* Flags */ + dev->reg124_set_0x4 = 0; + + /* Stats */ + memset(&dev->stats, 0, sizeof(dev->stats)); + + setup_struct_phy_for_init(dev, &dev->phy); + + /* IRQ related flags */ + dev->irq_reason = 0; + memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); + dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE; + + dev->mac_suspended = 1; + + /* Noise calculation context */ + memset(&dev->noisecalc, 0, sizeof(dev->noisecalc)); +} + +static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) +{ +#ifdef CONFIG_SSB_DRIVER_PCICORE + struct ssb_bus *bus = dev->dev->bus; + u32 tmp; + + if (bus->pcicore.dev && + bus->pcicore.dev->id.coreid == SSB_DEV_PCI && + 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 |= 0x32; + break; + case SSB_BUSTYPE_SSB: + tmp |= 0x53; + break; + } + ssb_write32(dev->dev, SSB_IMCFGLO, tmp); + } +#endif /* CONFIG_SSB_DRIVER_PCICORE */ +} + +/* Shutdown a wireless core */ +/* Locking: wl->mutex */ +static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct b43legacy_phy *phy = &dev->phy; + + B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED); + if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED) + return; + b43legacy_set_status(dev, B43legacy_STAT_UNINIT); + + mutex_unlock(&wl->mutex); + /* Must unlock as it would otherwise deadlock. No races here. + * Cancel possibly pending workqueues. */ + cancel_work_sync(&dev->restart_work); + mutex_lock(&wl->mutex); + + b43legacy_rng_exit(dev->wl); + b43legacy_pio_free(dev); + b43legacy_dma_free(dev); + b43legacy_chip_exit(dev); + b43legacy_radio_turn_off(dev); + b43legacy_switch_analog(dev, 0); + if (phy->dyn_tssi_tbl) + kfree(phy->tssi2dbm); + kfree(phy->lo_control); + phy->lo_control = NULL; + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(dev->dev->bus); +} + +static void prepare_phy_data_for_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + int i; + + /* Set default attenuation values. */ + phy->bbatt = b43legacy_default_baseband_attenuation(dev); + phy->rfatt = b43legacy_default_radio_attenuation(dev); + phy->txctl1 = b43legacy_default_txctl1(dev); + phy->txctl2 = 0xFFFF; + phy->txpwr_offset = 0; + + /* NRSSI */ + phy->nrssislope = 0; + for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) + phy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) + phy->nrssi_lt[i] = i; + + phy->lofcal = 0xFFFF; + phy->initval = 0xFFFF; + + phy->aci_enable = 0; + phy->aci_wlan_automatic = 0; + phy->aci_hw_rssi = 0; + + phy->antenna_diversity = 0xFFFF; + memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); + memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); + + /* Flags */ + phy->calibrated = 0; + phy->locked = 0; + + if (phy->_lo_pairs) + memset(phy->_lo_pairs, 0, + sizeof(struct b43legacy_lopair) * B43legacy_LO_COUNT); + memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain)); +} + +/* Initialize a wireless core */ +static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct ssb_bus *bus = dev->dev->bus; + struct b43legacy_phy *phy = &dev->phy; + struct ssb_sprom *sprom = &dev->dev->bus->sprom; + int err; + u32 hf; + u32 tmp; + + B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT); + + err = ssb_bus_powerup(bus, 0); + if (err) + goto out; + if (!ssb_device_is_enabled(dev->dev)) { + tmp = phy->gmode ? B43legacy_TMSLOW_GMODE : 0; + b43legacy_wireless_core_reset(dev, tmp); + } + + if ((phy->type == B43legacy_PHYTYPE_B) || + (phy->type == B43legacy_PHYTYPE_G)) { + phy->_lo_pairs = kzalloc(sizeof(struct b43legacy_lopair) + * B43legacy_LO_COUNT, + GFP_KERNEL); + if (!phy->_lo_pairs) + return -ENOMEM; + } + setup_struct_wldev_for_init(dev); + + err = b43legacy_phy_init_tssi2dbm_table(dev); + if (err) + goto err_kfree_lo_control; + + /* Enable IRQ routing to this device. */ + ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); + + b43legacy_imcfglo_timeouts_workaround(dev); + prepare_phy_data_for_init(dev); + b43legacy_phy_calibrate(dev); + err = b43legacy_chip_init(dev); + if (err) + goto err_kfree_tssitbl; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_WLCOREREV, + dev->dev->id.revision); + hf = b43legacy_hf_read(dev); + if (phy->type == B43legacy_PHYTYPE_G) { + hf |= B43legacy_HF_SYMW; + if (phy->rev == 1) + hf |= B43legacy_HF_GDCW; + if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL) + hf |= B43legacy_HF_OFDMPABOOST; + } else if (phy->type == B43legacy_PHYTYPE_B) { + hf |= B43legacy_HF_SYMW; + if (phy->rev >= 2 && phy->radio_ver == 0x2050) + hf &= ~B43legacy_HF_GDCW; + } + b43legacy_hf_write(dev, hf); + + /* Short/Long Retry Limit. + * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. + */ + tmp = limit_value(modparam_short_retry, 0, 0xF); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0006, tmp); + tmp = limit_value(modparam_long_retry, 0, 0xF); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0007, tmp); + + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + 0x0044, 3); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + 0x0046, 2); + + /* Disable sending probe responses from firmware. + * Setting the MaxTime to one usec will always trigger + * a timeout, so we never send any probe resp. + * A timeout of zero is infinite. */ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_PRMAXTIME, 1); + + b43legacy_rate_memory_init(dev); + + /* Minimum Contention Window */ + if (phy->type == B43legacy_PHYTYPE_B) + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0003, 31); + else + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0003, 15); + /* Maximum Contention Window */ + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0004, 1023); + + do { + if (b43legacy_using_pio(dev)) + err = b43legacy_pio_init(dev); + else { + err = b43legacy_dma_init(dev); + if (!err) + b43legacy_qos_init(dev); + } + } while (err == -EAGAIN); + if (err) + goto err_chip_exit; + + b43legacy_write16(dev, 0x0612, 0x0050); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0416, 0x0050); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4); + + ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ + wl->bssid = NULL; + b43legacy_upload_card_macaddress(dev, NULL); + b43legacy_security_init(dev); + b43legacy_rng_init(wl); + + b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); + +out: + return err; + +err_chip_exit: + b43legacy_chip_exit(dev); +err_kfree_tssitbl: + if (phy->dyn_tssi_tbl) + kfree(phy->tssi2dbm); +err_kfree_lo_control: + kfree(phy->lo_control); + phy->lo_control = NULL; + ssb_bus_may_powerdown(bus); + B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT); + return err; +} + +static int b43legacy_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + unsigned long flags; + int err = -EOPNOTSUPP; + int did_init = 0; + + mutex_lock(&wl->mutex); + if ((conf->type != IEEE80211_IF_TYPE_MNTR) && + wl->operating) + goto out_mutex_unlock; + + b43legacydbg(wl, "Adding Interface type %d\n", conf->type); + + dev = wl->current_dev; + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(dev); + if (err) + goto out_mutex_unlock; + did_init = 1; + } + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(dev); + if (err) { + if (did_init) + b43legacy_wireless_core_exit(dev); + goto out_mutex_unlock; + } + } + + spin_lock_irqsave(&wl->irq_lock, flags); + switch (conf->type) { + case IEEE80211_IF_TYPE_MNTR: + wl->monitor++; + break; + default: + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + b43legacy_upload_card_macaddress(dev, conf->mac_addr); + } + b43legacy_adjust_opmode(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + err = 0; +out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static void b43legacy_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + unsigned long flags; + + b43legacydbg(wl, "Removing Interface type %d\n", conf->type); + + mutex_lock(&wl->mutex); + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + wl->monitor--; + B43legacy_WARN_ON(wl->monitor < 0); + } else { + B43legacy_WARN_ON(!wl->operating); + wl->operating = 0; + } + + dev = wl->current_dev; + if (!wl->operating && wl->monitor == 0) { + /* No interface left. */ + if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(dev); + b43legacy_wireless_core_exit(dev); + } else { + /* Just monitor interfaces left. */ + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_adjust_opmode(dev); + if (!wl->operating) + b43legacy_upload_card_macaddress(dev, NULL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } + mutex_unlock(&wl->mutex); +} + + +static const struct ieee80211_ops b43legacy_hw_ops = { + .tx = b43legacy_tx, + .conf_tx = b43legacy_conf_tx, + .add_interface = b43legacy_add_interface, + .remove_interface = b43legacy_remove_interface, + .config = b43legacy_dev_config, + .config_interface = b43legacy_config_interface, + .set_key = b43legacy_dev_set_key, + .set_multicast_list = b43legacy_set_multicast_list, + .get_stats = b43legacy_get_stats, + .get_tx_stats = b43legacy_get_tx_stats, +}; + +/* Hard-reset the chip. Do not call this directly. + * Use b43legacy_controller_restart() + */ +static void b43legacy_chip_reset(struct work_struct *work) +{ + struct b43legacy_wldev *dev = + container_of(work, struct b43legacy_wldev, restart_work); + struct b43legacy_wl *wl = dev->wl; + int err = 0; + int prev_status; + + mutex_lock(&wl->mutex); + + prev_status = b43legacy_status(dev); + /* Bring the device down... */ + if (prev_status >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(dev); + if (prev_status >= B43legacy_STAT_INITIALIZED) + b43legacy_wireless_core_exit(dev); + + /* ...and up again. */ + if (prev_status >= B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(dev); + if (err) + goto out; + } + if (prev_status >= B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(dev); + if (err) { + b43legacy_wireless_core_exit(dev); + goto out; + } + } +out: + mutex_unlock(&wl->mutex); + if (err) + b43legacyerr(wl, "Controller restart FAILED\n"); + else + b43legacyinfo(wl, "Controller restarted\n"); +} + +static int b43legacy_setup_modes(struct b43legacy_wldev *dev, + int have_bphy, + int have_gphy) +{ + struct ieee80211_hw *hw = dev->wl->hw; + struct ieee80211_hw_mode *mode; + struct b43legacy_phy *phy = &dev->phy; + int cnt = 0; + int err; + + phy->possible_phymodes = 0; + for (; 1; cnt++) { + if (have_bphy) { + B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211B; + mode->num_channels = b43legacy_bg_chantable_size; + mode->channels = b43legacy_bg_chantable; + mode->num_rates = b43legacy_b_ratetable_size; + mode->rates = b43legacy_b_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43legacy_PHYMODE_B; + have_bphy = 0; + continue; + } + if (have_gphy) { + B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211G; + mode->num_channels = b43legacy_bg_chantable_size; + mode->channels = b43legacy_bg_chantable; + mode->num_rates = b43legacy_g_ratetable_size; + mode->rates = b43legacy_g_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43legacy_PHYMODE_G; + have_gphy = 0; + continue; + } + break; + } + + return 0; +} + +static void b43legacy_wireless_core_detach(struct b43legacy_wldev *dev) +{ + /* We release firmware that late to not be required to re-request + * is all the time when we reinit the core. */ + b43legacy_release_firmware(dev); +} + +static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct ssb_bus *bus = dev->dev->bus; + struct pci_dev *pdev = bus->host_pci; + int err; + int have_bphy = 0; + int have_gphy = 0; + u32 tmp; + + /* Do NOT do any device initialization here. + * Do it in wireless_core_init() instead. + * This function is for gathering basic information about the HW, only. + * Also some structs may be set up here. But most likely you want to + * have that in core_init(), too. + */ + + err = ssb_bus_powerup(bus, 0); + if (err) { + b43legacyerr(wl, "Bus powerup failed\n"); + goto out; + } + /* Get the PHY type. */ + if (dev->dev->id.revision >= 5) { + u32 tmshigh; + + tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + have_gphy = !!(tmshigh & B43legacy_TMSHIGH_GPHY); + if (!have_gphy) + have_bphy = 1; + } else if (dev->dev->id.revision == 4) + have_gphy = 1; + else + have_bphy = 1; + + /* Initialize LEDs structs. */ + err = b43legacy_leds_init(dev); + if (err) + goto err_powerdown; + + dev->phy.gmode = (have_gphy || have_bphy); + tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; + b43legacy_wireless_core_reset(dev, tmp); + + err = b43legacy_phy_versioning(dev); + if (err) + goto err_leds_exit; + /* Check if this device supports multiband. */ + if (!pdev || + (pdev->device != 0x4312 && + pdev->device != 0x4319 && + pdev->device != 0x4324)) { + /* No multiband support. */ + have_bphy = 0; + have_gphy = 0; + switch (dev->phy.type) { + case B43legacy_PHYTYPE_B: + have_bphy = 1; + break; + case B43legacy_PHYTYPE_G: + have_gphy = 1; + break; + default: + B43legacy_BUG_ON(1); + } + } + dev->phy.gmode = (have_gphy || have_bphy); + tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; + b43legacy_wireless_core_reset(dev, tmp); + + err = b43legacy_validate_chipaccess(dev); + if (err) + goto err_leds_exit; + err = b43legacy_setup_modes(dev, have_bphy, have_gphy); + if (err) + goto err_leds_exit; + + /* Now set some default "current_dev" */ + if (!wl->current_dev) + wl->current_dev = dev; + INIT_WORK(&dev->restart_work, b43legacy_chip_reset); + + b43legacy_radio_turn_off(dev); + b43legacy_switch_analog(dev, 0); + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); + +out: + return err; + +err_leds_exit: + b43legacy_leds_exit(dev); +err_powerdown: + ssb_bus_may_powerdown(bus); + return err; +} + +static void b43legacy_one_core_detach(struct ssb_device *dev) +{ + struct b43legacy_wldev *wldev; + struct b43legacy_wl *wl; + + wldev = ssb_get_drvdata(dev); + wl = wldev->wl; + cancel_work_sync(&wldev->restart_work); + b43legacy_debugfs_remove_device(wldev); + b43legacy_wireless_core_detach(wldev); + list_del(&wldev->list); + wl->nr_devs--; + ssb_set_drvdata(dev, NULL); + kfree(wldev); +} + +static int b43legacy_one_core_attach(struct ssb_device *dev, + struct b43legacy_wl *wl) +{ + struct b43legacy_wldev *wldev; + struct pci_dev *pdev; + int err = -ENOMEM; + + if (!list_empty(&wl->devlist)) { + /* We are not the first core on this chip. */ + pdev = dev->bus->host_pci; + /* Only special chips support more than one wireless + * core, although some of the other chips have more than + * one wireless core as well. Check for this and + * bail out early. + */ + if (!pdev || + ((pdev->device != 0x4321) && + (pdev->device != 0x4313) && + (pdev->device != 0x431A))) { + b43legacydbg(wl, "Ignoring unconnected 802.11 core\n"); + return -ENODEV; + } + } + + wldev = kzalloc(sizeof(*wldev), GFP_KERNEL); + if (!wldev) + goto out; + + wldev->dev = dev; + wldev->wl = wl; + b43legacy_set_status(wldev, B43legacy_STAT_UNINIT); + wldev->bad_frames_preempt = modparam_bad_frames_preempt; + tasklet_init(&wldev->isr_tasklet, + (void (*)(unsigned long))b43legacy_interrupt_tasklet, + (unsigned long)wldev); + if (modparam_pio) + wldev->__using_pio = 1; + INIT_LIST_HEAD(&wldev->list); + + err = b43legacy_wireless_core_attach(wldev); + if (err) + goto err_kfree_wldev; + + list_add(&wldev->list, &wl->devlist); + wl->nr_devs++; + ssb_set_drvdata(dev, wldev); + b43legacy_debugfs_add_device(wldev); +out: + return err; + +err_kfree_wldev: + kfree(wldev); + return err; +} + +static void b43legacy_sprom_fixup(struct ssb_bus *bus) +{ + /* boardflags workarounds */ + if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && + bus->boardinfo.type == 0x4E && + bus->boardinfo.rev > 0x40) + bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL; + + /* Convert Antennagain values to Q5.2 */ + if (bus->sprom.r1.antenna_gain_bg == 0xFF) + bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */ + bus->sprom.r1.antenna_gain_bg <<= 2; +} + +static void b43legacy_wireless_exit(struct ssb_device *dev, + struct b43legacy_wl *wl) +{ + struct ieee80211_hw *hw = wl->hw; + + ssb_set_devtypedata(dev, NULL); + ieee80211_free_hw(hw); +} + +static int b43legacy_wireless_init(struct ssb_device *dev) +{ + struct ssb_sprom *sprom = &dev->bus->sprom; + struct ieee80211_hw *hw; + struct b43legacy_wl *wl; + int err = -ENOMEM; + + b43legacy_sprom_fixup(dev->bus); + + hw = ieee80211_alloc_hw(sizeof(*wl), &b43legacy_hw_ops); + if (!hw) { + b43legacyerr(NULL, "Could not allocate ieee80211 device\n"); + goto out; + } + + /* fill hw info */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_RX_INCLUDES_FCS; + hw->max_signal = 100; + hw->max_rssi = -110; + hw->max_noise = -110; + hw->queues = 1; /* FIXME: hardware has more queues */ + SET_IEEE80211_DEV(hw, dev->dev); + if (is_valid_ether_addr(sprom->r1.et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + else + SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + + /* Get and initialize struct b43legacy_wl */ + wl = hw_to_b43legacy_wl(hw); + memset(wl, 0, sizeof(*wl)); + wl->hw = hw; + spin_lock_init(&wl->irq_lock); + spin_lock_init(&wl->leds_lock); + mutex_init(&wl->mutex); + INIT_LIST_HEAD(&wl->devlist); + + ssb_set_devtypedata(dev, wl); + b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); + err = 0; +out: + return err; +} + +static int b43legacy_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + struct b43legacy_wl *wl; + int err; + int first = 0; + + wl = ssb_get_devtypedata(dev); + if (!wl) { + /* Probing the first core - setup common struct b43legacy_wl */ + first = 1; + err = b43legacy_wireless_init(dev); + if (err) + goto out; + wl = ssb_get_devtypedata(dev); + B43legacy_WARN_ON(!wl); + } + err = b43legacy_one_core_attach(dev, wl); + if (err) + goto err_wireless_exit; + + if (first) { + err = ieee80211_register_hw(wl->hw); + if (err) + goto err_one_core_detach; + } + +out: + return err; + +err_one_core_detach: + b43legacy_one_core_detach(dev); +err_wireless_exit: + if (first) + b43legacy_wireless_exit(dev, wl); + return err; +} + +static void b43legacy_remove(struct ssb_device *dev) +{ + struct b43legacy_wl *wl = ssb_get_devtypedata(dev); + struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); + + B43legacy_WARN_ON(!wl); + if (wl->current_dev == wldev) + ieee80211_unregister_hw(wl->hw); + + b43legacy_one_core_detach(dev); + + if (list_empty(&wl->devlist)) + /* Last core on the chip unregistered. + * We can destroy common struct b43legacy_wl. + */ + b43legacy_wireless_exit(dev, wl); +} + +/* Perform a hardware reset. This can be called from any context. */ +void b43legacy_controller_restart(struct b43legacy_wldev *dev, + const char *reason) +{ + /* Must avoid requeueing, if we are in shutdown. */ + 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); +} + +#ifdef CONFIG_PM + +static int b43legacy_suspend(struct ssb_device *dev, pm_message_t state) +{ + struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); + struct b43legacy_wl *wl = wldev->wl; + + b43legacydbg(wl, "Suspending...\n"); + + mutex_lock(&wl->mutex); + wldev->suspend_init_status = b43legacy_status(wldev); + if (wldev->suspend_init_status >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(wldev); + if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED) + b43legacy_wireless_core_exit(wldev); + mutex_unlock(&wl->mutex); + + b43legacydbg(wl, "Device suspended.\n"); + + return 0; +} + +static int b43legacy_resume(struct ssb_device *dev) +{ + struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); + struct b43legacy_wl *wl = wldev->wl; + int err = 0; + + b43legacydbg(wl, "Resuming...\n"); + + mutex_lock(&wl->mutex); + if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(wldev); + if (err) { + b43legacyerr(wl, "Resume failed at core init\n"); + goto out; + } + } + if (wldev->suspend_init_status >= B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(wldev); + if (err) { + b43legacy_wireless_core_exit(wldev); + b43legacyerr(wl, "Resume failed at core start\n"); + goto out; + } + } + mutex_unlock(&wl->mutex); + + b43legacydbg(wl, "Device resumed.\n"); +out: + return err; +} + +#else /* CONFIG_PM */ +# define b43legacy_suspend NULL +# define b43legacy_resume NULL +#endif /* CONFIG_PM */ + +static struct ssb_driver b43legacy_ssb_driver = { + .name = KBUILD_MODNAME, + .id_table = b43legacy_ssb_tbl, + .probe = b43legacy_probe, + .remove = b43legacy_remove, + .suspend = b43legacy_suspend, + .resume = b43legacy_resume, +}; + +static int __init b43legacy_init(void) +{ + int err; + + b43legacy_debugfs_init(); + + err = ssb_driver_register(&b43legacy_ssb_driver); + if (err) + goto err_dfs_exit; + + return err; + +err_dfs_exit: + b43legacy_debugfs_exit(); + return err; +} + +static void __exit b43legacy_exit(void) +{ + ssb_driver_unregister(&b43legacy_ssb_driver); + b43legacy_debugfs_exit(); +} + +module_init(b43legacy_init) +module_exit(b43legacy_exit) diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h new file mode 100644 index 000000000000..673935e67e64 --- /dev/null +++ b/drivers/net/wireless/b43legacy/main.h @@ -0,0 +1,147 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005 Stefano Brivio + Copyright (c) 2005, 2006 Michael Buesch + Copyright (c) 2005 Danny van Dyk + Copyright (c) 2005 Andreas Jaggi + Copyright (c) 2007 Larry Finger + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43legacy_MAIN_H_ +#define B43legacy_MAIN_H_ + +#include "b43legacy.h" + + +#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] +#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) +/* Magic helper macro to pad structures. Ignore those above. It's magic. */ +#define PAD_BYTES(nr_bytes) P4D_BYTES(__LINE__ , (nr_bytes)) + + +/* Lightweight function to convert a frequency (in Mhz) to a channel number. */ +static inline +u8 b43legacy_freq_to_channel_bg(int freq) +{ + u8 channel; + + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; + + return channel; +} +static inline +u8 b43legacy_freq_to_channel(struct b43legacy_wldev *dev, + int freq) +{ + return b43legacy_freq_to_channel_bg(freq); +} + +/* Lightweight function to convert a channel number to a frequency (in Mhz). */ +static inline +int b43legacy_channel_to_freq_bg(u8 channel) +{ + int freq; + + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); + + return freq; +} + +static inline +int b43legacy_channel_to_freq(struct b43legacy_wldev *dev, + u8 channel) +{ + return b43legacy_channel_to_freq_bg(channel); +} + +static inline +int b43legacy_is_cck_rate(int rate) +{ + return (rate == B43legacy_CCK_RATE_1MB || + rate == B43legacy_CCK_RATE_2MB || + rate == B43legacy_CCK_RATE_5MB || + rate == B43legacy_CCK_RATE_11MB); +} + +static inline +int b43legacy_is_ofdm_rate(int rate) +{ + return !b43legacy_is_cck_rate(rate); +} + +static inline +int b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +{ + /* function to return state of hardware enable of radio + * returns 0 if radio disabled, 1 if radio enabled + */ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->rev >= 3) + return ((b43legacy_read32(dev, + B43legacy_MMIO_RADIO_HWENABLED_HI) + & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK) + == 0) ? 1 : 0; + else + return ((b43legacy_read16(dev, + B43legacy_MMIO_RADIO_HWENABLED_LO) + & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) + == 0) ? 0 : 1; +} + +void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf); +void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf); + +u32 b43legacy_shm_read32(struct b43legacy_wldev *dev, + u16 routing, u16 offset); +u16 b43legacy_shm_read16(struct b43legacy_wldev *dev, + u16 routing, u16 offset); +void b43legacy_shm_write32(struct b43legacy_wldev *dev, + u16 routing, u16 offset, + u32 value); +void b43legacy_shm_write16(struct b43legacy_wldev *dev, + u16 routing, u16 offset, + u16 value); + +u32 b43legacy_hf_read(struct b43legacy_wldev *dev); +void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value); + +void b43legacy_dummy_transmission(struct b43legacy_wldev *dev); + +void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags); + +void b43legacy_mac_suspend(struct b43legacy_wldev *dev); +void b43legacy_mac_enable(struct b43legacy_wldev *dev); + +void b43legacy_controller_restart(struct b43legacy_wldev *dev, + const char *reason); + +#endif /* B43legacy_MAIN_H_ */ diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c new file mode 100644 index 000000000000..f9edbd5f3009 --- /dev/null +++ b/drivers/net/wireless/b43legacy/phy.c @@ -0,0 +1,2265 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + Copyright (c) 2007 Larry Finger + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include + +#include "b43legacy.h" +#include "phy.h" +#include "main.h" +#include "radio.h" +#include "ilt.h" + + +static const s8 b43legacy_tssi2dbm_b_table[] = { + 0x4D, 0x4C, 0x4B, 0x4A, + 0x4A, 0x49, 0x48, 0x47, + 0x47, 0x46, 0x45, 0x45, + 0x44, 0x43, 0x42, 0x42, + 0x41, 0x40, 0x3F, 0x3E, + 0x3D, 0x3C, 0x3B, 0x3A, + 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x32, 0x31, + 0x30, 0x2F, 0x2D, 0x2C, + 0x2B, 0x29, 0x28, 0x26, + 0x25, 0x23, 0x21, 0x1F, + 0x1D, 0x1A, 0x17, 0x14, + 0x10, 0x0C, 0x06, 0x00, + -7, -7, -7, -7, + -7, -7, -7, -7, + -7, -7, -7, -7, +}; + +static const s8 b43legacy_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +static void b43legacy_phy_initg(struct b43legacy_wldev *dev); + + +static inline +void b43legacy_voluntary_preempt(void) +{ + B43legacy_BUG_ON(!(!in_atomic() && !in_irq() && + !in_interrupt() && !irqs_disabled())); +#ifndef CONFIG_PREEMPT + cond_resched(); +#endif /* CONFIG_PREEMPT */ +} + +void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + B43legacy_WARN_ON(!irqs_disabled()); + if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) { + phy->locked = 0; + return; + } + if (dev->dev->id.revision < 3) { + b43legacy_mac_suspend(dev); + spin_lock(&phy->lock); + } else { + if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43legacy_power_saving_ctl_bits(dev, -1, 1); + } + phy->locked = 1; +} + +void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + B43legacy_WARN_ON(!irqs_disabled()); + if (dev->dev->id.revision < 3) { + if (phy->locked) { + spin_unlock(&phy->lock); + b43legacy_mac_enable(dev); + } + } else { + if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43legacy_power_saving_ctl_bits(dev, -1, -1); + } + phy->locked = 0; +} + +u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset) +{ + b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset); + return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA); +} + +void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val) +{ + b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val); +} + +void b43legacy_phy_calibrate(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */ + if (phy->calibrated) + return; + if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) { + b43legacy_wireless_core_reset(dev, 0); + b43legacy_phy_initg(dev); + b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE); + } + phy->calibrated = 1; +} + +/* intialize B PHY power control + * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + */ +static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 saved_batt = 0; + u16 saved_ratt = 0; + u16 saved_txctl1 = 0; + int must_reset_txpower = 0; + + B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B || + phy->type == B43legacy_PHYTYPE_G)); + if (is_bcm_board_vendor(dev) && + (dev->dev->bus->boardinfo.type == 0x0416)) + return; + + b43legacy_phy_write(dev, 0x0028, 0x8018); + b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF); + + if (phy->type == B43legacy_PHYTYPE_G) { + if (!phy->gmode) + return; + b43legacy_phy_write(dev, 0x047A, 0xC111); + } + if (phy->savedpctlreg != 0xFFFF) + return; +#ifdef CONFIG_B43LEGACY_DEBUG + if (phy->manual_txpower_control) + return; +#endif + + if (phy->type == B43legacy_PHYTYPE_B && + phy->rev >= 2 && + phy->radio_ver == 0x2050) + b43legacy_radio_write16(dev, 0x0076, + b43legacy_radio_read16(dev, 0x0076) + | 0x0084); + else { + saved_batt = phy->bbatt; + saved_ratt = phy->rfatt; + saved_txctl1 = phy->txctl1; + if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8) + && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) + b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0); + else + b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0); + must_reset_txpower = 1; + } + b43legacy_dummy_transmission(dev); + + phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL); + + if (must_reset_txpower) + b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt, + saved_txctl1); + else + b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev, + 0x0076) & 0xFF7B); + b43legacy_radio_clear_tssi(dev); +} + +static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset = 0x0000; + + if (phy->rev == 1) + offset = 0x4C00; + + b43legacy_ilt_write(dev, offset, 0x00FE); + b43legacy_ilt_write(dev, offset + 1, 0x000D); + b43legacy_ilt_write(dev, offset + 2, 0x0013); + b43legacy_ilt_write(dev, offset + 3, 0x0019); + + if (phy->rev == 1) { + b43legacy_ilt_write(dev, 0x1800, 0x2710); + b43legacy_ilt_write(dev, 0x1801, 0x9B83); + b43legacy_ilt_write(dev, 0x1802, 0x9B83); + b43legacy_ilt_write(dev, 0x1803, 0x0F8D); + b43legacy_phy_write(dev, 0x0455, 0x0004); + } + + b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5) + & 0x00FF) | 0x5700); + b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A) + & 0xFF80) | 0x000F); + b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A) + & 0xC07F) | 0x2B80); + b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0300); + + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0008); + + b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0) + & 0xFFF0) | 0x0008); + b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1) + & 0xF0FF) | 0x0600); + b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0700); + b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0100); + + if (phy->rev == 1) + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x0007); + + b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488) + & 0xFF00) | 0x001C); + b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488) + & 0xC0FF) | 0x0200); + b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496) + & 0xFF00) | 0x001C); + b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489) + & 0xFF00) | 0x0020); + b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489) + & 0xC0FF) | 0x0200); + b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482) + & 0xFF00) | 0x002E); + b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496) + & 0x00FF) | 0x1A00); + b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481) + & 0xFF00) | 0x0028); + b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481) + & 0x00FF) | 0x2C00); + + if (phy->rev == 1) { + b43legacy_phy_write(dev, 0x0430, 0x092B); + b43legacy_phy_write(dev, 0x041B, + (b43legacy_phy_read(dev, 0x041B) + & 0xFFE1) | 0x0002); + } else { + b43legacy_phy_write(dev, 0x041B, + b43legacy_phy_read(dev, 0x041B) & 0xFFE1); + b43legacy_phy_write(dev, 0x041F, 0x287A); + b43legacy_phy_write(dev, 0x0420, + (b43legacy_phy_read(dev, 0x0420) + & 0xFFF0) | 0x0004); + } + + if (phy->rev > 2) { + b43legacy_phy_write(dev, 0x0422, 0x287A); + b43legacy_phy_write(dev, 0x0420, + (b43legacy_phy_read(dev, 0x0420) + & 0x0FFF) | 0x3000); + } + + b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8) + & 0x8080) | 0x7874); + b43legacy_phy_write(dev, 0x048E, 0x1C00); + + if (phy->rev == 1) { + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0600); + b43legacy_phy_write(dev, 0x048B, 0x005E); + b43legacy_phy_write(dev, 0x048C, + (b43legacy_phy_read(dev, 0x048C) & 0xFF00) + | 0x001E); + b43legacy_phy_write(dev, 0x048D, 0x0002); + } + + b43legacy_ilt_write(dev, offset + 0x0800, 0); + b43legacy_ilt_write(dev, offset + 0x0801, 7); + b43legacy_ilt_write(dev, offset + 0x0802, 16); + b43legacy_ilt_write(dev, offset + 0x0803, 28); + + if (phy->rev >= 6) { + b43legacy_phy_write(dev, 0x0426, + (b43legacy_phy_read(dev, 0x0426) & 0xFFFC)); + b43legacy_phy_write(dev, 0x0426, + (b43legacy_phy_read(dev, 0x0426) & 0xEFFF)); + } +} + +static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 i; + + B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G); + if (phy->rev == 1) { + b43legacy_phy_write(dev, 0x0406, 0x4F19); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + (b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340); + b43legacy_phy_write(dev, 0x042C, 0x005A); + b43legacy_phy_write(dev, 0x0427, 0x001A); + + for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++) + b43legacy_ilt_write(dev, 0x5800 + i, + b43legacy_ilt_finefreqg[i]); + for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++) + b43legacy_ilt_write(dev, 0x1800 + i, + b43legacy_ilt_noiseg1[i]); + for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++) + b43legacy_ilt_write32(dev, 0x2000 + i, + b43legacy_ilt_rotor[i]); + } else { + /* nrssi values are signed 6-bit values. Why 0x7654 here? */ + b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654); + + if (phy->rev == 2) { + b43legacy_phy_write(dev, 0x04C0, 0x1861); + b43legacy_phy_write(dev, 0x04C1, 0x0271); + } else if (phy->rev > 2) { + b43legacy_phy_write(dev, 0x04C0, 0x0098); + b43legacy_phy_write(dev, 0x04C1, 0x0070); + b43legacy_phy_write(dev, 0x04C9, 0x0080); + } + b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, + 0x042B) | 0x800); + + for (i = 0; i < 64; i++) + b43legacy_ilt_write(dev, 0x4000 + i, i); + for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++) + b43legacy_ilt_write(dev, 0x1800 + i, + b43legacy_ilt_noiseg2[i]); + } + + if (phy->rev <= 2) + for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) + b43legacy_ilt_write(dev, 0x1400 + i, + b43legacy_ilt_noisescaleg1[i]); + else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200)) + for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) + b43legacy_ilt_write(dev, 0x1400 + i, + b43legacy_ilt_noisescaleg3[i]); + else + for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) + b43legacy_ilt_write(dev, 0x1400 + i, + b43legacy_ilt_noisescaleg2[i]); + + if (phy->rev == 2) + for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++) + b43legacy_ilt_write(dev, 0x5000 + i, + b43legacy_ilt_sigmasqr1[i]); + else if ((phy->rev > 2) && (phy->rev <= 8)) + for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++) + b43legacy_ilt_write(dev, 0x5000 + i, + b43legacy_ilt_sigmasqr2[i]); + + if (phy->rev == 1) { + for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++) + b43legacy_ilt_write32(dev, 0x2400 + i, + b43legacy_ilt_retard[i]); + for (i = 4; i < 20; i++) + b43legacy_ilt_write(dev, 0x5400 + i, 0x0020); + b43legacy_phy_agcsetup(dev); + + if (is_bcm_board_vendor(dev) && + (dev->dev->bus->boardinfo.type == 0x0416) && + (dev->dev->bus->boardinfo.rev == 0x0017)) + return; + + b43legacy_ilt_write(dev, 0x5001, 0x0002); + b43legacy_ilt_write(dev, 0x5002, 0x0001); + } else { + for (i = 0; i <= 0x20; i++) + b43legacy_ilt_write(dev, 0x1000 + i, 0x0820); + b43legacy_phy_agcsetup(dev); + b43legacy_phy_read(dev, 0x0400); /* dummy read */ + b43legacy_phy_write(dev, 0x0403, 0x1000); + b43legacy_ilt_write(dev, 0x3C02, 0x000F); + b43legacy_ilt_write(dev, 0x3C03, 0x0014); + + if (is_bcm_board_vendor(dev) && + (dev->dev->bus->boardinfo.type == 0x0416) && + (dev->dev->bus->boardinfo.rev == 0x0017)) + return; + + b43legacy_ilt_write(dev, 0x0401, 0x0002); + b43legacy_ilt_write(dev, 0x0402, 0x0001); + } +} + +/* Initialize the APHY portion of a GPHY. */ +static void b43legacy_phy_inita(struct b43legacy_wldev *dev) +{ + + might_sleep(); + + b43legacy_phy_setupg(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) + b43legacy_phy_write(dev, 0x046E, 0x03CF); +} + +static void b43legacy_phy_initb2(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset; + int val; + + b43legacy_write16(dev, 0x03EC, 0x3F22); + b43legacy_phy_write(dev, 0x0020, 0x301C); + b43legacy_phy_write(dev, 0x0026, 0x0000); + b43legacy_phy_write(dev, 0x0030, 0x00C6); + b43legacy_phy_write(dev, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + b43legacy_phy_write(dev, offset, val); + val -= 0x0202; + } + b43legacy_phy_write(dev, 0x03E4, 0x3000); + if (phy->channel == 0xFF) + b43legacy_radio_selectchannel(dev, + B43legacy_RADIO_DEFAULT_CHANNEL_BG, + 0); + else + b43legacy_radio_selectchannel(dev, phy->channel, 0); + if (phy->radio_ver != 0x2050) { + b43legacy_radio_write16(dev, 0x0075, 0x0080); + b43legacy_radio_write16(dev, 0x0079, 0x0081); + } + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0023); + if (phy->radio_ver == 0x2050) { + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x005A, 0x0070); + b43legacy_radio_write16(dev, 0x005B, 0x007B); + b43legacy_radio_write16(dev, 0x005C, 0x00B0); + b43legacy_radio_write16(dev, 0x007A, 0x000F); + b43legacy_phy_write(dev, 0x0038, 0x0677); + b43legacy_radio_init2050(dev); + } + b43legacy_phy_write(dev, 0x0014, 0x0080); + b43legacy_phy_write(dev, 0x0032, 0x00CA); + b43legacy_phy_write(dev, 0x0032, 0x00CC); + b43legacy_phy_write(dev, 0x0035, 0x07C2); + b43legacy_phy_lo_b_measure(dev); + b43legacy_phy_write(dev, 0x0026, 0xCC00); + if (phy->radio_ver != 0x2050) + b43legacy_phy_write(dev, 0x0026, 0xCE00); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000); + b43legacy_phy_write(dev, 0x002A, 0x88A3); + if (phy->radio_ver != 0x2050) + b43legacy_phy_write(dev, 0x002A, 0x88C2); + b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + b43legacy_phy_init_pctl(dev); +} + +static void b43legacy_phy_initb4(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset; + u16 val; + + b43legacy_write16(dev, 0x03EC, 0x3F22); + b43legacy_phy_write(dev, 0x0020, 0x301C); + b43legacy_phy_write(dev, 0x0026, 0x0000); + b43legacy_phy_write(dev, 0x0030, 0x00C6); + b43legacy_phy_write(dev, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + b43legacy_phy_write(dev, offset, val); + val -= 0x0202; + } + b43legacy_phy_write(dev, 0x03E4, 0x3000); + if (phy->channel == 0xFF) + b43legacy_radio_selectchannel(dev, + B43legacy_RADIO_DEFAULT_CHANNEL_BG, + 0); + else + b43legacy_radio_selectchannel(dev, phy->channel, 0); + if (phy->radio_ver != 0x2050) { + b43legacy_radio_write16(dev, 0x0075, 0x0080); + b43legacy_radio_write16(dev, 0x0079, 0x0081); + } + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0023); + if (phy->radio_ver == 0x2050) { + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x005A, 0x0070); + b43legacy_radio_write16(dev, 0x005B, 0x007B); + b43legacy_radio_write16(dev, 0x005C, 0x00B0); + b43legacy_radio_write16(dev, 0x007A, 0x000F); + b43legacy_phy_write(dev, 0x0038, 0x0677); + b43legacy_radio_init2050(dev); + } + b43legacy_phy_write(dev, 0x0014, 0x0080); + b43legacy_phy_write(dev, 0x0032, 0x00CA); + if (phy->radio_ver == 0x2050) + b43legacy_phy_write(dev, 0x0032, 0x00E0); + b43legacy_phy_write(dev, 0x0035, 0x07C2); + + b43legacy_phy_lo_b_measure(dev); + + b43legacy_phy_write(dev, 0x0026, 0xCC00); + if (phy->radio_ver == 0x2050) + b43legacy_phy_write(dev, 0x0026, 0xCE00); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100); + b43legacy_phy_write(dev, 0x002A, 0x88A3); + if (phy->radio_ver == 0x2050) + b43legacy_phy_write(dev, 0x002A, 0x88C2); + b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + b43legacy_calc_nrssi_slope(dev); + b43legacy_calc_nrssi_threshold(dev); + } + b43legacy_phy_init_pctl(dev); +} + +static void b43legacy_phy_initb5(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset; + u16 value; + u8 old_channel; + + if (phy->analog == 1) + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0050); + if (!is_bcm_board_vendor(dev) && + (dev->dev->bus->boardinfo.type != 0x0416)) { + value = 0x2120; + for (offset = 0x00A8 ; offset < 0x00C7; offset++) { + b43legacy_phy_write(dev, offset, value); + value += 0x0202; + } + } + b43legacy_phy_write(dev, 0x0035, + (b43legacy_phy_read(dev, 0x0035) & 0xF0FF) + | 0x0700); + if (phy->radio_ver == 0x2050) + b43legacy_phy_write(dev, 0x0038, 0x0667); + + if (phy->gmode) { + if (phy->radio_ver == 0x2050) { + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0020); + b43legacy_radio_write16(dev, 0x0051, + b43legacy_radio_read16(dev, 0x0051) + | 0x0004); + } + b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000); + + b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802) + | 0x0100); + b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B) + | 0x2000); + + b43legacy_phy_write(dev, 0x001C, 0x186A); + + b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev, + 0x0013) & 0x00FF) | 0x1900); + b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev, + 0x0035) & 0xFFC0) | 0x0064); + b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, + 0x005D) & 0xFF80) | 0x000A); + } + + if (dev->bad_frames_preempt) + b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, + b43legacy_phy_read(dev, + B43legacy_PHY_RADIO_BITFIELD) | (1 << 11)); + + if (phy->analog == 1) { + b43legacy_phy_write(dev, 0x0026, 0xCE00); + b43legacy_phy_write(dev, 0x0021, 0x3763); + b43legacy_phy_write(dev, 0x0022, 0x1BC3); + b43legacy_phy_write(dev, 0x0023, 0x06F9); + b43legacy_phy_write(dev, 0x0024, 0x037E); + } else + b43legacy_phy_write(dev, 0x0026, 0xCC00); + b43legacy_phy_write(dev, 0x0030, 0x00C6); + b43legacy_write16(dev, 0x03EC, 0x3F22); + + if (phy->analog == 1) + b43legacy_phy_write(dev, 0x0020, 0x3E1C); + else + b43legacy_phy_write(dev, 0x0020, 0x301C); + + if (phy->analog == 0) + b43legacy_write16(dev, 0x03E4, 0x3000); + + old_channel = (phy->channel == 0xFF) ? 1 : phy->channel; + /* Force to channel 7, even if not supported. */ + b43legacy_radio_selectchannel(dev, 7, 0); + + if (phy->radio_ver != 0x2050) { + b43legacy_radio_write16(dev, 0x0075, 0x0080); + b43legacy_radio_write16(dev, 0x0079, 0x0081); + } + + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0023); + + if (phy->radio_ver == 0x2050) { + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x005A, 0x0070); + } + + b43legacy_radio_write16(dev, 0x005B, 0x007B); + b43legacy_radio_write16(dev, 0x005C, 0x00B0); + + b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev, + 0x007A) | 0x0007); + + b43legacy_radio_selectchannel(dev, old_channel, 0); + + b43legacy_phy_write(dev, 0x0014, 0x0080); + b43legacy_phy_write(dev, 0x0032, 0x00CA); + b43legacy_phy_write(dev, 0x002A, 0x88A3); + + b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + + if (phy->radio_ver == 0x2050) + b43legacy_radio_write16(dev, 0x005D, 0x000D); + + b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) & + 0xFFC0) | 0x0004); +} + +static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset; + u16 val; + u8 old_channel; + + b43legacy_phy_write(dev, 0x003E, 0x817A); + b43legacy_radio_write16(dev, 0x007A, + (b43legacy_radio_read16(dev, 0x007A) | 0x0058)); + if (phy->radio_rev == 4 || + phy->radio_rev == 5) { + b43legacy_radio_write16(dev, 0x0051, 0x0037); + b43legacy_radio_write16(dev, 0x0052, 0x0070); + b43legacy_radio_write16(dev, 0x0053, 0x00B3); + b43legacy_radio_write16(dev, 0x0054, 0x009B); + b43legacy_radio_write16(dev, 0x005A, 0x0088); + b43legacy_radio_write16(dev, 0x005B, 0x0088); + b43legacy_radio_write16(dev, 0x005D, 0x0088); + b43legacy_radio_write16(dev, 0x005E, 0x0088); + b43legacy_radio_write16(dev, 0x007D, 0x0088); + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + (b43legacy_shm_read32(dev, + B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET) + | 0x00000200)); + } + if (phy->radio_rev == 8) { + b43legacy_radio_write16(dev, 0x0051, 0x0000); + b43legacy_radio_write16(dev, 0x0052, 0x0040); + b43legacy_radio_write16(dev, 0x0053, 0x00B7); + b43legacy_radio_write16(dev, 0x0054, 0x0098); + b43legacy_radio_write16(dev, 0x005A, 0x0088); + b43legacy_radio_write16(dev, 0x005B, 0x006B); + b43legacy_radio_write16(dev, 0x005C, 0x000F); + if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) { + b43legacy_radio_write16(dev, 0x005D, 0x00FA); + b43legacy_radio_write16(dev, 0x005E, 0x00D8); + } else { + b43legacy_radio_write16(dev, 0x005D, 0x00F5); + b43legacy_radio_write16(dev, 0x005E, 0x00B8); + } + b43legacy_radio_write16(dev, 0x0073, 0x0003); + b43legacy_radio_write16(dev, 0x007D, 0x00A8); + b43legacy_radio_write16(dev, 0x007C, 0x0001); + b43legacy_radio_write16(dev, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + b43legacy_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + b43legacy_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + b43legacy_phy_write(dev, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == B43legacy_PHYTYPE_G) { + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) | + 0x0020); + b43legacy_radio_write16(dev, 0x0051, + b43legacy_radio_read16(dev, 0x0051) | + 0x0004); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) | 0x0100); + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) | 0x2000); + b43legacy_phy_write(dev, 0x5B, 0x0000); + b43legacy_phy_write(dev, 0x5C, 0x0000); + } + + old_channel = phy->channel; + if (old_channel >= 8) + b43legacy_radio_selectchannel(dev, 1, 0); + else + b43legacy_radio_selectchannel(dev, 13, 0); + + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0023); + udelay(40); + if (phy->radio_rev < 6 || phy->radio_rev == 8) { + b43legacy_radio_write16(dev, 0x007C, + (b43legacy_radio_read16(dev, 0x007C) + | 0x0002)); + b43legacy_radio_write16(dev, 0x0050, 0x0020); + } + if (phy->radio_rev <= 2) { + b43legacy_radio_write16(dev, 0x007C, 0x0020); + b43legacy_radio_write16(dev, 0x005A, 0x0070); + b43legacy_radio_write16(dev, 0x005B, 0x007B); + b43legacy_radio_write16(dev, 0x005C, 0x00B0); + } + b43legacy_radio_write16(dev, 0x007A, + (b43legacy_radio_read16(dev, + 0x007A) & 0x00F8) | 0x0007); + + b43legacy_radio_selectchannel(dev, old_channel, 0); + + b43legacy_phy_write(dev, 0x0014, 0x0200); + if (phy->radio_rev >= 6) + b43legacy_phy_write(dev, 0x002A, 0x88C2); + else + b43legacy_phy_write(dev, 0x002A, 0x8AC0); + b43legacy_phy_write(dev, 0x0038, 0x0668); + b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + if (phy->radio_rev <= 5) + b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, + 0x005D) & 0xFF80) | 0x0003); + if (phy->radio_rev <= 2) + b43legacy_radio_write16(dev, 0x005D, 0x000D); + + if (phy->analog == 4) { + b43legacy_write16(dev, 0x03E4, 0x0009); + b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61) + & 0xFFF); + } else + b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev, + 0x0002) & 0xFFC0) | 0x0004); + if (phy->type == B43legacy_PHYTYPE_G) + b43legacy_write16(dev, 0x03E6, 0x0); + if (phy->type == B43legacy_PHYTYPE_B) { + b43legacy_write16(dev, 0x03E6, 0x8140); + b43legacy_phy_write(dev, 0x0016, 0x0410); + b43legacy_phy_write(dev, 0x0017, 0x0820); + b43legacy_phy_write(dev, 0x0062, 0x0007); + b43legacy_radio_init2050(dev); + b43legacy_phy_lo_g_measure(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & + B43legacy_BFL_RSSI) { + b43legacy_calc_nrssi_slope(dev); + b43legacy_calc_nrssi_threshold(dev); + } + b43legacy_phy_init_pctl(dev); + } +} + +static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 backup_phy[15] = {0}; + u16 backup_radio[3]; + u16 backup_bband; + u16 i; + u16 loop1_cnt; + u16 loop1_done; + u16 loop1_omitted; + u16 loop2_done; + + backup_phy[0] = b43legacy_phy_read(dev, 0x0429); + backup_phy[1] = b43legacy_phy_read(dev, 0x0001); + backup_phy[2] = b43legacy_phy_read(dev, 0x0811); + backup_phy[3] = b43legacy_phy_read(dev, 0x0812); + if (phy->rev != 1) { + backup_phy[4] = b43legacy_phy_read(dev, 0x0814); + backup_phy[5] = b43legacy_phy_read(dev, 0x0815); + } + backup_phy[6] = b43legacy_phy_read(dev, 0x005A); + backup_phy[7] = b43legacy_phy_read(dev, 0x0059); + backup_phy[8] = b43legacy_phy_read(dev, 0x0058); + backup_phy[9] = b43legacy_phy_read(dev, 0x000A); + backup_phy[10] = b43legacy_phy_read(dev, 0x0003); + backup_phy[11] = b43legacy_phy_read(dev, 0x080F); + backup_phy[12] = b43legacy_phy_read(dev, 0x0810); + backup_phy[13] = b43legacy_phy_read(dev, 0x002B); + backup_phy[14] = b43legacy_phy_read(dev, 0x0015); + b43legacy_phy_read(dev, 0x002D); /* dummy read */ + backup_bband = phy->bbatt; + backup_radio[0] = b43legacy_radio_read16(dev, 0x0052); + backup_radio[1] = b43legacy_radio_read16(dev, 0x0043); + backup_radio[2] = b43legacy_radio_read16(dev, 0x007A); + + b43legacy_phy_write(dev, 0x0429, + b43legacy_phy_read(dev, 0x0429) & 0x3FFF); + b43legacy_phy_write(dev, 0x0001, + b43legacy_phy_read(dev, 0x0001) & 0x8000); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x0002); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) & 0xFFFD); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x0001); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) & 0xFFFE); + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0001); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFE); + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0002); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFD); + } + b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) | + 0x000C); + b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) | + 0x000C); + + b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811) + & 0xFFCF) | 0x0030); + b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812) + & 0xFFCF) | 0x0010); + + b43legacy_phy_write(dev, 0x005A, 0x0780); + b43legacy_phy_write(dev, 0x0059, 0xC810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + if (phy->analog == 0) + b43legacy_phy_write(dev, 0x0003, 0x0122); + else + b43legacy_phy_write(dev, 0x000A, + b43legacy_phy_read(dev, 0x000A) + | 0x2000); + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0004); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFB); + } + b43legacy_phy_write(dev, 0x0003, + (b43legacy_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) { + b43legacy_radio_write16(dev, 0x0052, 0x0000); + b43legacy_radio_write16(dev, 0x0043, + (b43legacy_radio_read16(dev, 0x0043) + & 0xFFF0) | 0x0009); + loop1_cnt = 9; + } else if (phy->radio_rev == 8) { + b43legacy_radio_write16(dev, 0x0043, 0x000F); + loop1_cnt = 15; + } else + loop1_cnt = 0; + + b43legacy_phy_set_baseband_attenuation(dev, 11); + + if (phy->rev >= 3) + b43legacy_phy_write(dev, 0x080F, 0xC020); + else + b43legacy_phy_write(dev, 0x080F, 0x8020); + b43legacy_phy_write(dev, 0x0810, 0x0000); + + b43legacy_phy_write(dev, 0x002B, + (b43legacy_phy_read(dev, 0x002B) + & 0xFFC0) | 0x0001); + b43legacy_phy_write(dev, 0x002B, + (b43legacy_phy_read(dev, 0x002B) + & 0xC0FF) | 0x0800); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x0100); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) & 0xCFFF); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) { + if (phy->rev >= 7) { + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) + | 0x0800); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) + | 0x8000); + } + } + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x00F7); + + for (i = 0; i < loop1_cnt; i++) { + b43legacy_radio_write16(dev, 0x0043, loop1_cnt); + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) + & 0xF0FF) | (i << 8)); + b43legacy_phy_write(dev, 0x0015, + (b43legacy_phy_read(dev, 0x0015) + & 0x0FFF) | 0xA000); + b43legacy_phy_write(dev, 0x0015, + (b43legacy_phy_read(dev, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC) + break; + } + loop1_done = i; + loop1_omitted = loop1_cnt - loop1_done; + + loop2_done = 0; + if (loop1_done >= 8) { + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) + | 0x0030); + for (i = loop1_done - 8; i < 16; i++) { + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) + & 0xF0FF) | (i << 8)); + b43legacy_phy_write(dev, 0x0015, + (b43legacy_phy_read(dev, 0x0015) + & 0x0FFF) | 0xA000); + b43legacy_phy_write(dev, 0x0015, + (b43legacy_phy_read(dev, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC) + break; + } + } + + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x0814, backup_phy[4]); + b43legacy_phy_write(dev, 0x0815, backup_phy[5]); + } + b43legacy_phy_write(dev, 0x005A, backup_phy[6]); + b43legacy_phy_write(dev, 0x0059, backup_phy[7]); + b43legacy_phy_write(dev, 0x0058, backup_phy[8]); + b43legacy_phy_write(dev, 0x000A, backup_phy[9]); + b43legacy_phy_write(dev, 0x0003, backup_phy[10]); + b43legacy_phy_write(dev, 0x080F, backup_phy[11]); + b43legacy_phy_write(dev, 0x0810, backup_phy[12]); + b43legacy_phy_write(dev, 0x002B, backup_phy[13]); + b43legacy_phy_write(dev, 0x0015, backup_phy[14]); + + b43legacy_phy_set_baseband_attenuation(dev, backup_bband); + + b43legacy_radio_write16(dev, 0x0052, backup_radio[0]); + b43legacy_radio_write16(dev, 0x0043, backup_radio[1]); + b43legacy_radio_write16(dev, 0x007A, backup_radio[2]); + + b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003); + udelay(10); + b43legacy_phy_write(dev, 0x0811, backup_phy[2]); + b43legacy_phy_write(dev, 0x0812, backup_phy[3]); + b43legacy_phy_write(dev, 0x0429, backup_phy[0]); + b43legacy_phy_write(dev, 0x0001, backup_phy[1]); + + phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; + phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; +} + +static void b43legacy_phy_initg(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 tmp; + + if (phy->rev == 1) + b43legacy_phy_initb5(dev); + else + b43legacy_phy_initb6(dev); + if (phy->rev >= 2 || phy->gmode) + b43legacy_phy_inita(dev); + + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0814, 0x0000); + b43legacy_phy_write(dev, 0x0815, 0x0000); + } + if (phy->rev == 2) { + b43legacy_phy_write(dev, 0x0811, 0x0000); + b43legacy_phy_write(dev, 0x0015, 0x00C0); + } + if (phy->rev > 5) { + b43legacy_phy_write(dev, 0x0811, 0x0400); + b43legacy_phy_write(dev, 0x0015, 0x00C0); + } + if (phy->rev >= 2 || phy->gmode) { + tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; + if (tmp == 3 || tmp == 5) { + b43legacy_phy_write(dev, 0x04C2, 0x1816); + b43legacy_phy_write(dev, 0x04C3, 0x8006); + if (tmp == 5) + b43legacy_phy_write(dev, 0x04CC, + (b43legacy_phy_read(dev, + 0x04CC) & 0x00FF) | + 0x1F00); + } + b43legacy_phy_write(dev, 0x047E, 0x0078); + } + if (phy->radio_rev == 8) { + b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801) + | 0x0080); + b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E) + | 0x0004); + } + if (phy->rev >= 2 && phy->gmode) + b43legacy_calc_loopback_gain(dev); + if (phy->radio_rev != 8) { + if (phy->initval == 0xFFFF) + phy->initval = b43legacy_radio_init2050(dev); + else + b43legacy_radio_write16(dev, 0x0078, phy->initval); + } + if (phy->txctl2 == 0xFFFF) + b43legacy_phy_lo_g_measure(dev); + else { + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) + b43legacy_radio_write16(dev, 0x0052, + (phy->txctl1 << 4) | + phy->txctl2); + else + b43legacy_radio_write16(dev, 0x0052, + (b43legacy_radio_read16(dev, + 0x0052) & 0xFFF0) | + phy->txctl1); + if (phy->rev >= 6) + b43legacy_phy_write(dev, 0x0036, + (b43legacy_phy_read(dev, 0x0036) + & 0x0FFF) | (phy->txctl2 << 12)); + if (dev->dev->bus->sprom.r1.boardflags_lo & + B43legacy_BFL_PACTRL) + b43legacy_phy_write(dev, 0x002E, 0x8075); + else + b43legacy_phy_write(dev, 0x002E, 0x807F); + if (phy->rev < 2) + b43legacy_phy_write(dev, 0x002F, 0x0101); + else + b43legacy_phy_write(dev, 0x002F, 0x0202); + } + if (phy->gmode || phy->rev >= 2) { + b43legacy_phy_lo_adjust(dev, 0); + b43legacy_phy_write(dev, 0x080F, 0x8078); + } + + if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the limit_value() in nrssi_hw_update()) + */ + b43legacy_nrssi_hw_update(dev, 0xFFFF); + b43legacy_calc_nrssi_threshold(dev); + } else if (phy->gmode || phy->rev >= 2) { + if (phy->nrssi[0] == -1000) { + B43legacy_WARN_ON(phy->nrssi[1] != -1000); + b43legacy_calc_nrssi_slope(dev); + } else { + B43legacy_WARN_ON(phy->nrssi[1] == -1000); + b43legacy_calc_nrssi_threshold(dev); + } + } + if (phy->radio_rev == 8) + b43legacy_phy_write(dev, 0x0805, 0x3230); + b43legacy_phy_init_pctl(dev); + if (dev->dev->bus->chip_id == 0x4306 + && dev->dev->bus->chip_package == 2) { + b43legacy_phy_write(dev, 0x0429, + b43legacy_phy_read(dev, 0x0429) & 0xBFFF); + b43legacy_phy_write(dev, 0x04C3, + b43legacy_phy_read(dev, 0x04C3) & 0x7FFF); + } +} + +static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev) +{ + int i; + u16 ret = 0; + unsigned long flags; + + local_irq_save(flags); + for (i = 0; i < 10; i++) { + b43legacy_phy_write(dev, 0x0015, 0xAFA0); + udelay(1); + b43legacy_phy_write(dev, 0x0015, 0xEFA0); + udelay(10); + b43legacy_phy_write(dev, 0x0015, 0xFFA0); + udelay(40); + ret += b43legacy_phy_read(dev, 0x002C); + } + local_irq_restore(flags); + b43legacy_voluntary_preempt(); + + return ret; +} + +void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 regstack[12] = { 0 }; + u16 mls; + u16 fval; + int i; + int j; + + regstack[0] = b43legacy_phy_read(dev, 0x0015); + regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0; + + if (phy->radio_ver == 0x2053) { + regstack[2] = b43legacy_phy_read(dev, 0x000A); + regstack[3] = b43legacy_phy_read(dev, 0x002A); + regstack[4] = b43legacy_phy_read(dev, 0x0035); + regstack[5] = b43legacy_phy_read(dev, 0x0003); + regstack[6] = b43legacy_phy_read(dev, 0x0001); + regstack[7] = b43legacy_phy_read(dev, 0x0030); + + regstack[8] = b43legacy_radio_read16(dev, 0x0043); + regstack[9] = b43legacy_radio_read16(dev, 0x007A); + regstack[10] = b43legacy_read16(dev, 0x03EC); + regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0; + + b43legacy_phy_write(dev, 0x0030, 0x00FF); + b43legacy_write16(dev, 0x03EC, 0x3F3F); + b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); + b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); + } + b43legacy_phy_write(dev, 0x0015, 0xB000); + b43legacy_phy_write(dev, 0x002B, 0x0004); + + if (phy->radio_ver == 0x2053) { + b43legacy_phy_write(dev, 0x002B, 0x0203); + b43legacy_phy_write(dev, 0x002A, 0x08A3); + } + + phy->minlowsig[0] = 0xFFFF; + + for (i = 0; i < 4; i++) { + b43legacy_radio_write16(dev, 0x0052, regstack[1] | i); + b43legacy_phy_lo_b_r15_loop(dev); + } + for (i = 0; i < 10; i++) { + b43legacy_radio_write16(dev, 0x0052, regstack[1] | i); + mls = b43legacy_phy_lo_b_r15_loop(dev) / 10; + if (mls < phy->minlowsig[0]) { + phy->minlowsig[0] = mls; + phy->minlowsigpos[0] = i; + } + } + b43legacy_radio_write16(dev, 0x0052, regstack[1] + | phy->minlowsigpos[0]); + + phy->minlowsig[1] = 0xFFFF; + + for (i = -4; i < 5; i += 2) { + for (j = -4; j < 5; j += 2) { + if (j < 0) + fval = (0x0100 * i) + j + 0x0100; + else + fval = (0x0100 * i) + j; + b43legacy_phy_write(dev, 0x002F, fval); + mls = b43legacy_phy_lo_b_r15_loop(dev) / 10; + if (mls < phy->minlowsig[1]) { + phy->minlowsig[1] = mls; + phy->minlowsigpos[1] = fval; + } + } + } + phy->minlowsigpos[1] += 0x0101; + + b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]); + if (phy->radio_ver == 0x2053) { + b43legacy_phy_write(dev, 0x000A, regstack[2]); + b43legacy_phy_write(dev, 0x002A, regstack[3]); + b43legacy_phy_write(dev, 0x0035, regstack[4]); + b43legacy_phy_write(dev, 0x0003, regstack[5]); + b43legacy_phy_write(dev, 0x0001, regstack[6]); + b43legacy_phy_write(dev, 0x0030, regstack[7]); + + b43legacy_radio_write16(dev, 0x0043, regstack[8]); + b43legacy_radio_write16(dev, 0x007A, regstack[9]); + + b43legacy_radio_write16(dev, 0x0052, + (b43legacy_radio_read16(dev, 0x0052) + & 0x000F) | regstack[11]); + + b43legacy_write16(dev, 0x03EC, regstack[10]); + } + b43legacy_phy_write(dev, 0x0015, regstack[0]); +} + +static inline +u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev, + u16 control) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 ret; + unsigned long flags; + + local_irq_save(flags); + if (phy->gmode) { + b43legacy_phy_write(dev, 0x15, 0xE300); + control <<= 8; + b43legacy_phy_write(dev, 0x0812, control | 0x00B0); + udelay(5); + b43legacy_phy_write(dev, 0x0812, control | 0x00B2); + udelay(2); + b43legacy_phy_write(dev, 0x0812, control | 0x00B3); + udelay(4); + b43legacy_phy_write(dev, 0x0015, 0xF300); + udelay(8); + } else { + b43legacy_phy_write(dev, 0x0015, control | 0xEFA0); + udelay(2); + b43legacy_phy_write(dev, 0x0015, control | 0xEFE0); + udelay(4); + b43legacy_phy_write(dev, 0x0015, control | 0xFFE0); + udelay(8); + } + ret = b43legacy_phy_read(dev, 0x002D); + local_irq_restore(flags); + b43legacy_voluntary_preempt(); + + return ret; +} + +static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev, + u16 control) +{ + int i; + u32 ret = 0; + + for (i = 0; i < 8; i++) + ret += b43legacy_phy_lo_g_deviation_subval(dev, control); + + return ret; +} + +/* Write the LocalOscillator CONTROL */ +static inline +void b43legacy_lo_write(struct b43legacy_wldev *dev, + struct b43legacy_lopair *pair) +{ + u16 value; + + value = (u8)(pair->low); + value |= ((u8)(pair->high)) << 8; + +#ifdef CONFIG_B43LEGACY_DEBUG + /* Sanity check. */ + if (pair->low < -8 || pair->low > 8 || + pair->high < -8 || pair->high > 8) { + struct b43legacy_phy *phy = &dev->phy; + b43legacydbg(dev->wl, + "WARNING: Writing invalid LOpair " + "(low: %d, high: %d, index: %lu)\n", + pair->low, pair->high, + (unsigned long)(pair - phy->_lo_pairs)); + dump_stack(); + } +#endif + + b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value); +} + +static inline +struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev, + u16 bbatt, + u16 rfatt, + u16 tx) +{ + static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; + struct b43legacy_phy *phy = &dev->phy; + + if (bbatt > 6) + bbatt = 6; + B43legacy_WARN_ON(rfatt >= 10); + + if (tx == 3) + return b43legacy_get_lopair(phy, rfatt, bbatt); + return b43legacy_get_lopair(phy, dict[rfatt], bbatt); +} + +static inline +struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + return b43legacy_find_lopair(dev, phy->bbatt, + phy->rfatt, phy->txctl1); +} + +/* Adjust B/G LO */ +void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed) +{ + struct b43legacy_lopair *pair; + + if (fixed) { + /* Use fixed values. Only for initialization. */ + pair = b43legacy_find_lopair(dev, 2, 3, 0); + } else + pair = b43legacy_current_lopair(dev); + b43legacy_lo_write(dev, pair); +} + +static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 txctl2 = 0; + u16 i; + u32 smallest; + u32 tmp; + + b43legacy_radio_write16(dev, 0x0052, 0x0000); + udelay(10); + smallest = b43legacy_phy_lo_g_singledeviation(dev, 0); + for (i = 0; i < 16; i++) { + b43legacy_radio_write16(dev, 0x0052, i); + udelay(10); + tmp = b43legacy_phy_lo_g_singledeviation(dev, 0); + if (tmp < smallest) { + smallest = tmp; + txctl2 = i; + } + } + phy->txctl2 = txctl2; +} + +static +void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev, + const struct b43legacy_lopair *in_pair, + struct b43legacy_lopair *out_pair, + u16 r27) +{ + static const struct b43legacy_lopair transitions[8] = { + { .high = 1, .low = 1, }, + { .high = 1, .low = 0, }, + { .high = 1, .low = -1, }, + { .high = 0, .low = -1, }, + { .high = -1, .low = -1, }, + { .high = -1, .low = 0, }, + { .high = -1, .low = 1, }, + { .high = 0, .low = 1, }, + }; + struct b43legacy_lopair lowest_transition = { + .high = in_pair->high, + .low = in_pair->low, + }; + struct b43legacy_lopair tmp_pair; + struct b43legacy_lopair transition; + int i = 12; + int state = 0; + int found_lower; + int j; + int begin; + int end; + u32 lowest_deviation; + u32 tmp; + + /* Note that in_pair and out_pair can point to the same pair. + * Be careful. */ + + b43legacy_lo_write(dev, &lowest_transition); + lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27); + do { + found_lower = 0; + B43legacy_WARN_ON(!(state >= 0 && state <= 8)); + if (state == 0) { + begin = 1; + end = 8; + } else if (state % 2 == 0) { + begin = state - 1; + end = state + 1; + } else { + begin = state - 2; + end = state + 2; + } + if (begin < 1) + begin += 8; + if (end > 8) + end -= 8; + + j = begin; + tmp_pair.high = lowest_transition.high; + tmp_pair.low = lowest_transition.low; + while (1) { + B43legacy_WARN_ON(!(j >= 1 && j <= 8)); + transition.high = tmp_pair.high + + transitions[j - 1].high; + transition.low = tmp_pair.low + transitions[j - 1].low; + if ((abs(transition.low) < 9) + && (abs(transition.high) < 9)) { + b43legacy_lo_write(dev, &transition); + tmp = b43legacy_phy_lo_g_singledeviation(dev, + r27); + if (tmp < lowest_deviation) { + lowest_deviation = tmp; + state = j; + found_lower = 1; + + lowest_transition.high = + transition.high; + lowest_transition.low = transition.low; + } + } + if (j == end) + break; + if (j == 8) + j = 1; + else + j++; + } + } while (i-- && found_lower); + + out_pair->high = lowest_transition.high; + out_pair->low = lowest_transition.low; +} + +/* Set the baseband attenuation value on chip. */ +void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev, + u16 bbatt) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 value; + + if (phy->analog == 0) { + value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0); + value |= (bbatt & 0x000F); + b43legacy_write16(dev, 0x03E6, value); + return; + } + + if (phy->analog > 1) { + value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3; + value |= (bbatt << 2) & 0x003C; + } else { + value = b43legacy_phy_read(dev, 0x0060) & 0xFF87; + value |= (bbatt << 3) & 0x0078; + } + b43legacy_phy_write(dev, 0x0060, value); +} + +/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ +void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev) +{ + static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; + const int is_initializing = (b43legacy_status(dev) + < B43legacy_STAT_STARTED); + struct b43legacy_phy *phy = &dev->phy; + u16 h; + u16 i; + u16 oldi = 0; + u16 j; + struct b43legacy_lopair control; + struct b43legacy_lopair *tmp_control; + u16 tmp; + u16 regstack[16] = { 0 }; + u8 oldchannel; + + /* XXX: What are these? */ + u8 r27 = 0; + u16 r31; + + oldchannel = phy->channel; + /* Setup */ + if (phy->gmode) { + regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS); + regstack[1] = b43legacy_phy_read(dev, 0x0802); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] + & 0x7FFF); + b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); + } + regstack[3] = b43legacy_read16(dev, 0x03E2); + b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000); + regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); + regstack[5] = b43legacy_phy_read(dev, 0x15); + regstack[6] = b43legacy_phy_read(dev, 0x2A); + regstack[7] = b43legacy_phy_read(dev, 0x35); + regstack[8] = b43legacy_phy_read(dev, 0x60); + regstack[9] = b43legacy_radio_read16(dev, 0x43); + regstack[10] = b43legacy_radio_read16(dev, 0x7A); + regstack[11] = b43legacy_radio_read16(dev, 0x52); + if (phy->gmode) { + regstack[12] = b43legacy_phy_read(dev, 0x0811); + regstack[13] = b43legacy_phy_read(dev, 0x0812); + regstack[14] = b43legacy_phy_read(dev, 0x0814); + regstack[15] = b43legacy_phy_read(dev, 0x0815); + } + b43legacy_radio_selectchannel(dev, 6, 0); + if (phy->gmode) { + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] + & 0x7FFF); + b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); + b43legacy_dummy_transmission(dev); + } + b43legacy_radio_write16(dev, 0x0043, 0x0006); + + b43legacy_phy_set_baseband_attenuation(dev, 2); + + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000); + b43legacy_phy_write(dev, 0x002E, 0x007F); + b43legacy_phy_write(dev, 0x080F, 0x0078); + b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7)); + b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0); + b43legacy_phy_write(dev, 0x002B, 0x0203); + b43legacy_phy_write(dev, 0x002A, 0x08A3); + if (phy->gmode) { + b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003); + b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC); + b43legacy_phy_write(dev, 0x0811, 0x01B3); + b43legacy_phy_write(dev, 0x0812, 0x00B2); + } + if (is_initializing) + b43legacy_phy_lo_g_measure_txctl2(dev); + b43legacy_phy_write(dev, 0x080F, 0x8078); + + /* Measure */ + control.low = 0; + control.high = 0; + for (h = 0; h < 10; h++) { + /* Loop over each possible RadioAttenuation (0-9) */ + i = pairorder[h]; + if (is_initializing) { + if (i == 3) { + control.low = 0; + control.high = 0; + } else if (((i % 2 == 1) && (oldi % 2 == 1)) || + ((i % 2 == 0) && (oldi % 2 == 0))) { + tmp_control = b43legacy_get_lopair(phy, oldi, + 0); + memcpy(&control, tmp_control, sizeof(control)); + } else { + tmp_control = b43legacy_get_lopair(phy, 3, 0); + memcpy(&control, tmp_control, sizeof(control)); + } + } + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp = i * 2 + j; + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = b43legacy_get_lopair(phy, i, + j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + b43legacy_radio_write16(dev, 0x43, i); + b43legacy_radio_write16(dev, 0x52, phy->txctl2); + udelay(10); + b43legacy_voluntary_preempt(); + + b43legacy_phy_set_baseband_attenuation(dev, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + b43legacy_radio_write16(dev, 0x007A, tmp); + + tmp_control = b43legacy_get_lopair(phy, i, j * 2); + b43legacy_phy_lo_g_state(dev, &control, tmp_control, + r27); + } + oldi = i; + } + /* Loop over each possible RadioAttenuation (10-13) */ + for (i = 10; i < 14; i++) { + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp_control = b43legacy_get_lopair(phy, i - 9, + j * 2); + memcpy(&control, tmp_control, sizeof(control)); + /* FIXME: The next line is wrong, as the + * following if statement can never trigger. */ + tmp = (i - 9) * 2 + j - 5; + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = b43legacy_get_lopair(phy, i - 9, + j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + b43legacy_radio_write16(dev, 0x43, i - 9); + /* FIXME: shouldn't txctl1 be zero in the next line + * and 3 in the loop above? */ + b43legacy_radio_write16(dev, 0x52, + phy->txctl2 + | (3/*txctl1*/ << 4)); + udelay(10); + b43legacy_voluntary_preempt(); + + b43legacy_phy_set_baseband_attenuation(dev, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + b43legacy_radio_write16(dev, 0x7A, tmp); + + tmp_control = b43legacy_get_lopair(phy, i, j * 2); + b43legacy_phy_lo_g_state(dev, &control, tmp_control, + r27); + } + } + + /* Restoration */ + if (phy->gmode) { + b43legacy_phy_write(dev, 0x0015, 0xE300); + b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0); + udelay(5); + b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2); + udelay(2); + b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3); + b43legacy_voluntary_preempt(); + } else + b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0); + b43legacy_phy_lo_adjust(dev, is_initializing); + b43legacy_phy_write(dev, 0x002E, 0x807F); + if (phy->gmode) + b43legacy_phy_write(dev, 0x002F, 0x0202); + else + b43legacy_phy_write(dev, 0x002F, 0x0101); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]); + b43legacy_phy_write(dev, 0x0015, regstack[5]); + b43legacy_phy_write(dev, 0x002A, regstack[6]); + b43legacy_phy_write(dev, 0x0035, regstack[7]); + b43legacy_phy_write(dev, 0x0060, regstack[8]); + b43legacy_radio_write16(dev, 0x0043, regstack[9]); + b43legacy_radio_write16(dev, 0x007A, regstack[10]); + regstack[11] &= 0x00F0; + regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F); + b43legacy_radio_write16(dev, 0x52, regstack[11]); + b43legacy_write16(dev, 0x03E2, regstack[3]); + if (phy->gmode) { + b43legacy_phy_write(dev, 0x0811, regstack[12]); + b43legacy_phy_write(dev, 0x0812, regstack[13]); + b43legacy_phy_write(dev, 0x0814, regstack[14]); + b43legacy_phy_write(dev, 0x0815, regstack[15]); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]); + b43legacy_phy_write(dev, 0x0802, regstack[1]); + } + b43legacy_radio_selectchannel(dev, oldchannel, 1); + +#ifdef CONFIG_B43LEGACY_DEBUG + { + /* Sanity check for all lopairs. */ + for (i = 0; i < B43legacy_LO_COUNT; i++) { + tmp_control = phy->_lo_pairs + i; + if (tmp_control->low < -8 || tmp_control->low > 8 || + tmp_control->high < -8 || tmp_control->high > 8) + b43legacywarn(dev->wl, + "WARNING: Invalid LOpair (low: %d, high:" + " %d, index: %d)\n", + tmp_control->low, tmp_control->high, i); + } + } +#endif /* CONFIG_B43LEGACY_DEBUG */ +} + +static +void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev) +{ + struct b43legacy_lopair *pair; + + pair = b43legacy_current_lopair(dev); + pair->used = 1; +} + +void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + struct b43legacy_lopair *pair; + int i; + + for (i = 0; i < B43legacy_LO_COUNT; i++) { + pair = phy->_lo_pairs + i; + pair->used = 0; + } +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) +{ + struct b43legacy_phy *phy = &dev->phy; + s8 dbm = 0; + s32 tmp; + + tmp = phy->idle_tssi; + tmp += tssi; + tmp -= phy->savedpctlreg; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + tmp = limit_value(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + B43legacy_BUG_ON(1); + } + + return dbm; +} + +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 tmp; + u16 txpower; + s8 v0; + s8 v1; + s8 v2; + s8 v3; + s8 average; + int max_pwr; + s16 desired_pwr; + s16 estimated_pwr; + s16 pwr_adjust; + s16 radio_att_delta; + s16 baseband_att_delta; + s16 radio_attenuation; + s16 baseband_attenuation; + unsigned long phylock_flags; + + if (phy->savedpctlreg == 0xFFFF) + return; + if ((dev->dev->bus->boardinfo.type == 0x0416) && + is_bcm_board_vendor(dev)) + return; +#ifdef CONFIG_B43LEGACY_DEBUG + if (phy->manual_txpower_control) + return; +#endif + + B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B || + phy->type == B43legacy_PHYTYPE_G)); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + 0x0070); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + 0x0072); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + b43legacy_radio_clear_tssi(dev); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E) + & 0x8)) + average -= 13; + + estimated_pwr = b43legacy_phy_estimate_power_out(dev, average); + + max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; + + if ((dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_PACTRL) && + (phy->type == B43legacy_PHYTYPE_G)) + max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM." + "\n"); + max_pwr = 74; /* fake it */ + dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + } + + /* Use regulatory information to get the maximum power. + * In the absence of such data from mac80211, we will use 20 dBm, which + * is the value for the EU, US, Canada, and most of the world. + * The regulatory maximum is reduced by the antenna gain (from sprom) + * and 1.5 dBm (a safety factor??). The result is in Q5.2 format + * which accounts for the factor of 4 */ +#define REG_MAX_PWR 20 + max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg + - 0x6, max_pwr); + + /* find the desired power in Q5.2 - power_level is in dBm + * and limit it - max_pwr is already in Q5.2 */ + desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr); + if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER)) + b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT + " dBm, Desired TX power output: " Q52_FMT + " dBm\n", Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr)); + /* Check if we need to adjust the current power. The factor of 2 is + * for damping */ + pwr_adjust = (desired_pwr - estimated_pwr) / 2; + /* RF attenuation delta + * The minus sign is because lower attenuation => more power */ + radio_att_delta = -(pwr_adjust + 7) >> 3; + /* Baseband attenuation delta */ + baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); + /* Do we need to adjust anything? */ + if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { + b43legacy_phy_lo_mark_current_used(dev); + return; + } + + /* Calculate the new attenuation values. */ + baseband_attenuation = phy->bbatt; + baseband_attenuation += baseband_att_delta; + radio_attenuation = phy->rfatt; + radio_attenuation += radio_att_delta; + + /* Get baseband and radio attenuation values into permitted ranges. + * baseband 0-11, radio 0-9. + * Radio attenuation affects power level 4 times as much as baseband. + */ + if (radio_attenuation < 0) { + baseband_attenuation -= (4 * -radio_attenuation); + radio_attenuation = 0; + } else if (radio_attenuation > 9) { + baseband_attenuation += (4 * (radio_attenuation - 9)); + radio_attenuation = 9; + } else { + while (baseband_attenuation < 0 && radio_attenuation > 0) { + baseband_attenuation += 4; + radio_attenuation--; + } + while (baseband_attenuation > 11 && radio_attenuation < 9) { + baseband_attenuation -= 4; + radio_attenuation++; + } + } + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + + txpower = phy->txctl1; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (radio_attenuation <= 1) { + if (txpower == 0) { + txpower = 3; + radio_attenuation += 2; + baseband_attenuation += 2; + } else if (dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_PACTRL) { + baseband_attenuation += 4 * + (radio_attenuation - 2); + radio_attenuation = 2; + } + } else if (radio_attenuation > 4 && txpower != 0) { + txpower = 0; + if (baseband_attenuation < 3) { + radio_attenuation -= 3; + baseband_attenuation += 2; + } else { + radio_attenuation -= 2; + baseband_attenuation -= 2; + } + } + } + /* Save the control values */ + phy->txctl1 = txpower; + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + radio_attenuation = limit_value(radio_attenuation, 0, 9); + phy->rfatt = radio_attenuation; + phy->bbatt = baseband_attenuation; + + /* Adjust the hardware */ + b43legacy_phy_lock(dev, phylock_flags); + b43legacy_radio_lock(dev); + b43legacy_radio_set_txpower_bg(dev, baseband_attenuation, + radio_attenuation, txpower); + b43legacy_phy_lo_mark_current_used(dev); + b43legacy_radio_unlock(dev); + b43legacy_phy_unlock(dev, phylock_flags); +} + +static inline +s32 b43legacy_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num/den; + else + return (num+den/2)/den; +} + +static inline +s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1; + s32 m2; + s32 f = 256; + s32 q; + s32 delta; + s8 i = 0; + + m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43legacy_tssi2dbm_ad(f * 4096 - + b43legacy_tssi2dbm_ad(m2 * f, 16) * + f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192), + -127, 128); + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + s16 pab0; + s16 pab1; + s16 pab2; + u8 idx; + s8 *dyn_tssi2dbm; + + B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B || + phy->type == B43legacy_PHYTYPE_G)); + pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0); + pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1); + pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2); + + if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { + phy->idle_tssi = 0x34; + phy->tssi2dbm = b43legacy_tssi2dbm_b_table; + return 0; + } + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 && + (s8)dev->dev->bus->sprom.r1.itssi_bg != -1) + phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg); + else + phy->idle_tssi = 62; + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + b43legacyerr(dev->wl, "Could not allocate memory" + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, + pab1, pab2)) { + phy->tssi2dbm = NULL; + b43legacyerr(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(dyn_tssi2dbm); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + switch (phy->type) { + case B43legacy_PHYTYPE_B: + phy->idle_tssi = 0x34; + phy->tssi2dbm = b43legacy_tssi2dbm_b_table; + break; + case B43legacy_PHYTYPE_G: + phy->idle_tssi = 0x34; + phy->tssi2dbm = b43legacy_tssi2dbm_g_table; + break; + } + } + + return 0; +} + +int b43legacy_phy_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + int err = -ENODEV; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + switch (phy->rev) { + case 2: + b43legacy_phy_initb2(dev); + err = 0; + break; + case 4: + b43legacy_phy_initb4(dev); + err = 0; + break; + case 5: + b43legacy_phy_initb5(dev); + err = 0; + break; + case 6: + b43legacy_phy_initb6(dev); + err = 0; + break; + } + break; + case B43legacy_PHYTYPE_G: + b43legacy_phy_initg(dev); + err = 0; + break; + } + if (err) + b43legacyerr(dev->wl, "Unknown PHYTYPE found\n"); + + return err; +} + +void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 antennadiv; + u16 offset; + u16 value; + u32 ucodeflags; + + antennadiv = phy->antenna_diversity; + + if (antennadiv == 0xFFFF) + antennadiv = 3; + B43legacy_WARN_ON(antennadiv > 3); + + ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET); + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV); + + switch (phy->type) { + case B43legacy_PHYTYPE_G: + offset = 0x0400; + + if (antennadiv == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + b43legacy_phy_write(dev, offset + 1, + (b43legacy_phy_read(dev, offset + 1) + & 0x7E7F) | value); + + if (antennadiv >= 2) { + if (antennadiv == 2) + value = (antennadiv << 7); + else + value = (0/*force0*/ << 7); + b43legacy_phy_write(dev, offset + 0x2B, + (b43legacy_phy_read(dev, + offset + 0x2B) + & 0xFEFF) | value); + } + + if (phy->type == B43legacy_PHYTYPE_G) { + if (antennadiv >= 2) + b43legacy_phy_write(dev, 0x048C, + b43legacy_phy_read(dev, + 0x048C) | 0x2000); + else + b43legacy_phy_write(dev, 0x048C, + b43legacy_phy_read(dev, + 0x048C) & ~0x2000); + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0461, + b43legacy_phy_read(dev, + 0x0461) | 0x0010); + b43legacy_phy_write(dev, 0x04AD, + (b43legacy_phy_read(dev, + 0x04AD) + & 0x00FF) | 0x0015); + if (phy->rev == 2) + b43legacy_phy_write(dev, 0x0427, + 0x0008); + else + b43legacy_phy_write(dev, 0x0427, + (b43legacy_phy_read(dev, 0x0427) + & 0x00FF) | 0x0008); + } else if (phy->rev >= 6) + b43legacy_phy_write(dev, 0x049B, 0x00DC); + } else { + if (phy->rev < 3) + b43legacy_phy_write(dev, 0x002B, + (b43legacy_phy_read(dev, + 0x002B) & 0x00FF) + | 0x0024); + else { + b43legacy_phy_write(dev, 0x0061, + b43legacy_phy_read(dev, + 0x0061) | 0x0010); + if (phy->rev == 3) { + b43legacy_phy_write(dev, 0x0093, + 0x001D); + b43legacy_phy_write(dev, 0x0027, + 0x0008); + } else { + b43legacy_phy_write(dev, 0x0093, + 0x003A); + b43legacy_phy_write(dev, 0x0027, + (b43legacy_phy_read(dev, 0x0027) + & 0x00FF) | 0x0008); + } + } + } + break; + case B43legacy_PHYTYPE_B: + if (dev->dev->id.revision == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + b43legacy_phy_write(dev, 0x03E2, + (b43legacy_phy_read(dev, 0x03E2) + & 0xFE7F) | value); + break; + default: + B43legacy_WARN_ON(1); + } + + if (antennadiv >= 2) { + ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET); + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + ucodeflags | B43legacy_UCODEFLAG_AUTODIV); + } + + phy->antenna_diversity = antennadiv; +} + +/* Set the PowerSavingControlBits. + * Bitvalues: + * 0 => unset the bit + * 1 => set the bit + * -1 => calculate the bit + */ +void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev, + int bit25, int bit26) +{ + int i; + u32 status; + +/* FIXME: Force 25 to off and 26 to on for now: */ +bit25 = 0; +bit26 = 1; + + if (bit25 == -1) { + /* TODO: If powersave is not off and FIXME is not set and we + * are not in adhoc and thus is not an AP and we arei + * associated, set bit 25 */ + } + if (bit26 == -1) { + /* TODO: If the device is awake or this is an AP, or we are + * scanning, or FIXME, or we are associated, or FIXME, + * or the latest PS-Poll packet sent was successful, + * set bit26 */ + } + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + if (bit25) + status |= B43legacy_SBF_PS1; + else + status &= ~B43legacy_SBF_PS1; + if (bit26) + status |= B43legacy_SBF_PS2; + else + status &= ~B43legacy_SBF_PS2; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); + if (bit26 && dev->dev->id.revision >= 5) { + for (i = 0; i < 100; i++) { + if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + 0x0040) != 4) + break; + udelay(10); + } + } +} diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h new file mode 100644 index 000000000000..f11b4271714c --- /dev/null +++ b/drivers/net/wireless/b43legacy/phy.h @@ -0,0 +1,219 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + Copyright (c) 2007 Larry Finger + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43legacy_PHY_H_ +#define B43legacy_PHY_H_ + +#include + +enum { + B43legacy_ANTENNA0, /* Antenna 0 */ + B43legacy_ANTENNA1, /* Antenna 0 */ + B43legacy_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ + B43legacy_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ + + B43legacy_ANTENNA_AUTO = B43legacy_ANTENNA_AUTO0, + B43legacy_ANTENNA_DEFAULT = B43legacy_ANTENNA_AUTO, +}; + +enum { + B43legacy_INTERFMODE_NONE, + B43legacy_INTERFMODE_NONWLAN, + B43legacy_INTERFMODE_MANUALWLAN, + B43legacy_INTERFMODE_AUTOWLAN, +}; + +/*** PHY Registers ***/ + +/* Routing */ +#define B43legacy_PHYROUTE_OFDM_GPHY 0x400 +#define B43legacy_PHYROUTE_EXT_GPHY 0x800 + +/* Base registers. */ +#define B43legacy_PHY_BASE(reg) (reg) +/* OFDM (A) registers of a G-PHY */ +#define B43legacy_PHY_OFDM(reg) ((reg) | B43legacy_PHYROUTE_OFDM_GPHY) +/* Extended G-PHY registers */ +#define B43legacy_PHY_EXTG(reg) ((reg) | B43legacy_PHYROUTE_EXT_GPHY) + + +/* Extended G-PHY Registers */ +#define B43legacy_PHY_CLASSCTL B43legacy_PHY_EXTG(0x02) /* Classify control */ +#define B43legacy_PHY_GTABCTL B43legacy_PHY_EXTG(0x03) /* G-PHY table control (see below) */ +#define B43legacy_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ +#define B43legacy_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ +#define B43legacy_PHY_GTABNR_SHIFT 10 +#define B43legacy_PHY_GTABDATA B43legacy_PHY_EXTG(0x04) /* G-PHY table data */ +#define B43legacy_PHY_LO_MASK B43legacy_PHY_EXTG(0x0F) /* Local Oscillator control mask */ +#define B43legacy_PHY_LO_CTL B43legacy_PHY_EXTG(0x10) /* Local Oscillator control */ +#define B43legacy_PHY_RFOVER B43legacy_PHY_EXTG(0x11) /* RF override */ +#define B43legacy_PHY_RFOVERVAL B43legacy_PHY_EXTG(0x12) /* RF override value */ +/*** OFDM table numbers ***/ +#define B43legacy_OFDMTAB(number, offset) \ + (((number) << B43legacy_PHY_OTABLENR_SHIFT) \ + | (offset)) +#define B43legacy_OFDMTAB_AGC1 B43legacy_OFDMTAB(0x00, 0) +#define B43legacy_OFDMTAB_GAIN0 B43legacy_OFDMTAB(0x00, 0) +#define B43legacy_OFDMTAB_GAINX B43legacy_OFDMTAB(0x01, 0) +#define B43legacy_OFDMTAB_GAIN1 B43legacy_OFDMTAB(0x01, 4) +#define B43legacy_OFDMTAB_AGC3 B43legacy_OFDMTAB(0x02, 0) +#define B43legacy_OFDMTAB_GAIN2 B43legacy_OFDMTAB(0x02, 3) +#define B43legacy_OFDMTAB_LNAHPFGAIN1 B43legacy_OFDMTAB(0x03, 0) +#define B43legacy_OFDMTAB_WRSSI B43legacy_OFDMTAB(0x04, 0) +#define B43legacy_OFDMTAB_LNAHPFGAIN2 B43legacy_OFDMTAB(0x04, 0) +#define B43legacy_OFDMTAB_NOISESCALE B43legacy_OFDMTAB(0x05, 0) +#define B43legacy_OFDMTAB_AGC2 B43legacy_OFDMTAB(0x06, 0) +#define B43legacy_OFDMTAB_ROTOR B43legacy_OFDMTAB(0x08, 0) +#define B43legacy_OFDMTAB_ADVRETARD B43legacy_OFDMTAB(0x09, 0) +#define B43legacy_OFDMTAB_DAC B43legacy_OFDMTAB(0x0C, 0) +#define B43legacy_OFDMTAB_DC B43legacy_OFDMTAB(0x0E, 7) +#define B43legacy_OFDMTAB_PWRDYN2 B43legacy_OFDMTAB(0x0E, 12) +#define B43legacy_OFDMTAB_LNAGAIN B43legacy_OFDMTAB(0x0E, 13) + +#define B43legacy_OFDMTAB_LPFGAIN B43legacy_OFDMTAB(0x0F, 12) +#define B43legacy_OFDMTAB_RSSI B43legacy_OFDMTAB(0x10, 0) + +#define B43legacy_OFDMTAB_AGC1_R1 B43legacy_OFDMTAB(0x13, 0) +#define B43legacy_OFDMTAB_GAINX_R1 B43legacy_OFDMTAB(0x14, 0) +#define B43legacy_OFDMTAB_MINSIGSQ B43legacy_OFDMTAB(0x14, 1) +#define B43legacy_OFDMTAB_AGC3_R1 B43legacy_OFDMTAB(0x15, 0) +#define B43legacy_OFDMTAB_WRSSI_R1 B43legacy_OFDMTAB(0x15, 4) +#define B43legacy_OFDMTAB_TSSI B43legacy_OFDMTAB(0x15, 0) +#define B43legacy_OFDMTAB_DACRFPABB B43legacy_OFDMTAB(0x16, 0) +#define B43legacy_OFDMTAB_DACOFF B43legacy_OFDMTAB(0x17, 0) +#define B43legacy_OFDMTAB_DCBIAS B43legacy_OFDMTAB(0x18, 0) + +void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt); + +/* OFDM (A) PHY Registers */ +#define B43legacy_PHY_VERSION_OFDM B43legacy_PHY_OFDM(0x00) /* Versioning register for A-PHY */ +#define B43legacy_PHY_BBANDCFG B43legacy_PHY_OFDM(0x01) /* Baseband config */ +#define B43legacy_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ +#define B43legacy_PHY_BBANDCFG_RXANT_SHIFT 7 +#define B43legacy_PHY_PWRDOWN B43legacy_PHY_OFDM(0x03) /* Powerdown */ +#define B43legacy_PHY_CRSTHRES1 B43legacy_PHY_OFDM(0x06) /* CRS Threshold 1 */ +#define B43legacy_PHY_LNAHPFCTL B43legacy_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43legacy_PHY_ADIVRELATED B43legacy_PHY_OFDM(0x27) /* FIXME rename */ +#define B43legacy_PHY_CRS0 B43legacy_PHY_OFDM(0x29) +#define B43legacy_PHY_ANTDWELL B43legacy_PHY_OFDM(0x2B) /* Antenna dwell */ +#define B43legacy_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ +#define B43legacy_PHY_ENCORE B43legacy_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ +#define B43legacy_PHY_ENCORE_EN 0x0200 /* Encore enable */ +#define B43legacy_PHY_LMS B43legacy_PHY_OFDM(0x55) +#define B43legacy_PHY_OFDM61 B43legacy_PHY_OFDM(0x61) /* FIXME rename */ +#define B43legacy_PHY_OFDM61_10 0x0010 /* FIXME rename */ +#define B43legacy_PHY_IQBAL B43legacy_PHY_OFDM(0x69) /* I/Q balance */ +#define B43legacy_PHY_OTABLECTL B43legacy_PHY_OFDM(0x72) /* OFDM table control (see below) */ +#define B43legacy_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ +#define B43legacy_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ +#define B43legacy_PHY_OTABLENR_SHIFT 10 +#define B43legacy_PHY_OTABLEI B43legacy_PHY_OFDM(0x73) /* OFDM table data I */ +#define B43legacy_PHY_OTABLEQ B43legacy_PHY_OFDM(0x74) /* OFDM table data Q */ +#define B43legacy_PHY_HPWR_TSSICTL B43legacy_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43legacy_PHY_NRSSITHRES B43legacy_PHY_OFDM(0x8A) /* NRSSI threshold */ +#define B43legacy_PHY_ANTWRSETT B43legacy_PHY_OFDM(0x8C) /* Antenna WR settle */ +#define B43legacy_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ +#define B43legacy_PHY_CLIPPWRDOWNT B43legacy_PHY_OFDM(0x93) /* Clip powerdown threshold */ +#define B43legacy_PHY_OFDM9B B43legacy_PHY_OFDM(0x9B) /* FIXME rename */ +#define B43legacy_PHY_N1P1GAIN B43legacy_PHY_OFDM(0xA0) +#define B43legacy_PHY_P1P2GAIN B43legacy_PHY_OFDM(0xA1) +#define B43legacy_PHY_N1N2GAIN B43legacy_PHY_OFDM(0xA2) +#define B43legacy_PHY_CLIPTHRES B43legacy_PHY_OFDM(0xA3) +#define B43legacy_PHY_CLIPN1P2THRES B43legacy_PHY_OFDM(0xA4) +#define B43legacy_PHY_DIVSRCHIDX B43legacy_PHY_OFDM(0xA8) /* Divider search gain/index */ +#define B43legacy_PHY_CLIPP2THRES B43legacy_PHY_OFDM(0xA9) +#define B43legacy_PHY_CLIPP3THRES B43legacy_PHY_OFDM(0xAA) +#define B43legacy_PHY_DIVP1P2GAIN B43legacy_PHY_OFDM(0xAB) +#define B43legacy_PHY_DIVSRCHGAINBACK B43legacy_PHY_OFDM(0xAD) /* Divider search gain back */ +#define B43legacy_PHY_DIVSRCHGAINCHNG B43legacy_PHY_OFDM(0xAE) /* Divider search gain change */ +#define B43legacy_PHY_CRSTHRES1_R1 B43legacy_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */ +#define B43legacy_PHY_CRSTHRES2_R1 B43legacy_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */ +#define B43legacy_PHY_TSSIP_LTBASE B43legacy_PHY_OFDM(0x380) /* TSSI power lookup table base */ +#define B43legacy_PHY_DC_LTBASE B43legacy_PHY_OFDM(0x3A0) /* DC lookup table base */ +#define B43legacy_PHY_GAIN_LTBASE B43legacy_PHY_OFDM(0x3C0) /* Gain lookup table base */ + +void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt); + +/* Masks for the different PHY versioning registers. */ +#define B43legacy_PHYVER_ANALOG 0xF000 +#define B43legacy_PHYVER_ANALOG_SHIFT 12 +#define B43legacy_PHYVER_TYPE 0x0F00 +#define B43legacy_PHYVER_TYPE_SHIFT 8 +#define B43legacy_PHYVER_VERSION 0x00FF + +struct b43legacy_wldev; + +void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev); +#define b43legacy_phy_lock(bcm, flags) \ + do { \ + local_irq_save(flags); \ + b43legacy_raw_phy_lock(bcm); \ + } while (0) +void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev); +#define b43legacy_phy_unlock(bcm, flags) \ + do { \ + b43legacy_raw_phy_unlock(bcm); \ + local_irq_restore(flags); \ + } while (0) + +/* Card uses the loopback gain stuff */ +#define has_loopback_gain(phy) \ + (((phy)->rev > 1) || ((phy)->gmode)) + +u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset); +void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val); + +int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev); +int b43legacy_phy_init(struct b43legacy_wldev *dev); + +void b43legacy_set_rx_antenna(struct b43legacy_wldev *dev, int antenna); + +void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev); +void b43legacy_phy_calibrate(struct b43legacy_wldev *dev); +int b43legacy_phy_connect(struct b43legacy_wldev *dev, int connect); + +void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev); +void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev); +void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev); + +/* Adjust the LocalOscillator to the saved values. + * "fixed" is only set to 1 once in initialization. Set to 0 otherwise. + */ +void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed); +void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev); + +void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev, + u16 baseband_attenuation); + +void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev, + int bit25, int bit26); + +#endif /* B43legacy_PHY_H_ */ diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c new file mode 100644 index 000000000000..de843ac147ae --- /dev/null +++ b/drivers/net/wireless/b43legacy/pio.c @@ -0,0 +1,668 @@ +/* + + Broadcom B43legacy wireless driver + + PIO Transmission + + Copyright (c) 2005 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43legacy.h" +#include "pio.h" +#include "main.h" +#include "xmit.h" + +#include + + +static void tx_start(struct b43legacy_pioqueue *queue) +{ + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_INIT); +} + +static void tx_octet(struct b43legacy_pioqueue *queue, + u8 octet) +{ + if (queue->need_workarounds) { + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet); + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_WRITELO); + } else { + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_WRITELO); + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet); + } +} + +static u16 tx_get_next_word(const u8 *txhdr, + const u8 *packet, + size_t txhdr_size, + unsigned int *pos) +{ + const u8 *source; + unsigned int i = *pos; + u16 ret; + + if (i < txhdr_size) + source = txhdr; + else { + source = packet; + i -= txhdr_size; + } + ret = le16_to_cpu(*((__le16 *)(source + i))); + *pos += 2; + + return ret; +} + +static void tx_data(struct b43legacy_pioqueue *queue, + u8 *txhdr, + const u8 *packet, + unsigned int octets) +{ + u16 data; + unsigned int i = 0; + + if (queue->need_workarounds) { + data = tx_get_next_word(txhdr, packet, + sizeof(struct b43legacy_txhdr_fw3), &i); + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data); + } + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_WRITELO | + B43legacy_PIO_TXCTL_WRITEHI); + while (i < octets - 1) { + data = tx_get_next_word(txhdr, packet, + sizeof(struct b43legacy_txhdr_fw3), &i); + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data); + } + if (octets % 2) + tx_octet(queue, packet[octets - + sizeof(struct b43legacy_txhdr_fw3) - 1]); +} + +static void tx_complete(struct b43legacy_pioqueue *queue, + struct sk_buff *skb) +{ + if (queue->need_workarounds) { + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, + skb->data[skb->len - 1]); + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_WRITELO | + B43legacy_PIO_TXCTL_COMPLETE); + } else + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_COMPLETE); +} + +static u16 generate_cookie(struct b43legacy_pioqueue *queue, + struct b43legacy_pio_txpacket *packet) +{ + u16 cookie = 0x0000; + int packetindex; + + /* We use the upper 4 bits for the PIO + * controller ID and the lower 12 bits + * for the packet index (in the cache). + */ + switch (queue->mmio_base) { + case B43legacy_MMIO_PIO1_BASE: + break; + case B43legacy_MMIO_PIO2_BASE: + cookie = 0x1000; + break; + case B43legacy_MMIO_PIO3_BASE: + cookie = 0x2000; + break; + case B43legacy_MMIO_PIO4_BASE: + cookie = 0x3000; + break; + default: + B43legacy_WARN_ON(1); + } + packetindex = pio_txpacket_getindex(packet); + B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000)); + cookie |= (u16)packetindex; + + return cookie; +} + +static +struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev, + u16 cookie, + struct b43legacy_pio_txpacket **packet) +{ + struct b43legacy_pio *pio = &dev->pio; + struct b43legacy_pioqueue *queue = NULL; + int packetindex; + + switch (cookie & 0xF000) { + case 0x0000: + queue = pio->queue0; + break; + case 0x1000: + queue = pio->queue1; + break; + case 0x2000: + queue = pio->queue2; + break; + case 0x3000: + queue = pio->queue3; + break; + default: + B43legacy_WARN_ON(1); + } + packetindex = (cookie & 0x0FFF); + B43legacy_WARN_ON(!(packetindex >= 0 && packetindex + < B43legacy_PIO_MAXTXPACKETS)); + *packet = &(queue->tx_packets_cache[packetindex]); + + return queue; +} + +union txhdr_union { + struct b43legacy_txhdr_fw3 txhdr_fw3; +}; + +static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue, + struct sk_buff *skb, + struct b43legacy_pio_txpacket *packet, + size_t txhdr_size) +{ + union txhdr_union txhdr_data; + u8 *txhdr = NULL; + unsigned int octets; + + txhdr = (u8 *)(&txhdr_data.txhdr_fw3); + + B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); + b43legacy_generate_txhdr(queue->dev, + txhdr, skb->data, skb->len, + &packet->txstat.control, + generate_cookie(queue, packet)); + + tx_start(queue); + octets = skb->len + txhdr_size; + if (queue->need_workarounds) + octets--; + tx_data(queue, txhdr, (u8 *)skb->data, octets); + tx_complete(queue, skb); +} + +static void free_txpacket(struct b43legacy_pio_txpacket *packet, + int irq_context) +{ + struct b43legacy_pioqueue *queue = packet->queue; + + if (packet->skb) { + if (irq_context) + dev_kfree_skb_irq(packet->skb); + else + dev_kfree_skb(packet->skb); + } + list_move(&packet->list, &queue->txfree); + queue->nr_txfree++; +} + +static int pio_tx_packet(struct b43legacy_pio_txpacket *packet) +{ + struct b43legacy_pioqueue *queue = packet->queue; + struct sk_buff *skb = packet->skb; + u16 octets; + + octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3); + if (queue->tx_devq_size < octets) { + b43legacywarn(queue->dev->wl, "PIO queue too small. " + "Dropping packet.\n"); + /* Drop it silently (return success) */ + free_txpacket(packet, 1); + return 0; + } + B43legacy_WARN_ON(queue->tx_devq_packets > + B43legacy_PIO_MAXTXDEVQPACKETS); + B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size); + /* Check if there is sufficient free space on the device + * TX queue. If not, return and let the TX tasklet + * retry later. + */ + if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS) + return -EBUSY; + if (queue->tx_devq_used + octets > queue->tx_devq_size) + return -EBUSY; + /* Now poke the device. */ + pio_tx_write_fragment(queue, skb, packet, + sizeof(struct b43legacy_txhdr_fw3)); + + /* Account for the packet size. + * (We must not overflow the device TX queue) + */ + queue->tx_devq_packets++; + queue->tx_devq_used += octets; + + /* Transmission started, everything ok, move the + * packet to the txrunning list. + */ + list_move_tail(&packet->list, &queue->txrunning); + + return 0; +} + +static void tx_tasklet(unsigned long d) +{ + struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d; + struct b43legacy_wldev *dev = queue->dev; + unsigned long flags; + struct b43legacy_pio_txpacket *packet, *tmp_packet; + int err; + u16 txctl; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if (queue->tx_frozen) + goto out_unlock; + txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL); + if (txctl & B43legacy_PIO_TXCTL_SUSPEND) + goto out_unlock; + + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { + /* Try to transmit the packet. This can fail, if + * the device queue is full. In case of failure, the + * packet is left in the txqueue. + * If transmission succeed, the packet is moved to txrunning. + * If it is impossible to transmit the packet, it + * is dropped. + */ + err = pio_tx_packet(packet); + if (err) + break; + } +out_unlock: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); +} + +static void setup_txqueues(struct b43legacy_pioqueue *queue) +{ + struct b43legacy_pio_txpacket *packet; + int i; + + queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS; + for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) { + packet = &(queue->tx_packets_cache[i]); + + packet->queue = queue; + INIT_LIST_HEAD(&packet->list); + + list_add(&packet->list, &queue->txfree); + } +} + +static +struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev, + u16 pio_mmio_base) +{ + struct b43legacy_pioqueue *queue; + u32 value; + u16 qsize; + + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + goto out; + + queue->dev = dev; + queue->mmio_base = pio_mmio_base; + queue->need_workarounds = (dev->dev->id.revision < 3); + + INIT_LIST_HEAD(&queue->txfree); + INIT_LIST_HEAD(&queue->txqueue); + INIT_LIST_HEAD(&queue->txrunning); + tasklet_init(&queue->txtask, tx_tasklet, + (unsigned long)queue); + + value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + value &= ~B43legacy_SBF_XFER_REG_BYTESWAP; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value); + + qsize = b43legacy_read16(dev, queue->mmio_base + + B43legacy_PIO_TXQBUFSIZE); + if (qsize == 0) { + b43legacyerr(dev->wl, "This card does not support PIO " + "operation mode. Please use DMA mode " + "(module parameter pio=0).\n"); + goto err_freequeue; + } + if (qsize <= B43legacy_PIO_TXQADJUST) { + b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n", + qsize); + goto err_freequeue; + } + qsize -= B43legacy_PIO_TXQADJUST; + queue->tx_devq_size = qsize; + + setup_txqueues(queue); + +out: + return queue; + +err_freequeue: + kfree(queue); + queue = NULL; + goto out; +} + +static void cancel_transfers(struct b43legacy_pioqueue *queue) +{ + struct b43legacy_pio_txpacket *packet, *tmp_packet; + + tasklet_disable(&queue->txtask); + + list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) + free_txpacket(packet, 0); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) + free_txpacket(packet, 0); +} + +static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue) +{ + if (!queue) + return; + + cancel_transfers(queue); + kfree(queue); +} + +void b43legacy_pio_free(struct b43legacy_wldev *dev) +{ + struct b43legacy_pio *pio; + + if (!b43legacy_using_pio(dev)) + return; + pio = &dev->pio; + + b43legacy_destroy_pioqueue(pio->queue3); + pio->queue3 = NULL; + b43legacy_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + b43legacy_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + b43legacy_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; +} + +int b43legacy_pio_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_pio *pio = &dev->pio; + struct b43legacy_pioqueue *queue; + int err = -ENOMEM; + + queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE); + if (!queue) + goto out; + pio->queue0 = queue; + + queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE); + if (!queue) + goto err_destroy0; + pio->queue1 = queue; + + queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE); + if (!queue) + goto err_destroy1; + pio->queue2 = queue; + + queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE); + if (!queue) + goto err_destroy2; + pio->queue3 = queue; + + if (dev->dev->id.revision < 3) + dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND; + + b43legacydbg(dev->wl, "PIO initialized\n"); + err = 0; +out: + return err; + +err_destroy2: + b43legacy_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; +err_destroy1: + b43legacy_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; +err_destroy0: + b43legacy_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; + goto out; +} + +int b43legacy_pio_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct b43legacy_pioqueue *queue = dev->pio.queue1; + struct b43legacy_pio_txpacket *packet; + + B43legacy_WARN_ON(queue->tx_suspended); + B43legacy_WARN_ON(list_empty(&queue->txfree)); + + packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket, + list); + packet->skb = skb; + + memset(&packet->txstat, 0, sizeof(packet->txstat)); + memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); + + list_move_tail(&packet->list, &queue->txqueue); + queue->nr_txfree--; + queue->nr_tx_packets++; + B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS); + + tasklet_schedule(&queue->txtask); + + return 0; +} + +void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ + struct b43legacy_pioqueue *queue; + struct b43legacy_pio_txpacket *packet; + + queue = parse_cookie(dev, status->cookie, &packet); + B43legacy_WARN_ON(!queue); + + queue->tx_devq_packets--; + queue->tx_devq_used -= (packet->skb->len + + sizeof(struct b43legacy_txhdr_fw3)); + + if (status->acked) + packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; + packet->txstat.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, + &(packet->txstat)); + packet->skb = NULL; + + free_txpacket(packet, 1); + /* If there are packets on the txqueue, poke the tasklet + * to transmit them. + */ + if (!list_empty(&queue->txqueue)) + tasklet_schedule(&queue->txtask); +} + +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43legacy_pio *pio = &dev->pio; + struct b43legacy_pioqueue *queue; + struct ieee80211_tx_queue_stats_data *data; + + queue = pio->queue1; + data = &(stats->data[0]); + data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; + data->limit = B43legacy_PIO_MAXTXPACKETS; + data->count = queue->nr_tx_packets; +} + +static void pio_rx_error(struct b43legacy_pioqueue *queue, + int clear_buffers, + const char *error) +{ + int i; + + b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error); + b43legacy_pio_write(queue, B43legacy_PIO_RXCTL, + B43legacy_PIO_RXCTL_READY); + if (clear_buffers) { + B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE); + for (i = 0; i < 15; i++) { + /* Dummy read. */ + b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + } + } +} + +void b43legacy_pio_rx(struct b43legacy_pioqueue *queue) +{ + __le16 preamble[21] = { 0 }; + struct b43legacy_rxhdr_fw3 *rxhdr; + u16 tmp; + u16 len; + u16 macstat; + int i; + int preamble_readwords; + struct sk_buff *skb; + + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL); + if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE)) + return; + b43legacy_pio_write(queue, B43legacy_PIO_RXCTL, + B43legacy_PIO_RXCTL_DATAAVAILABLE); + + for (i = 0; i < 10; i++) { + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL); + if (tmp & B43legacy_PIO_RXCTL_READY) + goto data_ready; + udelay(10); + } + b43legacydbg(queue->dev->wl, "PIO RX timed out\n"); + return; +data_ready: + + len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + if (unlikely(len > 0x700)) { + pio_rx_error(queue, 0, "len > 0x700"); + return; + } + if (unlikely(len == 0 && queue->mmio_base != + B43legacy_MMIO_PIO4_BASE)) { + pio_rx_error(queue, 0, "len == 0"); + return; + } + preamble[0] = cpu_to_le16(len); + if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) + preamble_readwords = 14 / sizeof(u16); + else + preamble_readwords = 18 / sizeof(u16); + for (i = 0; i < preamble_readwords; i++) { + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + preamble[i + 1] = cpu_to_le16(tmp); + } + rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble; + macstat = le16_to_cpu(rxhdr->mac_status); + if (macstat & B43legacy_RX_MAC_FCSERR) { + pio_rx_error(queue, + (queue->mmio_base == B43legacy_MMIO_PIO1_BASE), + "Frame FCS error"); + return; + } + if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) { + /* We received an xmit status. */ + struct b43legacy_hwtxstatus *hw; + + hw = (struct b43legacy_hwtxstatus *)(preamble + 1); + b43legacy_handle_hwtxstatus(queue->dev, hw); + + return; + } + + skb = dev_alloc_skb(len); + if (unlikely(!skb)) { + pio_rx_error(queue, 1, "OOM"); + return; + } + skb_put(skb, len); + for (i = 0; i < len - 1; i += 2) { + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); + } + if (len % 2) { + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + skb->data[len - 1] = (tmp & 0x00FF); + } + b43legacy_rx(queue->dev, skb, rxhdr); +} + +void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue) +{ + b43legacy_power_saving_ctl_bits(queue->dev, -1, 1); + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + b43legacy_pio_read(queue, B43legacy_PIO_TXCTL) + | B43legacy_PIO_TXCTL_SUSPEND); +} + +void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue) +{ + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + b43legacy_pio_read(queue, B43legacy_PIO_TXCTL) + & ~B43legacy_PIO_TXCTL_SUSPEND); + b43legacy_power_saving_ctl_bits(queue->dev, -1, -1); + tasklet_schedule(&queue->txtask); +} + +void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev) +{ + struct b43legacy_pio *pio; + + B43legacy_WARN_ON(!b43legacy_using_pio(dev)); + pio = &dev->pio; + pio->queue0->tx_frozen = 1; + pio->queue1->tx_frozen = 1; + pio->queue2->tx_frozen = 1; + pio->queue3->tx_frozen = 1; +} + +void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev) +{ + struct b43legacy_pio *pio; + + B43legacy_WARN_ON(!b43legacy_using_pio(dev)); + pio = &dev->pio; + pio->queue0->tx_frozen = 0; + pio->queue1->tx_frozen = 0; + pio->queue2->tx_frozen = 0; + pio->queue3->tx_frozen = 0; + if (!list_empty(&pio->queue0->txqueue)) + tasklet_schedule(&pio->queue0->txtask); + if (!list_empty(&pio->queue1->txqueue)) + tasklet_schedule(&pio->queue1->txtask); + if (!list_empty(&pio->queue2->txqueue)) + tasklet_schedule(&pio->queue2->txtask); + if (!list_empty(&pio->queue3->txqueue)) + tasklet_schedule(&pio->queue3->txtask); +} diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h new file mode 100644 index 000000000000..5bfed0c40030 --- /dev/null +++ b/drivers/net/wireless/b43legacy/pio.h @@ -0,0 +1,172 @@ +#ifndef B43legacy_PIO_H_ +#define B43legacy_PIO_H_ + +#include "b43legacy.h" + +#include +#include +#include + + +#define B43legacy_PIO_TXCTL 0x00 +#define B43legacy_PIO_TXDATA 0x02 +#define B43legacy_PIO_TXQBUFSIZE 0x04 +#define B43legacy_PIO_RXCTL 0x08 +#define B43legacy_PIO_RXDATA 0x0A + +#define B43legacy_PIO_TXCTL_WRITELO (1 << 0) +#define B43legacy_PIO_TXCTL_WRITEHI (1 << 1) +#define B43legacy_PIO_TXCTL_COMPLETE (1 << 2) +#define B43legacy_PIO_TXCTL_INIT (1 << 3) +#define B43legacy_PIO_TXCTL_SUSPEND (1 << 7) + +#define B43legacy_PIO_RXCTL_DATAAVAILABLE (1 << 0) +#define B43legacy_PIO_RXCTL_READY (1 << 1) + +/* PIO constants */ +#define B43legacy_PIO_MAXTXDEVQPACKETS 31 +#define B43legacy_PIO_TXQADJUST 80 + +/* PIO tuning knobs */ +#define B43legacy_PIO_MAXTXPACKETS 256 + + + +#ifdef CONFIG_B43LEGACY_PIO + + +struct b43legacy_pioqueue; +struct b43legacy_xmitstatus; + +struct b43legacy_pio_txpacket { + struct b43legacy_pioqueue *queue; + struct sk_buff *skb; + struct ieee80211_tx_status txstat; + struct list_head list; +}; + +#define pio_txpacket_getindex(packet) ((int)((packet) - \ + (packet)->queue->tx_packets_cache)) + +struct b43legacy_pioqueue { + struct b43legacy_wldev *dev; + u16 mmio_base; + + bool tx_suspended; + bool tx_frozen; + bool need_workarounds; /* Workarounds needed for core.rev < 3 */ + + /* Adjusted size of the device internal TX buffer. */ + u16 tx_devq_size; + /* Used octets of the device internal TX buffer. */ + u16 tx_devq_used; + /* Used packet slots in the device internal TX buffer. */ + u8 tx_devq_packets; + /* Packets from the txfree list can + * be taken on incoming TX requests. + */ + struct list_head txfree; + unsigned int nr_txfree; + /* Packets on the txqueue are queued, + * but not completely written to the chip, yet. + */ + struct list_head txqueue; + /* Packets on the txrunning queue are completely + * posted to the device. We are waiting for the txstatus. + */ + struct list_head txrunning; + /* Total number or packets sent. + * (This counter can obviously wrap). + */ + unsigned int nr_tx_packets; + struct tasklet_struct txtask; + struct b43legacy_pio_txpacket + tx_packets_cache[B43legacy_PIO_MAXTXPACKETS]; +}; + +static inline +u16 b43legacy_pio_read(struct b43legacy_pioqueue *queue, + u16 offset) +{ + return b43legacy_read16(queue->dev, queue->mmio_base + offset); +} + +static inline +void b43legacy_pio_write(struct b43legacy_pioqueue *queue, + u16 offset, u16 value) +{ + b43legacy_write16(queue->dev, queue->mmio_base + offset, value); + mmiowb(); +} + + +int b43legacy_pio_init(struct b43legacy_wldev *dev); +void b43legacy_pio_free(struct b43legacy_wldev *dev); + +int b43legacy_pio_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl); +void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status); +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats); +void b43legacy_pio_rx(struct b43legacy_pioqueue *queue); + +/* Suspend TX queue in hardware. */ +void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue); +void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue); +/* Suspend (freeze) the TX tasklet (software level). */ +void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev); +void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev); + +#else /* CONFIG_B43LEGACY_PIO */ + +static inline +int b43legacy_pio_init(struct b43legacy_wldev *dev) +{ + return 0; +} +static inline +void b43legacy_pio_free(struct b43legacy_wldev *dev) +{ +} +static inline +int b43legacy_pio_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline +void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ +} +static inline +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline +void b43legacy_pio_rx(struct b43legacy_pioqueue *queue) +{ +} +static inline +void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue) +{ +} +static inline +void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue) +{ +} +static inline +void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev) +{ +} +static inline +void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev) +{ +} + +#endif /* CONFIG_B43LEGACY_PIO */ +#endif /* B43legacy_PIO_H_ */ diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c new file mode 100644 index 000000000000..2a11ee63f400 --- /dev/null +++ b/drivers/net/wireless/b43legacy/radio.c @@ -0,0 +1,2131 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + Copyright (c) 2007 Larry Finger + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "b43legacy.h" +#include "main.h" +#include "phy.h" +#include "radio.h" +#include "ilt.h" + + +/* Table for b43legacy_radio_calibrationvalue() */ +static const u16 rcc_table[16] = { + 0x0002, 0x0003, 0x0001, 0x000F, + 0x0006, 0x0007, 0x0005, 0x000F, + 0x000A, 0x000B, 0x0009, 0x000F, + 0x000E, 0x000F, 0x000D, 0x000F, +}; + +/* Reverse the bits of a 4bit value. + * Example: 1101 is flipped 1011 + */ +static u16 flip_4bit(u16 value) +{ + u16 flipped = 0x0000; + + B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000)); + + flipped |= (value & 0x0001) << 3; + flipped |= (value & 0x0002) << 1; + flipped |= (value & 0x0004) >> 1; + flipped |= (value & 0x0008) >> 3; + + return flipped; +} + +/* Get the freq, as it has to be written to the device. */ +static inline +u16 channel2freq_bg(u8 channel) +{ + /* Frequencies are given as frequencies_bg[index] + 2.4GHz + * Starting with channel 1 + */ + static const u16 frequencies_bg[14] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, + }; + + if (unlikely(channel < 1 || channel > 14)) { + printk(KERN_INFO "b43legacy: Channel %d is out of range\n", + channel); + dump_stack(); + return 2412; + } + + return frequencies_bg[channel - 1]; +} + +void b43legacy_radio_lock(struct b43legacy_wldev *dev) +{ + u32 status; + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + status |= B43legacy_SBF_RADIOREG_LOCK; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); + mmiowb(); + udelay(10); +} + +void b43legacy_radio_unlock(struct b43legacy_wldev *dev) +{ + u32 status; + + b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */ + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + status &= ~B43legacy_SBF_RADIOREG_LOCK; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); + mmiowb(); +} + +u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset) +{ + struct b43legacy_phy *phy = &dev->phy; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + if (phy->radio_ver == 0x2053) { + if (offset < 0x70) + offset += 0x80; + else if (offset < 0x80) + offset += 0x70; + } else if (phy->radio_ver == 0x2050) + offset |= 0x80; + else + B43legacy_WARN_ON(1); + break; + case B43legacy_PHYTYPE_G: + offset |= 0x80; + break; + default: + B43legacy_BUG_ON(1); + } + + b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset); + return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW); +} + +void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val) +{ + b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val); +} + +static void b43legacy_set_all_gains(struct b43legacy_wldev *dev, + s16 first, s16 second, s16 third) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 i; + u16 start = 0x08; + u16 end = 0x18; + u16 offset = 0x0400; + u16 tmp; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x10; + end = 0x20; + } + + for (i = 0; i < 4; i++) + b43legacy_ilt_write(dev, offset + i, first); + + for (i = start; i < end; i++) + b43legacy_ilt_write(dev, offset + i, second); + + if (third != -1) { + tmp = ((u16)third << 14) | ((u16)third << 6); + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF) + | tmp); + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF) + | tmp); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF) + | tmp); + } + b43legacy_dummy_transmission(dev); +} + +static void b43legacy_set_original_gains(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 i; + u16 tmp; + u16 offset = 0x0400; + u16 start = 0x0008; + u16 end = 0x0018; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x0010; + end = 0x0020; + } + + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + b43legacy_ilt_write(dev, offset + i, tmp); + } + + for (i = start; i < end; i++) + b43legacy_ilt_write(dev, offset + i, i - start); + + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF) + | 0x4040); + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF) + | 0x4040); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF) + | 0x4000); + b43legacy_dummy_transmission(dev); +} + +/* Synthetic PU workaround */ +static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev, + u8 channel) +{ + struct b43legacy_phy *phy = &dev->phy; + + might_sleep(); + + if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) + /* We do not need the workaround. */ + return; + + if (channel <= 10) + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + else + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, + channel2freq_bg(channel)); + msleep(1); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, + channel2freq_bg(channel)); +} + +u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel) +{ + struct b43legacy_phy *phy = &dev->phy; + u8 ret = 0; + u16 saved; + u16 rssi; + u16 temp; + int i; + int j = 0; + + saved = b43legacy_phy_read(dev, 0x0403); + b43legacy_radio_selectchannel(dev, channel, 0); + b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); + if (phy->aci_hw_rssi) + rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0; i < 100; i++) { + temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + b43legacy_phy_write(dev, 0x0403, saved); + + return ret; +} + +u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u8 ret[13]; + unsigned int channel = phy->channel; + unsigned int i; + unsigned int j; + unsigned int start; + unsigned int end; + unsigned long phylock_flags; + + if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + b43legacy_phy_lock(dev, phylock_flags); + b43legacy_radio_lock(dev); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) & 0xFFFC); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + & 0x7FFF); + b43legacy_set_all_gains(dev, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i-1] = b43legacy_radio_aci_detect(dev, i); + } + b43legacy_radio_selectchannel(dev, channel, 0); + b43legacy_phy_write(dev, 0x0802, + (b43legacy_phy_read(dev, 0x0802) & 0xFFFC) + | 0x0003); + b43legacy_phy_write(dev, 0x0403, + b43legacy_phy_read(dev, 0x0403) & 0xFFF8); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + | 0x8000); + b43legacy_set_original_gains(dev); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + b43legacy_radio_unlock(dev); + b43legacy_phy_unlock(dev, phylock_flags); + + return ret[channel - 1]; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val) +{ + b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset); + mmiowb(); + b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset) +{ + u16 val; + + b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset); + val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA); + + return (s16)val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = b43legacy_nrssi_hw_read(dev, i); + tmp -= val; + tmp = limit_value(tmp, -32, 31); + b43legacy_nrssi_hw_write(dev, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + s16 i; + s16 delta; + s32 tmp; + + delta = 0x1F - phy->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * phy->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = limit_value(tmp, 0, 0x3F); + phy->nrssi_lt[i] = tmp; + } +} + +static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = b43legacy_phy_read(dev, 0x0001); + backup[1] = b43legacy_phy_read(dev, 0x0811); + backup[2] = b43legacy_phy_read(dev, 0x0812); + backup[3] = b43legacy_phy_read(dev, 0x0814); + backup[4] = b43legacy_phy_read(dev, 0x0815); + backup[5] = b43legacy_phy_read(dev, 0x005A); + backup[6] = b43legacy_phy_read(dev, 0x0059); + backup[7] = b43legacy_phy_read(dev, 0x0058); + backup[8] = b43legacy_phy_read(dev, 0x000A); + backup[9] = b43legacy_phy_read(dev, 0x0003); + backup[10] = b43legacy_radio_read16(dev, 0x007A); + backup[11] = b43legacy_radio_read16(dev, 0x0043); + + b43legacy_phy_write(dev, 0x0429, + b43legacy_phy_read(dev, 0x0429) & 0x7FFF); + b43legacy_phy_write(dev, 0x0001, + (b43legacy_phy_read(dev, 0x0001) & 0x3FFF) + | 0x4000); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x000C); + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) & 0xFFF3) + | 0x0004); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = b43legacy_phy_read(dev, 0x002E); + backup[13] = b43legacy_phy_read(dev, 0x002F); + backup[14] = b43legacy_phy_read(dev, 0x080F); + backup[15] = b43legacy_phy_read(dev, 0x0810); + backup[16] = b43legacy_phy_read(dev, 0x0801); + backup[17] = b43legacy_phy_read(dev, 0x0060); + backup[18] = b43legacy_phy_read(dev, 0x0014); + backup[19] = b43legacy_phy_read(dev, 0x0478); + + b43legacy_phy_write(dev, 0x002E, 0); + b43legacy_phy_write(dev, 0x002F, 0); + b43legacy_phy_write(dev, 0x080F, 0); + b43legacy_phy_write(dev, 0x0810, 0); + b43legacy_phy_write(dev, 0x0478, + b43legacy_phy_read(dev, 0x0478) | 0x0100); + b43legacy_phy_write(dev, 0x0801, + b43legacy_phy_read(dev, 0x0801) | 0x0040); + b43legacy_phy_write(dev, 0x0060, + b43legacy_phy_read(dev, 0x0060) | 0x0040); + b43legacy_phy_write(dev, 0x0014, + b43legacy_phy_read(dev, 0x0014) | 0x0200); + } + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) | 0x0070); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + b43legacy_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) + & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x007F); + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0001); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFE); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x000C); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) | 0x000C); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x0030); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) | 0x0030); + b43legacy_phy_write(dev, 0x005A, 0x0480); + b43legacy_phy_write(dev, 0x0059, 0x0810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + if (phy->analog == 0) + b43legacy_phy_write(dev, 0x0003, 0x0122); + else + b43legacy_phy_write(dev, 0x000A, + b43legacy_phy_read(dev, 0x000A) + | 0x2000); + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0004); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFB); + b43legacy_phy_write(dev, 0x0003, + (b43legacy_phy_read(dev, 0x0003) & 0xFF9F) + | 0x0040); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x000F); + b43legacy_set_all_gains(dev, 3, 0, 1); + b43legacy_radio_write16(dev, 0x0043, + (b43legacy_radio_read16(dev, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + b43legacy_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> + 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + b43legacy_radio_write16(dev, 0x007B, saved); + + if (phy->rev >= 6) { + b43legacy_phy_write(dev, 0x002E, backup[12]); + b43legacy_phy_write(dev, 0x002F, backup[13]); + b43legacy_phy_write(dev, 0x080F, backup[14]); + b43legacy_phy_write(dev, 0x0810, backup[15]); + } + b43legacy_phy_write(dev, 0x0814, backup[3]); + b43legacy_phy_write(dev, 0x0815, backup[4]); + b43legacy_phy_write(dev, 0x005A, backup[5]); + b43legacy_phy_write(dev, 0x0059, backup[6]); + b43legacy_phy_write(dev, 0x0058, backup[7]); + b43legacy_phy_write(dev, 0x000A, backup[8]); + b43legacy_phy_write(dev, 0x0003, backup[9]); + b43legacy_radio_write16(dev, 0x0043, backup[11]); + b43legacy_radio_write16(dev, 0x007A, backup[10]); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2); + b43legacy_phy_write(dev, 0x0429, + b43legacy_phy_read(dev, 0x0429) | 0x8000); + b43legacy_set_original_gains(dev); + if (phy->rev >= 6) { + b43legacy_phy_write(dev, 0x0801, backup[16]); + b43legacy_phy_write(dev, 0x0060, backup[17]); + b43legacy_phy_write(dev, 0x0014, backup[18]); + b43legacy_phy_write(dev, 0x0478, backup[19]); + } + b43legacy_phy_write(dev, 0x0001, backup[0]); + b43legacy_phy_write(dev, 0x0812, backup[2]); + b43legacy_phy_write(dev, 0x0811, backup[1]); +} + +void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0; + s16 nrssi1; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + backup[0] = b43legacy_radio_read16(dev, 0x007A); + backup[1] = b43legacy_radio_read16(dev, 0x0052); + backup[2] = b43legacy_radio_read16(dev, 0x0043); + backup[3] = b43legacy_phy_read(dev, 0x0030); + backup[4] = b43legacy_phy_read(dev, 0x0026); + backup[5] = b43legacy_phy_read(dev, 0x0015); + backup[6] = b43legacy_phy_read(dev, 0x002A); + backup[7] = b43legacy_phy_read(dev, 0x0020); + backup[8] = b43legacy_phy_read(dev, 0x005A); + backup[9] = b43legacy_phy_read(dev, 0x0059); + backup[10] = b43legacy_phy_read(dev, 0x0058); + backup[11] = b43legacy_read16(dev, 0x03E2); + backup[12] = b43legacy_read16(dev, 0x03E6); + backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); + + tmp = b43legacy_radio_read16(dev, 0x007A); + tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; + b43legacy_radio_write16(dev, 0x007A, tmp); + b43legacy_phy_write(dev, 0x0030, 0x00FF); + b43legacy_write16(dev, 0x03EC, 0x7F7F); + b43legacy_phy_write(dev, 0x0026, 0x0000); + b43legacy_phy_write(dev, 0x0015, + b43legacy_phy_read(dev, 0x0015) | 0x0020); + b43legacy_phy_write(dev, 0x002A, 0x08A3); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0080); + + nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x007F); + if (phy->analog >= 2) + b43legacy_write16(dev, 0x03E6, 0x0040); + else if (phy->analog == 0) + b43legacy_write16(dev, 0x03E6, 0x0122); + else + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) & 0x2000); + b43legacy_phy_write(dev, 0x0020, 0x3F3F); + b43legacy_phy_write(dev, 0x0015, 0xF330); + b43legacy_radio_write16(dev, 0x005A, 0x0060); + b43legacy_radio_write16(dev, 0x0043, + b43legacy_radio_read16(dev, 0x0043) + & 0x00F0); + b43legacy_phy_write(dev, 0x005A, 0x0480); + b43legacy_phy_write(dev, 0x0059, 0x0810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + udelay(20); + + nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027); + b43legacy_phy_write(dev, 0x0030, backup[3]); + b43legacy_radio_write16(dev, 0x007A, backup[0]); + b43legacy_write16(dev, 0x03E2, backup[11]); + b43legacy_phy_write(dev, 0x0026, backup[4]); + b43legacy_phy_write(dev, 0x0015, backup[5]); + b43legacy_phy_write(dev, 0x002A, backup[6]); + b43legacy_synth_pu_workaround(dev, phy->channel); + if (phy->analog != 0) + b43legacy_write16(dev, 0x03F4, backup[13]); + + b43legacy_phy_write(dev, 0x0020, backup[7]); + b43legacy_phy_write(dev, 0x005A, backup[8]); + b43legacy_phy_write(dev, 0x0059, backup[9]); + b43legacy_phy_write(dev, 0x0058, backup[10]); + b43legacy_radio_write16(dev, 0x0052, backup[1]); + b43legacy_radio_write16(dev, 0x0043, backup[2]); + + if (nrssi0 == nrssi1) + phy->nrssislope = 0x00010000; + else + phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + + if (nrssi0 <= -4) { + phy->nrssi[0] = nrssi0; + phy->nrssi[1] = nrssi1; + } + break; + case B43legacy_PHYTYPE_G: + if (phy->radio_rev >= 9) + return; + if (phy->radio_rev == 8) + b43legacy_calc_nrssi_offset(dev); + + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + & 0x7FFF); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) & 0xFFFC); + backup[7] = b43legacy_read16(dev, 0x03E2); + b43legacy_write16(dev, 0x03E2, + b43legacy_read16(dev, 0x03E2) | 0x8000); + backup[0] = b43legacy_radio_read16(dev, 0x007A); + backup[1] = b43legacy_radio_read16(dev, 0x0052); + backup[2] = b43legacy_radio_read16(dev, 0x0043); + backup[3] = b43legacy_phy_read(dev, 0x0015); + backup[4] = b43legacy_phy_read(dev, 0x005A); + backup[5] = b43legacy_phy_read(dev, 0x0059); + backup[6] = b43legacy_phy_read(dev, 0x0058); + backup[8] = b43legacy_read16(dev, 0x03E6); + backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = b43legacy_phy_read(dev, 0x002E); + backup[11] = b43legacy_phy_read(dev, 0x002F); + backup[12] = b43legacy_phy_read(dev, 0x080F); + backup[13] = b43legacy_phy_read(dev, + B43legacy_PHY_G_LO_CONTROL); + backup[14] = b43legacy_phy_read(dev, 0x0801); + backup[15] = b43legacy_phy_read(dev, 0x0060); + backup[16] = b43legacy_phy_read(dev, 0x0014); + backup[17] = b43legacy_phy_read(dev, 0x0478); + b43legacy_phy_write(dev, 0x002E, 0); + b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: case 6: case 7: + b43legacy_phy_write(dev, 0x0478, + b43legacy_phy_read(dev, + 0x0478) | 0x0100); + b43legacy_phy_write(dev, 0x0801, + b43legacy_phy_read(dev, + 0x0801) | 0x0040); + break; + case 3: case 5: + b43legacy_phy_write(dev, 0x0801, + b43legacy_phy_read(dev, + 0x0801) & 0xFFBF); + break; + } + b43legacy_phy_write(dev, 0x0060, + b43legacy_phy_read(dev, 0x0060) + | 0x0040); + b43legacy_phy_write(dev, 0x0014, + b43legacy_phy_read(dev, 0x0014) + | 0x0200); + } + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0070); + b43legacy_set_all_gains(dev, 0, 8, 0); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x00F7); + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0811, + (b43legacy_phy_read(dev, 0x0811) + & 0xFFCF) | 0x0030); + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) + & 0xFFCF) | 0x0010); + } + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0080); + udelay(20); + + nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x007F); + if (phy->analog >= 2) + b43legacy_phy_write(dev, 0x0003, + (b43legacy_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) | 0x2000); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x000F); + b43legacy_phy_write(dev, 0x0015, 0xF330); + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) + & 0xFFCF) | 0x0020); + b43legacy_phy_write(dev, 0x0811, + (b43legacy_phy_read(dev, 0x0811) + & 0xFFCF) | 0x0020); + } + + b43legacy_set_all_gains(dev, 3, 0, 1); + if (phy->radio_rev == 8) + b43legacy_radio_write16(dev, 0x0043, 0x001F); + else { + tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F; + b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060); + tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0; + b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009); + } + b43legacy_phy_write(dev, 0x005A, 0x0480); + b43legacy_phy_write(dev, 0x0059, 0x0810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + phy->nrssislope = 0x00010000; + else + phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + phy->nrssi[0] = nrssi1; + phy->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + b43legacy_phy_write(dev, 0x002E, backup[10]); + b43legacy_phy_write(dev, 0x002F, backup[11]); + b43legacy_phy_write(dev, 0x080F, backup[12]); + b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, + backup[13]); + } + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) + & 0xFFCF); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) + & 0xFFCF); + } + + b43legacy_radio_write16(dev, 0x007A, backup[0]); + b43legacy_radio_write16(dev, 0x0052, backup[1]); + b43legacy_radio_write16(dev, 0x0043, backup[2]); + b43legacy_write16(dev, 0x03E2, backup[7]); + b43legacy_write16(dev, 0x03E6, backup[8]); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]); + b43legacy_phy_write(dev, 0x0015, backup[3]); + b43legacy_phy_write(dev, 0x005A, backup[4]); + b43legacy_phy_write(dev, 0x0059, backup[5]); + b43legacy_phy_write(dev, 0x0058, backup[6]); + b43legacy_synth_pu_workaround(dev, phy->channel); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) | 0x0003); + b43legacy_set_original_gains(dev); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + | 0x8000); + if (phy->rev >= 3) { + b43legacy_phy_write(dev, 0x0801, backup[14]); + b43legacy_phy_write(dev, 0x0060, backup[15]); + b43legacy_phy_write(dev, 0x0014, backup[16]); + b43legacy_phy_write(dev, 0x0478, backup[17]); + } + b43legacy_nrssi_mem_update(dev); + b43legacy_calc_nrssi_threshold(dev); + break; + default: + B43legacy_BUG_ON(1); + } +} + +void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + s32 threshold; + s32 a; + s32 b; + s16 tmp16; + u16 tmp_u16; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: { + if (phy->radio_ver != 0x2050) + return; + if (!(dev->dev->bus->sprom.r1.boardflags_lo & + B43legacy_BFL_RSSI)) + return; + + if (phy->radio_rev >= 6) { + threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32; + threshold += 20 * (phy->nrssi[0] + 1); + threshold /= 40; + } else + threshold = phy->nrssi[1] - 5; + + threshold = limit_value(threshold, 0, 0x3E); + b43legacy_phy_read(dev, 0x0020); /* dummy read */ + b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8) + | 0x001C); + + if (phy->radio_rev >= 6) { + b43legacy_phy_write(dev, 0x0087, 0x0E0D); + b43legacy_phy_write(dev, 0x0086, 0x0C0B); + b43legacy_phy_write(dev, 0x0085, 0x0A09); + b43legacy_phy_write(dev, 0x0084, 0x0808); + b43legacy_phy_write(dev, 0x0083, 0x0808); + b43legacy_phy_write(dev, 0x0082, 0x0604); + b43legacy_phy_write(dev, 0x0081, 0x0302); + b43legacy_phy_write(dev, 0x0080, 0x0100); + } + break; + } + case B43legacy_PHYTYPE_G: + if (!phy->gmode || + !(dev->dev->bus->sprom.r1.boardflags_lo & + B43legacy_BFL_RSSI)) { + tmp16 = b43legacy_nrssi_hw_read(dev, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) + b43legacy_phy_write(dev, 0x048A, + (b43legacy_phy_read(dev, + 0x048A) & 0xF000) | 0x09EB); + else + b43legacy_phy_write(dev, 0x048A, + (b43legacy_phy_read(dev, + 0x048A) & 0xF000) | 0x0AED); + } else { + if (phy->interfmode == + B43legacy_RADIO_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!phy->aci_wlan_automatic && + phy->aci_enable) { + a = 0x13; + b = 0x12; + } else { + a = 0xE; + b = 0x11; + } + + a = a * (phy->nrssi[1] - phy->nrssi[0]); + a += (phy->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; + a = limit_value(a, -31, 31); + + b = b * (phy->nrssi[1] - phy->nrssi[0]); + b += (phy->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; + b = limit_value(b, -31, 31); + + tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000; + tmp_u16 |= ((u32)b & 0x0000003F); + tmp_u16 |= (((u32)a & 0x0000003F) << 6); + b43legacy_phy_write(dev, 0x048A, tmp_u16); + } + break; + default: + B43legacy_BUG_ON(1); + } +} + +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 *_stackptr, size_t *stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000)); + B43legacy_WARN_ON(!((id & 0xF8) == 0x00)); + *stackptr = offset; + *stackptr |= ((u32)id) << 13; + *stackptr |= ((u32)value) << 16; + (*stackidx)++; + B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE)); +} + +static u16 _stack_restore(u32 *stackptr, + u8 id, u16 offset) +{ + size_t i; + + B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000)); + B43legacy_WARN_ON(!((id & 0xF8) == 0x00)); + for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00001FFF) != offset) + continue; + if (((*stackptr & 0x00007000) >> 13) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + B43legacy_BUG_ON(1); + + return 0; +} + +#define phy_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + b43legacy_phy_read(dev, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + b43legacy_phy_write(dev, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + b43legacy_radio_read16(dev, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + b43legacy_radio_write16(dev, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ilt_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset), \ + b43legacy_ilt_read(dev, (offset))); \ + } while (0) +#define ilt_stackrestore(offset) \ + do { \ + b43legacy_ilt_write(dev, (offset), \ + _stack_restore(stack, 0x3, \ + (offset))); \ + } while (0) + +static void +b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev, + int mode) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 tmp; + u16 flipped; + u32 tmp32; + size_t stackidx = 0; + u32 *stack = phy->interfstack; + + switch (mode) { + case B43legacy_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) + | 0x0800); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) & ~0x4000); + break; + } + radio_stacksave(0x0078); + tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = flip_4bit(flipped); + flipped = (flipped << 1) | 0x0020; + b43legacy_radio_write16(dev, 0x0078, flipped); + + b43legacy_calc_nrssi_threshold(dev); + + phy_stacksave(0x0406); + b43legacy_phy_write(dev, 0x0406, 0x7E28); + + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) | 0x0800); + b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, + b43legacy_phy_read(dev, + B43legacy_PHY_RADIO_BITFIELD) | 0x1000); + + phy_stacksave(0x04A0); + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0) + | 0x0008); + phy_stacksave(0x04A1); + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0) + | 0x0605); + phy_stacksave(0x04A2); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0) + | 0x0204); + phy_stacksave(0x04A8); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0) + | 0x0803); + phy_stacksave(0x04AB); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0) + | 0x0605); + + phy_stacksave(0x04A7); + b43legacy_phy_write(dev, 0x04A7, 0x0002); + phy_stacksave(0x04A3); + b43legacy_phy_write(dev, 0x04A3, 0x287A); + phy_stacksave(0x04A9); + b43legacy_phy_write(dev, 0x04A9, 0x2027); + phy_stacksave(0x0493); + b43legacy_phy_write(dev, 0x0493, 0x32F5); + phy_stacksave(0x04AA); + b43legacy_phy_write(dev, 0x04AA, 0x2027); + phy_stacksave(0x04AC); + b43legacy_phy_write(dev, 0x04AC, 0x32F5); + break; + case B43legacy_RADIO_INTERFMODE_MANUALWLAN: + if (b43legacy_phy_read(dev, 0x0033) & 0x0800) + break; + + phy->aci_enable = 1; + + phy_stacksave(B43legacy_PHY_RADIO_BITFIELD); + phy_stacksave(B43legacy_PHY_G_CRS); + if (phy->rev < 2) + phy_stacksave(0x0406); + else { + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); + } + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ilt_stacksave(0x1A00 + 0x2); + ilt_stacksave(0x1A00 + 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); + + b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, + b43legacy_phy_read(dev, + B43legacy_PHY_RADIO_BITFIELD) & ~0x1000); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + (b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) + & 0xFFFC) | 0x0002); + + b43legacy_phy_write(dev, 0x0033, 0x0800); + b43legacy_phy_write(dev, 0x04A3, 0x2027); + b43legacy_phy_write(dev, 0x04A9, 0x1CA8); + b43legacy_phy_write(dev, 0x0493, 0x287A); + b43legacy_phy_write(dev, 0x04AA, 0x1CA8); + b43legacy_phy_write(dev, 0x04AC, 0x287A); + + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) + & 0xFFC0) | 0x001A); + b43legacy_phy_write(dev, 0x04A7, 0x000D); + + if (phy->rev < 2) + b43legacy_phy_write(dev, 0x0406, 0xFF0D); + else if (phy->rev == 2) { + b43legacy_phy_write(dev, 0x04C0, 0xFFFF); + b43legacy_phy_write(dev, 0x04C1, 0x00A9); + } else { + b43legacy_phy_write(dev, 0x04C0, 0x00C1); + b43legacy_phy_write(dev, 0x04C1, 0x0059); + } + + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) + & 0xC0FF) | 0x1800); + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) + & 0xFFC0) | 0x0015); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) + & 0xCFFF) | 0x1000); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) + & 0xF0FF) | 0x0A00); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xCFFF) | 0x1000); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0800); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xFFCF) | 0x0010); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xFFF0) | 0x0005); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) + & 0xFFCF) | 0x0010); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) + & 0xFFF0) | 0x0006); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0800); + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0500); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x000B); + + if (phy->rev >= 3) { + b43legacy_phy_write(dev, 0x048A, + b43legacy_phy_read(dev, 0x048A) + & ~0x8000); + b43legacy_phy_write(dev, 0x0415, + (b43legacy_phy_read(dev, 0x0415) + & 0x8000) | 0x36D8); + b43legacy_phy_write(dev, 0x0416, + (b43legacy_phy_read(dev, 0x0416) + & 0x8000) | 0x36D8); + b43legacy_phy_write(dev, 0x0417, + (b43legacy_phy_read(dev, 0x0417) + & 0xFE00) | 0x016D); + } else { + b43legacy_phy_write(dev, 0x048A, + b43legacy_phy_read(dev, 0x048A) + | 0x1000); + b43legacy_phy_write(dev, 0x048A, + (b43legacy_phy_read(dev, 0x048A) + & 0x9FFF) | 0x2000); + tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET); + if (!(tmp32 & 0x800)) { + tmp32 |= 0x800; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + tmp32); + } + } + if (phy->rev >= 2) + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) + | 0x0800); + b43legacy_phy_write(dev, 0x048C, + (b43legacy_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + b43legacy_phy_write(dev, 0x04AE, + (b43legacy_phy_read(dev, 0x04AE) + & 0xFF00) | 0x007F); + b43legacy_phy_write(dev, 0x04AD, + (b43legacy_phy_read(dev, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F); + b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F); + b43legacy_phy_write(dev, 0x04AD, + b43legacy_phy_read(dev, 0x04AD) + & 0x00FF); + } + b43legacy_calc_nrssi_slope(dev); + break; + default: + B43legacy_BUG_ON(1); + } +} + +static void +b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev, + int mode) +{ + struct b43legacy_phy *phy = &dev->phy; + u32 tmp32; + u32 *stack = phy->interfstack; + + switch (mode) { + case B43legacy_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) + & ~0x0800); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) | 0x4000); + break; + } + phy_stackrestore(0x0078); + b43legacy_calc_nrssi_threshold(dev); + phy_stackrestore(0x0406); + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) & ~0x0800); + if (!dev->bad_frames_preempt) + b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, + b43legacy_phy_read(dev, + B43legacy_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + break; + case B43legacy_RADIO_INTERFMODE_MANUALWLAN: + if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800)) + break; + + phy->aci_enable = 0; + + phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD); + phy_stackrestore(B43legacy_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ilt_stackrestore(0x1A00 + 0x2); + ilt_stackrestore(0x1A00 + 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET); + if (tmp32 & 0x800) { + tmp32 &= ~0x800; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + tmp32); + } + b43legacy_calc_nrssi_slope(dev); + break; + default: + B43legacy_BUG_ON(1); + } +} + +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ilt_stacksave +#undef ilt_stackrestore + +int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev, + int mode) +{ + struct b43legacy_phy *phy = &dev->phy; + int currentmode; + + if ((phy->type != B43legacy_PHYTYPE_G) || + (phy->rev == 0) || (!phy->gmode)) + return -ENODEV; + + phy->aci_wlan_automatic = 0; + switch (mode) { + case B43legacy_RADIO_INTERFMODE_AUTOWLAN: + phy->aci_wlan_automatic = 1; + if (phy->aci_enable) + mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN; + else + mode = B43legacy_RADIO_INTERFMODE_NONE; + break; + case B43legacy_RADIO_INTERFMODE_NONE: + case B43legacy_RADIO_INTERFMODE_NONWLAN: + case B43legacy_RADIO_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = phy->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != B43legacy_RADIO_INTERFMODE_NONE) + b43legacy_radio_interference_mitigation_disable(dev, + currentmode); + + if (mode == B43legacy_RADIO_INTERFMODE_NONE) { + phy->aci_enable = 0; + phy->aci_hw_rssi = 0; + } else + b43legacy_radio_interference_mitigation_enable(dev, mode); + phy->interfmode = mode; + + return 0; +} + +u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev) +{ + u16 reg; + u16 index; + u16 ret; + + reg = b43legacy_radio_read16(dev, 0x0060); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) +static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 loop_or = 0; + u16 adj_loopback_gain = phy->loopback_gain[0]; + u8 loop; + u16 extern_lna_control; + + if (!phy->gmode) + return 0; + if (!has_loopback_gain(phy)) { + if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_EXTLNA)) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x0FB2; + case LPD(0, 0, 1): + return 0x00B2; + case LPD(1, 0, 1): + return 0x30B2; + case LPD(1, 0, 0): + return 0x30B3; + default: + B43legacy_BUG_ON(1); + } + } else { + switch (lpd) { + case LPD(0, 1, 1): + return 0x8FB2; + case LPD(0, 0, 1): + return 0x80B2; + case LPD(1, 0, 1): + return 0x20B2; + case LPD(1, 0, 0): + return 0x20B3; + default: + B43legacy_BUG_ON(1); + } + } + } else { + if (phy->radio_rev == 8) + adj_loopback_gain += 0x003E; + else + adj_loopback_gain += 0x0026; + if (adj_loopback_gain >= 0x46) { + adj_loopback_gain -= 0x46; + extern_lna_control = 0x3000; + } else if (adj_loopback_gain >= 0x3A) { + adj_loopback_gain -= 0x3A; + extern_lna_control = 0x2000; + } else if (adj_loopback_gain >= 0x2E) { + adj_loopback_gain -= 0x2E; + extern_lna_control = 0x1000; + } else { + adj_loopback_gain -= 0x10; + extern_lna_control = 0x0000; + } + for (loop = 0; loop < 16; loop++) { + u16 tmp = adj_loopback_gain - 6 * loop; + if (tmp < 6) + break; + } + + loop_or = (loop << 8) | extern_lna_control; + if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_EXTLNA) { + if (extern_lna_control) + loop_or |= 0x8000; + switch (lpd) { + case LPD(0, 1, 1): + return 0x8F92; + case LPD(0, 0, 1): + return (0x8092 | loop_or); + case LPD(1, 0, 1): + return (0x2092 | loop_or); + case LPD(1, 0, 0): + return (0x2093 | loop_or); + default: + B43legacy_BUG_ON(1); + } + } else { + switch (lpd) { + case LPD(0, 1, 1): + return 0x0F92; + case LPD(0, 0, 1): + case LPD(1, 0, 1): + return (0x0092 | loop_or); + case LPD(1, 0, 0): + return (0x0093 | loop_or); + default: + B43legacy_BUG_ON(1); + } + } + } + return 0; +} + +u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 backup[21] = { 0 }; + u16 ret; + u16 i; + u16 j; + u32 tmp1 = 0; + u32 tmp2 = 0; + + backup[0] = b43legacy_radio_read16(dev, 0x0043); + backup[14] = b43legacy_radio_read16(dev, 0x0051); + backup[15] = b43legacy_radio_read16(dev, 0x0052); + backup[1] = b43legacy_phy_read(dev, 0x0015); + backup[16] = b43legacy_phy_read(dev, 0x005A); + backup[17] = b43legacy_phy_read(dev, 0x0059); + backup[18] = b43legacy_phy_read(dev, 0x0058); + if (phy->type == B43legacy_PHYTYPE_B) { + backup[2] = b43legacy_phy_read(dev, 0x0030); + backup[3] = b43legacy_read16(dev, 0x03EC); + b43legacy_phy_write(dev, 0x0030, 0x00FF); + b43legacy_write16(dev, 0x03EC, 0x3F3F); + } else { + if (phy->gmode) { + backup[4] = b43legacy_phy_read(dev, 0x0811); + backup[5] = b43legacy_phy_read(dev, 0x0812); + backup[6] = b43legacy_phy_read(dev, 0x0814); + backup[7] = b43legacy_phy_read(dev, 0x0815); + backup[8] = b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS); + backup[9] = b43legacy_phy_read(dev, 0x0802); + b43legacy_phy_write(dev, 0x0814, + (b43legacy_phy_read(dev, 0x0814) + | 0x0003)); + b43legacy_phy_write(dev, 0x0815, + (b43legacy_phy_read(dev, 0x0815) + & 0xFFFC)); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + (b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) & 0x7FFF)); + b43legacy_phy_write(dev, 0x0802, + (b43legacy_phy_read(dev, 0x0802) + & 0xFFFC)); + if (phy->rev > 1) { /* loopback gain enabled */ + backup[19] = b43legacy_phy_read(dev, 0x080F); + backup[20] = b43legacy_phy_read(dev, 0x0810); + if (phy->rev >= 3) + b43legacy_phy_write(dev, 0x080F, + 0xC020); + else + b43legacy_phy_write(dev, 0x080F, + 0x8020); + b43legacy_phy_write(dev, 0x0810, 0x0000); + } + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(0, 1, 1))); + if (phy->rev < 7 || + !(dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_EXTLNA)) + b43legacy_phy_write(dev, 0x0811, 0x01B3); + else + b43legacy_phy_write(dev, 0x0811, 0x09B3); + } + } + b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, + (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO) + | 0x8000)); + backup[10] = b43legacy_phy_read(dev, 0x0035); + b43legacy_phy_write(dev, 0x0035, + (b43legacy_phy_read(dev, 0x0035) & 0xFF7F)); + backup[11] = b43legacy_read16(dev, 0x03E6); + backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); + + /* Initialization */ + if (phy->analog == 0) + b43legacy_write16(dev, 0x03E6, 0x0122); + else { + if (phy->analog >= 2) + b43legacy_phy_write(dev, 0x0003, + (b43legacy_phy_read(dev, 0x0003) + & 0xFFBF) | 0x0040); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + (b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) | 0x2000)); + } + + ret = b43legacy_radio_calibrationvalue(dev); + + if (phy->type == B43legacy_PHYTYPE_B) + b43legacy_radio_write16(dev, 0x0078, 0x0026); + + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(0, 1, 1))); + b43legacy_phy_write(dev, 0x0015, 0xBFAF); + b43legacy_phy_write(dev, 0x002B, 0x1403); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(0, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xBFA0); + b43legacy_radio_write16(dev, 0x0051, + (b43legacy_radio_read16(dev, 0x0051) + | 0x0004)); + if (phy->radio_rev == 8) + b43legacy_radio_write16(dev, 0x0043, 0x001F); + else { + b43legacy_radio_write16(dev, 0x0052, 0x0000); + b43legacy_radio_write16(dev, 0x0043, + (b43legacy_radio_read16(dev, 0x0043) + & 0xFFF0) | 0x0009); + } + b43legacy_phy_write(dev, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + b43legacy_phy_write(dev, 0x005A, 0x0480); + b43legacy_phy_write(dev, 0x0059, 0xC810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xAFB0); + udelay(10); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xEFB0); + udelay(10); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 0))); + b43legacy_phy_write(dev, 0x0015, 0xFFF0); + udelay(20); + tmp1 += b43legacy_phy_read(dev, 0x002D); + b43legacy_phy_write(dev, 0x0058, 0x0000); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xAFB0); + } + + tmp1++; + tmp1 >>= 9; + udelay(10); + b43legacy_phy_write(dev, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1) + | 0x0020); + backup[13] = b43legacy_radio_read16(dev, 0x0078); + udelay(10); + for (j = 0; j < 16; j++) { + b43legacy_phy_write(dev, 0x005A, 0x0D80); + b43legacy_phy_write(dev, 0x0059, 0xC810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xAFB0); + udelay(10); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xEFB0); + udelay(10); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 0))); + b43legacy_phy_write(dev, 0x0015, 0xFFF0); + udelay(10); + tmp2 += b43legacy_phy_read(dev, 0x002D); + b43legacy_phy_write(dev, 0x0058, 0x0000); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + b43legacy_phy_write(dev, 0x0015, backup[1]); + b43legacy_radio_write16(dev, 0x0051, backup[14]); + b43legacy_radio_write16(dev, 0x0052, backup[15]); + b43legacy_radio_write16(dev, 0x0043, backup[0]); + b43legacy_phy_write(dev, 0x005A, backup[16]); + b43legacy_phy_write(dev, 0x0059, backup[17]); + b43legacy_phy_write(dev, 0x0058, backup[18]); + b43legacy_write16(dev, 0x03E6, backup[11]); + if (phy->analog != 0) + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]); + b43legacy_phy_write(dev, 0x0035, backup[10]); + b43legacy_radio_selectchannel(dev, phy->channel, 1); + if (phy->type == B43legacy_PHYTYPE_B) { + b43legacy_phy_write(dev, 0x0030, backup[2]); + b43legacy_write16(dev, 0x03EC, backup[3]); + } else { + if (phy->gmode) { + b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, + (b43legacy_read16(dev, + B43legacy_MMIO_PHY_RADIO) & 0x7FFF)); + b43legacy_phy_write(dev, 0x0811, backup[4]); + b43legacy_phy_write(dev, 0x0812, backup[5]); + b43legacy_phy_write(dev, 0x0814, backup[6]); + b43legacy_phy_write(dev, 0x0815, backup[7]); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + backup[8]); + b43legacy_phy_write(dev, 0x0802, backup[9]); + if (phy->rev > 1) { + b43legacy_phy_write(dev, 0x080F, backup[19]); + b43legacy_phy_write(dev, 0x0810, backup[20]); + } + } + } + if (i >= 15) + ret = backup[13]; + + return ret; +} + +static inline +u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = b43legacy_radio_read16(dev, 0x001E); + int i; + int j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] | data_low[j])) { + b43legacy_phy_write(dev, 0x0069, (i - j) << 8 | + 0x00C0); + return; + } + } + } +} + +int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, + u8 channel, + int synthetic_pu_workaround) +{ + struct b43legacy_phy *phy = &dev->phy; + +/* TODO: Check if channel is valid - return -EINVAL if not */ + if (synthetic_pu_workaround) + b43legacy_synth_pu_workaround(dev, channel); + + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, + channel2freq_bg(channel)); + + if (channel == 14) { + if (dev->dev->bus->sprom.r1.country_code == 5) /* JAPAN) */ + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + b43legacy_shm_read32(dev, + B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET) + & ~(1 << 7)); + else + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + b43legacy_shm_read32(dev, + B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET) + | (1 << 7)); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) | (1 << 11)); + } else + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF); + + phy->channel = channel; + /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states + * that 2000 usecs might suffice. */ + msleep(8); + + return 0; +} + +void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val) +{ + u16 tmp; + + val <<= 8; + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val); +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ +static u16 b43legacy_get_txgain_base_band(u16 txpower) +{ + u16 ret; + + B43legacy_WARN_ON(txpower > 63); + + if (txpower >= 54) + ret = 2; + else if (txpower >= 49) + ret = 4; + else if (txpower >= 44) + ret = 5; + else + ret = 6; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ +static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower) +{ + u16 ret; + + B43legacy_WARN_ON(txpower > 63); + + if (txpower >= 32) + ret = 0; + else if (txpower >= 25) + ret = 1; + else if (txpower >= 20) + ret = 2; + else if (txpower >= 12) + ret = 3; + else + ret = 4; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ +static u16 b43legacy_get_txgain_dac(u16 txpower) +{ + u16 ret; + + B43legacy_WARN_ON(txpower > 63); + + if (txpower >= 54) + ret = txpower - 53; + else if (txpower >= 49) + ret = txpower - 42; + else if (txpower >= 44) + ret = txpower - 37; + else if (txpower >= 32) + ret = txpower - 32; + else if (txpower >= 25) + ret = txpower - 20; + else if (txpower >= 20) + ret = txpower - 13; + else if (txpower >= 12) + ret = txpower - 8; + else + ret = txpower; + + return ret; +} + +void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 pamp; + u16 base; + u16 dac; + u16 ilt; + + txpower = limit_value(txpower, 0, 63); + + pamp = b43legacy_get_txgain_freq_power_amp(txpower); + pamp <<= 5; + pamp &= 0x00E0; + b43legacy_phy_write(dev, 0x0019, pamp); + + base = b43legacy_get_txgain_base_band(txpower); + base &= 0x000F; + b43legacy_phy_write(dev, 0x0017, base | 0x0020); + + ilt = b43legacy_ilt_read(dev, 0x3001); + ilt &= 0x0007; + + dac = b43legacy_get_txgain_dac(txpower); + dac <<= 3; + dac |= ilt; + + b43legacy_ilt_write(dev, 0x3001, dac); + + phy->txpwr_offset = txpower; + + /* TODO: FuncPlaceholder (Adjust BB loft cancel) */ +} + +void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev, + u16 baseband_attenuation, + u16 radio_attenuation, + u16 txpower) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (baseband_attenuation == 0xFFFF) + baseband_attenuation = phy->bbatt; + if (radio_attenuation == 0xFFFF) + radio_attenuation = phy->rfatt; + if (txpower == 0xFFFF) + txpower = phy->txctl1; + phy->bbatt = baseband_attenuation; + phy->rfatt = radio_attenuation; + phy->txctl1 = txpower; + + B43legacy_WARN_ON(baseband_attenuation > 11); + if (phy->radio_rev < 6) + B43legacy_WARN_ON(radio_attenuation > 9); + else + B43legacy_WARN_ON(radio_attenuation > 31); + B43legacy_WARN_ON(txpower > 7); + + b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation); + b43legacy_radio_write16(dev, 0x0043, radio_attenuation); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064, + radio_attenuation); + if (phy->radio_ver == 0x2050) + b43legacy_radio_write16(dev, 0x0052, + (b43legacy_radio_read16(dev, 0x0052) + & ~0x0070) | ((txpower << 4) & 0x0070)); + /* FIXME: The spec is very weird and unclear here. */ + if (phy->type == B43legacy_PHYTYPE_G) + b43legacy_phy_lo_adjust(dev, 0); +} + +u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) + return 0; + return 2; +} + +u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 att = 0xFFFF; + + switch (phy->radio_ver) { + case 0x2053: + switch (phy->radio_rev) { + case 1: + att = 6; + break; + } + break; + case 0x2050: + switch (phy->radio_rev) { + case 0: + att = 5; + break; + case 1: + if (phy->type == B43legacy_PHYTYPE_G) { + if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x421 && + dev->dev->bus->boardinfo.rev >= 30) + att = 3; + else if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x416) + att = 3; + else + att = 1; + } else { + if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x421 && + dev->dev->bus->boardinfo.rev >= 30) + att = 7; + else + att = 6; + } + break; + case 2: + if (phy->type == B43legacy_PHYTYPE_G) { + if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x421 && + dev->dev->bus->boardinfo.rev >= 30) + att = 3; + else if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == + 0x416) + att = 5; + else if (dev->dev->bus->chip_id == 0x4320) + att = 4; + else + att = 3; + } else + att = 6; + break; + case 3: + att = 5; + break; + case 4: + case 5: + att = 1; + break; + case 6: + case 7: + att = 5; + break; + case 8: + att = 0x1A; + break; + case 9: + default: + att = 5; + } + } + if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x421) { + if (dev->dev->bus->boardinfo.rev < 0x43) + att = 2; + else if (dev->dev->bus->boardinfo.rev < 0x51) + att = 3; + } + if (att == 0xFFFF) + att = 5; + + return att; +} + +u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->radio_ver != 0x2050) + return 0; + if (phy->radio_rev == 1) + return 3; + if (phy->radio_rev < 6) + return 2; + if (phy->radio_rev == 8) + return 1; + return 0; +} + +void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + int err; + + might_sleep(); + + if (phy->radio_on) + return; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + b43legacy_phy_write(dev, 0x0015, 0x8000); + b43legacy_phy_write(dev, 0x0015, 0xCC00); + b43legacy_phy_write(dev, 0x0015, + (phy->gmode ? 0x00C0 : 0x0000)); + err = b43legacy_radio_selectchannel(dev, + B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1); + B43legacy_WARN_ON(err != 0); + break; + default: + B43legacy_BUG_ON(1); + } + phy->radio_on = 1; + b43legacydbg(dev->wl, "Radio turned on\n"); + b43legacy_leds_update(dev, 0); +} + +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) { + b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) + | 0x008C); + b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) + & 0xFF73); + } else + b43legacy_phy_write(dev, 0x0015, 0xAA00); + phy->radio_on = 0; + b43legacydbg(dev->wl, "Radio turned off\n"); + b43legacy_leds_update(dev, 0); +} + +void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058, + 0x7F7F); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a, + 0x7F7F); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070, + 0x7F7F); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072, + 0x7F7F); + break; + } +} diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h new file mode 100644 index 000000000000..6c6a203439e1 --- /dev/null +++ b/drivers/net/wireless/b43legacy/radio.h @@ -0,0 +1,98 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43legacy_RADIO_H_ +#define B43legacy_RADIO_H_ + +#include "b43legacy.h" + + +#define B43legacy_RADIO_DEFAULT_CHANNEL_BG 6 + +/* Force antenna 0. */ +#define B43legacy_RADIO_TXANTENNA_0 0 +/* Force antenna 1. */ +#define B43legacy_RADIO_TXANTENNA_1 1 +/* Use the RX antenna, that was selected for the most recently + * received good PLCP header. + */ +#define B43legacy_RADIO_TXANTENNA_LASTPLCP 3 +#define B43legacy_RADIO_TXANTENNA_DEFAULT B43legacy_RADIO_TXANTENNA_LASTPLCP + +#define B43legacy_RADIO_INTERFMODE_NONE 0 +#define B43legacy_RADIO_INTERFMODE_NONWLAN 1 +#define B43legacy_RADIO_INTERFMODE_MANUALWLAN 2 +#define B43legacy_RADIO_INTERFMODE_AUTOWLAN 3 + + +void b43legacy_radio_lock(struct b43legacy_wldev *dev); +void b43legacy_radio_unlock(struct b43legacy_wldev *dev); + +u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset); +void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val); + +u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev); + +void b43legacy_radio_turn_on(struct b43legacy_wldev *dev); +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev); + +int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel, + int synthetic_pu_workaround); + +void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower); +void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev, + u16 baseband_attenuation, u16 attenuation, + u16 txpower); + +u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev); +u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev); +u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev); + +void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val); + +void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev); + +u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel); +u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev); + +int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev, + int mode); + +void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev); +void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev); +s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset); +void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val); +void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val); +void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev); + +void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev); +u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev); + +#endif /* B43legacy_RADIO_H_ */ diff --git a/drivers/net/wireless/b43legacy/sysfs.c b/drivers/net/wireless/b43legacy/sysfs.c new file mode 100644 index 000000000000..56c384fa9b1f --- /dev/null +++ b/drivers/net/wireless/b43legacy/sysfs.c @@ -0,0 +1,238 @@ +/* + + Broadcom B43legacy wireless driver + + SYSFS support routines + + Copyright (c) 2006 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "sysfs.h" +#include "b43legacy.h" +#include "main.h" +#include "phy.h" +#include "radio.h" + +#include + + +#define GENERIC_FILESIZE 64 + + +static int get_integer(const char *buf, size_t count) +{ + char tmp[10 + 1] = { 0 }; + int ret = -EINVAL; + + if (count == 0) + goto out; + count = min(count, (size_t)10); + memcpy(tmp, buf, count); + ret = simple_strtol(tmp, NULL, 10); +out: + return ret; +} + +static int get_boolean(const char *buf, size_t count) +{ + if (count != 0) { + if (buf[0] == '1') + return 1; + if (buf[0] == '0') + return 0; + if (count >= 4 && memcmp(buf, "true", 4) == 0) + return 1; + if (count >= 5 && memcmp(buf, "false", 5) == 0) + return 0; + if (count >= 3 && memcmp(buf, "yes", 3) == 0) + return 1; + if (count >= 2 && memcmp(buf, "no", 2) == 0) + return 0; + if (count >= 2 && memcmp(buf, "on", 2) == 0) + return 1; + if (count >= 3 && memcmp(buf, "off", 3) == 0) + return 0; + } + return -EINVAL; +} + +static ssize_t b43legacy_attr_interfmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); + ssize_t count = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&wldev->wl->mutex); + + switch (wldev->phy.interfmode) { + case B43legacy_INTERFMODE_NONE: + count = snprintf(buf, PAGE_SIZE, "0 (No Interference" + " Mitigation)\n"); + break; + case B43legacy_INTERFMODE_NONWLAN: + count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference" + " Mitigation)\n"); + break; + case B43legacy_INTERFMODE_MANUALWLAN: + count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference" + " Mitigation)\n"); + break; + default: + B43legacy_WARN_ON(1); + } + + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static ssize_t b43legacy_attr_interfmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); + unsigned long flags; + int err; + int mode; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mode = get_integer(buf, count); + switch (mode) { + case 0: + mode = B43legacy_INTERFMODE_NONE; + break; + case 1: + mode = B43legacy_INTERFMODE_NONWLAN; + break; + case 2: + mode = B43legacy_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = B43legacy_INTERFMODE_AUTOWLAN; + break; + default: + return -EINVAL; + } + + mutex_lock(&wldev->wl->mutex); + spin_lock_irqsave(&wldev->wl->irq_lock, flags); + + err = b43legacy_radio_set_interference_mitigation(wldev, mode); + if (err) + b43legacyerr(wldev->wl, "Interference Mitigation not " + "supported by device\n"); + mmiowb(); + spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); + mutex_unlock(&wldev->wl->mutex); + + return err ? err : count; +} + +static DEVICE_ATTR(interference, 0644, + b43legacy_attr_interfmode_show, + b43legacy_attr_interfmode_store); + +static ssize_t b43legacy_attr_preamble_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); + ssize_t count; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&wldev->wl->mutex); + + if (wldev->short_preamble) + count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble" + " enabled)\n"); + else + count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble" + " disabled)\n"); + + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static ssize_t b43legacy_attr_preamble_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); + unsigned long flags; + int value; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + value = get_boolean(buf, count); + if (value < 0) + return value; + mutex_lock(&wldev->wl->mutex); + spin_lock_irqsave(&wldev->wl->irq_lock, flags); + + wldev->short_preamble = !!value; + + spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static DEVICE_ATTR(shortpreamble, 0644, + b43legacy_attr_preamble_show, + b43legacy_attr_preamble_store); + +int b43legacy_sysfs_register(struct b43legacy_wldev *wldev) +{ + struct device *dev = wldev->dev->dev; + int err; + + B43legacy_WARN_ON(b43legacy_status(wldev) != + B43legacy_STAT_INITIALIZED); + + err = device_create_file(dev, &dev_attr_interference); + if (err) + goto out; + err = device_create_file(dev, &dev_attr_shortpreamble); + if (err) + goto err_remove_interfmode; + +out: + return err; +err_remove_interfmode: + device_remove_file(dev, &dev_attr_interference); + goto out; +} + +void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev) +{ + struct device *dev = wldev->dev->dev; + + device_remove_file(dev, &dev_attr_shortpreamble); + device_remove_file(dev, &dev_attr_interference); +} diff --git a/drivers/net/wireless/b43legacy/sysfs.h b/drivers/net/wireless/b43legacy/sysfs.h new file mode 100644 index 000000000000..417d509803c7 --- /dev/null +++ b/drivers/net/wireless/b43legacy/sysfs.h @@ -0,0 +1,9 @@ +#ifndef B43legacy_SYSFS_H_ +#define B43legacy_SYSFS_H_ + +struct b43legacy_wldev; + +int b43legacy_sysfs_register(struct b43legacy_wldev *dev); +void b43legacy_sysfs_unregister(struct b43legacy_wldev *dev); + +#endif /* B43legacy_SYSFS_H_ */ diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c new file mode 100644 index 000000000000..fa1e65687a63 --- /dev/null +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -0,0 +1,642 @@ +/* + + Broadcom B43legacy wireless driver + + Transmission (TX/RX) related functions. + + Copyright (C) 2005 Martin Langer + Copyright (C) 2005 Stefano Brivio + Copyright (C) 2005, 2006 Michael Buesch + Copyright (C) 2005 Danny van Dyk + Copyright (C) 2005 Andreas Jaggi + Copyright (C) 2007 Larry Finger + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "xmit.h" +#include "phy.h" +#include "dma.h" +#include "pio.h" + + +/* Extract the bitrate out of a CCK PLCP header. */ +static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp) +{ + switch (plcp->raw[0]) { + case 0x0A: + return B43legacy_CCK_RATE_1MB; + case 0x14: + return B43legacy_CCK_RATE_2MB; + case 0x37: + return B43legacy_CCK_RATE_5MB; + case 0x6E: + return B43legacy_CCK_RATE_11MB; + } + B43legacy_BUG_ON(1); + return 0; +} + +/* Extract the bitrate out of an OFDM PLCP header. */ +static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp) +{ + switch (plcp->raw[0] & 0xF) { + case 0xB: + return B43legacy_OFDM_RATE_6MB; + case 0xF: + return B43legacy_OFDM_RATE_9MB; + case 0xA: + return B43legacy_OFDM_RATE_12MB; + case 0xE: + return B43legacy_OFDM_RATE_18MB; + case 0x9: + return B43legacy_OFDM_RATE_24MB; + case 0xD: + return B43legacy_OFDM_RATE_36MB; + case 0x8: + return B43legacy_OFDM_RATE_48MB; + case 0xC: + return B43legacy_OFDM_RATE_54MB; + } + B43legacy_BUG_ON(1); + return 0; +} + +u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case B43legacy_CCK_RATE_1MB: + return 0x0A; + case B43legacy_CCK_RATE_2MB: + return 0x14; + case B43legacy_CCK_RATE_5MB: + return 0x37; + case B43legacy_CCK_RATE_11MB: + return 0x6E; + } + B43legacy_BUG_ON(1); + return 0; +} + +u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case B43legacy_OFDM_RATE_6MB: + return 0xB; + case B43legacy_OFDM_RATE_9MB: + return 0xF; + case B43legacy_OFDM_RATE_12MB: + return 0xA; + case B43legacy_OFDM_RATE_18MB: + return 0xE; + case B43legacy_OFDM_RATE_24MB: + return 0x9; + case B43legacy_OFDM_RATE_36MB: + return 0xD; + case B43legacy_OFDM_RATE_48MB: + return 0x8; + case B43legacy_OFDM_RATE_54MB: + return 0xC; + } + B43legacy_BUG_ON(1); + return 0; +} + +void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + if (b43legacy_is_ofdm_rate(bitrate)) { + u16 d; + + d = b43legacy_plcp_get_ratecode_ofdm(bitrate); + B43legacy_WARN_ON(octets & 0xF000); + d |= (octets << 5); + *data = cpu_to_le32(d); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == B43legacy_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) + raw[1] = 0x84; + else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = b43legacy_plcp_get_ratecode_cck(bitrate); + } +} + +static u8 b43legacy_calc_fallback_rate(u8 bitrate) +{ + switch (bitrate) { + case B43legacy_CCK_RATE_1MB: + return B43legacy_CCK_RATE_1MB; + case B43legacy_CCK_RATE_2MB: + return B43legacy_CCK_RATE_1MB; + case B43legacy_CCK_RATE_5MB: + return B43legacy_CCK_RATE_2MB; + case B43legacy_CCK_RATE_11MB: + return B43legacy_CCK_RATE_5MB; + case B43legacy_OFDM_RATE_6MB: + return B43legacy_CCK_RATE_5MB; + case B43legacy_OFDM_RATE_9MB: + return B43legacy_OFDM_RATE_6MB; + case B43legacy_OFDM_RATE_12MB: + return B43legacy_OFDM_RATE_9MB; + case B43legacy_OFDM_RATE_18MB: + return B43legacy_OFDM_RATE_12MB; + case B43legacy_OFDM_RATE_24MB: + return B43legacy_OFDM_RATE_18MB; + case B43legacy_OFDM_RATE_36MB: + return B43legacy_OFDM_RATE_24MB; + case B43legacy_OFDM_RATE_48MB: + return B43legacy_OFDM_RATE_36MB; + case B43legacy_OFDM_RATE_54MB: + return B43legacy_OFDM_RATE_48MB; + } + B43legacy_BUG_ON(1); + return 0; +} + +static void generate_txhdr_fw3(struct b43legacy_wldev *dev, + struct b43legacy_txhdr_fw3 *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) +{ + const struct ieee80211_hdr *wlhdr; + int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + u16 fctl; + u8 rate; + u8 rate_fb; + int rate_ofdm; + int rate_fb_ofdm; + unsigned int plcp_fragment_len; + u32 mac_ctl = 0; + u16 phy_ctl = 0; + + wlhdr = (const struct ieee80211_hdr *)fragment_data; + fctl = le16_to_cpu(wlhdr->frame_control); + + memset(txhdr, 0, sizeof(*txhdr)); + + rate = txctl->tx_rate; + rate_ofdm = b43legacy_is_ofdm_rate(rate); + rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; + rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb); + + txhdr->mac_frame_ctl = wlhdr->frame_control; + memcpy(txhdr->tx_receiver, wlhdr->addr1, 6); + + /* Calculate duration for fallback rate */ + if ((rate_fb == rate) || + (wlhdr->duration_id & cpu_to_le16(0x8000)) || + (wlhdr->duration_id == cpu_to_le16(0))) { + /* If the fallback rate equals the normal rate or the + * dur_id field contains an AID, CFP magic or 0, + * use the original dur_id field. */ + txhdr->dur_fb = wlhdr->duration_id; + } else { + int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb); + txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, + fragment_len, + fbrate_base100kbps); + } + + plcp_fragment_len = fragment_len + FCS_LEN; + if (use_encryption) { + u8 key_idx = (u16)(txctl->key_idx); + struct b43legacy_key *key; + int wlhdr_len; + size_t iv_len; + + B43legacy_WARN_ON(key_idx >= dev->max_nr_keys); + key = &(dev->key[key_idx]); + + if (key->enabled) { + /* Hardware appends ICV. */ + plcp_fragment_len += txctl->icv_len; + + key_idx = b43legacy_kidx_to_fw(dev, key_idx); + mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & + B43legacy_TX4_MAC_KEYIDX; + mac_ctl |= (key->algorithm << + B43legacy_TX4_MAC_KEYALG_SHIFT) & + B43legacy_TX4_MAC_KEYALG; + wlhdr_len = ieee80211_get_hdrlen(fctl); + iv_len = min((size_t)txctl->iv_len, + ARRAY_SIZE(txhdr->iv)); + memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); + } + } + b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) + (&txhdr->plcp), plcp_fragment_len, + rate); + b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) + (&txhdr->plcp_fb), plcp_fragment_len, + rate_fb); + + /* PHY TX Control word */ + if (rate_ofdm) + phy_ctl |= B43legacy_TX4_PHY_OFDM; + if (dev->short_preamble) + phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; + switch (txctl->antenna_sel_tx) { + case 0: + phy_ctl |= B43legacy_TX4_PHY_ANTLAST; + break; + case 1: + phy_ctl |= B43legacy_TX4_PHY_ANT0; + break; + case 2: + phy_ctl |= B43legacy_TX4_PHY_ANT1; + break; + default: + B43legacy_BUG_ON(1); + } + + /* MAC control */ + if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + mac_ctl |= B43legacy_TX4_MAC_ACK; + if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) + mac_ctl |= B43legacy_TX4_MAC_HWSEQ; + if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + mac_ctl |= B43legacy_TX4_MAC_STMSDU; + if (rate_fb_ofdm) + mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; + + /* Generate the RTS or CTS-to-self frame */ + if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || + (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + unsigned int len; + struct ieee80211_hdr *hdr; + int rts_rate; + int rts_rate_fb; + int rts_rate_ofdm; + int rts_rate_fb_ofdm; + + rts_rate = txctl->rts_cts_rate; + rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); + rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); + rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); + if (rts_rate_fb_ofdm) + mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; + + if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + ieee80211_ctstoself_get(dev->wl->hw, + dev->wl->if_id, + fragment_data, + fragment_len, txctl, + (struct ieee80211_cts *) + (txhdr->rts_frame)); + mac_ctl |= B43legacy_TX4_MAC_SENDCTS; + len = sizeof(struct ieee80211_cts); + } else { + ieee80211_rts_get(dev->wl->hw, + dev->wl->if_id, + fragment_data, fragment_len, txctl, + (struct ieee80211_rts *) + (txhdr->rts_frame)); + mac_ctl |= B43legacy_TX4_MAC_SENDRTS; + len = sizeof(struct ieee80211_rts); + } + len += FCS_LEN; + b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) + (&txhdr->rts_plcp), + len, rts_rate); + b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) + (&txhdr->rts_plcp_fb), + len, rts_rate_fb); + hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); + txhdr->rts_dur_fb = hdr->duration_id; + mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; + } + + /* Magic cookie */ + txhdr->cookie = cpu_to_le16(cookie); + + /* Apply the bitfields */ + txhdr->mac_ctl = cpu_to_le32(mac_ctl); + txhdr->phy_ctl = cpu_to_le16(phy_ctl); +} + +void b43legacy_generate_txhdr(struct b43legacy_wldev *dev, + u8 *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) +{ + generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, + fragment_data, fragment_len, + txctl, cookie); +} + +static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) +{ + struct b43legacy_phy *phy = &dev->phy; + s32 tmp; + + switch (phy->radio_ver) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = phy->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (phy->type == B43legacy_PHYTYPE_G && + adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8)tmp; +} + +void b43legacy_rx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + const void *_rxhdr) +{ + struct ieee80211_rx_status status; + struct b43legacy_plcp_hdr6 *plcp; + struct ieee80211_hdr *wlhdr; + const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr; + u16 fctl; + u16 phystat0; + u16 phystat3; + u16 chanstat; + u16 mactime; + u32 macstat; + u16 chanid; + u8 jssi; + int padding; + + memset(&status, 0, sizeof(status)); + + /* Get metadata about the frame from the header. */ + phystat0 = le16_to_cpu(rxhdr->phy_status0); + phystat3 = le16_to_cpu(rxhdr->phy_status3); + jssi = rxhdr->jssi; + macstat = le16_to_cpu(rxhdr->mac_status); + mactime = le16_to_cpu(rxhdr->mac_time); + chanstat = le16_to_cpu(rxhdr->channel); + + if (macstat & B43legacy_RX_MAC_FCSERR) + dev->wl->ieee_stats.dot11FCSErrorCount++; + + /* Skip PLCP and padding */ + padding = (macstat & B43legacy_RX_MAC_PADDING) ? 2 : 0; + if (unlikely(skb->len < (sizeof(struct b43legacy_plcp_hdr6) + + padding))) { + b43legacydbg(dev->wl, "RX: Packet size underrun (1)\n"); + goto drop; + } + plcp = (struct b43legacy_plcp_hdr6 *)(skb->data + padding); + skb_pull(skb, sizeof(struct b43legacy_plcp_hdr6) + padding); + /* The skb contains the Wireless Header + payload data now */ + if (unlikely(skb->len < (2+2+6/*minimum hdr*/ + FCS_LEN))) { + b43legacydbg(dev->wl, "RX: Packet size underrun (2)\n"); + goto drop; + } + wlhdr = (struct ieee80211_hdr *)(skb->data); + fctl = le16_to_cpu(wlhdr->frame_control); + + if ((macstat & B43legacy_RX_MAC_DEC) && + !(macstat & B43legacy_RX_MAC_DECERR)) { + unsigned int keyidx; + int wlhdr_len; + int iv_len; + int icv_len; + + keyidx = ((macstat & B43legacy_RX_MAC_KEYIDX) + >> B43legacy_RX_MAC_KEYIDX_SHIFT); + /* We must adjust the key index here. We want the "physical" + * key index, but the ucode passed it slightly different. + */ + keyidx = b43legacy_kidx_to_raw(dev, keyidx); + B43legacy_WARN_ON(keyidx >= dev->max_nr_keys); + + if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) { + /* Remove PROTECTED flag to mark it as decrypted. */ + B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED)); + fctl &= ~IEEE80211_FCTL_PROTECTED; + wlhdr->frame_control = cpu_to_le16(fctl); + + wlhdr_len = ieee80211_get_hdrlen(fctl); + if (unlikely(skb->len < (wlhdr_len + 3))) { + b43legacydbg(dev->wl, "RX: Packet size" + " underrun3\n"); + goto drop; + } + if (skb->data[wlhdr_len + 3] & (1 << 5)) { + /* The Ext-IV Bit is set in the "KeyID" + * octet of the IV. + */ + iv_len = 8; + icv_len = 8; + } else { + iv_len = 4; + icv_len = 4; + } + if (unlikely(skb->len < (wlhdr_len + iv_len + + icv_len))) { + b43legacydbg(dev->wl, "RX: Packet size" + " underrun4\n"); + goto drop; + } + /* Remove the IV */ + memmove(skb->data + iv_len, skb->data, wlhdr_len); + skb_pull(skb, iv_len); + /* Remove the ICV */ + skb_trim(skb, skb->len - icv_len); + + status.flag |= RX_FLAG_DECRYPTED; + } + } + + status.ssi = b43legacy_rssi_postprocess(dev, jssi, + (phystat0 & B43legacy_RX_PHYST0_OFDM), + (phystat0 & B43legacy_RX_PHYST0_GAINCTL), + (phystat3 & B43legacy_RX_PHYST3_TRSTATE)); + status.noise = dev->stats.link_noise; + status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI; + if (phystat0 & B43legacy_RX_PHYST0_OFDM) + status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp); + else + status.rate = b43legacy_plcp_get_bitrate_cck(plcp); + status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT); + status.mactime = mactime; + + chanid = (chanstat & B43legacy_RX_CHAN_ID) >> + B43legacy_RX_CHAN_ID_SHIFT; + switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) { + case B43legacy_PHYTYPE_B: + status.phymode = MODE_IEEE80211B; + status.freq = chanid + 2400; + status.channel = b43legacy_freq_to_channel_bg(chanid + 2400); + break; + case B43legacy_PHYTYPE_G: + status.phymode = MODE_IEEE80211G; + status.freq = chanid + 2400; + status.channel = b43legacy_freq_to_channel_bg(chanid + 2400); + break; + default: + b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n", + chanstat); + } + + dev->stats.last_rx = jiffies; + ieee80211_rx_irqsafe(dev->wl->hw, skb, &status); + + return; +drop: + b43legacydbg(dev->wl, "RX: Packet dropped\n"); + dev_kfree_skb_any(skb); +} + +void b43legacy_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ + b43legacy_debugfs_log_txstat(dev, status); + + if (status->intermediate) + return; + if (status->for_ampdu) + return; + if (!status->acked) + dev->wl->ieee_stats.dot11ACKFailureCount++; + if (status->rts_count) { + if (status->rts_count == 0xF) /* FIXME */ + dev->wl->ieee_stats.dot11RTSFailureCount++; + else + dev->wl->ieee_stats.dot11RTSSuccessCount++; + } + + if (b43legacy_using_pio(dev)) + b43legacy_pio_handle_txstatus(dev, status); + else + b43legacy_dma_handle_txstatus(dev, status); +} + +/* Handle TX status report as received through DMA/PIO queues */ +void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev, + const struct b43legacy_hwtxstatus *hw) +{ + struct b43legacy_txstatus status; + u8 tmp; + + status.cookie = le16_to_cpu(hw->cookie); + status.seq = le16_to_cpu(hw->seq); + status.phy_stat = hw->phy_stat; + tmp = hw->count; + status.frame_count = (tmp >> 4); + status.rts_count = (tmp & 0x0F); + tmp = hw->flags; + status.supp_reason = ((tmp & 0x1C) >> 2); + status.pm_indicated = !!(tmp & 0x80); + status.intermediate = !!(tmp & 0x40); + status.for_ampdu = !!(tmp & 0x20); + status.acked = !!(tmp & 0x02); + + b43legacy_handle_txstatus(dev, &status); +} + +/* Stop any TX operation on the device (suspend the hardware queues) */ +void b43legacy_tx_suspend(struct b43legacy_wldev *dev) +{ + if (b43legacy_using_pio(dev)) + b43legacy_pio_freeze_txqueues(dev); + else + b43legacy_dma_tx_suspend(dev); +} + +/* Resume any TX operation on the device (resume the hardware queues) */ +void b43legacy_tx_resume(struct b43legacy_wldev *dev) +{ + if (b43legacy_using_pio(dev)) + b43legacy_pio_thaw_txqueues(dev); + else + b43legacy_dma_tx_resume(dev); +} + +/* Initialize the QoS parameters */ +void b43legacy_qos_init(struct b43legacy_wldev *dev) +{ + /* FIXME: This function must probably be called from the mac80211 + * config callback. */ +return; + + b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF); + /* FIXME kill magic */ + b43legacy_write16(dev, 0x688, + b43legacy_read16(dev, 0x688) | 0x4); + + + /*TODO: We might need some stack support here to get the values. */ +} diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h new file mode 100644 index 000000000000..8a155d0a5d1f --- /dev/null +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -0,0 +1,259 @@ +#ifndef B43legacy_XMIT_H_ +#define B43legacy_XMIT_H_ + +#include "main.h" + + +#define _b43legacy_declare_plcp_hdr(size) \ + struct b43legacy_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct b43legacy_plcp_hdr4 */ +_b43legacy_declare_plcp_hdr(4); +/* struct b43legacy_plcp_hdr6 */ +_b43legacy_declare_plcp_hdr(6); + +#undef _b43legacy_declare_plcp_hdr + + +/* TX header for v3 firmware */ +struct b43legacy_txhdr_fw3 { + __le32 mac_ctl; /* MAC TX control */ + __le16 mac_frame_ctl; /* Copy of the FrameControl */ + __le16 tx_fes_time_norm; /* TX FES Time Normal */ + __le16 phy_ctl; /* PHY TX control */ + __u8 iv[16]; /* Encryption IV */ + __u8 tx_receiver[6]; /* TX Frame Receiver address */ + __le16 tx_fes_time_fb; /* TX FES Time Fallback */ + struct b43legacy_plcp_hdr4 rts_plcp_fb; /* RTS fallback PLCP */ + __le16 rts_dur_fb; /* RTS fallback duration */ + struct b43legacy_plcp_hdr4 plcp_fb; /* Fallback PLCP */ + __le16 dur_fb; /* Fallback duration */ + PAD_BYTES(2); + __le16 cookie; + __le16 unknown_scb_stuff; + struct b43legacy_plcp_hdr6 rts_plcp; /* RTS PLCP */ + __u8 rts_frame[18]; /* The RTS frame (if used) */ + struct b43legacy_plcp_hdr6 plcp; +} __attribute__((__packed__)); + +/* MAC TX control */ +#define B43legacy_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */ +#define B43legacy_TX4_MAC_KEYIDX_SHIFT 20 +#define B43legacy_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */ +#define B43legacy_TX4_MAC_KEYALG_SHIFT 16 +#define B43legacy_TX4_MAC_LIFETIME 0x00001000 +#define B43legacy_TX4_MAC_FRAMEBURST 0x00000800 +#define B43legacy_TX4_MAC_SENDCTS 0x00000400 +#define B43legacy_TX4_MAC_AMPDU 0x00000300 +#define B43legacy_TX4_MAC_AMPDU_SHIFT 8 +#define B43legacy_TX4_MAC_CTSFALLBACKOFDM 0x00000200 +#define B43legacy_TX4_MAC_FALLBACKOFDM 0x00000100 +#define B43legacy_TX4_MAC_5GHZ 0x00000080 +#define B43legacy_TX4_MAC_IGNPMQ 0x00000020 +#define B43legacy_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Seq No */ +#define B43legacy_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */ +#define B43legacy_TX4_MAC_SENDRTS 0x00000004 +#define B43legacy_TX4_MAC_LONGFRAME 0x00000002 +#define B43legacy_TX4_MAC_ACK 0x00000001 + +/* Extra Frame Types */ +#define B43legacy_TX4_EFT_FBOFDM 0x0001 /* Data frame fb rate type */ +#define B43legacy_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */ +#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ + +/* PHY TX control word */ +#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ +#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ +#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */ +#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ +#define B43legacy_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */ +#define B43legacy_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */ + + + +void b43legacy_generate_txhdr(struct b43legacy_wldev *dev, + u8 *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie); + + +/* Transmit Status */ +struct b43legacy_txstatus { + u16 cookie; /* The cookie from the txhdr */ + u16 seq; /* Sequence number */ + u8 phy_stat; /* PHY TX status */ + u8 frame_count; /* Frame transmit count */ + u8 rts_count; /* RTS transmit count */ + u8 supp_reason; /* Suppression reason */ + /* flags */ + u8 pm_indicated;/* PM mode indicated to AP */ + u8 intermediate;/* Intermediate status notification */ + u8 for_ampdu; /* Status is for an AMPDU (afterburner) */ + u8 acked; /* Wireless ACK received */ +}; + +/* txstatus supp_reason values */ +enum { + B43legacy_TXST_SUPP_NONE, /* Not suppressed */ + B43legacy_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */ + B43legacy_TXST_SUPP_FLUSH, /* Suppressed due to flush request */ + B43legacy_TXST_SUPP_PREV, /* Previous fragment failed */ + B43legacy_TXST_SUPP_CHAN, /* Channel mismatch */ + B43legacy_TXST_SUPP_LIFE, /* Lifetime expired */ + B43legacy_TXST_SUPP_UNDER, /* Buffer underflow */ + B43legacy_TXST_SUPP_ABNACK, /* Afterburner NACK */ +}; + +/* Transmit Status as received through DMA/PIO on old chips */ +struct b43legacy_hwtxstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 count; + PAD_BYTES(2); + __le16 seq; + u8 phy_stat; + PAD_BYTES(1); +} __attribute__((__packed__)); + + +/* Receive header for v3 firmware. */ +struct b43legacy_rxhdr_fw3 { + __le16 frame_len; /* Frame length */ + PAD_BYTES(2); + __le16 phy_status0; /* PHY RX Status 0 */ + __u8 jssi; /* PHY RX Status 1: JSSI */ + __u8 sig_qual; /* PHY RX Status 1: Signal Quality */ + PAD_BYTES(2); /* PHY RX Status 2 */ + __le16 phy_status3; /* PHY RX Status 3 */ + __le16 mac_status; /* MAC RX status */ + __le16 mac_time; + __le16 channel; +} __attribute__((__packed__)); + + +/* PHY RX Status 0 */ +#define B43legacy_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */ +#define B43legacy_RX_PHYST0_PLCPHCF 0x0200 +#define B43legacy_RX_PHYST0_PLCPFV 0x0100 +#define B43legacy_RX_PHYST0_SHORTPRMBL 0x0080 /* Recvd with Short Preamble */ +#define B43legacy_RX_PHYST0_LCRS 0x0040 +#define B43legacy_RX_PHYST0_ANT 0x0020 /* Antenna */ +#define B43legacy_RX_PHYST0_UNSRATE 0x0010 +#define B43legacy_RX_PHYST0_CLIP 0x000C +#define B43legacy_RX_PHYST0_CLIP_SHIFT 2 +#define B43legacy_RX_PHYST0_FTYPE 0x0003 /* Frame type */ +#define B43legacy_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */ +#define B43legacy_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */ +#define B43legacy_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */ +#define B43legacy_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */ + +/* PHY RX Status 2 */ +#define B43legacy_RX_PHYST2_LNAG 0xC000 /* LNA Gain */ +#define B43legacy_RX_PHYST2_LNAG_SHIFT 14 +#define B43legacy_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */ +#define B43legacy_RX_PHYST2_PNAG_SHIFT 10 +#define B43legacy_RX_PHYST2_FOFF 0x03FF /* F offset */ + +/* PHY RX Status 3 */ +#define B43legacy_RX_PHYST3_DIGG 0x1800 /* DIG Gain */ +#define B43legacy_RX_PHYST3_DIGG_SHIFT 11 +#define B43legacy_RX_PHYST3_TRSTATE 0x0400 /* TR state */ + +/* MAC RX Status */ +#define B43legacy_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */ +#define B43legacy_RX_MAC_KEYIDX 0x000007E0 /* Key index */ +#define B43legacy_RX_MAC_KEYIDX_SHIFT 5 +#define B43legacy_RX_MAC_DECERR 0x00000010 /* Decrypt error */ +#define B43legacy_RX_MAC_DEC 0x00000008 /* Decryption attempted */ +#define B43legacy_RX_MAC_PADDING 0x00000004 /* Pad bytes present */ +#define B43legacy_RX_MAC_RESP 0x00000002 /* Response frame xmitted */ +#define B43legacy_RX_MAC_FCSERR 0x00000001 /* FCS error */ + +/* RX channel */ +#define B43legacy_RX_CHAN_GAIN 0xFC00 /* Gain */ +#define B43legacy_RX_CHAN_GAIN_SHIFT 10 +#define B43legacy_RX_CHAN_ID 0x03FC /* Channel ID */ +#define B43legacy_RX_CHAN_ID_SHIFT 2 +#define B43legacy_RX_CHAN_PHYTYPE 0x0003 /* PHY type */ + + + +u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate); +u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate); + +void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate); + +void b43legacy_rx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + const void *_rxhdr); + +void b43legacy_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status); + +void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev, + const struct b43legacy_hwtxstatus *hw); + +void b43legacy_tx_suspend(struct b43legacy_wldev *dev); +void b43legacy_tx_resume(struct b43legacy_wldev *dev); + + +#define B43legacy_NR_QOSPARMS 22 +enum { + B43legacy_QOSPARM_TXOP = 0, + B43legacy_QOSPARM_CWMIN, + B43legacy_QOSPARM_CWMAX, + B43legacy_QOSPARM_CWCUR, + B43legacy_QOSPARM_AIFS, + B43legacy_QOSPARM_BSLOTS, + B43legacy_QOSPARM_REGGAP, + B43legacy_QOSPARM_STATUS, +}; + +void b43legacy_qos_init(struct b43legacy_wldev *dev); + + +/* Helper functions for converting the key-table index from "firmware-format" + * to "raw-format" and back. The firmware API changed for this at some revision. + * We need to account for that here. */ +static inline +int b43legacy_new_kidx_api(struct b43legacy_wldev *dev) +{ + /* FIXME: Not sure the change was at rev 351 */ + return (dev->fw.rev >= 351); +} +static inline +u8 b43legacy_kidx_to_fw(struct b43legacy_wldev *dev, u8 raw_kidx) +{ + u8 firmware_kidx; + if (b43legacy_new_kidx_api(dev)) + firmware_kidx = raw_kidx; + else { + if (raw_kidx >= 4) /* Is per STA key? */ + firmware_kidx = raw_kidx - 4; + else + firmware_kidx = raw_kidx; /* TX default key */ + } + return firmware_kidx; +} +static inline +u8 b43legacy_kidx_to_raw(struct b43legacy_wldev *dev, u8 firmware_kidx) +{ + u8 raw_kidx; + if (b43legacy_new_kidx_api(dev)) + raw_kidx = firmware_kidx; + else + /* RX default keys or per STA keys */ + raw_kidx = firmware_kidx + 4; + return raw_kidx; +} + +#endif /* B43legacy_XMIT_H_ */ From b481de9ca074528fe8c429604e2777db8b89806a Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 25 Sep 2007 17:54:57 -0700 Subject: [PATCH 1422/2804] [IWLWIFI]: add iwlwifi wireless drivers This patch adds the mac80211 based wireless drivers for the Intel PRO/Wireless 3945ABG/BG Network Connection and Intel Wireless WiFi Link AGN (4965) adapters. [ Move driver into it's own directory -DaveM ] Signed-off-by: Zhu Yi Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 9 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 2 + drivers/net/wireless/iwlwifi/Kconfig | 128 + drivers/net/wireless/iwlwifi/Makefile | 11 + drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 118 + drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 979 ++ drivers/net/wireless/iwlwifi/iwl-3945-rs.h | 191 + drivers/net/wireless/iwlwifi/iwl-3945.c | 2290 +++++ drivers/net/wireless/iwlwifi/iwl-3945.h | 41 + drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 581 ++ drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2118 +++++ drivers/net/wireless/iwlwifi/iwl-4965-rs.h | 266 + drivers/net/wireless/iwlwifi/iwl-4965.c | 4719 ++++++++++ drivers/net/wireless/iwlwifi/iwl-4965.h | 341 + drivers/net/wireless/iwlwifi/iwl-channel.h | 161 + drivers/net/wireless/iwlwifi/iwl-commands.h | 1734 ++++ drivers/net/wireless/iwlwifi/iwl-debug.h | 149 + drivers/net/wireless/iwlwifi/iwl-eeprom.h | 336 + drivers/net/wireless/iwlwifi/iwl-helpers.h | 255 + drivers/net/wireless/iwlwifi/iwl-hw.h | 537 ++ drivers/net/wireless/iwlwifi/iwl-io.h | 470 + drivers/net/wireless/iwlwifi/iwl-priv.h | 308 + drivers/net/wireless/iwlwifi/iwl-prph.h | 229 + drivers/net/wireless/iwlwifi/iwl-spectrum.h | 91 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 8732 +++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 9323 +++++++++++++++++++ drivers/net/wireless/iwlwifi/iwlwifi.h | 713 ++ 28 files changed, 34833 insertions(+) create mode 100644 drivers/net/wireless/iwlwifi/Kconfig create mode 100644 drivers/net/wireless/iwlwifi/Makefile create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-hw.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-rs.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-rs.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-hw.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-rs.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-rs.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-channel.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-commands.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-debug.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-eeprom.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-helpers.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-hw.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-io.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-priv.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-prph.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-spectrum.h create mode 100644 drivers/net/wireless/iwlwifi/iwl3945-base.c create mode 100644 drivers/net/wireless/iwlwifi/iwl4965-base.c create mode 100644 drivers/net/wireless/iwlwifi/iwlwifi.h diff --git a/MAINTAINERS b/MAINTAINERS index ef9402807de0..934afd3dfa40 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2080,6 +2080,15 @@ L: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel W: http://ipw2200.sourceforge.net S: Supported +INTEL WIRELESS WIFI LINK (iwlwifi) +P: Zhu Yi +M: yi.zhu@intel.com +L: linux-wireless@vger.kernel.org +L: ipw3945-devel@lists.sourceforge.net +W: http://intellinuxwireless.org +T: git git://intellinuxwireless.org/repos/iwlwifi +S: Supported + IOC3 ETHERNET DRIVER P: Ralf Baechle M: ralf@linux-mips.org diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index c2102653b2a9..085ba132835f 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -577,6 +577,7 @@ config ADM8211 Thanks to Infineon-ADMtek for their support of this driver. +source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/b43/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index d8dd907e4999..351024f2fe72 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -51,3 +51,5 @@ rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o obj-$(CONFIG_RTL8187) += rtl8187.o obj-$(CONFIG_ADM8211) += adm8211.o + +obj-$(CONFIG_IWLWIFI) += iwlwifi/ diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig new file mode 100644 index 000000000000..25cfc6c32509 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -0,0 +1,128 @@ +config IWLWIFI + bool "Intel Wireless WiFi Link Drivers" + depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select FW_LOADER + default n + ---help--- + Select to enable drivers based on the iwlwifi project. This + project provides a common foundation for Intel's wireless + drivers designed to use the mac80211 subsystem. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging issues and problems. + +config IWLWIFI_DEBUG + bool "Enable full debugging output in iwlwifi drivers" + depends on IWLWIFI + default y + ---help--- + This option will enable debug tracing output for the iwlwifi + drivers. + + This will result in the kernel module being ~100k larger. You can + control which debug output is sent to the kernel log by setting the + value in + + /sys/bus/pci/drivers/${DRIVER}/debug_level + + This entry will only exist if this option is enabled. + + To set a value, simply echo an 8-byte hex value to the same file: + + % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level + + You can find the list of debug mask values in: + drivers/net/wireless/mac80211/iwlwifi/iwl-debug.h + + If this is your first time using this driver, you should say Y here + as the debug information can assist others in helping you resolve + any problems you may encounter. + +config IWLWIFI_SENSITIVITY + bool "Enable Sensitivity Calibration in iwlwifi drivers" + depends on IWLWIFI + default y + ---help--- + This option will enable sensitivity calibration for the iwlwifi + drivers. + +config IWLWIFI_SPECTRUM_MEASUREMENT + bool "Enable Spectrum Measurement in iwlwifi drivers" + depends on IWLWIFI + default y + ---help--- + This option will enable spectrum measurement for the iwlwifi drivers. + +config IWLWIFI_QOS + bool "Enable Wireless QoS in iwlwifi drivers" + depends on IWLWIFI + default y + ---help--- + This option will enable wireless quality of service (QoS) for the + iwlwifi drivers. + +config IWLWIFI_HT + bool "Enable 802.11n HT features in iwlwifi drivers" + depends on EXPERIMENTAL + depends on IWLWIFI && MAC80211_HT + default n + ---help--- + This option enables IEEE 802.11n High Throughput features + for the iwlwifi drivers. + +config IWL4965 + tristate "Intel Wireless WiFi 4965AGN" + depends on m && IWLWIFI && EXPERIMENTAL + default m + ---help--- + Select to build the driver supporting the: + + Intel Wireless WiFi Link 4965AGN + + This driver uses the kernel's mac80211 subsystem. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging any issues or problems. + + In order to use this driver, you will need a microcode (uCode) + image for it. You can obtain the microcode from: + + . + + See the above referenced README.iwlwifi for information on where + to install the microcode images. + + If you want to compile the driver as a module ( = code which can be + inserted in and remvoed from the running kernel whenever you want), + say M here and read . The module + will be called iwl4965.ko. + +config IWL3945 + tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" + depends on m && IWLWIFI && EXPERIMENTAL + default m + ---help--- + Select to build the driver supporting the: + + Intel PRO/Wireless 3945ABG/BG Network Connection + + This driver uses the kernel's mac80211 subsystem. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging any issues or problems. + + In order to use this driver, you will need a microcode (uCode) + image for it. You can obtain the microcode from: + + . + + See the above referenced README.iwlwifi for information on where + to install the microcode images. + + If you want to compile the driver as a module ( = code which can be + inserted in and remvoed from the running kernel whenever you want), + say M here and read . The module + will be called iwl3945.ko. diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile new file mode 100644 index 000000000000..03837ff54312 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_IWL3945) += iwl3945.o +iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o +CFLAGS_iwl3945-base.o = -DIWL=3945 +CFLAGS_iwl-3945.o = -DIWL=3945 +CFLAGS_iwl-3945-rs.o = -DIWL=3945 + +obj-$(CONFIG_IWL4965) += iwl4965.o +iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o +CFLAGS_iwl4965-base.o = -DIWL=4965 +CFLAGS_iwl-4965.o = -DIWL=4965 +CFLAGS_iwl-4965-rs.o = -DIWL=4965 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h new file mode 100644 index 000000000000..fb5f0649f4f6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_3945_hw__ +#define __iwl_3945_hw__ + +#define IWL_RX_BUF_SIZE 3000 +/* card static random access memory (SRAM) for processor data and instructs */ +#define ALM_RTC_INST_UPPER_BOUND (0x014000) +#define ALM_RTC_DATA_UPPER_BOUND (0x808000) + +#define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) + +#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE +#define IWL_MAX_INST_SIZE ALM_RTC_INST_SIZE +#define IWL_MAX_DATA_SIZE ALM_RTC_DATA_SIZE +#define IWL_MAX_NUM_QUEUES 8 + +static inline int iwl_hw_valid_rtc_data_addr(u32 addr) +{ + return (addr >= RTC_DATA_LOWER_BOUND) && + (addr < ALM_RTC_DATA_UPPER_BOUND); +} + +/* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE + * and &iwl_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */ +struct iwl_shared { + __le32 tx_base_ptr[8]; + __le32 rx_read_ptr[3]; +} __attribute__ ((packed)); + +struct iwl_tfd_frame_data { + __le32 addr; + __le32 len; +} __attribute__ ((packed)); + +struct iwl_tfd_frame { + __le32 control_flags; + struct iwl_tfd_frame_data pa[4]; + u8 reserved[28]; +} __attribute__ ((packed)); + +static inline u8 iwl_hw_get_rate(__le16 rate_n_flags) +{ + return le16_to_cpu(rate_n_flags) & 0xFF; +} + +static inline u16 iwl_hw_get_rate_n_flags(__le16 rate_n_flags) +{ + return le16_to_cpu(rate_n_flags); +} + +static inline __le16 iwl_hw_set_rate_n_flags(u8 rate, u16 flags) +{ + return cpu_to_le16((u16)rate|flags); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c new file mode 100644 index 000000000000..a4f4c8798a83 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -0,0 +1,979 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "../net/mac80211/ieee80211_rate.h" + +#include "iwlwifi.h" + +#define RS_NAME "iwl-3945-rs" + +struct iwl_rate_scale_data { + u64 data; + s32 success_counter; + s32 success_ratio; + s32 counter; + s32 average_tpt; + unsigned long stamp; +}; + +struct iwl_rate_scale_priv { + spinlock_t lock; + s32 *expected_tpt; + unsigned long last_partial_flush; + unsigned long last_flush; + u32 flush_time; + u32 last_tx_packets; + u32 tx_packets; + u8 tgg; + u8 flush_pending; + u8 start_rate; + u8 ibss_sta_added; + struct timer_list rate_scale_flush; + struct iwl_rate_scale_data win[IWL_RATE_COUNT]; +}; + +static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = { + 0, 0, 76, 104, 130, 168, 191, 202, 7, 13, 35, 58 +}; + +static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = { + 0, 0, 0, 80, 93, 113, 123, 125, 7, 13, 35, 58 +}; + +static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = { + 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0, 0 +}; + +static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 0, 0, 0, 0, 7, 13, 35, 58 +}; + +struct iwl_tpt_entry { + s8 min_rssi; + u8 index; +}; + +static struct iwl_tpt_entry iwl_tpt_table_a[] = { + {-60, IWL_RATE_54M_INDEX}, + {-64, IWL_RATE_48M_INDEX}, + {-72, IWL_RATE_36M_INDEX}, + {-80, IWL_RATE_24M_INDEX}, + {-84, IWL_RATE_18M_INDEX}, + {-85, IWL_RATE_12M_INDEX}, + {-87, IWL_RATE_9M_INDEX}, + {-89, IWL_RATE_6M_INDEX} +}; + +static struct iwl_tpt_entry iwl_tpt_table_b[] = { + {-86, IWL_RATE_11M_INDEX}, + {-88, IWL_RATE_5M_INDEX}, + {-90, IWL_RATE_2M_INDEX}, + {-92, IWL_RATE_1M_INDEX} + +}; + +static struct iwl_tpt_entry iwl_tpt_table_g[] = { + {-60, IWL_RATE_54M_INDEX}, + {-64, IWL_RATE_48M_INDEX}, + {-68, IWL_RATE_36M_INDEX}, + {-80, IWL_RATE_24M_INDEX}, + {-84, IWL_RATE_18M_INDEX}, + {-85, IWL_RATE_12M_INDEX}, + {-86, IWL_RATE_11M_INDEX}, + {-88, IWL_RATE_5M_INDEX}, + {-90, IWL_RATE_2M_INDEX}, + {-92, IWL_RATE_1M_INDEX} +}; + +#define IWL_RATE_MAX_WINDOW 62 +#define IWL_RATE_FLUSH (3*HZ/10) +#define IWL_RATE_WIN_FLUSH (HZ/2) +#define IWL_RATE_HIGH_TH 11520 +#define IWL_RATE_MIN_FAILURE_TH 8 +#define IWL_RATE_MIN_SUCCESS_TH 8 +#define IWL_RATE_DECREASE_TH 1920 + +static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode) +{ + u32 index = 0; + u32 table_size = 0; + struct iwl_tpt_entry *tpt_table = NULL; + + if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL)) + rssi = IWL_MIN_RSSI_VAL; + + switch (mode) { + case MODE_IEEE80211G: + tpt_table = iwl_tpt_table_g; + table_size = ARRAY_SIZE(iwl_tpt_table_g); + break; + + case MODE_IEEE80211A: + tpt_table = iwl_tpt_table_a; + table_size = ARRAY_SIZE(iwl_tpt_table_a); + break; + + default: + case MODE_IEEE80211B: + tpt_table = iwl_tpt_table_b; + table_size = ARRAY_SIZE(iwl_tpt_table_b); + break; + } + + while ((index < table_size) && (rssi < tpt_table[index].min_rssi)) + index++; + + index = min(index, (table_size - 1)); + + return tpt_table[index].index; +} + +static void iwl_clear_window(struct iwl_rate_scale_data *window) +{ + window->data = 0; + window->success_counter = 0; + window->success_ratio = IWL_INVALID_VALUE; + window->counter = 0; + window->average_tpt = IWL_INVALID_VALUE; + window->stamp = 0; +} + +/** + * iwl_rate_scale_flush_windows - flush out the rate scale windows + * + * Returns the number of windows that have gathered data but were + * not flushed. If there were any that were not flushed, then + * reschedule the rate flushing routine. + */ +static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv) +{ + int unflushed = 0; + int i; + unsigned long flags; + + /* + * For each rate, if we have collected data on that rate + * and it has been more than IWL_RATE_WIN_FLUSH + * since we flushed, clear out the gathered statistics + */ + for (i = 0; i < IWL_RATE_COUNT; i++) { + if (!rs_priv->win[i].counter) + continue; + + spin_lock_irqsave(&rs_priv->lock, flags); + if (time_after(jiffies, rs_priv->win[i].stamp + + IWL_RATE_WIN_FLUSH)) { + IWL_DEBUG_RATE("flushing %d samples of rate " + "index %d\n", + rs_priv->win[i].counter, i); + iwl_clear_window(&rs_priv->win[i]); + } else + unflushed++; + spin_unlock_irqrestore(&rs_priv->lock, flags); + } + + return unflushed; +} + +#define IWL_RATE_FLUSH_MAX 5000 /* msec */ +#define IWL_RATE_FLUSH_MIN 50 /* msec */ + +static void iwl_bg_rate_scale_flush(unsigned long data) +{ + struct iwl_rate_scale_priv *rs_priv = (void *)data; + int unflushed = 0; + unsigned long flags; + u32 packet_count, duration, pps; + + IWL_DEBUG_RATE("enter\n"); + + unflushed = iwl_rate_scale_flush_windows(rs_priv); + + spin_lock_irqsave(&rs_priv->lock, flags); + + rs_priv->flush_pending = 0; + + /* Number of packets Rx'd since last time this timer ran */ + packet_count = (rs_priv->tx_packets - rs_priv->last_tx_packets) + 1; + + rs_priv->last_tx_packets = rs_priv->tx_packets + 1; + + if (unflushed) { + duration = + jiffies_to_msecs(jiffies - rs_priv->last_partial_flush); +/* duration = jiffies_to_msecs(rs_priv->flush_time); */ + + IWL_DEBUG_RATE("Tx'd %d packets in %dms\n", + packet_count, duration); + + /* Determine packets per second */ + if (duration) + pps = (packet_count * 1000) / duration; + else + pps = 0; + + if (pps) { + duration = IWL_RATE_FLUSH_MAX / pps; + if (duration < IWL_RATE_FLUSH_MIN) + duration = IWL_RATE_FLUSH_MIN; + } else + duration = IWL_RATE_FLUSH_MAX; + + rs_priv->flush_time = msecs_to_jiffies(duration); + + IWL_DEBUG_RATE("new flush period: %d msec ave %d\n", + duration, packet_count); + + mod_timer(&rs_priv->rate_scale_flush, jiffies + + rs_priv->flush_time); + + rs_priv->last_partial_flush = jiffies; + } + + /* If there weren't any unflushed entries, we don't schedule the timer + * to run again */ + + rs_priv->last_flush = jiffies; + + spin_unlock_irqrestore(&rs_priv->lock, flags); + + IWL_DEBUG_RATE("leave\n"); +} + +/** + * iwl_collect_tx_data - Update the success/failure sliding window + * + * We keep a sliding window of the last 64 packets transmitted + * at this rate. window->data contains the bitmask of successful + * packets. + */ +static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv, + struct iwl_rate_scale_data *window, + int success, int retries) +{ + unsigned long flags; + + if (!retries) { + IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n"); + return; + } + + while (retries--) { + spin_lock_irqsave(&rs_priv->lock, flags); + + /* If we have filled up the window then subtract one from the + * success counter if the high-bit is counting toward + * success */ + if (window->counter == IWL_RATE_MAX_WINDOW) { + if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1))) + window->success_counter--; + } else + window->counter++; + + /* Slide the window to the left one bit */ + window->data = (window->data << 1); + + /* If this packet was a success then set the low bit high */ + if (success) { + window->success_counter++; + window->data |= 1; + } + + /* window->counter can't be 0 -- it is either >0 or + * IWL_RATE_MAX_WINDOW */ + window->success_ratio = 12800 * window->success_counter / + window->counter; + + /* Tag this window as having been updated */ + window->stamp = jiffies; + + spin_unlock_irqrestore(&rs_priv->lock, flags); + } +} + +static void rs_rate_init(void *priv_rate, void *priv_sta, + struct ieee80211_local *local, struct sta_info *sta) +{ + int i; + + IWL_DEBUG_RATE("enter\n"); + + /* TODO: what is a good starting rate for STA? About middle? Maybe not + * the lowest or the highest rate.. Could consider using RSSI from + * previous packets? Need to have IEEE 802.1X auth succeed immediately + * after assoc.. */ + + for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { + if (sta->supp_rates & (1 << i)) { + sta->txrate = i; + break; + } + } + + sta->last_txrate = sta->txrate; + + IWL_DEBUG_RATE("leave\n"); +} + +static void *rs_alloc(struct ieee80211_local *local) +{ + return local->hw.priv; +} + +/* rate scale requires free function to be implmented */ +static void rs_free(void *priv) +{ + return; +} +static void rs_clear(void *priv) +{ + return; +} + + +static void *rs_alloc_sta(void *priv, gfp_t gfp) +{ + struct iwl_rate_scale_priv *rs_priv; + int i; + + IWL_DEBUG_RATE("enter\n"); + + rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp); + if (!rs_priv) { + IWL_DEBUG_RATE("leave: ENOMEM\n"); + return NULL; + } + + spin_lock_init(&rs_priv->lock); + + rs_priv->start_rate = IWL_RATE_INVALID; + + /* default to just 802.11b */ + rs_priv->expected_tpt = iwl_expected_tpt_b; + + rs_priv->last_partial_flush = jiffies; + rs_priv->last_flush = jiffies; + rs_priv->flush_time = IWL_RATE_FLUSH; + rs_priv->last_tx_packets = 0; + rs_priv->ibss_sta_added = 0; + + init_timer(&rs_priv->rate_scale_flush); + rs_priv->rate_scale_flush.data = (unsigned long)rs_priv; + rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush; + + for (i = 0; i < IWL_RATE_COUNT; i++) + iwl_clear_window(&rs_priv->win[i]); + + IWL_DEBUG_RATE("leave\n"); + + return rs_priv; +} + +static void rs_free_sta(void *priv, void *priv_sta) +{ + struct iwl_rate_scale_priv *rs_priv = priv_sta; + + IWL_DEBUG_RATE("enter\n"); + del_timer_sync(&rs_priv->rate_scale_flush); + kfree(rs_priv); + IWL_DEBUG_RATE("leave\n"); +} + +/** + * rs_tx_status - Update rate control values based on Tx results + * + * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by + * the hardware for each rate. + */ +static void rs_tx_status(void *priv_rate, + struct net_device *dev, + struct sk_buff *skb, + struct ieee80211_tx_status *tx_resp) +{ + u8 retries, current_count; + int scale_rate_index, first_index, last_index; + unsigned long flags; + struct sta_info *sta; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct iwl_rate_scale_priv *rs_priv; + + IWL_DEBUG_RATE("enter\n"); + + retries = tx_resp->retry_count; + + first_index = tx_resp->control.tx_rate; + if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { + IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n", + tx_resp->control.tx_rate, first_index); + return; + } + + sta = sta_info_get(local, hdr->addr1); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + sta_info_put(sta); + IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); + return; + } + + rs_priv = (void *)sta->rate_ctrl_priv; + + rs_priv->tx_packets++; + + scale_rate_index = first_index; + last_index = first_index; + + /* + * Update the window for each rate. We determine which rates + * were Tx'd based on the total number of retries vs. the number + * of retries configured for each rate -- currently set to the + * priv value 'retry_rate' vs. rate specific + * + * On exit from this while loop last_index indicates the rate + * at which the frame was finally transmitted (or failed if no + * ACK) + */ + while (retries > 0) { + if (retries < priv->retry_rate) { + current_count = retries; + last_index = scale_rate_index; + } else { + current_count = priv->retry_rate; + last_index = iwl_get_prev_ieee_rate(scale_rate_index); + } + + /* Update this rate accounting for as many retries + * as was used for it (per current_count) */ + iwl_collect_tx_data(rs_priv, + &rs_priv->win[scale_rate_index], + 0, current_count); + IWL_DEBUG_RATE("Update rate %d for %d retries.\n", + scale_rate_index, current_count); + + retries -= current_count; + + if (retries) + scale_rate_index = + iwl_get_prev_ieee_rate(scale_rate_index); + } + + /* Update the last index window with success/failure based on ACK */ + IWL_DEBUG_RATE("Update rate %d with %s.\n", + last_index, + (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ? + "success" : "failure"); + iwl_collect_tx_data(rs_priv, + &rs_priv->win[last_index], + tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1); + + /* We updated the rate scale window -- if its been more than + * flush_time since the last run, schedule the flush + * again */ + spin_lock_irqsave(&rs_priv->lock, flags); + + if (!rs_priv->flush_pending && + time_after(jiffies, rs_priv->last_partial_flush + + rs_priv->flush_time)) { + + rs_priv->flush_pending = 1; + mod_timer(&rs_priv->rate_scale_flush, + jiffies + rs_priv->flush_time); + } + + spin_unlock_irqrestore(&rs_priv->lock, flags); + + sta_info_put(sta); + + IWL_DEBUG_RATE("leave\n"); + + return; +} + +static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local + *local) +{ + struct ieee80211_hw_mode *mode = local->oper_hw_mode; + int i; + + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *rate = &mode->rates[i]; + + if (rate->flags & IEEE80211_RATE_SUPPORTED) + return rate; + } + + return &mode->rates[0]; +} + +static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv, + u8 index, u16 rate_mask, int phymode) +{ + u8 high = IWL_RATE_INVALID; + u8 low = IWL_RATE_INVALID; + + /* 802.11A walks to the next literal adjascent rate in + * the rate table */ + if (unlikely(phymode == MODE_IEEE80211A)) { + int i; + u32 mask; + + /* Find the previous rate that is in the rate mask */ + i = index - 1; + for (mask = (1 << i); i >= 0; i--, mask >>= 1) { + if (rate_mask & mask) { + low = i; + break; + } + } + + /* Find the next rate that is in the rate mask */ + i = index + 1; + for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { + if (rate_mask & mask) { + high = i; + break; + } + } + + return (high << 8) | low; + } + + low = index; + while (low != IWL_RATE_INVALID) { + if (rs_priv->tgg) + low = iwl_rates[low].prev_rs_tgg; + else + low = iwl_rates[low].prev_rs; + if (low == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << low)) + break; + IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low); + } + + high = index; + while (high != IWL_RATE_INVALID) { + if (rs_priv->tgg) + high = iwl_rates[high].next_rs_tgg; + else + high = iwl_rates[high].next_rs; + if (high == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << high)) + break; + IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high); + } + + return (high << 8) | low; +} + +/** + * rs_get_rate - find the rate for the requested packet + * + * Returns the ieee80211_rate structure allocated by the driver. + * + * The rate control algorithm has no internal mapping between hw_mode's + * rate ordering and the rate ordering used by the rate control algorithm. + * + * The rate control algorithm uses a single table of rates that goes across + * the entire A/B/G spectrum vs. being limited to just one particular + * hw_mode. + * + * As such, we can't convert the index obtained below into the hw_mode's + * rate table and must reference the driver allocated rate table + * + */ +static struct ieee80211_rate *rs_get_rate(void *priv_rate, + struct net_device *dev, + struct sk_buff *skb, + struct rate_control_extra *extra) +{ + u8 low = IWL_RATE_INVALID; + u8 high = IWL_RATE_INVALID; + u16 high_low; + int index; + struct iwl_rate_scale_priv *rs_priv; + struct iwl_rate_scale_data *window = NULL; + int current_tpt = IWL_INVALID_VALUE; + int low_tpt = IWL_INVALID_VALUE; + int high_tpt = IWL_INVALID_VALUE; + u32 fail_count; + s8 scale_action = 0; + unsigned long flags; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct sta_info *sta; + u16 fc, rate_mask; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + + IWL_DEBUG_RATE("enter\n"); + + memset(extra, 0, sizeof(*extra)); + + fc = le16_to_cpu(hdr->frame_control); + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || + (is_multicast_ether_addr(hdr->addr1))) { + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + IWL_DEBUG_RATE("leave: lowest rate (not data or is " + "multicast)\n"); + + return iwl_get_lowest_rate(local); + } + + sta = sta_info_get(local, hdr->addr1); + if (!sta || !sta->rate_ctrl_priv) { + IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); + if (sta) + sta_info_put(sta); + return NULL; + } + + rate_mask = sta->supp_rates; + index = min(sta->txrate & 0xffff, IWL_RATE_COUNT - 1); + + rs_priv = (void *)sta->rate_ctrl_priv; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !rs_priv->ibss_sta_added) { + u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", + MAC_ARG(hdr->addr1)); + sta_id = iwl_add_station(priv, + hdr->addr1, 0, CMD_ASYNC); + } + if (sta_id != IWL_INVALID_STATION) + rs_priv->ibss_sta_added = 1; + } + + spin_lock_irqsave(&rs_priv->lock, flags); + + if (rs_priv->start_rate != IWL_RATE_INVALID) { + index = rs_priv->start_rate; + rs_priv->start_rate = IWL_RATE_INVALID; + } + + window = &(rs_priv->win[index]); + + fail_count = window->counter - window->success_counter; + + if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { + window->average_tpt = IWL_INVALID_VALUE; + spin_unlock_irqrestore(&rs_priv->lock, flags); + + IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " + "counter: %d, success_counter: %d, " + "expected_tpt is %sNULL\n", + index, + window->counter, + window->success_counter, + rs_priv->expected_tpt ? "not " : ""); + goto out; + + } + + window->average_tpt = ((window->success_ratio * + rs_priv->expected_tpt[index] + 64) / 128); + current_tpt = window->average_tpt; + + high_low = iwl_get_adjacent_rate(rs_priv, index, rate_mask, + local->hw.conf.phymode); + low = high_low & 0xff; + high = (high_low >> 8) & 0xff; + + if (low != IWL_RATE_INVALID) + low_tpt = rs_priv->win[low].average_tpt; + + if (high != IWL_RATE_INVALID) + high_tpt = rs_priv->win[high].average_tpt; + + spin_unlock_irqrestore(&rs_priv->lock, flags); + + scale_action = 1; + + if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) { + IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); + scale_action = -1; + } else if ((low_tpt == IWL_INVALID_VALUE) && + (high_tpt == IWL_INVALID_VALUE)) + scale_action = 1; + else if ((low_tpt != IWL_INVALID_VALUE) && + (high_tpt != IWL_INVALID_VALUE) + && (low_tpt < current_tpt) + && (high_tpt < current_tpt)) { + IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < " + "current_tpt [%d]\n", + low_tpt, high_tpt, current_tpt); + scale_action = 0; + } else { + if (high_tpt != IWL_INVALID_VALUE) { + if (high_tpt > current_tpt) + scale_action = 1; + else { + IWL_DEBUG_RATE + ("decrease rate because of high tpt\n"); + scale_action = -1; + } + } else if (low_tpt != IWL_INVALID_VALUE) { + if (low_tpt > current_tpt) { + IWL_DEBUG_RATE + ("decrease rate because of low tpt\n"); + scale_action = -1; + } else + scale_action = 1; + } + } + + if ((window->success_ratio > IWL_RATE_HIGH_TH) || + (current_tpt > window->average_tpt)) { + IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or " + "current_tpt [%d] > average_tpt [%d]\n", + window->success_ratio, + current_tpt, window->average_tpt); + scale_action = 0; + } + + switch (scale_action) { + case -1: + if (low != IWL_RATE_INVALID) + index = low; + break; + + case 1: + if (high != IWL_RATE_INVALID) + index = high; + + break; + + case 0: + default: + break; + } + + IWL_DEBUG_RATE("Selected %d (action %d) - low %d high %d\n", + index, scale_action, low, high); + + out: + + sta->last_txrate = index; + sta->txrate = sta->last_txrate; + sta_info_put(sta); + + IWL_DEBUG_RATE("leave: %d\n", index); + + return &priv->ieee_rates[index]; +} + +static struct rate_control_ops rs_ops = { + .module = NULL, + .name = RS_NAME, + .tx_status = rs_tx_status, + .get_rate = rs_get_rate, + .rate_init = rs_rate_init, + .clear = rs_clear, + .alloc = rs_alloc, + .free = rs_free, + .alloc_sta = rs_alloc_sta, + .free_sta = rs_free_sta, +}; + +int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct iwl_priv *priv = hw->priv; + struct iwl_rate_scale_priv *rs_priv; + struct sta_info *sta; + unsigned long flags; + int count = 0, i; + u32 samples = 0, success = 0, good = 0; + unsigned long now = jiffies; + u32 max_time = 0; + + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) { + sta_info_put(sta); + IWL_DEBUG_RATE("leave - no private rate data!\n"); + } else + IWL_DEBUG_RATE("leave - no station!\n"); + return sprintf(buf, "station %d not found\n", sta_id); + } + + rs_priv = (void *)sta->rate_ctrl_priv; + spin_lock_irqsave(&rs_priv->lock, flags); + i = IWL_RATE_54M_INDEX; + while (1) { + u64 mask; + int j; + + count += + sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2); + + mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); + for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) + buf[count++] = + (rs_priv->win[i].data & mask) ? '1' : '0'; + + samples += rs_priv->win[i].counter; + good += rs_priv->win[i].success_counter; + success += rs_priv->win[i].success_counter * iwl_rates[i].ieee; + + if (rs_priv->win[i].stamp) { + int delta = + jiffies_to_msecs(now - rs_priv->win[i].stamp); + + if (delta > max_time) + max_time = delta; + + count += sprintf(&buf[count], "%5dms\n", delta); + } else + buf[count++] = '\n'; + + j = iwl_get_prev_ieee_rate(i); + if (j == i) + break; + i = j; + } + spin_unlock_irqrestore(&rs_priv->lock, flags); + sta_info_put(sta); + + /* Display the average rate of all samples taken. + * + * NOTE: We multiple # of samples by 2 since the IEEE measurement + * added from iwl_rates is actually 2X the rate */ + if (samples) + count += sprintf( + &buf[count], + "\nAverage rate is %3d.%02dMbs over last %4dms\n" + "%3d%% success (%d good packets over %d tries)\n", + success / (2 * samples), (success * 5 / samples) % 10, + max_time, good * 100 / samples, good, samples); + else + count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n"); + + return count; +} + +void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) +{ + struct iwl_priv *priv = hw->priv; + s32 rssi = 0; + unsigned long flags; + struct ieee80211_local *local = hw_to_local(hw); + struct iwl_rate_scale_priv *rs_priv; + struct sta_info *sta; + + IWL_DEBUG_RATE("enter\n"); + + if (!local->rate_ctrl->ops->name || + strcmp(local->rate_ctrl->ops->name, RS_NAME)) { + IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n"); + IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n"); + return; + } + + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + sta_info_put(sta); + IWL_DEBUG_RATE("leave - no private rate data!\n"); + return; + } + + rs_priv = (void *)sta->rate_ctrl_priv; + + spin_lock_irqsave(&rs_priv->lock, flags); + + rs_priv->tgg = 0; + switch (priv->phymode) { + case MODE_IEEE80211G: + if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) { + rs_priv->tgg = 1; + rs_priv->expected_tpt = iwl_expected_tpt_g_prot; + } else + rs_priv->expected_tpt = iwl_expected_tpt_g; + break; + + case MODE_IEEE80211A: + rs_priv->expected_tpt = iwl_expected_tpt_a; + break; + + default: + IWL_WARNING("Invalid phymode. Defaulting to 802.11b\n"); + case MODE_IEEE80211B: + rs_priv->expected_tpt = iwl_expected_tpt_b; + break; + } + + sta_info_put(sta); + spin_unlock_irqrestore(&rs_priv->lock, flags); + + rssi = priv->last_rx_rssi; + if (rssi == 0) + rssi = IWL_MIN_RSSI_VAL; + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi); + + rs_priv->start_rate = iwl_get_rate_index_by_rssi(rssi, priv->phymode); + + IWL_DEBUG_RATE("leave: rssi %d assign rate index: " + "%d (plcp 0x%x)\n", rssi, rs_priv->start_rate, + iwl_rates[rs_priv->start_rate].plcp); +} + +void iwl_rate_control_register(struct ieee80211_hw *hw) +{ + ieee80211_rate_control_register(&rs_ops); +} + +void iwl_rate_control_unregister(struct ieee80211_hw *hw) +{ + ieee80211_rate_control_unregister(&rs_ops); +} + + diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h new file mode 100644 index 000000000000..b926738e0ea1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -0,0 +1,191 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_3945_rs_h__ +#define __iwl_3945_rs_h__ + +struct iwl_rate_info { + u8 plcp; + u8 ieee; + u8 prev_ieee; /* previous rate in IEEE speeds */ + u8 next_ieee; /* next rate in IEEE speeds */ + u8 prev_rs; /* previous rate used in rs algo */ + u8 next_rs; /* next rate used in rs algo */ + u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ + u8 next_rs_tgg; /* next rate used in TGG rs algo */ +}; + +enum { + IWL_RATE_6M_INDEX = 0, + IWL_RATE_9M_INDEX, + IWL_RATE_12M_INDEX, + IWL_RATE_18M_INDEX, + IWL_RATE_24M_INDEX, + IWL_RATE_36M_INDEX, + IWL_RATE_48M_INDEX, + IWL_RATE_54M_INDEX, + IWL_RATE_1M_INDEX, + IWL_RATE_2M_INDEX, + IWL_RATE_5M_INDEX, + IWL_RATE_11M_INDEX, + IWL_RATE_COUNT, + IWL_RATE_INVM_INDEX, + IWL_RATE_INVALID = IWL_RATE_INVM_INDEX +}; + +enum { + IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, + IWL_LAST_OFDM_RATE = IWL_RATE_54M_INDEX, + IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, + IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, +}; + +/* #define vs. enum to keep from defaulting to 'large integer' */ +#define IWL_RATE_6M_MASK (1< + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "iwlwifi.h" +#include "iwl-helpers.h" +#include "iwl-3945.h" +#include "iwl-3945-rs.h" + +#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \ + [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ + IWL_RATE_##r##M_IEEE, \ + IWL_RATE_##ip##M_INDEX, \ + IWL_RATE_##in##M_INDEX, \ + IWL_RATE_##rp##M_INDEX, \ + IWL_RATE_##rn##M_INDEX, \ + IWL_RATE_##pp##M_INDEX, \ + IWL_RATE_##np##M_INDEX } + +/* + * Parameter order: + * rate, prev rate, next rate, prev tgg rate, next tgg rate + * + * If there isn't a valid next or previous rate then INV is used which + * maps to IWL_RATE_INVALID + * + */ +const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { + IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11), /* 6mbps */ + IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11), /* 9mbps */ + IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18), /* 12mbps */ + IWL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24), /* 18mbps */ + IWL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36), /* 24mbps */ + IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48), /* 36mbps */ + IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54), /* 48mbps */ + IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */ + IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2), /* 1mbps */ + IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5), /* 2mbps */ + IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11), /*5.5mbps */ + IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18), /* 11mbps */ +}; + +/* 1 = enable the iwl_disable_events() function */ +#define IWL_EVT_DISABLE (0) +#define IWL_EVT_DISABLE_SIZE (1532/32) + +/** + * iwl_disable_events - Disable selected events in uCode event log + * + * Disable an event by writing "1"s into "disable" + * bitmap in SRAM. Bit position corresponds to Event # (id/type). + * Default values of 0 enable uCode events to be logged. + * Use for only special debugging. This function is just a placeholder as-is, + * you'll need to provide the special bits! ... + * ... and set IWL_EVT_DISABLE to 1. */ +void iwl_disable_events(struct iwl_priv *priv) +{ + int rc; + int i; + u32 base; /* SRAM address of event log header */ + u32 disable_ptr; /* SRAM address of event-disable bitmap array */ + u32 array_size; /* # of u32 entries in array */ + u32 evt_disable[IWL_EVT_DISABLE_SIZE] = { + 0x00000000, /* 31 - 0 Event id numbers */ + 0x00000000, /* 63 - 32 */ + 0x00000000, /* 95 - 64 */ + 0x00000000, /* 127 - 96 */ + 0x00000000, /* 159 - 128 */ + 0x00000000, /* 191 - 160 */ + 0x00000000, /* 223 - 192 */ + 0x00000000, /* 255 - 224 */ + 0x00000000, /* 287 - 256 */ + 0x00000000, /* 319 - 288 */ + 0x00000000, /* 351 - 320 */ + 0x00000000, /* 383 - 352 */ + 0x00000000, /* 415 - 384 */ + 0x00000000, /* 447 - 416 */ + 0x00000000, /* 479 - 448 */ + 0x00000000, /* 511 - 480 */ + 0x00000000, /* 543 - 512 */ + 0x00000000, /* 575 - 544 */ + 0x00000000, /* 607 - 576 */ + 0x00000000, /* 639 - 608 */ + 0x00000000, /* 671 - 640 */ + 0x00000000, /* 703 - 672 */ + 0x00000000, /* 735 - 704 */ + 0x00000000, /* 767 - 736 */ + 0x00000000, /* 799 - 768 */ + 0x00000000, /* 831 - 800 */ + 0x00000000, /* 863 - 832 */ + 0x00000000, /* 895 - 864 */ + 0x00000000, /* 927 - 896 */ + 0x00000000, /* 959 - 928 */ + 0x00000000, /* 991 - 960 */ + 0x00000000, /* 1023 - 992 */ + 0x00000000, /* 1055 - 1024 */ + 0x00000000, /* 1087 - 1056 */ + 0x00000000, /* 1119 - 1088 */ + 0x00000000, /* 1151 - 1120 */ + 0x00000000, /* 1183 - 1152 */ + 0x00000000, /* 1215 - 1184 */ + 0x00000000, /* 1247 - 1216 */ + 0x00000000, /* 1279 - 1248 */ + 0x00000000, /* 1311 - 1280 */ + 0x00000000, /* 1343 - 1312 */ + 0x00000000, /* 1375 - 1344 */ + 0x00000000, /* 1407 - 1376 */ + 0x00000000, /* 1439 - 1408 */ + 0x00000000, /* 1471 - 1440 */ + 0x00000000, /* 1503 - 1472 */ + }; + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32))); + array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32))); + iwl_release_restricted_access(priv); + + if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) { + IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n", + disable_ptr); + rc = iwl_grab_restricted_access(priv); + for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) + iwl_write_restricted_mem(priv, + disable_ptr + + (i * sizeof(u32)), + evt_disable[i]); + + iwl_release_restricted_access(priv); + } else { + IWL_DEBUG_INFO("Selected uCode log events may be disabled\n"); + IWL_DEBUG_INFO(" by writing \"1\"s into disable bitmap\n"); + IWL_DEBUG_INFO(" in SRAM at 0x%x, size %d u32s\n", + disable_ptr, array_size); + } + +} + +/** + * iwl3945_get_antenna_flags - Get antenna flags for RXON command + * @priv: eeprom and antenna fields are used to determine antenna flags + * + * priv->eeprom is used to determine if antenna AUX/MAIN are reversed + * priv->antenna specifies the antenna diversity mode: + * + * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself + * IWL_ANTENNA_MAIN - Force MAIN antenna + * IWL_ANTENNA_AUX - Force AUX antenna + */ +__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv) +{ + switch (priv->antenna) { + case IWL_ANTENNA_DIVERSITY: + return 0; + + case IWL_ANTENNA_MAIN: + if (priv->eeprom.antenna_switch_type) + return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK; + return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK; + + case IWL_ANTENNA_AUX: + if (priv->eeprom.antenna_switch_type) + return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK; + return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK; + } + + /* bad antenna selector value */ + IWL_ERROR("Bad antenna selector value (0x%x)\n", priv->antenna); + return 0; /* "diversity" is default if error */ +} + +/***************************************************************************** + * + * Intel PRO/Wireless 3945ABG/BG Network Connection + * + * RX handler implementations + * + * Used by iwl-base.c + * + *****************************************************************************/ + +void iwl_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("Statistics notification received (%d vs %d).\n", + (int)sizeof(struct iwl_notif_statistics), + le32_to_cpu(pkt->len)); + + memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics)); + + priv->last_statistics_time = jiffies; +} + +static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats, + u16 phy_flags) +{ + struct ieee80211_hdr *hdr; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + short len = le16_to_cpu(rx_hdr->len); + + /* We received data from the HW, so stop the watchdog */ + if (unlikely((len + IWL_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { + IWL_DEBUG_DROP("Corruption detected!\n"); + return; + } + + /* We only process data packets if the interface is open */ + if (unlikely(!priv->is_open)) { + IWL_DEBUG_DROP_LIMIT + ("Dropping packet while interface is not open.\n"); + return; + } + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + if (iwl_param_hwcrypto) + iwl_set_decrypted_flag(priv, rxb->skb, + le32_to_cpu(rx_end->status), + stats); + iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt), + len, stats, phy_flags); + return; + } + + skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, le16_to_cpu(rx_hdr->len)); + + hdr = (void *)rxb->skb->data; + + if (iwl_param_hwcrypto) + iwl_set_decrypted_flag(priv, rxb->skb, + le32_to_cpu(rx_end->status), stats); + + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + rxb->skb = NULL; +} + +static void iwl3945_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + struct ieee80211_hdr *header; + u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags); + u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); + u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); + struct ieee80211_rx_status stats = { + .mactime = le64_to_cpu(rx_end->timestamp), + .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)), + .channel = le16_to_cpu(rx_hdr->channel), + .phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + MODE_IEEE80211G : MODE_IEEE80211A, + .antenna = 0, + .rate = rx_hdr->rate, + .flag = 0, + }; + u8 network_packet; + int snr; + + if ((unlikely(rx_stats->phy_count > 20))) { + IWL_DEBUG_DROP + ("dsp size out of range [0,20]: " + "%d/n", rx_stats->phy_count); + return; + } + + if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR) + || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status); + return; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags); + return; + } + + /* Convert 3945's rssi indicator to dBm */ + stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; + + /* Set default noise value to -127 */ + if (priv->last_rx_noise == 0) + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + /* 3945 provides noise info for OFDM frames only. + * sig_avg and noise_diff are measured by the 3945's digital signal + * processor (DSP), and indicate linear levels of signal level and + * distortion/noise within the packet preamble after + * automatic gain control (AGC). sig_avg should stay fairly + * constant if the radio's AGC is working well. + * Since these values are linear (not dB or dBm), linear + * signal-to-noise ratio (SNR) is (sig_avg / noise_diff). + * Convert linear SNR to dB SNR, then subtract that from rssi dBm + * to obtain noise level in dBm. + * Calculate stats.signal (quality indicator in %) based on SNR. */ + if (rx_stats_noise_diff) { + snr = rx_stats_sig_avg / rx_stats_noise_diff; + stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr); + stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise); + + /* If noise info not available, calculate signal quality indicator (%) + * using just the dBm signal level. */ + } else { + stats.noise = priv->last_rx_noise; + stats.signal = iwl_calc_sig_qual(stats.ssi, 0); + } + + + IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", + stats.ssi, stats.noise, stats.signal, + rx_stats_sig_avg, rx_stats_noise_diff); + + stats.freq = ieee80211chan2mhz(stats.channel); + + /* can be covered by iwl_report_frame() in most cases */ +/* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */ + + header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); + + network_packet = iwl_is_network_packet(priv, header); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_STATS && net_ratelimit()) + IWL_DEBUG_STATS + ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n", + network_packet ? '*' : ' ', + stats.channel, stats.ssi, stats.ssi, + stats.ssi, stats.rate); + + if (iwl_debug_level & (IWL_DL_RX)) + /* Set "1" to report good data frames in groups of 100 */ + iwl_report_frame(priv, pkt, header, 1); +#endif + + if (network_packet) { + priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); + priv->last_tsf = le64_to_cpu(rx_end->timestamp); + priv->last_rx_rssi = stats.ssi; + priv->last_rx_noise = stats.noise; + } + + switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_MGMT: + switch (le16_to_cpu(header->frame_control) & + IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_RESP: + case IEEE80211_STYPE_BEACON:{ + /* If this is a beacon or probe response for + * our network then cache the beacon + * timestamp */ + if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA) + && !compare_ether_addr(header->addr2, + priv->bssid)) || + ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + && !compare_ether_addr(header->addr3, + priv->bssid)))) { + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *)header; + __le32 *pos; + pos = + (__le32 *) & mgmt->u.beacon. + timestamp; + priv->timestamp0 = le32_to_cpu(pos[0]); + priv->timestamp1 = le32_to_cpu(pos[1]); + priv->beacon_int = le16_to_cpu( + mgmt->u.beacon.beacon_int); + if (priv->call_post_assoc_from_beacon && + (priv->iw_mode == + IEEE80211_IF_TYPE_STA)) + queue_work(priv->workqueue, + &priv->post_associate.work); + + priv->call_post_assoc_from_beacon = 0; + } + + break; + } + + case IEEE80211_STYPE_ACTION: + /* TODO: Parse 802.11h frames for CSA... */ + break; + + /* + * TODO: There is no callback function from upper + * stack to inform us when associated status. this + * work around to sniff assoc_resp management frame + * and finish the association process. + */ + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP:{ + struct ieee80211_mgmt *mgnt = + (struct ieee80211_mgmt *)header; + priv->assoc_id = (~((1 << 15) | (1 << 14)) & + le16_to_cpu(mgnt->u. + assoc_resp.aid)); + priv->assoc_capability = + le16_to_cpu(mgnt->u.assoc_resp.capab_info); + if (priv->beacon_int) + queue_work(priv->workqueue, + &priv->post_associate.work); + else + priv->call_post_assoc_from_beacon = 1; + break; + } + + case IEEE80211_STYPE_PROBE_REQ:{ + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + IWL_DEBUG_DROP + ("Dropping (non network): " MAC_FMT + ", " MAC_FMT ", " MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + return; + } + } + + iwl3945_handle_data_packet(priv, 0, rxb, &stats, phy_flags); + break; + + case IEEE80211_FTYPE_CTL: + break; + + case IEEE80211_FTYPE_DATA: + if (unlikely(is_duplicate_packet(priv, header))) + IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", " + MAC_FMT ", " MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + else + iwl3945_handle_data_packet(priv, 1, rxb, &stats, + phy_flags); + break; + } +} + +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, + dma_addr_t addr, u16 len) +{ + int count; + u32 pad; + struct iwl_tfd_frame *tfd = (struct iwl_tfd_frame *)ptr; + + count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); + pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags)); + + if ((count >= NUM_TFD_CHUNKS) || (count < 0)) { + IWL_ERROR("Error can not send more than %d chunks\n", + NUM_TFD_CHUNKS); + return -EINVAL; + } + + tfd->pa[count].addr = cpu_to_le32(addr); + tfd->pa[count].len = cpu_to_le32(len); + + count++; + + tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(count) | + TFD_CTL_PAD_SET(pad)); + + return 0; +} + +/** + * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used] + * + * Does NOT advance any indexes + */ +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; + struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used]; + struct pci_dev *dev = priv->pci_dev; + int i; + int counter; + + /* classify bd */ + if (txq->q.id == IWL_CMD_QUEUE_NUM) + /* nothing to cleanup after for host commands */ + return 0; + + /* sanity check */ + counter = TFD_CTL_COUNT_GET(le32_to_cpu(bd->control_flags)); + if (counter > NUM_TFD_CHUNKS) { + IWL_ERROR("Too many chunks: %i\n", counter); + /* @todo issue fatal error, it is quite serious situation */ + return 0; + } + + /* unmap chunks if any */ + + for (i = 1; i < counter; i++) { + pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr), + le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE); + if (txq->txb[txq->q.last_used].skb[0]) { + struct sk_buff *skb = txq->txb[txq->q.last_used].skb[0]; + if (txq->txb[txq->q.last_used].skb[0]) { + /* Can be called from interrupt context */ + dev_kfree_skb_any(skb); + txq->txb[txq->q.last_used].skb[0] = NULL; + } + } + } + return 0; +} + +u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) +{ + int i; + int ret = IWL_INVALID_STATION; + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + if ((priv->stations[i].used) && + (!compare_ether_addr + (priv->stations[i].sta.sta.addr, addr))) { + ret = i; + goto out; + } + + IWL_DEBUG_INFO("can not find STA " MAC_FMT " (total %d)\n", + MAC_ARG(addr), priv->num_stations); + out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; +} + +/** + * iwl_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: + * +*/ +void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, int sta_id, int tx_id) +{ + unsigned long flags; + u16 rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); + u16 rate_mask; + int rate; + u8 rts_retry_limit; + u8 data_retry_limit; + __le32 tx_flags; + u16 fc = le16_to_cpu(hdr->frame_control); + + rate = iwl_rates[rate_index].plcp; + tx_flags = cmd->cmd.tx.tx_flags; + + /* We need to figure out how to get the sta->supp_rates while + * in this running context; perhaps encoding into ctrl->tx_rate? */ + rate_mask = IWL_RATES_MASK; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].current_rate.rate_n_flags = rate; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + (sta_id != IWL3945_BROADCAST_ID) && + (sta_id != IWL_MULTICAST_ID)) + priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate; + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + if (tx_id >= IWL_CMD_QUEUE_NUM) + rts_retry_limit = 3; + else + rts_retry_limit = 7; + + if (ieee80211_is_probe_response(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; + + if (priv->data_retry_limit != -1) + data_retry_limit = priv->data_retry_limit; + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + if (tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; + } + } + + cmd->cmd.tx.rts_retry_limit = rts_retry_limit; + cmd->cmd.tx.data_retry_limit = data_retry_limit; + cmd->cmd.tx.rate = rate; + cmd->cmd.tx.tx_flags = tx_flags; + + /* OFDM */ + cmd->cmd.tx.supp_rates[0] = rate_mask & IWL_OFDM_RATES_MASK; + + /* CCK */ + cmd->cmd.tx.supp_rates[1] = (rate_mask >> 8) & 0xF; + + IWL_DEBUG_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X " + "cck/ofdm mask: 0x%x/0x%x\n", sta_id, + cmd->cmd.tx.rate, le32_to_cpu(cmd->cmd.tx.tx_flags), + cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]); +} + +u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) +{ + unsigned long flags_spin; + struct iwl_station_entry *station; + + if (sta_id == IWL_INVALID_STATION) + return IWL_INVALID_STATION; + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + station = &priv->stations[sta_id]; + + station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK; + station->sta.rate_n_flags = cpu_to_le16(tx_rate); + station->current_rate.rate_n_flags = tx_rate; + station->sta.mode = STA_CONTROL_MODIFY_MSK; + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + + iwl_send_add_station(priv, &station->sta, flags); + IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n", + sta_id, tx_rate); + return sta_id; +} + +void iwl_hw_card_show_info(struct iwl_priv *priv) +{ + IWL_DEBUG_INFO("3945ABG HW Version %u.%u.%u\n", + ((priv->eeprom.board_revision >> 8) & 0x0F), + ((priv->eeprom.board_revision >> 8) >> 4), + (priv->eeprom.board_revision & 0x00FF)); + + IWL_DEBUG_INFO("3945ABG PBA Number %.*s\n", + (int)sizeof(priv->eeprom.board_pba_number), + priv->eeprom.board_pba_number); + + IWL_DEBUG_INFO("EEPROM_ANTENNA_SWITCH_TYPE is 0x%02X\n", + priv->eeprom.antenna_switch_type); +} + +static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + if (!pwr_max) { + u32 val; + + rc = pci_read_config_dword(priv->pci_dev, + PCI_POWER_SOURCE, &val); + if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) { + iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + iwl_release_restricted_access(priv); + + iwl_poll_bit(priv, CSR_GPIO_IN, + CSR_GPIO_IN_VAL_VAUX_PWR_SRC, + CSR_GPIO_IN_BIT_AUX_POWER, 5000); + } else + iwl_release_restricted_access(priv); + } else { + iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); + + iwl_release_restricted_access(priv); + iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, + CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ + } + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl_write_restricted(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr); + iwl_write_restricted(priv, FH_RCSR_RPTR_ADDR(0), + priv->hw_setting.shared_phys + + offsetof(struct iwl_shared, rx_read_ptr[0])); + iwl_write_restricted(priv, FH_RCSR_WPTR(0), 0); + iwl_write_restricted(priv, FH_RCSR_CONFIG(0), + ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE | + ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE | + ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN | + ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 | + (RX_QUEUE_SIZE_LOG << ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) | + ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST | + (1 << ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) | + ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH); + + /* fake read to flush all prev I/O */ + iwl_read_restricted(priv, FH_RSSR_CTRL); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int iwl3945_tx_reset(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* bypass mode */ + iwl_write_restricted_reg(priv, SCD_MODE_REG, 0x2); + + /* RA 0 is active */ + iwl_write_restricted_reg(priv, SCD_ARASTAT_REG, 0x01); + + /* all 6 fifo are active */ + iwl_write_restricted_reg(priv, SCD_TXFACT_REG, 0x3f); + + iwl_write_restricted_reg(priv, SCD_SBYP_MODE_1_REG, 0x010000); + iwl_write_restricted_reg(priv, SCD_SBYP_MODE_2_REG, 0x030002); + iwl_write_restricted_reg(priv, SCD_TXF4MF_REG, 0x000004); + iwl_write_restricted_reg(priv, SCD_TXF5MF_REG, 0x000005); + + iwl_write_restricted(priv, FH_TSSR_CBB_BASE, + priv->hw_setting.shared_phys); + + iwl_write_restricted(priv, FH_TSSR_MSG_CONFIG, + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/** + * iwl3945_txq_ctx_reset - Reset TX queue context + * + * Destroys all DMA structures and initialize them again + */ +static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) +{ + int rc; + int txq_id, slots_num; + + iwl_hw_txq_ctx_free(priv); + + /* Tx CMD queue */ + rc = iwl3945_tx_reset(priv); + if (rc) + goto error; + + /* Tx queue(s) */ + for (txq_id = 0; txq_id < TFD_QUEUE_MAX; 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, + txq_id); + if (rc) { + IWL_ERROR("Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return rc; + + error: + iwl_hw_txq_ctx_free(priv); + return rc; +} + +int iwl_hw_nic_init(struct iwl_priv *priv) +{ + u8 rev_id; + int rc; + unsigned long flags; + struct iwl_rx_queue *rxq = &priv->rxq; + + iwl_power_init_handle(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24)); + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("Failed to init the card\n"); + return rc; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + udelay(20); + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + /* Determine HW type */ + rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + if (rc) + return rc; + IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); + + iwl3945_nic_set_pwr_src(priv, 1); + spin_lock_irqsave(&priv->lock, flags); + + if (rev_id & PCI_CFG_REV_ID_BIT_RTP) + IWL_DEBUG_INFO("RTP type \n"); + else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { + IWL_DEBUG_INFO("ALM-MB type\n"); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB); + } else { + IWL_DEBUG_INFO("ALM-MM type\n"); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Initialize the EEPROM */ + rc = iwl_eeprom_init(priv); + if (rc) + return rc; + + spin_lock_irqsave(&priv->lock, flags); + if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) { + IWL_DEBUG_INFO("SKU OP mode is mrc\n"); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC); + } else + IWL_DEBUG_INFO("SKU OP mode is basic\n"); + + if ((priv->eeprom.board_revision & 0xF0) == 0xD0) { + IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", + priv->eeprom.board_revision); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); + } else { + IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", + priv->eeprom.board_revision); + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); + } + + if (priv->eeprom.almgor_m_version <= 1) { + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A); + IWL_DEBUG_INFO("Card M type A version is 0x%X\n", + priv->eeprom.almgor_m_version); + } else { + IWL_DEBUG_INFO("Card M type B version is 0x%X\n", + priv->eeprom.almgor_m_version); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B); + } + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) + IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n"); + + if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) + IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n"); + + /* Allocate the RX queue, or reset if it is already allocated */ + if (!rxq->bd) { + rc = iwl_rx_queue_alloc(priv); + if (rc) { + IWL_ERROR("Unable to initialize Rx queue\n"); + return -ENOMEM; + } + } else + iwl_rx_queue_reset(priv, rxq); + + iwl_rx_replenish(priv); + + iwl3945_rx_init(priv, rxq); + + spin_lock_irqsave(&priv->lock, flags); + + /* Look at using this instead: + rxq->need_update = 1; + iwl_rx_queue_update_write_ptr(priv, rxq); + */ + + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + iwl_write_restricted(priv, FH_RCSR_WPTR(0), rxq->write & ~7); + iwl_release_restricted_access(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + rc = iwl3945_txq_ctx_reset(priv); + if (rc) + return rc; + + set_bit(STATUS_INIT, &priv->status); + + return 0; +} + +/** + * iwl_hw_txq_ctx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +{ + int txq_id; + + /* Tx queues */ + for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) + iwl_tx_queue_free(priv, &priv->txq[txq_id]); +} + +void iwl_hw_txq_ctx_stop(struct iwl_priv *priv) +{ + int queue; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_grab_restricted_access(priv)) { + spin_unlock_irqrestore(&priv->lock, flags); + iwl_hw_txq_ctx_free(priv); + return; + } + + /* stop SCD */ + iwl_write_restricted_reg(priv, SCD_MODE_REG, 0); + + /* reset TFD queues */ + for (queue = TFD_QUEUE_MIN; queue < TFD_QUEUE_MAX; queue++) { + iwl_write_restricted(priv, FH_TCSR_CONFIG(queue), 0x0); + iwl_poll_restricted_bit(priv, FH_TSSR_TX_STATUS, + ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(queue), + 1000); + } + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_hw_txq_ctx_free(priv); +} + +int iwl_hw_nic_stop_master(struct iwl_priv *priv) +{ + int rc = 0; + u32 reg_val; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + reg_val = iwl_read32(priv, CSR_GP_CNTRL); + + if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == + (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) + IWL_DEBUG_INFO("Card in power save, master is already " + "stopped\n"); + else { + rc = iwl_poll_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + } + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("stop master\n"); + + return rc; +} + +int iwl_hw_nic_reset(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + + iwl_hw_nic_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + + rc = iwl_grab_restricted_access(priv); + if (!rc) { + iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG, + APMG_CLK_VAL_BSM_CLK_RQT); + + udelay(10); + + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + iwl_write_restricted_reg(priv, APMG_RTC_INT_MSK_REG, 0x0); + iwl_write_restricted_reg(priv, APMG_RTC_INT_STT_REG, + 0xFFFFFFFF); + + /* enable DMA */ + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + udelay(10); + + iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + iwl_release_restricted_access(priv); + } + + /* Clear the 'host command active' bit... */ + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + + wake_up_interruptible(&priv->wait_command_queue); + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +/** + * iwl_hw_reg_adjust_power_by_temp - return index delta into power gain settings table + */ +static int iwl_hw_reg_adjust_power_by_temp(int new_reading, int old_reading) +{ + return (new_reading - old_reading) * (-11) / 100; +} + +/** + * iwl_hw_reg_temp_out_of_range - Keep temperature in sane range + */ +static inline int iwl_hw_reg_temp_out_of_range(int temperature) +{ + return (((temperature < -260) || (temperature > 25)) ? 1 : 0); +} + +int iwl_hw_get_temperature(struct iwl_priv *priv) +{ + return iwl_read32(priv, CSR_UCODE_DRV_GP2); +} + +/** + * iwl_hw_reg_txpower_get_temperature - get current temperature by reading from NIC + */ +static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv) +{ + int temperature; + + temperature = iwl_hw_get_temperature(priv); + + /* driver's okay range is -260 to +25. + * human readable okay range is 0 to +285 */ + IWL_DEBUG_INFO("Temperature: %d\n", temperature + IWL_TEMP_CONVERT); + + /* handle insane temp reading */ + if (iwl_hw_reg_temp_out_of_range(temperature)) { + IWL_ERROR("Error bad temperature value %d\n", temperature); + + /* if really really hot(?), + * substitute the 3rd band/group's temp measured at factory */ + if (priv->last_temperature > 100) + temperature = priv->eeprom.groups[2].temperature; + else /* else use most recent "sane" value from driver */ + temperature = priv->last_temperature; + } + + return temperature; /* raw, not "human readable" */ +} + +/* Adjust Txpower only if temperature variance is greater than threshold. + * + * Both are lower than older versions' 9 degrees */ +#define IWL_TEMPERATURE_LIMIT_TIMER 6 + +/** + * is_temp_calib_needed - determines if new calibration is needed + * + * records new temperature in tx_mgr->temperature. + * replaces tx_mgr->last_temperature *only* if calib needed + * (assumes caller will actually do the calibration!). */ +static int is_temp_calib_needed(struct iwl_priv *priv) +{ + int temp_diff; + + priv->temperature = iwl_hw_reg_txpower_get_temperature(priv); + temp_diff = priv->temperature - priv->last_temperature; + + /* get absolute value */ + if (temp_diff < 0) { + IWL_DEBUG_POWER("Getting cooler, delta %d,\n", temp_diff); + temp_diff = -temp_diff; + } else if (temp_diff == 0) + IWL_DEBUG_POWER("Same temp,\n"); + else + IWL_DEBUG_POWER("Getting warmer, delta %d,\n", temp_diff); + + /* if we don't need calibration, *don't* update last_temperature */ + if (temp_diff < IWL_TEMPERATURE_LIMIT_TIMER) { + IWL_DEBUG_POWER("Timed thermal calib not needed\n"); + return 0; + } + + IWL_DEBUG_POWER("Timed thermal calib needed\n"); + + /* assume that caller will actually do calib ... + * update the "last temperature" value */ + priv->last_temperature = priv->temperature; + return 1; +} + +#define IWL_MAX_GAIN_ENTRIES 78 +#define IWL_CCK_FROM_OFDM_POWER_DIFF -5 +#define IWL_CCK_FROM_OFDM_INDEX_DIFF (10) + +/* radio and DSP power table, each step is 1/2 dB. + * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */ +static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = { + { + {251, 127}, /* 2.4 GHz, highest power */ + {251, 127}, + {251, 127}, + {251, 127}, + {251, 125}, + {251, 110}, + {251, 105}, + {251, 98}, + {187, 125}, + {187, 115}, + {187, 108}, + {187, 99}, + {243, 119}, + {243, 111}, + {243, 105}, + {243, 97}, + {243, 92}, + {211, 106}, + {211, 100}, + {179, 120}, + {179, 113}, + {179, 107}, + {147, 125}, + {147, 119}, + {147, 112}, + {147, 106}, + {147, 101}, + {147, 97}, + {147, 91}, + {115, 107}, + {235, 121}, + {235, 115}, + {235, 109}, + {203, 127}, + {203, 121}, + {203, 115}, + {203, 108}, + {203, 102}, + {203, 96}, + {203, 92}, + {171, 110}, + {171, 104}, + {171, 98}, + {139, 116}, + {227, 125}, + {227, 119}, + {227, 113}, + {227, 107}, + {227, 101}, + {227, 96}, + {195, 113}, + {195, 106}, + {195, 102}, + {195, 95}, + {163, 113}, + {163, 106}, + {163, 102}, + {163, 95}, + {131, 113}, + {131, 106}, + {131, 102}, + {131, 95}, + {99, 113}, + {99, 106}, + {99, 102}, + {99, 95}, + {67, 113}, + {67, 106}, + {67, 102}, + {67, 95}, + {35, 113}, + {35, 106}, + {35, 102}, + {35, 95}, + {3, 113}, + {3, 106}, + {3, 102}, + {3, 95} }, /* 2.4 GHz, lowest power */ + { + {251, 127}, /* 5.x GHz, highest power */ + {251, 120}, + {251, 114}, + {219, 119}, + {219, 101}, + {187, 113}, + {187, 102}, + {155, 114}, + {155, 103}, + {123, 117}, + {123, 107}, + {123, 99}, + {123, 92}, + {91, 108}, + {59, 125}, + {59, 118}, + {59, 109}, + {59, 102}, + {59, 96}, + {59, 90}, + {27, 104}, + {27, 98}, + {27, 92}, + {115, 118}, + {115, 111}, + {115, 104}, + {83, 126}, + {83, 121}, + {83, 113}, + {83, 105}, + {83, 99}, + {51, 118}, + {51, 111}, + {51, 104}, + {51, 98}, + {19, 116}, + {19, 109}, + {19, 102}, + {19, 98}, + {19, 93}, + {171, 113}, + {171, 107}, + {171, 99}, + {139, 120}, + {139, 113}, + {139, 107}, + {139, 99}, + {107, 120}, + {107, 113}, + {107, 107}, + {107, 99}, + {75, 120}, + {75, 113}, + {75, 107}, + {75, 99}, + {43, 120}, + {43, 113}, + {43, 107}, + {43, 99}, + {11, 120}, + {11, 113}, + {11, 107}, + {11, 99}, + {131, 107}, + {131, 99}, + {99, 120}, + {99, 113}, + {99, 107}, + {99, 99}, + {67, 120}, + {67, 113}, + {67, 107}, + {67, 99}, + {35, 120}, + {35, 113}, + {35, 107}, + {35, 99}, + {3, 120} } /* 5.x GHz, lowest power */ +}; + +static inline u8 iwl_hw_reg_fix_power_index(int index) +{ + if (index < 0) + return 0; + if (index >= IWL_MAX_GAIN_ENTRIES) + return IWL_MAX_GAIN_ENTRIES - 1; + return (u8) index; +} + +/* Kick off thermal recalibration check every 60 seconds */ +#define REG_RECALIB_PERIOD (60) + +/** + * iwl_hw_reg_set_scan_power - Set Tx power for scan probe requests + * + * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK) + * or 6 Mbit (OFDM) rates. + */ +static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index, + s32 rate_index, const s8 *clip_pwrs, + struct iwl_channel_info *ch_info, + int band_index) +{ + struct iwl_scan_power_info *scan_power_info; + s8 power; + u8 power_index; + + scan_power_info = &ch_info->scan_pwr_info[scan_tbl_index]; + + /* use this channel group's 6Mbit clipping/saturation pwr, + * but cap at regulatory scan power restriction (set during init + * based on eeprom channel data) for this channel. */ + power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX]); + + /* further limit to user's max power preference. + * FIXME: Other spectrum management power limitations do not + * seem to apply?? */ + power = min(power, priv->user_txpower_limit); + scan_power_info->requested_power = power; + + /* find difference between new scan *power* and current "normal" + * Tx *power* for 6Mb. Use this difference (x2) to adjust the + * current "normal" temperature-compensated Tx power *index* for + * this rate (1Mb or 6Mb) to yield new temp-compensated scan power + * *index*. */ + power_index = ch_info->power_info[rate_index].power_table_index + - (power - ch_info->power_info + [IWL_RATE_6M_INDEX].requested_power) * 2; + + /* store reference index that we use when adjusting *all* scan + * powers. So we can accommodate user (all channel) or spectrum + * management (single channel) power changes "between" temperature + * feedback compensation procedures. + * don't force fit this reference index into gain table; it may be a + * negative number. This will help avoid errors when we're at + * the lower bounds (highest gains, for warmest temperatures) + * of the table. */ + + /* don't exceed table bounds for "real" setting */ + power_index = iwl_hw_reg_fix_power_index(power_index); + + scan_power_info->power_table_index = power_index; + scan_power_info->tpc.tx_gain = + power_gain_table[band_index][power_index].tx_gain; + scan_power_info->tpc.dsp_atten = + power_gain_table[band_index][power_index].dsp_atten; +} + +/** + * iwl_hw_reg_send_txpower - fill in Tx Power command with gain settings + * + * Configures power settings for all rates for the current channel, + * using values from channel info struct, and send to NIC + */ +int iwl_hw_reg_send_txpower(struct iwl_priv *priv) +{ + int rate_idx; + const struct iwl_channel_info *ch_info = NULL; + struct iwl_txpowertable_cmd txpower = { + .channel = priv->active_rxon.channel, + }; + + txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1; + ch_info = iwl_get_channel_info(priv, + priv->phymode, + le16_to_cpu(priv->active_rxon.channel)); + if (!ch_info) { + IWL_ERROR + ("Failed to get channel info for channel %d [%d]\n", + le16_to_cpu(priv->active_rxon.channel), priv->phymode); + return -EINVAL; + } + + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_POWER("Not calling TX_PWR_TABLE_CMD on " + "non-Tx channel.\n"); + return 0; + } + + /* fill cmd with power settings for all rates for current channel */ + for (rate_idx = 0; rate_idx < IWL_RATE_COUNT; rate_idx++) { + txpower.power[rate_idx].tpc = ch_info->power_info[rate_idx].tpc; + txpower.power[rate_idx].rate = iwl_rates[rate_idx].plcp; + + IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n", + le16_to_cpu(txpower.channel), + txpower.band, + txpower.power[rate_idx].tpc.tx_gain, + txpower.power[rate_idx].tpc.dsp_atten, + txpower.power[rate_idx].rate); + } + + return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, + sizeof(struct iwl_txpowertable_cmd), &txpower); + +} + +/** + * iwl_hw_reg_set_new_power - Configures power tables at new levels + * @ch_info: Channel to update. Uses power_info.requested_power. + * + * Replace requested_power and base_power_index ch_info fields for + * one channel. + * + * Called if user or spectrum management changes power preferences. + * Takes into account h/w and modulation limitations (clip power). + * + * This does *not* send anything to NIC, just sets up ch_info for one channel. + * + * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to + * properly fill out the scan powers, and actual h/w gain settings, + * and send changes to NIC + */ +static int iwl_hw_reg_set_new_power(struct iwl_priv *priv, + struct iwl_channel_info *ch_info) +{ + struct iwl_channel_power_info *power_info; + int power_changed = 0; + int i; + const s8 *clip_pwrs; + int power; + + /* Get this chnlgrp's rate-to-max/clip-powers table */ + clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers; + + /* Get this channel's rate-to-current-power settings table */ + power_info = ch_info->power_info; + + /* update OFDM Txpower settings */ + for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE; + i++, ++power_info) { + int delta_idx; + + /* limit new power to be no more than h/w capability */ + power = min(ch_info->curr_txpow, clip_pwrs[i]); + if (power == power_info->requested_power) + continue; + + /* find difference between old and new requested powers, + * update base (non-temp-compensated) power index */ + delta_idx = (power - power_info->requested_power) * 2; + power_info->base_power_index -= delta_idx; + + /* save new requested power value */ + power_info->requested_power = power; + + power_changed = 1; + } + + /* update CCK Txpower settings, based on OFDM 12M setting ... + * ... all CCK power settings for a given channel are the *same*. */ + if (power_changed) { + power = + ch_info->power_info[IWL_RATE_12M_INDEX]. + requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF; + + /* do all CCK rates' iwl_channel_power_info structures */ + for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++) { + power_info->requested_power = power; + power_info->base_power_index = + ch_info->power_info[IWL_RATE_12M_INDEX]. + base_power_index + IWL_CCK_FROM_OFDM_INDEX_DIFF; + ++power_info; + } + } + + return 0; +} + +/** + * iwl_hw_reg_get_ch_txpower_limit - returns new power limit for channel + * + * NOTE: Returned power limit may be less (but not more) than requested, + * based strictly on regulatory (eeprom and spectrum mgt) limitations + * (no consideration for h/w clipping limitations). + */ +static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info) +{ + s8 max_power; + +#if 0 + /* if we're using TGd limits, use lower of TGd or EEPROM */ + if (ch_info->tgd_data.max_power != 0) + max_power = min(ch_info->tgd_data.max_power, + ch_info->eeprom.max_power_avg); + + /* else just use EEPROM limits */ + else +#endif + max_power = ch_info->eeprom.max_power_avg; + + return min(max_power, ch_info->max_power_avg); +} + +/** + * iwl_hw_reg_comp_txpower_temp - Compensate for temperature + * + * Compensate txpower settings of *all* channels for temperature. + * This only accounts for the difference between current temperature + * and the factory calibration temperatures, and bases the new settings + * on the channel's base_power_index. + * + * If RxOn is "associated", this sends the new Txpower to NIC! + */ +static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch_info = NULL; + int delta_index; + const s8 *clip_pwrs; /* array of h/w max power levels for each rate */ + u8 a_band; + u8 rate_index; + u8 scan_tbl_index; + u8 i; + int ref_temp; + int temperature = priv->temperature; + + /* set up new Tx power info for each and every channel, 2.4 and 5.x */ + for (i = 0; i < priv->channel_count; i++) { + ch_info = &priv->channel_info[i]; + a_band = is_channel_a_band(ch_info); + + /* Get this chnlgrp's factory calibration temperature */ + ref_temp = (s16)priv->eeprom.groups[ch_info->group_index]. + temperature; + + /* get power index adjustment based on curr and factory + * temps */ + delta_index = iwl_hw_reg_adjust_power_by_temp(temperature, + ref_temp); + + /* set tx power value for all rates, OFDM and CCK */ + for (rate_index = 0; rate_index < IWL_RATE_COUNT; + rate_index++) { + int power_idx = + ch_info->power_info[rate_index].base_power_index; + + /* temperature compensate */ + power_idx += delta_index; + + /* stay within table range */ + power_idx = iwl_hw_reg_fix_power_index(power_idx); + ch_info->power_info[rate_index]. + power_table_index = (u8) power_idx; + ch_info->power_info[rate_index].tpc = + power_gain_table[a_band][power_idx]; + } + + /* Get this chnlgrp's rate-to-max/clip-powers table */ + clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers; + + /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */ + for (scan_tbl_index = 0; + scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { + s32 actual_index = (scan_tbl_index == 0) ? + IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX; + iwl_hw_reg_set_scan_power(priv, scan_tbl_index, + actual_index, clip_pwrs, + ch_info, a_band); + } + } + + /* send Txpower command for current channel to ucode */ + return iwl_hw_reg_send_txpower(priv); +} + +int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) +{ + struct iwl_channel_info *ch_info; + s8 max_power; + u8 a_band; + u8 i; + + if (priv->user_txpower_limit == power) { + IWL_DEBUG_POWER("Requested Tx power same as current " + "limit: %ddBm.\n", power); + return 0; + } + + IWL_DEBUG_POWER("Setting upper limit clamp to %ddBm.\n", power); + priv->user_txpower_limit = power; + + /* set up new Tx powers for each and every channel, 2.4 and 5.x */ + + for (i = 0; i < priv->channel_count; i++) { + ch_info = &priv->channel_info[i]; + a_band = is_channel_a_band(ch_info); + + /* find minimum power of all user and regulatory constraints + * (does not consider h/w clipping limitations) */ + max_power = iwl_hw_reg_get_ch_txpower_limit(ch_info); + max_power = min(power, max_power); + if (max_power != ch_info->curr_txpow) { + ch_info->curr_txpow = max_power; + + /* this considers the h/w clipping limitations */ + iwl_hw_reg_set_new_power(priv, ch_info); + } + } + + /* update txpower settings for all channels, + * send to NIC if associated. */ + is_temp_calib_needed(priv); + iwl_hw_reg_comp_txpower_temp(priv); + + return 0; +} + +/* will add 3945 channel switch cmd handling later */ +int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) +{ + return 0; +} + +/** + * iwl3945_reg_txpower_periodic - called when time to check our temperature. + * + * -- reset periodic timer + * -- see if temp has changed enough to warrant re-calibration ... if so: + * -- correct coeffs for temp (can reset temp timer) + * -- save this temp as "last", + * -- send new set of gain settings to NIC + * NOTE: This should continue working, even when we're not associated, + * so we can keep our internal table of scan powers current. */ +void iwl3945_reg_txpower_periodic(struct iwl_priv *priv) +{ + /* This will kick in the "brute force" + * iwl_hw_reg_comp_txpower_temp() below */ + if (!is_temp_calib_needed(priv)) + goto reschedule; + + /* Set up a new set of temp-adjusted TxPowers, send to NIC. + * This is based *only* on current temperature, + * ignoring any previous power measurements */ + iwl_hw_reg_comp_txpower_temp(priv); + + reschedule: + queue_delayed_work(priv->workqueue, + &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ); +} + +void iwl3945_bg_reg_txpower_periodic(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + thermal_periodic.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl3945_reg_txpower_periodic(priv); + mutex_unlock(&priv->mutex); +} + +/** + * iwl_hw_reg_get_ch_grp_index - find the channel-group index (0-4) + * for the channel. + * + * This function is used when initializing channel-info structs. + * + * NOTE: These channel groups do *NOT* match the bands above! + * These channel groups are based on factory-tested channels; + * on A-band, EEPROM's "group frequency" entries represent the top + * channel in each group 1-4. Group 5 All B/G channels are in group 0. + */ +static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv, + const struct iwl_channel_info *ch_info) +{ + struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0]; + u8 group; + u16 group_index = 0; /* based on factory calib frequencies */ + u8 grp_channel; + + /* Find the group index for the channel ... don't use index 1(?) */ + if (is_channel_a_band(ch_info)) { + for (group = 1; group < 5; group++) { + grp_channel = ch_grp[group].group_channel; + if (ch_info->channel <= grp_channel) { + group_index = group; + break; + } + } + /* group 4 has a few channels *above* its factory cal freq */ + if (group == 5) + group_index = 4; + } else + group_index = 0; /* 2.4 GHz, group 0 */ + + IWL_DEBUG_POWER("Chnl %d mapped to grp %d\n", ch_info->channel, + group_index); + return group_index; +} + +/** + * iwl_hw_reg_get_matched_power_index - Interpolate to get nominal index + * + * Interpolate to get nominal (i.e. at factory calibration temperature) index + * into radio/DSP gain settings table for requested power. + */ +static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv, + s8 requested_power, + s32 setting_index, s32 *new_index) +{ + const struct iwl_eeprom_txpower_group *chnl_grp = NULL; + s32 index0, index1; + s32 power = 2 * requested_power; + s32 i; + const struct iwl_eeprom_txpower_sample *samples; + s32 gains0, gains1; + s32 res; + s32 denominator; + + chnl_grp = &priv->eeprom.groups[setting_index]; + samples = chnl_grp->samples; + for (i = 0; i < 5; i++) { + if (power == samples[i].power) { + *new_index = samples[i].gain_index; + return 0; + } + } + + if (power > samples[1].power) { + index0 = 0; + index1 = 1; + } else if (power > samples[2].power) { + index0 = 1; + index1 = 2; + } else if (power > samples[3].power) { + index0 = 2; + index1 = 3; + } else { + index0 = 3; + index1 = 4; + } + + denominator = (s32) samples[index1].power - (s32) samples[index0].power; + if (denominator == 0) + return -EINVAL; + gains0 = (s32) samples[index0].gain_index * (1 << 19); + gains1 = (s32) samples[index1].gain_index * (1 << 19); + res = gains0 + (gains1 - gains0) * + ((s32) power - (s32) samples[index0].power) / denominator + + (1 << 18); + *new_index = res >> 19; + return 0; +} + +static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv) +{ + u32 i; + s32 rate_index; + const struct iwl_eeprom_txpower_group *group; + + IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n"); + + for (i = 0; i < IWL_NUM_TX_CALIB_GROUPS; i++) { + s8 *clip_pwrs; /* table of power levels for each rate */ + s8 satur_pwr; /* saturation power for each chnl group */ + group = &priv->eeprom.groups[i]; + + /* sanity check on factory saturation power value */ + if (group->saturation_power < 40) { + IWL_WARNING("Error: saturation power is %d, " + "less than minimum expected 40\n", + group->saturation_power); + return; + } + + /* + * Derive requested power levels for each rate, based on + * hardware capabilities (saturation power for band). + * Basic value is 3dB down from saturation, with further + * power reductions for highest 3 data rates. These + * backoffs provide headroom for high rate modulation + * power peaks, without too much distortion (clipping). + */ + /* we'll fill in this array with h/w max power levels */ + clip_pwrs = (s8 *) priv->clip_groups[i].clip_powers; + + /* divide factory saturation power by 2 to find -3dB level */ + satur_pwr = (s8) (group->saturation_power >> 1); + + /* fill in channel group's nominal powers for each rate */ + for (rate_index = 0; + rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) { + switch (rate_index) { + case IWL_RATE_36M_INDEX: + if (i == 0) /* B/G */ + *clip_pwrs = satur_pwr; + else /* A */ + *clip_pwrs = satur_pwr - 5; + break; + case IWL_RATE_48M_INDEX: + if (i == 0) + *clip_pwrs = satur_pwr - 7; + else + *clip_pwrs = satur_pwr - 10; + break; + case IWL_RATE_54M_INDEX: + if (i == 0) + *clip_pwrs = satur_pwr - 9; + else + *clip_pwrs = satur_pwr - 12; + break; + default: + *clip_pwrs = satur_pwr; + break; + } + } + } +} + +/** + * iwl3945_txpower_set_from_eeprom - Set channel power info based on EEPROM + * + * Second pass (during init) to set up priv->channel_info + * + * Set up Tx-power settings in our channel info database for each VALID + * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values + * and current temperature. + * + * Since this is based on current temperature (at init time), these values may + * not be valid for very long, but it gives us a starting/default point, + * and allows us to active (i.e. using Tx) scan. + * + * This does *not* write values to NIC, just sets up our internal table. + */ +int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch_info = NULL; + struct iwl_channel_power_info *pwr_info; + int delta_index; + u8 rate_index; + u8 scan_tbl_index; + const s8 *clip_pwrs; /* array of power levels for each rate */ + u8 gain, dsp_atten; + s8 power; + u8 pwr_index, base_pwr_index, a_band; + u8 i; + int temperature; + + /* save temperature reference, + * so we can determine next time to calibrate */ + temperature = iwl_hw_reg_txpower_get_temperature(priv); + priv->last_temperature = temperature; + + iwl_hw_reg_init_channel_groups(priv); + + /* initialize Tx power info for each and every channel, 2.4 and 5.x */ + for (i = 0, ch_info = priv->channel_info; i < priv->channel_count; + i++, ch_info++) { + a_band = is_channel_a_band(ch_info); + if (!is_channel_valid(ch_info)) + continue; + + /* find this channel's channel group (*not* "band") index */ + ch_info->group_index = + iwl_hw_reg_get_ch_grp_index(priv, ch_info); + + /* Get this chnlgrp's rate->max/clip-powers table */ + clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers; + + /* calculate power index *adjustment* value according to + * diff between current temperature and factory temperature */ + delta_index = iwl_hw_reg_adjust_power_by_temp(temperature, + priv->eeprom.groups[ch_info->group_index]. + temperature); + + IWL_DEBUG_POWER("Delta index for channel %d: %d [%d]\n", + ch_info->channel, delta_index, temperature + + IWL_TEMP_CONVERT); + + /* set tx power value for all OFDM rates */ + for (rate_index = 0; rate_index < IWL_OFDM_RATES; + rate_index++) { + s32 power_idx; + int rc; + + /* use channel group's clip-power table, + * but don't exceed channel's max power */ + s8 pwr = min(ch_info->max_power_avg, + clip_pwrs[rate_index]); + + pwr_info = &ch_info->power_info[rate_index]; + + /* get base (i.e. at factory-measured temperature) + * power table index for this rate's power */ + rc = iwl_hw_reg_get_matched_power_index(priv, pwr, + ch_info->group_index, + &power_idx); + if (rc) { + IWL_ERROR("Invalid power index\n"); + return rc; + } + pwr_info->base_power_index = (u8) power_idx; + + /* temperature compensate */ + power_idx += delta_index; + + /* stay within range of gain table */ + power_idx = iwl_hw_reg_fix_power_index(power_idx); + + /* fill 1 OFDM rate's iwl_channel_power_info struct */ + pwr_info->requested_power = pwr; + pwr_info->power_table_index = (u8) power_idx; + pwr_info->tpc.tx_gain = + power_gain_table[a_band][power_idx].tx_gain; + pwr_info->tpc.dsp_atten = + power_gain_table[a_band][power_idx].dsp_atten; + } + + /* set tx power for CCK rates, based on OFDM 12 Mbit settings*/ + pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX]; + power = pwr_info->requested_power + + IWL_CCK_FROM_OFDM_POWER_DIFF; + pwr_index = pwr_info->power_table_index + + IWL_CCK_FROM_OFDM_INDEX_DIFF; + base_pwr_index = pwr_info->base_power_index + + IWL_CCK_FROM_OFDM_INDEX_DIFF; + + /* stay within table range */ + pwr_index = iwl_hw_reg_fix_power_index(pwr_index); + gain = power_gain_table[a_band][pwr_index].tx_gain; + dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten; + + /* fill each CCK rate's iwl_channel_power_info structure + * NOTE: All CCK-rate Txpwrs are the same for a given chnl! + * NOTE: CCK rates start at end of OFDM rates! */ + for (rate_index = IWL_OFDM_RATES; + rate_index < IWL_RATE_COUNT; rate_index++) { + pwr_info = &ch_info->power_info[rate_index]; + pwr_info->requested_power = power; + pwr_info->power_table_index = pwr_index; + pwr_info->base_power_index = base_pwr_index; + pwr_info->tpc.tx_gain = gain; + pwr_info->tpc.dsp_atten = dsp_atten; + } + + /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */ + for (scan_tbl_index = 0; + scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { + s32 actual_index = (scan_tbl_index == 0) ? + IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX; + iwl_hw_reg_set_scan_power(priv, scan_tbl_index, + actual_index, clip_pwrs, ch_info, a_band); + } + } + + return 0; +} + +int iwl_hw_rxq_stop(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0); + rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000); + if (rc < 0) + IWL_ERROR("Can't stop Rx DMA.\n"); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + int rc; + unsigned long flags; + int txq_id = txq->q.id; + + struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + + shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0); + iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0); + + iwl_write_restricted(priv, FH_TCSR_CONFIG(txq_id), + ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT | + ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF | + ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | + ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | + ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); + iwl_release_restricted_access(priv); + + /* fake read to flush all prev. writes */ + iwl_read32(priv, FH_TSSR_CBB_BASE); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +int iwl_hw_get_rx_read(struct iwl_priv *priv) +{ + struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + + return le32_to_cpu(shared_data->rx_read_ptr[0]); +} + +/** + * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table + */ +int iwl3945_init_hw_rate_table(struct iwl_priv *priv) +{ + int rc, i; + struct iwl_rate_scaling_cmd rate_cmd = { + .reserved = {0, 0, 0}, + }; + struct iwl_rate_scaling_info *table = rate_cmd.table; + + for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) { + table[i].rate_n_flags = + iwl_hw_set_rate_n_flags(iwl_rates[i].plcp, 0); + table[i].try_cnt = priv->retry_rate; + table[i].next_rate_index = iwl_get_prev_ieee_rate(i); + } + + switch (priv->phymode) { + case MODE_IEEE80211A: + IWL_DEBUG_RATE("Select A mode rate scale\n"); + /* If one of the following CCK rates is used, + * have it fall back to the 6M OFDM rate */ + for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++) + table[i].next_rate_index = IWL_FIRST_OFDM_RATE; + + /* Don't fall back to CCK rates */ + table[IWL_RATE_12M_INDEX].next_rate_index = IWL_RATE_9M_INDEX; + + /* Don't drop out of OFDM rates */ + table[IWL_FIRST_OFDM_RATE].next_rate_index = + IWL_FIRST_OFDM_RATE; + break; + + case MODE_IEEE80211B: + IWL_DEBUG_RATE("Select B mode rate scale\n"); + /* If an OFDM rate is used, have it fall back to the + * 1M CCK rates */ + for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE; i++) + table[i].next_rate_index = IWL_FIRST_CCK_RATE; + + /* CCK shouldn't fall back to OFDM... */ + table[IWL_RATE_11M_INDEX].next_rate_index = IWL_RATE_5M_INDEX; + break; + + default: + IWL_DEBUG_RATE("Select G mode rate scale\n"); + break; + } + + /* Update the rate scaling for control frame Tx */ + rate_cmd.table_id = 0; + rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), + &rate_cmd); + if (rc) + return rc; + + /* Update the rate scaling for data frame Tx */ + rate_cmd.table_id = 1; + return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), + &rate_cmd); +} + +int iwl_hw_set_hw_setting(struct iwl_priv *priv) +{ + memset((void *)&priv->hw_setting, 0, + sizeof(struct iwl_driver_hw_info)); + + priv->hw_setting.shared_virt = + pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl_shared), + &priv->hw_setting.shared_phys); + + if (!priv->hw_setting.shared_virt) { + IWL_ERROR("failed to allocate pci memory\n"); + mutex_unlock(&priv->mutex); + return -ENOMEM; + } + + priv->hw_setting.ac_queue_count = AC_NUM; + priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE; + priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd); + priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE; + priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; + priv->hw_setting.cck_flag = 0; + priv->hw_setting.max_stations = IWL3945_STATION_COUNT; + priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID; + return 0; +} + +unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl_frame *frame, u8 rate) +{ + struct iwl_tx_beacon_cmd *tx_beacon_cmd; + unsigned int frame_size; + + tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u; + memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + + tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID; + tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + frame_size = iwl_fill_beacon_frame(priv, + tx_beacon_cmd->frame, + BROADCAST_ADDR, + sizeof(frame->u) - sizeof(*tx_beacon_cmd)); + + BUG_ON(frame_size > MAX_MPDU_SIZE); + tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); + + tx_beacon_cmd->tx.rate = rate; + tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK | + TX_CMD_FLG_TSF_MSK); + + /* supp_rates[0] == OFDM */ + tx_beacon_cmd->tx.supp_rates[0] = IWL_OFDM_BASIC_RATES_MASK; + + /* supp_rates[1] == CCK + * + * NOTE: IWL_*_RATES_MASK are not in the order that supp_rates + * expects so we have to shift them around. + * + * supp_rates expects: + * CCK rates are bit0..3 + * + * However IWL_*_RATES_MASK has: + * CCK rates are bit8..11 + */ + tx_beacon_cmd->tx.supp_rates[1] = + (IWL_CCK_BASIC_RATES_MASK >> 8) & 0xF; + + return (sizeof(struct iwl_tx_beacon_cmd) + frame_size); +} + +void iwl_hw_rx_handler_setup(struct iwl_priv *priv) +{ + priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx; +} + +void iwl_hw_setup_deferred_work(struct iwl_priv *priv) +{ + INIT_DELAYED_WORK(&priv->thermal_periodic, + iwl3945_bg_reg_txpower_periodic); +} + +void iwl_hw_cancel_deferred_work(struct iwl_priv *priv) +{ + cancel_delayed_work(&priv->thermal_periodic); +} + +struct pci_device_id iwl_hw_card_ids[] = { + {0x8086, 0x4222, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x4227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0} +}; + +inline int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv) +{ + _iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK); + return 0; +} + +MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h new file mode 100644 index 000000000000..813902e9f8c2 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_3945_h__ +#define __iwl_3945_h__ + +/* + * Forward declare iwl-3945.c functions for iwl-base.c + */ +extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv); +extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv); +extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv); +extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv); +extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work); +extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv); +extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, + u16 tx_rate, u8 flags); +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h new file mode 100644 index 000000000000..99a19ef4c743 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -0,0 +1,581 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_4965_hw_h__ +#define __iwl_4965_hw_h__ + +#define IWL_RX_BUF_SIZE (4 * 1024) +#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE +#define KDR_RTC_INST_UPPER_BOUND (0x018000) +#define KDR_RTC_DATA_UPPER_BOUND (0x80A000) +#define KDR_RTC_INST_SIZE (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define KDR_RTC_DATA_SIZE (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) + +#define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE +#define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE + +static inline int iwl_hw_valid_rtc_data_addr(u32 addr) +{ + return (addr >= RTC_DATA_LOWER_BOUND) && + (addr < KDR_RTC_DATA_UPPER_BOUND); +} + +/********************* START TXPOWER *****************************************/ +enum { + HT_IE_EXT_CHANNEL_NONE = 0, + HT_IE_EXT_CHANNEL_ABOVE, + HT_IE_EXT_CHANNEL_INVALID, + HT_IE_EXT_CHANNEL_BELOW, + HT_IE_EXT_CHANNEL_MAX +}; + +enum { + CALIB_CH_GROUP_1 = 0, + CALIB_CH_GROUP_2 = 1, + CALIB_CH_GROUP_3 = 2, + CALIB_CH_GROUP_4 = 3, + CALIB_CH_GROUP_5 = 4, + CALIB_CH_GROUP_MAX +}; + +/* Temperature calibration offset is 3% 0C in Kelvin */ +#define TEMPERATURE_CALIB_KELVIN_OFFSET 8 +#define TEMPERATURE_CALIB_A_VAL 259 + +#define IWL_TX_POWER_TEMPERATURE_MIN (263) +#define IWL_TX_POWER_TEMPERATURE_MAX (410) + +#define IWL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(t) \ + (((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \ + ((t) > IWL_TX_POWER_TEMPERATURE_MAX)) + +#define IWL_TX_POWER_ILLEGAL_TEMPERATURE (300) + +#define IWL_TX_POWER_TEMPERATURE_DIFFERENCE (2) + +#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6) + +#define IWL_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm = 1 milliwatt */ +#define IWL_TX_POWER_TARGET_POWER_MAX (16) /* 16 dBm */ + +/* timeout equivalent to 3 minutes */ +#define IWL_TX_POWER_TIMELIMIT_NOCALIB 1800000000 + +#define IWL_TX_POWER_CCK_COMPENSATION (9) + +#define MIN_TX_GAIN_INDEX (0) +#define MIN_TX_GAIN_INDEX_52GHZ_EXT (-9) +#define MAX_TX_GAIN_INDEX_52GHZ (98) +#define MIN_TX_GAIN_52GHZ (98) +#define MAX_TX_GAIN_INDEX_24GHZ (98) +#define MIN_TX_GAIN_24GHZ (98) +#define MAX_TX_GAIN (0) +#define MAX_TX_GAIN_52GHZ_EXT (-9) + +#define IWL_TX_POWER_DEFAULT_REGULATORY_24 (34) +#define IWL_TX_POWER_DEFAULT_REGULATORY_52 (34) +#define IWL_TX_POWER_REGULATORY_MIN (0) +#define IWL_TX_POWER_REGULATORY_MAX (34) +#define IWL_TX_POWER_DEFAULT_SATURATION_24 (38) +#define IWL_TX_POWER_DEFAULT_SATURATION_52 (38) +#define IWL_TX_POWER_SATURATION_MIN (20) +#define IWL_TX_POWER_SATURATION_MAX (50) + +/* dv *0.4 = dt; so that 5 degrees temperature diff equals + * 12.5 in voltage diff */ +#define IWL_TX_TEMPERATURE_UPDATE_LIMIT 9 + +#define IWL_INVALID_CHANNEL (0xffffffff) +#define IWL_TX_POWER_REGITRY_BIT (2) + +#define MIN_IWL_TX_POWER_CALIB_DUR (100) +#define IWL_CCK_FROM_OFDM_POWER_DIFF (-5) +#define IWL_CCK_FROM_OFDM_INDEX_DIFF (9) + +/* Number of entries in the gain table */ +#define POWER_GAIN_NUM_ENTRIES 78 +#define TX_POW_MAX_SESSION_NUM 5 +/* timeout equivalent to 3 minutes */ +#define TX_IWL_TIMELIMIT_NOCALIB 1800000000 + +/* Kedron TX_CALIB_STATES */ +#define IWL_TX_CALIB_STATE_SEND_TX 0x00000001 +#define IWL_TX_CALIB_WAIT_TX_RESPONSE 0x00000002 +#define IWL_TX_CALIB_ENABLED 0x00000004 +#define IWL_TX_CALIB_XVT_ON 0x00000008 +#define IWL_TX_CALIB_TEMPERATURE_CORRECT 0x00000010 +#define IWL_TX_CALIB_WORKING_WITH_XVT 0x00000020 +#define IWL_TX_CALIB_XVT_PERIODICAL 0x00000040 + +#define NUM_IWL_TX_CALIB_SETTINS 5 /* Number of tx correction groups */ + +#define IWL_MIN_POWER_IN_VP_TABLE 1 /* 0.5dBm multiplied by 2 */ +#define IWL_MAX_POWER_IN_VP_TABLE 40 /* 20dBm - multiplied by 2 (because + * entries are for each 0.5dBm) */ +#define IWL_STEP_IN_VP_TABLE 1 /* 0.5dB - multiplied by 2 */ +#define IWL_NUM_POINTS_IN_VPTABLE \ + (1 + IWL_MAX_POWER_IN_VP_TABLE - IWL_MIN_POWER_IN_VP_TABLE) + +#define MIN_TX_GAIN_INDEX (0) +#define MAX_TX_GAIN_INDEX_52GHZ (98) +#define MIN_TX_GAIN_52GHZ (98) +#define MAX_TX_GAIN_INDEX_24GHZ (98) +#define MIN_TX_GAIN_24GHZ (98) +#define MAX_TX_GAIN (0) + +/* First and last channels of all groups */ +#define CALIB_IWL_TX_ATTEN_GR1_FCH 34 +#define CALIB_IWL_TX_ATTEN_GR1_LCH 43 +#define CALIB_IWL_TX_ATTEN_GR2_FCH 44 +#define CALIB_IWL_TX_ATTEN_GR2_LCH 70 +#define CALIB_IWL_TX_ATTEN_GR3_FCH 71 +#define CALIB_IWL_TX_ATTEN_GR3_LCH 124 +#define CALIB_IWL_TX_ATTEN_GR4_FCH 125 +#define CALIB_IWL_TX_ATTEN_GR4_LCH 200 +#define CALIB_IWL_TX_ATTEN_GR5_FCH 1 +#define CALIB_IWL_TX_ATTEN_GR5_LCH 20 + + +union iwl_tx_power_dual_stream { + struct { + u8 radio_tx_gain[2]; + u8 dsp_predis_atten[2]; + } s; + u32 dw; +}; + +/********************* END TXPOWER *****************************************/ + +/* HT flags */ +#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) +#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1<<22) + +#define RXON_FLG_HT_OPERATING_MODE_POS (23) + +#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1<<23) +#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2<<23) + +#define RXON_FLG_CHANNEL_MODE_POS (25) +#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3<<25) +#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1<<25) +#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2<<25) + +#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1<<0) +#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7<<1) +#define RXON_RX_CHAIN_VALID_POS (1) +#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7<<4) +#define RXON_RX_CHAIN_FORCE_SEL_POS (4) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7<<7) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) +#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3<<10) +#define RXON_RX_CHAIN_CNT_POS (10) +#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3<<12) +#define RXON_RX_CHAIN_MIMO_CNT_POS (12) +#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1<<14) +#define RXON_RX_CHAIN_MIMO_FORCE_POS (14) + + +#define MCS_DUP_6M_PLCP 0x20 + +/* OFDM HT rate masks */ +/* ***************************************** */ +#define R_MCS_6M_MSK 0x1 +#define R_MCS_12M_MSK 0x2 +#define R_MCS_18M_MSK 0x4 +#define R_MCS_24M_MSK 0x8 +#define R_MCS_36M_MSK 0x10 +#define R_MCS_48M_MSK 0x20 +#define R_MCS_54M_MSK 0x40 +#define R_MCS_60M_MSK 0x80 +#define R_MCS_12M_DUAL_MSK 0x100 +#define R_MCS_24M_DUAL_MSK 0x200 +#define R_MCS_36M_DUAL_MSK 0x400 +#define R_MCS_48M_DUAL_MSK 0x800 + +#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) +#define is_siso(tbl) (((tbl) == LQ_SISO)) +#define is_mimo(tbl) (((tbl) == LQ_MIMO)) +#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) +#define is_a_band(tbl) (((tbl) == LQ_A)) +#define is_g_and(tbl) (((tbl) == LQ_G)) + +/* Flow Handler Definitions */ + +/**********************/ +/* Addresses */ +/**********************/ + +#define FH_MEM_LOWER_BOUND (0x1000) +#define FH_MEM_UPPER_BOUND (0x1EF0) + +#define IWL_FH_REGS_LOWER_BOUND (0x1000) +#define IWL_FH_REGS_UPPER_BOUND (0x2000) + +#define IWL_FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) + +/* CBBC Area - Circular buffers base address cache pointers table */ +#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) +#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10) +/* queues 0 - 15 */ +#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4) + +/* RSCSR Area */ +#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) +#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) +#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) + +#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) +#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) +#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) + +/* RCSR Area - Registers address map */ +#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) +#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0) +#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) + +#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) + +/* RSSR Area - Rx shared ctrl & status registers */ +#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40) +#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) +#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND) +#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004) +#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV (FH_MEM_RSSR_LOWER_BOUND + 0x008) + +/* TCSR */ +#define IWL_FH_TCSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xD00) +#define IWL_FH_TCSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xE60) + +#define IWL_FH_TCSR_CHNL_NUM (7) +#define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl) + +/* TSSR Area - Tx shared status registers */ +/* TSSR */ +#define IWL_FH_TSSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEA0) +#define IWL_FH_TSSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEC0) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG (IWL_FH_TSSR_LOWER_BOUND + 0x008) +#define IWL_FH_TSSR_TX_STATUS_REG (IWL_FH_TSSR_LOWER_BOUND + 0x010) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_64B (0x00000000) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_256B (0x00000800) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_512B (0x00000C00) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005) + +#define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) \ + ((1 << (_chnl)) << 24) +#define IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) \ + ((1 << (_chnl)) << 16) + +#define IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \ + (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ + IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) + +/* TCSR: tx_config register values */ +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_ARC (0x00000002) + +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) + +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) + +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000) + +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) + +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) + +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001) + +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) + +/* RCSR: channel 0 rx_config register defines */ +#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK (0x00030000) /* bits 16-17 */ +#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */ +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK (0x00001000) /* bit 12 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK (0x00000FF0) /* bit 4-11 */ + +#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) +#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT (16) + +/* RCSR: rx_config register values */ +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) + +#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) + +/* RCSR channel 0 config register values */ +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) + +/* RSCSR: defs used in normal mode */ +#define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK (0x00000FFF) /* bits 0-11 */ + +#define SCD_WIN_SIZE 64 +#define SCD_FRAME_LIMIT 64 + +/* memory mapped registers */ +#define SCD_START_OFFSET 0xa02c00 + +#define SCD_SRAM_BASE_ADDR (SCD_START_OFFSET + 0x0) +#define SCD_EMPTY_BITS (SCD_START_OFFSET + 0x4) +#define SCD_DRAM_BASE_ADDR (SCD_START_OFFSET + 0x10) +#define SCD_AIT (SCD_START_OFFSET + 0x18) +#define SCD_TXFACT (SCD_START_OFFSET + 0x1c) +#define SCD_QUEUE_WRPTR(x) (SCD_START_OFFSET + 0x24 + (x) * 4) +#define SCD_QUEUE_RDPTR(x) (SCD_START_OFFSET + 0x64 + (x) * 4) +#define SCD_SETQUEUENUM (SCD_START_OFFSET + 0xa4) +#define SCD_SET_TXSTAT_TXED (SCD_START_OFFSET + 0xa8) +#define SCD_SET_TXSTAT_DONE (SCD_START_OFFSET + 0xac) +#define SCD_SET_TXSTAT_NOT_SCHD (SCD_START_OFFSET + 0xb0) +#define SCD_DECREASE_CREDIT (SCD_START_OFFSET + 0xb4) +#define SCD_DECREASE_SCREDIT (SCD_START_OFFSET + 0xb8) +#define SCD_LOAD_CREDIT (SCD_START_OFFSET + 0xbc) +#define SCD_LOAD_SCREDIT (SCD_START_OFFSET + 0xc0) +#define SCD_BAR (SCD_START_OFFSET + 0xc4) +#define SCD_BAR_DW0 (SCD_START_OFFSET + 0xc8) +#define SCD_BAR_DW1 (SCD_START_OFFSET + 0xcc) +#define SCD_QUEUECHAIN_SEL (SCD_START_OFFSET + 0xd0) +#define SCD_QUERY_REQ (SCD_START_OFFSET + 0xd8) +#define SCD_QUERY_RES (SCD_START_OFFSET + 0xdc) +#define SCD_PENDING_FRAMES (SCD_START_OFFSET + 0xe0) +#define SCD_INTERRUPT_MASK (SCD_START_OFFSET + 0xe4) +#define SCD_INTERRUPT_THRESHOLD (SCD_START_OFFSET + 0xe8) +#define SCD_QUERY_MIN_FRAME_SIZE (SCD_START_OFFSET + 0x100) +#define SCD_QUEUE_STATUS_BITS(x) (SCD_START_OFFSET + 0x104 + (x) * 4) + +/* SRAM structures */ +#define SCD_CONTEXT_DATA_OFFSET 0x380 +#define SCD_TX_STTS_BITMAP_OFFSET 0x400 +#define SCD_TRANSLATE_TBL_OFFSET 0x500 +#define SCD_CONTEXT_QUEUE_OFFSET(x) (SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) +#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ + ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) + +#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \ + ((1<<(hi))|((1<<(hi))-(1<<(lo)))) + + +#define SCD_MODE_REG_BIT_SEARCH_MODE (1<<0) +#define SCD_MODE_REG_BIT_SBYP_MODE (1<<1) + +#define SCD_TXFIFO_POS_TID (0) +#define SCD_TXFIFO_POS_RA (4) +#define SCD_QUEUE_STTS_REG_POS_ACTIVE (0) +#define SCD_QUEUE_STTS_REG_POS_TXF (1) +#define SCD_QUEUE_STTS_REG_POS_WSL (5) +#define SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) +#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) +#define SCD_QUEUE_STTS_REG_MSK (0x0007FC00) + +#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) + +#define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) +#define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) +#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8) +#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) +#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) +#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) +#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) +#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) + +#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010) +#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) +#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) +#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) + +static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) +{ + return le32_to_cpu(rate_n_flags) & 0xFF; +} +static inline u16 iwl_hw_get_rate_n_flags(__le32 rate_n_flags) +{ + return le32_to_cpu(rate_n_flags) & 0xFFFF; +} +static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u16 flags) +{ + return cpu_to_le32(flags|(u16)rate); +} + +struct iwl_tfd_frame_data { + __le32 tb1_addr; + + __le32 val1; + /* __le32 ptb1_32_35:4; */ +#define IWL_tb1_addr_hi_POS 0 +#define IWL_tb1_addr_hi_LEN 4 +#define IWL_tb1_addr_hi_SYM val1 + /* __le32 tb_len1:12; */ +#define IWL_tb1_len_POS 4 +#define IWL_tb1_len_LEN 12 +#define IWL_tb1_len_SYM val1 + /* __le32 ptb2_0_15:16; */ +#define IWL_tb2_addr_lo16_POS 16 +#define IWL_tb2_addr_lo16_LEN 16 +#define IWL_tb2_addr_lo16_SYM val1 + + __le32 val2; + /* __le32 ptb2_16_35:20; */ +#define IWL_tb2_addr_hi20_POS 0 +#define IWL_tb2_addr_hi20_LEN 20 +#define IWL_tb2_addr_hi20_SYM val2 + /* __le32 tb_len2:12; */ +#define IWL_tb2_len_POS 20 +#define IWL_tb2_len_LEN 12 +#define IWL_tb2_len_SYM val2 +} __attribute__ ((packed)); + +struct iwl_tfd_frame { + __le32 val0; + /* __le32 rsvd1:24; */ + /* __le32 num_tbs:5; */ +#define IWL_num_tbs_POS 24 +#define IWL_num_tbs_LEN 5 +#define IWL_num_tbs_SYM val0 + /* __le32 rsvd2:1; */ + /* __le32 padding:2; */ + struct iwl_tfd_frame_data pa[10]; + __le32 reserved; +} __attribute__ ((packed)); + +#define IWL4965_MAX_WIN_SIZE 64 +#define IWL4965_QUEUE_SIZE 256 +#define IWL4965_NUM_FIFOS 7 +#define IWL_MAX_NUM_QUEUES 16 + +struct iwl4965_queue_byte_cnt_entry { + __le16 val; + /* __le16 byte_cnt:12; */ +#define IWL_byte_cnt_POS 0 +#define IWL_byte_cnt_LEN 12 +#define IWL_byte_cnt_SYM val + /* __le16 rsvd:4; */ +} __attribute__ ((packed)); + +struct iwl4965_sched_queue_byte_cnt_tbl { + struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE + + IWL4965_MAX_WIN_SIZE]; + u8 dont_care[1024 - + (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) * + sizeof(__le16)]; +} __attribute__ ((packed)); + +/* Base physical address of iwl_shared is provided to SCD_DRAM_BASE_ADDR + * and &iwl_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ +struct iwl_shared { + struct iwl4965_sched_queue_byte_cnt_tbl + queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES]; + __le32 val0; + + /* __le32 rb_closed_stts_rb_num:12; */ +#define IWL_rb_closed_stts_rb_num_POS 0 +#define IWL_rb_closed_stts_rb_num_LEN 12 +#define IWL_rb_closed_stts_rb_num_SYM val0 + /* __le32 rsrv1:4; */ + /* __le32 rb_closed_stts_rx_frame_num:12; */ +#define IWL_rb_closed_stts_rx_frame_num_POS 16 +#define IWL_rb_closed_stts_rx_frame_num_LEN 12 +#define IWL_rb_closed_stts_rx_frame_num_SYM val0 + /* __le32 rsrv2:4; */ + + __le32 val1; + /* __le32 frame_finished_stts_rb_num:12; */ +#define IWL_frame_finished_stts_rb_num_POS 0 +#define IWL_frame_finished_stts_rb_num_LEN 12 +#define IWL_frame_finished_stts_rb_num_SYM val1 + /* __le32 rsrv3:4; */ + /* __le32 frame_finished_stts_rx_frame_num:12; */ +#define IWL_frame_finished_stts_rx_frame_num_POS 16 +#define IWL_frame_finished_stts_rx_frame_num_LEN 12 +#define IWL_frame_finished_stts_rx_frame_num_SYM val1 + /* __le32 rsrv4:4; */ + + __le32 padding1; /* so that allocation will be aligned to 16B */ + __le32 padding2; +} __attribute__ ((packed)); + +#endif /* __iwl_4965_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c new file mode 100644 index 000000000000..f3638607d641 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -0,0 +1,2118 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "../net/mac80211/ieee80211_rate.h" + +#include "iwlwifi.h" +#include "iwl-helpers.h" + +#define RS_NAME "iwl-4965-rs" + +#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1 +#define IWL_NUMBER_TRY 1 +#define IWL_HT_NUMBER_TRY 3 + +#define IWL_RATE_MAX_WINDOW 62 +#define IWL_RATE_HIGH_TH 10880 +#define IWL_RATE_MIN_FAILURE_TH 6 +#define IWL_RATE_MIN_SUCCESS_TH 8 +#define IWL_RATE_DECREASE_TH 1920 +#define IWL_RATE_INCREASE_TH 8960 +#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) /*2 seconds */ + +static u8 rs_ht_to_legacy[] = { + IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX, + IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, + IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, + IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX +}; + +struct iwl_rate { + u32 rate_n_flags; +} __attribute__ ((packed)); + +struct iwl_rate_scale_data { + u64 data; + s32 success_counter; + s32 success_ratio; + s32 counter; + s32 average_tpt; + unsigned long stamp; +}; + +struct iwl_scale_tbl_info { + enum iwl_table_type lq_type; + enum iwl_antenna_type antenna_type; + u8 is_SGI; + u8 is_fat; + u8 is_dup; + u8 action; + s32 *expected_tpt; + struct iwl_rate current_rate; + struct iwl_rate_scale_data win[IWL_RATE_COUNT]; +}; + +struct iwl_rate_scale_priv { + u8 active_tbl; + u8 enable_counter; + u8 stay_in_tbl; + u8 search_better_tbl; + s32 last_tpt; + u32 table_count_limit; + u32 max_failure_limit; + u32 max_success_limit; + u32 table_count; + u32 total_failed; + u32 total_success; + u32 flush_timer; + u8 action_counter; + u8 antenna; + u8 valid_antenna; + u8 is_green; + u8 is_dup; + u8 phymode; + u8 ibss_sta_added; + u16 active_rate; + u16 active_siso_rate; + u16 active_mimo_rate; + u16 active_rate_basic; + struct iwl_link_quality_cmd lq; + struct iwl_scale_tbl_info lq_info[LQ_SIZE]; +}; + +static void rs_rate_scale_perform(struct iwl_priv *priv, + struct net_device *dev, + struct ieee80211_hdr *hdr, + struct sta_info *sta); +static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, + struct iwl_rate *tx_mcs, + struct iwl_link_quality_cmd *tbl, + struct sta_info *sta); + + +static s32 expected_tpt_A[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 +}; + +static s32 expected_tpt_G[IWL_RATE_COUNT] = { + 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186 +}; + +static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202 +}; + +static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211 +}; + +static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251 +}; + +static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257 +}; + +static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257 +}; + +static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264 +}; + +static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289 +}; + +static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 +}; + +static int iwl_lq_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + /*We didn't cache the SKB; let the caller free it */ + return 1; +} + +static inline u8 iwl_rate_get_rate(u32 rate_n_flags) +{ + return (u8)(rate_n_flags & 0xFF); +} + +static int rs_send_lq_cmd(struct iwl_priv *priv, + struct iwl_link_quality_cmd *lq, u8 flags) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + int i; +#endif + int rc = -1; + + struct iwl_host_cmd cmd = { + .id = REPLY_TX_LINK_QUALITY_CMD, + .len = sizeof(struct iwl_link_quality_cmd), + .meta.flags = flags, + .data = lq, + }; + + if ((lq->sta_id == 0xFF) && + (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + return rc; + + if (lq->sta_id == 0xFF) + lq->sta_id = IWL_AP_ID; + + IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id); + IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n", + lq->general_params.single_stream_ant_msk, + lq->general_params.dual_stream_ant_msk); +#ifdef CONFIG_IWLWIFI_DEBUG + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) + IWL_DEBUG_RATE("lq index %d 0x%X\n", + i, lq->rs_table[i].rate_n_flags); +#endif + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_lq_sync_callback; + + if (iwl_is_associated(priv) && priv->assoc_station_added && + priv->lq_mngr.lq_ready) + rc = iwl_send_cmd(priv, &cmd); + + return rc; +} + +static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) +{ + window->data = 0; + window->success_counter = 0; + window->success_ratio = IWL_INVALID_VALUE; + window->counter = 0; + window->average_tpt = IWL_INVALID_VALUE; + window->stamp = 0; + + return 0; +} + +static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, + int scale_index, s32 tpt, u32 status) +{ + int rc = 0; + struct iwl_rate_scale_data *window = NULL; + u64 mask; + u8 win_size = IWL_RATE_MAX_WINDOW; + s32 fail_count; + + if (scale_index < 0) + return -1; + + if (scale_index >= IWL_RATE_COUNT) + return -1; + + window = &(windows[scale_index]); + + if (window->counter >= win_size) { + + window->counter = win_size - 1; + mask = 1; + mask = (mask << (win_size - 1)); + if ((window->data & mask)) { + window->data &= ~mask; + window->success_counter = window->success_counter - 1; + } + } + + window->counter = window->counter + 1; + mask = window->data; + window->data = (mask << 1); + if (status != 0) { + window->success_counter = window->success_counter + 1; + window->data |= 0x1; + } + + if (window->counter > 0) + window->success_ratio = 128 * (100 * window->success_counter) + / window->counter; + else + window->success_ratio = IWL_INVALID_VALUE; + + fail_count = window->counter - window->success_counter; + + if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || + (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) + window->average_tpt = (window->success_ratio * tpt + 64) / 128; + else + window->average_tpt = IWL_INVALID_VALUE; + + window->stamp = jiffies; + + return rc; +} + +int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate, + struct iwl_scale_tbl_info *tbl, + int index, u8 use_green) +{ + int rc = 0; + + if (is_legacy(tbl->lq_type)) { + mcs_rate->rate_n_flags = iwl_rates[index].plcp; + if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) + mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK; + + } else if (is_siso(tbl->lq_type)) { + if (index > IWL_LAST_OFDM_RATE) + index = IWL_LAST_OFDM_RATE; + mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso | + RATE_MCS_HT_MSK; + } else { + if (index > IWL_LAST_OFDM_RATE) + index = IWL_LAST_OFDM_RATE; + mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo | + RATE_MCS_HT_MSK; + } + + switch (tbl->antenna_type) { + case ANT_BOTH: + mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK; + break; + case ANT_MAIN: + mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK; + break; + case ANT_AUX: + mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK; + break; + case ANT_NONE: + break; + } + + if (is_legacy(tbl->lq_type)) + return rc; + + if (tbl->is_fat) { + if (tbl->is_dup) + mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK; + else + mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK; + } + if (tbl->is_SGI) + mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK; + + if (use_green) { + mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK; + if (is_siso(tbl->lq_type)) + mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK; + } + return rc; +} + +static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate, + int phymode, struct iwl_scale_tbl_info *tbl, + int *rate_idx) +{ + int index; + u32 ant_msk; + + index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags); + + if (index == IWL_RATE_INVALID) { + *rate_idx = -1; + return -1; + } + tbl->is_SGI = 0; + tbl->is_fat = 0; + tbl->is_dup = 0; + tbl->antenna_type = ANT_BOTH; + + if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) { + ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); + + if (ant_msk == RATE_MCS_ANT_AB_MSK) + tbl->lq_type = LQ_NONE; + else { + + if (phymode == MODE_IEEE80211A) + tbl->lq_type = LQ_A; + else + tbl->lq_type = LQ_G; + + if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK) + tbl->antenna_type = ANT_MAIN; + else + tbl->antenna_type = ANT_AUX; + } + *rate_idx = index; + + } else if (iwl_rate_get_rate(mcs_rate->rate_n_flags) + <= IWL_RATE_SISO_60M_PLCP) { + tbl->lq_type = LQ_SISO; + + ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); + if (ant_msk == RATE_MCS_ANT_AB_MSK) + tbl->lq_type = LQ_NONE; + else { + if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK) + tbl->antenna_type = ANT_MAIN; + else + tbl->antenna_type = ANT_AUX; + } + if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) + tbl->is_SGI = 1; + + if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) || + (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)) + tbl->is_fat = 1; + + if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) + tbl->is_dup = 1; + + *rate_idx = index; + } else { + tbl->lq_type = LQ_MIMO; + if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) + tbl->is_SGI = 1; + + if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) || + (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)) + tbl->is_fat = 1; + + if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) + tbl->is_dup = 1; + *rate_idx = index; + } + return 0; +} + +static inline void rs_toggle_antenna(struct iwl_rate *new_rate, + struct iwl_scale_tbl_info *tbl) +{ + if (tbl->antenna_type == ANT_AUX) { + tbl->antenna_type = ANT_MAIN; + new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK; + new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK; + } else { + tbl->antenna_type = ANT_AUX; + new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK; + new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK; + } +} + +static inline s8 rs_use_green(struct iwl_priv *priv) +{ + s8 rc = 0; +#ifdef CONFIG_IWLWIFI_HT + if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) + return 0; + + if ((priv->current_assoc_ht.is_green_field) && + !(priv->current_assoc_ht.operating_mode & 0x4)) + rc = 1; +#endif /*CONFIG_IWLWIFI_HT */ + return rc; +} + +/** + * rs_get_supported_rates - get the available rates + * + * if management frame or broadcast frame only return + * basic available rates. + * + */ +static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data, + struct ieee80211_hdr *hdr, + enum iwl_table_type rate_type, + u16 *data_rate) +{ + if (is_legacy(rate_type)) + *data_rate = lq_data->active_rate; + else { + if (is_siso(rate_type)) + *data_rate = lq_data->active_siso_rate; + else + *data_rate = lq_data->active_mimo_rate; + } + + if (hdr && is_multicast_ether_addr(hdr->addr1) && + lq_data->active_rate_basic) + *data_rate = lq_data->active_rate_basic; +} + +static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) +{ + u8 high = IWL_RATE_INVALID; + u8 low = IWL_RATE_INVALID; + + /* 802.11A or ht walks to the next literal adjascent rate in + * the rate table */ + if (is_a_band(rate_type) || !is_legacy(rate_type)) { + int i; + u32 mask; + + /* Find the previous rate that is in the rate mask */ + i = index - 1; + for (mask = (1 << i); i >= 0; i--, mask >>= 1) { + if (rate_mask & mask) { + low = i; + break; + } + } + + /* Find the next rate that is in the rate mask */ + i = index + 1; + for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { + if (rate_mask & mask) { + high = i; + break; + } + } + + return (high << 8) | low; + } + + low = index; + while (low != IWL_RATE_INVALID) { + low = iwl_rates[low].prev_rs; + if (low == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << low)) + break; + IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low); + } + + high = index; + while (high != IWL_RATE_INVALID) { + high = iwl_rates[high].next_rs; + if (high == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << high)) + break; + IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high); + } + + return (high << 8) | low; +} + +static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl, u8 scale_index, + u8 ht_possible, struct iwl_rate *mcs_rate, + struct sta_info *sta) +{ + u8 is_green = lq_data->is_green; + s32 low; + u16 rate_mask; + u16 high_low; + u8 switch_to_legacy = 0; + + /* check if we need to switch from HT to legacy rates. + * assumption is that mandatory rates (1Mbps or 6Mbps) + * are always supported (spec demand) */ + if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { + switch_to_legacy = 1; + scale_index = rs_ht_to_legacy[scale_index]; + if (lq_data->phymode == MODE_IEEE80211A) + tbl->lq_type = LQ_A; + else + tbl->lq_type = LQ_G; + + if ((tbl->antenna_type == ANT_BOTH) || + (tbl->antenna_type == ANT_NONE)) + tbl->antenna_type = ANT_MAIN; + + tbl->is_fat = 0; + tbl->is_SGI = 0; + } + + rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask); + + /* mask with station rate restriction */ + if (is_legacy(tbl->lq_type)) { + if (lq_data->phymode == (u8) MODE_IEEE80211A) + rate_mask = (u16)(rate_mask & + (sta->supp_rates << IWL_FIRST_OFDM_RATE)); + else + rate_mask = (u16)(rate_mask & sta->supp_rates); + } + + /* if we did switched from HT to legacy check current rate */ + if ((switch_to_legacy) && + (rate_mask & (1 << scale_index))) { + rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); + return 0; + } + + high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type); + low = high_low & 0xff; + + if (low != IWL_RATE_INVALID) + rs_mcs_from_tbl(mcs_rate, tbl, low, is_green); + else + rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); + + return 0; +} + +static void rs_tx_status(void *priv_rate, + struct net_device *dev, + struct sk_buff *skb, + struct ieee80211_tx_status *tx_resp) +{ + int status; + u8 retries; + int rs_index, index = 0; + struct iwl_rate_scale_priv *lq; + struct iwl_link_quality_cmd *table; + struct sta_info *sta; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct iwl_rate_scale_data *window = NULL; + struct iwl_rate_scale_data *search_win = NULL; + struct iwl_rate tx_mcs; + struct iwl_scale_tbl_info tbl_type; + struct iwl_scale_tbl_info *curr_tbl, *search_tbl; + u8 active_index = 0; + u16 fc = le16_to_cpu(hdr->frame_control); + s32 tpt = 0; + + IWL_DEBUG_RATE("get frame ack response, update rate scale window\n"); + + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) + return; + + retries = tx_resp->retry_count; + + if (retries > 15) + retries = 15; + + + sta = sta_info_get(local, hdr->addr1); + + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + sta_info_put(sta); + return; + } + + lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + + if (!priv->lq_mngr.lq_ready) + return; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) + return; + + table = &lq->lq; + active_index = lq->active_tbl; + + lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx); + if (!lq->antenna) + lq->antenna = lq->valid_antenna; + + lq->antenna = lq->valid_antenna; + curr_tbl = &(lq->lq_info[active_index]); + search_tbl = &(lq->lq_info[(1 - active_index)]); + window = (struct iwl_rate_scale_data *) + &(curr_tbl->win[0]); + search_win = (struct iwl_rate_scale_data *) + &(search_tbl->win[0]); + + tx_mcs.rate_n_flags = tx_resp->control.tx_rate; + + rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + &tbl_type, &rs_index); + if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) { + IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n", + rs_index, tx_mcs.rate_n_flags); + sta_info_put(sta); + return; + } + + if (retries && + (tx_mcs.rate_n_flags != + le32_to_cpu(table->rs_table[0].rate_n_flags))) { + IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n", + tx_mcs.rate_n_flags, + le32_to_cpu(table->rs_table[0].rate_n_flags)); + sta_info_put(sta); + return; + } + + while (retries) { + tx_mcs.rate_n_flags = + le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + &tbl_type, &rs_index); + + if ((tbl_type.lq_type == search_tbl->lq_type) && + (tbl_type.antenna_type == search_tbl->antenna_type) && + (tbl_type.is_SGI == search_tbl->is_SGI)) { + if (search_tbl->expected_tpt) + tpt = search_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(search_win, + rs_index, tpt, 0); + } else if ((tbl_type.lq_type == curr_tbl->lq_type) && + (tbl_type.antenna_type == curr_tbl->antenna_type) && + (tbl_type.is_SGI == curr_tbl->is_SGI)) { + if (curr_tbl->expected_tpt) + tpt = curr_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(window, rs_index, tpt, 0); + } + if (lq->stay_in_tbl) + lq->total_failed++; + --retries; + index++; + + } + + if (!tx_resp->retry_count) + tx_mcs.rate_n_flags = tx_resp->control.tx_rate; + else + tx_mcs.rate_n_flags = + le32_to_cpu(table->rs_table[index].rate_n_flags); + + rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + &tbl_type, &rs_index); + + if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) + status = 1; + else + status = 0; + + if ((tbl_type.lq_type == search_tbl->lq_type) && + (tbl_type.antenna_type == search_tbl->antenna_type) && + (tbl_type.is_SGI == search_tbl->is_SGI)) { + if (search_tbl->expected_tpt) + tpt = search_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(search_win, + rs_index, tpt, status); + } else if ((tbl_type.lq_type == curr_tbl->lq_type) && + (tbl_type.antenna_type == curr_tbl->antenna_type) && + (tbl_type.is_SGI == curr_tbl->is_SGI)) { + if (curr_tbl->expected_tpt) + tpt = curr_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(window, rs_index, tpt, status); + } + + if (lq->stay_in_tbl) { + if (status) + lq->total_success++; + else + lq->total_failed++; + } + + rs_rate_scale_perform(priv, dev, hdr, sta); + sta_info_put(sta); + return; +} + +static u8 rs_is_ant_connected(u8 valid_antenna, + enum iwl_antenna_type antenna_type) +{ + if (antenna_type == ANT_AUX) + return ((valid_antenna & 0x2) ? 1:0); + else if (antenna_type == ANT_MAIN) + return ((valid_antenna & 0x1) ? 1:0); + else if (antenna_type == ANT_BOTH) { + if ((valid_antenna & 0x3) == 0x3) + return 1; + else + return 0; + } + + return 1; +} + +static u8 rs_is_other_ant_connected(u8 valid_antenna, + enum iwl_antenna_type antenna_type) +{ + if (antenna_type == ANT_AUX) + return (rs_is_ant_connected(valid_antenna, ANT_MAIN)); + else + return (rs_is_ant_connected(valid_antenna, ANT_AUX)); + + return 0; +} + +static void rs_set_stay_in_table(u8 is_legacy, + struct iwl_rate_scale_priv *lq_data) +{ + IWL_DEBUG_HT("we are staying in the same table\n"); + lq_data->stay_in_tbl = 1; + if (is_legacy) { + lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT; + lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; + lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT; + } else { + lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; + lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; + lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; + } + lq_data->table_count = 0; + lq_data->total_failed = 0; + lq_data->total_success = 0; +} + +static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl) +{ + if (is_legacy(tbl->lq_type)) { + if (!is_a_band(tbl->lq_type)) + tbl->expected_tpt = expected_tpt_G; + else + tbl->expected_tpt = expected_tpt_A; + } else if (is_siso(tbl->lq_type)) { + if (tbl->is_fat && !lq_data->is_dup) + if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_siso40MHzSGI; + else + tbl->expected_tpt = expected_tpt_siso40MHz; + else if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_siso20MHzSGI; + else + tbl->expected_tpt = expected_tpt_siso20MHz; + + } else if (is_mimo(tbl->lq_type)) { + if (tbl->is_fat && !lq_data->is_dup) + if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo40MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo40MHz; + else if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo20MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo20MHz; + } else + tbl->expected_tpt = expected_tpt_G; +} + +#ifdef CONFIG_IWLWIFI_HT +static s32 rs_get_best_rate(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl, + u16 rate_mask, s8 index, s8 rate) +{ + struct iwl_scale_tbl_info *active_tbl = + &(lq_data->lq_info[lq_data->active_tbl]); + s32 new_rate, high, low, start_hi; + s32 active_sr = active_tbl->win[index].success_ratio; + s32 *tpt_tbl = tbl->expected_tpt; + s32 active_tpt = active_tbl->expected_tpt[index]; + u16 high_low; + + new_rate = high = low = start_hi = IWL_RATE_INVALID; + + for (; ;) { + high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type); + + low = high_low & 0xff; + high = (high_low >> 8) & 0xff; + + if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) && + ((active_sr > IWL_RATE_DECREASE_TH) && + (active_sr <= IWL_RATE_HIGH_TH) && + (tpt_tbl[rate] <= active_tpt))) || + ((active_sr >= IWL_RATE_SCALE_SWITCH) && + (tpt_tbl[rate] > active_tpt))) { + + if (start_hi != IWL_RATE_INVALID) { + new_rate = start_hi; + break; + } + new_rate = rate; + if (low != IWL_RATE_INVALID) + rate = low; + else + break; + } else { + if (new_rate != IWL_RATE_INVALID) + break; + else if (high != IWL_RATE_INVALID) { + start_hi = high; + rate = high; + } else { + new_rate = rate; + break; + } + } + } + + return new_rate; +} +#endif /* CONFIG_IWLWIFI_HT */ + +static inline u8 rs_is_both_ant_supp(u8 valid_antenna) +{ + return (rs_is_ant_connected(valid_antenna, ANT_BOTH)); +} + +static int rs_switch_to_mimo(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl, int index) +{ + int rc = -1; +#ifdef CONFIG_IWLWIFI_HT + u16 rate_mask; + s32 rate; + s8 is_green = lq_data->is_green; + + if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) + return -1; + + IWL_DEBUG_HT("LQ: try to switch to MIMO\n"); + tbl->lq_type = LQ_MIMO; + rs_get_supported_rates(lq_data, NULL, tbl->lq_type, + &rate_mask); + + if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) + return -1; + + if (!rs_is_both_ant_supp(lq_data->antenna)) + return -1; + + rc = 0; + tbl->is_dup = lq_data->is_dup; + tbl->action = 0; + if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ) + tbl->is_fat = 1; + else + tbl->is_fat = 0; + + if (tbl->is_fat) { + if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + + rs_get_expected_tpt_table(lq_data, tbl); + + rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index); + + IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask); + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) + return -1; + rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); + + IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate.rate_n_flags, is_green); + +#endif /*CONFIG_IWLWIFI_HT */ + return rc; +} + +static int rs_switch_to_siso(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl, int index) +{ + int rc = -1; +#ifdef CONFIG_IWLWIFI_HT + u16 rate_mask; + u8 is_green = lq_data->is_green; + s32 rate; + + IWL_DEBUG_HT("LQ: try to switch to SISO\n"); + if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) + return -1; + + rc = 0; + tbl->is_dup = lq_data->is_dup; + tbl->lq_type = LQ_SISO; + tbl->action = 0; + rs_get_supported_rates(lq_data, NULL, tbl->lq_type, + &rate_mask); + + if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ) + tbl->is_fat = 1; + else + tbl->is_fat = 0; + + if (tbl->is_fat) { + if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + + if (is_green) + tbl->is_SGI = 0; + + rs_get_expected_tpt_table(lq_data, tbl); + rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index); + + IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask); + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_HT("can not switch with index %d rate mask %x\n", + rate, rate_mask); + return -1; + } + rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); + IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate.rate_n_flags, is_green); + +#endif /*CONFIG_IWLWIFI_HT */ + return rc; +} + +static int rs_move_legacy_other(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + int index) +{ + int rc = 0; + struct iwl_scale_tbl_info *tbl = + &(lq_data->lq_info[lq_data->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + + for (; ;) { + switch (tbl->action) { + case IWL_LEGACY_SWITCH_ANTENNA: + IWL_DEBUG_HT("LQ Legacy switch Antenna\n"); + + search_tbl->lq_type = LQ_NONE; + lq_data->action_counter++; + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + if (!rs_is_other_ant_connected(lq_data->antenna, + tbl->antenna_type)) + break; + + memcpy(search_tbl, tbl, sz); + + rs_toggle_antenna(&(search_tbl->current_rate), + search_tbl); + rs_get_expected_tpt_table(lq_data, search_tbl); + lq_data->search_better_tbl = 1; + goto out; + + case IWL_LEGACY_SWITCH_SISO: + IWL_DEBUG_HT("LQ: Legacy switch to SISO\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_SISO; + search_tbl->is_SGI = 0; + search_tbl->is_fat = 0; + rc = rs_switch_to_siso(priv, lq_data, search_tbl, + index); + if (!rc) { + lq_data->search_better_tbl = 1; + lq_data->action_counter = 0; + } + if (!rc) + goto out; + + break; + case IWL_LEGACY_SWITCH_MIMO: + IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_MIMO; + search_tbl->is_SGI = 0; + search_tbl->is_fat = 0; + search_tbl->antenna_type = ANT_BOTH; + rc = rs_switch_to_mimo(priv, lq_data, search_tbl, + index); + if (!rc) { + lq_data->search_better_tbl = 1; + lq_data->action_counter = 0; + } + if (!rc) + goto out; + break; + } + tbl->action++; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + + if (tbl->action == start_action) + break; + + } + return 0; + + out: + tbl->action++; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + return 0; + +} + +static int rs_move_siso_to_other(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + int index) +{ + int rc = -1; + u8 is_green = lq_data->is_green; + struct iwl_scale_tbl_info *tbl = + &(lq_data->lq_info[lq_data->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + + for (;;) { + lq_data->action_counter++; + switch (tbl->action) { + case IWL_SISO_SWITCH_ANTENNA: + IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n"); + search_tbl->lq_type = LQ_NONE; + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + if (!rs_is_other_ant_connected(lq_data->antenna, + tbl->antenna_type)) + break; + + memcpy(search_tbl, tbl, sz); + search_tbl->action = IWL_SISO_SWITCH_MIMO; + rs_toggle_antenna(&(search_tbl->current_rate), + search_tbl); + lq_data->search_better_tbl = 1; + + goto out; + + case IWL_SISO_SWITCH_MIMO: + IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_MIMO; + search_tbl->is_SGI = 0; + search_tbl->is_fat = 0; + search_tbl->antenna_type = ANT_BOTH; + rc = rs_switch_to_mimo(priv, lq_data, search_tbl, + index); + if (!rc) + lq_data->search_better_tbl = 1; + + if (!rc) + goto out; + break; + case IWL_SISO_SWITCH_GI: + IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->action = 0; + if (search_tbl->is_SGI) + search_tbl->is_SGI = 0; + else if (!is_green) + search_tbl->is_SGI = 1; + else + break; + lq_data->search_better_tbl = 1; + if ((tbl->lq_type == LQ_SISO) && + (tbl->is_SGI)) { + s32 tpt = lq_data->last_tpt / 100; + if (((!tbl->is_fat) && + (tpt >= expected_tpt_siso20MHz[index])) || + ((tbl->is_fat) && + (tpt >= expected_tpt_siso40MHz[index]))) + lq_data->search_better_tbl = 0; + } + rs_get_expected_tpt_table(lq_data, search_tbl); + rs_mcs_from_tbl(&search_tbl->current_rate, + search_tbl, index, is_green); + goto out; + } + tbl->action++; + if (tbl->action > IWL_SISO_SWITCH_GI) + tbl->action = IWL_SISO_SWITCH_ANTENNA; + + if (tbl->action == start_action) + break; + } + return 0; + + out: + tbl->action++; + if (tbl->action > IWL_SISO_SWITCH_GI) + tbl->action = IWL_SISO_SWITCH_ANTENNA; + return 0; +} + +static int rs_move_mimo_to_other(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + int index) +{ + int rc = -1; + s8 is_green = lq_data->is_green; + struct iwl_scale_tbl_info *tbl = + &(lq_data->lq_info[lq_data->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + + for (;;) { + lq_data->action_counter++; + switch (tbl->action) { + case IWL_MIMO_SWITCH_ANTENNA_A: + case IWL_MIMO_SWITCH_ANTENNA_B: + IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_SISO; + search_tbl->is_SGI = 0; + search_tbl->is_fat = 0; + if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) + search_tbl->antenna_type = ANT_MAIN; + else + search_tbl->antenna_type = ANT_AUX; + + rc = rs_switch_to_siso(priv, lq_data, search_tbl, + index); + if (!rc) { + lq_data->search_better_tbl = 1; + goto out; + } + break; + + case IWL_MIMO_SWITCH_GI: + IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_MIMO; + search_tbl->antenna_type = ANT_BOTH; + search_tbl->action = 0; + if (search_tbl->is_SGI) + search_tbl->is_SGI = 0; + else + search_tbl->is_SGI = 1; + lq_data->search_better_tbl = 1; + if ((tbl->lq_type == LQ_MIMO) && + (tbl->is_SGI)) { + s32 tpt = lq_data->last_tpt / 100; + if (((!tbl->is_fat) && + (tpt >= expected_tpt_mimo20MHz[index])) || + ((tbl->is_fat) && + (tpt >= expected_tpt_mimo40MHz[index]))) + lq_data->search_better_tbl = 0; + } + rs_get_expected_tpt_table(lq_data, search_tbl); + rs_mcs_from_tbl(&search_tbl->current_rate, + search_tbl, index, is_green); + goto out; + + } + tbl->action++; + if (tbl->action > IWL_MIMO_SWITCH_GI) + tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + + if (tbl->action == start_action) + break; + } + + return 0; + out: + tbl->action++; + if (tbl->action > IWL_MIMO_SWITCH_GI) + tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + return 0; + +} + +static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data) +{ + struct iwl_scale_tbl_info *tbl; + int i; + int active_tbl; + int flush_interval_passed = 0; + + active_tbl = lq_data->active_tbl; + + tbl = &(lq_data->lq_info[active_tbl]); + + if (lq_data->stay_in_tbl) { + + if (lq_data->flush_timer) + flush_interval_passed = + time_after(jiffies, + (unsigned long)(lq_data->flush_timer + + IWL_RATE_SCALE_FLUSH_INTVL)); + + flush_interval_passed = 0; + if ((lq_data->total_failed > lq_data->max_failure_limit) || + (lq_data->total_success > lq_data->max_success_limit) || + ((!lq_data->search_better_tbl) && (lq_data->flush_timer) + && (flush_interval_passed))) { + IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:", + lq_data->total_failed, + lq_data->total_success, + flush_interval_passed); + lq_data->stay_in_tbl = 0; + lq_data->total_failed = 0; + lq_data->total_success = 0; + lq_data->flush_timer = 0; + } else if (lq_data->table_count > 0) { + lq_data->table_count++; + if (lq_data->table_count >= + lq_data->table_count_limit) { + lq_data->table_count = 0; + + IWL_DEBUG_HT("LQ: stay in table clear win\n"); + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window( + &(tbl->win[i])); + } + } + + if (!lq_data->stay_in_tbl) { + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(tbl->win[i])); + } + } +} + +static void rs_rate_scale_perform(struct iwl_priv *priv, + struct net_device *dev, + struct ieee80211_hdr *hdr, + struct sta_info *sta) +{ + int low = IWL_RATE_INVALID; + int high = IWL_RATE_INVALID; + int index; + int i; + struct iwl_rate_scale_data *window = NULL; + int current_tpt = IWL_INVALID_VALUE; + int low_tpt = IWL_INVALID_VALUE; + int high_tpt = IWL_INVALID_VALUE; + u32 fail_count; + s8 scale_action = 0; + u16 fc, rate_mask; + u8 update_lq = 0; + struct iwl_rate_scale_priv *lq_data; + struct iwl_scale_tbl_info *tbl, *tbl1; + u16 rate_scale_index_msk = 0; + struct iwl_rate mcs_rate; + u8 is_green = 0; + u8 active_tbl = 0; + u8 done_search = 0; + u16 high_low; + + IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); + + fc = le16_to_cpu(hdr->frame_control); + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + return; + } + + if (!sta || !sta->rate_ctrl_priv) + return; + + if (!priv->lq_mngr.lq_ready) { + IWL_DEBUG_RATE("still rate scaling not ready\n"); + return; + } + lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + + if (!lq_data->search_better_tbl) + active_tbl = lq_data->active_tbl; + else + active_tbl = 1 - lq_data->active_tbl; + + tbl = &(lq_data->lq_info[active_tbl]); + is_green = lq_data->is_green; + + index = sta->last_txrate; + + IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, + tbl->lq_type); + + rs_get_supported_rates(lq_data, hdr, tbl->lq_type, + &rate_mask); + + IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask); + + /* mask with station rate restriction */ + if (is_legacy(tbl->lq_type)) { + if (lq_data->phymode == (u8) MODE_IEEE80211A) + rate_scale_index_msk = (u16) (rate_mask & + (sta->supp_rates << IWL_FIRST_OFDM_RATE)); + else + rate_scale_index_msk = (u16) (rate_mask & + sta->supp_rates); + + } else + rate_scale_index_msk = rate_mask; + + if (!rate_scale_index_msk) + rate_scale_index_msk = rate_mask; + + if (index < 0 || !((1 << index) & rate_scale_index_msk)) { + index = IWL_INVALID_VALUE; + update_lq = 1; + + /* get the lowest availabe rate */ + for (i = 0; i <= IWL_RATE_COUNT; i++) { + if ((1 << i) & rate_scale_index_msk) + index = i; + } + + if (index == IWL_INVALID_VALUE) { + IWL_WARNING("Can not find a suitable rate\n"); + return; + } + } + + if (!tbl->expected_tpt) + rs_get_expected_tpt_table(lq_data, tbl); + + window = &(tbl->win[index]); + + fail_count = window->counter - window->success_counter; + if (((fail_count < IWL_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) + || (tbl->expected_tpt == NULL)) { + IWL_DEBUG_RATE("LQ: still below TH succ %d total %d " + "for index %d\n", + window->success_counter, window->counter, index); + window->average_tpt = IWL_INVALID_VALUE; + rs_stay_in_table(lq_data); + if (update_lq) { + rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); + rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq, sta); + rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + } + goto out; + + } else + window->average_tpt = ((window->success_ratio * + tbl->expected_tpt[index] + 64) / 128); + + if (lq_data->search_better_tbl) { + int success_limit = IWL_RATE_SCALE_SWITCH; + + if ((window->success_ratio > success_limit) || + (window->average_tpt > lq_data->last_tpt)) { + if (!is_legacy(tbl->lq_type)) { + IWL_DEBUG_HT("LQ: we are switching to HT" + " rate suc %d current tpt %d" + " old tpt %d\n", + window->success_ratio, + window->average_tpt, + lq_data->last_tpt); + lq_data->enable_counter = 1; + } + lq_data->active_tbl = active_tbl; + current_tpt = window->average_tpt; + } else { + tbl->lq_type = LQ_NONE; + active_tbl = lq_data->active_tbl; + tbl = &(lq_data->lq_info[active_tbl]); + + index = iwl_rate_index_from_plcp( + tbl->current_rate.rate_n_flags); + + update_lq = 1; + current_tpt = lq_data->last_tpt; + IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n"); + } + lq_data->search_better_tbl = 0; + done_search = 1; + goto lq_update; + } + + high_low = rs_get_adjacent_rate(index, rate_scale_index_msk, + tbl->lq_type); + low = high_low & 0xff; + high = (high_low >> 8) & 0xff; + + current_tpt = window->average_tpt; + + if (low != IWL_RATE_INVALID) + low_tpt = tbl->win[low].average_tpt; + + if (high != IWL_RATE_INVALID) + high_tpt = tbl->win[high].average_tpt; + + + scale_action = 1; + + if ((window->success_ratio <= IWL_RATE_DECREASE_TH) || + (current_tpt == 0)) { + IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); + scale_action = -1; + } else if ((low_tpt == IWL_INVALID_VALUE) && + (high_tpt == IWL_INVALID_VALUE)) + scale_action = 1; + else if ((low_tpt != IWL_INVALID_VALUE) && + (high_tpt != IWL_INVALID_VALUE) && + (low_tpt < current_tpt) && + (high_tpt < current_tpt)) + scale_action = 0; + else { + if (high_tpt != IWL_INVALID_VALUE) { + if (high_tpt > current_tpt) + scale_action = 1; + else { + IWL_DEBUG_RATE + ("decrease rate because of high tpt\n"); + scale_action = -1; + } + } else if (low_tpt != IWL_INVALID_VALUE) { + if (low_tpt > current_tpt) { + IWL_DEBUG_RATE + ("decrease rate because of low tpt\n"); + scale_action = -1; + } else + scale_action = 1; + } + } + + if (scale_action == -1) { + if ((low != IWL_RATE_INVALID) && + ((window->success_ratio > IWL_RATE_HIGH_TH) || + (current_tpt > (100 * tbl->expected_tpt[low])))) + scale_action = 0; + } else if ((scale_action == 1) && + (window->success_ratio < IWL_RATE_INCREASE_TH)) + scale_action = 0; + + switch (scale_action) { + case -1: + if (low != IWL_RATE_INVALID) { + update_lq = 1; + index = low; + } + break; + case 1: + if (high != IWL_RATE_INVALID) { + update_lq = 1; + index = high; + } + + break; + case 0: + default: + break; + } + + IWL_DEBUG_HT("choose rate scale index %d action %d low %d " + "high %d type %d\n", + index, scale_action, low, high, tbl->lq_type); + + lq_update: + if (update_lq) { + rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); + rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq, sta); + rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + } + rs_stay_in_table(lq_data); + + if (!update_lq && !done_search && !lq_data->stay_in_tbl) { + lq_data->last_tpt = current_tpt; + + if (is_legacy(tbl->lq_type)) + rs_move_legacy_other(priv, lq_data, index); + else if (is_siso(tbl->lq_type)) + rs_move_siso_to_other(priv, lq_data, index); + else + rs_move_mimo_to_other(priv, lq_data, index); + + if (lq_data->search_better_tbl) { + tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(tbl->win[i])); + + index = iwl_rate_index_from_plcp( + tbl->current_rate.rate_n_flags); + + IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", + tbl->current_rate.rate_n_flags, index); + rs_fill_link_cmd(lq_data, &tbl->current_rate, + &(lq_data->lq), sta); + rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + } + tbl1 = &(lq_data->lq_info[lq_data->active_tbl]); + + if (is_legacy(tbl1->lq_type) && +#ifdef CONFIG_IWLWIFI_HT + !priv->current_assoc_ht.is_ht && +#endif + (lq_data->action_counter >= 1)) { + lq_data->action_counter = 0; + IWL_DEBUG_HT("LQ: STAY in legacy table\n"); + rs_set_stay_in_table(1, lq_data); + } + + if (lq_data->enable_counter && + (lq_data->action_counter >= IWL_ACTION_LIMIT)) { +#ifdef CONFIG_IWLWIFI_HT_AGG + if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) && + (priv->lq_mngr.agg_ctrl.auto_agg)) { + priv->lq_mngr.agg_ctrl.tid_retry = + TID_ALL_SPECIFIED; + schedule_work(&priv->agg_work); + } +#endif /*CONFIG_IWLWIFI_HT_AGG */ + lq_data->action_counter = 0; + rs_set_stay_in_table(0, lq_data); + } + } else { + if ((!update_lq) && (!done_search) && (!lq_data->flush_timer)) + lq_data->flush_timer = jiffies; + } + +out: + rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green); + i = index; + sta->last_txrate = i; + + /* sta->txrate is an index to A mode rates which start + * at IWL_FIRST_OFDM_RATE + */ + if (lq_data->phymode == (u8) MODE_IEEE80211A) + sta->txrate = i - IWL_FIRST_OFDM_RATE; + else + sta->txrate = i; + + return; +} + + +static void rs_initialize_lq(struct iwl_priv *priv, + struct sta_info *sta) +{ + int i; + struct iwl_rate_scale_priv *lq; + struct iwl_scale_tbl_info *tbl; + u8 active_tbl = 0; + int rate_idx; + u8 use_green = rs_use_green(priv); + struct iwl_rate mcs_rate; + + if (!sta || !sta->rate_ctrl_priv) + goto out; + + lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + i = sta->last_txrate; + + if ((lq->lq.sta_id == 0xff) && + (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + goto out; + + if (!lq->search_better_tbl) + active_tbl = lq->active_tbl; + else + active_tbl = 1 - lq->active_tbl; + + tbl = &(lq->lq_info[active_tbl]); + + if ((i < 0) || (i >= IWL_RATE_COUNT)) + i = 0; + + mcs_rate.rate_n_flags = iwl_rates[i].plcp ; + mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK; + mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK; + + if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) + mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK; + + tbl->antenna_type = ANT_AUX; + rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx); + if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type)) + rs_toggle_antenna(&mcs_rate, tbl), + + rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); + tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; + rs_get_expected_tpt_table(lq, tbl); + rs_fill_link_cmd(lq, &mcs_rate, &(lq->lq), sta); + rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC); + out: + return; +} + +static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local + *local) +{ + struct ieee80211_hw_mode *mode = local->oper_hw_mode; + int i; + + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *rate = &mode->rates[i]; + + if (rate->flags & IEEE80211_RATE_SUPPORTED) + return rate; + } + + return &mode->rates[0]; +} + +static struct ieee80211_rate *rs_get_rate(void *priv_rate, + struct net_device *dev, + struct sk_buff *skb, + struct rate_control_extra + *extra) +{ + + int i; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct sta_info *sta; + u16 fc; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_rate_scale_priv *lq; + + IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); + + memset(extra, 0, sizeof(*extra)); + + fc = le16_to_cpu(hdr->frame_control); + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + return rs_get_lowest_rate(local); + } + + sta = sta_info_get(local, hdr->addr1); + + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + sta_info_put(sta); + return rs_get_lowest_rate(local); + } + + lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + i = sta->last_txrate; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) { + u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", + MAC_ARG(hdr->addr1)); + sta_id = iwl_add_station(priv, + hdr->addr1, 0, CMD_ASYNC); + } + if ((sta_id != IWL_INVALID_STATION)) { + lq->lq.sta_id = sta_id; + lq->lq.rs_table[0].rate_n_flags = 0; + lq->ibss_sta_added = 1; + rs_initialize_lq(priv, sta); + } + if (!lq->ibss_sta_added) + goto done; + } + + done: + sta_info_put(sta); + if ((i < 0) || (i > IWL_RATE_COUNT)) + return rs_get_lowest_rate(local); + + return &priv->ieee_rates[i]; +} + +static void *rs_alloc_sta(void *priv, gfp_t gfp) +{ + struct iwl_rate_scale_priv *crl; + int i, j; + + IWL_DEBUG_RATE("create station rate scale window\n"); + + crl = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp); + + if (crl == NULL) + return NULL; + + memset(crl, 0, sizeof(struct iwl_rate_scale_priv)); + crl->lq.sta_id = 0xff; + + for (j = 0; j < LQ_SIZE; j++) + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(crl->lq_info[j].win[i])); + + return crl; +} + +static void rs_rate_init(void *priv_rate, void *priv_sta, + struct ieee80211_local *local, + struct sta_info *sta) +{ + int i, j; + struct ieee80211_hw_mode *mode = local->oper_hw_mode; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_rate_scale_priv *crl = priv_sta; + + memset(crl, 0, sizeof(struct iwl_rate_scale_priv)); + + crl->lq.sta_id = 0xff; + crl->flush_timer = 0; + sta->txrate = 3; + for (j = 0; j < LQ_SIZE; j++) + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(crl->lq_info[j].win[i])); + + IWL_DEBUG_RATE("rate scale global init\n"); + /* TODO: what is a good starting rate for STA? About middle? Maybe not + * the lowest or the highest rate.. Could consider using RSSI from + * previous packets? Need to have IEEE 802.1X auth succeed immediately + * after assoc.. */ + + crl->ibss_sta_added = 0; + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + u8 sta_id = iwl_hw_find_station(priv, sta->addr); + /* for IBSS the call are from tasklet */ + IWL_DEBUG_HT("LQ: ADD station " MAC_FMT " \n", + MAC_ARG(sta->addr)); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", + MAC_ARG(sta->addr)); + sta_id = iwl_add_station(priv, + sta->addr, 0, CMD_ASYNC); + } + if ((sta_id != IWL_INVALID_STATION)) { + crl->lq.sta_id = sta_id; + crl->lq.rs_table[0].rate_n_flags = 0; + } + /* FIXME: this is w/a remove it later */ + priv->assoc_station_added = 1; + } + + for (i = 0; i < mode->num_rates; i++) { + if ((sta->supp_rates & BIT(i)) && + (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) + sta->txrate = i; + } + sta->last_txrate = sta->txrate; + /* For MODE_IEEE80211A mode cck rate are at end + * rate table + */ + if (local->hw.conf.phymode == MODE_IEEE80211A) + sta->last_txrate += IWL_FIRST_OFDM_RATE; + + crl->is_dup = priv->is_dup; + crl->valid_antenna = priv->valid_antenna; + crl->antenna = priv->antenna; + crl->is_green = rs_use_green(priv); + crl->active_rate = priv->active_rate; + crl->active_rate &= ~(0x1000); + crl->active_rate_basic = priv->active_rate_basic; + crl->phymode = priv->phymode; +#ifdef CONFIG_IWLWIFI_HT + crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1); + crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1); + crl->active_siso_rate &= ~((u16)0x2); + crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE; + + crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1); + crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1); + crl->active_mimo_rate &= ~((u16)0x2); + crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE; + IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate, + crl->active_mimo_rate); +#endif /*CONFIG_IWLWIFI_HT*/ + + if (priv->assoc_station_added) + priv->lq_mngr.lq_ready = 1; + + rs_initialize_lq(priv, sta); +} + +static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, + struct iwl_rate *tx_mcs, + struct iwl_link_quality_cmd *lq_cmd, + struct sta_info *sta) +{ + int index = 0; + int rc = 0; + int rate_idx; + u8 ant_toggle_count = 0; + u8 use_ht_possible = 1; + u8 repeat_cur_rate = 0; + struct iwl_rate new_rate; + struct iwl_scale_tbl_info tbl_type = { 0 }; + + rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode, + &tbl_type, &rate_idx); + + if (is_legacy(tbl_type.lq_type)) { + ant_toggle_count = 1; + repeat_cur_rate = IWL_NUMBER_TRY; + } else + repeat_cur_rate = IWL_HT_NUMBER_TRY; + + lq_cmd->general_params.mimo_delimiter = + is_mimo(tbl_type.lq_type) ? 1 : 0; + lq_cmd->rs_table[index].rate_n_flags = + cpu_to_le32(tx_mcs->rate_n_flags); + new_rate.rate_n_flags = tx_mcs->rate_n_flags; + + if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN)) + lq_cmd->general_params.single_stream_ant_msk = 1; + else + lq_cmd->general_params.single_stream_ant_msk = 2; + + index++; + repeat_cur_rate--; + + while (index < LINK_QUAL_MAX_RETRY_NUM) { + while (repeat_cur_rate && (index < LINK_QUAL_MAX_RETRY_NUM)) { + if (is_legacy(tbl_type.lq_type)) { + if (ant_toggle_count < + NUM_TRY_BEFORE_ANTENNA_TOGGLE) + ant_toggle_count++; + else { + rs_toggle_antenna(&new_rate, &tbl_type); + ant_toggle_count = 1; + } + } + lq_cmd->rs_table[index].rate_n_flags = + cpu_to_le32(new_rate.rate_n_flags); + repeat_cur_rate--; + index++; + } + + rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type, + &rate_idx); + + if (is_mimo(tbl_type.lq_type)) + lq_cmd->general_params.mimo_delimiter = index; + + rs_get_lower_rate(lq_data, &tbl_type, rate_idx, + use_ht_possible, &new_rate, sta); + + if (is_legacy(tbl_type.lq_type)) { + if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) + ant_toggle_count++; + else { + rs_toggle_antenna(&new_rate, &tbl_type); + ant_toggle_count = 1; + } + repeat_cur_rate = IWL_NUMBER_TRY; + } else + repeat_cur_rate = IWL_HT_NUMBER_TRY; + + use_ht_possible = 0; + + lq_cmd->rs_table[index].rate_n_flags = + cpu_to_le32(new_rate.rate_n_flags); + /* lq_cmd->rs_table[index].rate_n_flags = 0x800d; */ + + index++; + repeat_cur_rate--; + } + + /* lq_cmd->rs_table[0].rate_n_flags = 0x800d; */ + + lq_cmd->general_params.dual_stream_ant_msk = 3; + lq_cmd->agg_params.agg_dis_start_th = 3; + lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); + return rc; +} + +static void *rs_alloc(struct ieee80211_local *local) +{ + return local->hw.priv; +} +/* rate scale requires free function to be implemented */ +static void rs_free(void *priv_rate) +{ + return; +} + +static void rs_clear(void *priv_rate) +{ + struct iwl_priv *priv = (struct iwl_priv *) priv_rate; + + IWL_DEBUG_RATE("enter\n"); + + priv->lq_mngr.lq_ready = 0; +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + if (priv->lq_mngr.agg_ctrl.granted_ba) + iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED); +#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + + IWL_DEBUG_RATE("leave\n"); +} + +static void rs_free_sta(void *priv, void *priv_sta) +{ + struct iwl_rate_scale_priv *rs_priv = priv_sta; + + IWL_DEBUG_RATE("enter\n"); + kfree(rs_priv); + IWL_DEBUG_RATE("leave\n"); +} + + +static struct rate_control_ops rs_ops = { + .module = NULL, + .name = RS_NAME, + .tx_status = rs_tx_status, + .get_rate = rs_get_rate, + .rate_init = rs_rate_init, + .clear = rs_clear, + .alloc = rs_alloc, + .free = rs_free, + .alloc_sta = rs_alloc_sta, + .free_sta = rs_free_sta, +}; + +int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct iwl_priv *priv = hw->priv; + struct iwl_rate_scale_priv *rs_priv; + struct sta_info *sta; + int count = 0, i; + u32 samples = 0, success = 0, good = 0; + unsigned long now = jiffies; + u32 max_time = 0; + u8 lq_type, antenna; + + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) { + sta_info_put(sta); + IWL_DEBUG_RATE("leave - no private rate data!\n"); + } else + IWL_DEBUG_RATE("leave - no station!\n"); + return sprintf(buf, "station %d not found\n", sta_id); + } + + rs_priv = (void *)sta->rate_ctrl_priv; + + lq_type = rs_priv->lq_info[rs_priv->active_tbl].lq_type; + antenna = rs_priv->lq_info[rs_priv->active_tbl].antenna_type; + + if (is_legacy(lq_type)) + i = IWL_RATE_54M_INDEX; + else + i = IWL_RATE_60M_INDEX; + while (1) { + u64 mask; + int j; + int active = rs_priv->active_tbl; + + count += + sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2); + + mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); + for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) + buf[count++] = + (rs_priv->lq_info[active].win[i].data & mask) + ? '1' : '0'; + + samples += rs_priv->lq_info[active].win[i].counter; + good += rs_priv->lq_info[active].win[i].success_counter; + success += rs_priv->lq_info[active].win[i].success_counter * + iwl_rates[i].ieee; + + if (rs_priv->lq_info[active].win[i].stamp) { + int delta = + jiffies_to_msecs(now - + rs_priv->lq_info[active].win[i].stamp); + + if (delta > max_time) + max_time = delta; + + count += sprintf(&buf[count], "%5dms\n", delta); + } else + buf[count++] = '\n'; + + j = iwl_get_prev_ieee_rate(i); + if (j == i) + break; + i = j; + } + + /* Display the average rate of all samples taken. + * + * NOTE: We multiple # of samples by 2 since the IEEE measurement + * added from iwl_rates is actually 2X the rate */ + if (samples) + count += sprintf(&buf[count], + "\nAverage rate is %3d.%02dMbs over last %4dms\n" + "%3d%% success (%d good packets over %d tries)\n", + success / (2 * samples), (success * 5 / samples) % 10, + max_time, good * 100 / samples, good, samples); + else + count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n"); + count += sprintf(&buf[count], "\nrate scale type %d anntena %d " + "active_search %d rate index %d\n", lq_type, antenna, + rs_priv->search_better_tbl, sta->last_txrate); + + sta_info_put(sta); + return count; +} + +void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) +{ + struct iwl_priv *priv = hw->priv; + + priv->lq_mngr.lq_ready = 1; +} + +void iwl_rate_control_register(struct ieee80211_hw *hw) +{ + ieee80211_rate_control_register(&rs_ops); +} + +void iwl_rate_control_unregister(struct ieee80211_hw *hw) +{ + ieee80211_rate_control_unregister(&rs_ops); +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h new file mode 100644 index 000000000000..c6325f72df68 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -0,0 +1,266 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_4965_rs_h__ +#define __iwl_4965_rs_h__ + +#include "iwl-4965.h" + +struct iwl_rate_info { + u8 plcp; + u8 plcp_siso; + u8 plcp_mimo; + u8 ieee; + u8 prev_ieee; /* previous rate in IEEE speeds */ + u8 next_ieee; /* next rate in IEEE speeds */ + u8 prev_rs; /* previous rate used in rs algo */ + u8 next_rs; /* next rate used in rs algo */ + u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ + u8 next_rs_tgg; /* next rate used in TGG rs algo */ +}; + +enum { + IWL_RATE_1M_INDEX = 0, + IWL_RATE_2M_INDEX, + IWL_RATE_5M_INDEX, + IWL_RATE_11M_INDEX, + IWL_RATE_6M_INDEX, + IWL_RATE_9M_INDEX, + IWL_RATE_12M_INDEX, + IWL_RATE_18M_INDEX, + IWL_RATE_24M_INDEX, + IWL_RATE_36M_INDEX, + IWL_RATE_48M_INDEX, + IWL_RATE_54M_INDEX, + IWL_RATE_60M_INDEX, + IWL_RATE_COUNT, + IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, + IWL_RATE_INVALID = IWL_RATE_INVM_INDEX +}; + +enum { + IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, + IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, + IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, + IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, +}; + +/* #define vs. enum to keep from defaulting to 'large integer' */ +#define IWL_RATE_6M_MASK (1< + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwlwifi.h" +#include "iwl-4965.h" +#include "iwl-helpers.h" + +#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ + [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ + IWL_RATE_SISO_##s##M_PLCP, \ + IWL_RATE_MIMO_##s##M_PLCP, \ + IWL_RATE_##r##M_IEEE, \ + IWL_RATE_##ip##M_INDEX, \ + IWL_RATE_##in##M_INDEX, \ + IWL_RATE_##rp##M_INDEX, \ + IWL_RATE_##rn##M_INDEX, \ + IWL_RATE_##pp##M_INDEX, \ + IWL_RATE_##np##M_INDEX } + +/* + * Parameter order: + * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate + * + * If there isn't a valid next or previous rate then INV is used which + * maps to IWL_RATE_INVALID + * + */ +const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { + IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ + IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ + IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ + IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ + IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ + IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ + IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ + IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ + IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ + IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ + IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ + IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ + IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ +}; + +static int is_fat_channel(__le32 rxon_flags) +{ + return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || + (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); +} + +static u8 is_single_stream(struct iwl_priv *priv) +{ +#ifdef CONFIG_IWLWIFI_HT + if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht || + (priv->active_rate_ht[1] == 0) || + (priv->ps_mode == IWL_MIMO_PS_STATIC)) + return 1; +#else + return 1; +#endif /*CONFIG_IWLWIFI_HT */ + return 0; +} + +/* + * Determine how many receiver/antenna chains to use. + * More provides better reception via diversity. Fewer saves power. + * MIMO (dual stream) requires at least 2, but works better with 3. + * This does not determine *which* chains to use, just how many. + */ +static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv, + u8 *idle_state, u8 *rx_state) +{ + u8 is_single = is_single_stream(priv); + u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; + + /* # of Rx chains to use when expecting MIMO. */ + if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) + *rx_state = 2; + else + *rx_state = 3; + + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->ps_mode) { + case IWL_MIMO_PS_STATIC: + case IWL_MIMO_PS_DYNAMIC: + *idle_state = (is_cam) ? 2 : 1; + break; + case IWL_MIMO_PS_NONE: + *idle_state = (is_cam) ? *rx_state : 1; + break; + default: + *idle_state = 1; + break; + } + + return 0; +} + +int iwl_hw_rxq_stop(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* stop HW */ + iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + (1 << 24), 1000); + if (rc < 0) + IWL_ERROR("Can't stop Rx DMA.\n"); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) +{ + int i; + int start = 0; + int ret = IWL_INVALID_STATION; + unsigned long flags; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || + (priv->iw_mode == IEEE80211_IF_TYPE_AP)) + start = IWL_STA_ID; + + if (is_broadcast_ether_addr(addr)) + return IWL4965_BROADCAST_ID; + + spin_lock_irqsave(&priv->sta_lock, flags); + for (i = start; i < priv->hw_setting.max_stations; i++) + if ((priv->stations[i].used) && + (!compare_ether_addr + (priv->stations[i].sta.sta.addr, addr))) { + ret = i; + goto out; + } + + IWL_DEBUG_ASSOC("can not find STA " MAC_FMT " total %d\n", + MAC_ARG(addr), priv->num_stations); + + out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; +} + +static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) +{ + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + if (!pwr_max) { + u32 val; + + rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, + &val); + + if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) + iwl_set_bits_mask_restricted_reg( + priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } else + iwl_set_bits_mask_restricted_reg( + priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* stop HW */ + iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + + iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, + rxq->dma_addr >> 8); + + iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, + (priv->hw_setting.shared_phys + + offsetof(struct iwl_shared, val0)) >> 4); + + iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K | + /*0x10 << 4 | */ + (RX_QUEUE_SIZE_LOG << + FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); + + /* + * iwl_write32(priv,CSR_INT_COAL_REG,0); + */ + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int iwl4965_kw_init(struct iwl_priv *priv) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) + goto out; + + iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG, + priv->kw.dma_addr >> 4); + iwl_release_restricted_access(priv); +out: + spin_unlock_irqrestore(&priv->lock, flags); + return rc; +} + +static int iwl4965_kw_alloc(struct iwl_priv *priv) +{ + struct pci_dev *dev = priv->pci_dev; + struct iwl_kw *kw = &priv->kw; + + kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */ + kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); + if (!kw->v_addr) + return -ENOMEM; + + return 0; +} + +#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ + ? # x " " : "") + +int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel, + const struct iwl_eeprom_channel *eeprom_ch, + u8 fat_extension_channel) +{ + struct iwl_channel_info *ch_info; + + ch_info = (struct iwl_channel_info *) + iwl_get_channel_info(priv, phymode, channel); + + if (!is_channel_valid(ch_info)) + return -1; + + IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + " %ddBm): Ad-Hoc %ssupported\n", + ch_info->channel, + is_channel_a_band(ch_info) ? + "5.2" : "2.4", + CHECK_AND_PRINT(IBSS), + CHECK_AND_PRINT(ACTIVE), + CHECK_AND_PRINT(RADAR), + CHECK_AND_PRINT(WIDE), + CHECK_AND_PRINT(NARROW), + CHECK_AND_PRINT(DFS), + eeprom_ch->flags, + eeprom_ch->max_power_avg, + ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) + && !(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; + + return 0; +} + +static void iwl4965_kw_free(struct iwl_priv *priv) +{ + struct pci_dev *dev = priv->pci_dev; + struct iwl_kw *kw = &priv->kw; + + if (kw->v_addr) { + pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); + memset(kw, 0, sizeof(*kw)); + } +} + +/** + * iwl4965_txq_ctx_reset - Reset TX queue context + * Destroys all DMA structures and initialise them again + * + * @param priv + * @return error code + */ +static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) +{ + int rc = 0; + int txq_id, slots_num; + unsigned long flags; + + iwl4965_kw_free(priv); + + iwl_hw_txq_ctx_free(priv); + + /* Tx CMD queue */ + rc = iwl4965_kw_alloc(priv); + if (rc) { + IWL_ERROR("Keep Warm allocation failed"); + goto error_kw; + } + + spin_lock_irqsave(&priv->lock, flags); + + rc = iwl_grab_restricted_access(priv); + if (unlikely(rc)) { + IWL_ERROR("TX reset failed"); + spin_unlock_irqrestore(&priv->lock, flags); + goto error_reset; + } + + iwl_write_restricted_reg(priv, SCD_TXFACT, 0); + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + rc = iwl4965_kw_init(priv); + if (rc) { + IWL_ERROR("kw_init failed\n"); + goto error_reset; + } + + /* Tx queue(s) */ + for (txq_id = 0; txq_id < priv->hw_setting.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, + txq_id); + if (rc) { + IWL_ERROR("Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return rc; + + error: + iwl_hw_txq_ctx_free(priv); + error_reset: + iwl4965_kw_free(priv); + error_kw: + return rc; +} + +int iwl_hw_nic_init(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + struct iwl_rx_queue *rxq = &priv->rxq; + u8 rev_id; + u32 val; + u8 val_link; + + iwl_power_init_handle(priv); + + /* nic_init */ + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("Failed to init the card\n"); + return rc; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG); + + iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG); + + udelay(20); + + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + + iwl_release_restricted_access(priv); + iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); + spin_unlock_irqrestore(&priv->lock, flags); + + /* Determine HW type */ + rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + if (rc) + return rc; + + IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); + + iwl4965_nic_set_pwr_src(priv, 1); + spin_lock_irqsave(&priv->lock, flags); + + if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) { + pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val); + /* Enable No Snoop field */ + pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8, + val & ~(1 << 11)); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Read the EEPROM */ + rc = iwl_eeprom_init(priv); + if (rc) + return rc; + + if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) { + IWL_ERROR("Older EEPROM detected! Aborting.\n"); + return -EINVAL; + } + + pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); + + /* disable L1 entry -- workaround for pre-B1 */ + pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); + + spin_lock_irqsave(&priv->lock, flags); + + /* set CSR_HW_CONFIG_REG for uCode use */ + + iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R | + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + + rc = iwl_grab_restricted_access(priv); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("Failed to init the card\n"); + return rc; + } + + iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG); + iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_hw_card_show_info(priv); + + /* end nic_init */ + + /* Allocate the RX queue, or reset if it is already allocated */ + if (!rxq->bd) { + rc = iwl_rx_queue_alloc(priv); + if (rc) { + IWL_ERROR("Unable to initialize Rx queue\n"); + return -ENOMEM; + } + } else + iwl_rx_queue_reset(priv, rxq); + + iwl_rx_replenish(priv); + + iwl4965_rx_init(priv, rxq); + + spin_lock_irqsave(&priv->lock, flags); + + rxq->need_update = 1; + iwl_rx_queue_update_write_ptr(priv, rxq); + + spin_unlock_irqrestore(&priv->lock, flags); + rc = iwl4965_txq_ctx_reset(priv); + if (rc) + return rc; + + if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) + IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n"); + + if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) + IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n"); + + set_bit(STATUS_INIT, &priv->status); + + return 0; +} + +int iwl_hw_nic_stop_master(struct iwl_priv *priv) +{ + int rc = 0; + u32 reg_val; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + reg_val = iwl_read32(priv, CSR_GP_CNTRL); + + if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == + (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) + IWL_DEBUG_INFO("Card in power save, master is already " + "stopped\n"); + else { + rc = iwl_poll_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + } + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("stop master\n"); + + return rc; +} + +void iwl_hw_txq_ctx_stop(struct iwl_priv *priv) +{ + + int txq_id; + unsigned long flags; + + /* reset TFD queues */ + for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { + spin_lock_irqsave(&priv->lock, flags); + if (iwl_grab_restricted_access(priv)) { + spin_unlock_irqrestore(&priv->lock, flags); + continue; + } + + iwl_write_restricted(priv, + IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), + 0x0); + iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, + IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE + (txq_id), 200); + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + } + + iwl_hw_txq_ctx_free(priv); +} + +int iwl_hw_nic_reset(struct iwl_priv *priv) +{ + int rc = 0; + unsigned long flags; + + iwl_hw_nic_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl_poll_bit(priv, CSR_RESET, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); + + udelay(10); + + rc = iwl_grab_restricted_access(priv); + if (!rc) { + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + + udelay(10); + + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + + iwl_release_restricted_access(priv); + } + + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; + +} + +#define REG_RECALIB_PERIOD (60) + +/** + * iwl4965_bg_statistics_periodic - Timer callback to queue statistics + * + * This callback is provided in order to queue the statistics_work + * in work_queue context (v. softirq) + * + * This timer function is continually reset to execute within + * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION + * was received. We need to ensure we receive the statistics in order + * to update the temperature used for calibrating the TXPOWER. However, + * we can't send the statistics command from softirq context (which + * is the context which timers run at) so we have to queue off the + * statistics_work to actually send the command to the hardware. + */ +static void iwl4965_bg_statistics_periodic(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + + queue_work(priv->workqueue, &priv->statistics_work); +} + +/** + * iwl4965_bg_statistics_work - Send the statistics request to the hardware. + * + * This is queued by iwl_bg_statistics_periodic. + */ +static void iwl4965_bg_statistics_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + statistics_work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_send_statistics_request(priv); + mutex_unlock(&priv->mutex); +} + +#define CT_LIMIT_CONST 259 +#define TM_CT_KILL_THRESHOLD 110 + +void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) +{ + struct iwl_ct_kill_config cmd; + u32 R1, R2, R3; + u32 temp_th; + u32 crit_temperature; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) { + 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]); + } else { + R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]); + R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]); + R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]); + } + + temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD); + + crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; + cmd.critical_temperature_R = cpu_to_le32(crit_temperature); + rc = iwl_send_cmd_pdu(priv, + REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); + if (rc) + IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n"); +} + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + +/* "false alarms" are signals that our DSP tries to lock onto, + * but then determines that they are either noise, or transmissions + * from a distant wireless network (also "noise", really) that get + * "stepped on" by stronger transmissions within our own network. + * This algorithm attempts to set a sensitivity level that is high + * enough to receive all of our own network traffic, but not so + * high that our DSP gets too busy trying to lock onto non-network + * activity/noise. */ +static int iwl4965_sens_energy_cck(struct iwl_priv *priv, + u32 norm_fa, + u32 rx_enable_time, + struct statistics_general_data *rx_info) +{ + u32 max_nrg_cck = 0; + int i = 0; + u8 max_silence_rssi = 0; + u32 silence_ref = 0; + u8 silence_rssi_a = 0; + u8 silence_rssi_b = 0; + u8 silence_rssi_c = 0; + u32 val; + + /* "false_alarms" values below are cross-multiplications to assess the + * numbers of false alarms within the measured period of actual Rx + * (Rx is off when we're txing), vs the min/max expected false alarms + * (some should be expected if rx is sensitive enough) in a + * hypothetical listening period of 200 time units (TU), 204.8 msec: + * + * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time + * + * */ + u32 false_alarms = norm_fa * 200 * 1024; + u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; + u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; + struct iwl_sensitivity_data *data = NULL; + + data = &(priv->sensitivity_data); + + data->nrg_auto_corr_silence_diff = 0; + + /* Find max silence rssi among all 3 receivers. + * This is background noise, which may include transmissions from other + * networks, measured during silence before our network's beacon */ + silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a & + ALL_BAND_FILTER)>>8); + silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b & + ALL_BAND_FILTER)>>8); + silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c & + ALL_BAND_FILTER)>>8); + + val = max(silence_rssi_b, silence_rssi_c); + max_silence_rssi = max(silence_rssi_a, (u8) val); + + /* Store silence rssi in 20-beacon history table */ + data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi; + data->nrg_silence_idx++; + if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L) + data->nrg_silence_idx = 0; + + /* Find max silence rssi across 20 beacon history */ + for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) { + val = data->nrg_silence_rssi[i]; + silence_ref = max(silence_ref, val); + } + IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n", + silence_rssi_a, silence_rssi_b, silence_rssi_c, + silence_ref); + + /* Find max rx energy (min value!) among all 3 receivers, + * measured during beacon frame. + * Save it in 10-beacon history table. */ + i = data->nrg_energy_idx; + val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c); + data->nrg_value[i] = min(rx_info->beacon_energy_a, val); + + data->nrg_energy_idx++; + if (data->nrg_energy_idx >= 10) + data->nrg_energy_idx = 0; + + /* Find min rx energy (max value) across 10 beacon history. + * This is the minimum signal level that we want to receive well. + * Add backoff (margin so we don't miss slightly lower energy frames). + * This establishes an upper bound (min value) for energy threshold. */ + max_nrg_cck = data->nrg_value[0]; + for (i = 1; i < 10; i++) + max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i])); + max_nrg_cck += 6; + + IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n", + rx_info->beacon_energy_a, rx_info->beacon_energy_b, + rx_info->beacon_energy_c, max_nrg_cck - 6); + + /* Count number of consecutive beacons with fewer-than-desired + * false alarms. */ + if (false_alarms < min_false_alarms) + data->num_in_cck_no_fa++; + else + data->num_in_cck_no_fa = 0; + IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n", + data->num_in_cck_no_fa); + + /* If we got too many false alarms this time, reduce sensitivity */ + if (false_alarms > max_false_alarms) { + IWL_DEBUG_CALIB("norm FA %u > max FA %u\n", + false_alarms, max_false_alarms); + IWL_DEBUG_CALIB("... reducing sensitivity\n"); + data->nrg_curr_state = IWL_FA_TOO_MANY; + + if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) { + /* Store for "fewer than desired" on later beacon */ + data->nrg_silence_ref = silence_ref; + + /* increase energy threshold (reduce nrg value) + * to decrease sensitivity */ + if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK)) + data->nrg_th_cck = data->nrg_th_cck + - NRG_STEP_CCK; + } + + /* increase auto_corr values to decrease sensitivity */ + if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK) + data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1; + else { + val = data->auto_corr_cck + AUTO_CORR_STEP_CCK; + data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val); + } + val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK; + data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val); + + /* Else if we got fewer than desired, increase sensitivity */ + } else if (false_alarms < min_false_alarms) { + data->nrg_curr_state = IWL_FA_TOO_FEW; + + /* Compare silence level with silence level for most recent + * healthy number or too many false alarms */ + data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref - + (s32)silence_ref; + + IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n", + false_alarms, min_false_alarms, + data->nrg_auto_corr_silence_diff); + + /* Increase value to increase sensitivity, but only if: + * 1a) previous beacon did *not* have *too many* false alarms + * 1b) AND there's a significant difference in Rx levels + * from a previous beacon with too many, or healthy # FAs + * OR 2) We've seen a lot of beacons (100) with too few + * false alarms */ + if ((data->nrg_prev_state != IWL_FA_TOO_MANY) && + ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || + (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { + + IWL_DEBUG_CALIB("... increasing sensitivity\n"); + /* Increase nrg value to increase sensitivity */ + val = data->nrg_th_cck + NRG_STEP_CCK; + data->nrg_th_cck = min((u32)NRG_MIN_CCK, val); + + /* Decrease auto_corr values to increase sensitivity */ + val = data->auto_corr_cck - AUTO_CORR_STEP_CCK; + data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val); + + val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK; + data->auto_corr_cck_mrc = + max((u32)AUTO_CORR_MIN_CCK_MRC, val); + + } else + IWL_DEBUG_CALIB("... but not changing sensitivity\n"); + + /* Else we got a healthy number of false alarms, keep status quo */ + } else { + IWL_DEBUG_CALIB(" FA in safe zone\n"); + data->nrg_curr_state = IWL_FA_GOOD_RANGE; + + /* Store for use in "fewer than desired" with later beacon */ + data->nrg_silence_ref = silence_ref; + + /* If previous beacon had too many false alarms, + * give it some extra margin by reducing sensitivity again + * (but don't go below measured energy of desired Rx) */ + if (IWL_FA_TOO_MANY == data->nrg_prev_state) { + IWL_DEBUG_CALIB("... increasing margin\n"); + data->nrg_th_cck -= NRG_MARGIN; + } + } + + /* Make sure the energy threshold does not go above the measured + * energy of the desired Rx signals (reduced by backoff margin), + * or else we might start missing Rx frames. + * Lower value is higher energy, so we use max()! + */ + data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck); + IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck); + + data->nrg_prev_state = data->nrg_curr_state; + + return 0; +} + + +static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, + u32 norm_fa, + u32 rx_enable_time) +{ + u32 val; + u32 false_alarms = norm_fa * 200 * 1024; + u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; + u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; + struct iwl_sensitivity_data *data = NULL; + + data = &(priv->sensitivity_data); + + /* If we got too many false alarms this time, reduce sensitivity */ + if (false_alarms > max_false_alarms) { + + IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n", + false_alarms, max_false_alarms); + + val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm = + min((u32)AUTO_CORR_MAX_OFDM, val); + + val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc = + min((u32)AUTO_CORR_MAX_OFDM_MRC, val); + + val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_x1 = + min((u32)AUTO_CORR_MAX_OFDM_X1, val); + + val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc_x1 = + min((u32)AUTO_CORR_MAX_OFDM_MRC_X1, val); + } + + /* Else if we got fewer than desired, increase sensitivity */ + else if (false_alarms < min_false_alarms) { + + IWL_DEBUG_CALIB("norm FA %u < min FA %u\n", + false_alarms, min_false_alarms); + + val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm = + max((u32)AUTO_CORR_MIN_OFDM, val); + + val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc = + max((u32)AUTO_CORR_MIN_OFDM_MRC, val); + + val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_x1 = + max((u32)AUTO_CORR_MIN_OFDM_X1, val); + + val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc_x1 = + max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val); + } + + else + IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n", + min_false_alarms, false_alarms, max_false_alarms); + + return 0; +} + +static int iwl_sensitivity_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ +static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) +{ + int rc = 0; + struct iwl_sensitivity_cmd cmd ; + struct iwl_sensitivity_data *data = NULL; + struct iwl_host_cmd cmd_out = { + .id = SENSITIVITY_CMD, + .len = sizeof(struct iwl_sensitivity_cmd), + .meta.flags = flags, + .data = &cmd, + }; + + data = &(priv->sensitivity_data); + + memset(&cmd, 0, sizeof(cmd)); + + cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm); + cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_mrc); + cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_x1); + cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1); + + cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_cck); + cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_cck_mrc); + + cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] = + cpu_to_le16((u16)data->nrg_th_cck); + cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] = + cpu_to_le16((u16)data->nrg_th_ofdm); + + cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = + __constant_cpu_to_le16(190); + cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = + __constant_cpu_to_le16(390); + cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = + __constant_cpu_to_le16(62); + + IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", + data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, + data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1, + data->nrg_th_ofdm); + + IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n", + data->auto_corr_cck, data->auto_corr_cck_mrc, + data->nrg_th_cck); + + cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; + + if (flags & CMD_ASYNC) + cmd_out.meta.u.callback = iwl_sensitivity_callback; + + /* Don't send command to uCode if nothing has changed */ + if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]), + sizeof(u16)*HD_TABLE_SIZE)) { + IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n"); + return 0; + } + + /* Copy table for comparison next time */ + memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), + sizeof(u16)*HD_TABLE_SIZE); + + rc = iwl_send_cmd(priv, &cmd_out); + if (!rc) { + IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n"); + return rc; + } + + return 0; +} + +void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) +{ + int rc = 0; + int i; + struct iwl_sensitivity_data *data = NULL; + + IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n"); + + if (force) + memset(&(priv->sensitivity_tbl[0]), 0, + sizeof(u16)*HD_TABLE_SIZE); + + /* Clear driver's sensitivity algo data */ + data = &(priv->sensitivity_data); + memset(data, 0, sizeof(struct iwl_sensitivity_data)); + + data->num_in_cck_no_fa = 0; + data->nrg_curr_state = IWL_FA_TOO_MANY; + data->nrg_prev_state = IWL_FA_TOO_MANY; + data->nrg_silence_ref = 0; + data->nrg_silence_idx = 0; + data->nrg_energy_idx = 0; + + for (i = 0; i < 10; i++) + data->nrg_value[i] = 0; + + for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) + data->nrg_silence_rssi[i] = 0; + + data->auto_corr_ofdm = 90; + data->auto_corr_ofdm_mrc = 170; + data->auto_corr_ofdm_x1 = 105; + data->auto_corr_ofdm_mrc_x1 = 220; + data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF; + data->auto_corr_cck_mrc = 200; + data->nrg_th_cck = 100; + data->nrg_th_ofdm = 100; + + data->last_bad_plcp_cnt_ofdm = 0; + data->last_fa_cnt_ofdm = 0; + data->last_bad_plcp_cnt_cck = 0; + data->last_fa_cnt_cck = 0; + + /* Clear prior Sensitivity command data to force send to uCode */ + if (force) + memset(&(priv->sensitivity_tbl[0]), 0, + sizeof(u16)*HD_TABLE_SIZE); + + rc |= iwl4965_sensitivity_write(priv, flags); + IWL_DEBUG_CALIB("<chain_noise_data); + if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { + struct iwl_calibration_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.diff_gain_a = 0; + cmd.diff_gain_b = 0; + cmd.diff_gain_c = 0; + rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + msleep(4); + data->state = IWL_CHAIN_NOISE_ACCUMULATE; + IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); + } + return; +} + +/* + * Accumulate 20 beacons of signal and noise statistics for each of + * 3 receivers/antennas/rx-chains, then figure out: + * 1) Which antennas are connected. + * 2) Differential rx gain settings to balance the 3 receivers. + */ +static void iwl4965_noise_calibration(struct iwl_priv *priv, + struct iwl_notif_statistics *stat_resp) +{ + struct iwl_chain_noise_data *data = NULL; + int rc = 0; + + u32 chain_noise_a; + u32 chain_noise_b; + u32 chain_noise_c; + u32 chain_sig_a; + u32 chain_sig_b; + u32 chain_sig_c; + u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; + u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; + u32 max_average_sig; + u16 max_average_sig_antenna_i; + u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE; + u16 min_average_noise_antenna_i = INITIALIZATION_VALUE; + u16 i = 0; + u16 chan_num = INITIALIZATION_VALUE; + u32 band = INITIALIZATION_VALUE; + u32 active_chains = 0; + unsigned long flags; + struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); + + data = &(priv->chain_noise_data); + + /* Accumulate just the first 20 beacons after the first association, + * then we're done forever. */ + if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { + if (data->state == IWL_CHAIN_NOISE_ALIVE) + IWL_DEBUG_CALIB("Wait for noise calib reset\n"); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB(" << Interference data unavailable\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1; + chan_num = le16_to_cpu(priv->staging_rxon.channel); + + /* Make sure we accumulate data for just the associated channel + * (even if scanning). */ + if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) || + ((STATISTICS_REPLY_FLG_BAND_24G_MSK == + (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) { + IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n", + chan_num, band); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + /* Accumulate beacon statistics values across 20 beacons */ + chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & + IN_BAND_FILTER; + chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) & + IN_BAND_FILTER; + chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) & + IN_BAND_FILTER; + + chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER; + chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER; + chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER; + + spin_unlock_irqrestore(&priv->lock, flags); + + data->beacon_count++; + + data->chain_noise_a = (chain_noise_a + data->chain_noise_a); + data->chain_noise_b = (chain_noise_b + data->chain_noise_b); + data->chain_noise_c = (chain_noise_c + data->chain_noise_c); + + data->chain_signal_a = (chain_sig_a + data->chain_signal_a); + data->chain_signal_b = (chain_sig_b + data->chain_signal_b); + data->chain_signal_c = (chain_sig_c + data->chain_signal_c); + + IWL_DEBUG_CALIB("chan=%d, band=%d, beacon=%d\n", chan_num, band, + data->beacon_count); + IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n", + chain_sig_a, chain_sig_b, chain_sig_c); + IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n", + chain_noise_a, chain_noise_b, chain_noise_c); + + /* If this is the 20th beacon, determine: + * 1) Disconnected antennas (using signal strengths) + * 2) Differential gain (using silence noise) to balance receivers */ + if (data->beacon_count == CAL_NUM_OF_BEACONS) { + + /* Analyze signal for disconnected antenna */ + average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS; + average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS; + average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS; + + if (average_sig[0] >= average_sig[1]) { + max_average_sig = average_sig[0]; + max_average_sig_antenna_i = 0; + active_chains = (1 << max_average_sig_antenna_i); + } else { + max_average_sig = average_sig[1]; + max_average_sig_antenna_i = 1; + active_chains = (1 << max_average_sig_antenna_i); + } + + if (average_sig[2] >= max_average_sig) { + max_average_sig = average_sig[2]; + max_average_sig_antenna_i = 2; + active_chains = (1 << max_average_sig_antenna_i); + } + + IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n", + average_sig[0], average_sig[1], average_sig[2]); + IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n", + max_average_sig, max_average_sig_antenna_i); + + /* Compare signal strengths for all 3 receivers. */ + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (i != max_average_sig_antenna_i) { + s32 rssi_delta = (max_average_sig - + average_sig[i]); + + /* If signal is very weak, compared with + * strongest, mark it as disconnected. */ + if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS) + data->disconn_array[i] = 1; + else + active_chains |= (1 << i); + IWL_DEBUG_CALIB("i = %d rssiDelta = %d " + "disconn_array[i] = %d\n", + i, rssi_delta, data->disconn_array[i]); + } + } + + /*If both chains A & B are disconnected - + * connect B and leave A as is */ + if (data->disconn_array[CHAIN_A] && + data->disconn_array[CHAIN_B]) { + data->disconn_array[CHAIN_B] = 0; + active_chains |= (1 << CHAIN_B); + IWL_DEBUG_CALIB("both A & B chains are disconnected! " + "W/A - declare B as connected\n"); + } + + IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", + active_chains); + + /* Save for use within RXON, TX, SCAN commands, etc. */ + priv->valid_antenna = active_chains; + + /* Analyze noise for rx balance */ + average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); + average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); + average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS); + + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (!(data->disconn_array[i]) && + (average_noise[i] <= min_average_noise)) { + /* This means that chain i is active and has + * lower noise values so far: */ + min_average_noise = average_noise[i]; + min_average_noise_antenna_i = i; + } + } + + data->delta_gain_code[min_average_noise_antenna_i] = 0; + + IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n", + average_noise[0], average_noise[1], + average_noise[2]); + + IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n", + min_average_noise, min_average_noise_antenna_i); + + for (i = 0; i < NUM_RX_CHAINS; i++) { + s32 delta_g = 0; + + if (!(data->disconn_array[i]) && + (data->delta_gain_code[i] == + CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) { + delta_g = average_noise[i] - min_average_noise; + data->delta_gain_code[i] = (u8)((delta_g * + 10) / 15); + if (CHAIN_NOISE_MAX_DELTA_GAIN_CODE < + data->delta_gain_code[i]) + data->delta_gain_code[i] = + CHAIN_NOISE_MAX_DELTA_GAIN_CODE; + + data->delta_gain_code[i] = + (data->delta_gain_code[i] | (1 << 2)); + } else + data->delta_gain_code[i] = 0; + } + IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n", + data->delta_gain_code[0], + data->delta_gain_code[1], + data->delta_gain_code[2]); + + /* Differential gain gets sent to uCode only once */ + if (!data->radio_write) { + struct iwl_calibration_cmd cmd; + data->radio_write = 1; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.diff_gain_a = data->delta_gain_code[0]; + cmd.diff_gain_b = data->delta_gain_code[1]; + cmd.diff_gain_c = data->delta_gain_code[2]; + rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + if (rc) + IWL_DEBUG_CALIB("fail sending cmd " + "REPLY_PHY_CALIBRATION_CMD \n"); + + /* TODO we might want recalculate + * rx_chain in rxon cmd */ + + /* Mark so we run this algo only once! */ + data->state = IWL_CHAIN_NOISE_CALIBRATED; + } + data->chain_noise_a = 0; + data->chain_noise_b = 0; + data->chain_noise_c = 0; + data->chain_signal_a = 0; + data->chain_signal_b = 0; + data->chain_signal_c = 0; + data->beacon_count = 0; + } + return; +} + +static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, + struct iwl_notif_statistics *resp) +{ + int rc = 0; + u32 rx_enable_time; + u32 fa_cck; + u32 fa_ofdm; + u32 bad_plcp_cck; + u32 bad_plcp_ofdm; + u32 norm_fa_ofdm; + u32 norm_fa_cck; + struct iwl_sensitivity_data *data = NULL; + struct statistics_rx_non_phy *rx_info = &(resp->rx.general); + struct statistics_rx *statistics = &(resp->rx); + unsigned long flags; + struct statistics_general_data statis; + + data = &(priv->sensitivity_data); + + if (!iwl_is_associated(priv)) { + IWL_DEBUG_CALIB("<< - not associated\n"); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB("<< invalid data.\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + /* Extract Statistics: */ + rx_enable_time = le32_to_cpu(rx_info->channel_load); + fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt); + fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt); + bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err); + bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err); + + statis.beacon_silence_rssi_a = + le32_to_cpu(statistics->general.beacon_silence_rssi_a); + statis.beacon_silence_rssi_b = + le32_to_cpu(statistics->general.beacon_silence_rssi_b); + statis.beacon_silence_rssi_c = + le32_to_cpu(statistics->general.beacon_silence_rssi_c); + statis.beacon_energy_a = + le32_to_cpu(statistics->general.beacon_energy_a); + statis.beacon_energy_b = + le32_to_cpu(statistics->general.beacon_energy_b); + statis.beacon_energy_c = + le32_to_cpu(statistics->general.beacon_energy_c); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time); + + if (!rx_enable_time) { + IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n"); + return; + } + + /* These statistics increase monotonically, and do not reset + * at each beacon. Calculate difference from last value, or just + * use the new statistics value if it has reset or wrapped around. */ + if (data->last_bad_plcp_cnt_cck > bad_plcp_cck) + data->last_bad_plcp_cnt_cck = bad_plcp_cck; + else { + bad_plcp_cck -= data->last_bad_plcp_cnt_cck; + data->last_bad_plcp_cnt_cck += bad_plcp_cck; + } + + if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm) + data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm; + else { + bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm; + data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm; + } + + if (data->last_fa_cnt_ofdm > fa_ofdm) + data->last_fa_cnt_ofdm = fa_ofdm; + else { + fa_ofdm -= data->last_fa_cnt_ofdm; + data->last_fa_cnt_ofdm += fa_ofdm; + } + + if (data->last_fa_cnt_cck > fa_cck) + data->last_fa_cnt_cck = fa_cck; + else { + fa_cck -= data->last_fa_cnt_cck; + data->last_fa_cnt_cck += fa_cck; + } + + /* Total aborted signal locks */ + norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm; + norm_fa_cck = fa_cck + bad_plcp_cck; + + IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck, + bad_plcp_cck, fa_ofdm, bad_plcp_ofdm); + + iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); + iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); + rc |= iwl4965_sensitivity_write(priv, CMD_ASYNC); + + return; +} + +static void iwl4965_bg_sensitivity_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + sensitivity_work); + + mutex_lock(&priv->mutex); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + test_bit(STATUS_SCANNING, &priv->status)) { + mutex_unlock(&priv->mutex); + return; + } + + if (priv->start_calib) { + iwl4965_noise_calibration(priv, &priv->statistics); + + if (priv->sensitivity_data.state == + IWL_SENS_CALIB_NEED_REINIT) { + iwl4965_init_sensitivity(priv, CMD_ASYNC, 0); + priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED; + } else + iwl4965_sensitivity_calibration(priv, + &priv->statistics); + } + + mutex_unlock(&priv->mutex); + return; +} +#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ + +static void iwl4965_bg_txpower_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + txpower_work); + + /* If a scan happened to start before we got here + * then just return; the statistics notification will + * kick off another scheduled work to compensate for + * any temperature delta we missed here. */ + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + test_bit(STATUS_SCANNING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + /* Regardless of if we are assocaited, we must reconfigure the + * TX power since frames can be sent on non-radar channels while + * not associated */ + iwl_hw_reg_send_txpower(priv); + + /* Update last_temperature to keep is_calib_needed from running + * when it isn't needed... */ + priv->last_temperature = priv->temperature; + + mutex_unlock(&priv->mutex); +} + +/* + * Acquire priv->lock before calling this function ! + */ +static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index) +{ + iwl_write_restricted(priv, HBUS_TARG_WRPTR, + (index & 0xff) | (txq_id << 8)); + iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(txq_id), index); +} + +/* + * Acquire priv->lock before calling this function ! + */ +static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + int tx_fifo_id, int scd_retry) +{ + int txq_id = txq->q.id; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + + iwl_write_restricted_reg(priv, SCD_QUEUE_STATUS_BITS(txq_id), + (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | + (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) | + (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) | + SCD_QUEUE_STTS_REG_MSK); + + txq->sched_retry = scd_retry; + + IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", + active ? "Activete" : "Deactivate", + scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); +} + +static const u16 default_queue_to_tx_fifo[] = { + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL_CMD_FIFO_NUM, + IWL_TX_FIFO_HCCA_1, + IWL_TX_FIFO_HCCA_2 +}; + +static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id) +{ + set_bit(txq_id, &priv->txq_ctx_active_msk); +} + +static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) +{ + clear_bit(txq_id, &priv->txq_ctx_active_msk); +} + +int iwl4965_alive_notify(struct iwl_priv *priv) +{ + u32 a; + int i = 0; + unsigned long flags; + int rc; + + spin_lock_irqsave(&priv->lock, flags); + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + memset(&(priv->sensitivity_data), 0, + sizeof(struct iwl_sensitivity_data)); + memset(&(priv->chain_noise_data), 0, + sizeof(struct iwl_chain_noise_data)); + for (i = 0; i < NUM_RX_CHAINS; i++) + priv->chain_noise_data.delta_gain_code[i] = + CHAIN_NOISE_DELTA_GAIN_INIT_VAL; +#endif /* CONFIG_IWLWIFI_SENSITIVITY*/ + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + priv->scd_base_addr = iwl_read_restricted_reg(priv, SCD_SRAM_BASE_ADDR); + a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET; + for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4) + iwl_write_restricted_mem(priv, a, 0); + for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4) + iwl_write_restricted_mem(priv, a, 0); + for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4) + iwl_write_restricted_mem(priv, a, 0); + + iwl_write_restricted_reg(priv, SCD_DRAM_BASE_ADDR, + (priv->hw_setting.shared_phys + + offsetof(struct iwl_shared, queues_byte_cnt_tbls)) >> 10); + iwl_write_restricted_reg(priv, SCD_QUEUECHAIN_SEL, 0); + + /* initiate the queues */ + for (i = 0; i < priv->hw_setting.max_txq_num; i++) { + iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(i), 0); + iwl_write_restricted(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); + iwl_write_restricted_mem(priv, priv->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(i), + (SCD_WIN_SIZE << + SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & + SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); + iwl_write_restricted_mem(priv, priv->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(i) + + sizeof(u32), + (SCD_FRAME_LIMIT << + SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); + + } + iwl_write_restricted_reg(priv, SCD_INTERRUPT_MASK, + (1 << priv->hw_setting.max_txq_num) - 1); + + iwl_write_restricted_reg(priv, SCD_TXFACT, + SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); + + iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* map qos queues to fifos one-to-one */ + for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { + int ac = default_queue_to_tx_fifo[i]; + iwl4965_txq_ctx_activate(priv, i); + iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); + } + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +int iwl_hw_set_hw_setting(struct iwl_priv *priv) +{ + priv->hw_setting.shared_virt = + pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl_shared), + &priv->hw_setting.shared_phys); + + if (!priv->hw_setting.shared_virt) + return -1; + + memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl_shared)); + + priv->hw_setting.max_txq_num = iwl_param_queues_num; + priv->hw_setting.ac_queue_count = AC_NUM; + + priv->hw_setting.cck_flag = RATE_MCS_CCK_MSK; + priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd); + priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE; + priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; + + priv->hw_setting.max_stations = IWL4965_STATION_COUNT; + priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID; + return 0; +} + +/** + * iwl_hw_txq_ctx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +{ + int txq_id; + + /* Tx queues */ + for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) + iwl_tx_queue_free(priv, &priv->txq[txq_id]); + + iwl4965_kw_free(priv); +} + +/** + * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used] + * + * Does NOT advance any indexes + */ +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; + struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used]; + struct pci_dev *dev = priv->pci_dev; + int i; + int counter = 0; + int index, is_odd; + + /* classify bd */ + if (txq->q.id == IWL_CMD_QUEUE_NUM) + /* nothing to cleanup after for host commands */ + return 0; + + /* sanity check */ + counter = IWL_GET_BITS(*bd, num_tbs); + if (counter > MAX_NUM_OF_TBS) { + IWL_ERROR("Too many chunks: %i\n", counter); + /* @todo issue fatal error, it is quite serious situation */ + return 0; + } + + /* unmap chunks if any */ + + for (i = 0; i < counter; i++) { + index = i / 2; + is_odd = i & 0x1; + + if (is_odd) + pci_unmap_single( + dev, + IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | + (IWL_GET_BITS(bd->pa[index], + tb2_addr_hi20) << 16), + IWL_GET_BITS(bd->pa[index], tb2_len), + PCI_DMA_TODEVICE); + + else if (i > 0) + pci_unmap_single(dev, + le32_to_cpu(bd->pa[index].tb1_addr), + IWL_GET_BITS(bd->pa[index], tb1_len), + PCI_DMA_TODEVICE); + + if (txq->txb[txq->q.last_used].skb[i]) { + struct sk_buff *skb = txq->txb[txq->q.last_used].skb[i]; + + dev_kfree_skb(skb); + txq->txb[txq->q.last_used].skb[i] = NULL; + } + } + return 0; +} + +int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) +{ + IWL_ERROR("TODO: Implement iwl_hw_reg_set_txpower!\n"); + return -EINVAL; +} + +static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res) +{ + s32 sign = 1; + + if (num < 0) { + sign = -sign; + num = -num; + } + if (denom < 0) { + sign = -sign; + denom = -denom; + } + *res = 1; + *res = ((num * 2 + denom) / (denom * 2)) * sign; + + return 1; +} + +static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, + s32 current_voltage) +{ + s32 comp = 0; + + if ((TX_POWER_IWL_ILLEGAL_VOLTAGE == eeprom_voltage) || + (TX_POWER_IWL_ILLEGAL_VOLTAGE == current_voltage)) + return 0; + + iwl4965_math_div_round(current_voltage - eeprom_voltage, + TX_POWER_IWL_VOLTAGE_CODES_PER_03V, &comp); + + if (current_voltage > eeprom_voltage) + comp *= 2; + if ((comp < -2) || (comp > 2)) + comp = 0; + + return comp; +} + +static const struct iwl_channel_info * +iwl4965_get_channel_txpower_info(struct iwl_priv *priv, u8 phymode, u16 channel) +{ + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, phymode, channel); + + if (!is_channel_valid(ch_info)) + return NULL; + + return ch_info; +} + +static s32 iwl4965_get_tx_atten_grp(u16 channel) +{ + if (channel >= CALIB_IWL_TX_ATTEN_GR5_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR5_LCH) + return CALIB_CH_GROUP_5; + + if (channel >= CALIB_IWL_TX_ATTEN_GR1_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR1_LCH) + return CALIB_CH_GROUP_1; + + if (channel >= CALIB_IWL_TX_ATTEN_GR2_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR2_LCH) + return CALIB_CH_GROUP_2; + + if (channel >= CALIB_IWL_TX_ATTEN_GR3_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR3_LCH) + return CALIB_CH_GROUP_3; + + if (channel >= CALIB_IWL_TX_ATTEN_GR4_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR4_LCH) + return CALIB_CH_GROUP_4; + + IWL_ERROR("Can't find txatten group for channel %d.\n", channel); + return -1; +} + +static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel) +{ + s32 b = -1; + + for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) { + if (priv->eeprom.calib_info.band_info[b].ch_from == 0) + continue; + + if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from) + && (channel <= priv->eeprom.calib_info.band_info[b].ch_to)) + break; + } + + return b; +} + +static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) +{ + s32 val; + + if (x2 == x1) + return y1; + else { + iwl4965_math_div_round((x2 - x) * (y1 - y2), (x2 - x1), &val); + return val + y2; + } +} + +static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, + struct iwl_eeprom_calib_ch_info *chan_info) +{ + s32 s = -1; + u32 c; + u32 m; + const struct iwl_eeprom_calib_measure *m1; + const struct iwl_eeprom_calib_measure *m2; + struct iwl_eeprom_calib_measure *omeas; + u32 ch_i1; + u32 ch_i2; + + s = iwl4965_get_sub_band(priv, channel); + if (s >= EEPROM_TX_POWER_BANDS) { + IWL_ERROR("Tx Power can not find channel %d ", channel); + return -1; + } + + ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num; + ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num; + chan_info->ch_num = (u8) channel; + + IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n", + channel, s, ch_i1, ch_i2); + + for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) { + for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) { + m1 = &(priv->eeprom.calib_info.band_info[s].ch1. + measurements[c][m]); + m2 = &(priv->eeprom.calib_info.band_info[s].ch2. + measurements[c][m]); + omeas = &(chan_info->measurements[c][m]); + + omeas->actual_pow = + (u8) iwl4965_interpolate_value(channel, ch_i1, + m1->actual_pow, + ch_i2, + m2->actual_pow); + omeas->gain_idx = + (u8) iwl4965_interpolate_value(channel, ch_i1, + m1->gain_idx, ch_i2, + m2->gain_idx); + omeas->temperature = + (u8) iwl4965_interpolate_value(channel, ch_i1, + m1->temperature, + ch_i2, + m2->temperature); + omeas->pa_det = + (s8) iwl4965_interpolate_value(channel, ch_i1, + m1->pa_det, ch_i2, + m2->pa_det); + + IWL_DEBUG_TXPOWER + ("chain %d meas %d AP1=%d AP2=%d AP=%d\n", c, m, + m1->actual_pow, m2->actual_pow, omeas->actual_pow); + IWL_DEBUG_TXPOWER + ("chain %d meas %d NI1=%d NI2=%d NI=%d\n", c, m, + m1->gain_idx, m2->gain_idx, omeas->gain_idx); + IWL_DEBUG_TXPOWER + ("chain %d meas %d PA1=%d PA2=%d PA=%d\n", c, m, + m1->pa_det, m2->pa_det, omeas->pa_det); + IWL_DEBUG_TXPOWER + ("chain %d meas %d T1=%d T2=%d T=%d\n", c, m, + m1->temperature, m2->temperature, + omeas->temperature); + } + } + + return 0; +} + +/* bit-rate-dependent table to prevent Tx distortion, in half-dB units, + * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates. */ +static s32 back_off_table[] = { + 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 20 MHz */ + 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 20 MHz */ + 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 40 MHz */ + 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 40 MHz */ + 10 /* CCK */ +}; + +/* Thermal compensation values for txpower for various frequency ranges ... + * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */ +static struct iwl_txpower_comp_entry { + s32 degrees_per_05db_a; + s32 degrees_per_05db_a_denom; +} tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = { + {9, 2}, /* group 0 5.2, ch 34-43 */ + {4, 1}, /* group 1 5.2, ch 44-70 */ + {4, 1}, /* group 2 5.2, ch 71-124 */ + {4, 1}, /* group 3 5.2, ch 125-200 */ + {3, 1} /* group 4 2.4, ch all */ +}; + +static s32 get_min_power_index(s32 rate_power_index, u32 band) +{ + if (!band) { + if ((rate_power_index & 7) <= 4) + return MIN_TX_GAIN_INDEX_52GHZ_EXT; + } + return MIN_TX_GAIN_INDEX; +} + +struct gain_entry { + u8 dsp; + u8 radio; +}; + +static const struct gain_entry gain_table[2][108] = { + /* 5.2GHz power gain index table */ + { + {123, 0x3F}, /* highest txpower */ + {117, 0x3F}, + {110, 0x3F}, + {104, 0x3F}, + {98, 0x3F}, + {110, 0x3E}, + {104, 0x3E}, + {98, 0x3E}, + {110, 0x3D}, + {104, 0x3D}, + {98, 0x3D}, + {110, 0x3C}, + {104, 0x3C}, + {98, 0x3C}, + {110, 0x3B}, + {104, 0x3B}, + {98, 0x3B}, + {110, 0x3A}, + {104, 0x3A}, + {98, 0x3A}, + {110, 0x39}, + {104, 0x39}, + {98, 0x39}, + {110, 0x38}, + {104, 0x38}, + {98, 0x38}, + {110, 0x37}, + {104, 0x37}, + {98, 0x37}, + {110, 0x36}, + {104, 0x36}, + {98, 0x36}, + {110, 0x35}, + {104, 0x35}, + {98, 0x35}, + {110, 0x34}, + {104, 0x34}, + {98, 0x34}, + {110, 0x33}, + {104, 0x33}, + {98, 0x33}, + {110, 0x32}, + {104, 0x32}, + {98, 0x32}, + {110, 0x31}, + {104, 0x31}, + {98, 0x31}, + {110, 0x30}, + {104, 0x30}, + {98, 0x30}, + {110, 0x25}, + {104, 0x25}, + {98, 0x25}, + {110, 0x24}, + {104, 0x24}, + {98, 0x24}, + {110, 0x23}, + {104, 0x23}, + {98, 0x23}, + {110, 0x22}, + {104, 0x18}, + {98, 0x18}, + {110, 0x17}, + {104, 0x17}, + {98, 0x17}, + {110, 0x16}, + {104, 0x16}, + {98, 0x16}, + {110, 0x15}, + {104, 0x15}, + {98, 0x15}, + {110, 0x14}, + {104, 0x14}, + {98, 0x14}, + {110, 0x13}, + {104, 0x13}, + {98, 0x13}, + {110, 0x12}, + {104, 0x08}, + {98, 0x08}, + {110, 0x07}, + {104, 0x07}, + {98, 0x07}, + {110, 0x06}, + {104, 0x06}, + {98, 0x06}, + {110, 0x05}, + {104, 0x05}, + {98, 0x05}, + {110, 0x04}, + {104, 0x04}, + {98, 0x04}, + {110, 0x03}, + {104, 0x03}, + {98, 0x03}, + {110, 0x02}, + {104, 0x02}, + {98, 0x02}, + {110, 0x01}, + {104, 0x01}, + {98, 0x01}, + {110, 0x00}, + {104, 0x00}, + {98, 0x00}, + {93, 0x00}, + {88, 0x00}, + {83, 0x00}, + {78, 0x00}, + }, + /* 2.4GHz power gain index table */ + { + {110, 0x3f}, /* highest txpower */ + {104, 0x3f}, + {98, 0x3f}, + {110, 0x3e}, + {104, 0x3e}, + {98, 0x3e}, + {110, 0x3d}, + {104, 0x3d}, + {98, 0x3d}, + {110, 0x3c}, + {104, 0x3c}, + {98, 0x3c}, + {110, 0x3b}, + {104, 0x3b}, + {98, 0x3b}, + {110, 0x3a}, + {104, 0x3a}, + {98, 0x3a}, + {110, 0x39}, + {104, 0x39}, + {98, 0x39}, + {110, 0x38}, + {104, 0x38}, + {98, 0x38}, + {110, 0x37}, + {104, 0x37}, + {98, 0x37}, + {110, 0x36}, + {104, 0x36}, + {98, 0x36}, + {110, 0x35}, + {104, 0x35}, + {98, 0x35}, + {110, 0x34}, + {104, 0x34}, + {98, 0x34}, + {110, 0x33}, + {104, 0x33}, + {98, 0x33}, + {110, 0x32}, + {104, 0x32}, + {98, 0x32}, + {110, 0x31}, + {104, 0x31}, + {98, 0x31}, + {110, 0x30}, + {104, 0x30}, + {98, 0x30}, + {110, 0x6}, + {104, 0x6}, + {98, 0x6}, + {110, 0x5}, + {104, 0x5}, + {98, 0x5}, + {110, 0x4}, + {104, 0x4}, + {98, 0x4}, + {110, 0x3}, + {104, 0x3}, + {98, 0x3}, + {110, 0x2}, + {104, 0x2}, + {98, 0x2}, + {110, 0x1}, + {104, 0x1}, + {98, 0x1}, + {110, 0x0}, + {104, 0x0}, + {98, 0x0}, + {97, 0}, + {96, 0}, + {95, 0}, + {94, 0}, + {93, 0}, + {92, 0}, + {91, 0}, + {90, 0}, + {89, 0}, + {88, 0}, + {87, 0}, + {86, 0}, + {85, 0}, + {84, 0}, + {83, 0}, + {82, 0}, + {81, 0}, + {80, 0}, + {79, 0}, + {78, 0}, + {77, 0}, + {76, 0}, + {75, 0}, + {74, 0}, + {73, 0}, + {72, 0}, + {71, 0}, + {70, 0}, + {69, 0}, + {68, 0}, + {67, 0}, + {66, 0}, + {65, 0}, + {64, 0}, + {63, 0}, + {62, 0}, + {61, 0}, + {60, 0}, + {59, 0}, + } +}; + +static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, + u8 is_fat, u8 ctrl_chan_high, + struct iwl_tx_power_db *tx_power_tbl) +{ + u8 saturation_power; + s32 target_power; + s32 user_target_power; + s32 power_limit; + s32 current_temp; + s32 reg_limit; + s32 current_regulatory; + s32 txatten_grp = CALIB_CH_GROUP_MAX; + int i; + int c; + const struct iwl_channel_info *ch_info = NULL; + struct iwl_eeprom_calib_ch_info ch_eeprom_info; + const struct iwl_eeprom_calib_measure *measurement; + s16 voltage; + s32 init_voltage; + s32 voltage_compensation; + s32 degrees_per_05db_num; + s32 degrees_per_05db_denom; + s32 factory_temp; + s32 temperature_comp[2]; + s32 factory_gain_index[2]; + s32 factory_actual_pwr[2]; + s32 power_index; + + /* Sanity check requested level (dBm) */ + if (priv->user_txpower_limit < IWL_TX_POWER_TARGET_POWER_MIN) { + IWL_WARNING("Requested user TXPOWER %d below limit.\n", + priv->user_txpower_limit); + return -EINVAL; + } + if (priv->user_txpower_limit > IWL_TX_POWER_TARGET_POWER_MAX) { + IWL_WARNING("Requested user TXPOWER %d above limit.\n", + priv->user_txpower_limit); + return -EINVAL; + } + + /* user_txpower_limit is in dBm, convert to half-dBm (half-dB units + * are used for indexing into txpower table) */ + user_target_power = 2 * priv->user_txpower_limit; + + /* Get current (RXON) channel, band, width */ + ch_info = + iwl4965_get_channel_txpower_info(priv, priv->phymode, channel); + + IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band, + is_fat); + + if (!ch_info) + return -EINVAL; + + /* get txatten group, used to select 1) thermal txpower adjustment + * and 2) mimo txpower balance between Tx chains. */ + txatten_grp = iwl4965_get_tx_atten_grp(channel); + if (txatten_grp < 0) + return -EINVAL; + + IWL_DEBUG_TXPOWER("channel %d belongs to txatten group %d\n", + channel, txatten_grp); + + if (is_fat) { + if (ctrl_chan_high) + channel -= 2; + else + channel += 2; + } + + /* hardware txpower limits ... + * saturation (clipping distortion) txpowers are in half-dBm */ + if (band) + saturation_power = priv->eeprom.calib_info.saturation_power24; + else + saturation_power = priv->eeprom.calib_info.saturation_power52; + + if (saturation_power < IWL_TX_POWER_SATURATION_MIN || + saturation_power > IWL_TX_POWER_SATURATION_MAX) { + if (band) + saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_24; + else + saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_52; + } + + /* 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; + else + reg_limit = ch_info->max_power_avg * 2; + + if ((reg_limit < IWL_TX_POWER_REGULATORY_MIN) || + (reg_limit > IWL_TX_POWER_REGULATORY_MAX)) { + if (band) + reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_24; + else + reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_52; + } + + /* Interpolate txpower calibration values for this channel, + * based on factory calibration tests on spaced channels. */ + iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info); + + /* calculate tx gain adjustment based on power supply voltage */ + voltage = priv->eeprom.calib_info.voltage; + init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage); + voltage_compensation = + iwl4965_get_voltage_compensation(voltage, init_voltage); + + IWL_DEBUG_TXPOWER("curr volt %d eeprom volt %d volt comp %d\n", + init_voltage, + voltage, voltage_compensation); + + /* get current temperature (Celsius) */ + current_temp = max(priv->temperature, IWL_TX_POWER_TEMPERATURE_MIN); + current_temp = min(priv->temperature, IWL_TX_POWER_TEMPERATURE_MAX); + current_temp = KELVIN_TO_CELSIUS(current_temp); + + /* select thermal txpower adjustment params, based on channel group + * (same frequency group used for mimo txatten adjustment) */ + degrees_per_05db_num = + tx_power_cmp_tble[txatten_grp].degrees_per_05db_a; + degrees_per_05db_denom = + tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom; + + /* get per-chain txpower values from factory measurements */ + for (c = 0; c < 2; c++) { + measurement = &ch_eeprom_info.measurements[c][1]; + + /* txgain adjustment (in half-dB steps) based on difference + * between factory and current temperature */ + factory_temp = measurement->temperature; + iwl4965_math_div_round((current_temp - factory_temp) * + degrees_per_05db_denom, + degrees_per_05db_num, + &temperature_comp[c]); + + factory_gain_index[c] = measurement->gain_idx; + factory_actual_pwr[c] = measurement->actual_pow; + + IWL_DEBUG_TXPOWER("chain = %d\n", c); + IWL_DEBUG_TXPOWER("fctry tmp %d, " + "curr tmp %d, comp %d steps\n", + factory_temp, current_temp, + temperature_comp[c]); + + IWL_DEBUG_TXPOWER("fctry idx %d, fctry pwr %d\n", + factory_gain_index[c], + factory_actual_pwr[c]); + } + + /* for each of 33 bit-rates (including 1 for CCK) */ + for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) { + u8 is_mimo_rate; + union iwl_tx_power_dual_stream tx_power; + + /* for mimo, reduce each chain's txpower by half + * (3dB, 6 steps), so total output power is regulatory + * compliant. */ + if (i & 0x8) { + current_regulatory = reg_limit - + IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION; + is_mimo_rate = 1; + } else { + current_regulatory = reg_limit; + is_mimo_rate = 0; + } + + /* find txpower limit, either hardware or regulatory */ + power_limit = saturation_power - back_off_table[i]; + if (power_limit > current_regulatory) + power_limit = current_regulatory; + + /* reduce user's txpower request if necessary + * for this rate on this channel */ + target_power = user_target_power; + if (target_power > power_limit) + target_power = power_limit; + + IWL_DEBUG_TXPOWER("rate %d sat %d reg %d usr %d tgt %d\n", + i, saturation_power - back_off_table[i], + current_regulatory, user_target_power, + target_power); + + /* for each of 2 Tx chains (radio transmitters) */ + for (c = 0; c < 2; c++) { + s32 atten_value; + + if (is_mimo_rate) + atten_value = + (s32)le32_to_cpu(priv->card_alive_init. + tx_atten[txatten_grp][c]); + else + atten_value = 0; + + /* calculate index; higher index means lower txpower */ + power_index = (u8) (factory_gain_index[c] - + (target_power - + factory_actual_pwr[c]) - + temperature_comp[c] - + voltage_compensation + + atten_value); + +/* IWL_DEBUG_TXPOWER("calculated txpower index %d\n", + power_index); */ + + if (power_index < get_min_power_index(i, band)) + power_index = get_min_power_index(i, band); + + /* adjust 5 GHz index to support negative indexes */ + if (!band) + power_index += 9; + + /* CCK, rate 32, reduce txpower for CCK */ + if (i == POWER_TABLE_CCK_ENTRY) + power_index += + IWL_TX_POWER_CCK_COMPENSATION_C_STEP; + + /* stay within the table! */ + if (power_index > 107) { + IWL_WARNING("txpower index %d > 107\n", + power_index); + power_index = 107; + } + if (power_index < 0) { + IWL_WARNING("txpower index %d < 0\n", + power_index); + power_index = 0; + } + + /* fill txpower command for this rate/chain */ + tx_power.s.radio_tx_gain[c] = + gain_table[band][power_index].radio; + tx_power.s.dsp_predis_atten[c] = + gain_table[band][power_index].dsp; + + IWL_DEBUG_TXPOWER("chain %d mimo %d index %d " + "gain 0x%02x dsp %d\n", + c, atten_value, power_index, + tx_power.s.radio_tx_gain[c], + tx_power.s.dsp_predis_atten[c]); + }/* for each chain */ + + tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw); + + }/* for each rate */ + + return 0; +} + +/** + * iwl_hw_reg_send_txpower - Configure the TXPOWER level user limit + * + * Uses the active RXON for channel, band, and characteristics (fat, high) + * The power limit is taken from priv->user_txpower_limit. + */ +int iwl_hw_reg_send_txpower(struct iwl_priv *priv) +{ + struct iwl_txpowertable_cmd cmd = { 0 }; + int rc = 0; + u8 band = 0; + u8 is_fat = 0; + u8 ctrl_chan_high = 0; + + if (test_bit(STATUS_SCANNING, &priv->status)) { + /* If this gets hit a lot, switch it to a BUG() and catch + * the stack trace to find out who is calling this during + * a scan. */ + IWL_WARNING("TX Power requested while scanning!\n"); + return -EAGAIN; + } + + band = ((priv->phymode == MODE_IEEE80211B) || + (priv->phymode == MODE_IEEE80211G)); + + is_fat = is_fat_channel(priv->active_rxon.flags); + + if (is_fat && + (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) + ctrl_chan_high = 1; + + cmd.band = band; + cmd.channel = priv->active_rxon.channel; + + rc = iwl4965_fill_txpower_tbl(priv, band, + le16_to_cpu(priv->active_rxon.channel), + is_fat, ctrl_chan_high, &cmd.tx_power); + if (rc) + return rc; + + rc = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); + return rc; +} + +int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) +{ + int rc; + u8 band = 0; + u8 is_fat = 0; + u8 ctrl_chan_high = 0; + struct iwl_channel_switch_cmd cmd = { 0 }; + const struct iwl_channel_info *ch_info; + + band = ((priv->phymode == MODE_IEEE80211B) || + (priv->phymode == MODE_IEEE80211G)); + + ch_info = iwl_get_channel_info(priv, priv->phymode, channel); + + is_fat = is_fat_channel(priv->staging_rxon.flags); + + if (is_fat && + (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) + ctrl_chan_high = 1; + + cmd.band = band; + cmd.expect_beacon = 0; + cmd.channel = cpu_to_le16(channel); + cmd.rxon_flags = priv->active_rxon.flags; + cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else + cmd.expect_beacon = 1; + + rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat, + ctrl_chan_high, &cmd.tx_power); + if (rc) { + IWL_DEBUG_11H("error:%d fill txpower_tbl\n", rc); + return rc; + } + + rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); + return rc; +} + +#define RTS_HCCA_RETRY_LIMIT 3 +#define RTS_DFAULT_RETRY_LIMIT 60 + +void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, int sta_id, + int is_hcca) +{ + u8 rate; + u8 rts_retry_limit = 0; + u8 data_retry_limit = 0; + __le32 tx_flags; + u16 fc = le16_to_cpu(hdr->frame_control); + + tx_flags = cmd->cmd.tx.tx_flags; + + rate = iwl_rates[ctrl->tx_rate].plcp; + + rts_retry_limit = (is_hcca) ? + RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; + + if (ieee80211_is_probe_response(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; + + if (priv->data_retry_limit != -1) + data_retry_limit = priv->data_retry_limit; + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + if (tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; + } + } + + cmd->cmd.tx.rts_retry_limit = rts_retry_limit; + cmd->cmd.tx.data_retry_limit = data_retry_limit; + cmd->cmd.tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, 0); + cmd->cmd.tx.tx_flags = tx_flags; +} + +int iwl_hw_get_rx_read(struct iwl_priv *priv) +{ + struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + + return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num); +} + +int iwl_hw_get_temperature(struct iwl_priv *priv) +{ + return priv->temperature; +} + +unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl_frame *frame, u8 rate) +{ + struct iwl_tx_beacon_cmd *tx_beacon_cmd; + unsigned int frame_size; + + tx_beacon_cmd = &frame->u.beacon; + memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + + tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID; + tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + frame_size = iwl_fill_beacon_frame(priv, + tx_beacon_cmd->frame, + BROADCAST_ADDR, + sizeof(frame->u) - sizeof(*tx_beacon_cmd)); + + BUG_ON(frame_size > MAX_MPDU_SIZE); + tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); + + if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); + else + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, 0); + + tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK | + TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK); + return (sizeof(*tx_beacon_cmd) + frame_size); +} + +int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + int rc; + unsigned long flags; + int txq_id = txq->q.id; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl_write_restricted(priv, FH_MEM_CBBC_QUEUE(txq_id), + txq->q.dma_addr >> 8); + iwl_write_restricted( + priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), + IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr) +{ + return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; +} + +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, + dma_addr_t addr, u16 len) +{ + int index, is_odd; + struct iwl_tfd_frame *tfd = ptr; + u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + + if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { + IWL_ERROR("Error can not send more than %d chunks\n", + MAX_NUM_OF_TBS); + return -EINVAL; + } + + index = num_tbs / 2; + is_odd = num_tbs & 0x1; + + if (!is_odd) { + tfd->pa[index].tb1_addr = cpu_to_le32(addr); + IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, + iwl4965_get_dma_hi_address(addr)); + IWL_SET_BITS(tfd->pa[index], tb1_len, len); + } else { + IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, + (u32) (addr & 0xffff)); + IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); + IWL_SET_BITS(tfd->pa[index], tb2_len, len); + } + + IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + + return 0; +} + +void iwl_hw_card_show_info(struct iwl_priv *priv) +{ + u16 hw_version = priv->eeprom.board_revision_4965; + + IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n", + ((hw_version >> 8) & 0x0F), + ((hw_version >> 8) >> 4), (hw_version & 0x00FF)); + + IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n", + priv->eeprom.board_pba_number_4965); +} + +#define IWL_TX_CRC_SIZE 4 +#define IWL_TX_DELIMITER_SIZE 4 + +int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq, u16 byte_cnt) +{ + int len; + int txq_id = txq->q.id; + struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + + if (txq->need_update == 0) + return 0; + + len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[txq->q.first_empty], byte_cnt, len); + + if (txq->q.first_empty < IWL4965_MAX_WIN_SIZE) + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[IWL4965_QUEUE_SIZE + txq->q.first_empty], + byte_cnt, len); + + return 0; +} + +/* Set up Rx receiver/antenna/chain usage in "staging" RXON image. + * This should not be used for scan command ... it puts data in wrong place. */ +void iwl4965_set_rxon_chain(struct iwl_priv *priv) +{ + u8 is_single = is_single_stream(priv); + u8 idle_state, rx_state; + + priv->staging_rxon.rx_chain = 0; + rx_state = idle_state = 3; + + /* Tell uCode which antennas are actually connected. + * Before first association, we assume all antennas are connected. + * Just after first association, iwl4965_noise_calibration() + * checks which antennas actually *are* connected. */ + priv->staging_rxon.rx_chain |= + cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS); + + /* How many receivers should we use? */ + iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state); + priv->staging_rxon.rx_chain |= + cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS); + priv->staging_rxon.rx_chain |= + cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); + + if (!is_single && (rx_state >= 2) && + !test_bit(STATUS_POWER_PMI, &priv->status)) + priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; + else + priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; + + IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); +} + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG +/* + get the traffic load value for tid +*/ +static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid) +{ + u32 load = 0; + u32 current_time = jiffies_to_msecs(jiffies); + u32 time_diff; + s32 index; + unsigned long flags; + struct iwl_traffic_load *tid_ptr = NULL; + + if (tid >= TID_MAX_LOAD_COUNT) + return 0; + + tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]); + + current_time -= current_time % TID_ROUND_VALUE; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + if (!(tid_ptr->queue_count)) + goto out; + + time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time); + index = time_diff / TID_QUEUE_CELL_SPACING; + + if (index >= TID_QUEUE_MAX_SIZE) { + u32 oldest_time = current_time - TID_MAX_TIME_DIFF; + + while (tid_ptr->queue_count && + (tid_ptr->time_stamp < oldest_time)) { + tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head]; + tid_ptr->packet_count[tid_ptr->head] = 0; + tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING; + tid_ptr->queue_count--; + tid_ptr->head++; + if (tid_ptr->head >= TID_QUEUE_MAX_SIZE) + tid_ptr->head = 0; + } + } + load = tid_ptr->total; + + out: + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + return load; +} + +/* + increment traffic load value for tid and also remove + any old values if passed the certian time period +*/ +static void iwl4965_tl_add_packet(struct iwl_priv *priv, u8 tid) +{ + u32 current_time = jiffies_to_msecs(jiffies); + u32 time_diff; + s32 index; + unsigned long flags; + struct iwl_traffic_load *tid_ptr = NULL; + + if (tid >= TID_MAX_LOAD_COUNT) + return; + + tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]); + + current_time -= current_time % TID_ROUND_VALUE; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + if (!(tid_ptr->queue_count)) { + tid_ptr->total = 1; + tid_ptr->time_stamp = current_time; + tid_ptr->queue_count = 1; + tid_ptr->head = 0; + tid_ptr->packet_count[0] = 1; + goto out; + } + + time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time); + index = time_diff / TID_QUEUE_CELL_SPACING; + + if (index >= TID_QUEUE_MAX_SIZE) { + u32 oldest_time = current_time - TID_MAX_TIME_DIFF; + + while (tid_ptr->queue_count && + (tid_ptr->time_stamp < oldest_time)) { + tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head]; + tid_ptr->packet_count[tid_ptr->head] = 0; + tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING; + tid_ptr->queue_count--; + tid_ptr->head++; + if (tid_ptr->head >= TID_QUEUE_MAX_SIZE) + tid_ptr->head = 0; + } + } + + index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE; + tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1; + tid_ptr->total = tid_ptr->total + 1; + + if ((index + 1) > tid_ptr->queue_count) + tid_ptr->queue_count = index + 1; + out: + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + +} + +#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS 7 +enum HT_STATUS { + BA_STATUS_FAILURE = 0, + BA_STATUS_INITIATOR_DELBA, + BA_STATUS_RECIPIENT_DELBA, + BA_STATUS_RENEW_ADDBA_REQUEST, + BA_STATUS_ACTIVE, +}; + +static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv) +{ + int i; + struct iwl_lq_mngr *lq; + u8 count = 0; + u16 msk; + + lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) { + msk = 1 << i; + if ((lq->agg_ctrl.granted_ba & msk) || + (lq->agg_ctrl.wait_for_agg_status & msk)) + count++; + } + + if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS) + return 1; + + return 0; +} + +static void iwl4965_ba_status(struct iwl_priv *priv, + u8 tid, enum HT_STATUS status); + +static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length, + u32 ba_timeout) +{ + int rc; + + rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid); + if (rc) + iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE); + + return rc; +} + +static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid) +{ + int rc; + + rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid); + if (rc) + iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE); + + return rc; +} + +static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv, + struct iwl_lq_mngr *lq, + u8 auto_agg, u8 tid) +{ + u32 tid_msk = (1 << tid); + unsigned long flags; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); +/* + if ((auto_agg) && (!lq->enable_counter)){ + lq->agg_ctrl.next_retry = 0; + lq->agg_ctrl.tid_retry = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + return; + } +*/ + if (!(lq->agg_ctrl.granted_ba & tid_msk) && + (lq->agg_ctrl.requested_ba & tid_msk)) { + u8 available_queues; + u32 load; + + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + available_queues = iwl4964_tl_ba_avail(priv); + load = iwl4965_tl_get_load(priv, tid); + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + if (!available_queues) { + if (auto_agg) + lq->agg_ctrl.tid_retry |= tid_msk; + else { + lq->agg_ctrl.requested_ba &= ~tid_msk; + lq->agg_ctrl.wait_for_agg_status &= ~tid_msk; + } + } else if ((auto_agg) && + ((load <= lq->agg_ctrl.tid_traffic_load_threshold) || + ((lq->agg_ctrl.wait_for_agg_status & tid_msk)))) + lq->agg_ctrl.tid_retry |= tid_msk; + else { + lq->agg_ctrl.wait_for_agg_status |= tid_msk; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + iwl4965_perform_addba(priv, tid, 0x40, + lq->agg_ctrl.ba_timeout); + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + } + } + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); +} + +static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid) +{ + struct iwl_lq_mngr *lq; + unsigned long flags; + + lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + + if ((tid < TID_MAX_LOAD_COUNT)) + iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg, + tid); + else if (tid == TID_ALL_SPECIFIED) { + if (lq->agg_ctrl.requested_ba) { + for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) + iwl4965_turn_on_agg_for_tid(priv, lq, + lq->agg_ctrl.auto_agg, tid); + } else { + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + lq->agg_ctrl.tid_retry = 0; + lq->agg_ctrl.next_retry = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + } + } + +} + +void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid) +{ + u32 tid_msk; + struct iwl_lq_mngr *lq; + unsigned long flags; + + lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + + if ((tid < TID_MAX_LOAD_COUNT)) { + tid_msk = 1 << tid; + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + lq->agg_ctrl.wait_for_agg_status |= tid_msk; + lq->agg_ctrl.requested_ba &= ~tid_msk; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + iwl4965_perform_delba(priv, tid); + } else if (tid == TID_ALL_SPECIFIED) { + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) { + tid_msk = 1 << tid; + lq->agg_ctrl.wait_for_agg_status |= tid_msk; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + iwl4965_perform_delba(priv, tid); + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + } + lq->agg_ctrl.requested_ba = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + } +} + +static void iwl4965_ba_status(struct iwl_priv *priv, + u8 tid, enum HT_STATUS status) +{ + struct iwl_lq_mngr *lq; + u32 tid_msk = (1 << tid); + unsigned long flags; + + lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + + if ((tid >= TID_MAX_LOAD_COUNT)) + goto out; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + switch (status) { + case BA_STATUS_ACTIVE: + if (!(lq->agg_ctrl.granted_ba & tid_msk)) + lq->agg_ctrl.granted_ba |= tid_msk; + break; + default: + if ((lq->agg_ctrl.granted_ba & tid_msk)) + lq->agg_ctrl.granted_ba &= ~tid_msk; + break; + } + + lq->agg_ctrl.wait_for_agg_status &= ~tid_msk; + if (status != BA_STATUS_ACTIVE) { + if (lq->agg_ctrl.auto_agg) { + lq->agg_ctrl.tid_retry |= tid_msk; + lq->agg_ctrl.next_retry = + jiffies + msecs_to_jiffies(500); + } else + lq->agg_ctrl.requested_ba &= ~tid_msk; + } + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + out: + return; +} + +static void iwl4965_bg_agg_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + agg_work); + + u32 tid; + u32 retry_tid; + u32 tid_msk; + unsigned long flags; + struct iwl_lq_mngr *lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + retry_tid = lq->agg_ctrl.tid_retry; + lq->agg_ctrl.tid_retry = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + + if (retry_tid == TID_ALL_SPECIFIED) + iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED); + else { + for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) { + tid_msk = (1 << tid); + if (retry_tid & tid_msk) + iwl4965_turn_on_agg(priv, tid); + } + } + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + if (lq->agg_ctrl.tid_retry) + lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500); + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + return; +} +#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + +int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd, + u8 sta_id, dma_addr_t txcmd_phys, + struct ieee80211_hdr *hdr, u8 hdr_len, + struct ieee80211_tx_control *ctrl, void *sta_in) +{ + struct iwl_tx_cmd cmd; + struct iwl_tx_cmd *tx = (struct iwl_tx_cmd *)&out_cmd->cmd.payload[0]; + dma_addr_t scratch_phys; + u8 unicast = 0; + u8 is_data = 1; + u16 fc; + u16 rate_flags; + int rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + __le16 *qc; +#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + + unicast = !is_multicast_ether_addr(hdr->addr1); + + fc = le16_to_cpu(hdr->frame_control); + if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + is_data = 0; + + memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl_tx_cmd)); + memset(tx, 0, sizeof(struct iwl_tx_cmd)); + memcpy(tx->hdr, hdr, hdr_len); + + tx->len = cmd.len; + tx->driver_txop = cmd.driver_txop; + tx->stop_time.life_time = cmd.stop_time.life_time; + tx->tx_flags = cmd.tx_flags; + tx->sta_id = cmd.sta_id; + tx->tid_tspec = cmd.tid_tspec; + tx->timeout.pm_frame_timeout = cmd.timeout.pm_frame_timeout; + tx->next_frame_len = cmd.next_frame_len; + + tx->sec_ctl = cmd.sec_ctl; + memcpy(&(tx->key[0]), &(cmd.key[0]), 16); + tx->tx_flags = cmd.tx_flags; + + tx->rts_retry_limit = cmd.rts_retry_limit; + tx->data_retry_limit = cmd.data_retry_limit; + + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + + offsetof(struct iwl_tx_cmd, scratch); + tx->dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx->dram_msb_ptr = iwl4965_get_dma_hi_address(scratch_phys); + + /* Hard coded to start at the highest retry fallback position + * until the 4965 specific rate control algorithm is tied in */ + tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1; + + /* Alternate between antenna A and B for successive frames */ + if (priv->use_ant_b_for_management_frame) { + priv->use_ant_b_for_management_frame = 0; + rate_flags = RATE_MCS_ANT_B_MSK; + } else { + priv->use_ant_b_for_management_frame = 1; + rate_flags = RATE_MCS_ANT_A_MSK; + } + + if (!unicast || !is_data) { + if ((rate_index >= IWL_FIRST_CCK_RATE) && + (rate_index <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + } else { + tx->initial_rate_index = 0; + tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; + } + + tx->rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[rate_index].plcp, + rate_flags); + + if (ieee80211_is_probe_request(fc)) + tx->tx_flags |= TX_CMD_FLG_TSF_MSK; + else if (ieee80211_is_back_request(fc)) + tx->tx_flags |= TX_CMD_FLG_ACK_MSK | + TX_CMD_FLG_IMM_BA_RSP_MASK; +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + qc = ieee80211_get_qos_ctrl(hdr); + if (qc && + (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) { + u8 tid = 0; + tid = (u8) (le16_to_cpu(*qc) & 0xF); + if (tid < TID_MAX_LOAD_COUNT) + iwl4965_tl_add_packet(priv, tid); + } + + if (priv->lq_mngr.agg_ctrl.next_retry && + (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) { + unsigned long flags; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + priv->lq_mngr.agg_ctrl.next_retry = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + schedule_work(&priv->agg_work); + } +#endif +#endif + return 0; +} + +/** + * sign_extend - Sign extend a value using specified bit as sign-bit + * + * Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1 + * and bit0..2 is 001b which when sign extended to 1111111111111001b is -7. + * + * @param oper value to sign extend + * @param index 0 based bit index (0<=index<32) to sign bit + */ +static s32 sign_extend(u32 oper, int index) +{ + u8 shift = 31 - index; + + return (s32)(oper << shift) >> shift; +} + +/** + * iwl4965_get_temperature - return the calibrated temperature (in Kelvin) + * @statistics: Provides the temperature reading from the uCode + * + * A return of <0 indicates bogus data in the statistics + */ +int iwl4965_get_temperature(const struct iwl_priv *priv) +{ + s32 temperature; + s32 vt; + s32 R1, R2, R3; + u32 R4; + + if (test_bit(STATUS_TEMPERATURE, &priv->status) && + (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) { + IWL_DEBUG_TEMP("Running FAT 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]); + R4 = le32_to_cpu(priv->card_alive_init.therm_r4[1]); + } else { + IWL_DEBUG_TEMP("Running temperature calibration\n"); + R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]); + R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]); + R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]); + R4 = le32_to_cpu(priv->card_alive_init.therm_r4[0]); + } + + /* + * Temperature is only 23 bits so sign extend out to 32 + * + * NOTE If we haven't received a statistics notification yet + * with an updated temperature, use R4 provided to us in the + * ALIVE response. */ + if (!test_bit(STATUS_TEMPERATURE, &priv->status)) + vt = sign_extend(R4, 23); + else + vt = sign_extend( + le32_to_cpu(priv->statistics.general.temperature), 23); + + IWL_DEBUG_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n", + R1, R2, R3, vt); + + if (R3 == R1) { + IWL_ERROR("Calibration conflict R1 == R3\n"); + return -1; + } + + /* Calculate temperature in degrees Kelvin, adjust by 97%. + * Add offset to center the adjustment around 0 degrees Centigrade. */ + temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2); + temperature /= (R3 - R1); + temperature = (temperature * 97) / 100 + + TEMPERATURE_CALIB_KELVIN_OFFSET; + + IWL_DEBUG_TEMP("Calibrated temperature: %dK, %dC\n", temperature, + KELVIN_TO_CELSIUS(temperature)); + + return temperature; +} + +/* Adjust Txpower only if temperature variance is greater than threshold. */ +#define IWL_TEMPERATURE_THRESHOLD 3 + +/** + * iwl4965_is_temp_calib_needed - determines if new calibration is needed + * + * If the temperature changed has changed sufficiently, then a recalibration + * is needed. + * + * Assumes caller will replace priv->last_temperature once calibration + * executed. + */ +static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) +{ + int temp_diff; + + if (!test_bit(STATUS_STATISTICS, &priv->status)) { + IWL_DEBUG_TEMP("Temperature not updated -- no statistics.\n"); + return 0; + } + + temp_diff = priv->temperature - priv->last_temperature; + + /* get absolute value */ + if (temp_diff < 0) { + IWL_DEBUG_POWER("Getting cooler, delta %d, \n", temp_diff); + temp_diff = -temp_diff; + } else if (temp_diff == 0) + IWL_DEBUG_POWER("Same temp, \n"); + else + IWL_DEBUG_POWER("Getting warmer, delta %d, \n", temp_diff); + + if (temp_diff < IWL_TEMPERATURE_THRESHOLD) { + IWL_DEBUG_POWER("Thermal txpower calib not needed\n"); + return 0; + } + + IWL_DEBUG_POWER("Thermal txpower calib needed\n"); + + return 1; +} + +/* Calculate noise level, based on measurements during network silence just + * before arriving beacon. This measurement can be done only if we know + * exactly when to expect beacons, therefore only when we're associated. */ +static void iwl4965_rx_calc_noise(struct iwl_priv *priv) +{ + struct statistics_rx_non_phy *rx_info + = &(priv->statistics.rx.general); + int num_active_rx = 0; + int total_silence = 0; + int bcn_silence_a = + le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; + int bcn_silence_b = + le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; + int bcn_silence_c = + le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; + + if (bcn_silence_a) { + total_silence += bcn_silence_a; + num_active_rx++; + } + if (bcn_silence_b) { + total_silence += bcn_silence_b; + num_active_rx++; + } + if (bcn_silence_c) { + total_silence += bcn_silence_c; + num_active_rx++; + } + + /* Average among active antennas */ + if (num_active_rx) + priv->last_rx_noise = (total_silence / num_active_rx) - 107; + else + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n", + bcn_silence_a, bcn_silence_b, bcn_silence_c, + priv->last_rx_noise); +} + +void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + int change; + s32 temp; + + IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", + (int)sizeof(priv->statistics), pkt->len); + + 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))); + + memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); + + set_bit(STATUS_STATISTICS, &priv->status); + + /* Reschedule the statistics timer to occur in + * REG_RECALIB_PERIOD seconds to ensure we get a + * thermal update even if the uCode doesn't give + * us one */ + mod_timer(&priv->statistics_periodic, jiffies + + msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); + + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { + iwl4965_rx_calc_noise(priv); +#ifdef CONFIG_IWLWIFI_SENSITIVITY + queue_work(priv->workqueue, &priv->sensitivity_work); +#endif + } + + /* If the hardware hasn't reported a change in + * temperature then don't bother computing a + * calibrated temperature value */ + if (!change) + return; + + temp = iwl4965_get_temperature(priv); + if (temp < 0) + return; + + if (priv->temperature != temp) { + if (priv->temperature) + IWL_DEBUG_TEMP("Temperature changed " + "from %dC to %dC\n", + KELVIN_TO_CELSIUS(priv->temperature), + KELVIN_TO_CELSIUS(temp)); + else + IWL_DEBUG_TEMP("Temperature " + "initialized to %dC\n", + KELVIN_TO_CELSIUS(temp)); + } + + priv->temperature = temp; + set_bit(STATUS_TEMPERATURE, &priv->status); + + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + iwl4965_is_temp_calib_needed(priv)) + queue_work(priv->workqueue, &priv->txpower_work); +} + +static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, + int include_phy, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_rx_phy_res *rx_start = (include_phy) ? + (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; + struct ieee80211_hdr *hdr; + u16 len; + __le32 *rx_end; + unsigned int skblen; + u32 ampdu_status; + + if (!include_phy && priv->last_phy_res[0]) + rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + + if (!rx_start) { + IWL_ERROR("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 iwl4965_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); + } + if (len > 2342 || len < 16) { + IWL_DEBUG_DROP("byte count out of range [16,2342]" + " : %d\n", len); + return; + } + + ampdu_status = le32_to_cpu(*rx_end); + skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32); + + /* 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 + ("Dropping packet while interface is not open.\n"); + return; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + if (iwl_param_hwcrypto) + iwl_set_decrypted_flag(priv, rxb->skb, + ampdu_status, stats); + iwl_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0); + return; + } + + stats->flag = 0; + hdr = (struct ieee80211_hdr *)rxb->skb->data; + + if (iwl_param_hwcrypto) + iwl_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats); + + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + priv->alloc_rxb_skb--; + rxb->skb = NULL; +#ifdef LED + priv->led_packets += len; + iwl_setup_activity_timer(priv); +#endif +} + +/* Calc max signal level (dBm) among 3 possible receivers */ +static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp) +{ + /* data from PHY/DSP regarding signal strength, etc., + * contents are always there, not configurable by host. */ + struct iwl4965_rx_non_cfg_phy *ncphy = + (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; + u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) + >> IWL_AGC_DB_POS; + + u32 valid_antennae = + (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) + >> RX_PHY_FLAGS_ANTENNAE_OFFSET; + u8 max_rssi = 0; + u32 i; + + /* Find max rssi among 3 possible receivers. + * These values are measured by the digital signal processor (DSP). + * They should stay fairly constant even as the signal strength varies, + * if the radio's automatic gain control (AGC) is working right. + * AGC value (see below) will provide the "interesting" info. */ + for (i = 0; i < 3; i++) + if (valid_antennae & (1 << i)) + max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); + + IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", + ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], + max_rssi, agc); + + /* dBm = max_rssi dB - agc dB - constant. + * Higher AGC (higher radio gain) means lower signal. */ + return (max_rssi - agc - IWL_RSSI_OFFSET); +} + +#ifdef CONFIG_IWLWIFI_HT + +/* Parsed Information Elements */ +struct ieee802_11_elems { + u8 *ds_params; + u8 ds_params_len; + u8 *tim; + u8 tim_len; + u8 *ibss_params; + u8 ibss_params_len; + u8 *erp_info; + u8 erp_info_len; + u8 *ht_cap_param; + u8 ht_cap_param_len; + u8 *ht_extra_param; + u8 ht_extra_param_len; +}; + +static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems) +{ + size_t left = len; + u8 *pos = start; + int unknown = 0; + + memset(elems, 0, sizeof(*elems)); + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) + return -1; + + switch (id) { + case WLAN_EID_DS_PARAMS: + elems->ds_params = pos; + elems->ds_params_len = elen; + break; + case WLAN_EID_TIM: + elems->tim = pos; + elems->tim_len = elen; + break; + case WLAN_EID_IBSS_PARAMS: + elems->ibss_params = pos; + elems->ibss_params_len = elen; + break; + case WLAN_EID_ERP_INFO: + elems->erp_info = pos; + elems->erp_info_len = elen; + break; + case WLAN_EID_HT_CAPABILITY: + elems->ht_cap_param = pos; + elems->ht_cap_param_len = elen; + break; + case WLAN_EID_HT_EXTRA_INFO: + elems->ht_extra_param = pos; + elems->ht_extra_param_len = elen; + break; + default: + unknown++; + break; + } + + left -= elen; + pos += elen; + } + + return 0; +} +#endif /* CONFIG_IWLWIFI_HT */ + +static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +{ + /* FIXME: need locking over ps_status ??? */ + u8 sta_id = iwl_hw_find_station(priv, addr); + + if (sta_id != IWL_INVALID_STATION) { + u8 sta_awake = priv->stations[sta_id]. + ps_status == STA_PS_STATUS_WAKE; + + if (sta_awake && ps_bit) + priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; + else if (!sta_awake && !ps_bit) { + iwl4965_sta_modify_ps_wake(priv, sta_id); + priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; + } + } +} + +/* Called for REPLY_4965_RX (legacy ABG frames), or + * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ +static void iwl4965_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)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_4965_RX); + struct iwl4965_rx_phy_res *rx_start = (include_phy) ? + (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : + (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + __le32 *rx_end; + unsigned int len = 0; + struct ieee80211_hdr *header; + u16 fc; + struct ieee80211_rx_status stats = { + .mactime = le64_to_cpu(rx_start->timestamp), + .channel = le16_to_cpu(rx_start->channel), + .phymode = + (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + MODE_IEEE80211G : MODE_IEEE80211A, + .antenna = 0, + .rate = iwl_hw_get_rate(rx_start->rate_n_flags), + .flag = 0, +#ifdef CONFIG_IWLWIFI_HT_AGG + .ordered = 0 +#endif /* CONFIG_IWLWIFI_HT_AGG */ + }; + u8 network_packet; + + if ((unlikely(rx_start->cfg_phy_cnt > 20))) { + IWL_DEBUG_DROP + ("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 iwl4965_rx_phy_res *) + &priv->last_phy_res[1]; + else + rx_start = NULL; + } + + if (!rx_start) { + IWL_ERROR("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 iwl4965_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("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); + + stats.freq = ieee80211chan2mhz(stats.channel); + + /* Find max signal strength (dBm) among 3 antenna/receiver chains */ + stats.ssi = iwl4965_calc_rssi(rx_start); + + /* Meaningful noise values are available only from beacon statistics, + * which are gathered only when associated, and indicate noise + * only for the associated network channel ... + * Ignore these noise values while scanning (other channels) */ + if (iwl_is_associated(priv) && + !test_bit(STATUS_SCANNING, &priv->status)) { + stats.noise = priv->last_rx_noise; + stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise); + } else { + stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + stats.signal = iwl_calc_sig_qual(stats.ssi, 0); + } + + /* Reset beacon noise level if not associated. */ + if (!iwl_is_associated(priv)) + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + +#ifdef CONFIG_IWLWIFI_DEBUG + /* TODO: Parts of iwl_report_frame are broken for 4965 */ + if (iwl_debug_level & (IWL_DL_RX)) + /* Set "1" to report good data frames in groups of 100 */ + iwl_report_frame(priv, pkt, header, 1); + + if (iwl_debug_level & (IWL_DL_RX | IWL_DL_STATS)) + IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n", + stats.ssi, stats.noise, stats.signal, + (long unsigned int)le64_to_cpu(rx_start->timestamp)); +#endif + + network_packet = iwl_is_network_packet(priv, header); + if (network_packet) { + priv->last_rx_rssi = stats.ssi; + priv->last_beacon_time = priv->ucode_beacon_time; + priv->last_tsf = le64_to_cpu(rx_start->timestamp); + } + + fc = le16_to_cpu(header->frame_control); + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_MGMT: + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, + header->addr2); + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_RESP: + case IEEE80211_STYPE_BEACON: + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA && + !compare_ether_addr(header->addr2, priv->bssid)) || + (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + !compare_ether_addr(header->addr3, priv->bssid))) { + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *)header; + u64 timestamp = + le64_to_cpu(mgmt->u.beacon.timestamp); + + priv->timestamp0 = timestamp & 0xFFFFFFFF; + priv->timestamp1 = + (timestamp >> 32) & 0xFFFFFFFF; + priv->beacon_int = le16_to_cpu( + mgmt->u.beacon.beacon_int); + if (priv->call_post_assoc_from_beacon && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { + priv->call_post_assoc_from_beacon = 0; + queue_work(priv->workqueue, + &priv->post_associate.work); + } + } + break; + + case IEEE80211_STYPE_ACTION: + break; + + /* + * TODO: There is no callback function from upper + * stack to inform us when associated status. this + * work around to sniff assoc_resp management frame + * and finish the association process. + */ + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: + if (network_packet && iwl_is_associated(priv)) { +#ifdef CONFIG_IWLWIFI_HT + u8 *pos = NULL; + struct ieee802_11_elems elems; +#endif /*CONFIG_IWLWIFI_HT */ + struct ieee80211_mgmt *mgnt = + (struct ieee80211_mgmt *)header; + + priv->assoc_id = (~((1 << 15) | (1 << 14)) + & le16_to_cpu(mgnt->u.assoc_resp.aid)); + priv->assoc_capability = + le16_to_cpu( + mgnt->u.assoc_resp.capab_info); +#ifdef CONFIG_IWLWIFI_HT + pos = mgnt->u.assoc_resp.variable; + if (!parse_elems(pos, + len - (pos - (u8 *) mgnt), + &elems)) { + if (elems.ht_extra_param && + elems.ht_cap_param) + break; + } +#endif /*CONFIG_IWLWIFI_HT */ + /* assoc_id is 0 no association */ + if (!priv->assoc_id) + break; + if (priv->beacon_int) + queue_work(priv->workqueue, + &priv->post_associate.work); + else + priv->call_post_assoc_from_beacon = 1; + } + + break; + + case IEEE80211_STYPE_PROBE_REQ: + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !iwl_is_associated(priv)) { + IWL_DEBUG_DROP("Dropping (non network): " + MAC_FMT ", " MAC_FMT ", " + MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + return; + } + } + iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats); + break; + + case IEEE80211_FTYPE_CTL: +#ifdef CONFIG_IWLWIFI_HT_AGG + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_BACK_REQ: + IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); + iwl4965_handle_data_packet(priv, 0, include_phy, + rxb, &stats); + break; + default: + break; + } +#endif + + break; + + case IEEE80211_FTYPE_DATA: + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, + header->addr2); + + if (unlikely(!network_packet)) + IWL_DEBUG_DROP("Dropping (non network): " + MAC_FMT ", " MAC_FMT ", " + MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + else if (unlikely(is_duplicate_packet(priv, header))) + IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", " + MAC_FMT ", " MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + else + iwl4965_handle_data_packet(priv, 1, include_phy, rxb, + &stats); + break; + default: + break; + + } +} + +/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). + * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ +static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + priv->last_phy_res[0] = 1; + memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), + sizeof(struct iwl4965_rx_phy_res)); +} + +static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) + +{ +#ifdef CONFIG_IWLWIFI_SENSITIVITY + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_missed_beacon_notif *missed_beacon; + + missed_beacon = &pkt->u.missed_beacon; + if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { + IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n", + le32_to_cpu(missed_beacon->consequtive_missed_beacons), + le32_to_cpu(missed_beacon->total_missed_becons), + le32_to_cpu(missed_beacon->num_recvd_beacons), + le32_to_cpu(missed_beacon->num_expected_beacons)); + priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status))) + queue_work(priv->workqueue, &priv->sensitivity_work); + } +#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ +} + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + +static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx, + u32 status, u32 retry_count, u32 rate) +{ + struct ieee80211_tx_status *tx_status = + &(priv->txq[txq_id].txb[idx].status); + + tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0; + tx_status->retry_count += retry_count; + tx_status->control.tx_rate = rate; +} + + +static void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, + int sta_id, int tid) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; + priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + + +static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl_compressed_ba_resp* + ba_resp) + +{ + int i, sh, ack; + u16 ba_seq_ctl = le16_to_cpu(ba_resp->ba_seq_ctl); + u32 bitmap0, bitmap1; + u32 resp_bitmap0 = le32_to_cpu(ba_resp->ba_bitmap0); + u32 resp_bitmap1 = le32_to_cpu(ba_resp->ba_bitmap1); + + if (unlikely(!agg->wait_for_ba)) { + IWL_ERROR("Received BA when not expected\n"); + return -EINVAL; + } + agg->wait_for_ba = 0; + IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl); + sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4); + if (sh < 0) /* tbw something is wrong with indeces */ + sh += 0x100; + + /* don't use 64 bits for now */ + bitmap0 = resp_bitmap0 >> sh; + bitmap1 = resp_bitmap1 >> sh; + bitmap0 |= (resp_bitmap1 & ((1<frame_count > (64 - sh)) { + IWL_DEBUG_TX_REPLY("more frames than bitmap size"); + return -1; + } + + /* check for success or failure according to the + * transmitted bitmap and back bitmap */ + bitmap0 &= agg->bitmap0; + bitmap1 &= agg->bitmap1; + + for (i = 0; i < agg->frame_count ; i++) { + int idx = (agg->start_idx + i) & 0xff; + ack = bitmap0 & (1 << i); + IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", + ack? "ACK":"NACK", i, idx, agg->start_idx + i); + iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0, + agg->rate_n_flags); + + } + + IWL_DEBUG_TX_REPLY("Bitmap %x%x\n", bitmap0, bitmap1); + + return 0; +} + +static inline int iwl_queue_dec_wrap(int index, int n_bd) +{ + return (index == 0) ? n_bd - 1 : index - 1; +} + +static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; + int index; + struct iwl_tx_queue *txq = NULL; + struct iwl_ht_agg *agg; + u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow); + u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); + + if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) { + IWL_ERROR("BUG_ON scd_flow is bigger than number of queues"); + return; + } + + txq = &priv->txq[ba_resp_scd_flow]; + agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; + index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); + + /* TODO: Need to get this copy more sefely - now good for debug */ +/* + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from " MAC_FMT ", + sta_id = %d\n", + agg->wait_for_ba, + MAC_ARG((u8*) &ba_resp->sta_addr_lo32), + ba_resp->sta_id); + IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = " + "%d, scd_ssn = %d\n", + ba_resp->tid, + ba_resp->ba_seq_ctl, + ba_resp->ba_bitmap1, + ba_resp->ba_bitmap0, + ba_resp->scd_flow, + ba_resp->scd_ssn); + IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%X%X \n", + agg->start_idx, + agg->bitmap1, + agg->bitmap0); +*/ + iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); + /* releases all the TFDs until the SSN */ + if (txq->q.last_used != (ba_resp_scd_ssn & 0xff)) + iwl_tx_queue_reclaim(priv, ba_resp_scd_flow, index); + +} + + +static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) +{ + iwl_write_restricted_reg(priv, + SCD_QUEUE_STATUS_BITS(txq_id), + (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); +} + +static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, + u16 txq_id) +{ + u32 tbl_dw_addr; + u32 tbl_dw; + u16 scd_q2ratid; + + scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK; + + tbl_dw_addr = priv->scd_base_addr + + SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); + + tbl_dw = iwl_read_restricted_mem(priv, tbl_dw_addr); + + if (txq_id & 0x1) + tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); + else + tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); + + iwl_write_restricted_mem(priv, tbl_dw_addr, tbl_dw); + + return 0; +} + +/** + * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID + */ +static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, + int tx_fifo, int sta_id, int tid, + u16 ssn_idx) +{ + unsigned long flags; + int rc; + u16 ra_tid; + + if (IWL_BACK_QUEUE_FIRST_ID > txq_id) + IWL_WARNING("queue number too small: %d, must be > %d\n", + txq_id, IWL_BACK_QUEUE_FIRST_ID); + + ra_tid = BUILD_RAxTID(sta_id, tid); + + iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl4965_tx_queue_stop_scheduler(priv, txq_id); + + iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id); + + + iwl_set_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1<txq[txq_id].q.last_used = (ssn_idx & 0xff); + priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff); + + /* supposes that ssn_idx is valid (!= 0xFFF) */ + iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); + + iwl_write_restricted_mem(priv, + priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), + (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & + SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); + + iwl_write_restricted_mem(priv, priv->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), + (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) + & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); + + iwl_set_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id)); + + iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/** + * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID + */ +static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) +{ + unsigned long flags; + int rc; + + if (IWL_BACK_QUEUE_FIRST_ID > txq_id) { + IWL_WARNING("queue number too small: %d, must be > %d\n", + txq_id, IWL_BACK_QUEUE_FIRST_ID); + return -EINVAL; + } + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl4965_tx_queue_stop_scheduler(priv, txq_id); + + iwl_clear_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1 << txq_id)); + + priv->txq[txq_id].q.last_used = (ssn_idx & 0xff); + priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff); + /* supposes that ssn_idx is valid (!= 0xFFF) */ + iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); + + iwl_clear_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl4965_txq_ctx_deactivate(priv, txq_id); + iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +#endif/* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ +/* + * RATE SCALE CODE + */ +int iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates) +{ + return 0; +} + + +/** + * iwl4965_add_station - Initialize a station's hardware rate table + * + * The uCode contains a table of fallback rates and retries per rate + * for automatic fallback during transmission. + * + * NOTE: This initializes the table for a single retry per data rate + * which is not optimal. Setting up an intelligent retry per rate + * requires feedback from transmission, which isn't exposed through + * rc80211_simple which is what this driver is currently using. + * + */ +void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int i, r; + struct iwl_link_quality_cmd link_cmd = { + .reserved1 = 0, + }; + u16 rate_flags; + + /* Set up the rate scaling to start at 54M and fallback + * all the way to 1M in IEEE order and then spin on IEEE */ + if (is_ap) + r = IWL_RATE_54M_INDEX; + else if (priv->phymode == MODE_IEEE80211A) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + rate_flags = 0; + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + rate_flags |= RATE_MCS_ANT_B_MSK; + rate_flags &= ~RATE_MCS_ANT_A_MSK; + link_cmd.rs_table[i].rate_n_flags = + iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + r = iwl_get_prev_ieee_rate(r); + } + + link_cmd.general_params.single_stream_ant_msk = 2; + link_cmd.general_params.dual_stream_ant_msk = 3; + link_cmd.agg_params.agg_dis_start_th = 3; + link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); + + /* Update the rate scaling for control frame Tx to AP */ + link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID; + + iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), + &link_cmd); +} + +#ifdef CONFIG_IWLWIFI_HT + +static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode, + u16 channel, u8 extension_chan_offset) +{ + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, phymode, channel); + if (!is_channel_valid(ch_info)) + return 0; + + if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO) + return 0; + + if ((ch_info->fat_extension_channel == extension_chan_offset) || + (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX)) + return 1; + + return 0; +} + +static u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, + const struct sta_ht_info *ht_info) +{ + + if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) + return 0; + + if (ht_info->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) + return 0; + + if (ht_info->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO) + return 0; + + /* no fat tx allowed on 2.4GHZ */ + if (priv->phymode != MODE_IEEE80211A) + return 0; + return (iwl_is_channel_extension(priv, priv->phymode, + ht_info->control_channel, + ht_info->extension_chan_offset)); +} + +void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info) +{ + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + u32 val; + + if (!ht_info->is_ht) + return; + + if (iwl_is_fat_tx_allowed(priv, ht_info)) + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; + else + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + + if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { + IWL_DEBUG_ASSOC("control diff than current %d %d\n", + le16_to_cpu(rxon->channel), + ht_info->control_channel); + rxon->channel = cpu_to_le16(ht_info->control_channel); + return; + } + + /* Note: control channel is oposit to extension channel */ + switch (ht_info->extension_chan_offset) { + case IWL_EXT_CHANNEL_OFFSET_ABOVE: + rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + break; + case IWL_EXT_CHANNEL_OFFSET_BELOW: + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + break; + case IWL_EXT_CHANNEL_OFFSET_AUTO: + rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; + break; + default: + rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; + break; + } + + val = ht_info->operating_mode; + + rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); + + priv->active_rate_ht[0] = ht_info->supp_rates[0]; + priv->active_rate_ht[1] = ht_info->supp_rates[1]; + iwl4965_set_rxon_chain(priv); + + IWL_DEBUG_ASSOC("supported HT rate 0x%X %X " + "rxon flags 0x%X operation mode :0x%X " + "extension channel offset 0x%x " + "control chan %d\n", + priv->active_rate_ht[0], priv->active_rate_ht[1], + le32_to_cpu(rxon->flags), ht_info->operating_mode, + ht_info->extension_chan_offset, + ht_info->control_channel); + return; +} + +void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index) +{ + __le32 sta_flags; + struct sta_ht_info *ht_info = &priv->current_assoc_ht; + + priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ; + if (!ht_info->is_ht) + goto done; + + sta_flags = priv->stations[index].sta.station_flags; + + if (ht_info->tx_mimo_ps_mode == IWL_MIMO_PS_DYNAMIC) + sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; + else + sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK; + + sta_flags |= cpu_to_le32( + (u32)ht_info->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); + + sta_flags |= cpu_to_le32( + (u32)ht_info->mpdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); + + sta_flags &= (~STA_FLG_FAT_EN_MSK); + ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_20MHZ; + ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_20MHZ; + + if (iwl_is_fat_tx_allowed(priv, ht_info)) { + sta_flags |= STA_FLG_FAT_EN_MSK; + ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_40MHZ; + if (ht_info->supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ) + ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_40MHZ; + } + priv->current_channel_width = ht_info->tx_chan_width; + priv->stations[index].sta.station_flags = sta_flags; + done: + return; +} + +#ifdef CONFIG_IWLWIFI_HT_AGG + +static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv, + int sta_id, int tid, u16 ssn) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; + priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv, + int sta_id, int tid) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; + priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +static const u16 default_tid_to_tx_fifo[] = { + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_AC3 +}; + +static int iwl_txq_ctx_activate_free(struct iwl_priv *priv) +{ + int txq_id; + + for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) + if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk)) + return txq_id; + return -1; +} + +int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, + u16 *start_seq_num) +{ + + struct iwl_priv *priv = hw->priv; + int sta_id; + int tx_fifo; + int txq_id; + int ssn = -1; + unsigned long flags; + struct iwl_tid_data *tid_data; + + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) + tx_fifo = default_tid_to_tx_fifo[tid]; + else + return -EINVAL; + + IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=" MAC_FMT + " tid=%d\n", MAC_ARG(da), tid); + + sta_id = iwl_hw_find_station(priv, da); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + txq_id = iwl_txq_ctx_activate_free(priv); + if (txq_id == -1) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + tid_data = &priv->stations[sta_id].tid[tid]; + ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data->agg.txq_id = txq_id; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + *start_seq_num = ssn; + iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE); + return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, + sta_id, tid, ssn); +} + + +int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, + int generator) +{ + + struct iwl_priv *priv = hw->priv; + int tx_fifo_id, txq_id, sta_id, ssn = -1; + struct iwl_tid_data *tid_data; + int rc; + if (!da) { + IWL_ERROR("%s: da = NULL\n", __func__); + return -EINVAL; + } + + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) + tx_fifo_id = default_tid_to_tx_fifo[tid]; + else + return -EINVAL; + + sta_id = iwl_hw_find_station(priv, da); + + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + tid_data = &priv->stations[sta_id].tid[tid]; + ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; + txq_id = tid_data->agg.txq_id; + + rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id); + /* FIXME: need more safe way to handle error condition */ + if (rc) + return rc; + + iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA); + IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=" MAC_FMT " tid=%d\n", + MAC_ARG(da), tid); + + return 0; +} + +int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da, + u16 tid, u16 start_seq_num) +{ + struct iwl_priv *priv = hw->priv; + int sta_id; + + IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=" MAC_FMT + " tid=%d\n", MAC_ARG(da), tid); + sta_id = iwl_hw_find_station(priv, da); + iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num); + return 0; +} + +int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da, + u16 tid, int generator) +{ + struct iwl_priv *priv = hw->priv; + int sta_id; + + IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=" MAC_FMT " tid=%d\n", + MAC_ARG(da), tid); + sta_id = iwl_hw_find_station(priv, da); + iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); + return 0; +} + +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + +/* Set up 4965-specific Rx frame reply handlers */ +void iwl_hw_rx_handler_setup(struct iwl_priv *priv) +{ + /* Legacy Rx frames */ + priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx; + + /* High-throughput (HT) Rx frames */ + priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; + priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; + + priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = + iwl4965_rx_missed_beacon_notif; + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; +#endif /* CONFIG_IWLWIFI_AGG */ +#endif /* CONFIG_IWLWIFI */ +} + +void iwl_hw_setup_deferred_work(struct iwl_priv *priv) +{ + INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work); + INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work); +#ifdef CONFIG_IWLWIFI_SENSITIVITY + INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work); +#endif +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work); +#endif /* CONFIG_IWLWIFI_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + init_timer(&priv->statistics_periodic); + priv->statistics_periodic.data = (unsigned long)priv; + priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; +} + +void iwl_hw_cancel_deferred_work(struct iwl_priv *priv) +{ + del_timer_sync(&priv->statistics_periodic); + + cancel_delayed_work(&priv->init_alive_start); +} + +struct pci_device_id iwl_hw_card_ids[] = { + {0x8086, 0x4229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x4230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0} +}; + +int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv) +{ + u16 count; + int rc; + + for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + rc = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); + if (rc >= 0) { + IWL_DEBUG_IO("Aqcuired semaphore after %d tries.\n", + count+1); + return rc; + } + } + + return rc; +} + +inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv) +{ + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); +} + + +MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h new file mode 100644 index 000000000000..4c700812b45b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -0,0 +1,341 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#ifndef __iwl_4965_h__ +#define __iwl_4965_h__ + +struct iwl_priv; +struct sta_ht_info; + +/* + * Forward declare iwl-4965.c functions for iwl-base.c + */ +extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv); +extern void iwl_eeprom_release_semaphore(struct iwl_priv *priv); + +extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + u16 byte_cnt); +extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, + int is_ap); +extern void iwl4965_set_rxon_ht(struct iwl_priv *priv, + struct sta_ht_info *ht_info); + +extern void iwl4965_set_rxon_chain(struct iwl_priv *priv); +extern int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd, + u8 sta_id, dma_addr_t txcmd_phys, + struct ieee80211_hdr *hdr, u8 hdr_len, + struct ieee80211_tx_control *ctrl, void *sta_in); +extern int iwl4965_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates); +extern int iwl4965_alive_notify(struct iwl_priv *priv); +extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); +extern void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index); + +extern void iwl4965_chain_noise_reset(struct iwl_priv *priv); +extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, + u8 force); +extern int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, + u16 channel, + const struct iwl_eeprom_channel *eeprom_ch, + u8 fat_extension_channel); +extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG +extern int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, + u16 tid, u16 *start_seq_num); +extern int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da, + u16 tid, u16 start_seq_num); +extern int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da, + u16 tid, int generator); +extern int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, + u16 tid, int generator); +extern void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid); +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /*CONFIG_IWLWIFI_HT */ +/* Structures, enum, and defines specific to the 4965 */ + +#define IWL4965_KW_SIZE 0x1000 /*4k */ + +struct iwl_kw { + dma_addr_t dma_addr; + void *v_addr; + size_t size; +}; + +#define TID_QUEUE_CELL_SPACING 50 /*mS */ +#define TID_QUEUE_MAX_SIZE 20 +#define TID_ROUND_VALUE 5 /* mS */ +#define TID_MAX_LOAD_COUNT 8 + +#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) +#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) + +#define TID_ALL_ENABLED 0x7f +#define TID_ALL_SPECIFIED 0xff +#define TID_AGG_TPT_THREHOLD 0x0 + +#define IWL_CHANNEL_WIDTH_20MHZ 0 +#define IWL_CHANNEL_WIDTH_40MHZ 1 + +#define IWL_MIMO_PS_STATIC 0 +#define IWL_MIMO_PS_NONE 3 +#define IWL_MIMO_PS_DYNAMIC 1 +#define IWL_MIMO_PS_INVALID 2 + +#define IWL_OPERATION_MODE_AUTO 0 +#define IWL_OPERATION_MODE_HT_ONLY 1 +#define IWL_OPERATION_MODE_MIXED 2 +#define IWL_OPERATION_MODE_20MHZ 3 + +#define IWL_EXT_CHANNEL_OFFSET_AUTO 0 +#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 +#define IWL_EXT_CHANNEL_OFFSET_ 2 +#define IWL_EXT_CHANNEL_OFFSET_BELOW 3 +#define IWL_EXT_CHANNEL_OFFSET_MAX 4 + +#define NRG_NUM_PREV_STAT_L 20 +#define NUM_RX_CHAINS (3) + +#define TX_POWER_IWL_ILLEGAL_VDET -100000 +#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 +#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18 +#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34 +#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17 +#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20 +#define TX_POWER_IWL_NOMINAL_POWER 26 +#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1 +#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V 7 +#define TX_POWER_IWL_DEGREES_PER_VDET_CODE 11 +#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1 +#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9) +#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5) + +struct iwl_traffic_load { + unsigned long time_stamp; + u32 packet_count[TID_QUEUE_MAX_SIZE]; + u8 queue_count; + u8 head; + u32 total; +}; + +#ifdef CONFIG_IWLWIFI_HT_AGG +struct iwl_agg_control { + unsigned long next_retry; + u32 wait_for_agg_status; + u32 tid_retry; + u32 requested_ba; + u32 granted_ba; + u8 auto_agg; + u32 tid_traffic_load_threshold; + u32 ba_timeout; + struct iwl_traffic_load traffic_load[TID_MAX_LOAD_COUNT]; +}; +#endif /*CONFIG_IWLWIFI_HT_AGG */ + +struct iwl_lq_mngr { +#ifdef CONFIG_IWLWIFI_HT_AGG + struct iwl_agg_control agg_ctrl; +#endif + spinlock_t lock; + s32 max_window_size; + s32 *expected_tpt; + u8 *next_higher_rate; + u8 *next_lower_rate; + unsigned long stamp; + unsigned long stamp_last; + u32 flush_time; + u32 tx_packets; + u8 lq_ready; +}; + + +/* Sensitivity and chain noise calibration */ +#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) +#define INITIALIZATION_VALUE 0xFFFF +#define CAL_NUM_OF_BEACONS 20 +#define MAXIMUM_ALLOWED_PATHLOSS 15 + +/* Param table within SENSITIVITY_CMD */ +#define HD_MIN_ENERGY_CCK_DET_INDEX (0) +#define HD_MIN_ENERGY_OFDM_DET_INDEX (1) +#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX (2) +#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX (3) +#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX (4) +#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX (5) +#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX (6) +#define HD_BARKER_CORR_TH_ADD_MIN_INDEX (7) +#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX (8) +#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9) +#define HD_OFDM_ENERGY_TH_IN_INDEX (10) + +#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) +#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) + +#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3 + +#define MAX_FA_OFDM 50 +#define MIN_FA_OFDM 5 +#define MAX_FA_CCK 50 +#define MIN_FA_CCK 5 + +#define NRG_MIN_CCK 97 +#define NRG_MAX_CCK 0 + +#define AUTO_CORR_MIN_OFDM 85 +#define AUTO_CORR_MIN_OFDM_MRC 170 +#define AUTO_CORR_MIN_OFDM_X1 105 +#define AUTO_CORR_MIN_OFDM_MRC_X1 220 +#define AUTO_CORR_MAX_OFDM 120 +#define AUTO_CORR_MAX_OFDM_MRC 210 +#define AUTO_CORR_MAX_OFDM_X1 140 +#define AUTO_CORR_MAX_OFDM_MRC_X1 270 +#define AUTO_CORR_STEP_OFDM 1 + +#define AUTO_CORR_MIN_CCK (125) +#define AUTO_CORR_MAX_CCK (200) +#define AUTO_CORR_MIN_CCK_MRC 200 +#define AUTO_CORR_MAX_CCK_MRC 400 +#define AUTO_CORR_STEP_CCK 3 +#define AUTO_CORR_MAX_TH_CCK 160 + +#define NRG_ALG 0 +#define AUTO_CORR_ALG 1 +#define NRG_DIFF 2 +#define NRG_STEP_CCK 2 +#define NRG_MARGIN 8 +#define MAX_NUMBER_CCK_NO_FA 100 + +#define AUTO_CORR_CCK_MIN_VAL_DEF (125) + +#define CHAIN_A 0 +#define CHAIN_B 1 +#define CHAIN_C 2 +#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4 +#define ALL_BAND_FILTER 0xFF00 +#define IN_BAND_FILTER 0xFF +#define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF + +enum iwl_false_alarm_state { + IWL_FA_TOO_MANY = 0, + IWL_FA_TOO_FEW = 1, + IWL_FA_GOOD_RANGE = 2, +}; + +enum iwl_chain_noise_state { + IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ + IWL_CHAIN_NOISE_ACCUMULATE = 1, + IWL_CHAIN_NOISE_CALIBRATED = 2, +}; + +enum iwl_sensitivity_state { + IWL_SENS_CALIB_ALLOWED = 0, + IWL_SENS_CALIB_NEED_REINIT = 1, +}; + +enum iwl_calib_enabled_state { + IWL_CALIB_DISABLED = 0, /* must be 0 */ + IWL_CALIB_ENABLED = 1, +}; + +struct statistics_general_data { + u32 beacon_silence_rssi_a; + u32 beacon_silence_rssi_b; + u32 beacon_silence_rssi_c; + u32 beacon_energy_a; + u32 beacon_energy_b; + u32 beacon_energy_c; +}; + +/* Sensitivity calib data */ +struct iwl_sensitivity_data { + u32 auto_corr_ofdm; + u32 auto_corr_ofdm_mrc; + u32 auto_corr_ofdm_x1; + u32 auto_corr_ofdm_mrc_x1; + u32 auto_corr_cck; + u32 auto_corr_cck_mrc; + + u32 last_bad_plcp_cnt_ofdm; + u32 last_fa_cnt_ofdm; + u32 last_bad_plcp_cnt_cck; + u32 last_fa_cnt_cck; + + u32 nrg_curr_state; + u32 nrg_prev_state; + u32 nrg_value[10]; + u8 nrg_silence_rssi[NRG_NUM_PREV_STAT_L]; + u32 nrg_silence_ref; + u32 nrg_energy_idx; + u32 nrg_silence_idx; + u32 nrg_th_cck; + s32 nrg_auto_corr_silence_diff; + u32 num_in_cck_no_fa; + u32 nrg_th_ofdm; + + u8 state; +}; + +/* Chain noise (differential Rx gain) calib data */ +struct iwl_chain_noise_data { + u8 state; + u16 beacon_count; + u32 chain_noise_a; + u32 chain_noise_b; + u32 chain_noise_c; + u32 chain_signal_a; + u32 chain_signal_b; + u32 chain_signal_c; + u8 disconn_array[NUM_RX_CHAINS]; + u8 delta_gain_code[NUM_RX_CHAINS]; + u8 radio_write; +}; + +/* IWL4965 */ +#define RATE_MCS_CODE_MSK 0x7 +#define RATE_MCS_MIMO_POS 3 +#define RATE_MCS_MIMO_MSK 0x8 +#define RATE_MCS_HT_DUP_POS 5 +#define RATE_MCS_HT_DUP_MSK 0x20 +#define RATE_MCS_FLAGS_POS 8 +#define RATE_MCS_HT_POS 8 +#define RATE_MCS_HT_MSK 0x100 +#define RATE_MCS_CCK_POS 9 +#define RATE_MCS_CCK_MSK 0x200 +#define RATE_MCS_GF_POS 10 +#define RATE_MCS_GF_MSK 0x400 + +#define RATE_MCS_FAT_POS 11 +#define RATE_MCS_FAT_MSK 0x800 +#define RATE_MCS_DUP_POS 12 +#define RATE_MCS_DUP_MSK 0x1000 +#define RATE_MCS_SGI_POS 13 +#define RATE_MCS_SGI_MSK 0x2000 + +#define EEPROM_SEM_TIMEOUT 10 +#define EEPROM_SEM_RETRY_LIMIT 1000 + +#endif /* __iwl_4965_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-channel.h b/drivers/net/wireless/iwlwifi/iwl-channel.h new file mode 100644 index 000000000000..023c3f240cea --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-channel.h @@ -0,0 +1,161 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#ifndef __iwl_channel_h__ +#define __iwl_channel_h__ + +#define IWL_NUM_SCAN_RATES (2) + +struct iwl_channel_tgd_info { + u8 type; + s8 max_power; +}; + +struct iwl_channel_tgh_info { + s64 last_radar_time; +}; + +/* current Tx power values to use, one for each rate for each channel. + * requested power is limited by: + * -- regulatory EEPROM limits for this channel + * -- hardware capabilities (clip-powers) + * -- spectrum management + * -- user preference (e.g. iwconfig) + * when requested power is set, base power index must also be set. */ +struct iwl_channel_power_info { + struct iwl_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 base_power_index; /* gain index for power at factory temp. */ + s8 requested_power; /* power (dBm) requested for this chnl/rate */ +}; + +/* current scan Tx power values to use, one for each scan rate for each + * channel. */ +struct iwl_scan_power_info { + struct iwl_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ +}; + +/* Channel unlock period is 15 seconds. If no beacon or probe response + * has been received within 15 seconds on a locked channel then the channel + * remains locked. */ +#define TX_UNLOCK_PERIOD 15 + +/* CSA lock period is 15 seconds. If a CSA has been received on a channel in + * the last 15 seconds, the channel is locked */ +#define CSA_LOCK_PERIOD 15 +/* + * One for each channel, holds all channel setup data + * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant + * with one another! + */ +#define IWL4965_MAX_RATE (33) + +struct iwl_channel_info { + struct iwl_channel_tgd_info tgd; + struct iwl_channel_tgh_info tgh; + struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ + struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for + * FAT channel */ + + u8 channel; /* channel number */ + u8 flags; /* flags copied from EEPROM */ + s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 min_power; /* always 0 */ + s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */ + + u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ + u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ + u8 phymode; /* MODE_IEEE80211{A,B,G} */ + + /* Radio/DSP gain settings for each "normal" data Tx rate. + * These include, in addition to RF and DSP gain, a few fields for + * remembering/modifying gain settings (indexes). */ + struct iwl_channel_power_info power_info[IWL4965_MAX_RATE]; + +#if IWL == 4965 + /* 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; +#endif + + /* Radio/DSP gain settings for each scan rate, for directed scans. */ + struct iwl_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; +}; + +struct iwl_clip_group { + /* maximum power level to prevent clipping for each rate, derived by + * us from this band's saturation power in EEPROM */ + const s8 clip_powers[IWL_MAX_RATES]; +}; + +static inline int is_channel_valid(const struct iwl_channel_info *ch_info) +{ + if (ch_info == NULL) + return 0; + return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; +} + +static inline int is_channel_narrow(const struct iwl_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; +} + +static inline int is_channel_radar(const struct iwl_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; +} + +static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info) +{ + return ch_info->phymode == MODE_IEEE80211A; +} + +static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info) +{ + return ((ch_info->phymode == MODE_IEEE80211B) || + (ch_info->phymode == MODE_IEEE80211G)); +} + +static inline int is_channel_passive(const struct iwl_channel_info *ch) +{ + return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; +} + +static inline int is_channel_ibss(const struct iwl_channel_info *ch) +{ + return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; +} + +extern const struct iwl_channel_info *iwl_get_channel_info( + const struct iwl_priv *priv, int phymode, u16 channel); + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h new file mode 100644 index 000000000000..9de8d7f6efa3 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -0,0 +1,1734 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_commands_h__ +#define __iwl_commands_h__ + +enum { + REPLY_ALIVE = 0x1, + REPLY_ERROR = 0x2, + + /* RXON and QOS commands */ + REPLY_RXON = 0x10, + REPLY_RXON_ASSOC = 0x11, + REPLY_QOS_PARAM = 0x13, + REPLY_RXON_TIMING = 0x14, + + /* Multi-Station support */ + REPLY_ADD_STA = 0x18, + REPLY_REMOVE_STA = 0x19, /* not used */ + REPLY_REMOVE_ALL_STA = 0x1a, /* not used */ + + /* RX, TX, LEDs */ +#if IWL == 3945 + REPLY_3945_RX = 0x1b, /* 3945 only */ +#endif + REPLY_TX = 0x1c, + REPLY_RATE_SCALE = 0x47, /* 3945 only */ + REPLY_LEDS_CMD = 0x48, + REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ + + /* 802.11h related */ + RADAR_NOTIFICATION = 0x70, /* not used */ + REPLY_QUIET_CMD = 0x71, /* not used */ + REPLY_CHANNEL_SWITCH = 0x72, + CHANNEL_SWITCH_NOTIFICATION = 0x73, + REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74, + SPECTRUM_MEASURE_NOTIFICATION = 0x75, + + /* Power Management */ + POWER_TABLE_CMD = 0x77, + PM_SLEEP_NOTIFICATION = 0x7A, + PM_DEBUG_STATISTIC_NOTIFIC = 0x7B, + + /* Scan commands and notifications */ + REPLY_SCAN_CMD = 0x80, + REPLY_SCAN_ABORT_CMD = 0x81, + SCAN_START_NOTIFICATION = 0x82, + SCAN_RESULTS_NOTIFICATION = 0x83, + SCAN_COMPLETE_NOTIFICATION = 0x84, + + /* IBSS/AP commands */ + BEACON_NOTIFICATION = 0x90, + REPLY_TX_BEACON = 0x91, + WHO_IS_AWAKE_NOTIFICATION = 0x94, /* not used */ + + /* Miscellaneous commands */ + QUIET_NOTIFICATION = 0x96, /* not used */ + REPLY_TX_PWR_TABLE_CMD = 0x97, + MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ + + /* BT config command */ + REPLY_BT_CONFIG = 0x9b, + + /* 4965 Statistics */ + REPLY_STATISTICS_CMD = 0x9c, + STATISTICS_NOTIFICATION = 0x9d, + + /* RF-KILL commands and notifications */ + REPLY_CARD_STATE_CMD = 0xa0, + CARD_STATE_NOTIFICATION = 0xa1, + + /* Missed beacons notification */ + MISSED_BEACONS_NOTIFICATION = 0xa2, + +#if IWL == 4965 + REPLY_CT_KILL_CONFIG_CMD = 0xa4, + SENSITIVITY_CMD = 0xa8, + REPLY_PHY_CALIBRATION_CMD = 0xb0, + REPLY_RX_PHY_CMD = 0xc0, + REPLY_RX_MPDU_CMD = 0xc1, + REPLY_4965_RX = 0xc3, + REPLY_COMPRESSED_BA = 0xc5, +#endif + REPLY_MAX = 0xff +}; + +/****************************************************************************** + * (0) + * Header + * + *****************************************************************************/ + +#define IWL_CMD_FAILED_MSK 0x40 + +struct iwl_cmd_header { + u8 cmd; + u8 flags; + /* We have 15 LSB to use as we please (MSB indicates + * a frame Rx'd from the HW). We encode the following + * information into the sequence field: + * + * 0:7 index in fifo + * 8:13 fifo selection + * 14:14 bit indicating if this packet references the 'extra' + * storage at the end of the memory queue + * 15:15 (Rx indication) + * + */ + __le16 sequence; + + /* command data follows immediately */ + u8 data[0]; +} __attribute__ ((packed)); + +/****************************************************************************** + * (0a) + * Alive and Error Commands & Responses: + * + *****************************************************************************/ + +#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define INITIALIZE_SUBTYPE (9) + +/* + * REPLY_ALIVE = 0x1 (response only, not a command) + */ +struct iwl_alive_resp { + u8 ucode_minor; + u8 ucode_major; + __le16 reserved1; + u8 sw_rev[8]; + u8 ver_type; + u8 ver_subtype; + __le16 reserved2; + __le32 log_event_table_ptr; + __le32 error_event_table_ptr; + __le32 timestamp; + __le32 is_valid; +} __attribute__ ((packed)); + +struct iwl_init_alive_resp { + u8 ucode_minor; + u8 ucode_major; + __le16 reserved1; + u8 sw_rev[8]; + u8 ver_type; + u8 ver_subtype; + __le16 reserved2; + __le32 log_event_table_ptr; + __le32 error_event_table_ptr; + __le32 timestamp; + __le32 is_valid; + +#if IWL == 4965 + /* calibration values from "initialize" uCode */ + __le32 voltage; /* signed */ + __le32 therm_r1[2]; /* signed 1st for normal, 2nd for FAT channel */ + __le32 therm_r2[2]; /* signed */ + __le32 therm_r3[2]; /* signed */ + __le32 therm_r4[2]; /* signed */ + __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, + * 2 Tx chains */ +#endif +} __attribute__ ((packed)); + +union tsf { + u8 byte[8]; + __le16 word[4]; + __le32 dw[2]; +}; + +/* + * REPLY_ERROR = 0x2 (response only, not a command) + */ +struct iwl_error_resp { + __le32 error_type; + u8 cmd_id; + u8 reserved1; + __le16 bad_cmd_seq_num; +#if IWL == 3945 + __le16 reserved2; +#endif + __le32 error_info; + union tsf timestamp; +} __attribute__ ((packed)); + +/****************************************************************************** + * (1) + * RXON Commands & Responses: + * + *****************************************************************************/ + +/* + * Rx config defines & structure + */ +/* rx_config device types */ +enum { + RXON_DEV_TYPE_AP = 1, + RXON_DEV_TYPE_ESS = 3, + RXON_DEV_TYPE_IBSS = 4, + RXON_DEV_TYPE_SNIFFER = 6, +}; + +/* rx_config flags */ +/* band & modulation selection */ +#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +/* auto detection enable */ +#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +/* TGg protection when tx */ +#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +/* cck short slot & preamble */ +#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +/* antenna selection */ +#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +/* radar detection enable */ +#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +/* rx response to host with 8-byte TSF +* (according to ON_AIR deassertion) */ +#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) + +/* rx_config filter flags */ +/* accept all data frames */ +#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +/* pass control & management to host */ +#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +/* accept multi-cast */ +#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +/* don't decrypt uni-cast frames */ +#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +/* don't decrypt multi-cast frames */ +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +/* STA is associated */ +#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +/* transfer to host non bssid beacons in associated state */ +#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) + +/* + * REPLY_RXON = 0x10 (command, has simple generic response) + */ +struct iwl_rxon_cmd { + u8 node_addr[6]; + __le16 reserved1; + u8 bssid_addr[6]; + __le16 reserved2; + u8 wlap_bssid_addr[6]; + __le16 reserved3; + u8 dev_type; + u8 air_propagation; +#if IWL == 3945 + __le16 reserved4; +#elif IWL == 4965 + __le16 rx_chain; +#endif + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 assoc_id; + __le32 flags; + __le32 filter_flags; + __le16 channel; +#if IWL == 3945 + __le16 reserved5; +#elif IWL == 4965 + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; +#endif +} __attribute__ ((packed)); + +/* + * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) + */ +struct iwl_rxon_assoc_cmd { + __le32 flags; + __le32 filter_flags; + u8 ofdm_basic_rates; + u8 cck_basic_rates; +#if IWL == 4965 + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + __le16 rx_chain_select_flags; +#endif + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) + */ +struct iwl_rxon_time_cmd { + union tsf timestamp; + __le16 beacon_interval; + __le16 atim_window; + __le32 beacon_init_val; + __le16 listen_interval; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwl_tx_power { + u8 tx_gain; /* gain for analog radio */ + u8 dsp_atten; /* gain for DSP */ +} __attribute__ ((packed)); + +#if IWL == 3945 +struct iwl_power_per_rate { + u8 rate; /* plcp */ + struct iwl_tx_power tpc; + u8 reserved; +} __attribute__ ((packed)); + +#elif IWL == 4965 +#define POWER_TABLE_NUM_ENTRIES 33 +#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 +#define POWER_TABLE_CCK_ENTRY 32 +struct tx_power_dual_stream { + __le32 dw; +} __attribute__ ((packed)); + +struct iwl_tx_power_db { + struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; +} __attribute__ ((packed)); +#endif + +/* + * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) + */ +struct iwl_channel_switch_cmd { + u8 band; + u8 expect_beacon; + __le16 channel; + __le32 rxon_flags; + __le32 rxon_filter_flags; + __le32 switch_time; +#if IWL == 3945 + struct iwl_power_per_rate power[IWL_MAX_RATES]; +#elif IWL == 4965 + struct iwl_tx_power_db tx_power; +#endif +} __attribute__ ((packed)); + +/* + * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) + */ +struct iwl_csa_notification { + __le16 band; + __le16 channel; + __le32 status; /* 0 - OK, 1 - fail */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (2) + * Quality-of-Service (QOS) Commands & Responses: + * + *****************************************************************************/ +struct iwl_ac_qos { + __le16 cw_min; + __le16 cw_max; + u8 aifsn; + u8 reserved1; + __le16 edca_txop; +} __attribute__ ((packed)); + +/* QoS flags defines */ +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) + +/* + * TXFIFO Queue number defines + */ +/* number of Access categories (AC) (EDCA), queues 0..3 */ +#define AC_NUM 4 + +/* + * REPLY_QOS_PARAM = 0x13 (command, has simple generic response) + */ +struct iwl_qosparam_cmd { + __le32 qos_flags; + struct iwl_ac_qos ac[AC_NUM]; +} __attribute__ ((packed)); + +/****************************************************************************** + * (3) + * Add/Modify Stations Commands & Responses: + * + *****************************************************************************/ +/* + * Multi station support + */ +#define IWL_AP_ID 0 +#define IWL_MULTICAST_ID 1 +#define IWL_STA_ID 2 + +#define IWL3945_BROADCAST_ID 24 +#define IWL3945_STATION_COUNT 25 + +#define IWL4965_BROADCAST_ID 31 +#define IWL4965_STATION_COUNT 32 + +#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ +#define IWL_INVALID_STATION 255 + +#if IWL == 3945 +#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1<<2); +#endif +#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1<<8); + +#define STA_CONTROL_MODIFY_MSK 0x01 + +/* key flags __le16*/ +#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7) +#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0) +#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1) +#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2) +#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3) + +#define STA_KEY_FLG_KEYID_POS 8 +#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) + +/* modify flags */ +#define STA_MODIFY_KEY_MASK 0x01 +#define STA_MODIFY_TID_DISABLE_TX 0x02 +#define STA_MODIFY_TX_RATE_MSK 0x04 +#define STA_MODIFY_ADDBA_TID_MSK 0x08 +#define STA_MODIFY_DELBA_TID_MSK 0x10 +#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) + +/* + * Antenna masks: + * bit14:15 01 B inactive, A active + * 10 B active, A inactive + * 11 Both active + */ +#define RATE_MCS_ANT_A_POS 14 +#define RATE_MCS_ANT_B_POS 15 +#define RATE_MCS_ANT_A_MSK 0x4000 +#define RATE_MCS_ANT_B_MSK 0x8000 +#define RATE_MCS_ANT_AB_MSK 0xc000 + +struct iwl_keyinfo { + __le16 key_flags; + u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ + u8 reserved1; + __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ + __le16 reserved2; + u8 key[16]; /* 16-byte unicast decryption key */ +} __attribute__ ((packed)); + +struct sta_id_modify { + u8 addr[ETH_ALEN]; + __le16 reserved1; + u8 sta_id; + u8 modify_mask; + __le16 reserved2; +} __attribute__ ((packed)); + +/* + * REPLY_ADD_STA = 0x18 (command) + */ +struct iwl_addsta_cmd { + u8 mode; + u8 reserved[3]; + struct sta_id_modify sta; + struct iwl_keyinfo key; + __le32 station_flags; + __le32 station_flags_msk; + __le16 tid_disable_tx; +#if IWL == 3945 + __le16 rate_n_flags; +#else + __le16 reserved1; +#endif + u8 add_immediate_ba_tid; + u8 remove_immediate_ba_tid; + __le16 add_immediate_ba_ssn; +#if IWL == 4965 + __le32 reserved2; +#endif +} __attribute__ ((packed)); + +/* + * REPLY_ADD_STA = 0x18 (response) + */ +struct iwl_add_sta_resp { + u8 status; +} __attribute__ ((packed)); + +#define ADD_STA_SUCCESS_MSK 0x1 + +/****************************************************************************** + * (4) + * Rx Responses: + * + *****************************************************************************/ + +struct iwl_rx_frame_stats { + u8 phy_count; + u8 id; + u8 rssi; + u8 agc; + __le16 sig_avg; + __le16 noise_diff; + u8 payload[0]; +} __attribute__ ((packed)); + +struct iwl_rx_frame_hdr { + __le16 channel; + __le16 phy_flags; + u8 reserved1; + u8 rate; + __le16 len; + u8 payload[0]; +} __attribute__ ((packed)); + +#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) + +#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) + +#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) +#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) +#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) +#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) +#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) + +#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) +#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) +#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) +#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) +#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) + +struct iwl_rx_frame_end { + __le32 status; + __le64 timestamp; + __le32 beacon_timestamp; +} __attribute__ ((packed)); + +/* + * REPLY_3945_RX = 0x1b (response only, not a command) + * + * NOTE: DO NOT dereference from casts to this structure + * It is provided only for calculating minimum data set size. + * The actual offsets of the hdr and end are dynamic based on + * stats.phy_count + */ +struct iwl_rx_frame { + struct iwl_rx_frame_stats stats; + struct iwl_rx_frame_hdr hdr; + struct iwl_rx_frame_end end; +} __attribute__ ((packed)); + +/* Fixed (non-configurable) rx data from phy */ +#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) +#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) +#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ +#define IWL_AGC_DB_POS (7) +struct iwl4965_rx_non_cfg_phy { + __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ + __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ + u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ + u8 pad[0]; +} __attribute__ ((packed)); + +/* + * REPLY_4965_RX = 0xc3 (response only, not a command) + * Used only for legacy (non 11n) frames. + */ +#define RX_RES_PHY_CNT 14 +struct iwl4965_rx_phy_res { + u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ + u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ + u8 stat_id; /* configurable DSP phy data set ID */ + u8 reserved1; + __le64 timestamp; /* TSF at on air rise */ + __le32 beacon_time_stamp; /* beacon at on-air rise */ + __le16 phy_flags; /* general phy flags: band, modulation, ... */ + __le16 channel; /* channel number */ + __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ + __le32 reserved2; + __le32 rate_n_flags; + __le16 byte_count; /* frame's byte-count */ + __le16 reserved3; +} __attribute__ ((packed)); + +struct iwl4965_rx_mpdu_res_start { + __le16 byte_count; + __le16 reserved; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (5) + * Tx Commands & Responses: + * + *****************************************************************************/ + +/* Tx flags */ +#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) +#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) +#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) +#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) +#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) +#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) + +/* ucode ignores BT priority for this frame */ +#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) + +/* ucode overrides sequence control */ +#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) + +/* signal that this frame is non-last MPDU */ +#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) + +/* calculate TSF in outgoing frame */ +#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) + +/* activate TX calibration. */ +#define TX_CMD_FLG_CALIB_MSK __constant_cpu_to_le32(1 << 17) + +/* signals that 2 bytes pad was inserted + after the MAC header */ +#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) + +/* HCCA-AP - disable duration overwriting. */ +#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) + +/* + * TX command security control + */ +#define TX_CMD_SEC_WEP 0x01 +#define TX_CMD_SEC_CCM 0x02 +#define TX_CMD_SEC_TKIP 0x03 +#define TX_CMD_SEC_MSK 0x03 +#define TX_CMD_SEC_SHIFT 6 +#define TX_CMD_SEC_KEY128 0x08 + +/* + * TX command Frame life time + */ + +struct iwl_dram_scratch { + u8 try_cnt; + u8 bt_kill_cnt; + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_TX = 0x1c (command) + */ +struct iwl_tx_cmd { + __le16 len; + __le16 next_frame_len; + __le32 tx_flags; +#if IWL == 3945 + u8 rate; + u8 sta_id; + u8 tid_tspec; +#elif IWL == 4965 + struct iwl_dram_scratch scratch; + __le32 rate_n_flags; + u8 sta_id; +#endif + u8 sec_ctl; +#if IWL == 4965 + u8 initial_rate_index; + u8 reserved; +#endif + u8 key[16]; +#if IWL == 3945 + union { + u8 byte[8]; + __le16 word[4]; + __le32 dw[2]; + } tkip_mic; + __le32 next_frame_info; +#elif IWL == 4965 + __le16 next_frame_flags; + __le16 reserved2; +#endif + union { + __le32 life_time; + __le32 attempt; + } stop_time; +#if IWL == 3945 + u8 supp_rates[2]; +#elif IWL == 4965 + __le32 dram_lsb_ptr; + u8 dram_msb_ptr; +#endif + u8 rts_retry_limit; /*byte 50 */ + u8 data_retry_limit; /*byte 51 */ +#if IWL == 4965 + u8 tid_tspec; +#endif + union { + __le16 pm_frame_timeout; + __le16 attempt_duration; + } timeout; + __le16 driver_txop; + u8 payload[0]; + struct ieee80211_hdr hdr[0]; +} __attribute__ ((packed)); + +/* TX command response is sent after *all* transmission attempts. + * + * NOTES: + * + * TX_STATUS_FAIL_NEXT_FRAG + * + * If the fragment flag in the MAC header for the frame being transmitted + * is set and there is insufficient time to transmit the next frame, the + * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. + * + * TX_STATUS_FIFO_UNDERRUN + * + * Indicates the host did not provide bytes to the FIFO fast enough while + * a TX was in progress. + * + * TX_STATUS_FAIL_MGMNT_ABORT + * + * This status is only possible if the ABORT ON MGMT RX parameter was + * set to true with the TX command. + * + * If the MSB of the status parameter is set then an abort sequence is + * required. This sequence consists of the host activating the TX Abort + * control line, and then waiting for the TX Abort command response. This + * indicates that a the device is no longer in a transmit state, and that the + * command FIFO has been cleared. The host must then deactivate the TX Abort + * control line. Receiving is still allowed in this case. + */ +enum { + TX_STATUS_SUCCESS = 0x01, + TX_STATUS_DIRECT_DONE = 0x02, + TX_STATUS_FAIL_SHORT_LIMIT = 0x82, + TX_STATUS_FAIL_LONG_LIMIT = 0x83, + TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84, + TX_STATUS_FAIL_MGMNT_ABORT = 0x85, + TX_STATUS_FAIL_NEXT_FRAG = 0x86, + TX_STATUS_FAIL_LIFE_EXPIRE = 0x87, + TX_STATUS_FAIL_DEST_PS = 0x88, + TX_STATUS_FAIL_ABORTED = 0x89, + TX_STATUS_FAIL_BT_RETRY = 0x8a, + TX_STATUS_FAIL_STA_INVALID = 0x8b, + TX_STATUS_FAIL_FRAG_DROPPED = 0x8c, + TX_STATUS_FAIL_TID_DISABLE = 0x8d, + TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e, + TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, + TX_STATUS_FAIL_TX_LOCKED = 0x90, + TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, +}; + +#define TX_PACKET_MODE_REGULAR 0x0000 +#define TX_PACKET_MODE_BURST_SEQ 0x0100 +#define TX_PACKET_MODE_BURST_FIRST 0x0200 + +enum { + TX_POWER_PA_NOT_ACTIVE = 0x0, +}; + +enum { + TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ + TX_STATUS_DELAY_MSK = 0x00000040, + TX_STATUS_ABORT_MSK = 0x00000080, + TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */ + TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */ + TX_RESERVED = 0x00780000, /* bits 19:22 */ + TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */ + TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ +}; + +/* ******************************* + * TX aggregation state + ******************************* */ + +enum { + AGG_TX_STATE_TRANSMITTED = 0x00, + AGG_TX_STATE_UNDERRUN_MSK = 0x01, + AGG_TX_STATE_BT_PRIO_MSK = 0x02, + AGG_TX_STATE_FEW_BYTES_MSK = 0x04, + AGG_TX_STATE_ABORT_MSK = 0x08, + AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10, + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20, + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40, + AGG_TX_STATE_SCD_QUERY_MSK = 0x80, + AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100, + AGG_TX_STATE_RESPONSE_MSK = 0x1ff, + AGG_TX_STATE_DUMP_TX_MSK = 0x200, + AGG_TX_STATE_DELAY_TX_MSK = 0x400 +}; + +#define AGG_TX_STATE_LAST_SENT_MSK \ +(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) + +#define AGG_TX_STATE_TRY_CNT_POS 12 +#define AGG_TX_STATE_TRY_CNT_MSK 0xf000 + +#define AGG_TX_STATE_SEQ_NUM_POS 16 +#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000 + +/* + * REPLY_TX = 0x1c (response) + */ +#if IWL == 4965 +struct iwl_tx_resp { + u8 frame_count; /* 1 no aggregation, >1 aggregation */ + u8 bt_kill_count; + u8 failure_rts; + u8 failure_frame; + __le32 rate_n_flags; + __le16 wireless_media_time; + __le16 reserved; + __le32 pa_power1; + __le32 pa_power2; + __le32 status; /* TX status (for aggregation status of 1st frame) */ +} __attribute__ ((packed)); + +#elif IWL == 3945 +struct iwl_tx_resp { + u8 failure_rts; + u8 failure_frame; + u8 bt_kill_count; + u8 rate; + __le32 wireless_media_time; + __le32 status; /* TX status (for aggregation status of 1st frame) */ +} __attribute__ ((packed)); +#endif + +/* + * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) + */ +struct iwl_compressed_ba_resp { + __le32 sta_addr_lo32; + __le16 sta_addr_hi16; + __le16 reserved; + u8 sta_id; + u8 tid; + __le16 ba_seq_ctl; + __le32 ba_bitmap0; + __le32 ba_bitmap1; + __le16 scd_flow; + __le16 scd_ssn; +} __attribute__ ((packed)); + +/* + * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) + */ +struct iwl_txpowertable_cmd { + u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ + u8 reserved; + __le16 channel; +#if IWL == 3945 + struct iwl_power_per_rate power[IWL_MAX_RATES]; +#elif IWL == 4965 + struct iwl_tx_power_db tx_power; +#endif +} __attribute__ ((packed)); + +#if IWL == 3945 +struct iwl_rate_scaling_info { + __le16 rate_n_flags; + u8 try_cnt; + u8 next_rate_index; +} __attribute__ ((packed)); + +/** + * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response + * + * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) + * + * NOTE: The table of rates passed to the uCode via the + * RATE_SCALE command sets up the corresponding order of + * rates used for all related commands, including rate + * masks, etc. + * + * For example, if you set 9MB (PLCP 0x0f) as the first + * rate in the rate table, the bit mask for that rate + * when passed through ofdm_basic_rates on the REPLY_RXON + * command would be bit 0 (1<<0) + */ +struct iwl_rate_scaling_cmd { + u8 table_id; + u8 reserved[3]; + struct iwl_rate_scaling_info table[IWL_MAX_RATES]; +} __attribute__ ((packed)); + +#elif IWL == 4965 + +/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ +#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1<<0) + +#define LINK_QUAL_AC_NUM AC_NUM +#define LINK_QUAL_MAX_RETRY_NUM 16 + +#define LINK_QUAL_ANT_A_MSK (1<<0) +#define LINK_QUAL_ANT_B_MSK (1<<1) +#define LINK_QUAL_ANT_MSK (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK) + +struct iwl_link_qual_general_params { + u8 flags; + u8 mimo_delimiter; + u8 single_stream_ant_msk; + u8 dual_stream_ant_msk; + u8 start_rate_index[LINK_QUAL_AC_NUM]; +} __attribute__ ((packed)); + +struct iwl_link_qual_agg_params { + __le16 agg_time_limit; + u8 agg_dis_start_th; + u8 agg_frame_cnt_limit; + __le32 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response) + */ +struct iwl_link_quality_cmd { + u8 sta_id; + u8 reserved1; + __le16 control; + struct iwl_link_qual_general_params general_params; + struct iwl_link_qual_agg_params agg_params; + struct { + __le32 rate_n_flags; + } rs_table[LINK_QUAL_MAX_RETRY_NUM]; + __le32 reserved2; +} __attribute__ ((packed)); +#endif + +/* + * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) + */ +struct iwl_bt_cmd { + u8 flags; + u8 lead_time; + u8 max_kill; + u8 reserved; + __le32 kill_ack_mask; + __le32 kill_cts_mask; +} __attribute__ ((packed)); + +/****************************************************************************** + * (6) + * Spectrum Management (802.11h) Commands, Responses, Notifications: + * + *****************************************************************************/ + +/* + * Spectrum Management + */ +#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK | \ + RXON_FILTER_CTL2HOST_MSK | \ + RXON_FILTER_ACCEPT_GRP_MSK | \ + RXON_FILTER_DIS_DECRYPT_MSK | \ + RXON_FILTER_DIS_GRP_DECRYPT_MSK | \ + RXON_FILTER_ASSOC_MSK | \ + RXON_FILTER_BCON_AWARE_MSK) + +struct iwl_measure_channel { + __le32 duration; /* measurement duration in extended beacon + * format */ + u8 channel; /* channel to measure */ + u8 type; /* see enum iwl_measure_type */ + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) + */ +struct iwl_spectrum_cmd { + __le16 len; /* number of bytes starting from token */ + u8 token; /* token id */ + u8 id; /* measurement id -- 0 or 1 */ + u8 origin; /* 0 = TGh, 1 = other, 2 = TGk */ + u8 periodic; /* 1 = periodic */ + __le16 path_loss_timeout; + __le32 start_time; /* start time in extended beacon format */ + __le32 reserved2; + __le32 flags; /* rxon flags */ + __le32 filter_flags; /* rxon filter flags */ + __le16 channel_count; /* minimum 1, maximum 10 */ + __le16 reserved3; + struct iwl_measure_channel channels[10]; +} __attribute__ ((packed)); + +/* + * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) + */ +struct iwl_spectrum_resp { + u8 token; + u8 id; /* id of the prior command replaced, or 0xff */ + __le16 status; /* 0 - command will be handled + * 1 - cannot handle (conflicts with another + * measurement) */ +} __attribute__ ((packed)); + +enum iwl_measurement_state { + IWL_MEASUREMENT_START = 0, + IWL_MEASUREMENT_STOP = 1, +}; + +enum iwl_measurement_status { + IWL_MEASUREMENT_OK = 0, + IWL_MEASUREMENT_CONCURRENT = 1, + IWL_MEASUREMENT_CSA_CONFLICT = 2, + IWL_MEASUREMENT_TGH_CONFLICT = 3, + /* 4-5 reserved */ + IWL_MEASUREMENT_STOPPED = 6, + IWL_MEASUREMENT_TIMEOUT = 7, + IWL_MEASUREMENT_PERIODIC_FAILED = 8, +}; + +#define NUM_ELEMENTS_IN_HISTOGRAM 8 + +struct iwl_measurement_histogram { + __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ + __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ +} __attribute__ ((packed)); + +/* clear channel availability counters */ +struct iwl_measurement_cca_counters { + __le32 ofdm; + __le32 cck; +} __attribute__ ((packed)); + +enum iwl_measure_type { + IWL_MEASURE_BASIC = (1 << 0), + IWL_MEASURE_CHANNEL_LOAD = (1 << 1), + IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), + IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3), + IWL_MEASURE_FRAME = (1 << 4), + /* bits 5:6 are reserved */ + IWL_MEASURE_IDLE = (1 << 7), +}; + +/* + * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) + */ +struct iwl_spectrum_notification { + u8 id; /* measurement id -- 0 or 1 */ + u8 token; + u8 channel_index; /* index in measurement channel list */ + u8 state; /* 0 - start, 1 - stop */ + __le32 start_time; /* lower 32-bits of TSF */ + u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ + u8 channel; + u8 type; /* see enum iwl_measurement_type */ + u8 reserved1; + /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only + * valid if applicable for measurement type requested. */ + __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */ + __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */ + __le32 cca_time; /* channel load time in usecs */ + u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - + * unidentified */ + u8 reserved2[3]; + struct iwl_measurement_histogram histogram; + __le32 stop_time; /* lower 32-bits of TSF */ + __le32 status; /* see iwl_measurement_status */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (7) + * Power Management Commands, Responses, Notifications: + * + *****************************************************************************/ + +/** + * struct iwl_powertable_cmd - Power Table Command + * @flags: See below: + * + * POWER_TABLE_CMD = 0x77 (command, has simple generic response) + * + * 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_LINK_CTRL & 0x1) + * '1' !(PCI_LINK_CTRL & 0x1) + * Force sleep Modes + * bit 31/30- '00' use both mac/xtal sleeps + * '01' force Mac sleep + * '10' force xtal sleep + * '11' Illegal set + * + * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then + * ucode assume sleep over DTIM is allowed and we don't need to wakeup + * for every DTIM. + */ +#define IWL_POWER_VEC_SIZE 5 + + +#if IWL == 3945 + +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1<<0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1<<2) +#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1<<3) +struct iwl_powertable_cmd { + __le32 flags; + __le32 rx_data_timeout; + __le32 tx_data_timeout; + __le32 sleep_interval[IWL_POWER_VEC_SIZE]; +} __attribute__((packed)); + +#elif IWL == 4965 + +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1<<0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1<<2) +#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1<<3) + +struct iwl_powertable_cmd { + __le16 flags; + u8 keep_alive_seconds; + u8 debug_flags; + __le32 rx_data_timeout; + __le32 tx_data_timeout; + __le32 sleep_interval[IWL_POWER_VEC_SIZE]; + __le32 keep_alive_beacons; +} __attribute__ ((packed)); +#endif + +/* + * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) + * 3945 and 4965 identical. + */ +struct iwl_sleep_notification { + u8 pm_sleep_mode; + u8 pm_wakeup_src; + __le16 reserved; + __le32 sleep_time; + __le32 tsf_low; + __le32 bcon_timer; +} __attribute__ ((packed)); + +/* Sleep states. 3945 and 4965 identical. */ +enum { + IWL_PM_NO_SLEEP = 0, + IWL_PM_SLP_MAC = 1, + IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2, + IWL_PM_SLP_FULL_MAC_CARD_STATE = 3, + IWL_PM_SLP_PHY = 4, + IWL_PM_SLP_REPENT = 5, + IWL_PM_WAKEUP_BY_TIMER = 6, + IWL_PM_WAKEUP_BY_DRIVER = 7, + IWL_PM_WAKEUP_BY_RFKILL = 8, + /* 3 reserved */ + IWL_PM_NUM_OF_MODES = 12, +}; + +/* + * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response) + */ +#define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ +#define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ +#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ +struct iwl_card_state_cmd { + __le32 status; /* CARD_STATE_CMD_* request new power state */ +} __attribute__ ((packed)); + +/* + * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) + */ +struct iwl_card_state_notif { + __le32 flags; +} __attribute__ ((packed)); + +#define HW_CARD_DISABLED 0x01 +#define SW_CARD_DISABLED 0x02 +#define RF_CARD_DISABLED 0x04 +#define RXON_CARD_DISABLED 0x10 + +struct iwl_ct_kill_config { + __le32 reserved; + __le32 critical_temperature_M; + __le32 critical_temperature_R; +} __attribute__ ((packed)); + +/****************************************************************************** + * (8) + * Scan Commands, Responses, Notifications: + * + *****************************************************************************/ + +struct iwl_scan_channel { + /* type is defined as: + * 0:0 active (0 - passive) + * 1:4 SSID direct + * If 1 is set then corresponding SSID IE is transmitted in probe + * 5:7 reserved + */ + u8 type; + u8 channel; + struct iwl_tx_power tpc; + __le16 active_dwell; + __le16 passive_dwell; +} __attribute__ ((packed)); + +struct iwl_ssid_ie { + u8 id; + u8 len; + u8 ssid[32]; +} __attribute__ ((packed)); + +#define PROBE_OPTION_MAX 0x4 +#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define IWL_MAX_SCAN_SIZE 1024 + +/* + * REPLY_SCAN_CMD = 0x80 (command) + */ +struct iwl_scan_cmd { + __le16 len; + u8 reserved0; + u8 channel_count; + __le16 quiet_time; /* dwell only this long on quiet chnl + * (active scan) */ + __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ + __le16 good_CRC_th; /* passive -> active promotion threshold */ +#if IWL == 3945 + __le16 reserved1; +#elif IWL == 4965 + __le16 rx_chain; +#endif + __le32 max_out_time; /* max usec to be out of associated (service) + * chnl */ + __le32 suspend_time; /* pause scan this long when returning to svc + * chnl. + * 3945 -- 31:24 # beacons, 19:0 additional usec, + * 4965 -- 31:22 # beacons, 21:0 additional usec. + */ + __le32 flags; + __le32 filter_flags; + + struct iwl_tx_cmd tx_cmd; + struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; + + u8 data[0]; + /* + * The channels start after the probe request payload and are of type: + * + * struct iwl_scan_channel channels[0]; + * + * NOTE: Only one band of channels can be scanned per pass. You + * can not mix 2.4GHz channels and 5.2GHz channels and must + * request a scan multiple times (not concurrently) + * + */ +} __attribute__ ((packed)); + +/* Can abort will notify by complete notification with abort status. */ +#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +/* complete notification statuses */ +#define ABORT_STATUS 0x2 + +/* + * REPLY_SCAN_CMD = 0x80 (response) + */ +struct iwl_scanreq_notification { + __le32 status; /* 1: okay, 2: cannot fulfill request */ +} __attribute__ ((packed)); + +/* + * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command) + */ +struct iwl_scanstart_notification { + __le32 tsf_low; + __le32 tsf_high; + __le32 beacon_timer; + u8 channel; + u8 band; + u8 reserved[2]; + __le32 status; +} __attribute__ ((packed)); + +#define SCAN_OWNER_STATUS 0x1; +#define MEASURE_OWNER_STATUS 0x2; + +#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */ +/* + * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command) + */ +struct iwl_scanresults_notification { + u8 channel; + u8 band; + u8 reserved[2]; + __le32 tsf_low; + __le32 tsf_high; + __le32 statistics[NUMBER_OF_STATISTICS]; +} __attribute__ ((packed)); + +/* + * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command) + */ +struct iwl_scancomplete_notification { + u8 scanned_channels; + u8 status; + u8 reserved; + u8 last_channel; + __le32 tsf_low; + __le32 tsf_high; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (9) + * IBSS/AP Commands and Notifications: + * + *****************************************************************************/ + +/* + * BEACON_NOTIFICATION = 0x90 (notification only, not a command) + */ +struct iwl_beacon_notif { + struct iwl_tx_resp beacon_notify_hdr; + __le32 low_tsf; + __le32 high_tsf; + __le32 ibss_mgr_status; +} __attribute__ ((packed)); + +/* + * REPLY_TX_BEACON = 0x91 (command, has simple generic response) + */ +struct iwl_tx_beacon_cmd { + struct iwl_tx_cmd tx; + __le16 tim_idx; + u8 tim_size; + u8 reserved1; + struct ieee80211_hdr frame[0]; /* beacon frame */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (10) + * Statistics Commands and Notifications: + * + *****************************************************************************/ + +#define IWL_TEMP_CONVERT 260 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/* Used for passing to driver number of successes and failures per rate */ +struct rate_histogram { + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } success; + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } failed; +} __attribute__ ((packed)); + +/* statistics command response */ + +struct statistics_rx_phy { + __le32 ina_cnt; + __le32 fina_cnt; + __le32 plcp_err; + __le32 crc32_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 false_alarm_cnt; + __le32 fina_sync_err_cnt; + __le32 sfd_timeout; + __le32 fina_timeout; + __le32 unresponded_rts; + __le32 rxe_frame_limit_overrun; + __le32 sent_ack_cnt; + __le32 sent_cts_cnt; +#if IWL == 4965 + __le32 sent_ba_rsp_cnt; + __le32 dsp_self_kill; + __le32 mh_format_err; + __le32 re_acq_main_rssi_sum; + __le32 reserved3; +#endif +} __attribute__ ((packed)); + +#if IWL == 4965 +struct statistics_rx_ht_phy { + __le32 plcp_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 crc32_err; + __le32 mh_format_err; + __le32 agg_crc32_good; + __le32 agg_mpdu_cnt; + __le32 agg_cnt; + __le32 reserved2; +} __attribute__ ((packed)); +#endif + +struct statistics_rx_non_phy { + __le32 bogus_cts; /* CTS received when not expecting CTS */ + __le32 bogus_ack; /* ACK received when not expecting ACK */ + __le32 non_bssid_frames; /* number of frames with BSSID that + * doesn't belong to the STA BSSID */ + __le32 filtered_frames; /* count frames that were dumped in the + * filtering process */ + __le32 non_channel_beacons; /* beacons with our bss id but not on + * our serving channel */ +#if IWL == 4965 + __le32 channel_beacons; /* beacons with our bss id and in our + * serving channel */ + __le32 num_missed_bcon; /* number of missed beacons */ + __le32 adc_rx_saturation_time; /* count in 0.8us units the time the + * ADC was in saturation */ + __le32 ina_detection_search_time;/* total time (in 0.8us) searched + * for INA */ + __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ + __le32 interference_data_flag; /* flag for interference data + * availability. 1 when data is + * available. */ + __le32 channel_load; /* counts RX Enable time */ + __le32 dsp_false_alarms; /* DSP false alarm (both OFDM + * and CCK) counter */ + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 beacon_rssi_c; + __le32 beacon_energy_a; + __le32 beacon_energy_b; + __le32 beacon_energy_c; +#endif +} __attribute__ ((packed)); + +struct statistics_rx { + struct statistics_rx_phy ofdm; + struct statistics_rx_phy cck; + struct statistics_rx_non_phy general; +#if IWL == 4965 + struct statistics_rx_ht_phy ofdm_ht; +#endif +} __attribute__ ((packed)); + +#if IWL == 4965 +struct statistics_tx_non_phy_agg { + __le32 ba_timeout; + __le32 ba_reschedule_frames; + __le32 scd_query_agg_frame_cnt; + __le32 scd_query_no_agg; + __le32 scd_query_agg; + __le32 scd_query_mismatch; + __le32 frame_not_ready; + __le32 underrun; + __le32 bt_prio_kill; + __le32 rx_ba_rsp_cnt; + __le32 reserved2; + __le32 reserved3; +} __attribute__ ((packed)); +#endif + +struct statistics_tx { + __le32 preamble_cnt; + __le32 rx_detected_cnt; + __le32 bt_prio_defer_cnt; + __le32 bt_prio_kill_cnt; + __le32 few_bytes_cnt; + __le32 cts_timeout; + __le32 ack_timeout; + __le32 expected_ack_cnt; + __le32 actual_ack_cnt; +#if IWL == 4965 + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; + struct statistics_tx_non_phy_agg agg; +#endif +} __attribute__ ((packed)); + +struct statistics_dbg { + __le32 burst_check; + __le32 burst_count; + __le32 reserved[4]; +} __attribute__ ((packed)); + +struct statistics_div { + __le32 tx_on_a; + __le32 tx_on_b; + __le32 exec_time; + __le32 probe_time; +#if IWL == 4965 + __le32 reserved1; + __le32 reserved2; +#endif +} __attribute__ ((packed)); + +struct statistics_general { + __le32 temperature; +#if IWL == 4965 + __le32 temperature_m; +#endif + struct statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct statistics_div div; +#if IWL == 4965 + __le32 rx_enable_counter; + __le32 reserved1; + __le32 reserved2; + __le32 reserved3; +#endif +} __attribute__ ((packed)); + +/* + * REPLY_STATISTICS_CMD = 0x9c, + * 3945 and 4965 identical. + * + * This command triggers an immediate response containing uCode statistics. + * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below. + * + * If the CLEAR_STATS configuration flag is set, uCode will clear its + * internal copy of the statistics (counters) after issuing the response. + * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below). + * + * If the DISABLE_NOTIF configuration flag is set, uCode will not issue + * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag + * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. + */ +#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +struct iwl_statistics_cmd { + __le32 configuration_flags; /* IWL_STATS_CONF_* */ +} __attribute__ ((packed)); + +/* + * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) + * + * By default, uCode issues this notification after receiving a beacon + * while associated. To disable this behavior, set DISABLE_NOTIF flag in the + * REPLY_STATISTICS_CMD 0x9c, above. + * + * Statistics counters continue to increment beacon after beacon, but are + * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD + * 0x9c with CLEAR_STATS bit set (see above). + * + * uCode also issues this notification during scans. uCode clears statistics + * appropriately so that each notification contains statistics for only the + * one channel that has just been scanned. + */ +#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +struct iwl_notif_statistics { + __le32 flag; + struct statistics_rx rx; + struct statistics_tx tx; + struct statistics_general general; +} __attribute__ ((packed)); + + +/* + * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command) + */ +/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row, + * then this notification will be sent. */ +#define CONSECUTIVE_MISSED_BCONS_TH 20 + +struct iwl_missed_beacon_notif { + __le32 consequtive_missed_beacons; + __le32 total_missed_becons; + __le32 num_expected_beacons; + __le32 num_recvd_beacons; +} __attribute__ ((packed)); + +/****************************************************************************** + * (11) + * Rx Calibration Commands: + * + *****************************************************************************/ + +#define PHY_CALIBRATE_DIFF_GAIN_CMD (7) +#define HD_TABLE_SIZE (11) + +struct iwl_sensitivity_cmd { + __le16 control; + __le16 table[HD_TABLE_SIZE]; +} __attribute__ ((packed)); + +struct iwl_calibration_cmd { + u8 opCode; + u8 flags; + __le16 reserved; + s8 diff_gain_a; + s8 diff_gain_b; + s8 diff_gain_c; + u8 reserved1; +} __attribute__ ((packed)); + +/****************************************************************************** + * (12) + * Miscellaneous Commands: + * + *****************************************************************************/ + +/* + * LEDs Command & Response + * REPLY_LEDS_CMD = 0x48 (command, has simple generic response) + * + * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field), + * this command turns it on or off, or sets up a periodic blinking cycle. + */ +struct iwl_led_cmd { + __le32 interval; /* "interval" in uSec */ + u8 id; /* 1: Activity, 2: Link, 3: Tech */ + u8 off; /* # intervals off while blinking; + * "0", with >0 "on" value, turns LED on */ + u8 on; /* # intervals on while blinking; + * "0", regardless of "off", turns LED off */ + u8 reserved; +} __attribute__ ((packed)); + +/****************************************************************************** + * (13) + * Union of all expected notifications/responses: + * + *****************************************************************************/ + +struct iwl_rx_packet { + __le32 len; + struct iwl_cmd_header hdr; + union { + struct iwl_alive_resp alive_frame; + struct iwl_rx_frame rx_frame; + struct iwl_tx_resp tx_resp; + struct iwl_spectrum_notification spectrum_notif; + struct iwl_csa_notification csa_notif; + struct iwl_error_resp err_resp; + struct iwl_card_state_notif card_state_notif; + struct iwl_beacon_notif beacon_status; + struct iwl_add_sta_resp add_sta; + struct iwl_sleep_notification sleep_notif; + struct iwl_spectrum_resp spectrum; + struct iwl_notif_statistics stats; +#if IWL == 4965 + struct iwl_compressed_ba_resp compressed_ba; + struct iwl_missed_beacon_notif missed_beacon; +#endif + __le32 status; + u8 raw[0]; + } u; +} __attribute__ ((packed)); + +#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl_rx_frame)) + +#endif /* __iwl_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h new file mode 100644 index 000000000000..abd344c549aa --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_debug_h__ +#define __iwl_debug_h__ + +#ifdef CONFIG_IWLWIFI_DEBUG +extern u32 iwl_debug_level; +#define IWL_DEBUG(level, fmt, args...) \ +do { if (iwl_debug_level & (level)) \ + printk(KERN_ERR DRV_NAME": %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + +#define IWL_DEBUG_LIMIT(level, fmt, args...) \ +do { if ((iwl_debug_level & (level)) && net_ratelimit()) \ + printk(KERN_ERR DRV_NAME": %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) +#else +static inline void IWL_DEBUG(int level, const char *fmt, ...) +{ +} +static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) +{ +} +#endif /* CONFIG_IWLWIFI_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 IWL_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 IWL_xxxx_DEBUG() macro definition for your + * classification, or use IWL_DEBUG(IWL_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/iwl/debug_level + * + * you simply need to add your entry to the iwl_debug_levels array. + * + * If you do not see debug_level in /proc/net/iwl then you do not have + * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration + * + */ + +#define IWL_DL_INFO (1<<0) +#define IWL_DL_MAC80211 (1<<1) +#define IWL_DL_HOST_COMMAND (1<<2) +#define IWL_DL_STATE (1<<3) + +#define IWL_DL_RADIO (1<<7) +#define IWL_DL_POWER (1<<8) +#define IWL_DL_TEMP (1<<9) + +#define IWL_DL_NOTIF (1<<10) +#define IWL_DL_SCAN (1<<11) +#define IWL_DL_ASSOC (1<<12) +#define IWL_DL_DROP (1<<13) + +#define IWL_DL_TXPOWER (1<<14) + +#define IWL_DL_AP (1<<15) + +#define IWL_DL_FW (1<<16) +#define IWL_DL_RF_KILL (1<<17) +#define IWL_DL_FW_ERRORS (1<<18) + +#define IWL_DL_LED (1<<19) + +#define IWL_DL_RATE (1<<20) + +#define IWL_DL_CALIB (1<<21) +#define IWL_DL_WEP (1<<22) +#define IWL_DL_TX (1<<23) +#define IWL_DL_RX (1<<24) +#define IWL_DL_ISR (1<<25) +#define IWL_DL_HT (1<<26) +#define IWL_DL_IO (1<<27) +#define IWL_DL_11H (1<<28) + +#define IWL_DL_STATS (1<<29) +#define IWL_DL_TX_REPLY (1<<30) +#define IWL_DL_QOS (1<<31) + +#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) +#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) +#define IWL_DEBUG_INFO(f, a...) IWL_DEBUG(IWL_DL_INFO, f, ## a) + +#define IWL_DEBUG_MAC80211(f, a...) IWL_DEBUG(IWL_DL_MAC80211, f, ## a) +#define IWL_DEBUG_TEMP(f, a...) IWL_DEBUG(IWL_DL_TEMP, f, ## a) +#define IWL_DEBUG_SCAN(f, a...) IWL_DEBUG(IWL_DL_SCAN, f, ## a) +#define IWL_DEBUG_RX(f, a...) IWL_DEBUG(IWL_DL_RX, f, ## a) +#define IWL_DEBUG_TX(f, a...) IWL_DEBUG(IWL_DL_TX, f, ## a) +#define IWL_DEBUG_ISR(f, a...) IWL_DEBUG(IWL_DL_ISR, f, ## a) +#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a) +#define IWL_DEBUG_WEP(f, a...) IWL_DEBUG(IWL_DL_WEP, f, ## a) +#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a) +#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a) +#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a) +#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a) +#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a) +#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a) +#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a) +#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a) +#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a) +#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a) +#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a) +#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) +#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) +#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) +#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) +#define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) +#define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) +#define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a) +#define IWL_DEBUG_11H(f, a...) IWL_DEBUG(IWL_DL_11H, f, ## a) + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h new file mode 100644 index 000000000000..e473c97e3f4f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -0,0 +1,336 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_eeprom_h__ +#define __iwl_eeprom_h__ + +/* + * This file defines EEPROM related constants, enums, and inline functions. + * + */ + +#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ +#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ +/* EEPROM field values */ +#define ANTENNA_SWITCH_NORMAL 0 +#define ANTENNA_SWITCH_INVERSE 1 + +enum { + EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ + EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ + /* Bit 2 Reserved */ + EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ + EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ + EEPROM_CHANNEL_WIDE = (1 << 5), + EEPROM_CHANNEL_NARROW = (1 << 6), + EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ +}; + +/* EEPROM field lengths */ +#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11 + +/* EEPROM field lengths */ +#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11 +#define EEPROM_REGULATORY_SKU_ID_LENGTH 4 +#define EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH 14 +#define EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH 13 +#define EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH 12 +#define EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH 11 +#define EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH 6 + +#if IWL == 3945 +#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \ + EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH) +#elif IWL == 4965 +#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH 7 +#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH 11 +#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \ + EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH) +#endif + +#define EEPROM_REGULATORY_NUMBER_OF_BANDS 5 + +/* SKU Capabilities */ +#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) +#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) +#define EEPROM_SKU_CAP_OP_MODE_MRC (1 << 7) + +/* *regulatory* channel data from eeprom, one for each channel */ +struct iwl_eeprom_channel { + u8 flags; /* flags copied from EEPROM */ + s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ +} __attribute__ ((packed)); + +/* + * Mapping of a Tx power level, at factory calibration temperature, + * to a radio/DSP gain table index. + * One for each of 5 "sample" power levels in each band. + * v_det is measured at the factory, using the 3945's built-in power amplifier + * (PA) output voltage detector. This same detector is used during Tx of + * long packets in normal operation to provide feedback as to proper output + * level. + * Data copied from EEPROM. + */ +struct iwl_eeprom_txpower_sample { + u8 gain_index; /* index into power (gain) setup table ... */ + s8 power; /* ... for this pwr level for this chnl group */ + u16 v_det; /* PA output voltage */ +} __attribute__ ((packed)); + +/* + * Mappings of Tx power levels -> nominal radio/DSP gain table indexes. + * One for each channel group (a.k.a. "band") (1 for BG, 4 for A). + * Tx power setup code interpolates between the 5 "sample" power levels + * to determine the nominal setup for a requested power level. + * Data copied from EEPROM. + * DO NOT ALTER THIS STRUCTURE!!! + */ +struct iwl_eeprom_txpower_group { + struct iwl_eeprom_txpower_sample samples[5]; /* 5 power levels */ + s32 a, b, c, d, e; /* coefficients for voltage->power + * formula (signed) */ + s32 Fa, Fb, Fc, Fd, Fe; /* these modify coeffs based on + * frequency (signed) */ + s8 saturation_power; /* highest power possible by h/w in this + * band */ + u8 group_channel; /* "representative" channel # in this band */ + s16 temperature; /* h/w temperature at factory calib this band + * (signed) */ +} __attribute__ ((packed)); + +/* + * Temperature-based Tx-power compensation data, not band-specific. + * These coefficients are use to modify a/b/c/d/e coeffs based on + * difference between current temperature and factory calib temperature. + * Data copied from EEPROM. + */ +struct iwl_eeprom_temperature_corr { + u32 Ta; + u32 Tb; + u32 Tc; + u32 Td; + u32 Te; +} __attribute__ ((packed)); + +#if IWL == 4965 +#define EEPROM_TX_POWER_TX_CHAINS (2) +#define EEPROM_TX_POWER_BANDS (8) +#define EEPROM_TX_POWER_MEASUREMENTS (3) +#define EEPROM_TX_POWER_VERSION (2) +#define EEPROM_TX_POWER_VERSION_NEW (5) + +struct iwl_eeprom_calib_measure { + u8 temperature; + u8 gain_idx; + u8 actual_pow; + s8 pa_det; +} __attribute__ ((packed)); + +struct iwl_eeprom_calib_ch_info { + u8 ch_num; + struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS] + [EEPROM_TX_POWER_MEASUREMENTS]; +} __attribute__ ((packed)); + +struct iwl_eeprom_calib_subband_info { + u8 ch_from; + u8 ch_to; + struct iwl_eeprom_calib_ch_info ch1; + struct iwl_eeprom_calib_ch_info ch2; +} __attribute__ ((packed)); + +struct iwl_eeprom_calib_info { + u8 saturation_power24; + u8 saturation_power52; + s16 voltage; /* signed */ + struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; +} __attribute__ ((packed)); + +#endif + +struct iwl_eeprom { + u8 reserved0[16]; +#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ + u16 device_id; /* abs.ofs: 16 */ + u8 reserved1[2]; +#define EEPROM_PMC (2*0x0A) /* 2 bytes */ + u16 pmc; /* abs.ofs: 20 */ + u8 reserved2[20]; +#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ + u8 mac_address[6]; /* abs.ofs: 42 */ + u8 reserved3[58]; +#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ + u16 board_revision; /* abs.ofs: 106 */ + u8 reserved4[11]; +#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ + u8 board_pba_number[9]; /* abs.ofs: 119 */ + u8 reserved5[8]; +#define EEPROM_VERSION (2*0x44) /* 2 bytes */ + u16 version; /* abs.ofs: 136 */ +#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ + u8 sku_cap; /* abs.ofs: 138 */ +#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ + u8 leds_mode; /* abs.ofs: 139 */ +#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ + u16 oem_mode; +#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ + u16 wowlan_mode; /* abs.ofs: 142 */ +#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ + u16 leds_time_interval; /* abs.ofs: 144 */ +#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ + u8 leds_off_time; /* abs.ofs: 146 */ +#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ + u8 leds_on_time; /* abs.ofs: 147 */ +#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ + u8 almgor_m_version; /* abs.ofs: 148 */ +#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ + u8 antenna_switch_type; /* abs.ofs: 149 */ +#if IWL == 3945 + u8 reserved6[42]; +#else + u8 reserved6[8]; +#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ + u16 board_revision_4965; /* abs.ofs: 158 */ + u8 reserved7[13]; +#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ + u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ + u8 reserved8[10]; +#endif +#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ + u8 sku_id[4]; /* abs.ofs: 192 */ +#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ + u16 band_1_count; /* abs.ofs: 196 */ +#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ + struct iwl_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ +#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ + u16 band_2_count; /* abs.ofs: 226 */ +#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ + struct iwl_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ +#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ + u16 band_3_count; /* abs.ofs: 254 */ +#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ + struct iwl_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ +#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ + u16 band_4_count; /* abs.ofs: 280 */ +#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ + struct iwl_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ +#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ + u16 band_5_count; /* abs.ofs: 304 */ +#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ + struct iwl_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ + +/* From here on out the EEPROM diverges between the 4965 and the 3945 */ +#if IWL == 3945 + + u8 reserved9[194]; + +#define EEPROM_TXPOWER_CALIB_GROUP0 0x200 +#define EEPROM_TXPOWER_CALIB_GROUP1 0x240 +#define EEPROM_TXPOWER_CALIB_GROUP2 0x280 +#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0 +#define EEPROM_TXPOWER_CALIB_GROUP4 0x300 +#define IWL_NUM_TX_CALIB_GROUPS 5 + struct iwl_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS]; +/* abs.ofs: 512 */ +#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340 + struct iwl_eeprom_temperature_corr corrections; /* abs.ofs: 832 */ + u8 reserved16[172]; /* fill out to full 1024 byte block */ + +/* 4965AGN adds fat channel support */ +#elif IWL == 4965 + + u8 reserved10[2]; +#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ + struct iwl_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ + u8 reserved11[2]; +#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ + struct iwl_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ + u8 reserved12[6]; +#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ + u16 calib_version; /* abs.ofs: 364 */ + u8 reserved13[2]; +#define EEPROM_SATURATION_POWER_OFFSET (2*0xB8) /* 2 bytes */ + u16 satruation_power; /* abs.ofs: 368 */ + u8 reserved14[94]; +#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ + struct iwl_eeprom_calib_info calib_info; /* abs.ofs: 464 */ + + u8 reserved16[140]; /* fill out to full 1024 byte block */ + +#endif + +} __attribute__ ((packed)); + +#define IWL_EEPROM_IMAGE_SIZE 1024 + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h new file mode 100644 index 000000000000..e2a8d95ad9cd --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -0,0 +1,255 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_helpers_h__ +#define __iwl_helpers_h__ + +#include + +/* + * The structures defined by the hardware/uCode interface + * have bit-wise operations. For each bit-field there is + * a data symbol in the structure, the start bit position + * and the length of the bit-field. + * + * iwl_get_bits and iwl_set_bits will return or set the + * appropriate bits on a 32-bit value. + * + * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to + * expand out to the appropriate call to iwl_get_bits + * and iwl_set_bits without having to reference all of the + * numerical constants and defines provided in the hardware + * definition + */ + +/** + * iwl_get_bits - Extract a hardware bit-field value + * @src: source hardware value (__le32) + * @pos: bit-position (0-based) of first bit of value + * @len: length of bit-field + * + * iwl_get_bits will return the bit-field in cpu endian ordering. + * + * NOTE: If used from IWL_GET_BITS then pos and len are compile-constants and + * will collapse to minimal code by the compiler. + */ +static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len) +{ + u32 tmp = le32_to_cpu(src); + + tmp >>= pos; + tmp &= (1UL << len) - 1; + return tmp; +} + +/** + * iwl_set_bits - Set a hardware bit-field value + * @dst: Address of __le32 hardware value + * @pos: bit-position (0-based) of first bit of value + * @len: length of bit-field + * @val: cpu endian value to encode into the bit-field + * + * iwl_set_bits will encode val into dst, masked to be len bits long at bit + * position pos. + * + * NOTE: If used IWL_SET_BITS pos and len will be compile-constants and + * will collapse to minimal code by the compiler. + */ +static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val) +{ + u32 tmp = le32_to_cpu(*dst); + + tmp &= ~(((1UL << len) - 1) << pos); + tmp |= (val & ((1UL << len) - 1)) << pos; + *dst = cpu_to_le32(tmp); +} + +static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val) +{ + u16 tmp = le16_to_cpu(*dst); + + tmp &= ~((1UL << (pos + len)) - (1UL << pos)); + tmp |= (val & ((1UL << len) - 1)) << pos; + *dst = cpu_to_le16(tmp); +} + +/* + * The bit-field definitions in iwl-xxxx-hw.h are in the form of: + * + * struct example { + * __le32 val1; + * #define IWL_name_POS 8 + * #define IWL_name_LEN 4 + * #define IWL_name_SYM val1 + * }; + * + * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver + * to call: + * + * struct example bar; + * u32 val = IWL_GET_BITS(bar, name); + * val = val * 2; + * IWL_SET_BITS(bar, name, val); + * + * All cpu / host ordering, masking, and shifts are performed by the macros + * and iwl_{get,set}_bits. + * + */ +#define IWL_SET_BITS(s, sym, v) \ + iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ + IWL_ ## sym ## _LEN, (v)) + +#define IWL_SET_BITS16(s, sym, v) \ + iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ + IWL_ ## sym ## _LEN, (v)) + +#define IWL_GET_BITS(s, sym) \ + iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ + IWL_ ## sym ## _LEN) + + +#define KELVIN_TO_CELSIUS(x) ((x)-273) +#define CELSIUS_TO_KELVIN(x) ((x)+273) + +#define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010 + +static inline struct ieee80211_conf *ieee80211_get_hw_conf( + struct ieee80211_hw *hw) +{ + return &hw->conf; +} + +#define QOS_CONTROL_LEN 2 + +#define IEEE80211_STYPE_BACK_REQ 0x0080 +#define IEEE80211_STYPE_BACK 0x0090 + + +static inline int ieee80211_is_management(u16 fc) +{ + return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT; +} + +static inline int ieee80211_is_control(u16 fc) +{ + return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL; +} + +static inline int ieee80211_is_data(u16 fc) +{ + return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA; +} + +static inline int ieee80211_is_back_request(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ); +} + +static inline int ieee80211_is_probe_response(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP); +} + +static inline int ieee80211_is_probe_request(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_REQ); +} + +static inline int ieee80211_is_beacon(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON); +} + +static inline int ieee80211_is_atim(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ATIM); +} + +static inline int ieee80211_is_assoc_request(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); +} + +static inline int ieee80211_is_assoc_response(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_RESP); +} + +static inline int ieee80211_is_auth(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); +} + +static inline int ieee80211_is_deauth(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); +} + +static inline int ieee80211_is_disassoc(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); +} + +static inline int ieee80211_is_reassoc_request(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ); +} + +static inline int ieee80211_is_reassoc_response(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP); +} + +static inline int iwl_check_bits(unsigned long field, unsigned long mask) +{ + return ((field & mask) == mask) ? 1 : 0; +} + +static inline unsigned long elapsed_jiffies(unsigned long start, + unsigned long end) +{ + if (end > start) + return end - start; + + return end + (MAX_JIFFY_OFFSET - start); +} + +#endif /* __iwl_helpers_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h new file mode 100644 index 000000000000..1aa6fcd39a5e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-hw.h @@ -0,0 +1,537 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwlwifi_hw_h__ +#define __iwlwifi_hw_h__ + +/* + * This file defines hardware constants common to 3945 and 4965. + * + * Device-specific constants are defined in iwl-3945-hw.h and iwl-4965-hw.h, + * although this file contains a few definitions for which the .c + * implementation is the same for 3945 and 4965, except for the value of + * a constant. + * + * uCode API constants are defined in iwl-commands.h. + * + * NOTE: DO NOT PUT OS IMPLEMENTATION-SPECIFIC DECLARATIONS HERE + * + * The iwl-*hw.h (and files they include) files should remain OS/driver + * implementation independent, declaring only the hardware interface. + */ + +/* uCode queue management definitions */ +#define IWL_CMD_QUEUE_NUM 4 +#define IWL_CMD_FIFO_NUM 4 +#define IWL_BACK_QUEUE_FIRST_ID 7 + +/* Tx rates */ +#define IWL_CCK_RATES 4 +#define IWL_OFDM_RATES 8 + +#if IWL == 3945 +#define IWL_HT_RATES 0 +#elif IWL == 4965 +#define IWL_HT_RATES 16 +#endif + +#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES) + +/* Time constants */ +#define SHORT_SLOT_TIME 9 +#define LONG_SLOT_TIME 20 + +/* RSSI to dBm */ +#if IWL == 3945 +#define IWL_RSSI_OFFSET 95 +#elif IWL == 4965 +#define IWL_RSSI_OFFSET 44 +#endif + +#include "iwl-eeprom.h" +#include "iwl-commands.h" + +#define PCI_LINK_CTRL 0x0F0 +#define PCI_POWER_SOURCE 0x0C8 +#define PCI_REG_WUM8 0x0E8 +#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) + +/*=== CSR (control and status registers) ===*/ +#define CSR_BASE (0x000) + +#define CSR_SW_VER (CSR_BASE+0x000) +#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ +#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ +#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ +#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ +#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ +#define CSR_GP_CNTRL (CSR_BASE+0x024) +#define CSR_HW_REV (CSR_BASE+0x028) +#define CSR_EEPROM_REG (CSR_BASE+0x02c) +#define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_GP_UCODE (CSR_BASE+0x044) +#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) +#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) +#define CSR_LED_REG (CSR_BASE+0x094) +#define CSR_DRAM_INT_TBL_CTL (CSR_BASE+0x0A0) +#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) +#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) + +/* HW I/F configuration */ +#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100) +#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200) +#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) +#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) +#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) +#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) +#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) + +/* interrupt flags in INTA, set by uCode or hardware (e.g. dma), + * acknowledged (reset) by host writing "1" to flagged bits. */ +#define CSR_INT_BIT_FH_RX (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */ +#define CSR_INT_BIT_HW_ERR (1<<29) /* DMA hardware error FH_INT[31] */ +#define CSR_INT_BIT_DNLD (1<<28) /* uCode Download */ +#define CSR_INT_BIT_FH_TX (1<<27) /* Tx DMA FH_INT[1:0] */ +#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */ +#define CSR_INT_BIT_SW_ERR (1<<25) /* uCode error */ +#define CSR_INT_BIT_RF_KILL (1<<7) /* HW RFKILL switch GP_CNTRL[27] toggled */ +#define CSR_INT_BIT_CT_KILL (1<<6) /* Critical temp (chip too hot) rfkill */ +#define CSR_INT_BIT_SW_RX (1<<3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_WAKEUP (1<<1) /* NIC controller waking up (pwr mgmt) */ +#define CSR_INT_BIT_ALIVE (1<<0) /* uCode interrupts once it initializes */ + +#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ + CSR_INT_BIT_HW_ERR | \ + CSR_INT_BIT_FH_TX | \ + CSR_INT_BIT_SW_ERR | \ + CSR_INT_BIT_RF_KILL | \ + CSR_INT_BIT_SW_RX | \ + CSR_INT_BIT_WAKEUP | \ + CSR_INT_BIT_ALIVE) + +/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ +#define CSR_FH_INT_BIT_ERR (1<<31) /* Error */ +#define CSR_FH_INT_BIT_HI_PRIOR (1<<30) /* High priority Rx, bypass coalescing */ +#define CSR_FH_INT_BIT_RX_CHNL2 (1<<18) /* Rx channel 2 (3945 only) */ +#define CSR_FH_INT_BIT_RX_CHNL1 (1<<17) /* Rx channel 1 */ +#define CSR_FH_INT_BIT_RX_CHNL0 (1<<16) /* Rx channel 0 */ +#define CSR_FH_INT_BIT_TX_CHNL6 (1<<6) /* Tx channel 6 (3945 only) */ +#define CSR_FH_INT_BIT_TX_CHNL1 (1<<1) /* Tx channel 1 */ +#define CSR_FH_INT_BIT_TX_CHNL0 (1<<0) /* Tx channel 0 */ + +#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL2 | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) + +#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \ + CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0 ) + + +/* RESET */ +#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) +#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) +#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) +#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) +#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) + +/* GP (general purpose) CONTROL */ +#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) +#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) +#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) +#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) + +#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) + +#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) +#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) +#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) + + +/* EEPROM REG */ +#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) +#define CSR_EEPROM_REG_BIT_CMD (0x00000002) + +/* EEPROM GP */ +#define CSR_EEPROM_GP_VALID_MSK (0x00000006) +#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) +#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) + +/* UCODE DRV GP */ +#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) +#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) +#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) +#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) + +/* GPIO */ +#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) +#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) +#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER + +/* 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) + +/* CSR_ANA_PLL_CFG */ +#define CSR_ANA_PLL_CFG_SH (0x00880300) + +#define CSR_LED_REG_TRUN_ON (0x00000078) +#define CSR_LED_REG_TRUN_OFF (0x00000038) +#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) + +/* DRAM_INT_TBL_CTRL */ +#define CSR_DRAM_INT_TBL_CTRL_EN (1<<31) +#define CSR_DRAM_INT_TBL_CTRL_WRAP_CHK (1<<27) + +/*=== HBUS (Host-side Bus) ===*/ +#define HBUS_BASE (0x400) + +#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) +#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) +#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) +#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) +#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) +#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) +#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) +#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) +#define HBUS_TARG_WRPTR (HBUS_BASE+0x060) + +#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) + + +/* SCD (Scheduler) */ +#define SCD_BASE (CSR_BASE + 0x2E00) + +#define SCD_MODE_REG (SCD_BASE + 0x000) +#define SCD_ARASTAT_REG (SCD_BASE + 0x004) +#define SCD_TXFACT_REG (SCD_BASE + 0x010) +#define SCD_TXF4MF_REG (SCD_BASE + 0x014) +#define SCD_TXF5MF_REG (SCD_BASE + 0x020) +#define SCD_SBYP_MODE_1_REG (SCD_BASE + 0x02C) +#define SCD_SBYP_MODE_2_REG (SCD_BASE + 0x030) + +/*=== FH (data Flow Handler) ===*/ +#define FH_BASE (0x800) + +#define FH_CBCC_TABLE (FH_BASE+0x140) +#define FH_TFDB_TABLE (FH_BASE+0x180) +#define FH_RCSR_TABLE (FH_BASE+0x400) +#define FH_RSSR_TABLE (FH_BASE+0x4c0) +#define FH_TCSR_TABLE (FH_BASE+0x500) +#define FH_TSSR_TABLE (FH_BASE+0x680) + +/* TFDB (Transmit Frame Buffer Descriptor) */ +#define FH_TFDB(_channel, buf) \ + (FH_TFDB_TABLE+((_channel)*2+(buf))*0x28) +#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \ + (FH_TFDB_TABLE + 0x50 * _channel) +/* CBCC _channel is [0,2] */ +#define FH_CBCC(_channel) (FH_CBCC_TABLE+(_channel)*0x8) +#define FH_CBCC_CTRL(_channel) (FH_CBCC(_channel)+0x00) +#define FH_CBCC_BASE(_channel) (FH_CBCC(_channel)+0x04) + +/* RCSR _channel is [0,2] */ +#define FH_RCSR(_channel) (FH_RCSR_TABLE+(_channel)*0x40) +#define FH_RCSR_CONFIG(_channel) (FH_RCSR(_channel)+0x00) +#define FH_RCSR_RBD_BASE(_channel) (FH_RCSR(_channel)+0x04) +#define FH_RCSR_WPTR(_channel) (FH_RCSR(_channel)+0x20) +#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24) + +#if IWL == 3945 +#define FH_RSCSR_CHNL0_WPTR (FH_RCSR_WPTR(0)) +#elif IWL == 4965 +#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) +#endif + +/* RSSR */ +#define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000) +#define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004) +/* TCSR */ +#define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20) +#define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00) +#define FH_TCSR_CREDIT(_channel) (FH_TCSR(_channel)+0x04) +#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08) +/* TSSR */ +#define FH_TSSR_CBB_BASE (FH_TSSR_TABLE+0x000) +#define FH_TSSR_MSG_CONFIG (FH_TSSR_TABLE+0x008) +#define FH_TSSR_TX_STATUS (FH_TSSR_TABLE+0x010) +/* 18 - reserved */ + +/* card static random access memory (SRAM) for processor data and instructs */ +#define RTC_INST_LOWER_BOUND (0x000000) +#define RTC_DATA_LOWER_BOUND (0x800000) + + +/* DBM */ + +#define ALM_FH_SRVC_CHNL (6) + +#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE (20) +#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH (4) + +#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN (0x08000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE (0x80000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE (0x20000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 (0x01000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST (0x00001000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH (0x00000000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) + +#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00004000) + +#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005) + +#define ALM_TB_MAX_BYTES_COUNT (0xFFF0) + +#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \ + ((1LU << _channel) << 24) +#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \ + ((1LU << _channel) << 16) + +#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \ + (ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \ + ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel)) +#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */ +#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ + +#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) + +#define TFD_QUEUE_MIN 0 +#define TFD_QUEUE_MAX 6 +#define TFD_QUEUE_SIZE_MAX (256) + +/* spectrum and channel data structures */ +#define IWL_NUM_SCAN_RATES (2) + +#define IWL_SCAN_FLAG_24GHZ (1<<0) +#define IWL_SCAN_FLAG_52GHZ (1<<1) +#define IWL_SCAN_FLAG_ACTIVE (1<<2) +#define IWL_SCAN_FLAG_DIRECT (1<<3) + +#define IWL_MAX_CMD_SIZE 1024 + +#define IWL_DEFAULT_TX_RETRY 15 +#define IWL_MAX_TX_RETRY 16 + +/*********************************************/ + +#define RFD_SIZE 4 +#define NUM_TFD_CHUNKS 4 + +#define RX_QUEUE_SIZE 256 +#define RX_QUEUE_MASK 255 +#define RX_QUEUE_SIZE_LOG 8 + +/* QoS definitions */ + +#define CW_MIN_OFDM 15 +#define CW_MAX_OFDM 1023 +#define CW_MIN_CCK 31 +#define CW_MAX_CCK 1023 + +#define QOS_TX0_CW_MIN_OFDM CW_MIN_OFDM +#define QOS_TX1_CW_MIN_OFDM CW_MIN_OFDM +#define QOS_TX2_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 2 - 1) +#define QOS_TX3_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 4 - 1) + +#define QOS_TX0_CW_MIN_CCK CW_MIN_CCK +#define QOS_TX1_CW_MIN_CCK CW_MIN_CCK +#define QOS_TX2_CW_MIN_CCK ((CW_MIN_CCK + 1) / 2 - 1) +#define QOS_TX3_CW_MIN_CCK ((CW_MIN_CCK + 1) / 4 - 1) + +#define QOS_TX0_CW_MAX_OFDM CW_MAX_OFDM +#define QOS_TX1_CW_MAX_OFDM CW_MAX_OFDM +#define QOS_TX2_CW_MAX_OFDM CW_MIN_OFDM +#define QOS_TX3_CW_MAX_OFDM ((CW_MIN_OFDM + 1) / 2 - 1) + +#define QOS_TX0_CW_MAX_CCK CW_MAX_CCK +#define QOS_TX1_CW_MAX_CCK CW_MAX_CCK +#define QOS_TX2_CW_MAX_CCK CW_MIN_CCK +#define QOS_TX3_CW_MAX_CCK ((CW_MIN_CCK + 1) / 2 - 1) + +#define QOS_TX0_AIFS 3 +#define QOS_TX1_AIFS 7 +#define QOS_TX2_AIFS 2 +#define QOS_TX3_AIFS 2 + +#define QOS_TX0_ACM 0 +#define QOS_TX1_ACM 0 +#define QOS_TX2_ACM 0 +#define QOS_TX3_ACM 0 + +#define QOS_TX0_TXOP_LIMIT_CCK 0 +#define QOS_TX1_TXOP_LIMIT_CCK 0 +#define QOS_TX2_TXOP_LIMIT_CCK 6016 +#define QOS_TX3_TXOP_LIMIT_CCK 3264 + +#define QOS_TX0_TXOP_LIMIT_OFDM 0 +#define QOS_TX1_TXOP_LIMIT_OFDM 0 +#define QOS_TX2_TXOP_LIMIT_OFDM 3008 +#define QOS_TX3_TXOP_LIMIT_OFDM 1504 + +#define DEF_TX0_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX1_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX2_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX3_CW_MIN_OFDM CW_MIN_OFDM + +#define DEF_TX0_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX1_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX2_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX3_CW_MIN_CCK CW_MIN_CCK + +#define DEF_TX0_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX1_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX2_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX3_CW_MAX_OFDM CW_MAX_OFDM + +#define DEF_TX0_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX1_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX2_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX3_CW_MAX_CCK CW_MAX_CCK + +#define DEF_TX0_AIFS (2) +#define DEF_TX1_AIFS (2) +#define DEF_TX2_AIFS (2) +#define DEF_TX3_AIFS (2) + +#define DEF_TX0_ACM 0 +#define DEF_TX1_ACM 0 +#define DEF_TX2_ACM 0 +#define DEF_TX3_ACM 0 + +#define DEF_TX0_TXOP_LIMIT_CCK 0 +#define DEF_TX1_TXOP_LIMIT_CCK 0 +#define DEF_TX2_TXOP_LIMIT_CCK 0 +#define DEF_TX3_TXOP_LIMIT_CCK 0 + +#define DEF_TX0_TXOP_LIMIT_OFDM 0 +#define DEF_TX1_TXOP_LIMIT_OFDM 0 +#define DEF_TX2_TXOP_LIMIT_OFDM 0 +#define DEF_TX3_TXOP_LIMIT_OFDM 0 + +#define QOS_QOS_SETS 3 +#define QOS_PARAM_SET_ACTIVE 0 +#define QOS_PARAM_SET_DEF_CCK 1 +#define QOS_PARAM_SET_DEF_OFDM 2 + +#define CTRL_QOS_NO_ACK (0x0020) +#define DCT_FLAG_EXT_QOS_ENABLED (0x10) + +#define U32_PAD(n) ((4-(n))&0x3) + +/* + * Generic queue structure + * + * Contains common data for Rx and Tx queues + */ +#define TFD_CTL_COUNT_SET(n) (n<<24) +#define TFD_CTL_COUNT_GET(ctl) ((ctl>>24) & 7) +#define TFD_CTL_PAD_SET(n) (n<<28) +#define TFD_CTL_PAD_GET(ctl) (ctl>>28) + +#define TFD_TX_CMD_SLOTS 256 +#define TFD_CMD_SLOTS 32 + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ + sizeof(struct iwl_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +#endif /* __iwlwifi_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h new file mode 100644 index 000000000000..8a8b96fcf48d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -0,0 +1,470 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_io_h__ +#define __iwl_io_h__ + +#include + +#include "iwl-debug.h" + +/* + * IO, register, and NIC memory access functions + * + * NOTE on naming convention and macro usage for these + * + * A single _ prefix before a an access function means that no state + * check or debug information is printed when that function is called. + * + * A double __ prefix before an access function means that state is checked + * (in the case of *restricted calls) and the current line number is printed + * in addition to any other debug output. + * + * The non-prefixed name is the #define that maps the caller into a + * #define that provides the caller's __LINE__ to the double prefix version. + * + * If you wish to call the function without any debug or state checking, + * you should use the single _ prefix version (as is used by dependent IO + * routines, for example _iwl_read_restricted calls the non-check version of + * _iwl_read32.) + * + * These declarations are *extremely* useful in quickly isolating code deltas + * which result in misconfiguring of the hardware I/O. In combination with + * git-bisect and the IO debug level you can quickly determine the specific + * commit which breaks the IO sequence to the hardware. + * + */ + +#define _iwl_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *iwl, + u32 ofs, u32 val) +{ + IWL_DEBUG_IO("write_direct32(0x%08X, 0x%08X) - %s %d\n", + (u32) (ofs), (u32) (val), f, l); + _iwl_write32(iwl, ofs, val); +} +#define iwl_write32(iwl, ofs, val) \ + __iwl_write32(__FILE__, __LINE__, iwl, ofs, val) +#else +#define iwl_write32(iwl, ofs, val) _iwl_write32(iwl, ofs, val) +#endif + +#define _iwl_read32(iwl, ofs) readl((iwl)->hw_base + (ofs)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *iwl, u32 ofs) +{ + IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); + return _iwl_read32(iwl, ofs); +} +#define iwl_read32(iwl, ofs) __iwl_read32(__FILE__, __LINE__, iwl, ofs) +#else +#define iwl_read32(p, o) _iwl_read32(p, o) +#endif + +static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_poll_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int rc = _iwl_poll_bit(priv, addr, bits, mask, timeout); + if (unlikely(rc == -ETIMEDOUT)) + IWL_DEBUG_IO + ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n", + addr, bits, mask, f, l); + else + IWL_DEBUG_IO + ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n", + addr, bits, mask, rc, f, l); + return rc; +} +#define iwl_poll_bit(iwl, addr, bits, mask, timeout) \ + __iwl_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout) +#else +#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) +#endif + +static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read32(priv, reg) | mask; + IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl_write32(priv, reg, val); +} +#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m) +#endif + +static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_clear_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read32(priv, reg) & ~mask; + IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl_write32(priv, reg, val); +} +#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m) +#endif + +static inline int _iwl_grab_restricted_access(struct iwl_priv *priv) +{ + int rc; + u32 gp_ctl; + +#ifdef CONFIG_IWLWIFI_DEBUG + if (atomic_read(&priv->restrict_refcnt)) + return 0; +#endif + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("WARNING: Requesting MAC access during RFKILL " + "wakes up NIC\n"); + + /* 10 msec allows time for NIC to complete its data save */ + gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL); + if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { + IWL_DEBUG_RF_KILL("Wait for complete power-down, " + "gpctl = 0x%08x\n", gp_ctl); + mdelay(10); + } else + IWL_DEBUG_RF_KILL("power-down complete, " + "gpctl = 0x%08x\n", gp_ctl); + } + + /* this bit wakes up the NIC */ + _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + rc = _iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50); + if (rc < 0) { + IWL_ERROR("MAC is in deep sleep!\n"); + return -EIO; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + atomic_inc(&priv->restrict_refcnt); +#endif + return 0; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_grab_restricted_access(const char *f, u32 l, + struct iwl_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt)) + IWL_DEBUG_INFO("Grabbing access while already held at " + "line %d.\n", l); + + IWL_DEBUG_IO("grabbing restricted access - %s %d\n", f, l); + + return _iwl_grab_restricted_access(priv); +} +#define iwl_grab_restricted_access(priv) \ + __iwl_grab_restricted_access(__FILE__, __LINE__, priv) +#else +#define iwl_grab_restricted_access(priv) \ + _iwl_grab_restricted_access(priv) +#endif + +static inline void _iwl_release_restricted_access(struct iwl_priv *priv) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + if (atomic_dec_and_test(&priv->restrict_refcnt)) +#endif + _iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_release_restricted_access(const char *f, u32 l, + struct iwl_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt) <= 0) + IWL_ERROR("Release unheld restricted access at line %d.\n", l); + + IWL_DEBUG_IO("releasing restricted access - %s %d\n", f, l); + _iwl_release_restricted_access(priv); +} +#define iwl_release_restricted_access(priv) \ + __iwl_release_restricted_access(__FILE__, __LINE__, priv) +#else +#define iwl_release_restricted_access(priv) \ + _iwl_release_restricted_access(priv) +#endif + +static inline u32 _iwl_read_restricted(struct iwl_priv *priv, u32 reg) +{ + return _iwl_read32(priv, reg); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read_restricted(const char *f, u32 l, + struct iwl_priv *priv, u32 reg) +{ + u32 value = _iwl_read_restricted(priv, reg); + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from %s %d\n", f, l); + IWL_DEBUG_IO("read_restricted(0x%4X) = 0x%08x - %s %d \n", reg, value, + f, l); + return value; +} +#define iwl_read_restricted(priv, reg) \ + __iwl_read_restricted(__FILE__, __LINE__, priv, reg) +#else +#define iwl_read_restricted _iwl_read_restricted +#endif + +static inline void _iwl_write_restricted(struct iwl_priv *priv, + u32 reg, u32 value) +{ + _iwl_write32(priv, reg, value); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static void __iwl_write_restricted(u32 line, + struct iwl_priv *priv, u32 reg, u32 value) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + _iwl_write_restricted(priv, reg, value); +} +#define iwl_write_restricted(priv, reg, value) \ + __iwl_write_restricted(__LINE__, priv, reg, value) +#else +#define iwl_write_restricted _iwl_write_restricted +#endif + +static inline void iwl_write_buffer_restricted(struct iwl_priv *priv, + u32 reg, u32 len, u32 *values) +{ + u32 count = sizeof(u32); + + if ((priv != NULL) && (values != NULL)) { + for (; 0 < len; len -= count, reg += count, values++) + _iwl_write_restricted(priv, reg, *values); + } +} + +static inline int _iwl_poll_restricted_bit(struct iwl_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl_read_restricted(priv, addr) & mask) == mask) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_poll_restricted_bit(const char *f, u32 l, + struct iwl_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int rc = _iwl_poll_restricted_bit(priv, addr, mask, timeout); + + if (unlikely(rc == -ETIMEDOUT)) + IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) - " + "timedout - %s %d\n", addr, mask, f, l); + else + IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X " + "- %s %d\n", addr, mask, rc, f, l); + return rc; +} +#define iwl_poll_restricted_bit(iwl, addr, mask, timeout) \ + __iwl_poll_restricted_bit(__FILE__, __LINE__, iwl, addr, mask, timeout) +#else +#define iwl_poll_restricted_bit _iwl_poll_restricted_bit +#endif + +static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg) +{ + _iwl_write_restricted(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + return _iwl_read_restricted(priv, HBUS_TARG_PRPH_RDAT); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read_restricted_reg(u32 line, + struct iwl_priv *priv, u32 reg) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + return _iwl_read_restricted_reg(priv, reg); +} + +#define iwl_read_restricted_reg(priv, reg) \ + __iwl_read_restricted_reg(__LINE__, priv, reg) +#else +#define iwl_read_restricted_reg _iwl_read_restricted_reg +#endif + +static inline void _iwl_write_restricted_reg(struct iwl_priv *priv, + u32 addr, u32 val) +{ + _iwl_write_restricted(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, val); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_write_restricted_reg(u32 line, + struct iwl_priv *priv, + u32 addr, u32 val) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + _iwl_write_restricted_reg(priv, addr, val); +} + +#define iwl_write_restricted_reg(priv, addr, val) \ + __iwl_write_restricted_reg(__LINE__, priv, addr, val); +#else +#define iwl_write_restricted_reg _iwl_write_restricted_reg +#endif + +#define _iwl_set_bits_restricted_reg(priv, reg, mask) \ + _iwl_write_restricted_reg(priv, reg, \ + (_iwl_read_restricted_reg(priv, reg) | mask)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bits_restricted_reg(u32 line, struct iwl_priv + *priv, u32 reg, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + _iwl_set_bits_restricted_reg(priv, reg, mask); +} +#define iwl_set_bits_restricted_reg(priv, reg, mask) \ + __iwl_set_bits_restricted_reg(__LINE__, priv, reg, mask) +#else +#define iwl_set_bits_restricted_reg _iwl_set_bits_restricted_reg +#endif + +#define _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \ + _iwl_write_restricted_reg( \ + priv, reg, ((_iwl_read_restricted_reg(priv, reg) & mask) | bits)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bits_mask_restricted_reg(u32 line, + struct iwl_priv *priv, u32 reg, u32 bits, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask); +} + +#define iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \ + __iwl_set_bits_mask_restricted_reg(__LINE__, priv, reg, bits, mask) +#else +#define iwl_set_bits_mask_restricted_reg _iwl_set_bits_mask_restricted_reg +#endif + +static inline void iwl_clear_bits_restricted_reg(struct iwl_priv + *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read_restricted_reg(priv, reg); + _iwl_write_restricted_reg(priv, reg, (val & ~mask)); +} + +static inline u32 iwl_read_restricted_mem(struct iwl_priv *priv, u32 addr) +{ + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, addr); + return iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); +} + +static inline void iwl_write_restricted_mem(struct iwl_priv *priv, u32 addr, + u32 val) +{ + iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr); + iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, val); +} + +static inline void iwl_write_restricted_mems(struct iwl_priv *priv, u32 addr, + u32 len, u32 *values) +{ + iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr); + for (; 0 < len; len -= sizeof(u32), values++) + iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, *values); +} + +static inline void iwl_write_restricted_regs(struct iwl_priv *priv, u32 reg, + u32 len, u8 *values) +{ + u32 reg_offset = reg; + u32 aligment = reg & 0x3; + + /* write any non-dword-aligned stuff at the beginning */ + if (len < sizeof(u32)) { + if ((aligment + len) <= sizeof(u32)) { + u8 size; + u32 value = 0; + size = len - 1; + memcpy(&value, values, len); + reg_offset = (reg_offset & 0x0000FFFF); + + _iwl_write_restricted(priv, + HBUS_TARG_PRPH_WADDR, + (reg_offset | (size << 24))); + _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, + value); + } + + return; + } + + /* now write all the dword-aligned stuff */ + for (; reg_offset < (reg + len); + reg_offset += sizeof(u32), values += sizeof(u32)) + _iwl_write_restricted_reg(priv, reg_offset, *((u32 *) values)); +} + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-priv.h b/drivers/net/wireless/iwlwifi/iwl-priv.h new file mode 100644 index 000000000000..6b490d08fea9 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-priv.h @@ -0,0 +1,308 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_priv_h__ +#define __iwl_priv_h__ + +#include + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +enum { + MEASUREMENT_READY = (1 << 0), + MEASUREMENT_ACTIVE = (1 << 1), +}; + +#endif + +struct iwl_priv { + + /* ieee device used by generic ieee processing code */ + struct ieee80211_hw *hw; + struct ieee80211_channel *ieee_channels; + struct ieee80211_rate *ieee_rates; + + /* temporary frame storage list */ + struct list_head free_frames; + int frames_count; + + u8 phymode; + int alloc_rxb_skb; + + void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); + + const struct ieee80211_hw_mode *modes; + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + /* spectrum measurement report caching */ + struct iwl_spectrum_notification measure_report; + u8 measurement_status; +#endif + /* ucode beacon time */ + u32 ucode_beacon_time; + + /* we allocate array of iwl_channel_info for NIC's valid channels. + * Access via channel # using indirect index array */ + struct iwl_channel_info *channel_info; /* channel info array */ + u8 channel_count; /* # of channels */ + + /* each calibration channel group in the EEPROM has a derived + * clip setting for each rate. */ + const struct iwl_clip_group clip_groups[5]; + + /* thermal calibration */ + s32 temperature; /* degrees Kelvin */ + s32 last_temperature; + + /* Scan related variables */ + unsigned long last_scan_jiffies; + unsigned long scan_start; + unsigned long scan_pass_start; + unsigned long scan_start_tsf; + int scan_bands; + int one_direct_scan; + u8 direct_ssid_len; + u8 direct_ssid[IW_ESSID_MAX_SIZE]; + struct iwl_scan_cmd *scan; + u8 only_active_channel; + + /* spinlock */ + spinlock_t lock; /* protect general shared data */ + spinlock_t hcmd_lock; /* protect hcmd */ + struct mutex mutex; + + /* basic pci-network driver stuff */ + struct pci_dev *pci_dev; + + /* pci hardware address support */ + void __iomem *hw_base; + + /* uCode images, save to reload in case of failure */ + struct fw_image_desc ucode_code; /* runtime inst */ + struct fw_image_desc ucode_data; /* runtime data original */ + struct fw_image_desc ucode_data_backup; /* runtime data save/restore */ + struct fw_image_desc ucode_init; /* initialization inst */ + struct fw_image_desc ucode_init_data; /* initialization data */ + struct fw_image_desc ucode_boot; /* bootstrap inst */ + + + struct iwl_rxon_time_cmd rxon_timing; + + /* We declare this const so it can only be + * changed via explicit cast within the + * routines that actually update the physical + * hardware */ + const struct iwl_rxon_cmd active_rxon; + struct iwl_rxon_cmd staging_rxon; + + int error_recovering; + struct iwl_rxon_cmd recovery_rxon; + + /* 1st responses from initialize and runtime uCode images. + * 4965's initialize alive response contains some calibration data. */ + struct iwl_init_alive_resp card_alive_init; + struct iwl_alive_resp card_alive; + +#ifdef LED + /* LED related variables */ + struct iwl_activity_blink activity; + unsigned long led_packets; + int led_state; +#endif + + u16 active_rate; + u16 active_rate_basic; + + u8 call_post_assoc_from_beacon; + u8 assoc_station_added; +#if IWL == 4965 + u8 use_ant_b_for_management_frame; /* Tx antenna selection */ + /* HT variables */ + u8 is_dup; + u8 is_ht_enabled; + u8 channel_width; /* 0=20MHZ, 1=40MHZ */ + u8 current_channel_width; + u8 valid_antenna; /* Bit mask of antennas actually connected */ +#ifdef CONFIG_IWLWIFI_SENSITIVITY + struct iwl_sensitivity_data sensitivity_data; + struct iwl_chain_noise_data chain_noise_data; + u8 start_calib; + __le16 sensitivity_tbl[HD_TABLE_SIZE]; +#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ + +#ifdef CONFIG_IWLWIFI_HT + struct sta_ht_info current_assoc_ht; +#endif + u8 active_rate_ht[2]; + u8 last_phy_res[100]; + + /* Rate scaling data */ + struct iwl_lq_mngr lq_mngr; +#endif + + /* Rate scaling data */ + s8 data_retry_limit; + u8 retry_rate; + + wait_queue_head_t wait_command_queue; + + int activity_timer_active; + + /* Rx and Tx DMA processing queues */ + struct iwl_rx_queue rxq; + struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; +#if IWL == 4965 + unsigned long txq_ctx_active_msk; + struct iwl_kw kw; /* keep warm address */ + u32 scd_base_addr; /* scheduler sram base address */ +#endif + + unsigned long status; + u32 config; + + int last_rx_rssi; /* From Rx packet statisitics */ + int last_rx_noise; /* From beacon statistics */ + + struct iwl_power_mgr power_data; + + struct iwl_notif_statistics statistics; + unsigned long last_statistics_time; + + /* context information */ + u8 essid[IW_ESSID_MAX_SIZE]; + u8 essid_len; + u16 rates_mask; + + u32 power_mode; + u32 antenna; + u8 bssid[ETH_ALEN]; + u16 rts_threshold; + u8 mac_addr[ETH_ALEN]; + + /*station table variables */ + spinlock_t sta_lock; + int num_stations; + struct iwl_station_entry stations[IWL_STATION_COUNT]; + + /* Indication if ieee80211_ops->open has been called */ + int is_open; + + u8 mac80211_registered; + int is_abg; + + u32 notif_missed_beacons; + + /* Rx'd packet timing information */ + u32 last_beacon_time; + u64 last_tsf; + + /* Duplicate packet detection */ + u16 last_seq_num; + u16 last_frag_num; + unsigned long last_packet_time; + struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; + + /* eeprom */ + struct iwl_eeprom eeprom; + + int iw_mode; + + struct sk_buff *ibss_beacon; + + /* Last Rx'd beacon timestamp */ + u32 timestamp0; + u32 timestamp1; + u16 beacon_int; + struct iwl_driver_hw_info hw_setting; + int interface_id; + + /* Current association information needed to configure the + * hardware */ + u16 assoc_id; + u16 assoc_capability; + u8 ps_mode; + +#ifdef CONFIG_IWLWIFI_QOS + struct iwl_qos_info qos_data; +#endif /*CONFIG_IWLWIFI_QOS */ + + struct workqueue_struct *workqueue; + + struct work_struct up; + struct work_struct restart; + struct work_struct calibrated_work; + struct work_struct scan_completed; + struct work_struct rx_replenish; + struct work_struct rf_kill; + struct work_struct abort_scan; + struct work_struct update_link_led; + struct work_struct auth_work; + struct work_struct report_work; + struct work_struct request_scan; + struct work_struct beacon_update; + + struct tasklet_struct irq_tasklet; + + struct delayed_work init_alive_start; + struct delayed_work alive_start; + struct delayed_work activity_timer; + struct delayed_work thermal_periodic; + struct delayed_work gather_stats; + struct delayed_work scan_check; + struct delayed_work post_associate; + +#define IWL_DEFAULT_TX_POWER 0x0F + s8 user_txpower_limit; + s8 max_channel_txpower_limit; + u32 cck_power_index_compensation; + +#ifdef CONFIG_PM + u32 pm_state[16]; +#endif + +#ifdef CONFIG_IWLWIFI_DEBUG + /* debugging info */ + u32 framecnt_to_us; + atomic_t restrict_refcnt; +#endif + +#if IWL == 4965 + struct work_struct txpower_work; +#ifdef CONFIG_IWLWIFI_SENSITIVITY + struct work_struct sensitivity_work; +#endif + struct work_struct statistics_work; + struct timer_list statistics_periodic; + +#ifdef CONFIG_IWLWIFI_HT_AGG + struct work_struct agg_work; +#endif + +#endif /* 4965 */ +}; /*iwl_priv */ + +#endif /* __iwl_priv_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h new file mode 100644 index 000000000000..0df41148eadc --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_prph_h__ +#define __iwl_prph_h__ + + +#define PRPH_BASE (0x00000) +#define PRPH_END (0xFFFFF) + +/* APMG (power management) constants */ +#define APMG_BASE (PRPH_BASE + 0x3000) +#define APMG_CLK_CTRL_REG (APMG_BASE + 0x0000) +#define APMG_CLK_EN_REG (APMG_BASE + 0x0004) +#define APMG_CLK_DIS_REG (APMG_BASE + 0x0008) +#define APMG_PS_CTRL_REG (APMG_BASE + 0x000c) +#define APMG_PCIDEV_STT_REG (APMG_BASE + 0x0010) +#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_CLK_VAL_DMA_CLK_RQT (0x00000200) +#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) + +#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) + +#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) + +#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) +#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) +#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x01000000) + + +/** + * BSM (Bootstrap State Machine) + * + * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program + * in special SRAM that does not power down when the embedded control + * processor is sleeping (e.g. for periodic power-saving shutdowns of radio). + * + * When powering back up after sleeps (or during initial uCode load), the BSM + * internally loads the short bootstrap program from the special SRAM into the + * embedded processor's instruction SRAM, and starts the processor so it runs + * the bootstrap program. + * + * This bootstrap program loads (via PCI busmaster DMA) instructions and data + * images for a uCode program from host DRAM locations. The host driver + * indicates DRAM locations and sizes for instruction and data images via the + * four BSM_DRAM_* registers. Once the bootstrap program loads the new program, + * the new program starts automatically. + * + * The uCode used for open-source drivers includes two programs: + * + * 1) Initialization -- performs hardware calibration and sets up some + * internal data, then notifies host via "initialize alive" notification + * (struct iwl_init_alive_resp) that it has completed all of its work. + * After signal from host, it then loads and starts the runtime program. + * The initialization program must be used when initially setting up the + * NIC after loading the driver. + * + * 2) Runtime/Protocol -- performs all normal runtime operations. This + * notifies host via "alive" notification (struct iwl_alive_resp) that it + * is ready to be used. + * + * When initializing the NIC, the host driver does the following procedure: + * + * 1) Load bootstrap program (instructions only, no data image for bootstrap) + * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND + * + * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction + * images in host DRAM. + * + * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked: + * BSM_WR_MEM_SRC_REG = 0 + * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND + * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image + * + * 4) Load bootstrap into instruction SRAM: + * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START + * + * 5) Wait for load completion: + * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0 + * + * 6) Enable future boot loads whenever NIC's power management triggers it: + * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN + * + * 7) Start the NIC by removing all reset bits: + * CSR_RESET = 0 + * + * The bootstrap uCode (already in instruction SRAM) loads initialization + * uCode. Initialization uCode performs data initialization, sends + * "initialize alive" notification to host, and waits for a signal from + * host to load runtime code. + * + * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction + * images in host DRAM. The last register loaded must be the instruction + * bytecount register ("1" in MSbit tells initialization uCode to load + * the runtime uCode): + * BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD + * + * 5) Wait for "alive" notification, then issue normal runtime commands. + * + * Data caching during power-downs: + * + * Just before the embedded controller powers down (e.g for automatic + * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA) + * a current snapshot of the embedded processor's data SRAM into host DRAM. + * This caches the data while the embedded processor's memory is powered down. + * Location and size are controlled by BSM_DRAM_DATA_* registers. + * + * NOTE: Instruction SRAM does not need to be saved, since that doesn't + * change during operation; the original image (from uCode distribution + * file) can be used for reload. + * + * When powering back up, the BSM loads the bootstrap program. Bootstrap looks + * at the BSM_DRAM_* registers, which now point to the runtime instruction + * image and the cached (modified) runtime data (*not* the initialization + * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the + * uCode from where it left off before the power-down. + * + * NOTE: Initialization uCode does *not* run as part of the save/restore + * procedure. + * + * This save/restore method is mostly for autonomous power management during + * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and + * RFKILL should use complete restarts (with total re-initialization) of uCode, + * allowing total shutdown (including BSM memory). + * + * Note that, during normal operation, the host DRAM that held the initial + * startup data for the runtime code is now being used as a backup data cache + * for modified data! If you need to completely re-initialize the NIC, make + * sure that you use the runtime data image from the uCode distribution file, + * not the modified/saved runtime data. You may want to store a separate + * "clean" runtime data image in DRAM to avoid disk reads of distribution file. + */ + +/* BSM bit fields */ +#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */ +#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/ +#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */ + +/* BSM addresses */ +#define BSM_BASE (PRPH_BASE + 0x3400) +#define BSM_END (PRPH_BASE + 0x3800) + +#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */ +#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */ +#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */ +#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */ +#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */ + +/* + * Pointers and size regs for bootstrap load and data SRAM save/restore. + * NOTE: 3945 pointers use bits 31:0 of DRAM address. + * 4965 pointers use bits 35:4 of DRAM address. + */ +#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090) +#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094) +#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098) +#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C) + +/* + * BSM special memory, stays powered on during power-save sleeps. + * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1) + */ +#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800) +#define BSM_SRAM_SIZE (1024) /* bytes */ + + +#endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h new file mode 100644 index 000000000000..b576ff24eb4f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -0,0 +1,91 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_spectrum_h__ +#define __iwl_spectrum_h__ +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_info_element { + u8 id; + u8 len; + u8 data[0]; +} __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)); +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c new file mode 100644 index 000000000000..474b6402040c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -0,0 +1,8732 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +/* + * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets + * by defining IWL to either 3945 or 4965. The Makefile used when building + * the base targets will create base-3945.o and base-4965.o + * + * The eventual goal is to move as many of the #if IWL / #endif blocks out of + * this file and into the hardware specific implementation files (iwl-XXXX.c) + * and leave only the common (non #ifdef sprinkled) code in this file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "iwlwifi.h" +#include "iwl-3945.h" +#include "iwl-helpers.h" + +#ifdef CONFIG_IWLWIFI_DEBUG +u32 iwl_debug_level; +#endif + +/****************************************************************************** + * + * module boiler plate + * + ******************************************************************************/ + +/* module parameters */ +int iwl_param_disable_hw_scan; +int iwl_param_debug; +int iwl_param_disable; /* def: enable radio */ +int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */ +int iwl_param_hwcrypto; /* def: using software encryption */ +int iwl_param_qos_enable = 1; +int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; + +/* + * module name, copyright, version, etc. + * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk + */ + +#define DRV_DESCRIPTION \ +"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux" + +#ifdef CONFIG_IWLWIFI_DEBUG +#define VD "d" +#else +#define VD +#endif + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#define VS "s" +#else +#define VS +#endif + +#define IWLWIFI_VERSION "0.1.15k" VD VS +#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" +#define DRV_VERSION IWLWIFI_VERSION + +/* Change firmware file name, using "-" and incrementing number, + * *only* when uCode interface or architecture changes so that it + * is not compatible with earlier drivers. + * This number will also appear in << 8 position of 1st dword of uCode file */ +#define IWL3945_UCODE_API "-1" + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + int hdr_len = ieee80211_get_hdrlen(fc); + + if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) + return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); + return NULL; +} + +static const struct ieee80211_hw_mode *iwl_get_hw_mode( + struct iwl_priv *priv, int mode) +{ + int i; + + for (i = 0; i < 3; i++) + if (priv->modes[i].mode == mode) + return &priv->modes[i]; + + return NULL; +} + +static int iwl_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + +static const char *iwl_escape_essid(const char *essid, u8 essid_len) +{ + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (iwl_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "", sizeof("")); + return escaped; + } + + essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else + *d++ = *s++; + } + *d = '\0'; + return escaped; +} + +static void iwl_print_hex_dump(int level, void *p, u32 len) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_debug_level & level)) + return; + + print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, + p, len, 1); +#endif +} + +/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** + * DMA services + * + * Theory of operation + * + * A queue is a circular buffers with 'Read' and 'Write' pointers. + * 2 empty entries always kept in the buffer to protect from overflow. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + * The IPW operates with six queues, one receive queue in the device's + * sram, one transmit queue for sending commands to the device firmware, + * and four transmit queues for data. + ***************************************************/ + +static int iwl_queue_space(const struct iwl_queue *q) +{ + int s = q->last_used - q->first_empty; + + if (q->last_used > q->first_empty) + s -= q->n_bd; + + if (s <= 0) + s += q->n_window; + /* keep some reserve to not confuse empty and full situations */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/* XXX: n_bd must be power-of-two size */ +static inline int iwl_queue_inc_wrap(int index, int n_bd) +{ + return ++index & (n_bd - 1); +} + +/* XXX: n_bd must be power-of-two size */ +static inline int iwl_queue_dec_wrap(int index, int n_bd) +{ + return --index & (n_bd - 1); +} + +static inline int x2_queue_used(const struct iwl_queue *q, int i) +{ + return q->first_empty > q->last_used ? + (i >= q->last_used && i < q->first_empty) : + !(i < q->last_used && i >= q->first_empty); +} + +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +{ + if (is_huge) + return q->n_window; + + return index & (q->n_window - 1); +} + +static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, + int count, int slots_num, u32 id) +{ + q->n_bd = count; + q->n_window = slots_num; + q->id = id; + + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ + BUG_ON(!is_power_of_2(count)); + + /* slots_num must be power-of-two size, otherwise + * get_cmd_index is broken. */ + BUG_ON(!is_power_of_2(slots_num)); + + q->low_mark = q->n_window / 4; + if (q->low_mark < 4) + q->low_mark = 4; + + q->high_mark = q->n_window / 8; + if (q->high_mark < 2) + q->high_mark = 2; + + q->first_empty = q->last_used = 0; + + return 0; +} + +static int iwl_tx_queue_alloc(struct iwl_priv *priv, + struct iwl_tx_queue *txq, u32 id) +{ + struct pci_dev *dev = priv->pci_dev; + + if (id != IWL_CMD_QUEUE_NUM) { + txq->txb = kmalloc(sizeof(txq->txb[0]) * + TFD_QUEUE_SIZE_MAX, GFP_KERNEL); + if (!txq->txb) { + IWL_ERROR("kmalloc for auxilary BD " + "structures failed\n"); + goto error; + } + } else + txq->txb = NULL; + + txq->bd = pci_alloc_consistent(dev, + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + &txq->q.dma_addr); + + if (!txq->bd) { + IWL_ERROR("pci_alloc_consistent(%zd) failed\n", + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + goto error; + } + txq->q.id = id; + + return 0; + + error: + if (txq->txb) { + kfree(txq->txb); + txq->txb = NULL; + } + + return -ENOMEM; +} + +int iwl_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq, int slots_num, u32 txq_id) +{ + struct pci_dev *dev = priv->pci_dev; + int len; + int rc = 0; + + /* alocate command space + one big command for scan since scan + * command is very huge the system will not have two scan at the + * same time */ + len = sizeof(struct iwl_cmd) * slots_num; + if (txq_id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); + if (!txq->cmd) + return -ENOMEM; + + rc = iwl_tx_queue_alloc(priv, txq, txq_id); + if (rc) { + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + return -ENOMEM; + } + txq->need_update = 0; + + /* 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)); + iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + + iwl_hw_tx_queue_init(priv, txq); + + return 0; +} + +/** + * iwl_tx_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. txq itself is not freed. + * + */ +void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int len; + + if (q->n_bd == 0) + return; + + /* first, empty all BD's */ + for (; q->first_empty != q->last_used; + q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) + iwl_hw_txq_free_tfd(priv, txq); + + len = sizeof(struct iwl_cmd) * q->n_window; + if (q->id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + /* free buffers belonging to queue itself */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + txq->q.n_bd, txq->bd, txq->q.dma_addr); + + if (txq->txb) { + kfree(txq->txb); + txq->txb = NULL; + } + + /* 0 fill whole structure */ + memset(txq, 0, sizeof(*txq)); +} + +const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +/*************** STATION TABLE MANAGEMENT **** + * + * NOTE: This needs to be overhauled to better synchronize between + * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c + * + * mac80211 should also be examined to determine if sta_info is duplicating + * the functionality provided here + */ + +/**************************************************************/ +static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int index = IWL_INVALID_STATION; + int i; + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_setting.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + if (priv->stations[i].used && + !compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (unlikely(index == IWL_INVALID_STATION)) + goto out; + + if (priv->stations[index].used) { + priv->stations[index].used = 0; + priv->num_stations--; + } + + BUG_ON(priv->num_stations < 0); + +out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; +} + +static void iwl_clear_stations_table(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + + +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) +{ + int i; + int index = IWL_INVALID_STATION; + struct iwl_station_entry *station; + unsigned long flags_spin; + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_setting.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) { + if (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (!priv->stations[i].used && + index == IWL_INVALID_STATION) + index = i; + } + + /* These twh conditions has the same outcome but keep them separate + since they have different meaning */ + if (unlikely(index == IWL_INVALID_STATION)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + if (priv->stations[index].used && + !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + IWL_DEBUG_ASSOC("Add STA ID %d: " MAC_FMT "\n", index, MAC_ARG(addr)); + station = &priv->stations[index]; + station->used = 1; + priv->num_stations++; + + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + memcpy(station->sta.sta.addr, addr, ETH_ALEN); + station->sta.mode = 0; + station->sta.sta.sta_id = index; + station->sta.station_flags = 0; + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + iwl_send_add_station(priv, &station->sta, flags); + return index; + +} + +/*************** DRIVER STATUS FUNCTIONS *****/ + +static inline int iwl_is_ready(struct iwl_priv *priv) +{ + /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are + * set but EXIT_PENDING is not */ + return test_bit(STATUS_READY, &priv->status) && + test_bit(STATUS_GEO_CONFIGURED, &priv->status) && + !test_bit(STATUS_EXIT_PENDING, &priv->status); +} + +static inline int iwl_is_alive(struct iwl_priv *priv) +{ + return test_bit(STATUS_ALIVE, &priv->status); +} + +static inline int iwl_is_init(struct iwl_priv *priv) +{ + return test_bit(STATUS_INIT, &priv->status); +} + +static inline int iwl_is_rfkill(struct iwl_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +static inline int iwl_is_ready_rf(struct iwl_priv *priv) +{ + + if (iwl_is_rfkill(priv)) + return 0; + + return iwl_is_ready(priv); +} + +/*************** HOST COMMAND QUEUE FUNCTIONS *****/ + +#define IWL_CMD(x) case x : return #x + +static const char *get_cmd_string(u8 cmd) +{ + switch (cmd) { + IWL_CMD(REPLY_ALIVE); + IWL_CMD(REPLY_ERROR); + IWL_CMD(REPLY_RXON); + IWL_CMD(REPLY_RXON_ASSOC); + IWL_CMD(REPLY_QOS_PARAM); + IWL_CMD(REPLY_RXON_TIMING); + IWL_CMD(REPLY_ADD_STA); + IWL_CMD(REPLY_REMOVE_STA); + IWL_CMD(REPLY_REMOVE_ALL_STA); + IWL_CMD(REPLY_3945_RX); + IWL_CMD(REPLY_TX); + IWL_CMD(REPLY_RATE_SCALE); + IWL_CMD(REPLY_LEDS_CMD); + IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(RADAR_NOTIFICATION); + IWL_CMD(REPLY_QUIET_CMD); + IWL_CMD(REPLY_CHANNEL_SWITCH); + IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); + IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); + IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); + IWL_CMD(POWER_TABLE_CMD); + IWL_CMD(PM_SLEEP_NOTIFICATION); + IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); + IWL_CMD(REPLY_SCAN_CMD); + IWL_CMD(REPLY_SCAN_ABORT_CMD); + IWL_CMD(SCAN_START_NOTIFICATION); + IWL_CMD(SCAN_RESULTS_NOTIFICATION); + IWL_CMD(SCAN_COMPLETE_NOTIFICATION); + IWL_CMD(BEACON_NOTIFICATION); + IWL_CMD(REPLY_TX_BEACON); + IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); + IWL_CMD(QUIET_NOTIFICATION); + IWL_CMD(REPLY_TX_PWR_TABLE_CMD); + IWL_CMD(MEASURE_ABORT_NOTIFICATION); + IWL_CMD(REPLY_BT_CONFIG); + IWL_CMD(REPLY_STATISTICS_CMD); + IWL_CMD(STATISTICS_NOTIFICATION); + IWL_CMD(REPLY_CARD_STATE_CMD); + IWL_CMD(CARD_STATE_NOTIFICATION); + IWL_CMD(MISSED_BEACONS_NOTIFICATION); + default: + return "UNKNOWN"; + + } +} + +#define HOST_COMPLETE_TIMEOUT (HZ / 2) + +/** + * iwl_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a point to the ucode command structure + * + * The function returns < 0 values to indicate the operation is + * failed. On success, it turns the index (> 0) of command in the + * command queue. + */ +static 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_tfd_frame *tfd; + u32 *control_flags; + struct iwl_cmd *out_cmd; + u32 idx; + u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + dma_addr_t phys_addr; + int pad; + u16 count; + int ret; + unsigned long flags; + + /* If any of the command structures end up being larger than + * 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)); + + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + IWL_ERROR("No space for Tx\n"); + return -ENOSPC; + } + + spin_lock_irqsave(&priv->hcmd_lock, flags); + + tfd = &txq->bd[q->first_empty]; + memset(tfd, 0, sizeof(*tfd)); + + control_flags = (u32 *) tfd; + + idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE); + out_cmd = &txq->cmd[idx]; + + 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 + * information */ + + out_cmd->hdr.flags = 0; + out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | + INDEX_TO_SEQ(q->first_empty)); + if (out_cmd->meta.flags & CMD_SIZE_HUGE) + out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + + phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + + offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + + pad = U32_PAD(cmd->len); + count = TFD_CTL_COUNT_GET(*control_flags); + *control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad); + + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM); + + txq->need_update = 1; + q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); + ret = iwl_tx_queue_update_write_ptr(priv, txq); + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return ret ? ret : idx; +} + +int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int ret; + + BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); + + /* An asynchronous command can not expect an SKB to be set. */ + BUG_ON(cmd->meta.flags & CMD_WANT_SKB); + + /* An asynchronous command MUST have a callback. */ + BUG_ON(!cmd->meta.u.callback); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return -EBUSY; + + ret = iwl_enqueue_hcmd(priv, cmd); + if (ret < 0) { + IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + return ret; + } + return 0; +} + +int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int cmd_idx; + int ret; + static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ + + BUG_ON(cmd->meta.flags & CMD_ASYNC); + + /* A synchronous command can not have a callback set. */ + BUG_ON(cmd->meta.u.callback != NULL); + + if (atomic_xchg(&entry, 1)) { + IWL_ERROR("Error sending %s: Already sending a host command\n", + get_cmd_string(cmd->id)); + return -EBUSY; + } + + 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; + IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + goto out; + } + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + !test_bit(STATUS_HCMD_ACTIVE, &priv->status), + HOST_COMPLETE_TIMEOUT); + if (!ret) { + if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { + IWL_ERROR("Error sending %s: time out after %dms.\n", + get_cmd_string(cmd->id), + jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); + + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + ret = -ETIMEDOUT; + goto cancel; + } + } + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", + get_cmd_string(cmd->id)); + ret = -ECANCELED; + goto fail; + } + if (test_bit(STATUS_FW_ERROR, &priv->status)) { + IWL_DEBUG_INFO("Command %s failed: FW Error\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto fail; + } + if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { + IWL_ERROR("Error: Response NULL in '%s'\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto out; + } + + ret = 0; + 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 + * 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; + } +fail: + if (cmd->meta.u.skb) { + dev_kfree_skb_any(cmd->meta.u.skb); + cmd->meta.u.skb = NULL; + } +out: + atomic_set(&entry, 0); + return ret; +} + +int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + /* A command can not be asynchronous AND expect an SKB to be set. */ + BUG_ON((cmd->meta.flags & CMD_ASYNC) && + (cmd->meta.flags & CMD_WANT_SKB)); + + if (cmd->meta.flags & CMD_ASYNC) + return iwl_send_cmd_async(priv, cmd); + + return iwl_send_cmd_sync(priv, cmd); +} + +int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = len, + .data = data, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} + +static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = sizeof(val), + .data = &val, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} + +int iwl_send_statistics_request(struct iwl_priv *priv) +{ + return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); +} + +/** + * iwl_rxon_add_station - add station into station table. + * + * there is only one AP station with id= IWL_AP_ID + * NOTE: mutex must be held before calling the this fnction +*/ +static int iwl_rxon_add_station(struct iwl_priv *priv, + const u8 *addr, int is_ap) +{ + u8 rc; + + /* Remove this station if it happens to already exist */ + iwl_remove_station(priv, addr, is_ap); + + rc = iwl_add_station(priv, addr, is_ap, 0); + + return rc; +} + +/** + * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON + * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz + * @channel: Any channel valid for the requested phymode + + * In addition to setting the staging RXON, priv->phymode is also set. + * + * NOTE: Does not commit to the hardware; it sets appropriate bit fields + * in the staging RXON flag structure based on the phymode + */ +static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) +{ + if (!iwl_get_channel_info(priv, phymode, channel)) { + IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", + channel, phymode); + return -EINVAL; + } + + if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && + (priv->phymode == phymode)) + return 0; + + priv->staging_rxon.channel = cpu_to_le16(channel); + if (phymode == MODE_IEEE80211A) + priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + + priv->phymode = phymode; + + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); + + return 0; +} + +/** + * iwl_check_rxon_cmd - validate RXON structure is valid + * + * NOTE: This is really only useful during development and can eventually + * be #ifdef'd out once the driver is stable and folks aren't actively + * making changes + */ +static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +{ + int error = 0; + int counter = 1; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + error |= le32_to_cpu(rxon->flags & + (RXON_FLG_TGJ_NARROW_BAND_MSK | + RXON_FLG_RADAR_DETECT_MSK)); + if (error) + IWL_WARNING("check 24G fields %d | %d\n", + counter++, error); + } else { + error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? + 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); + if (error) + IWL_WARNING("check 52 fields %d | %d\n", + counter++, error); + error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); + if (error) + IWL_WARNING("check 52 CCK %d | %d\n", + counter++, error); + } + error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; + if (error) + IWL_WARNING("check mac addr %d | %d\n", counter++, error); + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && + ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); + if (error) + IWL_WARNING("check basic rate %d | %d\n", counter++, error); + + error |= (le16_to_cpu(rxon->assoc_id) > 2007); + if (error) + IWL_WARNING("check assoc id %d | %d\n", counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); + if (error) + IWL_WARNING("check CCK and short slot %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); + if (error) + IWL_WARNING("check CCK & auto detect %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); + if (error) + IWL_WARNING("check TGG and auto detect %d | %d\n", + counter++, error); + + if ((rxon->flags & RXON_FLG_DIS_DIV_MSK)) + error |= ((rxon->flags & (RXON_FLG_ANT_B_MSK | + RXON_FLG_ANT_A_MSK)) == 0); + if (error) + IWL_WARNING("check antenna %d %d\n", counter++, error); + + if (error) + IWL_WARNING("Tuning to channel %d\n", + le16_to_cpu(rxon->channel)); + + if (error) { + IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); + return -1; + } + return 0; +} + +/** + * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit + * @priv: staging_rxon is comapred to active_rxon + * + * If the RXON structure is changing sufficient to require a new + * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 + * to indicate a new tune is required. + */ +static int iwl_full_rxon_required(struct iwl_priv *priv) +{ + + /* These items are only settable from the full RXON command */ + if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + compare_ether_addr(priv->staging_rxon.bssid_addr, + priv->active_rxon.bssid_addr) || + compare_ether_addr(priv->staging_rxon.node_addr, + priv->active_rxon.node_addr) || + compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, + priv->active_rxon.wlap_bssid_addr) || + (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || + (priv->staging_rxon.channel != priv->active_rxon.channel) || + (priv->staging_rxon.air_propagation != + priv->active_rxon.air_propagation) || + (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) + return 1; + + /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can + * be updated with the RXON_ASSOC command -- however only some + * flag transitions are allowed using RXON_ASSOC */ + + /* Check if we are not switching bands */ + if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != + (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) + return 1; + + /* Check if we are switching association toggle */ + if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != + (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) + return 1; + + return 0; +} + +static int iwl_send_rxon_assoc(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res = NULL; + struct iwl_rxon_assoc_cmd rxon_assoc; + struct iwl_host_cmd cmd = { + .id = REPLY_RXON_ASSOC, + .len = sizeof(rxon_assoc), + .meta.flags = CMD_WANT_SKB, + .data = &rxon_assoc, + }; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = priv->staging_rxon.flags; + rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; + rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; + rxon_assoc.reserved = 0; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n"); + rc = -EIO; + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +/** + * iwl_commit_rxon - commit staging_rxon to hardware + * + * The RXON command in staging_rxon is commited to the hardware and + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. + */ +static int iwl_commit_rxon(struct iwl_priv *priv) +{ + /* cast away the const for active_rxon in this function */ + struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -1; + + /* always get timestamp with Rx frame */ + priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; + + /* select antenna */ + priv->staging_rxon.flags &= + ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); + priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv); + + rc = iwl_check_rxon_cmd(&priv->staging_rxon); + if (rc) { + IWL_ERROR("Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* If we don't need to send a full RXON, we can use + * iwl_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. */ + if (!iwl_full_rxon_required(priv)) { + rc = iwl_send_rxon_assoc(priv); + if (rc) { + IWL_ERROR("Error setting RXON_ASSOC " + "configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + + return 0; + } + + /* If we are currently associated and the new config requires + * an RXON_ASSOC and the new config wants the associated mask enabled, + * we must clear the associated from the active configuration + * before we apply the new config */ + if (iwl_is_associated(priv) && + (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { + IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), + &priv->active_rxon); + + /* If the mask clearing failed then we set + * active_rxon back to what it was previously */ + if (rc) { + active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; + IWL_ERROR("Error clearing ASSOC_MSK on current " + "configuration (%d).\n", rc); + return rc; + } + + /* The RXON bit toggling will have cleared out the + * station table in the uCode, so blank it in the driver + * as well */ + iwl_clear_stations_table(priv); + } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { + /* When switching from non-associated to associated, the + * uCode clears out the station table; so clear it in the + * driver as well */ + iwl_clear_stations_table(priv); + } + + IWL_DEBUG_INFO("Sending RXON\n" + "* with%s RXON_FILTER_ASSOC_MSK\n" + "* channel = %d\n" + "* bssid = " MAC_FMT "\n", + ((priv->staging_rxon.filter_flags & + RXON_FILTER_ASSOC_MSK) ? "" : "out"), + le16_to_cpu(priv->staging_rxon.channel), + MAC_ARG(priv->staging_rxon.bssid_addr)); + + /* Apply the new configuration */ + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (rc) { + IWL_ERROR("Error setting new configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + + /* If we issue a new RXON command which required a tune then we must + * send a new TXPOWER command or we won't be able to Tx any frames */ + rc = iwl_hw_reg_send_txpower(priv); + if (rc) { + IWL_ERROR("Error setting Tx power (%d).\n", rc); + return rc; + } + + /* Add the broadcast address so we can send broadcast frames */ + if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == + IWL_INVALID_STATION) { + IWL_ERROR("Error adding BROADCAST address for transmit.\n"); + return -EIO; + } + + /* If we have set the ASSOC_MSK and we are in BSS mode then + * add the IWL_AP_ID to the station rate table */ + if (iwl_is_associated(priv) && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + == IWL_INVALID_STATION) { + IWL_ERROR("Error adding AP address for transmit.\n"); + return -EIO; + } + + /* Init the hardware's rate fallback order based on the + * phymode */ + rc = iwl3945_init_hw_rate_table(priv); + if (rc) { + IWL_ERROR("Error setting HW rate table: %02X\n", rc); + return -EIO; + } + + return 0; +} + +static int iwl_send_bt_config(struct iwl_priv *priv) +{ + struct iwl_bt_cmd bt_cmd = { + .flags = 3, + .lead_time = 0xAA, + .max_kill = 1, + .kill_ack_mask = 0, + .kill_cts_mask = 0, + }; + + return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(struct iwl_bt_cmd), &bt_cmd); +} + +static int iwl_send_scan_abort(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_ABORT_CMD, + .meta.flags = CMD_WANT_SKB, + }; + + /* If there isn't a scan actively going on in the hardware + * then we are in between scan bands and not actually + * actively scanning, so don't send the abort command */ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return 0; + } + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return rc; + } + + res = (struct iwl_rx_packet *)cmd.meta.u.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 + * due to simply not being in an active scan which + * can occur if we send the scan abort before we + * the microcode has notified us that a scan is + * completed. */ + IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + clear_bit(STATUS_SCAN_HW, &priv->status); + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +static int iwl_card_state_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct sk_buff *skb) +{ + return 1; +} + +/* + * CARD_STATE_CMD + * + * Use: Sets the internal card state to enable, disable, or halt + * + * When in the 'enable' state the card operates as normal. + * When in the 'disable' state, the card enters into a low power mode. + * When in the 'halt' state, the card is shut down and must be fully + * restarted to come back on. + */ +static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_CARD_STATE_CMD, + .len = sizeof(u32), + .data = &flags, + .meta.flags = meta_flag, + }; + + if (meta_flag & CMD_ASYNC) + cmd.meta.u.callback = iwl_card_state_sync_callback; + + return iwl_send_cmd(priv, &cmd); +} + +static int iwl_add_sta_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl_rx_packet *res = NULL; + + if (!skb) { + IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); + return 1; + } + + res = (struct iwl_rx_packet *)skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + return 1; + } + + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + break; + default: + break; + } + + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +int iwl_send_add_station(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags) +{ + struct iwl_rx_packet *res = NULL; + int rc = 0; + struct iwl_host_cmd cmd = { + .id = REPLY_ADD_STA, + .len = sizeof(struct iwl_addsta_cmd), + .meta.flags = flags, + .data = sta, + }; + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_add_sta_sync_callback; + else + cmd.meta.flags |= CMD_WANT_SKB; + + rc = iwl_send_cmd(priv, &cmd); + + if (rc || (flags & CMD_ASYNC)) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + rc = -EIO; + } + + if (rc == 0) { + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); + break; + default: + rc = -EIO; + IWL_WARNING("REPLY_ADD_STA failed\n"); + break; + } + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +static int iwl_update_sta_key_info(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + __le16 key_flags = 0; + + switch (keyconf->alg) { + case ALG_CCMP: + key_flags |= STA_KEY_FLG_CCMP; + key_flags |= cpu_to_le16( + keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + break; + case ALG_TKIP: + case ALG_WEP: + return -EINVAL; + default: + return -EINVAL; + } + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, + keyconf->keylen); + + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, + keyconf->keylen); + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); + iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + return 0; +} + +static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo)); + priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); + iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + return 0; +} + +static void iwl_clear_free_frames(struct iwl_priv *priv) +{ + struct list_head *element; + + IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", + priv->frames_count); + + while (!list_empty(&priv->free_frames)) { + element = priv->free_frames.next; + list_del(element); + kfree(list_entry(element, struct iwl_frame, list)); + priv->frames_count--; + } + + if (priv->frames_count) { + IWL_WARNING("%d frames still in use. Did we lose one?\n", + priv->frames_count); + priv->frames_count = 0; + } +} + +static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + struct list_head *element; + if (list_empty(&priv->free_frames)) { + frame = kzalloc(sizeof(*frame), GFP_KERNEL); + if (!frame) { + IWL_ERROR("Could not allocate frame!\n"); + return NULL; + } + + priv->frames_count++; + return frame; + } + + element = priv->free_frames.next; + list_del(element); + return list_entry(element, struct iwl_frame, list); +} + +static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) +{ + memset(frame, 0, sizeof(*frame)); + list_add(&frame->list, &priv->free_frames); +} + +unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left) +{ + + if (!iwl_is_associated(priv) || !priv->ibss_beacon || + ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && + (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + return 0; + + if (priv->ibss_beacon->len > left) + return 0; + + memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); + + return priv->ibss_beacon->len; +} + +static int iwl_rate_index_from_plcp(int plcp) +{ + int i = 0; + + for (i = 0; i < IWL_RATE_COUNT; i++) + if (iwl_rates[i].plcp == plcp) + return i; + return -1; +} + +static u8 iwl_rate_get_lowest_plcp(int rate_mask) +{ + u8 i; + + for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; + i = iwl_rates[i].next_ieee) { + if (rate_mask & (1 << i)) + return iwl_rates[i].plcp; + } + + return IWL_RATE_INVALID; +} + +static int iwl_send_beacon_cmd(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + unsigned int frame_size; + int rc; + u8 rate; + + frame = iwl_get_free_frame(priv); + + if (!frame) { + IWL_ERROR("Could not obtain free frame buffer for beacon " + "command.\n"); + return -ENOMEM; + } + + if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { + rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & + 0xFF0); + if (rate == IWL_INVALID_RATE) + rate = IWL_RATE_6M_PLCP; + } else { + rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); + if (rate == IWL_INVALID_RATE) + rate = IWL_RATE_1M_PLCP; + } + + frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); + + rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + &frame->u.cmd[0]); + + iwl_free_frame(priv, frame); + + return rc; +} + +/****************************************************************************** + * + * EEPROM related functions + * + ******************************************************************************/ + +static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac) +{ + memcpy(mac, priv->eeprom.mac_address, 6); +} + +/** + * iwl_eeprom_init - read EEPROM contents + * + * Load the EEPROM from adapter into priv->eeprom + * + * NOTE: This routine uses the non-debug IO access functions. + */ +int iwl_eeprom_init(struct iwl_priv *priv) +{ + u16 *e = (u16 *)&priv->eeprom; + u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + u32 r; + int sz = sizeof(priv->eeprom); + int rc; + int i; + u16 addr; + + /* The EEPROM structure has several padding buffers within it + * and when adding new EEPROM maps is subject to programmer errors + * which may be very difficult to identify without explicitly + * checking the resulting size of the eeprom map. */ + BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); + + if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { + IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); + return -ENOENT; + } + + rc = iwl_eeprom_aqcuire_semaphore(priv); + if (rc < 0) { + IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n"); + return -ENOENT; + } + + /* eeprom is an array of 16bit values */ + for (addr = 0; addr < sz; addr += sizeof(u16)) { + _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); + _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + + for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; + i += IWL_EEPROM_ACCESS_DELAY) { + r = _iwl_read_restricted(priv, CSR_EEPROM_REG); + if (r & CSR_EEPROM_REG_READ_VALID_MSK) + break; + udelay(IWL_EEPROM_ACCESS_DELAY); + } + + if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + IWL_ERROR("Time out reading EEPROM[%d]", addr); + return -ETIMEDOUT; + } + e[addr / 2] = le16_to_cpu(r >> 16); + } + + return 0; +} + +/****************************************************************************** + * + * Misc. internal state and helper functions + * + ******************************************************************************/ +#ifdef CONFIG_IWLWIFI_DEBUG + +/** + * iwl_report_frame - dump frame to syslog during debug sessions + * + * hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + * + * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type + * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats) + * is 3945-specific and gives bad output for 4965. Need to split the + * functionality, keep common stuff here. + */ +void iwl_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + u16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + int rate_sym; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + /* MAC header */ + fc = le16_to_cpu(header->frame_control); + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + rate_sym = rx_hdr->rate; + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == + (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + u32 rate; + + if (hundred) + title = "100Frames"; + else if (fc & IEEE80211_FCTL_RETRY) + title = "Retry"; + else if (ieee80211_is_assoc_response(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_response(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_response(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate = iwl_rate_index_from_plcp(rate_sym); + if (rate == -1) + rate = 0; + else + rate = iwl_rates[rate].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, fc, header->addr1[5], + length, rssi, channel, rate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, fc, header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl_print_hex_dump(IWL_DL_RX, data, length); +} +#endif + +static void iwl_unset_hw_setting(struct iwl_priv *priv) +{ + if (priv->hw_setting.shared_virt) + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl_shared), + priv->hw_setting.shared_virt, + priv->hw_setting.shared_phys); +} + +/** + * iwl_supported_rate_to_ie - fill in the supported rate in IE field + * + * return : set the bit for each supported rate insert in ie + */ +static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, + u16 basic_rate, int max_count) +{ + u16 ret_rates = 0, bit; + int i; + u8 *rates; + + rates = &(ie[1]); + + for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { + if (bit & supported_rate) { + ret_rates |= bit; + rates[*ie] = iwl_rates[i].ieee | + ((bit & basic_rate) ? 0x80 : 0x00); + *ie = *ie + 1; + if (*ie >= max_count) + break; + } + } + + return ret_rates; +} + +/** + * iwl_fill_probe_req - fill in all required fields and IE for probe request + */ +static u16 iwl_fill_probe_req(struct iwl_priv *priv, + struct ieee80211_mgmt *frame, + int left, int is_direct) +{ + int len = 0; + u8 *pos = NULL; + u16 ret_rates; + + /* Make sure there is enough space for the probe request, + * two mandatory IEs and the data */ + left -= 24; + if (left < 0) + return 0; + len += 24; + + frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN); + memcpy(frame->sa, priv->mac_addr, ETH_ALEN); + memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN); + frame->seq_ctrl = 0; + + /* fill in our indirect SSID IE */ + /* ...next IE... */ + + left -= 2; + if (left < 0) + return 0; + len += 2; + pos = &(frame->u.probe_req.variable[0]); + *pos++ = WLAN_EID_SSID; + *pos++ = 0; + + /* fill in our direct SSID IE... */ + if (is_direct) { + /* ...next IE... */ + left -= 2 + priv->essid_len; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_SSID; + *pos++ = priv->essid_len; + memcpy(pos, priv->essid, priv->essid_len); + pos += priv->essid_len; + len += 2 + priv->essid_len; + } + + /* fill in supported rate */ + /* ...next IE... */ + left -= 2; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_SUPP_RATES; + *pos = 0; + ret_rates = priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + iwl_supported_rate_to_ie(pos, priv->active_rate, + priv->active_rate_basic, left); + len += 2 + *pos; + pos += (*pos) + 1; + ret_rates = ~ret_rates & priv->active_rate; + + if (ret_rates == 0) + goto fill_end; + + /* fill in supported extended rate */ + /* ...next IE... */ + left -= 2; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos = 0; + iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left); + if (*pos > 0) + len += 2 + *pos; + + fill_end: + return (u16)len; +} + +/* + * QoS support +*/ +#ifdef CONFIG_IWLWIFI_QOS +static int iwl_send_qos_params_command(struct iwl_priv *priv, + struct iwl_qosparam_cmd *qos) +{ + + return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, + sizeof(struct iwl_qosparam_cmd), qos); +} + +static void iwl_reset_qos(struct iwl_priv *priv) +{ + u16 cw_min = 15; + u16 cw_max = 1023; + u8 aifs = 2; + u8 is_legacy = 0; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.qos_active = 0; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + if (!(priv->active_rate & 0xfff0)) { + cw_min = 31; + is_legacy = 1; + } + } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + cw_min = 31; + is_legacy = 1; + } + + if (priv->qos_data.qos_active) + aifs = 3; + + priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; + + if (priv->qos_data.qos_active) { + i = 1; + priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 7; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 2; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(6016); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3008); + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 3; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 4 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16((cw_max + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3264); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(1504); + } else { + for (i = 1; i < 4; i++) { + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + } + } + IWL_DEBUG_QOS("set QoS to default \n"); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_activate_qos(struct iwl_priv *priv, u8 force) +{ + unsigned long flags; + + if (priv == NULL) + return; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (!priv->qos_data.qos_enable) + return; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.def_qos_parm.qos_flags = 0; + + if (priv->qos_data.qos_cap.q_AP.queue_request && + !priv->qos_data.qos_cap.q_AP.txop_request) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_TXOP_TYPE_MSK; + + if (priv->qos_data.qos_active) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + spin_unlock_irqrestore(&priv->lock, flags); + + if (force || iwl_is_associated(priv)) { + IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", + priv->qos_data.qos_active); + + iwl_send_qos_params_command(priv, + &(priv->qos_data.def_qos_parm)); + } +} + +#endif /* CONFIG_IWLWIFI_QOS */ +/* + * Power management (not Tx power!) functions + */ +#define MSEC_TO_USEC 1024 + +#define NOSLP __constant_cpu_to_le32(0) +#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK +#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) +#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ + __constant_cpu_to_le32(X1), \ + __constant_cpu_to_le32(X2), \ + __constant_cpu_to_le32(X3), \ + __constant_cpu_to_le32(X4)} + + +/* default power management (not Tx power) table values */ +/* for tim 0-10 */ +static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { + {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1}, + {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} +}; + +/* for tim > 10 */ +static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { + {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), + SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), + SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), + SLP_VEC(2, 6, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), + SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} +}; + +int iwl_power_init_handle(struct iwl_priv *priv) +{ + int rc = 0, i; + struct iwl_power_mgr *pow_data; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + u16 pci_pm; + + IWL_DEBUG_POWER("Initialize power \n"); + + pow_data = &(priv->power_data); + + memset(pow_data, 0, sizeof(*pow_data)); + + pow_data->active_index = IWL_POWER_RANGE_0; + pow_data->dtim_val = 0xffff; + + memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); + memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); + + rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm); + if (rc != 0) + return 0; + else { + struct iwl_powertable_cmd *cmd; + + IWL_DEBUG_POWER("adjust power command flags\n"); + + for (i = 0; i < IWL_POWER_AC; i++) { + cmd = &pow_data->pwr_range_0[i].cmd; + + if (pci_pm & 0x1) + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + else + cmd->flags |= IWL_POWER_PCI_PM_MSK; + } + } + return rc; +} + +static int iwl_update_power_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, u32 mode) +{ + int rc = 0, i; + u8 skip; + u32 max_sleep = 0; + struct iwl_power_vec_entry *range; + u8 period = 0; + struct iwl_power_mgr *pow_data; + + if (mode > IWL_POWER_INDEX_5) { + IWL_DEBUG_POWER("Error invalid power mode \n"); + return -1; + } + pow_data = &(priv->power_data); + + if (pow_data->active_index == IWL_POWER_RANGE_0) + range = &pow_data->pwr_range_0[0]; + else + range = &pow_data->pwr_range_1[1]; + + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); + +#ifdef IWL_MAC80211_DISABLE + if (priv->assoc_network != NULL) { + unsigned long flags; + + period = priv->assoc_network->tim.tim_period; + } +#endif /*IWL_MAC80211_DISABLE */ + skip = range[mode].no_dtim; + + if (period == 0) { + period = 1; + skip = 0; + } + + if (skip == 0) { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = (le32_to_cpu(slp_itrvl) / period) * 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); + } + + IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); + IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); + IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); + IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", + le32_to_cpu(cmd->sleep_interval[0]), + le32_to_cpu(cmd->sleep_interval[1]), + le32_to_cpu(cmd->sleep_interval[2]), + le32_to_cpu(cmd->sleep_interval[3]), + le32_to_cpu(cmd->sleep_interval[4])); + + return rc; +} + +static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) +{ + u32 final_mode = mode; + int rc; + struct iwl_powertable_cmd cmd; + + /* If on battery, set to 3, + * if plugged into AC power, set to CAM ("continuosly aware mode"), + * else user level */ + switch (mode) { + case IWL_POWER_BATTERY: + final_mode = IWL_POWER_INDEX_3; + break; + case IWL_POWER_AC: + final_mode = IWL_POWER_MODE_CAM; + break; + default: + final_mode = mode; + break; + } + + iwl_update_power_cmd(priv, &cmd, final_mode); + + rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); + + if (final_mode == IWL_POWER_MODE_CAM) + clear_bit(STATUS_POWER_PMI, &priv->status); + else + set_bit(STATUS_POWER_PMI, &priv->status); + + return rc; +} + +int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +{ + /* Filter incoming packets to determine if they are targeted toward + * this network, discarding packets coming from ourselves */ + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + /* packets from our adapter are dropped (echo) */ + if (!compare_ether_addr(header->addr2, priv->mac_addr)) + return 0; + /* {broad,multi}cast packets to our IBSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !compare_ether_addr(header->addr3, priv->bssid); + /* packets to our adapter go through */ + return !compare_ether_addr(header->addr1, priv->mac_addr); + case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + /* packets from our adapter are dropped (echo) */ + if (!compare_ether_addr(header->addr3, priv->mac_addr)) + return 0; + /* {broad,multi}cast packets to our BSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !compare_ether_addr(header->addr2, priv->bssid); + /* packets to our adapter go through */ + return !compare_ether_addr(header->addr1, priv->mac_addr); + } + + return 1; +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +const char *iwl_get_tx_fail_reason(u32 status) +{ + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_ENTRY(SHORT_LIMIT); + TX_STATUS_ENTRY(LONG_LIMIT); + TX_STATUS_ENTRY(FIFO_UNDERRUN); + TX_STATUS_ENTRY(MGMNT_ABORT); + TX_STATUS_ENTRY(NEXT_FRAG); + TX_STATUS_ENTRY(LIFE_EXPIRE); + TX_STATUS_ENTRY(DEST_PS); + TX_STATUS_ENTRY(ABORTED); + TX_STATUS_ENTRY(BT_RETRY); + TX_STATUS_ENTRY(STA_INVALID); + TX_STATUS_ENTRY(FRAG_DROPPED); + TX_STATUS_ENTRY(TID_DISABLE); + TX_STATUS_ENTRY(FRAME_FLUSHED); + TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); + TX_STATUS_ENTRY(TX_LOCKED); + TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); + } + + return "UNKNOWN"; +} + +/** + * iwl_scan_cancel - Cancel any currently executing HW scan + * + * NOTE: priv->mutex is not required before calling this function + */ +static int iwl_scan_cancel(struct iwl_priv *priv) +{ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCANNING, &priv->status); + return 0; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Queuing scan abort.\n"); + set_bit(STATUS_SCAN_ABORTING, &priv->status); + queue_work(priv->workqueue, &priv->abort_scan); + + } else + IWL_DEBUG_SCAN("Scan abort already in progress.\n"); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return 0; +} + +/** + * iwl_scan_cancel_timeout - Cancel any currently executing HW scan + * @ms: amount of time to wait (in milliseconds) for scan to abort + * + * NOTE: priv->mutex must be held before calling this function + */ +static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) +{ + unsigned long now = jiffies; + int ret; + + ret = iwl_scan_cancel(priv); + if (ret && ms) { + mutex_unlock(&priv->mutex); + while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && + test_bit(STATUS_SCANNING, &priv->status)) + msleep(1); + mutex_lock(&priv->mutex); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return ret; +} + +static void iwl_sequence_reset(struct iwl_priv *priv) +{ + /* Reset ieee stats */ + + /* We don't reset the net_device_stats (ieee->stats) on + * re-association */ + + priv->last_seq_num = -1; + priv->last_frag_num = -1; + priv->last_packet_time = 0; + + iwl_scan_cancel(priv); +} + +#define MAX_UCODE_BEACON_INTERVAL 1024 +#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) + +static __le16 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; + + return cpu_to_le16(new_val); +} + +static void iwl_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.dw[1] = cpu_to_le32(priv->timestamp1); + priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0); + + priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; + + tsf = priv->timestamp1; + tsf = ((tsf << 32) | priv->timestamp0); + + beacon_int = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + 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 = + iwl_adjust_beacon_interval( + le16_to_cpu(priv->rxon_timing.beacon_interval)); + } + + priv->rxon_timing.atim_window = 0; + } else { + priv->rxon_timing.beacon_interval = + iwl_adjust_beacon_interval(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 + ("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 int iwl_scan_initiate(struct iwl_priv *priv) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("APs don't scan.\n"); + return 0; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); + return -EIO; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_SCAN("Scan already in progress.\n"); + return -EAGAIN; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Scan request while abort pending. " + "Queuing.\n"); + return -EAGAIN; + } + + IWL_DEBUG_INFO("Starting scan...\n"); + priv->scan_bands = 2; + set_bit(STATUS_SCANNING, &priv->status); + priv->scan_start = jiffies; + priv->scan_pass_start = priv->scan_start; + + queue_work(priv->workqueue, &priv->request_scan); + + return 0; +} + +static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +{ + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + + if (hw_decrypt) + rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; + else + rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; + + return 0; +} + +static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) +{ + if (phymode == MODE_IEEE80211A) { + priv->staging_rxon.flags &= + ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK + | RXON_FLG_CCK_MSK); + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + } else { + /* Copied from iwl_bg_post_associate() */ + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; + priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; + } +} + +/* + * initilize rxon structure with default values fromm eeprom + */ +static void iwl_connection_init_rx_config(struct iwl_priv *priv) +{ + const struct iwl_channel_info *ch_info; + + memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_AP: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; + break; + + case IEEE80211_IF_TYPE_STA: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; + priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_IBSS: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; + priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; + priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | + RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_MNTR: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; + priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; + break; + } + +#if 0 + /* TODO: Figure out when short_preamble would be set and cache from + * that */ + if (!hw_to_local(priv->hw)->short_preamble) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; +#endif + + ch_info = iwl_get_channel_info(priv, priv->phymode, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info) + ch_info = &priv->channel_info[0]; + + /* + * in some case A channels are all non IBSS + * in this case force B/G channel + */ + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !(is_channel_ibss(ch_info))) + ch_info = &priv->channel_info[0]; + + priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); + if (is_channel_a_band(ch_info)) + priv->phymode = MODE_IEEE80211A; + else + priv->phymode = MODE_IEEE80211G; + + iwl_set_flags_for_phymode(priv, priv->phymode); + + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; +} + +static int iwl_set_mode(struct iwl_priv *priv, int mode) +{ + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + + if (mode == IEEE80211_IF_TYPE_IBSS) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, + priv->phymode, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info || !is_channel_ibss(ch_info)) { + IWL_ERROR("channel %d not IBSS channel\n", + le16_to_cpu(priv->staging_rxon.channel)); + return -EINVAL; + } + } + + cancel_delayed_work(&priv->scan_check); + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + return -EAGAIN; + } + + priv->iw_mode = mode; + + iwl_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + + iwl_clear_stations_table(priv); + + iwl_commit_rxon(priv); + + return 0; +} + +static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, + struct ieee80211_tx_control *ctl, + struct iwl_cmd *cmd, + struct sk_buff *skb_frag, + int last_frag) +{ + struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + + switch (keyinfo->alg) { + case ALG_CCMP: + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; + memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); + IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + break; + + case ALG_TKIP: +#if 0 + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; + + if (last_frag) + memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8, + 8); + else + memset(cmd->cmd.tx.tkip_mic.byte, 0, 8); +#endif + break; + + case ALG_WEP: + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | + (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; + + if (keyinfo->keylen == 13) + cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; + + memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); + + IWL_DEBUG_TX("Configuring packet for WEP encryption " + "with key %d\n", ctl->key_idx); + break; + + case ALG_NONE: + IWL_DEBUG_TX("Tx packet in the clear (encrypt requested).\n"); + break; + + default: + printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); + break; + } +} + +/* + * handle build REPLY_TX command notification. + */ +static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int is_unicast, u8 std_id) +{ + __le16 *qc; + u16 fc = le16_to_cpu(hdr->frame_control); + __le32 tx_flags = cmd->cmd.tx.tx_flags; + + cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + tx_flags |= TX_CMD_FLG_ACK_MSK; + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (ieee80211_is_probe_response(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) + tx_flags |= TX_CMD_FLG_TSF_MSK; + } else { + tx_flags &= (~TX_CMD_FLG_ACK_MSK); + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + cmd->cmd.tx.sta_id = std_id; + if (ieee80211_get_morefrag(hdr)) + tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; + + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; + } else + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + + if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + tx_flags |= TX_CMD_FLG_RTS_MSK; + tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + + if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) + tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + + tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + cmd->cmd.tx.timeout.pm_frame_timeout = + cpu_to_le16(3); + else + cmd->cmd.tx.timeout.pm_frame_timeout = + cpu_to_le16(2); + } else + cmd->cmd.tx.timeout.pm_frame_timeout = 0; + + cmd->cmd.tx.driver_txop = 0; + cmd->cmd.tx.tx_flags = tx_flags; + cmd->cmd.tx.next_frame_len = 0; +} + +static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + int sta_id; + u16 fc = le16_to_cpu(hdr->frame_control); + + /* If this frame is broadcast or not data then use the broadcast + * station id */ + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || + is_multicast_ether_addr(hdr->addr1)) + return priv->hw_setting.bcast_sta_id; + + switch (priv->iw_mode) { + + /* If this frame is part of a BSS network (we're a station), then + * we use the AP's station id */ + case IEEE80211_IF_TYPE_STA: + return IWL_AP_ID; + + /* If we are an AP, then find the station, or use BCAST */ + case IEEE80211_IF_TYPE_AP: + sta_id = iwl_hw_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + return priv->hw_setting.bcast_sta_id; + + /* If this frame is part of a IBSS network, then we use the + * target specific station id */ + case IEEE80211_IF_TYPE_IBSS: + sta_id = iwl_hw_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); + + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " + "Defaulting to broadcast...\n", + MAC_ARG(hdr->addr1)); + iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + return priv->hw_setting.bcast_sta_id; + + default: + IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); + return priv->hw_setting.bcast_sta_id; + } +} + +/* + * start REPLY_TX command process + */ +static int iwl_tx_skb(struct iwl_priv *priv, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + int txq_id = ctl->queue; + struct iwl_tx_queue *txq = NULL; + struct iwl_queue *q = NULL; + dma_addr_t phys_addr; + dma_addr_t txcmd_phys; + struct iwl_cmd *out_cmd = NULL; + u16 len, idx, len_org; + u8 id, hdr_len, unicast; + u8 sta_id; + u16 seq_number = 0; + u16 fc; + __le16 *qc; + u8 wait_write_ptr = 0; + unsigned long flags; + int rc; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_DROP("Dropping - RF KILL\n"); + goto drop_unlock; + } + + if (!priv->interface_id) { + IWL_DEBUG_DROP("Dropping - !priv->interface_id\n"); + goto drop_unlock; + } + + if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + IWL_ERROR("ERROR: No TX rate available.\n"); + goto drop_unlock; + } + + unicast = !is_multicast_ether_addr(hdr->addr1); + id = 0; + + fc = le16_to_cpu(hdr->frame_control); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (ieee80211_is_auth(fc)) + IWL_DEBUG_TX("Sending AUTH frame\n"); + else if (ieee80211_is_assoc_request(fc)) + IWL_DEBUG_TX("Sending ASSOC frame\n"); + else if (ieee80211_is_reassoc_request(fc)) + IWL_DEBUG_TX("Sending REASSOC frame\n"); +#endif + + if (!iwl_is_associated(priv) && + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { + IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + goto drop_unlock; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + hdr_len = ieee80211_get_hdrlen(fc); + sta_id = iwl_get_sta_id(priv, hdr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", + MAC_ARG(hdr->addr1)); + goto drop; + } + + IWL_DEBUG_RATE("station Id %d\n", sta_id); + + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + seq_number = priv->stations[sta_id].tid[tid].seq_number & + IEEE80211_SCTL_SEQ; + hdr->seq_ctrl = cpu_to_le16(seq_number) | + (hdr->seq_ctrl & + __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); + seq_number += 0x10; + } + txq = &priv->txq[txq_id]; + q = &txq->q; + + spin_lock_irqsave(&priv->lock, flags); + + tfd = &txq->bd[q->first_empty]; + memset(tfd, 0, sizeof(*tfd)); + control_flags = (u32 *) tfd; + idx = get_cmd_index(q, q->first_empty, 0); + + memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info)); + txq->txb[q->first_empty].skb[0] = skb; + memcpy(&(txq->txb[q->first_empty].status.control), + ctl, sizeof(struct ieee80211_tx_control)); + out_cmd = &txq->cmd[idx]; + memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); + memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); + out_cmd->hdr.cmd = REPLY_TX; + out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->first_empty))); + /* copy frags header */ + memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); + + /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */ + len = priv->hw_setting.tx_cmd_len + + sizeof(struct iwl_cmd_header) + hdr_len; + + len_org = len; + len = (len + 3) & ~3; + + if (len_org != len) + len_org = 1; + else + len_org = 0; + + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); + + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + + if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + + /* 802.11 null functions have no payload... */ + len = skb->len - hdr_len; + if (len) { + phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, + len, PCI_DMA_TODEVICE); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + } + + /* If there is no payload, then only one TFD is used */ + if (!len) + *control_flags = TFD_CTL_COUNT_SET(1); + else + *control_flags = TFD_CTL_COUNT_SET(2) | + TFD_CTL_PAD_SET(U32_PAD(len)); + + len = (u16)skb->len; + out_cmd->cmd.tx.len = cpu_to_le16(len); + + /* TODO need this for burst mode later on */ + iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + + /* set is_hcca to 0; it probably will never be implemented */ + iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + + out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; + out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; + + if (!ieee80211_get_morefrag(hdr)) { + txq->need_update = 1; + if (qc) { + u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } + } else { + wait_write_ptr = 1; + txq->need_update = 0; + } + + iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, + sizeof(out_cmd->cmd.tx)); + + iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, + ieee80211_get_hdrlen(fc)); + + q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); + rc = iwl_tx_queue_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + + if (rc) + return rc; + + if ((iwl_queue_space(q) < q->high_mark) + && priv->mac80211_registered) { + if (wait_write_ptr) { + spin_lock_irqsave(&priv->lock, flags); + txq->need_update = 1; + iwl_tx_queue_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + } + + ieee80211_stop_queue(priv->hw, ctl->queue); + } + + return 0; + +drop_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +drop: + return -1; +} + +static void iwl_set_rate(struct iwl_priv *priv) +{ + const struct ieee80211_hw_mode *hw = NULL; + struct ieee80211_rate *rate; + int i; + + hw = iwl_get_hw_mode(priv, priv->phymode); + + priv->active_rate = 0; + priv->active_rate_basic = 0; + + IWL_DEBUG_RATE("Setting rates for 802.11%c\n", + hw->mode == MODE_IEEE80211A ? + 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); + + for (i = 0; i < hw->num_rates; i++) { + rate = &(hw->rates[i]); + if ((rate->val < IWL_RATE_COUNT) && + (rate->flags & IEEE80211_RATE_SUPPORTED)) { + IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", + rate->val, iwl_rates[rate->val].plcp, + (rate->flags & IEEE80211_RATE_BASIC) ? + "*" : ""); + priv->active_rate |= (1 << rate->val); + if (rate->flags & IEEE80211_RATE_BASIC) + priv->active_rate_basic |= (1 << rate->val); + } else + IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", + rate->val, iwl_rates[rate->val].plcp); + } + + IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", + priv->active_rate, priv->active_rate_basic); + + /* + * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK) + * otherwise set it to the default of all CCK rates and 6, 12, 24 for + * OFDM + */ + if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK) + priv->staging_rxon.cck_basic_rates = + ((priv->active_rate_basic & + IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF; + else + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; + + if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK) + priv->staging_rxon.ofdm_basic_rates = + ((priv->active_rate_basic & + (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >> + IWL_FIRST_OFDM_RATE) & 0xFF; + else + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; +} + +static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) +{ + unsigned long flags; + + if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status)) + return; + + IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n", + disable_radio ? "OFF" : "ON"); + + if (disable_radio) { + iwl_scan_cancel(priv); + /* FIXME: This is a workaround for AP */ + if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_SW_BIT_RFKILL); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); + set_bit(STATUS_RF_KILL_SW, &priv->status); + } + return; + } + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + clear_bit(STATUS_RF_KILL_SW, &priv->status); + spin_unlock_irqrestore(&priv->lock, flags); + + /* wake up ucode */ + msleep(10); + + spin_lock_irqsave(&priv->lock, flags); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_restricted_access(priv)) + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by HW switch\n"); + return; + } + + queue_work(priv->workqueue, &priv->restart); + return; +} + +void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, + u32 decrypt_res, struct ieee80211_rx_status *stats) +{ + u16 fc = + le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control); + + if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) + return; + + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return; + + IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); + switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { + case RX_RES_STATUS_SEC_TYPE_TKIP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_ICV_MIC) + stats->flag |= RX_FLAG_MMIC_ERROR; + case RX_RES_STATUS_SEC_TYPE_WEP: + case RX_RES_STATUS_SEC_TYPE_CCMP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_DECRYPT_OK) { + IWL_DEBUG_RX("hw decrypt successfully!!!\n"); + stats->flag |= RX_FLAG_DECRYPTED; + } + break; + + default: + break; + } +} + +void iwl_handle_data_packet_monitor(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags) +{ + struct iwl_rt_rx_hdr *iwl_rt; + + /* First cache any information we need before we overwrite + * the information provided in the skb from the hardware */ + s8 signal = stats->ssi; + s8 noise = 0; + int rate = stats->rate; + u64 tsf = stats->mactime; + __le16 phy_flags_hw = cpu_to_le16(phy_flags); + + /* We received data from the HW, so stop the watchdog */ + if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) { + IWL_DEBUG_DROP("Dropping too large packet in monitor\n"); + return; + } + + /* copy the frame data to write after where the radiotap header goes */ + iwl_rt = (void *)rxb->skb->data; + memmove(iwl_rt->payload, data, len); + + iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */ + + /* total header + data */ + iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt)); + + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, sizeof(*iwl_rt) + len); + + /* Big bitfield of all the fields we provide in radiotap */ + iwl_rt->rt_hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)); + + /* Zero the flags, we'll add to them as we go */ + iwl_rt->rt_flags = 0; + + iwl_rt->rt_tsf = cpu_to_le64(tsf); + + /* Convert to dBm */ + iwl_rt->rt_dbmsignal = signal; + iwl_rt->rt_dbmnoise = noise; + + /* Convert the channel frequency and set the flags */ + iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq); + if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); + else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); + else /* 802.11g */ + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ)); + + rate = iwl_rate_index_from_plcp(rate); + if (rate == -1) + iwl_rt->rt_rate = 0; + else + iwl_rt->rt_rate = iwl_rates[rate].ieee; + + /* antenna number */ + iwl_rt->rt_antenna = + le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if we have it */ + if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + + stats->flag |= RX_FLAG_RADIOTAP; + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + rxb->skb = NULL; +} + + +#define IWL_PACKET_RETRY_TIME HZ + +int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +{ + u16 sc = le16_to_cpu(header->seq_ctrl); + u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; + u16 frag = sc & IEEE80211_SCTL_FRAG; + u16 *last_seq, *last_frag; + unsigned long *last_time; + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS:{ + struct list_head *p; + struct iwl_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); + + __list_for_each(p, &priv->ibss_mac_hash[index]) { + entry = + list_entry(p, struct iwl_ibss_seq, list); + if (!compare_ether_addr(entry->mac, mac)) + break; + } + if (p == &priv->ibss_mac_hash[index]) { + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + IWL_ERROR + ("Cannot malloc new mac entry\n"); + return 0; + } + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num = seq; + entry->frag_num = frag; + entry->packet_time = jiffies; + list_add(&entry->list, + &priv->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num; + last_frag = &entry->frag_num; + last_time = &entry->packet_time; + break; + } + case IEEE80211_IF_TYPE_STA: + last_seq = &priv->last_seq_num; + last_frag = &priv->last_frag_num; + last_time = &priv->last_packet_time; + break; + default: + return 0; + } + if ((*last_seq == seq) && + time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag) + goto drop; + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + goto drop; + } else + *last_seq = seq; + + *last_frag = frag; + *last_time = jiffies; + return 0; + + drop: + return 1; +} + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} + +static int iwl_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO + ("Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +static void iwl_txstatus_to_ieee(struct iwl_priv *priv, + struct iwl_tx_info *tx_sta) +{ + + tx_sta->status.ack_signal = 0; + tx_sta->status.excessive_retries = 0; + tx_sta->status.queue_length = 0; + tx_sta->status.queue_number = 0; + + if (in_interrupt()) + ieee80211_tx_status_irqsafe(priv->hw, + tx_sta->skb[0], &(tx_sta->status)); + else + ieee80211_tx_status(priv->hw, + tx_sta->skb[0], &(tx_sta->status)); + + tx_sta->skb[0] = NULL; +} + +/** + * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC. + * + * When FW advances 'R' index, all entries between old and + * new 'R' index need to be reclaimed. As result, some free space + * forms. If there is enough free space (> low mark), wake Tx queue. + */ +int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + int nfreed = 0; + + if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->first_empty, q->last_used); + return 0; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); + q->last_used != index; + q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) { + if (txq_id != IWL_CMD_QUEUE_NUM) { + iwl_txstatus_to_ieee(priv, + &(txq->txb[txq->q.last_used])); + iwl_hw_txq_free_tfd(priv, txq); + } else if (nfreed > 1) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + q->first_empty, q->last_used); + queue_work(priv->workqueue, &priv->restart); + } + nfreed++; + } + + if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && + (txq_id != IWL_CMD_QUEUE_NUM) && + priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + + + return nfreed; +} + +static int iwl_is_tx_success(u32 status) +{ + return (status & 0xFF) == 0x1; +} + +/****************************************************************************** + * + * Generic RX handler implementations + * + ******************************************************************************/ +static void iwl_rx_reply_tx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_status *tx_status; + struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le32_to_cpu(tx_resp->status); + + if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.first_empty, + txq->q.last_used); + return; + } + + tx_status = &(txq->txb[txq->q.last_used].status); + + tx_status->retry_count = tx_resp->failure_frame; + tx_status->queue_number = status; + tx_status->queue_length = tx_resp->bt_kill_count; + tx_status->queue_length |= tx_resp->failure_rts; + + tx_status->flags = + iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; + + tx_status->control.tx_rate = iwl_rate_index_from_plcp(tx_resp->rate); + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", + txq_id, iwl_get_tx_fail_reason(status), status, + tx_resp->rate, tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); + if (index != -1) + iwl_tx_queue_reclaim(priv, txq_id, index); + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); +} + + +static void iwl_rx_reply_alive(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_alive_resp *palive; + struct delayed_work *pwork; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO("Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + if (palive->ver_subtype == INITIALIZE_SUBTYPE) { + IWL_DEBUG_INFO("Initialization Alive received.\n"); + memcpy(&priv->card_alive_init, + &pkt->u.alive_frame, + sizeof(struct iwl_init_alive_resp)); + pwork = &priv->init_alive_start; + } else { + IWL_DEBUG_INFO("Runtime Alive received.\n"); + memcpy(&priv->card_alive, &pkt->u.alive_frame, + sizeof(struct iwl_alive_resp)); + pwork = &priv->alive_start; + iwl_disable_events(priv); + } + + /* We delay the ALIVE response by 5ms to + * give the HW RF Kill time to activate... */ + if (palive->is_valid == UCODE_VALID_OK) + queue_delayed_work(priv->workqueue, pwork, + msecs_to_jiffies(5)); + else + IWL_WARNING("uCode did not respond OK.\n"); +} + +static void iwl_rx_reply_add_sta(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + + IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); + return; +} + +static void iwl_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + + IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " + "seq 0x%04X ser 0x%08X\n", + le32_to_cpu(pkt->u.err_resp.error_type), + get_cmd_string(pkt->u.err_resp.cmd_id), + pkt->u.err_resp.cmd_id, + le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), + le32_to_cpu(pkt->u.err_resp.error_info)); +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl_csa_notification *csa = &(pkt->u.csa_notif); + IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", + le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; +} + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +#endif +} + +static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); + IWL_DEBUG_RX("sleep mode: %d, src: %d\n", + sleep->pm_sleep_mode, sleep->pm_wakeup_src); +#endif +} + +static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + IWL_DEBUG_RADIO("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)); +} + +static void iwl_bg_beacon_update(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, beacon_update); + struct sk_buff *beacon; + + /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ + beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL); + + if (!beacon) { + IWL_ERROR("update beacon failed\n"); + return; + } + + mutex_lock(&priv->mutex); + /* new beacon skb is allocated every time; dispose previous.*/ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = beacon; + mutex_unlock(&priv->mutex); + + iwl_send_beacon_cmd(priv); +} + +static void iwl_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status); + u8 rate = beacon->beacon_notify_hdr.rate; + + IWL_DEBUG_RX("beacon status %x retries %d iss %d " + "tsf %d %d rate %d\n", + le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK, + beacon->beacon_notify_hdr.failure_frame, + le32_to_cpu(beacon->ibss_mgr_status), + le32_to_cpu(beacon->high_tsf), + le32_to_cpu(beacon->low_tsf), rate); +#endif + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!test_bit(STATUS_EXIT_PENDING, &priv->status))) + queue_work(priv->workqueue, &priv->beacon_update); +} + +/* Service response to REPLY_SCAN_CMD (0x80) */ +static void iwl_rx_reply_scan(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanreq_notification *notif = + (struct iwl_scanreq_notification *)pkt->u.raw; + + IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); +#endif +} + +/* Service SCAN_START_NOTIFICATION (0x82) */ +static void iwl_rx_scan_start_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanstart_notification *notif = + (struct iwl_scanstart_notification *)pkt->u.raw; + priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); + IWL_DEBUG_SCAN("Scan start: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", + notif->channel, + notif->band ? "bg" : "a", + notif->tsf_high, + notif->tsf_low, notif->status, notif->beacon_timer); +} + +/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ +static void iwl_rx_scan_results_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanresults_notification *notif = + (struct iwl_scanresults_notification *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan ch.res: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d " + "elapsed=%lu usec (%dms since last)\n", + notif->channel, + notif->band ? "bg" : "a", + le32_to_cpu(notif->tsf_high), + le32_to_cpu(notif->tsf_low), + le32_to_cpu(notif->statistics[0]), + le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, + jiffies_to_msecs(elapsed_jiffies + (priv->last_scan_jiffies, jiffies))); + + priv->last_scan_jiffies = jiffies; +} + +/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ +static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", + scan_notif->scanned_channels, + scan_notif->tsf_low, + scan_notif->tsf_high, scan_notif->status); + + /* The HW is no longer scanning */ + clear_bit(STATUS_SCAN_HW, &priv->status); + + /* The scan completion notification came in, so kill that timer... */ + cancel_delayed_work(&priv->scan_check); + + IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", + (priv->scan_bands == 2) ? "2.4" : "5.2", + jiffies_to_msecs(elapsed_jiffies + (priv->scan_pass_start, jiffies))); + + /* Remove this scanned band from the list + * of pending bands to scan */ + priv->scan_bands--; + + /* If a request to abort was given, or the scan did not succeed + * then we reset the scan state machine and terminate, + * re-queuing another scan if one has been requested */ + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_INFO("Aborted scan completed.\n"); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + } else { + /* If there are more bands on this scan pass reschedule */ + if (priv->scan_bands > 0) + goto reschedule; + } + + priv->last_scan_jiffies = jiffies; + IWL_DEBUG_INFO("Setting scan to off\n"); + + clear_bit(STATUS_SCANNING, &priv->status); + + IWL_DEBUG_INFO("Scan took %dms\n", + jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); + + queue_work(priv->workqueue, &priv->scan_completed); + + return; + +reschedule: + priv->scan_pass_start = jiffies; + queue_work(priv->workqueue, &priv->request_scan); +} + +/* Handle notification from uCode that card's power state is changing + * due to software, hardware, or critical temperature RFKILL */ +static void iwl_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); + unsigned long status = priv->status; + + IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n", + (flags & HW_CARD_DISABLED) ? "Kill" : "On", + (flags & SW_CARD_DISABLED) ? "Kill" : "On"); + + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + if (flags & HW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + + + if (flags & SW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_SW, &priv->status); + else + clear_bit(STATUS_RF_KILL_SW, &priv->status); + + iwl_scan_cancel(priv); + + if ((test_bit(STATUS_RF_KILL_HW, &status) != + test_bit(STATUS_RF_KILL_HW, &priv->status)) || + (test_bit(STATUS_RF_KILL_SW, &status) != + test_bit(STATUS_RF_KILL_SW, &priv->status))) + queue_work(priv->workqueue, &priv->rf_kill); + else + wake_up_interruptible(&priv->wait_command_queue); +} + +/** + * iwl_setup_rx_handlers - Initialize Rx handler callbacks + * + * Setup the RX handlers for each of the reply types sent from the uCode + * to the host. + * + * This function chains into the hardware specific files for them to setup + * any hardware specific handlers as well. + */ +static void iwl_setup_rx_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; + priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta; + priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; + priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = + iwl_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; + + /* NOTE: iwl_rx_statistics is different based on whether + * the build is for the 3945 or the 4965. See the + * corresponding implementation in iwl-XXXX.c + * + * The same handler is used for both the REPLY to a + * discrete statistics request from the host as well as + * for the periodic statistics notification from the uCode + */ + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics; + + priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; + priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; + priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = + iwl_rx_scan_results_notif; + priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = + iwl_rx_scan_complete_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; + priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx; + + /* Setup hardware specific Rx handlers */ + iwl_hw_rx_handler_setup(priv); +} + +/** + * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them + * @rxb: Rx buffer to reclaim + * + * If an Rx buffer has an async callback associated with it the callback + * will be executed. The attached skb (if present) will only be freed + * if the callback returns 1 + */ +static void iwl_tx_cmd_complete(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + int huge = sequence & SEQ_HUGE_FRAME; + int cmd_index; + struct iwl_cmd *cmd; + + /* 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 + * in the queue management code. */ + if (txq_id != IWL_CMD_QUEUE_NUM) + IWL_ERROR("Error wrong command queue %d command id 0x%X\n", + txq_id, pkt->hdr.cmd); + BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); + + cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); + cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[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; + rxb->skb = NULL; + } else if (cmd->meta.u.callback && + !cmd->meta.u.callback(priv, cmd, rxb->skb)) + rxb->skb = NULL; + + iwl_tx_queue_reclaim(priv, txq_id, index); + + if (!(cmd->meta.flags & CMD_ASYNC)) { + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + } +} + +/************************** RX-FUNCTIONS ****************************/ +/* + * Rx theory of operation + * + * The host allocates 32 DMA target addresses and passes the host address + * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is + * 0 to 31 + * + * Rx Queue Indexes + * The host/firmware share two index registers for managing the Rx buffers. + * + * The READ index maps to the first position that the firmware may be writing + * to -- the driver can read up to (but not including) this position and get + * good data. + * The READ index is managed by the firmware once the card is enabled. + * + * The WRITE index maps to the last position the driver has read from -- the + * position preceding WRITE is the last slot the firmware can place a packet. + * + * The queue is empty (no good data) if WRITE = READ - 1, and is full if + * WRITE = READ. + * + * During initialization the host sets up the READ queue position to the first + * INDEX position, and WRITE to the last (READ - 1 wrapped) + * + * When the firmware places a packet in a buffer it will advance the READ index + * and fire the RX interrupt. The driver can then query the READ index and + * process as many packets as possible, moving the WRITE index forward as it + * resets the Rx queue buffers with new memory. + * + * The management in the driver is as follows: + * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When + * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replensish the iwl->rxq->rx_free. + * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * iwl->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) + * + A received packet is processed and handed to the kernel network stack, + * detached from the iwl->rxq. The driver 'processed' index is updated. + * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free + * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ + * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there + * were enough free buffers and RX_STALLED is set it is cleared. + * + * + * Driver sequence: + * + * iwl_rx_queue_alloc() Allocates rx_free + * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl_rx_queue_restock + * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * queue, updates firmware pointers, and updates + * the WRITE index. If insufficient rx_free buffers + * are available, schedules iwl_rx_replenish + * + * -- enable interrupts -- + * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * READ INDEX, detaching the SKB from the pool. + * Moves the packet buffer from queue to rx_used. + * Calls iwl_rx_queue_restock to refill any empty + * slots. + * ... + * + */ + +/** + * iwl_rx_queue_space - Return number of free slots available in queue. + */ +static int iwl_rx_queue_space(const struct iwl_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/** + * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue + * + * NOTE: This function has 3945 and 4965 specific code sections + * but is declared in base due to the majority of the + * implementation being the same (only a numeric constant is + * different) + * + */ +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +{ + u32 reg = 0; + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + + if (q->need_update == 0) + goto exit_unlock; + + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) + goto exit_unlock; + + iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR, + q->write & ~0x7); + iwl_release_restricted_access(priv); + } else + iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + + + q->need_update = 0; + + exit_unlock: + spin_unlock_irqrestore(&q->lock, flags); + return rc; +} + +/** + * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer. + * + * NOTE: This function has 3945 and 4965 specific code paths in it. + */ +static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, + dma_addr_t dma_addr) +{ + return cpu_to_le32((u32)dma_addr); +} + +/** + * iwl_rx_queue_restock - refill RX queue from pre-allocated pool + * + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +int iwl_rx_queue_restock(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + int write, rc; + + spin_lock_irqsave(&rxq->lock, flags); + write = rxq->write & ~0x7; + while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + element = rxq->rx_free.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr); + rxq->queue[rxq->write] = rxb; + rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; + rxq->free_count--; + } + spin_unlock_irqrestore(&rxq->lock, flags); + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + queue_work(priv->workqueue, &priv->rx_replenish); + + + /* If we've added more space for the firmware to place data, tell it */ + if ((write != (rxq->write & ~0x7)) + || (abs(rxq->write - rxq->read) > 7)) { + spin_lock_irqsave(&rxq->lock, flags); + rxq->need_update = 1; + spin_unlock_irqrestore(&rxq->lock, flags); + rc = iwl_rx_queue_update_write_ptr(priv, rxq); + if (rc) + return rc; + } + + return 0; +} + +/** + * iwl_rx_replensih - Move all used packet from rx_used to rx_free + * + * When moving to rx_free an SKB is allocated for the slot. + * + * Also restock the Rx queue via iwl_rx_queue_restock. + * This is called as a scheduled work item (except for during intialization) + */ +void iwl_rx_replenish(void *data) +{ + struct iwl_priv *priv = data; + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + spin_lock_irqsave(&rxq->lock, flags); + while (!list_empty(&rxq->rx_used)) { + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + rxb->skb = + alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC); + if (!rxb->skb) { + if (net_ratelimit()) + printk(KERN_CRIT DRV_NAME + ": Can not allocate SKB buffers\n"); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ + break; + } + priv->alloc_rxb_skb++; + list_del(element); + rxb->dma_addr = + pci_map_single(priv->pci_dev, rxb->skb->data, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } + spin_unlock_irqrestore(&rxq->lock, flags); + + spin_lock_irqsave(&priv->lock, flags); + iwl_rx_queue_restock(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/* Assumes that the skb field of the buffers in 'pool' is kept accurate. + * If an SKB has been detached, the POOL needs to have it's SKB set to NULL + * This free routine walks the list of POOL entries and if SKB is set to + * non NULL it is unmapped and freed + */ +void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int i; + for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxq->pool[i].skb); + } + } + + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + rxq->bd = NULL; +} + +int iwl_rx_queue_alloc(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct pci_dev *dev = priv->pci_dev; + int i; + + spin_lock_init(&rxq->lock); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); + if (!rxq->bd) + return -ENOMEM; + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + rxq->need_update = 0; + return 0; +} + +void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + unsigned long flags; + int i; + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + priv->alloc_rxb_skb--; + dev_kfree_skb(rxq->pool[i].skb); + rxq->pool[i].skb = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); +} + +/* Convert linear signal-to-noise ratio into dB */ +static u8 ratio2dB[100] = { +/* 0 1 2 3 4 5 6 7 8 9 */ + 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ + 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ + 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ + 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ + 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ + 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ + 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ + 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ + 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ + 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ +}; + +/* Calculates a relative dB value from a ratio of linear + * (i.e. not dB) signal levels. + * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ +int iwl_calc_db_from_ratio(int sig_ratio) +{ + /* Anything above 1000:1 just report as 60 dB */ + if (sig_ratio > 1000) + return 60; + + /* Above 100:1, divide by 10 and use table, + * add 20 dB to make up for divide by 10 */ + if (sig_ratio > 100) + return (20 + (int)ratio2dB[sig_ratio/10]); + + /* We shouldn't see this */ + if (sig_ratio < 1) + return 0; + + /* Use table for ratios 1:1 - 99:1 */ + return (int)ratio2dB[sig_ratio]; +} + +#define PERFECT_RSSI (-20) /* dBm */ +#define WORST_RSSI (-95) /* dBm */ +#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) + +/* Calculate an indication of rx signal quality (a percentage, not dBm!). + * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info + * about formulas used below. */ +int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) +{ + int sig_qual; + int degradation = PERFECT_RSSI - rssi_dbm; + + /* If we get a noise measurement, use signal-to-noise ratio (SNR) + * as indicator; formula is (signal dbm - noise dbm). + * SNR at or above 40 is a great signal (100%). + * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. + * Weakest usable signal is usually 10 - 15 dB SNR. */ + if (noise_dbm) { + if (rssi_dbm - noise_dbm >= 40) + return 100; + else if (rssi_dbm < noise_dbm) + return 0; + sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; + + /* Else use just the signal level. + * This formula is a least squares fit of data points collected and + * compared with a reference system that had a percentage (%) display + * for signal quality. */ + } else + sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * + (15 * RSSI_RANGE + 62 * degradation)) / + (RSSI_RANGE * RSSI_RANGE); + + if (sig_qual > 100) + sig_qual = 100; + else if (sig_qual < 1) + sig_qual = 0; + + return sig_qual; +} + +/** + * iwl_rx_handle - Main entry function for receiving responses from the uCode + * + * Uses the priv->rx_handlers callback function array to invoke + * the appropriate handlers, including command responses, + * frame-received notifications, and other notifications. + */ +static void iwl_rx_handle(struct iwl_priv *priv) +{ + struct iwl_rx_mem_buffer *rxb; + struct iwl_rx_packet *pkt; + struct iwl_rx_queue *rxq = &priv->rxq; + u32 r, i; + int reclaim; + unsigned long flags; + + r = iwl_hw_get_rx_read(priv); + i = rxq->read; + + /* Rx interrupt, but nothing sent from uCode */ + if (i == r) + IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + + while (i != r) { + rxb = rxq->queue[i]; + + /* If an RXB doesn't have a queue slot associated with it + * then a bug has been introduced in the queue refilling + * routines -- catch it here */ + BUG_ON(rxb == NULL); + + rxq->queue[i] = NULL; + + pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, + IWL_RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + pkt = (struct iwl_rx_packet *)rxb->skb->data; + + /* Reclaim a command buffer only if this packet is a response + * to a (driver-originated) command. + * If the packet (e.g. Rx frame) originated from uCode, + * there is no command buffer to reclaim. + * Ucode should set SEQ_RX_FRAME bit if ucode-originated, + * but apparently a few don't get set; catch them here. */ + reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && + (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && + (pkt->hdr.cmd != REPLY_TX); + + /* Based on type of command response or notification, + * handle those that need handling via function in + * rx_handlers table. See iwl_setup_rx_handlers() */ + if (priv->rx_handlers[pkt->hdr.cmd]) { + IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + "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); + } else { + /* No handling needed */ + IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + "r %d i %d No handler needed for %s, 0x%02x\n", + r, i, get_cmd_string(pkt->hdr.cmd), + pkt->hdr.cmd); + } + + if (reclaim) { + /* Invoke any callbacks, transfer the skb to caller, + * and fire off the (possibly) blocking iwl_send_cmd() + * as we reclaim the driver command queue */ + if (rxb && rxb->skb) + iwl_tx_cmd_complete(priv, rxb); + else + IWL_WARNING("Claim null rxb?\n"); + } + + /* For now we just don't re-use anything. We can tweak this + * later to try and re-use notification packets and SKBs that + * fail to Rx correctly */ + if (rxb->skb != NULL) { + priv->alloc_rxb_skb--; + dev_kfree_skb_any(rxb->skb); + rxb->skb = NULL; + } + + pci_unmap_single(priv->pci_dev, rxb->dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &priv->rxq.rx_used); + spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; + } + + /* Backtrack one entry */ + priv->rxq.read = i; + iwl_rx_queue_restock(priv); +} + +int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq) +{ + u32 reg = 0; + int rc = 0; + int txq_id = txq->q.id; + + if (txq->need_update == 0) + return rc; + + /* if we're trying to save power */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + return rc; + } + + /* restore this queue's parameters in nic hardware. */ + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + iwl_write_restricted(priv, HBUS_TARG_WRPTR, + txq->q.first_empty | (txq_id << 8)); + iwl_release_restricted_access(priv); + + /* else not in power-save mode, uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). */ + } else + iwl_write32(priv, HBUS_TARG_WRPTR, + txq->q.first_empty | (txq_id << 8)); + + txq->need_update = 0; + + return rc; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) +{ + IWL_DEBUG_RADIO("RX CONFIG:\n"); + iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); + IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); + IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", + le32_to_cpu(rxon->filter_flags)); + IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); + IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", + rxon->ofdm_basic_rates); + IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); + IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n", + MAC_ARG(rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n", + MAC_ARG(rxon->bssid_addr)); + IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); +} +#endif + +static void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR("Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); +} + +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("Disabled interrupts\n"); +} + +static const char *desc_lookup(int i) +{ + switch (i) { + case 1: + return "FAIL"; + case 2: + return "BAD_PARAM"; + case 3: + return "BAD_CHECKSUM"; + case 4: + return "NMI_INTERRUPT"; + case 5: + return "SYSASSERT"; + case 6: + return "FATAL_ERROR"; + } + + return "UNKNOWN"; +} + +#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 i; + u32 desc, time, count, base, data1; + u32 blink1, blink2, ilink1, ilink2; + int rc; + + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Not valid error log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + count = iwl_read_restricted_mem(priv, base); + + if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { + IWL_ERROR("Start IWL Error Log Dump:\n"); + IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", + priv->status, priv->config, count); + } + + IWL_ERROR("Desc Time asrtPC blink2 " + "ilink1 nmiPC Line\n"); + for (i = ERROR_START_OFFSET; + i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET; + i += ERROR_ELEM_SIZE) { + desc = iwl_read_restricted_mem(priv, base + i); + time = + iwl_read_restricted_mem(priv, base + i + 1 * sizeof(u32)); + blink1 = + iwl_read_restricted_mem(priv, base + i + 2 * sizeof(u32)); + blink2 = + iwl_read_restricted_mem(priv, base + i + 3 * sizeof(u32)); + ilink1 = + iwl_read_restricted_mem(priv, base + i + 4 * sizeof(u32)); + ilink2 = + iwl_read_restricted_mem(priv, base + i + 5 * sizeof(u32)); + data1 = + iwl_read_restricted_mem(priv, base + i + 6 * sizeof(u32)); + + IWL_ERROR + ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n", + desc_lookup(desc), desc, time, blink1, blink2, + ilink1, ilink2, data1); + } + + iwl_release_restricted_access(priv); + +} + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + * NOTE: Must be called with iwl_grab_restricted_access() already obtained! + */ +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; + + 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_restricted_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) + IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ + else { + data = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); + } + } +} + +static void iwl_dump_nic_event_log(struct iwl_priv *priv) +{ + int rc; + 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 */ + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + /* event log header */ + capacity = iwl_read_restricted_mem(priv, base); + mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERROR("Start IPW Event Log Dump: nothing in log\n"); + iwl_release_restricted_access(priv); + return; + } + + IWL_ERROR("Start IPW 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_release_restricted_access(priv); +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +static void iwl_irq_handle_error(struct iwl_priv *priv) +{ + /* Set the FW error flag -- cleared on iwl_down */ + set_bit(STATUS_FW_ERROR, &priv->status); + + /* Cancel currently queued command. */ + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + +#ifdef CONFIG_IWLWIFI_DEBUG + 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->staging_rxon); + } +#endif + + wake_up_interruptible(&priv->wait_command_queue); + + /* Keep the restart process from trying to send host + * commands by clearing the INIT status bit */ + clear_bit(STATUS_READY, &priv->status); + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + + if (iwl_is_associated(priv)) { + memcpy(&priv->recovery_rxon, &priv->active_rxon, + sizeof(priv->recovery_rxon)); + priv->error_recovering = 1; + } + queue_work(priv->workqueue, &priv->restart); + } +} + +static void iwl_error_recovery(struct iwl_priv *priv) +{ + unsigned long flags; + + memcpy(&priv->staging_rxon, &priv->recovery_rxon, + sizeof(priv->staging_rxon)); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + iwl_rxon_add_station(priv, priv->bssid, 1); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); + priv->error_recovering = 0; + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_irq_tasklet(struct iwl_priv *priv) +{ + u32 inta, handled = 0; + u32 inta_fh; + unsigned long flags; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_mask; +#endif + + spin_lock_irqsave(&priv->lock, flags); + + /* Ack/clear/reset pending uCode interrupts. + * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, + * and will clear only when CSR_FH_INT_STATUS gets cleared. */ + inta = iwl_read32(priv, CSR_INT); + iwl_write32(priv, CSR_INT, inta); + + /* Ack/clear/reset pending flow-handler (DMA) interrupts. + * Any new interrupts that happen after this, either while we're + * in this tasklet, or later, will show up in next ISR/tasklet. */ + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_ISR) { + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + } +#endif + + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not + * atomic, make sure that inta covers all the interrupts that + * we've discovered, even if FH interrupt came in just after + * reading CSR_INT. */ + if (inta_fh & CSR_FH_INT_RX_MASK) + inta |= CSR_INT_BIT_FH_RX; + if (inta_fh & CSR_FH_INT_TX_MASK) + inta |= CSR_INT_BIT_FH_TX; + + /* Now service all interrupt bits discovered above. */ + if (inta & CSR_INT_BIT_HW_ERR) { + IWL_ERROR("Microcode HW error detected. Restarting.\n"); + + /* Tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + iwl_irq_handle_error(priv); + + handled |= CSR_INT_BIT_HW_ERR; + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & (IWL_DL_ISR)) { + /* NIC fires this, but we don't use it, redundant with WAKEUP */ + if (inta & CSR_INT_BIT_MAC_CLK_ACTV) + IWL_DEBUG_ISR("Microcode started or stopped.\n"); + + /* Alive notification via Rx interrupt will do the real work */ + if (inta & CSR_INT_BIT_ALIVE) + IWL_DEBUG_ISR("Alive interrupt\n"); + } +#endif + /* Safely ignore these bits for debug checks below */ + inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE); + + /* HW RF KILL switch toggled (4965 only) */ + if (inta & CSR_INT_BIT_RF_KILL) { + int hw_rf_kill = 0; + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, + "RF_KILL bit toggled to %s.\n", + hw_rf_kill ? "disable radio":"enable radio"); + + /* Queue restart only if RF_KILL switch was set to "kill" + * when we loaded driver, and is now set to "enable". + * After we're Alive, RF_KILL gets handled by + * iwl_rx_card_state_notif() */ + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + + handled |= CSR_INT_BIT_RF_KILL; + } + + /* Chip got too hot and stopped itself (4965 only) */ + if (inta & CSR_INT_BIT_CT_KILL) { + IWL_ERROR("Microcode CT kill error detected.\n"); + handled |= CSR_INT_BIT_CT_KILL; + } + + /* Error detected by uCode */ + if (inta & CSR_INT_BIT_SW_ERR) { + IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", + inta); + iwl_irq_handle_error(priv); + handled |= CSR_INT_BIT_SW_ERR; + } + + /* uCode wakes up after power-down sleep */ + if (inta & CSR_INT_BIT_WAKEUP) { + IWL_DEBUG_ISR("Wakeup interrupt\n"); + iwl_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]); + + handled |= CSR_INT_BIT_WAKEUP; + } + + /* All uCode command responses, including Tx command responses, + * Rx "responses" (frame-received notification), and other + * notifications from uCode come through here*/ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + iwl_rx_handle(priv); + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + } + + if (inta & CSR_INT_BIT_FH_TX) { + IWL_DEBUG_ISR("Tx interrupt\n"); + + iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted(priv, + FH_TCSR_CREDIT + (ALM_FH_SRVC_CHNL), 0x0); + iwl_release_restricted_access(priv); + } + handled |= CSR_INT_BIT_FH_TX; + } + + if (inta & ~handled) + IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); + + if (inta & ~CSR_INI_SET_MASK) { + IWL_WARNING("Disabled INTA bits 0x%08x were pending\n", + inta & ~CSR_INI_SET_MASK); + IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh); + } + + /* Re-enable all interrupts */ + iwl_enable_interrupts(priv); + +#ifdef CONFIG_IWLWIFI_DEBUG + 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); + IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " + "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); + } +#endif + spin_unlock_irqrestore(&priv->lock, flags); +} + +static irqreturn_t iwl_isr(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 inta_fh; + if (!priv) + return IRQ_NONE; + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(priv, CSR_INT); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta && !inta_fh) { + IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared */ + IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + goto none; + } + + IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + tasklet_schedule(&priv->irq_tasklet); + spin_unlock(&priv->lock); + + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ + iwl_enable_interrupts(priv); + spin_unlock(&priv->lock); + return IRQ_NONE; +} + +/************************** EEPROM BANDS **************************** + * + * The iwl_eeprom_band definitions below provide the mapping from the + * EEPROM contents to the specific channel number supported for each + * band. + * + * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3 + * definition below maps to physical channel 42 in the 5.2GHz spectrum. + * The specific geography and calibration information for that channel + * is contained in the eeprom map itself. + * + * During init, we copy the eeprom information and channel map + * information into priv->channel_info_24/52 and priv->channel_map_24/52 + * + * channel_map_24/52 provides the index in the channel_info array for a + * given channel. We have to have two separate maps as there is channel + * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and + * band_2 + * + * A value of 0xff stored in the channel_map indicates that the channel + * is not supported by the hardware at all. + * + * A value of 0xfe in the channel_map indicates that the channel is not + * valid for Tx with the current hardware. This means that + * while the system can tune and receive on a given channel, it may not + * be able to associate or transmit any frames on that + * channel. There is no corresponding channel information for that + * entry. + * + *********************************************************************/ + +/* 2.4 GHz */ +static const u8 iwl_eeprom_band_1[14] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +}; + +/* 5.2 GHz bands */ +static const u8 iwl_eeprom_band_2[] = { + 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 +}; + +static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */ + 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 +}; + +static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */ + 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 +}; + +static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ + 145, 149, 153, 157, 161, 165 +}; + +static void iwl_init_band_reference(const struct iwl_priv *priv, int band, + int *eeprom_ch_count, + const struct iwl_eeprom_channel + **eeprom_ch_info, + const u8 **eeprom_ch_index) +{ + switch (band) { + case 1: /* 2.4GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); + *eeprom_ch_info = priv->eeprom.band_1_channels; + *eeprom_ch_index = iwl_eeprom_band_1; + break; + case 2: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); + *eeprom_ch_info = priv->eeprom.band_2_channels; + *eeprom_ch_index = iwl_eeprom_band_2; + break; + case 3: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); + *eeprom_ch_info = priv->eeprom.band_3_channels; + *eeprom_ch_index = iwl_eeprom_band_3; + break; + case 4: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); + *eeprom_ch_info = priv->eeprom.band_4_channels; + *eeprom_ch_index = iwl_eeprom_band_4; + break; + case 5: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); + *eeprom_ch_info = priv->eeprom.band_5_channels; + *eeprom_ch_index = iwl_eeprom_band_5; + break; + default: + BUG(); + return; + } +} + +const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, + int phymode, u16 channel) +{ + int i; + + switch (phymode) { + case MODE_IEEE80211A: + for (i = 14; i < priv->channel_count; i++) { + if (priv->channel_info[i].channel == channel) + return &priv->channel_info[i]; + } + break; + + case MODE_IEEE80211B: + case MODE_IEEE80211G: + if (channel >= 1 && channel <= 14) + return &priv->channel_info[channel - 1]; + break; + + } + + return NULL; +} + +#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ + ? # x " " : "") + +static int iwl_init_channel_map(struct iwl_priv *priv) +{ + int eeprom_ch_count = 0; + const u8 *eeprom_ch_index = NULL; + const struct iwl_eeprom_channel *eeprom_ch_info = NULL; + int band, ch; + struct iwl_channel_info *ch_info; + + if (priv->channel_count) { + IWL_DEBUG_INFO("Channel map already initialized.\n"); + return 0; + } + + if (priv->eeprom.version < 0x2f) { + IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", + priv->eeprom.version); + return -EINVAL; + } + + IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); + + priv->channel_count = + ARRAY_SIZE(iwl_eeprom_band_1) + + ARRAY_SIZE(iwl_eeprom_band_2) + + ARRAY_SIZE(iwl_eeprom_band_3) + + ARRAY_SIZE(iwl_eeprom_band_4) + + ARRAY_SIZE(iwl_eeprom_band_5); + + IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count); + + priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * + priv->channel_count, GFP_KERNEL); + if (!priv->channel_info) { + IWL_ERROR("Could not allocate channel_info\n"); + priv->channel_count = 0; + return -ENOMEM; + } + + ch_info = priv->channel_info; + + /* Loop through the 5 EEPROM bands adding them in order to the + * channel map we maintain (that contains additional information than + * what just in the EEPROM) */ + for (band = 1; band <= 5; band++) { + + iwl_init_band_reference(priv, band, &eeprom_ch_count, + &eeprom_ch_info, &eeprom_ch_index); + + /* Loop through each band adding each of the channels */ + for (ch = 0; ch < eeprom_ch_count; ch++) { + ch_info->channel = eeprom_ch_index[ch]; + ch_info->phymode = (band == 1) ? MODE_IEEE80211B : + MODE_IEEE80211A; + + /* permanently store EEPROM's channel regulatory flags + * and max power in channel info database. */ + ch_info->eeprom = eeprom_ch_info[ch]; + + /* Copy the run-time flags so they are there even on + * invalid channels */ + ch_info->flags = eeprom_ch_info[ch].flags; + + if (!(is_channel_valid(ch_info))) { + IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - " + "No traffic\n", + ch_info->channel, + ch_info->flags, + is_channel_a_band(ch_info) ? + "5.2" : "2.4"); + ch_info++; + continue; + } + + /* Initialize regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + eeprom_ch_info[ch].max_power_avg; + ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; + ch_info->min_power = 0; + + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + " %ddBm): Ad-Hoc %ssupported\n", + ch_info->channel, + is_channel_a_band(ch_info) ? + "5.2" : "2.4", + CHECK_AND_PRINT(IBSS), + CHECK_AND_PRINT(ACTIVE), + CHECK_AND_PRINT(RADAR), + CHECK_AND_PRINT(WIDE), + CHECK_AND_PRINT(NARROW), + CHECK_AND_PRINT(DFS), + eeprom_ch_info[ch].flags, + eeprom_ch_info[ch].max_power_avg, + ((eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_IBSS) + && !(eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_RADAR)) + ? "" : "not "); + + /* Set the user_txpower_limit to the highest power + * supported by any channel */ + if (eeprom_ch_info[ch].max_power_avg > + priv->user_txpower_limit) + priv->user_txpower_limit = + eeprom_ch_info[ch].max_power_avg; + + ch_info++; + } + } + + if (iwl3945_txpower_set_from_eeprom(priv)) + return -EIO; + + return 0; +} + +/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after + * sending probe req. This should be set long enough to hear probe responses + * from more than one AP. */ +#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_ACTIVE_DWELL_TIME_52 (10) + +/* For faster active scanning, scan will move to the next channel if fewer than + * PLCP_QUIET_THRESH packets are heard on this channel within + * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell + * time if it's a quiet channel (nothing responded to our probe, and there's + * no other traffic). + * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ +#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ +#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ + +/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. + * Must be set longer than active dwell time. + * For the most reliable scan, set > AP beacon interval (typically 100msec). */ +#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_PASSIVE_DWELL_TIME_52 (10) +#define IWL_PASSIVE_DWELL_BASE (100) +#define IWL_CHANNEL_TUNE_TIME 5 + +static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode) +{ + if (phymode == MODE_IEEE80211A) + return IWL_ACTIVE_DWELL_TIME_52; + else + return IWL_ACTIVE_DWELL_TIME_24; +} + +static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode) +{ + u16 active = iwl_get_active_dwell_time(priv, phymode); + u16 passive = (phymode != MODE_IEEE80211A) ? + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; + + if (iwl_is_associated(priv)) { + /* If we're associated, we clamp the maximum passive + * dwell time to be 98% of the beacon interval (minus + * 2 * channel tune time) */ + passive = priv->beacon_int; + if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive) + passive = IWL_PASSIVE_DWELL_BASE; + passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; + } + + if (passive <= active) + passive = active + 1; + + return passive; +} + +static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, + u8 is_active, u8 direct_mask, + struct iwl_scan_channel *scan_ch) +{ + const struct ieee80211_channel *channels = NULL; + const struct ieee80211_hw_mode *hw_mode; + const struct iwl_channel_info *ch_info; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int added, i; + + hw_mode = iwl_get_hw_mode(priv, phymode); + if (!hw_mode) + return 0; + + channels = hw_mode->channels; + + active_dwell = iwl_get_active_dwell_time(priv, phymode); + passive_dwell = iwl_get_passive_dwell_time(priv, phymode); + + for (i = 0, added = 0; i < hw_mode->num_channels; i++) { + if (channels[i].chan == + le16_to_cpu(priv->active_rxon.channel)) { + if (iwl_is_associated(priv)) { + IWL_DEBUG_SCAN + ("Skipping current channel %d\n", + le16_to_cpu(priv->active_rxon.channel)); + continue; + } + } else if (priv->only_active_channel) + continue; + + scan_ch->channel = channels[i].chan; + + ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", + scan_ch->channel); + continue; + } + + if (!is_active || is_channel_passive(ch_info) || + !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + scan_ch->type = 0; /* passive */ + else + scan_ch->type = 1; /* active */ + + if (scan_ch->type & 1) + scan_ch->type |= (direct_mask << 1); + + if (is_channel_narrow(ch_info)) + scan_ch->type |= (1 << 7); + + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + + /* Set power levels to defaults */ + scan_ch->tpc.dsp_atten = 110; + /* scan_pwr_info->tpc.dsp_atten; */ + + /*scan_pwr_info->tpc.tx_gain; */ + if (phymode == MODE_IEEE80211A) + scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; + else { + scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); + /* NOTE: if we were doing 6Mb OFDM for scans we'd use + * power level + scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3; + */ + } + + IWL_DEBUG_SCAN("Scanning %d [%s %d]\n", + scan_ch->channel, + (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE", + (scan_ch->type & 1) ? + active_dwell : passive_dwell); + + scan_ch++; + added++; + } + + IWL_DEBUG_SCAN("total channels to scan %d \n", added); + return added; +} + +static void iwl_reset_channel_flag(struct iwl_priv *priv) +{ + int i, j; + for (i = 0; i < 3; i++) { + struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; + for (j = 0; j < hw_mode->num_channels; j++) + hw_mode->channels[j].flag = hw_mode->channels[j].val; + } +} + +static void iwl_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT; i++) { + rates[i].rate = iwl_rates[i].ieee * 5; + rates[i].val = i; /* Rate scaling will work on indexes */ + rates[i].val2 = i; + rates[i].flags = IEEE80211_RATE_SUPPORTED; + /* Only OFDM have the bits-per-symbol set */ + if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) + rates[i].flags |= IEEE80211_RATE_OFDM; + else { + /* + * If CCK 1M then set rate flag to CCK else CCK_2 + * which is CCK | PREAMBLE2 + */ + rates[i].flags |= (iwl_rates[i].plcp == 10) ? + IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + } + + /* Set up which ones are basic rates... */ + if (IWL_BASIC_RATES_MASK & (1 << i)) + rates[i].flags |= IEEE80211_RATE_BASIC; + } +} + +/** + * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom + */ +static int iwl_init_geos(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch; + struct ieee80211_hw_mode *modes; + struct ieee80211_channel *channels; + struct ieee80211_channel *geo_ch; + struct ieee80211_rate *rates; + int i = 0; + enum { + A = 0, + B = 1, + G = 2, + }; + int mode_count = 3; + + if (priv->modes) { + IWL_DEBUG_INFO("Geography modes already initialized.\n"); + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + return 0; + } + + modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, + GFP_KERNEL); + if (!modes) + return -ENOMEM; + + channels = kzalloc(sizeof(struct ieee80211_channel) * + priv->channel_count, GFP_KERNEL); + if (!channels) { + kfree(modes); + return -ENOMEM; + } + + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), + GFP_KERNEL); + if (!rates) { + kfree(modes); + kfree(channels); + return -ENOMEM; + } + + /* 0 = 802.11a + * 1 = 802.11b + * 2 = 802.11g + */ + + /* 5.2GHz channels start after the 2.4GHz channels */ + modes[A].mode = MODE_IEEE80211A; + modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + modes[A].rates = rates; + modes[A].num_rates = 8; /* just OFDM */ + modes[A].num_channels = 0; + + modes[B].mode = MODE_IEEE80211B; + modes[B].channels = channels; + modes[B].rates = &rates[8]; + modes[B].num_rates = 4; /* just CCK */ + modes[B].num_channels = 0; + + modes[G].mode = MODE_IEEE80211G; + modes[G].channels = channels; + modes[G].rates = rates; + modes[G].num_rates = 12; /* OFDM & CCK */ + modes[G].num_channels = 0; + + priv->ieee_channels = channels; + priv->ieee_rates = rates; + + iwl_init_hw_rates(priv, rates); + + for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { + ch = &priv->channel_info[i]; + + if (!is_channel_valid(ch)) { + IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " + "skipping.\n", + ch->channel, is_channel_a_band(ch) ? + "5.2" : "2.4"); + continue; + } + + if (is_channel_a_band(ch)) + geo_ch = &modes[A].channels[modes[A].num_channels++]; + else { + geo_ch = &modes[B].channels[modes[B].num_channels++]; + modes[G].num_channels++; + } + + geo_ch->freq = ieee80211chan2mhz(ch->channel); + geo_ch->chan = ch->channel; + geo_ch->power_level = ch->max_power_avg; + geo_ch->antenna_max = 0xff; + + if (is_channel_valid(ch)) { + geo_ch->flag = IEEE80211_CHAN_W_SCAN; + if (ch->flags & EEPROM_CHANNEL_IBSS) + geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + + if (ch->flags & EEPROM_CHANNEL_ACTIVE) + geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + + if (ch->flags & EEPROM_CHANNEL_RADAR) + geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + + if (ch->max_power_avg > priv->max_channel_txpower_limit) + priv->max_channel_txpower_limit = + ch->max_power_avg; + } + + geo_ch->val = geo_ch->flag; + } + + if ((modes[A].num_channels == 0) && priv->is_abg) { + printk(KERN_INFO DRV_NAME + ": Incorrectly detected BG card as ABG. Please send " + "your PCI ID 0x%04X:0x%04X to maintainer.\n", + priv->pci_dev->device, priv->pci_dev->subsystem_device); + priv->is_abg = 0; + } + + printk(KERN_INFO DRV_NAME + ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", + modes[G].num_channels, modes[A].num_channels); + + /* + * NOTE: We register these in preference of order -- the + * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick + * a phymode based on rates or AP capabilities but seems to + * configure it purely on if the channel being configured + * is supported by a mode -- and the first match is taken + */ + + if (modes[G].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[G]); + if (modes[B].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[B]); + if (modes[A].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[A]); + + priv->modes = modes; + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + + return 0; +} + +/****************************************************************************** + * + * uCode download functions + * + ******************************************************************************/ + +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +{ + if (priv->ucode_code.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_code.len, + priv->ucode_code.v_addr, + priv->ucode_code.p_addr); + priv->ucode_code.v_addr = NULL; + } + if (priv->ucode_data.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_data.len, + priv->ucode_data.v_addr, + priv->ucode_data.p_addr); + priv->ucode_data.v_addr = NULL; + } + if (priv->ucode_data_backup.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_data_backup.len, + priv->ucode_data_backup.v_addr, + priv->ucode_data_backup.p_addr); + priv->ucode_data_backup.v_addr = NULL; + } + if (priv->ucode_init.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_init.len, + priv->ucode_init.v_addr, + priv->ucode_init.p_addr); + priv->ucode_init.v_addr = NULL; + } + if (priv->ucode_init_data.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_init_data.len, + priv->ucode_init_data.v_addr, + priv->ucode_init_data.p_addr); + priv->ucode_init_data.v_addr = NULL; + } + if (priv->ucode_boot.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_boot.len, + priv->ucode_boot.v_addr, + priv->ucode_boot.p_addr); + priv->ucode_boot.v_addr = NULL; + } +} + +/** + * iwl_verify_inst_full - verify runtime uCode image in card vs. host, + * looking at all data. + */ +static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) +{ + u32 val; + u32 save_len = len; + int rc = 0; + u32 errcnt; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); + + errcnt = 0; + for (; len > 0; len -= sizeof(u32), image++) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + save_len - len, val, le32_to_cpu(*image)); + rc = -EIO; + errcnt++; + if (errcnt >= 20) + break; + } + } + + iwl_release_restricted_access(priv); + + if (!errcnt) + IWL_DEBUG_INFO + ("ucode image in INSTRUCTION memory is good\n"); + + return rc; +} + + +/** + * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, + * using sample data 100 bytes apart. If these sample points are good, + * it's a pretty good bet that everything between them is good, too. + */ +static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +{ + u32 val; + int rc = 0; + u32 errcnt = 0; + u32 i; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, + i + RTC_INST_LOWER_BOUND); + val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { +#if 0 /* Enable this if you want to see details */ + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + i, val, *image); +#endif + rc = -EIO; + errcnt++; + if (errcnt >= 3) + break; + } + } + + iwl_release_restricted_access(priv); + + return rc; +} + + +/** + * iwl_verify_ucode - determine which instruction image is in SRAM, + * and verify its contents + */ +static int iwl_verify_ucode(struct iwl_priv *priv) +{ + __le32 *image; + u32 len; + int rc = 0; + + /* Try bootstrap */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); + return 0; + } + + /* Try initialize */ + image = (__le32 *)priv->ucode_init.v_addr; + len = priv->ucode_init.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); + return 0; + } + + /* Try runtime/protocol */ + image = (__le32 *)priv->ucode_code.v_addr; + len = priv->ucode_code.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); + return 0; + } + + IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + + /* Show first several data entries in instruction SRAM. + * Selection of bootstrap image is arbitrary. */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + rc = iwl_verify_inst_full(priv, image, len); + + return rc; +} + + +/* check contents of special bootstrap uCode SRAM */ +static int iwl_verify_bsm(struct iwl_priv *priv) +{ + __le32 *image = priv->ucode_boot.v_addr; + u32 len = priv->ucode_boot.len; + u32 reg; + u32 val; + + IWL_DEBUG_INFO("Begin verify bsm\n"); + + /* verify BSM SRAM contents */ + val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG); + for (reg = BSM_SRAM_LOWER_BOUND; + reg < BSM_SRAM_LOWER_BOUND + len; + reg += sizeof(u32), image ++) { + val = iwl_read_restricted_reg(priv, reg); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("BSM uCode verification failed at " + "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", + BSM_SRAM_LOWER_BOUND, + reg - BSM_SRAM_LOWER_BOUND, len, + val, le32_to_cpu(*image)); + return -EIO; + } + } + + IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n"); + + return 0; +} + +/** + * iwl_load_bsm - Load bootstrap instructions + * + * BSM operation: + * + * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program + * in special SRAM that does not power down during RFKILL. When powering back + * up after power-saving sleeps (or during initial uCode load), the BSM loads + * the bootstrap program into the on-board processor, and starts it. + * + * The bootstrap program loads (via DMA) instructions and data for a new + * program from host DRAM locations indicated by the host driver in the + * BSM_DRAM_* registers. Once the new program is loaded, it starts + * automatically. + * + * When initializing the NIC, the host driver points the BSM to the + * "initialize" uCode image. This uCode sets up some internal data, then + * notifies host via "initialize alive" that it is complete. + * + * The host then replaces the BSM_DRAM_* pointer values to point to the + * normal runtime uCode instructions and a backup uCode data cache buffer + * (filled initially with starting data values for the on-board processor), + * then triggers the "initialize" uCode to load and launch the runtime uCode, + * which begins normal operation. + * + * When doing a power-save shutdown, runtime uCode saves data SRAM into + * the backup data cache in DRAM before SRAM is powered down. + * + * When powering back up, the BSM loads the bootstrap program. This reloads + * the runtime uCode instructions and the backup data cache into SRAM, + * and re-launches the runtime uCode from where it left off. + */ +static int iwl_load_bsm(struct iwl_priv *priv) +{ + __le32 *image = priv->ucode_boot.v_addr; + u32 len = priv->ucode_boot.len; + dma_addr_t pinst; + dma_addr_t pdata; + u32 inst_len; + u32 data_len; + int rc; + int i; + u32 done; + u32 reg_offset; + + IWL_DEBUG_INFO("Begin load bsm\n"); + + /* make sure bootstrap program is no larger than BSM's SRAM size */ + if (len > IWL_MAX_BSM_SIZE) + return -EINVAL; + + /* Tell bootstrap uCode where to find the "Initialize" uCode + * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965. + * NOTE: iwl_initialize_alive_start() will replace these values, + * after the "initialize" uCode has run, to point to + * runtime/protocol instructions and backup data cache. */ + pinst = priv->ucode_init.p_addr; + pdata = priv->ucode_init_data.p_addr; + inst_len = priv->ucode_init.len; + data_len = priv->ucode_init_data.len; + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); + + /* Fill BSM memory with bootstrap instructions */ + for (reg_offset = BSM_SRAM_LOWER_BOUND; + reg_offset < BSM_SRAM_LOWER_BOUND + len; + reg_offset += sizeof(u32), image++) + _iwl_write_restricted_reg(priv, reg_offset, + le32_to_cpu(*image)); + + rc = iwl_verify_bsm(priv); + if (rc) { + iwl_release_restricted_access(priv); + return rc; + } + + /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ + iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0); + iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG, + RTC_INST_LOWER_BOUND); + iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); + + /* Load bootstrap code into instruction SRAM now, + * to prepare to load "initialize" uCode */ + iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + BSM_WR_CTRL_REG_BIT_START); + + /* Wait for load of bootstrap uCode to finish */ + for (i = 0; i < 100; i++) { + done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG); + if (!(done & BSM_WR_CTRL_REG_BIT_START)) + break; + udelay(10); + } + if (i < 100) + IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i); + else { + IWL_ERROR("BSM write did not complete!\n"); + return -EIO; + } + + /* Enable future boot loads whenever power management unit triggers it + * (e.g. when powering back up after power-save shutdown) */ + iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + BSM_WR_CTRL_REG_BIT_START_EN); + + iwl_release_restricted_access(priv); + + return 0; +} + +static void iwl_nic_start(struct iwl_priv *priv) +{ + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); +} + +/** + * iwl_read_ucode - Read uCode images from disk file. + * + * Copy into buffers for card to fetch via bus-mastering + */ +static int iwl_read_ucode(struct iwl_priv *priv) +{ + struct iwl_ucode *ucode; + int rc = 0; + const struct firmware *ucode_raw; + /* firmware file name contains uCode/driver compatibility version */ + const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode"; + u8 *src; + size_t len; + u32 ver, 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. */ + rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); + if (rc < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc); + goto error; + } + + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + name, ucode_raw->size); + + /* Make sure that we got at least our header! */ + if (ucode_raw->size < sizeof(*ucode)) { + IWL_ERROR("File size way too small!\n"); + rc = -EINVAL; + goto err_release; + } + + /* Data from ucode file: header followed by uCode images */ + ucode = (void *)ucode_raw->data; + + ver = le32_to_cpu(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); + + IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", + inst_size); + IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", + data_size); + IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", + init_size); + IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", + init_data_size); + IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", + boot_size); + + /* Verify size of file vs. image size info in file's header */ + if (ucode_raw->size < sizeof(*ucode) + + inst_size + data_size + init_size + + init_data_size + boot_size) { + + IWL_DEBUG_INFO("uCode file size %d too small\n", + (int)ucode_raw->size); + rc = -EINVAL; + goto err_release; + } + + /* Verify that uCode images will fit in card's SRAM */ + if (inst_size > IWL_MAX_INST_SIZE) { + IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n", + (int)inst_size); + rc = -EINVAL; + goto err_release; + } + + if (data_size > IWL_MAX_DATA_SIZE) { + IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n", + (int)data_size); + rc = -EINVAL; + goto err_release; + } + if (init_size > IWL_MAX_INST_SIZE) { + IWL_DEBUG_INFO + ("uCode init instr len %d too large to fit in card\n", + (int)init_size); + rc = -EINVAL; + goto err_release; + } + if (init_data_size > IWL_MAX_DATA_SIZE) { + IWL_DEBUG_INFO + ("uCode init data len %d too large to fit in card\n", + (int)init_data_size); + rc = -EINVAL; + goto err_release; + } + if (boot_size > IWL_MAX_BSM_SIZE) { + IWL_DEBUG_INFO + ("uCode boot instr len %d too large to fit in bsm\n", + (int)boot_size); + rc = -EINVAL; + goto err_release; + } + + /* Allocate ucode buffers for card's bus-master loading ... */ + + /* Runtime instructions and 2 copies of data: + * 1) unmodified from disk + * 2) backup cache for save/restore during power-downs */ + priv->ucode_code.len = inst_size; + priv->ucode_code.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_code.len, + &(priv->ucode_code.p_addr)); + + priv->ucode_data.len = data_size; + priv->ucode_data.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_data.len, + &(priv->ucode_data.p_addr)); + + priv->ucode_data_backup.len = data_size; + priv->ucode_data_backup.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_data_backup.len, + &(priv->ucode_data_backup.p_addr)); + + + /* Initialization instructions and data */ + priv->ucode_init.len = init_size; + priv->ucode_init.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_init.len, + &(priv->ucode_init.p_addr)); + + priv->ucode_init_data.len = init_data_size; + priv->ucode_init_data.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_init_data.len, + &(priv->ucode_init_data.p_addr)); + + /* Bootstrap (instructions only, no data) */ + priv->ucode_boot.len = boot_size; + priv->ucode_boot.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_boot.len, + &(priv->ucode_boot.p_addr)); + + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || + !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr || + !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr) + goto err_pci_alloc; + + /* 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; + IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n", + (int)len); + memcpy(priv->ucode_code.v_addr, src, len); + IWL_DEBUG_INFO("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; + IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n", + (int)len); + memcpy(priv->ucode_data.v_addr, src, len); + memcpy(priv->ucode_data_backup.v_addr, src, len); + + /* Initialization instructions (3rd block) */ + if (init_size) { + src = &ucode->data[inst_size + data_size]; + len = priv->ucode_init.len; + IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n", + (int)len); + memcpy(priv->ucode_init.v_addr, 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; + IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n", + (int)len); + memcpy(priv->ucode_init_data.v_addr, src, len); + } + + /* Bootstrap instructions (5th block) */ + src = &ucode->data[inst_size + data_size + init_size + init_data_size]; + len = priv->ucode_boot.len; + IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n", + (int)len); + memcpy(priv->ucode_boot.v_addr, src, len); + + /* We have our copies now, allow OS release its copies */ + release_firmware(ucode_raw); + return 0; + + err_pci_alloc: + IWL_ERROR("failed to allocate pci memory\n"); + rc = -ENOMEM; + iwl_dealloc_ucode_pci(priv); + + err_release: + release_firmware(ucode_raw); + + error: + return rc; +} + + +/** + * iwl_set_ucode_ptrs - Set uCode address location + * + * Tell initialization uCode where to find runtime uCode. + * + * BSM registers initially contain pointers to initialization uCode. + * We need to replace them to load runtime uCode inst and data, + * and to save runtime data when powering down. + */ +static int iwl_set_ucode_ptrs(struct iwl_priv *priv) +{ + dma_addr_t pinst; + dma_addr_t pdata; + int rc = 0; + unsigned long flags; + + /* bits 31:0 for 3945 */ + pinst = priv->ucode_code.p_addr; + pdata = priv->ucode_data_backup.p_addr; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* Tell bootstrap uCode where to find image to load */ + iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + priv->ucode_data.len); + + /* Inst bytecount must be last to set up, bit 31 signals uCode + * that all new ptr/size info is in place */ + iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, + priv->ucode_code.len | BSM_DRAM_INST_LOAD); + + iwl_release_restricted_access(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); + + return rc; +} + +/** + * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved + * + * Called after REPLY_ALIVE notification received from "initialize" uCode. + * + * The 4965 "initialize" ALIVE reply contains calibration data for: + * Voltage, temperature, and MIMO tx gain correction, now stored in priv + * (3945 does not contain this data). + * + * Tell "initialize" uCode to go ahead and load the runtime uCode. +*/ +static void iwl_init_alive_start(struct iwl_priv *priv) +{ + /* 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 + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* Bootstrap uCode has loaded initialize uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + /* Send pointers to protocol/runtime uCode image ... init code will + * load and launch runtime uCode, which will send us another "Alive" + * notification. */ + IWL_DEBUG_INFO("Initialization Alive received.\n"); + if (iwl_set_ucode_ptrs(priv)) { + /* Runtime instruction load won't happen; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); + goto restart; + } + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + + +/** + * iwl_alive_start - called after REPLY_ALIVE notification received + * from protocol/runtime uCode (initialization uCode's + * Alive gets handled by iwl_init_alive_start()). + */ +static void iwl_alive_start(struct iwl_priv *priv) +{ + int rc = 0; + int thermal_spin = 0; + u32 rfkill; + + IWL_DEBUG_INFO("Runtime Alive received.\n"); + + if (priv->card_alive.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Alive failed.\n"); + goto restart; + } + + /* Initialize uCode has loaded Runtime uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "runtime" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad runtime uCode load.\n"); + goto restart; + } + + iwl_clear_stations_table(priv); + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read rfkill status from adapter\n"); + return; + } + + rfkill = iwl_read_restricted_reg(priv, APMG_RFKILL_REG); + IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill); + iwl_release_restricted_access(priv); + + if (rfkill & 0x1) { + clear_bit(STATUS_RF_KILL_HW, &priv->status); + /* if rfkill is not on, then wait for thermal + * sensor in adapter to kick in */ + while (iwl_hw_get_temperature(priv) == 0) { + thermal_spin++; + udelay(10); + } + + if (thermal_spin) + IWL_DEBUG_INFO("Thermal calibration took %dus\n", + thermal_spin * 10); + } else + set_bit(STATUS_RF_KILL_HW, &priv->status); + + /* After the ALIVE response, we can process host commands */ + set_bit(STATUS_ALIVE, &priv->status); + + /* Clear out the uCode error bit if it is set */ + clear_bit(STATUS_FW_ERROR, &priv->status); + + rc = iwl_init_channel_map(priv); + if (rc) { + IWL_ERROR("initializing regulatory failed: %d\n", rc); + return; + } + + iwl_init_geos(priv); + + if (iwl_is_rfkill(priv)) + return; + + if (!priv->mac80211_registered) { + /* Unlock so any user space entry points can call back into + * the driver without a deadlock... */ + mutex_unlock(&priv->mutex); + iwl_rate_control_register(priv->hw); + rc = ieee80211_register_hw(priv->hw); + priv->hw->conf.beacon_int = 100; + mutex_lock(&priv->mutex); + + if (rc) { + IWL_ERROR("Failed to register network " + "device (error %d)\n", rc); + return; + } + + priv->mac80211_registered = 1; + + iwl_reset_channel_flag(priv); + } else + ieee80211_start_queues(priv->hw); + + priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); + + if (iwl_is_associated(priv)) { + struct iwl_rxon_cmd *active_rxon = + (struct iwl_rxon_cmd *)(&priv->active_rxon); + + memcpy(&priv->staging_rxon, &priv->active_rxon, + sizeof(priv->staging_rxon)); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + } else { + /* Initialize our rx_config data */ + iwl_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + } + + /* Configure BT coexistence */ + iwl_send_bt_config(priv); + + /* Configure the adapter for unassociated operation */ + iwl_commit_rxon(priv); + + /* At this point, the NIC is initialized and operational */ + priv->notif_missed_beacons = 0; + set_bit(STATUS_READY, &priv->status); + + iwl3945_reg_txpower_periodic(priv); + + IWL_DEBUG_INFO("ALIVE processing complete.\n"); + + if (priv->error_recovering) + iwl_error_recovery(priv); + + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv); + +static void __iwl_down(struct iwl_priv *priv) +{ + unsigned long flags; + int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + struct ieee80211_conf *conf = NULL; + + IWL_DEBUG_INFO(DRV_NAME " is going down\n"); + + conf = ieee80211_get_hw_conf(priv->hw); + + if (!exit_pending) + set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl_clear_stations_table(priv); + + /* Unblock any waiting calls */ + wake_up_interruptible_all(&priv->wait_command_queue); + + iwl_cancel_deferred_work(priv); + + /* Wipe out the EXIT_PENDING status bit if we are not actually + * exiting the module */ + if (!exit_pending) + clear_bit(STATUS_EXIT_PENDING, &priv->status); + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + /* If we have not previously called iwl_init() then + * clear all bits but the RF Kill and SUSPEND bits and return */ + if (!iwl_is_init(priv)) { + priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND; + goto exit; + } + + /* ...otherwise clear out all the status bits but the RF Kill and + * SUSPEND bits and continue taking the NIC down. */ + priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND | + test_bit(STATUS_FW_ERROR, &priv->status) << + STATUS_FW_ERROR; + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_hw_txq_ctx_stop(priv); + iwl_hw_rxq_stop(priv); + + spin_lock_irqsave(&priv->lock, flags); + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_restricted_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + iwl_hw_nic_stop_master(priv); + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_hw_nic_reset(priv); + + exit: + memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + priv->ibss_beacon = NULL; + + /* clear out any free frames */ + iwl_clear_free_frames(priv); +} + +static void iwl_down(struct iwl_priv *priv) +{ + mutex_lock(&priv->mutex); + __iwl_down(priv); + mutex_unlock(&priv->mutex); +} + +#define MAX_HW_RESTARTS 5 + +static int __iwl_up(struct iwl_priv *priv) +{ + int rc, i; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_WARNING("Exit pending; will not bring the NIC up\n"); + return -EIO; + } + + if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("Radio disabled by SW RF kill (module " + "parameter)\n"); + return 0; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + rc = iwl_hw_nic_init(priv); + if (rc) { + IWL_ERROR("Unable to int nic\n"); + return rc; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* Copy original ucode data image from disk into backup cache. + * This will be used to initialize the on-board processor's + * data SRAM for a clean start when the runtime program first loads. */ + memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, + priv->ucode_data.len); + + for (i = 0; i < MAX_HW_RESTARTS; i++) { + + iwl_clear_stations_table(priv); + + /* load bootstrap state machine, + * load bootstrap program into processor's memory, + * prepare to load the "initialize" uCode */ + rc = iwl_load_bsm(priv); + + if (rc) { + IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc); + continue; + } + + /* start card; "initialize" will load runtime ucode */ + iwl_nic_start(priv); + + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n", + MAC_ARG(priv->mac_addr)); + + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + + IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); + + return 0; + } + + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + + /* tried to restart and config the device for as long as our + * patience could withstand */ + IWL_ERROR("Unable to initialize device after %d attempts.\n", i); + return -EIO; +} + + +/***************************************************************************** + * + * Workqueue callbacks + * + *****************************************************************************/ + +static void iwl_bg_init_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, init_alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_init_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_rf_kill(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); + + wake_up_interruptible(&priv->wait_command_queue); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + if (!iwl_is_rfkill(priv)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, + "HW and/or SW RF Kill no longer active, restarting " + "device\n"); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } else { + + if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by SW switch\n"); + else + IWL_WARNING("Radio Frequency Kill Switch is On:\n" + "Kill switch must be turned off for " + "wireless networking to work.\n"); + } + mutex_unlock(&priv->mutex); +} + +#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) + +static void iwl_bg_scan_check(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, scan_check.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + if (test_bit(STATUS_SCANNING, &priv->status) || + test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, + "Scan completion watchdog resetting adapter (%dms)\n", + jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_request_scan(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, request_scan); + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_CMD, + .len = sizeof(struct iwl_scan_cmd), + .meta.flags = CMD_SIZE_HUGE, + }; + int rc = 0; + struct iwl_scan_cmd *scan; + struct ieee80211_conf *conf = NULL; + u8 direct_mask; + int phymode; + + conf = ieee80211_get_hw_conf(priv->hw); + + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + IWL_WARNING("request scan called when driver not ready.\n"); + goto done; + } + + /* Make sure the scan wasn't cancelled before this queued work + * was given the chance to run... */ + if (!test_bit(STATUS_SCANNING, &priv->status)) + goto done; + + /* This should never be called or scheduled if there is currently + * a scan active in the hardware. */ + if (test_bit(STATUS_SCAN_HW, &priv->status)) { + IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " + "Ignoring second request.\n"); + rc = -EIO; + goto done; + } + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); + goto done; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); + goto done; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); + goto done; + } + + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); + goto done; + } + + if (!priv->scan_bands) { + IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); + goto done; + } + + if (!priv->scan) { + priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + + IWL_MAX_SCAN_SIZE, GFP_KERNEL); + if (!priv->scan) { + rc = -ENOMEM; + goto done; + } + } + scan = priv->scan; + memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + + scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; + scan->quiet_time = IWL_ACTIVE_QUIET_TIME; + + if (iwl_is_associated(priv)) { + u16 interval = 0; + u32 extra; + u32 suspend_time = 100; + u32 scan_suspend_time = 100; + unsigned long flags; + + IWL_DEBUG_INFO("Scanning while associated...\n"); + + spin_lock_irqsave(&priv->lock, flags); + interval = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + scan->suspend_time = 0; + scan->max_out_time = cpu_to_le32(600 * 1024); + if (!interval) + interval = suspend_time; + /* + * suspend time format: + * 0-19: beacon interval in usec (time before exec.) + * 20-23: 0 + * 24-31: number of beacons (suspend between channels) + */ + + extra = (suspend_time / interval) << 24; + scan_suspend_time = 0xFF0FFFFF & + (extra | ((suspend_time % interval) * 1024)); + + scan->suspend_time = cpu_to_le32(scan_suspend_time); + IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", + scan_suspend_time, interval); + } + + /* We should add the ability for user to lock to PASSIVE ONLY */ + if (priv->one_direct_scan) { + IWL_DEBUG_SCAN + ("Kicking off one direct scan for '%s'\n", + iwl_escape_essid(priv->direct_ssid, + priv->direct_ssid_len)); + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->direct_ssid_len; + memcpy(scan->direct_scan[0].ssid, + priv->direct_ssid, priv->direct_ssid_len); + direct_mask = 1; + } else if (!iwl_is_associated(priv)) { + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->essid_len; + memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); + direct_mask = 1; + } else + direct_mask = 0; + + /* We don't build a direct scan probe request; the uCode will do + * that based on the direct_mask added to each channel entry */ + scan->tx_cmd.len = cpu_to_le16( + iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, + IWL_MAX_SCAN_SIZE - sizeof(scan), 0)); + scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; + scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; + scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + /* flags + rate selection */ + + switch (priv->scan_bands) { + case 2: + scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; + scan->tx_cmd.rate = IWL_RATE_1M_PLCP; + scan->good_CRC_th = 0; + phymode = MODE_IEEE80211G; + break; + + case 1: + scan->tx_cmd.rate = IWL_RATE_6M_PLCP; + scan->good_CRC_th = IWL_GOOD_CRC_TH; + phymode = MODE_IEEE80211A; + break; + + default: + IWL_WARNING("Invalid scan band count\n"); + goto done; + } + + /* select Rx antennas */ + scan->flags |= iwl3945_get_antenna_flags(priv); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + scan->filter_flags = RXON_FILTER_PROMISC_MSK; + + if (direct_mask) + IWL_DEBUG_SCAN + ("Initiating direct scan for %s.\n", + iwl_escape_essid(priv->essid, priv->essid_len)); + else + IWL_DEBUG_SCAN("Initiating indirect scan.\n"); + + scan->channel_count = + iwl_get_channels_for_scan( + priv, phymode, 1, /* active */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + + cmd.len += le16_to_cpu(scan->tx_cmd.len) + + scan->channel_count * sizeof(struct iwl_scan_channel); + cmd.data = scan; + scan->len = cpu_to_le16(cmd.len); + + set_bit(STATUS_SCAN_HW, &priv->status); + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + goto done; + + queue_delayed_work(priv->workqueue, &priv->scan_check, + IWL_SCAN_CHECK_WATCHDOG); + + mutex_unlock(&priv->mutex); + return; + + done: + /* inform mac80211 sacn aborted */ + queue_work(priv->workqueue, &priv->scan_completed); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_up(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl_up(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_restart(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + iwl_down(priv); + queue_work(priv->workqueue, &priv->up); +} + +static void iwl_bg_rx_replenish(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, rx_replenish); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_rx_replenish(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_post_associate(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, + post_associate.work); + + int rc = 0; + struct ieee80211_conf *conf = NULL; + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); + return; + } + + + IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n", + priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr)); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + conf = ieee80211_get_hw_conf(priv->hw); + + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); + iwl_setup_rxon_timing(priv); + rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (rc) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + + IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", + priv->assoc_id, priv->beacon_int); + + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + } + + iwl_commit_rxon(priv); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_STA: + iwl_rate_scale_init(priv->hw, IWL_AP_ID); + break; + + case IEEE80211_IF_TYPE_IBSS: + + /* clear out the station table */ + iwl_clear_stations_table(priv); + + iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl_rxon_add_station(priv, priv->bssid, 0); + iwl3945_sync_sta(priv, IWL_STA_ID, + (priv->phymode == MODE_IEEE80211A)? + IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, + CMD_ASYNC); + iwl_rate_scale_init(priv->hw, IWL_STA_ID); + iwl_send_beacon_cmd(priv); + + break; + + default: + IWL_ERROR("%s Should not be called in %d mode\n", + __FUNCTION__, priv->iw_mode); + break; + } + + iwl_sequence_reset(priv); + +#ifdef CONFIG_IWLWIFI_QOS + iwl_activate_qos(priv, 0); +#endif /* CONFIG_IWLWIFI_QOS */ + mutex_unlock(&priv->mutex); +} + +static 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)) + return; + + mutex_lock(&priv->mutex); + + set_bit(STATUS_SCAN_ABORTING, &priv->status); + iwl_send_scan_abort(priv); + + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_scan_completed(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + ieee80211_scan_completed(priv->hw); + + /* Since setting the TXPOWER may have been deferred while + * performing the scan, fire one off */ + mutex_lock(&priv->mutex); + iwl_hw_reg_send_txpower(priv); + mutex_unlock(&priv->mutex); +} + +/***************************************************************************** + * + * mac80211 entry point functions + * + *****************************************************************************/ + +static int iwl_mac_open(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + /* we should be verifying the device is ready to be opened */ + mutex_lock(&priv->mutex); + + priv->is_open = 1; + + if (!iwl_is_rfkill(priv)) + ieee80211_start_queues(priv->hw); + + mutex_unlock(&priv->mutex); + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + priv->is_open = 0; + /*netif_stop_queue(dev); */ + flush_workqueue(priv->workqueue); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + IWL_DEBUG_MAC80211("leave - monitor\n"); + return -1; + } + + IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, + ctl->tx_rate); + + if (iwl_tx_skb(priv, skb, ctl)) + dev_kfree_skb_any(skb); + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); + if (conf->mac_addr) + IWL_DEBUG_MAC80211("enter: MAC " MAC_FMT "\n", + MAC_ARG(conf->mac_addr)); + + if (priv->interface_id) { + IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + priv->interface_id = conf->if_id; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + iwl_set_mode(priv, conf->type); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +/** + * iwl_mac_config - mac80211 config callback + * + * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to + * be set inappropriately and the driver currently sets the hardware up to + * use it whenever needed. + */ +static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only + * what is exposed through include/ declrations */ + if (unlikely(!iwl_param_disable_hw_scan && + test_bit(STATUS_SCANNING, &priv->status))) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + + ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", + conf->channel, conf->phymode); + IWL_DEBUG_MAC80211("leave - invalid channel\n"); + spin_unlock_irqrestore(&priv->lock, flags); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + iwl_set_rxon_channel(priv, conf->phymode, conf->channel); + + iwl_set_flags_for_phymode(priv, conf->phymode); + + /* The list of supported rates and rate mask can be different + * for each phymode; since the phymode may have changed, reset + * the rate mask to what mac80211 lists */ + iwl_set_rate(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef IEEE80211_CONF_CHANNEL_SWITCH + if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { + iwl_hw_channel_switch(priv, conf->channel); + mutex_unlock(&priv->mutex); + return 0; + } +#endif + + iwl_radio_kill_sw(priv, !conf->radio_enabled); + + if (!conf->radio_enabled) { + IWL_DEBUG_MAC80211("leave - radio disabled\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_MAC80211("leave - RF kill\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + iwl_set_rate(priv); + + if (memcmp(&priv->active_rxon, + &priv->staging_rxon, sizeof(priv->staging_rxon))) + iwl_commit_rxon(priv); + else + IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); + + IWL_DEBUG_MAC80211("leave\n"); + + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_config_ap(struct iwl_priv *priv) +{ + int rc = 0; + + if (priv->status & STATUS_EXIT_PENDING) + return; + + /* The following should be done only at AP bring up */ + if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + + /* RXON - unassoc (to set timing command) */ + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + /* RXON Timing */ + memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); + iwl_setup_rxon_timing(priv); + rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (rc) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + /* FIXME: what should be the assoc_id for AP? */ + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & + WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + } + /* restore RXON assoc */ + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl_send_beacon_cmd(priv); + } else + iwl_send_beacon_cmd(priv); + + /* FIXME - we need to add code here to detect a totally new + * configuration, reset the AP, unassoc, rxon timing, assoc, + * clear sta table, add BCAST sta... */ +} + +static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + int rc; + + if (conf == NULL) + return -EIO; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!conf->beacon || !conf->ssid_len)) { + IWL_DEBUG_MAC80211 + ("Leaving in AP mode because HostAPD is not ready.\n"); + return 0; + } + + mutex_lock(&priv->mutex); + + IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); + if (conf->bssid) + IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n", + MAC_ARG(conf->bssid)); + + if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && + !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (priv->interface_id != if_id) { + IWL_DEBUG_MAC80211("leave - interface_id != if_id\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (!conf->bssid) { + conf->bssid = priv->mac_addr; + memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); + IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n", + MAC_ARG(conf->bssid)); + } + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = conf->beacon; + } + + if (conf->bssid && !is_zero_ether_addr(conf->bssid) && + !is_multicast_ether_addr(conf->bssid)) { + /* If there is currently a HW scan going on in the background + * then we need to cancel it else the RXON below will fail. */ + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress " + "after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + mutex_unlock(&priv->mutex); + return -EAGAIN; + } + memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); + + /* TODO: Audit driver for usage of these members and see + * if mac80211 deprecates them (priv->bssid looks like it + * shouldn't be there, but I haven't scanned the IBSS code + * to verify) - jpk */ + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_config_ap(priv); + else { + priv->staging_rxon.filter_flags |= + RXON_FILTER_ASSOC_MSK; + rc = iwl_commit_rxon(priv); + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + iwl_rxon_add_station( + priv, priv->active_rxon.bssid_addr, 1); + } + + } else { + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + } + + spin_lock_irqsave(&priv->lock, flags); + if (!conf->ssid_len) + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + else + memcpy(priv->essid, conf->ssid, conf->ssid_len); + + priv->essid_len = conf->ssid_len; + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + mutex_lock(&priv->mutex); + if (priv->interface_id == conf->if_id) { + priv->interface_id = 0; + memset(priv->bssid, 0, ETH_ALEN); + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + priv->essid_len = 0; + } + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +#define IWL_DELAY_NEXT_SCAN (HZ*2) +static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +{ + int rc = 0; + unsigned long flags; + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + spin_lock_irqsave(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + rc = -EIO; + IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); + goto out_unlock; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ + rc = -EIO; + IWL_ERROR("ERROR: APs don't scan\n"); + goto out_unlock; + } + + /* if we just finished scan ask for delay */ + if (priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, + jiffies)) { + rc = -EAGAIN; + goto out_unlock; + } + if (len) { + IWL_DEBUG_SCAN("direct scan for " + "%s [%d]\n ", + iwl_escape_essid(ssid, len), (int)len); + + priv->one_direct_scan = 1; + priv->direct_ssid_len = (u8) + min((u8) len, (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); + } + + rc = iwl_scan_initiate(priv); + + IWL_DEBUG_MAC80211("leave\n"); + +out_unlock: + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct iwl_priv *priv = hw->priv; + int rc = 0; + u8 sta_id; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_param_hwcrypto) { + IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); + return -EOPNOTSUPP; + } + + if (is_zero_ether_addr(addr)) + /* only support pairwise keys */ + return -EOPNOTSUPP; + + sta_id = iwl_hw_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - " MAC_FMT " not in station map.\n", + MAC_ARG(addr)); + return -EINVAL; + } + + mutex_lock(&priv->mutex); + + switch (cmd) { + case SET_KEY: + rc = iwl_update_sta_key_info(priv, key, sta_id); + if (!rc) { + iwl_set_rxon_hwcrypto(priv, 1); + iwl_commit_rxon(priv); + key->hw_key_idx = sta_id; + IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n"); + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + break; + case DISABLE_KEY: + rc = iwl_clear_sta_key_info(priv, sta_id); + if (!rc) { + iwl_set_rxon_hwcrypto(priv, 0); + iwl_commit_rxon(priv); + IWL_DEBUG_MAC80211("disable hwcrypto key\n"); + } + break; + default: + rc = -EINVAL; + } + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return rc; +} + +static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct iwl_priv *priv = hw->priv; +#ifdef CONFIG_IWLWIFI_QOS + unsigned long flags; + int q; +#endif /* CONFIG_IWL_QOS */ + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + if (queue >= AC_NUM) { + IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue); + return 0; + } + +#ifdef CONFIG_IWLWIFI_QOS + if (!priv->qos_data.qos_enable) { + priv->qos_data.qos_active = 0; + IWL_DEBUG_MAC80211("leave - qos not enabled\n"); + return 0; + } + q = AC_NUM - 1 - queue; + + spin_lock_irqsave(&priv->lock, flags); + + priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); + priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); + priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; + priv->qos_data.def_qos_parm.ac[q].edca_txop = + cpu_to_le16((params->burst_time * 100)); + + priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; + priv->qos_data.qos_active = 1; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_activate_qos(priv, 1); + else if (priv->assoc_id && iwl_is_associated(priv)) + iwl_activate_qos(priv, 0); + + mutex_unlock(&priv->mutex); + +#endif /*CONFIG_IWLWIFI_QOS */ + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + int i, avail; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < AC_NUM; i++) { + txq = &priv->txq[i]; + q = &txq->q; + avail = iwl_queue_space(q); + + stats->data[i].len = q->n_window - avail; + stats->data[i].limit = q->n_window - q->high_mark; + stats->data[i].count = q->n_window; + + } + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl_mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw) +{ + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + +#ifdef CONFIG_IWLWIFI_QOS + iwl_reset_qos(priv); +#endif + cancel_delayed_work(&priv->post_associate); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = 0; + priv->assoc_capability = 0; + priv->call_post_assoc_from_beacon = 0; + + /* new association get rid of ibss beacon skb */ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = NULL; + + priv->beacon_int = priv->hw->conf.beacon_int; + priv->timestamp1 = 0; + priv->timestamp0 = 0; + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + priv->beacon_int = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Per mac80211.h: This is only used in IBSS mode... */ + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not in IBSS\n"); + mutex_unlock(&priv->mutex); + return; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + + priv->only_active_channel = 0; + + iwl_set_rate(priv); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not IBSS\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = skb; + + priv->assoc_id = 0; + + IWL_DEBUG_MAC80211("leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef CONFIG_IWLWIFI_QOS + iwl_reset_qos(priv); +#endif + + queue_work(priv->workqueue, &priv->post_associate.work); + + mutex_unlock(&priv->mutex); + + return 0; +} + +/***************************************************************************** + * + * sysfs attributes + * + *****************************************************************************/ + +#ifdef CONFIG_IWLWIFI_DEBUG + +/* + * The following adds a new attribute to the sysfs representation + * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) + * used for controlling the debug level. + * + * See the level definitions in iwl for details. + */ + +static ssize_t show_debug_level(struct device_driver *d, char *buf) +{ + return sprintf(buf, "0x%08X\n", iwl_debug_level); +} +static ssize_t store_debug_level(struct device_driver *d, + const char *buf, size_t count) +{ + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 0); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + iwl_debug_level = val; + + return strnlen(buf, count); +} + +static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + +#endif /* CONFIG_IWLWIFI_DEBUG */ + +static ssize_t show_rf_kill(struct device *d, + struct device_attribute *attr, char *buf) +{ + /* + * 0 - RF kill not enabled + * 1 - SW based RF kill active (sysfs) + * 2 - HW based RF kill active + * 3 - Both HW and SW based RF kill active + */ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | + (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); + + return sprintf(buf, "%i\n", val); +} + +static ssize_t store_rf_kill(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + mutex_lock(&priv->mutex); + iwl_radio_kill_sw(priv, buf[0] == '1'); + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); + +static ssize_t show_temperature(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv)); +} + +static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); + +static ssize_t show_rs_window(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct iwl_priv *priv = d->driver_data; + return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID); +} +static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); + +static ssize_t show_tx_power(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + return sprintf(buf, "%d\n", priv->user_txpower_limit); +} + +static ssize_t store_tx_power(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 10); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in decimal form.\n", buf); + else + iwl_hw_reg_set_txpower(priv, val); + + return count; +} + +static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); + +static ssize_t show_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); +} + +static ssize_t store_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.flags) != flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", + flags); + priv->staging_rxon.flags = cpu_to_le32(flags); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); + +static ssize_t show_filter_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + le32_to_cpu(priv->active_rxon.filter_flags)); +} + +static ssize_t store_filter_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 filter_flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.filter_flags = " + "0x%04X\n", filter_flags); + priv->staging_rxon.filter_flags = + cpu_to_le32(filter_flags); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, + store_filter_flags); + +static ssize_t show_tune(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + (priv->phymode << 8) | + le16_to_cpu(priv->active_rxon.channel)); +} + +static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode); + +static ssize_t store_tune(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u16 tune = simple_strtoul(p, &p, 0); + u8 phymode = (tune >> 8) & 0xff; + u16 channel = tune & 0xff; + + IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); + + mutex_lock(&priv->mutex); + if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || + (priv->phymode != phymode)) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, phymode, channel); + if (!ch_info) { + IWL_WARNING("Requested invalid phymode/channel " + "combination: %d %d\n", phymode, channel); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing phymode and " + "rxon.channel = %d %d\n", + phymode, channel); + + iwl_set_rxon_channel(priv, phymode, channel); + iwl_set_flags_for_phymode(priv, phymode); + + iwl_set_rate(priv); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +static ssize_t show_measurement(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl_spectrum_notification measure_report; + u32 size = sizeof(measure_report), len = 0, ofs = 0; + u8 *data = (u8 *) & measure_report; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (!(priv->measurement_status & MEASUREMENT_READY)) { + spin_unlock_irqrestore(&priv->lock, flags); + return 0; + } + memcpy(&measure_report, &priv->measure_report, size); + priv->measurement_status = 0; + spin_unlock_irqrestore(&priv->lock, flags); + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static ssize_t store_measurement(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct ieee80211_measurement_params params = { + .channel = le16_to_cpu(priv->active_rxon.channel), + .start_time = cpu_to_le64(priv->last_tsf), + .duration = cpu_to_le16(1), + }; + u8 type = IWL_MEASURE_BASIC; + u8 buffer[32]; + u8 channel; + + if (count) { + char *p = buffer; + strncpy(buffer, buf, min(sizeof(buffer), count)); + channel = simple_strtoul(p, NULL, 0); + if (channel) + params.channel = channel; + + p = buffer; + while (*p && *p != ' ') + p++; + if (*p) + type = simple_strtoul(p + 1, NULL, 0); + } + + IWL_DEBUG_INFO("Invoking measurement of type %d on " + "channel %d (for '%s')\n", type, params.channel, buf); + iwl_get_measurement(priv, ¶ms, type); + + return count; +} + +static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, + show_measurement, store_measurement); +#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */ + +static ssize_t show_rate(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->sta_lock, flags); + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) + i = priv->stations[IWL_AP_ID].current_rate.s.rate; + else + i = priv->stations[IWL_STA_ID].current_rate.s.rate; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + i = iwl_rate_index_from_plcp(i); + if (i == -1) + return sprintf(buf, "0\n"); + + return sprintf(buf, "%d%s\n", + (iwl_rates[i].ieee >> 1), + (iwl_rates[i].ieee & 0x1) ? ".5" : ""); +} + +static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL); + +static ssize_t store_retry_rate(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + priv->retry_rate = simple_strtoul(buf, NULL, 0); + if (priv->retry_rate <= 0) + priv->retry_rate = 1; + + return count; +} + +static ssize_t show_retry_rate(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d", priv->retry_rate); +} + +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 rc; + int mode; + + mode = simple_strtoul(buf, NULL, 0); + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + rc = -EAGAIN; + goto out; + } + + if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC)) + mode = IWL_POWER_AC; + else + mode |= IWL_POWER_ENABLED; + + if (mode != priv->power_mode) { + rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode)); + if (rc) { + IWL_DEBUG_MAC80211("failed setting power mode.\n"); + goto out; + } + priv->power_mode = mode; + } + + rc = count; + + out: + mutex_unlock(&priv->mutex); + return rc; +} + +#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_power_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int level = IWL_POWER_LEVEL(priv->power_mode); + char *p = buf; + + p += sprintf(p, "%d ", level); + switch (level) { + case IWL_POWER_MODE_CAM: + case IWL_POWER_AC: + p += sprintf(p, "(AC)"); + break; + case IWL_POWER_BATTERY: + p += sprintf(p, "(BATTERY)"); + break; + default: + p += sprintf(p, + "(Timeout %dms, Period %dms)", + timeout_duration[level - 1] / 1000, + period_duration[level - 1] / 1000); + } + + if (!(priv->power_mode & IWL_POWER_ENABLED)) + p += sprintf(p, " OFF\n"); + else + p += sprintf(p, " \n"); + + return (p - buf + 1); + +} + +static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, + store_power_level); + +static ssize_t show_channels(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int len = 0, i; + struct ieee80211_channel *channels = NULL; + const struct ieee80211_hw_mode *hw_mode = NULL; + int count = 0; + + if (!iwl_is_ready(priv)) + return -EAGAIN; + + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G); + if (!hw_mode) + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B); + if (hw_mode) { + channels = hw_mode->channels; + count = hw_mode->num_channels; + } + + len += + sprintf(&buf[len], + "Displaying %d channels in 2.4GHz band " + "(802.11bg):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + channels[i].chan, + channels[i].power_level, + channels[i]. + flag & IEEE80211_CHAN_W_RADAR_DETECT ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) + || (channels[i]. + flag & + IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : + ", IBSS", + channels[i]. + flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? + "active/passive" : "passive only"); + + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A); + if (hw_mode) { + channels = hw_mode->channels; + count = hw_mode->num_channels; + } else { + channels = NULL; + count = 0; + } + + len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " + "(802.11a):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + channels[i].chan, + channels[i].power_level, + channels[i]. + flag & IEEE80211_CHAN_W_RADAR_DETECT ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) + || (channels[i]. + flag & + IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : + ", IBSS", + channels[i]. + flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? + "active/passive" : "passive only"); + + return len; +} + +static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); + +static ssize_t show_statistics(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + u32 size = sizeof(struct iwl_notif_statistics); + u32 len = 0, ofs = 0; + u8 *data = (u8 *) & priv->statistics; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + mutex_lock(&priv->mutex); + rc = iwl_send_statistics_request(priv); + mutex_unlock(&priv->mutex); + + if (rc) { + len = sprintf(buf, + "Error sending statistics request: 0x%08X\n", rc); + return len; + } + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); + +static ssize_t show_antenna(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", priv->antenna); +} + +static ssize_t store_antenna(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ant; + struct iwl_priv *priv = dev_get_drvdata(d); + + if (count == 0) + return 0; + + if (sscanf(buf, "%1i", &ant) != 1) { + IWL_DEBUG_INFO("not in hex or decimal form.\n"); + return count; + } + + if ((ant >= 0) && (ant <= 2)) { + IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant); + priv->antenna = (enum iwl_antenna)ant; + } else + IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant); + + + return count; +} + +static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); + +static ssize_t show_status(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + if (!iwl_is_alive(priv)) + return -EAGAIN; + return sprintf(buf, "0x%08x\n", (int)priv->status); +} + +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); + +static ssize_t dump_error_log(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + + if (p[0] == '1') + iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); + +static ssize_t dump_event_log(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + + if (p[0] == '1') + iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); + +/***************************************************************************** + * + * driver setup and teardown + * + *****************************************************************************/ + +static void iwl_setup_deferred_work(struct iwl_priv *priv) +{ + priv->workqueue = create_workqueue(DRV_NAME); + + init_waitqueue_head(&priv->wait_command_queue); + + INIT_WORK(&priv->up, iwl_bg_up); + INIT_WORK(&priv->restart, iwl_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); + INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); + INIT_WORK(&priv->request_scan, iwl_bg_request_scan); + INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); + INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); + INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate); + INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); + + iwl_hw_setup_deferred_work(priv); + + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv) +{ + iwl_hw_cancel_deferred_work(priv); + + cancel_delayed_work(&priv->scan_check); + cancel_delayed_work(&priv->alive_start); + cancel_delayed_work(&priv->post_associate); + cancel_work_sync(&priv->beacon_update); +} + +static struct attribute *iwl_sysfs_entries[] = { + &dev_attr_antenna.attr, + &dev_attr_channels.attr, + &dev_attr_dump_errors.attr, + &dev_attr_dump_events.attr, + &dev_attr_flags.attr, + &dev_attr_filter_flags.attr, +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + &dev_attr_measurement.attr, +#endif + &dev_attr_power_level.attr, + &dev_attr_rate.attr, + &dev_attr_retry_rate.attr, + &dev_attr_rf_kill.attr, + &dev_attr_rs_window.attr, + &dev_attr_statistics.attr, + &dev_attr_status.attr, + &dev_attr_temperature.attr, + &dev_attr_tune.attr, + &dev_attr_tx_power.attr, + + NULL +}; + +static struct attribute_group iwl_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = iwl_sysfs_entries, +}; + +static struct ieee80211_ops iwl_hw_ops = { + .tx = iwl_mac_tx, + .open = iwl_mac_open, + .stop = iwl_mac_stop, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_mac_config, + .config_interface = iwl_mac_config_interface, + .set_key = iwl_mac_set_key, + .get_stats = iwl_mac_get_stats, + .get_tx_stats = iwl_mac_get_tx_stats, + .conf_tx = iwl_mac_conf_tx, + .get_tsf = iwl_mac_get_tsf, + .reset_tsf = iwl_mac_reset_tsf, + .beacon_update = iwl_mac_beacon_update, + .hw_scan = iwl_mac_hw_scan +}; + +static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = 0; + u32 pci_id; + struct iwl_priv *priv; + struct ieee80211_hw *hw; + int i; + + if (iwl_param_disable_hw_scan) { + IWL_DEBUG_INFO("Disabling hw_scan\n"); + iwl_hw_ops.hw_scan = NULL; + } + + if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) || + (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) { + IWL_ERROR("invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES); + err = -EINVAL; + goto out; + } + + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops); + if (hw == NULL) { + IWL_ERROR("Can not allocate network device\n"); + err = -ENOMEM; + goto out; + } + SET_IEEE80211_DEV(hw, &pdev->dev); + + IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); + priv = hw->priv; + priv->hw = hw; + + priv->pci_dev = pdev; + priv->antenna = (enum iwl_antenna)iwl_param_antenna; +#ifdef CONFIG_IWLWIFI_DEBUG + iwl_debug_level = iwl_param_debug; + atomic_set(&priv->restrict_refcnt, 0); +#endif + priv->retry_rate = 1; + + priv->ibss_beacon = NULL; + + /* Tell mac80211 and its clients (e.g. Wireless Extensions) + * the range of signal quality values that we'll provide. + * Negative values for level/noise indicate that we'll provide dBm. + * For WE, at least, non-0 values here *enable* display of values + * in app (iwconfig). */ + hw->max_rssi = -20; /* signal level, negative indicates dBm */ + hw->max_noise = -20; /* noise level, negative indicates dBm */ + hw->max_signal = 100; /* link quality indication (%) */ + + /* Tell mac80211 our Tx characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + + hw->queues = 4; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + if (pci_enable_device(pdev)) { + err = -ENODEV; + goto out_ieee80211_free_hw; + } + + pci_set_master(pdev); + + iwl_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->phymode = -1; + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); + goto out_pci_disable_device; + } + + pci_set_drvdata(pdev, priv); + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto out_pci_disable_device; + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, 0x41, 0x00); + priv->hw_base = pci_iomap(pdev, 0, 0); + if (!priv->hw_base) { + err = -ENODEV; + goto out_pci_release_regions; + } + + IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", + (unsigned long long) pci_resource_len(pdev, 0)); + IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); + + /* Initialize module parameter values here */ + + if (iwl_param_disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); + } + + priv->iw_mode = IEEE80211_IF_TYPE_STA; + + pci_id = + (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device; + + switch (pci_id) { + case 0x42221005: /* 0x4222 0x8086 0x1005 is BG SKU */ + case 0x42221034: /* 0x4222 0x8086 0x1034 is BG SKU */ + case 0x42271014: /* 0x4227 0x8086 0x1014 is BG SKU */ + case 0x42221044: /* 0x4222 0x8086 0x1044 is BG SKU */ + priv->is_abg = 0; + break; + + /* + * Rest are assumed ABG SKU -- if this is not the + * case then the card will get the wrong 'Detected' + * line in the kernel log however the code that + * initializes the GEO table will detect no A-band + * channels and remove the is_abg mask. + */ + default: + priv->is_abg = 1; + break; + } + + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n", + priv->is_abg ? "A" : ""); + + /* Device-specific setup */ + if (iwl_hw_set_hw_setting(priv)) { + IWL_ERROR("failed to set hw settings\n"); + mutex_unlock(&priv->mutex); + goto out_iounmap; + } + +#ifdef CONFIG_IWLWIFI_QOS + if (iwl_param_qos_enable) + priv->qos_data.qos_enable = 1; + + iwl_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; +#endif /* CONFIG_IWLWIFI_QOS */ + + iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl_setup_deferred_work(priv); + iwl_setup_rx_handlers(priv); + + priv->rates_mask = IWL_RATES_MASK; + /* If power management is turned on, default to AC mode */ + priv->power_mode = IWL_POWER_AC; + priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + + pci_enable_msi(pdev); + + err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); + if (err) { + IWL_ERROR("Error allocating IRQ %d\n", pdev->irq); + goto out_disable_msi; + } + + mutex_lock(&priv->mutex); + + err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); + if (err) { + IWL_ERROR("failed to create sysfs device attributes\n"); + mutex_unlock(&priv->mutex); + goto out_release_irq; + } + + /* fetch ucode file from disk, alloc and copy to bus-master buffers ... + * ucode filename and max sizes are card-specific. */ + err = iwl_read_ucode(priv); + if (err) { + IWL_ERROR("Could not read microcode: %d\n", err); + mutex_unlock(&priv->mutex); + goto out_pci_alloc; + } + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_INFO("Queing UP work.\n"); + + queue_work(priv->workqueue, &priv->up); + + return 0; + + out_pci_alloc: + iwl_dealloc_ucode_pci(priv); + + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + + out_release_irq: + free_irq(pdev->irq, priv); + + out_disable_msi: + pci_disable_msi(pdev); + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + iwl_unset_hw_setting(priv); + + out_iounmap: + pci_iounmap(pdev, priv->hw_base); + out_pci_release_regions: + pci_release_regions(pdev); + out_pci_disable_device: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + out_ieee80211_free_hw: + ieee80211_free_hw(priv->hw); + out: + return err; +} + +static void iwl_pci_remove(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + struct list_head *p, *q; + int i; + + if (!priv) + return; + + IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); + + mutex_lock(&priv->mutex); + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + mutex_unlock(&priv->mutex); + + /* Free MAC hash list for ADHOC */ + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { + list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { + list_del(p); + kfree(list_entry(p, struct iwl_ibss_seq, list)); + } + } + + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + + iwl_dealloc_ucode_pci(priv); + + if (priv->rxq.bd) + iwl_rx_queue_free(priv, &priv->rxq); + iwl_hw_txq_ctx_free(priv); + + iwl_unset_hw_setting(priv); + iwl_clear_stations_table(priv); + + if (priv->mac80211_registered) { + ieee80211_unregister_hw(priv->hw); + iwl_rate_control_unregister(priv->hw); + } + + /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes + * priv->workqueue... so we can't take down the workqueue + * until now... */ + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + + free_irq(pdev->irq, priv); + pci_disable_msi(pdev); + pci_iounmap(pdev, priv->hw_base); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + kfree(priv->channel_info); + + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + ieee80211_free_hw(priv->hw); +} + +#ifdef CONFIG_PM + +static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + + mutex_lock(&priv->mutex); + + set_bit(STATUS_IN_SUSPEND, &priv->status); + + /* Take down the device; powers it off, etc. */ + __iwl_down(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_resume(struct iwl_priv *priv) +{ + unsigned long flags; + + /* The following it a temporary work around due to the + * suspend / resume not fully initializing the NIC correctly. + * Without all of the following, resume will not attempt to take + * down the NIC (it shouldn't really need to) and will just try + * and bring the NIC back up. However that fails during the + * ucode verification process. This then causes iwl_down to be + * called *after* iwl_hw_nic_init() has succeeded -- which + * then lets the next init sequence succeed. So, we've + * replicated all of that NIC init code here... */ + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + iwl_hw_nic_init(priv); + + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_restricted_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + iwl_hw_nic_reset(priv); + + /* Bring the device back up */ + clear_bit(STATUS_IN_SUSPEND, &priv->status); + queue_work(priv->workqueue, &priv->up); +} + +static int iwl_pci_resume(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + int err; + + printk(KERN_INFO "Coming out of suspend...\n"); + + mutex_lock(&priv->mutex); + + pci_set_power_state(pdev, PCI_D0); + err = pci_enable_device(pdev); + pci_restore_state(pdev); + + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries + * from interfering with C3 CPU state. pci_restore_state won't help + * here since it only restores the first 64 bytes pci config header. + */ + pci_write_config_byte(pdev, 0x41, 0x00); + + iwl_resume(priv); + mutex_unlock(&priv->mutex); + + return 0; +} + +#endif /* CONFIG_PM */ + +/***************************************************************************** + * + * driver and module entry point + * + *****************************************************************************/ + +static struct pci_driver iwl_driver = { + .name = DRV_NAME, + .id_table = iwl_hw_card_ids, + .probe = iwl_pci_probe, + .remove = __devexit_p(iwl_pci_remove), +#ifdef CONFIG_PM + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, +#endif +}; + +static int __init iwl_init(void) +{ + + int ret; + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + ret = pci_register_driver(&iwl_driver); + if (ret) { + IWL_ERROR("Unable to initialize PCI module\n"); + return ret; + } +#ifdef CONFIG_IWLWIFI_DEBUG + ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level); + if (ret) { + IWL_ERROR("Unable to create driver sysfs file\n"); + pci_unregister_driver(&iwl_driver); + return ret; + } +#endif + + return ret; +} + +static void __exit iwl_exit(void) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level); +#endif + pci_unregister_driver(&iwl_driver); +} + +module_param_named(antenna, iwl_param_antenna, int, 0444); +MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); +module_param_named(disable, iwl_param_disable, int, 0444); +MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); +module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444); +MODULE_PARM_DESC(hwcrypto, + "using hardware crypto engine (default 0 [software])\n"); +module_param_named(debug, iwl_param_debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); +module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444); +MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); + +module_param_named(queues_num, iwl_param_queues_num, int, 0444); +MODULE_PARM_DESC(queues_num, "number of hw queues."); + +/* QoS */ +module_param_named(qos_enable, iwl_param_qos_enable, int, 0444); +MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); + +module_exit(iwl_exit); +module_init(iwl_init); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c new file mode 100644 index 000000000000..b79dabc8c01c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -0,0 +1,9323 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +/* + * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets + * by defining IWL to either 3945 or 4965. The Makefile used when building + * the base targets will create base-3945.o and base-4965.o + * + * The eventual goal is to move as many of the #if IWL / #endif blocks out of + * this file and into the hardware specific implementation files (iwl-XXXX.c) + * and leave only the common (non #ifdef sprinkled) code in this file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "iwlwifi.h" +#include "iwl-4965.h" +#include "iwl-helpers.h" + +#ifdef CONFIG_IWLWIFI_DEBUG +u32 iwl_debug_level; +#endif + +/****************************************************************************** + * + * module boiler plate + * + ******************************************************************************/ + +/* module parameters */ +int iwl_param_disable_hw_scan; +int iwl_param_debug; +int iwl_param_disable; /* def: enable radio */ +int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */ +int iwl_param_hwcrypto; /* def: using software encryption */ +int iwl_param_qos_enable = 1; +int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; + +/* + * module name, copyright, version, etc. + * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk + */ + +#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link 4965AGN driver for Linux" + +#ifdef CONFIG_IWLWIFI_DEBUG +#define VD "d" +#else +#define VD +#endif + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#define VS "s" +#else +#define VS +#endif + +#define IWLWIFI_VERSION "0.1.15k" VD VS +#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" +#define DRV_VERSION IWLWIFI_VERSION + +/* Change firmware file name, using "-" and incrementing number, + * *only* when uCode interface or architecture changes so that it + * is not compatible with earlier drivers. + * This number will also appear in << 8 position of 1st dword of uCode file */ +#define IWL4965_UCODE_API "-1" + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + int hdr_len = ieee80211_get_hdrlen(fc); + + if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) + return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); + return NULL; +} + +static const struct ieee80211_hw_mode *iwl_get_hw_mode( + struct iwl_priv *priv, int mode) +{ + int i; + + for (i = 0; i < 3; i++) + if (priv->modes[i].mode == mode) + return &priv->modes[i]; + + return NULL; +} + +static int iwl_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + +static const char *iwl_escape_essid(const char *essid, u8 essid_len) +{ + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (iwl_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "", sizeof("")); + return escaped; + } + + essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else + *d++ = *s++; + } + *d = '\0'; + return escaped; +} + +static void iwl_print_hex_dump(int level, void *p, u32 len) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_debug_level & level)) + return; + + print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, + p, len, 1); +#endif +} + +/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** + * DMA services + * + * Theory of operation + * + * A queue is a circular buffers with 'Read' and 'Write' pointers. + * 2 empty entries always kept in the buffer to protect from overflow. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + * The IPW operates with six queues, one receive queue in the device's + * sram, one transmit queue for sending commands to the device firmware, + * and four transmit queues for data. + ***************************************************/ + +static int iwl_queue_space(const struct iwl_queue *q) +{ + int s = q->last_used - q->first_empty; + + if (q->last_used > q->first_empty) + s -= q->n_bd; + + if (s <= 0) + s += q->n_window; + /* keep some reserve to not confuse empty and full situations */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/* XXX: n_bd must be power-of-two size */ +static inline int iwl_queue_inc_wrap(int index, int n_bd) +{ + return ++index & (n_bd - 1); +} + +/* XXX: n_bd must be power-of-two size */ +static inline int iwl_queue_dec_wrap(int index, int n_bd) +{ + return --index & (n_bd - 1); +} + +static inline int x2_queue_used(const struct iwl_queue *q, int i) +{ + return q->first_empty > q->last_used ? + (i >= q->last_used && i < q->first_empty) : + !(i < q->last_used && i >= q->first_empty); +} + +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +{ + if (is_huge) + return q->n_window; + + return index & (q->n_window - 1); +} + +static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, + int count, int slots_num, u32 id) +{ + q->n_bd = count; + q->n_window = slots_num; + q->id = id; + + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ + BUG_ON(!is_power_of_2(count)); + + /* slots_num must be power-of-two size, otherwise + * get_cmd_index is broken. */ + BUG_ON(!is_power_of_2(slots_num)); + + q->low_mark = q->n_window / 4; + if (q->low_mark < 4) + q->low_mark = 4; + + q->high_mark = q->n_window / 8; + if (q->high_mark < 2) + q->high_mark = 2; + + q->first_empty = q->last_used = 0; + + return 0; +} + +static int iwl_tx_queue_alloc(struct iwl_priv *priv, + struct iwl_tx_queue *txq, u32 id) +{ + struct pci_dev *dev = priv->pci_dev; + + if (id != IWL_CMD_QUEUE_NUM) { + txq->txb = kmalloc(sizeof(txq->txb[0]) * + TFD_QUEUE_SIZE_MAX, GFP_KERNEL); + if (!txq->txb) { + IWL_ERROR("kmalloc for auxilary BD " + "structures failed\n"); + goto error; + } + } else + txq->txb = NULL; + + txq->bd = pci_alloc_consistent(dev, + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + &txq->q.dma_addr); + + if (!txq->bd) { + IWL_ERROR("pci_alloc_consistent(%zd) failed\n", + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + goto error; + } + txq->q.id = id; + + return 0; + + error: + if (txq->txb) { + kfree(txq->txb); + txq->txb = NULL; + } + + return -ENOMEM; +} + +int iwl_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq, int slots_num, u32 txq_id) +{ + struct pci_dev *dev = priv->pci_dev; + int len; + int rc = 0; + + /* alocate command space + one big command for scan since scan + * command is very huge the system will not have two scan at the + * same time */ + len = sizeof(struct iwl_cmd) * slots_num; + if (txq_id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); + if (!txq->cmd) + return -ENOMEM; + + rc = iwl_tx_queue_alloc(priv, txq, txq_id); + if (rc) { + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + return -ENOMEM; + } + txq->need_update = 0; + + /* 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)); + iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + + iwl_hw_tx_queue_init(priv, txq); + + return 0; +} + +/** + * iwl_tx_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. txq itself is not freed. + * + */ +void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int len; + + if (q->n_bd == 0) + return; + + /* first, empty all BD's */ + for (; q->first_empty != q->last_used; + q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) + iwl_hw_txq_free_tfd(priv, txq); + + len = sizeof(struct iwl_cmd) * q->n_window; + if (q->id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + /* free buffers belonging to queue itself */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + txq->q.n_bd, txq->bd, txq->q.dma_addr); + + if (txq->txb) { + kfree(txq->txb); + txq->txb = NULL; + } + + /* 0 fill whole structure */ + memset(txq, 0, sizeof(*txq)); +} + +const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +/*************** STATION TABLE MANAGEMENT **** + * + * NOTE: This needs to be overhauled to better synchronize between + * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c + * + * mac80211 should also be examined to determine if sta_info is duplicating + * the functionality provided here + */ + +/**************************************************************/ + +static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int index = IWL_INVALID_STATION; + int i; + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_setting.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + if (priv->stations[i].used && + !compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (unlikely(index == IWL_INVALID_STATION)) + goto out; + + if (priv->stations[index].used) { + priv->stations[index].used = 0; + priv->num_stations--; + } + + BUG_ON(priv->num_stations < 0); + +out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; +} + +static void iwl_clear_stations_table(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) +{ + int i; + int index = IWL_INVALID_STATION; + struct iwl_station_entry *station; + unsigned long flags_spin; + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_setting.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) { + if (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (!priv->stations[i].used && + index == IWL_INVALID_STATION) + index = i; + } + + + /* These twh conditions has the same outcome but keep them separate + since they have different meaning */ + if (unlikely(index == IWL_INVALID_STATION)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + if (priv->stations[index].used && + !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + + IWL_DEBUG_ASSOC("Add STA ID %d: " MAC_FMT "\n", index, MAC_ARG(addr)); + station = &priv->stations[index]; + station->used = 1; + priv->num_stations++; + + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + memcpy(station->sta.sta.addr, addr, ETH_ALEN); + station->sta.mode = 0; + station->sta.sta.sta_id = index; + station->sta.station_flags = 0; + +#ifdef CONFIG_IWLWIFI_HT + /* BCAST station and IBSS stations do not work in HT mode */ + if (index != priv->hw_setting.bcast_sta_id && + priv->iw_mode != IEEE80211_IF_TYPE_IBSS) + iwl4965_set_ht_add_station(priv, index); +#endif /*CONFIG_IWLWIFI_HT*/ + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + iwl_send_add_station(priv, &station->sta, flags); + return index; + +} + +/*************** DRIVER STATUS FUNCTIONS *****/ + +static inline int iwl_is_ready(struct iwl_priv *priv) +{ + /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are + * set but EXIT_PENDING is not */ + return test_bit(STATUS_READY, &priv->status) && + test_bit(STATUS_GEO_CONFIGURED, &priv->status) && + !test_bit(STATUS_EXIT_PENDING, &priv->status); +} + +static inline int iwl_is_alive(struct iwl_priv *priv) +{ + return test_bit(STATUS_ALIVE, &priv->status); +} + +static inline int iwl_is_init(struct iwl_priv *priv) +{ + return test_bit(STATUS_INIT, &priv->status); +} + +static inline int iwl_is_rfkill(struct iwl_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +static inline int iwl_is_ready_rf(struct iwl_priv *priv) +{ + + if (iwl_is_rfkill(priv)) + return 0; + + return iwl_is_ready(priv); +} + +/*************** HOST COMMAND QUEUE FUNCTIONS *****/ + +#define IWL_CMD(x) case x : return #x + +static const char *get_cmd_string(u8 cmd) +{ + switch (cmd) { + IWL_CMD(REPLY_ALIVE); + IWL_CMD(REPLY_ERROR); + IWL_CMD(REPLY_RXON); + IWL_CMD(REPLY_RXON_ASSOC); + IWL_CMD(REPLY_QOS_PARAM); + IWL_CMD(REPLY_RXON_TIMING); + IWL_CMD(REPLY_ADD_STA); + IWL_CMD(REPLY_REMOVE_STA); + IWL_CMD(REPLY_REMOVE_ALL_STA); + IWL_CMD(REPLY_TX); + IWL_CMD(REPLY_RATE_SCALE); + IWL_CMD(REPLY_LEDS_CMD); + IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(RADAR_NOTIFICATION); + IWL_CMD(REPLY_QUIET_CMD); + IWL_CMD(REPLY_CHANNEL_SWITCH); + IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); + IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); + IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); + IWL_CMD(POWER_TABLE_CMD); + IWL_CMD(PM_SLEEP_NOTIFICATION); + IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); + IWL_CMD(REPLY_SCAN_CMD); + IWL_CMD(REPLY_SCAN_ABORT_CMD); + IWL_CMD(SCAN_START_NOTIFICATION); + IWL_CMD(SCAN_RESULTS_NOTIFICATION); + IWL_CMD(SCAN_COMPLETE_NOTIFICATION); + IWL_CMD(BEACON_NOTIFICATION); + IWL_CMD(REPLY_TX_BEACON); + IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); + IWL_CMD(QUIET_NOTIFICATION); + IWL_CMD(REPLY_TX_PWR_TABLE_CMD); + IWL_CMD(MEASURE_ABORT_NOTIFICATION); + IWL_CMD(REPLY_BT_CONFIG); + IWL_CMD(REPLY_STATISTICS_CMD); + IWL_CMD(STATISTICS_NOTIFICATION); + IWL_CMD(REPLY_CARD_STATE_CMD); + IWL_CMD(CARD_STATE_NOTIFICATION); + IWL_CMD(MISSED_BEACONS_NOTIFICATION); + IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); + IWL_CMD(SENSITIVITY_CMD); + IWL_CMD(REPLY_PHY_CALIBRATION_CMD); + IWL_CMD(REPLY_RX_PHY_CMD); + IWL_CMD(REPLY_RX_MPDU_CMD); + IWL_CMD(REPLY_4965_RX); + IWL_CMD(REPLY_COMPRESSED_BA); + default: + return "UNKNOWN"; + + } +} + +#define HOST_COMPLETE_TIMEOUT (HZ / 2) + +/** + * iwl_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a point to the ucode command structure + * + * The function returns < 0 values to indicate the operation is + * failed. On success, it turns the index (> 0) of command in the + * command queue. + */ +static 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_tfd_frame *tfd; + u32 *control_flags; + struct iwl_cmd *out_cmd; + u32 idx; + u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + dma_addr_t phys_addr; + int ret; + unsigned long flags; + + /* If any of the command structures end up being larger than + * 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)); + + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + IWL_ERROR("No space for Tx\n"); + return -ENOSPC; + } + + spin_lock_irqsave(&priv->hcmd_lock, flags); + + tfd = &txq->bd[q->first_empty]; + memset(tfd, 0, sizeof(*tfd)); + + control_flags = (u32 *) tfd; + + idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE); + out_cmd = &txq->cmd[idx]; + + 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 + * information */ + + out_cmd->hdr.flags = 0; + out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | + INDEX_TO_SEQ(q->first_empty)); + if (out_cmd->meta.flags & CMD_SIZE_HUGE) + out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + + phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + + offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM); + + txq->need_update = 1; + ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0); + q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); + iwl_tx_queue_update_write_ptr(priv, txq); + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return ret ? ret : idx; +} + +int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int ret; + + BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); + + /* An asynchronous command can not expect an SKB to be set. */ + BUG_ON(cmd->meta.flags & CMD_WANT_SKB); + + /* An asynchronous command MUST have a callback. */ + BUG_ON(!cmd->meta.u.callback); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return -EBUSY; + + ret = iwl_enqueue_hcmd(priv, cmd); + if (ret < 0) { + IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + return ret; + } + return 0; +} + +int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int cmd_idx; + int ret; + static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ + + BUG_ON(cmd->meta.flags & CMD_ASYNC); + + /* A synchronous command can not have a callback set. */ + BUG_ON(cmd->meta.u.callback != NULL); + + if (atomic_xchg(&entry, 1)) { + IWL_ERROR("Error sending %s: Already sending a host command\n", + get_cmd_string(cmd->id)); + return -EBUSY; + } + + 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; + IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + goto out; + } + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + !test_bit(STATUS_HCMD_ACTIVE, &priv->status), + HOST_COMPLETE_TIMEOUT); + if (!ret) { + if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { + IWL_ERROR("Error sending %s: time out after %dms.\n", + get_cmd_string(cmd->id), + jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); + + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + ret = -ETIMEDOUT; + goto cancel; + } + } + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", + get_cmd_string(cmd->id)); + ret = -ECANCELED; + goto fail; + } + if (test_bit(STATUS_FW_ERROR, &priv->status)) { + IWL_DEBUG_INFO("Command %s failed: FW Error\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto fail; + } + if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { + IWL_ERROR("Error: Response NULL in '%s'\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto out; + } + + ret = 0; + 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 + * 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; + } +fail: + if (cmd->meta.u.skb) { + dev_kfree_skb_any(cmd->meta.u.skb); + cmd->meta.u.skb = NULL; + } +out: + atomic_set(&entry, 0); + return ret; +} + +int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + /* A command can not be asynchronous AND expect an SKB to be set. */ + BUG_ON((cmd->meta.flags & CMD_ASYNC) && + (cmd->meta.flags & CMD_WANT_SKB)); + + if (cmd->meta.flags & CMD_ASYNC) + return iwl_send_cmd_async(priv, cmd); + + return iwl_send_cmd_sync(priv, cmd); +} + +int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = len, + .data = data, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} + +static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = sizeof(val), + .data = &val, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} + +int iwl_send_statistics_request(struct iwl_priv *priv) +{ + return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); +} + +/** + * iwl_rxon_add_station - add station into station table. + * + * there is only one AP station with id= IWL_AP_ID + * NOTE: mutex must be held before calling the this fnction +*/ +static int iwl_rxon_add_station(struct iwl_priv *priv, + const u8 *addr, int is_ap) +{ + u8 rc; + + /* Remove this station if it happens to already exist */ + iwl_remove_station(priv, addr, is_ap); + + rc = iwl_add_station(priv, addr, is_ap, 0); + + iwl4965_add_station(priv, addr, is_ap); + + return rc; +} + +/** + * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON + * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz + * @channel: Any channel valid for the requested phymode + + * In addition to setting the staging RXON, priv->phymode is also set. + * + * NOTE: Does not commit to the hardware; it sets appropriate bit fields + * in the staging RXON flag structure based on the phymode + */ +static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) +{ + if (!iwl_get_channel_info(priv, phymode, channel)) { + IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", + channel, phymode); + return -EINVAL; + } + + if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && + (priv->phymode == phymode)) + return 0; + + priv->staging_rxon.channel = cpu_to_le16(channel); + if (phymode == MODE_IEEE80211A) + priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + + priv->phymode = phymode; + + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); + + return 0; +} + +/** + * iwl_check_rxon_cmd - validate RXON structure is valid + * + * NOTE: This is really only useful during development and can eventually + * be #ifdef'd out once the driver is stable and folks aren't actively + * making changes + */ +static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +{ + int error = 0; + int counter = 1; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + error |= le32_to_cpu(rxon->flags & + (RXON_FLG_TGJ_NARROW_BAND_MSK | + RXON_FLG_RADAR_DETECT_MSK)); + if (error) + IWL_WARNING("check 24G fields %d | %d\n", + counter++, error); + } else { + error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? + 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); + if (error) + IWL_WARNING("check 52 fields %d | %d\n", + counter++, error); + error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); + if (error) + IWL_WARNING("check 52 CCK %d | %d\n", + counter++, error); + } + error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; + if (error) + IWL_WARNING("check mac addr %d | %d\n", counter++, error); + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && + ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); + if (error) + IWL_WARNING("check basic rate %d | %d\n", counter++, error); + + error |= (le16_to_cpu(rxon->assoc_id) > 2007); + if (error) + IWL_WARNING("check assoc id %d | %d\n", counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); + if (error) + IWL_WARNING("check CCK and short slot %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); + if (error) + IWL_WARNING("check CCK & auto detect %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); + if (error) + IWL_WARNING("check TGG and auto detect %d | %d\n", + counter++, error); + + if (error) + IWL_WARNING("Tuning to channel %d\n", + le16_to_cpu(rxon->channel)); + + if (error) { + IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); + return -1; + } + return 0; +} + +/** + * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit + * @priv: staging_rxon is comapred to active_rxon + * + * If the RXON structure is changing sufficient to require a new + * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 + * to indicate a new tune is required. + */ +static int iwl_full_rxon_required(struct iwl_priv *priv) +{ + + /* These items are only settable from the full RXON command */ + if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + compare_ether_addr(priv->staging_rxon.bssid_addr, + priv->active_rxon.bssid_addr) || + compare_ether_addr(priv->staging_rxon.node_addr, + priv->active_rxon.node_addr) || + compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, + priv->active_rxon.wlap_bssid_addr) || + (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || + (priv->staging_rxon.channel != priv->active_rxon.channel) || + (priv->staging_rxon.air_propagation != + priv->active_rxon.air_propagation) || + (priv->staging_rxon.ofdm_ht_single_stream_basic_rates != + priv->active_rxon.ofdm_ht_single_stream_basic_rates) || + (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != + priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || + (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) || + (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) + return 1; + + /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can + * be updated with the RXON_ASSOC command -- however only some + * flag transitions are allowed using RXON_ASSOC */ + + /* Check if we are not switching bands */ + if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != + (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) + return 1; + + /* Check if we are switching association toggle */ + if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != + (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) + return 1; + + return 0; +} + +static int iwl_send_rxon_assoc(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res = NULL; + struct iwl_rxon_assoc_cmd rxon_assoc; + struct iwl_host_cmd cmd = { + .id = REPLY_RXON_ASSOC, + .len = sizeof(rxon_assoc), + .meta.flags = CMD_WANT_SKB, + .data = &rxon_assoc, + }; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_ht_single_stream_basic_rates == + rxon2->ofdm_ht_single_stream_basic_rates) && + (rxon1->ofdm_ht_dual_stream_basic_rates == + rxon2->ofdm_ht_dual_stream_basic_rates) && + (rxon1->rx_chain == rxon2->rx_chain) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = priv->staging_rxon.flags; + rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; + rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; + rxon_assoc.reserved = 0; + rxon_assoc.ofdm_ht_single_stream_basic_rates = + priv->staging_rxon.ofdm_ht_single_stream_basic_rates; + rxon_assoc.ofdm_ht_dual_stream_basic_rates = + priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; + rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n"); + rc = -EIO; + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +/** + * iwl_commit_rxon - commit staging_rxon to hardware + * + * The RXON command in staging_rxon is commited to the hardware and + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. + */ +static int iwl_commit_rxon(struct iwl_priv *priv) +{ + /* cast away the const for active_rxon in this function */ + struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -1; + + /* always get timestamp with Rx frame */ + priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; + + rc = iwl_check_rxon_cmd(&priv->staging_rxon); + if (rc) { + IWL_ERROR("Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* If we don't need to send a full RXON, we can use + * iwl_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. */ + if (!iwl_full_rxon_required(priv)) { + rc = iwl_send_rxon_assoc(priv); + if (rc) { + IWL_ERROR("Error setting RXON_ASSOC " + "configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + + return 0; + } + + /* station table will be cleared */ + priv->assoc_station_added = 0; + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; + if (!priv->error_recovering) + priv->start_calib = 0; + + iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); +#endif /* CONFIG_IWLWIFI_SENSITIVITY */ + + /* If we are currently associated and the new config requires + * an RXON_ASSOC and the new config wants the associated mask enabled, + * we must clear the associated from the active configuration + * before we apply the new config */ + if (iwl_is_associated(priv) && + (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { + IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), + &priv->active_rxon); + + /* If the mask clearing failed then we set + * active_rxon back to what it was previously */ + if (rc) { + active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; + IWL_ERROR("Error clearing ASSOC_MSK on current " + "configuration (%d).\n", rc); + return rc; + } + + /* The RXON bit toggling will have cleared out the + * station table in the uCode, so blank it in the driver + * as well */ + iwl_clear_stations_table(priv); + } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { + /* When switching from non-associated to associated, the + * uCode clears out the station table; so clear it in the + * driver as well */ + iwl_clear_stations_table(priv); + } + + IWL_DEBUG_INFO("Sending RXON\n" + "* with%s RXON_FILTER_ASSOC_MSK\n" + "* channel = %d\n" + "* bssid = " MAC_FMT "\n", + ((priv->staging_rxon.filter_flags & + RXON_FILTER_ASSOC_MSK) ? "" : "out"), + le16_to_cpu(priv->staging_rxon.channel), + MAC_ARG(priv->staging_rxon.bssid_addr)); + + /* Apply the new configuration */ + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (rc) { + IWL_ERROR("Error setting new configuration (%d).\n", rc); + return rc; + } + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + if (!priv->error_recovering) + priv->start_calib = 0; + + priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; + iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); +#endif /* CONFIG_IWLWIFI_SENSITIVITY */ + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + + /* If we issue a new RXON command which required a tune then we must + * send a new TXPOWER command or we won't be able to Tx any frames */ + rc = iwl_hw_reg_send_txpower(priv); + if (rc) { + IWL_ERROR("Error setting Tx power (%d).\n", rc); + return rc; + } + + /* Add the broadcast address so we can send broadcast frames */ + if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == + IWL_INVALID_STATION) { + IWL_ERROR("Error adding BROADCAST address for transmit.\n"); + return -EIO; + } + + /* If we have set the ASSOC_MSK and we are in BSS mode then + * add the IWL_AP_ID to the station rate table */ + if (iwl_is_associated(priv) && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { + if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + == IWL_INVALID_STATION) { + IWL_ERROR("Error adding AP address for transmit.\n"); + return -EIO; + } + priv->assoc_station_added = 1; + } + + return 0; +} + +static int iwl_send_bt_config(struct iwl_priv *priv) +{ + struct iwl_bt_cmd bt_cmd = { + .flags = 3, + .lead_time = 0xAA, + .max_kill = 1, + .kill_ack_mask = 0, + .kill_cts_mask = 0, + }; + + return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(struct iwl_bt_cmd), &bt_cmd); +} + +static int iwl_send_scan_abort(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_ABORT_CMD, + .meta.flags = CMD_WANT_SKB, + }; + + /* If there isn't a scan actively going on in the hardware + * then we are in between scan bands and not actually + * actively scanning, so don't send the abort command */ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return 0; + } + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return rc; + } + + res = (struct iwl_rx_packet *)cmd.meta.u.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 + * due to simply not being in an active scan which + * can occur if we send the scan abort before we + * the microcode has notified us that a scan is + * completed. */ + IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + clear_bit(STATUS_SCAN_HW, &priv->status); + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +static int iwl_card_state_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct sk_buff *skb) +{ + return 1; +} + +/* + * CARD_STATE_CMD + * + * Use: Sets the internal card state to enable, disable, or halt + * + * When in the 'enable' state the card operates as normal. + * When in the 'disable' state, the card enters into a low power mode. + * When in the 'halt' state, the card is shut down and must be fully + * restarted to come back on. + */ +static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_CARD_STATE_CMD, + .len = sizeof(u32), + .data = &flags, + .meta.flags = meta_flag, + }; + + if (meta_flag & CMD_ASYNC) + cmd.meta.u.callback = iwl_card_state_sync_callback; + + return iwl_send_cmd(priv, &cmd); +} + +static int iwl_add_sta_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl_rx_packet *res = NULL; + + if (!skb) { + IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); + return 1; + } + + res = (struct iwl_rx_packet *)skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + return 1; + } + + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + break; + default: + break; + } + + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +int iwl_send_add_station(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags) +{ + struct iwl_rx_packet *res = NULL; + int rc = 0; + struct iwl_host_cmd cmd = { + .id = REPLY_ADD_STA, + .len = sizeof(struct iwl_addsta_cmd), + .meta.flags = flags, + .data = sta, + }; + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_add_sta_sync_callback; + else + cmd.meta.flags |= CMD_WANT_SKB; + + rc = iwl_send_cmd(priv, &cmd); + + if (rc || (flags & CMD_ASYNC)) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + rc = -EIO; + } + + if (rc == 0) { + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); + break; + default: + rc = -EIO; + IWL_WARNING("REPLY_ADD_STA failed\n"); + break; + } + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +static int iwl_update_sta_key_info(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + __le16 key_flags = 0; + + switch (keyconf->alg) { + case ALG_CCMP: + key_flags |= STA_KEY_FLG_CCMP; + key_flags |= cpu_to_le16( + keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + break; + case ALG_TKIP: + case ALG_WEP: + return -EINVAL; + default: + return -EINVAL; + } + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, + keyconf->keylen); + + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, + keyconf->keylen); + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); + iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + return 0; +} + +static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo)); + priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); + iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + return 0; +} + +static void iwl_clear_free_frames(struct iwl_priv *priv) +{ + struct list_head *element; + + IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", + priv->frames_count); + + while (!list_empty(&priv->free_frames)) { + element = priv->free_frames.next; + list_del(element); + kfree(list_entry(element, struct iwl_frame, list)); + priv->frames_count--; + } + + if (priv->frames_count) { + IWL_WARNING("%d frames still in use. Did we lose one?\n", + priv->frames_count); + priv->frames_count = 0; + } +} + +static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + struct list_head *element; + if (list_empty(&priv->free_frames)) { + frame = kzalloc(sizeof(*frame), GFP_KERNEL); + if (!frame) { + IWL_ERROR("Could not allocate frame!\n"); + return NULL; + } + + priv->frames_count++; + return frame; + } + + element = priv->free_frames.next; + list_del(element); + return list_entry(element, struct iwl_frame, list); +} + +static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) +{ + memset(frame, 0, sizeof(*frame)); + list_add(&frame->list, &priv->free_frames); +} + +unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left) +{ + + if (!iwl_is_associated(priv) || !priv->ibss_beacon || + ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && + (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + return 0; + + if (priv->ibss_beacon->len > left) + return 0; + + memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); + + return priv->ibss_beacon->len; +} + +int iwl_rate_index_from_plcp(int plcp) +{ + int i = 0; + + if (plcp & RATE_MCS_HT_MSK) { + i = (plcp & 0xff); + + if (i >= IWL_RATE_MIMO_6M_PLCP) + i = i - IWL_RATE_MIMO_6M_PLCP; + + i += IWL_FIRST_OFDM_RATE; + /* skip 9M not supported in ht*/ + if (i >= IWL_RATE_9M_INDEX) + i += 1; + if ((i >= IWL_FIRST_OFDM_RATE) && + (i <= IWL_LAST_OFDM_RATE)) + return i; + } else { + for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) + if (iwl_rates[i].plcp == (plcp &0xFF)) + return i; + } + return -1; +} + +static u8 iwl_rate_get_lowest_plcp(int rate_mask) +{ + u8 i; + + for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; + i = iwl_rates[i].next_ieee) { + if (rate_mask & (1 << i)) + return iwl_rates[i].plcp; + } + + return IWL_RATE_INVALID; +} + +static int iwl_send_beacon_cmd(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + unsigned int frame_size; + int rc; + u8 rate; + + frame = iwl_get_free_frame(priv); + + if (!frame) { + IWL_ERROR("Could not obtain free frame buffer for beacon " + "command.\n"); + return -ENOMEM; + } + + if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { + rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & + 0xFF0); + if (rate == IWL_INVALID_RATE) + rate = IWL_RATE_6M_PLCP; + } else { + rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); + if (rate == IWL_INVALID_RATE) + rate = IWL_RATE_1M_PLCP; + } + + frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); + + rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + &frame->u.cmd[0]); + + iwl_free_frame(priv, frame); + + return rc; +} + +/****************************************************************************** + * + * EEPROM related functions + * + ******************************************************************************/ + +static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac) +{ + memcpy(mac, priv->eeprom.mac_address, 6); +} + +/** + * iwl_eeprom_init - read EEPROM contents + * + * Load the EEPROM from adapter into priv->eeprom + * + * NOTE: This routine uses the non-debug IO access functions. + */ +int iwl_eeprom_init(struct iwl_priv *priv) +{ + u16 *e = (u16 *)&priv->eeprom; + u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + u32 r; + int sz = sizeof(priv->eeprom); + int rc; + int i; + u16 addr; + + /* The EEPROM structure has several padding buffers within it + * and when adding new EEPROM maps is subject to programmer errors + * which may be very difficult to identify without explicitly + * checking the resulting size of the eeprom map. */ + BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); + + if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { + IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); + return -ENOENT; + } + + rc = iwl_eeprom_aqcuire_semaphore(priv); + if (rc < 0) { + IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n"); + return -ENOENT; + } + + /* eeprom is an array of 16bit values */ + for (addr = 0; addr < sz; addr += sizeof(u16)) { + _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); + _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + + for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; + i += IWL_EEPROM_ACCESS_DELAY) { + r = _iwl_read_restricted(priv, CSR_EEPROM_REG); + if (r & CSR_EEPROM_REG_READ_VALID_MSK) + break; + udelay(IWL_EEPROM_ACCESS_DELAY); + } + + if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + IWL_ERROR("Time out reading EEPROM[%d]", addr); + rc = -ETIMEDOUT; + goto done; + } + e[addr / 2] = le16_to_cpu(r >> 16); + } + rc = 0; + +done: + iwl_eeprom_release_semaphore(priv); + return rc; +} + +/****************************************************************************** + * + * Misc. internal state and helper functions + * + ******************************************************************************/ +#ifdef CONFIG_IWLWIFI_DEBUG + +/** + * iwl_report_frame - dump frame to syslog during debug sessions + * + * hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + * + * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type + * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats) + * is 3945-specific and gives bad output for 4965. Need to split the + * functionality, keep common stuff here. + */ +void iwl_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + u16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + int rate_sym; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + /* MAC header */ + fc = le16_to_cpu(header->frame_control); + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + rate_sym = rx_hdr->rate; + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == + (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + u32 rate; + + if (hundred) + title = "100Frames"; + else if (fc & IEEE80211_FCTL_RETRY) + title = "Retry"; + else if (ieee80211_is_assoc_response(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_response(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_response(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate = iwl_rate_index_from_plcp(rate_sym); + if (rate == -1) + rate = 0; + else + rate = iwl_rates[rate].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, fc, header->addr1[5], + length, rssi, channel, rate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, fc, header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl_print_hex_dump(IWL_DL_RX, data, length); +} +#endif + +static void iwl_unset_hw_setting(struct iwl_priv *priv) +{ + if (priv->hw_setting.shared_virt) + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl_shared), + priv->hw_setting.shared_virt, + priv->hw_setting.shared_phys); +} + +/** + * iwl_supported_rate_to_ie - fill in the supported rate in IE field + * + * return : set the bit for each supported rate insert in ie + */ +static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, + u16 basic_rate, int max_count) +{ + u16 ret_rates = 0, bit; + int i; + u8 *rates; + + rates = &(ie[1]); + + for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { + if (bit & supported_rate) { + ret_rates |= bit; + rates[*ie] = iwl_rates[i].ieee | + ((bit & basic_rate) ? 0x80 : 0x00); + *ie = *ie + 1; + if (*ie >= max_count) + break; + } + } + + return ret_rates; +} + +#ifdef CONFIG_IWLWIFI_HT +void static iwl_set_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_ht_capability *ht_cap, + u8 use_wide_chan); +#endif + +/** + * iwl_fill_probe_req - fill in all required fields and IE for probe request + */ +static u16 iwl_fill_probe_req(struct iwl_priv *priv, + struct ieee80211_mgmt *frame, + int left, int is_direct) +{ + int len = 0; + u8 *pos = NULL; + u16 ret_rates; + + /* Make sure there is enough space for the probe request, + * two mandatory IEs and the data */ + left -= 24; + if (left < 0) + return 0; + len += 24; + + frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN); + memcpy(frame->sa, priv->mac_addr, ETH_ALEN); + memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN); + frame->seq_ctrl = 0; + + /* fill in our indirect SSID IE */ + /* ...next IE... */ + + left -= 2; + if (left < 0) + return 0; + len += 2; + pos = &(frame->u.probe_req.variable[0]); + *pos++ = WLAN_EID_SSID; + *pos++ = 0; + + /* fill in our direct SSID IE... */ + if (is_direct) { + /* ...next IE... */ + left -= 2 + priv->essid_len; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_SSID; + *pos++ = priv->essid_len; + memcpy(pos, priv->essid, priv->essid_len); + pos += priv->essid_len; + len += 2 + priv->essid_len; + } + + /* fill in supported rate */ + /* ...next IE... */ + left -= 2; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_SUPP_RATES; + *pos = 0; + ret_rates = priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + iwl_supported_rate_to_ie(pos, priv->active_rate, + priv->active_rate_basic, left); + len += 2 + *pos; + pos += (*pos) + 1; + ret_rates = ~ret_rates & priv->active_rate; + + if (ret_rates == 0) + goto fill_end; + + /* fill in supported extended rate */ + /* ...next IE... */ + left -= 2; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos = 0; + iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left); + if (*pos > 0) + len += 2 + *pos; + +#ifdef CONFIG_IWLWIFI_HT + if (is_direct && priv->is_ht_enabled) { + u8 use_wide_chan = 1; + + if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) + use_wide_chan = 0; + pos += (*pos) + 1; + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_capability); + iwl_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos, + use_wide_chan); + len += 2 + sizeof(struct ieee80211_ht_capability); + } +#endif /*CONFIG_IWLWIFI_HT */ + + fill_end: + return (u16)len; +} + +/* + * QoS support +*/ +#ifdef CONFIG_IWLWIFI_QOS +static int iwl_send_qos_params_command(struct iwl_priv *priv, + struct iwl_qosparam_cmd *qos) +{ + + return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, + sizeof(struct iwl_qosparam_cmd), qos); +} + +static void iwl_reset_qos(struct iwl_priv *priv) +{ + u16 cw_min = 15; + u16 cw_max = 1023; + u8 aifs = 2; + u8 is_legacy = 0; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.qos_active = 0; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + if (!(priv->active_rate & 0xfff0)) { + cw_min = 31; + is_legacy = 1; + } + } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + cw_min = 31; + is_legacy = 1; + } + + if (priv->qos_data.qos_active) + aifs = 3; + + priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; + + if (priv->qos_data.qos_active) { + i = 1; + priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 7; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 2; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(6016); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3008); + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 3; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 4 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16((cw_max + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3264); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(1504); + } else { + for (i = 1; i < 4; i++) { + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + } + } + IWL_DEBUG_QOS("set QoS to default \n"); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_activate_qos(struct iwl_priv *priv, u8 force) +{ + unsigned long flags; + + if (priv == NULL) + return; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (!priv->qos_data.qos_enable) + return; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.def_qos_parm.qos_flags = 0; + + if (priv->qos_data.qos_cap.q_AP.queue_request && + !priv->qos_data.qos_cap.q_AP.txop_request) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_TXOP_TYPE_MSK; + + if (priv->qos_data.qos_active) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + spin_unlock_irqrestore(&priv->lock, flags); + + if (force || iwl_is_associated(priv)) { + IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", + priv->qos_data.qos_active); + + iwl_send_qos_params_command(priv, + &(priv->qos_data.def_qos_parm)); + } +} + +#endif /* CONFIG_IWLWIFI_QOS */ +/* + * Power management (not Tx power!) functions + */ +#define MSEC_TO_USEC 1024 + +#define NOSLP __constant_cpu_to_le16(0), 0, 0 +#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 +#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) +#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ + __constant_cpu_to_le32(X1), \ + __constant_cpu_to_le32(X2), \ + __constant_cpu_to_le32(X3), \ + __constant_cpu_to_le32(X4)} + + +/* default power management (not Tx power) table values */ +/* for tim 0-10 */ +static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { + {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1}, + {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} +}; + +/* for tim > 10 */ +static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { + {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), + SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), + SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), + SLP_VEC(2, 6, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), + SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} +}; + +int iwl_power_init_handle(struct iwl_priv *priv) +{ + int rc = 0, i; + struct iwl_power_mgr *pow_data; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + u16 pci_pm; + + IWL_DEBUG_POWER("Initialize power \n"); + + pow_data = &(priv->power_data); + + memset(pow_data, 0, sizeof(*pow_data)); + + pow_data->active_index = IWL_POWER_RANGE_0; + pow_data->dtim_val = 0xffff; + + memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); + memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); + + rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm); + if (rc != 0) + return 0; + else { + struct iwl_powertable_cmd *cmd; + + IWL_DEBUG_POWER("adjust power command flags\n"); + + for (i = 0; i < IWL_POWER_AC; i++) { + cmd = &pow_data->pwr_range_0[i].cmd; + + if (pci_pm & 0x1) + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + else + cmd->flags |= IWL_POWER_PCI_PM_MSK; + } + } + return rc; +} + +static int iwl_update_power_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, u32 mode) +{ + int rc = 0, i; + u8 skip; + u32 max_sleep = 0; + struct iwl_power_vec_entry *range; + u8 period = 0; + struct iwl_power_mgr *pow_data; + + if (mode > IWL_POWER_INDEX_5) { + IWL_DEBUG_POWER("Error invalid power mode \n"); + return -1; + } + pow_data = &(priv->power_data); + + if (pow_data->active_index == IWL_POWER_RANGE_0) + range = &pow_data->pwr_range_0[0]; + else + range = &pow_data->pwr_range_1[1]; + + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); + +#ifdef IWL_MAC80211_DISABLE + if (priv->assoc_network != NULL) { + unsigned long flags; + + period = priv->assoc_network->tim.tim_period; + } +#endif /*IWL_MAC80211_DISABLE */ + skip = range[mode].no_dtim; + + if (period == 0) { + period = 1; + skip = 0; + } + + if (skip == 0) { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = (le32_to_cpu(slp_itrvl) / period) * 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); + } + + IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); + IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); + IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); + IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", + le32_to_cpu(cmd->sleep_interval[0]), + le32_to_cpu(cmd->sleep_interval[1]), + le32_to_cpu(cmd->sleep_interval[2]), + le32_to_cpu(cmd->sleep_interval[3]), + le32_to_cpu(cmd->sleep_interval[4])); + + return rc; +} + +static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) +{ + u32 final_mode = mode; + int rc; + struct iwl_powertable_cmd cmd; + + /* If on battery, set to 3, + * if plugged into AC power, set to CAM ("continuosly aware mode"), + * else user level */ + switch (mode) { + case IWL_POWER_BATTERY: + final_mode = IWL_POWER_INDEX_3; + break; + case IWL_POWER_AC: + final_mode = IWL_POWER_MODE_CAM; + break; + default: + final_mode = mode; + break; + } + + cmd.keep_alive_beacons = 0; + + iwl_update_power_cmd(priv, &cmd, final_mode); + + rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); + + if (final_mode == IWL_POWER_MODE_CAM) + clear_bit(STATUS_POWER_PMI, &priv->status); + else + set_bit(STATUS_POWER_PMI, &priv->status); + + return rc; +} + +int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +{ + /* Filter incoming packets to determine if they are targeted toward + * this network, discarding packets coming from ourselves */ + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + /* packets from our adapter are dropped (echo) */ + if (!compare_ether_addr(header->addr2, priv->mac_addr)) + return 0; + /* {broad,multi}cast packets to our IBSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !compare_ether_addr(header->addr3, priv->bssid); + /* packets to our adapter go through */ + return !compare_ether_addr(header->addr1, priv->mac_addr); + case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + /* packets from our adapter are dropped (echo) */ + if (!compare_ether_addr(header->addr3, priv->mac_addr)) + return 0; + /* {broad,multi}cast packets to our BSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !compare_ether_addr(header->addr2, priv->bssid); + /* packets to our adapter go through */ + return !compare_ether_addr(header->addr1, priv->mac_addr); + } + + return 1; +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +const char *iwl_get_tx_fail_reason(u32 status) +{ + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_ENTRY(SHORT_LIMIT); + TX_STATUS_ENTRY(LONG_LIMIT); + TX_STATUS_ENTRY(FIFO_UNDERRUN); + TX_STATUS_ENTRY(MGMNT_ABORT); + TX_STATUS_ENTRY(NEXT_FRAG); + TX_STATUS_ENTRY(LIFE_EXPIRE); + TX_STATUS_ENTRY(DEST_PS); + TX_STATUS_ENTRY(ABORTED); + TX_STATUS_ENTRY(BT_RETRY); + TX_STATUS_ENTRY(STA_INVALID); + TX_STATUS_ENTRY(FRAG_DROPPED); + TX_STATUS_ENTRY(TID_DISABLE); + TX_STATUS_ENTRY(FRAME_FLUSHED); + TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); + TX_STATUS_ENTRY(TX_LOCKED); + TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); + } + + return "UNKNOWN"; +} + +/** + * iwl_scan_cancel - Cancel any currently executing HW scan + * + * NOTE: priv->mutex is not required before calling this function + */ +static int iwl_scan_cancel(struct iwl_priv *priv) +{ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCANNING, &priv->status); + return 0; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Queuing scan abort.\n"); + set_bit(STATUS_SCAN_ABORTING, &priv->status); + queue_work(priv->workqueue, &priv->abort_scan); + + } else + IWL_DEBUG_SCAN("Scan abort already in progress.\n"); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return 0; +} + +/** + * iwl_scan_cancel_timeout - Cancel any currently executing HW scan + * @ms: amount of time to wait (in milliseconds) for scan to abort + * + * NOTE: priv->mutex must be held before calling this function + */ +static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) +{ + unsigned long now = jiffies; + int ret; + + ret = iwl_scan_cancel(priv); + if (ret && ms) { + mutex_unlock(&priv->mutex); + while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && + test_bit(STATUS_SCANNING, &priv->status)) + msleep(1); + mutex_lock(&priv->mutex); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return ret; +} + +static void iwl_sequence_reset(struct iwl_priv *priv) +{ + /* Reset ieee stats */ + + /* We don't reset the net_device_stats (ieee->stats) on + * re-association */ + + priv->last_seq_num = -1; + priv->last_frag_num = -1; + priv->last_packet_time = 0; + + iwl_scan_cancel(priv); +} + +#define MAX_UCODE_BEACON_INTERVAL 4096 +#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) + +static __le16 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; + + return cpu_to_le16(new_val); +} + +static void iwl_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.dw[1] = cpu_to_le32(priv->timestamp1); + priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0); + + priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; + + tsf = priv->timestamp1; + tsf = ((tsf << 32) | priv->timestamp0); + + beacon_int = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + 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 = + iwl_adjust_beacon_interval( + le16_to_cpu(priv->rxon_timing.beacon_interval)); + } + + priv->rxon_timing.atim_window = 0; + } else { + priv->rxon_timing.beacon_interval = + iwl_adjust_beacon_interval(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 + ("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 int iwl_scan_initiate(struct iwl_priv *priv) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("APs don't scan.\n"); + return 0; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); + return -EIO; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_SCAN("Scan already in progress.\n"); + return -EAGAIN; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Scan request while abort pending. " + "Queuing.\n"); + return -EAGAIN; + } + + IWL_DEBUG_INFO("Starting scan...\n"); + priv->scan_bands = 2; + set_bit(STATUS_SCANNING, &priv->status); + priv->scan_start = jiffies; + priv->scan_pass_start = priv->scan_start; + + queue_work(priv->workqueue, &priv->request_scan); + + return 0; +} + +static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +{ + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + + if (hw_decrypt) + rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; + else + rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; + + return 0; +} + +static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) +{ + if (phymode == MODE_IEEE80211A) { + priv->staging_rxon.flags &= + ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK + | RXON_FLG_CCK_MSK); + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + } else { + /* Copied from iwl_bg_post_associate() */ + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; + priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; + } +} + +/* + * initilize rxon structure with default values fromm eeprom + */ +static void iwl_connection_init_rx_config(struct iwl_priv *priv) +{ + const struct iwl_channel_info *ch_info; + + memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_AP: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; + break; + + case IEEE80211_IF_TYPE_STA: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; + priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_IBSS: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; + priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; + priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | + RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_MNTR: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; + priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; + break; + } + +#if 0 + /* TODO: Figure out when short_preamble would be set and cache from + * that */ + if (!hw_to_local(priv->hw)->short_preamble) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; +#endif + + ch_info = iwl_get_channel_info(priv, priv->phymode, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info) + ch_info = &priv->channel_info[0]; + + /* + * in some case A channels are all non IBSS + * in this case force B/G channel + */ + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !(is_channel_ibss(ch_info))) + ch_info = &priv->channel_info[0]; + + priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); + if (is_channel_a_band(ch_info)) + priv->phymode = MODE_IEEE80211A; + else + priv->phymode = MODE_IEEE80211G; + + iwl_set_flags_for_phymode(priv, priv->phymode); + + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; + + priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); + priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; + priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; + iwl4965_set_rxon_chain(priv); +} + +static int iwl_set_mode(struct iwl_priv *priv, int mode) +{ + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + + if (mode == IEEE80211_IF_TYPE_IBSS) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, + priv->phymode, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info || !is_channel_ibss(ch_info)) { + IWL_ERROR("channel %d not IBSS channel\n", + le16_to_cpu(priv->staging_rxon.channel)); + return -EINVAL; + } + } + + cancel_delayed_work(&priv->scan_check); + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + return -EAGAIN; + } + + priv->iw_mode = mode; + + iwl_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + + iwl_clear_stations_table(priv); + + iwl_commit_rxon(priv); + + return 0; +} + +static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, + struct ieee80211_tx_control *ctl, + struct iwl_cmd *cmd, + struct sk_buff *skb_frag, + int last_frag) +{ + struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + + switch (keyinfo->alg) { + case ALG_CCMP: + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; + memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); + IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + break; + + case ALG_TKIP: +#if 0 + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; + + if (last_frag) + memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8, + 8); + else + memset(cmd->cmd.tx.tkip_mic.byte, 0, 8); +#endif + break; + + case ALG_WEP: + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | + (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; + + if (keyinfo->keylen == 13) + cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; + + memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); + + IWL_DEBUG_TX("Configuring packet for WEP encryption " + "with key %d\n", ctl->key_idx); + break; + + case ALG_NONE: + IWL_DEBUG_TX("Tx packet in the clear (encrypt requested).\n"); + break; + + default: + printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); + break; + } +} + +/* + * handle build REPLY_TX command notification. + */ +static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int is_unicast, u8 std_id) +{ + __le16 *qc; + u16 fc = le16_to_cpu(hdr->frame_control); + __le32 tx_flags = cmd->cmd.tx.tx_flags; + + cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + tx_flags |= TX_CMD_FLG_ACK_MSK; + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (ieee80211_is_probe_response(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) + tx_flags |= TX_CMD_FLG_TSF_MSK; + } else { + tx_flags &= (~TX_CMD_FLG_ACK_MSK); + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + cmd->cmd.tx.sta_id = std_id; + if (ieee80211_get_morefrag(hdr)) + tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; + + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; + } else + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + + if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + tx_flags |= TX_CMD_FLG_RTS_MSK; + tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + + if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) + tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + + tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + cmd->cmd.tx.timeout.pm_frame_timeout = + cpu_to_le16(3); + else + cmd->cmd.tx.timeout.pm_frame_timeout = + cpu_to_le16(2); + } else + cmd->cmd.tx.timeout.pm_frame_timeout = 0; + + cmd->cmd.tx.driver_txop = 0; + cmd->cmd.tx.tx_flags = tx_flags; + cmd->cmd.tx.next_frame_len = 0; +} + +static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + int sta_id; + u16 fc = le16_to_cpu(hdr->frame_control); + + /* If this frame is broadcast or not data then use the broadcast + * station id */ + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || + is_multicast_ether_addr(hdr->addr1)) + return priv->hw_setting.bcast_sta_id; + + switch (priv->iw_mode) { + + /* If this frame is part of a BSS network (we're a station), then + * we use the AP's station id */ + case IEEE80211_IF_TYPE_STA: + return IWL_AP_ID; + + /* If we are an AP, then find the station, or use BCAST */ + case IEEE80211_IF_TYPE_AP: + sta_id = iwl_hw_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + return priv->hw_setting.bcast_sta_id; + + /* If this frame is part of a IBSS network, then we use the + * target specific station id */ + case IEEE80211_IF_TYPE_IBSS: + sta_id = iwl_hw_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); + + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " + "Defaulting to broadcast...\n", + MAC_ARG(hdr->addr1)); + iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + return priv->hw_setting.bcast_sta_id; + + default: + IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); + return priv->hw_setting.bcast_sta_id; + } +} + +/* + * start REPLY_TX command process + */ +static int iwl_tx_skb(struct iwl_priv *priv, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + int txq_id = ctl->queue; + struct iwl_tx_queue *txq = NULL; + struct iwl_queue *q = NULL; + dma_addr_t phys_addr; + dma_addr_t txcmd_phys; + struct iwl_cmd *out_cmd = NULL; + u16 len, idx, len_org; + u8 id, hdr_len, unicast; + u8 sta_id; + u16 seq_number = 0; + u16 fc; + __le16 *qc; + u8 wait_write_ptr = 0; + unsigned long flags; + int rc; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_DROP("Dropping - RF KILL\n"); + goto drop_unlock; + } + + if (!priv->interface_id) { + IWL_DEBUG_DROP("Dropping - !priv->interface_id\n"); + goto drop_unlock; + } + + if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + IWL_ERROR("ERROR: No TX rate available.\n"); + goto drop_unlock; + } + + unicast = !is_multicast_ether_addr(hdr->addr1); + id = 0; + + fc = le16_to_cpu(hdr->frame_control); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (ieee80211_is_auth(fc)) + IWL_DEBUG_TX("Sending AUTH frame\n"); + else if (ieee80211_is_assoc_request(fc)) + IWL_DEBUG_TX("Sending ASSOC frame\n"); + else if (ieee80211_is_reassoc_request(fc)) + IWL_DEBUG_TX("Sending REASSOC frame\n"); +#endif + + if (!iwl_is_associated(priv) && + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { + IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + goto drop_unlock; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + hdr_len = ieee80211_get_hdrlen(fc); + sta_id = iwl_get_sta_id(priv, hdr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", + MAC_ARG(hdr->addr1)); + goto drop; + } + + IWL_DEBUG_RATE("station Id %d\n", sta_id); + + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + seq_number = priv->stations[sta_id].tid[tid].seq_number & + IEEE80211_SCTL_SEQ; + hdr->seq_ctrl = cpu_to_le16(seq_number) | + (hdr->seq_ctrl & + __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); + seq_number += 0x10; +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + /* aggregation is on for this */ + if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG) + txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + } + txq = &priv->txq[txq_id]; + q = &txq->q; + + spin_lock_irqsave(&priv->lock, flags); + + tfd = &txq->bd[q->first_empty]; + memset(tfd, 0, sizeof(*tfd)); + control_flags = (u32 *) tfd; + idx = get_cmd_index(q, q->first_empty, 0); + + memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info)); + txq->txb[q->first_empty].skb[0] = skb; + memcpy(&(txq->txb[q->first_empty].status.control), + ctl, sizeof(struct ieee80211_tx_control)); + out_cmd = &txq->cmd[idx]; + memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); + memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); + out_cmd->hdr.cmd = REPLY_TX; + out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->first_empty))); + /* copy frags header */ + memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); + + /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */ + len = priv->hw_setting.tx_cmd_len + + sizeof(struct iwl_cmd_header) + hdr_len; + + len_org = len; + len = (len + 3) & ~3; + + if (len_org != len) + len_org = 1; + else + len_org = 0; + + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); + + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + + if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + + /* 802.11 null functions have no payload... */ + len = skb->len - hdr_len; + if (len) { + phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, + len, PCI_DMA_TODEVICE); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + } + + if (len_org) + out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + + len = (u16)skb->len; + out_cmd->cmd.tx.len = cpu_to_le16(len); + + /* TODO need this for burst mode later on */ + iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + + /* set is_hcca to 0; it probably will never be implemented */ + iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + + iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys, + hdr, hdr_len, ctl, NULL); + + if (!ieee80211_get_morefrag(hdr)) { + txq->need_update = 1; + if (qc) { + u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } + } else { + wait_write_ptr = 1; + txq->need_update = 0; + } + + iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, + sizeof(out_cmd->cmd.tx)); + + iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, + ieee80211_get_hdrlen(fc)); + + iwl4965_tx_queue_update_wr_ptr(priv, txq, len); + + q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); + rc = iwl_tx_queue_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + + if (rc) + return rc; + + if ((iwl_queue_space(q) < q->high_mark) + && priv->mac80211_registered) { + if (wait_write_ptr) { + spin_lock_irqsave(&priv->lock, flags); + txq->need_update = 1; + iwl_tx_queue_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + } + + ieee80211_stop_queue(priv->hw, ctl->queue); + } + + return 0; + +drop_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +drop: + return -1; +} + +static void iwl_set_rate(struct iwl_priv *priv) +{ + const struct ieee80211_hw_mode *hw = NULL; + struct ieee80211_rate *rate; + int i; + + hw = iwl_get_hw_mode(priv, priv->phymode); + + priv->active_rate = 0; + priv->active_rate_basic = 0; + + IWL_DEBUG_RATE("Setting rates for 802.11%c\n", + hw->mode == MODE_IEEE80211A ? + 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); + + for (i = 0; i < hw->num_rates; i++) { + rate = &(hw->rates[i]); + if ((rate->val < IWL_RATE_COUNT) && + (rate->flags & IEEE80211_RATE_SUPPORTED)) { + IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", + rate->val, iwl_rates[rate->val].plcp, + (rate->flags & IEEE80211_RATE_BASIC) ? + "*" : ""); + priv->active_rate |= (1 << rate->val); + if (rate->flags & IEEE80211_RATE_BASIC) + priv->active_rate_basic |= (1 << rate->val); + } else + IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", + rate->val, iwl_rates[rate->val].plcp); + } + + IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", + priv->active_rate, priv->active_rate_basic); + + /* + * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK) + * otherwise set it to the default of all CCK rates and 6, 12, 24 for + * OFDM + */ + if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK) + priv->staging_rxon.cck_basic_rates = + ((priv->active_rate_basic & + IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF; + else + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; + + if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK) + priv->staging_rxon.ofdm_basic_rates = + ((priv->active_rate_basic & + (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >> + IWL_FIRST_OFDM_RATE) & 0xFF; + else + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; +} + +static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) +{ + unsigned long flags; + + if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status)) + return; + + IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n", + disable_radio ? "OFF" : "ON"); + + if (disable_radio) { + iwl_scan_cancel(priv); + /* FIXME: This is a workaround for AP */ + if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_SW_BIT_RFKILL); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); + set_bit(STATUS_RF_KILL_SW, &priv->status); + } + return; + } + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + clear_bit(STATUS_RF_KILL_SW, &priv->status); + spin_unlock_irqrestore(&priv->lock, flags); + + /* wake up ucode */ + msleep(10); + + spin_lock_irqsave(&priv->lock, flags); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_restricted_access(priv)) + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by HW switch\n"); + return; + } + + queue_work(priv->workqueue, &priv->restart); + return; +} + +void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, + u32 decrypt_res, struct ieee80211_rx_status *stats) +{ + u16 fc = + le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control); + + if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) + return; + + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return; + + IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); + switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { + case RX_RES_STATUS_SEC_TYPE_TKIP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_ICV_MIC) + stats->flag |= RX_FLAG_MMIC_ERROR; + case RX_RES_STATUS_SEC_TYPE_WEP: + case RX_RES_STATUS_SEC_TYPE_CCMP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_DECRYPT_OK) { + IWL_DEBUG_RX("hw decrypt successfully!!!\n"); + stats->flag |= RX_FLAG_DECRYPTED; + } + break; + + default: + break; + } +} + +void iwl_handle_data_packet_monitor(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags) +{ + struct iwl_rt_rx_hdr *iwl_rt; + + /* First cache any information we need before we overwrite + * the information provided in the skb from the hardware */ + s8 signal = stats->ssi; + s8 noise = 0; + int rate = stats->rate; + u64 tsf = stats->mactime; + __le16 phy_flags_hw = cpu_to_le16(phy_flags); + + /* We received data from the HW, so stop the watchdog */ + if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) { + IWL_DEBUG_DROP("Dropping too large packet in monitor\n"); + return; + } + + /* copy the frame data to write after where the radiotap header goes */ + iwl_rt = (void *)rxb->skb->data; + memmove(iwl_rt->payload, data, len); + + iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */ + + /* total header + data */ + iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt)); + + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, sizeof(*iwl_rt) + len); + + /* Big bitfield of all the fields we provide in radiotap */ + iwl_rt->rt_hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)); + + /* Zero the flags, we'll add to them as we go */ + iwl_rt->rt_flags = 0; + + iwl_rt->rt_tsf = cpu_to_le64(tsf); + + /* Convert to dBm */ + iwl_rt->rt_dbmsignal = signal; + iwl_rt->rt_dbmnoise = noise; + + /* Convert the channel frequency and set the flags */ + iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq); + if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); + else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); + else /* 802.11g */ + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ)); + + rate = iwl_rate_index_from_plcp(rate); + if (rate == -1) + iwl_rt->rt_rate = 0; + else + iwl_rt->rt_rate = iwl_rates[rate].ieee; + + /* antenna number */ + iwl_rt->rt_antenna = + le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if we have it */ + if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + + stats->flag |= RX_FLAG_RADIOTAP; + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + rxb->skb = NULL; +} + + +#define IWL_PACKET_RETRY_TIME HZ + +int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +{ + u16 sc = le16_to_cpu(header->seq_ctrl); + u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; + u16 frag = sc & IEEE80211_SCTL_FRAG; + u16 *last_seq, *last_frag; + unsigned long *last_time; + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS:{ + struct list_head *p; + struct iwl_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); + + __list_for_each(p, &priv->ibss_mac_hash[index]) { + entry = + list_entry(p, struct iwl_ibss_seq, list); + if (!compare_ether_addr(entry->mac, mac)) + break; + } + if (p == &priv->ibss_mac_hash[index]) { + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + IWL_ERROR + ("Cannot malloc new mac entry\n"); + return 0; + } + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num = seq; + entry->frag_num = frag; + entry->packet_time = jiffies; + list_add(&entry->list, + &priv->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num; + last_frag = &entry->frag_num; + last_time = &entry->packet_time; + break; + } + case IEEE80211_IF_TYPE_STA: + last_seq = &priv->last_seq_num; + last_frag = &priv->last_frag_num; + last_time = &priv->last_packet_time; + break; + default: + return 0; + } + if ((*last_seq == seq) && + time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag) + goto drop; + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + goto drop; + } else + *last_seq = seq; + + *last_frag = frag; + *last_time = jiffies; + return 0; + + drop: + return 1; +} + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} + +static int iwl_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO + ("Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +static void iwl_txstatus_to_ieee(struct iwl_priv *priv, + struct iwl_tx_info *tx_sta) +{ + + tx_sta->status.ack_signal = 0; + tx_sta->status.excessive_retries = 0; + tx_sta->status.queue_length = 0; + tx_sta->status.queue_number = 0; + + if (in_interrupt()) + ieee80211_tx_status_irqsafe(priv->hw, + tx_sta->skb[0], &(tx_sta->status)); + else + ieee80211_tx_status(priv->hw, + tx_sta->skb[0], &(tx_sta->status)); + + tx_sta->skb[0] = NULL; +} + +/** + * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC. + * + * When FW advances 'R' index, all entries between old and + * new 'R' index need to be reclaimed. As result, some free space + * forms. If there is enough free space (> low mark), wake Tx queue. + */ +int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + int nfreed = 0; + + if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->first_empty, q->last_used); + return 0; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); + q->last_used != index; + q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) { + if (txq_id != IWL_CMD_QUEUE_NUM) { + iwl_txstatus_to_ieee(priv, + &(txq->txb[txq->q.last_used])); + iwl_hw_txq_free_tfd(priv, txq); + } else if (nfreed > 1) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + q->first_empty, q->last_used); + queue_work(priv->workqueue, &priv->restart); + } + nfreed++; + } + + if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && + (txq_id != IWL_CMD_QUEUE_NUM) && + priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + + + return nfreed; +} + +static int iwl_is_tx_success(u32 status) +{ + status &= TX_STATUS_MSK; + return (status == TX_STATUS_SUCCESS) + || (status == TX_STATUS_DIRECT_DONE); +} + +/****************************************************************************** + * + * Generic RX handler implementations + * + ******************************************************************************/ +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + +static inline int iwl_get_ra_sta_id(struct iwl_priv *priv, + struct ieee80211_hdr *hdr) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) + return IWL_AP_ID; + else { + u8 *da = ieee80211_get_DA(hdr); + return iwl_hw_find_station(priv, da); + } +} + +static struct ieee80211_hdr *iwl_tx_queue_get_hdr( + struct iwl_priv *priv, int txq_id, int idx) +{ + if (priv->txq[txq_id].txb[idx].skb[0]) + return (struct ieee80211_hdr *)priv->txq[txq_id]. + txb[idx].skb[0]->data; + return NULL; +} + +static inline u32 iwl_get_scd_ssn(struct iwl_tx_resp *tx_resp) +{ + __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status + + tx_resp->frame_count); + return le32_to_cpu(*scd_ssn) & MAX_SN; + +} +static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl_tx_resp *tx_resp, + u16 start_idx) +{ + u32 status; + __le32 *frame_status = &tx_resp->status; + struct ieee80211_tx_status *tx_status = NULL; + struct ieee80211_hdr *hdr = NULL; + int i, sh; + int txq_id, idx; + u16 seq; + + if (agg->wait_for_ba) + IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n"); + + agg->frame_count = tx_resp->frame_count; + agg->start_idx = start_idx; + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + agg->bitmap0 = agg->bitmap1 = 0; + + if (agg->frame_count == 1) { + struct iwl_tx_queue *txq ; + status = le32_to_cpu(frame_status[0]); + + txq_id = agg->txq_id; + txq = &priv->txq[txq_id]; + /* FIXME: code repetition */ + IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n", + agg->frame_count, agg->start_idx); + + tx_status = &(priv->txq[txq_id].txb[txq->q.last_used].status); + tx_status->retry_count = tx_resp->failure_frame; + tx_status->queue_number = status & 0xff; + tx_status->queue_length = tx_resp->bt_kill_count; + tx_status->queue_length |= tx_resp->failure_rts; + + tx_status->flags = iwl_is_tx_success(status)? + IEEE80211_TX_STATUS_ACK : 0; + tx_status->control.tx_rate = + iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags); + /* FIXME: code repetition end */ + + IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", + status & 0xff, tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", + iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags)); + + agg->wait_for_ba = 0; + } else { + u64 bitmap = 0; + int start = agg->start_idx; + + for (i = 0; i < agg->frame_count; i++) { + u16 sc; + status = le32_to_cpu(frame_status[i]); + seq = status >> 16; + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); + + if (status & (AGG_TX_STATE_FEW_BYTES_MSK | + AGG_TX_STATE_ABORT_MSK)) + continue; + + IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", + agg->frame_count, txq_id, idx); + + hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); + + sc = le16_to_cpu(hdr->seq_ctrl); + if (idx != (SEQ_TO_SN(sc) & 0xff)) { + IWL_ERROR("BUG_ON idx doesn't match seq control" + " idx=%d, seq_idx=%d, seq=%d\n", + idx, SEQ_TO_SN(sc), + hdr->seq_ctrl); + return -1; + } + + IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", + i, idx, SEQ_TO_SN(sc)); + + sh = idx - start; + if (sh > 64) { + sh = (start - idx) + 0xff; + bitmap = bitmap << sh; + sh = 0; + start = idx; + } else if (sh < -64) + sh = 0xff - (start - idx); + else if (sh < 0) { + sh = start - idx; + start = idx; + bitmap = bitmap << sh; + sh = 0; + } + bitmap |= (1 << sh); + IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", + start, (u32)(bitmap & 0xFFFFFFFF)); + } + + agg->bitmap0 = bitmap & 0xFFFFFFFF; + agg->bitmap1 = bitmap >> 32; + agg->start_idx = start; + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n", + agg->frame_count, agg->start_idx, + agg->bitmap0); + + if (bitmap) + agg->wait_for_ba = 1; + } + return 0; +} +#endif +#endif + +static void iwl_rx_reply_tx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_status *tx_status; + struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le32_to_cpu(tx_resp->status); +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + int tid, sta_id; +#endif +#endif + + if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.first_empty, + txq->q.last_used); + return; + } + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + if (txq->sched_retry) { + const u32 scd_ssn = iwl_get_scd_ssn(tx_resp); + struct ieee80211_hdr *hdr = + iwl_tx_queue_get_hdr(priv, txq_id, index); + struct iwl_ht_agg *agg = NULL; + __le16 *qc = ieee80211_get_qos_ctrl(hdr); + + if (qc == NULL) { + IWL_ERROR("BUG_ON qc is null!!!!\n"); + return; + } + + tid = le16_to_cpu(*qc) & 0xf; + + sta_id = iwl_get_ra_sta_id(priv, hdr); + if (unlikely(sta_id == IWL_INVALID_STATION)) { + IWL_ERROR("Station not known for\n"); + return; + } + + agg = &priv->stations[sta_id].tid[tid].agg; + + iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index); + + if ((tx_resp->frame_count == 1) && + !iwl_is_tx_success(status)) { + /* TODO: send BAR */ + } + + if ((txq->q.last_used != (scd_ssn & 0xff))) { + index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " + "%d index %d\n", scd_ssn , index); + iwl_tx_queue_reclaim(priv, txq_id, index); + } + } else { +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + tx_status = &(txq->txb[txq->q.last_used].status); + + tx_status->retry_count = tx_resp->failure_frame; + tx_status->queue_number = status; + tx_status->queue_length = tx_resp->bt_kill_count; + tx_status->queue_length |= tx_resp->failure_rts; + + tx_status->flags = + iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; + + tx_status->control.tx_rate = + iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags); + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " + "retries %d\n", txq_id, iwl_get_tx_fail_reason(status), + status, le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); + if (index != -1) + iwl_tx_queue_reclaim(priv, txq_id, index); +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + } +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); +} + + +static void iwl_rx_reply_alive(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_alive_resp *palive; + struct delayed_work *pwork; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO("Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + if (palive->ver_subtype == INITIALIZE_SUBTYPE) { + IWL_DEBUG_INFO("Initialization Alive received.\n"); + memcpy(&priv->card_alive_init, + &pkt->u.alive_frame, + sizeof(struct iwl_init_alive_resp)); + pwork = &priv->init_alive_start; + } else { + IWL_DEBUG_INFO("Runtime Alive received.\n"); + memcpy(&priv->card_alive, &pkt->u.alive_frame, + sizeof(struct iwl_alive_resp)); + pwork = &priv->alive_start; + } + + /* We delay the ALIVE response by 5ms to + * give the HW RF Kill time to activate... */ + if (palive->is_valid == UCODE_VALID_OK) + queue_delayed_work(priv->workqueue, pwork, + msecs_to_jiffies(5)); + else + IWL_WARNING("uCode did not respond OK.\n"); +} + +static void iwl_rx_reply_add_sta(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + + IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); + return; +} + +static void iwl_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + + IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " + "seq 0x%04X ser 0x%08X\n", + le32_to_cpu(pkt->u.err_resp.error_type), + get_cmd_string(pkt->u.err_resp.cmd_id), + pkt->u.err_resp.cmd_id, + le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), + le32_to_cpu(pkt->u.err_resp.error_info)); +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl_csa_notification *csa = &(pkt->u.csa_notif); + IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", + le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; +} + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +#endif +} + +static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); + IWL_DEBUG_RX("sleep mode: %d, src: %d\n", + sleep->pm_sleep_mode, sleep->pm_wakeup_src); +#endif +} + +static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + IWL_DEBUG_RADIO("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)); +} + +static void iwl_bg_beacon_update(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, beacon_update); + struct sk_buff *beacon; + + /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ + beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL); + + if (!beacon) { + IWL_ERROR("update beacon failed\n"); + return; + } + + mutex_lock(&priv->mutex); + /* new beacon skb is allocated every time; dispose previous.*/ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = beacon; + mutex_unlock(&priv->mutex); + + iwl_send_beacon_cmd(priv); +} + +static void iwl_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status); + u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); + + IWL_DEBUG_RX("beacon status %x retries %d iss %d " + "tsf %d %d rate %d\n", + le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK, + beacon->beacon_notify_hdr.failure_frame, + le32_to_cpu(beacon->ibss_mgr_status), + le32_to_cpu(beacon->high_tsf), + le32_to_cpu(beacon->low_tsf), rate); +#endif + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!test_bit(STATUS_EXIT_PENDING, &priv->status))) + queue_work(priv->workqueue, &priv->beacon_update); +} + +/* Service response to REPLY_SCAN_CMD (0x80) */ +static void iwl_rx_reply_scan(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanreq_notification *notif = + (struct iwl_scanreq_notification *)pkt->u.raw; + + IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); +#endif +} + +/* Service SCAN_START_NOTIFICATION (0x82) */ +static void iwl_rx_scan_start_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanstart_notification *notif = + (struct iwl_scanstart_notification *)pkt->u.raw; + priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); + IWL_DEBUG_SCAN("Scan start: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", + notif->channel, + notif->band ? "bg" : "a", + notif->tsf_high, + notif->tsf_low, notif->status, notif->beacon_timer); +} + +/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ +static void iwl_rx_scan_results_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanresults_notification *notif = + (struct iwl_scanresults_notification *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan ch.res: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d " + "elapsed=%lu usec (%dms since last)\n", + notif->channel, + notif->band ? "bg" : "a", + le32_to_cpu(notif->tsf_high), + le32_to_cpu(notif->tsf_low), + le32_to_cpu(notif->statistics[0]), + le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, + jiffies_to_msecs(elapsed_jiffies + (priv->last_scan_jiffies, jiffies))); + + priv->last_scan_jiffies = jiffies; +} + +/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ +static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", + scan_notif->scanned_channels, + scan_notif->tsf_low, + scan_notif->tsf_high, scan_notif->status); + + /* The HW is no longer scanning */ + clear_bit(STATUS_SCAN_HW, &priv->status); + + /* The scan completion notification came in, so kill that timer... */ + cancel_delayed_work(&priv->scan_check); + + IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", + (priv->scan_bands == 2) ? "2.4" : "5.2", + jiffies_to_msecs(elapsed_jiffies + (priv->scan_pass_start, jiffies))); + + /* Remove this scanned band from the list + * of pending bands to scan */ + priv->scan_bands--; + + /* If a request to abort was given, or the scan did not succeed + * then we reset the scan state machine and terminate, + * re-queuing another scan if one has been requested */ + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_INFO("Aborted scan completed.\n"); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + } else { + /* If there are more bands on this scan pass reschedule */ + if (priv->scan_bands > 0) + goto reschedule; + } + + priv->last_scan_jiffies = jiffies; + IWL_DEBUG_INFO("Setting scan to off\n"); + + clear_bit(STATUS_SCANNING, &priv->status); + + IWL_DEBUG_INFO("Scan took %dms\n", + jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); + + queue_work(priv->workqueue, &priv->scan_completed); + + return; + +reschedule: + priv->scan_pass_start = jiffies; + queue_work(priv->workqueue, &priv->request_scan); +} + +/* Handle notification from uCode that card's power state is changing + * due to software, hardware, or critical temperature RFKILL */ +static void iwl_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); + unsigned long status = priv->status; + + IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n", + (flags & HW_CARD_DISABLED) ? "Kill" : "On", + (flags & SW_CARD_DISABLED) ? "Kill" : "On"); + + if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | + RF_CARD_DISABLED)) { + + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted( + priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + + iwl_release_restricted_access(priv); + } + + if (!(flags & RXON_CARD_DISABLED)) { + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted( + priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + + iwl_release_restricted_access(priv); + } + } + + 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); + if (!iwl_grab_restricted_access(priv)) + iwl_release_restricted_access(priv); + } + } + + if (flags & HW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + + + if (flags & SW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_SW, &priv->status); + else + clear_bit(STATUS_RF_KILL_SW, &priv->status); + + if (!(flags & RXON_CARD_DISABLED)) + iwl_scan_cancel(priv); + + if ((test_bit(STATUS_RF_KILL_HW, &status) != + test_bit(STATUS_RF_KILL_HW, &priv->status)) || + (test_bit(STATUS_RF_KILL_SW, &status) != + test_bit(STATUS_RF_KILL_SW, &priv->status))) + queue_work(priv->workqueue, &priv->rf_kill); + else + wake_up_interruptible(&priv->wait_command_queue); +} + +/** + * iwl_setup_rx_handlers - Initialize Rx handler callbacks + * + * Setup the RX handlers for each of the reply types sent from the uCode + * to the host. + * + * This function chains into the hardware specific files for them to setup + * any hardware specific handlers as well. + */ +static void iwl_setup_rx_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; + priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta; + priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; + priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = + iwl_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; + + /* NOTE: iwl_rx_statistics is different based on whether + * the build is for the 3945 or the 4965. See the + * corresponding implementation in iwl-XXXX.c + * + * The same handler is used for both the REPLY to a + * discrete statistics request from the host as well as + * for the periodic statistics notification from the uCode + */ + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics; + + priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; + priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; + priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = + iwl_rx_scan_results_notif; + priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = + iwl_rx_scan_complete_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; + priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx; + + /* Setup hardware specific Rx handlers */ + iwl_hw_rx_handler_setup(priv); +} + +/** + * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them + * @rxb: Rx buffer to reclaim + * + * If an Rx buffer has an async callback associated with it the callback + * will be executed. The attached skb (if present) will only be freed + * if the callback returns 1 + */ +static void iwl_tx_cmd_complete(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + int huge = sequence & SEQ_HUGE_FRAME; + int cmd_index; + struct iwl_cmd *cmd; + + /* 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 + * in the queue management code. */ + if (txq_id != IWL_CMD_QUEUE_NUM) + IWL_ERROR("Error wrong command queue %d command id 0x%X\n", + txq_id, pkt->hdr.cmd); + BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); + + cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); + cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[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; + rxb->skb = NULL; + } else if (cmd->meta.u.callback && + !cmd->meta.u.callback(priv, cmd, rxb->skb)) + rxb->skb = NULL; + + iwl_tx_queue_reclaim(priv, txq_id, index); + + if (!(cmd->meta.flags & CMD_ASYNC)) { + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + } +} + +/************************** RX-FUNCTIONS ****************************/ +/* + * Rx theory of operation + * + * The host allocates 32 DMA target addresses and passes the host address + * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is + * 0 to 31 + * + * Rx Queue Indexes + * The host/firmware share two index registers for managing the Rx buffers. + * + * The READ index maps to the first position that the firmware may be writing + * to -- the driver can read up to (but not including) this position and get + * good data. + * The READ index is managed by the firmware once the card is enabled. + * + * The WRITE index maps to the last position the driver has read from -- the + * position preceding WRITE is the last slot the firmware can place a packet. + * + * The queue is empty (no good data) if WRITE = READ - 1, and is full if + * WRITE = READ. + * + * During initialization the host sets up the READ queue position to the first + * INDEX position, and WRITE to the last (READ - 1 wrapped) + * + * When the firmware places a packet in a buffer it will advance the READ index + * and fire the RX interrupt. The driver can then query the READ index and + * process as many packets as possible, moving the WRITE index forward as it + * resets the Rx queue buffers with new memory. + * + * The management in the driver is as follows: + * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When + * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replensish the iwl->rxq->rx_free. + * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * iwl->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) + * + A received packet is processed and handed to the kernel network stack, + * detached from the iwl->rxq. The driver 'processed' index is updated. + * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free + * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ + * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there + * were enough free buffers and RX_STALLED is set it is cleared. + * + * + * Driver sequence: + * + * iwl_rx_queue_alloc() Allocates rx_free + * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl_rx_queue_restock + * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * queue, updates firmware pointers, and updates + * the WRITE index. If insufficient rx_free buffers + * are available, schedules iwl_rx_replenish + * + * -- enable interrupts -- + * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * READ INDEX, detaching the SKB from the pool. + * Moves the packet buffer from queue to rx_used. + * Calls iwl_rx_queue_restock to refill any empty + * slots. + * ... + * + */ + +/** + * iwl_rx_queue_space - Return number of free slots available in queue. + */ +static int iwl_rx_queue_space(const struct iwl_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/** + * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue + * + * NOTE: This function has 3945 and 4965 specific code sections + * but is declared in base due to the majority of the + * implementation being the same (only a numeric constant is + * different) + * + */ +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +{ + u32 reg = 0; + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + + if (q->need_update == 0) + goto exit_unlock; + + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) + goto exit_unlock; + + iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR, + q->write & ~0x7); + iwl_release_restricted_access(priv); + } else + iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + + + q->need_update = 0; + + exit_unlock: + spin_unlock_irqrestore(&q->lock, flags); + return rc; +} + +/** + * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer. + * + * NOTE: This function has 3945 and 4965 specific code paths in it. + */ +static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, + dma_addr_t dma_addr) +{ + return cpu_to_le32((u32)(dma_addr >> 8)); +} + + +/** + * iwl_rx_queue_restock - refill RX queue from pre-allocated pool + * + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +int iwl_rx_queue_restock(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + int write, rc; + + spin_lock_irqsave(&rxq->lock, flags); + write = rxq->write & ~0x7; + while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + element = rxq->rx_free.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr); + rxq->queue[rxq->write] = rxb; + rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; + rxq->free_count--; + } + spin_unlock_irqrestore(&rxq->lock, flags); + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + queue_work(priv->workqueue, &priv->rx_replenish); + + + /* If we've added more space for the firmware to place data, tell it */ + if ((write != (rxq->write & ~0x7)) + || (abs(rxq->write - rxq->read) > 7)) { + spin_lock_irqsave(&rxq->lock, flags); + rxq->need_update = 1; + spin_unlock_irqrestore(&rxq->lock, flags); + rc = iwl_rx_queue_update_write_ptr(priv, rxq); + if (rc) + return rc; + } + + return 0; +} + +/** + * iwl_rx_replensih - Move all used packet from rx_used to rx_free + * + * When moving to rx_free an SKB is allocated for the slot. + * + * Also restock the Rx queue via iwl_rx_queue_restock. + * This is called as a scheduled work item (except for during intialization) + */ +void iwl_rx_replenish(void *data) +{ + struct iwl_priv *priv = data; + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + spin_lock_irqsave(&rxq->lock, flags); + while (!list_empty(&rxq->rx_used)) { + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + rxb->skb = + alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC); + if (!rxb->skb) { + if (net_ratelimit()) + printk(KERN_CRIT DRV_NAME + ": Can not allocate SKB buffers\n"); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ + break; + } + priv->alloc_rxb_skb++; + list_del(element); + rxb->dma_addr = + pci_map_single(priv->pci_dev, rxb->skb->data, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } + spin_unlock_irqrestore(&rxq->lock, flags); + + spin_lock_irqsave(&priv->lock, flags); + iwl_rx_queue_restock(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/* Assumes that the skb field of the buffers in 'pool' is kept accurate. + * If an SKB has been detached, the POOL needs to have it's SKB set to NULL + * This free routine walks the list of POOL entries and if SKB is set to + * non NULL it is unmapped and freed + */ +void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int i; + for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxq->pool[i].skb); + } + } + + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + rxq->bd = NULL; +} + +int iwl_rx_queue_alloc(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct pci_dev *dev = priv->pci_dev; + int i; + + spin_lock_init(&rxq->lock); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); + if (!rxq->bd) + return -ENOMEM; + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + rxq->need_update = 0; + return 0; +} + +void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + unsigned long flags; + int i; + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + priv->alloc_rxb_skb--; + dev_kfree_skb(rxq->pool[i].skb); + rxq->pool[i].skb = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); +} + +/* Convert linear signal-to-noise ratio into dB */ +static u8 ratio2dB[100] = { +/* 0 1 2 3 4 5 6 7 8 9 */ + 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ + 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ + 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ + 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ + 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ + 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ + 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ + 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ + 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ + 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ +}; + +/* Calculates a relative dB value from a ratio of linear + * (i.e. not dB) signal levels. + * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ +int iwl_calc_db_from_ratio(int sig_ratio) +{ + /* Anything above 1000:1 just report as 60 dB */ + if (sig_ratio > 1000) + return 60; + + /* Above 100:1, divide by 10 and use table, + * add 20 dB to make up for divide by 10 */ + if (sig_ratio > 100) + return (20 + (int)ratio2dB[sig_ratio/10]); + + /* We shouldn't see this */ + if (sig_ratio < 1) + return 0; + + /* Use table for ratios 1:1 - 99:1 */ + return (int)ratio2dB[sig_ratio]; +} + +#define PERFECT_RSSI (-20) /* dBm */ +#define WORST_RSSI (-95) /* dBm */ +#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) + +/* Calculate an indication of rx signal quality (a percentage, not dBm!). + * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info + * about formulas used below. */ +int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) +{ + int sig_qual; + int degradation = PERFECT_RSSI - rssi_dbm; + + /* If we get a noise measurement, use signal-to-noise ratio (SNR) + * as indicator; formula is (signal dbm - noise dbm). + * SNR at or above 40 is a great signal (100%). + * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. + * Weakest usable signal is usually 10 - 15 dB SNR. */ + if (noise_dbm) { + if (rssi_dbm - noise_dbm >= 40) + return 100; + else if (rssi_dbm < noise_dbm) + return 0; + sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; + + /* Else use just the signal level. + * This formula is a least squares fit of data points collected and + * compared with a reference system that had a percentage (%) display + * for signal quality. */ + } else + sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * + (15 * RSSI_RANGE + 62 * degradation)) / + (RSSI_RANGE * RSSI_RANGE); + + if (sig_qual > 100) + sig_qual = 100; + else if (sig_qual < 1) + sig_qual = 0; + + return sig_qual; +} + +/** + * iwl_rx_handle - Main entry function for receiving responses from the uCode + * + * Uses the priv->rx_handlers callback function array to invoke + * the appropriate handlers, including command responses, + * frame-received notifications, and other notifications. + */ +static void iwl_rx_handle(struct iwl_priv *priv) +{ + struct iwl_rx_mem_buffer *rxb; + struct iwl_rx_packet *pkt; + struct iwl_rx_queue *rxq = &priv->rxq; + u32 r, i; + int reclaim; + unsigned long flags; + + r = iwl_hw_get_rx_read(priv); + i = rxq->read; + + /* Rx interrupt, but nothing sent from uCode */ + if (i == r) + IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + + while (i != r) { + rxb = rxq->queue[i]; + + /* If an RXB doesn't have a queue slot associated with it + * then a bug has been introduced in the queue refilling + * routines -- catch it here */ + BUG_ON(rxb == NULL); + + rxq->queue[i] = NULL; + + pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, + IWL_RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + pkt = (struct iwl_rx_packet *)rxb->skb->data; + + /* Reclaim a command buffer only if this packet is a response + * to a (driver-originated) command. + * If the packet (e.g. Rx frame) originated from uCode, + * there is no command buffer to reclaim. + * Ucode should set SEQ_RX_FRAME bit if ucode-originated, + * but apparently a few don't get set; catch them here. */ + reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && + (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && + (pkt->hdr.cmd != REPLY_4965_RX) && + (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && + (pkt->hdr.cmd != REPLY_TX); + + /* Based on type of command response or notification, + * handle those that need handling via function in + * rx_handlers table. See iwl_setup_rx_handlers() */ + if (priv->rx_handlers[pkt->hdr.cmd]) { + IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + "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); + } else { + /* No handling needed */ + IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + "r %d i %d No handler needed for %s, 0x%02x\n", + r, i, get_cmd_string(pkt->hdr.cmd), + pkt->hdr.cmd); + } + + if (reclaim) { + /* Invoke any callbacks, transfer the skb to caller, + * and fire off the (possibly) blocking iwl_send_cmd() + * as we reclaim the driver command queue */ + if (rxb && rxb->skb) + iwl_tx_cmd_complete(priv, rxb); + else + IWL_WARNING("Claim null rxb?\n"); + } + + /* For now we just don't re-use anything. We can tweak this + * later to try and re-use notification packets and SKBs that + * fail to Rx correctly */ + if (rxb->skb != NULL) { + priv->alloc_rxb_skb--; + dev_kfree_skb_any(rxb->skb); + rxb->skb = NULL; + } + + pci_unmap_single(priv->pci_dev, rxb->dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &priv->rxq.rx_used); + spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; + } + + /* Backtrack one entry */ + priv->rxq.read = i; + iwl_rx_queue_restock(priv); +} + +int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq) +{ + u32 reg = 0; + int rc = 0; + int txq_id = txq->q.id; + + if (txq->need_update == 0) + return rc; + + /* if we're trying to save power */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + return rc; + } + + /* restore this queue's parameters in nic hardware. */ + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + iwl_write_restricted(priv, HBUS_TARG_WRPTR, + txq->q.first_empty | (txq_id << 8)); + iwl_release_restricted_access(priv); + + /* else not in power-save mode, uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). */ + } else + iwl_write32(priv, HBUS_TARG_WRPTR, + txq->q.first_empty | (txq_id << 8)); + + txq->need_update = 0; + + return rc; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) +{ + IWL_DEBUG_RADIO("RX CONFIG:\n"); + iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); + IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); + IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", + le32_to_cpu(rxon->filter_flags)); + IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); + IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", + rxon->ofdm_basic_rates); + IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); + IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n", + MAC_ARG(rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n", + MAC_ARG(rxon->bssid_addr)); + IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); +} +#endif + +static void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR("Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); +} + +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("Disabled interrupts\n"); +} + +static const char *desc_lookup(int i) +{ + switch (i) { + case 1: + return "FAIL"; + case 2: + return "BAD_PARAM"; + case 3: + return "BAD_CHECKSUM"; + case 4: + return "NMI_INTERRUPT"; + case 5: + return "SYSASSERT"; + case 6: + return "FATAL_ERROR"; + } + + return "UNKNOWN"; +} + +#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; + int rc; + + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Not valid error log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + count = iwl_read_restricted_mem(priv, base); + + if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { + IWL_ERROR("Start IWL Error Log Dump:\n"); + IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", + priv->status, priv->config, count); + } + + desc = iwl_read_restricted_mem(priv, base + 1 * sizeof(u32)); + blink1 = iwl_read_restricted_mem(priv, base + 3 * sizeof(u32)); + blink2 = iwl_read_restricted_mem(priv, base + 4 * sizeof(u32)); + ilink1 = iwl_read_restricted_mem(priv, base + 5 * sizeof(u32)); + ilink2 = iwl_read_restricted_mem(priv, base + 6 * sizeof(u32)); + data1 = iwl_read_restricted_mem(priv, base + 7 * sizeof(u32)); + data2 = iwl_read_restricted_mem(priv, base + 8 * sizeof(u32)); + line = iwl_read_restricted_mem(priv, base + 9 * sizeof(u32)); + time = iwl_read_restricted_mem(priv, base + 11 * sizeof(u32)); + + IWL_ERROR("Desc Time " + "data1 data2 line\n"); + IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", + desc_lookup(desc), desc, time, data1, data2, line); + IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); + IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, + ilink1, ilink2); + + iwl_release_restricted_access(priv); +} + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + * NOTE: Must be called with iwl_grab_restricted_access() already obtained! + */ +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; + + 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_restricted_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) + IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ + else { + data = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); + } + } +} + +static void iwl_dump_nic_event_log(struct iwl_priv *priv) +{ + int rc; + 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 */ + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + /* event log header */ + capacity = iwl_read_restricted_mem(priv, base); + mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERROR("Start IPW Event Log Dump: nothing in log\n"); + iwl_release_restricted_access(priv); + return; + } + + IWL_ERROR("Start IPW 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_release_restricted_access(priv); +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +static void iwl_irq_handle_error(struct iwl_priv *priv) +{ + /* Set the FW error flag -- cleared on iwl_down */ + set_bit(STATUS_FW_ERROR, &priv->status); + + /* Cancel currently queued command. */ + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + +#ifdef CONFIG_IWLWIFI_DEBUG + 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->staging_rxon); + } +#endif + + wake_up_interruptible(&priv->wait_command_queue); + + /* Keep the restart process from trying to send host + * commands by clearing the INIT status bit */ + clear_bit(STATUS_READY, &priv->status); + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + + if (iwl_is_associated(priv)) { + memcpy(&priv->recovery_rxon, &priv->active_rxon, + sizeof(priv->recovery_rxon)); + priv->error_recovering = 1; + } + queue_work(priv->workqueue, &priv->restart); + } +} + +static void iwl_error_recovery(struct iwl_priv *priv) +{ + unsigned long flags; + + memcpy(&priv->staging_rxon, &priv->recovery_rxon, + sizeof(priv->staging_rxon)); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + iwl_rxon_add_station(priv, priv->bssid, 1); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); + priv->error_recovering = 0; + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_irq_tasklet(struct iwl_priv *priv) +{ + u32 inta, handled = 0; + u32 inta_fh; + unsigned long flags; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_mask; +#endif + + spin_lock_irqsave(&priv->lock, flags); + + /* Ack/clear/reset pending uCode interrupts. + * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, + * and will clear only when CSR_FH_INT_STATUS gets cleared. */ + inta = iwl_read32(priv, CSR_INT); + iwl_write32(priv, CSR_INT, inta); + + /* Ack/clear/reset pending flow-handler (DMA) interrupts. + * Any new interrupts that happen after this, either while we're + * in this tasklet, or later, will show up in next ISR/tasklet. */ + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_ISR) { + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + } +#endif + + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not + * atomic, make sure that inta covers all the interrupts that + * we've discovered, even if FH interrupt came in just after + * reading CSR_INT. */ + if (inta_fh & CSR_FH_INT_RX_MASK) + inta |= CSR_INT_BIT_FH_RX; + if (inta_fh & CSR_FH_INT_TX_MASK) + inta |= CSR_INT_BIT_FH_TX; + + /* Now service all interrupt bits discovered above. */ + if (inta & CSR_INT_BIT_HW_ERR) { + IWL_ERROR("Microcode HW error detected. Restarting.\n"); + + /* Tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + iwl_irq_handle_error(priv); + + handled |= CSR_INT_BIT_HW_ERR; + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & (IWL_DL_ISR)) { + /* NIC fires this, but we don't use it, redundant with WAKEUP */ + if (inta & CSR_INT_BIT_MAC_CLK_ACTV) + IWL_DEBUG_ISR("Microcode started or stopped.\n"); + + /* Alive notification via Rx interrupt will do the real work */ + if (inta & CSR_INT_BIT_ALIVE) + IWL_DEBUG_ISR("Alive interrupt\n"); + } +#endif + /* Safely ignore these bits for debug checks below */ + inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE); + + /* HW RF KILL switch toggled (4965 only) */ + if (inta & CSR_INT_BIT_RF_KILL) { + int hw_rf_kill = 0; + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, + "RF_KILL bit toggled to %s.\n", + hw_rf_kill ? "disable radio":"enable radio"); + + /* Queue restart only if RF_KILL switch was set to "kill" + * when we loaded driver, and is now set to "enable". + * After we're Alive, RF_KILL gets handled by + * iwl_rx_card_state_notif() */ + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + + handled |= CSR_INT_BIT_RF_KILL; + } + + /* Chip got too hot and stopped itself (4965 only) */ + if (inta & CSR_INT_BIT_CT_KILL) { + IWL_ERROR("Microcode CT kill error detected.\n"); + handled |= CSR_INT_BIT_CT_KILL; + } + + /* Error detected by uCode */ + if (inta & CSR_INT_BIT_SW_ERR) { + IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", + inta); + iwl_irq_handle_error(priv); + handled |= CSR_INT_BIT_SW_ERR; + } + + /* uCode wakes up after power-down sleep */ + if (inta & CSR_INT_BIT_WAKEUP) { + IWL_DEBUG_ISR("Wakeup interrupt\n"); + iwl_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]); + + handled |= CSR_INT_BIT_WAKEUP; + } + + /* All uCode command responses, including Tx command responses, + * Rx "responses" (frame-received notification), and other + * notifications from uCode come through here*/ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + iwl_rx_handle(priv); + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + } + + if (inta & CSR_INT_BIT_FH_TX) { + IWL_DEBUG_ISR("Tx interrupt\n"); + handled |= CSR_INT_BIT_FH_TX; + } + + if (inta & ~handled) + IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); + + if (inta & ~CSR_INI_SET_MASK) { + IWL_WARNING("Disabled INTA bits 0x%08x were pending\n", + inta & ~CSR_INI_SET_MASK); + IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh); + } + + /* Re-enable all interrupts */ + iwl_enable_interrupts(priv); + +#ifdef CONFIG_IWLWIFI_DEBUG + 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); + IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " + "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); + } +#endif + spin_unlock_irqrestore(&priv->lock, flags); +} + +static irqreturn_t iwl_isr(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 inta_fh; + if (!priv) + return IRQ_NONE; + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(priv, CSR_INT); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta && !inta_fh) { + IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared */ + IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + goto none; + } + + IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + tasklet_schedule(&priv->irq_tasklet); + spin_unlock(&priv->lock); + + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ + iwl_enable_interrupts(priv); + spin_unlock(&priv->lock); + return IRQ_NONE; +} + +/************************** EEPROM BANDS **************************** + * + * The iwl_eeprom_band definitions below provide the mapping from the + * EEPROM contents to the specific channel number supported for each + * band. + * + * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3 + * definition below maps to physical channel 42 in the 5.2GHz spectrum. + * The specific geography and calibration information for that channel + * is contained in the eeprom map itself. + * + * During init, we copy the eeprom information and channel map + * information into priv->channel_info_24/52 and priv->channel_map_24/52 + * + * channel_map_24/52 provides the index in the channel_info array for a + * given channel. We have to have two separate maps as there is channel + * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and + * band_2 + * + * A value of 0xff stored in the channel_map indicates that the channel + * is not supported by the hardware at all. + * + * A value of 0xfe in the channel_map indicates that the channel is not + * valid for Tx with the current hardware. This means that + * while the system can tune and receive on a given channel, it may not + * be able to associate or transmit any frames on that + * channel. There is no corresponding channel information for that + * entry. + * + *********************************************************************/ + +/* 2.4 GHz */ +static const u8 iwl_eeprom_band_1[14] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +}; + +/* 5.2 GHz bands */ +static const u8 iwl_eeprom_band_2[] = { + 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 +}; + +static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */ + 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 +}; + +static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */ + 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 +}; + +static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ + 145, 149, 153, 157, 161, 165 +}; + +static u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */ + 1, 2, 3, 4, 5, 6, 7 +}; + +static u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */ + 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 +}; + +static void iwl_init_band_reference(const struct iwl_priv *priv, int band, + int *eeprom_ch_count, + const struct iwl_eeprom_channel + **eeprom_ch_info, + const u8 **eeprom_ch_index) +{ + switch (band) { + case 1: /* 2.4GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); + *eeprom_ch_info = priv->eeprom.band_1_channels; + *eeprom_ch_index = iwl_eeprom_band_1; + break; + case 2: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); + *eeprom_ch_info = priv->eeprom.band_2_channels; + *eeprom_ch_index = iwl_eeprom_band_2; + break; + case 3: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); + *eeprom_ch_info = priv->eeprom.band_3_channels; + *eeprom_ch_index = iwl_eeprom_band_3; + break; + case 4: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); + *eeprom_ch_info = priv->eeprom.band_4_channels; + *eeprom_ch_index = iwl_eeprom_band_4; + break; + case 5: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); + *eeprom_ch_info = priv->eeprom.band_5_channels; + *eeprom_ch_index = iwl_eeprom_band_5; + break; + case 6: + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); + *eeprom_ch_info = priv->eeprom.band_24_channels; + *eeprom_ch_index = iwl_eeprom_band_6; + break; + case 7: + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); + *eeprom_ch_info = priv->eeprom.band_52_channels; + *eeprom_ch_index = iwl_eeprom_band_7; + break; + default: + BUG(); + return; + } +} + +const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, + int phymode, u16 channel) +{ + int i; + + switch (phymode) { + case MODE_IEEE80211A: + for (i = 14; i < priv->channel_count; i++) { + if (priv->channel_info[i].channel == channel) + return &priv->channel_info[i]; + } + break; + + case MODE_IEEE80211B: + case MODE_IEEE80211G: + if (channel >= 1 && channel <= 14) + return &priv->channel_info[channel - 1]; + break; + + } + + return NULL; +} + +#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ + ? # x " " : "") + +static int iwl_init_channel_map(struct iwl_priv *priv) +{ + int eeprom_ch_count = 0; + const u8 *eeprom_ch_index = NULL; + const struct iwl_eeprom_channel *eeprom_ch_info = NULL; + int band, ch; + struct iwl_channel_info *ch_info; + + if (priv->channel_count) { + IWL_DEBUG_INFO("Channel map already initialized.\n"); + return 0; + } + + if (priv->eeprom.version < 0x2f) { + IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", + priv->eeprom.version); + return -EINVAL; + } + + IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); + + priv->channel_count = + ARRAY_SIZE(iwl_eeprom_band_1) + + ARRAY_SIZE(iwl_eeprom_band_2) + + ARRAY_SIZE(iwl_eeprom_band_3) + + ARRAY_SIZE(iwl_eeprom_band_4) + + ARRAY_SIZE(iwl_eeprom_band_5); + + IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count); + + priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * + priv->channel_count, GFP_KERNEL); + if (!priv->channel_info) { + IWL_ERROR("Could not allocate channel_info\n"); + priv->channel_count = 0; + return -ENOMEM; + } + + ch_info = priv->channel_info; + + /* Loop through the 5 EEPROM bands adding them in order to the + * channel map we maintain (that contains additional information than + * what just in the EEPROM) */ + for (band = 1; band <= 5; band++) { + + iwl_init_band_reference(priv, band, &eeprom_ch_count, + &eeprom_ch_info, &eeprom_ch_index); + + /* Loop through each band adding each of the channels */ + for (ch = 0; ch < eeprom_ch_count; ch++) { + ch_info->channel = eeprom_ch_index[ch]; + ch_info->phymode = (band == 1) ? MODE_IEEE80211B : + MODE_IEEE80211A; + + /* permanently store EEPROM's channel regulatory flags + * and max power in channel info database. */ + ch_info->eeprom = eeprom_ch_info[ch]; + + /* Copy the run-time flags so they are there even on + * invalid channels */ + ch_info->flags = eeprom_ch_info[ch].flags; + + if (!(is_channel_valid(ch_info))) { + IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - " + "No traffic\n", + ch_info->channel, + ch_info->flags, + is_channel_a_band(ch_info) ? + "5.2" : "2.4"); + ch_info++; + continue; + } + + /* Initialize regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + eeprom_ch_info[ch].max_power_avg; + ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; + ch_info->min_power = 0; + + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + " %ddBm): Ad-Hoc %ssupported\n", + ch_info->channel, + is_channel_a_band(ch_info) ? + "5.2" : "2.4", + CHECK_AND_PRINT(IBSS), + CHECK_AND_PRINT(ACTIVE), + CHECK_AND_PRINT(RADAR), + CHECK_AND_PRINT(WIDE), + CHECK_AND_PRINT(NARROW), + CHECK_AND_PRINT(DFS), + eeprom_ch_info[ch].flags, + eeprom_ch_info[ch].max_power_avg, + ((eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_IBSS) + && !(eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_RADAR)) + ? "" : "not "); + + /* Set the user_txpower_limit to the highest power + * supported by any channel */ + if (eeprom_ch_info[ch].max_power_avg > + priv->user_txpower_limit) + priv->user_txpower_limit = + eeprom_ch_info[ch].max_power_avg; + + ch_info++; + } + } + + for (band = 6; band <= 7; band++) { + int phymode; + u8 fat_extension_chan; + + iwl_init_band_reference(priv, band, &eeprom_ch_count, + &eeprom_ch_info, &eeprom_ch_index); + + phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A; + /* 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))) + fat_extension_chan = HT_IE_EXT_CHANNEL_MAX; + else + fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; + + iwl4965_set_fat_chan_info(priv, phymode, + eeprom_ch_index[ch], + &(eeprom_ch_info[ch]), + fat_extension_chan); + + iwl4965_set_fat_chan_info(priv, phymode, + (eeprom_ch_index[ch] + 4), + &(eeprom_ch_info[ch]), + HT_IE_EXT_CHANNEL_BELOW); + } + } + + return 0; +} + +/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after + * sending probe req. This should be set long enough to hear probe responses + * from more than one AP. */ +#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_ACTIVE_DWELL_TIME_52 (10) + +/* For faster active scanning, scan will move to the next channel if fewer than + * PLCP_QUIET_THRESH packets are heard on this channel within + * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell + * time if it's a quiet channel (nothing responded to our probe, and there's + * no other traffic). + * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ +#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ +#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ + +/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. + * Must be set longer than active dwell time. + * For the most reliable scan, set > AP beacon interval (typically 100msec). */ +#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_PASSIVE_DWELL_TIME_52 (10) +#define IWL_PASSIVE_DWELL_BASE (100) +#define IWL_CHANNEL_TUNE_TIME 5 + +static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode) +{ + if (phymode == MODE_IEEE80211A) + return IWL_ACTIVE_DWELL_TIME_52; + else + return IWL_ACTIVE_DWELL_TIME_24; +} + +static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode) +{ + u16 active = iwl_get_active_dwell_time(priv, phymode); + u16 passive = (phymode != MODE_IEEE80211A) ? + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; + + if (iwl_is_associated(priv)) { + /* If we're associated, we clamp the maximum passive + * dwell time to be 98% of the beacon interval (minus + * 2 * channel tune time) */ + passive = priv->beacon_int; + if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive) + passive = IWL_PASSIVE_DWELL_BASE; + passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; + } + + if (passive <= active) + passive = active + 1; + + return passive; +} + +static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, + u8 is_active, u8 direct_mask, + struct iwl_scan_channel *scan_ch) +{ + const struct ieee80211_channel *channels = NULL; + const struct ieee80211_hw_mode *hw_mode; + const struct iwl_channel_info *ch_info; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int added, i; + + hw_mode = iwl_get_hw_mode(priv, phymode); + if (!hw_mode) + return 0; + + channels = hw_mode->channels; + + active_dwell = iwl_get_active_dwell_time(priv, phymode); + passive_dwell = iwl_get_passive_dwell_time(priv, phymode); + + for (i = 0, added = 0; i < hw_mode->num_channels; i++) { + if (channels[i].chan == + le16_to_cpu(priv->active_rxon.channel)) { + if (iwl_is_associated(priv)) { + IWL_DEBUG_SCAN + ("Skipping current channel %d\n", + le16_to_cpu(priv->active_rxon.channel)); + continue; + } + } else if (priv->only_active_channel) + continue; + + scan_ch->channel = channels[i].chan; + + ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", + scan_ch->channel); + continue; + } + + if (!is_active || is_channel_passive(ch_info) || + !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + scan_ch->type = 0; /* passive */ + else + scan_ch->type = 1; /* active */ + + if (scan_ch->type & 1) + scan_ch->type |= (direct_mask << 1); + + if (is_channel_narrow(ch_info)) + scan_ch->type |= (1 << 7); + + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + + /* Set power levels to defaults */ + scan_ch->tpc.dsp_atten = 110; + /* scan_pwr_info->tpc.dsp_atten; */ + + /*scan_pwr_info->tpc.tx_gain; */ + if (phymode == MODE_IEEE80211A) + scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; + else { + scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); + /* NOTE: if we were doing 6Mb OFDM for scans we'd use + * power level + scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3; + */ + } + + IWL_DEBUG_SCAN("Scanning %d [%s %d]\n", + scan_ch->channel, + (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE", + (scan_ch->type & 1) ? + active_dwell : passive_dwell); + + scan_ch++; + added++; + } + + IWL_DEBUG_SCAN("total channels to scan %d \n", added); + return added; +} + +static void iwl_reset_channel_flag(struct iwl_priv *priv) +{ + int i, j; + for (i = 0; i < 3; i++) { + struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; + for (j = 0; j < hw_mode->num_channels; j++) + hw_mode->channels[j].flag = hw_mode->channels[j].val; + } +} + +static void iwl_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT; i++) { + rates[i].rate = iwl_rates[i].ieee * 5; + rates[i].val = i; /* Rate scaling will work on indexes */ + rates[i].val2 = i; + rates[i].flags = IEEE80211_RATE_SUPPORTED; + /* Only OFDM have the bits-per-symbol set */ + if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) + rates[i].flags |= IEEE80211_RATE_OFDM; + else { + /* + * If CCK 1M then set rate flag to CCK else CCK_2 + * which is CCK | PREAMBLE2 + */ + rates[i].flags |= (iwl_rates[i].plcp == 10) ? + IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + } + + /* Set up which ones are basic rates... */ + if (IWL_BASIC_RATES_MASK & (1 << i)) + rates[i].flags |= IEEE80211_RATE_BASIC; + } + + iwl4965_init_hw_rates(priv, rates); +} + +/** + * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom + */ +static int iwl_init_geos(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch; + struct ieee80211_hw_mode *modes; + struct ieee80211_channel *channels; + struct ieee80211_channel *geo_ch; + struct ieee80211_rate *rates; + int i = 0; + enum { + A = 0, + B = 1, + G = 2, + A_11N = 3, + G_11N = 4, + }; + int mode_count = 5; + + if (priv->modes) { + IWL_DEBUG_INFO("Geography modes already initialized.\n"); + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + return 0; + } + + modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, + GFP_KERNEL); + if (!modes) + return -ENOMEM; + + channels = kzalloc(sizeof(struct ieee80211_channel) * + priv->channel_count, GFP_KERNEL); + if (!channels) { + kfree(modes); + return -ENOMEM; + } + + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), + GFP_KERNEL); + if (!rates) { + kfree(modes); + kfree(channels); + return -ENOMEM; + } + + /* 0 = 802.11a + * 1 = 802.11b + * 2 = 802.11g + */ + + /* 5.2GHz channels start after the 2.4GHz channels */ + modes[A].mode = MODE_IEEE80211A; + modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + modes[A].rates = rates; + modes[A].num_rates = 8; /* just OFDM */ + modes[A].rates = &rates[4]; + modes[A].num_channels = 0; + + modes[B].mode = MODE_IEEE80211B; + modes[B].channels = channels; + modes[B].rates = rates; + modes[B].num_rates = 4; /* just CCK */ + modes[B].num_channels = 0; + + modes[G].mode = MODE_IEEE80211G; + modes[G].channels = channels; + modes[G].rates = rates; + modes[G].num_rates = 12; /* OFDM & CCK */ + modes[G].num_channels = 0; + + modes[G_11N].mode = MODE_IEEE80211G; + modes[G_11N].channels = channels; + modes[G_11N].num_rates = 13; /* OFDM & CCK */ + modes[G_11N].rates = rates; + modes[G_11N].num_channels = 0; + + modes[A_11N].mode = MODE_IEEE80211A; + modes[A_11N].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + modes[A_11N].rates = &rates[4]; + modes[A_11N].num_rates = 9; /* just OFDM */ + modes[A_11N].num_channels = 0; + + priv->ieee_channels = channels; + priv->ieee_rates = rates; + + iwl_init_hw_rates(priv, rates); + + for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { + ch = &priv->channel_info[i]; + + if (!is_channel_valid(ch)) { + IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " + "skipping.\n", + ch->channel, is_channel_a_band(ch) ? + "5.2" : "2.4"); + continue; + } + + if (is_channel_a_band(ch)) { + geo_ch = &modes[A].channels[modes[A].num_channels++]; + modes[A_11N].num_channels++; + } else { + geo_ch = &modes[B].channels[modes[B].num_channels++]; + modes[G].num_channels++; + modes[G_11N].num_channels++; + } + + geo_ch->freq = ieee80211chan2mhz(ch->channel); + geo_ch->chan = ch->channel; + geo_ch->power_level = ch->max_power_avg; + geo_ch->antenna_max = 0xff; + + if (is_channel_valid(ch)) { + geo_ch->flag = IEEE80211_CHAN_W_SCAN; + if (ch->flags & EEPROM_CHANNEL_IBSS) + geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + + if (ch->flags & EEPROM_CHANNEL_ACTIVE) + geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + + if (ch->flags & EEPROM_CHANNEL_RADAR) + geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + + if (ch->max_power_avg > priv->max_channel_txpower_limit) + priv->max_channel_txpower_limit = + ch->max_power_avg; + } + + geo_ch->val = geo_ch->flag; + } + + if ((modes[A].num_channels == 0) && priv->is_abg) { + printk(KERN_INFO DRV_NAME + ": Incorrectly detected BG card as ABG. Please send " + "your PCI ID 0x%04X:0x%04X to maintainer.\n", + priv->pci_dev->device, priv->pci_dev->subsystem_device); + priv->is_abg = 0; + } + + printk(KERN_INFO DRV_NAME + ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", + modes[G].num_channels, modes[A].num_channels); + + /* + * NOTE: We register these in preference of order -- the + * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick + * a phymode based on rates or AP capabilities but seems to + * configure it purely on if the channel being configured + * is supported by a mode -- and the first match is taken + */ + + if (modes[G].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[G]); + if (modes[B].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[B]); + if (modes[A].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[A]); + + priv->modes = modes; + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + + return 0; +} + +/****************************************************************************** + * + * uCode download functions + * + ******************************************************************************/ + +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +{ + if (priv->ucode_code.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_code.len, + priv->ucode_code.v_addr, + priv->ucode_code.p_addr); + priv->ucode_code.v_addr = NULL; + } + if (priv->ucode_data.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_data.len, + priv->ucode_data.v_addr, + priv->ucode_data.p_addr); + priv->ucode_data.v_addr = NULL; + } + if (priv->ucode_data_backup.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_data_backup.len, + priv->ucode_data_backup.v_addr, + priv->ucode_data_backup.p_addr); + priv->ucode_data_backup.v_addr = NULL; + } + if (priv->ucode_init.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_init.len, + priv->ucode_init.v_addr, + priv->ucode_init.p_addr); + priv->ucode_init.v_addr = NULL; + } + if (priv->ucode_init_data.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_init_data.len, + priv->ucode_init_data.v_addr, + priv->ucode_init_data.p_addr); + priv->ucode_init_data.v_addr = NULL; + } + if (priv->ucode_boot.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_boot.len, + priv->ucode_boot.v_addr, + priv->ucode_boot.p_addr); + priv->ucode_boot.v_addr = NULL; + } +} + +/** + * iwl_verify_inst_full - verify runtime uCode image in card vs. host, + * looking at all data. + */ +static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) +{ + u32 val; + u32 save_len = len; + int rc = 0; + u32 errcnt; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); + + errcnt = 0; + for (; len > 0; len -= sizeof(u32), image++) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + save_len - len, val, le32_to_cpu(*image)); + rc = -EIO; + errcnt++; + if (errcnt >= 20) + break; + } + } + + iwl_release_restricted_access(priv); + + if (!errcnt) + IWL_DEBUG_INFO + ("ucode image in INSTRUCTION memory is good\n"); + + return rc; +} + + +/** + * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, + * using sample data 100 bytes apart. If these sample points are good, + * it's a pretty good bet that everything between them is good, too. + */ +static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +{ + u32 val; + int rc = 0; + u32 errcnt = 0; + u32 i; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, + i + RTC_INST_LOWER_BOUND); + val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { +#if 0 /* Enable this if you want to see details */ + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + i, val, *image); +#endif + rc = -EIO; + errcnt++; + if (errcnt >= 3) + break; + } + } + + iwl_release_restricted_access(priv); + + return rc; +} + + +/** + * iwl_verify_ucode - determine which instruction image is in SRAM, + * and verify its contents + */ +static int iwl_verify_ucode(struct iwl_priv *priv) +{ + __le32 *image; + u32 len; + int rc = 0; + + /* Try bootstrap */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); + return 0; + } + + /* Try initialize */ + image = (__le32 *)priv->ucode_init.v_addr; + len = priv->ucode_init.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); + return 0; + } + + /* Try runtime/protocol */ + image = (__le32 *)priv->ucode_code.v_addr; + len = priv->ucode_code.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); + return 0; + } + + IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + + /* Show first several data entries in instruction SRAM. + * Selection of bootstrap image is arbitrary. */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + rc = iwl_verify_inst_full(priv, image, len); + + return rc; +} + + +/* check contents of special bootstrap uCode SRAM */ +static int iwl_verify_bsm(struct iwl_priv *priv) +{ + __le32 *image = priv->ucode_boot.v_addr; + u32 len = priv->ucode_boot.len; + u32 reg; + u32 val; + + IWL_DEBUG_INFO("Begin verify bsm\n"); + + /* verify BSM SRAM contents */ + val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG); + for (reg = BSM_SRAM_LOWER_BOUND; + reg < BSM_SRAM_LOWER_BOUND + len; + reg += sizeof(u32), image ++) { + val = iwl_read_restricted_reg(priv, reg); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("BSM uCode verification failed at " + "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", + BSM_SRAM_LOWER_BOUND, + reg - BSM_SRAM_LOWER_BOUND, len, + val, le32_to_cpu(*image)); + return -EIO; + } + } + + IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n"); + + return 0; +} + +/** + * iwl_load_bsm - Load bootstrap instructions + * + * BSM operation: + * + * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program + * in special SRAM that does not power down during RFKILL. When powering back + * up after power-saving sleeps (or during initial uCode load), the BSM loads + * the bootstrap program into the on-board processor, and starts it. + * + * The bootstrap program loads (via DMA) instructions and data for a new + * program from host DRAM locations indicated by the host driver in the + * BSM_DRAM_* registers. Once the new program is loaded, it starts + * automatically. + * + * When initializing the NIC, the host driver points the BSM to the + * "initialize" uCode image. This uCode sets up some internal data, then + * notifies host via "initialize alive" that it is complete. + * + * The host then replaces the BSM_DRAM_* pointer values to point to the + * normal runtime uCode instructions and a backup uCode data cache buffer + * (filled initially with starting data values for the on-board processor), + * then triggers the "initialize" uCode to load and launch the runtime uCode, + * which begins normal operation. + * + * When doing a power-save shutdown, runtime uCode saves data SRAM into + * the backup data cache in DRAM before SRAM is powered down. + * + * When powering back up, the BSM loads the bootstrap program. This reloads + * the runtime uCode instructions and the backup data cache into SRAM, + * and re-launches the runtime uCode from where it left off. + */ +static int iwl_load_bsm(struct iwl_priv *priv) +{ + __le32 *image = priv->ucode_boot.v_addr; + u32 len = priv->ucode_boot.len; + dma_addr_t pinst; + dma_addr_t pdata; + u32 inst_len; + u32 data_len; + int rc; + int i; + u32 done; + u32 reg_offset; + + IWL_DEBUG_INFO("Begin load bsm\n"); + + /* make sure bootstrap program is no larger than BSM's SRAM size */ + if (len > IWL_MAX_BSM_SIZE) + return -EINVAL; + + /* Tell bootstrap uCode where to find the "Initialize" uCode + * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965. + * NOTE: iwl_initialize_alive_start() will replace these values, + * after the "initialize" uCode has run, to point to + * runtime/protocol instructions and backup data cache. */ + pinst = priv->ucode_init.p_addr >> 4; + pdata = priv->ucode_init_data.p_addr >> 4; + inst_len = priv->ucode_init.len; + data_len = priv->ucode_init_data.len; + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); + + /* Fill BSM memory with bootstrap instructions */ + for (reg_offset = BSM_SRAM_LOWER_BOUND; + reg_offset < BSM_SRAM_LOWER_BOUND + len; + reg_offset += sizeof(u32), image++) + _iwl_write_restricted_reg(priv, reg_offset, + le32_to_cpu(*image)); + + rc = iwl_verify_bsm(priv); + if (rc) { + iwl_release_restricted_access(priv); + return rc; + } + + /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ + iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0); + iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG, + RTC_INST_LOWER_BOUND); + iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); + + /* Load bootstrap code into instruction SRAM now, + * to prepare to load "initialize" uCode */ + iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + BSM_WR_CTRL_REG_BIT_START); + + /* Wait for load of bootstrap uCode to finish */ + for (i = 0; i < 100; i++) { + done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG); + if (!(done & BSM_WR_CTRL_REG_BIT_START)) + break; + udelay(10); + } + if (i < 100) + IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i); + else { + IWL_ERROR("BSM write did not complete!\n"); + return -EIO; + } + + /* Enable future boot loads whenever power management unit triggers it + * (e.g. when powering back up after power-save shutdown) */ + iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + BSM_WR_CTRL_REG_BIT_START_EN); + + iwl_release_restricted_access(priv); + + return 0; +} + +static void iwl_nic_start(struct iwl_priv *priv) +{ + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); +} + +/** + * iwl_read_ucode - Read uCode images from disk file. + * + * Copy into buffers for card to fetch via bus-mastering + */ +static int iwl_read_ucode(struct iwl_priv *priv) +{ + struct iwl_ucode *ucode; + int rc = 0; + const struct firmware *ucode_raw; + const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode"; + u8 *src; + size_t len; + u32 ver, 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. */ + rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); + if (rc < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc); + goto error; + } + + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + name, ucode_raw->size); + + /* Make sure that we got at least our header! */ + if (ucode_raw->size < sizeof(*ucode)) { + IWL_ERROR("File size way too small!\n"); + rc = -EINVAL; + goto err_release; + } + + /* Data from ucode file: header followed by uCode images */ + ucode = (void *)ucode_raw->data; + + ver = le32_to_cpu(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); + + IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", + inst_size); + IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", + data_size); + IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", + init_size); + IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", + init_data_size); + IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", + boot_size); + + /* Verify size of file vs. image size info in file's header */ + if (ucode_raw->size < sizeof(*ucode) + + inst_size + data_size + init_size + + init_data_size + boot_size) { + + IWL_DEBUG_INFO("uCode file size %d too small\n", + (int)ucode_raw->size); + rc = -EINVAL; + goto err_release; + } + + /* Verify that uCode images will fit in card's SRAM */ + if (inst_size > IWL_MAX_INST_SIZE) { + IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n", + (int)inst_size); + rc = -EINVAL; + goto err_release; + } + + if (data_size > IWL_MAX_DATA_SIZE) { + IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n", + (int)data_size); + rc = -EINVAL; + goto err_release; + } + if (init_size > IWL_MAX_INST_SIZE) { + IWL_DEBUG_INFO + ("uCode init instr len %d too large to fit in card\n", + (int)init_size); + rc = -EINVAL; + goto err_release; + } + if (init_data_size > IWL_MAX_DATA_SIZE) { + IWL_DEBUG_INFO + ("uCode init data len %d too large to fit in card\n", + (int)init_data_size); + rc = -EINVAL; + goto err_release; + } + if (boot_size > IWL_MAX_BSM_SIZE) { + IWL_DEBUG_INFO + ("uCode boot instr len %d too large to fit in bsm\n", + (int)boot_size); + rc = -EINVAL; + goto err_release; + } + + /* Allocate ucode buffers for card's bus-master loading ... */ + + /* Runtime instructions and 2 copies of data: + * 1) unmodified from disk + * 2) backup cache for save/restore during power-downs */ + priv->ucode_code.len = inst_size; + priv->ucode_code.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_code.len, + &(priv->ucode_code.p_addr)); + + priv->ucode_data.len = data_size; + priv->ucode_data.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_data.len, + &(priv->ucode_data.p_addr)); + + priv->ucode_data_backup.len = data_size; + priv->ucode_data_backup.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_data_backup.len, + &(priv->ucode_data_backup.p_addr)); + + + /* Initialization instructions and data */ + priv->ucode_init.len = init_size; + priv->ucode_init.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_init.len, + &(priv->ucode_init.p_addr)); + + priv->ucode_init_data.len = init_data_size; + priv->ucode_init_data.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_init_data.len, + &(priv->ucode_init_data.p_addr)); + + /* Bootstrap (instructions only, no data) */ + priv->ucode_boot.len = boot_size; + priv->ucode_boot.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_boot.len, + &(priv->ucode_boot.p_addr)); + + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || + !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr || + !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr) + goto err_pci_alloc; + + /* 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; + IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n", + (int)len); + memcpy(priv->ucode_code.v_addr, src, len); + IWL_DEBUG_INFO("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; + IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n", + (int)len); + memcpy(priv->ucode_data.v_addr, src, len); + memcpy(priv->ucode_data_backup.v_addr, src, len); + + /* Initialization instructions (3rd block) */ + if (init_size) { + src = &ucode->data[inst_size + data_size]; + len = priv->ucode_init.len; + IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n", + (int)len); + memcpy(priv->ucode_init.v_addr, 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; + IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n", + (int)len); + memcpy(priv->ucode_init_data.v_addr, src, len); + } + + /* Bootstrap instructions (5th block) */ + src = &ucode->data[inst_size + data_size + init_size + init_data_size]; + len = priv->ucode_boot.len; + IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n", + (int)len); + memcpy(priv->ucode_boot.v_addr, src, len); + + /* We have our copies now, allow OS release its copies */ + release_firmware(ucode_raw); + return 0; + + err_pci_alloc: + IWL_ERROR("failed to allocate pci memory\n"); + rc = -ENOMEM; + iwl_dealloc_ucode_pci(priv); + + err_release: + release_firmware(ucode_raw); + + error: + return rc; +} + + +/** + * iwl_set_ucode_ptrs - Set uCode address location + * + * Tell initialization uCode where to find runtime uCode. + * + * BSM registers initially contain pointers to initialization uCode. + * We need to replace them to load runtime uCode inst and data, + * and to save runtime data when powering down. + */ +static int iwl_set_ucode_ptrs(struct iwl_priv *priv) +{ + dma_addr_t pinst; + dma_addr_t pdata; + int rc = 0; + unsigned long flags; + + /* bits 35:4 for 4965 */ + pinst = priv->ucode_code.p_addr >> 4; + pdata = priv->ucode_data_backup.p_addr >> 4; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* Tell bootstrap uCode where to find image to load */ + iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + priv->ucode_data.len); + + /* Inst bytecount must be last to set up, bit 31 signals uCode + * that all new ptr/size info is in place */ + iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, + priv->ucode_code.len | BSM_DRAM_INST_LOAD); + + iwl_release_restricted_access(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); + + return rc; +} + +/** + * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved + * + * Called after REPLY_ALIVE notification received from "initialize" uCode. + * + * The 4965 "initialize" ALIVE reply contains calibration data for: + * Voltage, temperature, and MIMO tx gain correction, now stored in priv + * (3945 does not contain this data). + * + * Tell "initialize" uCode to go ahead and load the runtime uCode. +*/ +static void iwl_init_alive_start(struct iwl_priv *priv) +{ + /* 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 + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* Bootstrap uCode has loaded initialize uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + /* Calculate temperature */ + priv->temperature = iwl4965_get_temperature(priv); + + /* Send pointers to protocol/runtime uCode image ... init code will + * load and launch runtime uCode, which will send us another "Alive" + * notification. */ + IWL_DEBUG_INFO("Initialization Alive received.\n"); + if (iwl_set_ucode_ptrs(priv)) { + /* Runtime instruction load won't happen; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); + goto restart; + } + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + + +/** + * iwl_alive_start - called after REPLY_ALIVE notification received + * from protocol/runtime uCode (initialization uCode's + * Alive gets handled by iwl_init_alive_start()). + */ +static void iwl_alive_start(struct iwl_priv *priv) +{ + int rc = 0; + + IWL_DEBUG_INFO("Runtime Alive received.\n"); + + if (priv->card_alive.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Alive failed.\n"); + goto restart; + } + + /* Initialize uCode has loaded Runtime uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "runtime" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad runtime uCode load.\n"); + goto restart; + } + + iwl_clear_stations_table(priv); + + rc = iwl4965_alive_notify(priv); + if (rc) { + IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", + rc); + goto restart; + } + + /* After the ALIVE response, we can process host commands */ + set_bit(STATUS_ALIVE, &priv->status); + + /* Clear out the uCode error bit if it is set */ + clear_bit(STATUS_FW_ERROR, &priv->status); + + rc = iwl_init_channel_map(priv); + if (rc) { + IWL_ERROR("initializing regulatory failed: %d\n", rc); + return; + } + + iwl_init_geos(priv); + + if (iwl_is_rfkill(priv)) + return; + + if (!priv->mac80211_registered) { + /* Unlock so any user space entry points can call back into + * the driver without a deadlock... */ + mutex_unlock(&priv->mutex); + iwl_rate_control_register(priv->hw); + rc = ieee80211_register_hw(priv->hw); + priv->hw->conf.beacon_int = 100; + mutex_lock(&priv->mutex); + + if (rc) { + IWL_ERROR("Failed to register network " + "device (error %d)\n", rc); + return; + } + + priv->mac80211_registered = 1; + + iwl_reset_channel_flag(priv); + } else + ieee80211_start_queues(priv->hw); + + priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); + + if (iwl_is_associated(priv)) { + struct iwl_rxon_cmd *active_rxon = + (struct iwl_rxon_cmd *)(&priv->active_rxon); + + memcpy(&priv->staging_rxon, &priv->active_rxon, + sizeof(priv->staging_rxon)); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + } else { + /* Initialize our rx_config data */ + iwl_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + } + + /* Configure BT coexistence */ + iwl_send_bt_config(priv); + + /* Configure the adapter for unassociated operation */ + iwl_commit_rxon(priv); + + /* At this point, the NIC is initialized and operational */ + priv->notif_missed_beacons = 0; + set_bit(STATUS_READY, &priv->status); + + iwl4965_rf_kill_ct_config(priv); + IWL_DEBUG_INFO("ALIVE processing complete.\n"); + + if (priv->error_recovering) + iwl_error_recovery(priv); + + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv); + +static void __iwl_down(struct iwl_priv *priv) +{ + unsigned long flags; + int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + struct ieee80211_conf *conf = NULL; + + IWL_DEBUG_INFO(DRV_NAME " is going down\n"); + + conf = ieee80211_get_hw_conf(priv->hw); + + if (!exit_pending) + set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl_clear_stations_table(priv); + + /* Unblock any waiting calls */ + wake_up_interruptible_all(&priv->wait_command_queue); + + iwl_cancel_deferred_work(priv); + + /* Wipe out the EXIT_PENDING status bit if we are not actually + * exiting the module */ + if (!exit_pending) + clear_bit(STATUS_EXIT_PENDING, &priv->status); + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + /* If we have not previously called iwl_init() then + * clear all bits but the RF Kill and SUSPEND bits and return */ + if (!iwl_is_init(priv)) { + priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND; + goto exit; + } + + /* ...otherwise clear out all the status bits but the RF Kill and + * SUSPEND bits and continue taking the NIC down. */ + priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND | + test_bit(STATUS_FW_ERROR, &priv->status) << + STATUS_FW_ERROR; + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_hw_txq_ctx_stop(priv); + iwl_hw_rxq_stop(priv); + + spin_lock_irqsave(&priv->lock, flags); + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_restricted_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + iwl_hw_nic_stop_master(priv); + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_hw_nic_reset(priv); + + exit: + memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + priv->ibss_beacon = NULL; + + /* clear out any free frames */ + iwl_clear_free_frames(priv); +} + +static void iwl_down(struct iwl_priv *priv) +{ + mutex_lock(&priv->mutex); + __iwl_down(priv); + mutex_unlock(&priv->mutex); +} + +#define MAX_HW_RESTARTS 5 + +static int __iwl_up(struct iwl_priv *priv) +{ + int rc, i; + u32 hw_rf_kill = 0; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_WARNING("Exit pending; will not bring the NIC up\n"); + return -EIO; + } + + if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("Radio disabled by SW RF kill (module " + "parameter)\n"); + return 0; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + rc = iwl_hw_nic_init(priv); + if (rc) { + IWL_ERROR("Unable to int nic\n"); + return rc; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* Copy original ucode data image from disk into backup cache. + * This will be used to initialize the on-board processor's + * data SRAM for a clean start when the runtime program first loads. */ + memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, + priv->ucode_data.len); + + /* If platform's RF_KILL switch is set to KILL, + * wait for BIT_INT_RF_KILL interrupt before loading uCode + * and getting things started */ + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) { + IWL_WARNING("Radio disabled by HW RF Kill switch\n"); + return 0; + } + + for (i = 0; i < MAX_HW_RESTARTS; i++) { + + iwl_clear_stations_table(priv); + + /* load bootstrap state machine, + * load bootstrap program into processor's memory, + * prepare to load the "initialize" uCode */ + rc = iwl_load_bsm(priv); + + if (rc) { + IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc); + continue; + } + + /* start card; "initialize" will load runtime ucode */ + iwl_nic_start(priv); + + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n", + MAC_ARG(priv->mac_addr)); + + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + + IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); + + return 0; + } + + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + + /* tried to restart and config the device for as long as our + * patience could withstand */ + IWL_ERROR("Unable to initialize device after %d attempts.\n", i); + return -EIO; +} + + +/***************************************************************************** + * + * Workqueue callbacks + * + *****************************************************************************/ + +static void iwl_bg_init_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, init_alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_init_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_rf_kill(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); + + wake_up_interruptible(&priv->wait_command_queue); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + if (!iwl_is_rfkill(priv)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, + "HW and/or SW RF Kill no longer active, restarting " + "device\n"); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } else { + + if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by SW switch\n"); + else + IWL_WARNING("Radio Frequency Kill Switch is On:\n" + "Kill switch must be turned off for " + "wireless networking to work.\n"); + } + mutex_unlock(&priv->mutex); +} + +#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) + +static void iwl_bg_scan_check(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, scan_check.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + if (test_bit(STATUS_SCANNING, &priv->status) || + test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, + "Scan completion watchdog resetting adapter (%dms)\n", + jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_request_scan(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, request_scan); + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_CMD, + .len = sizeof(struct iwl_scan_cmd), + .meta.flags = CMD_SIZE_HUGE, + }; + int rc = 0; + struct iwl_scan_cmd *scan; + struct ieee80211_conf *conf = NULL; + u8 direct_mask; + int phymode; + + conf = ieee80211_get_hw_conf(priv->hw); + + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + IWL_WARNING("request scan called when driver not ready.\n"); + goto done; + } + + /* Make sure the scan wasn't cancelled before this queued work + * was given the chance to run... */ + if (!test_bit(STATUS_SCANNING, &priv->status)) + goto done; + + /* This should never be called or scheduled if there is currently + * a scan active in the hardware. */ + if (test_bit(STATUS_SCAN_HW, &priv->status)) { + IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " + "Ignoring second request.\n"); + rc = -EIO; + goto done; + } + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); + goto done; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); + goto done; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); + goto done; + } + + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); + goto done; + } + + if (!priv->scan_bands) { + IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); + goto done; + } + + if (!priv->scan) { + priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + + IWL_MAX_SCAN_SIZE, GFP_KERNEL); + if (!priv->scan) { + rc = -ENOMEM; + goto done; + } + } + scan = priv->scan; + memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + + scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; + scan->quiet_time = IWL_ACTIVE_QUIET_TIME; + + if (iwl_is_associated(priv)) { + u16 interval = 0; + u32 extra; + u32 suspend_time = 100; + u32 scan_suspend_time = 100; + unsigned long flags; + + IWL_DEBUG_INFO("Scanning while associated...\n"); + + spin_lock_irqsave(&priv->lock, flags); + interval = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + scan->suspend_time = 0; + scan->max_out_time = cpu_to_le32(600 * 1024); + if (!interval) + interval = suspend_time; + + extra = (suspend_time / interval) << 22; + scan_suspend_time = (extra | + ((suspend_time % interval) * 1024)); + scan->suspend_time = cpu_to_le32(scan_suspend_time); + IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", + scan_suspend_time, interval); + } + + /* We should add the ability for user to lock to PASSIVE ONLY */ + if (priv->one_direct_scan) { + IWL_DEBUG_SCAN + ("Kicking off one direct scan for '%s'\n", + iwl_escape_essid(priv->direct_ssid, + priv->direct_ssid_len)); + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->direct_ssid_len; + memcpy(scan->direct_scan[0].ssid, + priv->direct_ssid, priv->direct_ssid_len); + direct_mask = 1; + } else if (!iwl_is_associated(priv)) { + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->essid_len; + memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); + direct_mask = 1; + } else + direct_mask = 0; + + /* We don't build a direct scan probe request; the uCode will do + * that based on the direct_mask added to each channel entry */ + scan->tx_cmd.len = cpu_to_le16( + iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, + IWL_MAX_SCAN_SIZE - sizeof(scan), 0)); + scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; + scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; + scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + /* flags + rate selection */ + + scan->tx_cmd.tx_flags |= cpu_to_le32(0x200); + + switch (priv->scan_bands) { + case 2: + scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; + scan->tx_cmd.rate_n_flags = + iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, + RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK); + + scan->good_CRC_th = 0; + phymode = MODE_IEEE80211G; + break; + + case 1: + scan->tx_cmd.rate_n_flags = + iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, + RATE_MCS_ANT_B_MSK); + scan->good_CRC_th = IWL_GOOD_CRC_TH; + phymode = MODE_IEEE80211A; + break; + + default: + IWL_WARNING("Invalid scan band count\n"); + goto done; + } + + /* select Rx chains */ + + /* Force use of chains B and C (0x6) for scan Rx. + * Avoid A (0x1) because of its off-channel reception on A-band. + * MIMO is not used here, but value is required to make uCode happy. */ + scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | + cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | + (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) | + (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + scan->filter_flags = RXON_FILTER_PROMISC_MSK; + + if (direct_mask) + IWL_DEBUG_SCAN + ("Initiating direct scan for %s.\n", + iwl_escape_essid(priv->essid, priv->essid_len)); + else + IWL_DEBUG_SCAN("Initiating indirect scan.\n"); + + scan->channel_count = + iwl_get_channels_for_scan( + priv, phymode, 1, /* active */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + + cmd.len += le16_to_cpu(scan->tx_cmd.len) + + scan->channel_count * sizeof(struct iwl_scan_channel); + cmd.data = scan; + scan->len = cpu_to_le16(cmd.len); + + set_bit(STATUS_SCAN_HW, &priv->status); + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + goto done; + + queue_delayed_work(priv->workqueue, &priv->scan_check, + IWL_SCAN_CHECK_WATCHDOG); + + mutex_unlock(&priv->mutex); + return; + + done: + /* inform mac80211 sacn aborted */ + queue_work(priv->workqueue, &priv->scan_completed); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_up(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl_up(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_restart(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + iwl_down(priv); + queue_work(priv->workqueue, &priv->up); +} + +static void iwl_bg_rx_replenish(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, rx_replenish); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_rx_replenish(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_post_associate(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, + post_associate.work); + + int rc = 0; + struct ieee80211_conf *conf = NULL; + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); + return; + } + + IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n", + priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr)); + + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + conf = ieee80211_get_hw_conf(priv->hw); + + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); + iwl_setup_rxon_timing(priv); + rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (rc) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + +#ifdef CONFIG_IWLWIFI_HT + if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht) + iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht); + else { + priv->active_rate_ht[0] = 0; + priv->active_rate_ht[1] = 0; + priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ; + } +#endif /* CONFIG_IWLWIFI_HT*/ + iwl4965_set_rxon_chain(priv); + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + + IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", + priv->assoc_id, priv->beacon_int); + + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + } + + iwl_commit_rxon(priv); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_STA: + iwl_rate_scale_init(priv->hw, IWL_AP_ID); + break; + + case IEEE80211_IF_TYPE_IBSS: + + /* clear out the station table */ + iwl_clear_stations_table(priv); + + iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl_rxon_add_station(priv, priv->bssid, 0); + iwl_rate_scale_init(priv->hw, IWL_STA_ID); + iwl_send_beacon_cmd(priv); + + break; + + default: + IWL_ERROR("%s Should not be called in %d mode\n", + __FUNCTION__, priv->iw_mode); + break; + } + + iwl_sequence_reset(priv); + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + /* Enable Rx differential gain and sensitivity calibrations */ + iwl4965_chain_noise_reset(priv); + priv->start_calib = 1; +#endif /* CONFIG_IWLWIFI_SENSITIVITY */ + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->assoc_station_added = 1; + +#ifdef CONFIG_IWLWIFI_QOS + iwl_activate_qos(priv, 0); +#endif /* CONFIG_IWLWIFI_QOS */ + mutex_unlock(&priv->mutex); +} + +static 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)) + return; + + mutex_lock(&priv->mutex); + + set_bit(STATUS_SCAN_ABORTING, &priv->status); + iwl_send_scan_abort(priv); + + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_scan_completed(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + ieee80211_scan_completed(priv->hw); + + /* Since setting the TXPOWER may have been deferred while + * performing the scan, fire one off */ + mutex_lock(&priv->mutex); + iwl_hw_reg_send_txpower(priv); + mutex_unlock(&priv->mutex); +} + +/***************************************************************************** + * + * mac80211 entry point functions + * + *****************************************************************************/ + +static int iwl_mac_open(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + /* we should be verifying the device is ready to be opened */ + mutex_lock(&priv->mutex); + + priv->is_open = 1; + + if (!iwl_is_rfkill(priv)) + ieee80211_start_queues(priv->hw); + + mutex_unlock(&priv->mutex); + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + priv->is_open = 0; + /*netif_stop_queue(dev); */ + flush_workqueue(priv->workqueue); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + IWL_DEBUG_MAC80211("leave - monitor\n"); + return -1; + } + + IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, + ctl->tx_rate); + + if (iwl_tx_skb(priv, skb, ctl)) + dev_kfree_skb_any(skb); + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); + if (conf->mac_addr) + IWL_DEBUG_MAC80211("enter: MAC " MAC_FMT "\n", + MAC_ARG(conf->mac_addr)); + + if (priv->interface_id) { + IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + priv->interface_id = conf->if_id; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + iwl_set_mode(priv, conf->type); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +/** + * iwl_mac_config - mac80211 config callback + * + * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to + * be set inappropriately and the driver currently sets the hardware up to + * use it whenever needed. + */ +static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only + * what is exposed through include/ declrations */ + if (unlikely(!iwl_param_disable_hw_scan && + test_bit(STATUS_SCANNING, &priv->status))) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + + ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", + conf->channel, conf->phymode); + IWL_DEBUG_MAC80211("leave - invalid channel\n"); + spin_unlock_irqrestore(&priv->lock, flags); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + +#ifdef CONFIG_IWLWIFI_HT + /* if we are switching fron ht to 2.4 clear flags + * from any ht related info since 2.4 does not + * support ht */ + if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel) +#ifdef IEEE80211_CONF_CHANNEL_SWITCH + && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) +#endif + ) + priv->staging_rxon.flags = 0; +#endif /* CONFIG_IWLWIFI_HT */ + + iwl_set_rxon_channel(priv, conf->phymode, conf->channel); + + iwl_set_flags_for_phymode(priv, conf->phymode); + + /* The list of supported rates and rate mask can be different + * for each phymode; since the phymode may have changed, reset + * the rate mask to what mac80211 lists */ + iwl_set_rate(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef IEEE80211_CONF_CHANNEL_SWITCH + if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { + iwl_hw_channel_switch(priv, conf->channel); + mutex_unlock(&priv->mutex); + return 0; + } +#endif + + iwl_radio_kill_sw(priv, !conf->radio_enabled); + + if (!conf->radio_enabled) { + IWL_DEBUG_MAC80211("leave - radio disabled\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_MAC80211("leave - RF kill\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + iwl_set_rate(priv); + + if (memcmp(&priv->active_rxon, + &priv->staging_rxon, sizeof(priv->staging_rxon))) + iwl_commit_rxon(priv); + else + IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); + + IWL_DEBUG_MAC80211("leave\n"); + + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_config_ap(struct iwl_priv *priv) +{ + int rc = 0; + + if (priv->status & STATUS_EXIT_PENDING) + return; + + /* The following should be done only at AP bring up */ + if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + + /* RXON - unassoc (to set timing command) */ + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + /* RXON Timing */ + memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); + iwl_setup_rxon_timing(priv); + rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (rc) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + iwl4965_set_rxon_chain(priv); + + /* FIXME: what should be the assoc_id for AP? */ + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & + WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + } + /* restore RXON assoc */ + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); +#ifdef CONFIG_IWLWIFI_QOS + iwl_activate_qos(priv, 1); +#endif + iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl_send_beacon_cmd(priv); + } else + iwl_send_beacon_cmd(priv); + + /* FIXME - we need to add code here to detect a totally new + * configuration, reset the AP, unassoc, rxon timing, assoc, + * clear sta table, add BCAST sta... */ +} + +static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + int rc; + + if (conf == NULL) + return -EIO; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!conf->beacon || !conf->ssid_len)) { + IWL_DEBUG_MAC80211 + ("Leaving in AP mode because HostAPD is not ready.\n"); + return 0; + } + + mutex_lock(&priv->mutex); + + IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); + if (conf->bssid) + IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n", + MAC_ARG(conf->bssid)); + + if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && + !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (priv->interface_id != if_id) { + IWL_DEBUG_MAC80211("leave - interface_id != if_id\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (!conf->bssid) { + conf->bssid = priv->mac_addr; + memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); + IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n", + MAC_ARG(conf->bssid)); + } + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = conf->beacon; + } + + if (conf->bssid && !is_zero_ether_addr(conf->bssid) && + !is_multicast_ether_addr(conf->bssid)) { + /* If there is currently a HW scan going on in the background + * then we need to cancel it else the RXON below will fail. */ + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress " + "after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + mutex_unlock(&priv->mutex); + return -EAGAIN; + } + memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); + + /* TODO: Audit driver for usage of these members and see + * if mac80211 deprecates them (priv->bssid looks like it + * shouldn't be there, but I haven't scanned the IBSS code + * to verify) - jpk */ + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_config_ap(priv); + else { + priv->staging_rxon.filter_flags |= + RXON_FILTER_ASSOC_MSK; + rc = iwl_commit_rxon(priv); + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + iwl_rxon_add_station( + priv, priv->active_rxon.bssid_addr, 1); + } + + } else { + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + } + + spin_lock_irqsave(&priv->lock, flags); + if (!conf->ssid_len) + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + else + memcpy(priv->essid, conf->ssid, conf->ssid_len); + + priv->essid_len = conf->ssid_len; + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + mutex_lock(&priv->mutex); + if (priv->interface_id == conf->if_id) { + priv->interface_id = 0; + memset(priv->bssid, 0, ETH_ALEN); + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + priv->essid_len = 0; + } + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +#define IWL_DELAY_NEXT_SCAN (HZ*2) +static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +{ + int rc = 0; + unsigned long flags; + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + spin_lock_irqsave(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + rc = -EIO; + IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); + goto out_unlock; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ + rc = -EIO; + IWL_ERROR("ERROR: APs don't scan\n"); + goto out_unlock; + } + + /* if we just finished scan ask for delay */ + if (priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, + jiffies)) { + rc = -EAGAIN; + goto out_unlock; + } + if (len) { + IWL_DEBUG_SCAN("direct scan for " + "%s [%d]\n ", + iwl_escape_essid(ssid, len), (int)len); + + priv->one_direct_scan = 1; + priv->direct_ssid_len = (u8) + min((u8) len, (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); + } + + rc = iwl_scan_initiate(priv); + + IWL_DEBUG_MAC80211("leave\n"); + +out_unlock: + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct iwl_priv *priv = hw->priv; + int rc = 0; + u8 sta_id; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_param_hwcrypto) { + IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); + return -EOPNOTSUPP; + } + + if (is_zero_ether_addr(addr)) + /* only support pairwise keys */ + return -EOPNOTSUPP; + + sta_id = iwl_hw_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - " MAC_FMT " not in station map.\n", + MAC_ARG(addr)); + return -EINVAL; + } + + mutex_lock(&priv->mutex); + + switch (cmd) { + case SET_KEY: + rc = iwl_update_sta_key_info(priv, key, sta_id); + if (!rc) { + iwl_set_rxon_hwcrypto(priv, 1); + iwl_commit_rxon(priv); + key->hw_key_idx = sta_id; + IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n"); + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + break; + case DISABLE_KEY: + rc = iwl_clear_sta_key_info(priv, sta_id); + if (!rc) { + iwl_set_rxon_hwcrypto(priv, 0); + iwl_commit_rxon(priv); + IWL_DEBUG_MAC80211("disable hwcrypto key\n"); + } + break; + default: + rc = -EINVAL; + } + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return rc; +} + +static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct iwl_priv *priv = hw->priv; +#ifdef CONFIG_IWLWIFI_QOS + unsigned long flags; + int q; +#endif /* CONFIG_IWL_QOS */ + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + if (queue >= AC_NUM) { + IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue); + return 0; + } + +#ifdef CONFIG_IWLWIFI_QOS + if (!priv->qos_data.qos_enable) { + priv->qos_data.qos_active = 0; + IWL_DEBUG_MAC80211("leave - qos not enabled\n"); + return 0; + } + q = AC_NUM - 1 - queue; + + spin_lock_irqsave(&priv->lock, flags); + + priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); + priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); + priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; + priv->qos_data.def_qos_parm.ac[q].edca_txop = + cpu_to_le16((params->burst_time * 100)); + + priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; + priv->qos_data.qos_active = 1; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_activate_qos(priv, 1); + else if (priv->assoc_id && iwl_is_associated(priv)) + iwl_activate_qos(priv, 0); + + mutex_unlock(&priv->mutex); + +#endif /*CONFIG_IWLWIFI_QOS */ + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + int i, avail; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < AC_NUM; i++) { + txq = &priv->txq[i]; + q = &txq->q; + avail = iwl_queue_space(q); + + stats->data[i].len = q->n_window - avail; + stats->data[i].limit = q->n_window - q->high_mark; + stats->data[i].count = q->n_window; + + } + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl_mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw) +{ + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + + priv->lq_mngr.lq_ready = 0; +#ifdef CONFIG_IWLWIFI_HT + spin_lock_irqsave(&priv->lock, flags); + memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info)); + spin_unlock_irqrestore(&priv->lock, flags); +#ifdef CONFIG_IWLWIFI_HT_AGG +/* if (priv->lq_mngr.agg_ctrl.granted_ba) + iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/ + + memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl_agg_control)); + priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10; + priv->lq_mngr.agg_ctrl.ba_timeout = 5000; + priv->lq_mngr.agg_ctrl.auto_agg = 1; + + if (priv->lq_mngr.agg_ctrl.auto_agg) + priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED; +#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + +#ifdef CONFIG_IWLWIFI_QOS + iwl_reset_qos(priv); +#endif + + cancel_delayed_work(&priv->post_associate); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = 0; + priv->assoc_capability = 0; + priv->call_post_assoc_from_beacon = 0; + priv->assoc_station_added = 0; + + /* new association get rid of ibss beacon skb */ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = NULL; + + priv->beacon_int = priv->hw->conf.beacon_int; + priv->timestamp1 = 0; + priv->timestamp0 = 0; + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + priv->beacon_int = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Per mac80211.h: This is only used in IBSS mode... */ + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not in IBSS\n"); + mutex_unlock(&priv->mutex); + return; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + + priv->only_active_channel = 0; + + iwl_set_rate(priv); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not IBSS\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = skb; + + priv->assoc_id = 0; + + IWL_DEBUG_MAC80211("leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef CONFIG_IWLWIFI_QOS + iwl_reset_qos(priv); +#endif + + queue_work(priv->workqueue, &priv->post_associate.work); + + mutex_unlock(&priv->mutex); + + return 0; +} + +#ifdef CONFIG_IWLWIFI_HT +union ht_cap_info { + struct { + u16 advanced_coding_cap :1; + u16 supported_chan_width_set :1; + u16 mimo_power_save_mode :2; + u16 green_field :1; + u16 short_GI20 :1; + u16 short_GI40 :1; + u16 tx_stbc :1; + u16 rx_stbc :1; + u16 beam_forming :1; + u16 delayed_ba :1; + u16 maximal_amsdu_size :1; + u16 cck_mode_at_40MHz :1; + u16 psmp_support :1; + u16 stbc_ctrl_frame_support :1; + u16 sig_txop_protection_support :1; + }; + u16 val; +} __attribute__ ((packed)); + +union ht_param_info{ + struct { + u8 max_rx_ampdu_factor :2; + u8 mpdu_density :3; + u8 reserved :3; + }; + u8 val; +} __attribute__ ((packed)); + +union ht_exra_param_info { + struct { + u8 ext_chan_offset :2; + u8 tx_chan_width :1; + u8 rifs_mode :1; + u8 controlled_access_only :1; + u8 service_interval_granularity :3; + }; + u8 val; +} __attribute__ ((packed)); + +union ht_operation_mode{ + struct { + u16 op_mode :2; + u16 non_GF :1; + u16 reserved :13; + }; + u16 val; +} __attribute__ ((packed)); + + +static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap, + struct ieee80211_ht_additional_info *ht_extra, + struct sta_ht_info *ht_info_ap, + struct sta_ht_info *ht_info) +{ + union ht_cap_info cap; + union ht_operation_mode op_mode; + union ht_param_info param_info; + union ht_exra_param_info extra_param_info; + + IWL_DEBUG_MAC80211("enter: \n"); + + if (!ht_info) { + IWL_DEBUG_MAC80211("leave: ht_info is NULL\n"); + return -1; + } + + if (ht_cap) { + cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info); + param_info.val = ht_cap->mac_ht_params_info; + ht_info->is_ht = 1; + if (cap.short_GI20) + ht_info->sgf |= 0x1; + if (cap.short_GI40) + ht_info->sgf |= 0x2; + ht_info->is_green_field = cap.green_field; + ht_info->max_amsdu_size = cap.maximal_amsdu_size; + ht_info->supported_chan_width = cap.supported_chan_width_set; + ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode; + memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16); + + ht_info->ampdu_factor = param_info.max_rx_ampdu_factor; + ht_info->mpdu_density = param_info.mpdu_density; + + IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n", + ht_cap->supported_mcs_set[0], + ht_cap->supported_mcs_set[1]); + + if (ht_info_ap) { + ht_info->control_channel = ht_info_ap->control_channel; + ht_info->extension_chan_offset = + ht_info_ap->extension_chan_offset; + ht_info->tx_chan_width = ht_info_ap->tx_chan_width; + ht_info->operating_mode = ht_info_ap->operating_mode; + } + + if (ht_extra) { + extra_param_info.val = ht_extra->ht_param; + ht_info->control_channel = ht_extra->control_chan; + ht_info->extension_chan_offset = + extra_param_info.ext_chan_offset; + ht_info->tx_chan_width = extra_param_info.tx_chan_width; + op_mode.val = (u16) + le16_to_cpu(ht_extra->operation_mode); + ht_info->operating_mode = op_mode.op_mode; + IWL_DEBUG_MAC80211("control channel %d\n", + ht_extra->control_chan); + } + } else + ht_info->is_ht = 0; + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_conf_ht(struct ieee80211_hw *hw, + struct ieee80211_ht_capability *ht_cap, + struct ieee80211_ht_additional_info *ht_extra) +{ + struct iwl_priv *priv = hw->priv; + int rs; + + IWL_DEBUG_MAC80211("enter: \n"); + + rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht); + iwl4965_set_rxon_chain(priv); + + if (priv && priv->assoc_id && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->beacon_int) + queue_work(priv->workqueue, &priv->post_associate.work); + else + priv->call_post_assoc_from_beacon = 1; + spin_unlock_irqrestore(&priv->lock, flags); + } + + IWL_DEBUG_MAC80211("leave: control channel %d\n", + ht_extra->control_chan); + return rs; + +} + +static void iwl_set_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_ht_capability *ht_cap, + u8 use_wide_chan) +{ + union ht_cap_info cap; + union ht_param_info param_info; + + memset(&cap, 0, sizeof(union ht_cap_info)); + memset(¶m_info, 0, sizeof(union ht_param_info)); + + cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K; + cap.green_field = 1; + cap.short_GI20 = 1; + cap.short_GI40 = 1; + cap.supported_chan_width_set = use_wide_chan; + cap.mimo_power_save_mode = 0x3; + + param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; + param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF; + ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val); + ht_cap->mac_ht_params_info = (u8) param_info.val; + + ht_cap->supported_mcs_set[0] = 0xff; + ht_cap->supported_mcs_set[1] = 0xff; + ht_cap->supported_mcs_set[4] = + (cap.supported_chan_width_set) ? 0x1: 0x0; +} + +static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_ht_capability *ht_cap) +{ + u8 use_wide_channel = 1; + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter: \n"); + if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) + use_wide_channel = 0; + + /* no fat tx allowed on 2.4GHZ */ + if (priv->phymode != MODE_IEEE80211A) + use_wide_channel = 0; + + iwl_set_ht_capab(hw, ht_cap, use_wide_channel); + IWL_DEBUG_MAC80211("leave: \n"); +} +#endif /*CONFIG_IWLWIFI_HT*/ + +/***************************************************************************** + * + * sysfs attributes + * + *****************************************************************************/ + +#ifdef CONFIG_IWLWIFI_DEBUG + +/* + * The following adds a new attribute to the sysfs representation + * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) + * used for controlling the debug level. + * + * See the level definitions in iwl for details. + */ + +static ssize_t show_debug_level(struct device_driver *d, char *buf) +{ + return sprintf(buf, "0x%08X\n", iwl_debug_level); +} +static ssize_t store_debug_level(struct device_driver *d, + const char *buf, size_t count) +{ + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 0); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + iwl_debug_level = val; + + return strnlen(buf, count); +} + +static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + +#endif /* CONFIG_IWLWIFI_DEBUG */ + +static ssize_t show_rf_kill(struct device *d, + struct device_attribute *attr, char *buf) +{ + /* + * 0 - RF kill not enabled + * 1 - SW based RF kill active (sysfs) + * 2 - HW based RF kill active + * 3 - Both HW and SW based RF kill active + */ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | + (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); + + return sprintf(buf, "%i\n", val); +} + +static ssize_t store_rf_kill(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + mutex_lock(&priv->mutex); + iwl_radio_kill_sw(priv, buf[0] == '1'); + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); + +static ssize_t show_temperature(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv)); +} + +static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); + +static ssize_t show_rs_window(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct iwl_priv *priv = d->driver_data; + return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID); +} +static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); + +static ssize_t show_tx_power(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + return sprintf(buf, "%d\n", priv->user_txpower_limit); +} + +static ssize_t store_tx_power(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 10); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in decimal form.\n", buf); + else + iwl_hw_reg_set_txpower(priv, val); + + return count; +} + +static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); + +static ssize_t show_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); +} + +static ssize_t store_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.flags) != flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", + flags); + priv->staging_rxon.flags = cpu_to_le32(flags); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); + +static ssize_t show_filter_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + le32_to_cpu(priv->active_rxon.filter_flags)); +} + +static ssize_t store_filter_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 filter_flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.filter_flags = " + "0x%04X\n", filter_flags); + priv->staging_rxon.filter_flags = + cpu_to_le32(filter_flags); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, + store_filter_flags); + +static ssize_t show_tune(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + (priv->phymode << 8) | + le16_to_cpu(priv->active_rxon.channel)); +} + +static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode); + +static ssize_t store_tune(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u16 tune = simple_strtoul(p, &p, 0); + u8 phymode = (tune >> 8) & 0xff; + u16 channel = tune & 0xff; + + IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); + + mutex_lock(&priv->mutex); + if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || + (priv->phymode != phymode)) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, phymode, channel); + if (!ch_info) { + IWL_WARNING("Requested invalid phymode/channel " + "combination: %d %d\n", phymode, channel); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing phymode and " + "rxon.channel = %d %d\n", + phymode, channel); + + iwl_set_rxon_channel(priv, phymode, channel); + iwl_set_flags_for_phymode(priv, phymode); + + iwl_set_rate(priv); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +static ssize_t show_measurement(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl_spectrum_notification measure_report; + u32 size = sizeof(measure_report), len = 0, ofs = 0; + u8 *data = (u8 *) & measure_report; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (!(priv->measurement_status & MEASUREMENT_READY)) { + spin_unlock_irqrestore(&priv->lock, flags); + return 0; + } + memcpy(&measure_report, &priv->measure_report, size); + priv->measurement_status = 0; + spin_unlock_irqrestore(&priv->lock, flags); + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static ssize_t store_measurement(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct ieee80211_measurement_params params = { + .channel = le16_to_cpu(priv->active_rxon.channel), + .start_time = cpu_to_le64(priv->last_tsf), + .duration = cpu_to_le16(1), + }; + u8 type = IWL_MEASURE_BASIC; + u8 buffer[32]; + u8 channel; + + if (count) { + char *p = buffer; + strncpy(buffer, buf, min(sizeof(buffer), count)); + channel = simple_strtoul(p, NULL, 0); + if (channel) + params.channel = channel; + + p = buffer; + while (*p && *p != ' ') + p++; + if (*p) + type = simple_strtoul(p + 1, NULL, 0); + } + + IWL_DEBUG_INFO("Invoking measurement of type %d on " + "channel %d (for '%s')\n", type, params.channel, buf); + iwl_get_measurement(priv, ¶ms, type); + + return count; +} + +static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, + show_measurement, store_measurement); +#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */ + +static ssize_t store_retry_rate(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + priv->retry_rate = simple_strtoul(buf, NULL, 0); + if (priv->retry_rate <= 0) + priv->retry_rate = 1; + + return count; +} + +static ssize_t show_retry_rate(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d", priv->retry_rate); +} + +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 rc; + int mode; + + mode = simple_strtoul(buf, NULL, 0); + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + rc = -EAGAIN; + goto out; + } + + if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC)) + mode = IWL_POWER_AC; + else + mode |= IWL_POWER_ENABLED; + + if (mode != priv->power_mode) { + rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode)); + if (rc) { + IWL_DEBUG_MAC80211("failed setting power mode.\n"); + goto out; + } + priv->power_mode = mode; + } + + rc = count; + + out: + mutex_unlock(&priv->mutex); + return rc; +} + +#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_power_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int level = IWL_POWER_LEVEL(priv->power_mode); + char *p = buf; + + p += sprintf(p, "%d ", level); + switch (level) { + case IWL_POWER_MODE_CAM: + case IWL_POWER_AC: + p += sprintf(p, "(AC)"); + break; + case IWL_POWER_BATTERY: + p += sprintf(p, "(BATTERY)"); + break; + default: + p += sprintf(p, + "(Timeout %dms, Period %dms)", + timeout_duration[level - 1] / 1000, + period_duration[level - 1] / 1000); + } + + if (!(priv->power_mode & IWL_POWER_ENABLED)) + p += sprintf(p, " OFF\n"); + else + p += sprintf(p, " \n"); + + return (p - buf + 1); + +} + +static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, + store_power_level); + +static ssize_t show_channels(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int len = 0, i; + struct ieee80211_channel *channels = NULL; + const struct ieee80211_hw_mode *hw_mode = NULL; + int count = 0; + + if (!iwl_is_ready(priv)) + return -EAGAIN; + + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G); + if (!hw_mode) + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B); + if (hw_mode) { + channels = hw_mode->channels; + count = hw_mode->num_channels; + } + + len += + sprintf(&buf[len], + "Displaying %d channels in 2.4GHz band " + "(802.11bg):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + channels[i].chan, + channels[i].power_level, + channels[i]. + flag & IEEE80211_CHAN_W_RADAR_DETECT ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) + || (channels[i]. + flag & + IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : + ", IBSS", + channels[i]. + flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? + "active/passive" : "passive only"); + + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A); + if (hw_mode) { + channels = hw_mode->channels; + count = hw_mode->num_channels; + } else { + channels = NULL; + count = 0; + } + + len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " + "(802.11a):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + channels[i].chan, + channels[i].power_level, + channels[i]. + flag & IEEE80211_CHAN_W_RADAR_DETECT ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) + || (channels[i]. + flag & + IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : + ", IBSS", + channels[i]. + flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? + "active/passive" : "passive only"); + + return len; +} + +static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); + +static ssize_t show_statistics(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + u32 size = sizeof(struct iwl_notif_statistics); + u32 len = 0, ofs = 0; + u8 *data = (u8 *) & priv->statistics; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + mutex_lock(&priv->mutex); + rc = iwl_send_statistics_request(priv); + mutex_unlock(&priv->mutex); + + if (rc) { + len = sprintf(buf, + "Error sending statistics request: 0x%08X\n", rc); + return len; + } + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); + +static ssize_t show_antenna(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", priv->antenna); +} + +static ssize_t store_antenna(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ant; + struct iwl_priv *priv = dev_get_drvdata(d); + + if (count == 0) + return 0; + + if (sscanf(buf, "%1i", &ant) != 1) { + IWL_DEBUG_INFO("not in hex or decimal form.\n"); + return count; + } + + if ((ant >= 0) && (ant <= 2)) { + IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant); + priv->antenna = (enum iwl_antenna)ant; + } else + IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant); + + + return count; +} + +static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); + +static ssize_t show_status(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + if (!iwl_is_alive(priv)) + return -EAGAIN; + return sprintf(buf, "0x%08x\n", (int)priv->status); +} + +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); + +static ssize_t dump_error_log(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + + if (p[0] == '1') + iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); + +static ssize_t dump_event_log(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + + if (p[0] == '1') + iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); + +/***************************************************************************** + * + * driver setup and teardown + * + *****************************************************************************/ + +static void iwl_setup_deferred_work(struct iwl_priv *priv) +{ + priv->workqueue = create_workqueue(DRV_NAME); + + init_waitqueue_head(&priv->wait_command_queue); + + INIT_WORK(&priv->up, iwl_bg_up); + INIT_WORK(&priv->restart, iwl_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); + INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); + INIT_WORK(&priv->request_scan, iwl_bg_request_scan); + INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); + INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); + INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate); + INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); + + iwl_hw_setup_deferred_work(priv); + + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv) +{ + iwl_hw_cancel_deferred_work(priv); + + cancel_delayed_work(&priv->scan_check); + cancel_delayed_work(&priv->alive_start); + cancel_delayed_work(&priv->post_associate); + cancel_work_sync(&priv->beacon_update); +} + +static struct attribute *iwl_sysfs_entries[] = { + &dev_attr_antenna.attr, + &dev_attr_channels.attr, + &dev_attr_dump_errors.attr, + &dev_attr_dump_events.attr, + &dev_attr_flags.attr, + &dev_attr_filter_flags.attr, +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + &dev_attr_measurement.attr, +#endif + &dev_attr_power_level.attr, + &dev_attr_retry_rate.attr, + &dev_attr_rf_kill.attr, + &dev_attr_rs_window.attr, + &dev_attr_statistics.attr, + &dev_attr_status.attr, + &dev_attr_temperature.attr, + &dev_attr_tune.attr, + &dev_attr_tx_power.attr, + + NULL +}; + +static struct attribute_group iwl_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = iwl_sysfs_entries, +}; + +static struct ieee80211_ops iwl_hw_ops = { + .tx = iwl_mac_tx, + .open = iwl_mac_open, + .stop = iwl_mac_stop, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_mac_config, + .config_interface = iwl_mac_config_interface, + .set_key = iwl_mac_set_key, + .get_stats = iwl_mac_get_stats, + .get_tx_stats = iwl_mac_get_tx_stats, + .conf_tx = iwl_mac_conf_tx, + .get_tsf = iwl_mac_get_tsf, + .reset_tsf = iwl_mac_reset_tsf, + .beacon_update = iwl_mac_beacon_update, +#ifdef CONFIG_IWLWIFI_HT + .conf_ht = iwl_mac_conf_ht, + .get_ht_capab = iwl_mac_get_ht_capab, +#ifdef CONFIG_IWLWIFI_HT_AGG + .ht_tx_agg_start = iwl_mac_ht_tx_agg_start, + .ht_tx_agg_stop = iwl_mac_ht_tx_agg_stop, + .ht_rx_agg_start = iwl_mac_ht_rx_agg_start, + .ht_rx_agg_stop = iwl_mac_ht_rx_agg_stop, +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + .hw_scan = iwl_mac_hw_scan +}; + +static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = 0; + struct iwl_priv *priv; + struct ieee80211_hw *hw; + int i; + + if (iwl_param_disable_hw_scan) { + IWL_DEBUG_INFO("Disabling hw_scan\n"); + iwl_hw_ops.hw_scan = NULL; + } + + if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) || + (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) { + IWL_ERROR("invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES); + err = -EINVAL; + goto out; + } + + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops); + if (hw == NULL) { + IWL_ERROR("Can not allocate network device\n"); + err = -ENOMEM; + goto out; + } + SET_IEEE80211_DEV(hw, &pdev->dev); + + IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); + priv = hw->priv; + priv->hw = hw; + + priv->pci_dev = pdev; + priv->antenna = (enum iwl_antenna)iwl_param_antenna; +#ifdef CONFIG_IWLWIFI_DEBUG + iwl_debug_level = iwl_param_debug; + atomic_set(&priv->restrict_refcnt, 0); +#endif + priv->retry_rate = 1; + + priv->ibss_beacon = NULL; + + /* Tell mac80211 and its clients (e.g. Wireless Extensions) + * the range of signal quality values that we'll provide. + * Negative values for level/noise indicate that we'll provide dBm. + * For WE, at least, non-0 values here *enable* display of values + * in app (iwconfig). */ + hw->max_rssi = -20; /* signal level, negative indicates dBm */ + hw->max_noise = -20; /* noise level, negative indicates dBm */ + hw->max_signal = 100; /* link quality indication (%) */ + + /* Tell mac80211 our Tx characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + + hw->queues = 4; +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + hw->queues = 16; +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + spin_lock_init(&priv->lq_mngr.lock); + + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + if (pci_enable_device(pdev)) { + err = -ENODEV; + goto out_ieee80211_free_hw; + } + + pci_set_master(pdev); + + iwl_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->phymode = -1; + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); + goto out_pci_disable_device; + } + + pci_set_drvdata(pdev, priv); + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto out_pci_disable_device; + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, 0x41, 0x00); + priv->hw_base = pci_iomap(pdev, 0, 0); + if (!priv->hw_base) { + err = -ENODEV; + goto out_pci_release_regions; + } + + IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", + (unsigned long long) pci_resource_len(pdev, 0)); + IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); + + /* Initialize module parameter values here */ + + if (iwl_param_disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); + } + + priv->iw_mode = IEEE80211_IF_TYPE_STA; + + priv->ps_mode = 0; + priv->use_ant_b_for_management_frame = 1; /* start with ant B */ + priv->is_ht_enabled = 1; + priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ; + priv->valid_antenna = 0x7; /* assume all 3 connected */ + priv->ps_mode = IWL_MIMO_PS_NONE; + priv->cck_power_index_compensation = iwl_read32( + priv, CSR_HW_REV_WA_REG); + + iwl4965_set_rxon_chain(priv); + + printk(KERN_INFO DRV_NAME + ": Detected Intel Wireless WiFi Link 4965AGN\n"); + + /* Device-specific setup */ + if (iwl_hw_set_hw_setting(priv)) { + IWL_ERROR("failed to set hw settings\n"); + mutex_unlock(&priv->mutex); + goto out_iounmap; + } + +#ifdef CONFIG_IWLWIFI_QOS + if (iwl_param_qos_enable) + priv->qos_data.qos_enable = 1; + + iwl_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; +#endif /* CONFIG_IWLWIFI_QOS */ + + iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl_setup_deferred_work(priv); + iwl_setup_rx_handlers(priv); + + priv->rates_mask = IWL_RATES_MASK; + /* If power management is turned on, default to AC mode */ + priv->power_mode = IWL_POWER_AC; + priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + + pci_enable_msi(pdev); + + err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); + if (err) { + IWL_ERROR("Error allocating IRQ %d\n", pdev->irq); + goto out_disable_msi; + } + + mutex_lock(&priv->mutex); + + err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); + if (err) { + IWL_ERROR("failed to create sysfs device attributes\n"); + mutex_unlock(&priv->mutex); + goto out_release_irq; + } + + /* fetch ucode file from disk, alloc and copy to bus-master buffers ... + * ucode filename and max sizes are card-specific. */ + err = iwl_read_ucode(priv); + if (err) { + IWL_ERROR("Could not read microcode: %d\n", err); + mutex_unlock(&priv->mutex); + goto out_pci_alloc; + } + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_INFO("Queing UP work.\n"); + + queue_work(priv->workqueue, &priv->up); + + return 0; + + out_pci_alloc: + iwl_dealloc_ucode_pci(priv); + + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + + out_release_irq: + free_irq(pdev->irq, priv); + + out_disable_msi: + pci_disable_msi(pdev); + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + iwl_unset_hw_setting(priv); + + out_iounmap: + pci_iounmap(pdev, priv->hw_base); + out_pci_release_regions: + pci_release_regions(pdev); + out_pci_disable_device: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + out_ieee80211_free_hw: + ieee80211_free_hw(priv->hw); + out: + return err; +} + +static void iwl_pci_remove(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + struct list_head *p, *q; + int i; + + if (!priv) + return; + + IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); + + mutex_lock(&priv->mutex); + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + mutex_unlock(&priv->mutex); + + /* Free MAC hash list for ADHOC */ + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { + list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { + list_del(p); + kfree(list_entry(p, struct iwl_ibss_seq, list)); + } + } + + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + + iwl_dealloc_ucode_pci(priv); + + if (priv->rxq.bd) + iwl_rx_queue_free(priv, &priv->rxq); + iwl_hw_txq_ctx_free(priv); + + iwl_unset_hw_setting(priv); + iwl_clear_stations_table(priv); + + if (priv->mac80211_registered) { + ieee80211_unregister_hw(priv->hw); + iwl_rate_control_unregister(priv->hw); + } + + /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes + * priv->workqueue... so we can't take down the workqueue + * until now... */ + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + + free_irq(pdev->irq, priv); + pci_disable_msi(pdev); + pci_iounmap(pdev, priv->hw_base); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + kfree(priv->channel_info); + + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + ieee80211_free_hw(priv->hw); +} + +#ifdef CONFIG_PM + +static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + + mutex_lock(&priv->mutex); + + set_bit(STATUS_IN_SUSPEND, &priv->status); + + /* Take down the device; powers it off, etc. */ + __iwl_down(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_resume(struct iwl_priv *priv) +{ + unsigned long flags; + + /* The following it a temporary work around due to the + * suspend / resume not fully initializing the NIC correctly. + * Without all of the following, resume will not attempt to take + * down the NIC (it shouldn't really need to) and will just try + * and bring the NIC back up. However that fails during the + * ucode verification process. This then causes iwl_down to be + * called *after* iwl_hw_nic_init() has succeeded -- which + * then lets the next init sequence succeed. So, we've + * replicated all of that NIC init code here... */ + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + iwl_hw_nic_init(priv); + + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_restricted_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + iwl_hw_nic_reset(priv); + + /* Bring the device back up */ + clear_bit(STATUS_IN_SUSPEND, &priv->status); + queue_work(priv->workqueue, &priv->up); +} + +static int iwl_pci_resume(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + int err; + + printk(KERN_INFO "Coming out of suspend...\n"); + + mutex_lock(&priv->mutex); + + pci_set_power_state(pdev, PCI_D0); + err = pci_enable_device(pdev); + pci_restore_state(pdev); + + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries + * from interfering with C3 CPU state. pci_restore_state won't help + * here since it only restores the first 64 bytes pci config header. + */ + pci_write_config_byte(pdev, 0x41, 0x00); + + iwl_resume(priv); + mutex_unlock(&priv->mutex); + + return 0; +} + +#endif /* CONFIG_PM */ + +/***************************************************************************** + * + * driver and module entry point + * + *****************************************************************************/ + +static struct pci_driver iwl_driver = { + .name = DRV_NAME, + .id_table = iwl_hw_card_ids, + .probe = iwl_pci_probe, + .remove = __devexit_p(iwl_pci_remove), +#ifdef CONFIG_PM + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, +#endif +}; + +static int __init iwl_init(void) +{ + + int ret; + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + ret = pci_register_driver(&iwl_driver); + if (ret) { + IWL_ERROR("Unable to initialize PCI module\n"); + return ret; + } +#ifdef CONFIG_IWLWIFI_DEBUG + ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level); + if (ret) { + IWL_ERROR("Unable to create driver sysfs file\n"); + pci_unregister_driver(&iwl_driver); + return ret; + } +#endif + + return ret; +} + +static void __exit iwl_exit(void) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level); +#endif + pci_unregister_driver(&iwl_driver); +} + +module_param_named(antenna, iwl_param_antenna, int, 0444); +MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); +module_param_named(disable, iwl_param_disable, int, 0444); +MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); +module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444); +MODULE_PARM_DESC(hwcrypto, + "using hardware crypto engine (default 0 [software])\n"); +module_param_named(debug, iwl_param_debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); +module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444); +MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); + +module_param_named(queues_num, iwl_param_queues_num, int, 0444); +MODULE_PARM_DESC(queues_num, "number of hw queues."); + +/* QoS */ +module_param_named(qos_enable, iwl_param_qos_enable, int, 0444); +MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); + +module_exit(iwl_exit); +module_init(iwl_init); diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h new file mode 100644 index 000000000000..00c79e200c68 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwlwifi.h @@ -0,0 +1,713 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwlwifi_h__ +#define __iwlwifi_h__ + +#include /* for struct pci_device_id */ +#include +#include + +struct iwl_priv; + +/* Hardware specific file defines the PCI IDs table for that hardware module */ +extern struct pci_device_id iwl_hw_card_ids[]; + +#if IWL == 3945 + +#define DRV_NAME "iwl3945" +#include "iwl-hw.h" +#include "iwl-3945-hw.h" + +#elif IWL == 4965 + +#define DRV_NAME "iwl4965" +#include "iwl-hw.h" +#include "iwl-4965-hw.h" + +#endif + +#include "iwl-prph.h" + +/* + * Driver implementation data structures, constants, inline + * functions + * + * NOTE: DO NOT PUT HARDWARE/UCODE SPECIFIC DECLRATIONS HERE + * + * Hardware specific declrations go into iwl-*hw.h + * + */ + +#include "iwl-debug.h" + +/* Default noise level to report when noise measurement is not available. + * This may be because we're: + * 1) Not associated (4965, no beacon statistics being sent to driver) + * 2) Scanning (noise measurement does not apply to associated channel) + * 3) Receiving CCK (3945 delivers noise info only for OFDM frames) + * Use default noise value of -127 ... this is below the range of measurable + * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user. + * Also, -127 works better than 0 when averaging frames with/without + * noise info (e.g. averaging might be done in app); measured dBm values are + * always negative ... using a negative value as the default keeps all + * averages within an s8's (used in some apps) range of negative values. */ +#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) + +/* Module parameters accessible from iwl-*.c */ +extern int iwl_param_disable_hw_scan; +extern int iwl_param_debug; +extern int iwl_param_mode; +extern int iwl_param_disable; +extern int iwl_param_antenna; +extern int iwl_param_hwcrypto; +extern int iwl_param_qos_enable; +extern int iwl_param_queues_num; + +enum iwl_antenna { + IWL_ANTENNA_DIVERSITY, + IWL_ANTENNA_MAIN, + IWL_ANTENNA_AUX +}; + +/* + * RTS threshold here is total size [2347] minus 4 FCS bytes + * Per spec: + * a value of 0 means RTS on all data/management packets + * a value > max MSDU size means no RTS + * else RTS for data/management frames where MPDU is larger + * than RTS value. + */ +#define DEFAULT_RTS_THRESHOLD 2347U +#define MIN_RTS_THRESHOLD 0U +#define MAX_RTS_THRESHOLD 2347U +#define MAX_MSDU_SIZE 2304U +#define MAX_MPDU_SIZE 2346U +#define DEFAULT_BEACON_INTERVAL 100U +#define DEFAULT_SHORT_RETRY_LIMIT 7U +#define DEFAULT_LONG_RETRY_LIMIT 4U + +struct iwl_rx_mem_buffer { + dma_addr_t dma_addr; + struct sk_buff *skb; + struct list_head list; +}; + +struct iwl_rt_rx_hdr { + struct ieee80211_radiotap_header rt_hdr; + __le64 rt_tsf; /* TSF */ + u8 rt_flags; /* radiotap packet flags */ + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channelMHz; /* channel in MHz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ + s8 rt_dbmnoise; + u8 rt_antenna; /* antenna number */ + u8 payload[0]; /* payload... */ +} __attribute__ ((packed)); + +struct iwl_rt_tx_hdr { + struct ieee80211_radiotap_header rt_hdr; + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channel; /* channel in mHz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ + u8 rt_antenna; /* antenna number */ + u8 payload[0]; /* payload... */ +} __attribute__ ((packed)); + +/* + * Generic queue structure + * + * Contains common data for Rx and Tx queues + */ +struct iwl_queue { + int n_bd; /* number of BDs in this queue */ + int first_empty; /* 1-st empty entry (index) host_w*/ + int last_used; /* last used entry (index) host_r*/ + dma_addr_t dma_addr; /* physical addr for BD's */ + int n_window; /* safe queue window */ + u32 id; + int low_mark; /* low watermark, resume queue if free + * space more than this */ + int high_mark; /* high watermark, stop queue if free + * space less than this */ +} __attribute__ ((packed)); + +#define MAX_NUM_OF_TBS (20) + +struct iwl_tx_info { + struct ieee80211_tx_status status; + struct sk_buff *skb[MAX_NUM_OF_TBS]; +}; + +/** + * struct iwl_tx_queue - Tx Queue for DMA + * @need_update: need to update read/write index + * @shed_retry: queue is HT AGG enabled + * + * Queue consists of circular buffer of BD's and required locking structures. + */ +struct iwl_tx_queue { + struct iwl_queue q; + struct iwl_tfd_frame *bd; + struct iwl_cmd *cmd; + dma_addr_t dma_addr_cmd; + struct iwl_tx_info *txb; + int need_update; + int sched_retry; + int active; +}; + +#include "iwl-channel.h" + +#if IWL == 3945 +#include "iwl-3945-rs.h" +#else +#include "iwl-4965-rs.h" +#endif + +#define IWL_TX_FIFO_AC0 0 +#define IWL_TX_FIFO_AC1 1 +#define IWL_TX_FIFO_AC2 2 +#define IWL_TX_FIFO_AC3 3 +#define IWL_TX_FIFO_HCCA_1 5 +#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 + +/* Power management (not Tx power) structures */ + +struct iwl_power_vec_entry { + struct iwl_powertable_cmd cmd; + u8 no_dtim; +}; +#define IWL_POWER_RANGE_0 (0) +#define IWL_POWER_RANGE_1 (1) + +#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */ +#define IWL_POWER_INDEX_3 0x03 +#define IWL_POWER_INDEX_5 0x05 +#define IWL_POWER_AC 0x06 +#define IWL_POWER_BATTERY 0x07 +#define IWL_POWER_LIMIT 0x07 +#define IWL_POWER_MASK 0x0F +#define IWL_POWER_ENABLED 0x10 +#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK) + +struct iwl_power_mgr { + spinlock_t lock; + struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC]; + struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC]; + u8 active_index; + u32 dtim_val; +}; + +#define IEEE80211_DATA_LEN 2304 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) + +struct iwl_frame { + union { + struct ieee80211_hdr frame; + struct iwl_tx_beacon_cmd beacon; + u8 raw[IEEE80211_FRAME_LEN]; + u8 cmd[360]; + } u; + struct list_head list; +}; + +#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) +#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) +#define SEQ_TO_INDEX(x) (x & 0xff) +#define INDEX_TO_SEQ(x) (x & 0xff) +#define SEQ_HUGE_FRAME (0x4000) +#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) +#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) +#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) + +enum { + /* CMD_SIZE_NORMAL = 0, */ + CMD_SIZE_HUGE = (1 << 0), + /* CMD_SYNC = 0, */ + CMD_ASYNC = (1 << 1), + /* CMD_NO_SKB = 0, */ + 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; + +} __attribute__ ((packed)); + +struct iwl_cmd { + struct iwl_cmd_meta meta; + struct iwl_cmd_header hdr; + union { + struct iwl_addsta_cmd addsta; + struct iwl_led_cmd led; + u32 flags; + u8 val8; + u16 val16; + u32 val32; + struct iwl_bt_cmd bt; + struct iwl_rxon_time_cmd rxon_time; + struct iwl_powertable_cmd powertable; + struct iwl_qosparam_cmd qosparam; + struct iwl_tx_cmd tx; + struct iwl_tx_beacon_cmd tx_beacon; + struct iwl_rxon_assoc_cmd rxon_assoc; + u8 *indirect; + u8 payload[360]; + } __attribute__ ((packed)) cmd; +} __attribute__ ((packed)); + +struct iwl_host_cmd { + u8 id; + u16 len; + struct iwl_cmd_meta meta; + const void *data; +}; + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ + sizeof(struct iwl_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/** + * struct iwl_rx_queue - Rx queue + * @processed: Internal index to last handled Rx packet + * @read: Shared index to newest available Rx buffer + * @write: Shared index to oldest written Rx packet + * @free_count: Number of pre-allocated buffers in rx_free + * @rx_free: list of free SKBs for use + * @rx_used: List of Rx buffers with no SKB + * @need_update: flag to indicate we need to update read/write index + * + * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers + */ +struct iwl_rx_queue { + __le32 *bd; + dma_addr_t dma_addr; + struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + u32 processed; + u32 read; + u32 write; + u32 free_count; + struct list_head rx_free; + struct list_head rx_used; + int need_update; + spinlock_t lock; +}; + +#define IWL_SUPPORTED_RATES_IE_LEN 8 + +#define SCAN_INTERVAL 100 + +#define MAX_A_CHANNELS 252 +#define MIN_A_CHANNELS 7 + +#define MAX_B_CHANNELS 14 +#define MIN_B_CHANNELS 1 + +#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ +#define STATUS_INT_ENABLED 1 +#define STATUS_RF_KILL_HW 2 +#define STATUS_RF_KILL_SW 3 +#define STATUS_INIT 4 +#define STATUS_ALIVE 5 +#define STATUS_READY 6 +#define STATUS_TEMPERATURE 7 +#define STATUS_GEO_CONFIGURED 8 +#define STATUS_EXIT_PENDING 9 +#define STATUS_IN_SUSPEND 10 +#define STATUS_STATISTICS 11 +#define STATUS_SCANNING 12 +#define STATUS_SCAN_ABORTING 13 +#define STATUS_SCAN_HW 14 +#define STATUS_POWER_PMI 15 +#define STATUS_FW_ERROR 16 + +#define MAX_TID_COUNT 9 + +#define IWL_INVALID_RATE 0xFF +#define IWL_INVALID_VALUE -1 + +#if IWL == 4965 +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG +struct iwl_ht_agg { + u16 txq_id; + u16 frame_count; + u16 wait_for_ba; + u16 start_idx; + u32 bitmap0; + u32 bitmap1; + u32 rate_n_flags; +}; +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ +#endif + +struct iwl_tid_data { + u16 seq_number; +#if IWL == 4965 +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + struct iwl_ht_agg agg; +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ +#endif +}; + +struct iwl_hw_key { + ieee80211_key_alg alg; + int keylen; + u8 key[32]; +}; + +union iwl_ht_rate_supp { + u16 rates; + struct { + u8 siso_rate; + u8 mimo_rate; + }; +}; + +#ifdef CONFIG_IWLWIFI_HT +#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) +#define HT_IE_MAX_AMSDU_SIZE_4K (0) +#define CFG_HT_MPDU_DENSITY_2USEC (0x5) +#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC + +struct sta_ht_info { + u8 is_ht; + u16 rx_mimo_ps_mode; + u16 tx_mimo_ps_mode; + u16 control_channel; + u8 max_amsdu_size; + u8 ampdu_factor; + u8 mpdu_density; + u8 operating_mode; + u8 supported_chan_width; + u8 extension_chan_offset; + u8 is_green_field; + u8 sgf; + u8 supp_rates[16]; + u8 tx_chan_width; + u8 chan_width_cap; +}; +#endif /*CONFIG_IWLWIFI_HT */ + +#ifdef CONFIG_IWLWIFI_QOS + +union iwl_qos_capabity { + struct { + u8 edca_count:4; /* bit 0-3 */ + u8 q_ack:1; /* bit 4 */ + u8 queue_request:1; /* bit 5 */ + u8 txop_request:1; /* bit 6 */ + u8 reserved:1; /* bit 7 */ + } q_AP; + struct { + u8 acvo_APSD:1; /* bit 0 */ + u8 acvi_APSD:1; /* bit 1 */ + u8 ac_bk_APSD:1; /* bit 2 */ + u8 ac_be_APSD:1; /* bit 3 */ + u8 q_ack:1; /* bit 4 */ + u8 max_len:2; /* bit 5-6 */ + u8 more_data_ack:1; /* bit 7 */ + } q_STA; + u8 val; +}; + +/* QoS sturctures */ +struct iwl_qos_info { + int qos_enable; + int qos_active; + union iwl_qos_capabity qos_cap; + struct iwl_qosparam_cmd def_qos_parm; +}; +#endif /*CONFIG_IWLWIFI_QOS */ + +#define STA_PS_STATUS_WAKE 0 +#define STA_PS_STATUS_SLEEP 1 + +struct iwl_station_entry { + struct iwl_addsta_cmd sta; + struct iwl_tid_data tid[MAX_TID_COUNT]; +#if IWL == 3945 + union { + struct { + u8 rate; + u8 flags; + } s; + u16 rate_n_flags; + } current_rate; +#endif + u8 used; + u8 ps_status; + struct iwl_hw_key keyinfo; +}; + +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_image_desc { + void *v_addr; /* access by driver */ + dma_addr_t p_addr; /* access by card's busmaster DMA */ + u32 len; /* bytes */ +}; + +/* uCode file layout */ +struct iwl_ucode { + __le32 ver; /* major/minor/subminor */ + __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 */ +}; + +#define IWL_IBSS_MAC_HASH_SIZE 32 + +struct iwl_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num; + u16 frag_num; + unsigned long packet_time; + struct list_head list; +}; + +struct iwl_driver_hw_info { + u16 max_txq_num; + u16 ac_queue_count; + u32 rx_buffer_size; + u16 tx_cmd_len; + u16 max_rxq_size; + u16 max_rxq_log; + u32 cck_flag; + u8 max_stations; + u8 bcast_sta_id; + void *shared_virt; + dma_addr_t shared_phys; +}; + + +#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) +#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) +#define STA_FLG_MAX_AGG_SIZE_POS (19) +#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) +#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) +#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) +#define STA_FLG_AGG_MPDU_DENSITY_POS (23) +#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) +#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) +#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) + + +#include "iwl-priv.h" + +/* Requires full declaration of iwl_priv before including */ +#include "iwl-io.h" + +#define IWL_RX_HDR(x) ((struct iwl_rx_frame_hdr *)(\ + x->u.rx_frame.stats.payload + \ + x->u.rx_frame.stats.phy_count)) +#define IWL_RX_END(x) ((struct iwl_rx_frame_end *)(\ + IWL_RX_HDR(x)->payload + \ + le16_to_cpu(IWL_RX_HDR(x)->len))) +#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) +#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) + + +/****************************************************************************** + * + * Functions implemented in iwl-base.c which are forward declared here + * for use by iwl-*.c + * + *****************************************************************************/ +struct iwl_addsta_cmd; +extern int iwl_send_add_station(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags); +extern const char *iwl_get_tx_fail_reason(u32 status); +extern u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid, + int is_ap, u8 flags); +extern int iwl_is_network_packet(struct iwl_priv *priv, + struct ieee80211_hdr *header); +extern int iwl_power_init_handle(struct iwl_priv *priv); +extern int iwl_eeprom_init(struct iwl_priv *priv); +#ifdef CONFIG_IWLWIFI_DEBUG +extern void iwl_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, int group100); +#else +static inline void iwl_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, + int group100) {} +#endif +extern int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq); +extern void iwl_handle_data_packet_monitor(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags); +extern int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr + *header); +extern void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); +extern int iwl_rx_queue_alloc(struct iwl_priv *priv); +extern void iwl_rx_queue_reset(struct iwl_priv *priv, + struct iwl_rx_queue *rxq); +extern int iwl_calc_db_from_ratio(int sig_ratio); +extern int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm); +extern int iwl_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq, int count, u32 id); +extern int iwl_rx_queue_restock(struct iwl_priv *priv); +extern void iwl_rx_replenish(void *data); +extern void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq); +extern int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, + const void *data); +extern int __must_check iwl_send_cmd_async(struct iwl_priv *priv, + struct iwl_host_cmd *cmd); +extern int __must_check iwl_send_cmd_sync(struct iwl_priv *priv, + struct iwl_host_cmd *cmd); +extern int __must_check iwl_send_cmd(struct iwl_priv *priv, + struct iwl_host_cmd *cmd); +extern unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left); +extern int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_rx_queue *q); +extern int iwl_send_statistics_request(struct iwl_priv *priv); +extern void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, + u32 decrypt_res, + struct ieee80211_rx_status *stats); +extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); + +extern const u8 BROADCAST_ADDR[ETH_ALEN]; + +/* + * Currently used by iwl-3945-rs... look at restructuring so that it doesn't + * call this... todo... fix that. +*/ +extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id, + u16 tx_rate, u8 flags); + +static inline int iwl_is_associated(struct iwl_priv *priv) +{ + return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; +} + +/****************************************************************************** + * + * Functions implemented in iwl-[34]*.c which are forward declared here + * for use by iwl-base.c + * + * NOTE: The implementation of these functions are hardware specific + * which is why they are in the hardware specific files (vs. iwl-base.c) + * + * Naming convention -- + * iwl_ <-- Its part of iwlwifi (should be changed to iwl_) + * iwl_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) + * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) + * iwl_bg_ <-- Called from work queue context + * iwl_mac_ <-- mac80211 callback + * + ****************************************************************************/ +extern void iwl_hw_rx_handler_setup(struct iwl_priv *priv); +extern void iwl_hw_setup_deferred_work(struct iwl_priv *priv); +extern void iwl_hw_cancel_deferred_work(struct iwl_priv *priv); +extern int iwl_hw_rxq_stop(struct iwl_priv *priv); +extern int iwl_hw_set_hw_setting(struct iwl_priv *priv); +extern int iwl_hw_nic_init(struct iwl_priv *priv); +extern void iwl_hw_card_show_info(struct iwl_priv *priv); +extern int iwl_hw_nic_stop_master(struct iwl_priv *priv); +extern void iwl_hw_txq_ctx_free(struct iwl_priv *priv); +extern void iwl_hw_txq_ctx_stop(struct iwl_priv *priv); +extern int iwl_hw_nic_reset(struct iwl_priv *priv); +extern int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, + dma_addr_t addr, u16 len); +extern int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); +extern int iwl_hw_get_temperature(struct iwl_priv *priv); +extern int iwl_hw_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq); +extern unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl_frame *frame, u8 rate); +extern int iwl_hw_get_rx_read(struct iwl_priv *priv); +extern void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id); +extern int iwl_hw_reg_send_txpower(struct iwl_priv *priv); +extern int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); +extern void iwl_hw_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +extern void iwl_disable_events(struct iwl_priv *priv); +extern int iwl4965_get_temperature(const struct iwl_priv *priv); + +/** + * iwl_hw_find_station - Find station id for a given BSSID + * @bssid: MAC address of station ID to find + * + * NOTE: This should not be hardware specific but the code has + * not yet been merged into a single common layer for managing the + * station tables. + */ +extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *bssid); + +extern int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel); +extern int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); +#endif From 95ea36275f3c9a1d3d04c217b4b576c657c4e70e Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 17:57:13 -0700 Subject: [PATCH 1423/2804] [RT2x00]: add driver for Ralink wireless hardware Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- CREDITS | 31 + MAINTAINERS | 8 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/rt2x00/Kconfig | 130 + drivers/net/wireless/rt2x00/Makefile | 22 + drivers/net/wireless/rt2x00/rt2400pci.c | 1689 ++++++++++++ drivers/net/wireless/rt2x00/rt2400pci.h | 943 +++++++ drivers/net/wireless/rt2x00/rt2500pci.c | 2000 ++++++++++++++ drivers/net/wireless/rt2x00/rt2500pci.h | 1236 +++++++++ drivers/net/wireless/rt2x00/rt2500usb.c | 1837 ++++++++++++ drivers/net/wireless/rt2x00/rt2500usb.h | 798 ++++++ drivers/net/wireless/rt2x00/rt2x00.h | 807 ++++++ drivers/net/wireless/rt2x00/rt2x00config.c | 165 ++ drivers/net/wireless/rt2x00/rt2x00debug.c | 331 +++ drivers/net/wireless/rt2x00/rt2x00debug.h | 57 + drivers/net/wireless/rt2x00/rt2x00dev.c | 1133 ++++++++ drivers/net/wireless/rt2x00/rt2x00firmware.c | 124 + drivers/net/wireless/rt2x00/rt2x00lib.h | 125 + drivers/net/wireless/rt2x00/rt2x00mac.c | 459 +++ drivers/net/wireless/rt2x00/rt2x00pci.c | 481 ++++ drivers/net/wireless/rt2x00/rt2x00pci.h | 127 + drivers/net/wireless/rt2x00/rt2x00reg.h | 283 ++ drivers/net/wireless/rt2x00/rt2x00rfkill.c | 148 + drivers/net/wireless/rt2x00/rt2x00ring.h | 255 ++ drivers/net/wireless/rt2x00/rt2x00usb.c | 595 ++++ drivers/net/wireless/rt2x00/rt2x00usb.h | 180 ++ drivers/net/wireless/rt2x00/rt61pci.c | 2603 ++++++++++++++++++ drivers/net/wireless/rt2x00/rt61pci.h | 1457 ++++++++++ drivers/net/wireless/rt2x00/rt73usb.c | 2124 ++++++++++++++ drivers/net/wireless/rt2x00/rt73usb.h | 1024 +++++++ 31 files changed, 21174 insertions(+) create mode 100644 drivers/net/wireless/rt2x00/Kconfig create mode 100644 drivers/net/wireless/rt2x00/Makefile create mode 100644 drivers/net/wireless/rt2x00/rt2400pci.c create mode 100644 drivers/net/wireless/rt2x00/rt2400pci.h create mode 100644 drivers/net/wireless/rt2x00/rt2500pci.c create mode 100644 drivers/net/wireless/rt2x00/rt2500pci.h create mode 100644 drivers/net/wireless/rt2x00/rt2500usb.c create mode 100644 drivers/net/wireless/rt2x00/rt2500usb.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00config.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00debug.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00debug.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00dev.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00firmware.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00lib.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00mac.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00pci.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00pci.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00reg.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00rfkill.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00ring.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00usb.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00usb.h create mode 100644 drivers/net/wireless/rt2x00/rt61pci.c create mode 100644 drivers/net/wireless/rt2x00/rt61pci.h create mode 100644 drivers/net/wireless/rt2x00/rt73usb.c create mode 100644 drivers/net/wireless/rt2x00/rt73usb.h diff --git a/CREDITS b/CREDITS index 832436e1dd91..550bb2b9fe8b 100644 --- a/CREDITS +++ b/CREDITS @@ -665,6 +665,11 @@ D: Minor updates to SCSI types, added /proc/pid/maps protection S: (ask for current address) S: USA +N: Robin Cornelius +E: robincornelius@users.sourceforge.net +D: Ralink rt2x00 WLAN driver +S: Cornwall, U.K. + N: Mark Corner E: mcorner@umich.edu W: http://www.eecs.umich.edu/~mcorner/ @@ -679,6 +684,11 @@ D: Kernel module SMART utilities S: Santa Cruz, California S: USA +N: Luis Correia +E: lfcorreia@users.sf.net +D: Ralink rt2x00 WLAN driver +S: Belas, Portugal + N: Alan Cox W: http://www.linux.org.uk/diary/ D: Linux Networking (0.99.10->2.0.29) @@ -833,6 +843,12 @@ S: Lancs S: PR4 6AX S: United Kingdom +N: Ivo van Doorn +E: IvDoorn@gmail.com +W: http://www.mendiosus.nl +D: Ralink rt2x00 WLAN driver +S: Haarlem, The Netherlands + N: John G Dorsey E: john+@cs.cmu.edu D: ARM Linux ports to Assabet/Neponset, Spot @@ -3517,6 +3533,12 @@ S: Maastrichterweg 63 S: 5554 GG Valkenswaard S: The Netherlands +N: Mark Wallis +E: mwallis@serialmonkey.com +W: http://mark.serialmonkey.com +D: Ralink rt2x00 WLAN driver +S: Newcastle, Australia + N: Peter Shaobo Wang E: pwang@mmdcorp.com W: http://www.mmdcorp.com/pw/linux @@ -3651,6 +3673,15 @@ S: Alte Regensburger Str. 11a S: 93149 Nittenau S: Germany +N: Gertjan van Wingerde +E: gwingerde@home.nl +D: Ralink rt2x00 WLAN driver +D: Minix V2 file-system +D: Misc fixes +S: Geessinkweg 177 +S: 7544 TX Enschede +S: The Netherlands + N: Lars Wirzenius E: liw@iki.fi D: Linux System Administrator's Guide, author, former maintainer diff --git a/MAINTAINERS b/MAINTAINERS index 934afd3dfa40..6ae2b9975269 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3147,6 +3147,14 @@ M: corey@world.std.com L: linux-wireless@vger.kernel.org S: Maintained +RALINK RT2X00 WLAN DRIVER +P: rt2x00 project +L: linux-wireless@vger.kernel.org +L: rt2400-devel@lists.sourceforge.net +W: http://rt2x00.serialmonkey.com/ +S: Maintained +F: drivers/net/wireless/rt2x00/ + RANDOM NUMBER DRIVER P: Matt Mackall M: mpm@selenic.com diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 085ba132835f..f481c757e22b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -583,5 +583,6 @@ source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/b43legacy/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" +source "drivers/net/wireless/rt2x00/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 351024f2fe72..a7a15e3509e8 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_RTL8187) += rtl8187.o obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_IWLWIFI) += iwlwifi/ +obj-$(CONFIG_RT2X00) += rt2x00/ diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig new file mode 100644 index 000000000000..da05b1faf60d --- /dev/null +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -0,0 +1,130 @@ +config RT2X00 + tristate "Ralink driver support" + depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + ---help--- + This will enable the experimental support for the Ralink drivers, + developed in the rt2x00 project . + + These drivers will make use of the Devicescape ieee80211 stack. + + When building one of the individual drivers, the rt2x00 library + will also be created. That library (when the driver is built as + a module) will be called "rt2x00lib.ko". + +config RT2X00_LIB + tristate + depends on RT2X00 + +config RT2X00_LIB_PCI + tristate + depends on RT2X00 + select RT2X00_LIB + +config RT2X00_LIB_USB + tristate + depends on RT2X00 + select RT2X00_LIB + +config RT2X00_LIB_FIRMWARE + boolean + depends on RT2X00_LIB + select CRC_ITU_T + select FW_LOADER + +config RT2X00_LIB_RFKILL + boolean + depends on RT2X00_LIB + select RFKILL + select INPUT_POLLDEV + +config RT2400PCI + tristate "Ralink rt2400 pci/pcmcia support" + depends on RT2X00 && PCI + select RT2X00_LIB_PCI + select EEPROM_93CX6 + ---help--- + This is an experimental driver for the Ralink rt2400 wireless chip. + + When compiled as a module, this driver will be called "rt2400pci.ko". + +config RT2400PCI_RFKILL + bool "RT2400 rfkill support" + depends on RT2400PCI + select RT2X00_LIB_RFKILL + ---help--- + This adds support for integrated rt2400 devices that feature a + hardware button to control the radio state. + This feature depends on the RF switch subsystem rfkill. + +config RT2500PCI + tristate "Ralink rt2500 pci/pcmcia support" + depends on RT2X00 && PCI + select RT2X00_LIB_PCI + select EEPROM_93CX6 + ---help--- + This is an experimental driver for the Ralink rt2500 wireless chip. + + When compiled as a module, this driver will be called "rt2500pci.ko". + +config RT2500PCI_RFKILL + bool "RT2500 rfkill support" + depends on RT2500PCI + select RT2X00_LIB_RFKILL + ---help--- + This adds support for integrated rt2500 devices that feature a + hardware button to control the radio state. + This feature depends on the RF switch subsystem rfkill. + +config RT61PCI + tristate "Ralink rt61 pci/pcmcia support" + depends on RT2X00 && PCI + select RT2X00_LIB_PCI + select RT2X00_LIB_FIRMWARE + select EEPROM_93CX6 + ---help--- + This is an experimental driver for the Ralink rt61 wireless chip. + + When compiled as a module, this driver will be called "rt61pci.ko". + +config RT61PCI_RFKILL + bool "RT61 rfkill support" + depends on RT61PCI + select RT2X00_LIB_RFKILL + ---help--- + This adds support for integrated rt61 devices that feature a + hardware button to control the radio state. + This feature depends on the RF switch subsystem rfkill. + +config RT2500USB + tristate "Ralink rt2500 usb support" + depends on RT2X00 && USB + select RT2X00_LIB_USB + ---help--- + This is an experimental driver for the Ralink rt2500 wireless chip. + + When compiled as a module, this driver will be called "rt2500usb.ko". + +config RT73USB + tristate "Ralink rt73 usb support" + depends on RT2X00 && USB + select RT2X00_LIB_USB + select RT2X00_LIB_FIRMWARE + ---help--- + This is an experimental driver for the Ralink rt73 wireless chip. + + When compiled as a module, this driver will be called "rt73usb.ko". + +config RT2X00_LIB_DEBUGFS + bool "Ralink debugfs support" + depends on RT2X00_LIB && MAC80211_DEBUGFS + ---help--- + Enable creation of debugfs files for the rt2x00 drivers. + These debugfs files support both reading and writing of the + most important register types of the rt2x00 devices. + +config RT2X00_DEBUG + bool "Ralink debug output" + depends on RT2X00_LIB + ---help--- + Enable debugging output for all rt2x00 modules + diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile new file mode 100644 index 000000000000..30d654a42eea --- /dev/null +++ b/drivers/net/wireless/rt2x00/Makefile @@ -0,0 +1,22 @@ +rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o + +ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y) + rt2x00lib-objs += rt2x00debug.o +endif + +ifeq ($(CONFIG_RT2X00_LIB_RFKILL),y) + rt2x00lib-objs += rt2x00rfkill.o +endif + +ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y) + rt2x00lib-objs += rt2x00firmware.o +endif + +obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o +obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o +obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o +obj-$(CONFIG_RT2400PCI) += rt2400pci.o +obj-$(CONFIG_RT2500PCI) += rt2500pci.o +obj-$(CONFIG_RT61PCI) += rt61pci.o +obj-$(CONFIG_RT2500USB) += rt2500usb.o +obj-$(CONFIG_RT73USB) += rt73usb.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c new file mode 100644 index 000000000000..38e2188937c5 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -0,0 +1,1689 @@ +/* + Copyright (C) 2004 - 2007 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: rt2400pci + Abstract: rt2400pci device specific routines. + Supported chipsets: RT2460. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2400pci" + +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" +#include "rt2400pci.h" + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt2x00pci_register_read and rt2x00pci_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); + if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2400pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); +} + +static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2400pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2400pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + *value = 0xff; + return; + } + + *value = rt2x00_get_field32(reg, BBPCSR_VALUE); +} + +static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, RFCSR, ®); + if (!rt2x00_get_field32(reg, RFCSR_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR21, ®); + + eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); + eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); + eeprom->reg_data_clock = + !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK); + eeprom->reg_chip_select = + !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT); +} + +static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg = 0; + + rt2x00_set_field32(®, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in); + rt2x00_set_field32(®, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out); + rt2x00_set_field32(®, CSR21_EEPROM_DATA_CLOCK, + !!eeprom->reg_data_clock); + rt2x00_set_field32(®, CSR21_EEPROM_CHIP_SELECT, + !!eeprom->reg_chip_select); + + rt2x00pci_register_write(rt2x00dev, CSR21, reg); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) + +static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); +} + +static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt2400pci_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2400pci_read_csr, + .write = rt2400pci_write_csr, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2400pci_bbp_read, + .write = rt2400pci_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2400pci_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +#ifdef CONFIG_RT2400PCI_RFKILL +static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); + return rt2x00_get_field32(reg, GPIOCSR_BIT0); +} +#endif /* CONFIG_RT2400PCI_RFKILL */ + +/* + * Configuration handlers. + */ +static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, ®, sizeof(reg)); +} + +static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); +} + +static void rt2400pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + u32 reg; + + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + +static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) +{ + u32 reg; + + rt2x00pci_register_write(rt2x00dev, CSR14, 0); + + /* + * Apply hardware packet filter. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); + else + rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); + } + + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); + + /* + * Enable beacon config + */ + rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); + rt2x00_set_field32(®, BCNCSR1_PRELOAD, + PREAMBLE + get_duration(IEEE80211_HEADER, 2)); + rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); + } + + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); + + rt2x00pci_register_write(rt2x00dev, CSR14, reg); +} + +static void rt2400pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u32 reg; + u32 preamble; + u16 value; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + rt2x00pci_register_write(rt2x00dev, ARCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, value); + value = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, value); + rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); + + preamble = DEVICE_GET_RATE_FIELD(rate, PREAMBLE) ? 0x08 : 0x00; + + rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); + rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble); + rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); + rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble); + rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); + rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble); + rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); + rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble); + rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); +} + +static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + rt2x00dev->curr_hwmode = HWMODE_B; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt2400pci_config_rate(rt2x00dev, rate->val2); +} + +static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel) +{ + struct rf_channel reg; + + /* + * Fill rf_reg structure. + */ + memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); + + /* + * Switch on tuning bits. + */ + rt2x00_set_field32(®.rf1, RF1_TUNER, 1); + rt2x00_set_field32(®.rf3, RF3_TUNER, 1); + + rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 2, reg.rf2); + rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + + /* + * RF2420 chipset don't need any additional actions. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2420)) + return; + + /* + * For the RT2421 chipsets we need to write an invalid + * reference clock rate to activate auto_tune. + * After that we set the value back to the correct channel. + */ + rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 2, 0x000c2a32); + rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + + msleep(1); + + rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 2, reg.rf2); + rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + + msleep(1); + + /* + * Switch off tuning bits. + */ + rt2x00_set_field32(®.rf1, RF1_TUNER, 0); + rt2x00_set_field32(®.rf3, RF3_TUNER, 0); + + rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + + /* + * Clear false CRC during channel switch. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®.rf1); +} + +static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) +{ + rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower)); +} + +static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, + int antenna_tx, int antenna_rx) +{ + u8 r1; + u8 r4; + + rt2400pci_bbp_read(rt2x00dev, 4, &r4); + rt2400pci_bbp_read(rt2x00dev, 1, &r1); + + /* + * Configure the TX antenna. + */ + switch (antenna_tx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + } + + rt2400pci_bbp_write(rt2x00dev, 4, r4); + rt2400pci_bbp_write(rt2x00dev, 1, r1); +} + +static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, + int short_slot_time, int beacon_int) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, SIFS); + rt2x00_set_field32(®, CSR18_PIFS, + short_slot_time ? SHORT_PIFS : PIFS); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, + short_slot_time ? SHORT_DIFS : DIFS); + rt2x00_set_field32(®, CSR19_EIFS, EIFS); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); + rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, CSR12, ®); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, CSR12, reg); +} + +static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt2400pci_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt2400pci_config_channel(rt2x00dev, conf->channel_val, + conf->channel); + if (flags & CONFIG_UPDATE_TXPOWER) + rt2400pci_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt2400pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2400pci_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev, + struct ieee80211_tx_queue_params *params) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_CWMIN, params->cw_min); + rt2x00_set_field32(®, CSR11_CWMAX, params->cw_max); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); +} + +/* + * LED functions. + */ +static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); + + rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); + rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); + + if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { + rt2x00_set_field32(®, LEDCSR_LINK, 1); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); + } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { + rt2x00_set_field32(®, LEDCSR_LINK, 0); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); + } else { + rt2x00_set_field32(®, LEDCSR_LINK, 1); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); + } + + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); +} + +static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); + rt2x00_set_field32(®, LEDCSR_LINK, 0); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); +} + +/* + * Link tuning + */ +static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u8 bbp; + + /* + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2400pci_bbp_read(rt2x00dev, 39, &bbp); + rt2x00dev->link.false_cca = bbp; +} + +static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2400pci_bbp_write(rt2x00dev, 13, 0x08); + rt2x00dev->link.vgc_level = 0x08; +} + +static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + u8 reg; + + /* + * The link tuner should not run longer then 60 seconds, + * and should run once every 2 seconds. + */ + if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count & 1)) + return; + + /* + * Base r13 link tuning on the false cca count. + */ + rt2400pci_bbp_read(rt2x00dev, 13, ®); + + if (rt2x00dev->link.false_cca > 512 && reg < 0x20) { + rt2400pci_bbp_write(rt2x00dev, 13, ++reg); + rt2x00dev->link.vgc_level = reg; + } else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) { + rt2400pci_bbp_write(rt2x00dev, 13, --reg); + rt2x00dev->link.vgc_level = reg; + } +} + +/* + * Initialization functions. + */ +static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + struct data_desc *rxd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + rxd = ring->entry[i].priv; + + rt2x00_desc_read(rxd, 2, &word); + rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, + ring->data_size); + rt2x00_desc_write(rxd, 2, word); + + rt2x00_desc_read(rxd, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(rxd, 1, word); + + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); + } + + rt2x00_ring_index_clear(rt2x00dev->rx); +} + +static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_desc *txd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + txd = ring->entry[i].priv; + + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, + ring->data_size); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); + } + + rt2x00_ring_index_clear(ring); +} + +static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Initialize rings. + */ + rt2400pci_init_rxring(rt2x00dev); + rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + /* + * Initialize registers. + */ + rt2x00pci_register_read(rt2x00dev, TXCSR2, ®); + rt2x00_set_field32(®, TXCSR2_TXD_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size); + rt2x00_set_field32(®, TXCSR2_NUM_TXD, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); + rt2x00_set_field32(®, TXCSR2_NUM_ATIM, + rt2x00dev->bcn[1].stats.limit); + rt2x00_set_field32(®, TXCSR2_NUM_PRIO, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); + rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); + rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); + rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, + rt2x00dev->bcn[1].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); + rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, + rt2x00dev->bcn[0].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); + rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); + rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit); + rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + rt2x00dev->rx->data_dma); + rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); + + return 0; +} + +static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002); + rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002); + rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00023f20); + rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002); + + rt2x00pci_register_read(rt2x00dev, TIMECSR, ®); + rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); + rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); + rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); + rt2x00pci_register_write(rt2x00dev, TIMECSR, reg); + + rt2x00pci_register_read(rt2x00dev, CSR9, ®); + rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, + (rt2x00dev->rx->data_size / 128)); + rt2x00pci_register_write(rt2x00dev, CSR9, reg); + + rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000); + + rt2x00pci_register_read(rt2x00dev, ARCSR0, ®); + rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA0, 133); + rt2x00_set_field32(®, ARCSR0_AR_BBP_ID0, 134); + rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA1, 136); + rt2x00_set_field32(®, ARCSR0_AR_BBP_ID1, 135); + rt2x00pci_register_write(rt2x00dev, ARCSR0, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR3, ®); + rt2x00_set_field32(®, RXCSR3_BBP_ID0, 3); /* Tx power.*/ + rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID1, 32); /* Signal */ + rt2x00_set_field32(®, RXCSR3_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID2, 36); /* Rssi */ + rt2x00_set_field32(®, RXCSR3_BBP_ID2_VALID, 1); + rt2x00pci_register_write(rt2x00dev, RXCSR3, reg); + + rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00217223); + rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518); + + rt2x00pci_register_read(rt2x00dev, MACCSR2, ®); + rt2x00_set_field32(®, MACCSR2_DELAY, 64); + rt2x00pci_register_write(rt2x00dev, MACCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, RALINKCSR, ®); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 154); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA1, 0); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID1, 154); + rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg); + + rt2x00pci_register_read(rt2x00dev, CSR1, ®); + rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, CSR1_BBP_RESET, 0); + rt2x00_set_field32(®, CSR1_HOST_READY, 0); + rt2x00pci_register_write(rt2x00dev, CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, CSR1, ®); + rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, CSR1_HOST_READY, 1); + rt2x00pci_register_write(rt2x00dev, CSR1, reg); + + /* + * We must clear the FCS and FIFO error count. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); + rt2x00pci_register_read(rt2x00dev, CNT4, ®); + + return 0; +} + +static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2400pci_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt2400pci_bbp_write(rt2x00dev, 1, 0x00); + rt2400pci_bbp_write(rt2x00dev, 3, 0x27); + rt2400pci_bbp_write(rt2x00dev, 4, 0x08); + rt2400pci_bbp_write(rt2x00dev, 10, 0x0f); + rt2400pci_bbp_write(rt2x00dev, 15, 0x72); + rt2400pci_bbp_write(rt2x00dev, 16, 0x74); + rt2400pci_bbp_write(rt2x00dev, 17, 0x20); + rt2400pci_bbp_write(rt2x00dev, 18, 0x72); + rt2400pci_bbp_write(rt2x00dev, 19, 0x0b); + rt2400pci_bbp_write(rt2x00dev, 20, 0x00); + rt2400pci_bbp_write(rt2x00dev, 28, 0x11); + rt2400pci_bbp_write(rt2x00dev, 29, 0x04); + rt2400pci_bbp_write(rt2x00dev, 30, 0x21); + rt2400pci_bbp_write(rt2x00dev, 31, 0x00); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt2400pci_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + +static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int mask = (state == STATE_RADIO_IRQ_OFF); + u32 reg; + + /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (state == STATE_RADIO_IRQ_ON) { + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); + rt2x00_set_field32(®, CSR8_RXDONE, mask); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); +} + +static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Initialize all registers. + */ + if (rt2400pci_init_rings(rt2x00dev) || + rt2400pci_init_registers(rt2x00dev) || + rt2400pci_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + /* + * Enable interrupts. + */ + rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); + + /* + * Enable LED + */ + rt2400pci_enable_led(rt2x00dev); + + return 0; +} + +static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Disable LED + */ + rt2400pci_disable_led(rt2x00dev); + + rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0); + + /* + * Disable synchronisation. + */ + rt2x00pci_register_write(rt2x00dev, CSR14, 0); + + /* + * Cancel RX and TX. + */ + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); + rt2x00_set_field32(®, TXCSR0_ABORT, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); + + /* + * Disable interrupts. + */ + rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); +} + +static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + unsigned int i; + char put_to_sleep; + char bbp_state; + char rf_state; + + put_to_sleep = (state != STATE_AWAKE); + + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); + rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); + rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); + rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); + rt2x00_set_field32(®, PWRCSR1_PUT_TO_SLEEP, put_to_sleep); + rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); + bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); + rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); + if (bbp_state == state && rf_state == state) + return 0; + msleep(10); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state: bbp %d and rf %d.\n", + state, bbp_state, rf_state); + + return -EBUSY; +} + +static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt2400pci_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt2400pci_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt2400pci_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2400pci_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + u32 signal = 0; + u32 service = 0; + u32 length_high = 0; + u32 length_low = 0; + + /* + * The PLCP values should be treated as if they + * were BBP values. + */ + rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal); + rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5); + rt2x00_set_field32(&signal, BBPCSR_BUSY, 1); + + rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service); + rt2x00_set_field32(&service, BBPCSR_REGNUM, 6); + rt2x00_set_field32(&service, BBPCSR_BUSY, 1); + + rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high); + rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7); + rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1); + + rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low); + rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8); + rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1); + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 3, &word); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service); + rt2x00_desc_write(txd, 3, word); + + rt2x00_desc_read(txd, 4, &word); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high); + rt2x00_desc_write(txd, 4, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); + rt2x00_set_field32(&word, TXD_W0_VALID, 1); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_RTS, + test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, + !!(control->flags & + IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u32 reg; + + if (queue == IEEE80211_TX_QUEUE_BEACON) { + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { + rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + } + return; + } + + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); + if (queue == IEEE80211_TX_QUEUE_DATA0) + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA1) + rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); + else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); +} + +/* + * RX control handlers + */ +static int rt2400pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct data_desc *rxd = entry->priv; + u32 word0; + u32 word2; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 2, &word2); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = 0; + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + return 0; +} + +/* + * Interrupt functions. + */ +static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_entry *entry; + struct data_desc *txd; + u32 word; + int tx_status; + int retry; + + while (!rt2x00_ring_empty(ring)) { + entry = rt2x00_get_data_entry_done(ring); + txd = entry->priv; + rt2x00_desc_read(txd, 0, &word); + + if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + !rt2x00_get_field32(word, TXD_W0_VALID)) + break; + + /* + * Obtain the status about this packet. + */ + tx_status = rt2x00_get_field32(word, TXD_W0_RESULT); + retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); + + rt2x00lib_txdone(entry, tx_status, retry); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_desc_write(txd, 0, word); + rt2x00_ring_index_done_inc(ring); + } + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + entry = ring->entry; + if (!rt2x00_ring_full(ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); +} + +static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) +{ + struct rt2x00_dev *rt2x00dev = dev_instance; + u32 reg; + + /* + * Get the interrupt sources & saved to local variable. + * Write register value back to clear pending interrupts. + */ + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + + if (!reg) + return IRQ_NONE; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* + * Handle interrupts, walk through all bits + * and run the tasks, the bits are checked in order of + * priority. + */ + + /* + * 1 - Beacon timer expired interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) + rt2x00lib_beacondone(rt2x00dev); + + /* + * 2 - Rx ring done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_RXDONE)) + rt2x00pci_rxdone(rt2x00dev); + + /* + * 3 - Atim ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) + rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + + /* + * 4 - Priority ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) + rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + + /* + * 5 - Tx ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) + rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + + return IRQ_HANDLED; +} + +/* + * Device probe functions. + */ +static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + struct eeprom_93cx6 eeprom; + u32 reg; + u16 word; + u8 *mac; + + rt2x00pci_register_read(rt2x00dev, CSR21, ®); + + eeprom.data = rt2x00dev; + eeprom.register_read = rt2400pci_eepromregister_read; + eeprom.register_write = rt2400pci_eepromregister_write; + eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ? + PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; + eeprom.reg_data_in = 0; + eeprom.reg_data_out = 0; + eeprom.reg_data_clock = 0; + eeprom.reg_chip_select = 0; + + eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, + EEPROM_SIZE / sizeof(u16)); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + ERROR(rt2x00dev, "Invalid EEPROM data detected.\n"); + return -EINVAL; + } + + return 0; +} + +static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00pci_register_read(rt2x00dev, CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2460, value, reg); + + if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && + !rt2x00_rf(&rt2x00dev->chip, RF2421)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Store led mode, for correct led behaviour. + */ + rt2x00dev->led_mode = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) + __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + + /* + * Check if the BBP tuning should be enabled. + */ + if (!rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING)) + __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); + + return 0; +} + +/* + * RF value list for RF2420 & RF2421 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg[] = { + { 1, 0x00022058, 0x000c1fda, 0x00000101, 0 }, + { 2, 0x00022058, 0x000c1fee, 0x00000101, 0 }, + { 3, 0x00022058, 0x000c2002, 0x00000101, 0 }, + { 4, 0x00022058, 0x000c2016, 0x00000101, 0 }, + { 5, 0x00022058, 0x000c202a, 0x00000101, 0 }, + { 6, 0x00022058, 0x000c203e, 0x00000101, 0 }, + { 7, 0x00022058, 0x000c2052, 0x00000101, 0 }, + { 8, 0x00022058, 0x000c2066, 0x00000101, 0 }, + { 9, 0x00022058, 0x000c207a, 0x00000101, 0 }, + { 10, 0x00022058, 0x000c208e, 0x00000101, 0 }, + { 11, 0x00022058, 0x000c20a2, 0x00000101, 0 }, + { 12, 0x00022058, 0x000c20b6, 0x00000101, 0 }, + { 13, 0x00022058, 0x000c20ca, 0x00000101, 0 }, + { 14, 0x00022058, 0x000c20fa, 0x00000101, 0 }, +}; + +static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = 0; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 2; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 1; + spec->num_rates = 4; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + spec->num_channels = ARRAY_SIZE(rf_vals_bg); + spec->channels = rf_vals_bg; +} + +static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2400pci_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2400pci_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt2400pci_probe_hw_mode(rt2x00dev); + + /* + * This device requires the beacon ring + */ + __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry, u32 long_retry) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + return 0; +} + +static int rt2400pci_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * We don't support variating cw_min and cw_max variables + * per queue. So by default we only configure the TX queue, + * and ignore all other configurations. + */ + if (queue != IEEE80211_TX_QUEUE_DATA0) + return -EINVAL; + + if (rt2x00mac_conf_tx(hw, queue, params)) + return -EINVAL; + + /* + * Write configuration to register. + */ + rt2400pci_config_cw(rt2x00dev, &rt2x00dev->tx->tx_params); + + return 0; +} + +static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR17, ®); + tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; + rt2x00pci_register_read(rt2x00dev, CSR16, ®); + tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); + + return tsf; +} + +static void rt2400pci_reset_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00pci_register_write(rt2x00dev, CSR16, 0); + rt2x00pci_register_write(rt2x00dev, CSR17, 0); +} + +static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR15, ®); + return rt2x00_get_field32(reg, CSR15_BEACON_SENT); +} + +static const struct ieee80211_ops rt2400pci_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .set_retry_limit = rt2400pci_set_retry_limit, + .conf_tx = rt2400pci_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt2400pci_get_tsf, + .reset_tsf = rt2400pci_reset_tsf, + .beacon_update = rt2x00pci_beacon_update, + .tx_last_beacon = rt2400pci_tx_last_beacon, +}; + +static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { + .irq_handler = rt2400pci_interrupt, + .probe_hw = rt2400pci_probe_hw, + .initialize = rt2x00pci_initialize, + .uninitialize = rt2x00pci_uninitialize, + .set_device_state = rt2400pci_set_device_state, +#ifdef CONFIG_RT2400PCI_RFKILL + .rfkill_poll = rt2400pci_rfkill_poll, +#endif /* CONFIG_RT2400PCI_RFKILL */ + .link_stats = rt2400pci_link_stats, + .reset_tuner = rt2400pci_reset_tuner, + .link_tuner = rt2400pci_link_tuner, + .write_tx_desc = rt2400pci_write_tx_desc, + .write_tx_data = rt2x00pci_write_tx_data, + .kick_tx_queue = rt2400pci_kick_tx_queue, + .fill_rxdone = rt2400pci_fill_rxdone, + .config_mac_addr = rt2400pci_config_mac_addr, + .config_bssid = rt2400pci_config_bssid, + .config_packet_filter = rt2400pci_config_packet_filter, + .config_type = rt2400pci_config_type, + .config = rt2400pci_config, +}; + +static const struct rt2x00_ops rt2400pci_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt2400pci_rt2x00_ops, + .hw = &rt2400pci_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2400pci_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * RT2400pci module information. + */ +static struct pci_device_id rt2400pci_device_table[] = { + { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards"); +MODULE_DEVICE_TABLE(pci, rt2400pci_device_table); +MODULE_LICENSE("GPL"); + +static struct pci_driver rt2400pci_driver = { + .name = DRV_NAME, + .id_table = rt2400pci_device_table, + .probe = rt2x00pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +}; + +static int __init rt2400pci_init(void) +{ + return pci_register_driver(&rt2400pci_driver); +} + +static void __exit rt2400pci_exit(void) +{ + pci_unregister_driver(&rt2400pci_driver); +} + +module_init(rt2400pci_init); +module_exit(rt2400pci_exit); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h new file mode 100644 index 000000000000..ae22501f085d --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -0,0 +1,943 @@ +/* + Copyright (C) 2004 - 2007 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: rt2400pci + Abstract: Data structures and registers for the rt2400pci module. + Supported chipsets: RT2460. + */ + +#ifndef RT2400PCI_H +#define RT2400PCI_H + +/* + * RF chip defines. + */ +#define RF2420 0x0000 +#define RF2421 0x0001 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 100 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x0000 +#define CSR_REG_SIZE 0x014c +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0100 +#define BBP_SIZE 0x0020 +#define RF_SIZE 0x0010 + +/* + * Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * CSR0: ASIC revision number. + */ +#define CSR0 0x0000 + +/* + * CSR1: System control register. + * SOFT_RESET: Software reset, 1: reset, 0: normal. + * BBP_RESET: Hardware reset, 1: reset, 0, release. + * HOST_READY: Host ready after initialization. + */ +#define CSR1 0x0004 +#define CSR1_SOFT_RESET FIELD32(0x00000001) +#define CSR1_BBP_RESET FIELD32(0x00000002) +#define CSR1_HOST_READY FIELD32(0x00000004) + +/* + * CSR2: System admin status register (invalid). + */ +#define CSR2 0x0008 + +/* + * CSR3: STA MAC address register 0. + */ +#define CSR3 0x000c +#define CSR3_BYTE0 FIELD32(0x000000ff) +#define CSR3_BYTE1 FIELD32(0x0000ff00) +#define CSR3_BYTE2 FIELD32(0x00ff0000) +#define CSR3_BYTE3 FIELD32(0xff000000) + +/* + * CSR4: STA MAC address register 1. + */ +#define CSR4 0x0010 +#define CSR4_BYTE4 FIELD32(0x000000ff) +#define CSR4_BYTE5 FIELD32(0x0000ff00) + +/* + * CSR5: BSSID register 0. + */ +#define CSR5 0x0014 +#define CSR5_BYTE0 FIELD32(0x000000ff) +#define CSR5_BYTE1 FIELD32(0x0000ff00) +#define CSR5_BYTE2 FIELD32(0x00ff0000) +#define CSR5_BYTE3 FIELD32(0xff000000) + +/* + * CSR6: BSSID register 1. + */ +#define CSR6 0x0018 +#define CSR6_BYTE4 FIELD32(0x000000ff) +#define CSR6_BYTE5 FIELD32(0x0000ff00) + +/* + * CSR7: Interrupt source register. + * Write 1 to clear interrupt. + * TBCN_EXPIRE: Beacon timer expired interrupt. + * TWAKE_EXPIRE: Wakeup timer expired interrupt. + * TATIMW_EXPIRE: Timer of atim window expired interrupt. + * TXDONE_TXRING: Tx ring transmit done interrupt. + * TXDONE_ATIMRING: Atim ring transmit done interrupt. + * TXDONE_PRIORING: Priority ring transmit done interrupt. + * RXDONE: Receive done interrupt. + */ +#define CSR7 0x001c +#define CSR7_TBCN_EXPIRE FIELD32(0x00000001) +#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002) +#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004) +#define CSR7_TXDONE_TXRING FIELD32(0x00000008) +#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010) +#define CSR7_TXDONE_PRIORING FIELD32(0x00000020) +#define CSR7_RXDONE FIELD32(0x00000040) + +/* + * CSR8: Interrupt mask register. + * Write 1 to mask interrupt. + * TBCN_EXPIRE: Beacon timer expired interrupt. + * TWAKE_EXPIRE: Wakeup timer expired interrupt. + * TATIMW_EXPIRE: Timer of atim window expired interrupt. + * TXDONE_TXRING: Tx ring transmit done interrupt. + * TXDONE_ATIMRING: Atim ring transmit done interrupt. + * TXDONE_PRIORING: Priority ring transmit done interrupt. + * RXDONE: Receive done interrupt. + */ +#define CSR8 0x0020 +#define CSR8_TBCN_EXPIRE FIELD32(0x00000001) +#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002) +#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004) +#define CSR8_TXDONE_TXRING FIELD32(0x00000008) +#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010) +#define CSR8_TXDONE_PRIORING FIELD32(0x00000020) +#define CSR8_RXDONE FIELD32(0x00000040) + +/* + * CSR9: Maximum frame length register. + * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12. + */ +#define CSR9 0x0024 +#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80) + +/* + * CSR11: Back-off control register. + * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1). + * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1). + * SLOT_TIME: Slot time, default is 20us for 802.11b. + * LONG_RETRY: Long retry count. + * SHORT_RETRY: Short retry count. + */ +#define CSR11 0x002c +#define CSR11_CWMIN FIELD32(0x0000000f) +#define CSR11_CWMAX FIELD32(0x000000f0) +#define CSR11_SLOT_TIME FIELD32(0x00001f00) +#define CSR11_LONG_RETRY FIELD32(0x00ff0000) +#define CSR11_SHORT_RETRY FIELD32(0xff000000) + +/* + * CSR12: Synchronization configuration register 0. + * All units in 1/16 TU. + * BEACON_INTERVAL: Beacon interval, default is 100 TU. + * CFPMAX_DURATION: Cfp maximum duration, default is 100 TU. + */ +#define CSR12 0x0030 +#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff) +#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000) + +/* + * CSR13: Synchronization configuration register 1. + * All units in 1/16 TU. + * ATIMW_DURATION: Atim window duration. + * CFP_PERIOD: Cfp period, default is 0 TU. + */ +#define CSR13 0x0034 +#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff) +#define CSR13_CFP_PERIOD FIELD32(0x00ff0000) + +/* + * CSR14: Synchronization control register. + * TSF_COUNT: Enable tsf auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * TBCN: Enable tbcn with reload value. + * TCFP: Enable tcfp & cfp / cp switching. + * TATIMW: Enable tatimw & atim window switching. + * BEACON_GEN: Enable beacon generator. + * CFP_COUNT_PRELOAD: Cfp count preload value. + * TBCM_PRELOAD: Tbcn preload value in units of 64us. + */ +#define CSR14 0x0038 +#define CSR14_TSF_COUNT FIELD32(0x00000001) +#define CSR14_TSF_SYNC FIELD32(0x00000006) +#define CSR14_TBCN FIELD32(0x00000008) +#define CSR14_TCFP FIELD32(0x00000010) +#define CSR14_TATIMW FIELD32(0x00000020) +#define CSR14_BEACON_GEN FIELD32(0x00000040) +#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00) +#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000) + +/* + * CSR15: Synchronization status register. + * CFP: ASIC is in contention-free period. + * ATIMW: ASIC is in ATIM window. + * BEACON_SENT: Beacon is send. + */ +#define CSR15 0x003c +#define CSR15_CFP FIELD32(0x00000001) +#define CSR15_ATIMW FIELD32(0x00000002) +#define CSR15_BEACON_SENT FIELD32(0x00000004) + +/* + * CSR16: TSF timer register 0. + */ +#define CSR16 0x0040 +#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff) + +/* + * CSR17: TSF timer register 1. + */ +#define CSR17 0x0044 +#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff) + +/* + * CSR18: IFS timer register 0. + * SIFS: Sifs, default is 10 us. + * PIFS: Pifs, default is 30 us. + */ +#define CSR18 0x0048 +#define CSR18_SIFS FIELD32(0x0000ffff) +#define CSR18_PIFS FIELD32(0xffff0000) + +/* + * CSR19: IFS timer register 1. + * DIFS: Difs, default is 50 us. + * EIFS: Eifs, default is 364 us. + */ +#define CSR19 0x004c +#define CSR19_DIFS FIELD32(0x0000ffff) +#define CSR19_EIFS FIELD32(0xffff0000) + +/* + * CSR20: Wakeup timer register. + * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU. + * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup. + * AUTOWAKE: Enable auto wakeup / sleep mechanism. + */ +#define CSR20 0x0050 +#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff) +#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000) +#define CSR20_AUTOWAKE FIELD32(0x01000000) + +/* + * CSR21: EEPROM control register. + * RELOAD: Write 1 to reload eeprom content. + * TYPE_93C46: 1: 93c46, 0:93c66. + */ +#define CSR21 0x0054 +#define CSR21_RELOAD FIELD32(0x00000001) +#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002) +#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004) +#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008) +#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010) +#define CSR21_TYPE_93C46 FIELD32(0x00000020) + +/* + * CSR22: CFP control register. + * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU. + * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain. + */ +#define CSR22 0x0058 +#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff) +#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000) + +/* + * Transmit related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXCSR0: TX Control Register. + * KICK_TX: Kick tx ring. + * KICK_ATIM: Kick atim ring. + * KICK_PRIO: Kick priority ring. + * ABORT: Abort all transmit related ring operation. + */ +#define TXCSR0 0x0060 +#define TXCSR0_KICK_TX FIELD32(0x00000001) +#define TXCSR0_KICK_ATIM FIELD32(0x00000002) +#define TXCSR0_KICK_PRIO FIELD32(0x00000004) +#define TXCSR0_ABORT FIELD32(0x00000008) + +/* + * TXCSR1: TX Configuration Register. + * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps. + * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps. + * TSF_OFFSET: Insert tsf offset. + * AUTORESPONDER: Enable auto responder which include ack & cts. + */ +#define TXCSR1 0x0064 +#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff) +#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00) +#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000) +#define TXCSR1_AUTORESPONDER FIELD32(0x01000000) + +/* + * TXCSR2: Tx descriptor configuration register. + * TXD_SIZE: Tx descriptor size, default is 48. + * NUM_TXD: Number of tx entries in ring. + * NUM_ATIM: Number of atim entries in ring. + * NUM_PRIO: Number of priority entries in ring. + */ +#define TXCSR2 0x0068 +#define TXCSR2_TXD_SIZE FIELD32(0x000000ff) +#define TXCSR2_NUM_TXD FIELD32(0x0000ff00) +#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000) +#define TXCSR2_NUM_PRIO FIELD32(0xff000000) + +/* + * TXCSR3: TX Ring Base address register. + */ +#define TXCSR3 0x006c +#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR4: TX Atim Ring Base address register. + */ +#define TXCSR4 0x0070 +#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR5: TX Prio Ring Base address register. + */ +#define TXCSR5 0x0074 +#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR6: Beacon Base address register. + */ +#define TXCSR6 0x0078 +#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR7: Auto responder control register. + * AR_POWERMANAGEMENT: Auto responder power management bit. + */ +#define TXCSR7 0x007c +#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001) + +/* + * Receive related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * RXCSR0: RX Control Register. + * DISABLE_RX: Disable rx engine. + * DROP_CRC: Drop crc error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TODS: Drop frame tods bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * PASS_CRC: Pass all packets with crc attached. + */ +#define RXCSR0 0x0080 +#define RXCSR0_DISABLE_RX FIELD32(0x00000001) +#define RXCSR0_DROP_CRC FIELD32(0x00000002) +#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004) +#define RXCSR0_DROP_CONTROL FIELD32(0x00000008) +#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010) +#define RXCSR0_DROP_TODS FIELD32(0x00000020) +#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040) +#define RXCSR0_PASS_CRC FIELD32(0x00000080) + +/* + * RXCSR1: RX descriptor configuration register. + * RXD_SIZE: Rx descriptor size, default is 32b. + * NUM_RXD: Number of rx entries in ring. + */ +#define RXCSR1 0x0084 +#define RXCSR1_RXD_SIZE FIELD32(0x000000ff) +#define RXCSR1_NUM_RXD FIELD32(0x0000ff00) + +/* + * RXCSR2: RX Ring base address register. + */ +#define RXCSR2 0x0088 +#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff) + +/* + * RXCSR3: BBP ID register for Rx operation. + * BBP_ID#: BBP register # id. + * BBP_ID#_VALID: BBP register # id is valid or not. + */ +#define RXCSR3 0x0090 +#define RXCSR3_BBP_ID0 FIELD32(0x0000007f) +#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080) +#define RXCSR3_BBP_ID1 FIELD32(0x00007f00) +#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000) +#define RXCSR3_BBP_ID2 FIELD32(0x007f0000) +#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000) +#define RXCSR3_BBP_ID3 FIELD32(0x7f000000) +#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * RXCSR4: BBP ID register for Rx operation. + * BBP_ID#: BBP register # id. + * BBP_ID#_VALID: BBP register # id is valid or not. + */ +#define RXCSR4 0x0094 +#define RXCSR4_BBP_ID4 FIELD32(0x0000007f) +#define RXCSR4_BBP_ID4_VALID FIELD32(0x00000080) +#define RXCSR4_BBP_ID5 FIELD32(0x00007f00) +#define RXCSR4_BBP_ID5_VALID FIELD32(0x00008000) + +/* + * ARCSR0: Auto Responder PLCP config register 0. + * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data. + * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id. + */ +#define ARCSR0 0x0098 +#define ARCSR0_AR_BBP_DATA0 FIELD32(0x000000ff) +#define ARCSR0_AR_BBP_ID0 FIELD32(0x0000ff00) +#define ARCSR0_AR_BBP_DATA1 FIELD32(0x00ff0000) +#define ARCSR0_AR_BBP_ID1 FIELD32(0xff000000) + +/* + * ARCSR1: Auto Responder PLCP config register 1. + * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data. + * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id. + */ +#define ARCSR1 0x009c +#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff) +#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00) +#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000) +#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000) + +/* + * Miscellaneous Registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * PCICSR: PCI control register. + * BIG_ENDIAN: 1: big endian, 0: little endian. + * RX_TRESHOLD: Rx threshold in dw to start pci access + * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw. + * TX_TRESHOLD: Tx threshold in dw to start pci access + * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward. + * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw. + * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational. + */ +#define PCICSR 0x008c +#define PCICSR_BIG_ENDIAN FIELD32(0x00000001) +#define PCICSR_RX_TRESHOLD FIELD32(0x00000006) +#define PCICSR_TX_TRESHOLD FIELD32(0x00000018) +#define PCICSR_BURST_LENTH FIELD32(0x00000060) +#define PCICSR_ENABLE_CLK FIELD32(0x00000080) + +/* + * CNT0: FCS error count. + * FCS_ERROR: FCS error count, cleared when read. + */ +#define CNT0 0x00a0 +#define CNT0_FCS_ERROR FIELD32(0x0000ffff) + +/* + * Statistic Register. + * CNT1: PLCP error count. + * CNT2: Long error count. + * CNT3: CCA false alarm count. + * CNT4: Rx FIFO overflow count. + * CNT5: Tx FIFO underrun count. + */ +#define TIMECSR2 0x00a8 +#define CNT1 0x00ac +#define CNT2 0x00b0 +#define TIMECSR3 0x00b4 +#define CNT3 0x00b8 +#define CNT4 0x00bc +#define CNT5 0x00c0 + +/* + * Baseband Control Register. + */ + +/* + * PWRCSR0: Power mode configuration register. + */ +#define PWRCSR0 0x00c4 + +/* + * Power state transition time registers. + */ +#define PSCSR0 0x00c8 +#define PSCSR1 0x00cc +#define PSCSR2 0x00d0 +#define PSCSR3 0x00d4 + +/* + * PWRCSR1: Manual power control / status register. + * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake. + * SET_STATE: Set state. Write 1 to trigger, self cleared. + * BBP_DESIRE_STATE: BBP desired state. + * RF_DESIRE_STATE: RF desired state. + * BBP_CURR_STATE: BBP current state. + * RF_CURR_STATE: RF current state. + * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared. + */ +#define PWRCSR1 0x00d8 +#define PWRCSR1_SET_STATE FIELD32(0x00000001) +#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006) +#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018) +#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060) +#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180) +#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200) + +/* + * TIMECSR: Timer control register. + * US_COUNT: 1 us timer count in units of clock cycles. + * US_64_COUNT: 64 us timer count in units of 1 us timer. + * BEACON_EXPECT: Beacon expect window. + */ +#define TIMECSR 0x00dc +#define TIMECSR_US_COUNT FIELD32(0x000000ff) +#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00) +#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000) + +/* + * MACCSR0: MAC configuration register 0. + */ +#define MACCSR0 0x00e0 + +/* + * MACCSR1: MAC configuration register 1. + * KICK_RX: Kick one-shot rx in one-shot rx mode. + * ONESHOT_RXMODE: Enable one-shot rx mode for debugging. + * BBPRX_RESET_MODE: Ralink bbp rx reset mode. + * AUTO_TXBBP: Auto tx logic access bbp control register. + * AUTO_RXBBP: Auto rx logic access bbp control register. + * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd. + * INTERSIL_IF: Intersil if calibration pin. + */ +#define MACCSR1 0x00e4 +#define MACCSR1_KICK_RX FIELD32(0x00000001) +#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002) +#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004) +#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008) +#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010) +#define MACCSR1_LOOPBACK FIELD32(0x00000060) +#define MACCSR1_INTERSIL_IF FIELD32(0x00000080) + +/* + * RALINKCSR: Ralink Rx auto-reset BBCR. + * AR_BBP_DATA#: Auto reset BBP register # data. + * AR_BBP_ID#: Auto reset BBP register # id. + */ +#define RALINKCSR 0x00e8 +#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff) +#define RALINKCSR_AR_BBP_ID0 FIELD32(0x0000ff00) +#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000) +#define RALINKCSR_AR_BBP_ID1 FIELD32(0xff000000) + +/* + * BCNCSR: Beacon interval control register. + * CHANGE: Write one to change beacon interval. + * DELTATIME: The delta time value. + * NUM_BEACON: Number of beacon according to mode. + * MODE: Please refer to asic specs. + * PLUS: Plus or minus delta time value. + */ +#define BCNCSR 0x00ec +#define BCNCSR_CHANGE FIELD32(0x00000001) +#define BCNCSR_DELTATIME FIELD32(0x0000001e) +#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0) +#define BCNCSR_MODE FIELD32(0x00006000) +#define BCNCSR_PLUS FIELD32(0x00008000) + +/* + * BBP / RF / IF Control Register. + */ + +/* + * BBPCSR: BBP serial control register. + * VALUE: Register value to program into BBP. + * REGNUM: Selected BBP register. + * BUSY: 1: asic is busy execute BBP programming. + * WRITE_CONTROL: 1: write BBP, 0: read BBP. + */ +#define BBPCSR 0x00f0 +#define BBPCSR_VALUE FIELD32(0x000000ff) +#define BBPCSR_REGNUM FIELD32(0x00007f00) +#define BBPCSR_BUSY FIELD32(0x00008000) +#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000) + +/* + * RFCSR: RF serial control register. + * VALUE: Register value + id to program into rf/if. + * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22). + * IF_SELECT: Chip to program: 0: rf, 1: if. + * PLL_LD: Rf pll_ld status. + * BUSY: 1: asic is busy execute rf programming. + */ +#define RFCSR 0x00f4 +#define RFCSR_VALUE FIELD32(0x00ffffff) +#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000) +#define RFCSR_IF_SELECT FIELD32(0x20000000) +#define RFCSR_PLL_LD FIELD32(0x40000000) +#define RFCSR_BUSY FIELD32(0x80000000) + +/* + * LEDCSR: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + * LINK: 0: linkoff, 1: linkup. + * ACTIVITY: 0: idle, 1: active. + */ +#define LEDCSR 0x00f8 +#define LEDCSR_ON_PERIOD FIELD32(0x000000ff) +#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00) +#define LEDCSR_LINK FIELD32(0x00010000) +#define LEDCSR_ACTIVITY FIELD32(0x00020000) + +/* + * ASIC pointer information. + * RXPTR: Current RX ring address. + * TXPTR: Current Tx ring address. + * PRIPTR: Current Priority ring address. + * ATIMPTR: Current ATIM ring address. + */ +#define RXPTR 0x0100 +#define TXPTR 0x0104 +#define PRIPTR 0x0108 +#define ATIMPTR 0x010c + +/* + * GPIO and others. + */ + +/* + * GPIOCSR: GPIO control register. + */ +#define GPIOCSR 0x0120 +#define GPIOCSR_BIT0 FIELD32(0x00000001) +#define GPIOCSR_BIT1 FIELD32(0x00000002) +#define GPIOCSR_BIT2 FIELD32(0x00000004) +#define GPIOCSR_BIT3 FIELD32(0x00000008) +#define GPIOCSR_BIT4 FIELD32(0x00000010) +#define GPIOCSR_BIT5 FIELD32(0x00000020) +#define GPIOCSR_BIT6 FIELD32(0x00000040) +#define GPIOCSR_BIT7 FIELD32(0x00000080) + +/* + * BBPPCSR: BBP Pin control register. + */ +#define BBPPCSR 0x0124 + +/* + * BCNCSR1: Tx BEACON offset time control register. + * PRELOAD: Beacon timer offset in units of usec. + */ +#define BCNCSR1 0x0130 +#define BCNCSR1_PRELOAD FIELD32(0x0000ffff) + +/* + * MACCSR2: TX_PE to RX_PE turn-around time control register + * DELAY: RX_PE low width, in units of pci clock cycle. + */ +#define MACCSR2 0x0134 +#define MACCSR2_DELAY FIELD32(0x000000ff) + +/* + * ARCSR2: 1 Mbps ACK/CTS PLCP. + */ +#define ARCSR2 0x013c +#define ARCSR2_SIGNAL FIELD32(0x000000ff) +#define ARCSR2_SERVICE FIELD32(0x0000ff00) +#define ARCSR2_LENGTH_LOW FIELD32(0x00ff0000) +#define ARCSR2_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR3: 2 Mbps ACK/CTS PLCP. + */ +#define ARCSR3 0x0140 +#define ARCSR3_SIGNAL FIELD32(0x000000ff) +#define ARCSR3_SERVICE FIELD32(0x0000ff00) +#define ARCSR3_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR4: 5.5 Mbps ACK/CTS PLCP. + */ +#define ARCSR4 0x0144 +#define ARCSR4_SIGNAL FIELD32(0x000000ff) +#define ARCSR4_SERVICE FIELD32(0x0000ff00) +#define ARCSR4_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR5: 11 Mbps ACK/CTS PLCP. + */ +#define ARCSR5 0x0148 +#define ARCSR5_SIGNAL FIELD32(0x000000ff) +#define ARCSR5_SERVICE FIELD32(0x0000ff00) +#define ARCSR5_LENGTH FIELD32(0xffff0000) + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R1: TX antenna control + */ +#define BBP_R1_TX_ANTENNA FIELD8(0x03) + +/* + * R4: RX antenna control + */ +#define BBP_R4_RX_ANTENNA FIELD8(0x06) + +/* + * RF registers + */ + +/* + * RF 1 + */ +#define RF1_TUNER FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TUNER FIELD32(0x00000100) +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RF_TYPE: Rf_type of this adapter. + * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd. + * RX_AGCVGC: 0: disable, 1:enable BBP R13 tuning. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + */ +#define EEPROM_ANTENNA 0x0b +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0040) +#define EEPROM_ANTENNA_LED_MODE FIELD16(0x0180) +#define EEPROM_ANTENNA_RX_AGCVGC_TUNING FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0c +#define EEPROM_BBP_SIZE 7 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER + */ +#define EEPROM_TXPOWER_START 0x13 +#define EEPROM_TXPOWER_SIZE 7 +#define EEPROM_TXPOWER_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_2 FIELD16(0xff00) + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 8 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 8 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_OWNER_NIC FIELD32(0x00000001) +#define TXD_W0_VALID FIELD32(0x00000002) +#define TXD_W0_RESULT FIELD32(0x0000001c) +#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0) +#define TXD_W0_MORE_FRAG FIELD32(0x00000100) +#define TXD_W0_ACK FIELD32(0x00000200) +#define TXD_W0_TIMESTAMP FIELD32(0x00000400) +#define TXD_W0_RTS FIELD32(0x00000800) +#define TXD_W0_IFS FIELD32(0x00006000) +#define TXD_W0_RETRY_MODE FIELD32(0x00008000) +#define TXD_W0_AGC FIELD32(0x00ff0000) +#define TXD_W0_R2 FIELD32(0xff000000) + +/* + * Word1 + */ +#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff) + +/* + * Word2 + */ +#define TXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff) +#define TXD_W2_DATABYTE_COUNT FIELD32(0xffff0000) + +/* + * Word3 & 4: PLCP information + */ +#define TXD_W3_PLCP_SIGNAL FIELD32(0x0000ffff) +#define TXD_W3_PLCP_SERVICE FIELD32(0xffff0000) +#define TXD_W4_PLCP_LENGTH_LOW FIELD32(0x0000ffff) +#define TXD_W4_PLCP_LENGTH_HIGH FIELD32(0xffff0000) + +/* + * Word5 + */ +#define TXD_W5_BBCR4 FIELD32(0x0000ffff) +#define TXD_W5_AGC_REG FIELD32(0x007f0000) +#define TXD_W5_AGC_REG_VALID FIELD32(0x00800000) +#define TXD_W5_XXX_REG FIELD32(0x7f000000) +#define TXD_W5_XXX_REG_VALID FIELD32(0x80000000) + +/* + * Word6 + */ +#define TXD_W6_SK_BUFF FIELD32(0xffffffff) + +/* + * Word7 + */ +#define TXD_W7_RESERVED FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + */ +#define RXD_W0_OWNER_NIC FIELD32(0x00000001) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002) +#define RXD_W0_MULTICAST FIELD32(0x00000004) +#define RXD_W0_BROADCAST FIELD32(0x00000008) +#define RXD_W0_MY_BSS FIELD32(0x00000010) +#define RXD_W0_CRC_ERROR FIELD32(0x00000020) +#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080) +#define RXD_W0_DATABYTE_COUNT FIELD32(0xffff0000) + +/* + * Word1 + */ +#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff) + +/* + * Word2 + */ +#define RXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff) +#define RXD_W2_SIGNAL FIELD32(0x00ff0000) +#define RXD_W2_RSSI FIELD32(0xff000000) + +/* + * Word3 + */ +#define RXD_W3_BBR2 FIELD32(0x000000ff) +#define RXD_W3_BBR3 FIELD32(0x0000ff00) +#define RXD_W3_BBR4 FIELD32(0x00ff0000) +#define RXD_W3_BBR5 FIELD32(0xff000000) + +/* + * Word4 + */ +#define RXD_W4_RX_END_TIME FIELD32(0xffffffff) + +/* + * Word5 & 6 & 7: Reserved + */ +#define RXD_W5_RESERVED FIELD32(0xffffffff) +#define RXD_W6_RESERVED FIELD32(0xffffffff) +#define RXD_W7_RESERVED FIELD32(0xffffffff) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + * NOTE: Logics in rt2400pci for txpower are reversed + * compared to the other rt2x00 drivers. A higher txpower + * value means that the txpower must be lowered. This is + * important when converting the value coming from the + * dscape stack to the rt2400 acceptable value. + */ +#define MIN_TXPOWER 31 +#define MAX_TXPOWER 62 +#define DEFAULT_TXPOWER 39 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \ + ((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \ + (((__txpower) - MAX_TXPOWER) + MIN_TXPOWER); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + (__txpower) += MIN_TXPOWER; \ + ((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER : \ + (MAX_TXPOWER - ((__txpower) - MIN_TXPOWER))); \ +}) + +#endif /* RT2400PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c new file mode 100644 index 000000000000..f6115c626fa7 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -0,0 +1,2000 @@ +/* + Copyright (C) 2004 - 2007 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: rt2500pci + Abstract: rt2500pci device specific routines. + Supported chipsets: RT2560. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2500pci" + +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" +#include "rt2500pci.h" + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt2x00pci_register_read and rt2x00pci_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); + if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); +} + +static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + *value = 0xff; + return; + } + + *value = rt2x00_get_field32(reg, BBPCSR_VALUE); +} + +static void rt2500pci_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, RFCSR, ®); + if (!rt2x00_get_field32(reg, RFCSR_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR21, ®); + + eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); + eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); + eeprom->reg_data_clock = + !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK); + eeprom->reg_chip_select = + !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT); +} + +static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg = 0; + + rt2x00_set_field32(®, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in); + rt2x00_set_field32(®, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out); + rt2x00_set_field32(®, CSR21_EEPROM_DATA_CLOCK, + !!eeprom->reg_data_clock); + rt2x00_set_field32(®, CSR21_EEPROM_CHIP_SELECT, + !!eeprom->reg_chip_select); + + rt2x00pci_register_write(rt2x00dev, CSR21, reg); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) + +static void rt2500pci_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); +} + +static void rt2500pci_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt2500pci_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2500pci_read_csr, + .write = rt2500pci_write_csr, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2500pci_bbp_read, + .write = rt2500pci_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2500pci_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +#ifdef CONFIG_RT2500PCI_RFKILL +static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); + return rt2x00_get_field32(reg, GPIOCSR_BIT0); +} +#endif /* CONFIG_RT2400PCI_RFKILL */ + +/* + * Configuration handlers. + */ +static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, ®, sizeof(reg)); +} + +static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); +} + +static void rt2500pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + int multicast = !!(filter & IFF_MULTICAST); + int broadcast = !!(filter & IFF_BROADCAST); + u32 reg; + + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); + rt2x00_set_field32(®, RXCSR0_DROP_MCAST, !multicast); + rt2x00_set_field32(®, RXCSR0_DROP_BCAST, !broadcast); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + +static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) +{ + u32 reg; + + rt2x00pci_register_write(rt2x00dev, CSR14, 0); + + /* + * Apply hardware packet filter. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); + else + rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); + } + + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); + + /* + * Enable beacon config + */ + rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); + rt2x00_set_field32(®, BCNCSR1_PRELOAD, + PREAMBLE + get_duration(IEEE80211_HEADER, 2)); + rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, + rt2x00lib_get_ring(rt2x00dev, + IEEE80211_TX_QUEUE_BEACON) + ->tx_params.cw_min); + rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); + } + + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); + + rt2x00pci_register_write(rt2x00dev, CSR14, reg); +} + +static void rt2500pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u32 reg; + u32 preamble; + u16 value; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + rt2x00pci_register_write(rt2x00dev, ARCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, value); + value = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, value); + rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); + + preamble = DEVICE_GET_RATE_FIELD(rate, PREAMBLE) ? 0x08 : 0x00; + + rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); + rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble); + rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); + rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble); + rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); + rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble); + rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); + rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble); + rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); +} + +static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + if (phymode == MODE_IEEE80211A) + rt2x00dev->curr_hwmode = HWMODE_A; + else if (phymode == MODE_IEEE80211B) + rt2x00dev->curr_hwmode = HWMODE_B; + else + rt2x00dev->curr_hwmode = HWMODE_G; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt2500pci_config_rate(rt2x00dev, rate->val2); +} + +static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel, + const int txpower) +{ + struct rf_channel reg; + u8 r70; + + /* + * Fill rf_reg structure. + */ + memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); + + /* + * Set TXpower. + */ + rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + + /* + * Switch on tuning bits. + * For RT2523 devices we do not need to update the R1 register. + */ + if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) + rt2x00_set_field32(®.rf1, RF1_TUNER, 1); + rt2x00_set_field32(®.rf3, RF3_TUNER, 1); + + /* + * For RT2525 we should first set the channel to half band higher. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + static const u32 vals[] = { + 0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a, + 0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a, + 0x00080d1e, 0x00080d22, 0x00080d26, 0x00080d2a, + 0x00080d2e, 0x00080d3a + }; + + rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2500pci_rf_write(rt2x00dev, 2, vals[channel - 1]); + rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); + if (reg.rf4) + rt2500pci_rf_write(rt2x00dev, 4, reg.rf4); + } + + rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2500pci_rf_write(rt2x00dev, 2, reg.rf2); + rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); + if (reg.rf4) + rt2500pci_rf_write(rt2x00dev, 4, reg.rf4); + + /* + * Channel 14 requires the Japan filter bit to be set. + */ + r70 = 0x46; + rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, channel == 14); + rt2500pci_bbp_write(rt2x00dev, 70, r70); + + msleep(1); + + /* + * Switch off tuning bits. + * For RT2523 devices we do not need to update the R1 register. + */ + if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) { + rt2x00_set_field32(®.rf1, RF1_TUNER, 0); + rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); + } + + rt2x00_set_field32(®.rf3, RF3_TUNER, 0); + rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); + + /* + * Clear false CRC during channel switch. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®.rf1); +} + +static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 rf3; + + rt2x00_rf_read(rt2x00dev, 3, &rf3); + rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2500pci_rf_write(rt2x00dev, 3, rf3); +} + +static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, const int antenna_rx) +{ + u32 reg; + u8 r14; + u8 r2; + + rt2x00pci_register_read(rt2x00dev, BBPCSR1, ®); + rt2500pci_bbp_read(rt2x00dev, 14, &r14); + rt2500pci_bbp_read(rt2x00dev, 2, &r2); + + /* + * Configure the TX antenna. + */ + switch (antenna_tx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field32(®, BBPCSR1_CCK, 2); + rt2x00_set_field32(®, BBPCSR1_OFDM, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); + rt2x00_set_field32(®, BBPCSR1_CCK, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field32(®, BBPCSR1_CCK, 2); + rt2x00_set_field32(®, BBPCSR1_OFDM, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + } + + /* + * RT2525E and RT5222 need to flip TX I/Q + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { + rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); + + /* + * RT2525E does not need RX I/Q Flip. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); + } else { + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 0); + } + + rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg); + rt2500pci_bbp_write(rt2x00dev, 14, r14); + rt2500pci_bbp_write(rt2x00dev, 2, r2); +} + +static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, + const int short_slot_time, + const int beacon_int) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, SIFS); + rt2x00_set_field32(®, CSR18_PIFS, + short_slot_time ? SHORT_PIFS : PIFS); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, + short_slot_time ? SHORT_DIFS : DIFS); + rt2x00_set_field32(®, CSR19_EIFS, EIFS); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); + rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, CSR12, ®); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, CSR12, reg); +} + +static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt2500pci_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt2500pci_config_channel(rt2x00dev, conf->channel_val, + conf->channel, conf->power_level); + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt2500pci_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt2500pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2500pci_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +/* + * LED functions. + */ +static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); + + rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); + rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); + + if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { + rt2x00_set_field32(®, LEDCSR_LINK, 1); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); + } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { + rt2x00_set_field32(®, LEDCSR_LINK, 0); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); + } else { + rt2x00_set_field32(®, LEDCSR_LINK, 1); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); + } + + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); +} + +static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); + rt2x00_set_field32(®, LEDCSR_LINK, 0); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); +} + +/* + * Link tuning + */ +static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT3, ®); + rt2x00dev->link.false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); +} + +static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2500pci_bbp_write(rt2x00dev, 17, 0x48); + rt2x00dev->link.vgc_level = 0x48; +} + +static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); + u8 r17; + + /* + * To prevent collisions with MAC ASIC on chipsets + * up to version C the link tuning should halt after 20 + * seconds. + */ + if (rt2x00_get_rev(&rt2x00dev->chip) < RT2560_VERSION_D && + rt2x00dev->link.count > 20) + return; + + rt2500pci_bbp_read(rt2x00dev, 17, &r17); + + /* + * Chipset versions C and lower should directly continue + * to the dynamic CCA tuning. + */ + if (rt2x00_get_rev(&rt2x00dev->chip) < RT2560_VERSION_D) + goto dynamic_cca_tune; + + /* + * A too low RSSI will cause too much false CCA which will + * then corrupt the R17 tuning. To remidy this the tuning should + * be stopped (While making sure the R17 value will not exceed limits) + */ + if (rssi < -80 && rt2x00dev->link.count > 20) { + if (r17 >= 0x41) { + r17 = rt2x00dev->link.vgc_level; + rt2500pci_bbp_write(rt2x00dev, 17, r17); + } + return; + } + + /* + * Special big-R17 for short distance + */ + if (rssi >= -58) { + if (r17 != 0x50) + rt2500pci_bbp_write(rt2x00dev, 17, 0x50); + return; + } + + /* + * Special mid-R17 for middle distance + */ + if (rssi >= -74) { + if (r17 != 0x41) + rt2500pci_bbp_write(rt2x00dev, 17, 0x41); + return; + } + + /* + * Leave short or middle distance condition, restore r17 + * to the dynamic tuning range. + */ + if (r17 >= 0x41) { + rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.vgc_level); + return; + } + +dynamic_cca_tune: + + /* + * R17 is inside the dynamic tuning range, + * start tuning the link based on the false cca counter. + */ + if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) { + rt2500pci_bbp_write(rt2x00dev, 17, ++r17); + rt2x00dev->link.vgc_level = r17; + } else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) { + rt2500pci_bbp_write(rt2x00dev, 17, --r17); + rt2x00dev->link.vgc_level = r17; + } +} + +/* + * Initialization functions. + */ +static void rt2500pci_init_rxring(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + struct data_desc *rxd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + rxd = ring->entry[i].priv; + + rt2x00_desc_read(rxd, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(rxd, 1, word); + + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); + } + + rt2x00_ring_index_clear(rt2x00dev->rx); +} + +static void rt2500pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_desc *txd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + txd = ring->entry[i].priv; + + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); + } + + rt2x00_ring_index_clear(ring); +} + +static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Initialize rings. + */ + rt2500pci_init_rxring(rt2x00dev); + rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + /* + * Initialize registers. + */ + rt2x00pci_register_read(rt2x00dev, TXCSR2, ®); + rt2x00_set_field32(®, TXCSR2_TXD_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size); + rt2x00_set_field32(®, TXCSR2_NUM_TXD, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); + rt2x00_set_field32(®, TXCSR2_NUM_ATIM, + rt2x00dev->bcn[1].stats.limit); + rt2x00_set_field32(®, TXCSR2_NUM_PRIO, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); + rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); + rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); + rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, + rt2x00dev->bcn[1].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); + rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, + rt2x00dev->bcn[0].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); + rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); + rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit); + rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + rt2x00dev->rx->data_dma); + rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); + + return 0; +} + +static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002); + rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002); + rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00020002); + rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002); + + rt2x00pci_register_read(rt2x00dev, TIMECSR, ®); + rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); + rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); + rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); + rt2x00pci_register_write(rt2x00dev, TIMECSR, reg); + + rt2x00pci_register_read(rt2x00dev, CSR9, ®); + rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, + rt2x00dev->rx->data_size / 128); + rt2x00pci_register_write(rt2x00dev, CSR9, reg); + + /* + * Always use CWmin and CWmax set in descriptor. + */ + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_CW_SELECT, 0); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_write(rt2x00dev, CNT3, 0); + + rt2x00pci_register_read(rt2x00dev, TXCSR8, ®); + rt2x00_set_field32(®, TXCSR8_BBP_ID0, 10); + rt2x00_set_field32(®, TXCSR8_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXCSR8_BBP_ID1, 11); + rt2x00_set_field32(®, TXCSR8_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXCSR8_BBP_ID2, 13); + rt2x00_set_field32(®, TXCSR8_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXCSR8_BBP_ID3, 12); + rt2x00_set_field32(®, TXCSR8_BBP_ID3_VALID, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR8, reg); + + rt2x00pci_register_read(rt2x00dev, ARTCSR0, ®); + rt2x00_set_field32(®, ARTCSR0_ACK_CTS_1MBS, 112); + rt2x00_set_field32(®, ARTCSR0_ACK_CTS_2MBS, 56); + rt2x00_set_field32(®, ARTCSR0_ACK_CTS_5_5MBS, 20); + rt2x00_set_field32(®, ARTCSR0_ACK_CTS_11MBS, 10); + rt2x00pci_register_write(rt2x00dev, ARTCSR0, reg); + + rt2x00pci_register_read(rt2x00dev, ARTCSR1, ®); + rt2x00_set_field32(®, ARTCSR1_ACK_CTS_6MBS, 45); + rt2x00_set_field32(®, ARTCSR1_ACK_CTS_9MBS, 37); + rt2x00_set_field32(®, ARTCSR1_ACK_CTS_12MBS, 33); + rt2x00_set_field32(®, ARTCSR1_ACK_CTS_18MBS, 29); + rt2x00pci_register_write(rt2x00dev, ARTCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, ARTCSR2, ®); + rt2x00_set_field32(®, ARTCSR2_ACK_CTS_24MBS, 29); + rt2x00_set_field32(®, ARTCSR2_ACK_CTS_36MBS, 25); + rt2x00_set_field32(®, ARTCSR2_ACK_CTS_48MBS, 25); + rt2x00_set_field32(®, ARTCSR2_ACK_CTS_54MBS, 25); + rt2x00pci_register_write(rt2x00dev, ARTCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR3, ®); + rt2x00_set_field32(®, RXCSR3_BBP_ID0, 47); /* CCK Signal */ + rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID1, 51); /* Rssi */ + rt2x00_set_field32(®, RXCSR3_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID2, 42); /* OFDM Rate */ + rt2x00_set_field32(®, RXCSR3_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID3, 51); /* RSSI */ + rt2x00_set_field32(®, RXCSR3_BBP_ID3_VALID, 1); + rt2x00pci_register_write(rt2x00dev, RXCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, PCICSR, ®); + rt2x00_set_field32(®, PCICSR_BIG_ENDIAN, 0); + rt2x00_set_field32(®, PCICSR_RX_TRESHOLD, 0); + rt2x00_set_field32(®, PCICSR_TX_TRESHOLD, 3); + rt2x00_set_field32(®, PCICSR_BURST_LENTH, 1); + rt2x00_set_field32(®, PCICSR_ENABLE_CLK, 1); + rt2x00_set_field32(®, PCICSR_READ_MULTIPLE, 1); + rt2x00_set_field32(®, PCICSR_WRITE_INVALID, 1); + rt2x00pci_register_write(rt2x00dev, PCICSR, reg); + + rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100); + + rt2x00pci_register_write(rt2x00dev, GPIOCSR, 0x0000ff00); + rt2x00pci_register_write(rt2x00dev, TESTCSR, 0x000000f0); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00213223); + rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518); + + rt2x00pci_register_read(rt2x00dev, MACCSR2, ®); + rt2x00_set_field32(®, MACCSR2_DELAY, 64); + rt2x00pci_register_write(rt2x00dev, MACCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, RALINKCSR, ®); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 26); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_VALID0, 1); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA1, 0); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID1, 26); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_VALID1, 1); + rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg); + + rt2x00pci_register_write(rt2x00dev, BBPCSR1, 0x82188200); + + rt2x00pci_register_write(rt2x00dev, TXACKCSR0, 0x00000020); + + rt2x00pci_register_read(rt2x00dev, CSR1, ®); + rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, CSR1_BBP_RESET, 0); + rt2x00_set_field32(®, CSR1_HOST_READY, 0); + rt2x00pci_register_write(rt2x00dev, CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, CSR1, ®); + rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, CSR1_HOST_READY, 1); + rt2x00pci_register_write(rt2x00dev, CSR1, reg); + + /* + * We must clear the FCS and FIFO error count. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); + rt2x00pci_register_read(rt2x00dev, CNT4, ®); + + return 0; +} + +static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500pci_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt2500pci_bbp_write(rt2x00dev, 3, 0x02); + rt2500pci_bbp_write(rt2x00dev, 4, 0x19); + rt2500pci_bbp_write(rt2x00dev, 14, 0x1c); + rt2500pci_bbp_write(rt2x00dev, 15, 0x30); + rt2500pci_bbp_write(rt2x00dev, 16, 0xac); + rt2500pci_bbp_write(rt2x00dev, 18, 0x18); + rt2500pci_bbp_write(rt2x00dev, 19, 0xff); + rt2500pci_bbp_write(rt2x00dev, 20, 0x1e); + rt2500pci_bbp_write(rt2x00dev, 21, 0x08); + rt2500pci_bbp_write(rt2x00dev, 22, 0x08); + rt2500pci_bbp_write(rt2x00dev, 23, 0x08); + rt2500pci_bbp_write(rt2x00dev, 24, 0x70); + rt2500pci_bbp_write(rt2x00dev, 25, 0x40); + rt2500pci_bbp_write(rt2x00dev, 26, 0x08); + rt2500pci_bbp_write(rt2x00dev, 27, 0x23); + rt2500pci_bbp_write(rt2x00dev, 30, 0x10); + rt2500pci_bbp_write(rt2x00dev, 31, 0x2b); + rt2500pci_bbp_write(rt2x00dev, 32, 0xb9); + rt2500pci_bbp_write(rt2x00dev, 34, 0x12); + rt2500pci_bbp_write(rt2x00dev, 35, 0x50); + rt2500pci_bbp_write(rt2x00dev, 39, 0xc4); + rt2500pci_bbp_write(rt2x00dev, 40, 0x02); + rt2500pci_bbp_write(rt2x00dev, 41, 0x60); + rt2500pci_bbp_write(rt2x00dev, 53, 0x10); + rt2500pci_bbp_write(rt2x00dev, 54, 0x18); + rt2500pci_bbp_write(rt2x00dev, 56, 0x08); + rt2500pci_bbp_write(rt2x00dev, 57, 0x10); + rt2500pci_bbp_write(rt2x00dev, 58, 0x08); + rt2500pci_bbp_write(rt2x00dev, 61, 0x6d); + rt2500pci_bbp_write(rt2x00dev, 62, 0x10); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt2500pci_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + +static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int mask = (state == STATE_RADIO_IRQ_OFF); + u32 reg; + + /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (state == STATE_RADIO_IRQ_ON) { + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); + rt2x00_set_field32(®, CSR8_RXDONE, mask); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); +} + +static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Initialize all registers. + */ + if (rt2500pci_init_rings(rt2x00dev) || + rt2500pci_init_registers(rt2x00dev) || + rt2500pci_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + /* + * Enable interrupts. + */ + rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); + + /* + * Enable LED + */ + rt2500pci_enable_led(rt2x00dev); + + return 0; +} + +static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Disable LED + */ + rt2500pci_disable_led(rt2x00dev); + + rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0); + + /* + * Disable synchronisation. + */ + rt2x00pci_register_write(rt2x00dev, CSR14, 0); + + /* + * Cancel RX and TX. + */ + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); + rt2x00_set_field32(®, TXCSR0_ABORT, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); + + /* + * Disable interrupts. + */ + rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); +} + +static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + unsigned int i; + char put_to_sleep; + char bbp_state; + char rf_state; + + put_to_sleep = (state != STATE_AWAKE); + + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); + rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); + rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); + rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); + rt2x00_set_field32(®, PWRCSR1_PUT_TO_SLEEP, put_to_sleep); + rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); + bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); + rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); + if (bbp_state == state && rf_state == state) + return 0; + msleep(10); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state: bbp %d and rf %d.\n", + state, bbp_state, rf_state); + + return -EBUSY; +} + +static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt2500pci_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt2500pci_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt2500pci_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2500pci_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W2_AIFS, desc->aifs); + rt2x00_set_field32(&word, TXD_W2_CWMIN, desc->cw_min); + rt2x00_set_field32(&word, TXD_W2_CWMAX, desc->cw_max); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 3, &word); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_desc_write(txd, 3, word); + + rt2x00_desc_read(txd, 10, &word); + rt2x00_set_field32(&word, TXD_W10_RTS, + test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags)); + rt2x00_desc_write(txd, 10, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); + rt2x00_set_field32(&word, TXD_W0_VALID, 1); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_OFDM, + test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, + !!(control->flags & + IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u32 reg; + + if (queue == IEEE80211_TX_QUEUE_BEACON) { + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { + rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + } + return; + } + + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); + if (queue == IEEE80211_TX_QUEUE_DATA0) + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA1) + rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); + else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); +} + +/* + * RX control handlers + */ +static int rt2500pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct data_desc *rxd = entry->priv; + u32 word0; + u32 word2; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 2, &word2); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || + rt2x00_get_field32(word0, RXD_W0_ICV_ERROR)) + return -EINVAL; + + *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + return 0; +} + +/* + * Interrupt functions. + */ +static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_entry *entry; + struct data_desc *txd; + u32 word; + int tx_status; + int retry; + + while (!rt2x00_ring_empty(ring)) { + entry = rt2x00_get_data_entry_done(ring); + txd = entry->priv; + rt2x00_desc_read(txd, 0, &word); + + if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + !rt2x00_get_field32(word, TXD_W0_VALID)) + break; + + /* + * Obtain the status about this packet. + */ + tx_status = rt2x00_get_field32(word, TXD_W0_RESULT); + retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); + + rt2x00lib_txdone(entry, tx_status, retry); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_desc_write(txd, 0, word); + rt2x00_ring_index_done_inc(ring); + } + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + entry = ring->entry; + if (!rt2x00_ring_full(ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); +} + +static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) +{ + struct rt2x00_dev *rt2x00dev = dev_instance; + u32 reg; + + /* + * Get the interrupt sources & saved to local variable. + * Write register value back to clear pending interrupts. + */ + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + + if (!reg) + return IRQ_NONE; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* + * Handle interrupts, walk through all bits + * and run the tasks, the bits are checked in order of + * priority. + */ + + /* + * 1 - Beacon timer expired interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) + rt2x00lib_beacondone(rt2x00dev); + + /* + * 2 - Rx ring done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_RXDONE)) + rt2x00pci_rxdone(rt2x00dev); + + /* + * 3 - Atim ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) + rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + + /* + * 4 - Priority ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) + rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + + /* + * 5 - Tx ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) + rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + + return IRQ_HANDLED; +} + +/* + * Device probe functions. + */ +static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + struct eeprom_93cx6 eeprom; + u32 reg; + u16 word; + u8 *mac; + + rt2x00pci_register_read(rt2x00dev, CSR21, ®); + + eeprom.data = rt2x00dev; + eeprom.register_read = rt2500pci_eepromregister_read; + eeprom.register_write = rt2500pci_eepromregister_write; + eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ? + PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; + eeprom.reg_data_in = 0; + eeprom.reg_data_out = 0; + eeprom.reg_data_clock = 0; + eeprom.reg_chip_select = 0; + + eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, + EEPROM_SIZE / sizeof(u16)); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, + DEFAULT_RSSI_OFFSET); + rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word); + EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word); + } + + return 0; +} + +static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00pci_register_read(rt2x00dev, CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2560, value, reg); + + if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && + !rt2x00_rf(&rt2x00dev->chip, RF2523) && + !rt2x00_rf(&rt2x00dev->chip, RF2524) && + !rt2x00_rf(&rt2x00dev->chip, RF2525) && + !rt2x00_rf(&rt2x00dev->chip, RF2525E) && + !rt2x00_rf(&rt2x00dev->chip, RF5222)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Store led mode, for correct led behaviour. + */ + rt2x00dev->led_mode = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) + __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + + /* + * Check if the BBP tuning should be enabled. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) + __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); + + /* + * Read the RSSI <-> dBm offset information. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); + rt2x00dev->rssi_offset = + rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); + + return 0; +} + +/* + * RF value list for RF2522 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2522[] = { + { 1, 0x00002050, 0x000c1fda, 0x00000101, 0 }, + { 2, 0x00002050, 0x000c1fee, 0x00000101, 0 }, + { 3, 0x00002050, 0x000c2002, 0x00000101, 0 }, + { 4, 0x00002050, 0x000c2016, 0x00000101, 0 }, + { 5, 0x00002050, 0x000c202a, 0x00000101, 0 }, + { 6, 0x00002050, 0x000c203e, 0x00000101, 0 }, + { 7, 0x00002050, 0x000c2052, 0x00000101, 0 }, + { 8, 0x00002050, 0x000c2066, 0x00000101, 0 }, + { 9, 0x00002050, 0x000c207a, 0x00000101, 0 }, + { 10, 0x00002050, 0x000c208e, 0x00000101, 0 }, + { 11, 0x00002050, 0x000c20a2, 0x00000101, 0 }, + { 12, 0x00002050, 0x000c20b6, 0x00000101, 0 }, + { 13, 0x00002050, 0x000c20ca, 0x00000101, 0 }, + { 14, 0x00002050, 0x000c20fa, 0x00000101, 0 }, +}; + +/* + * RF value list for RF2523 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2523[] = { + { 1, 0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b }, + { 2, 0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b }, + { 3, 0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b }, + { 4, 0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b }, + { 5, 0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b }, + { 6, 0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b }, + { 7, 0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b }, + { 8, 0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b }, + { 9, 0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b }, + { 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b }, + { 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b }, + { 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b }, + { 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b }, + { 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 }, +}; + +/* + * RF value list for RF2524 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2524[] = { + { 1, 0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b }, + { 2, 0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b }, + { 3, 0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b }, + { 4, 0x00032020, 0x00000caa, 0x00000101, 0x00000a1b }, + { 5, 0x00032020, 0x00000cae, 0x00000101, 0x00000a1b }, + { 6, 0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b }, + { 7, 0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b }, + { 8, 0x00032020, 0x00000cba, 0x00000101, 0x00000a1b }, + { 9, 0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b }, + { 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b }, + { 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b }, + { 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b }, + { 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b }, + { 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 }, +}; + +/* + * RF value list for RF2525 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2525[] = { + { 1, 0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b }, + { 2, 0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b }, + { 3, 0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b }, + { 4, 0x00022020, 0x00080caa, 0x00060111, 0x00000a1b }, + { 5, 0x00022020, 0x00080cae, 0x00060111, 0x00000a1b }, + { 6, 0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b }, + { 7, 0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b }, + { 8, 0x00022020, 0x00080cba, 0x00060111, 0x00000a1b }, + { 9, 0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b }, + { 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b }, + { 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b }, + { 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b }, + { 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b }, + { 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 }, +}; + +/* + * RF value list for RF2525e + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2525e[] = { + { 1, 0x00022020, 0x00081136, 0x00060111, 0x00000a0b }, + { 2, 0x00022020, 0x0008113a, 0x00060111, 0x00000a0b }, + { 3, 0x00022020, 0x0008113e, 0x00060111, 0x00000a0b }, + { 4, 0x00022020, 0x00081182, 0x00060111, 0x00000a0b }, + { 5, 0x00022020, 0x00081186, 0x00060111, 0x00000a0b }, + { 6, 0x00022020, 0x0008118a, 0x00060111, 0x00000a0b }, + { 7, 0x00022020, 0x0008118e, 0x00060111, 0x00000a0b }, + { 8, 0x00022020, 0x00081192, 0x00060111, 0x00000a0b }, + { 9, 0x00022020, 0x00081196, 0x00060111, 0x00000a0b }, + { 10, 0x00022020, 0x0008119a, 0x00060111, 0x00000a0b }, + { 11, 0x00022020, 0x0008119e, 0x00060111, 0x00000a0b }, + { 12, 0x00022020, 0x000811a2, 0x00060111, 0x00000a0b }, + { 13, 0x00022020, 0x000811a6, 0x00060111, 0x00000a0b }, + { 14, 0x00022020, 0x000811ae, 0x00060111, 0x00000a1b }, +}; + +/* + * RF value list for RF5222 + * Supports: 2.4 GHz & 5.2 GHz + */ +static const struct rf_channel rf_vals_5222[] = { + { 1, 0x00022020, 0x00001136, 0x00000101, 0x00000a0b }, + { 2, 0x00022020, 0x0000113a, 0x00000101, 0x00000a0b }, + { 3, 0x00022020, 0x0000113e, 0x00000101, 0x00000a0b }, + { 4, 0x00022020, 0x00001182, 0x00000101, 0x00000a0b }, + { 5, 0x00022020, 0x00001186, 0x00000101, 0x00000a0b }, + { 6, 0x00022020, 0x0000118a, 0x00000101, 0x00000a0b }, + { 7, 0x00022020, 0x0000118e, 0x00000101, 0x00000a0b }, + { 8, 0x00022020, 0x00001192, 0x00000101, 0x00000a0b }, + { 9, 0x00022020, 0x00001196, 0x00000101, 0x00000a0b }, + { 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b }, + { 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b }, + { 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b }, + { 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b }, + { 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f }, + { 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f }, + { 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f }, + { 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f }, + { 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f }, + { 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f }, + { 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f }, + { 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f }, + { 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f }, + { 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f }, + { 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f }, + { 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f }, + { 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f }, + { 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f }, + { 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f }, + { 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f }, + { 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f }, + + /* 802.11 UNII */ + { 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f }, + { 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 }, + { 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 }, + { 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 }, + { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 }, +}; + +static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = 0; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 2; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 2; + spec->num_rates = 12; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); + spec->channels = rf_vals_bg_2522; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); + spec->channels = rf_vals_bg_2523; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); + spec->channels = rf_vals_bg_2524; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); + spec->channels = rf_vals_bg_2525; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); + spec->channels = rf_vals_bg_2525e; + } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { + spec->num_channels = ARRAY_SIZE(rf_vals_5222); + spec->channels = rf_vals_5222; + spec->num_modes = 3; + } +} + +static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2500pci_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2500pci_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt2500pci_probe_hw_mode(rt2x00dev); + + /* + * This device requires the beacon ring + */ + __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry, u32 long_retry) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + return 0; +} + +static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR17, ®); + tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; + rt2x00pci_register_read(rt2x00dev, CSR16, ®); + tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); + + return tsf; +} + +static void rt2500pci_reset_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00pci_register_write(rt2x00dev, CSR16, 0); + rt2x00pci_register_write(rt2x00dev, CSR17, 0); +} + +static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR15, ®); + return rt2x00_get_field32(reg, CSR15_BEACON_SENT); +} + +static const struct ieee80211_ops rt2500pci_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .set_retry_limit = rt2500pci_set_retry_limit, + .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt2500pci_get_tsf, + .reset_tsf = rt2500pci_reset_tsf, + .beacon_update = rt2x00pci_beacon_update, + .tx_last_beacon = rt2500pci_tx_last_beacon, +}; + +static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { + .irq_handler = rt2500pci_interrupt, + .probe_hw = rt2500pci_probe_hw, + .initialize = rt2x00pci_initialize, + .uninitialize = rt2x00pci_uninitialize, + .set_device_state = rt2500pci_set_device_state, +#ifdef CONFIG_RT2500PCI_RFKILL + .rfkill_poll = rt2500pci_rfkill_poll, +#endif /* CONFIG_RT2500PCI_RFKILL */ + .link_stats = rt2500pci_link_stats, + .reset_tuner = rt2500pci_reset_tuner, + .link_tuner = rt2500pci_link_tuner, + .write_tx_desc = rt2500pci_write_tx_desc, + .write_tx_data = rt2x00pci_write_tx_data, + .kick_tx_queue = rt2500pci_kick_tx_queue, + .fill_rxdone = rt2500pci_fill_rxdone, + .config_mac_addr = rt2500pci_config_mac_addr, + .config_bssid = rt2500pci_config_bssid, + .config_packet_filter = rt2500pci_config_packet_filter, + .config_type = rt2500pci_config_type, + .config = rt2500pci_config, +}; + +static const struct rt2x00_ops rt2500pci_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt2500pci_rt2x00_ops, + .hw = &rt2500pci_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2500pci_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * RT2500pci module information. + */ +static struct pci_device_id rt2500pci_device_table[] = { + { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2500 PCI & PCMCIA Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards"); +MODULE_DEVICE_TABLE(pci, rt2500pci_device_table); +MODULE_LICENSE("GPL"); + +static struct pci_driver rt2500pci_driver = { + .name = DRV_NAME, + .id_table = rt2500pci_device_table, + .probe = rt2x00pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +}; + +static int __init rt2500pci_init(void) +{ + return pci_register_driver(&rt2500pci_driver); +} + +static void __exit rt2500pci_exit(void) +{ + pci_unregister_driver(&rt2500pci_driver); +} + +module_init(rt2500pci_init); +module_exit(rt2500pci_exit); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h new file mode 100644 index 000000000000..d92aa56b2f4b --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -0,0 +1,1236 @@ +/* + Copyright (C) 2004 - 2007 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: rt2500pci + Abstract: Data structures and registers for the rt2500pci module. + Supported chipsets: RT2560. + */ + +#ifndef RT2500PCI_H +#define RT2500PCI_H + +/* + * RF chip defines. + */ +#define RF2522 0x0000 +#define RF2523 0x0001 +#define RF2524 0x0002 +#define RF2525 0x0003 +#define RF2525E 0x0004 +#define RF5222 0x0010 + +/* + * RT2560 version + */ +#define RT2560_VERSION_B 2 +#define RT2560_VERSION_C 3 +#define RT2560_VERSION_D 4 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 121 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x0000 +#define CSR_REG_SIZE 0x0174 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0200 +#define BBP_SIZE 0x0040 +#define RF_SIZE 0x0014 + +/* + * Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * CSR0: ASIC revision number. + */ +#define CSR0 0x0000 + +/* + * CSR1: System control register. + * SOFT_RESET: Software reset, 1: reset, 0: normal. + * BBP_RESET: Hardware reset, 1: reset, 0, release. + * HOST_READY: Host ready after initialization. + */ +#define CSR1 0x0004 +#define CSR1_SOFT_RESET FIELD32(0x00000001) +#define CSR1_BBP_RESET FIELD32(0x00000002) +#define CSR1_HOST_READY FIELD32(0x00000004) + +/* + * CSR2: System admin status register (invalid). + */ +#define CSR2 0x0008 + +/* + * CSR3: STA MAC address register 0. + */ +#define CSR3 0x000c +#define CSR3_BYTE0 FIELD32(0x000000ff) +#define CSR3_BYTE1 FIELD32(0x0000ff00) +#define CSR3_BYTE2 FIELD32(0x00ff0000) +#define CSR3_BYTE3 FIELD32(0xff000000) + +/* + * CSR4: STA MAC address register 1. + */ +#define CSR4 0x0010 +#define CSR4_BYTE4 FIELD32(0x000000ff) +#define CSR4_BYTE5 FIELD32(0x0000ff00) + +/* + * CSR5: BSSID register 0. + */ +#define CSR5 0x0014 +#define CSR5_BYTE0 FIELD32(0x000000ff) +#define CSR5_BYTE1 FIELD32(0x0000ff00) +#define CSR5_BYTE2 FIELD32(0x00ff0000) +#define CSR5_BYTE3 FIELD32(0xff000000) + +/* + * CSR6: BSSID register 1. + */ +#define CSR6 0x0018 +#define CSR6_BYTE4 FIELD32(0x000000ff) +#define CSR6_BYTE5 FIELD32(0x0000ff00) + +/* + * CSR7: Interrupt source register. + * Write 1 to clear. + * TBCN_EXPIRE: Beacon timer expired interrupt. + * TWAKE_EXPIRE: Wakeup timer expired interrupt. + * TATIMW_EXPIRE: Timer of atim window expired interrupt. + * TXDONE_TXRING: Tx ring transmit done interrupt. + * TXDONE_ATIMRING: Atim ring transmit done interrupt. + * TXDONE_PRIORING: Priority ring transmit done interrupt. + * RXDONE: Receive done interrupt. + * DECRYPTION_DONE: Decryption done interrupt. + * ENCRYPTION_DONE: Encryption done interrupt. + * UART1_TX_TRESHOLD: UART1 TX reaches threshold. + * UART1_RX_TRESHOLD: UART1 RX reaches threshold. + * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold. + * UART1_TX_BUFF_ERROR: UART1 TX buffer error. + * UART1_RX_BUFF_ERROR: UART1 RX buffer error. + * UART2_TX_TRESHOLD: UART2 TX reaches threshold. + * UART2_RX_TRESHOLD: UART2 RX reaches threshold. + * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold. + * UART2_TX_BUFF_ERROR: UART2 TX buffer error. + * UART2_RX_BUFF_ERROR: UART2 RX buffer error. + * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period). + + */ +#define CSR7 0x001c +#define CSR7_TBCN_EXPIRE FIELD32(0x00000001) +#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002) +#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004) +#define CSR7_TXDONE_TXRING FIELD32(0x00000008) +#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010) +#define CSR7_TXDONE_PRIORING FIELD32(0x00000020) +#define CSR7_RXDONE FIELD32(0x00000040) +#define CSR7_DECRYPTION_DONE FIELD32(0x00000080) +#define CSR7_ENCRYPTION_DONE FIELD32(0x00000100) +#define CSR7_UART1_TX_TRESHOLD FIELD32(0x00000200) +#define CSR7_UART1_RX_TRESHOLD FIELD32(0x00000400) +#define CSR7_UART1_IDLE_TRESHOLD FIELD32(0x00000800) +#define CSR7_UART1_TX_BUFF_ERROR FIELD32(0x00001000) +#define CSR7_UART1_RX_BUFF_ERROR FIELD32(0x00002000) +#define CSR7_UART2_TX_TRESHOLD FIELD32(0x00004000) +#define CSR7_UART2_RX_TRESHOLD FIELD32(0x00008000) +#define CSR7_UART2_IDLE_TRESHOLD FIELD32(0x00010000) +#define CSR7_UART2_TX_BUFF_ERROR FIELD32(0x00020000) +#define CSR7_UART2_RX_BUFF_ERROR FIELD32(0x00040000) +#define CSR7_TIMER_CSR3_EXPIRE FIELD32(0x00080000) + +/* + * CSR8: Interrupt mask register. + * Write 1 to mask interrupt. + * TBCN_EXPIRE: Beacon timer expired interrupt. + * TWAKE_EXPIRE: Wakeup timer expired interrupt. + * TATIMW_EXPIRE: Timer of atim window expired interrupt. + * TXDONE_TXRING: Tx ring transmit done interrupt. + * TXDONE_ATIMRING: Atim ring transmit done interrupt. + * TXDONE_PRIORING: Priority ring transmit done interrupt. + * RXDONE: Receive done interrupt. + * DECRYPTION_DONE: Decryption done interrupt. + * ENCRYPTION_DONE: Encryption done interrupt. + * UART1_TX_TRESHOLD: UART1 TX reaches threshold. + * UART1_RX_TRESHOLD: UART1 RX reaches threshold. + * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold. + * UART1_TX_BUFF_ERROR: UART1 TX buffer error. + * UART1_RX_BUFF_ERROR: UART1 RX buffer error. + * UART2_TX_TRESHOLD: UART2 TX reaches threshold. + * UART2_RX_TRESHOLD: UART2 RX reaches threshold. + * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold. + * UART2_TX_BUFF_ERROR: UART2 TX buffer error. + * UART2_RX_BUFF_ERROR: UART2 RX buffer error. + * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period). + */ +#define CSR8 0x0020 +#define CSR8_TBCN_EXPIRE FIELD32(0x00000001) +#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002) +#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004) +#define CSR8_TXDONE_TXRING FIELD32(0x00000008) +#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010) +#define CSR8_TXDONE_PRIORING FIELD32(0x00000020) +#define CSR8_RXDONE FIELD32(0x00000040) +#define CSR8_DECRYPTION_DONE FIELD32(0x00000080) +#define CSR8_ENCRYPTION_DONE FIELD32(0x00000100) +#define CSR8_UART1_TX_TRESHOLD FIELD32(0x00000200) +#define CSR8_UART1_RX_TRESHOLD FIELD32(0x00000400) +#define CSR8_UART1_IDLE_TRESHOLD FIELD32(0x00000800) +#define CSR8_UART1_TX_BUFF_ERROR FIELD32(0x00001000) +#define CSR8_UART1_RX_BUFF_ERROR FIELD32(0x00002000) +#define CSR8_UART2_TX_TRESHOLD FIELD32(0x00004000) +#define CSR8_UART2_RX_TRESHOLD FIELD32(0x00008000) +#define CSR8_UART2_IDLE_TRESHOLD FIELD32(0x00010000) +#define CSR8_UART2_TX_BUFF_ERROR FIELD32(0x00020000) +#define CSR8_UART2_RX_BUFF_ERROR FIELD32(0x00040000) +#define CSR8_TIMER_CSR3_EXPIRE FIELD32(0x00080000) + +/* + * CSR9: Maximum frame length register. + * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12. + */ +#define CSR9 0x0024 +#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80) + +/* + * SECCSR0: WEP control register. + * KICK_DECRYPT: Kick decryption engine, self-clear. + * ONE_SHOT: 0: ring mode, 1: One shot only mode. + * DESC_ADDRESS: Descriptor physical address of frame. + */ +#define SECCSR0 0x0028 +#define SECCSR0_KICK_DECRYPT FIELD32(0x00000001) +#define SECCSR0_ONE_SHOT FIELD32(0x00000002) +#define SECCSR0_DESC_ADDRESS FIELD32(0xfffffffc) + +/* + * CSR11: Back-off control register. + * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1). + * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1). + * SLOT_TIME: Slot time, default is 20us for 802.11b + * CW_SELECT: CWmin/CWmax selection, 1: Register, 0: TXD. + * LONG_RETRY: Long retry count. + * SHORT_RETRY: Short retry count. + */ +#define CSR11 0x002c +#define CSR11_CWMIN FIELD32(0x0000000f) +#define CSR11_CWMAX FIELD32(0x000000f0) +#define CSR11_SLOT_TIME FIELD32(0x00001f00) +#define CSR11_CW_SELECT FIELD32(0x00002000) +#define CSR11_LONG_RETRY FIELD32(0x00ff0000) +#define CSR11_SHORT_RETRY FIELD32(0xff000000) + +/* + * CSR12: Synchronization configuration register 0. + * All units in 1/16 TU. + * BEACON_INTERVAL: Beacon interval, default is 100 TU. + * CFP_MAX_DURATION: Cfp maximum duration, default is 100 TU. + */ +#define CSR12 0x0030 +#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff) +#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000) + +/* + * CSR13: Synchronization configuration register 1. + * All units in 1/16 TU. + * ATIMW_DURATION: Atim window duration. + * CFP_PERIOD: Cfp period, default is 0 TU. + */ +#define CSR13 0x0034 +#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff) +#define CSR13_CFP_PERIOD FIELD32(0x00ff0000) + +/* + * CSR14: Synchronization control register. + * TSF_COUNT: Enable tsf auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * TBCN: Enable tbcn with reload value. + * TCFP: Enable tcfp & cfp / cp switching. + * TATIMW: Enable tatimw & atim window switching. + * BEACON_GEN: Enable beacon generator. + * CFP_COUNT_PRELOAD: Cfp count preload value. + * TBCM_PRELOAD: Tbcn preload value in units of 64us. + */ +#define CSR14 0x0038 +#define CSR14_TSF_COUNT FIELD32(0x00000001) +#define CSR14_TSF_SYNC FIELD32(0x00000006) +#define CSR14_TBCN FIELD32(0x00000008) +#define CSR14_TCFP FIELD32(0x00000010) +#define CSR14_TATIMW FIELD32(0x00000020) +#define CSR14_BEACON_GEN FIELD32(0x00000040) +#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00) +#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000) + +/* + * CSR15: Synchronization status register. + * CFP: ASIC is in contention-free period. + * ATIMW: ASIC is in ATIM window. + * BEACON_SENT: Beacon is send. + */ +#define CSR15 0x003c +#define CSR15_CFP FIELD32(0x00000001) +#define CSR15_ATIMW FIELD32(0x00000002) +#define CSR15_BEACON_SENT FIELD32(0x00000004) + +/* + * CSR16: TSF timer register 0. + */ +#define CSR16 0x0040 +#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff) + +/* + * CSR17: TSF timer register 1. + */ +#define CSR17 0x0044 +#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff) + +/* + * CSR18: IFS timer register 0. + * SIFS: Sifs, default is 10 us. + * PIFS: Pifs, default is 30 us. + */ +#define CSR18 0x0048 +#define CSR18_SIFS FIELD32(0x000001ff) +#define CSR18_PIFS FIELD32(0x001f0000) + +/* + * CSR19: IFS timer register 1. + * DIFS: Difs, default is 50 us. + * EIFS: Eifs, default is 364 us. + */ +#define CSR19 0x004c +#define CSR19_DIFS FIELD32(0x0000ffff) +#define CSR19_EIFS FIELD32(0xffff0000) + +/* + * CSR20: Wakeup timer register. + * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU. + * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup. + * AUTOWAKE: Enable auto wakeup / sleep mechanism. + */ +#define CSR20 0x0050 +#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff) +#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000) +#define CSR20_AUTOWAKE FIELD32(0x01000000) + +/* + * CSR21: EEPROM control register. + * RELOAD: Write 1 to reload eeprom content. + * TYPE_93C46: 1: 93c46, 0:93c66. + */ +#define CSR21 0x0054 +#define CSR21_RELOAD FIELD32(0x00000001) +#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002) +#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004) +#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008) +#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010) +#define CSR21_TYPE_93C46 FIELD32(0x00000020) + +/* + * CSR22: CFP control register. + * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU. + * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain. + */ +#define CSR22 0x0058 +#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff) +#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000) + +/* + * Transmit related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXCSR0: TX Control Register. + * KICK_TX: Kick tx ring. + * KICK_ATIM: Kick atim ring. + * KICK_PRIO: Kick priority ring. + * ABORT: Abort all transmit related ring operation. + */ +#define TXCSR0 0x0060 +#define TXCSR0_KICK_TX FIELD32(0x00000001) +#define TXCSR0_KICK_ATIM FIELD32(0x00000002) +#define TXCSR0_KICK_PRIO FIELD32(0x00000004) +#define TXCSR0_ABORT FIELD32(0x00000008) + +/* + * TXCSR1: TX Configuration Register. + * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps. + * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps. + * TSF_OFFSET: Insert tsf offset. + * AUTORESPONDER: Enable auto responder which include ack & cts. + */ +#define TXCSR1 0x0064 +#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff) +#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00) +#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000) +#define TXCSR1_AUTORESPONDER FIELD32(0x01000000) + +/* + * TXCSR2: Tx descriptor configuration register. + * TXD_SIZE: Tx descriptor size, default is 48. + * NUM_TXD: Number of tx entries in ring. + * NUM_ATIM: Number of atim entries in ring. + * NUM_PRIO: Number of priority entries in ring. + */ +#define TXCSR2 0x0068 +#define TXCSR2_TXD_SIZE FIELD32(0x000000ff) +#define TXCSR2_NUM_TXD FIELD32(0x0000ff00) +#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000) +#define TXCSR2_NUM_PRIO FIELD32(0xff000000) + +/* + * TXCSR3: TX Ring Base address register. + */ +#define TXCSR3 0x006c +#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR4: TX Atim Ring Base address register. + */ +#define TXCSR4 0x0070 +#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR5: TX Prio Ring Base address register. + */ +#define TXCSR5 0x0074 +#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR6: Beacon Base address register. + */ +#define TXCSR6 0x0078 +#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR7: Auto responder control register. + * AR_POWERMANAGEMENT: Auto responder power management bit. + */ +#define TXCSR7 0x007c +#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001) + +/* + * TXCSR8: CCK Tx BBP register. + */ +#define TXCSR8 0x0098 +#define TXCSR8_BBP_ID0 FIELD32(0x0000007f) +#define TXCSR8_BBP_ID0_VALID FIELD32(0x00000080) +#define TXCSR8_BBP_ID1 FIELD32(0x00007f00) +#define TXCSR8_BBP_ID1_VALID FIELD32(0x00008000) +#define TXCSR8_BBP_ID2 FIELD32(0x007f0000) +#define TXCSR8_BBP_ID2_VALID FIELD32(0x00800000) +#define TXCSR8_BBP_ID3 FIELD32(0x7f000000) +#define TXCSR8_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXCSR9: OFDM TX BBP registers + * OFDM_SIGNAL: BBP rate field address for OFDM. + * OFDM_SERVICE: BBP service field address for OFDM. + * OFDM_LENGTH_LOW: BBP length low byte address for OFDM. + * OFDM_LENGTH_HIGH: BBP length high byte address for OFDM. + */ +#define TXCSR9 0x0094 +#define TXCSR9_OFDM_RATE FIELD32(0x000000ff) +#define TXCSR9_OFDM_SERVICE FIELD32(0x0000ff00) +#define TXCSR9_OFDM_LENGTH_LOW FIELD32(0x00ff0000) +#define TXCSR9_OFDM_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Receive related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * RXCSR0: RX Control Register. + * DISABLE_RX: Disable rx engine. + * DROP_CRC: Drop crc error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TODS: Drop frame tods bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * PASS_CRC: Pass all packets with crc attached. + * PASS_CRC: Pass all packets with crc attached. + * PASS_PLCP: Pass all packets with 4 bytes PLCP attached. + * DROP_MCAST: Drop multicast frames. + * DROP_BCAST: Drop broadcast frames. + * ENABLE_QOS: Accept QOS data frame and parse QOS field. + */ +#define RXCSR0 0x0080 +#define RXCSR0_DISABLE_RX FIELD32(0x00000001) +#define RXCSR0_DROP_CRC FIELD32(0x00000002) +#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004) +#define RXCSR0_DROP_CONTROL FIELD32(0x00000008) +#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010) +#define RXCSR0_DROP_TODS FIELD32(0x00000020) +#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040) +#define RXCSR0_PASS_CRC FIELD32(0x00000080) +#define RXCSR0_PASS_PLCP FIELD32(0x00000100) +#define RXCSR0_DROP_MCAST FIELD32(0x00000200) +#define RXCSR0_DROP_BCAST FIELD32(0x00000400) +#define RXCSR0_ENABLE_QOS FIELD32(0x00000800) + +/* + * RXCSR1: RX descriptor configuration register. + * RXD_SIZE: Rx descriptor size, default is 32b. + * NUM_RXD: Number of rx entries in ring. + */ +#define RXCSR1 0x0084 +#define RXCSR1_RXD_SIZE FIELD32(0x000000ff) +#define RXCSR1_NUM_RXD FIELD32(0x0000ff00) + +/* + * RXCSR2: RX Ring base address register. + */ +#define RXCSR2 0x0088 +#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff) + +/* + * RXCSR3: BBP ID register for Rx operation. + * BBP_ID#: BBP register # id. + * BBP_ID#_VALID: BBP register # id is valid or not. + */ +#define RXCSR3 0x0090 +#define RXCSR3_BBP_ID0 FIELD32(0x0000007f) +#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080) +#define RXCSR3_BBP_ID1 FIELD32(0x00007f00) +#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000) +#define RXCSR3_BBP_ID2 FIELD32(0x007f0000) +#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000) +#define RXCSR3_BBP_ID3 FIELD32(0x7f000000) +#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * ARCSR1: Auto Responder PLCP config register 1. + * AR_BBP_DATA#: Auto responder BBP register # data. + * AR_BBP_ID#: Auto responder BBP register # Id. + */ +#define ARCSR1 0x009c +#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff) +#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00) +#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000) +#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000) + +/* + * Miscellaneous Registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + + */ + +/* + * PCICSR: PCI control register. + * BIG_ENDIAN: 1: big endian, 0: little endian. + * RX_TRESHOLD: Rx threshold in dw to start pci access + * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw. + * TX_TRESHOLD: Tx threshold in dw to start pci access + * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward. + * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw. + * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational. + * READ_MULTIPLE: Enable memory read multiple. + * WRITE_INVALID: Enable memory write & invalid. + */ +#define PCICSR 0x008c +#define PCICSR_BIG_ENDIAN FIELD32(0x00000001) +#define PCICSR_RX_TRESHOLD FIELD32(0x00000006) +#define PCICSR_TX_TRESHOLD FIELD32(0x00000018) +#define PCICSR_BURST_LENTH FIELD32(0x00000060) +#define PCICSR_ENABLE_CLK FIELD32(0x00000080) +#define PCICSR_READ_MULTIPLE FIELD32(0x00000100) +#define PCICSR_WRITE_INVALID FIELD32(0x00000200) + +/* + * CNT0: FCS error count. + * FCS_ERROR: FCS error count, cleared when read. + */ +#define CNT0 0x00a0 +#define CNT0_FCS_ERROR FIELD32(0x0000ffff) + +/* + * Statistic Register. + * CNT1: PLCP error count. + * CNT2: Long error count. + */ +#define TIMECSR2 0x00a8 +#define CNT1 0x00ac +#define CNT2 0x00b0 +#define TIMECSR3 0x00b4 + +/* + * CNT3: CCA false alarm count. + */ +#define CNT3 0x00b8 +#define CNT3_FALSE_CCA FIELD32(0x0000ffff) + +/* + * Statistic Register. + * CNT4: Rx FIFO overflow count. + * CNT5: Tx FIFO underrun count. + */ +#define CNT4 0x00bc +#define CNT5 0x00c0 + +/* + * Baseband Control Register. + */ + +/* + * PWRCSR0: Power mode configuration register. + */ +#define PWRCSR0 0x00c4 + +/* + * Power state transition time registers. + */ +#define PSCSR0 0x00c8 +#define PSCSR1 0x00cc +#define PSCSR2 0x00d0 +#define PSCSR3 0x00d4 + +/* + * PWRCSR1: Manual power control / status register. + * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake. + * SET_STATE: Set state. Write 1 to trigger, self cleared. + * BBP_DESIRE_STATE: BBP desired state. + * RF_DESIRE_STATE: RF desired state. + * BBP_CURR_STATE: BBP current state. + * RF_CURR_STATE: RF current state. + * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared. + */ +#define PWRCSR1 0x00d8 +#define PWRCSR1_SET_STATE FIELD32(0x00000001) +#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006) +#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018) +#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060) +#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180) +#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200) + +/* + * TIMECSR: Timer control register. + * US_COUNT: 1 us timer count in units of clock cycles. + * US_64_COUNT: 64 us timer count in units of 1 us timer. + * BEACON_EXPECT: Beacon expect window. + */ +#define TIMECSR 0x00dc +#define TIMECSR_US_COUNT FIELD32(0x000000ff) +#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00) +#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000) + +/* + * MACCSR0: MAC configuration register 0. + */ +#define MACCSR0 0x00e0 + +/* + * MACCSR1: MAC configuration register 1. + * KICK_RX: Kick one-shot rx in one-shot rx mode. + * ONESHOT_RXMODE: Enable one-shot rx mode for debugging. + * BBPRX_RESET_MODE: Ralink bbp rx reset mode. + * AUTO_TXBBP: Auto tx logic access bbp control register. + * AUTO_RXBBP: Auto rx logic access bbp control register. + * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd. + * INTERSIL_IF: Intersil if calibration pin. + */ +#define MACCSR1 0x00e4 +#define MACCSR1_KICK_RX FIELD32(0x00000001) +#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002) +#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004) +#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008) +#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010) +#define MACCSR1_LOOPBACK FIELD32(0x00000060) +#define MACCSR1_INTERSIL_IF FIELD32(0x00000080) + +/* + * RALINKCSR: Ralink Rx auto-reset BBCR. + * AR_BBP_DATA#: Auto reset BBP register # data. + * AR_BBP_ID#: Auto reset BBP register # id. + */ +#define RALINKCSR 0x00e8 +#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff) +#define RALINKCSR_AR_BBP_ID0 FIELD32(0x00007f00) +#define RALINKCSR_AR_BBP_VALID0 FIELD32(0x00008000) +#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000) +#define RALINKCSR_AR_BBP_ID1 FIELD32(0x7f000000) +#define RALINKCSR_AR_BBP_VALID1 FIELD32(0x80000000) + +/* + * BCNCSR: Beacon interval control register. + * CHANGE: Write one to change beacon interval. + * DELTATIME: The delta time value. + * NUM_BEACON: Number of beacon according to mode. + * MODE: Please refer to asic specs. + * PLUS: Plus or minus delta time value. + */ +#define BCNCSR 0x00ec +#define BCNCSR_CHANGE FIELD32(0x00000001) +#define BCNCSR_DELTATIME FIELD32(0x0000001e) +#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0) +#define BCNCSR_MODE FIELD32(0x00006000) +#define BCNCSR_PLUS FIELD32(0x00008000) + +/* + * BBP / RF / IF Control Register. + */ + +/* + * BBPCSR: BBP serial control register. + * VALUE: Register value to program into BBP. + * REGNUM: Selected BBP register. + * BUSY: 1: asic is busy execute BBP programming. + * WRITE_CONTROL: 1: write BBP, 0: read BBP. + */ +#define BBPCSR 0x00f0 +#define BBPCSR_VALUE FIELD32(0x000000ff) +#define BBPCSR_REGNUM FIELD32(0x00007f00) +#define BBPCSR_BUSY FIELD32(0x00008000) +#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000) + +/* + * RFCSR: RF serial control register. + * VALUE: Register value + id to program into rf/if. + * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22). + * IF_SELECT: Chip to program: 0: rf, 1: if. + * PLL_LD: Rf pll_ld status. + * BUSY: 1: asic is busy execute rf programming. + */ +#define RFCSR 0x00f4 +#define RFCSR_VALUE FIELD32(0x00ffffff) +#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000) +#define RFCSR_IF_SELECT FIELD32(0x20000000) +#define RFCSR_PLL_LD FIELD32(0x40000000) +#define RFCSR_BUSY FIELD32(0x80000000) + +/* + * LEDCSR: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + * LINK: 0: linkoff, 1: linkup. + * ACTIVITY: 0: idle, 1: active. + * LINK_POLARITY: 0: active low, 1: active high. + * ACTIVITY_POLARITY: 0: active low, 1: active high. + * LED_DEFAULT: LED state for "enable" 0: ON, 1: OFF. + */ +#define LEDCSR 0x00f8 +#define LEDCSR_ON_PERIOD FIELD32(0x000000ff) +#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00) +#define LEDCSR_LINK FIELD32(0x00010000) +#define LEDCSR_ACTIVITY FIELD32(0x00020000) +#define LEDCSR_LINK_POLARITY FIELD32(0x00040000) +#define LEDCSR_ACTIVITY_POLARITY FIELD32(0x00080000) +#define LEDCSR_LED_DEFAULT FIELD32(0x00100000) + +/* + * AES control register. + */ +#define SECCSR3 0x00fc + +/* + * ASIC pointer information. + * RXPTR: Current RX ring address. + * TXPTR: Current Tx ring address. + * PRIPTR: Current Priority ring address. + * ATIMPTR: Current ATIM ring address. + */ +#define RXPTR 0x0100 +#define TXPTR 0x0104 +#define PRIPTR 0x0108 +#define ATIMPTR 0x010c + +/* + * TXACKCSR0: TX ACK timeout. + */ +#define TXACKCSR0 0x0110 + +/* + * ACK timeout count registers. + * ACKCNT0: TX ACK timeout count. + * ACKCNT1: RX ACK timeout count. + */ +#define ACKCNT0 0x0114 +#define ACKCNT1 0x0118 + +/* + * GPIO and others. + */ + +/* + * GPIOCSR: GPIO control register. + */ +#define GPIOCSR 0x0120 +#define GPIOCSR_BIT0 FIELD32(0x00000001) +#define GPIOCSR_BIT1 FIELD32(0x00000002) +#define GPIOCSR_BIT2 FIELD32(0x00000004) +#define GPIOCSR_BIT3 FIELD32(0x00000008) +#define GPIOCSR_BIT4 FIELD32(0x00000010) +#define GPIOCSR_BIT5 FIELD32(0x00000020) +#define GPIOCSR_BIT6 FIELD32(0x00000040) +#define GPIOCSR_BIT7 FIELD32(0x00000080) +#define GPIOCSR_DIR0 FIELD32(0x00000100) +#define GPIOCSR_DIR1 FIELD32(0x00000200) +#define GPIOCSR_DIR2 FIELD32(0x00000400) +#define GPIOCSR_DIR3 FIELD32(0x00000800) +#define GPIOCSR_DIR4 FIELD32(0x00001000) +#define GPIOCSR_DIR5 FIELD32(0x00002000) +#define GPIOCSR_DIR6 FIELD32(0x00004000) +#define GPIOCSR_DIR7 FIELD32(0x00008000) + +/* + * FIFO pointer registers. + * FIFOCSR0: TX FIFO pointer. + * FIFOCSR1: RX FIFO pointer. + */ +#define FIFOCSR0 0x0128 +#define FIFOCSR1 0x012c + +/* + * BCNCSR1: Tx BEACON offset time control register. + * PRELOAD: Beacon timer offset in units of usec. + * BEACON_CWMIN: 2^CwMin. + */ +#define BCNCSR1 0x0130 +#define BCNCSR1_PRELOAD FIELD32(0x0000ffff) +#define BCNCSR1_BEACON_CWMIN FIELD32(0x000f0000) + +/* + * MACCSR2: TX_PE to RX_PE turn-around time control register + * DELAY: RX_PE low width, in units of pci clock cycle. + */ +#define MACCSR2 0x0134 +#define MACCSR2_DELAY FIELD32(0x000000ff) + +/* + * TESTCSR: TEST mode selection register. + */ +#define TESTCSR 0x0138 + +/* + * ARCSR2: 1 Mbps ACK/CTS PLCP. + */ +#define ARCSR2 0x013c +#define ARCSR2_SIGNAL FIELD32(0x000000ff) +#define ARCSR2_SERVICE FIELD32(0x0000ff00) +#define ARCSR2_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR3: 2 Mbps ACK/CTS PLCP. + */ +#define ARCSR3 0x0140 +#define ARCSR3_SIGNAL FIELD32(0x000000ff) +#define ARCSR3_SERVICE FIELD32(0x0000ff00) +#define ARCSR3_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR4: 5.5 Mbps ACK/CTS PLCP. + */ +#define ARCSR4 0x0144 +#define ARCSR4_SIGNAL FIELD32(0x000000ff) +#define ARCSR4_SERVICE FIELD32(0x0000ff00) +#define ARCSR4_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR5: 11 Mbps ACK/CTS PLCP. + */ +#define ARCSR5 0x0148 +#define ARCSR5_SIGNAL FIELD32(0x000000ff) +#define ARCSR5_SERVICE FIELD32(0x0000ff00) +#define ARCSR5_LENGTH FIELD32(0xffff0000) + +/* + * ARTCSR0: CCK ACK/CTS payload consumed time for 1/2/5.5/11 mbps. + */ +#define ARTCSR0 0x014c +#define ARTCSR0_ACK_CTS_11MBS FIELD32(0x000000ff) +#define ARTCSR0_ACK_CTS_5_5MBS FIELD32(0x0000ff00) +#define ARTCSR0_ACK_CTS_2MBS FIELD32(0x00ff0000) +#define ARTCSR0_ACK_CTS_1MBS FIELD32(0xff000000) + + +/* + * ARTCSR1: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps. + */ +#define ARTCSR1 0x0150 +#define ARTCSR1_ACK_CTS_6MBS FIELD32(0x000000ff) +#define ARTCSR1_ACK_CTS_9MBS FIELD32(0x0000ff00) +#define ARTCSR1_ACK_CTS_12MBS FIELD32(0x00ff0000) +#define ARTCSR1_ACK_CTS_18MBS FIELD32(0xff000000) + +/* + * ARTCSR2: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps. + */ +#define ARTCSR2 0x0154 +#define ARTCSR2_ACK_CTS_24MBS FIELD32(0x000000ff) +#define ARTCSR2_ACK_CTS_36MBS FIELD32(0x0000ff00) +#define ARTCSR2_ACK_CTS_48MBS FIELD32(0x00ff0000) +#define ARTCSR2_ACK_CTS_54MBS FIELD32(0xff000000) + +/* + * SECCSR1_RT2509: WEP control register. + * KICK_ENCRYPT: Kick encryption engine, self-clear. + * ONE_SHOT: 0: ring mode, 1: One shot only mode. + * DESC_ADDRESS: Descriptor physical address of frame. + */ +#define SECCSR1 0x0158 +#define SECCSR1_KICK_ENCRYPT FIELD32(0x00000001) +#define SECCSR1_ONE_SHOT FIELD32(0x00000002) +#define SECCSR1_DESC_ADDRESS FIELD32(0xfffffffc) + +/* + * BBPCSR1: BBP TX configuration. + */ +#define BBPCSR1 0x015c +#define BBPCSR1_CCK FIELD32(0x00000003) +#define BBPCSR1_CCK_FLIP FIELD32(0x00000004) +#define BBPCSR1_OFDM FIELD32(0x00030000) +#define BBPCSR1_OFDM_FLIP FIELD32(0x00040000) + +/* + * Dual band configuration registers. + * DBANDCSR0: Dual band configuration register 0. + * DBANDCSR1: Dual band configuration register 1. + */ +#define DBANDCSR0 0x0160 +#define DBANDCSR1 0x0164 + +/* + * BBPPCSR: BBP Pin control register. + */ +#define BBPPCSR 0x0168 + +/* + * MAC special debug mode selection registers. + * DBGSEL0: MAC special debug mode selection register 0. + * DBGSEL1: MAC special debug mode selection register 1. + */ +#define DBGSEL0 0x016c +#define DBGSEL1 0x0170 + +/* + * BISTCSR: BBP BIST register. + */ +#define BISTCSR 0x0174 + +/* + * Multicast filter registers. + * MCAST0: Multicast filter register 0. + * MCAST1: Multicast filter register 1. + */ +#define MCAST0 0x0178 +#define MCAST1 0x017c + +/* + * UART registers. + * UARTCSR0: UART1 TX register. + * UARTCSR1: UART1 RX register. + * UARTCSR3: UART1 frame control register. + * UARTCSR4: UART1 buffer control register. + * UART2CSR0: UART2 TX register. + * UART2CSR1: UART2 RX register. + * UART2CSR3: UART2 frame control register. + * UART2CSR4: UART2 buffer control register. + */ +#define UARTCSR0 0x0180 +#define UARTCSR1 0x0184 +#define UARTCSR3 0x0188 +#define UARTCSR4 0x018c +#define UART2CSR0 0x0190 +#define UART2CSR1 0x0194 +#define UART2CSR3 0x0198 +#define UART2CSR4 0x019c + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R2: TX antenna control + */ +#define BBP_R2_TX_ANTENNA FIELD8(0x03) +#define BBP_R2_TX_IQ_FLIP FIELD8(0x04) + +/* + * R14: RX antenna control + */ +#define BBP_R14_RX_ANTENNA FIELD8(0x03) +#define BBP_R14_RX_IQ_FLIP FIELD8(0x04) + +/* + * BBP_R70 + */ +#define BBP_R70_JAPAN_FILTER FIELD8(0x08) + +/* + * RF registers + */ + +/* + * RF 1 + */ +#define RF1_TUNER FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TUNER FIELD32(0x00000100) +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd. + * DYN_TXAGC: Dynamic TX AGC control. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + * RF_TYPE: Rf_type of this adapter. + */ +#define EEPROM_ANTENNA 0x10 +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0) +#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800) + +/* + * EEPROM NIC config. + * CARDBUS_ACCEL: 0: enable, 1: disable. + * DYN_BBP_TUNE: 0: enable, 1: disable. + * CCK_TX_POWER: CCK TX power compensation. + */ +#define EEPROM_NIC 0x11 +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001) +#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002) +#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c) + +/* + * EEPROM geography. + * GEO: Default geography setting for device. + */ +#define EEPROM_GEOGRAPHY 0x12 +#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x13 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER + */ +#define EEPROM_TXPOWER_START 0x23 +#define EEPROM_TXPOWER_SIZE 7 +#define EEPROM_TXPOWER_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_2 FIELD16(0xff00) + +/* + * RSSI <-> dBm offset calibration + */ +#define EEPROM_CALIBRATE_OFFSET 0x3e +#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff) + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 11 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 11 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_OWNER_NIC FIELD32(0x00000001) +#define TXD_W0_VALID FIELD32(0x00000002) +#define TXD_W0_RESULT FIELD32(0x0000001c) +#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0) +#define TXD_W0_MORE_FRAG FIELD32(0x00000100) +#define TXD_W0_ACK FIELD32(0x00000200) +#define TXD_W0_TIMESTAMP FIELD32(0x00000400) +#define TXD_W0_OFDM FIELD32(0x00000800) +#define TXD_W0_CIPHER_OWNER FIELD32(0x00001000) +#define TXD_W0_IFS FIELD32(0x00006000) +#define TXD_W0_RETRY_MODE FIELD32(0x00008000) +#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + */ +#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff) + +/* + * Word2 + */ +#define TXD_W2_IV_OFFSET FIELD32(0x0000003f) +#define TXD_W2_AIFS FIELD32(0x000000c0) +#define TXD_W2_CWMIN FIELD32(0x00000f00) +#define TXD_W2_CWMAX FIELD32(0x0000f000) + +/* + * Word3: PLCP information + */ +#define TXD_W3_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W3_PLCP_SERVICE FIELD32(0x0000ff00) +#define TXD_W3_PLCP_LENGTH_LOW FIELD32(0x00ff0000) +#define TXD_W3_PLCP_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Word4 + */ +#define TXD_W4_IV FIELD32(0xffffffff) + +/* + * Word5 + */ +#define TXD_W5_EIV FIELD32(0xffffffff) + +/* + * Word6-9: Key + */ +#define TXD_W6_KEY FIELD32(0xffffffff) +#define TXD_W7_KEY FIELD32(0xffffffff) +#define TXD_W8_KEY FIELD32(0xffffffff) +#define TXD_W9_KEY FIELD32(0xffffffff) + +/* + * Word10 + */ +#define TXD_W10_RTS FIELD32(0x00000001) +#define TXD_W10_TX_RATE FIELD32(0x000000fe) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + */ +#define RXD_W0_OWNER_NIC FIELD32(0x00000001) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002) +#define RXD_W0_MULTICAST FIELD32(0x00000004) +#define RXD_W0_BROADCAST FIELD32(0x00000008) +#define RXD_W0_MY_BSS FIELD32(0x00000010) +#define RXD_W0_CRC_ERROR FIELD32(0x00000020) +#define RXD_W0_OFDM FIELD32(0x00000040) +#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080) +#define RXD_W0_CIPHER_OWNER FIELD32(0x00000100) +#define RXD_W0_ICV_ERROR FIELD32(0x00000200) +#define RXD_W0_IV_OFFSET FIELD32(0x0000fc00) +#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + */ +#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff) + +/* + * Word2 + */ +#define RXD_W2_SIGNAL FIELD32(0x000000ff) +#define RXD_W2_RSSI FIELD32(0x0000ff00) +#define RXD_W2_TA FIELD32(0xffff0000) + +/* + * Word3 + */ +#define RXD_W3_TA FIELD32(0xffffffff) + +/* + * Word4 + */ +#define RXD_W4_IV FIELD32(0xffffffff) + +/* + * Word5 + */ +#define RXD_W5_EIV FIELD32(0xffffffff) + +/* + * Word6-9: Key + */ +#define RXD_W6_KEY FIELD32(0xffffffff) +#define RXD_W7_KEY FIELD32(0xffffffff) +#define RXD_W8_KEY FIELD32(0xffffffff) +#define RXD_W9_KEY FIELD32(0xffffffff) + +/* + * Word10 + */ +#define RXD_W10_DROP FIELD32(0x00000001) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + */ +#define MIN_TXPOWER 0 +#define MAX_TXPOWER 31 +#define DEFAULT_TXPOWER 24 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? \ + DEFAULT_TXPOWER : (__txpower); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ + (__txpower)); \ +}) + +#endif /* RT2500PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c new file mode 100644 index 000000000000..847bd7f58eed --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -0,0 +1,1837 @@ +/* + Copyright (C) 2004 - 2007 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: rt2500usb + Abstract: rt2500usb device specific routines. + Supported chipsets: RT2570. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2500usb" + +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00usb.h" +#include "rt2500usb.h" + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt2500usb_register_read and rt2500usb_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u16 *value) +{ + __le16 reg; + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(u16), REGISTER_TIMEOUT); + *value = le16_to_cpu(reg); +} + +static inline void rt2500usb_register_multiread(const struct rt2x00_dev + *rt2x00dev, + const unsigned int offset, + void *value, const u16 length) +{ + int timeout = REGISTER_TIMEOUT * (length / sizeof(u16)); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + value, length, timeout); +} + +static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u16 value) +{ + __le16 reg = cpu_to_le16(value); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(u16), REGISTER_TIMEOUT); +} + +static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev + *rt2x00dev, + const unsigned int offset, + void *value, const u16 length) +{ + int timeout = REGISTER_TIMEOUT * (length / sizeof(u16)); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + value, length, timeout); +} + +static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500usb_register_read(rt2x00dev, PHY_CSR8, ®); + if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u16 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500usb_bbp_check(rt2x00dev); + if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_DATA, value); + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); + + rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg); +} + +static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u16 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500usb_bbp_check(rt2x00dev); + if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); + + rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500usb_bbp_check(rt2x00dev); + if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); + *value = 0xff; + return; + } + + rt2500usb_register_read(rt2x00dev, PHY_CSR7, ®); + *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); +} + +static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u16 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500usb_register_read(rt2x00dev, PHY_CSR10, ®); + if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); + rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg); + + reg = 0; + rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); + rt2x00_set_field16(®, PHY_CSR10_RF_NUMBER_OF_BITS, 20); + rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); + rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); + + rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) ) + +static void rt2500usb_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data); +} + +static void rt2500usb_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt2500usb_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2500usb_read_csr, + .write = rt2500usb_write_csr, + .word_size = sizeof(u16), + .word_count = CSR_REG_SIZE / sizeof(u16), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2500usb_bbp_read, + .write = rt2500usb_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2500usb_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +/* + * Configuration handlers. + */ +static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le16 reg[3]; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); +} + +static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le16 reg[3]; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg)); +} + +static void rt2500usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + int multicast = !!(filter & IFF_MULTICAST); + int broadcast = !!(filter & IFF_BROADCAST); + u16 reg; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, !promisc); + rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, !multicast); + rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, !broadcast); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); +} + +static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) +{ + u16 reg; + + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + + /* + * Apply hardware packet filter. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 1); + else + rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 0); + rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 0); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 0); + rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 0); + } + + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); + + /* + * Enable beacon config + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); + rt2x00_set_field16(®, TXRX_CSR20_OFFSET, + (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); + if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); + else + rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2); + rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg); + + /* + * Enable synchronisation. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + rt2x00_set_field16(®, TXRX_CSR18_OFFSET, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); + } + + rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); + + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); +} + +static void rt2500usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u16 reg; + u16 value; + u16 preamble; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + + rt2500usb_register_write(rt2x00dev, TXRX_CSR11, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, value); + rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); + if (preamble == SHORT_PREAMBLE) + rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 1); + else + rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); +} + +static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + if (phymode == MODE_IEEE80211A) + rt2x00dev->curr_hwmode = HWMODE_A; + else if (phymode == MODE_IEEE80211B) + rt2x00dev->curr_hwmode = HWMODE_B; + else + rt2x00dev->curr_hwmode = HWMODE_G; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt2500usb_config_rate(rt2x00dev, rate->val2); + + if (phymode == MODE_IEEE80211B) { + rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b); + rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040); + } else { + rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0005); + rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x016c); + } +} + +static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel, + const int txpower) +{ + struct rf_channel reg; + + /* + * Fill rf_reg structure. + */ + memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); + + /* + * Set TXpower. + */ + rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + + /* + * For RT2525E we should first set the channel to half band higher. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + static const u32 vals[] = { + 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, + 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, + 0x000008ba, 0x000008be, 0x000008b7, 0x00000902, + 0x00000902, 0x00000906 + }; + + rt2500usb_rf_write(rt2x00dev, 2, vals[channel - 1]); + if (reg.rf4) + rt2500usb_rf_write(rt2x00dev, 4, reg.rf4); + } + + rt2500usb_rf_write(rt2x00dev, 1, reg.rf1); + rt2500usb_rf_write(rt2x00dev, 2, reg.rf2); + rt2500usb_rf_write(rt2x00dev, 3, reg.rf3); + if (reg.rf4) + rt2500usb_rf_write(rt2x00dev, 4, reg.rf4); +} + +static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 rf3; + + rt2x00_rf_read(rt2x00dev, 3, &rf3); + rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2500usb_rf_write(rt2x00dev, 3, rf3); +} + +static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, const int antenna_rx) +{ + u8 r2; + u8 r14; + u16 csr5; + u16 csr6; + + rt2500usb_bbp_read(rt2x00dev, 2, &r2); + rt2500usb_bbp_read(rt2x00dev, 14, &r14); + rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5); + rt2500usb_register_read(rt2x00dev, PHY_CSR6, &csr6); + + /* + * Configure the TX antenna. + */ + switch (antenna_tx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + } + + /* + * RT2525E and RT5222 need to flip TX I/Q + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { + rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1); + + /* + * RT2525E does not need RX I/Q Flip. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); + } else { + rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 0); + } + + rt2500usb_bbp_write(rt2x00dev, 2, r2); + rt2500usb_bbp_write(rt2x00dev, 14, r14); + rt2500usb_register_write(rt2x00dev, PHY_CSR5, csr5); + rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6); +} + +static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, + const int short_slot_time, + const int beacon_int) +{ + u16 reg; + + rt2500usb_register_write(rt2x00dev, MAC_CSR10, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, beacon_int * 4); + rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); +} + +static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt2500usb_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt2500usb_config_channel(rt2x00dev, conf->channel_val, + conf->channel, conf->power_level); + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt2500usb_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt2500usb_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2500usb_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +/* + * LED functions. + */ +static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + + rt2500usb_register_read(rt2x00dev, MAC_CSR21, ®); + rt2x00_set_field16(®, MAC_CSR21_ON_PERIOD, 70); + rt2x00_set_field16(®, MAC_CSR21_OFF_PERIOD, 30); + rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg); + + rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®); + + if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { + rt2x00_set_field16(®, MAC_CSR20_LINK, 1); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0); + } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { + rt2x00_set_field16(®, MAC_CSR20_LINK, 0); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1); + } else { + rt2x00_set_field16(®, MAC_CSR20_LINK, 1); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1); + } + + rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg); +} + +static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + + rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®); + rt2x00_set_field16(®, MAC_CSR20_LINK, 0); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0); + rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg); +} + +/* + * Link tuning + */ +static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + + /* + * Update FCS error count from register. + */ + rt2500usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2500usb_register_read(rt2x00dev, STA_CSR3, ®); + rt2x00dev->link.false_cca = + rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); +} + +static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + u16 eeprom; + u16 value; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R24_LOW); + rt2500usb_bbp_write(rt2x00dev, 24, value); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R25_LOW); + rt2500usb_bbp_write(rt2x00dev, 25, value); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R61_LOW); + rt2500usb_bbp_write(rt2x00dev, 61, value); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER); + rt2500usb_bbp_write(rt2x00dev, 17, value); + + rt2x00dev->link.vgc_level = value; +} + +static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); + u16 bbp_thresh; + u16 vgc_bound; + u16 sens; + u16 r24; + u16 r25; + u16 r61; + u16 r17_sens; + u8 r17; + u8 up_bound; + u8 low_bound; + + /* + * Determine the BBP tuning threshold and correctly + * set BBP 24, 25 and 61. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &bbp_thresh); + bbp_thresh = rt2x00_get_field16(bbp_thresh, EEPROM_BBPTUNE_THRESHOLD); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &r24); + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &r25); + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &r61); + + if ((rssi + bbp_thresh) > 0) { + r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_HIGH); + r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_HIGH); + r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_HIGH); + } else { + r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_LOW); + r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_LOW); + r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_LOW); + } + + rt2500usb_bbp_write(rt2x00dev, 24, r24); + rt2500usb_bbp_write(rt2x00dev, 25, r25); + rt2500usb_bbp_write(rt2x00dev, 61, r61); + + /* + * Read current r17 value, as well as the sensitivity values + * for the r17 register. + */ + rt2500usb_bbp_read(rt2x00dev, 17, &r17); + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens); + + /* + * A too low RSSI will cause too much false CCA which will + * then corrupt the R17 tuning. To remidy this the tuning should + * be stopped (While making sure the R17 value will not exceed limits) + */ + if (rssi >= -40) { + if (r17 != 0x60) + rt2500usb_bbp_write(rt2x00dev, 17, 0x60); + return; + } + + /* + * Special big-R17 for short distance + */ + if (rssi >= -58) { + sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_LOW); + if (r17 != sens) + rt2500usb_bbp_write(rt2x00dev, 17, sens); + return; + } + + /* + * Special mid-R17 for middle distance + */ + if (rssi >= -74) { + sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_HIGH); + if (r17 != sens) + rt2500usb_bbp_write(rt2x00dev, 17, sens); + return; + } + + /* + * Leave short or middle distance condition, restore r17 + * to the dynamic tuning range. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound); + vgc_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER); + + low_bound = 0x32; + if (rssi >= -77) + up_bound = vgc_bound; + else + up_bound = vgc_bound - (-77 - rssi); + + if (up_bound < low_bound) + up_bound = low_bound; + + if (r17 > up_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, up_bound); + rt2x00dev->link.vgc_level = up_bound; + } else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, ++r17); + rt2x00dev->link.vgc_level = r17; + } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, --r17); + rt2x00dev->link.vgc_level = r17; + } +} + +/* + * Initialization functions. + */ +static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0x0001, + USB_MODE_TEST, REGISTER_TIMEOUT); + rt2x00usb_vendor_request_sw(rt2x00dev, USB_SINGLE_WRITE, 0x0308, + 0x00f0, REGISTER_TIMEOUT); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); + + rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111); + rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11); + + rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 1); + rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 1); + rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0); + rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 0); + rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0); + rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR5, ®); + rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0, 13); + rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0_VALID, 1); + rt2x00_set_field16(®, TXRX_CSR5_BBP_ID1, 12); + rt2x00_set_field16(®, TXRX_CSR5_BBP_ID1_VALID, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR5, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR6, ®); + rt2x00_set_field16(®, TXRX_CSR6_BBP_ID0, 10); + rt2x00_set_field16(®, TXRX_CSR6_BBP_ID0_VALID, 1); + rt2x00_set_field16(®, TXRX_CSR6_BBP_ID1, 11); + rt2x00_set_field16(®, TXRX_CSR6_BBP_ID1_VALID, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR6, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00_set_field16(®, TXRX_CSR7_BBP_ID0, 7); + rt2x00_set_field16(®, TXRX_CSR7_BBP_ID0_VALID, 1); + rt2x00_set_field16(®, TXRX_CSR7_BBP_ID1, 6); + rt2x00_set_field16(®, TXRX_CSR7_BBP_ID1_VALID, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR7, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00_set_field16(®, TXRX_CSR8_BBP_ID0, 5); + rt2x00_set_field16(®, TXRX_CSR8_BBP_ID0_VALID, 1); + rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1, 0); + rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1_VALID, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg); + + rt2500usb_register_write(rt2x00dev, TXRX_CSR21, 0xe78f); + rt2500usb_register_write(rt2x00dev, MAC_CSR9, 0xff1d); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 0); + rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 1); + rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); + + if (rt2x00_get_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) { + rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); + reg &= ~0x0002; + } else { + reg = 0x3002; + } + rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg); + + rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0002); + rt2500usb_register_write(rt2x00dev, MAC_CSR22, 0x0053); + rt2500usb_register_write(rt2x00dev, MAC_CSR15, 0x01ee); + rt2500usb_register_write(rt2x00dev, MAC_CSR16, 0x0000); + + rt2500usb_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field16(®, MAC_CSR8_MAX_FRAME_UNIT, + rt2x00dev->rx->data_size); + rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0xff); + rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); + rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, 90); + rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); + + rt2500usb_register_read(rt2x00dev, PHY_CSR4, ®); + rt2x00_set_field16(®, PHY_CSR4_LOW_RF_LE, 1); + rt2500usb_register_write(rt2x00dev, PHY_CSR4, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00_set_field16(®, TXRX_CSR1_AUTO_SEQUENCE, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); + + return 0; +} + +static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 value; + u8 reg_id; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500usb_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt2500usb_bbp_write(rt2x00dev, 3, 0x02); + rt2500usb_bbp_write(rt2x00dev, 4, 0x19); + rt2500usb_bbp_write(rt2x00dev, 14, 0x1c); + rt2500usb_bbp_write(rt2x00dev, 15, 0x30); + rt2500usb_bbp_write(rt2x00dev, 16, 0xac); + rt2500usb_bbp_write(rt2x00dev, 18, 0x18); + rt2500usb_bbp_write(rt2x00dev, 19, 0xff); + rt2500usb_bbp_write(rt2x00dev, 20, 0x1e); + rt2500usb_bbp_write(rt2x00dev, 21, 0x08); + rt2500usb_bbp_write(rt2x00dev, 22, 0x08); + rt2500usb_bbp_write(rt2x00dev, 23, 0x08); + rt2500usb_bbp_write(rt2x00dev, 24, 0x80); + rt2500usb_bbp_write(rt2x00dev, 25, 0x50); + rt2500usb_bbp_write(rt2x00dev, 26, 0x08); + rt2500usb_bbp_write(rt2x00dev, 27, 0x23); + rt2500usb_bbp_write(rt2x00dev, 30, 0x10); + rt2500usb_bbp_write(rt2x00dev, 31, 0x2b); + rt2500usb_bbp_write(rt2x00dev, 32, 0xb9); + rt2500usb_bbp_write(rt2x00dev, 34, 0x12); + rt2500usb_bbp_write(rt2x00dev, 35, 0x50); + rt2500usb_bbp_write(rt2x00dev, 39, 0xc4); + rt2500usb_bbp_write(rt2x00dev, 40, 0x02); + rt2500usb_bbp_write(rt2x00dev, 41, 0x60); + rt2500usb_bbp_write(rt2x00dev, 53, 0x10); + rt2500usb_bbp_write(rt2x00dev, 54, 0x18); + rt2500usb_bbp_write(rt2x00dev, 56, 0x08); + rt2500usb_bbp_write(rt2x00dev, 57, 0x10); + rt2500usb_bbp_write(rt2x00dev, 58, 0x08); + rt2500usb_bbp_write(rt2x00dev, 61, 0x60); + rt2500usb_bbp_write(rt2x00dev, 62, 0x10); + rt2500usb_bbp_write(rt2x00dev, 75, 0xff); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt2500usb_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u16 reg; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); +} + +static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Initialize all registers. + */ + if (rt2500usb_init_registers(rt2x00dev) || + rt2500usb_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + rt2x00usb_enable_radio(rt2x00dev); + + /* + * Enable LED + */ + rt2500usb_enable_led(rt2x00dev); + + return 0; +} + +static void rt2500usb_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Disable LED + */ + rt2500usb_disable_led(rt2x00dev); + + rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x2121); + rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x2121); + + /* + * Disable synchronisation. + */ + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + + rt2x00usb_disable_radio(rt2x00dev); +} + +static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u16 reg; + u16 reg2; + unsigned int i; + char put_to_sleep; + char bbp_state; + char rf_state; + + put_to_sleep = (state != STATE_AWAKE); + + reg = 0; + rt2x00_set_field16(®, MAC_CSR17_BBP_DESIRE_STATE, state); + rt2x00_set_field16(®, MAC_CSR17_RF_DESIRE_STATE, state); + rt2x00_set_field16(®, MAC_CSR17_PUT_TO_SLEEP, put_to_sleep); + rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg); + rt2x00_set_field16(®, MAC_CSR17_SET_STATE, 1); + rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500usb_register_read(rt2x00dev, MAC_CSR17, ®2); + bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE); + rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE); + if (bbp_state == state && rf_state == state) + return 0; + rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg); + msleep(30); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state: bbp %d and rf %d.\n", + state, bbp_state, rf_state); + + return -EBUSY; +} + +static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt2500usb_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt2500usb_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt2500usb_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2500usb_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_AIFS, desc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_OFDM, + test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, + !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u16 reg; + + if (queue != IEEE80211_TX_QUEUE_BEACON) + return; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) { + 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. + */ + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + } +} + +/* + * RX control handlers + */ +static int rt2500usb_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct urb *urb = entry->priv; + struct data_desc *rxd = (struct data_desc *)(entry->skb->data + + (urb->actual_length - + entry->ring->desc_size)); + u32 word0; + u32 word1; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 1, &word1); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + return 0; +} + +/* + * Interrupt functions. + */ +static void rt2500usb_beacondone(struct urb *urb) +{ + struct data_entry *entry = (struct data_entry *)urb->context; + struct data_ring *ring = entry->ring; + + if (!test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) + return; + + /* + * Check if this was the guardian beacon, + * if that was the case we need to send the real beacon now. + * Otherwise we should free the sk_buffer, the device + * should be doing the rest of the work now. + */ + if (ring->index == 1) { + rt2x00_ring_index_done_inc(ring); + entry = rt2x00_get_data_entry(ring); + usb_submit_urb(entry->priv, GFP_ATOMIC); + rt2x00_ring_index_inc(ring); + } else if (ring->index_done == 1) { + entry = rt2x00_get_data_entry_done(ring); + if (entry->skb) { + dev_kfree_skb(entry->skb); + entry->skb = NULL; + } + rt2x00_ring_index_done_inc(ring); + } +} + +/* + * Device probe functions. + */ +static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + u8 *mac; + + rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, + DEFAULT_RSSI_OFFSET); + rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word); + EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_THRESHOLD, 45); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE, word); + EEPROM(rt2x00dev, "BBPtune: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); + EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_LOW, 0x48); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word); + EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_LOW, 0x40); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_HIGH, 0x80); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R24, word); + EEPROM(rt2x00dev, "BBPtune r24: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_LOW, 0x40); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_HIGH, 0x50); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R25, word); + EEPROM(rt2x00dev, "BBPtune r25: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_LOW, 0x60); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_HIGH, 0x6d); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R61, word); + EEPROM(rt2x00dev, "BBPtune r61: 0x%04x\n", word); + } + + return 0; +} + +static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2570, value, reg); + + if (rt2x00_rev(&rt2x00dev->chip, 0xffff0)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } + + if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && + !rt2x00_rf(&rt2x00dev->chip, RF2523) && + !rt2x00_rf(&rt2x00dev->chip, RF2524) && + !rt2x00_rf(&rt2x00dev->chip, RF2525) && + !rt2x00_rf(&rt2x00dev->chip, RF2525E) && + !rt2x00_rf(&rt2x00dev->chip, RF5222)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Store led mode, for correct led behaviour. + */ + rt2x00dev->led_mode = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + /* + * Check if the BBP tuning should be disabled. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) + __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); + + /* + * Read the RSSI <-> dBm offset information. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); + rt2x00dev->rssi_offset = + rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); + + return 0; +} + +/* + * RF value list for RF2522 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2522[] = { + { 1, 0x00002050, 0x000c1fda, 0x00000101, 0 }, + { 2, 0x00002050, 0x000c1fee, 0x00000101, 0 }, + { 3, 0x00002050, 0x000c2002, 0x00000101, 0 }, + { 4, 0x00002050, 0x000c2016, 0x00000101, 0 }, + { 5, 0x00002050, 0x000c202a, 0x00000101, 0 }, + { 6, 0x00002050, 0x000c203e, 0x00000101, 0 }, + { 7, 0x00002050, 0x000c2052, 0x00000101, 0 }, + { 8, 0x00002050, 0x000c2066, 0x00000101, 0 }, + { 9, 0x00002050, 0x000c207a, 0x00000101, 0 }, + { 10, 0x00002050, 0x000c208e, 0x00000101, 0 }, + { 11, 0x00002050, 0x000c20a2, 0x00000101, 0 }, + { 12, 0x00002050, 0x000c20b6, 0x00000101, 0 }, + { 13, 0x00002050, 0x000c20ca, 0x00000101, 0 }, + { 14, 0x00002050, 0x000c20fa, 0x00000101, 0 }, +}; + +/* + * RF value list for RF2523 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2523[] = { + { 1, 0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b }, + { 2, 0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b }, + { 3, 0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b }, + { 4, 0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b }, + { 5, 0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b }, + { 6, 0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b }, + { 7, 0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b }, + { 8, 0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b }, + { 9, 0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b }, + { 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b }, + { 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b }, + { 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b }, + { 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b }, + { 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 }, +}; + +/* + * RF value list for RF2524 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2524[] = { + { 1, 0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b }, + { 2, 0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b }, + { 3, 0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b }, + { 4, 0x00032020, 0x00000caa, 0x00000101, 0x00000a1b }, + { 5, 0x00032020, 0x00000cae, 0x00000101, 0x00000a1b }, + { 6, 0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b }, + { 7, 0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b }, + { 8, 0x00032020, 0x00000cba, 0x00000101, 0x00000a1b }, + { 9, 0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b }, + { 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b }, + { 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b }, + { 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b }, + { 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b }, + { 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 }, +}; + +/* + * RF value list for RF2525 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2525[] = { + { 1, 0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b }, + { 2, 0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b }, + { 3, 0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b }, + { 4, 0x00022020, 0x00080caa, 0x00060111, 0x00000a1b }, + { 5, 0x00022020, 0x00080cae, 0x00060111, 0x00000a1b }, + { 6, 0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b }, + { 7, 0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b }, + { 8, 0x00022020, 0x00080cba, 0x00060111, 0x00000a1b }, + { 9, 0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b }, + { 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b }, + { 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b }, + { 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b }, + { 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b }, + { 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 }, +}; + +/* + * RF value list for RF2525e + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2525e[] = { + { 1, 0x00022010, 0x0000089a, 0x00060111, 0x00000e1b }, + { 2, 0x00022010, 0x0000089e, 0x00060111, 0x00000e07 }, + { 3, 0x00022010, 0x0000089e, 0x00060111, 0x00000e1b }, + { 4, 0x00022010, 0x000008a2, 0x00060111, 0x00000e07 }, + { 5, 0x00022010, 0x000008a2, 0x00060111, 0x00000e1b }, + { 6, 0x00022010, 0x000008a6, 0x00060111, 0x00000e07 }, + { 7, 0x00022010, 0x000008a6, 0x00060111, 0x00000e1b }, + { 8, 0x00022010, 0x000008aa, 0x00060111, 0x00000e07 }, + { 9, 0x00022010, 0x000008aa, 0x00060111, 0x00000e1b }, + { 10, 0x00022010, 0x000008ae, 0x00060111, 0x00000e07 }, + { 11, 0x00022010, 0x000008ae, 0x00060111, 0x00000e1b }, + { 12, 0x00022010, 0x000008b2, 0x00060111, 0x00000e07 }, + { 13, 0x00022010, 0x000008b2, 0x00060111, 0x00000e1b }, + { 14, 0x00022010, 0x000008b6, 0x00060111, 0x00000e23 }, +}; + +/* + * RF value list for RF5222 + * Supports: 2.4 GHz & 5.2 GHz + */ +static const struct rf_channel rf_vals_5222[] = { + { 1, 0x00022020, 0x00001136, 0x00000101, 0x00000a0b }, + { 2, 0x00022020, 0x0000113a, 0x00000101, 0x00000a0b }, + { 3, 0x00022020, 0x0000113e, 0x00000101, 0x00000a0b }, + { 4, 0x00022020, 0x00001182, 0x00000101, 0x00000a0b }, + { 5, 0x00022020, 0x00001186, 0x00000101, 0x00000a0b }, + { 6, 0x00022020, 0x0000118a, 0x00000101, 0x00000a0b }, + { 7, 0x00022020, 0x0000118e, 0x00000101, 0x00000a0b }, + { 8, 0x00022020, 0x00001192, 0x00000101, 0x00000a0b }, + { 9, 0x00022020, 0x00001196, 0x00000101, 0x00000a0b }, + { 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b }, + { 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b }, + { 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b }, + { 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b }, + { 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f }, + { 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f }, + { 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f }, + { 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f }, + { 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f }, + { 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f }, + { 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f }, + { 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f }, + { 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f }, + { 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f }, + { 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f }, + { 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f }, + { 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f }, + { 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f }, + { 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f }, + { 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f }, + { 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f }, + + /* 802.11 UNII */ + { 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f }, + { 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 }, + { 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 }, + { 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 }, + { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 }, +}; + +static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 2; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 2; + spec->num_rates = 12; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); + spec->channels = rf_vals_bg_2522; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); + spec->channels = rf_vals_bg_2523; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); + spec->channels = rf_vals_bg_2524; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); + spec->channels = rf_vals_bg_2525; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); + spec->channels = rf_vals_bg_2525e; + } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { + spec->num_channels = ARRAY_SIZE(rf_vals_5222); + spec->channels = rf_vals_5222; + spec->num_modes = 3; + } +} + +static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2500usb_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2500usb_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt2500usb_probe_hw_mode(rt2x00dev); + + /* + * USB devices require scheduled packet filter toggling + *This device requires the beacon ring + */ + __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); + __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt2500usb_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + struct data_ring *ring = + rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct data_entry *beacon; + struct data_entry *guardian; + int length; + + /* + * Just in case the ieee80211 doesn't set this, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; + + /* + * Obtain 2 entries, one for the guardian byte, + * the second for the actual beacon. + */ + guardian = rt2x00_get_data_entry(ring); + rt2x00_ring_index_inc(ring); + beacon = rt2x00_get_data_entry(ring); + + /* + * First we create the beacon. + */ + skb_push(skb, ring->desc_size); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, + (struct ieee80211_hdr *)(skb->data + + ring->desc_size), + skb->len - ring->desc_size, control); + + /* + * Length passed to usb_fill_urb cannot be an odd number, + * so add 1 byte to make it even. + */ + length = skb->len; + if (length % 2) + length++; + + usb_fill_bulk_urb(beacon->priv, usb_dev, + usb_sndbulkpipe(usb_dev, 1), + skb->data, length, rt2500usb_beacondone, beacon); + + beacon->skb = skb; + + /* + * Second we need to create the guardian byte. + * We only need a single byte, so lets recycle + * the 'flags' field we are not using for beacons. + */ + guardian->flags = 0; + usb_fill_bulk_urb(guardian->priv, usb_dev, + usb_sndbulkpipe(usb_dev, 1), + &guardian->flags, 1, rt2500usb_beacondone, guardian); + + /* + * Send out the guardian byte. + */ + usb_submit_urb(guardian->priv, GFP_ATOMIC); + + /* + * Enable beacon generation. + */ + rt2500usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + return 0; +} + +static const struct ieee80211_ops rt2500usb_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .beacon_update = rt2500usb_beacon_update, +}; + +static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { + .probe_hw = rt2500usb_probe_hw, + .initialize = rt2x00usb_initialize, + .uninitialize = rt2x00usb_uninitialize, + .set_device_state = rt2500usb_set_device_state, + .link_stats = rt2500usb_link_stats, + .reset_tuner = rt2500usb_reset_tuner, + .link_tuner = rt2500usb_link_tuner, + .write_tx_desc = rt2500usb_write_tx_desc, + .write_tx_data = rt2x00usb_write_tx_data, + .kick_tx_queue = rt2500usb_kick_tx_queue, + .fill_rxdone = rt2500usb_fill_rxdone, + .config_mac_addr = rt2500usb_config_mac_addr, + .config_bssid = rt2500usb_config_bssid, + .config_packet_filter = rt2500usb_config_packet_filter, + .config_type = rt2500usb_config_type, + .config = rt2500usb_config, +}; + +static const struct rt2x00_ops rt2500usb_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt2500usb_rt2x00_ops, + .hw = &rt2500usb_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2500usb_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * rt2500usb module information. + */ +static struct usb_device_id rt2500usb_device_table[] = { + /* ASUS */ + { USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Cisco Systems */ + { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* D-LINK */ + { USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Hercules */ + { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Melco */ + { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) }, + + /* MSI */ + { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Siemens */ + { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* SMC */ + { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Spairon */ + { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Trust */ + { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2500 USB Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards"); +MODULE_DEVICE_TABLE(usb, rt2500usb_device_table); +MODULE_LICENSE("GPL"); + +static struct usb_driver rt2500usb_driver = { + .name = DRV_NAME, + .id_table = rt2500usb_device_table, + .probe = rt2x00usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +}; + +static int __init rt2500usb_init(void) +{ + return usb_register(&rt2500usb_driver); +} + +static void __exit rt2500usb_exit(void) +{ + usb_deregister(&rt2500usb_driver); +} + +module_init(rt2500usb_init); +module_exit(rt2500usb_exit); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h new file mode 100644 index 000000000000..b18d56e73cf1 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -0,0 +1,798 @@ +/* + Copyright (C) 2004 - 2007 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: rt2500usb + Abstract: Data structures and registers for the rt2500usb module. + Supported chipsets: RT2570. + */ + +#ifndef RT2500USB_H +#define RT2500USB_H + +/* + * RF chip defines. + */ +#define RF2522 0x0000 +#define RF2523 0x0001 +#define RF2524 0x0002 +#define RF2525 0x0003 +#define RF2525E 0x0005 +#define RF5222 0x0010 + +/* + * RT2570 version + */ +#define RT2570_VERSION_B 2 +#define RT2570_VERSION_C 3 +#define RT2570_VERSION_D 4 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 120 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x0400 +#define CSR_REG_SIZE 0x0100 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x006a +#define BBP_SIZE 0x0060 +#define RF_SIZE 0x0014 + +/* + * Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + */ +#define MAC_CSR0 0x0400 + +/* + * MAC_CSR1: System control. + * SOFT_RESET: Software reset, 1: reset, 0: normal. + * BBP_RESET: Hardware reset, 1: reset, 0, release. + * HOST_READY: Host ready after initialization. + */ +#define MAC_CSR1 0x0402 +#define MAC_CSR1_SOFT_RESET FIELD16(0x00000001) +#define MAC_CSR1_BBP_RESET FIELD16(0x00000002) +#define MAC_CSR1_HOST_READY FIELD16(0x00000004) + +/* + * MAC_CSR2: STA MAC register 0. + */ +#define MAC_CSR2 0x0404 +#define MAC_CSR2_BYTE0 FIELD16(0x00ff) +#define MAC_CSR2_BYTE1 FIELD16(0xff00) + +/* + * MAC_CSR3: STA MAC register 1. + */ +#define MAC_CSR3 0x0406 +#define MAC_CSR3_BYTE2 FIELD16(0x00ff) +#define MAC_CSR3_BYTE3 FIELD16(0xff00) + +/* + * MAC_CSR4: STA MAC register 2. + */ +#define MAC_CSR4 0X0408 +#define MAC_CSR4_BYTE4 FIELD16(0x00ff) +#define MAC_CSR4_BYTE5 FIELD16(0xff00) + +/* + * MAC_CSR5: BSSID register 0. + */ +#define MAC_CSR5 0x040a +#define MAC_CSR5_BYTE0 FIELD16(0x00ff) +#define MAC_CSR5_BYTE1 FIELD16(0xff00) + +/* + * MAC_CSR6: BSSID register 1. + */ +#define MAC_CSR6 0x040c +#define MAC_CSR6_BYTE2 FIELD16(0x00ff) +#define MAC_CSR6_BYTE3 FIELD16(0xff00) + +/* + * MAC_CSR7: BSSID register 2. + */ +#define MAC_CSR7 0x040e +#define MAC_CSR7_BYTE4 FIELD16(0x00ff) +#define MAC_CSR7_BYTE5 FIELD16(0xff00) + +/* + * MAC_CSR8: Max frame length. + */ +#define MAC_CSR8 0x0410 +#define MAC_CSR8_MAX_FRAME_UNIT FIELD16(0x0fff) + +/* + * Misc MAC_CSR registers. + * MAC_CSR9: Timer control. + * MAC_CSR10: Slot time. + * MAC_CSR11: IFS. + * MAC_CSR12: EIFS. + * MAC_CSR13: Power mode0. + * MAC_CSR14: Power mode1. + * MAC_CSR15: Power saving transition0 + * MAC_CSR16: Power saving transition1 + */ +#define MAC_CSR9 0x0412 +#define MAC_CSR10 0x0414 +#define MAC_CSR11 0x0416 +#define MAC_CSR12 0x0418 +#define MAC_CSR13 0x041a +#define MAC_CSR14 0x041c +#define MAC_CSR15 0x041e +#define MAC_CSR16 0x0420 + +/* + * MAC_CSR17: Manual power control / status register. + * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake. + * SET_STATE: Set state. Write 1 to trigger, self cleared. + * BBP_DESIRE_STATE: BBP desired state. + * RF_DESIRE_STATE: RF desired state. + * BBP_CURRENT_STATE: BBP current state. + * RF_CURRENT_STATE: RF current state. + * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared. + */ +#define MAC_CSR17 0x0422 +#define MAC_CSR17_SET_STATE FIELD16(0x0001) +#define MAC_CSR17_BBP_DESIRE_STATE FIELD16(0x0006) +#define MAC_CSR17_RF_DESIRE_STATE FIELD16(0x0018) +#define MAC_CSR17_BBP_CURR_STATE FIELD16(0x0060) +#define MAC_CSR17_RF_CURR_STATE FIELD16(0x0180) +#define MAC_CSR17_PUT_TO_SLEEP FIELD16(0x0200) + +/* + * MAC_CSR18: Wakeup timer register. + * DELAY_AFTER_BEACON: Delay after Tbcn expired in units of 1/16 TU. + * BEACONS_BEFORE_WAKEUP: Number of beacon before wakeup. + * AUTO_WAKE: Enable auto wakeup / sleep mechanism. + */ +#define MAC_CSR18 0x0424 +#define MAC_CSR18_DELAY_AFTER_BEACON FIELD16(0x00ff) +#define MAC_CSR18_BEACONS_BEFORE_WAKEUP FIELD16(0x7f00) +#define MAC_CSR18_AUTO_WAKE FIELD16(0x8000) + +/* + * MAC_CSR19: GPIO control register. + */ +#define MAC_CSR19 0x0426 + +/* + * MAC_CSR20: LED control register. + * ACTIVITY: 0: idle, 1: active. + * LINK: 0: linkoff, 1: linkup. + * ACTIVITY_POLARITY: 0: active low, 1: active high. + */ +#define MAC_CSR20 0x0428 +#define MAC_CSR20_ACTIVITY FIELD16(0x0001) +#define MAC_CSR20_LINK FIELD16(0x0002) +#define MAC_CSR20_ACTIVITY_POLARITY FIELD16(0x0004) + +/* + * MAC_CSR21: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + */ +#define MAC_CSR21 0x042a +#define MAC_CSR21_ON_PERIOD FIELD16(0x00ff) +#define MAC_CSR21_OFF_PERIOD FIELD16(0xff00) + +/* + * Collision window control register. + */ +#define MAC_CSR22 0x042c + +/* + * Transmit related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXRX_CSR0: Security control register. + */ +#define TXRX_CSR0 0x0440 +#define TXRX_CSR0_ALGORITHM FIELD16(0x0007) +#define TXRX_CSR0_IV_OFFSET FIELD16(0x01f8) +#define TXRX_CSR0_KEY_ID FIELD16(0x1e00) + +/* + * TXRX_CSR1: TX configuration. + * ACK_TIMEOUT: ACK Timeout in unit of 1-us. + * TSF_OFFSET: TSF offset in MAC header. + * AUTO_SEQUENCE: Let ASIC control frame sequence number. + */ +#define TXRX_CSR1 0x0442 +#define TXRX_CSR1_ACK_TIMEOUT FIELD16(0x00ff) +#define TXRX_CSR1_TSF_OFFSET FIELD16(0x7f00) +#define TXRX_CSR1_AUTO_SEQUENCE FIELD16(0x8000) + +/* + * TXRX_CSR2: RX control. + * DISABLE_RX: Disable rx engine. + * DROP_CRC: Drop crc error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TODS: Drop frame tods bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * DROP_MCAST: Drop multicast frames. + * DROP_BCAST: Drop broadcast frames. + */ +#define TXRX_CSR2 0x0444 +#define TXRX_CSR2_DISABLE_RX FIELD16(0x0001) +#define TXRX_CSR2_DROP_CRC FIELD16(0x0002) +#define TXRX_CSR2_DROP_PHYSICAL FIELD16(0x0004) +#define TXRX_CSR2_DROP_CONTROL FIELD16(0x0008) +#define TXRX_CSR2_DROP_NOT_TO_ME FIELD16(0x0010) +#define TXRX_CSR2_DROP_TODS FIELD16(0x0020) +#define TXRX_CSR2_DROP_VERSION_ERROR FIELD16(0x0040) +#define TXRX_CSR2_DROP_MULTICAST FIELD16(0x0200) +#define TXRX_CSR2_DROP_BROADCAST FIELD16(0x0400) + +/* + * RX BBP ID registers + * TXRX_CSR3: CCK RX BBP ID. + * TXRX_CSR4: OFDM RX BBP ID. + */ +#define TXRX_CSR3 0x0446 +#define TXRX_CSR4 0x0448 + +/* + * TXRX_CSR5: CCK TX BBP ID0. + */ +#define TXRX_CSR5 0x044a +#define TXRX_CSR5_BBP_ID0 FIELD16(0x007f) +#define TXRX_CSR5_BBP_ID0_VALID FIELD16(0x0080) +#define TXRX_CSR5_BBP_ID1 FIELD16(0x7f00) +#define TXRX_CSR5_BBP_ID1_VALID FIELD16(0x8000) + +/* + * TXRX_CSR6: CCK TX BBP ID1. + */ +#define TXRX_CSR6 0x044c +#define TXRX_CSR6_BBP_ID0 FIELD16(0x007f) +#define TXRX_CSR6_BBP_ID0_VALID FIELD16(0x0080) +#define TXRX_CSR6_BBP_ID1 FIELD16(0x7f00) +#define TXRX_CSR6_BBP_ID1_VALID FIELD16(0x8000) + +/* + * TXRX_CSR7: OFDM TX BBP ID0. + */ +#define TXRX_CSR7 0x044e +#define TXRX_CSR7_BBP_ID0 FIELD16(0x007f) +#define TXRX_CSR7_BBP_ID0_VALID FIELD16(0x0080) +#define TXRX_CSR7_BBP_ID1 FIELD16(0x7f00) +#define TXRX_CSR7_BBP_ID1_VALID FIELD16(0x8000) + +/* + * TXRX_CSR5: OFDM TX BBP ID1. + */ +#define TXRX_CSR8 0x0450 +#define TXRX_CSR8_BBP_ID0 FIELD16(0x007f) +#define TXRX_CSR8_BBP_ID0_VALID FIELD16(0x0080) +#define TXRX_CSR8_BBP_ID1 FIELD16(0x7f00) +#define TXRX_CSR8_BBP_ID1_VALID FIELD16(0x8000) + +/* + * TXRX_CSR9: TX ACK time-out. + */ +#define TXRX_CSR9 0x0452 + +/* + * TXRX_CSR10: Auto responder control. + */ +#define TXRX_CSR10 0x0454 +#define TXRX_CSR10_AUTORESPOND_PREAMBLE FIELD16(0x0004) + +/* + * TXRX_CSR11: Auto responder basic rate. + */ +#define TXRX_CSR11 0x0456 + +/* + * ACK/CTS time registers. + */ +#define TXRX_CSR12 0x0458 +#define TXRX_CSR13 0x045a +#define TXRX_CSR14 0x045c +#define TXRX_CSR15 0x045e +#define TXRX_CSR16 0x0460 +#define TXRX_CSR17 0x0462 + +/* + * TXRX_CSR18: Synchronization control register. + */ +#define TXRX_CSR18 0x0464 +#define TXRX_CSR18_OFFSET FIELD16(0x000f) +#define TXRX_CSR18_INTERVAL FIELD16(0xfff0) + +/* + * TXRX_CSR19: Synchronization control register. + * TSF_COUNT: Enable TSF auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * TBCN: Enable Tbcn with reload value. + * BEACON_GEN: Enable beacon generator. + */ +#define TXRX_CSR19 0x0466 +#define TXRX_CSR19_TSF_COUNT FIELD16(0x0001) +#define TXRX_CSR19_TSF_SYNC FIELD16(0x0006) +#define TXRX_CSR19_TBCN FIELD16(0x0008) +#define TXRX_CSR19_BEACON_GEN FIELD16(0x0010) + +/* + * TXRX_CSR20: Tx BEACON offset time control register. + * OFFSET: In units of usec. + * BCN_EXPECT_WINDOW: Default: 2^CWmin + */ +#define TXRX_CSR20 0x0468 +#define TXRX_CSR20_OFFSET FIELD16(0x1fff) +#define TXRX_CSR20_BCN_EXPECT_WINDOW FIELD16(0xe000) + +/* + * TXRX_CSR21 + */ +#define TXRX_CSR21 0x046a + +/* + * Encryption related CSRs. + * + */ + +/* + * SEC_CSR0-SEC_CSR7: Shared key 0, word 0-7 + */ +#define SEC_CSR0 0x0480 +#define SEC_CSR1 0x0482 +#define SEC_CSR2 0x0484 +#define SEC_CSR3 0x0486 +#define SEC_CSR4 0x0488 +#define SEC_CSR5 0x048a +#define SEC_CSR6 0x048c +#define SEC_CSR7 0x048e + +/* + * SEC_CSR8-SEC_CSR15: Shared key 1, word 0-7 + */ +#define SEC_CSR8 0x0490 +#define SEC_CSR9 0x0492 +#define SEC_CSR10 0x0494 +#define SEC_CSR11 0x0496 +#define SEC_CSR12 0x0498 +#define SEC_CSR13 0x049a +#define SEC_CSR14 0x049c +#define SEC_CSR15 0x049e + +/* + * SEC_CSR16-SEC_CSR23: Shared key 2, word 0-7 + */ +#define SEC_CSR16 0x04a0 +#define SEC_CSR17 0x04a2 +#define SEC_CSR18 0X04A4 +#define SEC_CSR19 0x04a6 +#define SEC_CSR20 0x04a8 +#define SEC_CSR21 0x04aa +#define SEC_CSR22 0x04ac +#define SEC_CSR23 0x04ae + +/* + * SEC_CSR24-SEC_CSR31: Shared key 3, word 0-7 + */ +#define SEC_CSR24 0x04b0 +#define SEC_CSR25 0x04b2 +#define SEC_CSR26 0x04b4 +#define SEC_CSR27 0x04b6 +#define SEC_CSR28 0x04b8 +#define SEC_CSR29 0x04ba +#define SEC_CSR30 0x04bc +#define SEC_CSR31 0x04be + +/* + * PHY control registers. + */ + +/* + * PHY_CSR0: RF switching timing control. + */ +#define PHY_CSR0 0x04c0 + +/* + * PHY_CSR1: TX PA configuration. + */ +#define PHY_CSR1 0x04c2 + +/* + * MAC configuration registers. + * PHY_CSR2: TX MAC configuration. + * PHY_CSR3: RX MAC configuration. + */ +#define PHY_CSR2 0x04c4 +#define PHY_CSR3 0x04c6 + +/* + * PHY_CSR4: Interface configuration. + */ +#define PHY_CSR4 0x04c8 +#define PHY_CSR4_LOW_RF_LE FIELD16(0x0001) + +/* + * BBP pre-TX registers. + * PHY_CSR5: BBP pre-TX CCK. + */ +#define PHY_CSR5 0x04ca +#define PHY_CSR5_CCK FIELD16(0x0003) +#define PHY_CSR5_CCK_FLIP FIELD16(0x0004) + +/* + * BBP pre-TX registers. + * PHY_CSR6: BBP pre-TX OFDM. + */ +#define PHY_CSR6 0x04cc +#define PHY_CSR6_OFDM FIELD16(0x0003) +#define PHY_CSR6_OFDM_FLIP FIELD16(0x0004) + +/* + * PHY_CSR7: BBP access register 0. + * BBP_DATA: BBP data. + * BBP_REG_ID: BBP register ID. + * BBP_READ_CONTROL: 0: write, 1: read. + */ +#define PHY_CSR7 0x04ce +#define PHY_CSR7_DATA FIELD16(0x00ff) +#define PHY_CSR7_REG_ID FIELD16(0x7f00) +#define PHY_CSR7_READ_CONTROL FIELD16(0x8000) + +/* + * PHY_CSR8: BBP access register 1. + * BBP_BUSY: ASIC is busy execute BBP programming. + */ +#define PHY_CSR8 0x04d0 +#define PHY_CSR8_BUSY FIELD16(0x0001) + +/* + * PHY_CSR9: RF access register. + * RF_VALUE: Register value + id to program into rf/if. + */ +#define PHY_CSR9 0x04d2 +#define PHY_CSR9_RF_VALUE FIELD16(0xffff) + +/* + * PHY_CSR10: RF access register. + * RF_VALUE: Register value + id to program into rf/if. + * RF_NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22). + * RF_IF_SELECT: Chip to program: 0: rf, 1: if. + * RF_PLL_LD: Rf pll_ld status. + * RF_BUSY: 1: asic is busy execute rf programming. + */ +#define PHY_CSR10 0x04d4 +#define PHY_CSR10_RF_VALUE FIELD16(0x00ff) +#define PHY_CSR10_RF_NUMBER_OF_BITS FIELD16(0x1f00) +#define PHY_CSR10_RF_IF_SELECT FIELD16(0x2000) +#define PHY_CSR10_RF_PLL_LD FIELD16(0x4000) +#define PHY_CSR10_RF_BUSY FIELD16(0x8000) + +/* + * STA_CSR0: FCS error count. + * FCS_ERROR: FCS error count, cleared when read. + */ +#define STA_CSR0 0x04e0 +#define STA_CSR0_FCS_ERROR FIELD16(0xffff) + +/* + * STA_CSR1: PLCP error count. + */ +#define STA_CSR1 0x04e2 + +/* + * STA_CSR2: LONG error count. + */ +#define STA_CSR2 0x04e4 + +/* + * STA_CSR3: CCA false alarm. + * FALSE_CCA_ERROR: False CCA error count, cleared when read. + */ +#define STA_CSR3 0x04e6 +#define STA_CSR3_FALSE_CCA_ERROR FIELD16(0xffff) + +/* + * STA_CSR4: RX FIFO overflow. + */ +#define STA_CSR4 0x04e8 + +/* + * STA_CSR5: Beacon sent counter. + */ +#define STA_CSR5 0x04ea + +/* + * Statistics registers + */ +#define STA_CSR6 0x04ec +#define STA_CSR7 0x04ee +#define STA_CSR8 0x04f0 +#define STA_CSR9 0x04f2 +#define STA_CSR10 0x04f4 + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R2: TX antenna control + */ +#define BBP_R2_TX_ANTENNA FIELD8(0x03) +#define BBP_R2_TX_IQ_FLIP FIELD8(0x04) + +/* + * R14: RX antenna control + */ +#define BBP_R14_RX_ANTENNA FIELD8(0x03) +#define BBP_R14_RX_IQ_FLIP FIELD8(0x04) + +/* + * RF registers. + */ + +/* + * RF 1 + */ +#define RF1_TUNER FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TUNER FIELD32(0x00000100) +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * EEPROM contents. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * LED_MODE: 0: default, 1: TX/RX activity, 2: Single (ignore link), 3: rsvd. + * DYN_TXAGC: Dynamic TX AGC control. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + * RF_TYPE: Rf_type of this adapter. + */ +#define EEPROM_ANTENNA 0x000b +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0) +#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800) + +/* + * EEPROM NIC config. + * CARDBUS_ACCEL: 0: enable, 1: disable. + * DYN_BBP_TUNE: 0: enable, 1: disable. + * CCK_TX_POWER: CCK TX power compensation. + */ +#define EEPROM_NIC 0x000c +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001) +#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002) +#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c) + +/* + * EEPROM geography. + * GEO: Default geography setting for device. + */ +#define EEPROM_GEOGRAPHY 0x000d +#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x000e +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER + */ +#define EEPROM_TXPOWER_START 0x001e +#define EEPROM_TXPOWER_SIZE 7 +#define EEPROM_TXPOWER_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_2 FIELD16(0xff00) + +/* + * EEPROM Tuning threshold + */ +#define EEPROM_BBPTUNE 0x0030 +#define EEPROM_BBPTUNE_THRESHOLD FIELD16(0x00ff) + +/* + * EEPROM BBP R24 Tuning. + */ +#define EEPROM_BBPTUNE_R24 0x0031 +#define EEPROM_BBPTUNE_R24_LOW FIELD16(0x00ff) +#define EEPROM_BBPTUNE_R24_HIGH FIELD16(0xff00) + +/* + * EEPROM BBP R25 Tuning. + */ +#define EEPROM_BBPTUNE_R25 0x0032 +#define EEPROM_BBPTUNE_R25_LOW FIELD16(0x00ff) +#define EEPROM_BBPTUNE_R25_HIGH FIELD16(0xff00) + +/* + * EEPROM BBP R24 Tuning. + */ +#define EEPROM_BBPTUNE_R61 0x0033 +#define EEPROM_BBPTUNE_R61_LOW FIELD16(0x00ff) +#define EEPROM_BBPTUNE_R61_HIGH FIELD16(0xff00) + +/* + * EEPROM BBP VGC Tuning. + */ +#define EEPROM_BBPTUNE_VGC 0x0034 +#define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff) + +/* + * EEPROM BBP R17 Tuning. + */ +#define EEPROM_BBPTUNE_R17 0x0035 +#define EEPROM_BBPTUNE_R17_LOW FIELD16(0x00ff) +#define EEPROM_BBPTUNE_R17_HIGH FIELD16(0xff00) + +/* + * RSSI <-> dBm offset calibration + */ +#define EEPROM_CALIBRATE_OFFSET 0x0036 +#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff) + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 5 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 4 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_PACKET_ID FIELD32(0x0000000f) +#define TXD_W0_RETRY_LIMIT FIELD32(0x000000f0) +#define TXD_W0_MORE_FRAG FIELD32(0x00000100) +#define TXD_W0_ACK FIELD32(0x00000200) +#define TXD_W0_TIMESTAMP FIELD32(0x00000400) +#define TXD_W0_OFDM FIELD32(0x00000800) +#define TXD_W0_NEW_SEQ FIELD32(0x00001000) +#define TXD_W0_IFS FIELD32(0x00006000) +#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define TXD_W0_CIPHER FIELD32(0x20000000) +#define TXD_W0_KEY_ID FIELD32(0xc0000000) + +/* + * Word1 + */ +#define TXD_W1_IV_OFFSET FIELD32(0x0000003f) +#define TXD_W1_AIFS FIELD32(0x000000c0) +#define TXD_W1_CWMIN FIELD32(0x00000f00) +#define TXD_W1_CWMAX FIELD32(0x0000f000) + +/* + * Word2: PLCP information + */ +#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00) +#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000) +#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Word3 + */ +#define TXD_W3_IV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define TXD_W4_EIV FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + */ +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002) +#define RXD_W0_MULTICAST FIELD32(0x00000004) +#define RXD_W0_BROADCAST FIELD32(0x00000008) +#define RXD_W0_MY_BSS FIELD32(0x00000010) +#define RXD_W0_CRC_ERROR FIELD32(0x00000020) +#define RXD_W0_OFDM FIELD32(0x00000040) +#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080) +#define RXD_W0_CIPHER FIELD32(0x00000100) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000200) +#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) + +/* + * Word1 + */ +#define RXD_W1_RSSI FIELD32(0x000000ff) +#define RXD_W1_SIGNAL FIELD32(0x0000ff00) + +/* + * Word2 + */ +#define RXD_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + */ +#define RXD_W3_EIV FIELD32(0xffffffff) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + */ +#define MIN_TXPOWER 0 +#define MAX_TXPOWER 31 +#define DEFAULT_TXPOWER 24 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? \ + DEFAULT_TXPOWER : (__txpower); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ + (__txpower)); \ +}) + +#endif /* RT2500USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h new file mode 100644 index 000000000000..80b079d723d6 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -0,0 +1,807 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00 + Abstract: rt2x00 global information. + */ + +#ifndef RT2X00_H +#define RT2X00_H + +#include +#include +#include +#include +#include + +#include + +#include "rt2x00debug.h" +#include "rt2x00reg.h" +#include "rt2x00ring.h" + +/* + * Module information. + * DRV_NAME should be set within the individual module source files. + */ +#define DRV_VERSION "2.0.8" +#define DRV_PROJECT "http://rt2x00.serialmonkey.com" + +/* + * Debug definitions. + * Debug output has to be enabled during compile time. + */ +#define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...) \ + printk(__kernlvl "%s -> %s: %s - " __msg, \ + wiphy_name((__dev)->hw->wiphy), __FUNCTION__, __lvl, ##__args) + +#define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...) \ + printk(__kernlvl "%s -> %s: %s - " __msg, \ + DRV_NAME, __FUNCTION__, __lvl, ##__args) + +#ifdef CONFIG_RT2X00_DEBUG +#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \ + DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args); +#else +#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \ + do { } while (0) +#endif /* CONFIG_RT2X00_DEBUG */ + +/* + * Various debug levels. + * The debug levels PANIC and ERROR both indicate serious problems, + * for this reason they should never be ignored. + * The special ERROR_PROBE message is for messages that are generated + * when the rt2x00_dev is not yet initialized. + */ +#define PANIC(__dev, __msg, __args...) \ + DEBUG_PRINTK_MSG(__dev, KERN_CRIT, "Panic", __msg, ##__args) +#define ERROR(__dev, __msg, __args...) \ + DEBUG_PRINTK_MSG(__dev, KERN_ERR, "Error", __msg, ##__args) +#define ERROR_PROBE(__msg, __args...) \ + DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args) +#define WARNING(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args) +#define NOTICE(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args) +#define INFO(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args) +#define DEBUG(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args) +#define EEPROM(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args) + +/* + * Ring sizes. + * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes. + * DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings. + * MGMT_FRAME_SIZE is used for the BEACON ring. + */ +#define DATA_FRAME_SIZE 2432 +#define MGMT_FRAME_SIZE 256 + +/* + * Number of entries in a packet ring. + * PCI devices only need 1 Beacon entry, + * but USB devices require a second because they + * have to send a Guardian byte first. + */ +#define RX_ENTRIES 12 +#define TX_ENTRIES 12 +#define ATIM_ENTRIES 1 +#define BEACON_ENTRIES 2 + +/* + * Standard timing and size defines. + * These values should follow the ieee80211 specifications. + */ +#define ACK_SIZE 14 +#define IEEE80211_HEADER 24 +#define PLCP 48 +#define BEACON 100 +#define PREAMBLE 144 +#define SHORT_PREAMBLE 72 +#define SLOT_TIME 20 +#define SHORT_SLOT_TIME 9 +#define SIFS 10 +#define PIFS ( SIFS + SLOT_TIME ) +#define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME ) +#define DIFS ( PIFS + SLOT_TIME ) +#define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) +#define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) ) + +/* + * IEEE802.11 header defines + */ +static inline int is_rts_frame(u16 fc) +{ + return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS)); +} + +static inline int is_cts_frame(u16 fc) +{ + return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS)); +} + +static inline int is_probe_resp(u16 fc) +{ + return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)); +} + +/* + * Chipset identification + * The chipset on the device is composed of a RT and RF chip. + * The chipset combination is important for determining device capabilities. + */ +struct rt2x00_chip { + u16 rt; +#define RT2460 0x0101 +#define RT2560 0x0201 +#define RT2570 0x1201 +#define RT2561 0x0301 +#define RT2561s 0x0302 +#define RT2661 0x0401 +#define RT2571 0x1300 + + u16 rf; + u32 rev; +}; + +/* + * RF register values that belong to a particular channel. + */ +struct rf_channel { + int channel; + u32 rf1; + u32 rf2; + u32 rf3; + u32 rf4; +}; + +/* + * To optimize the quality of the link we need to store + * the quality of received frames and periodically + * optimize the link. + */ +struct link { + /* + * Link tuner counter + * The number of times the link has been tuned + * since the radio has been switched on. + */ + u32 count; + + /* + * Statistics required for Link tuning. + * For the average RSSI value we use the "Walking average" approach. + * When adding RSSI to the average value the following calculation + * is needed: + * + * avg_rssi = ((avg_rssi * 7) + rssi) / 8; + * + * The advantage of this approach is that we only need 1 variable + * to store the average in (No need for a count and a total). + * But more importantly, normal average values will over time + * move less and less towards newly added values this results + * that with link tuning, the device can have a very good RSSI + * 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. + */ + int avg_rssi; + int vgc_level; + int false_cca; + + /* + * Statistics required for Signal quality calculation. + * For calculating the Signal quality we have to determine + * the total number of success and failed RX and TX frames. + * After that we also use the average RSSI value to help + * determining the signal quality. + * For the calculation we will use the following algorithm: + * + * rssi_percentage = (avg_rssi * 100) / rssi_offset + * rx_percentage = (rx_success * 100) / rx_total + * tx_percentage = (tx_success * 100) / tx_total + * avg_signal = ((WEIGHT_RSSI * avg_rssi) + + * (WEIGHT_TX * tx_percentage) + + * (WEIGHT_RX * rx_percentage)) / 100 + * + * This value should then be checked to not be greated then 100. + */ + int rx_percentage; + int rx_success; + int rx_failed; + int tx_percentage; + int tx_success; + int tx_failed; +#define WEIGHT_RSSI 20 +#define WEIGHT_RX 40 +#define WEIGHT_TX 40 + + /* + * Work structure for scheduling periodic link tuning. + */ + struct delayed_work work; +}; + +/* + * Clear all counters inside the link structure. + * This can be easiest achieved by memsetting everything + * except for the work structure at the end. + */ +static inline void rt2x00_clear_link(struct link *link) +{ + memset(link, 0x00, sizeof(*link) - sizeof(link->work)); + link->rx_percentage = 50; + link->tx_percentage = 50; +} + +/* + * Update the rssi using the walking average approach. + */ +static inline void rt2x00_update_link_rssi(struct link *link, int rssi) +{ + if (!link->avg_rssi) + link->avg_rssi = rssi; + else + link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8; +} + +/* + * When the avg_rssi is unset or no frames have been received), + * we need to return the default value which needs to be less + * than -80 so the device will select the maximum sensitivity. + */ +static inline int rt2x00_get_link_rssi(struct link *link) +{ + return (link->avg_rssi && link->rx_success) ? link->avg_rssi : -128; +} + +/* + * Interface structure + * Configuration details about the current interface. + */ +struct interface { + /* + * Interface identification. The value is assigned + * to us by the 80211 stack, and is used to request + * new beacons. + */ + int id; + + /* + * Current working type (IEEE80211_IF_TYPE_*). + * This excludes the type IEEE80211_IF_TYPE_MNTR + * since that is counted seperately in the monitor_count + * field. + * When set to INVALID_INTERFACE, no interface is configured. + */ + int type; +#define INVALID_INTERFACE IEEE80211_IF_TYPE_MGMT + + /* + * MAC of the device. + */ + u8 mac[ETH_ALEN]; + + /* + * BBSID of the AP to associate with. + */ + u8 bssid[ETH_ALEN]; + + /* + * Store the packet filter mode for the current interface. + * monitor mode always disabled filtering. But in such + * cases we still need to store the value here in case + * the monitor mode interfaces are removed, while a + * non-monitor mode interface remains. + */ + unsigned short filter; + + /* + * Monitor mode count, the number of interfaces + * in monitor mode that that have been added. + */ + unsigned short monitor_count; +}; + +static inline int is_interface_present(struct interface *intf) +{ + return !!intf->id; +} + +static inline int is_monitor_present(struct interface *intf) +{ + return !!intf->monitor_count; +} + +/* + * Details about the supported modes, rates and channels + * of a particular chipset. This is used by rt2x00lib + * to build the ieee80211_hw_mode array for mac80211. + */ +struct hw_mode_spec { + /* + * Number of modes, rates and channels. + */ + int num_modes; + int num_rates; + int num_channels; + + /* + * txpower values. + */ + const u8 *tx_power_a; + const u8 *tx_power_bg; + u8 tx_power_default; + + /* + * Device/chipset specific value. + */ + const struct rf_channel *channels; +}; + +/* + * rt2x00lib callback functions. + */ +struct rt2x00lib_ops { + /* + * Interrupt handlers. + */ + irq_handler_t irq_handler; + + /* + * Device init handlers. + */ + int (*probe_hw) (struct rt2x00_dev *rt2x00dev); + char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev); + int (*load_firmware) (struct rt2x00_dev *rt2x00dev, void *data, + const size_t len); + + /* + * Device initialization/deinitialization handlers. + */ + int (*initialize) (struct rt2x00_dev *rt2x00dev); + void (*uninitialize) (struct rt2x00_dev *rt2x00dev); + + /* + * Radio control handlers. + */ + int (*set_device_state) (struct rt2x00_dev *rt2x00dev, + enum dev_state state); + int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev); + void (*link_stats) (struct rt2x00_dev *rt2x00dev); + void (*reset_tuner) (struct rt2x00_dev *rt2x00dev); + void (*link_tuner) (struct rt2x00_dev *rt2x00dev); + + /* + * TX control handlers + */ + void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control); + int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control); + void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, + unsigned int queue); + + /* + * RX control handlers + */ + int (*fill_rxdone) (struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size); + + /* + * Configuration handlers. + */ + void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, u8 *mac); + void (*config_bssid) (struct rt2x00_dev *rt2x00dev, u8 *bssid); + void (*config_packet_filter) (struct rt2x00_dev *rt2x00dev, + const unsigned int filter); + void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type); + void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, + struct ieee80211_conf *conf); +#define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) +#define CONFIG_UPDATE_CHANNEL ( 1 << 2 ) +#define CONFIG_UPDATE_TXPOWER ( 1 << 3 ) +#define CONFIG_UPDATE_ANTENNA ( 1 << 4 ) +#define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 ) +#define CONFIG_UPDATE_BEACON_INT ( 1 << 6 ) +#define CONFIG_UPDATE_ALL 0xffff +}; + +/* + * rt2x00 driver callback operation structure. + */ +struct rt2x00_ops { + const char *name; + const unsigned int rxd_size; + const unsigned int txd_size; + const unsigned int eeprom_size; + const unsigned int rf_size; + const struct rt2x00lib_ops *lib; + const struct ieee80211_ops *hw; +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + const struct rt2x00debug *debugfs; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * rt2x00 device structure. + */ +struct rt2x00_dev { + /* + * Device structure. + * 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. + */ + void *dev; +#define rt2x00dev_pci(__dev) ( (struct pci_dev*)(__dev)->dev ) +#define rt2x00dev_usb(__dev) ( (struct usb_interface*)(__dev)->dev ) + + /* + * Callback functions. + */ + const struct rt2x00_ops *ops; + + /* + * IEEE80211 control structure. + */ + struct ieee80211_hw *hw; + struct ieee80211_hw_mode *hwmodes; + unsigned int curr_hwmode; +#define HWMODE_B 0 +#define HWMODE_G 1 +#define HWMODE_A 2 + + /* + * rfkill structure for RF state switching support. + * This will only be compiled in when required. + */ +#ifdef CONFIG_RT2X00_LIB_RFKILL + struct rfkill *rfkill; + struct input_polled_dev *poll_dev; +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + + /* + * If enabled, the debugfs interface structures + * required for deregistration of debugfs. + */ +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + const struct rt2x00debug_intf *debugfs_intf; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + + /* + * Device flags. + * In these flags the current status and some + * of the device capabilities are stored. + */ + unsigned long flags; +#define DEVICE_ENABLED_RADIO 1 +#define DEVICE_ENABLED_RADIO_HW 2 +#define DEVICE_INITIALIZED 3 +#define DEVICE_INITIALIZED_HW 4 +#define REQUIRE_FIRMWARE 5 +#define PACKET_FILTER_SCHEDULED 6 +#define PACKET_FILTER_PENDING 7 +#define INTERFACE_RESUME 8 +#define INTERFACE_ENABLED 9 +#define INTERFACE_ENABLED_MONITOR 10 +#define REQUIRE_BEACON_RING 11 +#define DEVICE_SUPPORT_HW_BUTTON 12 +#define CONFIG_FRAME_TYPE 13 +#define CONFIG_RF_SEQUENCE 14 +/* Hole: Add new Flag here */ +#define CONFIG_EXTERNAL_LNA_A 16 +#define CONFIG_EXTERNAL_LNA_BG 17 +#define CONFIG_DOUBLE_ANTENNA 18 +#define CONFIG_DISABLE_LINK_TUNING 19 + + /* + * Chipset identification. + */ + struct rt2x00_chip chip; + + /* + * hw capability specifications. + */ + struct hw_mode_spec spec; + + /* + * Register pointers + * csr_addr: Base register address. (PCI) + * csr_cache: CSR cache for usb_control_msg. (USB) + */ + void __iomem *csr_addr; + void *csr_cache; + + /* + * Interface configuration. + */ + struct interface interface; + + /* + * Link quality + */ + struct link link; + + /* + * EEPROM data. + */ + __le16 *eeprom; + + /* + * Active RF register values. + * These are stored here so we don't need + * to read the rf registers and can directly + * use this value instead. + * This field should be accessed by using + * rt2x00_rf_read() and rt2x00_rf_write(). + */ + u32 *rf; + + /* + * Current TX power value. + */ + u16 tx_power; + + /* + * LED register (for rt61pci & rt73usb). + */ + u16 led_reg; + + /* + * Led mode (LED_MODE_*) + */ + u8 led_mode; + + /* + * Rssi <-> Dbm offset + */ + u8 rssi_offset; + + /* + * Frequency offset (for rt61pci & rt73usb). + */ + u8 freq_offset; + + /* + * Low level statistics which will have + * to be kept up to date while device is running. + */ + struct ieee80211_low_level_stats low_level_stats; + + /* + * RX configuration information. + */ + struct ieee80211_rx_status rx_status; + + /* + * Beacon scheduled work. + */ + struct work_struct beacon_work; + + /* + * Data ring arrays for RX, TX and Beacon. + * The Beacon array also contains the Atim ring + * if that is supported by the device. + */ + int data_rings; + struct data_ring *rx; + struct data_ring *tx; + struct data_ring *bcn; + + /* + * Firmware image. + */ + const struct firmware *fw; +}; + +/* + * For-each loop for the ring array. + * All rings have been allocated as a single array, + * this means we can create a very simply loop macro + * that is capable of looping through all rings. + * ring_end(), txring_end() and ring_loop() are helper macro's which + * should not be used directly. Instead the following should be used: + * ring_for_each() - Loops through all rings (RX, TX, Beacon & Atim) + * txring_for_each() - Loops through TX data rings (TX only) + * txringall_for_each() - Loops through all TX rings (TX, Beacon & Atim) + */ +#define ring_end(__dev) \ + &(__dev)->rx[(__dev)->data_rings] + +#define txring_end(__dev) \ + &(__dev)->tx[(__dev)->hw->queues] + +#define ring_loop(__entry, __start, __end) \ + for ((__entry) = (__start); \ + prefetch(&(__entry)[1]), (__entry) != (__end); \ + (__entry) = &(__entry)[1]) + +#define ring_for_each(__dev, __entry) \ + ring_loop(__entry, (__dev)->rx, ring_end(__dev)) + +#define txring_for_each(__dev, __entry) \ + ring_loop(__entry, (__dev)->tx, txring_end(__dev)) + +#define txringall_for_each(__dev, __entry) \ + ring_loop(__entry, (__dev)->tx, ring_end(__dev)) + +/* + * Generic RF access. + * The RF is being accessed by word index. + */ +static inline void rt2x00_rf_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + *data = rt2x00dev->rf[word]; +} + +static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2x00dev->rf[word] = data; +} + +/* + * Generic EEPROM access. + * The EEPROM is being accessed by word index. + */ +static inline void *rt2x00_eeprom_addr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word) +{ + return (void *)&rt2x00dev->eeprom[word]; +} + +static inline void rt2x00_eeprom_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u16 *data) +{ + *data = le16_to_cpu(rt2x00dev->eeprom[word]); +} + +static inline void rt2x00_eeprom_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u16 data) +{ + rt2x00dev->eeprom[word] = cpu_to_le16(data); +} + +/* + * Chipset handlers + */ +static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, + const u16 rt, const u16 rf, const u32 rev) +{ + INFO(rt2x00dev, + "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", + rt, rf, rev); + + rt2x00dev->chip.rt = rt; + rt2x00dev->chip.rf = rf; + rt2x00dev->chip.rev = rev; +} + +static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) +{ + return (chipset->rt == chip); +} + +static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip) +{ + return (chipset->rf == chip); +} + +static inline u16 rt2x00_get_rev(const struct rt2x00_chip *chipset) +{ + return chipset->rev; +} + +static inline u16 rt2x00_rev(const struct rt2x00_chip *chipset, const u32 mask) +{ + return chipset->rev & mask; +} + +/* + * Duration calculations + * The rate variable passed is: 100kbs. + * To convert from bytes to bits we multiply size with 8, + * then the size is multiplied with 10 to make the + * real rate -> rate argument correction. + */ +static inline u16 get_duration(const unsigned int size, const u8 rate) +{ + return ((size * 8 * 10) / rate); +} + +static inline u16 get_duration_res(const unsigned int size, const u8 rate) +{ + return ((size * 8 * 10) % rate); +} + +/* + * Library functions. + */ +struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, + const unsigned int queue); + +/* + * Interrupt context handlers. + */ +void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_txdone(struct data_entry *entry, + const int status, const int retry); +void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, + const int signal, const int rssi, const int ofdm); + +/* + * TX descriptor initializer + */ +void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control); + +/* + * mac80211 handlers. + */ +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control); +int rt2x00mac_start(struct ieee80211_hw *hw); +void rt2x00mac_stop(struct ieee80211_hw *hw); +int rt2x00mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +void rt2x00mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf); +void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, + unsigned short flags, int mc_count); +int rt2x00mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats); +int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params); + +/* + * Driver allocation handlers. + */ +int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev); +#ifdef CONFIG_PM +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state); +int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev); +#endif /* CONFIG_PM */ + +#endif /* RT2X00_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c new file mode 100644 index 000000000000..de890a17d8fd --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -0,0 +1,165 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00lib + Abstract: rt2x00 generic configuration routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac) +{ + if (mac) + rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, mac); +} + +void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + if (bssid) + rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid); +} + +void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter) +{ + /* + * Only configure the device when something has changed, + * or if we are in RESUME state in which case all configuration + * will be forced upon the device. + */ + if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && + !test_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags)) + return; + + /* + * Write configuration to device and clear the update flag. + */ + rt2x00dev->ops->lib->config_packet_filter(rt2x00dev, filter); + __clear_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); +} + +void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) +{ + struct interface *intf = &rt2x00dev->interface; + + /* + * Fallback when a invalid interface is attempted to + * be configured. If a monitor interface is present, + * we are going configure that, otherwise exit. + */ + if (type == INVALID_INTERFACE) { + if (is_monitor_present(intf)) + type = IEEE80211_IF_TYPE_MNTR; + else + return; + } + + /* + * Only configure the device when something has changed, + * or if we are in RESUME state in which case all configuration + * will be forced upon the device. + */ + if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && + (!(is_interface_present(intf) ^ + test_bit(INTERFACE_ENABLED, &rt2x00dev->flags)) && + !(is_monitor_present(intf) ^ + test_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags)))) + return; + + /* + * Configure device. + */ + rt2x00dev->ops->lib->config_type(rt2x00dev, type); + + /* + * Update the configuration flags. + */ + if (type != IEEE80211_IF_TYPE_MNTR) { + if (is_interface_present(intf)) + __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + else + __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + } else { + if (is_monitor_present(intf)) + __set_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags); + else + __clear_bit(INTERFACE_ENABLED_MONITOR, + &rt2x00dev->flags); + } +} + +void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf) +{ + int flags = 0; + + /* + * If we are in RESUME state we should + * force all configuration options. + */ + if (test_bit(INTERFACE_RESUME, &rt2x00dev->flags)) { + flags = CONFIG_UPDATE_ALL; + goto config; + } + + /* + * Check which configuration options have been + * updated and should be send to the device. + */ + if (rt2x00dev->rx_status.phymode != conf->phymode) + flags |= CONFIG_UPDATE_PHYMODE; + if (rt2x00dev->rx_status.channel != conf->channel) + flags |= CONFIG_UPDATE_CHANNEL; + if (rt2x00dev->tx_power != conf->power_level) + flags |= CONFIG_UPDATE_TXPOWER; + if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx) + flags |= CONFIG_UPDATE_ANTENNA; + + /* + * The following configuration options are never + * stored anywhere and will always be updated. + */ + flags |= CONFIG_UPDATE_SLOT_TIME; + flags |= CONFIG_UPDATE_BEACON_INT; + +config: + rt2x00dev->ops->lib->config(rt2x00dev, flags, conf); + + /* + * Some configuration changes affect the link quality + * which means we need to reset the link tuner. + */ + if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) + rt2x00lib_reset_link_tuner(rt2x00dev); + + rt2x00dev->rx_status.phymode = conf->phymode; + rt2x00dev->rx_status.freq = conf->freq; + rt2x00dev->rx_status.channel = conf->channel; + rt2x00dev->tx_power = conf->power_level; + rt2x00dev->rx_status.antenna = conf->antenna_sel_rx; +} diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c new file mode 100644 index 000000000000..4d2aaecd9dfe --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -0,0 +1,331 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00lib + Abstract: rt2x00 debugfs specific routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +#define PRINT_LINE_LEN_MAX 32 + +struct rt2x00debug_intf { + /* + * Pointer to driver structure where + * this debugfs entry belongs to. + */ + struct rt2x00_dev *rt2x00dev; + + /* + * Reference to the rt2x00debug structure + * which can be used to communicate with + * the registers. + */ + const struct rt2x00debug *debug; + + /* + * Debugfs entries for: + * - driver folder + * - driver file + * - chipset file + * - register offset/value files + * - eeprom offset/value files + * - bbp offset/value files + * - rf offset/value files + */ + struct dentry *driver_folder; + struct dentry *driver_entry; + struct dentry *chipset_entry; + struct dentry *csr_off_entry; + struct dentry *csr_val_entry; + struct dentry *eeprom_off_entry; + struct dentry *eeprom_val_entry; + struct dentry *bbp_off_entry; + struct dentry *bbp_val_entry; + struct dentry *rf_off_entry; + struct dentry *rf_val_entry; + + /* + * Driver and chipset files will use a data buffer + * that has been created in advance. This will simplify + * the code since we can use the debugfs functions. + */ + struct debugfs_blob_wrapper driver_blob; + struct debugfs_blob_wrapper chipset_blob; + + /* + * Requested offset for each register type. + */ + unsigned int offset_csr; + unsigned int offset_eeprom; + unsigned int offset_bbp; + unsigned int offset_rf; +}; + +static int rt2x00debug_file_open(struct inode *inode, struct file *file) +{ + struct rt2x00debug_intf *intf = inode->i_private; + + file->private_data = inode->i_private; + + if (!try_module_get(intf->debug->owner)) + return -EBUSY; + + return 0; +} + +static int rt2x00debug_file_release(struct inode *inode, struct file *file) +{ + struct rt2x00debug_intf *intf = file->private_data; + + module_put(intf->debug->owner); + + return 0; +} + +#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ +static ssize_t rt2x00debug_read_##__name(struct file *file, \ + char __user *buf, \ + size_t length, \ + loff_t *offset) \ +{ \ + struct rt2x00debug_intf *intf = file->private_data; \ + const struct rt2x00debug *debug = intf->debug; \ + char line[16]; \ + size_t size; \ + __type value; \ + \ + if (*offset) \ + return 0; \ + \ + if (intf->offset_##__name >= debug->__name.word_count) \ + return -EINVAL; \ + \ + debug->__name.read(intf->rt2x00dev, \ + intf->offset_##__name, &value); \ + \ + size = sprintf(line, __format, value); \ + \ + if (copy_to_user(buf, line, size)) \ + return -EFAULT; \ + \ + *offset += size; \ + return size; \ +} + +#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \ +static ssize_t rt2x00debug_write_##__name(struct file *file, \ + const char __user *buf,\ + size_t length, \ + loff_t *offset) \ +{ \ + struct rt2x00debug_intf *intf = file->private_data; \ + const struct rt2x00debug *debug = intf->debug; \ + char line[16]; \ + size_t size; \ + __type value; \ + \ + if (*offset) \ + return 0; \ + \ + if (!capable(CAP_NET_ADMIN)) \ + return -EPERM; \ + \ + if (intf->offset_##__name >= debug->__name.word_count) \ + return -EINVAL; \ + \ + if (copy_from_user(line, buf, length)) \ + return -EFAULT; \ + \ + size = strlen(line); \ + value = simple_strtoul(line, NULL, 0); \ + \ + debug->__name.write(intf->rt2x00dev, \ + intf->offset_##__name, value); \ + \ + *offset += size; \ + return size; \ +} + +#define RT2X00DEBUGFS_OPS(__name, __format, __type) \ +RT2X00DEBUGFS_OPS_READ(__name, __format, __type); \ +RT2X00DEBUGFS_OPS_WRITE(__name, __type); \ + \ +static const struct file_operations rt2x00debug_fop_##__name = {\ + .owner = THIS_MODULE, \ + .read = rt2x00debug_read_##__name, \ + .write = rt2x00debug_write_##__name, \ + .open = rt2x00debug_file_open, \ + .release = rt2x00debug_file_release, \ +}; + +RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32); +RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16); +RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8); +RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32); + +static struct dentry *rt2x00debug_create_file_driver(const char *name, + struct rt2x00debug_intf + *intf, + struct debugfs_blob_wrapper + *blob) +{ + char *data; + + data = kzalloc(3 * PRINT_LINE_LEN_MAX, GFP_KERNEL); + if (!data) + return NULL; + + blob->data = data; + data += sprintf(data, "driver: %s\n", intf->rt2x00dev->ops->name); + data += sprintf(data, "version: %s\n", DRV_VERSION); + data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__); + blob->size = strlen(blob->data); + + return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob); +} + +static struct dentry *rt2x00debug_create_file_chipset(const char *name, + struct rt2x00debug_intf + *intf, + struct + debugfs_blob_wrapper + *blob) +{ + const struct rt2x00debug *debug = intf->debug; + char *data; + + data = kzalloc(4 * PRINT_LINE_LEN_MAX, GFP_KERNEL); + if (!data) + return NULL; + + blob->data = data; + data += sprintf(data, "csr length: %d\n", debug->csr.word_count); + data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count); + data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count); + data += sprintf(data, "rf length: %d\n", debug->rf.word_count); + blob->size = strlen(blob->data); + + return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob); +} + +void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) +{ + const struct rt2x00debug *debug = rt2x00dev->ops->debugfs; + struct rt2x00debug_intf *intf; + + intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL); + if (!intf) { + ERROR(rt2x00dev, "Failed to allocate debug handler.\n"); + return; + } + + intf->debug = debug; + intf->rt2x00dev = rt2x00dev; + rt2x00dev->debugfs_intf = intf; + + intf->driver_folder = + debugfs_create_dir(intf->rt2x00dev->ops->name, + rt2x00dev->hw->wiphy->debugfsdir); + if (IS_ERR(intf->driver_folder)) + goto exit; + + intf->driver_entry = + rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob); + if (IS_ERR(intf->driver_entry)) + goto exit; + + intf->chipset_entry = + rt2x00debug_create_file_chipset("chipset", + intf, &intf->chipset_blob); + if (IS_ERR(intf->chipset_entry)) + goto exit; + +#define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \ +({ \ + (__intf)->__name##_off_entry = \ + debugfs_create_u32(__stringify(__name) "_offset", \ + S_IRUGO | S_IWUSR, \ + (__intf)->driver_folder, \ + &(__intf)->offset_##__name); \ + if (IS_ERR((__intf)->__name##_off_entry)) \ + goto exit; \ + \ + (__intf)->__name##_val_entry = \ + debugfs_create_file(__stringify(__name) "_value", \ + S_IRUGO | S_IWUSR, \ + (__intf)->driver_folder, \ + (__intf), &rt2x00debug_fop_##__name);\ + if (IS_ERR((__intf)->__name##_val_entry)) \ + goto exit; \ +}) + + RT2X00DEBUGFS_CREATE_ENTRY(intf, csr); + RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom); + RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp); + RT2X00DEBUGFS_CREATE_ENTRY(intf, rf); + +#undef RT2X00DEBUGFS_CREATE_ENTRY + + return; + +exit: + rt2x00debug_deregister(rt2x00dev); + ERROR(rt2x00dev, "Failed to register debug handler.\n"); + + return; +} + +void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) +{ + const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; + + if (unlikely(!intf)) + return; + + debugfs_remove(intf->rf_val_entry); + debugfs_remove(intf->rf_off_entry); + debugfs_remove(intf->bbp_val_entry); + debugfs_remove(intf->bbp_off_entry); + debugfs_remove(intf->eeprom_val_entry); + debugfs_remove(intf->eeprom_off_entry); + debugfs_remove(intf->csr_val_entry); + debugfs_remove(intf->csr_off_entry); + debugfs_remove(intf->chipset_entry); + debugfs_remove(intf->driver_entry); + debugfs_remove(intf->driver_folder); + kfree(intf->chipset_blob.data); + kfree(intf->driver_blob.data); + kfree(intf); + + rt2x00dev->debugfs_intf = NULL; +} diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h new file mode 100644 index 000000000000..860e8fa3a0da --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00debug + Abstract: Data structures for the rt2x00debug. + */ + +#ifndef RT2X00DEBUG_H +#define RT2X00DEBUG_H + +struct rt2x00_dev; + +#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \ +struct reg##__name { \ + void (*read)(const struct rt2x00_dev *rt2x00dev, \ + const unsigned int word, __type *data); \ + void (*write)(const struct rt2x00_dev *rt2x00dev, \ + const unsigned int word, __type data); \ + \ + unsigned int word_size; \ + unsigned int word_count; \ +} __name + +struct rt2x00debug { + /* + * Reference to the modules structure. + */ + struct module *owner; + + /* + * Register access entries. + */ + RT2X00DEBUGFS_REGISTER_ENTRY(csr, u32); + RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16); + RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8); + RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32); +}; + +#endif /* RT2X00DEBUG_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c new file mode 100644 index 000000000000..cd82eeface8f --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -0,0 +1,1133 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00lib + Abstract: rt2x00 generic device routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +/* + * Ring handler. + */ +struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, + const unsigned int queue) +{ + int beacon = test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Check if we are requesting a reqular TX ring, + * or if we are requesting a Beacon or Atim ring. + * For Atim rings, we should check if it is supported. + */ + if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) + return &rt2x00dev->tx[queue]; + + if (!rt2x00dev->bcn || !beacon) + return NULL; + + if (queue == IEEE80211_TX_QUEUE_BEACON) + return &rt2x00dev->bcn[0]; + else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + return &rt2x00dev->bcn[1]; + + return NULL; +} +EXPORT_SYMBOL_GPL(rt2x00lib_get_ring); + +/* + * Link tuning handlers + */ +static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2x00_clear_link(&rt2x00dev->link); + + /* + * Reset the link tuner. + */ + rt2x00dev->ops->lib->reset_tuner(rt2x00dev); + + queue_delayed_work(rt2x00dev->hw->workqueue, + &rt2x00dev->link.work, LINK_TUNE_INTERVAL); +} + +static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + if (delayed_work_pending(&rt2x00dev->link.work)) + cancel_rearming_delayed_work(&rt2x00dev->link.work); +} + +void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2x00lib_stop_link_tuner(rt2x00dev); + rt2x00lib_start_link_tuner(rt2x00dev); +} + +/* + * Radio control handlers. + */ +int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + int status; + + /* + * Don't enable the radio twice. + * And check if the hardware button has been disabled. + */ + if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + (test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && + !test_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags))) + return 0; + + /* + * Enable radio. + */ + status = rt2x00dev->ops->lib->set_device_state(rt2x00dev, + STATE_RADIO_ON); + if (status) + return status; + + __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags); + + /* + * Enable RX. + */ + rt2x00lib_toggle_rx(rt2x00dev, 1); + + /* + * Start the TX queues. + */ + ieee80211_start_queues(rt2x00dev->hw); + + return 0; +} + +void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + /* + * Stop beacon generation. + */ + if (work_pending(&rt2x00dev->beacon_work)) + cancel_work_sync(&rt2x00dev->beacon_work); + + /* + * Stop the TX queues. + */ + ieee80211_stop_queues(rt2x00dev->hw); + + /* + * Disable RX. + */ + rt2x00lib_toggle_rx(rt2x00dev, 0); + + /* + * Disable radio. + */ + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF); +} + +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) +{ + enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF; + + /* + * When we are disabling the RX, we should also stop the link tuner. + */ + if (!enable) + rt2x00lib_stop_link_tuner(rt2x00dev); + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + + /* + * When we are enabling the RX, we should also start the link tuner. + */ + if (enable && is_interface_present(&rt2x00dev->interface)) + rt2x00lib_start_link_tuner(rt2x00dev); +} + +static void rt2x00lib_precalculate_link_signal(struct link *link) +{ + if (link->rx_failed || link->rx_success) + link->rx_percentage = + (link->rx_success * 100) / + (link->rx_failed + link->rx_success); + else + link->rx_percentage = 50; + + if (link->tx_failed || link->tx_success) + link->tx_percentage = + (link->tx_success * 100) / + (link->tx_failed + link->tx_success); + else + link->tx_percentage = 50; + + link->rx_success = 0; + link->rx_failed = 0; + link->tx_success = 0; + link->tx_failed = 0; +} + +static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev, + int rssi) +{ + int rssi_percentage = 0; + int signal; + + /* + * We need a positive value for the RSSI. + */ + if (rssi < 0) + rssi += rt2x00dev->rssi_offset; + + /* + * Calculate the different percentages, + * which will be used for the signal. + */ + if (rt2x00dev->rssi_offset) + rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset; + + /* + * Add the individual percentages and use the WEIGHT + * defines to calculate the current link signal. + */ + signal = ((WEIGHT_RSSI * rssi_percentage) + + (WEIGHT_TX * rt2x00dev->link.tx_percentage) + + (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100; + + return (signal > 100) ? 100 : signal; +} + +static void rt2x00lib_link_tuner(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, link.work.work); + + /* + * Update statistics. + */ + rt2x00dev->ops->lib->link_stats(rt2x00dev); + + rt2x00dev->low_level_stats.dot11FCSErrorCount += + rt2x00dev->link.rx_failed; + + rt2x00lib_precalculate_link_signal(&rt2x00dev->link); + + /* + * Only perform the link tuning when Link tuning + * has been enabled (This could have been disabled from the EEPROM). + */ + if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags)) + rt2x00dev->ops->lib->link_tuner(rt2x00dev); + + /* + * Increase tuner counter, and reschedule the next link tuner run. + */ + rt2x00dev->link.count++; + queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, + LINK_TUNE_INTERVAL); +} + +/* + * Interrupt context handlers. + */ +static void rt2x00lib_beacondone_scheduled(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, beacon_work); + struct data_ring *ring = + rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct data_entry *entry = rt2x00_get_data_entry(ring); + struct sk_buff *skb; + + skb = ieee80211_beacon_get(rt2x00dev->hw, + rt2x00dev->interface.id, + &entry->tx_status.control); + if (!skb) + return; + + rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb, + &entry->tx_status.control); + + dev_kfree_skb(skb); +} + +void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work); +} +EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); + +void rt2x00lib_txdone(struct data_entry *entry, + const int status, const int retry) +{ + struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; + struct ieee80211_tx_status *tx_status = &entry->tx_status; + struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats; + int success = !!(status == TX_SUCCESS || status == TX_SUCCESS_RETRY); + int fail = !!(status == TX_FAIL_RETRY || status == TX_FAIL_INVALID || + status == TX_FAIL_OTHER); + + /* + * Update TX statistics. + */ + tx_status->flags = 0; + tx_status->ack_signal = 0; + tx_status->excessive_retries = (status == TX_FAIL_RETRY); + tx_status->retry_count = retry; + rt2x00dev->link.tx_success += success; + rt2x00dev->link.tx_failed += retry + fail; + + if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (success) + tx_status->flags |= IEEE80211_TX_STATUS_ACK; + else + stats->dot11ACKFailureCount++; + } + + tx_status->queue_length = entry->ring->stats.limit; + tx_status->queue_number = tx_status->control.queue; + + if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (success) + stats->dot11RTSSuccessCount++; + else + stats->dot11RTSFailureCount++; + } + + /* + * Send the tx_status to mac80211, + * that method also cleans up the skb structure. + */ + ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status); + entry->skb = NULL; +} +EXPORT_SYMBOL_GPL(rt2x00lib_txdone); + +void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, + const int signal, const int rssi, const int ofdm) +{ + struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; + struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + unsigned int i; + int val = 0; + + /* + * Update RX statistics. + */ + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + for (i = 0; i < mode->num_rates; i++) { + rate = &mode->rates[i]; + + /* + * When frame was received with an OFDM bitrate, + * the signal is the PLCP value. If it was received with + * a CCK bitrate the signal is the rate in 0.5kbit/s. + */ + if (!ofdm) + val = DEVICE_GET_RATE_FIELD(rate->val, RATE); + else + val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); + + if (val == signal) { + val = rate->val; + break; + } + } + + rt2x00_update_link_rssi(&rt2x00dev->link, rssi); + rt2x00dev->link.rx_success++; + rx_status->rate = val; + rx_status->signal = rt2x00lib_calculate_link_signal(rt2x00dev, rssi); + rx_status->ssi = rssi; + + /* + * Send frame to mac80211 + */ + ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status); +} +EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); + +/* + * TX descriptor initializer + */ +void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + struct data_entry_desc desc; + struct data_ring *ring; + int tx_rate; + int bitrate; + int duration; + int residual; + u16 frame_control; + u16 seq_ctrl; + + /* + * Make sure the descriptor is properly cleared. + */ + memset(&desc, 0x00, sizeof(desc)); + + /* + * Get ring pointer, if we fail to obtain the + * correct ring, then use the first TX ring. + */ + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + if (!ring) + ring = rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + + desc.cw_min = ring->tx_params.cw_min; + desc.cw_max = ring->tx_params.cw_max; + desc.aifs = ring->tx_params.aifs; + + /* + * Identify queue + */ + if (control->queue < rt2x00dev->hw->queues) + desc.queue = control->queue; + else if (control->queue == IEEE80211_TX_QUEUE_BEACON || + control->queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + desc.queue = QUEUE_MGMT; + else + desc.queue = QUEUE_OTHER; + + /* + * Read required fields from ieee80211 header. + */ + frame_control = le16_to_cpu(ieee80211hdr->frame_control); + seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl); + + tx_rate = control->tx_rate; + + /* + * Check if this is a RTS/CTS frame + */ + if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { + __set_bit(ENTRY_TXD_BURST, &desc.flags); + if (is_rts_frame(frame_control)) + __set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags); + if (control->rts_cts_rate) + tx_rate = control->rts_cts_rate; + } + + /* + * Check for OFDM + */ + if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATEMASK) + __set_bit(ENTRY_TXD_OFDM_RATE, &desc.flags); + + /* + * Check if more fragments are pending + */ + if (ieee80211_get_morefrag(ieee80211hdr)) { + __set_bit(ENTRY_TXD_BURST, &desc.flags); + __set_bit(ENTRY_TXD_MORE_FRAG, &desc.flags); + } + + /* + * Beacons and probe responses require the tsf timestamp + * to be inserted into the frame. + */ + if (control->queue == IEEE80211_TX_QUEUE_BEACON || + is_probe_resp(frame_control)) + __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc.flags); + + /* + * Determine with what IFS priority this frame should be send. + * Set ifs to IFS_SIFS when the this is not the first fragment, + * or this fragment came after RTS/CTS. + */ + if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 || + test_bit(ENTRY_TXD_RTS_FRAME, &desc.flags)) + desc.ifs = IFS_SIFS; + else + desc.ifs = IFS_BACKOFF; + + /* + * PLCP setup + * Length calculation depends on OFDM/CCK rate. + */ + desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP); + desc.service = 0x04; + + if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) { + desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f; + desc.length_low = ((length + FCS_LEN) & 0x3f); + } else { + bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE); + + /* + * Convert length to microseconds. + */ + residual = get_duration_res(length + FCS_LEN, bitrate); + duration = get_duration(length + FCS_LEN, bitrate); + + if (residual != 0) { + duration++; + + /* + * Check if we need to set the Length Extension + */ + if (bitrate == 110 && residual <= 3) + desc.service |= 0x80; + } + + desc.length_high = (duration >> 8) & 0xff; + desc.length_low = duration & 0xff; + + /* + * When preamble is enabled we should set the + * preamble bit for the signal. + */ + if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE)) + desc.signal |= 0x08; + } + + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, txd, &desc, + ieee80211hdr, length, control); +} +EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); + +/* + * Driver initialization handlers. + */ +static void rt2x00lib_channel(struct ieee80211_channel *entry, + const int channel, const int tx_power, + const int value) +{ + entry->chan = channel; + if (channel <= 14) + entry->freq = 2407 + (5 * channel); + else + entry->freq = 5000 + (5 * channel); + entry->val = value; + entry->flag = + IEEE80211_CHAN_W_IBSS | + IEEE80211_CHAN_W_ACTIVE_SCAN | + IEEE80211_CHAN_W_SCAN; + entry->power_level = tx_power; + entry->antenna_max = 0xff; +} + +static void rt2x00lib_rate(struct ieee80211_rate *entry, + const int rate, const int mask, + const int plcp, const int flags) +{ + entry->rate = rate; + entry->val = + DEVICE_SET_RATE_FIELD(rate, RATE) | + DEVICE_SET_RATE_FIELD(mask, RATEMASK) | + DEVICE_SET_RATE_FIELD(plcp, PLCP); + entry->flags = flags; + entry->val2 = entry->val; + if (entry->flags & IEEE80211_RATE_PREAMBLE2) + entry->val2 |= DEVICE_SET_RATE_FIELD(1, PREAMBLE); + entry->min_rssi_ack = 0; + entry->min_rssi_ack_delta = 0; +} + +static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, + struct hw_mode_spec *spec) +{ + struct ieee80211_hw *hw = rt2x00dev->hw; + struct ieee80211_hw_mode *hwmodes; + struct ieee80211_channel *channels; + struct ieee80211_rate *rates; + unsigned int i; + unsigned char tx_power; + + hwmodes = kzalloc(sizeof(*hwmodes) * spec->num_modes, GFP_KERNEL); + if (!hwmodes) + goto exit; + + channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL); + if (!channels) + goto exit_free_modes; + + rates = kzalloc(sizeof(*rates) * spec->num_rates, GFP_KERNEL); + if (!rates) + goto exit_free_channels; + + /* + * Initialize Rate list. + */ + rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB, + 0x00, IEEE80211_RATE_CCK); + rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB, + 0x01, IEEE80211_RATE_CCK_2); + rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB, + 0x02, IEEE80211_RATE_CCK_2); + rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB, + 0x03, IEEE80211_RATE_CCK_2); + + if (spec->num_rates > 4) { + rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB, + 0x0b, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB, + 0x0f, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB, + 0x0a, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB, + 0x0e, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB, + 0x09, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB, + 0x0d, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB, + 0x08, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB, + 0x0c, IEEE80211_RATE_OFDM); + } + + /* + * Initialize Channel list. + */ + for (i = 0; i < spec->num_channels; i++) { + if (spec->channels[i].channel <= 14) + tx_power = spec->tx_power_bg[i]; + else if (spec->tx_power_a) + tx_power = spec->tx_power_a[i]; + else + tx_power = spec->tx_power_default; + + rt2x00lib_channel(&channels[i], + spec->channels[i].channel, tx_power, i); + } + + /* + * Intitialize 802.11b + * Rates: CCK. + * Channels: OFDM. + */ + if (spec->num_modes > HWMODE_B) { + hwmodes[HWMODE_B].mode = MODE_IEEE80211B; + hwmodes[HWMODE_B].num_channels = 14; + hwmodes[HWMODE_B].num_rates = 4; + hwmodes[HWMODE_B].channels = channels; + hwmodes[HWMODE_B].rates = rates; + } + + /* + * Intitialize 802.11g + * Rates: CCK, OFDM. + * Channels: OFDM. + */ + if (spec->num_modes > HWMODE_G) { + hwmodes[HWMODE_G].mode = MODE_IEEE80211G; + hwmodes[HWMODE_G].num_channels = 14; + hwmodes[HWMODE_G].num_rates = spec->num_rates; + hwmodes[HWMODE_G].channels = channels; + hwmodes[HWMODE_G].rates = rates; + } + + /* + * Intitialize 802.11a + * Rates: OFDM. + * Channels: OFDM, UNII, HiperLAN2. + */ + if (spec->num_modes > HWMODE_A) { + hwmodes[HWMODE_A].mode = MODE_IEEE80211A; + hwmodes[HWMODE_A].num_channels = spec->num_channels - 14; + hwmodes[HWMODE_A].num_rates = spec->num_rates - 4; + hwmodes[HWMODE_A].channels = &channels[14]; + hwmodes[HWMODE_A].rates = &rates[4]; + } + + if (spec->num_modes > HWMODE_G && + ieee80211_register_hwmode(hw, &hwmodes[HWMODE_G])) + goto exit_free_rates; + + if (spec->num_modes > HWMODE_B && + ieee80211_register_hwmode(hw, &hwmodes[HWMODE_B])) + goto exit_free_rates; + + if (spec->num_modes > HWMODE_A && + ieee80211_register_hwmode(hw, &hwmodes[HWMODE_A])) + goto exit_free_rates; + + rt2x00dev->hwmodes = hwmodes; + + return 0; + +exit_free_rates: + kfree(rates); + +exit_free_channels: + kfree(channels); + +exit_free_modes: + kfree(hwmodes); + +exit: + ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n"); + return -ENOMEM; +} + +static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) +{ + if (test_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags)) + ieee80211_unregister_hw(rt2x00dev->hw); + + if (likely(rt2x00dev->hwmodes)) { + kfree(rt2x00dev->hwmodes->channels); + kfree(rt2x00dev->hwmodes->rates); + kfree(rt2x00dev->hwmodes); + rt2x00dev->hwmodes = NULL; + } +} + +static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + int status; + + /* + * Initialize HW modes. + */ + status = rt2x00lib_probe_hw_modes(rt2x00dev, spec); + if (status) + return status; + + /* + * Register HW. + */ + status = ieee80211_register_hw(rt2x00dev->hw); + if (status) { + rt2x00lib_remove_hw(rt2x00dev); + return status; + } + + __set_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags); + + return 0; +} + +/* + * Initialization/uninitialization handlers. + */ +static int rt2x00lib_alloc_entries(struct data_ring *ring, + const u16 max_entries, const u16 data_size, + const u16 desc_size) +{ + struct data_entry *entry; + unsigned int i; + + ring->stats.limit = max_entries; + ring->data_size = data_size; + ring->desc_size = desc_size; + + /* + * Allocate all ring entries. + */ + entry = kzalloc(ring->stats.limit * sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + for (i = 0; i < ring->stats.limit; i++) { + entry[i].flags = 0; + entry[i].ring = ring; + entry[i].skb = NULL; + } + + ring->entry = entry; + + return 0; +} + +static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + /* + * Allocate the RX ring. + */ + if (rt2x00lib_alloc_entries(rt2x00dev->rx, RX_ENTRIES, DATA_FRAME_SIZE, + rt2x00dev->ops->rxd_size)) + return -ENOMEM; + + /* + * First allocate the TX rings. + */ + txring_for_each(rt2x00dev, ring) { + if (rt2x00lib_alloc_entries(ring, TX_ENTRIES, DATA_FRAME_SIZE, + rt2x00dev->ops->txd_size)) + return -ENOMEM; + } + + if (!test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)) + return 0; + + /* + * Allocate the BEACON ring. + */ + if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[0], BEACON_ENTRIES, + MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size)) + return -ENOMEM; + + /* + * Allocate the Atim ring. + */ + if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[1], ATIM_ENTRIES, + DATA_FRAME_SIZE, rt2x00dev->ops->txd_size)) + return -ENOMEM; + + return 0; +} + +static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + ring_for_each(rt2x00dev, ring) { + kfree(ring->entry); + ring->entry = NULL; + } +} + +void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) +{ + if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return; + + /* + * Unregister rfkill. + */ + rt2x00rfkill_unregister(rt2x00dev); + + /* + * Allow the HW to uninitialize. + */ + rt2x00dev->ops->lib->uninitialize(rt2x00dev); + + /* + * Free allocated ring entries. + */ + rt2x00lib_free_ring_entries(rt2x00dev); +} + +int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) +{ + int status; + + if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* + * Allocate all ring entries. + */ + status = rt2x00lib_alloc_ring_entries(rt2x00dev); + if (status) { + ERROR(rt2x00dev, "Ring entries allocation failed.\n"); + return status; + } + + /* + * Initialize the device. + */ + status = rt2x00dev->ops->lib->initialize(rt2x00dev); + if (status) + goto exit; + + __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags); + + /* + * Register the rfkill handler. + */ + status = rt2x00rfkill_register(rt2x00dev); + if (status) + goto exit_unitialize; + + return 0; + +exit_unitialize: + rt2x00lib_uninitialize(rt2x00dev); + +exit: + rt2x00lib_free_ring_entries(rt2x00dev); + + return status; +} + +/* + * driver allocation handlers. + */ +static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + /* + * We need the following rings: + * RX: 1 + * TX: hw->queues + * Beacon: 1 (if required) + * Atim: 1 (if required) + */ + rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues + + (2 * test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)); + + ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL); + if (!ring) { + ERROR(rt2x00dev, "Ring allocation failed.\n"); + return -ENOMEM; + } + + /* + * Initialize pointers + */ + rt2x00dev->rx = ring; + rt2x00dev->tx = &rt2x00dev->rx[1]; + if (test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)) + rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues]; + + /* + * Initialize ring parameters. + * cw_min: 2^5 = 32. + * cw_max: 2^10 = 1024. + */ + ring_for_each(rt2x00dev, ring) { + ring->rt2x00dev = rt2x00dev; + ring->tx_params.aifs = 2; + ring->tx_params.cw_min = 5; + ring->tx_params.cw_max = 10; + } + + return 0; +} + +static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rx); + rt2x00dev->rx = NULL; + rt2x00dev->tx = NULL; + rt2x00dev->bcn = NULL; +} + +int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) +{ + int retval = -ENOMEM; + + /* + * Let the driver probe the device to detect the capabilities. + */ + retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev); + if (retval) { + ERROR(rt2x00dev, "Failed to allocate device.\n"); + goto exit; + } + + /* + * Initialize configuration work. + */ + INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); + INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); + + /* + * Reset current working type. + */ + rt2x00dev->interface.type = INVALID_INTERFACE; + + /* + * Allocate ring array. + */ + retval = rt2x00lib_alloc_rings(rt2x00dev); + if (retval) + goto exit; + + /* + * Initialize ieee80211 structure. + */ + retval = rt2x00lib_probe_hw(rt2x00dev); + if (retval) { + ERROR(rt2x00dev, "Failed to initialize hw.\n"); + goto exit; + } + + /* + * Allocatie rfkill. + */ + retval = rt2x00rfkill_allocate(rt2x00dev); + if (retval) + goto exit; + + /* + * Open the debugfs entry. + */ + rt2x00debug_register(rt2x00dev); + + return 0; + +exit: + rt2x00lib_remove_dev(rt2x00dev); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); + +void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) +{ + /* + * Disable radio. + */ + rt2x00lib_disable_radio(rt2x00dev); + + /* + * Uninitialize device. + */ + rt2x00lib_uninitialize(rt2x00dev); + + /* + * Close debugfs entry. + */ + rt2x00debug_deregister(rt2x00dev); + + /* + * Free rfkill + */ + rt2x00rfkill_free(rt2x00dev); + + /* + * Free ieee80211_hw memory. + */ + rt2x00lib_remove_hw(rt2x00dev); + + /* + * Free firmware image. + */ + rt2x00lib_free_firmware(rt2x00dev); + + /* + * Free ring structures. + */ + rt2x00lib_free_rings(rt2x00dev); +} +EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); + +/* + * Device state handlers + */ +#ifdef CONFIG_PM +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) +{ + int retval; + + NOTICE(rt2x00dev, "Going to sleep.\n"); + + /* + * Disable radio and unitialize all items + * that must be recreated on resume. + */ + rt2x00lib_disable_radio(rt2x00dev); + rt2x00lib_uninitialize(rt2x00dev); + rt2x00debug_deregister(rt2x00dev); + + /* + * Set device mode to sleep for power management. + */ + retval = rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP); + if (retval) + return retval; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00lib_suspend); + +int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) +{ + struct interface *intf = &rt2x00dev->interface; + int retval; + + NOTICE(rt2x00dev, "Waking up.\n"); + __set_bit(INTERFACE_RESUME, &rt2x00dev->flags); + + /* + * Open the debugfs entry. + */ + rt2x00debug_register(rt2x00dev); + + /* + * Reinitialize device and all active interfaces. + */ + retval = rt2x00mac_start(rt2x00dev->hw); + if (retval) + goto exit; + + /* + * Reconfigure device. + */ + retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); + if (retval) + goto exit; + + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + rt2x00lib_config_type(rt2x00dev, intf->type); + rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); + + /* + * When in Master or Ad-hoc mode, + * restart Beacon transmitting by faking a beacondone event. + */ + if (intf->type == IEEE80211_IF_TYPE_AP || + intf->type == IEEE80211_IF_TYPE_IBSS) + rt2x00lib_beacondone(rt2x00dev); + + __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags); + + return 0; + +exit: + rt2x00lib_disable_radio(rt2x00dev); + rt2x00lib_uninitialize(rt2x00dev); + rt2x00debug_deregister(rt2x00dev); + + __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00lib_resume); +#endif /* CONFIG_PM */ + +/* + * rt2x00lib module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c new file mode 100644 index 000000000000..236025f8b90f --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -0,0 +1,124 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00lib + Abstract: rt2x00 firmware loading routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) +{ + struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); + const struct firmware *fw; + char *fw_name; + int retval; + u16 crc; + u16 tmp; + + /* + * Read correct firmware from harddisk. + */ + fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev); + if (!fw_name) { + ERROR(rt2x00dev, + "Invalid firmware filename.\n" + "Please file bug report to %s.\n", DRV_PROJECT); + return -EINVAL; + } + + INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name); + + retval = request_firmware(&fw, fw_name, device); + if (retval) { + ERROR(rt2x00dev, "Failed to request Firmware.\n"); + return retval; + } + + if (!fw || !fw->size || !fw->data) { + ERROR(rt2x00dev, "Failed to read Firmware.\n"); + return -ENOENT; + } + + /* + * Validate the firmware using 16 bit CRC. + * The last 2 bytes of the firmware are the CRC + * so substract those 2 bytes from the CRC checksum, + * and set those 2 bytes to 0 when calculating CRC. + */ + tmp = 0; + crc = crc_itu_t(0, fw->data, fw->size - 2); + crc = crc_itu_t(crc, (u8 *)&tmp, 2); + + if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) { + ERROR(rt2x00dev, "Firmware CRC error.\n"); + retval = -ENOENT; + goto exit; + } + + INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n", + fw->data[fw->size - 4], fw->data[fw->size - 3]); + + rt2x00dev->fw = fw; + + return 0; + +exit: + release_firmware(fw); + + return retval; +} + +int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + if (!rt2x00dev->fw) { + retval = rt2x00lib_request_firmware(rt2x00dev); + if (retval) + return retval; + } + + /* + * Send firmware to the device. + */ + retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev, + rt2x00dev->fw->data, + rt2x00dev->fw->size); + return retval; +} + +void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) +{ + release_firmware(rt2x00dev->fw); + rt2x00dev->fw = NULL; +} + diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h new file mode 100644 index 000000000000..3324090a96a7 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -0,0 +1,125 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00lib + Abstract: Data structures and definitions for the rt2x00lib module. + */ + +#ifndef RT2X00LIB_H +#define RT2X00LIB_H + +/* + * Interval defines + */ +#define LINK_TUNE_INTERVAL ( round_jiffies(HZ) ) +#define RFKILL_POLL_INTERVAL ( HZ / 4 ) + +/* + * Radio control handlers. + */ +int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable); +void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev); + +/* + * Initialization handlers. + */ +int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); + +/* + * Configuration handlers. + */ +void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); +void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); +void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter); +void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); +void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf); + +/* + * Firmware handlers. + */ +#ifdef CONFIG_RT2X00_LIB_FIRMWARE +int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev); +#else +static inline int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) +{ + return 0; +} +static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2X00_LIB_FIRMWARE */ + +/* + * Debugfs handlers. + */ +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); +void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); +#else +static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +/* + * RFkill handlers. + */ +#ifdef CONFIG_RT2X00_LIB_RFKILL +int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev); +void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev); +int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev); +void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); +#else +static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) +{ + /* + * Force enable this flag, this will assure that + * devices with a hardware button but without rfkill support + * can still use their hardware. + */ + __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + + return 0; +} + +static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) +{ + return 0; +} + +static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + +#endif /* RT2X00LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c new file mode 100644 index 000000000000..778ed41e21ef --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -0,0 +1,459 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00mac + Abstract: rt2x00 generic mac80211 routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, + struct sk_buff *frag_skb, + struct ieee80211_tx_control *control) +{ + struct sk_buff *skb; + int size; + + if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + size = sizeof(struct ieee80211_cts); + else + size = sizeof(struct ieee80211_rts); + + skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom); + if (!skb) { + WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); + return NETDEV_TX_BUSY; + } + + skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); + skb_put(skb, size); + + if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id, + frag_skb->data, frag_skb->len, control, + (struct ieee80211_cts *)(skb->data)); + else + ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id, + frag_skb->data, frag_skb->len, control, + (struct ieee80211_rts *)(skb->data)); + + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) { + WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); + return NETDEV_TX_BUSY; + } + + return NETDEV_TX_OK; +} + +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; + struct data_ring *ring; + u16 frame_control; + + /* + * Determine which ring to put packet on. + */ + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + if (unlikely(!ring)) { + ERROR(rt2x00dev, + "Attempt to send packet over invalid queue %d.\n" + "Please file bug report to %s.\n", + control->queue, DRV_PROJECT); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + /* + * If CTS/RTS is required. and this frame is not CTS or RTS, + * create and queue that frame first. But make sure we have + * at least enough entries available to send this CTS/RTS + * frame as well as the data frame. + */ + frame_control = le16_to_cpu(ieee80211hdr->frame_control); + if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && + (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT))) { + if (rt2x00_ring_free(ring) <= 1) + return NETDEV_TX_BUSY; + + if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) + return NETDEV_TX_BUSY; + } + + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) + return NETDEV_TX_BUSY; + + if (rt2x00dev->ops->lib->kick_tx_queue) + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); + + return NETDEV_TX_OK; +} +EXPORT_SYMBOL_GPL(rt2x00mac_tx); + +int rt2x00mac_start(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int status; + + if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* + * If this is the first interface which is added, + * we should load the firmware now. + */ + if (test_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags)) { + status = rt2x00lib_load_firmware(rt2x00dev); + if (status) + return status; + } + + /* + * Initialize the device. + */ + status = rt2x00lib_initialize(rt2x00dev); + if (status) + return status; + + /* + * Enable radio. + */ + status = rt2x00lib_enable_radio(rt2x00dev); + if (status) { + rt2x00lib_uninitialize(rt2x00dev); + return status; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_start); + +void rt2x00mac_stop(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Perhaps we can add something smarter here, + * but for now just disabling the radio should do. + */ + rt2x00lib_disable_radio(rt2x00dev); +} +EXPORT_SYMBOL_GPL(rt2x00mac_stop); + +int rt2x00mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + int retval; + + /* + * We only support 1 non-monitor interface. + */ + if (conf->type != IEEE80211_IF_TYPE_MNTR && is_interface_present(intf)) + return -ENOBUFS; + + /* + * HACK: Placeholder until start/stop handler has been + * added to the mac80211 callback functions structure. + */ + retval = rt2x00mac_start(hw); + if (retval) + return retval; + + /* + * We support muliple monitor mode interfaces. + * All we need to do is increase the monitor_count. + */ + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + intf->monitor_count++; + } else { + intf->id = conf->if_id; + intf->type = conf->type; + if (conf->type == IEEE80211_IF_TYPE_AP) + memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); + memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); + intf->filter = 0; + } + + /* + * Configure interface. + * The MAC adddress must be configured after the device + * has been initialized. Else the device can reset the + * MAC registers. + */ + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_type(rt2x00dev, conf->type); + rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_add_interface); + +void rt2x00mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + + /* + * We only support 1 non-monitor interface. + */ + if (conf->type != IEEE80211_IF_TYPE_MNTR && !is_interface_present(intf)) + return; + + /* + * When removing an monitor interface, decrease monitor_count. + * For non-monitor interfaces, all interface data needs to be reset. + */ + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + intf->monitor_count--; + } else if (intf->type == conf->type) { + intf->id = 0; + intf->type = INVALID_INTERFACE; + memset(&intf->bssid, 0x00, ETH_ALEN); + memset(&intf->mac, 0x00, ETH_ALEN); + intf->filter = 0; + } + + /* + * Make sure the bssid and mac address registers + * are cleared to prevent false ACKing of frames. + */ + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + rt2x00lib_config_type(rt2x00dev, intf->type); + + /* + * HACK: Placeholder untill start/stop handler has been + * added to the mac80211 callback functions structure. + */ + rt2x00mac_stop(hw); +} +EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); + +int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * If the device is not initialized we shouldn't accept + * any configuration changes. Mac80211 might be calling + * this function while we are trying to remove the device + * or perhaps suspending it. + */ + if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* + * Check if we need to disable the radio, + * if this is not the case, at least the RX must be disabled. + */ + if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) { + if (!conf->radio_enabled) + rt2x00lib_disable_radio(rt2x00dev); + else + rt2x00lib_toggle_rx(rt2x00dev, 0); + } + + rt2x00lib_config(rt2x00dev, conf); + + /* + * If promisc mode cannot be configured in irq context, + * then it is now the time to configure it. + */ + if (test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags)) + rt2x00lib_config_packet_filter(rt2x00dev, + rt2x00dev->interface.filter); + + /* + * Reenable RX only if the radio should be on. + */ + if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2x00lib_toggle_rx(rt2x00dev, 1); + else if (conf->radio_enabled) + return rt2x00lib_enable_radio(rt2x00dev); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_config); + +int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + int status; + + /* + * If the device is not initialized we shouldn't accept + * any configuration changes. Mac80211 might be calling + * this function while we are trying to remove the device + * or perhaps suspending it. + */ + if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* + * Monitor mode does not need configuring. + * If the given type does not match the configured type, + * there has been a problem. + */ + if (conf->type == IEEE80211_IF_TYPE_MNTR) + return 0; + else if (conf->type != intf->type) + return -EINVAL; + + /* + * If the interface does not work in master mode, + * then the bssid value in the interface structure + * should now be set. + */ + if (conf->type != IEEE80211_IF_TYPE_AP) + memcpy(&intf->bssid, conf->bssid, ETH_ALEN); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + + /* + * We only need to initialize the beacon when master mode is enabled. + */ + if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon) + return 0; + + status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, + conf->beacon, + conf->beacon_control); + if (status) + dev_kfree_skb(conf->beacon); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); + +void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, + unsigned short flags, int mc_count) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Check if the new state is different then the old state. + */ + if (rt2x00dev->interface.filter == flags) + return; + + rt2x00dev->interface.filter = flags; + + /* + * Raise the pending bit to indicate the + * packet filter should be updated. + */ + __set_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); + + /* + * Check if Packet filter actions are allowed in + * atomic context. If not, raise the pending flag and + * let it be. + */ + if (!test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags) || + !in_atomic()) + rt2x00lib_config_packet_filter(rt2x00dev, flags); +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_multicast_list); + +int rt2x00mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * The dot11ACKFailureCount, dot11RTSFailureCount and + * dot11RTSSuccessCount are updated in interrupt time. + * dot11FCSErrorCount is updated in the link tuner. + */ + memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats)); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); + +int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + unsigned int i; + + for (i = 0; i < hw->queues; i++) + memcpy(&stats->data[i], &rt2x00dev->tx[i].stats, + sizeof(rt2x00dev->tx[i].stats)); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); + +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_ring *ring; + + ring = rt2x00lib_get_ring(rt2x00dev, queue); + if (unlikely(!ring)) + return -EINVAL; + + /* + * The passed variables are stored as real value ((2^n)-1). + * Ralink registers require to know the bit number 'n'. + */ + if (params->cw_min) + ring->tx_params.cw_min = fls(params->cw_min); + else + ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */ + + if (params->cw_max) + ring->tx_params.cw_max = fls(params->cw_max); + else + ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */ + + if (params->aifs) + ring->tx_params.aifs = params->aifs; + else + ring->tx_params.aifs = 2; + + INFO(rt2x00dev, + "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", + queue, ring->tx_params.cw_min, ring->tx_params.cw_max, + ring->tx_params.aifs); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c new file mode 100644 index 000000000000..85629f1999ab --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -0,0 +1,481 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00pci + Abstract: rt2x00 generic pci device routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00pci" + +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" + +/* + * Beacon handlers. + */ +int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_ring *ring = + rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct data_entry *entry = rt2x00_get_data_entry(ring); + + /* + * Just in case mac80211 doesn't set this correctly, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; + + /* + * Update the beacon entry. + */ + memcpy(entry->data_addr, skb->data, skb->len); + rt2x00lib_write_tx_desc(rt2x00dev, entry->priv, + (struct ieee80211_hdr *)skb->data, + skb->len, control); + + /* + * Enable beacon generation. + */ + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update); + +/* + * TX data handlers. + */ +int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; + struct data_entry *entry = rt2x00_get_data_entry(ring); + struct data_desc *txd = entry->priv; + u32 word; + + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + return -EINVAL; + } + + rt2x00_desc_read(txd, 0, &word); + + if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || + rt2x00_get_field32(word, TXD_ENTRY_VALID)) { + ERROR(rt2x00dev, + "Arrived at non-free entry in the non-full queue %d.\n" + "Please file bug report to %s.\n", + control->queue, DRV_PROJECT); + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + return -EINVAL; + } + + entry->skb = skb; + memcpy(&entry->tx_status.control, control, sizeof(*control)); + memcpy(entry->data_addr, skb->data, skb->len); + rt2x00lib_write_tx_desc(rt2x00dev, txd, ieee80211hdr, + skb->len, control); + + rt2x00_ring_index_inc(ring); + + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data); + +/* + * RX data handlers. + */ +void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + struct data_entry *entry; + struct data_desc *rxd; + struct sk_buff *skb; + u32 desc; + int retval; + int signal; + int rssi; + int ofdm; + int size; + + while (1) { + entry = rt2x00_get_data_entry(ring); + rxd = entry->priv; + rt2x00_desc_read(rxd, 0, &desc); + + if (rt2x00_get_field32(desc, RXD_ENTRY_OWNER_NIC)) + break; + + retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, + &rssi, &ofdm, &size); + if (retval) + goto skip_entry; + + /* + * Allocate the sk_buffer, initialize it and copy + * all data into it. + */ + skb = dev_alloc_skb(size + NET_IP_ALIGN); + if (!skb) + return; + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, size); + memcpy(skb->data, entry->data_addr, size); + + /* + * Send the frame to rt2x00lib for further processing. + */ + rt2x00lib_rxdone(entry, skb, signal, rssi, ofdm); + +skip_entry: + if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { + rt2x00_set_field32(&desc, RXD_ENTRY_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, desc); + } + + rt2x00_ring_index_inc(ring); + } +} +EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); + +/* + * Device initialization handlers. + */ +#define priv_offset(__ring, __i) \ +({ \ + ring->data_addr + (i * ring->desc_size); \ +}) + +#define data_addr_offset(__ring, __i) \ +({ \ + (__ring)->data_addr + \ + ((__ring)->stats.limit * (__ring)->desc_size) + \ + ((__i) * (__ring)->data_size); \ +}) + +#define data_dma_offset(__ring, __i) \ +({ \ + (__ring)->data_dma + \ + ((__ring)->stats.limit * (__ring)->desc_size) + \ + ((__i) * (__ring)->data_size); \ +}) + +static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring) +{ + unsigned int i; + + /* + * Allocate DMA memory for descriptor and buffer. + */ + ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev), + rt2x00_get_ring_size(ring), + &ring->data_dma); + if (!ring->data_addr) + return -ENOMEM; + + /* + * Initialize all ring entries to contain valid + * addresses. + */ + for (i = 0; i < ring->stats.limit; i++) { + ring->entry[i].priv = priv_offset(ring, i); + ring->entry[i].data_addr = data_addr_offset(ring, i); + ring->entry[i].data_dma = data_dma_offset(ring, i); + } + + return 0; +} + +static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring) +{ + if (ring->data_addr) + pci_free_consistent(rt2x00dev_pci(rt2x00dev), + rt2x00_get_ring_size(ring), + ring->data_addr, ring->data_dma); + ring->data_addr = NULL; +} + +int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) +{ + struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + struct data_ring *ring; + int status; + + /* + * Allocate DMA + */ + ring_for_each(rt2x00dev, ring) { + status = rt2x00pci_alloc_dma(rt2x00dev, ring); + if (status) + goto exit; + } + + /* + * Register interrupt handler. + */ + status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler, + IRQF_SHARED, pci_name(pci_dev), rt2x00dev); + if (status) { + ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", + pci_dev->irq, status); + return status; + } + + return 0; + +exit: + rt2x00pci_uninitialize(rt2x00dev); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00pci_initialize); + +void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + /* + * Free irq line. + */ + free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev); + + /* + * Free DMA + */ + ring_for_each(rt2x00dev, ring) + rt2x00pci_free_dma(rt2x00dev, ring); +} +EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize); + +/* + * PCI driver handlers. + */ +static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rf); + rt2x00dev->rf = NULL; + + kfree(rt2x00dev->eeprom); + rt2x00dev->eeprom = NULL; + + if (rt2x00dev->csr_addr) { + iounmap(rt2x00dev->csr_addr); + rt2x00dev->csr_addr = NULL; + } +} + +static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) +{ + struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + + rt2x00dev->csr_addr = ioremap(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + if (!rt2x00dev->csr_addr) + goto exit; + + rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); + if (!rt2x00dev->eeprom) + goto exit; + + rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); + if (!rt2x00dev->rf) + goto exit; + + return 0; + +exit: + ERROR_PROBE("Failed to allocate registers.\n"); + + rt2x00pci_free_reg(rt2x00dev); + + return -ENOMEM; +} + +int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +{ + struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data; + struct ieee80211_hw *hw; + struct rt2x00_dev *rt2x00dev; + int retval; + + retval = pci_request_regions(pci_dev, pci_name(pci_dev)); + if (retval) { + ERROR_PROBE("PCI request regions failed.\n"); + return retval; + } + + retval = pci_enable_device(pci_dev); + if (retval) { + ERROR_PROBE("Enable device failed.\n"); + goto exit_release_regions; + } + + pci_set_master(pci_dev); + + if (pci_set_mwi(pci_dev)) + ERROR_PROBE("MWI not available.\n"); + + if (pci_set_dma_mask(pci_dev, DMA_64BIT_MASK) && + pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) { + ERROR_PROBE("PCI DMA not supported.\n"); + retval = -EIO; + goto exit_disable_device; + } + + hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); + if (!hw) { + ERROR_PROBE("Failed to allocate hardware.\n"); + retval = -ENOMEM; + goto exit_disable_device; + } + + pci_set_drvdata(pci_dev, hw); + + rt2x00dev = hw->priv; + rt2x00dev->dev = pci_dev; + rt2x00dev->ops = ops; + rt2x00dev->hw = hw; + + retval = rt2x00pci_alloc_reg(rt2x00dev); + if (retval) + goto exit_free_device; + + retval = rt2x00lib_probe_dev(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00pci_free_reg(rt2x00dev); + +exit_free_device: + ieee80211_free_hw(hw); + +exit_disable_device: + if (retval != -EBUSY) + pci_disable_device(pci_dev); + +exit_release_regions: + pci_release_regions(pci_dev); + + pci_set_drvdata(pci_dev, NULL); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00pci_probe); + +void rt2x00pci_remove(struct pci_dev *pci_dev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Free all allocated data. + */ + rt2x00lib_remove_dev(rt2x00dev); + rt2x00pci_free_reg(rt2x00dev); + ieee80211_free_hw(hw); + + /* + * Free the PCI device data. + */ + pci_set_drvdata(pci_dev, NULL); + pci_disable_device(pci_dev); + pci_release_regions(pci_dev); +} +EXPORT_SYMBOL_GPL(rt2x00pci_remove); + +#ifdef CONFIG_PM +int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct rt2x00_dev *rt2x00dev = hw->priv; + int retval; + + retval = rt2x00lib_suspend(rt2x00dev, state); + if (retval) + return retval; + + rt2x00pci_free_reg(rt2x00dev); + + pci_save_state(pci_dev); + pci_disable_device(pci_dev); + return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); +} +EXPORT_SYMBOL_GPL(rt2x00pci_suspend); + +int rt2x00pci_resume(struct pci_dev *pci_dev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct rt2x00_dev *rt2x00dev = hw->priv; + int retval; + + if (pci_set_power_state(pci_dev, PCI_D0) || + pci_enable_device(pci_dev) || + pci_restore_state(pci_dev)) { + ERROR(rt2x00dev, "Failed to resume device.\n"); + return -EIO; + } + + retval = rt2x00pci_alloc_reg(rt2x00dev); + if (retval) + return retval; + + retval = rt2x00lib_resume(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00pci_free_reg(rt2x00dev); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00pci_resume); +#endif /* CONFIG_PM */ + +/* + * rt2x00pci module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h new file mode 100644 index 000000000000..82adeac061d0 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00pci + Abstract: Data structures for the rt2x00pci module. + */ + +#ifndef RT2X00PCI_H +#define RT2X00PCI_H + +#include + +/* + * This variable should be used with the + * pci_driver structure initialization. + */ +#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops) + +/* + * Register defines. + * Some registers require multiple attempts before success, + * in those cases REGISTER_BUSY_COUNT attempts should be + * taken with a REGISTER_BUSY_DELAY interval. + */ +#define REGISTER_BUSY_COUNT 5 +#define REGISTER_BUSY_DELAY 100 + +/* + * Descriptor availability flags. + * All PCI device descriptors have these 2 flags + * with the exact same definition. + * By storing them here we can use them inside rt2x00pci + * for some simple entry availability checking. + */ +#define TXD_ENTRY_OWNER_NIC FIELD32(0x00000001) +#define TXD_ENTRY_VALID FIELD32(0x00000002) +#define RXD_ENTRY_OWNER_NIC FIELD32(0x00000001) + +/* + * Register access. + */ +static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev, + const unsigned long offset, + u32 *value) +{ + *value = readl(rt2x00dev->csr_addr + offset); +} + +static inline void +rt2x00pci_register_multiread(const struct rt2x00_dev *rt2x00dev, + const unsigned long offset, + void *value, const u16 length) +{ + memcpy_fromio(value, rt2x00dev->csr_addr + offset, length); +} + +static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev, + const unsigned long offset, + u32 value) +{ + writel(value, rt2x00dev->csr_addr + offset); +} + +static inline void +rt2x00pci_register_multiwrite(const struct rt2x00_dev *rt2x00dev, + const unsigned long offset, + void *value, const u16 length) +{ + memcpy_toio(rt2x00dev->csr_addr + offset, value, length); +} + +/* + * Beacon handlers. + */ +int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control); + +/* + * TX data handlers. + */ +int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control); + +/* + * RX data handlers. + */ +void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); + +/* + * Device initialization handlers. + */ +int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev); + +/* + * PCI driver handlers. + */ +int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id); +void rt2x00pci_remove(struct pci_dev *pci_dev); +#ifdef CONFIG_PM +int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state); +int rt2x00pci_resume(struct pci_dev *pci_dev); +#else +#define rt2x00pci_suspend NULL +#define rt2x00pci_resume NULL +#endif /* CONFIG_PM */ + +#endif /* RT2X00PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h new file mode 100644 index 000000000000..7927d5f7bcc7 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -0,0 +1,283 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00 + Abstract: rt2x00 generic register information. + */ + +#ifndef RT2X00REG_H +#define RT2X00REG_H + +/* + * TX result flags. + */ +enum TX_STATUS { + TX_SUCCESS = 0, + TX_SUCCESS_RETRY = 1, + TX_FAIL_RETRY = 2, + TX_FAIL_INVALID = 3, + TX_FAIL_OTHER = 4, +}; + +/* + * Antenna values + */ +enum antenna { + ANTENNA_SW_DIVERSITY = 0, + ANTENNA_A = 1, + ANTENNA_B = 2, + ANTENNA_HW_DIVERSITY = 3, +}; + +/* + * Led mode values. + */ +enum led_mode { + LED_MODE_DEFAULT = 0, + LED_MODE_TXRX_ACTIVITY = 1, + LED_MODE_SIGNAL_STRENGTH = 2, + LED_MODE_ASUS = 3, + LED_MODE_ALPHA = 4, +}; + +/* + * Device states + */ +enum dev_state { + STATE_DEEP_SLEEP = 0, + STATE_SLEEP = 1, + STATE_STANDBY = 2, + STATE_AWAKE = 3, + +/* + * Additional device states, these values are + * not strict since they are not directly passed + * into the device. + */ + STATE_RADIO_ON, + STATE_RADIO_OFF, + STATE_RADIO_RX_ON, + STATE_RADIO_RX_OFF, + STATE_RADIO_IRQ_ON, + STATE_RADIO_IRQ_OFF, +}; + +/* + * IFS backoff values + */ +enum ifs { + IFS_BACKOFF = 0, + IFS_SIFS = 1, + IFS_NEW_BACKOFF = 2, + IFS_NONE = 3, +}; + +/* + * Cipher types for hardware encryption + */ +enum cipher { + CIPHER_NONE = 0, + CIPHER_WEP64 = 1, + CIPHER_WEP128 = 2, + CIPHER_TKIP = 3, + CIPHER_AES = 4, +/* + * The following fields were added by rt61pci and rt73usb. + */ + CIPHER_CKIP64 = 5, + CIPHER_CKIP128 = 6, + CIPHER_TKIP_NO_MIC = 7, +}; + +/* + * Register handlers. + * We store the position of a register field inside a field structure, + * This will simplify the process of setting and reading a certain field + * inside the register while making sure the process remains byte order safe. + */ +struct rt2x00_field8 { + u8 bit_offset; + u8 bit_mask; +}; + +struct rt2x00_field16 { + u16 bit_offset; + u16 bit_mask; +}; + +struct rt2x00_field32 { + u32 bit_offset; + u32 bit_mask; +}; + +/* + * Power of two check, this will check + * if the mask that has been given contains + * and contiguous set of bits. + */ +#define is_power_of_two(x) ( !((x) & ((x)-1)) ) +#define low_bit_mask(x) ( ((x)-1) & ~(x) ) +#define is_valid_mask(x) is_power_of_two(1 + (x) + low_bit_mask(x)) + +#define FIELD8(__mask) \ +({ \ + BUILD_BUG_ON(!(__mask) || \ + !is_valid_mask(__mask) || \ + (__mask) != (u8)(__mask)); \ + (struct rt2x00_field8) { \ + __ffs(__mask), (__mask) \ + }; \ +}) + +#define FIELD16(__mask) \ +({ \ + BUILD_BUG_ON(!(__mask) || \ + !is_valid_mask(__mask) || \ + (__mask) != (u16)(__mask));\ + (struct rt2x00_field16) { \ + __ffs(__mask), (__mask) \ + }; \ +}) + +#define FIELD32(__mask) \ +({ \ + BUILD_BUG_ON(!(__mask) || \ + !is_valid_mask(__mask) || \ + (__mask) != (u32)(__mask));\ + (struct rt2x00_field32) { \ + __ffs(__mask), (__mask) \ + }; \ +}) + +static inline void rt2x00_set_field32(u32 *reg, + const struct rt2x00_field32 field, + const u32 value) +{ + *reg &= ~(field.bit_mask); + *reg |= (value << field.bit_offset) & field.bit_mask; +} + +static inline u32 rt2x00_get_field32(const u32 reg, + const struct rt2x00_field32 field) +{ + return (reg & field.bit_mask) >> field.bit_offset; +} + +static inline void rt2x00_set_field16(u16 *reg, + const struct rt2x00_field16 field, + const u16 value) +{ + *reg &= ~(field.bit_mask); + *reg |= (value << field.bit_offset) & field.bit_mask; +} + +static inline u16 rt2x00_get_field16(const u16 reg, + const struct rt2x00_field16 field) +{ + return (reg & field.bit_mask) >> field.bit_offset; +} + +static inline void rt2x00_set_field8(u8 *reg, + const struct rt2x00_field8 field, + const u8 value) +{ + *reg &= ~(field.bit_mask); + *reg |= (value << field.bit_offset) & field.bit_mask; +} + +static inline u8 rt2x00_get_field8(const u8 reg, + const struct rt2x00_field8 field) +{ + return (reg & field.bit_mask) >> field.bit_offset; +} + +/* + * Device specific rate value. + * We will have to create the device specific rate value + * passed to the ieee80211 kernel. We need to make it a consist of + * multiple fields because we want to store more then 1 device specific + * values inside the value. + * 1 - rate, stored as 100 kbit/s. + * 2 - preamble, short_preamble enabled flag. + * 3 - MASK_RATE, which rates are enabled in this mode, this mask + * corresponds with the TX register format for the current device. + * 4 - plcp, 802.11b rates are device specific, + * 802.11g rates are set according to the ieee802.11a-1999 p.14. + * The bit to enable preamble is set in a seperate define. + */ +#define DEV_RATE FIELD32(0x000007ff) +#define DEV_PREAMBLE FIELD32(0x00000800) +#define DEV_RATEMASK FIELD32(0x00fff000) +#define DEV_PLCP FIELD32(0xff000000) + +/* + * Bitfields + */ +#define DEV_RATEBIT_1MB ( 1 << 0 ) +#define DEV_RATEBIT_2MB ( 1 << 1 ) +#define DEV_RATEBIT_5_5MB ( 1 << 2 ) +#define DEV_RATEBIT_11MB ( 1 << 3 ) +#define DEV_RATEBIT_6MB ( 1 << 4 ) +#define DEV_RATEBIT_9MB ( 1 << 5 ) +#define DEV_RATEBIT_12MB ( 1 << 6 ) +#define DEV_RATEBIT_18MB ( 1 << 7 ) +#define DEV_RATEBIT_24MB ( 1 << 8 ) +#define DEV_RATEBIT_36MB ( 1 << 9 ) +#define DEV_RATEBIT_48MB ( 1 << 10 ) +#define DEV_RATEBIT_54MB ( 1 << 11 ) + +/* + * Bitmasks for DEV_RATEMASK + */ +#define DEV_RATEMASK_1MB ( (DEV_RATEBIT_1MB << 1) -1 ) +#define DEV_RATEMASK_2MB ( (DEV_RATEBIT_2MB << 1) -1 ) +#define DEV_RATEMASK_5_5MB ( (DEV_RATEBIT_5_5MB << 1) -1 ) +#define DEV_RATEMASK_11MB ( (DEV_RATEBIT_11MB << 1) -1 ) +#define DEV_RATEMASK_6MB ( (DEV_RATEBIT_6MB << 1) -1 ) +#define DEV_RATEMASK_9MB ( (DEV_RATEBIT_9MB << 1) -1 ) +#define DEV_RATEMASK_12MB ( (DEV_RATEBIT_12MB << 1) -1 ) +#define DEV_RATEMASK_18MB ( (DEV_RATEBIT_18MB << 1) -1 ) +#define DEV_RATEMASK_24MB ( (DEV_RATEBIT_24MB << 1) -1 ) +#define DEV_RATEMASK_36MB ( (DEV_RATEBIT_36MB << 1) -1 ) +#define DEV_RATEMASK_48MB ( (DEV_RATEBIT_48MB << 1) -1 ) +#define DEV_RATEMASK_54MB ( (DEV_RATEBIT_54MB << 1) -1 ) + +/* + * Bitmask groups of bitrates + */ +#define DEV_BASIC_RATEMASK \ + ( DEV_RATEMASK_11MB | \ + DEV_RATEBIT_6MB | DEV_RATEBIT_12MB | DEV_RATEBIT_24MB ) + +#define DEV_CCK_RATEMASK ( DEV_RATEMASK_11MB ) +#define DEV_OFDM_RATEMASK ( DEV_RATEMASK_54MB & ~DEV_CCK_RATEMASK ) + +/* + * Macro's to set and get specific fields from the device specific val and val2 + * fields inside the ieee80211_rate entry. + */ +#define DEVICE_SET_RATE_FIELD(__value, __mask) \ + (int)( ((__value) << DEV_##__mask.bit_offset) & DEV_##__mask.bit_mask ) + +#define DEVICE_GET_RATE_FIELD(__value, __mask) \ + (int)( ((__value) & DEV_##__mask.bit_mask) >> DEV_##__mask.bit_offset ) + +#endif /* RT2X00REG_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c new file mode 100644 index 000000000000..dc5b696f4751 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -0,0 +1,148 @@ +/* + Copyright (C) 2004 - 2007 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. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) +{ + struct rt2x00_dev *rt2x00dev = data; + int retval = 0; + + if (unlikely(!rt2x00dev)) + return 0; + + /* + * Only continue if we have an active interface, + * either monitor or non-monitor should be present. + */ + if (!is_interface_present(&rt2x00dev->interface) && + !is_monitor_present(&rt2x00dev->interface)) + return 0; + + if (state == RFKILL_STATE_ON) { + INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); + __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + retval = rt2x00lib_enable_radio(rt2x00dev); + } else if (state == RFKILL_STATE_OFF) { + INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); + __clear_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + rt2x00lib_disable_radio(rt2x00dev); + } + + return retval; +} + +static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev) +{ + struct rt2x00_dev *rt2x00dev = poll_dev->private; + int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + + if (rt2x00dev->rfkill->state != state) + input_report_key(poll_dev->input, KEY_WLAN, 1); +} + +int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + return 0; + + retval = rfkill_register(rt2x00dev->rfkill); + if (retval) { + ERROR(rt2x00dev, "Failed to register rfkill handler.\n"); + return retval; + } + + retval = input_register_polled_device(rt2x00dev->poll_dev); + if (retval) { + ERROR(rt2x00dev, "Failed to register polled device.\n"); + rfkill_unregister(rt2x00dev->rfkill); + return retval; + } + + return 0; +} + +void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + return; + + input_unregister_polled_device(rt2x00dev->poll_dev); + rfkill_unregister(rt2x00dev->rfkill); +} + +int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) +{ + struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); + + if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + return 0; + + rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + if (!rt2x00dev->rfkill) { + ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); + return -ENOMEM; + } + + rt2x00dev->rfkill->name = rt2x00dev->ops->name; + rt2x00dev->rfkill->data = rt2x00dev; + rt2x00dev->rfkill->state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; + + rt2x00dev->poll_dev = input_allocate_polled_device(); + if (!rt2x00dev->poll_dev) { + ERROR(rt2x00dev, "Failed to allocate polled device.\n"); + rfkill_free(rt2x00dev->rfkill); + return -ENOMEM; + } + + rt2x00dev->poll_dev->private = rt2x00dev; + rt2x00dev->poll_dev->poll = rt2x00rfkill_poll; + rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL; + + return 0; +} + +void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + return; + + input_free_polled_device(rt2x00dev->poll_dev); + rfkill_free(rt2x00dev->rfkill); +} diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h new file mode 100644 index 000000000000..122c75248e74 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00ring.h @@ -0,0 +1,255 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00 + Abstract: rt2x00 ring datastructures and routines + */ + +#ifndef RT2X00RING_H +#define RT2X00RING_H + +/* + * data_desc + * Each data entry also contains a descriptor which is used by the + * device to determine what should be done with the packet and + * what the current status is. + * This structure is greatly simplified, but the descriptors + * are basically a list of little endian 32 bit values. + * Make the array by default 1 word big, this will allow us + * to use sizeof() correctly. + */ +struct data_desc { + __le32 word[1]; +}; + +/* + * data_entry_desc + * Summary of information that should be written into the + * descriptor for sending a TX frame. + */ +struct data_entry_desc { + unsigned long flags; +#define ENTRY_TXDONE 1 +#define ENTRY_TXD_RTS_FRAME 2 +#define ENTRY_TXD_OFDM_RATE 3 +#define ENTRY_TXD_MORE_FRAG 4 +#define ENTRY_TXD_REQ_TIMESTAMP 5 +#define ENTRY_TXD_BURST 6 + +/* + * Queue ID. ID's 0-4 are data TX rings + */ + int queue; +#define QUEUE_MGMT 13 +#define QUEUE_RX 14 +#define QUEUE_OTHER 15 + + /* + * PLCP values. + */ + u16 length_high; + u16 length_low; + u16 signal; + u16 service; + + /* + * Timing information + */ + int aifs; + int ifs; + int cw_min; + int cw_max; +}; + +/* + * data_entry + * The data ring is a list of data entries. + * Each entry holds a reference to the descriptor + * and the data buffer. For TX rings the reference to the + * sk_buff of the packet being transmitted is also stored here. + */ +struct data_entry { + /* + * Status flags + */ + unsigned long flags; +#define ENTRY_OWNER_NIC 1 + + /* + * Ring we belong to. + */ + struct data_ring *ring; + + /* + * sk_buff for the packet which is being transmitted + * in this entry (Only used with TX related rings). + */ + struct sk_buff *skb; + + /* + * Store a ieee80211_tx_status structure in each + * ring entry, this will optimize the txdone + * handler. + */ + struct ieee80211_tx_status tx_status; + + /* + * private pointer specific to driver. + */ + void *priv; + + /* + * Data address for this entry. + */ + void *data_addr; + dma_addr_t data_dma; +}; + +/* + * data_ring + * Data rings are used by the device to send and receive packets. + * The data_addr is the base address of the data memory. + * To determine at which point in the ring we are, + * have to use the rt2x00_ring_index_*() functions. + */ +struct data_ring { + /* + * Pointer to main rt2x00dev structure where this + * ring belongs to. + */ + struct rt2x00_dev *rt2x00dev; + + /* + * Base address for the device specific data entries. + */ + struct data_entry *entry; + + /* + * TX queue statistic info. + */ + struct ieee80211_tx_queue_stats_data stats; + + /* + * TX Queue parameters. + */ + struct ieee80211_tx_queue_params tx_params; + + /* + * Base address for data ring. + */ + dma_addr_t data_dma; + void *data_addr; + + /* + * Index variables. + */ + u16 index; + u16 index_done; + + /* + * Size of packet and descriptor in bytes. + */ + u16 data_size; + u16 desc_size; +}; + +/* + * Handlers to determine the address of the current device specific + * data entry, where either index or index_done points to. + */ +static inline struct data_entry *rt2x00_get_data_entry(struct data_ring *ring) +{ + return &ring->entry[ring->index]; +} + +static inline struct data_entry *rt2x00_get_data_entry_done(struct data_ring + *ring) +{ + return &ring->entry[ring->index_done]; +} + +/* + * Total ring memory + */ +static inline int rt2x00_get_ring_size(struct data_ring *ring) +{ + return ring->stats.limit * (ring->desc_size + ring->data_size); +} + +/* + * Ring index manipulation functions. + */ +static inline void rt2x00_ring_index_inc(struct data_ring *ring) +{ + ring->index++; + if (ring->index >= ring->stats.limit) + ring->index = 0; + ring->stats.len++; +} + +static inline void rt2x00_ring_index_done_inc(struct data_ring *ring) +{ + ring->index_done++; + if (ring->index_done >= ring->stats.limit) + ring->index_done = 0; + ring->stats.len--; + ring->stats.count++; +} + +static inline void rt2x00_ring_index_clear(struct data_ring *ring) +{ + ring->index = 0; + ring->index_done = 0; + ring->stats.len = 0; + ring->stats.count = 0; +} + +static inline int rt2x00_ring_empty(struct data_ring *ring) +{ + return ring->stats.len == 0; +} + +static inline int rt2x00_ring_full(struct data_ring *ring) +{ + return ring->stats.len == ring->stats.limit; +} + +static inline int rt2x00_ring_free(struct data_ring *ring) +{ + return ring->stats.limit - ring->stats.len; +} + +/* + * TX/RX Descriptor access functions. + */ +static inline void rt2x00_desc_read(struct data_desc *desc, + const u8 word, u32 *value) +{ + *value = le32_to_cpu(desc->word[word]); +} + +static inline void rt2x00_desc_write(struct data_desc *desc, + const u8 word, const u32 value) +{ + desc->word[word] = cpu_to_le32(value); +} + +#endif /* RT2X00RING_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c new file mode 100644 index 000000000000..a0f05ca54bb4 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -0,0 +1,595 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00usb + Abstract: rt2x00 generic usb device routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00usb" + +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00usb.h" + +/* + * Interfacing with the HW. + */ +int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, const u16 value, + void *buffer, const u16 buffer_length, + u16 timeout) +{ + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + int status; + unsigned int i; + unsigned int pipe = + (requesttype == USB_VENDOR_REQUEST_IN) ? + usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + status = usb_control_msg(usb_dev, pipe, request, requesttype, + value, offset, buffer, buffer_length, + timeout); + if (status >= 0) + return 0; + + /* + * Check for errors, + * -ETIMEDOUT: We need a bit more time to complete. + * -ENODEV: Device has disappeared, no point continuing. + */ + if (status == -ETIMEDOUT) + timeout *= 2; + else if (status == -ENODEV) + break; + } + + ERROR(rt2x00dev, + "Vendor Request 0x%02x failed for offset 0x%04x with error %d.\n", + request, offset, status); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request); + +int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, void *buffer, + const u16 buffer_length, u16 timeout) +{ + int status; + + /* + * Check for Cache availability. + */ + if (unlikely(!rt2x00dev->csr_cache || buffer_length > CSR_CACHE_SIZE)) { + ERROR(rt2x00dev, "CSR cache not available.\n"); + return -ENOMEM; + } + + if (requesttype == USB_VENDOR_REQUEST_OUT) + memcpy(rt2x00dev->csr_cache, buffer, buffer_length); + + status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype, + offset, 0, rt2x00dev->csr_cache, + buffer_length, timeout); + + if (!status && requesttype == USB_VENDOR_REQUEST_IN) + memcpy(buffer, rt2x00dev->csr_cache, buffer_length); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); + +/* + * TX data handlers. + */ +static void rt2x00usb_interrupt_txdone(struct urb *urb) +{ + struct data_entry *entry = (struct data_entry *)urb->context; + struct data_ring *ring = entry->ring; + struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; + struct data_desc *txd = (struct data_desc *)entry->skb->data; + u32 word; + int tx_status; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags)) + return; + + rt2x00_desc_read(txd, 0, &word); + + /* + * Remove the descriptor data from the buffer. + */ + skb_pull(entry->skb, ring->desc_size); + + /* + * Obtain the status about this packet. + */ + tx_status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; + + rt2x00lib_txdone(entry, tx_status, 0); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + rt2x00_ring_index_done_inc(entry->ring); + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + if (!rt2x00_ring_full(ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); +} + +int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; + struct data_entry *entry = rt2x00_get_data_entry(ring); + u32 length = skb->len; + + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + return -EINVAL; + } + + if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) { + ERROR(rt2x00dev, + "Arrived at non-free entry in the non-full queue %d.\n" + "Please file bug report to %s.\n", + control->queue, DRV_PROJECT); + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + return -EINVAL; + } + + /* + * Add the descriptor in front of the skb. + */ + skb_push(skb, rt2x00dev->hw->extra_tx_headroom); + memset(skb->data, 0x00, rt2x00dev->hw->extra_tx_headroom); + + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, + ieee80211hdr, length, control); + memcpy(&entry->tx_status.control, control, sizeof(*control)); + entry->skb = skb; + + /* + * Length passed to usb_fill_urb cannot be an odd number, + * so add 1 byte to make it even. + */ + length += rt2x00dev->hw->extra_tx_headroom; + if (length % 2) + length++; + + __set_bit(ENTRY_OWNER_NIC, &entry->flags); + usb_fill_bulk_urb(entry->priv, usb_dev, + usb_sndbulkpipe(usb_dev, 1), + skb->data, length, rt2x00usb_interrupt_txdone, entry); + usb_submit_urb(entry->priv, GFP_ATOMIC); + + rt2x00_ring_index_inc(ring); + + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); + +/* + * RX data handlers. + */ +static void rt2x00usb_interrupt_rxdone(struct urb *urb) +{ + struct data_entry *entry = (struct data_entry *)urb->context; + struct data_ring *ring = entry->ring; + struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; + struct sk_buff *skb; + int retval; + int signal; + int rssi; + int ofdm; + int size; + int frame_size; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags)) + return; + + /* + * Check if the received data is simply too small + * to be actually valid, or if the urb is signaling + * a problem. + */ + if (urb->actual_length < entry->ring->desc_size || urb->status) + goto skip_entry; + + retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, &rssi, + &ofdm, &size); + if (retval) + goto skip_entry; + + /* + * Allocate a new sk buffer to replace the current one. + * If allocation fails, we should drop the current frame + * so we can recycle the existing sk buffer for the new frame. + */ + frame_size = entry->ring->data_size + entry->ring->desc_size; + skb = dev_alloc_skb(frame_size + NET_IP_ALIGN); + if (!skb) + goto skip_entry; + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, frame_size); + + /* + * Trim the skb_buffer to only contain the valid + * frame data (so ignore the device's descriptor). + */ + skb_trim(entry->skb, size); + + /* + * Send the frame to rt2x00lib for further processing. + */ + rt2x00lib_rxdone(entry, entry->skb, signal, rssi, ofdm); + + /* + * Replace current entry's skb with the newly allocated one, + * and reinitialize the urb. + */ + entry->skb = skb; + urb->transfer_buffer = entry->skb->data; + urb->transfer_buffer_length = entry->skb->len; + +skip_entry: + if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { + __set_bit(ENTRY_OWNER_NIC, &entry->flags); + usb_submit_urb(urb, GFP_ATOMIC); + } + + rt2x00_ring_index_inc(ring); +} + +/* + * Radio handlers + */ +void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + struct data_ring *ring; + struct data_entry *entry; + unsigned int i; + + /* + * Initialize the TX rings + */ + txringall_for_each(rt2x00dev, ring) { + for (i = 0; i < ring->stats.limit; i++) + ring->entry[i].flags = 0; + + rt2x00_ring_index_clear(ring); + } + + /* + * Initialize and start the RX ring. + */ + rt2x00_ring_index_clear(rt2x00dev->rx); + + for (i = 0; i < rt2x00dev->rx->stats.limit; i++) { + entry = &rt2x00dev->rx->entry[i]; + + usb_fill_bulk_urb(entry->priv, usb_dev, + usb_rcvbulkpipe(usb_dev, 1), + entry->skb->data, entry->skb->len, + rt2x00usb_interrupt_rxdone, entry); + + __set_bit(ENTRY_OWNER_NIC, &entry->flags); + usb_submit_urb(entry->priv, GFP_ATOMIC); + } +} +EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio); + +void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + unsigned int i; + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000, + REGISTER_TIMEOUT); + + /* + * Cancel all rings. + */ + ring_for_each(rt2x00dev, ring) { + for (i = 0; i < ring->stats.limit; i++) + usb_kill_urb(ring->entry[i].priv); + } +} +EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); + +/* + * Device initialization handlers. + */ +static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring) +{ + unsigned int i; + + /* + * Allocate the URB's + */ + for (i = 0; i < ring->stats.limit; i++) { + ring->entry[i].priv = usb_alloc_urb(0, GFP_KERNEL); + if (!ring->entry[i].priv) + return -ENOMEM; + } + + return 0; +} + +static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring) +{ + unsigned int i; + + if (!ring->entry) + return; + + for (i = 0; i < ring->stats.limit; i++) { + usb_kill_urb(ring->entry[i].priv); + usb_free_urb(ring->entry[i].priv); + if (ring->entry[i].skb) + kfree_skb(ring->entry[i].skb); + } +} + +int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + struct sk_buff *skb; + unsigned int entry_size; + unsigned int i; + int status; + + /* + * Allocate DMA + */ + ring_for_each(rt2x00dev, ring) { + status = rt2x00usb_alloc_urb(rt2x00dev, ring); + if (status) + goto exit; + } + + /* + * For the RX ring, skb's should be allocated. + */ + entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size; + for (i = 0; i < rt2x00dev->rx->stats.limit; i++) { + skb = dev_alloc_skb(NET_IP_ALIGN + entry_size); + if (!skb) + goto exit; + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, entry_size); + + rt2x00dev->rx->entry[i].skb = skb; + } + + return 0; + +exit: + rt2x00usb_uninitialize(rt2x00dev); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00usb_initialize); + +void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + ring_for_each(rt2x00dev, ring) + rt2x00usb_free_urb(rt2x00dev, ring); +} +EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize); + +/* + * USB driver handlers. + */ +static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rf); + rt2x00dev->rf = NULL; + + kfree(rt2x00dev->eeprom); + rt2x00dev->eeprom = NULL; + + kfree(rt2x00dev->csr_cache); + rt2x00dev->csr_cache = NULL; +} + +static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev) +{ + rt2x00dev->csr_cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL); + if (!rt2x00dev->csr_cache) + goto exit; + + rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); + if (!rt2x00dev->eeprom) + goto exit; + + rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); + if (!rt2x00dev->rf) + goto exit; + + return 0; + +exit: + ERROR_PROBE("Failed to allocate registers.\n"); + + rt2x00usb_free_reg(rt2x00dev); + + return -ENOMEM; +} + +int rt2x00usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + struct usb_device *usb_dev = interface_to_usbdev(usb_intf); + struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info; + struct ieee80211_hw *hw; + struct rt2x00_dev *rt2x00dev; + int retval; + + usb_dev = usb_get_dev(usb_dev); + + hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); + if (!hw) { + ERROR_PROBE("Failed to allocate hardware.\n"); + retval = -ENOMEM; + goto exit_put_device; + } + + usb_set_intfdata(usb_intf, hw); + + rt2x00dev = hw->priv; + rt2x00dev->dev = usb_intf; + rt2x00dev->ops = ops; + rt2x00dev->hw = hw; + + retval = rt2x00usb_alloc_reg(rt2x00dev); + if (retval) + goto exit_free_device; + + retval = rt2x00lib_probe_dev(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00usb_free_reg(rt2x00dev); + +exit_free_device: + ieee80211_free_hw(hw); + +exit_put_device: + usb_put_dev(usb_dev); + + usb_set_intfdata(usb_intf, NULL); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00usb_probe); + +void rt2x00usb_disconnect(struct usb_interface *usb_intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Free all allocated data. + */ + rt2x00lib_remove_dev(rt2x00dev); + rt2x00usb_free_reg(rt2x00dev); + ieee80211_free_hw(hw); + + /* + * Free the USB device data. + */ + usb_set_intfdata(usb_intf, NULL); + usb_put_dev(interface_to_usbdev(usb_intf)); +} +EXPORT_SYMBOL_GPL(rt2x00usb_disconnect); + +#ifdef CONFIG_PM +int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state) +{ + struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); + struct rt2x00_dev *rt2x00dev = hw->priv; + int retval; + + retval = rt2x00lib_suspend(rt2x00dev, state); + if (retval) + return retval; + + rt2x00usb_free_reg(rt2x00dev); + + /* + * Decrease usbdev refcount. + */ + usb_put_dev(interface_to_usbdev(usb_intf)); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00usb_suspend); + +int rt2x00usb_resume(struct usb_interface *usb_intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); + struct rt2x00_dev *rt2x00dev = hw->priv; + int retval; + + usb_get_dev(interface_to_usbdev(usb_intf)); + + retval = rt2x00usb_alloc_reg(rt2x00dev); + if (retval) + return retval; + + retval = rt2x00lib_resume(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00usb_free_reg(rt2x00dev); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00usb_resume); +#endif /* CONFIG_PM */ + +/* + * rt2x00pci module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h new file mode 100644 index 000000000000..d4113e5158f0 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -0,0 +1,180 @@ +/* + Copyright (C) 2004 - 2007 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: rt2x00usb + Abstract: Data structures for the rt2x00usb module. + */ + +#ifndef RT2X00USB_H +#define RT2X00USB_H + +/* + * This variable should be used with the + * usb_driver structure initialization. + */ +#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) + +/* + * Register defines. + * Some registers require multiple attempts before success, + * in those cases REGISTER_BUSY_COUNT attempts should be + * taken with a REGISTER_BUSY_DELAY interval. + * For USB vendor requests we need to pass a timeout + * time in ms, for this we use the REGISTER_TIMEOUT, + * however when loading firmware a higher value is + * required. In that case we use the REGISTER_TIMEOUT_FIRMWARE. + */ +#define REGISTER_BUSY_COUNT 5 +#define REGISTER_BUSY_DELAY 100 +#define REGISTER_TIMEOUT 20 +#define REGISTER_TIMEOUT_FIRMWARE 1000 + +/* + * Cache size + */ +#define CSR_CACHE_SIZE 8 +#define CSR_CACHE_SIZE_FIRMWARE 64 + +/* + * USB request types. + */ +#define USB_VENDOR_REQUEST ( USB_TYPE_VENDOR | USB_RECIP_DEVICE ) +#define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST ) +#define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST ) + +/* + * USB vendor commands. + */ +#define USB_DEVICE_MODE 0x01 +#define USB_SINGLE_WRITE 0x02 +#define USB_SINGLE_READ 0x03 +#define USB_MULTI_WRITE 0x06 +#define USB_MULTI_READ 0x07 +#define USB_EEPROM_WRITE 0x08 +#define USB_EEPROM_READ 0x09 +#define USB_LED_CONTROL 0x0a /* RT73USB */ +#define USB_RX_CONTROL 0x0c + +/* + * Device modes offset + */ +#define USB_MODE_RESET 0x01 +#define USB_MODE_UNPLUG 0x02 +#define USB_MODE_FUNCTION 0x03 +#define USB_MODE_TEST 0x04 +#define USB_MODE_SLEEP 0x07 /* RT73USB */ +#define USB_MODE_FIRMWARE 0x08 /* RT73USB */ +#define USB_MODE_WAKEUP 0x09 /* RT73USB */ + +/* + * Used to read/write from/to the device. + * This is the main function to communicate with the device, + * the buffer argument _must_ either be NULL or point to + * a buffer allocated by kmalloc. Failure to do so can lead + * to unexpected behavior depending on the architecture. + */ +int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, const u16 value, + void *buffer, const u16 buffer_length, + u16 timeout); + +/* + * Used to read/write from/to the device. + * This function will use a previously with kmalloc allocated cache + * to communicate with the device. The contents of the buffer pointer + * will be copied to this cache when writing, or read from the cache + * when reading. + * Buffers send to rt2x00usb_vendor_request _must_ be allocated with + * kmalloc. Hence the reason for using a previously allocated cache + * which has been allocated properly. + */ +int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, void *buffer, + const u16 buffer_length, u16 timeout); + +/* + * Simple wrapper around rt2x00usb_vendor_request to write a single + * command to the device. Since we don't use the buffer argument we + * don't have to worry about kmalloc here. + */ +static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev + *rt2x00dev, + const u8 request, + const u16 offset, + const u16 value, + int timeout) +{ + return rt2x00usb_vendor_request(rt2x00dev, request, + USB_VENDOR_REQUEST_OUT, offset, + value, NULL, 0, timeout); +} + +/* + * Simple wrapper around rt2x00usb_vendor_request to read the eeprom + * from the device. Note that the eeprom argument _must_ be allocated using + * kmalloc for correct handling inside the kernel USB layer. + */ +static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev, + __le16 *eeprom, const u16 lenght) +{ + int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16)); + + return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ, + USB_VENDOR_REQUEST_IN, 0x0000, + 0x0000, eeprom, lenght, timeout); +} + +/* + * Radio handlers + */ +void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev); +void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); + +/* + * TX data handlers. + */ +int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control); + +/* + * Device initialization handlers. + */ +int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); + +/* + * USB driver handlers. + */ +int rt2x00usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id); +void rt2x00usb_disconnect(struct usb_interface *usb_intf); +#ifdef CONFIG_PM +int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state); +int rt2x00usb_resume(struct usb_interface *usb_intf); +#else +#define rt2x00usb_suspend NULL +#define rt2x00usb_resume NULL +#endif /* CONFIG_PM */ + +#endif /* RT2X00USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c new file mode 100644 index 000000000000..730bed5a1984 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -0,0 +1,2603 @@ +/* + Copyright (C) 2004 - 2007 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: rt61pci + Abstract: rt61pci device specific routines. + Supported chipsets: RT2561, RT2561s, RT2661. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt61pci" + +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" +#include "rt61pci.h" + +/* + * Register access. + * BBP and RF register require indirect register access, + * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PHY_CSR3, ®); + if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt61pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); +} + +static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt61pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt61pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + *value = 0xff; + return; + } + + *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); +} + +static void rt61pci_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PHY_CSR4, ®); + if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +static void rt61pci_mcu_request(const struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, ®); + + if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) { + ERROR(rt2x00dev, "mcu request error. " + "Request 0x%02x failed for token 0x%02x.\n", + command, token); + return; + } + + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, ®); + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); + rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); +} + +static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + + eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); + eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); + eeprom->reg_data_clock = + !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK); + eeprom->reg_chip_select = + !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT); +} + +static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg = 0; + + rt2x00_set_field32(®, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in); + rt2x00_set_field32(®, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out); + rt2x00_set_field32(®, E2PROM_CSR_DATA_CLOCK, + !!eeprom->reg_data_clock); + rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, + !!eeprom->reg_chip_select); + + rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) + +static void rt61pci_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); +} + +static void rt61pci_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt61pci_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt61pci_read_csr, + .write = rt61pci_write_csr, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt61pci_bbp_read, + .write = rt61pci_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt61pci_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +#ifdef CONFIG_RT61PCI_RFKILL +static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); + return rt2x00_get_field32(reg, MAC_CSR13_BIT5);; +} +#endif /* CONFIG_RT2400PCI_RFKILL */ + +/* + * Configuration handlers. + */ +static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le32 reg[2]; + u32 tmp; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + tmp = le32_to_cpu(reg[1]); + rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); + reg[1] = cpu_to_le32(tmp); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); +} + +static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le32 reg[2]; + u32 tmp; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + tmp = le32_to_cpu(reg[1]); + rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); + reg[1] = cpu_to_le32(tmp); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); +} + +static void rt61pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + int multicast = !!(filter & IFF_MULTICAST); + int broadcast = !!(filter & IFF_BROADCAST); + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); +} + +static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) +{ + u32 reg; + + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + + /* + * Apply hardware packet filter. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); + else + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); + } + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); + } + + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); +} + +static void rt61pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u32 reg; + u32 value; + u32 preamble; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + /* + * Extract the allowed ratemask from the device specific rate value, + * We need to set TXRX_CSR5 to the basic rate mask so we need to mask + * off the non-basic rates. + */ + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, value); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + if (preamble == SHORT_PREAMBLE) + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 1); + else + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); +} + +static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + if (phymode == MODE_IEEE80211A) + rt2x00dev->curr_hwmode = HWMODE_A; + else if (phymode == MODE_IEEE80211B) + rt2x00dev->curr_hwmode = HWMODE_B; + else + rt2x00dev->curr_hwmode = HWMODE_G; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt61pci_config_rate(rt2x00dev, rate->val2); +} + +static void rt61pci_config_lock_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, + const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt61pci_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt61pci_bbp_write(rt2x00dev, 94, r94); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + msleep(1); +} + +static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel, + const int txpower) +{ + struct rf_channel rf; + + /* + * Fill rf_reg structure. + */ + memcpy(&rf, &rt2x00dev->spec.channels[index], sizeof(rf)); + + rt61pci_config_lock_channel(rt2x00dev, &rf, txpower); +} + +static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt61pci_config_lock_channel(rt2x00dev, &rf, txpower); +} + +static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u8 r3; + u8 r4; + u8 r77; + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt61pci_bbp_read(rt2x00dev, 4, &r4); + rt61pci_bbp_read(rt2x00dev, 77, &r77); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, + !rt2x00_rf(&rt2x00dev->chip, RF5225)); + + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !!(rt2x00dev->curr_hwmode != HWMODE_A)); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + if (rt2x00dev->curr_hwmode == HWMODE_A) + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + else + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + if (rt2x00dev->curr_hwmode == HWMODE_A) + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + else + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_bbp_write(rt2x00dev, 3, r3); + rt61pci_bbp_write(rt2x00dev, 4, r4); +} + +static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u8 r3; + u8 r4; + u8 r77; + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt61pci_bbp_read(rt2x00dev, 4, &r4); + rt61pci_bbp_read(rt2x00dev, 77, &r77); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, + !rt2x00_rf(&rt2x00dev->chip, RF2527)); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_bbp_write(rt2x00dev, 3, r3); + rt61pci_bbp_write(rt2x00dev, 4, r4); +} + +static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev, + const int p1, const int p2) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); + + if (p1 != 0xff) { + rt2x00_set_field32(®, MAC_CSR13_BIT4, !!p1); + rt2x00_set_field32(®, MAC_CSR13_BIT12, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); + } + if (p2 != 0xff) { + rt2x00_set_field32(®, MAC_CSR13_BIT3, !p2); + rt2x00_set_field32(®, MAC_CSR13_BIT11, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); + } +} + +static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u16 eeprom; + u8 r3; + u8 r4; + u8 r77; + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt61pci_bbp_read(rt2x00dev, 4, &r4); + rt61pci_bbp_read(rt2x00dev, 77, &r77); + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && + rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 1); + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); + } else if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) { + if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) >= 2) { + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt61pci_bbp_write(rt2x00dev, 77, r77); + } + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); + } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && + rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { + case 0: + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); + break; + case 1: + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0); + break; + case 2: + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); + break; + case 3: + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); + break; + } + } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && + !rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { + case 0: + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); + break; + case 1: + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0); + break; + case 2: + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); + break; + case 3: + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); + break; + } + } + + rt61pci_bbp_write(rt2x00dev, 3, r3); + rt61pci_bbp_write(rt2x00dev, 4, r4); +} + +struct antenna_sel { + u8 word; + /* + * value[0] -> non-LNA + * value[1] -> LNA + */ + u8 value[2]; +}; + +static const struct antenna_sel antenna_sel_a[] = { + { 96, { 0x58, 0x78 } }, + { 104, { 0x38, 0x48 } }, + { 75, { 0xfe, 0x80 } }, + { 86, { 0xfe, 0x80 } }, + { 88, { 0xfe, 0x80 } }, + { 35, { 0x60, 0x60 } }, + { 97, { 0x58, 0x58 } }, + { 98, { 0x58, 0x58 } }, +}; + +static const struct antenna_sel antenna_sel_bg[] = { + { 96, { 0x48, 0x68 } }, + { 104, { 0x2c, 0x3c } }, + { 75, { 0xfe, 0x80 } }, + { 86, { 0xfe, 0x80 } }, + { 88, { 0xfe, 0x80 } }, + { 35, { 0x50, 0x50 } }, + { 97, { 0x48, 0x48 } }, + { 98, { 0x48, 0x48 } }, +}; + +static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, const int antenna_rx) +{ + const struct antenna_sel *sel; + unsigned int lna; + unsigned int i; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, PHY_CSR0, ®); + + if (rt2x00dev->curr_hwmode == HWMODE_A) { + sel = antenna_sel_a; + lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 0); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 1); + } else { + sel = antenna_sel_bg; + lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 1); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 0); + } + + for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) + rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg); + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5325)) + rt61pci_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx); + else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) + rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx); + else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) { + if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) + rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, + antenna_rx); + else + rt61pci_config_antenna_2529(rt2x00dev, antenna_tx, + antenna_rx); + } +} + +static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, + const int short_slot_time, + const int beacon_int) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, SIFS); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, EIFS); + rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); +} + +static void rt61pci_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt61pci_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt61pci_config_channel(rt2x00dev, conf->channel_val, + conf->channel, conf->power_level); + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt61pci_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt61pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt61pci_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +/* + * LED functions. + */ +static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 led_reg; + u8 arg0; + u8 arg1; + + rt2x00pci_register_read(rt2x00dev, MAC_CSR14, ®); + rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70); + rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30); + rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg); + + led_reg = rt2x00dev->led_reg; + rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 1); + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) + rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 1); + else + rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 1); + + arg0 = led_reg & 0xff; + arg1 = (led_reg >> 8) & 0xff; + + rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); +} + +static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev) +{ + u16 led_reg; + u8 arg0; + u8 arg1; + + led_reg = rt2x00dev->led_reg; + rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 0); + rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 0); + rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 0); + + arg0 = led_reg & 0xff; + arg1 = (led_reg >> 8) & 0xff; + + rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); +} + +static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) +{ + u8 led; + + if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH) + return; + + /* + * Led handling requires a positive value for the rssi, + * to do that correctly we need to add the correction. + */ + rssi += rt2x00dev->rssi_offset; + + if (rssi <= 30) + led = 0; + else if (rssi <= 39) + led = 1; + else if (rssi <= 49) + led = 2; + else if (rssi <= 53) + led = 3; + else if (rssi <= 63) + led = 4; + else + led = 5; + + rt61pci_mcu_request(rt2x00dev, MCU_LED_STRENGTH, 0xff, led, 0); +} + +/* + * Link tuning + */ +static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2x00pci_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00dev->link.false_cca = + rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); +} + +static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt61pci_bbp_write(rt2x00dev, 17, 0x20); + rt2x00dev->link.vgc_level = 0x20; +} + +static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); + u8 r17; + u8 up_bound; + u8 low_bound; + + /* + * Update Led strength + */ + rt61pci_activity_led(rt2x00dev, rssi); + + rt61pci_bbp_read(rt2x00dev, 17, &r17); + + /* + * Determine r17 bounds. + */ + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + low_bound = 0x28; + up_bound = 0x48; + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + low_bound += 0x10; + up_bound += 0x10; + } + } else { + low_bound = 0x20; + up_bound = 0x40; + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + low_bound += 0x10; + up_bound += 0x10; + } + } + + /* + * Special big-R17 for very short distance + */ + if (rssi >= -35) { + if (r17 != 0x60) + rt61pci_bbp_write(rt2x00dev, 17, 0x60); + return; + } + + /* + * Special big-R17 for short distance + */ + if (rssi >= -58) { + if (r17 != up_bound) + rt61pci_bbp_write(rt2x00dev, 17, up_bound); + return; + } + + /* + * Special big-R17 for middle-short distance + */ + if (rssi >= -66) { + low_bound += 0x10; + if (r17 != low_bound) + rt61pci_bbp_write(rt2x00dev, 17, low_bound); + return; + } + + /* + * Special mid-R17 for middle distance + */ + if (rssi >= -74) { + low_bound += 0x08; + if (r17 != low_bound) + rt61pci_bbp_write(rt2x00dev, 17, low_bound); + return; + } + + /* + * Special case: Change up_bound based on the rssi. + * Lower up_bound when rssi is weaker then -74 dBm. + */ + up_bound -= 2 * (-74 - rssi); + if (low_bound > up_bound) + up_bound = low_bound; + + if (r17 > up_bound) { + rt61pci_bbp_write(rt2x00dev, 17, up_bound); + return; + } + + /* + * r17 does not yet exceed upper limit, continue and base + * the r17 tuning on the false CCA count. + */ + if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + if (++r17 > up_bound) + r17 = up_bound; + rt61pci_bbp_write(rt2x00dev, 17, r17); + } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + if (--r17 < low_bound) + r17 = low_bound; + rt61pci_bbp_write(rt2x00dev, 17, r17); + } +} + +/* + * Firmware name function. + */ +static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) +{ + char *fw_name; + + switch (rt2x00dev->chip.rt) { + case RT2561: + fw_name = FIRMWARE_RT2561; + break; + case RT2561s: + fw_name = FIRMWARE_RT2561s; + break; + case RT2661: + fw_name = FIRMWARE_RT2661; + break; + default: + fw_name = NULL; + break; + } + + return fw_name; +} + +/* + * Initialization functions. + */ +static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, + const size_t len) +{ + int i; + u32 reg; + + /* + * Wait for stable hardware. + */ + for (i = 0; i < 100; i++) { + rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg) + break; + msleep(1); + } + + if (!reg) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + /* + * Prepare MCU and mailbox for firmware loading. + */ + reg = 0; + rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 1); + rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg); + rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, 0); + + /* + * Write firmware to device. + */ + reg = 0; + rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 1); + rt2x00_set_field32(®, MCU_CNTL_CSR_SELECT_BANK, 1); + rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg); + + rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + data, len); + + rt2x00_set_field32(®, MCU_CNTL_CSR_SELECT_BANK, 0); + rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg); + + rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 0); + rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg); + + for (i = 0; i < 100; i++) { + rt2x00pci_register_read(rt2x00dev, MCU_CNTL_CSR, ®); + if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY)) + break; + msleep(1); + } + + if (i == 100) { + ERROR(rt2x00dev, "MCU Control register not ready.\n"); + return -EBUSY; + } + + /* + * Reset MAC and BBP registers. + */ + reg = 0; + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + return 0; +} + +static void rt61pci_init_rxring(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + struct data_desc *rxd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + rxd = ring->entry[i].priv; + + rt2x00_desc_read(rxd, 5, &word); + rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(rxd, 5, word); + + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); + } + + rt2x00_ring_index_clear(rt2x00dev->rx); +} + +static void rt61pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_desc *txd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + txd = ring->entry[i].priv; + + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, queue); + rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, i); + rt2x00_desc_write(txd, 5, word); + + rt2x00_desc_read(txd, 6, &word); + rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(txd, 6, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); + } + + rt2x00_ring_index_clear(ring); +} + +static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Initialize rings. + */ + rt61pci_init_rxring(rt2x00dev); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4); + + /* + * Initialize registers. + */ + rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, ®); + rt2x00_set_field32(®, TX_RING_CSR0_AC0_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00_set_field32(®, TX_RING_CSR0_AC1_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); + rt2x00_set_field32(®, TX_RING_CSR0_AC2_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].stats.limit); + rt2x00_set_field32(®, TX_RING_CSR0_AC3_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].stats.limit); + rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, ®); + rt2x00_set_field32(®, TX_RING_CSR1_MGMT_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].stats.limit); + rt2x00_set_field32(®, TX_RING_CSR1_TXD_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size / + 4); + rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, ®); + rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, ®); + rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, ®); + rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].data_dma); + rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, ®); + rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].data_dma); + rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MGMT_BASE_CSR, ®); + rt2x00_set_field32(®, MGMT_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].data_dma); + rt2x00pci_register_write(rt2x00dev, MGMT_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, ®); + rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, + rt2x00dev->rx->stats.limit); + rt2x00_set_field32(®, RX_RING_CSR_RXD_SIZE, + rt2x00dev->rx->desc_size / 4); + rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); + rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, ®); + rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, + rt2x00dev->rx->data_dma); + rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, ®); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC0, 2); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC1, 2); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC2, 2); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC3, 2); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_MGMT, 0); + rt2x00pci_register_write(rt2x00dev, TX_DMA_DST_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, LOAD_TX_RING_CSR, ®); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 1); + rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, ®); + rt2x00_set_field32(®, RX_CNTL_CSR_LOAD_RXD, 1); + rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg); + + return 0; +} + +static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); + rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, reg); + + /* + * CCK TXD BBP registers + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2, 11); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, reg); + + /* + * OFDM TXD BBP registers + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR3, ®); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR3, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR7, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg); + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); + + rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); + + rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x0000071c); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt2x00pci_register_write(rt2x00dev, MAC_CSR13, 0x0000e000); + + /* + * Invalidate all Shared Keys (SEC_CSR0), + * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) + */ + rt2x00pci_register_write(rt2x00dev, SEC_CSR0, 0x00000000); + rt2x00pci_register_write(rt2x00dev, SEC_CSR1, 0x00000000); + rt2x00pci_register_write(rt2x00dev, SEC_CSR5, 0x00000000); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0); + rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c); + rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606); + rt2x00pci_register_write(rt2x00dev, PHY_CSR7, 0x00000a08); + + rt2x00pci_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404); + + rt2x00pci_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200); + + rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); + rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); + rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + + /* + * We must clear the error counters. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00pci_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00pci_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00pci_register_read(rt2x00dev, STA_CSR2, ®); + + /* + * Reset MAC and BBP registers. + */ + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + return 0; +} + +static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt61pci_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt61pci_bbp_write(rt2x00dev, 3, 0x00); + rt61pci_bbp_write(rt2x00dev, 15, 0x30); + rt61pci_bbp_write(rt2x00dev, 21, 0xc8); + rt61pci_bbp_write(rt2x00dev, 22, 0x38); + rt61pci_bbp_write(rt2x00dev, 23, 0x06); + rt61pci_bbp_write(rt2x00dev, 24, 0xfe); + rt61pci_bbp_write(rt2x00dev, 25, 0x0a); + rt61pci_bbp_write(rt2x00dev, 26, 0x0d); + rt61pci_bbp_write(rt2x00dev, 34, 0x12); + rt61pci_bbp_write(rt2x00dev, 37, 0x07); + rt61pci_bbp_write(rt2x00dev, 39, 0xf8); + rt61pci_bbp_write(rt2x00dev, 41, 0x60); + rt61pci_bbp_write(rt2x00dev, 53, 0x10); + rt61pci_bbp_write(rt2x00dev, 54, 0x18); + rt61pci_bbp_write(rt2x00dev, 60, 0x10); + rt61pci_bbp_write(rt2x00dev, 61, 0x04); + rt61pci_bbp_write(rt2x00dev, 62, 0x04); + rt61pci_bbp_write(rt2x00dev, 75, 0xfe); + rt61pci_bbp_write(rt2x00dev, 86, 0xfe); + rt61pci_bbp_write(rt2x00dev, 88, 0xfe); + rt61pci_bbp_write(rt2x00dev, 90, 0x0f); + rt61pci_bbp_write(rt2x00dev, 99, 0x00); + rt61pci_bbp_write(rt2x00dev, 102, 0x16); + rt61pci_bbp_write(rt2x00dev, 107, 0x04); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt61pci_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); +} + +static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int mask = (state == STATE_RADIO_IRQ_OFF); + u32 reg; + + /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (state == STATE_RADIO_IRQ_ON) { + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_ENABLE_MITIGATION, mask); + rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_0, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_1, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_2, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_3, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_4, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_5, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_6, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_7, mask); + rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); +} + +static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Initialize all registers. + */ + if (rt61pci_init_rings(rt2x00dev) || + rt61pci_init_registers(rt2x00dev) || + rt61pci_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + /* + * Enable interrupts. + */ + rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); + + /* + * Enable RX. + */ + rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, ®); + rt2x00_set_field32(®, RX_CNTL_CSR_ENABLE_RX_DMA, 1); + rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg); + + /* + * Enable LED + */ + rt61pci_enable_led(rt2x00dev); + + return 0; +} + +static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Disable LED + */ + rt61pci_disable_led(rt2x00dev); + + rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818); + + /* + * Disable synchronisation. + */ + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); + + /* + * Cancel RX and TX. + */ + rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_MGMT, 1); + rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); + + /* + * Disable interrupts. + */ + rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); +} + +static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) +{ + u32 reg; + unsigned int i; + char put_to_sleep; + char current_state; + + put_to_sleep = (state != STATE_AWAKE); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); + rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); + rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®); + current_state = + rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); + if (current_state == !put_to_sleep) + return 0; + msleep(10); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state %d.\n", !put_to_sleep, current_state); + + return -EBUSY; +} + +static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt61pci_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt61pci_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt61pci_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt61pci_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue); + rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_TX_POWER, + TXPOWER_TO_DEV(control->power_level)); + rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); + rt2x00_desc_write(txd, 5, word); + + rt2x00_desc_read(txd, 11, &word); + rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, length); + rt2x00_desc_write(txd, 11, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); + rt2x00_set_field32(&word, TXD_W0_VALID, 1); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_OFDM, + test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, + !!(control->flags & + IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_BURST, + test_bit(ENTRY_TXD_BURST, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u32 reg; + + if (queue == IEEE80211_TX_QUEUE_BEACON) { + /* + * For Wi-Fi faily generated beacons between participating + * stations. Set TBTT phase adaptive adjustment step to 8us. + */ + rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + } + return; + } + + rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); + if (queue == IEEE80211_TX_QUEUE_DATA0) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA1) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA2) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA3) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA4) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_MGMT, 1); + rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); +} + +/* + * RX control handlers + */ +static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) +{ + u16 eeprom; + u8 offset; + u8 lna; + + lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); + switch (lna) { + case 3: + offset = 90; + break; + case 2: + offset = 74; + break; + case 1: + offset = 64; + break; + default: + return 0; + } + + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + offset += 14; + + if (lna == 3 || lna == 2) + offset += 10; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + offset += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } + + return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; +} + +static int rt61pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct data_desc *rxd = entry->priv; + u32 word0; + u32 word1; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 1, &word1); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + return 0; +} + +/* + * Interrupt functions. + */ +static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + struct data_entry *entry; + struct data_desc *txd; + u32 word; + u32 reg; + u32 old_reg; + int type; + int index; + int tx_status; + int retry; + + /* + * During each loop we will compare the freshly read + * STA_CSR4 register value with the value read from + * the previous loop. If the 2 values are equal then + * we should stop processing because the chance it + * quite big that the device has been unplugged and + * we risk going into an endless loop. + */ + old_reg = 0; + + while (1) { + rt2x00pci_register_read(rt2x00dev, STA_CSR4, ®); + if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) + break; + + if (old_reg == reg) + break; + old_reg = reg; + + /* + * Skip this entry when it contains an invalid + * ring identication number. + */ + type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE); + ring = rt2x00lib_get_ring(rt2x00dev, type); + if (unlikely(!ring)) + continue; + + /* + * Skip this entry when it contains an invalid + * index number. + */ + index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE); + if (unlikely(index >= ring->stats.limit)) + continue; + + entry = &ring->entry[index]; + txd = entry->priv; + rt2x00_desc_read(txd, 0, &word); + + if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + !rt2x00_get_field32(word, TXD_W0_VALID)) + return; + + /* + * Obtain the status about this packet. + */ + tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); + retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); + + rt2x00lib_txdone(entry, tx_status, retry); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_desc_write(txd, 0, word); + rt2x00_ring_index_done_inc(entry->ring); + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + if (!rt2x00_ring_full(ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); + } +} + +static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) +{ + struct rt2x00_dev *rt2x00dev = dev_instance; + u32 reg_mcu; + u32 reg; + + /* + * Get the interrupt sources & saved to local variable. + * Write register value back to clear pending interrupts. + */ + rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®_mcu); + rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu); + + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + if (!reg && !reg_mcu) + return IRQ_NONE; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* + * Handle interrupts, walk through all bits + * and run the tasks, the bits are checked in order of + * priority. + */ + + /* + * 1 - Rx ring done interrupt. + */ + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) + rt2x00pci_rxdone(rt2x00dev); + + /* + * 2 - Tx ring done interrupt. + */ + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE)) + rt61pci_txdone(rt2x00dev); + + /* + * 3 - Handle MCU command done. + */ + if (reg_mcu) + rt2x00pci_register_write(rt2x00dev, + M2H_CMD_DONE_CSR, 0xffffffff); + + return IRQ_HANDLED; +} + +/* + * Device probe functions. + */ +static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + struct eeprom_93cx6 eeprom; + u32 reg; + u16 word; + u8 *mac; + s8 value; + + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + + eeprom.data = rt2x00dev; + eeprom.register_read = rt61pci_eepromregister_read; + eeprom.register_write = rt61pci_eepromregister_write; + eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ? + PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; + eeprom.reg_data_in = 0; + eeprom.reg_data_out = 0; + eeprom.reg_data_clock = 0; + eeprom.reg_chip_select = 0; + + eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, + EEPROM_SIZE / sizeof(u16)); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0); + rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0); + rt2x00_set_field16(&word, EEPROM_NIC_TX_RX_FIXED, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_LED_LED_MODE, + LED_MODE_DEFAULT); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word); + EEPROM(rt2x00dev, "Led: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); + rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + } + + return 0; +} + +static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + u16 device; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + * To determine the RT chip we have to read the + * PCI header of the device. + */ + pci_read_config_word(rt2x00dev_pci(rt2x00dev), + PCI_CONFIG_HEADER_DEVICE, &device); + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip(rt2x00dev, device, value, reg); + + if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && + !rt2x00_rf(&rt2x00dev->chip, RF5325) && + !rt2x00_rf(&rt2x00dev->chip, RF2527) && + !rt2x00_rf(&rt2x00dev->chip, RF2529)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Read the Frame type. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) + __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + + /* + * Determine number of antenna's. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) + __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) + __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) + __set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags); + + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Read external LNA informations. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) + __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + /* + * Store led settings, for correct led behaviour. + * If the eeprom value is invalid, + * switch to default led mode. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + + rt2x00dev->led_mode = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); + + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE, + rt2x00dev->led_mode); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_0)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_1)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_2)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_3)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_4)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT, + rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_RDY_G)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_RDY_A)); + + return 0; +} + +/* + * RF value list for RF5225 & RF5325 + * Supports: 2.4 GHz & 5.2 GHz, rf_sequence disabled + */ +static const struct rf_channel rf_vals_noseq[] = { + { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, + { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, + { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, + { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, + { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, + { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, + { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, + { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, + { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, + { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, + { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, + { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, + { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, + { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 }, + { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 }, + { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b }, + { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 }, + { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b }, + { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 }, + { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 }, + { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 }, + { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b }, + { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 }, + { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b }, + { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 }, + { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 }, + { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b }, + { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 }, + { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b }, + { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 }, + + /* 802.11 UNII */ + { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 }, + { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f }, + { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 }, + { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 }, + { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f }, + { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 }, + + /* MMAC(Japan)J52 ch 34,38,42,46 */ + { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b }, + { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 }, + { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b }, + { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 }, +}; + +/* + * RF value list for RF5225 & RF5325 + * Supports: 2.4 GHz & 5.2 GHz, rf_sequence enabled + */ +static const struct rf_channel rf_vals_seq[] = { + { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, + { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, + { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, + { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, + { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, + { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, + { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, + { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, + { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, + { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, + { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, + { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, + { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, + { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00002cd4, 0x0004481a, 0x00098455, 0x000c0a03 }, + { 40, 0x00002cd0, 0x00044682, 0x00098455, 0x000c0a03 }, + { 44, 0x00002cd0, 0x00044686, 0x00098455, 0x000c0a1b }, + { 48, 0x00002cd0, 0x0004468e, 0x00098655, 0x000c0a0b }, + { 52, 0x00002cd0, 0x00044692, 0x00098855, 0x000c0a23 }, + { 56, 0x00002cd0, 0x0004469a, 0x00098c55, 0x000c0a13 }, + { 60, 0x00002cd0, 0x000446a2, 0x00098e55, 0x000c0a03 }, + { 64, 0x00002cd0, 0x000446a6, 0x00099255, 0x000c0a1b }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00002cd4, 0x0004489a, 0x000b9855, 0x000c0a03 }, + { 104, 0x00002cd4, 0x000448a2, 0x000b9855, 0x000c0a03 }, + { 108, 0x00002cd4, 0x000448aa, 0x000b9855, 0x000c0a03 }, + { 112, 0x00002cd4, 0x000448b2, 0x000b9a55, 0x000c0a03 }, + { 116, 0x00002cd4, 0x000448ba, 0x000b9a55, 0x000c0a03 }, + { 120, 0x00002cd0, 0x00044702, 0x000b9a55, 0x000c0a03 }, + { 124, 0x00002cd0, 0x00044706, 0x000b9a55, 0x000c0a1b }, + { 128, 0x00002cd0, 0x0004470e, 0x000b9c55, 0x000c0a0b }, + { 132, 0x00002cd0, 0x00044712, 0x000b9c55, 0x000c0a23 }, + { 136, 0x00002cd0, 0x0004471a, 0x000b9e55, 0x000c0a13 }, + + /* 802.11 UNII */ + { 140, 0x00002cd0, 0x00044722, 0x000b9e55, 0x000c0a03 }, + { 149, 0x00002cd0, 0x0004472e, 0x000ba255, 0x000c0a1b }, + { 153, 0x00002cd0, 0x00044736, 0x000ba255, 0x000c0a0b }, + { 157, 0x00002cd4, 0x0004490a, 0x000ba255, 0x000c0a17 }, + { 161, 0x00002cd4, 0x00044912, 0x000ba255, 0x000c0a17 }, + { 165, 0x00002cd4, 0x0004491a, 0x000ba255, 0x000c0a17 }, + + /* MMAC(Japan)J52 ch 34,38,42,46 */ + { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000c0a0b }, + { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000c0a13 }, + { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000c0a1b }, + { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 }, +}; + +static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = 0; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 5; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 2; + spec->num_rates = 12; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) { + spec->num_channels = 14; + spec->channels = rf_vals_noseq; + } else { + spec->num_channels = 14; + spec->channels = rf_vals_seq; + } + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5325)) { + spec->num_modes = 3; + spec->num_channels = ARRAY_SIZE(rf_vals_seq); + + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + spec->tx_power_a = txpower; + } +} + +static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt61pci_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt61pci_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt61pci_probe_hw_mode(rt2x00dev); + + /* + * This device requires firmware + */ + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry, u32 long_retry) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); + + return 0; +} + +static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR13, ®); + tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; + rt2x00pci_register_read(rt2x00dev, TXRX_CSR12, ®); + tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); + + return tsf; +} + +static void rt61pci_reset_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR12, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0); +} + +int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Just in case the ieee80211 doesn't set this, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; + + /* + * We need to append the descriptor in front of the + * beacon frame. + */ + if (skb_headroom(skb) < TXD_DESC_SIZE) { + if (pskb_expand_head(skb, TXD_DESC_SIZE, 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return -ENOMEM; + } + } + + /* + * First we create the beacon. + */ + skb_push(skb, TXD_DESC_SIZE); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, + (struct ieee80211_hdr *)(skb->data + + TXD_DESC_SIZE), + skb->len - TXD_DESC_SIZE, control); + + /* + * Write entire beacon with descriptor to register, + * and kick the beacon generator. + */ + rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0, skb->data, skb->len); + rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + return 0; +} + +static const struct ieee80211_ops rt61pci_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .set_retry_limit = rt61pci_set_retry_limit, + .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt61pci_get_tsf, + .reset_tsf = rt61pci_reset_tsf, + .beacon_update = rt61pci_beacon_update, +}; + +static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { + .irq_handler = rt61pci_interrupt, + .probe_hw = rt61pci_probe_hw, + .get_firmware_name = rt61pci_get_firmware_name, + .load_firmware = rt61pci_load_firmware, + .initialize = rt2x00pci_initialize, + .uninitialize = rt2x00pci_uninitialize, + .set_device_state = rt61pci_set_device_state, +#ifdef CONFIG_RT61PCI_RFKILL + .rfkill_poll = rt61pci_rfkill_poll, +#endif /* CONFIG_RT61PCI_RFKILL */ + .link_stats = rt61pci_link_stats, + .reset_tuner = rt61pci_reset_tuner, + .link_tuner = rt61pci_link_tuner, + .write_tx_desc = rt61pci_write_tx_desc, + .write_tx_data = rt2x00pci_write_tx_data, + .kick_tx_queue = rt61pci_kick_tx_queue, + .fill_rxdone = rt61pci_fill_rxdone, + .config_mac_addr = rt61pci_config_mac_addr, + .config_bssid = rt61pci_config_bssid, + .config_packet_filter = rt61pci_config_packet_filter, + .config_type = rt61pci_config_type, + .config = rt61pci_config, +}; + +static const struct rt2x00_ops rt61pci_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt61pci_rt2x00_ops, + .hw = &rt61pci_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt61pci_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * RT61pci module information. + */ +static struct pci_device_id rt61pci_device_table[] = { + /* RT2561s */ + { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) }, + /* RT2561 v2 */ + { PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) }, + /* RT2661 */ + { PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2561, RT2561s & RT2661 " + "PCI & PCMCIA chipset based cards"); +MODULE_DEVICE_TABLE(pci, rt61pci_device_table); +MODULE_FIRMWARE(FIRMWARE_RT2561); +MODULE_FIRMWARE(FIRMWARE_RT2561s); +MODULE_FIRMWARE(FIRMWARE_RT2661); +MODULE_LICENSE("GPL"); + +static struct pci_driver rt61pci_driver = { + .name = DRV_NAME, + .id_table = rt61pci_device_table, + .probe = rt2x00pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +}; + +static int __init rt61pci_init(void) +{ + return pci_register_driver(&rt61pci_driver); +} + +static void __exit rt61pci_exit(void) +{ + pci_unregister_driver(&rt61pci_driver); +} + +module_init(rt61pci_init); +module_exit(rt61pci_exit); diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h new file mode 100644 index 000000000000..6721d7dd32bc --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -0,0 +1,1457 @@ +/* + Copyright (C) 2004 - 2007 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: rt61pci + Abstract: Data structures and registers for the rt61pci module. + Supported chipsets: RT2561, RT2561s, RT2661. + */ + +#ifndef RT61PCI_H +#define RT61PCI_H + +/* + * RF chip defines. + */ +#define RF5225 0x0001 +#define RF5325 0x0002 +#define RF2527 0x0003 +#define RF2529 0x0004 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 120 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x3000 +#define CSR_REG_SIZE 0x04b0 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0100 +#define BBP_SIZE 0x0080 +#define RF_SIZE 0x0014 + +/* + * PCI registers. + */ + +/* + * PCI Configuration Header + */ +#define PCI_CONFIG_HEADER_VENDOR 0x0000 +#define PCI_CONFIG_HEADER_DEVICE 0x0002 + +/* + * HOST_CMD_CSR: For HOST to interrupt embedded processor + */ +#define HOST_CMD_CSR 0x0008 +#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x0000007f) +#define HOST_CMD_CSR_INTERRUPT_MCU FIELD32(0x00000080) + +/* + * MCU_CNTL_CSR + * SELECT_BANK: Select 8051 program bank. + * RESET: Enable 8051 reset state. + * READY: Ready state for 8051. + */ +#define MCU_CNTL_CSR 0x000c +#define MCU_CNTL_CSR_SELECT_BANK FIELD32(0x00000001) +#define MCU_CNTL_CSR_RESET FIELD32(0x00000002) +#define MCU_CNTL_CSR_READY FIELD32(0x00000004) + +/* + * SOFT_RESET_CSR + */ +#define SOFT_RESET_CSR 0x0010 + +/* + * MCU_INT_SOURCE_CSR: MCU interrupt source/mask register. + */ +#define MCU_INT_SOURCE_CSR 0x0014 +#define MCU_INT_SOURCE_CSR_0 FIELD32(0x00000001) +#define MCU_INT_SOURCE_CSR_1 FIELD32(0x00000002) +#define MCU_INT_SOURCE_CSR_2 FIELD32(0x00000004) +#define MCU_INT_SOURCE_CSR_3 FIELD32(0x00000008) +#define MCU_INT_SOURCE_CSR_4 FIELD32(0x00000010) +#define MCU_INT_SOURCE_CSR_5 FIELD32(0x00000020) +#define MCU_INT_SOURCE_CSR_6 FIELD32(0x00000040) +#define MCU_INT_SOURCE_CSR_7 FIELD32(0x00000080) +#define MCU_INT_SOURCE_CSR_TWAKEUP FIELD32(0x00000100) +#define MCU_INT_SOURCE_CSR_TBTT_EXPIRE FIELD32(0x00000200) + +/* + * MCU_INT_MASK_CSR: MCU interrupt source/mask register. + */ +#define MCU_INT_MASK_CSR 0x0018 +#define MCU_INT_MASK_CSR_0 FIELD32(0x00000001) +#define MCU_INT_MASK_CSR_1 FIELD32(0x00000002) +#define MCU_INT_MASK_CSR_2 FIELD32(0x00000004) +#define MCU_INT_MASK_CSR_3 FIELD32(0x00000008) +#define MCU_INT_MASK_CSR_4 FIELD32(0x00000010) +#define MCU_INT_MASK_CSR_5 FIELD32(0x00000020) +#define MCU_INT_MASK_CSR_6 FIELD32(0x00000040) +#define MCU_INT_MASK_CSR_7 FIELD32(0x00000080) +#define MCU_INT_MASK_CSR_TWAKEUP FIELD32(0x00000100) +#define MCU_INT_MASK_CSR_TBTT_EXPIRE FIELD32(0x00000200) + +/* + * PCI_USEC_CSR + */ +#define PCI_USEC_CSR 0x001c + +/* + * Security key table memory. + * 16 entries 32-byte for shared key table + * 64 entries 32-byte for pairwise key table + * 64 entries 8-byte for pairwise ta key table + */ +#define SHARED_KEY_TABLE_BASE 0x1000 +#define PAIRWISE_KEY_TABLE_BASE 0x1200 +#define PAIRWISE_TA_TABLE_BASE 0x1a00 + +struct hw_key_entry { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __attribute__ ((packed)); + +struct hw_pairwise_ta_entry { + u8 address[6]; + u8 reserved[2]; +} __attribute__ ((packed)); + +/* + * Other on-chip shared memory space. + */ +#define HW_CIS_BASE 0x2000 +#define HW_NULL_BASE 0x2b00 + +/* + * Since NULL frame won't be that long (256 byte), + * We steal 16 tail bytes to save debugging settings. + */ +#define HW_DEBUG_SETTING_BASE 0x2bf0 + +/* + * On-chip BEACON frame space. + */ +#define HW_BEACON_BASE0 0x2c00 +#define HW_BEACON_BASE1 0x2d00 +#define HW_BEACON_BASE2 0x2e00 +#define HW_BEACON_BASE3 0x2f00 +#define HW_BEACON_OFFSET 0x0100 + +/* + * HOST-MCU shared memory. + */ + +/* + * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. + */ +#define H2M_MAILBOX_CSR 0x2100 +#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000) +#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000) + +/* + * MCU_LEDCS: LED control for MCU Mailbox. + */ +#define MCU_LEDCS_LED_MODE FIELD16(0x001f) +#define MCU_LEDCS_RADIO_STATUS FIELD16(0x0020) +#define MCU_LEDCS_LINK_BG_STATUS FIELD16(0x0040) +#define MCU_LEDCS_LINK_A_STATUS FIELD16(0x0080) +#define MCU_LEDCS_POLARITY_GPIO_0 FIELD16(0x0100) +#define MCU_LEDCS_POLARITY_GPIO_1 FIELD16(0x0200) +#define MCU_LEDCS_POLARITY_GPIO_2 FIELD16(0x0400) +#define MCU_LEDCS_POLARITY_GPIO_3 FIELD16(0x0800) +#define MCU_LEDCS_POLARITY_GPIO_4 FIELD16(0x1000) +#define MCU_LEDCS_POLARITY_ACT FIELD16(0x2000) +#define MCU_LEDCS_POLARITY_READY_BG FIELD16(0x4000) +#define MCU_LEDCS_POLARITY_READY_A FIELD16(0x8000) + +/* + * M2H_CMD_DONE_CSR. + */ +#define M2H_CMD_DONE_CSR 0x2104 + +/* + * MCU_TXOP_ARRAY_BASE. + */ +#define MCU_TXOP_ARRAY_BASE 0x2110 + +/* + * MAC Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + */ +#define MAC_CSR0 0x3000 + +/* + * MAC_CSR1: System control register. + * SOFT_RESET: Software reset bit, 1: reset, 0: normal. + * BBP_RESET: Hardware reset BBP. + * HOST_READY: Host is ready after initialization, 1: ready. + */ +#define MAC_CSR1 0x3004 +#define MAC_CSR1_SOFT_RESET FIELD32(0x00000001) +#define MAC_CSR1_BBP_RESET FIELD32(0x00000002) +#define MAC_CSR1_HOST_READY FIELD32(0x00000004) + +/* + * MAC_CSR2: STA MAC register 0. + */ +#define MAC_CSR2 0x3008 +#define MAC_CSR2_BYTE0 FIELD32(0x000000ff) +#define MAC_CSR2_BYTE1 FIELD32(0x0000ff00) +#define MAC_CSR2_BYTE2 FIELD32(0x00ff0000) +#define MAC_CSR2_BYTE3 FIELD32(0xff000000) + +/* + * MAC_CSR3: STA MAC register 1. + */ +#define MAC_CSR3 0x300c +#define MAC_CSR3_BYTE4 FIELD32(0x000000ff) +#define MAC_CSR3_BYTE5 FIELD32(0x0000ff00) +#define MAC_CSR3_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) + +/* + * MAC_CSR4: BSSID register 0. + */ +#define MAC_CSR4 0x3010 +#define MAC_CSR4_BYTE0 FIELD32(0x000000ff) +#define MAC_CSR4_BYTE1 FIELD32(0x0000ff00) +#define MAC_CSR4_BYTE2 FIELD32(0x00ff0000) +#define MAC_CSR4_BYTE3 FIELD32(0xff000000) + +/* + * MAC_CSR5: BSSID register 1. + * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID. + */ +#define MAC_CSR5 0x3014 +#define MAC_CSR5_BYTE4 FIELD32(0x000000ff) +#define MAC_CSR5_BYTE5 FIELD32(0x0000ff00) +#define MAC_CSR5_BSS_ID_MASK FIELD32(0x00ff0000) + +/* + * MAC_CSR6: Maximum frame length register. + */ +#define MAC_CSR6 0x3018 +#define MAC_CSR6_MAX_FRAME_UNIT FIELD32(0x00000fff) + +/* + * MAC_CSR7: Reserved + */ +#define MAC_CSR7 0x301c + +/* + * MAC_CSR8: SIFS/EIFS register. + * All units are in US. + */ +#define MAC_CSR8 0x3020 +#define MAC_CSR8_SIFS FIELD32(0x000000ff) +#define MAC_CSR8_SIFS_AFTER_RX_OFDM FIELD32(0x0000ff00) +#define MAC_CSR8_EIFS FIELD32(0xffff0000) + +/* + * MAC_CSR9: Back-Off control register. + * SLOT_TIME: Slot time, default is 20us for 802.11BG. + * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1). + * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1). + * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD. + */ +#define MAC_CSR9 0x3024 +#define MAC_CSR9_SLOT_TIME FIELD32(0x000000ff) +#define MAC_CSR9_CWMIN FIELD32(0x00000f00) +#define MAC_CSR9_CWMAX FIELD32(0x0000f000) +#define MAC_CSR9_CW_SELECT FIELD32(0x00010000) + +/* + * MAC_CSR10: Power state configuration. + */ +#define MAC_CSR10 0x3028 + +/* + * MAC_CSR11: Power saving transition time register. + * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU. + * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup. + * WAKEUP_LATENCY: In unit of TU. + */ +#define MAC_CSR11 0x302c +#define MAC_CSR11_DELAY_AFTER_TBCN FIELD32(0x000000ff) +#define MAC_CSR11_TBCN_BEFORE_WAKEUP FIELD32(0x00007f00) +#define MAC_CSR11_AUTOWAKE FIELD32(0x00008000) +#define MAC_CSR11_WAKEUP_LATENCY FIELD32(0x000f0000) + +/* + * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1). + * CURRENT_STATE: 0:sleep, 1:awake. + * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP. + * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake. + */ +#define MAC_CSR12 0x3030 +#define MAC_CSR12_CURRENT_STATE FIELD32(0x00000001) +#define MAC_CSR12_PUT_TO_SLEEP FIELD32(0x00000002) +#define MAC_CSR12_FORCE_WAKEUP FIELD32(0x00000004) +#define MAC_CSR12_BBP_CURRENT_STATE FIELD32(0x00000008) + +/* + * MAC_CSR13: GPIO. + */ +#define MAC_CSR13 0x3034 +#define MAC_CSR13_BIT0 FIELD32(0x00000001) +#define MAC_CSR13_BIT1 FIELD32(0x00000002) +#define MAC_CSR13_BIT2 FIELD32(0x00000004) +#define MAC_CSR13_BIT3 FIELD32(0x00000008) +#define MAC_CSR13_BIT4 FIELD32(0x00000010) +#define MAC_CSR13_BIT5 FIELD32(0x00000020) +#define MAC_CSR13_BIT6 FIELD32(0x00000040) +#define MAC_CSR13_BIT7 FIELD32(0x00000080) +#define MAC_CSR13_BIT8 FIELD32(0x00000100) +#define MAC_CSR13_BIT9 FIELD32(0x00000200) +#define MAC_CSR13_BIT10 FIELD32(0x00000400) +#define MAC_CSR13_BIT11 FIELD32(0x00000800) +#define MAC_CSR13_BIT12 FIELD32(0x00001000) + +/* + * MAC_CSR14: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON. + * SW_LED: s/w LED, 1: ON, 0: OFF. + * HW_LED_POLARITY: 0: active low, 1: active high. + */ +#define MAC_CSR14 0x3038 +#define MAC_CSR14_ON_PERIOD FIELD32(0x000000ff) +#define MAC_CSR14_OFF_PERIOD FIELD32(0x0000ff00) +#define MAC_CSR14_HW_LED FIELD32(0x00010000) +#define MAC_CSR14_SW_LED FIELD32(0x00020000) +#define MAC_CSR14_HW_LED_POLARITY FIELD32(0x00040000) +#define MAC_CSR14_SW_LED2 FIELD32(0x00080000) + +/* + * MAC_CSR15: NAV control. + */ +#define MAC_CSR15 0x303c + +/* + * TXRX control registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXRX_CSR0: TX/RX configuration register. + * TSF_OFFSET: Default is 24. + * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame. + * DISABLE_RX: Disable Rx engine. + * DROP_CRC: Drop CRC error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TO_DS: Drop fram ToDs bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * DROP_MULTICAST: Drop multicast frames. + * DROP_BORADCAST: Drop broadcast frames. + * ROP_ACK_CTS: Drop received ACK and CTS. + */ +#define TXRX_CSR0 0x3040 +#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff) +#define TXRX_CSR0_TSF_OFFSET FIELD32(0x00007e00) +#define TXRX_CSR0_AUTO_TX_SEQ FIELD32(0x00008000) +#define TXRX_CSR0_DISABLE_RX FIELD32(0x00010000) +#define TXRX_CSR0_DROP_CRC FIELD32(0x00020000) +#define TXRX_CSR0_DROP_PHYSICAL FIELD32(0x00040000) +#define TXRX_CSR0_DROP_CONTROL FIELD32(0x00080000) +#define TXRX_CSR0_DROP_NOT_TO_ME FIELD32(0x00100000) +#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000) +#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000) +#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000) +#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000) +#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000) +#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000) + +/* + * TXRX_CSR1 + */ +#define TXRX_CSR1 0x3044 +#define TXRX_CSR1_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR1_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR1_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR1_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR1_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR1_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR1_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR1_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR2 + */ +#define TXRX_CSR2 0x3048 +#define TXRX_CSR2_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR2_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR2_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR2_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR2_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR2_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR2_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR2_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR3 + */ +#define TXRX_CSR3 0x304c +#define TXRX_CSR3_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR3_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR3_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR3_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR3_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR3_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR3_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR3_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR4: Auto-Responder/Tx-retry register. + * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble. + * OFDM_TX_RATE_DOWN: 1:enable. + * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step. + * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M. + */ +#define TXRX_CSR4 0x3050 +#define TXRX_CSR4_TX_ACK_TIMEOUT FIELD32(0x000000ff) +#define TXRX_CSR4_CNTL_ACK_POLICY FIELD32(0x00000700) +#define TXRX_CSR4_ACK_CTS_PSM FIELD32(0x00010000) +#define TXRX_CSR4_AUTORESPOND_ENABLE FIELD32(0x00020000) +#define TXRX_CSR4_AUTORESPOND_PREAMBLE FIELD32(0x00040000) +#define TXRX_CSR4_OFDM_TX_RATE_DOWN FIELD32(0x00080000) +#define TXRX_CSR4_OFDM_TX_RATE_STEP FIELD32(0x00300000) +#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK FIELD32(0x00400000) +#define TXRX_CSR4_LONG_RETRY_LIMIT FIELD32(0x0f000000) +#define TXRX_CSR4_SHORT_RETRY_LIMIT FIELD32(0xf0000000) + +/* + * TXRX_CSR5 + */ +#define TXRX_CSR5 0x3054 + +/* + * TXRX_CSR6: ACK/CTS payload consumed time + */ +#define TXRX_CSR6 0x3058 + +/* + * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps. + */ +#define TXRX_CSR7 0x305c +#define TXRX_CSR7_ACK_CTS_6MBS FIELD32(0x000000ff) +#define TXRX_CSR7_ACK_CTS_9MBS FIELD32(0x0000ff00) +#define TXRX_CSR7_ACK_CTS_12MBS FIELD32(0x00ff0000) +#define TXRX_CSR7_ACK_CTS_18MBS FIELD32(0xff000000) + +/* + * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps. + */ +#define TXRX_CSR8 0x3060 +#define TXRX_CSR8_ACK_CTS_24MBS FIELD32(0x000000ff) +#define TXRX_CSR8_ACK_CTS_36MBS FIELD32(0x0000ff00) +#define TXRX_CSR8_ACK_CTS_48MBS FIELD32(0x00ff0000) +#define TXRX_CSR8_ACK_CTS_54MBS FIELD32(0xff000000) + +/* + * TXRX_CSR9: Synchronization control register. + * BEACON_INTERVAL: In unit of 1/16 TU. + * TSF_TICKING: Enable TSF auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * BEACON_GEN: Enable beacon generator. + */ +#define TXRX_CSR9 0x3064 +#define TXRX_CSR9_BEACON_INTERVAL FIELD32(0x0000ffff) +#define TXRX_CSR9_TSF_TICKING FIELD32(0x00010000) +#define TXRX_CSR9_TSF_SYNC FIELD32(0x00060000) +#define TXRX_CSR9_TBTT_ENABLE FIELD32(0x00080000) +#define TXRX_CSR9_BEACON_GEN FIELD32(0x00100000) +#define TXRX_CSR9_TIMESTAMP_COMPENSATE FIELD32(0xff000000) + +/* + * TXRX_CSR10: BEACON alignment. + */ +#define TXRX_CSR10 0x3068 + +/* + * TXRX_CSR11: AES mask. + */ +#define TXRX_CSR11 0x306c + +/* + * TXRX_CSR12: TSF low 32. + */ +#define TXRX_CSR12 0x3070 +#define TXRX_CSR12_LOW_TSFTIMER FIELD32(0xffffffff) + +/* + * TXRX_CSR13: TSF high 32. + */ +#define TXRX_CSR13 0x3074 +#define TXRX_CSR13_HIGH_TSFTIMER FIELD32(0xffffffff) + +/* + * TXRX_CSR14: TBTT timer. + */ +#define TXRX_CSR14 0x3078 + +/* + * TXRX_CSR15: TKIP MIC priority byte "AND" mask. + */ +#define TXRX_CSR15 0x307c + +/* + * PHY control registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * PHY_CSR0: RF/PS control. + */ +#define PHY_CSR0 0x3080 +#define PHY_CSR0_PA_PE_BG FIELD32(0x00010000) +#define PHY_CSR0_PA_PE_A FIELD32(0x00020000) + +/* + * PHY_CSR1 + */ +#define PHY_CSR1 0x3084 + +/* + * PHY_CSR2: Pre-TX BBP control. + */ +#define PHY_CSR2 0x3088 + +/* + * PHY_CSR3: BBP serial control register. + * VALUE: Register value to program into BBP. + * REG_NUM: Selected BBP register. + * READ_CONTROL: 0: Write BBP, 1: Read BBP. + * BUSY: 1: ASIC is busy execute BBP programming. + */ +#define PHY_CSR3 0x308c +#define PHY_CSR3_VALUE FIELD32(0x000000ff) +#define PHY_CSR3_REGNUM FIELD32(0x00007f00) +#define PHY_CSR3_READ_CONTROL FIELD32(0x00008000) +#define PHY_CSR3_BUSY FIELD32(0x00010000) + +/* + * PHY_CSR4: RF serial control register + * VALUE: Register value (include register id) serial out to RF/IF chip. + * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22). + * IF_SELECT: 1: select IF to program, 0: select RF to program. + * PLL_LD: RF PLL_LD status. + * BUSY: 1: ASIC is busy execute RF programming. + */ +#define PHY_CSR4 0x3090 +#define PHY_CSR4_VALUE FIELD32(0x00ffffff) +#define PHY_CSR4_NUMBER_OF_BITS FIELD32(0x1f000000) +#define PHY_CSR4_IF_SELECT FIELD32(0x20000000) +#define PHY_CSR4_PLL_LD FIELD32(0x40000000) +#define PHY_CSR4_BUSY FIELD32(0x80000000) + +/* + * PHY_CSR5: RX to TX signal switch timing control. + */ +#define PHY_CSR5 0x3094 +#define PHY_CSR5_IQ_FLIP FIELD32(0x00000004) + +/* + * PHY_CSR6: TX to RX signal timing control. + */ +#define PHY_CSR6 0x3098 +#define PHY_CSR6_IQ_FLIP FIELD32(0x00000004) + +/* + * PHY_CSR7: TX DAC switching timing control. + */ +#define PHY_CSR7 0x309c + +/* + * Security control register. + */ + +/* + * SEC_CSR0: Shared key table control. + */ +#define SEC_CSR0 0x30a0 +#define SEC_CSR0_BSS0_KEY0_VALID FIELD32(0x00000001) +#define SEC_CSR0_BSS0_KEY1_VALID FIELD32(0x00000002) +#define SEC_CSR0_BSS0_KEY2_VALID FIELD32(0x00000004) +#define SEC_CSR0_BSS0_KEY3_VALID FIELD32(0x00000008) +#define SEC_CSR0_BSS1_KEY0_VALID FIELD32(0x00000010) +#define SEC_CSR0_BSS1_KEY1_VALID FIELD32(0x00000020) +#define SEC_CSR0_BSS1_KEY2_VALID FIELD32(0x00000040) +#define SEC_CSR0_BSS1_KEY3_VALID FIELD32(0x00000080) +#define SEC_CSR0_BSS2_KEY0_VALID FIELD32(0x00000100) +#define SEC_CSR0_BSS2_KEY1_VALID FIELD32(0x00000200) +#define SEC_CSR0_BSS2_KEY2_VALID FIELD32(0x00000400) +#define SEC_CSR0_BSS2_KEY3_VALID FIELD32(0x00000800) +#define SEC_CSR0_BSS3_KEY0_VALID FIELD32(0x00001000) +#define SEC_CSR0_BSS3_KEY1_VALID FIELD32(0x00002000) +#define SEC_CSR0_BSS3_KEY2_VALID FIELD32(0x00004000) +#define SEC_CSR0_BSS3_KEY3_VALID FIELD32(0x00008000) + +/* + * SEC_CSR1: Shared key table security mode register. + */ +#define SEC_CSR1 0x30a4 +#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG FIELD32(0x00000007) +#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG FIELD32(0x00000070) +#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG FIELD32(0x00000700) +#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG FIELD32(0x00007000) +#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG FIELD32(0x00070000) +#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG FIELD32(0x00700000) +#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG FIELD32(0x07000000) +#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG FIELD32(0x70000000) + +/* + * Pairwise key table valid bitmap registers. + * SEC_CSR2: pairwise key table valid bitmap 0. + * SEC_CSR3: pairwise key table valid bitmap 1. + */ +#define SEC_CSR2 0x30a8 +#define SEC_CSR3 0x30ac + +/* + * SEC_CSR4: Pairwise key table lookup control. + */ +#define SEC_CSR4 0x30b0 + +/* + * SEC_CSR5: shared key table security mode register. + */ +#define SEC_CSR5 0x30b4 +#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG FIELD32(0x00000007) +#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG FIELD32(0x00000070) +#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG FIELD32(0x00000700) +#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG FIELD32(0x00007000) +#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG FIELD32(0x00070000) +#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG FIELD32(0x00700000) +#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG FIELD32(0x07000000) +#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG FIELD32(0x70000000) + +/* + * STA control registers. + */ + +/* + * STA_CSR0: RX PLCP error count & RX FCS error count. + */ +#define STA_CSR0 0x30c0 +#define STA_CSR0_FCS_ERROR FIELD32(0x0000ffff) +#define STA_CSR0_PLCP_ERROR FIELD32(0xffff0000) + +/* + * STA_CSR1: RX False CCA count & RX LONG frame count. + */ +#define STA_CSR1 0x30c4 +#define STA_CSR1_PHYSICAL_ERROR FIELD32(0x0000ffff) +#define STA_CSR1_FALSE_CCA_ERROR FIELD32(0xffff0000) + +/* + * STA_CSR2: TX Beacon count and RX FIFO overflow count. + */ +#define STA_CSR2 0x30c8 +#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT FIELD32(0x0000ffff) +#define STA_CSR2_RX_OVERFLOW_COUNT FIELD32(0xffff0000) + +/* + * STA_CSR3: TX Beacon count. + */ +#define STA_CSR3 0x30cc +#define STA_CSR3_TX_BEACON_COUNT FIELD32(0x0000ffff) + +/* + * STA_CSR4: TX Result status register. + * VALID: 1:This register contains a valid TX result. + */ +#define STA_CSR4 0x30d0 +#define STA_CSR4_VALID FIELD32(0x00000001) +#define STA_CSR4_TX_RESULT FIELD32(0x0000000e) +#define STA_CSR4_RETRY_COUNT FIELD32(0x000000f0) +#define STA_CSR4_PID_SUBTYPE FIELD32(0x00001f00) +#define STA_CSR4_PID_TYPE FIELD32(0x0000e000) +#define STA_CSR4_TXRATE FIELD32(0x000f0000) + +/* + * QOS control registers. + */ + +/* + * QOS_CSR0: TXOP holder MAC address register. + */ +#define QOS_CSR0 0x30e0 +#define QOS_CSR0_BYTE0 FIELD32(0x000000ff) +#define QOS_CSR0_BYTE1 FIELD32(0x0000ff00) +#define QOS_CSR0_BYTE2 FIELD32(0x00ff0000) +#define QOS_CSR0_BYTE3 FIELD32(0xff000000) + +/* + * QOS_CSR1: TXOP holder MAC address register. + */ +#define QOS_CSR1 0x30e4 +#define QOS_CSR1_BYTE4 FIELD32(0x000000ff) +#define QOS_CSR1_BYTE5 FIELD32(0x0000ff00) + +/* + * QOS_CSR2: TXOP holder timeout register. + */ +#define QOS_CSR2 0x30e8 + +/* + * RX QOS-CFPOLL MAC address register. + * QOS_CSR3: RX QOS-CFPOLL MAC address 0. + * QOS_CSR4: RX QOS-CFPOLL MAC address 1. + */ +#define QOS_CSR3 0x30ec +#define QOS_CSR4 0x30f0 + +/* + * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL. + */ +#define QOS_CSR5 0x30f4 + +/* + * Host DMA registers. + */ + +/* + * AC0_BASE_CSR: AC_BK base address. + */ +#define AC0_BASE_CSR 0x3400 +#define AC0_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * AC1_BASE_CSR: AC_BE base address. + */ +#define AC1_BASE_CSR 0x3404 +#define AC1_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * AC2_BASE_CSR: AC_VI base address. + */ +#define AC2_BASE_CSR 0x3408 +#define AC2_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * AC3_BASE_CSR: AC_VO base address. + */ +#define AC3_BASE_CSR 0x340c +#define AC3_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * MGMT_BASE_CSR: MGMT ring base address. + */ +#define MGMT_BASE_CSR 0x3410 +#define MGMT_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO. + */ +#define TX_RING_CSR0 0x3418 +#define TX_RING_CSR0_AC0_RING_SIZE FIELD32(0x000000ff) +#define TX_RING_CSR0_AC1_RING_SIZE FIELD32(0x0000ff00) +#define TX_RING_CSR0_AC2_RING_SIZE FIELD32(0x00ff0000) +#define TX_RING_CSR0_AC3_RING_SIZE FIELD32(0xff000000) + +/* + * TX_RING_CSR1: TX Ring size for MGMT Ring, HCCA Ring + * TXD_SIZE: In unit of 32-bit. + */ +#define TX_RING_CSR1 0x341c +#define TX_RING_CSR1_MGMT_RING_SIZE FIELD32(0x000000ff) +#define TX_RING_CSR1_HCCA_RING_SIZE FIELD32(0x0000ff00) +#define TX_RING_CSR1_TXD_SIZE FIELD32(0x003f0000) + +/* + * AIFSN_CSR: AIFSN for each EDCA AC. + * AIFSN0: For AC_BK. + * AIFSN1: For AC_BE. + * AIFSN2: For AC_VI. + * AIFSN3: For AC_VO. + */ +#define AIFSN_CSR 0x3420 +#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f) +#define AIFSN_CSR_AIFSN1 FIELD32(0x000000f0) +#define AIFSN_CSR_AIFSN2 FIELD32(0x00000f00) +#define AIFSN_CSR_AIFSN3 FIELD32(0x0000f000) + +/* + * CWMIN_CSR: CWmin for each EDCA AC. + * CWMIN0: For AC_BK. + * CWMIN1: For AC_BE. + * CWMIN2: For AC_VI. + * CWMIN3: For AC_VO. + */ +#define CWMIN_CSR 0x3424 +#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f) +#define CWMIN_CSR_CWMIN1 FIELD32(0x000000f0) +#define CWMIN_CSR_CWMIN2 FIELD32(0x00000f00) +#define CWMIN_CSR_CWMIN3 FIELD32(0x0000f000) + +/* + * CWMAX_CSR: CWmax for each EDCA AC. + * CWMAX0: For AC_BK. + * CWMAX1: For AC_BE. + * CWMAX2: For AC_VI. + * CWMAX3: For AC_VO. + */ +#define CWMAX_CSR 0x3428 +#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f) +#define CWMAX_CSR_CWMAX1 FIELD32(0x000000f0) +#define CWMAX_CSR_CWMAX2 FIELD32(0x00000f00) +#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000) + +/* + * TX_DMA_DST_CSR: TX DMA destination + * 0: TX ring0, 1: TX ring1, 2: TX ring2 3: invalid + */ +#define TX_DMA_DST_CSR 0x342c +#define TX_DMA_DST_CSR_DEST_AC0 FIELD32(0x00000003) +#define TX_DMA_DST_CSR_DEST_AC1 FIELD32(0x0000000c) +#define TX_DMA_DST_CSR_DEST_AC2 FIELD32(0x00000030) +#define TX_DMA_DST_CSR_DEST_AC3 FIELD32(0x000000c0) +#define TX_DMA_DST_CSR_DEST_MGMT FIELD32(0x00000300) + +/* + * TX_CNTL_CSR: KICK/Abort TX. + * KICK_TX_AC0: For AC_BK. + * KICK_TX_AC1: For AC_BE. + * KICK_TX_AC2: For AC_VI. + * KICK_TX_AC3: For AC_VO. + * ABORT_TX_AC0: For AC_BK. + * ABORT_TX_AC1: For AC_BE. + * ABORT_TX_AC2: For AC_VI. + * ABORT_TX_AC3: For AC_VO. + */ +#define TX_CNTL_CSR 0x3430 +#define TX_CNTL_CSR_KICK_TX_AC0 FIELD32(0x00000001) +#define TX_CNTL_CSR_KICK_TX_AC1 FIELD32(0x00000002) +#define TX_CNTL_CSR_KICK_TX_AC2 FIELD32(0x00000004) +#define TX_CNTL_CSR_KICK_TX_AC3 FIELD32(0x00000008) +#define TX_CNTL_CSR_KICK_TX_MGMT FIELD32(0x00000010) +#define TX_CNTL_CSR_ABORT_TX_AC0 FIELD32(0x00010000) +#define TX_CNTL_CSR_ABORT_TX_AC1 FIELD32(0x00020000) +#define TX_CNTL_CSR_ABORT_TX_AC2 FIELD32(0x00040000) +#define TX_CNTL_CSR_ABORT_TX_AC3 FIELD32(0x00080000) +#define TX_CNTL_CSR_ABORT_TX_MGMT FIELD32(0x00100000) + +/* + * LOAD_TX_RING_CSR: Load RX de + */ +#define LOAD_TX_RING_CSR 0x3434 +#define LOAD_TX_RING_CSR_LOAD_TXD_AC0 FIELD32(0x00000001) +#define LOAD_TX_RING_CSR_LOAD_TXD_AC1 FIELD32(0x00000002) +#define LOAD_TX_RING_CSR_LOAD_TXD_AC2 FIELD32(0x00000004) +#define LOAD_TX_RING_CSR_LOAD_TXD_AC3 FIELD32(0x00000008) +#define LOAD_TX_RING_CSR_LOAD_TXD_MGMT FIELD32(0x00000010) + +/* + * Several read-only registers, for debugging. + */ +#define AC0_TXPTR_CSR 0x3438 +#define AC1_TXPTR_CSR 0x343c +#define AC2_TXPTR_CSR 0x3440 +#define AC3_TXPTR_CSR 0x3444 +#define MGMT_TXPTR_CSR 0x3448 + +/* + * RX_BASE_CSR + */ +#define RX_BASE_CSR 0x3450 +#define RX_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * RX_RING_CSR. + * RXD_SIZE: In unit of 32-bit. + */ +#define RX_RING_CSR 0x3454 +#define RX_RING_CSR_RING_SIZE FIELD32(0x000000ff) +#define RX_RING_CSR_RXD_SIZE FIELD32(0x00003f00) +#define RX_RING_CSR_RXD_WRITEBACK_SIZE FIELD32(0x00070000) + +/* + * RX_CNTL_CSR + */ +#define RX_CNTL_CSR 0x3458 +#define RX_CNTL_CSR_ENABLE_RX_DMA FIELD32(0x00000001) +#define RX_CNTL_CSR_LOAD_RXD FIELD32(0x00000002) + +/* + * RXPTR_CSR: Read-only, for debugging. + */ +#define RXPTR_CSR 0x345c + +/* + * PCI_CFG_CSR + */ +#define PCI_CFG_CSR 0x3460 + +/* + * BUF_FORMAT_CSR + */ +#define BUF_FORMAT_CSR 0x3464 + +/* + * INT_SOURCE_CSR: Interrupt source register. + * Write one to clear corresponding bit. + */ +#define INT_SOURCE_CSR 0x3468 +#define INT_SOURCE_CSR_TXDONE FIELD32(0x00000001) +#define INT_SOURCE_CSR_RXDONE FIELD32(0x00000002) +#define INT_SOURCE_CSR_BEACON_DONE FIELD32(0x00000004) +#define INT_SOURCE_CSR_TX_ABORT_DONE FIELD32(0x00000010) +#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00010000) +#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00020000) +#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00040000) +#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00080000) +#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00100000) +#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00200000) + +/* + * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF. + * MITIGATION_PERIOD: Interrupt mitigation in unit of 32 PCI clock. + */ +#define INT_MASK_CSR 0x346c +#define INT_MASK_CSR_TXDONE FIELD32(0x00000001) +#define INT_MASK_CSR_RXDONE FIELD32(0x00000002) +#define INT_MASK_CSR_BEACON_DONE FIELD32(0x00000004) +#define INT_MASK_CSR_TX_ABORT_DONE FIELD32(0x00000010) +#define INT_MASK_CSR_ENABLE_MITIGATION FIELD32(0x00000080) +#define INT_MASK_CSR_MITIGATION_PERIOD FIELD32(0x0000ff00) +#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00010000) +#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00020000) +#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00040000) +#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00080000) +#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00100000) +#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00200000) + +/* + * E2PROM_CSR: EEPROM control register. + * RELOAD: Write 1 to reload eeprom content. + * TYPE_93C46: 1: 93c46, 0:93c66. + * LOAD_STATUS: 1:loading, 0:done. + */ +#define E2PROM_CSR 0x3470 +#define E2PROM_CSR_RELOAD FIELD32(0x00000001) +#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000002) +#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000004) +#define E2PROM_CSR_DATA_IN FIELD32(0x00000008) +#define E2PROM_CSR_DATA_OUT FIELD32(0x00000010) +#define E2PROM_CSR_TYPE_93C46 FIELD32(0x00000020) +#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040) + +/* + * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register. + * AC0_TX_OP: For AC_BK, in unit of 32us. + * AC1_TX_OP: For AC_BE, in unit of 32us. + */ +#define AC_TXOP_CSR0 0x3474 +#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff) +#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000) + +/* + * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register. + * AC2_TX_OP: For AC_VI, in unit of 32us. + * AC3_TX_OP: For AC_VO, in unit of 32us. + */ +#define AC_TXOP_CSR1 0x3478 +#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff) +#define AC_TXOP_CSR1_AC3_TX_OP FIELD32(0xffff0000) + +/* + * DMA_STATUS_CSR + */ +#define DMA_STATUS_CSR 0x3480 + +/* + * TEST_MODE_CSR + */ +#define TEST_MODE_CSR 0x3484 + +/* + * UART0_TX_CSR + */ +#define UART0_TX_CSR 0x3488 + +/* + * UART0_RX_CSR + */ +#define UART0_RX_CSR 0x348c + +/* + * UART0_FRAME_CSR + */ +#define UART0_FRAME_CSR 0x3490 + +/* + * UART0_BUFFER_CSR + */ +#define UART0_BUFFER_CSR 0x3494 + +/* + * IO_CNTL_CSR + */ +#define IO_CNTL_CSR 0x3498 + +/* + * UART_INT_SOURCE_CSR + */ +#define UART_INT_SOURCE_CSR 0x34a8 + +/* + * UART_INT_MASK_CSR + */ +#define UART_INT_MASK_CSR 0x34ac + +/* + * PBF_QUEUE_CSR + */ +#define PBF_QUEUE_CSR 0x34b0 + +/* + * Firmware DMA registers. + * Firmware DMA registers are dedicated for MCU usage + * and should not be touched by host driver. + * Therefore we skip the definition of these registers. + */ +#define FW_TX_BASE_CSR 0x34c0 +#define FW_TX_START_CSR 0x34c4 +#define FW_TX_LAST_CSR 0x34c8 +#define FW_MODE_CNTL_CSR 0x34cc +#define FW_TXPTR_CSR 0x34d0 + +/* + * 8051 firmware image. + */ +#define FIRMWARE_RT2561 "rt2561.bin" +#define FIRMWARE_RT2561s "rt2561s.bin" +#define FIRMWARE_RT2661 "rt2661.bin" +#define FIRMWARE_IMAGE_BASE 0x4000 + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R2 + */ +#define BBP_R2_BG_MODE FIELD8(0x20) + +/* + * R3 + */ +#define BBP_R3_SMART_MODE FIELD8(0x01) + +/* + * R4: RX antenna control + * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529) + */ +#define BBP_R4_RX_ANTENNA FIELD8(0x03) +#define BBP_R4_RX_FRAME_END FIELD8(0x20) + +/* + * R77 + */ +#define BBP_R77_PAIR FIELD8(0x03) + +/* + * RF registers + */ + +/* + * RF 3 + */ +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * RF 4 + */ +#define RF4_FREQ_OFFSET FIELD32(0x0003f000) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0004 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0006 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * 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. + * DYN_TXAGC: Dynamic TX AGC control. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + * RF_TYPE: Rf_type of this adapter. + */ +#define EEPROM_ANTENNA 0x0010 +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_FRAME_TYPE FIELD16(0x0040) +#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800) + +/* + * EEPROM NIC config. + * ENABLE_DIVERSITY: 1:enable, 0:disable. + * EXTERNAL_LNA_BG: External LNA enable for 2.4G. + * CARDBUS_ACCEL: 0:enable, 1:disable. + * EXTERNAL_LNA_A: External LNA enable for 5G. + */ +#define EEPROM_NIC 0x0011 +#define EEPROM_NIC_ENABLE_DIVERSITY FIELD16(0x0001) +#define EEPROM_NIC_TX_DIVERSITY FIELD16(0x0002) +#define EEPROM_NIC_TX_RX_FIXED FIELD16(0x000c) +#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0010) +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0020) +#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0040) + +/* + * EEPROM geography. + * GEO_A: Default geographical setting for 5GHz band + * GEO: Default geographical setting. + */ +#define EEPROM_GEOGRAPHY 0x0012 +#define EEPROM_GEOGRAPHY_GEO_A FIELD16(0x00ff) +#define EEPROM_GEOGRAPHY_GEO FIELD16(0xff00) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0013 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER 802.11G + */ +#define EEPROM_TXPOWER_G_START 0x0023 +#define EEPROM_TXPOWER_G_SIZE 7 +#define EEPROM_TXPOWER_G_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_G_2 FIELD16(0xff00) + +/* + * EEPROM Frequency + */ +#define EEPROM_FREQ 0x002f +#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) +#define EEPROM_FREQ_SEQ_MASK FIELD16(0xff00) +#define EEPROM_FREQ_SEQ FIELD16(0x0300) + +/* + * EEPROM LED. + * POLARITY_RDY_G: Polarity RDY_G setting. + * POLARITY_RDY_A: Polarity RDY_A setting. + * POLARITY_ACT: Polarity ACT setting. + * POLARITY_GPIO_0: Polarity GPIO0 setting. + * POLARITY_GPIO_1: Polarity GPIO1 setting. + * POLARITY_GPIO_2: Polarity GPIO2 setting. + * POLARITY_GPIO_3: Polarity GPIO3 setting. + * POLARITY_GPIO_4: Polarity GPIO4 setting. + * LED_MODE: Led mode. + */ +#define EEPROM_LED 0x0030 +#define EEPROM_LED_POLARITY_RDY_G FIELD16(0x0001) +#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) +#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) +#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) +#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) +#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) +#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) +#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) +#define EEPROM_LED_LED_MODE FIELD16(0x1f00) + +/* + * EEPROM TXPOWER 802.11A + */ +#define EEPROM_TXPOWER_A_START 0x0031 +#define EEPROM_TXPOWER_A_SIZE 12 +#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + +/* + * EEPROM RSSI offset 802.11BG + */ +#define EEPROM_RSSI_OFFSET_BG 0x004d +#define EEPROM_RSSI_OFFSET_BG_1 FIELD16(0x00ff) +#define EEPROM_RSSI_OFFSET_BG_2 FIELD16(0xff00) + +/* + * EEPROM RSSI offset 802.11A + */ +#define EEPROM_RSSI_OFFSET_A 0x004e +#define EEPROM_RSSI_OFFSET_A_1 FIELD16(0x00ff) +#define EEPROM_RSSI_OFFSET_A_2 FIELD16(0xff00) + +/* + * MCU mailbox commands. + */ +#define MCU_SLEEP 0x30 +#define MCU_WAKEUP 0x31 +#define MCU_LED 0x50 +#define MCU_LED_STRENGTH 0x52 + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 16 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 16 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO and Beacon Ring. + */ + +/* + * Word0 + * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used. + * KEY_TABLE: Use per-client pairwise KEY table. + * KEY_INDEX: + * Key index (0~31) to the pairwise KEY table. + * 0~3 to shared KEY table 0 (BSS0). + * 4~7 to shared KEY table 1 (BSS1). + * 8~11 to shared KEY table 2 (BSS2). + * 12~15 to shared KEY table 3 (BSS3). + * BURST: Next frame belongs to same "burst" event. + */ +#define TXD_W0_OWNER_NIC FIELD32(0x00000001) +#define TXD_W0_VALID FIELD32(0x00000002) +#define TXD_W0_MORE_FRAG FIELD32(0x00000004) +#define TXD_W0_ACK FIELD32(0x00000008) +#define TXD_W0_TIMESTAMP FIELD32(0x00000010) +#define TXD_W0_OFDM FIELD32(0x00000020) +#define TXD_W0_IFS FIELD32(0x00000040) +#define TXD_W0_RETRY_MODE FIELD32(0x00000080) +#define TXD_W0_TKIP_MIC FIELD32(0x00000100) +#define TXD_W0_KEY_TABLE FIELD32(0x00000200) +#define TXD_W0_KEY_INDEX FIELD32(0x0000fc00) +#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define TXD_W0_BURST FIELD32(0x10000000) +#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + * HOST_Q_ID: EDCA/HCCA queue ID. + * HW_SEQUENCE: MAC overwrites the frame sequence number. + * BUFFER_COUNT: Number of buffers in this TXD. + */ +#define TXD_W1_HOST_Q_ID FIELD32(0x0000000f) +#define TXD_W1_AIFSN FIELD32(0x000000f0) +#define TXD_W1_CWMIN FIELD32(0x00000f00) +#define TXD_W1_CWMAX FIELD32(0x0000f000) +#define TXD_W1_IV_OFFSET FIELD32(0x003f0000) +#define TXD_W1_PIGGY_BACK FIELD32(0x01000000) +#define TXD_W1_HW_SEQUENCE FIELD32(0x10000000) +#define TXD_W1_BUFFER_COUNT FIELD32(0xe0000000) + +/* + * Word2: PLCP information + */ +#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00) +#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000) +#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Word3 + */ +#define TXD_W3_IV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define TXD_W4_EIV FIELD32(0xffffffff) + +/* + * Word5 + * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field). + * TXD_W5_PID_SUBTYPE: Driver assigned packet ID index for txdone handler. + * TXD_W5_PID_TYPE: Driver assigned packet ID type for txdone handler. + * WAITING_DMA_DONE_INT: TXD been filled with data + * and waiting for TxDoneISR housekeeping. + */ +#define TXD_W5_FRAME_OFFSET FIELD32(0x000000ff) +#define TXD_W5_PID_SUBTYPE FIELD32(0x00001f00) +#define TXD_W5_PID_TYPE FIELD32(0x0000e000) +#define TXD_W5_TX_POWER FIELD32(0x00ff0000) +#define TXD_W5_WAITING_DMA_DONE_INT FIELD32(0x01000000) + +/* + * the above 24-byte is called TXINFO and will be DMAed to MAC block + * through TXFIFO. MAC block use this TXINFO to control the transmission + * behavior of this frame. + * The following fields are not used by MAC block. + * They are used by DMA block and HOST driver only. + * Once a frame has been DMA to ASIC, all the following fields are useless + * to ASIC. + */ + +/* + * Word6-10: Buffer physical address + */ +#define TXD_W6_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) +#define TXD_W7_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) +#define TXD_W8_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) +#define TXD_W9_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) +#define TXD_W10_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) + +/* + * Word11-13: Buffer length + */ +#define TXD_W11_BUFFER_LENGTH0 FIELD32(0x00000fff) +#define TXD_W11_BUFFER_LENGTH1 FIELD32(0x0fff0000) +#define TXD_W12_BUFFER_LENGTH2 FIELD32(0x00000fff) +#define TXD_W12_BUFFER_LENGTH3 FIELD32(0x0fff0000) +#define TXD_W13_BUFFER_LENGTH4 FIELD32(0x00000fff) + +/* + * Word14 + */ +#define TXD_W14_SK_BUFFER FIELD32(0xffffffff) + +/* + * Word15 + */ +#define TXD_W15_NEXT_SK_BUFFER FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key. + * KEY_INDEX: Decryption key actually used. + */ +#define RXD_W0_OWNER_NIC FIELD32(0x00000001) +#define RXD_W0_DROP FIELD32(0x00000002) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000004) +#define RXD_W0_MULTICAST FIELD32(0x00000008) +#define RXD_W0_BROADCAST FIELD32(0x00000010) +#define RXD_W0_MY_BSS FIELD32(0x00000020) +#define RXD_W0_CRC_ERROR FIELD32(0x00000040) +#define RXD_W0_OFDM FIELD32(0x00000080) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000300) +#define RXD_W0_KEY_INDEX FIELD32(0x0000fc00) +#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + * SIGNAL: RX raw data rate reported by BBP. + */ +#define RXD_W1_SIGNAL FIELD32(0x000000ff) +#define RXD_W1_RSSI_AGC FIELD32(0x00001f00) +#define RXD_W1_RSSI_LNA FIELD32(0x00006000) +#define RXD_W1_FRAME_OFFSET FIELD32(0x7f000000) + +/* + * Word2 + * IV: Received IV of originally encrypted. + */ +#define RXD_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + * EIV: Received EIV of originally encrypted. + */ +#define RXD_W3_EIV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define RXD_W4_RESERVED FIELD32(0xffffffff) + +/* + * the above 20-byte is called RXINFO and will be DMAed to MAC RX block + * and passed to the HOST driver. + * The following fields are for DMA block and HOST usage only. + * Can't be touched by ASIC MAC block. + */ + +/* + * Word5 + */ +#define RXD_W5_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) + +/* + * Word6-15: Reserved + */ +#define RXD_W6_RESERVED FIELD32(0xffffffff) +#define RXD_W7_RESERVED FIELD32(0xffffffff) +#define RXD_W8_RESERVED FIELD32(0xffffffff) +#define RXD_W9_RESERVED FIELD32(0xffffffff) +#define RXD_W10_RESERVED FIELD32(0xffffffff) +#define RXD_W11_RESERVED FIELD32(0xffffffff) +#define RXD_W12_RESERVED FIELD32(0xffffffff) +#define RXD_W13_RESERVED FIELD32(0xffffffff) +#define RXD_W14_RESERVED FIELD32(0xffffffff) +#define RXD_W15_RESERVED FIELD32(0xffffffff) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + */ +#define MIN_TXPOWER 0 +#define MAX_TXPOWER 31 +#define DEFAULT_TXPOWER 24 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? \ + DEFAULT_TXPOWER : (__txpower); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ + (__txpower)); \ +}) + +#endif /* RT61PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c new file mode 100644 index 000000000000..b047c7c0f9ee --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -0,0 +1,2124 @@ +/* + Copyright (C) 2004 - 2007 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: rt73usb + Abstract: rt73usb device specific routines. + Supported chipsets: rt2571W & rt2671. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt73usb" + +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00usb.h" +#include "rt73usb.h" + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt73usb_register_read and rt73usb_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(u32), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +static inline void rt73usb_register_multiread(const struct rt2x00_dev + *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + int timeout = REGISTER_TIMEOUT * (length / sizeof(u32)); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + value, length, timeout); +} + +static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(u32), REGISTER_TIMEOUT); +} + +static inline void rt73usb_register_multiwrite(const struct rt2x00_dev + *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + int timeout = REGISTER_TIMEOUT * (length / sizeof(u32)); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + value, length, timeout); +} + +static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt73usb_register_read(rt2x00dev, PHY_CSR3, ®); + if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt73usb_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt73usb_register_write(rt2x00dev, PHY_CSR3, reg); +} + +static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt73usb_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + + rt73usb_register_write(rt2x00dev, PHY_CSR3, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt73usb_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + *value = 0xff; + return; + } + + *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); +} + +static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt73usb_register_read(rt2x00dev, PHY_CSR4, ®); + if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); + else + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 20); + + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + + rt73usb_register_write(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) + +static void rt73usb_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data); +} + +static void rt73usb_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt73usb_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt73usb_read_csr, + .write = rt73usb_write_csr, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt73usb_bbp_read, + .write = rt73usb_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt73usb_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +/* + * Configuration handlers. + */ +static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le32 reg[2]; + u32 tmp; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + tmp = le32_to_cpu(reg[1]); + rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); + reg[1] = cpu_to_le32(tmp); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); +} + +static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le32 reg[2]; + u32 tmp; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + tmp = le32_to_cpu(reg[1]); + rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); + reg[1] = cpu_to_le32(tmp); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); +} + +static void rt73usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + int multicast = !!(filter & IFF_MULTICAST); + int broadcast = !!(filter & IFF_BROADCAST); + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); +} + +static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) +{ + u32 reg; + + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + + /* + * Apply hardware packet filter. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); + else + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); + } + + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + /* + * Enable synchronisation. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); + } + + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); + + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); +} + +static void rt73usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u32 reg; + u32 value; + u32 preamble; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + + rt73usb_register_write(rt2x00dev, TXRX_CSR5, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, value); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + if (preamble == SHORT_PREAMBLE) + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 1); + else + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); +} + +static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + if (phymode == MODE_IEEE80211A) + rt2x00dev->curr_hwmode = HWMODE_A; + else if (phymode == MODE_IEEE80211B) + rt2x00dev->curr_hwmode = HWMODE_B; + else + rt2x00dev->curr_hwmode = HWMODE_G; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt73usb_config_rate(rt2x00dev, rate->val2); +} + +static void rt73usb_config_lock_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, + const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt73usb_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt73usb_bbp_write(rt2x00dev, 94, r94); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(10); +} + +static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel, + const int txpower) +{ + struct rf_channel rf; + + /* + * Fill rf_reg structure. + */ + memcpy(&rf, &rt2x00dev->spec.channels[index], sizeof(rf)); + + rt73usb_config_lock_channel(rt2x00dev, &rf, txpower); +} + +static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt73usb_config_lock_channel(rt2x00dev, &rf, txpower); +} + +static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u8 r3; + u8 r4; + u8 r77; + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt73usb_bbp_read(rt2x00dev, 4, &r4); + rt73usb_bbp_read(rt2x00dev, 77, &r77); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !!(rt2x00dev->curr_hwmode != HWMODE_A)); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + if (rt2x00dev->curr_hwmode == HWMODE_A) + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + else + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + if (rt2x00dev->curr_hwmode == HWMODE_A) + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + else + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + + rt73usb_bbp_write(rt2x00dev, 77, r77); + rt73usb_bbp_write(rt2x00dev, 3, r3); + rt73usb_bbp_write(rt2x00dev, 4, r4); +} + +static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u8 r3; + u8 r4; + u8 r77; + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt73usb_bbp_read(rt2x00dev, 4, &r4); + rt73usb_bbp_read(rt2x00dev, 77, &r77); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + + rt73usb_bbp_write(rt2x00dev, 77, r77); + rt73usb_bbp_write(rt2x00dev, 3, r3); + rt73usb_bbp_write(rt2x00dev, 4, r4); +} + +struct antenna_sel { + u8 word; + /* + * value[0] -> non-LNA + * value[1] -> LNA + */ + u8 value[2]; +}; + +static const struct antenna_sel antenna_sel_a[] = { + { 96, { 0x58, 0x78 } }, + { 104, { 0x38, 0x48 } }, + { 75, { 0xfe, 0x80 } }, + { 86, { 0xfe, 0x80 } }, + { 88, { 0xfe, 0x80 } }, + { 35, { 0x60, 0x60 } }, + { 97, { 0x58, 0x58 } }, + { 98, { 0x58, 0x58 } }, +}; + +static const struct antenna_sel antenna_sel_bg[] = { + { 96, { 0x48, 0x68 } }, + { 104, { 0x2c, 0x3c } }, + { 75, { 0xfe, 0x80 } }, + { 86, { 0xfe, 0x80 } }, + { 88, { 0xfe, 0x80 } }, + { 35, { 0x50, 0x50 } }, + { 97, { 0x48, 0x48 } }, + { 98, { 0x48, 0x48 } }, +}; + +static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, const int antenna_rx) +{ + const struct antenna_sel *sel; + unsigned int lna; + unsigned int i; + u32 reg; + + rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); + + if (rt2x00dev->curr_hwmode == HWMODE_A) { + sel = antenna_sel_a; + lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 0); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 1); + } else { + sel = antenna_sel_bg; + lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 1); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 0); + } + + for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) + rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); + + rt73usb_register_write(rt2x00dev, PHY_CSR0, reg); + + if (rt2x00_rf(&rt2x00dev->chip, RF5226) || + rt2x00_rf(&rt2x00dev->chip, RF5225)) + rt73usb_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx); + else if (rt2x00_rf(&rt2x00dev->chip, RF2528) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) + rt73usb_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx); +} + +static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, + const int short_slot_time, + const int beacon_int) +{ + u32 reg; + + rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + + rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, SIFS); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, EIFS); + rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, beacon_int * 16); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); +} + +static void rt73usb_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt73usb_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt73usb_config_channel(rt2x00dev, conf->channel_val, + conf->channel, conf->power_level); + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt73usb_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt73usb_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt73usb_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +/* + * LED functions. + */ +static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt73usb_register_read(rt2x00dev, MAC_CSR14, ®); + rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70); + rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30); + rt73usb_register_write(rt2x00dev, MAC_CSR14, reg); + + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) + rt2x00_set_field16(&rt2x00dev->led_reg, + MCU_LEDCS_LINK_A_STATUS, 1); + else + rt2x00_set_field16(&rt2x00dev->led_reg, + MCU_LEDCS_LINK_BG_STATUS, 1); + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, + rt2x00dev->led_reg, REGISTER_TIMEOUT); +} + +static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev) +{ + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 0); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, 0); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, 0); + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, + rt2x00dev->led_reg, REGISTER_TIMEOUT); +} + +static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) +{ + u32 led; + + if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH) + return; + + /* + * Led handling requires a positive value for the rssi, + * to do that correctly we need to add the correction. + */ + rssi += rt2x00dev->rssi_offset; + + if (rssi <= 30) + led = 0; + else if (rssi <= 39) + led = 1; + else if (rssi <= 49) + led = 2; + else if (rssi <= 53) + led = 3; + else if (rssi <= 63) + led = 4; + else + led = 5; + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, led, + rt2x00dev->led_reg, REGISTER_TIMEOUT); +} + +/* + * Link tuning + */ +static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt73usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt73usb_register_read(rt2x00dev, STA_CSR1, ®); + reg = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); + rt2x00dev->link.false_cca = + rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); +} + +static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt73usb_bbp_write(rt2x00dev, 17, 0x20); + rt2x00dev->link.vgc_level = 0x20; +} + +static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); + u8 r17; + u8 up_bound; + u8 low_bound; + + /* + * Update Led strength + */ + rt73usb_activity_led(rt2x00dev, rssi); + + rt73usb_bbp_read(rt2x00dev, 17, &r17); + + /* + * Determine r17 bounds. + */ + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + low_bound = 0x28; + up_bound = 0x48; + + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + low_bound += 0x10; + up_bound += 0x10; + } + } else { + if (rssi > -82) { + low_bound = 0x1c; + up_bound = 0x40; + } else if (rssi > -84) { + low_bound = 0x1c; + up_bound = 0x20; + } else { + low_bound = 0x1c; + up_bound = 0x1c; + } + + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + low_bound += 0x14; + up_bound += 0x10; + } + } + + /* + * Special big-R17 for very short distance + */ + if (rssi > -35) { + if (r17 != 0x60) + rt73usb_bbp_write(rt2x00dev, 17, 0x60); + return; + } + + /* + * Special big-R17 for short distance + */ + if (rssi >= -58) { + if (r17 != up_bound) + rt73usb_bbp_write(rt2x00dev, 17, up_bound); + return; + } + + /* + * Special big-R17 for middle-short distance + */ + if (rssi >= -66) { + low_bound += 0x10; + if (r17 != low_bound) + rt73usb_bbp_write(rt2x00dev, 17, low_bound); + return; + } + + /* + * Special mid-R17 for middle distance + */ + if (rssi >= -74) { + if (r17 != (low_bound + 0x10)) + rt73usb_bbp_write(rt2x00dev, 17, low_bound + 0x08); + return; + } + + /* + * Special case: Change up_bound based on the rssi. + * Lower up_bound when rssi is weaker then -74 dBm. + */ + up_bound -= 2 * (-74 - rssi); + if (low_bound > up_bound) + up_bound = low_bound; + + if (r17 > up_bound) { + rt73usb_bbp_write(rt2x00dev, 17, up_bound); + return; + } + + /* + * r17 does not yet exceed upper limit, continue and base + * the r17 tuning on the false CCA count. + */ + if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + r17 += 4; + if (r17 > up_bound) + r17 = up_bound; + rt73usb_bbp_write(rt2x00dev, 17, r17); + } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + r17 -= 4; + if (r17 < low_bound) + r17 = low_bound; + rt73usb_bbp_write(rt2x00dev, 17, r17); + } +} + +/* + * Firmware name function. + */ +static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) +{ + return FIRMWARE_RT2571; +} + +/* + * Initialization functions. + */ +static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, + const size_t len) +{ + unsigned int i; + int status; + u32 reg; + char *ptr = data; + char *cache; + int buflen; + int timeout; + + /* + * Wait for stable hardware. + */ + for (i = 0; i < 100; i++) { + rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg) + break; + msleep(1); + } + + if (!reg) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + /* + * Write firmware to device. + * We setup a seperate cache for this action, + * since we are going to write larger chunks of data + * then normally used cache size. + */ + cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL); + if (!cache) { + ERROR(rt2x00dev, "Failed to allocate firmware cache.\n"); + return -ENOMEM; + } + + for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) { + buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE); + timeout = REGISTER_TIMEOUT * (buflen / sizeof(u32)); + + memcpy(cache, ptr, buflen); + + rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + FIRMWARE_IMAGE_BASE + i, 0x0000, + cache, buflen, timeout); + + ptr += buflen; + } + + kfree(cache); + + /* + * Send firmware request to device to load firmware, + * we need to specify a long timeout time. + */ + status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, + 0x0000, USB_MODE_FIRMWARE, + REGISTER_TIMEOUT_FIRMWARE); + if (status < 0) { + ERROR(rt2x00dev, "Failed to write Firmware to device.\n"); + return status; + } + + rt73usb_disable_led(rt2x00dev); + + return 0; +} + +static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); + rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg); + + /* + * CCK TXD BBP registers + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2, 11); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg); + + /* + * OFDM TXD BBP registers + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR3, ®); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); + rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); + rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg); + + rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); + + rt73usb_register_read(rt2x00dev, MAC_CSR6, ®); + rt2x00_set_field32(®, MAC_CSR6_MAX_FRAME_UNIT, 0xfff); + rt73usb_register_write(rt2x00dev, MAC_CSR6, reg); + + rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); + + /* + * Invalidate all Shared Keys (SEC_CSR0), + * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) + */ + rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); + rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); + rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); + + reg = 0x000023b0; + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) + rt2x00_set_field32(®, PHY_CSR1_RF_RPI, 1); + rt73usb_register_write(rt2x00dev, PHY_CSR1, reg); + + rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06); + rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); + rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); + rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); + rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + + rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); + rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + + /* + * We must clear the error counters. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt73usb_register_read(rt2x00dev, STA_CSR0, ®); + rt73usb_register_read(rt2x00dev, STA_CSR1, ®); + rt73usb_register_read(rt2x00dev, STA_CSR2, ®); + + /* + * Reset MAC and BBP registers. + */ + rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); + rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + + rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); + rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + + rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); + rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + + return 0; +} + +static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt73usb_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt73usb_bbp_write(rt2x00dev, 3, 0x80); + rt73usb_bbp_write(rt2x00dev, 15, 0x30); + rt73usb_bbp_write(rt2x00dev, 21, 0xc8); + rt73usb_bbp_write(rt2x00dev, 22, 0x38); + rt73usb_bbp_write(rt2x00dev, 23, 0x06); + rt73usb_bbp_write(rt2x00dev, 24, 0xfe); + rt73usb_bbp_write(rt2x00dev, 25, 0x0a); + rt73usb_bbp_write(rt2x00dev, 26, 0x0d); + rt73usb_bbp_write(rt2x00dev, 32, 0x0b); + rt73usb_bbp_write(rt2x00dev, 34, 0x12); + rt73usb_bbp_write(rt2x00dev, 37, 0x07); + rt73usb_bbp_write(rt2x00dev, 39, 0xf8); + rt73usb_bbp_write(rt2x00dev, 41, 0x60); + rt73usb_bbp_write(rt2x00dev, 53, 0x10); + rt73usb_bbp_write(rt2x00dev, 54, 0x18); + rt73usb_bbp_write(rt2x00dev, 60, 0x10); + rt73usb_bbp_write(rt2x00dev, 61, 0x04); + rt73usb_bbp_write(rt2x00dev, 62, 0x04); + rt73usb_bbp_write(rt2x00dev, 75, 0xfe); + rt73usb_bbp_write(rt2x00dev, 86, 0xfe); + rt73usb_bbp_write(rt2x00dev, 88, 0xfe); + rt73usb_bbp_write(rt2x00dev, 90, 0x0f); + rt73usb_bbp_write(rt2x00dev, 99, 0x00); + rt73usb_bbp_write(rt2x00dev, 102, 0x16); + rt73usb_bbp_write(rt2x00dev, 107, 0x04); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt73usb_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); +} + +static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Initialize all registers. + */ + if (rt73usb_init_registers(rt2x00dev) || + rt73usb_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + rt2x00usb_enable_radio(rt2x00dev); + + /* + * Enable LED + */ + rt73usb_enable_led(rt2x00dev); + + return 0; +} + +static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Disable LED + */ + rt73usb_disable_led(rt2x00dev); + + rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); + + /* + * Disable synchronisation. + */ + rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); + + rt2x00usb_disable_radio(rt2x00dev); +} + +static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) +{ + u32 reg; + unsigned int i; + char put_to_sleep; + char current_state; + + put_to_sleep = (state != STATE_AWAKE); + + rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); + rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); + rt73usb_register_write(rt2x00dev, MAC_CSR12, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + current_state = + rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); + if (current_state == !put_to_sleep) + return 0; + msleep(10); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state %d.\n", !put_to_sleep, current_state); + + return -EBUSY; +} + +static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt73usb_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt73usb_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt73usb_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt73usb_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue); + rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_TX_POWER, + TXPOWER_TO_DEV(control->power_level)); + rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); + rt2x00_desc_write(txd, 5, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_BURST, + test_bit(ENTRY_TXD_BURST, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_VALID, 1); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_OFDM, + test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, + !!(control->flags & + IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_BURST2, + test_bit(ENTRY_TXD_BURST, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u32 reg; + + if (queue != IEEE80211_TX_QUEUE_BEACON) + return; + + /* + * For Wi-Fi faily generated beacons between participating stations. + * Set TBTT phase adaptive adjustment step to 8us (default 16us) + */ + rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); + + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + } +} + +/* + * RX control handlers + */ +static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) +{ + u16 eeprom; + u8 offset; + u8 lna; + + lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); + switch (lna) { + case 3: + offset = 90; + break; + case 2: + offset = 74; + break; + case 1: + offset = 64; + break; + default: + return 0; + } + + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + if (lna == 3 || lna == 2) + offset += 10; + } else { + if (lna == 3) + offset += 6; + else if (lna == 2) + offset += 8; + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + offset += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } + + return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; +} + +static int rt73usb_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct data_desc *rxd = (struct data_desc *)entry->skb->data; + u32 word0; + u32 word1; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 1, &word1); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + /* + * Pull the skb to clear the descriptor area. + */ + skb_pull(entry->skb, entry->ring->desc_size); + + return 0; +} + +/* + * Device probe functions. + */ +static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + u8 *mac; + s8 value; + + rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5226); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_G, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_A, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_ACT, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_0, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_1, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_2, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_3, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_4, 0); + rt2x00_set_field16(&word, EEPROM_LED_LED_MODE, + LED_MODE_DEFAULT); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word); + EEPROM(rt2x00dev, "Led: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); + rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + } + + return 0; +} + +static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2571, value, reg); + + if (!rt2x00_rev(&rt2x00dev->chip, 0x25730)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } + + if (!rt2x00_rf(&rt2x00dev->chip, RF5226) && + !rt2x00_rf(&rt2x00dev->chip, RF2528) && + !rt2x00_rf(&rt2x00dev->chip, RF5225) && + !rt2x00_rf(&rt2x00dev->chip, RF2527)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Read the Frame type. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) + __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + + /* + * Read frequency offset. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Read external LNA informations. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) { + __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + } + + /* + * Store led settings, for correct led behaviour. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE, + rt2x00dev->led_mode); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_0)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_1)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_2)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_3)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_4)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT, + rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_RDY_G)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_RDY_A)); + + return 0; +} + +/* + * RF value list for RF2528 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2528[] = { + { 1, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b }, + { 2, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f }, + { 3, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b }, + { 4, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f }, + { 5, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b }, + { 6, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f }, + { 7, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b }, + { 8, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f }, + { 9, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b }, + { 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f }, + { 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b }, + { 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f }, + { 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b }, + { 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 }, +}; + +/* + * RF value list for RF5226 + * Supports: 2.4 GHz & 5.2 GHz + */ +static const struct rf_channel rf_vals_5226[] = { + { 1, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b }, + { 2, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f }, + { 3, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b }, + { 4, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f }, + { 5, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b }, + { 6, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f }, + { 7, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b }, + { 8, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f }, + { 9, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b }, + { 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f }, + { 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b }, + { 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f }, + { 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b }, + { 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00002c0c, 0x0000099a, 0x00098255, 0x000fea23 }, + { 40, 0x00002c0c, 0x000009a2, 0x00098255, 0x000fea03 }, + { 44, 0x00002c0c, 0x000009a6, 0x00098255, 0x000fea0b }, + { 48, 0x00002c0c, 0x000009aa, 0x00098255, 0x000fea13 }, + { 52, 0x00002c0c, 0x000009ae, 0x00098255, 0x000fea1b }, + { 56, 0x00002c0c, 0x000009b2, 0x00098255, 0x000fea23 }, + { 60, 0x00002c0c, 0x000009ba, 0x00098255, 0x000fea03 }, + { 64, 0x00002c0c, 0x000009be, 0x00098255, 0x000fea0b }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00002c0c, 0x00000a2a, 0x000b8255, 0x000fea03 }, + { 104, 0x00002c0c, 0x00000a2e, 0x000b8255, 0x000fea0b }, + { 108, 0x00002c0c, 0x00000a32, 0x000b8255, 0x000fea13 }, + { 112, 0x00002c0c, 0x00000a36, 0x000b8255, 0x000fea1b }, + { 116, 0x00002c0c, 0x00000a3a, 0x000b8255, 0x000fea23 }, + { 120, 0x00002c0c, 0x00000a82, 0x000b8255, 0x000fea03 }, + { 124, 0x00002c0c, 0x00000a86, 0x000b8255, 0x000fea0b }, + { 128, 0x00002c0c, 0x00000a8a, 0x000b8255, 0x000fea13 }, + { 132, 0x00002c0c, 0x00000a8e, 0x000b8255, 0x000fea1b }, + { 136, 0x00002c0c, 0x00000a92, 0x000b8255, 0x000fea23 }, + + /* 802.11 UNII */ + { 140, 0x00002c0c, 0x00000a9a, 0x000b8255, 0x000fea03 }, + { 149, 0x00002c0c, 0x00000aa2, 0x000b8255, 0x000fea1f }, + { 153, 0x00002c0c, 0x00000aa6, 0x000b8255, 0x000fea27 }, + { 157, 0x00002c0c, 0x00000aae, 0x000b8255, 0x000fea07 }, + { 161, 0x00002c0c, 0x00000ab2, 0x000b8255, 0x000fea0f }, + { 165, 0x00002c0c, 0x00000ab6, 0x000b8255, 0x000fea17 }, + + /* MMAC(Japan)J52 ch 34,38,42,46 */ + { 34, 0x00002c0c, 0x0008099a, 0x000da255, 0x000d3a0b }, + { 38, 0x00002c0c, 0x0008099e, 0x000da255, 0x000d3a13 }, + { 42, 0x00002c0c, 0x000809a2, 0x000da255, 0x000d3a1b }, + { 46, 0x00002c0c, 0x000809a6, 0x000da255, 0x000d3a23 }, +}; + +/* + * RF value list for RF5225 & RF2527 + * Supports: 2.4 GHz & 5.2 GHz + */ +static const struct rf_channel rf_vals_5225_2527[] = { + { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, + { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, + { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, + { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, + { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, + { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, + { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, + { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, + { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, + { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, + { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, + { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, + { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, + { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 }, + { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 }, + { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b }, + { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 }, + { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b }, + { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 }, + { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 }, + { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 }, + { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b }, + { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 }, + { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b }, + { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 }, + { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 }, + { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b }, + { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 }, + { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b }, + { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 }, + + /* 802.11 UNII */ + { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 }, + { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f }, + { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 }, + { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 }, + { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f }, + { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 }, + + /* MMAC(Japan)J52 ch 34,38,42,46 */ + { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b }, + { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 }, + { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b }, + { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 }, +}; + + +static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 5; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 2; + spec->num_rates = 12; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + if (rt2x00_rf(&rt2x00dev->chip, RF2528)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); + spec->channels = rf_vals_bg_2528; + } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) { + spec->num_channels = ARRAY_SIZE(rf_vals_5226); + spec->channels = rf_vals_5226; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) { + spec->num_channels = 14; + spec->channels = rf_vals_5225_2527; + } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) { + spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527); + spec->channels = rf_vals_5225_2527; + } + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5226)) { + spec->num_modes = 3; + + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + spec->tx_power_a = txpower; + } +} + +static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt73usb_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt73usb_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt73usb_probe_hw_mode(rt2x00dev); + + /* + * USB devices require scheduled packet filter toggling + * This device requires firmware + */ + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry, u32 long_retry) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); + rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + + return 0; +} + +#if 0 +/* + * Mac80211 demands get_tsf must be atomic. + * This is not possible for rt73usb since all register access + * functions require sleeping. Untill mac80211 no longer needs + * get_tsf to be atomic, this function should be disabled. + */ +static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR13, ®); + tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; + rt73usb_register_read(rt2x00dev, TXRX_CSR12, ®); + tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); + + return tsf; +} +#endif + +static void rt73usb_reset_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt73usb_register_write(rt2x00dev, TXRX_CSR12, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0); +} + +int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int timeout; + + /* + * Just in case the ieee80211 doesn't set this, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; + + /* + * First we create the beacon. + */ + skb_push(skb, TXD_DESC_SIZE); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, + (struct ieee80211_hdr *)(skb->data + + TXD_DESC_SIZE), + skb->len - TXD_DESC_SIZE, control); + + /* + * Write entire beacon with descriptor to register, + * and kick the beacon generator. + */ + timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32)); + rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + HW_BEACON_BASE0, 0x0000, + skb->data, skb->len, timeout); + rt73usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + return 0; +} + +static const struct ieee80211_ops rt73usb_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .set_retry_limit = rt73usb_set_retry_limit, + .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, +#if 0 +/* + * See comment at the rt73usb_get_tsf function. + */ + .get_tsf = rt73usb_get_tsf, +#endif + .reset_tsf = rt73usb_reset_tsf, + .beacon_update = rt73usb_beacon_update, +}; + +static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { + .probe_hw = rt73usb_probe_hw, + .get_firmware_name = rt73usb_get_firmware_name, + .load_firmware = rt73usb_load_firmware, + .initialize = rt2x00usb_initialize, + .uninitialize = rt2x00usb_uninitialize, + .set_device_state = rt73usb_set_device_state, + .link_stats = rt73usb_link_stats, + .reset_tuner = rt73usb_reset_tuner, + .link_tuner = rt73usb_link_tuner, + .write_tx_desc = rt73usb_write_tx_desc, + .write_tx_data = rt2x00usb_write_tx_data, + .kick_tx_queue = rt73usb_kick_tx_queue, + .fill_rxdone = rt73usb_fill_rxdone, + .config_mac_addr = rt73usb_config_mac_addr, + .config_bssid = rt73usb_config_bssid, + .config_packet_filter = rt73usb_config_packet_filter, + .config_type = rt73usb_config_type, + .config = rt73usb_config, +}; + +static const struct rt2x00_ops rt73usb_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt73usb_rt2x00_ops, + .hw = &rt73usb_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt73usb_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * rt73usb module information. + */ +static struct usb_device_id rt73usb_device_table[] = { + /* AboCom */ + { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Askey */ + { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Billionton */ + { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Buffalo */ + { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, + /* CNet */ + { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) }, + /* D-Link */ + { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Gemtek */ + { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Huawei-3Com */ + { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Hercules */ + { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Linksys */ + { USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) }, + /* MSI */ + { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Qcom */ + { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Senao */ + { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Surecom */ + { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Planex */ + { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT73 USB Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2571W & RT2671 USB chipset based cards"); +MODULE_DEVICE_TABLE(usb, rt73usb_device_table); +MODULE_FIRMWARE(FIRMWARE_RT2571); +MODULE_LICENSE("GPL"); + +static struct usb_driver rt73usb_driver = { + .name = DRV_NAME, + .id_table = rt73usb_device_table, + .probe = rt2x00usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +}; + +static int __init rt73usb_init(void) +{ + return usb_register(&rt73usb_driver); +} + +static void __exit rt73usb_exit(void) +{ + usb_deregister(&rt73usb_driver); +} + +module_init(rt73usb_init); +module_exit(rt73usb_exit); diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h new file mode 100644 index 000000000000..5d63a1a714f3 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -0,0 +1,1024 @@ +/* + Copyright (C) 2004 - 2007 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: rt73usb + Abstract: Data structures and registers for the rt73usb module. + Supported chipsets: rt2571W & rt2671. + */ + +#ifndef RT73USB_H +#define RT73USB_H + +/* + * RF chip defines. + */ +#define RF5226 0x0001 +#define RF2528 0x0002 +#define RF5225 0x0003 +#define RF2527 0x0004 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 120 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x3000 +#define CSR_REG_SIZE 0x04b0 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0100 +#define BBP_SIZE 0x0080 +#define RF_SIZE 0x0014 + +/* + * USB registers. + */ + +/* + * MCU_LEDCS: LED control for MCU Mailbox. + */ +#define MCU_LEDCS_LED_MODE FIELD16(0x001f) +#define MCU_LEDCS_RADIO_STATUS FIELD16(0x0020) +#define MCU_LEDCS_LINK_BG_STATUS FIELD16(0x0040) +#define MCU_LEDCS_LINK_A_STATUS FIELD16(0x0080) +#define MCU_LEDCS_POLARITY_GPIO_0 FIELD16(0x0100) +#define MCU_LEDCS_POLARITY_GPIO_1 FIELD16(0x0200) +#define MCU_LEDCS_POLARITY_GPIO_2 FIELD16(0x0400) +#define MCU_LEDCS_POLARITY_GPIO_3 FIELD16(0x0800) +#define MCU_LEDCS_POLARITY_GPIO_4 FIELD16(0x1000) +#define MCU_LEDCS_POLARITY_ACT FIELD16(0x2000) +#define MCU_LEDCS_POLARITY_READY_BG FIELD16(0x4000) +#define MCU_LEDCS_POLARITY_READY_A FIELD16(0x8000) + +/* + * 8051 firmware image. + */ +#define FIRMWARE_RT2571 "rt73.bin" +#define FIRMWARE_IMAGE_BASE 0x0800 + +/* + * Security key table memory. + * 16 entries 32-byte for shared key table + * 64 entries 32-byte for pairwise key table + * 64 entries 8-byte for pairwise ta key table + */ +#define SHARED_KEY_TABLE_BASE 0x1000 +#define PAIRWISE_KEY_TABLE_BASE 0x1200 +#define PAIRWISE_TA_TABLE_BASE 0x1a00 + +struct hw_key_entry { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __attribute__ ((packed)); + +struct hw_pairwise_ta_entry { + u8 address[6]; + u8 reserved[2]; +} __attribute__ ((packed)); + +/* + * Since NULL frame won't be that long (256 byte), + * We steal 16 tail bytes to save debugging settings. + */ +#define HW_DEBUG_SETTING_BASE 0x2bf0 + +/* + * On-chip BEACON frame space. + */ +#define HW_BEACON_BASE0 0x2400 +#define HW_BEACON_BASE1 0x2500 +#define HW_BEACON_BASE2 0x2600 +#define HW_BEACON_BASE3 0x2700 + +/* + * MAC Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + */ +#define MAC_CSR0 0x3000 + +/* + * MAC_CSR1: System control register. + * SOFT_RESET: Software reset bit, 1: reset, 0: normal. + * BBP_RESET: Hardware reset BBP. + * HOST_READY: Host is ready after initialization, 1: ready. + */ +#define MAC_CSR1 0x3004 +#define MAC_CSR1_SOFT_RESET FIELD32(0x00000001) +#define MAC_CSR1_BBP_RESET FIELD32(0x00000002) +#define MAC_CSR1_HOST_READY FIELD32(0x00000004) + +/* + * MAC_CSR2: STA MAC register 0. + */ +#define MAC_CSR2 0x3008 +#define MAC_CSR2_BYTE0 FIELD32(0x000000ff) +#define MAC_CSR2_BYTE1 FIELD32(0x0000ff00) +#define MAC_CSR2_BYTE2 FIELD32(0x00ff0000) +#define MAC_CSR2_BYTE3 FIELD32(0xff000000) + +/* + * MAC_CSR3: STA MAC register 1. + */ +#define MAC_CSR3 0x300c +#define MAC_CSR3_BYTE4 FIELD32(0x000000ff) +#define MAC_CSR3_BYTE5 FIELD32(0x0000ff00) +#define MAC_CSR3_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) + +/* + * MAC_CSR4: BSSID register 0. + */ +#define MAC_CSR4 0x3010 +#define MAC_CSR4_BYTE0 FIELD32(0x000000ff) +#define MAC_CSR4_BYTE1 FIELD32(0x0000ff00) +#define MAC_CSR4_BYTE2 FIELD32(0x00ff0000) +#define MAC_CSR4_BYTE3 FIELD32(0xff000000) + +/* + * MAC_CSR5: BSSID register 1. + * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID. + */ +#define MAC_CSR5 0x3014 +#define MAC_CSR5_BYTE4 FIELD32(0x000000ff) +#define MAC_CSR5_BYTE5 FIELD32(0x0000ff00) +#define MAC_CSR5_BSS_ID_MASK FIELD32(0x00ff0000) + +/* + * MAC_CSR6: Maximum frame length register. + */ +#define MAC_CSR6 0x3018 +#define MAC_CSR6_MAX_FRAME_UNIT FIELD32(0x00000fff) + +/* + * MAC_CSR7: Reserved + */ +#define MAC_CSR7 0x301c + +/* + * MAC_CSR8: SIFS/EIFS register. + * All units are in US. + */ +#define MAC_CSR8 0x3020 +#define MAC_CSR8_SIFS FIELD32(0x000000ff) +#define MAC_CSR8_SIFS_AFTER_RX_OFDM FIELD32(0x0000ff00) +#define MAC_CSR8_EIFS FIELD32(0xffff0000) + +/* + * MAC_CSR9: Back-Off control register. + * SLOT_TIME: Slot time, default is 20us for 802.11BG. + * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1). + * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1). + * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD. + */ +#define MAC_CSR9 0x3024 +#define MAC_CSR9_SLOT_TIME FIELD32(0x000000ff) +#define MAC_CSR9_CWMIN FIELD32(0x00000f00) +#define MAC_CSR9_CWMAX FIELD32(0x0000f000) +#define MAC_CSR9_CW_SELECT FIELD32(0x00010000) + +/* + * MAC_CSR10: Power state configuration. + */ +#define MAC_CSR10 0x3028 + +/* + * MAC_CSR11: Power saving transition time register. + * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU. + * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup. + * WAKEUP_LATENCY: In unit of TU. + */ +#define MAC_CSR11 0x302c +#define MAC_CSR11_DELAY_AFTER_TBCN FIELD32(0x000000ff) +#define MAC_CSR11_TBCN_BEFORE_WAKEUP FIELD32(0x00007f00) +#define MAC_CSR11_AUTOWAKE FIELD32(0x00008000) +#define MAC_CSR11_WAKEUP_LATENCY FIELD32(0x000f0000) + +/* + * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1). + * CURRENT_STATE: 0:sleep, 1:awake. + * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP. + * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake. + */ +#define MAC_CSR12 0x3030 +#define MAC_CSR12_CURRENT_STATE FIELD32(0x00000001) +#define MAC_CSR12_PUT_TO_SLEEP FIELD32(0x00000002) +#define MAC_CSR12_FORCE_WAKEUP FIELD32(0x00000004) +#define MAC_CSR12_BBP_CURRENT_STATE FIELD32(0x00000008) + +/* + * MAC_CSR13: GPIO. + */ +#define MAC_CSR13 0x3034 + +/* + * MAC_CSR14: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON. + * SW_LED: s/w LED, 1: ON, 0: OFF. + * HW_LED_POLARITY: 0: active low, 1: active high. + */ +#define MAC_CSR14 0x3038 +#define MAC_CSR14_ON_PERIOD FIELD32(0x000000ff) +#define MAC_CSR14_OFF_PERIOD FIELD32(0x0000ff00) +#define MAC_CSR14_HW_LED FIELD32(0x00010000) +#define MAC_CSR14_SW_LED FIELD32(0x00020000) +#define MAC_CSR14_HW_LED_POLARITY FIELD32(0x00040000) +#define MAC_CSR14_SW_LED2 FIELD32(0x00080000) + +/* + * MAC_CSR15: NAV control. + */ +#define MAC_CSR15 0x303c + +/* + * TXRX control registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXRX_CSR0: TX/RX configuration register. + * TSF_OFFSET: Default is 24. + * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame. + * DISABLE_RX: Disable Rx engine. + * DROP_CRC: Drop CRC error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TO_DS: Drop fram ToDs bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * DROP_MULTICAST: Drop multicast frames. + * DROP_BORADCAST: Drop broadcast frames. + * ROP_ACK_CTS: Drop received ACK and CTS. + */ +#define TXRX_CSR0 0x3040 +#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff) +#define TXRX_CSR0_TSF_OFFSET FIELD32(0x00007e00) +#define TXRX_CSR0_AUTO_TX_SEQ FIELD32(0x00008000) +#define TXRX_CSR0_DISABLE_RX FIELD32(0x00010000) +#define TXRX_CSR0_DROP_CRC FIELD32(0x00020000) +#define TXRX_CSR0_DROP_PHYSICAL FIELD32(0x00040000) +#define TXRX_CSR0_DROP_CONTROL FIELD32(0x00080000) +#define TXRX_CSR0_DROP_NOT_TO_ME FIELD32(0x00100000) +#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000) +#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000) +#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000) +#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000) +#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000) +#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000) + +/* + * TXRX_CSR1 + */ +#define TXRX_CSR1 0x3044 +#define TXRX_CSR1_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR1_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR1_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR1_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR1_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR1_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR1_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR1_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR2 + */ +#define TXRX_CSR2 0x3048 +#define TXRX_CSR2_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR2_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR2_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR2_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR2_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR2_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR2_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR2_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR3 + */ +#define TXRX_CSR3 0x304c +#define TXRX_CSR3_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR3_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR3_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR3_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR3_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR3_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR3_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR3_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR4: Auto-Responder/Tx-retry register. + * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble. + * OFDM_TX_RATE_DOWN: 1:enable. + * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step. + * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M. + */ +#define TXRX_CSR4 0x3050 +#define TXRX_CSR4_TX_ACK_TIMEOUT FIELD32(0x000000ff) +#define TXRX_CSR4_CNTL_ACK_POLICY FIELD32(0x00000700) +#define TXRX_CSR4_ACK_CTS_PSM FIELD32(0x00010000) +#define TXRX_CSR4_AUTORESPOND_ENABLE FIELD32(0x00020000) +#define TXRX_CSR4_AUTORESPOND_PREAMBLE FIELD32(0x00040000) +#define TXRX_CSR4_OFDM_TX_RATE_DOWN FIELD32(0x00080000) +#define TXRX_CSR4_OFDM_TX_RATE_STEP FIELD32(0x00300000) +#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK FIELD32(0x00400000) +#define TXRX_CSR4_LONG_RETRY_LIMIT FIELD32(0x0f000000) +#define TXRX_CSR4_SHORT_RETRY_LIMIT FIELD32(0xf0000000) + +/* + * TXRX_CSR5 + */ +#define TXRX_CSR5 0x3054 + +/* + * TXRX_CSR6: ACK/CTS payload consumed time + */ +#define TXRX_CSR6 0x3058 + +/* + * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps. + */ +#define TXRX_CSR7 0x305c +#define TXRX_CSR7_ACK_CTS_6MBS FIELD32(0x000000ff) +#define TXRX_CSR7_ACK_CTS_9MBS FIELD32(0x0000ff00) +#define TXRX_CSR7_ACK_CTS_12MBS FIELD32(0x00ff0000) +#define TXRX_CSR7_ACK_CTS_18MBS FIELD32(0xff000000) + +/* + * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps. + */ +#define TXRX_CSR8 0x3060 +#define TXRX_CSR8_ACK_CTS_24MBS FIELD32(0x000000ff) +#define TXRX_CSR8_ACK_CTS_36MBS FIELD32(0x0000ff00) +#define TXRX_CSR8_ACK_CTS_48MBS FIELD32(0x00ff0000) +#define TXRX_CSR8_ACK_CTS_54MBS FIELD32(0xff000000) + +/* + * TXRX_CSR9: Synchronization control register. + * BEACON_INTERVAL: In unit of 1/16 TU. + * TSF_TICKING: Enable TSF auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * BEACON_GEN: Enable beacon generator. + */ +#define TXRX_CSR9 0x3064 +#define TXRX_CSR9_BEACON_INTERVAL FIELD32(0x0000ffff) +#define TXRX_CSR9_TSF_TICKING FIELD32(0x00010000) +#define TXRX_CSR9_TSF_SYNC FIELD32(0x00060000) +#define TXRX_CSR9_TBTT_ENABLE FIELD32(0x00080000) +#define TXRX_CSR9_BEACON_GEN FIELD32(0x00100000) +#define TXRX_CSR9_TIMESTAMP_COMPENSATE FIELD32(0xff000000) + +/* + * TXRX_CSR10: BEACON alignment. + */ +#define TXRX_CSR10 0x3068 + +/* + * TXRX_CSR11: AES mask. + */ +#define TXRX_CSR11 0x306c + +/* + * TXRX_CSR12: TSF low 32. + */ +#define TXRX_CSR12 0x3070 +#define TXRX_CSR12_LOW_TSFTIMER FIELD32(0xffffffff) + +/* + * TXRX_CSR13: TSF high 32. + */ +#define TXRX_CSR13 0x3074 +#define TXRX_CSR13_HIGH_TSFTIMER FIELD32(0xffffffff) + +/* + * TXRX_CSR14: TBTT timer. + */ +#define TXRX_CSR14 0x3078 + +/* + * TXRX_CSR15: TKIP MIC priority byte "AND" mask. + */ +#define TXRX_CSR15 0x307c + +/* + * PHY control registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * PHY_CSR0: RF/PS control. + */ +#define PHY_CSR0 0x3080 +#define PHY_CSR0_PA_PE_BG FIELD32(0x00010000) +#define PHY_CSR0_PA_PE_A FIELD32(0x00020000) + +/* + * PHY_CSR1 + */ +#define PHY_CSR1 0x3084 +#define PHY_CSR1_RF_RPI FIELD32(0x00010000) + +/* + * PHY_CSR2: Pre-TX BBP control. + */ +#define PHY_CSR2 0x3088 + +/* + * PHY_CSR3: BBP serial control register. + * VALUE: Register value to program into BBP. + * REG_NUM: Selected BBP register. + * READ_CONTROL: 0: Write BBP, 1: Read BBP. + * BUSY: 1: ASIC is busy execute BBP programming. + */ +#define PHY_CSR3 0x308c +#define PHY_CSR3_VALUE FIELD32(0x000000ff) +#define PHY_CSR3_REGNUM FIELD32(0x00007f00) +#define PHY_CSR3_READ_CONTROL FIELD32(0x00008000) +#define PHY_CSR3_BUSY FIELD32(0x00010000) + +/* + * PHY_CSR4: RF serial control register + * VALUE: Register value (include register id) serial out to RF/IF chip. + * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22). + * IF_SELECT: 1: select IF to program, 0: select RF to program. + * PLL_LD: RF PLL_LD status. + * BUSY: 1: ASIC is busy execute RF programming. + */ +#define PHY_CSR4 0x3090 +#define PHY_CSR4_VALUE FIELD32(0x00ffffff) +#define PHY_CSR4_NUMBER_OF_BITS FIELD32(0x1f000000) +#define PHY_CSR4_IF_SELECT FIELD32(0x20000000) +#define PHY_CSR4_PLL_LD FIELD32(0x40000000) +#define PHY_CSR4_BUSY FIELD32(0x80000000) + +/* + * PHY_CSR5: RX to TX signal switch timing control. + */ +#define PHY_CSR5 0x3094 +#define PHY_CSR5_IQ_FLIP FIELD32(0x00000004) + +/* + * PHY_CSR6: TX to RX signal timing control. + */ +#define PHY_CSR6 0x3098 +#define PHY_CSR6_IQ_FLIP FIELD32(0x00000004) + +/* + * PHY_CSR7: TX DAC switching timing control. + */ +#define PHY_CSR7 0x309c + +/* + * Security control register. + */ + +/* + * SEC_CSR0: Shared key table control. + */ +#define SEC_CSR0 0x30a0 +#define SEC_CSR0_BSS0_KEY0_VALID FIELD32(0x00000001) +#define SEC_CSR0_BSS0_KEY1_VALID FIELD32(0x00000002) +#define SEC_CSR0_BSS0_KEY2_VALID FIELD32(0x00000004) +#define SEC_CSR0_BSS0_KEY3_VALID FIELD32(0x00000008) +#define SEC_CSR0_BSS1_KEY0_VALID FIELD32(0x00000010) +#define SEC_CSR0_BSS1_KEY1_VALID FIELD32(0x00000020) +#define SEC_CSR0_BSS1_KEY2_VALID FIELD32(0x00000040) +#define SEC_CSR0_BSS1_KEY3_VALID FIELD32(0x00000080) +#define SEC_CSR0_BSS2_KEY0_VALID FIELD32(0x00000100) +#define SEC_CSR0_BSS2_KEY1_VALID FIELD32(0x00000200) +#define SEC_CSR0_BSS2_KEY2_VALID FIELD32(0x00000400) +#define SEC_CSR0_BSS2_KEY3_VALID FIELD32(0x00000800) +#define SEC_CSR0_BSS3_KEY0_VALID FIELD32(0x00001000) +#define SEC_CSR0_BSS3_KEY1_VALID FIELD32(0x00002000) +#define SEC_CSR0_BSS3_KEY2_VALID FIELD32(0x00004000) +#define SEC_CSR0_BSS3_KEY3_VALID FIELD32(0x00008000) + +/* + * SEC_CSR1: Shared key table security mode register. + */ +#define SEC_CSR1 0x30a4 +#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG FIELD32(0x00000007) +#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG FIELD32(0x00000070) +#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG FIELD32(0x00000700) +#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG FIELD32(0x00007000) +#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG FIELD32(0x00070000) +#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG FIELD32(0x00700000) +#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG FIELD32(0x07000000) +#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG FIELD32(0x70000000) + +/* + * Pairwise key table valid bitmap registers. + * SEC_CSR2: pairwise key table valid bitmap 0. + * SEC_CSR3: pairwise key table valid bitmap 1. + */ +#define SEC_CSR2 0x30a8 +#define SEC_CSR3 0x30ac + +/* + * SEC_CSR4: Pairwise key table lookup control. + */ +#define SEC_CSR4 0x30b0 + +/* + * SEC_CSR5: shared key table security mode register. + */ +#define SEC_CSR5 0x30b4 +#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG FIELD32(0x00000007) +#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG FIELD32(0x00000070) +#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG FIELD32(0x00000700) +#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG FIELD32(0x00007000) +#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG FIELD32(0x00070000) +#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG FIELD32(0x00700000) +#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG FIELD32(0x07000000) +#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG FIELD32(0x70000000) + +/* + * STA control registers. + */ + +/* + * STA_CSR0: RX PLCP error count & RX FCS error count. + */ +#define STA_CSR0 0x30c0 +#define STA_CSR0_FCS_ERROR FIELD32(0x0000ffff) +#define STA_CSR0_PLCP_ERROR FIELD32(0xffff0000) + +/* + * STA_CSR1: RX False CCA count & RX LONG frame count. + */ +#define STA_CSR1 0x30c4 +#define STA_CSR1_PHYSICAL_ERROR FIELD32(0x0000ffff) +#define STA_CSR1_FALSE_CCA_ERROR FIELD32(0xffff0000) + +/* + * STA_CSR2: TX Beacon count and RX FIFO overflow count. + */ +#define STA_CSR2 0x30c8 +#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT FIELD32(0x0000ffff) +#define STA_CSR2_RX_OVERFLOW_COUNT FIELD32(0xffff0000) + +/* + * STA_CSR3: TX Beacon count. + */ +#define STA_CSR3 0x30cc +#define STA_CSR3_TX_BEACON_COUNT FIELD32(0x0000ffff) + +/* + * STA_CSR4: TX Retry count. + */ +#define STA_CSR4 0x30d0 +#define STA_CSR4_TX_NO_RETRY_COUNT FIELD32(0x0000ffff) +#define STA_CSR4_TX_ONE_RETRY_COUNT FIELD32(0xffff0000) + +/* + * STA_CSR5: TX Retry count. + */ +#define STA_CSR5 0x30d4 +#define STA_CSR4_TX_MULTI_RETRY_COUNT FIELD32(0x0000ffff) +#define STA_CSR4_TX_RETRY_FAIL_COUNT FIELD32(0xffff0000) + +/* + * QOS control registers. + */ + +/* + * QOS_CSR1: TXOP holder MAC address register. + */ +#define QOS_CSR1 0x30e4 +#define QOS_CSR1_BYTE4 FIELD32(0x000000ff) +#define QOS_CSR1_BYTE5 FIELD32(0x0000ff00) + +/* + * QOS_CSR2: TXOP holder timeout register. + */ +#define QOS_CSR2 0x30e8 + +/* + * RX QOS-CFPOLL MAC address register. + * QOS_CSR3: RX QOS-CFPOLL MAC address 0. + * QOS_CSR4: RX QOS-CFPOLL MAC address 1. + */ +#define QOS_CSR3 0x30ec +#define QOS_CSR4 0x30f0 + +/* + * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL. + */ +#define QOS_CSR5 0x30f4 + +/* + * WMM Scheduler Register + */ + +/* + * AIFSN_CSR: AIFSN for each EDCA AC. + * AIFSN0: For AC_BK. + * AIFSN1: For AC_BE. + * AIFSN2: For AC_VI. + * AIFSN3: For AC_VO. + */ +#define AIFSN_CSR 0x0400 +#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f) +#define AIFSN_CSR_AIFSN1 FIELD32(0x000000f0) +#define AIFSN_CSR_AIFSN2 FIELD32(0x00000f00) +#define AIFSN_CSR_AIFSN3 FIELD32(0x0000f000) + +/* + * CWMIN_CSR: CWmin for each EDCA AC. + * CWMIN0: For AC_BK. + * CWMIN1: For AC_BE. + * CWMIN2: For AC_VI. + * CWMIN3: For AC_VO. + */ +#define CWMIN_CSR 0x0404 +#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f) +#define CWMIN_CSR_CWMIN1 FIELD32(0x000000f0) +#define CWMIN_CSR_CWMIN2 FIELD32(0x00000f00) +#define CWMIN_CSR_CWMIN3 FIELD32(0x0000f000) + +/* + * CWMAX_CSR: CWmax for each EDCA AC. + * CWMAX0: For AC_BK. + * CWMAX1: For AC_BE. + * CWMAX2: For AC_VI. + * CWMAX3: For AC_VO. + */ +#define CWMAX_CSR 0x0408 +#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f) +#define CWMAX_CSR_CWMAX1 FIELD32(0x000000f0) +#define CWMAX_CSR_CWMAX2 FIELD32(0x00000f00) +#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000) + +/* + * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register. + * AC0_TX_OP: For AC_BK, in unit of 32us. + * AC1_TX_OP: For AC_BE, in unit of 32us. + */ +#define AC_TXOP_CSR0 0x040c +#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff) +#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000) + +/* + * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register. + * AC2_TX_OP: For AC_VI, in unit of 32us. + * AC3_TX_OP: For AC_VO, in unit of 32us. + */ +#define AC_TXOP_CSR1 0x0410 +#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff) +#define AC_TXOP_CSR1_AC3_TX_OP FIELD32(0xffff0000) + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R2 + */ +#define BBP_R2_BG_MODE FIELD8(0x20) + +/* + * R3 + */ +#define BBP_R3_SMART_MODE FIELD8(0x01) + +/* + * R4: RX antenna control + * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529) + */ +#define BBP_R4_RX_ANTENNA FIELD8(0x03) +#define BBP_R4_RX_FRAME_END FIELD8(0x20) + +/* + * R77 + */ +#define BBP_R77_PAIR FIELD8(0x03) + +/* + * RF registers + */ + +/* + * RF 3 + */ +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * RF 4 + */ +#define RF4_FREQ_OFFSET FIELD32(0x0003f000) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * 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. + * DYN_TXAGC: Dynamic TX AGC control. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + * RF_TYPE: Rf_type of this adapter. + */ +#define EEPROM_ANTENNA 0x0010 +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_FRAME_TYPE FIELD16(0x0040) +#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800) + +/* + * EEPROM NIC config. + * EXTERNAL_LNA: External LNA. + */ +#define EEPROM_NIC 0x0011 +#define EEPROM_NIC_EXTERNAL_LNA FIELD16(0x0010) + +/* + * EEPROM geography. + * GEO_A: Default geographical setting for 5GHz band + * GEO: Default geographical setting. + */ +#define EEPROM_GEOGRAPHY 0x0012 +#define EEPROM_GEOGRAPHY_GEO_A FIELD16(0x00ff) +#define EEPROM_GEOGRAPHY_GEO FIELD16(0xff00) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0013 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER 802.11G + */ +#define EEPROM_TXPOWER_G_START 0x0023 +#define EEPROM_TXPOWER_G_SIZE 7 +#define EEPROM_TXPOWER_G_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_G_2 FIELD16(0xff00) + +/* + * EEPROM Frequency + */ +#define EEPROM_FREQ 0x002f +#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) +#define EEPROM_FREQ_SEQ_MASK FIELD16(0xff00) +#define EEPROM_FREQ_SEQ FIELD16(0x0300) + +/* + * EEPROM LED. + * POLARITY_RDY_G: Polarity RDY_G setting. + * POLARITY_RDY_A: Polarity RDY_A setting. + * POLARITY_ACT: Polarity ACT setting. + * POLARITY_GPIO_0: Polarity GPIO0 setting. + * POLARITY_GPIO_1: Polarity GPIO1 setting. + * POLARITY_GPIO_2: Polarity GPIO2 setting. + * POLARITY_GPIO_3: Polarity GPIO3 setting. + * POLARITY_GPIO_4: Polarity GPIO4 setting. + * LED_MODE: Led mode. + */ +#define EEPROM_LED 0x0030 +#define EEPROM_LED_POLARITY_RDY_G FIELD16(0x0001) +#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) +#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) +#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) +#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) +#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) +#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) +#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) +#define EEPROM_LED_LED_MODE FIELD16(0x1f00) + +/* + * EEPROM TXPOWER 802.11A + */ +#define EEPROM_TXPOWER_A_START 0x0031 +#define EEPROM_TXPOWER_A_SIZE 12 +#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + +/* + * EEPROM RSSI offset 802.11BG + */ +#define EEPROM_RSSI_OFFSET_BG 0x004d +#define EEPROM_RSSI_OFFSET_BG_1 FIELD16(0x00ff) +#define EEPROM_RSSI_OFFSET_BG_2 FIELD16(0xff00) + +/* + * EEPROM RSSI offset 802.11A + */ +#define EEPROM_RSSI_OFFSET_A 0x004e +#define EEPROM_RSSI_OFFSET_A_1 FIELD16(0x00ff) +#define EEPROM_RSSI_OFFSET_A_2 FIELD16(0xff00) + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 6 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 6 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO and Beacon Ring. + */ + +/* + * Word0 + * BURST: Next frame belongs to same "burst" event. + * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used. + * KEY_TABLE: Use per-client pairwise KEY table. + * KEY_INDEX: + * Key index (0~31) to the pairwise KEY table. + * 0~3 to shared KEY table 0 (BSS0). + * 4~7 to shared KEY table 1 (BSS1). + * 8~11 to shared KEY table 2 (BSS2). + * 12~15 to shared KEY table 3 (BSS3). + * BURST2: For backward compatibility, set to same value as BURST. + */ +#define TXD_W0_BURST FIELD32(0x00000001) +#define TXD_W0_VALID FIELD32(0x00000002) +#define TXD_W0_MORE_FRAG FIELD32(0x00000004) +#define TXD_W0_ACK FIELD32(0x00000008) +#define TXD_W0_TIMESTAMP FIELD32(0x00000010) +#define TXD_W0_OFDM FIELD32(0x00000020) +#define TXD_W0_IFS FIELD32(0x00000040) +#define TXD_W0_RETRY_MODE FIELD32(0x00000080) +#define TXD_W0_TKIP_MIC FIELD32(0x00000100) +#define TXD_W0_KEY_TABLE FIELD32(0x00000200) +#define TXD_W0_KEY_INDEX FIELD32(0x0000fc00) +#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define TXD_W0_BURST2 FIELD32(0x10000000) +#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + * HOST_Q_ID: EDCA/HCCA queue ID. + * HW_SEQUENCE: MAC overwrites the frame sequence number. + * BUFFER_COUNT: Number of buffers in this TXD. + */ +#define TXD_W1_HOST_Q_ID FIELD32(0x0000000f) +#define TXD_W1_AIFSN FIELD32(0x000000f0) +#define TXD_W1_CWMIN FIELD32(0x00000f00) +#define TXD_W1_CWMAX FIELD32(0x0000f000) +#define TXD_W1_IV_OFFSET FIELD32(0x003f0000) +#define TXD_W1_HW_SEQUENCE FIELD32(0x10000000) +#define TXD_W1_BUFFER_COUNT FIELD32(0xe0000000) + +/* + * Word2: PLCP information + */ +#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00) +#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000) +#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Word3 + */ +#define TXD_W3_IV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define TXD_W4_EIV FIELD32(0xffffffff) + +/* + * Word5 + * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field). + * PACKET_ID: Driver assigned packet ID to categorize TXResult in interrupt. + * WAITING_DMA_DONE_INT: TXD been filled with data + * and waiting for TxDoneISR housekeeping. + */ +#define TXD_W5_FRAME_OFFSET FIELD32(0x000000ff) +#define TXD_W5_PACKET_ID FIELD32(0x0000ff00) +#define TXD_W5_TX_POWER FIELD32(0x00ff0000) +#define TXD_W5_WAITING_DMA_DONE_INT FIELD32(0x01000000) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key. + * KEY_INDEX: Decryption key actually used. + */ +#define RXD_W0_OWNER_NIC FIELD32(0x00000001) +#define RXD_W0_DROP FIELD32(0x00000002) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000004) +#define RXD_W0_MULTICAST FIELD32(0x00000008) +#define RXD_W0_BROADCAST FIELD32(0x00000010) +#define RXD_W0_MY_BSS FIELD32(0x00000020) +#define RXD_W0_CRC_ERROR FIELD32(0x00000040) +#define RXD_W0_OFDM FIELD32(0x00000080) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000300) +#define RXD_W0_KEY_INDEX FIELD32(0x0000fc00) +#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * WORD1 + * SIGNAL: RX raw data rate reported by BBP. + * RSSI: RSSI reported by BBP. + */ +#define RXD_W1_SIGNAL FIELD32(0x000000ff) +#define RXD_W1_RSSI_AGC FIELD32(0x00001f00) +#define RXD_W1_RSSI_LNA FIELD32(0x00006000) +#define RXD_W1_FRAME_OFFSET FIELD32(0x7f000000) + +/* + * Word2 + * IV: Received IV of originally encrypted. + */ +#define RXD_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + * EIV: Received EIV of originally encrypted. + */ +#define RXD_W3_EIV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define RXD_W4_RESERVED FIELD32(0xffffffff) + +/* + * the above 20-byte is called RXINFO and will be DMAed to MAC RX block + * and passed to the HOST driver. + * The following fields are for DMA block and HOST usage only. + * Can't be touched by ASIC MAC block. + */ + +/* + * Word5 + */ +#define RXD_W5_RESERVED FIELD32(0xffffffff) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + */ +#define MIN_TXPOWER 0 +#define MAX_TXPOWER 31 +#define DEFAULT_TXPOWER 24 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? \ + DEFAULT_TXPOWER : (__txpower); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ + (__txpower)); \ +}) + +#endif /* RT73USB_H */ From 0795af5729b18218767fab27c44b1384f72dc9ad Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 3 Oct 2007 17:59:30 -0700 Subject: [PATCH 1424/2804] [NET]: Introduce and use print_mac() and DECLARE_MAC_BUF() This is nicer than the MAC_FMT stuff. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/3c503.c | 4 +- drivers/net/3c505.c | 10 +- drivers/net/3c507.c | 6 +- drivers/net/3c509.c | 18 +- drivers/net/3c515.c | 4 +- drivers/net/3c523.c | 22 +- drivers/net/3c527.c | 7 +- drivers/net/3c59x.c | 7 +- drivers/net/8139cp.c | 8 +- drivers/net/8139too.c | 8 +- drivers/net/82596.c | 18 +- drivers/net/a2065.c | 6 +- drivers/net/ac3200.c | 8 +- drivers/net/acenic.c | 7 +- drivers/net/amd8111e.c | 12 +- drivers/net/apne.c | 9 +- drivers/net/ariadne.c | 44 ++-- drivers/net/arm/am79c961a.c | 8 +- drivers/net/arm/at91_ether.c | 18 +- drivers/net/arm/ether1.c | 8 +- drivers/net/arm/ether3.c | 8 +- drivers/net/arm/etherh.c | 8 +- drivers/net/at1700.c | 4 +- drivers/net/atarilance.c | 43 ++-- drivers/net/atp.c | 8 +- drivers/net/b44.c | 9 +- drivers/net/bmac.c | 6 +- drivers/net/bnx2.c | 12 +- drivers/net/bonding/bond_main.c | 34 +-- drivers/net/bonding/bond_sysfs.c | 11 +- drivers/net/cassini.c | 11 +- drivers/net/cris/eth_v10.c | 8 +- drivers/net/cs89x0.c | 15 +- drivers/net/de600.c | 6 +- drivers/net/de620.c | 8 +- drivers/net/declance.c | 14 +- drivers/net/depca.c | 13 +- drivers/net/dgrs.c | 18 +- drivers/net/dl2k.c | 7 +- drivers/net/dm9000.c | 9 +- drivers/net/e100.c | 9 +- drivers/net/e1000/e1000_main.c | 5 +- drivers/net/eepro.c | 5 +- drivers/net/eepro100.c | 9 +- drivers/net/epic100.c | 9 +- drivers/net/es3210.c | 22 +- drivers/net/ewrk3.c | 16 +- drivers/net/fealnx.c | 9 +- drivers/net/fec.c | 7 +- drivers/net/forcedeth.c | 12 +- drivers/net/gianfar.c | 7 +- drivers/net/hamachi.c | 8 +- drivers/net/hamradio/bpqether.c | 23 +- drivers/net/hp-plus.c | 6 +- drivers/net/hp.c | 5 +- drivers/net/hp100.c | 6 +- drivers/net/hydra.c | 7 +- drivers/net/ibm_emac/ibm_emac_core.c | 14 +- drivers/net/ibmlana.c | 6 +- drivers/net/ibmveth.c | 9 +- drivers/net/ioc3-eth.c | 12 +- drivers/net/isa-skeleton.c | 5 +- drivers/net/jazzsonic.c | 10 +- drivers/net/lance.c | 6 +- drivers/net/lguest_net.c | 4 +- drivers/net/lib82596.c | 18 +- drivers/net/lne390.c | 9 +- drivers/net/mac89x0.c | 11 +- drivers/net/macb.c | 6 +- drivers/net/mace.c | 9 +- drivers/net/macmace.c | 6 +- drivers/net/macsonic.c | 21 +- drivers/net/meth.c | 6 +- drivers/net/mv643xx_eth.c | 5 +- drivers/net/mvme147.c | 11 +- drivers/net/myri10ge/myri10ge.c | 11 +- drivers/net/myri_sbus.c | 29 +-- drivers/net/natsemi.c | 11 +- drivers/net/ne-h8300.c | 8 +- drivers/net/ne.c | 5 +- drivers/net/ne2.c | 17 +- drivers/net/ne2k-pci.c | 11 +- drivers/net/ne3210.c | 11 +- drivers/net/netconsole.c | 14 +- drivers/net/netxen/netxen_nic_main.c | 13 +- drivers/net/netxen/netxen_nic_niu.c | 14 +- drivers/net/ni5010.c | 4 +- drivers/net/ns83820.c | 7 +- drivers/net/pasemi_mac.c | 6 +- drivers/net/pci-skeleton.c | 9 +- drivers/net/pcmcia/3c574_cs.c | 9 +- drivers/net/pcmcia/3c589_cs.c | 10 +- drivers/net/pcmcia/axnet_cs.c | 9 +- drivers/net/pcmcia/fmvj18x_cs.c | 8 +- drivers/net/pcmcia/nmclan_cs.c | 9 +- drivers/net/pcmcia/pcnet_cs.c | 7 +- drivers/net/pcmcia/smc91c92_cs.c | 8 +- drivers/net/pcmcia/xirc2ps_cs.c | 9 +- drivers/net/pppoe.c | 8 +- drivers/net/ps3_gelic_net.c | 7 +- drivers/net/qla3xxx.c | 7 +- drivers/net/rionet.c | 6 +- drivers/net/rrunner.c | 8 +- drivers/net/s2io.c | 11 +- drivers/net/sb1250-mac.c | 7 +- drivers/net/seeq8005.c | 4 +- drivers/net/sgiseeq.c | 6 +- drivers/net/sis190.c | 10 +- drivers/net/sis900.c | 9 +- drivers/net/skge.c | 7 +- drivers/net/sky2.c | 7 +- drivers/net/smc-mca.c | 8 +- drivers/net/smc-ultra.c | 8 +- drivers/net/smc-ultra32.c | 8 +- drivers/net/smc9194.c | 7 +- drivers/net/smc91x.c | 9 +- drivers/net/starfire.c | 26 ++- drivers/net/sun3lance.c | 36 ++- drivers/net/sunbmac.c | 8 +- drivers/net/sundance.c | 10 +- drivers/net/sungem.c | 12 +- drivers/net/sunhme.c | 12 +- drivers/net/sunlance.c | 9 +- drivers/net/tokenring/abyss.c | 12 +- drivers/net/tokenring/ibmtr.c | 26 ++- drivers/net/tokenring/lanstreamer.c | 64 +++--- drivers/net/tokenring/madgemc.c | 19 +- drivers/net/tokenring/olympic.c | 138 +++++------- drivers/net/tokenring/proteon.c | 8 +- drivers/net/tokenring/skisa.c | 8 +- drivers/net/tokenring/tmspci.c | 10 +- drivers/net/tsi108_eth.c | 7 +- drivers/net/tulip/de2104x.c | 9 +- drivers/net/tulip/de4x5.c | 33 +-- drivers/net/tulip/dmfe.c | 15 +- drivers/net/tulip/tulip_core.c | 15 +- drivers/net/tulip/uli526x.c | 9 +- drivers/net/tulip/winbond-840.c | 29 ++- drivers/net/tulip/xircom_cb.c | 7 +- drivers/net/tun.c | 33 ++- drivers/net/typhoon.c | 10 +- drivers/net/usb/pegasus.c | 11 +- drivers/net/usb/usbnet.c | 8 +- drivers/net/via-rhine.c | 13 +- drivers/net/wd.c | 7 +- drivers/net/wireless/adm8211.c | 5 +- drivers/net/wireless/airo.c | 32 +-- drivers/net/wireless/arlan-main.c | 23 +- drivers/net/wireless/atmel.c | 7 +- drivers/net/wireless/b43/main.c | 5 +- drivers/net/wireless/b43legacy/main.c | 3 +- drivers/net/wireless/bcm43xx/bcm43xx.h | 6 - drivers/net/wireless/hostap/hostap_80211_rx.c | 49 +++-- drivers/net/wireless/hostap/hostap_80211_tx.c | 13 +- drivers/net/wireless/hostap/hostap_ap.c | 198 ++++++++++------- drivers/net/wireless/hostap/hostap_common.h | 3 - drivers/net/wireless/hostap/hostap_hw.c | 11 +- drivers/net/wireless/hostap/hostap_info.c | 17 +- drivers/net/wireless/hostap/hostap_ioctl.c | 15 +- drivers/net/wireless/hostap/hostap_main.c | 30 ++- drivers/net/wireless/hostap/hostap_proc.c | 15 +- drivers/net/wireless/ipw2100.c | 48 ++-- drivers/net/wireless/ipw2200.c | 207 ++++++++++-------- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 5 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 34 +-- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 17 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 73 +++--- drivers/net/wireless/iwlwifi/iwl3945-base.c | 65 +++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 59 +++-- drivers/net/wireless/libertas/assoc.c | 19 +- drivers/net/wireless/libertas/cmdresp.c | 5 +- drivers/net/wireless/libertas/debugfs.c | 5 +- drivers/net/wireless/libertas/join.c | 16 +- drivers/net/wireless/libertas/main.c | 12 +- drivers/net/wireless/libertas/scan.c | 14 +- drivers/net/wireless/libertas/wext.c | 5 +- drivers/net/wireless/netwave_cs.c | 14 +- drivers/net/wireless/orinoco.c | 7 +- drivers/net/wireless/prism54/isl_ioctl.c | 50 ++--- drivers/net/wireless/ray_cs.c | 13 +- drivers/net/wireless/rt2x00/rt2400pci.c | 4 +- drivers/net/wireless/rt2x00/rt2500pci.c | 5 +- drivers/net/wireless/rt2x00/rt2500usb.c | 4 +- drivers/net/wireless/rt2x00/rt61pci.c | 4 +- drivers/net/wireless/rt2x00/rt73usb.c | 4 +- drivers/net/wireless/rtl8187_dev.c | 5 +- drivers/net/wireless/wavelan.c | 53 ++--- drivers/net/wireless/wavelan_cs.c | 54 ++--- drivers/net/wireless/wl3501_cs.c | 22 +- drivers/net/wireless/zd1211rw/zd_chip.c | 3 +- drivers/net/wireless/zd1211rw/zd_mac.c | 8 +- drivers/net/yellowfin.c | 19 +- drivers/net/znet.c | 11 +- drivers/net/zorro8390.c | 17 +- include/linux/if_ether.h | 8 + include/net/ieee80211.h | 5 - include/net/mac80211.h | 4 - net/802/tr.c | 28 +-- net/appletalk/aarp.c | 9 +- net/atm/br2684.c | 16 +- net/atm/lec.c | 29 +-- net/core/netpoll.c | 12 +- net/core/pktgen.c | 17 +- net/ethernet/eth.c | 8 + net/ieee80211/ieee80211_crypt_ccmp.c | 27 ++- net/ieee80211/ieee80211_crypt_tkip.c | 31 +-- net/ieee80211/ieee80211_rx.c | 59 ++--- net/ieee80211/ieee80211_wx.c | 5 +- .../softmac/ieee80211softmac_assoc.c | 4 +- net/ieee80211/softmac/ieee80211softmac_auth.c | 35 +-- net/ieee80211/softmac/ieee80211softmac_wx.c | 1 + net/irda/irlan/irlan_client.c | 6 +- net/llc/llc_proc.c | 12 +- net/mac80211/debugfs_key.c | 3 +- net/mac80211/debugfs_netdev.c | 3 +- net/mac80211/debugfs_sta.c | 6 +- net/mac80211/event.c | 5 +- net/mac80211/ieee80211.c | 5 +- net/mac80211/ieee80211_ioctl.c | 5 +- net/mac80211/ieee80211_sta.c | 180 ++++++++------- net/mac80211/key.c | 10 +- net/mac80211/rc80211_simple.c | 5 +- net/mac80211/rx.c | 103 +++++---- net/mac80211/sta_info.c | 13 +- net/mac80211/tkip.c | 10 +- net/mac80211/tx.c | 32 +-- net/mac80211/wpa.c | 19 +- net/tipc/eth_media.c | 4 +- 228 files changed, 1876 insertions(+), 1953 deletions(-) diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index f9e7ffbcb772..9c23336750e2 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -177,6 +177,7 @@ el2_probe1(struct net_device *dev, int ioaddr) int i, iobase_reg, membase_reg, saved_406, wordlength, retval; static unsigned version_printed; unsigned long vendor_id; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -226,7 +227,8 @@ el2_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + dev->dev_addr[i] = inb(ioaddr + i); + printk("%s", print_mac(mac, dev->dev_addr)); /* Map the 8390 back into the window. */ outb(ECNTRL_THIN, ioaddr + 0x406); diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index c05bb3fc57a2..9c6573419f5a 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1386,6 +1386,7 @@ static int __init elplus_setup(struct net_device *dev) unsigned long timeout; unsigned long cookie = 0; int err = -ENODEV; + DECLARE_MAC_BUF(mac); /* * setup adapter structure @@ -1521,11 +1522,10 @@ static int __init elplus_setup(struct net_device *dev) /* * print remainder of startup message */ - printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, ", - dev->name, dev->base_addr, dev->irq, dev->dma); - printk("addr %02x:%02x:%02x:%02x:%02x:%02x, ", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, " + "addr %s, ", + dev->name, dev->base_addr, dev->irq, dev->dma, + print_mac(mac, dev->dev_addr)); /* * read more information from the adapter diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 3d06271c3a8b..964d31ac9449 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -357,6 +357,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) static unsigned char init_ID_done, version_printed; int i, irq, irqval, retval; struct net_local *lp; + DECLARE_MAC_BUF(mac); if (init_ID_done == 0) { ushort lrs_state = 0xff; @@ -402,10 +403,9 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; outb(0x01, ioaddr + MISC_CTRL); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk(" %02x", dev->dev_addr[i]); - } + printk(" %s", print_mac(mac, dev->dev_addr)); if (mem_start) net_debug = mem_start & 7; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 7466987d8451..c576fe76d54f 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -313,8 +313,9 @@ static int nopnp; static int __init el3_common_init(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); - short i; int err; + DECLARE_MAC_BUF(mac); + const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; spin_lock_init(&lp->lock); @@ -346,17 +347,10 @@ static int __init el3_common_init(struct net_device *dev) return err; } - { - const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; - printk("%s: 3c5x9 found at %#3.3lx, %s port, address ", - dev->name, dev->base_addr, - if_names[(dev->if_port & 0x03)]); - } - - /* Read in the station address. */ - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i]); - printk(", IRQ %d.\n", dev->irq); + printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, " + "address %s, IRQ %d.\n", + dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], + print_mac(mac, dev->dev_addr), dev->irq); if (el3_debug > 0) printk(KERN_INFO "%s", version); diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 38a2ebea9b45..275e7510ebaf 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -569,6 +569,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; int irq; + DECLARE_MAC_BUF(mac); if (idev) { irq = pnp_irq(idev, 0); @@ -630,8 +631,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); - for (i = 0; i < 6; i++) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); + printk(" %s", print_mac(mac, dev->dev_addr)); if (eeprom[16] == 0x11c7) { /* Corkscrew */ if (request_dma(dev->dma, "3c515")) { printk(", DMA %d allocation failed", dev->dma); diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 10852b2a40ab..239fc42fb8df 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -383,8 +383,8 @@ void alloc586(struct net_device *dev) static int elmc_getinfo(char *buf, int slot, void *d) { int len = 0; - struct net_device *dev = (struct net_device *) d; - int i; + struct net_device *dev = d; + DECLARE_MAC_BUF(mac); if (dev == NULL) return len; @@ -399,12 +399,8 @@ static int elmc_getinfo(char *buf, int slot, void *d) len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ? "External" : "Internal"); len += sprintf(buf + len, "Device: %s\n", dev->name); - len += sprintf(buf + len, "Hardware Address:"); - for (i = 0; i < 6; i++) { - len += sprintf(buf + len, " %02x", dev->dev_addr[i]); - } - buf[len++] = '\n'; - buf[len] = 0; + len += sprintf(buf + len, "Hardware Address: %s\n", + print_mac(mac, dev->dev_addr)); return len; } /* elmc_getinfo() */ @@ -422,6 +418,7 @@ static int __init do_elmc_probe(struct net_device *dev) unsigned int size = 0; int retval; struct priv *pr = dev->priv; + DECLARE_MAC_BUF(mac); if (MCA_bus == 0) { return -ENODEV; @@ -544,12 +541,11 @@ static int __init do_elmc_probe(struct net_device *dev) /* The hardware address for the 3c523 is stored in the first six bytes of the IO address. */ - printk(KERN_INFO "%s: hardware address ", dev->name); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(dev->base_addr + i); - printk(" %02x", dev->dev_addr[i]); - } - printk("\n"); + + printk(KERN_INFO "%s: hardware address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); dev->open = &elmc_open; dev->stop = &elmc_close; diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 5b5f44cdfc1d..b72b89d53ec8 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -336,6 +336,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) "82586 initialisation failure", "Adapter list configuration error" }; + DECLARE_MAC_BUF(mac); /* Time to play MCA games */ @@ -396,17 +397,17 @@ static int __init mc32_probe1(struct net_device *dev, int slot) * Go PROM browsing */ - printk("%s: Address ", dev->name); - /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) { mca_write_pos(slot, 6, i+12); mca_write_pos(slot, 7, 0); - printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3)); + dev->dev_addr[i] = mca_read_pos(slot,3); } + printk("%s: Address %s", dev->name, print_mac(mac, dev->dev_addr)); + mca_write_pos(slot, 6, 0); mca_write_pos(slot, 7, 0); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index ad0f6a729d29..58311199e321 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1014,6 +1014,7 @@ static int __devinit vortex_probe1(struct device *gendev, char *print_name = "3c59x"; struct pci_dev *pdev = NULL; struct eisa_device *edev = NULL; + DECLARE_MAC_BUF(mac); if (!printed_version) { printk (version); @@ -1205,10 +1206,8 @@ static int __devinit vortex_probe1(struct device *gendev, for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (print_info) { - for (i = 0; i < 6; i++) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - } + if (print_info) + printk(" %s", print_mac(mac, dev->dev_addr)); /* Unfortunately an all zero eeprom passes the checksum and this gets found in the wild in failure cases. Crypto is hard 8) */ if (!is_valid_ether_addr(dev->dev_addr)) { diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 58fad1b2f72e..7edd50cf7776 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1823,6 +1823,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *regs; resource_size_t pciaddr; unsigned int addr_len, i, pci_using_dac; + DECLARE_MAC_BUF(mac); #ifndef MODULE static int version_printed; @@ -1964,13 +1965,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iomap; printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, " - "%02x:%02x:%02x:%02x:%02x:%02x, " - "IRQ %d\n", + "%s, IRQ %d\n", dev->name, dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + print_mac(mac, dev->dev_addr), dev->irq); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 28c1aaf1fe1d..d3088a786e26 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -926,6 +926,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, int i, addr_len, option; void __iomem *ioaddr; static int board_idx = -1; + DECLARE_MAC_BUF(mac); assert (pdev != NULL); assert (ent != NULL); @@ -1017,14 +1018,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, pci_set_drvdata (pdev, dev); printk (KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "IRQ %d\n", + "%s, IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + print_mac(mac, dev->dev_addr), dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 6b03416731de..bb30d5be7824 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1116,15 +1116,12 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) static void print_eth(unsigned char *add, char *str) { - int i; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); - printk(KERN_DEBUG "i596 0x%p, ", add); - for (i = 0; i < 6; i++) - printk(" %02X", add[i + 6]); - printk(" -->"); - for (i = 0; i < 6; i++) - printk(" %02X", add[i]); - printk(" %02X%02X, %s\n", add[12], add[13], str); + printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n", + add, print_mac(mac, add + 6), print_mac(mac2, add), + add[12], add[13], str); } static int io = 0x300; @@ -1539,6 +1536,7 @@ static void set_multicast_list(struct net_device *dev) struct dev_mc_list *dmi; unsigned char *cp; struct mc_cmd *cmd; + DECLARE_MAC_BUF(mac); if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out")) return; @@ -1549,8 +1547,8 @@ static void set_multicast_list(struct net_device *dev) for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) { memcpy(cp, dmi->dmi_addr, 6); if (i596_debug > 1) - DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5])); + DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %s\n", + dev->name, print_mac(mac, cp))); } i596_add_cmd(dev, &cmd->cmd); } diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 77773ce52eff..18f7f815f66e 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -716,6 +716,7 @@ static int __devinit a2065_init_one(struct zorro_dev *z, unsigned long board, base_addr, mem_start; struct resource *r1, *r2; int err; + DECLARE_MAC_BUF(mac); board = z->resource.start; base_addr = board+A2065_LANCE; @@ -792,9 +793,8 @@ static int __devinit a2065_init_one(struct zorro_dev *z, zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: A2065 at 0x%08lx, Ethernet Address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + "%s\n", dev->name, board, + print_mac(mac, dev->dev_addr)); return 0; } diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 65b2de56ed22..5136d94923aa 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -146,6 +146,7 @@ out: static int __init ac_probe1(int ioaddr, struct net_device *dev) { int i, retval; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -167,10 +168,11 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3)); #endif - printk("AC3200 in EISA slot %d, node", ioaddr/0x1000); - for(i = 0; i < 6; i++) - printk(" %02x", dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i)); + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i); + printk(KERN_DEBUG "AC3200 in EISA slot %d, node %s", + ioaddr/0x1000, print_mac(mac, dev->dev_addr)); #if 0 /* Check the vendor ID/prefix. Redundant after checking the EISA ID */ if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0 diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index ca00f41e4d85..2c2ed6dc98bc 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -893,6 +893,7 @@ static int __devinit ace_init(struct net_device *dev) int board_idx, ecode = 0; short i; unsigned char cache_size; + DECLARE_MAC_BUF(mac); ap = netdev_priv(dev); regs = ap->regs; @@ -1012,10 +1013,6 @@ static int __devinit ace_init(struct net_device *dev) writel(mac1, ®s->MacAddrHi); writel(mac2, ®s->MacAddrLo); - printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", - (mac1 >> 8) & 0xff, mac1 & 0xff, (mac2 >> 24) &0xff, - (mac2 >> 16) & 0xff, (mac2 >> 8) & 0xff, mac2 & 0xff); - dev->dev_addr[0] = (mac1 >> 8) & 0xff; dev->dev_addr[1] = mac1 & 0xff; dev->dev_addr[2] = (mac2 >> 24) & 0xff; @@ -1023,6 +1020,8 @@ static int __devinit ace_init(struct net_device *dev) dev->dev_addr[4] = (mac2 >> 8) & 0xff; dev->dev_addr[5] = mac2 & 0xff; + printk("MAC: %s\n", print_mac(mac, dev->dev_addr)); + /* * Looks like this is necessary to deal with on all architectures, * even this %$#%$# N440BX Intel based thing doesn't get it right. diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index afb60a5927ae..73f40a45441a 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1934,6 +1934,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, unsigned long reg_addr,reg_len; struct amd8111e_priv* lp; struct net_device* dev; + DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if(err){ @@ -2006,7 +2007,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, /* Initializing MAC address */ for(i = 0; i < ETH_ADDR_LEN; i++) - dev->dev_addr[i] =readb(lp->mmio + PADR + i); + dev->dev_addr[i] = readb(lp->mmio + PADR + i); /* Setting user defined parametrs */ lp->ext_phy_option = speed_duplex[card_idx]; @@ -2075,11 +2076,10 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, /* display driver and device information */ chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; - printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", dev->name,MODULE_VERS); - printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version); - for (i = 0; i < 6; i++) - printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':'); - printk( "\n"); + printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", + dev->name,MODULE_VERS); + printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %s\n", + dev->name, chip_version, print_mac(mac, dev->dev_addr)); if (lp->ext_phy_id) printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n", dev->name, lp->ext_phy_id, lp->ext_phy_addr); diff --git a/drivers/net/apne.c b/drivers/net/apne.c index b5a974a964c2..c12cbdf368b1 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -204,6 +204,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) int neX000, ctron; #endif static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (ei_debug && version_printed++ == 0) printk(version); @@ -316,12 +317,12 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev); if (i) return i; - for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); + for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - } - printk("\n%s: %s found.\n", dev->name, name); + printk(" %s\n", print_mac(mac, dev->dev_addr)); + + printk("%s: %s found.\n", dev->name, name); ei_status.name = name; ei_status.tx_start_page = start_page; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 2c020a36177e..3fa3bccd1adb 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -166,6 +166,7 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, struct net_device *dev; struct ariadne_private *priv; int err; + DECLARE_MAC_BUF(mac); r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960"); if (!r1) @@ -216,9 +217,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + "%s\n", dev->name, board, + print_mac(mac, dev->dev_addr)); return 0; } @@ -614,21 +614,17 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Fill in a Tx ring entry */ #if 0 - printk(KERN_DEBUG "TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); - { - int i; - u_char *ptr = &((u_char *)skb->data)[6]; - for (i = 0; i < 6; i++) - printk("%02x", ptr[i]); - } - printk(" to "); - { - int i; - u_char *ptr = (u_char *)skb->data; - for (i = 0; i < 6; i++) - printk("%02x", ptr[i]); - } - printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); +{ + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + printk(KERN_DEBUG "TX pkt type 0x%04x from %s to %s " + " data 0x%08x len %d\n", + ((u_short *)skb->data)[6], + print_mac(mac, ((const u8 *)skb->data)+6), + print_mac(mac, (const u8 *)skb->data), + (int)skb->data, (int)skb->len); +} #endif local_irq_save(flags); @@ -748,22 +744,22 @@ static int ariadne_rx(struct net_device *dev) skb_copy_to_linear_data(skb, (char *)priv->rx_buff[entry], pkt_len); skb->protocol=eth_type_trans(skb,dev); #if 0 +{ + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "RX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); { - int i; u_char *ptr = &((u_char *)skb->data)[6]; - for (i = 0; i < 6; i++) - printk("%02x", ptr[i]); + printk("%s", print_mac(mac, ptr)); } printk(" to "); { - int i; u_char *ptr = (u_char *)skb->data; - for (i = 0; i < 6; i++) - printk("%02x", ptr[i]); + printk("%s", print_mac(mac, ptr)); } printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); +} #endif netif_rx(skb); diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 77964556776e..ba6bd03a015f 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -741,12 +741,10 @@ static int __init am79c961_probe(struct platform_device *pdev) ret = register_netdev(dev); if (ret == 0) { - printk(KERN_INFO "%s: ether address ", dev->name); - - /* Retrive and print the ethernet address. */ - for (i = 0; i < 6; i++) - printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); + DECLARE_MAC_BUF(mac); + printk(KERN_INFO "%s: ether address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; } diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 619810a01e5b..25b114a4e2b1 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -485,6 +485,7 @@ static void update_mac_address(struct net_device *dev) static int set_mac_address(struct net_device *dev, void* addr) { struct sockaddr *address = addr; + DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(address->sa_data)) return -EADDRNOTAVAIL; @@ -492,9 +493,8 @@ static int set_mac_address(struct net_device *dev, void* addr) memcpy(dev->dev_addr, address->sa_data, dev->addr_len); update_mac_address(dev); - printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\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]); + printk("%s: Setting MAC address to %s\n", dev->name, + print_mac(mac, dev->dev_addr)); return 0; } @@ -979,6 +979,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add struct at91_private *lp; unsigned int val; int res; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct at91_private)); if (!dev) @@ -1081,12 +1082,11 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add } /* Display ethernet banner */ - printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", - dev->name, (uint) dev->base_addr, dev->irq, - at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-", - at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%s)\n", + dev->name, (uint) dev->base_addr, dev->irq, + at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-", + at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex", + print_mac(mac, dev->dev_addr)); if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); else if (phy_type == MII_LXT971A_ID) diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index 6ec8a587c1d2..3bb9e293e2ef 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -996,6 +996,7 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) { struct net_device *dev; int i, ret = 0; + DECLARE_MAC_BUF(mac); ether1_banner(); @@ -1043,12 +1044,9 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: ether1 in slot %d, ", - dev->name, ec->slot_no); + printk(KERN_INFO "%s: ether1 in slot %d, %s\n", + dev->name, ec->slot_no, print_mac(mac, dev->dev_addr)); - for (i = 0; i < 6; i++) - printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - ecard_set_drvdata(ec, dev); return 0; diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 4a914748c0e4..67e96ae85035 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -775,7 +775,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) { const struct ether3_data *data = id->data; struct net_device *dev; - int i, bus_type, ret; + int bus_type, ret; + DECLARE_MAC_BUF(mac); ether3_banner(); @@ -858,9 +859,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk("%s: %s in slot %d, ", dev->name, data->name, ec->slot_no); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + printk("%s: %s in slot %d, %s\n", + dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr)); ecard_set_drvdata(ec, dev); return 0; diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 5d093b3ddcd4..00081d2b9cd5 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -648,6 +648,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) struct net_device *dev; struct etherh_priv *eh; int i, ret; + DECLARE_MAC_BUF(mac); etherh_banner(); @@ -745,11 +746,8 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: %s in slot %d, ", - dev->name, data->name, ec->slot_no); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + printk(KERN_INFO "%s: %s in slot %d, %s\n", + dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr)); ecard_set_drvdata(ec, dev); diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index a124fdb2bce6..b032c1bf492f 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -265,6 +265,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr) unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; struct net_local *lp = netdev_priv(dev); + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -388,16 +389,15 @@ found: if (is_at1700) { for(i = 0; i < 3; i++) { unsigned short eeprom_val = read_eeprom(ioaddr, 4+i); - printk("%04x", eeprom_val); ((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val); } } else { for(i = 0; i < 6; i++) { unsigned char val = inb(ioaddr + SAPROM + i); - printk("%02x", val); dev->dev_addr[i] = val; } } + printk("%s", print_mac(mac, dev->dev_addr)); /* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals, rather than 150 ohm shielded twisted pair compensation. diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 8bf548e1cb4e..ebf1a3a88e15 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -467,6 +467,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, int i; static int did_version; unsigned short save1, save2; + DECLARE_MAC_BUF(mac); PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", (long)memaddr, (long)ioaddr )); @@ -595,8 +596,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, i = IO->mem; break; } - for( i = 0; i < 6; ++i ) - printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" ); + printk("%s\n", print_mac(mac, dev->dev_addr)); if (lp->cardtype == OLD_RIEBL) { printk( "%s: Warning: This is a default ethernet address!\n", dev->name ); @@ -779,6 +779,8 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) int entry, len; struct lance_tx_head *head; unsigned long flags; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, DREG )); @@ -801,17 +803,13 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* Fill in a Tx ring entry */ if (lance_debug >= 3) { - u_char *p; - int i; - printk( "%s: TX pkt type 0x%04x from ", dev->name, - ((u_short *)skb->data)[6]); - for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" to "); - for( p = (u_char *)skb->data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" data at 0x%08x len %d\n", (int)skb->data, - (int)skb->len ); + printk( "%s: TX pkt type 0x%04x from " + "%s to %s" + " data at 0x%08x len %d\n", + dev->name, ((u_short *)skb->data)[6], + print_mac(mac, &skb->data[6]), + print_mac(mac2, skb->data), + (int)skb->data, (int)skb->len ); } /* We're not prepared for the int until the last flags are set/reset. And @@ -1021,19 +1019,18 @@ static int lance_rx( struct net_device *dev ) } if (lance_debug >= 3) { - u_char *data = PKTBUF_ADDR(head), *p; - printk( "%s: RX pkt type 0x%04x from ", dev->name, - ((u_short *)data)[6]); - for( p = &data[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" to "); - for( p = data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " + u_char *data = PKTBUF_ADDR(head); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s ", + "data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d\n", + dev->name, ((u_short *)data)[6], + print_mac(mac, &data[6]), print_mac(mac2, data), data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], - pkt_len ); + pkt_len); } skb_reserve( skb, 2 ); /* 16 byte align */ diff --git a/drivers/net/atp.c b/drivers/net/atp.c index cec2e3672cd0..62f09e59d9c4 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -248,6 +248,7 @@ static int __init atp_probe1(long ioaddr) struct net_local *lp; int saved_ctrl_reg, status, i; int res; + DECLARE_MAC_BUF(mac); outb(0xff, ioaddr + PAR_DATA); /* Save the original value of the Control register, in case we guessed @@ -322,10 +323,9 @@ static int __init atp_probe1(long ioaddr) printk(KERN_INFO "%s", version); #endif - printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM " - "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr, - dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, " + "SAPROM %s.\n", + dev->name, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); /* Reset the ethernet hardware and activate the printer pass-through. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 6d193705a3bc..40842a6aa994 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2100,7 +2100,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev, unsigned long b44reg_base, b44reg_len; struct net_device *dev; struct b44 *bp; - int err, i; + int err; + DECLARE_MAC_BUF(mac); if (b44_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2229,10 +2230,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev, */ b44_chip_reset(bp); - printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? '\n' : ':'); + printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 2761441f6644..a42bd19646d3 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1258,6 +1258,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i unsigned char addr[6]; struct net_device *dev; int is_bmac_plus = ((int)match->data) != 0; + DECLARE_MAC_BUF(mac); if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n"); @@ -1367,9 +1368,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i goto err_out_irq2; } - printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": "")); - for (j = 0; j < 6; ++j) - printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); + printk(KERN_INFO "%s: BMAC%s at %s", + dev->name, (is_bmac_plus ? "+" : ""), print_mac(mac, dev->dev_addr)); XXDEBUG((", base_addr=%#0lx", dev->base_addr)); printk("\n"); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 5ee805b3e0e6..ee9aed3aa489 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6821,8 +6821,9 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static int version_printed = 0; struct net_device *dev = NULL; struct bnx2 *bp; - int rc, i; + int rc; char str[40]; + DECLARE_MAC_BUF(mac); if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -6890,19 +6891,14 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, " - "IRQ %d, ", + "IRQ %d, node addr %s\n", dev->name, bp->name, ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', ((CHIP_ID(bp) & 0x0ff0) >> 4), bnx2_bus_string(bp, str), dev->base_addr, - bp->pdev->irq); - - printk("node addr "); - for (i = 0; i < 6; i++) - printk("%2.2x", dev->dev_addr[i]); - printk("\n"); + bp->pdev->irq, print_mac(mac, dev->dev_addr)); return 0; } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ea58144c220e..8f77db2112ce 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1604,6 +1604,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) struct slave *slave, *oldcurrent; struct sockaddr addr; int mac_addr_differ; + DECLARE_MAC_BUF(mac); /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -1631,19 +1632,13 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) ETH_ALEN); if (!mac_addr_differ && (bond->slave_cnt > 1)) { printk(KERN_WARNING DRV_NAME - ": %s: Warning: the permanent HWaddr of %s " - "- %02X:%02X:%02X:%02X:%02X:%02X - is " - "still in use by %s. Set the HWaddr of " - "%s to a different address to avoid " - "conflicts.\n", + ": %s: Warning: the permanent HWaddr of %s - " + "%s - is still in use by %s. " + "Set the HWaddr of %s to a different address " + "to avoid conflicts.\n", bond_dev->name, slave_dev->name, - slave->perm_hwaddr[0], - slave->perm_hwaddr[1], - slave->perm_hwaddr[2], - slave->perm_hwaddr[3], - slave->perm_hwaddr[4], - slave->perm_hwaddr[5], + print_mac(mac, slave->perm_hwaddr), bond_dev->name, slave_dev->name); } @@ -3006,6 +3001,7 @@ static void bond_info_show_master(struct seq_file *seq) if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; + DECLARE_MAC_BUF(mac); seq_puts(seq, "\n802.3ad info\n"); seq_printf(seq, "LACP rate: %s\n", @@ -3025,13 +3021,8 @@ static void bond_info_show_master(struct seq_file *seq) ad_info.actor_key); seq_printf(seq, "\tPartner Key: %d\n", ad_info.partner_key); - seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - ad_info.partner_system[0], - ad_info.partner_system[1], - ad_info.partner_system[2], - ad_info.partner_system[3], - ad_info.partner_system[4], - ad_info.partner_system[5]); + seq_printf(seq, "\tPartner Mac Address: %s\n", + print_mac(mac, ad_info.partner_system)); } } } @@ -3039,6 +3030,7 @@ static void bond_info_show_master(struct seq_file *seq) static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) { struct bonding *bond = seq->private; + DECLARE_MAC_BUF(mac); seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", @@ -3047,10 +3039,8 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave slave->link_failure_count); seq_printf(seq, - "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n", - slave->perm_hwaddr[0], slave->perm_hwaddr[1], - slave->perm_hwaddr[2], slave->perm_hwaddr[3], - slave->perm_hwaddr[4], slave->perm_hwaddr[5]); + "Permanent HW addr: %s\n", + print_mac(mac, slave->perm_hwaddr)); if (bond->params.mode == BOND_MODE_8023AD) { const struct aggregator *agg diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index a771853219da..f10927639b5c 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1361,17 +1361,14 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, { int count = 0; struct bonding *bond = to_bond(d); + DECLARE_MAC_BUF(mac); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; if (!bond_3ad_get_active_agg_info(bond, &ad_info)) { - count = sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x\n", - ad_info.partner_system[0], - ad_info.partner_system[1], - ad_info.partner_system[2], - ad_info.partner_system[3], - ad_info.partner_system[4], - ad_info.partner_system[5]) + 1; + count = sprintf(buf,"%s\n", + print_mac(mac, ad_info.partner_system)) + + 1; } } else diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f44f3d2a4b4e..adc2e4d5a69e 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4877,6 +4877,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, int i, err, pci_using_dac; u16 pci_cmd; u8 orig_cacheline_size = 0, cas_cacheline_size = 0; + DECLARE_MAC_BUF(mac); if (cas_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -5084,16 +5085,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev, i = readl(cp->regs + REG_BIM_CFG); printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) " - "Ethernet[%d] ", dev->name, + "Ethernet[%d] %s\n", dev->name, (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "", (i & BIM_CFG_32BIT) ? "32" : "64", (i & BIM_CFG_66MHZ) ? "66" : "33", - (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ' : ':'); - printk("\n"); + (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq, + print_mac(mac, dev->dev_addr)); pci_set_drvdata(pdev, dev); cp->hw_running = 1; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 5bdf5ca85a65..314b2f68f78f 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -618,12 +618,8 @@ e100_set_mac_address(struct net_device *dev, void *p) /* show it in the log as well */ - printk(KERN_INFO "%s: changed MAC to ", dev->name); - - for (i = 0; i < 5; i++) - printk("%02X:", dev->dev_addr[i]); - - printk("%02X\n", dev->dev_addr[i]); + printk(KERN_INFO "%s: changed MAC to %s\n", + dev->name, print_mac(mac, dev->dev_addr)); spin_unlock(&np->lock); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 4cf82cf5ac10..571750975137 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -516,6 +516,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; int retval; + DECLARE_MAC_BUF(mac); /* Initialize the device structure. */ if (!modular) { @@ -840,11 +841,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } /* print the ethernet address. */ - printk(", MAC"); - for (i = 0; i < ETH_ALEN; i++) - { - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - } + printk(", MAC %s", print_mac(mac, dev->dev_addr)); dev->open = net_open; dev->stop = net_close; @@ -1806,17 +1803,15 @@ static int set_mac_address(struct net_device *dev, void *p) int i; struct sockaddr *addr = p; - if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); if (net_debug) { - printk("%s: Setting MAC address to ", dev->name); - for (i = 0; i < dev->addr_len; i++) - printk(" %2.2x", dev->dev_addr[i]); - printk(".\n"); + DECLARE_MAC_BUF(mac); + printk("%s: Setting MAC address to %s.\n", + dev->name, print_mac(mac, dev->dev_addr)); } /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 421c2ca49711..cb849b091f98 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -384,6 +384,7 @@ static struct net_device * __init de600_probe(void) int i; struct net_device *dev; int err; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(0); if (!dev) @@ -438,10 +439,7 @@ static struct net_device * __init de600_probe(void) goto out1; } - printk(", Ethernet Address: %02X", dev->dev_addr[0]); - for (i = 1; i < ETH_ALEN; i++) - printk(":%02X",dev->dev_addr[i]); - printk("\n"); + printk(", Ethernet Address: %s\n", print_mac(mac, dev->dev_addr)); dev->open = de600_open; dev->stop = de600_close; diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 4b93902906ba..3f5190c654cf 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -807,6 +807,7 @@ struct net_device * __init de620_probe(int unit) struct net_device *dev; int err = -ENOMEM; int i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(0); if (!dev) @@ -853,13 +854,14 @@ struct net_device * __init de620_probe(int unit) } /* else, got it! */ - printk(", Ethernet Address: %2.2X", - dev->dev_addr[0] = nic_data.NodeID[0]); + dev->dev_addr[0] = nic_data.NodeID[0]; for (i = 1; i < ETH_ALEN; i++) { - printk(":%2.2X", dev->dev_addr[i] = nic_data.NodeID[i]); + dev->dev_addr[i] = nic_data.NodeID[i]; dev->broadcast[i] = 0xff; } + printk(", Ethernet Address: %s", print_mac(mac, dev->dev_addr)); + printk(" (%dk RAM,", (nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64); diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 7e7ac3330e60..00e0194bfef0 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -1027,6 +1027,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type) int i, ret; unsigned long esar_base; unsigned char *esar; + DECLARE_MAC_BUF(mac); if (dec_lance_debug && version_printed++ == 0) printk(version); @@ -1214,21 +1215,20 @@ static int __init dec_lance_probe(struct device *bdev, const int type) */ switch (type) { case ASIC_LANCE: - printk("%s: IOASIC onboard LANCE, addr = ", name); + printk("%s: IOASIC onboard LANCE", name); break; case PMAD_LANCE: - printk("%s: PMAD-AA, addr = ", name); + printk("%s: PMAD-AA", name); break; case PMAX_LANCE: - printk("%s: PMAX onboard LANCE, addr = ", name); + printk("%s: PMAX onboard LANCE", name); break; } - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = esar[i * 4]; - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':'); - } - printk(" irq = %d\n", dev->irq); + printk(", addr = %s, irq = %d\n", + print_mac(mac, dev->dev_addr), dev->irq); dev->open = &lance_open; dev->stop = &lance_close; diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 28fa2bdc8c79..ace39ec0a367 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -573,6 +573,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) s16 nicsr; u_long ioaddr; u_long mem_start; + DECLARE_MAC_BUF(mac); /* * We are now supposed to enter this function with the @@ -632,14 +633,11 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) printk(", h/w address "); status = get_hw_addr(dev); + printk("%s", print_mac(mac, dev->dev_addr)); if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); return -ENXIO; } - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x", dev->dev_addr[i]); /* Set up the maximum amount of network RAM(kB) */ netRAM = ((lp->adapter != DEPCA) ? 64 : 48); @@ -1843,6 +1841,7 @@ static void depca_dbg_open(struct net_device *dev) u_long ioaddr = dev->base_addr; struct depca_init *p = &lp->init_block; int i; + DECLARE_MAC_BUF(mac); if (depca_debug > 1) { /* Do not copy the shadow init block into shared memory */ @@ -1881,11 +1880,7 @@ static void depca_dbg_open(struct net_device *dev) printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start); printk(" mode: 0x%4.4x\n", p->mode); - printk(" physical address: "); - for (i = 0; i < ETH_ALEN - 1; i++) { - printk("%2.2x:", p->phys_addr[i]); - } - printk("%2.2x\n", p->phys_addr[i]); + printk(" physical address: %s\n", print_mac(mac, p->phys_addr)); printk(" multicast hash table: "); for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) { printk("%2.2x:", p->mcast_table[i]); diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index a9ef79da3dc7..054f2ba5f698 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1139,6 +1139,7 @@ dgrs_probe1(struct net_device *dev) DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; unsigned long i; int rc; + DECLARE_MAC_BUF(mac); printk("%s: Digi RightSwitch io=%lx mem=%lx irq=%d plx=%lx dma=%lx\n", dev->name, dev->base_addr, dev->mem_start, dev->irq, @@ -1154,11 +1155,9 @@ dgrs_probe1(struct net_device *dev) /* * Get ether address of board */ - printk("%s: Ethernet address", dev->name); memcpy(dev->dev_addr, priv->port->ethaddr, 6); - for (i = 0; i < 6; ++i) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - printk("\n"); + printk("%s: Ethernet address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); if (dev->dev_addr[0] & 1) { @@ -1214,15 +1213,12 @@ static int __init dgrs_initclone(struct net_device *dev) { DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - int i; + DECLARE_MAC_BUF(mac); - printk("%s: Digi RightSwitch port %d ", - dev->name, priv->chan); - for (i = 0; i < 6; ++i) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - printk("\n"); + printk("%s: Digi RightSwitch port %d %s\n", + dev->name, priv->chan, print_mac(mac, dev->dev_addr)); - return (0); + return 0; } static struct net_device * __init diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 12486e13b85b..e91b7096838a 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -97,6 +97,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) static int version_printed; void *ring_space; dma_addr_t ring_dma; + DECLARE_MAC_BUF(mac); if (!version_printed++) printk ("%s", version); @@ -256,10 +257,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) card_idx++; - printk (KERN_INFO "%s: %s, %02x:%02x:%02x:%02x:%02x:%02x, IRQ %d\n", - dev->name, np->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], irq); + printk (KERN_INFO "%s: %s, %s, IRQ %d\n", + dev->name, np->name, print_mac(mac, dev->dev_addr), irq); if (tx_coalesce > 1) printk(KERN_INFO "tx_coalesce:\t%d packets\n", tx_coalesce); diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index f691ef61b2d3..27ac010900ab 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -595,11 +595,10 @@ dm9000_probe(struct platform_device *pdev) ret = register_netdev(ndev); if (ret == 0) { - printk("%s: dm9000 at %p,%p IRQ %d MAC: ", - ndev->name, db->io_addr, db->io_data, ndev->irq); - for (i = 0; i < 5; i++) - printk("%02x:", ndev->dev_addr[i]); - printk("%02x\n", ndev->dev_addr[5]); + DECLARE_MAC_BUF(mac); + printk("%s: dm9000 at %p,%p IRQ %d MAC: %s\n", + ndev->name, db->io_addr, db->io_data, ndev->irq, + print_mac(mac, ndev->dev_addr)); } return 0; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 99126564f1a0..720994b1e13a 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2548,6 +2548,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, struct net_device *netdev; struct nic *nic; int err; + DECLARE_MAC_BUF(mac); if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { if(((1 << debug) - 1) & NETIF_MSG_PROBE) @@ -2679,11 +2680,9 @@ static int __devinit e100_probe(struct pci_dev *pdev, goto err_out_free; } - DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, " - "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", - (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq, - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n", + (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), + pdev->irq, print_mac(mac, netdev->dev_addr)); return 0; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7befb706ad55..ad444c9a5d04 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -872,6 +872,8 @@ e1000_probe(struct pci_dev *pdev, int i, err, pci_using_dac; uint16_t eeprom_data = 0; uint16_t eeprom_apme_mask = E1000_EEPROM_APME; + DECLARE_MAC_BUF(mac); + if ((err = pci_enable_device(pdev))) return err; @@ -1132,8 +1134,7 @@ e1000_probe(struct pci_dev *pdev, "32-bit")); } - for (i = 0; i < 6; i++) - printk("%2.2x%c", netdev->dev_addr[i], i == 5 ? '\n' : ':'); + printk("%s\n", print_mac(mac, netdev->dev_addr)); /* reset the hardware with the new settings */ e1000_reset(adapter); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 54811f6f766d..83bda6ccde98 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -690,6 +690,7 @@ static void __init eepro_print_info (struct net_device *dev) struct eepro_local * lp = netdev_priv(dev); int i; const char * ifmap[] = {"AUI", "10Base2", "10BaseT"}; + DECLARE_MAC_BUF(mac); i = inb(dev->base_addr + ID_REG); printk(KERN_DEBUG " id: %#x ",i); @@ -711,10 +712,10 @@ static void __init eepro_print_info (struct net_device *dev) case LAN595: printk("%s: Intel 82595-based lan card at %#x,", dev->name, (unsigned)dev->base_addr); + break; } - for (i=0; i < 6; i++) - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); + printk(" %s", print_mac(mac, dev->dev_addr)); if (net_debug > 3) printk(KERN_DEBUG ", %dK RCV buffer", diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index f8b69ceb2be6..1548a80f917d 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -622,6 +622,7 @@ static int __devinit speedo_found1(struct pci_dev *pdev, int size; void *tx_ring_space; dma_addr_t tx_ring_dma; + DECLARE_MAC_BUF(mac); size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats); tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma); @@ -705,12 +706,8 @@ static int __devinit speedo_found1(struct pci_dev *pdev, else product = pci_name(pdev); - printk(KERN_INFO "%s: %s, ", dev->name, product); - - for (i = 0; i < 5; i++) - printk("%2.2X:", dev->dev_addr[i]); - printk("%2.2X, ", dev->dev_addr[i]); - printk("IRQ %d.\n", pdev->irq); + printk(KERN_INFO "%s: %s, %s, IRQ %d.\n", dev->name, product, + print_mac(mac, dev->dev_addr), pdev->irq); sp = netdev_priv(dev); diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 5ac56f20003d..ecdd3fc8d70c 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -317,6 +317,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, int i, ret, option = 0, duplex = 0; void *ring_space; dma_addr_t ring_dma; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -493,11 +494,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, if (ret < 0) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq, + print_mac(mac, dev->dev_addr)); out: return ret; diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 238fa8aff02d..deefa51b8c31 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -179,6 +179,7 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) { int i, retval; unsigned long eisa_id; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210")) return -ENODEV; @@ -190,7 +191,6 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6)); #endif - /* Check the EISA ID of the card. */ eisa_id = inl(ioaddr + ES_ID_PORT); if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) { @@ -198,21 +198,21 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) goto out; } + for (i = 0; i < ETHER_ADDR_LEN ; i++) + dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i); + /* Check the Racal vendor ID as well. */ - if (inb(ioaddr + ES_SA_PROM + 0) != ES_ADDR0 - || inb(ioaddr + ES_SA_PROM + 1) != ES_ADDR1 - || inb(ioaddr + ES_SA_PROM + 2) != ES_ADDR2 ) { - printk("es3210.c: card not found"); - for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %02x", inb(ioaddr + ES_SA_PROM + i)); - printk(" (invalid prefix).\n"); + if (dev->dev_addr[0] != ES_ADDR0 || + dev->dev_addr[1] != ES_ADDR1 || + dev->dev_addr[2] != ES_ADDR2) { + printk("es3210.c: card not found %s (invalid_prefix).\n", + print_mac(mac, dev->dev_addr)); retval = -ENODEV; goto out; } - printk("es3210.c: ES3210 rev. %ld at %#x, node", eisa_id>>24, ioaddr); - for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i))); + printk("es3210.c: ES3210 rev. %ld at %#x, node %s", + eisa_id>>24, ioaddr, print_mac(mac, dev->dev_addr)); /* Snarf the interrupt now. */ if (dev->irq == 0) { diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 142aa225d89e..593a120e31b2 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -396,6 +396,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) u_long mem_start, shmem_length; u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0; u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; + DECLARE_MAC_BUF(mac); /* ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. @@ -460,10 +461,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) if (lemac != LeMAC2) DevicePresent(iobase); /* need after EWRK3_INIT */ status = get_hw_addr(dev, eeprom_image, lemac); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); + printk("%s\n", print_mac(mac, dev->dev_addr)); if (status) { printk(" which has an EEPROM CRC error.\n"); @@ -628,7 +626,7 @@ static int ewrk3_open(struct net_device *dev) { struct ewrk3_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int i, status = 0; + int status = 0; u_char icr, csr; /* @@ -648,12 +646,10 @@ static int ewrk3_open(struct net_device *dev) ewrk3_init(dev); if (ewrk3_debug > 1) { + DECLARE_MAC_BUF(mac); printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq); - printk(" physical address: "); - for (i = 0; i < 5; i++) { - printk("%2.2x:", (u_char) dev->dev_addr[i]); - } - printk("%2.2x\n", (u_char) dev->dev_addr[i]); + printk(" physical address: %s\n", + print_mac(mac, dev->dev_addr)); if (lp->shmem_length == 0) { printk(" no shared memory, I/O only mode\n"); } else { diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 402b071d8d53..43f7647ff246 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -486,6 +486,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, #else int bar = 1; #endif + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -664,11 +665,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, if (err) goto err_out_free_tx; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr, + print_mac(mac, dev->dev_addr), irq); return 0; diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 4419c3cee995..2b5782056dda 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -2635,6 +2635,7 @@ static int __init fec_enet_module_init(void) { struct net_device *dev; int i, j, err; + DECLARE_MAC_BUF(mac); printk("FEC ENET Version 0.2\n"); @@ -2653,10 +2654,8 @@ static int __init fec_enet_module_init(void) return -EIO; } - printk("%s: ethernet ", dev->name); - for (j = 0; (j < 5); j++) - printk("%02x:", dev->dev_addr[j]); - printk("%02x\n", dev->dev_addr[5]); + printk("%s: ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } return 0; } diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index be744573b1c2..f7354bc9b009 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4991,6 +4991,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i u32 powerstate, txreg; u32 phystate_orig = 0, phystate; int phyinitialized = 0; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct fe_priv)); err = -ENOMEM; @@ -5205,10 +5206,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i * Bad mac address. At least one bios sets the mac address * to 01:23:45:67:89:ab */ - printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n", - pci_name(pci_dev), - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_ERR "%s: Invalid Mac address detected: %s\n", + pci_name(pci_dev), print_mac(mac, dev->dev_addr)); printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n"); dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x00; @@ -5216,9 +5215,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i get_random_bytes(&dev->dev_addr[3], 3); } - dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev), - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + dprintk(KERN_DEBUG "%s: MAC Address %s\n", + pci_name(pci_dev), print_mac(mac, dev->dev_addr)); /* set mac address */ nv_copy_mac_to_hw(dev); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 5a1a1165b48c..0db5e6fabe73 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -170,6 +170,7 @@ static int gfar_probe(struct platform_device *pdev) struct resource *r; int idx; int err = 0; + DECLARE_MAC_BUF(mac); einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; @@ -356,10 +357,8 @@ static int gfar_probe(struct platform_device *pdev) gfar_init_sysfs(dev); /* Print out the device info */ - printk(KERN_INFO DEVICE_NAME, dev->name); - for (idx = 0; idx < 6; idx++) - printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':'); - printk("\n"); + printk(KERN_INFO DEVICE_NAME "%s\n", + dev->name, print_mac(mac, dev->dev_addr)); /* Even more device info helps when determining which kernel */ /* provided which set of benchmarks. */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index da12b3db023f..015ed3a4057f 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -580,6 +580,7 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, void *ring_space; dma_addr_t ring_dma; int ret = -ENOMEM; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -741,12 +742,9 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, goto err_out_unmap_rx; } - printk(KERN_INFO "%s: %s type %x at %p, ", + printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n", dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), - ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + ioaddr, print_mac(mac, dev->dev_addr), irq); i = readb(ioaddr + PCIClkMeas); printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " "%2.2x, LPA %4.4x.\n", diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index df09210f7351..c05bc37df356 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include #include #include @@ -95,7 +95,6 @@ static char bpq_eth_addr[6]; static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); static int bpq_device_event(struct notifier_block *, unsigned long, void *); -static const char *bpq_print_ethaddr(const unsigned char *); static struct packet_type bpq_packet_type = { .type = __constant_htons(ETH_P_BPQ), @@ -383,16 +382,6 @@ static int bpq_close(struct net_device *dev) /* * Proc filesystem */ -static const char * bpq_print_ethaddr(const unsigned char *e) -{ - static char buf[18]; - - sprintf(buf, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", - e[0], e[1], e[2], e[3], e[4], e[5]); - - return buf; -} - static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) { int i = 1; @@ -438,14 +427,16 @@ static int bpq_seq_show(struct seq_file *seq, void *v) "dev ether destination accept from\n"); else { const struct bpqdev *bpqdev = v; + DECLARE_MAC_BUF(mac); seq_printf(seq, "%-5s %-10s %s ", bpqdev->axdev->name, bpqdev->ethdev->name, - bpq_print_ethaddr(bpqdev->dest_addr)); + print_mac(mac, bpqdev->dest_addr)); - seq_printf(seq, "%s\n", - (bpqdev->acpt_addr[0] & 0x01) ? "*" - : bpq_print_ethaddr(bpqdev->acpt_addr)); + if (is_multicast_ether_addr(bpqdev->acpt_addr)) + seq_printf(seq, "*\n"); + else + seq_printf(seq, "%s\n", print_mac(mac, bpqdev->acpt_addr)); } return 0; diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 8d4f810fa288..c2c4f49d7578 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -166,6 +166,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) const char name[] = "HP-PC-LAN+"; int mem_start; static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -180,7 +181,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) if (ei_debug && version_printed++ == 0) printk(version); - printk("%s: %s at %#3x,", dev->name, name, ioaddr); + printk("%s: %s at %#3x, ", dev->name, name, ioaddr); /* Retrieve and checksum the station address. */ outw(MAC_Page, ioaddr + HP_PAGING); @@ -189,10 +190,11 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) unsigned char inval = inb(ioaddr + 8 + i); dev->dev_addr[i] = inval; checksum += inval; - printk(" %2.2x", inval); } checksum += inb(ioaddr + 14); + printk("%s", print_mac(mac, dev->dev_addr)); + if (checksum != 0xff) { printk(" bad checksum %2.2x.\n", checksum); retval = -ENODEV; diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 1f11126de354..c649a8019beb 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -127,6 +127,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) int i, retval, board_id, wordmode; const char *name; static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -158,7 +159,9 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr); for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + dev->dev_addr[i] = inb(ioaddr + i); + + printk(" %s", print_mac(mac, dev->dev_addr)); /* Snarf the interrupt now. Someday this could be moved to open(). */ if (dev->irq < 2) { diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 406d6525e222..e4fde17e2841 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2093,9 +2093,9 @@ static void hp100_set_multicast_list(struct net_device *dev) addrs = dmi->dmi_addr; if ((*addrs & 0x01) == 0x01) { /* multicast address? */ #ifdef HP100_DEBUG - printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ", - dev->name, addrs[0], addrs[1], addrs[2], - addrs[3], addrs[4], addrs[5]); + DECLARE_MAC_BUF(mac); + printk("hp100: %s: multicast = %s, ", + dev->name, print_mac(mac, addrs)); #endif for (j = idx = 0; j < 6; j++) { idx ^= *addrs++ & 0x3f; diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 31300a9dd965..b96cf2dcb109 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -103,6 +103,7 @@ static int __devinit hydra_init(struct zorro_dev *z) int start_page, stop_page; int j; int err; + DECLARE_MAC_BUF(mac); static u32 hydra_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, @@ -162,10 +163,8 @@ static int __devinit hydra_init(struct zorro_dev *z) zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: Hydra at 0x%08lx, address " - "%02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", - dev->name, z->resource.start, dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); + "%s (hydra.c " HYDRA_VERSION ")\n", + dev->name, z->resource.start, print_mac(mac, dev->dev_addr)); return 0; } diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index d7da56b105cb..7d4fa7644e4b 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -353,10 +353,9 @@ static void emac_hash_mc(struct ocp_enet_private *dev) for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { int bit; - DBG2("%d: mc %02x:%02x:%02x:%02x:%02x:%02x" NL, - dev->def->index, - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + DECLARE_MAC_BUF(mac); + DBG2("%d: mc %s" NL, + dev->def->index, print_mac(mac, dmi->dmi_addr)); bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26); gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f); @@ -1940,6 +1939,7 @@ static int __init emac_probe(struct ocp_device *ocpdev) struct ocp_device *maldev; struct ocp_enet_private *dev; int err, i; + DECLARE_MAC_BUF(mac); DBG("%d: probe" NL, ocpdev->def->index); @@ -2188,10 +2188,8 @@ static int __init emac_probe(struct ocp_device *ocpdev) ocp_set_drvdata(ocpdev, dev); - printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, dev->def->index, - ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], - ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + printk("%s: emac%d, MAC %s\n", + ndev->name, dev->def->index, print_mac(mac, ndev->dev_addr)); if (dev->phy.address >= 0) printk("%s: found %s PHY (0x%02x)\n", ndev->name, diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index eebf39acf586..91d83aca6bc7 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -898,6 +898,7 @@ static int ibmlana_probe(struct net_device *dev) int base = 0, irq = 0, iobase = 0, memlen = 0; ibmlana_priv *priv; ibmlana_medium medium; + DECLARE_MAC_BUF(mac); /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) @@ -981,11 +982,10 @@ static int ibmlana_probe(struct net_device *dev) /* print config */ printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, " - "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n", + "MAC address %s.\n", dev->name, priv->realirq, dev->base_addr, dev->mem_start, dev->mem_end - 1, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + print_mac(mac, dev->dev_addr)); printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]); /* reset board */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0636883449fc..228973484ed8 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1276,16 +1276,13 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v) struct ibmveth_adapter *adapter = seq->private; char *current_mac = ((char*) &adapter->netdev->dev_addr); char *firmware_mac = ((char*) &adapter->mac_addr) ; + DECLARE_MAC_BUF(mac); seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version); seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address); - seq_printf(seq, "Current MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", - current_mac[0], current_mac[1], current_mac[2], - current_mac[3], current_mac[4], current_mac[5]); - seq_printf(seq, "Firmware MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", - firmware_mac[0], firmware_mac[1], firmware_mac[2], - firmware_mac[3], firmware_mac[4], firmware_mac[5]); + seq_printf(seq, "Current MAC: %s\n", print_mac(mac, current_mac)); + seq_printf(seq, "Firmware MAC: %s\n", print_mac(mac, firmware_mac)); seq_printf(seq, "\nAdapter Statistics:\n"); seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed); diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 05d2bc15144e..373f72cdbe8e 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -443,18 +443,12 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip) */ static void ioc3_get_eaddr(struct ioc3_private *ip) { - int i; - + DECLARE_MAC_BUF(mac); ioc3_get_eaddr_nic(ip); - printk("Ethernet address is "); - for (i = 0; i < 6; i++) { - printk("%02x", priv_netdev(ip)->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk(".\n"); + printk("Ethernet address is %s.\n", + print_mac(mac, priv_netdev(ip)->dev_addr)); } static void __ioc3_set_mac_address(struct net_device *dev) diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 54178111eec5..d6ff26af37b3 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -192,6 +192,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) static unsigned version_printed; int i; int err = -ENODEV; + DECLARE_MAC_BUF(mac); /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname)) @@ -217,7 +218,9 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + dev->dev_addr[i] = inb(ioaddr + i); + + printk("%s", print_mac(mac, dev->dev_addr)); err = -EAGAIN; #ifdef jumpered_interrupts diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 13847a3e43e5..d3825c8ee994 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -209,6 +209,7 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) struct resource *res; int err = 0; int i; + DECLARE_MAC_BUF(mac); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -233,13 +234,8 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) if (err) goto out1; - printk("%s: MAC ", dev->name); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk(" IRQ %d\n", dev->irq); + printk("%s: MAC %s IRQ %d\n", + dev->name, print_mac(mac, dev->dev_addr), dev->irq); return 0; diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 7b17212d687e..977ed3401bb3 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -466,6 +466,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int unsigned long flags; int err = -ENOMEM; void __iomem *bios; + DECLARE_MAC_BUF(mac); /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. @@ -522,12 +523,13 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int /* We can't allocate dev->priv from alloc_etherdev() because it must a ISA DMA-able region. */ chipname = chip_table[lance_version].name; - printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); + printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr); /* There is a 16 byte station address PROM at the base address. The first six bytes are the station address. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + dev->dev_addr[i] = inb(ioaddr + i); + printk("%s", print_mac(mac, dev->dev_addr)); dev->base_addr = ioaddr; /* Make certain the data structures used by the LANCE are aligned and DMAble. */ diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c index 7f34c92bcd86..abce2ee8430a 100644 --- a/drivers/net/lguest_net.c +++ b/drivers/net/lguest_net.c @@ -235,9 +235,9 @@ static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev) struct lguestnet_info *info = netdev_priv(dev); /* Extract the destination ethernet address from the packet. */ const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; + DECLARE_MAC_BUF(mac); - pr_debug("%s: xmit %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, dest[0],dest[1],dest[2],dest[3],dest[4],dest[5]); + pr_debug("%s: xmit %s\n", dev->name, print_mac(mac, dest)); /* If it's a multicast packet, we broadcast to everyone. That's not * very efficient, but there are very few applications which actually diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index afa4638052a2..ffaa14f2cd01 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1034,15 +1034,12 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) static void print_eth(unsigned char *add, char *str) { - int i; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); - printk(KERN_DEBUG "i596 0x%p, ", add); - for (i = 0; i < 6; i++) - printk(" %02X", add[i + 6]); - printk(" -->"); - for (i = 0; i < 6; i++) - printk(" %02X", add[i]); - printk(" %02X%02X, %s\n", add[12], add[13], str); + printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n", + add, print_mac(mac, add + 6), print_mac(mac2, add), + add[12], add[13], str); } static int __devinit i82596_probe(struct net_device *dev) @@ -1352,6 +1349,7 @@ static void set_multicast_list(struct net_device *dev) struct i596_private *lp = netdev_priv(dev); struct i596_dma *dma = lp->dma; int config = 0, cnt; + DECLARE_MAC_BUF(mac); DEB(DEB_MULTI, printk(KERN_DEBUG @@ -1415,8 +1413,8 @@ static void set_multicast_list(struct net_device *dev) if (i596_debug > 1) DEB(DEB_MULTI, printk(KERN_DEBUG - "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5])); + "%s: Adding address %s\n", + dev->name, print_mac(mac, cp))); } DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd)); i596_add_cmd(dev, &cmd->cmd); diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 2dd396983213..b36989097883 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -169,6 +169,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) { int i, revision, ret; unsigned long eisa_id; + DECLARE_MAC_BUF(mac); if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV; @@ -200,10 +201,12 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) } #endif - printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000); for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i))); - printk(".\nlne390.c: "); + dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i); + printk("lne390.c: LNE390%X in EISA slot %d, address %s.\n", + 0xa+revision, ioaddr/0x1000, print_mac(mac, dev->dev_addr)); + + printk("lne390.c: "); /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */ if (dev->irq == 0) { diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index f6f3fdfe41db..30854f094965 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -181,6 +181,7 @@ struct net_device * __init mac89x0_probe(int unit) unsigned long ioaddr; unsigned short sig; int err = -ENODEV; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) @@ -272,13 +273,11 @@ struct net_device * __init mac89x0_probe(int unit) } dev->irq = SLOT2IRQ(slot); - printk(" IRQ %d ADDR ", dev->irq); - /* print the ethernet address. */ - for (i = 0; i < ETH_ALEN; i++) - printk("%2.2x%s", dev->dev_addr[i], - ((i < ETH_ALEN-1) ? ":" : "")); - printk("\n"); + /* print the IRQ and ethernet address. */ + + printk(" IRQ %d ADDR %s\n", + dev->irq, print_mac(mac, dev->dev_addr)); dev->open = net_open; dev->stop = net_close; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index c6707580c305..047ea7be4850 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1071,6 +1071,7 @@ static int __devinit macb_probe(struct platform_device *pdev) unsigned long pclk_hz; u32 config; int err = -ENXIO; + DECLARE_MAC_BUF(mac); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { @@ -1190,10 +1191,9 @@ static int __devinit macb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d " - "(%02x:%02x:%02x:%02x:%02x:%02x)\n", + "(%s)\n", dev->name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + print_mac(mac, dev->dev_addr)); phydev = bp->phy_dev; printk(KERN_INFO "%s: attached PHY driver [%s] " diff --git a/drivers/net/mace.c b/drivers/net/mace.c index ee132b1e09b0..95ebe72f320f 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -101,6 +101,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i struct mace_data *mp; const unsigned char *addr; int j, rev, rc = -EBUSY; + DECLARE_MAC_BUF(mac); if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n", @@ -240,11 +241,9 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i goto err_free_rx_irq; } - printk(KERN_INFO "%s: MACE at", dev->name); - for (j = 0; j < 6; ++j) { - printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); - } - printk(", chip revision %d.%d\n", mp->chipid >> 8, mp->chipid & 0xff); + printk(KERN_INFO "%s: MACE at %s, chip revision %d.%d\n", + dev->name, print_mac(mac, dev->dev_addr), + mp->chipid >> 8, mp->chipid & 0xff); return 0; diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 57f7c1a2c1d7..6589239b79ee 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -194,6 +194,7 @@ static int __devinit mace_probe(struct platform_device *pdev) unsigned char checksum = 0; static int found = 0; int err; + DECLARE_MAC_BUF(mac); if (found || macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; @@ -248,9 +249,8 @@ static int __devinit mace_probe(struct platform_device *pdev) dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]); - for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]); - printk("\n"); + printk(KERN_INFO "%s: 68K MACE, hardware address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); err = register_netdev(dev); if (!err) diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index a55a8399344c..b267161418ea 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -223,6 +223,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; int i; + DECLARE_MAC_BUF(mac); /* On NuBus boards we can sometimes look in the ROM resources. No such luck for comm-slot/onboard. */ @@ -266,13 +267,8 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; - printk(KERN_INFO "HW Address from CAM 15: "); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); + printk(KERN_INFO "HW Address from CAM 15: %s\n", + print_mac(mac, dev->dev_addr)); } else return 0; if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && @@ -567,7 +563,7 @@ static int __init mac_sonic_probe(struct platform_device *pdev) struct net_device *dev; struct sonic_local *lp; int err; - int i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct sonic_local)); if (!dev) @@ -591,13 +587,8 @@ found: if (err) goto out; - printk("%s: MAC ", dev->name); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk(" IRQ %d\n", dev->irq); + printk("%s: MAC %s IRQ %d\n", + dev->name, print_mac(mac, dev->dev_addr), dev->irq); return 0; diff --git a/drivers/net/meth.c b/drivers/net/meth.c index fe5b6c372072..e25dbab67363 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -95,11 +95,11 @@ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0}; static inline void load_eaddr(struct net_device *dev) { int i; - DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - (int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF, - (int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF); + DECLARE_MAC_BUF(mac); + for (i = 0; i < 6; i++) dev->dev_addr[i] = o2meth_eaddr[i]; + DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr)); mace->eth.mac_addr = (*(unsigned long*)o2meth_eaddr) >> 16; } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 34df02cfdbe7..e379165d8375 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -784,6 +784,7 @@ static int mv643xx_eth_open(struct net_device *dev) unsigned int port_num = mp->port_num; unsigned int size; int err; + DECLARE_MAC_BUF(mac); /* Clear any pending ethernet port interrupts */ mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); @@ -1413,8 +1414,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) p = dev->dev_addr; printk(KERN_NOTICE - "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, port_num, p[0], p[1], p[2], p[3], p[4], p[5]); + "%s: port %d with MAC address %s\n", + dev->name, port_num, print_mac(mac, p)); if (dev->features & NETIF_F_SG) printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name); diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 837ad0f2b05d..86c9c06433cb 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -67,6 +67,7 @@ struct net_device * __init mvme147lance_probe(int unit) u_long *addr; u_long address; int err; + DECLARE_MAC_BUF(mac); if (!MACH_IS_MVME147 || called) return ERR_PTR(-ENODEV); @@ -101,12 +102,10 @@ struct net_device * __init mvme147lance_probe(int unit) address=address>>8; dev->dev_addr[3]=address&0xff; - printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, dev->base_addr, MVME147_LANCE_IRQ, - dev->dev_addr[0], - dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); + printk("%s: MVME147 at 0x%08lx, irq %d, " + "Hardware Address %s\n", + dev->name, dev->base_addr, MVME147_LANCE_IRQ, + print_mac(mac, dev->dev_addr)); lp = (struct m147lance_private *)dev->priv; lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */ diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 2f8864e70ca9..38b03f538e95 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2395,6 +2395,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) struct dev_mc_list *mc_list; __be32 data[2] = { 0, 0 }; int err; + DECLARE_MAC_BUF(mac); mgp = netdev_priv(dev); /* can be called from atomic contexts, @@ -2442,14 +2443,8 @@ static void myri10ge_set_multicast_list(struct net_device *dev) printk(KERN_ERR "myri10ge: %s: Failed " "MXGEFW_JOIN_MULTICAST_GROUP, error status:" "%d\t", dev->name, err); - printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ((unsigned char *)&mc_list->dmi_addr)[0], - ((unsigned char *)&mc_list->dmi_addr)[1], - ((unsigned char *)&mc_list->dmi_addr)[2], - ((unsigned char *)&mc_list->dmi_addr)[3], - ((unsigned char *)&mc_list->dmi_addr)[4], - ((unsigned char *)&mc_list->dmi_addr)[5] - ); + printk(KERN_ERR "MAC %s\n", + print_mac(mac, mc_list->dmi_addr)); goto abort; } } diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 35c4c598c8d2..d68ee51c095f 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -311,12 +311,12 @@ static void myri_is_not_so_happy(struct myri_eth *mp) #ifdef DEBUG_HEADER static void dump_ehdr(struct ethhdr *ehdr) { - printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)" - "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n", - ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2], - ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4], - ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2], - ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4], + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + printk("ehdr[h_dst(%s)" + "h_source(%s)" + "h_proto(%04x)]\n", + print_mac(mac, ehdr->h_dest), print_mac(mac2, ehdr->h_source), ehdr->h_proto); } @@ -325,13 +325,7 @@ static void dump_ehdr_and_myripad(unsigned char *stuff) struct ethhdr *ehdr = (struct ethhdr *) (stuff + 2); printk("pad[%02x:%02x]", stuff[0], stuff[1]); - printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)" - "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n", - ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2], - ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4], - ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2], - ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4], - ehdr->h_proto); + dump_ehdr(ehdr); } #endif @@ -895,6 +889,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) struct myri_eth *mp; unsigned char prop_buf[32]; int i; + DECLARE_MAC_BUF(mac); DET(("myri_ether_init(%p,%d):\n", sdev, num)); dev = alloc_etherdev(sizeof(struct myri_eth)); @@ -1089,12 +1084,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) num++; - printk("%s: MyriCOM MyriNET Ethernet ", dev->name); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ' : ':'); - printk("\n"); + printk("%s: MyriCOM MyriNET Ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 5ee4e8795d23..ea38da6d31ff 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -805,6 +805,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, const int pcibar = 1; /* PCI base address register */ int prev_eedata; u32 tmp; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -958,12 +959,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, goto err_create_file; if (netif_msg_drv(np)) { - printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", - dev->name, natsemi_pci_info[chip_idx].name, iostart, - pci_name(np->pci_dev)); - for (i = 0; i < ETH_ALEN-1; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x, IRQ %d", dev->dev_addr[i], irq); + printk(KERN_INFO "natsemi %s: %s at %#08lx " + "(%s), %s, IRQ %d", + dev->name, natsemi_pci_info[chip_idx].name, iostart, + pci_name(np->pci_dev), print_mac(mac, dev->dev_addr), irq); if (dev->if_port == PORT_TP) printk(", port TP.\n"); else if (np->ignore_phy) diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 2b85d1b53344..368f2560856d 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -204,6 +204,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) static unsigned version_printed; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char bus_width; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -296,12 +297,11 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; - for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); + for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - } + printk(" %s\n", print_mac(mac, dev->dev_addr)); - printk("\n%s: %s found at %#x, using IRQ %d.\n", + printk("%s: %s found at %#x, using IRQ %d.\n", dev->name, name, ioaddr, dev->irq); ei_status.name = name; diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 27d87985bb63..874d291cbaed 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -291,6 +291,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) int neX000, ctron, copam, bad_card; int reg0, ret; static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -503,16 +504,14 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) for (i = 0 ; i < ETHER_ADDR_LEN ; i++) { dev->dev_addr[i] = SA_prom[i] = inb_p(ioaddr + EN1_PHYS_SHIFT(i)); - printk(" %2.2x", SA_prom[i]); } #else for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; } #endif - printk("\n"); + printk("%s\n", print_mac(mac, dev->dev_addr)); ei_status.name = name; ei_status.tx_start_page = start_page; diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index f73073b1218a..f4cd8c7e81ba 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -302,6 +302,7 @@ out: static int ne2_procinfo(char *buf, int slot, struct net_device *dev) { int len=0; + DECLARE_MAC_BUF(mac); len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" ); len += sprintf(buf+len, "Driver written by Wim Dumon "); @@ -312,12 +313,7 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev) len += sprintf(buf+len, "Based on the original NE2000 drivers\n" ); len += sprintf(buf+len, "Base IO: %#x\n", (unsigned int)dev->base_addr); len += sprintf(buf+len, "IRQ : %d\n", dev->irq); - -#define HW_ADDR(i) dev->dev_addr[i] - len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n", - HW_ADDR(0), HW_ADDR(1), HW_ADDR(2), - HW_ADDR(3), HW_ADDR(4), HW_ADDR(5) ); -#undef HW_ADDR + len += sprintf(buf+len, "HW addr : %s\n", print_mac(mac, dev->dev_addr)); return len; } @@ -330,6 +326,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) const char *name = "NE/2"; int start_page, stop_page; static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (ei_debug && version_printed++ == 0) printk(version); @@ -469,12 +466,12 @@ static int __init ne2_probe1(struct net_device *dev, int slot) dev->base_addr = base_addr; - for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); + for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - } - printk("\n%s: %s found at %#x, using IRQ %d.\n", + printk(" %s\n", print_mac(mac, dev->dev_addr)); + + printk("%s: %s found at %#x, using IRQ %d.\n", dev->name, name, base_addr, dev->irq); mca_set_adapter_procfn(slot, (MCA_ProcFn) ne2_procinfo, dev); diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index a5879672903e..b569c90da4ba 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -212,6 +212,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, static unsigned int fnd_cnt; long ioaddr; int flags = pci_clone_list[chip_idx].flags; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -365,12 +366,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, if (i) goto err_out_free_netdev; - printk("%s: %s found at %#lx, IRQ %d, ", - dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); - for(i = 0; i < 6; i++) { - printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); + for(i = 0; i < 6; i++) dev->dev_addr[i] = SA_prom[i]; - } + printk("%s: %s found at %#lx, IRQ %d, %s.\n", + dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq, + print_mac(mac, dev->dev_addr)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); return 0; diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index b1bf8331e872..425043a88db9 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -99,6 +99,7 @@ static int __init ne3210_eisa_probe (struct device *device) int i, retval, port_index; struct eisa_device *edev = to_eisa_device (device); struct net_device *dev; + DECLARE_MAC_BUF(mac); /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (!(dev = alloc_ei_netdev ())) { @@ -127,17 +128,15 @@ static int __init ne3210_eisa_probe (struct device *device) inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2)); #endif - port_index = inb(ioaddr + NE3210_CFG2) >> 6; - printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr:", - edev->slot, ifmap[port_index]); for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i))); - + dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i); + printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %s.\n", + edev->slot, ifmap[port_index], print_mac(mac, dev->dev_addr)); /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */ dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07]; - printk(".\nne3210.c: using IRQ %d, ", dev->irq); + printk("ne3210.c: using IRQ %d, ", dev->irq); retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev); if (retval) { diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 69ef1eb03bea..5ffbb8891647 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -306,18 +306,16 @@ static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) { - return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", - nt->np.local_mac[0], nt->np.local_mac[1], - nt->np.local_mac[2], nt->np.local_mac[3], - nt->np.local_mac[4], nt->np.local_mac[5]); + DECLARE_MAC_BUF(mac); + return snprintf(buf, PAGE_SIZE, "%s\n", + print_mac(mac, nt->np.local_mac)); } static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) { - return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", - nt->np.remote_mac[0], nt->np.remote_mac[1], - nt->np.remote_mac[2], nt->np.remote_mac[3], - nt->np.remote_mac[4], nt->np.remote_mac[5]); + DECLARE_MAC_BUF(mac); + return snprintf(buf, PAGE_SIZE, "%s\n", + print_mac(mac, nt->np.remote_mac)); } /* diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1b165a8c74f3..b9cde65e7f31 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -285,6 +285,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int valid_mac = 0; u32 val; int pci_func_id = PCI_FUNC(pdev->devfn); + DECLARE_MAC_BUF(mac); printk(KERN_INFO "%s \n", netxen_nic_driver_string); @@ -573,15 +574,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); if (!is_valid_ether_addr(netdev->perm_addr)) { - printk(KERN_ERR "%s: Bad MAC address " - "%02x:%02x:%02x:%02x:%02x:%02x.\n", - netxen_nic_driver_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]); + printk(KERN_ERR "%s: Bad MAC address %s.\n", + netxen_nic_driver_name, + print_mac(mac, netdev->dev_addr)); } else { if (adapter->macaddr_set) adapter->macaddr_set(adapter, diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 05e0577a0e10..5b9e1b300fab 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -603,6 +603,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, int phy = physical_port[adapter->portnum]; unsigned char mac_addr[6]; int i; + DECLARE_MAC_BUF(mac); for (i = 0; i < 10; i++) { temp[0] = temp[1] = 0; @@ -627,15 +628,10 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, if (i == 10) { printk(KERN_ERR "%s: cannot set Mac addr for %s\n", netxen_nic_driver_name, adapter->netdev->name); - printk(KERN_ERR "MAC address set: " - "%02x:%02x:%02x:%02x:%02x:%02x.\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - - printk(KERN_ERR "MAC address get: " - "%02x:%02x:%02x:%02x:%02x:%02x.\n", - mac_addr[0], - mac_addr[1], - mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + printk(KERN_ERR "MAC address set: %s.\n", + print_mac(mac, addr)); + printk(KERN_ERR "MAC address get: %s.\n", + print_mac(mac, mac_addr)); } return 0; } diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 1dc74a78afa6..14a768fbce2e 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -203,6 +203,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) unsigned int data = 0; int boguscount = 40; int err = -ENODEV; + DECLARE_MAC_BUF(mac); dev->base_addr = ioaddr; dev->irq = irq; @@ -268,8 +269,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) for (i=0; i<6; i++) { outw(i, IE_GP); - printk("%2.2x ", dev->dev_addr[i] = inb(IE_SAPROM)); + dev->dev_addr[i] = inb(IE_SAPROM); } + printk("%s ", print_mac(mac, dev->dev_addr)); PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name)); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index de495b697294..ea71f6d82661 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1962,6 +1962,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ long addr; int err; int using_dac = 0; + DECLARE_MAC_BUF(mac); /* See if we can set the dma mask early on; failure is fatal. */ if (sizeof(dma_addr_t) == 8 && @@ -2226,13 +2227,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ndev->features |= NETIF_F_HIGHDMA; } - printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n", + printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n", ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, - ndev->dev_addr[0], ndev->dev_addr[1], - ndev->dev_addr[2], ndev->dev_addr[3], - ndev->dev_addr[4], ndev->dev_addr[5], + print_mac(mac, ndev->dev_addr), addr, pci_dev->irq, (ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" ); diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index f310d94443a0..4d87cd65626f 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1155,6 +1155,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *dev; struct pasemi_mac *mac; int err; + DECLARE_MAC_BUF(mac_buf); err = pci_enable_device(pdev); if (err) @@ -1237,11 +1238,10 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out; } else printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, " - "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n", + "hw addr %s\n", dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI", mac->dma_if, mac->dma_txch, mac->dma_rxch, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + print_mac(mac_buf, dev->dev_addr)); return err; diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 7dace63fb6e6..ed402e00e730 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -737,6 +737,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -796,15 +797,11 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, tp->phys[0] = 32; - printk (KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "IRQ %d\n", + printk (KERN_INFO "%s: %s at 0x%lx, %sIRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + print_mac(mac, dev->dev_addr), dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 2b395ee21f75..73dcbb7296da 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -343,6 +343,7 @@ static int tc574_config(struct pcmcia_device *link) u16 *phys_addr; char *cardname; union wn3_config config; + DECLARE_MAC_BUF(mac); phys_addr = (u16 *)dev->dev_addr; @@ -458,10 +459,10 @@ static int tc574_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); - printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ", - dev->name, cardname, dev->base_addr, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n")); + printk(KERN_INFO "%s: %s at io %#3lx, irq %d, " + "hw_addr %s.\n", + dev->name, cardname, dev->base_addr, dev->irq, + print_mac(mac, dev->dev_addr)); printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n", 8 << config.u.ram_size, ram_split[config.u.ram_split], config.u.autoselect ? "autoselect " : ""); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 2136c80c0581..32076ca6a9e1 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -255,6 +255,7 @@ static int tc589_config(struct pcmcia_device *link) int last_fn, last_ret, i, j, multi = 0, fifo; kio_addr_t ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + DECLARE_MAC_BUF(mac); DEBUG(0, "3c589_config(0x%p)\n", link); @@ -330,11 +331,10 @@ static int tc589_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); - printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ", - dev->name, (multi ? "562" : "589"), dev->base_addr, - dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, " + "hw_addr %s\n", + dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq, + print_mac(mac, dev->dev_addr)); printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n", (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], if_names[dev->if_port]); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 28eea206766d..de59313d10f5 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -292,6 +292,7 @@ static int axnet_config(struct pcmcia_device *link) cisparse_t parse; int i, j, last_ret, last_fn; u_short buf[64]; + DECLARE_MAC_BUF(mac); DEBUG(0, "axnet_config(0x%p)\n", link); @@ -403,11 +404,11 @@ static int axnet_config(struct pcmcia_device *link) strcpy(info->node.dev_name, dev->name); - printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ", + printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, " + "hw_addr %s\n", dev->name, ((info->flags & IS_AX88790) ? 7 : 1), - dev->base_addr, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + dev->base_addr, dev->irq, + print_mac(mac, dev->dev_addr)); if (info->phy_id != -1) { DEBUG(0, " MII transceiver at index %d, status %x.\n", info->phy_id, j); } else { diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 7f29e95a0644..62844677c784 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -346,6 +346,7 @@ static int fmvj18x_config(struct pcmcia_device *link) cardtype_t cardtype; char *card_name = "unknown"; u_char *node_id; + DECLARE_MAC_BUF(mac); DEBUG(0, "fmvj18x_config(0x%p)\n", link); @@ -533,11 +534,10 @@ static int fmvj18x_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); /* print current configuration */ - printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", + printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, " + "hw_addr %s\n", dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", - dev->base_addr, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 1bb2ffa294de..a355a93b908b 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -658,6 +658,7 @@ static int nmclan_config(struct pcmcia_device *link) u_char buf[64]; int i, last_ret, last_fn; kio_addr_t ioaddr; + DECLARE_MAC_BUF(mac); DEBUG(0, "nmclan_config(0x%p)\n", link); @@ -716,10 +717,10 @@ static int nmclan_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); - printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ", - dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port," + " hw_addr %s\n", + dev->name, dev->base_addr, dev->irq, if_names[dev->if_port], + print_mac(mac, dev->dev_addr)); return 0; cs_failed: diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 8ce251cd3209..6a647516c380 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -38,7 +38,7 @@ #include #include #include -#include <../drivers/net/8390.h> +#include "../8390.h" #include #include @@ -521,6 +521,7 @@ static int pcnet_config(struct pcmcia_device *link) int has_shmem = 0; u_short buf[64]; hw_info_t *hw_info; + DECLARE_MAC_BUF(mac); DEBUG(0, "pcnet_config(0x%p)\n", link); @@ -670,9 +671,7 @@ static int pcnet_config(struct pcmcia_device *link) printk (" mem %#5lx,", dev->mem_start); if (info->flags & HAS_MISC_REG) printk(" %s xcvr,", if_names[dev->if_port]); - printk(" hw_addr "); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(" hw_addr %s\n", print_mac(mac, dev->dev_addr)); return 0; cs_failed: diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index b25f1985d03e..58d716fd17cf 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -962,6 +962,7 @@ static int smc91c92_config(struct pcmcia_device *link) int i, j, rev; kio_addr_t ioaddr; u_long mir; + DECLARE_MAC_BUF(mac); DEBUG(0, "smc91c92_config(0x%p)\n", link); @@ -1074,10 +1075,9 @@ static int smc91c92_config(struct pcmcia_device *link) strcpy(smc->node.dev_name, dev->name); printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, " - "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr, - dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + "hw_addr %s\n", + dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq, + print_mac(mac, dev->dev_addr)); if (rev > 0) { if (mir & 0x3ff) diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index d5c2d2c8c852..c3b69602e275 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -731,6 +731,7 @@ xirc2ps_config(struct pcmcia_device * link) u_char buf[64]; cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; cistpl_cftable_entry_t *cf = &parse.cftable_entry; + DECLARE_MAC_BUF(mac); local->dingo_ccr = NULL; @@ -1032,11 +1033,9 @@ xirc2ps_config(struct pcmcia_device * link) strcpy(local->node.dev_name, dev->name); /* give some infos about the hardware */ - printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr", - dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq); - for (i = 0; i < 6; i++) - printk("%c%02X", i?':':' ', dev->dev_addr[i]); - printk("\n"); + printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %s\n", + dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq, + print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 2f130e06b6dc..ba2eb04aac9f 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -955,6 +955,7 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) { struct pppox_sock *po; char *dev_name; + DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) { seq_puts(seq, "Id Address Device\n"); @@ -964,11 +965,8 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) po = v; dev_name = po->pppoe_pa.dev; - seq_printf(seq, "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n", - po->pppoe_pa.sid, - po->pppoe_pa.remote[0], po->pppoe_pa.remote[1], - po->pppoe_pa.remote[2], po->pppoe_pa.remote[3], - po->pppoe_pa.remote[4], po->pppoe_pa.remote[5], dev_name); + seq_printf(seq, "%08X %s %8s\n", + po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name); out: return 0; } diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index f375bbbd6604..0a42bf517465 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1348,6 +1348,7 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) unsigned int i; int status; u64 v1, v2; + DECLARE_MAC_BUF(mac); SET_NETDEV_DEV(netdev, &card->dev->core); spin_lock_init(&card->tx_dma_lock); @@ -1373,10 +1374,8 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) v1 <<= 16; memcpy(addr.sa_data, &v1, ETH_ALEN); memcpy(netdev->dev_addr, addr.sa_data, ETH_ALEN); - dev_info(ctodev(card), "MAC addr %02x:%02x:%02x:%02x:%02x:%02x\n", - netdev->dev_addr[0], netdev->dev_addr[1], - netdev->dev_addr[2], netdev->dev_addr[3], - netdev->dev_addr[4], netdev->dev_addr[5]); + dev_info(ctodev(card), "MAC addr %s\n", + print_mac(mac, netdev->dev_addr)); card->vlan_index = -1; /* no vlan */ for (i = 0; i < GELIC_NET_VLAN_MAX; i++) { diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 97c6ed07dd15..ed79aa820df2 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -3557,6 +3557,7 @@ static void ql_display_dev_info(struct net_device *ndev) { struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); struct pci_dev *pdev = qdev->pdev; + DECLARE_MAC_BUF(mac); printk(KERN_INFO PFX "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n", @@ -3582,10 +3583,8 @@ static void ql_display_dev_info(struct net_device *ndev) if (netif_msg_probe(qdev)) printk(KERN_INFO PFX - "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, ndev->dev_addr[0], ndev->dev_addr[1], - ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], - ndev->dev_addr[5]); + "%s: MAC address %s\n", + ndev->name, print_mac(mac, ndev->dev_addr)); } static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset) diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index d43dcf3ed5a9..e7fd08adbbac 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -432,6 +432,7 @@ static int rionet_setup_netdev(struct rio_mport *mport) struct net_device *ndev = NULL; struct rionet_private *rnet; u16 device_id; + DECLARE_MAC_BUF(mac); /* Allocate our net_device structure */ ndev = alloc_etherdev(sizeof(struct rionet_private)); @@ -472,13 +473,12 @@ static int rionet_setup_netdev(struct rio_mport *mport) if (rc != 0) goto out; - printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + printk("%s: %s %s Version %s, MAC %s\n", ndev->name, DRV_NAME, DRV_DESC, DRV_VERSION, - ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], - ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + print_mac(mac, ndev->dev_addr)); out: return rc; diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 03facba05259..19152f54ef2b 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -520,7 +520,7 @@ static int __devinit rr_init(struct net_device *dev) struct rr_regs __iomem *regs; struct eeprom *hw = NULL; u32 sram_size, rev; - int i; + DECLARE_MAC_BUF(mac); rrpriv = netdev_priv(dev); regs = rrpriv->regs; @@ -558,11 +558,7 @@ static int __devinit rr_init(struct net_device *dev) *(u32 *)(dev->dev_addr+2) = htonl(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA[4])); - printk(" MAC: "); - - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x\n", dev->dev_addr[i]); + printk(" MAC: %s\n", print_mac(mac, dev->dev_addr)); sram_size = rr_read_eeprom_word(rrpriv, (void *)8); printk(" SRAM size 0x%06x\n", sram_size); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index a285dd734a03..26895de3e264 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -7417,6 +7417,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) struct config_param *config; int mode; u8 dev_intr_type = intr_type; + DECLARE_MAC_BUF(mac); if ((ret = s2io_verify_parm(pdev, &dev_intr_type))) return ret; @@ -7720,14 +7721,8 @@ 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: " - "%02x:%02x:%02x:%02x:%02x:%02x", dev->name, - sp->def_mac_addr[0].mac_addr[0], - sp->def_mac_addr[0].mac_addr[1], - sp->def_mac_addr[0].mac_addr[2], - sp->def_mac_addr[0].mac_addr[3], - sp->def_mac_addr[0].mac_addr[4], - sp->def_mac_addr[0].mac_addr[5]); + DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n", + dev->name, print_mac(mac, 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); diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 76e7ee9a6cbc..6001ab47fba0 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2407,6 +2407,7 @@ static int sbmac_init(struct net_device *dev, int idx) uint64_t ea_reg; int i; int err; + DECLARE_MAC_BUF(mac); sc = netdev_priv(dev); @@ -2487,10 +2488,8 @@ static int sbmac_init(struct net_device *dev, int idx) * was being displayed) */ printk(KERN_INFO - "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->name, dev->base_addr, - eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); - + "%s: SiByte Ethernet at 0x%08lX, address: %s\n", + dev->name, dev->base_addr, print_mac(mac, eaddr)); return 0; diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 8ef94028cba5..48c64fb20eec 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -158,6 +158,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) int old_dmaar; int old_rear; int retval; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005")) return -ENODEV; @@ -301,7 +302,8 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = SA_prom[i+6]); + dev->dev_addr[i] = SA_prom[i+6]; + printk("%s", print_mac(mac, dev->dev_addr)); if (dev->irq == 0xff) ; /* Do nothing: a user-level program will set it. */ diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 5189ef066884..ff4056310356 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -622,6 +622,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev) struct sgiseeq_private *sp; struct net_device *dev; int err, i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof (struct sgiseeq_private)); if (!dev) { @@ -695,9 +696,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev) goto err_out_free_page; } - printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + printk(KERN_INFO "%s: %s %s\n", + dev->name, sgiseeqstr, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 808141b46585..720088396bb9 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1759,6 +1759,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, struct net_device *dev; void __iomem *ioaddr; int rc; + DECLARE_MAC_BUF(mac); if (!printed_version) { net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n"); @@ -1809,12 +1810,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, goto err_remove_mii; net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", - pci_name(pdev), sis_chip_info[ent->driver_data].name, - ioaddr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + "%s\n", + pci_name(pdev), sis_chip_info[ent->driver_data].name, + ioaddr, dev->irq, print_mac(mac, dev->dev_addr)); net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name, (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII"); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 5da8e671324d..0857d2c88aa0 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -404,6 +404,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, int i, ret; const char *card_name = card_names[pci_id->driver_data]; const char *dev_name = pci_name(pci_dev); + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -533,11 +534,9 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, goto err_unmap_rx; /* print some information about our NIC */ - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, - card_name, ioaddr, net_dev->irq); - for (i = 0; i < 5; i++) - printk("%2.2x:", (u8)net_dev->dev_addr[i]); - printk("%2.2x.\n", net_dev->dev_addr[i]); + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n", + net_dev->name, card_name, ioaddr, net_dev->irq, + print_mac(mac, net_dev->dev_addr)); /* Detect Wake on Lan support */ ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index cac499f84131..ec1acfddf350 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3616,12 +3616,11 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, static void __devinit skge_show_addr(struct net_device *dev) { const struct skge_port *skge = netdev_priv(dev); + DECLARE_MAC_BUF(mac); if (netif_msg_probe(skge)) - printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\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]); + printk(KERN_INFO PFX "%s: addr %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } static int __devinit skge_probe(struct pci_dev *pdev, diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b8c15f881eba..a70bcbcf8a16 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3984,12 +3984,11 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, static void __devinit sky2_show_addr(struct net_device *dev) { const struct sky2_port *sky2 = netdev_priv(dev); + DECLARE_MAC_BUF(mac); if (netif_msg_probe(sky2)) - printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\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]); + printk(KERN_INFO PFX "%s: addr %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } /* Handle software interrupt used during MSI test */ diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 3b43fa8fd088..d6abb68e6e2f 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -196,6 +196,7 @@ static int __init ultramca_probe(struct device *gen_dev) int tirq = 0; int base_addr = ultra_io[ultra_found]; int irq = ultra_irq[ultra_found]; + DECLARE_MAC_BUF(mac); if (base_addr || irq) { printk(KERN_INFO "Probing for SMC MCA adapter"); @@ -330,10 +331,11 @@ static int __init ultramca_probe(struct device *gen_dev) reg4 = inb(ioaddr + 4) & 0x7f; outb(reg4, ioaddr + 4); - printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x,", slot + 1, ioaddr); - for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + dev->dev_addr[i] = inb(ioaddr + 8 + i); + + printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %s", + slot + 1, ioaddr, print_mac(mac, dev->dev_addr)); /* Switch from the station address to the alternate register set * and read the useful registers there. diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index d02bd7bc1bae..00d6cf1af484 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -198,6 +198,7 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) unsigned char num_pages, irqreg, addr, piomode; unsigned char idreg = inb(ioaddr + 7); unsigned char reg4 = inb(ioaddr + 4) & 0x7f; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -224,10 +225,11 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ"; - printk("%s: %s at %#3x,", dev->name, model_name, ioaddr); - for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + dev->dev_addr[i] = inb(ioaddr + 8 + i); + + printk("%s: %s at %#3x, %s", dev->name, model_name, + ioaddr, print_mac(mac, dev->dev_addr)); /* Switch from the station address to the alternate register set and read the useful registers there. */ diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index 043a5002029c..a5a91ace28cc 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -163,6 +163,7 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) unsigned char idreg; unsigned char reg4; const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"}; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -203,10 +204,11 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) model_name = "SMC Ultra32"; - printk("%s: %s at 0x%X,", dev->name, model_name, ioaddr); - for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + dev->dev_addr[i] = inb(ioaddr + 8 + i); + + printk("%s: %s at 0x%X, %s", + dev->name, model_name, ioaddr, print_mac(mac, dev->dev_addr)); /* Switch from the station address to the alternate register set and read the useful registers there. */ diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 5b6748e3ea0e..cb2698de5190 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -876,6 +876,8 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) word memory_info_register; word memory_cfg_register; + DECLARE_MAC_BUF(mac); + /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -1031,10 +1033,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) /* . Print the Ethernet address */ - printk("ADDR: "); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i] ); - printk("%2.2x \n", dev->dev_addr[5] ); + printk("ADDR: %s\n", print_mac(mac, dev->dev_addr)); /* set the private data to zero by default */ memset(dev->priv, 0, sizeof(struct smc_local)); diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index fe28d277f21a..24e610e711e8 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1822,9 +1822,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) { struct smc_local *lp = netdev_priv(dev); static int version_printed = 0; - int i, retval; + int retval; unsigned int val, revision_register; const char *version_string; + DECLARE_MAC_BUF(mac); DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); @@ -2014,10 +2015,8 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) "set using ifconfig\n", dev->name); } else { /* Print the Ethernet address */ - printk("%s: Ethernet addr: ", dev->name); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x\n", dev->dev_addr[5]); + printk("%s: Ethernet addr: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } if (lp->phy_type == 0) { diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 5785429ca0e2..ea253754763a 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -694,6 +694,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, void __iomem *base; int drv_flags, io_size; int boguscnt; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -863,11 +864,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, if (register_netdev(dev)) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, netdrv_tbl[chip_idx].name, base); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, netdrv_tbl[chip_idx].name, base, + print_mac(mac, dev->dev_addr), irq); if (drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -1472,13 +1471,16 @@ static int __netdev_rx(struct net_device *dev, int *quota) } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ - if (debug > 5) - printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" - "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x.\n", - skb->data[0], skb->data[1], skb->data[2], skb->data[3], - skb->data[4], skb->data[5], skb->data[6], skb->data[7], - skb->data[8], skb->data[9], skb->data[10], - skb->data[11], skb->data[12], skb->data[13]); + if (debug > 5) { + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + printk(KERN_DEBUG " Rx data %s %s" + " %2.2x%2.2x.\n", + print_mac(mac, &skb->data[0]), + print_mac(mac2, &skb->data[6]), + skb->data[12], skb->data[13]); + } #endif skb->protocol = eth_type_trans(skb, dev); diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index f8fbc0492706..f8d46134daca 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -300,6 +300,7 @@ static int __init lance_probe( struct net_device *dev) static int did_version; volatile unsigned short *ioaddr_probe; unsigned short tmp1, tmp2; + DECLARE_MAC_BUF(mac); #ifdef CONFIG_SUN3 ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); @@ -375,8 +376,7 @@ static int __init lance_probe( struct net_device *dev) MEM->init.hwaddr[4] = dev->dev_addr[5]; MEM->init.hwaddr[5] = dev->dev_addr[4]; - for( i = 0; i < 6; ++i ) - printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" ); + printk("%s\n", print_mac(mac, dev->dev_addr)); MEM->init.mode = 0x0000; MEM->init.filter[0] = 0x00000000; @@ -590,17 +590,12 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* Fill in a Tx ring entry */ #if 0 if (lance_debug >= 2) { - u_char *p; - int i; - printk( "%s: TX pkt %d type 0x%04x from ", dev->name, - lp->new_tx, ((u_short *)skb->data)[6]); - for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" to "); - for( p = (u_char *)skb->data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" data at 0x%08x len %d\n", (int)skb->data, - (int)skb->len ); + printk( "%s: TX pkt %d type 0x%04x" + " from %s to %s" + " data at 0x%08x len %d\n", + dev->name, lp->new_tx, ((u_short *)skb->data)[6], + DEV_ADDR(&skb->data[6]), DEV_ADDR(skb->data), + (int)skb->data, (int)skb->len ); } #endif /* We're not prepared for the int until the last flags are set/reset. @@ -825,13 +820,14 @@ static int lance_rx( struct net_device *dev ) #if 0 if (lance_debug >= 3) { - u_char *data = PKTBUF_ADDR(head), *p; - printk( "%s: RX pkt %d type 0x%04x from ", dev->name, entry, ((u_short *)data)[6]); - for( p = &data[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" to "); - for( p = data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); + u_char *data = PKTBUF_ADDR(head); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2) + printk("%s: RX pkt %d type 0x%04x" + " from %s to %s", + dev->name, lp->new_tx, ((u_short *)data)[6], + print_mac(mac, &data[6]), print_mac(mac2, data)); + printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d at %08x\n", data[15], data[16], data[17], data[18], diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 4ba3e4857e90..fe3ac6f9ae89 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1082,6 +1082,7 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) struct bigmac *bp; u8 bsizes, bsizes_more; int i; + DECLARE_MAC_BUF(mac); /* Get a new device struct for this interface. */ dev = alloc_etherdev(sizeof(struct bigmac)); @@ -1226,11 +1227,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp); - printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ' : ':'); - printk("\n"); + printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 3c553dcc2b9d..a37637ec9b77 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -467,7 +467,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, int bar = 1; #endif int phy, phy_idx = 0; - + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -546,11 +546,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, if (i) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, + print_mac(mac, dev->dev_addr), irq); np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 869ac44c51f3..53b8344a68ef 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2965,7 +2965,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev, unsigned long gemreg_base, gemreg_len; struct net_device *dev; struct gem *gp; - int i, err, pci_using_dac; + int err, pci_using_dac; + DECLARE_MAC_BUF(mac); if (gem_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -3149,12 +3150,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev, goto err_out_free_consistent; } - printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", - dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ' : ':'); - printk("\n"); + printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet " + "%s\n", + dev->name, print_mac(mac, dev->dev_addr)); if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 170580c13127..120c8affe83d 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2664,6 +2664,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe struct net_device *dev; int i, qfe_slot = -1; int err = -ENODEV; + DECLARE_MAC_BUF(mac); if (is_qfe) { qp = quattro_sbus_find(sdev); @@ -2850,10 +2851,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", - dev->dev_addr[i], i == 5 ? ' ' : ':'); - printk("\n"); + printk("%s\n", print_mac(mac, dev->dev_addr)); return 0; @@ -2988,6 +2986,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, int i, qfe_slot = -1; char prom_name[64]; int err; + DECLARE_MAC_BUF(mac); /* Now make sure pci_dev cookie is there. */ #ifdef CONFIG_SPARC @@ -3201,10 +3200,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':'); - - printk("\n"); + printk("%s\n", print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 7bf5c90b7749..26ade68aeabf 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1321,6 +1321,7 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, struct net_device *dev; struct lance_private *lp; int i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct lance_private) + 8); if (!dev) @@ -1478,12 +1479,8 @@ no_link_test: dev_set_drvdata(&sdev->ofdev.dev, lp); - printk(KERN_INFO "%s: LANCE ", dev->name); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ': ':'); - printk("\n"); + printk(KERN_INFO "%s: LANCE %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 22fad5112406..124cfd4fbcf4 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -97,8 +97,9 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ static int versionprinted; struct net_device *dev; struct net_local *tp; - int i, ret, pci_irq_line; + int ret, pci_irq_line; unsigned long pci_ioaddr; + DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -145,12 +146,9 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ } abyss_read_eeprom(dev); - - printk("%s: Ring Station Address: ", dev->name); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk("\n"); + + printk("%s: Ring Station Address: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); tp = netdev_priv(dev); tp->setnselout = abyss_setnselout_pins; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 65e21eb7e685..e494c63bfbd9 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -389,6 +389,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) unsigned long timeout; static int version_printed; #endif + DECLARE_MAC_BUF(mac); /* Query the adapter PIO base port which will return * indication of where MMIO was placed. We also have a @@ -702,9 +703,8 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) channel_def[cardpresent - 1], adapter_def(ti->adapter_type)); DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", irq, PIOaddr, ti->mapped_ram_size / 2); - DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + DPRINTK("Hardware address : %s\n", + print_mac(mac, dev->dev_addr)); if (ti->page_mask) DPRINTK("Shared RAM paging enabled. " "Page size: %uK Shared Ram size %dK\n", @@ -1739,18 +1739,20 @@ static void tr_rx(struct net_device *dev) if (!IPv4_p) { void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data); - + u8 saddr[6]; + u8 daddr[6]; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + int i; + for (i = 0 ; i < 6 ; i++) + saddr[i] = readb(trhhdr + SADDR_OFST + i); + for (i = 0 ; i < 6 ; i++) + daddr[i] = readb(trhhdr + DADDR_OFST + i); DPRINTK("Probably non-IP frame received.\n"); DPRINTK("ssap: %02X dsap: %02X " - "saddr: %02X:%02X:%02X:%02X:%02X:%02X " - "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n", + "saddr: %s daddr: %$s\n", readb(llc + SSAP_OFST), readb(llc + DSAP_OFST), - readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1), - readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3), - readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5), - readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1), - readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3), - readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5)); + print_mac(mac, saddr), print_mac(mac2, daddr)); } #endif diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index f114fb729f54..47d84cd28097 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -447,6 +447,9 @@ static int streamer_reset(struct net_device *dev) unsigned int uaa_addr; struct sk_buff *skb = NULL; __u16 misr; +#if STREAMER_DEBUG + DECLARE_MAC_BUF(mac); +#endif streamer_priv = netdev_priv(dev); streamer_mmio = streamer_priv->streamer_mmio; @@ -575,11 +578,8 @@ static int streamer_reset(struct net_device *dev) dev->dev_addr[i+1]= addr & 0xff; } #if STREAMER_DEBUG - printk("Adapter address: "); - for (i = 0; i < 6; i++) { - printk("%02x:", dev->dev_addr[i]); - } - printk("\n"); + printk("Adapter address: %s\n", + print_mac(mac, dev->dev_addr)); #endif } return 0; @@ -1539,6 +1539,7 @@ static void streamer_arb_cmd(struct net_device *dev) #if STREAMER_NETWORK_MONITOR struct trh_hdr *mac_hdr; + DECLARE_MAC_BUF(mac); #endif writew(streamer_priv->arb, streamer_mmio + LAPA); @@ -1611,15 +1612,11 @@ static void streamer_arb_cmd(struct net_device *dev) dev->name); mac_hdr = tr_hdr(mac_frame); printk(KERN_WARNING - "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", - dev->name, mac_hdr->daddr[0], mac_hdr->daddr[1], - mac_hdr->daddr[2], mac_hdr->daddr[3], - mac_hdr->daddr[4], mac_hdr->daddr[5]); + "%s: MAC Frame Dest. Addr: %s\n", + dev->name, print_mac(mac, mac_hdr->daddr)); printk(KERN_WARNING - "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", - dev->name, mac_hdr->saddr[0], mac_hdr->saddr[1], - mac_hdr->saddr[2], mac_hdr->saddr[3], - mac_hdr->saddr[4], mac_hdr->saddr[5]); + "%s: MAC Frame Srce. Addr: %s\n", + dev->name, DEV->ADDR6(mac_hdr->saddr)); #endif netif_rx(mac_frame); @@ -1854,6 +1851,8 @@ static int sprintf_info(char *buffer, struct net_device *dev) struct streamer_parameters_table spt; int size = 0; int i; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA); for (i = 0; i < 14; i += 2) { @@ -1875,37 +1874,30 @@ static int sprintf_info(char *buffer, struct net_device *dev) size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\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], sat.node_addr[0], sat.node_addr[1], - sat.node_addr[2], sat.node_addr[3], sat.node_addr[4], - sat.node_addr[5], sat.func_addr[0], sat.func_addr[1], - sat.func_addr[2], sat.func_addr[3]); + "%6s: %s : %s : %02x:%02x:%02x:%02x\n", + dev->name, print_mac(mac, dev->dev_addr), + print_mac(mac2, sat.node_addr), + sat.func_addr[0], sat.func_addr[1], + sat.func_addr[2], sat.func_addr[3]); size += sprintf(buffer + size, "\n%6s: Token Ring Parameters Table:\n", dev->name); size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name); size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n", + "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n", dev->name, spt.phys_addr[0], spt.phys_addr[1], spt.phys_addr[2], spt.phys_addr[3], - spt.up_node_addr[0], spt.up_node_addr[1], - spt.up_node_addr[2], spt.up_node_addr[3], - spt.up_node_addr[4], spt.up_node_addr[4], - spt.poll_addr[0], spt.poll_addr[1], spt.poll_addr[2], - spt.poll_addr[3], spt.poll_addr[4], spt.poll_addr[5], + print_mac(mac, spt.up_node_addr), + print_mac(mac2, spt.poll_addr), ntohs(spt.acc_priority), ntohs(spt.auth_source_class), ntohs(spt.att_code)); size += sprintf(buffer + size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name); size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n", - dev->name, spt.source_addr[0], spt.source_addr[1], - spt.source_addr[2], spt.source_addr[3], - spt.source_addr[4], spt.source_addr[5], + "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n", + dev->name, print_mac(mac, spt.source_addr), ntohs(spt.beacon_type), ntohs(spt.major_vector), ntohs(spt.lan_status), ntohs(spt.local_ring), ntohs(spt.mon_error), ntohs(spt.frame_correl)); @@ -1914,14 +1906,12 @@ static int sprintf_info(char *buffer, struct net_device *dev) dev->name); size += sprintf(buffer + size, - "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n", + "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n", dev->name, ntohs(spt.beacon_transmit), - ntohs(spt.beacon_receive), spt.beacon_naun[0], - spt.beacon_naun[1], spt.beacon_naun[2], - spt.beacon_naun[3], spt.beacon_naun[4], - spt.beacon_naun[5], spt.beacon_phys[0], - spt.beacon_phys[1], spt.beacon_phys[2], - spt.beacon_phys[3]); + ntohs(spt.beacon_receive), + print_mac(mac, spt.beacon_naun), + spt.beacon_phys[0], spt.beacon_phys[1], + spt.beacon_phys[2], spt.beacon_phys[3]); return size; } #endif diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index d0ce2ce675d5..5a4151362fc0 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -151,7 +151,8 @@ static int __devinit madgemc_probe(struct device *device) struct net_local *tp; struct card_info *card; struct mca_device *mdev = to_mca_device(device); - int ret = 0, i = 0; + int ret = 0; + DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -322,11 +323,8 @@ static int __devinit madgemc_probe(struct device *device) mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev); - printk("%s: Ring Station Address: ", dev->name); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk("\n"); + printk("%s: Ring Station Address: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); if (tmsdev_init(dev, device)) { printk("%s: unable to get memory for dev->priv.\n", @@ -692,11 +690,11 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) struct net_local *tp = netdev_priv(dev); struct card_info *curcard = tp->tmspriv; int len = 0; + DECLARE_MAC_BUF(mac); len += sprintf(buf+len, "-------\n"); if (curcard) { struct net_local *tp = netdev_priv(dev); - int i; len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev); len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize); @@ -716,11 +714,8 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) } len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair"); - len += sprintf(buf+len, "Ring Station Address: "); - len += sprintf(buf+len, "%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - len += sprintf(buf+len, " %2.2x", dev->dev_addr[i]); - len += sprintf(buf+len, "\n"); + len += sprintf(buf+len, "Ring Station Address: %s\n", + print_mac(mac, dev->dev_addr)); } else len += sprintf(buf+len, "Card not configured\n"); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index a149d5e2965c..74c1f0f189f5 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -418,14 +418,15 @@ static int __devinit olympic_init(struct net_device *dev) writel(uaa_addr,olympic_mmio+LAPA); adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800)); -#if OLYMPIC_DEBUG - printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n", - readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2), - readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5)); -#endif - memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); +#if OLYMPIC_DEBUG + { + DECLARE_MAC_BUF(mac); + printk("adapter address: %s\n", print_mac(mac, dev->dev_addr)); + } +#endif + olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); olympic_priv->olympic_parms_addr = swab16(readw(init_srb + 14)); @@ -440,6 +441,7 @@ static int olympic_open(struct net_device *dev) unsigned long flags, t; int i, open_finished = 1 ; u8 resp, err; + DECLARE_MAC_BUF(mac); DECLARE_WAITQUEUE(wait,current) ; @@ -567,14 +569,8 @@ static int olympic_open(struct net_device *dev) goto out; case 0x32: - printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - olympic_priv->olympic_laa[0], - olympic_priv->olympic_laa[1], - olympic_priv->olympic_laa[2], - olympic_priv->olympic_laa[3], - olympic_priv->olympic_laa[4], - olympic_priv->olympic_laa[5]) ; + printk(KERN_WARNING "%s: Invalid LAA: %s\n", + dev->name, print_mac(mac, olympic_priv->olympic_laa)); goto out; default: @@ -704,30 +700,26 @@ static int olympic_open(struct net_device *dev) #endif if (olympic_priv->olympic_network_monitor) { - u8 __iomem *oat ; - u8 __iomem *opt ; - oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; - opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + u8 __iomem *oat; + u8 __iomem *opt; + int i; + u8 addr[6]; + DECLARE_MAC_BUF(mac); + oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr); + opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr); - printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5)); + for (i = 0; i < 6; i++) + addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i); + printk("%s: Node Address: %s\n",dev->name, print_mac(mac, addr)); printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); - printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5)); + + for (i = 0; i < 6; i++) + addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i); + printk("%s: NAUN Address: %s\n",dev->name, print_mac(mac, addr)); } netif_start_queue(dev); @@ -1445,11 +1437,14 @@ static void olympic_arb_cmd(struct net_device *dev) mac_frame->protocol = tr_type_trans(mac_frame, dev); if (olympic_priv->olympic_network_monitor) { - struct trh_hdr *mac_hdr ; - printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ; + struct trh_hdr *mac_hdr; + DECLARE_MAC_BUF(mac); + printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name); mac_hdr = tr_hdr(mac_frame); - printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; - printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; + printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %s\n", + dev->name, print_mac(mac, mac_hdr->daddr)); + printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %s\n", + dev->name, print_mac(mac, mac_hdr->saddr)); } netif_rx(mac_frame); dev->last_rx = jiffies; @@ -1644,26 +1639,24 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt int len=0; off_t begin=0; off_t pos=0; - + u8 addr[6]; + u8 addr2[6]; + int i; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + size = sprintf(buffer, "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name); size += sprintf(buffer+size, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n", + for (i = 0 ; i < 6 ; i++) + addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i); + + size += sprintf(buffer+size, "%6s: %s : %s : %02x:%02x:%02x:%02x\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], - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5), + print_mac(mac, dev->dev_addr), + print_mac(mac2, addr), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), @@ -1673,25 +1666,20 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name) ; - - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n", + + for (i = 0 ; i < 6 ; i++) + addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr) + i); + for (i = 0 ; i < 6 ; i++) + addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i); + + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n", dev->name, readb(opt+offsetof(struct olympic_parameters_table, phys_addr)), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5), + print_mac(mac, addr), + print_mac(mac2, addr2), swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); @@ -1699,14 +1687,11 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name) ; - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n", + for (i = 0 ; i < 6 ; i++) + addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i); + size += sprintf(buffer+size, "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n", dev->name, - readb(opt+offsetof(struct olympic_parameters_table, source_addr)), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5), + print_mac(mac, addr), swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), @@ -1717,16 +1702,13 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", dev->name) ; - size += sprintf(buffer+size, "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n", + for (i = 0 ; i < 6 ; i++) + addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i); + size += sprintf(buffer+size, "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n", dev->name, swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5), + print_mac(mac, addr), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index 85d156dea033..ca6b65919b3d 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -122,6 +122,7 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) static int versionprinted; const unsigned *port; int j,err = 0; + DECLARE_MAC_BUF(mac); if (!dev) return -ENOMEM; @@ -152,11 +153,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) proteon_read_eeprom(dev); - printk(KERN_DEBUG "proteon.c: Ring Station Address: "); - printk("%2.2x", dev->dev_addr[0]); - for (j = 1; j < 6; j++) - printk(":%2.2x", dev->dev_addr[j]); - printk("\n"); + printk(KERN_DEBUG "proteon.c: Ring Station Address: %s\n", + print_mac(mac, dev->dev_addr)); tp = netdev_priv(dev); tp->setnselout = proteon_setnselout_pins; diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index ecbddc80a2a5..32e8d5a9f958 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -139,6 +139,7 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) static int versionprinted; const unsigned *port; int j, err = 0; + DECLARE_MAC_BUF(mac); if (!dev) return -ENOMEM; @@ -169,11 +170,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) sk_isa_read_eeprom(dev); - printk(KERN_DEBUG "skisa.c: Ring Station Address: "); - printk("%2.2x", dev->dev_addr[0]); - for (j = 1; j < 6; j++) - printk(":%2.2x", dev->dev_addr[j]); - printk("\n"); + printk(KERN_DEBUG "skisa.c: Ring Station Address: %s\n", + print_mac(mac, dev->dev_addr)); tp = netdev_priv(dev); tp->setnselout = sk_isa_setnselout_pins; diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index ecdd8511a67b..1c18f782f522 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -96,10 +96,11 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic static int versionprinted; struct net_device *dev; struct net_local *tp; - int i, ret; + int ret; unsigned int pci_irq_line; unsigned long pci_ioaddr; struct card_info *cardinfo = &card_info_table[ent->driver_data]; + DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -136,11 +137,8 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic tms_pci_read_eeprom(dev); - printk("%s: Ring Station Address: ", dev->name); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk("\n"); + printk("%s: Ring Station Address: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); ret = tmsdev_init(dev, &pdev->dev); if (ret) { diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index fe3225df0d32..df10af7df7b8 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -1540,6 +1540,7 @@ tsi108_init_one(struct platform_device *pdev) struct tsi108_prv_data *data = NULL; hw_info *einfo; int err = 0; + DECLARE_MAC_BUF(mac); einfo = pdev->dev.platform_data; @@ -1628,10 +1629,8 @@ tsi108_init_one(struct platform_device *pdev) goto register_fail; } - printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: " - "%02x:%02x:%02x:%02x:%02x:%02x\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]); + printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n" + dev->name, print_mac(mac, dev->dev_addr)); #ifdef DEBUG data->msg_enable = DEBUG; dump_eth_one(dev); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index ba3d0e5574a4..f12e33a17363 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1929,6 +1929,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, void __iomem *regs; unsigned long pciaddr; static int board_idx = -1; + DECLARE_MAC_BUF(mac); board_idx++; @@ -2042,15 +2043,11 @@ static int __devinit de_init_one (struct pci_dev *pdev, goto err_out_iomap; /* print info about board and interface just registered */ - printk (KERN_INFO "%s: %s at 0x%lx, " - "%02x:%02x:%02x:%02x:%02x:%02x, " - "IRQ %d\n", + printk (KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n", dev->name, de->de21040 ? "21040" : "21041", dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + print_mac(mac, dev->dev_addr), dev->irq); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index ee4215ca63f0..4633cc6dd412 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1088,6 +1088,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) struct de4x5_private *lp = netdev_priv(dev); struct pci_dev *pdev = NULL; int i, status=0; + DECLARE_MAC_BUF(mac); gendev->driver_data = dev; @@ -1123,12 +1124,8 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) dev->base_addr = iobase; printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase); - printk(", h/w address "); status = get_hw_addr(dev); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); + printk(", h/w address %s\n", print_mac(mac, dev->dev_addr)); if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); @@ -5468,19 +5465,16 @@ static void de4x5_dbg_srom(struct de4x5_srom *p) { int i; + DECLARE_MAC_BUF(mac); if (de4x5_debug & DEBUG_SROM) { printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id)); printk("Sub-system ID: %04x\n", *((u_short *)p->sub_system_id)); printk("ID Block CRC: %02x\n", (u_char)(p->id_block_crc)); printk("SROM version: %02x\n", (u_char)(p->version)); - printk("# controllers: %02x\n", (u_char)(p->num_controllers)); + printk("# controllers: %02x\n", (u_char)(p->num_controllers)); - printk("Hardware Address: "); - for (i=0;iieee_addr+i)); - } - printk("%02x\n", (u_char)*(p->ieee_addr+i)); + printk("Hardware Address: %s\n", print_mac(mac, p->ieee_addr)); printk("CRC checksum: %04x\n", (u_short)(p->chksum)); for (i=0; i<64; i++) { printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i)); @@ -5494,21 +5488,12 @@ static void de4x5_dbg_rx(struct sk_buff *skb, int len) { int i, j; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (de4x5_debug & DEBUG_RX) { - printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", - (u_char)skb->data[0], - (u_char)skb->data[1], - (u_char)skb->data[2], - (u_char)skb->data[3], - (u_char)skb->data[4], - (u_char)skb->data[5], - (u_char)skb->data[6], - (u_char)skb->data[7], - (u_char)skb->data[8], - (u_char)skb->data[9], - (u_char)skb->data[10], - (u_char)skb->data[11], + printk("R: %s <- %s len/SAP:%02x%02x [%d]\n", + print_mac(mac, skb->data), print_mac(mac2, &skb->data[6]), (u_char)skb->data[12], (u_char)skb->data[13], len); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index e2596e9ab1d7..ca90566d5bcd 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -362,6 +362,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, struct net_device *dev; u32 pci_pmr; int i, err; + DECLARE_MAC_BUF(mac); DMFE_DBUG(0, "dmfe_init_one()", 0); @@ -470,13 +471,13 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,", - dev->name, - ent->driver_data >> 16, - pci_name(pdev)); - for (i = 0; i < 6; i++) - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - printk(", irq %d.\n", dev->irq); + printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, " + "%s, irq %d.\n", + dev->name, + ent->driver_data >> 16, + pci_name(pdev), + print_mac(mac, dev->dev_addr), + dev->irq); pci_set_master(pdev); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 66977aaa7176..80fee2292531 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1051,12 +1051,11 @@ static void set_rx_mode(struct net_device *dev) filterbit &= 0x3f; mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); if (tulip_debug > 2) { - printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:" - "%2.2x:%2.2x:%2.2x %8.8x bit %d.\n", dev->name, - mclist->dmi_addr[0], mclist->dmi_addr[1], - mclist->dmi_addr[2], mclist->dmi_addr[3], - mclist->dmi_addr[4], mclist->dmi_addr[5], - ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); + DECLARE_MAC_BUF(mac); + printk(KERN_INFO "%s: Added filter for %s" + " %8.8x bit %d.\n", + dev->name, print_mac(mac, mclist->dmi_addr), + ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); } } if (mc_filter[0] == tp->mc_filter[0] && @@ -1256,6 +1255,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, const char *chip_name = tulip_tbl[chip_idx].chip_name; unsigned int eeprom_missing = 0; unsigned int force_csr0 = 0; + DECLARE_MAC_BUF(mac); #ifndef MODULE static int did_version; /* Already printed version info. */ @@ -1639,8 +1639,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (eeprom_missing) printk(" EEPROM not present,"); - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]); + printk(" %s", print_mac(mac, dev->dev_addr)); printk(", IRQ %d.\n", irq); if (tp->chip_id == PNIC2) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 2b7257d97c32..a4fd782bcd27 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -258,6 +258,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, struct uli526x_board_info *db; /* board information structure */ struct net_device *dev; int i, err; + DECLARE_MAC_BUF(mac); ULI526X_DBUG(0, "uli526x_init_one()", 0); @@ -372,11 +373,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev)); - - for (i = 0; i < 6; i++) - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - printk(", irq %d.\n", dev->irq); + printk(KERN_INFO "%s: ULi M%04lx at pci%s, %s, irq %d.\n", + dev->name,ent->driver_data >> 16,pci_name(pdev), + print_mac(mac, dev->dev_addr), dev->irq); pci_set_master(pdev); diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index e00833fadc0b..3c40dd6e1a2f 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -354,6 +354,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, int irq; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; void __iomem *ioaddr; + DECLARE_MAC_BUF(mac); i = pci_enable_device(pdev); if (i) return i; @@ -433,11 +434,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, if (i) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, + print_mac(mac, dev->dev_addr), irq); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -1245,16 +1244,16 @@ static int netdev_rx(struct net_device *dev) } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ - if (debug > 5) - printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" - "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " - "%d.%d.%d.%d.\n", - skb->data[0], skb->data[1], skb->data[2], skb->data[3], - skb->data[4], skb->data[5], skb->data[6], skb->data[7], - skb->data[8], skb->data[9], skb->data[10], - skb->data[11], skb->data[12], skb->data[13], - skb->data[14], skb->data[15], skb->data[16], - skb->data[17]); + if (debug > 5) { + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + printk(KERN_DEBUG " Rx data %s %s" + " %2.2x%2.2x %d.%d.%d.%d.\n", + print_mac(mac, &skb->data[0]), print_mac(mac2, &skb->data[6]), + skb->data[12], skb->data[13], + skb->data[14], skb->data[15], skb->data[16], skb->data[17]); + } #endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index de8c92083e92..70befe33e454 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -1074,6 +1074,7 @@ static void read_mac_address(struct xircom_private *card) unsigned char j, tuple, link, data_id, data_count; unsigned long flags; int i; + DECLARE_MAC_BUF(mac); enter("read_mac_address"); @@ -1103,11 +1104,7 @@ static void read_mac_address(struct xircom_private *card) } } spin_unlock_irqrestore(&card->lock, flags); -#ifdef DEBUG - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]); - printk("\n"); -#endif + pr_debug(" %s\n", print_mac(mac, card->dev->dev_addr)); leave("read_mac_address"); } diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d8b8e68ef70b..1f7644695976 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -159,16 +159,15 @@ tun_net_mclist(struct net_device *dev) struct tun_struct *tun = netdev_priv(dev); const struct dev_mc_list *mclist; int i; + DECLARE_MAC_BUF(mac); DBG(KERN_DEBUG "%s: tun_net_mclist: mc_count %d\n", dev->name, dev->mc_count); memset(tun->chr_filter, 0, sizeof tun->chr_filter); for (i = 0, mclist = dev->mc_list; i < dev->mc_count && mclist != NULL; i++, mclist = mclist->next) { add_multi(tun->net_filter, mclist->dmi_addr); - DBG(KERN_DEBUG "%s: tun_net_mclist: %x:%x:%x:%x:%x:%x\n", - dev->name, - mclist->dmi_addr[0], mclist->dmi_addr[1], mclist->dmi_addr[2], - mclist->dmi_addr[3], mclist->dmi_addr[4], mclist->dmi_addr[5]); + DBG(KERN_DEBUG "%s: tun_net_mclist: %s\n", + dev->name, print_mac(mac, mclist->dmi_addr)); } } @@ -358,6 +357,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t len, ret = 0; + DECLARE_MAC_BUF(mac); if (!tun) return -EBADFD; @@ -412,16 +412,14 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, (addr[0] == 0x33 && addr[1] == 0x33)) && ((tun->if_flags & IFF_ALLMULTI) || (tun->chr_filter[bit_nr >> 5] & (1 << (bit_nr & 31)))))) { - DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, addr[0], addr[1], addr[2], - addr[3], addr[4], addr[5]); + DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %s\n", + tun->dev->name, print_mac(mac, addr)); ret = tun_put_user(tun, skb, (struct iovec *) iv, len); kfree_skb(skb); break; } else { - DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, addr[0], addr[1], addr[2], - addr[3], addr[4], addr[5]); + DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %s\n", + tun->dev->name, print_mac(mac, addr)); kfree_skb(skb); continue; } @@ -564,6 +562,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, struct tun_struct *tun = file->private_data; void __user* argp = (void __user*)arg; struct ifreq ifr; + DECLARE_MAC_BUF(mac); if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) if (copy_from_user(&ifr, argp, sizeof ifr)) @@ -692,22 +691,16 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, /** Add the specified group to the character device's multicast filter * list. */ add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data); - DBG(KERN_DEBUG "%s: add multi: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, - (u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1], - (u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3], - (u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]); + DBG(KERN_DEBUG "%s: add multi: %s\n", + tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); return 0; case SIOCDELMULTI: /** Remove the specified group from the character device's multicast * filter list. */ del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data); - DBG(KERN_DEBUG "%s: del multi: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, - (u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1], - (u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3], - (u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]); + DBG(KERN_DEBUG "%s: del multi: %s\n", + tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); return 0; default: diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index c6d8513ecad6..43894e95fcb3 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -2316,8 +2316,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dma_addr_t shared_dma; struct cmd_desc xp_cmd; struct resp_desc xp_resp[3]; - int i; int err = 0; + DECLARE_MAC_BUF(mac); if(!did_version++) printk(KERN_INFO "%s", version); @@ -2532,13 +2532,11 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: %s at %s 0x%llx, ", + printk(KERN_INFO "%s: %s at %s 0x%llx, %s\n", dev->name, typhoon_card_info[card_id].name, use_mmio ? "MMIO" : "IO", - (unsigned long long)pci_resource_start(pdev, use_mmio)); - for(i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x\n", dev->dev_addr[i]); + (unsigned long long)pci_resource_start(pdev, use_mmio), + print_mac(mac, dev->dev_addr)); /* xp_resp still contains the response to the READ_VERSIONS command. * For debugging, let the user know what version he has. diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 432a2f054468..d1ed68a11e70 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1297,6 +1297,7 @@ static int pegasus_probe(struct usb_interface *intf, pegasus_t *pegasus; int dev_index = id - pegasus_ids; int res = -ENOMEM; + DECLARE_MAC_BUF(mac); usb_get_dev(dev); net = alloc_etherdev(sizeof(struct pegasus)); @@ -1367,12 +1368,10 @@ static int pegasus_probe(struct usb_interface *intf, queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, CARRIER_CHECK_DELAY); - dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n", - net->name, - usb_dev_id[dev_index].name, - net->dev_addr [0], net->dev_addr [1], - net->dev_addr [2], net->dev_addr [3], - net->dev_addr [4], net->dev_addr [5]); + dev_info(&intf->dev, "%s, %s, %s\n", + net->name, + usb_dev_id[dev_index].name, + print_mac(mac, net->dev_addr)); return 0; out3: diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 3542ca5fb0fa..acd5f1c0e63a 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1134,6 +1134,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) struct usb_device *xdev; int status; const char *name; + DECLARE_MAC_BUF(mac); name = udev->dev.driver->name; info = (struct driver_info *) prod->driver_info; @@ -1241,14 +1242,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if (status) goto out3; if (netif_msg_probe (dev)) - devinfo (dev, "register '%s' at usb-%s-%s, %s, " - "%02x:%02x:%02x:%02x:%02x:%02x", + devinfo (dev, "register '%s' at usb-%s-%s, %s, %s", udev->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description, - net->dev_addr [0], net->dev_addr [1], - net->dev_addr [2], net->dev_addr [3], - net->dev_addr [4], net->dev_addr [5]); + print_mac(mac, net->dev_addr)); // ok, it's ready to go. usb_set_intfdata (udev, dev); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index d55c4fdff489..9669bce0fd07 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -638,6 +638,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, #else int bar = 0; #endif + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -794,18 +795,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rc) goto err_out_unmap; - printk(KERN_INFO "%s: VIA %s at 0x%lx, ", + printk(KERN_INFO "%s: VIA %s at 0x%lx, %s, IRQ %d.\n", dev->name, name, #ifdef USE_MMIO - memaddr + memaddr, #else - (long)ioaddr + (long)ioaddr, #endif - ); - - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); + print_mac(mac, dev->dev_addr), pdev->irq); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/wd.c b/drivers/net/wd.c index cef365881ac2..fa14255282af 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -156,6 +156,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */ const char *model_name; static unsigned version_printed; + DECLARE_MAC_BUF(mac); for (i = 0; i < 8; i++) checksum += inb(ioaddr + 8 + i); @@ -174,9 +175,11 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) if (ei_debug && version_printed++ == 0) printk(version); - printk("%s: WD80x3 at %#3x,", dev->name, ioaddr); for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + dev->dev_addr[i] = inb(ioaddr + 8 + i); + + printk("%s: WD80x3 at %#3x, %s", + dev->name, ioaddr, print_mac(mac, dev->dev_addr)); /* The following PureData probe code was contributed by Mike Jagdis . Puredata does software diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index eec01fc15282..ac2ea237019d 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1787,6 +1787,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, int err; u32 reg; u8 perm_addr[ETH_ALEN]; + DECLARE_MAC_BUF(mac); #ifndef MODULE static unsigned int cardidx; @@ -1938,8 +1939,8 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_desc; } - printk(KERN_INFO "%s: hwaddr " MAC_FMT ", Rev 0x%02x\n", - wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n", + wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), priv->revid); return 0; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 7d717c4d9845..95d3cd1c49a7 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2821,6 +2821,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, struct net_device *dev; struct airo_info *ai; int i, rc; + DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_netdev(sizeof(*ai), "", ether_setup); @@ -2923,9 +2924,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, goto err_out_reg; set_bit(FLAG_REGISTERED,&ai->flags); - airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); + airo_print_info(dev->name, "MAC enabled %s", + print_mac(mac, dev->dev_addr)); /* Allocate the transmit buffers */ if (probe && !test_bit(FLAG_MPI,&ai->flags)) @@ -2982,6 +2982,7 @@ int reset_airo_card( struct net_device *dev ) { int i; struct airo_info *ai = dev->priv; + DECLARE_MAC_BUF(mac); if (reset_card (dev, 1)) return -1; @@ -2990,9 +2991,8 @@ int reset_airo_card( struct net_device *dev ) airo_print_err(dev->name, "MAC could not be enabled"); return -1; } - airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + airo_print_info(dev->name, "MAC enabled %s", + print_mac(mac, dev->dev_addr)); /* Allocate the transmit buffers if needed */ if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) @@ -5426,6 +5426,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { int i; char *ptr; APListRid APList_rid; + DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5449,13 +5450,8 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { // We end when we find a zero MAC if ( !*(int*)APList_rid.ap[i] && !*(int*)&APList_rid.ap[i][2]) break; - ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n", - (int)APList_rid.ap[i][0], - (int)APList_rid.ap[i][1], - (int)APList_rid.ap[i][2], - (int)APList_rid.ap[i][3], - (int)APList_rid.ap[i][4], - (int)APList_rid.ap[i][5]); + ptr += sprintf(ptr, "%s\n", + print_mac(mac, APList_rid.ap[i])); } if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); @@ -5474,6 +5470,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { int rc; /* If doLoseSync is not 1, we won't do a Lose Sync */ int doLoseSync = -1; + DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5510,13 +5507,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { we have to add a spin lock... */ rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); while(rc == 0 && BSSList_rid.index != 0xffff) { - ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d", - (int)BSSList_rid.bssid[0], - (int)BSSList_rid.bssid[1], - (int)BSSList_rid.bssid[2], - (int)BSSList_rid.bssid[3], - (int)BSSList_rid.bssid[4], - (int)BSSList_rid.bssid[5], + ptr += sprintf(ptr, "%s %*s rssi = %d", + print_mac(mac, BSSList_rid.bssid), (int)BSSList_rid.ssidLen, BSSList_rid.ssid, (int)BSSList_rid.dBm); diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index 3eaaab0ba0cc..dbdfc9e39d20 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1469,10 +1469,10 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short while (dmi) { if (dmi->dmi_addrlen == 6) { + DECLARE_MAC_BUF(mac); if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) - printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + printk(KERN_ERR "%s mcl %s\n", + dev->name, print_mac(mac, dmi->dmi_addr)); for (i = 0; i < 6; i++) if (dmi->dmi_addr[i] != hw_dst_addr[i]) break; @@ -1512,17 +1512,18 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short { char immedDestAddress[6]; char immedSrcAddress[6]; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); - printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name, - (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3], - (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7], - (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11], - immedDestAddress[0], immedDestAddress[1], immedDestAddress[2], - immedDestAddress[3], immedDestAddress[4], immedDestAddress[5], - immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2], - immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]); + printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n", + dev->name, print_mac(mac, skbtmp), + print_mac(mac2, &skbtmp[6]), + print_mac(mac3, immedDestAddress), + print_mac(mac4, immedSrcAddress)); } skb->protocol = eth_type_trans(skb, dev); IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 47dbdf95ea6f..059ce3f07dba 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1484,6 +1484,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, struct net_device *dev; struct atmel_private *priv; int rc; + DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_etherdev(sizeof(*priv)); @@ -1598,10 +1599,8 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, if (!ent) printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); - printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - dev->name, DRIVER_MAJOR, DRIVER_MINOR, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); + printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n", + dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr)); return dev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 184ebe3ed738..fd4ef27fcf25 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2883,6 +2883,7 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, u8 algorithm; u8 index; int err = -EINVAL; + DECLARE_MAC_BUF(mac); if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ @@ -2969,9 +2970,9 @@ out_unlock: out: if (!err) { b43dbg(wl, "%s hardware based encryption for keyidx: %d, " - "mac: " MAC_FMT "\n", + "mac: %s\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, - MAC_ARG(addr)); + print_mac(mac, addr)); } return err; } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index ac4831adb574..61b94218094b 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2679,6 +2679,7 @@ static int b43legacy_dev_set_key(struct ieee80211_hw *hw, struct b43legacy_wldev *dev = wl->current_dev; unsigned long flags; int err = -EOPNOTSUPP; + DECLARE_MAC_BUF(mac); if (!dev) return -ENODEV; @@ -2691,7 +2692,7 @@ static int b43legacy_dev_set_key(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); b43legacydbg(wl, "Using software based encryption for " - "mac: " MAC_FMT "\n", MAC_ARG(addr)); + "mac: %s\n", print_mac(mac, addr)); return err; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 10e07e865426..5fdbf24d2443 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -994,10 +994,4 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu __value; \ }) -/** Helpers to print MAC addresses. */ -#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x" -#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \ - ((u8*)(x))[2], ((u8*)(x))[3], \ - ((u8*)(x))[4], ((u8*)(x))[5] - #endif /* BCM43xx_H_ */ diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index cbedc9ee740a..ef084df3d48e 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -19,6 +19,7 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; u16 fc; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -44,10 +45,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, - MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); + printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); + printk(" A2=%s", print_mac(mac, hdr->addr2)); + printk(" A3=%s", print_mac(mac, hdr->addr3)); if (skb->len >= 30) - printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); + printk(" A4=%s", print_mac(mac, hdr->addr4)); printk("\n"); } @@ -534,6 +536,7 @@ static int hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, u16 fc, struct net_device **wds) { + DECLARE_MAC_BUF(mac); /* FIX: is this really supposed to accept WDS frames only in Master * mode? What about Repeater or Managed with WDS frames? */ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != @@ -549,10 +552,10 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { /* RA (or BSSID) is not ours - drop */ PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with " - "not own or broadcast %s=" MACSTR "\n", + "not own or broadcast %s=%s\n", local->dev->name, fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", - MAC2STR(hdr->addr1)); + print_mac(mac, hdr->addr1)); return -1; } @@ -565,8 +568,8 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, /* require that WDS link has been registered with TA or the * frame is from current AP when using 'AP client mode' */ PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " - "from unknown TA=" MACSTR "\n", - local->dev->name, MAC2STR(hdr->addr2)); + "from unknown TA=%s\n", + local->dev->name, print_mac(mac, hdr->addr2)); if (local->ap && local->ap->autom_ap_wds) hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); return -1; @@ -632,6 +635,7 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; + DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; @@ -643,8 +647,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, strcmp(crypt->ops->name, "TKIP") == 0) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from " MACSTR "\n", - local->dev->name, MAC2STR(hdr->addr2)); + "received packet from %s\n", + local->dev->name, print_mac(mac, hdr->addr2)); } return -1; } @@ -653,9 +657,9 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR + printk(KERN_DEBUG "%s: decryption failed (SA=%s" ") res=%d\n", - local->dev->name, MAC2STR(hdr->addr2), res); + local->dev->name, print_mac(mac, hdr->addr2), res); local->comm_tallies.rx_discards_wep_undecryptable++; return -1; } @@ -671,6 +675,7 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; + DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; @@ -683,8 +688,8 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=" MACSTR " keyidx=%d)\n", - local->dev->name, MAC2STR(hdr->addr2), keyidx); + " (SA=%s keyidx=%d)\n", + local->dev->name, print_mac(mac, hdr->addr2), keyidx); return -1; } @@ -716,6 +721,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, struct ieee80211_crypt_data *crypt = NULL; void *sta = NULL; int keyidx = 0; + DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -792,8 +798,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ printk(KERN_DEBUG "%s: WEP decryption failed (not set)" - " (SA=" MACSTR ")\n", - local->dev->name, MAC2STR(hdr->addr2)); + " (SA=%s)\n", + local->dev->name, print_mac(mac, hdr->addr2)); #endif local->comm_tallies.rx_discards_wep_undecryptable++; goto rx_dropped; @@ -807,8 +813,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MACSTR "\n", dev->name, - MAC2STR(hdr->addr2)); + "from %s\n", dev->name, + print_mac(mac, hdr->addr2)); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -976,8 +982,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, "unencrypted EAPOL frame\n", local->dev->name); } else { printk(KERN_DEBUG "%s: encryption configured, but RX " - "frame not encrypted (SA=" MACSTR ")\n", - local->dev->name, MAC2STR(hdr->addr2)); + "frame not encrypted (SA=%s)\n", + local->dev->name, print_mac(mac, hdr->addr2)); goto rx_dropped; } } @@ -986,8 +992,9 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, !hostap_is_eapol_frame(local, skb)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: dropped unencrypted RX data " - "frame from " MACSTR " (drop_unencrypted=1)\n", - dev->name, MAC2STR(hdr->addr2)); + "frame from %s" + " (drop_unencrypted=1)\n", + dev->name, print_mac(mac, hdr->addr2)); } goto rx_dropped; } diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 3df3c60263d4..e7afc3ec3e6d 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -17,6 +17,7 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { struct ieee80211_hdr_4addr *hdr; u16 fc; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -40,10 +41,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, - MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); + printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); + printk(" A2=%s", print_mac(mac, hdr->addr2)); + printk(" A3=%s", print_mac(mac, hdr->addr3)); if (skb->len >= 30) - printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); + printk(" A4=%s", print_mac(mac, hdr->addr4)); printk("\n"); } @@ -312,6 +314,7 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, struct ieee80211_hdr_4addr *hdr; u16 fc; int prefix_len, postfix_len, hdr_len, res; + DECLARE_MAC_BUF(mac); iface = netdev_priv(skb->dev); local = iface->local; @@ -326,8 +329,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to " MACSTR "\n", - local->dev->name, MAC2STR(hdr->addr1)); + "TX packet to %s\n", + local->dev->name, print_mac(mac, hdr->addr1)); } kfree_skb(skb); return NULL; diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 90900525379c..6bbdb76b32df 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -94,6 +94,7 @@ static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) { struct sta_info *s; + DECLARE_MAC_BUF(mac); s = ap->sta_hash[STA_HASH(sta->addr)]; if (s == NULL) return; @@ -108,18 +109,20 @@ static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) if (s->hnext != NULL) s->hnext = s->hnext->hnext; else - printk("AP: could not remove STA " MACSTR " from hash table\n", - MAC2STR(sta->addr)); + printk("AP: could not remove STA %s" + " from hash table\n", + print_mac(mac, sta->addr)); } static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) { + DECLARE_MAC_BUF(mac); if (sta->ap && sta->local) hostap_event_expired_sta(sta->local->dev, sta); if (ap->proc != NULL) { char name[20]; - sprintf(name, MACSTR, MAC2STR(sta->addr)); + sprintf(name, "%s", print_mac(mac, sta->addr)); remove_proc_entry(name, ap->proc); } @@ -182,6 +185,7 @@ static void ap_handle_timer(unsigned long data) struct ap_data *ap; unsigned long next_time = 0; int was_assoc; + DECLARE_MAC_BUF(mac); if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); @@ -238,8 +242,8 @@ static void ap_handle_timer(unsigned long data) if (sta->ap) { if (ap->autom_ap_wds) { PDEBUG(DEBUG_AP, "%s: removing automatic WDS " - "connection to AP " MACSTR "\n", - local->dev->name, MAC2STR(sta->addr)); + "connection to AP %s\n", + local->dev->name, print_mac(mac, sta->addr)); hostap_wds_link_oper(local, sta->addr, WDS_DEL); } } else if (sta->timeout_next == STA_NULLFUNC) { @@ -255,11 +259,11 @@ static void ap_handle_timer(unsigned long data) } else { int deauth = sta->timeout_next == STA_DEAUTH; u16 resp; - PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR + PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s" "(last=%lu, jiffies=%lu)\n", local->dev->name, deauth ? "deauthentication" : "disassociation", - MAC2STR(sta->addr), sta->last_rx, jiffies); + print_mac(mac, sta->addr), sta->last_rx, jiffies); resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); @@ -271,9 +275,10 @@ static void ap_handle_timer(unsigned long data) if (sta->timeout_next == STA_DEAUTH) { if (sta->flags & WLAN_STA_PERM) { - PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been " - "removed, but it has 'perm' flag\n", - local->dev->name, MAC2STR(sta->addr)); + PDEBUG(DEBUG_AP, "%s: STA %s" + " would have been removed, " + "but it has 'perm' flag\n", + local->dev->name, print_mac(mac, sta->addr)); } else ap_free_sta(ap, sta); return; @@ -327,6 +332,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; char *policy_txt; struct mac_entry *entry; + DECLARE_MAC_BUF(mac); if (off != 0) { *eof = 1; @@ -357,7 +363,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off, break; } - p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr)); + p += sprintf(p, "%s\n", print_mac(mac, entry->addr)); } spin_unlock_bh(&ap->mac_restrictions.lock); @@ -514,6 +520,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; struct sta_info *sta; int i; + DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -526,7 +533,8 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, if (!sta->ap) continue; - p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr), + p += sprintf(p, "%s %d %d %d %d '", + print_mac(mac, sta->addr), sta->u.ap.channel, sta->last_rx_signal, sta->last_rx_silence, sta->last_rx_rate); for (i = 0; i < sta->u.ap.ssid_len; i++) @@ -623,6 +631,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) u16 fc, *pos, auth_alg, auth_transaction, status; struct sta_info *sta = NULL; char *txt = NULL; + DECLARE_MAC_BUF(mac); if (ap->local->hostapd) { dev_kfree_skb(skb); @@ -674,9 +683,9 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d " - "status=%d - %s\n", - dev->name, MAC2STR(hdr->addr1), auth_alg, + PDEBUG(DEBUG_AP, "%s: %s auth_cb - alg=%d " + "trans#=%d status=%d - %s\n", + dev->name, print_mac(mac, hdr->addr1), auth_alg, auth_transaction, status, txt); } dev_kfree_skb(skb); @@ -692,6 +701,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) u16 fc, *pos, status; struct sta_info *sta = NULL; char *txt = NULL; + DECLARE_MAC_BUF(mac); if (ap->local->hostapd) { dev_kfree_skb(skb); @@ -742,8 +752,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n", - dev->name, MAC2STR(hdr->addr1), txt); + PDEBUG(DEBUG_AP, "%s: %s assoc_cb - %s\n", + dev->name, print_mac(mac, hdr->addr1), txt); } dev_kfree_skb(skb); } @@ -755,6 +765,7 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) struct ap_data *ap = data; struct ieee80211_hdr_4addr *hdr; struct sta_info *sta; + DECLARE_MAC_BUF(mac); if (skb->len < 24) goto fail; @@ -766,9 +777,9 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) sta->flags &= ~WLAN_STA_PENDING_POLL; spin_unlock(&ap->sta_table_lock); } else { - PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity " - "poll frame\n", ap->local->dev->name, - MAC2STR(hdr->addr1)); + PDEBUG(DEBUG_AP, "%s: STA %s" + " did not ACK activity poll frame\n", + ap->local->dev->name, print_mac(mac, hdr->addr1)); } fail: @@ -985,6 +996,7 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, char *p = page; struct sta_info *sta = (struct sta_info *) data; int i; + DECLARE_MAC_BUF(mac); /* FIX: possible race condition.. the STA data could have just expired, * but proc entry was still here so that the read could have started; @@ -995,11 +1007,11 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, return 0; } - p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n" + p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n" "flags=0x%04x%s%s%s%s%s%s%s\n" "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", sta->ap ? "AP" : "STA", - MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid, + print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid, sta->flags, sta->flags & WLAN_STA_AUTH ? " AUTH" : "", sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", @@ -1060,6 +1072,7 @@ static void handle_add_proc_queue(struct work_struct *work) struct sta_info *sta; char name[20]; struct add_sta_proc_data *entry, *prev; + DECLARE_MAC_BUF(mac); entry = ap->add_sta_proc_entries; ap->add_sta_proc_entries = NULL; @@ -1072,7 +1085,7 @@ static void handle_add_proc_queue(struct work_struct *work) spin_unlock_bh(&ap->sta_table_lock); if (sta) { - sprintf(name, MACSTR, MAC2STR(sta->addr)); + sprintf(name, "%s", print_mac(mac, sta->addr)); sta->proc = create_proc_read_entry( name, 0, ap->proc, prism2_sta_proc_read, sta); @@ -1290,6 +1303,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, struct sta_info *sta = NULL; struct ieee80211_crypt_data *crypt; char *txt = ""; + DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1298,8 +1312,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (len < 6) { PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " - "(len=%d) from " MACSTR "\n", dev->name, len, - MAC2STR(hdr->addr2)); + "(len=%d) from %s\n", dev->name, len, + print_mac(mac, hdr->addr2)); return; } @@ -1364,8 +1378,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (time_after(jiffies, sta->u.ap.last_beacon + (10 * sta->listen_interval * HZ) / 1024)) { PDEBUG(DEBUG_AP, "%s: no beacons received for a while," - " assuming AP " MACSTR " is now STA\n", - dev->name, MAC2STR(sta->addr)); + " assuming AP %s is now STA\n", + dev->name, print_mac(mac, sta->addr)); sta->ap = 0; sta->flags = 0; sta->u.sta.challenge = NULL; @@ -1480,9 +1494,9 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, } if (resp) { - PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d " - "stat=%d len=%d fc=%04x) ==> %d (%s)\n", - dev->name, MAC2STR(hdr->addr2), auth_alg, + PDEBUG(DEBUG_AP, "%s: %s auth (alg=%d " + "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", + dev->name, print_mac(mac, hdr->addr2), auth_alg, auth_transaction, status_code, len, fc, resp, txt); } } @@ -1502,13 +1516,14 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, int send_deauth = 0; char *txt = ""; u8 prev_ap[ETH_ALEN]; + DECLARE_MAC_BUF(mac); left = len = skb->len - IEEE80211_MGMT_HDR_LEN; if (len < (reassoc ? 10 : 4)) { PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " - "(len=%d, reassoc=%d) from " MACSTR "\n", - dev->name, len, reassoc, MAC2STR(hdr->addr2)); + "(len=%d, reassoc=%d) from %s\n", + dev->name, len, reassoc, print_mac(mac, hdr->addr2)); return; } @@ -1585,9 +1600,9 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } if (left > 0) { - PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra" - " data (%d bytes) [", - dev->name, MAC2STR(hdr->addr2), left); + PDEBUG(DEBUG_AP, "%s: assoc from %s" + " with extra data (%d bytes) [", + dev->name, print_mac(mac, hdr->addr2), left); while (left > 0) { PDEBUG2(DEBUG_AP, "<%02x>", *u); u++; left--; @@ -1687,10 +1702,10 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } #if 0 - PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR - ") => %d(%d) (%s)\n", - dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len, - MAC2STR(prev_ap), resp, send_deauth, txt); + PDEBUG(DEBUG_AP, "%s: %s %sassoc (len=%d " + "prev_ap=%s) => %d(%d) (%s)\n", + dev->name, print_mac(mac, hdr->addr2), reassoc ? "re" : "", len, + print_mac(mac, prev_ap), resp, send_deauth, txt); #endif } @@ -1705,6 +1720,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, int len; u16 reason_code, *pos; struct sta_info *sta = NULL; + DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1716,8 +1732,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, pos = (u16 *) body; reason_code = __le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, " - "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, + PDEBUG(DEBUG_AP, "%s: deauthentication: %s len=%d, " + "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1729,9 +1745,9 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: deauthentication from " MACSTR ", " + printk("%s: deauthentication from %s, " "reason_code=%d, but STA not authenticated\n", dev->name, - MAC2STR(hdr->addr2), reason_code); + print_mac(mac, hdr->addr2), reason_code); } } @@ -1746,6 +1762,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, int len; u16 reason_code, *pos; struct sta_info *sta = NULL; + DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1757,8 +1774,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, pos = (u16 *) body; reason_code = __le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, " - "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, + PDEBUG(DEBUG_AP, "%s: disassociation: %s len=%d, " + "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1770,9 +1787,9 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: disassociation from " MACSTR ", " + printk("%s: disassociation from %s, " "reason_code=%d, but STA not authenticated\n", - dev->name, MAC2STR(hdr->addr2), reason_code); + dev->name, print_mac(mac, hdr->addr2), reason_code); } } @@ -1862,15 +1879,16 @@ static void handle_pspoll(local_info_t *local, struct sta_info *sta; u16 aid; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); - PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR - " PWRMGT=%d\n", - MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), + PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%s" + ", TA=%s PWRMGT=%d\n", + print_mac(mac, hdr->addr1), print_mac(mac, hdr->addr2), !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR - " not own MAC\n", MAC2STR(hdr->addr1)); + PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=%s" + " not own MAC\n", print_mac(mac, hdr->addr1)); return; } @@ -1948,6 +1966,7 @@ static void handle_wds_oper_queue(struct work_struct *work) wds_oper_queue); local_info_t *local = ap->local; struct wds_oper_data *entry, *prev; + DECLARE_MAC_BUF(mac); spin_lock_bh(&local->lock); entry = local->ap->wds_oper_entries; @@ -1956,10 +1975,10 @@ static void handle_wds_oper_queue(struct work_struct *work) while (entry) { PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " - "to AP " MACSTR "\n", + "to AP %s\n", local->dev->name, entry->type == WDS_ADD ? "adding" : "removing", - MAC2STR(entry->addr)); + print_mac(mac, entry->addr)); if (entry->type == WDS_ADD) prism2_wds_add(local, entry->addr, 0); else if (entry->type == WDS_DEL) @@ -2135,6 +2154,7 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ u16 fc, type, stype; struct ieee80211_hdr_4addr *hdr; + DECLARE_MAC_BUF(mac); /* FIX: should give skb->len to handler functions and check that the * buffer is long enough */ @@ -2163,8 +2183,8 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" - MACSTR " not own MAC\n", - MAC2STR(hdr->addr1)); + "%s not own MAC\n", + print_mac(mac, hdr->addr1)); goto done; } @@ -2200,14 +2220,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR - " not own MAC\n", MAC2STR(hdr->addr1)); + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%s" + " not own MAC\n", print_mac(mac, hdr->addr1)); goto done; } if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR - " not own MAC\n", MAC2STR(hdr->addr3)); + PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%s" + " not own MAC\n", print_mac(mac, hdr->addr3)); goto done; } @@ -2288,6 +2308,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) struct sk_buff *skb; struct ieee80211_hdr_4addr *hdr; struct hostap_80211_rx_status rx_stats; + DECLARE_MAC_BUF(mac); if (skb_queue_empty(&sta->tx_buf)) return; @@ -2308,8 +2329,8 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) memcpy(hdr->addr2, sta->addr, ETH_ALEN); hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); - PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for " - "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr)); + PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA " + "%s\n", local->dev->name, print_mac(mac, sta->addr)); skb->dev = local->dev; @@ -2636,6 +2657,7 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) int ret = sta->tx_rate; struct hostap_interface *iface; local_info_t *local; + DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -2663,9 +2685,9 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to" - " %d\n", dev->name, MAC2STR(sta->addr), - sta->tx_rate); + PDEBUG(DEBUG_AP, "%s: STA %s" + " TX rate raised to %d\n", + dev->name, print_mac(mac, sta->addr), sta->tx_rate); } sta->tx_since_last_failure = 0; } @@ -2683,6 +2705,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) int set_tim, ret; struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; + DECLARE_MAC_BUF(mac); meta = (struct hostap_skb_tx_data *) skb->cb; ret = AP_TX_CONTINUE; @@ -2718,7 +2741,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) * print out any errors here. */ if (net_ratelimit()) { printk(KERN_DEBUG "AP: drop packet to non-associated " - "STA " MACSTR "\n", MAC2STR(hdr->addr1)); + "STA %s\n", + print_mac(mac, hdr->addr1)); } #endif local->ap->tx_drop_nonassoc++; @@ -2756,8 +2780,9 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) } if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { - PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS " - "mode buffer\n", local->dev->name, MAC2STR(sta->addr)); + PDEBUG(DEBUG_PS, "%s: No more space in STA (%s" + ")'s PS mode buffer\n", + local->dev->name, print_mac(mac, sta->addr)); /* Make sure that TIM is set for the station (it might not be * after AP wlan hw reset). */ /* FIX: should fix hw reset to restore bits based on STA @@ -2821,6 +2846,7 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) struct sta_info *sta; struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; meta = (struct hostap_skb_tx_data *) skb->cb; @@ -2829,9 +2855,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) sta = ap_get_sta(local->ap, hdr->addr1); if (!sta) { spin_unlock(&local->ap->sta_table_lock); - PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this " - "TX error (@%lu)\n", - local->dev->name, MAC2STR(hdr->addr1), jiffies); + PDEBUG(DEBUG_AP, "%s: Could not find STA %s" + " for this TX error (@%lu)\n", + local->dev->name, print_mac(mac, hdr->addr1), jiffies); return; } @@ -2858,8 +2884,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered " - "to %d\n", local->dev->name, MAC2STR(sta->addr), + PDEBUG(DEBUG_AP, "%s: STA %s" + " TX rate lowered to %d\n", + local->dev->name, print_mac(mac, sta->addr), sta->tx_rate); } sta->tx_consecutive_exc = 0; @@ -2871,16 +2898,17 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, int pwrmgt, int type, int stype) { + DECLARE_MAC_BUF(mac); if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { sta->flags |= WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS " + PDEBUG(DEBUG_PS2, "STA %s changed to use PS " "mode (type=0x%02X, stype=0x%02X)\n", - MAC2STR(sta->addr), type >> 2, stype >> 4); + print_mac(mac, sta->addr), type >> 2, stype >> 4); } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { sta->flags &= ~WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use " + PDEBUG(DEBUG_PS2, "STA %s changed to not use " "PS mode (type=0x%02X, stype=0x%02X)\n", - MAC2STR(sta->addr), type >> 2, stype >> 4); + print_mac(mac, sta->addr), type >> 2, stype >> 4); if (type != IEEE80211_FTYPE_CTL || stype != IEEE80211_STYPE_PSPOLL) schedule_packet_send(local, sta); @@ -2924,6 +2952,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, struct sta_info *sta; u16 fc, type, stype; struct ieee80211_hdr_4addr *hdr; + DECLARE_MAC_BUF(mac); if (local->ap == NULL) return AP_RX_CONTINUE; @@ -2954,9 +2983,10 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT } else { printk(KERN_DEBUG "%s: dropped received packet" - " from non-associated STA " MACSTR + " from non-associated STA " + "%s" " (type=0x%02x, subtype=0x%02x)\n", - dev->name, MAC2STR(hdr->addr2), + dev->name, print_mac(mac, hdr->addr2), type >> 2, stype >> 4); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ @@ -2991,8 +3021,8 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * being associated. */ printk(KERN_DEBUG "%s: rejected received nullfunc " "frame without ToDS from not associated STA " - MACSTR "\n", - dev->name, MAC2STR(hdr->addr2)); + "%s\n", + dev->name, print_mac(mac, hdr->addr2)); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ } @@ -3009,9 +3039,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * If BSSID is own, report the dropping of this frame. */ if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { printk(KERN_DEBUG "%s: dropped received packet from " - MACSTR " with no ToDS flag (type=0x%02x, " - "subtype=0x%02x)\n", dev->name, - MAC2STR(hdr->addr2), type >> 2, stype >> 4); + "%s with no ToDS flag " + "(type=0x%02x, subtype=0x%02x)\n", dev->name, + print_mac(mac, hdr->addr2), type >> 2, stype >> 4); hostap_dump_rx_80211(dev->name, skb, rx_stats); } ret = AP_RX_DROP; diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index b31e6a05f23c..ceb7f1e5e9e0 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h @@ -6,9 +6,6 @@ #define BIT(x) (1 << (x)) -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" - /* IEEE 802.11 defines */ diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index adedb9716542..7fa7ab0a4b23 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2335,6 +2335,10 @@ static void prism2_txexc(local_info_t *local) int show_dump, res; char *payload = NULL; struct hfa384x_tx_frame txdesc; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; local->stats.tx_errors++; @@ -2400,10 +2404,9 @@ static void prism2_txexc(local_info_t *local) WLAN_FC_GET_STYPE(fc) >> 4, fc & IEEE80211_FCTL_TODS ? " ToDS" : "", fc & IEEE80211_FCTL_FROMDS ? " FromDS" : ""); - PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3=" - MACSTR " A4=" MACSTR "\n", - MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2), - MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4)); + PDEBUG(DEBUG_EXTRA, " A1=%s A2=%s A3=%s A4=%s\n", + print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2), + print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4)); } diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index b6a02a02da74..636f4b2382ea 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -166,6 +166,7 @@ static void prism2_host_roaming(local_info_t *local) struct hfa384x_hostscan_result *selected, *entry; int i; unsigned long flags; + DECLARE_MAC_BUF(mac); if (local->last_join_time && time_before(jiffies, local->last_join_time + 10 * HZ)) { @@ -198,8 +199,9 @@ static void prism2_host_roaming(local_info_t *local) local->preferred_ap[2] || local->preferred_ap[3] || local->preferred_ap[4] || local->preferred_ap[5]) { /* Try to find preferred AP */ - PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n", - dev->name, MAC2STR(local->preferred_ap)); + PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " + "%s\n", + dev->name, print_mac(mac, local->preferred_ap)); for (i = 0; i < local->last_scan_results_count; i++) { entry = &local->last_scan_results[i]; if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) @@ -216,8 +218,9 @@ static void prism2_host_roaming(local_info_t *local) req.channel = selected->chid; spin_unlock_irqrestore(&local->lock, flags); - PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n", - dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel)); + PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s" + " channel=%d\n", + dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel)); if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); @@ -409,6 +412,7 @@ static void handle_info_queue_linkstatus(local_info_t *local) int val = local->prev_link_status; int connected; union iwreq_data wrqu; + DECLARE_MAC_BUF(mac); connected = val == HFA384X_LINKSTATUS_CONNECTED || @@ -420,9 +424,10 @@ static void handle_info_queue_linkstatus(local_info_t *local) printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " "LinkStatus event\n", local->dev->name); } else { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n", + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" + "%s\n", local->dev->name, - MAC2STR((unsigned char *) local->bssid)); + print_mac(mac, (unsigned char *) local->bssid)); if (local->wds_type & HOSTAP_WDS_AP_CLIENT) hostap_add_sta(local->ap, local->bssid); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 730b3541e325..7036ecff5ec1 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -664,6 +664,7 @@ static int hostap_join_ap(struct net_device *dev) unsigned long flags; int i; struct hfa384x_hostscan_result *entry; + DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -685,14 +686,14 @@ static int hostap_join_ap(struct net_device *dev) if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest " MACSTR + printk(KERN_DEBUG "%s: JoinRequest %s" " failed\n", - dev->name, MAC2STR(local->preferred_ap)); + dev->name, print_mac(mac, local->preferred_ap)); return -1; } - printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n", - dev->name, MAC2STR(local->preferred_ap)); + printk(KERN_DEBUG "%s: Trying to join BSSID %s\n", + dev->name, print_mac(mac, local->preferred_ap)); return 0; } @@ -3697,8 +3698,10 @@ static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, struct prism2_hostapd_param *param, int param_len) { - printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n", - local->dev->name, MAC2STR(param->sta_addr)); + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%ssta: associated as client with AP " + "%s\n", + local->dev->name, print_mac(mac, param->sta_addr)); memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); return 0; } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 9a470e80ca24..4cb09d81b404 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -530,6 +530,10 @@ int hostap_set_auth_algs(local_info_t *local) void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) { u16 status, fc; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); status = __le16_to_cpu(rx->status); @@ -548,13 +552,12 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" - MACSTR "\n", - MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3), - MAC2STR(rx->addr4)); + printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", + print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2), + print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4)); - printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", - MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr), + printk(KERN_DEBUG " dst=%s src=%s len=%d\n", + print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr), __be16_to_cpu(rx->len)); } @@ -562,6 +565,10 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) { u16 fc; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " "tx_control=0x%04x; jiffies=%ld\n", @@ -577,13 +584,12 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" - MACSTR "\n", - MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3), - MAC2STR(tx->addr4)); + printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", + print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2), + print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4)); - printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", - MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr), + printk(KERN_DEBUG " dst=%s src=%s len=%d\n", + print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr), __be16_to_cpu(tx->len)); } diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index d1d8ce022e63..b03536008ad9 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -106,6 +106,7 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, local_info_t *local = (local_info_t *) data; struct list_head *ptr; struct hostap_interface *iface; + DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -117,9 +118,9 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, iface = list_entry(ptr, struct hostap_interface, list); if (iface->type != HOSTAP_INTERFACE_WDS) continue; - p += sprintf(p, "%s\t" MACSTR "\n", + p += sprintf(p, "%s\t%s\n", iface->dev->name, - MAC2STR(iface->u.wds.remote_addr)); + print_mac(mac, iface->u.wds.remote_addr)); if ((p - page) > PROC_LIMIT) { printk(KERN_DEBUG "%s: wds proc did not fit\n", local->dev->name); @@ -147,6 +148,7 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, struct list_head *ptr; struct hostap_bss_info *bss; int i; + DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -158,8 +160,8 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, spin_lock_bh(&local->lock); list_for_each(ptr, &local->bss_list) { bss = list_entry(ptr, struct hostap_bss_info, list); - p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t", - MAC2STR(bss->bssid), bss->last_update, + p += sprintf(p, "%s\t%lu\t%u\t0x%x\t", + print_mac(mac, bss->bssid), bss->last_update, bss->count, bss->capab_info); for (i = 0; i < bss->ssid_len; i++) { p += sprintf(p, "%c", @@ -312,6 +314,7 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, int entry, i, len, total = 0; struct hfa384x_hostscan_result *scanres; u8 *pos; + DECLARE_MAC_BUF(mac); p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " "SSID\n"); @@ -329,14 +332,14 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, if ((p - page) > (PAGE_SIZE - 200)) break; - p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ", + p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ", le16_to_cpu(scanres->chid), (s16) le16_to_cpu(scanres->anl), (s16) le16_to_cpu(scanres->sl), le16_to_cpu(scanres->beacon_interval), le16_to_cpu(scanres->capability), le16_to_cpu(scanres->rate), - MAC2STR(scanres->bssid), + print_mac(mac, scanres->bssid), le16_to_cpu(scanres->atim)); pos = scanres->sup_rates; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index b3c07b93afce..2d46a16c0945 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1922,6 +1922,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) u32 chan; char *txratename; u8 bssid[ETH_ALEN]; + DECLARE_MAC_BUF(mac); /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not @@ -1983,9 +1984,9 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) } IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=" - MAC_FMT ")\n", + "%s)\n", priv->net_dev->name, escape_essid(essid, essid_len), - txratename, chan, MAC_ARG(bssid)); + txratename, chan, print_mac(mac, bssid)); /* now we copy read ssid into dev */ if (!(priv->config & CFG_STATIC_ESSID)) { @@ -2053,10 +2054,12 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) { + DECLARE_MAC_BUF(mac); + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' " MAC_FMT " \n", + "disassociated: '%s' %s \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); @@ -4049,6 +4052,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, char *out = buf; int length; int ret; + DECLARE_MAC_BUF(mac); if (priv->status & STATUS_RF_KILL_MASK) return 0; @@ -4076,9 +4080,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, __LINE__); out += sprintf(out, "ESSID: %s\n", essid); - out += sprintf(out, "BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", - bssid[0], bssid[1], bssid[2], - bssid[3], bssid[4], bssid[5]); + out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid)); out += sprintf(out, "Channel: %d\n", chan); return out - buf; @@ -4652,19 +4654,20 @@ static void ipw2100_rx_free(struct ipw2100_priv *priv) static int ipw2100_read_mac_address(struct ipw2100_priv *priv) { u32 length = ETH_ALEN; - u8 mac[ETH_ALEN]; + u8 addr[ETH_ALEN]; + DECLARE_MAC_BUF(mac); int err; - err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length); + err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length); if (err) { IPW_DEBUG_INFO("MAC address read failed\n"); return -EIO; } - IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN); + memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN); + IPW_DEBUG_INFO("card MAC is %s\n", + print_mac(mac, priv->net_dev->dev_addr)); return 0; } @@ -5043,10 +5046,10 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, int err; #ifdef CONFIG_IPW2100_DEBUG + DECLARE_MAC_BUF(mac); if (bssid != NULL) - IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n", - bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], - bssid[5]); + IPW_DEBUG_HC("MANDATORY_BSSID: %s\n", + print_mac(mac, bssid)); else IPW_DEBUG_HC("MANDATORY_BSSID: \n"); #endif @@ -6892,6 +6895,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, static const unsigned char off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + DECLARE_MAC_BUF(mac); // sanity checks if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) @@ -6917,13 +6921,8 @@ static int ipw2100_wx_set_wap(struct net_device *dev, err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0); - IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n", - wrqu->ap_addr.sa_data[0] & 0xff, - wrqu->ap_addr.sa_data[1] & 0xff, - wrqu->ap_addr.sa_data[2] & 0xff, - wrqu->ap_addr.sa_data[3] & 0xff, - wrqu->ap_addr.sa_data[4] & 0xff, - wrqu->ap_addr.sa_data[5] & 0xff); + IPW_DEBUG_WX("SET BSSID -> %s\n", + print_mac(mac, wrqu->ap_addr.sa_data)); done: mutex_unlock(&priv->action_mutex); @@ -6939,6 +6938,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, */ struct ipw2100_priv *priv = ieee80211_priv(dev); + DECLARE_MAC_BUF(mac); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -6948,8 +6948,8 @@ static int ipw2100_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", - MAC_ARG(wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %s\n", + print_mac(mac, wrqu->ap_addr.sa_data)); return 0; } diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index afad8bb7e334..2119a79dcc86 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2247,8 +2247,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) return -1; } - IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", - priv->net_dev->name, MAC_ARG(mac)); + IPW_DEBUG_INFO("%s: Setting MAC to %s\n", + priv->net_dev->name, print_mac(mac, mac)); return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); } @@ -3796,6 +3796,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) { struct ipw_station_entry entry; int i; + DECLARE_MAC_BUF(mac); for (i = 0; i < priv->num_stations; i++) { if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { @@ -3812,7 +3813,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) if (i == MAX_STATIONS) return IPW_INVALID_STATION; - IPW_DEBUG_SCAN("Adding AdHoc station: " MAC_FMT "\n", MAC_ARG(bssid)); + IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid)); entry.reserved = 0; entry.support_mode = 0; @@ -3839,6 +3840,7 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid) static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) { int err; + DECLARE_MAC_BUF(mac); if (priv->status & STATUS_ASSOCIATING) { IPW_DEBUG_ASSOC("Disassociating while associating.\n"); @@ -3851,9 +3853,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) return; } - IPW_DEBUG_ASSOC("Disassocation attempt from " MAC_FMT " " + IPW_DEBUG_ASSOC("Disassocation attempt from %s " "on channel %d.\n", - MAC_ARG(priv->assoc_request.bssid), + print_mac(mac, priv->assoc_request.bssid), priv->assoc_request.channel); priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); @@ -4348,6 +4350,7 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, static void ipw_rx_notification(struct ipw_priv *priv, struct ipw_rx_notification *notif) { + DECLARE_MAC_BUF(mac); notif->size = le16_to_cpu(notif->size); IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size); @@ -4360,11 +4363,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_ASSOCIATED:{ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "associated: '%s' " MAC_FMT + "associated: '%s' %s" " \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); switch (priv->ieee->iw_mode) { case IW_MODE_INFRA: @@ -4444,13 +4447,13 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DL_STATE | IPW_DL_ASSOC, "deauthenticated: '%s' " - MAC_FMT + "%s" ": (0x%04X) - %s \n", escape_essid(priv-> essid, priv-> essid_len), - MAC_ARG(priv->bssid), + print_mac(mac, priv->bssid), ntohs(auth->status), ipw_get_status_code (ntohs @@ -4467,11 +4470,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "authenticated: '%s' " MAC_FMT + "authenticated: '%s' %s" "\n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); break; } @@ -4496,11 +4499,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' " MAC_FMT + "disassociated: '%s' %s" " \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); priv->status &= ~(STATUS_DISASSOCIATING | @@ -4535,10 +4538,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, switch (auth->state) { case CMAS_AUTHENTICATED: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "authenticated: '%s' " MAC_FMT " \n", + "authenticated: '%s' %s \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); priv->status |= STATUS_AUTH; break; @@ -4554,10 +4557,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, } IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "deauthenticated: '%s' " MAC_FMT "\n", + "deauthenticated: '%s' %s\n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); priv->status &= ~(STATUS_ASSOCIATING | STATUS_AUTH | @@ -5383,25 +5386,27 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, int roaming) { struct ipw_supported_rates rates; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ if ((priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to " "capability mismatch.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* If we do not have an ESSID for this AP, we can not associate with * it */ if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of hidden ESSID.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } @@ -5411,11 +5416,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of non-network ESSID.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } } else { @@ -5430,9 +5435,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, MAC_ARG(network->bssid), + escaped, print_mac(mac, network->bssid), escape_essid(priv->essid, priv->essid_len)); return 0; @@ -5459,10 +5464,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5470,10 +5475,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of channel mismatch: %d != %d.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), network->channel, priv->channel); return 0; } @@ -5481,10 +5486,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of privacy mismatch: %s != %s.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), priv-> capability & CAP_PRIVACY_ON ? "on" : "off", network-> @@ -5494,40 +5499,41 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, } if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " - "because of the same BSSID match: " MAC_FMT + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + "because of the same BSSID match: %s" ".\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), MAC_ARG(priv->bssid)); + print_mac(mac, network->bssid), + print_mac(mac2, priv->bssid)); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of invalid frequency/mode " "combination.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of no compatible rates.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } @@ -5538,9 +5544,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Set up 'new' AP to this network */ ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n", + IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 1; } @@ -5594,6 +5600,7 @@ static int ipw_best_network(struct ipw_priv *priv, struct ieee80211_network *network, int roaming) { struct ipw_supported_rates rates; + DECLARE_MAC_BUF(mac); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ @@ -5601,20 +5608,20 @@ static int ipw_best_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_ESS)) || (priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded due to " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to " "capability mismatch.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* If we do not have an ESSID for this AP, we can not associate with * it */ if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of hidden ESSID.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } @@ -5624,11 +5631,11 @@ static int ipw_best_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_ASSOC("Netowrk '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of non-network ESSID.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } } else { @@ -5642,9 +5649,9 @@ static int ipw_best_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, MAC_ARG(network->bssid), + escaped, print_mac(mac, network->bssid), escape_essid(priv->essid, priv->essid_len)); return 0; @@ -5658,12 +5665,12 @@ static int ipw_best_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded because " - "'%s (" MAC_FMT ")' has a stronger signal.\n", - escaped, MAC_ARG(network->bssid), + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because " + "'%s (%s)' has a stronger signal.\n", + escaped, print_mac(mac, network->bssid), escape_essid(match->network->ssid, match->network->ssid_len), - MAC_ARG(match->network->bssid)); + print_mac(mac, match->network->bssid)); return 0; } @@ -5671,11 +5678,11 @@ static int ipw_best_network(struct ipw_priv *priv, * last 3 seconds, do not try and associate again... */ if (network->last_associate && time_after(network->last_associate + (HZ * 3UL), jiffies)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of storming (%ums since last " "assoc attempt).\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), jiffies_to_msecs(jiffies - network->last_associate)); return 0; @@ -5684,10 +5691,10 @@ static int ipw_best_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5695,10 +5702,10 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of channel mismatch: %d != %d.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), network->channel, priv->channel); return 0; } @@ -5706,10 +5713,10 @@ static int ipw_best_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of privacy mismatch: %s != %s.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), priv->capability & CAP_PRIVACY_ON ? "on" : "off", network->capability & @@ -5719,48 +5726,48 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_BSSID) && memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of BSSID mismatch: " MAC_FMT ".\n", + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + "because of BSSID mismatch: %s.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), MAC_ARG(priv->bssid)); + print_mac(mac, network->bssid), print_mac(mac, priv->bssid)); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of invalid frequency/mode " "combination.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* Filter out invalid channel in current GEO */ if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of invalid channel in current GEO\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of no compatible rates.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } @@ -5772,9 +5779,9 @@ static int ipw_best_network(struct ipw_priv *priv, ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' is a viable match.\n", + IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 1; } @@ -6016,6 +6023,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work) static void ipw_debug_config(struct ipw_priv *priv) { + DECLARE_MAC_BUF(mac); IPW_DEBUG_INFO("Scan completed, no valid APs matched " "[CFG 0x%08X]\n", priv->config); if (priv->config & CFG_STATIC_CHANNEL) @@ -6028,8 +6036,8 @@ static void ipw_debug_config(struct ipw_priv *priv) else IPW_DEBUG_INFO("ESSID unlocked.\n"); if (priv->config & CFG_STATIC_BSSID) - IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n", - MAC_ARG(priv->bssid)); + IPW_DEBUG_INFO("BSSID locked to %s\n", + print_mac(mac, priv->bssid)); else IPW_DEBUG_INFO("BSSID unlocked.\n"); if (priv->capability & CAP_PRIVACY_ON) @@ -7221,6 +7229,7 @@ static int ipw_associate_network(struct ipw_priv *priv, struct ipw_supported_rates *rates, int roaming) { int err; + DECLARE_MAC_BUF(mac); if (priv->config & CFG_FIXED_RATE) ipw_set_fixed_rate(priv, network->mode); @@ -7388,9 +7397,9 @@ static int ipw_associate_network(struct ipw_priv *priv, return err; } - IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n", + IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); return 0; } @@ -8202,6 +8211,9 @@ static void ipw_rx(struct ipw_priv *priv) struct ieee80211_hdr_4addr *header; u32 r, w, i; u8 network_packet; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); r = ipw_read32(priv, IPW_RX_READ_INDEX); w = ipw_read32(priv, IPW_RX_WRITE_INDEX); @@ -8328,14 +8340,17 @@ static void ipw_rx(struct ipw_priv *priv) header))) { IPW_DEBUG_DROP("Dropping: " - MAC_FMT ", " - MAC_FMT ", " - MAC_FMT "\n", - MAC_ARG(header-> + "%s, " + "%s, " + "%s\n", + print_mac(mac, + header-> addr1), - MAC_ARG(header-> + print_mac(mac2, + header-> addr2), - MAC_ARG(header-> + print_mac(mac3, + header-> addr3)); break; } @@ -8867,6 +8882,7 @@ static int ipw_wx_set_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + DECLARE_MAC_BUF(mac); static const unsigned char any[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff @@ -8897,8 +8913,8 @@ static int ipw_wx_set_wap(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting mandatory BSSID to " MAC_FMT "\n", - MAC_ARG(wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Setting mandatory BSSID to %s\n", + print_mac(mac, wrqu->ap_addr.sa_data)); memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); @@ -8916,6 +8932,8 @@ static int ipw_wx_get_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + DECLARE_MAC_BUF(mac); + /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ mutex_lock(&priv->mutex); @@ -8926,8 +8944,8 @@ static int ipw_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", - MAC_ARG(wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %s\n", + print_mac(mac, wrqu->ap_addr.sa_data)); mutex_unlock(&priv->mutex); return 0; } @@ -10133,6 +10151,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, u8 id, hdr_len, unicast; u16 remaining_bytes; int fc; + DECLARE_MAC_BUF(mac); hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); switch (priv->ieee->iw_mode) { @@ -10143,8 +10162,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, id = ipw_add_station(priv, hdr->addr1); if (id == IPW_INVALID_STATION) { IPW_WARNING("Attempt to send data to " - "invalid cell: " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + "invalid cell: %s\n", + print_mac(mac, hdr->addr1)); goto drop; } } @@ -10460,13 +10479,15 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) { struct ipw_priv *priv = ieee80211_priv(dev); struct sockaddr *addr = p; + DECLARE_MAC_BUF(mac); + if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; mutex_lock(&priv->mutex); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); - printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", - priv->net_dev->name, MAC_ARG(priv->mac_addr)); + printk(KERN_INFO "%s: Setting MAC to %s\n", + priv->net_dev->name, print_mac(mac, priv->mac_addr)); queue_work(priv->workqueue, &priv->adapter_restart); mutex_unlock(&priv->mutex); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index a4f4c8798a83..b0d28ae0b324 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -646,6 +646,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, struct sta_info *sta; u16 fc, rate_mask; struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + DECLARE_MAC_BUF(mac); IWL_DEBUG_RATE("enter\n"); @@ -681,8 +682,8 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, hdr->addr1)); sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 26f03a0b878d..55f7d89aad8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -457,13 +457,16 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, } case IEEE80211_STYPE_PROBE_REQ:{ + DECLARE_MAC_BUF(mac1); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) IWL_DEBUG_DROP - ("Dropping (non network): " MAC_FMT - ", " MAC_FMT ", " MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + ("Dropping (non network): %s" + ", %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); return; } } @@ -474,18 +477,22 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, case IEEE80211_FTYPE_CTL: break; - case IEEE80211_FTYPE_DATA: + case IEEE80211_FTYPE_DATA: { + DECLARE_MAC_BUF(mac1); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + if (unlikely(is_duplicate_packet(priv, header))) - IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", " - MAC_FMT ", " MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); else iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags); break; } + } } int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, @@ -563,6 +570,7 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) int i; int ret = IWL_INVALID_STATION; unsigned long flags; + DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) @@ -573,8 +581,8 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_INFO("can not find STA " MAC_FMT " (total %d)\n", - MAC_ARG(addr), priv->num_stations); + IWL_DEBUG_INFO("can not find STA %s (total %d)\n", + print_mac(mac, addr), priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index f3638607d641..7b74481f5282 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1737,10 +1737,11 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) { u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); + DECLARE_MAC_BUF(mac); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, hdr->addr1)); sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); } @@ -1811,14 +1812,16 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, crl->ibss_sta_added = 0; if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { u8 sta_id = iwl_hw_find_station(priv, sta->addr); + DECLARE_MAC_BUF(mac); + /* for IBSS the call are from tasklet */ - IWL_DEBUG_HT("LQ: ADD station " MAC_FMT " \n", - MAC_ARG(sta->addr)); + IWL_DEBUG_HT("LQ: ADD station %s\n", + print_mac(mac, sta->addr)); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", - MAC_ARG(sta->addr)); - sta_id = iwl_add_station(priv, + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, sta->addr)); + sta_id = iwl_add_station(priv, sta->addr, 0, CMD_ASYNC); } if ((sta_id != IWL_INVALID_STATION)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ba35b3ac7c7e..e624f2a41e0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -164,6 +164,7 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) int start = 0; int ret = IWL_INVALID_STATION; unsigned long flags; + DECLARE_MAC_BUF(mac); if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || (priv->iw_mode == IEEE80211_IF_TYPE_AP)) @@ -181,8 +182,8 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC("can not find STA " MAC_FMT " total %d\n", - MAC_ARG(addr), priv->num_stations); + IWL_DEBUG_ASSOC("can not find STA %s total %d\n", + print_mac(mac, addr), priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -3909,12 +3910,15 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, case IEEE80211_STYPE_PROBE_REQ: if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !iwl_is_associated(priv)) { + DECLARE_MAC_BUF(mac1); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + IWL_DEBUG_DROP("Dropping (non network): " - MAC_FMT ", " MAC_FMT ", " - MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + "%s, %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); return; } } @@ -3936,28 +3940,31 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, break; - case IEEE80211_FTYPE_DATA: + case IEEE80211_FTYPE_DATA: { + DECLARE_MAC_BUF(mac1); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, header->addr2); if (unlikely(!network_packet)) IWL_DEBUG_DROP("Dropping (non network): " - MAC_FMT ", " MAC_FMT ", " - MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + "%s, %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); else if (unlikely(is_duplicate_packet(priv, header))) - IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", " - MAC_FMT ", " MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); else iwl4965_handle_data_packet(priv, 1, include_phy, rxb, &stats); break; + } default: break; @@ -4106,10 +4113,12 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, /* TODO: Need to get this copy more sefely - now good for debug */ /* - IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from " MAC_FMT ", - sta_id = %d\n", + { + DECLARE_MAC_BUF(mac); + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " + "sta_id = %d\n", agg->wait_for_ba, - MAC_ARG((u8*) &ba_resp->sta_addr_lo32), + print_mac(mac, (u8*) &ba_resp->sta_addr_lo32), ba_resp->sta_id); IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = " "%d, scd_ssn = %d\n", @@ -4123,6 +4132,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, agg->start_idx, agg->bitmap1, agg->bitmap0); + } */ iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); /* releases all the TFDs until the SSN */ @@ -4539,14 +4549,15 @@ int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, int ssn = -1; unsigned long flags; struct iwl_tid_data *tid_data; + DECLARE_MAC_BUF(mac); if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo = default_tid_to_tx_fifo[tid]; else return -EINVAL; - IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=" MAC_FMT - " tid=%d\n", MAC_ARG(da), tid); + IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=%s" + " tid=%d\n", print_mac(mac, da), tid); sta_id = iwl_hw_find_station(priv, da); if (sta_id == IWL_INVALID_STATION) @@ -4577,6 +4588,8 @@ int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, int tx_fifo_id, txq_id, sta_id, ssn = -1; struct iwl_tid_data *tid_data; int rc; + DECLARE_MAC_BUF(mac); + if (!da) { IWL_ERROR("%s: da = NULL\n", __func__); return -EINVAL; @@ -4602,8 +4615,8 @@ int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, return rc; iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA); - IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=" MAC_FMT " tid=%d\n", - MAC_ARG(da), tid); + IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=%s tid=%d\n", + print_mac(mac, da), tid); return 0; } @@ -4613,9 +4626,10 @@ int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da, { struct iwl_priv *priv = hw->priv; int sta_id; + DECLARE_MAC_BUF(mac); - IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=" MAC_FMT - " tid=%d\n", MAC_ARG(da), tid); + IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=%s" + " tid=%d\n", print_mac(mac, da), tid); sta_id = iwl_hw_find_station(priv, da); iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num); return 0; @@ -4626,9 +4640,10 @@ int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da, { struct iwl_priv *priv = hw->priv; int sta_id; + DECLARE_MAC_BUF(mac); - IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=" MAC_FMT " tid=%d\n", - MAC_ARG(da), tid); + IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=%s tid=%d\n", + print_mac(mac, da), tid); sta_id = iwl_hw_find_station(priv, da); iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 474b6402040c..cc405f4a8647 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -460,6 +460,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) int index = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; + DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -492,7 +493,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) return index; } - IWL_DEBUG_ASSOC("Add STA ID %d: " MAC_FMT "\n", index, MAC_ARG(addr)); + IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); station = &priv->stations[index]; station->used = 1; priv->num_stations++; @@ -1064,6 +1065,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; int rc = 0; + DECLARE_MAC_BUF(mac); if (!iwl_is_alive(priv)) return -1; @@ -1134,11 +1136,11 @@ static int iwl_commit_rxon(struct iwl_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = " MAC_FMT "\n", + "* bssid = %s\n", ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - MAC_ARG(priv->staging_rxon.bssid_addr)); + print_mac(mac, priv->staging_rxon.bssid_addr)); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, @@ -2693,7 +2695,9 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If this frame is part of a IBSS network, then we use the * target specific station id */ - case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_IBSS: { + DECLARE_MAC_BUF(mac); + sta_id = iwl_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -2703,12 +2707,12 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " + IWL_DEBUG_DROP("Station %s not in station map. " "Defaulting to broadcast...\n", - MAC_ARG(hdr->addr1)); + print_mac(mac, hdr->addr1)); iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; - + } default: IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); return priv->hw_setting.bcast_sta_id; @@ -2781,8 +2785,10 @@ static int iwl_tx_skb(struct iwl_priv *priv, hdr_len = ieee80211_get_hdrlen(fc); sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", + print_mac(mac, hdr->addr1)); goto drop; } @@ -4385,6 +4391,8 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) { + DECLARE_MAC_BUF(mac); + IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); @@ -4395,10 +4403,10 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n", - MAC_ARG(rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n", - MAC_ARG(rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", + print_mac(mac, rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", + print_mac(mac, rxon->bssid_addr)); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif @@ -6322,6 +6330,7 @@ static void iwl_down(struct iwl_priv *priv) static int __iwl_up(struct iwl_priv *priv) { + DECLARE_MAC_BUF(mac); int rc, i; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { @@ -6381,8 +6390,8 @@ static int __iwl_up(struct iwl_priv *priv) /* MAC Address location in EEPROM same for 3945/4965 */ get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n", - MAC_ARG(priv->mac_addr)); + IWL_DEBUG_INFO("MAC address: %s\n", + print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); @@ -6728,6 +6737,7 @@ static void iwl_bg_post_associate(struct work_struct *data) int rc = 0; struct ieee80211_conf *conf = NULL; + DECLARE_MAC_BUF(mac); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); @@ -6735,8 +6745,9 @@ static void iwl_bg_post_associate(struct work_struct *data) } - IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n", - priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %s\n", + priv->assoc_id, + print_mac(mac, priv->active_rxon.bssid_addr)); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6916,11 +6927,12 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw, { struct iwl_priv *priv = hw->priv; unsigned long flags; + DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); if (conf->mac_addr) - IWL_DEBUG_MAC80211("enter: MAC " MAC_FMT "\n", - MAC_ARG(conf->mac_addr)); + IWL_DEBUG_MAC80211("enter: MAC %s\n", + print_mac(mac, conf->mac_addr)); if (priv->interface_id) { IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); @@ -7094,6 +7106,7 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf) { struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -7111,8 +7124,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n", - MAC_ARG(conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %s\n", + print_mac(mac, conf->bssid)); if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { @@ -7131,8 +7144,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n", - MAC_ARG(conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %s\n", + print_mac(mac, conf->bssid)); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -7282,8 +7295,10 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, sta_id = iwl_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - " MAC_FMT " not in station map.\n", - MAC_ARG(addr)); + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index b79dabc8c01c..6cea3118b7c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -459,6 +459,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) int index = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; + DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -493,7 +494,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) } - IWL_DEBUG_ASSOC("Add STA ID %d: " MAC_FMT "\n", index, MAC_ARG(addr)); + IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); station = &priv->stations[index]; station->used = 1; priv->num_stations++; @@ -1083,6 +1084,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + DECLARE_MAC_BUF(mac); int rc = 0; if (!iwl_is_alive(priv)) @@ -1160,11 +1162,11 @@ static int iwl_commit_rxon(struct iwl_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = " MAC_FMT "\n", + "* bssid = %s\n", ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - MAC_ARG(priv->staging_rxon.bssid_addr)); + print_mac(mac, priv->staging_rxon.bssid_addr)); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, @@ -2748,6 +2750,7 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; u16 fc = le16_to_cpu(hdr->frame_control); + DECLARE_MAC_BUF(mac); /* If this frame is broadcast or not data then use the broadcast * station id */ @@ -2781,9 +2784,9 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " + IWL_DEBUG_DROP("Station %s not in station map. " "Defaulting to broadcast...\n", - MAC_ARG(hdr->addr1)); + print_mac(mac, hdr->addr1)); iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; @@ -2859,8 +2862,10 @@ static int iwl_tx_skb(struct iwl_priv *priv, hdr_len = ieee80211_get_hdrlen(fc); sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", + print_mac(mac, hdr->addr1)); goto drop; } @@ -4703,6 +4708,8 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) { + DECLARE_MAC_BUF(mac); + IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); @@ -4713,10 +4720,10 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n", - MAC_ARG(rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n", - MAC_ARG(rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", + print_mac(mac, rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", + print_mac(mac, rxon->bssid_addr)); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif @@ -6670,6 +6677,7 @@ static void iwl_down(struct iwl_priv *priv) static int __iwl_up(struct iwl_priv *priv) { + DECLARE_MAC_BUF(mac); int rc, i; u32 hw_rf_kill = 0; @@ -6742,8 +6750,8 @@ static int __iwl_up(struct iwl_priv *priv) /* MAC Address location in EEPROM same for 3945/4965 */ get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n", - MAC_ARG(priv->mac_addr)); + IWL_DEBUG_INFO("MAC address: %s\n", + print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); @@ -7096,14 +7104,16 @@ static void iwl_bg_post_associate(struct work_struct *data) int rc = 0; struct ieee80211_conf *conf = NULL; + DECLARE_MAC_BUF(mac); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); return; } - IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n", - priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %s\n", + priv->assoc_id, + print_mac(mac, priv->active_rxon.bssid_addr)); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -7299,11 +7309,12 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw, { struct iwl_priv *priv = hw->priv; unsigned long flags; + DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); if (conf->mac_addr) - IWL_DEBUG_MAC80211("enter: MAC " MAC_FMT "\n", - MAC_ARG(conf->mac_addr)); + IWL_DEBUG_MAC80211("enter: MAC %s\n", + print_mac(mac, conf->mac_addr)); if (priv->interface_id) { IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); @@ -7494,6 +7505,7 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf) { struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -7511,8 +7523,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n", - MAC_ARG(conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %s\n", + print_mac(mac, conf->bssid)); if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { @@ -7531,8 +7543,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n", - MAC_ARG(conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %s\n", + print_mac(mac, conf->bssid)); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -7666,6 +7678,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); int rc = 0; u8 sta_id; @@ -7682,8 +7695,8 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, sta_id = iwl_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - " MAC_FMT " not in station map.\n", - MAC_ARG(addr)); + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); return -EINVAL; } diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 3131afcf4590..2c6ddb1f0072 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -16,6 +16,7 @@ static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static void print_assoc_req(const char * extra, struct assoc_request * assoc_req) { + DECLARE_MAC_BUF(mac); lbs_deb_assoc( "#### Association Request: %s\n" " flags: 0x%08lX\n" @@ -23,13 +24,13 @@ static void print_assoc_req(const char * extra, struct assoc_request * assoc_req " channel: %d\n" " band: %d\n" " mode: %d\n" - " BSSID: " MAC_FMT "\n" + " BSSID: %s\n" " Encryption:%s%s%s\n" " auth: %d\n", extra, assoc_req->flags, escape_essid(assoc_req->ssid, assoc_req->ssid_len), assoc_req->channel, assoc_req->band, assoc_req->mode, - MAC_ARG(assoc_req->bssid), + print_mac(mac, assoc_req->bssid), assoc_req->secinfo.WPAenabled ? " WPA" : "", assoc_req->secinfo.WPA2enabled ? " WPA2" : "", assoc_req->secinfo.wep_enabled ? " WEP" : "", @@ -104,16 +105,17 @@ static int assoc_helper_bssid(wlan_private *priv, wlan_adapter *adapter = priv->adapter; int ret = 0; struct bss_descriptor * bss; + DECLARE_MAC_BUF(mac); - lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT, - MAC_ARG(assoc_req->bssid)); + lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s", + print_mac(mac, assoc_req->bssid)); /* Search for index position in list for requested MAC */ bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid, assoc_req->mode); if (bss == NULL) { - lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, " - "cannot associate.\n", MAC_ARG(assoc_req->bssid)); + lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, " + "cannot associate.\n", print_mac(mac, assoc_req->bssid)); goto out; } @@ -481,6 +483,7 @@ void libertas_association_worker(struct work_struct *work) struct assoc_request * assoc_req = NULL; int ret = 0; int find_any_ssid = 0; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_ASSOC); @@ -629,10 +632,10 @@ void libertas_association_worker(struct work_struct *work) if (success) { lbs_deb_assoc("ASSOC: association attempt successful. " - "Associated to '%s' (" MAC_FMT ")\n", + "Associated to '%s' (%s)\n", escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), - MAC_ARG(adapter->curbssparams.bssid)); + print_mac(mac, adapter->curbssparams.bssid)); libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index d64ad87db459..fe70e30b1f3c 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -159,6 +159,7 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec; wlan_adapter *adapter = priv->adapter; int ret = 0; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_CMD); @@ -169,8 +170,8 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n", adapter->fwreleasenumber[2], adapter->fwreleasenumber[1], adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]); - lbs_deb_cmd("GET_HW_SPEC: MAC addr " MAC_FMT "\n", - MAC_ARG(hwspec->permanentaddr)); + lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n", + print_mac(mac, hwspec->permanentaddr)); lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", hwspec->hwifversion, hwspec->version); diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 816f42e4f5b4..cb00b080409e 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -63,6 +63,7 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, int numscansdone = 0, res; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + DECLARE_MAC_BUF(mac); struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, @@ -75,9 +76,9 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %04ld | " MAC_FMT " |", + "%02u| %03d | %04ld | %s |", numscansdone, iter_bss->channel, iter_bss->rssi, - MAC_ARG(iter_bss->bssid)); + print_mac(mac, iter_bss->bssid)); pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", ibss ? 'A' : 'I', privacy ? 'P' : ' ', diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 0ad1362b14e2..8dcff00574f3 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -293,6 +293,7 @@ int libertas_cmd_80211_authenticate(wlan_private * priv, struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; int ret = -1; u8 *bssid = pdata_buf; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -319,8 +320,8 @@ int libertas_cmd_80211_authenticate(wlan_private * priv, memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n", - MAC_ARG(bssid), pauthenticate->authtype); + lbs_deb_join("AUTH_CMD: BSSID is : %s auth=0x%X\n", + print_mac(mac, bssid), pauthenticate->authtype); ret = 0; out: @@ -598,6 +599,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, int cmdappendsize = 0; int ret = 0; u16 ratesize = 0; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -621,8 +623,9 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, /* information on BSSID descriptor passed to FW */ lbs_deb_join( - "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n", - MAC_ARG(join_cmd->bss.bssid), join_cmd->bss.ssid); + "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", + print_mac(mac, join_cmd->bss.bssid), + join_cmd->bss.ssid); /* failtimeout */ join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); @@ -829,6 +832,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, struct cmd_ds_802_11_ad_hoc_result *padhocresult; union iwreq_data wrqu; struct bss_descriptor *bss; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -894,8 +898,8 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel); - lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n", - MAC_ARG(padhocresult->bssid)); + lbs_deb_join("ADHOC_RESP: BSSID = %s\n", + print_mac(mac, padhocresult->bssid)); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a54171af7b97..5ead08312e1e 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -677,6 +677,7 @@ static void libertas_set_multicast_list(struct net_device *dev) wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; int oldpacketfilter; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_NET); @@ -723,14 +724,9 @@ static void libertas_set_multicast_list(struct net_device *dev) dev->mc_count); for (i = 0; i < dev->mc_count; i++) { - lbs_deb_net("Multicast address %d:" - MAC_FMT "\n", i, - adapter->multicastlist[i][0], - adapter->multicastlist[i][1], - adapter->multicastlist[i][2], - adapter->multicastlist[i][3], - adapter->multicastlist[i][4], - adapter->multicastlist[i][5]); + lbs_deb_net("Multicast address %d:%s\n", + i, print_mac(mac, + adapter->multicastlist[i])); } /* send multicast addresses to firmware */ libertas_prepare_and_send_command(priv, diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index e2e9ebcd8340..8f073ad1957f 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -777,6 +777,7 @@ int wlan_scan_networks(wlan_private * priv, #ifdef CONFIG_LIBERTAS_DEBUG struct bss_descriptor * iter_bss; int i = 0; + DECLARE_MAC_BUF(mac); #endif lbs_deb_enter(LBS_DEB_SCAN); @@ -831,8 +832,8 @@ int wlan_scan_networks(wlan_private * priv, /* Dump the scan table */ mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { - lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n", - i++, MAC_ARG(iter_bss->bssid), (s32) iter_bss->rssi, + lbs_deb_scan("Scan:(%02d) %s, RSSI[%03d], SSID[%s]\n", + i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi, escape_essid(iter_bss->ssid, iter_bss->ssid_len)); } mutex_unlock(&adapter->lock); @@ -876,6 +877,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; + DECLARE_MAC_BUF(mac); struct ieeetypes_countryinfoset *pcountryinfo; u8 *pos, *end, *p; u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; @@ -906,7 +908,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, *bytesleft -= beaconsize; memcpy(bss->bssid, pos, ETH_ALEN); - lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", MAC_ARG(bss->bssid)); + lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid)); pos += ETH_ALEN; if ((end - pos) < 12) { @@ -1724,6 +1726,7 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) struct bss_descriptor new; struct bss_descriptor * found = NULL; struct bss_descriptor * oldest = NULL; + DECLARE_MAC_BUF(mac); /* Process the data fields and IEs returned for this BSS */ memset(&new, 0, sizeof (struct bss_descriptor)); @@ -1762,9 +1765,8 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) continue; } - lbs_deb_scan("SCAN_RESP: BSSID = " MAC_FMT "\n", - new.bssid[0], new.bssid[1], new.bssid[2], - new.bssid[3], new.bssid[4], new.bssid[5]); + lbs_deb_scan("SCAN_RESP: BSSID = %s\n", + print_mac(mac, new.bssid)); /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index f8036efd7294..0b2103e0af57 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1160,7 +1160,7 @@ static int wlan_get_encode(struct net_device *dev, dwrq->flags |= IW_ENCODE_NOKEY; - lbs_deb_wext("key: " MAC_FMT ", keylen %d\n", + lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n", extra[0], extra[1], extra[2], extra[3], extra[4], extra[5], dwrq->length); @@ -1980,13 +1980,14 @@ static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, wlan_adapter *adapter = priv->adapter; struct assoc_request * assoc_req; int ret = 0; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_WEXT); if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; - lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data)); + lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data)); mutex_lock(&adapter->lock); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index d8a59afa7178..c2d71afd57e5 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -737,6 +737,7 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { win_req_t req; memreq_t mem; u_char __iomem *ramBase = NULL; + DECLARE_MAC_BUF(mac); DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); @@ -805,12 +806,13 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); - printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id " - "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq, - (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI), - (int) readb(ramBase+NETWAVE_EREG_NI+1)); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx" + "id %c%c, hw_addr %s\n", + dev->name, dev->base_addr, dev->irq, + (u_long) ramBase, + (int) readb(ramBase+NETWAVE_EREG_NI), + (int) readb(ramBase+NETWAVE_EREG_NI+1), + print_mac(mac, dev->dev_addr)); /* get revision words */ printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 062286dc8e15..ca6c2da7bc5d 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2232,6 +2232,7 @@ static int orinoco_init(struct net_device *dev) struct hermes_idstring nickbuf; u16 reclen; int len; + DECLARE_MAC_BUF(mac); /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ @@ -2274,10 +2275,8 @@ static int orinoco_init(struct net_device *dev) goto out; } - printk(KERN_DEBUG "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\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]); + printk(KERN_DEBUG "%s: MAC address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 77ea13bf0c02..6d80ca421cf0 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -2029,12 +2029,12 @@ static void format_event(islpci_private *priv, char *dest, const char *str, const struct obj_mlme *mlme, u16 *length, int error) { - const u8 *a = mlme->address; + DECLARE_MAC_BUF(mac); int n = snprintf(dest, IW_CUSTOM_MAX, - "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)", + "%s %s %s %s (%2.2X)", str, ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), - a[0], a[1], a[2], a[3], a[4], a[5], + print_mac(mac, mlme->address), (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") : ""), mlme->code); BUG_ON(n > IW_CUSTOM_MAX); @@ -2105,15 +2105,13 @@ struct ieee80211_beacon_phdr { #define WLAN_EID_GENERIC 0xdd static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" - static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, u8 *wpa_ie, size_t wpa_ie_len) { struct list_head *ptr; struct islpci_bss_wpa_ie *bss = NULL; + DECLARE_MAC_BUF(mac); if (wpa_ie_len > MAX_WPA_IE_LEN) wpa_ie_len = MAX_WPA_IE_LEN; @@ -2154,8 +2152,8 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, bss->wpa_ie_len = wpa_ie_len; bss->last_update = jiffies; } else { - printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR - "\n", MAC2STR(bssid)); + printk(KERN_DEBUG "Failed to add BSS WPA entry for " + "%s\n", print_mac(mac, bssid)); } /* expire old entries from WPA list */ @@ -2221,6 +2219,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, { struct ieee80211_beacon_phdr *hdr; u8 *pos, *end; + DECLARE_MAC_BUF(mac); if (!priv->wpa) return; @@ -2231,7 +2230,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, while (pos < end) { if (pos + 2 + pos[1] > end) { printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " - "for " MACSTR "\n", MAC2STR(addr)); + "for %s\n", print_mac(mac, addr)); return; } if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && @@ -2270,6 +2269,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, size_t len = 0; /* u16, better? */ u8 *payload = NULL, *pos = NULL; int ret; + DECLARE_MAC_BUF(mac); /* I think all trapable objects are listed here. * Some oids have a EX version. The difference is that they are emitted @@ -2358,14 +2358,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, break; memcpy(&confirm->address, mlmeex->address, ETH_ALEN); - printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", - mlmeex->address[0], - mlmeex->address[1], - mlmeex->address[2], - mlmeex->address[3], - mlmeex->address[4], - mlmeex->address[5] - ); + printk(KERN_DEBUG "Authenticate from: address:\t%s\n", + print_mac(mac, mlmeex->address)); confirm->id = -1; /* or mlmeex->id ? */ confirm->state = 0; /* not used */ confirm->code = 0; @@ -2410,15 +2404,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from " - "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", - mlmeex->address[0], - mlmeex->address[1], - mlmeex->address[2], - mlmeex->address[3], - mlmeex->address[4], - mlmeex->address[5] - ); + printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", + print_mac(mac, mlmeex->address)); kfree(confirm); break; } @@ -2454,15 +2441,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from " - "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", - mlmeex->address[0], - mlmeex->address[1], - mlmeex->address[2], - mlmeex->address[3], - mlmeex->address[4], - mlmeex->address[5] - ); + printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", + print_mac(mac, mlmeex->address)); kfree(confirm); break; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 429bca8d0b5f..f87fe10059ae 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -412,6 +412,7 @@ static int ray_config(struct pcmcia_device *link) memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; ray_dev_t *local = netdev_priv(dev); + DECLARE_MAC_BUF(mac); DEBUG(1, "ray_config(0x%p)\n", link); @@ -482,10 +483,8 @@ static int ray_config(struct pcmcia_device *link) strcpy(local->node.dev_name, dev->name); link->dev_node = &local->node; - printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ", - dev->name, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n", + dev->name, dev->irq, print_mac(mac, dev->dev_addr)); return 0; @@ -2610,6 +2609,7 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) UCHAR *p; struct freq_hop_element *pfh; UCHAR c[33]; + DECLARE_MAC_BUF(mac); link = this_device; if (!link) @@ -2639,9 +2639,8 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) nettype[local->sparm.b5.a_network_type], c); p = local->bss_id; - len += sprintf(buf + len, - "BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", - p[0],p[1],p[2],p[3],p[4],p[5]); + len += sprintf(buf + len, "BSSID = %s\n", + print_mac(mac, p)); len += sprintf(buf + len, "Country code = %d\n", local->sparm.b5.a_curr_country_code); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 38e2188937c5..398c20105c81 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1362,8 +1362,10 @@ static int rt2400pci_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: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index f6115c626fa7..e8d63aaab7bc 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1509,8 +1509,11 @@ static int rt2500pci_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: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", + print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 847bd7f58eed..614600c5510d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1233,8 +1233,10 @@ static int rt2500usb_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: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 730bed5a1984..09c8c96e2f83 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2019,8 +2019,10 @@ static int rt61pci_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: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index b047c7c0f9ee..3397881bd63d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1475,8 +1475,10 @@ static int rt73usb_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: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 7dbf11e30db3..bf9f0cc5a645 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -574,6 +574,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, struct ieee80211_channel *channel; u16 txpwr, reg; int err, i; + DECLARE_MAC_BUF(mac); dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); if (!dev) { @@ -681,8 +682,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } - printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n", - wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n", + wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), priv->asic_rev, priv->rf_init == rtl8225_rf_init ? "rtl8225" : "rtl8225z2"); diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 33ed9fe95f3d..a1f8a1687842 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -880,6 +880,8 @@ static void wv_82586_reconfig(struct net_device * dev) */ static void wv_psa_show(psa_t * p) { + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -891,22 +893,13 @@ static void wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG - "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2], - p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5], - p->psa_unused0[6]); + printk(KERN_DEBUG "psa_unused0[]: %s\n", + print_mac(mac, p->psa_unused0)); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG - "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1], - p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3], - p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]); - printk(KERN_DEBUG - "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_local_mac_addr[0], p->psa_local_mac_addr[1], - p->psa_local_mac_addr[2], p->psa_local_mac_addr[3], - p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", + print_mac(mac, p->psa_univ_mac_addr)); + printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", + print_mac(mac, p->psa_local_mac_addr)); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); @@ -1248,14 +1241,14 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */ { /* Name of the function */ int i; int maxi; + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG - "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", - msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); + "%s: %s(): dest %s, length %d\n", + msg1, msg2, print_mac(mac, p), length); printk(KERN_DEBUG - "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", - msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], - p[13]); + "%s: %s(): src %s, type 0x%02X%02X\n", + msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1286,7 +1279,9 @@ static void wv_init_info(struct net_device * dev) short ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; psa_t psa; - int i; +#ifdef DEBUG_BASIC_SHOW + DECLARE_MAC_BUF(mac); +#endif /* Read the parameter storage area */ psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1303,10 +1298,8 @@ static void wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff. */ - printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr); - for (i = 0; i < WAVELAN_ADDR_SIZE; i++) - printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); - printk(", IRQ %d", dev->irq); + printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d", + dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq); /* Print current network ID. */ if (psa.psa_nwid_select) @@ -3596,15 +3589,15 @@ static void wv_82586_config(struct net_device * dev) WAVELAN_ADDR_SIZE >> 1); #ifdef DEBUG_CONFIG_INFO + { + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for (dmi = dev->mc_list; dmi; dmi = dmi->next) - printk(KERN_DEBUG - " %02x:%02x:%02x:%02x:%02x:%02x\n", - dmi->dmi_addr[0], dmi->dmi_addr[1], - dmi->dmi_addr[2], dmi->dmi_addr[3], - dmi->dmi_addr[4], dmi->dmi_addr[5]); + printk(KERN_DEBUG " %s\n", + print_mac(mac, dmi->dmi_addr)); + } #endif } diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 9b7f44957869..577c647824fe 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1042,6 +1042,7 @@ wv_82593_reconfig(struct net_device * dev) static void wv_psa_show(psa_t * p) { + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -1055,29 +1056,13 @@ wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - p->psa_unused0[0], - p->psa_unused0[1], - p->psa_unused0[2], - p->psa_unused0[3], - p->psa_unused0[4], - p->psa_unused0[5], - p->psa_unused0[6]); + printk(KERN_DEBUG "psa_unused0[]: %s\n", + print_mac(mac, p->psa_unused0)); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_univ_mac_addr[0], - p->psa_univ_mac_addr[1], - p->psa_univ_mac_addr[2], - p->psa_univ_mac_addr[3], - p->psa_univ_mac_addr[4], - p->psa_univ_mac_addr[5]); - printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_local_mac_addr[0], - p->psa_local_mac_addr[1], - p->psa_local_mac_addr[2], - p->psa_local_mac_addr[3], - p->psa_local_mac_addr[4], - p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", + print_mac(mac, p->psa_univ_mac_addr)); + printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", + print_mac(mac, p->psa_local_mac_addr)); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); @@ -1277,11 +1262,12 @@ wv_packet_info(u_char * p, /* Packet to dump */ { int i; int maxi; + DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", - msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); - printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", - msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); + printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n", + msg1, msg2, print_mac(mac, p), length); + printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n", + msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1312,7 +1298,7 @@ wv_init_info(struct net_device * dev) { kio_addr_t base = dev->base_addr; psa_t psa; - int i; + DECLARE_MAC_BUF(mac); /* Read the parameter storage area */ psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1329,10 +1315,10 @@ wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff */ - printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, hw_addr", - dev->name, base, dev->irq); - for(i = 0; i < WAVELAN_ADDR_SIZE; i++) - printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); + printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, " + "hw_addr %s", + dev->name, base, dev->irq, + print_mac(mac, dev->dev_addr)); /* Print current network id */ if(psa.psa_nwid_select) @@ -3691,12 +3677,12 @@ wv_82593_config(struct net_device * dev) int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; #ifdef DEBUG_CONFIG_INFO + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for(dmi=dev->mc_list; dmi; dmi=dmi->next) - printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n", - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] ); + printk(KERN_DEBUG " %s\n", + print_mac(mac, dmi->dmi_addr)); #endif /* Initialize adapter's ethernet multicast addresses */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 2690f291e3f7..42a36b3f3ff7 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -860,11 +860,10 @@ static int wl3501_esbq_confirm(struct wl3501_card *this) static void wl3501_online(struct net_device *dev) { struct wl3501_card *this = netdev_priv(dev); + DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: Wireless LAN online. BSSID: " - "%02X %02X %02X %02X %02X %02X\n", dev->name, - this->bssid[0], this->bssid[1], this->bssid[2], - this->bssid[3], this->bssid[4], this->bssid[5]); + printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n", + dev->name, print_mac(mac, this->bssid)); netif_wake_queue(dev); } @@ -1966,6 +1965,7 @@ static int wl3501_config(struct pcmcia_device *link) struct net_device *dev = link->priv; int i = 0, j, last_fn, last_ret; struct wl3501_card *this; + DECLARE_MAC_BUF(mac); /* Try allocating IO ports. This tries a few fixed addresses. If you * want, you can also read the card's config table to pick addresses -- @@ -2019,14 +2019,14 @@ static int wl3501_config(struct pcmcia_device *link) } strcpy(this->node.dev_name, dev->name); - /* print probe information */ - printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:", - dev->name, this->base_addr, (int)dev->irq); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = ((char *)&this->mac_addr)[i]; - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - } - printk("\n"); + + /* print probe information */ + printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " + "MAC addr in flash ROM:%s\n", + dev->name, this->base_addr, (int)dev->irq, + print_mac(mac, dev->dev_addr)); /* * Initialize card parameters - added by jss */ diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 495904218b1b..750c0f99e86f 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -377,6 +377,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) [0] = { .addr = CR_MAC_ADDR_P1 }, [1] = { .addr = CR_MAC_ADDR_P2 }, }; + DECLARE_MAC_BUF(mac); reqs[0].value = (mac_addr[3] << 24) | (mac_addr[2] << 16) @@ -386,7 +387,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) | mac_addr[4]; dev_dbg_f(zd_chip_dev(chip), - "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr)); + "mac addr %s\n", print_mac(mac, mac_addr)); mutex_lock(&chip->mutex); r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 451308d7095d..06b342b39792 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -289,12 +289,13 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p) struct sockaddr *addr = p; struct zd_mac *mac = zd_netdev_mac(netdev); struct zd_chip *chip = &mac->chip; + DECLARE_MAC_BUF(mac2); if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; dev_dbg_f(zd_mac_dev(mac), - "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data)); + "Setting MAC to %s\n", print_mac(mac2, addr->sa_data)); if (netdev->flags & IFF_UP) { r = zd_write_mac_addr(chip, addr->sa_data); @@ -329,6 +330,7 @@ void zd_mac_set_multicast_list(struct net_device *dev) struct zd_mc_hash hash; struct dev_mc_list *mc; unsigned long flags; + DECLARE_MAC_BUF(mac2); if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) || ieee->iw_mode == IW_MODE_MONITOR) { @@ -336,8 +338,8 @@ void zd_mac_set_multicast_list(struct net_device *dev) } else { zd_mc_clear(&hash); for (mc = dev->mc_list; mc; mc = mc->next) { - dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n", - MAC_ARG(mc->dmi_addr)); + dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n", + print_mac(mac2, mc->dmi_addr)); zd_mc_add_addr(&hash, mc->dmi_addr); } } diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 709623e1c611..87f002ade531 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -374,6 +374,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, #else int bar = 1; #endif + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -480,12 +481,10 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, if (i) goto err_out_unmap_status; - printk(KERN_INFO "%s: %s type %8x at %p, ", + printk(KERN_INFO "%s: %s type %8x at %p, %s, IRQ %d.\n", dev->name, pci_id_tbl[chip_idx].name, - ioread32(ioaddr + ChipRev), ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + ioread32(ioaddr + ChipRev), ioaddr, + print_mac(mac, dev->dev_addr), irq); if (np->drv_flags & HasMII) { int phy, phy_idx = 0; @@ -1101,11 +1100,11 @@ static int yellowfin_rx(struct net_device *dev) memcmp(le32_to_cpu(yp->rx_ring_dma + entry*sizeof(struct yellowfin_desc)), "\377\377\377\377\377\377", 6) != 0) { - if (bogus_rx++ == 0) - printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:" - "%2.2x:%2.2x.\n", - dev->name, buf_addr[0], buf_addr[1], buf_addr[2], - buf_addr[3], buf_addr[4], buf_addr[5]); + if (bogus_rx++ == 0) { + DECLARE_MAC_BUF(mac); + printk(KERN_WARNING "%s: Bad frame to %s\n", + dev->name, print_mac(mac, buf_addr)); + } #endif } else { struct sk_buff *skb; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 43712c7b9ecf..a86c022d6a94 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -370,6 +370,7 @@ static int __init znet_probe (void) struct net_device *dev; char *p; int err = -ENOMEM; + DECLARE_MAC_BUF(mac); /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) @@ -392,14 +393,14 @@ static int __init znet_probe (void) dev->base_addr = netinfo->iobase1; dev->irq = netinfo->irq1; - printk(KERN_INFO "%s: ZNET at %#3lx,", dev->name, dev->base_addr); - /* The station address is in the "netidblk" at 0x0f0000. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]); + dev->dev_addr[i] = netinfo->netid[i]; - printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1, - netinfo->dma2); + printk(KERN_INFO "%s: ZNET at %#3lx, %s" + ", using IRQ %d DMA %d and %d.\n", + dev->name, dev->base_addr, print_mac(mac, dev->dev_addr), + dev->irq, netinfo->dma1, netinfo->dma2); if (znet_debug > 1) { printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n", diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index fb215eb6dcf3..3926b2aa9cca 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -151,6 +151,7 @@ static int __devinit zorro8390_init(struct net_device *dev, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; + DECLARE_MAC_BUF(mac); /* Reset card. Who knows what dain-bramaged state it was left in. */ { @@ -211,12 +212,12 @@ static int __devinit zorro8390_init(struct net_device *dev, i = request_irq(IRQ_AMIGA_PORTS, __ei_interrupt, IRQF_SHARED, DRV_NAME, dev); if (i) return i; - for(i = 0; i < ETHER_ADDR_LEN; i++) { -#ifdef DEBUG - printk(" %2.2x", SA_prom[i]); -#endif + for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - } + +#ifdef DEBUG + printk("%s", print_mac(mac, dev->dev_addr)); +#endif ei_status.name = name; ei_status.tx_start_page = start_page; @@ -243,10 +244,8 @@ static int __devinit zorro8390_init(struct net_device *dev, return err; } - printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %s\n", + dev->name, name, board, print_mac(mac, dev->dev_addr)); return 0; } diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 3213f6f4aa58..0e791e2c0c5a 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -120,6 +120,14 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) #ifdef CONFIG_SYSCTL extern struct ctl_table ether_table[]; #endif + +/* + * Display a 6 byte device address (MAC) in a readable format. + */ +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +extern char *print_mac(char *buf, const u8 *addr); +#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused + #endif #endif /* _LINUX_IF_ETHER_H */ diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index bbd85cd61ed5..164d13211165 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -119,11 +119,6 @@ do { if (ieee80211_debug_level & (level)) \ #define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) #endif /* CONFIG_IEEE80211_DEBUG */ -/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */ - -#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] - /* escape_essid() is intended to be used in debug (and possibly error) * messages. It should never be used for passing essid to user space. */ const char *escape_essid(const char *essid, u8 essid_len); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a2c14f95b9a0..947f3c820e42 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1106,8 +1106,4 @@ static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr) IEEE80211_FCTL_MOREFRAGS) != 0; } -#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \ - ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5] - #endif /* MAC80211_H */ diff --git a/net/802/tr.c b/net/802/tr.c index 55c76d77d322..aa3c2e936abc 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -283,8 +283,10 @@ void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_device * if(entry) { #if TR_SR_DEBUG -printk("source routing for %02X:%02X:%02X:%02X:%02X:%02X\n",trh->daddr[0], - trh->daddr[1],trh->daddr[2],trh->daddr[3],trh->daddr[4],trh->daddr[5]); +{ +DECLARE_MAC_BUF(mac); +printk("source routing for %s\n",print_mac(mac, trh->daddr)); +} #endif if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8) { @@ -366,10 +368,9 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) if(entry==NULL) { #if TR_SR_DEBUG -printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", - trh->saddr[0],trh->saddr[1],trh->saddr[2], - trh->saddr[3],trh->saddr[4],trh->saddr[5], - ntohs(trh->rcf)); + DECLARE_MAC_BUF(mac); + printk("adding rif_entry: addr:%s rcf:%04X\n", + print_mac(mac, trh->saddr), ntohs(trh->rcf)); #endif /* * Allocate our new entry. A failure to allocate loses @@ -414,10 +415,11 @@ printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", !(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) { #if TR_SR_DEBUG -printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", - trh->saddr[0],trh->saddr[1],trh->saddr[2], - trh->saddr[3],trh->saddr[4],trh->saddr[5], - ntohs(trh->rcf)); +{ +DECLARE_MAC_BUF(mac); +printk("updating rif_entry: addr:%s rcf:%04X\n", + print_mac(mac, trh->saddr), ntohs(trh->rcf)); +} #endif entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK); memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short)); @@ -528,6 +530,7 @@ static int rif_seq_show(struct seq_file *seq, void *v) { int j, rcf_len, segment, brdgnmb; struct rif_cache *entry = v; + DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) seq_puts(seq, @@ -537,10 +540,9 @@ static int rif_seq_show(struct seq_file *seq, void *v) long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout) - (long) jiffies; - seq_printf(seq, "%s %02X:%02X:%02X:%02X:%02X:%02X %7li ", + seq_printf(seq, "%s %s %7li ", dev?dev->name:"?", - entry->addr[0],entry->addr[1],entry->addr[2], - entry->addr[3],entry->addr[4],entry->addr[5], + print_mac(mac, entry->addr), ttl/HZ); if (entry->local_ring) diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index e9a51a69870e..92cd74973c97 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -997,6 +997,7 @@ static int aarp_seq_show(struct seq_file *seq, void *v) struct aarp_iter_state *iter = seq->private; struct aarp_entry *entry = v; unsigned long now = jiffies; + DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) seq_puts(seq, @@ -1007,13 +1008,7 @@ static int aarp_seq_show(struct seq_file *seq, void *v) ntohs(entry->target_addr.s_net), (unsigned int) entry->target_addr.s_node, entry->dev ? entry->dev->name : "????"); - seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X", - entry->hwaddr[0] & 0xFF, - entry->hwaddr[1] & 0xFF, - entry->hwaddr[2] & 0xFF, - entry->hwaddr[3] & 0xFF, - entry->hwaddr[4] & 0xFF, - entry->hwaddr[5] & 0xFF); + seq_printf(seq, "%s", print_mac(mac, entry->hwaddr)); seq_printf(seq, " %8s", dt2str((long)entry->expires_at - (long)now)); if (iter->table == unresolved) diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 81eb4f4cbe10..c742d37bfb97 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -709,17 +709,13 @@ static int br2684_seq_show(struct seq_file *seq, void *v) br2684_devs); const struct net_device *net_dev = brdev->net_dev; const struct br2684_vcc *brvcc; + DECLARE_MAC_BUF(mac); - seq_printf(seq, "dev %.16s: num=%d, mac=%02X:%02X:" - "%02X:%02X:%02X:%02X (%s)\n", net_dev->name, - brdev->number, - net_dev->dev_addr[0], - net_dev->dev_addr[1], - net_dev->dev_addr[2], - net_dev->dev_addr[3], - net_dev->dev_addr[4], - net_dev->dev_addr[5], - brdev->mac_was_set ? "set" : "auto"); + seq_printf(seq, "dev %.16s: num=%d, mac=%s (%s)\n", + net_dev->name, + brdev->number, + print_mac(mac, net_dev->dev_addr), + brdev->mac_was_set ? "set" : "auto"); list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { seq_printf(seq, " vcc %d.%d.%d: encaps=%s" diff --git a/net/atm/lec.c b/net/atm/lec.c index 813a090dcaf4..c909c76223e1 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -266,6 +266,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) char buf[300]; int i = 0; #endif /* DUMP_PACKETS >0 */ + DECLARE_MAC_BUF(mac); pr_debug("lec_start_xmit called\n"); if (!priv->lecd) { @@ -373,19 +374,15 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { pr_debug("%s:lec_start_xmit: queuing packet, ", dev->name); - pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - lec_h->h_dest[0], lec_h->h_dest[1], - lec_h->h_dest[2], lec_h->h_dest[3], - lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %s\n", + print_mac(mac, lec_h->h_dest)); skb_queue_tail(&entry->tx_wait, skb); } else { pr_debug ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", dev->name); - pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - lec_h->h_dest[0], lec_h->h_dest[1], - lec_h->h_dest[2], lec_h->h_dest[3], - lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %s\n", + print_mac(mac, lec_h->h_dest)); priv->stats.tx_dropped++; dev_kfree_skb(skb); } @@ -397,9 +394,8 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { pr_debug("lec.c: emptying tx queue, "); - pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], - lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %s\n", + print_mac(mac, lec_h->h_dest)); lec_send(vcc, skb2, priv); } @@ -453,6 +449,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) struct lec_arp_table *entry; int i; char *tmp; /* FIXME */ + DECLARE_MAC_BUF(mac); atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); mesg = (struct atmlec_msg *)skb->data; @@ -539,13 +536,9 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) struct net_bridge_fdb_entry *f; pr_debug - ("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, mesg->content.proxy.mac_addr[0], - mesg->content.proxy.mac_addr[1], - mesg->content.proxy.mac_addr[2], - mesg->content.proxy.mac_addr[3], - mesg->content.proxy.mac_addr[4], - mesg->content.proxy.mac_addr[5]); + ("%s: bridge zeppelin asks about %s\n", + dev->name, + print_mac(mac, mesg->content.proxy.mac_addr)); if (br_fdb_get_hook == NULL || dev->br_port == NULL) break; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index bb7523a5b408..e13602d8154d 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -534,6 +534,7 @@ out: void netpoll_print_options(struct netpoll *np) { + DECLARE_MAC_BUF(mac); printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", @@ -544,15 +545,8 @@ void netpoll_print_options(struct netpoll *np) np->name, np->remote_port); printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", np->name, HIPQUAD(np->remote_ip)); - printk(KERN_INFO "%s: remote ethernet address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - np->name, - np->remote_mac[0], - np->remote_mac[1], - np->remote_mac[2], - np->remote_mac[3], - np->remote_mac[4], - np->remote_mac[5]); + printk(KERN_INFO "%s: remote ethernet address %s\n", + np->name, print_mac(mac, np->remote_mac)); } int netpoll_parse_options(struct netpoll *np, char *opt) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 94e42be16daa..f07bd590f8f9 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -599,11 +599,11 @@ static const struct file_operations pktgen_fops = { static int pktgen_if_show(struct seq_file *seq, void *v) { - int i; struct pktgen_dev *pkt_dev = seq->private; __u64 sa; __u64 stopped; __u64 now = getCurUs(); + DECLARE_MAC_BUF(mac); seq_printf(seq, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", @@ -648,19 +648,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v) seq_puts(seq, " src_mac: "); - if (is_zero_ether_addr(pkt_dev->src_mac)) - for (i = 0; i < 6; i++) - seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i], - i == 5 ? " " : ":"); - else - for (i = 0; i < 6; i++) - seq_printf(seq, "%02X%s", pkt_dev->src_mac[i], - i == 5 ? " " : ":"); + seq_printf(seq, "%s ", + print_mac(mac, is_zero_ether_addr(pkt_dev->src_mac) ? + pkt_dev->odev->dev_addr : pkt_dev->src_mac)); seq_printf(seq, "dst_mac: "); - for (i = 0; i < 6; i++) - seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i], - i == 5 ? "\n" : ":"); + seq_printf(seq, "%s\n", print_mac(mac, pkt_dev->dst_mac)); seq_printf(seq, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 57c592ed0105..2aaf6faf74ac 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -337,3 +337,11 @@ struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count) return alloc_netdev_mq(sizeof_priv, "eth%d", ether_setup, queue_count); } EXPORT_SYMBOL(alloc_etherdev_mq); + +char *print_mac(char *buf, const u8 *addr) +{ + sprintf(buf, MAC_FMT, + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + return buf; +} +EXPORT_SYMBOL(print_mac); diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 2e6b099fc84c..0936a3e0210b 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -297,6 +297,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) int i, blocks, last, len; size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; + DECLARE_MAC_BUF(mac); if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { key->dot11RSNAStatsCCMPFormatErrors++; @@ -309,7 +310,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (!(keyidx & (1 << 5))) { if (net_ratelimit()) { printk(KERN_DEBUG "CCMP: received packet without ExtIV" - " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); + " flag from %s\n", print_mac(mac, hdr->addr2)); } key->dot11RSNAStatsCCMPFormatErrors++; return -2; @@ -322,9 +323,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } if (!key->key_set) { if (net_ratelimit()) { - printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT + printk(KERN_DEBUG "CCMP: received packet from %s" " with keyid=%d that does not have a configured" - " key\n", MAC_ARG(hdr->addr2), keyidx); + " key\n", print_mac(mac, hdr->addr2), keyidx); } return -3; } @@ -339,11 +340,13 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (ccmp_replay_check(pn, key->rx_pn)) { if (net_ratelimit()) { - IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=" MAC_FMT - " previous PN %02x%02x%02x%02x%02x%02x " - "received PN %02x%02x%02x%02x%02x%02x\n", - MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn), - MAC_ARG(pn)); + IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=%s " + "previous PN %02x%02x%02x%02x%02x%02x " + "received PN %02x%02x%02x%02x%02x%02x\n", + print_mac(mac, hdr->addr2), + key->rx_pn[0], key->rx_pn[1], key->rx_pn[2], + key->rx_pn[3], key->rx_pn[4], key->rx_pn[5], + pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); } key->dot11RSNAStatsCCMPReplays++; return -4; @@ -371,7 +374,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { if (net_ratelimit()) { printk(KERN_DEBUG "CCMP: decrypt failed: STA=" - MAC_FMT "\n", MAC_ARG(hdr->addr2)); + "%s\n", print_mac(mac, hdr->addr2)); } key->dot11RSNAStatsCCMPDecryptErrors++; return -5; @@ -443,12 +446,16 @@ static int ieee80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv) static char *ieee80211_ccmp_print_stats(char *p, void *priv) { struct ieee80211_ccmp_data *ccmp = priv; + p += sprintf(p, "key[%d] alg=CCMP key_set=%d " "tx_pn=%02x%02x%02x%02x%02x%02x " "rx_pn=%02x%02x%02x%02x%02x%02x " "format_errors=%d replays=%d decrypt_errors=%d\n", ccmp->key_idx, ccmp->key_set, - MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn), + ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2], + ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5], + ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2], + ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5], ccmp->dot11RSNAStatsCCMPFormatErrors, ccmp->dot11RSNAStatsCCMPReplays, ccmp->dot11RSNAStatsCCMPDecryptErrors); diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 5a48d8e0aec1..6cc54eeca3ed 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -359,14 +359,15 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) u8 rc4key[16], *pos, *icv; u32 crc; struct scatterlist sg; + DECLARE_MAC_BUF(mac); if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *)skb->data; printk(KERN_DEBUG ": TKIP countermeasures: dropped " - "TX packet to " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + "TX packet to %s\n", + print_mac(mac, hdr->addr1)); } return -1; } @@ -421,14 +422,15 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) u32 crc; struct scatterlist sg; int plen; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *)skb->data; if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { printk(KERN_DEBUG ": TKIP countermeasures: dropped " - "received packet from " MAC_FMT "\n", - MAC_ARG(hdr->addr2)); + "received packet from %s\n", + print_mac(mac, hdr->addr2)); } return -1; } @@ -441,7 +443,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (!(keyidx & (1 << 5))) { if (net_ratelimit()) { printk(KERN_DEBUG "TKIP: received packet without ExtIV" - " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); + " flag from %s\n", print_mac(mac, hdr->addr2)); } return -2; } @@ -453,9 +455,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } if (!tkey->key_set) { if (net_ratelimit()) { - printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT + printk(KERN_DEBUG "TKIP: received packet from %s" " with keyid=%d that does not have a configured" - " key\n", MAC_ARG(hdr->addr2), keyidx); + " key\n", print_mac(mac, hdr->addr2), keyidx); } return -3; } @@ -465,9 +467,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { if (net_ratelimit()) { - IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=" MAC_FMT + IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=%s" " previous TSC %08x%04x received TSC " - "%08x%04x\n", MAC_ARG(hdr->addr2), + "%08x%04x\n", print_mac(mac, hdr->addr2), tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); } tkey->dot11RSNAStatsTKIPReplays++; @@ -489,8 +491,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { if (net_ratelimit()) { printk(KERN_DEBUG ": TKIP: failed to decrypt " - "received packet from " MAC_FMT "\n", - MAC_ARG(hdr->addr2)); + "received packet from %s\n", + print_mac(mac, hdr->addr2)); } return -7; } @@ -508,7 +510,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } if (net_ratelimit()) { IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA=" - MAC_FMT "\n", MAC_ARG(hdr->addr2)); + "%s\n", print_mac(mac, hdr->addr2)); } tkey->dot11RSNAStatsTKIPICVErrors++; return -5; @@ -639,6 +641,7 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, { struct ieee80211_tkip_data *tkey = priv; u8 mic[8]; + DECLARE_MAC_BUF(mac); if (!tkey->key_set) return -1; @@ -651,8 +654,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, struct ieee80211_hdr_4addr *hdr; hdr = (struct ieee80211_hdr_4addr *)skb->data; printk(KERN_DEBUG "%s: Michael MIC verification failed for " - "MSDU from " MAC_FMT " keyidx=%d\n", - skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), + "MSDU from %s keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", print_mac(mac, hdr->addr2), keyidx); if (skb->dev) ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 6284c99b456e..21c0fadde03b 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -271,6 +271,7 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, { struct ieee80211_hdr_3addr *hdr; int res, hdrlen; + DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; @@ -282,8 +283,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT - ") res=%d\n", MAC_ARG(hdr->addr2), res); + IEEE80211_DEBUG_DROP("decryption failed (SA=%s" + ") res=%d\n", print_mac(mac, hdr->addr2), res); if (res == -2) IEEE80211_DEBUG_DROP("Decryption failed ICV " "mismatch (key %d)\n", @@ -303,6 +304,7 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, { struct ieee80211_hdr_3addr *hdr; int res, hdrlen; + DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; @@ -315,8 +317,8 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=" MAC_FMT " keyidx=%d)\n", - ieee->dev->name, MAC_ARG(hdr->addr2), keyidx); + " (SA=%s keyidx=%d)\n", + ieee->dev->name, print_mac(mac, hdr->addr2), keyidx); return -1; } @@ -350,6 +352,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_crypt_data *crypt = NULL; int keyidx = 0; int can_be_decrypted = 0; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *)skb->data; stats = &ieee->stats; @@ -459,8 +462,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ IEEE80211_DEBUG_DROP("Decryption failed (not set)" - " (SA=" MAC_FMT ")\n", - MAC_ARG(hdr->addr2)); + " (SA=%s)\n", + print_mac(mac, hdr->addr2)); ieee->ieee_stats.rx_discards_undecryptable++; goto rx_dropped; } @@ -471,8 +474,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt && (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MAC_FMT "\n", dev->name, - MAC_ARG(hdr->addr2)); + "from %s\n", dev->name, + print_mac(mac, hdr->addr2)); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -650,8 +653,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * configured */ } else { IEEE80211_DEBUG_DROP("encryption configured, but RX " - "frame not encrypted (SA=" MAC_FMT - ")\n", MAC_ARG(hdr->addr2)); + "frame not encrypted (SA=%s" + ")\n", print_mac(mac, hdr->addr2)); goto rx_dropped; } } @@ -659,9 +662,9 @@ 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 " - "frame from " MAC_FMT + "frame from %s" " (drop_unencrypted=1)\n", - MAC_ARG(hdr->addr2)); + print_mac(mac, hdr->addr2)); goto rx_dropped; } @@ -1411,6 +1414,8 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 struct ieee80211_network *network, struct ieee80211_rx_stats *stats) { + DECLARE_MAC_BUF(mac); + network->qos_data.active = 0; network->qos_data.supported = 0; network->qos_data.param_count = 0; @@ -1457,11 +1462,11 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 } if (network->mode == 0) { - IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' " + IEEE80211_DEBUG_SCAN("Filtered out '%s (%s)' " "network.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 1; } @@ -1490,6 +1495,7 @@ static void update_network(struct ieee80211_network *dst, { int qos_active; u8 old_param; + DECLARE_MAC_BUF(mac); ieee80211_network_reset(dst); dst->ibss_dfs = src->ibss_dfs; @@ -1503,8 +1509,8 @@ static void update_network(struct ieee80211_network *dst, memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); else - IEEE80211_DEBUG_SCAN("Network " MAC_FMT " info received " - "off channel (%d vs. %d)\n", MAC_ARG(src->bssid), + IEEE80211_DEBUG_SCAN("Network %s info received " + "off channel (%d vs. %d)\n", print_mac(mac, src->bssid), dst->channel, src->stats.received_channel); dst->capability = src->capability; @@ -1576,12 +1582,13 @@ static void ieee80211_process_probe_response(struct ieee80211_device struct ieee80211_info_element *info_element = beacon->info_element; #endif unsigned long flags; + DECLARE_MAC_BUF(mac); - IEEE80211_DEBUG_SCAN("'%s' (" MAC_FMT + IEEE80211_DEBUG_SCAN("'%s' (%s" "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", escape_essid(info_element->data, info_element->len), - MAC_ARG(beacon->header.addr3), + print_mac(mac, beacon->header.addr3), (beacon->capability & (1 << 0xf)) ? '1' : '0', (beacon->capability & (1 << 0xe)) ? '1' : '0', (beacon->capability & (1 << 0xd)) ? '1' : '0', @@ -1600,10 +1607,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device (beacon->capability & (1 << 0x0)) ? '1' : '0'); if (ieee80211_network_init(ieee, beacon, &network, stats)) { - IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n", + IEEE80211_DEBUG_SCAN("Dropped '%s' (%s) via %s.\n", escape_essid(info_element->data, info_element->len), - MAC_ARG(beacon->header.addr3), + print_mac(mac, beacon->header.addr3), is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); return; @@ -1637,11 +1644,11 @@ 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' (" MAC_FMT ") from " + IEEE80211_DEBUG_SCAN("Expired '%s' (%s) from " "network list.\n", escape_essid(target->ssid, target->ssid_len), - MAC_ARG(target->bssid)); + print_mac(mac, target->bssid)); ieee80211_network_reset(target); } else { /* Otherwise just pull from the free list */ @@ -1651,10 +1658,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device } #ifdef CONFIG_IEEE80211_DEBUG - IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", + IEEE80211_DEBUG_SCAN("Adding '%s' (%s) via %s.\n", escape_essid(network.ssid, network.ssid_len), - MAC_ARG(network.bssid), + print_mac(mac, network.bssid), is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); #endif @@ -1662,10 +1669,10 @@ 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' (" MAC_FMT ") via %s.\n", + IEEE80211_DEBUG_SCAN("Updating '%s' (%s) via %s.\n", escape_essid(target->ssid, target->ssid_len), - MAC_ARG(target->bssid), + print_mac(mac, target->bssid), is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); update_network(target, &network); diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 465b73d50532..9b58dd67acb6 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -257,6 +257,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, char *ev = extra; char *stop = ev + wrqu->data.length; int i = 0; + DECLARE_MAC_BUF(mac); IEEE80211_DEBUG_WX("Getting scan\n"); @@ -274,10 +275,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ev = ieee80211_translate_scan(ieee, ev, stop, network); else IEEE80211_DEBUG_SCAN("Not showing network '%s (" - MAC_FMT ")' due to age (%dms).\n", + "%s)' due to age (%dms).\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), jiffies_to_msecs(jiffies - network-> last_scanned)); diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index e475f2e1be13..4c0feb2dacd8 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -372,6 +372,7 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, u16 status = le16_to_cpup(&resp->status); struct ieee80211softmac_network *network = NULL; unsigned long flags; + DECLARE_MAC_BUF(mac2); if (unlikely(!mac->running)) return -ENODEV; @@ -388,7 +389,8 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, /* someone sending us things without us knowing him? Ignore. */ if (!network) { - dprintk(KERN_INFO PFX "Received unrequested assocation response from " MAC_FMT "\n", MAC_ARG(resp->header.addr3)); + dprintk(KERN_INFO PFX "Received unrequested assocation response from %s\n", + print_mac(mac2, resp->header.addr3)); spin_unlock_irqrestore(&mac->lock, flags); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index 826c32d24461..855fa0fe641b 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -35,6 +35,7 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, { struct ieee80211softmac_auth_queue_item *auth; unsigned long flags; + DECLARE_MAC_BUF(mac2); if (net->authenticating || net->authenticated) return 0; @@ -43,7 +44,7 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, /* Add the network if it's not already added */ ieee80211softmac_add_network(mac, net); - dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid)); + dprintk(KERN_NOTICE PFX "Queueing Authentication Request to %s\n", print_mac(mac2, net->bssid)); /* Queue the auth request */ auth = (struct ieee80211softmac_auth_queue_item *) kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL); @@ -76,6 +77,7 @@ ieee80211softmac_auth_queue(struct work_struct *work) struct ieee80211softmac_auth_queue_item *auth; struct ieee80211softmac_network *net; unsigned long flags; + DECLARE_MAC_BUF(mac2); auth = container_of(work, struct ieee80211softmac_auth_queue_item, work.work); @@ -99,13 +101,14 @@ ieee80211softmac_auth_queue(struct work_struct *work) auth->retry--; spin_unlock_irqrestore(&mac->lock, flags); if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state)) - dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid)); + dprintk(KERN_NOTICE PFX "Sending Authentication Request to %s failed (this shouldn't happen, wait for the timeout).\n", + print_mac(mac2, net->bssid)); else - dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid)); + dprintk(KERN_NOTICE PFX "Sent Authentication Request to %s.\n", print_mac(mac2, net->bssid)); return; } - printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid)); + printkl(KERN_WARNING PFX "Authentication timed out with %s\n", print_mac(mac2, net->bssid)); /* Remove this item from the queue */ spin_lock_irqsave(&mac->lock, flags); net->authenticating = 0; @@ -142,6 +145,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) struct ieee80211softmac_network *net = NULL; unsigned long flags; u8 * data; + DECLARE_MAC_BUF(mac2); if (unlikely(!mac->running)) return -ENODEV; @@ -161,7 +165,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) /* Make sure that we've got an auth queue item for this request */ if(aq == NULL) { - dprintkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2)); + dprintkl(KERN_DEBUG PFX "Authentication response received from %s but no queue item exists.\n", print_mac(mac2, auth->header.addr2)); /* Error #? */ return -1; } @@ -169,7 +173,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) /* Check for out of order authentication */ if(!net->authenticating) { - dprintkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2)); + dprintkl(KERN_DEBUG PFX "Authentication response received from %s but did not request authentication.\n",print_mac(mac2, auth->header.addr2)); return -1; } @@ -187,7 +191,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) spin_unlock_irqrestore(&mac->lock, flags); /* Send event */ - printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid)); + printkl(KERN_NOTICE PFX "Open Authentication completed with %s\n", print_mac(mac2, net->bssid)); ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); break; default: @@ -197,8 +201,8 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) net->authenticating = 0; spin_unlock_irqrestore(&mac->lock, flags); - printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n", - MAC_ARG(net->bssid), le16_to_cpup(&auth->status)); + printkl(KERN_NOTICE PFX "Open Authentication with %s failed, error code: %i\n", + print_mac(mac2, net->bssid), le16_to_cpup(&auth->status)); /* Count the error? */ break; } @@ -253,13 +257,13 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) net->authenticating = 0; net->authenticated = 1; spin_unlock_irqrestore(&mac->lock, flags); - printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n", - MAC_ARG(net->bssid)); + printkl(KERN_NOTICE PFX "Shared Key Authentication completed with %s\n", + print_mac(mac2, net->bssid)); ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); break; default: - printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n", - MAC_ARG(net->bssid), le16_to_cpup(&auth->status)); + printkl(KERN_NOTICE PFX "Shared Key Authentication with %s failed, error code: %i\n", + print_mac(mac2, net->bssid), le16_to_cpup(&auth->status)); /* Lock and reset flags */ spin_lock_irqsave(&mac->lock, flags); net->authenticating = 0; @@ -375,6 +379,7 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de struct ieee80211softmac_network *net = NULL; struct ieee80211softmac_device *mac = ieee80211_priv(dev); + DECLARE_MAC_BUF(mac2); if (unlikely(!mac->running)) return -ENODEV; @@ -387,8 +392,8 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2); if (net == NULL) { - dprintkl(KERN_DEBUG PFX "Received deauthentication packet from "MAC_FMT", but that network is unknown.\n", - MAC_ARG(deauth->header.addr2)); + dprintkl(KERN_DEBUG PFX "Received deauthentication packet from %s, but that network is unknown.\n", + print_mac(mac2, deauth->header.addr2)); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index 5742dc803b79..8e8ad08a411c 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c @@ -72,6 +72,7 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev, struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); struct ieee80211softmac_auth_queue_item *authptr; int length = 0; + DECLARE_MAC_BUF(mac); check_assoc_again: mutex_lock(&sm->associnfo.mutex); diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c index a4c1c9545827..87039c2fb6a2 100644 --- a/net/irda/irlan/irlan_client.c +++ b/net/irda/irlan/irlan_client.c @@ -436,6 +436,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, __u16 tmp_cpu; /* Temporary value in host order */ __u8 *bytes; int i; + DECLARE_MAC_BUF(mac); IRDA_DEBUG(4, "%s(), parm=%s\n", __FUNCTION__ , param); @@ -520,9 +521,8 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, /* FILTER_ENTRY, have we got an ethernet address? */ if (strcmp(param, "FILTER_ENTRY") == 0) { bytes = value; - IRDA_DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n", - bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], - bytes[5]); + IRDA_DEBUG(4, "Ethernet address = %s\n", + print_mac(mac, bytes)); for (i = 0; i < 6; i++) self->dev->dev_addr[i] = bytes[i]; } diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 4865d82896b1..cb34bc0518e8 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -25,10 +25,10 @@ #include #include -static void llc_ui_format_mac(struct seq_file *seq, unsigned char *mac) +static void llc_ui_format_mac(struct seq_file *seq, u8 *addr) { - seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + DECLARE_MAC_BUF(mac); + seq_printf(seq, "%s", print_mac(mac, addr)); } static struct sock *llc_get_sk_idx(loff_t pos) @@ -128,8 +128,10 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v) if (llc->dev) llc_ui_format_mac(seq, llc->dev->dev_addr); - else - seq_printf(seq, "00:00:00:00:00:00"); + else { + u8 addr[6] = {0,0,0,0,0,0}; + llc_ui_format_mac(seq, addr); + } seq_printf(seq, "@%02X ", llc->sap->laddr.lsap); llc_ui_format_mac(seq, llc->daddr.mac); seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap, diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 8e4a1bcd16ea..c881524c8725 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -262,11 +262,12 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, struct sta_info *sta) { char buf[50]; + DECLARE_MAC_BUF(mac); if (!key->debugfs.dir) return; - sprintf(buf, "../../stations/" MAC_FMT, MAC_ARG(sta->addr)); + sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); key->debugfs.stalink = debugfs_create_symlink("station", key->debugfs.dir, buf); } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 8ceda33efc12..9efb84c47bb0 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -66,7 +66,8 @@ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, char *buf, \ int buflen) \ { \ - return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\ + DECLARE_MAC_BUF(mac); \ + return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\ } #define __IEEE80211_IF_FILE(name) \ diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 2daaa802bbd0..f7c717c906dc 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -203,15 +203,15 @@ STA_OPS(wme_tx_queue); void ieee80211_sta_debugfs_add(struct sta_info *sta) { - char buf[3*6]; struct dentry *stations_dir = sta->local->debugfs.stations; + DECLARE_MAC_BUF(mac); if (!stations_dir) return; - sprintf(buf, MAC_FMT, MAC_ARG(sta->addr)); + print_mac(mac, sta->addr); - sta->debugfs.dir = debugfs_create_dir(buf, stations_dir); + sta->debugfs.dir = debugfs_create_dir(mac, stations_dir); if (!sta->debugfs.dir) return; diff --git a/net/mac80211/event.c b/net/mac80211/event.c index 68a526cb7623..2280f40b4560 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -22,13 +22,14 @@ void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, { union iwreq_data wrqu; char *buf = kmalloc(128, GFP_ATOMIC); + DECLARE_MAC_BUF(mac); if (buf) { /* TODO: needed parameters: count, key type, TSC */ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=" MAC_FMT ")", + "keyid=%d %scast addr=%s)", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); + print_mac(mac, hdr->addr2)); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 0c1f7b2e157c..4229d150e783 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -602,6 +602,7 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; + DECLARE_MAC_BUF(mac); if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) return 0; @@ -619,8 +620,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) sta_info_put(sta); } else { printk(KERN_DEBUG "%s: could not find STA entry for WDS link " - "peer " MAC_FMT "\n", - dev->name, MAC_ARG(sdata->u.wds.remote_addr)); + "peer %s\n", + dev->name, print_mac(mac, sdata->u.wds.remote_addr)); } /* Update WDS link data */ diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 51dca21f77c7..6ccdde82bded 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -98,9 +98,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, sta = sta_info_get(local, sta_addr); if (!sta) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: set_encrypt - unknown addr " - MAC_FMT "\n", - dev->name, MAC_ARG(sta_addr)); + "%s\n", + dev->name, print_mac(mac, sta_addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ return -ENOENT; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 8fdbd38e02c4..f47cbd294ceb 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -319,14 +319,15 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; u8 changes = 0; + DECLARE_MAC_BUF(mac); if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" - MAC_FMT ")\n", + "%s)\n", dev->name, use_protection ? "enabled" : "disabled", - MAC_ARG(ifsta->bssid)); + print_mac(mac, ifsta->bssid)); } if (use_protection) sdata->flags |= IEEE80211_SDATA_USE_PROTECTION; @@ -338,11 +339,11 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: switched to %s barker preamble" - " (BSSID=" MAC_FMT ")\n", + " (BSSID=%s)\n", dev->name, (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ? "short" : "long", - MAC_ARG(ifsta->bssid)); + print_mac(mac, ifsta->bssid)); } if (preamble_mode) sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE; @@ -524,18 +525,20 @@ static void ieee80211_send_auth(struct net_device *dev, static void ieee80211_authenticate(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + DECLARE_MAC_BUF(mac); + ifsta->auth_tries++; if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT + printk(KERN_DEBUG "%s: authentication with AP %s" " timed out\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); ifsta->state = IEEE80211_DISABLED; return; } ifsta->state = IEEE80211_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: authenticate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0); @@ -744,18 +747,20 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, static void ieee80211_associate(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + DECLARE_MAC_BUF(mac); + ifsta->assoc_tries++; if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with AP " MAC_FMT + printk(KERN_DEBUG "%s: association with AP %s" " timed out\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); ifsta->state = IEEE80211_DISABLED; return; } ifsta->state = IEEE80211_ASSOCIATE; - printk(KERN_DEBUG "%s: associate with AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: associate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); if (ieee80211_privacy_mismatch(dev, ifsta)) { printk(KERN_DEBUG "%s: mismatch in privacy configuration and " "mixed-cell disabled - abort association\n", dev->name); @@ -775,6 +780,7 @@ static void ieee80211_associated(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; int disassoc; + DECLARE_MAC_BUF(mac); /* TODO: start monitoring current AP signal quality and number of * missed beacons. Scan other channels every now and then and search @@ -785,8 +791,8 @@ static void ieee80211_associated(struct net_device *dev, sta = sta_info_get(local, ifsta->bssid); if (!sta) { - printk(KERN_DEBUG "%s: No STA entry for own AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; } else { disassoc = 0; @@ -794,9 +800,9 @@ static void ieee80211_associated(struct net_device *dev, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { printk(KERN_DEBUG "%s: No ProbeResp from " - "current AP " MAC_FMT " - assume out of " + "current AP %s - assume out of " "range\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; sta_info_free(sta); } else @@ -944,37 +950,38 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u16 auth_alg, auth_transaction, status_code; + DECLARE_MAC_BUF(mac); if (ifsta->state != IEEE80211_AUTHENTICATE && sdata->type != IEEE80211_IF_TYPE_IBSS) { printk(KERN_DEBUG "%s: authentication frame received from " - MAC_FMT ", but not in authenticate state - ignored\n", - dev->name, MAC_ARG(mgmt->sa)); + "%s, but not in authenticate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); return; } if (len < 24 + 6) { printk(KERN_DEBUG "%s: too short (%zd) authentication frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (sdata->type != IEEE80211_IF_TYPE_IBSS && memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: authentication frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } if (sdata->type != IEEE80211_IF_TYPE_IBSS && memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: authentication frame received from " - "unknown BSSID (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown BSSID (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } @@ -982,9 +989,9 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); status_code = le16_to_cpu(mgmt->u.auth.status_code); - printk(KERN_DEBUG "%s: RX authentication from " MAC_FMT " (alg=%d " + printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d " "transaction=%d status=%d)\n", - dev->name, MAC_ARG(mgmt->sa), auth_alg, + dev->name, print_mac(mac, mgmt->sa), auth_alg, auth_transaction, status_code); if (sdata->type == IEEE80211_IF_TYPE_IBSS) { @@ -1071,27 +1078,28 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, size_t len) { u16 reason_code; + DECLARE_MAC_BUF(mac); if (len < 24 + 2) { printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: deauthentication frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - printk(KERN_DEBUG "%s: RX deauthentication from " MAC_FMT + printk(KERN_DEBUG "%s: RX deauthentication from %s" " (reason=%d)\n", - dev->name, MAC_ARG(mgmt->sa), reason_code); + dev->name, print_mac(mac, mgmt->sa), reason_code); if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); @@ -1116,27 +1124,28 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, size_t len) { u16 reason_code; + DECLARE_MAC_BUF(mac); if (len < 24 + 2) { printk(KERN_DEBUG "%s: too short (%zd) disassociation frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: disassociation frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - printk(KERN_DEBUG "%s: RX disassociation from " MAC_FMT + printk(KERN_DEBUG "%s: RX disassociation from %s" " (reason=%d)\n", - dev->name, MAC_ARG(mgmt->sa), reason_code); + dev->name, print_mac(mac, mgmt->sa), reason_code); if (ifsta->flags & IEEE80211_STA_ASSOCIATED) printk(KERN_DEBUG "%s: disassociated\n", dev->name); @@ -1165,29 +1174,30 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, struct ieee802_11_elems elems; u8 *pos; int i, j; + DECLARE_MAC_BUF(mac); /* AssocResp and ReassocResp have identical structure, so process both * of them in this function. */ if (ifsta->state != IEEE80211_ASSOCIATE) { printk(KERN_DEBUG "%s: association frame received from " - MAC_FMT ", but not in associate state - ignored\n", - dev->name, MAC_ARG(mgmt->sa)); + "%s, but not in associate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); return; } if (len < 24 + 6) { printk(KERN_DEBUG "%s: too short (%zd) association frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: association frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } @@ -1199,9 +1209,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, "set\n", dev->name, aid); aid &= ~(BIT(15) | BIT(14)); - printk(KERN_DEBUG "%s: RX %sssocResp from " MAC_FMT " (capab=0x%x " + printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " "status=%d aid=%d)\n", - dev->name, reassoc ? "Rea" : "A", MAC_ARG(mgmt->sa), + dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), capab_info, status_code, aid); if (status_code != WLAN_STATUS_SUCCESS) { @@ -1435,14 +1445,16 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u64 timestamp; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ #if 0 - printk(KERN_DEBUG "%s: RX %s from " MAC_FMT " to " MAC_FMT "\n", + printk(KERN_DEBUG "%s: RX %s from %s to %s\n", dev->name, beacon ? "Beacon" : "Probe Response", - MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da)); + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da)); #endif baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; @@ -1461,10 +1473,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, else tsf = -1LLU; if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { - printk(KERN_DEBUG "RX beacon SA=" MAC_FMT " BSSID=" - MAC_FMT " TSF=0x%llx BCN=0x%llx diff=%lld " + printk(KERN_DEBUG "RX beacon SA=%s BSSID=" + "%s TSF=0x%llx BCN=0x%llx diff=%lld " "@%lu\n", - MAC_ARG(mgmt->sa), MAC_ARG(mgmt->bssid), + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid), (unsigned long long)tsf, (unsigned long long)timestamp, (unsigned long long)(tsf - timestamp), @@ -1518,9 +1530,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev, } if (sta->supp_rates != prev_rates) { printk(KERN_DEBUG "%s: updated supp_rates set for " - MAC_FMT " based on beacon info (0x%x & 0x%x -> " + "%s based on beacon info (0x%x & 0x%x -> " "0x%x)\n", - dev->name, MAC_ARG(sta->addr), prev_rates, + dev->name, print_mac(mac, sta->addr), prev_rates, supp_rates, sta->supp_rates); } sta_info_put(sta); @@ -1722,6 +1734,11 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, struct sk_buff *skb; struct ieee80211_mgmt *resp; u8 *pos, *end; + DECLARE_MAC_BUF(mac); +#ifdef CONFIG_MAC80211_IBSS_DEBUG + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); +#endif if (sdata->type != IEEE80211_IF_TYPE_IBSS || ifsta->state != IEEE80211_IBSS_JOINED || @@ -1734,10 +1751,10 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, tx_last_beacon = 1; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: RX ProbeReq SA=" MAC_FMT " DA=" MAC_FMT " BSSID=" - MAC_FMT " (tx_last_beacon=%d)\n", - dev->name, MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da), - MAC_ARG(mgmt->bssid), tx_last_beacon); + printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID=" + "%s (tx_last_beacon=%d)\n", + dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da), + print_mac(mac3, mgmt->bssid), tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (!tx_last_beacon) @@ -1753,8 +1770,8 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, pos + 2 + pos[1] > end) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " - "from " MAC_FMT "\n", - dev->name, MAC_ARG(mgmt->sa)); + "from %s\n", + dev->name, print_mac(mac, mgmt->sa)); } return; } @@ -1773,8 +1790,8 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, resp = (struct ieee80211_mgmt *) skb->data; memcpy(resp->da, mgmt->sa, ETH_ALEN); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: Sending ProbeResp to " MAC_FMT "\n", - dev->name, MAC_ARG(resp->da)); + printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", + dev->name, print_mac(mac, resp->da)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ ieee80211_sta_tx(dev, skb, 0); } @@ -1925,13 +1942,14 @@ static void ieee80211_sta_expire(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); + DECLARE_MAC_BUF(mac); write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + IEEE80211_IBSS_INACTIVITY_LIMIT)) { - printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT - "\n", dev->name, MAC_ARG(sta->addr)); + printk(KERN_DEBUG "%s: expiring inactive STA %s\n", + dev->name, print_mac(mac, sta->addr)); __sta_info_get(sta); sta_info_remove(sta); list_add(&sta->list, &tmp_list); @@ -2362,6 +2380,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, struct ieee80211_hw_mode *mode; u8 bssid[ETH_ALEN], *pos; int i; + DECLARE_MAC_BUF(mac); #if 0 /* Easier testing, use fixed BSSID. */ @@ -2377,8 +2396,8 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, bssid[0] |= 0x02; #endif - printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n", - dev->name, MAC_ARG(bssid)); + printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", + dev->name, print_mac(mac, bssid)); bss = ieee80211_rx_bss_add(dev, bssid); if (!bss) @@ -2418,6 +2437,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, int found = 0; u8 bssid[ETH_ALEN]; int active_ibss; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (ifsta->ssid_len == 0) return -EINVAL; @@ -2434,8 +2455,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, || !(bss->capability & WLAN_CAPABILITY_IBSS)) continue; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " bssid=" MAC_FMT " found\n", - MAC_ARG(bss->bssid)); + printk(KERN_DEBUG " bssid=%s found\n", + print_mac(mac, bss->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ memcpy(bssid, bss->bssid, ETH_ALEN); found = 1; @@ -2445,14 +2466,14 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, spin_unlock_bh(&local->sta_bss_lock); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " sta_find_ibss: selected " MAC_FMT " current " - MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG " sta_find_ibss: selected %s current " + "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && (bss = ieee80211_rx_bss_get(dev, bssid))) { - printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT + printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" " based on configured SSID\n", - dev->name, MAC_ARG(bssid)); + dev->name, print_mac(mac, bssid)); return ieee80211_sta_join_ibss(dev, ifsta, bss); } #ifdef CONFIG_MAC80211_IBSS_DEBUG @@ -3070,19 +3091,20 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); /* TODO: Could consider removing the least recently used entry and * allow new one to be added. */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: No room for a new IBSS STA " - "entry " MAC_FMT "\n", dev->name, MAC_ARG(addr)); + "entry %s\n", dev->name, print_mac(mac, addr)); } return NULL; } - printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n", - local->mdev->name, MAC_ARG(addr), dev->name); + printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", + local->mdev->name, print_mac(mac, addr), dev->name); sta = sta_info_add(local, dev, addr, GFP_ATOMIC); if (!sta) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index dd6fc4aa3ff5..c10e53afbb4f 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -63,6 +63,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; + DECLARE_MAC_BUF(mac); if (!key->local->ops->set_key) return; @@ -78,15 +79,16 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) printk(KERN_ERR "mac80211-%s: failed to set key " - "(%d, " MAC_FMT ") to hardware (%d)\n", + "(%d, %s) to hardware (%d)\n", wiphy_name(key->local->hw.wiphy), - key->conf.keyidx, MAC_ARG(addr), ret); + key->conf.keyidx, print_mac(mac, addr), ret); } static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; + DECLARE_MAC_BUF(mac); if (!key->local->ops->set_key) return; @@ -102,9 +104,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) if (ret) printk(KERN_ERR "mac80211-%s: failed to remove key " - "(%d, " MAC_FMT ") from hardware (%d)\n", + "(%d, %s) from hardware (%d)\n", wiphy_name(key->local->hw.wiphy), - key->conf.keyidx, MAC_ARG(addr), ret); + key->conf.keyidx, print_mac(mac, addr), ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; } diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index ef91ce428aca..314b8de88862 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -201,9 +201,10 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, srctrl->avg_rate_update = jiffies; if (srctrl->tx_avg_rate_num > 0) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: " + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: STA %s Average rate: " "%d (%d/%d)\n", - dev->name, MAC_ARG(sta->addr), + dev->name, print_mac(mac, sta->addr), srctrl->tx_avg_rate_sum / srctrl->tx_avg_rate_num, srctrl->tx_avg_rate_sum, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c985c7a537db..e9dcc6229c3c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -403,6 +403,8 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; + DECLARE_MAC_BUF(mac); + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss) @@ -410,8 +412,8 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) sta->flags |= WLAN_STA_PS; sta->pspoll = 0; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); + printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", + dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -422,6 +424,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) int sent = 0; struct ieee80211_sub_if_data *sdata; struct ieee80211_tx_packet_data *pkt_data; + DECLARE_MAC_BUF(mac); sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss) @@ -435,8 +438,8 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) bss_tim_clear(local, sdata->bss, sta->aid); } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); + printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n", + dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { @@ -450,9 +453,9 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) local->total_ps_buffered--; sent++; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame " + printk(KERN_DEBUG "%s: STA %s aid %d send PS frame " "since STA not sleeping anymore\n", dev->name, - MAC_ARG(sta->addr), sta->aid); + print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ pkt_data->flags |= IEEE80211_TXPD_REQUEUE; dev_queue_xmit(skb); @@ -590,13 +593,15 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_DEBUG struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " - "addr1=" MAC_FMT " addr2=" MAC_FMT "\n", + "addr1=%s addr2=%s\n", sdata->dev->name, idx, jiffies - entry->first_frag_time, entry->seq, - entry->last_frag, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2)); + entry->last_frag, print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2)); #endif /* CONFIG_MAC80211_DEBUG */ __skb_queue_purge(&entry->skb_list); } @@ -662,6 +667,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) unsigned int frag, seq; struct ieee80211_fragment_entry *entry; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr *) rx->skb->data; sc = le16_to_cpu(hdr->seq_ctrl); @@ -720,10 +726,10 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { if (net_ratelimit()) printk(KERN_DEBUG "%s: defrag: CCMP PN not " - "sequential A2=" MAC_FMT + "sequential A2=%s" " PN=%02x%02x%02x%02x%02x%02x " "(expected %02x%02x%02x%02x%02x%02x)\n", - rx->dev->name, MAC_ARG(hdr->addr2), + rx->dev->name, print_mac(mac, hdr->addr2), rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); @@ -774,6 +780,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) { struct sk_buff *skb; int no_pending_pkts; + DECLARE_MAC_BUF(mac); if (likely(!rx->sta || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || @@ -799,9 +806,8 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) rx->sta->pspoll = 1; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries " - "after %d)\n", - MAC_ARG(rx->sta->addr), rx->sta->aid, + printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", + print_mac(mac, rx->sta->addr), rx->sta->aid, skb_queue_len(&rx->sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ @@ -824,9 +830,9 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG } else if (!rx->u.rx.sent_ps_buffered) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even " + printk(KERN_DEBUG "%s: STA %s sent PS Poll even " "though there is no buffered frames for it\n", - rx->dev->name, MAC_ARG(rx->sta->addr)); + rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -881,9 +887,10 @@ ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) #ifdef CONFIG_MAC80211_DEBUG struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: dropped frame from %s" " (unauthorized port)\n", rx->dev->name, - MAC_ARG(hdr->addr2)); + print_mac(mac, hdr->addr2)); #endif /* CONFIG_MAC80211_DEBUG */ return TXRX_DROP; } @@ -928,6 +935,10 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) u8 src[ETH_ALEN]; struct sk_buff *skb = rx->skb, *skb2; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); fc = rx->fc; if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) @@ -958,13 +969,11 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) sdata->type != IEEE80211_IF_TYPE_VLAN)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped ToDS frame " - "(BSSID=" MAC_FMT - " SA=" MAC_FMT - " DA=" MAC_FMT ")\n", + "(BSSID=%s SA=%s DA=%s)\n", dev->name, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3)); return TXRX_DROP; } break; @@ -976,14 +985,12 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped FromDS&ToDS " - "frame (RA=" MAC_FMT - " TA=" MAC_FMT " DA=" MAC_FMT - " SA=" MAC_FMT ")\n", + "frame (RA=%s TA=%s DA=%s SA=%s)\n", rx->dev->name, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3), - MAC_ARG(hdr->addr4)); + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3), + print_mac(mac4, hdr->addr4)); return TXRX_DROP; } break; @@ -1004,12 +1011,12 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) if (sdata->type != IEEE80211_IF_TYPE_IBSS) { if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped IBSS frame (DA=" - MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT - ")\n", - dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); + printk(KERN_DEBUG "%s: dropped IBSS frame " + "(DA=%s SA=%s BSSID=%s)\n", + dev->name, + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3)); } return TXRX_DROP; } @@ -1172,6 +1179,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_txrx_data *rx) { int keyidx, hdrlen; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb); if (rx->skb->len >= hdrlen + 4) @@ -1181,9 +1190,9 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " - "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", - dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), - keyidx); + "failure from %s to %s keyidx=%d\n", + dev->name, print_mac(mac, hdr->addr2), + print_mac(mac2, hdr->addr1), keyidx); if (!sta) { /* @@ -1192,8 +1201,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, */ if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for unknown address " MAC_FMT "\n", - dev->name, MAC_ARG(hdr->addr2)); + "error for unknown address %s\n", + dev->name, print_mac(mac, hdr->addr2)); goto ignore; } @@ -1201,7 +1210,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " "error for a frame with no PROTECTED flag (src " - MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); + "%s)\n", dev->name, print_mac(mac, hdr->addr2)); goto ignore; } @@ -1215,8 +1224,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored Michael MIC error for " "a frame with non-zero keyidx (%d)" - " (src " MAC_FMT ")\n", dev->name, keyidx, - MAC_ARG(hdr->addr2)); + " (src %s)\n", dev->name, keyidx, + print_mac(mac, hdr->addr2)); goto ignore; } @@ -1226,8 +1235,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " "error for a frame that cannot be encrypted " - "(fc=0x%04x) (src " MAC_FMT ")\n", - dev->name, rx->fc, MAC_ARG(hdr->addr2)); + "(fc=0x%04x) (src %s)\n", + dev->name, rx->fc, print_mac(mac, hdr->addr2)); goto ignore; } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c17172abb21c..44d983404952 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -132,6 +132,7 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp) { struct sta_info *sta; + DECLARE_MAC_BUF(mac); sta = kzalloc(sizeof(*sta), gfp); if (!sta) @@ -164,8 +165,8 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, write_unlock_bh(&local->sta_lock); #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n", - local->mdev->name, MAC_ARG(addr)); + printk(KERN_DEBUG "%s: Added STA %s\n", + local->mdev->name, print_mac(mac, addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_DEBUGFS @@ -207,6 +208,7 @@ void sta_info_free(struct sta_info *sta) { struct sk_buff *skb; struct ieee80211_local *local = sta->local; + DECLARE_MAC_BUF(mac); might_sleep(); @@ -223,8 +225,8 @@ void sta_info_free(struct sta_info *sta) } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", - local->mdev->name, MAC_ARG(sta->addr)); + printk(KERN_DEBUG "%s: Removed STA %s\n", + local->mdev->name, print_mac(mac, sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ ieee80211_key_free(sta->key); @@ -263,6 +265,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); if (skb_queue_empty(&sta->ps_tx_buf)) return; @@ -281,7 +284,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (skb) { local->total_ps_buffered--; printk(KERN_DEBUG "Buffered frame expired (STA " - MAC_FMT ")\n", MAC_ARG(sta->addr)); + "%s)\n", print_mac(mac, sta->addr)); dev_kfree_skb(skb); } else break; diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index b9c1d5405180..5b11f14abfba 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -275,9 +275,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, (iv32 == key->u.tkip.iv32_rx[queue] && iv16 <= key->u.tkip.iv16_rx[queue]))) { #ifdef CONFIG_TKIP_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "TKIP replay detected for RX frame from " - MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", - MAC_ARG(ta), + "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", + print_mac(mac, ta), iv32, iv16, key->u.tkip.iv32_rx[queue], key->u.tkip.iv16_rx[queue]); #endif /* CONFIG_TKIP_DEBUG */ @@ -299,8 +300,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, #ifdef CONFIG_TKIP_DEBUG { int i; - printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT - " TK=", MAC_ARG(ta)); + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s" + " TK=", print_mac(mac, ta)); for (i = 0; i < 16; i++) printk("%02x ", key->conf.key[ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ca262a99e56f..04b4fa9c69ea 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -54,6 +54,7 @@ static void ieee80211_dump_frame(const char *ifname, const char *title, const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 fc; int hdrlen; + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); if (skb->len < 4) { @@ -69,13 +70,13 @@ static void ieee80211_dump_frame(const char *ifname, const char *title, printk(" FC=0x%04x DUR=0x%04x", fc, le16_to_cpu(hdr->duration_id)); if (hdrlen >= 10) - printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1)); + printk(" A1=%s", print_mac(mac, hdr->addr1)); if (hdrlen >= 16) - printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2)); + printk(" A2=%s", print_mac(mac, hdr->addr2)); if (hdrlen >= 24) - printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3)); + printk(" A3=%s", print_mac(mac, hdr->addr3)); if (hdrlen >= 30) - printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4)); + printk(" A4=%s", print_mac(mac, hdr->addr4)); printk("\n"); } #else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ @@ -236,9 +237,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) tx->sdata->type != IEEE80211_IF_TYPE_IBSS && (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: dropped data frame to not " - "associated station " MAC_FMT "\n", - tx->dev->name, MAC_ARG(hdr->addr1)); + "associated station %s\n", + tx->dev->name, print_mac(mac, hdr->addr1)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); return TXRX_DROP; @@ -259,9 +261,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x && !(sta_flags & WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: dropped frame to %s" " (unauthorized port)\n", tx->dev->name, - MAC_ARG(hdr->addr1)); + print_mac(mac, hdr->addr1)); #endif I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port); return TXRX_DROP; @@ -357,6 +360,7 @@ static inline ieee80211_txrx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) { struct sta_info *sta = tx->sta; + DECLARE_MAC_BUF(mac); if (unlikely(!sta || ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && @@ -366,9 +370,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries " + printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " "before %d)\n", - MAC_ARG(sta->addr), sta->aid, + print_mac(mac, sta->addr), sta->aid, skb_queue_len(&sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ sta->flags |= WLAN_STA_TIM; @@ -377,9 +381,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); if (net_ratelimit()) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " TX " + printk(KERN_DEBUG "%s: STA %s TX " "buffer full - dropping oldest frame\n", - tx->dev->name, MAC_ARG(sta->addr)); + tx->dev->name, print_mac(mac, sta->addr)); } dev_kfree_skb(old); } else @@ -399,9 +403,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(sta->flags & WLAN_STA_PS)) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll " + printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, - MAC_ARG(sta->addr)); + print_mac(mac, sta->addr)); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ sta->pspoll = 0; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 6e12638054aa..360d11e9de15 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -132,6 +132,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) u8 mic[MICHAEL_MIC_LEN]; struct sk_buff *skb = rx->skb; int authenticator = 1, wpa_test = 0; + DECLARE_MAC_BUF(mac); fc = rx->fc; @@ -164,7 +165,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) return TXRX_DROP; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " - MAC_FMT "\n", rx->dev->name, MAC_ARG(sa)); + "%s\n", rx->dev->name, print_mac(mac, sa)); mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, (void *) skb->data); @@ -287,6 +288,7 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) int hdrlen, res, hwaccel = 0, wpa_test = 0; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; + DECLARE_MAC_BUF(mac); fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); @@ -319,8 +321,8 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) hwaccel, rx->u.rx.queue); if (res != TKIP_DECRYPT_OK || wpa_test) { printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from " - MAC_FMT " (res=%d)\n", - rx->dev->name, MAC_ARG(rx->sta->addr), res); + "%s (res=%d)\n", + rx->dev->name, print_mac(mac, rx->sta->addr), res); return TXRX_DROP; } @@ -542,6 +544,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) struct sk_buff *skb = rx->skb; u8 pn[CCMP_PN_LEN]; int data_len; + DECLARE_MAC_BUF(mac); fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); @@ -564,10 +567,11 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) { #ifdef CONFIG_MAC80211_DEBUG u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue]; + printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from " - MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " + "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name, - MAC_ARG(rx->sta->addr), + print_mac(mac, rx->sta->addr), pn[0], pn[1], pn[2], pn[3], pn[4], pn[5], ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]); #endif /* CONFIG_MAC80211_DEBUG */ @@ -591,8 +595,8 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) skb->data + skb->len - CCMP_MIC_LEN, skb->data + hdrlen + CCMP_HDR_LEN)) { printk(KERN_DEBUG "%s: CCMP decrypt failed for RX " - "frame from " MAC_FMT "\n", rx->dev->name, - MAC_ARG(rx->sta->addr)); + "frame from %s\n", rx->dev->name, + print_mac(mac, rx->sta->addr)); return TXRX_DROP; } } @@ -606,4 +610,3 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; } - diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index d6fc0575816b..1a99e2947145 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -243,12 +243,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) { unchar *addr = (unchar *)&a->dev_addr; + DECLARE_MAC_BUF(mac); if (str_size < 18) *str_buf = '\0'; else - sprintf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + sprintf(str_buf, "%s", print_mac(mac, addr)); return str_buf; } From eff1a59c48e3c6a006eb4fe5f2e405a996f2259d Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Tue, 25 Sep 2007 18:11:01 -0700 Subject: [PATCH 1425/2804] [P54]: add mac80211-based driver for prism54 softmac hardware Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 8 + drivers/net/wireless/Kconfig | 13 + drivers/net/wireless/Makefile | 4 + drivers/net/wireless/net2280.h | 452 ++++++++++++++ drivers/net/wireless/p54.h | 80 +++ drivers/net/wireless/p54common.c | 983 +++++++++++++++++++++++++++++++ drivers/net/wireless/p54common.h | 329 +++++++++++ drivers/net/wireless/p54pci.c | 691 ++++++++++++++++++++++ drivers/net/wireless/p54pci.h | 106 ++++ drivers/net/wireless/p54usb.c | 906 ++++++++++++++++++++++++++++ drivers/net/wireless/p54usb.h | 133 +++++ 11 files changed, 3705 insertions(+) create mode 100644 drivers/net/wireless/net2280.h create mode 100644 drivers/net/wireless/p54.h create mode 100644 drivers/net/wireless/p54common.c create mode 100644 drivers/net/wireless/p54common.h create mode 100644 drivers/net/wireless/p54pci.c create mode 100644 drivers/net/wireless/p54pci.h create mode 100644 drivers/net/wireless/p54usb.c create mode 100644 drivers/net/wireless/p54usb.h diff --git a/MAINTAINERS b/MAINTAINERS index 6ae2b9975269..c96505c2678d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3060,6 +3060,14 @@ L: kpreempt-tech@lists.sourceforge.net W: ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel S: Supported +P54 WIRELESS DRIVER +P: Michael Wu +M: flamingice@sourmilk.net +L: linux-wireless@vger.kernel.org +W: http://prism54.org +T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git +S: Maintained + PRISM54 WIRELESS DRIVER P: Luis R. Rodriguez M: mcgrof@gmail.com diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f481c757e22b..5a6fdfd0f140 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -577,6 +577,19 @@ config ADM8211 Thanks to Infineon-ADMtek for their support of this driver. +config P54_COMMON + tristate "Softmac Prism54 support" + depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL + +config P54_USB + tristate "Prism54 USB support" + depends on P54_COMMON && USB + select CRC32 + +config P54_PCI + tristate "Prism54 PCI support" + depends on P54_COMMON && PCI + source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index a7a15e3509e8..6f32b53ee128 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -54,3 +54,7 @@ obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_IWLWIFI) += iwlwifi/ obj-$(CONFIG_RT2X00) += rt2x00/ + +obj-$(CONFIG_P54_COMMON) += p54common.o +obj-$(CONFIG_P54_USB) += p54usb.o +obj-$(CONFIG_P54_PCI) += p54pci.o diff --git a/drivers/net/wireless/net2280.h b/drivers/net/wireless/net2280.h new file mode 100644 index 000000000000..120eb831b287 --- /dev/null +++ b/drivers/net/wireless/net2280.h @@ -0,0 +1,452 @@ +#ifndef NET2280_H +#define NET2280_H +/* + * NetChip 2280 high/full speed USB device controller. + * Unlike many such controllers, this one talks PCI. + */ + +/* + * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) + * Copyright (C) 2003 David Brownell + * + * 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 + */ + +/*-------------------------------------------------------------------------*/ + +/* NET2280 MEMORY MAPPED REGISTERS + * + * The register layout came from the chip documentation, and the bit + * number definitions were extracted from chip specification. + * + * Use the shift operator ('<<') to build bit masks, with readl/writel + * to access the registers through PCI. + */ + +/* main registers, BAR0 + 0x0000 */ +struct net2280_regs { + // offset 0x0000 + __le32 devinit; +#define LOCAL_CLOCK_FREQUENCY 8 +#define FORCE_PCI_RESET 7 +#define PCI_ID 6 +#define PCI_ENABLE 5 +#define FIFO_SOFT_RESET 4 +#define CFG_SOFT_RESET 3 +#define PCI_SOFT_RESET 2 +#define USB_SOFT_RESET 1 +#define M8051_RESET 0 + __le32 eectl; +#define EEPROM_ADDRESS_WIDTH 23 +#define EEPROM_CHIP_SELECT_ACTIVE 22 +#define EEPROM_PRESENT 21 +#define EEPROM_VALID 20 +#define EEPROM_BUSY 19 +#define EEPROM_CHIP_SELECT_ENABLE 18 +#define EEPROM_BYTE_READ_START 17 +#define EEPROM_BYTE_WRITE_START 16 +#define EEPROM_READ_DATA 8 +#define EEPROM_WRITE_DATA 0 + __le32 eeclkfreq; + u32 _unused0; + // offset 0x0010 + + __le32 pciirqenb0; /* interrupt PCI master ... */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + __le32 pciirqenb1; +#define PCI_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + __le32 cpu_irqenb0; /* ... or onboard 8051 */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + __le32 cpu_irqenb1; +#define CPU_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + + // offset 0x0020 + u32 _unused1; + __le32 usbirqenb1; +#define USB_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + __le32 irqstat0; +#define INTA_ASSERTED 12 +#define SETUP_PACKET_INTERRUPT 7 +#define ENDPOINT_F_INTERRUPT 6 +#define ENDPOINT_E_INTERRUPT 5 +#define ENDPOINT_D_INTERRUPT 4 +#define ENDPOINT_C_INTERRUPT 3 +#define ENDPOINT_B_INTERRUPT 2 +#define ENDPOINT_A_INTERRUPT 1 +#define ENDPOINT_0_INTERRUPT 0 + __le32 irqstat1; +#define POWER_STATE_CHANGE_INTERRUPT 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 +#define PCI_PARITY_ERROR_INTERRUPT 25 +#define PCI_INTA_INTERRUPT 24 +#define PCI_PME_INTERRUPT 23 +#define PCI_SERR_INTERRUPT 22 +#define PCI_PERR_INTERRUPT 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 +#define PCI_RETRY_ABORT_INTERRUPT 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 +#define GPIO_INTERRUPT 13 +#define DMA_D_INTERRUPT 12 +#define DMA_C_INTERRUPT 11 +#define DMA_B_INTERRUPT 10 +#define DMA_A_INTERRUPT 9 +#define EEPROM_DONE_INTERRUPT 8 +#define VBUS_INTERRUPT 7 +#define CONTROL_STATUS_INTERRUPT 6 +#define ROOT_PORT_RESET_INTERRUPT 4 +#define SUSPEND_REQUEST_INTERRUPT 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 +#define RESUME_INTERRUPT 1 +#define SOF_INTERRUPT 0 + // offset 0x0030 + __le32 idxaddr; + __le32 idxdata; + __le32 fifoctl; +#define PCI_BASE2_RANGE 16 +#define IGNORE_FIFO_AVAILABILITY 3 +#define PCI_BASE2_SELECT 2 +#define FIFO_CONFIGURATION_SELECT 0 + u32 _unused2; + // offset 0x0040 + __le32 memaddr; +#define START 28 +#define DIRECTION 27 +#define FIFO_DIAGNOSTIC_SELECT 24 +#define MEMORY_ADDRESS 0 + __le32 memdata0; + __le32 memdata1; + u32 _unused3; + // offset 0x0050 + __le32 gpioctl; +#define GPIO3_LED_SELECT 12 +#define GPIO3_INTERRUPT_ENABLE 11 +#define GPIO2_INTERRUPT_ENABLE 10 +#define GPIO1_INTERRUPT_ENABLE 9 +#define GPIO0_INTERRUPT_ENABLE 8 +#define GPIO3_OUTPUT_ENABLE 7 +#define GPIO2_OUTPUT_ENABLE 6 +#define GPIO1_OUTPUT_ENABLE 5 +#define GPIO0_OUTPUT_ENABLE 4 +#define GPIO3_DATA 3 +#define GPIO2_DATA 2 +#define GPIO1_DATA 1 +#define GPIO0_DATA 0 + __le32 gpiostat; +#define GPIO3_INTERRUPT 3 +#define GPIO2_INTERRUPT 2 +#define GPIO1_INTERRUPT 1 +#define GPIO0_INTERRUPT 0 +} __attribute__ ((packed)); + +/* usb control, BAR0 + 0x0080 */ +struct net2280_usb_regs { + // offset 0x0080 + __le32 stdrsp; +#define STALL_UNSUPPORTED_REQUESTS 31 +#define SET_TEST_MODE 16 +#define GET_OTHER_SPEED_CONFIGURATION 15 +#define GET_DEVICE_QUALIFIER 14 +#define SET_ADDRESS 13 +#define ENDPOINT_SET_CLEAR_HALT 12 +#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 +#define GET_STRING_DESCRIPTOR_2 10 +#define GET_STRING_DESCRIPTOR_1 9 +#define GET_STRING_DESCRIPTOR_0 8 +#define GET_SET_INTERFACE 6 +#define GET_SET_CONFIGURATION 5 +#define GET_CONFIGURATION_DESCRIPTOR 4 +#define GET_DEVICE_DESCRIPTOR 3 +#define GET_ENDPOINT_STATUS 2 +#define GET_INTERFACE_STATUS 1 +#define GET_DEVICE_STATUS 0 + __le32 prodvendid; +#define PRODUCT_ID 16 +#define VENDOR_ID 0 + __le32 relnum; + __le32 usbctl; +#define SERIAL_NUMBER_INDEX 16 +#define PRODUCT_ID_STRING_ENABLE 13 +#define VENDOR_ID_STRING_ENABLE 12 +#define USB_ROOT_PORT_WAKEUP_ENABLE 11 +#define VBUS_PIN 10 +#define TIMED_DISCONNECT 9 +#define SUSPEND_IMMEDIATELY 7 +#define SELF_POWERED_USB_DEVICE 6 +#define REMOTE_WAKEUP_SUPPORT 5 +#define PME_POLARITY 4 +#define USB_DETECT_ENABLE 3 +#define PME_WAKEUP_ENABLE 2 +#define DEVICE_REMOTE_WAKEUP_ENABLE 1 +#define SELF_POWERED_STATUS 0 + // offset 0x0090 + __le32 usbstat; +#define HIGH_SPEED 7 +#define FULL_SPEED 6 +#define GENERATE_RESUME 5 +#define GENERATE_DEVICE_REMOTE_WAKEUP 4 + __le32 xcvrdiag; +#define FORCE_HIGH_SPEED_MODE 31 +#define FORCE_FULL_SPEED_MODE 30 +#define USB_TEST_MODE 24 +#define LINE_STATE 16 +#define TRANSCEIVER_OPERATION_MODE 2 +#define TRANSCEIVER_SELECT 1 +#define TERMINATION_SELECT 0 + __le32 setup0123; + __le32 setup4567; + // offset 0x0090 + u32 _unused0; + __le32 ouraddr; +#define FORCE_IMMEDIATE 7 +#define OUR_USB_ADDRESS 0 + __le32 ourconfig; +} __attribute__ ((packed)); + +/* pci control, BAR0 + 0x0100 */ +struct net2280_pci_regs { + // offset 0x0100 + __le32 pcimstctl; +#define PCI_ARBITER_PARK_SELECT 13 +#define PCI_MULTI LEVEL_ARBITER 12 +#define PCI_RETRY_ABORT_ENABLE 11 +#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 +#define DMA_READ_MULTIPLE_ENABLE 9 +#define DMA_READ_LINE_ENABLE 8 +#define PCI_MASTER_COMMAND_SELECT 6 +#define MEM_READ_OR_WRITE 0 +#define IO_READ_OR_WRITE 1 +#define CFG_READ_OR_WRITE 2 +#define PCI_MASTER_START 5 +#define PCI_MASTER_READ_WRITE 4 +#define PCI_MASTER_WRITE 0 +#define PCI_MASTER_READ 1 +#define PCI_MASTER_BYTE_WRITE_ENABLES 0 + __le32 pcimstaddr; + __le32 pcimstdata; + __le32 pcimststat; +#define PCI_ARBITER_CLEAR 2 +#define PCI_EXTERNAL_ARBITER 1 +#define PCI_HOST_MODE 0 +} __attribute__ ((packed)); + +/* dma control, BAR0 + 0x0180 ... array of four structs like this, + * for channels 0..3. see also struct net2280_dma: descriptor + * that can be loaded into some of these registers. + */ +struct net2280_dma_regs { /* [11.7] */ + // offset 0x0180, 0x01a0, 0x01c0, 0x01e0, + __le32 dmactl; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 +#define DMA_CLEAR_COUNT_ENABLE 21 +#define DESCRIPTOR_POLLING_RATE 19 +#define POLL_CONTINUOUS 0 +#define POLL_1_USEC 1 +#define POLL_100_USEC 2 +#define POLL_1_MSEC 3 +#define DMA_VALID_BIT_POLLING_ENABLE 18 +#define DMA_VALID_BIT_ENABLE 17 +#define DMA_SCATTER_GATHER_ENABLE 16 +#define DMA_OUT_AUTO_START_ENABLE 4 +#define DMA_PREEMPT_ENABLE 3 +#define DMA_FIFO_VALIDATE 2 +#define DMA_ENABLE 1 +#define DMA_ADDRESS_HOLD 0 + __le32 dmastat; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 +#define DMA_TRANSACTION_DONE_INTERRUPT 24 +#define DMA_ABORT 1 +#define DMA_START 0 + u32 _unused0[2]; + // offset 0x0190, 0x01b0, 0x01d0, 0x01f0, + __le32 dmacount; +#define VALID_BIT 31 +#define DMA_DIRECTION 30 +#define DMA_DONE_INTERRUPT_ENABLE 29 +#define END_OF_CHAIN 28 +#define DMA_BYTE_COUNT_MASK ((1<<24)-1) +#define DMA_BYTE_COUNT 0 + __le32 dmaaddr; + __le32 dmadesc; + u32 _unused1; +} __attribute__ ((packed)); + +/* dedicated endpoint registers, BAR0 + 0x0200 */ + +struct net2280_dep_regs { /* [11.8] */ + // offset 0x0200, 0x0210, 0x220, 0x230, 0x240 + __le32 dep_cfg; + // offset 0x0204, 0x0214, 0x224, 0x234, 0x244 + __le32 dep_rsp; + u32 _unused[2]; +} __attribute__ ((packed)); + +/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs + * like this, for ep0 then the configurable endpoints A..F + * ep0 reserved for control; E and F have only 64 bytes of fifo + */ +struct net2280_ep_regs { /* [11.9] */ + // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 + __le32 ep_cfg; +#define ENDPOINT_BYTE_COUNT 16 +#define ENDPOINT_ENABLE 10 +#define ENDPOINT_TYPE 8 +#define ENDPOINT_DIRECTION 7 +#define ENDPOINT_NUMBER 0 + __le32 ep_rsp; +#define SET_NAK_OUT_PACKETS 15 +#define SET_EP_HIDE_STATUS_PHASE 14 +#define SET_EP_FORCE_CRC_ERROR 13 +#define SET_INTERRUPT_MODE 12 +#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 +#define SET_NAK_OUT_PACKETS_MODE 10 +#define SET_ENDPOINT_TOGGLE 9 +#define SET_ENDPOINT_HALT 8 +#define CLEAR_NAK_OUT_PACKETS 7 +#define CLEAR_EP_HIDE_STATUS_PHASE 6 +#define CLEAR_EP_FORCE_CRC_ERROR 5 +#define CLEAR_INTERRUPT_MODE 4 +#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 +#define CLEAR_NAK_OUT_PACKETS_MODE 2 +#define CLEAR_ENDPOINT_TOGGLE 1 +#define CLEAR_ENDPOINT_HALT 0 + __le32 ep_irqenb; +#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 +#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 +#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 + __le32 ep_stat; +#define FIFO_VALID_COUNT 24 +#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 +#define TIMEOUT 21 +#define USB_STALL_SENT 20 +#define USB_IN_NAK_SENT 19 +#define USB_IN_ACK_RCVD 18 +#define USB_OUT_PING_NAK_SENT 17 +#define USB_OUT_ACK_SENT 16 +#define FIFO_OVERFLOW 13 +#define FIFO_UNDERFLOW 12 +#define FIFO_FULL 11 +#define FIFO_EMPTY 10 +#define FIFO_FLUSH 9 +#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 +#define NAK_OUT_PACKETS 4 +#define DATA_PACKET_RECEIVED_INTERRUPT 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT 1 +#define DATA_IN_TOKEN_INTERRUPT 0 + // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 + __le32 ep_avail; + __le32 ep_data; + u32 _unused0[2]; +} __attribute__ ((packed)); + +struct net2280_reg_write { + __le16 port; + __le32 addr; + __le32 val; +} __attribute__ ((packed)); + +struct net2280_reg_read { + __le16 port; + __le32 addr; +} __attribute__ ((packed)); +#endif /* NET2280_H */ diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h new file mode 100644 index 000000000000..e558d697d9e5 --- /dev/null +++ b/drivers/net/wireless/p54.h @@ -0,0 +1,80 @@ +#ifndef PRISM54_H +#define PRISM54_H + +/* + * Shared defines for all mac80211 Prism54 code + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * 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. + */ + +enum control_frame_types { + P54_CONTROL_TYPE_FILTER_SET = 0, + P54_CONTROL_TYPE_CHANNEL_CHANGE, + P54_CONTROL_TYPE_FREQDONE, + P54_CONTROL_TYPE_DCFINIT, + P54_CONTROL_TYPE_FREEQUEUE = 7, + P54_CONTROL_TYPE_TXDONE, + P54_CONTROL_TYPE_PING, + P54_CONTROL_TYPE_STAT_READBACK, + P54_CONTROL_TYPE_BBP, + P54_CONTROL_TYPE_EEPROM_READBACK, + P54_CONTROL_TYPE_LED +}; + +struct p54_control_hdr { + __le16 magic1; + __le16 len; + __le32 req_id; + __le16 type; /* enum control_frame_types */ + u8 retry1; + u8 retry2; + u8 data[0]; +} __attribute__ ((packed)); + +#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */) +#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 ) + +#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 + +struct p54_common { + u32 rx_start; + u32 rx_end; + struct sk_buff_head tx_queue; + void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data, + size_t len, int free_on_tx); + int (*open)(struct ieee80211_hw *dev); + void (*stop)(struct ieee80211_hw *dev); + int mode; + u8 *mac_addr; + struct pda_iq_autocal_entry *iq_autocal; + unsigned int iq_autocal_len; + struct pda_channel_output_limit *output_limit; + unsigned int output_limit_len; + struct pda_pa_curve_data *curve_data; + __le16 rxhw; + u8 version; + unsigned int tx_hdr_len; + void *cached_vdcf; + unsigned int fw_var; + /* FIXME: this channels/modes/rates stuff sucks */ + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_hw_mode modes[2]; + struct ieee80211_tx_queue_stats tx_stats; +}; + +int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); +void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); +int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); +void p54_fill_eeprom_readback(struct p54_control_hdr *hdr); +struct ieee80211_hw *p54_init_common(size_t priv_data_len); +void p54_free_common(struct ieee80211_hw *dev); + +#endif /* PRISM54_H */ diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c new file mode 100644 index 000000000000..b05b5c5b4c04 --- /dev/null +++ b/drivers/net/wireless/p54common.c @@ -0,0 +1,983 @@ + +/* + * Common code 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. + * + * 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 "p54common.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_DESCRIPTION("Softmac Prism54 common code"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("prism54common"); + +void 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; + + if (priv->rx_start) + return; + + 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: + switch (be32_to_cpu(*bootrec->data)) { + case FW_FMAC: + printk(KERN_INFO "p54: FreeMAC firmware\n"); + break; + case FW_LM20: + printk(KERN_INFO "p54: LM20 firmware\n"); + break; + case FW_LM86: + printk(KERN_INFO "p54: LM86 firmware\n"); + break; + case FW_LM87: + printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n"); + break; + default: + printk(KERN_INFO "p54: unknown firmware\n"); + break; + } + 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: + priv->rx_start = le32_to_cpu(bootrec->data[1]); + /* FIXME add sanity checking */ + priv->rx_end = le32_to_cpu(bootrec->data[2]) - 0x3500; + 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 == 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 "p54: FW rev %s - Softmac protocol %x.%x\n", + fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); + + if (priv->fw_var >= 0x300) { + /* Firmware supports QoS, use it! */ + priv->tx_stats.data[0].limit = 3; + priv->tx_stats.data[1].limit = 4; + priv->tx_stats.data[2].limit = 3; + priv->tx_stats.data[3].limit = 1; + dev->queues = 4; + } +} +EXPORT_SYMBOL_GPL(p54_parse_firmware); + +static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct pda_pa_curve_data_sample_rev1 *rev1; + struct pda_pa_curve_data_sample_rev0 *rev0; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*rev1) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kmalloc(cd_len, GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + memcpy(priv->curve_data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = priv->curve_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++) { + rev1 = target; + rev0 = source; + + rev1->rf_power = rev0->rf_power; + rev1->pa_detector = rev0->pa_detector; + rev1->data_64qam = rev0->pcv; + /* "invent" the points for the other modulations */ +#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y) + rev1->data_16qam = SUB(rev0->pcv, 12); + rev1->data_qpsk = SUB(rev1->data_16qam, 12); + rev1->data_bpsk = SUB(rev1->data_qpsk, 12); + rev1->data_barker= SUB(rev1->data_bpsk, 14); +#undef SUB + target += sizeof(*rev1); + source += sizeof(*rev0); + } + } + + return 0; +} + +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; + int i = 0; + unsigned int data_len, entry_len; + void *tmp; + int err; + + wrap = (struct eeprom_pda_wrap *) eeprom; + entry = (void *)wrap->data + wrap->len; + i += 2; + i += le16_to_cpu(entry->len)*2; + while (i < len) { + entry_len = le16_to_cpu(entry->len); + data_len = ((entry_len - 1) << 1); + switch (le16_to_cpu(entry->code)) { + case PDR_MAC_ADDRESS: + SET_IEEE80211_PERM_ADDR(dev, entry->data); + break; + case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: + if (data_len < 2) { + err = -EINVAL; + goto err; + } + + if (2 + entry->data[1]*sizeof(*priv->output_limit) > data_len) { + err = -EINVAL; + goto err; + } + + priv->output_limit = kmalloc(entry->data[1] * + sizeof(*priv->output_limit), GFP_KERNEL); + + if (!priv->output_limit) { + err = -ENOMEM; + goto err; + } + + memcpy(priv->output_limit, &entry->data[2], + entry->data[1]*sizeof(*priv->output_limit)); + priv->output_limit_len = entry->data[1]; + break; + case PDR_PRISM_PA_CAL_CURVE_DATA: + if (data_len < sizeof(struct pda_pa_curve_data)) { + err = -EINVAL; + goto err; + } + + if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) { + priv->curve_data = kmalloc(data_len, GFP_KERNEL); + if (!priv->curve_data) { + err = -ENOMEM; + goto err; + } + + memcpy(priv->curve_data, entry->data, data_len); + } else { + err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data); + 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_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) + priv->rxhw = exp_if->variant & cpu_to_le16(0x07); + tmp += sizeof(struct bootrec_exp_if); + } + break; + case PDR_HARDWARE_PLATFORM_COMPONENT_ID: + priv->version = *(u8 *)(entry->data + 1); + break; + case PDR_END: + i = len; + break; + } + + entry = (void *)entry + (entry_len + 1)*2; + i += 2; + i += entry_len*2; + } + + if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) { + printk(KERN_ERR "p54: not all required entries found in eeprom!\n"); + err = -EINVAL; + goto err; + } + + 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 "p54: eeprom parse failed!\n"); + return err; +} +EXPORT_SYMBOL_GPL(p54_parse_eeprom); + +void p54_fill_eeprom_readback(struct p54_control_hdr *hdr) +{ + struct p54_eeprom_lm86 *eeprom_hdr; + + hdr->magic1 = cpu_to_le16(0x8000); + hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK); + hdr->retry1 = hdr->retry2 = 0; + eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data; + eeprom_hdr->offset = 0x0; + eeprom_hdr->len = cpu_to_le16(0x2000); +} +EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback); + +static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; + struct ieee80211_rx_status rx_status = {0}; + u16 freq = le16_to_cpu(hdr->freq); + + rx_status.ssi = hdr->rssi; + rx_status.rate = hdr->rate & 0x1f; /* report short preambles & CCK too */ + rx_status.channel = freq == 2484 ? 14 : (freq - 2407)/5; + rx_status.freq = freq; + rx_status.phymode = MODE_IEEE80211G; + rx_status.antenna = hdr->antenna; + rx_status.mactime = le64_to_cpu(hdr->timestamp); + + skb_pull(skb, sizeof(*hdr)); + skb_trim(skb, le16_to_cpu(hdr->len)); + + ieee80211_rx_irqsafe(dev, skb, &rx_status); +} + +static void inline p54_wake_free_queues(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int i; + + /* ieee80211_start_queues is great if all queues are really empty. + * But, what if some are full? */ + + for (i = 0; i < dev->queues; i++) + if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit) + ieee80211_wake_queue(dev, i); +} + +static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data; + struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; + u32 addr = le32_to_cpu(hdr->req_id) - 0x70; + struct memrecord *range = NULL; + u32 freed = 0; + u32 last_addr = priv->rx_start; + + while (entry != (struct sk_buff *)&priv->tx_queue) { + range = (struct memrecord *)&entry->cb; + if (range->start_addr == addr) { + struct ieee80211_tx_status status = {{0}}; + struct p54_control_hdr *entry_hdr; + struct p54_tx_control_allocdata *entry_data; + int pad = 0; + + if (entry->next != (struct sk_buff *)&priv->tx_queue) + freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr; + else + freed = priv->rx_end - last_addr; + + last_addr = range->end_addr; + __skb_unlink(entry, &priv->tx_queue); + if (!range->control) { + kfree_skb(entry); + break; + } + memcpy(&status.control, range->control, + sizeof(status.control)); + kfree(range->control); + priv->tx_stats.data[status.control.queue].len--; + + entry_hdr = (struct p54_control_hdr *) entry->data; + entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; + if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) + pad = entry_data->align[0]; + + if (!status.control.flags & IEEE80211_TXCTL_NO_ACK) { + if (!(payload->status & 0x01)) + status.flags |= IEEE80211_TX_STATUS_ACK; + else + status.excessive_retries = 1; + } + status.retry_count = payload->retries - 1; + status.ack_signal = le16_to_cpu(payload->ack_rssi); + skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); + ieee80211_tx_status_irqsafe(dev, entry, &status); + break; + } else + last_addr = range->end_addr; + entry = entry->next; + } + + if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + + sizeof(struct p54_control_hdr)) + p54_wake_free_queues(dev); +} + +static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_control_hdr *hdr = (struct p54_control_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_BBP: + break; + default: + printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n", + wiphy_name(dev->wiphy), le16_to_cpu(hdr->type)); + break; + } +} + +/* returns zero if skb can be reused */ +int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8; + switch (type) { + case 0x00: + case 0x01: + p54_rx_data(dev, skb); + return -1; + case 0x4d: + /* TODO: do something better... but then again, I've never seen this happen */ + printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n", + wiphy_name(dev->wiphy)); + break; + case 0x80: + p54_rx_control(dev, skb); + break; + default: + printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n", + wiphy_name(dev->wiphy), type); + break; + } + return 0; +} +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 frees + * allocated areas. + */ +static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, + struct p54_control_hdr *data, u32 len, + struct ieee80211_tx_control *control) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *entry = priv->tx_queue.next; + struct sk_buff *target_skb = NULL; + struct memrecord *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 + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */ + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + left = skb_queue_len(&priv->tx_queue); + while (left--) { + u32 hole_size; + range = (struct memrecord *)&entry->cb; + 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)) { + range = (struct memrecord *)&target_skb->cb; + target_addr = range->end_addr; + } + } else + largest_hole = max(largest_hole, priv->rx_end - last_addr); + + if (skb) { + range = (struct memrecord *)&skb->cb; + range->start_addr = target_addr; + range->end_addr = target_addr + len; + range->control = control; + __skb_queue_after(&priv->tx_queue, target_skb, skb); + if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + + sizeof(struct p54_control_hdr)) + ieee80211_stop_queues(dev); + } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + + data->req_id = cpu_to_le32(target_addr + 0x70); +} + +static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct ieee80211_tx_queue_stats_data *current_queue; + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_allocdata *txhdr; + struct ieee80211_tx_control *control_copy; + size_t padding, len; + u8 rate; + + current_queue = &priv->tx_stats.data[control->queue]; + if (unlikely(current_queue->len > current_queue->limit)) + return NETDEV_TX_BUSY; + current_queue->len++; + current_queue->count++; + if (current_queue->len == current_queue->limit) + ieee80211_stop_queue(dev, control->queue); + + padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; + len = skb->len; + + control_copy = kmalloc(sizeof(*control), GFP_ATOMIC); + if (control_copy) + memcpy(control_copy, control, sizeof(*control)); + + txhdr = (struct p54_tx_control_allocdata *) + skb_push(skb, sizeof(*txhdr) + padding); + hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); + + if (padding) + hdr->magic1 = cpu_to_le16(0x4010); + else + hdr->magic1 = cpu_to_le16(0x0010); + hdr->len = cpu_to_le16(len); + hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1); + hdr->retry1 = hdr->retry2 = control->retry_limit; + p54_assign_address(dev, skb, hdr, skb->len, control_copy); + + memset(txhdr->wep_key, 0x0, 16); + txhdr->padding = 0; + txhdr->padding2 = 0; + + /* TODO: add support for alternate retry TX rates */ + rate = control->tx_rate; + if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + rate |= 0x40; + else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + rate |= 0x20; + memset(txhdr->rateset, rate, 8); + txhdr->wep_key_present = 0; + txhdr->wep_key_len = 0; + txhdr->frame_type = cpu_to_le32(control->queue + 4); + txhdr->magic4 = 0; + txhdr->antenna = (control->antenna_sel_tx == 0) ? + 2 : control->antenna_sel_tx - 1; + txhdr->output_power = 0x7f; // HW Maximum + txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ? + 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23)); + if (padding) + txhdr->align[0] = padding; + + priv->tx(dev, hdr, skb->len, 0); + return 0; +} + +static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, + const u8 *dst, const u8 *src, u8 antenna, + u32 magic3, u32 magic8, u32 magic9) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_filter *filter; + + hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + + priv->tx_hdr_len, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; + + filter = (struct p54_tx_control_filter *) hdr->data; + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*filter)); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); + + filter->filter_type = cpu_to_le16(filter_type); + memcpy(filter->dst, dst, ETH_ALEN); + if (!src) + memset(filter->src, ~0, ETH_ALEN); + else + memcpy(filter->src, src, ETH_ALEN); + filter->antenna = antenna; + filter->magic3 = cpu_to_le32(magic3); + filter->rx_addr = cpu_to_le32(priv->rx_end); + filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */ + filter->rxhw = priv->rxhw; + filter->magic8 = cpu_to_le16(magic8); + filter->magic9 = cpu_to_le16(magic9); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1); + return 0; +} + +static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_channel *chan; + unsigned int i; + size_t payload_len = sizeof(*chan) + sizeof(u32)*2 + + sizeof(*chan->curve_data) * + priv->curve_data->points_per_channel; + void *entry; + + hdr = kzalloc(sizeof(*hdr) + payload_len + + priv->tx_hdr_len, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; + + chan = (struct p54_tx_control_channel *) hdr->data; + + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*chan)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL); + + chan->magic1 = cpu_to_le16(0x1); + chan->magic2 = cpu_to_le16(0x0); + + for (i = 0; i < priv->iq_autocal_len; i++) { + if (priv->iq_autocal[i].freq != freq) + continue; + + memcpy(&chan->iq_autocal, &priv->iq_autocal[i], + sizeof(*priv->iq_autocal)); + break; + } + if (i == priv->iq_autocal_len) + goto err; + + for (i = 0; i < priv->output_limit_len; i++) { + if (priv->output_limit[i].freq != freq) + continue; + + chan->val_barker = 0x38; + chan->val_bpsk = priv->output_limit[i].val_bpsk; + chan->val_qpsk = priv->output_limit[i].val_qpsk; + chan->val_16qam = priv->output_limit[i].val_16qam; + chan->val_64qam = priv->output_limit[i].val_64qam; + break; + } + if (i == priv->output_limit_len) + goto err; + + chan->pa_points_per_curve = priv->curve_data->points_per_channel; + + entry = priv->curve_data->data; + for (i = 0; i < priv->curve_data->channels; i++) { + if (*((__le16 *)entry) != freq) { + entry += sizeof(__le16); + entry += sizeof(struct pda_pa_curve_data_sample_rev1) * + chan->pa_points_per_curve; + continue; + } + + entry += sizeof(__le16); + memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * + chan->pa_points_per_curve); + break; + } + + memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4); + + priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1); + return 0; + + err: + printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); + kfree(hdr); + return -EINVAL; +} + +static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_led *led; + + hdr = kzalloc(sizeof(*hdr) + sizeof(*led) + + priv->tx_hdr_len, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*led)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL); + + led = (struct p54_tx_control_led *) hdr->data; + led->mode = cpu_to_le16(mode); + led->led_permanent = cpu_to_le16(link); + led->led_temporary = cpu_to_le16(act); + led->duration = cpu_to_le16(1000); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1); + + return 0; +} + +#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, burst) \ +do { \ + queue.aifs = cpu_to_le16(ai_fs); \ + queue.cwmin = cpu_to_le16(cw_min); \ + queue.cwmax = cpu_to_le16(cw_max); \ + queue.txop = (burst == 0) ? \ + 0 : cpu_to_le16((burst * 100) / 32 + 1); \ +} while(0) + +static void p54_init_vdcf(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_vdcf *vdcf; + + /* all USB V1 adapters need a extra headroom */ + hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*vdcf)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT); + hdr->req_id = cpu_to_le32(priv->rx_start); + + vdcf = (struct p54_tx_control_vdcf *) hdr->data; + + P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 0x000f); + P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 0x001e); + P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 0x0014); + P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0x0000); +} + +static void p54_set_vdcf(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_vdcf *vdcf; + + hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL); + + vdcf = (struct p54_tx_control_vdcf *) hdr->data; + + if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + vdcf->slottime = 9; + vdcf->magic1 = 0x00; + vdcf->magic2 = 0x10; + } else { + vdcf->slottime = 20; + vdcf->magic1 = 0x0a; + vdcf->magic2 = 0x06; + } + + /* (see prism54/isl_oid.h for further details) */ + vdcf->frameburst = cpu_to_le16(0); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); +} + +static int p54_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + int err; + + /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ + if (priv->mode != IEEE80211_IF_TYPE_MGMT) + return -1; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + priv->mac_addr = conf->mac_addr; + + err = priv->open(dev); + if (err) { + priv->mode = IEEE80211_IF_TYPE_MGMT; + skb_queue_purge(&priv->tx_queue); + return err; + } + + p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642); + p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642); + p54_set_vdcf(dev); + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0); + break; + } + + p54_set_leds(dev, 1, 0, 0); + + return 0; +} + +static void p54_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + while ((skb = skb_dequeue(&priv->tx_queue))) { + struct memrecord *range = (struct memrecord *)&skb->cb; + if (range->control) + kfree(range->control); + kfree_skb(skb); + } + priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->stop(dev); +} + +static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +{ + int ret; + + ret = p54_set_freq(dev, cpu_to_le16(conf->freq)); + p54_set_vdcf(dev); + return ret; +} + +static int p54_config_interface(struct ieee80211_hw *dev, int if_id, + struct ieee80211_if_conf *conf) +{ + struct p54_common *priv = dev->priv; + + p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642); + p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0); + p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); + return 0; +} + +static int p54_conf_tx(struct ieee80211_hw *dev, int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct p54_common *priv = dev->priv; + struct p54_tx_control_vdcf *vdcf; + + vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) + ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); + + if ((params) && !((queue < 0) || (queue > 4))) { + P54_SET_QUEUE(vdcf->queue[queue], params->aifs, + params->cw_min, params->cw_max, params->burst_time); + } else + return -EINVAL; + + p54_set_vdcf(dev); + + return 0; +} + +static int p54_get_stats(struct ieee80211_hw *dev, + struct ieee80211_low_level_stats *stats) +{ + /* TODO */ + return 0; +} + +static int p54_get_tx_stats(struct ieee80211_hw *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct p54_common *priv = dev->priv; + unsigned int i; + + for (i = 0; i < dev->queues; i++) + memcpy(&stats->data[i], &priv->tx_stats.data[i], + sizeof(stats->data[i])); + + return 0; +} + +static const struct ieee80211_ops p54_ops = { + .tx = p54_tx, + .add_interface = p54_add_interface, + .remove_interface = p54_remove_interface, + .config = p54_config, + .config_interface = p54_config_interface, + .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; + int i; + + dev = ieee80211_alloc_hw(priv_data_len, &p54_ops); + if (!dev) + return NULL; + + priv = dev->priv; + priv->mode = IEEE80211_IF_TYPE_MGMT; + skb_queue_head_init(&priv->tx_queue); + memcpy(priv->channels, p54_channels, sizeof(p54_channels)); + memcpy(priv->rates, p54_rates, sizeof(p54_rates)); + priv->modes[1].mode = MODE_IEEE80211B; + priv->modes[1].num_rates = 4; + priv->modes[1].rates = priv->rates; + priv->modes[1].num_channels = ARRAY_SIZE(p54_channels); + priv->modes[1].channels = priv->channels; + priv->modes[0].mode = MODE_IEEE80211G; + priv->modes[0].num_rates = ARRAY_SIZE(p54_rates); + priv->modes[0].rates = priv->rates; + priv->modes[0].num_channels = ARRAY_SIZE(p54_channels); + priv->modes[0].channels = priv->channels; + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ + IEEE80211_HW_RX_INCLUDES_FCS; + dev->channel_change_time = 1000; /* TODO: find actual value */ + dev->max_rssi = 127; + + priv->tx_stats.data[0].limit = 5; + dev->queues = 1; + + dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + + sizeof(struct p54_tx_control_allocdata); + + priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf) + + priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL); + + if (!priv->cached_vdcf) { + ieee80211_free_hw(dev); + return NULL; + } + + p54_init_vdcf(dev); + + for (i = 0; i < 2; i++) { + if (ieee80211_register_hwmode(dev, &priv->modes[i])) { + kfree(priv->cached_vdcf); + ieee80211_free_hw(dev); + return NULL; + } + } + + return dev; +} +EXPORT_SYMBOL_GPL(p54_init_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->cached_vdcf); +} +EXPORT_SYMBOL_GPL(p54_free_common); + +static int __init p54_init(void) +{ + return 0; +} + +static void __exit p54_exit(void) +{ +} + +module_init(p54_init); +module_exit(p54_exit); diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54common.h new file mode 100644 index 000000000000..a721334e20d9 --- /dev/null +++ b/drivers/net/wireless/p54common.h @@ -0,0 +1,329 @@ +#ifndef PRISM54COMMON_H +#define PRISM54COMMON_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. + * + * 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[0]; +} __attribute__((packed)); + +struct bootrec_exp_if { + __le16 role; + __le16 if_id; + __le16 variant; + __le16 btm_compat; + __le16 top_compat; +} __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 FW_FMAC 0x464d4143 +#define FW_LM86 0x4c4d3836 +#define FW_LM87 0x4c4d3837 +#define FW_LM20 0x4c4d3230 + +/* 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 { + u32 magic; + u16 pad; + u16 len; + u32 arm_opcode; + u8 data[0]; +} __attribute__ ((packed)); + +struct pda_iq_autocal_entry { + __le16 freq; + __le16 iq_param[4]; +} __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; + 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)); + +/* + * 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 + +/* stored in skb->cb */ +struct memrecord { + u32 start_addr; + u32 end_addr; + struct ieee80211_tx_control *control; +}; + +struct p54_eeprom_lm86 { + __le16 offset; + __le16 len; + u8 data[0]; +} __attribute__ ((packed)); + +struct p54_rx_hdr { + __le16 magic; + __le16 len; + __le16 freq; + u8 antenna; + u8 rate; + u8 rssi; + u8 quality; + u16 unknown2; + __le64 timestamp; + u8 data[0]; +} __attribute__ ((packed)); + +struct p54_frame_sent_hdr { + u8 status; + u8 retries; + __le16 ack_rssi; + __le16 seq; + u16 rate; +} __attribute__ ((packed)); + +struct p54_tx_control_allocdata { + u8 rateset[8]; + u16 padding; + u8 wep_key_present; + u8 wep_key_len; + u8 wep_key[16]; + __le32 frame_type; + u32 padding2; + __le16 magic4; + u8 antenna; + u8 output_power; + __le32 magic5; + u8 align[0]; +} __attribute__ ((packed)); + +struct p54_tx_control_filter { + __le16 filter_type; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 antenna; + u8 debug; + __le32 magic3; + u8 rates[8]; // FIXME: what's this for? + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 magic8; + __le16 magic9; +} __attribute__ ((packed)); + +struct p54_tx_control_channel { + __le16 magic1; + __le16 magic2; + u8 padding1[20]; + struct pda_iq_autocal_entry iq_autocal; + u8 pa_points_per_curve; + u8 val_barker; + u8 val_bpsk; + u8 val_qpsk; + u8 val_16qam; + u8 val_64qam; + struct pda_pa_curve_data_sample_rev1 curve_data[0]; + /* additional padding/data after curve_data */ +} __attribute__ ((packed)); + +struct p54_tx_control_led { + __le16 mode; + __le16 led_temporary; + __le16 led_permanent; + __le16 duration; +} __attribute__ ((packed)); + +struct p54_tx_vdcf_queues { + __le16 aifs; + __le16 cwmin; + __le16 cwmax; + __le16 txop; +} __attribute__ ((packed)); + +struct p54_tx_control_vdcf { + u8 padding; + u8 slottime; + u8 magic1; + u8 magic2; + struct p54_tx_vdcf_queues queue[8]; + u8 pad2[4]; + __le16 frameburst; +} __attribute__ ((packed)); + +static const struct ieee80211_rate p54_rates[] = { + { .rate = 10, + .val = 0, + .val2 = 0x10, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 20, + .val = 1, + .val2 = 0x11, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 55, + .val = 2, + .val2 = 0x12, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 110, + .val = 3, + .val2 = 0x13, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 60, + .val = 4, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 90, + .val = 5, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 120, + .val = 6, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 180, + .val = 7, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 240, + .val = 8, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 360, + .val = 9, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 480, + .val = 10, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 540, + .val = 11, + .flags = IEEE80211_RATE_OFDM }, +}; + +// TODO: just generate this.. +static const struct ieee80211_channel p54_channels[] = { + { .chan = 1, + .freq = 2412}, + { .chan = 2, + .freq = 2417}, + { .chan = 3, + .freq = 2422}, + { .chan = 4, + .freq = 2427}, + { .chan = 5, + .freq = 2432}, + { .chan = 6, + .freq = 2437}, + { .chan = 7, + .freq = 2442}, + { .chan = 8, + .freq = 2447}, + { .chan = 9, + .freq = 2452}, + { .chan = 10, + .freq = 2457}, + { .chan = 11, + .freq = 2462}, + { .chan = 12, + .freq = 2467}, + { .chan = 13, + .freq = 2472}, + { .chan = 14, + .freq = 2484} +}; + +#endif /* PRISM54COMMON_H */ diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c new file mode 100644 index 000000000000..e9ecc663dc70 --- /dev/null +++ b/drivers/net/wireless/p54pci.c @@ -0,0 +1,691 @@ + +/* + * Linux device driver for PCI based Prism54 + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * 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 "p54.h" +#include "p54pci.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_DESCRIPTION("Prism54 PCI wireless driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("prism54pci"); + +static struct pci_device_id p54p_table[] __devinitdata = { + /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ + { PCI_DEVICE(0x1260, 0x3890) }, + /* 3COM 3CRWE154G72 Wireless LAN adapter */ + { PCI_DEVICE(0x10b7, 0x6001) }, + /* Intersil PRISM Indigo Wireless LAN adapter */ + { PCI_DEVICE(0x1260, 0x3877) }, + /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ + { PCI_DEVICE(0x1260, 0x3886) }, +}; + +MODULE_DEVICE_TABLE(pci, p54p_table); + +static int p54p_upload_firmware(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + const struct firmware *fw_entry = NULL; + __le32 reg; + int err; + u32 *data; + u32 remains, left, device_addr; + + P54P_WRITE(int_enable, 0); + P54P_READ(int_enable); + udelay(10); + + reg = P54P_READ(ctrl_stat); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT); + P54P_WRITE(ctrl_stat, reg); + P54P_READ(ctrl_stat); + udelay(10); + + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); + P54P_WRITE(ctrl_stat, reg); + wmb(); + udelay(10); + + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + P54P_WRITE(ctrl_stat, reg); + wmb(); + + mdelay(50); + + err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); + if (err) { + printk(KERN_ERR "%s (prism54pci): cannot find firmware " + "(isl3886)\n", pci_name(priv->pdev)); + return err; + } + + p54_parse_firmware(dev, fw_entry); + + data = (u32 *) fw_entry->data; + remains = fw_entry->size; + device_addr = ISL38XX_DEV_FIRMWARE_ADDR; + while (remains) { + u32 i = 0; + left = min((u32)0x1000, remains); + P54P_WRITE(direct_mem_base, cpu_to_le32(device_addr)); + P54P_READ(int_enable); + + device_addr += 0x1000; + while (i < left) { + P54P_WRITE(direct_mem_win[i], *data++); + i += sizeof(u32); + } + + remains -= left; + P54P_READ(int_enable); + } + + release_firmware(fw_entry); + + reg = P54P_READ(ctrl_stat); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT); + P54P_WRITE(ctrl_stat, reg); + P54P_READ(ctrl_stat); + udelay(10); + + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); + P54P_WRITE(ctrl_stat, reg); + wmb(); + udelay(10); + + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + P54P_WRITE(ctrl_stat, reg); + wmb(); + udelay(10); + + return 0; +} + +static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id) +{ + struct p54p_priv *priv = (struct p54p_priv *) dev_id; + __le32 reg; + + reg = P54P_READ(int_ident); + P54P_WRITE(int_ack, reg); + + if (reg & P54P_READ(int_enable)) + complete(&priv->boot_comp); + + return IRQ_HANDLED; +} + +static int p54p_read_eeprom(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + int err; + struct p54_control_hdr *hdr; + void *eeprom; + dma_addr_t rx_mapping, tx_mapping; + u16 alen; + + init_completion(&priv->boot_comp); + err = request_irq(priv->pdev->irq, &p54p_simple_interrupt, + IRQF_SHARED, "prism54pci", priv); + if (err) { + printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n", + pci_name(priv->pdev)); + return err; + } + + eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL); + if (!eeprom) { + printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n", + pci_name(priv->pdev)); + err = -ENOMEM; + goto out; + } + + memset(priv->ring_control, 0, sizeof(*priv->ring_control)); + P54P_WRITE(ring_control_base, priv->ring_control_dma); + P54P_READ(ring_control_base); + udelay(10); + + P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT)); + P54P_READ(int_enable); + udelay(10); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); + + if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { + printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n", + pci_name(priv->pdev)); + err = -EINVAL; + goto out; + } + + P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); + P54P_READ(int_enable); + + hdr = eeprom + 0x2010; + p54_fill_eeprom_readback(hdr); + hdr->req_id = cpu_to_le32(priv->common.rx_start); + + rx_mapping = pci_map_single(priv->pdev, eeprom, + 0x2010, PCI_DMA_FROMDEVICE); + tx_mapping = pci_map_single(priv->pdev, (void *)hdr, + EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); + + priv->ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping); + priv->ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010); + priv->ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping); + priv->ring_control->tx_data[0].device_addr = hdr->req_id; + priv->ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN); + + priv->ring_control->host_idx[2] = cpu_to_le32(1); + priv->ring_control->host_idx[1] = cpu_to_le32(1); + + wmb(); + mdelay(100); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + + wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); + wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); + + pci_unmap_single(priv->pdev, tx_mapping, + EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); + pci_unmap_single(priv->pdev, rx_mapping, + 0x2010, PCI_DMA_FROMDEVICE); + + alen = le16_to_cpu(priv->ring_control->rx_mgmt[0].len); + if (le32_to_cpu(priv->ring_control->device_idx[2]) != 1 || + alen < 0x10) { + printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n", + pci_name(priv->pdev)); + err = -EINVAL; + goto out; + } + + p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10); + + out: + kfree(eeprom); + P54P_WRITE(int_enable, 0); + P54P_READ(int_enable); + udelay(10); + free_irq(priv->pdev->irq, priv); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); + return err; +} + +static void p54p_refill_rx_ring(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + u32 limit, host_idx, idx; + + host_idx = le32_to_cpu(priv->ring_control->host_idx[0]); + limit = host_idx; + limit -= le32_to_cpu(priv->ring_control->device_idx[0]); + limit = ARRAY_SIZE(priv->ring_control->rx_data) - limit; + + idx = host_idx % ARRAY_SIZE(priv->ring_control->rx_data); + while (limit-- > 1) { + struct p54p_desc *desc = &priv->ring_control->rx_data[idx]; + + if (!desc->host_addr) { + struct sk_buff *skb; + dma_addr_t mapping; + skb = dev_alloc_skb(MAX_RX_SIZE); + if (!skb) + break; + + mapping = pci_map_single(priv->pdev, + skb_tail_pointer(skb), + MAX_RX_SIZE, + PCI_DMA_FROMDEVICE); + desc->host_addr = cpu_to_le32(mapping); + desc->device_addr = 0; // FIXME: necessary? + desc->len = cpu_to_le16(MAX_RX_SIZE); + desc->flags = 0; + priv->rx_buf[idx] = skb; + } + + idx++; + host_idx++; + idx %= ARRAY_SIZE(priv->ring_control->rx_data); + } + + wmb(); + priv->ring_control->host_idx[0] = cpu_to_le32(host_idx); +} + +static irqreturn_t p54p_interrupt(int irq, void *dev_id) +{ + struct ieee80211_hw *dev = dev_id; + struct p54p_priv *priv = dev->priv; + __le32 reg; + + spin_lock(&priv->lock); + reg = P54P_READ(int_ident); + if (unlikely(reg == 0xFFFFFFFF)) { + spin_unlock(&priv->lock); + return IRQ_HANDLED; + } + + P54P_WRITE(int_ack, reg); + + reg &= P54P_READ(int_enable); + + if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { + struct p54p_desc *desc; + u32 idx, i; + i = priv->tx_idx; + i %= ARRAY_SIZE(priv->ring_control->tx_data); + priv->tx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[1]); + idx %= ARRAY_SIZE(priv->ring_control->tx_data); + + while (i != idx) { + desc = &priv->ring_control->tx_data[i]; + if (priv->tx_buf[i]) { + kfree(priv->tx_buf[i]); + priv->tx_buf[i] = NULL; + } + + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + + desc->host_addr = 0; + desc->device_addr = 0; + desc->len = 0; + desc->flags = 0; + + i++; + i %= ARRAY_SIZE(priv->ring_control->tx_data); + } + + i = priv->rx_idx; + i %= ARRAY_SIZE(priv->ring_control->rx_data); + priv->rx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[0]); + idx %= ARRAY_SIZE(priv->ring_control->rx_data); + while (i != idx) { + u16 len; + struct sk_buff *skb; + desc = &priv->ring_control->rx_data[i]; + len = le16_to_cpu(desc->len); + skb = priv->rx_buf[i]; + + skb_put(skb, len); + + if (p54_rx(dev, skb)) { + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + + priv->rx_buf[i] = NULL; + desc->host_addr = 0; + } else { + skb_trim(skb, 0); + desc->len = cpu_to_le16(MAX_RX_SIZE); + } + + i++; + i %= ARRAY_SIZE(priv->ring_control->rx_data); + } + + p54p_refill_rx_ring(dev); + + wmb(); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) + complete(&priv->boot_comp); + + spin_unlock(&priv->lock); + + return reg ? IRQ_HANDLED : IRQ_NONE; +} + +static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, + size_t len, int free_on_tx) +{ + struct p54p_priv *priv = dev->priv; + unsigned long flags; + struct p54p_desc *desc; + dma_addr_t mapping; + u32 device_idx, idx, i; + + spin_lock_irqsave(&priv->lock, flags); + + device_idx = le32_to_cpu(priv->ring_control->device_idx[1]); + idx = le32_to_cpu(priv->ring_control->host_idx[1]); + i = idx % ARRAY_SIZE(priv->ring_control->tx_data); + + mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); + desc = &priv->ring_control->tx_data[i]; + desc->host_addr = cpu_to_le32(mapping); + desc->device_addr = data->req_id; + desc->len = cpu_to_le16(len); + desc->flags = 0; + + wmb(); + priv->ring_control->host_idx[1] = cpu_to_le32(idx + 1); + + if (free_on_tx) + priv->tx_buf[i] = data; + + spin_unlock_irqrestore(&priv->lock, flags); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + P54P_READ(dev_int); + + /* FIXME: unlikely to happen because the device usually runs out of + memory before we fill the ring up, but we can make it impossible */ + if (idx - device_idx > ARRAY_SIZE(priv->ring_control->tx_data) - 2) + printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); +} + +static int p54p_open(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + int err; + + init_completion(&priv->boot_comp); + err = request_irq(priv->pdev->irq, &p54p_interrupt, + IRQF_SHARED, "prism54pci", dev); + if (err) { + printk(KERN_ERR "%s: failed to register IRQ handler\n", + wiphy_name(dev->wiphy)); + return err; + } + + memset(priv->ring_control, 0, sizeof(*priv->ring_control)); + priv->rx_idx = priv->tx_idx = 0; + p54p_refill_rx_ring(dev); + + p54p_upload_firmware(dev); + + P54P_WRITE(ring_control_base, priv->ring_control_dma); + P54P_READ(ring_control_base); + wmb(); + udelay(10); + + P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT)); + P54P_READ(int_enable); + wmb(); + udelay(10); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); + P54P_READ(dev_int); + + if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { + printk(KERN_ERR "%s: Cannot boot firmware!\n", + wiphy_name(dev->wiphy)); + free_irq(priv->pdev->irq, dev); + return -ETIMEDOUT; + } + + P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); + P54P_READ(int_enable); + wmb(); + udelay(10); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + P54P_READ(dev_int); + wmb(); + udelay(10); + + return 0; +} + +static void p54p_stop(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + unsigned int i; + struct p54p_desc *desc; + + P54P_WRITE(int_enable, 0); + P54P_READ(int_enable); + udelay(10); + + free_irq(priv->pdev->irq, dev); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); + + for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) { + desc = &priv->ring_control->rx_data[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + kfree_skb(priv->rx_buf[i]); + priv->rx_buf[i] = NULL; + } + + for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) { + desc = &priv->ring_control->tx_data[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + + kfree(priv->tx_buf[i]); + priv->tx_buf[i] = NULL; + } + + memset(priv->ring_control, 0, sizeof(*priv->ring_control)); +} + +static int __devinit p54p_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct p54p_priv *priv; + struct ieee80211_hw *dev; + unsigned long mem_addr, mem_len; + int err; + DECLARE_MAC_BUF(mac); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n", + pci_name(pdev)); + return err; + } + + mem_addr = pci_resource_start(pdev, 0); + mem_len = pci_resource_len(pdev, 0); + if (mem_len < sizeof(struct p54p_csr)) { + printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n", + pci_name(pdev)); + pci_disable_device(pdev); + return err; + } + + err = pci_request_regions(pdev, "prism54pci"); + if (err) { + printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n", + pci_name(pdev)); + return err; + } + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || + pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n", + pci_name(pdev)); + goto err_free_reg; + } + + pci_set_master(pdev); + pci_try_set_mwi(pdev); + + pci_write_config_byte(pdev, 0x40, 0); + pci_write_config_byte(pdev, 0x41, 0); + + dev = p54_init_common(sizeof(*priv)); + if (!dev) { + printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + + priv = dev->priv; + priv->pdev = pdev; + + SET_IEEE80211_DEV(dev, &pdev->dev); + pci_set_drvdata(pdev, dev); + + priv->map = ioremap(mem_addr, mem_len); + if (!priv->map) { + printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n", + pci_name(pdev)); + err = -EINVAL; // TODO: use a better error code? + goto err_free_dev; + } + + priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control), + &priv->ring_control_dma); + if (!priv->ring_control) { + printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_iounmap; + } + memset(priv->ring_control, 0, sizeof(*priv->ring_control)); + + err = p54p_upload_firmware(dev); + if (err) + goto err_free_desc; + + err = p54p_read_eeprom(dev); + if (err) + goto err_free_desc; + + priv->common.open = p54p_open; + priv->common.stop = p54p_stop; + priv->common.tx = p54p_tx; + + spin_lock_init(&priv->lock); + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n", + pci_name(pdev)); + goto err_free_common; + } + + printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n", + wiphy_name(dev->wiphy), + print_mac(mac, dev->wiphy->perm_addr), + priv->common.version); + + return 0; + + err_free_common: + p54_free_common(dev); + + err_free_desc: + pci_free_consistent(pdev, sizeof(*priv->ring_control), + priv->ring_control, priv->ring_control_dma); + + err_iounmap: + iounmap(priv->map); + + err_free_dev: + pci_set_drvdata(pdev, NULL); + ieee80211_free_hw(dev); + + err_free_reg: + pci_release_regions(pdev); + pci_disable_device(pdev); + return err; +} + +static void __devexit p54p_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct p54p_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + priv = dev->priv; + 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); +} + +#ifdef CONFIG_PM +static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct p54p_priv *priv = dev->priv; + + if (priv->common.mode != IEEE80211_IF_TYPE_MGMT) { + ieee80211_stop_queues(dev); + p54p_stop(dev); + } + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int p54p_resume(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct p54p_priv *priv = dev->priv; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (priv->common.mode != IEEE80211_IF_TYPE_MGMT) { + p54p_open(dev); + ieee80211_start_queues(dev); + } + + return 0; +} +#endif /* CONFIG_PM */ + +static struct pci_driver p54p_driver = { + .name = "prism54pci", + .id_table = p54p_table, + .probe = p54p_probe, + .remove = __devexit_p(p54p_remove), +#ifdef CONFIG_PM + .suspend = p54p_suspend, + .resume = p54p_resume, +#endif /* CONFIG_PM */ +}; + +static int __init p54p_init(void) +{ + return pci_register_driver(&p54p_driver); +} + +static void __exit p54p_exit(void) +{ + pci_unregister_driver(&p54p_driver); +} + +module_init(p54p_init); +module_exit(p54p_exit); diff --git a/drivers/net/wireless/p54pci.h b/drivers/net/wireless/p54pci.h new file mode 100644 index 000000000000..52feb597dc4a --- /dev/null +++ b/drivers/net/wireless/p54pci.h @@ -0,0 +1,106 @@ +#ifndef PRISM54PCI_H +#define PRISM54PCI_H + +/* + * Defines for PCI based mac80211 Prism54 driver + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * 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. + */ + +/* Device Interrupt register bits */ +#define ISL38XX_DEV_INT_RESET 0x0001 +#define ISL38XX_DEV_INT_UPDATE 0x0002 +#define ISL38XX_DEV_INT_WAKEUP 0x0008 +#define ISL38XX_DEV_INT_SLEEP 0x0010 +#define ISL38XX_DEV_INT_ABORT 0x0020 +/* these two only used in USB */ +#define ISL38XX_DEV_INT_DATA 0x0040 +#define ISL38XX_DEV_INT_MGMT 0x0080 + +#define ISL38XX_DEV_INT_PCIUART_CTS 0x4000 +#define ISL38XX_DEV_INT_PCIUART_DR 0x8000 + +/* Interrupt Identification/Acknowledge/Enable register bits */ +#define ISL38XX_INT_IDENT_UPDATE 0x0002 +#define ISL38XX_INT_IDENT_INIT 0x0004 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008 +#define ISL38XX_INT_IDENT_SLEEP 0x0010 +#define ISL38XX_INT_IDENT_PCIUART_CTS 0x4000 +#define ISL38XX_INT_IDENT_PCIUART_DR 0x8000 + +/* Control/Status register bits */ +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 +#define ISL38XX_CTRL_STAT_RESET 0x10000000 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 + +struct p54p_csr { + __le32 dev_int; + u8 unused_1[12]; + __le32 int_ident; + __le32 int_ack; + __le32 int_enable; + u8 unused_2[4]; + union { + __le32 ring_control_base; + __le32 gen_purp_com[2]; + }; + u8 unused_3[8]; + __le32 direct_mem_base; + u8 unused_4[44]; + __le32 dma_addr; + __le32 dma_len; + __le32 dma_ctrl; + u8 unused_5[12]; + __le32 ctrl_stat; + u8 unused_6[1924]; + u8 cardbus_cis[0x800]; + u8 direct_mem_win[0x1000]; +} __attribute__ ((packed)); + +/* usb backend only needs the register defines above */ +#ifndef PRISM54USB_H +struct p54p_desc { + __le32 host_addr; + __le32 device_addr; + __le16 len; + __le16 flags; +} __attribute__ ((packed)); + +struct p54p_ring_control { + __le32 host_idx[4]; + __le32 device_idx[4]; + struct p54p_desc rx_data[8]; + struct p54p_desc tx_data[32]; + struct p54p_desc rx_mgmt[4]; + struct p54p_desc tx_mgmt[4]; +} __attribute__ ((packed)); + +#define P54P_READ(r) __raw_readl(&priv->map->r) +#define P54P_WRITE(r, val) __raw_writel((__force u32)(val), &priv->map->r) + +struct p54p_priv { + struct p54_common common; + struct pci_dev *pdev; + struct p54p_csr __iomem *map; + + spinlock_t lock; + struct p54p_ring_control *ring_control; + dma_addr_t ring_control_dma; + u32 rx_idx, tx_idx; + struct sk_buff *rx_buf[8]; + void *tx_buf[32]; + struct completion boot_comp; +}; + +#endif /* PRISM54USB_H */ +#endif /* PRISM54PCI_H */ diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c new file mode 100644 index 000000000000..7446c39ce5d0 --- /dev/null +++ b/drivers/net/wireless/p54usb.c @@ -0,0 +1,906 @@ + +/* + * Linux device driver for USB based Prism54 + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * 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 "p54.h" +#include "p54usb.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_DESCRIPTION("Prism54 USB wireless driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("prism54usb"); + +static struct usb_device_id p54u_table[] __devinitdata = { + /* Version 1 devices (pci chip + net2280) */ + {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ + {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ + {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */ + {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */ + {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */ + {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ + {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ + {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ + {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ + {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ + {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ + {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ + {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */ + {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */ + {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */ + + /* Version 2 devices (3887) */ + {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */ + {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */ + {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */ + {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ + {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ + {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ + {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */ + {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */ + {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/ + {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/ + {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */ + {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ + {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ + {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ + {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ + {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ + {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ + {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */ + {} +}; + +MODULE_DEVICE_TABLE(usb, p54u_table); + +static void p54u_rx_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb; + struct ieee80211_hw *dev = info->dev; + struct p54u_priv *priv = dev->priv; + + if (unlikely(urb->status)) { + info->urb = NULL; + usb_free_urb(urb); + return; + } + + skb_unlink(skb, &priv->rx_queue); + skb_put(skb, urb->actual_length); + if (!priv->hw_type) + skb_pull(skb, sizeof(struct net2280_tx_hdr)); + + if (p54_rx(dev, skb)) { + skb = dev_alloc_skb(MAX_RX_SIZE); + if (unlikely(!skb)) { + usb_free_urb(urb); + /* TODO check rx queue length and refill *somewhere* */ + return; + } + + info = (struct p54u_rx_info *) skb->cb; + info->urb = urb; + info->dev = dev; + urb->transfer_buffer = skb_tail_pointer(skb); + urb->context = skb; + skb_queue_tail(&priv->rx_queue, skb); + } else { + skb_trim(skb, 0); + skb_queue_tail(&priv->rx_queue, skb); + } + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static void p54u_tx_cb(struct urb *urb) +{ + usb_free_urb(urb); +} + +static void p54u_tx_free_cb(struct urb *urb) +{ + kfree(urb->transfer_buffer); + usb_free_urb(urb); +} + +static int p54u_init_urbs(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + struct urb *entry; + struct sk_buff *skb; + struct p54u_rx_info *info; + + while (skb_queue_len(&priv->rx_queue) < 32) { + skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL); + if (!skb) + break; + entry = usb_alloc_urb(0, GFP_KERNEL); + if (!entry) { + kfree_skb(skb); + break; + } + usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb); + info = (struct p54u_rx_info *) skb->cb; + info->urb = entry; + info->dev = dev; + skb_queue_tail(&priv->rx_queue, skb); + usb_submit_urb(entry, GFP_KERNEL); + } + + return 0; +} + +static void p54u_free_urbs(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + struct p54u_rx_info *info; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&priv->rx_queue))) { + info = (struct p54u_rx_info *) skb->cb; + if (!info->urb) + continue; + + usb_kill_urb(info->urb); + kfree_skb(skb); + } +} + +static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, + size_t len, int free_on_tx) +{ + struct p54u_priv *priv = dev->priv; + struct urb *addr_urb, *data_urb; + + addr_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!addr_urb) + return; + + data_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!data_urb) { + usb_free_urb(addr_urb); + return; + } + + usb_fill_bulk_urb(addr_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id, + sizeof(data->req_id), p54u_tx_cb, dev); + usb_fill_bulk_urb(data_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len, + free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + + usb_submit_urb(addr_urb, GFP_ATOMIC); + usb_submit_urb(data_urb, GFP_ATOMIC); +} + +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, + size_t len, int free_on_tx) +{ + struct p54u_priv *priv = dev->priv; + struct urb *int_urb, *data_urb; + struct net2280_tx_hdr *hdr; + struct net2280_reg_write *reg; + + reg = kmalloc(sizeof(*reg), GFP_ATOMIC); + if (!reg) + return; + + int_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!int_urb) { + kfree(reg); + return; + } + + data_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!data_urb) { + kfree(reg); + usb_free_urb(int_urb); + return; + } + + reg->port = cpu_to_le16(NET2280_DEV_U32); + reg->addr = cpu_to_le32(P54U_DEV_BASE); + reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); + + len += sizeof(*data); + hdr = (void *)data - sizeof(*hdr); + memset(hdr, 0, sizeof(*hdr)); + hdr->device_addr = data->req_id; + hdr->len = cpu_to_le16(len); + + usb_fill_bulk_urb(int_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), + p54u_tx_free_cb, dev); + usb_submit_urb(int_urb, GFP_ATOMIC); + + usb_fill_bulk_urb(data_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr), + free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_submit_urb(data_urb, GFP_ATOMIC); +} + +static int p54u_write(struct p54u_priv *priv, + struct net2280_reg_write *buf, + enum net2280_op_type type, + __le32 addr, __le32 val) +{ + unsigned int ep; + int alen; + + if (type & 0x0800) + ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV); + else + ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG); + + buf->port = cpu_to_le16(type); + buf->addr = addr; + buf->val = val; + + return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000); +} + +static int p54u_read(struct p54u_priv *priv, void *buf, + enum net2280_op_type type, + __le32 addr, __le32 *val) +{ + struct net2280_reg_read *read = buf; + __le32 *reg = buf; + unsigned int ep; + int alen, err; + + if (type & 0x0800) + ep = P54U_PIPE_DEV; + else + ep = P54U_PIPE_BRG; + + read->port = cpu_to_le16(type); + read->addr = addr; + + err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep), + read, sizeof(*read), &alen, 1000); + if (err) + return err; + + err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep), + reg, sizeof(*reg), &alen, 1000); + if (err) + return err; + + *val = *reg; + return 0; +} + +static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, + void *data, size_t len) +{ + int alen; + return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep), + data, len, &alen, 2000); +} + +static int p54u_read_eeprom(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + void *buf; + struct p54_control_hdr *hdr; + int err, alen; + size_t offset = priv->hw_type ? 0x10 : 0x20; + + buf = kmalloc(0x2020, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "prism54usb: cannot allocate memory for" + "eeprom readback!\n"); + return -ENOMEM; + } + + if (priv->hw_type) { + *((u32 *) buf) = priv->common.rx_start; + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); + if (err) { + printk(KERN_ERR "prism54usb: addr send failed\n"); + goto fail; + } + } else { + struct net2280_reg_write *reg = buf; + reg->port = cpu_to_le16(NET2280_DEV_U32); + reg->addr = cpu_to_le32(P54U_DEV_BASE); + reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); + err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg)); + if (err) { + printk(KERN_ERR "prism54usb: dev_int send failed\n"); + goto fail; + } + } + + hdr = buf + priv->common.tx_hdr_len; + p54_fill_eeprom_readback(hdr); + hdr->req_id = cpu_to_le32(priv->common.rx_start); + if (priv->common.tx_hdr_len) { + struct net2280_tx_hdr *tx_hdr = buf; + tx_hdr->device_addr = hdr->req_id; + tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN); + } + + /* we can just pretend to send 0x2000 bytes of nothing in the headers */ + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, + EEPROM_READBACK_LEN + priv->common.tx_hdr_len); + if (err) { + printk(KERN_ERR "prism54usb: eeprom req send failed\n"); + goto fail; + } + + err = usb_bulk_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), + buf, 0x2020, &alen, 1000); + if (!err && alen > offset) { + p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset); + } else { + printk(KERN_ERR "prism54usb: eeprom read failed!\n"); + err = -EINVAL; + goto fail; + } + + fail: + kfree(buf); + return err; +} + +static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) +{ + static char start_string[] = "~~~~<\r"; + struct p54u_priv *priv = dev->priv; + const struct firmware *fw_entry = NULL; + int err, alen; + u8 carry = 0; + u8 *buf, *tmp, *data; + unsigned int left, remains, block_size; + struct x2_header *hdr; + unsigned long timeout; + + tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n"); + err = -ENOMEM; + goto err_bufalloc; + } + + memcpy(buf, start_string, 4); + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4); + if (err) { + printk(KERN_ERR "p54usb: reset failed! (%d)\n", err); + goto err_reset; + } + + err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); + if (err) { + printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n"); + goto err_req_fw_failed; + } + + p54_parse_firmware(dev, fw_entry); + + left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); + strcpy(buf, start_string); + left -= strlen(start_string); + tmp += strlen(start_string); + + data = fw_entry->data; + remains = fw_entry->size; + + hdr = (struct x2_header *)(buf + strlen(start_string)); + memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); + hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); + hdr->fw_length = cpu_to_le32(fw_entry->size); + hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr, + sizeof(u32)*2)); + left -= sizeof(*hdr); + tmp += sizeof(*hdr); + + while (remains) { + while (left--) { + if (carry) { + *tmp++ = carry; + carry = 0; + remains--; + continue; + } + switch (*data) { + case '~': + *tmp++ = '}'; + carry = '^'; + break; + case '}': + *tmp++ = '}'; + carry = ']'; + break; + default: + *tmp++ = *data; + remains--; + break; + } + data++; + } + + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); + if (err) { + printk(KERN_ERR "prism54usb: firmware upload failed!\n"); + goto err_upload_failed; + } + + tmp = buf; + left = block_size = min((unsigned int)P54U_FW_BLOCK, remains); + } + + *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); + if (err) { + printk(KERN_ERR "prism54usb: firmware upload failed!\n"); + goto err_upload_failed; + } + + timeout = jiffies + msecs_to_jiffies(1000); + while (!(err = usb_bulk_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { + if (alen > 2 && !memcmp(buf, "OK", 2)) + break; + + if (alen > 5 && !memcmp(buf, "ERROR", 5)) { + printk(KERN_INFO "prism54usb: firmware upload failed!\n"); + err = -EINVAL; + break; + } + + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "prism54usb: firmware boot timed out!\n"); + err = -ETIMEDOUT; + break; + } + } + if (err) + goto err_upload_failed; + + buf[0] = 'g'; + buf[1] = '\r'; + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); + if (err) { + printk(KERN_ERR "prism54usb: firmware boot failed!\n"); + goto err_upload_failed; + } + + timeout = jiffies + msecs_to_jiffies(1000); + while (!(err = usb_bulk_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { + if (alen > 0 && buf[0] == 'g') + break; + + if (time_after(jiffies, timeout)) { + err = -ETIMEDOUT; + break; + } + } + if (err) + goto err_upload_failed; + + err_upload_failed: + release_firmware(fw_entry); + err_req_fw_failed: + err_reset: + kfree(buf); + err_bufalloc: + return err; +} + +static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + const struct firmware *fw_entry = NULL; + const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE; + int err, alen; + void *buf; + __le32 reg; + unsigned int remains, offset; + u8 *data; + + buf = kmalloc(512, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n"); + return -ENOMEM; + } + + err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); + if (err) { + printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n"); + kfree(buf); + return err; + } + + p54_parse_firmware(dev, fw_entry); + +#define P54U_WRITE(type, addr, data) \ + do {\ + err = p54u_write(priv, buf, type,\ + cpu_to_le32((u32)(unsigned long)addr), data);\ + if (err) \ + goto fail;\ + } while (0) + +#define P54U_READ(type, addr) \ + do {\ + err = p54u_read(priv, buf, type,\ + cpu_to_le32((u32)(unsigned long)addr), ®);\ + if (err)\ + goto fail;\ + } while (0) + + /* power down net2280 bridge */ + P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL); + reg |= cpu_to_le32(P54U_BRG_POWER_DOWN); + reg &= cpu_to_le32(~P54U_BRG_POWER_UP); + P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg); + + mdelay(100); + + /* power up bridge */ + reg |= cpu_to_le32(P54U_BRG_POWER_UP); + reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN); + P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg); + + mdelay(100); + + P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT, + cpu_to_le32(NET2280_CLK_30Mhz | + NET2280_PCI_ENABLE | + NET2280_PCI_SOFT_RESET)); + + mdelay(20); + + P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND, + cpu_to_le32(PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER)); + + P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0, + cpu_to_le32(NET2280_BASE)); + + P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS); + reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT); + P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg); + + // TODO: we really need this? + P54U_READ(NET2280_BRG_U32, NET2280_RELNUM); + + P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP, + cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE)); + P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP, + cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE)); + + P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2, + cpu_to_le32(NET2280_BASE2)); + + /* finally done setting up the bridge */ + + P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND, + cpu_to_le32(PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER)); + + P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0); + P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0, + cpu_to_le32(P54U_DEV_BASE)); + + P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0); + P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, + cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); + + /* do romboot */ + P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0); + + P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(20); + + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(20); + + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(100); + + P54U_READ(NET2280_DEV_U32, &devreg->int_ident); + P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); + + /* finally, we can upload firmware now! */ + remains = fw_entry->size; + data = fw_entry->data; + offset = ISL38XX_DEV_FIRMWARE_ADDR; + + while (remains) { + unsigned int block_len = min(remains, (unsigned int)512); + memcpy(buf, data, block_len); + + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); + if (err) { + printk(KERN_ERR "prism54usb: firmware block upload " + "failed\n"); + goto fail; + } + + P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base, + cpu_to_le32(0xc0000f00)); + + P54U_WRITE(NET2280_DEV_U32, + 0x0020 | (unsigned long)&devreg->direct_mem_win, 0); + P54U_WRITE(NET2280_DEV_U32, + 0x0020 | (unsigned long)&devreg->direct_mem_win, + cpu_to_le32(1)); + + P54U_WRITE(NET2280_DEV_U32, + 0x0024 | (unsigned long)&devreg->direct_mem_win, + cpu_to_le32(block_len)); + P54U_WRITE(NET2280_DEV_U32, + 0x0028 | (unsigned long)&devreg->direct_mem_win, + cpu_to_le32(offset)); + + P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr, + cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR)); + P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len, + cpu_to_le32(block_len >> 2)); + P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl, + cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER)); + + mdelay(10); + + P54U_READ(NET2280_DEV_U32, + 0x002C | (unsigned long)&devreg->direct_mem_win); + if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || + !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { + printk(KERN_ERR "prism54usb: firmware DMA transfer " + "failed\n"); + goto fail; + } + + P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT, + cpu_to_le32(NET2280_FIFO_FLUSH)); + + remains -= block_len; + data += block_len; + offset += block_len; + } + + /* do ramboot */ + P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(20); + + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(100); + + P54U_READ(NET2280_DEV_U32, &devreg->int_ident); + P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); + + /* start up the firmware */ + P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, + cpu_to_le32(ISL38XX_INT_IDENT_INIT)); + + P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, + cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); + + P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, + cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE | + NET2280_USB_INTERRUPT_ENABLE)); + + P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int, + cpu_to_le32(ISL38XX_DEV_INT_RESET)); + + err = usb_interrupt_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT), + buf, sizeof(__le32), &alen, 1000); + if (err || alen != sizeof(__le32)) + goto fail; + + P54U_READ(NET2280_DEV_U32, &devreg->int_ident); + P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); + + if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))) + err = -EINVAL; + + P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0); + P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, + cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); + +#undef P54U_WRITE +#undef P54U_READ + + fail: + release_firmware(fw_entry); + kfree(buf); + return err; +} + +static int p54u_open(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + int err; + + err = p54u_init_urbs(dev); + if (err) { + return err; + } + + priv->common.open = p54u_init_urbs; + + return 0; +} + +static void p54u_stop(struct ieee80211_hw *dev) +{ + /* TODO: figure out how to reliably stop the 3887 and net2280 so + the hardware is still usable next time we want to start it. + until then, we just stop listening to the hardware.. */ + p54u_free_urbs(dev); + return; +} + +static int __devinit p54u_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct ieee80211_hw *dev; + struct p54u_priv *priv; + int err; + unsigned int i, recognized_pipes; + DECLARE_MAC_BUF(mac); + + dev = p54_init_common(sizeof(*priv)); + if (!dev) { + printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n"); + return -ENOMEM; + } + + priv = dev->priv; + + SET_IEEE80211_DEV(dev, &intf->dev); + usb_set_intfdata(intf, dev); + priv->udev = udev; + + usb_get_dev(udev); + + /* really lazy and simple way of figuring out if we're a 3887 */ + /* TODO: should just stick the identification in the device table */ + i = intf->altsetting->desc.bNumEndpoints; + recognized_pipes = 0; + while (i--) { + switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) { + case P54U_PIPE_DATA: + case P54U_PIPE_MGMT: + case P54U_PIPE_BRG: + case P54U_PIPE_DEV: + case P54U_PIPE_DATA | USB_DIR_IN: + case P54U_PIPE_MGMT | USB_DIR_IN: + case P54U_PIPE_BRG | USB_DIR_IN: + case P54U_PIPE_DEV | USB_DIR_IN: + case P54U_PIPE_INT | USB_DIR_IN: + recognized_pipes++; + } + } + priv->common.open = p54u_open; + + if (recognized_pipes < P54U_PIPE_NUMBER) { + priv->hw_type = P54U_3887; + priv->common.tx = p54u_tx_3887; + } else { + dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); + priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); + priv->common.tx = p54u_tx_net2280; + } + priv->common.stop = p54u_stop; + + if (priv->hw_type) + err = p54u_upload_firmware_3887(dev); + else + err = p54u_upload_firmware_net2280(dev); + if (err) + goto err_free_dev; + + err = p54u_read_eeprom(dev); + if (err) + goto err_free_dev; + + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + u8 perm_addr[ETH_ALEN]; + + printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n"); + random_ether_addr(perm_addr); + SET_IEEE80211_PERM_ADDR(dev, perm_addr); + } + + skb_queue_head_init(&priv->rx_queue); + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "prism54usb: Cannot register netdevice\n"); + goto err_free_dev; + } + + printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n", + wiphy_name(dev->wiphy), + print_mac(mac, dev->wiphy->perm_addr), + priv->common.version); + + return 0; + + err_free_dev: + ieee80211_free_hw(dev); + usb_set_intfdata(intf, NULL); + usb_put_dev(udev); + return err; +} + +static void __devexit p54u_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct p54u_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + usb_put_dev(interface_to_usbdev(intf)); + p54_free_common(dev); + ieee80211_free_hw(dev); +} + +static struct usb_driver p54u_driver = { + .name = "prism54usb", + .id_table = p54u_table, + .probe = p54u_probe, + .disconnect = p54u_disconnect, +}; + +static int __init p54u_init(void) +{ + return usb_register(&p54u_driver); +} + +static void __exit p54u_exit(void) +{ + usb_deregister(&p54u_driver); +} + +module_init(p54u_init); +module_exit(p54u_exit); diff --git a/drivers/net/wireless/p54usb.h b/drivers/net/wireless/p54usb.h new file mode 100644 index 000000000000..d1896b396c1c --- /dev/null +++ b/drivers/net/wireless/p54usb.h @@ -0,0 +1,133 @@ +#ifndef PRISM54USB_H +#define PRISM54USB_H + +/* + * Defines for USB based mac80211 Prism54 driver + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * 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. + */ + +/* for isl3886 register definitions used on ver 1 devices */ +#include "p54pci.h" +#include "net2280.h" + +/* pci */ +#define NET2280_BASE 0x10000000 +#define NET2280_BASE2 0x20000000 + +/* gpio */ +#define P54U_BRG_POWER_UP (1 << GPIO0_DATA) +#define P54U_BRG_POWER_DOWN (1 << GPIO1_DATA) + +/* devinit */ +#define NET2280_CLK_4Mhz (15 << LOCAL_CLOCK_FREQUENCY) +#define NET2280_CLK_30Mhz (2 << LOCAL_CLOCK_FREQUENCY) +#define NET2280_CLK_60Mhz (1 << LOCAL_CLOCK_FREQUENCY) +#define NET2280_CLK_STOP (0 << LOCAL_CLOCK_FREQUENCY) +#define NET2280_PCI_ENABLE (1 << PCI_ENABLE) +#define NET2280_PCI_SOFT_RESET (1 << PCI_SOFT_RESET) + +/* endpoints */ +#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE (1 << CLEAR_NAK_OUT_PACKETS_MODE) +#define NET2280_FIFO_FLUSH (1 << FIFO_FLUSH) + +/* irq */ +#define NET2280_USB_INTERRUPT_ENABLE (1 << USB_INTERRUPT_ENABLE) +#define NET2280_PCI_INTA_INTERRUPT (1 << PCI_INTA_INTERRUPT) +#define NET2280_PCI_INTA_INTERRUPT_ENABLE (1 << PCI_INTA_INTERRUPT_ENABLE) + +/* registers */ +#define NET2280_DEVINIT 0x00 +#define NET2280_USBIRQENB1 0x24 +#define NET2280_IRQSTAT1 0x2c +#define NET2280_FIFOCTL 0x38 +#define NET2280_GPIOCTL 0x50 +#define NET2280_RELNUM 0x88 +#define NET2280_EPA_RSP 0x324 +#define NET2280_EPA_STAT 0x32c +#define NET2280_EPB_STAT 0x34c +#define NET2280_EPC_RSP 0x364 +#define NET2280_EPC_STAT 0x36c +#define NET2280_EPD_STAT 0x38c + +#define NET2280_EPA_CFG 0x320 +#define NET2280_EPB_CFG 0x340 +#define NET2280_EPC_CFG 0x360 +#define NET2280_EPD_CFG 0x380 +#define NET2280_EPE_CFG 0x3A0 +#define NET2280_EPF_CFG 0x3C0 +#define P54U_DEV_BASE 0x40000000 + +struct net2280_tx_hdr { + __le32 device_addr; + __le16 len; + __le16 follower; /* ? */ + u8 padding[8]; +} __attribute__((packed)); + +/* Some flags for the isl hardware registers controlling DMA inside the + * chip */ +#define ISL38XX_DMA_STATUS_DONE 0x00000001 +#define ISL38XX_DMA_STATUS_READY 0x00000002 +#define NET2280_EPA_FIFO_PCI_ADDR 0x20000000 +#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER 0x00000004 + +enum net2280_op_type { + NET2280_BRG_U32 = 0x001F, + NET2280_BRG_CFG_U32 = 0x000F, + NET2280_BRG_CFG_U16 = 0x0003, + NET2280_DEV_U32 = 0x080F, + NET2280_DEV_CFG_U32 = 0x088F, + NET2280_DEV_CFG_U16 = 0x0883 +}; + +#define P54U_FW_BLOCK 2048 + +#define X2_SIGNATURE "x2 " +#define X2_SIGNATURE_SIZE 4 + +struct x2_header { + u8 signature[X2_SIGNATURE_SIZE]; + __le32 fw_load_addr; + __le32 fw_length; + __le32 crc; +} __attribute__((packed)); + +/* pipes 3 and 4 are not used by the driver */ +#define P54U_PIPE_NUMBER 9 + +enum p54u_pipe_addr { + P54U_PIPE_DATA = 0x01, + P54U_PIPE_MGMT = 0x02, + P54U_PIPE_3 = 0x03, + P54U_PIPE_4 = 0x04, + P54U_PIPE_BRG = 0x0d, + P54U_PIPE_DEV = 0x0e, + P54U_PIPE_INT = 0x0f +}; + +struct p54u_rx_info { + struct urb *urb; + struct ieee80211_hw *dev; +}; + +struct p54u_priv { + struct p54_common common; + struct usb_device *udev; + enum { + P54U_NET2280 = 0, + P54U_3887 + } hw_type; + + spinlock_t lock; + struct sk_buff_head rx_queue; +}; + +#endif /* PRISM54USB_H */ From 753f492093da7a40141bfe083073400f518f4c68 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 14:20:30 -0700 Subject: [PATCH 1426/2804] [B44]: port to native ssb support Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/Kconfig | 28 +- drivers/net/b44.c | 745 +++++++++++++++++++++----------------------- drivers/net/b44.h | 81 +---- 3 files changed, 387 insertions(+), 467 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index fd284a93c9dd..83b3f7b8fb73 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1448,18 +1448,38 @@ config APRICOT called apricot. config B44 - tristate "Broadcom 4400 ethernet support" - depends on NET_PCI && PCI + tristate "Broadcom 440x/47xx ethernet support" + depends on SSB_POSSIBLE + select SSB select MII help - If you have a network (Ethernet) controller of this type, say Y and - read the Ethernet-HOWTO, available from + If you have a network (Ethernet) controller of this type, say Y + or M and read the Ethernet-HOWTO, available from . To compile this driver as a module, choose M here and read . The module will be called b44. +# Auto-select SSB PCI-HOST support, if possible +config B44_PCI_AUTOSELECT + bool + depends on B44 && SSB_PCIHOST_POSSIBLE + select SSB_PCIHOST + default y + +# Auto-select SSB PCICORE driver, if possible +config B44_PCICORE_AUTOSELECT + bool + depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE + select SSB_DRIVER_PCICORE + default y + +config B44_PCI + bool + depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT + default y + config FORCEDETH tristate "nForce Ethernet support" depends on NET_PCI && PCI diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 40842a6aa994..e90ba217d244 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1,8 +1,11 @@ -/* b44.c: Broadcom 4400 device driver. +/* b44.c: Broadcom 44xx/47xx Fast Ethernet device driver. * * Copyright (C) 2002 David S. Miller (davem@redhat.com) - * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) + * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi) + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org) * Copyright (C) 2006 Broadcom Corporation. + * Copyright (C) 2007 Michael Buesch * * Distribute under GPL. */ @@ -21,17 +24,18 @@ #include #include #include +#include #include #include #include + #include "b44.h" #define DRV_MODULE_NAME "b44" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.01" -#define DRV_MODULE_RELDATE "Jun 16, 2006" +#define DRV_MODULE_VERSION "2.0" #define B44_DEF_MSG_ENABLE \ (NETIF_MSG_DRV | \ @@ -85,10 +89,10 @@ #define B44_ETHIPV4UDP_HLEN 42 static char version[] __devinitdata = - DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION "\n"; -MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller"); -MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver"); +MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller"); +MODULE_DESCRIPTION("Broadcom 44xx/47xx 10/100 PCI ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -96,18 +100,28 @@ static int b44_debug = -1; /* -1 == use B44_DEF_MSG_ENABLE as value */ module_param(b44_debug, int, 0); MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value"); -static struct pci_device_id b44_pci_tbl[] = { - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { } /* terminate list with empty entry */ -}; +#ifdef CONFIG_B44_PCI +static const struct pci_device_id b44_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) }, + { 0 } /* terminate list with empty entry */ +}; MODULE_DEVICE_TABLE(pci, b44_pci_tbl); +static struct pci_driver b44_pci_driver = { + .name = DRV_MODULE_NAME, + .id_table = b44_pci_tbl, +}; +#endif /* CONFIG_B44_PCI */ + +static const struct ssb_device_id b44_ssb_tbl[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, b44_ssb_tbl); + static void b44_halt(struct b44 *); static void b44_init_rings(struct b44 *); @@ -119,6 +133,7 @@ static void b44_init_hw(struct b44 *, int); static int dma_desc_align_mask; static int dma_desc_sync_size; +static int instance; static const char b44_gstrings[][ETH_GSTRING_LEN] = { #define _B44(x...) # x, @@ -126,35 +141,35 @@ B44_STAT_REG_DECLARE #undef _B44 }; -static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev, - dma_addr_t dma_base, - unsigned long offset, - enum dma_data_direction dir) +static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) { - dma_sync_single_range_for_device(&pdev->dev, dma_base, - offset & dma_desc_align_mask, - dma_desc_sync_size, dir); + dma_sync_single_range_for_device(sdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); } -static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev, - dma_addr_t dma_base, - unsigned long offset, - enum dma_data_direction dir) +static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) { - dma_sync_single_range_for_cpu(&pdev->dev, dma_base, - offset & dma_desc_align_mask, - dma_desc_sync_size, dir); + dma_sync_single_range_for_cpu(sdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); } static inline unsigned long br32(const struct b44 *bp, unsigned long reg) { - return readl(bp->regs + reg); + return ssb_read32(bp->sdev, reg); } static inline void bw32(const struct b44 *bp, unsigned long reg, unsigned long val) { - writel(val, bp->regs + reg); + ssb_write32(bp->sdev, reg, val); } static int b44_wait_bit(struct b44 *bp, unsigned long reg, @@ -182,117 +197,29 @@ static int b44_wait_bit(struct b44 *bp, unsigned long reg, return 0; } -/* Sonics SiliconBackplane support routines. ROFL, you should see all the - * buzz words used on this company's website :-) - * - * All of these routines must be invoked with bp->lock held and - * interrupts disabled. - */ - -#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */ -#define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */ - -static u32 ssb_get_core_rev(struct b44 *bp) -{ - return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK); -} - -static u32 ssb_pci_setup(struct b44 *bp, u32 cores) -{ - u32 bar_orig, pci_rev, val; - - pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig); - pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR); - pci_rev = ssb_get_core_rev(bp); - - val = br32(bp, B44_SBINTVEC); - val |= cores; - bw32(bp, B44_SBINTVEC, val); - - val = br32(bp, SSB_PCI_TRANS_2); - val |= SSB_PCI_PREF | SSB_PCI_BURST; - bw32(bp, SSB_PCI_TRANS_2, val); - - pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig); - - return pci_rev; -} - -static void ssb_core_disable(struct b44 *bp) -{ - if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET) - return; - - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); - b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0); - b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1); - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | - SBTMSLOW_REJECT | SBTMSLOW_RESET)); - br32(bp, B44_SBTMSLOW); - udelay(1); - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET)); - br32(bp, B44_SBTMSLOW); - udelay(1); -} - -static void ssb_core_reset(struct b44 *bp) +static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index) { u32 val; - ssb_core_disable(bp); - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC)); - br32(bp, B44_SBTMSLOW); - udelay(1); + bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ | + (index << CAM_CTRL_INDEX_SHIFT))); - /* Clear SERR if set, this is a hw bug workaround. */ - if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR) - bw32(bp, B44_SBTMSHIGH, 0); + b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); - val = br32(bp, B44_SBIMSTATE); - if (val & (SBIMSTATE_IBE | SBIMSTATE_TO)) - bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO)); + val = br32(bp, B44_CAM_DATA_LO); - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); - br32(bp, B44_SBTMSLOW); - udelay(1); + data[2] = (val >> 24) & 0xFF; + data[3] = (val >> 16) & 0xFF; + data[4] = (val >> 8) & 0xFF; + data[5] = (val >> 0) & 0xFF; - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK)); - br32(bp, B44_SBTMSLOW); - udelay(1); + val = br32(bp, B44_CAM_DATA_HI); + + data[0] = (val >> 8) & 0xFF; + data[1] = (val >> 0) & 0xFF; } -static int ssb_core_unit(struct b44 *bp) -{ -#if 0 - u32 val = br32(bp, B44_SBADMATCH0); - u32 base; - - type = val & SBADMATCH0_TYPE_MASK; - switch (type) { - case 0: - base = val & SBADMATCH0_BS0_MASK; - break; - - case 1: - base = val & SBADMATCH0_BS1_MASK; - break; - - case 2: - default: - base = val & SBADMATCH0_BS2_MASK; - break; - }; -#endif - return 0; -} - -static int ssb_is_core_up(struct b44 *bp) -{ - return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) - == SBTMSLOW_CLOCK); -} - -static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) +static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) { u32 val; @@ -328,14 +255,14 @@ static void b44_enable_ints(struct b44 *bp) bw32(bp, B44_IMASK, bp->imask); } -static int b44_readphy(struct b44 *bp, int reg, u32 *val) +static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val) { int err; bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) | - (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | + (phy_addr << MDIO_DATA_PMD_SHIFT) | (reg << MDIO_DATA_RA_SHIFT) | (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT))); err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); @@ -344,29 +271,40 @@ static int b44_readphy(struct b44 *bp, int reg, u32 *val) return err; } -static int b44_writephy(struct b44 *bp, int reg, u32 val) +static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val) { bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) | - (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | + (phy_addr << MDIO_DATA_PMD_SHIFT) | (reg << MDIO_DATA_RA_SHIFT) | (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) | (val & MDIO_DATA_DATA))); return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); } +static inline int b44_readphy(struct b44 *bp, int reg, u32 *val) +{ + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) + return 0; + + return __b44_readphy(bp, bp->phy_addr, reg, val); +} + +static inline int b44_writephy(struct b44 *bp, int reg, u32 val) +{ + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) + return 0; + + return __b44_writephy(bp, bp->phy_addr, reg, val); +} + /* miilib interface */ -/* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional - * due to code existing before miilib use was added to this driver. - * Someone should remove this artificial driver limitation in - * b44_{read,write}phy. bp->phy_addr itself is fine (and needed). - */ static int b44_mii_read(struct net_device *dev, int phy_id, int location) { u32 val; struct b44 *bp = netdev_priv(dev); - int rc = b44_readphy(bp, location, &val); + int rc = __b44_readphy(bp, phy_id, location, &val); if (rc) return 0xffffffff; return val; @@ -376,7 +314,7 @@ static void b44_mii_write(struct net_device *dev, int phy_id, int location, int val) { struct b44 *bp = netdev_priv(dev); - b44_writephy(bp, location, val); + __b44_writephy(bp, phy_id, location, val); } static int b44_phy_reset(struct b44 *bp) @@ -384,6 +322,8 @@ static int b44_phy_reset(struct b44 *bp) u32 val; int err; + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) + return 0; err = b44_writephy(bp, MII_BMCR, BMCR_RESET); if (err) return err; @@ -442,11 +382,52 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) __b44_set_flow_ctrl(bp, pause_enab); } +#ifdef SSB_DRIVER_MIPS +extern char *nvram_get(char *name); +static void b44_wap54g10_workaround(struct b44 *bp) +{ + const char *str; + u32 val; + int err; + + /* + * workaround for bad hardware design in Linksys WAP54G v1.0 + * see https://dev.openwrt.org/ticket/146 + * check and reset bit "isolate" + */ + str = nvram_get("boardnum"); + if (!str) + return; + if (simple_strtoul(str, NULL, 0) == 2) { + err = __b44_readphy(bp, 0, MII_BMCR, &val); + if (err) + goto error; + if (!(val & BMCR_ISOLATE)) + return; + val &= ~BMCR_ISOLATE; + err = __b44_writephy(bp, 0, MII_BMCR, val); + if (err) + goto error; + } + return; +error: + printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n"); +} +#else +static inline void b44_wap54g10_workaround(struct b44 *bp) +{ +} +#endif + static int b44_setup_phy(struct b44 *bp) { u32 val; int err; + b44_wap54g10_workaround(bp); + + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) + return 0; if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0) goto out; if ((err = b44_writephy(bp, B44_MII_ALEDCTRL, @@ -542,6 +523,19 @@ static void b44_check_phy(struct b44 *bp) { u32 bmsr, aux; + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) { + bp->flags |= B44_FLAG_100_BASE_T; + bp->flags |= B44_FLAG_FULL_DUPLEX; + if (!netif_carrier_ok(bp->dev)) { + u32 val = br32(bp, B44_TX_CTRL); + val |= TX_CTRL_DUPLEX; + bw32(bp, B44_TX_CTRL, val); + netif_carrier_on(bp->dev); + b44_link_report(bp); + } + return; + } + if (!b44_readphy(bp, MII_BMSR, &bmsr) && !b44_readphy(bp, B44_MII_AUXCTRL, &aux) && (bmsr != 0xffff)) { @@ -617,10 +611,10 @@ static void b44_tx(struct b44 *bp) BUG_ON(skb == NULL); - pci_unmap_single(bp->pdev, - pci_unmap_addr(rp, mapping), + dma_unmap_single(bp->sdev->dev, + rp->mapping, skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); rp->skb = NULL; dev_kfree_skb_irq(skb); } @@ -657,9 +651,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) if (skb == NULL) return -ENOMEM; - mapping = pci_map_single(bp->pdev, skb->data, + mapping = dma_map_single(bp->sdev->dev, skb->data, RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); /* Hardware bug work-around, the chip is unable to do PCI DMA to/from anything above 1GB :-( */ @@ -667,18 +661,19 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { /* Sigh... */ if (!dma_mapping_error(mapping)) - pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); + dma_unmap_single(bp->sdev->dev, mapping, + RX_PKT_BUF_SZ, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); if (skb == NULL) return -ENOMEM; - mapping = pci_map_single(bp->pdev, skb->data, + mapping = dma_map_single(bp->sdev->dev, skb->data, RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); if (dma_mapping_error(mapping) || mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) - pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); + dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); dev_kfree_skb_any(skb); return -ENOMEM; } @@ -691,7 +686,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) rh->flags = 0; map->skb = skb; - pci_unmap_addr_set(map, mapping, mapping); + map->mapping = mapping; if (src_map != NULL) src_map->skb = NULL; @@ -705,9 +700,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset); if (bp->flags & B44_FLAG_RX_RING_HACK) - b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, - dest_idx * sizeof(dp), - DMA_BIDIRECTIONAL); + b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, + dest_idx * sizeof(dp), + DMA_BIDIRECTIONAL); return RX_PKT_BUF_SZ; } @@ -730,13 +725,12 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) rh = (struct rx_header *) src_map->skb->data; rh->len = 0; rh->flags = 0; - pci_unmap_addr_set(dest_map, mapping, - pci_unmap_addr(src_map, mapping)); + dest_map->mapping = src_map->mapping; if (bp->flags & B44_FLAG_RX_RING_HACK) - b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma, - src_idx * sizeof(src_desc), - DMA_BIDIRECTIONAL); + b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma, + src_idx * sizeof(src_desc), + DMA_BIDIRECTIONAL); ctrl = src_desc->ctrl; if (dest_idx == (B44_RX_RING_SIZE - 1)) @@ -750,13 +744,13 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) src_map->skb = NULL; if (bp->flags & B44_FLAG_RX_RING_HACK) - b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, - dest_idx * sizeof(dest_desc), - DMA_BIDIRECTIONAL); + b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, + dest_idx * sizeof(dest_desc), + DMA_BIDIRECTIONAL); - pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr), - RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr), + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); } static int b44_rx(struct b44 *bp, int budget) @@ -772,13 +766,13 @@ static int b44_rx(struct b44 *bp, int budget) while (cons != prod && budget > 0) { struct ring_info *rp = &bp->rx_buffers[cons]; struct sk_buff *skb = rp->skb; - dma_addr_t map = pci_unmap_addr(rp, mapping); + dma_addr_t map = rp->mapping; struct rx_header *rh; u16 len; - pci_dma_sync_single_for_cpu(bp->pdev, map, + dma_sync_single_for_cpu(bp->sdev->dev, map, RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); rh = (struct rx_header *) skb->data; len = le16_to_cpu(rh->len); if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) || @@ -810,8 +804,8 @@ static int b44_rx(struct b44 *bp, int budget) skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); if (skb_size < 0) goto drop_it; - pci_unmap_single(bp->pdev, map, - skb_size, PCI_DMA_FROMDEVICE); + dma_unmap_single(bp->sdev->dev, map, + skb_size, DMA_FROM_DEVICE); /* Leave out rx_header */ skb_put(skb, len + RX_PKT_OFFSET); skb_pull(skb, RX_PKT_OFFSET); @@ -970,24 +964,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) goto err_out; } - mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); + mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { struct sk_buff *bounce_skb; /* Chip can't handle DMA to/from >1GB, use bounce buffer */ if (!dma_mapping_error(mapping)) - pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE); + dma_unmap_single(bp->sdev->dev, mapping, len, + DMA_TO_DEVICE); bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) goto err_out; - mapping = pci_map_single(bp->pdev, bounce_skb->data, - len, PCI_DMA_TODEVICE); + mapping = dma_map_single(bp->sdev->dev, bounce_skb->data, + len, DMA_TO_DEVICE); if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) - pci_unmap_single(bp->pdev, mapping, - len, PCI_DMA_TODEVICE); + dma_unmap_single(bp->sdev->dev, mapping, + len, DMA_TO_DEVICE); dev_kfree_skb_any(bounce_skb); goto err_out; } @@ -999,7 +994,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) entry = bp->tx_prod; bp->tx_buffers[entry].skb = skb; - pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping); + bp->tx_buffers[entry].mapping = mapping; ctrl = (len & DESC_CTRL_LEN); ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF; @@ -1010,9 +1005,9 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); if (bp->flags & B44_FLAG_TX_RING_HACK) - b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma, - entry * sizeof(bp->tx_ring[0]), - DMA_TO_DEVICE); + b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma, + entry * sizeof(bp->tx_ring[0]), + DMA_TO_DEVICE); entry = NEXT_TX(entry); @@ -1085,10 +1080,8 @@ static void b44_free_rings(struct b44 *bp) if (rp->skb == NULL) continue; - pci_unmap_single(bp->pdev, - pci_unmap_addr(rp, mapping), - RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + dma_unmap_single(bp->sdev->dev, rp->mapping, RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); dev_kfree_skb_any(rp->skb); rp->skb = NULL; } @@ -1099,10 +1092,8 @@ static void b44_free_rings(struct b44 *bp) if (rp->skb == NULL) continue; - pci_unmap_single(bp->pdev, - pci_unmap_addr(rp, mapping), - rp->skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(bp->sdev->dev, rp->mapping, rp->skb->len, + DMA_TO_DEVICE); dev_kfree_skb_any(rp->skb); rp->skb = NULL; } @@ -1124,14 +1115,14 @@ static void b44_init_rings(struct b44 *bp) memset(bp->tx_ring, 0, B44_TX_RING_BYTES); if (bp->flags & B44_FLAG_RX_RING_HACK) - dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma, - DMA_TABLE_BYTES, - PCI_DMA_BIDIRECTIONAL); + dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); if (bp->flags & B44_FLAG_TX_RING_HACK) - dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma, - DMA_TABLE_BYTES, - PCI_DMA_TODEVICE); + dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); for (i = 0; i < bp->rx_pending; i++) { if (b44_alloc_rx_skb(bp, -1, i) < 0) @@ -1151,24 +1142,24 @@ static void b44_free_consistent(struct b44 *bp) bp->tx_buffers = NULL; if (bp->rx_ring) { if (bp->flags & B44_FLAG_RX_RING_HACK) { - dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, - DMA_TABLE_BYTES, - DMA_BIDIRECTIONAL); + dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); kfree(bp->rx_ring); } else - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, bp->rx_ring, bp->rx_ring_dma); bp->rx_ring = NULL; bp->flags &= ~B44_FLAG_RX_RING_HACK; } if (bp->tx_ring) { if (bp->flags & B44_FLAG_TX_RING_HACK) { - dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma, - DMA_TABLE_BYTES, - DMA_TO_DEVICE); + dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); kfree(bp->tx_ring); } else - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, bp->tx_ring, bp->tx_ring_dma); bp->tx_ring = NULL; bp->flags &= ~B44_FLAG_TX_RING_HACK; @@ -1179,22 +1170,22 @@ static void b44_free_consistent(struct b44 *bp) * Must not be invoked with interrupt sources disabled and * the hardware shutdown down. Can sleep. */ -static int b44_alloc_consistent(struct b44 *bp) +static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) { int size; size = B44_RX_RING_SIZE * sizeof(struct ring_info); - bp->rx_buffers = kzalloc(size, GFP_KERNEL); + bp->rx_buffers = kzalloc(size, gfp); if (!bp->rx_buffers) goto out_err; size = B44_TX_RING_SIZE * sizeof(struct ring_info); - bp->tx_buffers = kzalloc(size, GFP_KERNEL); + bp->tx_buffers = kzalloc(size, gfp); if (!bp->tx_buffers) goto out_err; size = DMA_TABLE_BYTES; - bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); + bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, gfp); if (!bp->rx_ring) { /* Allocation may have failed due to pci_alloc_consistent insisting on use of GFP_DMA, which is more restrictive @@ -1202,13 +1193,13 @@ static int b44_alloc_consistent(struct b44 *bp) struct dma_desc *rx_ring; dma_addr_t rx_ring_dma; - rx_ring = kzalloc(size, GFP_KERNEL); + rx_ring = kzalloc(size, gfp); if (!rx_ring) goto out_err; - rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring, - DMA_TABLE_BYTES, - DMA_BIDIRECTIONAL); + rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); if (dma_mapping_error(rx_ring_dma) || rx_ring_dma + size > DMA_30BIT_MASK) { @@ -1221,21 +1212,21 @@ static int b44_alloc_consistent(struct b44 *bp) bp->flags |= B44_FLAG_RX_RING_HACK; } - bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); + bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, gfp); if (!bp->tx_ring) { - /* Allocation may have failed due to pci_alloc_consistent + /* Allocation may have failed due to dma_alloc_coherent insisting on use of GFP_DMA, which is more restrictive than necessary... */ struct dma_desc *tx_ring; dma_addr_t tx_ring_dma; - tx_ring = kzalloc(size, GFP_KERNEL); + tx_ring = kzalloc(size, gfp); if (!tx_ring) goto out_err; - tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring, - DMA_TABLE_BYTES, - DMA_TO_DEVICE); + tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); if (dma_mapping_error(tx_ring_dma) || tx_ring_dma + size > DMA_30BIT_MASK) { @@ -1270,7 +1261,9 @@ static void b44_clear_stats(struct b44 *bp) /* bp->lock is held. */ static void b44_chip_reset(struct b44 *bp) { - if (ssb_is_core_up(bp)) { + struct ssb_device *sdev = bp->sdev; + + if (ssb_device_is_enabled(bp->sdev)) { bw32(bp, B44_RCV_LAZY, 0); bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); @@ -1282,19 +1275,25 @@ static void b44_chip_reset(struct b44 *bp) } bw32(bp, B44_DMARX_CTRL, 0); bp->rx_prod = bp->rx_cons = 0; - } else { - ssb_pci_setup(bp, (bp->core_unit == 0 ? - SBINTVEC_ENET0 : - SBINTVEC_ENET1)); - } - - ssb_core_reset(bp); + } else + ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev); + ssb_device_enable(bp->sdev, 0); b44_clear_stats(bp); - /* Make PHY accessible. */ - bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | - (0x0d & MDIO_CTRL_MAXF_MASK))); + 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) + & 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; + } + br32(bp, B44_MDIO_CTRL); if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { @@ -1337,6 +1336,7 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) { struct b44 *bp = netdev_priv(dev); struct sockaddr *addr = p; + u32 val; if (netif_running(dev)) return -EBUSY; @@ -1347,7 +1347,11 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); spin_lock_irq(&bp->lock); - __b44_set_mac_addr(bp); + + val = br32(bp, B44_RXCONFIG); + if (!(val & RXCONFIG_CAM_ABSENT)) + __b44_set_mac_addr(bp); + spin_unlock_irq(&bp->lock); return 0; @@ -1404,7 +1408,7 @@ static int b44_open(struct net_device *dev) struct b44 *bp = netdev_priv(dev); int err; - err = b44_alloc_consistent(bp); + err = b44_alloc_consistent(bp, GFP_KERNEL); if (err) goto out; @@ -1436,18 +1440,6 @@ out: return err; } -#if 0 -/*static*/ void b44_dump_state(struct b44 *bp) -{ - u32 val32, val32_2, val32_3, val32_4, val32_5; - u16 val16; - - pci_read_config_word(bp->pdev, PCI_STATUS, &val16); - printk("DEBUG: PCI status [%04x] \n", val16); - -} -#endif - #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling receive - used by netconsole and other diagnostic tools @@ -1558,10 +1550,24 @@ static void b44_setup_pseudo_magicp(struct b44 *bp) } +#ifdef CONFIG_B44_PCI +static void b44_setup_wol_pci(struct b44 *bp) +{ + u16 val; + + if (bp->sdev->bus->bustype != SSB_BUSTYPE_SSB) { + bw32(bp, SSB_TMSLOW, br32(bp, SSB_TMSLOW) | SSB_TMSLOW_PE); + pci_read_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, &val); + pci_write_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, val | SSB_PE); + } +} +#else +static inline void b44_setup_wol_pci(struct b44 *bp) { } +#endif /* CONFIG_B44_PCI */ + static void b44_setup_wol(struct b44 *bp) { u32 val; - u16 pmval; bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI); @@ -1585,13 +1591,7 @@ static void b44_setup_wol(struct b44 *bp) } else { b44_setup_pseudo_magicp(bp); } - - val = br32(bp, B44_SBTMSLOW); - bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE); - - pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval); - pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE); - + b44_setup_wol_pci(bp); } static int b44_close(struct net_device *dev) @@ -1606,9 +1606,6 @@ static int b44_close(struct net_device *dev) spin_lock_irq(&bp->lock); -#if 0 - b44_dump_state(bp); -#endif b44_halt(bp); b44_free_rings(bp); netif_carrier_off(dev); @@ -1689,7 +1686,7 @@ static void __b44_set_rx_mode(struct net_device *dev) val = br32(bp, B44_RXCONFIG); val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI); - if (dev->flags & IFF_PROMISC) { + if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) { val |= RXCONFIG_PROMISC; bw32(bp, B44_RXCONFIG, val); } else { @@ -1737,11 +1734,19 @@ static void b44_set_msglevel(struct net_device *dev, u32 value) static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) { struct b44 *bp = netdev_priv(dev); - struct pci_dev *pci_dev = bp->pdev; + struct ssb_bus *bus = bp->sdev->bus; - strcpy (info->driver, DRV_MODULE_NAME); - strcpy (info->version, DRV_MODULE_VERSION); - strcpy (info->bus_info, pci_name(pci_dev)); + strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); + strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver)); + switch (bus->bustype) { + case SSB_BUSTYPE_PCI: + strncpy(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)); + break; + } } static int b44_nway_reset(struct net_device *dev) @@ -2040,33 +2045,23 @@ out: return err; } -/* Read 128-bytes of EEPROM. */ -static int b44_read_eeprom(struct b44 *bp, u8 *data) -{ - long i; - __le16 *ptr = (__le16 *) data; - - for (i = 0; i < 128; i += 2) - ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); - - return 0; -} - static int __devinit b44_get_invariants(struct b44 *bp) { - u8 eeprom[128]; - int err; + struct ssb_device *sdev = bp->sdev; + int err = 0; + u8 *addr; - err = b44_read_eeprom(bp, &eeprom[0]); - if (err) - goto out; + bp->dma_offset = ssb_dma_translation(sdev); - bp->dev->dev_addr[0] = eeprom[79]; - bp->dev->dev_addr[1] = eeprom[78]; - bp->dev->dev_addr[2] = eeprom[81]; - bp->dev->dev_addr[3] = eeprom[80]; - bp->dev->dev_addr[4] = eeprom[83]; - bp->dev->dev_addr[5] = eeprom[82]; + if (sdev->bus->bustype == SSB_BUSTYPE_SSB && + instance > 1) { + addr = sdev->bus->sprom.r1.et1mac; + bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr; + } else { + addr = sdev->bus->sprom.r1.et0mac; + bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr; + } + memcpy(bp->dev->dev_addr, addr, 6); if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){ printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n"); @@ -2075,103 +2070,53 @@ static int __devinit b44_get_invariants(struct b44 *bp) memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); - bp->phy_addr = eeprom[90] & 0x1f; - bp->imask = IMASK_DEF; - bp->core_unit = ssb_core_unit(bp); - bp->dma_offset = SB_PCI_DMA; - /* XXX - really required? bp->flags |= B44_FLAG_BUGGY_TXPTR; - */ + */ - if (ssb_get_core_rev(bp) >= 7) - bp->flags |= B44_FLAG_B0_ANDLATER; + if (bp->sdev->id.revision >= 7) + bp->flags |= B44_FLAG_B0_ANDLATER; -out: return err; } -static int __devinit b44_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int __devinit b44_init_one(struct ssb_device *sdev, + const struct ssb_device_id *ent) { static int b44_version_printed = 0; - unsigned long b44reg_base, b44reg_len; struct net_device *dev; struct b44 *bp; int err; DECLARE_MAC_BUF(mac); + instance++; + if (b44_version_printed++ == 0) printk(KERN_INFO "%s", version); - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "Cannot enable PCI device, " - "aborting.\n"); - return err; - } - - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - dev_err(&pdev->dev, - "Cannot find proper PCI device " - "base address, aborting.\n"); - err = -ENODEV; - goto err_out_disable_pdev; - } - - err = pci_request_regions(pdev, DRV_MODULE_NAME); - if (err) { - dev_err(&pdev->dev, - "Cannot obtain PCI resources, aborting.\n"); - goto err_out_disable_pdev; - } - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK); - if (err) { - dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); - goto err_out_free_res; - } - - err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK); - if (err) { - dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); - goto err_out_free_res; - } - - b44reg_base = pci_resource_start(pdev, 0); - b44reg_len = pci_resource_len(pdev, 0); dev = alloc_etherdev(sizeof(*bp)); if (!dev) { - dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n"); + dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n"); err = -ENOMEM; - goto err_out_free_res; + goto out; } - SET_NETDEV_DEV(dev,&pdev->dev); + SET_NETDEV_DEV(dev, sdev->dev); /* No interesting netdevice features in this card... */ dev->features |= 0; bp = netdev_priv(dev); - bp->pdev = pdev; + bp->sdev = sdev; bp->dev = dev; bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE); spin_lock_init(&bp->lock); - bp->regs = ioremap(b44reg_base, b44reg_len); - if (bp->regs == 0UL) { - dev_err(&pdev->dev, "Cannot map device registers, aborting.\n"); - err = -ENOMEM; - goto err_out_free_dev; - } - bp->rx_pending = B44_DEF_RX_RING_PENDING; bp->tx_pending = B44_DEF_TX_RING_PENDING; @@ -2189,16 +2134,28 @@ static int __devinit b44_init_one(struct pci_dev *pdev, dev->poll_controller = b44_poll_controller; #endif dev->change_mtu = b44_change_mtu; - dev->irq = pdev->irq; + dev->irq = sdev->irq; SET_ETHTOOL_OPS(dev, &b44_ethtool_ops); netif_carrier_off(dev); + err = ssb_bus_powerup(sdev->bus, 0); + if (err) { + dev_err(sdev->dev, + "Failed to powerup the bus\n"); + goto err_out_free_dev; + } + err = ssb_dma_set_mask(sdev, DMA_30BIT_MASK); + if (err) { + dev_err(sdev->dev, + "Required 30BIT DMA mask unsupported by the system.\n"); + goto err_out_powerdown; + } err = b44_get_invariants(bp); if (err) { - dev_err(&pdev->dev, + dev_err(sdev->dev, "Problem fetching invariants of chip, aborting.\n"); - goto err_out_iounmap; + goto err_out_powerdown; } bp->mii_if.dev = dev; @@ -2217,59 +2174,49 @@ static int __devinit b44_init_one(struct pci_dev *pdev, err = register_netdev(dev); if (err) { - dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); - goto err_out_iounmap; + dev_err(sdev->dev, "Cannot register net device, aborting.\n"); + goto err_out_powerdown; } - pci_set_drvdata(pdev, dev); - - pci_save_state(bp->pdev); + ssb_set_drvdata(sdev, dev); /* Chip reset provides power to the b44 MAC & PCI cores, which * is necessary for MAC register access. */ b44_chip_reset(bp); - printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet %s\n", + printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n", dev->name, print_mac(mac, dev->dev_addr)); return 0; -err_out_iounmap: - iounmap(bp->regs); +err_out_powerdown: + ssb_bus_may_powerdown(sdev->bus); err_out_free_dev: free_netdev(dev); -err_out_free_res: - pci_release_regions(pdev); - -err_out_disable_pdev: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); +out: return err; } -static void __devexit b44_remove_one(struct pci_dev *pdev) +static void __devexit b44_remove_one(struct ssb_device *sdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct b44 *bp = netdev_priv(dev); + struct net_device *dev = ssb_get_drvdata(sdev); unregister_netdev(dev); - iounmap(bp->regs); + ssb_bus_may_powerdown(sdev->bus); free_netdev(dev); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); + ssb_set_drvdata(sdev, NULL); } -static int b44_suspend(struct pci_dev *pdev, pm_message_t state) +static int b44_suspend(struct ssb_device *sdev, pm_message_t state) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = ssb_get_drvdata(sdev); struct b44 *bp = netdev_priv(dev); - if (!netif_running(dev)) - return 0; + if (!netif_running(dev)) + return 0; del_timer_sync(&bp->timer); @@ -2287,33 +2234,29 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) b44_init_hw(bp, B44_PARTIAL_RESET); b44_setup_wol(bp); } - pci_disable_device(pdev); + return 0; } -static int b44_resume(struct pci_dev *pdev) +static int b44_resume(struct ssb_device *sdev) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = ssb_get_drvdata(sdev); struct b44 *bp = netdev_priv(dev); int rc = 0; - pci_restore_state(pdev); - rc = pci_enable_device(pdev); + rc = ssb_bus_powerup(sdev->bus, 0); if (rc) { - printk(KERN_ERR PFX "%s: pci_enable_device failed\n", - dev->name); + dev_err(sdev->dev, + "Failed to powerup the bus\n"); return rc; } - pci_set_master(pdev); - if (!netif_running(dev)) return 0; rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); if (rc) { printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); - pci_disable_device(pdev); return rc; } @@ -2332,29 +2275,53 @@ static int b44_resume(struct pci_dev *pdev) return 0; } -static struct pci_driver b44_driver = { +static struct ssb_driver b44_ssb_driver = { .name = DRV_MODULE_NAME, - .id_table = b44_pci_tbl, + .id_table = b44_ssb_tbl, .probe = b44_init_one, .remove = __devexit_p(b44_remove_one), - .suspend = b44_suspend, - .resume = b44_resume, + .suspend = b44_suspend, + .resume = b44_resume, }; +static inline int b44_pci_init(void) +{ + int err = 0; +#ifdef CONFIG_B44_PCI + err = ssb_pcihost_register(&b44_pci_driver); +#endif + return err; +} + +static inline void b44_pci_exit(void) +{ +#ifdef CONFIG_B44_PCI + ssb_pcihost_unregister(&b44_pci_driver); +#endif +} + static int __init b44_init(void) { unsigned int dma_desc_align_size = dma_get_cache_alignment(); + int err; /* Setup paramaters for syncing RX/TX DMA descriptors */ dma_desc_align_mask = ~(dma_desc_align_size - 1); dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); - return pci_register_driver(&b44_driver); + err = b44_pci_init(); + if (err) + return err; + err = ssb_driver_register(&b44_ssb_driver); + if (err) + b44_pci_exit(); + return err; } static void __exit b44_cleanup(void) { - pci_unregister_driver(&b44_driver); + ssb_driver_unregister(&b44_ssb_driver); + b44_pci_exit(); } module_init(b44_init); diff --git a/drivers/net/b44.h b/drivers/net/b44.h index 63c55a4ab3cd..7db0c84a7950 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -129,6 +129,7 @@ #define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */ #define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */ #define RXCONFIG_RFILT 0x00000080 /* Reject Filter */ +#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */ #define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */ #define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */ #define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */ @@ -227,76 +228,6 @@ #define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */ #define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */ -/* Silicon backplane register definitions */ -#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */ -#define SBIMSTATE_PC 0x0000000f /* Pipe Count */ -#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ -#define SBIMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */ -#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */ -#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */ -#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */ -#define SBIMSTATE_IBE 0x00020000 /* In Band Error */ -#define SBIMSTATE_TO 0x00040000 /* Timeout */ -#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */ -#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */ -#define SBINTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */ -#define SBINTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */ -#define SBINTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */ -#define SBINTVEC_USB 0x00000010 /* Enable interrupts for usb */ -#define SBINTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */ -#define SBINTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ -#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */ -#define SBTMSLOW_RESET 0x00000001 /* Reset */ -#define SBTMSLOW_REJECT 0x00000002 /* Reject */ -#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */ -#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ -#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */ -#define SBTMSLOW_BE 0x80000000 /* BIST Enable */ -#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */ -#define SBTMSHIGH_SERR 0x00000001 /* S-error */ -#define SBTMSHIGH_INT 0x00000002 /* Interrupt */ -#define SBTMSHIGH_BUSY 0x00000004 /* Busy */ -#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */ -#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */ -#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */ -#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */ -#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */ -#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */ -#define SBIDHIGH_CC_SHIFT 4 -#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */ -#define SBIDHIGH_VC_SHIFT 16 - -/* SSB PCI config space registers. */ -#define SSB_PMCSR 0x44 -#define SSB_PE 0x100 -#define SSB_BAR0_WIN 0x80 -#define SSB_BAR1_WIN 0x84 -#define SSB_SPROM_CONTROL 0x88 -#define SSB_BAR1_CONTROL 0x8c - -/* SSB core and host control registers. */ -#define SSB_CONTROL 0x0000UL -#define SSB_ARBCONTROL 0x0010UL -#define SSB_ISTAT 0x0020UL -#define SSB_IMASK 0x0024UL -#define SSB_MBOX 0x0028UL -#define SSB_BCAST_ADDR 0x0050UL -#define SSB_BCAST_DATA 0x0054UL -#define SSB_PCI_TRANS_0 0x0100UL -#define SSB_PCI_TRANS_1 0x0104UL -#define SSB_PCI_TRANS_2 0x0108UL -#define SSB_SPROM 0x0800UL - -#define SSB_PCI_MEM 0x00000000 -#define SSB_PCI_IO 0x00000001 -#define SSB_PCI_CFG0 0x00000002 -#define SSB_PCI_CFG1 0x00000003 -#define SSB_PCI_PREF 0x00000004 -#define SSB_PCI_BURST 0x00000008 -#define SSB_PCI_MASK0 0xfc000000 -#define SSB_PCI_MASK1 0xfc000000 -#define SSB_PCI_MASK2 0xc0000000 - /* 4400 PHY registers */ #define B44_MII_AUXCTRL 24 /* Auxiliary Control */ #define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */ @@ -346,10 +277,12 @@ struct rx_header { struct ring_info { struct sk_buff *skb; - DECLARE_PCI_UNMAP_ADDR(mapping); + dma_addr_t mapping; }; #define B44_MCAST_TABLE_SIZE 32 +#define B44_PHY_ADDR_NO_PHY 30 +#define B44_MDC_RATIO 5000000 #define B44_STAT_REG_DECLARE \ _B44(tx_good_octets) \ @@ -410,6 +343,8 @@ B44_STAT_REG_DECLARE #undef _B44 }; +struct ssb_device; + struct b44 { spinlock_t lock; @@ -452,8 +387,7 @@ struct b44 { struct net_device_stats stats; struct b44_hw_stats hw_stats; - void __iomem *regs; - struct pci_dev *pdev; + struct ssb_device *sdev; struct net_device *dev; dma_addr_t rx_ring_dma, tx_ring_dma; @@ -461,7 +395,6 @@ struct b44 { u32 rx_pending; u32 tx_pending; u8 phy_addr; - u8 core_unit; struct mii_if_info mii_if; }; From b9f2c0440d806e01968c3ed4def930a43be248ad Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 18:07:32 -0700 Subject: [PATCH 1427/2804] [netdrvr] Stop using legacy hooks ->self_test_count, ->get_stats_count These have been superceded by the new ->get_sset_count() hook. Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 11 +++- drivers/net/8139cp.c | 11 +++- drivers/net/8139too.c | 11 +++- drivers/net/atl1/atl1_ethtool.c | 11 +++- drivers/net/b44.c | 11 +++- drivers/net/bnx2.c | 20 +++---- drivers/net/cassini.c | 11 +++- drivers/net/chelsio/cxgb2.c | 11 +++- drivers/net/cxgb3/cxgb3_main.c | 11 +++- drivers/net/e100.c | 19 ++++--- drivers/net/e1000/e1000_ethtool.c | 22 ++++---- drivers/net/e1000e/ethtool.c | 21 ++++--- drivers/net/ehea/ehea_ethtool.c | 13 +++-- drivers/net/forcedeth.c | 45 ++++++++------- drivers/net/gianfar_ethtool.c | 20 ++++--- drivers/net/ibm_emac/ibm_emac_core.c | 12 ++-- drivers/net/ibmveth.c | 11 +++- drivers/net/ixgb/ixgb_ethtool.c | 11 +++- drivers/net/ixgbe/ixgbe_ethtool.c | 11 +++- drivers/net/mv643xx_eth.c | 10 +++- drivers/net/myri10ge/myri10ge.c | 11 +++- drivers/net/netxen/netxen_nic_ethtool.c | 21 ++++--- drivers/net/pcnet32.c | 11 +++- drivers/net/qla3xxx.c | 2 - drivers/net/r8169.c | 11 +++- drivers/net/s2io.c | 47 +++++++--------- drivers/net/sc92031.c | 11 +++- drivers/net/skge.c | 11 +++- drivers/net/sky2.c | 11 +++- drivers/net/spider_net_ethtool.c | 11 +++- drivers/net/tc35815.c | 12 +++- drivers/net/tg3.c | 19 ++++--- drivers/net/ucc_geth_ethtool.c | 26 +++++---- drivers/net/veth.c | 11 +++- drivers/net/wireless/libertas/ethtool.c | 74 +++++++++++-------------- 35 files changed, 346 insertions(+), 246 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 58311199e321..93eb78425d6d 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2833,9 +2833,14 @@ static void vortex_set_msglevel(struct net_device *dev, u32 dbg) vortex_debug = dbg; } -static int vortex_get_stats_count(struct net_device *dev) +static int vortex_get_sset_count(struct net_device *dev, int sset) { - return VORTEX_NUM_STATS; + switch (sset) { + case ETH_SS_STATS: + return VORTEX_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void vortex_get_ethtool_stats(struct net_device *dev, @@ -2892,7 +2897,7 @@ static const struct ethtool_ops vortex_ethtool_ops = { .get_msglevel = vortex_get_msglevel, .set_msglevel = vortex_set_msglevel, .get_ethtool_stats = vortex_get_ethtool_stats, - .get_stats_count = vortex_get_stats_count, + .get_sset_count = vortex_get_sset_count, .get_settings = vortex_get_settings, .set_settings = vortex_set_settings, .get_link = ethtool_op_get_link, diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 7edd50cf7776..d437823c2c5e 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1383,9 +1383,14 @@ static int cp_get_regs_len(struct net_device *dev) return CP_REGS_SIZE; } -static int cp_get_stats_count (struct net_device *dev) +static int cp_get_sset_count (struct net_device *dev, int sset) { - return CP_NUM_STATS; + switch (sset) { + case ETH_SS_STATS: + return CP_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static int cp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -1563,7 +1568,7 @@ static void cp_get_ethtool_stats (struct net_device *dev, static const struct ethtool_ops cp_ethtool_ops = { .get_drvinfo = cp_get_drvinfo, .get_regs_len = cp_get_regs_len, - .get_stats_count = cp_get_stats_count, + .get_sset_count = cp_get_sset_count, .get_settings = cp_get_settings, .set_settings = cp_set_settings, .nway_reset = cp_nway_reset, diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index d3088a786e26..973b684c11e3 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2406,9 +2406,14 @@ static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, } #endif /* CONFIG_8139TOO_MMIO */ -static int rtl8139_get_stats_count(struct net_device *dev) +static int rtl8139_get_sset_count(struct net_device *dev, int sset) { - return RTL_NUM_STATS; + switch (sset) { + case ETH_SS_STATS: + return RTL_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) @@ -2439,7 +2444,7 @@ static const struct ethtool_ops rtl8139_ethtool_ops = { .get_wol = rtl8139_get_wol, .set_wol = rtl8139_set_wol, .get_strings = rtl8139_get_strings, - .get_stats_count = rtl8139_get_stats_count, + .get_sset_count = rtl8139_get_sset_count, .get_ethtool_stats = rtl8139_get_ethtool_stats, }; diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c index 53353b60a9c8..68a83be843ab 100644 --- a/drivers/net/atl1/atl1_ethtool.c +++ b/drivers/net/atl1/atl1_ethtool.c @@ -88,9 +88,14 @@ static void atl1_get_ethtool_stats(struct net_device *netdev, } -static int atl1_get_stats_count(struct net_device *netdev) +static int atl1_get_sset_count(struct net_device *netdev, int sset) { - return ARRAY_SIZE(atl1_gstrings_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(atl1_gstrings_stats); + default: + return -EOPNOTSUPP; + } } static int atl1_get_settings(struct net_device *netdev, @@ -495,6 +500,6 @@ const struct ethtool_ops atl1_ethtool_ops = { .get_strings = atl1_get_strings, .nway_reset = atl1_nway_reset, .get_ethtool_stats = atl1_get_ethtool_stats, - .get_stats_count = atl1_get_stats_count, + .get_sset_count = atl1_get_sset_count, .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index e90ba217d244..3d247f3f4a3c 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1962,9 +1962,14 @@ static void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int b44_get_stats_count(struct net_device *dev) +static int b44_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(b44_gstrings); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(b44_gstrings); + default: + return -EOPNOTSUPP; + } } static void b44_get_ethtool_stats(struct net_device *dev, @@ -2025,7 +2030,7 @@ static const struct ethtool_ops b44_ethtool_ops = { .get_msglevel = b44_get_msglevel, .set_msglevel = b44_set_msglevel, .get_strings = b44_get_strings, - .get_stats_count = b44_get_stats_count, + .get_sset_count = b44_get_sset_count, .get_ethtool_stats = b44_get_ethtool_stats, }; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index ee9aed3aa489..57f7d994c9c1 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6068,9 +6068,16 @@ static struct { }; static int -bnx2_self_test_count(struct net_device *dev) +bnx2_get_sset_count(struct net_device *dev, int sset) { - return BNX2_NUM_TESTS; + switch (sset) { + case ETH_SS_TEST: + return BNX2_NUM_TESTS; + case ETH_SS_STATS: + return BNX2_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void @@ -6144,12 +6151,6 @@ bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } -static int -bnx2_get_stats_count(struct net_device *dev) -{ - return BNX2_NUM_STATS; -} - static void bnx2_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *buf) @@ -6260,12 +6261,11 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_tx_csum = bnx2_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = bnx2_set_tso, - .self_test_count = bnx2_self_test_count, .self_test = bnx2_self_test, .get_strings = bnx2_get_strings, .phys_id = bnx2_phys_id, - .get_stats_count = bnx2_get_stats_count, .get_ethtool_stats = bnx2_get_ethtool_stats, + .get_sset_count = bnx2_get_sset_count, }; /* Called with rtnl_lock */ diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index adc2e4d5a69e..563bf5f6fa2a 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4772,9 +4772,14 @@ static void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs, cas_read_regs(cp, p, regs->len / sizeof(u32)); } -static int cas_get_stats_count(struct net_device *dev) +static int cas_get_sset_count(struct net_device *dev, int sset) { - return CAS_NUM_STAT_KEYS; + switch (sset) { + case ETH_SS_STATS: + return CAS_NUM_STAT_KEYS; + default: + return -EOPNOTSUPP; + } } static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -4818,7 +4823,7 @@ static const struct ethtool_ops cas_ethtool_ops = { .set_msglevel = cas_set_msglevel, .get_regs_len = cas_get_regs_len, .get_regs = cas_get_regs, - .get_stats_count = cas_get_stats_count, + .get_sset_count = cas_get_sset_count, .get_strings = cas_get_strings, .get_ethtool_stats = cas_get_ethtool_stats, }; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 7029f13d008d..2dbf8dc116c6 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -439,9 +439,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) strcpy(info->bus_info, pci_name(adapter->pdev)); } -static int get_stats_count(struct net_device *dev) +static int get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(stats_strings); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } } static void get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -798,7 +803,7 @@ static const struct ethtool_ops t1_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, - .get_stats_count = get_stats_count, + .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 04633ea55202..e22d06531051 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1131,9 +1131,14 @@ static char stats_strings[][ETH_GSTRING_LEN] = { }; -static int get_stats_count(struct net_device *dev) +static int get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(stats_strings); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } } #define T3_REGMAP_SIZE (3 * 1024) @@ -1640,7 +1645,7 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .get_strings = get_strings, .phys_id = cxgb3_phys_id, .nway_reset = restart_autoneg, - .get_stats_count = get_stats_count, + .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 720994b1e13a..7bd960402687 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2374,11 +2374,6 @@ static const char e100_gstrings_test[][ETH_GSTRING_LEN] = { }; #define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN -static int e100_diag_test_count(struct net_device *netdev) -{ - return E100_TEST_LEN; -} - static void e100_diag_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) { @@ -2441,9 +2436,16 @@ static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = { #define E100_NET_STATS_LEN 21 #define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN -static int e100_get_stats_count(struct net_device *netdev) +static int e100_get_sset_count(struct net_device *netdev, int sset) { - return E100_STATS_LEN; + switch (sset) { + case ETH_SS_TEST: + return E100_TEST_LEN; + case ETH_SS_STATS: + return E100_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void e100_get_ethtool_stats(struct net_device *netdev, @@ -2494,12 +2496,11 @@ static const struct ethtool_ops e100_ethtool_ops = { .set_eeprom = e100_set_eeprom, .get_ringparam = e100_get_ringparam, .set_ringparam = e100_set_ringparam, - .self_test_count = e100_diag_test_count, .self_test = e100_diag_test, .get_strings = e100_get_strings, .phys_id = e100_phys_id, - .get_stats_count = e100_get_stats_count, .get_ethtool_stats = e100_get_ethtool_stats, + .get_sset_count = e100_get_sset_count, }; static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index e6c4a3bb9e4c..6c9a643426f5 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -618,8 +618,6 @@ e1000_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - drvinfo->n_stats = E1000_STATS_LEN; - drvinfo->testinfo_len = E1000_TEST_LEN; drvinfo->regdump_len = e1000_get_regs_len(netdev); drvinfo->eedump_len = e1000_get_eeprom_len(netdev); } @@ -1611,9 +1609,16 @@ e1000_link_test(struct e1000_adapter *adapter, uint64_t *data) } static int -e1000_diag_test_count(struct net_device *netdev) +e1000_get_sset_count(struct net_device *netdev, int sset) { - return E1000_TEST_LEN; + switch (sset) { + case ETH_SS_TEST: + return E1000_TEST_LEN; + case ETH_SS_STATS: + return E1000_STATS_LEN; + default: + return -EOPNOTSUPP; + } } extern void e1000_power_up_phy(struct e1000_adapter *); @@ -1898,12 +1903,6 @@ e1000_nway_reset(struct net_device *netdev) return 0; } -static int -e1000_get_stats_count(struct net_device *netdev) -{ - return E1000_STATS_LEN; -} - static void e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) @@ -1967,12 +1966,11 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_tx_csum = e1000_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = e1000_set_tso, - .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, - .get_stats_count = e1000_get_stats_count, .get_ethtool_stats = e1000_get_ethtool_stats, + .get_sset_count = e1000_get_sset_count, }; void e1000_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 0e80406bfbd7..3423f33769b7 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -577,8 +577,6 @@ static void e1000_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - drvinfo->n_stats = E1000_STATS_LEN; - drvinfo->testinfo_len = E1000_TEST_LEN; drvinfo->regdump_len = e1000_get_regs_len(netdev); drvinfo->eedump_len = e1000_get_eeprom_len(netdev); } @@ -1493,9 +1491,16 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) return *data; } -static int e1000_diag_test_count(struct net_device *netdev) +static int e1000e_get_sset_count(struct net_device *netdev, int sset) { - return E1000_TEST_LEN; + switch (sset) { + case ETH_SS_TEST: + return E1000_TEST_LEN; + case ETH_SS_STATS: + return E1000_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void e1000_diag_test(struct net_device *netdev, @@ -1692,11 +1697,6 @@ static int e1000_nway_reset(struct net_device *netdev) return 0; } -static int e1000_get_stats_count(struct net_device *netdev) -{ - return E1000_STATS_LEN; -} - static void e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) @@ -1760,12 +1760,11 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = e1000_set_tso, - .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, - .get_stats_count = e1000_get_stats_count, .get_ethtool_stats = e1000_get_ethtool_stats, + .get_sset_count = e1000e_get_sset_count, }; void e1000e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 6498455bf97c..679f40ee9572 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -196,9 +196,14 @@ static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int ehea_get_stats_count(struct net_device *dev) +static int ehea_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(ehea_ethtool_stats_keys); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ehea_ethtool_stats_keys); + default: + return -EOPNOTSUPP; + } } static void ehea_get_ethtool_stats(struct net_device *dev, @@ -207,7 +212,7 @@ static void ehea_get_ethtool_stats(struct net_device *dev, int i, k, tmp; struct ehea_port *port = netdev_priv(dev); - for (i = 0; i < ehea_get_stats_count(dev); i++) + for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++) data[i] = 0; i = 0; @@ -264,7 +269,7 @@ const struct ethtool_ops ehea_ethtool_ops = { .get_link = ethtool_op_get_link, .set_tso = ethtool_op_set_tso, .get_strings = ehea_get_strings, - .get_stats_count = ehea_get_stats_count, + .get_sset_count = ehea_get_sset_count, .get_ethtool_stats = ehea_get_ethtool_stats, .get_rx_csum = ehea_get_rx_csum, .set_settings = ehea_set_settings, diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index f7354bc9b009..666de42e5a76 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4333,16 +4333,26 @@ static int nv_set_sg(struct net_device *dev, u32 data) return -EOPNOTSUPP; } -static int nv_get_stats_count(struct net_device *dev) +static int nv_get_sset_count(struct net_device *dev, int sset) { struct fe_priv *np = netdev_priv(dev); - if (np->driver_data & DEV_HAS_STATISTICS_V1) - return NV_DEV_STATISTICS_V1_COUNT; - else if (np->driver_data & DEV_HAS_STATISTICS_V2) - return NV_DEV_STATISTICS_V2_COUNT; - else - return 0; + switch (sset) { + case ETH_SS_TEST: + if (np->driver_data & DEV_HAS_TEST_EXTENDED) + return NV_TEST_COUNT_EXTENDED; + else + return NV_TEST_COUNT_BASE; + case ETH_SS_STATS: + if (np->driver_data & DEV_HAS_STATISTICS_V1) + return NV_DEV_STATISTICS_V1_COUNT; + else if (np->driver_data & DEV_HAS_STATISTICS_V2) + return NV_DEV_STATISTICS_V2_COUNT; + else + return 0; + default: + return -EOPNOTSUPP; + } } static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer) @@ -4352,17 +4362,7 @@ static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *e /* update stats */ nv_do_stats_poll((unsigned long)dev); - memcpy(buffer, &np->estats, nv_get_stats_count(dev)*sizeof(u64)); -} - -static int nv_self_test_count(struct net_device *dev) -{ - struct fe_priv *np = netdev_priv(dev); - - if (np->driver_data & DEV_HAS_TEST_EXTENDED) - return NV_TEST_COUNT_EXTENDED; - else - return NV_TEST_COUNT_BASE; + memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64)); } static int nv_link_test(struct net_device *dev) @@ -4609,7 +4609,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int result; - memset(buffer, 0, nv_self_test_count(dev)*sizeof(u64)); + memset(buffer, 0, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(u64)); if (!nv_link_test(dev)) { test->flags |= ETH_TEST_FL_FAILED; @@ -4692,10 +4692,10 @@ static void nv_get_strings(struct net_device *dev, u32 stringset, u8 *buffer) { switch (stringset) { case ETH_SS_STATS: - memcpy(buffer, &nv_estats_str, nv_get_stats_count(dev)*sizeof(struct nv_ethtool_str)); + memcpy(buffer, &nv_estats_str, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(struct nv_ethtool_str)); break; case ETH_SS_TEST: - memcpy(buffer, &nv_etests_str, nv_self_test_count(dev)*sizeof(struct nv_ethtool_str)); + memcpy(buffer, &nv_etests_str, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(struct nv_ethtool_str)); break; } } @@ -4720,9 +4720,8 @@ static const struct ethtool_ops ops = { .set_tx_csum = nv_set_tx_csum, .set_sg = nv_set_sg, .get_strings = nv_get_strings, - .get_stats_count = nv_get_stats_count, .get_ethtool_stats = nv_get_ethtool_stats, - .self_test_count = nv_self_test_count, + .get_sset_count = nv_get_sset_count, .self_test = nv_self_test, }; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 2470903fbc74..6007147cc1e9 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -152,15 +152,19 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, buf[i] = extra[i]; } -/* Returns the number of stats (and their corresponding strings) */ -static int gfar_stats_count(struct net_device *dev) +static int gfar_sset_count(struct net_device *dev, int sset) { struct gfar_private *priv = netdev_priv(dev); - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) - return GFAR_STATS_LEN; - else - return GFAR_EXTRA_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) + return GFAR_STATS_LEN; + else + return GFAR_EXTRA_STATS_LEN; + default: + return -EOPNOTSUPP; + } } /* Fills in the drvinfo structure with some basic info */ @@ -171,8 +175,6 @@ static void gfar_gdrvinfo(struct net_device *dev, struct strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN); strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN); strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN); - drvinfo->n_stats = GFAR_STATS_LEN; - drvinfo->testinfo_len = 0; drvinfo->regdump_len = 0; drvinfo->eedump_len = 0; } @@ -575,7 +577,7 @@ const struct ethtool_ops gfar_ethtool_ops = { .get_ringparam = gfar_gringparam, .set_ringparam = gfar_sringparam, .get_strings = gfar_gstrings, - .get_stats_count = gfar_stats_count, + .get_sset_count = gfar_sset_count, .get_ethtool_stats = gfar_fill_stats, .get_rx_csum = gfar_get_rx_csum, .get_tx_csum = gfar_get_tx_csum, diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 7d4fa7644e4b..73664f226f32 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1842,9 +1842,14 @@ static int emac_ethtool_nway_reset(struct net_device *ndev) return res; } -static int emac_ethtool_get_stats_count(struct net_device *ndev) +static int emac_get_sset_count(struct net_device *ndev, int sset) { - return EMAC_ETHTOOL_STATS_COUNT; + switch (sset) { + case ETH_SS_STATS: + return EMAC_ETHTOOL_STATS_COUNT; + default: + return -EOPNOTSUPP; + } } static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset, @@ -1875,7 +1880,6 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev, strcpy(info->version, DRV_VERSION); info->fw_version[0] = '\0'; sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index); - info->n_stats = emac_ethtool_get_stats_count(ndev); info->regdump_len = emac_ethtool_get_regs_len(ndev); } @@ -1895,7 +1899,7 @@ static const struct ethtool_ops emac_ethtool_ops = { .get_rx_csum = emac_ethtool_get_rx_csum, .get_strings = emac_ethtool_get_strings, - .get_stats_count = emac_ethtool_get_stats_count, + .get_sset_count = emac_get_sset_count, .get_ethtool_stats = emac_ethtool_get_ethtool_stats, .get_link = ethtool_op_get_link, diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 228973484ed8..4ac161e1ca12 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -802,9 +802,14 @@ static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) memcpy(data, ibmveth_stats[i].name, ETH_GSTRING_LEN); } -static int ibmveth_get_stats_count(struct net_device *dev) +static int ibmveth_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(ibmveth_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ibmveth_stats); + default: + return -EOPNOTSUPP; + } } static void ibmveth_get_ethtool_stats(struct net_device *dev, @@ -825,7 +830,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_rx_csum = ibmveth_get_rx_csum, .set_rx_csum = ibmveth_set_rx_csum, .get_strings = ibmveth_get_strings, - .get_stats_count = ibmveth_get_stats_count, + .get_sset_count = ibmveth_get_sset_count, .get_ethtool_stats = ibmveth_get_ethtool_stats, }; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 181b59dc1ac3..ddad26bb5c58 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -659,9 +659,14 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data) } static int -ixgb_get_stats_count(struct net_device *netdev) +ixgb_get_sset_count(struct net_device *netdev, int sset) { - return IXGB_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + return IXGB_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void @@ -719,7 +724,7 @@ static const struct ethtool_ops ixgb_ethtool_ops = { .set_tso = ixgb_set_tso, .get_strings = ixgb_get_strings, .phys_id = ixgb_phys_id, - .get_stats_count = ixgb_get_stats_count, + .get_sset_count = ixgb_get_sset_count, .get_ethtool_stats = ixgb_get_ethtool_stats, }; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 43a2a46e2874..a4e576a0c543 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -737,9 +737,14 @@ err_setup: return err; } -static int ixgbe_get_stats_count(struct net_device *netdev) +static int ixgbe_get_sset_count(struct net_device *netdev, int sset) { - return IXGBE_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + return IXGBE_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void ixgbe_get_ethtool_stats(struct net_device *netdev, @@ -931,7 +936,7 @@ static struct ethtool_ops ixgbe_ethtool_ops = { .set_tso = ixgbe_set_tso, .get_strings = ixgbe_get_strings, .phys_id = ixgbe_phys_id, - .get_stats_count = ixgbe_get_stats_count, + .get_sset_count = ixgbe_get_sset_count, .get_ethtool_stats = ixgbe_get_ethtool_stats, .get_coalesce = ixgbe_get_coalesce, .set_coalesce = ixgbe_set_coalesce, diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e379165d8375..b33d21f4efff 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2674,9 +2674,14 @@ static void mv643xx_get_drvinfo(struct net_device *netdev, drvinfo->n_stats = MV643XX_STATS_LEN; } -static int mv643xx_get_stats_count(struct net_device *netdev) +static int mv643xx_get_sset_count(struct net_device *netdev, int sset) { - return MV643XX_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + return MV643XX_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void mv643xx_get_ethtool_stats(struct net_device *netdev, @@ -2737,7 +2742,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = { .get_drvinfo = mv643xx_get_drvinfo, .get_link = mv643xx_eth_get_link, .set_sg = ethtool_op_set_sg, - .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, .get_strings = mv643xx_get_strings, .nway_reset = mv643xx_eth_nway_restart, diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 38b03f538e95..e8afa101433e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1418,9 +1418,14 @@ myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data) } } -static int myri10ge_get_stats_count(struct net_device *netdev) +static int myri10ge_get_sset_count(struct net_device *netdev, int sset) { - return MYRI10GE_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + return MYRI10GE_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void @@ -1504,7 +1509,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .set_tso = ethtool_op_set_tso, .get_link = ethtool_op_get_link, .get_strings = myri10ge_get_strings, - .get_stats_count = myri10ge_get_stats_count, + .get_sset_count = myri10ge_get_sset_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, .set_msglevel = myri10ge_set_msglevel, .get_msglevel = myri10ge_get_msglevel diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 08c76b343663..78e42316e70f 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -115,8 +115,6 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - drvinfo->n_stats = NETXEN_NIC_STATS_LEN; - drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN; drvinfo->regdump_len = NETXEN_NIC_REGS_LEN; drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev); } @@ -672,9 +670,16 @@ static int netxen_nic_reg_test(struct net_device *dev) return 0; } -static int netxen_nic_diag_test_count(struct net_device *dev) +static int netxen_get_sset_count(struct net_device *dev, int sset) { - return NETXEN_NIC_TEST_LEN; + switch (sset) { + case ETH_SS_TEST: + return NETXEN_NIC_TEST_LEN; + case ETH_SS_STATS: + return NETXEN_NIC_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void @@ -709,11 +714,6 @@ netxen_nic_get_strings(struct net_device *dev, u32 stringset, u8 * data) } } -static int netxen_nic_get_stats_count(struct net_device *dev) -{ - return NETXEN_NIC_STATS_LEN; -} - static void netxen_nic_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 * data) @@ -747,9 +747,8 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = ethtool_op_set_tso, - .self_test_count = netxen_nic_diag_test_count, .self_test = netxen_nic_diag_test, .get_strings = netxen_nic_get_strings, - .get_stats_count = netxen_nic_get_stats_count, .get_ethtool_stats = netxen_nic_get_ethtool_stats, + .get_sset_count = netxen_get_sset_count, }; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 4840ddea71ac..36f92dd55508 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -847,9 +847,14 @@ static void pcnet32_get_strings(struct net_device *dev, u32 stringset, memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test)); } -static int pcnet32_self_test_count(struct net_device *dev) +static int pcnet32_get_sset_count(struct net_device *dev, int sset) { - return PCNET32_TEST_LEN; + switch (sset) { + case ETH_SS_TEST: + return PCNET32_TEST_LEN; + default: + return -EOPNOTSUPP; + } } static void pcnet32_ethtool_test(struct net_device *dev, @@ -1510,11 +1515,11 @@ static const struct ethtool_ops pcnet32_ethtool_ops = { .get_ringparam = pcnet32_get_ringparam, .set_ringparam = pcnet32_set_ringparam, .get_strings = pcnet32_get_strings, - .self_test_count = pcnet32_self_test_count, .self_test = pcnet32_ethtool_test, .phys_id = pcnet32_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, + .get_sset_count = pcnet32_get_sset_count, }; /* only probes for non-PCI devices, the rest are handled by diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index ed79aa820df2..48069ece4e51 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1865,8 +1865,6 @@ static void ql_get_drvinfo(struct net_device *ndev, strncpy(drvinfo->version, ql3xxx_driver_version, 32); strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32); - drvinfo->n_stats = 0; - drvinfo->testinfo_len = 0; drvinfo->regdump_len = 0; drvinfo->eedump_len = 0; } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 06a1a6f2d17b..eecd811feead 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -992,9 +992,14 @@ struct rtl8169_counters { u16 tx_underun; }; -static int rtl8169_get_stats_count(struct net_device *dev) +static int rtl8169_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(rtl8169_gstrings); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(rtl8169_gstrings); + default: + return -EOPNOTSUPP; + } } static void rtl8169_get_ethtool_stats(struct net_device *dev, @@ -1068,7 +1073,7 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_wol = rtl8169_get_wol, .set_wol = rtl8169_set_wol, .get_strings = rtl8169_get_strings, - .get_stats_count = rtl8169_get_stats_count, + .get_sset_count = rtl8169_get_sset_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, }; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 26895de3e264..7f6b0e611e3b 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5040,12 +5040,6 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info)); info->regdump_len = XENA_REG_SPACE; info->eedump_len = XENA_EEPROM_SPACE; - info->testinfo_len = S2IO_TEST_LEN; - - if (sp->device_type == XFRAME_I_DEVICE) - info->n_stats = XFRAME_I_STAT_LEN; - else - info->n_stats = XFRAME_II_STAT_LEN; } /** @@ -6241,9 +6235,25 @@ static int s2io_get_eeprom_len(struct net_device *dev) return (XENA_EEPROM_SPACE); } -static int s2io_ethtool_self_test_count(struct net_device *dev) +static int s2io_get_sset_count(struct net_device *dev, int sset) { - return (S2IO_TEST_LEN); + struct s2io_nic *sp = dev->priv; + + switch (sset) { + case ETH_SS_TEST: + return S2IO_TEST_LEN; + case ETH_SS_STATS: + switch(sp->device_type) { + case XFRAME_I_DEVICE: + return XFRAME_I_STAT_LEN; + case XFRAME_II_DEVICE: + return XFRAME_II_STAT_LEN; + default: + return 0; + } + default: + return -EOPNOTSUPP; + } } static void s2io_ethtool_get_strings(struct net_device *dev, @@ -6270,22 +6280,6 @@ static void s2io_ethtool_get_strings(struct net_device *dev, sizeof(ethtool_driver_stats_keys)); } } -static int s2io_ethtool_get_stats_count(struct net_device *dev) -{ - struct s2io_nic *sp = dev->priv; - int stat_count = 0; - switch(sp->device_type) { - case XFRAME_I_DEVICE: - stat_count = XFRAME_I_STAT_LEN; - break; - - case XFRAME_II_DEVICE: - stat_count = XFRAME_II_STAT_LEN; - break; - } - - return stat_count; -} static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) { @@ -6331,12 +6325,11 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_tso = s2io_ethtool_op_get_tso, .set_tso = s2io_ethtool_op_set_tso, .set_ufo = ethtool_op_set_ufo, - .self_test_count = s2io_ethtool_self_test_count, .self_test = s2io_ethtool_test, .get_strings = s2io_ethtool_get_strings, .phys_id = s2io_ethtool_idnic, - .get_stats_count = s2io_ethtool_get_stats_count, - .get_ethtool_stats = s2io_get_ethtool_stats + .get_ethtool_stats = s2io_get_ethtool_stats, + .get_sset_count = s2io_get_sset_count, }; /** diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 02c472ecbe55..37b42394560d 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1372,9 +1372,14 @@ static void sc92031_ethtool_get_strings(struct net_device *dev, SILAN_STATS_NUM * ETH_GSTRING_LEN); } -static int sc92031_ethtool_get_stats_count(struct net_device *dev) +static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset) { - return SILAN_STATS_NUM; + switch (sset) { + case ETH_SS_STATS: + return SILAN_STATS_NUM; + default: + return -EOPNOTSUPP; + } } static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, @@ -1397,7 +1402,7 @@ static struct ethtool_ops sc92031_ethtool_ops = { .nway_reset = sc92031_ethtool_nway_reset, .get_link = ethtool_op_get_link, .get_strings = sc92031_ethtool_get_strings, - .get_stats_count = sc92031_ethtool_get_stats_count, + .get_sset_count = sc92031_ethtool_get_sset_count, .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, }; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index ec1acfddf350..2aae9fe38c5a 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -410,9 +410,14 @@ static const struct skge_stat { { "rx_fcs_error", XM_RXF_FCS_ERR, GM_RXF_FCS_ERR }, }; -static int skge_get_stats_count(struct net_device *dev) +static int skge_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(skge_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(skge_stats); + default: + return -EOPNOTSUPP; + } } static void skge_get_ethtool_stats(struct net_device *dev, @@ -817,7 +822,7 @@ static const struct ethtool_ops skge_ethtool_ops = { .set_rx_csum = skge_set_rx_csum, .get_strings = skge_get_strings, .phys_id = skge_phys_id, - .get_stats_count = skge_get_stats_count, + .get_sset_count = skge_get_sset_count, .get_ethtool_stats = skge_get_ethtool_stats, }; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a70bcbcf8a16..fe0e7560d236 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3190,9 +3190,14 @@ static void sky2_set_msglevel(struct net_device *netdev, u32 value) sky2->msg_enable = value; } -static int sky2_get_stats_count(struct net_device *dev) +static int sky2_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(sky2_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(sky2_stats); + default: + return -EOPNOTSUPP; + } } static void sky2_get_ethtool_stats(struct net_device *dev, @@ -3723,7 +3728,7 @@ static const struct ethtool_ops sky2_ethtool_ops = { .get_pauseparam = sky2_get_pauseparam, .set_pauseparam = sky2_set_pauseparam, .phys_id = sky2_phys_id, - .get_stats_count = sky2_get_stats_count, + .get_sset_count = sky2_get_sset_count, .get_ethtool_stats = sky2_get_ethtool_stats, }; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 1460d5006d1c..94273037102f 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -147,9 +147,14 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev, ering->rx_pending = card->rx_chain.num_desc; } -static int spider_net_get_stats_count(struct net_device *netdev) +static int spider_net_get_sset_count(struct net_device *netdev, int sset) { - return SPIDER_NET_NUM_STATS; + switch (sset) { + case ETH_SS_STATS: + return SPIDER_NET_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void spider_net_get_ethtool_stats(struct net_device *netdev, @@ -191,7 +196,7 @@ const struct ethtool_ops spider_net_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_csum, .get_ringparam = spider_net_ethtool_get_ringparam, .get_strings = spider_net_get_strings, - .get_stats_count = spider_net_get_stats_count, + .get_sset_count = spider_net_get_sset_count, .get_ethtool_stats = spider_net_get_ethtool_stats, }; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index df8237360f58..a679f4310ce1 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -2162,10 +2162,16 @@ static void tc35815_set_msglevel(struct net_device *dev, u32 datum) lp->msg_enable = datum; } -static int tc35815_get_stats_count(struct net_device *dev) +static int tc35815_get_sset_count(struct net_device *dev, int sset) { struct tc35815_local *lp = dev->priv; - return sizeof(lp->lstats) / sizeof(int); + + switch (sset) { + case ETH_SS_STATS: + return sizeof(lp->lstats) / sizeof(int); + default: + return -EOPNOTSUPP; + } } static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) @@ -2200,7 +2206,7 @@ static const struct ethtool_ops tc35815_ethtool_ops = { .get_msglevel = tc35815_get_msglevel, .set_msglevel = tc35815_set_msglevel, .get_strings = tc35815_get_strings, - .get_stats_count = tc35815_get_stats_count, + .get_sset_count = tc35815_get_sset_count, .get_ethtool_stats = tc35815_get_ethtool_stats, }; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1b860e0817f6..d4ac6e9ef6db 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8347,14 +8347,16 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) return 0; } -static int tg3_get_stats_count (struct net_device *dev) +static int tg3_get_sset_count (struct net_device *dev, int sset) { - return TG3_NUM_STATS; -} - -static int tg3_get_test_count (struct net_device *dev) -{ - return TG3_NUM_TEST; + switch (sset) { + case ETH_SS_TEST: + return TG3_NUM_TEST; + case ETH_SS_STATS: + return TG3_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf) @@ -9281,14 +9283,13 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_tx_csum = tg3_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = tg3_set_tso, - .self_test_count = tg3_get_test_count, .self_test = tg3_self_test, .get_strings = tg3_get_strings, .phys_id = tg3_phys_id, - .get_stats_count = tg3_get_stats_count, .get_ethtool_stats = tg3_get_ethtool_stats, .get_coalesce = tg3_get_coalesce, .set_coalesce = tg3_set_coalesce, + .get_sset_count = tg3_get_sset_count, }; static void __devinit tg3_get_eeprom_size(struct tg3 *tp) diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 73aa677a4a3e..9a9622c13e2b 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -276,20 +276,26 @@ uec_set_ringparam(struct net_device *netdev, return ret; } -static int uec_get_stats_count(struct net_device *netdev) +static int uec_get_sset_count(struct net_device *netdev, int sset) { struct ucc_geth_private *ugeth = netdev_priv(netdev); u32 stats_mode = ugeth->ug_info->statisticsMode; int len = 0; - if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) - len += UEC_HW_STATS_LEN; - if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) - len += UEC_TX_FW_STATS_LEN; - if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) - len += UEC_RX_FW_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) + len += UEC_HW_STATS_LEN; + if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) + len += UEC_TX_FW_STATS_LEN; + if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) + len += UEC_RX_FW_STATS_LEN; - return len; + return len; + + default: + return -EOPNOTSUPP; + } } static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) @@ -353,8 +359,6 @@ uec_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->version, DRV_VERSION, 32); strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, "QUICC ENGINE", 32); - drvinfo->n_stats = uec_get_stats_count(netdev); - drvinfo->testinfo_len = 0; drvinfo->eedump_len = 0; drvinfo->regdump_len = uec_get_regs_len(netdev); } @@ -374,7 +378,7 @@ static const struct ethtool_ops uec_ethtool_ops = { .get_pauseparam = uec_get_pauseparam, .set_pauseparam = uec_set_pauseparam, .set_sg = ethtool_op_set_sg, - .get_stats_count = uec_get_stats_count, + .get_sset_count = uec_get_sset_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, }; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2c86a4459d8a..fdd1e034569d 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -79,9 +79,14 @@ static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } -static int veth_get_stats_count(struct net_device *dev) +static int veth_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(ethtool_stats_keys); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ethtool_stats_keys); + default: + return -EOPNOTSUPP; + } } static void veth_get_ethtool_stats(struct net_device *dev, @@ -135,7 +140,7 @@ static struct ethtool_ops veth_ethtool_ops = { .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_strings = veth_get_strings, - .get_stats_count = veth_get_stats_count, + .get_sset_count = veth_get_sset_count, .get_ethtool_stats = veth_get_ethtool_stats, }; diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index d793d843f7d5..3dae15211b6a 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -109,29 +109,8 @@ static void libertas_ethtool_get_stats(struct net_device * dev, struct ethtool_stats * stats, u64 * data) { wlan_private *priv = dev->priv; - - lbs_deb_enter(LBS_DEB_ETHTOOL); - - stats->cmd = ETHTOOL_GSTATS; - BUG_ON(stats->n_stats != MESH_STATS_NUM); - - data[0] = priv->mstats.fwd_drop_rbt; - data[1] = priv->mstats.fwd_drop_ttl; - data[2] = priv->mstats.fwd_drop_noroute; - data[3] = priv->mstats.fwd_drop_nobuf; - data[4] = priv->mstats.fwd_unicast_cnt; - data[5] = priv->mstats.fwd_bcast_cnt; - data[6] = priv->mstats.drop_blind; - data[7] = priv->mstats.tx_failed_cnt; - - lbs_deb_enter(LBS_DEB_ETHTOOL); -} - -static int libertas_ethtool_get_stats_count(struct net_device * dev) -{ - int ret; - wlan_private *priv = dev->priv; struct cmd_ds_mesh_access mesh_access; + int ret; lbs_deb_enter(LBS_DEB_ETHTOOL); @@ -140,25 +119,38 @@ static int libertas_ethtool_get_stats_count(struct net_device * dev) CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS, CMD_OPTION_WAITFORRSP, 0, &mesh_access); - if (ret) { - ret = 0; - goto done; + if (ret) + return; + + priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); + priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); + priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); + priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); + priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); + priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); + priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); + priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); + + data[0] = priv->mstats.fwd_drop_rbt; + data[1] = priv->mstats.fwd_drop_ttl; + data[2] = priv->mstats.fwd_drop_noroute; + data[3] = priv->mstats.fwd_drop_nobuf; + data[4] = priv->mstats.fwd_unicast_cnt; + data[5] = priv->mstats.fwd_bcast_cnt; + data[6] = priv->mstats.drop_blind; + data[7] = priv->mstats.tx_failed_cnt; + + lbs_deb_enter(LBS_DEB_ETHTOOL); +} + +static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return MESH_STATS_NUM; + default: + return -EOPNOTSUPP; } - - priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); - priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); - priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); - priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); - priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); - priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); - priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); - priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); - - ret = MESH_STATS_NUM; - -done: - lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret); - return ret; } static void libertas_ethtool_get_strings (struct net_device * dev, @@ -185,7 +177,7 @@ struct ethtool_ops libertas_ethtool_ops = { .get_drvinfo = libertas_ethtool_get_drvinfo, .get_eeprom = libertas_ethtool_get_eeprom, .get_eeprom_len = libertas_ethtool_get_eeprom_len, - .get_stats_count = libertas_ethtool_get_stats_count, + .get_sset_count = libertas_ethtool_get_sset_count, .get_ethtool_stats = libertas_ethtool_get_stats, .get_strings = libertas_ethtool_get_strings, }; From bd684e43d6290d40876230a68a0a6481dc24950a Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Fri, 14 Sep 2007 07:28:50 -0400 Subject: [PATCH 1428/2804] S2io: Change kmalloc+memset to k[zc]alloc - Changed kmalloc+memset to k[zc]alloc as per Mariusz's patch Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 7f6b0e611e3b..75102fb69519 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -561,7 +561,7 @@ static int init_shared_mem(struct s2io_nic *nic) for (i = 0; i < config->tx_fifo_num; i++) { int fifo_len = config->tx_cfg[i].fifo_len; int list_holder_size = fifo_len * sizeof(struct list_info_hold); - mac_control->fifos[i].list_info = kmalloc(list_holder_size, + mac_control->fifos[i].list_info = kzalloc(list_holder_size, GFP_KERNEL); if (!mac_control->fifos[i].list_info) { DBG_PRINT(INFO_DBG, @@ -569,7 +569,6 @@ static int init_shared_mem(struct s2io_nic *nic) return -ENOMEM; } mem_allocated += list_holder_size; - memset(mac_control->fifos[i].list_info, 0, list_holder_size); } for (i = 0; i < config->tx_fifo_num; i++) { int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, @@ -3661,9 +3660,9 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; - nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), + nic->entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct msix_entry), GFP_KERNEL); - if (nic->entries == NULL) { + if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ __FUNCTION__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; @@ -3671,12 +3670,11 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) } nic->mac_control.stats_info->sw_stat.mem_allocated += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); - memset(nic->entries, 0,MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); nic->s2io_entries = - kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), + kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry), GFP_KERNEL); - if (nic->s2io_entries == NULL) { + if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; @@ -3687,8 +3685,6 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) } nic->mac_control.stats_info->sw_stat.mem_allocated += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); - memset(nic->s2io_entries, 0, - MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); for (i=0; i< MAX_REQUESTED_MSI_X; i++) { nic->entries[i].entry = i; From 8a4bdbaa93c2df4cfac2174ba536cd586014787d Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Tue, 18 Sep 2007 18:14:20 -0400 Subject: [PATCH 1429/2804] S2io: Removed unused feature - bimodal interrupts Removed bimodal interrupt support - unused feature Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik [also, trim trailing whitespace] --- drivers/net/s2io.c | 236 +++++++++++++++++---------------------------- drivers/net/s2io.h | 1 - 2 files changed, 90 insertions(+), 147 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 75102fb69519..3885f6b83cc3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.2" +#define DRV_VERSION "2.0.26.4" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -452,7 +452,6 @@ S2IO_PARM_INT(mc_pause_threshold_q4q7, 187); S2IO_PARM_INT(shared_splits, 0); S2IO_PARM_INT(tmac_util_period, 5); S2IO_PARM_INT(rmac_util_period, 5); -S2IO_PARM_INT(bimodal, 0); S2IO_PARM_INT(l3l4hdr_size, 128); /* Frequency of Rx desc syncs expressed as power of 2 */ S2IO_PARM_INT(rxsync_frequency, 3); @@ -699,7 +698,7 @@ static int init_shared_mem(struct s2io_nic *nic) GFP_KERNEL); if (!rx_blocks->rxds) return -ENOMEM; - mem_allocated += + mem_allocated += (sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); for (l=0; lrxd_mode];l++) { rx_blocks->rxds[l].virt_addr = @@ -761,7 +760,7 @@ static int init_shared_mem(struct s2io_nic *nic) (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL); if (!ba->ba_0_org) return -ENOMEM; - mem_allocated += + mem_allocated += (BUF0_LEN + ALIGN_SIZE); tmp = (unsigned long)ba->ba_0_org; tmp += ALIGN_SIZE; @@ -772,7 +771,7 @@ static int init_shared_mem(struct s2io_nic *nic) (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL); if (!ba->ba_1_org) return -ENOMEM; - mem_allocated + mem_allocated += (BUF1_LEN + ALIGN_SIZE); tmp = (unsigned long) ba->ba_1_org; tmp += ALIGN_SIZE; @@ -857,7 +856,7 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->fifos[i]. list_info[mem_blks]. list_phy_addr); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += PAGE_SIZE; } /* If we got a zero DMA address during allocation, @@ -872,11 +871,11 @@ 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 + nic->mac_control.stats_info->sw_stat.mem_freed += PAGE_SIZE; } kfree(mac_control->fifos[i].list_info); - nic->mac_control.stats_info->sw_stat.mem_freed += + nic->mac_control.stats_info->sw_stat.mem_freed += (nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold)); } @@ -894,7 +893,7 @@ static void free_shared_mem(struct s2io_nic *nic) 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); - nic->mac_control.stats_info->sw_stat.mem_freed += + nic->mac_control.stats_info->sw_stat.mem_freed += ( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); } } @@ -925,7 +924,7 @@ static void free_shared_mem(struct s2io_nic *nic) (rxd_count[nic->rxd_mode] + 1)); } kfree(mac_control->rings[i].ba); - nic->mac_control.stats_info->sw_stat.mem_freed += + nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd *) * blk_cnt); } } @@ -935,12 +934,12 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->stats_mem_sz, mac_control->stats_mem, mac_control->stats_mem_phy); - nic->mac_control.stats_info->sw_stat.mem_freed += + nic->mac_control.stats_info->sw_stat.mem_freed += mac_control->stats_mem_sz; } if (nic->ufo_in_band_v) { kfree(nic->ufo_in_band_v); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += (ufo_size * sizeof(u64)); } } @@ -1485,7 +1484,7 @@ static int init_nic(struct s2io_nic *nic) &bar0->rts_frm_len_n[i]); } } - + /* Disable differentiated services steering logic */ for (i = 0; i < 64; i++) { if (rts_ds_steer(nic, i, 0) == FAILURE) { @@ -1565,90 +1564,57 @@ static int init_nic(struct s2io_nic *nic) time++; } - if (nic->config.bimodal) { - int k = 0; - for (k = 0; k < config->rx_ring_num; k++) { - val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; - val64 |= TTI_CMD_MEM_OFFSET(0x38+k); - writeq(val64, &bar0->tti_command_mem); + /* RTI Initialization */ + if (nic->device_type == XFRAME_II_DEVICE) { + /* + * Programmed to generate Apprx 500 Intrs per + * second + */ + int count = (nic->config.bus_speed * 125)/4; + val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count); + } 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; + + 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)); + else + 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); + writeq(val64, &bar0->rti_command_mem); /* - * Once the operation completes, the Strobe bit of the command - * register will be reset. We poll for this particular condition - * We wait for a maximum of 500ms for the operation to complete, - * if it's not complete by then we return error. - */ - time = 0; - while (TRUE) { - val64 = readq(&bar0->tti_command_mem); - if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) { - break; - } - if (time > 10) { - DBG_PRINT(ERR_DBG, - "%s: TTI init Failed\n", - dev->name); - return -1; - } - time++; - msleep(50); - } - } - } else { - - /* RTI Initialization */ - if (nic->device_type == XFRAME_II_DEVICE) { - /* - * Programmed to generate Apprx 500 Intrs per - * second - */ - int count = (nic->config.bus_speed * 125)/4; - val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count); - } 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; - - 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)); - else - 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); - writeq(val64, &bar0->rti_command_mem); - - /* - * Once the operation completes, the Strobe bit of the - * command register will be reset. We poll for this - * particular condition. We wait for a maximum of 500ms - * for the operation to complete, if it's not complete - * by then we return error. - */ - time = 0; - while (TRUE) { - val64 = readq(&bar0->rti_command_mem); - if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) { - break; - } - if (time > 10) { - DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", - dev->name); - return -1; - } - time++; - msleep(50); + * Once the operation completes, the Strobe bit of the + * command register will be reset. We poll for this + * particular condition. We wait for a maximum of 500ms + * for the operation to complete, if it's not complete + * by then we return error. + */ + time = 0; + while (TRUE) { + val64 = readq(&bar0->rti_command_mem); + if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) + break; + + if (time > 10) { + DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", + dev->name); + return -1; } + time++; + msleep(50); } } @@ -2005,7 +1971,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag) int ret = 0, herc; struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = readq(&bar0->adapter_status); - + herc = (sp->device_type == XFRAME_II_DEVICE); if (flag == FALSE) { @@ -2151,8 +2117,6 @@ static int start_nic(struct s2io_nic *nic) &bar0->prc_rxd0_n[i]); val64 = readq(&bar0->prc_ctrl_n[i]); - if (nic->config.bimodal) - val64 |= PRC_CTRL_BIMODAL_INTERRUPT; if (nic->rxd_mode == RXD_MODE_1) val64 |= PRC_CTRL_RC_ENABLED; else @@ -2312,7 +2276,7 @@ static void free_tx_buffers(struct s2io_nic *nic) mac_control->fifos[i].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 + nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; dev_kfree_skb(skb); cnt++; @@ -2477,7 +2441,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) mem_alloc_fail_cnt++; return -ENOMEM ; } - nic->mac_control.stats_info->sw_stat.mem_allocated + nic->mac_control.stats_info->sw_stat.mem_allocated += skb->truesize; if (nic->rxd_mode == RXD_MODE_1) { /* 1 buffer mode - normal operation mode */ @@ -2492,7 +2456,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) DMA_ERROR_CODE)) goto pci_map_failed; - rxdp->Control_2 = + rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); } else if (nic->rxd_mode == RXD_MODE_3B) { @@ -3406,7 +3370,7 @@ 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; @@ -3668,22 +3632,22 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated + nic->mac_control.stats_info->sw_stat.mem_allocated += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); nic->s2io_entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry), GFP_KERNEL); if (!nic->s2io_entries) { - DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", + DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; kfree(nic->entries); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated + nic->mac_control.stats_info->sw_stat.mem_allocated += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); for (i=0; i< MAX_REQUESTED_MSI_X; i++) { @@ -3702,27 +3666,15 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) } writeq(tx_mat, &bar0->tx_mat0_n[0]); - if (!nic->config.bimodal) { - rx_mat = readq(&bar0->rx_mat); - for (j=0; jconfig.rx_ring_num; j++, msix_indx++) { - rx_mat |= RX_MAT_SET(j, msix_indx); - nic->s2io_entries[msix_indx].arg - = &nic->mac_control.rings[j]; - nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; - nic->s2io_entries[msix_indx].in_use = MSIX_FLG; - } - writeq(rx_mat, &bar0->rx_mat); - } else { - tx_mat = readq(&bar0->tx_mat0_n[7]); - for (j=0; jconfig.rx_ring_num; j++, msix_indx++) { - tx_mat |= TX_MAT_SET(i, msix_indx); - nic->s2io_entries[msix_indx].arg - = &nic->mac_control.rings[j]; - nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; - nic->s2io_entries[msix_indx].in_use = MSIX_FLG; - } - writeq(tx_mat, &bar0->tx_mat0_n[7]); + rx_mat = readq(&bar0->rx_mat); + for (j = 0; j < nic->config.rx_ring_num; j++, msix_indx++) { + rx_mat |= RX_MAT_SET(j, msix_indx); + nic->s2io_entries[msix_indx].arg + = &nic->mac_control.rings[j]; + nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; } + writeq(rx_mat, &bar0->rx_mat); nic->avail_msix_vectors = 0; ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X); @@ -3734,10 +3686,10 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) if (ret) { DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name); kfree(nic->entries); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); kfree(nic->s2io_entries); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); nic->entries = NULL; nic->s2io_entries = NULL; @@ -3906,12 +3858,12 @@ 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->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); } if (sp->s2io_entries) { kfree(sp->s2io_entries); - sp->mac_control.stats_info->sw_stat.mem_freed + sp->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); } } @@ -4676,7 +4628,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) if (cnt == 5) break; /* Updt failed */ } while(1); - } + } } /** @@ -5165,13 +5117,13 @@ static void s2io_ethtool_gringparam(struct net_device *dev, ering->rx_max_pending = MAX_RX_DESC_2; ering->tx_max_pending = MAX_TX_DESC; - for (i = 0 ; i < sp->config.tx_fifo_num ; i++) + 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); ering->tx_pending = tx_desc_count; rx_desc_count = 0; - for (i = 0 ; i < sp->config.rx_ring_num ; i++) + for (i = 0 ; i < sp->config.rx_ring_num ; i++) rx_desc_count += sp->config.rx_cfg[i].num_rxd; ering->rx_pending = rx_desc_count; @@ -6539,7 +6491,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, mem_alloc_fail_cnt++; return -ENOMEM ; } - sp->mac_control.stats_info->sw_stat.mem_allocated + sp->mac_control.stats_info->sw_stat.mem_allocated += (*skb)->truesize; /* storing the mapped addr in a temp variable * such it will be used for next rxd whose @@ -6572,7 +6524,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, mem_alloc_fail_cnt++; return -ENOMEM; } - sp->mac_control.stats_info->sw_stat.mem_allocated + sp->mac_control.stats_info->sw_stat.mem_allocated += (*skb)->truesize; rxdp3->Buffer2_ptr = *temp2 = pci_map_single(sp->pdev, (*skb)->data, @@ -7107,7 +7059,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); sp->stats.rx_crc_errors++; - sp->mac_control.stats_info->sw_stat.mem_freed + sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; dev_kfree_skb(skb); atomic_dec(&sp->rx_bufs_left[ring_no]); @@ -7261,13 +7213,13 @@ static void s2io_link(struct s2io_nic * sp, int link) DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name); 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 = + 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 = + 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); @@ -7752,14 +7704,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Initialize device name */ sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); - /* Initialize bimodal Interrupts */ - sp->config.bimodal = bimodal; - if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) { - sp->config.bimodal = 0; - DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n", - dev->name); - } - /* * Make Link state as off at this point, when the Link change * interrupt comes the state will be automatically changed to diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 1a70cf02c915..9b645f406399 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -444,7 +444,6 @@ struct config_param { #define MAX_RX_BLOCKS_PER_RING 150 struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */ - u8 bimodal; /*Flag for setting bimodal interrupts*/ #define HEADER_ETHERNET_II_802_3_SIZE 14 #define HEADER_802_2_SIZE 3 From 2fd37688455857b7b92bc2b1379a4c48aa9af147 Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Fri, 14 Sep 2007 07:39:19 -0400 Subject: [PATCH 1430/2804] S2io: Added support set_mac_address driver entry point - Added set_mac_address driver entry point - Copying permanent mac address to dev->perm_addr - Incorporated following review comments from Jeff - Converted the macro to a function and removed call to memset - regarding function naming convention, for all callbacks and entry points will have 's2io_' prefix and helper functions will have 'do_s2io_' prefix. Signed-off-by: Sreenivasa Honnur Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 107 ++++++++++++++++++++++++++++----------------- drivers/net/s2io.h | 2 +- 2 files changed, 68 insertions(+), 41 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 3885f6b83cc3..01e4b1c26a36 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -355,6 +355,16 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { 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) +{ + sp->def_mac_addr[offset].mac_addr[5] = (u8) (mac_addr); + sp->def_mac_addr[offset].mac_addr[4] = (u8) (mac_addr >> 8); + sp->def_mac_addr[offset].mac_addr[3] = (u8) (mac_addr >> 16); + sp->def_mac_addr[offset].mac_addr[2] = (u8) (mac_addr >> 24); + sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32); + sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40); +} /* Add the vlan */ static void s2io_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) @@ -3412,7 +3422,7 @@ static void s2io_reset(struct s2io_nic * sp) } /* restore the previously assigned mac address */ - s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr); + do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr); sp->device_enabled_once = FALSE; } @@ -3843,7 +3853,7 @@ static int s2io_open(struct net_device *dev) goto hw_init_failed; } - if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { + if (do_s2io_prog_unicast(dev, dev->dev_addr) == FAILURE) { DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n"); s2io_card_down(sp); err = -ENODEV; @@ -4845,8 +4855,48 @@ static void s2io_set_multicast(struct net_device *dev) } } +/* add unicast MAC address to CAM */ +static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off) +{ + u64 val64; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + + writeq(RMAC_ADDR_DATA0_MEM_ADDR(addr), + &bar0->rmac_addr_data0_mem); + + 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)) { + DBG_PRINT(INFO_DBG, "add_mac_addr failed\n"); + return FAILURE; + } + return SUCCESS; +} + /** - * s2io_set_mac_addr - Programs the Xframe mac address + * s2io_set_mac_addr driver entry point + */ +static int s2io_set_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + 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)); +} + +/** + * do_s2io_prog_unicast - Programs the Xframe mac address * @dev : pointer to the device structure. * @addr: a uchar pointer to the new mac address which is to be set. * Description : This procedure will program the Xframe to receive @@ -4854,56 +4904,31 @@ static void s2io_set_multicast(struct net_device *dev) * Return value: SUCCESS on success and an appropriate (-)ve integer * as defined in errno.h file on failure. */ - -static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) +static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) { struct s2io_nic *sp = dev->priv; - struct XENA_dev_config __iomem *bar0 = sp->bar0; - register u64 val64, mac_addr = 0; + register u64 mac_addr = 0, perm_addr = 0; int i; - u64 old_mac_addr = 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. - */ + * 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]; - old_mac_addr <<= 8; - old_mac_addr |= sp->def_mac_addr[0].mac_addr[i]; + perm_addr <<= 8; + perm_addr |= sp->def_mac_addr[0].mac_addr[i]; } - if(0 == mac_addr) + /* check if the dev_addr is different than perm_addr */ + if (mac_addr == perm_addr) return SUCCESS; /* Update the internal structure with this new mac address */ - if(mac_addr != old_mac_addr) { - memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN)); - sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr); - sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8); - sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16); - sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24); - sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32); - sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40); - } - - writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr), - &bar0->rmac_addr_data0_mem); - - val64 = - RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(0); - 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)) { - DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name); - return FAILURE; - } - - return SUCCESS; + do_s2io_copy_mac_addr(sp, 0, mac_addr); + return (do_s2io_add_unicast(sp, mac_addr, 0)); } /** @@ -7530,6 +7555,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->get_stats = &s2io_get_stats; dev->set_multicast_list = &s2io_set_multicast; dev->do_ioctl = &s2io_ioctl; + dev->set_mac_address = &s2io_set_mac_addr; dev->change_mtu = &s2io_change_mtu; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; @@ -7615,6 +7641,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Set the factory defined MAC address initially */ dev->addr_len = ETH_ALEN; memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); + memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); /* Store the values of the MSIX table in the s2io_nic structure */ store_xmsi_data(sp); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 9b645f406399..f6b45565304f 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -1047,7 +1047,7 @@ static void s2io_link(struct s2io_nic * sp, int link); static void s2io_reset(struct s2io_nic * sp); static int s2io_poll(struct napi_struct *napi, int budget); static void s2io_init_pci(struct s2io_nic * sp); -static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); +static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr); static void s2io_alarm_handle(unsigned long data); static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id); From 1a7eb72b68c1c6a00a237bc242885222ab74536f Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Fri, 14 Sep 2007 07:43:16 -0400 Subject: [PATCH 1431/2804] S2io: Updating transceiver information in ethtool function - Update transceiver information in ethtool function Signed-off-by: Sreenivasa Honnur Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 01e4b1c26a36..203cc1e87de0 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.4" +#define DRV_VERSION "2.0.26.5" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -4976,7 +4976,9 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->port = PORT_FIBRE; - /* info->transceiver?? TODO */ + + /* info->transceiver */ + info->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(sp->dev)) { info->speed = 10000; From 73f83182862a2c9113421720997c75ee939902f8 Mon Sep 17 00:00:00 2001 From: Alex Landau Date: Wed, 19 Sep 2007 23:14:18 +0800 Subject: [PATCH 1432/2804] Blackfin EMAC driver: add function to change the MAC address Alex Landau writes in the forums: Previously, changing the MAC address (e.g. via ifconfig) resulted in a generic function to be called that only changed a variable in memory. This patch also updated the Blackfin MAC address registers to filter the correct new MAC. Signed-off-by: Alex Landau Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Acked-by: Jeff Garzik Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index cebe55440e13..ead7be969975 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -463,7 +463,7 @@ void setup_system_regs(struct net_device *dev) bfin_write_DMA1_Y_MODIFY(0); } -void setup_mac_addr(u8 * mac_addr) +static void setup_mac_addr(u8 *mac_addr) { u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]); u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]); @@ -473,6 +473,16 @@ void setup_mac_addr(u8 * mac_addr) bfin_write_EMAC_ADDRHI(addr_hi); } +static int bf537mac_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + if (netif_running(dev)) + return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + setup_mac_addr(dev->dev_addr); + return 0; +} + static void adjust_tx_list(void) { int timeout_cnt = MAX_TIMEOUT_CNT; @@ -876,6 +886,7 @@ static int __init bf537mac_probe(struct net_device *dev) dev->open = bf537mac_open; dev->stop = bf537mac_close; dev->hard_start_xmit = bf537mac_hard_start_xmit; + dev->set_mac_address = bf537mac_set_mac_address; dev->tx_timeout = bf537mac_timeout; dev->set_multicast_list = bf537mac_set_multicast_list; #ifdef CONFIG_NET_POLL_CONTROLLER From 496a34c2249fecc87ee689eede2bb8510c1b37a9 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 19 Sep 2007 23:37:14 +0800 Subject: [PATCH 1433/2804] Blackfin EMAC driver: add power management interface and change the bf537mac_reset to bf537mac_disable Signed-off-by: Bryan Wu Acked-by: Jeff Garzik Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index ead7be969975..5cb4433d5612 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -672,7 +672,7 @@ static void bf537mac_poll(struct net_device *dev) } #endif /* CONFIG_NET_POLL_CONTROLLER */ -static void bf537mac_reset(void) +static void bf537mac_disable(void) { unsigned int opmode; @@ -730,7 +730,7 @@ static void bf537mac_timeout(struct net_device *dev) { pr_debug("%s: %s\n", dev->name, __FUNCTION__); - bf537mac_reset(); + bf537mac_disable(); /* reset tx queue */ tx_list_tail = tx_list_head->next; @@ -810,7 +810,7 @@ static int bf537mac_open(struct net_device *dev) bf537mac_setphy(dev); setup_system_regs(dev); - bf537mac_reset(); + bf537mac_disable(); bf537mac_enable(dev); pr_debug("hardware init finished\n"); @@ -968,15 +968,30 @@ static int bfin_mac_remove(struct platform_device *pdev) return 0; } -static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM +static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg) { + struct net_device *net_dev = platform_get_drvdata(pdev); + + if (netif_running(net_dev)) + bf537mac_close(net_dev); + return 0; } static int bfin_mac_resume(struct platform_device *pdev) { + struct net_device *net_dev = platform_get_drvdata(pdev); + + if (netif_running(net_dev)) + bf537mac_open(net_dev); + return 0; } +#else +#define bfin_mac_suspend NULL +#define bfin_mac_resume NULL +#endif /* CONFIG_PM */ static struct platform_driver bfin_mac_driver = { .probe = bfin_mac_probe, From 4ae5a3ad5aa35972863f9c656ebd35446fbb5192 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 19 Sep 2007 23:37:36 +0800 Subject: [PATCH 1434/2804] Blackfin EMAC driver: Add phy abstraction layer supporting in bfin_emac driver - add MDIO functions and register mdio bus - add phy abstraction layer (PAL) functions and use PAL API - test on STAMP537 board Signed-off-by: Bryan Wu Acked-by: Jeff Garzik Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 321 ++++++++++++++++++++++++----------------- drivers/net/bfin_mac.h | 53 ++----- 2 files changed, 201 insertions(+), 173 deletions(-) diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 5cb4433d5612..53fe7ded5d50 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,9 @@ static struct net_dma_desc_tx *current_tx_ptr; static struct net_dma_desc_tx *tx_desc; static struct net_dma_desc_rx *rx_desc; +static void bf537mac_disable(void); +static void bf537mac_enable(void); + static void desc_list_free(void) { struct net_dma_desc_rx *r; @@ -282,8 +286,11 @@ static int setup_pin_mux(int action) return 0; } +/* + * MII operations + */ /* Wait until the previous MDC/MDIO transaction has completed */ -static void poll_mdc_done(void) +static void mdio_poll(void) { int timeout_cnt = MAX_TIMEOUT_CNT; @@ -299,154 +306,201 @@ static void poll_mdc_done(void) } /* Read an off-chip register in a PHY through the MDC/MDIO port */ -static u16 read_phy_reg(u16 PHYAddr, u16 RegAddr) +static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) { - poll_mdc_done(); - /* read mode */ - bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) | - SET_REGAD(RegAddr) | - STABUSY); - poll_mdc_done(); + mdio_poll(); - return (u16) bfin_read_EMAC_STADAT(); + /* read mode */ + bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) | + SET_REGAD((u16) regnum) | + STABUSY); + + mdio_poll(); + + return (int) bfin_read_EMAC_STADAT(); } /* Write an off-chip register in a PHY through the MDC/MDIO port */ -static void raw_write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data) +static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, + u16 value) { - bfin_write_EMAC_STADAT(Data); + mdio_poll(); + + bfin_write_EMAC_STADAT((u32) value); /* write mode */ - bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) | - SET_REGAD(RegAddr) | + bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) | + SET_REGAD((u16) regnum) | STAOP | STABUSY); - poll_mdc_done(); + mdio_poll(); + + return 0; } -static void write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data) +static int mdiobus_reset(struct mii_bus *bus) { - poll_mdc_done(); - raw_write_phy_reg(PHYAddr, RegAddr, Data); + return 0; } -/* set up the phy */ -static void bf537mac_setphy(struct net_device *dev) +static void bf537_adjust_link(struct net_device *dev) { - u16 phydat; struct bf537mac_local *lp = netdev_priv(dev); + struct phy_device *phydev = lp->phydev; + unsigned long flags; + int new_state = 0; - /* Program PHY registers */ - pr_debug("start setting up phy\n"); + spin_lock_irqsave(&lp->lock, flags); + if (phydev->link) { + /* Now we make sure that we can be in full duplex mode. + * If not, we operate in half-duplex mode. */ + if (phydev->duplex != lp->old_duplex) { + u32 opmode = bfin_read_EMAC_OPMODE(); + new_state = 1; - /* issue a reset */ - raw_write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, 0x8000); + if (phydev->duplex) + opmode |= FDMODE; + else + opmode &= ~(FDMODE); - /* wait half a second */ - msleep(500); + bfin_write_EMAC_OPMODE(opmode); + lp->old_duplex = phydev->duplex; + } - phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL); + if (phydev->speed != lp->old_speed) { +#if defined(CONFIG_BFIN_MAC_RMII) + u32 opmode = bfin_read_EMAC_OPMODE(); + bf537mac_disable(); + switch (phydev->speed) { + case 10: + opmode |= RMII_10; + break; + case 100: + opmode &= ~(RMII_10); + break; + default: + printk(KERN_WARNING + "%s: Ack! Speed (%d) is not 10/100!\n", + DRV_NAME, phydev->speed); + break; + } + bfin_write_EMAC_OPMODE(opmode); + bf537mac_enable(); +#endif - /* advertise flow control supported */ - phydat = read_phy_reg(lp->PhyAddr, PHYREG_ANAR); - phydat |= (1 << 10); - write_phy_reg(lp->PhyAddr, PHYREG_ANAR, phydat); + new_state = 1; + lp->old_speed = phydev->speed; + } - phydat = 0; - if (lp->Negotiate) - phydat |= 0x1000; /* enable auto negotiation */ - else { - if (lp->FullDuplex) - phydat |= (1 << 8); /* full duplex */ - else - phydat &= (~(1 << 8)); /* half duplex */ - - if (!lp->Port10) - phydat |= (1 << 13); /* 100 Mbps */ - else - phydat &= (~(1 << 13)); /* 10 Mbps */ + if (!lp->old_link) { + new_state = 1; + lp->old_link = 1; + netif_schedule(dev); + } + } else if (lp->old_link) { + new_state = 1; + lp->old_link = 0; + lp->old_speed = 0; + lp->old_duplex = -1; } - if (lp->Loopback) - phydat |= (1 << 14); /* enable TX->RX loopback */ - - write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, phydat); - msleep(500); - - phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL); - /* check for SMSC PHY */ - if ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID1) == 0x7) && - ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID2) & 0xfff0) == 0xC0A0)) { - /* - * we have SMSC PHY so reqest interrupt - * on link down condition - */ - - /* enable interrupts */ - write_phy_reg(lp->PhyAddr, 30, 0x0ff); + if (new_state) { + u32 opmode = bfin_read_EMAC_OPMODE(); + phy_print_status(phydev); + pr_debug("EMAC_OPMODE = 0x%08x\n", opmode); } + + spin_unlock_irqrestore(&lp->lock, flags); +} + +static int mii_probe(struct net_device *dev) +{ + struct bf537mac_local *lp = netdev_priv(dev); + struct phy_device *phydev = NULL; + unsigned short sysctl; + int i; + + /* Enable PHY output early */ + if (!(bfin_read_VR_CTL() & PHYCLKOE)) + bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE); + + /* MDC = 2.5 MHz */ + sysctl = bfin_read_EMAC_SYSCTL(); + sysctl |= SET_MDCDIV(24); + bfin_write_EMAC_SYSCTL(sysctl); + + /* search for connect PHY device */ + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i]; + + if (!tmp_phydev) + continue; /* no PHY here... */ + + phydev = tmp_phydev; + break; /* found it */ + } + + /* now we are supposed to have a proper phydev, to attach to... */ + if (!phydev) { + printk(KERN_INFO "%s: Don't found any phy device at all\n", + dev->name); + return -ENODEV; + } + +#if defined(CONFIG_BFIN_MAC_RMII) + phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0, + PHY_INTERFACE_MODE_RMII); +#else + phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0, + PHY_INTERFACE_MODE_MII); +#endif + + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + /* mask with MAC supported features */ + phydev->supported &= (SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_Autoneg + | SUPPORTED_Pause | SUPPORTED_Asym_Pause + | SUPPORTED_MII + | SUPPORTED_TP); + + phydev->advertising = phydev->supported; + + lp->old_link = 0; + lp->old_speed = 0; + lp->old_duplex = -1; + lp->phydev = phydev; + + printk(KERN_INFO "%s: attached PHY driver [%s] " + "(mii_bus:phy_addr=%s, irq=%d)\n", + DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq); + + return 0; } /**************************************************************************/ void setup_system_regs(struct net_device *dev) { - int phyaddr; - unsigned short sysctl, phydat; - u32 opmode; - struct bf537mac_local *lp = netdev_priv(dev); - int count = 0; + unsigned short sysctl; - phyaddr = lp->PhyAddr; - - /* Enable PHY output */ - if (!(bfin_read_VR_CTL() & PHYCLKOE)) - bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE); - - /* MDC = 2.5 MHz */ - sysctl = SET_MDCDIV(24); - /* Odd word alignment for Receive Frame DMA word */ - /* Configure checksum support and rcve frame word alignment */ + /* + * Odd word alignment for Receive Frame DMA word + * Configure checksum support and rcve frame word alignment + */ + sysctl = bfin_read_EMAC_SYSCTL(); #if defined(BFIN_MAC_CSUM_OFFLOAD) sysctl |= RXDWA | RXCKS; #else sysctl |= RXDWA; #endif bfin_write_EMAC_SYSCTL(sysctl); - /* auto negotiation on */ - /* full duplex */ - /* 100 Mbps */ - phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET; - write_phy_reg(phyaddr, PHYREG_MODECTL, phydat); - - /* test if full duplex supported */ - do { - msleep(100); - phydat = read_phy_reg(phyaddr, PHYREG_MODESTAT); - if (count > 30) { - printk(KERN_NOTICE DRV_NAME ": Link is down\n"); - printk(KERN_NOTICE DRV_NAME - "please check your network connection\n"); - break; - } - count++; - } while (!(phydat & 0x0004)); - - phydat = read_phy_reg(phyaddr, PHYREG_ANLPAR); - - if ((phydat & 0x0100) || (phydat & 0x0040)) { - opmode = FDMODE; - } else { - opmode = 0; - printk(KERN_INFO DRV_NAME - ": Network is set to half duplex\n"); - } - -#if defined(CONFIG_BFIN_MAC_RMII) - opmode |= RMII; /* For Now only 100MBit are supported */ -#endif - - bfin_write_EMAC_OPMODE(opmode); bfin_write_EMAC_MMC_CTL(RSTC | CROLL); @@ -686,18 +740,18 @@ static void bf537mac_disable(void) /* * Enable Interrupts, Receive, and Transmit */ -static int bf537mac_enable(struct net_device *dev) +static void bf537mac_enable(void) { u32 opmode; - pr_debug("%s: %s\n", dev->name, __FUNCTION__); + pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__); /* Set RX DMA */ bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a)); bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config); /* Wait MII done */ - poll_mdc_done(); + mdio_poll(); /* We enable only RX here */ /* ASTP : Enable Automatic Pad Stripping @@ -721,8 +775,6 @@ static int bf537mac_enable(struct net_device *dev) #endif /* Turn on the EMAC rx */ bfin_write_EMAC_OPMODE(opmode); - - return 0; } /* Our watchdog timed out. Called by the networking layer */ @@ -735,7 +787,7 @@ static void bf537mac_timeout(struct net_device *dev) /* reset tx queue */ tx_list_tail = tx_list_head->next; - bf537mac_enable(dev); + bf537mac_enable(); /* We can accept TX packets again */ dev->trans_start = jiffies; @@ -789,6 +841,7 @@ static void bf537mac_shutdown(struct net_device *dev) */ static int bf537mac_open(struct net_device *dev) { + struct bf537mac_local *lp = netdev_priv(dev); int retval; pr_debug("%s: %s\n", dev->name, __FUNCTION__); @@ -808,10 +861,10 @@ static int bf537mac_open(struct net_device *dev) if (retval) return retval; - bf537mac_setphy(dev); + phy_start(lp->phydev); setup_system_regs(dev); bf537mac_disable(); - bf537mac_enable(dev); + bf537mac_enable(); pr_debug("hardware init finished\n"); netif_start_queue(dev); @@ -828,11 +881,14 @@ static int bf537mac_open(struct net_device *dev) */ static int bf537mac_close(struct net_device *dev) { + struct bf537mac_local *lp = netdev_priv(dev); pr_debug("%s: %s\n", dev->name, __FUNCTION__); netif_stop_queue(dev); netif_carrier_off(dev); + phy_stop(lp->phydev); + /* clear everything */ bf537mac_shutdown(dev); @@ -846,6 +902,7 @@ static int __init bf537mac_probe(struct net_device *dev) { struct bf537mac_local *lp = netdev_priv(dev); int retval; + int i; /* Grab the MAC address in the MAC */ *(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO()); @@ -862,7 +919,6 @@ static int __init bf537mac_probe(struct net_device *dev) /* set the GPIO pins to Ethernet mode */ retval = setup_pin_mux(1); - if (retval) return retval; @@ -880,6 +936,23 @@ static int __init bf537mac_probe(struct net_device *dev) setup_mac_addr(dev->dev_addr); + /* MDIO bus initial */ + lp->mii_bus.priv = dev; + lp->mii_bus.read = mdiobus_read; + lp->mii_bus.write = mdiobus_write; + lp->mii_bus.reset = mdiobus_reset; + lp->mii_bus.name = "bfin_mac_mdio"; + lp->mii_bus.id = 0; + lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + for (i = 0; i < PHY_MAX_ADDR; ++i) + lp->mii_bus.irq[i] = PHY_POLL; + + mdiobus_register(&lp->mii_bus); + + retval = mii_probe(dev); + if (retval) + return retval; + /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); @@ -893,13 +966,6 @@ static int __init bf537mac_probe(struct net_device *dev) dev->poll_controller = bf537mac_poll; #endif - /* fill in some of the fields */ - lp->version = 1; - lp->PhyAddr = 0x01; - lp->CLKIN = 25; - lp->FullDuplex = 0; - lp->Negotiate = 1; - lp->FlowControl = 0; spin_lock_init(&lp->lock); /* now, enable interrupts */ @@ -912,9 +978,6 @@ static int __init bf537mac_probe(struct net_device *dev) return -EBUSY; } - /* Enable PHY output early */ - if (!(bfin_read_VR_CTL() & PHYCLKOE)) - bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE); retval = register_netdev(dev); if (retval == 0) { diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h index b82724692283..3a107ad75381 100644 --- a/drivers/net/bfin_mac.h +++ b/drivers/net/bfin_mac.h @@ -31,32 +31,6 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* - * PHY REGISTER NAMES - */ -#define PHYREG_MODECTL 0x0000 -#define PHYREG_MODESTAT 0x0001 -#define PHYREG_PHYID1 0x0002 -#define PHYREG_PHYID2 0x0003 -#define PHYREG_ANAR 0x0004 -#define PHYREG_ANLPAR 0x0005 -#define PHYREG_ANER 0x0006 -#define PHYREG_NSR 0x0010 -#define PHYREG_LBREMR 0x0011 -#define PHYREG_REC 0x0012 -#define PHYREG_10CFG 0x0013 -#define PHYREG_PHY1_1 0x0014 -#define PHYREG_PHY1_2 0x0015 -#define PHYREG_PHY2 0x0016 -#define PHYREG_TW_1 0x0017 -#define PHYREG_TW_2 0x0018 -#define PHYREG_TEST 0x0019 - -#define PHY_RESET 0x8000 -#define PHY_ANEG_EN 0x1000 -#define PHY_DUPLEX 0x0100 -#define PHY_SPD_SET 0x2000 - #define BFIN_MAC_CSUM_OFFLOAD struct dma_descriptor { @@ -104,27 +78,18 @@ struct bf537mac_local { * can find out semi-useless statistics of how well the card is * performing */ - int version; + struct net_device_stats stats; - int FlowEnabled; /* record if data flow is active */ - int EtherIntIVG; /* IVG for the ethernet interrupt */ - int RXIVG; /* IVG for the RX completion */ - int TXIVG; /* IVG for the TX completion */ - int PhyAddr; /* PHY address */ - int OpMode; /* set these bits n the OPMODE regs */ - int Port10; /* set port speed to 10 Mbit/s */ - int GenChksums; /* IP checksums to be calculated */ - int NoRcveLnth; /* dont insert recv length at start of buffer */ - int StripPads; /* remove trailing pad bytes */ - int FullDuplex; /* set full duplex mode */ - int Negotiate; /* enable auto negotiation */ - int Loopback; /* loopback at the PHY */ - int Cache; /* Buffers may be cached */ - int FlowControl; /* flow control active */ - int CLKIN; /* clock in value in MHZ */ - unsigned short IntMask; /* interrupt mask */ unsigned char Mac[6]; /* MAC address of the board */ spinlock_t lock; + + /* MII and PHY stuffs */ + int old_link; /* used by bf537_adjust_link */ + int old_speed; + int old_duplex; + + struct phy_device *phydev; + struct mii_bus mii_bus; }; extern void get_bf537_ether_addr(char *addr); From eeb70af91d3f38ba429d3c8e0519b3c1ff8a0955 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 19 Sep 2007 23:37:41 +0800 Subject: [PATCH 1435/2804] Blackfin EMAC driver: add a select for the PHYLIB of this driver Since we are adding requirement for the PHYLIB for this driver, there should be a select for that Cc: Robin Getz Signed-off-by: Bryan Wu Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 83b3f7b8fb73..9dc4a80a6acd 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -838,6 +838,8 @@ config BFIN_MAC tristate "Blackfin 536/537 on-chip mac support" depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H) select CRC32 + select MII + select PHYLIB select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE help This is the driver for blackfin on-chip mac device. Say Y if you want it From 03233b90b0977d577322a6e1ddd56d9cc570d406 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:31:17 +0100 Subject: [PATCH 1436/2804] 8139cp: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index d437823c2c5e..abb2a3471087 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -303,25 +303,25 @@ static const unsigned int cp_rx_config = (RX_DMA_BURST << RxCfgDMAShift); struct cp_desc { - u32 opts1; + __le32 opts1; u32 opts2; - u64 addr; + __le64 addr; }; struct cp_dma_stats { - u64 tx_ok; - u64 rx_ok; - u64 tx_err; - u32 rx_err; - u16 rx_fifo; - u16 frame_align; - u32 tx_ok_1col; - u32 tx_ok_mcol; - u64 rx_ok_phys; - u64 rx_ok_bcast; - u32 rx_ok_mcast; - u16 tx_abort; - u16 tx_underrun; + __le64 tx_ok; + __le64 rx_ok; + __le64 tx_err; + __le32 rx_err; + __le16 rx_fifo; + __le16 frame_align; + __le32 tx_ok_1col; + __le32 tx_ok_mcol; + __le64 rx_ok_phys; + __le64 rx_ok_bcast; + __le32 rx_ok_mcast; + __le16 tx_abort; + __le16 tx_underrun; } __attribute__((packed)); struct cp_extra_stats { @@ -1018,8 +1018,8 @@ static void cp_init_hw (struct cp_private *cp) cpw8_f (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ - cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); - cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); + cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0))); + cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4))); cp_start_hw(cp); cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ @@ -1930,8 +1930,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) /* read MAC address from EEPROM */ addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) - ((u16 *) (dev->dev_addr))[i] = - le16_to_cpu (read_eeprom (regs, i + 7, addr_len)); + ((__le16 *) (dev->dev_addr))[i] = + cpu_to_le16(read_eeprom (regs, i + 7, addr_len)); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = cp_open; From 1d3bb996481e116f5f2b127cbd29b83365d2cf62 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 23 Aug 2007 13:56:01 +1000 Subject: [PATCH 1437/2804] Device tree aware EMAC driver Based on BenH's earlier work, this is a new version of the EMAC driver for the built-in ethernet found on PowerPC 4xx embedded CPUs. The same ASIC is also found in the Axon bridge chip. This new version is designed to work in the arch/powerpc tree, using the device tree to probe the device, rather than the old and ugly arch/ppc OCP layer. This driver is designed to sit alongside the old driver (that lies in drivers/net/ibm_emac and this one in drivers/net/ibm_newemac). The old driver is left in place to support arch/ppc until arch/ppc itself reaches its final demise (not too long now, with luck). This driver still has a number of things that could do with cleaning up, but I think they can be fixed up after merging. Specifically: - Should be adjusted to properly use the dma mapping API. Axon needs this. - Probe logic needs reworking, in conjuction with the general probing code for of_platform devices. The dependencies here between EMAC, MAL, ZMII etc. make this complicated. At present, it usually works, because we initialize and register the sub-drivers before the EMAC driver itself, and (being in driver code) runs after the devices themselves have been instantiated from the device tree. Signed-off-by: David Gibson Signed-off-by: Jeff Garzik --- Documentation/powerpc/booting-without-of.txt | 156 + arch/powerpc/platforms/44x/Kconfig | 3 +- arch/powerpc/platforms/cell/Kconfig | 4 + drivers/net/Kconfig | 71 +- drivers/net/Makefile | 1 + drivers/net/ibm_emac/Kconfig | 70 + drivers/net/ibm_newemac/Kconfig | 63 + drivers/net/ibm_newemac/Makefile | 11 + drivers/net/ibm_newemac/core.c | 2907 ++++++++++++++++++ drivers/net/ibm_newemac/core.h | 355 +++ drivers/net/ibm_newemac/debug.c | 238 ++ drivers/net/ibm_newemac/debug.h | 78 + drivers/net/ibm_newemac/emac.h | 268 ++ drivers/net/ibm_newemac/mal.c | 728 +++++ drivers/net/ibm_newemac/mal.h | 276 ++ drivers/net/ibm_newemac/phy.c | 373 +++ drivers/net/ibm_newemac/phy.h | 80 + drivers/net/ibm_newemac/rgmii.c | 323 ++ drivers/net/ibm_newemac/rgmii.h | 76 + drivers/net/ibm_newemac/tah.c | 173 ++ drivers/net/ibm_newemac/tah.h | 90 + drivers/net/ibm_newemac/zmii.c | 322 ++ drivers/net/ibm_newemac/zmii.h | 73 + 23 files changed, 6668 insertions(+), 71 deletions(-) create mode 100644 drivers/net/ibm_emac/Kconfig create mode 100644 drivers/net/ibm_newemac/Kconfig create mode 100644 drivers/net/ibm_newemac/Makefile create mode 100644 drivers/net/ibm_newemac/core.c create mode 100644 drivers/net/ibm_newemac/core.h create mode 100644 drivers/net/ibm_newemac/debug.c create mode 100644 drivers/net/ibm_newemac/debug.h create mode 100644 drivers/net/ibm_newemac/emac.h create mode 100644 drivers/net/ibm_newemac/mal.c create mode 100644 drivers/net/ibm_newemac/mal.h create mode 100644 drivers/net/ibm_newemac/phy.c create mode 100644 drivers/net/ibm_newemac/phy.h create mode 100644 drivers/net/ibm_newemac/rgmii.c create mode 100644 drivers/net/ibm_newemac/rgmii.h create mode 100644 drivers/net/ibm_newemac/tah.c create mode 100644 drivers/net/ibm_newemac/tah.h create mode 100644 drivers/net/ibm_newemac/zmii.c create mode 100644 drivers/net/ibm_newemac/zmii.h diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 76733a3962f0..838fd323e797 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1824,6 +1824,162 @@ platforms are moved over to use the flattened-device-tree model. fsl,has-rstcr; }; + + h) 4xx/Axon EMAC ethernet nodes + + The EMAC ethernet controller in IBM and AMCC 4xx chips, and also + the Axon bridge. To operate this needs to interact with a ths + special McMAL DMA controller, and sometimes an RGMII or ZMII + interface. In addition to the nodes and properties described + below, the node for the OPB bus on which the EMAC sits must have a + correct clock-frequency property. + + i) The EMAC node itself + + Required properties: + - device_type : "network" + + - compatible : compatible list, contains 2 entries, first is + "ibm,emac-CHIP" where CHIP is the host ASIC (440gx, + 405gp, Axon) and second is either "ibm,emac" or + "ibm,emac4". For Axon, thus, we have: "ibm,emac-axon", + "ibm,emac4" + - interrupts : + - interrupt-parent : optional, if needed for interrupt mapping + - reg : + - local-mac-address : 6 bytes, MAC address + - mal-device : phandle of the associated McMAL node + - mal-tx-channel : 1 cell, index of the tx channel on McMAL associated + with this EMAC + - mal-rx-channel : 1 cell, index of the rx channel on McMAL associated + with this EMAC + - cell-index : 1 cell, hardware index of the EMAC cell on a given + ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on + each Axon chip) + - max-frame-size : 1 cell, maximum frame size supported in bytes + - rx-fifo-size : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec + operations. + For Axon, 2048 + - tx-fifo-size : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec + operations. + For Axon, 2048. + - fifo-entry-size : 1 cell, size of a fifo entry (used to calculate + thresholds). + For Axon, 0x00000010 + - mal-burst-size : 1 cell, MAL burst size (used to calculate thresholds) + in bytes. + For Axon, 0x00000100 (I think ...) + - phy-mode : string, mode of operations of the PHY interface. + Supported values are: "mii", "rmii", "smii", "rgmii", + "tbi", "gmii", rtbi", "sgmii". + For Axon on CAB, it is "rgmii" + - mdio-device : 1 cell, required iff using shared MDIO registers + (440EP). phandle of the EMAC to use to drive the + MDIO lines for the PHY used by this EMAC. + - zmii-device : 1 cell, required iff connected to a ZMII. phandle of + the ZMII device node + - zmii-channel : 1 cell, required iff connected to a ZMII. Which ZMII + channel or 0xffffffff if ZMII is only used for MDIO. + - rgmii-device : 1 cell, required iff connected to an RGMII. phandle + of the RGMII device node. + For Axon: phandle of plb5/plb4/opb/rgmii + - rgmii-channel : 1 cell, required iff connected to an RGMII. Which + RGMII channel is used by this EMAC. + Fox Axon: present, whatever value is appropriate for each + EMAC, that is the content of the current (bogus) "phy-port" + property. + + Recommended properties: + - linux,network-index : This is the intended "index" of this + network device. This is used by the bootwrapper to interpret + MAC addresses passed by the firmware when no information other + than indices is available to associate an address with a device. + + Optional properties: + - phy-address : 1 cell, optional, MDIO address of the PHY. If absent, + a search is performed. + - phy-map : 1 cell, optional, bitmap of addresses to probe the PHY + for, used if phy-address is absent. bit 0x00000001 is + MDIO address 0. + For Axon it can be absent, thouugh my current driver + doesn't handle phy-address yet so for now, keep + 0x00ffffff in it. + - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec + operations (if absent the value is the same as + rx-fifo-size). For Axon, either absent or 2048. + - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec + operations (if absent the value is the same as + tx-fifo-size). For Axon, either absent or 2048. + - tah-device : 1 cell, optional. If connected to a TAH engine for + offload, phandle of the TAH device node. + - tah-channel : 1 cell, optional. If appropriate, channel used on the + TAH engine. + + Example: + + EMAC0: ethernet@40000800 { + linux,network-index = <0>; + device_type = "network"; + compatible = "ibm,emac-440gp", "ibm,emac"; + interrupt-parent = <&UIC1>; + interrupts = <1c 4 1d 4>; + reg = <40000800 70>; + local-mac-address = [00 04 AC E3 1B 1E]; + mal-device = <&MAL0>; + mal-tx-channel = <0 1>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000001>; + zmii-device = <&ZMII0>; + zmii-channel = <0>; + }; + + ii) McMAL node + + Required properties: + - device_type : "dma-controller" + - compatible : compatible list, containing 2 entries, first is + "ibm,mcmal-CHIP" where CHIP is the host ASIC (like + emac) and the second is either "ibm,mcmal" or + "ibm,mcmal2". + For Axon, "ibm,mcmal-axon","ibm,mcmal2" + - interrupts : . + For Axon: This is _different_ from the current + firmware. We use the "delayed" interrupts for txeob + and rxeob. Thus we end up with mapping those 5 MPIC + interrupts, all level positive sensitive: 10, 11, 32, + 33, 34 (in decimal) + - dcr-reg : < DCR registers range > + - dcr-parent : if needed for dcr-reg + - num-tx-chans : 1 cell, number of Tx channels + - num-rx-chans : 1 cell, number of Rx channels + + iii) ZMII node + + Required properties: + - compatible : compatible list, containing 2 entries, first is + "ibm,zmii-CHIP" where CHIP is the host ASIC (like + EMAC) and the second is "ibm,zmii". + For Axon, there is no ZMII node. + - reg : + + iv) RGMII node + + Required properties: + - compatible : compatible list, containing 2 entries, first is + "ibm,rgmii-CHIP" where CHIP is the host ASIC (like + EMAC) and the second is "ibm,rgmii". + For Axon, "ibm,rgmii-axon","ibm,rgmii" + - reg : + - revision : as provided by the RGMII new version register if + available. + For Axon: 0x0000012a + More devices will be defined as this spec matures. VII - Specifying interrupt information for devices diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 1b3e008fd148..8e66949e7c67 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -38,8 +38,7 @@ config 440EP config 440GP bool -# Disabled until the new EMAC Driver is merged. -# select IBM_NEW_EMAC_ZMII + select IBM_NEW_EMAC_ZMII config 440GX bool diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index ac8032034fb8..e1e2f6a43019 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -10,6 +10,10 @@ config PPC_CELL_NATIVE select PPC_INDIRECT_IO select PPC_NATIVE select MPIC + select IBM_NEW_EMAC_EMAC4 + select IBM_NEW_EMAC_RGMII + select IBM_NEW_EMAC_ZMII #test only + select IBM_NEW_EMAC_TAH #test only default n config PPC_IBM_CELL_BLADE diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9dc4a80a6acd..cfa97f3fbebd 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1247,75 +1247,8 @@ config IBMVETH . The module will be called ibmveth. -config IBM_EMAC - tristate "PowerPC 4xx on-chip Ethernet support" - depends on 4xx && !PPC_MERGE - help - This driver supports the PowerPC 4xx EMAC family of on-chip - Ethernet controllers. - -config IBM_EMAC_RXB - int "Number of receive buffers" - depends on IBM_EMAC - default "128" - -config IBM_EMAC_TXB - int "Number of transmit buffers" - depends on IBM_EMAC - default "64" - -config IBM_EMAC_POLL_WEIGHT - int "MAL NAPI polling weight" - depends on IBM_EMAC - default "32" - -config IBM_EMAC_RX_COPY_THRESHOLD - int "RX skb copy threshold (bytes)" - depends on IBM_EMAC - default "256" - -config IBM_EMAC_RX_SKB_HEADROOM - int "Additional RX skb headroom (bytes)" - depends on IBM_EMAC - default "0" - help - Additional receive skb headroom. Note, that driver - will always reserve at least 2 bytes to make IP header - aligned, so usually there is no need to add any additional - headroom. - - If unsure, set to 0. - -config IBM_EMAC_PHY_RX_CLK_FIX - bool "PHY Rx clock workaround" - depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR) - help - Enable this if EMAC attached to a PHY which doesn't generate - RX clock if there is no link, if this is the case, you will - see "TX disable timeout" or "RX disable timeout" in the system - log. - - If unsure, say N. - -config IBM_EMAC_DEBUG - bool "Debugging" - depends on IBM_EMAC - default n - -config IBM_EMAC_ZMII - bool - depends on IBM_EMAC && (NP405H || NP405L || 44x) - default y - -config IBM_EMAC_RGMII - bool - depends on IBM_EMAC && 440GX - default y - -config IBM_EMAC_TAH - bool - depends on IBM_EMAC && 440GX - default y +source "drivers/net/ibm_emac/Kconfig" +source "drivers/net/ibm_newemac/Kconfig" config NET_PCI bool "EISA, VLB, PCI and on board controllers" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 2ab33e8b9159..9cbef5829870 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ +obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_IP1000) += ipg.o diff --git a/drivers/net/ibm_emac/Kconfig b/drivers/net/ibm_emac/Kconfig new file mode 100644 index 000000000000..f61c48047dc0 --- /dev/null +++ b/drivers/net/ibm_emac/Kconfig @@ -0,0 +1,70 @@ +config IBM_EMAC + tristate "PowerPC 4xx on-chip Ethernet support" + depends on 4xx && !PPC_MERGE + help + This driver supports the PowerPC 4xx EMAC family of on-chip + Ethernet controllers. + +config IBM_EMAC_RXB + int "Number of receive buffers" + depends on IBM_EMAC + default "128" + +config IBM_EMAC_TXB + int "Number of transmit buffers" + depends on IBM_EMAC + default "64" + +config IBM_EMAC_POLL_WEIGHT + int "MAL NAPI polling weight" + depends on IBM_EMAC + default "32" + +config IBM_EMAC_RX_COPY_THRESHOLD + int "RX skb copy threshold (bytes)" + depends on IBM_EMAC + default "256" + +config IBM_EMAC_RX_SKB_HEADROOM + int "Additional RX skb headroom (bytes)" + depends on IBM_EMAC + default "0" + help + Additional receive skb headroom. Note, that driver + will always reserve at least 2 bytes to make IP header + aligned, so usually there is no need to add any additional + headroom. + + If unsure, set to 0. + +config IBM_EMAC_PHY_RX_CLK_FIX + bool "PHY Rx clock workaround" + depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR) + help + Enable this if EMAC attached to a PHY which doesn't generate + RX clock if there is no link, if this is the case, you will + see "TX disable timeout" or "RX disable timeout" in the system + log. + + If unsure, say N. + +config IBM_EMAC_DEBUG + bool "Debugging" + depends on IBM_EMAC + default n + +config IBM_EMAC_ZMII + bool + depends on IBM_EMAC && (NP405H || NP405L || 44x) + default y + +config IBM_EMAC_RGMII + bool + depends on IBM_EMAC && 440GX + default y + +config IBM_EMAC_TAH + bool + depends on IBM_EMAC && 440GX + default y + diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig new file mode 100644 index 000000000000..0d3e7380bad0 --- /dev/null +++ b/drivers/net/ibm_newemac/Kconfig @@ -0,0 +1,63 @@ +config IBM_NEW_EMAC + tristate "IBM EMAC Ethernet support" + depends on PPC_DCR && PPC_MERGE + help + This driver supports the IBM EMAC family of Ethernet controllers + typically found on 4xx embedded PowerPC chips, but also on the + Axon southbridge for Cell. + +config IBM_NEW_EMAC_RXB + int "Number of receive buffers" + depends on IBM_NEW_EMAC + default "128" + +config IBM_NEW_EMAC_TXB + int "Number of transmit buffers" + depends on IBM_NEW_EMAC + default "64" + +config IBM_NEW_EMAC_POLL_WEIGHT + int "MAL NAPI polling weight" + depends on IBM_NEW_EMAC + default "32" + +config IBM_NEW_EMAC_RX_COPY_THRESHOLD + int "RX skb copy threshold (bytes)" + depends on IBM_NEW_EMAC + default "256" + +config IBM_NEW_EMAC_RX_SKB_HEADROOM + int "Additional RX skb headroom (bytes)" + depends on IBM_NEW_EMAC + default "0" + help + Additional receive skb headroom. Note, that driver + will always reserve at least 2 bytes to make IP header + aligned, so usually there is no need to add any additional + headroom. + + If unsure, set to 0. + +config IBM_NEW_EMAC_DEBUG + bool "Debugging" + depends on IBM_NEW_EMAC + default n + +# The options below has to be select'ed by the respective +# processor types or platforms + +config IBM_NEW_EMAC_ZMII + bool + default n + +config IBM_NEW_EMAC_RGMII + bool + default n + +config IBM_NEW_EMAC_TAH + bool + default n + +config IBM_NEW_EMAC_EMAC4 + bool + default n diff --git a/drivers/net/ibm_newemac/Makefile b/drivers/net/ibm_newemac/Makefile new file mode 100644 index 000000000000..0b5c99512762 --- /dev/null +++ b/drivers/net/ibm_newemac/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the PowerPC 4xx on-chip ethernet driver +# + +obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac.o + +ibm_newemac-y := mal.o core.o phy.o +ibm_newemac-$(CONFIG_IBM_NEW_EMAC_ZMII) += zmii.o +ibm_newemac-$(CONFIG_IBM_NEW_EMAC_RGMII) += rgmii.o +ibm_newemac-$(CONFIG_IBM_NEW_EMAC_TAH) += tah.o +ibm_newemac-$(CONFIG_IBM_NEW_EMAC_DEBUG) += debug.o diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c new file mode 100644 index 000000000000..653bfdc291e0 --- /dev/null +++ b/drivers/net/ibm_newemac/core.c @@ -0,0 +1,2907 @@ +/* + * drivers/net/ibm_newemac/core.c + * + * Driver for PowerPC 4xx on-chip ethernet controller. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Matt Porter + * (c) 2003 Benjamin Herrenschmidt + * Armin Kuster + * Johnnie Peters + * + * 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 "core.h" + +/* + * Lack of dma_unmap_???? calls is intentional. + * + * API-correct usage requires additional support state information to be + * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to + * EMAC design (e.g. TX buffer passed from network stack can be split into + * several BDs, dma_map_single/dma_map_page can be used to map particular BD), + * maintaining such information will add additional overhead. + * Current DMA API implementation for 4xx processors only ensures cache coherency + * and dma_unmap_???? routines are empty and are likely to stay this way. + * I decided to omit dma_unmap_??? calls because I don't want to add additional + * complexity just for the sake of following some abstract API, when it doesn't + * add any real benefit to the driver. I understand that this decision maybe + * controversial, but I really tried to make code API-correct and efficient + * at the same time and didn't come up with code I liked :(. --ebs + */ + +#define DRV_NAME "emac" +#define DRV_VERSION "3.54" +#define DRV_DESC "PPC 4xx OCP EMAC driver" + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR + ("Eugene Surovegin or "); +MODULE_LICENSE("GPL"); + +/* + * PPC64 doesn't (yet) have a cacheable_memcpy + */ +#ifdef CONFIG_PPC64 +#define cacheable_memcpy(d,s,n) memcpy((d),(s),(n)) +#endif + +/* minimum number of free TX descriptors required to wake up TX process */ +#define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4) + +/* If packet size is less than this number, we allocate small skb and copy packet + * contents into it instead of just sending original big skb up + */ +#define EMAC_RX_COPY_THRESH CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD + +/* Since multiple EMACs share MDIO lines in various ways, we need + * to avoid re-using the same PHY ID in cases where the arch didn't + * setup precise phy_map entries + * + * XXX This is something that needs to be reworked as we can have multiple + * EMAC "sets" (multiple ASICs containing several EMACs) though we can + * probably require in that case to have explicit PHY IDs in the device-tree + */ +static u32 busy_phy_map; +static DEFINE_MUTEX(emac_phy_map_lock); + +/* This is the wait queue used to wait on any event related to probe, that + * is discovery of MALs, other EMACs, ZMII/RGMIIs, etc... + */ +static DECLARE_WAIT_QUEUE_HEAD(emac_probe_wait); + +/* Having stable interface names is a doomed idea. However, it would be nice + * if we didn't have completely random interface names at boot too :-) It's + * just a matter of making everybody's life easier. Since we are doing + * threaded probing, it's a bit harder though. The base idea here is that + * we make up a list of all emacs in the device-tree before we register the + * driver. Every emac will then wait for the previous one in the list to + * initialize before itself. We should also keep that list ordered by + * cell_index. + * That list is only 4 entries long, meaning that additional EMACs don't + * get ordering guarantees unless EMAC_BOOT_LIST_SIZE is increased. + */ + +#define EMAC_BOOT_LIST_SIZE 4 +static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE]; + +/* How long should I wait for dependent devices ? */ +#define EMAC_PROBE_DEP_TIMEOUT (HZ * 5) + +/* I don't want to litter system log with timeout errors + * when we have brain-damaged PHY. + */ +static inline void emac_report_timeout_error(struct emac_instance *dev, + const char *error) +{ + if (net_ratelimit()) + printk(KERN_ERR "%s: %s\n", dev->ndev->name, error); +} + +/* PHY polling intervals */ +#define PHY_POLL_LINK_ON HZ +#define PHY_POLL_LINK_OFF (HZ / 5) + +/* Graceful stop timeouts in us. + * We should allow up to 1 frame time (full-duplex, ignoring collisions) + */ +#define STOP_TIMEOUT_10 1230 +#define STOP_TIMEOUT_100 124 +#define STOP_TIMEOUT_1000 13 +#define STOP_TIMEOUT_1000_JUMBO 73 + +/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ +static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { + "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", + "tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom", + "rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu", + "rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet", + "rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error", + "rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range", + "rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun", + "rx_bad_packet", "rx_runt_packet", "rx_short_event", + "rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long", + "rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors", + "tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral", + "tx_bd_excessive_collisions", "tx_bd_late_collision", + "tx_bd_multple_collisions", "tx_bd_single_collision", + "tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe", + "tx_errors" +}; + +static irqreturn_t emac_irq(int irq, void *dev_instance); +static void emac_clean_tx_ring(struct emac_instance *dev); +static void __emac_set_multicast_list(struct emac_instance *dev); + +static inline int emac_phy_supports_gige(int phy_mode) +{ + return phy_mode == PHY_MODE_GMII || + phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline int emac_phy_gpcs(int phy_mode) +{ + return phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline void emac_tx_enable(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + DBG(dev, "tx_enable" NL); + + r = in_be32(&p->mr0); + if (!(r & EMAC_MR0_TXE)) + out_be32(&p->mr0, r | EMAC_MR0_TXE); +} + +static void emac_tx_disable(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + DBG(dev, "tx_disable" NL); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_TXE) { + int n = dev->stop_timeout; + out_be32(&p->mr0, r & ~EMAC_MR0_TXE); + while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) { + udelay(1); + --n; + } + if (unlikely(!n)) + emac_report_timeout_error(dev, "TX disable timeout"); + } +} + +static void emac_rx_enable(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + if (unlikely(test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags))) + goto out; + + DBG(dev, "rx_enable" NL); + + r = in_be32(&p->mr0); + if (!(r & EMAC_MR0_RXE)) { + if (unlikely(!(r & EMAC_MR0_RXI))) { + /* Wait if previous async disable is still in progress */ + int n = dev->stop_timeout; + while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { + udelay(1); + --n; + } + if (unlikely(!n)) + emac_report_timeout_error(dev, + "RX disable timeout"); + } + out_be32(&p->mr0, r | EMAC_MR0_RXE); + } + out: + ; +} + +static void emac_rx_disable(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + DBG(dev, "rx_disable" NL); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_RXE) { + int n = dev->stop_timeout; + out_be32(&p->mr0, r & ~EMAC_MR0_RXE); + while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { + udelay(1); + --n; + } + if (unlikely(!n)) + emac_report_timeout_error(dev, "RX disable timeout"); + } +} + +static inline void emac_netif_stop(struct emac_instance *dev) +{ + netif_tx_lock_bh(dev->ndev); + dev->no_mcast = 1; + netif_tx_unlock_bh(dev->ndev); + dev->ndev->trans_start = jiffies; /* prevent tx timeout */ + mal_poll_disable(dev->mal, &dev->commac); + netif_tx_disable(dev->ndev); +} + +static inline void emac_netif_start(struct emac_instance *dev) +{ + netif_tx_lock_bh(dev->ndev); + dev->no_mcast = 0; + if (dev->mcast_pending && netif_running(dev->ndev)) + __emac_set_multicast_list(dev); + netif_tx_unlock_bh(dev->ndev); + + netif_wake_queue(dev->ndev); + + /* NOTE: unconditional netif_wake_queue is only appropriate + * so long as all callers are assured to have free tx slots + * (taken from tg3... though the case where that is wrong is + * not terribly harmful) + */ + mal_poll_enable(dev->mal, &dev->commac); +} + +static inline void emac_rx_disable_async(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + DBG(dev, "rx_disable_async" NL); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_RXE) + out_be32(&p->mr0, r & ~EMAC_MR0_RXE); +} + +static int emac_reset(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + int n = 20; + + DBG(dev, "reset" NL); + + if (!dev->reset_failed) { + /* 40x erratum suggests stopping RX channel before reset, + * we stop TX as well + */ + emac_rx_disable(dev); + emac_tx_disable(dev); + } + + out_be32(&p->mr0, EMAC_MR0_SRST); + while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) + --n; + + if (n) { + dev->reset_failed = 0; + return 0; + } else { + emac_report_timeout_error(dev, "reset timeout"); + dev->reset_failed = 1; + return -ETIMEDOUT; + } +} + +static void emac_hash_mc(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u16 gaht[4] = { 0 }; + struct dev_mc_list *dmi; + + DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count); + + for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { + int bit; + DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL, + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + + bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26); + gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f); + } + out_be32(&p->gaht1, gaht[0]); + out_be32(&p->gaht2, gaht[1]); + out_be32(&p->gaht3, gaht[2]); + out_be32(&p->gaht4, gaht[3]); +} + +static inline u32 emac_iff2rmr(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + u32 r; + + r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE; + + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r |= EMAC4_RMR_BASE; + else + r |= EMAC_RMR_BASE; + + if (ndev->flags & IFF_PROMISC) + r |= EMAC_RMR_PME; + else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32) + r |= EMAC_RMR_PMME; + else if (ndev->mc_count > 0) + r |= EMAC_RMR_MAE; + + return r; +} + +static u32 __emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size) +{ + u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC_MR1_TR0_MULT; + + DBG2(dev, "__emac_calc_base_mr1" NL); + + switch(tx_size) { + case 2048: + ret |= EMAC_MR1_TFS_2K; + break; + default: + printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n", + dev->ndev->name, tx_size); + } + + switch(rx_size) { + case 16384: + ret |= EMAC_MR1_RFS_16K; + break; + case 4096: + ret |= EMAC_MR1_RFS_4K; + break; + default: + printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n", + dev->ndev->name, rx_size); + } + + return ret; +} + +static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size) +{ + u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC4_MR1_TR | + EMAC4_MR1_OBCI(dev->opb_bus_freq); + + DBG2(dev, "__emac4_calc_base_mr1" NL); + + switch(tx_size) { + case 4096: + ret |= EMAC4_MR1_TFS_4K; + break; + case 2048: + ret |= EMAC4_MR1_TFS_2K; + break; + default: + printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n", + dev->ndev->name, tx_size); + } + + switch(rx_size) { + case 16384: + ret |= EMAC4_MR1_RFS_16K; + break; + case 4096: + ret |= EMAC4_MR1_RFS_4K; + break; + case 2048: + ret |= EMAC4_MR1_RFS_2K; + break; + default: + printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n", + dev->ndev->name, rx_size); + } + + return ret; +} + +static u32 emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size) +{ + return emac_has_feature(dev, EMAC_FTR_EMAC4) ? + __emac4_calc_base_mr1(dev, tx_size, rx_size) : + __emac_calc_base_mr1(dev, tx_size, rx_size); +} + +static inline u32 emac_calc_trtr(struct emac_instance *dev, unsigned int size) +{ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + return ((size >> 6) - 1) << EMAC_TRTR_SHIFT_EMAC4; + else + return ((size >> 6) - 1) << EMAC_TRTR_SHIFT; +} + +static inline u32 emac_calc_rwmr(struct emac_instance *dev, + unsigned int low, unsigned int high) +{ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + return (low << 22) | ( (high & 0x3ff) << 6); + else + return (low << 23) | ( (high & 0x1ff) << 7); +} + +static int emac_configure(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + struct net_device *ndev = dev->ndev; + int tx_size, rx_size; + u32 r, mr1 = 0; + + DBG(dev, "configure" NL); + + if (emac_reset(dev) < 0) + return -ETIMEDOUT; + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + tah_reset(dev->tah_dev); + + DBG(dev, " duplex = %d, pause = %d, asym_pause = %d\n", + dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause); + + /* Default fifo sizes */ + tx_size = dev->tx_fifo_size; + rx_size = dev->rx_fifo_size; + + /* Check for full duplex */ + if (dev->phy.duplex == DUPLEX_FULL) + mr1 |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001; + + /* Adjust fifo sizes, mr1 and timeouts based on link speed */ + dev->stop_timeout = STOP_TIMEOUT_10; + switch (dev->phy.speed) { + case SPEED_1000: + if (emac_phy_gpcs(dev->phy.mode)) { + mr1 |= EMAC_MR1_MF_1000GPCS | + EMAC_MR1_MF_IPPA(dev->phy.address); + + /* Put some arbitrary OUI, Manuf & Rev IDs so we can + * identify this GPCS PHY later. + */ + out_be32(&p->ipcr, 0xdeadbeef); + } else + mr1 |= EMAC_MR1_MF_1000; + + /* Extended fifo sizes */ + tx_size = dev->tx_fifo_size_gige; + rx_size = dev->rx_fifo_size_gige; + + if (dev->ndev->mtu > ETH_DATA_LEN) { + mr1 |= EMAC_MR1_JPSM; + dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO; + } else + dev->stop_timeout = STOP_TIMEOUT_1000; + break; + case SPEED_100: + mr1 |= EMAC_MR1_MF_100; + dev->stop_timeout = STOP_TIMEOUT_100; + break; + default: /* make gcc happy */ + break; + } + + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_set_speed(dev->rgmii_dev, dev->rgmii_port, + dev->phy.speed); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_set_speed(dev->zmii_dev, dev->zmii_port, dev->phy.speed); + + /* on 40x erratum forces us to NOT use integrated flow control, + * let's hope it works on 44x ;) + */ + if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x) && + dev->phy.duplex == DUPLEX_FULL) { + if (dev->phy.pause) + mr1 |= EMAC_MR1_EIFC | EMAC_MR1_APP; + else if (dev->phy.asym_pause) + mr1 |= EMAC_MR1_APP; + } + + /* Add base settings & fifo sizes & program MR1 */ + mr1 |= emac_calc_base_mr1(dev, tx_size, rx_size); + out_be32(&p->mr1, mr1); + + /* Set individual MAC address */ + out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]); + out_be32(&p->ialr, (ndev->dev_addr[2] << 24) | + (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) | + ndev->dev_addr[5]); + + /* VLAN Tag Protocol ID */ + out_be32(&p->vtpid, 0x8100); + + /* Receive mode register */ + r = emac_iff2rmr(ndev); + if (r & EMAC_RMR_MAE) + emac_hash_mc(dev); + out_be32(&p->rmr, r); + + /* FIFOs thresholds */ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r = EMAC4_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1, + tx_size / 2 / dev->fifo_entry_size); + else + r = EMAC_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1, + tx_size / 2 / dev->fifo_entry_size); + out_be32(&p->tmr1, r); + out_be32(&p->trtr, emac_calc_trtr(dev, tx_size / 2)); + + /* PAUSE frame is sent when RX FIFO reaches its high-water mark, + there should be still enough space in FIFO to allow the our link + partner time to process this frame and also time to send PAUSE + frame itself. + + Here is the worst case scenario for the RX FIFO "headroom" + (from "The Switch Book") (100Mbps, without preamble, inter-frame gap): + + 1) One maximum-length frame on TX 1522 bytes + 2) One PAUSE frame time 64 bytes + 3) PAUSE frame decode time allowance 64 bytes + 4) One maximum-length frame on RX 1522 bytes + 5) Round-trip propagation delay of the link (100Mb) 15 bytes + ---------- + 3187 bytes + + I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes) + low-water mark to RX_FIFO_SIZE / 8 (512 bytes) + */ + r = emac_calc_rwmr(dev, rx_size / 8 / dev->fifo_entry_size, + rx_size / 4 / dev->fifo_entry_size); + out_be32(&p->rwmr, r); + + /* Set PAUSE timer to the maximum */ + out_be32(&p->ptr, 0xffff); + + /* IRQ sources */ + r = EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE | + EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE | + EMAC_ISR_IRE | EMAC_ISR_TE; + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r |= EMAC4_ISR_TXPE | EMAC4_ISR_RXPE /* | EMAC4_ISR_TXUE | + EMAC4_ISR_RXOE | */; + out_be32(&p->iser, r); + + /* We need to take GPCS PHY out of isolate mode after EMAC reset */ + if (emac_phy_gpcs(dev->phy.mode)) + emac_mii_reset_phy(&dev->phy); + + return 0; +} + +static void emac_reinitialize(struct emac_instance *dev) +{ + DBG(dev, "reinitialize" NL); + + emac_netif_stop(dev); + if (!emac_configure(dev)) { + emac_tx_enable(dev); + emac_rx_enable(dev); + } + emac_netif_start(dev); +} + +static void emac_full_tx_reset(struct emac_instance *dev) +{ + DBG(dev, "full_tx_reset" NL); + + emac_tx_disable(dev); + mal_disable_tx_channel(dev->mal, dev->mal_tx_chan); + emac_clean_tx_ring(dev); + dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0; + + emac_configure(dev); + + mal_enable_tx_channel(dev->mal, dev->mal_tx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); +} + +static void emac_reset_work(struct work_struct *work) +{ + struct emac_instance *dev = container_of(work, struct emac_instance, reset_work); + + DBG(dev, "reset_work" NL); + + mutex_lock(&dev->link_lock); + emac_netif_stop(dev); + emac_full_tx_reset(dev); + emac_netif_start(dev); + mutex_unlock(&dev->link_lock); +} + +static void emac_tx_timeout(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + + DBG(dev, "tx_timeout" NL); + + schedule_work(&dev->reset_work); +} + + +static inline int emac_phy_done(struct emac_instance *dev, u32 stacr) +{ + int done = !!(stacr & EMAC_STACR_OC); + + if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT)) + done = !done; + + return done; +}; + +static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r = 0; + int n, err = -ETIMEDOUT; + + mutex_lock(&dev->mdio_lock); + + DBG2(dev, "mdio_read(%02x,%02x)" NL, id, reg); + + /* Enable proper MDIO port */ + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_get_mdio(dev->zmii_dev, dev->zmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port); + + /* Wait for management interface to become idle */ + n = 10; + while (!emac_phy_done(dev, in_be32(&p->stacr))) { + udelay(1); + if (!--n) { + DBG2(dev, " -> timeout wait idle\n"); + goto bail; + } + } + + /* Issue read command */ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r = EMAC4_STACR_BASE(dev->opb_bus_freq); + else + r = EMAC_STACR_BASE(dev->opb_bus_freq); + if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT)) + r |= EMAC_STACR_OC; + if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR)) + r |= EMACX_STACR_STAC_READ; + else + r |= EMAC_STACR_STAC_READ; + r |= (reg & EMAC_STACR_PRA_MASK) + | ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT); + out_be32(&p->stacr, r); + + /* Wait for read to complete */ + n = 100; + while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) { + udelay(1); + if (!--n) { + DBG2(dev, " -> timeout wait complete\n"); + goto bail; + } + } + + if (unlikely(r & EMAC_STACR_PHYE)) { + DBG(dev, "mdio_read(%02x, %02x) failed" NL, id, reg); + err = -EREMOTEIO; + goto bail; + } + + r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK); + + DBG2(dev, "mdio_read -> %04x" NL, r); + err = 0; + bail: + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_put_mdio(dev->zmii_dev, dev->zmii_port); + mutex_unlock(&dev->mdio_lock); + + return err == 0 ? r : err; +} + +static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg, + u16 val) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r = 0; + int n, err = -ETIMEDOUT; + + mutex_lock(&dev->mdio_lock); + + DBG2(dev, "mdio_write(%02x,%02x,%04x)" NL, id, reg, val); + + /* Enable proper MDIO port */ + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_get_mdio(dev->zmii_dev, dev->zmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port); + + /* Wait for management interface to be idle */ + n = 10; + while (!emac_phy_done(dev, in_be32(&p->stacr))) { + udelay(1); + if (!--n) { + DBG2(dev, " -> timeout wait idle\n"); + goto bail; + } + } + + /* Issue write command */ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r = EMAC4_STACR_BASE(dev->opb_bus_freq); + else + r = EMAC_STACR_BASE(dev->opb_bus_freq); + if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT)) + r |= EMAC_STACR_OC; + if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR)) + r |= EMACX_STACR_STAC_WRITE; + else + r |= EMAC_STACR_STAC_WRITE; + r |= (reg & EMAC_STACR_PRA_MASK) | + ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) | + (val << EMAC_STACR_PHYD_SHIFT); + out_be32(&p->stacr, r); + + /* Wait for write to complete */ + n = 100; + while (!emac_phy_done(dev, in_be32(&p->stacr))) { + udelay(1); + if (!--n) { + DBG2(dev, " -> timeout wait complete\n"); + goto bail; + } + } + err = 0; + bail: + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_put_mdio(dev->zmii_dev, dev->zmii_port); + mutex_unlock(&dev->mdio_lock); +} + +static int emac_mdio_read(struct net_device *ndev, int id, int reg) +{ + struct emac_instance *dev = netdev_priv(ndev); + int res; + + res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev, + (u8) id, (u8) reg); + return res; +} + +static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) +{ + struct emac_instance *dev = netdev_priv(ndev); + + __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev, + (u8) id, (u8) reg, (u16) val); +} + +/* Tx lock BH */ +static void __emac_set_multicast_list(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 rmr = emac_iff2rmr(dev->ndev); + + DBG(dev, "__multicast %08x" NL, rmr); + + /* I decided to relax register access rules here to avoid + * full EMAC reset. + * + * There is a real problem with EMAC4 core if we use MWSW_001 bit + * in MR1 register and do a full EMAC reset. + * One TX BD status update is delayed and, after EMAC reset, it + * never happens, resulting in TX hung (it'll be recovered by TX + * timeout handler eventually, but this is just gross). + * So we either have to do full TX reset or try to cheat here :) + * + * The only required change is to RX mode register, so I *think* all + * we need is just to stop RX channel. This seems to work on all + * tested SoCs. --ebs + * + * If we need the full reset, we might just trigger the workqueue + * and do it async... a bit nasty but should work --BenH + */ + dev->mcast_pending = 0; + emac_rx_disable(dev); + if (rmr & EMAC_RMR_MAE) + emac_hash_mc(dev); + out_be32(&p->rmr, rmr); + emac_rx_enable(dev); +} + +/* Tx lock BH */ +static void emac_set_multicast_list(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + + DBG(dev, "multicast" NL); + + BUG_ON(!netif_running(dev->ndev)); + + if (dev->no_mcast) { + dev->mcast_pending = 1; + return; + } + __emac_set_multicast_list(dev); +} + +static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu) +{ + int rx_sync_size = emac_rx_sync_size(new_mtu); + int rx_skb_size = emac_rx_skb_size(new_mtu); + int i, ret = 0; + + mutex_lock(&dev->link_lock); + emac_netif_stop(dev); + emac_rx_disable(dev); + mal_disable_rx_channel(dev->mal, dev->mal_rx_chan); + + if (dev->rx_sg_skb) { + ++dev->estats.rx_dropped_resize; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } + + /* Make a first pass over RX ring and mark BDs ready, dropping + * non-processed packets on the way. We need this as a separate pass + * to simplify error recovery in the case of allocation failure later. + */ + for (i = 0; i < NUM_RX_BUFF; ++i) { + if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST) + ++dev->estats.rx_dropped_resize; + + dev->rx_desc[i].data_len = 0; + dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | + (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + } + + /* Reallocate RX ring only if bigger skb buffers are required */ + if (rx_skb_size <= dev->rx_skb_size) + goto skip; + + /* Second pass, allocate new skbs */ + for (i = 0; i < NUM_RX_BUFF; ++i) { + struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC); + if (!skb) { + ret = -ENOMEM; + goto oom; + } + + BUG_ON(!dev->rx_skb[i]); + dev_kfree_skb(dev->rx_skb[i]); + + skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); + dev->rx_desc[i].data_ptr = + dma_map_single(&dev->ofdev->dev, skb->data - 2, rx_sync_size, + DMA_FROM_DEVICE) + 2; + dev->rx_skb[i] = skb; + } + skip: + /* Check if we need to change "Jumbo" bit in MR1 */ + if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) { + /* This is to prevent starting RX channel in emac_rx_enable() */ + set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + + dev->ndev->mtu = new_mtu; + emac_full_tx_reset(dev); + } + + mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(new_mtu)); + oom: + /* Restart RX */ + clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + dev->rx_slot = 0; + mal_enable_rx_channel(dev->mal, dev->mal_rx_chan); + emac_rx_enable(dev); + emac_netif_start(dev); + mutex_unlock(&dev->link_lock); + + return ret; +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct emac_instance *dev = netdev_priv(ndev); + int ret = 0; + + if (new_mtu < EMAC_MIN_MTU || new_mtu > dev->max_mtu) + return -EINVAL; + + DBG(dev, "change_mtu(%d)" NL, new_mtu); + + if (netif_running(ndev)) { + /* Check if we really need to reinitalize RX ring */ + if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu)) + ret = emac_resize_rx_ring(dev, new_mtu); + } + + if (!ret) { + ndev->mtu = new_mtu; + dev->rx_skb_size = emac_rx_skb_size(new_mtu); + dev->rx_sync_size = emac_rx_sync_size(new_mtu); + } + + return ret; +} + +static void emac_clean_tx_ring(struct emac_instance *dev) +{ + int i; + + for (i = 0; i < NUM_TX_BUFF; ++i) { + if (dev->tx_skb[i]) { + dev_kfree_skb(dev->tx_skb[i]); + dev->tx_skb[i] = NULL; + if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY) + ++dev->estats.tx_dropped; + } + dev->tx_desc[i].ctrl = 0; + dev->tx_desc[i].data_ptr = 0; + } +} + +static void emac_clean_rx_ring(struct emac_instance *dev) +{ + int i; + + for (i = 0; i < NUM_RX_BUFF; ++i) + if (dev->rx_skb[i]) { + dev->rx_desc[i].ctrl = 0; + dev_kfree_skb(dev->rx_skb[i]); + dev->rx_skb[i] = NULL; + dev->rx_desc[i].data_ptr = 0; + } + + if (dev->rx_sg_skb) { + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } +} + +static inline int emac_alloc_rx_skb(struct emac_instance *dev, int slot, + gfp_t flags) +{ + struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags); + if (unlikely(!skb)) + return -ENOMEM; + + dev->rx_skb[slot] = skb; + dev->rx_desc[slot].data_len = 0; + + skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); + dev->rx_desc[slot].data_ptr = + dma_map_single(&dev->ofdev->dev, skb->data - 2, dev->rx_sync_size, + DMA_FROM_DEVICE) + 2; + wmb(); + dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | + (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + + return 0; +} + +static void emac_print_link_status(struct emac_instance *dev) +{ + if (netif_carrier_ok(dev->ndev)) + printk(KERN_INFO "%s: link is up, %d %s%s\n", + dev->ndev->name, dev->phy.speed, + dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX", + dev->phy.pause ? ", pause enabled" : + dev->phy.asym_pause ? ", asymmetric pause enabled" : ""); + else + printk(KERN_INFO "%s: link is down\n", dev->ndev->name); +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_open(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + int err, i; + + DBG(dev, "open" NL); + + /* Setup error IRQ handler */ + err = request_irq(dev->emac_irq, emac_irq, 0, "EMAC", dev); + if (err) { + printk(KERN_ERR "%s: failed to request IRQ %d\n", + ndev->name, dev->emac_irq); + return err; + } + + /* Allocate RX ring */ + for (i = 0; i < NUM_RX_BUFF; ++i) + if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) { + printk(KERN_ERR "%s: failed to allocate RX ring\n", + ndev->name); + goto oom; + } + + dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = 0; + clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + dev->rx_sg_skb = NULL; + + mutex_lock(&dev->link_lock); + + /* XXX Start PHY polling now. Shouldn't wr do like sungem instead and + * always poll the PHY even when the iface is down ? That would allow + * things like laptop-net to work. --BenH + */ + if (dev->phy.address >= 0) { + int link_poll_interval; + if (dev->phy.def->ops->poll_link(&dev->phy)) { + dev->phy.def->ops->read_link(&dev->phy); + netif_carrier_on(dev->ndev); + link_poll_interval = PHY_POLL_LINK_ON; + } else { + netif_carrier_off(dev->ndev); + link_poll_interval = PHY_POLL_LINK_OFF; + } + dev->link_polling = 1; + wmb(); + schedule_delayed_work(&dev->link_work, link_poll_interval); + emac_print_link_status(dev); + } else + netif_carrier_on(dev->ndev); + + emac_configure(dev); + mal_poll_add(dev->mal, &dev->commac); + mal_enable_tx_channel(dev->mal, dev->mal_tx_chan); + mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(ndev->mtu)); + mal_enable_rx_channel(dev->mal, dev->mal_rx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); + emac_netif_start(dev); + + mutex_unlock(&dev->link_lock); + + return 0; + oom: + emac_clean_rx_ring(dev); + free_irq(dev->emac_irq, dev); + + return -ENOMEM; +} + +/* BHs disabled */ +#if 0 +static int emac_link_differs(struct emac_instance *dev) +{ + u32 r = in_be32(&dev->emacp->mr1); + + int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF; + int speed, pause, asym_pause; + + if (r & EMAC_MR1_MF_1000) + speed = SPEED_1000; + else if (r & EMAC_MR1_MF_100) + speed = SPEED_100; + else + speed = SPEED_10; + + switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) { + case (EMAC_MR1_EIFC | EMAC_MR1_APP): + pause = 1; + asym_pause = 0; + break; + case EMAC_MR1_APP: + pause = 0; + asym_pause = 1; + break; + default: + pause = asym_pause = 0; + } + return speed != dev->phy.speed || duplex != dev->phy.duplex || + pause != dev->phy.pause || asym_pause != dev->phy.asym_pause; +} +#endif + +static void emac_link_timer(struct work_struct *work) +{ + struct emac_instance *dev = + container_of((struct delayed_work *)work, + struct emac_instance, link_work); + int link_poll_interval; + + mutex_lock(&dev->link_lock); + + DBG2(dev, "link timer" NL); + + if (dev->phy.def->ops->poll_link(&dev->phy)) { + if (!netif_carrier_ok(dev->ndev)) { + /* Get new link parameters */ + dev->phy.def->ops->read_link(&dev->phy); + + netif_carrier_on(dev->ndev); + emac_netif_stop(dev); + emac_full_tx_reset(dev); + emac_netif_start(dev); + emac_print_link_status(dev); + } + link_poll_interval = PHY_POLL_LINK_ON; + } else { + if (netif_carrier_ok(dev->ndev)) { + emac_reinitialize(dev); + netif_carrier_off(dev->ndev); + netif_tx_disable(dev->ndev); + emac_print_link_status(dev); + } + link_poll_interval = PHY_POLL_LINK_OFF; + } + schedule_delayed_work(&dev->link_work, link_poll_interval); + + mutex_unlock(&dev->link_lock); +} + +static void emac_force_link_update(struct emac_instance *dev) +{ + netif_carrier_off(dev->ndev); + if (dev->link_polling) { + cancel_rearming_delayed_work(&dev->link_work); + if (dev->link_polling) + schedule_delayed_work(&dev->link_work, PHY_POLL_LINK_OFF); + } +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_close(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + + DBG(dev, "close" NL); + + if (dev->phy.address >= 0) + cancel_rearming_delayed_work(&dev->link_work); + + emac_netif_stop(dev); + flush_scheduled_work(); + + emac_rx_disable(dev); + emac_tx_disable(dev); + mal_disable_rx_channel(dev->mal, dev->mal_rx_chan); + mal_disable_tx_channel(dev->mal, dev->mal_tx_chan); + mal_poll_del(dev->mal, &dev->commac); + + emac_clean_tx_ring(dev); + emac_clean_rx_ring(dev); + + free_irq(dev->emac_irq, dev); + + return 0; +} + +static inline u16 emac_tx_csum(struct emac_instance *dev, + struct sk_buff *skb) +{ + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH && + skb->ip_summed == CHECKSUM_PARTIAL)) { + ++dev->stats.tx_packets_csum; + return EMAC_TX_CTRL_TAH_CSUM; + } + return 0; +} + +static inline int emac_xmit_finish(struct emac_instance *dev, int len) +{ + struct emac_regs __iomem *p = dev->emacp; + struct net_device *ndev = dev->ndev; + + /* Send the packet out. If the if makes a significant perf + * difference, then we can store the TMR0 value in "dev" + * instead + */ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + out_be32(&p->tmr0, EMAC_TMR0_XMIT); + else + out_be32(&p->tmr0, EMAC4_TMR0_XMIT); + + if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { + netif_stop_queue(ndev); + DBG2(dev, "stopped TX queue" NL); + } + + ndev->trans_start = jiffies; + ++dev->stats.tx_packets; + dev->stats.tx_bytes += len; + + return 0; +} + +/* Tx lock BH */ +static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + unsigned int len = skb->len; + int slot; + + u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb); + + slot = dev->tx_slot++; + if (dev->tx_slot == NUM_TX_BUFF) { + dev->tx_slot = 0; + ctrl |= MAL_TX_CTRL_WRAP; + } + + DBG2(dev, "xmit(%u) %d" NL, len, slot); + + dev->tx_skb[slot] = skb; + dev->tx_desc[slot].data_ptr = dma_map_single(&dev->ofdev->dev, + skb->data, len, + DMA_TO_DEVICE); + dev->tx_desc[slot].data_len = (u16) len; + wmb(); + dev->tx_desc[slot].ctrl = ctrl; + + return emac_xmit_finish(dev, len); +} + +#ifdef CONFIG_IBM_NEW_EMAC_TAH +static inline int emac_xmit_split(struct emac_instance *dev, int slot, + u32 pd, int len, int last, u16 base_ctrl) +{ + while (1) { + u16 ctrl = base_ctrl; + int chunk = min(len, MAL_MAX_TX_SIZE); + len -= chunk; + + slot = (slot + 1) % NUM_TX_BUFF; + + if (last && !len) + ctrl |= MAL_TX_CTRL_LAST; + if (slot == NUM_TX_BUFF - 1) + ctrl |= MAL_TX_CTRL_WRAP; + + dev->tx_skb[slot] = NULL; + dev->tx_desc[slot].data_ptr = pd; + dev->tx_desc[slot].data_len = (u16) chunk; + dev->tx_desc[slot].ctrl = ctrl; + ++dev->tx_cnt; + + if (!len) + break; + + pd += chunk; + } + return slot; +} + +/* Tx lock BH disabled (SG version for TAH equipped EMACs) */ +static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + int nr_frags = skb_shinfo(skb)->nr_frags; + int len = skb->len, chunk; + int slot, i; + u16 ctrl; + u32 pd; + + /* This is common "fast" path */ + if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE)) + return emac_start_xmit(skb, ndev); + + len -= skb->data_len; + + /* Note, this is only an *estimation*, we can still run out of empty + * slots because of the additional fragmentation into + * MAL_MAX_TX_SIZE-sized chunks + */ + if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF)) + goto stop_queue; + + ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + emac_tx_csum(dev, skb); + slot = dev->tx_slot; + + /* skb data */ + dev->tx_skb[slot] = NULL; + chunk = min(len, MAL_MAX_TX_SIZE); + dev->tx_desc[slot].data_ptr = pd = + dma_map_single(&dev->ofdev->dev, skb->data, len, DMA_TO_DEVICE); + dev->tx_desc[slot].data_len = (u16) chunk; + len -= chunk; + if (unlikely(len)) + slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags, + ctrl); + /* skb fragments */ + for (i = 0; i < nr_frags; ++i) { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + len = frag->size; + + if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF)) + goto undo_frame; + + pd = dma_map_page(&dev->ofdev->dev, frag->page, frag->page_offset, len, + DMA_TO_DEVICE); + + slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1, + ctrl); + } + + DBG2(dev, "xmit_sg(%u) %d - %d" NL, skb->len, dev->tx_slot, slot); + + /* Attach skb to the last slot so we don't release it too early */ + dev->tx_skb[slot] = skb; + + /* Send the packet out */ + if (dev->tx_slot == NUM_TX_BUFF - 1) + ctrl |= MAL_TX_CTRL_WRAP; + wmb(); + dev->tx_desc[dev->tx_slot].ctrl = ctrl; + dev->tx_slot = (slot + 1) % NUM_TX_BUFF; + + return emac_xmit_finish(dev, skb->len); + + undo_frame: + /* Well, too bad. Our previous estimation was overly optimistic. + * Undo everything. + */ + while (slot != dev->tx_slot) { + dev->tx_desc[slot].ctrl = 0; + --dev->tx_cnt; + if (--slot < 0) + slot = NUM_TX_BUFF - 1; + } + ++dev->estats.tx_undo; + + stop_queue: + netif_stop_queue(ndev); + DBG2(dev, "stopped TX queue" NL); + return 1; +} +#else +# define emac_start_xmit_sg emac_start_xmit +#endif /* !defined(CONFIG_IBM_NEW_EMAC_TAH) */ + +/* Tx lock BHs */ +static void emac_parse_tx_error(struct emac_instance *dev, u16 ctrl) +{ + struct emac_error_stats *st = &dev->estats; + + DBG(dev, "BD TX error %04x" NL, ctrl); + + ++st->tx_bd_errors; + if (ctrl & EMAC_TX_ST_BFCS) + ++st->tx_bd_bad_fcs; + if (ctrl & EMAC_TX_ST_LCS) + ++st->tx_bd_carrier_loss; + if (ctrl & EMAC_TX_ST_ED) + ++st->tx_bd_excessive_deferral; + if (ctrl & EMAC_TX_ST_EC) + ++st->tx_bd_excessive_collisions; + if (ctrl & EMAC_TX_ST_LC) + ++st->tx_bd_late_collision; + if (ctrl & EMAC_TX_ST_MC) + ++st->tx_bd_multple_collisions; + if (ctrl & EMAC_TX_ST_SC) + ++st->tx_bd_single_collision; + if (ctrl & EMAC_TX_ST_UR) + ++st->tx_bd_underrun; + if (ctrl & EMAC_TX_ST_SQE) + ++st->tx_bd_sqe; +} + +static void emac_poll_tx(void *param) +{ + struct emac_instance *dev = param; + u32 bad_mask; + + DBG2(dev, "poll_tx, %d %d" NL, dev->tx_cnt, dev->ack_slot); + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + bad_mask = EMAC_IS_BAD_TX_TAH; + else + bad_mask = EMAC_IS_BAD_TX; + + netif_tx_lock_bh(dev->ndev); + if (dev->tx_cnt) { + u16 ctrl; + int slot = dev->ack_slot, n = 0; + again: + ctrl = dev->tx_desc[slot].ctrl; + if (!(ctrl & MAL_TX_CTRL_READY)) { + struct sk_buff *skb = dev->tx_skb[slot]; + ++n; + + if (skb) { + dev_kfree_skb(skb); + dev->tx_skb[slot] = NULL; + } + slot = (slot + 1) % NUM_TX_BUFF; + + if (unlikely(ctrl & bad_mask)) + emac_parse_tx_error(dev, ctrl); + + if (--dev->tx_cnt) + goto again; + } + if (n) { + dev->ack_slot = slot; + if (netif_queue_stopped(dev->ndev) && + dev->tx_cnt < EMAC_TX_WAKEUP_THRESH) + netif_wake_queue(dev->ndev); + + DBG2(dev, "tx %d pkts" NL, n); + } + } + netif_tx_unlock_bh(dev->ndev); +} + +static inline void emac_recycle_rx_skb(struct emac_instance *dev, int slot, + int len) +{ + struct sk_buff *skb = dev->rx_skb[slot]; + + DBG2(dev, "recycle %d %d" NL, slot, len); + + if (len) + dma_map_single(&dev->ofdev->dev, skb->data - 2, + EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE); + + dev->rx_desc[slot].data_len = 0; + wmb(); + dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | + (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); +} + +static void emac_parse_rx_error(struct emac_instance *dev, u16 ctrl) +{ + struct emac_error_stats *st = &dev->estats; + + DBG(dev, "BD RX error %04x" NL, ctrl); + + ++st->rx_bd_errors; + if (ctrl & EMAC_RX_ST_OE) + ++st->rx_bd_overrun; + if (ctrl & EMAC_RX_ST_BP) + ++st->rx_bd_bad_packet; + if (ctrl & EMAC_RX_ST_RP) + ++st->rx_bd_runt_packet; + if (ctrl & EMAC_RX_ST_SE) + ++st->rx_bd_short_event; + if (ctrl & EMAC_RX_ST_AE) + ++st->rx_bd_alignment_error; + if (ctrl & EMAC_RX_ST_BFCS) + ++st->rx_bd_bad_fcs; + if (ctrl & EMAC_RX_ST_PTL) + ++st->rx_bd_packet_too_long; + if (ctrl & EMAC_RX_ST_ORE) + ++st->rx_bd_out_of_range; + if (ctrl & EMAC_RX_ST_IRE) + ++st->rx_bd_in_range; +} + +static inline void emac_rx_csum(struct emac_instance *dev, + struct sk_buff *skb, u16 ctrl) +{ +#ifdef CONFIG_IBM_NEW_EMAC_TAH + if (!ctrl && dev->tah_dev) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + ++dev->stats.rx_packets_csum; + } +#endif +} + +static inline int emac_rx_sg_append(struct emac_instance *dev, int slot) +{ + if (likely(dev->rx_sg_skb != NULL)) { + int len = dev->rx_desc[slot].data_len; + int tot_len = dev->rx_sg_skb->len + len; + + if (unlikely(tot_len + 2 > dev->rx_skb_size)) { + ++dev->estats.rx_dropped_mtu; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } else { + cacheable_memcpy(dev->rx_sg_skb->tail, + dev->rx_skb[slot]->data, len); + skb_put(dev->rx_sg_skb, len); + emac_recycle_rx_skb(dev, slot, len); + return 0; + } + } + emac_recycle_rx_skb(dev, slot, 0); + return -1; +} + +/* NAPI poll context */ +static int emac_poll_rx(void *param, int budget) +{ + struct emac_instance *dev = param; + int slot = dev->rx_slot, received = 0; + + DBG2(dev, "poll_rx(%d)" NL, budget); + + again: + while (budget > 0) { + int len; + struct sk_buff *skb; + u16 ctrl = dev->rx_desc[slot].ctrl; + + if (ctrl & MAL_RX_CTRL_EMPTY) + break; + + skb = dev->rx_skb[slot]; + mb(); + len = dev->rx_desc[slot].data_len; + + if (unlikely(!MAL_IS_SINGLE_RX(ctrl))) + goto sg; + + ctrl &= EMAC_BAD_RX_MASK; + if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { + emac_parse_rx_error(dev, ctrl); + ++dev->estats.rx_dropped_error; + emac_recycle_rx_skb(dev, slot, 0); + len = 0; + goto next; + } + + if (len && len < EMAC_RX_COPY_THRESH) { + struct sk_buff *copy_skb = + alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC); + if (unlikely(!copy_skb)) + goto oom; + + skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2); + cacheable_memcpy(copy_skb->data - 2, skb->data - 2, + len + 2); + emac_recycle_rx_skb(dev, slot, len); + skb = copy_skb; + } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) + goto oom; + + skb_put(skb, len); + push_packet: + skb->dev = dev->ndev; + skb->protocol = eth_type_trans(skb, dev->ndev); + emac_rx_csum(dev, skb, ctrl); + + if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) + ++dev->estats.rx_dropped_stack; + next: + ++dev->stats.rx_packets; + skip: + dev->stats.rx_bytes += len; + slot = (slot + 1) % NUM_RX_BUFF; + --budget; + ++received; + continue; + sg: + if (ctrl & MAL_RX_CTRL_FIRST) { + BUG_ON(dev->rx_sg_skb); + if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) { + DBG(dev, "rx OOM %d" NL, slot); + ++dev->estats.rx_dropped_oom; + emac_recycle_rx_skb(dev, slot, 0); + } else { + dev->rx_sg_skb = skb; + skb_put(skb, len); + } + } else if (!emac_rx_sg_append(dev, slot) && + (ctrl & MAL_RX_CTRL_LAST)) { + + skb = dev->rx_sg_skb; + dev->rx_sg_skb = NULL; + + ctrl &= EMAC_BAD_RX_MASK; + if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { + emac_parse_rx_error(dev, ctrl); + ++dev->estats.rx_dropped_error; + dev_kfree_skb(skb); + len = 0; + } else + goto push_packet; + } + goto skip; + oom: + DBG(dev, "rx OOM %d" NL, slot); + /* Drop the packet and recycle skb */ + ++dev->estats.rx_dropped_oom; + emac_recycle_rx_skb(dev, slot, 0); + goto next; + } + + if (received) { + DBG2(dev, "rx %d BDs" NL, received); + dev->rx_slot = slot; + } + + if (unlikely(budget && test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags))) { + mb(); + if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) { + DBG2(dev, "rx restart" NL); + received = 0; + goto again; + } + + if (dev->rx_sg_skb) { + DBG2(dev, "dropping partial rx packet" NL); + ++dev->estats.rx_dropped_error; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } + + clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + mal_enable_rx_channel(dev->mal, dev->mal_rx_chan); + emac_rx_enable(dev); + dev->rx_slot = 0; + } + return received; +} + +/* NAPI poll context */ +static int emac_peek_rx(void *param) +{ + struct emac_instance *dev = param; + + return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY); +} + +/* NAPI poll context */ +static int emac_peek_rx_sg(void *param) +{ + struct emac_instance *dev = param; + + int slot = dev->rx_slot; + while (1) { + u16 ctrl = dev->rx_desc[slot].ctrl; + if (ctrl & MAL_RX_CTRL_EMPTY) + return 0; + else if (ctrl & MAL_RX_CTRL_LAST) + return 1; + + slot = (slot + 1) % NUM_RX_BUFF; + + /* I'm just being paranoid here :) */ + if (unlikely(slot == dev->rx_slot)) + return 0; + } +} + +/* Hard IRQ */ +static void emac_rxde(void *param) +{ + struct emac_instance *dev = param; + + ++dev->estats.rx_stopped; + emac_rx_disable_async(dev); +} + +/* Hard IRQ */ +static irqreturn_t emac_irq(int irq, void *dev_instance) +{ + struct emac_instance *dev = dev_instance; + struct emac_regs __iomem *p = dev->emacp; + struct emac_error_stats *st = &dev->estats; + u32 isr; + + spin_lock(&dev->lock); + + isr = in_be32(&p->isr); + out_be32(&p->isr, isr); + + DBG(dev, "isr = %08x" NL, isr); + + if (isr & EMAC4_ISR_TXPE) + ++st->tx_parity; + if (isr & EMAC4_ISR_RXPE) + ++st->rx_parity; + if (isr & EMAC4_ISR_TXUE) + ++st->tx_underrun; + if (isr & EMAC4_ISR_RXOE) + ++st->rx_fifo_overrun; + if (isr & EMAC_ISR_OVR) + ++st->rx_overrun; + if (isr & EMAC_ISR_BP) + ++st->rx_bad_packet; + if (isr & EMAC_ISR_RP) + ++st->rx_runt_packet; + if (isr & EMAC_ISR_SE) + ++st->rx_short_event; + if (isr & EMAC_ISR_ALE) + ++st->rx_alignment_error; + if (isr & EMAC_ISR_BFCS) + ++st->rx_bad_fcs; + if (isr & EMAC_ISR_PTLE) + ++st->rx_packet_too_long; + if (isr & EMAC_ISR_ORE) + ++st->rx_out_of_range; + if (isr & EMAC_ISR_IRE) + ++st->rx_in_range; + if (isr & EMAC_ISR_SQE) + ++st->tx_sqe; + if (isr & EMAC_ISR_TE) + ++st->tx_errors; + + spin_unlock(&dev->lock); + + return IRQ_HANDLED; +} + +static struct net_device_stats *emac_stats(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + struct emac_stats *st = &dev->stats; + struct emac_error_stats *est = &dev->estats; + struct net_device_stats *nst = &dev->nstats; + unsigned long flags; + + DBG2(dev, "stats" NL); + + /* Compute "legacy" statistics */ + spin_lock_irqsave(&dev->lock, flags); + nst->rx_packets = (unsigned long)st->rx_packets; + nst->rx_bytes = (unsigned long)st->rx_bytes; + nst->tx_packets = (unsigned long)st->tx_packets; + nst->tx_bytes = (unsigned long)st->tx_bytes; + nst->rx_dropped = (unsigned long)(est->rx_dropped_oom + + est->rx_dropped_error + + est->rx_dropped_resize + + est->rx_dropped_mtu); + nst->tx_dropped = (unsigned long)est->tx_dropped; + + nst->rx_errors = (unsigned long)est->rx_bd_errors; + nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun + + est->rx_fifo_overrun + + est->rx_overrun); + nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error + + est->rx_alignment_error); + nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs + + est->rx_bad_fcs); + nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet + + est->rx_bd_short_event + + est->rx_bd_packet_too_long + + est->rx_bd_out_of_range + + est->rx_bd_in_range + + est->rx_runt_packet + + est->rx_short_event + + est->rx_packet_too_long + + est->rx_out_of_range + + est->rx_in_range); + + nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors); + nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun + + est->tx_underrun); + nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss; + nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral + + est->tx_bd_excessive_collisions + + est->tx_bd_late_collision + + est->tx_bd_multple_collisions); + spin_unlock_irqrestore(&dev->lock, flags); + return nst; +} + +static struct mal_commac_ops emac_commac_ops = { + .poll_tx = &emac_poll_tx, + .poll_rx = &emac_poll_rx, + .peek_rx = &emac_peek_rx, + .rxde = &emac_rxde, +}; + +static struct mal_commac_ops emac_commac_sg_ops = { + .poll_tx = &emac_poll_tx, + .poll_rx = &emac_poll_rx, + .peek_rx = &emac_peek_rx_sg, + .rxde = &emac_rxde, +}; + +/* Ethtool support */ +static int emac_ethtool_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct emac_instance *dev = netdev_priv(ndev); + + cmd->supported = dev->phy.features; + cmd->port = PORT_MII; + cmd->phy_address = dev->phy.address; + cmd->transceiver = + dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL; + + mutex_lock(&dev->link_lock); + cmd->advertising = dev->phy.advertising; + cmd->autoneg = dev->phy.autoneg; + cmd->speed = dev->phy.speed; + cmd->duplex = dev->phy.duplex; + mutex_unlock(&dev->link_lock); + + return 0; +} + +static int emac_ethtool_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct emac_instance *dev = netdev_priv(ndev); + u32 f = dev->phy.features; + + DBG(dev, "set_settings(%d, %d, %d, 0x%08x)" NL, + cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising); + + /* Basic sanity checks */ + if (dev->phy.address < 0) + return -EOPNOTSUPP; + if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) + return -EINVAL; + if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) + return -EINVAL; + if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_DISABLE) { + switch (cmd->speed) { + case SPEED_10: + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_10baseT_Half)) + return -EINVAL; + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_10baseT_Full)) + return -EINVAL; + break; + case SPEED_100: + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_100baseT_Half)) + return -EINVAL; + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_100baseT_Full)) + return -EINVAL; + break; + case SPEED_1000: + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_1000baseT_Half)) + return -EINVAL; + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_1000baseT_Full)) + return -EINVAL; + break; + default: + return -EINVAL; + } + + mutex_lock(&dev->link_lock); + dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed, + cmd->duplex); + mutex_unlock(&dev->link_lock); + + } else { + if (!(f & SUPPORTED_Autoneg)) + return -EINVAL; + + mutex_lock(&dev->link_lock); + dev->phy.def->ops->setup_aneg(&dev->phy, + (cmd->advertising & f) | + (dev->phy.advertising & + (ADVERTISED_Pause | + ADVERTISED_Asym_Pause))); + mutex_unlock(&dev->link_lock); + } + emac_force_link_update(dev); + + return 0; +} + +static void emac_ethtool_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *rp) +{ + rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF; + rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF; +} + +static void emac_ethtool_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + struct emac_instance *dev = netdev_priv(ndev); + + mutex_lock(&dev->link_lock); + if ((dev->phy.features & SUPPORTED_Autoneg) && + (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause))) + pp->autoneg = 1; + + if (dev->phy.duplex == DUPLEX_FULL) { + if (dev->phy.pause) + pp->rx_pause = pp->tx_pause = 1; + else if (dev->phy.asym_pause) + pp->tx_pause = 1; + } + mutex_unlock(&dev->link_lock); +} + +static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + + return dev->tah_dev != 0; +} + +static int emac_get_regs_len(struct emac_instance *dev) +{ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + return sizeof(struct emac_ethtool_regs_subhdr) + + EMAC4_ETHTOOL_REGS_SIZE; + else + return sizeof(struct emac_ethtool_regs_subhdr) + + EMAC_ETHTOOL_REGS_SIZE; +} + +static int emac_ethtool_get_regs_len(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + int size; + + size = sizeof(struct emac_ethtool_regs_hdr) + + emac_get_regs_len(dev) + mal_get_regs_len(dev->mal); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + size += zmii_get_regs_len(dev->zmii_dev); + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + size += rgmii_get_regs_len(dev->rgmii_dev); + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + size += tah_get_regs_len(dev->tah_dev); + + return size; +} + +static void *emac_dump_regs(struct emac_instance *dev, void *buf) +{ + struct emac_ethtool_regs_subhdr *hdr = buf; + + hdr->index = dev->cell_index; + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) { + hdr->version = EMAC4_ETHTOOL_REGS_VER; + memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE); + return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE); + } else { + hdr->version = EMAC_ETHTOOL_REGS_VER; + memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE); + return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE); + } +} + +static void emac_ethtool_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *buf) +{ + struct emac_instance *dev = netdev_priv(ndev); + struct emac_ethtool_regs_hdr *hdr = buf; + + hdr->components = 0; + buf = hdr + 1; + + buf = mal_dump_regs(dev->mal, buf); + buf = emac_dump_regs(dev, buf); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) { + hdr->components |= EMAC_ETHTOOL_REGS_ZMII; + buf = zmii_dump_regs(dev->zmii_dev, buf); + } + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) { + hdr->components |= EMAC_ETHTOOL_REGS_RGMII; + buf = rgmii_dump_regs(dev->rgmii_dev, buf); + } + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) { + hdr->components |= EMAC_ETHTOOL_REGS_TAH; + buf = tah_dump_regs(dev->tah_dev, buf); + } +} + +static int emac_ethtool_nway_reset(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + int res = 0; + + DBG(dev, "nway_reset" NL); + + if (dev->phy.address < 0) + return -EOPNOTSUPP; + + mutex_lock(&dev->link_lock); + if (!dev->phy.autoneg) { + res = -EINVAL; + goto out; + } + + dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising); + out: + mutex_unlock(&dev->link_lock); + emac_force_link_update(dev); + return res; +} + +static int emac_ethtool_get_stats_count(struct net_device *ndev) +{ + return EMAC_ETHTOOL_STATS_COUNT; +} + +static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset, + u8 * buf) +{ + if (stringset == ETH_SS_STATS) + memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys)); +} + +static void emac_ethtool_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *estats, + u64 * tmp_stats) +{ + struct emac_instance *dev = netdev_priv(ndev); + + memcpy(tmp_stats, &dev->stats, sizeof(dev->stats)); + tmp_stats += sizeof(dev->stats) / sizeof(u64); + memcpy(tmp_stats, &dev->estats, sizeof(dev->estats)); +} + +static void emac_ethtool_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct emac_instance *dev = netdev_priv(ndev); + + strcpy(info->driver, "ibm_emac"); + strcpy(info->version, DRV_VERSION); + info->fw_version[0] = '\0'; + sprintf(info->bus_info, "PPC 4xx EMAC-%d %s", + dev->cell_index, dev->ofdev->node->full_name); + info->n_stats = emac_ethtool_get_stats_count(ndev); + info->regdump_len = emac_ethtool_get_regs_len(ndev); +} + +static const struct ethtool_ops emac_ethtool_ops = { + .get_settings = emac_ethtool_get_settings, + .set_settings = emac_ethtool_set_settings, + .get_drvinfo = emac_ethtool_get_drvinfo, + + .get_regs_len = emac_ethtool_get_regs_len, + .get_regs = emac_ethtool_get_regs, + + .nway_reset = emac_ethtool_nway_reset, + + .get_ringparam = emac_ethtool_get_ringparam, + .get_pauseparam = emac_ethtool_get_pauseparam, + + .get_rx_csum = emac_ethtool_get_rx_csum, + + .get_strings = emac_ethtool_get_strings, + .get_stats_count = emac_ethtool_get_stats_count, + .get_ethtool_stats = emac_ethtool_get_ethtool_stats, + + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, +}; + +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; + + DBG(dev, "ioctl %08x" NL, cmd); + + if (dev->phy.address < 0) + return -EOPNOTSUPP; + + 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]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +struct emac_depentry { + u32 phandle; + struct device_node *node; + struct of_device *ofdev; + void *drvdata; +}; + +#define EMAC_DEP_MAL_IDX 0 +#define EMAC_DEP_ZMII_IDX 1 +#define EMAC_DEP_RGMII_IDX 2 +#define EMAC_DEP_TAH_IDX 3 +#define EMAC_DEP_MDIO_IDX 4 +#define EMAC_DEP_PREV_IDX 5 +#define EMAC_DEP_COUNT 6 + +static int __devinit emac_check_deps(struct emac_instance *dev, + struct emac_depentry *deps) +{ + int i, there = 0; + struct device_node *np; + + for (i = 0; i < EMAC_DEP_COUNT; i++) { + /* no dependency on that item, allright */ + if (deps[i].phandle == 0) { + there++; + continue; + } + /* special case for blist as the dependency might go away */ + if (i == EMAC_DEP_PREV_IDX) { + np = *(dev->blist - 1); + if (np == NULL) { + deps[i].phandle = 0; + there++; + continue; + } + if (deps[i].node == NULL) + deps[i].node = of_node_get(np); + } + if (deps[i].node == NULL) + deps[i].node = of_find_node_by_phandle(deps[i].phandle); + if (deps[i].node == NULL) + continue; + if (deps[i].ofdev == NULL) + deps[i].ofdev = of_find_device_by_node(deps[i].node); + if (deps[i].ofdev == NULL) + continue; + if (deps[i].drvdata == NULL) + deps[i].drvdata = dev_get_drvdata(&deps[i].ofdev->dev); + if (deps[i].drvdata != NULL) + there++; + } + return (there == EMAC_DEP_COUNT); +} + +static void emac_put_deps(struct emac_instance *dev) +{ + if (dev->mal_dev) + of_dev_put(dev->mal_dev); + if (dev->zmii_dev) + of_dev_put(dev->zmii_dev); + if (dev->rgmii_dev) + of_dev_put(dev->rgmii_dev); + if (dev->mdio_dev) + of_dev_put(dev->mdio_dev); + if (dev->tah_dev) + of_dev_put(dev->tah_dev); +} + +static int __devinit emac_of_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + /* We are only intereted in device addition */ + if (action == BUS_NOTIFY_BOUND_DRIVER) + wake_up_all(&emac_probe_wait); + return 0; +} + +static struct notifier_block emac_of_bus_notifier = { + .notifier_call = emac_of_bus_notify +}; + +static int __devinit emac_wait_deps(struct emac_instance *dev) +{ + struct emac_depentry deps[EMAC_DEP_COUNT]; + int i, err; + + memset(&deps, 0, sizeof(deps)); + + deps[EMAC_DEP_MAL_IDX].phandle = dev->mal_ph; + deps[EMAC_DEP_ZMII_IDX].phandle = dev->zmii_ph; + deps[EMAC_DEP_RGMII_IDX].phandle = dev->rgmii_ph; + if (dev->tah_ph) + deps[EMAC_DEP_TAH_IDX].phandle = dev->tah_ph; + if (dev->mdio_ph) + deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph; + if (dev->blist && dev->blist > emac_boot_list) + deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu; + bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier); + wait_event_timeout(emac_probe_wait, + emac_check_deps(dev, deps), + EMAC_PROBE_DEP_TIMEOUT); + bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier); + err = emac_check_deps(dev, deps) ? 0 : -ENODEV; + for (i = 0; i < EMAC_DEP_COUNT; i++) { + if (deps[i].node) + of_node_put(deps[i].node); + if (err && deps[i].ofdev) + of_dev_put(deps[i].ofdev); + } + if (err == 0) { + dev->mal_dev = deps[EMAC_DEP_MAL_IDX].ofdev; + dev->zmii_dev = deps[EMAC_DEP_ZMII_IDX].ofdev; + dev->rgmii_dev = deps[EMAC_DEP_RGMII_IDX].ofdev; + dev->tah_dev = deps[EMAC_DEP_TAH_IDX].ofdev; + dev->mdio_dev = deps[EMAC_DEP_MDIO_IDX].ofdev; + } + if (deps[EMAC_DEP_PREV_IDX].ofdev) + of_dev_put(deps[EMAC_DEP_PREV_IDX].ofdev); + return err; +} + +static int __devinit emac_read_uint_prop(struct device_node *np, const char *name, + u32 *val, int fatal) +{ + int len; + const u32 *prop = of_get_property(np, name, &len); + if (prop == NULL || len < sizeof(u32)) { + if (fatal) + printk(KERN_ERR "%s: missing %s property\n", + np->full_name, name); + return -ENODEV; + } + *val = *prop; + return 0; +} + +static int __devinit emac_init_phy(struct emac_instance *dev) +{ + struct device_node *np = dev->ofdev->node; + struct net_device *ndev = dev->ndev; + u32 phy_map, adv; + int i; + + dev->phy.dev = ndev; + dev->phy.mode = dev->phy_mode; + + /* PHY-less configuration. + * XXX I probably should move these settings to the dev tree + */ + if (dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) { + emac_reset(dev); + + /* PHY-less configuration. + * XXX I probably should move these settings to the dev tree + */ + dev->phy.address = -1; + dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; + dev->phy.pause = 1; + + return 0; + } + + mutex_lock(&emac_phy_map_lock); + phy_map = dev->phy_map | busy_phy_map; + + DBG(dev, "PHY maps %08x %08x" NL, dev->phy_map, busy_phy_map); + + dev->phy.mdio_read = emac_mdio_read; + dev->phy.mdio_write = emac_mdio_write; + + /* Configure EMAC with defaults so we can at least use MDIO + * This is needed mostly for 440GX + */ + if (emac_phy_gpcs(dev->phy.mode)) { + /* XXX + * Make GPCS PHY address equal to EMAC index. + * We probably should take into account busy_phy_map + * and/or phy_map here. + * + * Note that the busy_phy_map is currently global + * while it should probably be per-ASIC... + */ + dev->phy.address = dev->cell_index; + } + + emac_configure(dev); + + if (dev->phy_address != 0xffffffff) + phy_map = ~(1 << dev->phy_address); + + for (i = 0; i < 0x20; phy_map >>= 1, ++i) + if (!(phy_map & 1)) { + int r; + busy_phy_map |= 1 << i; + + /* Quick check if there is a PHY at the address */ + r = emac_mdio_read(dev->ndev, i, MII_BMCR); + if (r == 0xffff || r < 0) + continue; + if (!emac_mii_phy_probe(&dev->phy, i)) + break; + } + mutex_unlock(&emac_phy_map_lock); + if (i == 0x20) { + printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name); + return -ENXIO; + } + + /* Init PHY */ + if (dev->phy.def->ops->init) + dev->phy.def->ops->init(&dev->phy); + + /* Disable any PHY features not supported by the platform */ + dev->phy.def->features &= ~dev->phy_feat_exc; + + /* Setup initial link parameters */ + if (dev->phy.features & SUPPORTED_Autoneg) { + adv = dev->phy.features; + if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x)) + adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; + /* Restart autonegotiation */ + dev->phy.def->ops->setup_aneg(&dev->phy, adv); + } else { + u32 f = dev->phy.def->features; + int speed = SPEED_10, fd = DUPLEX_HALF; + + /* Select highest supported speed/duplex */ + if (f & SUPPORTED_1000baseT_Full) { + speed = SPEED_1000; + fd = DUPLEX_FULL; + } else if (f & SUPPORTED_1000baseT_Half) + speed = SPEED_1000; + else if (f & SUPPORTED_100baseT_Full) { + speed = SPEED_100; + fd = DUPLEX_FULL; + } else if (f & SUPPORTED_100baseT_Half) + speed = SPEED_100; + else if (f & SUPPORTED_10baseT_Full) + fd = DUPLEX_FULL; + + /* Force link parameters */ + dev->phy.def->ops->setup_forced(&dev->phy, speed, fd); + } + return 0; +} + +static int __devinit emac_init_config(struct emac_instance *dev) +{ + struct device_node *np = dev->ofdev->node; + const void *p; + unsigned int plen; + const char *pm, *phy_modes[] = { + [PHY_MODE_NA] = "", + [PHY_MODE_MII] = "mii", + [PHY_MODE_RMII] = "rmii", + [PHY_MODE_SMII] = "smii", + [PHY_MODE_RGMII] = "rgmii", + [PHY_MODE_TBI] = "tbi", + [PHY_MODE_GMII] = "gmii", + [PHY_MODE_RTBI] = "rtbi", + [PHY_MODE_SGMII] = "sgmii", + }; + + /* Read config from device-tree */ + if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "mal-tx-channel", &dev->mal_tx_chan, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "mal-rx-channel", &dev->mal_rx_chan, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "cell-index", &dev->cell_index, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "max-frame-size", &dev->max_mtu, 0)) + dev->max_mtu = 1500; + if (emac_read_uint_prop(np, "rx-fifo-size", &dev->rx_fifo_size, 0)) + dev->rx_fifo_size = 2048; + if (emac_read_uint_prop(np, "tx-fifo-size", &dev->tx_fifo_size, 0)) + dev->tx_fifo_size = 2048; + if (emac_read_uint_prop(np, "rx-fifo-size-gige", &dev->rx_fifo_size_gige, 0)) + dev->rx_fifo_size_gige = dev->rx_fifo_size; + if (emac_read_uint_prop(np, "tx-fifo-size-gige", &dev->tx_fifo_size_gige, 0)) + dev->tx_fifo_size_gige = dev->tx_fifo_size; + if (emac_read_uint_prop(np, "phy-address", &dev->phy_address, 0)) + dev->phy_address = 0xffffffff; + if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0)) + dev->phy_map = 0xffffffff; + if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0)) + dev->tah_ph = 0; + if (emac_read_uint_prop(np, "tah-channel", &dev->tah_port, 0)) + dev->tah_ph = 0; + if (emac_read_uint_prop(np, "mdio-device", &dev->mdio_ph, 0)) + dev->mdio_ph = 0; + if (emac_read_uint_prop(np, "zmii-device", &dev->zmii_ph, 0)) + dev->zmii_ph = 0;; + if (emac_read_uint_prop(np, "zmii-channel", &dev->zmii_port, 0)) + dev->zmii_port = 0xffffffff;; + if (emac_read_uint_prop(np, "rgmii-device", &dev->rgmii_ph, 0)) + dev->rgmii_ph = 0;; + if (emac_read_uint_prop(np, "rgmii-channel", &dev->rgmii_port, 0)) + dev->rgmii_port = 0xffffffff;; + if (emac_read_uint_prop(np, "fifo-entry-size", &dev->fifo_entry_size, 0)) + dev->fifo_entry_size = 16; + if (emac_read_uint_prop(np, "mal-burst-size", &dev->mal_burst_size, 0)) + dev->mal_burst_size = 256; + + /* PHY mode needs some decoding */ + dev->phy_mode = PHY_MODE_NA; + pm = of_get_property(np, "phy-mode", &plen); + if (pm != NULL) { + int i; + for (i = 0; i < ARRAY_SIZE(phy_modes); i++) + if (!strcasecmp(pm, phy_modes[i])) { + dev->phy_mode = i; + break; + } + } + + /* Backward compat with non-final DT */ + if (dev->phy_mode == PHY_MODE_NA && pm != NULL && plen == 4) { + u32 nmode = *(const u32 *)pm; + if (nmode > PHY_MODE_NA && nmode <= PHY_MODE_SGMII) + dev->phy_mode = nmode; + } + + /* Check EMAC version */ + if (of_device_is_compatible(np, "ibm,emac4")) + dev->features |= EMAC_FTR_EMAC4; + if (of_device_is_compatible(np, "ibm,emac-axon") + || of_device_is_compatible(np, "ibm,emac-440epx")) + dev->features |= EMAC_FTR_HAS_AXON_STACR + | EMAC_FTR_STACR_OC_INVERT; + if (of_device_is_compatible(np, "ibm,emac-440spe")) + dev->features |= EMAC_FTR_STACR_OC_INVERT; + + /* Fixup some feature bits based on the device tree and verify + * we have support for them compiled in + */ + if (dev->tah_ph != 0) { +#ifdef CONFIG_IBM_NEW_EMAC_TAH + dev->features |= EMAC_FTR_HAS_TAH; +#else + printk(KERN_ERR "%s: TAH support not enabled !\n", + np->full_name); + return -ENXIO; +#endif + } + + if (dev->zmii_ph != 0) { +#ifdef CONFIG_IBM_NEW_EMAC_ZMII + dev->features |= EMAC_FTR_HAS_ZMII; +#else + printk(KERN_ERR "%s: ZMII support not enabled !\n", + np->full_name); + return -ENXIO; +#endif + } + + if (dev->rgmii_ph != 0) { +#ifdef CONFIG_IBM_NEW_EMAC_RGMII + dev->features |= EMAC_FTR_HAS_RGMII; +#else + printk(KERN_ERR "%s: RGMII support not enabled !\n", + np->full_name); + return -ENXIO; +#endif + } + + /* Read MAC-address */ + p = of_get_property(np, "local-mac-address", NULL); + if (p == NULL) { + printk(KERN_ERR "%s: Can't find local-mac-address property\n", + np->full_name); + return -ENXIO; + } + memcpy(dev->ndev->dev_addr, p, 6); + + DBG(dev, "features : 0x%08x / 0x%08x\n", dev->features, EMAC_FTRS_POSSIBLE); + DBG(dev, "tx_fifo_size : %d (%d gige)\n", dev->tx_fifo_size, dev->tx_fifo_size_gige); + DBG(dev, "rx_fifo_size : %d (%d gige)\n", dev->rx_fifo_size, dev->rx_fifo_size_gige); + DBG(dev, "max_mtu : %d\n", dev->max_mtu); + DBG(dev, "OPB freq : %d\n", dev->opb_bus_freq); + + return 0; +} + +static int __devinit emac_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct net_device *ndev; + struct emac_instance *dev; + struct device_node *np = ofdev->node; + struct device_node **blist = NULL; + int err, i; + + /* Find ourselves in the bootlist if we are there */ + for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++) + if (emac_boot_list[i] == np) + blist = &emac_boot_list[i]; + + /* Allocate our net_device structure */ + err = -ENOMEM; + ndev = alloc_etherdev(sizeof(struct emac_instance)); + if (!ndev) { + printk(KERN_ERR "%s: could not allocate ethernet device!\n", + np->full_name); + goto err_gone; + } + dev = netdev_priv(ndev); + dev->ndev = ndev; + dev->ofdev = ofdev; + dev->blist = blist; + SET_MODULE_OWNER(ndev); + SET_NETDEV_DEV(ndev, &ofdev->dev); + + /* Initialize some embedded data structures */ + mutex_init(&dev->mdio_lock); + mutex_init(&dev->link_lock); + spin_lock_init(&dev->lock); + INIT_WORK(&dev->reset_work, emac_reset_work); + + /* Init various config data based on device-tree */ + err = emac_init_config(dev); + if (err != 0) + goto err_free; + + /* Get interrupts. EMAC irq is mandatory, WOL irq is optional */ + dev->emac_irq = irq_of_parse_and_map(np, 0); + dev->wol_irq = irq_of_parse_and_map(np, 1); + if (dev->emac_irq == NO_IRQ) { + printk(KERN_ERR "%s: Can't map main interrupt\n", np->full_name); + goto err_free; + } + ndev->irq = dev->emac_irq; + + /* Map EMAC regs */ + if (of_address_to_resource(np, 0, &dev->rsrc_regs)) { + printk(KERN_ERR "%s: Can't get registers address\n", + np->full_name); + goto err_irq_unmap; + } + // TODO : request_mem_region + dev->emacp = ioremap(dev->rsrc_regs.start, sizeof(struct emac_regs)); + if (dev->emacp == NULL) { + printk(KERN_ERR "%s: Can't map device registers!\n", + np->full_name); + err = -ENOMEM; + goto err_irq_unmap; + } + + /* Wait for dependent devices */ + err = emac_wait_deps(dev); + if (err) { + printk(KERN_ERR + "%s: Timeout waiting for dependent devices\n", + np->full_name); + /* display more info about what's missing ? */ + goto err_reg_unmap; + } + dev->mal = dev_get_drvdata(&dev->mal_dev->dev); + if (dev->mdio_dev != NULL) + dev->mdio_instance = dev_get_drvdata(&dev->mdio_dev->dev); + + /* Register with MAL */ + dev->commac.ops = &emac_commac_ops; + dev->commac.dev = dev; + dev->commac.tx_chan_mask = MAL_CHAN_MASK(dev->mal_tx_chan); + dev->commac.rx_chan_mask = MAL_CHAN_MASK(dev->mal_rx_chan); + err = mal_register_commac(dev->mal, &dev->commac); + if (err) { + printk(KERN_ERR "%s: failed to register with mal %s!\n", + np->full_name, dev->mal_dev->node->full_name); + goto err_rel_deps; + } + dev->rx_skb_size = emac_rx_skb_size(ndev->mtu); + dev->rx_sync_size = emac_rx_sync_size(ndev->mtu); + + /* Get pointers to BD rings */ + dev->tx_desc = + dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, dev->mal_tx_chan); + dev->rx_desc = + dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, dev->mal_rx_chan); + + DBG(dev, "tx_desc %p" NL, dev->tx_desc); + DBG(dev, "rx_desc %p" NL, dev->rx_desc); + + /* Clean rings */ + memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor)); + memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor)); + + /* Attach to ZMII, if needed */ + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) && + (err = zmii_attach(dev->zmii_dev, dev->zmii_port, &dev->phy_mode)) != 0) + goto err_unreg_commac; + + /* Attach to RGMII, if needed */ + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII) && + (err = rgmii_attach(dev->rgmii_dev, dev->rgmii_port, dev->phy_mode)) != 0) + goto err_detach_zmii; + + /* Attach to TAH, if needed */ + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH) && + (err = tah_attach(dev->tah_dev, dev->tah_port)) != 0) + goto err_detach_rgmii; + + /* Set some link defaults before we can find out real parameters */ + dev->phy.speed = SPEED_100; + dev->phy.duplex = DUPLEX_FULL; + dev->phy.autoneg = AUTONEG_DISABLE; + dev->phy.pause = dev->phy.asym_pause = 0; + dev->stop_timeout = STOP_TIMEOUT_100; + INIT_DELAYED_WORK(&dev->link_work, emac_link_timer); + + /* Find PHY if any */ + err = emac_init_phy(dev); + if (err != 0) + goto err_detach_tah; + + /* Fill in the driver function table */ + ndev->open = &emac_open; +#ifdef CONFIG_IBM_NEW_EMAC_TAH + if (dev->tah_dev) { + ndev->hard_start_xmit = &emac_start_xmit_sg; + ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + } else +#endif + ndev->hard_start_xmit = &emac_start_xmit; + ndev->tx_timeout = &emac_tx_timeout; + ndev->watchdog_timeo = 5 * HZ; + ndev->stop = &emac_close; + ndev->get_stats = &emac_stats; + ndev->set_multicast_list = &emac_set_multicast_list; + ndev->do_ioctl = &emac_ioctl; + if (emac_phy_supports_gige(dev->phy_mode)) { + ndev->change_mtu = &emac_change_mtu; + dev->commac.ops = &emac_commac_sg_ops; + } + SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); + + netif_carrier_off(ndev); + netif_stop_queue(ndev); + + err = register_netdev(ndev); + if (err) { + printk(KERN_ERR "%s: failed to register net device (%d)!\n", + np->full_name, err); + goto err_detach_tah; + } + + /* Set our drvdata last as we don't want them visible until we are + * fully initialized + */ + wmb(); + dev_set_drvdata(&ofdev->dev, dev); + + /* There's a new kid in town ! Let's tell everybody */ + wake_up_all(&emac_probe_wait); + + + printk(KERN_INFO + "%s: EMAC-%d %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, dev->cell_index, np->full_name, + ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], + ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + + if (dev->phy.address >= 0) + printk("%s: found %s PHY (0x%02x)\n", ndev->name, + dev->phy.def->name, dev->phy.address); + + emac_dbg_register(dev); + + /* Life is good */ + return 0; + + /* I have a bad feeling about this ... */ + + err_detach_tah: + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + tah_detach(dev->tah_dev, dev->tah_port); + err_detach_rgmii: + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_detach(dev->rgmii_dev, dev->rgmii_port); + err_detach_zmii: + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_detach(dev->zmii_dev, dev->zmii_port); + err_unreg_commac: + mal_unregister_commac(dev->mal, &dev->commac); + err_rel_deps: + emac_put_deps(dev); + err_reg_unmap: + iounmap(dev->emacp); + err_irq_unmap: + if (dev->wol_irq != NO_IRQ) + irq_dispose_mapping(dev->wol_irq); + if (dev->emac_irq != NO_IRQ) + irq_dispose_mapping(dev->emac_irq); + err_free: + kfree(ndev); + err_gone: + /* if we were on the bootlist, remove us as we won't show up and + * wake up all waiters to notify them in case they were waiting + * on us + */ + if (blist) { + *blist = NULL; + wake_up_all(&emac_probe_wait); + } + return err; +} + +static int __devexit emac_remove(struct of_device *ofdev) +{ + struct emac_instance *dev = dev_get_drvdata(&ofdev->dev); + + DBG(dev, "remove" NL); + + dev_set_drvdata(&ofdev->dev, NULL); + + unregister_netdev(dev->ndev); + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + tah_detach(dev->tah_dev, dev->tah_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_detach(dev->rgmii_dev, dev->rgmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_detach(dev->zmii_dev, dev->zmii_port); + + mal_unregister_commac(dev->mal, &dev->commac); + emac_put_deps(dev); + + emac_dbg_unregister(dev); + iounmap(dev->emacp); + + if (dev->wol_irq != NO_IRQ) + irq_dispose_mapping(dev->wol_irq); + if (dev->emac_irq != NO_IRQ) + irq_dispose_mapping(dev->emac_irq); + + kfree(dev->ndev); + + return 0; +} + +/* XXX Features in here should be replaced by properties... */ +static struct of_device_id emac_match[] = +{ + { + .type = "network", + .compatible = "ibm,emac", + }, + { + .type = "network", + .compatible = "ibm,emac4", + }, + {}, +}; + +static struct of_platform_driver emac_driver = { + .name = "emac", + .match_table = emac_match, + + .probe = emac_probe, + .remove = emac_remove, +}; + +static void __init emac_make_bootlist(void) +{ + struct device_node *np = NULL; + int j, max, i = 0, k; + int cell_indices[EMAC_BOOT_LIST_SIZE]; + + /* Collect EMACs */ + while((np = of_find_all_nodes(np)) != NULL) { + const u32 *idx; + + if (of_match_node(emac_match, np) == NULL) + continue; + if (of_get_property(np, "unused", NULL)) + continue; + idx = of_get_property(np, "cell-index", NULL); + if (idx == NULL) + continue; + cell_indices[i] = *idx; + emac_boot_list[i++] = of_node_get(np); + if (i >= EMAC_BOOT_LIST_SIZE) { + of_node_put(np); + break; + } + } + max = i; + + /* Bubble sort them (doh, what a creative algorithm :-) */ + for (i = 0; max > 1 && (i < (max - 1)); i++) + for (j = i; j < max; j++) { + if (cell_indices[i] > cell_indices[j]) { + np = emac_boot_list[i]; + emac_boot_list[i] = emac_boot_list[j]; + emac_boot_list[j] = np; + k = cell_indices[i]; + cell_indices[i] = cell_indices[j]; + cell_indices[j] = k; + } + } +} + +static int __init emac_init(void) +{ + int rc; + + printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n"); + + /* Init debug stuff */ + emac_init_debug(); + + /* Build EMAC boot list */ + emac_make_bootlist(); + + /* Init submodules */ + rc = mal_init(); + if (rc) + goto err; + rc = zmii_init(); + if (rc) + goto err_mal; + rc = rgmii_init(); + if (rc) + goto err_zmii; + rc = tah_init(); + if (rc) + goto err_rgmii; + rc = of_register_platform_driver(&emac_driver); + if (rc) + goto err_tah; + + return 0; + + err_tah: + tah_exit(); + err_rgmii: + rgmii_exit(); + err_zmii: + zmii_exit(); + err_mal: + mal_exit(); + err: + return rc; +} + +static void __exit emac_exit(void) +{ + int i; + + of_unregister_platform_driver(&emac_driver); + + tah_exit(); + rgmii_exit(); + zmii_exit(); + mal_exit(); + emac_fini_debug(); + + /* Destroy EMAC boot list */ + for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++) + if (emac_boot_list[i]) + of_node_put(emac_boot_list[i]); +} + +module_init(emac_init); +module_exit(emac_exit); diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h new file mode 100644 index 000000000000..4011803117ca --- /dev/null +++ b/drivers/net/ibm_newemac/core.h @@ -0,0 +1,355 @@ +/* + * drivers/net/ibm_newemac/core.h + * + * Driver for PowerPC 4xx on-chip ethernet controller. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Johnnie Peters + * Copyright 2000, 2001 MontaVista Softare 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. + * + */ +#ifndef __IBM_NEWEMAC_CORE_H +#define __IBM_NEWEMAC_CORE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "emac.h" +#include "phy.h" +#include "zmii.h" +#include "rgmii.h" +#include "mal.h" +#include "tah.h" +#include "debug.h" + +#define NUM_TX_BUFF CONFIG_IBM_NEW_EMAC_TXB +#define NUM_RX_BUFF CONFIG_IBM_NEW_EMAC_RXB + +/* Simple sanity check */ +#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256 +#error Invalid number of buffer descriptors (greater than 256) +#endif + +#define EMAC_MIN_MTU 46 + +/* Maximum L2 header length (VLAN tagged, no FCS) */ +#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4) + +/* RX BD size for the given MTU */ +static inline int emac_rx_size(int mtu) +{ + if (mtu > ETH_DATA_LEN) + return MAL_MAX_RX_SIZE; + else + return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD); +} + +#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment()) + +#define EMAC_RX_SKB_HEADROOM \ + EMAC_DMA_ALIGN(CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM) + +/* Size of RX skb for the given MTU */ +static inline int emac_rx_skb_size(int mtu) +{ + int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu)); + return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM; +} + +/* RX DMA sync size */ +static inline int emac_rx_sync_size(int mtu) +{ + return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2); +} + +/* Driver statistcs is split into two parts to make it more cache friendly: + * - normal statistics (packet count, etc) + * - error statistics + * + * When statistics is requested by ethtool, these parts are concatenated, + * normal one goes first. + * + * Please, keep these structures in sync with emac_stats_keys. + */ + +/* Normal TX/RX Statistics */ +struct emac_stats { + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + u64 rx_packets_csum; + u64 tx_packets_csum; +}; + +/* Error statistics */ +struct emac_error_stats { + u64 tx_undo; + + /* Software RX Errors */ + u64 rx_dropped_stack; + u64 rx_dropped_oom; + u64 rx_dropped_error; + u64 rx_dropped_resize; + u64 rx_dropped_mtu; + u64 rx_stopped; + /* BD reported RX errors */ + u64 rx_bd_errors; + u64 rx_bd_overrun; + u64 rx_bd_bad_packet; + u64 rx_bd_runt_packet; + u64 rx_bd_short_event; + u64 rx_bd_alignment_error; + u64 rx_bd_bad_fcs; + u64 rx_bd_packet_too_long; + u64 rx_bd_out_of_range; + u64 rx_bd_in_range; + /* EMAC IRQ reported RX errors */ + u64 rx_parity; + u64 rx_fifo_overrun; + u64 rx_overrun; + u64 rx_bad_packet; + u64 rx_runt_packet; + u64 rx_short_event; + u64 rx_alignment_error; + u64 rx_bad_fcs; + u64 rx_packet_too_long; + u64 rx_out_of_range; + u64 rx_in_range; + + /* Software TX Errors */ + u64 tx_dropped; + /* BD reported TX errors */ + u64 tx_bd_errors; + u64 tx_bd_bad_fcs; + u64 tx_bd_carrier_loss; + u64 tx_bd_excessive_deferral; + u64 tx_bd_excessive_collisions; + u64 tx_bd_late_collision; + u64 tx_bd_multple_collisions; + u64 tx_bd_single_collision; + u64 tx_bd_underrun; + u64 tx_bd_sqe; + /* EMAC IRQ reported TX errors */ + u64 tx_parity; + u64 tx_underrun; + u64 tx_sqe; + u64 tx_errors; +}; + +#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct emac_stats) + \ + sizeof(struct emac_error_stats)) \ + / sizeof(u64)) + +struct emac_instance { + struct net_device *ndev; + struct resource rsrc_regs; + struct emac_regs __iomem *emacp; + struct of_device *ofdev; + struct device_node **blist; /* bootlist entry */ + + /* MAL linkage */ + u32 mal_ph; + struct of_device *mal_dev; + u32 mal_rx_chan; + u32 mal_tx_chan; + struct mal_instance *mal; + struct mal_commac commac; + + /* PHY infos */ + u32 phy_mode; + u32 phy_map; + u32 phy_address; + u32 phy_feat_exc; + struct mii_phy phy; + struct mutex link_lock; + struct delayed_work link_work; + int link_polling; + + /* Shared MDIO if any */ + u32 mdio_ph; + struct of_device *mdio_dev; + struct emac_instance *mdio_instance; + struct mutex mdio_lock; + + /* ZMII infos if any */ + u32 zmii_ph; + u32 zmii_port; + struct of_device *zmii_dev; + + /* RGMII infos if any */ + u32 rgmii_ph; + u32 rgmii_port; + struct of_device *rgmii_dev; + + /* TAH infos if any */ + u32 tah_ph; + u32 tah_port; + struct of_device *tah_dev; + + /* IRQs */ + int wol_irq; + int emac_irq; + + /* OPB bus frequency in Mhz */ + u32 opb_bus_freq; + + /* Cell index within an ASIC (for clk mgmnt) */ + u32 cell_index; + + /* Max supported MTU */ + u32 max_mtu; + + /* Feature bits (from probe table) */ + unsigned int features; + + /* Tx and Rx fifo sizes & other infos in bytes */ + u32 tx_fifo_size; + u32 tx_fifo_size_gige; + u32 rx_fifo_size; + u32 rx_fifo_size_gige; + u32 fifo_entry_size; + u32 mal_burst_size; /* move to MAL ? */ + + /* Descriptor management + */ + struct mal_descriptor *tx_desc; + int tx_cnt; + int tx_slot; + int ack_slot; + + struct mal_descriptor *rx_desc; + int rx_slot; + struct sk_buff *rx_sg_skb; /* 1 */ + int rx_skb_size; + int rx_sync_size; + + struct sk_buff *tx_skb[NUM_TX_BUFF]; + struct sk_buff *rx_skb[NUM_RX_BUFF]; + + /* Stats + */ + struct emac_error_stats estats; + struct net_device_stats nstats; + struct emac_stats stats; + + /* Misc + */ + int reset_failed; + int stop_timeout; /* in us */ + int no_mcast; + int mcast_pending; + struct work_struct reset_work; + spinlock_t lock; +}; + +/* + * Features of various EMAC implementations + */ + +/* + * No flow control on 40x according to the original driver + */ +#define EMAC_FTR_NO_FLOW_CONTROL_40x 0x00000001 +/* + * Cell is an EMAC4 + */ +#define EMAC_FTR_EMAC4 0x00000002 +/* + * For the 440SPe, AMCC inexplicably changed the polarity of + * the "operation complete" bit in the MII control register. + */ +#define EMAC_FTR_STACR_OC_INVERT 0x00000004 +/* + * Set if we have a TAH. + */ +#define EMAC_FTR_HAS_TAH 0x00000008 +/* + * Set if we have a ZMII. + */ +#define EMAC_FTR_HAS_ZMII 0x00000010 +/* + * Set if we have a RGMII. + */ +#define EMAC_FTR_HAS_RGMII 0x00000020 +/* + * Set if we have axon-type STACR + */ +#define EMAC_FTR_HAS_AXON_STACR 0x00000040 + + +/* Right now, we don't quite handle the always/possible masks on the + * most optimal way as we don't have a way to say something like + * always EMAC4. Patches welcome. + */ +enum { + EMAC_FTRS_ALWAYS = 0, + + EMAC_FTRS_POSSIBLE = +#ifdef CONFIG_IBM_NEW_EMAC_EMAC4 + EMAC_FTR_EMAC4 | EMAC_FTR_HAS_AXON_STACR | + EMAC_FTR_STACR_OC_INVERT | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_TAH + EMAC_FTR_HAS_TAH | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_ZMII + EMAC_FTR_HAS_ZMII | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_RGMII + EMAC_FTR_HAS_RGMII | +#endif + 0, +}; + +static inline int emac_has_feature(struct emac_instance *dev, + unsigned long feature) +{ + return (EMAC_FTRS_ALWAYS & feature) || + (EMAC_FTRS_POSSIBLE & dev->features & feature); +} + + +/* Ethtool get_regs complex data. + * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH + * when available. + * + * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr, + * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers. + * Each register component is preceded with emac_ethtool_regs_subhdr. + * Order of the optional headers follows their relative bit posititions + * in emac_ethtool_regs_hdr.components + */ +#define EMAC_ETHTOOL_REGS_ZMII 0x00000001 +#define EMAC_ETHTOOL_REGS_RGMII 0x00000002 +#define EMAC_ETHTOOL_REGS_TAH 0x00000004 + +struct emac_ethtool_regs_hdr { + u32 components; +}; + +struct emac_ethtool_regs_subhdr { + u32 version; + u32 index; +}; + +#endif /* __IBM_NEWEMAC_CORE_H */ diff --git a/drivers/net/ibm_newemac/debug.c b/drivers/net/ibm_newemac/debug.c new file mode 100644 index 000000000000..170524ee0f19 --- /dev/null +++ b/drivers/net/ibm_newemac/debug.c @@ -0,0 +1,238 @@ +/* + * drivers/net/ibm_newemac/debug.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. + * + * Copyright (c) 2004, 2005 Zultys Technologies + * Eugene Surovegin or + * + * 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 "core.h" + +static spinlock_t emac_dbg_lock = SPIN_LOCK_UNLOCKED; + +static void emac_desc_dump(struct emac_instance *p) +{ + int i; + printk("** EMAC %s TX BDs **\n" + " tx_cnt = %d tx_slot = %d ack_slot = %d\n", + p->ofdev->node->full_name, + p->tx_cnt, p->tx_slot, p->ack_slot); + for (i = 0; i < NUM_TX_BUFF / 2; ++i) + printk + ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", + i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ', + p->tx_desc[i].ctrl, p->tx_desc[i].data_len, + NUM_TX_BUFF / 2 + i, + p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr, + p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ', + p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl, + p->tx_desc[NUM_TX_BUFF / 2 + i].data_len); + + printk("** EMAC %s RX BDs **\n" + " rx_slot = %d flags = 0x%lx rx_skb_size = %d rx_sync_size = %d\n" + " rx_sg_skb = 0x%p\n", + p->ofdev->node->full_name, + p->rx_slot, p->commac.flags, p->rx_skb_size, + p->rx_sync_size, p->rx_sg_skb); + for (i = 0; i < NUM_RX_BUFF / 2; ++i) + printk + ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", + i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ', + p->rx_desc[i].ctrl, p->rx_desc[i].data_len, + NUM_RX_BUFF / 2 + i, + p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr, + p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ', + p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl, + p->rx_desc[NUM_RX_BUFF / 2 + i].data_len); +} + +static void emac_mac_dump(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + + printk("** EMAC %s registers **\n" + "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n" + "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n" + "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n" + "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x " + "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n" + "LSA = %04x%08x IPGVR = 0x%04x\n" + "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n" + "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n", + dev->ofdev->node->full_name, in_be32(&p->mr0), in_be32(&p->mr1), + in_be32(&p->tmr0), in_be32(&p->tmr1), + in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser), + in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid), + in_be32(&p->vtci), + in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3), + in_be32(&p->iaht4), + in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3), + in_be32(&p->gaht4), + in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr), + in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr), + in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr) + ); + + emac_desc_dump(dev); +} + +static void emac_mal_dump(struct mal_instance *mal) +{ + int i; + + printk("** MAL %s Registers **\n" + "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n" + "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n" + "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n", + mal->ofdev->node->full_name, + get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR), + get_mal_dcrn(mal, MAL_IER), + get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR), + get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR), + get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR), + get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR) + ); + + printk("TX|"); + for (i = 0; i < mal->num_tx_chans; ++i) { + if (i && !(i % 4)) + printk("\n "); + printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i))); + } + printk("\nRX|"); + for (i = 0; i < mal->num_rx_chans; ++i) { + if (i && !(i % 4)) + printk("\n "); + printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i))); + } + printk("\n "); + for (i = 0; i < mal->num_rx_chans; ++i) { + u32 r = get_mal_dcrn(mal, MAL_RCBS(i)); + if (i && !(i % 3)) + printk("\n "); + printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16); + } + printk("\n"); +} + +static struct emac_instance *__emacs[4]; +static struct mal_instance *__mals[1]; + +void emac_dbg_register(struct emac_instance *dev) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&emac_dbg_lock, flags); + for (i = 0; i < ARRAY_SIZE(__emacs); i++) + if (__emacs[i] == NULL) { + __emacs[i] = dev; + break; + } + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +void emac_dbg_unregister(struct emac_instance *dev) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&emac_dbg_lock, flags); + for (i = 0; i < ARRAY_SIZE(__emacs); i++) + if (__emacs[i] == dev) { + __emacs[i] = NULL; + break; + } + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +void mal_dbg_register(struct mal_instance *mal) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&emac_dbg_lock, flags); + for (i = 0; i < ARRAY_SIZE(__mals); i++) + if (__mals[i] == NULL) { + __mals[i] = mal; + break; + } + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +void mal_dbg_unregister(struct mal_instance *mal) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&emac_dbg_lock, flags); + for (i = 0; i < ARRAY_SIZE(__mals); i++) + if (__mals[i] == mal) { + __mals[i] = NULL; + break; + } + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +void emac_dbg_dump_all(void) +{ + unsigned int i; + unsigned long flags; + + spin_lock_irqsave(&emac_dbg_lock, flags); + + for (i = 0; i < ARRAY_SIZE(__mals); ++i) + if (__mals[i]) + emac_mal_dump(__mals[i]); + + for (i = 0; i < ARRAY_SIZE(__emacs); ++i) + if (__emacs[i]) + emac_mac_dump(__emacs[i]); + + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +#if defined(CONFIG_MAGIC_SYSRQ) +static void emac_sysrq_handler(int key, struct tty_struct *tty) +{ + emac_dbg_dump_all(); +} + +static struct sysrq_key_op emac_sysrq_op = { + .handler = emac_sysrq_handler, + .help_msg = "emaC", + .action_msg = "Show EMAC(s) status", +}; + +int __init emac_init_debug(void) +{ + return register_sysrq_key('c', &emac_sysrq_op); +} + +void __exit emac_fini_debug(void) +{ + unregister_sysrq_key('c', &emac_sysrq_op); +} + +#else +int __init emac_init_debug(void) +{ + return 0; +} +void __exit emac_fini_debug(void) +{ +} +#endif /* CONFIG_MAGIC_SYSRQ */ diff --git a/drivers/net/ibm_newemac/debug.h b/drivers/net/ibm_newemac/debug.h new file mode 100644 index 000000000000..1dd2dcbc157f --- /dev/null +++ b/drivers/net/ibm_newemac/debug.h @@ -0,0 +1,78 @@ +/* + * drivers/net/ibm_newemac/debug.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. + * + * Copyright (c) 2004, 2005 Zultys Technologies + * Eugene Surovegin or + * + * 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 __IBM_NEWEMAC_DEBUG_H +#define __IBM_NEWEMAC_DEBUG_H + +#include + +#include "core.h" + +#if defined(CONFIG_IBM_NEW_EMAC_DEBUG) + +struct emac_instance; +struct mal_instance; + +extern void emac_dbg_register(struct emac_instance *dev); +extern void emac_dbg_unregister(struct emac_instance *dev); +extern void mal_dbg_register(struct mal_instance *mal); +extern void mal_dbg_unregister(struct mal_instance *mal); +extern int emac_init_debug(void) __init; +extern void emac_fini_debug(void) __exit; +extern void emac_dbg_dump_all(void); + +# define DBG_LEVEL 1 + +#else + +# define emac_dbg_register(x) do { } while(0) +# define emac_dbg_unregister(x) do { } while(0) +# define mal_dbg_register(x) do { } while(0) +# define mal_dbg_unregister(x) do { } while(0) +# define emac_init_debug() do { } while(0) +# define emac_fini_debug() do { } while(0) +# define emac_dbg_dump_all() do { } while(0) + +# define DBG_LEVEL 0 + +#endif + +#define EMAC_DBG(dev, name, fmt, arg...) \ + printk(KERN_DEBUG #name "%s: " fmt, dev->ofdev->node->full_name, ## arg) + +#if DBG_LEVEL > 0 +# define DBG(d,f,x...) EMAC_DBG(d, emac, f, ##x) +# define MAL_DBG(d,f,x...) EMAC_DBG(d, mal, f, ##x) +# define ZMII_DBG(d,f,x...) EMAC_DBG(d, zmii, f, ##x) +# define RGMII_DBG(d,f,x...) EMAC_DBG(d, rgmii, f, ##x) +# define NL "\n" +#else +# define DBG(f,x...) ((void)0) +# define MAL_DBG(d,f,x...) ((void)0) +# define ZMII_DBG(d,f,x...) ((void)0) +# define RGMII_DBG(d,f,x...) ((void)0) +#endif +#if DBG_LEVEL > 1 +# define DBG2(d,f,x...) DBG(d,f, ##x) +# define MAL_DBG2(d,f,x...) MAL_DBG(d,f, ##x) +# define ZMII_DBG2(d,f,x...) ZMII_DBG(d,f, ##x) +# define RGMII_DBG2(d,f,x...) RGMII_DBG(d,f, ##x) +#else +# define DBG2(f,x...) ((void)0) +# define MAL_DBG2(d,f,x...) ((void)0) +# define ZMII_DBG2(d,f,x...) ((void)0) +# define RGMII_DBG2(d,f,x...) ((void)0) +#endif + +#endif /* __IBM_NEWEMAC_DEBUG_H */ diff --git a/drivers/net/ibm_newemac/emac.h b/drivers/net/ibm_newemac/emac.h new file mode 100644 index 000000000000..bef92efeeadc --- /dev/null +++ b/drivers/net/ibm_newemac/emac.h @@ -0,0 +1,268 @@ +/* + * drivers/net/ibm_newemac/emac.h + * + * Register definitions for PowerPC 4xx on-chip ethernet contoller + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Matt Porter + * Armin Kuster + * Copyright 2002-2004 MontaVista Software 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. + * + */ +#ifndef __IBM_NEWEMAC_H +#define __IBM_NEWEMAC_H + +#include + +/* EMAC registers Write Access rules */ +struct emac_regs { + u32 mr0; /* special */ + u32 mr1; /* Reset */ + u32 tmr0; /* special */ + u32 tmr1; /* special */ + u32 rmr; /* Reset */ + u32 isr; /* Always */ + u32 iser; /* Reset */ + u32 iahr; /* Reset, R, T */ + u32 ialr; /* Reset, R, T */ + u32 vtpid; /* Reset, R, T */ + u32 vtci; /* Reset, R, T */ + u32 ptr; /* Reset, T */ + u32 iaht1; /* Reset, R */ + u32 iaht2; /* Reset, R */ + u32 iaht3; /* Reset, R */ + u32 iaht4; /* Reset, R */ + u32 gaht1; /* Reset, R */ + u32 gaht2; /* Reset, R */ + u32 gaht3; /* Reset, R */ + u32 gaht4; /* Reset, R */ + u32 lsah; + u32 lsal; + u32 ipgvr; /* Reset, T */ + u32 stacr; /* special */ + u32 trtr; /* special */ + u32 rwmr; /* Reset */ + u32 octx; + u32 ocrx; + u32 ipcr; +}; + +/* + * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY) + */ +#define PHY_MODE_NA 0 +#define PHY_MODE_MII 1 +#define PHY_MODE_RMII 2 +#define PHY_MODE_SMII 3 +#define PHY_MODE_RGMII 4 +#define PHY_MODE_TBI 5 +#define PHY_MODE_GMII 6 +#define PHY_MODE_RTBI 7 +#define PHY_MODE_SGMII 8 + + +#define EMAC_ETHTOOL_REGS_VER 0 +#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32)) +#define EMAC4_ETHTOOL_REGS_VER 1 +#define EMAC4_ETHTOOL_REGS_SIZE sizeof(struct emac_regs) + +/* EMACx_MR0 */ +#define EMAC_MR0_RXI 0x80000000 +#define EMAC_MR0_TXI 0x40000000 +#define EMAC_MR0_SRST 0x20000000 +#define EMAC_MR0_TXE 0x10000000 +#define EMAC_MR0_RXE 0x08000000 +#define EMAC_MR0_WKE 0x04000000 + +/* EMACx_MR1 */ +#define EMAC_MR1_FDE 0x80000000 +#define EMAC_MR1_ILE 0x40000000 +#define EMAC_MR1_VLE 0x20000000 +#define EMAC_MR1_EIFC 0x10000000 +#define EMAC_MR1_APP 0x08000000 +#define EMAC_MR1_IST 0x01000000 + +#define EMAC_MR1_MF_MASK 0x00c00000 +#define EMAC_MR1_MF_10 0x00000000 +#define EMAC_MR1_MF_100 0x00400000 +#define EMAC_MR1_MF_1000 0x00800000 +#define EMAC_MR1_MF_1000GPCS 0x00c00000 +#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6) + +#define EMAC_MR1_RFS_4K 0x00300000 +#define EMAC_MR1_RFS_16K 0x00000000 +#define EMAC_MR1_TFS_2K 0x00080000 +#define EMAC_MR1_TR0_MULT 0x00008000 +#define EMAC_MR1_JPSM 0x00000000 +#define EMAC_MR1_MWSW_001 0x00000000 +#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT) + + +#define EMAC4_MR1_RFS_2K 0x00100000 +#define EMAC4_MR1_RFS_4K 0x00180000 +#define EMAC4_MR1_RFS_16K 0x00280000 +#define EMAC4_MR1_TFS_2K 0x00020000 +#define EMAC4_MR1_TFS_4K 0x00030000 +#define EMAC4_MR1_TR 0x00008000 +#define EMAC4_MR1_MWSW_001 0x00001000 +#define EMAC4_MR1_JPSM 0x00000800 +#define EMAC4_MR1_OBCI_MASK 0x00000038 +#define EMAC4_MR1_OBCI_50 0x00000000 +#define EMAC4_MR1_OBCI_66 0x00000008 +#define EMAC4_MR1_OBCI_83 0x00000010 +#define EMAC4_MR1_OBCI_100 0x00000018 +#define EMAC4_MR1_OBCI_100P 0x00000020 +#define EMAC4_MR1_OBCI(freq) ((freq) <= 50 ? EMAC4_MR1_OBCI_50 : \ + (freq) <= 66 ? EMAC4_MR1_OBCI_66 : \ + (freq) <= 83 ? EMAC4_MR1_OBCI_83 : \ + (freq) <= 100 ? EMAC4_MR1_OBCI_100 : \ + EMAC4_MR1_OBCI_100P) + +/* EMACx_TMR0 */ +#define EMAC_TMR0_GNP 0x80000000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC4_TMR0_TFAE_2_32 0x00000001 +#define EMAC4_TMR0_TFAE_4_64 0x00000002 +#define EMAC4_TMR0_TFAE_8_128 0x00000003 +#define EMAC4_TMR0_TFAE_16_256 0x00000004 +#define EMAC4_TMR0_TFAE_32_512 0x00000005 +#define EMAC4_TMR0_TFAE_64_1024 0x00000006 +#define EMAC4_TMR0_TFAE_128_2048 0x00000007 +#define EMAC4_TMR0_DEFAULT EMAC4_TMR0_TFAE_2_32 +#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT) +#define EMAC4_TMR0_XMIT (EMAC_TMR0_GNP | EMAC4_TMR0_DEFAULT) + +/* EMACx_TMR1 */ + +#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16)) +#define EMAC4_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14)) + +/* EMACx_RMR */ +#define EMAC_RMR_SP 0x80000000 +#define EMAC_RMR_SFCS 0x40000000 +#define EMAC_RMR_RRP 0x20000000 +#define EMAC_RMR_RFP 0x10000000 +#define EMAC_RMR_ROP 0x08000000 +#define EMAC_RMR_RPIR 0x04000000 +#define EMAC_RMR_PPP 0x02000000 +#define EMAC_RMR_PME 0x01000000 +#define EMAC_RMR_PMME 0x00800000 +#define EMAC_RMR_IAE 0x00400000 +#define EMAC_RMR_MIAE 0x00200000 +#define EMAC_RMR_BAE 0x00100000 +#define EMAC_RMR_MAE 0x00080000 +#define EMAC_RMR_BASE 0x00000000 +#define EMAC4_RMR_RFAF_2_32 0x00000001 +#define EMAC4_RMR_RFAF_4_64 0x00000002 +#define EMAC4_RMR_RFAF_8_128 0x00000003 +#define EMAC4_RMR_RFAF_16_256 0x00000004 +#define EMAC4_RMR_RFAF_32_512 0x00000005 +#define EMAC4_RMR_RFAF_64_1024 0x00000006 +#define EMAC4_RMR_RFAF_128_2048 0x00000007 +#define EMAC4_RMR_BASE EMAC4_RMR_RFAF_128_2048 + +/* EMACx_ISR & EMACx_ISER */ +#define EMAC4_ISR_TXPE 0x20000000 +#define EMAC4_ISR_RXPE 0x10000000 +#define EMAC4_ISR_TXUE 0x08000000 +#define EMAC4_ISR_RXOE 0x04000000 +#define EMAC_ISR_OVR 0x02000000 +#define EMAC_ISR_PP 0x01000000 +#define EMAC_ISR_BP 0x00800000 +#define EMAC_ISR_RP 0x00400000 +#define EMAC_ISR_SE 0x00200000 +#define EMAC_ISR_ALE 0x00100000 +#define EMAC_ISR_BFCS 0x00080000 +#define EMAC_ISR_PTLE 0x00040000 +#define EMAC_ISR_ORE 0x00020000 +#define EMAC_ISR_IRE 0x00010000 +#define EMAC_ISR_SQE 0x00000080 +#define EMAC_ISR_TE 0x00000040 +#define EMAC_ISR_MOS 0x00000002 +#define EMAC_ISR_MOF 0x00000001 + +/* EMACx_STACR */ +#define EMAC_STACR_PHYD_MASK 0xffff +#define EMAC_STACR_PHYD_SHIFT 16 +#define EMAC_STACR_OC 0x00008000 +#define EMAC_STACR_PHYE 0x00004000 +#define EMAC_STACR_STAC_MASK 0x00003000 +#define EMAC_STACR_STAC_READ 0x00001000 +#define EMAC_STACR_STAC_WRITE 0x00002000 +#define EMAC_STACR_OPBC_MASK 0x00000C00 +#define EMAC_STACR_OPBC_50 0x00000000 +#define EMAC_STACR_OPBC_66 0x00000400 +#define EMAC_STACR_OPBC_83 0x00000800 +#define EMAC_STACR_OPBC_100 0x00000C00 +#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \ + (freq) <= 66 ? EMAC_STACR_OPBC_66 : \ + (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100) +#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb) +#define EMAC4_STACR_BASE(opb) 0x00000000 +#define EMAC_STACR_PCDA_MASK 0x1f +#define EMAC_STACR_PCDA_SHIFT 5 +#define EMAC_STACR_PRA_MASK 0x1f +#define EMACX_STACR_STAC_MASK 0x00003800 +#define EMACX_STACR_STAC_READ 0x00001000 +#define EMACX_STACR_STAC_WRITE 0x00000800 +#define EMACX_STACR_STAC_IND_ADDR 0x00002000 +#define EMACX_STACR_STAC_IND_READ 0x00003800 +#define EMACX_STACR_STAC_IND_READINC 0x00003000 +#define EMACX_STACR_STAC_IND_WRITE 0x00002800 + + +/* EMACx_TRTR */ +#define EMAC_TRTR_SHIFT_EMAC4 27 +#define EMAC_TRTR_SHIFT 24 + +/* EMAC specific TX descriptor control fields (write access) */ +#define EMAC_TX_CTRL_GFCS 0x0200 +#define EMAC_TX_CTRL_GP 0x0100 +#define EMAC_TX_CTRL_ISA 0x0080 +#define EMAC_TX_CTRL_RSA 0x0040 +#define EMAC_TX_CTRL_IVT 0x0020 +#define EMAC_TX_CTRL_RVT 0x0010 +#define EMAC_TX_CTRL_TAH_CSUM 0x000e + +/* EMAC specific TX descriptor status fields (read access) */ +#define EMAC_TX_ST_BFCS 0x0200 +#define EMAC_TX_ST_LCS 0x0080 +#define EMAC_TX_ST_ED 0x0040 +#define EMAC_TX_ST_EC 0x0020 +#define EMAC_TX_ST_LC 0x0010 +#define EMAC_TX_ST_MC 0x0008 +#define EMAC_TX_ST_SC 0x0004 +#define EMAC_TX_ST_UR 0x0002 +#define EMAC_TX_ST_SQE 0x0001 +#define EMAC_IS_BAD_TX (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ + EMAC_TX_ST_EC | EMAC_TX_ST_LC | \ + EMAC_TX_ST_MC | EMAC_TX_ST_UR) +#define EMAC_IS_BAD_TX_TAH (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ + EMAC_TX_ST_EC | EMAC_TX_ST_LC) + +/* EMAC specific RX descriptor status fields (read access) */ +#define EMAC_RX_ST_OE 0x0200 +#define EMAC_RX_ST_PP 0x0100 +#define EMAC_RX_ST_BP 0x0080 +#define EMAC_RX_ST_RP 0x0040 +#define EMAC_RX_ST_SE 0x0020 +#define EMAC_RX_ST_AE 0x0010 +#define EMAC_RX_ST_BFCS 0x0008 +#define EMAC_RX_ST_PTL 0x0004 +#define EMAC_RX_ST_ORE 0x0002 +#define EMAC_RX_ST_IRE 0x0001 +#define EMAC_RX_TAH_BAD_CSUM 0x0003 +#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \ + EMAC_RX_ST_RP | EMAC_RX_ST_SE | \ + EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \ + EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \ + EMAC_RX_ST_IRE ) +#endif /* __IBM_NEWEMAC_H */ diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c new file mode 100644 index 000000000000..c4335b7d308c --- /dev/null +++ b/drivers/net/ibm_newemac/mal.c @@ -0,0 +1,728 @@ +/* + * drivers/net/ibm_newemac/mal.c + * + * Memory Access Layer (MAL) support + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Benjamin Herrenschmidt , + * David Gibson , + * + * Armin Kuster + * Copyright 2002 MontaVista Softare 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 "core.h" + +static int mal_count; + +int __devinit mal_register_commac(struct mal_instance *mal, + struct mal_commac *commac) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "reg(%08x, %08x)" NL, + commac->tx_chan_mask, commac->rx_chan_mask); + + /* Don't let multiple commacs claim the same channel(s) */ + if ((mal->tx_chan_mask & commac->tx_chan_mask) || + (mal->rx_chan_mask & commac->rx_chan_mask)) { + spin_unlock_irqrestore(&mal->lock, flags); + printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n", + mal->index); + return -EBUSY; + } + + mal->tx_chan_mask |= commac->tx_chan_mask; + mal->rx_chan_mask |= commac->rx_chan_mask; + list_add(&commac->list, &mal->list); + + spin_unlock_irqrestore(&mal->lock, flags); + + return 0; +} + +void __devexit mal_unregister_commac(struct mal_instance *mal, + struct mal_commac *commac) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "unreg(%08x, %08x)" NL, + commac->tx_chan_mask, commac->rx_chan_mask); + + mal->tx_chan_mask &= ~commac->tx_chan_mask; + mal->rx_chan_mask &= ~commac->rx_chan_mask; + list_del_init(&commac->list); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size) +{ + BUG_ON(channel < 0 || channel >= mal->num_rx_chans || + size > MAL_MAX_RX_SIZE); + + MAL_DBG(mal, "set_rbcs(%d, %lu)" NL, channel, size); + + if (size & 0xf) { + printk(KERN_WARNING + "mal%d: incorrect RX size %lu for the channel %d\n", + mal->index, size, channel); + return -EINVAL; + } + + set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4); + return 0; +} + +int mal_tx_bd_offset(struct mal_instance *mal, int channel) +{ + BUG_ON(channel < 0 || channel >= mal->num_tx_chans); + + return channel * NUM_TX_BUFF; +} + +int mal_rx_bd_offset(struct mal_instance *mal, int channel) +{ + BUG_ON(channel < 0 || channel >= mal->num_rx_chans); + return mal->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF; +} + +void mal_enable_tx_channel(struct mal_instance *mal, int channel) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "enable_tx(%d)" NL, channel); + + set_mal_dcrn(mal, MAL_TXCASR, + get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel)); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +void mal_disable_tx_channel(struct mal_instance *mal, int channel) +{ + set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel)); + + MAL_DBG(mal, "disable_tx(%d)" NL, channel); +} + +void mal_enable_rx_channel(struct mal_instance *mal, int channel) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "enable_rx(%d)" NL, channel); + + set_mal_dcrn(mal, MAL_RXCASR, + get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel)); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +void mal_disable_rx_channel(struct mal_instance *mal, int channel) +{ + set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel)); + + MAL_DBG(mal, "disable_rx(%d)" NL, channel); +} + +void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "poll_add(%p)" NL, commac); + + /* starts disabled */ + set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags); + + list_add_tail(&commac->poll_list, &mal->poll_list); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "poll_del(%p)" NL, commac); + + list_del(&commac->poll_list); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +/* synchronized by mal_poll() */ +static inline void mal_enable_eob_irq(struct mal_instance *mal) +{ + MAL_DBG2(mal, "enable_irq" NL); + + // XXX might want to cache MAL_CFG as the DCR read can be slooooow + set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE); +} + +/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */ +static inline void mal_disable_eob_irq(struct mal_instance *mal) +{ + // XXX might want to cache MAL_CFG as the DCR read can be slooooow + set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE); + + MAL_DBG2(mal, "disable_irq" NL); +} + +static irqreturn_t mal_serr(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + + u32 esr = get_mal_dcrn(mal, MAL_ESR); + + /* Clear the error status register */ + set_mal_dcrn(mal, MAL_ESR, esr); + + MAL_DBG(mal, "SERR %08x" NL, esr); + + if (esr & MAL_ESR_EVB) { + if (esr & MAL_ESR_DE) { + /* We ignore Descriptor error, + * TXDE or RXDE interrupt will be generated anyway. + */ + return IRQ_HANDLED; + } + + if (esr & MAL_ESR_PEIN) { + /* PLB error, it's probably buggy hardware or + * incorrect physical address in BD (i.e. bug) + */ + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: system error, " + "PLB (ESR = 0x%08x)\n", + mal->index, esr); + return IRQ_HANDLED; + } + + /* OPB error, it's probably buggy hardware or incorrect + * EBC setup + */ + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: system error, OPB (ESR = 0x%08x)\n", + mal->index, esr); + } + return IRQ_HANDLED; +} + +static inline void mal_schedule_poll(struct mal_instance *mal) +{ + if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { + MAL_DBG2(mal, "schedule_poll" NL); + mal_disable_eob_irq(mal); + __netif_rx_schedule(&mal->poll_dev); + } else + MAL_DBG2(mal, "already in poll" NL); +} + +static irqreturn_t mal_txeob(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + + u32 r = get_mal_dcrn(mal, MAL_TXEOBISR); + + MAL_DBG2(mal, "txeob %08x" NL, r); + + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_TXEOBISR, r); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_rxeob(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + + u32 r = get_mal_dcrn(mal, MAL_RXEOBISR); + + MAL_DBG2(mal, "rxeob %08x" NL, r); + + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_RXEOBISR, r); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_txde(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + + u32 deir = get_mal_dcrn(mal, MAL_TXDEIR); + set_mal_dcrn(mal, MAL_TXDEIR, deir); + + MAL_DBG(mal, "txde %08x" NL, deir); + + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n", + mal->index, deir); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_rxde(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + struct list_head *l; + + u32 deir = get_mal_dcrn(mal, MAL_RXDEIR); + + MAL_DBG(mal, "rxde %08x" NL, deir); + + list_for_each(l, &mal->list) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); + if (deir & mc->rx_chan_mask) { + set_bit(MAL_COMMAC_RX_STOPPED, &mc->flags); + mc->ops->rxde(mc->dev); + } + } + + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_RXDEIR, deir); + + return IRQ_HANDLED; +} + +void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac) +{ + /* Spinlock-type semantics: only one caller disable poll at a time */ + while (test_and_set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags)) + msleep(1); + + /* Synchronize with the MAL NAPI poller. */ + while (test_bit(__LINK_STATE_RX_SCHED, &mal->poll_dev.state)) + msleep(1); +} + +void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac) +{ + smp_wmb(); + clear_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags); + + // XXX might want to kick a poll now... +} + +static int mal_poll(struct net_device *ndev, int *budget) +{ + struct mal_instance *mal = netdev_priv(ndev); + struct list_head *l; + int rx_work_limit = min(ndev->quota, *budget), received = 0, done; + unsigned long flags; + + MAL_DBG2(mal, "poll(%d) %d ->" NL, *budget, + rx_work_limit); + again: + /* Process TX skbs */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + mc->ops->poll_tx(mc->dev); + } + + /* Process RX skbs. + * + * We _might_ need something more smart here to enforce polling + * fairness. + */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + int n; + if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags))) + continue; + n = mc->ops->poll_rx(mc->dev, rx_work_limit); + if (n) { + received += n; + rx_work_limit -= n; + if (rx_work_limit <= 0) { + done = 0; + // XXX What if this is the last one ? + goto more_work; + } + } + } + + /* We need to disable IRQs to protect from RXDE IRQ here */ + spin_lock_irqsave(&mal->lock, flags); + __netif_rx_complete(ndev); + mal_enable_eob_irq(mal); + spin_unlock_irqrestore(&mal->lock, flags); + + done = 1; + + /* Check for "rotting" packet(s) */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags))) + continue; + if (unlikely(mc->ops->peek_rx(mc->dev) || + test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) { + MAL_DBG2(mal, "rotting packet" NL); + if (netif_rx_reschedule(ndev, received)) + mal_disable_eob_irq(mal); + else + MAL_DBG2(mal, "already in poll list" NL); + + if (rx_work_limit > 0) + goto again; + else + goto more_work; + } + mc->ops->poll_tx(mc->dev); + } + + more_work: + ndev->quota -= received; + *budget -= received; + + MAL_DBG2(mal, "poll() %d <- %d" NL, *budget, + done ? 0 : 1); + + return done ? 0 : 1; +} + +static void mal_reset(struct mal_instance *mal) +{ + int n = 10; + + MAL_DBG(mal, "reset" NL); + + set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR); + + /* Wait for reset to complete (1 system clock) */ + while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n) + --n; + + if (unlikely(!n)) + printk(KERN_ERR "mal%d: reset timeout\n", mal->index); +} + +int mal_get_regs_len(struct mal_instance *mal) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct mal_regs); +} + +void *mal_dump_regs(struct mal_instance *mal, void *buf) +{ + struct emac_ethtool_regs_subhdr *hdr = buf; + struct mal_regs *regs = (struct mal_regs *)(hdr + 1); + int i; + + hdr->version = mal->version; + hdr->index = mal->index; + + regs->tx_count = mal->num_tx_chans; + regs->rx_count = mal->num_rx_chans; + + regs->cfg = get_mal_dcrn(mal, MAL_CFG); + regs->esr = get_mal_dcrn(mal, MAL_ESR); + regs->ier = get_mal_dcrn(mal, MAL_IER); + regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR); + regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR); + regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR); + regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR); + regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR); + regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR); + regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR); + regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR); + + for (i = 0; i < regs->tx_count; ++i) + regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i)); + + for (i = 0; i < regs->rx_count; ++i) { + regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i)); + regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i)); + } + return regs + 1; +} + +static int __devinit mal_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct mal_instance *mal; + int err = 0, i, bd_size; + int index = mal_count++; + const u32 *prop; + u32 cfg; + + mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL); + if (!mal) { + printk(KERN_ERR + "mal%d: out of memory allocating MAL structure!\n", + index); + return -ENOMEM; + } + mal->index = index; + mal->ofdev = ofdev; + mal->version = of_device_is_compatible(ofdev->node, "ibm,mcmal2") ? 2 : 1; + + MAL_DBG(mal, "probe" NL); + + prop = of_get_property(ofdev->node, "num-tx-chans", NULL); + if (prop == NULL) { + printk(KERN_ERR + "mal%d: can't find MAL num-tx-chans property!\n", + index); + err = -ENODEV; + goto fail; + } + mal->num_tx_chans = prop[0]; + + prop = of_get_property(ofdev->node, "num-rx-chans", NULL); + if (prop == NULL) { + printk(KERN_ERR + "mal%d: can't find MAL num-rx-chans property!\n", + index); + err = -ENODEV; + goto fail; + } + mal->num_rx_chans = prop[0]; + + mal->dcr_base = dcr_resource_start(ofdev->node, 0); + if (mal->dcr_base == 0) { + printk(KERN_ERR + "mal%d: can't find DCR resource!\n", index); + err = -ENODEV; + goto fail; + } + mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100); + if (!DCR_MAP_OK(mal->dcr_host)) { + printk(KERN_ERR + "mal%d: failed to map DCRs !\n", index); + err = -ENODEV; + goto fail; + } + + mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0); + mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1); + mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2); + mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3); + mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4); + if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ || + mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ || + mal->rxde_irq == NO_IRQ) { + printk(KERN_ERR + "mal%d: failed to map interrupts !\n", index); + err = -ENODEV; + goto fail_unmap; + } + + INIT_LIST_HEAD(&mal->poll_list); + set_bit(__LINK_STATE_START, &mal->poll_dev.state); + mal->poll_dev.weight = CONFIG_IBM_NEW_EMAC_POLL_WEIGHT; + mal->poll_dev.poll = mal_poll; + mal->poll_dev.priv = mal; + atomic_set(&mal->poll_dev.refcnt, 1); + INIT_LIST_HEAD(&mal->list); + spin_lock_init(&mal->lock); + + /* Load power-on reset defaults */ + mal_reset(mal); + + /* Set the MAL configuration register */ + cfg = (mal->version == 2) ? MAL2_CFG_DEFAULT : MAL1_CFG_DEFAULT; + cfg |= MAL_CFG_PLBB | MAL_CFG_OPBBL | MAL_CFG_LEA; + + /* Current Axon is not happy with priority being non-0, it can + * deadlock, fix it up here + */ + if (of_device_is_compatible(ofdev->node, "ibm,mcmal-axon")) + cfg &= ~(MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10); + + /* Apply configuration */ + set_mal_dcrn(mal, MAL_CFG, cfg); + + /* Allocate space for BD rings */ + BUG_ON(mal->num_tx_chans <= 0 || mal->num_tx_chans > 32); + BUG_ON(mal->num_rx_chans <= 0 || mal->num_rx_chans > 32); + + bd_size = sizeof(struct mal_descriptor) * + (NUM_TX_BUFF * mal->num_tx_chans + + NUM_RX_BUFF * mal->num_rx_chans); + mal->bd_virt = + dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma, + GFP_KERNEL); + if (mal->bd_virt == NULL) { + printk(KERN_ERR + "mal%d: out of memory allocating RX/TX descriptors!\n", + index); + err = -ENOMEM; + goto fail_unmap; + } + memset(mal->bd_virt, 0, bd_size); + + for (i = 0; i < mal->num_tx_chans; ++i) + set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma + + sizeof(struct mal_descriptor) * + mal_tx_bd_offset(mal, i)); + + for (i = 0; i < mal->num_rx_chans; ++i) + set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma + + sizeof(struct mal_descriptor) * + mal_rx_bd_offset(mal, i)); + + err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal); + if (err) + goto fail2; + err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal); + if (err) + goto fail3; + err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); + if (err) + goto fail4; + err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); + if (err) + goto fail5; + err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); + if (err) + goto fail6; + + /* Enable all MAL SERR interrupt sources */ + if (mal->version == 2) + set_mal_dcrn(mal, MAL_IER, MAL2_IER_EVENTS); + else + set_mal_dcrn(mal, MAL_IER, MAL1_IER_EVENTS); + + /* Enable EOB interrupt */ + mal_enable_eob_irq(mal); + + printk(KERN_INFO + "MAL v%d %s, %d TX channels, %d RX channels\n", + mal->version, ofdev->node->full_name, + mal->num_tx_chans, mal->num_rx_chans); + + /* Advertise this instance to the rest of the world */ + wmb(); + dev_set_drvdata(&ofdev->dev, mal); + + mal_dbg_register(mal); + + return 0; + + fail6: + free_irq(mal->rxde_irq, mal); + fail5: + free_irq(mal->txeob_irq, mal); + fail4: + free_irq(mal->txde_irq, mal); + fail3: + free_irq(mal->serr_irq, mal); + fail2: + dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); + fail_unmap: + dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100); + fail: + kfree(mal); + + return err; +} + +static int __devexit mal_remove(struct of_device *ofdev) +{ + struct mal_instance *mal = dev_get_drvdata(&ofdev->dev); + + MAL_DBG(mal, "remove" NL); + + /* Syncronize with scheduled polling, + stolen from net/core/dev.c:dev_close() + */ + clear_bit(__LINK_STATE_START, &mal->poll_dev.state); + netif_poll_disable(&mal->poll_dev); + + if (!list_empty(&mal->list)) { + /* This is *very* bad */ + printk(KERN_EMERG + "mal%d: commac list is not empty on remove!\n", + mal->index); + WARN_ON(1); + } + + dev_set_drvdata(&ofdev->dev, NULL); + + free_irq(mal->serr_irq, mal); + free_irq(mal->txde_irq, mal); + free_irq(mal->txeob_irq, mal); + free_irq(mal->rxde_irq, mal); + free_irq(mal->rxeob_irq, mal); + + mal_reset(mal); + + mal_dbg_unregister(mal); + + dma_free_coherent(&ofdev->dev, + sizeof(struct mal_descriptor) * + (NUM_TX_BUFF * mal->num_tx_chans + + NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt, + mal->bd_dma); + kfree(mal); + + return 0; +} + +static struct of_device_id mal_platform_match[] = +{ + { + .compatible = "ibm,mcmal", + }, + { + .compatible = "ibm,mcmal2", + }, + /* Backward compat */ + { + .type = "mcmal-dma", + .compatible = "ibm,mcmal", + }, + { + .type = "mcmal-dma", + .compatible = "ibm,mcmal2", + }, + {}, +}; + +static struct of_platform_driver mal_of_driver = { + .name = "mcmal", + .match_table = mal_platform_match, + + .probe = mal_probe, + .remove = mal_remove, +}; + +int __init mal_init(void) +{ + return of_register_platform_driver(&mal_of_driver); +} + +void mal_exit(void) +{ + of_unregister_platform_driver(&mal_of_driver); +} diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h new file mode 100644 index 000000000000..57b69dc32e9d --- /dev/null +++ b/drivers/net/ibm_newemac/mal.h @@ -0,0 +1,276 @@ +/* + * drivers/net/ibm_newemac/mal.h + * + * Memory Access Layer (MAL) support + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Copyright 2002 MontaVista Softare 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. + * + */ +#ifndef __IBM_NEWEMAC_MAL_H +#define __IBM_NEWEMAC_MAL_H + +/* + * There are some variations on the MAL, we express them in this driver as + * MAL Version 1 and 2 though that doesn't match any IBM terminology. + * + * We call MAL 1 the version in 405GP, 405GPR, 405EP, 440EP, 440GR and + * NP405H. + * + * We call MAL 2 the version in 440GP, 440GX, 440SP, 440SPE and Axon + * + * The driver expects a "version" property in the emac node containing + * a number 1 or 2. New device-trees for EMAC capable platforms are thus + * required to include that when porting to arch/powerpc. + */ + +/* MALx DCR registers */ +#define MAL_CFG 0x00 +#define MAL_CFG_SR 0x80000000 +#define MAL_CFG_PLBB 0x00004000 +#define MAL_CFG_OPBBL 0x00000080 +#define MAL_CFG_EOPIE 0x00000004 +#define MAL_CFG_LEA 0x00000002 +#define MAL_CFG_SD 0x00000001 + +/* MAL V1 CFG bits */ +#define MAL1_CFG_PLBP_MASK 0x00c00000 +#define MAL1_CFG_PLBP_10 0x00800000 +#define MAL1_CFG_GA 0x00200000 +#define MAL1_CFG_OA 0x00100000 +#define MAL1_CFG_PLBLE 0x00080000 +#define MAL1_CFG_PLBT_MASK 0x00078000 +#define MAL1_CFG_DEFAULT (MAL1_CFG_PLBP_10 | MAL1_CFG_PLBT_MASK) + +/* MAL V2 CFG bits */ +#define MAL2_CFG_RPP_MASK 0x00c00000 +#define MAL2_CFG_RPP_10 0x00800000 +#define MAL2_CFG_RMBS_MASK 0x00300000 +#define MAL2_CFG_WPP_MASK 0x000c0000 +#define MAL2_CFG_WPP_10 0x00080000 +#define MAL2_CFG_WMBS_MASK 0x00030000 +#define MAL2_CFG_PLBLE 0x00008000 +#define MAL2_CFG_DEFAULT (MAL2_CFG_RMBS_MASK | MAL2_CFG_WMBS_MASK | \ + MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10) + +#define MAL_ESR 0x01 +#define MAL_ESR_EVB 0x80000000 +#define MAL_ESR_CIDT 0x40000000 +#define MAL_ESR_CID_MASK 0x3e000000 +#define MAL_ESR_CID_SHIFT 25 +#define MAL_ESR_DE 0x00100000 +#define MAL_ESR_OTE 0x00040000 +#define MAL_ESR_OSE 0x00020000 +#define MAL_ESR_PEIN 0x00010000 +#define MAL_ESR_DEI 0x00000010 +#define MAL_ESR_OTEI 0x00000004 +#define MAL_ESR_OSEI 0x00000002 +#define MAL_ESR_PBEI 0x00000001 + +/* MAL V1 ESR bits */ +#define MAL1_ESR_ONE 0x00080000 +#define MAL1_ESR_ONEI 0x00000008 + +/* MAL V2 ESR bits */ +#define MAL2_ESR_PTE 0x00800000 +#define MAL2_ESR_PRE 0x00400000 +#define MAL2_ESR_PWE 0x00200000 +#define MAL2_ESR_PTEI 0x00000080 +#define MAL2_ESR_PREI 0x00000040 +#define MAL2_ESR_PWEI 0x00000020 + + +#define MAL_IER 0x02 +#define MAL_IER_DE 0x00000010 +#define MAL_IER_OTE 0x00000004 +#define MAL_IER_OE 0x00000002 +#define MAL_IER_PE 0x00000001 +/* MAL V1 IER bits */ +#define MAL1_IER_NWE 0x00000008 +#define MAL1_IER_SOC_EVENTS MAL1_IER_NWE +#define MAL1_IER_EVENTS (MAL1_IER_SOC_EVENTS | MAL_IER_OTE | \ + MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) + +/* MAL V2 IER bits */ +#define MAL2_IER_PT 0x00000080 +#define MAL2_IER_PRE 0x00000040 +#define MAL2_IER_PWE 0x00000020 +#define MAL2_IER_SOC_EVENTS (MAL2_IER_PT | MAL2_IER_PRE | MAL2_IER_PWE) +#define MAL2_IER_EVENTS (MAL2_IER_SOC_EVENTS | MAL_IER_OTE | \ + MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) + + +#define MAL_TXCASR 0x04 +#define MAL_TXCARR 0x05 +#define MAL_TXEOBISR 0x06 +#define MAL_TXDEIR 0x07 +#define MAL_RXCASR 0x10 +#define MAL_RXCARR 0x11 +#define MAL_RXEOBISR 0x12 +#define MAL_RXDEIR 0x13 +#define MAL_TXCTPR(n) ((n) + 0x20) +#define MAL_RXCTPR(n) ((n) + 0x40) +#define MAL_RCBS(n) ((n) + 0x60) + +/* In reality MAL can handle TX buffers up to 4095 bytes long, + * but this isn't a good round number :) --ebs + */ +#define MAL_MAX_TX_SIZE 4080 +#define MAL_MAX_RX_SIZE 4080 + +static inline int mal_rx_size(int len) +{ + len = (len + 0xf) & ~0xf; + return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len; +} + +static inline int mal_tx_chunks(int len) +{ + return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE; +} + +#define MAL_CHAN_MASK(n) (0x80000000 >> (n)) + +/* MAL Buffer Descriptor structure */ +struct mal_descriptor { + u16 ctrl; /* MAL / Commac status control bits */ + u16 data_len; /* Max length is 4K-1 (12 bits) */ + u32 data_ptr; /* pointer to actual data buffer */ +}; + +/* the following defines are for the MadMAL status and control registers. */ +/* MADMAL transmit and receive status/control bits */ +#define MAL_RX_CTRL_EMPTY 0x8000 +#define MAL_RX_CTRL_WRAP 0x4000 +#define MAL_RX_CTRL_CM 0x2000 +#define MAL_RX_CTRL_LAST 0x1000 +#define MAL_RX_CTRL_FIRST 0x0800 +#define MAL_RX_CTRL_INTR 0x0400 +#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST) +#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE) + +#define MAL_TX_CTRL_READY 0x8000 +#define MAL_TX_CTRL_WRAP 0x4000 +#define MAL_TX_CTRL_CM 0x2000 +#define MAL_TX_CTRL_LAST 0x1000 +#define MAL_TX_CTRL_INTR 0x0400 + +struct mal_commac_ops { + void (*poll_tx) (void *dev); + int (*poll_rx) (void *dev, int budget); + int (*peek_rx) (void *dev); + void (*rxde) (void *dev); +}; + +struct mal_commac { + struct mal_commac_ops *ops; + void *dev; + struct list_head poll_list; + long flags; +#define MAL_COMMAC_RX_STOPPED 0 +#define MAL_COMMAC_POLL_DISABLED 1 + u32 tx_chan_mask; + u32 rx_chan_mask; + struct list_head list; +}; + +struct mal_instance { + int version; + int dcr_base; + dcr_host_t dcr_host; + + int num_tx_chans; /* Number of TX channels */ + int num_rx_chans; /* Number of RX channels */ + int txeob_irq; /* TX End Of Buffer IRQ */ + int rxeob_irq; /* RX End Of Buffer IRQ */ + int txde_irq; /* TX Descriptor Error IRQ */ + int rxde_irq; /* RX Descriptor Error IRQ */ + int serr_irq; /* MAL System Error IRQ */ + + struct list_head poll_list; + struct net_device poll_dev; + + struct list_head list; + u32 tx_chan_mask; + u32 rx_chan_mask; + + dma_addr_t bd_dma; + struct mal_descriptor *bd_virt; + + struct of_device *ofdev; + int index; + spinlock_t lock; +}; + +static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) +{ + return dcr_read(mal->dcr_host, mal->dcr_base + reg); +} + +static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val) +{ + dcr_write(mal->dcr_host, mal->dcr_base + reg, val); +} + +/* Register MAL devices */ +int mal_init(void); +void mal_exit(void); + +int mal_register_commac(struct mal_instance *mal, + struct mal_commac *commac); +void mal_unregister_commac(struct mal_instance *mal, + struct mal_commac *commac); +int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size); + +/* Returns BD ring offset for a particular channel + (in 'struct mal_descriptor' elements) +*/ +int mal_tx_bd_offset(struct mal_instance *mal, int channel); +int mal_rx_bd_offset(struct mal_instance *mal, int channel); + +void mal_enable_tx_channel(struct mal_instance *mal, int channel); +void mal_disable_tx_channel(struct mal_instance *mal, int channel); +void mal_enable_rx_channel(struct mal_instance *mal, int channel); +void mal_disable_rx_channel(struct mal_instance *mal, int channel); + +void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac); +void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac); + +/* Add/remove EMAC to/from MAL polling list */ +void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac); +void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac); + +/* Ethtool MAL registers */ +struct mal_regs { + u32 tx_count; + u32 rx_count; + + u32 cfg; + u32 esr; + u32 ier; + u32 tx_casr; + u32 tx_carr; + u32 tx_eobisr; + u32 tx_deir; + u32 rx_casr; + u32 rx_carr; + u32 rx_eobisr; + u32 rx_deir; + u32 tx_ctpr[32]; + u32 rx_ctpr[32]; + u32 rcbs[32]; +}; + +int mal_get_regs_len(struct mal_instance *mal); +void *mal_dump_regs(struct mal_instance *mal, void *buf); + +#endif /* __IBM_NEWEMAC_MAL_H */ diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c new file mode 100644 index 000000000000..aa1f0ddf1e3e --- /dev/null +++ b/drivers/net/ibm_newemac/phy.c @@ -0,0 +1,373 @@ +/* + * drivers/net/ibm_newemac/phy.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, PHY support. + * Borrowed from sungem_phy.c, though I only kept the generic MII + * driver for now. + * + * This file should be shared with other drivers or eventually + * merged as the "low level" part of miilib + * + * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org) + * (c) 2004-2005, Eugene Surovegin + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "emac.h" +#include "phy.h" + +static inline int phy_read(struct mii_phy *phy, int reg) +{ + return phy->mdio_read(phy->dev, phy->address, reg); +} + +static inline void phy_write(struct mii_phy *phy, int reg, int val) +{ + phy->mdio_write(phy->dev, phy->address, reg, val); +} + +int emac_mii_reset_phy(struct mii_phy *phy) +{ + int val; + int limit = 10000; + + val = phy_read(phy, MII_BMCR); + val &= ~(BMCR_ISOLATE | BMCR_ANENABLE); + val |= BMCR_RESET; + phy_write(phy, MII_BMCR, val); + + udelay(300); + + while (limit--) { + val = phy_read(phy, MII_BMCR); + if (val >= 0 && (val & BMCR_RESET) == 0) + break; + udelay(10); + } + if ((val & BMCR_ISOLATE) && limit > 0) + phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); + + return limit <= 0; +} + +static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) +{ + int ctl, adv; + + phy->autoneg = AUTONEG_ENABLE; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + phy->advertising = advertise; + + ctl = phy_read(phy, MII_BMCR); + if (ctl < 0) + return ctl; + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + + /* First clear the PHY */ + phy_write(phy, MII_BMCR, ctl); + + /* Setup standard advertise */ + adv = phy_read(phy, MII_ADVERTISE); + if (adv < 0) + return adv; + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + phy_write(phy, MII_ADVERTISE, adv); + + if (phy->features & + (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { + adv = phy_read(phy, MII_CTRL1000); + if (adv < 0) + return adv; + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (advertise & ADVERTISED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + if (advertise & ADVERTISED_1000baseT_Half) + adv |= ADVERTISE_1000HALF; + phy_write(phy, MII_CTRL1000, adv); + } + + /* Start/Restart aneg */ + ctl = phy_read(phy, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) +{ + int ctl; + + phy->autoneg = AUTONEG_DISABLE; + phy->speed = speed; + phy->duplex = fd; + phy->pause = phy->asym_pause = 0; + + ctl = phy_read(phy, MII_BMCR); + if (ctl < 0) + return ctl; + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + + /* First clear the PHY */ + phy_write(phy, MII_BMCR, ctl | BMCR_RESET); + + /* Select speed & duplex */ + switch (speed) { + case SPEED_10: + break; + case SPEED_100: + ctl |= BMCR_SPEED100; + break; + case SPEED_1000: + ctl |= BMCR_SPEED1000; + break; + default: + return -EINVAL; + } + if (fd == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_poll_link(struct mii_phy *phy) +{ + int status; + + /* Clear latched value with dummy read */ + phy_read(phy, MII_BMSR); + status = phy_read(phy, MII_BMSR); + if (status < 0 || (status & BMSR_LSTATUS) == 0) + return 0; + if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE)) + return 0; + return 1; +} + +static int genmii_read_link(struct mii_phy *phy) +{ + if (phy->autoneg == AUTONEG_ENABLE) { + int glpa = 0; + int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); + if (lpa < 0) + return lpa; + + if (phy->features & + (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { + int adv = phy_read(phy, MII_CTRL1000); + glpa = phy_read(phy, MII_STAT1000); + + if (glpa < 0 || adv < 0) + return adv; + + glpa &= adv << 2; + } + + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + + if (glpa & (LPA_1000FULL | LPA_1000HALF)) { + phy->speed = SPEED_1000; + if (glpa & LPA_1000FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & (LPA_100FULL | LPA_100HALF)) { + phy->speed = SPEED_100; + if (lpa & LPA_100FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & LPA_10FULL) + phy->duplex = DUPLEX_FULL; + + if (phy->duplex == DUPLEX_FULL) { + phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; + } + } else { + int bmcr = phy_read(phy, MII_BMCR); + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phy->duplex = DUPLEX_FULL; + else + phy->duplex = DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + phy->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phy->speed = SPEED_100; + else + phy->speed = SPEED_10; + + phy->pause = phy->asym_pause = 0; + } + return 0; +} + +/* Generic implementation for most 10/100/1000 PHYs */ +static struct mii_phy_ops generic_phy_ops = { + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link +}; + +static struct mii_phy_def genmii_phy_def = { + .phy_id = 0x00000000, + .phy_id_mask = 0x00000000, + .name = "Generic MII", + .ops = &generic_phy_ops +}; + +/* CIS8201 */ +#define MII_CIS8201_10BTCSR 0x16 +#define TENBTCSR_ECHO_DISABLE 0x2000 +#define MII_CIS8201_EPCR 0x17 +#define EPCR_MODE_MASK 0x3000 +#define EPCR_GMII_MODE 0x0000 +#define EPCR_RGMII_MODE 0x1000 +#define EPCR_TBI_MODE 0x2000 +#define EPCR_RTBI_MODE 0x3000 +#define MII_CIS8201_ACSR 0x1c +#define ACSR_PIN_PRIO_SELECT 0x0004 + +static int cis8201_init(struct mii_phy *phy) +{ + int epcr; + + epcr = phy_read(phy, MII_CIS8201_EPCR); + if (epcr < 0) + return epcr; + + epcr &= ~EPCR_MODE_MASK; + + switch (phy->mode) { + case PHY_MODE_TBI: + epcr |= EPCR_TBI_MODE; + break; + case PHY_MODE_RTBI: + epcr |= EPCR_RTBI_MODE; + break; + case PHY_MODE_GMII: + epcr |= EPCR_GMII_MODE; + break; + case PHY_MODE_RGMII: + default: + epcr |= EPCR_RGMII_MODE; + } + + phy_write(phy, MII_CIS8201_EPCR, epcr); + + /* MII regs override strap pins */ + phy_write(phy, MII_CIS8201_ACSR, + phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT); + + /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */ + phy_write(phy, MII_CIS8201_10BTCSR, + phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE); + + return 0; +} + +static struct mii_phy_ops cis8201_phy_ops = { + .init = cis8201_init, + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link +}; + +static struct mii_phy_def cis8201_phy_def = { + .phy_id = 0x000fc410, + .phy_id_mask = 0x000ffff0, + .name = "CIS8201 Gigabit Ethernet", + .ops = &cis8201_phy_ops +}; + +static struct mii_phy_def *mii_phy_table[] = { + &cis8201_phy_def, + &genmii_phy_def, + NULL +}; + +int emac_mii_phy_probe(struct mii_phy *phy, int address) +{ + struct mii_phy_def *def; + int i; + u32 id; + + phy->autoneg = AUTONEG_DISABLE; + phy->advertising = 0; + phy->address = address; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + + /* Take PHY out of isolate mode and reset it. */ + if (emac_mii_reset_phy(phy)) + return -ENODEV; + + /* Read ID and find matching entry */ + id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2); + for (i = 0; (def = mii_phy_table[i]) != NULL; i++) + if ((id & def->phy_id_mask) == def->phy_id) + break; + /* Should never be NULL (we have a generic entry), but... */ + if (!def) + return -ENODEV; + + phy->def = def; + + /* Determine PHY features if needed */ + phy->features = def->features; + if (!phy->features) { + u16 bmsr = phy_read(phy, MII_BMSR); + if (bmsr & BMSR_ANEGCAPABLE) + phy->features |= SUPPORTED_Autoneg; + if (bmsr & BMSR_10HALF) + phy->features |= SUPPORTED_10baseT_Half; + if (bmsr & BMSR_10FULL) + phy->features |= SUPPORTED_10baseT_Full; + if (bmsr & BMSR_100HALF) + phy->features |= SUPPORTED_100baseT_Half; + if (bmsr & BMSR_100FULL) + phy->features |= SUPPORTED_100baseT_Full; + if (bmsr & BMSR_ESTATEN) { + u16 esr = phy_read(phy, MII_ESTATUS); + if (esr & ESTATUS_1000_TFULL) + phy->features |= SUPPORTED_1000baseT_Full; + if (esr & ESTATUS_1000_THALF) + phy->features |= SUPPORTED_1000baseT_Half; + } + phy->features |= SUPPORTED_MII; + } + + /* Setup default advertising */ + phy->advertising = phy->features; + + return 0; +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h new file mode 100644 index 000000000000..6feca26afedb --- /dev/null +++ b/drivers/net/ibm_newemac/phy.h @@ -0,0 +1,80 @@ +/* + * drivers/net/ibm_newemac/phy.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, PHY support + * + * Benjamin Herrenschmidt + * February 2003 + * + * Minor additions by Eugene Surovegin , 2004 + * + * 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 file basically duplicates sungem_phy.{c,h} with different PHYs + * supported. I'm looking into merging that in a single mii layer more + * flexible than mii.c + */ + +#ifndef __IBM_NEWEMAC_PHY_H +#define __IBM_NEWEMAC_PHY_H + +struct mii_phy; + +/* Operations supported by any kind of PHY */ +struct mii_phy_ops { + int (*init) (struct mii_phy * phy); + int (*suspend) (struct mii_phy * phy, int wol_options); + int (*setup_aneg) (struct mii_phy * phy, u32 advertise); + int (*setup_forced) (struct mii_phy * phy, int speed, int fd); + int (*poll_link) (struct mii_phy * phy); + int (*read_link) (struct mii_phy * phy); +}; + +/* Structure used to statically define an mii/gii based PHY */ +struct mii_phy_def { + u32 phy_id; /* Concatenated ID1 << 16 | ID2 */ + u32 phy_id_mask; /* Significant bits */ + u32 features; /* Ethtool SUPPORTED_* defines or + 0 for autodetect */ + int magic_aneg; /* Autoneg does all speed test for us */ + const char *name; + const struct mii_phy_ops *ops; +}; + +/* An instance of a PHY, partially borrowed from mii_if_info */ +struct mii_phy { + struct mii_phy_def *def; + u32 advertising; /* Ethtool ADVERTISED_* defines */ + u32 features; /* Copied from mii_phy_def.features + or determined automaticaly */ + int address; /* PHY address */ + int mode; /* PHY mode */ + + /* 1: autoneg enabled, 0: disabled */ + int autoneg; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + int pause; + int asym_pause; + + /* Provided by host chip */ + struct net_device *dev; + int (*mdio_read) (struct net_device * dev, int addr, int reg); + void (*mdio_write) (struct net_device * dev, int addr, int reg, + int val); +}; + +/* Pass in a struct mii_phy with dev, mdio_read and mdio_write + * filled, the remaining fields will be filled on return + */ +int emac_mii_phy_probe(struct mii_phy *phy, int address); +int emac_mii_reset_phy(struct mii_phy *phy); + +#endif /* __IBM_NEWEMAC_PHY_H */ diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c new file mode 100644 index 000000000000..bcd7fc639c40 --- /dev/null +++ b/drivers/net/ibm_newemac/rgmii.c @@ -0,0 +1,323 @@ +/* + * drivers/net/ibm_newemac/rgmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Matt Porter + * Copyright 2004 MontaVista Software, 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 "emac.h" +#include "debug.h" + +// XXX FIXME: Axon seems to support a subset of the RGMII, we +// thus need to take that into account and possibly change some +// of the bit settings below that don't seem to quite match the +// AXON spec + +/* RGMIIx_FER */ +#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4)) +#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4)) +#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4)) +#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4)) +#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4)) + +/* RGMIIx_SSR */ +#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8)) +#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8)) +#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8)) + +/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */ +static inline int rgmii_valid_mode(int phy_mode) +{ + return phy_mode == PHY_MODE_GMII || + phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline const char *rgmii_mode_name(int mode) +{ + switch (mode) { + case PHY_MODE_RGMII: + return "RGMII"; + case PHY_MODE_TBI: + return "TBI"; + case PHY_MODE_GMII: + return "GMII"; + case PHY_MODE_RTBI: + return "RTBI"; + default: + BUG(); + } +} + +static inline u32 rgmii_mode_mask(int mode, int input) +{ + switch (mode) { + case PHY_MODE_RGMII: + return RGMII_FER_RGMII(input); + case PHY_MODE_TBI: + return RGMII_FER_TBI(input); + case PHY_MODE_GMII: + return RGMII_FER_GMII(input); + case PHY_MODE_RTBI: + return RGMII_FER_RTBI(input); + default: + BUG(); + } +} + +int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + + RGMII_DBG(dev, "attach(%d)" NL, input); + + /* Check if we need to attach to a RGMII */ + if (input < 0 || !rgmii_valid_mode(mode)) { + printk(KERN_ERR "%s: unsupported settings !\n", + ofdev->node->full_name); + return -ENODEV; + } + + mutex_lock(&dev->lock); + + /* Enable this input */ + out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input)); + + printk(KERN_NOTICE "%s: input %d in %s mode\n", + ofdev->node->full_name, input, rgmii_mode_name(mode)); + + ++dev->users; + + mutex_unlock(&dev->lock); + + return 0; +} + +void rgmii_set_speed(struct of_device *ofdev, int input, int speed) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + u32 ssr; + + mutex_lock(&dev->lock); + + ssr = in_be32(&p->ssr) & ~RGMII_SSR_MASK(input); + + RGMII_DBG(dev, "speed(%d, %d)" NL, input, speed); + + if (speed == SPEED_1000) + ssr |= RGMII_SSR_1000(input); + else if (speed == SPEED_100) + ssr |= RGMII_SSR_100(input); + + out_be32(&p->ssr, ssr); + + mutex_unlock(&dev->lock); +} + +void rgmii_get_mdio(struct of_device *ofdev, int input) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + u32 fer; + + RGMII_DBG2(dev, "get_mdio(%d)" NL, input); + + if (dev->type != RGMII_AXON) + return; + + mutex_lock(&dev->lock); + + fer = in_be32(&p->fer); + fer |= 0x00080000u >> input; + out_be32(&p->fer, fer); + (void)in_be32(&p->fer); + + DBG2(dev, " fer = 0x%08x\n", fer); +} + +void rgmii_put_mdio(struct of_device *ofdev, int input) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + u32 fer; + + RGMII_DBG2(dev, "put_mdio(%d)" NL, input); + + if (dev->type != RGMII_AXON) + return; + + fer = in_be32(&p->fer); + fer &= ~(0x00080000u >> input); + out_be32(&p->fer, fer); + (void)in_be32(&p->fer); + + DBG2(dev, " fer = 0x%08x\n", fer); + + mutex_unlock(&dev->lock); +} + +void __devexit rgmii_detach(struct of_device *ofdev, int input) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + + mutex_lock(&dev->lock); + + BUG_ON(!dev || dev->users == 0); + + RGMII_DBG(dev, "detach(%d)" NL, input); + + /* Disable this input */ + out_be32(&p->fer, in_be32(&p->fer) & ~RGMII_FER_MASK(input)); + + --dev->users; + + mutex_unlock(&dev->lock); +} + +int rgmii_get_regs_len(struct of_device *ofdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct rgmii_regs); +} + +void *rgmii_dump_regs(struct of_device *ofdev, void *buf) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = 0; /* for now, are there chips with more than one + * rgmii ? if yes, then we'll add a cell_index + * like we do for emac + */ + memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs)); + return regs + 1; +} + + +static int __devinit rgmii_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct rgmii_instance *dev; + struct resource regs; + int rc; + + rc = -ENOMEM; + dev = kzalloc(sizeof(struct rgmii_instance), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "%s: could not allocate RGMII device!\n", + np->full_name); + goto err_gone; + } + + mutex_init(&dev->lock); + dev->ofdev = ofdev; + + rc = -ENXIO; + if (of_address_to_resource(np, 0, ®s)) { + printk(KERN_ERR "%s: Can't get registers address\n", + np->full_name); + goto err_free; + } + + rc = -ENOMEM; + dev->base = (struct rgmii_regs *)ioremap(regs.start, + sizeof(struct rgmii_regs)); + if (dev->base == NULL) { + printk(KERN_ERR "%s: Can't map device registers!\n", + np->full_name); + goto err_free; + } + + /* Check for RGMII type */ + if (device_is_compatible(ofdev->node, "ibm,rgmii-axon")) + dev->type = RGMII_AXON; + else + dev->type = RGMII_STANDARD; + + DBG2(dev, " Boot FER = 0x%08x, SSR = 0x%08x\n", + in_be32(&dev->base->fer), in_be32(&dev->base->ssr)); + + /* Disable all inputs by default */ + out_be32(&dev->base->fer, 0); + + printk(KERN_INFO + "RGMII %s %s initialized\n", + dev->type == RGMII_STANDARD ? "standard" : "axon", + ofdev->node->full_name); + + wmb(); + dev_set_drvdata(&ofdev->dev, dev); + + return 0; + + err_free: + kfree(dev); + err_gone: + return rc; +} + +static int __devexit rgmii_remove(struct of_device *ofdev) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + + dev_set_drvdata(&ofdev->dev, NULL); + + WARN_ON(dev->users != 0); + + iounmap(dev->base); + kfree(dev); + + return 0; +} + +static struct of_device_id rgmii_match[] = +{ + { + .type = "rgmii-interface", + .compatible = "ibm,rgmii", + }, + { + .type = "emac-rgmii", + }, + {}, +}; + +static struct of_platform_driver rgmii_driver = { + .name = "emac-rgmii", + .match_table = rgmii_match, + + .probe = rgmii_probe, + .remove = rgmii_remove, +}; + +int __init rgmii_init(void) +{ + return of_register_platform_driver(&rgmii_driver); +} + +void rgmii_exit(void) +{ + of_unregister_platform_driver(&rgmii_driver); +} diff --git a/drivers/net/ibm_newemac/rgmii.h b/drivers/net/ibm_newemac/rgmii.h new file mode 100644 index 000000000000..57806833121e --- /dev/null +++ b/drivers/net/ibm_newemac/rgmii.h @@ -0,0 +1,76 @@ +/* + * drivers/net/ibm_newemac/rgmii.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. + * + * Based on ocp_zmii.h/ibm_emac_zmii.h + * Armin Kuster akuster@mvista.com + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * 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 __IBM_NEWEMAC_RGMII_H +#define __IBM_NEWEMAC_RGMII_H + +/* RGMII bridge type */ +#define RGMII_STANDARD 0 +#define RGMII_AXON 1 + +/* RGMII bridge */ +struct rgmii_regs { + u32 fer; /* Function enable register */ + u32 ssr; /* Speed select register */ +}; + +/* RGMII device */ +struct rgmii_instance { + struct rgmii_regs __iomem *base; + + /* Type of RGMII bridge */ + int type; + + /* Only one EMAC whacks us at a time */ + struct mutex lock; + + /* number of EMACs using this RGMII bridge */ + int users; + + /* OF device instance */ + struct of_device *ofdev; +}; + +#ifdef CONFIG_IBM_NEW_EMAC_RGMII + +extern int rgmii_init(void); +extern void rgmii_exit(void); +extern int rgmii_attach(struct of_device *ofdev, int input, int mode); +extern void rgmii_detach(struct of_device *ofdev, int input); +extern void rgmii_get_mdio(struct of_device *ofdev, int input); +extern void rgmii_put_mdio(struct of_device *ofdev, int input); +extern void rgmii_set_speed(struct of_device *ofdev, int input, int speed); +extern int rgmii_get_regs_len(struct of_device *ofdev); +extern void *rgmii_dump_regs(struct of_device *ofdev, void *buf); + +#else + +# define rgmii_init() 0 +# define rgmii_exit() do { } while(0) +# define rgmii_attach(x,y,z) (-ENXIO) +# define rgmii_detach(x,y) do { } while(0) +# define rgmii_get_mdio(o,i) do { } while (0) +# define rgmii_put_mdio(o,i) do { } while (0) +# define rgmii_set_speed(x,y,z) do { } while(0) +# define rgmii_get_regs_len(x) 0 +# define rgmii_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_NEW_EMAC_RGMII */ + +#endif /* __IBM_NEWEMAC_RGMII_H */ diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c new file mode 100644 index 000000000000..e05c7e81efb6 --- /dev/null +++ b/drivers/net/ibm_newemac/tah.c @@ -0,0 +1,173 @@ +/* + * drivers/net/ibm_newemac/tah.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * Copyright (c) 2005 Eugene Surovegin + * + * 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 "emac.h" +#include "core.h" + +int __devinit tah_attach(struct of_device *ofdev, int channel) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + + mutex_lock(&dev->lock); + /* Reset has been done at probe() time... nothing else to do for now */ + ++dev->users; + mutex_unlock(&dev->lock); + + return 0; +} + +void __devexit tah_detach(struct of_device *ofdev, int channel) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + + mutex_lock(&dev->lock); + --dev->users; + mutex_unlock(&dev->lock); +} + +void tah_reset(struct of_device *ofdev) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + struct tah_regs *p = dev->base; + int n; + + /* Reset TAH */ + out_be32(&p->mr, TAH_MR_SR); + n = 100; + while ((in_be32(&p->mr) & TAH_MR_SR) && n) + --n; + + if (unlikely(!n)) + printk(KERN_ERR "%s: reset timeout\n", ofdev->node->full_name); + + /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ + out_be32(&p->mr, + TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | + TAH_MR_DIG); +} + +int tah_get_regs_len(struct of_device *ofdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct tah_regs); +} + +void *tah_dump_regs(struct of_device *ofdev, void *buf) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct tah_regs *regs = (struct tah_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = 0; /* for now, are there chips with more than one + * zmii ? if yes, then we'll add a cell_index + * like we do for emac + */ + memcpy_fromio(regs, dev->base, sizeof(struct tah_regs)); + return regs + 1; +} + +static int __devinit tah_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct tah_instance *dev; + struct resource regs; + int rc; + + rc = -ENOMEM; + dev = kzalloc(sizeof(struct tah_instance), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "%s: could not allocate TAH device!\n", + np->full_name); + goto err_gone; + } + + mutex_init(&dev->lock); + dev->ofdev = ofdev; + + rc = -ENXIO; + if (of_address_to_resource(np, 0, ®s)) { + printk(KERN_ERR "%s: Can't get registers address\n", + np->full_name); + goto err_free; + } + + rc = -ENOMEM; + dev->base = (struct tah_regs *)ioremap(regs.start, + sizeof(struct tah_regs)); + if (dev->base == NULL) { + printk(KERN_ERR "%s: Can't map device registers!\n", + np->full_name); + goto err_free; + } + + /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */ + tah_reset(ofdev); + + printk(KERN_INFO + "TAH %s initialized\n", ofdev->node->full_name); + wmb(); + dev_set_drvdata(&ofdev->dev, dev); + + return 0; + + err_free: + kfree(dev); + err_gone: + return rc; +} + +static int __devexit tah_remove(struct of_device *ofdev) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + + dev_set_drvdata(&ofdev->dev, NULL); + + WARN_ON(dev->users != 0); + + iounmap(dev->base); + kfree(dev); + + return 0; +} + +static struct of_device_id tah_match[] = +{ + { + .type = "tah", + }, + {}, +}; + +static struct of_platform_driver tah_driver = { + .name = "emac-tah", + .match_table = tah_match, + + .probe = tah_probe, + .remove = tah_remove, +}; + +int __init tah_init(void) +{ + return of_register_platform_driver(&tah_driver); +} + +void tah_exit(void) +{ + of_unregister_platform_driver(&tah_driver); +} diff --git a/drivers/net/ibm_newemac/tah.h b/drivers/net/ibm_newemac/tah.h new file mode 100644 index 000000000000..bc41853b6e26 --- /dev/null +++ b/drivers/net/ibm_newemac/tah.h @@ -0,0 +1,90 @@ +/* + * drivers/net/ibm_newemac/tah.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * Copyright (c) 2005 Eugene Surovegin + * + * 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 __IBM_NEWEMAC_TAH_H +#define __IBM_NEWEMAC_TAH_H + +/* TAH */ +struct tah_regs { + u32 revid; + u32 pad[3]; + u32 mr; + u32 ssr0; + u32 ssr1; + u32 ssr2; + u32 ssr3; + u32 ssr4; + u32 ssr5; + u32 tsr; +}; + + +/* TAH device */ +struct tah_instance { + struct tah_regs __iomem *base; + + /* Only one EMAC whacks us at a time */ + struct mutex lock; + + /* number of EMACs using this TAH */ + int users; + + /* OF device instance */ + struct of_device *ofdev; +}; + + +/* TAH engine */ +#define TAH_MR_CVR 0x80000000 +#define TAH_MR_SR 0x40000000 +#define TAH_MR_ST_256 0x01000000 +#define TAH_MR_ST_512 0x02000000 +#define TAH_MR_ST_768 0x03000000 +#define TAH_MR_ST_1024 0x04000000 +#define TAH_MR_ST_1280 0x05000000 +#define TAH_MR_ST_1536 0x06000000 +#define TAH_MR_TFS_16KB 0x00000000 +#define TAH_MR_TFS_2KB 0x00200000 +#define TAH_MR_TFS_4KB 0x00400000 +#define TAH_MR_TFS_6KB 0x00600000 +#define TAH_MR_TFS_8KB 0x00800000 +#define TAH_MR_TFS_10KB 0x00a00000 +#define TAH_MR_DTFP 0x00100000 +#define TAH_MR_DIG 0x00080000 + +#ifdef CONFIG_IBM_NEW_EMAC_TAH + +extern int tah_init(void); +extern void tah_exit(void); +extern int tah_attach(struct of_device *ofdev, int channel); +extern void tah_detach(struct of_device *ofdev, int channel); +extern void tah_reset(struct of_device *ofdev); +extern int tah_get_regs_len(struct of_device *ofdev); +extern void *tah_dump_regs(struct of_device *ofdev, void *buf); + +#else + +# define tah_init() 0 +# define tah_exit() do { } while(0) +# define tah_attach(x,y) (-ENXIO) +# define tah_detach(x,y) do { } while(0) +# define tah_reset(x) do { } while(0) +# define tah_get_regs_len(x) 0 +# define tah_dump_regs(x,buf) (buf) + +#endif /* !CONFIG_IBM_NEW_EMAC_TAH */ + +#endif /* __IBM_NEWEMAC_TAH_H */ diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c new file mode 100644 index 000000000000..d06312901848 --- /dev/null +++ b/drivers/net/ibm_newemac/zmii.c @@ -0,0 +1,322 @@ +/* + * drivers/net/ibm_newemac/zmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Copyright 2001 MontaVista Softare 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 "emac.h" +#include "core.h" + +/* ZMIIx_FER */ +#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4)) +#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \ + ZMII_FER_MDI(2) | ZMII_FER_MDI(3)) + +#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4)) +#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4)) +#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4)) + +/* ZMIIx_SSR */ +#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4)) +#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4)) +#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4)) + +/* ZMII only supports MII, RMII and SMII + * we also support autodetection for backward compatibility + */ +static inline int zmii_valid_mode(int mode) +{ + return mode == PHY_MODE_MII || + mode == PHY_MODE_RMII || + mode == PHY_MODE_SMII || + mode == PHY_MODE_NA; +} + +static inline const char *zmii_mode_name(int mode) +{ + switch (mode) { + case PHY_MODE_MII: + return "MII"; + case PHY_MODE_RMII: + return "RMII"; + case PHY_MODE_SMII: + return "SMII"; + default: + BUG(); + } +} + +static inline u32 zmii_mode_mask(int mode, int input) +{ + switch (mode) { + case PHY_MODE_MII: + return ZMII_FER_MII(input); + case PHY_MODE_RMII: + return ZMII_FER_RMII(input); + case PHY_MODE_SMII: + return ZMII_FER_SMII(input); + default: + return 0; + } +} + +int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct zmii_regs *p = dev->base; + + ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode); + + if (!zmii_valid_mode(*mode)) + /* Probably an EMAC connected to RGMII, + * but it still may need ZMII for MDIO so + * we don't fail here. + */ + return 0; + + mutex_lock(&dev->lock); + + /* Autodetect ZMII mode if not specified. + * This is only for backward compatibility with the old driver. + * Please, always specify PHY mode in your board port to avoid + * any surprises. + */ + if (dev->mode == PHY_MODE_NA) { + if (*mode == PHY_MODE_NA) { + u32 r = dev->fer_save; + + ZMII_DBG(dev, "autodetecting mode, FER = 0x%08x" NL, r); + + if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1))) + dev->mode = PHY_MODE_MII; + else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1))) + dev->mode = PHY_MODE_RMII; + else + dev->mode = PHY_MODE_SMII; + } else + dev->mode = *mode; + + printk(KERN_NOTICE "%s: bridge in %s mode\n", + ofdev->node->full_name, zmii_mode_name(dev->mode)); + } else { + /* All inputs must use the same mode */ + if (*mode != PHY_MODE_NA && *mode != dev->mode) { + printk(KERN_ERR + "%s: invalid mode %d specified for input %d\n", + ofdev->node->full_name, *mode, input); + mutex_unlock(&dev->lock); + return -EINVAL; + } + } + + /* Report back correct PHY mode, + * it may be used during PHY initialization. + */ + *mode = dev->mode; + + /* Enable this input */ + out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input)); + ++dev->users; + + mutex_unlock(&dev->lock); + + return 0; +} + +void zmii_get_mdio(struct of_device *ofdev, int input) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + u32 fer; + + ZMII_DBG2(dev, "get_mdio(%d)" NL, input); + + mutex_lock(&dev->lock); + + fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL; + out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input)); +} + +void zmii_put_mdio(struct of_device *ofdev, int input) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + + ZMII_DBG2(dev, "put_mdio(%d)" NL, input); + mutex_unlock(&dev->lock); +} + + +void zmii_set_speed(struct of_device *ofdev, int input, int speed) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + u32 ssr; + + mutex_lock(&dev->lock); + + ssr = in_be32(&dev->base->ssr); + + ZMII_DBG(dev, "speed(%d, %d)" NL, input, speed); + + if (speed == SPEED_100) + ssr |= ZMII_SSR_SP(input); + else + ssr &= ~ZMII_SSR_SP(input); + + out_be32(&dev->base->ssr, ssr); + + mutex_unlock(&dev->lock); +} + +void __devexit zmii_detach(struct of_device *ofdev, int input) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + + BUG_ON(!dev || dev->users == 0); + + mutex_lock(&dev->lock); + + ZMII_DBG(dev, "detach(%d)" NL, input); + + /* Disable this input */ + out_be32(&dev->base->fer, + in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input)); + + --dev->users; + + mutex_unlock(&dev->lock); +} + +int zmii_get_regs_len(struct of_device *ofdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct zmii_regs); +} + +void *zmii_dump_regs(struct of_device *ofdev, void *buf) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = 0; /* for now, are there chips with more than one + * zmii ? if yes, then we'll add a cell_index + * like we do for emac + */ + memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs)); + return regs + 1; +} + +static int __devinit zmii_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct zmii_instance *dev; + struct resource regs; + int rc; + + rc = -ENOMEM; + dev = kzalloc(sizeof(struct zmii_instance), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "%s: could not allocate ZMII device!\n", + np->full_name); + goto err_gone; + } + + mutex_init(&dev->lock); + dev->ofdev = ofdev; + dev->mode = PHY_MODE_NA; + + rc = -ENXIO; + if (of_address_to_resource(np, 0, ®s)) { + printk(KERN_ERR "%s: Can't get registers address\n", + np->full_name); + goto err_free; + } + + rc = -ENOMEM; + dev->base = (struct zmii_regs *)ioremap(regs.start, + sizeof(struct zmii_regs)); + if (dev->base == NULL) { + printk(KERN_ERR "%s: Can't map device registers!\n", + np->full_name); + goto err_free; + } + + /* We may need FER value for autodetection later */ + dev->fer_save = in_be32(&dev->base->fer); + + /* Disable all inputs by default */ + out_be32(&dev->base->fer, 0); + + printk(KERN_INFO + "ZMII %s initialized\n", ofdev->node->full_name); + wmb(); + dev_set_drvdata(&ofdev->dev, dev); + + return 0; + + err_free: + kfree(dev); + err_gone: + return rc; +} + +static int __devexit zmii_remove(struct of_device *ofdev) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + + dev_set_drvdata(&ofdev->dev, NULL); + + WARN_ON(dev->users != 0); + + iounmap(dev->base); + kfree(dev); + + return 0; +} + +static struct of_device_id zmii_match[] = +{ + { + .compatible = "ibm,zmii", + }, + /* For backward compat with old DT */ + { + .type = "emac-zmii", + }, + {}, +}; + +static struct of_platform_driver zmii_driver = { + .name = "emac-zmii", + .match_table = zmii_match, + + .probe = zmii_probe, + .remove = zmii_remove, +}; + +int __init zmii_init(void) +{ + return of_register_platform_driver(&zmii_driver); +} + +void zmii_exit(void) +{ + of_unregister_platform_driver(&zmii_driver); +} diff --git a/drivers/net/ibm_newemac/zmii.h b/drivers/net/ibm_newemac/zmii.h new file mode 100644 index 000000000000..82a9968b1f74 --- /dev/null +++ b/drivers/net/ibm_newemac/zmii.h @@ -0,0 +1,73 @@ +/* + * drivers/net/ibm_newemac/zmii.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Copyright 2001 MontaVista Softare 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. + * + */ +#ifndef __IBM_NEWEMAC_ZMII_H +#define __IBM_NEWEMAC_ZMII_H + +/* ZMII bridge registers */ +struct zmii_regs { + u32 fer; /* Function enable reg */ + u32 ssr; /* Speed select reg */ + u32 smiirs; /* SMII status reg */ +}; + +/* ZMII device */ +struct zmii_instance { + struct zmii_regs __iomem *base; + + /* Only one EMAC whacks us at a time */ + struct mutex lock; + + /* subset of PHY_MODE_XXXX */ + int mode; + + /* number of EMACs using this ZMII bridge */ + int users; + + /* FER value left by firmware */ + u32 fer_save; + + /* OF device instance */ + struct of_device *ofdev; +}; + +#ifdef CONFIG_IBM_NEW_EMAC_ZMII + +extern int zmii_init(void); +extern void zmii_exit(void); +extern int zmii_attach(struct of_device *ofdev, int input, int *mode); +extern void zmii_detach(struct of_device *ofdev, int input); +extern void zmii_get_mdio(struct of_device *ofdev, int input); +extern void zmii_put_mdio(struct of_device *ofdev, int input); +extern void zmii_set_speed(struct of_device *ofdev, int input, int speed); +extern int zmii_get_regs_len(struct of_device *ocpdev); +extern void *zmii_dump_regs(struct of_device *ofdev, void *buf); + +#else +# define zmii_init() 0 +# define zmii_exit() do { } while(0) +# define zmii_attach(x,y,z) (-ENXIO) +# define zmii_detach(x,y) do { } while(0) +# define zmii_get_mdio(x,y) do { } while(0) +# define zmii_put_mdio(x,y) do { } while(0) +# define zmii_set_speed(x,y,z) do { } while(0) +# define zmii_get_regs_len(x) 0 +# define zmii_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_NEW_EMAC_ZMII */ + +#endif /* __IBM_NEWEMAC_ZMII_H */ From 200eef20db6de7535438c9af9becc8169c6cb6c0 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 3 Sep 2007 10:33:35 +0530 Subject: [PATCH 1438/2804] netxen: ethtool fixes Resubmitting the patch. This patch improves ethtool support for printing correct ring statistics, segmentation offload status, etc. Signed-off by: Dhananjay Phadke Signed-off-by: Jeff Garzik --- drivers/net/netxen/netxen_nic.h | 2 +- drivers/net/netxen/netxen_nic_ethtool.c | 27 +++++++++++++++++++------ drivers/net/netxen/netxen_nic_init.c | 7 +++++-- drivers/net/netxen/netxen_nic_main.c | 1 + 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 7bbd5d14175f..fbc2553275dc 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -919,7 +919,7 @@ struct netxen_adapter { u16 link_duplex; u16 state; u16 link_autoneg; - int rcsum; + int rx_csum; int status; spinlock_t stats_lock; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 78e42316e70f..cfb847b0cae3 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -516,17 +516,17 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) ring->rx_jumbo_pending = 0; for (i = 0; i < MAX_RCV_CTX; ++i) { ring->rx_pending += adapter->recv_ctx[i]. - rcv_desc[RCV_DESC_NORMAL_CTXID].rcv_pending; + rcv_desc[RCV_DESC_NORMAL_CTXID].max_rx_desc_count; ring->rx_jumbo_pending += adapter->recv_ctx[i]. - rcv_desc[RCV_DESC_JUMBO_CTXID].rcv_pending; + rcv_desc[RCV_DESC_JUMBO_CTXID].max_rx_desc_count; } + ring->tx_pending = adapter->max_tx_desc_count; - ring->rx_max_pending = adapter->max_rx_desc_count; - ring->tx_max_pending = adapter->max_tx_desc_count; - ring->rx_jumbo_max_pending = adapter->max_jumbo_rx_desc_count; + ring->rx_max_pending = MAX_RCV_DESCRIPTORS; + ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS; ring->rx_mini_max_pending = 0; ring->rx_mini_pending = 0; - ring->rx_jumbo_pending = 0; } static void @@ -731,6 +731,19 @@ netxen_nic_get_ethtool_stats(struct net_device *dev, } } +static u32 netxen_nic_get_rx_csum(struct net_device *dev) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + return adapter->rx_csum; +} + +static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + adapter->rx_csum = !!data; + return 0; +} + struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, @@ -751,4 +764,6 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_strings = netxen_nic_get_strings, .get_ethtool_stats = netxen_nic_get_ethtool_stats, .get_sset_count = netxen_get_sset_count, + .get_rx_csum = netxen_nic_get_rx_csum, + .set_rx_csum = netxen_nic_set_rx_csum, }; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 1811bcb8c380..37589265297e 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1118,10 +1118,13 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, skb = (struct sk_buff *)buffer->skb; - if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) { + if (likely(adapter->rx_csum && + netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) { adapter->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; - } + } else + skb->ip_summed = CHECKSUM_NONE; + skb->dev = netdev; if (desc_ctx == RCV_DESC_LRO_CTXID) { /* True length was only available on the last pkt */ diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index b9cde65e7f31..2a1d6d7ec351 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -409,6 +409,7 @@ 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->status &= ~NETXEN_NETDEV_STATUS; + adapter->rx_csum = 1; netdev->open = netxen_nic_open; netdev->stop = netxen_nic_close; From 25a72dfe044a716222d7adb4f075afc62ed4061f Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 14 Sep 2007 11:57:33 +0100 Subject: [PATCH 1439/2804] NET_SB1250_MAC: Update Kconfig entry The SB1250 network interfaces are Gigabit Ethernet ones. Move the Kconfig entry to the appropriate section and add some help text. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index cfa97f3fbebd..53615374f16a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -481,10 +481,6 @@ config MIPS_AU1X00_ENET If you have an Alchemy Semi AU1X00 based system say Y. Otherwise, say N. -config NET_SB1250_MAC - tristate "SB1250 Ethernet support" - depends on SIBYTE_SB1xxx_SOC - config SGI_IOC3_ETH bool "SGI IOC3 Ethernet" depends on PCI && SGI_IP27 @@ -2127,6 +2123,18 @@ config R8169_VLAN If in doubt, say Y. +config NET_SB1250_MAC + tristate "SB1250 Gigabit Ethernet support" + depends on SIBYTE_SB1xxx_SOC + ---help--- + This driver supports Gigabit Ethernet interfaces based on the + Broadcom SiByte family of System-On-a-Chip parts. They include + the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455 + and BCM1480 chips. + + To compile this driver as a module, choose M here: the module + will be called sb1250-mac. + config SIS190 tristate "SiS190/SiS191 gigabit ethernet support" depends on PCI From 1a9e8549efda23a08451d0ac582713dfd04f0951 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 14 Sep 2007 12:05:00 +0100 Subject: [PATCH 1440/2804] NET_SB1250_MAC: Rename to SB1250_MAC Rename NET_SB1250_MAC to SB1250_MAC to follow the convention. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- arch/mips/configs/bigsur_defconfig | 2 +- arch/mips/configs/sb1250-swarm_defconfig | 2 +- drivers/net/Kconfig | 2 +- drivers/net/Makefile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 700a3a2d688e..9861fe670d89 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -574,7 +574,7 @@ CONFIG_MII=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -CONFIG_NET_SB1250_MAC=y +CONFIG_SB1250_MAC=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index 93f9e8331ad7..2f28557f3d72 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig @@ -566,7 +566,7 @@ CONFIG_MII=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -CONFIG_NET_SB1250_MAC=y +CONFIG_SB1250_MAC=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 53615374f16a..467532c7975c 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2123,7 +2123,7 @@ config R8169_VLAN If in doubt, say Y. -config NET_SB1250_MAC +config SB1250_MAC tristate "SB1250 Gigabit Ethernet support" depends on SIBYTE_SB1xxx_SOC ---help--- diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9cbef5829870..6220c50596ec 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -111,7 +111,7 @@ obj-$(CONFIG_E2100) += e2100.o 8390.o obj-$(CONFIG_ES3210) += es3210.o 8390.o obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o -obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o +obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_NE_H8300) += ne-h8300.o From aa90f5032129b43569896c1c6c15a706c02c6abf Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Tue, 18 Sep 2007 20:05:27 +0400 Subject: [PATCH 1441/2804] FS_ENET: TX stuff should use fep->tx_lock, instead of fep->lock. Signed-off-by: Vitaly Bordug Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f9079599dd22..83c9bf27ecfd 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -335,7 +335,7 @@ static void fs_enet_tx(struct net_device *dev) int dirtyidx, do_wake, do_restart; u16 sc; - spin_lock(&fep->lock); + spin_lock(&fep->tx_lock); bdp = fep->dirty_tx; do_wake = do_restart = 0; @@ -415,7 +415,7 @@ static void fs_enet_tx(struct net_device *dev) if (do_restart) (*fep->ops->tx_restart)(dev); - spin_unlock(&fep->lock); + spin_unlock(&fep->tx_lock); if (do_wake) netif_wake_queue(dev); @@ -818,7 +818,9 @@ static int fs_enet_close(struct net_device *dev) phy_stop(fep->phydev); spin_lock_irqsave(&fep->lock, flags); + spin_lock(&fep->tx_lock); (*fep->ops->stop)(dev); + spin_unlock(&fep->tx_lock); spin_unlock_irqrestore(&fep->lock, flags); /* release any irqs */ From 9b8ee8e7d6b7f2270b19b3425a393d918fe497d3 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Tue, 18 Sep 2007 20:05:35 +0400 Subject: [PATCH 1442/2804] FS_ENET: Add polling support Signed-off-by: Vitaly Bordug Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 71 ++++++++++++++++++------------ drivers/net/fs_enet/mac-fcc.c | 12 ++--- drivers/net/fs_enet/mac-fec.c | 30 ++++++------- drivers/net/fs_enet/mac-scc.c | 20 ++++----- drivers/net/fs_enet/mii-bitbang.c | 10 ++--- 5 files changed, 80 insertions(+), 63 deletions(-) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 83c9bf27ecfd..dcbe83c773ee 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -1,17 +1,17 @@ /* * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. * - * Copyright (c) 2003 Intracom S.A. + * Copyright (c) 2003 Intracom S.A. * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. + * + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * * Heavily based on original FEC driver by Dan Malek * and modifications by Joakim Tjernlund * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ @@ -59,6 +59,9 @@ module_param(fs_enet_debug, int, 0); MODULE_PARM_DESC(fs_enet_debug, "Freescale bitmapped debugging message enable value"); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void fs_enet_netpoll(struct net_device *dev); +#endif static void fs_set_multicast_list(struct net_device *dev) { @@ -104,7 +107,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) dev->name); /* - * Check for errors. + * Check for errors. */ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { @@ -181,7 +184,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); /* - * Update BD pointer to next entry. + * Update BD pointer to next entry. */ if ((sc & BD_ENET_RX_WRAP) == 0) bdp++; @@ -234,7 +237,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) dev->name); /* - * Check for errors. + * Check for errors. */ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { @@ -312,7 +315,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); /* - * Update BD pointer to next entry. + * Update BD pointer to next entry. */ if ((sc & BD_ENET_RX_WRAP) == 0) bdp++; @@ -349,7 +352,7 @@ static void fs_enet_tx(struct net_device *dev) skb = fep->tx_skbuff[dirtyidx]; /* - * Check for errors. + * Check for errors. */ if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { @@ -389,13 +392,13 @@ static void fs_enet_tx(struct net_device *dev) skb->len, DMA_TO_DEVICE); /* - * Free the sk buffer associated with this last transmit. + * Free the sk buffer associated with this last transmit. */ dev_kfree_skb_irq(skb); fep->tx_skbuff[dirtyidx] = NULL; /* - * Update pointer to next buffer descriptor to be transmitted. + * Update pointer to next buffer descriptor to be transmitted. */ if ((sc & BD_ENET_TX_WRAP) == 0) bdp++; @@ -491,7 +494,7 @@ void fs_init_bds(struct net_device *dev) fep->cur_rx = fep->rx_bd_base; /* - * Initialize the receive buffer descriptors. + * Initialize the receive buffer descriptors. */ for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { skb = dev_alloc_skb(ENET_RX_FRSIZE); @@ -511,7 +514,7 @@ void fs_init_bds(struct net_device *dev) ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); } /* - * if we failed, fillup remainder + * if we failed, fillup remainder */ for (; i < fep->rx_ring; i++, bdp++) { fep->rx_skbuff[i] = NULL; @@ -519,7 +522,7 @@ void fs_init_bds(struct net_device *dev) } /* - * ...and the same for transmit. + * ...and the same for transmit. */ for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { fep->tx_skbuff[i] = NULL; @@ -537,7 +540,7 @@ void fs_cleanup_bds(struct net_device *dev) int i; /* - * Reset SKB transmit buffers. + * Reset SKB transmit buffers. */ for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { if ((skb = fep->tx_skbuff[i]) == NULL) @@ -552,7 +555,7 @@ void fs_cleanup_bds(struct net_device *dev) } /* - * Reset SKB receive buffers + * Reset SKB receive buffers */ for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { if ((skb = fep->rx_skbuff[i]) == NULL) @@ -582,7 +585,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&fep->tx_lock, flags); /* - * Fill in a Tx ring entry + * Fill in a Tx ring entry */ bdp = fep->cur_tx; @@ -601,19 +604,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) curidx = bdp - fep->tx_bd_base; /* - * Clear all of the status flags. + * Clear all of the status flags. */ CBDC_SC(bdp, BD_ENET_TX_STATS); /* - * Save skb pointer. + * Save skb pointer. */ fep->tx_skbuff[curidx] = skb; fep->stats.tx_bytes += skb->len; /* - * Push the data cache so the CPM does not get stale memory data. + * Push the data cache so the CPM does not get stale memory data. */ CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE)); @@ -622,7 +625,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; /* - * If this was the last BD in the ring, start at the beginning again. + * If this was the last BD in the ring, start at the beginning again. */ if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) fep->cur_tx++; @@ -1003,13 +1006,13 @@ static struct net_device *fs_init_instance(struct device *dev, spin_lock_init(&fep->tx_lock); /* - * Set the Ethernet address. + * Set the Ethernet address. */ for (i = 0; i < 6; i++) ndev->dev_addr[i] = fpi->macaddr[i]; - + r = (*fep->ops->allocate_bd)(ndev); - + if (fep->ring_base == NULL) { printk(KERN_ERR DRV_MODULE_NAME ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r); @@ -1028,7 +1031,7 @@ static struct net_device *fs_init_instance(struct device *dev, fep->rx_ring = fpi->rx_ring; /* - * The FEC Ethernet specific entries in the device structure. + * The FEC Ethernet specific entries in the device structure. */ ndev->open = fs_enet_open; ndev->hard_start_xmit = fs_enet_start_xmit; @@ -1037,6 +1040,11 @@ static struct net_device *fs_init_instance(struct device *dev, ndev->stop = fs_enet_close; ndev->get_stats = fs_enet_get_stats; ndev->set_multicast_list = fs_set_multicast_list; + +#ifdef CONFIG_NET_POLL_CONTROLLER + ndev->poll_controller = fs_enet_netpoll; +#endif + netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi, fpi->napi_weight); @@ -1251,7 +1259,7 @@ static int __init fs_init(void) err: cleanup_immap(); return r; - + } static void __exit fs_cleanup(void) @@ -1262,6 +1270,15 @@ static void __exit fs_cleanup(void) cleanup_immap(); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void fs_enet_netpoll(struct net_device *dev) +{ + disable_irq(dev->irq); + fs_enet_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /**************************************************************************************/ module_init(fs_init); diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 5603121132cd..64071514d7d5 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -1,14 +1,14 @@ /* * FCC driver for Motorola MPC82xx (PQ2). * - * Copyright (c) 2003 Intracom S.A. + * Copyright (c) 2003 Intracom S.A. * by Pantelis Antoniou * - * 2005 (c) MontaVista Software, Inc. + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ @@ -92,7 +92,7 @@ static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) u32 v; int i; - /* Currently I don't know what feature call will look like. But + /* Currently I don't know what feature call will look like. But I guess there'd be something like do_cpm_cmd() which will require page & sblock */ v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); W32(cpmp, cp_cpcr, v | CPM_CR_FLG); @@ -548,7 +548,7 @@ int get_regs_len(struct net_device *dev) * down. We now issue a restart transmit. Since the * errors close the BD and update the pointers, the restart * _should_ pick up without having to reset any of our - * pointers either. Also, To workaround 8260 device erratum + * pointers either. Also, To workaround 8260 device erratum * CPM37, we must disable and then re-enable the transmitter * following a Late Collision, Underrun, or Retry Limit error. */ diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 04b4f80a1cde..cbdc17b743db 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -1,14 +1,14 @@ /* * Freescale Ethernet controllers * - * Copyright (c) 2005 Intracom S.A. + * Copyright (c) 2005 Intracom S.A. * by Pantelis Antoniou * - * 2005 (c) MontaVista Software, Inc. + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ @@ -95,9 +95,9 @@ static int whack_reset(fec_t * fecp) static int do_pd_setup(struct fs_enet_private *fep) { - struct platform_device *pdev = to_platform_device(fep->dev); + struct platform_device *pdev = to_platform_device(fep->dev); struct resource *r; - + /* Fill out IRQ field */ fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); if (fep->interrupt < 0) @@ -110,7 +110,7 @@ static int do_pd_setup(struct fs_enet_private *fep) return -EINVAL; return 0; - + } #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) @@ -141,7 +141,7 @@ static int allocate_bd(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - + fep->ring_base = dma_alloc_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), &fep->ring_mem_addr, @@ -280,13 +280,13 @@ static void restart(struct net_device *dev) FW(fecp, addr_high, addrlo); /* - * Reset all multicast. + * Reset all multicast. */ FW(fecp, hash_table_high, fep->fec.hthi); FW(fecp, hash_table_low, fep->fec.htlo); /* - * Set maximum receive buffer size. + * Set maximum receive buffer size. */ FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); FW(fecp, r_hash, PKT_MAXBUF_SIZE); @@ -296,7 +296,7 @@ static void restart(struct net_device *dev) tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; /* - * Set receive and transmit descriptor base. + * Set receive and transmit descriptor base. */ FW(fecp, r_des_start, rx_bd_base_phys); FW(fecp, x_des_start, tx_bd_base_phys); @@ -304,7 +304,7 @@ static void restart(struct net_device *dev) fs_init_bds(dev); /* - * Enable big endian and don't care about SDMA FC. + * Enable big endian and don't care about SDMA FC. */ FW(fecp, fun_code, 0x78000000); @@ -366,13 +366,13 @@ static void restart(struct net_device *dev) } /* - * Enable interrupts we wish to service. + * Enable interrupts we wish to service. */ FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | FEC_ENET_RXF | FEC_ENET_RXB); /* - * And last, enable the transmit and receive processing. + * And last, enable the transmit and receive processing. */ FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); FW(fecp, r_des_active, 0x01000000); @@ -401,7 +401,7 @@ static void stop(struct net_device *dev) ": %s FEC timeout on graceful transmit stop\n", dev->name); /* - * Disable FEC. Let only MII interrupts. + * Disable FEC. Let only MII interrupts. */ FW(fecp, imask, 0); FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 7540966687ec..6f32674a78e9 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -1,14 +1,14 @@ /* * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx. * - * Copyright (c) 2003 Intracom S.A. + * Copyright (c) 2003 Intracom S.A. * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. + * + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ @@ -82,7 +82,7 @@ #define SCC_MAX_MULTICAST_ADDRS 64 /* - * Delay to wait for SCC reset command to complete (in us) + * Delay to wait for SCC reset command to complete (in us) */ #define SCC_RESET_DELAY 50 #define MAX_CR_CMD_LOOPS 10000 @@ -189,7 +189,7 @@ static void cleanup_data(struct net_device *dev) } static void set_promiscuous_mode(struct net_device *dev) -{ +{ struct fs_enet_private *fep = netdev_priv(dev); scc_t *sccp = fep->scc.sccp; @@ -323,7 +323,7 @@ static void restart(struct net_device *dev) W16(ep, sen_iaddr3, 0); W16(ep, sen_iaddr4, 0); - /* set address + /* set address */ mac = dev->dev_addr; paddrh = ((u16) mac[5] << 8) | mac[4]; @@ -345,7 +345,7 @@ static void restart(struct net_device *dev) W16(sccp, scc_scce, 0xffff); - /* Enable interrupts we wish to service. + /* Enable interrupts we wish to service. */ W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); @@ -373,7 +373,7 @@ static void restart(struct net_device *dev) S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } -static void stop(struct net_device *dev) +static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); scc_t *sccp = fep->scc.sccp; diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index d3840108ffbd..1a41ea60f982 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -1,14 +1,14 @@ /* * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. * - * Copyright (c) 2003 Intracom S.A. + * Copyright (c) 2003 Intracom S.A. * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. + * + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ From dd96df2cc2539ecd451614a2ffed4d8a4c541d92 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 19 Sep 2007 13:09:02 +0200 Subject: [PATCH 1443/2804] s390 networking MAINTAINERS maintainer change for s390 networking Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- MAINTAINERS | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c96505c2678d..27e1110ec6ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3248,8 +3248,8 @@ W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported S390 NETWORK DRIVERS -P: Frank Pavlic -M: fpavlic@de.ibm.com +P: Ursula Braun +M: ubraun@linux.vnet.ibm.com M: linux390@de.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ @@ -3263,6 +3263,14 @@ L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported +S390 IUCV NETWORK LAYER +P: Ursula Braun +M: ubraun@linux.vnet.ibm.com +M: linux390@de.ibm.com +L: linux-s390@vger.kernel.org +W: http://www.ibm.com/developerworks/linux/linux390/ +S: Supported + SAA7146 VIDEO4LINUX-2 DRIVER P: Michael Hunold M: michael@mihu.de From d3bb52b0948cf118131c951c5a34a2d4d0246171 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 20:06:58 -0400 Subject: [PATCH 1444/2804] endianness annotations drivers/net/bonding/ Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_3ad.c | 42 +++++++------------------------- drivers/net/bonding/bond_3ad.h | 20 +++++++-------- drivers/net/bonding/bond_alb.c | 19 +++++++-------- drivers/net/bonding/bond_alb.h | 4 +-- drivers/net/bonding/bond_main.c | 22 ++++++++--------- drivers/net/bonding/bond_sysfs.c | 8 +++--- drivers/net/bonding/bonding.h | 6 ++--- 7 files changed, 48 insertions(+), 73 deletions(-) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 94bd73941451..7a045a37056e 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -101,7 +101,6 @@ static u16 __get_link_speed(struct port *port); static u8 __get_duplex(struct port *port); static inline void __initialize_port_locks(struct port *port); //conversions -static void __htons_lacpdu(struct lacpdu *lacpdu); static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par); @@ -420,26 +419,6 @@ static inline void __initialize_port_locks(struct port *port) } //conversions -/** - * __htons_lacpdu - convert the contents of a LACPDU to network byte order - * @lacpdu: the speicifed lacpdu - * - * For each multi-byte field in the lacpdu, convert its content - */ -static void __htons_lacpdu(struct lacpdu *lacpdu) -{ - if (lacpdu) { - lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority); - lacpdu->actor_key = htons(lacpdu->actor_key); - lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority); - lacpdu->actor_port = htons(lacpdu->actor_port); - lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority); - lacpdu->partner_key = htons(lacpdu->partner_key); - lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority); - lacpdu->partner_port = htons(lacpdu->partner_port); - lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay); - } -} /** * __ad_timer_to_ticks - convert a given timer type to AD module ticks @@ -827,11 +806,11 @@ static inline void __update_lacpdu_from_port(struct port *port) * lacpdu->actor_information_length initialized */ - lacpdu->actor_system_priority = port->actor_system_priority; + lacpdu->actor_system_priority = htons(port->actor_system_priority); lacpdu->actor_system = port->actor_system; - lacpdu->actor_key = port->actor_oper_port_key; - lacpdu->actor_port_priority = port->actor_port_priority; - lacpdu->actor_port = port->actor_port_number; + lacpdu->actor_key = htons(port->actor_oper_port_key); + lacpdu->actor_port_priority = htons(port->actor_port_priority); + lacpdu->actor_port = htons(port->actor_port_number); lacpdu->actor_state = port->actor_oper_port_state; /* lacpdu->reserved_3_1 initialized @@ -839,11 +818,11 @@ static inline void __update_lacpdu_from_port(struct port *port) * lacpdu->partner_information_length initialized */ - lacpdu->partner_system_priority = port->partner_oper_system_priority; + lacpdu->partner_system_priority = htons(port->partner_oper_system_priority); lacpdu->partner_system = port->partner_oper_system; - lacpdu->partner_key = port->partner_oper_key; - lacpdu->partner_port_priority = port->partner_oper_port_priority; - lacpdu->partner_port = port->partner_oper_port_number; + lacpdu->partner_key = htons(port->partner_oper_key); + lacpdu->partner_port_priority = htons(port->partner_oper_port_priority); + lacpdu->partner_port = htons(port->partner_oper_port_number); lacpdu->partner_state = port->partner_oper_port_state; /* lacpdu->reserved_3_2 initialized @@ -855,9 +834,6 @@ static inline void __update_lacpdu_from_port(struct port *port) * terminator_length initialized * reserved_50[50] initialized */ - - /* Convert all non u8 parameters to Big Endian for transmit */ - __htons_lacpdu(lacpdu); } ////////////////////////////////////////////////////////////////////////////////////// @@ -1834,7 +1810,7 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu) } lacpdu->tlv_type_collector_info = 0x03; lacpdu->collector_information_length= 0x10; - lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY; + lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY); for (index=0; index<=11; index++) { lacpdu->reserved_12[index]=0; } diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 6ad5ad6e65d5..862952fa6fd9 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -108,7 +108,7 @@ typedef enum { typedef struct ad_header { struct mac_addr destination_address; struct mac_addr source_address; - u16 length_type; + __be16 length_type; } ad_header_t; // Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) @@ -117,25 +117,25 @@ typedef struct lacpdu { u8 version_number; u8 tlv_type_actor_info; // = actor information(type/length/value) u8 actor_information_length; // = 20 - u16 actor_system_priority; + __be16 actor_system_priority; struct mac_addr actor_system; - u16 actor_key; - u16 actor_port_priority; - u16 actor_port; + __be16 actor_key; + __be16 actor_port_priority; + __be16 actor_port; u8 actor_state; u8 reserved_3_1[3]; // = 0 u8 tlv_type_partner_info; // = partner information u8 partner_information_length; // = 20 - u16 partner_system_priority; + __be16 partner_system_priority; struct mac_addr partner_system; - u16 partner_key; - u16 partner_port_priority; - u16 partner_port; + __be16 partner_key; + __be16 partner_port_priority; + __be16 partner_port; u8 partner_state; u8 reserved_3_2[3]; // = 0 u8 tlv_type_collector_info; // = collector information u8 collector_information_length; // = 16 - u16 collector_max_delay; + __be16 collector_max_delay; u8 reserved_12[12]; u8 tlv_type_terminator; // = terminator u8 terminator_length; // = 0 diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 419a9f8fdd53..aea2217c56eb 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -87,20 +87,20 @@ static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; struct learning_pkt { u8 mac_dst[ETH_ALEN]; u8 mac_src[ETH_ALEN]; - u16 type; + __be16 type; u8 padding[ETH_ZLEN - ETH_HLEN]; }; struct arp_pkt { - u16 hw_addr_space; - u16 prot_addr_space; + __be16 hw_addr_space; + __be16 prot_addr_space; u8 hw_addr_len; u8 prot_addr_len; - u16 op_code; + __be16 op_code; u8 mac_src[ETH_ALEN]; /* sender hardware address */ - u32 ip_src; /* sender IP address */ + __be32 ip_src; /* sender IP address */ u8 mac_dst[ETH_ALEN]; /* target hardware address */ - u32 ip_dst; /* target IP address */ + __be32 ip_dst; /* target IP address */ }; #pragma pack() @@ -582,7 +582,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla } /* mark all clients using src_ip to be updated */ -static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) +static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct rlb_client_info *client_info; @@ -1267,7 +1267,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) struct ethhdr *eth_data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; - static const u32 ip_bcast = 0xffffffff; + static const __be32 ip_bcast = htonl(0xffffffff); int hash_size = 0; int do_tx_balance = 1; u32 hash_index = 0; @@ -1311,8 +1311,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) hash_size = sizeof(ipv6_hdr(skb)->daddr); break; case ETH_P_IPX: - if (ipx_hdr(skb)->ipx_checksum != - __constant_htons(IPX_NO_CHECKSUM)) { + if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) { /* something is wrong with this packet */ do_tx_balance = 0; break; diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 28f2a2fd1b5a..fd8726429890 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -60,8 +60,8 @@ struct tlb_client_info { * ------------------------------------------------------------------------- */ struct rlb_client_info { - u32 ip_src; /* the server IP address */ - u32 ip_dst; /* the client IP address */ + __be32 ip_src; /* the server IP address */ + __be32 ip_dst; /* the client IP address */ u8 mac_dst[ETH_ALEN]; /* the client MAC address */ u32 next; /* The next Hash table entry index */ u32 prev; /* The previous Hash table entry index */ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 8f77db2112ce..64bfec32e2a6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -144,7 +144,7 @@ static struct proc_dir_entry *bond_proc_dir = NULL; #endif extern struct rw_semaphore bonding_rwsem; -static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; +static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; static int arp_ip_count = 0; static int bond_mode = BOND_MODE_ROUNDROBIN; static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2; @@ -2226,7 +2226,7 @@ out: } -static u32 bond_glean_dev_ip(struct net_device *dev) +static __be32 bond_glean_dev_ip(struct net_device *dev) { struct in_device *idev; struct in_ifaddr *ifa; @@ -2269,7 +2269,7 @@ static int bond_has_ip(struct bonding *bond) return 0; } -static int bond_has_this_ip(struct bonding *bond, u32 ip) +static int bond_has_this_ip(struct bonding *bond, __be32 ip) { struct vlan_entry *vlan, *vlan_next; @@ -2293,7 +2293,7 @@ static int bond_has_this_ip(struct bonding *bond, u32 ip) * switches in VLAN mode (especially if ports are configured as * "native" to a VLAN) might not pass non-tagged frames. */ -static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id) +static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id) { struct sk_buff *skb; @@ -2321,7 +2321,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, static void bond_arp_send_all(struct bonding *bond, struct slave *slave) { int i, vlan_id, rv; - u32 *targets = bond->params.arp_targets; + __be32 *targets = bond->params.arp_targets; struct vlan_entry *vlan, *vlan_next; struct net_device *vlan_dev; struct flowi fl; @@ -2426,10 +2426,10 @@ static void bond_send_gratuitous_arp(struct bonding *bond) } } -static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip) +static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) { int i; - u32 *targets = bond->params.arp_targets; + __be32 *targets = bond->params.arp_targets; targets = bond->params.arp_targets; for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { @@ -2451,7 +2451,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack struct slave *slave; struct bonding *bond; unsigned char *arp_ptr; - u32 sip, tip; + __be32 sip, tip; if (dev->nd_net != &init_net) goto out; @@ -3427,14 +3427,14 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, { struct ethhdr *data = (struct ethhdr *)skb->data; struct iphdr *iph = ip_hdr(skb); - u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl); + __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); int layer4_xor = 0; if (skb->protocol == __constant_htons(ETH_P_IP)) { if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) && (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP)) { - layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1))); + layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1))); } return (layer4_xor ^ ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count; @@ -4521,7 +4521,7 @@ static int bond_check_params(struct bond_params *params) arp_ip_target[arp_ip_count]); arp_interval = 0; } else { - u32 ip = in_aton(arp_ip_target[arp_ip_count]); + __be32 ip = in_aton(arp_ip_target[arp_ip_count]); arp_target[arp_ip_count] = ip; } } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index f10927639b5c..6f49ca7e9b66 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -682,16 +682,16 @@ static ssize_t bonding_store_arp_targets(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - u32 newtarget; + __be32 newtarget; int i = 0, done = 0, ret = count; struct bonding *bond = to_bond(d); - u32 *targets; + __be32 *targets; targets = bond->params.arp_targets; newtarget = in_aton(buf + 1); /* look for adds */ if (buf[0] == '+') { - if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) { + if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { printk(KERN_ERR DRV_NAME ": %s: invalid ARP target %u.%u.%u.%u specified for addition\n", bond->dev->name, NIPQUAD(newtarget)); @@ -727,7 +727,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, } else if (buf[0] == '-') { - if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) { + if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { printk(KERN_ERR DRV_NAME ": %s: invalid ARP target %d.%d.%d.%d specified for removal\n", bond->dev->name, NIPQUAD(newtarget)); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6dcbd25e3ef0..2a6af7d23728 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -132,7 +132,7 @@ struct bond_params { int downdelay; int lacp_fast; char primary[IFNAMSIZ]; - u32 arp_targets[BOND_MAX_ARP_TARGETS]; + __be32 arp_targets[BOND_MAX_ARP_TARGETS]; }; struct bond_parm_tbl { @@ -142,7 +142,7 @@ struct bond_parm_tbl { struct vlan_entry { struct list_head vlan_list; - u32 vlan_ip; + __be32 vlan_ip; unsigned short vlan_id; }; @@ -193,7 +193,7 @@ struct bonding { struct list_head bond_list; struct dev_mc_list *mc_list; int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int); - u32 master_ip; + __be32 master_ip; u16 flags; struct ad_bond_info ad_info; struct alb_bond_info alb_info; From cf9830195a3f35b1248425b69a01ee43f5b68221 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 21:18:56 -0400 Subject: [PATCH 1445/2804] fix vlan in 8139cp on big-endian Layout of opts2 is : MSB(vlan_tag) : LSB(vlan_tag) : flags : 0 : regardless of the host endianness. On little-endian the current code ends up with the right values, but on big-endian it blows. In r8169.c the same bug had been fixed in commit d35da12a40426184b1d0844104b1d464753eba19 (r8169: endianness fixes). Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index abb2a3471087..a453eda834d5 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -78,7 +78,7 @@ #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define CP_VLAN_TAG_USED 1 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ - do { (tx_desc)->opts2 = (vlan_tag_value); } while (0) + do { (tx_desc)->opts2 = cpu_to_le32(vlan_tag_value); } while (0) #else #define CP_VLAN_TAG_USED 0 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ @@ -304,7 +304,7 @@ static const unsigned int cp_rx_config = struct cp_desc { __le32 opts1; - u32 opts2; + __le32 opts2; __le64 addr; }; @@ -462,9 +462,9 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, cp->dev->last_rx = jiffies; #if CP_VLAN_TAG_USED - if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) { + if (cp->vlgrp && (desc->opts2 & cpu_to_le32(RxVlanTagged))) { vlan_hwaccel_receive_skb(skb, cp->vlgrp, - be16_to_cpu(desc->opts2 & 0xffff)); + swab16(le32_to_cpu(desc->opts2) & 0xffff)); } else #endif netif_receive_skb(skb); @@ -765,7 +765,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) #if CP_VLAN_TAG_USED if (cp->vlgrp && vlan_tx_tag_present(skb)) - vlan_tag = TxVlanTag | cpu_to_be16(vlan_tx_tag_get(skb)); + vlan_tag = TxVlanTag | swab16(vlan_tx_tag_get(skb)); #endif entry = cp->tx_head; From cc2d6596ca79667830a90ca177ba53b0d83262de Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 21:34:46 -0400 Subject: [PATCH 1446/2804] 3c59x: trivial endianness annotations, NULL noise removal Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/3c59x.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 93eb78425d6d..8d3893da06f5 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -538,10 +538,10 @@ enum MasterCtrl { #define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ #define DN_COMPLETE 0x00010000 /* This packet has been downloaded */ struct boom_rx_desc { - u32 next; /* Last entry points to 0. */ - s32 status; - u32 addr; /* Up to 63 addr/len pairs possible. */ - s32 length; /* Set LAST_FRAG to indicate last pair. */ + __le32 next; /* Last entry points to 0. */ + __le32 status; + __le32 addr; /* Up to 63 addr/len pairs possible. */ + __le32 length; /* Set LAST_FRAG to indicate last pair. */ }; /* Values for the Rx status entry. */ enum rx_desc_status { @@ -558,16 +558,16 @@ enum rx_desc_status { #endif struct boom_tx_desc { - u32 next; /* Last entry points to 0. */ - s32 status; /* bits 0:12 length, others see below. */ + __le32 next; /* Last entry points to 0. */ + __le32 status; /* bits 0:12 length, others see below. */ #if DO_ZEROCOPY struct { - u32 addr; - s32 length; + __le32 addr; + __le32 length; } frag[1+MAX_SKB_FRAGS]; #else - u32 addr; - s32 length; + __le32 addr; + __le32 length; #endif }; @@ -1131,7 +1131,7 @@ static int __devinit vortex_probe1(struct device *gendev, + sizeof(struct boom_tx_desc) * TX_RING_SIZE, &vp->rx_ring_dma); retval = -ENOMEM; - if (vp->rx_ring == 0) + if (!vp->rx_ring) goto free_region; vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); @@ -1204,7 +1204,7 @@ static int __devinit vortex_probe1(struct device *gendev, if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO)) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++) - ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); + ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (print_info) printk(" %s", print_mac(mac, dev->dev_addr)); @@ -2500,7 +2500,7 @@ boomerang_rx(struct net_device *dev) /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ @@ -2914,7 +2914,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; unsigned long flags; - int state = 0; + pci_power_t state = 0; if(VORTEX_PCI(vp)) state = VORTEX_PCI(vp)->current_state; From ee41a82fa362449e608c4dab7df261058ffd52c0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 21:37:46 -0400 Subject: [PATCH 1447/2804] amd8111e: trivial endianness annotations, NULL noise removal Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/amd8111e.c | 6 +++--- drivers/net/amd8111e.h | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 73f40a45441a..babe0de2ce44 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1404,7 +1404,7 @@ This function checks if there is any transmit descriptors available to queue mo static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp ) { int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK; - if(lp->tx_skbuff[tx_index] != 0) + if (lp->tx_skbuff[tx_index]) return -1; else return 0; @@ -1441,7 +1441,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) lp->tx_dma_addr[tx_index] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); lp->tx_ring[tx_index].buff_phy_addr = - (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]); + cpu_to_le32(lp->tx_dma_addr[tx_index]); /* Set FCS and LTINT bits */ wmb(); @@ -1998,7 +1998,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, spin_lock_init(&lp->lock); lp->mmio = ioremap(reg_addr, reg_len); - if (lp->mmio == 0) { + if (!lp->mmio) { printk(KERN_ERR "amd8111e: Cannot map device registers, " "exiting\n"); err = -ENOMEM; diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h index 612e653610e1..28c60a71ed50 100644 --- a/drivers/net/amd8111e.h +++ b/drivers/net/amd8111e.h @@ -655,32 +655,32 @@ typedef enum { struct amd8111e_tx_dr{ - u16 buff_count; /* Size of the buffer pointed by this descriptor */ + __le16 buff_count; /* Size of the buffer pointed by this descriptor */ - u16 tx_flags; + __le16 tx_flags; - u16 tag_ctrl_info; + __le16 tag_ctrl_info; - u16 tag_ctrl_cmd; + __le16 tag_ctrl_cmd; - u32 buff_phy_addr; + __le32 buff_phy_addr; - u32 reserved; + __le32 reserved; }; struct amd8111e_rx_dr{ - u32 reserved; + __le32 reserved; - u16 msg_count; /* Received message len */ + __le16 msg_count; /* Received message len */ - u16 tag_ctrl_info; + __le16 tag_ctrl_info; - u16 buff_count; /* Len of the buffer pointed by descriptor. */ + __le16 buff_count; /* Len of the buffer pointed by descriptor. */ - u16 rx_flags; + __le16 rx_flags; - u32 buff_phy_addr; + __le32 buff_phy_addr; }; struct amd8111e_link_config{ From 05d2fec9f5e5fd1d7169435631b9d55ae4c566d1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 21:42:28 -0400 Subject: [PATCH 1448/2804] amd8111e big-endian fix amd8111e_calc_coalesce() ends up with insane values of tx_data_rate since ->tx_bytes increments missing conversion from little- to host-endian Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/amd8111e.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index babe0de2ce44..1cc74ec88a58 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -709,7 +709,8 @@ static int amd8111e_tx(struct net_device *dev) lp->tx_complete_idx++; /*COAL update tx coalescing parameters */ lp->coal_conf.tx_packets++; - lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count; + lp->coal_conf.tx_bytes += + le16_to_cpu(lp->tx_ring[tx_index].buff_count); if (netif_queue_stopped(dev) && lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){ From 701181ac1d9ac465a3614061cb60ded4033c4d07 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 22:59:11 -0400 Subject: [PATCH 1449/2804] arcnet endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/arcnet/rfc1051.c | 4 ++-- drivers/net/arcnet/rfc1201.c | 6 +++--- include/linux/arcdevice.h | 4 ++-- include/linux/if_arcnet.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index 2de8877ece29..dab185bc51f1 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -34,7 +34,7 @@ #define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n" -static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); +static __be16 type_trans(struct sk_buff *skb, struct net_device *dev); static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length); static int build_header(struct sk_buff *skb, struct net_device *dev, @@ -86,7 +86,7 @@ MODULE_LICENSE("GPL"); * * With ARCnet we have to convert everything to Ethernet-style stuff. */ -static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) +static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) { struct arcnet_local *lp = dev->priv; struct archdr *pkt = (struct archdr *) skb->data; diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index 460a095000c2..6d6d95cc4404 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -34,7 +34,7 @@ MODULE_LICENSE("GPL"); #define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n" -static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); +static __be16 type_trans(struct sk_buff *skb, struct net_device *dev); static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length); static int build_header(struct sk_buff *skb, struct net_device *dev, @@ -88,7 +88,7 @@ module_exit(arcnet_rfc1201_exit); * * With ARCnet we have to convert everything to Ethernet-style stuff. */ -static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) +static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) { struct archdr *pkt = (struct archdr *) skb->data; struct arc_rfc1201 *soft = &pkt->soft.rfc1201; @@ -456,7 +456,7 @@ static void load_pkt(struct net_device *dev, struct arc_hardware *hard, excsoft.proto = soft->proto; excsoft.split_flag = 0xff; - excsoft.sequence = 0xffff; + excsoft.sequence = htons(0xffff); hard->offset[0] = 0; ofs = 512 - softlen; diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index 2f85049cfb3d..fde675872c56 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -214,7 +214,7 @@ extern struct ArcProto *arc_proto_map[256], *arc_proto_default, */ struct Incoming { struct sk_buff *skb; /* packet data buffer */ - uint16_t sequence; /* sequence number of assembly */ + __be16 sequence; /* sequence number of assembly */ uint8_t lastpacket, /* number of last packet (from 1) */ numpackets; /* number of packets in split */ }; @@ -292,7 +292,7 @@ struct arcnet_local { struct { uint16_t sequence; /* sequence number (incs with each packet) */ - uint16_t aborted_seq; + __be16 aborted_seq; struct Incoming incoming[256]; /* one from each address */ } rfc1201; diff --git a/include/linux/if_arcnet.h b/include/linux/if_arcnet.h index af380cb876a0..27ea2ac445ad 100644 --- a/include/linux/if_arcnet.h +++ b/include/linux/if_arcnet.h @@ -59,7 +59,7 @@ struct arc_rfc1201 { uint8_t proto; /* protocol ID field - varies */ uint8_t split_flag; /* for use with split packets */ - uint16_t sequence; /* sequence number */ + __be16 sequence; /* sequence number */ uint8_t payload[0]; /* space remaining in packet (504 bytes)*/ }; #define RFC1201_HDR_SIZE 4 From c559a5bc9417c00ba2df59397a27eaf8d8e52aec Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:43:22 -0400 Subject: [PATCH 1450/2804] tulip: endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/tulip/de2104x.c | 12 ++++++------ drivers/net/tulip/de4x5.c | 10 +++++----- drivers/net/tulip/tulip.h | 16 ++++++++-------- drivers/net/tulip/tulip_core.c | 10 +++++----- drivers/net/tulip/uli526x.c | 6 +++--- drivers/net/tulip/winbond-840.c | 2 +- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index f12e33a17363..77d9dd7ea34f 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -264,10 +264,10 @@ struct de_srom_info_leaf { } __attribute__((packed)); struct de_desc { - u32 opts1; - u32 opts2; - u32 addr1; - u32 addr2; + __le32 opts1; + __le32 opts2; + __le32 addr1; + __le32 addr2; }; struct media_info { @@ -1771,8 +1771,8 @@ static void __devinit de21041_get_srom_info (struct de_private *de) /* download entire eeprom */ for (i = 0; i < DE_EEPROM_WORDS; i++) - ((u16 *)ee_data)[i] = - le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size)); + ((__le16 *)ee_data)[i] = + cpu_to_le16(tulip_read_eeprom(de->regs, i, ee_addr_size)); /* DEC now has a specification but early board makers just put the address in the first EEPROM locations. */ diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 4633cc6dd412..9b9cd83fb8b6 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -482,7 +482,7 @@ static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n"; #define c_char const char -#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a))) +#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a))) /* ** MII Information @@ -756,10 +756,10 @@ struct de4x5_srom { /* Multiple of 4 for DC21040 */ /* Allows 512 byte alignment */ struct de4x5_desc { - volatile s32 status; - u32 des1; - u32 buf; - u32 next; + volatile __le32 status; + __le32 des1; + __le32 buf; + __le32 next; DESC_ALIGN }; diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 5a4d7270973e..3f69f53d7768 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -178,18 +178,18 @@ enum tulip_busconfig_bits { /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { - s32 status; - s32 length; - u32 buffer1; - u32 buffer2; + __le32 status; + __le32 length; + __le32 buffer1; + __le32 buffer2; }; struct tulip_tx_desc { - s32 status; - s32 length; - u32 buffer1; - u32 buffer2; /* We use only buffer 1. */ + __le32 status; + __le32 length; + __le32 buffer1; + __le32 buffer2; /* We use only buffer 1. */ }; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 80fee2292531..ee08292bcf85 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -326,8 +326,8 @@ static void tulip_up(struct net_device *dev) tp->dirty_rx = tp->dirty_tx = 0; if (tp->flags & MC_HASH_ONLY) { - u32 addr_low = le32_to_cpu(get_unaligned((u32 *)dev->dev_addr)); - u32 addr_high = le16_to_cpu(get_unaligned((u16 *)(dev->dev_addr+4))); + u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr)); + u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4))); if (tp->chip_id == AX88140) { iowrite32(0, ioaddr + CSR13); iowrite32(addr_low, ioaddr + CSR14); @@ -1443,13 +1443,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, do value = ioread32(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); - put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); + put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i); sum += value & 0xffff; } } else if (chip_idx == COMET) { /* No need to read the EEPROM. */ - put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (u32 *)dev->dev_addr); - put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (u16 *)(dev->dev_addr + 4)); + put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr); + put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4)); for (i = 0; i < 6; i ++) sum += dev->dev_addr[i]; } else { diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index a4fd782bcd27..53c7523960c4 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -112,13 +112,13 @@ /* Structure/enum declaration ------------------------------- */ struct tx_desc { - u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ + __le32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ char *tx_buf_ptr; /* Data for us */ struct tx_desc *next_tx_desc; } __attribute__(( aligned(32) )); struct rx_desc { - u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ + __le32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ struct sk_buff *rx_skb_ptr; /* Data for us */ struct rx_desc *next_rx_desc; } __attribute__(( aligned(32) )); @@ -344,7 +344,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, /* read 64 word srom data */ for (i = 0; i < 64; i++) - ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i)); + ((__le16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i)); /* Set Node address */ if(((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0) /* SROM absent, so read MAC address from ID Table */ diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 3c40dd6e1a2f..3c8e3b63be07 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -381,7 +381,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, goto err_out_free_res; for (i = 0; i < 3; i++) - ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i)); + ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(eeprom_read(ioaddr, i)); /* Reset the chip to erase previous misconfiguration. No hold time required! */ From 03a710ffcb0c4e682087f4cf4f0236d10ed09253 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:44:39 -0400 Subject: [PATCH 1451/2804] typhoon: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/typhoon.c | 36 ++++---- drivers/net/typhoon.h | 190 +++++++++++++++++++++--------------------- 2 files changed, 113 insertions(+), 113 deletions(-) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 43894e95fcb3..72e5e9be7e99 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -300,9 +300,9 @@ struct typhoon { const char * name; struct typhoon_shared * shared; dma_addr_t shared_dma; - u16 xcvr_select; - u16 wol_events; - u32 offload; + __le16 xcvr_select; + __le16 wol_events; + __le32 offload; /* unused stuff (future use) */ int capabilities; @@ -828,7 +828,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) first_txd->processFlags |= TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY; first_txd->processFlags |= - cpu_to_le32(htons(vlan_tx_tag_get(skb)) << + cpu_to_le32(ntohs(vlan_tx_tag_get(skb)) << TYPHOON_TX_PF_VLAN_TAG_SHIFT); } @@ -920,7 +920,7 @@ typhoon_set_rx_mode(struct net_device *dev) struct typhoon *tp = netdev_priv(dev); struct cmd_desc xp_cmd; u32 mc_filter[2]; - u16 filter; + __le16 filter; filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST; if(dev->flags & IFF_PROMISC) { @@ -1131,7 +1131,7 @@ typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct typhoon *tp = netdev_priv(dev); struct cmd_desc xp_cmd; - int xcvr; + __le16 xcvr; int err; err = -EINVAL; @@ -1536,7 +1536,7 @@ out_timeout: static u32 typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing, - volatile u32 * index) + volatile __le32 * index) { u32 lastRead = txRing->lastRead; struct tx_desc *tx; @@ -1572,7 +1572,7 @@ typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing, static void typhoon_tx_complete(struct typhoon *tp, struct transmit_ring *txRing, - volatile u32 * index) + volatile __le32 * index) { u32 lastRead; int numDesc = MAX_SKB_FRAGS + 1; @@ -1662,8 +1662,8 @@ typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx) } static int -typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready, - volatile u32 * cleared, int budget) +typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * ready, + volatile __le32 * cleared, int budget) { struct rx_desc *rx; struct sk_buff *skb, *new_skb; @@ -1673,7 +1673,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready, u32 rxaddr; int pkt_len; u32 idx; - u32 csum_bits; + __le32 csum_bits; int received; received = 0; @@ -1840,7 +1840,7 @@ typhoon_free_rx_rings(struct typhoon *tp) } static int -typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events) +typhoon_sleep(struct typhoon *tp, pci_power_t state, __le16 events) { struct pci_dev *pdev = tp->pdev; void __iomem *ioaddr = tp->ioaddr; @@ -1928,8 +1928,8 @@ typhoon_start_runtime(struct typhoon *tp) goto error_out; INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS); - xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0])); - xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2])); + xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0])); + xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2])); err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL); if(err < 0) goto error_out; @@ -2229,8 +2229,8 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state) } INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS); - xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0])); - xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2])); + xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0])); + xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2])); if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) { printk(KERN_ERR "%s: unable to set mac address in suspend\n", dev->name); @@ -2465,8 +2465,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto error_out_reset; } - *(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1)); - *(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2)); + *(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1)); + *(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2)); if(!is_valid_ether_addr(dev->dev_addr)) { printk(ERR_PFX "%s: Could not obtain valid ethernet address, " diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h index 2f14a050051b..19df20889b82 100644 --- a/drivers/net/typhoon.h +++ b/drivers/net/typhoon.h @@ -64,19 +64,19 @@ struct transmit_ring { */ struct typhoon_indexes { /* The first four are written by the host, and read by the NIC */ - volatile u32 rxHiCleared; - volatile u32 rxLoCleared; - volatile u32 rxBuffReady; - volatile u32 respCleared; + volatile __le32 rxHiCleared; + volatile __le32 rxLoCleared; + volatile __le32 rxBuffReady; + volatile __le32 respCleared; /* The remaining are written by the NIC, and read by the host */ - volatile u32 txLoCleared; - volatile u32 txHiCleared; - volatile u32 rxLoReady; - volatile u32 rxBuffCleared; - volatile u32 cmdCleared; - volatile u32 respReady; - volatile u32 rxHiReady; + volatile __le32 txLoCleared; + volatile __le32 txHiCleared; + volatile __le32 rxLoReady; + volatile __u32 rxBuffCleared; /* AV: really? */ + volatile __le32 cmdCleared; + volatile __le32 respReady; + volatile __le32 rxHiReady; } __attribute__ ((packed)); /* The host<->Typhoon interface @@ -100,31 +100,31 @@ struct typhoon_indexes { * be zero. */ struct typhoon_interface { - u32 ringIndex; - u32 ringIndexHi; - u32 txLoAddr; - u32 txLoAddrHi; - u32 txLoSize; - u32 txHiAddr; - u32 txHiAddrHi; - u32 txHiSize; - u32 rxLoAddr; - u32 rxLoAddrHi; - u32 rxLoSize; - u32 rxBuffAddr; - u32 rxBuffAddrHi; - u32 rxBuffSize; - u32 cmdAddr; - u32 cmdAddrHi; - u32 cmdSize; - u32 respAddr; - u32 respAddrHi; - u32 respSize; - u32 zeroAddr; - u32 zeroAddrHi; - u32 rxHiAddr; - u32 rxHiAddrHi; - u32 rxHiSize; + __le32 ringIndex; + __le32 ringIndexHi; + __le32 txLoAddr; + __le32 txLoAddrHi; + __le32 txLoSize; + __le32 txHiAddr; + __le32 txHiAddrHi; + __le32 txHiSize; + __le32 rxLoAddr; + __le32 rxLoAddrHi; + __le32 rxLoSize; + __le32 rxBuffAddr; + __le32 rxBuffAddrHi; + __le32 rxBuffSize; + __le32 cmdAddr; + __le32 cmdAddrHi; + __le32 cmdSize; + __le32 respAddr; + __le32 respAddrHi; + __le32 respSize; + __le32 zeroAddr; + __le32 zeroAddrHi; + __le32 rxHiAddr; + __le32 rxHiAddrHi; + __le32 rxHiSize; } __attribute__ ((packed)); /* The Typhoon transmit/fragment descriptor @@ -165,10 +165,10 @@ struct tx_desc { #define TYPHOON_RX_ERROR 0x40 #define TYPHOON_DESC_VALID 0x80 u8 numDesc; - u16 len; + __le16 len; u32 addr; u32 addrHi; - u32 processFlags; + __le32 processFlags; #define TYPHOON_TX_PF_NO_CRC __constant_cpu_to_le32(0x00000001) #define TYPHOON_TX_PF_IP_CHKSUM __constant_cpu_to_le32(0x00000002) #define TYPHOON_TX_PF_TCP_CHKSUM __constant_cpu_to_le32(0x00000004) @@ -197,12 +197,12 @@ struct tx_desc { struct tcpopt_desc { u8 flags; u8 numDesc; - u16 mss_flags; + __le16 mss_flags; #define TYPHOON_TSO_FIRST __constant_cpu_to_le16(0x1000) #define TYPHOON_TSO_LAST __constant_cpu_to_le16(0x2000) - u32 respAddrLo; - u32 bytesTx; - u32 status; + __le32 respAddrLo; + __le32 bytesTx; + __le32 status; } __attribute__ ((packed)); /* The IPSEC Offload descriptor @@ -216,12 +216,12 @@ struct tcpopt_desc { struct ipsec_desc { u8 flags; u8 numDesc; - u16 ipsecFlags; + __le16 ipsecFlags; #define TYPHOON_IPSEC_GEN_IV __constant_cpu_to_le16(0x0000) #define TYPHOON_IPSEC_USE_IV __constant_cpu_to_le16(0x0001) - u32 sa1; - u32 sa2; - u32 reserved; + __le32 sa1; + __le32 sa2; + __le32 reserved; } __attribute__ ((packed)); /* The Typhoon receive descriptor (Updated by NIC) @@ -239,10 +239,10 @@ struct ipsec_desc { struct rx_desc { u8 flags; u8 numDesc; - u16 frameLen; + __le16 frameLen; u32 addr; u32 addrHi; - u32 rxStatus; + __le32 rxStatus; #define TYPHOON_RX_ERR_INTERNAL __constant_cpu_to_le32(0x00000000) #define TYPHOON_RX_ERR_FIFO_UNDERRUN __constant_cpu_to_le32(0x00000001) #define TYPHOON_RX_ERR_BAD_SSD __constant_cpu_to_le32(0x00000002) @@ -264,10 +264,10 @@ struct rx_desc { #define TYPHOON_RX_IP_CHK_GOOD __constant_cpu_to_le32(0x00000100) #define TYPHOON_RX_TCP_CHK_GOOD __constant_cpu_to_le32(0x00000200) #define TYPHOON_RX_UDP_CHK_GOOD __constant_cpu_to_le32(0x00000400) - u16 filterResults; + __le16 filterResults; #define TYPHOON_RX_FILTER_MASK __constant_cpu_to_le16(0x7fff) #define TYPHOON_RX_FILTERED __constant_cpu_to_le16(0x8000) - u16 ipsecResults; + __le16 ipsecResults; #define TYPHOON_RX_OUTER_AH_GOOD __constant_cpu_to_le16(0x0001) #define TYPHOON_RX_OUTER_ESP_GOOD __constant_cpu_to_le16(0x0002) #define TYPHOON_RX_INNER_AH_GOOD __constant_cpu_to_le16(0x0004) @@ -278,7 +278,7 @@ struct rx_desc { #define TYPHOON_RX_INNER_ESP_FAIL __constant_cpu_to_le16(0x0080) #define TYPHOON_RX_UNKNOWN_SA __constant_cpu_to_le16(0x0100) #define TYPHOON_RX_ESP_FORMAT_ERR __constant_cpu_to_le16(0x0200) - u32 vlanTag; + __be32 vlanTag; } __attribute__ ((packed)); /* The Typhoon free buffer descriptor, used to give a buffer to the NIC @@ -292,8 +292,8 @@ struct rx_desc { * from the NIC */ struct rx_free { - u32 physAddr; - u32 physAddrHi; + __le32 physAddr; + __le32 physAddrHi; u32 virtAddr; u32 virtAddrHi; } __attribute__ ((packed)); @@ -312,7 +312,7 @@ struct rx_free { struct cmd_desc { u8 flags; u8 numDesc; - u16 cmd; + __le16 cmd; #define TYPHOON_CMD_TX_ENABLE __constant_cpu_to_le16(0x0001) #define TYPHOON_CMD_TX_DISABLE __constant_cpu_to_le16(0x0002) #define TYPHOON_CMD_RX_ENABLE __constant_cpu_to_le16(0x0003) @@ -339,9 +339,9 @@ struct cmd_desc { #define TYPHOON_CMD_GET_IPSEC_ENABLE __constant_cpu_to_le16(0x0067) #define TYPHOON_CMD_GET_CMD_LVL __constant_cpu_to_le16(0x0069) u16 seqNo; - u16 parm1; - u32 parm2; - u32 parm3; + __le16 parm1; + __le32 parm2; + __le32 parm3; } __attribute__ ((packed)); /* The Typhoon response descriptor, see command descriptor for details @@ -349,11 +349,11 @@ struct cmd_desc { struct resp_desc { u8 flags; u8 numDesc; - u16 cmd; - u16 seqNo; - u16 parm1; - u32 parm2; - u32 parm3; + __le16 cmd; + __le16 seqNo; + __le16 parm1; + __le32 parm2; + __le32 parm3; } __attribute__ ((packed)); #define INIT_COMMAND_NO_RESPONSE(x, command) \ @@ -386,31 +386,31 @@ struct resp_desc { struct stats_resp { u8 flags; u8 numDesc; - u16 cmd; - u16 seqNo; - u16 unused; - u32 txPackets; - u64 txBytes; - u32 txDeferred; - u32 txLateCollisions; - u32 txCollisions; - u32 txCarrierLost; - u32 txMultipleCollisions; - u32 txExcessiveCollisions; - u32 txFifoUnderruns; - u32 txMulticastTxOverflows; - u32 txFiltered; - u32 rxPacketsGood; - u64 rxBytesGood; - u32 rxFifoOverruns; - u32 BadSSD; - u32 rxCrcErrors; - u32 rxOversized; - u32 rxBroadcast; - u32 rxMulticast; - u32 rxOverflow; - u32 rxFiltered; - u32 linkStatus; + __le16 cmd; + __le16 seqNo; + __le16 unused; + __le32 txPackets; + __le64 txBytes; + __le32 txDeferred; + __le32 txLateCollisions; + __le32 txCollisions; + __le32 txCarrierLost; + __le32 txMultipleCollisions; + __le32 txExcessiveCollisions; + __le32 txFifoUnderruns; + __le32 txMulticastTxOverflows; + __le32 txFiltered; + __le32 rxPacketsGood; + __le64 rxBytesGood; + __le32 rxFifoOverruns; + __le32 BadSSD; + __le32 rxCrcErrors; + __le32 rxOversized; + __le32 rxBroadcast; + __le32 rxMulticast; + __le32 rxOverflow; + __le32 rxFiltered; + __le32 linkStatus; #define TYPHOON_LINK_STAT_MASK __constant_cpu_to_le32(0x00000001) #define TYPHOON_LINK_GOOD __constant_cpu_to_le32(0x00000001) #define TYPHOON_LINK_BAD __constant_cpu_to_le32(0x00000000) @@ -420,8 +420,8 @@ struct stats_resp { #define TYPHOON_LINK_DUPLEX_MASK __constant_cpu_to_le32(0x00000004) #define TYPHOON_LINK_FULL_DUPLEX __constant_cpu_to_le32(0x00000004) #define TYPHOON_LINK_HALF_DUPLEX __constant_cpu_to_le32(0x00000000) - u32 unused2; - u32 unused3; + __le32 unused2; + __le32 unused3; } __attribute__ ((packed)); /* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1) @@ -509,17 +509,17 @@ struct sa_descriptor { */ struct typhoon_file_header { u8 tag[8]; - u32 version; - u32 numSections; - u32 startAddr; - u32 hmacDigest[5]; + __le32 version; + __le32 numSections; + __le32 startAddr; + __le32 hmacDigest[5]; } __attribute__ ((packed)); struct typhoon_section_header { - u32 len; + __le32 len; u16 checksum; u16 reserved; - u32 startAddr; + __le32 startAddr; } __attribute__ ((packed)); /* The Typhoon Register offsets From 3e33545ba6f8ca04b28a015e095662a35a4e2670 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:45:46 -0400 Subject: [PATCH 1452/2804] pcnet32: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 98 +++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 36f92dd55508..5f994b5beda1 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -210,31 +210,31 @@ static int homepna[MAX_UNITS]; /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { - u32 base; - s16 buf_length; /* two`s complement of length */ - s16 status; - u32 msg_length; - u32 reserved; + __le32 base; + __le16 buf_length; /* two`s complement of length */ + __le16 status; + __le32 msg_length; + __le32 reserved; }; struct pcnet32_tx_head { - u32 base; - s16 length; /* two`s complement of length */ - s16 status; - u32 misc; - u32 reserved; + __le32 base; + __le16 length; /* two`s complement of length */ + __le16 status; + __le32 misc; + __le32 reserved; }; /* The PCNET32 32-Bit initialization block, described in databook. */ struct pcnet32_init_block { - u16 mode; - u16 tlen_rlen; + __le16 mode; + __le16 tlen_rlen; u8 phys_addr[6]; - u16 reserved; - u32 filter[2]; + __le16 reserved; + __le32 filter[2]; /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; - u32 tx_ring; + __le32 rx_ring; + __le32 tx_ring; }; /* PCnet32 access functions */ @@ -610,9 +610,9 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, new_dma_addr_list[new] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); - new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]); - new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ); - new_rx_ring[new].status = le16_to_cpu(0x8000); + new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]); + new_rx_ring[new].buf_length = cpu_to_le16(2 - PKT_BUF_SZ); + new_rx_ring[new].status = cpu_to_le16(0x8000); } /* and free any unneeded buffers */ for (; new < lp->rx_ring_size; new++) { @@ -888,7 +888,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) int x, i; /* counters */ int numbuffs = 4; /* number of TX/RX buffers and descs */ u16 status = 0x8300; /* TX ring status */ - u16 teststatus; /* test of ring status */ + __le16 teststatus; /* test of ring status */ int rc; /* return code */ int size; /* size of packets */ unsigned char *packet; /* source packet data */ @@ -935,7 +935,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) packet = skb->data; skb_put(skb, size); /* create space for data */ lp->tx_skbuff[x] = skb; - lp->tx_ring[x].length = le16_to_cpu(-skb->len); + lp->tx_ring[x].length = cpu_to_le16(-skb->len); lp->tx_ring[x].misc = 0; /* put DA and SA into the skb */ @@ -955,10 +955,9 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) lp->tx_dma_addr[x] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); - lp->tx_ring[x].base = - (u32) le32_to_cpu(lp->tx_dma_addr[x]); + lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]); wmb(); /* Make sure owner changes after all others are visible */ - lp->tx_ring[x].status = le16_to_cpu(status); + lp->tx_ring[x].status = cpu_to_le16(status); } } @@ -969,7 +968,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) x = a->read_csr(ioaddr, CSR15) & 0xfffc; lp->a.write_csr(ioaddr, CSR15, x | 0x0044); - teststatus = le16_to_cpu(0x8000); + teststatus = cpu_to_le16(0x8000); lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */ /* Check status of descriptors */ @@ -1099,6 +1098,7 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data) mod_timer(&lp->blink_timer, jiffies); set_current_state(TASK_INTERRUPTIBLE); + /* AV: the limit here makes no sense whatsoever */ if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ))) data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ); @@ -1224,7 +1224,7 @@ static void pcnet32_rx_entry(struct net_device *dev, newskb->data, PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); - rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]); + rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]); rx_in_place = 1; } else skb = NULL; @@ -1283,9 +1283,9 @@ static int pcnet32_rx(struct net_device *dev, int budget) * The docs say that the buffer length isn't touched, but Andrew * Boyd of QNX reports that some revs of the 79C965 clear it. */ - rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ); + rxp->buf_length = cpu_to_le16(2 - PKT_BUF_SZ); wmb(); /* Make sure owner changes after others are visible */ - rxp->status = le16_to_cpu(0x8000); + rxp->status = cpu_to_le16(0x8000); entry = (++lp->cur_rx) & lp->rx_mod_mask; rxp = &lp->rx_ring[entry]; } @@ -1875,15 +1875,15 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) && dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; - lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ + lp->init_block->mode = cpu_to_le16(0x0003); /* Disable Rx and Tx. */ lp->init_block->tlen_rlen = - le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); + cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block->phys_addr[i] = dev->dev_addr[i]; lp->init_block->filter[0] = 0x00000000; lp->init_block->filter[1] = 0x00000000; - lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr); + lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); @@ -2274,7 +2274,7 @@ static int pcnet32_open(struct net_device *dev) #endif lp->init_block->mode = - le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); + cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7); pcnet32_load_multicast(dev); if (pcnet32_init_ring(dev)) { @@ -2401,10 +2401,10 @@ static int pcnet32_init_ring(struct net_device *dev) lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); - lp->rx_ring[i].base = (u32) le32_to_cpu(lp->rx_dma_addr[i]); - lp->rx_ring[i].buf_length = le16_to_cpu(2 - PKT_BUF_SZ); + lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]); + lp->rx_ring[i].buf_length = cpu_to_le16(2 - PKT_BUF_SZ); wmb(); /* Make sure owner changes after all others are visible */ - lp->rx_ring[i].status = le16_to_cpu(0x8000); + lp->rx_ring[i].status = cpu_to_le16(0x8000); } /* The Tx buffer address is filled in as needed, but we do need to clear * the upper ownership bit. */ @@ -2416,11 +2416,11 @@ static int pcnet32_init_ring(struct net_device *dev) } lp->init_block->tlen_rlen = - le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); + cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block->phys_addr[i] = dev->dev_addr[i]; - lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr); + lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr); wmb(); /* Make sure all changes are visible */ return 0; } @@ -2529,16 +2529,16 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Caution: the write order is important here, set the status * with the "ownership" bits last. */ - lp->tx_ring[entry].length = le16_to_cpu(-skb->len); + lp->tx_ring[entry].length = cpu_to_le16(-skb->len); lp->tx_ring[entry].misc = 0x00000000; lp->tx_skbuff[entry] = skb; lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); - lp->tx_ring[entry].base = (u32) le32_to_cpu(lp->tx_dma_addr[entry]); + lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]); wmb(); /* Make sure owner changes after all others are visible */ - lp->tx_ring[entry].status = le16_to_cpu(status); + lp->tx_ring[entry].status = cpu_to_le16(status); lp->cur_tx++; lp->stats.tx_bytes += skb->len; @@ -2709,7 +2709,7 @@ static void pcnet32_load_multicast(struct net_device *dev) { struct pcnet32_private *lp = netdev_priv(dev); volatile struct pcnet32_init_block *ib = lp->init_block; - volatile u16 *mcast_table = (u16 *) & ib->filter; + volatile __le16 *mcast_table = (__le16 *)ib->filter; struct dev_mc_list *dmi = dev->mc_list; unsigned long ioaddr = dev->base_addr; char *addrs; @@ -2718,8 +2718,8 @@ static void pcnet32_load_multicast(struct net_device *dev) /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI) { - ib->filter[0] = 0xffffffff; - ib->filter[1] = 0xffffffff; + ib->filter[0] = cpu_to_le32(~0U); + ib->filter[1] = cpu_to_le32(~0U); lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff); lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff); lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff); @@ -2741,9 +2741,7 @@ static void pcnet32_load_multicast(struct net_device *dev) crc = ether_crc_le(6, addrs); crc = crc >> 26; - mcast_table[crc >> 4] = - le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) | - (1 << (crc & 0xf))); + mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf)); } for (i = 0; i < 4; i++) lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i, @@ -2769,12 +2767,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev) printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); lp->init_block->mode = - le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << + cpu_to_le16(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000); } else { lp->init_block->mode = - le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); + cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff); pcnet32_load_multicast(dev); } From c676504ef5fe682bd343149de0e5c57bbf793ff9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:47:03 -0400 Subject: [PATCH 1453/2804] ixgb: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/ixgb/ixgb_ee.c | 16 ++++++++-------- drivers/net/ixgb/ixgb_ee.h | 28 ++++++++++++++-------------- drivers/net/ixgb/ixgb_ethtool.c | 4 ++-- drivers/net/ixgb/ixgb_hw.h | 4 ++-- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c index 52c99d01d568..e8eb0fd6c576 100644 --- a/drivers/net/ixgb/ixgb_ee.c +++ b/drivers/net/ixgb/ixgb_ee.c @@ -411,7 +411,7 @@ ixgb_write_eeprom(struct ixgb_hw *hw, uint16_t offset, uint16_t data) ixgb_cleanup_eeprom(hw); /* clear the init_ctrl_reg_1 to signify that the cache is invalidated */ - ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR); + ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR); return; } @@ -476,19 +476,19 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw) uint16_t ee_data; ee_data = ixgb_read_eeprom(hw, i); checksum += ee_data; - hw->eeprom[i] = le16_to_cpu(ee_data); + hw->eeprom[i] = cpu_to_le16(ee_data); } if (checksum != (uint16_t) EEPROM_SUM) { DEBUGOUT("ixgb_ee: Checksum invalid.\n"); /* clear the init_ctrl_reg_1 to signify that the cache is * invalidated */ - ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR); + ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR); return (FALSE); } - if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK)) - != le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) { + if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK)) + != cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) { DEBUGOUT("ixgb_ee: Signature invalid.\n"); return(FALSE); } @@ -511,8 +511,8 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw) { struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK)) - == le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) { + if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK)) + == cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) { return (TRUE); } else { return ixgb_get_eeprom_data(hw); @@ -528,7 +528,7 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw) * Returns: * Word at indexed offset in eeprom, if valid, 0 otherwise. ******************************************************************************/ -uint16_t +__le16 ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index) { diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h index ef236b935c15..7908bf3005ed 100644 --- a/drivers/net/ixgb/ixgb_ee.h +++ b/drivers/net/ixgb/ixgb_ee.h @@ -76,22 +76,22 @@ /* EEPROM structure */ struct ixgb_ee_map_type { uint8_t mac_addr[IXGB_ETH_LENGTH_OF_ADDRESS]; - uint16_t compatibility; - uint16_t reserved1[4]; - uint32_t pba_number; - uint16_t init_ctrl_reg_1; - uint16_t subsystem_id; - uint16_t subvendor_id; - uint16_t device_id; - uint16_t vendor_id; - uint16_t init_ctrl_reg_2; - uint16_t oem_reserved[16]; - uint16_t swdpins_reg; - uint16_t circuit_ctrl_reg; + __le16 compatibility; + __le16 reserved1[4]; + __le32 pba_number; + __le16 init_ctrl_reg_1; + __le16 subsystem_id; + __le16 subvendor_id; + __le16 device_id; + __le16 vendor_id; + __le16 init_ctrl_reg_2; + __le16 oem_reserved[16]; + __le16 swdpins_reg; + __le16 circuit_ctrl_reg; uint8_t d3_power; uint8_t d0_power; - uint16_t reserved2[28]; - uint16_t checksum; + __le16 reserved2[28]; + __le16 checksum; }; /* EEPROM Functions */ diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index ddad26bb5c58..fddd5844168d 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -422,7 +422,7 @@ ixgb_get_eeprom(struct net_device *netdev, { struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; - uint16_t *eeprom_buff; + __le16 *eeprom_buff; int i, max_len, first_word, last_word; int ret_val = 0; @@ -446,7 +446,7 @@ ixgb_get_eeprom(struct net_device *netdev, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(uint16_t) * + eeprom_buff = kmalloc(sizeof(__le16) * (last_word - first_word + 1), GFP_KERNEL); if(!eeprom_buff) return -ENOMEM; diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index 40ef5ca88717..af5643324ee3 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -711,7 +711,7 @@ struct ixgb_hw { uint32_t bar2; uint32_t bar3; uint16_t pci_cmd_word; /* PCI command register id from PCI configuration space */ - uint16_t eeprom[IXGB_EEPROM_SIZE]; /* EEPROM contents read at init time */ + __le16 eeprom[IXGB_EEPROM_SIZE]; /* EEPROM contents read at init time */ unsigned long io_base; /* Our I/O mapped location */ uint32_t lastLFC; uint32_t lastRFC; @@ -809,7 +809,7 @@ void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr); uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw); uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw); boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw); -uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index); +__le16 ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index); /* Everything else */ void ixgb_led_on(struct ixgb_hw *hw); From 37e1370b701b9a032399e8e2d130009eefa66782 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:54:10 -0400 Subject: [PATCH 1454/2804] drivers/net/irda: endianness, NULL noise Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/irda/mcs7780.c | 2 +- drivers/net/irda/sir_dev.c | 2 +- drivers/net/irda/stir4200.c | 2 +- drivers/net/irda/vlsi_ir.h | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 808939b9f8fb..0b769192d4ce 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -464,7 +464,7 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) } fcs = ~(crc32_le(~0, buf, new_len)); - if(fcs != le32_to_cpu(get_unaligned((u32 *)(buf+new_len)))) { + if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) { IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len); mcs->stats.rx_errors++; mcs->stats.rx_crc_errors++; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index bbe4e094c424..6078e03de9a8 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -414,7 +414,7 @@ EXPORT_SYMBOL(sirdev_raw_read); int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts) { int ret = -ENXIO; - if (dev->drv->set_dtr_rts != 0) + if (dev->drv->set_dtr_rts) ret = dev->drv->set_dtr_rts(dev, dtr, rts); return ret; } diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 1afaee0fa7e0..042bc2f0417d 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -332,7 +332,7 @@ static void fir_eof(struct stir_cb *stir) } fcs = ~(crc32_le(~0, rx_buff->data, len)); - if (fcs != le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len)))) { + if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) { pr_debug("crc error calc 0x%x len %d\n", fcs, len); stir->stats.rx_errors++; stir->stats.rx_crc_errors++; diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index ca12a6096419..c8b9c74eea52 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -537,10 +537,10 @@ calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect) */ struct ring_descr_hw { - volatile u16 rd_count; /* tx/rx count [11:0] */ - u16 reserved; + volatile __le16 rd_count; /* tx/rx count [11:0] */ + __le16 reserved; union { - u32 addr; /* [23:0] of the buffer's busaddress */ + __le32 addr; /* [23:0] of the buffer's busaddress */ struct { u8 addr_res[3]; volatile u8 status; /* descriptor status */ From 88b1943bd3e4d2620e5936181861e00bf6236aa4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:29:45 -0400 Subject: [PATCH 1455/2804] starfire: trivial endianness annotations Note: we still have several fishy areas - mcast filter and vlan handling. Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/starfire.c | 88 +++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index ea253754763a..bcc430bd9e49 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -155,7 +155,7 @@ static int full_duplex[MAX_UNITS] = {0, }; #if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) /* 64-bit dma_addr_t */ #define ADDR_64BITS /* This chip uses 64 bit addresses. */ -#define netdrv_addr_t u64 +#define netdrv_addr_t __le64 #define cpu_to_dma(x) cpu_to_le64(x) #define dma_to_cpu(x) le64_to_cpu(x) #define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit @@ -164,7 +164,7 @@ static int full_duplex[MAX_UNITS] = {0, }; #define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit #define RX_DESC_ADDR_SIZE RxDescAddr64bit #else /* 32-bit dma_addr_t */ -#define netdrv_addr_t u32 +#define netdrv_addr_t __le32 #define cpu_to_dma(x) cpu_to_le32(x) #define dma_to_cpu(x) le32_to_cpu(x) #define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit @@ -494,7 +494,7 @@ enum intr_ctrl_bits { /* The Rx and Tx buffer descriptors. */ struct starfire_rx_desc { - dma_addr_t rxaddr; + netdrv_addr_t rxaddr; }; enum rx_desc_bits { RxDescValid=1, RxDescEndRing=2, @@ -502,25 +502,25 @@ enum rx_desc_bits { /* Completion queue entry. */ struct short_rx_done_desc { - u32 status; /* Low 16 bits is length. */ + __le32 status; /* Low 16 bits is length. */ }; struct basic_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 vlanid; - u16 status2; + __le32 status; /* Low 16 bits is length. */ + __le16 vlanid; + __le16 status2; }; struct csum_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 csum; /* Partial checksum */ - u16 status2; + __le32 status; /* Low 16 bits is length. */ + __le16 csum; /* Partial checksum */ + __le16 status2; }; struct full_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 status3; - u16 status2; - u16 vlanid; - u16 csum; /* partial checksum */ - u32 timestamp; + __le32 status; /* Low 16 bits is length. */ + __le16 status3; + __le16 status2; + __le16 vlanid; + __le16 csum; /* partial checksum */ + __le32 timestamp; }; /* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */ #ifdef VLAN_SUPPORT @@ -537,15 +537,15 @@ enum rx_done_bits { /* Type 1 Tx descriptor. */ struct starfire_tx_desc_1 { - u32 status; /* Upper bits are status, lower 16 length. */ - u32 addr; + __le32 status; /* Upper bits are status, lower 16 length. */ + __le32 addr; }; /* Type 2 Tx descriptor. */ struct starfire_tx_desc_2 { - u32 status; /* Upper bits are status, lower 16 length. */ - u32 reserved; - u64 addr; + __le32 status; /* Upper bits are status, lower 16 length. */ + __le32 reserved; + __le64 addr; }; #ifdef ADDR_64BITS @@ -563,9 +563,9 @@ enum tx_desc_bits { TxRingWrap=0x04000000, TxCalTCP=0x02000000, }; struct tx_done_desc { - u32 status; /* timestamp, index. */ + __le32 status; /* timestamp, index. */ #if 0 - u32 intrstatus; /* interrupt status */ + __le32 intrstatus; /* interrupt status */ #endif }; @@ -963,7 +963,7 @@ static int netdev_open(struct net_device *dev) dev->name, dev->irq); /* Allocate the various queues. */ - if (np->queue_mem == 0) { + if (!np->queue_mem) { tx_done_q_size = ((sizeof(struct tx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; rx_done_q_size = ((sizeof(rx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; tx_ring_size = ((sizeof(starfire_tx_desc) * TX_RING_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; @@ -1036,11 +1036,11 @@ static int netdev_open(struct net_device *dev) writew(0, ioaddr + PerfFilterTable + 4); writew(0, ioaddr + PerfFilterTable + 8); for (i = 1; i < 16; i++) { - u16 *eaddrs = (u16 *)dev->dev_addr; + __be16 *eaddrs = (__be16 *)dev->dev_addr; void __iomem *setup_frm = ioaddr + PerfFilterTable + i * 16; - writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4; - writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4; - writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8; + writew(be16_to_cpu(eaddrs[2]), setup_frm); setup_frm += 4; + writew(be16_to_cpu(eaddrs[1]), setup_frm); setup_frm += 4; + writew(be16_to_cpu(eaddrs[0]), setup_frm); setup_frm += 8; } /* Initialize other registers. */ @@ -1767,26 +1767,26 @@ static void set_rx_mode(struct net_device *dev) } else if (dev->mc_count <= 14) { /* Use the 16 element perfect filter, skip first two entries. */ void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16; - u16 *eaddrs; + __be16 *eaddrs; for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2; i++, mclist = mclist->next) { - eaddrs = (u16 *)mclist->dmi_addr; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8; + eaddrs = (__be16 *)mclist->dmi_addr; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8; } - eaddrs = (u16 *)dev->dev_addr; + eaddrs = (__be16 *)dev->dev_addr; while (i++ < 16) { - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8; } rx_mode |= AcceptBroadcast|PerfectFilter; } else { /* Must use a multicast hash table. */ void __iomem *filter_addr; - u16 *eaddrs; - u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ + __be16 *eaddrs; + __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; @@ -1794,17 +1794,17 @@ static void set_rx_mode(struct net_device *dev) /* The chip uses the upper 9 CRC bits as index into the hash table */ int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23; - __u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1]; + __le32 *fptr = (__le32 *) &mc_filter[(bit_nr >> 4) & ~1]; *fptr |= cpu_to_le32(1 << (bit_nr & 31)); } /* Clear the perfect filter list, skip first two entries. */ filter_addr = ioaddr + PerfFilterTable + 2 * 16; - eaddrs = (u16 *)dev->dev_addr; + eaddrs = (__be16 *)dev->dev_addr; for (i = 2; i < 16; i++) { - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8; } for (filter_addr = ioaddr + HashTable, i = 0; i < 32; filter_addr+= 16, i++) writew(mc_filter[i], filter_addr); From b1eab70130fd60082cce11caba14fe8c99a018e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:30:16 -0400 Subject: [PATCH 1456/2804] r8169: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/r8169.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index eecd811feead..419c00cbe6e9 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -977,19 +977,19 @@ static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = { }; struct rtl8169_counters { - u64 tx_packets; - u64 rx_packets; - u64 tx_errors; - u32 rx_errors; - u16 rx_missed; - u16 align_errors; - u32 tx_one_collision; - u32 tx_multi_collision; - u64 rx_unicast; - u64 rx_broadcast; - u32 rx_multicast; - u16 tx_aborted; - u16 tx_underun; + __le64 tx_packets; + __le64 rx_packets; + __le64 tx_errors; + __le32 rx_errors; + __le16 rx_missed; + __le16 align_errors; + __le32 tx_one_collision; + __le32 tx_multi_collision; + __le64 rx_unicast; + __le64 rx_broadcast; + __le32 rx_multicast; + __le16 tx_aborted; + __le16 tx_underun; }; static int rtl8169_get_sset_count(struct net_device *dev, int sset) From 53c03f5c9e3c05a2484ad6bb1d88c0aa54befa47 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:33:30 -0400 Subject: [PATCH 1457/2804] via-rhine: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 9669bce0fd07..07263cd93f9c 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -335,16 +335,16 @@ enum wol_bits { /* The Rx and Tx buffer descriptors. */ struct rx_desc { - s32 rx_status; - u32 desc_length; /* Chain flag, Buffer/frame length */ - u32 addr; - u32 next_desc; + __le32 rx_status; + __le32 desc_length; /* Chain flag, Buffer/frame length */ + __le32 addr; + __le32 next_desc; }; struct tx_desc { - s32 tx_status; - u32 desc_length; /* Chain flag, Tx Config, Frame length */ - u32 addr; - u32 next_desc; + __le32 tx_status; + __le32 desc_length; /* Chain flag, Tx Config, Frame length */ + __le32 addr; + __le32 next_desc; }; /* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */ From b963dc1df78399a2166c2e6e3eb726a2dc98cf11 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:55:33 -0400 Subject: [PATCH 1458/2804] pppoe: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/pppoe.c | 18 +++++++++--------- include/linux/if_pppox.h | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index ba2eb04aac9f..d48b7b73d896 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -103,7 +103,7 @@ static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b) (memcmp(a->remote, b->remote, ETH_ALEN) == 0)); } -static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr) +static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr) { return (a->sid == sid && (memcmp(a->remote,addr,ETH_ALEN) == 0)); @@ -113,7 +113,7 @@ static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr) #error 8 must be a multiple of PPPOE_HASH_BITS #endif -static int hash_item(unsigned int sid, unsigned char *addr) +static int hash_item(__be16 sid, unsigned char *addr) { unsigned char hash = 0; unsigned int i; @@ -122,7 +122,7 @@ static int hash_item(unsigned int sid, unsigned char *addr) hash ^= addr[i]; } for (i = 0 ; i < sizeof(sid_t)*8 ; i += 8 ){ - hash ^= sid>>i; + hash ^= (__force __u32)sid>>i; } for (i = 8 ; (i>>=1) >= PPPOE_HASH_BITS ; ) { hash ^= hash>>i; @@ -139,7 +139,7 @@ static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE]; * Set/get/delete/rehash items (internal versions) * **********************************************************************/ -static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr, int ifindex) +static struct pppox_sock *__get_item(__be16 sid, unsigned char *addr, int ifindex) { int hash = hash_item(sid, addr); struct pppox_sock *ret; @@ -171,7 +171,7 @@ static int __set_item(struct pppox_sock *po) return 0; } -static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifindex) +static struct pppox_sock *__delete_item(__be16 sid, char *addr, int ifindex) { int hash = hash_item(sid, addr); struct pppox_sock *ret, **src; @@ -197,7 +197,7 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifind * Set/get/delete/rehash items * **********************************************************************/ -static inline struct pppox_sock *get_item(unsigned long sid, +static inline struct pppox_sock *get_item(__be16 sid, unsigned char *addr, int ifindex) { struct pppox_sock *po; @@ -224,7 +224,7 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex); } -static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex) +static inline struct pppox_sock *delete_item(__be16 sid, char *addr, int ifindex) { struct pppox_sock *ret; @@ -400,7 +400,7 @@ static int pppoe_rcv(struct sk_buff *skb, ph = pppoe_hdr(skb); - po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); + po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex); if (po != NULL) return sk_receive_skb(sk_pppox(po), skb, 0); drop: @@ -437,7 +437,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb, if (ph->code != PADT_CODE) goto abort; - po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); + po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex); if (po) { struct sock *sk = sk_pppox(po); diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h index 43cfc9f0c078..40743e032845 100644 --- a/include/linux/if_pppox.h +++ b/include/linux/if_pppox.h @@ -40,7 +40,7 @@ /************************************************************************ * PPPoE addressing definition */ -typedef __u16 sid_t; +typedef __be16 sid_t; struct pppoe_addr{ sid_t sid; /* Session identifier */ unsigned char remote[ETH_ALEN]; /* Remote address */ @@ -90,8 +90,8 @@ struct sockaddr_pppol2tp { #define PADS_CODE 0x65 #define PADT_CODE 0xa7 struct pppoe_tag { - __u16 tag_type; - __u16 tag_len; + __be16 tag_type; + __be16 tag_len; char tag_data[0]; } __attribute ((packed)); @@ -118,8 +118,8 @@ struct pppoe_hdr { #error "Please fix " #endif __u8 code; - __u16 sid; - __u16 length; + __be16 sid; + __be16 length; struct pppoe_tag tag[0]; } __attribute__ ((packed)); @@ -152,7 +152,7 @@ struct pppox_sock { union { struct pppoe_opt pppoe; } proto; - unsigned short num; + __be16 num; }; #define pppoe_dev proto.pppoe.dev #define pppoe_ifindex proto.pppoe.ifindex From 2929e7700fb64f58f9c501a293b98b6bf6c49403 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:57:00 -0400 Subject: [PATCH 1459/2804] tms380tr: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/tokenring/tms380tr.c | 4 ++-- drivers/net/tokenring/tms380tr.h | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 12bd294045a7..d5fa36d36515 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -2124,7 +2124,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) /* Get the frame size (Byte swap for Intel). * Do this early (see workaround comment below) */ - Length = be16_to_cpu((unsigned short)rpl->FrameSize); + Length = be16_to_cpu(rpl->FrameSize); /* Check if the Frame_Start, Frame_End and * Frame_Complete bits are set. @@ -2140,7 +2140,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) * Length2 is there because there have also been * cases where the FrameSize was partially written */ - Length2 = be16_to_cpu((unsigned short)rpl->FrameSize); + Length2 = be16_to_cpu(rpl->FrameSize); if(Length == 0 || Length != Length2) { diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h index 2a16078ac3fd..7daf74e31ccd 100644 --- a/drivers/net/tokenring/tms380tr.h +++ b/drivers/net/tokenring/tms380tr.h @@ -476,13 +476,13 @@ typedef struct { * bytes = 0xC000 */ u_int32_t FunctAddr; /* High order bytes = 0xC000 */ - u_int16_t RxListSize; /* RPL size: 0 (=26), 14, 20 or + __be16 RxListSize; /* RPL size: 0 (=26), 14, 20 or * 26 bytes read by the adapter. * (Depending on the number of * fragments/list) */ - u_int16_t TxListSize; /* TPL size */ - u_int16_t BufSize; /* Is automatically rounded up to the + __be16 TxListSize; /* TPL size */ + __be16 BufSize; /* Is automatically rounded up to the * nearest nK boundary. */ u_int16_t FullDuplex; @@ -580,14 +580,14 @@ typedef struct { /*--------------------- Send and Receive definitions -------------------*/ #pragma pack(1) typedef struct { - u_int16_t DataCount; /* Value 0, even and odd values are + __be16 DataCount; /* Value 0, even and odd values are * permitted; value is unaltered most * significant bit set: following * fragments last fragment: most * significant bit is not evaluated. * (???) */ - u_int32_t DataAddr; /* Pointer to frame data fragment; + __be32 DataAddr; /* Pointer to frame data fragment; * even or odd. */ } Fragment; @@ -679,7 +679,7 @@ typedef struct { typedef struct s_TPL TPL; struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ - u_int32_t NextTPLAddr; /* Pointer to next TPL in chain; if + __be32 NextTPLAddr; /* Pointer to next TPL in chain; if * pointer is odd: this is the last * TPL. Pointing to itself can cause * problems! @@ -689,7 +689,7 @@ struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ * significant bit first! Set by the * adapter: CSTAT_COMPLETE status. */ - u_int16_t FrameSize; /* Number of bytes to be transmitted + __be16 FrameSize; /* Number of bytes to be transmitted * as a frame including AC/FC, * Destination, Source, Routing field * not including CRC, FS, End Delimiter @@ -1020,7 +1020,7 @@ enum SKB_STAT { #pragma pack(1) typedef struct s_RPL RPL; struct s_RPL { /* Receive Parameter List */ - u_int32_t NextRPLAddr; /* Pointer to next RPL in chain + __be32 NextRPLAddr; /* Pointer to next RPL in chain * (normalized = physical 32 bit * address) if pointer is odd: this * is last RPL. Pointing to itself can @@ -1031,7 +1031,7 @@ struct s_RPL { /* Receive Parameter List */ * adapter in lists that start or end * a frame. */ - volatile u_int16_t FrameSize; /* Number of bytes received as a + volatile __be16 FrameSize; /* Number of bytes received as a * frame including AC/FC, Destination, * Source, Routing field not including * CRC, FS (Frame Status), End Delimiter From 16989ba6e9c501ffc004ec3c031b1c6065708ccf Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 03:03:13 -0400 Subject: [PATCH 1460/2804] drivers/net/appletalk: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/appletalk/ipddp.c | 2 +- drivers/net/appletalk/ipddp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 56cb96794026..1071144edd66 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -116,7 +116,7 @@ static struct net_device_stats *ipddp_get_stats(struct net_device *dev) */ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) { - u32 paddr = ((struct rtable*)skb->dst)->rt_gateway; + __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway; struct ddpehdr *ddp; struct ipddp_route *rt; struct atalk_addr *our_addr; diff --git a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h index 52072fb0c610..531519da99a3 100644 --- a/drivers/net/appletalk/ipddp.h +++ b/drivers/net/appletalk/ipddp.h @@ -14,7 +14,7 @@ struct ipddp_route { struct net_device *dev; /* Carrier device */ - __u32 ip; /* IP address */ + __be32 ip; /* IP address */ struct atalk_addr at; /* Gateway appletalk address */ int flags; struct ipddp_route *next; From bd7eb1c549188e4f7993e324b1bbe267fc13675c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 03:03:51 -0400 Subject: [PATCH 1461/2804] 3c509: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/3c509.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index c576fe76d54f..edda6e10ebe5 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -299,7 +299,7 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = { { } /* terminate list */ }; -static u16 el3_isapnp_phys_addr[8][3]; +static __be16 el3_isapnp_phys_addr[8][3]; static int nopnp; #endif /* __ISAPNP__ */ @@ -379,7 +379,7 @@ static int __init el3_probe(int card_idx) struct el3_private *lp; short lrs_state = 0xff, i; int ioaddr, irq, if_port; - u16 phys_addr[3]; + __be16 phys_addr[3]; static int current_tag; int err = -ENODEV; #if defined(__ISAPNP__) From fb8e4444cc8c7719d9947e21a93e2e84bb1b36eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 03:04:12 -0400 Subject: [PATCH 1462/2804] cxgb3: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 4 ++-- drivers/net/cxgb3/sge.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 3e5b0db7784e..99c75d30f67a 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -168,8 +168,8 @@ enum { }; struct sg_ent { /* SGE scatter/gather entry */ - u32 len[2]; - u64 addr[2]; + __be32 len[2]; + __be64 addr[2]; }; #ifndef SGE_NUM_GENBITS diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 540ce5fa1d32..77f3ec5ff8a7 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -79,7 +79,7 @@ enum { }; struct tx_desc { - u64 flit[TX_DESC_FLITS]; + __be64 flit[TX_DESC_FLITS]; }; struct rx_desc { @@ -904,8 +904,8 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, const struct sge_txq *q, const struct sg_ent *sgl, unsigned int flits, unsigned int sgl_flits, - unsigned int gen, unsigned int wr_hi, - unsigned int wr_lo) + unsigned int gen, __be32 wr_hi, + __be32 wr_lo) { struct work_request_hdr *wrp = (struct work_request_hdr *)d; struct tx_sw_desc *sd = &q->sdesc[pidx]; From 1a09404a2338163f181d170c7abdc2242b6c6f03 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 20 Sep 2007 11:13:40 -0700 Subject: [PATCH 1463/2804] [B43]: Fix sparse warnings. The remaining warning in phy.c will be fixed later. Signed-off-by: Michael Buesch Signed-off-by: David S. Miller --- drivers/net/wireless/b43/debugfs.c | 31 ++++++++++++++++++++---------- drivers/net/wireless/b43/leds.c | 8 ++++---- drivers/net/wireless/b43/leds.h | 8 ++++---- drivers/net/wireless/b43/main.c | 5 ++--- drivers/net/wireless/b43/pcmcia.c | 3 +++ drivers/net/wireless/b43/pio.c | 18 +++++++++-------- drivers/net/wireless/b43/pio.h | 3 +-- drivers/net/wireless/b43/xmit.c | 8 +++++--- 8 files changed, 50 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index f82e3ef9bd73..3aafde9f08a8 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -39,7 +39,7 @@ /* The root directory. */ -struct dentry *rootdir; +static struct dentry *rootdir; struct b43_debugfs_fops { ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize); @@ -76,7 +76,8 @@ struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev, /* wl->irq_lock is locked */ -ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t tsf_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; u64 tsf; @@ -90,7 +91,8 @@ ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) } /* wl->irq_lock is locked */ -int tsf_write_file(struct b43_wldev *dev, const char *buf, size_t count) +static int tsf_write_file(struct b43_wldev *dev, + const char *buf, size_t count) { u64 tsf; @@ -102,7 +104,8 @@ int tsf_write_file(struct b43_wldev *dev, const char *buf, size_t count) } /* wl->irq_lock is locked */ -ssize_t ucode_regs_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t ucode_regs_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; int i; @@ -116,7 +119,8 @@ ssize_t ucode_regs_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) } /* wl->irq_lock is locked */ -ssize_t shm_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t shm_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; int i; @@ -135,7 +139,8 @@ ssize_t shm_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) return count; } -ssize_t txstat_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t txstat_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; ssize_t count = 0; @@ -182,7 +187,8 @@ out_unlock: return count; } -ssize_t txpower_g_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t txpower_g_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; @@ -214,7 +220,8 @@ out: return count; } -int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count) +static int txpower_g_write_file(struct b43_wldev *dev, + const char *buf, size_t count) { unsigned long flags; unsigned long phy_flags; @@ -262,7 +269,8 @@ out_unlock: } /* wl->irq_lock is locked */ -int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) +static int restart_write_file(struct b43_wldev *dev, + const char *buf, size_t count) { int err = 0; @@ -294,7 +302,8 @@ static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, return count; } -ssize_t loctls_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t loctls_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; struct b43_txpower_lo_control *lo; @@ -383,6 +392,8 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, err = -ENOMEM; goto out_unlock; } + /* Sparse warns about the following memset, because it has a big + * size value. That warning is bogus, so I will ignore it. --mb */ memset(buf, 0, bufsize); if (dfops->take_irqlock) { spin_lock_irq(&dev->wl->irq_lock); diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 535f960412d7..85d965de5791 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -32,14 +32,13 @@ static void b43_led_changestate(struct b43_led *led) { struct b43_wldev *dev = led->dev; - const int index = b43_led_index(led); - const u16 mask = (1 << index); + const int index = led->index; u16 ledctl; B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); B43_WARN_ON(!led->blink_interval); ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); + ledctl ^= (1 << index); b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); } @@ -70,7 +69,7 @@ static void b43_led_blink_start(struct b43_led *led, unsigned long interval) static void b43_led_blink_stop(struct b43_led *led, int sync) { struct b43_wldev *dev = led->dev; - const int index = b43_led_index(led); + const int index = led->index; u16 ledctl; if (!led->blink_interval) @@ -139,6 +138,7 @@ int b43_leds_init(struct b43_wldev *dev) for (i = 0; i < B43_NR_LEDS; i++) { led = &(dev->leds[i]); + led->index = i; led->dev = dev; setup_timer(&led->blink_timer, b43_led_blink, (unsigned long)led); diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h index 36b46cfda220..d94851d291c0 100644 --- a/drivers/net/wireless/b43/leds.h +++ b/drivers/net/wireless/b43/leds.h @@ -5,14 +5,14 @@ #include struct b43_led { - u8 behaviour:7; - u8 activelow:1; - + u8 behaviour; + bool activelow; + /* Index in the "leds" array in b43_wldev */ + u8 index; struct b43_wldev *dev; struct timer_list blink_timer; unsigned long blink_interval; }; -#define b43_led_index(led) ((int)((led) - (led)->dev->leds)) /* Delay between state changes when blinking in jiffies */ #define B43_LEDBLINK_SLOW (HZ / 1) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index fd4ef27fcf25..66c89df51fb8 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1062,7 +1062,7 @@ static void handle_irq_noise(struct b43_wldev *dev) B43_WARN_ON(!dev->noisecalc.calculation_running); if (dev->noisecalc.channel_at_start != phy->channel) goto drop_calculation; - *((u32 *) noise) = cpu_to_le32(b43_jssi_read(dev)); + *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev)); if (noise[0] == 0x7F || noise[1] == 0x7F || noise[2] == 0x7F || noise[3] == 0x7F) goto generate_new; @@ -1598,8 +1598,7 @@ static int do_request_fw(struct b43_wldev *dev, const char *name, const struct firmware **fw) { - const size_t plen = sizeof(modparam_fwpostfix) + 32; - char path[plen]; + char path[sizeof(modparam_fwpostfix) + 32]; struct b43_fw_header *hdr; u32 size; int err; diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 3e75a8a12c96..b242a9a90dd2 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -21,6 +21,8 @@ */ +#include "pcmcia.h" + #include #include @@ -30,6 +32,7 @@ #include #include + static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = { PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), PCMCIA_DEVICE_NULL, diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 4ac91fdd356e..67752a28eb9c 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -60,7 +60,7 @@ static u16 tx_get_next_word(const u8 * txhdr, source = packet; i -= txhdr_size; } - ret = le16_to_cpu(*((u16 *) (source + i))); + ret = le16_to_cpu(*((__le16 *)(source + i))); *pos += 2; return ret; @@ -104,7 +104,7 @@ static u16 generate_cookie(struct b43_pioqueue *queue, struct b43_pio_txpacket *packet) { u16 cookie = 0x0000; - int packetindex; + u16 packetindex; /* We use the upper 4 bits for the PIO * controller ID and the lower 12 bits @@ -125,7 +125,7 @@ static u16 generate_cookie(struct b43_pioqueue *queue, default: B43_WARN_ON(1); } - packetindex = pio_txpacket_getindex(packet); + packetindex = packet->index; B43_WARN_ON(packetindex & ~0x0FFF); cookie |= (u16) packetindex; @@ -286,6 +286,7 @@ static void setup_txqueues(struct b43_pioqueue *queue) packet->queue = queue; INIT_LIST_HEAD(&packet->list); + packet->index = i; list_add(&packet->list, &queue->txfree); } @@ -518,9 +519,10 @@ static void pio_rx_error(struct b43_pioqueue *queue, void b43_pio_rx(struct b43_pioqueue *queue) { - u16 preamble[21] = { 0 }; + __le16 preamble[21] = { 0 }; struct b43_rxhdr_fw4 *rxhdr; - u16 tmp, len, macstat; + u16 tmp, len; + u32 macstat; int i, preamble_readwords; struct sk_buff *skb; @@ -537,7 +539,7 @@ void b43_pio_rx(struct b43_pioqueue *queue) } b43dbg(queue->dev->wl, "PIO RX timed out\n"); return; - data_ready: +data_ready: len = b43_pio_read(queue, B43_PIO_RXDATA); if (unlikely(len > 0x700)) { @@ -558,7 +560,7 @@ void b43_pio_rx(struct b43_pioqueue *queue) preamble[i + 1] = cpu_to_le16(tmp); } rxhdr = (struct b43_rxhdr_fw4 *)preamble; - macstat = le16_to_cpu(rxhdr->mac_status); + macstat = le32_to_cpu(rxhdr->mac_status); if (macstat & B43_RX_MAC_FCSERR) { pio_rx_error(queue, (queue->mmio_base == B43_MMIO_PIO1_BASE), @@ -583,7 +585,7 @@ void b43_pio_rx(struct b43_pioqueue *queue) skb_put(skb, len); for (i = 0; i < len - 1; i += 2) { tmp = b43_pio_read(queue, B43_PIO_RXDATA); - *((u16 *) (skb->data + i)) = cpu_to_le16(tmp); + *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); } if (len % 2) { tmp = b43_pio_read(queue, B43_PIO_RXDATA); diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 46d6d2ea9b5f..34a44c1b6314 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -39,10 +39,9 @@ struct b43_pio_txpacket { struct sk_buff *skb; struct ieee80211_tx_status txstat; struct list_head list; + u16 index; /* Index in the tx_packets_cache */ }; -#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) - struct b43_pioqueue { struct b43_wldev *dev; u16 mmio_base; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index e6174b6f11fb..0bd6f8a348a8 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -121,10 +121,12 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, __u8 *raw = plcp->raw; if (b43_is_ofdm_rate(bitrate)) { - *data = b43_plcp_get_ratecode_ofdm(bitrate); + u32 d; + + d = b43_plcp_get_ratecode_ofdm(bitrate); B43_WARN_ON(octets & 0xF000); - *data |= (octets << 5); - *data = cpu_to_le32(*data); + d |= (octets << 5); + *data = cpu_to_le32(d); } else { u32 plen; From 0dde7b5404a3d52dcd9ce66d46197f6c3ca97dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 20 Sep 2007 11:28:05 -0700 Subject: [PATCH 1464/2804] [TCP]: Maintain highest_sack accurately to the highest skb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In general, it should not be necessary to call tcp_fragment for already SACKed skbs, but it's better to be safe than sorry. And indeed, it can be called from sacktag when a DSACK arrives or some ACK (with SACK) reordering occurs (sacktag could be made to avoid the call in the latter case though I'm not sure if it's worth of the trouble and added complexity to cover such marginal case). The collapse case has return for SACKED_ACKED case earlier, so just WARN_ON if internal inconsistency is detected for some reason. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index d65d17bb2a09..9df5b2a4da6e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -692,6 +692,9 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; + if (tp->sacked_out && (TCP_SKB_CB(skb)->seq == tp->highest_sack)) + tp->highest_sack = TCP_SKB_CB(buff)->seq; + /* PSH and FIN should only be set in the second packet. */ flags = TCP_SKB_CB(skb)->flags; TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); @@ -1723,6 +1726,10 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m /* Update sequence range on original skb. */ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq; + if (WARN_ON(tp->sacked_out && + (TCP_SKB_CB(next_skb)->seq == tp->highest_sack))) + return; + /* Merge over control information. */ flags |= TCP_SKB_CB(next_skb)->flags; /* This moves PSH/FIN etc. over */ TCP_SKB_CB(skb)->flags = flags; From 91fed7a15c9222af29a653ecb0ee72cff178fdd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 9 Oct 2007 01:24:15 -0700 Subject: [PATCH 1465/2804] [TCP]: Make fackets_out accurate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Substraction for fackets_out is unconditional when snd_una advances, thus there's no need to do it inside the loop. Just make sure correct bounds are honored. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 10 +++------- net/ipv4/tcp_output.c | 44 +++++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f9e4d7ad68b7..46aedd6ca020 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2299,8 +2299,8 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) * 1. Reno does not count dupacks (sacked_out) automatically. */ if (!tp->packets_out) tp->sacked_out = 0; - /* 2. SACK counts snd_fack in packets inaccurately. */ - if (tp->sacked_out == 0) + + if (WARN_ON(!tp->sacked_out && tp->fackets_out)) tp->fackets_out = 0; /* Now state machine starts. @@ -2568,10 +2568,6 @@ static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb, } else if (*seq_rtt < 0) *seq_rtt = now - scb->when; - if (tp->fackets_out) { - __u32 dval = min(tp->fackets_out, packets_acked); - tp->fackets_out -= dval; - } /* hint's skb might be NULL but we don't need to care */ tp->fastpath_cnt_hint -= min_t(u32, packets_acked, tp->fastpath_cnt_hint); @@ -2657,7 +2653,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) seq_rtt = now - scb->when; last_ackt = skb->tstamp; } - tcp_dec_pcount_approx(&tp->fackets_out, skb); tp->packets_out -= tcp_skb_pcount(skb); tcp_unlink_write_queue(skb, sk); sk_stream_free_skb(sk, skb); @@ -2672,6 +2667,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) tcp_ack_update_rtt(sk, acked, seq_rtt); tcp_rearm_rto(sk); + tp->fackets_out -= min(pkts_acked, tp->fackets_out); if (tcp_is_reno(tp)) tcp_remove_reno_sacks(sk, pkts_acked); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 9df5b2a4da6e..cbe8bf6dab5f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -652,6 +652,26 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned } } +/* When a modification to fackets out becomes necessary, we need to check + * skb is counted to fackets_out or not. Another important thing is to + * tweak SACK fastpath hint too as it would overwrite all changes unless + * hint is also changed. + */ +static void tcp_adjust_fackets_out(struct tcp_sock *tp, struct sk_buff *skb, + int decr) +{ + if (!tp->sacked_out) + return; + + if (!before(tp->highest_sack, TCP_SKB_CB(skb)->seq)) + tp->fackets_out -= decr; + + /* cnt_hint is "off-by-one" compared with fackets_out (see sacktag) */ + if (tp->fastpath_skb_hint != NULL && + after(TCP_SKB_CB(tp->fastpath_skb_hint)->seq, TCP_SKB_CB(skb)->seq)) + tp->fastpath_cnt_hint -= decr; +} + /* Function to create two new TCP segments. Shrinks the given segment * to the specified size and appends a new segment with the rest of the * packet to the list. This won't be called frequently, I hope. @@ -746,21 +766,12 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) tp->lost_out -= diff; - if (diff > 0) { - /* Adjust Reno SACK estimate. */ - if (tcp_is_reno(tp)) { - tcp_dec_pcount_approx_int(&tp->sacked_out, diff); - tcp_verify_left_out(tp); - } - - tcp_dec_pcount_approx_int(&tp->fackets_out, diff); - /* SACK fastpath might overwrite it unless dealt with */ - if (tp->fastpath_skb_hint != NULL && - after(TCP_SKB_CB(tp->fastpath_skb_hint)->seq, - TCP_SKB_CB(skb)->seq)) { - tcp_dec_pcount_approx_int(&tp->fastpath_cnt_hint, diff); - } + /* Adjust Reno SACK estimate. */ + if (tcp_is_reno(tp) && diff > 0) { + tcp_dec_pcount_approx_int(&tp->sacked_out, diff); + tcp_verify_left_out(tp); } + tcp_adjust_fackets_out(tp, skb, diff); } /* Link BUFF into the send queue. */ @@ -1746,10 +1757,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m if (tcp_is_reno(tp) && tp->sacked_out) tcp_dec_pcount_approx(&tp->sacked_out, next_skb); - /* Not quite right: it can be > snd.fack, but - * it is better to underestimate fackets. - */ - tcp_dec_pcount_approx(&tp->fackets_out, next_skb); + tcp_adjust_fackets_out(tp, skb, tcp_skb_pcount(next_skb)); tp->packets_out -= tcp_skb_pcount(next_skb); sk_stream_free_skb(sk, next_skb); } From 5af4ec236f7c98f3671fb26731457a172d85e0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 20 Sep 2007 11:30:48 -0700 Subject: [PATCH 1466/2804] [TCP]: clear_all_retrans_hints prefixed by tcp_ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In addition, fix its function comment spacing. Signed-off-by: Ilpo Jรคrvinen --- include/net/tcp.h | 4 ++-- net/ipv4/tcp_input.c | 10 +++++----- net/ipv4/tcp_output.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 4ba256a3f5e0..d78ad9bfcfa7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1066,8 +1066,8 @@ static inline void tcp_mib_init(void) TCP_ADD_STATS_USER(TCP_MIB_MAXCONN, -1); } -/*from STCP */ -static inline void clear_all_retrans_hints(struct tcp_sock *tp){ +/* from STCP */ +static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp) { tp->lost_skb_hint = NULL; tp->scoreboard_skb_hint = NULL; tp->retransmit_skb_hint = NULL; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 46aedd6ca020..31e7e339b567 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1667,7 +1667,7 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) tp->high_seq = tp->frto_highmark; TCP_ECN_queue_cwr(tp); - clear_all_retrans_hints(tp); + tcp_clear_all_retrans_hints(tp); } void tcp_clear_retrans(struct tcp_sock *tp) @@ -1738,7 +1738,7 @@ void tcp_enter_loss(struct sock *sk, int how) /* Abort FRTO algorithm if one is in progress */ tp->frto_counter = 0; - clear_all_retrans_hints(tp); + tcp_clear_all_retrans_hints(tp); } static int tcp_check_sack_reneging(struct sock *sk) @@ -2103,7 +2103,7 @@ static void tcp_undo_cwr(struct sock *sk, const int undo) /* There is something screwy going on with the retrans hints after an undo */ - clear_all_retrans_hints(tp); + tcp_clear_all_retrans_hints(tp); } static inline int tcp_may_undo(struct tcp_sock *tp) @@ -2196,7 +2196,7 @@ static int tcp_try_undo_loss(struct sock *sk) TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; } - clear_all_retrans_hints(tp); + tcp_clear_all_retrans_hints(tp); DBGUNDO(sk, "partial loss"); tp->lost_out = 0; @@ -2656,7 +2656,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) tp->packets_out -= tcp_skb_pcount(skb); tcp_unlink_write_queue(skb, sk); sk_stream_free_skb(sk, skb); - clear_all_retrans_hints(tp); + tcp_clear_all_retrans_hints(tp); } if (acked&FLAG_ACKED) { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index cbe8bf6dab5f..f46d24b8410f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -687,7 +687,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss BUG_ON(len > skb->len); - clear_all_retrans_hints(tp); + tcp_clear_all_retrans_hints(tp); nsize = skb_headlen(skb) - len; if (nsize < 0) nsize = 0; @@ -1719,7 +1719,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m tcp_skb_pcount(next_skb) != 1); /* changing transmit queue under us so clear hints */ - clear_all_retrans_hints(tp); + tcp_clear_all_retrans_hints(tp); /* Ok. We will be able to collapse the packet. */ tcp_unlink_write_queue(next_skb, sk); @@ -1792,7 +1792,7 @@ void tcp_simple_retransmit(struct sock *sk) } } - clear_all_retrans_hints(tp); + tcp_clear_all_retrans_hints(tp); if (!lost) return; From 13fcf850cc20373db4dd8a5c9f349583ab3817c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 9 Oct 2007 01:28:45 -0700 Subject: [PATCH 1467/2804] [TCP]: Move accounting from tso_acked to clean_rtx_queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The accounting code is pretty much the same, so it's a shame we do it in two places. I'm not too sure if added fully_acked check in MTU probing is really what we want perhaps the added end_seq could be used in the after() comparison. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 81 +++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 31e7e339b567..4238ed98acb9 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2525,14 +2525,12 @@ static void tcp_rearm_rto(struct sock *sk) } } -static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb, - __u32 now, __s32 *seq_rtt) +static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); struct tcp_skb_cb *scb = TCP_SKB_CB(skb); __u32 seq = tp->snd_una; __u32 packets_acked; - int acked = 0; /* If we get here, the whole TSO packet has not been * acked. @@ -2545,39 +2543,11 @@ static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb, packets_acked -= tcp_skb_pcount(skb); if (packets_acked) { - __u8 sacked = scb->sacked; - - acked |= FLAG_DATA_ACKED; - if (sacked) { - if (sacked & TCPCB_RETRANS) { - if (sacked & TCPCB_SACKED_RETRANS) - tp->retrans_out -= packets_acked; - acked |= FLAG_RETRANS_DATA_ACKED; - *seq_rtt = -1; - } else if (*seq_rtt < 0) - *seq_rtt = now - scb->when; - if (sacked & TCPCB_SACKED_ACKED) - tp->sacked_out -= packets_acked; - if (sacked & TCPCB_LOST) - tp->lost_out -= packets_acked; - if (sacked & TCPCB_URG) { - if (tp->urg_mode && - !before(seq, tp->snd_up)) - tp->urg_mode = 0; - } - } else if (*seq_rtt < 0) - *seq_rtt = now - scb->when; - - /* hint's skb might be NULL but we don't need to care */ - tp->fastpath_cnt_hint -= min_t(u32, packets_acked, - tp->fastpath_cnt_hint); - tp->packets_out -= packets_acked; - BUG_ON(tcp_skb_pcount(skb) == 0); BUG_ON(!before(scb->seq, scb->end_seq)); } - return acked; + return packets_acked; } /* Remove acknowledged frames from the retransmission queue. */ @@ -2587,6 +2557,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) const struct inet_connection_sock *icsk = inet_csk(sk); struct sk_buff *skb; __u32 now = tcp_time_stamp; + int fully_acked = 1; int acked = 0; int prior_packets = tp->packets_out; __s32 seq_rtt = -1; @@ -2595,6 +2566,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) { struct tcp_skb_cb *scb = TCP_SKB_CB(skb); + u32 end_seq; + u32 packets_acked; __u8 sacked = scb->sacked; /* If our packet is before the ack sequence we can @@ -2602,11 +2575,19 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) * the other end. */ if (after(scb->end_seq, tp->snd_una)) { - if (tcp_skb_pcount(skb) > 1 && - after(tp->snd_una, scb->seq)) - acked |= tcp_tso_acked(sk, skb, - now, &seq_rtt); - break; + if (tcp_skb_pcount(skb) == 1 || + !after(tp->snd_una, scb->seq)) + break; + + packets_acked = tcp_tso_acked(sk, skb); + if (!packets_acked) + break; + + fully_acked = 0; + end_seq = tp->snd_una; + } else { + packets_acked = tcp_skb_pcount(skb); + end_seq = scb->end_seq; } /* Initial outgoing SYN's get put onto the write_queue @@ -2624,7 +2605,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) } /* MTU probing checks */ - if (icsk->icsk_mtup.probe_size) { + if (fully_acked && icsk->icsk_mtup.probe_size) { if (!after(tp->mtu_probe.probe_seq_end, TCP_SKB_CB(skb)->end_seq)) { tcp_mtup_probe_success(sk, skb); } @@ -2633,27 +2614,32 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) if (sacked) { if (sacked & TCPCB_RETRANS) { if (sacked & TCPCB_SACKED_RETRANS) - tp->retrans_out -= tcp_skb_pcount(skb); + tp->retrans_out -= packets_acked; acked |= FLAG_RETRANS_DATA_ACKED; seq_rtt = -1; } else if (seq_rtt < 0) { seq_rtt = now - scb->when; - last_ackt = skb->tstamp; + if (fully_acked) + last_ackt = skb->tstamp; } if (sacked & TCPCB_SACKED_ACKED) - tp->sacked_out -= tcp_skb_pcount(skb); + tp->sacked_out -= packets_acked; if (sacked & TCPCB_LOST) - tp->lost_out -= tcp_skb_pcount(skb); + tp->lost_out -= packets_acked; if (sacked & TCPCB_URG) { - if (tp->urg_mode && - !before(scb->end_seq, tp->snd_up)) + if (tp->urg_mode && !before(end_seq, tp->snd_up)) tp->urg_mode = 0; } } else if (seq_rtt < 0) { seq_rtt = now - scb->when; - last_ackt = skb->tstamp; + if (fully_acked) + last_ackt = skb->tstamp; } - tp->packets_out -= tcp_skb_pcount(skb); + tp->packets_out -= packets_acked; + + if (!fully_acked) + break; + tcp_unlink_write_queue(skb, sk); sk_stream_free_skb(sk, skb); tcp_clear_all_retrans_hints(tp); @@ -2668,6 +2654,9 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) tcp_rearm_rto(sk); tp->fackets_out -= min(pkts_acked, tp->fackets_out); + /* hint's skb might be NULL but we don't need to care */ + tp->fastpath_cnt_hint -= min_t(u32, pkts_acked, + tp->fastpath_cnt_hint); if (tcp_is_reno(tp)) tcp_remove_reno_sacks(sk, pkts_acked); From 7c46a03e67d11d917d6c3dbf501b465b2ca97a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 20 Sep 2007 11:33:43 -0700 Subject: [PATCH 1468/2804] [TCP]: Cleanup tcp_tso_acked and tcp_clean_rtx_queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements following cleanups: - Comment re-placement (CodingStyle) - tcp_tso_acked() local (wrapper-like) variable removal (readability) - __-types removed (IMHO they make local variables jumpy looking and just was space) - acked -> flag (naming conventions elsewhere in TCP code) - linebreak adjustments (readability) - nested if()s combined (reduced indentation) - clarifying newlines added Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 66 ++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4238ed98acb9..8fe754be8076 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2525,55 +2525,49 @@ static void tcp_rearm_rto(struct sock *sk) } } +/* If we get here, the whole TSO packet has not been acked. */ static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); - struct tcp_skb_cb *scb = TCP_SKB_CB(skb); - __u32 seq = tp->snd_una; - __u32 packets_acked; + u32 packets_acked; - /* If we get here, the whole TSO packet has not been - * acked. - */ - BUG_ON(!after(scb->end_seq, seq)); + BUG_ON(!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)); packets_acked = tcp_skb_pcount(skb); - if (tcp_trim_head(sk, skb, seq - scb->seq)) + if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) return 0; packets_acked -= tcp_skb_pcount(skb); if (packets_acked) { BUG_ON(tcp_skb_pcount(skb) == 0); - BUG_ON(!before(scb->seq, scb->end_seq)); + BUG_ON(!before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)); } return packets_acked; } -/* Remove acknowledged frames from the retransmission queue. */ -static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) +/* Remove acknowledged frames from the retransmission queue. If our packet + * is before the ack sequence we can discard it as it's confirmed to have + * arrived at the other end. + */ +static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p) { struct tcp_sock *tp = tcp_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); struct sk_buff *skb; - __u32 now = tcp_time_stamp; + u32 now = tcp_time_stamp; int fully_acked = 1; - int acked = 0; + int flag = 0; int prior_packets = tp->packets_out; - __s32 seq_rtt = -1; + s32 seq_rtt = -1; ktime_t last_ackt = net_invalid_timestamp(); - while ((skb = tcp_write_queue_head(sk)) && - skb != tcp_send_head(sk)) { + while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) { struct tcp_skb_cb *scb = TCP_SKB_CB(skb); u32 end_seq; u32 packets_acked; - __u8 sacked = scb->sacked; + u8 sacked = scb->sacked; - /* If our packet is before the ack sequence we can - * discard it as it's confirmed to have arrived at - * the other end. - */ if (after(scb->end_seq, tp->snd_una)) { if (tcp_skb_pcount(skb) == 1 || !after(tp->snd_una, scb->seq)) @@ -2598,38 +2592,38 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) * quickly. This is severely frowned upon behavior. */ if (!(scb->flags & TCPCB_FLAG_SYN)) { - acked |= FLAG_DATA_ACKED; + flag |= FLAG_DATA_ACKED; } else { - acked |= FLAG_SYN_ACKED; + flag |= FLAG_SYN_ACKED; tp->retrans_stamp = 0; } /* MTU probing checks */ - if (fully_acked && icsk->icsk_mtup.probe_size) { - if (!after(tp->mtu_probe.probe_seq_end, TCP_SKB_CB(skb)->end_seq)) { - tcp_mtup_probe_success(sk, skb); - } + if (fully_acked && icsk->icsk_mtup.probe_size && + !after(tp->mtu_probe.probe_seq_end, scb->end_seq)) { + tcp_mtup_probe_success(sk, skb); } if (sacked) { if (sacked & TCPCB_RETRANS) { if (sacked & TCPCB_SACKED_RETRANS) tp->retrans_out -= packets_acked; - acked |= FLAG_RETRANS_DATA_ACKED; + flag |= FLAG_RETRANS_DATA_ACKED; seq_rtt = -1; } else if (seq_rtt < 0) { seq_rtt = now - scb->when; if (fully_acked) last_ackt = skb->tstamp; } + if (sacked & TCPCB_SACKED_ACKED) tp->sacked_out -= packets_acked; if (sacked & TCPCB_LOST) tp->lost_out -= packets_acked; - if (sacked & TCPCB_URG) { - if (tp->urg_mode && !before(end_seq, tp->snd_up)) - tp->urg_mode = 0; - } + + if ((sacked & TCPCB_URG) && tp->urg_mode && + !before(end_seq, tp->snd_up)) + tp->urg_mode = 0; } else if (seq_rtt < 0) { seq_rtt = now - scb->when; if (fully_acked) @@ -2645,12 +2639,12 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) tcp_clear_all_retrans_hints(tp); } - if (acked&FLAG_ACKED) { + if (flag & FLAG_ACKED) { u32 pkts_acked = prior_packets - tp->packets_out; const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; - tcp_ack_update_rtt(sk, acked, seq_rtt); + tcp_ack_update_rtt(sk, flag, seq_rtt); tcp_rearm_rto(sk); tp->fackets_out -= min(pkts_acked, tp->fackets_out); @@ -2664,7 +2658,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) s32 rtt_us = -1; /* Is the ACK triggering packet unambiguous? */ - if (!(acked & FLAG_RETRANS_DATA_ACKED)) { + if (!(flag & FLAG_RETRANS_DATA_ACKED)) { /* High resolution needed and available? */ if (ca_ops->flags & TCP_CONG_RTT_STAMP && !ktime_equal(last_ackt, @@ -2703,7 +2697,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) } #endif *seq_rtt_p = seq_rtt; - return acked; + return flag; } static void tcp_ack_probe(struct sock *sk) From 009a2e3e4ec395a290b9e4c7c9ff99296fd6b7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 20 Sep 2007 11:34:38 -0700 Subject: [PATCH 1469/2804] [TCP] FRTO: Improve interoperability with other undo_marker users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Basically this change enables it, previously other undo_marker users were left with nothing. Reverse undo_marker logic completely to get it set right in CA_Loss. On the other hand, when spurious RTO is detected, clear it. Clearing might be too heavy for some scenarios but seems safe enough starting point for now and shouldn't have much effect except in majority of cases (if in any). By adding a new FLAG_ we avoid looping through write_queue when RTO occurs. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 8fe754be8076..0feb10935be1 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -104,6 +104,7 @@ int sysctl_tcp_abc __read_mostly; #define FLAG_ONLY_ORIG_SACKED 0x200 /* SACKs only non-rexmit sent before RTO */ #define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ #define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained DSACK info */ +#define FLAG_NONHEAD_RETRANS_ACKED 0x1000 /* Non-head rexmitted data was ACKed */ #define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) #define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) @@ -1594,6 +1595,8 @@ void tcp_enter_frto(struct sock *sk) tp->undo_retrans = 0; skb = tcp_write_queue_head(sk); + if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS) + tp->undo_marker = 0; if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; tp->retrans_out -= tcp_skb_pcount(skb); @@ -1643,6 +1646,8 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) /* ...enter this if branch just for the first segment */ flag |= FLAG_DATA_ACKED; } else { + if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS) + tp->undo_marker = 0; TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); } @@ -1658,7 +1663,6 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments; tp->snd_cwnd_cnt = 0; tp->snd_cwnd_stamp = tcp_time_stamp; - tp->undo_marker = 0; tp->frto_counter = 0; tp->reordering = min_t(unsigned int, tp->reordering, @@ -2584,20 +2588,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p) end_seq = scb->end_seq; } - /* Initial outgoing SYN's get put onto the write_queue - * just like anything else we transmit. It is not - * true data, and if we misinform our callers that - * this ACK acks real data, we will erroneously exit - * connection startup slow start one packet too - * quickly. This is severely frowned upon behavior. - */ - if (!(scb->flags & TCPCB_FLAG_SYN)) { - flag |= FLAG_DATA_ACKED; - } else { - flag |= FLAG_SYN_ACKED; - tp->retrans_stamp = 0; - } - /* MTU probing checks */ if (fully_acked && icsk->icsk_mtup.probe_size && !after(tp->mtu_probe.probe_seq_end, scb->end_seq)) { @@ -2610,6 +2600,9 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p) tp->retrans_out -= packets_acked; flag |= FLAG_RETRANS_DATA_ACKED; seq_rtt = -1; + if ((flag & FLAG_DATA_ACKED) || + (packets_acked > 1)) + flag |= FLAG_NONHEAD_RETRANS_ACKED; } else if (seq_rtt < 0) { seq_rtt = now - scb->when; if (fully_acked) @@ -2631,6 +2624,20 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p) } tp->packets_out -= packets_acked; + /* Initial outgoing SYN's get put onto the write_queue + * just like anything else we transmit. It is not + * true data, and if we misinform our callers that + * this ACK acks real data, we will erroneously exit + * connection startup slow start one packet too + * quickly. This is severely frowned upon behavior. + */ + if (!(scb->flags & TCPCB_FLAG_SYN)) { + flag |= FLAG_DATA_ACKED; + } else { + flag |= FLAG_SYN_ACKED; + tp->retrans_stamp = 0; + } + if (!fully_acked) break; @@ -2852,6 +2859,10 @@ static int tcp_process_frto(struct sock *sk, int flag) if (flag&FLAG_DATA_ACKED) inet_csk(sk)->icsk_retransmits = 0; + if ((flag & FLAG_NONHEAD_RETRANS_ACKED) || + ((tp->frto_counter >= 2) && (flag & FLAG_RETRANS_DATA_ACKED))) + tp->undo_marker = 0; + if (!before(tp->snd_una, tp->frto_highmark)) { tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); return 1; @@ -2916,6 +2927,7 @@ static int tcp_process_frto(struct sock *sk, int flag) break; } tp->frto_counter = 0; + tp->undo_marker = 0; } return 0; } From cd99889c616afe1e8addcf28da505600c04f065a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 20 Sep 2007 11:35:26 -0700 Subject: [PATCH 1470/2804] [TCP] FRTO: Update sysctl documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the SACK enhanced FRTO was added, the code has been under test numerous times so remove "experimental" claim from the documentation. Also be a bit more verbose about the usage. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 32c2e9da5f3a..6ae2feff3087 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -180,13 +180,20 @@ tcp_fin_timeout - INTEGER to live longer. Cf. tcp_max_orphans. tcp_frto - INTEGER - Enables F-RTO, an enhanced recovery algorithm for TCP retransmission + Enables Forward RTO-Recovery (F-RTO) defined in RFC4138. + F-RTO is an enhanced recovery algorithm for TCP retransmission timeouts. It is particularly beneficial in wireless environments where packet loss is typically due to random radio interference - rather than intermediate router congestion. If set to 1, basic - version is enabled. 2 enables SACK enhanced F-RTO, which is - EXPERIMENTAL. The basic version can be used also when SACK is - enabled for a flow through tcp_sack sysctl. + rather than intermediate router congestion. FRTO is sender-side + only modification. Therefore it does not require any support from + the peer, but in a typical case, however, where wireless link is + the local access link and most of the data flows downlink, the + faraway servers should have FRTO enabled to take advantage of it. + If set to 1, basic version is enabled. 2 enables SACK enhanced + F-RTO if flow uses SACK. The basic version can be used also when + SACK is in use though scenario(s) with it exists where FRTO + interacts badly with the packet counting of the SACK enabled TCP + flow. tcp_frto_response - INTEGER When F-RTO has detected that a TCP retransmission timeout was From c96fd3d461fa495400df24be3b3b66f0e0b152f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 20 Sep 2007 11:36:37 -0700 Subject: [PATCH 1471/2804] [TCP]: Enable SACK enhanced FRTO (RFC4138) by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the description that follows comes from my mail to netdev (some editing done): Main obstacle to FRTO use is its deployment as it has to be on the sender side where as wireless link is often the receiver's access link. Take initiative on behalf of unlucky receivers and enable it by default in future Linux TCP senders. Also IETF seems to interested in advancing FRTO from experimental [1]. How does FRTO help? =================== FRTO detects spurious RTOs and avoids a number of unnecessary retransmissions and a couple of other problems that can arise due to incorrect guess made at RTO (i.e., that segments were lost when they actually got delayed which is likely to occur e.g. in wireless environments with link-layer retransmission). Though FRTO cannot prevent the first (potentially unnecessary) retransmission at RTO, I suspect that it won't cost that much even if you have to pay for each bit (won't be that high percentage out of all packets after all :-)). However, usually when you have a spurious RTO, not only the first segment unnecessarily retransmitted but the *whole window*. It goes like this: all cumulative ACKs got delayed due to in-order delivery, then TCP will actually send 1.5*original cwnd worth of data in the RTO's slow-start when the delayed ACKs arrive (basically the original cwnd worth of it unnecessarily). In case one is interested in minimizing unnecessary retransmissions e.g. due to cost, those rexmissions must never see daylight. Besides, in the worst case the generated burst overloads the bottleneck buffers which is likely to significantly delay the further progress of the flow. In case of ll rexmissions, ACK compression often occurs at the same time making the burst very "sharp edged" (in that case TCP often loses most of the segments above high_seq => very bad performance too). When FRTO is enabled, those unnecessary retransmissions are fully avoided except for the first segment and the cwnd behavior after detected spurious RTO is determined by the response (one can tune that by sysctl). Basic version (non-SACK enhanced one), FRTO can fail to detect spurious RTO as spurious and falls back to conservative behavior. ACK lossage is much less significant than reordering, usually the FRTO can detect spurious RTO if at least 2 cumulative ACKs from original window are preserved (excluding the ACK that advances to high_seq). With SACK-enhanced version, the detection is quite robust. FRTO should remove the need to set a high lower bound for the RTO estimator due to delay spikes that occur relatively common in some environments (esp. in wireless/cellular ones). [1] http://www1.ietf.org/mail-archive/web/tcpm/current/msg02862.html Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0feb10935be1..65b9f274a774 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -85,7 +85,7 @@ int sysctl_tcp_adv_win_scale __read_mostly = 2; int sysctl_tcp_stdurg __read_mostly; int sysctl_tcp_rfc1337 __read_mostly; int sysctl_tcp_max_orphans __read_mostly = NR_FILE; -int sysctl_tcp_frto __read_mostly; +int sysctl_tcp_frto __read_mostly = 2; int sysctl_tcp_frto_response __read_mostly; int sysctl_tcp_nometrics_save __read_mostly; From b76892051cf1c04d95872838e70146f65e3b9d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 20 Sep 2007 11:37:19 -0700 Subject: [PATCH 1472/2804] [TCP]: Avoid clearing sacktag hint in trivial situations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no reason to clear the sacktag skb hint when small part of the rexmit queue changes. Account changes (if any) instead when fragmenting/collapsing. RTO/FRTO do not touch SACKED_ACKED bits so no need to discard SACK tag hint at all. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/net/tcp.h | 6 +++++- net/ipv4/tcp_input.c | 14 ++++++++------ net/ipv4/tcp_output.c | 12 ++++++++---- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index d78ad9bfcfa7..456983d1fcec 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1067,11 +1067,15 @@ static inline void tcp_mib_init(void) } /* from STCP */ -static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp) { +static inline void tcp_clear_retrans_hints_partial(struct tcp_sock *tp) { tp->lost_skb_hint = NULL; tp->scoreboard_skb_hint = NULL; tp->retransmit_skb_hint = NULL; tp->forward_skb_hint = NULL; +} + +static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp) { + tcp_clear_retrans_hints_partial(tp); tp->fastpath_skb_hint = NULL; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 65b9f274a774..4c10d9cad20f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1671,7 +1671,7 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) tp->high_seq = tp->frto_highmark; TCP_ECN_queue_cwr(tp); - tcp_clear_all_retrans_hints(tp); + tcp_clear_retrans_hints_partial(tp); } void tcp_clear_retrans(struct tcp_sock *tp) @@ -1711,10 +1711,14 @@ void tcp_enter_loss(struct sock *sk, int how) tp->bytes_acked = 0; tcp_clear_retrans(tp); - /* Push undo marker, if it was plain RTO and nothing - * was retransmitted. */ - if (!how) + if (!how) { + /* Push undo marker, if it was plain RTO and nothing + * was retransmitted. */ tp->undo_marker = tp->snd_una; + tcp_clear_retrans_hints_partial(tp); + } else { + tcp_clear_all_retrans_hints(tp); + } tcp_for_write_queue(skb, sk) { if (skb == tcp_send_head(sk)) @@ -1741,8 +1745,6 @@ void tcp_enter_loss(struct sock *sk, int how) TCP_ECN_queue_cwr(tp); /* Abort FRTO algorithm if one is in progress */ tp->frto_counter = 0; - - tcp_clear_all_retrans_hints(tp); } static int tcp_check_sack_reneging(struct sock *sk) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f46d24b8410f..cbb83acd830a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -687,7 +687,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss BUG_ON(len > skb->len); - tcp_clear_all_retrans_hints(tp); + tcp_clear_retrans_hints_partial(tp); nsize = skb_headlen(skb) - len; if (nsize < 0) nsize = 0; @@ -1718,9 +1718,6 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1); - /* changing transmit queue under us so clear hints */ - tcp_clear_all_retrans_hints(tp); - /* Ok. We will be able to collapse the packet. */ tcp_unlink_write_queue(next_skb, sk); @@ -1759,6 +1756,13 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m tcp_adjust_fackets_out(tp, skb, tcp_skb_pcount(next_skb)); tp->packets_out -= tcp_skb_pcount(next_skb); + + /* changed transmit queue under us so clear hints */ + tcp_clear_retrans_hints_partial(tp); + /* manually tune sacktag skb hint */ + if (tp->fastpath_skb_hint == next_skb) + tp->fastpath_skb_hint = skb; + sk_stream_free_skb(sk, next_skb); } } From 0800f170263d19b882e519441156c5f6ed190fc1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 20 Sep 2007 11:40:37 -0700 Subject: [PATCH 1473/2804] [TCP]: Minor coding style fixup. Signed-off-by: David S. Miller --- include/net/tcp.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 456983d1fcec..92049e681258 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1067,14 +1067,16 @@ static inline void tcp_mib_init(void) } /* from STCP */ -static inline void tcp_clear_retrans_hints_partial(struct tcp_sock *tp) { +static inline void tcp_clear_retrans_hints_partial(struct tcp_sock *tp) +{ tp->lost_skb_hint = NULL; tp->scoreboard_skb_hint = NULL; tp->retransmit_skb_hint = NULL; tp->forward_skb_hint = NULL; } -static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp) { +static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp) +{ tcp_clear_retrans_hints_partial(tp); tp->fastpath_skb_hint = NULL; } From 556829657397b9b05baec6691ead4e22ee8d1567 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Sep 2007 13:09:35 -0400 Subject: [PATCH 1474/2804] [NL80211]: add netlink interface to cfg80211 Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/linux/nl80211.h | 97 +++++++- include/net/cfg80211.h | 11 +- include/net/iw_handler.h | 8 +- net/mac80211/ieee80211_cfg.c | 2 +- net/wireless/Kconfig | 17 +- net/wireless/Makefile | 1 + net/wireless/core.c | 148 ++++++++++++ net/wireless/core.h | 32 +++ net/wireless/nl80211.c | 431 +++++++++++++++++++++++++++++++++++ net/wireless/nl80211.h | 24 ++ 10 files changed, 762 insertions(+), 9 deletions(-) create mode 100644 net/wireless/nl80211.c create mode 100644 net/wireless/nl80211.h diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 9a30ba2ca75e..538ee1dd3d0a 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -6,8 +6,98 @@ * Copyright 2006, 2007 Johannes Berg */ +/** + * enum nl80211_commands - supported nl80211 commands + * + * @NL80211_CMD_UNSPEC: unspecified command to catch errors + * + * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request + * to get a list of all present wiphys. + * @NL80211_CMD_SET_WIPHY: set wiphy name, needs %NL80211_ATTR_WIPHY and + * %NL80211_ATTR_WIPHY_NAME. + * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request + * or rename notification. Has attributes %NL80211_ATTR_WIPHY and + * %NL80211_ATTR_WIPHY_NAME. + * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes + * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. + * + * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; + * either a dump request on a %NL80211_ATTR_WIPHY or a specific get + * on an %NL80211_ATTR_IFINDEX is supported. + * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. + * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response + * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, + * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also + * be sent from userspace to request creation of a new virtual interface, + * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and + * %NL80211_ATTR_IFNAME. + * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from + * userspace to request deletion of a virtual interface, then requires + * attribute %NL80211_ATTR_IFINDEX. + * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +enum nl80211_commands { +/* don't change the order or add anything inbetween, this is ABI! */ + NL80211_CMD_UNSPEC, + + NL80211_CMD_GET_WIPHY, /* can dump */ + NL80211_CMD_SET_WIPHY, + NL80211_CMD_NEW_WIPHY, + NL80211_CMD_DEL_WIPHY, + + NL80211_CMD_GET_INTERFACE, /* can dump */ + NL80211_CMD_SET_INTERFACE, + NL80211_CMD_NEW_INTERFACE, + NL80211_CMD_DEL_INTERFACE, + + /* add commands here */ + + /* used to define NL80211_CMD_MAX below */ + __NL80211_CMD_AFTER_LAST, + NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 +}; + + +/** + * enum nl80211_attrs - nl80211 netlink attributes + * + * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors + * + * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. + * /sys/class/ieee80211//index + * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) + * + * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on + * @NL80211_ATTR_IFNAME: network interface name + * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype + * + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use + */ +enum nl80211_attrs { +/* don't change the order or add anything inbetween, this is ABI! */ + NL80211_ATTR_UNSPEC, + + NL80211_ATTR_WIPHY, + NL80211_ATTR_WIPHY_NAME, + + NL80211_ATTR_IFINDEX, + NL80211_ATTR_IFNAME, + NL80211_ATTR_IFTYPE, + + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, + NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 +}; + /** * enum nl80211_iftype - (virtual) interface types + * * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides * @NL80211_IFTYPE_ADHOC: independent BSS member * @NL80211_IFTYPE_STATION: managed BSS member @@ -15,9 +105,10 @@ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points * @NL80211_IFTYPE_WDS: wireless distribution interface * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames + * @NL80211_IFTYPE_MAX: highest interface type number currently defined * @__NL80211_IFTYPE_AFTER_LAST: internal use * - * These values are used with the NL80211_ATTR_IFTYPE + * These values are used with the %NL80211_ATTR_IFTYPE * to set the type of an interface. * */ @@ -31,8 +122,8 @@ enum nl80211_iftype { NL80211_IFTYPE_MONITOR, /* keep last */ - __NL80211_IFTYPE_AFTER_LAST + __NL80211_IFTYPE_AFTER_LAST, + NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 }; -#define NL80211_IFTYPE_MAX (__NL80211_IFTYPE_AFTER_LAST - 1) #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7edaef6b29d6..d30960e1755c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3,15 +3,15 @@ #include #include +#include #include /* * 802.11 configuration in-kernel interface * - * Copyright 2006 Johannes Berg + * Copyright 2006, 2007 Johannes Berg */ - /* Radiotap header iteration * implemented in net/wireless/radiotap.c * docs in Documentation/networking/radiotap-headers.txt @@ -68,11 +68,16 @@ struct wiphy; * @add_virtual_intf: create a new virtual interface with the given name * * @del_virtual_intf: remove the virtual interface determined by ifindex. + * + * @change_virtual_intf: change type of virtual interface + * */ struct cfg80211_ops { int (*add_virtual_intf)(struct wiphy *wiphy, char *name, - unsigned int type); + enum nl80211_iftype type); int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); + int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type); }; #endif /* __NET_CFG80211_H */ diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index f23d07ca7c59..369d50e08b99 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -431,7 +431,13 @@ struct iw_public_data { * Those may be called only within the kernel. */ -/* functions that may be called by driver modules */ +/* First : function strictly used inside the kernel */ + +/* Handle /proc/net/wireless, called in net/code/dev.c */ +extern int dev_get_wireless_info(char * buffer, char **start, off_t offset, + int length); + +/* Second : functions that may be called by driver modules */ /* Send a single event to user space */ extern void wireless_send_event(struct net_device * dev, diff --git a/net/mac80211/ieee80211_cfg.c b/net/mac80211/ieee80211_cfg.c index b1c13bc9c3ca..d6fc55cc8ad4 100644 --- a/net/mac80211/ieee80211_cfg.c +++ b/net/mac80211/ieee80211_cfg.c @@ -14,7 +14,7 @@ #include "ieee80211_cfg.h" static int ieee80211_add_iface(struct wiphy *wiphy, char *name, - unsigned int type) + enum nl80211_iftype type) { struct ieee80211_local *local = wiphy_priv(wiphy); int itype; diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index a228d56a91b8..6291f13bba09 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -1,6 +1,19 @@ config CFG80211 tristate "Improved wireless configuration API" +config NL80211 + bool "nl80211 new netlink interface support" + depends CFG80211 + default y + ---help--- + This option turns on the new netlink interface + (nl80211) support in cfg80211. + + If =n, drivers using mac80211 will be configured via + wireless extension support provided by that subsystem. + + If unsure, say Y. + config WIRELESS_EXT bool "Wireless extensions" default n @@ -10,7 +23,9 @@ config WIRELESS_EXT Wireless extensions will be replaced by cfg80211 and will be required only by legacy drivers that implement - wireless extension handlers. + 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. diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 092116e390b6..65710a42e5a7 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_WIRELESS_EXT) += wext.o obj-$(CONFIG_CFG80211) += cfg80211.o cfg80211-y += core.o sysfs.o radiotap.o +cfg80211-$(CONFIG_NL80211) += nl80211.o diff --git a/net/wireless/core.c b/net/wireless/core.c index 9771451eae21..febc33bc9c09 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -16,6 +16,7 @@ #include #include #include +#include "nl80211.h" #include "core.h" #include "sysfs.h" @@ -36,6 +37,146 @@ static int wiphy_counter; /* for debugfs */ static struct dentry *ieee80211_debugfs_dir; +/* requires cfg80211_drv_mutex to be held! */ +static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy) +{ + struct cfg80211_registered_device *result = NULL, *drv; + + list_for_each_entry(drv, &cfg80211_drv_list, list) { + if (drv->idx == wiphy) { + result = drv; + break; + } + } + + return result; +} + +/* requires cfg80211_drv_mutex to be held! */ +static struct cfg80211_registered_device * +__cfg80211_drv_from_info(struct genl_info *info) +{ + int ifindex; + struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL; + struct net_device *dev; + int err = -EINVAL; + + if (info->attrs[NL80211_ATTR_WIPHY]) { + bywiphy = cfg80211_drv_by_wiphy( + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); + err = -ENODEV; + } + + if (info->attrs[NL80211_ATTR_IFINDEX]) { + ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); + dev = dev_get_by_index(&init_net, ifindex); + if (dev) { + if (dev->ieee80211_ptr) + byifidx = + wiphy_to_dev(dev->ieee80211_ptr->wiphy); + dev_put(dev); + } + err = -ENODEV; + } + + if (bywiphy && byifidx) { + if (bywiphy != byifidx) + return ERR_PTR(-EINVAL); + else + return bywiphy; /* == byifidx */ + } + if (bywiphy) + return bywiphy; + + if (byifidx) + return byifidx; + + return ERR_PTR(err); +} + +struct cfg80211_registered_device * +cfg80211_get_dev_from_info(struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + + mutex_lock(&cfg80211_drv_mutex); + drv = __cfg80211_drv_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); + + mutex_unlock(&cfg80211_drv_mutex); + + return drv; +} + +struct cfg80211_registered_device * +cfg80211_get_dev_from_ifindex(int ifindex) +{ + struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV); + struct net_device *dev; + + mutex_lock(&cfg80211_drv_mutex); + dev = dev_get_by_index(&init_net, ifindex); + if (!dev) + goto out; + if (dev->ieee80211_ptr) { + drv = wiphy_to_dev(dev->ieee80211_ptr->wiphy); + mutex_lock(&drv->mtx); + } else + drv = ERR_PTR(-ENODEV); + dev_put(dev); + out: + mutex_unlock(&cfg80211_drv_mutex); + return drv; +} + +void cfg80211_put_dev(struct cfg80211_registered_device *drv) +{ + BUG_ON(IS_ERR(drv)); + mutex_unlock(&drv->mtx); +} + +int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, + char *newname) +{ + int idx, taken = -1, result, digits; + + /* prohibit calling the thing phy%d when %d is not its number */ + sscanf(newname, PHY_NAME "%d%n", &idx, &taken); + if (taken == strlen(newname) && idx != rdev->idx) { + /* count number of places needed to print idx */ + digits = 1; + while (idx /= 10) + digits++; + /* + * deny the name if it is phy where is printed + * without leading zeroes. taken == strlen(newname) here + */ + if (taken == strlen(PHY_NAME) + digits) + return -EINVAL; + } + + /* this will check for collisions */ + result = device_rename(&rdev->wiphy.dev, newname); + if (result) + return result; + + if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent, + rdev->wiphy.debugfsdir, + rdev->wiphy.debugfsdir->d_parent, + newname)) + printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", + newname); + + nl80211_notify_dev_rename(rdev); + + return 0; +} + /* exported functions */ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) @@ -204,10 +345,16 @@ static int cfg80211_init(void) if (err) goto out_fail_notifier; + err = nl80211_init(); + if (err) + goto out_fail_nl80211; + ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL); return 0; +out_fail_nl80211: + unregister_netdevice_notifier(&cfg80211_netdev_notifier); out_fail_notifier: wiphy_sysfs_exit(); out_fail_sysfs: @@ -218,6 +365,7 @@ subsys_initcall(cfg80211_init); static void cfg80211_exit(void) { debugfs_remove(ieee80211_debugfs_dir); + nl80211_exit(); unregister_netdevice_notifier(&cfg80211_netdev_notifier); wiphy_sysfs_exit(); } diff --git a/net/wireless/core.h b/net/wireless/core.h index 158db1edb92a..eb0f846b40df 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -43,7 +43,39 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) extern struct mutex cfg80211_drv_mutex; extern struct list_head cfg80211_drv_list; +/* + * This function returns a pointer to the driver + * that the genl_info item that is passed refers to. + * If successful, it returns non-NULL and also locks + * the driver's mutex! + * + * This means that you need to call cfg80211_put_dev() + * before being allowed to acquire &cfg80211_drv_mutex! + * + * 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 don't want to keep cfg80211_drv_mutex locked + * for all the time in order to allow requests on + * other interfaces to go through at the same time. + * + * The result of this can be a PTR_ERR and hence must + * be checked with IS_ERR() for errors. + */ +extern struct cfg80211_registered_device * +cfg80211_get_dev_from_info(struct genl_info *info); + +/* identical to cfg80211_get_dev_from_info but only operate on ifindex */ +extern struct cfg80211_registered_device * +cfg80211_get_dev_from_ifindex(int ifindex); + +extern void cfg80211_put_dev(struct cfg80211_registered_device *drv); + /* free object */ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); +extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv, + char *newname); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c new file mode 100644 index 000000000000..48b0d453e4e1 --- /dev/null +++ b/net/wireless/nl80211.c @@ -0,0 +1,431 @@ +/* + * This is the new netlink-based wireless configuration interface. + * + * Copyright 2006, 2007 Johannes Berg + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "nl80211.h" + +/* the netlink family */ +static struct genl_family nl80211_fam = { + .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ + .name = "nl80211", /* have users key off the name instead */ + .hdrsize = 0, /* no private header */ + .version = 1, /* no particular meaning now */ + .maxattr = NL80211_ATTR_MAX, +}; + +/* internal helper: get drv and dev */ +static int get_drv_dev_by_info_ifindex(struct genl_info *info, + struct cfg80211_registered_device **drv, + struct net_device **dev) +{ + int ifindex; + + if (!info->attrs[NL80211_ATTR_IFINDEX]) + return -EINVAL; + + ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); + *dev = dev_get_by_index(&init_net, ifindex); + if (!*dev) + return -ENODEV; + + *drv = cfg80211_get_dev_from_ifindex(ifindex); + if (IS_ERR(*drv)) { + dev_put(*dev); + return PTR_ERR(*drv); + } + + return 0; +} + +/* policy for the attributes */ +static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { + [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, + .len = BUS_ID_SIZE-1 }, + + [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, + [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, +}; + +/* message building helper */ +static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, + int flags, u8 cmd) +{ + /* since there is no private header just add the generic one */ + return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); +} + +/* netlink command implementations */ + +static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, + struct cfg80211_registered_device *dev) +{ + void *hdr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); + NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + return genlmsg_end(msg, hdr); + + nla_put_failure: + return genlmsg_cancel(msg, hdr); +} + +static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) +{ + int idx = 0; + int start = cb->args[0]; + struct cfg80211_registered_device *dev; + + mutex_lock(&cfg80211_drv_mutex); + list_for_each_entry(dev, &cfg80211_drv_list, list) { + if (++idx < start) + continue; + if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + dev) < 0) + break; + } + mutex_unlock(&cfg80211_drv_mutex); + + cb->args[0] = idx; + + return skb->len; +} + +static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + struct cfg80211_registered_device *dev; + + dev = cfg80211_get_dev_from_info(info); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto out_err; + + if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) + goto out_free; + + cfg80211_put_dev(dev); + + return genlmsg_unicast(msg, info->snd_pid); + + out_free: + nlmsg_free(msg); + out_err: + cfg80211_put_dev(dev); + return -ENOBUFS; +} + +static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + int result; + + if (!info->attrs[NL80211_ATTR_WIPHY_NAME]) + return -EINVAL; + + rdev = cfg80211_get_dev_from_info(info); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); + + cfg80211_put_dev(rdev); + return result; +} + + +static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, + struct net_device *dev) +{ + void *hdr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); + /* TODO: interface type */ + return genlmsg_end(msg, hdr); + + nla_put_failure: + return genlmsg_cancel(msg, hdr); +} + +static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) +{ + int wp_idx = 0; + int if_idx = 0; + int wp_start = cb->args[0]; + int if_start = cb->args[1]; + struct cfg80211_registered_device *dev; + struct wireless_dev *wdev; + + mutex_lock(&cfg80211_drv_mutex); + list_for_each_entry(dev, &cfg80211_drv_list, list) { + if (++wp_idx < wp_start) + continue; + if_idx = 0; + + mutex_lock(&dev->devlist_mtx); + list_for_each_entry(wdev, &dev->netdev_list, list) { + if (++if_idx < if_start) + continue; + if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + wdev->netdev) < 0) + break; + } + mutex_unlock(&dev->devlist_mtx); + } + mutex_unlock(&cfg80211_drv_mutex); + + cb->args[0] = wp_idx; + cb->args[1] = if_idx; + + return skb->len; +} + +static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + struct cfg80211_registered_device *dev; + struct net_device *netdev; + int err; + + err = get_drv_dev_by_info_ifindex(info, &dev, &netdev); + if (err) + return err; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto out_err; + + if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0) + goto out_free; + + dev_put(netdev); + cfg80211_put_dev(dev); + + return genlmsg_unicast(msg, info->snd_pid); + + out_free: + nlmsg_free(msg); + out_err: + dev_put(netdev); + cfg80211_put_dev(dev); + return -ENOBUFS; +} + +static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err, ifindex; + enum nl80211_iftype type; + struct net_device *dev; + + if (info->attrs[NL80211_ATTR_IFTYPE]) { + type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); + if (type > NL80211_IFTYPE_MAX) + return -EINVAL; + } else + return -EINVAL; + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + ifindex = dev->ifindex; + dev_put(dev); + + if (!drv->ops->change_virtual_intf) { + err = -EOPNOTSUPP; + goto unlock; + } + + rtnl_lock(); + err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type); + rtnl_unlock(); + + unlock: + cfg80211_put_dev(drv); + return err; +} + +static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; + + if (!info->attrs[NL80211_ATTR_IFNAME]) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_IFTYPE]) { + type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); + if (type > NL80211_IFTYPE_MAX) + return -EINVAL; + } + + drv = cfg80211_get_dev_from_info(info); + if (IS_ERR(drv)) + return PTR_ERR(drv); + + if (!drv->ops->add_virtual_intf) { + err = -EOPNOTSUPP; + goto unlock; + } + + rtnl_lock(); + err = drv->ops->add_virtual_intf(&drv->wiphy, + nla_data(info->attrs[NL80211_ATTR_IFNAME]), type); + rtnl_unlock(); + + unlock: + cfg80211_put_dev(drv); + return err; +} + +static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int ifindex, err; + struct net_device *dev; + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + ifindex = dev->ifindex; + dev_put(dev); + + if (!drv->ops->del_virtual_intf) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + return err; +} + +static struct genl_ops nl80211_ops[] = { + { + .cmd = NL80211_CMD_GET_WIPHY, + .doit = nl80211_get_wiphy, + .dumpit = nl80211_dump_wiphy, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + }, + { + .cmd = NL80211_CMD_SET_WIPHY, + .doit = nl80211_set_wiphy, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_GET_INTERFACE, + .doit = nl80211_get_interface, + .dumpit = nl80211_dump_interface, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + }, + { + .cmd = NL80211_CMD_SET_INTERFACE, + .doit = nl80211_set_interface, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_NEW_INTERFACE, + .doit = nl80211_new_interface, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_DEL_INTERFACE, + .doit = nl80211_del_interface, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, +}; + +/* multicast groups */ +static struct genl_multicast_group nl80211_config_mcgrp = { + .name = "config", +}; + +/* notification functions */ + +void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); +} + +/* initialisation/exit functions */ + +int nl80211_init(void) +{ + int err, i; + + err = genl_register_family(&nl80211_fam); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) { + err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]); + if (err) + goto err_out; + } + + err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); + if (err) + goto err_out; + + return 0; + err_out: + genl_unregister_family(&nl80211_fam); + return err; +} + +void nl80211_exit(void) +{ + genl_unregister_family(&nl80211_fam); +} diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h new file mode 100644 index 000000000000..f3ea5c029aee --- /dev/null +++ b/net/wireless/nl80211.h @@ -0,0 +1,24 @@ +#ifndef __NET_WIRELESS_NL80211_H +#define __NET_WIRELESS_NL80211_H + +#include "core.h" + +#ifdef CONFIG_NL80211 +extern int nl80211_init(void); +extern void nl80211_exit(void); +extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); +#else +static inline int nl80211_init(void) +{ + return 0; +} +static inline void nl80211_exit(void) +{ +} +static inline void nl80211_notify_dev_rename( + struct cfg80211_registered_device *rdev) +{ +} +#endif /* CONFIG_NL80211 */ + +#endif /* __NET_WIRELESS_NL80211_H */ From de3cb747ffac5f2a4a6bb156e7e2fd5229e688e5 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2007 19:16:28 -0700 Subject: [PATCH 1475/2804] [NET]: Dynamically allocate the loopback device, part 1. This patch replaces all occurences to the static variable loopback_dev to a pointer loopback_dev. That provides the mindless, trivial, uninteressting change part for the dynamic allocation for the loopback. Signed-off-by: Eric W. Biederman Signed-off-by: Daniel Lezcano Acked-By: Kirill Korotaev Acked-by: Benjamin Thery Signed-off-by: David S. Miller --- drivers/net/loopback.c | 6 ++++-- include/linux/netdevice.h | 2 +- net/core/dst.c | 8 ++++---- net/decnet/dn_dev.c | 4 ++-- net/decnet/dn_route.c | 14 +++++++------- net/ipv4/devinet.c | 6 +++--- net/ipv4/ipconfig.c | 6 +++--- net/ipv4/ipvs/ip_vs_core.c | 2 +- net/ipv4/route.c | 18 +++++++++--------- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 15 +++++++++------ net/ipv6/ip6_input.c | 2 +- net/ipv6/netfilter/ip6t_REJECT.c | 2 +- net/ipv6/route.c | 15 ++++++--------- net/ipv6/xfrm6_policy.c | 2 +- net/xfrm/xfrm_policy.c | 4 ++-- 16 files changed, 55 insertions(+), 53 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 0e2252fd71ab..588092e13186 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -202,7 +202,7 @@ static const struct ethtool_ops loopback_ethtool_ops = { * The loopback device is special. There is only one instance and * it is statically allocated. Don't do this for other devices. */ -struct net_device loopback_dev = { +struct net_device __loopback_dev = { .name = "lo", .get_stats = &get_stats, .mtu = (16 * 1024) + 20 + 20 + 12, @@ -227,10 +227,12 @@ struct net_device loopback_dev = { .nd_net = &init_net, }; +struct net_device *loopback_dev = &__loopback_dev; + /* Setup and register the loopback device. */ static int __init loopback_init(void) { - int err = register_netdev(&loopback_dev); + int err = register_netdev(loopback_dev); if (err) panic("loopback: Failed to register netdevice: %d\n", err); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cf89ce677e41..baa915f0d285 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -741,7 +741,7 @@ struct packet_type { #include #include -extern struct net_device loopback_dev; /* The loopback */ +extern struct net_device *loopback_dev; /* The loopback */ extern rwlock_t dev_base_lock; /* Device list lock */ diff --git a/net/core/dst.c b/net/core/dst.c index 38c741ac5d08..ad5ffa19d809 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -278,13 +278,13 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev, if (!unregister) { dst->input = dst->output = dst_discard; } else { - dst->dev = &loopback_dev; - dev_hold(&loopback_dev); + dst->dev = loopback_dev; + dev_hold(dst->dev); dev_put(dev); if (dst->neighbour && dst->neighbour->dev == dev) { - dst->neighbour->dev = &loopback_dev; + dst->neighbour->dev = loopback_dev; dev_put(dev); - dev_hold(&loopback_dev); + dev_hold(dst->neighbour->dev); } } } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index fa24614b5a37..bcaf4c5aa68e 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -869,10 +869,10 @@ last_chance: rv = dn_dev_get_first(dev, addr); read_unlock(&dev_base_lock); dev_put(dev); - if (rv == 0 || dev == &loopback_dev) + if (rv == 0 || dev == loopback_dev) return rv; } - dev = &loopback_dev; + dev = loopback_dev; dev_hold(dev); goto last_chance; } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 70b1c3fa00f3..96fe0aa1638e 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -887,7 +887,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old .scope = RT_SCOPE_UNIVERSE, } }, .mark = oldflp->mark, - .iif = loopback_dev.ifindex, + .iif = loopback_dev->ifindex, .oif = oldflp->oif }; struct dn_route *rt = NULL; struct net_device *dev_out = NULL, *dev; @@ -904,7 +904,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old "dn_route_output_slow: dst=%04x src=%04x mark=%d" " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), dn_ntohs(oldflp->fld_src), - oldflp->mark, loopback_dev.ifindex, oldflp->oif); + oldflp->mark, loopback_dev->ifindex, oldflp->oif); /* If we have an output interface, verify its a DECnet device */ if (oldflp->oif) { @@ -957,7 +957,7 @@ source_ok: err = -EADDRNOTAVAIL; if (dev_out) dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); if (!fl.fld_dst) { fl.fld_dst = @@ -966,7 +966,7 @@ source_ok: if (!fl.fld_dst) goto out; } - fl.oif = loopback_dev.ifindex; + fl.oif = loopback_dev->ifindex; res.type = RTN_LOCAL; goto make_route; } @@ -1012,7 +1012,7 @@ source_ok: if (dev_out) dev_put(dev_out); if (dn_dev_islocal(neigh->dev, fl.fld_dst)) { - dev_out = &loopback_dev; + dev_out = loopback_dev; res.type = RTN_LOCAL; } else { dev_out = neigh->dev; @@ -1033,7 +1033,7 @@ source_ok: /* Possible improvement - check all devices for local addr */ if (dn_dev_islocal(dev_out, fl.fld_dst)) { dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); res.type = RTN_LOCAL; goto select_source; @@ -1069,7 +1069,7 @@ select_source: fl.fld_src = fl.fld_dst; if (dev_out) dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 721b89b60963..affea9b121fc 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -203,7 +203,7 @@ static void inetdev_destroy(struct in_device *in_dev) ASSERT_RTNL(); dev = in_dev->dev; - if (dev == &loopback_dev) + if (dev == loopback_dev) return; in_dev->dead = 1; @@ -1061,7 +1061,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, in_dev = inetdev_init(dev); if (!in_dev) return notifier_from_errno(-ENOMEM); - if (dev == &loopback_dev) { + if (dev == loopback_dev) { IN_DEV_CONF_SET(in_dev, NOXFRM, 1); IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); } @@ -1077,7 +1077,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, case NETDEV_UP: if (dev->mtu < 68) break; - if (dev == &loopback_dev) { + if (dev == loopback_dev) { struct in_ifaddr *ifa; if ((ifa = inet_alloc_ifa()) != NULL) { ifa->ifa_local = diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 4303851749f6..2d2e0cda0470 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -190,11 +190,11 @@ static int __init ic_open_devs(void) rtnl_lock(); /* bring loopback device up first */ - if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0) - printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev.name); + if (dev_change_flags(loopback_dev, loopback_dev->flags | IFF_UP) < 0) + printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev->name); for_each_netdev(&init_net, dev) { - if (dev == &loopback_dev) + if (dev == loopback_dev) continue; if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : (!(dev->flags & IFF_LOOPBACK) && diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index f005a2f929f4..74503267e5d4 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -961,7 +961,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff **pskb, * ... don't know why 1st test DOES NOT include 2nd (?) */ if (unlikely(skb->pkt_type != PACKET_HOST - || skb->dev == &loopback_dev || skb->sk)) { + || skb->dev == loopback_dev || skb->sk)) { IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n", skb->pkt_type, ip_hdr(skb)->protocol, diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 006d6058a806..ca2878dc6188 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1402,8 +1402,8 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, { struct rtable *rt = (struct rtable *) dst; struct in_device *idev = rt->idev; - if (dev != &loopback_dev && idev && idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(&loopback_dev); + if (dev != loopback_dev && idev && idev->dev == dev) { + struct in_device *loopback_idev = in_dev_get(loopback_dev); if (loopback_idev) { rt->idev = loopback_idev; in_dev_put(idev); @@ -1555,7 +1555,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = &loopback_dev; + rth->u.dst.dev = loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->fl.oif = 0; @@ -1812,7 +1812,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (res.type == RTN_LOCAL) { int result; result = fib_validate_source(saddr, daddr, tos, - loopback_dev.ifindex, + loopback_dev->ifindex, dev, &spec_dst, &itag); if (result < 0) goto martian_source; @@ -1879,7 +1879,7 @@ local_input: #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = &loopback_dev; + rth->u.dst.dev = loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->rt_gateway = daddr; @@ -2149,7 +2149,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) RT_SCOPE_UNIVERSE), } }, .mark = oldflp->mark, - .iif = loopback_dev.ifindex, + .iif = loopback_dev->ifindex, .oif = oldflp->oif }; struct fib_result res; unsigned flags = 0; @@ -2243,9 +2243,9 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK); if (dev_out) dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); - fl.oif = loopback_dev.ifindex; + fl.oif = loopback_dev->ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route; @@ -2290,7 +2290,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) fl.fl4_src = fl.fl4_dst; if (dev_out) dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 4ff8ed30024f..29ab3de8c47f 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -306,7 +306,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt.idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(&loopback_dev); + struct in_device *loopback_idev = in_dev_get(loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9c2e94f1c637..b43574f73375 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2410,7 +2410,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) ASSERT_RTNL(); - if (dev == &loopback_dev && how == 1) + if (dev == loopback_dev && how == 1) how = 0; rt6_ifdown(dev); @@ -4212,16 +4212,19 @@ int __init addrconf_init(void) * device and it being up should be removed. */ rtnl_lock(); - if (!ipv6_add_dev(&loopback_dev)) + if (!ipv6_add_dev(loopback_dev)) err = -ENOMEM; rtnl_unlock(); if (err) return err; - ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev); + ip6_null_entry.u.dst.dev = loopback_dev; + ip6_null_entry.rt6i_idev = in6_dev_get(loopback_dev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES - ip6_prohibit_entry.rt6i_idev = in6_dev_get(&loopback_dev); - ip6_blk_hole_entry.rt6i_idev = in6_dev_get(&loopback_dev); + ip6_prohibit_entry.u.dst.dev = loopback_dev; + ip6_prohibit_entry.rt6i_idev = in6_dev_get(loopback_dev); + ip6_blk_hole_entry.u.dst.dev = loopback_dev; + ip6_blk_hole_entry.rt6i_idev = in6_dev_get(loopback_dev); #endif register_netdevice_notifier(&ipv6_dev_notf); @@ -4276,7 +4279,7 @@ void __exit addrconf_cleanup(void) continue; addrconf_ifdown(dev, 1); } - addrconf_ifdown(&loopback_dev, 2); + addrconf_ifdown(loopback_dev, 2); /* * Check hash table. diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 7d18cac3f110..9149fc239759 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -91,7 +91,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt * * BTW, when we send a packet for our own local address on a * non-loopback interface (e.g. ethX), it is being delivered - * via the loopback interface (lo) here; skb->dev = &loopback_dev. + * via the loopback interface (lo) here; skb->dev = loopback_dev. * It, however, should be considered as if it is being * arrived via the sending interface (ethX), because of the * nature of scoping architecture. --yoshfuji diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 2f487cda3b6b..50860531cd3c 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -167,7 +167,7 @@ static inline void send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum) { if (hooknum == NF_IP6_LOCAL_OUT && skb_in->dev == NULL) - skb_in->dev = &loopback_dev; + skb_in->dev = loopback_dev; icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 104070e92cea..a7a21a7ba790 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -138,7 +138,6 @@ struct rt6_info ip6_null_entry = { .dst = { .__refcnt = ATOMIC_INIT(1), .__use = 1, - .dev = &loopback_dev, .obsolete = -1, .error = -ENETUNREACH, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, @@ -164,7 +163,6 @@ struct rt6_info ip6_prohibit_entry = { .dst = { .__refcnt = ATOMIC_INIT(1), .__use = 1, - .dev = &loopback_dev, .obsolete = -1, .error = -EACCES, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, @@ -184,7 +182,6 @@ struct rt6_info ip6_blk_hole_entry = { .dst = { .__refcnt = ATOMIC_INIT(1), .__use = 1, - .dev = &loopback_dev, .obsolete = -1, .error = -EINVAL, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, @@ -224,8 +221,8 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; - if (dev != &loopback_dev && idev != NULL && idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev); + if (dev != loopback_dev && idev != NULL && idev->dev == dev) { + struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); if (loopback_idev != NULL) { rt->rt6i_idev = loopback_idev; in6_dev_put(idev); @@ -1188,12 +1185,12 @@ int ip6_route_add(struct fib6_config *cfg) if ((cfg->fc_flags & RTF_REJECT) || (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { /* hold loopback dev/idev if we haven't done so. */ - if (dev != &loopback_dev) { + if (dev != loopback_dev) { if (dev) { dev_put(dev); in6_dev_put(idev); } - dev = &loopback_dev; + dev = loopback_dev; dev_hold(dev); idev = in6_dev_get(dev); if (!idev) { @@ -1897,13 +1894,13 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, if (rt == NULL) return ERR_PTR(-ENOMEM); - dev_hold(&loopback_dev); + dev_hold(loopback_dev); in6_dev_hold(idev); rt->u.dst.flags = DST_HOST; rt->u.dst.input = ip6_input; rt->u.dst.output = ip6_output; - rt->rt6i_dev = &loopback_dev; + rt->rt6i_dev = loopback_dev; rt->rt6i_idev = idev; rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 3ec0c4770ee3..cc07216cfd59 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -375,7 +375,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt6.rt6i_idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev); + struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 50682d3cd7a9..d6dfd7d1948f 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1949,8 +1949,8 @@ static int stale_bundle(struct dst_entry *dst) void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) { while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { - dst->dev = &loopback_dev; - dev_hold(&loopback_dev); + dst->dev = loopback_dev; + dev_hold(dst->dev); dev_put(dev); } } From 854d8363f37491c955b0edc60d37b62f3d71bb67 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2007 19:18:04 -0700 Subject: [PATCH 1476/2804] [NET]: Dynamically allocate the loopback device, part 2. Doing this makes loopback.c a better example of how to do a simple network device, and it removes the special case single static allocation of a struct net_device, hopefully making maintenance easier. Signed-off-by: Eric W. Biederman Signed-off-by: Daniel Lezcano Acked-By: Kirill Korotaev Acked-by: Benjamin Thery --- drivers/net/loopback.c | 72 ++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 588092e13186..4b6f7b2abea5 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -202,44 +202,60 @@ static const struct ethtool_ops loopback_ethtool_ops = { * The loopback device is special. There is only one instance and * it is statically allocated. Don't do this for other devices. */ -struct net_device __loopback_dev = { - .name = "lo", - .get_stats = &get_stats, - .mtu = (16 * 1024) + 20 + 20 + 12, - .hard_start_xmit = loopback_xmit, - .hard_header = eth_header, - .hard_header_cache = eth_header_cache, - .header_cache_update = eth_header_cache_update, - .hard_header_len = ETH_HLEN, /* 14 */ - .addr_len = ETH_ALEN, /* 6 */ - .tx_queue_len = 0, - .type = ARPHRD_LOOPBACK, /* 0x0001*/ - .rebuild_header = eth_rebuild_header, - .flags = IFF_LOOPBACK, - .features = NETIF_F_SG | NETIF_F_FRAGLIST +static void loopback_setup(struct net_device *dev) +{ + dev->get_stats = &get_stats; + dev->mtu = (16 * 1024) + 20 + 20 + 12; + dev->hard_start_xmit = loopback_xmit; + dev->hard_header = eth_header; + dev->hard_header_cache = eth_header_cache; + dev->header_cache_update = eth_header_cache_update; + dev->hard_header_len = ETH_HLEN; /* 14 */ + dev->addr_len = ETH_ALEN; /* 6 */ + dev->tx_queue_len = 0; + dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ + dev->rebuild_header = eth_rebuild_header; + dev->flags = IFF_LOOPBACK; + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST #ifdef LOOPBACK_TSO - | NETIF_F_TSO + | NETIF_F_TSO #endif - | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA - | NETIF_F_LLTX - | NETIF_F_NETNS_LOCAL, - .ethtool_ops = &loopback_ethtool_ops, - .nd_net = &init_net, -}; - -struct net_device *loopback_dev = &__loopback_dev; + | NETIF_F_NO_CSUM + | NETIF_F_HIGHDMA + | NETIF_F_LLTX + | NETIF_F_NETNS_LOCAL, + dev->ethtool_ops = &loopback_ethtool_ops; +} /* Setup and register the loopback device. */ static int __init loopback_init(void) { - int err = register_netdev(loopback_dev); + struct net_device *dev; + int err; + err = -ENOMEM; + dev = alloc_netdev(0, "lo", loopback_setup); + if (!dev) + goto out; + + err = register_netdev(dev); + if (err) + goto out_free_netdev; + + err = 0; + loopback_dev = dev; + +out: if (err) panic("loopback: Failed to register netdevice: %d\n", err); - return err; -}; -module_init(loopback_init); +out_free_netdev: + free_netdev(dev); + goto out; +} +fs_initcall(loopback_init); + +struct net_device *loopback_dev; EXPORT_SYMBOL(loopback_dev); From 8236632fb3532188c75656421e29f5ab51b47db7 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 25 Sep 2007 19:27:13 -0700 Subject: [PATCH 1477/2804] [NET_SCHED]: explict hold dev tx lock For N cpus, with full throttle traffic on all N CPUs, funneling traffic to the same ethernet device, the devices queue lock is contended by all N CPUs constantly. The TX lock is only contended by a max of 2 CPUS. In the current mode of operation, after all the work of entering the dequeue region, we may endup aborting the path if we are unable to get the tx lock and go back to contend for the queue lock. As N goes up, this gets worse. The changes in this patch result in a small increase in performance with a 4CPU (2xdual-core) with no irq binding. Both e1000 and tg3 showed similar behavior; Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index e970e8e75720..95ae11956f35 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -134,34 +134,19 @@ static inline int qdisc_restart(struct net_device *dev) { struct Qdisc *q = dev->qdisc; struct sk_buff *skb; - unsigned lockless; int ret; /* Dequeue packet */ if (unlikely((skb = dev_dequeue_skb(dev, q)) == NULL)) return 0; - /* - * When the driver has LLTX set, it does its own locking in - * start_xmit. These checks are worth it because even uncongested - * locks can be quite expensive. The driver can do a trylock, as - * is being done here; in case of lock contention it should return - * NETDEV_TX_LOCKED and the packet will be requeued. - */ - lockless = (dev->features & NETIF_F_LLTX); - - if (!lockless && !netif_tx_trylock(dev)) { - /* Another CPU grabbed the driver tx lock */ - return handle_dev_cpu_collision(skb, dev, q); - } /* And release queue */ spin_unlock(&dev->queue_lock); + HARD_TX_LOCK(dev, smp_processor_id()); ret = dev_hard_start_xmit(skb, dev); - - if (!lockless) - netif_tx_unlock(dev); + HARD_TX_UNLOCK(dev); spin_lock(&dev->queue_lock); q = dev->qdisc; From 1156b2c689bf509cdc254394598d410787a02aec Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 25 Sep 2007 19:34:09 -0700 Subject: [PATCH 1478/2804] [IWLWIFI]: remove per-file CFLAGS for IWL define Signed-off-by: Zhu Yi Signed-off-by: David S. Miller --- drivers/net/wireless/iwlwifi/Makefile | 6 ------ drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-3945.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-4965.c | 2 ++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 ++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 ++ 7 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 03837ff54312..3bbd38358d53 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,11 +1,5 @@ obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o -CFLAGS_iwl3945-base.o = -DIWL=3945 -CFLAGS_iwl-3945.o = -DIWL=3945 -CFLAGS_iwl-3945-rs.o = -DIWL=3945 obj-$(CONFIG_IWL4965) += iwl4965.o iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o -CFLAGS_iwl4965-base.o = -DIWL=4965 -CFLAGS_iwl-4965.o = -DIWL=4965 -CFLAGS_iwl-4965-rs.o = -DIWL=4965 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index b0d28ae0b324..f4aabcf480e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -40,6 +40,8 @@ #include #include +#define IWL 3945 + #include "../net/mac80211/ieee80211_rate.h" #include "iwlwifi.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 55f7d89aad8d..acb38750535f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -40,6 +40,8 @@ #include #include +#define IWL 3945 + #include "iwlwifi.h" #include "iwl-helpers.h" #include "iwl-3945.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 7b74481f5282..bc5e67b0b0e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -39,6 +39,8 @@ #include #include +#define IWL 4965 + #include "../net/mac80211/ieee80211_rate.h" #include "iwlwifi.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e624f2a41e0e..b704fe7fca27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -39,6 +39,8 @@ #include #include +#define IWL 4965 + #include "iwlwifi.h" #include "iwl-4965.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index cc405f4a8647..44f983b6d39b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -58,6 +58,8 @@ #include +#define IWL 3945 + #include "iwlwifi.h" #include "iwl-3945.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6cea3118b7c1..61500a209297 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -58,6 +58,8 @@ #include +#define IWL 4965 + #include "iwlwifi.h" #include "iwl-4965.h" #include "iwl-helpers.h" From e24eb521fbf2a350ce879dfc1d8e56d4ffa2aa22 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 25 Sep 2007 19:42:02 -0700 Subject: [PATCH 1479/2804] [NET]: note that NETIF_F_LLTX is deprecated Am Freitag, 21. September 2007 schrieb Herbert Xu: > Please don't use LLTX in new drivers. We're trying to get rid > of it since it's > > 1) unnecessary; > 2) causes problems with AF_PACKET seeing things twice. I suggest to document that LLTX is deprecated. Signed-off-by: Christian Borntraeger Acked-by: Herbert Xu Signed-off-by: David S. Miller --- Documentation/networking/netdevices.txt | 3 ++- include/linux/netdevice.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt index 9f7be9b7785e..d0f71fc7f782 100644 --- a/Documentation/networking/netdevices.txt +++ b/Documentation/networking/netdevices.txt @@ -73,7 +73,8 @@ dev->hard_start_xmit: has to lock by itself when needed. It is recommended to use a try lock for this and return NETDEV_TX_LOCKED when the spin lock fails. The locking there should also properly protect against - set_multicast_list. + set_multicast_list. Note that the use of NETIF_F_LLTX is deprecated. + Dont use it for new drivers. Context: Process with BHs disabled or BH (timer), will be called with interrupts disabled by netconsole. diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index baa915f0d285..2088097663b5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -449,7 +449,8 @@ struct net_device #define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */ #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ #define NETIF_F_GSO 2048 /* Enable software GSO. */ -#define NETIF_F_LLTX 4096 /* LockLess TX */ +#define NETIF_F_LLTX 4096 /* LockLess TX - deprecated. Please */ + /* do not use LLTX in new drivers */ #define NETIF_F_NETNS_LOCAL 8192 /* Does not change network namespaces */ #define NETIF_F_MULTI_QUEUE 16384 /* Has multiple TX/RX queues */ #define NETIF_F_LRO 32768 /* large receive offload */ From fa46081c506ab518e8ea4095bc21b6d544006c00 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 31 Aug 2007 00:30:31 +0200 Subject: [PATCH 1480/2804] [ZD1211RW]: Don't needlessly initialize variable to NULL in zd_chip No need to initialize to NULL when variable is never used before it's assigned the return value of a kmalloc() call. Signed-off-by: Jesper Juhl Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/zd1211rw/zd_chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 750c0f99e86f..3d60c69b20e7 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -106,7 +106,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr { int r; int i; - zd_addr_t *a16 = (zd_addr_t *)NULL; + zd_addr_t *a16; u16 *v16; unsigned int count16; From 01449c5a469c8c1c647cfd3705b1ff290be6afff Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 16 Sep 2007 17:26:49 -0500 Subject: [PATCH 1481/2804] [BCM43XX]: Change radio hardware switch status printk from debug to regular Some distros ship bcm43xx with debugging printout disabled. For those BCM43xx devices with radio on/off switches, this makes it impossible to know if the radio is on or off. This patch changes a pair of debug printk's into ordinary printk's. It also changes the message that prints when the radio is initialized to the off state as the old message seems to confuse users. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 ++-- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index e038d072398d..45683437a98d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2380,7 +2380,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) goto err_gpio_cleanup; bcm43xx_radio_turn_on(bcm); bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); - dprintk(KERN_INFO PFX "Radio %s by hardware\n", + printk(KERN_INFO PFX "Radio %s by hardware\n", (bcm->radio_hw_enable == 0) ? "disabled" : "enabled"); bcm43xx_write16(bcm, 0x03E6, 0x0000); @@ -3129,7 +3129,7 @@ static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm) radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) { bcm->radio_hw_enable = radio_hw_enable; - dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n", + printk(KERN_INFO PFX "Radio hardware status changed to %s\n", (radio_hw_enable == 0) ? "disabled" : "enabled"); bcm43xx_leds_update(bcm, 0); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 6a109f4a1b71..c605099c9baf 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -2146,7 +2146,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) } else bcm43xx_phy_write(bcm, 0x0015, 0xAA00); radio->enabled = 0; - dprintk(KERN_INFO PFX "Radio turned off\n"); + dprintk(KERN_INFO PFX "Radio initialized\n"); bcm43xx_leds_update(bcm, 0); } From ababda03e1a4c41d75cd86c186025532bf91d057 Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Sat, 1 Sep 2007 22:40:32 +0100 Subject: [PATCH 1482/2804] [ZD1211RD]: add USB id for Telegent TG54USB WLAN adapter Reinhard Speyerer reported at 2007-08-10 a new device. Here are the information strings. Product: Telegent TG54USB WLAN Adapter USB ID: 129b:1666 Chip ID: zd1211 chip 129b:1666 v4330 high 00-01-36 RF2959_RF pa0 ----- FCC ID: N89-UW620Z Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index e49628b7d4ce..895ff8441874 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -55,6 +55,7 @@ static struct usb_device_id usb_ids[] = { { 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 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, From 90f4dd0f4ba910b86f387874ed990ca69c0951a5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 16 Sep 2007 15:08:37 -0700 Subject: [PATCH 1483/2804] [P54PCI]: terminate pci table Signed-off-by: Andrew Morton Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/p54pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c index e9ecc663dc70..75927583f766 100644 --- a/drivers/net/wireless/p54pci.c +++ b/drivers/net/wireless/p54pci.c @@ -37,6 +37,7 @@ static struct pci_device_id p54p_table[] __devinitdata = { { PCI_DEVICE(0x1260, 0x3877) }, /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ { PCI_DEVICE(0x1260, 0x3886) }, + { }, }; MODULE_DEVICE_TABLE(pci, p54p_table); From b85b3b7af52d1c1bd45bfcd47aa425a15fda45f7 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 18:51:38 +0200 Subject: [PATCH 1484/2804] [B43]: Don't lock irq_lock in debugfs txpower adjust It's not required and the txpower adjustment must not be in atomic. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/debugfs.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 3aafde9f08a8..734e70e1a06d 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -223,15 +223,10 @@ out: static int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count) { - unsigned long flags; unsigned long phy_flags; - int err = 0; - spin_lock_irqsave(&dev->wl->irq_lock, flags); - if (dev->phy.type != B43_PHYTYPE_G) { - err = -ENODEV; - goto out_unlock; - } + if (dev->phy.type != B43_PHYTYPE_G) + return -ENODEV; if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { /* Automatic control */ dev->phy.manual_txpower_control = 0; @@ -240,10 +235,8 @@ static int txpower_g_write_file(struct b43_wldev *dev, int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; /* Manual control */ if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, - &txmix, &pa2db, &pa3db) != 5) { - err = -EINVAL; - goto out_unlock; - } + &txmix, &pa2db, &pa3db) != 5) + return -EINVAL; b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); dev->phy.manual_txpower_control = 1; dev->phy.bbatt.att = bbatt; @@ -262,10 +255,8 @@ static int txpower_g_write_file(struct b43_wldev *dev, b43_radio_unlock(dev); b43_phy_unlock(dev, phy_flags); } -out_unlock: - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - return err; + return 0; } /* wl->irq_lock is locked */ From 4b402c65a3a17257af45875159395278e4a2f0cd Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 18:53:44 +0200 Subject: [PATCH 1485/2804] [SSB]: Use ioreadX() and iowriteX() for PCI. On a PCI bus use ioreadX() and iowriteX(). We map the I/O space with pci_iomap(), so we must use the correct accessor functions, too. readX() and writeX() are not guaranteed to accept the cookie returned from pci_iomap() (though, it currently works on most architectures). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/ssb/pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 3d23ca4befe3..e19b9f90195e 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -531,7 +531,7 @@ static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) if (unlikely(ssb_pci_switch_core(bus, dev))) return 0xFFFF; } - return readw(bus->mmio + offset); + return ioread16(bus->mmio + offset); } static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) @@ -544,7 +544,7 @@ static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) if (unlikely(ssb_pci_switch_core(bus, dev))) return 0xFFFFFFFF; } - return readl(bus->mmio + offset); + return ioread32(bus->mmio + offset); } static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) @@ -557,7 +557,7 @@ static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) if (unlikely(ssb_pci_switch_core(bus, dev))) return; } - writew(value, bus->mmio + offset); + iowrite16(value, bus->mmio + offset); } static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) @@ -570,7 +570,7 @@ static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) if (unlikely(ssb_pci_switch_core(bus, dev))) return; } - writel(value, bus->mmio + offset); + iowrite32(value, bus->mmio + offset); } /* Not "static", as it's used in main.c */ From 6b9bafec6608539d07f7ccdeefe121dabe06604f Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 18:55:12 +0200 Subject: [PATCH 1486/2804] [SSB]: Sparse fixes. This fixes all Sparse warnings in SSB. No semantics change. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/ssb/b43_pci_bridge.c | 2 ++ drivers/ssb/driver_chipcommon.c | 7 +++---- drivers/ssb/pci.c | 10 +++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index fa3bd292f5f7..f145d8a4cfde 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c @@ -13,6 +13,8 @@ #include #include +#include "ssb_private.h" + static const struct pci_device_id b43_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) }, diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index a890544e8fba..6fbf1c53b6f2 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -345,8 +345,7 @@ void ssb_chipco_timing_init(struct ssb_chipcommon *cc, } /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -void -ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) +void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) { /* instant NMI */ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); @@ -359,12 +358,12 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) { - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); + chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); } void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) { - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); + chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); } #ifdef CONFIG_SSB_SERIAL diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index e19b9f90195e..0ab095c6581a 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -306,15 +306,15 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0); for (i = 0; i < 3; i++) { v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; - *(((u16 *)out->il0mac) + i) = cpu_to_be16(v); + *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } for (i = 0; i < 3; i++) { v = in[SPOFF(SSB_SPROM1_ET0MAC) + i]; - *(((u16 *)out->et0mac) + i) = cpu_to_be16(v); + *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); } for (i = 0; i < 3; i++) { v = in[SPOFF(SSB_SPROM1_ET1MAC) + i]; - *(((u16 *)out->et1mac) + i) = cpu_to_be16(v); + *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); } SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, @@ -352,7 +352,7 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) SSB_SPROM1_AGAIN_BG_SHIFT); for (i = 0; i < 4; i++) { v = in[SPOFF(SSB_SPROM1_OEM) + i]; - *(((u16 *)out->oem) + i) = cpu_to_le16(v); + *(((__le16 *)out->oem) + i) = cpu_to_le16(v); } } @@ -374,7 +374,7 @@ static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in) SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); for (i = 0; i < 4; i++) { v = in[SPOFF(SSB_SPROM2_CCODE) + i]; - *(((u16 *)out->country_str) + i) = cpu_to_le16(v); + *(((__le16 *)out->country_str) + i) = cpu_to_le16(v); } } From 05155c83d13b983ac2c5691575fd471543df31fe Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 19:10:08 +0200 Subject: [PATCH 1487/2804] [B43]: Change loglevel of radio-enable message. Also cleanup the code a bit and remove the inline. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/leds.c | 15 +++++++-------- drivers/net/wireless/b43/main.c | 23 +++++++++++++++++++---- drivers/net/wireless/b43/main.h | 17 ----------------- 3 files changed, 26 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 85d965de5791..0f155b4f34eb 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -176,6 +176,7 @@ void b43_leds_update(struct b43_wldev *dev, int activity) unsigned long interval = 0; u16 ledctl; unsigned long flags; + bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); spin_lock_irqsave(&dev->wl->leds_lock, flags); ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); @@ -195,21 +196,19 @@ void b43_leds_update(struct b43_wldev *dev, int activity) turn_on = activity; break; case B43_LED_RADIO_ALL: - turn_on = phy->radio_on && b43_is_hw_radio_enabled(dev); + turn_on = radio_enabled; break; case B43_LED_RADIO_A: - turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) - && phy->type == B43_PHYTYPE_A); + turn_on = (radio_enabled && phy->type == B43_PHYTYPE_A); break; case B43_LED_RADIO_B: - turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) - && (phy->type == B43_PHYTYPE_B - || phy->type == B43_PHYTYPE_G)); + turn_on = (radio_enabled && + (phy->type == B43_PHYTYPE_B + || phy->type == B43_PHYTYPE_G)); break; case B43_LED_MODE_BG: if (phy->type == B43_PHYTYPE_G - && b43_is_hw_radio_enabled(dev) - && 1 /*FIXME: using G rates. */ ) + && radio_enabled) turn_on = 1; break; case B43_LED_TRANSFER: diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 66c89df51fb8..1390f41425f1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2175,6 +2175,21 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); } +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) +{ + if (dev->phy.rev >= 3) { + if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) + & B43_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) + & B43_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; + } + return 0; +} + /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { @@ -2214,7 +2229,7 @@ static int b43_chip_init(struct b43_wldev *dev) b43_radio_turn_on(dev); dev->radio_hw_enable = b43_is_hw_radio_enabled(dev); b43dbg(dev->wl, "Radio %s by hardware\n", - (dev->radio_hw_enable == 0) ? "disabled" : "enabled"); + dev->radio_hw_enable ? "enabled" : "disabled"); b43_write16(dev, 0x03E6, 0x0000); err = b43_phy_init(dev); @@ -2373,14 +2388,14 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) static void b43_periodic_every1sec(struct b43_wldev *dev) { - int radio_hw_enable; + bool radio_hw_enable; /* check if radio hardware enabled status changed */ radio_hw_enable = b43_is_hw_radio_enabled(dev); if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { dev->radio_hw_enable = radio_hw_enable; - b43dbg(dev->wl, "Radio hardware status changed to %s\n", - (radio_hw_enable == 0) ? "disabled" : "enabled"); + b43info(dev->wl, "Radio hardware status changed to %s\n", + radio_hw_enable ? "ENABLED" : "DISABLED"); b43_leds_update(dev, 0); } } diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index bd8fcf72dc5d..284d17da17d1 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -96,23 +96,6 @@ static inline int b43_is_ofdm_rate(int rate) return !b43_is_cck_rate(rate); } -static inline int b43_is_hw_radio_enabled(struct b43_wldev *dev) -{ - /* function to return state of hardware enable of radio - * returns 0 if radio disabled, 1 if radio enabled - */ - struct b43_phy *phy = &dev->phy; - - if (phy->rev >= 3) - return ((b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) - & B43_MMIO_RADIO_HWENABLED_HI_MASK) - == 0) ? 1 : 0; - else - return ((b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) - & B43_MMIO_RADIO_HWENABLED_LO_MASK) - == 0) ? 0 : 1; -} - void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); From 501d857ec93e797d4872d6b9b265b7472b455ddf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Oct 2007 18:14:23 -0700 Subject: [PATCH 1488/2804] [IEEE80211]: Fix softmac lockdep reports. It seems I was actually able to hit this deadlock, on my quad G5 softmac locks up more often than not. This fixes it by using an own workqueue that can safely be flushed under RTNL. Not sure if the patch is correct with the workqueue naming. And don't think with the patch it doesn't continually lock up. It still does, just doesn't invoke lockdep warnings all the time. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/ieee80211softmac.h | 2 ++ net/ieee80211/softmac/ieee80211softmac_assoc.c | 8 ++++---- net/ieee80211/softmac/ieee80211softmac_auth.c | 8 ++++---- net/ieee80211/softmac/ieee80211softmac_event.c | 2 +- net/ieee80211/softmac/ieee80211softmac_module.c | 10 ++++++++-- net/ieee80211/softmac/ieee80211softmac_scan.c | 4 ++-- net/ieee80211/softmac/ieee80211softmac_wx.c | 8 ++++---- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h index 89119277553d..1ef6282fdded 100644 --- a/include/net/ieee80211softmac.h +++ b/include/net/ieee80211softmac.h @@ -229,6 +229,8 @@ struct ieee80211softmac_device { /* this lock protects this structure */ spinlock_t lock; + struct workqueue_struct *wq; + u8 running; /* SoftMAC started? */ u8 scanning; diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index 4c0feb2dacd8..c4d122ddd72c 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -53,7 +53,7 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft /* Set a timer for timeout */ /* FIXME: make timeout configurable */ if (likely(mac->running)) - schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ); + queue_delayed_work(mac->wq, &mac->associnfo.timeout, 5 * HZ); spin_unlock_irqrestore(&mac->lock, flags); } @@ -419,7 +419,7 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, network->authenticated = 0; /* we don't want to do this more than once ... */ network->auth_desynced_once = 1; - schedule_delayed_work(&mac->associnfo.work, 0); + queue_delayed_work(mac->wq, &mac->associnfo.work, 0); break; } default: @@ -441,7 +441,7 @@ ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac) spin_lock_irqsave(&mac->lock, flags); mac->associnfo.associating = 1; - schedule_delayed_work(&mac->associnfo.work, 0); + queue_delayed_work(mac->wq, &mac->associnfo.work, 0); spin_unlock_irqrestore(&mac->lock, flags); } @@ -483,7 +483,7 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev, dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); return 0; } - schedule_delayed_work(&mac->associnfo.work, 0); + queue_delayed_work(mac->wq, &mac->associnfo.work, 0); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index 855fa0fe641b..a53a751d0702 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -62,7 +62,7 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, /* add to list */ list_add_tail(&auth->list, &mac->auth_queue); - schedule_delayed_work(&auth->work, 0); + queue_delayed_work(mac->wq, &auth->work, 0); spin_unlock_irqrestore(&mac->lock, flags); return 0; @@ -97,7 +97,7 @@ ieee80211softmac_auth_queue(struct work_struct *work) } net->authenticated = 0; /* add a timeout call so we eventually give up waiting for an auth reply */ - schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT); + queue_delayed_work(mac->wq, &auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT); auth->retry--; spin_unlock_irqrestore(&mac->lock, flags); if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state)) @@ -242,7 +242,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) * request. */ cancel_delayed_work(&aq->work); INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response); - schedule_delayed_work(&aq->work, 0); + queue_delayed_work(mac->wq, &aq->work, 0); spin_unlock_irqrestore(&mac->lock, flags); return 0; case IEEE80211SOFTMAC_AUTH_SHARED_PASS: @@ -408,6 +408,6 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de ieee80211softmac_deauth_from_net(mac, net); /* let's try to re-associate */ - schedule_delayed_work(&mac->associnfo.work, 0); + queue_delayed_work(mac->wq, &mac->associnfo.work, 0); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c index b3e33a4d4869..8cef05b60f16 100644 --- a/net/ieee80211/softmac/ieee80211softmac_event.c +++ b/net/ieee80211/softmac/ieee80211softmac_event.c @@ -172,7 +172,7 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve /* User may have subscribed to ANY event, so * we tell them which event triggered it. */ eventptr->event_type = event; - schedule_delayed_work(&eventptr->work, 0); + queue_delayed_work(mac->wq, &eventptr->work, 0); } } } diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c index 6398e6e67493..07505ca859af 100644 --- a/net/ieee80211/softmac/ieee80211softmac_module.c +++ b/net/ieee80211/softmac/ieee80211softmac_module.c @@ -36,8 +36,13 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv) dev = alloc_ieee80211(sizeof(*softmac) + sizeof_priv); if (!dev) return NULL; - softmac = ieee80211_priv(dev); + softmac->wq = create_freezeable_workqueue("softmac"); + if (!softmac->wq) { + free_ieee80211(dev); + return NULL; + } + softmac->dev = dev; softmac->ieee = netdev_priv(dev); spin_lock_init(&softmac->lock); @@ -105,7 +110,7 @@ ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm) cancel_delayed_work(&eventptr->work); spin_unlock_irqrestore(&sm->lock, flags); - flush_scheduled_work(); + flush_workqueue(sm->wq); /* now we should be save and no longer need locking... */ spin_lock_irqsave(&sm->lock, flags); @@ -139,6 +144,7 @@ void free_ieee80211softmac(struct net_device *dev) ieee80211softmac_clear_pending_work(sm); kfree(sm->scaninfo); kfree(sm->wpa.IE); + destroy_workqueue(sm->wq); free_ieee80211(dev); } EXPORT_SYMBOL_GPL(free_ieee80211softmac); diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c index abea3648680e..bfab8d7db88f 100644 --- a/net/ieee80211/softmac/ieee80211softmac_scan.c +++ b/net/ieee80211/softmac/ieee80211softmac_scan.c @@ -123,7 +123,7 @@ void ieee80211softmac_scan(struct work_struct *work) spin_unlock_irqrestore(&sm->lock, flags); break; } - schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY); + queue_delayed_work(sm->wq, &si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY); spin_unlock_irqrestore(&sm->lock, flags); return; } else { @@ -190,7 +190,7 @@ int ieee80211softmac_start_scan_implementation(struct net_device *dev) sm->scaninfo->started = 1; sm->scaninfo->stop = 0; INIT_COMPLETION(sm->scaninfo->finished); - schedule_delayed_work(&sm->scaninfo->softmac_scan, 0); + queue_delayed_work(sm->wq, &sm->scaninfo->softmac_scan, 0); spin_unlock_irqrestore(&sm->lock, flags); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index 8e8ad08a411c..ac36767b56e8 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c @@ -91,7 +91,7 @@ check_assoc_again: /* We must unlock to avoid deadlocks with the assoc workqueue * on the associnfo.mutex */ mutex_unlock(&sm->associnfo.mutex); - flush_scheduled_work(); + flush_workqueue(sm->wq); /* Avoid race! Check assoc status again. Maybe someone started an * association while we flushed. */ goto check_assoc_again; @@ -114,7 +114,7 @@ check_assoc_again: sm->associnfo.associating = 1; /* queue lower level code to do work (if necessary) */ - schedule_delayed_work(&sm->associnfo.work, 0); + queue_delayed_work(sm->wq, &sm->associnfo.work, 0); mutex_unlock(&sm->associnfo.mutex); @@ -349,7 +349,7 @@ ieee80211softmac_wx_set_wap(struct net_device *net_dev, /* force reassociation */ mac->associnfo.bssvalid = 0; if (mac->associnfo.associated) - schedule_delayed_work(&mac->associnfo.work, 0); + queue_delayed_work(mac->wq, &mac->associnfo.work, 0); } else if (is_zero_ether_addr(data->ap_addr.sa_data)) { /* the bssid we have is no longer fixed */ mac->associnfo.bssfixed = 0; @@ -366,7 +366,7 @@ ieee80211softmac_wx_set_wap(struct net_device *net_dev, /* tell the other code that this bssid should be used no matter what */ mac->associnfo.bssfixed = 1; /* queue associate if new bssid or (old one again and not associated) */ - schedule_delayed_work(&mac->associnfo.work, 0); + queue_delayed_work(mac->wq, &mac->associnfo.work, 0); } out: From 61609bc0e4d3bc677ecdccf216a0a77563f52457 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 20 Sep 2007 22:06:39 +0200 Subject: [PATCH 1489/2804] [MAC80211]: Add support for setting TX power and radio status This adds support for disabling the radio and setting the TXpower through wext. This also fixes the prism TXpower ioctl (It always overwrote the TXpower value in ieee80211_hw_config()) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211.c | 7 ++++++- net/mac80211/ieee80211_ioctl.c | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 4229d150e783..23853331e8db 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -704,7 +704,12 @@ int ieee80211_hw_config(struct ieee80211_local *local) local->hw.conf.channel = chan->chan; local->hw.conf.channel_val = chan->val; - local->hw.conf.power_level = chan->power_level; + if (!local->hw.conf.power_level) { + local->hw.conf.power_level = chan->power_level; + } else { + local->hw.conf.power_level = min(chan->power_level, + local->hw.conf.power_level); + } local->hw.conf.freq = chan->freq; local->hw.conf.phymode = mode->mode; local->hw.conf.antenna_max = chan->antenna_max; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 6ccdde82bded..b4cce441d7e6 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -666,6 +666,38 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, return 0; } +static int ieee80211_ioctl_siwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + bool need_reconfig = 0; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + if (!data->txpower.fixed) + return -EINVAL; + + if (local->hw.conf.power_level != data->txpower.value) { + local->hw.conf.power_level = data->txpower.value; + need_reconfig = 1; + } + if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { + local->hw.conf.radio_enabled = !(data->txpower.disabled); + need_reconfig = 1; + } + if (need_reconfig) { + ieee80211_hw_config(local); + /* The return value of hw_config is not of big interest here, + * as it doesn't say that it failed because of _this_ config + * change or something else. Ignore it. */ + } + + return 0; +} + static int ieee80211_ioctl_giwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *extra) @@ -1339,7 +1371,7 @@ static const iw_handler ieee80211_handler[] = (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ From 6a724d68a38c33ba4c7f7b5f008301ac12c9ced1 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 20 Sep 2007 22:12:58 +0200 Subject: [PATCH 1490/2804] [B43]: Remove the "radio hw enabled" message on startup. This message is useless. Only report state changes. Cc: Larry Finger Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1390f41425f1..cc5285407e88 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2227,9 +2227,6 @@ static int b43_chip_init(struct b43_wldev *dev) if (err) goto err_gpio_cleanup; b43_radio_turn_on(dev); - dev->radio_hw_enable = b43_is_hw_radio_enabled(dev); - b43dbg(dev->wl, "Radio %s by hardware\n", - dev->radio_hw_enable ? "enabled" : "disabled"); b43_write16(dev, 0x03E6, 0x0000); err = b43_phy_init(dev); @@ -3252,6 +3249,9 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev) { /* Flags */ dev->reg124_set_0x4 = 0; + /* Assume the radio is enabled. If it's not enabled, the state will + * immediately get fixed on the first periodic work run. */ + dev->radio_hw_enable = 1; /* Stats */ memset(&dev->stats, 0, sizeof(dev->stats)); From fda9abcf1a5b6b78a4ead25729583541af9876b5 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 20 Sep 2007 22:14:18 +0200 Subject: [PATCH 1491/2804] [B43]: Support for turning the radio off from software. This adds support for turning the radio off in software. That's useful in environments, where you don't want the RF to radiate any signals, but don't want to bring the interface down. Cc: Larry Finger Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/b43.h | 11 +++++++- drivers/net/wireless/b43/main.c | 17 ++++++++++++ drivers/net/wireless/b43/phy.c | 48 ++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 270a2112de2a..a22435ade8ca 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -459,7 +459,6 @@ struct b43_phy { u16 radio_ver; /* Radio version */ u8 radio_rev; /* Radio revision */ - bool radio_on; /* Radio switched on/off */ bool locked; /* Only used in b43_phy_{un}lock() */ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ @@ -468,6 +467,16 @@ struct b43_phy { bool aci_wlan_automatic; bool aci_hw_rssi; + /* Radio switched on/off */ + bool radio_on; + struct { + /* Values saved when turning the radio off. + * They are needed when turning it on again. */ + bool valid; + u16 rfover; + u16 rfoverval; + } radio_off_context; + u16 minlowsig[2]; u16 minlowsigpos[2]; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cc5285407e88..b44c9f928848 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2874,6 +2874,21 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) b43_set_beacon_int(dev, conf->beacon_int); + if (!!conf->radio_enabled != phy->radio_on) { + if (conf->radio_enabled) { + b43_radio_turn_on(dev); + b43info(dev->wl, "Radio turned on by software\n"); + if (!dev->radio_hw_enable) { + b43info(dev->wl, "The hardware RF-kill button " + "still turns the radio physically off. " + "Press the button to turn it on.\n"); + } + } else { + b43_radio_turn_off(dev); + b43info(dev->wl, "Radio turned off by software\n"); + } + } + spin_lock_irqsave(&wl->irq_lock, flags); b43_interrupt_enable(dev, savedirqs); mmiowb(); @@ -3218,6 +3233,8 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, phy->aci_wlan_automatic = 0; phy->aci_hw_rssi = 0; + phy->radio_off_context.valid = 0; + lo = phy->lo_control; if (lo) { memset(lo, 0, sizeof(*(phy->lo_control))); diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 3282893021b0..354d18238752 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -1205,10 +1205,7 @@ static void b43_phy_initb2(struct b43_wldev *dev) val -= 0x0202; } b43_phy_write(dev, 0x03E4, 0x3000); - if (phy->channel == 0xFF) - b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0); - else - b43_radio_selectchannel(dev, phy->channel, 0); + b43_radio_selectchannel(dev, phy->channel, 0); if (phy->radio_ver != 0x2050) { b43_radio_write16(dev, 0x0075, 0x0080); b43_radio_write16(dev, 0x0079, 0x0081); @@ -1256,10 +1253,7 @@ static void b43_phy_initb4(struct b43_wldev *dev) val -= 0x0202; } b43_phy_write(dev, 0x03E4, 0x3000); - if (phy->channel == 0xFF) - b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0); - else - b43_radio_selectchannel(dev, phy->channel, 0); + b43_radio_selectchannel(dev, phy->channel, 0); if (phy->radio_ver != 0x2050) { b43_radio_write16(dev, 0x0075, 0x0080); b43_radio_write16(dev, 0x0079, 0x0081); @@ -4110,6 +4104,20 @@ int b43_radio_selectchannel(struct b43_wldev *dev, u16 freq; u16 channelcookie; + if (channel == 0xFF) { + switch (phy->type) { + case B43_PHYTYPE_A: + channel = B43_DEFAULT_CHANNEL_A; + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + channel = B43_DEFAULT_CHANNEL_BG; + break; + default: + B43_WARN_ON(1); + } + } + /* First we set the channel radio code to prevent the * firmware from sending ghost packets. */ @@ -4302,6 +4310,7 @@ void b43_radio_turn_on(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; int err; + u8 channel; might_sleep(); @@ -4321,14 +4330,23 @@ void b43_radio_turn_on(struct b43_wldev *dev) b43_phy_write(dev, 0x0015, 0x8000); b43_phy_write(dev, 0x0015, 0xCC00); b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); + if (phy->radio_off_context.valid) { + /* Restore the RFover values. */ + b43_phy_write(dev, B43_PHY_RFOVER, + phy->radio_off_context.rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + phy->radio_off_context.rfoverval); + phy->radio_off_context.valid = 0; + } + channel = phy->channel; err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1); + err |= b43_radio_selectchannel(dev, channel, 0); B43_WARN_ON(err); break; default: B43_WARN_ON(1); } phy->radio_on = 1; - b43dbg(dev->wl, "Radio turned on\n"); } void b43_radio_turn_off(struct b43_wldev *dev) @@ -4342,10 +4360,16 @@ void b43_radio_turn_off(struct b43_wldev *dev) b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); } if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) { - b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x008C); - b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) & 0xFF73); + u16 rfover, rfoverval; + + rfover = b43_phy_read(dev, B43_PHY_RFOVER); + rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); } else b43_phy_write(dev, 0x0015, 0xAA00); phy->radio_on = 0; - b43dbg(dev->wl, "Radio turned off\n"); } From 42a9174f541d2338d35b91869415d9ae9312ca0d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 20 Sep 2007 21:11:02 -0500 Subject: [PATCH 1492/2804] [B43LEGACY]: Support for turning the radio off from software. This adds support for turning the radio off in software. That's useful in environments, where you don't want the RF to radiate any signals, but don't want to bring the interface down. This patch is based on a similar patch of b43 by Michael Buesch. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43legacy/b43legacy.h | 11 +++++- drivers/net/wireless/b43legacy/main.c | 16 +++++++++ drivers/net/wireless/b43legacy/phy.c | 14 ++------ drivers/net/wireless/b43legacy/radio.c | 39 ++++++++++++++++++---- 4 files changed, 61 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 34a6277051a1..746de2ff498c 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -411,7 +411,6 @@ struct b43legacy_phy { u8 calibrated:1; u8 radio_rev; /* Radio revision */ - bool radio_on; /* Radio switched on/off */ bool locked; /* Only used in b43legacy_phy_{un}lock() */ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ @@ -420,6 +419,16 @@ struct b43legacy_phy { bool aci_wlan_automatic; bool aci_hw_rssi; + /* Radio switched on/off */ + bool radio_on; + struct { + /* Values saved when turning the radio off. + * They are needed when turning it on again. */ + bool valid; + u16 rfover; + u16 rfoverval; + } radio_off_context; + u16 minlowsig[2]; u16 minlowsigpos[2]; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 61b94218094b..3e935d0d4b80 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2660,6 +2660,22 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, b43legacy_set_beacon_int(dev, conf->beacon_int); + if (!!conf->radio_enabled != phy->radio_on) { + if (conf->radio_enabled) { + b43legacy_radio_turn_on(dev); + b43legacyinfo(dev->wl, "Radio turned on by software\n"); + if (!dev->radio_hw_enable) + b43legacyinfo(dev->wl, "The hardware RF-kill" + " button still turns the radio" + " physically off. Press the" + " button to turn it on.\n"); + } else { + b43legacy_radio_turn_off(dev); + b43legacyinfo(dev->wl, "Radio turned off by" + " software\n"); + } + } + spin_lock_irqsave(&wl->irq_lock, flags); b43legacy_interrupt_enable(dev, savedirqs); mmiowb(); diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index f9edbd5f3009..22a4b3d0186d 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -462,12 +462,7 @@ static void b43legacy_phy_initb2(struct b43legacy_wldev *dev) val -= 0x0202; } b43legacy_phy_write(dev, 0x03E4, 0x3000); - if (phy->channel == 0xFF) - b43legacy_radio_selectchannel(dev, - B43legacy_RADIO_DEFAULT_CHANNEL_BG, - 0); - else - b43legacy_radio_selectchannel(dev, phy->channel, 0); + b43legacy_radio_selectchannel(dev, phy->channel, 0); if (phy->radio_ver != 0x2050) { b43legacy_radio_write16(dev, 0x0075, 0x0080); b43legacy_radio_write16(dev, 0x0079, 0x0081); @@ -516,12 +511,7 @@ static void b43legacy_phy_initb4(struct b43legacy_wldev *dev) val -= 0x0202; } b43legacy_phy_write(dev, 0x03E4, 0x3000); - if (phy->channel == 0xFF) - b43legacy_radio_selectchannel(dev, - B43legacy_RADIO_DEFAULT_CHANNEL_BG, - 0); - else - b43legacy_radio_selectchannel(dev, phy->channel, 0); + b43legacy_radio_selectchannel(dev, phy->channel, 0); if (phy->radio_ver != 0x2050) { b43legacy_radio_write16(dev, 0x0075, 0x0080); b43legacy_radio_write16(dev, 0x0079, 0x0081); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 2a11ee63f400..54067f082825 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -1767,6 +1767,17 @@ int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, { struct b43legacy_phy *phy = &dev->phy; + if (channel == 0xFF) { + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG; + break; + default: + B43legacy_WARN_ON(1); + } + } + /* TODO: Check if channel is valid - return -EINVAL if not */ if (synthetic_pu_workaround) b43legacy_synth_pu_workaround(dev, channel); @@ -2070,6 +2081,7 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) { struct b43legacy_phy *phy = &dev->phy; int err; + u8 channel; might_sleep(); @@ -2083,15 +2095,24 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0015, 0xCC00); b43legacy_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); + if (phy->radio_off_context.valid) { + /* Restore the RFover values. */ + b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, + phy->radio_off_context.rfover); + b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, + phy->radio_off_context.rfoverval); + phy->radio_off_context.valid = 0; + } + channel = phy->channel; err = b43legacy_radio_selectchannel(dev, B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1); - B43legacy_WARN_ON(err != 0); + err |= b43legacy_radio_selectchannel(dev, channel, 0); + B43legacy_WARN_ON(err); break; default: B43legacy_BUG_ON(1); } phy->radio_on = 1; - b43legacydbg(dev->wl, "Radio turned on\n"); b43legacy_leds_update(dev, 0); } @@ -2100,10 +2121,16 @@ void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) struct b43legacy_phy *phy = &dev->phy; if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) { - b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) - | 0x008C); - b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) - & 0xFF73); + u16 rfover, rfoverval; + + rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER); + rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL); + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C); + b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, + rfoverval & 0xFF73); } else b43legacy_phy_write(dev, 0x0015, 0xAA00); phy->radio_on = 0; From 1065de1562b1552a24f83e379bcb5fed351a8bc4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 20 Sep 2007 20:10:07 -0500 Subject: [PATCH 1493/2804] [B43LEGACY]: Change the hardware radio enable logic and cleanup code This change cleans up the radio-related messages in several ways. (1) The state of the rfkill switch is assumed to be on, rather than tested. Now, any user without such a switch will not see any messages. For devices with such a switch, a message will be logged only if the initial state is off, or if the switch is toggled. (2) The routine for testing the switch state is no longer inline. (3) The LED handling routine is simplified. (4) The "Radio turned off" message that has confused some users has been changed to "Radio initialized". This patch is patterned after a similar change to b43 by Michael Buesch. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43legacy/leds.c | 12 ++++-------- drivers/net/wireless/b43legacy/main.c | 25 ++++++++++++++++++++----- drivers/net/wireless/b43legacy/main.h | 20 -------------------- drivers/net/wireless/b43legacy/radio.c | 2 +- 4 files changed, 25 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 498912ddeddb..a584ea810502 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -182,6 +182,7 @@ void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) unsigned long interval = 0; u16 ledctl; unsigned long flags; + bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); spin_lock_irqsave(&dev->wl->leds_lock, flags); ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); @@ -201,20 +202,15 @@ void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) turn_on = activity; break; case B43legacy_LED_RADIO_ALL: - turn_on = phy->radio_on && - b43legacy_is_hw_radio_enabled(dev); + turn_on = radio_enabled; break; case B43legacy_LED_RADIO_A: break; case B43legacy_LED_RADIO_B: - turn_on = (phy->radio_on && - b43legacy_is_hw_radio_enabled(dev) && - (phy->type == B43legacy_PHYTYPE_B || - phy->type == B43legacy_PHYTYPE_G)); + turn_on = radio_enabled; break; case B43legacy_LED_MODE_BG: - if (phy->type == B43legacy_PHYTYPE_G && - b43legacy_is_hw_radio_enabled(dev)) + if (phy->type == B43legacy_PHYTYPE_G && radio_enabled) turn_on = 1; break; case B43legacy_LED_TRANSFER: diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 3e935d0d4b80..a793f183a2c0 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2007,6 +2007,21 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev, B43legacy_SHM_SH_PRPHYCTL, tmp); } +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +{ + if (dev->phy.rev >= 3) { + if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) + & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) + & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; + } + return 0; +} + /* This is the opposite of b43legacy_chip_init() */ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) { @@ -2046,9 +2061,6 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) if (err) goto err_gpio_cleanup; b43legacy_radio_turn_on(dev); - dev->radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); - b43legacyinfo(dev->wl, "Radio %s by hardware\n", - (dev->radio_hw_enable == 0) ? "disabled" : "enabled"); b43legacy_write16(dev, 0x03E6, 0x0000); err = b43legacy_phy_init(dev); @@ -2170,14 +2182,14 @@ static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev) static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) { - int radio_hw_enable; + bool radio_hw_enable; /* check if radio hardware enabled status changed */ radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { dev->radio_hw_enable = radio_hw_enable; b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n", - (radio_hw_enable == 0) ? "disabled" : "enabled"); + (radio_hw_enable) ? "enabled" : "disabled"); b43legacy_leds_update(dev, 0); } } @@ -2933,6 +2945,9 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, /* Flags */ phy->locked = 0; + /* Assume the radio is enabled. If it's not enabled, the state will + * immediately get fixed on the first periodic work run. */ + dev->radio_hw_enable = 1; phy->savedpctlreg = 0xFFFF; phy->aci_enable = 0; diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h index 673935e67e64..68435c50d8e0 100644 --- a/drivers/net/wireless/b43legacy/main.h +++ b/drivers/net/wireless/b43legacy/main.h @@ -97,26 +97,6 @@ int b43legacy_is_ofdm_rate(int rate) return !b43legacy_is_cck_rate(rate); } -static inline -int b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) -{ - /* function to return state of hardware enable of radio - * returns 0 if radio disabled, 1 if radio enabled - */ - struct b43legacy_phy *phy = &dev->phy; - - if (phy->rev >= 3) - return ((b43legacy_read32(dev, - B43legacy_MMIO_RADIO_HWENABLED_HI) - & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK) - == 0) ? 1 : 0; - else - return ((b43legacy_read16(dev, - B43legacy_MMIO_RADIO_HWENABLED_LO) - & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) - == 0) ? 0 : 1; -} - void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf); void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 54067f082825..a361dee664af 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -2134,7 +2134,7 @@ void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) } else b43legacy_phy_write(dev, 0x0015, 0xAA00); phy->radio_on = 0; - b43legacydbg(dev->wl, "Radio turned off\n"); + b43legacydbg(dev->wl, "Radio initialized\n"); b43legacy_leds_update(dev, 0); } From 6f05cbe5882e8b0fc5a984313cbb14ce7741411b Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Thu, 6 Sep 2007 21:30:32 -0400 Subject: [PATCH 1494/2804] [LIBERTAS]: set dnld_sent correctly for CF parts Corrects a minor bug with priv->dnld_sent being set incorrectly in if_cs_host_to_card. Signed-off-by: Ryan Mallon Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/if_cs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 09c87df5c2fd..364da4cac214 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -617,11 +617,12 @@ static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) switch (type) { case MVMS_DAT: - priv->dnld_sent = DNLD_CMD_SENT; + priv->dnld_sent = DNLD_DATA_SENT; if_cs_send_data(priv, buf, nb); ret = 0; break; case MVMS_CMD: + priv->dnld_sent = DNLD_CMD_SENT; ret = if_cs_send_cmd(priv, buf, nb); break; default: From 28de0b36be2a4e7fb0ba7c9a77d61aeb229b27c0 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Thu, 6 Sep 2007 21:32:42 -0400 Subject: [PATCH 1495/2804] [LIBERTAS]: fix interrupts in CF driver The following patch fixes the tx transmit timeout problem, which is caused by the interrupts being incorrectly check and masked. The patch moves the interrupt masking code so that interrupts are enabled only when the driver is registered and only disabled when the driver is unregistered. Signed-off-by: Ryan Mallon Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/if_cs.c | 33 +++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 364da4cac214..e74ec5c309be 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -248,22 +248,26 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) lbs_deb_enter(LBS_DEB_CS); int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); - switch (int_cause) { - case 0x0000: - /* not for us */ + if(int_cause == 0x0) { + /* Not for us */ return IRQ_NONE; - case 0xffff: - /* if one reads junk, then probably the card was removed */ + + } else if(int_cause == 0xffff) { + /* Read in junk, the card has probably been removed */ card->priv->adapter->surpriseremoved = 1; - break; - case IF_CS_H_IC_TX_OVER: - if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED) - netif_wake_queue(card->priv->dev); - /* fallthrought */ - default: + + } else { + if(int_cause & IF_CS_H_IC_TX_OVER) { + card->priv->dnld_sent = DNLD_RES_RECEIVED; + if (!card->priv->adapter->cur_cmd) + wake_up_interruptible(&card->priv->waitq); + + if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED) + netif_wake_queue(card->priv->dev); + } + /* clear interrupt */ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK); - if_cs_disable_ints(card); } libertas_interrupt(card->priv->dev); @@ -652,7 +656,6 @@ static int if_cs_get_int_status(wlan_private *priv, u8 *ireg) if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause); *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK; - if_cs_enable_ints(card); if (!*ireg) goto sbi_get_int_status_exit; @@ -841,7 +844,6 @@ 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); - if_cs_enable_ints(card); /* Load the firmware early, before calling into libertas.ko */ ret = if_cs_prog_helper(card); @@ -874,6 +876,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out3; } + if_cs_enable_ints(card); + /* And finally bring the card up */ if (libertas_start_card(priv) != 0) { lbs_pr_err("could not activate card\n"); @@ -909,6 +913,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) libertas_stop_card(card->priv); libertas_remove_card(card->priv); + if_cs_disable_ints(card); if_cs_release(p_dev); kfree(card); From f31ce76b781d15ab6b529663b95223f58171ec80 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Thu, 6 Sep 2007 21:41:02 -0400 Subject: [PATCH 1496/2804] [LIBERTAS]: fix oops on the blackfin architecture Reserve two bytes to align pointer to the IP header. Signed-off-by: Vladimir Davydov Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/if_cs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index e74ec5c309be..0360cad363a8 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -402,10 +402,12 @@ static struct sk_buff *if_cs_receive_data(wlan_private *priv) } //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN); - skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); + skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2); if (!skb) goto out; - data = skb_put(skb, len); + skb_put(skb, len); + skb_reserve(skb, 2);/* 16 byte align */ + data = skb->data; /* read even number of bytes, then odd byte if necessary */ if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16)); From ac630c2b1933e79ff32e3653ae656620cf4b4c79 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Thu, 6 Sep 2007 21:45:36 -0400 Subject: [PATCH 1497/2804] [LIBERTAS]: fix oops on the blackfin architecture Fixing memory alignment problems on the blackfin architecture (maybe on the ARM also) Signed-off-by: Vladimir Davydov Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/scan.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8f073ad1957f..fab93d8fe9c7 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -13,6 +13,8 @@ #include #include +#include + #include "host.h" #include "decl.h" #include "dev.h" @@ -888,7 +890,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ - beaconsize = le16_to_cpup((void *)*pbeaconinfo); + beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo)); *bytesleft -= sizeof(beaconsize); *pbeaconinfo += sizeof(beaconsize); } @@ -1698,10 +1700,10 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) goto done; } - bytesleft = le16_to_cpu(pscan->bssdescriptsize); + bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize)); lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); - scanrespsize = le16_to_cpu(resp->size); + scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size)); lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n", pscan->nr_sets); From 72abd81b980ef7ffb83ecb4ac4a7627d9d575f50 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Sep 2007 01:29:22 -0400 Subject: [PATCH 1498/2804] [MAC80211]: allow drivers to indicate failed FCS/PLCP checksum This patch allows drivers to indicate bad FCS/PLCP CRC to the stack and have the stack drop packets like that except for monitor interfaces. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 6 ++++++ net/mac80211/rx.c | 32 +++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 947f3c820e42..7d9dc20ee42f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -235,6 +235,10 @@ struct ieee80211_tx_control { * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. * If this flag is set, the stack cannot do any replay detection * hence the driver or hardware will have to do that. + * @RX_FLAG_FAILED_FCS_CRC: Set this flag if the FCS check failed on + * the frame. + * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on + * the frame. */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -242,6 +246,8 @@ enum mac80211_rx_flags { RX_FLAG_RADIOTAP = 1<<2, RX_FLAG_MMIC_STRIPPED = 1<<3, RX_FLAG_IV_STRIPPED = 1<<4, + RX_FLAG_FAILED_FCS_CRC = 1<<5, + RX_FLAG_FAILED_PLCP_CRC = 1<<6, }; /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e9dcc6229c3c..cf2a72f89d68 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -145,6 +145,8 @@ ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, __le16 chan_freq; __le16 chan_flags; u8 antsignal; + u8 padding_for_rxflags; + __le16 rx_flags; } __attribute__ ((packed)) *rthdr; skb->dev = dev; @@ -167,12 +169,21 @@ ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)); + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_RX_FLAGS)); rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? IEEE80211_RADIOTAP_F_FCS : 0; + + /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ + rthdr->rx_flags = 0; + if (status->flag & + (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) + rthdr->rx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); + rate = ieee80211_get_rate(local, status->phymode, status->rate); if (rate) rthdr->rate = rate->rate / 5; + rthdr->chan_freq = cpu_to_le16(status->freq); rthdr->chan_flags = status->phymode == MODE_IEEE80211A ? @@ -200,6 +211,15 @@ ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx) return TXRX_QUEUED; } + /* + * Drop frames with failed FCS/PLCP checksums here, they are only + * relevant for monitor mode, the rest of the stack should never + * see them. + */ + if (rx->u.rx.status->flag & + (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) + return TXRX_DROP; + if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP) skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb->data)); @@ -1360,6 +1380,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; u8 *bssid; + int bogon; if (status->flag & RX_FLAG_RADIOTAP) { radiotap_len = ieee80211_get_radiotap_len(skb->data); @@ -1380,10 +1401,15 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, rx.u.rx.status = status; rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0; type = rx.fc & IEEE80211_FCTL_FTYPE; - if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) + + bogon = status->flag & (RX_FLAG_FAILED_FCS_CRC | + RX_FLAG_FAILED_PLCP_CRC); + + if (!bogon && (type == IEEE80211_FTYPE_DATA || + type == IEEE80211_FTYPE_MGMT)) local->dot11ReceivedFragmentCount++; - if (skb->len >= 16) { + if (!bogon && skb->len >= 16) { sta = rx.sta = sta_info_get(local, hdr->addr2); if (sta) { rx.dev = rx.sta->dev; From 011bfcc4f3d3444b140da3880ae30a62cc93529e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Sep 2007 01:29:25 -0400 Subject: [PATCH 1499/2804] [MAC80211]: remove key threshold stuff This patch removes the key threshold stuff from mac80211. I have patches for later that add it as a per-key setting to nl/cfg80211. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/debugfs.c | 4 ---- net/mac80211/hostapd_ioctl.h | 1 - net/mac80211/ieee80211.c | 35 --------------------------------- net/mac80211/ieee80211_common.h | 2 +- net/mac80211/ieee80211_i.h | 7 ------- net/mac80211/ieee80211_ioctl.c | 8 -------- net/mac80211/rx.c | 7 +------ net/mac80211/tx.c | 7 +------ 8 files changed, 3 insertions(+), 68 deletions(-) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 12db9adc0361..60514b2c97b9 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -90,8 +90,6 @@ DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", local->hw.conf.antenna_sel_rx); DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d", local->bridge_packets); -DEBUGFS_READONLY_FILE(key_tx_rx_threshold, 20, "%d", - local->key_tx_rx_threshold); DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", local->rts_threshold); DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", @@ -301,7 +299,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(antenna_sel_tx); DEBUGFS_ADD(antenna_sel_rx); DEBUGFS_ADD(bridge_packets); - DEBUGFS_ADD(key_tx_rx_threshold); DEBUGFS_ADD(rts_threshold); DEBUGFS_ADD(fragmentation_threshold); DEBUGFS_ADD(short_retry_limit); @@ -364,7 +361,6 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_DEL(antenna_sel_tx); DEBUGFS_DEL(antenna_sel_rx); DEBUGFS_DEL(bridge_packets); - DEBUGFS_DEL(key_tx_rx_threshold); DEBUGFS_DEL(rts_threshold); DEBUGFS_DEL(fragmentation_threshold); DEBUGFS_DEL(short_retry_limit); diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h index ac812ec9fa2f..2300c5516458 100644 --- a/net/mac80211/hostapd_ioctl.h +++ b/net/mac80211/hostapd_ioctl.h @@ -32,7 +32,6 @@ enum { PRISM2_PARAM_PREAMBLE = 1003, PRISM2_PARAM_SHORT_SLOT_TIME = 1006, PRISM2_PARAM_NEXT_MODE = 1008, - PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024, PRISM2_PARAM_WIFI_WME_NOACK_TEST = 1033, PRISM2_PARAM_SCAN_FLAGS = 1035, PRISM2_PARAM_HW_MODES = 1036, diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 23853331e8db..5e924588e9a2 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -189,41 +189,6 @@ ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, netif_rx(skb); } -void ieee80211_key_threshold_notify(struct net_device *dev, - struct ieee80211_key *key, - struct sta_info *sta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - struct ieee80211_msg_key_notification *msg; - - /* if no one will get it anyway, don't even allocate it. - * unlikely because this is only relevant for APs - * where the device must be open... */ - if (unlikely(!local->apdev)) - return; - - skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + - sizeof(struct ieee80211_msg_key_notification)); - if (!skb) - return; - - skb_reserve(skb, sizeof(struct ieee80211_frame_info)); - msg = (struct ieee80211_msg_key_notification *) - skb_put(skb, sizeof(struct ieee80211_msg_key_notification)); - msg->tx_rx_count = key->tx_rx_count; - memcpy(msg->ifname, dev->name, IFNAMSIZ); - if (sta) - memcpy(msg->addr, sta->addr, ETH_ALEN); - else - memset(msg->addr, 0xff, ETH_ALEN); - - key->tx_rx_count = 0; - - ieee80211_rx_mgmt(local, skb, NULL, - ieee80211_msg_key_threshold_notification); -} - static int ieee80211_mgmt_open(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h index 5b5fb7bcfd72..c15295d43d87 100644 --- a/net/mac80211/ieee80211_common.h +++ b/net/mac80211/ieee80211_common.h @@ -53,7 +53,7 @@ enum ieee80211_msg_type { /* hole at 6, was monitor but never sent to userspace */ ieee80211_msg_sta_not_assoc = 7, /* 8 was ieee80211_msg_set_aid_for_sta */ - ieee80211_msg_key_threshold_notification = 9, + /* 9 was ieee80211_msg_key_threshold_notification */ /* 11 was ieee80211_msg_radar */ }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 14e8c366af3d..c3f6f89755b1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -465,9 +465,6 @@ struct ieee80211_local { struct crypto_blkcipher *wep_tx_tfm; struct crypto_blkcipher *wep_rx_tfm; u32 wep_iv; - int key_tx_rx_threshold; /* number of times any key can be used in TX - * or RX before generating a rekey - * notification; 0 = notification disabled. */ int bridge_packets; /* bridge packets between associated stations and * deliver multicast frames both back to wireless @@ -573,7 +570,6 @@ struct ieee80211_local { struct dentry *antenna_sel_tx; struct dentry *antenna_sel_rx; struct dentry *bridge_packets; - struct dentry *key_tx_rx_threshold; struct dentry *rts_threshold; struct dentry *fragmentation_threshold; struct dentry *short_retry_limit; @@ -724,9 +720,6 @@ void ieee80211_if_setup(struct net_device *dev); void ieee80211_if_mgmt_setup(struct net_device *dev); struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hwrate); -void ieee80211_key_threshold_notify(struct net_device *dev, - struct ieee80211_key *key, - struct sta_info *sta); /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index b4cce441d7e6..99023d0d7edc 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -912,10 +912,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, local->next_mode = hostapd_mode_to_mode(value); break; - case PRISM2_PARAM_KEY_TX_RX_THRESHOLD: - local->key_tx_rx_threshold = value; - break; - case PRISM2_PARAM_WIFI_WME_NOACK_TEST: local->wifi_wme_noack_test = value; break; @@ -1011,10 +1007,6 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, *param = local->next_mode; break; - case PRISM2_PARAM_KEY_TX_RX_THRESHOLD: - *param = local->key_tx_rx_threshold; - break; - case PRISM2_PARAM_WIFI_WME_NOACK_TEST: *param = local->wifi_wme_noack_test; break; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cf2a72f89d68..9700c1c5b3cf 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -409,12 +409,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) if (rx->key) { rx->key->tx_rx_count++; - if (unlikely(rx->local->key_tx_rx_threshold && - rx->key->tx_rx_count > - rx->local->key_tx_rx_threshold)) { - ieee80211_key_threshold_notify(rx->dev, rx->key, - rx->sta); - } + /* TODO: add threshold stuff again */ } return TXRX_CONTINUE; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 04b4fa9c69ea..e33f7641e6b4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -451,12 +451,7 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) if (tx->key) { tx->key->tx_rx_count++; - if (unlikely(tx->local->key_tx_rx_threshold && - tx->key->tx_rx_count > - tx->local->key_tx_rx_threshold)) { - ieee80211_key_threshold_notify(tx->dev, tx->key, - tx->sta); - } + /* TODO: add threshold stuff again */ } return TXRX_CONTINUE; From c33e3f3bcd2b63b735c5b1028f3cfd1048c300c2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Sep 2007 01:29:26 -0400 Subject: [PATCH 1500/2804] [MAC80211]: remove IEEE80211_CONF_SSID_HIDDEN The IEEE80211_CONF_SSID_HIDDEN setting is not useful for any driver we have and should be a per-interface setting anyway. Remove it. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7d9dc20ee42f..7a2463f39cfd 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -322,8 +322,7 @@ struct ieee80211_conf { #define IEEE80211_CONF_SHORT_SLOT_TIME (1<<0) /* use IEEE 802.11g Short Slot * Time */ -#define IEEE80211_CONF_SSID_HIDDEN (1<<1) /* do not broadcast the ssid */ -#define IEEE80211_CONF_RADIOTAP (1<<2) /* use radiotap if supported +#define IEEE80211_CONF_RADIOTAP (1<<1) /* use radiotap if supported check this bit at RX time */ u32 flags; /* configuration flags defined above */ From 6b301cdfad96daa3cf4f0d775ab408f898308890 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:20 -0400 Subject: [PATCH 1501/2804] [MAC80211]: yet more documentation Add more mac80211 documentation. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 198 +++++++++++++++++++++++++++++++---------- 1 file changed, 149 insertions(+), 49 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7a2463f39cfd..f0e19f9df2a7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -98,42 +98,96 @@ struct ieee80211_rate { * optimizing channel utilization estimates */ }; -/* 802.11g is backwards-compatible with 802.11b, so a wlan card can - * actually be both in 11b and 11g modes at the same time. */ +/** + * enum ieee80211_phymode - PHY modes + * + * @MODE_IEEE80211A: 5GHz as defined by 802.11a/802.11h + * @MODE_IEEE80211B: 2.4 GHz as defined by 802.11b + * @MODE_IEEE80211G: 2.4 GHz as defined by 802.11g (with OFDM), + * backwards compatible with 11b mode + * @NUM_IEEE80211_MODES: internal + */ enum ieee80211_phymode { - MODE_IEEE80211A, /* IEEE 802.11a */ - MODE_IEEE80211B, /* IEEE 802.11b only */ - MODE_IEEE80211G, /* IEEE 802.11g (and 802.11b compatibility) */ + MODE_IEEE80211A, + MODE_IEEE80211B, + MODE_IEEE80211G, /* keep last */ NUM_IEEE80211_MODES }; +/** + * struct ieee80211_hw_mode - PHY mode definition + * + * This structure describes the capabilities supported by the device + * in a single PHY mode. + * + * @mode: the PHY mode for this definition + * @num_channels: number of supported channels + * @channels: pointer to array of supported channels + * @num_rates: number of supported bitrates + * @rates: pointer to array of supported bitrates + * @list: internal + */ struct ieee80211_hw_mode { - int mode; /* MODE_IEEE80211... */ - int num_channels; /* Number of channels (below) */ - struct ieee80211_channel *channels; /* Array of supported channels */ - int num_rates; /* Number of rates (below) */ - struct ieee80211_rate *rates; /* Array of supported rates */ - - struct list_head list; /* Internal, don't touch */ + struct list_head list; + struct ieee80211_channel *channels; + struct ieee80211_rate *rates; + enum ieee80211_phymode mode; + int num_channels; + int num_rates; }; +/** + * struct ieee80211_tx_queue_params - transmit queue configuration + * + * The information provided in this structure is required for QoS + * transmit queue configuration. + * + * @aifs: arbitration interface space [0..255, -1: use default] + * @cw_min: minimum contention window [will be a value of the form + * 2^n-1 in the range 1..1023; 0: use default] + * @cw_max: maximum contention window [like @cw_min] + * @burst_time: maximum burst time in units of 0.1ms, 0 meaning disabled + */ struct ieee80211_tx_queue_params { - int aifs; /* 0 .. 255; -1 = use default */ - int cw_min; /* 2^n-1: 1, 3, 7, .. , 1023; 0 = use default */ - int cw_max; /* 2^n-1: 1, 3, 7, .. , 1023; 0 = use default */ - int burst_time; /* maximum burst time in 0.1 ms (i.e., 10 = 1 ms); - * 0 = disabled */ + int aifs; + int cw_min; + int cw_max; + int burst_time; }; +/** + * struct ieee80211_tx_queue_stats_data - transmit queue statistics + * + * @len: number of packets in queue + * @limit: queue length limit + * @count: number of frames sent + */ struct ieee80211_tx_queue_stats_data { - unsigned int len; /* num packets in queue */ - unsigned int limit; /* queue len (soft) limit */ - unsigned int count; /* total num frames sent */ + unsigned int len; + unsigned int limit; + unsigned int count; }; -enum { +/** + * enum ieee80211_tx_queue - transmit queue number + * + * These constants are used with some callbacks that take a + * queue number to set parameters for a queue. + * + * @IEEE80211_TX_QUEUE_DATA0: data queue 0 + * @IEEE80211_TX_QUEUE_DATA1: data queue 1 + * @IEEE80211_TX_QUEUE_DATA2: data queue 2 + * @IEEE80211_TX_QUEUE_DATA3: data queue 3 + * @IEEE80211_TX_QUEUE_DATA4: data queue 4 + * @IEEE80211_TX_QUEUE_SVP: ?? + * @NUM_TX_DATA_QUEUES: number of data queues + * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be + * sent after a beacon + * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames + */ +enum ieee80211_tx_queue { IEEE80211_TX_QUEUE_DATA0, IEEE80211_TX_QUEUE_DATA1, IEEE80211_TX_QUEUE_DATA2, @@ -271,7 +325,7 @@ struct ieee80211_rx_status { u64 mactime; int freq; int channel; - int phymode; + enum ieee80211_phymode phymode; int ssi; int signal; int noise; @@ -280,25 +334,65 @@ struct ieee80211_rx_status { int flag; }; -/* Transmit status. The low-level driver should provide this information - * (the subset supported by hardware) to the 802.11 code for each transmit - * frame. */ +/** + * enum ieee80211_tx_status_flags - transmit status flags + * + * Status flags to indicate various transmit conditions. + * + * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted + * because the destination STA was in powersave mode. + * + * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged + */ +enum ieee80211_tx_status_flags { + IEEE80211_TX_STATUS_TX_FILTERED = 1<<0, + IEEE80211_TX_STATUS_ACK = 1<<1, +}; + +/** + * struct ieee80211_tx_status - transmit status + * + * As much information as possible should be provided for each transmitted + * frame with ieee80211_tx_status(). + * + * @control: a copy of the &struct ieee80211_tx_control passed to the driver + * in the tx() callback. + * + * @flags: transmit status flags, defined above + * + * @ack_signal: signal strength of the ACK frame + * + * @excessive_retries: set to 1 if the frame was retried many times + * but not acknowledged + * + * @retry_count: number of retries + * + * @queue_length: ?? REMOVE + * @queue_number: ?? REMOVE + */ struct ieee80211_tx_status { - /* copied ieee80211_tx_control structure */ struct ieee80211_tx_control control; - -#define IEEE80211_TX_STATUS_TX_FILTERED (1<<0) -#define IEEE80211_TX_STATUS_ACK (1<<1) /* whether the TX frame was ACKed */ - u32 flags; /* tx staus flags defined above */ - - int ack_signal; /* measured signal strength of the ACK frame */ - int excessive_retries; - int retry_count; - - int queue_length; /* information about TX queue */ + u8 flags; + bool excessive_retries; + u8 retry_count; + int ack_signal; + int queue_length; int queue_number; }; +/** + * enum ieee80211_conf_flags - configuration flags + * + * Flags to define PHY configuration options + * + * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time + * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) + * + */ +enum ieee80211_conf_flags { + IEEE80211_CONF_SHORT_SLOT_TIME = 1<<0, + IEEE80211_CONF_RADIOTAP = 1<<1, +}; /** * struct ieee80211_conf - configuration of the device @@ -306,31 +400,37 @@ struct ieee80211_tx_status { * This struct indicates how the driver shall configure the hardware. * * @radio_enabled: when zero, driver is required to switch off the radio. + * TODO make a flag + * @channel: IEEE 802.11 channel number + * @freq: frequency in MHz + * @channel_val: hardware specific channel value for the channel + * @phymode: PHY mode to activate (REMOVE) + * @chan: channel to switch to, pointer to the channel information + * @mode: pointer to mode definition + * @regulatory_domain: ?? + * @beacon_int: beacon interval (TODO make interface config) + * @flags: configuration flags defined above + * @power_level: transmit power limit for current regulatory domain in dBm + * @antenna_max: maximum antenna gain + * @antenna_sel_tx: transmit antenna selection, 0: default/diversity, + * 1/2: antenna 0/1 + * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx */ struct ieee80211_conf { int channel; /* IEEE 802.11 channel number */ int freq; /* MHz */ int channel_val; /* hw specific value for the channel */ - int phymode; /* MODE_IEEE80211A, .. */ + enum ieee80211_phymode phymode; struct ieee80211_channel *chan; struct ieee80211_hw_mode *mode; unsigned int regulatory_domain; int radio_enabled; int beacon_int; - -#define IEEE80211_CONF_SHORT_SLOT_TIME (1<<0) /* use IEEE 802.11g Short Slot - * Time */ -#define IEEE80211_CONF_RADIOTAP (1<<1) /* use radiotap if supported - check this bit at RX time */ - u32 flags; /* configuration flags defined above */ - - u8 power_level; /* transmit power limit for current - * regulatory domain; in dBm */ - u8 antenna_max; /* maximum antenna gain */ - - /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ + u32 flags; + u8 power_level; + u8 antenna_max; u8 antenna_sel_tx; u8 antenna_sel_rx; }; From 693d454dffd43b2bab021d0e039a0c426181c1b0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:20 -0400 Subject: [PATCH 1502/2804] [MAC80211]: fix warnings introduced by the doc patches This fixes a warning about NUM_IEEE80211_MODES missing in a switch statement. Intentionally do not add a default case so we get warnings at these places if we need to add new modes. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 29c0a0e1f52c..5a0564e1dbd6 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -98,6 +98,9 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, rate->rate == 55 || rate->rate == 110) rate->flags |= IEEE80211_RATE_BASIC; break; + case NUM_IEEE80211_MODES: + /* not useful */ + break; } /* Set ERP and MANDATORY flags based on phymode */ @@ -118,6 +121,9 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, rate->rate == 240) rate->flags |= IEEE80211_RATE_MANDATORY; break; + case NUM_IEEE80211_MODES: + /* not useful */ + break; } if (ieee80211_is_erp_rate(mode->mode, rate->rate)) rate->flags |= IEEE80211_RATE_ERP; From 9c7d7728baf79c63ae58df95fb39ea13db487599 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:20 -0400 Subject: [PATCH 1503/2804] [MAC80211]: remove tx info sw_retry_attempt member This is unused. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f0e19f9df2a7..5ff45553a985 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -260,9 +260,6 @@ struct ieee80211_tx_control { u8 iv_len; /* length of the IV field in octets */ u8 queue; /* hardware queue to use for this frame; * 0 = highest, hw->queues-1 = lowest */ - u8 sw_retry_attempt; /* number of times hw has tried to - * transmit frame (not incl. hw retries) */ - struct ieee80211_rate *rate; /* internal 80211.o rate */ struct ieee80211_rate *rts_rate; /* internal 80211.o rate * for RTS/CTS */ From dd1cd4c620c174ebbdf78dc01b924115a06de5d3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:20 -0400 Subject: [PATCH 1504/2804] [MAC80211]: print out wiphy name instead of master device This makes mac80211 print out the wiphy name instead of the master device name where appropriate. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211.c | 14 +++++++------- net/mac80211/ieee80211_rate.c | 4 ++-- net/mac80211/ieee80211_sta.c | 2 +- net/mac80211/rx.c | 3 ++- net/mac80211/sta_info.c | 4 ++-- net/mac80211/tx.c | 9 +++++---- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 5e924588e9a2..4a213a20373a 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -814,7 +814,7 @@ static void ieee80211_tasklet_handler(unsigned long data) break; default: /* should never get here! */ printk(KERN_ERR "%s: Unknown message type (%d)\n", - local->mdev->name, skb->pkt_type); + wiphy_name(local->hw.wiphy), skb->pkt_type); dev_kfree_skb(skb); break; } @@ -904,7 +904,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, if (!status) { printk(KERN_ERR "%s: ieee80211_tx_status called with NULL status\n", - local->mdev->name); + wiphy_name(local->hw.wiphy)); dev_kfree_skb(skb); return; } @@ -961,7 +961,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, printk(KERN_DEBUG "%s: dropped TX " "filtered frame queue_len=%d " "PS=%d @%lu\n", - local->mdev->name, + wiphy_name(local->hw.wiphy), skb_queue_len( &sta->tx_filtered), !!(sta->flags & WLAN_STA_PS), @@ -1282,7 +1282,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) result = ieee80211_init_rate_ctrl_alg(local, NULL); if (result < 0) { printk(KERN_DEBUG "%s: Failed to initialize rate control " - "algorithm\n", local->mdev->name); + "algorithm\n", wiphy_name(local->hw.wiphy)); goto fail_rate; } @@ -1290,7 +1290,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (result < 0) { printk(KERN_DEBUG "%s: Failed to initialize wep\n", - local->mdev->name); + wiphy_name(local->hw.wiphy)); goto fail_wep; } @@ -1301,7 +1301,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) IEEE80211_IF_TYPE_STA); if (result) printk(KERN_WARNING "%s: Failed to add default virtual iface\n", - local->mdev->name); + wiphy_name(local->hw.wiphy)); local->reg_state = IEEE80211_DEV_REGISTERED; rtnl_unlock(); @@ -1401,7 +1401,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) printk(KERN_WARNING "%s: skb_queue not empty\n", - local->mdev->name); + wiphy_name(local->hw.wiphy)); skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index a1ded7449784..91a9fe2cbad9 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c @@ -152,7 +152,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, ref = rate_control_alloc(name, local); if (!ref) { printk(KERN_WARNING "%s: Failed to select rate control " - "algorithm\n", local->mdev->name); + "algorithm\n", wiphy_name(local->hw.wiphy)); return -ENOENT; } @@ -164,7 +164,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, } printk(KERN_DEBUG "%s: Selected rate control " - "algorithm '%s'\n", local->mdev->name, + "algorithm '%s'\n", wiphy_name(local->hw.wiphy), ref->ops->name); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index f47cbd294ceb..8a4f2441b59c 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -3104,7 +3104,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, } printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", - local->mdev->name, print_mac(mac, addr), dev->name); + wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); sta = sta_info_add(local, dev, addr, GFP_ATOMIC); if (!sta) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9700c1c5b3cf..b5f2e4c25c7e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1474,7 +1474,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, if (net_ratelimit()) printk(KERN_DEBUG "%s: failed to copy " "multicast frame for %s", - local->mdev->name, prev->dev->name); + wiphy_name(local->hw.wiphy), + prev->dev->name); continue; } rx.skb = skb_new; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 44d983404952..7c7df87f673c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -166,7 +166,7 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Added STA %s\n", - local->mdev->name, print_mac(mac, addr)); + wiphy_name(local->hw.wiphy), print_mac(mac, addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_DEBUGFS @@ -226,7 +226,7 @@ void sta_info_free(struct sta_info *sta) #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Removed STA %s\n", - local->mdev->name, print_mac(mac, sta->addr)); + wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ ieee80211_key_free(sta->key); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e33f7641e6b4..38394c40f6ad 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -324,7 +324,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) local->total_ps_buffered = total; printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", - local->mdev->name, purged); + wiphy_name(local->hw.wiphy), purged); } static inline ieee80211_txrx_result @@ -1049,7 +1049,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, return IEEE80211_TX_AGAIN; } if (skb) { - ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb); + ieee80211_dump_frame(wiphy_name(local->hw.wiphy), + "TX to low-level driver", skb); ret = local->ops->tx(local_to_hw(local), skb, control); if (ret) return IEEE80211_TX_AGAIN; @@ -1077,7 +1078,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } - ieee80211_dump_frame(local->mdev->name, + ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", tx->u.tx.extra_frag[i]); ret = local->ops->tx(local_to_hw(local), @@ -1799,7 +1800,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, if (!rate) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate " - "found\n", local->mdev->name); + "found\n", wiphy_name(local->hw.wiphy)); } dev_kfree_skb(skb); return NULL; From fa5fea711f4c3bd71f00181d6f385ef4d53ab375 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:20 -0400 Subject: [PATCH 1505/2804] [MAC80211]: rename ieee80211_cfg.c to cfg.c It's just painful to have the extra ieee80211_ prefix. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/Makefile | 2 +- net/mac80211/{ieee80211_cfg.c => cfg.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename net/mac80211/{ieee80211_cfg.c => cfg.c} (100%) diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 793733835628..219cd9f9341f 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -17,7 +17,7 @@ mac80211-objs := \ regdomain.o \ tkip.o \ aes_ccm.o \ - ieee80211_cfg.o \ + cfg.o \ rx.o \ tx.o \ key.o \ diff --git a/net/mac80211/ieee80211_cfg.c b/net/mac80211/cfg.c similarity index 100% rename from net/mac80211/ieee80211_cfg.c rename to net/mac80211/cfg.c From c095df531f3ab9699b031e220c0da76d6407b157 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:21 -0400 Subject: [PATCH 1506/2804] [MAC80211]: kill IE parse typedef The parse result typedef isn't needed. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211_sta.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 8a4f2441b59c..3f0a2faf37d4 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -108,11 +108,10 @@ struct ieee802_11_elems { u8 wmm_param_len; }; -typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; +enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 }; - -static ParseRes ieee802_11_parse_elems(u8 *start, size_t len, - struct ieee802_11_elems *elems) +static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len, + struct ieee802_11_elems *elems) { size_t left = len; u8 *pos = start; From d86ec781ef9627a3fcd64a7a91d1b79a74d3927b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:21 -0400 Subject: [PATCH 1507/2804] [MAC80211]: kill vlan_id Each station has a vlan_id that is useless. Remove it. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/debugfs_sta.c | 1 - net/mac80211/sta_info.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index f7c717c906dc..8f5944c53d4e 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -61,7 +61,6 @@ static const struct file_operations sta_ ##name## _ops = { \ STA_FILE(aid, aid, D); STA_FILE(dev, dev->name, S); -STA_FILE(vlan_id, vlan_id, D); STA_FILE(rx_packets, rx_packets, LU); STA_FILE(tx_packets, tx_packets, LU); STA_FILE(rx_bytes, rx_bytes, LU); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index e3ae0f5cc228..8f7ebe41c024 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -97,8 +97,6 @@ struct sta_info { unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ - int vlan_id; - u16 listen_interval; #ifdef CONFIG_MAC80211_DEBUGFS From e0eb68596232788bc352368f2fbc3cb088e42e41 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Tue, 18 Sep 2007 17:29:21 -0400 Subject: [PATCH 1508/2804] [MAC80211]: rename ieee80211_cfg.h to cfg.h Might as well rename ieee80211_cfg.h to cfg.h to keep things consistent. Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/cfg.c | 2 +- net/mac80211/{ieee80211_cfg.h => cfg.h} | 6 +++--- net/mac80211/ieee80211.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename net/mac80211/{ieee80211_cfg.h => cfg.h} (55%) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d6fc55cc8ad4..6981ba178e19 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -11,7 +11,7 @@ #include #include #include "ieee80211_i.h" -#include "ieee80211_cfg.h" +#include "cfg.h" static int ieee80211_add_iface(struct wiphy *wiphy, char *name, enum nl80211_iftype type) diff --git a/net/mac80211/ieee80211_cfg.h b/net/mac80211/cfg.h similarity index 55% rename from net/mac80211/ieee80211_cfg.h rename to net/mac80211/cfg.h index 85ed2c924878..7d7879f5b00b 100644 --- a/net/mac80211/ieee80211_cfg.h +++ b/net/mac80211/cfg.h @@ -1,9 +1,9 @@ /* * mac80211 configuration hooks for cfg80211 */ -#ifndef __IEEE80211_CFG_H -#define __IEEE80211_CFG_H +#ifndef __CFG_H +#define __CFG_H extern struct cfg80211_ops mac80211_config_ops; -#endif /* __IEEE80211_CFG_H */ +#endif /* __CFG_H */ diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 4a213a20373a..89be6629cfc0 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -31,7 +31,7 @@ #include "wme.h" #include "aes_ccm.h" #include "ieee80211_led.h" -#include "ieee80211_cfg.h" +#include "cfg.h" #include "debugfs.h" #include "debugfs_netdev.h" From aa97efd97acefb7d3dcd864adb878c7ce34061b3 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 25 Sep 2007 22:39:16 -0700 Subject: [PATCH 1509/2804] [DCCP]: Reuse ktime_get_real() calls again This patch reduces the number of timestamps taken in the receive path for each packet. The ccid3_hc_tx_update_x() routine is called in * the receive path for each CCID3-controlled packet * for the nofeedback timer (if no feedback arrives during 4 RTT) Currently, when there is no loss, each packet gets timestamped twice. The patch resolves this by recycling the first timestamp taken on packet reception for RTT sampling. When the no_feedback_timer() is called, then the timestamp argument is simply set to NULL - so that ccid3_hc_tx_update_x() takes care of the logic. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index e75efe72da2b..e16f9bb9eaaf 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -113,27 +113,24 @@ static inline void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hctx) hctx->ccid3hctx_s, (unsigned)(hctx->ccid3hctx_x >> 6)); } -/* - * Update X by - * If (p > 0) - * X_calc = calcX(s, R, p); - * X = max(min(X_calc, 2 * X_recv), s / t_mbi); - * Else - * If (now - tld >= R) - * X = max(min(2 * X, 2 * X_recv), s / R); - * tld = now; + +/** + * ccid3_hc_tx_update_x - Update allowed sending rate X + * @stamp: most recent time if available - can be left NULL. + * This function tracks draft rfc3448bis, check there for latest details. * * Note: X and X_recv are both stored in units of 64 * bytes/second, to support * fine-grained resolution of sending rates. This requires scaling by 2^6 * throughout the code. Only X_calc is unscaled (in bytes/second). * */ -static void ccid3_hc_tx_update_x(struct sock *sk) +static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp) { struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); __u64 min_rate = 2 * hctx->ccid3hctx_x_recv; const __u64 old_x = hctx->ccid3hctx_x; + ktime_t now = stamp? *stamp : ktime_get_real(); /* * Handle IDLE periods: do not reduce below RFC3390 initial sending rate @@ -153,18 +150,14 @@ static void ccid3_hc_tx_update_x(struct sock *sk) (((__u64)hctx->ccid3hctx_s) << 6) / TFRC_T_MBI); - } else { - const ktime_t now = ktime_get_real(); + } else if (ktime_us_delta(now, hctx->ccid3hctx_t_ld) + - (s64)hctx->ccid3hctx_rtt >= 0) { - if ((ktime_us_delta(now, hctx->ccid3hctx_t_ld) - - (s64)hctx->ccid3hctx_rtt) >= 0) { - - hctx->ccid3hctx_x = - max(min(2 * hctx->ccid3hctx_x, min_rate), - scaled_div(((__u64)hctx->ccid3hctx_s) << 6, - hctx->ccid3hctx_rtt)); - hctx->ccid3hctx_t_ld = now; - } + hctx->ccid3hctx_x = + max(min(2 * hctx->ccid3hctx_x, min_rate), + scaled_div(((__u64)hctx->ccid3hctx_s) << 6, + hctx->ccid3hctx_rtt)); + hctx->ccid3hctx_t_ld = now; } if (hctx->ccid3hctx_x != old_x) { @@ -273,7 +266,7 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) hctx->ccid3hctx_x_recv <<= 4; } /* Now recalculate X [RFC 3448, 4.3, step (4)] */ - ccid3_hc_tx_update_x(sk); + ccid3_hc_tx_update_x(sk, NULL); /* * Schedule no feedback timer to expire in * max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi) @@ -493,7 +486,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) tfrc_calc_x(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt, hctx->ccid3hctx_p); - ccid3_hc_tx_update_x(sk); + ccid3_hc_tx_update_x(sk, &now); ccid3_pr_debug("%s(%p), RTT=%uus (sample=%uus), s=%u, " "p=%u, X_calc=%u, X_recv=%u, X=%u\n", From 4c70f383e0c0273c4092c4efdb414be0966978b7 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 25 Sep 2007 22:40:13 -0700 Subject: [PATCH 1510/2804] [DCCP]: Provide 10s of microsecond timesource This provides a timesource, conveniently used for DCCP timestamps, which returns the elapsed time in 10s of microseconds since initialisation. This makes for a wrap-around time of about 11.9 hours, which should be sufficient for most applications. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/dccp.h | 2 ++ net/dccp/options.c | 2 +- net/dccp/proto.c | 2 ++ net/dccp/timer.c | 21 +++++++++++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index ddacc23be5e8..a75c740ae6c0 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -396,6 +396,8 @@ extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); extern int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb, u32 elapsed_time); +extern u32 dccp_timestamp(void); +extern void dccp_timestamping_init(void); extern int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb); extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb, diff --git a/net/dccp/options.c b/net/dccp/options.c index 167415677a75..a57fcbd7d03c 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -372,7 +372,7 @@ EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) { - __be32 now = htonl(((suseconds_t)ktime_to_us(ktime_get_real())) / 10); + __be32 now = htonl(dccp_timestamp()); /* yes this will overflow but that is the point as we want a * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 8d545da35262..14ec1d21452c 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -1076,6 +1076,8 @@ static int __init dccp_init(void) rc = dccp_sysctl_init(); if (rc) goto out_ackvec_exit; + + dccp_timestamping_init(); out: return rc; out_ackvec_exit: diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 0197a41c256a..3af067354bd4 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -291,3 +291,24 @@ void dccp_init_xmit_timers(struct sock *sk) inet_csk_init_xmit_timers(sk, &dccp_write_timer, &dccp_delack_timer, &dccp_keepalive_timer); } + +static ktime_t dccp_timestamp_seed; +/** + * dccp_timestamp - 10s of microseconds time source + * Returns the number of 10s of microseconds since loading DCCP. This is native + * DCCP time difference format (RFC 4340, sec. 13). + * Please note: This will wrap around about circa every 11.9 hours. + */ +u32 dccp_timestamp(void) +{ + s64 delta = ktime_us_delta(ktime_get_real(), dccp_timestamp_seed); + + do_div(delta, 10); + return delta; +} +EXPORT_SYMBOL_GPL(dccp_timestamp); + +void __init dccp_timestamping_init(void) +{ + dccp_timestamp_seed = ktime_get_real(); +} From 3393da8241ae3a53e183ba15f8bd822995ec97cd Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 25 Sep 2007 22:40:44 -0700 Subject: [PATCH 1511/2804] [DCCP]: Simplify interface of dccp_sample_rtt The third parameter of dccp_sample_rtt now becomes useless and is removed. Also combined the subtraction of the timestamp echo and the elapsed time. This is safe, since (a) presence of timestamp echo is tested first and (b) elapsed time is either present and non-zero or it is not set and equals 0 due to the memset in dccp_parse_options. To avoid measuring option-processing time, the timestamp for measuring the initial Request/Response RTT sample is taken directly when the function is called (the Linux implementation always adds a timestamp on the Request, so there is no loss in doing this). Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 6 +++--- net/dccp/dccp.h | 3 +-- net/dccp/input.c | 44 ++++++++++++++---------------------------- 3 files changed, 19 insertions(+), 34 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index e16f9bb9eaaf..0bb338be9dd7 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -448,7 +448,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) * Calculate new round trip sample as per [RFC 3448, 4.3] by * R_sample = (now - t_recvdata) - t_elapsed */ - r_sample = dccp_sample_rtt(sk, now, &packet->dccphtx_tstamp); + r_sample = dccp_sample_rtt(sk, ktime_us_delta(now, packet->dccphtx_tstamp)); /* * Update RTT estimate by @@ -881,9 +881,9 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) case DCCP_PKT_DATAACK: if (opt_recv->dccpor_timestamp_echo == 0) break; + r_sample = dccp_timestamp() - opt_recv->dccpor_timestamp_echo; rtt_prev = hcrx->ccid3hcrx_rtt; - now = ktime_get_real(); - r_sample = dccp_sample_rtt(sk, now, NULL); + r_sample = dccp_sample_rtt(sk, 10 * r_sample); if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) hcrx->ccid3hcrx_rtt = r_sample; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index a75c740ae6c0..bd4645b3a36c 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -297,8 +297,7 @@ extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); extern void dccp_send_close(struct sock *sk, const int active); extern int dccp_invalid_packet(struct sk_buff *skb); -extern u32 dccp_sample_rtt(struct sock *sk, ktime_t t_recv, - ktime_t *t_history); +extern u32 dccp_sample_rtt(struct sock *sk, long delta); static inline int dccp_bad_service_code(const struct sock *sk, const __be32 service) diff --git a/net/dccp/input.c b/net/dccp/input.c index 782cdb7292fa..3b651701cfe4 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -280,6 +280,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, if (dh->dccph_type == DCCP_PKT_RESPONSE) { const struct inet_connection_sock *icsk = inet_csk(sk); struct dccp_sock *dp = dccp_sk(sk); + long tstamp = dccp_timestamp(); /* Stop the REQUEST timer */ inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); @@ -300,11 +301,10 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, if (dccp_parse_options(sk, skb)) goto out_invalid_packet; - /* Obtain RTT sample from SYN exchange (used by CCID 3) */ - if (dp->dccps_options_received.dccpor_timestamp_echo) - dp->dccps_syn_rtt = dccp_sample_rtt(sk, - ktime_get_real(), - NULL); + /* Obtain usec RTT sample from SYN exchange (used by CCID 3) */ + if (likely(dp->dccps_options_received.dccpor_timestamp_echo)) + dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * (tstamp - + dp->dccps_options_received.dccpor_timestamp_echo)); if (dccp_msk(sk)->dccpms_send_ack_vector && dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, @@ -585,36 +585,22 @@ discard: EXPORT_SYMBOL_GPL(dccp_rcv_state_process); /** - * dccp_sample_rtt - Sample RTT from packet exchange - * - * @sk: connected dccp_sock - * @t_recv: receive timestamp of packet with timestamp echo - * @t_hist: packet history timestamp or NULL + * dccp_sample_rtt - Validate and finalise computation of RTT sample + * @delta: number of microseconds between packet and acknowledgment + * The routine is kept generic to work in different contexts. It should be + * called immediately when the ACK used for the RTT sample arrives. */ -u32 dccp_sample_rtt(struct sock *sk, ktime_t t_recv, ktime_t *t_hist) +u32 dccp_sample_rtt(struct sock *sk, long delta) { - struct dccp_sock *dp = dccp_sk(sk); - struct dccp_options_received *or = &dp->dccps_options_received; - s64 delta; - - if (t_hist == NULL) { - if (!or->dccpor_timestamp_echo) { - DCCP_WARN("packet without timestamp echo\n"); - return DCCP_SANE_RTT_MAX; - } - ktime_sub_us(t_recv, or->dccpor_timestamp_echo * 10); - delta = ktime_to_us(t_recv); - } else - delta = ktime_us_delta(t_recv, *t_hist); - - delta -= or->dccpor_elapsed_time * 10; /* either set or 0 */ + /* dccpor_elapsed_time is either zeroed out or set and > 0 */ + delta -= dccp_sk(sk)->dccps_options_received.dccpor_elapsed_time * 10; if (unlikely(delta <= 0)) { - DCCP_WARN("unusable RTT sample %ld, using min\n", (long)delta); + DCCP_WARN("unusable RTT sample %ld, using min\n", delta); return DCCP_SANE_RTT_MIN; } - if (unlikely(delta - (s64)DCCP_SANE_RTT_MAX > 0)) { - DCCP_WARN("RTT sample %ld too large, using max\n", (long)delta); + if (unlikely(delta > DCCP_SANE_RTT_MAX)) { + DCCP_WARN("RTT sample %ld too large, using max\n", delta); return DCCP_SANE_RTT_MAX; } From cbe1f5f88af454303a9c1a0624209269430d49fe Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 25 Sep 2007 22:41:19 -0700 Subject: [PATCH 1512/2804] [DCCP]: Shorten variable names in dccp_check_seqno This patch is in part required by the next patch; it * replaces 6 instances of `DCCP_SKB_CB(skb)->dccpd_seq' with `seqno'; * replaces 7 instances of `DCCP_SKB_CB(skb)->dccpd_ack_seq' with `ackno'; * replaces 1 use of dccp_inc_seqno() by unfolding `ADD48' macro in place. No changes in algorithm, all changes are text replacement/substitution. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/input.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/net/dccp/input.c b/net/dccp/input.c index 3b651701cfe4..6276b23fc204 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -68,7 +68,8 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) { const struct dccp_hdr *dh = dccp_hdr(skb); struct dccp_sock *dp = dccp_sk(sk); - u64 lswl, lawl; + u64 lswl, lawl, seqno = DCCP_SKB_CB(skb)->dccpd_seq, + ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; /* * Step 5: Prepare sequence numbers for Sync @@ -84,11 +85,9 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) */ if (dh->dccph_type == DCCP_PKT_SYNC || dh->dccph_type == DCCP_PKT_SYNCACK) { - if (between48(DCCP_SKB_CB(skb)->dccpd_ack_seq, - dp->dccps_awl, dp->dccps_awh) && - dccp_delta_seqno(dp->dccps_swl, - DCCP_SKB_CB(skb)->dccpd_seq) >= 0) - dccp_update_gsr(sk, DCCP_SKB_CB(skb)->dccpd_seq); + if (between48(ackno, dp->dccps_awl, dp->dccps_awh) && + dccp_delta_seqno(dp->dccps_swl, seqno) >= 0) + dccp_update_gsr(sk, seqno); else return -1; } @@ -113,35 +112,30 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) if (dh->dccph_type == DCCP_PKT_CLOSEREQ || dh->dccph_type == DCCP_PKT_CLOSE || dh->dccph_type == DCCP_PKT_RESET) { - lswl = dp->dccps_gsr; - dccp_inc_seqno(&lswl); + lswl = ADD48(dp->dccps_gsr, 1); lawl = dp->dccps_gar; } - if (between48(DCCP_SKB_CB(skb)->dccpd_seq, lswl, dp->dccps_swh) && - (DCCP_SKB_CB(skb)->dccpd_ack_seq == DCCP_PKT_WITHOUT_ACK_SEQ || - between48(DCCP_SKB_CB(skb)->dccpd_ack_seq, - lawl, dp->dccps_awh))) { - dccp_update_gsr(sk, DCCP_SKB_CB(skb)->dccpd_seq); + if (between48(seqno, lswl, dp->dccps_swh) && + (ackno == DCCP_PKT_WITHOUT_ACK_SEQ || + between48(ackno, lawl, dp->dccps_awh))) { + dccp_update_gsr(sk, seqno); if (dh->dccph_type != DCCP_PKT_SYNC && - (DCCP_SKB_CB(skb)->dccpd_ack_seq != - DCCP_PKT_WITHOUT_ACK_SEQ)) - dp->dccps_gar = DCCP_SKB_CB(skb)->dccpd_ack_seq; + (ackno != DCCP_PKT_WITHOUT_ACK_SEQ)) + dp->dccps_gar = ackno; } else { DCCP_WARN("DCCP: Step 6 failed for %s packet, " "(LSWL(%llu) <= P.seqno(%llu) <= S.SWH(%llu)) and " "(P.ackno %s or LAWL(%llu) <= P.ackno(%llu) <= S.AWH(%llu), " "sending SYNC...\n", dccp_packet_name(dh->dccph_type), - (unsigned long long) lswl, - (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq, + (unsigned long long) lswl, (unsigned long long) seqno, (unsigned long long) dp->dccps_swh, - (DCCP_SKB_CB(skb)->dccpd_ack_seq == - DCCP_PKT_WITHOUT_ACK_SEQ) ? "doesn't exist" : "exists", - (unsigned long long) lawl, - (unsigned long long) DCCP_SKB_CB(skb)->dccpd_ack_seq, + (ackno == DCCP_PKT_WITHOUT_ACK_SEQ) ? "doesn't exist" + : "exists", + (unsigned long long) lawl, (unsigned long long) ackno, (unsigned long long) dp->dccps_awh); - dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_PKT_SYNC); + dccp_send_sync(sk, seqno, DCCP_PKT_SYNC); return -1; } From e155d7692290f7bc539ccb8ebc3450ec964e53fd Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 25 Sep 2007 22:41:56 -0700 Subject: [PATCH 1513/2804] [DCCP]: Fix Reset/Sync-Flood Bug This updates sequence number checking with regard to RFC 4340, 7.5.4. Missing in the code was an exception for sequence-invalid Reset packets, which get a Sync acknowledging GSR, instead of (as usual) P.seqno. This can lead to an oscillating ping-pong flood of Reset packets. In fact, it has been observed on the wire as follows: 1. client establishes connection to server; 2. before server can write to client, client crashes without notifying the server (NB: now no longer possible due to ABORT function); 3. server sends DCCP-Data packet (has no ackno); 4. client generates Reset "No Connection", seqno=0, increments seqno; 5. server replies with Sync, using ackno = P.seqno; 6. client generates Reset "No Connection" with seqno = ackno + 1; 7. goto (5). The difference is that now in (5) the server uses GSR. This causes the Reset sent by the client in (6) to become sequence-valid, so that in (7) the vicious circle is broken; the Reset is then enqueued and causes the socket to enter TIMEWAIT state. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/input.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/dccp/input.c b/net/dccp/input.c index 6276b23fc204..cde0e704dfce 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -102,9 +102,6 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) * Update S.GSR, S.SWL, S.SWH * If P.type != Sync, * Update S.GAR - * Otherwise, - * Send Sync packet acknowledging P.seqno - * Drop packet and return */ lswl = dp->dccps_swl; lawl = dp->dccps_awl; @@ -135,6 +132,17 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) : "exists", (unsigned long long) lawl, (unsigned long long) ackno, (unsigned long long) dp->dccps_awh); + /* + * Step 6: Check sequence numbers + * Otherwise, + * If P.type == Reset, + * Send Sync packet acknowledging S.GSR + * Otherwise, + * Send Sync packet acknowledging P.seqno + * Drop packet and return + */ + if (dh->dccph_type == DCCP_PKT_RESET) + seqno = dp->dccps_gsr; dccp_send_sync(sk, seqno, DCCP_PKT_SYNC); return -1; } From b0d045ca45a44d9f8bd66d0a10558b10c60f895a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 25 Sep 2007 22:42:27 -0700 Subject: [PATCH 1514/2804] [DCCP]: Parameter renaming The parameter `seq' of dccp_send_sync() is in fact an acknowledgement number and not a sequence number - thus renamed by this patch into `ackno'. Secondly, a `critical' warning is added when a Sync/SyncAck could not be sent. Sanity: I have checked all other functions that are called in dccp_transmit_skb, there are no clashes with the use of dccpd_ack_seq; no other function is using this slot at the same time. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/output.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/dccp/output.c b/net/dccp/output.c index c8d843e983fc..6e23d5b57e79 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -69,7 +69,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) case DCCP_PKT_SYNC: case DCCP_PKT_SYNCACK: - ackno = dcb->dccpd_seq; + ackno = dcb->dccpd_ack_seq; /* fall through */ default: /* @@ -507,7 +507,7 @@ void dccp_send_delayed_ack(struct sock *sk) sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout); } -void dccp_send_sync(struct sock *sk, const u64 seq, +void dccp_send_sync(struct sock *sk, const u64 ackno, const enum dccp_pkt_type pkt_type) { /* @@ -517,14 +517,16 @@ void dccp_send_sync(struct sock *sk, const u64 seq, */ struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header, GFP_ATOMIC); - if (skb == NULL) + if (skb == NULL) { /* FIXME: how to make sure the sync is sent? */ + DCCP_CRIT("could not send %s", dccp_packet_name(pkt_type)); return; + } /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, sk->sk_prot->max_header); DCCP_SKB_CB(skb)->dccpd_type = pkt_type; - DCCP_SKB_CB(skb)->dccpd_seq = seq; + DCCP_SKB_CB(skb)->dccpd_ack_seq = ackno; dccp_transmit_skb(sk, skb); } From a6963a6b3d2d3921b60f45e0cf18be26495d5ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 25 Sep 2007 22:44:14 -0700 Subject: [PATCH 1515/2804] [TCP]: Re-place highest_sack check to a more robust position MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I previously added checking to position that is rather poor as state has already been adjusted quite a bit. Re-placing it above all state changes should be more robust though the return should never ever get executed regardless of its place :-). Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index cbb83acd830a..94c80113df7e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1718,6 +1718,10 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1); + if (WARN_ON(tp->sacked_out && + (TCP_SKB_CB(next_skb)->seq == tp->highest_sack))) + return; + /* Ok. We will be able to collapse the packet. */ tcp_unlink_write_queue(next_skb, sk); @@ -1734,10 +1738,6 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m /* Update sequence range on original skb. */ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq; - if (WARN_ON(tp->sacked_out && - (TCP_SKB_CB(next_skb)->seq == tp->highest_sack))) - return; - /* Merge over control information. */ flags |= TCP_SKB_CB(next_skb)->flags; /* This moves PSH/FIN etc. over */ TCP_SKB_CB(skb)->flags = flags; From 93e680202929802558f783fbd96c41697ae65472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 25 Sep 2007 22:46:50 -0700 Subject: [PATCH 1516/2804] [TCP]: Reordered ACK's (old) SACKs not included to discarded MIB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of ACK reordering, the SACK block might be valid in it's time but is already obsoleted since we've received another kind of confirmation about arrival of the segments through snd_una advancement of an earlier packet. I didn't bother to build distinguishing of valid and invalid SACK blocks but simply made reordered SACK blocks that are too old always not counted regardless of their "real" validity which could be determined by using the ack field of the reordered packet (won't be significant IMHO). DSACKs can very well be considered useful even in this situation, so won't do any of this for them. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4c10d9cad20f..4866e75e98e0 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1247,8 +1247,13 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO); else NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD); - } else + } else { + /* Don't count olds caused by ACK reordering */ + if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) && + !after(end_seq, tp->snd_una)) + continue; NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD); + } continue; } From 912d8f0b1f17b7e851ebbfeb17a16de9f9c7cb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 25 Sep 2007 22:47:31 -0700 Subject: [PATCH 1517/2804] [TCP] MIB: Count FRTO's successfully detected spurious RTOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/linux/snmp.h | 1 + net/ipv4/proc.c | 1 + net/ipv4/tcp_input.c | 1 + 3 files changed, 3 insertions(+) diff --git a/include/linux/snmp.h b/include/linux/snmp.h index d8fd3ec4148a..89f0c2b5f405 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -213,6 +213,7 @@ enum LINUX_MIB_TCPSACKDISCARD, /* TCPSACKDiscard */ LINUX_MIB_TCPDSACKIGNOREDOLD, /* TCPSACKIgnoredOld */ LINUX_MIB_TCPDSACKIGNOREDNOUNDO, /* TCPSACKIgnoredNoUndo */ + LINUX_MIB_TCPSPURIOUSRTOS, /* TCPSpuriousRTOs */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 2015148b41a8..9dee70e1cf0d 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -245,6 +245,7 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPSACKDiscard", LINUX_MIB_TCPSACKDISCARD), SNMP_MIB_ITEM("TCPDSACKIgnoredOld", LINUX_MIB_TCPDSACKIGNOREDOLD), SNMP_MIB_ITEM("TCPDSACKIgnoredNoUndo", LINUX_MIB_TCPDSACKIGNOREDNOUNDO), + SNMP_MIB_ITEM("TCPSpuriousRTOs", LINUX_MIB_TCPSPURIOUSRTOS), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4866e75e98e0..4b27739031fb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2935,6 +2935,7 @@ static int tcp_process_frto(struct sock *sk, int flag) } tp->frto_counter = 0; tp->undo_marker = 0; + NET_INC_STATS_BH(LINUX_MIB_TCPSPURIOUSRTOS); } return 0; } From 53465eb4ab16660eab0a7be168a087a97172e650 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 25 Sep 2007 22:57:31 -0700 Subject: [PATCH 1518/2804] [BLUETOOTH]: Make hidp_setup_input() return int This patch: - makes hidp_setup_input() return int to indicate errors; - checks its return value to handle errors. And this time it is against -rc7-mm1 tree. Thanks to roel and Marcel Holtmann for comments. Signed-off-by: WANG Cong Signed-off-by: Marcel Holtmann Signed-off-by: David S. Miller --- net/bluetooth/hidp/core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 64d89ca28847..ff5784b440d7 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -625,7 +625,7 @@ static struct device *hidp_get_device(struct hidp_session *session) return conn ? &conn->dev : NULL; } -static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req) +static inline int hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req) { struct input_dev *input = session->input; int i; @@ -667,7 +667,7 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co input->event = hidp_input_event; - input_register_device(input); + return input_register_device(input); } static int hidp_open(struct hid_device *hid) @@ -820,8 +820,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); session->idle_to = req->idle_to; - if (session->input) - hidp_setup_input(session, req); + if (session->input) { + err = hidp_setup_input(session, req); + if (err < 0) + goto failed; + } if (session->hid) hidp_setup_hid(session, req); From 08831700cc65f85a497d6b32b1c83ca84d71de4a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 10:30:05 -0300 Subject: [PATCH 1519/2804] [DCCP]: Send Reset upon Sync in state REQUEST This fixes the code to correspond to RFC 4340, 7.5.4, which states the exception that a Sync received in state REQUEST generates a Reset (not a SyncAck). To achieve this, only a small change is required. Since dccp_rcv_request_sent_state_process() already uses the correct Reset Code number 4 ("Packet Error"), we only need to shift the if-statement a few lines further down. (To test this case: replace DCCP_PKT_RESPONSE with DCCP_PKT_SYNC in dccp_make_response.) Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/input.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/dccp/input.c b/net/dccp/input.c index cde0e704dfce..86ad3ba0649a 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -540,11 +540,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, return 0; } - if (unlikely(dh->dccph_type == DCCP_PKT_SYNC)) { - dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNCACK); - goto discard; - } - switch (sk->sk_state) { case DCCP_CLOSED: dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; @@ -575,6 +570,9 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, sk_wake_async(sk, 0, POLL_OUT); break; } + } else if (unlikely(dh->dccph_type == DCCP_PKT_SYNC)) { + dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNCACK); + goto discard; } if (!queued) { From 2e86908f7dfb71b67ca4739d9a6c678b83b01078 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 11:24:28 -0300 Subject: [PATCH 1520/2804] [CCID3]: Move NULL-protection into function This moves several instances of testing against NULL into the function which is used to de-reference the CCID-private data. Committer note: Made the BUG_ON depend on having CONFIG_IP_DCCP_CCID3_DEBUG, as it is too much to have this on production code. Also made sure that the macro is used only after checking if sk_state is not LISTEN, to make it equivalent to what we had before. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/ccids/ccid3.c | 35 ++++++++++------------------------- net/dccp/ccids/ccid3.h | 20 ++++++++++++++------ 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 0bb338be9dd7..a4099398bcc8 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -302,8 +302,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) ktime_t now = ktime_get_real(); s64 delay; - BUG_ON(hctx == NULL); - /* * This function is called only for Data and DataAck packets. Sending * zero-sized Data(Ack)s is theoretically possible, but for congestion @@ -383,8 +381,6 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct dccp_tx_hist_entry *packet; - BUG_ON(hctx == NULL); - ccid3_hc_tx_update_s(hctx, len); packet = dccp_tx_hist_entry_new(ccid3_tx_hist, GFP_ATOMIC); @@ -409,8 +405,6 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) unsigned long t_nfb; u32 pinv, r_sample; - BUG_ON(hctx == NULL); - /* we are only interested in ACKs */ if (!(DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK || DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_DATAACK)) @@ -551,8 +545,6 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct ccid3_options_received *opt_recv; - BUG_ON(hctx == NULL); - opt_recv = &hctx->ccid3hctx_options_received; if (opt_recv->ccid3or_seqno != dp->dccps_gsr) { @@ -626,8 +618,6 @@ static void ccid3_hc_tx_exit(struct sock *sk) { struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - BUG_ON(hctx == NULL); - ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM); sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer); @@ -637,14 +627,13 @@ static void ccid3_hc_tx_exit(struct sock *sk) static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) { - const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); + struct ccid3_hc_tx_sock *hctx; /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return; - BUG_ON(hctx == NULL); - + hctx = ccid3_hc_tx_sk(sk); info->tcpi_rto = hctx->ccid3hctx_t_rto; info->tcpi_rtt = hctx->ccid3hctx_rtt; } @@ -652,13 +641,14 @@ static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, u32 __user *optval, int __user *optlen) { - const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); + const struct ccid3_hc_tx_sock *hctx; const void *val; /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return -EINVAL; + hctx = ccid3_hc_tx_sk(sk); switch (optname) { case DCCP_SOCKOPT_CCID_TX_INFO: if (len < sizeof(hctx->ccid3hctx_tfrc)) @@ -772,14 +762,13 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) { - const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); + const struct ccid3_hc_rx_sock *hcrx; __be32 x_recv, pinv; - BUG_ON(hcrx == NULL); - if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) return 0; + hcrx = ccid3_hc_rx_sk(sk); DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_ccval_last_counter; if (dccp_packet_without_ack(skb)) @@ -870,8 +859,6 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) int loss, payload_size; ktime_t now; - BUG_ON(hcrx == NULL); - opt_recv = &dccp_sk(sk)->dccps_options_received; switch (DCCP_SKB_CB(skb)->dccpd_type) { @@ -985,8 +972,6 @@ static void ccid3_hc_rx_exit(struct sock *sk) { struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); - BUG_ON(hcrx == NULL); - ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM); /* Empty packet history */ @@ -998,14 +983,13 @@ static void ccid3_hc_rx_exit(struct sock *sk) static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) { - const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); + const struct ccid3_hc_rx_sock *hcrx; /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return; - BUG_ON(hcrx == NULL); - + hcrx = ccid3_hc_rx_sk(sk); info->tcpi_ca_state = hcrx->ccid3hcrx_state; info->tcpi_options |= TCPI_OPT_TIMESTAMPS; info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt; @@ -1014,13 +998,14 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len, u32 __user *optval, int __user *optlen) { - const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); + const struct ccid3_hc_rx_sock *hcrx; const void *val; /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return -EINVAL; + hcrx = ccid3_hc_rx_sk(sk); switch (optname) { case DCCP_SOCKOPT_CCID_RX_INFO: if (len < sizeof(hcrx->ccid3hcrx_tfrc)) diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 7cbf2b1329d9..ae99ec430371 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -117,6 +117,15 @@ struct ccid3_hc_tx_sock { struct ccid3_options_received ccid3hctx_options_received; }; +static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) +{ + struct ccid3_hc_tx_sock *hctx = ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid); +#ifdef CONFIG_IP_DCCP_CCID3_DEBUG + BUG_ON(hctx == NULL); +#endif + return hctx; +} + /* TFRC receiver states */ enum ccid3_hc_rx_states { TFRC_RSTATE_NO_DATA = 1, @@ -161,14 +170,13 @@ struct ccid3_hc_rx_sock { u32 ccid3hcrx_elapsed_time; }; -static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) -{ - return ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid); -} - static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk) { - return ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid); + struct ccid3_hc_rx_sock *hcrx = ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid); +#ifdef CONFIG_IP_DCCP_CCID3_DEBUG + BUG_ON(hcrx == NULL); +#endif + return hcrx; } #endif /* _DCCP_CCID3_H_ */ From 727ecc5faaf6e976fc841649821c865ebd1e822d Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 11:26:04 -0300 Subject: [PATCH 1521/2804] [DCCP]: Add FIXME for send_delayed_ack This adds a FIXME to signal that the function dccp_send_delayed_ack is nowhere used in the entire DCCP/CCID code. Using a delayed Ack timer is suggested in 11.3 of RFC 4340, but it has also rather subtle implications for the Ack-Ratio-accounting. CCID2 does not use this (maybe it should). I think leaving the function in is good, in case someone wants to implement this. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/dccp.h | 1 - net/dccp/output.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index bd4645b3a36c..f62eeb374931 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -209,7 +209,6 @@ extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); extern void dccp_send_ack(struct sock *sk); -extern void dccp_send_delayed_ack(struct sock *sk); extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk); extern void dccp_send_sync(struct sock *sk, const u64 seq, diff --git a/net/dccp/output.c b/net/dccp/output.c index 6e23d5b57e79..d0c9ec6494bf 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -477,6 +477,7 @@ void dccp_send_ack(struct sock *sk) EXPORT_SYMBOL_GPL(dccp_send_ack); +/* FIXME: Is this still necessary (11.3) - currently nowhere used by DCCP. */ void dccp_send_delayed_ack(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); From 0430ee3451f4589b68f522552b1896825f2043b3 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 11:27:56 -0300 Subject: [PATCH 1522/2804] [DCCP]: Add Support for Data 1 .. 3 fields of Reset packets This adds fields to support the informational Data 1..3 fields of the DCCP-Reset packets (RFC 4340, 5.6), and makes minor cosmetic changes to documentation. Code which fills in these fields follows in subsequent patches, it is primarily used for reporting option-processing and feature-negotiation errors. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/dccp.h | 14 ++++++-------- net/dccp/dccp.h | 14 +++++++++++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/linux/dccp.h b/include/linux/dccp.h index a0441190dc71..20e0717aa8e1 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -56,10 +56,9 @@ struct dccp_hdr_ext { }; /** - * struct dccp_hdr_request - Conection initiation request header + * struct dccp_hdr_request - Connection initiation request header * * @dccph_req_service - Service to which the client app wants to connect - * @dccph_req_options - list of options (must be a multiple of 32 bits */ struct dccp_hdr_request { __be32 dccph_req_service; @@ -76,12 +75,10 @@ struct dccp_hdr_ack_bits { __be32 dccph_ack_nr_low; }; /** - * struct dccp_hdr_response - Conection initiation response header + * struct dccp_hdr_response - Connection initiation response header * - * @dccph_resp_ack_nr_high - 48 bit ack number high order bits, contains GSR - * @dccph_resp_ack_nr_low - 48 bit ack number low order bits, contains GSR + * @dccph_resp_ack - 48 bit Acknowledgment Number Subheader (5.3) * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request - * @dccph_resp_options - list of options (must be a multiple of 32 bits */ struct dccp_hdr_response { struct dccp_hdr_ack_bits dccph_resp_ack; @@ -91,8 +88,9 @@ struct dccp_hdr_response { /** * struct dccp_hdr_reset - Unconditionally shut down a connection * - * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request - * @dccph_reset_options - list of options (must be a multiple of 32 bits + * @dccph_reset_ack - 48 bit Acknowledgment Number Subheader (5.6) + * @dccph_reset_code - one of %dccp_reset_codes + * @dccph_reset_data - the Data 1 ... Data 3 fields from 5.6 */ struct dccp_hdr_reset { struct dccp_hdr_ack_bits dccph_reset_ack; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index f62eeb374931..e28220183208 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -308,10 +308,22 @@ static inline int dccp_bad_service_code(const struct sock *sk, return !dccp_list_has_service(dp->dccps_service_list, service); } +/** + * dccp_skb_cb - DCCP per-packet control information + * @dccpd_type: one of %dccp_pkt_type (or unknown) + * @dccpd_ccval: CCVal field (5.1), see e.g. RFC 4342, 8.1 + * @dccpd_reset_code: one of %dccp_reset_codes + * @dccpd_reset_data: Data1..3 fields (depend on @dccpd_reset_code) + * @dccpd_opt_len: total length of all options (5.8) in the packet + * @dccpd_seq: sequence number + * @dccpd_ack_seq: acknowledgment number subheader field value + * This is used for transmission as well as for reception. + */ struct dccp_skb_cb { __u8 dccpd_type:4; __u8 dccpd_ccval:4; - __u8 dccpd_reset_code; + __u8 dccpd_reset_code, + dccpd_reset_data[3]; __u16 dccpd_opt_len; __u64 dccpd_seq; __u64 dccpd_ack_seq; From ee1a15922d356aff0e31bf9bb9088ab346b8033a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 11:30:02 -0300 Subject: [PATCH 1523/2804] [DCCP]: Remove duplicate code for Reset from connected socket In this patch, duplicated code is removed for the case when a Reset packet is sent from a connected socket. This code duplication is between dccp_make_reset and dccp_transmit_skb, which already contained an (up to now entirely unused) switch statement to fill in the reset code from the DCCP_SKB_CB. The only thing that has been removed is the call to dst_clone(dst), since the queue_xmit functions use sk_dst_cache anyway. I wasn't sure which purpose inet_sk_rebuild_header served, so I left it in. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/output.c | 78 ++++++++++++----------------------------------- 1 file changed, 19 insertions(+), 59 deletions(-) diff --git a/net/dccp/output.c b/net/dccp/output.c index d0c9ec6494bf..f4bde2056204 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -61,6 +61,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) set_ack = 0; /* fall through */ case DCCP_PKT_DATAACK: + case DCCP_PKT_RESET: break; case DCCP_PKT_REQUEST: @@ -73,8 +74,10 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) /* fall through */ default: /* - * Only data packets should come through with skb->sk - * set. + * Set owner/destructor: some skbs are allocated via + * alloc_skb (e.g. when retransmission may happen). + * Only Data, DataAck, and Reset packets should come + * through here with skb->sk set. */ WARN_ON(skb->sk); skb_set_owner_w(skb, sk); @@ -324,72 +327,29 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, EXPORT_SYMBOL_GPL(dccp_make_response); -static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, - const enum dccp_reset_codes code) -{ - struct dccp_hdr *dh; - struct dccp_sock *dp = dccp_sk(sk); - const u32 dccp_header_size = sizeof(struct dccp_hdr) + - sizeof(struct dccp_hdr_ext) + - sizeof(struct dccp_hdr_reset); - struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1, - GFP_ATOMIC); - if (skb == NULL) - return NULL; - - /* Reserve space for headers. */ - skb_reserve(skb, sk->sk_prot->max_header); - - skb->dst = dst_clone(dst); - - dccp_inc_seqno(&dp->dccps_gss); - - DCCP_SKB_CB(skb)->dccpd_reset_code = code; - DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESET; - DCCP_SKB_CB(skb)->dccpd_seq = dp->dccps_gss; - - if (dccp_insert_options(sk, skb)) { - kfree_skb(skb); - return NULL; - } - - dh = dccp_zeroed_hdr(skb, dccp_header_size); - - dh->dccph_sport = inet_sk(sk)->sport; - dh->dccph_dport = inet_sk(sk)->dport; - dh->dccph_doff = (dccp_header_size + - DCCP_SKB_CB(skb)->dccpd_opt_len) / 4; - dh->dccph_type = DCCP_PKT_RESET; - dh->dccph_x = 1; - dccp_hdr_set_seq(dh, dp->dccps_gss); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr); - - dccp_hdr_reset(skb)->dccph_reset_code = code; - inet_csk(sk)->icsk_af_ops->send_check(sk, 0, skb); - - DCCP_INC_STATS(DCCP_MIB_OUTSEGS); - return skb; -} - +/* send Reset on established socket, to close or abort the connection */ int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code) { + struct sk_buff *skb; /* * FIXME: what if rebuild_header fails? * Should we be doing a rebuild_header here? */ int err = inet_sk_rebuild_header(sk); - if (err == 0) { - struct sk_buff *skb = dccp_make_reset(sk, sk->sk_dst_cache, - code); - if (skb != NULL) { - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, 0); - return net_xmit_eval(err); - } - } + if (err != 0) + return err; - return err; + skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1, GFP_ATOMIC); + if (skb == NULL) + return -ENOBUFS; + + /* Reserve space for headers and prepare control bits. */ + skb_reserve(skb, sk->sk_prot->max_header); + DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESET; + DCCP_SKB_CB(skb)->dccpd_reset_code = code; + + return dccp_transmit_skb(sk, skb); } /* From a94f0f970549e63e54c80c4509db299c514d8c11 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 11:31:49 -0300 Subject: [PATCH 1524/2804] [DCCP]: Rate-limit DCCP-Syncs This implements a SHOULD from RFC 4340, 7.5.4: "To protect against denial-of-service attacks, DCCP implementations SHOULD impose a rate limit on DCCP-Syncs sent in response to sequence-invalid packets, such as not more than eight DCCP-Syncs per second." The rate-limit is maintained on a per-socket basis. This is a more stringent policy than enforcing the rate-limit on a per-source-address basis and protects against attacks with forged source addresses. Moreover, the mechanism is deliberately kept simple. In contrast to xrlim_allow(), bursts of Sync packets in reply to sequence-invalid packets are not supported. This foils such attacks where the receipt of a Sync triggers further sequence-invalid packets. (I have tested this mechanism against xrlim_allow algorithm for Syncs, permitting bursts just increases the problems.) In order to keep flexibility, the timeout parameter can be set via sysctl; and the whole mechanism can even be disabled (which is however not recommended). The algorithm in this patch has been improved with regard to wrapping issues thanks to a suggestion by Arnaldo. Commiter note: Rate limited the step 6 DCCP_WARN too, as it says we're sending a sync. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/networking/dccp.txt | 5 +++++ include/linux/dccp.h | 2 ++ net/dccp/dccp.h | 1 + net/dccp/input.c | 29 ++++++++++++++++++++--------- net/dccp/proto.c | 1 + net/dccp/sysctl.c | 10 ++++++++++ 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 4504cc59e405..477026ae0ffb 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -112,6 +112,11 @@ tx_qlen = 5 The size of the transmit buffer in packets. A value of 0 corresponds to an unbounded transmit buffer. +sync_ratelimit = 125 ms + The timeout between subsequent DCCP-Sync packets sent in response to + sequence-invalid packets on the same socket (RFC 4340, 7.5.4). The unit + of this parameter is milliseconds; a value of 0 disables rate-limiting. + Notes ===== diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 20e0717aa8e1..4ed82e2c9f65 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -470,6 +470,7 @@ struct dccp_ackvec; * @dccps_pcrlen - receiver partial checksum coverage (via sockopt) * @dccps_ndp_count - number of Non Data Packets since last data packet * @dccps_mss_cache - current value of MSS (path MTU minus header sizes) + * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4) * @dccps_minisock - associated minisock (accessed via dccp_msk) * @dccps_hc_rx_ackvec - rx half connection ack vector * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection) @@ -505,6 +506,7 @@ struct dccp_sock { __u16 dccps_pcrlen; unsigned long dccps_ndp_count; __u32 dccps_mss_cache; + unsigned long dccps_rate_last; struct dccp_minisock dccps_minisock; struct dccp_ackvec *dccps_hc_rx_ackvec; struct ccid *dccps_hc_rx_ccid; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index e28220183208..a602d9212c64 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -92,6 +92,7 @@ extern int sysctl_dccp_feat_ack_ratio; extern int sysctl_dccp_feat_send_ack_vector; extern int sysctl_dccp_feat_send_ndp_count; extern int sysctl_dccp_tx_qlen; +extern int sysctl_dccp_sync_ratelimit; /* * 48-bit sequence number arithmetic (signed and unsigned) diff --git a/net/dccp/input.c b/net/dccp/input.c index 86ad3ba0649a..19d7e1dbd87e 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -122,6 +122,23 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) (ackno != DCCP_PKT_WITHOUT_ACK_SEQ)) dp->dccps_gar = ackno; } else { + unsigned long now = jiffies; + /* + * Step 6: Check sequence numbers + * Otherwise, + * If P.type == Reset, + * Send Sync packet acknowledging S.GSR + * Otherwise, + * Send Sync packet acknowledging P.seqno + * Drop packet and return + * + * These Syncs are rate-limited as per RFC 4340, 7.5.4: + * at most 1 / (dccp_sync_rate_limit * HZ) Syncs per second. + */ + if (time_before(now, (dp->dccps_rate_last + + sysctl_dccp_sync_ratelimit))) + return 0; + DCCP_WARN("DCCP: Step 6 failed for %s packet, " "(LSWL(%llu) <= P.seqno(%llu) <= S.SWH(%llu)) and " "(P.ackno %s or LAWL(%llu) <= P.ackno(%llu) <= S.AWH(%llu), " @@ -132,15 +149,9 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) : "exists", (unsigned long long) lawl, (unsigned long long) ackno, (unsigned long long) dp->dccps_awh); - /* - * Step 6: Check sequence numbers - * Otherwise, - * If P.type == Reset, - * Send Sync packet acknowledging S.GSR - * Otherwise, - * Send Sync packet acknowledging P.seqno - * Drop packet and return - */ + + dp->dccps_rate_last = now; + if (dh->dccph_type == DCCP_PKT_RESET) seqno = dp->dccps_gsr; dccp_send_sync(sk, seqno, DCCP_PKT_SYNC); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 14ec1d21452c..604de8bfa068 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -219,6 +219,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) sk->sk_write_space = dccp_write_space; icsk->icsk_sync_mss = dccp_sync_mss; dp->dccps_mss_cache = 536; + dp->dccps_rate_last = jiffies; dp->dccps_role = DCCP_ROLE_UNDEFINED; dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 1260aabac5e1..9364b2fb4dbd 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -18,6 +18,9 @@ #error This file should not be compiled without CONFIG_SYSCTL defined #endif +/* rate-limit for syncs in reply to sequence-invalid packets; RFC 4340, 7.5.4 */ +int sysctl_dccp_sync_ratelimit __read_mostly = HZ / 8; + static struct ctl_table dccp_default_table[] = { { .procname = "seq_window", @@ -89,6 +92,13 @@ static struct ctl_table dccp_default_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "sync_ratelimit", + .data = &sysctl_dccp_sync_ratelimit, + .maxlen = sizeof(sysctl_dccp_sync_ratelimit), + .mode = 0644, + .proc_handler = proc_dointvec_ms_jiffies, + }, { .ctl_name = 0, } }; From 9bf55cda9b2487fa7316dad3880acb0031ad3c0f Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 11:32:49 -0300 Subject: [PATCH 1525/2804] [DCCP]: Sequence number wrap-around when sending reset This replaces normal addition with mod-48 addition so that sequence number wraparound is respected. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/ipv4.c | 2 +- net/dccp/ipv6.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2c6282815264..58a79c2ae55c 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -552,7 +552,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) /* See "8.3.1. Abnormal Termination" in RFC 4340 */ if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) - dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); + seqno = ADD48(DCCP_SKB_CB(rxskb)->dccpd_ack_seq, 1); dccp_hdr_set_seq(dh, seqno); dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index b158c661867b..d954e8319dbd 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -336,7 +336,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) /* See "8.3.1. Abnormal Termination" in RFC 4340 */ if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) - dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); + seqno = ADD48(DCCP_SKB_CB(rxskb)->dccpd_ack_seq, 1); dccp_hdr_set_seq(dh, seqno); dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); From e356d37a096a990ea1a74c44c15640122e56110b Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 14:35:19 -0300 Subject: [PATCH 1526/2804] [DCCP]: Factor out common code for generating Resets This factors code common to dccp_v{4,6}_ctl_send_reset into a separate function, and adds support for filling in the Data 1 ... Data 3 fields from RFC 4340, 5.6. It is useful to have this separate, since the following Reset codes will always be generated from the control socket rather than via dccp_send_reset: * Code 3, "No Connection", cf. 8.3.1; * Code 4, "Packet Error" (identification for Data 1 added); * Code 5, "Option Error" (identification for Data 1..3 added, will be used later); * Code 6, "Mandatory Error" (same as Option Error); * Code 7, "Connection Refused" (what on Earth is the difference to "No Connection"?); * Code 8, "Bad Service Code"; * Code 9, "Too Busy"; * Code 10, "Bad Init Cookie" (not used). Code 0 is not recommended by the RFC, the following codes would be used in dccp_send_reset() instead, since they all relate to an established DCCP connection: * Code 1, "Closed"; * Code 2, "Aborted"; * Code 11, "Aggression Penalty" (12.3). Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/dccp.h | 2 ++ net/dccp/ipv4.c | 38 +++++----------------------------- net/dccp/ipv6.c | 39 ++++++----------------------------- net/dccp/output.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 66 deletions(-) diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index a602d9212c64..ee97950d77d1 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -294,6 +294,8 @@ extern unsigned int dccp_poll(struct file *file, struct socket *sock, extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); +extern struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, + struct sk_buff *skb); extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); extern void dccp_send_close(struct sock *sk, const int active); extern int dccp_invalid_packet(struct sk_buff *skb); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 58a79c2ae55c..2312b9f4d7af 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -510,17 +510,12 @@ out: static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) { int err; - struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; const struct iphdr *rxiph; - const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) + - sizeof(struct dccp_hdr_ext) + - sizeof(struct dccp_hdr_reset); struct sk_buff *skb; struct dst_entry *dst; - u64 seqno = 0; /* Never send a reset in response to a reset. */ - if (rxdh->dccph_type == DCCP_PKT_RESET) + if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) @@ -530,37 +525,14 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (dst == NULL) return; - skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header, - GFP_ATOMIC); + skb = dccp_ctl_make_reset(dccp_v4_ctl_socket, rxskb); if (skb == NULL) goto out; - /* Reserve space for headers. */ - skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); - skb->dst = dst_clone(dst); - - dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); - - /* Build DCCP header and checksum it. */ - dh->dccph_type = DCCP_PKT_RESET; - dh->dccph_sport = rxdh->dccph_dport; - dh->dccph_dport = rxdh->dccph_sport; - dh->dccph_doff = dccp_hdr_reset_len / 4; - dh->dccph_x = 1; - dccp_hdr_reset(skb)->dccph_reset_code = - DCCP_SKB_CB(rxskb)->dccpd_reset_code; - - /* See "8.3.1. Abnormal Termination" in RFC 4340 */ - if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) - seqno = ADD48(DCCP_SKB_CB(rxskb)->dccpd_ack_seq, 1); - - dccp_hdr_set_seq(dh, seqno); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); - - dccp_csum_outgoing(skb); rxiph = ip_hdr(rxskb); - dh->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr, - rxiph->daddr); + dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr, + rxiph->daddr); + skb->dst = dst_clone(dst); bh_lock_sock(dccp_v4_ctl_socket->sk); err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index d954e8319dbd..b7c0f66e2834 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -301,50 +301,23 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req) static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) { - struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; struct ipv6hdr *rxip6h; - const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) + - sizeof(struct dccp_hdr_ext) + - sizeof(struct dccp_hdr_reset); struct sk_buff *skb; struct flowi fl; - u64 seqno = 0; - if (rxdh->dccph_type == DCCP_PKT_RESET) + if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; if (!ipv6_unicast_destination(rxskb)) return; - skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header, - GFP_ATOMIC); + skb = dccp_ctl_make_reset(dccp_v6_ctl_socket, rxskb); if (skb == NULL) return; - skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); - - dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); - - /* Swap the send and the receive. */ - dh->dccph_type = DCCP_PKT_RESET; - dh->dccph_sport = rxdh->dccph_dport; - dh->dccph_dport = rxdh->dccph_sport; - dh->dccph_doff = dccp_hdr_reset_len / 4; - dh->dccph_x = 1; - dccp_hdr_reset(skb)->dccph_reset_code = - DCCP_SKB_CB(rxskb)->dccpd_reset_code; - - /* See "8.3.1. Abnormal Termination" in RFC 4340 */ - if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) - seqno = ADD48(DCCP_SKB_CB(rxskb)->dccpd_ack_seq, 1); - - dccp_hdr_set_seq(dh, seqno); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); - - dccp_csum_outgoing(skb); rxip6h = ipv6_hdr(rxskb); - dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr, - &rxip6h->daddr); + dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr, + &rxip6h->daddr); memset(&fl, 0, sizeof(fl)); ipv6_addr_copy(&fl.fl6_dst, &rxip6h->saddr); @@ -352,8 +325,8 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) fl.proto = IPPROTO_DCCP; fl.oif = inet6_iif(rxskb); - fl.fl_ip_dport = dh->dccph_dport; - fl.fl_ip_sport = dh->dccph_sport; + fl.fl_ip_dport = dccp_hdr(skb)->dccph_dport; + fl.fl_ip_sport = dccp_hdr(skb)->dccph_sport; security_skb_classify_flow(rxskb, &fl); /* sk = NULL, but it is safe for now. RST socket required. */ diff --git a/net/dccp/output.c b/net/dccp/output.c index f4bde2056204..6a334ed5e9d6 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -327,6 +327,58 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, EXPORT_SYMBOL_GPL(dccp_make_response); +/* answer offending packet in @rcv_skb with Reset from control socket @ctl */ +struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, struct sk_buff *rcv_skb) +{ + struct dccp_hdr *rxdh = dccp_hdr(rcv_skb), *dh; + struct dccp_skb_cb *dcb = DCCP_SKB_CB(rcv_skb); + const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) + + sizeof(struct dccp_hdr_ext) + + sizeof(struct dccp_hdr_reset); + struct dccp_hdr_reset *dhr; + struct sk_buff *skb; + + skb = alloc_skb(ctl->sk->sk_prot->max_header, GFP_ATOMIC); + if (skb == NULL) + return NULL; + + skb_reserve(skb, ctl->sk->sk_prot->max_header); + + /* Swap the send and the receive. */ + dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); + dh->dccph_type = DCCP_PKT_RESET; + dh->dccph_sport = rxdh->dccph_dport; + dh->dccph_dport = rxdh->dccph_sport; + dh->dccph_doff = dccp_hdr_reset_len / 4; + dh->dccph_x = 1; + + dhr = dccp_hdr_reset(skb); + dhr->dccph_reset_code = dcb->dccpd_reset_code; + + switch (dcb->dccpd_reset_code) { + case DCCP_RESET_CODE_PACKET_ERROR: + dhr->dccph_reset_data[0] = rxdh->dccph_type; + break; + case DCCP_RESET_CODE_OPTION_ERROR: /* fall through */ + case DCCP_RESET_CODE_MANDATORY_ERROR: + memcpy(dhr->dccph_reset_data, dcb->dccpd_reset_data, 3); + break; + } + /* + * From RFC 4340, 8.3.1: + * If P.ackno exists, set R.seqno := P.ackno + 1. + * Else set R.seqno := 0. + */ + if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) + dccp_hdr_set_seq(dh, ADD48(dcb->dccpd_ack_seq, 1)); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dcb->dccpd_seq); + + dccp_csum_outgoing(skb); + return skb; +} + +EXPORT_SYMBOL_GPL(dccp_ctl_make_reset); + /* send Reset on established socket, to close or abort the connection */ int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code) { From cecd8d0ec4cb4fec728f67163bb0a78f80c292eb Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 26 Sep 2007 19:36:08 -0300 Subject: [PATCH 1527/2804] [DCCP]: Reduce the number of writable states Since DCCP requires to close both ends of a connection simultaneously, permission to write in state DCCP_CLOSING is removed in dccp_sendmsg(): * if the sending end closed, it would encounter a write error anyhow; * if the other end has closed the connection, it accepts no more data. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/proto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 604de8bfa068..7e4f54a4ecaf 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -664,7 +664,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, * so that the trick in dccp_rcv_request_sent_state_process. */ /* Wait for a connection to finish. */ - if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN | DCCPF_CLOSING)) + if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN)) if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0) goto out_release; From bb293e6a24cc2031f74775d95925e003e7250232 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 26 Sep 2007 19:38:55 -0300 Subject: [PATCH 1528/2804] [CCID3]: Remove ifdef surrounding BUG_ON As suggested by DaveM. Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/ccids/ccid3.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index ae99ec430371..0cdc982cfe47 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -120,9 +120,7 @@ struct ccid3_hc_tx_sock { static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) { struct ccid3_hc_tx_sock *hctx = ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid); -#ifdef CONFIG_IP_DCCP_CCID3_DEBUG BUG_ON(hctx == NULL); -#endif return hctx; } @@ -173,9 +171,7 @@ struct ccid3_hc_rx_sock { static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk) { struct ccid3_hc_rx_sock *hcrx = ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid); -#ifdef CONFIG_IP_DCCP_CCID3_DEBUG BUG_ON(hcrx == NULL); -#endif return hcrx; } From 8b41d1887db718be9a2cd9e18c58ce25a4c7fd93 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:02:53 -0700 Subject: [PATCH 1529/2804] [NET]: Fix running without sysfs When sysfs support is compiled out the kernel still keeps and maintains the kobject tree. So it is not safe to skip our kobject reference counting or to avoid becoming members of the kobject tree. It is safe to not add the networking specific sysfs attributes. This patch removes the sysfs special cases from net/core/dev.c renames functions from netdev_sysfs_xxxx to netdev_kobject_xxxx and always compiles in net-sysfs.c net-sysfs.c is modified with a CONFIG_SYSFS guard around the parts that are actually sysfs specific. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/core/Makefile | 2 +- net/core/dev.c | 28 +++++++++------------------- net/core/net-sysfs.c | 13 ++++++++++--- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/net/core/Makefile b/net/core/Makefile index ea9b3f32d1c0..b1332f6d0042 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -11,7 +11,7 @@ obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \ neighbour.o rtnetlink.o utils.o link_watch.o filter.o obj-$(CONFIG_XFRM) += flow.o -obj-$(CONFIG_SYSFS) += net-sysfs.o +obj-y += net-sysfs.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_NETPOLL) += netpoll.o obj-$(CONFIG_NET_DMA) += user_dma.o diff --git a/net/core/dev.c b/net/core/dev.c index 080d32c4034f..3923d5133050 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -249,15 +249,9 @@ static RAW_NOTIFIER_HEAD(netdev_chain); DEFINE_PER_CPU(struct softnet_data, softnet_data); -#ifdef CONFIG_SYSFS -extern int netdev_sysfs_init(void); -extern int netdev_register_sysfs(struct net_device *); -extern void netdev_unregister_sysfs(struct net_device *); -#else -#define netdev_sysfs_init() (0) -#define netdev_register_sysfs(dev) (0) -#define netdev_unregister_sysfs(dev) do { } while(0) -#endif +extern int netdev_kobject_init(void); +extern int netdev_register_kobject(struct net_device *); +extern void netdev_unregister_kobject(struct net_device *); #ifdef CONFIG_DEBUG_LOCK_ALLOC /* @@ -3575,7 +3569,7 @@ int register_netdevice(struct net_device *dev) if (!dev->rebuild_header) dev->rebuild_header = default_rebuild_header; - ret = netdev_register_sysfs(dev); + ret = netdev_register_kobject(dev); if (ret) goto err_uninit; dev->reg_state = NETREG_REGISTERED; @@ -3838,7 +3832,6 @@ EXPORT_SYMBOL(alloc_netdev_mq); */ void free_netdev(struct net_device *dev) { -#ifdef CONFIG_SYSFS /* Compatibility with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { kfree((char *)dev - dev->padded); @@ -3850,9 +3843,6 @@ void free_netdev(struct net_device *dev) /* will free via device release */ put_device(&dev->dev); -#else - kfree((char *)dev - dev->padded); -#endif } /* Synchronize with packet receive processing. */ @@ -3921,8 +3911,8 @@ void unregister_netdevice(struct net_device *dev) /* Notifier chain MUST detach us from master device. */ BUG_TRAP(!dev->master); - /* Remove entries from sysfs */ - netdev_unregister_sysfs(dev); + /* Remove entries from kobject tree */ + netdev_unregister_kobject(dev); /* Finish processing unregister after unlock */ net_set_todo(dev); @@ -4053,9 +4043,9 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char dev->iflink = dev->ifindex; } - /* Fixup sysfs */ + /* Fixup kobjects */ err = device_rename(&dev->dev, dev->name); - BUG_ON(err); + WARN_ON(err); /* Add the device back in the hashes */ list_netdevice(dev); @@ -4358,7 +4348,7 @@ static int __init net_dev_init(void) if (dev_proc_init()) goto out; - if (netdev_sysfs_init()) + if (netdev_kobject_init()) goto out; INIT_LIST_HEAD(&ptype_all); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 79159db6acb9..909a03d6c0e9 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -18,6 +18,7 @@ #include #include +#ifdef CONFIG_SYSFS static const char fmt_hex[] = "%#x\n"; static const char fmt_long_hex[] = "%#lx\n"; static const char fmt_dec[] = "%d\n"; @@ -392,6 +393,8 @@ static struct attribute_group wireless_group = { }; #endif +#endif /* CONFIG_SYSFS */ + #ifdef CONFIG_HOTPLUG static int netdev_uevent(struct device *d, char **envp, int num_envp, char *buf, int size) @@ -435,7 +438,9 @@ static void netdev_release(struct device *d) static struct class net_class = { .name = "net", .dev_release = netdev_release, +#ifdef CONFIG_SYSFS .dev_attrs = net_class_attributes, +#endif /* CONFIG_SYSFS */ #ifdef CONFIG_HOTPLUG .dev_uevent = netdev_uevent, #endif @@ -444,7 +449,7 @@ static struct class net_class = { /* Delete sysfs entries but hold kobject reference until after all * netdev references are gone. */ -void netdev_unregister_sysfs(struct net_device * net) +void netdev_unregister_kobject(struct net_device * net) { struct device *dev = &(net->dev); @@ -453,7 +458,7 @@ void netdev_unregister_sysfs(struct net_device * net) } /* Create sysfs entries for network device. */ -int netdev_register_sysfs(struct net_device *net) +int netdev_register_kobject(struct net_device *net) { struct device *dev = &(net->dev); struct attribute_group **groups = net->sysfs_groups; @@ -466,6 +471,7 @@ int netdev_register_sysfs(struct net_device *net) BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); strlcpy(dev->bus_id, net->name, BUS_ID_SIZE); +#ifdef CONFIG_SYSFS if (net->get_stats) *groups++ = &netstat_group; @@ -473,11 +479,12 @@ int netdev_register_sysfs(struct net_device *net) if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats) *groups++ = &wireless_group; #endif +#endif /* CONFIG_SYSFS */ return device_add(dev); } -int netdev_sysfs_init(void) +int netdev_kobject_init(void) { return class_register(&net_class); } From 9dd776b6d7b0b85966b6ddd03e2b2aae59012ab1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:04:26 -0700 Subject: [PATCH 1530/2804] [NET]: Add network namespace clone & unshare support. This patch allows you to create a new network namespace using sys_clone, or sys_unshare. As the network namespace is still experimental and under development clone and unshare support is only made available when CONFIG_NET_NS is selected at compile time. As this patch introduces network namespace support into code paths that exist when the CONFIG_NET is not selected there are a few additions made to net_namespace.h to allow a few more functions to be used when the networking stack is not compiled in. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/linux/sched.h | 1 + include/net/net_namespace.h | 18 ++++++++++++++++ kernel/fork.c | 3 ++- kernel/nsproxy.c | 15 +++++++++++-- net/Kconfig | 8 +++++++ net/core/net_namespace.c | 43 +++++++++++++++++++++++++++++++++++-- 6 files changed, 83 insertions(+), 5 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 313c6b6e774f..a4a141055c44 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -27,6 +27,7 @@ #define CLONE_NEWUTS 0x04000000 /* New utsname group? */ #define CLONE_NEWIPC 0x08000000 /* New ipcs */ #define CLONE_NEWUSER 0x10000000 /* New user namespace */ +#define CLONE_NEWNET 0x20000000 /* New network namespace */ /* * Scheduling policies diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index ac8f8304094e..3ea4194613ed 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -38,11 +38,23 @@ extern struct net init_net; extern struct list_head net_namespace_list; +#ifdef CONFIG_NET +extern struct net *copy_net_ns(unsigned long flags, struct net *net_ns); +#else +static inline struct net *copy_net_ns(unsigned long flags, struct net *net_ns) +{ + /* There is nothing to copy so this is a noop */ + return net_ns; +} +#endif + extern void __put_net(struct net *net); static inline struct net *get_net(struct net *net) { +#ifdef CONFIG_NET atomic_inc(&net->count); +#endif return net; } @@ -60,19 +72,25 @@ static inline struct net *maybe_get_net(struct net *net) static inline void put_net(struct net *net) { +#ifdef CONFIG_NET if (atomic_dec_and_test(&net->count)) __put_net(net); +#endif } static inline struct net *hold_net(struct net *net) { +#ifdef CONFIG_NET atomic_inc(&net->use_count); +#endif return net; } static inline void release_net(struct net *net) { +#ifdef CONFIG_NET atomic_dec(&net->use_count); +#endif } extern void net_lock(void); diff --git a/kernel/fork.c b/kernel/fork.c index 33f12f48684a..5e67f90a1694 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1608,7 +1608,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) err = -EINVAL; if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| - CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER)) + CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER| + CLONE_NEWNET)) goto bad_unshare_out; if ((err = unshare_thread(unshare_flags))) diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index a4fb7d46971f..f1decd21a534 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -20,6 +20,7 @@ #include #include #include +#include static struct kmem_cache *nsproxy_cachep; @@ -98,8 +99,17 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, goto out_user; } + new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns); + if (IS_ERR(new_nsp->net_ns)) { + err = PTR_ERR(new_nsp->net_ns); + goto out_net; + } + return new_nsp; +out_net: + if (new_nsp->user_ns) + put_user_ns(new_nsp->user_ns); out_user: if (new_nsp->pid_ns) put_pid_ns(new_nsp->pid_ns); @@ -132,7 +142,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) get_nsproxy(old_ns); - if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER))) + if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWNET))) return 0; if (!capable(CAP_SYS_ADMIN)) { @@ -164,6 +174,7 @@ void free_nsproxy(struct nsproxy *ns) put_pid_ns(ns->pid_ns); if (ns->user_ns) put_user_ns(ns->user_ns); + put_net(ns->net_ns); kmem_cache_free(nsproxy_cachep, ns); } @@ -177,7 +188,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags, int err = 0; if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | - CLONE_NEWUSER))) + CLONE_NEWUSER | CLONE_NEWNET))) return 0; if (!capable(CAP_SYS_ADMIN)) diff --git a/net/Kconfig b/net/Kconfig index cdba08ca2efe..ab4e6da5012f 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -27,6 +27,14 @@ if NET menu "Networking options" +config NET_NS + bool "Network namespace support" + default n + depends on EXPERIMENTAL && !SYSFS + help + Allow user space to create what appear to be multiple instances + of the network stack. + source "net/packet/Kconfig" source "net/unix/Kconfig" source "net/xfrm/Kconfig" diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 0e6cb02d7b77..e478e353ea6b 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -4,6 +4,7 @@ #include #include #include +#include #include /* @@ -32,12 +33,10 @@ void net_unlock(void) mutex_unlock(&net_list_mutex); } -#if 0 static struct net *net_alloc(void) { return kmem_cache_alloc(net_cachep, GFP_KERNEL); } -#endif static void net_free(struct net *net) { @@ -128,6 +127,46 @@ out_undo: goto out; } +struct net *copy_net_ns(unsigned long flags, struct net *old_net) +{ + struct net *new_net = NULL; + int err; + + get_net(old_net); + + if (!(flags & CLONE_NEWNET)) + return old_net; + +#ifndef CONFIG_NET_NS + return ERR_PTR(-EINVAL); +#endif + + err = -ENOMEM; + new_net = net_alloc(); + if (!new_net) + goto out; + + mutex_lock(&net_mutex); + err = setup_net(new_net); + if (err) + goto out_unlock; + + net_lock(); + list_add_tail(&new_net->list, &net_namespace_list); + net_unlock(); + + +out_unlock: + mutex_unlock(&net_mutex); +out: + put_net(old_net); + if (err) { + net_free(new_net); + new_net = ERR_PTR(err); + } + return new_net; +} + static int __init net_ns_init(void) { int err; From 5f6d88b9149d537f3db0798f7d312be632422e15 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:08:12 -0700 Subject: [PATCH 1531/2804] [NET]: Dynamically allocate the per cpu counters for the loopback device. This patch add support for dynamically allocating the statistics counters for the loopback device and adds appropriate device methods for allocating and freeing the loopback device. This completes support for creating multiple instances of the loopback device, in preparation for creating per network namespace instances. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/loopback.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 4b6f7b2abea5..f3018bb7570d 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -62,7 +62,6 @@ struct pcpu_lstats { unsigned long packets; unsigned long bytes; }; -static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats); #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) @@ -134,7 +133,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcpu_lstats *lb_stats; + struct pcpu_lstats *pcpu_lstats, *lb_stats; skb_orphan(skb); @@ -155,7 +154,8 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) dev->last_rx = jiffies; /* it's OK to use __get_cpu_var() because BHs are off */ - lb_stats = &__get_cpu_var(pcpu_lstats); + pcpu_lstats = netdev_priv(dev); + lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); lb_stats->bytes += skb->len; lb_stats->packets++; @@ -166,15 +166,17 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *get_stats(struct net_device *dev) { + const struct pcpu_lstats *pcpu_lstats; struct net_device_stats *stats = &dev->stats; unsigned long bytes = 0; unsigned long packets = 0; int i; + pcpu_lstats = netdev_priv(dev); for_each_possible_cpu(i) { const struct pcpu_lstats *lb_stats; - lb_stats = &per_cpu(pcpu_lstats, i); + lb_stats = per_cpu_ptr(pcpu_lstats, i); bytes += lb_stats->bytes; packets += lb_stats->packets; } @@ -198,6 +200,26 @@ static const struct ethtool_ops loopback_ethtool_ops = { .get_rx_csum = always_on, }; +static int loopback_dev_init(struct net_device *dev) +{ + struct pcpu_lstats *lstats; + + lstats = alloc_percpu(struct pcpu_lstats); + if (!lstats) + return -ENOMEM; + + dev->priv = lstats; + return 0; +} + +static void loopback_dev_free(struct net_device *dev) +{ + struct pcpu_lstats *lstats = netdev_priv(dev); + + free_percpu(lstats); + free_netdev(dev); +} + /* * The loopback device is special. There is only one instance and * it is statically allocated. Don't do this for other devices. @@ -225,6 +247,8 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL, dev->ethtool_ops = &loopback_ethtool_ops; + dev->init = loopback_dev_init; + dev->destructor = loopback_dev_free; } /* Setup and register the loopback device. */ From 5967789dbc8aafdba5813fa8e8cfce3c90516f83 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:09:25 -0700 Subject: [PATCH 1532/2804] [IPV4]: Remove unnecessary test for the loopback device from inetdev_destroy Currently we never call unregister_netdev for the loopback device so it is impossible for us to reach inetdev_destroy with the loopback device. So the test in inetdev_destroy is unnecessary. Further when testing with my network namespace patches removing unregistering the loopback device and calling inetdev_destroy works fine so there appears to be no reason for avoiding unregistering the loopback device. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index affea9b121fc..e7f2b022316e 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -203,8 +203,6 @@ static void inetdev_destroy(struct in_device *in_dev) ASSERT_RTNL(); dev = in_dev->dev; - if (dev == loopback_dev) - return; in_dev->dead = 1; From 0cc217e16cb8ca8ef2544363571fce94259900e0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:10:06 -0700 Subject: [PATCH 1533/2804] [IPV4]: When possible test for IFF_LOOPBACK and not dev == loopback_dev Now that multiple loopback devices are becoming possible it makes the code a little cleaner and more maintainable to test if a deivice is th a loopback device by testing dev->flags & IFF_LOOPBACK instead of dev == loopback_dev. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 4 ++-- net/ipv4/ipconfig.c | 10 +++++++--- net/ipv4/ipvs/ip_vs_core.c | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e7f2b022316e..55d199e4ae21 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1059,7 +1059,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, in_dev = inetdev_init(dev); if (!in_dev) return notifier_from_errno(-ENOMEM); - if (dev == loopback_dev) { + if (dev->flags & IFF_LOOPBACK) { IN_DEV_CONF_SET(in_dev, NOXFRM, 1); IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); } @@ -1075,7 +1075,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, case NETDEV_UP: if (dev->mtu < 68) break; - if (dev == loopback_dev) { + if (dev->flags & IFF_LOOPBACK) { struct in_ifaddr *ifa; if ((ifa = inet_alloc_ifa()) != NULL) { ifa->ifa_local = diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 2d2e0cda0470..af5d5b39fc13 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -190,11 +190,15 @@ static int __init ic_open_devs(void) rtnl_lock(); /* bring loopback device up first */ - if (dev_change_flags(loopback_dev, loopback_dev->flags | IFF_UP) < 0) - printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev->name); + for_each_netdev(&init_net, dev) { + if (!(dev->flags & IFF_LOOPBACK)) + continue; + if (dev_change_flags(dev, dev->flags | IFF_UP) < 0) + printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name); + } for_each_netdev(&init_net, dev) { - if (dev == loopback_dev) + if (dev->flags & IFF_LOOPBACK) continue; if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : (!(dev->flags & IFF_LOOPBACK) && diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 74503267e5d4..fbca2a2ff29f 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -961,7 +961,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff **pskb, * ... don't know why 1st test DOES NOT include 2nd (?) */ if (unlikely(skb->pkt_type != PACKET_HOST - || skb->dev == loopback_dev || skb->sk)) { + || skb->dev->flags & IFF_LOOPBACK || skb->sk)) { IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n", skb->pkt_type, ip_hdr(skb)->protocol, From 2774c7aba6c97a2535be3309a2209770953780b3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:10:56 -0700 Subject: [PATCH 1534/2804] [NET]: Make the loopback device per network namespace. This patch makes loopback_dev per network namespace. Adding code to create a different loopback device for each network namespace and adding the code to free a loopback device when a network namespace exits. This patch modifies all users the loopback_dev so they access it as init_net.loopback_dev, keeping all of the code compiling and working. A later pass will be needed to update the users to use something other than the initial network namespace. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/loopback.c | 26 +++++++++++++++++++++----- include/linux/netdevice.h | 1 - include/net/net_namespace.h | 3 +++ net/core/dst.c | 5 +++-- net/decnet/dn_dev.c | 4 ++-- net/decnet/dn_route.c | 14 +++++++------- net/ipv4/route.c | 18 +++++++++--------- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 18 +++++++++--------- net/ipv6/netfilter/ip6t_REJECT.c | 2 +- net/ipv6/route.c | 12 ++++++------ net/ipv6/xfrm6_policy.c | 2 +- net/xfrm/xfrm_policy.c | 2 +- 13 files changed, 64 insertions(+), 45 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index f3018bb7570d..0f9d8c60c964 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -57,6 +57,7 @@ #include #include #include +#include struct pcpu_lstats { unsigned long packets; @@ -252,7 +253,7 @@ static void loopback_setup(struct net_device *dev) } /* Setup and register the loopback device. */ -static int __init loopback_init(void) +static int loopback_net_init(struct net *net) { struct net_device *dev; int err; @@ -262,12 +263,13 @@ static int __init loopback_init(void) if (!dev) goto out; + dev->nd_net = net; err = register_netdev(dev); if (err) goto out_free_netdev; err = 0; - loopback_dev = dev; + net->loopback_dev = dev; out: if (err) @@ -279,7 +281,21 @@ out_free_netdev: goto out; } -fs_initcall(loopback_init); +static void loopback_net_exit(struct net *net) +{ + struct net_device *dev = net->loopback_dev; -struct net_device *loopback_dev; -EXPORT_SYMBOL(loopback_dev); + unregister_netdev(dev); +} + +static struct pernet_operations loopback_net_ops = { + .init = loopback_net_init, + .exit = loopback_net_exit, +}; + +static int __init loopback_init(void) +{ + return register_pernet_device(&loopback_net_ops); +} + +fs_initcall(loopback_init); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2088097663b5..71cf409ad17e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -742,7 +742,6 @@ struct packet_type { #include #include -extern struct net_device *loopback_dev; /* The loopback */ extern rwlock_t dev_base_lock; /* Device list lock */ diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3ea4194613ed..13b0e3b547f0 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -9,6 +9,7 @@ #include struct proc_dir_entry; +struct net_device; struct net { atomic_t count; /* To decided when the network * namespace should be freed. @@ -23,6 +24,8 @@ struct net { struct proc_dir_entry *proc_net_stat; struct proc_dir_entry *proc_net_root; + struct net_device *loopback_dev; /* The loopback */ + struct list_head dev_base_head; struct hlist_head *dev_name_head; struct hlist_head *dev_index_head; diff --git a/net/core/dst.c b/net/core/dst.c index ad5ffa19d809..16958e64e577 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -18,6 +18,7 @@ #include #include +#include #include /* @@ -278,11 +279,11 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev, if (!unregister) { dst->input = dst->output = dst_discard; } else { - dst->dev = loopback_dev; + dst->dev = init_net.loopback_dev; dev_hold(dst->dev); dev_put(dev); if (dst->neighbour && dst->neighbour->dev == dev) { - dst->neighbour->dev = loopback_dev; + dst->neighbour->dev = init_net.loopback_dev; dev_put(dev); dev_hold(dst->neighbour->dev); } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index bcaf4c5aa68e..26130afd8029 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -869,10 +869,10 @@ last_chance: rv = dn_dev_get_first(dev, addr); read_unlock(&dev_base_lock); dev_put(dev); - if (rv == 0 || dev == loopback_dev) + if (rv == 0 || dev == init_net.loopback_dev) return rv; } - dev = loopback_dev; + dev = init_net.loopback_dev; dev_hold(dev); goto last_chance; } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 96fe0aa1638e..b7ebf9947ebd 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -887,7 +887,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old .scope = RT_SCOPE_UNIVERSE, } }, .mark = oldflp->mark, - .iif = loopback_dev->ifindex, + .iif = init_net.loopback_dev->ifindex, .oif = oldflp->oif }; struct dn_route *rt = NULL; struct net_device *dev_out = NULL, *dev; @@ -904,7 +904,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old "dn_route_output_slow: dst=%04x src=%04x mark=%d" " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), dn_ntohs(oldflp->fld_src), - oldflp->mark, loopback_dev->ifindex, oldflp->oif); + oldflp->mark, init_net.loopback_dev->ifindex, oldflp->oif); /* If we have an output interface, verify its a DECnet device */ if (oldflp->oif) { @@ -957,7 +957,7 @@ source_ok: err = -EADDRNOTAVAIL; if (dev_out) dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); if (!fl.fld_dst) { fl.fld_dst = @@ -966,7 +966,7 @@ source_ok: if (!fl.fld_dst) goto out; } - fl.oif = loopback_dev->ifindex; + fl.oif = init_net.loopback_dev->ifindex; res.type = RTN_LOCAL; goto make_route; } @@ -1012,7 +1012,7 @@ source_ok: if (dev_out) dev_put(dev_out); if (dn_dev_islocal(neigh->dev, fl.fld_dst)) { - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; res.type = RTN_LOCAL; } else { dev_out = neigh->dev; @@ -1033,7 +1033,7 @@ source_ok: /* Possible improvement - check all devices for local addr */ if (dn_dev_islocal(dev_out, fl.fld_dst)) { dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); res.type = RTN_LOCAL; goto select_source; @@ -1069,7 +1069,7 @@ select_source: fl.fld_src = fl.fld_dst; if (dev_out) dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ca2878dc6188..2a9b363e820c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1402,8 +1402,8 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, { struct rtable *rt = (struct rtable *) dst; struct in_device *idev = rt->idev; - if (dev != loopback_dev && idev && idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(loopback_dev); + if (dev != init_net.loopback_dev && idev && idev->dev == dev) { + struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev); if (loopback_idev) { rt->idev = loopback_idev; in_dev_put(idev); @@ -1555,7 +1555,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = loopback_dev; + rth->u.dst.dev = init_net.loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->fl.oif = 0; @@ -1812,7 +1812,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (res.type == RTN_LOCAL) { int result; result = fib_validate_source(saddr, daddr, tos, - loopback_dev->ifindex, + init_net.loopback_dev->ifindex, dev, &spec_dst, &itag); if (result < 0) goto martian_source; @@ -1879,7 +1879,7 @@ local_input: #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = loopback_dev; + rth->u.dst.dev = init_net.loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->rt_gateway = daddr; @@ -2149,7 +2149,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) RT_SCOPE_UNIVERSE), } }, .mark = oldflp->mark, - .iif = loopback_dev->ifindex, + .iif = init_net.loopback_dev->ifindex, .oif = oldflp->oif }; struct fib_result res; unsigned flags = 0; @@ -2243,9 +2243,9 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK); if (dev_out) dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); - fl.oif = loopback_dev->ifindex; + fl.oif = init_net.loopback_dev->ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route; @@ -2290,7 +2290,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) fl.fl4_src = fl.fl4_dst; if (dev_out) dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 29ab3de8c47f..329825ca68fe 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -306,7 +306,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt.idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(loopback_dev); + struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b43574f73375..6d5c3c299148 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2410,7 +2410,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) ASSERT_RTNL(); - if (dev == loopback_dev && how == 1) + if (dev == init_net.loopback_dev && how == 1) how = 0; rt6_ifdown(dev); @@ -4212,19 +4212,19 @@ int __init addrconf_init(void) * device and it being up should be removed. */ rtnl_lock(); - if (!ipv6_add_dev(loopback_dev)) + if (!ipv6_add_dev(init_net.loopback_dev)) err = -ENOMEM; rtnl_unlock(); if (err) return err; - ip6_null_entry.u.dst.dev = loopback_dev; - ip6_null_entry.rt6i_idev = in6_dev_get(loopback_dev); + ip6_null_entry.u.dst.dev = init_net.loopback_dev; + ip6_null_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES - ip6_prohibit_entry.u.dst.dev = loopback_dev; - ip6_prohibit_entry.rt6i_idev = in6_dev_get(loopback_dev); - ip6_blk_hole_entry.u.dst.dev = loopback_dev; - ip6_blk_hole_entry.rt6i_idev = in6_dev_get(loopback_dev); + ip6_prohibit_entry.u.dst.dev = init_net.loopback_dev; + ip6_prohibit_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); + ip6_blk_hole_entry.u.dst.dev = init_net.loopback_dev; + ip6_blk_hole_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); #endif register_netdevice_notifier(&ipv6_dev_notf); @@ -4279,7 +4279,7 @@ void __exit addrconf_cleanup(void) continue; addrconf_ifdown(dev, 1); } - addrconf_ifdown(loopback_dev, 2); + addrconf_ifdown(init_net.loopback_dev, 2); /* * Check hash table. diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 50860531cd3c..3fd08d5567a6 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -167,7 +167,7 @@ static inline void send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum) { if (hooknum == NF_IP6_LOCAL_OUT && skb_in->dev == NULL) - skb_in->dev = loopback_dev; + skb_in->dev = init_net.loopback_dev; icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a7a21a7ba790..6ff19f9eb9ee 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -221,8 +221,8 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; - if (dev != loopback_dev && idev != NULL && idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); + if (dev != init_net.loopback_dev && idev != NULL && idev->dev == dev) { + struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev); if (loopback_idev != NULL) { rt->rt6i_idev = loopback_idev; in6_dev_put(idev); @@ -1185,12 +1185,12 @@ int ip6_route_add(struct fib6_config *cfg) if ((cfg->fc_flags & RTF_REJECT) || (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { /* hold loopback dev/idev if we haven't done so. */ - if (dev != loopback_dev) { + if (dev != init_net.loopback_dev) { if (dev) { dev_put(dev); in6_dev_put(idev); } - dev = loopback_dev; + dev = init_net.loopback_dev; dev_hold(dev); idev = in6_dev_get(dev); if (!idev) { @@ -1894,13 +1894,13 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, if (rt == NULL) return ERR_PTR(-ENOMEM); - dev_hold(loopback_dev); + dev_hold(init_net.loopback_dev); in6_dev_hold(idev); rt->u.dst.flags = DST_HOST; rt->u.dst.input = ip6_input; rt->u.dst.output = ip6_output; - rt->rt6i_dev = loopback_dev; + rt->rt6i_dev = init_net.loopback_dev; rt->rt6i_idev = idev; rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index cc07216cfd59..15aa4c58c315 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -375,7 +375,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt6.rt6i_idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); + struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d6dfd7d1948f..76f172f13f90 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1949,7 +1949,7 @@ static int stale_bundle(struct dst_entry *dst) void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) { while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { - dst->dev = loopback_dev; + dst->dev = init_net.loopback_dev; dev_hold(dst->dev); dev_put(dev); } From 4c94f8c0c9a82fad84bc5df453aff755cfed70b7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 26 Sep 2007 22:11:56 -0700 Subject: [PATCH 1535/2804] [NET]: Remove no longer relevant comment in loopback driver. It talks about __get_cpu_var() which the driver no longer does. Signed-off-by: David S. Miller --- drivers/net/loopback.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 0f9d8c60c964..f11120b7a3b2 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -154,7 +154,6 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif dev->last_rx = jiffies; - /* it's OK to use __get_cpu_var() because BHs are off */ pcpu_lstats = netdev_priv(dev); lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); lb_stats->bytes += skb->len; From 0c4e85813d0a94eeb8bf813397a4907bdd7bb610 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Oct 2007 01:36:32 -0700 Subject: [PATCH 1536/2804] [NET]: Wrap netdevice hardware header creation. Add inline for common usage of hardware header creation, and fix bug in IPV6 mcast where the assumption about negative return is an errno. Negative return from hard_header means not enough space was available,(ie -N bytes). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hamradio/bpqether.c | 2 +- drivers/net/macvlan.c | 4 ++-- drivers/net/pppoe.c | 8 ++++---- drivers/net/wan/lapbether.c | 2 +- include/linux/netdevice.h | 9 +++++++++ include/net/dn_route.h | 3 +-- net/802/p8023.c | 2 +- net/8021q/vlan_dev.c | 14 ++++++-------- net/core/neighbour.c | 17 ++++++++--------- net/core/netpoll.c | 8 +++----- net/decnet/dn_neigh.c | 3 ++- net/econet/af_econet.c | 14 +++++++------- net/ethernet/pe2.c | 4 +--- net/ipv4/arp.c | 3 +-- net/ipv4/ipconfig.c | 4 ++-- net/ipv6/mcast.c | 15 +++++---------- net/packet/af_packet.c | 14 ++++---------- net/sched/sch_teql.c | 5 ++++- net/tipc/eth_media.c | 2 +- 19 files changed, 63 insertions(+), 70 deletions(-) diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index c05bc37df356..4bff23e3b970 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -286,7 +286,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) skb->protocol = ax25_type_trans(skb, dev); skb_reset_network_header(skb); - dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); + dev_hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); bpq->stats.tx_packets++; bpq->stats.tx_bytes+=skb->len; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 2f6cdaa88729..a22087ca968d 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -170,8 +170,8 @@ static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, const struct macvlan_dev *vlan = netdev_priv(dev); struct net_device *lowerdev = vlan->lowerdev; - return lowerdev->hard_header(skb, lowerdev, type, daddr, - saddr ? : dev->dev_addr, len); + return dev_hard_header(skb, lowerdev, type, daddr, + saddr ? : dev->dev_addr, len); } static int macvlan_open(struct net_device *dev) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index d48b7b73d896..8936ed3469cf 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -834,8 +834,8 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, } error = total_len; - dev->hard_header(skb, dev, ETH_P_PPP_SES, - po->pppoe_pa.remote, NULL, total_len); + dev_hard_header(skb, dev, ETH_P_PPP_SES, + po->pppoe_pa.remote, NULL, total_len); memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); @@ -886,8 +886,8 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) skb->protocol = __constant_htons(ETH_P_PPP_SES); skb->dev = dev; - dev->hard_header(skb, dev, ETH_P_PPP_SES, - po->pppoe_pa.remote, NULL, data_len); + dev_hard_header(skb, dev, ETH_P_PPP_SES, + po->pppoe_pa.remote, NULL, data_len); dev_queue_xmit(skb); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 36e683ccae5e..fb37b8095231 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -216,7 +216,7 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb) skb->dev = dev = lapbeth->ethdev; - dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0); + dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0); dev_queue_xmit(skb); } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 71cf409ad17e..b33d084712fa 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -800,6 +800,15 @@ extern int dev_restart(struct net_device *dev); extern int netpoll_trap(void); #endif +static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + void *daddr, void *saddr, unsigned len) +{ + if (!dev->hard_header) + return 0; + return dev->hard_header(skb, dev, type, daddr, saddr, len); +} + typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); static inline int unregister_gifconf(unsigned int family) diff --git a/include/net/dn_route.h b/include/net/dn_route.h index c10e8e7e59a7..60c9f22d8694 100644 --- a/include/net/dn_route.h +++ b/include/net/dn_route.h @@ -100,8 +100,7 @@ static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst, char *src if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) dst = NULL; - if (!dev->hard_header || (dev->hard_header(skb, dev, ETH_P_DNA_RT, - dst, src, skb->len) >= 0)) + if (dev_hard_header(skb, dev, ETH_P_DNA_RT, dst, src, skb->len) >= 0) dn_rt_send(skb); else kfree_skb(skb); diff --git a/net/802/p8023.c b/net/802/p8023.c index 53cf05709283..6ab1835041a7 100644 --- a/net/802/p8023.c +++ b/net/802/p8023.c @@ -31,7 +31,7 @@ static int p8023_request(struct datalink_proto *dl, { struct net_device *dev = skb->dev; - dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); + dev_hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); return dev_queue_xmit(skb); } diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 6644e8f5f199..ca8090fdabbb 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -434,21 +434,19 @@ int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, if (build_vlan_header) { /* Now make the underlying real hard header */ - rc = dev->hard_header(skb, dev, ETH_P_8021Q, daddr, saddr, len + VLAN_HLEN); - - if (rc > 0) { + rc = dev_hard_header(skb, dev, ETH_P_8021Q, daddr, saddr, + len + VLAN_HLEN); + if (rc > 0) rc += VLAN_HLEN; - } else if (rc < 0) { + else if (rc < 0) rc -= VLAN_HLEN; - } - } else { + } else /* If here, then we'll just make a normal looking ethernet frame, * but, the hard_start_xmit method will insert the tag (it has to * be able to do this for bridged and other skbs that don't come * down the protocol stack in an orderly manner. */ - rc = dev->hard_header(skb, dev, type, daddr, saddr, len); - } + rc = dev_hard_header(skb, dev, type, daddr, saddr, len); return rc; } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 2c6577c1eedd..10bcb9f8da5c 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1125,9 +1125,8 @@ int neigh_compat_output(struct sk_buff *skb) __skb_pull(skb, skb_network_offset(skb)); - if (dev->hard_header && - dev->hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, - skb->len) < 0 && + if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, + skb->len) < 0 && dev->rebuild_header(skb)) return 0; @@ -1154,13 +1153,13 @@ int neigh_resolve_output(struct sk_buff *skb) write_lock_bh(&neigh->lock); if (!dst->hh) neigh_hh_init(neigh, dst, dst->ops->protocol); - err = dev->hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + neigh->ha, NULL, skb->len); write_unlock_bh(&neigh->lock); } else { read_lock_bh(&neigh->lock); - err = dev->hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + neigh->ha, NULL, skb->len); read_unlock_bh(&neigh->lock); } if (err >= 0) @@ -1191,8 +1190,8 @@ int neigh_connected_output(struct sk_buff *skb) __skb_pull(skb, skb_network_offset(skb)); read_lock_bh(&neigh->lock); - err = dev->hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + neigh->ha, NULL, skb->len); read_unlock_bh(&neigh->lock); if (err >= 0) err = neigh->ops->queue_xmit(skb); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index e13602d8154d..95daba624967 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -415,11 +415,9 @@ static void arp_reply(struct sk_buff *skb) send_skb->protocol = htons(ETH_P_ARP); /* Fill the device header for the ARP frame */ - - if (np->dev->hard_header && - np->dev->hard_header(send_skb, skb->dev, ptype, - sha, np->local_mac, - send_skb->len) < 0) { + if (dev_hard_header(send_skb, skb->dev, ptype, + sha, np->local_mac, + send_skb->len) < 0) { kfree_skb(send_skb); return; } diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index a424a8ddbaf7..b66e3be3eb84 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -211,7 +211,8 @@ static int dn_neigh_output_packet(struct sk_buff *skb) char mac_addr[ETH_ALEN]; dn_dn2eth(mac_addr, rt->rt_local_src); - if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0) + if (dev_hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, + mac_addr, skb->len) >= 0) return neigh->ops->queue_xmit(skb); if (net_ratelimit()) diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 9938e76a8ff6..9cae16b4e0b7 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -336,6 +336,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, /* Real hardware Econet. We're not worthy etc. */ #ifdef CONFIG_ECONET_NATIVE unsigned short proto = 0; + int res; dev_hold(dev); @@ -354,12 +355,12 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, eb->sec = *saddr; eb->sent = ec_tx_done; - if (dev->hard_header) { - int res; + err = -EINVAL; + res = dev_hard_header(skb, dev, ntohs(proto), &addr, NULL, len); + if (res < 0) + goto out_free; + if (res > 0) { struct ec_framehdr *fh; - err = -EINVAL; - res = dev->hard_header(skb, dev, ntohs(proto), - &addr, NULL, len); /* Poke in our control byte and port number. Hack, hack. */ fh = (struct ec_framehdr *)(skb->data); @@ -368,8 +369,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, if (sock->type != SOCK_DGRAM) { skb_reset_tail_pointer(skb); skb->len = 0; - } else if (res < 0) - goto out_free; + } } /* Copy the data. Returns -EFAULT on error */ diff --git a/net/ethernet/pe2.c b/net/ethernet/pe2.c index 9d57b4fb6440..d60e15d9365e 100644 --- a/net/ethernet/pe2.c +++ b/net/ethernet/pe2.c @@ -12,9 +12,7 @@ static int pEII_request(struct datalink_proto *dl, struct net_device *dev = skb->dev; skb->protocol = htons(ETH_P_IPX); - if (dev->hard_header) - dev->hard_header(skb, dev, ETH_P_IPX, - dest_node, NULL, skb->len); + dev_hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len); return dev_queue_xmit(skb); } diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 3a683006d761..5b24c65b13c6 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -591,8 +591,7 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, /* * Fill the device header for the ARP frame */ - if (dev->hard_header && - dev->hard_header(skb,dev,ptype,dest_hw,src_hw,skb->len) < 0) + if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0) goto out; /* diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index af5d5b39fc13..c5c107a01823 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -757,8 +757,8 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d /* Chain packet down the line... */ skb->dev = dev; skb->protocol = htons(ETH_P_IP); - if ((dev->hard_header && - dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) || + if (dev_hard_header(skb, dev, ntohs(skb->protocol), + dev->broadcast, dev->dev_addr, skb->len) < 0 || dev_queue_xmit(skb) < 0) printk("E"); } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 86d908b1caea..8668ab3af32e 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1438,17 +1438,12 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) static inline int mld_dev_queue_xmit2(struct sk_buff *skb) { struct net_device *dev = skb->dev; + unsigned char ha[MAX_ADDR_LEN]; - if (dev->hard_header) { - unsigned char ha[MAX_ADDR_LEN]; - int err; - - ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1); - err = dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len); - if (err < 0) { - kfree_skb(skb); - return err; - } + ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1); + if (dev_hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len) < 0) { + kfree_skb(skb); + return -EINVAL; } return dev_queue_xmit(skb); } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 745e2cb87c96..c5244b309640 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -765,16 +765,10 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, skb_reserve(skb, LL_RESERVED_SPACE(dev)); skb_reset_network_header(skb); - if (dev->hard_header) { - int res; - err = -EINVAL; - res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); - if (sock->type != SOCK_DGRAM) { - skb_reset_tail_pointer(skb); - skb->len = 0; - } else if (res < 0) - goto out_free; - } + err = -EINVAL; + if (sock->type == SOCK_DGRAM && + dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len) < 0) + goto out_free; /* Returns -EFAULT on error */ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 146f453d7378..d13970f3c7b1 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -232,9 +232,12 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * } if (neigh_event_send(n, skb_res) == 0) { int err; + read_lock(&n->lock); - err = dev->hard_header(skb, dev, ntohs(skb->protocol), n->ha, NULL, skb->len); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + n->ha, NULL, skb->len); read_unlock(&n->lock); + if (err < 0) { neigh_release(n); return -EINVAL; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 1a99e2947145..3bbef2ab22ae 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -77,7 +77,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, skb_reset_network_header(clone); dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev; clone->dev = dev; - dev->hard_header(clone, dev, ETH_P_TIPC, + dev_hard_header(clone, dev, ETH_P_TIPC, &dest->dev_addr.eth_addr, dev->dev_addr, clone->len); dev_queue_xmit(clone); From b95cce3576813ac3f86bafa6b5daaaaf7574b0fe Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 26 Sep 2007 22:13:38 -0700 Subject: [PATCH 1537/2804] [NET]: Wrap hard_header_parse Wrap the hard_header_parse function to simplify next step of header_ops conversion. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/ieee1394/eth1394.c | 10 +++++----- drivers/net/wireless/airo.c | 7 +------ drivers/s390/net/qeth_main.c | 6 +++--- include/linux/netdevice.h | 12 +++++++++++- net/ethernet/eth.c | 4 ++-- net/ipv4/netfilter/ip_queue.c | 6 ++---- net/ipv6/netfilter/ip6_queue.c | 5 +---- net/mac80211/ieee80211.c | 2 +- net/netfilter/nfnetlink_log.c | 11 ++++++----- net/netfilter/nfnetlink_queue.c | 13 ++++++------- net/packet/af_packet.c | 8 ++------ 11 files changed, 40 insertions(+), 44 deletions(-) diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 33b80817d68c..b31f90082e35 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -162,7 +162,8 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); static int ether1394_rebuild_header(struct sk_buff *skb); -static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr); +static int ether1394_header_parse(const struct sk_buff *skb, + unsigned char *haddr); static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh); static void ether1394_header_cache_update(struct hh_cache *hh, struct net_device *dev, @@ -751,11 +752,10 @@ static int ether1394_rebuild_header(struct sk_buff *skb) return 0; } -static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr) +static int ether1394_header_parse(const struct sk_buff *skb, + unsigned char *haddr) { - struct net_device *dev = skb->dev; - - memcpy(haddr, dev->dev_addr, ETH1394_ALEN); + memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN); return ETH1394_ALEN; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 95d3cd1c49a7..cd03a61359aa 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2481,7 +2481,7 @@ void stop_airo_card( struct net_device *dev, int freeres ) EXPORT_SYMBOL(stop_airo_card); -static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) +static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr) { memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); return ETH_ALEN; @@ -2698,11 +2698,6 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) static void wifi_setup(struct net_device *dev) { - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update= NULL; - dev->hard_header_parse = wll_header_parse; dev->hard_start_xmit = &airo_start_xmit11; dev->get_stats = &airo_get_stats; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 8c46978e0afa..65225b3989dd 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -6561,10 +6561,10 @@ static struct ethtool_ops qeth_ethtool_ops = { }; static int -qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr) +qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct qeth_card *card; - struct ethhdr *eth; + const struct qeth_card *card; + const struct ethhdr *eth; card = qeth_get_card_from_dev(skb->dev); if (card->options.layer2) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b33d084712fa..aae9ec367f5d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -657,7 +657,7 @@ struct net_device void (*vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); - int (*hard_header_parse)(struct sk_buff *skb, + int (*hard_header_parse)(const struct sk_buff *skb, unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); #ifdef CONFIG_NETPOLL @@ -809,6 +809,16 @@ static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, return dev->hard_header(skb, dev, type, daddr, saddr, len); } +static inline int dev_parse_header(const struct sk_buff *skb, + unsigned char *haddr) +{ + const struct net_device *dev = skb->dev; + + if (!dev->hard_header_parse) + return 0; + return dev->hard_header_parse(skb, haddr); +} + typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); static inline int unregister_gifconf(unsigned int family) diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 2aaf6faf74ac..bdeb2f0ace32 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -207,9 +207,9 @@ EXPORT_SYMBOL(eth_type_trans); * @skb: packet to extract header from * @haddr: destination buffer */ -static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr) +static int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct ethhdr *eth = eth_hdr(skb); + const struct ethhdr *eth = eth_hdr(skb); memcpy(haddr, eth->h_source, ETH_ALEN); return ETH_ALEN; } diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 82fda92e6b97..aaa3f5c56761 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -250,10 +250,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) if (entry->info->indev && entry->skb->dev) { pmsg->hw_type = entry->skb->dev->type; - if (entry->skb->dev->hard_header_parse) - pmsg->hw_addrlen = - entry->skb->dev->hard_header_parse(entry->skb, - pmsg->hw_addr); + pmsg->hw_addrlen = dev_parse_header(entry->skb, + pmsg->hw_addr); } if (data_len) diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 2f5a52453834..c75f467a8f51 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -248,10 +248,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) if (entry->info->indev && entry->skb->dev) { pmsg->hw_type = entry->skb->dev->type; - if (entry->skb->dev->hard_header_parse) - pmsg->hw_addrlen = - entry->skb->dev->hard_header_parse(entry->skb, - pmsg->hw_addr); + pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr); } if (data_len) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 89be6629cfc0..0cdcf0d0c6ca 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -47,7 +47,7 @@ struct ieee80211_tx_status_rtap_hdr { /* common interface routines */ -static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) +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; diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 8e4001b8f764..332e0f7f6f9e 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -481,12 +481,13 @@ __build_packet_message(struct nfulnl_instance *inst, NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint); } - if (indev && skb->dev && skb->dev->hard_header_parse) { + if (indev && skb->dev) { struct nfulnl_msg_packet_hw phw; - int len = skb->dev->hard_header_parse((struct sk_buff *)skb, - phw.hw_addr); - phw.hw_addrlen = htons(len); - NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); + int len = dev_parse_header(skb, phw.hw_addr); + if (len > 0) { + phw.hw_addrlen = htons(len); + NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); + } } if (skb->tstamp.tv64) { diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index c97369f48db7..a813185c766d 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -485,14 +485,13 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); } - if (indev && entskb->dev - && entskb->dev->hard_header_parse) { + if (indev && entskb->dev) { struct nfqnl_msg_packet_hw phw; - - int len = entskb->dev->hard_header_parse(entskb, - phw.hw_addr); - phw.hw_addrlen = htons(len); - NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); + int len = dev_parse_header(entskb, phw.hw_addr); + if (len) { + phw.hw_addrlen = htons(len); + NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); + } } if (entskb->tstamp.tv64) { diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c5244b309640..c9ee343c2a6c 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -519,10 +519,8 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet sll->sll_ifindex = orig_dev->ifindex; else sll->sll_ifindex = dev->ifindex; - sll->sll_halen = 0; - if (dev->hard_header_parse) - sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + sll->sll_halen = dev_parse_header(skb, sll->sll_addr); PACKET_SKB_CB(skb)->origlen = skb->len; @@ -658,9 +656,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe h->tp_usec = tv.tv_usec; sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); - sll->sll_halen = 0; - if (dev->hard_header_parse) - sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + sll->sll_halen = dev_parse_header(skb, sll->sll_addr); sll->sll_family = AF_PACKET; sll->sll_hatype = dev->type; sll->sll_protocol = skb->protocol; From 3b04ddde02cf1b6f14f2697da5c20eca5715017f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Oct 2007 01:40:57 -0700 Subject: [PATCH 1538/2804] [NET]: Move hardware header operations out of netdevice. Since hardware header operations are part of the protocol class not the device instance, make them into a separate object and save memory. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/ieee1394/eth1394.c | 40 ++++---- drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 +- drivers/isdn/i4l/isdn_net.c | 105 +++++++-------------- drivers/media/dvb/dvb-core/dvb_net.c | 9 +- drivers/net/appletalk/cops.c | 20 +--- drivers/net/appletalk/ltpc.c | 10 -- drivers/net/arcnet/arcnet.c | 18 ++-- drivers/net/hamradio/6pack.c | 13 ++- drivers/net/hamradio/baycom_epp.c | 3 +- drivers/net/hamradio/bpqether.c | 3 +- drivers/net/hamradio/dmascc.c | 3 +- drivers/net/hamradio/hdlcdrv.c | 3 +- drivers/net/hamradio/mkiss.c | 14 ++- drivers/net/hamradio/scc.c | 4 +- drivers/net/hamradio/yam.c | 3 +- drivers/net/loopback.c | 8 +- drivers/net/macvlan.c | 15 ++- drivers/net/myri_sbus.c | 28 ++++-- drivers/net/plip.c | 50 +++++----- drivers/net/shaper.c | 61 +++--------- drivers/net/skfp/skfddi.c | 1 - drivers/net/wan/cycx_x25.c | 31 +++--- drivers/net/wan/dlci.c | 10 +- drivers/net/wan/hdlc.c | 10 +- drivers/net/wan/hdlc_cisco.c | 10 +- drivers/net/wan/hdlc_ppp.c | 2 +- drivers/net/wan/lmc/lmc_proto.c | 2 +- drivers/net/wan/syncppp.c | 19 ++-- drivers/net/wireless/airo.c | 6 +- drivers/net/wireless/hostap/hostap.h | 3 +- drivers/net/wireless/hostap/hostap_hw.c | 3 +- drivers/net/wireless/hostap/hostap_ioctl.c | 5 +- drivers/net/wireless/hostap/hostap_main.c | 43 +++++---- drivers/net/wireless/hostap/hostap_wlan.h | 2 - drivers/net/wireless/strip.c | 13 ++- drivers/s390/net/qeth.h | 3 +- drivers/s390/net/qeth_main.c | 44 +++++---- include/linux/etherdevice.h | 20 ++-- include/linux/if_ether.h | 2 + include/linux/if_shaper.h | 11 --- include/linux/isdn.h | 7 -- include/linux/netdevice.h | 43 +++++---- include/net/ax25.h | 5 +- include/net/pkt_sched.h | 5 +- net/802/fc.c | 11 ++- net/802/fddi.c | 10 +- net/802/hippi.c | 16 ++-- net/802/tr.c | 15 ++- net/8021q/vlan.c | 14 +-- net/8021q/vlan.h | 4 +- net/8021q/vlan_dev.c | 4 +- net/appletalk/dev.c | 4 - net/ax25/ax25_ip.c | 15 ++- net/core/dev.c | 16 ---- net/core/neighbour.c | 11 ++- net/ethernet/eth.c | 36 ++++--- net/ipv4/arp.c | 6 +- net/ipv4/ip_gre.c | 13 ++- net/ipv4/ip_output.c | 2 +- net/ipv6/ndisc.c | 6 +- net/mac80211/ieee80211.c | 12 ++- net/netrom/nr_dev.c | 14 ++- net/packet/af_packet.c | 6 +- net/rose/rose_dev.c | 13 ++- net/sched/sch_teql.c | 6 +- 65 files changed, 479 insertions(+), 473 deletions(-) diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index b31f90082e35..dc9dce22f6a8 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -159,15 +159,16 @@ MODULE_PARM_DESC(max_partial_datagrams, static int ether1394_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); + unsigned short type, const void *daddr, + const void *saddr, unsigned len); static int ether1394_rebuild_header(struct sk_buff *skb); static int ether1394_header_parse(const struct sk_buff *skb, unsigned char *haddr); -static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh); +static int ether1394_header_cache(const struct neighbour *neigh, + struct hh_cache *hh); static void ether1394_header_cache_update(struct hh_cache *hh, - struct net_device *dev, - unsigned char *haddr); + const struct net_device *dev, + const unsigned char *haddr); static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); @@ -507,6 +508,14 @@ static void ether1394_reset_priv(struct net_device *dev, int set_mtu) spin_unlock_irqrestore(&priv->lock, flags); } +static const struct header_ops ether1394_header_ops = { + .create = ether1394_header, + .rebuild = ether1394_rebuild_header, + .cache = ether1394_header_cache, + .cache_update = ether1394_header_cache_update, + .parse = ether1394_header_parse, +}; + static void ether1394_init_dev(struct net_device *dev) { dev->open = ether1394_open; @@ -516,11 +525,7 @@ static void ether1394_init_dev(struct net_device *dev) dev->tx_timeout = ether1394_tx_timeout; dev->change_mtu = ether1394_change_mtu; - dev->hard_header = ether1394_header; - dev->rebuild_header = ether1394_rebuild_header; - dev->hard_header_cache = ether1394_header_cache; - dev->header_cache_update= ether1394_header_cache_update; - dev->hard_header_parse = ether1394_header_parse; + dev->header_ops = ðer1394_header_ops; SET_ETHTOOL_OPS(dev, ðtool_ops); @@ -711,8 +716,8 @@ static void ether1394_host_reset(struct hpsb_host *host) * saddr=NULL means use device source address * daddr=NULL means leave destination address (eg unresolved arp). */ static int ether1394_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); @@ -759,7 +764,8 @@ static int ether1394_header_parse(const struct sk_buff *skb, return ETH1394_ALEN; } -static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh) +static int ether1394_header_cache(const struct neighbour *neigh, + struct hh_cache *hh) { unsigned short type = hh->hh_type; struct net_device *dev = neigh->dev; @@ -778,8 +784,8 @@ static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh) /* Called by Address Resolution module to notify changes in address. */ static void ether1394_header_cache_update(struct hh_cache *hh, - struct net_device *dev, - unsigned char * haddr) + const struct net_device *dev, + const unsigned char * haddr) { memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len); } @@ -899,8 +905,8 @@ static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, } /* Now add the ethernet header. */ - if (dev->hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL, - skb->len) >= 0) + if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL, + skb->len) >= 0) ret = ether1394_type_trans(skb, dev); return ret; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index b1c3d6cd8eba..2bd76ef57154 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -780,7 +780,7 @@ static void ipoib_timeout(struct net_device *dev) static int ipoib_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, unsigned len) { struct ipoib_header *header; @@ -940,6 +940,10 @@ void ipoib_dev_cleanup(struct net_device *dev) priv->tx_ring = NULL; } +static const struct header_ops ipoib_header_ops = { + .create = ipoib_hard_header, +}; + static void ipoib_setup(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -950,7 +954,7 @@ static void ipoib_setup(struct net_device *dev) dev->hard_start_xmit = ipoib_start_xmit; dev->get_stats = ipoib_get_stats; dev->tx_timeout = ipoib_timeout; - dev->hard_header = ipoib_hard_header; + dev->header_ops = &ipoib_header_ops; dev->set_multicast_list = ipoib_set_mcast_list; dev->neigh_setup = ipoib_neigh_setup_dev; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index aa83277aba74..54546604656d 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1873,54 +1873,14 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb) return 0; } -static int -my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) -{ - struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); - - /* - * Set the protocol type. For a packet of type ETH_P_802_3 we - * put the length here instead. It is up to the 802.2 layer to - * carry protocol information. - */ - - if (type != ETH_P_802_3) - eth->h_proto = htons(type); - else - eth->h_proto = htons(len); - - /* - * Set the source hardware address. - */ - if (saddr) - memcpy(eth->h_source, saddr, dev->addr_len); - else - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - - /* - * Anyway, the loopback-device should never use this function... - */ - - if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { - memset(eth->h_dest, 0, dev->addr_len); - return ETH_HLEN /*(dev->hard_header_len)*/; - } - if (daddr) { - memcpy(eth->h_dest, daddr, dev->addr_len); - return ETH_HLEN /*dev->hard_header_len*/; - } - return -ETH_HLEN /*dev->hard_header_len*/; -} - /* * build an header * depends on encaps that is being used. */ -static int -isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned plen) +static int isdn_net_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned plen) { isdn_net_local *lp = dev->priv; unsigned char *p; @@ -1928,7 +1888,7 @@ isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type switch (lp->p_encap) { case ISDN_NET_ENCAP_ETHER: - len = my_eth_header(skb, dev, type, daddr, saddr, plen); + len = eth_header(skb, dev, type, daddr, saddr, plen); break; #ifdef CONFIG_ISDN_PPP case ISDN_NET_ENCAP_SYNCPPP: @@ -2005,6 +1965,32 @@ isdn_net_rebuild_header(struct sk_buff *skb) return ret; } +static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh) +{ + const struct net_device *dev = neigh->dev; + isdn_net_local *lp = dev->priv; + + if (lp->p_encap == ISDN_NET_ENCAP_ETHER) + return eth_header_cache(neigh, hh); + return -1; +} + +static void isdn_header_cache_update(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr) +{ + isdn_net_local *lp = dev->priv; + if (lp->p_encap == ISDN_NET_ENCAP_ETHER) + return eth_header_cache_update(hh, dev, haddr); +} + +static const struct header_ops isdn_header_ops = { + .create = isdn_net_header, + .rebuild = isdn_net_rebuild_header, + .cache = isdn_header_cache, + .cache_update = isdn_header_cache_update, +}; + /* * Interface-setup. (just after registering a new interface) */ @@ -2012,18 +1998,12 @@ static int isdn_net_init(struct net_device *ndev) { ushort max_hlhdr_len = 0; - isdn_net_local *lp = (isdn_net_local *) ndev->priv; - int drvidx, i; + int drvidx; ether_setup(ndev); - lp->org_hhc = ndev->hard_header_cache; - lp->org_hcu = ndev->header_cache_update; + ndev->header_ops = NULL; /* Setup the generic properties */ - - ndev->hard_header = NULL; - ndev->hard_header_cache = NULL; - ndev->header_cache_update = NULL; ndev->mtu = 1500; ndev->flags = IFF_NOARP|IFF_POINTOPOINT; ndev->type = ARPHRD_ETHER; @@ -2032,9 +2012,6 @@ isdn_net_init(struct net_device *ndev) /* for clients with MPPP maybe higher values better */ ndev->tx_queue_len = 30; - for (i = 0; i < ETH_ALEN; i++) - ndev->broadcast[i] = 0xff; - /* The ISDN-specific entries in the device structure. */ ndev->open = &isdn_net_open; ndev->hard_start_xmit = &isdn_net_start_xmit; @@ -2052,7 +2029,6 @@ isdn_net_init(struct net_device *ndev) ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; ndev->stop = &isdn_net_close; ndev->get_stats = &isdn_net_get_stats; - ndev->rebuild_header = &isdn_net_rebuild_header; ndev->do_ioctl = NULL; return 0; } @@ -2861,21 +2837,14 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) } if (cfg->p_encap != lp->p_encap) { if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { - p->dev.hard_header = NULL; - p->dev.hard_header_cache = NULL; - p->dev.header_cache_update = NULL; + p->dev.header_ops = NULL; p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; } else { - p->dev.hard_header = isdn_net_header; - if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) { - p->dev.hard_header_cache = lp->org_hhc; - p->dev.header_cache_update = lp->org_hcu; + p->dev.header_ops = &isdn_header_ops; + if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; - } else { - p->dev.hard_header_cache = NULL; - p->dev.header_cache_update = NULL; + else p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; - } } } lp->p_encap = cfg->p_encap; @@ -3127,8 +3096,6 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave; } else { /* Unregister only if it's a master-device */ - p->dev.hard_header_cache = p->local->org_hhc; - p->dev.header_cache_update = p->local->org_hcu; unregister_netdev(&p->dev); } /* Unlink device from chain */ diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index bdd797071cb0..06800e5a0770 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1225,10 +1225,17 @@ static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) return &((struct dvb_net_priv*) dev->priv)->stats; } +static const struct header_ops dvb_header_ops = { + .create = eth_header, + .parse = eth_header_parse, + .rebuild = eth_rebuild_header, +}; + static void dvb_net_setup(struct net_device *dev) { ether_setup(dev); + dev->header_ops = &dvb_header_ops; dev->open = dvb_net_open; dev->stop = dvb_net_stop; dev->hard_start_xmit = dvb_net_tx; @@ -1237,7 +1244,7 @@ static void dvb_net_setup(struct net_device *dev) dev->set_mac_address = dvb_net_set_mac; dev->mtu = 4096; dev->mc_count = 0; - dev->hard_header_cache = NULL; + dev->flags |= IFF_NOARP; } diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index c4b560d42a67..92c3a4cf0bb1 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -194,10 +194,6 @@ 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 void set_multicast_list (struct net_device *dev); -static int cops_hard_header (struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); - static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static int cops_close (struct net_device *dev); static struct net_device_stats *cops_get_stats (struct net_device *dev); @@ -331,7 +327,6 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; lp = netdev_priv(dev); - memset(lp, 0, sizeof(struct cops_local)); spin_lock_init(&lp->lock); /* Copy local board variable to lp struct. */ @@ -340,7 +335,7 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) dev->hard_start_xmit = cops_send_packet; dev->tx_timeout = cops_timeout; dev->watchdog_timeo = HZ * 2; - dev->hard_header = cops_hard_header; + dev->get_stats = cops_get_stats; dev->open = cops_open; dev->stop = cops_close; @@ -944,19 +939,6 @@ static void set_multicast_list(struct net_device *dev) printk("%s: set_multicast_list executed\n", dev->name); } -/* - * Another Dummy function to keep the Appletalk layer happy. - */ - -static int cops_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) -{ - if(cops_debug >= 3) - printk("%s: cops_hard_header executed. Wow!\n", dev->name); - return 0; -} - /* * System ioctls for the COPS LocalTalk card. */ diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index cb4744e56905..6ab2c2d4d673 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -870,15 +870,6 @@ static void set_multicast_list(struct net_device *dev) /* Actually netatalk needs fixing! */ } -static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - if(debug & DEBUG_VERBOSE) - printk("ltpc_hard_header called for device %s\n", - dev->name); - return 0; -} - static int ltpc_poll_counter; static void ltpc_poll(unsigned long l) @@ -1141,7 +1132,6 @@ struct net_device * __init ltpc_probe(void) /* Fill in the fields of the device structure with ethernet-generic values. */ dev->hard_start_xmit = ltpc_xmit; - dev->hard_header = ltpc_hard_header; dev->get_stats = ltpc_get_stats; /* add the ltpc-specific things */ diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 681e20b8466f..c59c8067de99 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -102,8 +102,8 @@ static int arcnet_close(struct net_device *dev); static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev); static void arcnet_timeout(struct net_device *dev); static int arcnet_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); + unsigned short type, const void *daddr, + const void *saddr, unsigned len); static int arcnet_rebuild_header(struct sk_buff *skb); static struct net_device_stats *arcnet_get_stats(struct net_device *dev); static int go_tx(struct net_device *dev); @@ -317,11 +317,17 @@ static int choose_mtu(void) return mtu == 65535 ? XMTU : mtu; } +static const struct header_ops arcnet_header_ops = { + .create = arcnet_header, + .rebuild = arcnet_rebuild_header, +}; + /* Setup a struct device for ARCnet. */ static void arcdev_setup(struct net_device *dev) { dev->type = ARPHRD_ARCNET; + dev->header_ops = &arcnet_header_ops; dev->hard_header_len = sizeof(struct archdr); dev->mtu = choose_mtu(); @@ -342,8 +348,6 @@ static void arcdev_setup(struct net_device *dev) dev->hard_start_xmit = arcnet_send_packet; dev->tx_timeout = arcnet_timeout; dev->get_stats = arcnet_get_stats; - dev->hard_header = arcnet_header; - dev->rebuild_header = arcnet_rebuild_header; } struct net_device *alloc_arcdev(char *name) @@ -488,10 +492,10 @@ static int arcnet_close(struct net_device *dev) static int arcnet_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { - struct arcnet_local *lp = dev->priv; + const struct arcnet_local *lp = netdev_priv(dev); uint8_t _daddr, proto_num; struct ArcProto *proto; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 0a847326a5e4..ecd156def039 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -288,7 +288,8 @@ static int sp_close(struct net_device *dev) /* Return the frame type ID */ static int sp_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { #ifdef CONFIG_INET if (type != htons(ETH_P_AX25)) @@ -323,6 +324,11 @@ static int sp_rebuild_header(struct sk_buff *skb) #endif } +static const struct header_ops sp_header_ops = { + .create = sp_header, + .rebuild = sp_rebuild_header, +}; + static void sp_setup(struct net_device *dev) { /* Finish setting up the DEVICE info. */ @@ -331,14 +337,15 @@ static void sp_setup(struct net_device *dev) dev->open = sp_open_dev; dev->destructor = free_netdev; dev->stop = sp_close; - dev->hard_header = sp_header; + dev->get_stats = sp_get_stats; dev->set_mac_address = sp_set_mac_address; dev->hard_header_len = AX25_MAX_HEADER_LEN; + dev->header_ops = &sp_header_ops; + dev->addr_len = AX25_ADDR_LEN; dev->type = ARPHRD_AX25; dev->tx_queue_len = 10; - dev->rebuild_header = sp_rebuild_header; dev->tx_timeout = NULL; /* Only activated in AX.25 mode */ diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 355c6cf3d112..1a5a75acf73e 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -1159,8 +1159,7 @@ static void baycom_probe(struct net_device *dev) /* Fill in the fields of the device structure */ bc->skb = NULL; - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; dev->set_mac_address = baycom_set_mac_address; dev->type = ARPHRD_AX25; /* AF_AX25 device */ diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 4bff23e3b970..5ddf8b0c34f9 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -483,8 +483,7 @@ static void bpq_setup(struct net_device *dev) dev->flags = 0; #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; #endif dev->type = ARPHRD_AX25; diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 205f09672492..bc02e4694804 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -581,8 +581,7 @@ static int __init setup_adapter(int card_base, int type, int n) dev->do_ioctl = scc_ioctl; dev->hard_start_xmit = scc_send_packet; dev->get_stats = scc_get_stats; - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; dev->set_mac_address = scc_set_mac_address; } if (register_netdev(info->dev[0])) { diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index b33adc6a340b..ae9629fa6882 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -682,8 +682,7 @@ static void hdlcdrv_setup(struct net_device *dev) s->skb = NULL; - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; dev->set_mac_address = hdlcdrv_set_mac_address; dev->type = ARPHRD_AX25; /* AF_AX25 device */ diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d08fbc396648..9e43c47691ca 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -578,8 +578,9 @@ static int ax_open_dev(struct net_device *dev) #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) /* Return the frame type ID */ -static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int ax_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { #ifdef CONFIG_INET if (type != htons(ETH_P_AX25)) @@ -670,6 +671,11 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev) return &ax->stats; } +static const struct header_ops ax_header_ops = { + .create = ax_header, + .rebuild = ax_rebuild_header, +}; + static void ax_setup(struct net_device *dev) { /* Finish setting up the DEVICE info. */ @@ -683,8 +689,8 @@ static void ax_setup(struct net_device *dev) dev->addr_len = 0; dev->type = ARPHRD_AX25; dev->tx_queue_len = 10; - dev->hard_header = ax_header; - dev->rebuild_header = ax_rebuild_header; + dev->header_ops = &ax_header_ops; + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 39b3b82aa4a4..353d13e543ce 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1551,8 +1551,8 @@ static void scc_net_setup(struct net_device *dev) dev->stop = scc_net_close; dev->hard_start_xmit = scc_net_tx; - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; + dev->set_mac_address = scc_net_set_mac_address; dev->get_stats = scc_net_get_stats; dev->do_ioctl = scc_net_ioctl; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 401724ddafcd..1c942862a3f4 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -1097,8 +1097,7 @@ static void yam_setup(struct net_device *dev) skb_queue_head_init(&yp->send_queue); - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; dev->set_mac_address = yam_set_mac_address; diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index f11120b7a3b2..b6d4ae3ad506 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -221,22 +221,17 @@ static void loopback_dev_free(struct net_device *dev) } /* - * The loopback device is special. There is only one instance and - * it is statically allocated. Don't do this for other devices. + * The loopback device is special. There is only one instance. */ static void loopback_setup(struct net_device *dev) { dev->get_stats = &get_stats; dev->mtu = (16 * 1024) + 20 + 20 + 12; dev->hard_start_xmit = loopback_xmit; - dev->hard_header = eth_header; - dev->hard_header_cache = eth_header_cache; - dev->header_cache_update = eth_header_cache_update; dev->hard_header_len = ETH_HLEN; /* 14 */ dev->addr_len = ETH_ALEN; /* 6 */ dev->tx_queue_len = 0; dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ - dev->rebuild_header = eth_rebuild_header; dev->flags = IFF_LOOPBACK; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST #ifdef LOOPBACK_TSO @@ -247,6 +242,7 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL, dev->ethtool_ops = &loopback_ethtool_ops; + dev->header_ops = ð_header_ops; dev->init = loopback_dev_init; dev->destructor = loopback_dev_free; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index a22087ca968d..b7c81c874f7a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -164,8 +164,8 @@ static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { const struct macvlan_dev *vlan = netdev_priv(dev); struct net_device *lowerdev = vlan->lowerdev; @@ -174,6 +174,15 @@ static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, saddr ? : dev->dev_addr, len); } +static const struct header_ops macvlan_hard_header_ops = { + .create = macvlan_hard_header, + .rebuild = eth_rebuild_header, + .parse = eth_header_parse, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + static int macvlan_open(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -295,9 +304,9 @@ static void macvlan_setup(struct net_device *dev) dev->change_mtu = macvlan_change_mtu; dev->change_rx_flags = macvlan_change_rx_flags; dev->set_multicast_list = macvlan_set_multicast_list; - dev->hard_header = macvlan_hard_header; dev->hard_start_xmit = macvlan_hard_start_xmit; dev->destructor = free_netdev; + dev->header_ops = &macvlan_hard_header_ops, dev->ethtool_ops = &macvlan_ethtool_ops; dev->tx_queue_len = 0; } diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index d68ee51c095f..8d29319cc5cb 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -676,8 +676,9 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) * saddr=NULL means use device source address * daddr=NULL means leave destination address (eg unresolved arp) */ -static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int myri_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); unsigned char *pad = (unsigned char *) skb_push(skb, MYRI_PAD_LEN); @@ -759,18 +760,18 @@ static int myri_rebuild_header(struct sk_buff *skb) return 0; } -int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) +static int myri_header_cache(const struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; unsigned char *pad; struct ethhdr *eth; - struct net_device *dev = neigh->dev; + const struct net_device *dev = neigh->dev; pad = ((unsigned char *) hh->hh_data) + HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN); eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); - if (type == __constant_htons(ETH_P_802_3)) + if (type == htons(ETH_P_802_3)) return -1; /* Refill MyriNet padding identifiers, this is just being anal. */ @@ -786,7 +787,9 @@ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) /* Called by Address Resolution module to notify changes in address. */ -void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) +void myri_header_cache_update(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char * haddr) { memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), haddr, dev->addr_len); @@ -881,6 +884,13 @@ static void dump_eeprom(struct myri_eth *mp) } #endif +static const struct header_ops myri_header_ops = { + .create = myri_header, + .rebuild = myri_rebuild_header, + .cache = myri_header_cache, + .cache_update = myri_header_cache_update, +}; + static int __devinit myri_ether_init(struct sbus_dev *sdev) { static int num; @@ -1065,11 +1075,9 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) dev->mtu = MYRINET_MTU; dev->change_mtu = myri_change_mtu; - dev->hard_header = myri_header; - dev->rebuild_header = myri_rebuild_header; + dev->header_ops = &myri_header_ops; + dev->hard_header_len = (ETH_HLEN + MYRI_PAD_LEN); - dev->hard_header_cache = myri_header_cache; - dev->header_cache_update= myri_header_cache_update; /* Load code onto the LANai. */ DET(("Loading LANAI firmware\n")); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index c17d9ac9ff30..b5e9981d1060 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -148,9 +148,9 @@ static void plip_interrupt(int irq, void *dev_id); /* Functions for DEV methods */ static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev); static int plip_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len); -static int plip_hard_header_cache(struct neighbour *neigh, + unsigned short type, const void *daddr, + const void *saddr, unsigned len); +static int plip_hard_header_cache(const struct neighbour *neigh, struct hh_cache *hh); static int plip_open(struct net_device *dev); static int plip_close(struct net_device *dev); @@ -219,11 +219,6 @@ struct net_local { int is_deferred; int port_owner; int should_relinquish; - int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len); - int (*orig_hard_header_cache)(struct neighbour *neigh, - struct hh_cache *hh); spinlock_t lock; atomic_t kill_timer; struct semaphore killed_timer_sem; @@ -265,6 +260,11 @@ static inline unsigned char read_status (struct net_device *dev) return port->ops->read_status (port); } +static const struct header_ops plip_header_ops = { + .create = plip_hard_header, + .cache = plip_hard_header_cache, +}; + /* Entry point of PLIP driver. Probe the hardware, and register/initialize the driver. @@ -284,17 +284,12 @@ plip_init_netdev(struct net_device *dev) dev->open = plip_open; dev->stop = plip_close; dev->do_ioctl = plip_ioctl; - dev->header_cache_update = NULL; + dev->tx_queue_len = 10; dev->flags = IFF_POINTOPOINT|IFF_NOARP; memset(dev->dev_addr, 0xfc, ETH_ALEN); - /* Set the private structure */ - nl->orig_hard_header = dev->hard_header; - dev->hard_header = plip_hard_header; - - nl->orig_hard_header_cache = dev->hard_header_cache; - dev->hard_header_cache = plip_hard_header_cache; + dev->header_ops = &plip_header_ops; nl->port_owner = 0; @@ -993,14 +988,14 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) } static void -plip_rewrite_address(struct net_device *dev, struct ethhdr *eth) +plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth) { - struct in_device *in_dev; + const struct in_device *in_dev = dev->ip_ptr; - if ((in_dev=dev->ip_ptr) != NULL) { + if (in_dev) { /* Any address will do - we take the first */ - struct in_ifaddr *ifa=in_dev->ifa_list; - if (ifa != NULL) { + const struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa) { memcpy(eth->h_source, dev->dev_addr, 6); memset(eth->h_dest, 0xfc, 2); memcpy(eth->h_dest+2, &ifa->ifa_address, 4); @@ -1010,26 +1005,25 @@ plip_rewrite_address(struct net_device *dev, struct ethhdr *eth) static int plip_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { - struct net_local *nl = netdev_priv(dev); int ret; - if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0) + ret = eth_header(skb, dev, type, daddr, saddr, len); + if (ret >= 0) plip_rewrite_address (dev, (struct ethhdr *)skb->data); return ret; } -int plip_hard_header_cache(struct neighbour *neigh, +int plip_hard_header_cache(const struct neighbour *neigh, struct hh_cache *hh) { - struct net_local *nl = neigh->dev->priv; int ret; - if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0) - { + ret = eth_header_cache(neigh, hh); + if (ret == 0) { struct ethhdr *eth; eth = (struct ethhdr*)(((u8*)hh->hh_data) + diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 315feba7dacc..228f650250f6 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -331,15 +331,16 @@ static int shaper_close(struct net_device *dev) */ static int shaper_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct shaper *sh=dev->priv; int v; if(sh_debug) printk("Shaper header\n"); - skb->dev=sh->dev; - v=sh->hard_header(skb,sh->dev,type,daddr,saddr,len); - skb->dev=dev; + skb->dev = sh->dev; + v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len); + skb->dev = dev; return v; } @@ -351,7 +352,7 @@ static int shaper_rebuild_header(struct sk_buff *skb) if(sh_debug) printk("Shaper rebuild header\n"); skb->dev=sh->dev; - v=sh->rebuild_header(skb); + v = sh->dev->header_ops->rebuild(skb); skb->dev=dev; return v; } @@ -415,51 +416,17 @@ static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) #endif +static const struct header_ops shaper_ops = { + .create = shaper_header, + .rebuild = shaper_rebuild_header, +}; + static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev) { sh->dev = dev; - sh->hard_start_xmit=dev->hard_start_xmit; sh->get_stats=dev->get_stats; - if(dev->hard_header) - { - sh->hard_header=dev->hard_header; - shdev->hard_header = shaper_header; - } - else - shdev->hard_header = NULL; - if(dev->rebuild_header) - { - sh->rebuild_header = dev->rebuild_header; - shdev->rebuild_header = shaper_rebuild_header; - } - else - shdev->rebuild_header = NULL; - -#if 0 - if(dev->hard_header_cache) - { - sh->hard_header_cache = dev->hard_header_cache; - shdev->hard_header_cache= shaper_cache; - } - else - { - shdev->hard_header_cache= NULL; - } - - if(dev->header_cache_update) - { - sh->header_cache_update = dev->header_cache_update; - shdev->header_cache_update = shaper_cache_update; - } - else - shdev->header_cache_update= NULL; -#else - shdev->header_cache_update = NULL; - shdev->hard_header_cache = NULL; -#endif shdev->neigh_setup = shaper_neigh_setup_dev; - shdev->hard_header_len=dev->hard_header_len; shdev->type=dev->type; shdev->addr_len=dev->addr_len; @@ -542,12 +509,6 @@ static void __init shaper_setup(struct net_device *dev) * Handlers for when we attach to a device. */ - dev->hard_header = shaper_header; - dev->rebuild_header = shaper_rebuild_header; -#if 0 - dev->hard_header_cache = shaper_cache; - dev->header_cache_update= shaper_cache_update; -#endif dev->neigh_setup = shaper_neigh_setup_dev; dev->do_ioctl = shaper_ioctl; dev->hard_header_len = 0; diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index ca508708229d..7cf9b9f35dee 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -260,7 +260,6 @@ static int skfp_init_one(struct pci_dev *pdev, dev->set_multicast_list = &skfp_ctl_set_multicast_list; dev->set_mac_address = &skfp_ctl_set_mac_address; dev->do_ioctl = &skfp_ioctl; - dev->header_cache_update = NULL; /* not supported */ SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 46e053106d4d..8a1778cf98d1 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -131,14 +131,15 @@ static int cycx_wan_update(struct wan_device *wandev), cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev); /* Network device interface */ -static int cycx_netdevice_init(struct net_device *dev), - cycx_netdevice_open(struct net_device *dev), - cycx_netdevice_stop(struct net_device *dev), - cycx_netdevice_hard_header(struct sk_buff *skb, - struct net_device *dev, u16 type, - void *daddr, void *saddr, unsigned len), - cycx_netdevice_rebuild_header(struct sk_buff *skb), - cycx_netdevice_hard_start_xmit(struct sk_buff *skb, +static int cycx_netdevice_init(struct net_device *dev); +static int cycx_netdevice_open(struct net_device *dev); +static int cycx_netdevice_stop(struct net_device *dev); +static int cycx_netdevice_hard_header(struct sk_buff *skb, + struct net_device *dev, u16 type, + 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 struct net_device_stats * @@ -468,7 +469,14 @@ static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev) return 0; } + /* Network Device Interface */ + +static const struct header_ops cycx_header_ops = { + .create = cycx_netdevice_hard_header, + .rebuild = cycx_netdevice_rebuild_header, +}; + /* Initialize Linux network interface. * * This routine is called only once for each interface, during Linux network @@ -483,8 +491,8 @@ static int cycx_netdevice_init(struct net_device *dev) /* Initialize device driver entry points */ dev->open = cycx_netdevice_open; dev->stop = cycx_netdevice_stop; - dev->hard_header = cycx_netdevice_hard_header; - dev->rebuild_header = cycx_netdevice_rebuild_header; + dev->header_ops = &cycx_header_ops; + dev->hard_start_xmit = cycx_netdevice_hard_start_xmit; dev->get_stats = cycx_netdevice_get_stats; @@ -554,7 +562,8 @@ static int cycx_netdevice_stop(struct net_device *dev) * Return: media header length. */ static int cycx_netdevice_hard_header(struct sk_buff *skb, struct net_device *dev, u16 type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, + unsigned len) { skb->protocol = type; diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index bc12810157e0..96b232446c0b 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -66,8 +66,8 @@ static void dlci_setup(struct net_device *); */ static int dlci_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { struct frhdr hdr; struct dlci_local *dlp; @@ -485,6 +485,10 @@ static int dlci_ioctl(unsigned int cmd, void __user *arg) return(err); } +static const struct header_ops dlci_header_ops = { + .create = dlci_header, +}; + static void dlci_setup(struct net_device *dev) { struct dlci_local *dlp = dev->priv; @@ -494,7 +498,7 @@ static void dlci_setup(struct net_device *dev) dev->stop = dlci_close; dev->do_ioctl = dlci_dev_ioctl; dev->hard_start_xmit = dlci_transmit; - dev->hard_header = dlci_header; + dev->header_ops = &dlci_header_ops; dev->get_stats = dlci_get_stats; dev->change_mtu = dlci_change_mtu; dev->destructor = free_netdev; diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index ee23b91f23d9..d553e6f32851 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -232,6 +232,8 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; } +static const struct header_ops hdlc_null_ops; + static void hdlc_setup_dev(struct net_device *dev) { /* Re-init all variables changed by HDLC protocol drivers, @@ -243,13 +245,9 @@ static void hdlc_setup_dev(struct net_device *dev) dev->type = ARPHRD_RAWHDLC; dev->hard_header_len = 16; dev->addr_len = 0; - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; + dev->header_ops = &hdlc_null_ops; + dev->change_mtu = hdlc_change_mtu; - dev->hard_header_parse = NULL; } static void hdlc_setup(struct net_device *dev) diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 9ec6cf2e510e..038a6e748bbf 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -74,7 +74,7 @@ static inline struct cisco_state * state(hdlc_device *hdlc) static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, - u16 type, void *daddr, void *saddr, + u16 type, const void *daddr, const void *saddr, unsigned int len) { struct hdlc_header *data; @@ -309,7 +309,6 @@ static void cisco_stop(struct net_device *dev) } - static struct hdlc_proto proto = { .start = cisco_start, .stop = cisco_stop, @@ -317,7 +316,10 @@ static struct hdlc_proto proto = { .ioctl = cisco_ioctl, .module = THIS_MODULE, }; - + +static const struct header_ops cisco_header_ops = { + .create = cisco_hard_header, +}; static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) { @@ -365,7 +367,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) memcpy(&state(hdlc)->settings, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; - dev->hard_header = cisco_hard_header; + dev->header_ops = &cisco_header_ops; dev->type = ARPHRD_CISCO; netif_dormant_on(dev); return 0; diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 4591437dd2f3..3caeb528eace 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -73,7 +73,7 @@ static void ppp_close(struct net_device *dev) sppp_close(dev); sppp_detach(dev); - dev->rebuild_header = NULL; + dev->change_mtu = state(hdlc)->old_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->hard_header_len = 16; diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c index 31e1799571ad..426c0678d983 100644 --- a/drivers/net/wan/lmc/lmc_proto.c +++ b/drivers/net/wan/lmc/lmc_proto.c @@ -111,7 +111,7 @@ void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/ * They set a few basics because they don't use sync_ppp */ dev->flags |= IFF_POINTOPOINT; - dev->hard_header = NULL; + dev->hard_header_len = 0; dev->addr_len = 0; } diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 5c71af6ea3a5..232ecba5340f 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -359,8 +359,10 @@ done: * Handle transmit packets. */ -static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type, - void *daddr, void *saddr, unsigned int len) +static int sppp_hard_header(struct sk_buff *skb, + struct net_device *dev, __u16 type, + const void *daddr, const void *saddr, + unsigned int len) { struct sppp *sp = (struct sppp *)sppp_of(dev); struct ppp_header *h; @@ -392,10 +394,9 @@ static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 t return sizeof(struct ppp_header); } -static int sppp_rebuild_header(struct sk_buff *skb) -{ - return 0; -} +static const struct header_ops sppp_header_ops = { + .create = sppp_hard_header, +}; /* * Send keepalive packets, every 10 seconds. @@ -1098,8 +1099,8 @@ void sppp_attach(struct ppp_device *pd) * hard_start_xmit. */ - dev->hard_header = sppp_hard_header; - dev->rebuild_header = sppp_rebuild_header; + dev->header_ops = &sppp_header_ops; + dev->tx_queue_len = 10; dev->type = ARPHRD_HDLC; dev->addr_len = 0; @@ -1115,8 +1116,6 @@ void sppp_attach(struct ppp_device *pd) dev->stop = sppp_close; #endif dev->change_mtu = sppp_change_mtu; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index cd03a61359aa..074055e18c5c 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2696,9 +2696,13 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) return rc; } +static const struct header_ops airo_header_ops = { + .parse = wll_header_parse, +}; + static void wifi_setup(struct net_device *dev) { - dev->hard_header_parse = wll_header_parse; + dev->header_ops = &airo_header_ops; dev->hard_start_xmit = &airo_start_xmit11; dev->get_stats = &airo_get_stats; dev->set_mac_address = &airo_set_mac_address; diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index ef37a75d550b..951df83702f9 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -30,8 +30,7 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx); void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx); -int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr); -int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr); +extern const struct header_ops hostap_80211_ops; int hostap_80211_get_hdrlen(u16 fc); struct net_device_stats *hostap_get_stats(struct net_device *dev); void hostap_setup_dev(struct net_device *dev, local_info_t *local, diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 7fa7ab0a4b23..b20bb013d57e 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3258,11 +3258,10 @@ while (0) INIT_LIST_HEAD(&local->bss_list); hostap_setup_dev(dev, local, 1); - local->saved_eth_header_parse = dev->hard_header_parse; dev->hard_start_xmit = hostap_master_start_xmit; dev->type = ARPHRD_IEEE80211; - dev->hard_header_parse = hostap_80211_header_parse; + dev->header_ops = &hostap_80211_ops; rtnl_lock(); ret = dev_alloc_name(dev, "wifi%d"); diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 7036ecff5ec1..40f516d42c5e 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -897,11 +897,8 @@ static void hostap_monitor_set_type(local_info_t *local) if (local->monitor_type == PRISM2_MONITOR_PRISM || local->monitor_type == PRISM2_MONITOR_CAPHDR) { dev->type = ARPHRD_IEEE80211_PRISM; - dev->hard_header_parse = - hostap_80211_prism_header_parse; } else { dev->type = ARPHRD_IEEE80211; - dev->hard_header_parse = hostap_80211_header_parse; } } @@ -1141,7 +1138,7 @@ static int hostap_monitor_mode_disable(local_info_t *local) printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); dev->type = ARPHRD_ETHER; - dev->hard_header_parse = local->saved_eth_header_parse; + if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | (HFA384X_TEST_STOP << 8), 0, NULL, NULL)) diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 4cb09d81b404..b75cf9205ce0 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -594,24 +594,27 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) } -int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr) +int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} + struct hostap_interface *iface = netdev_priv(skb->dev); + local_info_t *local = iface->local; + if (local->monitor_type == PRISM2_MONITOR_PRISM || + local->monitor_type == PRISM2_MONITOR_CAPHDR) { + const unsigned char *mac = skb_mac_header(skb); -int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr) -{ - const unsigned char *mac = skb_mac_header(skb); + if (*(u32 *)mac == LWNG_CAP_DID_BASE) { + memcpy(haddr, + mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10, + ETH_ALEN); /* addr2 */ + } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */ + memcpy(haddr, + mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10, + ETH_ALEN); /* addr2 */ + } + } else + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - if (*(u32 *)mac == LWNG_CAP_DID_BASE) { - memcpy(haddr, mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10, - ETH_ALEN); /* addr2 */ - } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */ - memcpy(haddr, mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10, - ETH_ALEN); /* addr2 */ - } return ETH_ALEN; } @@ -843,6 +846,15 @@ static void prism2_tx_timeout(struct net_device *dev) local->func->schedule_reset(local); } +const struct header_ops hostap_80211_ops = { + .create = eth_header, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, + + .parse = hostap_80211_header_parse, +}; +EXPORT_SYMBOL(hostap_80211_ops); void hostap_setup_dev(struct net_device *dev, local_info_t *local, int main_dev) @@ -883,7 +895,6 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, netif_stop_queue(dev); } - static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) { struct net_device *dev = local->dev; @@ -901,7 +912,7 @@ static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) local->apdev->hard_start_xmit = hostap_mgmt_start_xmit; local->apdev->type = ARPHRD_IEEE80211; - local->apdev->hard_header_parse = hostap_80211_header_parse; + local->apdev->header_ops = &hostap_80211_ops; return 0; } diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index a42325c145b4..c27b2c1c06af 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -736,8 +736,6 @@ struct local_info { PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, PRISM2_MONITOR_CAPHDR = 2 } monitor_type; - int (*saved_eth_header_parse)(struct sk_buff *skb, - unsigned char *haddr); int monitor_allow_fcserr; int hostapd; /* whether user space daemon, hostapd, is used for AP diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 404cd1512312..4bd14b331862 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1631,8 +1631,8 @@ static void strip_IdleTask(unsigned long parameter) */ static int strip_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { struct strip *strip_info = netdev_priv(dev); STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header)); @@ -2497,6 +2497,11 @@ static int strip_close_low(struct net_device *dev) return 0; } +static const struct header_ops strip_header_ops = { + .create = strip_header, + .rebuild = strip_rebuild_header, +}; + /* * This routine is called by DDI when the * (dynamically assigned) device is registered @@ -2531,8 +2536,8 @@ static void strip_dev_setup(struct net_device *dev) dev->open = strip_open_low; dev->stop = strip_close_low; dev->hard_start_xmit = strip_xmit; - dev->hard_header = strip_header; - dev->rebuild_header = strip_rebuild_header; + dev->header_ops = &strip_header_ops; + dev->set_mac_address = strip_set_mac_address; dev->get_stats = strip_get_stats; dev->change_mtu = strip_change_mtu; diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 6d4959807abc..8c6b72d05b1d 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -833,8 +833,7 @@ struct qeth_card { struct qeth_qdio_info qdio; struct qeth_perf_stats perf_stats; int use_hard_stop; - int (*orig_hard_header)(struct sk_buff *,struct net_device *, - unsigned short,void *,void *,unsigned); + const struct header_ops *orig_header_ops; struct qeth_osn_info osn_info; atomic_t force_alloc_skb; }; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 65225b3989dd..778ddfb99077 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -160,6 +160,9 @@ qeth_set_multicast_list(struct net_device *); static void qeth_setadp_promisc_mode(struct qeth_card *); +static int +qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr); + static void qeth_notify_processes(void) { @@ -3787,8 +3790,8 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype) /*hard_header fake function; used in case fake_ll is set */ static int qeth_fake_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, const void *saddr, + unsigned len) { if(dev->type == ARPHRD_IEEE802_TR){ struct trh_hdr *hdr; @@ -3811,6 +3814,11 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev, } } +static const struct header_ops qeth_fake_ops = { + .create = qeth_fake_header, + .parse = qeth_hard_header_parse, +}; + static int qeth_send_packet(struct qeth_card *, struct sk_buff *); @@ -4649,7 +4657,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) [qeth_get_priority_queue(card, skb, ipv, cast_type)]; if (!card->options.layer2) { ipv = qeth_get_ip_version(skb); - if ((card->dev->hard_header == qeth_fake_header) && ipv) { + if ((card->dev->header_ops == &qeth_fake_ops) && ipv) { new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC); if (!new_skb) return -ENOMEM; @@ -6566,6 +6574,9 @@ qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr) const struct qeth_card *card; const struct ethhdr *eth; + if (dev->type != ARPHRD_IEEE802_TR) + return 0; + card = qeth_get_card_from_dev(skb->dev); if (card->options.layer2) goto haveheader; @@ -6596,6 +6607,10 @@ haveheader: return ETH_ALEN; } +static const struct header_ops qeth_null_ops = { + .parse = qeth_hard_header_parse, +}; + static int qeth_netdev_init(struct net_device *dev) { @@ -6620,12 +6635,8 @@ qeth_netdev_init(struct net_device *dev) dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid; dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid; #endif - if (qeth_get_netdev_flags(card) & IFF_NOARP) { - dev->rebuild_header = NULL; - dev->hard_header = NULL; - dev->header_cache_update = NULL; - dev->hard_header_cache = NULL; - } + dev->header_ops = &qeth_null_ops; + #ifdef CONFIG_QETH_IPV6 /*IPv6 address autoconfiguration stuff*/ if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) @@ -6633,11 +6644,8 @@ qeth_netdev_init(struct net_device *dev) #endif if (card->options.fake_ll && (qeth_get_netdev_flags(card) & IFF_NOARP)) - dev->hard_header = qeth_fake_header; - if (dev->type == ARPHRD_IEEE802_TR) - dev->hard_header_parse = NULL; - else - dev->hard_header_parse = qeth_hard_header_parse; + dev->header_ops = &qeth_fake_ops; + dev->set_mac_address = qeth_layer2_set_mac_address; dev->flags |= qeth_get_netdev_flags(card); if ((card->options.fake_broadcast) || @@ -6740,10 +6748,10 @@ retry: } /*network device will be recovered*/ if (card->dev) { - card->dev->hard_header = card->orig_hard_header; + card->dev->header_ops = card->orig_header_ops; if (card->options.fake_ll && (qeth_get_netdev_flags(card) & IFF_NOARP)) - card->dev->hard_header = qeth_fake_header; + card->dev->header_ops = &qeth_fake_ops; return 0; } /* at first set_online allocate netdev */ @@ -6757,7 +6765,7 @@ retry: goto out; } card->dev->priv = card; - card->orig_hard_header = card->dev->hard_header; + card->orig_header_ops = card->dev->header_ops; card->dev->type = qeth_get_arphdr_type(card->info.type, card->info.link_type); card->dev->init = qeth_netdev_init; @@ -8308,7 +8316,7 @@ qeth_arp_constructor(struct neighbour *neigh) if (card == NULL) goto out; if((card->options.layer2) || - (card->dev->hard_header == qeth_fake_header)) + (card->dev->header_ops == &qeth_fake_ops)) goto out; rcu_read_lock(); diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 6cdb97365e47..b7558ec81ed5 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -29,15 +29,19 @@ #include #ifdef __KERNEL__ -extern int eth_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len); -extern int eth_rebuild_header(struct sk_buff *skb); extern __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); -extern void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, - unsigned char * haddr); -extern int eth_header_cache(struct neighbour *neigh, - struct hh_cache *hh); +extern const struct header_ops eth_header_ops; + +extern int eth_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len); +extern int eth_rebuild_header(struct sk_buff *skb); +extern int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr); +extern int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh); +extern void eth_header_cache_update(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr); + extern struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count); #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1) diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 0e791e2c0c5a..5f9297793661 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -117,6 +117,8 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) return (struct ethhdr *)skb_mac_header(skb); } +int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr); + #ifdef CONFIG_SYSCTL extern struct ctl_table ether_table[]; #endif diff --git a/include/linux/if_shaper.h b/include/linux/if_shaper.h index 51574743aa1b..3b1b7ba19825 100644 --- a/include/linux/if_shaper.h +++ b/include/linux/if_shaper.h @@ -25,17 +25,6 @@ struct shaper an empty queue */ spinlock_t lock; struct net_device *dev; - int (*hard_start_xmit) (struct sk_buff *skb, - struct net_device *dev); - int (*hard_header) (struct sk_buff *skb, - struct net_device *dev, - unsigned short type, - void *daddr, - void *saddr, - unsigned len); - int (*rebuild_header)(struct sk_buff *skb); - int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh); - void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr); struct net_device_stats* (*get_stats)(struct net_device *dev); struct timer_list timer; }; diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 3c7875b7ab5b..a6fb366748bb 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -353,13 +353,6 @@ typedef struct isdn_net_local_s { /* a particular channel (including */ /* the frame_cnt */ - int (*org_hhc)( - struct neighbour *neigh, - struct hh_cache *hh); - /* Ptr to orig. header_cache_update */ - void (*org_hcu)(struct hh_cache *, - struct net_device *, - unsigned char *); int pppbind; /* ippp device for bindings */ int dialtimeout; /* How long shall we try on dialing? (jiffies) */ int dialwait; /* How long shall we wait after failed attempt? (jiffies) */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index aae9ec367f5d..91cd3f3db507 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -250,6 +250,19 @@ struct hh_cache #define LL_RESERVED_SPACE_EXTRA(dev,extra) \ ((((dev)->hard_header_len+extra)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD) +struct header_ops { + int (*create) (struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len); + int (*parse)(const struct sk_buff *skb, unsigned char *haddr); + int (*rebuild)(struct sk_buff *skb); +#define HAVE_HEADER_CACHE + int (*cache)(const struct neighbour *neigh, struct hh_cache *hh); + void (*cache_update)(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr); +}; + /* These flag bits are private to the generic network queueing * layer, they may not be explicitly referenced by any other * code. @@ -492,6 +505,9 @@ struct net_device #endif const struct ethtool_ops *ethtool_ops; + /* Hardware header description */ + const struct header_ops *header_ops; + /* * This marks the end of the "visible" part of the structure. All * fields hereafter are internal to the system, and may change at @@ -615,13 +631,6 @@ struct net_device int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev); #define HAVE_NETDEV_POLL - int (*hard_header) (struct sk_buff *skb, - struct net_device *dev, - unsigned short type, - void *daddr, - void *saddr, - unsigned len); - int (*rebuild_header)(struct sk_buff *skb); #define HAVE_CHANGE_RX_FLAGS void (*change_rx_flags)(struct net_device *dev, int flags); @@ -638,12 +647,6 @@ struct net_device #define HAVE_SET_CONFIG int (*set_config)(struct net_device *dev, struct ifmap *map); -#define HAVE_HEADER_CACHE - int (*hard_header_cache)(struct neighbour *neigh, - struct hh_cache *hh); - void (*header_cache_update)(struct hh_cache *hh, - struct net_device *dev, - unsigned char * haddr); #define HAVE_CHANGE_MTU int (*change_mtu)(struct net_device *dev, int new_mtu); @@ -657,8 +660,6 @@ struct net_device void (*vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); - int (*hard_header_parse)(const struct sk_buff *skb, - unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); #ifdef CONFIG_NETPOLL struct netpoll_info *npinfo; @@ -802,11 +803,13 @@ extern int netpoll_trap(void); static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, + unsigned len) { - if (!dev->hard_header) + if (!dev->header_ops) return 0; - return dev->hard_header(skb, dev, type, daddr, saddr, len); + + return dev->header_ops->create(skb, dev, type, daddr, saddr, len); } static inline int dev_parse_header(const struct sk_buff *skb, @@ -814,9 +817,9 @@ static inline int dev_parse_header(const struct sk_buff *skb, { const struct net_device *dev = skb->dev; - if (!dev->hard_header_parse) + if (!dev->header_ops->parse) return 0; - return dev->hard_header_parse(skb, haddr); + return dev->header_ops->parse(skb, haddr); } typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); diff --git a/include/net/ax25.h b/include/net/ax25.h index 99a4e364c74a..4e3cd93f81fc 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -363,8 +363,11 @@ extern int ax25_rx_iframe(ax25_cb *, struct sk_buff *); extern int ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); /* ax25_ip.c */ -extern int ax25_hard_header(struct sk_buff *, struct net_device *, unsigned short, void *, void *, unsigned int); +extern int ax25_hard_header(struct sk_buff *, struct net_device *, + unsigned short, const void *, + const void *, unsigned int); extern int ax25_rebuild_header(struct sk_buff *); +extern const struct header_ops ax25_header_ops; /* ax25_out.c */ extern ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct net_device *); diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 9e22526e80e7..ab61809a9616 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -97,10 +97,9 @@ extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, /* Calculate maximal size of packet seen by hard_start_xmit routine of this device. */ -static inline unsigned psched_mtu(struct net_device *dev) +static inline unsigned psched_mtu(const struct net_device *dev) { - unsigned mtu = dev->mtu; - return dev->hard_header ? mtu + dev->hard_header_len : mtu; + return dev->mtu + dev->hard_header_len; } #endif diff --git a/net/802/fc.c b/net/802/fc.c index 675d9ba8e591..cb3475ea6fda 100644 --- a/net/802/fc.c +++ b/net/802/fc.c @@ -35,7 +35,7 @@ static int fc_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, unsigned len) { struct fch_hdr *fch; int hdr_len; @@ -95,11 +95,14 @@ static int fc_rebuild_header(struct sk_buff *skb) #endif } +static const struct header_ops fc_header_ops = { + .create = fc_header, + .rebuild = fc_rebuild_header, +}; + static void fc_setup(struct net_device *dev) { - dev->hard_header = fc_header; - dev->rebuild_header = fc_rebuild_header; - + dev->header_ops = &fc_header_ops; dev->type = ARPHRD_IEEE802; dev->hard_header_len = FC_HLEN; dev->mtu = 2024; diff --git a/net/802/fddi.c b/net/802/fddi.c index 91dde41b5481..0549317b9356 100644 --- a/net/802/fddi.c +++ b/net/802/fddi.c @@ -52,7 +52,7 @@ static int fddi_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, unsigned len) { int hl = FDDI_K_SNAP_HLEN; struct fddihdr *fddi; @@ -175,11 +175,15 @@ static int fddi_change_mtu(struct net_device *dev, int new_mtu) return(0); } +static const struct header_ops fddi_header_ops = { + .create = fddi_header, + .rebuild = fddi_rebuild_header, +}; + static void fddi_setup(struct net_device *dev) { dev->change_mtu = fddi_change_mtu; - dev->hard_header = fddi_header; - dev->rebuild_header = fddi_rebuild_header; + dev->header_ops = &fddi_header_ops; dev->type = ARPHRD_FDDI; dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ diff --git a/net/802/hippi.c b/net/802/hippi.c index 87ffc12b6891..e35dc1e0915d 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c @@ -45,8 +45,8 @@ */ static int hippi_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct hippi_hdr *hip = (struct hippi_hdr *)skb_push(skb, HIPPI_HLEN); struct hippi_cb *hcb = (struct hippi_cb *) skb->cb; @@ -182,16 +182,18 @@ static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) return 0; } +static const struct header_ops hippi_header_ops = { + .create = hippi_header, + .rebuild = hippi_rebuild_header, +}; + + static void hippi_setup(struct net_device *dev) { dev->set_multicast_list = NULL; dev->change_mtu = hippi_change_mtu; - dev->hard_header = hippi_header; - dev->rebuild_header = hippi_rebuild_header; + dev->header_ops = &hippi_header_ops; dev->set_mac_address = hippi_mac_addr; - dev->hard_header_parse = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; dev->neigh_setup = hippi_neigh_setup_dev; /* diff --git a/net/802/tr.c b/net/802/tr.c index aa3c2e936abc..a2bd0f2e3af8 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -100,7 +100,7 @@ static inline unsigned long rif_hash(const unsigned char *addr) static int tr_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, unsigned len) { struct trh_hdr *trh; int hdr_len; @@ -142,7 +142,7 @@ static int tr_header(struct sk_buff *skb, struct net_device *dev, if(daddr) { memcpy(trh->daddr,daddr,dev->addr_len); - tr_source_route(skb,trh,dev); + tr_source_route(skb, trh, dev); return(hdr_len); } @@ -247,7 +247,8 @@ __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev) * We try to do source routing... */ -void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_device *dev) +void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh, + struct net_device *dev) { int slack; unsigned int hash; @@ -592,14 +593,18 @@ static const struct file_operations rif_seq_fops = { #endif +static const struct header_ops tr_header_ops = { + .create = tr_header, + .rebuild= tr_rebuild_header, +}; + static void tr_setup(struct net_device *dev) { /* * Configure and register */ - dev->hard_header = tr_header; - dev->rebuild_header = tr_rebuild_header; + dev->header_ops = &tr_header_ops; dev->type = ARPHRD_IEEE802_TR; dev->hard_header_len = TR_HLEN; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 4d003e391754..f2bee234d361 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -314,6 +314,12 @@ int unregister_vlan_device(struct net_device *dev) */ static struct lock_class_key vlan_netdev_xmit_lock_key; +static const struct header_ops vlan_header_ops = { + .create = vlan_dev_hard_header, + .rebuild = vlan_dev_rebuild_header, + .parse = eth_header_parse, +}; + static int vlan_dev_init(struct net_device *dev) { struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; @@ -331,18 +337,14 @@ static int vlan_dev_init(struct net_device *dev) memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len); if (real_dev->features & NETIF_F_HW_VLAN_TX) { - dev->hard_header = real_dev->hard_header; + dev->header_ops = real_dev->header_ops; dev->hard_header_len = real_dev->hard_header_len; dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit; - dev->rebuild_header = real_dev->rebuild_header; } else { - dev->hard_header = vlan_dev_hard_header; + dev->header_ops = &vlan_header_ops; dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; dev->hard_start_xmit = vlan_dev_hard_start_xmit; - dev->rebuild_header = vlan_dev_rebuild_header; } - dev->hard_header_parse = real_dev->hard_header_parse; - dev->hard_header_cache = NULL; lockdep_set_class(&dev->_xmit_lock, &vlan_netdev_xmit_lock_key); return 0; diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 7df5b2935579..cf4a80d06b35 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -53,8 +53,8 @@ int vlan_dev_rebuild_header(struct sk_buff *skb); int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev); int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); + unsigned short type, const void *daddr, + const void *saddr, unsigned len); int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); int vlan_dev_change_mtu(struct net_device *dev, int new_mtu); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index ca8090fdabbb..1a1740aa9a8b 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -343,8 +343,8 @@ static inline unsigned short vlan_dev_get_egress_qos_mask(struct net_device* dev * physical devices. */ int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct vlan_hdr *vhdr; unsigned short veth_TCI = 0; diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c index 9e4dffc1e423..d856a62ab50f 100644 --- a/net/appletalk/dev.c +++ b/net/appletalk/dev.c @@ -24,11 +24,7 @@ static void ltalk_setup(struct net_device *dev) /* Fill in the fields of the device structure with localtalk-generic values. */ dev->change_mtu = ltalk_change_mtu; - dev->hard_header = NULL; - dev->rebuild_header = NULL; dev->set_mac_address = ltalk_mac_addr; - dev->hard_header_cache = NULL; - dev->header_cache_update= NULL; dev->type = ARPHRD_LOCALTLK; dev->hard_header_len = LTALK_HLEN; diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index 930e4918037f..f047a57aa95c 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -46,7 +46,9 @@ #ifdef CONFIG_INET -int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) +int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { unsigned char *buff; @@ -215,7 +217,9 @@ put: #else /* INET */ -int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) +int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { return -AX25_HEADER_LEN; } @@ -227,5 +231,12 @@ int ax25_rebuild_header(struct sk_buff *skb) #endif +const struct header_ops ax25_header_ops = { + .create = ax25_hard_header, + .rebuild = ax25_rebuild_header, +}; + EXPORT_SYMBOL(ax25_hard_header); EXPORT_SYMBOL(ax25_rebuild_header); +EXPORT_SYMBOL(ax25_header_ops); + diff --git a/net/core/dev.c b/net/core/dev.c index 3923d5133050..d99864662582 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -967,14 +967,6 @@ void dev_load(struct net *net, const char *name) request_module("%s", name); } -static int default_rebuild_header(struct sk_buff *skb) -{ - printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n", - skb->dev ? skb->dev->name : "NULL!!!"); - kfree_skb(skb); - return 1; -} - /** * dev_open - prepare an interface for use. * @dev: device to open @@ -3561,14 +3553,6 @@ int register_netdevice(struct net_device *dev) } } - /* - * nil rebuild_header routine, - * that should be never called and used as just bug trap. - */ - - if (!dev->rebuild_header) - dev->rebuild_header = default_rebuild_header; - ret = netdev_register_kobject(dev); if (ret) goto err_uninit; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 10bcb9f8da5c..c52df858d0be 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -897,8 +897,8 @@ out_unlock_bh: static void neigh_update_hhs(struct neighbour *neigh) { struct hh_cache *hh; - void (*update)(struct hh_cache*, struct net_device*, unsigned char *) = - neigh->dev->header_cache_update; + void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *) + = neigh->dev->header_ops->cache_update; if (update) { for (hh = neigh->hh; hh; hh = hh->hh_next) { @@ -1095,7 +1095,8 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, hh->hh_type = protocol; atomic_set(&hh->hh_refcnt, 0); hh->hh_next = NULL; - if (dev->hard_header_cache(n, hh)) { + + if (dev->header_ops->cache(n, hh)) { kfree(hh); hh = NULL; } else { @@ -1127,7 +1128,7 @@ int neigh_compat_output(struct sk_buff *skb) if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, skb->len) < 0 && - dev->rebuild_header(skb)) + dev->header_ops->rebuild(skb)) return 0; return dev_queue_xmit(skb); @@ -1149,7 +1150,7 @@ int neigh_resolve_output(struct sk_buff *skb) if (!neigh_event_send(neigh, skb)) { int err; struct net_device *dev = neigh->dev; - if (dev->hard_header_cache && !dst->hh) { + if (dev->header_ops->cache && !dst->hh) { write_lock_bh(&neigh->lock); if (!dst->hh) neigh_hh_init(neigh, dst, dst->ops->protocol); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index bdeb2f0ace32..ed8a3d49487d 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -75,8 +75,9 @@ __setup("ether=", netdev_boot_setup); * Set the protocol type. For a packet of type ETH_P_802_3 we put the length * in here instead. It is up to the 802.2 layer to carry protocol information. */ -int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +int eth_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); @@ -109,6 +110,7 @@ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, return -ETH_HLEN; } +EXPORT_SYMBOL(eth_header); /** * eth_rebuild_header- rebuild the Ethernet MAC header. @@ -141,6 +143,7 @@ int eth_rebuild_header(struct sk_buff *skb) return 0; } +EXPORT_SYMBOL(eth_rebuild_header); /** * eth_type_trans - determine the packet's protocol ID. @@ -207,12 +210,13 @@ EXPORT_SYMBOL(eth_type_trans); * @skb: packet to extract header from * @haddr: destination buffer */ -static int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) +int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) { const struct ethhdr *eth = eth_hdr(skb); memcpy(haddr, eth->h_source, ETH_ALEN); return ETH_ALEN; } +EXPORT_SYMBOL(eth_header_parse); /** * eth_header_cache - fill cache entry from neighbour @@ -220,11 +224,11 @@ static int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) * @hh: destination cache entry * Create an Ethernet header template from the neighbour. */ -int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) +int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh) { __be16 type = hh->hh_type; struct ethhdr *eth; - struct net_device *dev = neigh->dev; + const struct net_device *dev = neigh->dev; eth = (struct ethhdr *) (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); @@ -238,6 +242,7 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) hh->hh_len = ETH_HLEN; return 0; } +EXPORT_SYMBOL(eth_header_cache); /** * eth_header_cache_update - update cache entry @@ -247,12 +252,14 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) * * Called by Address Resolution module to notify changes in address. */ -void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, - unsigned char *haddr) +void eth_header_cache_update(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr) { memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), haddr, ETH_ALEN); } +EXPORT_SYMBOL(eth_header_cache_update); /** * eth_mac_addr - set new Ethernet hardware address @@ -291,6 +298,14 @@ static int eth_change_mtu(struct net_device *dev, int new_mtu) return 0; } +const struct header_ops eth_header_ops ____cacheline_aligned = { + .create = eth_header, + .parse = eth_header_parse, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + /** * ether_setup - setup Ethernet network device * @dev: network device @@ -298,13 +313,10 @@ static int eth_change_mtu(struct net_device *dev, int new_mtu) */ void ether_setup(struct net_device *dev) { + dev->header_ops = ð_header_ops; + dev->change_mtu = eth_change_mtu; - dev->hard_header = eth_header; - dev->rebuild_header = eth_rebuild_header; dev->set_mac_address = eth_mac_addr; - dev->hard_header_cache = eth_header_cache; - dev->header_cache_update= eth_header_cache_update; - dev->hard_header_parse = eth_header_parse; dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 5b24c65b13c6..d8248198bcd7 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -253,7 +253,7 @@ static int arp_constructor(struct neighbour *neigh) neigh->parms = neigh_parms_clone(parms); rcu_read_unlock(); - if (dev->hard_header == NULL) { + if (!dev->header_ops) { neigh->nud_state = NUD_NOARP; neigh->ops = &arp_direct_ops; neigh->output = neigh->ops->queue_xmit; @@ -310,10 +310,12 @@ static int arp_constructor(struct neighbour *neigh) neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->broadcast, dev->addr_len); } - if (dev->hard_header_cache) + + if (dev->header_ops->cache) neigh->ops = &arp_hh_ops; else neigh->ops = &arp_generic_ops; + if (neigh->nud_state&NUD_VALID) neigh->output = neigh->ops->connected_output; else diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index ffa9f1c9dcbb..f151900efaf9 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -684,7 +684,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_error; } - if (dev->hard_header) { + if (dev->header_ops) { gre_hlen = 0; tiph = (struct iphdr*)skb->data; } else { @@ -1063,8 +1063,9 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu) */ -static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int ipgre_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct ip_tunnel *t = netdev_priv(dev); struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); @@ -1091,6 +1092,10 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned sh return -t->hlen; } +static const struct header_ops ipgre_header_ops = { + .create = ipgre_header, +}; + static int ipgre_open(struct net_device *dev) { struct ip_tunnel *t = netdev_priv(dev); @@ -1187,7 +1192,7 @@ static int ipgre_tunnel_init(struct net_device *dev) if (!iph->saddr) return -EINVAL; dev->flags = IFF_BROADCAST; - dev->hard_header = ipgre_header; + dev->header_ops = &ipgre_header_ops; dev->open = ipgre_open; dev->stop = ipgre_close; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 77f67b7cb9bf..699f06781fd8 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -169,7 +169,7 @@ static inline int ip_finish_output2(struct sk_buff *skb) IP_INC_STATS(IPSTATS_MIB_OUTBCASTPKTS); /* Be paranoid, rather than too clever. */ - if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) { + if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { struct sk_buff *skb2; skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev)); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7ea5a502ca08..b761dbed8cec 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -354,7 +354,7 @@ static int ndisc_constructor(struct neighbour *neigh) rcu_read_unlock(); neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST; - if (dev->hard_header == NULL) { + if (!dev->header_ops) { neigh->nud_state = NUD_NOARP; neigh->ops = &ndisc_direct_ops; neigh->output = neigh->ops->queue_xmit; @@ -371,7 +371,7 @@ static int ndisc_constructor(struct neighbour *neigh) neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->broadcast, dev->addr_len); } - if (dev->hard_header_cache) + if (dev->header_ops->cache) neigh->ops = &ndisc_hh_ops; else neigh->ops = &ndisc_generic_ops; @@ -807,7 +807,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) neigh_update(neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE); - if (neigh || !dev->hard_header) { + if (neigh || !dev->header_ops) { ndisc_send_na(dev, neigh, saddr, &msg->target, is_router, 1, (ifp != NULL && inc), inc); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 0cdcf0d0c6ca..57ec8880bb1a 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -228,7 +228,6 @@ void ieee80211_if_mgmt_setup(struct net_device *dev) dev->open = ieee80211_mgmt_open; dev->stop = ieee80211_mgmt_stop; dev->type = ARPHRD_IEEE80211_PRISM; - dev->hard_header_parse = header_parse_80211; dev->uninit = ieee80211_if_reinit; dev->destructor = ieee80211_if_free; } @@ -546,10 +545,19 @@ static void ieee80211_set_multicast_list(struct net_device *dev) netif_tx_unlock(local->mdev); } +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, +}; + /* Must not be called for mdev and apdev */ void ieee80211_if_setup(struct net_device *dev) { ether_setup(dev); + dev->header_ops = &ieee80211_header_ops; dev->hard_start_xmit = ieee80211_subif_start_xmit; dev->wireless_handlers = &ieee80211_iw_handler_def; dev->set_multicast_list = ieee80211_set_multicast_list; @@ -1197,7 +1205,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mdev->open = ieee80211_master_open; mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; - mdev->hard_header_parse = header_parse_80211; + mdev->header_ops = &ieee80211_header_ops; sdata->type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index c7b5d930e732..8c68da5ef0a1 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -95,8 +95,9 @@ static int nr_rebuild_header(struct sk_buff *skb) #endif -static int nr_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int nr_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); @@ -193,6 +194,12 @@ static struct net_device_stats *nr_get_stats(struct net_device *dev) return &nr->stats; } +static const struct header_ops nr_header_ops = { + .create = nr_header, + .rebuild= nr_rebuild_header, +}; + + void nr_setup(struct net_device *dev) { dev->mtu = NR_MAX_PACKET_SIZE; @@ -200,11 +207,10 @@ void nr_setup(struct net_device *dev) dev->open = nr_open; dev->stop = nr_close; - dev->hard_header = nr_header; + dev->header_ops = &nr_header_ops; dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN; dev->addr_len = AX25_ADDR_LEN; dev->type = ARPHRD_NETROM; - dev->rebuild_header = nr_rebuild_header; dev->set_mac_address = nr_set_mac_address; /* New-style flags. */ diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c9ee343c2a6c..e11000a8e950 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -389,7 +389,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, skb_reset_network_header(skb); /* Try to align data part correctly */ - if (dev->hard_header) { + if (dev->header_ops) { skb->data -= dev->hard_header_len; skb->tail -= dev->hard_header_len; if (len < dev->hard_header_len) @@ -466,7 +466,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet skb->dev = dev; - if (dev->hard_header) { + if (dev->header_ops) { /* The device has an explicit notion of ll header, exported to higher levels. @@ -581,7 +581,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev->hard_header) { + if (dev->header_ops) { if (sk->sk_type != SOCK_DGRAM) skb_push(skb, skb->data - skb_mac_header(skb)); else if (skb->pkt_type == PACKET_OUTGOING) { diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index 8d88795dc663..1b6741f1d746 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -35,8 +35,9 @@ #include #include -static int rose_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int rose_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2); @@ -148,6 +149,11 @@ static struct net_device_stats *rose_get_stats(struct net_device *dev) return netdev_priv(dev); } +static const struct header_ops rose_header_ops = { + .create = rose_header, + .rebuild= rose_rebuild_header, +}; + void rose_setup(struct net_device *dev) { dev->mtu = ROSE_MAX_PACKET_SIZE - 2; @@ -155,11 +161,10 @@ void rose_setup(struct net_device *dev) dev->open = rose_open; dev->stop = rose_close; - dev->hard_header = rose_header; + dev->header_ops = &rose_header_ops; dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; dev->addr_len = ROSE_ADDR_LEN; dev->type = ARPHRD_ROSE; - dev->rebuild_header = rose_rebuild_header; dev->set_mac_address = rose_set_mac_address; /* New-style flags. */ diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index d13970f3c7b1..be57cf317a7f 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -249,10 +249,10 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * return (skb_res == NULL) ? -EAGAIN : 1; } -static __inline__ int -teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev) +static inline int teql_resolve(struct sk_buff *skb, + struct sk_buff *skb_res, struct net_device *dev) { - if (dev->hard_header == NULL || + if (dev->header_ops == NULL || skb->dst == NULL || skb->dst->neighbour == NULL) return 0; From 0aa4f3331b1df09a500e1fda84145255303af573 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 26 Sep 2007 22:21:28 -0700 Subject: [PATCH 1539/2804] [WIRELESS]: Fix Kconfig. Seems that a bare "depends" is no longer allowed in Sam's kbuild tree. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/wireless/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 6291f13bba09..6426055a8be0 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -3,7 +3,7 @@ config CFG80211 config NL80211 bool "nl80211 new netlink interface support" - depends CFG80211 + depends on CFG80211 default y ---help--- This option turns on the new netlink interface From 7a876fae9da2b1417246a3eac0ac83889f12fa27 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Wed, 26 Sep 2007 22:29:02 -0700 Subject: [PATCH 1540/2804] [SPIDERNET] spider_net_ethtool: Keep up with recent netdev stats changes drivers/net/spider_net_ethtool.c: In function 'spider_net_get_ethtool_stats': drivers/net/spider_net_ethtool.c:160: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:161: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:162: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:163: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:164: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:165: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:166: error: structure has no member named 'netdev_stats' make[2]: *** [drivers/net/spider_net_ethtool.o] Error 1 Also do another ARRAY_SIZE() cleanup while at it. Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/spider_net_ethtool.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 94273037102f..85691d2a0be2 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -28,8 +28,6 @@ #include "spider_net.h" -#define SPIDER_NET_NUM_STATS 13 - static struct { const char str[ETH_GSTRING_LEN]; } ethtool_stats_keys[] = { @@ -151,7 +149,7 @@ static int spider_net_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { case ETH_SS_STATS: - return SPIDER_NET_NUM_STATS; + return ARRAY_SIZE(ethtool_stats_keys); default: return -EOPNOTSUPP; } @@ -162,13 +160,13 @@ static void spider_net_get_ethtool_stats(struct net_device *netdev, { struct spider_net_card *card = netdev->priv; - data[0] = card->netdev_stats.tx_packets; - data[1] = card->netdev_stats.tx_bytes; - data[2] = card->netdev_stats.rx_packets; - data[3] = card->netdev_stats.rx_bytes; - data[4] = card->netdev_stats.tx_errors; - data[5] = card->netdev_stats.tx_dropped; - data[6] = card->netdev_stats.rx_dropped; + data[0] = netdev->stats.tx_packets; + data[1] = netdev->stats.tx_bytes; + data[2] = netdev->stats.rx_packets; + data[3] = netdev->stats.rx_bytes; + data[4] = netdev->stats.tx_errors; + data[5] = netdev->stats.tx_dropped; + data[6] = netdev->stats.rx_dropped; data[7] = card->spider_stats.rx_desc_error; data[8] = card->spider_stats.tx_timeouts; data[9] = card->spider_stats.alloc_rx_skb_error; From dcffde5345c917b98b094d0ef27f6280bc7d4655 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Wed, 26 Sep 2007 22:29:51 -0700 Subject: [PATCH 1541/2804] [PASEMI_MAC]: remove unused function drivers/net/pasemi_mac.c: At top level: drivers/net/pasemi_mac.c:89: warning: 'read_iob_reg' defined but not used Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 4d87cd65626f..912bc5d33d28 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -85,11 +85,6 @@ MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); static struct pasdma_status *dma_status; -static unsigned int read_iob_reg(struct pasemi_mac *mac, unsigned int reg) -{ - return in_le32(mac->iob_regs+reg); -} - static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { From 58c14a8fe64d047218522cf2f18a2d7f24c12f51 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 26 Sep 2007 22:31:19 -0700 Subject: [PATCH 1542/2804] [ATM] net/atm/lec.c: printk warning fix net/atm/lec.c: In function 'lec_start_xmit': net/atm/lec.c:371: warning: format '%x' expects type 'unsigned int', but argument 4 has type 'long unsigned int' Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/atm/lec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/atm/lec.c b/net/atm/lec.c index c909c76223e1..7eb1b21a0e94 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -368,7 +368,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif entry = NULL; vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry); - pr_debug("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name, + pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n", dev->name, vcc, vcc ? vcc->flags : 0, entry); if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) { if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { From 32db927686f6d475fc05b6229f82ed576c0c8096 Mon Sep 17 00:00:00 2001 From: Jonathan Bastien-Filiatrault Date: Wed, 26 Sep 2007 22:34:25 -0700 Subject: [PATCH 1543/2804] [IRDA]: Document the fact that smsc-ircc2 will not use PNP by default This avoids user confusion when they see that their device is not detected. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/irda/smsc-ircc2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 029fdde2a4d3..7e7b5828214a 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -81,7 +81,7 @@ MODULE_LICENSE("GPL"); static int smsc_nopnp = 1; module_param_named(nopnp, smsc_nopnp, bool, 0); -MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); +MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings, defaults to true"); #define DMA_INVAL 255 static int ircc_dma = DMA_INVAL; From f4618d39a34dab316090263b42cd8799f31ce277 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:40:08 -0700 Subject: [PATCH 1544/2804] [NETNS]: Simplify the network namespace list locking rules. Denis V. Lunev noticed that the locking rules for the network namespace list are over complicated and broken. In particular the current register_netdev_notifier currently does not take any lock making the for_each_net iteration racy with network namespace creation and destruction. Oops. The fact that we need to use for_each_net in rtnl_unlock() when the rtnetlink support becomes per network namespace makes designing the proper locking tricky. In addition we need to be able to call rtnl_lock() and rtnl_unlock() when we have the net_mutex held. After thinking about it and looking at the alternatives carefully it looks like the simplest and most maintainable solution is to remove net_list_mutex altogether, and to use the rtnl_mutex instead. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/net_namespace.h | 3 --- net/core/net_namespace.c | 23 ++++++----------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 13b0e3b547f0..934c840b5941 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -96,9 +96,6 @@ static inline void release_net(struct net *net) #endif } -extern void net_lock(void); -extern void net_unlock(void); - #define for_each_net(VAR) \ list_for_each_entry(VAR, &net_namespace_list, list) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index e478e353ea6b..0e0ca6d06fa5 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -15,7 +15,6 @@ static LIST_HEAD(pernet_list); static struct list_head *first_device = &pernet_list; static DEFINE_MUTEX(net_mutex); -static DEFINE_MUTEX(net_list_mutex); LIST_HEAD(net_namespace_list); static struct kmem_cache *net_cachep; @@ -23,16 +22,6 @@ static struct kmem_cache *net_cachep; struct net init_net; EXPORT_SYMBOL_GPL(init_net); -void net_lock(void) -{ - mutex_lock(&net_list_mutex); -} - -void net_unlock(void) -{ - mutex_unlock(&net_list_mutex); -} - static struct net *net_alloc(void) { return kmem_cache_alloc(net_cachep, GFP_KERNEL); @@ -62,9 +51,9 @@ static void cleanup_net(struct work_struct *work) mutex_lock(&net_mutex); /* Don't let anyone else find us. */ - net_lock(); + rtnl_lock(); list_del(&net->list); - net_unlock(); + rtnl_unlock(); /* Run all of the network namespace exit methods */ list_for_each_entry_reverse(ops, &pernet_list, list) { @@ -151,9 +140,9 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) if (err) goto out_unlock; - net_lock(); + rtnl_lock(); list_add_tail(&new_net->list, &net_namespace_list); - net_unlock(); + rtnl_unlock(); out_unlock: @@ -178,9 +167,9 @@ static int __init net_ns_init(void) mutex_lock(&net_mutex); err = setup_net(&init_net); - net_lock(); + rtnl_lock(); list_add_tail(&init_net.list, &net_namespace_list); - net_unlock(); + rtnl_unlock(); mutex_unlock(&net_mutex); if (err) From 070ac3a2651e3c1c4d277c5f1981517427c386a7 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 27 Sep 2007 12:04:19 -0700 Subject: [PATCH 1545/2804] [NET]: Proper comment for loopback initialization order. Loopback device is special. It should be initialized at the very beginning. Initialization order has been changed by Eric W. Biederman and this change is non-obvious and important enough to add proper comment. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- drivers/net/loopback.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b6d4ae3ad506..2617320efa95 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -293,4 +293,7 @@ static int __init loopback_init(void) return register_pernet_device(&loopback_net_ops); } +/* Loopback is special. It should be initialized before any other network + * device and network subsystem. + */ fs_initcall(loopback_init); From 4150c57212ad134765dd78c654a4b9906252b66d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Sep 2007 01:29:23 -0400 Subject: [PATCH 1546/2804] [PATCH] mac80211: revamp interface and filter configuration Drivers are currently supposed to keep track of monitor interfaces if they allow so-called "hard" monitor, and they are also supposed to keep track of multicast etc. This patch changes that, replaces the set_multicast_list() callback with a new configure_filter() callback that takes filter flags (FIF_*) instead of interface flags (IFF_*). For a driver, this means it should open the filter as much as necessary to get all frames requested by the filter flags. Accordingly, the filter flags are named "positively", e.g. FIF_ALLMULTI. Multicast filtering is a bit special in that drivers that have no multicast address filters need to allow multicast frames through when either the FIF_ALLMULTI flag is set or when the mc_count value is positive. At the same time, drivers are no longer notified about monitor interfaces at all, this means they now need to implement the start() and stop() callbacks and the new change_filter_flags() callback. Also, the start()/stop() ordering changed, start() is now called *before* any add_interface() as it really should be, and stop() after any remove_interface(). The patch also changes the behaviour of setting the bssid to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed and the filter flag FIF_BCN_PRBRESP_PROMISC introduced. This is a lot more efficient for hardware like b43 that supports it and other hardware can still set the BSSID to all-ones. Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu (rtl8187, adm8211, and p54), Larry Finger (b43legacy), and Ivo van Doorn (rt2x00). Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: Larry Finger Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 144 ++++---- drivers/net/wireless/adm8211.h | 1 - drivers/net/wireless/b43/b43.h | 15 +- drivers/net/wireless/b43/main.c | 250 +++++++------ drivers/net/wireless/b43legacy/b43legacy.h | 20 +- drivers/net/wireless/b43legacy/main.c | 249 +++++++------ drivers/net/wireless/iwlwifi/iwl3945-base.c | 28 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 26 +- drivers/net/wireless/p54.h | 3 +- drivers/net/wireless/p54common.c | 82 +++-- drivers/net/wireless/rt2x00/rt2400pci.c | 155 ++++---- drivers/net/wireless/rt2x00/rt2500pci.c | 165 +++++---- drivers/net/wireless/rt2x00/rt2500usb.c | 179 ++++++---- drivers/net/wireless/rt2x00/rt2x00.h | 37 +- drivers/net/wireless/rt2x00/rt2x00config.c | 60 +--- drivers/net/wireless/rt2x00/rt2x00dev.c | 33 +- drivers/net/wireless/rt2x00/rt2x00lib.h | 1 - drivers/net/wireless/rt2x00/rt2x00mac.c | 104 +----- drivers/net/wireless/rt2x00/rt2x00pci.c | 31 +- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 6 +- drivers/net/wireless/rt2x00/rt2x00ring.h | 17 +- drivers/net/wireless/rt2x00/rt2x00usb.c | 16 +- drivers/net/wireless/rt2x00/rt61pci.c | 164 +++++---- drivers/net/wireless/rt2x00/rt73usb.c | 175 +++++---- drivers/net/wireless/rt2x00/rt73usb.h | 2 +- drivers/net/wireless/rtl8187.h | 5 +- drivers/net/wireless/rtl8187_dev.c | 129 ++++++- drivers/net/wireless/rtl818x.h | 1 + include/net/mac80211.h | 147 +++++--- net/mac80211/debugfs_netdev.c | 16 - net/mac80211/ieee80211.c | 376 ++++++++------------ net/mac80211/ieee80211_i.h | 3 +- net/mac80211/ieee80211_sta.c | 26 +- net/mac80211/rx.c | 4 +- 34 files changed, 1393 insertions(+), 1277 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index ac2ea237019d..49a6b9eda4ea 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -281,49 +281,6 @@ static int adm8211_get_stats(struct ieee80211_hw *dev, return 0; } -static void adm8211_set_rx_mode(struct ieee80211_hw *dev, - unsigned short flags, int mc_count) -{ - struct adm8211_priv *priv = dev->priv; - unsigned int bit_nr; - u32 mc_filter[2]; - struct dev_mc_list *mclist; - void *tmp; - - if (flags & IFF_PROMISC) { - priv->nar |= ADM8211_NAR_PR; - priv->nar &= ~ADM8211_NAR_MM; - mc_filter[1] = mc_filter[0] = ~0; - } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) { - 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; - mclist = NULL; - while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) { - bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - - bit_nr &= 0x3F; - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - } - } - - ADM8211_IDLE_RX(); - - ADM8211_CSR_WRITE(MAR0, mc_filter[0]); - ADM8211_CSR_WRITE(MAR1, mc_filter[1]); - ADM8211_CSR_READ(NAR); - - if (flags & IFF_PROMISC) - dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; - else - dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; - - ADM8211_RESTORE(); -} - static int adm8211_get_tx_stats(struct ieee80211_hw *dev, struct ieee80211_tx_queue_stats *stats) { @@ -1254,13 +1211,6 @@ static void adm8211_hw_init(struct ieee80211_hw *dev) /* Clear the missed-packet counter. */ ADM8211_CSR_READ(LPC); - - if (!priv->mac_addr) - return; - - /* set mac address */ - ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr); - ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]); } static int adm8211_hw_reset(struct ieee80211_hw *dev) @@ -1334,7 +1284,7 @@ static void adm8211_set_interval(struct ieee80211_hw *dev, ADM8211_CSR_WRITE(BPLI, reg); } -static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid) +static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) { struct adm8211_priv *priv = dev->priv; u32 reg; @@ -1395,24 +1345,87 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id, return 0; } +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) +{ + static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + struct adm8211_priv *priv = dev->priv; + unsigned int bit_nr, new_flags; + u32 mc_filter[2]; + int i; + + new_flags = 0; + + if (*total_flags & FIF_PROMISC_IN_BSS) { + new_flags |= FIF_PROMISC_IN_BSS; + 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)) { + 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(); + + ADM8211_CSR_WRITE(MAR0, mc_filter[0]); + ADM8211_CSR_WRITE(MAR1, mc_filter[1]); + ADM8211_CSR_READ(NAR); + + if (priv->nar & ADM8211_NAR_PR) + dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + adm8211_set_bssid(dev, bcast); + else + adm8211_set_bssid(dev, priv->bssid); + + ADM8211_RESTORE(); + + *total_flags = new_flags; +} + static int adm8211_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: priv->mode = conf->type; break; default: return -EOPNOTSUPP; } - priv->mac_addr = conf->mac_addr; + ADM8211_IDLE(); + + ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr); + ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4)); + + adm8211_update_mode(dev); + + ADM8211_RESTORE(); return 0; } @@ -1421,7 +1434,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; } static int adm8211_init_rings(struct ieee80211_hw *dev) @@ -1505,7 +1518,7 @@ static void adm8211_free_rings(struct ieee80211_hw *dev) } } -static int adm8211_open(struct ieee80211_hw *dev) +static int adm8211_start(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; int retval; @@ -1550,7 +1563,7 @@ fail: return retval; } -static int adm8211_stop(struct ieee80211_hw *dev) +static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; @@ -1562,7 +1575,6 @@ static int adm8211_stop(struct ieee80211_hw *dev) free_irq(priv->pdev->irq, dev); adm8211_free_rings(dev); - return 0; } static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len, @@ -1765,13 +1777,13 @@ static int adm8211_alloc_rings(struct ieee80211_hw *dev) static const struct ieee80211_ops adm8211_ops = { .tx = adm8211_tx, - .open = adm8211_open, + .start = adm8211_start, .stop = adm8211_stop, .add_interface = adm8211_add_interface, .remove_interface = adm8211_remove_interface, .config = adm8211_config, .config_interface = adm8211_config_interface, - .set_multicast_list = adm8211_set_rx_mode, + .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, .get_tx_stats = adm8211_get_tx_stats, .get_tsf = adm8211_get_tsft @@ -1905,7 +1917,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; /* Power-on issue. EEPROM won't read correctly without */ if (priv->revid >= ADM8211_REV_BA) { @@ -2000,7 +2012,7 @@ 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 != IEEE80211_IF_TYPE_MGMT) { + if (priv->mode != IEEE80211_IF_TYPE_MNTR) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2018,8 +2030,8 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_MGMT) { - adm8211_open(dev); + if (priv->mode != IEEE80211_IF_TYPE_MNTR) { + adm8211_start(dev); ieee80211_start_queues(dev); } diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 795d895f5c99..5991b17c4a7b 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -612,7 +612,6 @@ struct adm8211_priv { u8 bssid[ETH_ALEN]; u8 ssid[32]; size_t ssid_len; - u8 *mac_addr; u8 soft_rx_crc; u8 retry_limit; diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a22435ade8ca..2c8fa1c3465e 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -604,9 +604,8 @@ struct b43_wl { * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface (!= monitor - * interface) from the ieee80211 subsystem. - * Do not modify. + /* Opaque ID of the operating interface from the ieee80211 + * subsystem. Do not modify. */ int if_id; /* The MAC address of the operating interface. */ @@ -615,14 +614,10 @@ struct b43_wl { u8 bssid[ETH_ALEN]; /* Interface type. (IEEE80211_IF_TYPE_XXX) */ int if_type; - /* Counter of active monitor interfaces. */ - int monitor; /* Is the card operating in AP, STA or IBSS mode? */ bool operating; - /* Promisc mode active? - * Note that (monitor != 0) implies promisc. - */ - bool promisc; + /* filter flags */ + unsigned int filter_flags; /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; @@ -779,8 +774,6 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) /* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ static inline int b43_is_mode(struct b43_wl *wl, int type) { - if (type == IEEE80211_IF_TYPE_MNTR) - return !!(wl->monitor); return (wl->operating && wl->if_type == type); } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index b44c9f928848..72467c86f8d4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -92,14 +92,6 @@ static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); -static int modparam_mon_keep_bad; -module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); - -static int modparam_mon_keep_badplcp; -module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); - static int modparam_hwpctl; module_param_named(hwpctl, modparam_hwpctl, int, 0444); MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)"); @@ -561,15 +553,10 @@ static void b43_write_mac_bssid_templates(struct b43_wldev *dev) } } -static void b43_upload_card_macaddress(struct b43_wldev *dev, - const u8 * mac_addr) +static void b43_upload_card_macaddress(struct b43_wldev *dev) { - if (mac_addr) - memcpy(dev->wl->mac_addr, mac_addr, ETH_ALEN); - else - memset(dev->wl->mac_addr, 0, ETH_ALEN); b43_write_mac_bssid_templates(dev); - b43_macfilter_set(dev, B43_MACFILTER_SELF, mac_addr); + b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr); } static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) @@ -2052,33 +2039,25 @@ static void b43_adjust_opmode(struct b43_wldev *dev) ctl &= ~B43_MACCTL_KEEP_BADPLCP; ctl &= ~B43_MACCTL_KEEP_BAD; ctl &= ~B43_MACCTL_PROMISC; + ctl &= ~B43_MACCTL_BEACPROMISC; ctl |= B43_MACCTL_INFRA; - if (wl->operating) { - switch (wl->if_type) { - case IEEE80211_IF_TYPE_AP: - ctl |= B43_MACCTL_AP; - break; - case IEEE80211_IF_TYPE_IBSS: - ctl &= ~B43_MACCTL_INFRA; - break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_WDS: - break; - default: - B43_WARN_ON(1); - } - } - if (wl->monitor) { + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + ctl |= B43_MACCTL_AP; + else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + ctl &= ~B43_MACCTL_INFRA; + + if (wl->filter_flags & FIF_CONTROL) ctl |= B43_MACCTL_KEEP_CTL; - if (modparam_mon_keep_bad) - ctl |= B43_MACCTL_KEEP_BAD; - if (modparam_mon_keep_badplcp) - ctl |= B43_MACCTL_KEEP_BADPLCP; - } - if (wl->promisc) + if (wl->filter_flags & FIF_FCSFAIL) + ctl |= B43_MACCTL_KEEP_BAD; + if (wl->filter_flags & FIF_PLCPFAIL) + ctl |= B43_MACCTL_KEEP_BADPLCP; + if (wl->filter_flags & FIF_PROMISC_IN_BSS) ctl |= B43_MACCTL_PROMISC; + if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC) + ctl |= B43_MACCTL_BEACPROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter * doesn't work properly, so always run promisc in filter * it in software. */ @@ -2254,9 +2233,6 @@ static int b43_chip_init(struct b43_wldev *dev) & ~B43_MACCTL_INFRA); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) | B43_MACCTL_INFRA); - /* Let beacons come through */ - b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) - | B43_MACCTL_BEACPROMISC); if (b43_using_pio(dev)) { b43_write32(dev, 0x0210, 0x00000100); @@ -2899,9 +2875,9 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) return err; } -static int b43_dev_set_key(struct ieee80211_hw *hw, - set_key_cmd cmd, const u8 *local_addr, - const u8 *addr, struct ieee80211_key_conf *key) +static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -3003,21 +2979,40 @@ out: return err; } -static void b43_set_multicast_list(struct ieee80211_hw *hw, - unsigned short netflags, int mc_count) +static void b43_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, unsigned int *fflags, + int mc_count, struct dev_addr_list *mc_list) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; unsigned long flags; - if (!dev) + if (!dev) { + *fflags = 0; return; - spin_lock_irqsave(&wl->irq_lock, flags); - if (wl->promisc != !!(netflags & IFF_PROMISC)) { - wl->promisc = !!(netflags & IFF_PROMISC); - if (b43_status(dev) >= B43_STAT_INITIALIZED) - b43_adjust_opmode(dev); } + + spin_lock_irqsave(&wl->irq_lock, flags); + *fflags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + wl->filter_flags = *fflags; + + if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) + b43_adjust_opmode(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); } @@ -3032,21 +3027,19 @@ static int b43_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - if (conf->type != IEEE80211_IF_TYPE_MNTR) { - B43_WARN_ON(wl->if_id != if_id); - if (conf->bssid) - memcpy(wl->bssid, conf->bssid, ETH_ALEN); - else - memset(wl->bssid, 0, ETH_ALEN); - if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); - b43_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) - b43_refresh_templates(dev, conf->beacon); - } - b43_write_mac_bssid_templates(dev); + B43_WARN_ON(wl->if_id != if_id); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + if (b43_status(dev) >= B43_STAT_INITIALIZED) { + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + b43_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->beacon) + b43_refresh_templates(dev, conf->beacon); } + b43_write_mac_bssid_templates(dev); } spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); @@ -3472,7 +3465,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ memset(wl->bssid, 0, ETH_ALEN); - b43_upload_card_macaddress(dev, NULL); + memset(wl->mac_addr, 0, ETH_ALEN); + b43_upload_card_macaddress(dev); b43_security_init(dev); b43_rng_init(wl); @@ -3502,46 +3496,34 @@ static int b43_add_interface(struct ieee80211_hw *hw, struct b43_wldev *dev; unsigned long flags; int err = -EOPNOTSUPP; - int did_init = 0; + + /* TODO: allow WDS/AP devices to coexist */ + + if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_STA && + conf->type != IEEE80211_IF_TYPE_WDS && + conf->type != IEEE80211_IF_TYPE_IBSS) + return -EOPNOTSUPP; mutex_lock(&wl->mutex); - if ((conf->type != IEEE80211_IF_TYPE_MNTR) && wl->operating) + if (wl->operating) goto out_mutex_unlock; b43dbg(wl, "Adding Interface type %d\n", conf->type); dev = wl->current_dev; - if (b43_status(dev) < B43_STAT_INITIALIZED) { - err = b43_wireless_core_init(dev); - if (err) - goto out_mutex_unlock; - did_init = 1; - } - if (b43_status(dev) < B43_STAT_STARTED) { - err = b43_wireless_core_start(dev); - if (err) { - if (did_init) - b43_wireless_core_exit(dev); - goto out_mutex_unlock; - } - } + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); spin_lock_irqsave(&wl->irq_lock, flags); - switch (conf->type) { - case IEEE80211_IF_TYPE_MNTR: - wl->monitor++; - break; - default: - wl->operating = 1; - wl->if_id = conf->if_id; - wl->if_type = conf->type; - b43_upload_card_macaddress(dev, conf->mac_addr); - } b43_adjust_opmode(dev); + b43_upload_card_macaddress(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); err = 0; - out_mutex_unlock: + out_mutex_unlock: mutex_unlock(&wl->mutex); return err; @@ -3551,34 +3533,67 @@ static void b43_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev; + struct b43_wldev *dev = wl->current_dev; unsigned long flags; b43dbg(wl, "Removing Interface type %d\n", conf->type); mutex_lock(&wl->mutex); - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - wl->monitor--; - B43_WARN_ON(wl->monitor < 0); - } else { - B43_WARN_ON(!wl->operating); - wl->operating = 0; + + B43_WARN_ON(!wl->operating); + B43_WARN_ON(wl->if_id != conf->if_id); + + 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); +} + +static int b43_start(struct ieee80211_hw *hw) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + int did_init = 0; + int err; + + mutex_lock(&wl->mutex); + + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(dev); + if (err) + goto out_mutex_unlock; + did_init = 1; } - dev = wl->current_dev; - if (!wl->operating && wl->monitor == 0) { - /* No interface left. */ - if (b43_status(dev) >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); - b43_wireless_core_exit(dev); - } else { - /* Just monitor interfaces left. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43_adjust_opmode(dev); - if (!wl->operating) - b43_upload_card_macaddress(dev, NULL); - spin_unlock_irqrestore(&wl->irq_lock, flags); + if (b43_status(dev) < B43_STAT_STARTED) { + err = b43_wireless_core_start(dev); + if (err) { + if (did_init) + b43_wireless_core_exit(dev); + goto out_mutex_unlock; + } } + + out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +void b43_stop(struct ieee80211_hw *hw) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + + mutex_lock(&wl->mutex); + if (b43_status(dev) >= B43_STAT_STARTED) + b43_wireless_core_stop(dev); + b43_wireless_core_exit(dev); mutex_unlock(&wl->mutex); } @@ -3589,10 +3604,12 @@ static const struct ieee80211_ops b43_hw_ops = { .remove_interface = b43_remove_interface, .config = b43_dev_config, .config_interface = b43_config_interface, - .set_multicast_list = b43_set_multicast_list, + .configure_filter = b43_configure_filter, .set_key = b43_dev_set_key, .get_stats = b43_get_stats, .get_tx_stats = b43_get_tx_stats, + .start = b43_start, + .stop = b43_stop, }; /* Hard-reset the chip. Do not call this directly. @@ -3930,8 +3947,7 @@ static int b43_wireless_init(struct ssb_device *dev) } /* fill hw info */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_MONITOR_DURING_OPER; + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; hw->max_signal = 100; hw->max_rssi = -110; hw->max_noise = -110; diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 746de2ff498c..afe145cec067 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -179,6 +179,7 @@ #define B43legacy_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */ #define B43legacy_MACCTL_INFRA 0x00020000 /* Infrastructure mode */ #define B43legacy_MACCTL_AP 0x00040000 /* AccessPoint mode */ +#define B43legacy_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */ #define B43legacy_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep bad PLCP frames */ #define B43legacy_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */ #define B43legacy_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */ @@ -570,25 +571,20 @@ struct b43legacy_wl { * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface (!= monitor - * interface) from the ieee80211 subsystem. - * Do not modify. + /* Opaque ID of the operating interface from the ieee80211 + * subsystem. Do not modify. */ int if_id; /* MAC address (can be NULL). */ - const u8 *mac_addr; + u8 mac_addr[ETH_ALEN]; /* Current BSSID (can be NULL). */ - const u8 *bssid; + u8 bssid[ETH_ALEN]; /* Interface type. (IEEE80211_IF_TYPE_XXX) */ int if_type; - /* Counter of active monitor interfaces. */ - int monitor; /* Is the card operating in AP, STA or IBSS mode? */ bool operating; - /* Promisc mode active? - * Note that (monitor != 0) implies promisc. - */ - bool promisc; + /* filter flags */ + unsigned int filter_flags; /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; @@ -753,8 +749,6 @@ struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev) static inline int b43legacy_is_mode(struct b43legacy_wl *wl, int type) { - if (type == IEEE80211_IF_TYPE_MNTR) - return !!(wl->monitor); return (wl->operating && wl->if_type == type); } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index a793f183a2c0..f0749510bcd7 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -91,14 +91,6 @@ static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); -static int modparam_mon_keep_bad; -module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); - -static int modparam_mon_keep_badplcp; -module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); - /* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */ static const struct ssb_device_id b43legacy_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2), @@ -566,12 +558,11 @@ static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev) } } -static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev, - const u8 *mac_addr) +static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev) { - dev->wl->mac_addr = mac_addr; b43legacy_write_mac_bssid_templates(dev); - b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, mac_addr); + b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, + dev->wl->mac_addr); } static void b43legacy_set_slot_time(struct b43legacy_wldev *dev, @@ -1874,34 +1865,25 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev) ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP; ctl &= ~B43legacy_MACCTL_KEEP_BAD; ctl &= ~B43legacy_MACCTL_PROMISC; + ctl &= ~B43legacy_MACCTL_BEACPROMISC; ctl |= B43legacy_MACCTL_INFRA; - if (wl->operating) { - switch (wl->if_type) { - case IEEE80211_IF_TYPE_AP: - ctl |= B43legacy_MACCTL_AP; - break; - case IEEE80211_IF_TYPE_IBSS: - ctl &= ~B43legacy_MACCTL_INFRA; - break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_WDS: - break; - default: - b43legacyerr(wl, "Improper value of %d for" - " wl->if_type\n", wl->if_type); - } - } - if (wl->monitor) { + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + ctl |= B43legacy_MACCTL_AP; + else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + ctl &= ~B43legacy_MACCTL_INFRA; + + if (wl->filter_flags & FIF_CONTROL) ctl |= B43legacy_MACCTL_KEEP_CTL; - if (modparam_mon_keep_bad) - ctl |= B43legacy_MACCTL_KEEP_BAD; - if (modparam_mon_keep_badplcp) - ctl |= B43legacy_MACCTL_KEEP_BADPLCP; - } - if (wl->promisc) + if (wl->filter_flags & FIF_FCSFAIL) + ctl |= B43legacy_MACCTL_KEEP_BAD; + if (wl->filter_flags & FIF_PLCPFAIL) + ctl |= B43legacy_MACCTL_KEEP_BADPLCP; + if (wl->filter_flags & FIF_PROMISC_IN_BSS) ctl |= B43legacy_MACCTL_PROMISC; + if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC) + ctl |= B43legacy_MACCTL_BEACPROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter * doesn't work properly, so always run promisc in filter * it in software. */ @@ -2091,10 +2073,6 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) value32 |= B43legacy_SBF_MODE_NOTADHOC; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); - value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); - value32 |= 0x100000; - b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); - if (b43legacy_using_pio(dev)) { b43legacy_write32(dev, 0x0210, 0x00000100); b43legacy_write32(dev, 0x0230, 0x00000100); @@ -2699,7 +2677,7 @@ out_unlock_mutex: } static int b43legacy_dev_set_key(struct ieee80211_hw *hw, - set_key_cmd cmd, + enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { @@ -2724,22 +2702,42 @@ static int b43legacy_dev_set_key(struct ieee80211_hw *hw, return err; } -static void b43legacy_set_multicast_list(struct ieee80211_hw *hw, - unsigned short netflags, - int mc_count) +static void b43legacy_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *fflags, + int mc_count, + struct dev_addr_list *mc_list) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; unsigned long flags; - if (!dev) + if (!dev) { + *fflags = 0; return; - spin_lock_irqsave(&wl->irq_lock, flags); - if (wl->promisc != !!(netflags & IFF_PROMISC)) { - wl->promisc = !!(netflags & IFF_PROMISC); - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) - b43legacy_adjust_opmode(dev); } + + spin_lock_irqsave(&wl->irq_lock, flags); + *fflags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + wl->filter_flags = *fflags; + + if (changed && b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) + b43legacy_adjust_opmode(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); } @@ -2755,21 +2753,19 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - if (conf->type != IEEE80211_IF_TYPE_MNTR) { - B43legacy_WARN_ON(wl->if_id != if_id); - wl->bssid = conf->bssid; - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43legacy_WARN_ON(conf->type != - IEEE80211_IF_TYPE_AP); - b43legacy_set_ssid(dev, conf->ssid, - conf->ssid_len); - if (conf->beacon) - b43legacy_refresh_templates(dev, - conf->beacon); - } - b43legacy_write_mac_bssid_templates(dev); + B43legacy_WARN_ON(wl->if_id != if_id); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->beacon) + b43legacy_refresh_templates(dev, conf->beacon); } + b43legacy_write_mac_bssid_templates(dev); } spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); @@ -3216,8 +3212,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4); ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ - wl->bssid = NULL; - b43legacy_upload_card_macaddress(dev, NULL); + memset(wl->bssid, 0, ETH_ALEN); + memset(wl->mac_addr, 0, ETH_ALEN); + b43legacy_upload_card_macaddress(dev); b43legacy_security_init(dev); b43legacy_rng_init(wl); @@ -3246,47 +3243,34 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, struct b43legacy_wldev *dev; unsigned long flags; int err = -EOPNOTSUPP; - int did_init = 0; + + /* TODO: allow WDS/AP devices to coexist */ + + if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_STA && + conf->type != IEEE80211_IF_TYPE_WDS && + conf->type != IEEE80211_IF_TYPE_IBSS) + return -EOPNOTSUPP; mutex_lock(&wl->mutex); - if ((conf->type != IEEE80211_IF_TYPE_MNTR) && - wl->operating) + if (wl->operating) goto out_mutex_unlock; b43legacydbg(wl, "Adding Interface type %d\n", conf->type); dev = wl->current_dev; - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { - err = b43legacy_wireless_core_init(dev); - if (err) - goto out_mutex_unlock; - did_init = 1; - } - if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { - err = b43legacy_wireless_core_start(dev); - if (err) { - if (did_init) - b43legacy_wireless_core_exit(dev); - goto out_mutex_unlock; - } - } + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); spin_lock_irqsave(&wl->irq_lock, flags); - switch (conf->type) { - case IEEE80211_IF_TYPE_MNTR: - wl->monitor++; - break; - default: - wl->operating = 1; - wl->if_id = conf->if_id; - wl->if_type = conf->type; - b43legacy_upload_card_macaddress(dev, conf->mac_addr); - } b43legacy_adjust_opmode(dev); + b43legacy_upload_card_macaddress(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); err = 0; -out_mutex_unlock: + out_mutex_unlock: mutex_unlock(&wl->mutex); return err; @@ -3296,34 +3280,67 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev; + struct b43legacy_wldev *dev = wl->current_dev; unsigned long flags; b43legacydbg(wl, "Removing Interface type %d\n", conf->type); mutex_lock(&wl->mutex); - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - wl->monitor--; - B43legacy_WARN_ON(wl->monitor < 0); - } else { - B43legacy_WARN_ON(!wl->operating); - wl->operating = 0; + + B43legacy_WARN_ON(!wl->operating); + B43legacy_WARN_ON(wl->if_id != conf->if_id); + + wl->operating = 0; + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_adjust_opmode(dev); + memset(wl->mac_addr, 0, ETH_ALEN); + b43legacy_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + mutex_unlock(&wl->mutex); +} + +static int b43legacy_start(struct ieee80211_hw *hw) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + int did_init = 0; + int err; + + mutex_lock(&wl->mutex); + + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(dev); + if (err) + goto out_mutex_unlock; + did_init = 1; } - dev = wl->current_dev; - if (!wl->operating && wl->monitor == 0) { - /* No interface left. */ - if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) - b43legacy_wireless_core_stop(dev); - b43legacy_wireless_core_exit(dev); - } else { - /* Just monitor interfaces left. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_adjust_opmode(dev); - if (!wl->operating) - b43legacy_upload_card_macaddress(dev, NULL); - spin_unlock_irqrestore(&wl->irq_lock, flags); + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(dev); + if (err) { + if (did_init) + b43legacy_wireless_core_exit(dev); + goto out_mutex_unlock; + } } + +out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +void b43legacy_stop(struct ieee80211_hw *hw) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + + mutex_lock(&wl->mutex); + if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(dev); + b43legacy_wireless_core_exit(dev); mutex_unlock(&wl->mutex); } @@ -3336,9 +3353,11 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .config = b43legacy_dev_config, .config_interface = b43legacy_config_interface, .set_key = b43legacy_dev_set_key, - .set_multicast_list = b43legacy_set_multicast_list, + .configure_filter = b43legacy_configure_filter, .get_stats = b43legacy_get_stats, .get_tx_stats = b43legacy_get_tx_stats, + .start = b43legacy_start, + .stop = b43legacy_stop, }; /* Hard-reset the chip. Do not call this directly. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 44f983b6d39b..8acda640df25 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6870,7 +6870,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -static int iwl_mac_open(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -6889,7 +6889,7 @@ static int iwl_mac_open(struct ieee80211_hw *hw) return 0; } -static int iwl_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -6898,8 +6898,6 @@ static int iwl_mac_stop(struct ieee80211_hw *hw) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); IWL_DEBUG_MAC80211("leave\n"); - - return 0; } static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -7115,6 +7113,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (conf == NULL) return -EIO; + /* XXX: this MUST use conf->mac_addr */ + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && (!conf->beacon || !conf->ssid_len)) { IWL_DEBUG_MAC80211 @@ -7129,8 +7129,13 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); +/* + * very dubious code was here; the probe filtering flag is never set: + * if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + */ + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); mutex_unlock(&priv->mutex); return 0; @@ -7205,6 +7210,18 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } +static 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) +{ + /* + * XXX: dummy + * see also iwl_connection_init_rx_config + */ + *total_flags = 0; +} + static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { @@ -8265,12 +8282,13 @@ static struct attribute_group iwl_attribute_group = { static struct ieee80211_ops iwl_hw_ops = { .tx = iwl_mac_tx, - .open = iwl_mac_open, + .start = iwl_mac_start, .stop = iwl_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, .set_key = iwl_mac_set_key, .get_stats = iwl_mac_get_stats, .get_tx_stats = iwl_mac_get_tx_stats, diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 61500a209297..7b9227c562b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7252,7 +7252,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -static int iwl_mac_open(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -7271,7 +7271,7 @@ static int iwl_mac_open(struct ieee80211_hw *hw) return 0; } -static int iwl_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -7280,8 +7280,6 @@ static int iwl_mac_stop(struct ieee80211_hw *hw) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); IWL_DEBUG_MAC80211("leave\n"); - - return 0; } static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -7528,8 +7526,13 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); +/* + * very dubious code was here; the probe filtering flag is never set: + * if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + */ + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); mutex_unlock(&priv->mutex); return 0; @@ -7604,6 +7607,18 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } +static 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) +{ + /* + * XXX: dummy + * see also iwl_connection_init_rx_config + */ + *total_flags = 0; +} + static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { @@ -8852,12 +8867,13 @@ static struct attribute_group iwl_attribute_group = { static struct ieee80211_ops iwl_hw_ops = { .tx = iwl_mac_tx, - .open = iwl_mac_open, + .start = iwl_mac_start, .stop = iwl_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, .set_key = iwl_mac_set_key, .get_stats = iwl_mac_get_stats, .get_tx_stats = iwl_mac_get_tx_stats, diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h index e558d697d9e5..744c866066c5 100644 --- a/drivers/net/wireless/p54.h +++ b/drivers/net/wireless/p54.h @@ -52,7 +52,8 @@ struct p54_common { int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; - u8 *mac_addr; + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c index b05b5c5b4c04..9befd6cc7911 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -774,15 +774,39 @@ static void p54_set_vdcf(struct ieee80211_hw *dev) priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); } -static int p54_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) +static int p54_start(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; int err; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + err = priv->open(dev); + if (!err) + priv->mode = IEEE80211_IF_TYPE_MNTR; + + return err; +} + +static void p54_stop(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + while ((skb = skb_dequeue(&priv->tx_queue))) { + struct memrecord *range = (struct memrecord *)&skb->cb; + if (range->control) + kfree(range->control); + kfree_skb(skb); + } + priv->stop(dev); + priv->mode = IEEE80211_IF_TYPE_MGMT; +} + +static int p54_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: @@ -792,23 +816,18 @@ static int p54_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } - priv->mac_addr = conf->mac_addr; - - err = priv->open(dev); - if (err) { - priv->mode = IEEE80211_IF_TYPE_MGMT; - skb_queue_purge(&priv->tx_queue); - return err; - } + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642); p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642); - p54_set_vdcf(dev); switch (conf->type) { case IEEE80211_IF_TYPE_STA: p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0); break; + default: + BUG(); /* impossible */ + break; } p54_set_leds(dev, 1, 0, 0); @@ -820,15 +839,9 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; - struct sk_buff *skb; - while ((skb = skb_dequeue(&priv->tx_queue))) { - struct memrecord *range = (struct memrecord *)&skb->cb; - if (range->control) - kfree(range->control); - kfree_skb(skb); - } - priv->mode = IEEE80211_IF_TYPE_MGMT; - priv->stop(dev); + priv->mode = IEEE80211_IF_TYPE_MNTR; + memset(priv->mac_addr, 0, ETH_ALEN); + p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0); } static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -848,9 +861,29 @@ static int p54_config_interface(struct ieee80211_hw *dev, int if_id, p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642); p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); + memcpy(priv->bssid, conf->bssid, ETH_ALEN); return 0; } +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_BCN_PRBRESP_PROMISC; + + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + p54_set_filter(dev, 0, priv->mac_addr, + NULL, 2, 0, 0, 0); + else + p54_set_filter(dev, 0, priv->mac_addr, + priv->bssid, 2, 0, 0, 0); + } +} + static int p54_conf_tx(struct ieee80211_hw *dev, int queue, const struct ieee80211_tx_queue_params *params) { @@ -893,10 +926,13 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, 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, .config = p54_config, .config_interface = p54_config_interface, + .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, .get_tx_stats = p54_get_tx_stats diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 398c20105c81..03a94a33e6bd 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -277,54 +277,13 @@ static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); } -static void rt2400pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); -} - static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); - /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); - else - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); - } - - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); - /* * Enable beacon config */ @@ -337,20 +296,16 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); - } - + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1104,7 +1059,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1200,8 +1155,8 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2400pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2400pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1210,20 +1165,20 @@ static int rt2400pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 2, &word2); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = 0; - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - - return 0; + desc->ofdm = 0; + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } /* @@ -1460,10 +1415,7 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1530,6 +1482,68 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2400pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * since there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1602,11 +1616,13 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) static const struct ieee80211_ops rt2400pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2400pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2400pci_set_retry_limit, .conf_tx = rt2400pci_conf_tx, @@ -1635,7 +1651,6 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .fill_rxdone = rt2400pci_fill_rxdone, .config_mac_addr = rt2400pci_config_mac_addr, .config_bssid = rt2400pci_config_bssid, - .config_packet_filter = rt2400pci_config_packet_filter, .config_type = rt2400pci_config_type, .config = rt2400pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index e8d63aaab7bc..892baa907a6b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -277,58 +277,13 @@ static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); } -static void rt2500pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, RXCSR0_DROP_MCAST, !multicast); - rt2x00_set_field32(®, RXCSR0_DROP_BCAST, !broadcast); - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); -} - static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); - /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); - else - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); - } - - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); - /* * Enable beacon config */ @@ -345,20 +300,16 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); - } - + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1269,7 +1220,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1349,8 +1300,8 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2500pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2500pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1359,18 +1310,17 @@ static int rt2500pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 2, &word2); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || - rt2x00_get_field32(word0, RXD_W0_ICV_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; - *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - - return 0; + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } /* @@ -1779,10 +1729,7 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1867,6 +1814,73 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2500pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, RXCSR0_DROP_MCAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, RXCSR0_DROP_BCAST, 0); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1914,11 +1928,13 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) static const struct ieee80211_ops rt2500pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2500pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2500pci_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -1947,7 +1963,6 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .fill_rxdone = rt2500pci_fill_rxdone, .config_mac_addr = rt2500pci_config_mac_addr, .config_bssid = rt2500pci_config_bssid, - .config_packet_filter = rt2500pci_config_packet_filter, .config_type = rt2500pci_config_type, .config = rt2500pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 614600c5510d..f4e6f6eb7fb5 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -282,65 +282,20 @@ static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg)); } -static void rt2500usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u16 reg; - - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); - rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, !multicast); - rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, !broadcast); - rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); -} - static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u16 reg; rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); - /* - * Apply hardware packet filter. - */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 1); - else - rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 0); - } - - rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); - /* * Enable beacon config */ rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); - if (type == IEEE80211_IF_TYPE_STA) + if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); else rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2); @@ -354,20 +309,16 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); - } - + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } @@ -1084,7 +1035,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1156,8 +1107,8 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2500usb_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2500usb_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct urb *urb = entry->priv; struct data_desc *rxd = (struct data_desc *)(entry->skb->data + @@ -1169,21 +1120,22 @@ static int rt2500usb_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - return 0; + return; } /* @@ -1549,9 +1501,7 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1621,10 +1571,8 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) rt2500usb_probe_hw_mode(rt2x00dev); /* - * USB devices require scheduled packet filter toggling - *This device requires the beacon ring + * This device requires the beacon ring */ - __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); /* @@ -1638,6 +1586,82 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2500usb_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u16 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); + return; + } + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); +} + static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) @@ -1714,11 +1738,13 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, static const struct ieee80211_ops rt2500usb_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2500usb_configure_filter, .get_stats = rt2x00mac_get_stats, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1739,7 +1765,6 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .fill_rxdone = rt2500usb_fill_rxdone, .config_mac_addr = rt2500usb_config_mac_addr, .config_bssid = rt2500usb_config_bssid, - .config_packet_filter = rt2500usb_config_packet_filter, .config_type = rt2500usb_config_type, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 80b079d723d6..046eecfb16c0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -294,9 +294,6 @@ struct interface { /* * Current working type (IEEE80211_IF_TYPE_*). - * This excludes the type IEEE80211_IF_TYPE_MNTR - * since that is counted seperately in the monitor_count - * field. * When set to INVALID_INTERFACE, no interface is configured. */ int type; @@ -314,18 +311,8 @@ struct interface { /* * Store the packet filter mode for the current interface. - * monitor mode always disabled filtering. But in such - * cases we still need to store the value here in case - * the monitor mode interfaces are removed, while a - * non-monitor mode interface remains. */ - unsigned short filter; - - /* - * Monitor mode count, the number of interfaces - * in monitor mode that that have been added. - */ - unsigned short monitor_count; + unsigned int filter; }; static inline int is_interface_present(struct interface *intf) @@ -333,9 +320,9 @@ static inline int is_interface_present(struct interface *intf) return !!intf->id; } -static inline int is_monitor_present(struct interface *intf) +static inline int is_interface_type(struct interface *intf, int type) { - return !!intf->monitor_count; + return intf->type == type; } /* @@ -402,7 +389,7 @@ struct rt2x00lib_ops { */ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control); @@ -415,8 +402,8 @@ struct rt2x00lib_ops { /* * RX control handlers */ - int (*fill_rxdone) (struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size); + void (*fill_rxdone) (struct data_entry *entry, + struct rxdata_entry_desc *desc); /* * Configuration handlers. @@ -511,11 +498,10 @@ struct rt2x00_dev { #define DEVICE_INITIALIZED 3 #define DEVICE_INITIALIZED_HW 4 #define REQUIRE_FIRMWARE 5 -#define PACKET_FILTER_SCHEDULED 6 -#define PACKET_FILTER_PENDING 7 +/* Hole: Add new Flag here */ #define INTERFACE_RESUME 8 #define INTERFACE_ENABLED 9 -#define INTERFACE_ENABLED_MONITOR 10 +/* Hole: Add new Flag here */ #define REQUIRE_BEACON_RING 11 #define DEVICE_SUPPORT_HW_BUTTON 12 #define CONFIG_FRAME_TYPE 13 @@ -606,9 +592,10 @@ struct rt2x00_dev { struct ieee80211_rx_status rx_status; /* - * Beacon scheduled work. + * Scheduled work. */ struct work_struct beacon_work; + struct work_struct filter_work; /* * Data ring arrays for RX, TX and Beacon. @@ -760,7 +747,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); void rt2x00lib_txdone(struct data_entry *entry, const int status, const int retry); void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, - const int signal, const int rssi, const int ofdm); + struct rxdata_entry_desc *desc); /* * TX descriptor initializer @@ -785,8 +772,6 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf); -void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, - unsigned short flags, int mc_count); int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index de890a17d8fd..f962ce497086 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -46,72 +46,24 @@ void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid); } -void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter) -{ - /* - * Only configure the device when something has changed, - * or if we are in RESUME state in which case all configuration - * will be forced upon the device. - */ - if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && - !test_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags)) - return; - - /* - * Write configuration to device and clear the update flag. - */ - rt2x00dev->ops->lib->config_packet_filter(rt2x00dev, filter); - __clear_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); -} - void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) { struct interface *intf = &rt2x00dev->interface; - /* - * Fallback when a invalid interface is attempted to - * be configured. If a monitor interface is present, - * we are going configure that, otherwise exit. - */ - if (type == INVALID_INTERFACE) { - if (is_monitor_present(intf)) - type = IEEE80211_IF_TYPE_MNTR; - else - return; - } - - /* - * Only configure the device when something has changed, - * or if we are in RESUME state in which case all configuration - * will be forced upon the device. - */ if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && - (!(is_interface_present(intf) ^ - test_bit(INTERFACE_ENABLED, &rt2x00dev->flags)) && - !(is_monitor_present(intf) ^ - test_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags)))) + (!!test_bit(INTERFACE_ENABLED, &rt2x00dev->flags) == + !!is_interface_present(intf))) return; - /* - * Configure device. - */ rt2x00dev->ops->lib->config_type(rt2x00dev, type); /* * Update the configuration flags. */ - if (type != IEEE80211_IF_TYPE_MNTR) { - if (is_interface_present(intf)) - __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - } else { - if (is_monitor_present(intf)) - __set_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED_MONITOR, - &rt2x00dev->flags); - } + if (is_interface_present(intf)) + __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + else + __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); } void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index cd82eeface8f..bbccb8933876 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -135,10 +135,12 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) return; /* - * Stop beacon generation. + * Stop all scheduled work. */ if (work_pending(&rt2x00dev->beacon_work)) cancel_work_sync(&rt2x00dev->beacon_work); + if (work_pending(&rt2x00dev->filter_work)) + cancel_work_sync(&rt2x00dev->filter_work); /* * Stop the TX queues. @@ -257,6 +259,17 @@ static void rt2x00lib_link_tuner(struct work_struct *work) LINK_TUNE_INTERVAL); } +static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, filter_work); + + rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw, + rt2x00dev->interface.filter, + &rt2x00dev->interface.filter, + 0, NULL); +} + /* * Interrupt context handlers. */ @@ -337,7 +350,7 @@ void rt2x00lib_txdone(struct data_entry *entry, EXPORT_SYMBOL_GPL(rt2x00lib_txdone); void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, - const int signal, const int rssi, const int ofdm) + struct rxdata_entry_desc *desc) { struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; @@ -358,22 +371,24 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, * the signal is the PLCP value. If it was received with * a CCK bitrate the signal is the rate in 0.5kbit/s. */ - if (!ofdm) + if (!desc->ofdm) val = DEVICE_GET_RATE_FIELD(rate->val, RATE); else val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); - if (val == signal) { + if (val == desc->signal) { val = rate->val; break; } } - rt2x00_update_link_rssi(&rt2x00dev->link, rssi); + rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi); rt2x00dev->link.rx_success++; rx_status->rate = val; - rx_status->signal = rt2x00lib_calculate_link_signal(rt2x00dev, rssi); - rx_status->ssi = rssi; + rx_status->signal = + rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi); + rx_status->ssi = desc->rssi; + rx_status->flag = desc->flags; /* * Send frame to mac80211 @@ -391,7 +406,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, unsigned int length, struct ieee80211_tx_control *control) { - struct data_entry_desc desc; + struct txdata_entry_desc desc; struct data_ring *ring; int tx_rate; int bitrate; @@ -956,6 +971,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) * Initialize configuration work. */ INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); + INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); /* @@ -1098,7 +1114,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_bssid(rt2x00dev, intf->bssid); rt2x00lib_config_type(rt2x00dev, intf->type); - rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); /* * When in Master or Ad-hoc mode, diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 3324090a96a7..fcc2ffdd1a3c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -51,7 +51,6 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); */ void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); -void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter); void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 778ed41e21ef..17802f6d3d6d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -176,46 +176,26 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct interface *intf = &rt2x00dev->interface; - int retval; /* * We only support 1 non-monitor interface. */ - if (conf->type != IEEE80211_IF_TYPE_MNTR && is_interface_present(intf)) + if (is_interface_present(intf)) return -ENOBUFS; - /* - * HACK: Placeholder until start/stop handler has been - * added to the mac80211 callback functions structure. - */ - retval = rt2x00mac_start(hw); - if (retval) - return retval; + intf->id = conf->if_id; + intf->type = conf->type; + if (conf->type == IEEE80211_IF_TYPE_AP) + memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); + memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); /* - * We support muliple monitor mode interfaces. - * All we need to do is increase the monitor_count. - */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - intf->monitor_count++; - } else { - intf->id = conf->if_id; - intf->type = conf->type; - if (conf->type == IEEE80211_IF_TYPE_AP) - memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); - memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); - intf->filter = 0; - } - - /* - * Configure interface. * The MAC adddress must be configured after the device - * has been initialized. Else the device can reset the - * MAC registers. + * has been initialized. Otherwise the device can reset + * the MAC registers. */ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_type(rt2x00dev, conf->type); - rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); return 0; } @@ -230,22 +210,13 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, /* * We only support 1 non-monitor interface. */ - if (conf->type != IEEE80211_IF_TYPE_MNTR && !is_interface_present(intf)) + if (!is_interface_present(intf)) return; - /* - * When removing an monitor interface, decrease monitor_count. - * For non-monitor interfaces, all interface data needs to be reset. - */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - intf->monitor_count--; - } else if (intf->type == conf->type) { - intf->id = 0; - intf->type = INVALID_INTERFACE; - memset(&intf->bssid, 0x00, ETH_ALEN); - memset(&intf->mac, 0x00, ETH_ALEN); - intf->filter = 0; - } + intf->id = 0; + intf->type = INVALID_INTERFACE; + memset(&intf->bssid, 0x00, ETH_ALEN); + memset(&intf->mac, 0x00, ETH_ALEN); /* * Make sure the bssid and mac address registers @@ -254,12 +225,6 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_bssid(rt2x00dev, intf->bssid); rt2x00lib_config_type(rt2x00dev, intf->type); - - /* - * HACK: Placeholder untill start/stop handler has been - * added to the mac80211 callback functions structure. - */ - rt2x00mac_stop(hw); } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); @@ -289,14 +254,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) rt2x00lib_config(rt2x00dev, conf); - /* - * If promisc mode cannot be configured in irq context, - * then it is now the time to configure it. - */ - if (test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags)) - rt2x00lib_config_packet_filter(rt2x00dev, - rt2x00dev->interface.filter); - /* * Reenable RX only if the radio should be on. */ @@ -326,13 +283,10 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; /* - * Monitor mode does not need configuring. * If the given type does not match the configured type, * there has been a problem. */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) - return 0; - else if (conf->type != intf->type) + if (conf->type != intf->type) return -EINVAL; /* @@ -360,36 +314,6 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, } EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); -void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, - unsigned short flags, int mc_count) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - - /* - * Check if the new state is different then the old state. - */ - if (rt2x00dev->interface.filter == flags) - return; - - rt2x00dev->interface.filter = flags; - - /* - * Raise the pending bit to indicate the - * packet filter should be updated. - */ - __set_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); - - /* - * Check if Packet filter actions are allowed in - * atomic context. If not, raise the pending flag and - * let it be. - */ - if (!test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags) || - !in_atomic()) - rt2x00lib_config_packet_filter(rt2x00dev, flags); -} -EXPORT_SYMBOL_GPL(rt2x00mac_set_multicast_list); - int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 85629f1999ab..2780df00623c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -124,47 +124,40 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) struct data_entry *entry; struct data_desc *rxd; struct sk_buff *skb; - u32 desc; - int retval; - int signal; - int rssi; - int ofdm; - int size; + struct rxdata_entry_desc desc; + u32 word; while (1) { entry = rt2x00_get_data_entry(ring); rxd = entry->priv; - rt2x00_desc_read(rxd, 0, &desc); + rt2x00_desc_read(rxd, 0, &word); - if (rt2x00_get_field32(desc, RXD_ENTRY_OWNER_NIC)) + if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; - retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, - &rssi, &ofdm, &size); - if (retval) - goto skip_entry; + memset(&desc, 0x00, sizeof(desc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &desc); /* * Allocate the sk_buffer, initialize it and copy * all data into it. */ - skb = dev_alloc_skb(size + NET_IP_ALIGN); + skb = dev_alloc_skb(desc.size + NET_IP_ALIGN); if (!skb) return; skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, size); - memcpy(skb->data, entry->data_addr, size); + skb_put(skb, desc.size); + memcpy(skb->data, entry->data_addr, desc.size); /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, skb, signal, rssi, ofdm); + rt2x00lib_rxdone(entry, skb, &desc); -skip_entry: if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - rt2x00_set_field32(&desc, RXD_ENTRY_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, desc); + rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); } rt2x00_ring_index_inc(ring); diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index dc5b696f4751..b54457c921c5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -45,11 +45,9 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) return 0; /* - * Only continue if we have an active interface, - * either monitor or non-monitor should be present. + * Only continue if we have an active interface. */ - if (!is_interface_present(&rt2x00dev->interface) && - !is_monitor_present(&rt2x00dev->interface)) + if (!is_interface_present(&rt2x00dev->interface)) return 0; if (state == RFKILL_STATE_ON) { diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h index 122c75248e74..1a864d32cfbd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ring.h +++ b/drivers/net/wireless/rt2x00/rt2x00ring.h @@ -41,11 +41,24 @@ struct data_desc { }; /* - * data_entry_desc + * rxdata_entry_desc + * Summary of information that has been read from the + * RX frame descriptor. + */ +struct rxdata_entry_desc { + int signal; + int rssi; + int ofdm; + int size; + int flags; +}; + +/* + * txdata_entry_desc * Summary of information that should be written into the * descriptor for sending a TX frame. */ -struct data_entry_desc { +struct txdata_entry_desc { unsigned long flags; #define ENTRY_TXDONE 1 #define ENTRY_TXD_RTS_FRAME 2 diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index a0f05ca54bb4..8d2081189025 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -220,11 +220,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct data_ring *ring = entry->ring; struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; struct sk_buff *skb; - int retval; - int signal; - int rssi; - int ofdm; - int size; + struct rxdata_entry_desc desc; int frame_size; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || @@ -239,10 +235,8 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) if (urb->actual_length < entry->ring->desc_size || urb->status) goto skip_entry; - retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, &rssi, - &ofdm, &size); - if (retval) - goto skip_entry; + memset(&desc, 0x00, sizeof(desc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &desc); /* * Allocate a new sk buffer to replace the current one. @@ -261,12 +255,12 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * Trim the skb_buffer to only contain the valid * frame data (so ignore the device's descriptor). */ - skb_trim(entry->skb, size); + skb_trim(entry->skb, desc.size); /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, entry->skb, signal, rssi, ofdm); + rt2x00lib_rxdone(entry, entry->skb, &desc); /* * Replace current entry's skb with the newly allocated one, diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 09c8c96e2f83..dea7a8a4fa00 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -312,23 +312,9 @@ static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); } -static void rt61pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); - rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); -} - static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -343,57 +329,20 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0); rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); - /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); - else - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); - } - - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); - /* * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); - } - + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1686,7 +1635,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1826,8 +1775,8 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; } -static int rt61pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt61pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1836,19 +1785,19 @@ static int rt61pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - return 0; + return; } /* @@ -2340,9 +2289,7 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -2426,6 +2373,74 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt61pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); +} + static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -2506,11 +2521,13 @@ int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static const struct ieee80211_ops rt61pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt61pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -2540,7 +2557,6 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .fill_rxdone = rt61pci_fill_rxdone, .config_mac_addr = rt61pci_config_mac_addr, .config_bssid = rt61pci_config_bssid, - .config_packet_filter = rt61pci_config_packet_filter, .config_type = rt61pci_config_type, .config = rt61pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 3397881bd63d..aac13aa4039c 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -293,23 +293,9 @@ static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); } -static void rt73usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); - rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); -} - static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -324,57 +310,20 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); - /* - * Apply hardware packet filter. - */ - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); - else - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); - } - - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); - /* * Enable synchronisation. */ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); - } - + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1301,7 +1250,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1429,8 +1378,8 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; } -static int rt73usb_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt73usb_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = (struct data_desc *)entry->skb->data; u32 word0; @@ -1439,24 +1388,24 @@ static int rt73usb_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); /* * Pull the skb to clear the descriptor area. */ skb_pull(entry->skb, entry->ring->desc_size); - return 0; + return; } /* @@ -1802,9 +1751,7 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1878,11 +1825,9 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) rt73usb_probe_hw_mode(rt2x00dev); /* - * USB devices require scheduled packet filter toggling * This device requires firmware */ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1895,6 +1840,83 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt73usb_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); + return; + } + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); +} + static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1977,11 +1999,13 @@ int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static const struct ieee80211_ops rt73usb_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt73usb_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -2012,7 +2036,6 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .fill_rxdone = rt73usb_fill_rxdone, .config_mac_addr = rt73usb_config_mac_addr, .config_bssid = rt73usb_config_bssid, - .config_packet_filter = rt73usb_config_packet_filter, .config_type = rt73usb_config_type, .config = rt73usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 5d63a1a714f3..f0951519f74b 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -290,7 +290,7 @@ struct hw_pairwise_ta_entry { #define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000) #define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000) #define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000) -#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000) +#define TXRX_CSR0_DROP_BROADCAST FIELD32(0x01000000) #define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000) #define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000) diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 7993b3d87203..6ad322ef0da1 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -36,8 +36,7 @@ struct rtl8187_rx_info { }; struct rtl8187_rx_hdr { - __le16 len; - __le16 rate; + __le32 flags; u8 noise; u8 signal; u8 agc; @@ -74,7 +73,7 @@ struct rtl8187_priv { struct ieee80211_rate rates[12]; struct ieee80211_hw_mode modes[2]; struct usb_device *udev; - u8 *hwaddr; + u32 rx_conf; u16 txpwr_base; u8 asic_rev; struct sk_buff_head rx_queue; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index bf9f0cc5a645..b0a92f543da4 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -41,6 +41,57 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { MODULE_DEVICE_TABLE(usb, rtl8187_table); +static void rtl8187_iowrite_async_cb(struct urb *urb) +{ + kfree(urb->context); + usb_free_urb(urb); +} + +static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, + void *data, u16 len) +{ + struct usb_ctrlrequest *dr; + struct urb *urb; + struct rtl8187_async_write_data { + u8 data[4]; + struct usb_ctrlrequest dr; + } *buf; + + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) + return; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree(buf); + return; + } + + dr = &buf->dr; + + dr->bRequestType = RTL8187_REQT_WRITE; + dr->bRequest = RTL8187_REQ_SET_REG; + dr->wValue = addr; + dr->wIndex = 0; + dr->wLength = cpu_to_le16(len); + + memcpy(buf, data, len); + + usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), + (unsigned char *)dr, buf, len, + rtl8187_iowrite_async_cb, buf); + usb_submit_urb(urb, GFP_ATOMIC); +} + +static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, + __le32 *addr, u32 val) +{ + __le32 buf = cpu_to_le32(val); + + rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), + &buf, sizeof(buf)); +} + void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) { struct rtl8187_priv *priv = dev->priv; @@ -125,6 +176,7 @@ static void rtl8187_rx_cb(struct urb *urb) struct rtl8187_rx_hdr *hdr; struct ieee80211_rx_status rx_status = { 0 }; int rate, signal; + u32 flags; spin_lock(&priv->rx_queue.lock); if (skb->next) @@ -143,10 +195,11 @@ static void rtl8187_rx_cb(struct urb *urb) skb_put(skb, urb->actual_length); hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr)); - skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF); + flags = le32_to_cpu(hdr->flags); + skb_trim(skb, flags & 0x0FFF); signal = hdr->agc >> 1; - rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF; + rate = (flags >> 20) & 0xF; if (rate > 3) { /* OFDM rate */ if (signal > 90) signal = 90; @@ -169,6 +222,8 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.channel = dev->conf.channel; rx_status.phymode = dev->conf.phymode; rx_status.mactime = le64_to_cpu(hdr->mac_time); + if (flags & (1 << 13)) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); skb = dev_alloc_skb(RTL8187_MAX_RX); @@ -293,8 +348,6 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]); rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); @@ -365,7 +418,7 @@ static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel) rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); } -static int rtl8187_open(struct ieee80211_hw *dev) +static int rtl8187_start(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; u32 reg; @@ -383,16 +436,13 @@ static int rtl8187_open(struct ieee80211_hw *dev) RTL818X_RX_CONF_RX_AUTORESETPHY | RTL818X_RX_CONF_BSSID | RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_CTRL | RTL818X_RX_CONF_DATA | (7 << 13 /* RX FIFO threshold NONE */) | (7 << 10 /* MAX RX DMA */) | RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_MULTICAST | RTL818X_RX_CONF_NICMAC; - if (priv->mode == IEEE80211_IF_TYPE_MNTR) - reg |= RTL818X_RX_CONF_MONITOR; + priv->rx_conf = reg; rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); @@ -419,7 +469,7 @@ static int rtl8187_open(struct ieee80211_hw *dev) return 0; } -static int rtl8187_stop(struct ieee80211_hw *dev) +static void rtl8187_stop(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; struct rtl8187_rx_info *info; @@ -445,28 +495,31 @@ static int rtl8187_stop(struct ieee80211_hw *dev) usb_kill_urb(info->urb); kfree_skb(skb); } - return 0; + return; } static int rtl8187_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; + int i; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: priv->mode = conf->type; break; default: return -EOPNOTSUPP; } - priv->hwaddr = conf->mac_addr ? conf->mac_addr : dev->wiphy->perm_addr; + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->MAC[i], + ((u8 *)conf->mac_addr)[i]); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); return 0; } @@ -475,7 +528,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; } static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -523,14 +576,52 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id, return 0; } +static void rtl8187_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + struct rtl8187_priv *priv = dev->priv; + + *total_flags = 0; + + if (changed_flags & FIF_PROMISC_IN_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_NICMAC; + if (changed_flags & FIF_ALLMULTI) + priv->rx_conf ^= RTL818X_RX_CONF_MULTICAST; + if (changed_flags & FIF_FCSFAIL) + priv->rx_conf ^= RTL818X_RX_CONF_FCS; + if (changed_flags & FIF_CONTROL) + priv->rx_conf ^= RTL818X_RX_CONF_CTRL; + if (changed_flags & FIF_OTHER_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; + + if (mc_count > 0) + priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; + + if (priv->rx_conf & RTL818X_RX_CONF_NICMAC) + *total_flags |= FIF_PROMISC_IN_BSS; + if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) + *total_flags |= FIF_ALLMULTI; + if (priv->rx_conf & RTL818X_RX_CONF_FCS) + *total_flags |= FIF_FCSFAIL; + if (priv->rx_conf & RTL818X_RX_CONF_CTRL) + *total_flags |= FIF_CONTROL; + if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) + *total_flags |= FIF_OTHER_BSS; + + rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); +} + static const struct ieee80211_ops rtl8187_ops = { .tx = rtl8187_tx, - .open = rtl8187_open, + .start = rtl8187_start, .stop = rtl8187_stop, .add_interface = rtl8187_add_interface, .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .config_interface = rtl8187_config_interface, + .configure_filter = rtl8187_configure_filter, }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -604,7 +695,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->modes[1].rates = priv->rates; priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); priv->modes[1].channels = priv->channels; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 283de30628e1..880d4becae31 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -71,6 +71,7 @@ struct rtl818x_csr { #define RTL818X_RX_CONF_NICMAC (1 << 1) #define RTL818X_RX_CONF_MULTICAST (1 << 2) #define RTL818X_RX_CONF_BROADCAST (1 << 3) +#define RTL818X_RX_CONF_FCS (1 << 5) #define RTL818X_RX_CONF_DATA (1 << 18) #define RTL818X_RX_CONF_CTRL (1 << 19) #define RTL818X_RX_CONF_MGMT (1 << 20) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5ff45553a985..855754d4c50d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -467,7 +467,6 @@ enum ieee80211_if_types { * @mac_addr: pointer to MAC address of the interface. This pointer is valid * until the interface is removed (i.e. it cannot be used after * remove_interface() callback was called for this interface). - * This pointer will be %NULL for monitor interfaces, be careful. * * This structure is used in add_interface() and remove_interface() * callbacks of &struct ieee80211_hw. @@ -653,13 +652,9 @@ struct ieee80211_hw { /* hole at 8 */ - /* Device is capable of performing full monitor mode even during - * normal operation. */ -#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9) +/* hole at 9 */ - /* Device does not need BSSID filter set to broadcast in order to - * receive all probe responses while scanning */ -#define IEEE80211_HW_NO_PROBE_FILTERING (1<<10) +/* hole at 10 */ /* Channels are already configured to the default regulatory domain * specified in the device's EEPROM */ @@ -694,6 +689,39 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +/* + * flags for change_filter_flags() + * + * Note that e.g. if PROMISC_IN_BSS is unset then + * you should still do MAC address filtering if + * possible even if OTHER_BSS is set to indicate + * no BSSID filtering should be done. + */ +/* + * promiscuous mode within your BSS, + * think of the BSS as your network segment and then this corresponds + * to the regular ethernet device promiscuous mode + */ +#define FIF_PROMISC_IN_BSS 0x01 +/* show all multicast frames */ +#define FIF_ALLMULTI 0x02 +/* show frames with failed FCS, but set RX_FLAG_FAILED_FCS_CRC for them */ +#define FIF_FCSFAIL 0x04 +/* show frames with failed PLCP CRC, but set RX_FLAG_FAILED_PLCP_CRC for them */ +#define FIF_PLCPFAIL 0x08 +/* + * This flag is set during scanning to indicate to the hardware + * that it should not filter beacons or probe responses by BSSID. + */ +#define FIF_BCN_PRBRESP_PROMISC 0x10 +/* + * show control frames, if PROMISC_IN_BSS is not set then + * only those addressed to this station + */ +#define FIF_CONTROL 0x20 +/* show frames from other BSSes */ +#define FIF_OTHER_BSS 0x40 + /* Configuration block used by the low-level driver to tell the 802.11 code * about supported hardware features and to pass function pointers to callback * functions. */ @@ -706,32 +734,55 @@ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control); - /* Handler that is called when any netdevice attached to the hardware - * device is set UP for the first time. This can be used, e.g., to - * enable interrupts and beacon sending. */ - int (*open)(struct ieee80211_hw *hw); + /* + * Called before the first netdevice attached to the hardware + * is enabled. This should turn on the hardware and must turn on + * frame reception (for possibly enabled monitor interfaces.) + * Returns negative error codes, these may be seen in userspace, + * or zero. + * When the device is started it should not have a MAC address + * to avoid acknowledging frames before a non-monitor device + * is added. + * + * Must be implemented. + */ + int (*start)(struct ieee80211_hw *hw); - /* Handler that is called when the last netdevice attached to the - * hardware device is set DOWN. This can be used, e.g., to disable - * interrupts and beacon sending. */ - int (*stop)(struct ieee80211_hw *hw); + /* + * Called after last netdevice attached to the hardware + * 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. + * + * Must be implemented. + */ + void (*stop)(struct ieee80211_hw *hw); - /* Handler for asking a driver if a new interface can be added (or, - * more exactly, set UP). If the handler returns zero, the interface - * is added. Driver should perform any initialization it needs prior - * to returning zero. By returning non-zero addition of the interface - * is inhibited. Unless monitor_during_oper is set, it is guaranteed - * that monitor interfaces and normal interfaces are mutually - * exclusive. If assigned, the open() handler is called after - * add_interface() if this is the first device added. The - * add_interface() callback has to be assigned because it is the only - * way to obtain the requested MAC address for any interface. + /* + * Called when a netdevice attached to the hardware is enabled. + * Because it is not called for monitor mode devices, open() + * and stop() must be implemented. + * The driver should perform any initialization it needs before + * the device can be enabled. The initial configuration for the + * interface is given in the conf parameter. + * + * Must be implemented. */ int (*add_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); - /* Notify a driver that an interface is going down. The stop() handler - * is called prior to this if this is a last interface. */ + /* + * Notifies a driver that an interface is going down. The stop() handler + * is called after this if it is the last interface and no monitor + * interfaces are present. + * When all interfaces are removed, the MAC address in the hardware + * must be cleared so the device no longer acknowledges packets, + * the mac_addr member of the conf structure is, however, set to the + * MAC address of the device going away. + * + * Hence, this callback must be implemented. + */ void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); @@ -744,15 +795,21 @@ struct ieee80211_ops { int (*config_interface)(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf); - /* ieee80211 drivers do not have access to the &struct net_device - * that is (are) connected with their device. Hence (and because - * we need to combine the multicast lists and flags for multiple - * virtual interfaces), they cannot assign set_multicast_list. - * The parameters here replace dev->flags and dev->mc_count, - * dev->mc_list is replaced by calling ieee80211_get_mc_list_item. - * Must be atomic. */ - void (*set_multicast_list)(struct ieee80211_hw *hw, - unsigned short flags, int mc_count); + /* + * Configure the device's RX filter. + * + * The multicast address filter must be changed if the hardware flags + * indicate that one is present. + * + * All unsupported flags in 'total_flags' must be cleared, + * clear all bits except those you honoured. + * + * The callback must be implemented and must be atomic. + */ + void (*configure_filter)(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list); /* Set TIM bit handler. If the hardware/firmware takes care of beacon * generation, IEEE 802.11 code uses this function to tell the @@ -1155,24 +1212,6 @@ void ieee80211_stop_queues(struct ieee80211_hw *hw); */ void ieee80211_wake_queues(struct ieee80211_hw *hw); -/** - * ieee80211_get_mc_list_item - iteration over items in multicast list - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @prev: value returned by previous call to ieee80211_get_mc_list_item() or - * NULL to start a new iteration. - * @ptr: pointer to buffer of void * type for internal usage of - * ieee80211_get_mc_list_item(). - * - * Iterates over items in multicast list of given device. To get the first - * item, pass NULL in @prev and in *@ptr. In subsequent calls, pass the - * value returned by previous call in @prev. Don't alter *@ptr during - * iteration. When there are no more items, NULL is returned. - */ -struct dev_mc_list * -ieee80211_get_mc_list_item(struct ieee80211_hw *hw, - struct dev_mc_list *prev, - void **ptr); - /* called by driver to notify scan status completed */ void ieee80211_scan_completed(struct ieee80211_hw *hw); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 9efb84c47bb0..c9948fa58e08 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -165,20 +165,6 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); /* VLAN attributes */ IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC); -/* MONITOR attributes */ -static ssize_t ieee80211_if_fmt_mode( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - struct ieee80211_local *local = sdata->local; - - return scnprintf(buf, buflen, "%s\n", - ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) || - local->open_count == local->monitors) ? - "hard" : "soft"); -} -__IEEE80211_IF_FILE(mode); - - #define DEBUGFS_ADD(name, type)\ sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ sdata->debugfsdir, sdata, &name##_ops); @@ -242,7 +228,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) static void add_monitor_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(mode, monitor); } static void add_files(struct ieee80211_sub_if_data *sdata) @@ -337,7 +322,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) static void del_monitor_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(mode, monitor); } static void del_files(struct ieee80211_sub_if_data *sdata, int type) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 57ec8880bb1a..319ec2a1d84f 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -53,6 +53,38 @@ static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) return ETH_ALEN; } +/* must be called under mdev tx lock */ +static void ieee80211_configure_filter(struct ieee80211_local *local) +{ + unsigned int changed_flags; + unsigned int new_flags = 0; + + if (local->iff_promiscs) + new_flags |= FIF_PROMISC_IN_BSS; + + if (local->iff_allmultis) + new_flags |= FIF_ALLMULTI; + + if (local->monitors) + new_flags |= FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed_flags = local->filter_flags ^ new_flags; + + /* be a bit nasty */ + new_flags |= (1<<31); + + local->ops->configure_filter(local_to_hw(local), + changed_flags, &new_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + WARN_ON(new_flags & (1<<31)); + + local->filter_flags = new_flags & ~(1<<31); +} + /* master interface */ static int ieee80211_master_open(struct net_device *dev) @@ -86,6 +118,13 @@ static int ieee80211_master_stop(struct net_device *dev) return 0; } +static void ieee80211_master_set_multicast_list(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + ieee80211_configure_filter(local); +} + /* management interface */ static void @@ -267,49 +306,6 @@ static inline int identical_mac_addr_allowed(int type1, int type2) type2 == IEEE80211_IF_TYPE_VLAN))); } -/* Check if running monitor interfaces should go to a "soft monitor" mode - * and switch them if necessary. */ -static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && - local->ops->remove_interface) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->remove_interface(local_to_hw(local), &conf); - } -} - -/* Check if running monitor interfaces should go to a "hard monitor" mode - * and switch them if necessary. */ -static void ieee80211_start_hard_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->add_interface(local_to_hw(local), &conf); - } -} - -static void ieee80211_if_open(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - break; - } -} - static int ieee80211_open(struct net_device *dev) { struct ieee80211_sub_if_data *sdata, *nsdata; @@ -335,84 +331,96 @@ static int ieee80211_open(struct net_device *dev) is_zero_ether_addr(sdata->u.wds.remote_addr)) return -ENOLINK; - if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* run the interface in a "soft monitor" mode */ - local->monitors++; - local->open_count++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - return 0; - } - ieee80211_if_open(dev); - ieee80211_start_soft_monitor(local); - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - if (sdata->type == IEEE80211_IF_TYPE_MNTR) - conf.mac_addr = NULL; - else - conf.mac_addr = dev->dev_addr; - res = local->ops->add_interface(local_to_hw(local), &conf); - if (res) { - if (sdata->type == IEEE80211_IF_TYPE_MNTR) - ieee80211_start_hard_monitor(local); - return res; - } - if (local->open_count == 0) { res = 0; - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - if (local->ops->open) - res = local->ops->open(local_to_hw(local)); - if (res == 0) { - res = dev_open(local->mdev); - if (res) { - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - } else { - res = ieee80211_hw_config(local); - if (res && local->ops->stop) - local->ops->stop(local_to_hw(local)); - else if (!res && local->apdev) - dev_open(local->apdev); - } - } - if (res) { - if (local->ops->remove_interface) - local->ops->remove_interface(local_to_hw(local), - &conf); + if (local->ops->start) + res = local->ops->start(local_to_hw(local)); + if (res) return res; - } } - local->open_count++; - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { + switch (sdata->type) { + case IEEE80211_IF_TYPE_MNTR: + /* must be before the call to ieee80211_configure_filter */ local->monitors++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - } else { + if (local->monitors == 1) { + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); + + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + ieee80211_hw_config(local); + } + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; + /* fall through */ + default: + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; + res = local->ops->add_interface(local_to_hw(local), &conf); + if (res && !local->open_count && local->ops->stop) + local->ops->stop(local_to_hw(local)); + if (res) + return res; + ieee80211_if_config(dev); ieee80211_reset_erp_info(dev); ieee80211_enable_keys(sdata); + + if (sdata->type == IEEE80211_IF_TYPE_STA && + !local->user_space_mlme) + netif_carrier_off(dev); + else + netif_carrier_on(dev); } - if (sdata->type == IEEE80211_IF_TYPE_STA && - !local->user_space_mlme) - netif_carrier_off(dev); - else - netif_carrier_on(dev); + if (local->open_count == 0) { + res = dev_open(local->mdev); + WARN_ON(res); + if (local->apdev) { + res = dev_open(local->apdev); + WARN_ON(res); + } + tasklet_enable(&local->tx_pending_tasklet); + tasklet_enable(&local->tasklet); + } + + local->open_count++; netif_start_queue(dev); + return 0; } -static void ieee80211_if_shutdown(struct net_device *dev) +static int ieee80211_stop(struct net_device *dev) { + struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_init_conf conf; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + netif_stop_queue(dev); + + dev_mc_unsync(local->mdev, dev); + + local->open_count--; - ASSERT_RTNL(); switch (sdata->type) { + case IEEE80211_IF_TYPE_MNTR: + local->monitors--; + if (local->monitors == 0) { + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); + + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + ieee80211_hw_config(local); + } + break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.state = IEEE80211_DISABLED; @@ -433,116 +441,61 @@ static void ieee80211_if_shutdown(struct net_device *dev) cancel_delayed_work(&local->scan_work); } flush_workqueue(local->hw.workqueue); - break; - } -} - -static int ieee80211_stop(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR && - local->open_count > 1 && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* remove "soft monitor" interface */ - local->open_count--; - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - return 0; - } - - netif_stop_queue(dev); - ieee80211_if_shutdown(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - } else { - /* disable all keys for as long as this netdev is down */ - ieee80211_disable_keys(sdata); - } - - local->open_count--; - if (local->open_count == 0) { - if (netif_running(local->mdev)) - dev_close(local->mdev); - if (local->apdev) - dev_close(local->apdev); - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - tasklet_disable(&local->tx_pending_tasklet); - tasklet_disable(&local->tasklet); - } - if (local->ops->remove_interface) { - struct ieee80211_if_init_conf conf; - + /* fall through */ + default: conf.if_id = dev->ifindex; conf.type = sdata->type; conf.mac_addr = dev->dev_addr; + /* disable all keys for as long as this netdev is down */ + ieee80211_disable_keys(sdata); local->ops->remove_interface(local_to_hw(local), &conf); } - ieee80211_start_hard_monitor(local); + if (local->open_count == 0) { + if (netif_running(local->mdev)) + dev_close(local->mdev); + + if (local->apdev) + dev_close(local->apdev); + + if (local->ops->stop) + local->ops->stop(local_to_hw(local)); + + tasklet_disable(&local->tx_pending_tasklet); + tasklet_disable(&local->tasklet); + } return 0; } -enum netif_tx_lock_class { - TX_LOCK_NORMAL, - TX_LOCK_MASTER, -}; - -static inline void netif_tx_lock_nested(struct net_device *dev, int subclass) -{ - spin_lock_nested(&dev->_xmit_lock, subclass); - dev->xmit_lock_owner = smp_processor_id(); -} - static void ieee80211_set_multicast_list(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - unsigned short flags; + int allmulti, promisc, sdata_allmulti, sdata_promisc; - netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); - if (((dev->flags & IFF_ALLMULTI) != 0) ^ - ((sdata->flags & IEEE80211_SDATA_ALLMULTI) != 0)) { - if (sdata->flags & IEEE80211_SDATA_ALLMULTI) - local->iff_allmultis--; - else + allmulti = !!(dev->flags & IFF_ALLMULTI); + promisc = !!(dev->flags & IFF_PROMISC); + sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; + sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC; + + if (allmulti != sdata_allmulti) { + if (dev->flags & IFF_ALLMULTI) local->iff_allmultis++; + else + local->iff_allmultis--; sdata->flags ^= IEEE80211_SDATA_ALLMULTI; } - if (((dev->flags & IFF_PROMISC) != 0) ^ - ((sdata->flags & IEEE80211_SDATA_PROMISC) != 0)) { - if (sdata->flags & IEEE80211_SDATA_PROMISC) - local->iff_promiscs--; - else + + if (promisc != sdata_promisc) { + if (dev->flags & IFF_PROMISC) local->iff_promiscs++; + else + local->iff_promiscs--; sdata->flags ^= IEEE80211_SDATA_PROMISC; } - if (dev->mc_count != sdata->mc_count) { - local->mc_count = local->mc_count - sdata->mc_count + - dev->mc_count; - sdata->mc_count = dev->mc_count; - } - if (local->ops->set_multicast_list) { - flags = local->mdev->flags; - if (local->iff_allmultis) - flags |= IFF_ALLMULTI; - if (local->iff_promiscs) - flags |= IFF_PROMISC; - read_lock(&local->sub_if_lock); - local->ops->set_multicast_list(local_to_hw(local), flags, - local->mc_count); - read_unlock(&local->sub_if_lock); - } - netif_tx_unlock(local->mdev); + + dev_mc_sync(local->mdev, dev); } static const struct header_ops ieee80211_header_ops = { @@ -612,7 +565,6 @@ static int __ieee80211_if_config(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_if_conf conf; - static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (!local->ops->config_interface || !netif_running(dev)) return 0; @@ -621,11 +573,7 @@ static int __ieee80211_if_config(struct net_device *dev, conf.type = sdata->type; if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { - if (local->sta_scanning && - local->scan_dev == dev) - conf.bssid = scan_bssid; - else - conf.bssid = sdata->u.sta.bssid; + conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; conf.generic_elem = sdata->u.sta.extra_ie; @@ -722,37 +670,6 @@ void ieee80211_reset_erp_info(struct net_device *dev) IEEE80211_ERP_CHANGE_PREAMBLE); } -struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, - struct dev_mc_list *prev, - void **ptr) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata = *ptr; - struct dev_mc_list *mc; - - if (!prev) { - WARN_ON(sdata); - sdata = NULL; - } - if (!prev || !prev->next) { - if (sdata) - sdata = list_entry(sdata->list.next, - struct ieee80211_sub_if_data, list); - else - sdata = list_entry(local->sub_if_list.next, - struct ieee80211_sub_if_data, list); - if (&sdata->list != &local->sub_if_list) - mc = sdata->dev->mc_list; - else - mc = NULL; - } else - mc = prev->next; - - *ptr = sdata; - return mc; -} -EXPORT_SYMBOL(ieee80211_get_mc_list_item); - void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) @@ -1158,8 +1075,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); BUG_ON(!ops->tx); + BUG_ON(!ops->start); + BUG_ON(!ops->stop); BUG_ON(!ops->config); BUG_ON(!ops->add_interface); + BUG_ON(!ops->remove_interface); + BUG_ON(!ops->configure_filter); local->ops = ops; /* for now, mdev needs sub_if_data :/ */ @@ -1206,6 +1127,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; mdev->header_ops = &ieee80211_header_ops; + mdev->set_multicast_list = ieee80211_master_set_multicast_list; sdata->type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c3f6f89755b1..74deecd09677 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -297,8 +297,6 @@ struct ieee80211_sub_if_data { struct net_device *dev; struct ieee80211_local *local; - int mc_count; - unsigned int flags; int drop_unencrypted; @@ -411,6 +409,7 @@ struct ieee80211_local { struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ int open_count; int monitors; + unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; u8 wstats_flags; int tx_headroom; /* required headroom for hardware/radiotap */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 3f0a2faf37d4..17455c6a5229 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2662,10 +2662,16 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) printk(KERN_DEBUG "%s: failed to restore operational" "channel after scan\n", dev->name); - if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && - ieee80211_if_config(dev)) - printk(KERN_DEBUG "%s: failed to restore operational" - "BSSID after scan\n", dev->name); + + netif_tx_lock_bh(local->mdev); + local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + netif_tx_unlock_bh(local->mdev); memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); @@ -2849,10 +2855,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev, local->scan_channel_idx = 0; local->scan_dev = dev; - if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && - ieee80211_if_config(dev)) - printk(KERN_DEBUG "%s: failed to set BSSID for scan\n", - dev->name); + netif_tx_lock_bh(local->mdev); + local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + netif_tx_unlock_bh(local->mdev); /* 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/rx.c b/net/mac80211/rx.c index b5f2e4c25c7e..2535d8d4ce90 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1307,7 +1307,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { - if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) + if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } @@ -1322,7 +1322,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { - if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) + if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } else if (!rx->sta) From 0ec3ca445931ff0e7ad6ac61d6c5d2aaafe7a9f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Sep 2007 01:29:24 -0400 Subject: [PATCH 1547/2804] [PATCH] mac80211: validate VLAN interfaces better This patch changes mac80211 to verify that VLAN interfaces are valid and not bother drivers about them any more. VLAN interfaces are now only valid when an AP interface is up with the same MAC address, and are automatically turned off when the AP interface is set down. Signed-off-by: Johannes Berg Cc: Jouni Malinen Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- include/net/mac80211.h | 17 ++++++----- net/mac80211/debugfs_netdev.c | 5 ---- net/mac80211/ieee80211.c | 54 +++++++++++++++++++++++++++++----- net/mac80211/ieee80211_i.h | 6 ++-- net/mac80211/ieee80211_iface.c | 5 ++++ 5 files changed, 65 insertions(+), 22 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 855754d4c50d..494a4c022a9b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -442,16 +442,17 @@ struct ieee80211_conf { * @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode. * @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode. * @IEEE80211_IF_TYPE_WDS: interface in WDS mode. - * @IEEE80211_IF_TYPE_VLAN: not used. + * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers + * will never see this type. */ enum ieee80211_if_types { - IEEE80211_IF_TYPE_AP = 0x00000000, - IEEE80211_IF_TYPE_MGMT = 0x00000001, - IEEE80211_IF_TYPE_STA = 0x00000002, - IEEE80211_IF_TYPE_IBSS = 0x00000003, - IEEE80211_IF_TYPE_MNTR = 0x00000004, - IEEE80211_IF_TYPE_WDS = 0x5A580211, - IEEE80211_IF_TYPE_VLAN = 0x00080211, + IEEE80211_IF_TYPE_AP, + IEEE80211_IF_TYPE_MGMT, + IEEE80211_IF_TYPE_STA, + IEEE80211_IF_TYPE_IBSS, + IEEE80211_IF_TYPE_MNTR, + IEEE80211_IF_TYPE_WDS, + IEEE80211_IF_TYPE_VLAN, }; /** diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index c9948fa58e08..f0e6ab7eb624 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -162,9 +162,6 @@ __IEEE80211_IF_FILE(beacon_tail_len); /* WDS attributes */ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); -/* VLAN attributes */ -IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC); - #define DEBUGFS_ADD(name, type)\ sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ sdata->debugfsdir, sdata, &name##_ops); @@ -223,7 +220,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(drop_unencrypted, vlan); DEBUGFS_ADD(eapol, vlan); DEBUGFS_ADD(ieee8021_x, vlan); - DEBUGFS_ADD(vlan_id, vlan); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -317,7 +313,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(drop_unencrypted, vlan); DEBUGFS_DEL(eapol, vlan); DEBUGFS_DEL(ieee8021_x, vlan); - DEBUGFS_DEL(vlan_id, vlan); } static void del_monitor_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 319ec2a1d84f..4e345f82f044 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -314,22 +314,43 @@ static int ieee80211_open(struct net_device *dev) int res; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + read_lock(&local->sub_if_lock); list_for_each_entry(nsdata, &local->sub_if_list, list) { struct net_device *ndev = nsdata->dev; if (ndev != dev && ndev != local->mdev && netif_running(ndev) && - compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 && - !identical_mac_addr_allowed(sdata->type, nsdata->type)) { - read_unlock(&local->sub_if_lock); - return -ENOTUNIQ; + compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) { + /* + * check whether it may have the same address + */ + if (!identical_mac_addr_allowed(sdata->type, + nsdata->type)) { + read_unlock(&local->sub_if_lock); + return -ENOTUNIQ; + } + + /* + * can only add VLANs to enabled APs + */ + if (sdata->type == IEEE80211_IF_TYPE_VLAN && + nsdata->type == IEEE80211_IF_TYPE_AP && + netif_running(nsdata->dev)) + sdata->u.vlan.ap = nsdata; } } read_unlock(&local->sub_if_lock); - if (sdata->type == IEEE80211_IF_TYPE_WDS && - is_zero_ether_addr(sdata->u.wds.remote_addr)) - return -ENOLINK; + switch (sdata->type) { + case IEEE80211_IF_TYPE_WDS: + if (is_zero_ether_addr(sdata->u.wds.remote_addr)) + return -ENOLINK; + break; + case IEEE80211_IF_TYPE_VLAN: + if (!sdata->u.vlan.ap) + return -ENOLINK; + break; + } if (local->open_count == 0) { res = 0; @@ -340,6 +361,10 @@ static int ieee80211_open(struct net_device *dev) } switch (sdata->type) { + case IEEE80211_IF_TYPE_VLAN: + list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans); + /* no need to tell driver */ + break; case IEEE80211_IF_TYPE_MNTR: /* must be before the call to ieee80211_configure_filter */ local->monitors++; @@ -407,9 +432,24 @@ static int ieee80211_stop(struct net_device *dev) dev_mc_unsync(local->mdev, dev); + /* down all dependent devices, that is VLANs */ + if (sdata->type == IEEE80211_IF_TYPE_AP) { + struct ieee80211_sub_if_data *vlan, *tmp; + + list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, + u.vlan.list) + dev_close(vlan->dev); + WARN_ON(!list_empty(&sdata->u.ap.vlans)); + } + local->open_count--; switch (sdata->type) { + case IEEE80211_IF_TYPE_VLAN: + list_del(&sdata->u.vlan.list); + sdata->u.vlan.ap = NULL; + /* no need to tell driver */ + break; case IEEE80211_IF_TYPE_MNTR: local->monitors--; if (local->monitors == 0) { diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 74deecd09677..1a43f3e9b6bd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -191,6 +191,8 @@ struct ieee80211_if_ap { u8 *beacon_head, *beacon_tail; int beacon_head_len, beacon_tail_len; + struct list_head vlans; + u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; u8 *generic_elem; @@ -214,7 +216,8 @@ struct ieee80211_if_wds { }; struct ieee80211_if_vlan { - u8 id; + struct ieee80211_sub_if_data *ap; + struct list_head list; }; /* flags used in struct ieee80211_if_sta.flags */ @@ -377,7 +380,6 @@ struct ieee80211_sub_if_data { struct dentry *drop_unencrypted; struct dentry *eapol; struct dentry *ieee8021_x; - struct dentry *vlan_id; } vlan; struct { struct dentry *mode; diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index f9c74bb09d31..4590205fdf4b 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -164,6 +164,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) sdata->bss = NULL; break; case IEEE80211_IF_TYPE_VLAN: + sdata->u.vlan.ap = NULL; break; case IEEE80211_IF_TYPE_AP: sdata->u.ap.dtim_period = 2; @@ -171,6 +172,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) sdata->u.ap.max_ratectrl_rateidx = -1; skb_queue_head_init(&sdata->u.ap.ps_bc_buf); sdata->bss = &sdata->u.ap; + INIT_LIST_HEAD(&sdata->u.ap.vlans); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: { @@ -284,6 +286,9 @@ void ieee80211_if_reinit(struct net_device *dev) case IEEE80211_IF_TYPE_MNTR: dev->type = ARPHRD_ETHER; break; + case IEEE80211_IF_TYPE_VLAN: + sdata->u.vlan.ap = NULL; + break; } /* remove all STAs that are bound to this virtual interface */ From 1bc0826c8f5f3fa26644a8e878aae0be304a670f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:15 -0400 Subject: [PATCH 1548/2804] [PATCH] mac80211: renumber and document the hardware flags Currently, hardware flags that drivers must set are not documented well enough. Fix this. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- include/net/mac80211.h | 85 ++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 494a4c022a9b..c5554ad87a17 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -598,6 +598,51 @@ typedef enum set_key_cmd { SET_KEY, DISABLE_KEY, } set_key_cmd; + +/** + * enum ieee80211_hw_flags - hardware flags + * + * These flags are used to indicate hardware capabilities to + * the stack. Generally, flags here should have their meaning + * done in a way that the simplest hardware doesn't need setting + * any particular flags. There are some exceptions to this rule, + * however, so you are advised to review these flags carefully. + * + * @IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE: + * The device only needs to be supplied with a beacon template. + * If you need the host to generate each beacon then don't use + * this flag and call ieee80211_beacon_get() when you need the + * next beacon frame. Note that if you set this flag, you must + * implement the set_tim() callback for powersave mode to work + * properly. + * This flag is only relevant for access-point mode. + * + * @IEEE80211_HW_RX_INCLUDES_FCS: + * Indicates that received frames passed to the stack include + * the FCS at the end. + * + * @IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING: + * Some wireless LAN chipsets buffer broadcast/multicast frames + * for power saving stations in the hardware/firmware and others + * rely on the host system for such buffering. This option is used + * to configure the IEEE 802.11 upper layer to buffer broadcast and + * multicast frames when there are power saving stations so that + * the driver can fetch them with ieee80211_get_buffered_bc(). Note + * that not setting this flag works properly only when the + * %IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is also not set because + * otherwise the stack will not know when the DTIM beacon was sent. + * + * @IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED: + * Channels are already configured to the default regulatory domain + * specified in the device's EEPROM + */ +enum ieee80211_hw_flags { + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0, + IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, + IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED = 1<<3, +}; + /** * struct ieee80211_hw - hardware information and state * TODO: move documentation into kernel-doc format @@ -621,46 +666,6 @@ struct ieee80211_hw { /* The rest is information about your hardware */ - /* TODO: frame_type 802.11/802.3, sw_encryption requirements */ - -/* hole at 0 */ - - /* - * The device only needs to be supplied with a beacon template. - * If you need the host to generate each beacon then don't use - * this flag and use ieee80211_beacon_get(). - */ -#define IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE (1<<1) - -/* hole at 2 */ - - /* Whether RX frames passed to ieee80211_rx() include FCS in the end */ -#define IEEE80211_HW_RX_INCLUDES_FCS (1<<3) - - /* Some wireless LAN chipsets buffer broadcast/multicast frames for - * power saving stations in the hardware/firmware and others rely on - * the host system for such buffering. This option is used to - * configure the IEEE 802.11 upper layer to buffer broadcast/multicast - * frames when there are power saving stations so that low-level driver - * can fetch them with ieee80211_get_buffered_bc(). */ -#define IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING (1<<4) - -/* hole at 5 */ - -/* hole at 6 */ - -/* hole at 7 */ - -/* hole at 8 */ - -/* hole at 9 */ - -/* hole at 10 */ - - /* Channels are already configured to the default regulatory domain - * specified in the device's EEPROM */ -#define IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED (1<<11) - u32 flags; /* hardware flags defined above */ /* Set to the size of a needed device specific skb headroom for TX skbs. */ From 75a5f0ccfdbc0151ee40bb742f7b5c8eba493c0e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:20 -0400 Subject: [PATCH 1549/2804] [PATCH] mac80211: document a lot more This patch adds a lot more documentation (in kernel-doc format) to include/net/mac80211.h Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- include/net/mac80211.h | 794 ++++++++++++++++++++++++++--------------- 1 file changed, 500 insertions(+), 294 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c5554ad87a17..d2cf734402e3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -22,29 +22,51 @@ #include #include -/* Note! Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be +/** + * DOC: Introduction + * + * mac80211 is the Linux stack for 802.11 hardware that implements + * only partial functionality in hard- or firmware. This document + * defines the interface between mac80211 and low-level hardware + * drivers. + */ + +/** + * DOC: Calling mac80211 from interrupts + * + * Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be * called in hardware interrupt context. The low-level driver must not call any * other functions in hardware interrupt context. If there is a need for such * call, the low-level driver should first ACK the interrupt and perform the - * IEEE 802.11 code call after this, e.g., from a scheduled tasklet (in - * software interrupt context). + * IEEE 802.11 code call after this, e.g. from a scheduled workqueue function. */ -/* - * Frame format used when passing frame between low-level hardware drivers - * and IEEE 802.11 driver the same as used in the wireless media, i.e., - * buffers start with IEEE 802.11 header and include the same octets that - * are sent over air. +/** + * DOC: Warning * - * If hardware uses IEEE 802.3 headers (and perform 802.3 <-> 802.11 - * conversion in firmware), upper layer 802.11 code needs to be changed to - * support this. + * If you're reading this document and not the header file itself, it will + * be incomplete because not all documentation has been converted yet. + */ + +/** + * DOC: Frame format * - * If the receive frame format is not the same as the real frame sent - * on the wireless media (e.g., due to padding etc.), upper layer 802.11 code - * could be updated to provide support for such format assuming this would - * optimize the performance, e.g., by removing need to re-allocation and - * copying of the data. + * As a general rule, when frames are passed between mac80211 and the driver, + * they start with the IEEE 802.11 header and include the same octets that are + * sent over the air except for the FCS which should be calculated by the + * hardware. + * + * There are, however, various exceptions to this rule for advanced features: + * + * The first exception is for hardware encryption and decryption offload + * where the IV/ICV may or may not be generated in hardware. + * + * Secondly, when the hardware handles fragmentation, the frame handed to + * the driver from mac80211 is the MSDU, not the MPDU. + * + * Finally, for received frames, the driver is able to indicate that it has + * filled a radiotap header and put that in front of the frame; if it does + * not do so then mac80211 may add this under certain circumstances. */ #define IEEE80211_CHAN_W_SCAN 0x00000001 @@ -480,7 +502,7 @@ enum ieee80211_if_types { */ struct ieee80211_if_init_conf { int if_id; - int type; + enum ieee80211_if_types type; void *mac_addr; }; @@ -645,351 +667,426 @@ enum ieee80211_hw_flags { /** * struct ieee80211_hw - hardware information and state - * TODO: move documentation into kernel-doc format + * + * This structure contains the configuration and hardware + * information for an 802.11 PHY. + * + * @wiphy: This points to the &struct wiphy allocated for this + * 802.11 PHY. You must fill in the @perm_addr and @dev + * members of this structure using SET_IEEE80211_DEV() + * and SET_IEEE80211_PERM_ADDR(). + * + * @conf: &struct ieee80211_conf, device configuration, don't use. + * + * @workqueue: single threaded workqueue available for driver use, + * allocated by mac80211 on registration and flushed on + * unregistration. + * + * @priv: pointer to private area that was allocated for driver use + * along with this structure. + * + * @flags: hardware flags, see &enum ieee80211_hw_flags. + * + * @extra_tx_headroom: headroom to reserve in each transmit skb + * for use by the driver (e.g. for transmit headers.) + * + * @channel_change_time: time (in microseconds) it takes to change channels. + * + * @max_rssi: Maximum value for ssi in RX information, use + * negative numbers for dBm and 0 to indicate no support. + * + * @max_signal: like @max_rssi, but for the signal value. + * + * @max_noise: like @max_rssi, but for the noise value. + * + * @queues: number of available hardware transmit queues for + * data packets. WMM/QoS requires at least four. */ struct ieee80211_hw { - /* points to the cfg80211 wiphy for this piece. Note - * that you must fill in the perm_addr and dev fields - * of this structure, use the macros provided below. */ - struct wiphy *wiphy; - - /* assigned by mac80211, don't write */ struct ieee80211_conf conf; - - /* Single thread workqueue available for driver use - * Allocated by mac80211 on registration */ + struct wiphy *wiphy; struct workqueue_struct *workqueue; - - /* Pointer to the private area that was - * allocated with this struct for you. */ void *priv; - - /* The rest is information about your hardware */ - - u32 flags; /* hardware flags defined above */ - - /* Set to the size of a needed device specific skb headroom for TX skbs. */ + u32 flags; unsigned int extra_tx_headroom; - - /* This is the time in us to change channels - */ int channel_change_time; - /* Maximum values for various statistics. - * Leave at 0 to indicate no support. Use negative numbers for dBm. */ + u8 queues; s8 max_rssi; s8 max_signal; s8 max_noise; - - /* Number of available hardware TX queues for data packets. - * WMM requires at least four queues. */ - int queues; }; +/** + * SET_IEEE80211_DEV - set device for 802.11 hardware + * + * @hw: the &struct ieee80211_hw to set the device for + * @dev: the &struct device of this 802.11 device + */ static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev) { set_wiphy_dev(hw->wiphy, dev); } +/** + * SET_IEEE80211_PERM_ADDR - set the permanenet MAC address for 802.11 hardware + * + * @hw: the &struct ieee80211_hw to set the MAC address for + * @addr: the address to set + */ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) { memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } -/* - * flags for change_filter_flags() +/** + * DOC: Hardware crypto acceleration * - * Note that e.g. if PROMISC_IN_BSS is unset then - * you should still do MAC address filtering if - * possible even if OTHER_BSS is set to indicate - * no BSSID filtering should be done. + * mac80211 is capable of taking advantage of many hardware + * acceleration designs for encryption and decryption operations. + * + * The set_key() callback in the &struct ieee80211_ops for a given + * device is called to enable hardware acceleration of encryption and + * decryption. The callback takes an @address parameter that will be + * the broadcast address for default keys, the other station's hardware + * address for individual keys or the zero address for keys that will + * be used only for transmission. + * Multiple transmission keys with the same key index may be used when + * VLANs are configured for an access point. + * + * The @local_address parameter will always be set to our own address, + * this is only relevant if you support multiple local addresses. + * + * When transmitting, the TX control data will use the @hw_key_idx + * selected by the driver by modifying the &struct ieee80211_key_conf + * pointed to by the @key parameter to the set_key() function. + * + * The set_key() call for the %SET_KEY command should return 0 if + * the key is now in use, -%EOPNOTSUPP or -%ENOSPC if it couldn't be + * added; if you return 0 then hw_key_idx must be assigned to the + * hardware key index, you are free to use the full u8 range. + * + * When the cmd is %DISABLE_KEY then it must succeed. + * + * Note that it is permissible to not decrypt a frame even if a key + * for it has been uploaded to hardware, the stack will not make any + * decision based on whether a key has been uploaded or not but rather + * based on the receive flags. + * + * The &struct ieee80211_key_conf structure pointed to by the @key + * parameter is guaranteed to be valid until another call to set_key() + * removes it, but it can only be used as a cookie to differentiate + * keys. */ -/* - * promiscuous mode within your BSS, - * think of the BSS as your network segment and then this corresponds - * to the regular ethernet device promiscuous mode - */ -#define FIF_PROMISC_IN_BSS 0x01 -/* show all multicast frames */ -#define FIF_ALLMULTI 0x02 -/* show frames with failed FCS, but set RX_FLAG_FAILED_FCS_CRC for them */ -#define FIF_FCSFAIL 0x04 -/* show frames with failed PLCP CRC, but set RX_FLAG_FAILED_PLCP_CRC for them */ -#define FIF_PLCPFAIL 0x08 -/* - * This flag is set during scanning to indicate to the hardware - * that it should not filter beacons or probe responses by BSSID. - */ -#define FIF_BCN_PRBRESP_PROMISC 0x10 -/* - * show control frames, if PROMISC_IN_BSS is not set then - * only those addressed to this station - */ -#define FIF_CONTROL 0x20 -/* show frames from other BSSes */ -#define FIF_OTHER_BSS 0x40 -/* Configuration block used by the low-level driver to tell the 802.11 code - * about supported hardware features and to pass function pointers to callback - * functions. */ +/** + * DOC: Frame filtering + * + * mac80211 requires to see many management frames for proper + * operation, and users may want to see many more frames when + * in monitor mode. However, for best CPU usage and power consumption, + * having as few frames as possible percolate through the stack is + * desirable. Hence, the hardware should filter as much as possible. + * + * To achieve this, mac80211 uses filter flags (see below) to tell + * 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. + * + * If your device has no multicast address filters your driver will + * need to check both the %FIF_ALLMULTI flag and the @mc_count + * parameter to see whether multicast frames should be accepted + * or dropped. + * + * All unsupported flags in @total_flags must be cleared, i.e. you + * should clear all bits except those you honoured. + */ + +/** + * enum ieee80211_filter_flags - hardware filter flags + * + * These flags determine what the filter in hardware should be + * programmed to let through and what should not be passed to the + * stack. It is always safe to pass more frames than requested, + * but this has negative impact on power consumption. + * + * @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS, + * think of the BSS as your network segment and then this corresponds + * to the regular ethernet device promiscuous mode. + * + * @FIF_ALLMULTI: pass all multicast frames, this is used if requested + * by the user or if the hardware is not capable of filtering by + * multicast address. + * + * @FIF_FCSFAIL: pass frames with failed FCS (but you need to set the + * %RX_FLAG_FAILED_FCS_CRC for them) + * + * @FIF_PLCPFAIL: pass frames with failed PLCP CRC (but you need to set + * the %RX_FLAG_FAILED_PLCP_CRC for them + * + * @FIF_BCN_PRBRESP_PROMISC: This flag is set during scanning to indicate + * to the hardware that it should not filter beacons or probe responses + * by BSSID. Filtering them can greatly reduce the amount of processing + * 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_OTHER_BSS: pass frames destined to other BSSes + */ +enum ieee80211_filter_flags { + FIF_PROMISC_IN_BSS = 1<<0, + FIF_ALLMULTI = 1<<1, + FIF_FCSFAIL = 1<<2, + FIF_PLCPFAIL = 1<<3, + FIF_BCN_PRBRESP_PROMISC = 1<<4, + FIF_CONTROL = 1<<5, + FIF_OTHER_BSS = 1<<6, +}; + +/** + * enum ieee80211_erp_change_flags - erp change flags + * + * These flags are used with the erp_ie_changed() callback in + * &struct ieee80211_ops to indicate which parameter(s) changed. + * @IEEE80211_ERP_CHANGE_PROTECTION: protection changed + * @IEEE80211_ERP_CHANGE_PREAMBLE: barker preamble mode changed + */ +enum ieee80211_erp_change_flags { + IEEE80211_ERP_CHANGE_PROTECTION = 1<<0, + IEEE80211_ERP_CHANGE_PREAMBLE = 1<<1, +}; + + +/** + * struct ieee80211_ops - callbacks from mac80211 to the driver + * + * This structure contains various callbacks that the driver may + * handle or, in some cases, must handle, for example to configure + * the hardware to a new channel or to transmit a frame. + * + * @tx: Handler that 802.11 module calls for each transmitted frame. + * skb contains the buffer starting from the IEEE 802.11 header. + * The low-level driver should send the frame out based on + * configuration in the TX control data. Must be implemented and + * atomic. + * + * @start: Called before the first netdevice attached to the hardware + * is enabled. This should turn on the hardware and must turn on + * frame reception (for possibly enabled monitor interfaces.) + * Returns negative error codes, these may be seen in userspace, + * or zero. + * When the device is started it should not have a MAC address + * to avoid acknowledging frames before a non-monitor device + * is added. + * Must be implemented. + * + * @stop: Called after last netdevice attached to the hardware + * 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. + * Must be implemented. + * + * @add_interface: Called when a netdevice attached to the hardware is + * enabled. Because it is not called for monitor mode devices, @open + * and @stop must be implemented. + * The driver should perform any initialization it needs before + * the device can be enabled. The initial configuration for the + * interface is given in the conf parameter. + * The callback may refuse to add an interface by returning a + * negative error code (which will be seen in userspace.) + * Must be implemented. + * + * @remove_interface: Notifies a driver that an interface is going down. + * The @stop callback is called after this if it is the last interface + * and no monitor interfaces are present. + * When all interfaces are removed, the MAC address in the hardware + * must be cleared so the device no longer acknowledges packets, + * the mac_addr member of the conf structure is, however, set to the + * MAC address of the device going away. + * Hence, this callback must be implemented. + * + * @config: Handler for configuration requests. IEEE 802.11 code calls this + * function to change hardware configuration, e.g., channel. + * + * @config_interface: Handler for configuration requests related to interfaces + * (e.g. BSSID changes.) + * + * @configure_filter: Configure the device's RX filter. + * See the section "Frame filtering" for more information. + * This callback must be implemented and atomic. + * + * @set_tim: Set TIM bit. If the hardware/firmware takes care of beacon + * generation (that is, %IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is set) + * mac80211 calls this function when a TIM bit must be set or cleared + * for a given AID. Must be atomic. + * + * @set_key: See the section "Hardware crypto acceleration" + * This callback can sleep, and is only called between add_interface + * and remove_interface calls, i.e. while the interface with the + * given local_address is enabled. + * + * @set_ieee8021x: Enable/disable IEEE 802.1X. This item requests wlan card + * to pass unencrypted EAPOL-Key frames even when encryption is + * configured. If the wlan card does not require such a configuration, + * this function pointer can be set to NULL. + * + * @set_port_auth: Set port authorization state (IEEE 802.1X PAE) to be + * authorized (@authorized=1) or unauthorized (=0). This function can be + * used if the wlan hardware or low-level driver implements PAE. + * mac80211 will filter frames based on authorization state in any case, + * so this function pointer can be NULL if low-level driver does not + * require event notification about port state changes. + * + * @hw_scan: Ask the hardware to service the scan request, no need to start + * the scan state machine in stack. + * + * @get_stats: return low-level statistics + * + * @set_privacy_invoked: For devices that generate their own beacons and probe + * response or association responses this updates the state of privacy_invoked + * returns 0 for success or an error number. + * + * @get_sequence_counter: For devices that have internal sequence counters this + * callback allows mac80211 to access the current value of a counter. + * This callback seems not well-defined, tell us if you need it. + * + * @set_rts_threshold: Configuration of RTS threshold (if device needs it) + * + * @set_frag_threshold: Configuration of fragmentation threshold. Assign this if + * the device does fragmentation by itself; if this method is assigned then + * the stack will not do fragmentation. + * + * @set_retry_limit: Configuration of retry limits (if device needs it) + * + * @sta_table_notification: Number of STAs in STA table notification. Must + * be atomic. + * + * @erp_ie_changed: Handle ERP IE change notifications. Must be atomic. + * + * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), + * bursting) for a hardware TX queue. The @queue parameter uses the + * %IEEE80211_TX_QUEUE_* constants. Must be atomic. + * + * @get_tx_stats: Get statistics of the current TX queue status. This is used + * to get number of currently queued packets (queue length), maximum queue + * size (limit), and total number of packets sent using each TX queue + * (count). This information is used for WMM to find out which TX + * queues have room for more packets and by hostapd to provide + * statistics about the current queueing state to external programs. + * + * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, + * this is only used for IBSS mode debugging and, as such, is not a + * required function. Must be atomic. + * + * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize + * with other STAs in the IBSS. This is only used in IBSS mode. This + * function is optional if the firmware/hardware takes full care of + * TSF synchronization. + * + * @beacon_update: Setup beacon data for IBSS beacons. Unlike access point, + * IBSS uses a fixed beacon frame which is configured using this + * function. This handler is required only for IBSS mode. + * + * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. + * This is needed only for IBSS mode and the result of this function is + * used to determine whether to reply to Probe Requests. + */ struct ieee80211_ops { - /* Handler that 802.11 module calls for each transmitted frame. - * skb contains the buffer starting from the IEEE 802.11 header. - * The low-level driver should send the frame out based on - * configuration in the TX control data. - * Must be atomic. */ int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control); - - /* - * Called before the first netdevice attached to the hardware - * is enabled. This should turn on the hardware and must turn on - * frame reception (for possibly enabled monitor interfaces.) - * Returns negative error codes, these may be seen in userspace, - * or zero. - * When the device is started it should not have a MAC address - * to avoid acknowledging frames before a non-monitor device - * is added. - * - * Must be implemented. - */ int (*start)(struct ieee80211_hw *hw); - - /* - * Called after last netdevice attached to the hardware - * 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. - * - * Must be implemented. - */ void (*stop)(struct ieee80211_hw *hw); - - /* - * Called when a netdevice attached to the hardware is enabled. - * Because it is not called for monitor mode devices, open() - * and stop() must be implemented. - * The driver should perform any initialization it needs before - * the device can be enabled. The initial configuration for the - * interface is given in the conf parameter. - * - * Must be implemented. - */ int (*add_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); - - /* - * Notifies a driver that an interface is going down. The stop() handler - * is called after this if it is the last interface and no monitor - * interfaces are present. - * When all interfaces are removed, the MAC address in the hardware - * must be cleared so the device no longer acknowledges packets, - * the mac_addr member of the conf structure is, however, set to the - * MAC address of the device going away. - * - * Hence, this callback must be implemented. - */ void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); - - /* Handler for configuration requests. IEEE 802.11 code calls this - * function to change hardware configuration, e.g., channel. */ int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf); - - /* Handler for configuration requests related to interfaces (e.g. - * BSSID). */ int (*config_interface)(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf); - - /* - * Configure the device's RX filter. - * - * The multicast address filter must be changed if the hardware flags - * indicate that one is present. - * - * All unsupported flags in 'total_flags' must be cleared, - * clear all bits except those you honoured. - * - * The callback must be implemented and must be atomic. - */ void (*configure_filter)(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list); - - /* Set TIM bit handler. If the hardware/firmware takes care of beacon - * generation, IEEE 802.11 code uses this function to tell the - * low-level to set (or clear if set==0) TIM bit for the given aid. If - * host system is used to generate beacons, this handler is not used - * and low-level driver should set it to NULL. - * Must be atomic. */ int (*set_tim)(struct ieee80211_hw *hw, int aid, int set); - - /* - * Set encryption key. - * - * This is called to enable hardware acceleration of encryption and - * decryption. The address will be the broadcast address for default - * keys, the other station's hardware address for individual keys or - * the zero address for keys that will be used only for transmission. - * - * The local_address parameter will always be set to our own address, - * this is only relevant if you support multiple local addresses. - * - * When transmitting, the TX control data will use the hw_key_idx - * selected by the low-level driver. - * - * Return 0 if the key is now in use, -EOPNOTSUPP or -ENOSPC if it - * couldn't be added; if you return 0 then hw_key_idx must be assigned - * to the hardware key index, you are free to use the full u8 range. - * - * When the cmd is DISABLE_KEY then it must succeed. - * - * Note that it is permissible to not decrypt a frame even if a key - * for it has been uploaded to hardware, the stack will not make any - * decision based on whether a key has been uploaded or not but rather - * based on the receive flags. - * - * This callback can sleep, and is only called between add_interface - * and remove_interface calls, i.e. while the interface with the - * given local_address is enabled. - * - * The ieee80211_key_conf structure pointed to by the key parameter - * is guaranteed to be valid until another call to set_key removes - * it, but it can only be used as a cookie to differentiate keys. - */ int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, const u8 *local_address, const u8 *address, struct ieee80211_key_conf *key); - - /* Enable/disable IEEE 802.1X. This item requests wlan card to pass - * unencrypted EAPOL-Key frames even when encryption is configured. - * If the wlan card does not require such a configuration, this - * function pointer can be set to NULL. */ int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x); - - /* Set port authorization state (IEEE 802.1X PAE) to be authorized - * (authorized=1) or unauthorized (authorized=0). This function can be - * used if the wlan hardware or low-level driver implements PAE. - * 80211.o module will anyway filter frames based on authorization - * state, so this function pointer can be NULL if low-level driver does - * not require event notification about port state changes. - * Currently unused. */ int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr, int authorized); - - /* Ask the hardware to service the scan request, no need to start - * the scan state machine in stack. */ int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); - - /* return low-level statistics */ int (*get_stats)(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); - - /* For devices that generate their own beacons and probe response - * or association responses this updates the state of privacy_invoked - * returns 0 for success or an error number */ int (*set_privacy_invoked)(struct ieee80211_hw *hw, int privacy_invoked); - - /* For devices that have internal sequence counters, allow 802.11 - * code to access the current value of a counter */ int (*get_sequence_counter)(struct ieee80211_hw *hw, u8* addr, u8 keyidx, u8 txrx, u32* iv32, u16* iv16); - - /* Configuration of RTS threshold (if device needs it) */ int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); - - /* Configuration of fragmentation threshold. - * Assign this if the device does fragmentation by itself, - * if this method is assigned then the stack will not do - * fragmentation. */ int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); - - /* Configuration of retry limits (if device needs it) */ int (*set_retry_limit)(struct ieee80211_hw *hw, u32 short_retry, u32 long_retr); - - /* Number of STAs in STA table notification (NULL = disabled). - * Must be atomic. */ void (*sta_table_notification)(struct ieee80211_hw *hw, int num_sta); - - /* Handle ERP IE change notifications. Must be atomic. */ void (*erp_ie_changed)(struct ieee80211_hw *hw, u8 changes, int cts_protection, int preamble); - - /* Flags for the erp_ie_changed changes parameter */ -#define IEEE80211_ERP_CHANGE_PROTECTION (1<<0) /* protection flag changed */ -#define IEEE80211_ERP_CHANGE_PREAMBLE (1<<1) /* barker preamble mode changed */ - - /* Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), - * bursting) for a hardware TX queue. - * queue = IEEE80211_TX_QUEUE_*. - * Must be atomic. */ int (*conf_tx)(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params); - - /* Get statistics of the current TX queue status. This is used to get - * number of currently queued packets (queue length), maximum queue - * size (limit), and total number of packets sent using each TX queue - * (count). - * Currently unused. */ int (*get_tx_stats)(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); - - /* Get the current TSF timer value from firmware/hardware. Currently, - * this is only used for IBSS mode debugging and, as such, is not a - * required function. - * Must be atomic. */ u64 (*get_tsf)(struct ieee80211_hw *hw); - - /* Reset the TSF timer and allow firmware/hardware to synchronize with - * other STAs in the IBSS. This is only used in IBSS mode. This - * function is optional if the firmware/hardware takes full care of - * TSF synchronization. */ void (*reset_tsf)(struct ieee80211_hw *hw); - - /* Setup beacon data for IBSS beacons. Unlike access point (Master), - * IBSS uses a fixed beacon frame which is configured using this - * function. This handler is required only for IBSS mode. */ int (*beacon_update)(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control); - - /* Determine whether the last IBSS beacon was sent by us. This is - * needed only for IBSS mode and the result of this function is used to - * determine whether to reply to Probe Requests. */ int (*tx_last_beacon)(struct ieee80211_hw *hw); }; -/* Allocate a new hardware device. This must be called once for each - * hardware device. The returned pointer must be used to refer to this - * device when calling other functions. 802.11 code allocates a private data - * area for the low-level driver. The size of this area is given as - * priv_data_len. +/** + * ieee80211_alloc_hw - Allocate a new hardware device + * + * This must be called once for each hardware device. The returned pointer + * must be used to refer to this device when calling other functions. + * mac80211 allocates a private data area for the driver pointed to by + * @priv in &struct ieee80211_hw, the size of this area is given as + * @priv_data_len. + * + * @priv_data_len: length of private data + * @ops: callbacks for this device */ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops); -/* Register hardware device to the IEEE 802.11 code and kernel. Low-level - * drivers must call this function before using any other IEEE 802.11 - * function except ieee80211_register_hwmode. */ +/** + * ieee80211_register_hw - Register hardware device + * + * You must call this function before any other functions + * except ieee80211_register_hwmode. + * + * @hw: the device to register as returned by ieee80211_alloc_hw() + */ int ieee80211_register_hw(struct ieee80211_hw *hw); -/* driver can use this and ieee80211_get_rx_led_name to get the - * name of the registered LEDs after ieee80211_register_hw - * was called. - * This is useful to set the default trigger on the LED class - * device that your driver should export for each LED the device - * has, that way the default behaviour will be as expected but - * the user can still change it/turn off the LED etc. - */ #ifdef CONFIG_MAC80211_LEDS extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); #endif +/** + * ieee80211_get_tx_led_name - get name of TX LED + * + * mac80211 creates a transmit LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw) { #ifdef CONFIG_MAC80211_LEDS @@ -999,6 +1096,16 @@ static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw) #endif } +/** + * ieee80211_get_rx_led_name - get name of RX LED + * + * mac80211 creates a receive LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) { #ifdef CONFIG_MAC80211_LEDS @@ -1012,29 +1119,80 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) int ieee80211_register_hwmode(struct ieee80211_hw *hw, struct ieee80211_hw_mode *mode); -/* Unregister a hardware device. This function instructs 802.11 code to free - * allocated resources and unregister netdevices from the kernel. */ +/** + * ieee80211_unregister_hw - Unregister a hardware device + * + * This function instructs mac80211 to free allocated resources + * and unregister netdevices from the networking subsystem. + * + * @hw: the hardware to unregister + */ void ieee80211_unregister_hw(struct ieee80211_hw *hw); -/* Free everything that was allocated including private data of a driver. */ +/** + * ieee80211_free_hw - free hardware descriptor + * + * This function frees everything that was allocated, including the + * private data for the driver. You must call ieee80211_unregister_hw() + * before calling this function + * + * @hw: the hardware to free + */ void ieee80211_free_hw(struct ieee80211_hw *hw); -/* Receive frame callback function. The low-level driver uses this function to - * send received frames to the IEEE 802.11 code. Receive buffer (skb) must - * start with IEEE 802.11 header. */ +/* 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); + +/** + * ieee80211_rx - receive frame + * + * Use this function to hand received frames to mac80211. The receive + * buffer in @skb must start with an IEEE 802.11 header or a radiotap + * header if %RX_FLAG_RADIOTAP is set in the @status flags. + * + * This function may not be called in IRQ context. + * + * @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) +{ + __ieee80211_rx(hw, skb, status); +} + +/** + * ieee80211_rx_irqsafe - receive frame + * + * Like ieee80211_rx() but can be called in IRQ context + * (internally defers to a workqueue.) + * + * @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); -/* Transmit status callback function. The low-level driver must call this - * function to report transmit status for all the TX frames that had - * req_tx_status set in the transmit control fields. In addition, this should - * be called at least for all unicast frames to provide information for TX rate - * control algorithm. In order to maintain all statistics, this function is - * recommended to be called after each frame, including multicast/broadcast, is - * sent. */ +/** + * ieee80211_tx_status - transmit status callback + * + * Call this function for all transmitted frames after they have been + * transmitted. It is permissible to not call this function for + * multicast frames but this can affect statistics. + * + * @hw: the hardware the frame was transmitted by + * @skb: the frame that was transmitted, owned by mac80211 after this call + * @status: status information for 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_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status); @@ -1166,14 +1324,26 @@ struct sk_buff * ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, struct ieee80211_tx_control *control); -/* Given an sk_buff with a raw 802.11 header at the data pointer this function +/** + * ieee80211_get_hdrlen_from_skb - get header length from data + * + * Given an skb with a raw 802.11 header at the data pointer this function * returns the 802.11 header length in bytes (not including encryption * headers). If the data in the sk_buff is too short to contain a valid 802.11 * header the function returns 0. + * + * @skb: the frame */ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); -/* Like ieee80211_get_hdrlen_from_skb() but takes a FC in CPU order. */ +/** + * ieee80211_get_hdrlen - get header length from frame control + * + * This function returns the 802.11 header length in bytes (not including + * encryption headers.) + * + * @fc: the frame control field (in CPU endianness) + */ int ieee80211_get_hdrlen(u16 fc); /** @@ -1218,10 +1388,28 @@ void ieee80211_stop_queues(struct ieee80211_hw *hw); */ void ieee80211_wake_queues(struct ieee80211_hw *hw); -/* called by driver to notify scan status completed */ +/** + * ieee80211_scan_completed - completed hardware scan + * + * When hardware scan offload is used (i.e. the hw_scan() callback is + * assigned) this function needs to be called by the driver to notify + * mac80211 that the scan finished. + * + * @hw: the hardware that finished the scan + */ void ieee80211_scan_completed(struct ieee80211_hw *hw); -/* return a pointer to the source address (SA) */ +/** + * ieee80211_get_SA - get pointer to SA + * + * Given an 802.11 frame, this function returns the offset + * to the source address (SA). It does not verify that the + * header is long enough to contain the address, and the + * header must be long enough to contain the frame control + * field. + * + * @hdr: the frame + */ static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) { u8 *raw = (u8 *) hdr; @@ -1236,7 +1424,17 @@ static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) return hdr->addr2; } -/* return a pointer to the destination address (DA) */ +/** + * ieee80211_get_DA - get pointer to DA + * + * Given an 802.11 frame, this function returns the offset + * to the destination address (DA). It does not verify that + * the header is long enough to contain the address, and the + * header must be long enough to contain the frame control + * field. + * + * @hdr: the frame + */ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) { u8 *raw = (u8 *) hdr; @@ -1247,6 +1445,14 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) return hdr->addr1; } +/** + * ieee80211_get_morefrag - determine whether the MOREFRAGS bit is set + * + * This function determines whether the "more fragments" bit is set + * in the frame. + * + * @hdr: the frame + */ static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr) { return (le16_to_cpu(hdr->frame_control) & From f97df02e23269c7650869f6192e809f8ac1a4b39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:20 -0400 Subject: [PATCH 1550/2804] [PATCH] wireless networking: move frame inline functions to generic header These inlines are generally useful, not just with mac80211. Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 61 +++++++++++++++++++++++++++++++++++++++ include/net/mac80211.h | 60 -------------------------------------- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 272f8c8c90da..30621c27159f 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -16,6 +16,7 @@ #define IEEE80211_H #include +#include #define FCS_LEN 4 @@ -350,4 +351,64 @@ enum ieee80211_eid { #define WLAN_MAX_KEY_LEN 32 +/** + * ieee80211_get_SA - get pointer to SA + * + * Given an 802.11 frame, this function returns the offset + * to the source address (SA). It does not verify that the + * header is long enough to contain the address, and the + * header must be long enough to contain the frame control + * field. + * + * @hdr: the frame + */ +static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) +{ + u8 *raw = (u8 *) hdr; + u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */ + + switch (tofrom) { + case 2: + return hdr->addr3; + case 3: + return hdr->addr4; + } + return hdr->addr2; +} + +/** + * ieee80211_get_DA - get pointer to DA + * + * Given an 802.11 frame, this function returns the offset + * to the destination address (DA). It does not verify that + * the header is long enough to contain the address, and the + * header must be long enough to contain the frame control + * field. + * + * @hdr: the frame + */ +static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) +{ + u8 *raw = (u8 *) hdr; + u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */ + + if (to_ds) + return hdr->addr3; + return hdr->addr1; +} + +/** + * ieee80211_get_morefrag - determine whether the MOREFRAGS bit is set + * + * This function determines whether the "more fragments" bit is set + * in the frame. + * + * @hdr: the frame + */ +static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr) +{ + return (le16_to_cpu(hdr->frame_control) & + IEEE80211_FCTL_MOREFRAGS) != 0; +} + #endif /* IEEE80211_H */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d2cf734402e3..fcca9c39b9e7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1399,64 +1399,4 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw); */ void ieee80211_scan_completed(struct ieee80211_hw *hw); -/** - * ieee80211_get_SA - get pointer to SA - * - * Given an 802.11 frame, this function returns the offset - * to the source address (SA). It does not verify that the - * header is long enough to contain the address, and the - * header must be long enough to contain the frame control - * field. - * - * @hdr: the frame - */ -static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) -{ - u8 *raw = (u8 *) hdr; - u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */ - - switch (tofrom) { - case 2: - return hdr->addr3; - case 3: - return hdr->addr4; - } - return hdr->addr2; -} - -/** - * ieee80211_get_DA - get pointer to DA - * - * Given an 802.11 frame, this function returns the offset - * to the destination address (DA). It does not verify that - * the header is long enough to contain the address, and the - * header must be long enough to contain the frame control - * field. - * - * @hdr: the frame - */ -static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) -{ - u8 *raw = (u8 *) hdr; - u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */ - - if (to_ds) - return hdr->addr3; - return hdr->addr1; -} - -/** - * ieee80211_get_morefrag - determine whether the MOREFRAGS bit is set - * - * This function determines whether the "more fragments" bit is set - * in the frame. - * - * @hdr: the frame - */ -static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr) -{ - return (le16_to_cpu(hdr->frame_control) & - IEEE80211_FCTL_MOREFRAGS) != 0; -} - #endif /* MAC80211_H */ From ea49c359f36d5b40bf033c45a08332cb73777aa2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:21 -0400 Subject: [PATCH 1551/2804] [PATCH] mac80211: remove crypto algorithm typedef The typedef is not required, we can just use "enum ieee80211_key_alg" instead of "ieee80211_key_alg" Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- drivers/net/wireless/iwlwifi/iwlwifi.h | 2 +- include/net/mac80211.h | 12 ++++++------ net/mac80211/ieee80211_key.h | 2 +- net/mac80211/key.c | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8acda640df25..0700076e55b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7293,7 +7293,7 @@ out_unlock: return rc; } -static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, +static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 7b9227c562b7..7bc25f74e3ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7690,7 +7690,7 @@ out_unlock: return rc; } -static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, +static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h index 00c79e200c68..e0b97c341215 100644 --- a/drivers/net/wireless/iwlwifi/iwlwifi.h +++ b/drivers/net/wireless/iwlwifi/iwlwifi.h @@ -412,7 +412,7 @@ struct iwl_tid_data { }; struct iwl_hw_key { - ieee80211_key_alg alg; + enum ieee80211_key_alg alg; int keylen; u8 key[32]; }; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fcca9c39b9e7..8fb975f0bed4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -551,12 +551,12 @@ struct ieee80211_if_conf { * @ALG_TKIP: TKIP * @ALG_CCMP: CCMP (AES) */ -typedef enum ieee80211_key_alg { +enum ieee80211_key_alg { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, -} ieee80211_key_alg; +}; /** @@ -596,7 +596,7 @@ enum ieee80211_key_flags { * @key: key material */ struct ieee80211_key_conf { - ieee80211_key_alg alg; + enum ieee80211_key_alg alg; u8 hw_key_idx; u8 flags; s8 keyidx; @@ -616,9 +616,9 @@ struct ieee80211_key_conf { * @SET_KEY: a key is set * @DISABLE_KEY: a key must be disabled */ -typedef enum set_key_cmd { +enum set_key_cmd { SET_KEY, DISABLE_KEY, -} set_key_cmd; +}; /** @@ -1014,7 +1014,7 @@ struct ieee80211_ops { unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list); int (*set_tim)(struct ieee80211_hw *hw, int aid, int set); - int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, + int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_address, const u8 *address, struct ieee80211_key_conf *key); int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x); diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index ae49418f18b4..fc770e98d47b 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -114,7 +114,7 @@ struct ieee80211_key { struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, - ieee80211_key_alg alg, + enum ieee80211_key_alg alg, int idx, size_t key_len, const u8 *key_data); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index c10e53afbb4f..f13d46b2c13c 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -113,7 +113,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, - ieee80211_key_alg alg, + enum ieee80211_key_alg alg, int idx, size_t key_len, const u8 *key_data) From 79010420cc3f78eab911598bfdd29c4b06a83e1f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:21 -0400 Subject: [PATCH 1552/2804] [PATCH] mac80211: fix virtual interface locking Florian Lohoff noticed a bug in mac80211: when bringing the master interface down while other virtual interfaces are up we call dev_close() under a spinlock which is not allowed. This patch removes the sub_if_lock used by mac80211 in favour of using an RCU list. All list manipulations are already done under rtnl so are well protected against each other, and the read-side locks we took in the RX and TX code are already in RCU read-side critical sections. Signed-off-by: Johannes Berg Cc: Florian Lohoff Cc: Herbert Xu Cc: Michal Piotrowski Cc: Satyam Sharma Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 56 +++++++++++++++------------------- net/mac80211/ieee80211_i.h | 5 ++- net/mac80211/ieee80211_iface.c | 31 +++++++++---------- net/mac80211/ieee80211_sta.c | 12 ++++---- net/mac80211/rx.c | 9 +++--- net/mac80211/tx.c | 10 ++++-- 6 files changed, 58 insertions(+), 65 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 4e345f82f044..ccf84634f156 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -93,14 +93,13 @@ static int ieee80211_master_open(struct net_device *dev) struct ieee80211_sub_if_data *sdata; int res = -EOPNOTSUPP; - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->dev != dev && netif_running(sdata->dev)) { res = 0; break; } } - read_unlock(&local->sub_if_lock); return res; } @@ -109,11 +108,10 @@ static int ieee80211_master_stop(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(sdata, &local->interfaces, list) if (sdata->dev != dev && netif_running(sdata->dev)) dev_close(sdata->dev); - read_unlock(&local->sub_if_lock); return 0; } @@ -315,8 +313,8 @@ static int ieee80211_open(struct net_device *dev) sdata = IEEE80211_DEV_TO_SUB_IF(dev); - read_lock(&local->sub_if_lock); - list_for_each_entry(nsdata, &local->sub_if_list, list) { + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(nsdata, &local->interfaces, list) { struct net_device *ndev = nsdata->dev; if (ndev != dev && ndev != local->mdev && netif_running(ndev) && @@ -325,10 +323,8 @@ static int ieee80211_open(struct net_device *dev) * check whether it may have the same address */ if (!identical_mac_addr_allowed(sdata->type, - nsdata->type)) { - read_unlock(&local->sub_if_lock); + nsdata->type)) return -ENOTUNIQ; - } /* * can only add VLANs to enabled APs @@ -339,7 +335,6 @@ static int ieee80211_open(struct net_device *dev) sdata->u.vlan.ap = nsdata; } } - read_unlock(&local->sub_if_lock); switch (sdata->type) { case IEEE80211_IF_TYPE_WDS: @@ -466,14 +461,13 @@ static int ieee80211_stop(struct net_device *dev) sdata->u.sta.state = IEEE80211_DISABLED; del_timer_sync(&sdata->u.sta.timer); /* - * Holding the sub_if_lock for writing here blocks - * out the receive path and makes sure it's not - * currently processing a packet that may get - * added to the queue. + * When we get here, the interface is marked down. + * Call synchronize_rcu() to wait for the RX path + * should it be using the interface and enqueuing + * frames at this very time on another CPU. */ - write_lock_bh(&local->sub_if_lock); + synchronize_rcu(); skb_queue_purge(&sdata->u.sta.skb_queue); - write_unlock_bh(&local->sub_if_lock); if (!local->ops->hw_scan && local->scan_dev == sdata->dev) { @@ -1033,9 +1027,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, rthdr->data_retries = status->retry_count; - read_lock(&local->sub_if_lock); + rcu_read_lock(); monitors = local->monitors; - list_for_each_entry(sdata, &local->sub_if_list, list) { + list_for_each_entry_rcu(sdata, &local->interfaces, list) { /* * Using the monitors counter is possibly racy, but * if the value is wrong we simply either clone the skb @@ -1051,7 +1045,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, continue; monitors--; if (monitors) - skb2 = skb_clone(skb, GFP_KERNEL); + skb2 = skb_clone(skb, GFP_ATOMIC); else skb2 = NULL; skb->dev = sdata->dev; @@ -1066,7 +1060,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, } } out: - read_unlock(&local->sub_if_lock); + rcu_read_unlock(); if (skb) dev_kfree_skb(skb); } @@ -1154,8 +1148,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_LIST_HEAD(&local->modes_list); - rwlock_init(&local->sub_if_lock); - INIT_LIST_HEAD(&local->sub_if_list); + INIT_LIST_HEAD(&local->interfaces); INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); ieee80211_rx_bss_list_init(mdev); @@ -1175,7 +1168,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, sdata->u.ap.force_unicast_rateidx = -1; sdata->u.ap.max_ratectrl_rateidx = -1; ieee80211_if_sdata_init(sdata); - list_add_tail(&sdata->list, &local->sub_if_list); + /* no RCU needed since we're still during init phase */ + list_add_tail(&sdata->list, &local->interfaces); tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); @@ -1334,7 +1328,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata, *tmp; - struct list_head tmp_list; int i; tasklet_kill(&local->tx_pending_tasklet); @@ -1348,11 +1341,12 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) if (local->apdev) ieee80211_if_del_mgmt(local); - write_lock_bh(&local->sub_if_lock); - list_replace_init(&local->sub_if_list, &tmp_list); - write_unlock_bh(&local->sub_if_lock); - - list_for_each_entry_safe(sdata, tmp, &tmp_list, list) + /* + * At this point, interface list manipulations are fine + * because the driver cannot be handing us frames any + * more and the tasklet is killed. + */ + list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) __ieee80211_if_del(local, sdata); rtnl_unlock(); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1a43f3e9b6bd..a5961f16f206 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -475,9 +475,8 @@ struct ieee80211_local { ieee80211_rx_handler *rx_handlers; ieee80211_tx_handler *tx_handlers; - rwlock_t sub_if_lock; /* Protects sub_if_list. Cannot be taken under - * sta_bss_lock or sta_lock. */ - struct list_head sub_if_list; + struct list_head interfaces; + int sta_scanning; int scan_channel_idx; enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 4590205fdf4b..2ba24ef319da 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -79,16 +79,15 @@ int ieee80211_if_add(struct net_device *dev, const char *name, ieee80211_debugfs_add_netdev(sdata); ieee80211_if_set_type(ndev, type); - write_lock_bh(&local->sub_if_lock); + /* we're under RTNL so all this is fine */ if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { - write_unlock_bh(&local->sub_if_lock); __ieee80211_if_del(local, sdata); return -ENODEV; } - list_add(&sdata->list, &local->sub_if_list); + list_add_tail_rcu(&sdata->list, &local->interfaces); + if (new_dev) *new_dev = ndev; - write_unlock_bh(&local->sub_if_lock); return 0; @@ -226,22 +225,22 @@ void ieee80211_if_reinit(struct net_device *dev) /* Remove all virtual interfaces that use this BSS * as their sdata->bss */ struct ieee80211_sub_if_data *tsdata, *n; - LIST_HEAD(tmp_list); - write_lock_bh(&local->sub_if_lock); - list_for_each_entry_safe(tsdata, n, &local->sub_if_list, list) { + list_for_each_entry_safe(tsdata, n, &local->interfaces, list) { if (tsdata != sdata && tsdata->bss == &sdata->u.ap) { printk(KERN_DEBUG "%s: removing virtual " "interface %s because its BSS interface" " is being removed\n", sdata->dev->name, tsdata->dev->name); - list_move_tail(&tsdata->list, &tmp_list); + list_del_rcu(&tsdata->list); + /* + * We have lots of time and can afford + * to sync for each interface + */ + synchronize_rcu(); + __ieee80211_if_del(local, tsdata); } } - write_unlock_bh(&local->sub_if_lock); - - list_for_each_entry_safe(tsdata, n, &tmp_list, list) - __ieee80211_if_del(local, tsdata); kfree(sdata->u.ap.beacon_head); kfree(sdata->u.ap.beacon_tail); @@ -318,18 +317,16 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id) ASSERT_RTNL(); - write_lock_bh(&local->sub_if_lock); - list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) { + list_for_each_entry_safe(sdata, n, &local->interfaces, list) { if ((sdata->type == id || id == -1) && strcmp(name, sdata->dev->name) == 0 && sdata->dev != local->mdev) { - list_del(&sdata->list); - write_unlock_bh(&local->sub_if_lock); + list_del_rcu(&sdata->list); + synchronize_rcu(); __ieee80211_if_del(local, sdata); return 0; } } - write_unlock_bh(&local->sub_if_lock); return -ENODEV; } diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 17455c6a5229..651aaba1add4 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2676,8 +2676,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { /* No need to wake the master device. */ if (sdata->dev == local->mdev) @@ -2691,7 +2691,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) netif_wake_queue(sdata->dev); } - read_unlock(&local->sub_if_lock); + rcu_read_unlock(); sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_IBSS) { @@ -2828,8 +2828,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev, local->sta_scanning = 1; - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { /* Don't stop the master interface, otherwise we can't transmit * probes! */ @@ -2841,7 +2841,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev, (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) ieee80211_send_nullfunc(local, sdata, 1); } - read_unlock(&local->sub_if_lock); + rcu_read_unlock(); if (ssid) { local->scan_ssid_len = ssid_len; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2535d8d4ce90..cb44a9db0e19 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1383,8 +1383,9 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, } /* - * key references are protected using RCU and this requires that - * we are in a read-site RCU section during receive processing + * key references and virtual interfaces are protected using RCU + * and this requires that we are in a read-side RCU section during + * receive processing */ rcu_read_lock(); @@ -1439,8 +1440,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len); - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { + list_for_each_entry_rcu(sdata, &local->interfaces, list) { rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; if (!netif_running(sdata->dev)) @@ -1493,7 +1493,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, &rx, sta); } else dev_kfree_skb(skb); - read_unlock(&local->sub_if_lock); end: rcu_read_unlock(); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 38394c40f6ad..244c80d0c8fb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -295,8 +295,12 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) struct ieee80211_sub_if_data *sdata; struct sta_info *sta; - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { + /* + * virtual interfaces are protected by RCU + */ + rcu_read_lock(); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { struct ieee80211_if_ap *ap; if (sdata->dev == local->mdev || sdata->type != IEEE80211_IF_TYPE_AP) @@ -309,7 +313,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) } total += skb_queue_len(&ap->ps_bc_buf); } - read_unlock(&local->sub_if_lock); + rcu_read_unlock(); read_lock_bh(&local->sta_lock); list_for_each_entry(sta, &local->sta_list, list) { From 725d99d4660fcd9abe37d7b733c9412a58465d13 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:53:20 +0200 Subject: [PATCH 1553/2804] [PATCH] rt2x00: Correct error in calculating rssi for link tuner The call to rt2x00lib_precalculate_link_signal resets link.rx_success which is needed when calculating the average rssi for the link tuner. Change the call order so the link tuner runs first as it doesn't need the result of the precalculate. Signed-off-by: Adam Baker Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index bbccb8933876..4f66adc5b09c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -242,8 +242,6 @@ static void rt2x00lib_link_tuner(struct work_struct *work) rt2x00dev->low_level_stats.dot11FCSErrorCount += rt2x00dev->link.rx_failed; - rt2x00lib_precalculate_link_signal(&rt2x00dev->link); - /* * Only perform the link tuning when Link tuning * has been enabled (This could have been disabled from the EEPROM). @@ -251,6 +249,12 @@ static void rt2x00lib_link_tuner(struct work_struct *work) if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags)) rt2x00dev->ops->lib->link_tuner(rt2x00dev); + /* + * Precalculate a portion of the link signal which is + * in based on the tx/rx success/failure counters. + */ + rt2x00lib_precalculate_link_signal(&rt2x00dev->link); + /* * Increase tuner counter, and reschedule the next link tuner run. */ From 2484591049ad1b92f585c1ff1c1d63f41e149faa Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:53:43 +0200 Subject: [PATCH 1554/2804] [PATCH] rt2x00: Make *_beacon_update static Make rt61pci_beacon_update and rt73usb_beacon_update static, they are only used inside their own source file and then only for setting it as callback funtion for mac80211. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index dea7a8a4fa00..3edcd743dce5 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2477,7 +2477,7 @@ static void rt61pci_reset_tsf(struct ieee80211_hw *hw) rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0); } -int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, +static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index aac13aa4039c..b18cc934ff82 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1961,7 +1961,7 @@ static void rt73usb_reset_tsf(struct ieee80211_hw *hw) rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0); } -int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, +static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; From e9136550eb7d9409292a93e2d2265afa11bee234 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:54:20 +0200 Subject: [PATCH 1555/2804] [PATCH] rt2x00: Increase rt2x00usb_vendor_request timeout. By increasing the timeout for rt2x00usb_vendor_request, we should limit the number of loops required to send a signal to the device succefully. 500ms timeout is specified by the Ralink legacy drivers for rt2500usb. For rt73usb 1000ms is specified, but that includes the timeout for the firmware which is already specified in a different define. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.c | 10 ++++------ drivers/net/wireless/rt2x00/rt2x00usb.h | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 8d2081189025..66e47615f2a6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -42,7 +42,7 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, const u16 value, void *buffer, const u16 buffer_length, - u16 timeout) + const int timeout) { struct usb_device *usb_dev = interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); @@ -60,12 +60,10 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, return 0; /* - * Check for errors, - * -ETIMEDOUT: We need a bit more time to complete. + * Check for errors * -ENODEV: Device has disappeared, no point continuing. + * All other errors: Try again. */ - if (status == -ETIMEDOUT) - timeout *= 2; else if (status == -ENODEV) break; } @@ -81,7 +79,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request); int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, void *buffer, - const u16 buffer_length, u16 timeout) + const u16 buffer_length, const int timeout) { int status; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index d4113e5158f0..2681abe4d49e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -44,7 +44,7 @@ */ #define REGISTER_BUSY_COUNT 5 #define REGISTER_BUSY_DELAY 100 -#define REGISTER_TIMEOUT 20 +#define REGISTER_TIMEOUT 500 #define REGISTER_TIMEOUT_FIRMWARE 1000 /* @@ -95,7 +95,7 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, const u16 value, void *buffer, const u16 buffer_length, - u16 timeout); + const int timeout); /* * Used to read/write from/to the device. @@ -110,7 +110,7 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, void *buffer, - const u16 buffer_length, u16 timeout); + const u16 buffer_length, const int timeout); /* * Simple wrapper around rt2x00usb_vendor_request to write a single @@ -122,7 +122,7 @@ static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev const u8 request, const u16 offset, const u16 value, - int timeout) + const int timeout) { return rt2x00usb_vendor_request(rt2x00dev, request, USB_VENDOR_REQUEST_OUT, offset, From 12dadb9009723dd0512091643e6e403f9e1b25cb Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:54:44 +0200 Subject: [PATCH 1556/2804] [PATCH] rt2x00: Correctly identify rt2561turbo Apparently rt2561s actually has PCI ID 0x0301 and rt2561 actually has PCI ID 0x0302. Where rt2561s supports Turbo. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 046eecfb16c0..5f05c7ee0dfa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -159,8 +159,8 @@ struct rt2x00_chip { #define RT2460 0x0101 #define RT2560 0x0201 #define RT2570 0x1201 -#define RT2561 0x0301 -#define RT2561s 0x0302 +#define RT2561s 0x0301 /* Turbo */ +#define RT2561 0x0302 #define RT2661 0x0401 #define RT2571 0x1300 From 066cb637b1b562bebd09d237bfaaca6724f247e5 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:55:39 +0200 Subject: [PATCH 1557/2804] [PATCH] rt2x00: Reorganize rt2x00dev->flags The rt2x00dev->flags has become a chaos over time, this will reorganize the flags by renaming, deleting, adding and properly implement the flags. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 4 +- drivers/net/wireless/rt2x00/rt2500pci.c | 4 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 31 ++++++------ drivers/net/wireless/rt2x00/rt2x00config.c | 27 +++-------- drivers/net/wireless/rt2x00/rt2x00dev.c | 55 ++++++++++++++++------ drivers/net/wireless/rt2x00/rt2x00lib.h | 3 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 55 +++++++++++++++------- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 12 ++--- drivers/net/wireless/rt2x00/rt61pci.c | 4 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 11 files changed, 115 insertions(+), 84 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 03a94a33e6bd..faa47111a579 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1374,7 +1374,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); /* * Check if the BBP tuning should be enabled. @@ -1469,7 +1469,7 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the beacon ring */ - __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 892baa907a6b..929257d34ae4 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1545,7 +1545,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); /* * Check if the BBP tuning should be enabled. @@ -1801,7 +1801,7 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the beacon ring */ - __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index f4e6f6eb7fb5..7aacc7b5c1b2 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1573,7 +1573,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the beacon ring */ - __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 5f05c7ee0dfa..ea20f3adde5b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -493,24 +493,21 @@ struct rt2x00_dev { * of the device capabilities are stored. */ unsigned long flags; -#define DEVICE_ENABLED_RADIO 1 -#define DEVICE_ENABLED_RADIO_HW 2 +#define DEVICE_PRESENT 1 +#define DEVICE_REGISTERED_HW 2 #define DEVICE_INITIALIZED 3 -#define DEVICE_INITIALIZED_HW 4 -#define REQUIRE_FIRMWARE 5 -/* Hole: Add new Flag here */ -#define INTERFACE_RESUME 8 -#define INTERFACE_ENABLED 9 -/* Hole: Add new Flag here */ -#define REQUIRE_BEACON_RING 11 -#define DEVICE_SUPPORT_HW_BUTTON 12 -#define CONFIG_FRAME_TYPE 13 -#define CONFIG_RF_SEQUENCE 14 -/* Hole: Add new Flag here */ -#define CONFIG_EXTERNAL_LNA_A 16 -#define CONFIG_EXTERNAL_LNA_BG 17 -#define CONFIG_DOUBLE_ANTENNA 18 -#define CONFIG_DISABLE_LINK_TUNING 19 +#define DEVICE_STARTED 4 +#define DEVICE_ENABLED_RADIO 5 +#define DEVICE_ENABLED_RADIO_HW 6 +#define DRIVER_REQUIRE_FIRMWARE 7 +#define DRIVER_REQUIRE_BEACON_RING 8 +#define CONFIG_SUPPORT_HW_BUTTON 9 +#define CONFIG_FRAME_TYPE 10 +#define CONFIG_RF_SEQUENCE 11 +#define CONFIG_EXTERNAL_LNA_A 12 +#define CONFIG_EXTERNAL_LNA_BG 13 +#define CONFIG_DOUBLE_ANTENNA 14 +#define CONFIG_DISABLE_LINK_TUNING 15 /* * Chipset identification. diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f962ce497086..13b510687bcb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -48,33 +48,20 @@ void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) { - struct interface *intf = &rt2x00dev->interface; - - if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && - (!!test_bit(INTERFACE_ENABLED, &rt2x00dev->flags) == - !!is_interface_present(intf))) - return; - - rt2x00dev->ops->lib->config_type(rt2x00dev, type); - - /* - * Update the configuration flags. - */ - if (is_interface_present(intf)) - __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + if (type != INVALID_INTERFACE) + rt2x00dev->ops->lib->config_type(rt2x00dev, type); } -void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf) +void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, const int force_config) { int flags = 0; /* - * If we are in RESUME state we should - * force all configuration options. + * In some situations we want to force all configurations + * to be reloaded (When resuming for instance). */ - if (test_bit(INTERFACE_RESUME, &rt2x00dev->flags)) { + if (force_config) { flags = CONFIG_UPDATE_ALL; goto config; } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 4f66adc5b09c..f8f7e6e47f80 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -40,7 +40,7 @@ struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, const unsigned int queue) { - int beacon = test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); /* * Check if we are requesting a reqular TX ring, @@ -102,7 +102,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * And check if the hardware button has been disabled. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - (test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && + (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && !test_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags))) return 0; @@ -162,6 +162,9 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) { enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF; + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + /* * When we are disabling the RX, we should also stop the link tuner. */ @@ -721,7 +724,7 @@ exit: static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) { - if (test_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) ieee80211_unregister_hw(rt2x00dev->hw); if (likely(rt2x00dev->hwmodes)) { @@ -753,7 +756,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) return status; } - __set_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags); + __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags); return 0; } @@ -810,7 +813,7 @@ static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev) return -ENOMEM; } - if (!test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)) + if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)) return 0; /* @@ -919,7 +922,7 @@ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) * Atim: 1 (if required) */ rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues + - (2 * test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)); + (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)); ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL); if (!ring) { @@ -932,7 +935,7 @@ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->rx = ring; rt2x00dev->tx = &rt2x00dev->rx[1]; - if (test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)) + if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)) rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues]; /* @@ -1011,6 +1014,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00debug_register(rt2x00dev); + __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + return 0; exit: @@ -1022,6 +1027,8 @@ EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { + __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + /* * Disable radio. */ @@ -1068,6 +1075,13 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) int retval; NOTICE(rt2x00dev, "Going to sleep.\n"); + __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + + /* + * Only continue if mac80211 has open interfaces. + */ + if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + goto exit; /* * Disable radio and unitialize all items @@ -1077,6 +1091,7 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); +exit: /* * Set device mode to sleep for power management. */ @@ -1094,13 +1109,19 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) int retval; NOTICE(rt2x00dev, "Waking up.\n"); - __set_bit(INTERFACE_RESUME, &rt2x00dev->flags); + __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * Open the debugfs entry. */ rt2x00debug_register(rt2x00dev); + /* + * Only continue if mac80211 has open interfaces. + */ + if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + return 0; + /* * Reinitialize device and all active interfaces. */ @@ -1111,14 +1132,22 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Reconfigure device. */ - retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); - if (retval) - goto exit; + rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1); + if (!rt2x00dev->hw->conf.radio_enabled) + rt2x00lib_disable_radio(rt2x00dev); rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_bssid(rt2x00dev, intf->bssid); rt2x00lib_config_type(rt2x00dev, intf->type); + /* + * It is possible that during that mac80211 has attempted + * to send frames while we were suspending or resuming. + * In that case we have disabled the TX queue and should + * now enable it again + */ + ieee80211_start_queues(rt2x00dev->hw); + /* * When in Master or Ad-hoc mode, * restart Beacon transmitting by faking a beacondone event. @@ -1127,8 +1156,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) intf->type == IEEE80211_IF_TYPE_IBSS) rt2x00lib_beacondone(rt2x00dev); - __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags); - return 0; exit: @@ -1136,8 +1163,6 @@ exit: rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); - __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags); - return retval; } EXPORT_SYMBOL_GPL(rt2x00lib_resume); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index fcc2ffdd1a3c..6dd92eb2b223 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -52,7 +52,8 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); -void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf); +void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, const int force_config); /* * Firmware handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 17802f6d3d6d..e98d013a189f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -81,6 +81,17 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, struct data_ring *ring; u16 frame_control; + /* + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. + * Note that we can only stop the TX queues inside the TX path + * due to possible race conditions in mac80211. + */ + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) { + ieee80211_stop_queues(hw); + return 0; + } + /* * Determine which ring to put packet on. */ @@ -126,14 +137,15 @@ int rt2x00mac_start(struct ieee80211_hw *hw) struct rt2x00_dev *rt2x00dev = hw->priv; int status; - if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + test_bit(DEVICE_STARTED, &rt2x00dev->flags)) return 0; /* * If this is the first interface which is added, * we should load the firmware now. */ - if (test_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags)) { + if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) { status = rt2x00lib_load_firmware(rt2x00dev); if (status) return status; @@ -155,6 +167,8 @@ int rt2x00mac_start(struct ieee80211_hw *hw) return status; } + __set_bit(DEVICE_STARTED, &rt2x00dev->flags); + return 0; } EXPORT_SYMBOL_GPL(rt2x00mac_start); @@ -163,11 +177,16 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + return; + /* * Perhaps we can add something smarter here, * but for now just disabling the radio should do. */ rt2x00lib_disable_radio(rt2x00dev); + + __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); } EXPORT_SYMBOL_GPL(rt2x00mac_stop); @@ -178,9 +197,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct interface *intf = &rt2x00dev->interface; /* - * We only support 1 non-monitor interface. + * Don't allow interfaces to be added while + * either the device has disappeared or when + * another interface is already present. */ - if (is_interface_present(intf)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + is_interface_present(intf)) return -ENOBUFS; intf->id = conf->if_id; @@ -208,9 +230,12 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct interface *intf = &rt2x00dev->interface; /* - * We only support 1 non-monitor interface. + * Don't allow interfaces to be remove while + * either the device has disappeared or when + * no interface is present. */ - if (!is_interface_present(intf)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + !is_interface_present(intf)) return; intf->id = 0; @@ -233,12 +258,10 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) struct rt2x00_dev *rt2x00dev = hw->priv; /* - * If the device is not initialized we shouldn't accept - * any configuration changes. Mac80211 might be calling - * this function while we are trying to remove the device - * or perhaps suspending it. + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) return 0; /* @@ -252,7 +275,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) rt2x00lib_toggle_rx(rt2x00dev, 0); } - rt2x00lib_config(rt2x00dev, conf); + rt2x00lib_config(rt2x00dev, conf, 0); /* * Reenable RX only if the radio should be on. @@ -274,12 +297,10 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, int status; /* - * If the device is not initialized we shouldn't accept - * any configuration changes. Mac80211 might be calling - * this function while we are trying to remove the device - * or perhaps suspending it. + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) return 0; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index b54457c921c5..06af01451cde 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -45,9 +45,9 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) return 0; /* - * Only continue if we have an active interface. + * Only continue if there are enabled interfaces. */ - if (!is_interface_present(&rt2x00dev->interface)) + if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) return 0; if (state == RFKILL_STATE_ON) { @@ -76,7 +76,7 @@ int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { int retval; - if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return 0; retval = rfkill_register(rt2x00dev->rfkill); @@ -97,7 +97,7 @@ int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return; input_unregister_polled_device(rt2x00dev->poll_dev); @@ -108,7 +108,7 @@ int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) { struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); - if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return 0; rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); @@ -138,7 +138,7 @@ int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return; input_free_polled_device(rt2x00dev->poll_dev); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3edcd743dce5..4c5e317a3ad7 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2105,7 +2105,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); /* * Read frequency offset and RF programming sequence. @@ -2360,7 +2360,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires firmware */ - __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index b18cc934ff82..ffed3ec5fb99 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1827,7 +1827,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires firmware */ - __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); /* * Set the rssi offset. From 643b252123fab1a524449be3b79937f17e06a5ac Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:13:51 +0200 Subject: [PATCH 1558/2804] rt2x00: Add rt2x00dev->flags to debugfs Loosely based on the patch by Matthijs Kooijman, this will add the dev_flags entry into debugfs which will display rt2x00dev->flags. This will allow easier debugging of flag handling. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 37 +++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 4d2aaecd9dfe..9275d6f9517e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -57,6 +57,7 @@ struct rt2x00debug_intf { * - driver folder * - driver file * - chipset file + * - device flags file * - register offset/value files * - eeprom offset/value files * - bbp offset/value files @@ -65,6 +66,7 @@ struct rt2x00debug_intf { struct dentry *driver_folder; struct dentry *driver_entry; struct dentry *chipset_entry; + struct dentry *dev_flags; struct dentry *csr_off_entry; struct dentry *csr_val_entry; struct dentry *eeprom_off_entry; @@ -193,6 +195,34 @@ RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16); RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8); RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32); +static ssize_t rt2x00debug_read_dev_flags(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) +{ + struct rt2x00debug_intf *intf = file->private_data; + char line[16]; + size_t size; + + if (*offset) + return 0; + + size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags); + + if (copy_to_user(buf, line, size)) + return -EFAULT; + + *offset += size; + return size; +} + +static const struct file_operations rt2x00debug_fop_dev_flags = { + .owner = THIS_MODULE, + .read = rt2x00debug_read_dev_flags, + .open = rt2x00debug_file_open, + .release = rt2x00debug_file_release, +}; + static struct dentry *rt2x00debug_create_file_driver(const char *name, struct rt2x00debug_intf *intf, @@ -270,6 +300,12 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->chipset_entry)) goto exit; + intf->dev_flags = debugfs_create_file("dev_flags", S_IRUGO, + intf->driver_folder, intf, + &rt2x00debug_fop_dev_flags); + if (IS_ERR(intf->dev_flags)) + goto exit; + #define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \ ({ \ (__intf)->__name##_off_entry = \ @@ -320,6 +356,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) debugfs_remove(intf->eeprom_off_entry); debugfs_remove(intf->csr_val_entry); debugfs_remove(intf->csr_off_entry); + debugfs_remove(intf->dev_flags); debugfs_remove(intf->chipset_entry); debugfs_remove(intf->driver_entry); debugfs_remove(intf->driver_folder); From 3e30968e55e43ef08ee08c71258711a79c550f25 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:56:36 +0200 Subject: [PATCH 1559/2804] [PATCH] rt2x00: make rt2x00lib_stop_link_tuner() reentrant with link_tuner work Calling cancel_delayed_work_sync() unconditionally won't hurt and it will avoid race conditions when another CPU is already executing link_tuner work. Signed-off-by: Modestas Vainius Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f8f7e6e47f80..e8c91fb71a52 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -80,8 +80,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev) { - if (delayed_work_pending(&rt2x00dev->link.work)) - cancel_rearming_delayed_work(&rt2x00dev->link.work); + cancel_delayed_work_sync(&rt2x00dev->link.work); } void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) From 25ab002f94c73d9f214130fe0e0a8065e7b55841 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:57:04 +0200 Subject: [PATCH 1560/2804] [PATCH] rt2x00: Stop link tuning when radio is down As pointed out by Modestas Vainius the link tuner could continue working while the radio is already down. This because at the start of disable_radio the ENABLED_RADIO flag is cleared and causes the toggle_rx to skip the stop_link_tuner() call. This will add a check to the start of the link tuner which will automatically stop the link tuner when the radio is disabled. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e8c91fb71a52..92b725263578 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -236,6 +236,13 @@ static void rt2x00lib_link_tuner(struct work_struct *work) struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, link.work.work); + /* + * When the radio is shutting down we should + * immediately cease all link tuning. + */ + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + /* * Update statistics. */ From dcf5475bc8458798794af9afafdb3ef33ab67fd9 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:57:25 +0200 Subject: [PATCH 1561/2804] [PATCH] rt2x00: Fix obvious typo in comment Signed-off-by: Modestas Vainius Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 929257d34ae4..842da900d7c1 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -244,7 +244,7 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); return rt2x00_get_field32(reg, GPIOCSR_BIT0); } -#endif /* CONFIG_RT2400PCI_RFKILL */ +#endif /* CONFIG_RT2500PCI_RFKILL */ /* * Configuration handlers. diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 4c5e317a3ad7..6aa517645b6a 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -269,7 +269,7 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); return rt2x00_get_field32(reg, MAC_CSR13_BIT5);; } -#endif /* CONFIG_RT2400PCI_RFKILL */ +#endif /* CONFIG_RT61PCI_RFKILL */ /* * Configuration handlers. From fdd0abc8175dc43a14fe414a09fd7e6a162757bd Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:57:49 +0200 Subject: [PATCH 1562/2804] [PATCH] rt2x00: Fix panic on rmmod with rfkill enabled When ieee80211_hw.config indicates that the radio is enabled and is configuring options that require the link tuner to be restarted the link tuner will cause a kernel panic when rfkill has indicated the radio was in fact disabled. Signed-off-by: Modestas Vainius Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 92b725263578..0216096c88cd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -85,6 +85,9 @@ static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev) void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) { + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + rt2x00lib_stop_link_tuner(rt2x00dev); rt2x00lib_start_link_tuner(rt2x00dev); } From 3a1532f2f87175285b9459dcce58e467feec6b78 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:58:08 +0200 Subject: [PATCH 1563/2804] [PATCH] rt2x00: Release rt2x00 2.0.9 Version bump Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ea20f3adde5b..511c11c4edda 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -42,7 +42,7 @@ * Module information. * DRV_NAME should be set within the individual module source files. */ -#define DRV_VERSION "2.0.8" +#define DRV_VERSION "2.0.9" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* From 2e08ac7e27c1e54ebf0f82abc03285663efe7d89 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH 1564/2804] [PATCH] adm8211: kill interrupt loop Looping in the interrupt handler is unnecessary. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 74 ++++++++++++++++------------------ 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 49a6b9eda4ea..0893d0d4a5eb 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -458,51 +458,45 @@ do { \ struct ieee80211_hw *dev = dev_id; struct adm8211_priv *priv = dev->priv; - unsigned int count = 0; - u32 stsr; + u32 stsr = ADM8211_CSR_READ(STSR); + ADM8211_CSR_WRITE(STSR, stsr); + if (stsr == 0xffffffff) + return IRQ_HANDLED; - do { - stsr = ADM8211_CSR_READ(STSR); - ADM8211_CSR_WRITE(STSR, stsr); - if (stsr == 0xffffffff) - return IRQ_HANDLED; + if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS))) + return IRQ_HANDLED; - if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS))) - break; + if (stsr & ADM8211_STSR_RCI) + adm8211_interrupt_rci(dev); + if (stsr & ADM8211_STSR_TCI) + adm8211_interrupt_tci(dev); - if (stsr & ADM8211_STSR_RCI) - adm8211_interrupt_rci(dev); - if (stsr & ADM8211_STSR_TCI) - adm8211_interrupt_tci(dev); + /*ADM8211_INT(LinkOn);*/ + /*ADM8211_INT(LinkOff);*/ - /*ADM8211_INT(LinkOn);*/ - /*ADM8211_INT(LinkOff);*/ + ADM8211_INT(PCF); + ADM8211_INT(BCNTC); + ADM8211_INT(GPINT); + ADM8211_INT(ATIMTC); + ADM8211_INT(TSFTF); + ADM8211_INT(TSCZ); + ADM8211_INT(SQL); + ADM8211_INT(WEPTD); + ADM8211_INT(ATIME); + /*ADM8211_INT(TBTT);*/ + ADM8211_INT(TEIS); + ADM8211_INT(FBE); + ADM8211_INT(REIS); + ADM8211_INT(GPTT); + ADM8211_INT(RPS); + ADM8211_INT(RDU); + ADM8211_INT(TUF); + /*ADM8211_INT(TRT);*/ + /*ADM8211_INT(TLT);*/ + /*ADM8211_INT(TDU);*/ + ADM8211_INT(TPS); - ADM8211_INT(PCF); - ADM8211_INT(BCNTC); - ADM8211_INT(GPINT); - ADM8211_INT(ATIMTC); - ADM8211_INT(TSFTF); - ADM8211_INT(TSCZ); - ADM8211_INT(SQL); - ADM8211_INT(WEPTD); - ADM8211_INT(ATIME); - /*ADM8211_INT(TBTT);*/ - ADM8211_INT(TEIS); - ADM8211_INT(FBE); - ADM8211_INT(REIS); - ADM8211_INT(GPTT); - ADM8211_INT(RPS); - ADM8211_INT(RDU); - ADM8211_INT(TUF); - /*ADM8211_INT(TRT);*/ - /*ADM8211_INT(TLT);*/ - /*ADM8211_INT(TDU);*/ - ADM8211_INT(TPS); - - } while (count++ < 20); - - return IRQ_RETVAL(count); + return IRQ_HANDLED; #undef ADM8211_INT } From fb9bc28f8bd8a6b9bc5fba7bcacc4bb131d2d5dc Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH 1565/2804] [PATCH] adm8211: Improve writing of mac addrs to registers The mac address write is broken for big endian and the bssid write can be simplified. This patch does both. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 0893d0d4a5eb..4c43cdb567c9 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1283,8 +1283,7 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) struct adm8211_priv *priv = dev->priv; u32 reg; - reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24); - ADM8211_CSR_WRITE(BSSID0, reg); + ADM8211_CSR_WRITE(BSSID0, le32_to_cpu(*(__le32 *)bssid)); reg = ADM8211_CSR_READ(ABDA1); reg &= 0x0000ffff; reg |= (bssid[4] << 16) | (bssid[5] << 24); @@ -1414,8 +1413,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, ADM8211_IDLE(); - ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr); - ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4)); + ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr)); + ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); adm8211_update_mode(dev); From 0d282764eb82f89395493b5e0541c1e30c985838 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH 1566/2804] [PATCH] adm8211: kill version printks No need to pollute dmesg with copyright info. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 4c43cdb567c9..ce1f8e304eaa 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -39,11 +39,6 @@ static unsigned int rx_ring_size __read_mostly = 16; module_param(tx_ring_size, uint, 0); module_param(rx_ring_size, uint, 0); -static const char version[] = KERN_INFO "adm8211: " -"Copyright 2003, Jouni Malinen ; " -"Copyright 2004-2007, Michael Wu \n"; - - static struct pci_device_id adm8211_pci_id_table[] __devinitdata = { /* ADMtek ADM8211 */ { PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */ @@ -1794,12 +1789,6 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, u8 perm_addr[ETH_ALEN]; DECLARE_MAC_BUF(mac); -#ifndef MODULE - static unsigned int cardidx; - if (!cardidx++) - printk(version); -#endif - err = pci_enable_device(pdev); if (err) { printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n", @@ -2051,10 +2040,6 @@ static struct pci_driver adm8211_driver = { static int __init adm8211_init(void) { -#ifdef MODULE - printk(version); -#endif - return pci_register_driver(&adm8211_driver); } From f6ac0adf54ed3fc7fa47e66b92defcbdf37b44ab Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH 1567/2804] [PATCH] adm8211: Use revision from pci_dev No need to load the revision ourselves anymore. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 44 ++++++++++++++++------------------ drivers/net/wireless/adm8211.h | 4 +--- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index ce1f8e304eaa..e950a7d55711 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -117,7 +117,7 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) break; default: - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) priv->rf_type = ADM8211_TYPE_RFMD; else priv->rf_type = ADM8211_TYPE_AIROHA; @@ -135,7 +135,7 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) case ADM8211_TYPE_ADMTEK: break; default: - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) priv->bbp_type = ADM8211_TYPE_RFMD; else priv->bbp_type = ADM8211_TYPE_ADMTEK; @@ -175,7 +175,7 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) break; default: - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) priv->specific_bbptype = ADM8211_BBP_RFMD3000; else priv->specific_bbptype = ADM8211_BBP_ADM8011; @@ -194,11 +194,11 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) break; default: - if (priv->revid == ADM8211_REV_BA) + if (priv->pdev->revision == ADM8211_REV_BA) priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER; - else if (priv->revid == ADM8211_REV_CA) + else if (priv->pdev->revision == ADM8211_REV_CA) priv->transceiver_type = ADM8211_AL2210L; - else if (priv->revid == ADM8211_REV_AB) + else if (priv->pdev->revision == ADM8211_REV_AB) priv->transceiver_type = ADM8211_RFMD2948; printk(KERN_WARNING "%s (adm8211): Unknown transceiver: %d\n", @@ -220,7 +220,7 @@ static inline void adm8211_write_sram(struct ieee80211_hw *dev, struct adm8211_priv *priv = dev->priv; ADM8211_CSR_WRITE(WEPCTL, addr | ADM8211_WEPCTL_TABLE_WR | - (priv->revid < ADM8211_REV_BA ? + (priv->pdev->revision < ADM8211_REV_BA ? 0 : ADM8211_WEPCTL_SEL_WEPTABLE )); ADM8211_CSR_READ(WEPCTL); msleep(1); @@ -238,7 +238,7 @@ static void adm8211_write_sram_bytes(struct ieee80211_hw *dev, u32 reg = ADM8211_CSR_READ(WEPCTL); unsigned int i; - if (priv->revid < ADM8211_REV_BA) { + if (priv->pdev->revision < ADM8211_REV_BA) { for (i = 0; i < len; i += 2) { u16 val = buf[i] | (buf[i + 1] << 8); adm8211_write_sram(dev, addr + i / 2, val); @@ -421,7 +421,7 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) if (skb) { struct ieee80211_rx_status rx_status = {0}; - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) rx_status.ssi = rssi; else rx_status.ssi = 100 - rssi; @@ -703,7 +703,7 @@ static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg); /* set TXRX TX_GAIN */ adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 | - (priv->revid < ADM8211_REV_CA ? tx_power : 0)); + (priv->pdev->revision < ADM8211_REV_CA ? tx_power : 0)); } else { reg = ADM8211_CSR_READ(PLCPHD); reg &= 0xff00ffff; @@ -722,7 +722,7 @@ static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) tx_power<<2); adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff); adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh); - adm8211_write_bbp(dev, 0x1c, priv->revid == ADM8211_REV_BA ? + adm8211_write_bbp(dev, 0x1c, priv->pdev->revision == ADM8211_REV_BA ? priv->eeprom->cr28 : 0); adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29); @@ -761,7 +761,7 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR; /* don't trust the error bits on rev 0x20 and up in adhoc */ - if (priv->revid >= ADM8211_REV_BA) + if (priv->pdev->revision >= ADM8211_REV_BA) priv->soft_rx_crc = 1; break; case IEEE80211_IF_TYPE_MNTR: @@ -862,7 +862,7 @@ static int adm8211_hw_init_bbp(struct ieee80211_hw *dev) break; } - switch (priv->revid) { + switch (priv->pdev->revision) { case ADM8211_REV_CA: if (priv->transceiver_type == ADM8211_RFMD2958 || priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || @@ -920,7 +920,7 @@ static int adm8211_hw_init_bbp(struct ieee80211_hw *dev) adm8211_write_bbp(dev, 0x1c, 0x00); adm8211_write_bbp(dev, 0x1d, 0x80); } else { - if (priv->revid == ADM8211_REV_BA) + if (priv->pdev->revision == ADM8211_REV_BA) adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28); else adm8211_write_bbp(dev, 0x1c, 0x00); @@ -1052,7 +1052,7 @@ static int adm8211_set_rate(struct ieee80211_hw *dev) u8 rate_buf[12] = {0}; /* write supported rates */ - if (priv->revid != ADM8211_REV_BA) { + if (priv->pdev->revision != ADM8211_REV_BA) { rate_buf[0] = ARRAY_SIZE(adm8211_rates); for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++) rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80; @@ -1136,7 +1136,7 @@ static void adm8211_hw_init(struct ieee80211_hw *dev) * PWR0PE2 = 13 us * PWR1PE2 = 1 us * PWR0TXPE = 8 or 6 */ - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) ADM8211_CSR_WRITE(TOFS2, 0x8815cd18); else ADM8211_CSR_WRITE(TOFS2, 0x8535cd16); @@ -1165,7 +1165,7 @@ static void adm8211_hw_init(struct ieee80211_hw *dev) /* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us), * DIFS=50 us, EIFS=100 us */ - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) ADM8211_CSR_WRITE(IFST, (20 << 23) | (110 << 15) | (50 << 9) | 100); else @@ -1224,13 +1224,13 @@ static int adm8211_hw_reset(struct ieee80211_hw *dev) ADM8211_CSR_WRITE(PAR, tmp); - if (priv->revid == ADM8211_REV_BA && + if (priv->pdev->revision == ADM8211_REV_BA && (priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || priv->transceiver_type == ADM8211_RFMD2958)) { reg = ADM8211_CSR_READ(CSR_TEST1); reg |= (1 << 4) | (1 << 5); ADM8211_CSR_WRITE(CSR_TEST1, reg); - } else if (priv->revid == ADM8211_REV_CA) { + } else if (priv->pdev->revision == ADM8211_REV_CA) { reg = ADM8211_CSR_READ(CSR_TEST1); reg &= ~((1 << 4) | (1 << 5)); ADM8211_CSR_WRITE(CSR_TEST1, reg); @@ -1866,8 +1866,6 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_iounmap; } - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &priv->revid); - *(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0)); *(u16 *)&perm_addr[4] = le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF); @@ -1902,7 +1900,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->mode = IEEE80211_IF_TYPE_MNTR; /* Power-on issue. EEPROM won't read correctly without */ - if (priv->revid >= ADM8211_REV_BA) { + if (pdev->revision >= ADM8211_REV_BA) { ADM8211_CSR_WRITE(FRCTL, 0); ADM8211_CSR_READ(FRCTL); ADM8211_CSR_WRITE(FRCTL, 1); @@ -1935,7 +1933,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n", wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), - priv->revid); + pdev->revision); return 0; diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 5991b17c4a7b..ef326fed42e4 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -416,7 +416,7 @@ struct adm8211_desc { #define TDES1_CONTROL_RBS1 (0x00000fff) /* SRAM offsets */ -#define ADM8211_SRAM(x) (priv->revid < ADM8211_REV_BA ? \ +#define ADM8211_SRAM(x) (priv->pdev->revision < ADM8211_REV_BA ? \ ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x) #define ADM8211_SRAM_INDIV_KEY 0x0000 @@ -623,8 +623,6 @@ struct adm8211_priv { struct adm8211_eeprom *eeprom; size_t eeprom_len; - u8 revid; - u32 nar; #define ADM8211_TYPE_INTERSIL 0x00 From d703e29a88c91f015aa691a195e8fd4426c4ec73 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH 1568/2804] [PATCH] adm8211: Pass all TXed frames to tx_status_irqsafe ieee80211_tx_status_irqsafe can handle the freeing of all TXed frames. Also, set excessive_retries for failed frames. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index e950a7d55711..95c8315d71ec 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -299,6 +299,7 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) { unsigned int entry = dirty_tx % priv->tx_ring_size; u32 status = le32_to_cpu(priv->tx_ring[entry].status); + struct ieee80211_tx_status tx_status; struct adm8211_tx_ring_info *info; struct sk_buff *skb; @@ -314,21 +315,19 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - if (info->tx_control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) { - struct ieee80211_tx_status tx_status = {{0}}; - struct ieee80211_hdr *hdr; - size_t hdrlen = info->hdrlen; - - skb_pull(skb, sizeof(struct adm8211_tx_hdr)); - hdr = (struct ieee80211_hdr *)skb_push(skb, hdrlen); - memcpy(hdr, skb->cb, hdrlen); - memcpy(&tx_status.control, &info->tx_control, - sizeof(tx_status.control)); - if (!(status & TDES0_STATUS_ES)) + memset(&tx_status, 0, sizeof(tx_status)); + skb_pull(skb, sizeof(struct adm8211_tx_hdr)); + memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); + memcpy(&tx_status.control, &info->tx_control, + sizeof(tx_status.control)); + if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (status & TDES0_STATUS_ES) + tx_status.excessive_retries = 1; + else tx_status.flags |= IEEE80211_TX_STATUS_ACK; - ieee80211_tx_status_irqsafe(dev, skb, &tx_status); - } else - dev_kfree_skb_irq(skb); + } + ieee80211_tx_status_irqsafe(dev, skb, &tx_status); + info->skb = NULL; } From ce1234d299f3823ea07019c0f7b7b0bcb81ee7a0 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH 1569/2804] [PATCH] adm8211: Detect interface up/down in suspend/resume hooks correctly Interface up/down detection was incorrectly changed during the filter API update. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 95c8315d71ec..e4fdadb52503 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1540,6 +1540,7 @@ static int adm8211_start(struct ieee80211_hw *dev) ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | ADM8211_IER_TDUIE | ADM8211_IER_GPTIE); + priv->mode = IEEE80211_IF_TYPE_MNTR; adm8211_update_mode(dev); ADM8211_CSR_WRITE(RDR, 0); @@ -1554,6 +1555,7 @@ static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; + priv->mode = IEEE80211_IF_TYPE_MGMT; priv->nar = 0; ADM8211_CSR_WRITE(NAR, 0); ADM8211_CSR_WRITE(IER, 0); @@ -1896,7 +1898,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = IEEE80211_IF_TYPE_MGMT; /* Power-on issue. EEPROM won't read correctly without */ if (pdev->revision >= ADM8211_REV_BA) { @@ -1991,7 +1993,7 @@ 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 != IEEE80211_IF_TYPE_MNTR) { + if (priv->mode != IEEE80211_IF_TYPE_MGMT) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2009,7 +2011,7 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_MNTR) { + if (priv->mode != IEEE80211_IF_TYPE_MGMT) { adm8211_start(dev); ieee80211_start_queues(dev); } From b4219952356baa162368f2f5dab6421a5dbc5e15 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 27 Sep 2007 12:48:05 -0700 Subject: [PATCH 1570/2804] [PKT_SCHED]: Add stateless NAT Stateless NAT is useful in controlled environments where restrictions are placed on through traffic such that we don't need connection tracking to correctly NAT protocol-specific data. In particular, this is of interest when the number of flows or the number of addresses being NATed is large, or if connection tracking information has to be replicated and where it is not practical to do so. Previously we had stateless NAT functionality which was integrated into the IPv4 routing subsystem. This was a great solution as long as the NAT worked on a subnet to subnet basis such that the number of NAT rules was relatively small. The reason is that for SNAT the routing based system had to perform a linear scan through the rules. If the number of rules is large then major renovations would have take place in the routing subsystem to make this practical. For the time being, the least intrusive way of achieving this is to use the u32 classifier written by Alexey Kuznetsov along with the actions infrastructure implemented by Jamal Hadi Salim. The following patch is an attempt at this problem by creating a new nat action that can be invoked from u32 hash tables which would allow large number of stateless NAT rules that can be used/updated in constant time. The actual NAT code is mostly based on the previous stateless NAT code written by Alexey. In future we might be able to utilise the protocol NAT code from netfilter to improve support for other protocols. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/tc_act/tc_nat.h | 29 +++ include/net/tc_act/tc_nat.h | 21 +++ net/sched/Kconfig | 11 ++ net/sched/Makefile | 1 + net/sched/act_nat.c | 322 ++++++++++++++++++++++++++++++++++ 5 files changed, 384 insertions(+) create mode 100644 include/linux/tc_act/tc_nat.h create mode 100644 include/net/tc_act/tc_nat.h create mode 100644 net/sched/act_nat.c diff --git a/include/linux/tc_act/tc_nat.h b/include/linux/tc_act/tc_nat.h new file mode 100644 index 000000000000..e7cf31e8ba79 --- /dev/null +++ b/include/linux/tc_act/tc_nat.h @@ -0,0 +1,29 @@ +#ifndef __LINUX_TC_NAT_H +#define __LINUX_TC_NAT_H + +#include +#include + +#define TCA_ACT_NAT 9 + +enum +{ + TCA_NAT_UNSPEC, + TCA_NAT_PARMS, + TCA_NAT_TM, + __TCA_NAT_MAX +}; +#define TCA_NAT_MAX (__TCA_NAT_MAX - 1) + +#define TCA_NAT_FLAG_EGRESS 1 + +struct tc_nat +{ + tc_gen; + __be32 old_addr; + __be32 new_addr; + __be32 mask; + __u32 flags; +}; + +#endif diff --git a/include/net/tc_act/tc_nat.h b/include/net/tc_act/tc_nat.h new file mode 100644 index 000000000000..4a691f34d703 --- /dev/null +++ b/include/net/tc_act/tc_nat.h @@ -0,0 +1,21 @@ +#ifndef __NET_TC_NAT_H +#define __NET_TC_NAT_H + +#include +#include + +struct tcf_nat { + struct tcf_common common; + + __be32 old_addr; + __be32 new_addr; + __be32 mask; + u32 flags; +}; + +static inline struct tcf_nat *to_tcf_nat(struct tcf_common *pc) +{ + return container_of(pc, struct tcf_nat, common); +} + +#endif /* __NET_TC_NAT_H */ diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 8a74cac0be8c..92435a882fac 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -447,6 +447,17 @@ config NET_ACT_IPT To compile this code as a module, choose M here: the module will be called ipt. +config NET_ACT_NAT + tristate "Stateless NAT" + depends on NET_CLS_ACT + select NETFILTER + ---help--- + Say Y here to do stateless NAT on IPv4 packets. You should use + netfilter for NAT unless you know what you are doing. + + To compile this code as a module, choose M here: the + module will be called nat. + config NET_ACT_PEDIT tristate "Packet Editing" depends on NET_CLS_ACT diff --git a/net/sched/Makefile b/net/sched/Makefile index b67c36f65cf2..81ecbe8e7dce 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_NET_ACT_POLICE) += act_police.o obj-$(CONFIG_NET_ACT_GACT) += act_gact.o obj-$(CONFIG_NET_ACT_MIRRED) += act_mirred.o obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o +obj-$(CONFIG_NET_ACT_NAT) += act_nat.o obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c new file mode 100644 index 000000000000..c96273bcaf9c --- /dev/null +++ b/net/sched/act_nat.c @@ -0,0 +1,322 @@ +/* + * Stateless NAT actions + * + * Copyright (c) 2007 Herbert Xu + * + * 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 + + +#define NAT_TAB_MASK 15 +static struct tcf_common *tcf_nat_ht[NAT_TAB_MASK + 1]; +static u32 nat_idx_gen; +static DEFINE_RWLOCK(nat_lock); + +static struct tcf_hashinfo nat_hash_info = { + .htab = tcf_nat_ht, + .hmask = NAT_TAB_MASK, + .lock = &nat_lock, +}; + +static int tcf_nat_init(struct rtattr *rta, struct rtattr *est, + struct tc_action *a, int ovr, int bind) +{ + struct rtattr *tb[TCA_NAT_MAX]; + struct tc_nat *parm; + int ret = 0; + struct tcf_nat *p; + struct tcf_common *pc; + + if (rta == NULL || rtattr_parse_nested(tb, TCA_NAT_MAX, rta) < 0) + return -EINVAL; + + if (tb[TCA_NAT_PARMS - 1] == NULL || + RTA_PAYLOAD(tb[TCA_NAT_PARMS - 1]) < sizeof(*parm)) + return -EINVAL; + parm = RTA_DATA(tb[TCA_NAT_PARMS - 1]); + + pc = tcf_hash_check(parm->index, a, bind, &nat_hash_info); + if (!pc) { + pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, + &nat_idx_gen, &nat_hash_info); + if (unlikely(!pc)) + return -ENOMEM; + p = to_tcf_nat(pc); + ret = ACT_P_CREATED; + } else { + p = to_tcf_nat(pc); + if (!ovr) { + tcf_hash_release(pc, bind, &nat_hash_info); + return -EEXIST; + } + } + + spin_lock_bh(&p->tcf_lock); + p->old_addr = parm->old_addr; + p->new_addr = parm->new_addr; + p->mask = parm->mask; + p->flags = parm->flags; + + p->tcf_action = parm->action; + spin_unlock_bh(&p->tcf_lock); + + if (ret == ACT_P_CREATED) + tcf_hash_insert(pc, &nat_hash_info); + + return ret; +} + +static int tcf_nat_cleanup(struct tc_action *a, int bind) +{ + struct tcf_nat *p = a->priv; + + return tcf_hash_release(&p->common, bind, &nat_hash_info); +} + +static int tcf_nat(struct sk_buff *skb, struct tc_action *a, + struct tcf_result *res) +{ + struct tcf_nat *p = a->priv; + struct iphdr *iph; + __be32 old_addr; + __be32 new_addr; + __be32 mask; + __be32 addr; + int egress; + int action; + int ihl; + + spin_lock(&p->tcf_lock); + + p->tcf_tm.lastuse = jiffies; + old_addr = p->old_addr; + new_addr = p->new_addr; + mask = p->mask; + egress = p->flags & TCA_NAT_FLAG_EGRESS; + action = p->tcf_action; + + p->tcf_bstats.bytes += skb->len; + p->tcf_bstats.packets++; + + spin_unlock(&p->tcf_lock); + + if (unlikely(action == TC_ACT_SHOT)) + goto drop; + + if (!pskb_may_pull(skb, sizeof(*iph))) + goto drop; + + iph = ip_hdr(skb); + + if (egress) + addr = iph->saddr; + else + addr = iph->daddr; + + if (!((old_addr ^ addr) & mask)) { + if (skb_cloned(skb) && + !skb_clone_writable(skb, sizeof(*iph)) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto drop; + + new_addr &= mask; + new_addr |= addr & ~mask; + + /* Rewrite IP header */ + iph = ip_hdr(skb); + if (egress) + iph->saddr = new_addr; + else + iph->daddr = new_addr; + + nf_csum_replace4(&iph->check, addr, new_addr); + } + + ihl = iph->ihl * 4; + + /* It would be nice to share code with stateful NAT. */ + switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) { + case IPPROTO_TCP: + { + struct tcphdr *tcph; + + if (!pskb_may_pull(skb, ihl + sizeof(*tcph)) || + (skb_cloned(skb) && + !skb_clone_writable(skb, ihl + sizeof(*tcph)) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + goto drop; + + tcph = (void *)(skb_network_header(skb) + ihl); + nf_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 1); + break; + } + case IPPROTO_UDP: + { + struct udphdr *udph; + + if (!pskb_may_pull(skb, ihl + sizeof(*udph)) || + (skb_cloned(skb) && + !skb_clone_writable(skb, ihl + sizeof(*udph)) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + goto drop; + + udph = (void *)(skb_network_header(skb) + ihl); + if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) { + nf_proto_csum_replace4(&udph->check, skb, addr, + new_addr, 1); + if (!udph->check) + udph->check = CSUM_MANGLED_0; + } + break; + } + case IPPROTO_ICMP: + { + struct icmphdr *icmph; + + if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph))) + goto drop; + + icmph = (void *)(skb_network_header(skb) + ihl); + + if ((icmph->type != ICMP_DEST_UNREACH) && + (icmph->type != ICMP_TIME_EXCEEDED) && + (icmph->type != ICMP_PARAMETERPROB)) + break; + + iph = (void *)(icmph + 1); + if (egress) + addr = iph->daddr; + else + addr = iph->saddr; + + if ((old_addr ^ addr) & mask) + break; + + if (skb_cloned(skb) && + !skb_clone_writable(skb, + ihl + sizeof(*icmph) + sizeof(*iph)) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto drop; + + icmph = (void *)(skb_network_header(skb) + ihl); + iph = (void *)(icmph + 1); + + new_addr &= mask; + new_addr |= addr & ~mask; + + /* XXX Fix up the inner checksums. */ + if (egress) + iph->daddr = new_addr; + else + iph->saddr = new_addr; + + nf_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, + 1); + break; + } + default: + break; + } + + return action; + +drop: + spin_lock(&p->tcf_lock); + p->tcf_qstats.drops++; + spin_unlock(&p->tcf_lock); + return TC_ACT_SHOT; +} + +static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, + int bind, int ref) +{ + unsigned char *b = skb_tail_pointer(skb); + struct tcf_nat *p = a->priv; + struct tc_nat *opt; + struct tcf_t t; + int s; + + s = sizeof(*opt); + + /* netlink spinlocks held above us - must use ATOMIC */ + opt = kzalloc(s, GFP_ATOMIC); + if (unlikely(!opt)) + return -ENOBUFS; + + opt->old_addr = p->old_addr; + opt->new_addr = p->new_addr; + opt->mask = p->mask; + opt->flags = p->flags; + + opt->index = p->tcf_index; + opt->action = p->tcf_action; + opt->refcnt = p->tcf_refcnt - ref; + opt->bindcnt = p->tcf_bindcnt - bind; + + RTA_PUT(skb, TCA_NAT_PARMS, s, opt); + t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); + t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); + t.expires = jiffies_to_clock_t(p->tcf_tm.expires); + RTA_PUT(skb, TCA_NAT_TM, sizeof(t), &t); + + kfree(opt); + + return skb->len; + +rtattr_failure: + nlmsg_trim(skb, b); + kfree(opt); + return -1; +} + +static struct tc_action_ops act_nat_ops = { + .kind = "nat", + .hinfo = &nat_hash_info, + .type = TCA_ACT_NAT, + .capab = TCA_CAP_NONE, + .owner = THIS_MODULE, + .act = tcf_nat, + .dump = tcf_nat_dump, + .cleanup = tcf_nat_cleanup, + .lookup = tcf_hash_search, + .init = tcf_nat_init, + .walk = tcf_generic_walker +}; + +MODULE_DESCRIPTION("Stateless NAT actions"); +MODULE_LICENSE("GPL"); + +static int __init nat_init_module(void) +{ + return tcf_register_action(&act_nat_ops); +} + +static void __exit nat_cleanup_module(void) +{ + tcf_unregister_action(&act_nat_ops); +} + +module_init(nat_init_module); +module_exit(nat_cleanup_module); From 5b2812e925c8e976852867f8d760637c5926d817 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 14:27:23 +0200 Subject: [PATCH 1571/2804] [PATCH] mac80211: fix interface initialisation and deinitialisation When an interface is registered it is still uninitialised so ieee80211_if_reinit() can't be called on it (it will oops.) Hence, we need to move the uninit method assignment. Also, this patch fixes the bug that the master device is never initialised nor deinitialised at all. Oddly, the deinit code had an if statement to not run some code when running for the master interface (which never happened), but that if statement is also wrong. Fix that too. Now that the uninit code is run for the master device, another bug surfaced: it tries to remove all dependent interfaces and that oopses or BUGs at some point, either because it unregisters already unregistered interfaces (missing list_del bug) or due to trying to iterate a list that has had other things removed. Fix this too by handling the master interface specially. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 19 +++++++++++++++--- net/mac80211/ieee80211_iface.c | 35 ++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index ccf84634f156..52638194e45f 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -265,7 +265,6 @@ void ieee80211_if_mgmt_setup(struct net_device *dev) dev->open = ieee80211_mgmt_open; dev->stop = ieee80211_mgmt_stop; dev->type = ARPHRD_IEEE80211_PRISM; - dev->uninit = ieee80211_if_reinit; dev->destructor = ieee80211_if_free; } @@ -551,7 +550,6 @@ void ieee80211_if_setup(struct net_device *dev) dev->change_mtu = ieee80211_change_mtu; dev->open = ieee80211_open; dev->stop = ieee80211_stop; - dev->uninit = ieee80211_if_reinit; dev->destructor = ieee80211_if_free; } @@ -1242,6 +1240,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_dev; ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); + ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP); result = ieee80211_init_rate_ctrl_alg(local, NULL); if (result < 0) { @@ -1346,8 +1345,22 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) * because the driver cannot be handing us frames any * more and the tasklet is killed. */ - list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) + + /* + * First, we remove all non-master interfaces. Do this because they + * may have bss pointer dependency on the master, and when we free + * the master these would be freed as well, breaking our list + * iteration completely. + */ + list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { + if (sdata->dev == local->mdev) + continue; + list_del(&sdata->list); __ieee80211_if_del(local, sdata); + } + + /* then, finally, remove the master interface */ + __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev)); rtnl_unlock(); diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 2ba24ef319da..369ee4f52a29 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -127,6 +127,12 @@ int ieee80211_if_add_mgmt(struct ieee80211_local *local) if (ret) goto fail; + /* + * Called even when register_netdevice fails, it would + * oops if assigned before initialising the rest. + */ + ndev->uninit = ieee80211_if_reinit; + ieee80211_debugfs_add_netdev(nsdata); if (local->open_count > 0) @@ -155,12 +161,27 @@ void ieee80211_if_set_type(struct net_device *dev, int type) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int oldtype = sdata->type; - dev->hard_start_xmit = ieee80211_subif_start_xmit; + /* + * We need to call this function on the master interface + * which already has a hard_start_xmit routine assigned + * which must not be changed. + */ + if (!dev->hard_start_xmit) + dev->hard_start_xmit = ieee80211_subif_start_xmit; + /* + * Called even when register_netdevice fails, it would + * oops if assigned before initialising the rest. + */ + dev->uninit = ieee80211_if_reinit; + + /* most have no BSS pointer */ + sdata->bss = NULL; sdata->type = type; + switch (type) { case IEEE80211_IF_TYPE_WDS: - sdata->bss = NULL; + /* nothing special */ break; case IEEE80211_IF_TYPE_VLAN: sdata->u.vlan.ap = NULL; @@ -213,6 +234,7 @@ void ieee80211_if_reinit(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; + struct sk_buff *skb; ASSERT_RTNL(); @@ -246,12 +268,9 @@ void ieee80211_if_reinit(struct net_device *dev) kfree(sdata->u.ap.beacon_tail); kfree(sdata->u.ap.generic_elem); - if (dev != local->mdev) { - struct sk_buff *skb; - while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { - local->total_ps_buffered--; - dev_kfree_skb(skb); - } + while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { + local->total_ps_buffered--; + dev_kfree_skb(skb); } break; From b2e7771e556917cc301a3308561f49b2b2272c07 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:39 +0200 Subject: [PATCH 1572/2804] [PATCH] mac80211: pass frames to monitor interfaces early This makes mac80211 pass all frames to monitor interfaces early before all receive processing with the benefit that only a single copy needs to be made, all monitors can receive clones of the skb and if the frame will be discarded we don't even need to make a single copy. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 350 ++++++++++++++++++++++++++++++---------------- 1 file changed, 226 insertions(+), 124 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cb44a9db0e19..a0dfafb4f38b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -25,6 +25,207 @@ #include "tkip.h" #include "wme.h" +/* + * monitor mode reception + * + * This function cleans up the SKB, i.e. it removes all the stuff + * only useful for monitoring. + */ +static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, + struct sk_buff *skb, + int rtap_len) +{ + skb_pull(skb, rtap_len); + + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { + if (likely(skb->len > FCS_LEN)) + skb_trim(skb, skb->len - FCS_LEN); + else { + /* driver bug */ + WARN_ON(1); + dev_kfree_skb(skb); + skb = NULL; + } + } + + return skb; +} + +static inline int should_drop_frame(struct ieee80211_rx_status *status, + struct sk_buff *skb, + int present_fcs_len, + int radiotap_len) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) + return 1; + if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len)) + return 1; + if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL)) + return 1; + return 0; +} + +/* + * This function copies a received frame to all monitor interfaces and + * returns a cleaned-up SKB that no longer includes the FCS nor the + * radiotap header the driver might have added. + */ +static struct sk_buff * +ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, + struct ieee80211_rx_status *status) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_rate *rate; + int needed_headroom = 0; + struct ieee80211_rtap_hdr { + struct ieee80211_radiotap_header hdr; + u8 flags; + u8 rate; + __le16 chan_freq; + __le16 chan_flags; + u8 antsignal; + u8 padding_for_rxflags; + __le16 rx_flags; + } __attribute__ ((packed)) *rthdr; + struct sk_buff *skb, *skb2; + struct net_device *prev_dev = NULL; + int present_fcs_len = 0; + int rtap_len = 0; + + /* + * First, we may need to make a copy of the skb because + * (1) we need to modify it for radiotap (if not present), and + * (2) the other RX handlers will modify the skb we got. + * + * We don't need to, of course, if we aren't going to return + * the SKB because it has a bad FCS/PLCP checksum. + */ + if (status->flag & RX_FLAG_RADIOTAP) + rtap_len = ieee80211_get_radiotap_len(origskb->data); + else + needed_headroom = sizeof(*rthdr); + + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) + present_fcs_len = FCS_LEN; + + if (!local->monitors) { + if (should_drop_frame(status, origskb, present_fcs_len, + rtap_len)) { + dev_kfree_skb(origskb); + return NULL; + } + + return remove_monitor_info(local, origskb, rtap_len); + } + + if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) { + /* only need to expand headroom if necessary */ + skb = origskb; + origskb = NULL; + + /* + * This shouldn't trigger often because most devices have an + * RX header they pull before we get here, and that should + * be big enough for our radiotap information. We should + * probably export the length to drivers so that we can have + * them allocate enough headroom to start with. + */ + if (skb_headroom(skb) < needed_headroom && + pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return NULL; + } + } else { + /* + * Need to make a copy and possibly remove radiotap header + * and FCS from the original. + */ + skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); + + origskb = remove_monitor_info(local, origskb, rtap_len); + + if (!skb) + return origskb; + } + + /* if necessary, prepend radiotap information */ + if (!(status->flag & RX_FLAG_RADIOTAP)) { + rthdr = (void *) skb_push(skb, sizeof(*rthdr)); + memset(rthdr, 0, sizeof(*rthdr)); + rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); + rthdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_RX_FLAGS)); + rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? + IEEE80211_RADIOTAP_F_FCS : 0; + + /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ + rthdr->rx_flags = 0; + if (status->flag & + (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) + rthdr->rx_flags |= + cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); + + rate = ieee80211_get_rate(local, status->phymode, + status->rate); + if (rate) + rthdr->rate = rate->rate / 5; + + rthdr->chan_freq = cpu_to_le16(status->freq); + + if (status->phymode == MODE_IEEE80211A) + rthdr->chan_flags = + cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ); + else + rthdr->chan_flags = + cpu_to_le16(IEEE80211_CHAN_DYN | + IEEE80211_CHAN_2GHZ); + + rthdr->antsignal = status->ssi; + } + + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->type != IEEE80211_IF_TYPE_MNTR) + continue; + + if (prev_dev) { + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; + sdata->dev->stats.rx_packets++; + sdata->dev->stats.rx_bytes += skb->len; + } + + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + } else + dev_kfree_skb(skb); + + return origskb; +} + + /* pre-rx handlers * * these don't have dev/sdata fields in the rx data @@ -132,100 +333,6 @@ ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; } -static void -ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_rx_status *status) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_rate *rate; - struct ieee80211_rtap_hdr { - struct ieee80211_radiotap_header hdr; - u8 flags; - u8 rate; - __le16 chan_freq; - __le16 chan_flags; - u8 antsignal; - u8 padding_for_rxflags; - __le16 rx_flags; - } __attribute__ ((packed)) *rthdr; - - skb->dev = dev; - - if (status->flag & RX_FLAG_RADIOTAP) - goto out; - - if (skb_headroom(skb) < sizeof(*rthdr)) { - I802_DEBUG_INC(local->rx_expand_skb_head); - if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return; - } - } - - rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr)); - memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_RX_FLAGS)); - rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? - IEEE80211_RADIOTAP_F_FCS : 0; - - /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ - rthdr->rx_flags = 0; - if (status->flag & - (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) - rthdr->rx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); - - rate = ieee80211_get_rate(local, status->phymode, status->rate); - if (rate) - rthdr->rate = rate->rate / 5; - - rthdr->chan_freq = cpu_to_le16(status->freq); - rthdr->chan_flags = - status->phymode == MODE_IEEE80211A ? - cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) : - cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ); - rthdr->antsignal = status->ssi; - - out: - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - -static ieee80211_txrx_result -ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx) -{ - if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) { - ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status); - return TXRX_QUEUED; - } - - /* - * Drop frames with failed FCS/PLCP checksums here, they are only - * relevant for monitor mode, the rest of the stack should never - * see them. - */ - if (rx->u.rx.status->flag & - (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) - return TXRX_DROP; - - if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP) - skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb->data)); - - return TXRX_CONTINUE; -} - static ieee80211_txrx_result ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) { @@ -266,10 +373,6 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; } - if ((rx->local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) && - rx->skb->len > FCS_LEN) - skb_trim(rx->skb, rx->skb->len - FCS_LEN); - if (unlikely(rx->skb->len < 16)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_short); return TXRX_DROP; @@ -1264,7 +1367,6 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, ieee80211_rx_handler ieee80211_rx_handlers[] = { ieee80211_rx_h_if_stats, - ieee80211_rx_h_monitor, ieee80211_rx_h_passive_scan, ieee80211_rx_h_check, ieee80211_rx_h_load_key, @@ -1371,16 +1473,10 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_hdr *hdr; struct ieee80211_txrx_data rx; u16 type; - int radiotap_len = 0, prepres; + int prepres; struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; u8 *bssid; - int bogon; - - if (status->flag & RX_FLAG_RADIOTAP) { - radiotap_len = ieee80211_get_radiotap_len(skb->data); - skb_pull(skb, radiotap_len); - } /* * key references and virtual interfaces are protected using RCU @@ -1389,30 +1485,35 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, */ rcu_read_lock(); + /* + * Frames with failed FCS/PLCP checksum are not returned, + * all other frames are returned without radiotap header + * if it was previously present. + * Also, frames with less than 16 bytes are dropped. + */ + skb = ieee80211_rx_monitor(local, skb, status); + if (!skb) { + rcu_read_unlock(); + return; + } + hdr = (struct ieee80211_hdr *) skb->data; memset(&rx, 0, sizeof(rx)); rx.skb = skb; rx.local = local; rx.u.rx.status = status; - rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0; + rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; - bogon = status->flag & (RX_FLAG_FAILED_FCS_CRC | - RX_FLAG_FAILED_PLCP_CRC); - - if (!bogon && (type == IEEE80211_FTYPE_DATA || - type == IEEE80211_FTYPE_MGMT)) + if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) local->dot11ReceivedFragmentCount++; - if (!bogon && skb->len >= 16) { - sta = rx.sta = sta_info_get(local, hdr->addr2); - if (sta) { - rx.dev = rx.sta->dev; - rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); - } - } else - sta = rx.sta = NULL; + sta = rx.sta = sta_info_get(local, hdr->addr2); + if (sta) { + rx.dev = rx.sta->dev; + rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); + } if ((status->flag & RX_FLAG_MMIC_ERROR)) { ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); @@ -1427,7 +1528,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, goto end; skb = rx.skb; - skb_push(skb, radiotap_len); if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) && !local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) { rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; @@ -1438,14 +1538,16 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, return; } - bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len); + bssid = ieee80211_get_bssid(hdr, skb->len); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; - if (!netif_running(sdata->dev)) continue; + if (sdata->type == IEEE80211_IF_TYPE_MNTR) + continue; + + rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; prepres = prepare_for_handlers(sdata, bssid, &rx, hdr); /* prepare_for_handlers can change sta */ sta = rx.sta; From 4f0d18e26f8bc4c6507b69aa0080d0fae807c990 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:40 +0200 Subject: [PATCH 1573/2804] [PATCH] mac80211: consolidate decryption Currently, we run through all three crypto algorithms for each received frame even though we have previously determined which key we have and as such already know which algorithm will be used. Change it to invoke only the needed function. Also move the WEP decrypt handler to wep.c so that fewer functions need to be non-static. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 40 +++++++++++++++++----------------------- net/mac80211/wep.c | 34 +++++++++++++++++++++++++++++----- net/mac80211/wep.h | 8 +++----- net/mac80211/wpa.c | 12 ++++-------- net/mac80211/wpa.h | 4 ++-- 5 files changed, 55 insertions(+), 43 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a0dfafb4f38b..453ccab060a2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -662,36 +662,32 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) } static ieee80211_txrx_result -ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) { - if ((rx->key && rx->key->conf.alg != ALG_WEP) || - !(rx->fc & IEEE80211_FCTL_PROTECTED) || - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) + if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) return TXRX_CONTINUE; if (!rx->key) { if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n", - rx->dev->name); + printk(KERN_DEBUG "%s: RX protected frame," + " but have no key\n", rx->dev->name); return TXRX_DROP; } - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { - if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX WEP frame, decrypt " - "failed\n", rx->dev->name); - return TXRX_DROP; - } - } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { - ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); - /* remove ICV */ - skb_trim(rx->skb, rx->skb->len - 4); + switch (rx->key->conf.alg) { + case ALG_WEP: + return ieee80211_crypto_wep_decrypt(rx); + case ALG_TKIP: + return ieee80211_crypto_tkip_decrypt(rx); + case ALG_CCMP: + return ieee80211_crypto_ccmp_decrypt(rx); + case ALG_NONE: + return TXRX_CONTINUE; } - return TXRX_CONTINUE; + /* not reached */ + WARN_ON(1); + return TXRX_DROP; } static inline struct ieee80211_fragment_entry * @@ -1371,10 +1367,8 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = ieee80211_rx_h_check, ieee80211_rx_h_load_key, ieee80211_rx_h_sta_process, - ieee80211_rx_h_ccmp_decrypt, - ieee80211_rx_h_tkip_decrypt, ieee80211_rx_h_wep_weak_iv_detection, - ieee80211_rx_h_wep_decrypt, + ieee80211_rx_h_decrypt, ieee80211_rx_h_defragment, ieee80211_rx_h_ps_poll, ieee80211_rx_h_michael_mic_verify, diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 0b19e89fcf6a..e785fe1f78ed 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -63,8 +63,8 @@ static inline int ieee80211_wep_weak_iv(u32 iv, int keylen) } -void ieee80211_wep_get_iv(struct ieee80211_local *local, - struct ieee80211_key *key, u8 *iv) +static void ieee80211_wep_get_iv(struct ieee80211_local *local, + struct ieee80211_key *key, u8 *iv) { local->wep_iv++; if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen)) @@ -109,9 +109,9 @@ u8 * ieee80211_wep_add_iv(struct ieee80211_local *local, } -void ieee80211_wep_remove_iv(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_key *key) +static void ieee80211_wep_remove_iv(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_key *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 fc; @@ -326,3 +326,27 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) return NULL; } + +ieee80211_txrx_result +ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) +{ + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && + ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) + return TXRX_CONTINUE; + + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { + if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX WEP frame, decrypt " + "failed\n", rx->dev->name); + return TXRX_DROP; + } + } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { + ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); + /* remove ICV */ + skb_trim(rx->skb, rx->skb->len - 4); + } + + return TXRX_CONTINUE; +} diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index bfe29e8e10aa..dfa5af143386 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -18,14 +18,9 @@ int ieee80211_wep_init(struct ieee80211_local *local); void ieee80211_wep_free(struct ieee80211_local *local); -void ieee80211_wep_get_iv(struct ieee80211_local *local, - struct ieee80211_key *key, u8 *iv); u8 * ieee80211_wep_add_iv(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); -void ieee80211_wep_remove_iv(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_key *key); 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, @@ -37,4 +32,7 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, int ieee80211_wep_get_keyidx(struct sk_buff *skb); u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); +ieee80211_txrx_result +ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); + #endif /* WEP_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 360d11e9de15..108fe3e81e24 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -281,7 +281,7 @@ ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx) ieee80211_txrx_result -ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc; @@ -293,9 +293,7 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); - if (!rx->key || rx->key->conf.alg != ALG_TKIP || - !(rx->fc & IEEE80211_FCTL_PROTECTED) || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) return TXRX_CONTINUE; if (!rx->sta || skb->len - hdrlen < 12) @@ -535,7 +533,7 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) ieee80211_txrx_result -ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc; @@ -549,9 +547,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); - if (!key || key->conf.alg != ALG_CCMP || - !(rx->fc & IEEE80211_FCTL_PROTECTED) || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) return TXRX_CONTINUE; data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index da3b9594f9c3..e49946f54623 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -21,11 +21,11 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); ieee80211_txrx_result ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx); ieee80211_txrx_result -ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); ieee80211_txrx_result ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx); ieee80211_txrx_result -ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); #endif /* WPA_H */ From 6a22a59d487e7fe509b457b72497593e402911c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:41 +0200 Subject: [PATCH 1574/2804] [PATCH] mac80211: consolidate encryption Currently we run through all crypto handlers for each transmitted frame although we already know which one will be used. This changes the code to invoke only the needed handler. It also moves the wep code into wep.c. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 62 +++++++++++----------------------------------- net/mac80211/wep.c | 57 +++++++++++++++++++++++++++++++++++++++--- net/mac80211/wep.h | 5 ++-- net/mac80211/wpa.c | 10 +++----- net/mac80211/wpa.h | 4 +-- 5 files changed, 77 insertions(+), 61 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 244c80d0c8fb..54e05392410d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -541,56 +541,26 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) return TXRX_DROP; } -static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) -{ - if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) - return -1; - } else { - tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { - if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) - return -1; - } - } - return 0; -} - static ieee80211_txrx_result -ieee80211_tx_h_wep_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 fc; - - fc = le16_to_cpu(hdr->frame_control); - - if (!tx->key || tx->key->conf.alg != ALG_WEP || - ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) + if (!tx->key) return TXRX_CONTINUE; - tx->u.tx.control->iv_len = WEP_IV_LEN; - tx->u.tx.control->icv_len = WEP_ICV_LEN; - ieee80211_tx_set_iswep(tx); - - if (wep_encrypt_skb(tx, tx->skb) < 0) { - I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); - return TXRX_DROP; + switch (tx->key->conf.alg) { + case ALG_WEP: + return ieee80211_crypto_wep_encrypt(tx); + case ALG_TKIP: + return ieee80211_crypto_tkip_encrypt(tx); + case ALG_CCMP: + return ieee80211_crypto_ccmp_encrypt(tx); + case ALG_NONE: + return TXRX_CONTINUE; } - if (tx->u.tx.extra_frag) { - int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { - I802_DEBUG_INC(tx->local-> - tx_handlers_drop_wep); - return TXRX_DROP; - } - } - } - - return TXRX_CONTINUE; + /* not reached */ + WARN_ON(1); + return TXRX_DROP; } static ieee80211_txrx_result @@ -805,9 +775,7 @@ ieee80211_tx_handler ieee80211_tx_handlers[] = ieee80211_tx_h_select_key, ieee80211_tx_h_michael_mic_add, ieee80211_tx_h_fragment, - ieee80211_tx_h_tkip_encrypt, - ieee80211_tx_h_ccmp_encrypt, - ieee80211_tx_h_wep_encrypt, + ieee80211_tx_h_encrypt, ieee80211_tx_h_rate_ctrl, ieee80211_tx_h_misc, ieee80211_tx_h_load_stats, diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index e785fe1f78ed..16fee142f984 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -80,9 +80,9 @@ static void ieee80211_wep_get_iv(struct ieee80211_local *local, } -u8 * ieee80211_wep_add_iv(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_key *key) +static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_key *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 fc; @@ -350,3 +350,54 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; } + +static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) +{ + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) + return -1; + } else { + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; + if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { + if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) + return -1; + } + } + return 0; +} + +ieee80211_txrx_result +ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + u16 fc; + + fc = le16_to_cpu(hdr->frame_control); + + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && + ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) + return TXRX_CONTINUE; + + tx->u.tx.control->iv_len = WEP_IV_LEN; + tx->u.tx.control->icv_len = WEP_ICV_LEN; + ieee80211_tx_set_iswep(tx); + + if (wep_encrypt_skb(tx, tx->skb) < 0) { + I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); + return TXRX_DROP; + } + + if (tx->u.tx.extra_frag) { + int i; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { + I802_DEBUG_INC(tx->local-> + tx_handlers_drop_wep); + return TXRX_DROP; + } + } + } + + return TXRX_CONTINUE; +} diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index dfa5af143386..da53190affc0 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -18,9 +18,6 @@ int ieee80211_wep_init(struct ieee80211_local *local); void ieee80211_wep_free(struct ieee80211_local *local); -u8 * ieee80211_wep_add_iv(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_key *key); 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, @@ -34,5 +31,7 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_txrx_result ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_txrx_result +ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx); #endif /* WEP_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 108fe3e81e24..a07fd7484cdf 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -239,17 +239,16 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, ieee80211_txrx_result -ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc; - struct ieee80211_key *key = tx->key; struct sk_buff *skb = tx->skb; int wpa_test = 0, test = 0; fc = le16_to_cpu(hdr->frame_control); - if (!key || key->conf.alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc)) + if (!WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; tx->u.tx.control->icv_len = TKIP_ICV_LEN; @@ -491,17 +490,16 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, ieee80211_txrx_result -ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - struct ieee80211_key *key = tx->key; u16 fc; struct sk_buff *skb = tx->skb; int test = 0; fc = le16_to_cpu(hdr->frame_control); - if (!key || key->conf.alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc)) + if (!WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; tx->u.tx.control->icv_len = CCMP_MIC_LEN; diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index e49946f54623..49d80cf0cd75 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -19,12 +19,12 @@ ieee80211_txrx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); ieee80211_txrx_result -ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx); +ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx); ieee80211_txrx_result ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); ieee80211_txrx_result -ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx); +ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx); ieee80211_txrx_result ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); From af1a90da397f071d7ee893145a1e7b2124689376 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:42 +0200 Subject: [PATCH 1575/2804] [PATCH] mac80211: remove ieee80211_wep_get_keyidx This function is not used any more. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/wep.c | 19 ------------------- net/mac80211/wep.h | 1 - 2 files changed, 20 deletions(-) diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 16fee142f984..6675261e958f 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -286,25 +286,6 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, } -int ieee80211_wep_get_keyidx(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc; - int hdrlen; - - fc = le16_to_cpu(hdr->frame_control); - if (!(fc & IEEE80211_FCTL_PROTECTED)) - return -1; - - hdrlen = ieee80211_get_hdrlen(fc); - - if (skb->len < 8 + hdrlen) - return -1; - - return skb->data[hdrlen + 3] >> 6; -} - - u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index da53190affc0..785fbb4e0dd7 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -26,7 +26,6 @@ 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); -int ieee80211_wep_get_keyidx(struct sk_buff *skb); u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_txrx_result From fb1c1cd6c5a8988b14c5c6c0dfe55542df3a34c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:43 +0200 Subject: [PATCH 1576/2804] [PATCH] mac80211: fix vlan bug VLAN interfaces have yet another bug: they aren't accounted for properly in the receive path in prepare_for_handlers(). I noticed this by code inspection, but it would be easy for the compiler to catch such things if we'd just use the proper enum where appropriate. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 7 +++++++ net/mac80211/ieee80211_i.h | 2 +- net/mac80211/ieee80211_iface.c | 3 +++ net/mac80211/rx.c | 8 ++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 52638194e45f..b1180536c335 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -344,6 +344,13 @@ static int ieee80211_open(struct net_device *dev) if (!sdata->u.vlan.ap) return -ENOLINK; break; + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_MGMT: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_IBSS: + /* no special treatment */ + break; } if (local->open_count == 0) { diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a5961f16f206..636de70cd85d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -290,7 +290,7 @@ struct ieee80211_if_sta { #define IEEE80211_SDATA_SHORT_PREAMBLE BIT(3) struct ieee80211_sub_if_data { struct list_head list; - unsigned int type; + enum ieee80211_if_types type; struct wireless_dev wdev; diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 369ee4f52a29..60cee6e602d2 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -243,6 +243,9 @@ void ieee80211_if_reinit(struct net_device *dev) ieee80211_if_sdata_deinit(sdata); switch (sdata->type) { + case IEEE80211_IF_TYPE_MGMT: + /* nothing to do */ + break; case IEEE80211_IF_TYPE_AP: { /* Remove all virtual interfaces that use this BSS * as their sdata->bss */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 453ccab060a2..34adc5288fbc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1425,6 +1425,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, bssid, hdr->addr2); break; + case IEEE80211_IF_TYPE_VLAN: case IEEE80211_IF_TYPE_AP: if (!bssid) { if (compare_ether_addr(sdata->dev->dev_addr, @@ -1449,6 +1450,13 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2)) return 0; break; + case IEEE80211_IF_TYPE_MNTR: + /* take everything */ + break; + case IEEE80211_IF_TYPE_MGMT: + /* should never get here */ + WARN_ON(1); + break; } return 1; From 50741ae05a4742cae99361f57d84b5f8d33822a4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:45 +0200 Subject: [PATCH 1577/2804] [PATCH] mac80211: fix TKIP IV update The TKIP IV should be updated only after MMIC verification, this patch changes it to be at that spot. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/tkip.c | 16 ++++++++++------ net/mac80211/tkip.h | 3 ++- net/mac80211/wpa.c | 8 +++++++- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 636de70cd85d..32d19bbf522c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -153,6 +153,8 @@ struct ieee80211_txrx_data { int sent_ps_buffered; int queue; int load; + u32 tkip_iv32; + u16 tkip_iv16; } rx; } u; }; diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 5b11f14abfba..3abe194e4d55 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -238,7 +238,8 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, - int only_iv, int queue) + int only_iv, int queue, + u32 *out_iv32, u16 *out_iv16) { u32 iv32; u32 iv16; @@ -332,11 +333,14 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); done: if (res == TKIP_DECRYPT_OK) { - /* FIX: these should be updated only after Michael MIC has been - * verified */ - /* Record previously received IV */ - key->u.tkip.iv32_rx[queue] = iv32; - key->u.tkip.iv16_rx[queue] = iv16; + /* + * Record previously received IV, will be copied into the + * key information after MIC verification. It is possible + * that we don't catch replays of fragments but that's ok + * because the Michael MIC verication will then fail. + */ + *out_iv32 = iv32; + *out_iv16 = iv16; } return res; diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index a0d181a18049..73d8ef2a93b0 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -31,6 +31,7 @@ enum { int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, - int only_iv, int queue); + int only_iv, int queue, + u32 *out_iv32, u16 *out_iv16); #endif /* TKIP_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index a07fd7484cdf..6695efba57ec 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -175,6 +175,10 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); + /* update IV in key information to be able to detect replays */ + rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32; + rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16; + return TXRX_CONTINUE; } @@ -315,7 +319,9 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->addr, - hwaccel, rx->u.rx.queue); + hwaccel, rx->u.rx.queue, + &rx->u.rx.tkip_iv32, + &rx->u.rx.tkip_iv16); if (res != TKIP_DECRYPT_OK || wpa_test) { printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from " "%s (res=%d)\n", From 53918994b7c8c3bf0af5f641e1f299856799d883 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:47 +0200 Subject: [PATCH 1578/2804] [PATCH] mac80211: fix iff_promiscs, iff_allmultis race When we update the counters iff_promiscs and iff_allmultis in struct ieee80211_local we have no common lock held to protect them. The problem is that the update to each counter may not be atomic, so we could end up with iff_promiscs == -1 in unfortunate conditions. To fix it, use atomic_t values. It doesn't matter whether the two counters are updated together atomically or not, if there are two invocations of set_multicast_list we will end up with multiple configure_filter() invocations of which the latter will always be correct. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 12 ++++++------ net/mac80211/ieee80211_i.h | 5 ++--- net/mac80211/rx.c | 3 ++- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index b1180536c335..2501bff0d15e 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -59,10 +59,10 @@ static void ieee80211_configure_filter(struct ieee80211_local *local) unsigned int changed_flags; unsigned int new_flags = 0; - if (local->iff_promiscs) + if (atomic_read(&local->iff_promiscs)) new_flags |= FIF_PROMISC_IN_BSS; - if (local->iff_allmultis) + if (atomic_read(&local->iff_allmultis)) new_flags |= FIF_ALLMULTI; if (local->monitors) @@ -521,17 +521,17 @@ static void ieee80211_set_multicast_list(struct net_device *dev) if (allmulti != sdata_allmulti) { if (dev->flags & IFF_ALLMULTI) - local->iff_allmultis++; + atomic_inc(&local->iff_allmultis); else - local->iff_allmultis--; + atomic_dec(&local->iff_allmultis); sdata->flags ^= IEEE80211_SDATA_ALLMULTI; } if (promisc != sdata_promisc) { if (dev->flags & IFF_PROMISC) - local->iff_promiscs++; + atomic_inc(&local->iff_promiscs); else - local->iff_promiscs--; + atomic_dec(&local->iff_promiscs); sdata->flags ^= IEEE80211_SDATA_PROMISC; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 32d19bbf522c..38e0a467fa8e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -444,9 +444,8 @@ struct ieee80211_local { struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES]; struct tasklet_struct tx_pending_tasklet; - int mc_count; /* total count of multicast entries in all interfaces */ - int iff_allmultis, iff_promiscs; - /* number of interfaces with corresponding IFF_ flags */ + /* number of interfaces with corresponding IFF_ flags */ + atomic_t iff_allmultis, iff_promiscs; struct rate_control_ref *rate_ctrl; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 34adc5288fbc..03635fb3e9b6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1531,7 +1531,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, skb = rx.skb; if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) && - !local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) { + !atomic_read(&local->iff_promiscs) && + !is_multicast_ether_addr(hdr->addr1)) { rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, rx.sta); From 51617f0b76389b29740aa9d7736df99b75d1d9ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:48 +0200 Subject: [PATCH 1579/2804] [PATCH] mac80211: remove all prism2 ioctls This patch removes all prism2 ioctls. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/hostapd_ioctl.h | 61 -------- net/mac80211/ieee80211_i.h | 5 - net/mac80211/ieee80211_ioctl.c | 272 --------------------------------- net/mac80211/ieee80211_sta.c | 1 - 4 files changed, 339 deletions(-) delete mode 100644 net/mac80211/hostapd_ioctl.h diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h deleted file mode 100644 index 2300c5516458..000000000000 --- a/net/mac80211/hostapd_ioctl.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Host AP (software wireless LAN access point) user space daemon for - * Host AP kernel driver - * Copyright 2002-2003, Jouni Malinen - * Copyright 2002-2004, Instant802 Networks, Inc. - * Copyright 2005, 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. - */ - -#ifndef HOSTAPD_IOCTL_H -#define HOSTAPD_IOCTL_H - -#ifdef __KERNEL__ -#include -#endif /* __KERNEL__ */ - -#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) -#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) -#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3) - -/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: - * This table is no longer added to, the whole sub-ioctl - * mess shall be deleted completely. */ -enum { - PRISM2_PARAM_IEEE_802_1X = 23, - - /* Instant802 additions */ - PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001, - PRISM2_PARAM_PREAMBLE = 1003, - PRISM2_PARAM_SHORT_SLOT_TIME = 1006, - PRISM2_PARAM_NEXT_MODE = 1008, - PRISM2_PARAM_WIFI_WME_NOACK_TEST = 1033, - PRISM2_PARAM_SCAN_FLAGS = 1035, - PRISM2_PARAM_HW_MODES = 1036, - PRISM2_PARAM_CREATE_IBSS = 1037, - PRISM2_PARAM_WMM_ENABLED = 1038, - PRISM2_PARAM_MIXED_CELL = 1039, -}; - -/* Data structures used for get_hw_features ioctl */ -struct hostapd_ioctl_hw_modes_hdr { - int mode; - int num_channels; - int num_rates; -}; - -struct ieee80211_channel_data { - short chan; /* channel number (IEEE 802.11) */ - short freq; /* frequency in MHz */ - int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */ -}; - -struct ieee80211_rate_data { - int rate; /* rate in 100 kbps */ - int flags; /* IEEE80211_RATE_ flags */ -}; - -#endif /* HOSTAPD_IOCTL_H */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 38e0a467fa8e..d2f8c8e57ac4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -449,11 +449,6 @@ struct ieee80211_local { struct rate_control_ref *rate_ctrl; - int next_mode; /* MODE_IEEE80211* - * The mode preference for next channel change. This is - * used to select .11g vs. .11b channels (or 4.9 GHz vs. - * .11a) when the channel number is not unique. */ - /* Supported and basic rate filters for different modes. These are * pointers to -1 terminated lists and rates in 100 kbps units. */ int *supp_rates[NUM_IEEE80211_MODES]; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 99023d0d7edc..3c324c3bcd9c 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -21,46 +21,11 @@ #include #include "ieee80211_i.h" -#include "hostapd_ioctl.h" #include "ieee80211_rate.h" #include "wpa.h" #include "aes_ccm.h" -/* - * Wow. This ioctl interface is such crap, it's tied - * to internal definitions. I hope it dies soon. - */ -static int mode_to_hostapd_mode(enum ieee80211_phymode mode) -{ - switch (mode) { - case MODE_IEEE80211A: - return 0; - case MODE_IEEE80211B: - return 1; - case MODE_IEEE80211G: - return 3; - case NUM_IEEE80211_MODES: - WARN_ON(1); - break; - } - WARN_ON(1); - return -1; -} - -static enum ieee80211_phymode hostapd_mode_to_mode(int hostapd_mode) -{ - switch (hostapd_mode) { - case 0: - return MODE_IEEE80211A; - case 1: - return MODE_IEEE80211B; - case 3: - return MODE_IEEE80211G; - } - return NUM_IEEE80211_MODES; -} - static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, int idx, int alg, int set_tx_key, const u8 *_key, size_t key_len) @@ -347,11 +312,6 @@ int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq) struct ieee80211_channel *chan = &mode->channels[c]; if (chan->flag & IEEE80211_CHAN_W_SCAN && ((chan->chan == channel) || (chan->freq == freq))) { - /* Use next_mode as the mode preference to - * resolve non-unique channel numbers. */ - if (set && mode->mode != local->next_mode) - continue; - local->oper_channel = chan; local->oper_hw_mode = mode; set++; @@ -844,220 +804,6 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev, return 0; } -static int ieee80211_ioctl_prism2_param(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - int *i = (int *) extra; - int param = *i; - int value = *(i + 1); - int ret = 0; - int mode; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (param) { - case PRISM2_PARAM_IEEE_802_1X: - if (local->ops->set_ieee8021x) - ret = local->ops->set_ieee8021x(local_to_hw(local), - value); - if (ret) - printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) " - "for low-level driver\n", dev->name, value); - else - sdata->ieee802_1x = value; - break; - - case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: - if (sdata->type == IEEE80211_IF_TYPE_AP) { - if (value) - sdata->flags |= IEEE80211_SDATA_USE_PROTECTION; - else - sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION; - ieee80211_erp_info_change_notify(dev, - IEEE80211_ERP_CHANGE_PROTECTION); - } else { - ret = -ENOENT; - } - break; - - case PRISM2_PARAM_PREAMBLE: - if (sdata->type == IEEE80211_IF_TYPE_AP) { - if (value) - sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE; - else - sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE; - ieee80211_erp_info_change_notify(dev, - IEEE80211_ERP_CHANGE_PREAMBLE); - } else { - ret = -ENOENT; - } - break; - - case PRISM2_PARAM_SHORT_SLOT_TIME: - if (value) - local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME; - else - local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME; - if (ieee80211_hw_config(local)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_NEXT_MODE: - local->next_mode = hostapd_mode_to_mode(value); - break; - - case PRISM2_PARAM_WIFI_WME_NOACK_TEST: - local->wifi_wme_noack_test = value; - break; - - case PRISM2_PARAM_SCAN_FLAGS: - local->scan_flags = value; - break; - - case PRISM2_PARAM_MIXED_CELL: - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else { - if (value) - sdata->u.sta.flags |= IEEE80211_STA_MIXED_CELL; - else - sdata->u.sta.flags &= ~IEEE80211_STA_MIXED_CELL; - } - break; - - case PRISM2_PARAM_HW_MODES: - mode = 1; - local->enabled_modes = 0; - while (value) { - if (value & 1) - local->enabled_modes |= - hostapd_mode_to_mode(mode); - mode <<= 1; - value >>= 1; - } - break; - - case PRISM2_PARAM_CREATE_IBSS: - if (sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else { - if (value) - sdata->u.sta.flags |= IEEE80211_STA_CREATE_IBSS; - else - sdata->u.sta.flags &= ~IEEE80211_STA_CREATE_IBSS; - } - break; - case PRISM2_PARAM_WMM_ENABLED: - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else { - if (value) - sdata->u.sta.flags |= IEEE80211_STA_WMM_ENABLED; - else - sdata->u.sta.flags &= ~IEEE80211_STA_WMM_ENABLED; - } - break; - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - - -static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - int *param = (int *) extra; - int ret = 0; - int mode; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (*param) { - case PRISM2_PARAM_IEEE_802_1X: - *param = sdata->ieee802_1x; - break; - - case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: - *param = !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION); - break; - - case PRISM2_PARAM_PREAMBLE: - *param = !!(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE); - break; - - case PRISM2_PARAM_SHORT_SLOT_TIME: - *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME); - break; - - case PRISM2_PARAM_NEXT_MODE: - *param = local->next_mode; - break; - - case PRISM2_PARAM_WIFI_WME_NOACK_TEST: - *param = local->wifi_wme_noack_test; - break; - - case PRISM2_PARAM_SCAN_FLAGS: - *param = local->scan_flags; - break; - - case PRISM2_PARAM_HW_MODES: - mode = 0; - *param = 0; - while (mode < NUM_IEEE80211_MODES) { - if (local->enabled_modes & (1<type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - *param = !!(sdata->u.sta.flags & - IEEE80211_STA_CREATE_IBSS); - break; - - case PRISM2_PARAM_MIXED_CELL: - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - *param = !!(sdata->u.sta.flags & - IEEE80211_STA_MIXED_CELL); - break; - - case PRISM2_PARAM_WMM_ENABLED: - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - *param = !!(sdata->u.sta.flags & - IEEE80211_STA_WMM_ENABLED); - break; - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - static int ieee80211_ioctl_siwmlme(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) @@ -1313,14 +1059,6 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, } -static const struct iw_priv_args ieee80211_ioctl_priv[] = { - { PRISM2_IOCTL_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" }, - { PRISM2_IOCTL_GET_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" }, -}; - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -1383,19 +1121,9 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* -- hole -- */ }; -static const iw_handler ieee80211_private_handler[] = -{ /* SIOCIWFIRSTPRIV + */ - (iw_handler) ieee80211_ioctl_prism2_param, /* 0 */ - (iw_handler) ieee80211_ioctl_get_prism2_param, /* 1 */ -}; - const struct iw_handler_def ieee80211_iw_handler_def = { .num_standard = ARRAY_SIZE(ieee80211_handler), - .num_private = ARRAY_SIZE(ieee80211_private_handler), - .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv), .standard = (iw_handler *) ieee80211_handler, - .private = (iw_handler *) ieee80211_private_handler, - .private_args = (struct iw_priv_args *) ieee80211_ioctl_priv, .get_wireless_stats = ieee80211_get_wireless_stats, }; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 651aaba1add4..cf50a7bfb970 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -31,7 +31,6 @@ #include #include "ieee80211_i.h" #include "ieee80211_rate.h" -#include "hostapd_ioctl.h" #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_MAX_TRIES 3 From b4010e08907bdafe8bf4a3fe7ef9b52ddec4dda5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 15:19:50 +0200 Subject: [PATCH 1580/2804] [PATCH] mac80211: remove generic IE for AP interfaces This is not useful since we do not support probe response offload to hardware at this time and beacons are set in another way. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 7 ------- net/mac80211/ieee80211.c | 4 ---- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/ieee80211_iface.c | 1 - net/mac80211/ieee80211_ioctl.c | 9 --------- 5 files changed, 23 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8fb975f0bed4..6ec12bd3a3ec 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -519,11 +519,6 @@ struct ieee80211_if_init_conf { * config_interface() call, so copy the value somewhere if you need * it. * @ssid_len: length of the @ssid field. - * @generic_elem: used (together with @generic_elem_len) by drivers for - * hardware that generate beacons independently. The pointer is valid - * only during the config_interface() call, so copy the value somewhere - * if you need it. - * @generic_elem_len: length of the generic element. * @beacon: beacon template. Valid only if @host_gen_beacon_template in * &struct ieee80211_hw is set. The driver is responsible of freeing * the sk_buff. @@ -538,8 +533,6 @@ struct ieee80211_if_conf { u8 *bssid; u8 *ssid; size_t ssid_len; - u8 *generic_elem; - size_t generic_elem_len; struct sk_buff *beacon; struct ieee80211_tx_control *beacon_control; }; diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 2501bff0d15e..210319f9ea2f 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -615,13 +615,9 @@ static int __ieee80211_if_config(struct net_device *dev, conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; - conf.generic_elem = sdata->u.sta.extra_ie; - conf.generic_elem_len = sdata->u.sta.extra_ie_len; } else if (sdata->type == IEEE80211_IF_TYPE_AP) { conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; - conf.generic_elem = sdata->u.ap.generic_elem; - conf.generic_elem_len = sdata->u.ap.generic_elem_len; conf.beacon = beacon; conf.beacon_control = control; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d2f8c8e57ac4..0c9548a0a4ec 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -197,8 +197,6 @@ struct ieee80211_if_ap { u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; - u8 *generic_elem; - size_t generic_elem_len; /* yes, this looks ugly, but guarantees that we can later use * bitmap_empty :) diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 60cee6e602d2..08c1e188d4b8 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -269,7 +269,6 @@ void ieee80211_if_reinit(struct net_device *dev) kfree(sdata->u.ap.beacon_head); kfree(sdata->u.ap.beacon_tail); - kfree(sdata->u.ap.generic_elem); while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { local->total_ps_buffered--; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 3c324c3bcd9c..48e68434b38a 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -120,15 +120,6 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, return 0; } - if (sdata->type == IEEE80211_IF_TYPE_AP) { - kfree(sdata->u.ap.generic_elem); - sdata->u.ap.generic_elem = kmalloc(data->length, GFP_KERNEL); - if (!sdata->u.ap.generic_elem) - return -ENOMEM; - memcpy(sdata->u.ap.generic_elem, extra, data->length); - sdata->u.ap.generic_elem_len = data->length; - return ieee80211_if_config(dev); - } return -EOPNOTSUPP; } From 30ccb08847c2d89e1cf893bf5f3155c023a9d142 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 26 Sep 2007 21:08:47 +0200 Subject: [PATCH 1581/2804] [PATCH] mac80211: bss_tim_clear must use ~ instead of ! We need to use bitwise NOT. This also cleans up the code a little bit to make it more readable. Signed-off-by: Michael Buesch Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0c9548a0a4ec..9e3c365e3f03 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -642,34 +642,34 @@ struct sta_attribute { ssize_t (*store)(struct sta_info *, const char *buf, size_t count); }; -static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid) +static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) { /* - * This format has ben mandated by the IEEE specifications, + * This format has been mandated by the IEEE specifications, * so this line may not be changed to use the __set_bit() format. */ - bss->tim[(aid)/8] |= 1<<((aid) % 8); + bss->tim[aid / 8] |= (1 << (aid % 8)); } static inline void bss_tim_set(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, int aid) + struct ieee80211_if_ap *bss, u16 aid) { read_lock_bh(&local->sta_lock); __bss_tim_set(bss, aid); read_unlock_bh(&local->sta_lock); } -static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid) +static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) { /* - * This format has ben mandated by the IEEE specifications, + * This format has been mandated by the IEEE specifications, * so this line may not be changed to use the __clear_bit() format. */ - bss->tim[(aid)/8] &= !(1<<((aid) % 8)); + bss->tim[aid / 8] &= ~(1 << (aid % 8)); } static inline void bss_tim_clear(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, int aid) + struct ieee80211_if_ap *bss, u16 aid) { read_lock_bh(&local->sta_lock); __bss_tim_clear(bss, aid); From 279632be3f546f4d88bdb086fa71479bcde9d641 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 27 Sep 2007 14:42:42 +0200 Subject: [PATCH 1582/2804] [PATCH] rfkill: Fix documentation typos Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- include/linux/rfkill.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index f9a50dab4168..8909682415dc 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -29,9 +29,9 @@ /** * enum rfkill_type - type of rfkill switch. - * RFKILL_TYPE_WLAN: switch is no a Wireless network devices. - * RFKILL_TYPE_BlUETOOTH: switch is on a bluetooth device. - * RFKILL_TYPE_UWB: switch is on a Ultra wideband device. + * RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. + * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. + * RFKILL_TYPE_UWB: switch is on a ultra wideband device. */ enum rfkill_type { RFKILL_TYPE_WLAN , From 583fab37da52199a8b1ea30d9c39dc95f1ead24f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:30 +0800 Subject: [PATCH 1583/2804] [PATCH] iwlwifi: replacing IPW with IWL in error messages This patch repaces IPW with IWL in error messages. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0700076e55b2..2077f26e3e85 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -204,7 +204,7 @@ static void iwl_print_hex_dump(int level, void *p, u32 len) * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * The IPW operates with six queues, one receive queue in the device's + * The IWL operates with six queues, one receive queue in the device's * sram, one transmit queue for sending commands to the device firmware, * and four transmit queues for data. ***************************************************/ @@ -4591,12 +4591,12 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv) /* bail out if nothing in log */ if (size == 0) { - IWL_ERROR("Start IPW Event Log Dump: nothing in log\n"); + IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); iwl_release_restricted_access(priv); return; } - IWL_ERROR("Start IPW Event Log Dump: display count %d, wraps %d\n", + IWL_ERROR("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, diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 7bc25f74e3ab..d0ec1a0807e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -203,7 +203,7 @@ static void iwl_print_hex_dump(int level, void *p, u32 len) * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * The IPW operates with six queues, one receive queue in the device's + * The IWL operates with six queues, one receive queue in the device's * sram, one transmit queue for sending commands to the device firmware, * and four transmit queues for data. ***************************************************/ @@ -4900,12 +4900,12 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv) /* bail out if nothing in log */ if (size == 0) { - IWL_ERROR("Start IPW Event Log Dump: nothing in log\n"); + IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); iwl_release_restricted_access(priv); return; } - IWL_ERROR("Start IPW Event Log Dump: display count %d, wraps %d\n", + IWL_ERROR("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, From cfe01709871cccf711c70a970bfc1a8d7bd13f84 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:31 +0800 Subject: [PATCH 1584/2804] [PATCH] iwlwifi: workaournd REPLY_COMPRESSED_BA command in iwl_rx_handle Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index d0ec1a0807e7..db4d82785a65 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4613,6 +4613,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && (pkt->hdr.cmd != REPLY_4965_RX) && + (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); From e1493deb74d22b005769e6ecbd24a00106941c6c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:32 +0800 Subject: [PATCH 1585/2804] [PATCH] iwlwifi: Correction for sending beacon in config_ap This patch takes out sending beacon from conditional in config_ap function. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index db4d82785a65..fac130d0e9e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7493,9 +7493,8 @@ static void iwl_config_ap(struct iwl_priv *priv) iwl_activate_qos(priv, 1); #endif iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); - iwl_send_beacon_cmd(priv); - } else - iwl_send_beacon_cmd(priv); + } + iwl_send_beacon_cmd(priv); /* FIXME - we need to add code here to detect a totally new * configuration, reset the AP, unassoc, rxon timing, assoc, From 556f8db74809a435195c840f495fd1bf855dfadb Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:33 +0800 Subject: [PATCH 1586/2804] [PATCH] iwlwifi: clear station table in rxon unconditionally This patch clears stations table for every rxon command. It removes iwl_rxon_add_station function in 3945. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 55 ++++++--------------- drivers/net/wireless/iwlwifi/iwl4965-base.c | 24 +++------ 2 files changed, 21 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2077f26e3e85..dacf55ba0b7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -407,6 +407,7 @@ const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; */ /**************************************************************/ +#if 0 /* temparary disable till we add real remove station */ static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { int index = IWL_INVALID_STATION; @@ -442,7 +443,7 @@ out: spin_unlock_irqrestore(&priv->sta_lock, flags); return 0; } - +#endif static void iwl_clear_stations_table(struct iwl_priv *priv) { unsigned long flags; @@ -834,25 +835,6 @@ int iwl_send_statistics_request(struct iwl_priv *priv) return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); } -/** - * iwl_rxon_add_station - add station into station table. - * - * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling the this fnction -*/ -static int iwl_rxon_add_station(struct iwl_priv *priv, - const u8 *addr, int is_ap) -{ - u8 rc; - - /* Remove this station if it happens to already exist */ - iwl_remove_station(priv, addr, is_ap); - - rc = iwl_add_station(priv, addr, is_ap, 0); - - return rc; -} - /** * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz @@ -1123,16 +1105,6 @@ static int iwl_commit_rxon(struct iwl_priv *priv) "configuration (%d).\n", rc); return rc; } - - /* The RXON bit toggling will have cleared out the - * station table in the uCode, so blank it in the driver - * as well */ - iwl_clear_stations_table(priv); - } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { - /* When switching from non-associated to associated, the - * uCode clears out the station table; so clear it in the - * driver as well */ - iwl_clear_stations_table(priv); } IWL_DEBUG_INFO("Sending RXON\n" @@ -1154,6 +1126,8 @@ static int iwl_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + iwl_clear_stations_table(priv); + /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ rc = iwl_hw_reg_send_txpower(priv); @@ -1163,7 +1137,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == + if (iwl_add_station(priv, BROADCAST_ADDR, 0, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -1173,7 +1147,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) * add the IWL_AP_ID to the station rate table */ if (iwl_is_associated(priv) && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) - if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + if (iwl_add_station(priv, priv->active_rxon.bssid_addr, 1, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); return -EIO; @@ -4658,7 +4632,7 @@ static void iwl_error_recovery(struct iwl_priv *priv) priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl_commit_rxon(priv); - iwl_rxon_add_station(priv, priv->bssid, 1); + iwl_add_station(priv, priv->bssid, 1, 0); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); @@ -6804,8 +6778,8 @@ static void iwl_bg_post_associate(struct work_struct *data) /* clear out the station table */ iwl_clear_stations_table(priv); - iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); - iwl_rxon_add_station(priv, priv->bssid, 0); + iwl_add_station(priv, BROADCAST_ADDR, 0, 0); + iwl_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->phymode == MODE_IEEE80211A)? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, @@ -7092,10 +7066,9 @@ static void iwl_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwl_commit_rxon(priv); - iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); - iwl_send_beacon_cmd(priv); - } else - iwl_send_beacon_cmd(priv); + iwl_add_station(priv, BROADCAST_ADDR, 0, 0); + } + iwl_send_beacon_cmd(priv); /* FIXME - we need to add code here to detect a totally new * configuration, reset the AP, unassoc, rxon timing, assoc, @@ -7186,8 +7159,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, RXON_FILTER_ASSOC_MSK; rc = iwl_commit_rxon(priv); if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) - iwl_rxon_add_station( - priv, priv->active_rxon.bssid_addr, 1); + iwl_add_station(priv, + priv->active_rxon.bssid_addr, 1, 0); } } else { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index fac130d0e9e5..c663288a675e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -407,6 +407,7 @@ const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /**************************************************************/ +#if 0 /* temparary disable till we add real remove station */ static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { int index = IWL_INVALID_STATION; @@ -442,6 +443,7 @@ out: spin_unlock_irqrestore(&priv->sta_lock, flags); return 0; } +#endif static void iwl_clear_stations_table(struct iwl_priv *priv) { @@ -852,16 +854,12 @@ int iwl_send_statistics_request(struct iwl_priv *priv) static int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { - u8 rc; - - /* Remove this station if it happens to already exist */ - iwl_remove_station(priv, addr, is_ap); - - rc = iwl_add_station(priv, addr, is_ap, 0); + u8 sta_id; + sta_id = iwl_add_station(priv, addr, is_ap, 0); iwl4965_add_station(priv, addr, is_ap); - return rc; + return sta_id; } /** @@ -1149,16 +1147,6 @@ static int iwl_commit_rxon(struct iwl_priv *priv) "configuration (%d).\n", rc); return rc; } - - /* The RXON bit toggling will have cleared out the - * station table in the uCode, so blank it in the driver - * as well */ - iwl_clear_stations_table(priv); - } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { - /* When switching from non-associated to associated, the - * uCode clears out the station table; so clear it in the - * driver as well */ - iwl_clear_stations_table(priv); } IWL_DEBUG_INFO("Sending RXON\n" @@ -1178,6 +1166,8 @@ static int iwl_commit_rxon(struct iwl_priv *priv) return rc; } + iwl_clear_stations_table(priv); + #ifdef CONFIG_IWLWIFI_SENSITIVITY if (!priv->error_recovering) priv->start_calib = 0; From 46640a8ccebee34bd16b1af672feaa7dc320f3f6 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:34 +0800 Subject: [PATCH 1587/2804] [PATCH] iwlwifi: Fix typo in rate sacling algorithm This patch fixes tiny typo in 4965 rate sacling algorithm Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index bc5e67b0b0e2..edcc542c3b34 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1672,7 +1672,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, tbl->antenna_type = ANT_AUX; rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx); if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type)) - rs_toggle_antenna(&mcs_rate, tbl), + rs_toggle_antenna(&mcs_rate, tbl); rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; From c14c521e440a6a83835a2879a4c5f4311b1df68f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:35 +0800 Subject: [PATCH 1588/2804] [PATCH] iwlwifi: fix add_station to avoid FW error There were a few Firmware errors reported the most reproducible http://bughost.org/bugzilla/show_bug.cgi?id=1471 The root cause is rate_n_flags isn't set anymore. This patch fixes the problem. Signed-off-by: Ian Schram Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index dacf55ba0b7b..d153ca5f9573 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -464,6 +464,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) struct iwl_station_entry *station; unsigned long flags_spin; DECLARE_MAC_BUF(mac); + u8 rate; spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -507,6 +508,15 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) station->sta.sta.sta_id = index; station->sta.station_flags = 0; + rate = (priv->phymode == MODE_IEEE80211A) ? IWL_RATE_6M_PLCP : + IWL_RATE_1M_PLCP | priv->hw_setting.cck_flag; + + /* Turn on both antennas for the station... */ + station->sta.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); + station->current_rate.rate_n_flags = + le16_to_cpu(station->sta.rate_n_flags); + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); iwl_send_add_station(priv, &station->sta, flags); return index; From 63fddb9f7f65b41277043344ae0d24dbbb451ada Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:36 +0800 Subject: [PATCH 1589/2804] [PATCH] iwlwifi: removing unnecessary memset in 4965 rate scale This patch removes redundant memset in rate scale. In rs_alloc_sta, kzalloc is used so the memset can be avoided. In rs_rate_init, it is a bug fix since it overrides everything set in other handlers namely add_debugfs. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index edcc542c3b34..86e650dbddff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1776,10 +1776,9 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp) if (crl == NULL) return NULL; - - memset(crl, 0, sizeof(struct iwl_rate_scale_priv)); crl->lq.sta_id = 0xff; + for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&(crl->lq_info[j].win[i])); @@ -1796,9 +1795,6 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl_rate_scale_priv *crl = priv_sta; - memset(crl, 0, sizeof(struct iwl_rate_scale_priv)); - - crl->lq.sta_id = 0xff; crl->flush_timer = 0; sta->txrate = 3; for (j = 0; j < LQ_SIZE; j++) From 93dc646adb94127ca1c2e74275a85265ec57b9af Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:37 +0800 Subject: [PATCH 1590/2804] [PATCH] iwlwifi: add debugfs framework to rate scale This patch adds debugfs handler to rate scale algorithms. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 86e650dbddff..e849ab5aa80f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1999,6 +1999,23 @@ static void rs_free_sta(void *priv, void *priv_sta) } +#ifdef CONFIG_MAC80211_DEBUGFS +static void rs_add_debugfs(void *priv, void *priv_sta, + struct dentry *dir) +{ + /* struct iwl_rate_scale_priv *rs_priv = priv_sta; */ + IWL_DEBUG_RATE("%s enter\n", __FUNCTION__); + IWL_DEBUG_RATE("%s leave\n", __FUNCTION__); +} + +static void rs_remove_debugfs(void *priv, void *priv_sta) +{ + /* struct iwl_rate_scale_priv *rs_priv = priv_sta; */ + IWL_DEBUG_RATE("%s enter\n", __FUNCTION__); + IWL_DEBUG_RATE("%s leave\n", __FUNCTION__); +} +#endif + static struct rate_control_ops rs_ops = { .module = NULL, .name = RS_NAME, @@ -2010,6 +2027,10 @@ static struct rate_control_ops rs_ops = { .free = rs_free, .alloc_sta = rs_alloc_sta, .free_sta = rs_free_sta, +#ifdef CONFIG_MAC80211_DEBUGFS + .add_sta_debugfs = rs_add_debugfs, + .remove_sta_debugfs = rs_remove_debugfs, +#endif }; int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) From 5ae212c9273deb417bcc458d1dfb54ef880e5516 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:38 +0800 Subject: [PATCH 1591/2804] [PATCH] iwlwifi: add read rate scale table debugfs function This patch adds read rate scale table debugfs function for 4965 rate scaling module. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 67 ++++++++++++++++++++-- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e849ab5aa80f..e3a0ccaf71fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -121,6 +121,9 @@ struct iwl_rate_scale_priv { u16 active_rate_basic; struct iwl_link_quality_cmd lq; struct iwl_scale_tbl_info lq_info[LQ_SIZE]; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_scale_table_file; +#endif }; static void rs_rate_scale_perform(struct iwl_priv *priv, @@ -2000,19 +2003,71 @@ static void rs_free_sta(void *priv, void *priv_sta) #ifdef CONFIG_MAC80211_DEBUGFS +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int i = 0; + + struct iwl_rate_scale_priv *rs_priv = file->private_data; + + desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id); + desc += sprintf(buff+desc, "failed=%d success=%d rate=%X\n", + rs_priv->total_failed, rs_priv->total_success, + rs_priv->active_rate); + desc += sprintf(buff+desc, "general:" + "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", + rs_priv->lq.general_params.flags, + rs_priv->lq.general_params.mimo_delimiter, + rs_priv->lq.general_params.single_stream_ant_msk, + rs_priv->lq.general_params.dual_stream_ant_msk); + + desc += sprintf(buff+desc, "agg:" + "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n", + le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit), + rs_priv->lq.agg_params.agg_dis_start_th, + rs_priv->lq.agg_params.agg_frame_cnt_limit); + + desc += sprintf(buff+desc, + "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", + rs_priv->lq.general_params.start_rate_index[0], + rs_priv->lq.general_params.start_rate_index[1], + rs_priv->lq.general_params.start_rate_index[2], + rs_priv->lq.general_params.start_rate_index[3]); + + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) + desc += sprintf(buff+desc, " rate[%d] 0x%X\n", + i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags)); + + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_scale_table_ops = { + .read = rs_sta_dbgfs_scale_table_read, + .open = open_file_generic, +}; + static void rs_add_debugfs(void *priv, void *priv_sta, struct dentry *dir) { - /* struct iwl_rate_scale_priv *rs_priv = priv_sta; */ - IWL_DEBUG_RATE("%s enter\n", __FUNCTION__); - IWL_DEBUG_RATE("%s leave\n", __FUNCTION__); + struct iwl_rate_scale_priv *rs_priv = priv_sta; + rs_priv->rs_sta_dbgfs_scale_table_file = + debugfs_create_file("rate_scale_table", 0444, dir, + rs_priv, &rs_sta_dbgfs_scale_table_ops); } static void rs_remove_debugfs(void *priv, void *priv_sta) { - /* struct iwl_rate_scale_priv *rs_priv = priv_sta; */ - IWL_DEBUG_RATE("%s enter\n", __FUNCTION__); - IWL_DEBUG_RATE("%s leave\n", __FUNCTION__); + struct iwl_rate_scale_priv *rs_priv = priv_sta; + debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file); } #endif From 588263515fecd926ea82950e5b7752b8696b595c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:39 +0800 Subject: [PATCH 1592/2804] [PATCH] iwlwifi: limit printouts on hot path This patch change printouts on TX path to the net_ratelimit version. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-debug.h | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e3a0ccaf71fe..b9d7ad8b70e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -622,7 +622,7 @@ static void rs_tx_status(void *priv_rate, u16 fc = le16_to_cpu(hdr->frame_control); s32 tpt = 0; - IWL_DEBUG_RATE("get frame ack response, update rate scale window\n"); + IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) return; @@ -1717,7 +1717,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl_rate_scale_priv *lq; - IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); + IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); memset(extra, 0, sizeof(*extra)); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b704fe7fca27..b41addf2056a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -184,7 +184,7 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC("can not find STA %s total %d\n", + IWL_DEBUG_ASSOC_LIMIT("can not find STA " MAC_FMT " total %d\n", print_mac(mac, addr), priv->num_stations); out: diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index abd344c549aa..72318d78957e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -136,8 +136,11 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) #define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a) #define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a) #define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a) +#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a) #define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a) #define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) +#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \ + IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) #define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) From 02dede04f280a2ea249025414ddb4b1da1fca770 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:40 +0800 Subject: [PATCH 1593/2804] [PATCH] iwlwifi: add supp_rates to rate scale sta private data This patch adds supp_rate bit mask to rate scale sta private data structre and thus removes sta from the argument list in helper functions. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index b9d7ad8b70e5..bad746613f5b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -115,6 +115,7 @@ struct iwl_rate_scale_priv { u8 is_dup; u8 phymode; u8 ibss_sta_added; + u32 supp_rates; u16 active_rate; u16 active_siso_rate; u16 active_mimo_rate; @@ -132,8 +133,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct sta_info *sta); static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate *tx_mcs, - struct iwl_link_quality_cmd *tbl, - struct sta_info *sta); + struct iwl_link_quality_cmd *tbl); static s32 expected_tpt_A[IWL_RATE_COUNT] = { @@ -542,14 +542,13 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, struct iwl_scale_tbl_info *tbl, u8 scale_index, - u8 ht_possible, struct iwl_rate *mcs_rate, - struct sta_info *sta) + u8 ht_possible, struct iwl_rate *mcs_rate) { - u8 is_green = lq_data->is_green; s32 low; u16 rate_mask; u16 high_low; u8 switch_to_legacy = 0; + u8 is_green = lq_data->is_green; /* check if we need to switch from HT to legacy rates. * assumption is that mandatory rates (1Mbps or 6Mbps) @@ -576,9 +575,9 @@ static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, if (is_legacy(tbl->lq_type)) { if (lq_data->phymode == (u8) MODE_IEEE80211A) rate_mask = (u16)(rate_mask & - (sta->supp_rates << IWL_FIRST_OFDM_RATE)); + (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); else - rate_mask = (u16)(rate_mask & sta->supp_rates); + rate_mask = (u16)(rate_mask & lq_data->supp_rates); } /* if we did switched from HT to legacy check current rate */ @@ -1391,10 +1390,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (is_legacy(tbl->lq_type)) { if (lq_data->phymode == (u8) MODE_IEEE80211A) rate_scale_index_msk = (u16) (rate_mask & - (sta->supp_rates << IWL_FIRST_OFDM_RATE)); + (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); else rate_scale_index_msk = (u16) (rate_mask & - sta->supp_rates); + lq_data->supp_rates); } else rate_scale_index_msk = rate_mask; @@ -1434,7 +1433,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, rs_stay_in_table(lq_data); if (update_lq) { rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq, sta); + rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); } goto out; @@ -1558,7 +1557,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_update: if (update_lq) { rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq, sta); + rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); } rs_stay_in_table(lq_data); @@ -1584,7 +1583,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", tbl->current_rate.rate_n_flags, index); rs_fill_link_cmd(lq_data, &tbl->current_rate, - &(lq_data->lq), sta); + &lq_data->lq); rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); } tbl1 = &(lq_data->lq_info[lq_data->active_tbl]); @@ -1680,7 +1679,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; rs_get_expected_tpt_table(lq, tbl); - rs_fill_link_cmd(lq, &mcs_rate, &(lq->lq), sta); + rs_fill_link_cmd(lq, &mcs_rate, &lq->lq); rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC); out: return; @@ -1799,6 +1798,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, struct iwl_rate_scale_priv *crl = priv_sta; crl->flush_timer = 0; + crl->supp_rates = sta->supp_rates; sta->txrate = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) @@ -1875,8 +1875,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate *tx_mcs, - struct iwl_link_quality_cmd *lq_cmd, - struct sta_info *sta) + struct iwl_link_quality_cmd *lq_cmd) { int index = 0; int rc = 0; @@ -1934,7 +1933,7 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, lq_cmd->general_params.mimo_delimiter = index; rs_get_lower_rate(lq_data, &tbl_type, rate_idx, - use_ht_possible, &new_rate, sta); + use_ht_possible, &new_rate); if (is_legacy(tbl_type.lq_type)) { if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) From 1b696de23bb21b89f4a4c4fd6b12e26fe2cc4a37 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:41 +0800 Subject: [PATCH 1594/2804] [PATCH] iwlwifi: rs_rate_scale_perform clean up This patch cleans up rs_rate_scale_perform function. It removes dead code, shortens variable names and removes useless return i.e. function now returns void. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 27 +++++++++------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index bad746613f5b..c4b8ca128495 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -131,7 +131,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct net_device *dev, struct ieee80211_hdr *hdr, struct sta_info *sta); -static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, +static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate *tx_mcs, struct iwl_link_quality_cmd *tbl); @@ -1873,16 +1873,15 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, rs_initialize_lq(priv, sta); } -static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, +static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate *tx_mcs, struct iwl_link_quality_cmd *lq_cmd) { int index = 0; - int rc = 0; int rate_idx; + int repeat_rate = 0; u8 ant_toggle_count = 0; u8 use_ht_possible = 1; - u8 repeat_cur_rate = 0; struct iwl_rate new_rate; struct iwl_scale_tbl_info tbl_type = { 0 }; @@ -1891,9 +1890,9 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, if (is_legacy(tbl_type.lq_type)) { ant_toggle_count = 1; - repeat_cur_rate = IWL_NUMBER_TRY; + repeat_rate = IWL_NUMBER_TRY; } else - repeat_cur_rate = IWL_HT_NUMBER_TRY; + repeat_rate = IWL_HT_NUMBER_TRY; lq_cmd->general_params.mimo_delimiter = is_mimo(tbl_type.lq_type) ? 1 : 0; @@ -1907,10 +1906,10 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, lq_cmd->general_params.single_stream_ant_msk = 2; index++; - repeat_cur_rate--; + repeat_rate--; while (index < LINK_QUAL_MAX_RETRY_NUM) { - while (repeat_cur_rate && (index < LINK_QUAL_MAX_RETRY_NUM)) { + while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { if (is_legacy(tbl_type.lq_type)) { if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) @@ -1922,7 +1921,7 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, } lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate.rate_n_flags); - repeat_cur_rate--; + repeat_rate--; index++; } @@ -1942,26 +1941,22 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, rs_toggle_antenna(&new_rate, &tbl_type); ant_toggle_count = 1; } - repeat_cur_rate = IWL_NUMBER_TRY; + repeat_rate = IWL_NUMBER_TRY; } else - repeat_cur_rate = IWL_HT_NUMBER_TRY; + repeat_rate = IWL_HT_NUMBER_TRY; use_ht_possible = 0; lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate.rate_n_flags); - /* lq_cmd->rs_table[index].rate_n_flags = 0x800d; */ index++; - repeat_cur_rate--; + repeat_rate--; } - /* lq_cmd->rs_table[0].rate_n_flags = 0x800d; */ - lq_cmd->general_params.dual_stream_ant_msk = 3; lq_cmd->agg_params.agg_dis_start_th = 3; lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); - return rc; } static void *rs_alloc(struct ieee80211_local *local) From 98d7e09af513da19389128f23d49893b11de81fa Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:42 +0800 Subject: [PATCH 1595/2804] [PATCH] iwlwifi: set fixed rate through debugfs This patch adds fixed rate setting through debugfs $ echo > \ /sys/kernel/debug/ieee80211/phy/stations//rate_scale_table Currently there is no way to turn to rate scaling working again. Will be fixed in later. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 72 +++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index c4b8ca128495..e5f8cce443ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -123,7 +123,9 @@ struct iwl_rate_scale_priv { struct iwl_link_quality_cmd lq; struct iwl_scale_tbl_info lq_info[LQ_SIZE]; #ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_scale_table_file; + struct dentry *rs_sta_dbgfs_scale_table_file; + struct iwl_rate dbg_fixed; + struct iwl_priv *drv; #endif }; @@ -136,6 +138,14 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_link_quality_cmd *tbl); +#ifdef CONFIG_MAC80211_DEBUGFS +static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, + struct iwl_rate *mcs, int index); +#else +static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, + struct iwl_rate *mcs, int index) +{} +#endif static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -1866,6 +1876,9 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate, crl->active_mimo_rate); #endif /*CONFIG_IWLWIFI_HT*/ +#ifdef CONFIG_MAC80211_DEBUGFS + crl->drv = priv; +#endif if (priv->assoc_station_added) priv->lq_mngr.lq_ready = 1; @@ -1885,6 +1898,8 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate new_rate; struct iwl_scale_tbl_info tbl_type = { 0 }; + rs_dbgfs_set_mcs(lq_data, tx_mcs, index); + rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode, &tbl_type, &rate_idx); @@ -1919,6 +1934,8 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, ant_toggle_count = 1; } } + + rs_dbgfs_set_mcs(lq_data, &new_rate, index); lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate.rate_n_flags); repeat_rate--; @@ -1947,6 +1964,7 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, use_ht_possible = 0; + rs_dbgfs_set_mcs(lq_data, &new_rate, index); lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate.rate_n_flags); @@ -2002,7 +2020,54 @@ static int open_file_generic(struct inode *inode, struct file *file) file->private_data = inode->i_private; return 0; } +static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, + struct iwl_rate *mcs, int index) +{ + const u32 cck_rate = 0x820A; + if (rs_priv->dbg_fixed.rate_n_flags) { + if (index < 12) + mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags; + else + mcs->rate_n_flags = cck_rate; + IWL_DEBUG_RATE("Fixed rate ON\n"); + return; + } + IWL_DEBUG_RATE("Fixed rate OFF\n"); +} + +static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct iwl_rate_scale_priv *rs_priv = file->private_data; + char buf[64]; + int buf_size; + u32 parsed_rate; + + 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", &parsed_rate) == 1) + rs_priv->dbg_fixed.rate_n_flags = parsed_rate; + else + rs_priv->dbg_fixed.rate_n_flags = 0; + + rs_priv->active_rate = 0x0FFF; + rs_priv->active_siso_rate = 0x1FD0; + rs_priv->active_mimo_rate = 0x1FD0; + + IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", + rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags); + + if (rs_priv->dbg_fixed.rate_n_flags) { + rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq); + rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC); + } + + return count; +} static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2013,9 +2078,11 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, struct iwl_rate_scale_priv *rs_priv = file->private_data; desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id); - desc += sprintf(buff+desc, "failed=%d success=%d rate=%X\n", + desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", rs_priv->total_failed, rs_priv->total_success, rs_priv->active_rate); + desc += sprintf(buff+desc, "fixed rate 0x%X\n", + rs_priv->dbg_fixed.rate_n_flags); desc += sprintf(buff+desc, "general:" "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", rs_priv->lq.general_params.flags, @@ -2045,6 +2112,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, } static const struct file_operations rs_sta_dbgfs_scale_table_ops = { + .write = rs_sta_dbgfs_scale_table_write, .read = rs_sta_dbgfs_scale_table_read, .open = open_file_generic, }; From 0209dc11c769f51f037a17a4ea7bed43eaee998c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:43 +0800 Subject: [PATCH 1596/2804] [PATCH] iwlwifi: add debugfs rate scale stats This patch adds rates scale statistics to debugfs: $ cat /sys/kernel/debug/ieee80211/phy/stations//rate_stats_table Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 40 +++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e5f8cce443ba..287c75705c44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -124,6 +124,7 @@ struct iwl_rate_scale_priv { struct iwl_scale_tbl_info lq_info[LQ_SIZE]; #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; + struct dentry *rs_sta_dbgfs_stats_table_file; struct iwl_rate dbg_fixed; struct iwl_priv *drv; #endif @@ -2068,6 +2069,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, return count; } + static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2116,20 +2118,56 @@ static const struct file_operations rs_sta_dbgfs_scale_table_ops = { .read = rs_sta_dbgfs_scale_table_read, .open = open_file_generic, }; +static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int i, j; + + struct iwl_rate_scale_priv *rs_priv = file->private_data; + for (i = 0; i < LQ_SIZE; i++) { + desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" + "rate=0x%X\n", + rs_priv->active_tbl == i?"*":"x", + rs_priv->lq_info[i].lq_type, + rs_priv->lq_info[i].is_SGI, + rs_priv->lq_info[i].is_fat, + rs_priv->lq_info[i].is_dup, + rs_priv->lq_info[i].current_rate.rate_n_flags); + for (j = 0; j < IWL_RATE_COUNT; j++) { + desc += sprintf(buff+desc, + "counter=%d success=%d %%=%d\n", + rs_priv->lq_info[i].win[j].counter, + rs_priv->lq_info[i].win[j].success_counter, + rs_priv->lq_info[i].win[j].success_ratio); + } + } + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_stats_table_ops = { + .read = rs_sta_dbgfs_stats_table_read, + .open = open_file_generic, +}; static void rs_add_debugfs(void *priv, void *priv_sta, struct dentry *dir) { struct iwl_rate_scale_priv *rs_priv = priv_sta; rs_priv->rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", 0444, dir, + debugfs_create_file("rate_scale_table", 0600, dir, rs_priv, &rs_sta_dbgfs_scale_table_ops); + rs_priv->rs_sta_dbgfs_stats_table_file = + debugfs_create_file("rate_stats_table", 0600, dir, + rs_priv, &rs_sta_dbgfs_stats_table_ops); } static void rs_remove_debugfs(void *priv, void *priv_sta) { struct iwl_rate_scale_priv *rs_priv = priv_sta; debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file); + debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file); } #endif From 61f622532371985ec46b9684179152735a80f7e0 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:44 +0800 Subject: [PATCH 1597/2804] [PATCH] iwlwifi: Update iwlwifi version stamp to 1.1.17 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d153ca5f9573..2cd7caa69e46 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -103,7 +103,7 @@ int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; #define VS #endif -#define IWLWIFI_VERSION "0.1.15k" VD VS +#define IWLWIFI_VERSION "1.1.17k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" #define DRV_VERSION IWLWIFI_VERSION diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index c663288a675e..5a8342664af1 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -102,7 +102,7 @@ int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; #define VS #endif -#define IWLWIFI_VERSION "0.1.15k" VD VS +#define IWLWIFI_VERSION "1.1.17k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" #define DRV_VERSION IWLWIFI_VERSION From a50e2e3f3e6303e893c4c438c0692d459d7093a5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 27 Sep 2007 17:00:29 -0400 Subject: [PATCH 1598/2804] [PATCH] iwlwifi: fix imcomplete conversion to print_mac API Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b41addf2056a..b50d20267c8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -184,7 +184,7 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC_LIMIT("can not find STA " MAC_FMT " total %d\n", + IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", print_mac(mac, addr), priv->num_stations); out: From fe242cfd3390b1c7d54d60f7ebb6a4054804cd41 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 27 Sep 2007 14:57:05 -0700 Subject: [PATCH 1599/2804] [RFKILL]: Move rfkill_switch_all out of global header rfkill_switch_all shouldn't be called by drivers directly, instead they should send a signal over the input device. To prevent confusion for driver developers, move the function into a rfkill private header. Signed-off-by: Ivo van Doorn Signed-off-by: David S. Miller --- include/linux/rfkill.h | 4 +--- net/rfkill/rfkill-input.c | 2 ++ net/rfkill/rfkill-input.h | 16 ++++++++++++++++ net/rfkill/rfkill.c | 2 +- 4 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 net/rfkill/rfkill-input.h diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 8909682415dc..d76397ca95ad 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -2,7 +2,7 @@ #define __RFKILL_H /* - * Copyright (C) 2006 Ivo van Doorn + * Copyright (C) 2006 - 2007 Ivo van Doorn * Copyright (C) 2007 Dmitry Torokhov * * This program is free software; you can redistribute it and/or modify @@ -84,6 +84,4 @@ void rfkill_free(struct rfkill *rfkill); int rfkill_register(struct rfkill *rfkill); void rfkill_unregister(struct rfkill *rfkill); -void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); - #endif /* RFKILL_H */ diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c index 8e4516a5fe32..eaabf087c59b 100644 --- a/net/rfkill/rfkill-input.c +++ b/net/rfkill/rfkill-input.c @@ -17,6 +17,8 @@ #include #include +#include "rfkill-input.h" + MODULE_AUTHOR("Dmitry Torokhov "); MODULE_DESCRIPTION("Input layer to RF switch connector"); MODULE_LICENSE("GPL"); diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill-input.h new file mode 100644 index 000000000000..4dae5006fc77 --- /dev/null +++ b/net/rfkill/rfkill-input.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2007 Ivo van Doorn + */ + +/* + * 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 __RFKILL_INPUT_H +#define __RFKILL_INPUT_H + +void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); + +#endif /* __RFKILL_INPUT_H */ diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 03ed7fd8afe0..637a9f0c7655 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Ivo van Doorn + * Copyright (C) 2006 - 2007 Ivo van Doorn * Copyright (C) 2007 Dmitry Torokhov * * This program is free software; you can redistribute it and/or modify From 9e0db4b12c7deda532ad13d37a84ee41dd691066 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 27 Sep 2007 17:09:39 -0700 Subject: [PATCH 1600/2804] [NET]: Bring comments in loopback.c uptodate. A hint as to why it is safe to use per cpu variables, and note that we actually can have multiple instances of the loopback device now. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/loopback.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 2617320efa95..d6997aec45dd 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -154,6 +154,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif dev->last_rx = jiffies; + /* it's OK to use per_cpu_ptr() because BHs are off */ pcpu_lstats = netdev_priv(dev); lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); lb_stats->bytes += skb->len; @@ -221,7 +222,8 @@ static void loopback_dev_free(struct net_device *dev) } /* - * The loopback device is special. There is only one instance. + * The loopback device is special. There is only one instance + * per network namespace. */ static void loopback_setup(struct net_device *dev) { From 169e36742572934f5d846cfa5f9d76e72d505db4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 27 Sep 2007 17:10:06 -0700 Subject: [PATCH 1601/2804] [NETNS]: CLONE_NEWNET don't use the same clone flag as the pid namespace. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/linux/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index a4a141055c44..833f7dc2b8de 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -27,7 +27,7 @@ #define CLONE_NEWUTS 0x04000000 /* New utsname group? */ #define CLONE_NEWIPC 0x08000000 /* New ipcs */ #define CLONE_NEWUSER 0x10000000 /* New user namespace */ -#define CLONE_NEWNET 0x20000000 /* New network namespace */ +#define CLONE_NEWNET 0x40000000 /* New network namespace */ /* * Scheduling policies From 7c8d4cb4198d199e65a6ced8c81f71e3ac3f4cfc Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:15:45 -0700 Subject: [PATCH 1602/2804] [NETFILTER]: nfnetlink: make subsystem and callbacks const Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink.h | 10 +++++----- net/netfilter/nf_conntrack_netlink.c | 8 ++++---- net/netfilter/nfnetlink.c | 18 +++++++++--------- net/netfilter/nfnetlink_log.c | 4 ++-- net/netfilter/nfnetlink_queue.c | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 0f9311df1559..e32418bcc661 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -118,9 +118,9 @@ struct nfnl_callback struct nfnetlink_subsystem { const char *name; - __u8 subsys_id; /* nfnetlink subsystem ID */ - __u8 cb_count; /* number of callbacks */ - struct nfnl_callback *cb; /* callback for individual types */ + __u8 subsys_id; /* nfnetlink subsystem ID */ + __u8 cb_count; /* number of callbacks */ + const struct nfnl_callback *cb; /* callback for individual types */ }; extern void __nfa_fill(struct sk_buff *skb, int attrtype, @@ -129,8 +129,8 @@ extern void __nfa_fill(struct sk_buff *skb, int attrtype, ({ if (skb_tailroom(skb) < (int)NFA_SPACE(attrlen)) goto nfattr_failure; \ __nfa_fill(skb, attrtype, attrlen, data); }) -extern int nfnetlink_subsys_register(struct nfnetlink_subsystem *n); -extern int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n); +extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); +extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); extern void nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 2863e72b4091..5080045fdc74 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1548,7 +1548,7 @@ static struct notifier_block ctnl_notifier_exp = { }; #endif -static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { +static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, .attr_count = CTA_MAX, }, [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, @@ -1559,7 +1559,7 @@ static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { .attr_count = CTA_MAX, }, }; -static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { +static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, .attr_count = CTA_EXPECT_MAX, }, [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, @@ -1568,14 +1568,14 @@ static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { .attr_count = CTA_EXPECT_MAX, }, }; -static struct nfnetlink_subsystem ctnl_subsys = { +static const struct nfnetlink_subsystem ctnl_subsys = { .name = "conntrack", .subsys_id = NFNL_SUBSYS_CTNETLINK, .cb_count = IPCTNL_MSG_MAX, .cb = ctnl_cb, }; -static struct nfnetlink_subsystem ctnl_exp_subsys = { +static const struct nfnetlink_subsystem ctnl_exp_subsys = { .name = "conntrack_expect", .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, .cb_count = IPCTNL_MSG_EXP_MAX, diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 4aa56e7ff156..032224c1409f 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -41,7 +41,7 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); static char __initdata nfversion[] = "0.30"; static struct sock *nfnl = NULL; -static struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; +static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; static DEFINE_MUTEX(nfnl_mutex); static void nfnl_lock(void) @@ -66,7 +66,7 @@ static void nfnl_unlock(void) nfnl->sk_data_ready(nfnl, 0); } -int nfnetlink_subsys_register(struct nfnetlink_subsystem *n) +int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n) { nfnl_lock(); if (subsys_table[n->subsys_id]) { @@ -80,7 +80,7 @@ int nfnetlink_subsys_register(struct nfnetlink_subsystem *n) } EXPORT_SYMBOL_GPL(nfnetlink_subsys_register); -int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n) +int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n) { nfnl_lock(); subsys_table[n->subsys_id] = NULL; @@ -90,7 +90,7 @@ int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n) } EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); -static inline struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t type) +static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t type) { u_int8_t subsys_id = NFNL_SUBSYS_ID(type); @@ -100,8 +100,8 @@ static inline struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t type) return subsys_table[subsys_id]; } -static inline struct nfnl_callback * -nfnetlink_find_client(u_int16_t type, struct nfnetlink_subsystem *ss) +static inline const struct nfnl_callback * +nfnetlink_find_client(u_int16_t type, const struct nfnetlink_subsystem *ss) { u_int8_t cb_id = NFNL_MSG_TYPE(type); @@ -147,7 +147,7 @@ EXPORT_SYMBOL_GPL(nfattr_parse); * */ static int -nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys, +nfnetlink_check_attributes(const struct nfnetlink_subsystem *subsys, struct nlmsghdr *nlh, struct nfattr *cda[]) { int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); @@ -197,8 +197,8 @@ EXPORT_SYMBOL_GPL(nfnetlink_unicast); /* Process one complete nfnetlink message. */ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { - struct nfnl_callback *nc; - struct nfnetlink_subsystem *ss; + const struct nfnl_callback *nc; + const struct nfnetlink_subsystem *ss; int type, err; if (security_netlink_recv(skb, CAP_NET_ADMIN)) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 332e0f7f6f9e..c3aa8918035f 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -883,14 +883,14 @@ out: return ret; } -static struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = { +static const struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = { [NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp, .attr_count = NFULA_MAX, }, [NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config, .attr_count = NFULA_CFG_MAX, }, }; -static struct nfnetlink_subsystem nfulnl_subsys = { +static const struct nfnetlink_subsystem nfulnl_subsys = { .name = "log", .subsys_id = NFNL_SUBSYS_ULOG, .cb_count = NFULNL_MSG_MAX, diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index a813185c766d..bfcc0563bfd4 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -961,7 +961,7 @@ out_put: return ret; } -static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { +static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { [NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp, .attr_count = NFQA_MAX, }, [NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict, @@ -970,7 +970,7 @@ static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { .attr_count = NFQA_CFG_MAX, }, }; -static struct nfnetlink_subsystem nfqnl_subsys = { +static const struct nfnetlink_subsystem nfqnl_subsys = { .name = "nf_queue", .subsys_id = NFNL_SUBSYS_QUEUE, .cb_count = NFQNL_MSG_MAX, From df6fb868d6118686805c2fa566e213a8f31c8e4f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:37:03 -0700 Subject: [PATCH 1603/2804] [NETFILTER]: nfnetlink: convert to generic netlink attribute functions Get rid of the duplicated rtnetlink macros and use the generic netlink attribute functions. The old duplicated stuff is moved to a new header file that exists just for userspace. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/nfnetlink.h | 78 +--- include/linux/netfilter/nfnetlink_compat.h | 61 +++ include/net/netfilter/nf_conntrack_l3proto.h | 5 +- include/net/netfilter/nf_conntrack_l4proto.h | 10 +- include/net/netfilter/nf_nat_protocol.h | 4 +- .../netfilter/nf_conntrack_l3proto_ipv4.c | 20 +- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 30 +- net/ipv4/netfilter/nf_nat_core.c | 16 +- .../netfilter/nf_conntrack_l3proto_ipv6.c | 20 +- .../netfilter/nf_conntrack_proto_icmpv6.c | 30 +- net/netfilter/nf_conntrack_core.c | 21 +- net/netfilter/nf_conntrack_netlink.c | 393 ++++++++++-------- net/netfilter/nf_conntrack_proto_tcp.c | 63 +-- net/netfilter/nfnetlink.c | 39 +- net/netfilter/nfnetlink_log.c | 155 ++++--- net/netfilter/nfnetlink_queue.c | 113 +++-- 17 files changed, 527 insertions(+), 532 deletions(-) create mode 100644 include/linux/netfilter/nfnetlink_compat.h diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index ab57cb7d7c61..f2eaea2234ec 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -40,5 +40,6 @@ unifdef-y += nf_conntrack_common.h unifdef-y += nf_conntrack_ftp.h unifdef-y += nf_conntrack_tcp.h unifdef-y += nfnetlink.h +unifdef-y += nfnetlink_compat.h unifdef-y += x_tables.h unifdef-y += xt_physdev.h diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index e32418bcc661..47457b4c8c62 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -1,16 +1,7 @@ #ifndef _NFNETLINK_H #define _NFNETLINK_H #include - -#ifndef __KERNEL__ -/* nfnetlink groups: Up to 32 maximum - backwards compatibility for userspace */ -#define NF_NETLINK_CONNTRACK_NEW 0x00000001 -#define NF_NETLINK_CONNTRACK_UPDATE 0x00000002 -#define NF_NETLINK_CONNTRACK_DESTROY 0x00000004 -#define NF_NETLINK_CONNTRACK_EXP_NEW 0x00000008 -#define NF_NETLINK_CONNTRACK_EXP_UPDATE 0x00000010 -#define NF_NETLINK_CONNTRACK_EXP_DESTROY 0x00000020 -#endif +#include enum nfnetlink_groups { NFNLGRP_NONE, @@ -31,48 +22,6 @@ enum nfnetlink_groups { }; #define NFNLGRP_MAX (__NFNLGRP_MAX - 1) -/* Generic structure for encapsulation optional netfilter information. - * It is reminiscent of sockaddr, but with sa_family replaced - * with attribute type. - * ! This should someday be put somewhere generic as now rtnetlink and - * ! nfnetlink use the same attributes methods. - J. Schulist. - */ - -struct nfattr -{ - u_int16_t nfa_len; - u_int16_t nfa_type; /* we use 15 bits for the type, and the highest - * bit to indicate whether the payload is nested */ -}; - -/* FIXME: Apart from NFNL_NFA_NESTED shamelessly copy and pasted from - * rtnetlink.h, it's time to put this in a generic file */ - -#define NFNL_NFA_NEST 0x8000 -#define NFA_TYPE(attr) ((attr)->nfa_type & 0x7fff) - -#define NFA_ALIGNTO 4 -#define NFA_ALIGN(len) (((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1)) -#define NFA_OK(nfa,len) ((len) > 0 && (nfa)->nfa_len >= sizeof(struct nfattr) \ - && (nfa)->nfa_len <= (len)) -#define NFA_NEXT(nfa,attrlen) ((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \ - (struct nfattr *)(((char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len))) -#define NFA_LENGTH(len) (NFA_ALIGN(sizeof(struct nfattr)) + (len)) -#define NFA_SPACE(len) NFA_ALIGN(NFA_LENGTH(len)) -#define NFA_DATA(nfa) ((void *)(((char *)(nfa)) + NFA_LENGTH(0))) -#define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0)) -#define NFA_NEST(skb, type) \ -({ struct nfattr *__start = (struct nfattr *)skb_tail_pointer(skb); \ - NFA_PUT(skb, (NFNL_NFA_NEST | type), 0, NULL); \ - __start; }) -#define NFA_NEST_END(skb, start) \ -({ (start)->nfa_len = skb_tail_pointer(skb) - (unsigned char *)(start); \ - (skb)->len; }) -#define NFA_NEST_CANCEL(skb, start) \ -({ if (start) \ - skb_trim(skb, (unsigned char *) (start) - (skb)->data); \ - -1; }) - /* General form of address family dependent message. */ struct nfgenmsg { @@ -83,10 +32,6 @@ struct nfgenmsg { #define NFNETLINK_V0 0 -#define NFM_NFA(n) ((struct nfattr *)(((char *)(n)) \ - + NLMSG_ALIGN(sizeof(struct nfgenmsg)))) -#define NFM_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg)) - /* netfilter netlink message types are split in two pieces: * 8 bit subsystem, 8bit operation. */ @@ -107,12 +52,13 @@ struct nfgenmsg { #include #include +#include struct nfnl_callback { int (*call)(struct sock *nl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *cda[]); - u_int16_t attr_count; /* number of nfattr's */ + struct nlmsghdr *nlh, struct nlattr *cda[]); + u_int16_t attr_count; /* number of nlattr's */ }; struct nfnetlink_subsystem @@ -123,27 +69,15 @@ struct nfnetlink_subsystem const struct nfnl_callback *cb; /* callback for individual types */ }; -extern void __nfa_fill(struct sk_buff *skb, int attrtype, - int attrlen, const void *data); -#define NFA_PUT(skb, attrtype, attrlen, data) \ -({ if (skb_tailroom(skb) < (int)NFA_SPACE(attrlen)) goto nfattr_failure; \ - __nfa_fill(skb, attrtype, attrlen, data); }) - extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); -extern void nfattr_parse(struct nfattr *tb[], int maxattr, - struct nfattr *nfa, int len); - -#define nfattr_parse_nested(tb, max, nfa) \ - nfattr_parse((tb), (max), NFA_DATA((nfa)), NFA_PAYLOAD((nfa))) - #define nfattr_bad_size(tb, max, cta_min) \ ({ int __i, __res = 0; \ - for (__i=0; __infa_type & 0x7fff) + +#define NFA_ALIGNTO 4 +#define NFA_ALIGN(len) (((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1)) +#define NFA_OK(nfa,len) ((len) > 0 && (nfa)->nfa_len >= sizeof(struct nfattr) \ + && (nfa)->nfa_len <= (len)) +#define NFA_NEXT(nfa,attrlen) ((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \ + (struct nfattr *)(((char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len))) +#define NFA_LENGTH(len) (NFA_ALIGN(sizeof(struct nfattr)) + (len)) +#define NFA_SPACE(len) NFA_ALIGN(NFA_LENGTH(len)) +#define NFA_DATA(nfa) ((void *)(((char *)(nfa)) + NFA_LENGTH(0))) +#define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0)) +#define NFA_NEST(skb, type) \ +({ struct nfattr *__start = (struct nfattr *)skb_tail_pointer(skb); \ + NFA_PUT(skb, (NFNL_NFA_NEST | type), 0, NULL); \ + __start; }) +#define NFA_NEST_END(skb, start) \ +({ (start)->nfa_len = skb_tail_pointer(skb) - (unsigned char *)(start); \ + (skb)->len; }) +#define NFA_NEST_CANCEL(skb, start) \ +({ if (start) \ + skb_trim(skb, (unsigned char *) (start) - (skb)->data); \ + -1; }) + +#define NFM_NFA(n) ((struct nfattr *)(((char *)(n)) \ + + NLMSG_ALIGN(sizeof(struct nfgenmsg)))) +#define NFM_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg)) + +#endif /* ! __KERNEL__ */ +#endif /* _NFNETLINK_COMPAT_H */ diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index 3c58a2c4df28..c02402d5ec36 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h @@ -11,11 +11,10 @@ #ifndef _NF_CONNTRACK_L3PROTO_H #define _NF_CONNTRACK_L3PROTO_H +#include #include #include -struct nfattr; - struct nf_conntrack_l3proto { /* L3 Protocol Family number. ex) PF_INET */ @@ -67,7 +66,7 @@ struct nf_conntrack_l3proto int (*tuple_to_nfattr)(struct sk_buff *skb, const struct nf_conntrack_tuple *t); - int (*nfattr_to_tuple)(struct nfattr *tb[], + int (*nfattr_to_tuple)(struct nlattr *tb[], struct nf_conntrack_tuple *t); #ifdef CONFIG_SYSCTL diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index f46cb930414c..a43c4e484ea1 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -9,10 +9,10 @@ #ifndef _NF_CONNTRACK_L4PROTO_H #define _NF_CONNTRACK_L4PROTO_H +#include #include struct seq_file; -struct nfattr; struct nf_conntrack_l4proto { @@ -65,15 +65,15 @@ struct nf_conntrack_l4proto int pf, unsigned int hooknum); /* convert protoinfo to nfnetink attributes */ - int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa, + int (*to_nfattr)(struct sk_buff *skb, struct nlattr *nla, const struct nf_conn *ct); /* convert nfnetlink attributes to protoinfo */ - int (*from_nfattr)(struct nfattr *tb[], struct nf_conn *ct); + int (*from_nfattr)(struct nlattr *tb[], struct nf_conn *ct); int (*tuple_to_nfattr)(struct sk_buff *skb, const struct nf_conntrack_tuple *t); - int (*nfattr_to_tuple)(struct nfattr *tb[], + int (*nfattr_to_tuple)(struct nlattr *tb[], struct nf_conntrack_tuple *t); #ifdef CONFIG_SYSCTL @@ -113,7 +113,7 @@ extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto); /* Generic netlink helpers */ extern int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple); -extern int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[], +extern int nf_ct_port_nfattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t); /* Log invalid packets */ diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h index a9ec5ef61468..90a82de7e7e0 100644 --- a/include/net/netfilter/nf_nat_protocol.h +++ b/include/net/netfilter/nf_nat_protocol.h @@ -41,7 +41,7 @@ struct nf_nat_protocol int (*range_to_nfattr)(struct sk_buff *skb, const struct nf_nat_range *range); - int (*nfattr_to_range)(struct nfattr *tb[], + int (*nfattr_to_range)(struct nlattr *tb[], struct nf_nat_range *range); }; @@ -64,7 +64,7 @@ extern struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); extern int nf_nat_port_range_to_nfattr(struct sk_buff *skb, const struct nf_nat_range *range); -extern int nf_nat_port_nfattr_to_range(struct nfattr *tb[], +extern int nf_nat_port_nfattr_to_range(struct nlattr *tb[], struct nf_nat_range *range); #endif /*_NF_NAT_PROTO_H*/ diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index f813e02aab30..f8771e058b9e 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -363,32 +363,32 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) static int ipv4_tuple_to_nfattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple) { - NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), + NLA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.u3.ip); - NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), + NLA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.u3.ip); return 0; -nfattr_failure: +nla_put_failure: return -1; } -static const size_t cta_min_ip[CTA_IP_MAX] = { - [CTA_IP_V4_SRC-1] = sizeof(u_int32_t), - [CTA_IP_V4_DST-1] = sizeof(u_int32_t), +static const size_t cta_min_ip[CTA_IP_MAX+1] = { + [CTA_IP_V4_SRC] = sizeof(u_int32_t), + [CTA_IP_V4_DST] = sizeof(u_int32_t), }; -static int ipv4_nfattr_to_tuple(struct nfattr *tb[], +static int ipv4_nfattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t) { - if (!tb[CTA_IP_V4_SRC-1] || !tb[CTA_IP_V4_DST-1]) + if (!tb[CTA_IP_V4_SRC] || !tb[CTA_IP_V4_DST]) return -EINVAL; if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) return -EINVAL; - t->src.u3.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); - t->dst.u3.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]); + t->src.u3.ip = *(__be32 *)nla_data(tb[CTA_IP_V4_SRC]); + t->dst.u3.ip = *(__be32 *)nla_data(tb[CTA_IP_V4_DST]); return 0; } diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 6593fd2c5b10..714332b8869e 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -235,42 +235,42 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff, static int icmp_tuple_to_nfattr(struct sk_buff *skb, const struct nf_conntrack_tuple *t) { - NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t), + NLA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t), &t->src.u.icmp.id); - NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t), + NLA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t), &t->dst.u.icmp.type); - NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t), + NLA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t), &t->dst.u.icmp.code); return 0; -nfattr_failure: +nla_put_failure: return -1; } -static const size_t cta_min_proto[CTA_PROTO_MAX] = { - [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t), - [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t), - [CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t) +static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { + [CTA_PROTO_ICMP_TYPE] = sizeof(u_int8_t), + [CTA_PROTO_ICMP_CODE] = sizeof(u_int8_t), + [CTA_PROTO_ICMP_ID] = sizeof(u_int16_t) }; -static int icmp_nfattr_to_tuple(struct nfattr *tb[], +static int icmp_nfattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *tuple) { - if (!tb[CTA_PROTO_ICMP_TYPE-1] - || !tb[CTA_PROTO_ICMP_CODE-1] - || !tb[CTA_PROTO_ICMP_ID-1]) + if (!tb[CTA_PROTO_ICMP_TYPE] + || !tb[CTA_PROTO_ICMP_CODE] + || !tb[CTA_PROTO_ICMP_ID]) return -EINVAL; if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) return -EINVAL; tuple->dst.u.icmp.type = - *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]); + *(u_int8_t *)nla_data(tb[CTA_PROTO_ICMP_TYPE]); tuple->dst.u.icmp.code = - *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); + *(u_int8_t *)nla_data(tb[CTA_PROTO_ICMP_CODE]); tuple->src.u.icmp.id = - *(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); + *(__be16 *)nla_data(tb[CTA_PROTO_ICMP_ID]); if (tuple->dst.u.icmp.type >= sizeof(invmap) || !invmap[tuple->dst.u.icmp.type]) diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index deab27facbad..4bdbb128fe50 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -547,38 +547,38 @@ int nf_nat_port_range_to_nfattr(struct sk_buff *skb, const struct nf_nat_range *range) { - NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), + NLA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), &range->min.tcp.port); - NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), + NLA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), &range->max.tcp.port); return 0; -nfattr_failure: +nla_put_failure: return -1; } EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range); int -nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) +nf_nat_port_nfattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) { int ret = 0; /* we have to return whether we actually parsed something or not */ - if (tb[CTA_PROTONAT_PORT_MIN-1]) { + if (tb[CTA_PROTONAT_PORT_MIN]) { ret = 1; range->min.tcp.port = - *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); + *(__be16 *)nla_data(tb[CTA_PROTONAT_PORT_MIN]); } - if (!tb[CTA_PROTONAT_PORT_MAX-1]) { + if (!tb[CTA_PROTONAT_PORT_MAX]) { if (ret) range->max.tcp.port = range->min.tcp.port; } else { ret = 1; range->max.tcp.port = - *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); + *(__be16 *)nla_data(tb[CTA_PROTONAT_PORT_MAX]); } return ret; diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 3153e15e0f7c..f0ea3fb51670 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -340,33 +340,33 @@ static ctl_table nf_ct_ipv6_sysctl_table[] = { static int ipv6_tuple_to_nfattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple) { - NFA_PUT(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4, + NLA_PUT(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4, &tuple->src.u3.ip6); - NFA_PUT(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4, + NLA_PUT(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4, &tuple->dst.u3.ip6); return 0; -nfattr_failure: +nla_put_failure: return -1; } -static const size_t cta_min_ip[CTA_IP_MAX] = { - [CTA_IP_V6_SRC-1] = sizeof(u_int32_t)*4, - [CTA_IP_V6_DST-1] = sizeof(u_int32_t)*4, +static const size_t cta_min_ip[CTA_IP_MAX+1] = { + [CTA_IP_V6_SRC] = sizeof(u_int32_t)*4, + [CTA_IP_V6_DST] = sizeof(u_int32_t)*4, }; -static int ipv6_nfattr_to_tuple(struct nfattr *tb[], +static int ipv6_nfattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t) { - if (!tb[CTA_IP_V6_SRC-1] || !tb[CTA_IP_V6_DST-1]) + if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST]) return -EINVAL; if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) return -EINVAL; - memcpy(&t->src.u3.ip6, NFA_DATA(tb[CTA_IP_V6_SRC-1]), + memcpy(&t->src.u3.ip6, nla_data(tb[CTA_IP_V6_SRC]), sizeof(u_int32_t) * 4); - memcpy(&t->dst.u3.ip6, NFA_DATA(tb[CTA_IP_V6_DST-1]), + memcpy(&t->dst.u3.ip6, nla_data(tb[CTA_IP_V6_DST]), sizeof(u_int32_t) * 4); return 0; diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index ab154fb90018..c18183823faf 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -213,42 +213,42 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff, static int icmpv6_tuple_to_nfattr(struct sk_buff *skb, const struct nf_conntrack_tuple *t) { - NFA_PUT(skb, CTA_PROTO_ICMPV6_ID, sizeof(u_int16_t), + NLA_PUT(skb, CTA_PROTO_ICMPV6_ID, sizeof(u_int16_t), &t->src.u.icmp.id); - NFA_PUT(skb, CTA_PROTO_ICMPV6_TYPE, sizeof(u_int8_t), + NLA_PUT(skb, CTA_PROTO_ICMPV6_TYPE, sizeof(u_int8_t), &t->dst.u.icmp.type); - NFA_PUT(skb, CTA_PROTO_ICMPV6_CODE, sizeof(u_int8_t), + NLA_PUT(skb, CTA_PROTO_ICMPV6_CODE, sizeof(u_int8_t), &t->dst.u.icmp.code); return 0; -nfattr_failure: +nla_put_failure: return -1; } -static const size_t cta_min_proto[CTA_PROTO_MAX] = { - [CTA_PROTO_ICMPV6_TYPE-1] = sizeof(u_int8_t), - [CTA_PROTO_ICMPV6_CODE-1] = sizeof(u_int8_t), - [CTA_PROTO_ICMPV6_ID-1] = sizeof(u_int16_t) +static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { + [CTA_PROTO_ICMPV6_TYPE] = sizeof(u_int8_t), + [CTA_PROTO_ICMPV6_CODE] = sizeof(u_int8_t), + [CTA_PROTO_ICMPV6_ID] = sizeof(u_int16_t) }; -static int icmpv6_nfattr_to_tuple(struct nfattr *tb[], +static int icmpv6_nfattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *tuple) { - if (!tb[CTA_PROTO_ICMPV6_TYPE-1] - || !tb[CTA_PROTO_ICMPV6_CODE-1] - || !tb[CTA_PROTO_ICMPV6_ID-1]) + if (!tb[CTA_PROTO_ICMPV6_TYPE] + || !tb[CTA_PROTO_ICMPV6_CODE] + || !tb[CTA_PROTO_ICMPV6_ID]) return -EINVAL; if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) return -EINVAL; tuple->dst.u.icmp.type = - *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_TYPE-1]); + *(u_int8_t *)nla_data(tb[CTA_PROTO_ICMPV6_TYPE]); tuple->dst.u.icmp.code = - *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_CODE-1]); + *(u_int8_t *)nla_data(tb[CTA_PROTO_ICMPV6_CODE]); tuple->src.u.icmp.id = - *(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMPV6_ID-1]); + *(__be16 *)nla_data(tb[CTA_PROTO_ICMPV6_ID]); if (tuple->dst.u.icmp.type < 128 || tuple->dst.u.icmp.type - 128 >= sizeof(invmap) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 0fe11889ce14..b64656abc4e0 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -827,40 +827,39 @@ EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); #include #include - /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be * in ip_conntrack_core, since we don't want the protocols to autoload * or depend on ctnetlink */ int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple) { - NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t), + NLA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t), &tuple->src.u.tcp.port); - NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t), + NLA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t), &tuple->dst.u.tcp.port); return 0; -nfattr_failure: +nla_put_failure: return -1; } EXPORT_SYMBOL_GPL(nf_ct_port_tuple_to_nfattr); -static const size_t cta_min_proto[CTA_PROTO_MAX] = { - [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t), - [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t) +static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { + [CTA_PROTO_SRC_PORT] = sizeof(u_int16_t), + [CTA_PROTO_DST_PORT] = sizeof(u_int16_t) }; -int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[], +int nf_ct_port_nfattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t) { - if (!tb[CTA_PROTO_SRC_PORT-1] || !tb[CTA_PROTO_DST_PORT-1]) + if (!tb[CTA_PROTO_SRC_PORT] || !tb[CTA_PROTO_DST_PORT]) return -EINVAL; if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) return -EINVAL; - t->src.u.tcp.port = *(__be16 *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]); - t->dst.u.tcp.port = *(__be16 *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]); + t->src.u.tcp.port = *(__be16 *)nla_data(tb[CTA_PROTO_SRC_PORT]); + t->dst.u.tcp.port = *(__be16 *)nla_data(tb[CTA_PROTO_DST_PORT]); return 0; } diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 5080045fdc74..221c38f889bf 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -54,18 +54,21 @@ ctnetlink_dump_tuples_proto(struct sk_buff *skb, struct nf_conntrack_l4proto *l4proto) { int ret = 0; - struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); + struct nlattr *nest_parms; - NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); + nest_parms = nla_nest_start(skb, CTA_TUPLE_PROTO | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + NLA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); if (likely(l4proto->tuple_to_nfattr)) ret = l4proto->tuple_to_nfattr(skb, tuple); - NFA_NEST_END(skb, nest_parms); + nla_nest_end(skb, nest_parms); return ret; -nfattr_failure: +nla_put_failure: return -1; } @@ -75,16 +78,20 @@ ctnetlink_dump_tuples_ip(struct sk_buff *skb, struct nf_conntrack_l3proto *l3proto) { int ret = 0; - struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); + struct nlattr *nest_parms; + + nest_parms = nla_nest_start(skb, CTA_TUPLE_IP | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; if (likely(l3proto->tuple_to_nfattr)) ret = l3proto->tuple_to_nfattr(skb, tuple); - NFA_NEST_END(skb, nest_parms); + nla_nest_end(skb, nest_parms); return ret; -nfattr_failure: +nla_put_failure: return -1; } @@ -114,10 +121,10 @@ static inline int ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct) { __be32 status = htonl((u_int32_t) ct->status); - NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); + NLA_PUT(skb, CTA_STATUS, sizeof(status), &status); return 0; -nfattr_failure: +nla_put_failure: return -1; } @@ -132,10 +139,10 @@ ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct) else timeout = htonl(timeout_l / HZ); - NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); + NLA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); return 0; -nfattr_failure: +nla_put_failure: return -1; } @@ -143,7 +150,7 @@ static inline int ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) { struct nf_conntrack_l4proto *l4proto = nf_ct_l4proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); - struct nfattr *nest_proto; + struct nlattr *nest_proto; int ret; if (!l4proto->to_nfattr) { @@ -151,17 +158,19 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) return 0; } - nest_proto = NFA_NEST(skb, CTA_PROTOINFO); + nest_proto = nla_nest_start(skb, CTA_PROTOINFO | NLA_F_NESTED); + if (!nest_proto) + goto nla_put_failure; ret = l4proto->to_nfattr(skb, nest_proto, ct); nf_ct_l4proto_put(l4proto); - NFA_NEST_END(skb, nest_proto); + nla_nest_end(skb, nest_proto); return ret; -nfattr_failure: +nla_put_failure: nf_ct_l4proto_put(l4proto); return -1; } @@ -169,7 +178,7 @@ nfattr_failure: static inline int ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) { - struct nfattr *nest_helper; + struct nlattr *nest_helper; const struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_helper *helper; @@ -181,18 +190,20 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) if (!helper) goto out; - nest_helper = NFA_NEST(skb, CTA_HELP); - NFA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name); + nest_helper = nla_nest_start(skb, CTA_HELP | NLA_F_NESTED); + if (!nest_helper) + goto nla_put_failure; + NLA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name); if (helper->to_nfattr) helper->to_nfattr(skb, ct); - NFA_NEST_END(skb, nest_helper); + nla_nest_end(skb, nest_helper); out: rcu_read_unlock(); return 0; -nfattr_failure: +nla_put_failure: rcu_read_unlock(); return -1; } @@ -203,20 +214,24 @@ ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct, enum ip_conntrack_dir dir) { enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; - struct nfattr *nest_count = NFA_NEST(skb, type); + struct nlattr *nest_count; __be32 tmp; + nest_count = nla_nest_start(skb, type | NLA_F_NESTED); + if (!nest_count) + goto nla_put_failure; + tmp = htonl(ct->counters[dir].packets); - NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp); + NLA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp); tmp = htonl(ct->counters[dir].bytes); - NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp); + NLA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp); - NFA_NEST_END(skb, nest_count); + nla_nest_end(skb, nest_count); return 0; -nfattr_failure: +nla_put_failure: return -1; } #else @@ -229,10 +244,10 @@ ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct) { __be32 mark = htonl(ct->mark); - NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark); + NLA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark); return 0; -nfattr_failure: +nla_put_failure: return -1; } #else @@ -243,10 +258,10 @@ static inline int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) { __be32 id = htonl(ct->id); - NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); + NLA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); return 0; -nfattr_failure: +nla_put_failure: return -1; } @@ -255,10 +270,10 @@ ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct) { __be32 use = htonl(atomic_read(&ct->ct_general.use)); - NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); + NLA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); return 0; -nfattr_failure: +nla_put_failure: return -1; } @@ -271,7 +286,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - struct nfattr *nest_parms; + struct nlattr *nest_parms; unsigned char *b = skb_tail_pointer(skb); event |= NFNL_SUBSYS_CTNETLINK << 8; @@ -284,15 +299,19 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; - nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); + nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) - goto nfattr_failure; - NFA_NEST_END(skb, nest_parms); + goto nla_put_failure; + nla_nest_end(skb, nest_parms); - nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); + nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) - goto nfattr_failure; - NFA_NEST_END(skb, nest_parms); + goto nla_put_failure; + nla_nest_end(skb, nest_parms); if (ctnetlink_dump_status(skb, ct) < 0 || ctnetlink_dump_timeout(skb, ct) < 0 || @@ -303,13 +322,13 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, ctnetlink_dump_mark(skb, ct) < 0 || ctnetlink_dump_id(skb, ct) < 0 || ctnetlink_dump_use(skb, ct) < 0) - goto nfattr_failure; + goto nla_put_failure; nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: -nfattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -320,7 +339,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - struct nfattr *nest_parms; + struct nlattr *nest_parms; struct nf_conn *ct = (struct nf_conn *)ptr; struct sk_buff *skb; unsigned int type; @@ -362,45 +381,49 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; - nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); + nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) - goto nfattr_failure; - NFA_NEST_END(skb, nest_parms); + goto nla_put_failure; + nla_nest_end(skb, nest_parms); - nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); + nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) - goto nfattr_failure; - NFA_NEST_END(skb, nest_parms); + goto nla_put_failure; + nla_nest_end(skb, nest_parms); if (events & IPCT_DESTROY) { if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) - goto nfattr_failure; + goto nla_put_failure; } else { if (ctnetlink_dump_status(skb, ct) < 0) - goto nfattr_failure; + goto nla_put_failure; if (ctnetlink_dump_timeout(skb, ct) < 0) - goto nfattr_failure; + goto nla_put_failure; if (events & IPCT_PROTOINFO && ctnetlink_dump_protoinfo(skb, ct) < 0) - goto nfattr_failure; + goto nla_put_failure; if ((events & IPCT_HELPER || nfct_help(ct)) && ctnetlink_dump_helpinfo(skb, ct) < 0) - goto nfattr_failure; + goto nla_put_failure; #ifdef CONFIG_NF_CONNTRACK_MARK if ((events & IPCT_MARK || ct->mark) && ctnetlink_dump_mark(skb, ct) < 0) - goto nfattr_failure; + goto nla_put_failure; #endif if (events & IPCT_COUNTER_FILLING && (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)) - goto nfattr_failure; + goto nla_put_failure; } nlh->nlmsg_len = skb->tail - b; @@ -408,7 +431,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, return NOTIFY_DONE; nlmsg_failure: -nfattr_failure: +nla_put_failure: kfree_skb(skb); return NOTIFY_DONE; } @@ -479,13 +502,13 @@ out: } static inline int -ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) +ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple) { - struct nfattr *tb[CTA_IP_MAX]; + struct nlattr *tb[CTA_IP_MAX+1]; struct nf_conntrack_l3proto *l3proto; int ret = 0; - nfattr_parse_nested(tb, CTA_IP_MAX, attr); + nla_parse_nested(tb, CTA_IP_MAX, attr, NULL); l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); @@ -497,26 +520,26 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) return ret; } -static const size_t cta_min_proto[CTA_PROTO_MAX] = { - [CTA_PROTO_NUM-1] = sizeof(u_int8_t), +static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { + [CTA_PROTO_NUM] = sizeof(u_int8_t), }; static inline int -ctnetlink_parse_tuple_proto(struct nfattr *attr, +ctnetlink_parse_tuple_proto(struct nlattr *attr, struct nf_conntrack_tuple *tuple) { - struct nfattr *tb[CTA_PROTO_MAX]; + struct nlattr *tb[CTA_PROTO_MAX+1]; struct nf_conntrack_l4proto *l4proto; int ret = 0; - nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); + nla_parse_nested(tb, CTA_PROTO_MAX, attr, NULL); if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) return -EINVAL; - if (!tb[CTA_PROTO_NUM-1]) + if (!tb[CTA_PROTO_NUM]) return -EINVAL; - tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); + tuple->dst.protonum = *(u_int8_t *)nla_data(tb[CTA_PROTO_NUM]); l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); @@ -529,29 +552,29 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr, } static inline int -ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, +ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple, enum ctattr_tuple type, u_int8_t l3num) { - struct nfattr *tb[CTA_TUPLE_MAX]; + struct nlattr *tb[CTA_TUPLE_MAX+1]; int err; memset(tuple, 0, sizeof(*tuple)); - nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); + nla_parse_nested(tb, CTA_TUPLE_MAX, cda[type], NULL); - if (!tb[CTA_TUPLE_IP-1]) + if (!tb[CTA_TUPLE_IP]) return -EINVAL; tuple->src.l3num = l3num; - err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); + err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP], tuple); if (err < 0) return err; - if (!tb[CTA_TUPLE_PROTO-1]) + if (!tb[CTA_TUPLE_PROTO]) return -EINVAL; - err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); + err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO], tuple); if (err < 0) return err; @@ -565,19 +588,19 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, } #ifdef CONFIG_NF_NAT_NEEDED -static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { - [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), - [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), +static const size_t cta_min_protonat[CTA_PROTONAT_MAX+1] = { + [CTA_PROTONAT_PORT_MIN] = sizeof(u_int16_t), + [CTA_PROTONAT_PORT_MAX] = sizeof(u_int16_t), }; -static int nfnetlink_parse_nat_proto(struct nfattr *attr, +static int nfnetlink_parse_nat_proto(struct nlattr *attr, const struct nf_conn *ct, struct nf_nat_range *range) { - struct nfattr *tb[CTA_PROTONAT_MAX]; + struct nlattr *tb[CTA_PROTONAT_MAX+1]; struct nf_nat_protocol *npt; - nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); + nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, NULL); if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) return -EINVAL; @@ -598,40 +621,40 @@ static int nfnetlink_parse_nat_proto(struct nfattr *attr, return 0; } -static const size_t cta_min_nat[CTA_NAT_MAX] = { - [CTA_NAT_MINIP-1] = sizeof(u_int32_t), - [CTA_NAT_MAXIP-1] = sizeof(u_int32_t), +static const size_t cta_min_nat[CTA_NAT_MAX+1] = { + [CTA_NAT_MINIP] = sizeof(u_int32_t), + [CTA_NAT_MAXIP] = sizeof(u_int32_t), }; static inline int -nfnetlink_parse_nat(struct nfattr *nat, +nfnetlink_parse_nat(struct nlattr *nat, const struct nf_conn *ct, struct nf_nat_range *range) { - struct nfattr *tb[CTA_NAT_MAX]; + struct nlattr *tb[CTA_NAT_MAX+1]; int err; memset(range, 0, sizeof(*range)); - nfattr_parse_nested(tb, CTA_NAT_MAX, nat); + nla_parse_nested(tb, CTA_NAT_MAX, nat, NULL); if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) return -EINVAL; - if (tb[CTA_NAT_MINIP-1]) - range->min_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MINIP-1]); + if (tb[CTA_NAT_MINIP]) + range->min_ip = *(__be32 *)nla_data(tb[CTA_NAT_MINIP]); - if (!tb[CTA_NAT_MAXIP-1]) + if (!tb[CTA_NAT_MAXIP]) range->max_ip = range->min_ip; else - range->max_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); + range->max_ip = *(__be32 *)nla_data(tb[CTA_NAT_MAXIP]); if (range->min_ip) range->flags |= IP_NAT_RANGE_MAP_IPS; - if (!tb[CTA_NAT_PROTO-1]) + if (!tb[CTA_NAT_PROTO]) return 0; - err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); + err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range); if (err < 0) return err; @@ -640,31 +663,31 @@ nfnetlink_parse_nat(struct nfattr *nat, #endif static inline int -ctnetlink_parse_help(struct nfattr *attr, char **helper_name) +ctnetlink_parse_help(struct nlattr *attr, char **helper_name) { - struct nfattr *tb[CTA_HELP_MAX]; + struct nlattr *tb[CTA_HELP_MAX+1]; - nfattr_parse_nested(tb, CTA_HELP_MAX, attr); + nla_parse_nested(tb, CTA_HELP_MAX, attr, NULL); - if (!tb[CTA_HELP_NAME-1]) + if (!tb[CTA_HELP_NAME]) return -EINVAL; - *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); + *helper_name = nla_data(tb[CTA_HELP_NAME]); return 0; } -static const size_t cta_min[CTA_MAX] = { - [CTA_STATUS-1] = sizeof(u_int32_t), - [CTA_TIMEOUT-1] = sizeof(u_int32_t), - [CTA_MARK-1] = sizeof(u_int32_t), - [CTA_USE-1] = sizeof(u_int32_t), - [CTA_ID-1] = sizeof(u_int32_t) +static const size_t cta_min[CTA_MAX+1] = { + [CTA_STATUS] = sizeof(u_int32_t), + [CTA_TIMEOUT] = sizeof(u_int32_t), + [CTA_MARK] = sizeof(u_int32_t), + [CTA_USE] = sizeof(u_int32_t), + [CTA_ID] = sizeof(u_int32_t) }; static int ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *cda[]) + struct nlmsghdr *nlh, struct nlattr *cda[]) { struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; @@ -676,9 +699,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; - if (cda[CTA_TUPLE_ORIG-1]) + if (cda[CTA_TUPLE_ORIG]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); - else if (cda[CTA_TUPLE_REPLY-1]) + else if (cda[CTA_TUPLE_REPLY]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); else { /* Flush the whole table */ @@ -695,8 +718,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ct = nf_ct_tuplehash_to_ctrack(h); - if (cda[CTA_ID-1]) { - u_int32_t id = ntohl(*(__be32 *)NFA_DATA(cda[CTA_ID-1])); + if (cda[CTA_ID]) { + u_int32_t id = ntohl(*(__be32 *)nla_data(cda[CTA_ID])); if (ct->id != id) { nf_ct_put(ct); return -ENOENT; @@ -712,7 +735,7 @@ 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 nfattr *cda[]) + struct nlmsghdr *nlh, struct nlattr *cda[]) { struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; @@ -734,9 +757,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; - if (cda[CTA_TUPLE_ORIG-1]) + if (cda[CTA_TUPLE_ORIG]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); - else if (cda[CTA_TUPLE_REPLY-1]) + else if (cda[CTA_TUPLE_REPLY]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); else return -EINVAL; @@ -776,10 +799,10 @@ out: } static inline int -ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) +ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[]) { unsigned long d; - unsigned int status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1])); + unsigned int status = ntohl(*(__be32 *)nla_data(cda[CTA_STATUS])); d = ct->status ^ status; if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) @@ -795,14 +818,14 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) /* ASSURED bit can only be set */ return -EINVAL; - if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { + if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { #ifndef CONFIG_NF_NAT_NEEDED return -EINVAL; #else struct nf_nat_range range; - if (cda[CTA_NAT_DST-1]) { - if (nfnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, + if (cda[CTA_NAT_DST]) { + if (nfnetlink_parse_nat(cda[CTA_NAT_DST], ct, &range) < 0) return -EINVAL; if (nf_nat_initialized(ct, @@ -810,8 +833,8 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) return -EEXIST; nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); } - if (cda[CTA_NAT_SRC-1]) { - if (nfnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, + if (cda[CTA_NAT_SRC]) { + if (nfnetlink_parse_nat(cda[CTA_NAT_SRC], ct, &range) < 0) return -EINVAL; if (nf_nat_initialized(ct, @@ -831,7 +854,7 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) static inline int -ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) +ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[]) { struct nf_conntrack_helper *helper; struct nf_conn_help *help = nfct_help(ct); @@ -842,7 +865,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) if (ct->master) return -EINVAL; - err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); + err = ctnetlink_parse_help(cda[CTA_HELP], &helpname); if (err < 0) return err; @@ -879,9 +902,9 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) } static inline int -ctnetlink_change_timeout(struct nf_conn *ct, struct nfattr *cda[]) +ctnetlink_change_timeout(struct nf_conn *ct, struct nlattr *cda[]) { - u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); + u_int32_t timeout = ntohl(*(__be32 *)nla_data(cda[CTA_TIMEOUT])); if (!del_timer(&ct->timeout)) return -ETIME; @@ -893,15 +916,15 @@ ctnetlink_change_timeout(struct nf_conn *ct, struct nfattr *cda[]) } static inline int -ctnetlink_change_protoinfo(struct nf_conn *ct, struct nfattr *cda[]) +ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) { - struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1]; + struct nlattr *tb[CTA_PROTOINFO_MAX+1], *attr = cda[CTA_PROTOINFO]; struct nf_conntrack_l4proto *l4proto; u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; u_int16_t l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; int err = 0; - nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr); + nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL); l4proto = nf_ct_l4proto_find_get(l3num, npt); @@ -913,44 +936,44 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nfattr *cda[]) } static int -ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[]) +ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) { int err; - if (cda[CTA_HELP-1]) { + if (cda[CTA_HELP]) { err = ctnetlink_change_helper(ct, cda); if (err < 0) return err; } - if (cda[CTA_TIMEOUT-1]) { + if (cda[CTA_TIMEOUT]) { err = ctnetlink_change_timeout(ct, cda); if (err < 0) return err; } - if (cda[CTA_STATUS-1]) { + if (cda[CTA_STATUS]) { err = ctnetlink_change_status(ct, cda); if (err < 0) return err; } - if (cda[CTA_PROTOINFO-1]) { + if (cda[CTA_PROTOINFO]) { err = ctnetlink_change_protoinfo(ct, cda); if (err < 0) return err; } #if defined(CONFIG_NF_CONNTRACK_MARK) - if (cda[CTA_MARK-1]) - ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); + if (cda[CTA_MARK]) + ct->mark = ntohl(*(__be32 *)nla_data(cda[CTA_MARK])); #endif return 0; } static int -ctnetlink_create_conntrack(struct nfattr *cda[], +ctnetlink_create_conntrack(struct nlattr *cda[], struct nf_conntrack_tuple *otuple, struct nf_conntrack_tuple *rtuple) { @@ -963,28 +986,28 @@ ctnetlink_create_conntrack(struct nfattr *cda[], if (ct == NULL || IS_ERR(ct)) return -ENOMEM; - if (!cda[CTA_TIMEOUT-1]) + if (!cda[CTA_TIMEOUT]) goto err; - ct->timeout.expires = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); + ct->timeout.expires = ntohl(*(__be32 *)nla_data(cda[CTA_TIMEOUT])); ct->timeout.expires = jiffies + ct->timeout.expires * HZ; ct->status |= IPS_CONFIRMED; - if (cda[CTA_STATUS-1]) { + if (cda[CTA_STATUS]) { err = ctnetlink_change_status(ct, cda); if (err < 0) goto err; } - if (cda[CTA_PROTOINFO-1]) { + if (cda[CTA_PROTOINFO]) { err = ctnetlink_change_protoinfo(ct, cda); if (err < 0) goto err; } #if defined(CONFIG_NF_CONNTRACK_MARK) - if (cda[CTA_MARK-1]) - ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); + if (cda[CTA_MARK]) + ct->mark = ntohl(*(__be32 *)nla_data(cda[CTA_MARK])); #endif helper = nf_ct_helper_find_get(rtuple); @@ -1014,7 +1037,7 @@ err: static int ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *cda[]) + struct nlmsghdr *nlh, struct nlattr *cda[]) { struct nf_conntrack_tuple otuple, rtuple; struct nf_conntrack_tuple_hash *h = NULL; @@ -1025,22 +1048,22 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; - if (cda[CTA_TUPLE_ORIG-1]) { + if (cda[CTA_TUPLE_ORIG]) { err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3); if (err < 0) return err; } - if (cda[CTA_TUPLE_REPLY-1]) { + if (cda[CTA_TUPLE_REPLY]) { err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY, u3); if (err < 0) return err; } write_lock_bh(&nf_conntrack_lock); - if (cda[CTA_TUPLE_ORIG-1]) + if (cda[CTA_TUPLE_ORIG]) h = __nf_conntrack_find(&otuple, NULL); - else if (cda[CTA_TUPLE_REPLY-1]) + else if (cda[CTA_TUPLE_REPLY]) h = __nf_conntrack_find(&rtuple, NULL); if (h == NULL) { @@ -1057,7 +1080,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, err = -EEXIST; if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { /* we only allow nat config for new conntracks */ - if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { + if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { err = -EINVAL; goto out_unlock; } @@ -1079,16 +1102,18 @@ ctnetlink_exp_dump_tuple(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple, enum ctattr_expect type) { - struct nfattr *nest_parms = NFA_NEST(skb, type); + struct nlattr *nest_parms; + nest_parms = nla_nest_start(skb, type | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; if (ctnetlink_dump_tuples(skb, tuple) < 0) - goto nfattr_failure; - - NFA_NEST_END(skb, nest_parms); + goto nla_put_failure; + nla_nest_end(skb, nest_parms); return 0; -nfattr_failure: +nla_put_failure: return -1; } @@ -1101,32 +1126,34 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb, struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; struct nf_conntrack_tuple m; - struct nfattr *nest_parms; + struct nlattr *nest_parms; memset(&m, 0xFF, sizeof(m)); m.src.u.all = mask->src.u.all; memcpy(&m.src.u3, &mask->src.u3, sizeof(m.src.u3)); - nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); + nest_parms = nla_nest_start(skb, CTA_EXPECT_MASK | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto); nf_ct_l3proto_put(l3proto); if (unlikely(ret < 0)) - goto nfattr_failure; + goto nla_put_failure; l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto); nf_ct_l4proto_put(l4proto); if (unlikely(ret < 0)) - goto nfattr_failure; + goto nla_put_failure; - NFA_NEST_END(skb, nest_parms); + nla_nest_end(skb, nest_parms); return 0; -nfattr_failure: +nla_put_failure: return -1; } @@ -1139,20 +1166,20 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, __be32 id = htonl(exp->id); if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) - goto nfattr_failure; + goto nla_put_failure; if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) - goto nfattr_failure; + goto nla_put_failure; if (ctnetlink_exp_dump_tuple(skb, &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, CTA_EXPECT_MASTER) < 0) - goto nfattr_failure; + goto nla_put_failure; - NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout); - NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id); + NLA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout); + NLA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id); return 0; -nfattr_failure: +nla_put_failure: return -1; } @@ -1176,13 +1203,13 @@ ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, nfmsg->res_id = 0; if (ctnetlink_exp_dump_expect(skb, exp) < 0) - goto nfattr_failure; + goto nla_put_failure; nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: -nfattr_failure: +nla_put_failure: nlmsg_trim(skb, b); return -1; } @@ -1224,14 +1251,14 @@ static int ctnetlink_expect_event(struct notifier_block *this, nfmsg->res_id = 0; if (ctnetlink_exp_dump_expect(skb, exp) < 0) - goto nfattr_failure; + goto nla_put_failure; nlh->nlmsg_len = skb->tail - b; nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); return NOTIFY_DONE; nlmsg_failure: -nfattr_failure: +nla_put_failure: kfree_skb(skb); return NOTIFY_DONE; } @@ -1286,14 +1313,14 @@ out: return skb->len; } -static const size_t cta_min_exp[CTA_EXPECT_MAX] = { - [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t), - [CTA_EXPECT_ID-1] = sizeof(u_int32_t) +static const size_t cta_min_exp[CTA_EXPECT_MAX+1] = { + [CTA_EXPECT_TIMEOUT] = sizeof(u_int32_t), + [CTA_EXPECT_ID] = sizeof(u_int32_t) }; static int ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *cda[]) + struct nlmsghdr *nlh, struct nlattr *cda[]) { struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; @@ -1311,7 +1338,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, ctnetlink_exp_done); } - if (cda[CTA_EXPECT_MASTER-1]) + if (cda[CTA_EXPECT_MASTER]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3); else return -EINVAL; @@ -1323,8 +1350,8 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (!exp) return -ENOENT; - if (cda[CTA_EXPECT_ID-1]) { - __be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); + if (cda[CTA_EXPECT_ID]) { + __be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]); if (exp->id != ntohl(id)) { nf_ct_expect_put(exp); return -ENOENT; @@ -1355,7 +1382,7 @@ out: static int ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *cda[]) + struct nlmsghdr *nlh, struct nlattr *cda[]) { struct nf_conntrack_expect *exp; struct nf_conntrack_tuple tuple; @@ -1369,7 +1396,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; - if (cda[CTA_EXPECT_TUPLE-1]) { + if (cda[CTA_EXPECT_TUPLE]) { /* delete a single expect by tuple */ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); if (err < 0) @@ -1380,8 +1407,8 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, if (!exp) return -ENOENT; - if (cda[CTA_EXPECT_ID-1]) { - __be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); + if (cda[CTA_EXPECT_ID]) { + __be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]); if (exp->id != ntohl(id)) { nf_ct_expect_put(exp); return -ENOENT; @@ -1393,8 +1420,8 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, /* have to put what we 'get' above. * after this line usage count == 0 */ nf_ct_expect_put(exp); - } else if (cda[CTA_EXPECT_HELP_NAME-1]) { - char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]); + } else if (cda[CTA_EXPECT_HELP_NAME]) { + char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]); struct nf_conn_help *m_help; /* delete all expectations for this helper */ @@ -1436,13 +1463,13 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return 0; } static int -ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nfattr *cda[]) +ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nlattr *cda[]) { return -EOPNOTSUPP; } static int -ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) +ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3) { struct nf_conntrack_tuple tuple, mask, master_tuple; struct nf_conntrack_tuple_hash *h = NULL; @@ -1499,7 +1526,7 @@ out: static int ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *cda[]) + struct nlmsghdr *nlh, struct nlattr *cda[]) { struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; @@ -1510,9 +1537,9 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; - if (!cda[CTA_EXPECT_TUPLE-1] - || !cda[CTA_EXPECT_MASK-1] - || !cda[CTA_EXPECT_MASTER-1]) + if (!cda[CTA_EXPECT_TUPLE] + || !cda[CTA_EXPECT_MASK] + || !cda[CTA_EXPECT_MASTER]) return -EINVAL; err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index eb3fe7401466..1d167e61cc44 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1067,93 +1067,96 @@ static int tcp_new(struct nf_conn *conntrack, #include #include -static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, +static int tcp_to_nfattr(struct sk_buff *skb, struct nlattr *nla, const struct nf_conn *ct) { - struct nfattr *nest_parms; + struct nlattr *nest_parms; struct nf_ct_tcp_flags tmp = {}; read_lock_bh(&tcp_lock); - nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP); - NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), + nest_parms = nla_nest_start(skb, CTA_PROTOINFO_TCP | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + + NLA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), &ct->proto.tcp.state); - NFA_PUT(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, sizeof(u_int8_t), + NLA_PUT(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, sizeof(u_int8_t), &ct->proto.tcp.seen[0].td_scale); - NFA_PUT(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY, sizeof(u_int8_t), + NLA_PUT(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY, sizeof(u_int8_t), &ct->proto.tcp.seen[1].td_scale); tmp.flags = ct->proto.tcp.seen[0].flags; - NFA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, + NLA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, sizeof(struct nf_ct_tcp_flags), &tmp); tmp.flags = ct->proto.tcp.seen[1].flags; - NFA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY, + NLA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY, sizeof(struct nf_ct_tcp_flags), &tmp); read_unlock_bh(&tcp_lock); - NFA_NEST_END(skb, nest_parms); + nla_nest_end(skb, nest_parms); return 0; -nfattr_failure: +nla_put_failure: read_unlock_bh(&tcp_lock); return -1; } -static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = { - [CTA_PROTOINFO_TCP_STATE-1] = sizeof(u_int8_t), - [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL-1] = sizeof(u_int8_t), - [CTA_PROTOINFO_TCP_WSCALE_REPLY-1] = sizeof(u_int8_t), - [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL-1] = sizeof(struct nf_ct_tcp_flags), - [CTA_PROTOINFO_TCP_FLAGS_REPLY-1] = sizeof(struct nf_ct_tcp_flags) +static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX+1] = { + [CTA_PROTOINFO_TCP_STATE] = sizeof(u_int8_t), + [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = sizeof(u_int8_t), + [CTA_PROTOINFO_TCP_WSCALE_REPLY] = sizeof(u_int8_t), + [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = sizeof(struct nf_ct_tcp_flags), + [CTA_PROTOINFO_TCP_FLAGS_REPLY] = sizeof(struct nf_ct_tcp_flags) }; -static int nfattr_to_tcp(struct nfattr *cda[], struct nf_conn *ct) +static int nfattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) { - struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1]; - struct nfattr *tb[CTA_PROTOINFO_TCP_MAX]; + struct nlattr *attr = cda[CTA_PROTOINFO_TCP]; + struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1]; /* updates could not contain anything about the private * protocol info, in that case skip the parsing */ if (!attr) return 0; - nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr); + nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr, NULL); if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp)) return -EINVAL; - if (!tb[CTA_PROTOINFO_TCP_STATE-1]) + if (!tb[CTA_PROTOINFO_TCP_STATE]) return -EINVAL; write_lock_bh(&tcp_lock); ct->proto.tcp.state = - *(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]); + *(u_int8_t *)nla_data(tb[CTA_PROTOINFO_TCP_STATE]); - if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL-1]) { + if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) { struct nf_ct_tcp_flags *attr = - NFA_DATA(tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL-1]); + nla_data(tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]); ct->proto.tcp.seen[0].flags &= ~attr->mask; ct->proto.tcp.seen[0].flags |= attr->flags & attr->mask; } - if (tb[CTA_PROTOINFO_TCP_FLAGS_REPLY-1]) { + if (tb[CTA_PROTOINFO_TCP_FLAGS_REPLY]) { struct nf_ct_tcp_flags *attr = - NFA_DATA(tb[CTA_PROTOINFO_TCP_FLAGS_REPLY-1]); + nla_data(tb[CTA_PROTOINFO_TCP_FLAGS_REPLY]); ct->proto.tcp.seen[1].flags &= ~attr->mask; ct->proto.tcp.seen[1].flags |= attr->flags & attr->mask; } - if (tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL-1] && - tb[CTA_PROTOINFO_TCP_WSCALE_REPLY-1] && + if (tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] && + tb[CTA_PROTOINFO_TCP_WSCALE_REPLY] && ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_WINDOW_SCALE && ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_WINDOW_SCALE) { ct->proto.tcp.seen[0].td_scale = *(u_int8_t *) - NFA_DATA(tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL-1]); + nla_data(tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]); ct->proto.tcp.seen[1].td_scale = *(u_int8_t *) - NFA_DATA(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY-1]); + nla_data(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY]); } write_unlock_bh(&tcp_lock); diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 032224c1409f..3cfa76b89a20 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -111,44 +111,17 @@ nfnetlink_find_client(u_int16_t type, const struct nfnetlink_subsystem *ss) return &ss->cb[cb_id]; } -void __nfa_fill(struct sk_buff *skb, int attrtype, int attrlen, - const void *data) -{ - struct nfattr *nfa; - int size = NFA_LENGTH(attrlen); - - nfa = (struct nfattr *)skb_put(skb, NFA_ALIGN(size)); - nfa->nfa_type = attrtype; - nfa->nfa_len = size; - memcpy(NFA_DATA(nfa), data, attrlen); - memset(NFA_DATA(nfa) + attrlen, 0, NFA_ALIGN(size) - size); -} -EXPORT_SYMBOL_GPL(__nfa_fill); - -void nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len) -{ - memset(tb, 0, sizeof(struct nfattr *) * maxattr); - - while (NFA_OK(nfa, len)) { - unsigned flavor = NFA_TYPE(nfa); - if (flavor && flavor <= maxattr) - tb[flavor-1] = nfa; - nfa = NFA_NEXT(nfa, len); - } -} -EXPORT_SYMBOL_GPL(nfattr_parse); - /** * nfnetlink_check_attributes - check and parse nfnetlink attributes * * subsys: nfnl subsystem for which this message is to be parsed * nlmsghdr: netlink message to be checked/parsed - * cda: array of pointers, needs to be at least subsys->attr_count big + * cda: array of pointers, needs to be at least subsys->attr_count+1 big * */ static int nfnetlink_check_attributes(const struct nfnetlink_subsystem *subsys, - struct nlmsghdr *nlh, struct nfattr *cda[]) + struct nlmsghdr *nlh, struct nlattr *cda[]) { int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); @@ -156,9 +129,9 @@ nfnetlink_check_attributes(const struct nfnetlink_subsystem *subsys, /* check attribute lengths. */ if (likely(nlh->nlmsg_len > min_len)) { - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + struct nlattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - nfattr_parse(cda, attr_count, attr, attrlen); + nla_parse(cda, attr_count, attr, attrlen, NULL); } /* implicit: if nlmsg_len == min_len, we return 0, and an empty @@ -230,9 +203,9 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { u_int16_t attr_count = ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count; - struct nfattr *cda[attr_count]; + struct nlattr *cda[attr_count+1]; - memset(cda, 0, sizeof(struct nfattr *) * attr_count); + memset(cda, 0, sizeof(struct nlattr *) * attr_count); err = nfnetlink_check_attributes(ss, nlh, cda); if (err < 0) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index c3aa8918035f..c7fd82f6cb7d 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -244,7 +244,7 @@ nfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode, case NFULNL_COPY_PACKET: inst->copy_mode = mode; - /* we're using struct nfattr which has 16bit nfa_len */ + /* we're using struct nlattr which has 16bit nfa_len */ if (range > 0xffff) inst->copy_range = 0xffff; else @@ -409,36 +409,36 @@ __build_packet_message(struct nfulnl_instance *inst, pmsg.hw_protocol = skb->protocol; pmsg.hook = hooknum; - NFA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg); + NLA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg); if (prefix) - NFA_PUT(inst->skb, NFULA_PREFIX, plen, prefix); + NLA_PUT(inst->skb, NFULA_PREFIX, plen, prefix); if (indev) { tmp_uint = htonl(indev->ifindex); #ifndef CONFIG_BRIDGE_NETFILTER - NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint), + NLA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); #else if (pf == PF_BRIDGE) { /* Case 1: outdev is physical input device, we need to * look for bridge group (when called from * netfilter_bridge) */ - NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV, + NLA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), &tmp_uint); /* this is the bridge group "brX" */ tmp_uint = htonl(indev->br_port->br->dev->ifindex); - NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, + NLA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); } else { /* Case 2: indev is bridge group, we need to look for * physical device (when called from ipv4) */ - NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, + NLA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); if (skb->nf_bridge && skb->nf_bridge->physindev) { tmp_uint = htonl(skb->nf_bridge->physindev->ifindex); - NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV, + NLA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), &tmp_uint); } } @@ -448,28 +448,28 @@ __build_packet_message(struct nfulnl_instance *inst, if (outdev) { tmp_uint = htonl(outdev->ifindex); #ifndef CONFIG_BRIDGE_NETFILTER - NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint), + NLA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); #else if (pf == PF_BRIDGE) { /* Case 1: outdev is physical output device, we need to * look for bridge group (when called from * netfilter_bridge) */ - NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, + NLA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), &tmp_uint); /* this is the bridge group "brX" */ tmp_uint = htonl(outdev->br_port->br->dev->ifindex); - NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, + NLA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); } else { /* Case 2: indev is a bridge group, we need to look * for physical device (when called from ipv4) */ - NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, + NLA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); if (skb->nf_bridge && skb->nf_bridge->physoutdev) { tmp_uint = htonl(skb->nf_bridge->physoutdev->ifindex); - NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, + NLA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), &tmp_uint); } } @@ -478,7 +478,7 @@ __build_packet_message(struct nfulnl_instance *inst, if (skb->mark) { tmp_uint = htonl(skb->mark); - NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint); + NLA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint); } if (indev && skb->dev) { @@ -486,7 +486,7 @@ __build_packet_message(struct nfulnl_instance *inst, int len = dev_parse_header(skb, phw.hw_addr); if (len > 0) { phw.hw_addrlen = htons(len); - NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); + NLA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); } } @@ -496,7 +496,7 @@ __build_packet_message(struct nfulnl_instance *inst, ts.sec = cpu_to_be64(tv.tv_sec); ts.usec = cpu_to_be64(tv.tv_usec); - NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts); + NLA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts); } /* UID */ @@ -504,9 +504,9 @@ __build_packet_message(struct nfulnl_instance *inst, read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) { __be32 uid = htonl(skb->sk->sk_socket->file->f_uid); - /* need to unlock here since NFA_PUT may goto */ + /* need to unlock here since NLA_PUT may goto */ read_unlock_bh(&skb->sk->sk_callback_lock); - NFA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid); + NLA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid); } else read_unlock_bh(&skb->sk->sk_callback_lock); } @@ -514,28 +514,28 @@ __build_packet_message(struct nfulnl_instance *inst, /* local sequence number */ if (inst->flags & NFULNL_CFG_F_SEQ) { tmp_uint = htonl(inst->seq++); - NFA_PUT(inst->skb, NFULA_SEQ, sizeof(tmp_uint), &tmp_uint); + NLA_PUT(inst->skb, NFULA_SEQ, sizeof(tmp_uint), &tmp_uint); } /* global sequence number */ if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) { tmp_uint = htonl(atomic_inc_return(&global_seq)); - NFA_PUT(inst->skb, NFULA_SEQ_GLOBAL, sizeof(tmp_uint), &tmp_uint); + NLA_PUT(inst->skb, NFULA_SEQ_GLOBAL, sizeof(tmp_uint), &tmp_uint); } if (data_len) { - struct nfattr *nfa; - int size = NFA_LENGTH(data_len); + struct nlattr *nla; + int size = nla_attr_size(data_len); - if (skb_tailroom(inst->skb) < (int)NFA_SPACE(data_len)) { + if (skb_tailroom(inst->skb) < nla_total_size(data_len)) { printk(KERN_WARNING "nfnetlink_log: no tailroom!\n"); goto nlmsg_failure; } - nfa = (struct nfattr *)skb_put(inst->skb, NFA_ALIGN(size)); - nfa->nfa_type = NFULA_PAYLOAD; - nfa->nfa_len = size; + nla = (struct nlattr *)skb_put(inst->skb, nla_total_size(data_len)); + nla->nla_type = NFULA_PAYLOAD; + nla->nla_len = size; - if (skb_copy_bits(skb, 0, NFA_DATA(nfa), data_len)) + if (skb_copy_bits(skb, 0, nla_data(nla), data_len)) BUG(); } @@ -544,7 +544,7 @@ __build_packet_message(struct nfulnl_instance *inst, nlmsg_failure: UDEBUG("nlmsg_failure\n"); -nfattr_failure: +nla_put_failure: PRINTR(KERN_ERR "nfnetlink_log: error creating log nlmsg\n"); return -1; } @@ -591,32 +591,31 @@ nfulnl_log_packet(unsigned int pf, if (prefix) plen = strlen(prefix) + 1; - /* all macros expand to constant values at compile time */ /* FIXME: do we want to make the size calculation conditional based on * what is actually present? way more branches and checks, but more * memory efficient... */ - size = NLMSG_SPACE(sizeof(struct nfgenmsg)) - + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hdr)) - + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ - + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ + size = NLMSG_ALIGN(sizeof(struct nfgenmsg)) + + nla_total_size(sizeof(struct nfulnl_msg_packet_hdr)) + + nla_total_size(sizeof(u_int32_t)) /* ifindex */ + + nla_total_size(sizeof(u_int32_t)) /* ifindex */ #ifdef CONFIG_BRIDGE_NETFILTER - + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ - + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ + + nla_total_size(sizeof(u_int32_t)) /* ifindex */ + + nla_total_size(sizeof(u_int32_t)) /* ifindex */ #endif - + NFA_SPACE(sizeof(u_int32_t)) /* mark */ - + NFA_SPACE(sizeof(u_int32_t)) /* uid */ - + NFA_SPACE(plen) /* prefix */ - + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hw)) - + NFA_SPACE(sizeof(struct nfulnl_msg_packet_timestamp)); + + nla_total_size(sizeof(u_int32_t)) /* mark */ + + nla_total_size(sizeof(u_int32_t)) /* uid */ + + nla_total_size(plen) /* prefix */ + + nla_total_size(sizeof(struct nfulnl_msg_packet_hw)) + + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp)); UDEBUG("initial size=%u\n", size); spin_lock_bh(&inst->lock); if (inst->flags & NFULNL_CFG_F_SEQ) - size += NFA_SPACE(sizeof(u_int32_t)); + size += nla_total_size(sizeof(u_int32_t)); if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) - size += NFA_SPACE(sizeof(u_int32_t)); + size += nla_total_size(sizeof(u_int32_t)); qthreshold = inst->qthreshold; /* per-rule qthreshold overrides per-instance */ @@ -636,7 +635,7 @@ nfulnl_log_packet(unsigned int pf, else data_len = inst->copy_range; - size += NFA_SPACE(data_len); + size += nla_total_size(data_len); UDEBUG("copy_packet, therefore size now %u\n", size); break; @@ -723,7 +722,7 @@ static struct notifier_block nfulnl_rtnl_notifier = { static int nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *nfqa[]) + struct nlmsghdr *nlh, struct nlattr *nfqa[]) { return -ENOTSUPP; } @@ -734,34 +733,34 @@ static struct nf_logger nfulnl_logger = { .me = THIS_MODULE, }; -static const int nfula_min[NFULA_MAX] = { - [NFULA_PACKET_HDR-1] = sizeof(struct nfulnl_msg_packet_hdr), - [NFULA_MARK-1] = sizeof(u_int32_t), - [NFULA_TIMESTAMP-1] = sizeof(struct nfulnl_msg_packet_timestamp), - [NFULA_IFINDEX_INDEV-1] = sizeof(u_int32_t), - [NFULA_IFINDEX_OUTDEV-1]= sizeof(u_int32_t), - [NFULA_IFINDEX_PHYSINDEV-1] = sizeof(u_int32_t), - [NFULA_IFINDEX_PHYSOUTDEV-1] = sizeof(u_int32_t), - [NFULA_HWADDR-1] = sizeof(struct nfulnl_msg_packet_hw), - [NFULA_PAYLOAD-1] = 0, - [NFULA_PREFIX-1] = 0, - [NFULA_UID-1] = sizeof(u_int32_t), - [NFULA_SEQ-1] = sizeof(u_int32_t), - [NFULA_SEQ_GLOBAL-1] = sizeof(u_int32_t), +static const int nfula_min[NFULA_MAX+1] = { + [NFULA_PACKET_HDR] = sizeof(struct nfulnl_msg_packet_hdr), + [NFULA_MARK] = sizeof(u_int32_t), + [NFULA_TIMESTAMP] = sizeof(struct nfulnl_msg_packet_timestamp), + [NFULA_IFINDEX_INDEV] = sizeof(u_int32_t), + [NFULA_IFINDEX_OUTDEV] = sizeof(u_int32_t), + [NFULA_IFINDEX_PHYSINDEV] = sizeof(u_int32_t), + [NFULA_IFINDEX_PHYSOUTDEV] = sizeof(u_int32_t), + [NFULA_HWADDR] = sizeof(struct nfulnl_msg_packet_hw), + [NFULA_PAYLOAD] = 0, + [NFULA_PREFIX] = 0, + [NFULA_UID] = sizeof(u_int32_t), + [NFULA_SEQ] = sizeof(u_int32_t), + [NFULA_SEQ_GLOBAL] = sizeof(u_int32_t), }; -static const int nfula_cfg_min[NFULA_CFG_MAX] = { - [NFULA_CFG_CMD-1] = sizeof(struct nfulnl_msg_config_cmd), - [NFULA_CFG_MODE-1] = sizeof(struct nfulnl_msg_config_mode), - [NFULA_CFG_TIMEOUT-1] = sizeof(u_int32_t), - [NFULA_CFG_QTHRESH-1] = sizeof(u_int32_t), - [NFULA_CFG_NLBUFSIZ-1] = sizeof(u_int32_t), - [NFULA_CFG_FLAGS-1] = sizeof(u_int16_t), +static const int nfula_cfg_min[NFULA_CFG_MAX+1] = { + [NFULA_CFG_CMD] = sizeof(struct nfulnl_msg_config_cmd), + [NFULA_CFG_MODE] = sizeof(struct nfulnl_msg_config_mode), + [NFULA_CFG_TIMEOUT] = sizeof(u_int32_t), + [NFULA_CFG_QTHRESH] = sizeof(u_int32_t), + [NFULA_CFG_NLBUFSIZ] = sizeof(u_int32_t), + [NFULA_CFG_FLAGS] = sizeof(u_int16_t), }; static int nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *nfula[]) + struct nlmsghdr *nlh, struct nlattr *nfula[]) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); u_int16_t group_num = ntohs(nfmsg->res_id); @@ -776,10 +775,10 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } inst = instance_lookup_get(group_num); - if (nfula[NFULA_CFG_CMD-1]) { + if (nfula[NFULA_CFG_CMD]) { u_int8_t pf = nfmsg->nfgen_family; struct nfulnl_msg_config_cmd *cmd; - cmd = NFA_DATA(nfula[NFULA_CFG_CMD-1]); + cmd = nla_data(nfula[NFULA_CFG_CMD]); UDEBUG("found CFG_CMD for\n"); switch (cmd->command) { @@ -842,38 +841,38 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } } - if (nfula[NFULA_CFG_MODE-1]) { + if (nfula[NFULA_CFG_MODE]) { struct nfulnl_msg_config_mode *params; - params = NFA_DATA(nfula[NFULA_CFG_MODE-1]); + params = nla_data(nfula[NFULA_CFG_MODE]); nfulnl_set_mode(inst, params->copy_mode, ntohl(params->copy_range)); } - if (nfula[NFULA_CFG_TIMEOUT-1]) { + if (nfula[NFULA_CFG_TIMEOUT]) { __be32 timeout = - *(__be32 *)NFA_DATA(nfula[NFULA_CFG_TIMEOUT-1]); + *(__be32 *)nla_data(nfula[NFULA_CFG_TIMEOUT]); nfulnl_set_timeout(inst, ntohl(timeout)); } - if (nfula[NFULA_CFG_NLBUFSIZ-1]) { + if (nfula[NFULA_CFG_NLBUFSIZ]) { __be32 nlbufsiz = - *(__be32 *)NFA_DATA(nfula[NFULA_CFG_NLBUFSIZ-1]); + *(__be32 *)nla_data(nfula[NFULA_CFG_NLBUFSIZ]); nfulnl_set_nlbufsiz(inst, ntohl(nlbufsiz)); } - if (nfula[NFULA_CFG_QTHRESH-1]) { + if (nfula[NFULA_CFG_QTHRESH]) { __be32 qthresh = - *(__be32 *)NFA_DATA(nfula[NFULA_CFG_QTHRESH-1]); + *(__be32 *)nla_data(nfula[NFULA_CFG_QTHRESH]); nfulnl_set_qthresh(inst, ntohl(qthresh)); } - if (nfula[NFULA_CFG_FLAGS-1]) { + if (nfula[NFULA_CFG_FLAGS]) { __be16 flags = - *(__be16 *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]); + *(__be16 *)nla_data(nfula[NFULA_CFG_FLAGS]); nfulnl_set_flags(inst, ntohs(flags)); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index bfcc0563bfd4..068e88b46ba0 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -299,7 +299,7 @@ __nfqnl_set_mode(struct nfqnl_instance *queue, case NFQNL_COPY_PACKET: queue->copy_mode = mode; - /* we're using struct nfattr which has 16bit nfa_len */ + /* we're using struct nlattr which has 16bit nla_len */ if (range > 0xffff) queue->copy_range = 0xffff; else @@ -353,18 +353,17 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, QDEBUG("entered\n"); - /* all macros expand to constant values at compile time */ - size = NLMSG_SPACE(sizeof(struct nfgenmsg)) + - + NFA_SPACE(sizeof(struct nfqnl_msg_packet_hdr)) - + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ - + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ + size = NLMSG_ALIGN(sizeof(struct nfgenmsg)) + + nla_total_size(sizeof(struct nfqnl_msg_packet_hdr)) + + nla_total_size(sizeof(u_int32_t)) /* ifindex */ + + nla_total_size(sizeof(u_int32_t)) /* ifindex */ #ifdef CONFIG_BRIDGE_NETFILTER - + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ - + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ + + nla_total_size(sizeof(u_int32_t)) /* ifindex */ + + nla_total_size(sizeof(u_int32_t)) /* ifindex */ #endif - + NFA_SPACE(sizeof(u_int32_t)) /* mark */ - + NFA_SPACE(sizeof(struct nfqnl_msg_packet_hw)) - + NFA_SPACE(sizeof(struct nfqnl_msg_packet_timestamp)); + + nla_total_size(sizeof(u_int32_t)) /* mark */ + + nla_total_size(sizeof(struct nfqnl_msg_packet_hw)) + + nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp)); outdev = entinf->outdev; @@ -389,7 +388,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, else data_len = queue->copy_range; - size += NFA_SPACE(data_len); + size += nla_total_size(data_len); break; default: @@ -417,33 +416,33 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, pmsg.hw_protocol = entskb->protocol; pmsg.hook = entinf->hook; - NFA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg); + NLA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg); indev = entinf->indev; if (indev) { tmp_uint = htonl(indev->ifindex); #ifndef CONFIG_BRIDGE_NETFILTER - NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); + NLA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); #else if (entinf->pf == PF_BRIDGE) { /* Case 1: indev is physical input device, we need to * look for bridge group (when called from * netfilter_bridge) */ - NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), + NLA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), &tmp_uint); /* this is the bridge group "brX" */ tmp_uint = htonl(indev->br_port->br->dev->ifindex); - NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), + NLA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); } else { /* Case 2: indev is bridge group, we need to look for * physical device (when called from ipv4) */ - NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), + NLA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); if (entskb->nf_bridge && entskb->nf_bridge->physindev) { tmp_uint = htonl(entskb->nf_bridge->physindev->ifindex); - NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, + NLA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), &tmp_uint); } } @@ -453,27 +452,27 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, if (outdev) { tmp_uint = htonl(outdev->ifindex); #ifndef CONFIG_BRIDGE_NETFILTER - NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); + NLA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); #else if (entinf->pf == PF_BRIDGE) { /* Case 1: outdev is physical output device, we need to * look for bridge group (when called from * netfilter_bridge) */ - NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), + NLA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), &tmp_uint); /* this is the bridge group "brX" */ tmp_uint = htonl(outdev->br_port->br->dev->ifindex); - NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), + NLA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); } else { /* Case 2: outdev is bridge group, we need to look for * physical output device (when called from ipv4) */ - NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), + NLA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); if (entskb->nf_bridge && entskb->nf_bridge->physoutdev) { tmp_uint = htonl(entskb->nf_bridge->physoutdev->ifindex); - NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, + NLA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), &tmp_uint); } } @@ -482,7 +481,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, if (entskb->mark) { tmp_uint = htonl(entskb->mark); - NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); + NLA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); } if (indev && entskb->dev) { @@ -490,7 +489,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, int len = dev_parse_header(entskb, phw.hw_addr); if (len) { phw.hw_addrlen = htons(len); - NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); + NLA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); } } @@ -500,23 +499,23 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, ts.sec = cpu_to_be64(tv.tv_sec); ts.usec = cpu_to_be64(tv.tv_usec); - NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts); + NLA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts); } if (data_len) { - struct nfattr *nfa; - int size = NFA_LENGTH(data_len); + struct nlattr *nla; + int size = nla_attr_size(data_len); - if (skb_tailroom(skb) < (int)NFA_SPACE(data_len)) { + if (skb_tailroom(skb) < nla_total_size(data_len)) { printk(KERN_WARNING "nf_queue: no tailroom!\n"); goto nlmsg_failure; } - nfa = (struct nfattr *)skb_put(skb, NFA_ALIGN(size)); - nfa->nfa_type = NFQA_PAYLOAD; - nfa->nfa_len = size; + nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len)); + nla->nla_type = NFQA_PAYLOAD; + nla->nla_len = size; - if (skb_copy_bits(entskb, 0, NFA_DATA(nfa), data_len)) + if (skb_copy_bits(entskb, 0, nla_data(nla), data_len)) BUG(); } @@ -524,7 +523,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, return skb; nlmsg_failure: -nfattr_failure: +nla_put_failure: if (skb) kfree_skb(skb); *errp = -EINVAL; @@ -778,15 +777,15 @@ static struct notifier_block nfqnl_rtnl_notifier = { .notifier_call = nfqnl_rcv_nl_event, }; -static const int nfqa_verdict_min[NFQA_MAX] = { - [NFQA_VERDICT_HDR-1] = sizeof(struct nfqnl_msg_verdict_hdr), - [NFQA_MARK-1] = sizeof(u_int32_t), - [NFQA_PAYLOAD-1] = 0, +static const int nfqa_verdict_min[NFQA_MAX+1] = { + [NFQA_VERDICT_HDR] = sizeof(struct nfqnl_msg_verdict_hdr), + [NFQA_MARK] = sizeof(u_int32_t), + [NFQA_PAYLOAD] = 0, }; static int nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *nfqa[]) + struct nlmsghdr *nlh, struct nlattr *nfqa[]) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); u_int16_t queue_num = ntohs(nfmsg->res_id); @@ -811,12 +810,12 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, goto err_out_put; } - if (!nfqa[NFQA_VERDICT_HDR-1]) { + if (!nfqa[NFQA_VERDICT_HDR]) { err = -EINVAL; goto err_out_put; } - vhdr = NFA_DATA(nfqa[NFQA_VERDICT_HDR-1]); + vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); verdict = ntohl(vhdr->verdict); if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) { @@ -830,15 +829,15 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, goto err_out_put; } - if (nfqa[NFQA_PAYLOAD-1]) { - if (nfqnl_mangle(NFA_DATA(nfqa[NFQA_PAYLOAD-1]), - NFA_PAYLOAD(nfqa[NFQA_PAYLOAD-1]), entry) < 0) + if (nfqa[NFQA_PAYLOAD]) { + if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), + nla_len(nfqa[NFQA_PAYLOAD]), entry) < 0) verdict = NF_DROP; } - if (nfqa[NFQA_MARK-1]) + if (nfqa[NFQA_MARK]) entry->skb->mark = ntohl(*(__be32 *) - NFA_DATA(nfqa[NFQA_MARK-1])); + nla_data(nfqa[NFQA_MARK])); issue_verdict(entry, verdict); instance_put(queue); @@ -851,14 +850,14 @@ err_out_put: static int nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *nfqa[]) + struct nlmsghdr *nlh, struct nlattr *nfqa[]) { return -ENOTSUPP; } -static const int nfqa_cfg_min[NFQA_CFG_MAX] = { - [NFQA_CFG_CMD-1] = sizeof(struct nfqnl_msg_config_cmd), - [NFQA_CFG_PARAMS-1] = sizeof(struct nfqnl_msg_config_params), +static const int nfqa_cfg_min[NFQA_CFG_MAX+1] = { + [NFQA_CFG_CMD] = sizeof(struct nfqnl_msg_config_cmd), + [NFQA_CFG_PARAMS] = sizeof(struct nfqnl_msg_config_params), }; static struct nf_queue_handler nfqh = { @@ -868,7 +867,7 @@ static struct nf_queue_handler nfqh = { static int nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nfattr *nfqa[]) + struct nlmsghdr *nlh, struct nlattr *nfqa[]) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); u_int16_t queue_num = ntohs(nfmsg->res_id); @@ -883,9 +882,9 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } queue = instance_lookup_get(queue_num); - if (nfqa[NFQA_CFG_CMD-1]) { + if (nfqa[NFQA_CFG_CMD]) { struct nfqnl_msg_config_cmd *cmd; - cmd = NFA_DATA(nfqa[NFQA_CFG_CMD-1]); + cmd = nla_data(nfqa[NFQA_CFG_CMD]); QDEBUG("found CFG_CMD\n"); switch (cmd->command) { @@ -936,21 +935,21 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } } - if (nfqa[NFQA_CFG_PARAMS-1]) { + if (nfqa[NFQA_CFG_PARAMS]) { struct nfqnl_msg_config_params *params; if (!queue) { ret = -ENOENT; goto out_put; } - params = NFA_DATA(nfqa[NFQA_CFG_PARAMS-1]); + params = nla_data(nfqa[NFQA_CFG_PARAMS]); nfqnl_set_mode(queue, params->copy_mode, ntohl(params->copy_range)); } - if (nfqa[NFQA_CFG_QUEUE_MAXLEN-1]) { + if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) { __be32 *queue_maxlen; - queue_maxlen = NFA_DATA(nfqa[NFQA_CFG_QUEUE_MAXLEN-1]); + queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]); spin_lock_bh(&queue->lock); queue->queue_maxlen = ntohl(*queue_maxlen); spin_unlock_bh(&queue->lock); From fdf708322d4658daa6eb795d1a835b97efdb335e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:37:41 -0700 Subject: [PATCH 1604/2804] [NETFILTER]: nfnetlink: rename functions containing 'nfattr' There is no struct nfattr anymore, rename functions to 'nlattr'. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink.h | 2 +- include/net/netfilter/nf_conntrack_helper.h | 2 +- include/net/netfilter/nf_conntrack_l3proto.h | 4 +- include/net/netfilter/nf_conntrack_l4proto.h | 12 ++--- include/net/netfilter/nf_nat_protocol.h | 8 +-- .../netfilter/nf_conntrack_l3proto_ipv4.c | 10 ++-- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 10 ++-- net/ipv4/netfilter/nf_nat_core.c | 8 +-- net/ipv4/netfilter/nf_nat_proto_gre.c | 4 +- net/ipv4/netfilter/nf_nat_proto_icmp.c | 4 +- net/ipv4/netfilter/nf_nat_proto_tcp.c | 4 +- net/ipv4/netfilter/nf_nat_proto_udp.c | 4 +- .../netfilter/nf_conntrack_l3proto_ipv6.c | 10 ++-- .../netfilter/nf_conntrack_proto_icmpv6.c | 10 ++-- net/netfilter/nf_conntrack_core.c | 10 ++-- net/netfilter/nf_conntrack_netlink.c | 52 +++++++++---------- net/netfilter/nf_conntrack_proto_gre.c | 4 +- net/netfilter/nf_conntrack_proto_tcp.c | 22 ++++---- net/netfilter/nf_conntrack_proto_udp.c | 8 +-- net/netfilter/nf_conntrack_proto_udplite.c | 8 +-- net/netfilter/nfnetlink_log.c | 2 +- net/netfilter/nfnetlink_queue.c | 4 +- 22 files changed, 101 insertions(+), 101 deletions(-) diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 47457b4c8c62..e61a8a5fcaff 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -72,7 +72,7 @@ struct nfnetlink_subsystem extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); -#define nfattr_bad_size(tb, max, cta_min) \ +#define nlattr_bad_size(tb, max, cta_min) \ ({ int __i, __res = 0; \ for (__i=1; __i <= max; __i++) { \ if (!cta_min[__i]) \ diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index d04f99964d94..0dcc4c828ce9 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -36,7 +36,7 @@ struct nf_conntrack_helper void (*destroy)(struct nf_conn *ct); - int (*to_nfattr)(struct sk_buff *skb, const struct nf_conn *ct); + int (*to_nlattr)(struct sk_buff *skb, const struct nf_conn *ct); }; extern struct nf_conntrack_helper * diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index c02402d5ec36..f6c372d4ec1f 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h @@ -63,10 +63,10 @@ struct nf_conntrack_l3proto int (*get_l4proto)(const struct sk_buff *skb, unsigned int nhoff, unsigned int *dataoff, u_int8_t *protonum); - int (*tuple_to_nfattr)(struct sk_buff *skb, + int (*tuple_to_nlattr)(struct sk_buff *skb, const struct nf_conntrack_tuple *t); - int (*nfattr_to_tuple)(struct nlattr *tb[], + int (*nlattr_to_tuple)(struct nlattr *tb[], struct nf_conntrack_tuple *t); #ifdef CONFIG_SYSCTL diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index a43c4e484ea1..658daccc6b56 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -65,15 +65,15 @@ struct nf_conntrack_l4proto int pf, unsigned int hooknum); /* convert protoinfo to nfnetink attributes */ - int (*to_nfattr)(struct sk_buff *skb, struct nlattr *nla, + int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, const struct nf_conn *ct); /* convert nfnetlink attributes to protoinfo */ - int (*from_nfattr)(struct nlattr *tb[], struct nf_conn *ct); + int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); - int (*tuple_to_nfattr)(struct sk_buff *skb, + int (*tuple_to_nlattr)(struct sk_buff *skb, const struct nf_conntrack_tuple *t); - int (*nfattr_to_tuple)(struct nlattr *tb[], + int (*nlattr_to_tuple)(struct nlattr *tb[], struct nf_conntrack_tuple *t); #ifdef CONFIG_SYSCTL @@ -111,9 +111,9 @@ extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto); extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto); /* Generic netlink helpers */ -extern int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb, +extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple); -extern int nf_ct_port_nfattr_to_tuple(struct nlattr *tb[], +extern int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t); /* Log invalid packets */ diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h index 90a82de7e7e0..14c7b2d7263c 100644 --- a/include/net/netfilter/nf_nat_protocol.h +++ b/include/net/netfilter/nf_nat_protocol.h @@ -38,10 +38,10 @@ struct nf_nat_protocol enum nf_nat_manip_type maniptype, const struct nf_conn *ct); - int (*range_to_nfattr)(struct sk_buff *skb, + int (*range_to_nlattr)(struct sk_buff *skb, const struct nf_nat_range *range); - int (*nfattr_to_range)(struct nlattr *tb[], + int (*nlattr_to_range)(struct nlattr *tb[], struct nf_nat_range *range); }; @@ -62,9 +62,9 @@ extern int init_protocols(void) __init; extern void cleanup_protocols(void); extern struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); -extern int nf_nat_port_range_to_nfattr(struct sk_buff *skb, +extern int nf_nat_port_range_to_nlattr(struct sk_buff *skb, const struct nf_nat_range *range); -extern int nf_nat_port_nfattr_to_range(struct nlattr *tb[], +extern int nf_nat_port_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range); #endif /*_NF_NAT_PROTO_H*/ diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index f8771e058b9e..77ca556aad91 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -360,7 +360,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) #include #include -static int ipv4_tuple_to_nfattr(struct sk_buff *skb, +static int ipv4_tuple_to_nlattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple) { NLA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), @@ -378,13 +378,13 @@ static const size_t cta_min_ip[CTA_IP_MAX+1] = { [CTA_IP_V4_DST] = sizeof(u_int32_t), }; -static int ipv4_nfattr_to_tuple(struct nlattr *tb[], +static int ipv4_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t) { if (!tb[CTA_IP_V4_SRC] || !tb[CTA_IP_V4_DST]) return -EINVAL; - if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) + if (nlattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) return -EINVAL; t->src.u3.ip = *(__be32 *)nla_data(tb[CTA_IP_V4_SRC]); @@ -411,8 +411,8 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = { .print_conntrack = ipv4_print_conntrack, .get_l4proto = ipv4_get_l4proto, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = ipv4_tuple_to_nfattr, - .nfattr_to_tuple = ipv4_nfattr_to_tuple, + .tuple_to_nlattr = ipv4_tuple_to_nlattr, + .nlattr_to_tuple = ipv4_nlattr_to_tuple, #endif #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) .ctl_table_path = nf_net_ipv4_netfilter_sysctl_path, diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 714332b8869e..ca7252c10758 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -232,7 +232,7 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff, #include #include -static int icmp_tuple_to_nfattr(struct sk_buff *skb, +static int icmp_tuple_to_nlattr(struct sk_buff *skb, const struct nf_conntrack_tuple *t) { NLA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t), @@ -254,7 +254,7 @@ static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { [CTA_PROTO_ICMP_ID] = sizeof(u_int16_t) }; -static int icmp_nfattr_to_tuple(struct nlattr *tb[], +static int icmp_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *tuple) { if (!tb[CTA_PROTO_ICMP_TYPE] @@ -262,7 +262,7 @@ static int icmp_nfattr_to_tuple(struct nlattr *tb[], || !tb[CTA_PROTO_ICMP_ID]) return -EINVAL; - if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) + if (nlattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) return -EINVAL; tuple->dst.u.icmp.type = @@ -327,8 +327,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = .destroy = NULL, .me = NULL, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = icmp_tuple_to_nfattr, - .nfattr_to_tuple = icmp_nfattr_to_tuple, + .tuple_to_nlattr = icmp_tuple_to_nlattr, + .nlattr_to_tuple = icmp_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_header = &icmp_sysctl_header, diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 4bdbb128fe50..7221aa20e6ff 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -544,7 +544,7 @@ EXPORT_SYMBOL(nf_nat_protocol_unregister); #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) int -nf_nat_port_range_to_nfattr(struct sk_buff *skb, +nf_nat_port_range_to_nlattr(struct sk_buff *skb, const struct nf_nat_range *range) { NLA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), @@ -557,10 +557,10 @@ nf_nat_port_range_to_nfattr(struct sk_buff *skb, nla_put_failure: return -1; } -EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range); +EXPORT_SYMBOL_GPL(nf_nat_port_nlattr_to_range); int -nf_nat_port_nfattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) +nf_nat_port_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) { int ret = 0; @@ -583,7 +583,7 @@ nf_nat_port_nfattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) return ret; } -EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); +EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nlattr); #endif /* Noone using conntrack by the time this called. */ diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index 2e40cc83526a..d562290b1820 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -142,8 +142,8 @@ static struct nf_nat_protocol gre __read_mostly = { .in_range = gre_in_range, .unique_tuple = gre_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .range_to_nfattr = nf_nat_port_range_to_nfattr, - .nfattr_to_range = nf_nat_port_nfattr_to_range, + .range_to_nlattr = nf_nat_port_range_to_nlattr, + .nlattr_to_range = nf_nat_port_nlattr_to_range, #endif }; diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c index f71ef9b5f428..898d73771155 100644 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -79,7 +79,7 @@ struct nf_nat_protocol nf_nat_protocol_icmp = { .in_range = icmp_in_range, .unique_tuple = icmp_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .range_to_nfattr = nf_nat_port_range_to_nfattr, - .nfattr_to_range = nf_nat_port_nfattr_to_range, + .range_to_nlattr = nf_nat_port_range_to_nlattr, + .nlattr_to_range = nf_nat_port_nlattr_to_range, #endif }; diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c index 123c95913f28..5bbbb2acdc70 100644 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -145,7 +145,7 @@ struct nf_nat_protocol nf_nat_protocol_tcp = { .in_range = tcp_in_range, .unique_tuple = tcp_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .range_to_nfattr = nf_nat_port_range_to_nfattr, - .nfattr_to_range = nf_nat_port_nfattr_to_range, + .range_to_nlattr = nf_nat_port_range_to_nlattr, + .nlattr_to_range = nf_nat_port_nlattr_to_range, #endif }; diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c index 1c4c70e25cd4..a0af4fd95584 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -135,7 +135,7 @@ struct nf_nat_protocol nf_nat_protocol_udp = { .in_range = udp_in_range, .unique_tuple = udp_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .range_to_nfattr = nf_nat_port_range_to_nfattr, - .nfattr_to_range = nf_nat_port_nfattr_to_range, + .range_to_nlattr = nf_nat_port_range_to_nlattr, + .nlattr_to_range = nf_nat_port_nlattr_to_range, #endif }; diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index f0ea3fb51670..567fbe230ce6 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -337,7 +337,7 @@ static ctl_table nf_ct_ipv6_sysctl_table[] = { #include #include -static int ipv6_tuple_to_nfattr(struct sk_buff *skb, +static int ipv6_tuple_to_nlattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple) { NLA_PUT(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4, @@ -355,13 +355,13 @@ static const size_t cta_min_ip[CTA_IP_MAX+1] = { [CTA_IP_V6_DST] = sizeof(u_int32_t)*4, }; -static int ipv6_nfattr_to_tuple(struct nlattr *tb[], +static int ipv6_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t) { if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST]) return -EINVAL; - if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) + if (nlattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) return -EINVAL; memcpy(&t->src.u3.ip6, nla_data(tb[CTA_IP_V6_SRC]), @@ -382,8 +382,8 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { .print_conntrack = ipv6_print_conntrack, .get_l4proto = ipv6_get_l4proto, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = ipv6_tuple_to_nfattr, - .nfattr_to_tuple = ipv6_nfattr_to_tuple, + .tuple_to_nlattr = ipv6_tuple_to_nlattr, + .nlattr_to_tuple = ipv6_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_path = nf_net_netfilter_sysctl_path, diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index c18183823faf..238ea6bc864e 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -210,7 +210,7 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff, #include #include -static int icmpv6_tuple_to_nfattr(struct sk_buff *skb, +static int icmpv6_tuple_to_nlattr(struct sk_buff *skb, const struct nf_conntrack_tuple *t) { NLA_PUT(skb, CTA_PROTO_ICMPV6_ID, sizeof(u_int16_t), @@ -232,7 +232,7 @@ static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { [CTA_PROTO_ICMPV6_ID] = sizeof(u_int16_t) }; -static int icmpv6_nfattr_to_tuple(struct nlattr *tb[], +static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *tuple) { if (!tb[CTA_PROTO_ICMPV6_TYPE] @@ -240,7 +240,7 @@ static int icmpv6_nfattr_to_tuple(struct nlattr *tb[], || !tb[CTA_PROTO_ICMPV6_ID]) return -EINVAL; - if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) + if (nlattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) return -EINVAL; tuple->dst.u.icmp.type = @@ -289,8 +289,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = .new = icmpv6_new, .error = icmpv6_error, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = icmpv6_tuple_to_nfattr, - .nfattr_to_tuple = icmpv6_nfattr_to_tuple, + .tuple_to_nlattr = icmpv6_tuple_to_nlattr, + .nlattr_to_tuple = icmpv6_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_header = &icmpv6_sysctl_header, diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index b64656abc4e0..9edaaf2d57e7 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -830,7 +830,7 @@ EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be * in ip_conntrack_core, since we don't want the protocols to autoload * or depend on ctnetlink */ -int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb, +int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple) { NLA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t), @@ -842,20 +842,20 @@ int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb, nla_put_failure: return -1; } -EXPORT_SYMBOL_GPL(nf_ct_port_tuple_to_nfattr); +EXPORT_SYMBOL_GPL(nf_ct_port_tuple_to_nlattr); static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { [CTA_PROTO_SRC_PORT] = sizeof(u_int16_t), [CTA_PROTO_DST_PORT] = sizeof(u_int16_t) }; -int nf_ct_port_nfattr_to_tuple(struct nlattr *tb[], +int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t) { if (!tb[CTA_PROTO_SRC_PORT] || !tb[CTA_PROTO_DST_PORT]) return -EINVAL; - if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) + if (nlattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) return -EINVAL; t->src.u.tcp.port = *(__be16 *)nla_data(tb[CTA_PROTO_SRC_PORT]); @@ -863,7 +863,7 @@ int nf_ct_port_nfattr_to_tuple(struct nlattr *tb[], return 0; } -EXPORT_SYMBOL_GPL(nf_ct_port_nfattr_to_tuple); +EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple); #endif /* Used by ipt_REJECT and ip6t_REJECT. */ diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 221c38f889bf..9f9bef2446a1 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -61,8 +61,8 @@ ctnetlink_dump_tuples_proto(struct sk_buff *skb, goto nla_put_failure; NLA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); - if (likely(l4proto->tuple_to_nfattr)) - ret = l4proto->tuple_to_nfattr(skb, tuple); + if (likely(l4proto->tuple_to_nlattr)) + ret = l4proto->tuple_to_nlattr(skb, tuple); nla_nest_end(skb, nest_parms); @@ -84,8 +84,8 @@ ctnetlink_dump_tuples_ip(struct sk_buff *skb, if (!nest_parms) goto nla_put_failure; - if (likely(l3proto->tuple_to_nfattr)) - ret = l3proto->tuple_to_nfattr(skb, tuple); + if (likely(l3proto->tuple_to_nlattr)) + ret = l3proto->tuple_to_nlattr(skb, tuple); nla_nest_end(skb, nest_parms); @@ -153,7 +153,7 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) struct nlattr *nest_proto; int ret; - if (!l4proto->to_nfattr) { + if (!l4proto->to_nlattr) { nf_ct_l4proto_put(l4proto); return 0; } @@ -162,7 +162,7 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) if (!nest_proto) goto nla_put_failure; - ret = l4proto->to_nfattr(skb, nest_proto, ct); + ret = l4proto->to_nlattr(skb, nest_proto, ct); nf_ct_l4proto_put(l4proto); @@ -195,8 +195,8 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) goto nla_put_failure; NLA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name); - if (helper->to_nfattr) - helper->to_nfattr(skb, ct); + if (helper->to_nlattr) + helper->to_nlattr(skb, ct); nla_nest_end(skb, nest_helper); out: @@ -512,8 +512,8 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple) l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); - if (likely(l3proto->nfattr_to_tuple)) - ret = l3proto->nfattr_to_tuple(tb, tuple); + if (likely(l3proto->nlattr_to_tuple)) + ret = l3proto->nlattr_to_tuple(tb, tuple); nf_ct_l3proto_put(l3proto); @@ -534,7 +534,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, nla_parse_nested(tb, CTA_PROTO_MAX, attr, NULL); - if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) + if (nlattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) return -EINVAL; if (!tb[CTA_PROTO_NUM]) @@ -543,8 +543,8 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); - if (likely(l4proto->nfattr_to_tuple)) - ret = l4proto->nfattr_to_tuple(tb, tuple); + if (likely(l4proto->nlattr_to_tuple)) + ret = l4proto->nlattr_to_tuple(tb, tuple); nf_ct_l4proto_put(l4proto); @@ -602,18 +602,18 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr, nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, NULL); - if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) + if (nlattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) return -EINVAL; npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); - if (!npt->nfattr_to_range) { + if (!npt->nlattr_to_range) { nf_nat_proto_put(npt); return 0; } - /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ - if (npt->nfattr_to_range(tb, range) > 0) + /* nlattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ + if (npt->nlattr_to_range(tb, range) > 0) range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; nf_nat_proto_put(npt); @@ -637,7 +637,7 @@ nfnetlink_parse_nat(struct nlattr *nat, nla_parse_nested(tb, CTA_NAT_MAX, nat, NULL); - if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) + if (nlattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) return -EINVAL; if (tb[CTA_NAT_MINIP]) @@ -696,7 +696,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - if (nfattr_bad_size(cda, CTA_MAX, cta_min)) + if (nlattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; if (cda[CTA_TUPLE_ORIG]) @@ -754,7 +754,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, ctnetlink_done); } - if (nfattr_bad_size(cda, CTA_MAX, cta_min)) + if (nlattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; if (cda[CTA_TUPLE_ORIG]) @@ -928,8 +928,8 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) l4proto = nf_ct_l4proto_find_get(l3num, npt); - if (l4proto->from_nfattr) - err = l4proto->from_nfattr(tb, ct); + if (l4proto->from_nlattr) + err = l4proto->from_nlattr(tb, ct); nf_ct_l4proto_put(l4proto); return err; @@ -1045,7 +1045,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - if (nfattr_bad_size(cda, CTA_MAX, cta_min)) + if (nlattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; if (cda[CTA_TUPLE_ORIG]) { @@ -1329,7 +1329,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) + if (nlattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; if (nlh->nlmsg_flags & NLM_F_DUMP) { @@ -1393,7 +1393,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, unsigned int i; int err; - if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) + if (nlattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; if (cda[CTA_EXPECT_TUPLE]) { @@ -1534,7 +1534,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) + if (nlattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) return -EINVAL; if (!cda[CTA_EXPECT_TUPLE] diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index bdbead8a7a83..ff8d03b88402 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -274,8 +274,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { .destroy = gre_destroy, .me = THIS_MODULE, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, - .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, #endif }; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 1d167e61cc44..84f47bc90f63 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1067,7 +1067,7 @@ static int tcp_new(struct nf_conn *conntrack, #include #include -static int tcp_to_nfattr(struct sk_buff *skb, struct nlattr *nla, +static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, const struct nf_conn *ct) { struct nlattr *nest_parms; @@ -1113,7 +1113,7 @@ static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX+1] = { [CTA_PROTOINFO_TCP_FLAGS_REPLY] = sizeof(struct nf_ct_tcp_flags) }; -static int nfattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) +static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) { struct nlattr *attr = cda[CTA_PROTOINFO_TCP]; struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1]; @@ -1125,7 +1125,7 @@ static int nfattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr, NULL); - if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp)) + if (nlattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp)) return -EINVAL; if (!tb[CTA_PROTOINFO_TCP_STATE]) @@ -1387,10 +1387,10 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = .new = tcp_new, .error = tcp_error, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .to_nfattr = tcp_to_nfattr, - .from_nfattr = nfattr_to_tcp, - .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, - .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, + .to_nlattr = tcp_to_nlattr, + .from_nlattr = nlattr_to_tcp, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &tcp_sysctl_table_users, @@ -1416,10 +1416,10 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = .new = tcp_new, .error = tcp_error, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .to_nfattr = tcp_to_nfattr, - .from_nfattr = nfattr_to_tcp, - .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, - .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, + .to_nlattr = tcp_to_nlattr, + .from_nlattr = nlattr_to_tcp, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &tcp_sysctl_table_users, diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 2a2fd1a764ea..751ff7e2a0d9 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -203,8 +203,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = .new = udp_new, .error = udp_error, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, - .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &udp_sysctl_table_users, @@ -230,8 +230,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = .new = udp_new, .error = udp_error, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, - .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &udp_sysctl_table_users, diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index b906b413997c..4209ddb8fbaf 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -203,8 +203,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = .new = udplite_new, .error = udplite_error, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, - .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &udplite_sysctl_table_users, @@ -226,8 +226,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = .new = udplite_new, .error = udplite_error, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, - .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &udplite_sysctl_table_users, diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index c7fd82f6cb7d..b656648537c6 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -769,7 +769,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, UDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type)); - if (nfattr_bad_size(nfula, NFULA_CFG_MAX, nfula_cfg_min)) { + if (nlattr_bad_size(nfula, NFULA_CFG_MAX, nfula_cfg_min)) { UDEBUG("bad attribute size\n"); return -EINVAL; } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 068e88b46ba0..1c34668588f1 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -796,7 +796,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_queue_entry *entry; int err; - if (nfattr_bad_size(nfqa, NFQA_MAX, nfqa_verdict_min)) { + if (nlattr_bad_size(nfqa, NFQA_MAX, nfqa_verdict_min)) { QDEBUG("bad attribute size\n"); return -EINVAL; } @@ -876,7 +876,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, QDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type)); - if (nfattr_bad_size(nfqa, NFQA_CFG_MAX, nfqa_cfg_min)) { + if (nlattr_bad_size(nfqa, NFQA_CFG_MAX, nfqa_cfg_min)) { QDEBUG("bad attribute size\n"); return -EINVAL; } From dd82185f2c55e9dc2247c83d78517ef14e71d30e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:38:07 -0700 Subject: [PATCH 1605/2804] [NETFILTER]: nfnetlink: use nlmsg_notify() Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 3cfa76b89a20..e212102b0e4a 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -148,16 +148,7 @@ EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) { - int err = 0; - - NETLINK_CB(skb).dst_group = group; - if (echo) - atomic_inc(&skb->users); - netlink_broadcast(nfnl, skb, pid, group, gfp_any()); - if (echo) - err = netlink_unicast(nfnl, skb, pid, MSG_DONTWAIT); - - return err; + return nlmsg_notify(nfnl, skb, pid, group, echo, gfp_any()); } EXPORT_SYMBOL_GPL(nfnetlink_send); From e3730578285fcf0c628f08b0dc89425cfeafd4ba Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:38:52 -0700 Subject: [PATCH 1606/2804] [NETFILTER]: nfnetlink: support attribute policies Add support for automatic checking of per-callback attribute policies. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink.h | 3 +- net/netfilter/nfnetlink.c | 48 ++++++++--------------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index e61a8a5fcaff..cd8fded36550 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -58,7 +58,8 @@ struct nfnl_callback { int (*call)(struct sock *nl, struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr *cda[]); - u_int16_t attr_count; /* number of nlattr's */ + const struct nla_policy *policy; /* netlink attribute policy */ + const u_int16_t attr_count; /* number of nlattr's */ }; struct nfnetlink_subsystem diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index e212102b0e4a..cb41990f92e0 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -111,35 +111,6 @@ nfnetlink_find_client(u_int16_t type, const struct nfnetlink_subsystem *ss) return &ss->cb[cb_id]; } -/** - * nfnetlink_check_attributes - check and parse nfnetlink attributes - * - * subsys: nfnl subsystem for which this message is to be parsed - * nlmsghdr: netlink message to be checked/parsed - * cda: array of pointers, needs to be at least subsys->attr_count+1 big - * - */ -static int -nfnetlink_check_attributes(const struct nfnetlink_subsystem *subsys, - struct nlmsghdr *nlh, struct nlattr *cda[]) -{ - int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); - u_int16_t attr_count = subsys->cb[cb_id].attr_count; - - /* check attribute lengths. */ - if (likely(nlh->nlmsg_len > min_len)) { - struct nlattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - nla_parse(cda, attr_count, attr, attrlen, NULL); - } - - /* implicit: if nlmsg_len == min_len, we return 0, and an empty - * (zeroed) cda[] array. The message is valid, but empty. */ - - return 0; -} - int nfnetlink_has_listeners(unsigned int group) { return netlink_has_listeners(nfnl, group); @@ -192,15 +163,22 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EINVAL; { - u_int16_t attr_count = - ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count; + int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); + u_int16_t attr_count = ss->cb[cb_id].attr_count; struct nlattr *cda[attr_count+1]; - memset(cda, 0, sizeof(struct nlattr *) * attr_count); + if (likely(nlh->nlmsg_len >= min_len)) { + struct nlattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + err = nla_parse(cda, attr_count, attr, attrlen, + ss->cb[cb_id].policy); + if (err < 0) + return err; + } else + return -EINVAL; - err = nfnetlink_check_attributes(ss, nlh, cda); - if (err < 0) - return err; return nc->call(nfnl, skb, nlh, cda); } } From fd8281adacd2ed68a92e7aa9dde239181f40ee15 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:39:09 -0700 Subject: [PATCH 1607/2804] [NETFILTER]: nfnetlink_log: use netlink policy Also remove unused nfula_min array. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink_log.c | 38 +++++++++-------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index b656648537c6..a90a26bd618b 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -733,29 +733,13 @@ static struct nf_logger nfulnl_logger = { .me = THIS_MODULE, }; -static const int nfula_min[NFULA_MAX+1] = { - [NFULA_PACKET_HDR] = sizeof(struct nfulnl_msg_packet_hdr), - [NFULA_MARK] = sizeof(u_int32_t), - [NFULA_TIMESTAMP] = sizeof(struct nfulnl_msg_packet_timestamp), - [NFULA_IFINDEX_INDEV] = sizeof(u_int32_t), - [NFULA_IFINDEX_OUTDEV] = sizeof(u_int32_t), - [NFULA_IFINDEX_PHYSINDEV] = sizeof(u_int32_t), - [NFULA_IFINDEX_PHYSOUTDEV] = sizeof(u_int32_t), - [NFULA_HWADDR] = sizeof(struct nfulnl_msg_packet_hw), - [NFULA_PAYLOAD] = 0, - [NFULA_PREFIX] = 0, - [NFULA_UID] = sizeof(u_int32_t), - [NFULA_SEQ] = sizeof(u_int32_t), - [NFULA_SEQ_GLOBAL] = sizeof(u_int32_t), -}; - -static const int nfula_cfg_min[NFULA_CFG_MAX+1] = { - [NFULA_CFG_CMD] = sizeof(struct nfulnl_msg_config_cmd), - [NFULA_CFG_MODE] = sizeof(struct nfulnl_msg_config_mode), - [NFULA_CFG_TIMEOUT] = sizeof(u_int32_t), - [NFULA_CFG_QTHRESH] = sizeof(u_int32_t), - [NFULA_CFG_NLBUFSIZ] = sizeof(u_int32_t), - [NFULA_CFG_FLAGS] = sizeof(u_int16_t), +static const struct nla_policy nfula_cfg_policy[NFULA_CFG_MAX+1] = { + [NFULA_CFG_CMD] = { .len = sizeof(struct nfulnl_msg_config_cmd) }, + [NFULA_CFG_MODE] = { .len = sizeof(struct nfulnl_msg_config_mode) }, + [NFULA_CFG_TIMEOUT] = { .type = NLA_U32 }, + [NFULA_CFG_QTHRESH] = { .type = NLA_U32 }, + [NFULA_CFG_NLBUFSIZ] = { .type = NLA_U32 }, + [NFULA_CFG_FLAGS] = { .type = NLA_U16 }, }; static int @@ -769,11 +753,6 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, UDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type)); - if (nlattr_bad_size(nfula, NFULA_CFG_MAX, nfula_cfg_min)) { - UDEBUG("bad attribute size\n"); - return -EINVAL; - } - inst = instance_lookup_get(group_num); if (nfula[NFULA_CFG_CMD]) { u_int8_t pf = nfmsg->nfgen_family; @@ -886,7 +865,8 @@ static const struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = { [NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp, .attr_count = NFULA_MAX, }, [NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config, - .attr_count = NFULA_CFG_MAX, }, + .attr_count = NFULA_CFG_MAX, + .policy = nfula_cfg_policy }, }; static const struct nfnetlink_subsystem nfulnl_subsys = { From 5bf758539388fa9383afd539d052ae93229544b9 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:39:26 -0700 Subject: [PATCH 1608/2804] [NETFILTER]: nfnetlink_queue: use netlink policy Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink_queue.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 1c34668588f1..48e095a7de2d 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -777,10 +777,10 @@ static struct notifier_block nfqnl_rtnl_notifier = { .notifier_call = nfqnl_rcv_nl_event, }; -static const int nfqa_verdict_min[NFQA_MAX+1] = { - [NFQA_VERDICT_HDR] = sizeof(struct nfqnl_msg_verdict_hdr), - [NFQA_MARK] = sizeof(u_int32_t), - [NFQA_PAYLOAD] = 0, +static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = { + [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) }, + [NFQA_MARK] = { .type = NLA_U32 }, + [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, }; static int @@ -796,11 +796,6 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_queue_entry *entry; int err; - if (nlattr_bad_size(nfqa, NFQA_MAX, nfqa_verdict_min)) { - QDEBUG("bad attribute size\n"); - return -EINVAL; - } - queue = instance_lookup_get(queue_num); if (!queue) return -ENODEV; @@ -855,9 +850,9 @@ nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, return -ENOTSUPP; } -static const int nfqa_cfg_min[NFQA_CFG_MAX+1] = { - [NFQA_CFG_CMD] = sizeof(struct nfqnl_msg_config_cmd), - [NFQA_CFG_PARAMS] = sizeof(struct nfqnl_msg_config_params), +static const struct nla_policy nfqa_cfg_policy[NFQA_CFG_MAX+1] = { + [NFQA_CFG_CMD] = { .len = sizeof(struct nfqnl_msg_config_cmd) }, + [NFQA_CFG_PARAMS] = { .len = sizeof(struct nfqnl_msg_config_params) }, }; static struct nf_queue_handler nfqh = { @@ -876,11 +871,6 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, QDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type)); - if (nlattr_bad_size(nfqa, NFQA_CFG_MAX, nfqa_cfg_min)) { - QDEBUG("bad attribute size\n"); - return -EINVAL; - } - queue = instance_lookup_get(queue_num); if (nfqa[NFQA_CFG_CMD]) { struct nfqnl_msg_config_cmd *cmd; @@ -964,9 +954,11 @@ static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { [NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp, .attr_count = NFQA_MAX, }, [NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict, - .attr_count = NFQA_MAX, }, + .attr_count = NFQA_MAX, + .policy = nfqa_verdict_policy }, [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, - .attr_count = NFQA_CFG_MAX, }, + .attr_count = NFQA_CFG_MAX, + .policy = nfqa_cfg_policy }, }; static const struct nfnetlink_subsystem nfqnl_subsys = { From f73e924cdd166360e8cc9a1b193008fdc9b3e3e2 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:39:55 -0700 Subject: [PATCH 1609/2804] [NETFILTER]: ctnetlink: use netlink policy Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/netfilter/nf_conntrack_l3proto.h | 2 + include/net/netfilter/nf_conntrack_l4proto.h | 3 + .../netfilter/nf_conntrack_l3proto_ipv4.c | 10 +- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 12 +- .../netfilter/nf_conntrack_l3proto_ipv6.c | 10 +- .../netfilter/nf_conntrack_proto_icmpv6.c | 12 +- net/netfilter/nf_conntrack_core.c | 10 +- net/netfilter/nf_conntrack_netlink.c | 111 +++++++++--------- net/netfilter/nf_conntrack_proto_gre.c | 1 + net/netfilter/nf_conntrack_proto_tcp.c | 22 ++-- net/netfilter/nf_conntrack_proto_udp.c | 2 + net/netfilter/nf_conntrack_proto_udplite.c | 2 + 12 files changed, 97 insertions(+), 100 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index f6c372d4ec1f..15888fc7b72d 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h @@ -12,6 +12,7 @@ #ifndef _NF_CONNTRACK_L3PROTO_H #define _NF_CONNTRACK_L3PROTO_H #include +#include #include #include @@ -68,6 +69,7 @@ struct nf_conntrack_l3proto int (*nlattr_to_tuple)(struct nlattr *tb[], struct nf_conntrack_tuple *t); + const struct nla_policy *nla_policy; #ifdef CONFIG_SYSCTL struct ctl_table_header *ctl_table_header; diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 658daccc6b56..fb50c217ba0a 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -10,6 +10,7 @@ #ifndef _NF_CONNTRACK_L4PROTO_H #define _NF_CONNTRACK_L4PROTO_H #include +#include #include struct seq_file; @@ -75,6 +76,7 @@ struct nf_conntrack_l4proto const struct nf_conntrack_tuple *t); int (*nlattr_to_tuple)(struct nlattr *tb[], struct nf_conntrack_tuple *t); + const struct nla_policy *nla_policy; #ifdef CONFIG_SYSCTL struct ctl_table_header **ctl_table_header; @@ -115,6 +117,7 @@ extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple); extern int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t); +extern const struct nla_policy nf_ct_port_nla_policy[]; /* Log invalid packets */ extern unsigned int nf_ct_log_invalid; diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 77ca556aad91..2fcb9249a8da 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -373,9 +373,9 @@ nla_put_failure: return -1; } -static const size_t cta_min_ip[CTA_IP_MAX+1] = { - [CTA_IP_V4_SRC] = sizeof(u_int32_t), - [CTA_IP_V4_DST] = sizeof(u_int32_t), +static const struct nla_policy ipv4_nla_policy[CTA_IP_MAX+1] = { + [CTA_IP_V4_SRC] = { .type = NLA_U32 }, + [CTA_IP_V4_DST] = { .type = NLA_U32 }, }; static int ipv4_nlattr_to_tuple(struct nlattr *tb[], @@ -384,9 +384,6 @@ static int ipv4_nlattr_to_tuple(struct nlattr *tb[], if (!tb[CTA_IP_V4_SRC] || !tb[CTA_IP_V4_DST]) return -EINVAL; - if (nlattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) - return -EINVAL; - t->src.u3.ip = *(__be32 *)nla_data(tb[CTA_IP_V4_SRC]); t->dst.u3.ip = *(__be32 *)nla_data(tb[CTA_IP_V4_DST]); @@ -413,6 +410,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = { #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = ipv4_tuple_to_nlattr, .nlattr_to_tuple = ipv4_nlattr_to_tuple, + .nla_policy = ipv4_nla_policy, #endif #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) .ctl_table_path = nf_net_ipv4_netfilter_sysctl_path, diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index ca7252c10758..11fedc73049c 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -248,10 +248,10 @@ nla_put_failure: return -1; } -static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { - [CTA_PROTO_ICMP_TYPE] = sizeof(u_int8_t), - [CTA_PROTO_ICMP_CODE] = sizeof(u_int8_t), - [CTA_PROTO_ICMP_ID] = sizeof(u_int16_t) +static const struct nla_policy icmp_nla_policy[CTA_PROTO_MAX+1] = { + [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 }, + [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 }, + [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 }, }; static int icmp_nlattr_to_tuple(struct nlattr *tb[], @@ -262,9 +262,6 @@ static int icmp_nlattr_to_tuple(struct nlattr *tb[], || !tb[CTA_PROTO_ICMP_ID]) return -EINVAL; - if (nlattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) - return -EINVAL; - tuple->dst.u.icmp.type = *(u_int8_t *)nla_data(tb[CTA_PROTO_ICMP_TYPE]); tuple->dst.u.icmp.code = @@ -329,6 +326,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = icmp_tuple_to_nlattr, .nlattr_to_tuple = icmp_nlattr_to_tuple, + .nla_policy = icmp_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_header = &icmp_sysctl_header, diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 567fbe230ce6..37a3db926953 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -350,9 +350,9 @@ nla_put_failure: return -1; } -static const size_t cta_min_ip[CTA_IP_MAX+1] = { - [CTA_IP_V6_SRC] = sizeof(u_int32_t)*4, - [CTA_IP_V6_DST] = sizeof(u_int32_t)*4, +static const struct nla_policy ipv6_nla_policy[CTA_IP_MAX+1] = { + [CTA_IP_V6_SRC] = { .len = sizeof(u_int32_t)*4 }, + [CTA_IP_V6_DST] = { .len = sizeof(u_int32_t)*4 }, }; static int ipv6_nlattr_to_tuple(struct nlattr *tb[], @@ -361,9 +361,6 @@ static int ipv6_nlattr_to_tuple(struct nlattr *tb[], if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST]) return -EINVAL; - if (nlattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) - return -EINVAL; - memcpy(&t->src.u3.ip6, nla_data(tb[CTA_IP_V6_SRC]), sizeof(u_int32_t) * 4); memcpy(&t->dst.u3.ip6, nla_data(tb[CTA_IP_V6_DST]), @@ -384,6 +381,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = ipv6_tuple_to_nlattr, .nlattr_to_tuple = ipv6_nlattr_to_tuple, + .nla_policy = ipv6_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_path = nf_net_netfilter_sysctl_path, diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 238ea6bc864e..fbdc66920de4 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -226,10 +226,10 @@ nla_put_failure: return -1; } -static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { - [CTA_PROTO_ICMPV6_TYPE] = sizeof(u_int8_t), - [CTA_PROTO_ICMPV6_CODE] = sizeof(u_int8_t), - [CTA_PROTO_ICMPV6_ID] = sizeof(u_int16_t) +static const struct nla_policy icmpv6_nla_policy[CTA_PROTO_MAX+1] = { + [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 }, + [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 }, + [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 }, }; static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], @@ -240,9 +240,6 @@ static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], || !tb[CTA_PROTO_ICMPV6_ID]) return -EINVAL; - if (nlattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) - return -EINVAL; - tuple->dst.u.icmp.type = *(u_int8_t *)nla_data(tb[CTA_PROTO_ICMPV6_TYPE]); tuple->dst.u.icmp.code = @@ -291,6 +288,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = icmpv6_tuple_to_nlattr, .nlattr_to_tuple = icmpv6_nlattr_to_tuple, + .nla_policy = icmpv6_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_header = &icmpv6_sysctl_header, diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 9edaaf2d57e7..f9d36cab70f4 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -844,10 +844,11 @@ nla_put_failure: } EXPORT_SYMBOL_GPL(nf_ct_port_tuple_to_nlattr); -static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { - [CTA_PROTO_SRC_PORT] = sizeof(u_int16_t), - [CTA_PROTO_DST_PORT] = sizeof(u_int16_t) +const struct nla_policy nf_ct_port_nla_policy[CTA_PROTO_MAX+1] = { + [CTA_PROTO_SRC_PORT] = { .type = NLA_U16 }, + [CTA_PROTO_DST_PORT] = { .type = NLA_U16 }, }; +EXPORT_SYMBOL_GPL(nf_ct_port_nla_policy); int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *t) @@ -855,9 +856,6 @@ int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], if (!tb[CTA_PROTO_SRC_PORT] || !tb[CTA_PROTO_DST_PORT]) return -EINVAL; - if (nlattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) - return -EINVAL; - t->src.u.tcp.port = *(__be16 *)nla_data(tb[CTA_PROTO_SRC_PORT]); t->dst.u.tcp.port = *(__be16 *)nla_data(tb[CTA_PROTO_DST_PORT]); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 9f9bef2446a1..ce3581266b87 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -512,16 +512,20 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple) l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); - if (likely(l3proto->nlattr_to_tuple)) - ret = l3proto->nlattr_to_tuple(tb, tuple); + if (likely(l3proto->nlattr_to_tuple)) { + ret = nla_validate_nested(attr, CTA_IP_MAX, + l3proto->nla_policy); + if (ret == 0) + ret = l3proto->nlattr_to_tuple(tb, tuple); + } nf_ct_l3proto_put(l3proto); return ret; } -static const size_t cta_min_proto[CTA_PROTO_MAX+1] = { - [CTA_PROTO_NUM] = sizeof(u_int8_t), +static const struct nla_policy proto_nla_policy[CTA_PROTO_MAX+1] = { + [CTA_PROTO_NUM] = { .type = NLA_U8 }, }; static inline int @@ -532,10 +536,9 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, struct nf_conntrack_l4proto *l4proto; int ret = 0; - nla_parse_nested(tb, CTA_PROTO_MAX, attr, NULL); - - if (nlattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) - return -EINVAL; + ret = nla_parse_nested(tb, CTA_PROTO_MAX, attr, proto_nla_policy); + if (ret < 0) + return ret; if (!tb[CTA_PROTO_NUM]) return -EINVAL; @@ -543,8 +546,12 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); - if (likely(l4proto->nlattr_to_tuple)) - ret = l4proto->nlattr_to_tuple(tb, tuple); + if (likely(l4proto->nlattr_to_tuple)) { + ret = nla_validate_nested(attr, CTA_PROTO_MAX, + l4proto->nla_policy); + if (ret == 0) + ret = l4proto->nlattr_to_tuple(tb, tuple); + } nf_ct_l4proto_put(l4proto); @@ -588,9 +595,9 @@ ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple, } #ifdef CONFIG_NF_NAT_NEEDED -static const size_t cta_min_protonat[CTA_PROTONAT_MAX+1] = { - [CTA_PROTONAT_PORT_MIN] = sizeof(u_int16_t), - [CTA_PROTONAT_PORT_MAX] = sizeof(u_int16_t), +static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = { + [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 }, + [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 }, }; static int nfnetlink_parse_nat_proto(struct nlattr *attr, @@ -599,11 +606,11 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr, { struct nlattr *tb[CTA_PROTONAT_MAX+1]; struct nf_nat_protocol *npt; + int err; - nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, NULL); - - if (nlattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) - return -EINVAL; + err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy); + if (err < 0) + return err; npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); @@ -621,9 +628,9 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr, return 0; } -static const size_t cta_min_nat[CTA_NAT_MAX+1] = { - [CTA_NAT_MINIP] = sizeof(u_int32_t), - [CTA_NAT_MAXIP] = sizeof(u_int32_t), +static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = { + [CTA_NAT_MINIP] = { .type = NLA_U32 }, + [CTA_NAT_MAXIP] = { .type = NLA_U32 }, }; static inline int @@ -635,10 +642,9 @@ nfnetlink_parse_nat(struct nlattr *nat, memset(range, 0, sizeof(*range)); - nla_parse_nested(tb, CTA_NAT_MAX, nat, NULL); - - if (nlattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) - return -EINVAL; + err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy); + if (err < 0) + return err; if (tb[CTA_NAT_MINIP]) range->min_ip = *(__be32 *)nla_data(tb[CTA_NAT_MINIP]); @@ -677,12 +683,12 @@ ctnetlink_parse_help(struct nlattr *attr, char **helper_name) return 0; } -static const size_t cta_min[CTA_MAX+1] = { - [CTA_STATUS] = sizeof(u_int32_t), - [CTA_TIMEOUT] = sizeof(u_int32_t), - [CTA_MARK] = sizeof(u_int32_t), - [CTA_USE] = sizeof(u_int32_t), - [CTA_ID] = sizeof(u_int32_t) +static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { + [CTA_STATUS] = { .type = NLA_U32 }, + [CTA_TIMEOUT] = { .type = NLA_U32 }, + [CTA_MARK] = { .type = NLA_U32 }, + [CTA_USE] = { .type = NLA_U32 }, + [CTA_ID] = { .type = NLA_U32 }, }; static int @@ -696,9 +702,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - if (nlattr_bad_size(cda, CTA_MAX, cta_min)) - return -EINVAL; - if (cda[CTA_TUPLE_ORIG]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); else if (cda[CTA_TUPLE_REPLY]) @@ -754,9 +757,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, ctnetlink_done); } - if (nlattr_bad_size(cda, CTA_MAX, cta_min)) - return -EINVAL; - if (cda[CTA_TUPLE_ORIG]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); else if (cda[CTA_TUPLE_REPLY]) @@ -1045,9 +1045,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - if (nlattr_bad_size(cda, CTA_MAX, cta_min)) - return -EINVAL; - if (cda[CTA_TUPLE_ORIG]) { err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3); if (err < 0) @@ -1313,9 +1310,9 @@ out: return skb->len; } -static const size_t cta_min_exp[CTA_EXPECT_MAX+1] = { - [CTA_EXPECT_TIMEOUT] = sizeof(u_int32_t), - [CTA_EXPECT_ID] = sizeof(u_int32_t) +static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { + [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 }, + [CTA_EXPECT_ID] = { .type = NLA_U32 }, }; static int @@ -1329,9 +1326,6 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - if (nlattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) - return -EINVAL; - if (nlh->nlmsg_flags & NLM_F_DUMP) { return netlink_dump_start(ctnl, skb, nlh, ctnetlink_exp_dump_table, @@ -1393,9 +1387,6 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, unsigned int i; int err; - if (nlattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) - return -EINVAL; - if (cda[CTA_EXPECT_TUPLE]) { /* delete a single expect by tuple */ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); @@ -1534,9 +1525,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, u_int8_t u3 = nfmsg->nfgen_family; int err = 0; - if (nlattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) - return -EINVAL; - if (!cda[CTA_EXPECT_TUPLE] || !cda[CTA_EXPECT_MASK] || !cda[CTA_EXPECT_MASTER]) @@ -1577,22 +1565,29 @@ static struct notifier_block ctnl_notifier_exp = { static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, - .attr_count = CTA_MAX, }, + .attr_count = CTA_MAX, + .policy = ct_nla_policy }, [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, - .attr_count = CTA_MAX, }, + .attr_count = CTA_MAX, + .policy = ct_nla_policy }, [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, - .attr_count = CTA_MAX, }, + .attr_count = CTA_MAX, + .policy = ct_nla_policy }, [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, - .attr_count = CTA_MAX, }, + .attr_count = CTA_MAX, + .policy = ct_nla_policy }, }; static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, - .attr_count = CTA_EXPECT_MAX, }, + .attr_count = CTA_EXPECT_MAX, + .policy = exp_nla_policy }, [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, - .attr_count = CTA_EXPECT_MAX, }, + .attr_count = CTA_EXPECT_MAX, + .policy = exp_nla_policy }, [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, - .attr_count = CTA_EXPECT_MAX, }, + .attr_count = CTA_EXPECT_MAX, + .policy = exp_nla_policy }, }; static const struct nfnetlink_subsystem ctnl_subsys = { diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index ff8d03b88402..4a185f6aa65a 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -276,6 +276,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, #endif }; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 84f47bc90f63..df718e7c7ee4 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1105,28 +1105,28 @@ nla_put_failure: return -1; } -static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX+1] = { - [CTA_PROTOINFO_TCP_STATE] = sizeof(u_int8_t), - [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = sizeof(u_int8_t), - [CTA_PROTOINFO_TCP_WSCALE_REPLY] = sizeof(u_int8_t), - [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = sizeof(struct nf_ct_tcp_flags), - [CTA_PROTOINFO_TCP_FLAGS_REPLY] = sizeof(struct nf_ct_tcp_flags) +static const struct nla_policy tcp_nla_policy[CTA_PROTOINFO_TCP_MAX+1] = { + [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 }, + [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 }, + [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 }, + [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .len = sizeof(struct nf_ct_tcp_flags) }, + [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .len = sizeof(struct nf_ct_tcp_flags) }, }; static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) { struct nlattr *attr = cda[CTA_PROTOINFO_TCP]; struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1]; + int err; /* updates could not contain anything about the private * protocol info, in that case skip the parsing */ if (!attr) return 0; - nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr, NULL); - - if (nlattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp)) - return -EINVAL; + err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr, tcp_nla_policy); + if (err < 0) + return err; if (!tb[CTA_PROTOINFO_TCP_STATE]) return -EINVAL; @@ -1391,6 +1391,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = .from_nlattr = nlattr_to_tcp, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &tcp_sysctl_table_users, @@ -1420,6 +1421,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = .from_nlattr = nlattr_to_tcp, .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &tcp_sysctl_table_users, diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 751ff7e2a0d9..ba80e1a1ea17 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -205,6 +205,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &udp_sysctl_table_users, @@ -232,6 +233,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &udp_sysctl_table_users, diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 4209ddb8fbaf..b8981dd922be 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -205,6 +205,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &udplite_sysctl_table_users, @@ -228,6 +229,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, #endif #ifdef CONFIG_SYSCTL .ctl_table_users = &udplite_sysctl_table_users, From 2b5c841f2c41c023809e3b6b95a8320246cf7f5a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:40:56 -0700 Subject: [PATCH 1610/2804] [NETFILTER]: nfnetlink: kill nlattr_bad_size Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index cd8fded36550..0d8424f76899 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -73,19 +73,6 @@ struct nfnetlink_subsystem extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); -#define nlattr_bad_size(tb, max, cta_min) \ -({ int __i, __res = 0; \ - for (__i=1; __i <= max; __i++) { \ - if (!cta_min[__i]) \ - continue; \ - if (tb[__i] && nla_len(tb[__i]) < cta_min[__i]){ \ - __res = 1; \ - break; \ - } \ - } \ - __res; \ -}) - extern int nfnetlink_has_listeners(unsigned int group); extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo); From 7f85f914721ffcef382a57995182916bd43d8a65 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:41:27 -0700 Subject: [PATCH 1611/2804] [NETFILTER]: nf_conntrack: kill unique ID Remove the per-conntrack ID, its not necessary anymore for dumping. For compatiblity reasons we send the address of the conntrack to userspace as ID. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/netfilter/nf_conntrack.h | 3 --- net/netfilter/nf_conntrack_core.c | 2 -- net/netfilter/nf_conntrack_netlink.c | 4 ++-- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 810020ec345d..90fb66d99d0c 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -116,9 +116,6 @@ struct nf_conn struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; #endif - /* Unique ID that identifies this conntrack*/ - unsigned int id; - #if defined(CONFIG_NF_CONNTRACK_MARK) u_int32_t mark; #endif diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f9d36cab70f4..83c30b45d170 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -63,7 +63,6 @@ unsigned int nf_ct_log_invalid __read_mostly; HLIST_HEAD(unconfirmed); static int nf_conntrack_vmalloc __read_mostly; static struct kmem_cache *nf_conntrack_cachep __read_mostly; -static unsigned int nf_conntrack_next_id; DEFINE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat); EXPORT_PER_CPU_SYMBOL(nf_conntrack_stat); @@ -287,7 +286,6 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct, unsigned int hash, unsigned int repl_hash) { - ct->id = ++nf_conntrack_next_id; hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, &nf_conntrack_hash[hash]); hlist_add_head(&ct->tuplehash[IP_CT_DIR_REPLY].hnode, diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index ce3581266b87..8406aee1cdee 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -257,7 +257,7 @@ nla_put_failure: static inline int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) { - __be32 id = htonl(ct->id); + __be32 id = htonl((unsigned long)ct); NLA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); return 0; @@ -723,7 +723,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, if (cda[CTA_ID]) { u_int32_t id = ntohl(*(__be32 *)nla_data(cda[CTA_ID])); - if (ct->id != id) { + if (id != (u32)(unsigned long)ct) { nf_ct_put(ct); return -ENOENT; } From 3583240249ef354760e04ae49bd7b462a638f40c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 28 Sep 2007 14:41:50 -0700 Subject: [PATCH 1612/2804] [NETFILTER]: nf_conntrack_expect: kill unique ID Similar to the conntrack ID, the per-expectation ID is not needed anymore, kill it. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/netfilter/nf_conntrack_expect.h | 3 --- net/netfilter/nf_conntrack_expect.c | 2 -- net/netfilter/nf_conntrack_netlink.c | 6 +++--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index cae1a0dce365..b47c04f12dbe 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -38,9 +38,6 @@ struct nf_conntrack_expect /* Usage count. */ atomic_t use; - /* Unique ID */ - unsigned int id; - /* Flags */ unsigned int flags; diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 8a3e3af656bf..7a0ae36c9b47 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -41,7 +41,6 @@ static int nf_ct_expect_hash_rnd_initted __read_mostly; static int nf_ct_expect_vmalloc; static struct kmem_cache *nf_ct_expect_cachep __read_mostly; -static unsigned int nf_ct_expect_next_id; /* nf_conntrack_expect helper functions */ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) @@ -302,7 +301,6 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) exp->timeout.expires = jiffies + master_help->helper->timeout * HZ; add_timer(&exp->timeout); - exp->id = ++nf_ct_expect_next_id; atomic_inc(&exp->use); NF_CT_STAT_INC(expect_create); } diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 8406aee1cdee..2abd648f7d6f 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1160,7 +1160,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, { struct nf_conn *master = exp->master; __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ); - __be32 id = htonl(exp->id); + __be32 id = htonl((unsigned long)exp); if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) goto nla_put_failure; @@ -1346,7 +1346,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (cda[CTA_EXPECT_ID]) { __be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]); - if (exp->id != ntohl(id)) { + if (ntohl(id) != (u32)(unsigned long)exp) { nf_ct_expect_put(exp); return -ENOENT; } @@ -1400,7 +1400,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, if (cda[CTA_EXPECT_ID]) { __be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]); - if (exp->id != ntohl(id)) { + if (ntohl(id) != (u32)(unsigned long)exp) { nf_ct_expect_put(exp); return -ENOENT; } From 5faa1f4cb5a1f124f76172d775467f4a9db5b452 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 28 Sep 2007 14:43:53 -0700 Subject: [PATCH 1613/2804] [NETFILTER]: nf_conntrack_netlink: add support to related connections This patch adds support to relate a connection to an existing master connection. This patch is used by conntrackd to correctly replicate related connections. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink_conntrack.h | 1 + net/netfilter/nf_conntrack_netlink.c | 43 +++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index d7c35039721e..4affa3fe78e0 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -36,6 +36,7 @@ enum ctattr_type { CTA_USE, CTA_ID, CTA_NAT_DST, + CTA_TUPLE_MASTER, __CTA_MAX }; #define CTA_MAX (__CTA_MAX - 1) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 2abd648f7d6f..9be1826e6cdd 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -4,7 +4,7 @@ * (C) 2001 by Jay Schulist * (C) 2002-2006 by Harald Welte * (C) 2003 by Patrick Mchardy - * (C) 2005-2006 by Pablo Neira Ayuso + * (C) 2005-2007 by Pablo Neira Ayuso * * Initial connection tracking via netlink development funded and * generally made possible by Network Robots, Inc. (www.networkrobots.com) @@ -975,7 +975,8 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) static int ctnetlink_create_conntrack(struct nlattr *cda[], struct nf_conntrack_tuple *otuple, - struct nf_conntrack_tuple *rtuple) + struct nf_conntrack_tuple *rtuple, + struct nf_conn *master_ct) { struct nf_conn *ct; int err = -EINVAL; @@ -1022,6 +1023,10 @@ ctnetlink_create_conntrack(struct nlattr *cda[], rcu_assign_pointer(help->helper, helper); } + /* setup master conntrack: this is a confirmed expectation */ + if (master_ct) + ct->master = master_ct; + add_timer(&ct->timeout); nf_conntrack_hash_insert(ct); @@ -1064,10 +1069,37 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, h = __nf_conntrack_find(&rtuple, NULL); if (h == NULL) { + struct nf_conntrack_tuple master; + struct nf_conntrack_tuple_hash *master_h = NULL; + struct nf_conn *master_ct = NULL; + + if (cda[CTA_TUPLE_MASTER]) { + err = ctnetlink_parse_tuple(cda, + &master, + CTA_TUPLE_MASTER, + u3); + if (err < 0) + return err; + + master_h = __nf_conntrack_find(&master, NULL); + if (master_h == NULL) { + err = -ENOENT; + goto out_unlock; + } + master_ct = nf_ct_tuplehash_to_ctrack(master_h); + atomic_inc(&master_ct->ct_general.use); + } + write_unlock_bh(&nf_conntrack_lock); err = -ENOENT; if (nlh->nlmsg_flags & NLM_F_CREATE) - err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); + err = ctnetlink_create_conntrack(cda, + &otuple, + &rtuple, + master_ct); + if (err < 0 && master_ct) + nf_ct_put(master_ct); + return err; } /* implicit 'else' */ @@ -1081,6 +1113,11 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, err = -EINVAL; goto out_unlock; } + /* can't link an existing conntrack to a master */ + if (cda[CTA_TUPLE_MASTER]) { + err = -EINVAL; + goto out_unlock; + } err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda); } From e35670614d10588fb9c6ed32ecd55b8242e98872 Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Fri, 28 Sep 2007 14:44:21 -0700 Subject: [PATCH 1614/2804] [NETFILTER]: nfnetlink_log: kill duplicate code Kill some cut'n'paste effect. Just after __nfulnl_send() returning, inst->skb is always NULL. Signed-off-by: Michal Miroslaw Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink_log.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index a90a26bd618b..512741afca9f 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -188,7 +188,7 @@ out_unlock: return NULL; } -static int __nfulnl_send(struct nfulnl_instance *inst); +static void __nfulnl_flush(struct nfulnl_instance *inst); static void __instance_destroy(struct nfulnl_instance *inst) @@ -202,17 +202,8 @@ __instance_destroy(struct nfulnl_instance *inst) /* then flush all pending packets from skb */ spin_lock_bh(&inst->lock); - if (inst->skb) { - /* timer "holds" one reference (we have one more) */ - if (del_timer(&inst->timer)) - instance_put(inst); - if (inst->qlen) - __nfulnl_send(inst); - if (inst->skb) { - kfree_skb(inst->skb); - inst->skb = NULL; - } - } + if (inst->skb) + __nfulnl_flush(inst); spin_unlock_bh(&inst->lock); /* and finally put the refcount */ @@ -364,6 +355,16 @@ nlmsg_failure: return status; } +static void +__nfulnl_flush(struct nfulnl_instance *inst) +{ + /* timer holds a reference */ + if (del_timer(&inst->timer)) + instance_put(inst); + if (inst->skb) + __nfulnl_send(inst); +} + static void nfulnl_timer(unsigned long data) { struct nfulnl_instance *inst = (struct nfulnl_instance *)data; @@ -650,10 +651,7 @@ nfulnl_log_packet(unsigned int pf, * enough room in the skb left. flush to userspace. */ UDEBUG("flushing old skb\n"); - /* timer "holds" one reference (we have another one) */ - if (del_timer(&inst->timer)) - instance_put(inst); - __nfulnl_send(inst); + __nfulnl_flush(inst); } if (!inst->skb) { From d63b043d955c261f4f413eecf6e0488d7459acd4 Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Fri, 28 Sep 2007 14:44:44 -0700 Subject: [PATCH 1615/2804] [NETFILTER]: nfnetlink_log: flush queue early If queue is filled to its threshold, then flush it right away instead of waiting for timer or next packet. Signed-off-by: Michal Miroslaw Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink_log.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 512741afca9f..0fa17421bbc6 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -644,9 +644,8 @@ nfulnl_log_packet(unsigned int pf, goto unlock_and_release; } - if (inst->qlen >= qthreshold || - (inst->skb && size > - skb_tailroom(inst->skb) - sizeof(struct nfgenmsg))) { + if (inst->skb && + size > skb_tailroom(inst->skb) - sizeof(struct nfgenmsg)) { /* either the queue len is too high or we don't have * enough room in the skb left. flush to userspace. */ UDEBUG("flushing old skb\n"); @@ -666,9 +665,11 @@ nfulnl_log_packet(unsigned int pf, __build_packet_message(inst, skb, data_len, pf, hooknum, in, out, li, prefix, plen); + if (inst->qlen >= qthreshold) + __nfulnl_flush(inst); /* timer_pending always called within inst->lock, so there * is no chance of a race here */ - if (!timer_pending(&inst->timer)) { + else if (!timer_pending(&inst->timer)) { instance_get(inst); inst->timer.expires = jiffies + (inst->flushtimeout*HZ/100); add_timer(&inst->timer); From c6a8f648362a5d8b934f4267b0ab9f255c130ab0 Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Fri, 28 Sep 2007 14:45:06 -0700 Subject: [PATCH 1616/2804] [NETFILTER]: nfnetlink_log: fix style Fix function definition style to match other functions in nfnetlink_log.c. Signed-off-by: Michal Miroslaw Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink_log.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 0fa17421bbc6..d2e811f46067 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -301,8 +301,8 @@ nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags) return 0; } -static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size, - unsigned int pkt_size) +static struct sk_buff * +nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size) { struct sk_buff *skb; unsigned int n; @@ -365,7 +365,8 @@ __nfulnl_flush(struct nfulnl_instance *inst) __nfulnl_send(inst); } -static void nfulnl_timer(unsigned long data) +static void +nfulnl_timer(unsigned long data) { struct nfulnl_instance *inst = (struct nfulnl_instance *)data; From aace57e054e9322e20af52cede7de46ade64a5e2 Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Fri, 28 Sep 2007 14:45:27 -0700 Subject: [PATCH 1617/2804] [NETFILTER]: nfnetlink_log: fix instance_create() failure path Fix memory leak on instance_create() while module is being unloaded. Signed-off-by: Michal Miroslaw Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink_log.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index d2e811f46067..16ae53918606 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -152,6 +152,11 @@ instance_create(u_int16_t group_num, int pid) if (!inst) goto out_unlock; + if (!try_module_get(THIS_MODULE)) { + kfree(inst); + goto out_unlock; + } + INIT_HLIST_NODE(&inst->hlist); spin_lock_init(&inst->lock); /* needs to be two, since we _put() after creation */ @@ -168,9 +173,6 @@ instance_create(u_int16_t group_num, int pid) inst->copy_mode = NFULNL_COPY_PACKET; inst->copy_range = 0xffff; - if (!try_module_get(THIS_MODULE)) - goto out_free; - hlist_add_head(&inst->hlist, &instance_table[instance_hashfn(group_num)]); @@ -181,8 +183,6 @@ instance_create(u_int16_t group_num, int pid) return inst; -out_free: - instance_put(inst); out_unlock: write_unlock_bh(&instances_lock); return NULL; From 6b6ec99a03601aba0419f34e17630f7aa8d68e5f Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Fri, 28 Sep 2007 14:45:52 -0700 Subject: [PATCH 1618/2804] [NETFILTER]: nfnetlink_log: fix some constants Fix timeout (one second is 1 * HZ) and convert max packet copy length to #defined constant. Signed-off-by: Michal Miroslaw Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink_log.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 16ae53918606..2135926199ca 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -37,8 +37,9 @@ #endif #define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE -#define NFULNL_TIMEOUT_DEFAULT 100 /* every second */ +#define NFULNL_TIMEOUT_DEFAULT HZ /* every second */ #define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */ +#define NFULNL_COPY_RANGE_MAX 0xFFFF /* max packet size is limited by 16-bit struct nfattr nfa_len field */ #define PRINTR(x, args...) do { if (net_ratelimit()) \ printk(x, ## args); } while (0); @@ -171,7 +172,7 @@ instance_create(u_int16_t group_num, int pid) inst->flushtimeout = NFULNL_TIMEOUT_DEFAULT; inst->nlbufsiz = NFULNL_NLBUFSIZ_DEFAULT; inst->copy_mode = NFULNL_COPY_PACKET; - inst->copy_range = 0xffff; + inst->copy_range = NFULNL_COPY_RANGE_MAX; hlist_add_head(&inst->hlist, &instance_table[instance_hashfn(group_num)]); @@ -235,11 +236,8 @@ nfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode, case NFULNL_COPY_PACKET: inst->copy_mode = mode; - /* we're using struct nlattr which has 16bit nfa_len */ - if (range > 0xffff) - inst->copy_range = 0xffff; - else - inst->copy_range = range; + inst->copy_range = min_t(unsigned int, + range, NFULNL_COPY_RANGE_MAX); break; default: From ee4411a1b1e0b679c99686629b5eab5a072ce49f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 28 Sep 2007 14:46:43 -0700 Subject: [PATCH 1619/2804] [NETFILTER]: x_tables: add xt_time match This is ipt_time from POM-ng enhanced by the following: * xtables/ipv6 support * second granularity for daytime * day-of-month support (for example "match on the 15th of each month") * match against UTC or local timezone Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/xt_time.h | 25 +++ net/netfilter/Kconfig | 14 ++ net/netfilter/Makefile | 1 + net/netfilter/xt_time.c | 269 ++++++++++++++++++++++++++++++ 4 files changed, 309 insertions(+) create mode 100644 include/linux/netfilter/xt_time.h create mode 100644 net/netfilter/xt_time.c diff --git a/include/linux/netfilter/xt_time.h b/include/linux/netfilter/xt_time.h new file mode 100644 index 000000000000..14b6df412c9f --- /dev/null +++ b/include/linux/netfilter/xt_time.h @@ -0,0 +1,25 @@ +#ifndef _XT_TIME_H +#define _XT_TIME_H 1 + +struct xt_time_info { + u_int32_t date_start; + u_int32_t date_stop; + u_int32_t daytime_start; + u_int32_t daytime_stop; + u_int32_t monthdays_match; + u_int8_t weekdays_match; + u_int8_t flags; +}; + +enum { + /* Match against local time (instead of UTC) */ + XT_TIME_LOCAL_TZ = 1 << 0, + + /* Shortcuts */ + XT_TIME_ALL_MONTHDAYS = 0xFFFFFFFE, + XT_TIME_ALL_WEEKDAYS = 0xFE, + XT_TIME_MIN_DAYTIME = 0, + XT_TIME_MAX_DAYTIME = 24 * 60 * 60 - 1, +}; + +#endif /* _XT_TIME_H */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 3599770a2473..d7a600a5720a 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -665,6 +665,20 @@ config NETFILTER_XT_MATCH_TCPMSS To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_MATCH_TIME + tristate '"time" match support' + depends on NETFILTER_XTABLES + ---help--- + This option adds a "time" match, which allows you to match based on + the packet arrival time (at the machine which netfilter is running) + on) or departure time/date (for locally generated packets). + + If you say Y here, try `iptables -m time --help` for + more information. + + If you want to compile it as a module, say M here. + If unsure, say N. + config NETFILTER_XT_MATCH_U32 tristate '"u32" match support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 0c054bf27973..93c58f973831 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o +obj-$(CONFIG_NETFILTER_XT_MATCH_TIME) += xt_time.o obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c new file mode 100644 index 000000000000..ef48bbd93573 --- /dev/null +++ b/net/netfilter/xt_time.c @@ -0,0 +1,269 @@ +/* + * xt_time + * Copyright ยฉ Jan Engelhardt , 2007 + * + * based on ipt_time by Fabrice MARIE + * This is a module which is used for time matching + * It is using some modified code from dietlibc (localtime() function) + * that you can find at http://www.fefe.de/dietlibc/ + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from gnu.org/gpl. + */ +#include +#include +#include +#include +#include +#include + +struct xtm { + u_int8_t month; /* (1-12) */ + u_int8_t monthday; /* (1-31) */ + u_int8_t weekday; /* (1-7) */ + u_int8_t hour; /* (0-23) */ + u_int8_t minute; /* (0-59) */ + u_int8_t second; /* (0-59) */ + unsigned int dse; +}; + +extern struct timezone sys_tz; /* ouch */ + +static const u_int16_t days_since_year[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, +}; + +static const u_int16_t days_since_leapyear[] = { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, +}; + +/* + * Since time progresses forward, it is best to organize this array in reverse, + * to minimize lookup time. + */ +enum { + DSE_FIRST = 2039, +}; +static const u_int16_t days_since_epoch[] = { + /* 2039 - 2030 */ + 25202, 24837, 24472, 24106, 23741, 23376, 23011, 22645, 22280, 21915, + /* 2029 - 2020 */ + 21550, 21184, 20819, 20454, 20089, 19723, 19358, 18993, 18628, 18262, + /* 2019 - 2010 */ + 17897, 17532, 17167, 16801, 16436, 16071, 15706, 15340, 14975, 14610, + /* 2009 - 2000 */ + 14245, 13879, 13514, 13149, 12784, 12418, 12053, 11688, 11323, 10957, + /* 1999 - 1990 */ + 10592, 10227, 9862, 9496, 9131, 8766, 8401, 8035, 7670, 7305, + /* 1989 - 1980 */ + 6940, 6574, 6209, 5844, 5479, 5113, 4748, 4383, 4018, 3652, + /* 1979 - 1970 */ + 3287, 2922, 2557, 2191, 1826, 1461, 1096, 730, 365, 0, +}; + +static inline bool is_leap(unsigned int y) +{ + return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); +} + +/* + * Each network packet has a (nano)seconds-since-the-epoch (SSTE) timestamp. + * Since we match against days and daytime, the SSTE value needs to be + * computed back into human-readable dates. + * + * This is done in three separate functions so that the most expensive + * calculations are done last, in case a "simple match" can be found earlier. + */ +static inline unsigned int localtime_1(struct xtm *r, time_t time) +{ + unsigned int v, w; + + /* Each day has 86400s, so finding the hour/minute is actually easy. */ + v = time % 86400; + r->second = v % 60; + w = v / 60; + r->minute = w % 60; + r->hour = w / 60; + return v; +} + +static inline void localtime_2(struct xtm *r, time_t time) +{ + /* + * Here comes the rest (weekday, monthday). First, divide the SSTE + * by seconds-per-day to get the number of _days_ since the epoch. + */ + r->dse = time / 86400; + + /* 1970-01-01 (w=0) was a Thursday (4). */ + r->weekday = (4 + r->dse) % 7; +} + +static void localtime_3(struct xtm *r, time_t time) +{ + unsigned int year, i, w = r->dse; + + /* + * In each year, a certain number of days-since-the-epoch have passed. + * Find the year that is closest to said days. + * + * Consider, for example, w=21612 (2029-03-04). Loop will abort on + * dse[i] <= w, which happens when dse[i] == 21550. This implies + * year == 2009. w will then be 62. + */ + for (i = 0, year = DSE_FIRST; days_since_epoch[i] > w; + ++i, --year) + /* just loop */; + + w -= days_since_epoch[i]; + + /* + * By now we have the current year, and the day of the year. + * r->yearday = w; + * + * On to finding the month (like above). In each month, a certain + * number of days-since-New Year have passed, and find the closest + * one. + * + * Consider w=62 (in a non-leap year). Loop will abort on + * dsy[i] < w, which happens when dsy[i] == 31+28 (i == 2). + * Concludes i == 2, i.e. 3rd month => March. + * + * (A different approach to use would be to subtract a monthlength + * from w repeatedly while counting.) + */ + if (is_leap(year)) { + for (i = ARRAY_SIZE(days_since_leapyear) - 1; + i > 0 && days_since_year[i] > w; --i) + /* just loop */; + } else { + for (i = ARRAY_SIZE(days_since_year) - 1; + i > 0 && days_since_year[i] > w; --i) + /* just loop */; + } + + r->month = i + 1; + r->monthday = w - days_since_year[i] + 1; + return; +} + +static bool xt_time_match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct xt_match *match, const void *matchinfo, + int offset, unsigned int protoff, bool *hotdrop) +{ + const struct xt_time_info *info = matchinfo; + unsigned int packet_time; + struct xtm current_time; + s64 stamp; + + /* + * We cannot use get_seconds() instead of __net_timestamp() here. + * Suppose you have two rules: + * 1. match before 13:00 + * 2. match after 13:00 + * If you match against processing time (get_seconds) it + * may happen that the same packet matches both rules if + * it arrived at the right moment before 13:00. + */ + if (skb->tstamp.tv64 == 0) + __net_timestamp((struct sk_buff *)skb); + + stamp = skb->tstamp.tv64; + do_div(stamp, NSEC_PER_SEC); + + if (info->flags & XT_TIME_LOCAL_TZ) + /* Adjust for local timezone */ + stamp -= 60 * sys_tz.tz_minuteswest; + + /* + * xt_time will match when _all_ of the following hold: + * - 'now' is in the global time range date_start..date_end + * - 'now' is in the monthday mask + * - 'now' is in the weekday mask + * - 'now' is in the daytime range time_start..time_end + * (and by default, libxt_time will set these so as to match) + */ + + if (stamp < info->date_start || stamp > info->date_stop) + return false; + + packet_time = localtime_1(¤t_time, stamp); + + if (info->daytime_start < info->daytime_stop) { + if (packet_time < info->daytime_start || + packet_time > info->daytime_stop) + return false; + } else { + if (packet_time < info->daytime_start && + packet_time > info->daytime_stop) + return false; + } + + localtime_2(¤t_time, stamp); + + if (!(info->weekdays_match & (1 << current_time.weekday))) + return false; + + /* Do not spend time computing monthday if all days match anyway */ + if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) { + localtime_3(¤t_time, stamp); + if (!(info->monthdays_match & (1 << current_time.monthday))) + return false; + } + + return true; +} + +static bool xt_time_check(const char *tablename, const void *ip, + const struct xt_match *match, void *matchinfo, + unsigned int hook_mask) +{ + struct xt_time_info *info = matchinfo; + + if (info->daytime_start > XT_TIME_MAX_DAYTIME || + info->daytime_stop > XT_TIME_MAX_DAYTIME) { + printk(KERN_WARNING "xt_time: invalid argument - start or " + "stop time greater than 23:59:59\n"); + return false; + } + + return true; +} + +static struct xt_match xt_time_reg[] __read_mostly = { + { + .name = "time", + .family = AF_INET, + .match = xt_time_match, + .matchsize = sizeof(struct xt_time_info), + .checkentry = xt_time_check, + .me = THIS_MODULE, + }, + { + .name = "time", + .family = AF_INET6, + .match = xt_time_match, + .matchsize = sizeof(struct xt_time_info), + .checkentry = xt_time_check, + .me = THIS_MODULE, + }, +}; + +static int __init xt_time_init(void) +{ + return xt_register_matches(xt_time_reg, ARRAY_SIZE(xt_time_reg)); +} + +static void __exit xt_time_exit(void) +{ + xt_unregister_matches(xt_time_reg, ARRAY_SIZE(xt_time_reg)); +} + +module_init(xt_time_init); +module_exit(xt_time_exit); +MODULE_AUTHOR("Jan Engelhardt "); +MODULE_DESCRIPTION("netfilter time match"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_time"); +MODULE_ALIAS("ip6t_time"); From 587117414909e9c52f50e3c9d1f85b3dc1815d75 Mon Sep 17 00:00:00 2001 From: Joseph Fannin Date: Fri, 28 Sep 2007 14:47:32 -0700 Subject: [PATCH 1620/2804] [NETFILTER]: bridge: remove broken netfilter binary sysctls The netfilter sysctls in the bridging code don't set strategy routines: sysctl table check failed: /net/bridge/bridge-nf-call-arptables .3.10.1 Missing strategy sysctl table check failed: /net/bridge/bridge-nf-call-iptables .3.10.2 Missing strategy sysctl table check failed: /net/bridge/bridge-nf-call-ip6tables .3.10.3 Missing strategy sysctl table check failed: /net/bridge/bridge-nf-filter-vlan-tagged .3.10.4 Missing strategy sysctl table check failed: /net/bridge/bridge-nf-filter-pppoe-tagged .3.10.5 Missing strategy These binary sysctls can't work. The binary sysctl numbers of other netfilter sysctls with this problem are being removed. These need to go as well. Signed-off-by: Joseph Fannin Acked-by: "Eric W. Biederman" Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/bridge/br_netfilter.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index fc13130035e7..8245f051ccbb 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -904,7 +904,6 @@ int brnf_sysctl_call_tables(ctl_table * ctl, int write, struct file *filp, static ctl_table brnf_table[] = { { - .ctl_name = NET_BRIDGE_NF_CALL_ARPTABLES, .procname = "bridge-nf-call-arptables", .data = &brnf_call_arptables, .maxlen = sizeof(int), @@ -912,7 +911,6 @@ static ctl_table brnf_table[] = { .proc_handler = &brnf_sysctl_call_tables, }, { - .ctl_name = NET_BRIDGE_NF_CALL_IPTABLES, .procname = "bridge-nf-call-iptables", .data = &brnf_call_iptables, .maxlen = sizeof(int), @@ -920,7 +918,6 @@ static ctl_table brnf_table[] = { .proc_handler = &brnf_sysctl_call_tables, }, { - .ctl_name = NET_BRIDGE_NF_CALL_IP6TABLES, .procname = "bridge-nf-call-ip6tables", .data = &brnf_call_ip6tables, .maxlen = sizeof(int), @@ -928,7 +925,6 @@ static ctl_table brnf_table[] = { .proc_handler = &brnf_sysctl_call_tables, }, { - .ctl_name = NET_BRIDGE_NF_FILTER_VLAN_TAGGED, .procname = "bridge-nf-filter-vlan-tagged", .data = &brnf_filter_vlan_tagged, .maxlen = sizeof(int), @@ -936,7 +932,6 @@ static ctl_table brnf_table[] = { .proc_handler = &brnf_sysctl_call_tables, }, { - .ctl_name = NET_BRIDGE_NF_FILTER_PPPOE_TAGGED, .procname = "bridge-nf-filter-pppoe-tagged", .data = &brnf_filter_pppoe_tagged, .maxlen = sizeof(int), From de90351219a1f1fd3cb45cf6fcc4e9d6407fd2c9 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 28 Sep 2007 15:33:51 -0700 Subject: [PATCH 1621/2804] [IPoIB]: Convert to netdevice internal stats Use the stats member of struct netdevice in IPoIB, so we can save memory by deleting the stats member of struct ipoib_dev_priv, and save code by deleting ipoib_get_stats(). Signed-off-by: Roland Dreier Signed-off-by: David S. Miller --- drivers/infiniband/ulp/ipoib/ipoib.h | 2 -- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 20 ++++++++--------- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 18 +++++++-------- drivers/infiniband/ulp/ipoib/ipoib_main.c | 22 ++++++------------- .../infiniband/ulp/ipoib/ipoib_multicast.c | 10 ++++----- 5 files changed, 31 insertions(+), 41 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 35f3ca42bd60..34c6128d2a34 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -280,8 +280,6 @@ struct ipoib_dev_priv { struct ib_event_handler event_handler; - struct net_device_stats stats; - struct net_device *parent; struct list_head child_intfs; struct list_head list; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 08b4676a3820..1afd93cdd6bb 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -430,7 +430,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) ipoib_dbg(priv, "cm recv error " "(status=%d, wrid=%d vend_err %x)\n", wc->status, wr_id, wc->vendor_err); - ++priv->stats.rx_dropped; + ++dev->stats.rx_dropped; goto repost; } @@ -457,7 +457,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) * this packet and reuse the old buffer. */ ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id); - ++priv->stats.rx_dropped; + ++dev->stats.rx_dropped; goto repost; } @@ -474,8 +474,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb_pull(skb, IPOIB_ENCAP_LEN); dev->last_rx = jiffies; - ++priv->stats.rx_packets; - priv->stats.rx_bytes += skb->len; + ++dev->stats.rx_packets; + dev->stats.rx_bytes += skb->len; skb->dev = dev; /* XXX get correct PACKET_ type here */ @@ -512,8 +512,8 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ if (unlikely(skb->len > tx->mtu)) { ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", skb->len, tx->mtu); - ++priv->stats.tx_dropped; - ++priv->stats.tx_errors; + ++dev->stats.tx_dropped; + ++dev->stats.tx_errors; ipoib_cm_skb_too_long(dev, skb, tx->mtu - IPOIB_ENCAP_LEN); return; } @@ -532,7 +532,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ tx_req->skb = skb; addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE); if (unlikely(ib_dma_mapping_error(priv->ca, addr))) { - ++priv->stats.tx_errors; + ++dev->stats.tx_errors; dev_kfree_skb_any(skb); return; } @@ -542,7 +542,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), addr, skb->len))) { ipoib_warn(priv, "post_send failed\n"); - ++priv->stats.tx_errors; + ++dev->stats.tx_errors; ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); } else { @@ -580,8 +580,8 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE); /* FIXME: is this right? Shouldn't we only increment on success? */ - ++priv->stats.tx_packets; - priv->stats.tx_bytes += tx_req->skb->len; + ++dev->stats.tx_packets; + dev->stats.tx_bytes += tx_req->skb->len; dev_kfree_skb_any(tx_req->skb); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 481e4b6bd949..0ec28c302fbf 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -208,7 +208,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) * this packet and reuse the old buffer. */ if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) { - ++priv->stats.rx_dropped; + ++dev->stats.rx_dropped; goto repost; } @@ -225,8 +225,8 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb_pull(skb, IPOIB_ENCAP_LEN); dev->last_rx = jiffies; - ++priv->stats.rx_packets; - priv->stats.rx_bytes += skb->len; + ++dev->stats.rx_packets; + dev->stats.rx_bytes += skb->len; skb->dev = dev; /* XXX get correct PACKET_ type here */ @@ -260,8 +260,8 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE); - ++priv->stats.tx_packets; - priv->stats.tx_bytes += tx_req->skb->len; + ++dev->stats.tx_packets; + dev->stats.tx_bytes += tx_req->skb->len; dev_kfree_skb_any(tx_req->skb); @@ -362,8 +362,8 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) { ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN); - ++priv->stats.tx_dropped; - ++priv->stats.tx_errors; + ++dev->stats.tx_dropped; + ++dev->stats.tx_errors; ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu); return; } @@ -383,7 +383,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE); if (unlikely(ib_dma_mapping_error(priv->ca, addr))) { - ++priv->stats.tx_errors; + ++dev->stats.tx_errors; dev_kfree_skb_any(skb); return; } @@ -392,7 +392,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), address->ah, qpn, addr, skb->len))) { ipoib_warn(priv, "post_send failed\n"); - ++priv->stats.tx_errors; + ++dev->stats.tx_errors; ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); } else { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 2bd76ef57154..6b1b4b2ec5ba 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -517,7 +517,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) neigh = ipoib_neigh_alloc(skb->dst->neighbour); if (!neigh) { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); return; } @@ -582,7 +582,7 @@ err_list: err_path: ipoib_neigh_free(dev, neigh); err_drop: - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); spin_unlock(&priv->lock); @@ -631,7 +631,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, } else __path_add(dev, path); } else { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } @@ -650,7 +650,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, skb_push(skb, sizeof *phdr); __skb_queue_tail(&path->queue, skb); } else { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } @@ -718,7 +718,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) __skb_queue_tail(&neigh->queue, skb); spin_unlock(&priv->lock); } else { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } } else { @@ -744,7 +744,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) IPOIB_QPN(phdr->hwaddr), IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); dev_kfree_skb_any(skb); - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; goto out; } @@ -758,13 +758,6 @@ out: return NETDEV_TX_OK; } -static struct net_device_stats *ipoib_get_stats(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - - return &priv->stats; -} - static void ipoib_timeout(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -865,7 +858,7 @@ void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh) struct sk_buff *skb; *to_ipoib_neigh(neigh->neighbour) = NULL; while ((skb = __skb_dequeue(&neigh->queue))) { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } if (ipoib_cm_get(neigh)) @@ -952,7 +945,6 @@ static void ipoib_setup(struct net_device *dev) dev->stop = ipoib_stop; dev->change_mtu = ipoib_change_mtu; dev->hard_start_xmit = ipoib_start_xmit; - dev->get_stats = ipoib_get_stats; dev->tx_timeout = ipoib_timeout; dev->header_ops = &ipoib_header_ops; dev->set_multicast_list = ipoib_set_mcast_list; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index aae367057a56..98e904a7f3e8 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -125,7 +125,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) } spin_lock_irqsave(&priv->tx_lock, flags); - priv->stats.tx_dropped += tx_dropped; + dev->stats.tx_dropped += tx_dropped; spin_unlock_irqrestore(&priv->tx_lock, flags); kfree(mcast); @@ -320,7 +320,7 @@ ipoib_mcast_sendonly_join_complete(int status, /* Flush out any queued packets */ spin_lock_irq(&priv->tx_lock); while (!skb_queue_empty(&mcast->pkt_queue)) { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); } spin_unlock_irq(&priv->tx_lock); @@ -675,7 +675,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) if (!test_bit(IPOIB_MCAST_STARTED, &priv->flags) || !priv->broadcast || !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); goto unlock; } @@ -690,7 +690,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) if (!mcast) { ipoib_warn(priv, "unable to allocate memory for " "multicast structure\n"); - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); goto out; } @@ -705,7 +705,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE) skb_queue_tail(&mcast->pkt_queue, skb); else { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } From 6a290e3d5d48e8932fae068a558b3d8dff4c7acf Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 26 Sep 2007 16:23:31 -0500 Subject: [PATCH 1622/2804] pasemi_mac: set interface speed correctly on XAUI ports pasemi_mac: set interface speed correctly on XAUI ports Set interface speed for XAUI to 10G per default, not 1G. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 912bc5d33d28..daba11062d3b 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -789,7 +789,10 @@ static int pasemi_mac_open(struct net_device *dev) flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; - flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; + if (mac->type == MAC_TYPE_GMAC) + flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; + else + flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G; write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); From ca7e235f5eb960d83b45cef4384b490672538cd9 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 26 Sep 2007 16:23:59 -0500 Subject: [PATCH 1623/2804] pasemi_mac: flags as passed to spin_*_irqsave() should be unsigned long pasemi_mac: flags as passed to spin_*_irqsave() should be unsigned long. Signed-off-by: Tony Breeds Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index daba11062d3b..8892b658655c 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -552,7 +552,7 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) struct pas_dma_xct_descr *dp; unsigned int start, count, limit; unsigned int total_count; - int flags; + unsigned long flags; struct sk_buff *skbs[32]; dma_addr_t dmas[32]; @@ -973,7 +973,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) struct pas_dma_xct_descr *dp; u64 dflags, mactx, ptr; dma_addr_t map; - int flags; + unsigned long flags; dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD; From 36033766533176d61ba15793d8ef219775499c2f Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 26 Sep 2007 16:24:42 -0500 Subject: [PATCH 1624/2804] pasemi_mac: don't enable rx before there are buffers on the ring pasemi_mac: don't enable rx before there are buffers on the ring Reorder initialization of the DMA channels and the interface. Before there was a time window when the interface was enabled before DMA was enabled. Also, now there will always be RX buffers available at the time the MAC interface is enabled, to avoid temporary out-of-buffer errors for the very first packets (on busy networks). Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 8892b658655c..643fce860e5c 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -786,14 +786,6 @@ static int pasemi_mac_open(struct net_device *dev) write_mac_reg(mac, PAS_MAC_CFG_TXP, flags); - flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | - PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; - - if (mac->type == MAC_TYPE_GMAC) - flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; - else - flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G; - write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); @@ -808,8 +800,6 @@ static int pasemi_mac_open(struct net_device *dev) write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG, PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); - write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); - ret = pasemi_mac_setup_rx_resources(dev); if (ret) goto out_rx_resources; @@ -837,6 +827,17 @@ static int pasemi_mac_open(struct net_device *dev) pasemi_mac_replenish_rx_ring(dev); + flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | + PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; + + if (mac->type == MAC_TYPE_GMAC) + flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; + else + flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G; + + /* Enable interface in MAC */ + write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); + ret = pasemi_mac_phy_init(dev); /* Some configs don't have PHYs (XAUI etc), so don't complain about * failed init due to -ENODEV. From 928773c23a4cf053a34ad480439448f75efa350c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 26 Sep 2007 16:25:06 -0500 Subject: [PATCH 1625/2804] pasemi_mac: pass in count of buffers to replenish rx ring with pasemi_mac: pass in count of buffers to replenish rx ring with Refactor replenish_rx_ring to take an argument for how many entries to fill. Since it's normally available from where it's called anyway, this is just simpler. It also removes the awkward logic to try to figure out if we're filling for the first time or not. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 643fce860e5c..c2d34a804d40 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -370,23 +370,18 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) mac->rx = NULL; } -static void pasemi_mac_replenish_rx_ring(struct net_device *dev) +static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) { struct pasemi_mac *mac = netdev_priv(dev); unsigned int i; int start = mac->rx->next_to_fill; - unsigned int limit, count; - - limit = RING_AVAIL(mac->rx); - /* Check to see if we're doing first-time setup */ - if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) - limit = RX_RING_SIZE; + int count; if (limit <= 0) return; i = start; - for (count = limit; count; count--) { + for (count = 0; count < limit; count++) { struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); u64 *buff = &RX_BUFF(mac, i); struct sk_buff *skb; @@ -417,10 +412,10 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) wmb(); - write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), limit - count); - write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), limit - count); + write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count); + write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count); - mac->rx->next_to_fill += limit - count; + mac->rx->next_to_fill += count; } static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) @@ -538,7 +533,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } mac->rx->next_to_clean += limit - count; - pasemi_mac_replenish_rx_ring(mac->netdev); + pasemi_mac_replenish_rx_ring(mac->netdev, limit-count); spin_unlock(&mac->rx->lock); @@ -825,7 +820,7 @@ static int pasemi_mac_open(struct net_device *dev) write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_EN); - pasemi_mac_replenish_rx_ring(dev); + pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE); flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; From c7e86e344b3599c0679a4a1f59a27953856f181c Mon Sep 17 00:00:00 2001 From: Nathanael Nerode Date: Wed, 26 Sep 2007 18:14:45 -0700 Subject: [PATCH 1626/2804] dgrs: remove from build, config, and maintainer list Stop building and configuring driver for Digi RightSwitch, which was never actually sold to anyone, and remove it from MAINTAINERS. In response to an investigation into the firmware of the "Digi Rightswitch" driver, Andres Salomon discovered: > > Dear Andres: > > After further research, we found that this product was killed in place > and never reached the market. We would like to request that this not be > included. Since the product never reached market, clearly nobody is using this orphaned driver. Signed-off-by: Nathanael Nerode Cc: "David S. Miller" Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- Documentation/networking/dgrs.txt | 52 - MAINTAINERS | 6 - drivers/net/Kconfig | 15 - drivers/net/Makefile | 1 - drivers/net/dgrs.c | 1593 ----- drivers/net/dgrs.h | 38 - drivers/net/dgrs_asstruct.h | 37 - drivers/net/dgrs_bcomm.h | 148 - drivers/net/dgrs_es4h.h | 183 - drivers/net/dgrs_ether.h | 135 - drivers/net/dgrs_firmware.c | 9966 ----------------------------- drivers/net/dgrs_i82596.h | 473 -- drivers/net/dgrs_plx9060.h | 175 - 13 files changed, 12822 deletions(-) delete mode 100644 Documentation/networking/dgrs.txt delete mode 100644 drivers/net/dgrs.c delete mode 100644 drivers/net/dgrs.h delete mode 100644 drivers/net/dgrs_asstruct.h delete mode 100644 drivers/net/dgrs_bcomm.h delete mode 100644 drivers/net/dgrs_es4h.h delete mode 100644 drivers/net/dgrs_ether.h delete mode 100644 drivers/net/dgrs_firmware.c delete mode 100644 drivers/net/dgrs_i82596.h delete mode 100644 drivers/net/dgrs_plx9060.h diff --git a/Documentation/networking/dgrs.txt b/Documentation/networking/dgrs.txt deleted file mode 100644 index 1aa1bb3f94ab..000000000000 --- a/Documentation/networking/dgrs.txt +++ /dev/null @@ -1,52 +0,0 @@ - The Digi International RightSwitch SE-X (dgrs) Device Driver - -This is a Linux driver for the Digi International RightSwitch SE-X -EISA and PCI boards. These are 4 (EISA) or 6 (PCI) port Ethernet -switches and a NIC combined into a single board. This driver can -be compiled into the kernel statically or as a loadable module. - -There is also a companion management tool, called "xrightswitch". -The management tool lets you watch the performance graphically, -as well as set the SNMP agent IP and IPX addresses, IEEE Spanning -Tree, and Aging time. These can also be set from the command line -when the driver is loaded. The driver command line options are: - - debug=NNN Debug printing level - dma=0/1 Disable/Enable DMA on PCI card - spantree=0/1 Disable/Enable IEEE spanning tree - hashexpire=NNN Change address aging time (default 300 seconds) - ipaddr=A,B,C,D Set SNMP agent IP address i.e. 199,86,8,221 - iptrap=A,B,C,D Set SNMP agent IP trap address i.e. 199,86,8,221 - ipxnet=NNN Set SNMP agent IPX network number - nicmode=0/1 Disable/Enable multiple NIC mode - -There is also a tool for setting up input and output packet filters -on each port, called "dgrsfilt". - -Both the management tool and the filtering tool are available -separately from the following FTP site: - - ftp://ftp.dgii.com/drivers/rightswitch/linux/ - -When nicmode=1, the board and driver operate as 4 or 6 individual -NIC ports (eth0...eth5) instead of as a switch. All switching -functions are disabled. In the future, the board firmware may include -a routing cache when in this mode. - -Copyright 1995-1996 Digi International Inc. - -This software may be used and distributed according to the terms -of the GNU General Public License, incorporated herein by reference. - -For information on purchasing a RightSwitch SE-4 or SE-6 -board, please contact Digi's sales department at 1-612-912-3444 -or 1-800-DIGIBRD. Outside the U.S., please check our Web page at: - - http://www.dgii.com - -for sales offices worldwide. Tech support is also available through -the channels listed on the Web site, although as long as I am -employed on networking products at Digi I will be happy to provide -any bug fixes that may be needed. - --Rick Richardson, rick@dgii.com diff --git a/MAINTAINERS b/MAINTAINERS index 27e1110ec6ca..16646801105c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1274,12 +1274,6 @@ L: Eng.Linux@digi.com W: http://www.digi.com S: Orphaned -DIGI RIGHTSWITCH NETWORK DRIVER -P: Rick Richardson -L: netdev@vger.kernel.org -W: http://www.digi.com -S: Orphaned - DIRECTORY NOTIFICATION P: Stephen Rothwell M: sfr@canb.auug.org.au diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 467532c7975c..764325917f6a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1459,21 +1459,6 @@ config TC35815 depends on NET_PCI && PCI && MIPS select MII -config DGRS - tristate "Digi Intl. RightSwitch SE-X support" - depends on NET_PCI && (PCI || EISA) - ---help--- - This is support for the Digi International RightSwitch series of - PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 - models. If you have a network card of this type, say Y and read the - Ethernet-HOWTO, available from - . More specific - information is contained in . - - To compile this driver as a module, choose M here and read - . The module - will be called dgrs. - config EEPRO100 tristate "EtherExpressPro/100 support (eepro100, original Becker driver)" depends on NET_PCI && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6220c50596ec..eb5c655e26d5 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -44,7 +44,6 @@ obj-$(CONFIG_SUNVNET) += sunvnet.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o -obj-$(CONFIG_DGRS) += dgrs.o obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_TYPHOON) += typhoon.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c deleted file mode 100644 index 054f2ba5f698..000000000000 --- a/drivers/net/dgrs.c +++ /dev/null @@ -1,1593 +0,0 @@ -/* - * Digi RightSwitch SE-X loadable device driver for Linux - * - * The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and - * a NIC on an internal board. - * - * Author: Rick Richardson, rick@remotepoint.com - * Derived from the SVR4.2 (UnixWare) driver for the same card. - * - * Copyright 1995-1996 Digi International Inc. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For information on purchasing a RightSwitch SE-4 or SE-6 - * board, please contact Digi's sales department at 1-612-912-3444 - * or 1-800-DIGIBRD. Outside the U.S., please check our Web page - * at http://www.dgii.com for sales offices worldwide. - * - * OPERATION: - * When compiled as a loadable module, this driver can operate - * the board as either a 4/6 port switch with a 5th or 7th port - * that is a conventional NIC interface as far as the host is - * concerned, OR as 4/6 independent NICs. To select multi-NIC - * mode, add "nicmode=1" on the insmod load line for the driver. - * - * This driver uses the "dev" common ethernet device structure - * and a private "priv" (dev->priv) structure that contains - * mostly DGRS-specific information and statistics. To keep - * the code for both the switch mode and the multi-NIC mode - * as similar as possible, I have introduced the concept of - * "dev0"/"priv0" and "devN"/"privN" pointer pairs in subroutines - * where needed. The first pair of pointers points to the - * "dev" and "priv" structures of the zeroth (0th) device - * interface associated with a board. The second pair of - * pointers points to the current (Nth) device interface - * for the board: the one for which we are processing data. - * - * In switch mode, the pairs of pointers are always the same, - * that is, dev0 == devN and priv0 == privN. This is just - * like previous releases of this driver which did not support - * NIC mode. - * - * In multi-NIC mode, the pairs of pointers may be different. - * We use the devN and privN pointers to reference just the - * name, port number, and statistics for the current interface. - * We use the dev0 and priv0 pointers to access the variables - * that control access to the board, such as board address - * and simulated 82596 variables. This is because there is - * only one "fake" 82596 that serves as the interface to - * the board. We do not want to try to keep the variables - * associated with this 82596 in sync across all devices. - * - * This scheme works well. As you will see, except for - * initialization, there is very little difference between - * the two modes as far as this driver is concerned. On the - * receive side in NIC mode, the interrupt *always* comes in on - * the 0th interface (dev0/priv0). We then figure out which - * real 82596 port it came in on from looking at the "chan" - * member that the board firmware adds at the end of each - * RBD (a.k.a. TBD). We get the channel number like this: - * int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan; - * - * On the transmit side in multi-NIC mode, we specify the - * output 82596 port by setting the new "dstchan" structure - * member that is at the end of the RFD, like this: - * priv0->rfdp->dstchan = privN->chan; - * - * TODO: - * - Multi-NIC mode is not yet supported when the driver is linked - * into the kernel. - * - Better handling of multicast addresses. - * - * Fixes: - * Arnaldo Carvalho de Melo - 11/01/2001 - * - fix dgrs_found_device wrt checking kmalloc return and - * rollbacking the partial steps of the whole process when - * one of the devices can't be allocated. Fix SET_MODULE_OWNER - * on the loop to use devN instead of repeated calls to dev. - * - * davej - 9/2/2001 - * - Enable PCI device before reading ioaddr/irq - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static char version[] __initdata = - "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $"; - -/* - * DGRS include files - */ -typedef unsigned char uchar; -#define vol volatile - -#include "dgrs.h" -#include "dgrs_es4h.h" -#include "dgrs_plx9060.h" -#include "dgrs_i82596.h" -#include "dgrs_ether.h" -#include "dgrs_asstruct.h" -#include "dgrs_bcomm.h" - -#ifdef CONFIG_PCI -static struct pci_device_id dgrs_pci_tbl[] = { - { SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl); -#endif - -#ifdef CONFIG_EISA -static struct eisa_device_id dgrs_eisa_tbl[] = { - { "DBI0A01" }, - { } -}; -MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl); -#endif - -MODULE_LICENSE("GPL"); - - -/* - * Firmware. Compiled separately for local compilation, - * but #included for Linux distribution. - */ -#ifndef NOFW - #include "dgrs_firmware.c" -#else - extern int dgrs_firmnum; - extern char dgrs_firmver[]; - extern char dgrs_firmdate[]; - extern uchar dgrs_code[]; - extern int dgrs_ncode; -#endif - -/* - * Linux out*() is backwards from all other operating systems - */ -#define OUTB(ADDR, VAL) outb(VAL, ADDR) -#define OUTW(ADDR, VAL) outw(VAL, ADDR) -#define OUTL(ADDR, VAL) outl(VAL, ADDR) - -/* - * Macros to convert switch to host and host to switch addresses - * (assumes a local variable priv points to board dependent struct) - */ -#define S2H(A) ( ((unsigned long)(A)&0x00ffffff) + priv0->vmem ) -#define S2HN(A) ( ((unsigned long)(A)&0x00ffffff) + privN->vmem ) -#define H2S(A) ( ((char *) (A) - priv0->vmem) + 0xA3000000 ) - -/* - * Convert a switch address to a "safe" address for use with the - * PLX 9060 DMA registers and the associated HW kludge that allows - * for host access of the DMA registers. - */ -#define S2DMA(A) ( (unsigned long)(A) & 0x00ffffff) - -/* - * "Space.c" variables, now settable from module interface - * Use the name below, minus the "dgrs_" prefix. See init_module(). - */ -static int dgrs_debug = 1; -static int dgrs_dma = 1; -static int dgrs_spantree = -1; -static int dgrs_hashexpire = -1; -static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff}; -static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff}; -static __u32 dgrs_ipxnet = -1; -static int dgrs_nicmode; - -/* - * Private per-board data structure (dev->priv) - */ -typedef struct -{ - /* - * DGRS specific data - */ - char *vmem; - - struct bios_comm *bcomm; /* Firmware BIOS comm structure */ - PORT *port; /* Ptr to PORT[0] struct in VM */ - I596_SCB *scbp; /* Ptr to SCB struct in VM */ - I596_RFD *rfdp; /* Current RFD list */ - I596_RBD *rbdp; /* Current RBD list */ - - volatile int intrcnt; /* Count of interrupts */ - - /* - * SE-4 (EISA) board variables - */ - uchar is_reg; /* EISA: Value for ES4H_IS reg */ - - /* - * SE-6 (PCI) board variables - * - * The PLX "expansion rom" space is used for DMA register - * access from the host on the SE-6. These are the physical - * and virtual addresses of that space. - */ - ulong plxreg; /* Phys address of PLX chip */ - char *vplxreg; /* Virtual address of PLX chip */ - ulong plxdma; /* Phys addr of PLX "expansion rom" */ - ulong volatile *vplxdma; /* Virtual addr of "expansion rom" */ - int use_dma; /* Flag: use DMA */ - DMACHAIN *dmadesc_s; /* area for DMA chains (SW addr.) */ - DMACHAIN *dmadesc_h; /* area for DMA chains (Host Virtual) */ - - /* - * Multi-NIC mode variables - * - * All entries of the devtbl[] array are valid for the 0th - * device (i.e. eth0, but not eth1...eth5). devtbl[0] is - * valid for all devices (i.e. eth0, eth1, ..., eth5). - */ - int nports; /* Number of physical ports (4 or 6) */ - int chan; /* Channel # (1-6) for this device */ - struct net_device *devtbl[6]; /* Ptrs to N device structs */ - -} DGRS_PRIV; - - -/* - * reset or un-reset the IDT processor - */ -static void -proc_reset(struct net_device *dev0, int reset) -{ - DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; - - if (priv0->plxreg) - { - ulong val; - val = inl(dev0->base_addr + PLX_MISC_CSR); - if (reset) - val |= SE6_RESET; - else - val &= ~SE6_RESET; - OUTL(dev0->base_addr + PLX_MISC_CSR, val); - } - else - { - OUTB(dev0->base_addr + ES4H_PC, reset ? ES4H_PC_RESET : 0); - } -} - -/* - * See if the board supports bus master DMA - */ -static int -check_board_dma(struct net_device *dev0) -{ - DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; - ulong x; - - /* - * If Space.c says not to use DMA, or if it's not a PLX based - * PCI board, or if the expansion ROM space is not PCI - * configured, then return false. - */ - if (!dgrs_dma || !priv0->plxreg || !priv0->plxdma) - return (0); - - /* - * Set the local address remap register of the "expansion rom" - * area to 0x80000000 so that we can use it to access the DMA - * registers from the host side. - */ - OUTL(dev0->base_addr + PLX_ROM_BASE_ADDR, 0x80000000); - - /* - * Set the PCI region descriptor to: - * Space 0: - * disable read-prefetch - * enable READY - * enable BURST - * 0 internal wait states - * Expansion ROM: (used for host DMA register access) - * disable read-prefetch - * enable READY - * disable BURST - * 0 internal wait states - */ - OUTL(dev0->base_addr + PLX_BUS_REGION, 0x49430343); - - /* - * Now map the DMA registers into our virtual space - */ - priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256); - if (!priv0->vplxdma) - { - printk("%s: can't *remap() the DMA regs\n", dev0->name); - return (0); - } - - /* - * Now test to see if we can access the DMA registers - * If we write -1 and get back 1FFF, then we accessed the - * DMA register. Otherwise, we probably have an old board - * and wrote into regular RAM. - */ - priv0->vplxdma[PLX_DMA0_MODE/4] = 0xFFFFFFFF; - x = priv0->vplxdma[PLX_DMA0_MODE/4]; - if (x != 0x00001FFF) { - iounmap((void *)priv0->vplxdma); - return (0); - } - - return (1); -} - -/* - * Initiate DMA using PLX part on PCI board. Spin the - * processor until completed. All addresses are physical! - * - * If pciaddr is NULL, then it's a chaining DMA, and lcladdr is - * the address of the first DMA descriptor in the chain. - * - * If pciaddr is not NULL, then it's a single DMA. - * - * In either case, "lcladdr" must have been fixed up to make - * sure the MSB isn't set using the S2DMA macro before passing - * the address to this routine. - */ -static int -do_plx_dma( - struct net_device *dev, - ulong pciaddr, - ulong lcladdr, - int len, - int to_host -) -{ - int i; - ulong csr = 0; - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - - if (pciaddr) - { - /* - * Do a single, non-chain DMA - */ - priv->vplxdma[PLX_DMA0_PCI_ADDR/4] = pciaddr; - priv->vplxdma[PLX_DMA0_LCL_ADDR/4] = lcladdr; - priv->vplxdma[PLX_DMA0_SIZE/4] = len; - priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = to_host - ? PLX_DMA_DESC_TO_HOST - : PLX_DMA_DESC_TO_BOARD; - priv->vplxdma[PLX_DMA0_MODE/4] = - PLX_DMA_MODE_WIDTH32 - | PLX_DMA_MODE_WAITSTATES(0) - | PLX_DMA_MODE_READY - | PLX_DMA_MODE_NOBTERM - | PLX_DMA_MODE_BURST - | PLX_DMA_MODE_NOCHAIN; - } - else - { - /* - * Do a chaining DMA - */ - priv->vplxdma[PLX_DMA0_MODE/4] = - PLX_DMA_MODE_WIDTH32 - | PLX_DMA_MODE_WAITSTATES(0) - | PLX_DMA_MODE_READY - | PLX_DMA_MODE_NOBTERM - | PLX_DMA_MODE_BURST - | PLX_DMA_MODE_CHAIN; - priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = lcladdr; - } - - priv->vplxdma[PLX_DMA_CSR/4] = - PLX_DMA_CSR_0_ENABLE | PLX_DMA_CSR_0_START; - - /* - * Wait for DMA to complete - */ - for (i = 0; i < 1000000; ++i) - { - /* - * Spin the host CPU for 1 usec, so we don't thrash - * the PCI bus while the PLX 9060 is doing DMA. - */ - udelay(1); - - csr = (volatile unsigned long) priv->vplxdma[PLX_DMA_CSR/4]; - - if (csr & PLX_DMA_CSR_0_DONE) - break; - } - - if ( ! (csr & PLX_DMA_CSR_0_DONE) ) - { - printk("%s: DMA done never occurred. DMA disabled.\n", - dev->name); - priv->use_dma = 0; - return 1; - } - return 0; -} - -/* - * dgrs_rcv_frame() - * - * Process a received frame. This is called from the interrupt - * routine, and works for both switch mode and multi-NIC mode. - * - * Note that when in multi-NIC mode, we want to always access the - * hardware using the dev and priv structures of the first port, - * so that we are using only one set of variables to maintain - * the board interface status, but we want to use the Nth port - * dev and priv structures to maintain statistics and to pass - * the packet up. - * - * Only the first device structure is attached to the interrupt. - * We use the special "chan" variable at the end of the first RBD - * to select the Nth device in multi-NIC mode. - * - * We currently do chained DMA on a per-packet basis when the - * packet is "long", and we spin the CPU a short time polling - * for DMA completion. This avoids a second interrupt overhead, - * and gives the best performance for light traffic to the host. - * - * However, a better scheme that could be implemented would be - * to see how many packets are outstanding for the host, and if - * the number is "large", create a long chain to DMA several - * packets into the host in one go. In this case, we would set - * up some state variables to let the host CPU continue doing - * other things until a DMA completion interrupt comes along. - */ -static void -dgrs_rcv_frame( - struct net_device *dev0, - DGRS_PRIV *priv0, - I596_CB *cbp -) -{ - int len; - I596_TBD *tbdp; - struct sk_buff *skb; - uchar *putp; - uchar *p; - struct net_device *devN; - DGRS_PRIV *privN; - - /* - * Determine Nth priv and dev structure pointers - */ - if (dgrs_nicmode) - { /* Multi-NIC mode */ - int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan; - - devN = priv0->devtbl[chan-1]; - /* - * If devN is null, we got an interrupt before the I/F - * has been initialized. Pitch the packet. - */ - if (devN == NULL) - goto out; - privN = (DGRS_PRIV *) devN->priv; - } - else - { /* Switch mode */ - devN = dev0; - privN = priv0; - } - - if (0) printk("%s: rcv len=%ld\n", devN->name, cbp->xmit.count); - - /* - * Allocate a message block big enough to hold the whole frame - */ - len = cbp->xmit.count; - if ((skb = dev_alloc_skb(len+5)) == NULL) - { - printk("%s: dev_alloc_skb failed for rcv buffer\n", devN->name); - ++dev0->stats.rx_dropped; - /* discarding the frame */ - goto out; - } - skb_reserve(skb, 2); /* Align IP header */ - -again: - putp = p = skb_put(skb, len); - - /* - * There are three modes here for doing the packet copy. - * If we have DMA, and the packet is "long", we use the - * chaining mode of DMA. If it's shorter, we use single - * DMA's. Otherwise, we use memcpy(). - */ - if (priv0->use_dma && priv0->dmadesc_h && len > 64) - { - /* - * If we can use DMA and it's a long frame, copy it using - * DMA chaining. - */ - DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */ - DMACHAIN *ddp_s; /* Switch physical DMA desc. pointer */ - uchar *phys_p; - - /* - * Get the physical address of the STREAMS buffer. - * NOTE: allocb() guarantees that the whole buffer - * is in a single page if the length < 4096. - */ - phys_p = (uchar *) virt_to_phys(putp); - - ddp_h = priv0->dmadesc_h; - ddp_s = priv0->dmadesc_s; - tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); - for (;;) - { - int count; - int amt; - - count = tbdp->count; - amt = count & 0x3fff; - if (amt == 0) - break; /* For safety */ - if ( (p-putp) >= len) - { - printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); - proc_reset(dev0, 1); /* Freeze IDT */ - break; /* For Safety */ - } - - ddp_h->pciaddr = (ulong) phys_p; - ddp_h->lcladdr = S2DMA(tbdp->buf); - ddp_h->len = amt; - - phys_p += amt; - p += amt; - - if (count & I596_TBD_EOF) - { - ddp_h->next = PLX_DMA_DESC_TO_HOST - | PLX_DMA_DESC_EOC; - ++ddp_h; - break; - } - else - { - ++ddp_s; - ddp_h->next = PLX_DMA_DESC_TO_HOST - | (ulong) ddp_s; - tbdp = (I596_TBD *) S2H(tbdp->next); - ++ddp_h; - } - } - if (ddp_h - priv0->dmadesc_h) - { - int rc; - - rc = do_plx_dma(dev0, - 0, (ulong) priv0->dmadesc_s, len, 0); - if (rc) - { - printk("%s: Chained DMA failure\n", devN->name); - goto again; - } - } - } - else if (priv0->use_dma) - { - /* - * If we can use DMA and it's a shorter frame, copy it - * using single DMA transfers. - */ - uchar *phys_p; - - /* - * Get the physical address of the STREAMS buffer. - * NOTE: allocb() guarantees that the whole buffer - * is in a single page if the length < 4096. - */ - phys_p = (uchar *) virt_to_phys(putp); - - tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); - for (;;) - { - int count; - int amt; - int rc; - - count = tbdp->count; - amt = count & 0x3fff; - if (amt == 0) - break; /* For safety */ - if ( (p-putp) >= len) - { - printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); - proc_reset(dev0, 1); /* Freeze IDT */ - break; /* For Safety */ - } - rc = do_plx_dma(dev0, (ulong) phys_p, - S2DMA(tbdp->buf), amt, 1); - if (rc) - { - memcpy(p, S2H(tbdp->buf), amt); - printk("%s: Single DMA failed\n", devN->name); - } - phys_p += amt; - p += amt; - if (count & I596_TBD_EOF) - break; - tbdp = (I596_TBD *) S2H(tbdp->next); - } - } - else - { - /* - * Otherwise, copy it piece by piece using memcpy() - */ - tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); - for (;;) - { - int count; - int amt; - - count = tbdp->count; - amt = count & 0x3fff; - if (amt == 0) - break; /* For safety */ - if ( (p-putp) >= len) - { - printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); - proc_reset(dev0, 1); /* Freeze IDT */ - break; /* For Safety */ - } - memcpy(p, S2H(tbdp->buf), amt); - p += amt; - if (count & I596_TBD_EOF) - break; - tbdp = (I596_TBD *) S2H(tbdp->next); - } - } - - /* - * Pass the frame to upper half - */ - skb->protocol = eth_type_trans(skb, devN); - netif_rx(skb); - devN->last_rx = jiffies; - ++devN->stats.rx_packets; - devN->stats.rx_bytes += len; - -out: - cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK; -} - -/* - * Start transmission of a frame - * - * The interface to the board is simple: we pretend that we are - * a fifth 82596 ethernet controller 'receiving' data, and copy the - * data into the same structures that a real 82596 would. This way, - * the board firmware handles the host 'port' the same as any other. - * - * NOTE: we do not use Bus master DMA for this routine. Turns out - * that it is not needed. Slave writes over the PCI bus are about - * as fast as DMA, due to the fact that the PLX part can do burst - * writes. The same is not true for data being read from the board. - * - * For multi-NIC mode, we tell the firmware the desired 82596 - * output port by setting the special "dstchan" member at the - * end of the traditional 82596 RFD structure. - */ - -static int dgrs_start_xmit(struct sk_buff *skb, struct net_device *devN) -{ - DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; - struct net_device *dev0; - DGRS_PRIV *priv0; - I596_RBD *rbdp; - int count; - int i, len, amt; - - /* - * Determine 0th priv and dev structure pointers - */ - if (dgrs_nicmode) - { - dev0 = privN->devtbl[0]; - priv0 = (DGRS_PRIV *) dev0->priv; - } - else - { - dev0 = devN; - priv0 = privN; - } - - if (dgrs_debug > 1) - printk("%s: xmit len=%d\n", devN->name, (int) skb->len); - - devN->trans_start = jiffies; - netif_start_queue(devN); - - if (priv0->rfdp->cmd & I596_RFD_EL) - { /* Out of RFD's */ - if (0) printk("%s: NO RFD's\n", devN->name); - goto no_resources; - } - - rbdp = priv0->rbdp; - count = 0; - priv0->rfdp->rbdp = (I596_RBD *) H2S(rbdp); - - i = 0; len = skb->len; - for (;;) - { - if (rbdp->size & I596_RBD_EL) - { /* Out of RBD's */ - if (0) printk("%s: NO RBD's\n", devN->name); - goto no_resources; - } - - amt = min_t(unsigned int, len, rbdp->size - count); - skb_copy_from_linear_data_offset(skb, i, S2H(rbdp->buf) + count, amt); - i += amt; - count += amt; - len -= amt; - if (len == 0) - { - if (skb->len < 60) - rbdp->count = 60 | I596_RBD_EOF; - else - rbdp->count = count | I596_RBD_EOF; - rbdp = (I596_RBD *) S2H(rbdp->next); - goto frame_done; - } - else if (count < 32) - { - /* More data to come, but we used less than 32 - * bytes of this RBD. Keep filling this RBD. - */ - {} /* Yes, we do nothing here */ - } - else - { - rbdp->count = count; - rbdp = (I596_RBD *) S2H(rbdp->next); - count = 0; - } - } - -frame_done: - priv0->rbdp = rbdp; - if (dgrs_nicmode) - priv0->rfdp->dstchan = privN->chan; - priv0->rfdp->status = I596_RFD_C | I596_RFD_OK; - priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next); - - ++devN->stats.tx_packets; - - dev_kfree_skb (skb); - return (0); - -no_resources: - priv0->scbp->status |= I596_SCB_RNR; /* simulate I82596 */ - return (-EAGAIN); -} - -/* - * Open the interface - */ -static int -dgrs_open( struct net_device *dev ) -{ - netif_start_queue(dev); - return (0); -} - -/* - * Close the interface - */ -static int dgrs_close( struct net_device *dev ) -{ - netif_stop_queue(dev); - return (0); -} - -/* - * Set multicast list and/or promiscuous mode - */ - -static void dgrs_set_multicast_list( struct net_device *dev) -{ - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - - priv->port->is_promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; -} - -/* - * Unique ioctl's - */ -static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd) -{ - DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; - DGRS_IOCTL ioc; - int i; - - if (cmd != DGRSIOCTL) - return -EINVAL; - - if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL))) - return -EFAULT; - - switch (ioc.cmd) - { - case DGRS_GETMEM: - if (ioc.len != sizeof(ulong)) - return -EINVAL; - if(copy_to_user(ioc.data, &devN->mem_start, ioc.len)) - return -EFAULT; - return (0); - case DGRS_SETFILTER: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (ioc.port > privN->bcomm->bc_nports) - return -EINVAL; - if (ioc.filter >= NFILTERS) - return -EINVAL; - if (ioc.len > privN->bcomm->bc_filter_area_len) - return -EINVAL; - - /* Wait for old command to finish */ - for (i = 0; i < 1000; ++i) - { - if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 ) - break; - udelay(1); - } - if (i >= 1000) - return -EIO; - - privN->bcomm->bc_filter_port = ioc.port; - privN->bcomm->bc_filter_num = ioc.filter; - privN->bcomm->bc_filter_len = ioc.len; - - if (ioc.len) - { - if(copy_from_user(S2HN(privN->bcomm->bc_filter_area), - ioc.data, ioc.len)) - return -EFAULT; - privN->bcomm->bc_filter_cmd = BC_FILTER_SET; - } - else - privN->bcomm->bc_filter_cmd = BC_FILTER_CLR; - return(0); - default: - return -EOPNOTSUPP; - } -} - -/* - * Process interrupts - * - * dev, priv will always refer to the 0th device in Multi-NIC mode. - */ - -static irqreturn_t dgrs_intr(int irq, void *dev_id) -{ - struct net_device *dev0 = dev_id; - DGRS_PRIV *priv0 = dev0->priv; - I596_CB *cbp; - int cmd; - int i; - - ++priv0->intrcnt; - if (1) ++priv0->bcomm->bc_cnt[4]; - if (0) - { - static int cnt = 100; - if (--cnt > 0) - printk("%s: interrupt: irq %d\n", dev0->name, irq); - } - - /* - * Get 596 command - */ - cmd = priv0->scbp->cmd; - - /* - * See if RU has been restarted - */ - if ( (cmd & I596_SCB_RUC) == I596_SCB_RUC_START) - { - if (0) printk("%s: RUC start\n", dev0->name); - priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp); - priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp); - priv0->scbp->status &= ~(I596_SCB_RNR|I596_SCB_RUS); - /* - * Tell upper half (halves) - */ - if (dgrs_nicmode) - { - for (i = 0; i < priv0->nports; ++i) - netif_wake_queue (priv0->devtbl[i]); - } - else - netif_wake_queue (dev0); - /* if (bd->flags & TX_QUEUED) - DL_sched(bd, bdd); */ - } - - /* - * See if any CU commands to process - */ - if ( (cmd & I596_SCB_CUC) != I596_SCB_CUC_START) - { - priv0->scbp->cmd = 0; /* Ignore all other commands */ - goto ack_intr; - } - priv0->scbp->status &= ~(I596_SCB_CNA|I596_SCB_CUS); - - /* - * Process a command - */ - cbp = (I596_CB *) S2H(priv0->scbp->cbp); - priv0->scbp->cmd = 0; /* Safe to clear the command */ - for (;;) - { - switch (cbp->nop.cmd & I596_CB_CMD) - { - case I596_CB_CMD_XMIT: - dgrs_rcv_frame(dev0, priv0, cbp); - break; - default: - cbp->nop.status = I596_CB_STATUS_C | I596_CB_STATUS_OK; - break; - } - if (cbp->nop.cmd & I596_CB_CMD_EL) - break; - cbp = (I596_CB *) S2H(cbp->nop.next); - } - priv0->scbp->status |= I596_SCB_CNA; - - /* - * Ack the interrupt - */ -ack_intr: - if (priv0->plxreg) - OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1); - - return IRQ_HANDLED; -} - -/* - * Download the board firmware - */ -static int __init -dgrs_download(struct net_device *dev0) -{ - DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; - int is; - unsigned long i; - - static const int iv2is[16] = { - 0, 0, 0, ES4H_IS_INT3, - 0, ES4H_IS_INT5, 0, ES4H_IS_INT7, - 0, 0, ES4H_IS_INT10, ES4H_IS_INT11, - ES4H_IS_INT12, 0, 0, ES4H_IS_INT15 }; - - /* - * Map in the dual port memory - */ - priv0->vmem = ioremap(dev0->mem_start, 2048*1024); - if (!priv0->vmem) - { - printk("%s: cannot map in board memory\n", dev0->name); - return -ENXIO; - } - - /* - * Hold the processor and configure the board addresses - */ - if (priv0->plxreg) - { /* PCI bus */ - proc_reset(dev0, 1); - } - else - { /* EISA bus */ - is = iv2is[dev0->irq & 0x0f]; - if (!is) - { - printk("%s: Illegal IRQ %d\n", dev0->name, dev0->irq); - iounmap(priv0->vmem); - priv0->vmem = NULL; - return -ENXIO; - } - OUTB(dev0->base_addr + ES4H_AS_31_24, - (uchar) (dev0->mem_start >> 24) ); - OUTB(dev0->base_addr + ES4H_AS_23_16, - (uchar) (dev0->mem_start >> 16) ); - priv0->is_reg = ES4H_IS_LINEAR | is | - ((uchar) (dev0->mem_start >> 8) & ES4H_IS_AS15); - OUTB(dev0->base_addr + ES4H_IS, priv0->is_reg); - OUTB(dev0->base_addr + ES4H_EC, ES4H_EC_ENABLE); - OUTB(dev0->base_addr + ES4H_PC, ES4H_PC_RESET); - OUTB(dev0->base_addr + ES4H_MW, ES4H_MW_ENABLE | 0x00); - } - - /* - * See if we can do DMA on the SE-6 - */ - priv0->use_dma = check_board_dma(dev0); - if (priv0->use_dma) - printk("%s: Bus Master DMA is enabled.\n", dev0->name); - - /* - * Load and verify the code at the desired address - */ - memcpy(priv0->vmem, dgrs_code, dgrs_ncode); /* Load code */ - if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode)) - { - iounmap(priv0->vmem); - priv0->vmem = NULL; - printk("%s: download compare failed\n", dev0->name); - return -ENXIO; - } - - /* - * Configurables - */ - priv0->bcomm = (struct bios_comm *) (priv0->vmem + 0x0100); - priv0->bcomm->bc_nowait = 1; /* Tell board to make printf not wait */ - priv0->bcomm->bc_squelch = 0; /* Flag from Space.c */ - priv0->bcomm->bc_150ohm = 0; /* Flag from Space.c */ - - priv0->bcomm->bc_spew = 0; /* Debug flag from Space.c */ - priv0->bcomm->bc_maxrfd = 0; /* Debug flag from Space.c */ - priv0->bcomm->bc_maxrbd = 0; /* Debug flag from Space.c */ - - /* - * Tell board we are operating in switch mode (1) or in - * multi-NIC mode (2). - */ - priv0->bcomm->bc_host = dgrs_nicmode ? BC_MULTINIC : BC_SWITCH; - - /* - * Request memory space on board for DMA chains - */ - if (priv0->use_dma) - priv0->bcomm->bc_hostarea_len = (2048/64) * 16; - - /* - * NVRAM configurables from Space.c - */ - priv0->bcomm->bc_spantree = dgrs_spantree; - priv0->bcomm->bc_hashexpire = dgrs_hashexpire; - memcpy(priv0->bcomm->bc_ipaddr, dgrs_ipaddr, 4); - memcpy(priv0->bcomm->bc_iptrap, dgrs_iptrap, 4); - memcpy(priv0->bcomm->bc_ipxnet, &dgrs_ipxnet, 4); - - /* - * Release processor, wait 8 seconds for board to initialize - */ - proc_reset(dev0, 0); - - for (i = jiffies + 8 * HZ; time_after(i, jiffies); ) - { - barrier(); /* Gcc 2.95 needs this */ - if (priv0->bcomm->bc_status >= BC_RUN) - break; - } - - if (priv0->bcomm->bc_status < BC_RUN) - { - printk("%s: board not operating\n", dev0->name); - iounmap(priv0->vmem); - priv0->vmem = NULL; - return -ENXIO; - } - - priv0->port = (PORT *) S2H(priv0->bcomm->bc_port); - priv0->scbp = (I596_SCB *) S2H(priv0->port->scbp); - priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp); - priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp); - - priv0->scbp->status = I596_SCB_CNA; /* CU is idle */ - - /* - * Get switch physical and host virtual pointers to DMA - * chaining area. NOTE: the MSB of the switch physical - * address *must* be turned off. Otherwise, the HW kludge - * that allows host access of the PLX DMA registers will - * erroneously select the PLX registers. - */ - priv0->dmadesc_s = (DMACHAIN *) S2DMA(priv0->bcomm->bc_hostarea); - if (priv0->dmadesc_s) - priv0->dmadesc_h = (DMACHAIN *) S2H(priv0->dmadesc_s); - else - priv0->dmadesc_h = NULL; - - /* - * Enable board interrupts - */ - if (priv0->plxreg) - { /* PCI bus */ - OUTL(dev0->base_addr + PLX_INT_CSR, - inl(dev0->base_addr + PLX_INT_CSR) - | PLX_PCI_DOORBELL_IE); /* Enable intr to host */ - OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1); - } - else - { /* EISA bus */ - } - - return (0); -} - -/* - * Probe (init) a board - */ -static int __init -dgrs_probe1(struct net_device *dev) -{ - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - unsigned long i; - int rc; - DECLARE_MAC_BUF(mac); - - printk("%s: Digi RightSwitch io=%lx mem=%lx irq=%d plx=%lx dma=%lx\n", - dev->name, dev->base_addr, dev->mem_start, dev->irq, - priv->plxreg, priv->plxdma); - - /* - * Download the firmware and light the processor - */ - rc = dgrs_download(dev); - if (rc) - goto err_out; - - /* - * Get ether address of board - */ - memcpy(dev->dev_addr, priv->port->ethaddr, 6); - printk("%s: Ethernet address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); - - if (dev->dev_addr[0] & 1) - { - printk("%s: Illegal Ethernet Address\n", dev->name); - rc = -ENXIO; - goto err_out; - } - - /* - * ACK outstanding interrupts, hook the interrupt, - * and verify that we are getting interrupts from the board. - */ - if (priv->plxreg) - OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1); - - rc = request_irq(dev->irq, &dgrs_intr, IRQF_SHARED, "RightSwitch", dev); - if (rc) - goto err_out; - - priv->intrcnt = 0; - for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); ) - { - cpu_relax(); - if (priv->intrcnt >= 2) - break; - } - if (priv->intrcnt < 2) - { - printk(KERN_ERR "%s: Not interrupting on IRQ %d (%d)\n", - dev->name, dev->irq, priv->intrcnt); - rc = -ENXIO; - goto err_free_irq; - } - - /* - * Entry points... - */ - dev->open = &dgrs_open; - dev->stop = &dgrs_close; - dev->hard_start_xmit = &dgrs_start_xmit; - dev->set_multicast_list = &dgrs_set_multicast_list; - dev->do_ioctl = &dgrs_ioctl; - - return rc; - -err_free_irq: - free_irq(dev->irq, dev); -err_out: - return rc; -} - -static int __init -dgrs_initclone(struct net_device *dev) -{ - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - DECLARE_MAC_BUF(mac); - - printk("%s: Digi RightSwitch port %d %s\n", - dev->name, priv->chan, print_mac(mac, dev->dev_addr)); - - return 0; -} - -static struct net_device * __init -dgrs_found_device( - int io, - ulong mem, - int irq, - ulong plxreg, - ulong plxdma, - struct device *pdev -) -{ - DGRS_PRIV *priv; - struct net_device *dev; - int i, ret = -ENOMEM; - - dev = alloc_etherdev(sizeof(DGRS_PRIV)); - if (!dev) - goto err0; - - priv = (DGRS_PRIV *)dev->priv; - - dev->base_addr = io; - dev->mem_start = mem; - dev->mem_end = mem + 2048 * 1024 - 1; - dev->irq = irq; - priv->plxreg = plxreg; - priv->plxdma = plxdma; - priv->vplxdma = NULL; - - priv->chan = 1; - priv->devtbl[0] = dev; - - SET_NETDEV_DEV(dev, pdev); - - ret = dgrs_probe1(dev); - if (ret) - goto err1; - - ret = register_netdev(dev); - if (ret) - goto err2; - - if ( !dgrs_nicmode ) - return dev; /* Switch mode, we are done */ - - /* - * Operating card as N separate NICs - */ - - priv->nports = priv->bcomm->bc_nports; - - for (i = 1; i < priv->nports; ++i) - { - struct net_device *devN; - DGRS_PRIV *privN; - /* Allocate new dev and priv structures */ - devN = alloc_etherdev(sizeof(DGRS_PRIV)); - ret = -ENOMEM; - if (!devN) - goto fail; - - /* Don't copy the network device structure! */ - - /* copy the priv structure of dev[0] */ - privN = (DGRS_PRIV *)devN->priv; - *privN = *priv; - - /* ... and zero out VM areas */ - privN->vmem = NULL; - privN->vplxdma = NULL; - /* ... and zero out IRQ */ - devN->irq = 0; - /* ... and base MAC address off address of 1st port */ - devN->dev_addr[5] += i; - - ret = dgrs_initclone(devN); - if (ret) - goto fail; - - SET_NETDEV_DEV(dev, pdev); - - ret = register_netdev(devN); - if (ret) { - free_netdev(devN); - goto fail; - } - privN->chan = i+1; - priv->devtbl[i] = devN; - } - return dev; - - fail: - while (i >= 0) { - struct net_device *d = priv->devtbl[i--]; - unregister_netdev(d); - free_netdev(d); - } - - err2: - free_irq(dev->irq, dev); - err1: - free_netdev(dev); - err0: - return ERR_PTR(ret); -} - -static void __devexit dgrs_remove(struct net_device *dev) -{ - DGRS_PRIV *priv = dev->priv; - int i; - - unregister_netdev(dev); - - for (i = 1; i < priv->nports; ++i) { - struct net_device *d = priv->devtbl[i]; - if (d) { - unregister_netdev(d); - free_netdev(d); - } - } - - proc_reset(priv->devtbl[0], 1); - - if (priv->vmem) - iounmap(priv->vmem); - if (priv->vplxdma) - iounmap((uchar *) priv->vplxdma); - - if (dev->irq) - free_irq(dev->irq, dev); - - for (i = 1; i < priv->nports; ++i) { - if (priv->devtbl[i]) - unregister_netdev(priv->devtbl[i]); - } -} - -#ifdef CONFIG_PCI -static int __init dgrs_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - int err; - uint io; - uint mem; - uint irq; - uint plxreg; - uint plxdma; - - /* - * Get and check the bus-master and latency values. - * Some PCI BIOSes fail to set the master-enable bit, - * and the latency timer must be set to the maximum - * value to avoid data corruption that occurs when the - * timer expires during a transfer. Yes, it's a bug. - */ - err = pci_enable_device(pdev); - if (err) - return err; - err = pci_request_regions(pdev, "RightSwitch"); - if (err) - return err; - - pci_set_master(pdev); - - plxreg = pci_resource_start (pdev, 0); - io = pci_resource_start (pdev, 1); - mem = pci_resource_start (pdev, 2); - pci_read_config_dword(pdev, 0x30, &plxdma); - irq = pdev->irq; - plxdma &= ~15; - - /* - * On some BIOSES, the PLX "expansion rom" (used for DMA) - * address comes up as "0". This is probably because - * the BIOS doesn't see a valid 55 AA ROM signature at - * the "ROM" start and zeroes the address. To get - * around this problem the SE-6 is configured to ask - * for 4 MB of space for the dual port memory. We then - * must set its range back to 2 MB, and use the upper - * half for DMA register access - */ - OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L); - if (plxdma == 0) - plxdma = mem + (2048L * 1024L); - pci_write_config_dword(pdev, 0x30, plxdma + 1); - pci_read_config_dword(pdev, 0x30, &plxdma); - plxdma &= ~15; - - dev = dgrs_found_device(io, mem, irq, plxreg, plxdma, &pdev->dev); - if (IS_ERR(dev)) { - pci_release_regions(pdev); - return PTR_ERR(dev); - } - - pci_set_drvdata(pdev, dev); - return 0; -} - -static void __devexit dgrs_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - dgrs_remove(dev); - pci_release_regions(pdev); - free_netdev(dev); -} - -static struct pci_driver dgrs_pci_driver = { - .name = "dgrs", - .id_table = dgrs_pci_tbl, - .probe = dgrs_pci_probe, - .remove = __devexit_p(dgrs_pci_remove), -}; -#else -static struct pci_driver dgrs_pci_driver = {}; -#endif - - -#ifdef CONFIG_EISA -static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 }; - -static int __init dgrs_eisa_probe (struct device *gendev) -{ - struct net_device *dev; - struct eisa_device *edev = to_eisa_device(gendev); - uint io = edev->base_addr; - uint mem; - uint irq; - int rc = -ENODEV; /* Not EISA configured */ - - if (!request_region(io, 256, "RightSwitch")) { - printk(KERN_ERR "dgrs: eisa io 0x%x, which is busy.\n", io); - return -EBUSY; - } - - if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) ) - goto err_out; - - mem = (inb(io+ES4H_AS_31_24) << 24) - + (inb(io+ES4H_AS_23_16) << 16); - - irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ]; - - dev = dgrs_found_device(io, mem, irq, 0L, 0L, gendev); - if (IS_ERR(dev)) { - rc = PTR_ERR(dev); - goto err_out; - } - - gendev->driver_data = dev; - return 0; - err_out: - release_region(io, 256); - return rc; -} - -static int __devexit dgrs_eisa_remove(struct device *gendev) -{ - struct net_device *dev = gendev->driver_data; - - dgrs_remove(dev); - - release_region(dev->base_addr, 256); - - free_netdev(dev); - return 0; -} - - -static struct eisa_driver dgrs_eisa_driver = { - .id_table = dgrs_eisa_tbl, - .driver = { - .name = "dgrs", - .probe = dgrs_eisa_probe, - .remove = __devexit_p(dgrs_eisa_remove), - } -}; -#endif - -/* - * Variables that can be overriden from module command line - */ -static int debug = -1; -static int dma = -1; -static int hashexpire = -1; -static int spantree = -1; -static int ipaddr[4] = { -1 }; -static int iptrap[4] = { -1 }; -static __u32 ipxnet = -1; -static int nicmode = -1; - -module_param(debug, int, 0); -module_param(dma, int, 0); -module_param(hashexpire, int, 0); -module_param(spantree, int, 0); -module_param_array(ipaddr, int, NULL, 0); -module_param_array(iptrap, int, NULL, 0); -module_param(ipxnet, int, 0); -module_param(nicmode, int, 0); -MODULE_PARM_DESC(debug, "Digi RightSwitch enable debugging (0-1)"); -MODULE_PARM_DESC(dma, "Digi RightSwitch enable BM DMA (0-1)"); -MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-NIC)"); - -static int __init dgrs_init_module (void) -{ - int i; - int err; - - /* - * Command line variable overrides - * debug=NNN - * dma=0/1 - * spantree=0/1 - * hashexpire=NNN - * ipaddr=A,B,C,D - * iptrap=A,B,C,D - * ipxnet=NNN - * nicmode=NNN - */ - if (debug >= 0) - dgrs_debug = debug; - if (dma >= 0) - dgrs_dma = dma; - if (nicmode >= 0) - dgrs_nicmode = nicmode; - if (hashexpire >= 0) - dgrs_hashexpire = hashexpire; - if (spantree >= 0) - dgrs_spantree = spantree; - if (ipaddr[0] != -1) - for (i = 0; i < 4; ++i) - dgrs_ipaddr[i] = ipaddr[i]; - if (iptrap[0] != -1) - for (i = 0; i < 4; ++i) - dgrs_iptrap[i] = iptrap[i]; - if (ipxnet != -1) - dgrs_ipxnet = htonl( ipxnet ); - - if (dgrs_debug) - { - printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n", - version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver); - } - - /* - * Find and configure all the cards - */ -#ifdef CONFIG_EISA - err = eisa_driver_register(&dgrs_eisa_driver); - if (err) - return err; -#endif - err = pci_register_driver(&dgrs_pci_driver); - if (err) - return err; - return 0; -} - -static void __exit dgrs_cleanup_module (void) -{ -#ifdef CONFIG_EISA - eisa_driver_unregister (&dgrs_eisa_driver); -#endif -#ifdef CONFIG_PCI - pci_unregister_driver (&dgrs_pci_driver); -#endif -} - -module_init(dgrs_init_module); -module_exit(dgrs_cleanup_module); diff --git a/drivers/net/dgrs.h b/drivers/net/dgrs.h deleted file mode 100644 index 6058d5301cb6..000000000000 --- a/drivers/net/dgrs.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ioctl's for the Digi Intl. RightSwitch - * - * These network driver ioctl's are a bit obtuse compared to the usual - * ioctl's for a "normal" device driver. Hey, I didn't invent it. - * - * Typical use: - * - * struct ifreq ifr; - * DGRS_IOCTL ioc; - * int x; - * - * strcpy(ifr.ifr_name, "eth1"); - * ifr.ifr_data = (caddr_t) &ioc; - * ioc.cmd = DGRS_GETMEM; - * ioc.len = sizeof(x); - * ioc.data = (caddr_t) &x; - * rc = ioctl(fd, DGRSIOCTL, &ifr); - * printf("rc=%d mem=%x\n", rc, x); - * - */ -#include - -#define DGRSIOCTL SIOCDEVPRIVATE - -typedef struct dgrs_ioctl { - unsigned short cmd; /* Command to run */ - unsigned short len; /* Length of the data buffer */ - unsigned char __user *data; /* Pointer to the data buffer */ - unsigned short port; /* port number for command, if needed */ - unsigned short filter; /* filter number for command, if needed */ -} DGRS_IOCTL; - -/* - * Commands for the driver - */ -#define DGRS_GETMEM 0x01 /* Get the dual port memory address */ -#define DGRS_SETFILTER 0x02 /* Set a filter */ diff --git a/drivers/net/dgrs_asstruct.h b/drivers/net/dgrs_asstruct.h deleted file mode 100644 index f0e2121770f1..000000000000 --- a/drivers/net/dgrs_asstruct.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * For declaring structures shared with assembly routines - * - * $Id: asstruct.h,v 1.1.1.1 1994/10/23 05:08:32 rick Exp $ - */ - -#ifdef ASSEMBLER - -# define MO(t,a) (a) -# define VMO(t,a) (a) - -# define BEGIN_STRUCT(x) _Off=0 -# define S1A(t,x,n) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+(1*n) -# define S2A(t,x,n) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+(2*n) -# define S4A(t,x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n) -# define WORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4 -# define WORDA(x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n) -# define VWORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4 -# define S1(t,x) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+1 -# define S2(t,x) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+2 -# define S4(t,x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4 -# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off - -#else /* C */ - -#define VMO(t,a) (*(volatile t *)(a)) - -# define BEGIN_STRUCT(x) struct x { -# define S1(t,x) t x ; -# define S1A(t,x,n) t x[n] ; -# define S2(t,x) t x ; -# define S2A(t,x,n) t x[n] ; -# define S4(t,x) t x ; -# define S4A(t,x,n) t x[n] ; -# define END_STRUCT(x) } ; - -#endif diff --git a/drivers/net/dgrs_bcomm.h b/drivers/net/dgrs_bcomm.h deleted file mode 100644 index 5e9c25273981..000000000000 --- a/drivers/net/dgrs_bcomm.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * The bios low-memory structure - * - * Some of the variables in here can be used to set parameters that - * are stored in NVRAM and will retain their old values the next time - * the card is brought up. To use the values stored in NVRAM, the - * parameter should be set to "all ones". This tells the firmware to - * use the NVRAM value or a suitable default. The value that is used - * will be stored back into this structure by the firmware. If the - * value of the variable is not "all ones", then that value will be - * used and will be stored into NVRAM if it isn't already there. - * The variables this applies to are the following: - * Variable Set to: Gets default of: - * bc_hashexpire -1 300 (5 minutes) - * bc_spantree -1 1 (spanning tree on) - * bc_ipaddr FF:FF:FF:FF 0 (no SNMP IP address) - * bc_ipxnet FF:FF:FF:FF 0 (no SNMP IPX net) - * bc_iptrap FF:FF:FF:FF 0 (no SNMP IP trap address) - * - * Some variables MUST have their value set after the firmware - * is loaded onto the board, but before the processor is released. - * These are: - * bc_host 0 means no host "port", run as standalone switch. - * 1 means run as a switch, with a host port. (normal) - * 2 means run as multiple NICs, not as a switch. - * -1 means run in diagnostics mode. - * bc_nowait - * bc_hostarea_len - * bc_filter_len - * - */ -BEGIN_STRUCT(bios_comm) - S4(ulong, bc_intflag) /* Count of all interrupts */ - S4(ulong, bc_lbolt) /* Count of timer interrupts */ - S4(ulong, bc_maincnt) /* Count of main loops */ - S4(ulong, bc_hashcnt) /* Count of entries in hash table */ - S4A(ulong, bc_cnt, 8) /* Misc counters, for debugging */ - S4A(ulong, bc_flag, 8) /* Misc flags, for debugging */ - S4(ulong, bc_memsize) /* Size of memory */ - S4(ulong, bc_dcache) /* Size of working dcache */ - S4(ulong, bc_icache) /* Size of working icache */ - S4(long, bc_status) /* Firmware status */ - S1A(char, bc_file, 8) /* File name of assertion failure */ - S4(ulong, bc_line) /* Line # of assertion failure */ - S4(uchar *, bc_ramstart) - S4(uchar *, bc_ramend) - S4(uchar *, bc_heapstart) /* Start of heap (end of loaded memory) */ - S4(uchar *, bc_heapend) /* End of heap */ - - /* Configurable Parameters */ - S4(long, bc_host) /* 1=Host Port, 0=No Host Port, -1=Test Mode */ - S4(long, bc_nowait) /* Don't wait for 2host circ buffer to empty*/ - S4(long, bc_150ohm) /* 0 == 100 ohm UTP, 1 == 150 ohm STP */ - S4(long, bc_squelch) /* 0 == normal squelch, 1 == reduced squelch */ - S4(ulong, bc_hashexpire) /* Expiry time in seconds for hash table */ - S4(long, bc_spantree) /* 1 == enable IEEE spanning tree */ - - S2A(ushort, bc_eaddr, 3) /* New ether address */ - S2(ushort, bc_dummy1) /* padding for DOS compilers */ - - /* Various debugging aids */ - S4(long, bc_debug) /* Debugging is turned on */ - S4(long, bc_spew) /* Spew data on port 4 for bs_spew seconds */ - S4(long, bc_spewlen) /* Length of spewed data packets */ - S4(long, bc_maxrfd) /* If != 0, max number of RFD's to allocate */ - S4(long, bc_maxrbd) /* If != 0, max number of RBD's to allocate */ - - /* Circular buffers for messages to/from host */ - S4(ulong, bc_2host_head) - S4(ulong, bc_2host_tail) - S4(ulong, bc_2host_mask) - S1A(char, bc_2host, 0x200) /* Circ buff to host */ - - S4(ulong, bc_2idt_head) - S4(ulong, bc_2idt_tail) - S4(ulong, bc_2idt_mask) - S1A(char, bc_2idt, 0x200) /* Circ buff to idt */ - - /* Pointers to structures for driver access */ - S4(uchar *, bc_port) /* pointer to Port[] structures */ - S4(long, bc_nports) /* Number of ports */ - S4(long, bc_portlen) /* sizeof(PORT) */ - S4(uchar *, bc_hash) /* Pointer to hash table */ - S4(long, bc_hashlen) /* sizeof(Table) */ - - /* SNMP agent addresses */ - S1A(uchar, bc_ipaddr, 4) /* IP address for SNMP */ - S1A(uchar, bc_ipxnet, 4) /* IPX net address for SNMP */ - - S4(long, bc_nohostintr) /* Do not cause periodic host interrupts */ - - S4(uchar *, bc_dmaaddr) /* Physical addr of host DMA buf for diags */ - S4(ulong, bc_dmalen) /* Length of DMA buffer 0..2048 */ - - /* - * Board memory allocated on startup for use by host, usually - * for the purposes of creating DMA chain descriptors. The - * "len" must be set before the processor is released. The - * address of the area is returned in bc_hostarea. The area - * is guaranteed to be aligned on a 16 byte boundary. - */ - S4(ulong, bc_hostarea_len) /* RW: Number of bytes to allocate */ - S4(uchar *, bc_hostarea) /* RO: Address of allocated memory */ - - /* - * Variables for communicating filters into the board - */ - S4(ulong *, bc_filter_area) /* RO: Space to put filter into */ - S4(ulong, bc_filter_area_len) /* RO: Length of area, in bytes */ - S4(long, bc_filter_cmd) /* RW: Filter command, see below */ - S4(ulong, bc_filter_len) /* RW: Actual length of filter */ - S4(ulong, bc_filter_port) /* RW: Port # for filter 0..6 */ - S4(ulong, bc_filter_num) /* RW: Filter #, 0=input, 1=output */ - - /* more SNMP agent addresses */ - S1A(uchar, bc_iptrap, 4) /* IP address for SNMP */ - - S4A(long, bc_spare, 2) /* spares */ -END_STRUCT(bios_comm) - -#define bc VMO(struct bios_comm, 0xa3000100) - -/* - * bc_status values - */ -#define BC_INIT 0 -#define BC_RUN 100 - -/* - * bc_host values - */ -#define BC_DIAGS -1 -#define BC_SASWITCH 0 -#define BC_SWITCH 1 -#define BC_MULTINIC 2 - -/* - * Values for spew (debugging) - */ -#define BC_SPEW_ENABLE 0x80000000 - -/* - * filter commands - */ -#define BC_FILTER_ERR -1 -#define BC_FILTER_OK 0 -#define BC_FILTER_SET 1 -#define BC_FILTER_CLR 2 diff --git a/drivers/net/dgrs_es4h.h b/drivers/net/dgrs_es4h.h deleted file mode 100644 index 5518fba46b2c..000000000000 --- a/drivers/net/dgrs_es4h.h +++ /dev/null @@ -1,183 +0,0 @@ -/************************************************************************/ -/* */ -/* es4h.h: Hardware definition of the ES/4h Ethernet Switch, from */ -/* both the host and the 3051's point of view. */ -/* NOTE: this name is a misnomer now that there is a PCI */ -/* board. Everything that says "es4h" should really be */ -/* "se4". But we'll keep the old name for now. */ -/* */ -/* $Id: es4h.h,v 1.10 1996/08/22 17:16:53 rick Exp $ */ -/* */ -/************************************************************************/ - -/************************************************************************/ -/* */ -/* EISA I/O Registers. These are located at 0x1000 * slot-number */ -/* plus the indicated address. I.E. 0x4000-0x4009 for slot 4. */ -/* */ -/************************************************************************/ - -#define ES4H_MANUFmsb 0x00 /* Read-only */ -#define ES4H_MANUFlsb 0x01 /* Read-only */ -# define ES4H_MANUF_CODE 0x1049 /* = "DBI" */ - -#define ES4H_PRODUCT 0x02 /* Read-only */ -# define ES4H_PRODUCT_CODE 0x0A -# define EPC_PRODUCT_CODE 0x03 - -#define ES4H_REVISION 0x03 /* Read-only */ -# define ES4H_REVISION_CODE 0x01 - -#define ES4H_EC 0x04 /* EISA Control */ -# define ES4H_EC_RESET 0x04 /* WO, EISA reset */ -# define ES4H_EC_ENABLE 0x01 /* RW, EISA enable - set to */ - /* 1 before memory enable */ -#define ES4H_PC 0x05 /* Processor Control */ -# define ES4H_PC_RESET 0x04 /* RW, 3051 reset */ -# define ES4H_PC_INT 0x08 /* WO, assert 3051 intr. 3 */ - -#define ES4H_MW 0x06 /* Memory Window select and enable */ -# define ES4H_MW_ENABLE 0x80 /* WO, enable memory */ -# define ES4H_MW_SELECT_MASK 0x1f /* WO, 32k window selected */ - -#define ES4H_IS 0x07 /* Interrupt, addr select */ -# define ES4H_IS_INTMASK 0x07 /* WO, interrupt select */ -# define ES4H_IS_INTOFF 0x00 /* No IRQ */ -# define ES4H_IS_INT3 0x03 /* IRQ 3 */ -# define ES4H_IS_INT5 0x02 /* IRQ 5 */ -# define ES4H_IS_INT7 0x01 /* IRQ 7 */ -# define ES4H_IS_INT10 0x04 /* IRQ 10 */ -# define ES4H_IS_INT11 0x05 /* IRQ 11 */ -# define ES4H_IS_INT12 0x06 /* IRQ 12 */ -# define ES4H_IS_INT15 0x07 /* IRQ 15 */ -# define ES4H_IS_INTACK 0x10 /* WO, interrupt ack */ -# define ES4H_IS_INTPEND 0x10 /* RO, interrupt pending */ -# define ES4H_IS_LINEAR 0x40 /* WO, no memory windowing */ -# define ES4H_IS_AS15 0x80 /* RW, address select bit 15 */ - -#define ES4H_AS_23_16 0x08 /* Address select bits 23-16 */ -#define ES4H_AS_31_24 0x09 /* Address select bits 31-24 */ - -#define ES4H_IO_MAX 0x09 /* Size of I/O space */ - -/* - * PCI - */ -#define SE6_RESET PLX_USEROUT - -/************************************************************************/ -/* */ -/* 3051 Memory Map */ -/* */ -/* Note: 3051 has 4K I-cache, 2K D-cache. 1 cycle is 50 nsec. */ -/* */ -/************************************************************************/ -#define SE4_NPORTS 4 /* # of ethernet ports */ -#define SE6_NPORTS 6 /* # of ethernet ports */ -#define SE_NPORTS 6 /* Max # of ethernet ports */ - -#define ES4H_RAM_BASE 0x83000000 /* Base address of RAM */ -#define ES4H_RAM_SIZE 0x00200000 /* Size of RAM (2MB) */ -#define ES4H_RAM_INTBASE 0x83800000 /* Base of int-on-write RAM */ - /* a.k.a. PKT RAM */ - - /* Ethernet controllers */ - /* See: i82596.h */ -#define ES4H_ETHER0_PORT 0xA2000000 -#define ES4H_ETHER0_CMD 0xA2000100 -#define ES4H_ETHER1_PORT 0xA2000200 -#define ES4H_ETHER1_CMD 0xA2000300 -#define ES4H_ETHER2_PORT 0xA2000400 -#define ES4H_ETHER2_CMD 0xA2000500 -#define ES4H_ETHER3_PORT 0xA2000600 -#define ES4H_ETHER3_CMD 0xA2000700 -#define ES4H_ETHER4_PORT 0xA2000800 /* RS SE-6 only */ -#define ES4H_ETHER4_CMD 0xA2000900 /* RS SE-6 only */ -#define ES4H_ETHER5_PORT 0xA2000A00 /* RS SE-6 only */ -#define ES4H_ETHER5_CMD 0xA2000B00 /* RS SE-6 only */ - -#define ES4H_I8254 0xA2040000 /* 82C54 timers */ - /* See: i8254.h */ - -#define SE4_I8254_HZ (23000000/4) /* EISA clock input freq. */ -#define SE4_IDT_HZ (46000000) /* EISA CPU freq. */ -#define SE6_I8254_HZ (20000000/4) /* PCI clock input freq. */ -#define SE6_IDT_HZ (50000000) /* PCI CPU freq. */ -#define ES4H_I8254_HZ (23000000/4) /* EISA clock input freq. */ - -#define ES4H_GPP 0xA2050000 /* General purpose port */ - /* - * SE-4 (EISA) GPP bits - */ -# define ES4H_GPP_C0_100 0x0001 /* WO, Chan 0: 100 ohm TP */ -# define ES4H_GPP_C0_SQE 0x0002 /* WO, Chan 0: normal squelch */ -# define ES4H_GPP_C1_100 0x0004 /* WO, Chan 1: 100 ohm TP */ -# define ES4H_GPP_C1_SQE 0x0008 /* WO, Chan 1: normal squelch */ -# define ES4H_GPP_C2_100 0x0010 /* WO, Chan 2: 100 ohm TP */ -# define ES4H_GPP_C2_SQE 0x0020 /* WO, Chan 2: normal squelch */ -# define ES4H_GPP_C3_100 0x0040 /* WO, Chan 3: 100 ohm TP */ -# define ES4H_GPP_C3_SQE 0x0080 /* WO, Chan 3: normal squelch */ -# define ES4H_GPP_SQE 0x00AA /* WO, All: normal squelch */ -# define ES4H_GPP_100 0x0055 /* WO, All: 100 ohm TP */ -# define ES4H_GPP_HOSTINT 0x0100 /* RO, cause intr. to host */ - /* Hold high > 250 nsec */ -# define SE4_GPP_EED 0x0200 /* RW, EEPROM data bit */ -# define SE4_GPP_EECS 0x0400 /* RW, EEPROM chip select */ -# define SE4_GPP_EECK 0x0800 /* RW, EEPROM clock */ - - /* - * SE-6 (PCI) GPP bits - */ -# define SE6_GPP_EED 0x0001 /* RW, EEPROM data bit */ -# define SE6_GPP_EECS 0x0002 /* RW, EEPROM chip select */ -# define SE6_GPP_EECK 0x0004 /* RW, EEPROM clock */ -# define SE6_GPP_LINK 0x00fc /* R, Link status LEDs */ - -#define ES4H_INTVEC 0xA2060000 /* RO: Interrupt Vector */ -# define ES4H_IV_DMA0 0x01 /* Chan 0 DMA interrupt */ -# define ES4H_IV_PKT0 0x02 /* Chan 0 PKT interrupt */ -# define ES4H_IV_DMA1 0x04 /* Chan 1 DMA interrupt */ -# define ES4H_IV_PKT1 0x08 /* Chan 1 PKT interrupt */ -# define ES4H_IV_DMA2 0x10 /* Chan 2 DMA interrupt */ -# define ES4H_IV_PKT2 0x20 /* Chan 2 PKT interrupt */ -# define ES4H_IV_DMA3 0x40 /* Chan 3 DMA interrupt */ -# define ES4H_IV_PKT3 0x80 /* Chan 3 PKT interrupt */ - -#define ES4H_INTACK 0xA2060000 /* WO: Interrupt Ack */ -# define ES4H_INTACK_8254 0x01 /* Real Time Clock (int 0) */ -# define ES4H_INTACK_HOST 0x02 /* Host (int 1) */ -# define ES4H_INTACK_PKT0 0x04 /* Chan 0 Pkt (int 2) */ -# define ES4H_INTACK_PKT1 0x08 /* Chan 1 Pkt (int 3) */ -# define ES4H_INTACK_PKT2 0x10 /* Chan 2 Pkt (int 4) */ -# define ES4H_INTACK_PKT3 0x20 /* Chan 3 Pkt (int 5) */ - -#define SE6_PLX 0xA2070000 /* PLX 9060, SE-6 (PCI) only */ - /* see plx9060.h */ - -#define SE6_PCI_VENDOR_ID 0x114F /* Digi PCI vendor ID */ -#define SE6_PCI_DEVICE_ID 0x0003 /* RS SE-6 device ID */ -#define SE6_PCI_ID ((SE6_PCI_DEVICE_ID<<16) | SE6_PCI_VENDOR_ID) - -/* - * IDT Interrupts - */ -#define ES4H_INT_8254 IDT_INT0 -#define ES4H_INT_HOST IDT_INT1 -#define ES4H_INT_ETHER0 IDT_INT2 -#define ES4H_INT_ETHER1 IDT_INT3 -#define ES4H_INT_ETHER2 IDT_INT4 -#define ES4H_INT_ETHER3 IDT_INT5 - -/* - * Because there are differences between the SE-4 and the SE-6, - * we assume that the following globals will be set up at init - * time in main.c to containt the appropriate constants from above - */ -extern ushort Gpp; /* Softcopy of GPP register */ -extern ushort EEck; /* Clock bit */ -extern ushort EEcs; /* CS bit */ -extern ushort EEd; /* Data bit */ -extern ulong I8254_Hz; /* i8254 input frequency */ -extern ulong IDT_Hz; /* IDT CPU frequency */ -extern int Nports; /* Number of ethernet controllers */ -extern int Nchan; /* Nports+1 */ diff --git a/drivers/net/dgrs_ether.h b/drivers/net/dgrs_ether.h deleted file mode 100644 index 7539b596bff8..000000000000 --- a/drivers/net/dgrs_ether.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * A filtering function. There are two filters/port. Filter "0" - * is the input filter, and filter "1" is the output filter. - */ -typedef int (FILTER_FUNC)(uchar *pktp, int pktlen, ulong *scratch, int port); -#define NFILTERS 2 - -/* - * The per port structure - */ -typedef struct -{ - int chan; /* Channel number (0-3) */ - ulong portaddr; /* address of 596 port register */ - volatile ulong *ca; /* address of 596 chan attention */ - ulong intmask; /* Interrupt mask for this port */ - ulong intack; /* Ack bit for this port */ - - uchar ethaddr[6]; /* Ethernet address of this port */ - int is_promisc; /* Port is promiscuous */ - - int debug; /* Debugging turned on */ - - I596_ISCP *iscpp; /* Uncached ISCP pointer */ - I596_SCP *scpp; /* Uncached SCP pointer */ - I596_SCB *scbp; /* Uncached SCB pointer */ - - I596_ISCP iscp; - I596_SCB scb; - - /* Command Queue */ - I596_CB *cb0; - I596_CB *cbN; - I596_CB *cb_head; - I596_CB *cb_tail; - - /* Receive Queue */ - I596_RFD *rfd0; - I596_RFD *rfdN; - I596_RFD *rfd_head; - I596_RFD *rfd_tail; - - /* Receive Buffers */ - I596_RBD *rbd0; - I596_RBD *rbdN; - I596_RBD *rbd_head; - I596_RBD *rbd_tail; - int buf_size; /* Size of an RBD buffer */ - int buf_cnt; /* Total RBD's allocated */ - - /* Rx Statistics */ - ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */ - ulong cnt_rx_good; /* Total good packets rcvd */ - ulong cnt_rx_bad; /* Total of all bad packets rcvd */ - /* Subtotals can be gotten from SCB */ - ulong cnt_rx_nores; /* No resources */ - ulong cnt_rx_bytes; /* Total bytes rcvd */ - - /* Tx Statistics */ - ulong cnt_tx_queued; - ulong cnt_tx_done; - ulong cnt_tx_freed; - ulong cnt_tx_nores; /* No resources */ - - ulong cnt_tx_bad; - ulong cnt_tx_err_late; - ulong cnt_tx_err_nocrs; - ulong cnt_tx_err_nocts; - ulong cnt_tx_err_under; - ulong cnt_tx_err_maxcol; - ulong cnt_tx_collisions; - - /* Special stuff for host */ -# define rfd_freed cnt_rx_cnt - ulong rbd_freed; - int host_timer; - - /* Added after first beta */ - ulong cnt_tx_races; /* Counts race conditions */ - int spanstate; - ulong cnt_st_tx; /* send span tree pkts */ - ulong cnt_st_fail_tx; /* Failures to send span tree pkts */ - ulong cnt_st_fail_rbd;/* Failures to send span tree pkts */ - ulong cnt_st_rx; /* rcv span tree pkts */ - ulong cnt_st_rx_bad; /* bogus st packets rcvd */ - ulong cnt_rx_fwd; /* Rcvd packets that were forwarded */ - - ulong cnt_rx_mcast; /* Multicast pkts received */ - ulong cnt_tx_mcast; /* Multicast pkts transmitted */ - ulong cnt_tx_bytes; /* Bytes transmitted */ - - /* - * Packet filtering - * Filter 0: input filter - * Filter 1: output filter - */ - - ulong *filter_space[NFILTERS]; - FILTER_FUNC *filter_func[NFILTERS]; - ulong filter_cnt[NFILTERS]; - ulong filter_len[NFILTERS]; - - ulong pad[ (512-300) / 4]; -} PORT; - -/* - * Port[0] is host interface - * Port[1..SE_NPORTS] are external 10 Base T ports. Fewer may be in - * use, depending on whether this is an SE-4 or - * an SE-6. - * Port[SE_NPORTS] Pseudo-port for Spanning tree and SNMP - */ -extern PORT Port[1+SE_NPORTS+1]; - -extern int Nports; /* Number of genuine ethernet controllers */ -extern int Nchan; /* ... plus one for host interface */ - -extern int FirstChan; /* 0 or 1, depedning on whether host is used */ -extern int NumChan; /* 4 or 5 */ - -/* - * A few globals - */ -extern int IsPromisc; -extern int MultiNicMode; - -/* - * Functions - */ -extern void eth_xmit_spew_on(PORT *p, int cnt); -extern void eth_xmit_spew_off(PORT *p); - -extern I596_RBD *alloc_rbds(PORT *p, int num); - -extern I596_CB * eth_cb_alloc(PORT *p); diff --git a/drivers/net/dgrs_firmware.c b/drivers/net/dgrs_firmware.c deleted file mode 100644 index 8c20d4c99937..000000000000 --- a/drivers/net/dgrs_firmware.c +++ /dev/null @@ -1,9966 +0,0 @@ -static const int dgrs_firmnum = 550; -static char dgrs_firmver[] = "$Version$"; -static char dgrs_firmdate[] = "11/16/96 03:45:15"; -static unsigned char dgrs_code[] __initdata = { - 213,5,192,8,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,64,40,35,41, - 101,115,52,104,46,98,105,110,32,32,32,32, - 32,32,49,46,48,32,48,48,47,48,48,47, - 57,52,0,64,40,35,41,67,111,112,121,114, - 105,103,104,116,32,49,57,57,53,44,32,68, - 105,103,105,32,73,110,116,101,114,110,97,116, - 105,111,110,97,108,46,32,32,65,108,108,32, - 82,105,103,104,116,115,32,82,101,115,101,114, - 118,101,100,46,0,0,0,0,97,5,192,8, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,255,255,0,16,0,0,0,0, - 0,0,0,0,8,0,224,3,0,0,0,0, - 148,255,189,39,16,0,161,175,20,0,162,175, - 24,0,163,175,28,0,164,175,32,0,165,175, - 36,0,166,175,40,0,167,175,44,0,168,175, - 48,0,169,175,52,0,170,175,56,0,171,175, - 60,0,172,175,64,0,173,175,68,0,174,175, - 72,0,175,175,76,0,184,175,80,0,185,175, - 88,0,190,175,92,0,191,175,0,112,8,64, - 18,72,0,0,16,80,0,0,0,96,11,64, - 84,0,168,175,96,0,169,175,100,0,170,175, - 104,0,171,175,33,56,0,1,0,131,24,60, - 0,1,24,39,0,0,8,143,0,0,0,0, - 1,0,8,33,0,0,8,175,0,104,5,64, - 0,96,6,64,124,0,168,48,212,255,0,21, - 0,0,0,0,36,64,166,0,0,255,8,49, - 27,0,0,17,0,0,0,0,130,65,8,0, - 2,131,9,60,33,72,40,1,0,220,41,141, - 66,64,8,0,2,131,10,60,33,80,72,1, - 0,224,74,141,0,0,0,0,38,80,70,1, - 1,255,74,49,33,40,192,0,38,48,202,0, - 0,96,134,64,66,64,8,0,2,131,4,60, - 33,32,136,0,0,226,132,144,9,248,32,1, - 0,0,0,0,104,0,166,143,0,0,0,0, - 0,96,134,64,0,104,5,64,227,255,0,16, - 0,0,0,0,104,0,168,143,96,0,169,143, - 100,0,170,143,0,0,0,0,0,96,136,64, - 19,0,32,1,17,0,64,1,20,0,162,143, - 24,0,163,143,28,0,164,143,32,0,165,143, - 36,0,166,143,40,0,167,143,44,0,168,143, - 48,0,169,143,52,0,170,143,56,0,171,143, - 60,0,172,143,64,0,173,143,68,0,174,143, - 72,0,175,143,76,0,184,143,80,0,185,143, - 88,0,190,143,92,0,191,143,0,0,0,0, - 84,0,186,143,16,0,161,143,108,0,189,39, - 8,0,64,3,16,0,0,66,0,96,26,64, - 0,0,0,0,255,255,27,60,254,0,123,55, - 0,0,0,0,36,208,91,3,0,0,0,0, - 0,96,154,64,0,0,0,0,0,112,26,64, - 0,0,0,0,16,0,0,66,0,0,0,0, - 8,0,64,3,0,0,0,0,255,255,8,36, - 133,255,0,17,0,0,0,0,1,0,8,37, - 130,255,0,21,0,0,0,0,255,255,8,36, - 33,8,0,1,126,255,40,20,0,0,0,0, - 1,0,33,36,123,255,32,20,0,0,0,0, - 255,255,2,36,120,255,72,20,0,0,0,0, - 1,0,66,36,117,255,64,20,0,0,0,0, - 255,255,3,36,114,255,104,20,0,0,0,0, - 1,0,99,36,111,255,96,20,0,0,0,0, - 255,255,4,36,108,255,136,20,0,0,0,0, - 1,0,132,36,105,255,128,20,0,0,0,0, - 255,255,5,36,102,255,168,20,0,0,0,0, - 1,0,165,36,99,255,160,20,0,0,0,0, - 255,255,6,36,96,255,200,20,0,0,0,0, - 1,0,198,36,93,255,192,20,0,0,0,0, - 255,255,7,36,90,255,232,20,0,0,0,0, - 1,0,231,36,87,255,224,20,0,0,0,0, - 255,255,9,36,84,255,40,21,0,0,0,0, - 1,0,41,37,81,255,32,21,0,0,0,0, - 255,255,10,36,78,255,72,21,0,0,0,0, - 1,0,74,37,75,255,64,21,0,0,0,0, - 255,255,11,36,72,255,104,21,0,0,0,0, - 1,0,107,37,69,255,96,21,0,0,0,0, - 255,255,12,36,66,255,136,21,0,0,0,0, - 1,0,140,37,63,255,128,21,0,0,0,0, - 255,255,13,36,60,255,168,21,0,0,0,0, - 1,0,173,37,57,255,160,21,0,0,0,0, - 255,255,14,36,54,255,200,21,0,0,0,0, - 1,0,206,37,51,255,192,21,0,0,0,0, - 255,255,15,36,48,255,232,21,0,0,0,0, - 1,0,239,37,45,255,224,21,0,0,0,0, - 255,255,24,36,42,255,8,23,0,0,0,0, - 1,0,24,39,39,255,0,23,0,0,0,0, - 255,255,16,36,36,255,8,22,0,0,0,0, - 1,0,16,38,33,255,0,22,0,0,0,0, - 255,255,17,36,30,255,40,22,0,0,0,0, - 1,0,49,38,27,255,32,22,0,0,0,0, - 255,255,18,36,24,255,72,22,0,0,0,0, - 1,0,82,38,21,255,64,22,0,0,0,0, - 255,255,19,36,18,255,104,22,0,0,0,0, - 1,0,115,38,15,255,96,22,0,0,0,0, - 255,255,20,36,12,255,136,22,0,0,0,0, - 1,0,148,38,9,255,128,22,0,0,0,0, - 255,255,21,36,6,255,168,22,0,0,0,0, - 1,0,181,38,3,255,160,22,0,0,0,0, - 255,255,22,36,0,255,200,22,0,0,0,0, - 1,0,214,38,253,254,192,22,0,0,0,0, - 255,255,23,36,250,254,232,22,0,0,0,0, - 1,0,247,38,247,254,224,22,0,0,0,0, - 255,255,26,36,244,254,72,23,0,0,0,0, - 1,0,90,39,241,254,64,23,0,0,0,0, - 255,255,27,36,238,254,104,23,0,0,0,0, - 1,0,123,39,235,254,96,23,0,0,0,0, - 255,255,28,36,232,254,136,23,0,0,0,0, - 1,0,156,39,229,254,128,23,0,0,0,0, - 255,255,29,36,226,254,168,23,0,0,0,0, - 1,0,189,39,223,254,160,23,0,0,0,0, - 255,255,30,36,220,254,200,23,0,0,0,0, - 1,0,222,39,217,254,192,23,0,0,0,0, - 255,255,31,36,214,254,232,23,0,0,0,0, - 1,0,255,39,211,254,224,23,0,0,0,0, - 0,131,24,60,0,1,24,39,0,32,1,60, - 37,192,1,3,0,96,8,64,0,0,0,0, - 1,0,1,60,37,64,1,1,0,96,136,64, - 33,16,0,0,165,165,3,60,165,165,99,52, - 0,128,1,60,0,0,35,172,0,128,9,60, - 0,0,41,141,0,0,0,0,0,96,10,64, - 0,0,0,0,8,0,1,60,36,80,65,1, - 29,0,64,21,0,0,0,0,27,0,105,20, - 0,0,0,0,0,1,2,36,0,128,1,60, - 33,8,34,0,0,0,32,172,64,16,2,0, - 1,0,1,60,1,0,33,52,43,8,65,0, - 248,255,32,20,0,0,0,0,255,255,3,36, - 0,128,1,60,0,0,35,172,0,1,2,36, - 0,128,3,60,33,24,98,0,0,0,99,140, - 0,0,0,0,7,0,96,20,0,0,0,0, - 64,16,2,0,1,0,1,60,1,0,33,52, - 43,8,65,0,245,255,32,20,0,0,0,0, - 0,96,128,64,0,0,0,0,84,0,2,175, - 0,96,8,64,0,0,0,0,3,0,1,60, - 37,64,1,1,0,96,136,64,33,16,0,0, - 165,165,3,60,165,165,99,52,0,128,1,60, - 0,0,35,172,0,128,9,60,0,0,41,141, - 0,0,0,0,0,96,10,64,0,0,0,0, - 8,0,1,60,36,80,65,1,29,0,64,21, - 0,0,0,0,27,0,105,20,0,0,0,0, - 0,1,2,36,0,128,1,60,33,8,34,0, - 0,0,32,172,64,16,2,0,1,0,1,60, - 1,0,33,52,43,8,65,0,248,255,32,20, - 0,0,0,0,255,255,3,36,0,128,1,60, - 0,0,35,172,0,1,2,36,0,128,3,60, - 33,24,98,0,0,0,99,140,0,0,0,0, - 7,0,96,20,0,0,0,0,64,16,2,0, - 1,0,1,60,1,0,33,52,43,8,65,0, - 245,255,32,20,0,0,0,0,0,96,128,64, - 0,0,0,0,88,0,2,175,88,0,9,143, - 0,0,0,0,17,0,32,17,0,0,0,0, - 0,0,0,0,3,0,2,60,0,0,0,0, - 0,96,130,64,0,128,8,60,37,72,40,1, - 0,0,0,161,4,0,0,161,8,0,0,161, - 12,0,0,161,16,0,0,161,20,0,0,161, - 24,0,0,161,32,0,8,37,247,255,9,21, - 252,255,0,161,84,0,9,143,0,0,0,0, - 17,0,32,17,0,0,0,0,0,0,0,0, - 1,0,2,60,0,0,0,0,0,96,130,64, - 0,128,8,60,37,72,40,1,0,0,0,161, - 4,0,0,161,8,0,0,161,12,0,0,161, - 16,0,0,161,20,0,0,161,24,0,0,161, - 32,0,8,37,247,255,9,21,252,255,0,161, - 32,0,8,60,0,96,136,64,0,104,128,64, - 0,131,2,60,152,28,66,36,255,31,9,60, - 255,255,41,53,36,16,73,0,0,128,9,60, - 37,16,73,0,8,0,64,0,0,0,0,0, - 2,131,8,60,224,210,8,37,252,255,1,36, - 36,64,1,1,3,131,9,60,124,18,41,37, - 252,255,1,36,36,72,33,1,0,0,10,36, - 0,0,10,173,254,255,9,21,4,0,8,37, - 3,131,8,60,128,18,8,37,252,255,1,36, - 36,64,1,1,31,131,9,60,252,255,41,53, - 252,255,1,36,36,72,33,1,237,254,10,60, - 175,222,74,53,0,0,10,173,254,255,9,21, - 4,0,8,37,2,131,8,60,0,212,8,37, - 252,255,1,36,36,64,1,1,2,131,9,60, - 252,219,41,37,252,255,1,36,36,72,33,1, - 173,222,10,60,239,190,74,53,0,0,10,173, - 254,255,9,21,4,0,8,37,0,4,8,60, - 0,0,0,0,0,24,136,64,0,0,0,0, - 2,131,29,60,0,220,189,39,0,0,30,36, - 2,131,28,60,51,8,192,12,16,78,156,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 232,255,189,39,16,0,191,175,8,128,132,39, - 15,63,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,12,128,132,39, - 15,63,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,16,128,132,39, - 15,63,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,20,128,132,39, - 15,63,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,24,133,131,143,6,0,2,36, - 20,0,191,175,6,0,98,20,16,0,176,175, - 7,162,3,60,228,0,99,52,1,0,2,36, - 184,7,192,8,0,0,98,172,0,128,130,151, - 5,162,16,60,0,1,66,52,120,63,192,12, - 0,0,2,166,0,128,130,151,0,0,0,0, - 255,254,66,48,0,0,2,166,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,33,16,128,0,3,0,64,4, - 16,0,191,175,254,255,2,60,192,29,66,52, - 0,163,4,60,96,1,132,52,0,163,1,60, - 92,1,34,172,0,163,1,60,104,1,38,172, - 204,63,192,12,8,0,6,36,228,63,192,12, - 255,255,4,36,204,7,192,8,0,0,0,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,216,255,189,39,1,0,6,36, - 3,131,2,60,143,18,66,36,240,255,3,36, - 36,16,67,0,0,163,1,60,120,1,34,172, - 0,163,2,60,120,1,66,140,33,56,0,0, - 32,0,191,175,28,0,177,175,24,0,176,175, - 16,0,160,175,0,163,1,60,116,1,34,172, - 0,163,3,60,112,1,99,140,0,163,2,60, - 116,1,66,140,0,163,4,60,116,1,132,140, - 35,136,98,0,84,64,192,12,33,40,32,2, - 13,0,64,16,0,0,0,0,1,131,4,60, - 96,127,132,36,24,128,144,39,33,40,0,2, - 1,131,7,60,128,127,231,36,15,63,192,12, - 148,0,6,36,1,0,4,36,33,40,0,2, - 188,7,192,12,148,0,6,36,2,0,33,6, - 33,16,32,2,3,0,34,38,131,136,2,0, - 0,163,2,60,116,1,66,140,0,0,0,0, - 6,0,32,18,237,254,3,60,175,222,99,52, - 0,0,67,172,255,255,49,38,253,255,32,22, - 4,0,66,36,32,0,191,143,28,0,177,143, - 24,0,176,143,8,0,224,3,40,0,189,39, - 224,255,189,39,15,0,132,36,240,255,3,36, - 20,0,177,175,0,163,17,60,120,1,49,142, - 0,163,2,60,120,1,66,140,36,32,131,0, - 33,16,68,0,0,163,1,60,120,1,34,172, - 0,163,3,60,120,1,99,140,0,163,2,60, - 112,1,66,140,24,0,191,175,43,16,67,0, - 13,0,64,16,16,0,176,175,1,131,4,60, - 96,127,132,36,24,128,144,39,33,40,0,2, - 1,131,7,60,176,127,231,36,15,63,192,12, - 171,0,6,36,1,0,4,36,33,40,0,2, - 188,7,192,12,171,0,6,36,33,16,32,2, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,216,255,189,39, - 3,0,2,60,7,162,3,60,36,0,191,175, - 32,0,176,175,0,163,1,60,92,1,32,172, - 0,0,99,140,79,17,66,52,32,0,98,20, - 87,0,4,60,76,0,8,60,64,75,8,53, - 250,2,7,60,128,240,231,52,7,162,6,60, - 152,0,198,52,67,73,3,60,67,3,99,52, - 7,162,4,60,48,1,132,52,7,162,5,60, - 0,1,165,52,6,0,2,36,24,133,130,175, - 0,163,1,60,204,5,34,172,4,0,2,36, - 50,133,130,167,2,0,2,36,48,133,130,167, - 1,0,2,36,20,133,130,167,119,119,2,36, - 28,133,136,175,16,133,135,175,0,0,195,172, - 0,0,130,172,67,1,2,36,0,0,162,172, - 109,8,192,8,31,131,4,60,240,188,132,52, - 189,2,3,60,128,231,99,52,4,0,2,36, - 24,133,130,175,0,163,1,60,204,5,34,172, - 0,8,2,36,50,133,130,167,0,4,2,36, - 48,133,130,167,0,2,2,36,20,133,130,167, - 28,133,132,175,16,133,131,175,31,131,4,60, - 0,240,132,52,24,133,131,143,0,131,2,60, - 0,163,1,60,108,1,34,172,0,163,1,60, - 112,1,36,172,1,0,99,36,32,133,131,175, - 210,7,192,12,0,0,0,0,0,163,2,60, - 132,1,66,140,0,128,128,167,2,0,64,20, - 85,0,2,36,0,128,130,167,0,163,2,60, - 136,1,66,140,0,0,0,0,5,0,64,20, - 0,0,0,0,0,128,130,151,0,0,0,0, - 170,0,66,52,0,128,130,167,0,128,131,151, - 5,162,2,60,0,0,67,164,188,64,192,12, - 1,0,16,36,2,131,4,60,0,220,132,36, - 2,131,5,60,0,224,165,36,2,131,6,60, - 0,226,198,36,8,0,7,36,2,131,2,60, - 112,154,66,36,16,0,162,175,2,131,2,60, - 144,154,66,36,20,0,162,175,2,131,2,60, - 176,154,66,36,24,0,162,175,0,131,2,60, - 36,30,66,36,0,163,1,60,92,1,48,172, - 240,64,192,12,28,0,162,175,0,163,3,60, - 124,1,99,140,40,133,128,175,2,0,98,40, - 7,0,64,16,2,0,2,36,18,0,97,4, - 255,255,2,36,7,0,98,16,0,0,0,0, - 196,8,192,8,0,0,0,0,16,0,98,16, - 0,0,0,0,196,8,192,8,0,0,0,0, - 24,133,133,143,1,131,4,60,15,63,192,12, - 208,127,132,36,0,163,1,60,112,25,192,12, - 124,1,32,172,207,8,192,8,0,0,0,0, - 211,8,192,12,0,0,0,0,207,8,192,8, - 0,0,0,0,40,133,144,175,31,10,192,12, - 0,0,0,0,207,8,192,8,0,0,0,0, - 1,131,4,60,96,127,132,36,24,128,144,39, - 33,40,0,2,32,128,135,39,15,63,192,12, - 58,1,6,36,1,0,4,36,33,40,0,2, - 188,7,192,12,58,1,6,36,36,0,191,143, - 32,0,176,143,8,0,224,3,40,0,189,39, - 192,255,189,39,56,0,191,175,52,0,181,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,180,10,192,12,32,0,176,175, - 33,32,0,0,2,0,2,36,0,163,1,60, - 244,57,192,12,92,1,34,172,3,0,2,36, - 0,163,1,60,0,12,192,12,92,1,34,172, - 1,0,4,36,4,0,2,36,0,163,1,60, - 34,11,192,12,92,1,34,172,5,0,2,36, - 0,163,1,60,92,1,34,172,0,163,19,60, - 124,1,115,142,0,163,3,60,160,1,99,140, - 1,0,98,46,80,133,130,175,0,128,2,60, - 5,0,98,20,0,0,0,0,32,133,130,143, - 0,0,0,0,252,8,192,8,255,255,66,36, - 32,133,130,143,0,0,0,0,84,133,130,175, - 130,11,192,12,0,0,0,0,33,32,64,0, - 2,0,5,36,232,3,6,36,0,131,7,60, - 196,37,231,36,156,11,192,12,16,0,160,175, - 35,35,192,12,0,0,0,0,6,0,2,36, - 0,163,1,60,84,35,192,12,92,1,34,172, - 7,0,2,36,0,163,1,60,141,47,192,12, - 92,1,34,172,8,0,2,36,0,163,1,60, - 120,50,192,12,92,1,34,172,9,0,2,36, - 0,163,1,60,92,1,34,172,0,163,2,60, - 240,5,66,140,0,0,0,0,8,0,64,16, - 10,0,2,36,0,163,4,60,240,5,132,140, - 13,8,192,12,0,0,0,0,0,163,1,60, - 244,5,34,172,10,0,2,36,0,163,1,60, - 92,1,34,172,157,15,192,12,1,0,21,36, - 2,131,2,60,192,246,66,36,33,160,64,0, - 80,133,131,143,11,0,2,36,0,163,1,60, - 92,1,34,172,100,0,2,36,0,163,1,60, - 92,1,34,172,84,133,130,143,64,26,3,0, - 33,136,116,0,64,18,2,0,33,144,84,0, - 0,163,2,60,8,1,66,140,0,0,0,0, - 1,0,66,36,0,163,1,60,8,1,34,172, - 0,163,2,60,8,1,66,140,0,163,2,60, - 124,1,66,140,0,0,0,0,14,0,83,16, - 0,0,0,0,4,0,64,16,33,152,64,0, - 80,133,128,175,76,9,192,8,0,0,0,0, - 80,133,149,175,2,131,4,60,163,23,192,12, - 192,246,132,36,80,133,130,143,0,0,0,0, - 64,18,2,0,33,136,84,0,0,163,2,60, - 0,6,66,140,0,0,0,0,3,0,64,24, - 33,128,32,2,239,15,192,12,0,0,0,0, - 43,16,18,2,11,0,64,16,33,32,0,2, - 151,18,192,12,10,0,5,36,27,22,192,12, - 33,32,0,2,142,22,192,12,33,32,0,2, - 0,2,16,38,43,16,18,2,247,255,64,20, - 33,32,0,2,184,11,192,12,0,0,0,0, - 54,9,192,8,0,0,0,0,56,0,191,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,4,128,130,143, - 232,255,189,39,20,0,191,175,16,0,176,175, - 1,0,67,36,4,128,131,175,255,255,3,36, - 4,0,67,20,255,31,4,60,0,163,1,60, - 8,1,32,172,255,31,4,60,255,255,132,52, - 0,163,16,60,0,163,2,60,8,1,66,140, - 208,132,131,143,220,5,16,54,35,16,67,0, - 0,163,1,60,16,1,34,172,2,131,2,60, - 192,246,66,36,36,16,68,0,0,160,3,60, - 37,16,67,0,0,163,3,60,8,1,99,140, - 28,0,68,140,0,0,5,142,3,131,2,60, - 20,18,66,140,208,132,131,175,36,133,132,175, - 18,0,162,16,0,163,4,60,99,59,192,12, - 220,5,132,52,255,0,5,60,255,0,165,52, - 0,255,6,60,0,0,4,142,0,255,198,52, - 0,20,4,0,2,28,4,0,37,16,67,0, - 2,26,2,0,36,24,101,0,0,18,2,0, - 36,16,70,0,37,24,98,0,176,133,132,175, - 184,133,131,175,0,163,16,60,16,6,16,54, - 0,0,3,142,3,131,2,60,68,18,66,140, - 0,0,0,0,18,0,98,16,0,163,4,60, - 119,59,192,12,16,6,132,52,255,0,5,60, - 255,0,165,52,0,255,6,60,0,0,4,142, - 0,255,198,52,0,20,4,0,2,28,4,0, - 37,16,67,0,2,26,2,0,36,24,101,0, - 0,18,2,0,36,16,70,0,37,24,98,0, - 196,133,132,175,192,133,131,175,0,163,16,60, - 224,5,16,54,0,0,3,142,3,131,2,60, - 24,18,66,140,0,0,0,0,18,0,98,16, - 0,163,4,60,139,59,192,12,224,5,132,52, - 255,0,5,60,255,0,165,52,0,255,6,60, - 0,0,4,142,0,255,198,52,0,20,4,0, - 2,28,4,0,37,16,67,0,2,26,2,0, - 36,24,101,0,0,18,2,0,36,16,70,0, - 37,24,98,0,188,133,132,175,180,133,131,175, - 44,133,131,143,0,163,2,60,144,1,66,140, - 0,0,0,0,5,0,98,16,0,0,0,0, - 0,163,4,60,144,1,132,140,159,59,192,12, - 0,0,0,0,0,163,3,60,140,1,99,140, - 3,131,2,60,64,18,66,140,0,0,0,0, - 5,0,98,16,0,0,0,0,0,163,4,60, - 140,1,132,140,51,60,192,12,0,0,0,0, - 44,133,130,143,0,0,0,0,3,0,64,16, - 0,0,0,0,116,38,192,12,0,0,0,0, - 164,7,192,12,0,0,0,0,36,128,130,143, - 0,0,0,0,1,0,66,36,36,128,130,175, - 60,0,66,40,8,0,64,20,0,0,0,0, - 3,131,2,60,24,18,66,140,36,128,128,175, - 3,0,64,16,0,0,0,0,222,48,192,12, - 0,0,0,0,0,163,2,60,48,1,66,140, - 0,0,0,0,20,0,64,16,0,0,0,0, - 0,163,1,60,48,1,32,172,0,163,1,60, - 16,1,32,172,0,163,1,60,20,1,32,172, - 0,163,1,60,24,1,32,172,0,163,1,60, - 28,1,32,172,0,163,1,60,32,1,32,172, - 0,163,1,60,36,1,32,172,0,163,1,60, - 40,1,32,172,0,163,1,60,201,13,192,12, - 44,1,32,172,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,216,255,189,39, - 36,0,191,175,32,0,178,175,28,0,177,175, - 180,10,192,12,24,0,176,175,33,32,0,0, - 2,0,2,36,0,163,1,60,244,57,192,12, - 92,1,34,172,3,0,2,36,0,163,1,60, - 0,12,192,12,92,1,34,172,1,0,4,36, - 4,0,2,36,0,163,1,60,34,11,192,12, - 92,1,34,172,32,133,131,143,5,0,2,36, - 0,163,1,60,92,1,34,172,80,133,128,175, - 84,133,131,175,130,11,192,12,0,0,0,0, - 33,32,64,0,2,0,5,36,232,3,6,36, - 0,131,7,60,196,37,231,36,156,11,192,12, - 16,0,160,175,0,163,2,60,240,5,66,140, - 0,0,0,0,8,0,64,16,10,0,2,36, - 0,163,4,60,240,5,132,140,13,8,192,12, - 0,0,0,0,0,163,1,60,244,5,34,172, - 10,0,2,36,0,163,1,60,92,1,34,172, - 100,0,2,36,80,133,131,143,2,131,4,60, - 192,246,132,36,0,163,1,60,92,1,34,172, - 84,133,130,143,64,26,3,0,33,144,100,0, - 64,18,2,0,33,136,68,0,0,163,2,60, - 8,1,66,140,33,128,64,2,1,0,66,36, - 0,163,1,60,8,1,34,172,0,163,2,60, - 8,1,66,140,43,16,17,2,11,0,64,16, - 33,32,0,2,151,18,192,12,10,0,5,36, - 27,22,192,12,33,32,0,2,142,22,192,12, - 33,32,0,2,0,2,16,38,43,16,17,2, - 247,255,64,20,33,32,0,2,184,11,192,12, - 0,0,0,0,91,10,192,8,0,0,0,0, - 36,0,191,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,40,0,189,39, - 4,128,130,143,232,255,189,39,16,0,191,175, - 1,0,67,36,4,128,131,175,255,255,3,36, - 4,0,67,20,255,31,4,60,0,163,1,60, - 8,1,32,172,255,31,4,60,0,163,2,60, - 8,1,66,140,212,132,131,143,255,255,132,52, - 35,16,67,0,0,163,1,60,16,1,34,172, - 2,131,2,60,192,246,66,36,36,16,68,0, - 0,160,3,60,37,16,67,0,0,163,3,60, - 8,1,99,140,28,0,66,140,212,132,131,175, - 36,133,130,175,164,7,192,12,0,0,0,0, - 0,163,2,60,48,1,66,140,0,0,0,0, - 20,0,64,16,0,0,0,0,0,163,1,60, - 48,1,32,172,0,163,1,60,16,1,32,172, - 0,163,1,60,20,1,32,172,0,163,1,60, - 24,1,32,172,0,163,1,60,28,1,32,172, - 0,163,1,60,32,1,32,172,0,163,1,60, - 36,1,32,172,0,163,1,60,40,1,32,172, - 0,163,1,60,201,13,192,12,44,1,32,172, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,224,255,189,39,24,0,191,175, - 20,0,177,175,120,63,192,12,16,0,176,175, - 52,0,2,36,4,162,1,60,12,0,34,160, - 120,63,192,12,232,3,16,36,28,133,130,143, - 0,0,0,0,27,0,80,0,2,0,0,22, - 0,0,0,0,13,0,7,0,18,16,0,0, - 4,162,17,60,120,63,192,12,0,0,34,162, - 28,133,130,143,0,0,0,0,27,0,80,0, - 2,0,0,22,0,0,0,0,13,0,7,0, - 18,16,0,0,33,40,0,0,33,32,0,0, - 6,162,3,60,2,18,2,0,0,0,34,162, - 1,0,2,36,0,163,1,60,4,1,32,172, - 0,0,98,172,2,131,1,60,33,8,36,0, - 8,245,32,172,1,0,165,36,22,0,162,44, - 250,255,64,20,20,0,132,36,31,131,4,60, - 0,240,132,52,52,128,131,143,1,0,2,36, - 68,133,128,175,48,128,130,175,64,133,128,175, - 32,131,1,60,252,239,36,172,8,0,96,16, - 31,131,5,60,252,239,165,52,31,131,6,60, - 1,131,4,60,224,127,132,36,15,63,192,12, - 0,240,198,52,52,128,128,175,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,16,0,176,175, - 116,0,2,36,20,0,191,175,4,162,1,60, - 12,0,34,160,130,63,192,12,33,128,128,0, - 4,162,1,60,4,0,48,160,130,63,192,12, - 3,130,16,0,4,162,1,60,130,63,192,12, - 4,0,48,160,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,224,255,189,39, - 64,0,2,36,24,0,191,175,20,0,177,175, - 16,0,176,175,4,162,1,60,130,63,192,12, - 12,0,34,160,4,162,17,60,4,0,49,146, - 0,0,0,0,130,63,192,12,255,0,49,50, - 4,162,16,60,4,0,16,146,0,0,0,0, - 130,63,192,12,255,0,16,50,0,130,16,0, - 37,16,17,2,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 48,128,130,143,232,255,189,39,16,0,176,175, - 33,128,128,0,3,0,64,20,20,0,191,175, - 180,10,192,12,0,0,0,0,5,0,0,18, - 0,0,0,0,236,63,192,12,1,4,4,36, - 50,11,192,8,0,0,0,0,228,63,192,12, - 0,4,4,36,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,216,255,189,39, - 6,162,3,60,1,0,2,36,32,0,191,175, - 28,0,177,175,24,0,176,175,0,0,98,172, - 0,163,2,60,4,1,66,140,33,136,224,0, - 1,0,66,36,0,163,1,60,4,1,34,172, - 56,128,130,143,0,163,3,60,4,1,99,140, - 1,0,66,36,56,128,130,175,232,3,66,40, - 21,0,64,20,255,127,3,60,68,133,130,143, - 254,255,99,52,56,128,128,175,1,0,66,36, - 43,24,98,0,68,133,130,175,13,0,96,16, - 0,0,0,0,2,131,4,60,28,128,132,36, - 60,128,144,39,33,40,0,2,2,131,7,60, - 60,128,231,36,15,63,192,12,144,0,6,36, - 1,0,4,36,33,40,0,2,188,7,192,12, - 144,0,6,36,64,133,134,143,0,0,0,0, - 14,0,192,24,33,24,0,0,2,131,5,60, - 0,245,165,36,33,32,0,0,2,131,2,60, - 33,16,68,0,0,245,66,140,20,0,132,36, - 1,0,99,36,255,255,66,36,0,0,162,172, - 42,16,102,0,247,255,64,20,20,0,165,36, - 31,131,4,60,252,239,132,52,31,131,2,60, - 0,0,131,140,255,255,66,52,0,0,113,172, - 4,0,99,36,43,16,67,0,3,0,64,16, - 0,0,0,0,31,131,3,60,0,240,99,52, - 0,0,131,172,32,0,191,143,28,0,177,143, - 24,0,176,143,8,0,224,3,40,0,189,39, - 64,133,130,143,232,255,189,39,20,0,191,175, - 22,0,66,40,13,0,64,20,16,0,176,175, - 2,131,4,60,28,128,132,36,60,128,144,39, - 33,40,0,2,2,131,7,60,84,128,231,36, - 15,63,192,12,173,0,6,36,1,0,4,36, - 33,40,0,2,188,7,192,12,173,0,6,36, - 64,133,130,143,0,0,0,0,1,0,67,36, - 64,133,131,175,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,128,16,4,0, - 33,16,68,0,16,0,163,143,128,16,2,0, - 2,131,1,60,33,8,34,0,4,245,38,172, - 2,131,1,60,33,8,34,0,12,245,39,172, - 2,131,1,60,33,8,34,0,0,245,38,172, - 2,131,1,60,33,8,34,0,8,245,37,172, - 2,131,1,60,33,8,34,0,16,245,35,172, - 8,0,224,3,33,16,0,1,128,16,4,0, - 33,16,68,0,128,16,2,0,2,131,1,60, - 33,8,34,0,8,0,224,3,8,245,32,172, - 64,133,130,143,192,255,189,39,40,0,180,175, - 33,160,0,0,56,0,191,175,52,0,183,175, - 48,0,182,175,44,0,181,175,36,0,179,175, - 32,0,178,175,28,0,177,175,48,0,64,24, - 24,0,176,175,1,0,23,36,2,0,22,36, - 2,131,16,60,12,245,16,38,4,0,19,38, - 244,255,17,38,252,255,18,38,33,168,0,0, - 0,0,67,142,0,0,0,0,7,0,119,16, - 2,0,98,40,25,0,64,20,0,0,0,0, - 9,0,118,16,0,0,0,0,236,11,192,8, - 20,0,16,38,0,0,34,142,0,0,0,0, - 17,0,64,28,0,0,0,0,230,11,192,8, - 0,0,64,174,0,0,34,142,0,0,0,0, - 11,0,64,28,0,0,0,0,2,131,2,60, - 33,16,85,0,4,245,66,140,0,0,0,0, - 0,0,34,174,0,0,100,142,0,0,2,142, - 0,0,0,0,9,248,64,0,0,0,0,0, - 20,0,16,38,20,0,115,38,20,0,49,38, - 20,0,82,38,64,133,130,143,1,0,148,38, - 42,16,130,2,218,255,64,20,20,0,181,38, - 56,0,191,143,52,0,183,143,48,0,182,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,64,0,189,39,0,0,0,0, - 2,131,3,60,192,246,99,36,0,2,2,36, - 0,163,1,60,200,5,35,172,0,163,1,60, - 208,5,34,172,0,163,2,60,124,1,66,140, - 216,255,189,39,16,0,176,175,33,128,0,0, - 28,0,179,175,255,255,19,36,24,0,178,175, - 21,0,114,36,20,0,177,175,32,0,191,175, - 1,0,66,44,80,133,130,175,139,14,192,12, - 20,0,113,36,184,24,192,12,0,0,0,0, - 27,67,192,12,33,32,0,2,6,0,83,20, - 1,0,16,38,2,131,4,60,15,63,192,12, - 112,128,132,36,126,12,192,8,1,0,2,36, - 0,0,34,162,3,18,2,0,0,0,66,162, - 2,0,82,38,3,0,2,42,241,255,64,20, - 2,0,49,38,2,131,17,60,212,246,49,38, - 33,32,32,2,33,40,0,0,255,127,6,60, - 247,24,192,12,255,255,198,52,255,31,3,60, - 255,255,99,52,236,255,48,38,36,0,34,38, - 36,16,67,0,0,160,3,60,37,16,67,0, - 0,32,3,36,236,255,32,174,2,131,1,60, - 220,246,32,172,2,131,1,60,204,246,32,172, - 2,131,1,60,236,246,34,172,0,0,67,164, - 222,21,192,12,33,32,0,2,122,15,192,12, - 33,32,0,2,242,21,192,12,33,32,0,2, - 32,133,130,143,1,0,16,36,42,16,2,2, - 12,0,64,16,255,31,3,60,236,1,49,38, - 133,12,192,12,33,32,0,2,242,21,192,12, - 33,32,32,2,32,133,130,143,1,0,16,38, - 42,16,2,2,248,255,64,20,0,2,49,38, - 255,31,3,60,255,255,99,52,2,131,16,60, - 192,4,16,38,7,0,2,36,0,0,2,174, - 56,0,2,38,36,16,67,0,0,160,3,60, - 37,16,67,0,0,32,3,36,2,131,1,60, - 220,4,32,172,2,131,1,60,204,4,32,172, - 2,131,1,60,236,4,34,172,0,0,67,164, - 2,131,2,60,212,246,66,140,2,131,3,60, - 216,246,99,132,20,0,2,174,24,0,3,166, - 2,131,2,60,217,4,66,144,0,0,0,0, - 7,0,66,36,2,131,1,60,217,4,34,160, - 112,15,192,12,33,32,0,2,33,32,0,2, - 19,15,192,12,32,0,5,36,20,0,16,38, - 33,32,0,2,7,0,5,36,255,127,6,60, - 247,24,192,12,255,255,198,52,33,16,0,0, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,200,255,189,39,48,0,180,175, - 33,160,128,0,255,31,6,60,255,255,198,52, - 64,26,20,0,2,131,2,60,192,246,66,36, - 40,0,178,175,33,144,98,0,255,255,132,38, - 64,18,4,0,0,162,3,60,33,16,67,0, - 52,0,191,175,44,0,179,175,36,0,177,175, - 32,0,176,175,4,0,66,174,0,1,66,36, - 8,0,66,174,0,16,2,36,4,16,130,0, - 12,0,66,174,4,0,2,36,4,16,130,0, - 0,160,5,60,16,0,66,174,48,0,66,38, - 36,16,70,0,37,16,69,0,36,0,66,174, - 64,16,4,0,33,16,68,0,128,16,2,0, - 2,131,3,60,240,231,99,36,33,16,67,0, - 36,16,70,0,37,16,69,0,40,0,66,174, - 56,0,66,38,36,16,70,0,37,16,69,0, - 0,0,84,174,44,0,66,174,32,0,64,174, - 2,131,2,60,212,246,66,140,2,131,3,60, - 216,246,99,132,20,0,66,174,24,0,67,166, - 25,0,66,146,0,0,0,0,33,32,84,0, - 2,131,2,60,0,227,66,36,36,16,70,0, - 37,128,69,0,2,131,2,60,32,227,66,36, - 36,16,70,0,25,0,68,162,40,133,131,143, - 0,0,0,0,3,0,96,16,37,136,69,0, - 255,255,130,36,25,0,66,162,12,0,68,142, - 28,0,64,174,228,63,192,12,1,0,132,52, - 4,0,68,142,0,0,0,0,76,67,192,12, - 33,40,0,0,76,63,192,12,0,0,0,0, - 76,63,192,12,0,0,0,0,255,255,2,36, - 4,0,2,174,4,0,2,142,0,0,0,0, - 0,0,2,174,4,0,68,142,0,0,0,0, - 76,67,192,12,1,0,5,54,4,0,4,38, - 33,40,0,0,255,255,6,36,211,67,192,12, - 208,7,7,36,8,0,64,20,255,255,2,52, - 2,131,4,60,184,128,132,36,4,0,6,142, - 0,0,0,0,15,63,192,12,33,40,128,2, - 255,255,2,52,48,1,34,174,4,0,68,142, - 0,0,0,0,76,67,192,12,3,0,37,54, - 48,1,36,38,33,40,0,0,255,255,6,52, - 211,67,192,12,208,7,7,36,7,0,64,20, - 0,0,0,0,2,131,4,60,8,129,132,36, - 48,1,38,142,0,0,0,0,15,63,192,12, - 33,40,128,2,143,63,192,12,0,0,0,0, - 40,0,69,142,4,0,68,142,0,0,0,0, - 76,67,192,12,2,0,165,52,44,0,81,142, - 84,128,131,143,80,128,132,143,100,0,2,36, - 0,0,32,166,2,0,32,166,4,0,32,174, - 8,0,32,174,12,0,32,174,16,0,32,174, - 24,0,32,174,20,0,32,174,28,0,32,174, - 32,0,32,174,36,0,34,166,38,0,34,166, - 36,0,35,166,38,0,36,166,36,0,83,142, - 1,0,2,36,0,0,98,174,44,0,66,142, - 0,0,0,0,4,0,98,174,40,0,67,142, - 116,0,2,60,0,0,98,172,40,0,67,142, - 36,0,66,142,0,0,0,0,8,0,98,172, - 8,0,66,142,0,0,0,0,0,0,64,172, - 0,0,98,142,0,0,0,0,10,0,64,16, - 33,128,0,0,208,7,2,42,7,0,64,16, - 0,0,0,0,143,63,192,12,0,0,0,0, - 0,0,98,142,0,0,0,0,248,255,64,20, - 1,0,16,38,0,0,98,142,0,0,0,0, - 6,0,64,16,33,32,32,2,2,131,4,60, - 76,129,132,36,15,63,192,12,33,40,128,2, - 33,32,32,2,8,0,5,36,0,0,34,150, - 8,0,6,36,0,240,66,48,0,6,66,52, - 2,0,34,166,8,0,66,142,208,7,7,36, - 129,67,192,12,0,0,64,172,6,0,64,20, - 2,0,36,38,2,131,4,60,160,129,132,36, - 15,63,192,12,33,40,128,2,2,0,36,38, - 33,40,0,0,0,0,34,150,33,48,0,0, - 0,240,66,48,2,0,34,166,8,0,66,142, - 208,7,7,36,129,67,192,12,0,0,64,172, - 4,0,64,20,0,0,0,0,2,131,4,60, - 15,63,192,12,248,129,132,36,143,63,192,12, - 0,0,0,0,108,0,80,142,0,128,2,52, - 0,0,0,166,2,0,2,166,44,0,66,142, - 0,32,5,36,4,0,80,172,44,0,67,142, - 0,241,2,52,2,0,98,164,8,0,66,142, - 0,32,6,36,0,0,64,172,44,0,68,142, - 0,0,0,0,129,67,192,12,208,7,7,36, - 12,0,64,20,0,0,0,0,44,0,66,142, - 0,0,0,0,0,0,69,148,2,131,4,60, - 15,63,192,12,16,130,132,36,254,255,4,36, - 2,131,5,60,44,130,165,36,188,7,192,12, - 1,1,6,36,108,0,80,142,2,128,2,52, - 0,0,0,166,2,0,2,166,14,0,2,36, - 8,0,2,162,200,0,2,36,9,0,2,162, - 65,0,2,36,10,0,2,162,46,0,2,36, - 11,0,2,162,87,0,2,36,12,0,0,162, - 13,0,2,162,242,0,2,36,14,0,0,162, - 15,0,2,162,1,0,2,36,16,0,2,162, - 8,0,2,36,17,0,2,162,88,128,130,143, - 0,0,0,0,6,0,64,16,64,0,2,36, - 2,131,4,60,15,63,192,12,56,130,132,36, - 88,128,128,175,64,0,2,36,18,0,2,162, - 255,0,2,36,19,0,2,162,63,0,2,36, - 20,0,0,162,21,0,2,162,44,0,66,142, - 0,32,5,36,4,0,80,172,44,0,67,142, - 0,33,2,36,2,0,98,164,8,0,66,142, - 0,32,6,36,0,0,64,172,44,0,68,142, - 0,0,0,0,129,67,192,12,208,7,7,36, - 12,0,64,20,0,0,0,0,44,0,66,142, - 0,0,0,0,0,0,69,148,2,131,4,60, - 15,63,192,12,16,130,132,36,253,255,4,36, - 2,131,5,60,44,130,165,36,188,7,192,12, - 85,1,6,36,222,21,192,12,33,32,64,2, - 122,15,192,12,33,32,64,2,52,0,191,143, - 48,0,180,143,44,0,179,143,40,0,178,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 56,0,189,39,248,255,189,39,32,133,133,143, - 0,0,0,0,50,0,160,24,33,32,0,0, - 2,131,3,60,192,246,99,36,44,0,98,140, - 152,0,96,172,156,0,96,172,160,0,96,172, - 164,0,96,172,168,0,96,172,172,0,96,172, - 176,0,96,172,180,0,96,172,184,0,96,172, - 188,0,96,172,192,0,96,172,196,0,96,172, - 200,0,96,172,204,0,96,172,208,0,96,172, - 212,0,96,172,216,0,96,172,224,0,96,172, - 232,0,96,172,236,0,96,172,240,0,96,172, - 244,0,96,172,248,0,96,172,252,0,96,172, - 0,1,96,172,4,1,96,172,8,1,96,172, - 12,0,64,172,44,0,98,140,0,0,0,0, - 16,0,64,172,44,0,98,140,0,0,0,0, - 24,0,64,172,44,0,98,140,0,0,0,0, - 20,0,64,172,44,0,98,140,1,0,132,36, - 28,0,64,172,44,0,98,140,0,2,99,36, - 32,0,64,172,42,16,133,0,210,255,64,20, - 0,0,0,0,33,32,0,0,0,163,3,60, - 0,1,99,52,32,0,5,36,33,16,131,0, - 188,0,69,160,1,0,132,36,0,2,130,44, - 251,255,64,20,0,0,0,0,8,0,224,3, - 8,0,189,39,0,0,0,0,124,133,130,143, - 232,255,189,39,20,0,191,175,17,0,64,20, - 16,0,176,175,208,7,16,36,7,0,0,26, - 0,0,0,0,143,63,192,12,255,255,16,38, - 124,133,130,143,0,0,0,0,249,255,64,16, - 0,0,0,0,6,0,0,22,0,0,0,0, - 2,131,4,60,15,63,192,12,80,130,132,36, - 45,14,192,8,33,16,0,0,220,63,192,12, - 33,32,0,0,33,32,64,0,124,133,144,143, - 128,133,130,143,4,0,3,142,255,255,66,36, - 128,133,130,175,124,133,131,175,220,63,192,12, - 0,0,0,0,33,16,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,96,133,130,143,33,40,128,0, - 43,16,162,0,6,0,64,20,16,0,191,175, - 100,133,130,143,0,0,0,0,43,16,162,0, - 6,0,64,20,0,0,0,0,2,131,4,60, - 15,63,192,12,116,130,132,36,71,14,192,8, - 0,0,0,0,124,133,131,143,128,133,130,143, - 124,133,133,175,1,0,66,36,4,0,163,172, - 128,133,130,175,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,108,133,130,143, - 232,255,189,39,20,0,191,175,17,0,64,20, - 16,0,176,175,208,7,16,36,7,0,0,26, - 0,0,0,0,143,63,192,12,255,255,16,38, - 108,133,130,143,0,0,0,0,249,255,64,16, - 0,0,0,0,6,0,0,22,0,0,0,0, - 2,131,4,60,15,63,192,12,148,130,132,36, - 108,14,192,8,33,16,0,0,220,63,192,12, - 33,32,0,0,33,32,64,0,108,133,144,143, - 120,133,130,143,0,0,3,142,255,255,66,36, - 120,133,130,175,108,133,131,175,220,63,192,12, - 0,0,0,0,33,16,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,104,133,130,143,33,40,128,0, - 43,16,162,0,6,0,64,20,16,0,191,175, - 112,133,130,143,0,0,0,0,43,16,162,0, - 6,0,64,20,0,0,0,0,2,131,4,60, - 15,63,192,12,184,130,132,36,135,14,192,8, - 0,0,0,0,108,133,130,143,0,0,0,0, - 0,0,162,172,120,133,130,143,108,133,133,175, - 1,0,66,36,120,133,130,175,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,20,0,191,175,16,0,176,175, - 124,133,128,175,13,8,192,12,0,32,4,36, - 255,31,3,60,255,255,99,52,255,1,16,36, - 36,16,67,0,0,160,3,60,37,16,67,0, - 96,133,130,175,0,32,66,36,100,133,130,175, - 0,17,16,0,96,133,132,143,255,255,16,38, - 49,14,192,12,33,32,130,0,251,255,1,6, - 0,17,16,0,0,2,2,36,132,133,130,175, - 108,133,128,175,13,8,192,12,18,0,4,60, - 255,31,3,60,255,255,99,52,255,17,16,36, - 36,16,67,0,0,160,3,60,37,16,67,0, - 18,0,3,60,104,133,130,175,33,16,67,0, - 112,133,130,175,0,18,16,0,104,133,132,143, - 255,255,16,38,112,14,192,12,33,32,130,0, - 251,255,1,6,0,18,16,0,0,18,2,36, - 116,133,130,175,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,0,0,0,0, - 0,0,0,0,0,0,0,0,0,163,2,60, - 168,1,66,140,216,255,189,39,28,0,177,175, - 33,136,128,0,32,0,178,175,33,144,160,0, - 36,0,191,175,17,0,64,16,24,0,176,175, - 0,163,2,60,168,1,66,140,0,0,0,0, - 42,16,82,0,12,0,64,16,128,128,18,0, - 0,0,34,142,0,163,18,60,168,1,82,142, - 0,0,0,0,6,0,64,20,128,128,18,0, - 2,131,4,60,224,130,132,36,15,63,192,12, - 33,40,64,2,128,128,18,0,33,128,18,2, - 128,128,16,0,13,8,192,12,33,32,0,2, - 255,31,3,60,255,255,99,52,33,32,0,0, - 36,16,67,0,0,160,3,60,37,16,67,0, - 112,0,34,174,112,0,35,142,33,16,80,0, - 15,0,64,26,116,0,34,174,8,0,5,36, - 1,0,132,36,20,0,98,36,4,0,98,172, - 2,0,101,164,0,0,96,164,8,0,96,172, - 14,0,96,164,12,0,96,164,33,24,64,0, - 42,16,146,0,246,255,64,20,1,0,132,36, - 255,255,132,36,116,0,35,142,112,0,34,142, - 0,0,0,0,240,255,98,172,116,0,35,142, - 0,0,0,0,218,255,98,148,0,0,0,0, - 0,128,66,52,218,255,98,164,116,0,35,142, - 0,0,0,0,238,255,98,148,0,0,0,0, - 0,128,66,52,238,255,98,164,116,0,34,142, - 112,0,35,142,216,255,66,36,120,0,35,174, - 124,0,34,174,36,0,191,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,200,255,189,39,32,0,178,175, - 33,144,128,0,0,1,2,36,48,0,191,175, - 44,0,181,175,40,0,180,175,36,0,179,175, - 28,0,177,175,24,0,176,175,144,0,66,174, - 0,163,2,60,172,1,66,140,0,0,0,0, - 17,0,64,16,33,160,160,0,0,163,2,60, - 172,1,66,140,0,0,0,0,42,16,84,0, - 12,0,64,16,128,128,20,0,0,0,66,142, - 0,163,20,60,172,1,148,142,0,0,0,0, - 6,0,64,20,128,128,20,0,2,131,4,60, - 236,130,132,36,15,63,192,12,33,40,128,2, - 128,128,20,0,33,128,20,2,128,128,16,0, - 33,32,0,2,13,8,192,12,148,0,84,174, - 255,31,3,60,255,255,99,52,33,152,0,0, - 36,16,67,0,0,160,3,60,37,16,67,0, - 128,0,66,174,128,0,81,142,33,16,80,0, - 15,0,128,26,132,0,66,174,0,1,21,36, - 20,0,48,38,4,0,48,174,75,14,192,12, - 0,0,32,174,8,0,34,174,12,0,53,174, - 0,0,66,142,1,0,115,38,16,0,34,162, - 17,0,32,162,42,16,116,2,244,255,64,20, - 33,136,0,2,132,0,67,142,128,0,66,142, - 0,0,0,0,240,255,98,172,132,0,67,142, - 0,0,0,0,228,255,98,140,0,0,0,0, - 0,128,66,52,228,255,98,172,132,0,67,142, - 0,0,0,0,248,255,98,140,0,0,0,0, - 0,128,66,52,248,255,98,172,132,0,66,142, - 128,0,67,142,216,255,66,36,136,0,67,174, - 140,0,66,174,48,0,191,143,44,0,181,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 56,0,189,39,152,0,128,172,156,0,128,172, - 160,0,128,172,164,0,128,172,168,0,128,172, - 252,0,128,172,0,1,128,172,152,0,128,172, - 8,0,224,3,216,0,128,172,232,255,189,39, - 16,0,176,175,20,0,191,175,112,15,192,12, - 33,128,128,0,33,32,0,2,192,14,192,12, - 0,4,5,36,33,32,0,2,19,15,192,12, - 128,2,5,36,120,0,3,142,136,0,2,142, - 0,0,0,0,8,0,98,172,44,0,3,142, - 120,0,2,142,0,0,0,0,8,0,98,172, - 0,0,2,142,0,0,0,0,255,255,66,36, - 6,0,66,44,7,0,64,16,16,0,3,36, - 44,0,2,142,0,0,0,0,2,0,67,164, - 8,0,2,142,0,0,0,0,0,0,64,172, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,184,255,189,39,0,32,6,36, - 68,0,191,175,64,0,190,175,60,0,183,175, - 56,0,182,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,0,163,1,60,252,5,38,172, - 13,8,192,12,0,32,4,36,255,31,4,60, - 255,255,132,52,33,168,0,0,255,31,6,60, - 255,255,198,52,2,131,3,60,212,247,99,36, - 16,0,101,36,8,0,126,36,248,255,119,36, - 33,176,96,0,36,16,68,0,0,160,3,60, - 37,16,67,0,16,0,166,175,0,163,1,60, - 248,5,34,172,0,163,1,60,0,6,32,172, - 33,160,0,0,33,128,224,2,33,152,160,0, - 33,144,192,3,33,136,192,2,32,133,130,143, - 0,0,32,174,0,0,0,174,0,0,64,174, - 42,16,162,2,10,0,64,16,0,0,96,174, - 0,32,4,36,13,8,192,12,24,0,165,175, - 16,0,166,143,0,128,3,60,36,16,70,0, - 37,16,67,0,0,0,2,174,24,0,165,143, - 4,0,16,38,4,0,115,38,4,0,82,38, - 1,0,148,38,2,0,130,42,234,255,64,20, - 4,0,49,38,0,2,165,36,0,2,222,39, - 0,2,247,38,1,0,181,38,7,0,162,42, - 222,255,64,20,0,2,214,38,68,0,191,143, - 64,0,190,143,60,0,183,143,56,0,182,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,72,0,189,39,0,163,4,60, - 0,6,132,140,0,163,3,60,8,6,99,140, - 32,133,130,143,224,255,189,39,16,0,176,175, - 0,163,16,60,12,6,16,142,20,0,177,175, - 0,163,17,60,4,6,49,142,43,16,98,0, - 42,0,64,16,24,0,191,175,2,0,2,46, - 40,0,64,16,255,255,2,36,0,163,2,60, - 252,5,66,140,0,0,0,0,43,16,81,0, - 34,0,64,20,255,255,2,36,64,18,3,0, - 2,131,3,60,192,246,99,36,33,24,67,0, - 1,0,2,36,5,0,130,16,2,0,2,36, - 18,0,130,16,128,16,16,0,36,16,192,8, - 0,0,0,0,128,128,16,0,33,128,3,2, - 12,1,4,142,0,163,5,60,248,5,165,140, - 33,48,32,2,80,68,192,12,36,1,17,174, - 12,1,4,142,12,1,2,142,33,40,32,2, - 114,68,192,12,20,1,2,174,36,16,192,8, - 0,0,0,0,33,16,67,0,20,1,64,172, - 36,1,64,172,0,163,1,60,42,16,192,8, - 0,6,32,172,255,255,2,36,0,163,1,60, - 0,6,34,172,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 176,133,136,143,188,133,137,143,232,255,189,39, - 3,0,0,21,16,0,191,175,124,0,32,17, - 0,0,0,0,12,0,194,148,0,0,0,0, - 0,26,2,0,2,18,2,0,37,56,98,0, - 255,255,227,48,221,5,98,44,36,0,64,20, - 170,170,2,52,0,8,2,36,23,0,98,20, - 6,8,2,36,21,0,0,17,0,0,0,0, - 32,0,194,148,30,0,195,148,0,20,2,0, - 37,56,67,0,36,0,195,148,0,161,2,52, - 5,0,98,16,8,0,2,36,34,0,195,148, - 0,0,0,0,98,0,98,20,0,0,0,0, - 3,0,232,16,255,255,2,36,94,0,226,20, - 0,0,0,0,226,46,192,12,14,0,6,36, - 177,16,192,8,0,0,0,0,7,0,98,20, - 255,255,227,48,71,0,0,17,55,129,2,52, - 108,43,192,12,14,0,6,36,177,16,192,8, - 0,0,0,0,162,16,192,8,55,129,2,52, - 14,0,195,148,0,0,0,0,61,0,98,20, - 255,255,2,52,16,0,195,144,3,0,2,36, - 55,0,98,20,255,255,2,52,20,0,194,148, - 0,0,0,0,0,26,2,0,2,18,2,0, - 37,56,98,0,255,255,227,48,0,8,2,36, - 23,0,98,20,6,8,2,36,21,0,0,17, - 0,0,0,0,40,0,194,148,38,0,195,148, - 0,20,2,0,37,56,67,0,44,0,195,148, - 0,161,2,52,5,0,98,16,8,0,2,36, - 42,0,195,148,0,0,0,0,49,0,98,20, - 0,0,0,0,3,0,232,16,255,255,2,36, - 45,0,226,20,0,0,0,0,226,46,192,12, - 22,0,6,36,177,16,192,8,0,0,0,0, - 7,0,98,20,255,255,227,48,6,0,0,17, - 55,129,2,52,108,43,192,12,22,0,6,36, - 177,16,192,8,0,0,0,0,55,129,2,52, - 30,0,98,20,0,0,0,0,28,0,32,17, - 144,15,3,36,38,0,194,148,28,0,198,140, - 24,0,67,20,0,0,0,0,3,0,201,16, - 0,0,0,0,20,0,192,20,0,0,0,0, - 175,16,192,8,22,0,6,36,14,0,195,148, - 0,0,0,0,14,0,98,20,0,0,0,0, - 12,0,32,17,144,15,3,36,30,0,194,148, - 20,0,198,140,8,0,67,20,0,0,0,0, - 3,0,201,16,0,0,0,0,4,0,192,20, - 0,0,0,0,14,0,6,36,126,49,192,12, - 0,0,0,0,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,128,255,189,39, - 116,0,183,175,33,184,128,0,3,0,3,36, - 124,0,191,175,120,0,190,175,112,0,182,175, - 108,0,181,175,104,0,180,175,100,0,179,175, - 96,0,178,175,92,0,177,175,88,0,176,175, - 0,0,245,142,8,0,178,140,192,17,21,0, - 3,131,4,60,33,32,130,0,20,13,132,140, - 8,0,84,142,0,0,0,0,59,0,131,16, - 5,0,130,44,57,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,104,131,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 44,133,130,143,0,0,0,0,48,0,64,16, - 6,0,132,38,4,0,131,150,2,131,2,60, - 68,207,66,148,0,0,0,0,6,0,98,20, - 33,32,0,0,0,0,130,142,48,129,131,143, - 0,0,0,0,38,16,67,0,1,0,68,44, - 72,1,128,16,33,32,160,2,114,42,192,12, - 33,40,128,2,45,18,192,8,33,32,64,2, - 44,133,130,143,0,0,0,0,27,0,64,16, - 6,0,132,38,4,0,131,150,2,131,2,60, - 68,207,66,148,0,0,0,0,6,0,98,20, - 33,32,0,0,0,0,130,142,48,129,131,143, - 0,0,0,0,38,16,67,0,1,0,68,44, - 5,0,128,16,33,32,160,2,114,42,192,12, - 33,40,128,2,45,18,192,8,33,32,64,2, - 6,0,132,38,0,163,6,60,140,1,198,140, - 0,0,0,0,247,24,192,12,33,40,160,2, - 45,18,192,8,33,32,64,2,6,0,132,38, - 0,163,6,60,140,1,198,140,0,0,0,0, - 247,24,192,12,33,40,160,2,203,24,192,12, - 33,32,128,2,20,1,227,142,0,0,0,0, - 14,0,96,16,33,240,64,0,33,32,128,2, - 16,0,166,39,18,0,69,150,0,0,0,0, - 9,248,96,0,33,56,192,3,6,0,64,16, - 33,32,64,2,28,1,226,142,0,0,0,0, - 1,0,66,36,45,18,192,8,28,1,226,174, - 132,0,193,7,7,0,2,36,4,0,131,150, - 2,131,2,60,68,207,66,148,0,0,0,0, - 6,0,98,20,33,32,0,0,0,0,130,142, - 48,129,131,143,0,0,0,0,38,16,67,0, - 1,0,68,44,9,0,128,16,255,255,2,36, - 44,133,130,143,0,0,0,0,251,0,64,16, - 33,32,160,2,114,42,192,12,33,40,128,2, - 45,18,192,8,33,32,64,2,10,0,194,23, - 0,0,0,0,8,0,160,18,0,0,0,0, - 36,133,130,143,0,0,0,0,8,0,64,16, - 1,0,19,36,80,133,147,143,69,17,192,8, - 0,0,0,0,0,1,226,142,80,133,147,143, - 1,0,66,36,0,1,226,174,84,133,130,143, - 0,0,0,0,35,16,83,0,255,255,66,36, - 17,0,66,162,84,133,130,143,33,128,96,2, - 42,16,2,2,15,0,64,16,64,18,16,0, - 2,131,3,60,192,246,99,36,33,136,67,0, - 5,0,21,18,0,0,0,0,247,22,192,12, - 33,32,32,2,217,0,64,16,33,16,0,0, - 84,133,130,143,1,0,16,38,42,16,2,2, - 246,255,64,20,0,2,49,38,84,133,130,143, - 33,128,96,2,42,16,2,2,55,0,64,16, - 64,18,16,0,2,131,3,60,192,246,99,36, - 33,152,67,0,33,136,64,0,192,177,16,0, - 41,0,21,18,0,0,0,0,2,131,2,60, - 33,16,81,0,216,247,66,140,0,0,0,0, - 15,0,64,16,33,32,128,2,16,0,166,39, - 18,0,69,150,0,0,0,0,9,248,64,0, - 33,56,160,2,8,0,64,16,0,0,0,0, - 2,131,2,60,33,16,81,0,224,247,66,140, - 0,0,0,0,1,0,66,36,140,17,192,8, - 32,1,98,174,44,133,130,143,0,0,0,0, - 7,0,64,16,3,0,8,36,3,131,2,60, - 33,16,86,0,20,13,66,140,0,0,0,0, - 6,0,72,20,0,0,0,0,33,32,96,2, - 6,23,192,12,33,40,64,2,146,17,192,8, - 0,2,115,38,17,0,66,146,0,0,0,0, - 255,255,66,36,17,0,66,162,17,0,66,146, - 0,2,115,38,0,2,49,38,84,133,130,143, - 1,0,16,38,42,16,2,2,208,255,64,20, - 128,0,214,38,254,255,2,36,4,0,194,23, - 33,32,224,2,33,40,64,2,47,16,192,12, - 33,48,128,2,17,0,66,146,0,0,0,0, - 140,0,64,16,33,32,64,2,36,18,192,8, - 0,0,0,0,26,0,194,23,0,0,0,0, - 36,133,130,143,0,0,0,0,11,0,64,16, - 33,32,224,2,9,0,160,18,1,0,2,36, - 17,0,66,162,2,131,4,60,192,246,132,36, - 6,23,192,12,33,40,64,2,126,0,64,16, - 33,16,0,0,33,32,224,2,33,40,64,2, - 47,16,192,12,33,48,128,2,36,133,130,143, - 0,0,0,0,115,0,64,16,33,32,64,2, - 116,0,160,22,1,0,2,36,45,18,192,8, - 0,0,0,0,87,0,213,19,64,130,30,0, - 2,131,2,60,33,16,80,0,216,247,66,140, - 0,0,0,0,18,0,64,16,33,32,128,2, - 16,0,166,39,18,0,69,150,0,0,0,0, - 9,248,64,0,33,56,160,2,11,0,64,16, - 33,32,64,2,2,131,2,60,33,16,80,0, - 224,247,66,140,0,0,0,0,1,0,66,36, - 2,131,1,60,33,8,48,0,224,247,34,172, - 45,18,192,8,17,0,128,160,36,133,130,143, - 0,0,0,0,43,0,64,16,0,0,0,0, - 41,0,192,19,0,0,0,0,39,0,160,18, - 64,18,30,0,2,131,16,60,192,246,16,38, - 33,136,80,0,247,22,192,12,33,32,32,2, - 74,0,64,16,33,16,0,0,247,22,192,12, - 33,32,0,2,63,0,64,16,2,0,2,36, - 17,0,66,162,44,133,130,143,0,0,0,0, - 7,0,64,16,192,17,30,0,3,131,3,60, - 33,24,98,0,20,13,99,140,3,0,2,36, - 6,0,98,20,0,0,0,0,33,32,32,2, - 6,23,192,12,33,40,64,2,0,18,192,8, - 0,0,0,0,17,0,66,146,0,0,0,0, - 255,255,66,36,17,0,66,162,17,0,66,146, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,64,2,36,18,192,8,0,0,0,0, - 44,133,130,143,0,0,0,0,7,0,64,16, - 192,17,30,0,3,131,3,60,33,24,98,0, - 20,13,99,140,3,0,2,36,28,0,98,20, - 0,0,0,0,1,0,2,36,17,0,66,162, - 64,18,30,0,2,131,4,60,192,246,132,36, - 32,18,192,8,33,32,68,0,36,133,130,143, - 0,0,0,0,17,0,64,16,0,0,0,0, - 15,0,192,19,1,0,2,36,17,0,66,162, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,64,2,13,0,64,16,33,16,0,0, - 252,0,226,142,0,0,0,0,1,0,66,36, - 47,18,192,8,252,0,226,174,48,18,192,8, - 33,16,0,0,17,0,64,162,33,32,64,2, - 152,21,192,12,0,0,0,0,1,0,2,36, - 124,0,191,143,120,0,190,143,116,0,183,143, - 112,0,182,143,108,0,181,143,104,0,180,143, - 100,0,179,143,96,0,178,143,92,0,177,143, - 88,0,176,143,8,0,224,3,128,0,189,39, - 216,255,189,39,24,0,178,175,33,144,128,0, - 32,0,191,175,28,0,179,175,20,0,177,175, - 16,0,176,175,8,0,177,140,0,0,66,142, - 8,0,38,142,36,0,64,16,0,0,0,0, - 28,0,66,142,0,0,0,0,18,0,64,20, - 1,0,2,36,0,0,194,144,0,0,0,0, - 1,0,66,48,13,0,64,20,1,0,2,36, - 4,0,195,148,24,0,66,150,0,0,0,0, - 6,0,98,20,33,32,0,0,0,0,194,140, - 20,0,67,142,0,0,0,0,38,16,67,0, - 1,0,68,44,10,0,128,16,1,0,2,36, - 17,0,34,162,2,131,4,60,192,246,132,36, - 6,23,192,12,33,40,32,2,45,0,64,16, - 33,16,0,0,139,18,192,8,0,0,0,0, - 17,0,32,162,152,21,192,12,33,32,32,2, - 144,18,192,8,1,0,2,36,16,0,179,140, - 0,0,0,0,6,0,96,26,0,0,0,0, - 32,133,130,143,0,0,0,0,42,16,98,2, - 15,0,64,20,1,0,2,36,2,131,4,60, - 248,130,132,36,2,131,16,60,24,131,16,38, - 33,40,0,2,2,131,7,60,36,131,231,36, - 15,63,192,12,188,2,6,36,1,0,4,36, - 33,40,0,2,188,7,192,12,188,2,6,36, - 1,0,2,36,17,0,34,162,64,18,19,0, - 2,131,4,60,192,246,132,36,33,32,68,0, - 6,23,192,12,33,40,32,2,6,0,64,16, - 33,16,0,0,252,0,66,142,0,0,0,0, - 1,0,66,36,252,0,66,174,1,0,2,36, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,72,255,189,39,164,0,181,175, - 33,168,128,0,180,0,191,175,176,0,190,175, - 172,0,183,175,168,0,182,175,160,0,180,175, - 156,0,179,175,152,0,178,175,148,0,177,175, - 144,0,176,175,88,0,165,175,120,0,160,175, - 120,0,168,142,0,0,0,0,96,0,168,175, - 124,0,169,142,0,0,0,0,15,2,160,24, - 104,0,169,175,96,0,168,143,0,0,0,0, - 0,0,4,149,0,0,0,0,0,128,130,48, - 9,2,64,16,0,0,0,0,128,0,160,175, - 8,0,2,141,136,0,169,142,255,255,8,36, - 18,0,72,16,112,0,169,175,112,0,169,143, - 0,0,0,0,0,0,35,141,4,0,40,141, - 128,0,169,143,255,63,98,48,33,72,34,1, - 0,128,99,48,112,0,168,175,246,255,96,16, - 128,0,169,175,96,0,168,143,0,0,0,0, - 8,0,2,141,128,0,169,151,0,0,0,0, - 18,0,73,164,0,32,130,48,200,1,64,16, - 0,0,0,0,40,133,130,143,0,0,0,0, - 75,0,64,16,3,0,8,36,96,0,168,143, - 0,0,0,0,8,0,16,141,0,0,162,142, - 8,0,5,142,30,0,64,16,0,0,0,0, - 28,0,162,142,0,0,0,0,18,0,64,20, - 1,0,9,36,0,0,162,144,0,0,0,0, - 1,0,66,48,13,0,64,20,0,0,0,0, - 4,0,163,148,24,0,162,150,0,0,0,0, - 6,0,98,20,33,32,0,0,0,0,162,140, - 20,0,163,142,0,0,0,0,38,16,67,0, - 1,0,68,44,6,0,128,16,1,0,9,36, - 17,0,9,162,2,131,4,60,192,246,132,36, - 18,19,192,8,33,40,0,2,17,0,0,162, - 130,20,192,8,33,32,0,2,16,0,17,141, - 0,0,0,0,6,0,32,26,0,0,0,0, - 32,133,130,143,0,0,0,0,42,16,34,2, - 15,0,64,20,1,0,9,36,2,131,4,60, - 248,130,132,36,2,131,5,60,24,131,165,36, - 2,131,7,60,36,131,231,36,15,63,192,12, - 188,2,6,36,1,0,4,36,2,131,5,60, - 24,131,165,36,188,7,192,12,188,2,6,36, - 1,0,9,36,17,0,9,162,64,34,17,0, - 2,131,8,60,192,246,8,37,33,32,136,0, - 33,40,0,2,6,23,192,12,0,0,0,0, - 112,1,64,16,33,16,0,0,252,0,162,142, - 0,0,0,0,1,0,66,36,132,20,192,8, - 252,0,162,174,0,0,182,142,96,0,169,143, - 192,17,22,0,8,0,50,141,3,131,3,60, - 33,24,98,0,20,13,99,140,8,0,84,142, - 0,0,0,0,59,0,104,16,5,0,98,44, - 57,0,64,16,128,16,3,0,2,131,1,60, - 33,8,34,0,128,131,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,44,133,130,143, - 0,0,0,0,48,0,64,16,6,0,132,38, - 4,0,131,150,2,131,2,60,68,207,66,148, - 0,0,0,0,6,0,98,20,33,32,0,0, - 0,0,130,142,48,129,131,143,0,0,0,0, - 38,16,67,0,1,0,68,44,67,1,128,16, - 33,32,192,2,114,42,192,12,33,40,128,2, - 130,20,192,8,33,32,64,2,44,133,130,143, - 0,0,0,0,27,0,64,16,6,0,132,38, - 4,0,131,150,2,131,2,60,68,207,66,148, - 0,0,0,0,6,0,98,20,33,32,0,0, - 0,0,130,142,48,129,131,143,0,0,0,0, - 38,16,67,0,1,0,68,44,5,0,128,16, - 33,32,192,2,114,42,192,12,33,40,128,2, - 130,20,192,8,33,32,64,2,6,0,132,38, - 0,163,6,60,140,1,198,140,0,0,0,0, - 247,24,192,12,33,40,192,2,130,20,192,8, - 33,32,64,2,6,0,132,38,0,163,6,60, - 140,1,198,140,0,0,0,0,247,24,192,12, - 33,40,192,2,203,24,192,12,33,32,128,2, - 20,1,163,142,0,0,0,0,14,0,96,16, - 33,240,64,0,33,32,128,2,16,0,166,39, - 18,0,69,150,0,0,0,0,9,248,96,0, - 33,56,192,3,6,0,64,16,33,32,64,2, - 28,1,162,142,0,0,0,0,1,0,66,36, - 130,20,192,8,28,1,162,174,132,0,193,7, - 7,0,2,36,4,0,131,150,2,131,2,60, - 68,207,66,148,0,0,0,0,6,0,98,20, - 33,32,0,0,0,0,130,142,48,129,131,143, - 0,0,0,0,38,16,67,0,1,0,68,44, - 9,0,128,16,255,255,9,36,44,133,130,143, - 0,0,0,0,246,0,64,16,33,32,192,2, - 114,42,192,12,33,40,128,2,130,20,192,8, - 33,32,64,2,10,0,201,23,0,0,0,0, - 8,0,192,18,0,0,0,0,36,133,130,143, - 0,0,0,0,8,0,64,16,1,0,19,36, - 80,133,147,143,159,19,192,8,0,0,0,0, - 0,1,162,142,80,133,147,143,1,0,66,36, - 0,1,162,174,84,133,130,143,0,0,0,0, - 35,16,83,0,255,255,66,36,17,0,66,162, - 84,133,130,143,33,136,96,2,42,16,34,2, - 15,0,64,16,64,18,17,0,2,131,8,60, - 192,246,8,37,33,128,72,0,5,0,54,18, - 0,0,0,0,247,22,192,12,33,32,0,2, - 212,0,64,16,33,16,0,0,84,133,130,143, - 1,0,49,38,42,16,34,2,246,255,64,20, - 0,2,16,38,84,133,130,143,33,136,96,2, - 42,16,34,2,55,0,64,16,64,18,17,0, - 2,131,9,60,192,246,41,37,33,152,73,0, - 33,128,64,0,192,185,17,0,41,0,54,18, - 0,0,0,0,2,131,2,60,33,16,80,0, - 216,247,66,140,0,0,0,0,15,0,64,16, - 33,32,128,2,16,0,166,39,18,0,69,150, - 0,0,0,0,9,248,64,0,33,56,192,2, - 8,0,64,16,0,0,0,0,2,131,2,60, - 33,16,80,0,224,247,66,140,0,0,0,0, - 1,0,66,36,230,19,192,8,32,1,98,174, - 44,133,130,143,0,0,0,0,7,0,64,16, - 3,0,8,36,3,131,2,60,33,16,87,0, - 20,13,66,140,0,0,0,0,6,0,72,20, - 0,0,0,0,33,32,96,2,6,23,192,12, - 33,40,64,2,236,19,192,8,0,2,115,38, - 17,0,66,146,0,0,0,0,255,255,66,36, - 17,0,66,162,17,0,66,146,0,2,115,38, - 0,2,16,38,84,133,130,143,1,0,49,38, - 42,16,34,2,208,255,64,20,128,0,247,38, - 254,255,2,36,4,0,194,23,33,32,160,2, - 33,40,64,2,47,16,192,12,33,48,128,2, - 17,0,66,146,0,0,0,0,135,0,64,16, - 33,32,64,2,22,19,192,8,0,0,0,0, - 26,0,194,23,0,0,0,0,36,133,130,143, - 0,0,0,0,11,0,64,16,33,32,160,2, - 9,0,192,18,1,0,9,36,17,0,73,162, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,64,2,121,0,64,16,33,16,0,0, - 33,32,160,2,33,40,64,2,47,16,192,12, - 33,48,128,2,36,133,130,143,0,0,0,0, - 110,0,64,16,33,32,64,2,111,0,192,22, - 1,0,2,36,130,20,192,8,0,0,0,0, - 89,0,214,19,64,130,30,0,2,131,2,60, - 33,16,80,0,216,247,66,140,0,0,0,0, - 18,0,64,16,33,32,128,2,16,0,166,39, - 18,0,69,150,0,0,0,0,9,248,64,0, - 33,56,192,2,11,0,64,16,33,32,64,2, - 2,131,8,60,192,246,8,37,2,131,2,60, - 33,16,80,0,224,247,66,140,33,24,8,2, - 1,0,66,36,32,1,98,172,130,20,192,8, - 17,0,128,160,36,133,130,143,0,0,0,0, - 44,0,64,16,0,0,0,0,42,0,192,19, - 0,0,0,0,40,0,192,18,64,18,30,0, - 2,131,9,60,192,246,41,37,33,128,73,0, - 247,22,192,12,33,32,0,2,69,0,64,16, - 33,16,0,0,2,131,4,60,247,22,192,12, - 192,246,132,36,57,0,64,16,2,0,2,36, - 17,0,66,162,44,133,130,143,0,0,0,0, - 7,0,64,16,192,17,30,0,3,131,1,60, - 33,8,34,0,20,13,34,140,3,0,8,36, - 6,0,72,20,0,0,0,0,33,32,0,2, - 6,23,192,12,33,40,64,2,91,20,192,8, - 0,0,0,0,17,0,66,146,0,0,0,0, - 255,255,66,36,17,0,66,162,17,0,66,146, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,64,2,22,19,192,8,0,0,0,0, - 44,133,130,143,0,0,0,0,7,0,64,16, - 192,17,30,0,3,131,1,60,33,8,34,0, - 20,13,34,140,3,0,9,36,22,0,73,20, - 0,0,0,0,1,0,8,36,17,0,72,162, - 64,34,30,0,2,131,9,60,192,246,41,37, - 33,32,137,0,18,19,192,8,33,40,64,2, - 36,133,130,143,0,0,0,0,10,0,64,16, - 0,0,0,0,8,0,192,19,1,0,8,36, - 17,0,72,162,2,131,4,60,192,246,132,36, - 18,19,192,8,33,40,64,2,133,20,192,8, - 33,16,0,0,17,0,64,162,33,32,64,2, - 152,21,192,12,0,0,0,0,1,0,2,36, - 52,0,64,16,0,0,0,0,152,0,162,142, - 0,0,0,0,1,0,66,36,152,0,162,174, - 156,0,162,142,168,0,163,142,1,0,66,36, - 156,0,162,174,128,0,169,143,0,0,0,0, - 33,24,105,0,163,20,192,8,168,0,163,174, - 152,0,162,142,160,0,163,142,1,0,66,36, - 1,0,99,36,152,0,162,174,160,0,163,174, - 96,0,168,143,0,0,0,0,8,0,2,141, - 255,255,9,36,4,0,73,16,0,0,0,0, - 8,0,4,141,152,21,192,12,0,0,0,0, - 120,0,168,143,112,0,169,143,1,0,8,37, - 120,0,168,175,136,0,169,174,96,0,168,143, - 8,128,2,52,0,0,0,165,2,0,2,165, - 104,0,169,143,8,0,2,36,2,0,34,165, - 4,0,40,141,96,0,169,143,104,0,168,175, - 4,0,41,141,120,0,168,143,96,0,169,175, - 88,0,169,143,0,0,0,0,42,16,9,1, - 243,253,64,20,0,0,0,0,96,0,168,143, - 44,0,163,142,120,0,168,174,104,0,169,143, - 0,0,0,0,124,0,169,174,0,0,98,148, - 0,0,0,0,0,16,66,48,43,0,64,16, - 0,0,0,0,2,0,98,148,0,0,0,0, - 39,0,64,20,0,0,0,0,0,0,2,149, - 0,0,0,0,35,0,64,20,0,0,0,0, - 2,0,2,149,8,0,3,36,255,255,66,48, - 30,0,67,20,0,0,0,0,136,0,162,142, - 0,0,0,0,12,0,66,140,0,0,0,0, - 0,128,66,48,23,0,64,20,0,0,0,0, - 164,0,162,142,44,0,163,142,1,0,66,36, - 164,0,162,174,8,0,104,172,136,0,162,142, - 0,0,0,0,8,0,2,173,44,0,163,142, - 16,16,2,36,2,0,98,164,0,0,162,142, - 0,0,0,0,5,0,64,20,0,0,0,0, - 164,7,192,12,0,0,0,0,239,20,192,8, - 0,0,0,0,8,0,162,142,0,0,0,0, - 0,0,64,172,180,0,191,143,176,0,190,143, - 172,0,183,143,168,0,182,143,164,0,181,143, - 160,0,180,143,156,0,179,143,152,0,178,143, - 148,0,177,143,144,0,176,143,8,0,224,3, - 184,0,189,39,216,255,189,39,28,0,177,175, - 33,136,128,0,32,0,178,175,33,144,160,0, - 96,128,132,39,6,0,37,38,24,0,176,175, - 104,128,144,39,36,0,191,175,31,21,192,12, - 33,48,0,2,108,128,132,39,33,40,32,2, - 31,21,192,12,33,48,0,2,10,0,64,26, - 33,128,0,0,116,128,132,39,33,16,17,2, - 12,0,69,144,0,0,0,0,15,63,192,12, - 1,0,16,38,42,16,18,2,248,255,64,20, - 0,0,0,0,124,128,132,39,15,63,192,12, - 0,0,0,0,36,0,191,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,208,255,189,39,40,0,191,175, - 2,0,162,144,0,0,163,144,1,0,167,144, - 16,0,162,175,3,0,162,144,33,64,128,0, - 20,0,162,175,4,0,162,144,2,131,4,60, - 68,131,132,36,24,0,162,175,5,0,162,144, - 33,40,0,1,32,0,166,175,33,48,96,0, - 15,63,192,12,28,0,162,175,40,0,191,143, - 48,0,189,39,8,0,224,3,0,0,0,0, - 248,255,189,39,136,0,135,140,255,255,163,36, - 12,0,160,16,33,48,224,0,255,255,5,36, - 12,0,194,140,0,0,0,0,0,128,66,48, - 8,0,64,20,33,16,0,0,255,255,99,36, - 0,0,192,172,4,0,198,140,247,255,101,20, - 0,0,0,0,136,0,134,172,33,16,224,0, - 8,0,224,3,8,0,189,39,224,255,189,39, - 16,0,176,175,33,128,160,0,28,0,191,175, - 24,0,178,175,33,0,128,20,20,0,177,175, - 84,133,130,143,80,133,131,143,0,0,0,0, - 35,16,67,0,17,0,2,162,80,133,145,143, - 84,133,130,143,0,0,0,0,42,16,34,2, - 19,0,64,16,64,18,17,0,2,131,3,60, - 192,246,99,36,33,144,67,0,33,32,64,2, - 6,23,192,12,33,40,0,2,6,0,64,20, - 0,0,0,0,17,0,2,146,0,0,0,0, - 255,255,66,36,17,0,2,162,17,0,2,146, - 84,133,130,143,1,0,49,38,42,16,34,2, - 242,255,64,20,0,2,82,38,17,0,2,146, - 144,21,192,8,0,0,0,0,36,133,130,143, - 0,0,0,0,25,0,64,16,1,0,2,36, - 0,0,130,140,0,0,0,0,20,0,64,16, - 2,0,2,36,17,0,2,162,6,23,192,12, - 33,40,0,2,19,0,64,16,33,16,0,0, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,0,2,7,0,64,20,0,0,0,0, - 17,0,2,146,0,0,0,0,255,255,66,36, - 17,0,2,162,17,0,2,146,0,0,0,0, - 144,21,192,8,1,0,2,36,1,0,2,36, - 17,0,2,162,6,23,192,12,33,40,0,2, - 28,0,191,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 0,0,0,0,0,0,0,0,0,129,9,52, - 16,0,130,144,2,131,3,60,192,246,99,36, - 64,18,2,0,33,56,67,0,140,0,230,140, - 0,1,8,36,4,0,197,140,0,0,131,140, - 0,0,128,172,12,0,137,172,4,0,164,172, - 12,0,200,172,33,48,160,0,216,0,226,140, - 33,40,128,0,1,0,66,36,0,128,99,48, - 4,0,96,20,216,0,226,172,4,0,132,140, - 161,21,192,8,0,0,0,0,8,0,224,3, - 140,0,230,172,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,8,0,224,3,0,0,0,0, - 172,0,128,172,176,0,128,172,180,0,128,172, - 184,0,128,172,188,0,128,172,192,0,128,172, - 196,0,128,172,200,0,128,172,204,0,128,172, - 208,0,128,172,212,0,128,172,224,0,128,172, - 8,1,128,172,4,1,128,172,236,0,128,172, - 240,0,128,172,232,0,128,172,244,0,128,172, - 8,0,224,3,248,0,128,172,224,255,189,39, - 16,0,176,175,33,128,128,0,20,0,177,175, - 0,2,17,36,24,0,191,175,13,8,192,12, - 0,48,4,36,255,31,3,60,255,255,99,52, - 33,32,0,0,36,16,67,0,0,128,3,60, - 37,40,67,0,33,24,160,0,0,128,6,52, - 1,0,132,36,24,0,98,36,0,0,96,164, - 2,0,102,164,4,0,98,172,33,24,64,0, - 42,16,145,0,249,255,64,20,1,0,132,36, - 255,255,132,36,64,16,17,0,33,16,81,0, - 192,16,2,0,33,16,69,0,48,0,163,36, - 236,255,69,172,108,0,3,174,104,0,3,174, - 96,0,5,174,100,0,2,174,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,248,255,189,39,0,32,14,60, - 4,0,177,175,7,0,17,60,0,0,176,175, - 4,0,16,60,2,131,25,60,192,246,57,39, - 0,1,15,36,108,0,152,140,104,0,137,140, - 176,0,140,140,180,0,141,140,94,0,56,17, - 0,0,0,0,4,0,43,141,0,0,0,0, - 37,16,110,1,0,0,66,148,0,0,0,0, - 0,128,66,48,86,0,64,16,37,16,46,1, - 0,0,67,140,0,0,0,0,36,16,113,0, - 76,0,80,20,0,32,98,48,41,0,64,20, - 15,0,98,48,188,0,130,140,0,0,0,0, - 1,0,66,36,188,0,130,172,0,8,98,48, - 6,0,64,16,0,4,98,48,192,0,130,140, - 0,0,0,0,1,0,66,36,192,0,130,172, - 0,4,98,48,6,0,64,16,0,2,98,48, - 196,0,130,140,0,0,0,0,1,0,66,36, - 196,0,130,172,0,2,98,48,6,0,64,16, - 0,1,98,48,200,0,130,140,0,0,0,0, - 1,0,66,36,200,0,130,172,0,1,98,48, - 6,0,64,16,32,0,98,48,204,0,130,140, - 0,0,0,0,1,0,66,36,204,0,130,172, - 32,0,98,48,6,0,64,16,15,0,98,48, - 208,0,130,140,0,0,0,0,1,0,66,36, - 208,0,130,172,15,0,98,48,212,0,131,140, - 8,0,37,141,33,24,98,0,212,0,131,172, - 17,0,162,144,1,0,140,37,255,255,66,36, - 17,0,162,160,25,0,64,20,37,24,46,1, - 16,0,162,144,1,0,173,37,64,18,2,0, - 33,64,89,0,140,0,7,141,0,129,10,52, - 4,0,230,140,0,0,163,140,0,0,160,172, - 12,0,170,172,4,0,197,172,12,0,239,172, - 33,56,192,0,216,0,2,141,33,48,160,0, - 1,0,66,36,0,128,99,48,4,0,96,20, - 216,0,2,173,4,0,165,140,114,22,192,8, - 0,0,0,0,140,0,7,173,37,24,46,1, - 0,128,2,60,0,0,98,172,40,22,192,8, - 33,72,96,1,104,0,137,172,176,0,140,172, - 180,0,141,172,4,0,177,143,0,0,176,143, - 8,0,224,3,8,0,189,39,224,255,189,39, - 16,0,176,175,33,128,128,0,24,0,191,175, - 20,0,177,175,44,0,17,142,0,0,0,0, - 0,0,34,150,0,0,0,0,0,32,66,48, - 89,0,64,16,0,0,0,0,2,0,34,150, - 0,0,0,0,0,1,66,48,84,0,64,20, - 0,0,0,0,27,22,192,12,0,0,0,0, - 104,0,4,142,0,0,0,0,2,0,130,148, - 0,128,3,52,255,255,66,48,75,0,67,16, - 0,0,0,0,224,0,2,142,0,0,0,0, - 1,0,66,36,224,0,2,174,4,0,36,174, - 0,0,128,164,4,0,130,140,0,0,0,0, - 0,0,64,164,0,0,2,142,0,0,0,0, - 51,0,64,16,0,33,2,36,2,0,34,150, - 0,0,0,0,47,0,64,16,0,33,2,36, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 2,0,34,150,0,0,0,0,211,255,64,20, - 0,33,2,36,2,0,34,166,0,0,2,142, - 0,0,0,0,5,0,64,16,0,0,0,0, - 8,0,2,142,0,0,0,0,242,22,192,8, - 0,0,64,172,164,7,192,12,0,0,0,0, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,108,0,133,140, - 0,0,0,0,4,0,162,140,0,0,0,0, - 4,0,67,140,104,0,130,140,0,0,0,0, - 5,0,98,20,33,16,160,0,184,0,131,140, - 33,16,0,0,1,0,99,36,184,0,131,172, - 8,0,224,3,0,0,0,0,224,255,189,39, - 16,0,176,175,33,128,128,0,28,0,191,175, - 24,0,178,175,20,0,177,175,108,0,18,142, - 8,1,6,142,44,0,17,142,4,0,66,142, - 104,0,7,142,4,0,66,140,18,0,163,148, - 172,0,4,142,0,0,0,0,6,0,71,20, - 255,255,99,48,184,0,3,142,33,16,0,0, - 1,0,99,36,157,23,192,8,184,0,3,174, - 33,48,195,0,1,0,130,36,172,0,2,174, - 8,1,6,174,8,0,162,140,4,1,3,142, - 0,0,70,144,33,32,64,2,8,0,69,174, - 12,0,64,174,1,0,194,48,2,0,64,16, - 1,0,98,36,4,1,2,174,0,0,2,142, - 0,0,0,0,35,0,64,20,0,0,0,0, - 18,0,162,148,0,0,0,0,255,255,66,48, - 12,0,66,174,0,0,34,150,0,0,0,0, - 0,32,66,48,24,0,64,16,12,0,2,36, - 2,0,34,150,0,0,0,0,0,1,66,48, - 19,0,64,20,12,0,2,36,4,0,242,16, - 0,0,0,0,27,22,192,12,33,32,0,2, - 12,0,2,36,2,0,66,166,104,0,4,142, - 0,0,0,0,0,0,128,164,4,0,130,140, - 0,0,0,0,0,0,64,164,0,33,2,36, - 4,0,36,174,164,7,192,12,2,0,34,166, - 154,23,192,8,0,0,0,0,154,23,192,8, - 2,0,130,164,0,0,34,150,0,0,0,0, - 0,32,66,48,69,0,64,16,12,0,2,36, - 4,0,242,16,0,0,0,0,27,22,192,12, - 33,32,0,2,12,0,2,36,2,0,66,166, - 104,0,4,142,0,0,0,0,0,0,128,164, - 4,0,130,140,0,0,0,0,0,0,64,164, - 4,0,36,174,2,0,34,150,0,0,0,0, - 47,0,64,16,0,33,2,36,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,2,0,34,150, - 0,0,0,0,211,255,64,20,0,33,2,36, - 2,0,34,166,8,0,2,142,0,0,0,0, - 154,23,192,8,0,0,64,172,2,0,66,166, - 4,0,67,142,1,0,2,36,108,0,3,174, - 28,0,191,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 216,255,189,39,20,0,177,175,33,136,128,0, - 24,0,178,175,2,131,18,60,192,131,82,38, - 28,0,179,175,0,1,19,36,32,0,191,175, - 16,0,176,175,104,0,48,142,108,0,34,142, - 0,0,0,0,4,0,2,22,0,0,0,0, - 2,0,2,150,245,23,192,8,0,0,0,0, - 2,0,2,150,0,0,0,0,7,0,66,48, - 11,0,64,20,33,40,64,2,2,131,4,60, - 160,131,132,36,2,131,7,60,252,131,231,36, - 15,63,192,12,0,2,6,36,1,0,4,36, - 33,40,64,2,188,7,192,12,0,2,6,36, - 2,0,2,150,4,0,3,36,7,0,66,48, - 40,0,67,20,0,128,2,52,8,0,3,142, - 0,0,0,0,17,0,98,144,0,0,0,0, - 255,255,66,36,17,0,98,160,17,0,98,144, - 0,0,0,0,30,0,64,20,0,128,2,52, - 180,0,34,142,33,32,96,0,1,0,66,36, - 180,0,34,174,16,0,130,144,2,131,3,60, - 192,246,99,36,64,18,2,0,33,56,67,0, - 140,0,230,140,0,129,8,52,4,0,197,140, - 0,0,131,140,0,0,128,172,12,0,136,172, - 4,0,164,172,12,0,211,172,33,48,160,0, - 216,0,226,140,33,40,128,0,1,0,66,36, - 0,128,99,48,4,0,96,20,216,0,226,172, - 4,0,132,140,223,23,192,8,0,0,0,0, - 140,0,230,172,0,128,2,52,2,0,2,166, - 0,0,0,166,4,0,16,142,174,23,192,8, - 0,0,0,0,44,0,35,142,104,0,48,174, - 0,0,98,148,0,0,0,0,0,32,66,52, - 0,0,98,164,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,0,163,2,60, - 0,1,66,52,0,0,66,140,2,131,3,60, - 192,6,99,36,255,3,66,48,60,0,66,36, - 0,128,66,52,8,0,224,3,0,0,98,172, - 208,255,189,39,28,0,177,175,33,136,128,0, - 32,0,178,175,33,144,160,0,24,0,176,175, - 0,163,16,60,0,163,2,60,164,1,66,140, - 0,1,16,54,44,0,191,175,40,0,180,175, - 4,0,64,20,36,0,179,175,60,0,2,36, - 0,163,1,60,164,1,34,172,0,163,2,60, - 164,1,66,140,0,0,0,0,221,5,66,40, - 3,0,64,20,220,5,2,36,0,163,1,60, - 164,1,34,172,0,163,3,60,164,1,99,140, - 255,255,2,36,21,0,98,20,0,0,0,0, - 128,128,130,143,0,0,0,0,5,0,67,20, - 2,0,5,36,130,11,192,12,0,0,0,0, - 128,128,130,175,2,0,5,36,10,0,6,36, - 128,128,132,143,0,131,7,60,8,96,231,36, - 156,11,192,12,16,0,160,175,0,0,2,142, - 2,131,3,60,192,6,99,36,255,3,66,48, - 66,24,192,8,64,0,66,36,0,163,2,60, - 164,1,66,140,2,131,3,60,192,6,99,36, - 0,128,66,52,0,0,98,172,255,31,4,60, - 255,255,132,52,2,131,2,60,208,6,66,36, - 36,16,68,0,0,160,5,60,37,16,69,0, - 2,131,3,60,176,12,99,36,2,131,1,60, - 196,6,32,172,2,131,1,60,200,6,34,172, - 12,0,2,36,0,0,96,164,2,131,1,60, - 178,12,34,164,6,0,65,6,36,16,100,0, - 37,16,69,0,2,131,1,60,180,12,34,172, - 99,24,192,8,255,31,18,60,2,131,2,60, - 178,12,66,148,0,0,0,0,0,128,66,52, - 2,131,1,60,178,12,34,164,255,31,18,60, - 255,255,82,54,2,131,2,60,192,6,66,36, - 36,16,82,0,0,160,20,60,37,16,84,0, - 2,131,1,60,184,12,34,172,2,131,1,60, - 188,12,32,172,44,0,34,142,0,0,0,0, - 0,0,66,148,2,131,19,60,176,12,115,38, - 0,32,66,48,15,0,64,20,33,40,0,0, - 2,131,4,60,160,131,132,36,2,131,16,60, - 192,131,16,38,33,40,0,2,2,131,7,60, - 24,132,231,36,15,63,192,12,71,2,6,36, - 1,0,4,36,33,40,0,2,188,7,192,12, - 71,2,6,36,33,40,0,0,33,48,0,0, - 36,16,114,2,44,0,35,142,37,16,84,0, - 4,0,98,172,44,0,36,142,208,7,7,36, - 129,67,192,12,2,0,132,36,12,0,64,20, - 0,0,0,0,44,0,34,142,0,0,0,0, - 2,0,69,148,2,131,4,60,15,63,192,12, - 56,132,132,36,255,255,4,36,2,131,5,60, - 192,131,165,36,188,7,192,12,79,2,6,36, - 44,0,34,142,0,33,3,36,2,0,67,164, - 8,0,34,142,0,0,0,0,0,0,64,172, - 44,0,191,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,232,255,189,39, - 128,128,132,143,0,128,2,52,16,0,191,175, - 2,131,1,60,3,0,128,4,178,12,34,164, - 177,11,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 8,0,224,3,0,0,0,0,0,0,0,0, - 0,0,0,0,240,255,2,52,2,131,1,60, - 33,8,34,0,208,12,32,172,240,255,66,36, - 251,255,65,4,0,0,0,0,2,131,2,60, - 208,12,66,36,0,163,1,60,12,1,32,172, - 0,163,1,60,212,5,34,172,1,0,2,60, - 148,133,128,175,144,133,128,175,0,163,1,60, - 8,0,224,3,216,5,34,172,0,0,136,148, - 4,0,138,148,1,0,2,49,34,0,64,20, - 2,0,137,148,0,25,10,0,38,24,106,0, - 38,24,105,0,240,255,99,48,2,131,15,60, - 208,12,239,37,33,40,111,0,68,133,142,143, - 128,0,3,36,0,0,162,140,4,0,171,148, - 23,0,64,16,43,16,194,1,9,0,64,16, - 6,0,172,148,7,0,11,21,8,0,173,148, - 5,0,44,21,0,0,0,0,3,0,77,21, - 10,0,162,148,8,0,224,3,0,0,0,0, - 255,255,99,36,10,0,96,16,240,255,165,36, - 43,16,175,0,238,255,64,16,0,0,162,140, - 248,127,229,37,248,127,165,36,218,24,192,8, - 0,0,162,140,8,0,224,3,254,255,2,36, - 8,0,224,3,255,255,2,36,8,0,224,3, - 0,0,0,0,0,0,136,148,68,133,142,143, - 1,0,2,49,53,0,64,20,2,0,137,148, - 0,131,2,60,4,0,138,148,12,1,89,140, - 0,25,10,0,38,24,106,0,38,24,105,0, - 240,255,99,48,2,131,15,60,208,12,239,37, - 33,56,111,0,128,0,3,36,0,0,248,140, - 4,0,235,148,43,16,216,1,14,0,64,16, - 6,0,236,148,24,0,11,21,8,0,237,148, - 22,0,44,21,255,127,2,60,20,0,77,21, - 255,255,66,52,43,16,2,3,2,0,64,16, - 33,16,198,1,0,0,226,172,10,0,229,164, - 8,0,224,3,0,0,2,36,3,0,0,23, - 1,0,57,35,0,131,2,60,12,1,89,172, - 33,16,198,1,0,0,226,172,10,0,229,164, - 4,0,232,164,6,0,233,164,8,0,234,164, - 8,0,224,3,1,0,2,36,255,255,99,36, - 11,0,96,16,0,0,0,0,240,255,231,36, - 43,16,239,0,221,255,64,16,0,0,248,140, - 248,127,231,37,248,127,231,36,8,25,192,8, - 0,0,248,140,8,0,224,3,0,0,2,36, - 144,133,130,143,0,0,0,0,1,0,66,32, - 144,133,130,175,8,0,224,3,255,255,2,36, - 8,0,224,3,0,0,0,0,164,128,130,143, - 0,0,0,0,7,0,130,20,232,255,189,39, - 160,128,130,143,2,131,3,60,208,12,99,36, - 0,17,2,0,108,25,192,8,33,16,67,0, - 42,16,130,0,3,0,64,16,255,255,2,36, - 164,128,128,175,160,128,130,175,164,128,130,143, - 160,128,131,143,35,48,130,0,1,0,101,36, - 0,16,162,40,25,0,64,16,0,25,5,0, - 68,133,135,143,2,131,2,60,33,16,67,0, - 208,12,66,140,0,0,0,0,43,16,226,0, - 4,0,64,16,0,0,0,0,255,255,198,36, - 6,0,192,16,0,16,162,40,1,0,165,36, - 0,16,162,40,243,255,64,20,16,0,99,36, - 0,16,162,40,7,0,64,16,0,25,5,0, - 2,131,2,60,208,12,66,36,160,128,133,175, - 164,128,132,175,108,25,192,8,33,16,98,0, - 33,16,0,0,255,255,3,36,164,128,128,175, - 160,128,131,175,8,0,224,3,24,0,189,39, - 0,0,0,0,0,0,0,0,24,255,189,39, - 228,0,191,175,224,0,190,175,220,0,183,175, - 216,0,182,175,212,0,181,175,208,0,180,175, - 204,0,179,175,200,0,178,175,196,0,177,175, - 192,0,176,175,44,28,192,12,0,0,0,0, - 176,128,132,39,15,63,192,12,1,0,17,36, - 24,0,176,39,164,68,192,12,33,32,0,2, - 24,0,162,131,0,0,0,0,137,25,192,8, - 32,0,8,36,0,0,2,130,32,0,8,36, - 253,255,72,16,1,0,16,38,255,255,16,38, - 9,0,8,36,249,255,72,16,1,0,16,38, - 255,255,16,38,0,0,2,146,0,0,0,0, - 208,255,66,36,10,0,66,44,27,0,64,16, - 33,32,0,2,33,40,0,0,212,68,192,12, - 33,48,0,0,0,0,3,146,0,0,0,0, - 208,255,99,36,10,0,99,44,9,0,96,16, - 33,136,64,0,1,0,16,38,0,0,2,146, - 0,0,0,0,208,255,66,36,10,0,66,44, - 251,255,64,20,1,0,16,38,255,255,16,38, - 0,0,2,130,32,0,8,36,253,255,72,16, - 1,0,16,38,255,255,16,38,9,0,8,36, - 249,255,72,16,1,0,16,38,255,255,16,38, - 0,0,2,130,0,0,3,146,0,0,0,0, - 22,0,64,16,104,0,180,39,32,0,8,36, - 19,0,72,16,9,0,8,36,17,0,72,16, - 32,0,5,36,9,0,4,36,208,255,98,36, - 10,0,66,44,12,0,64,20,0,0,0,0, - 1,0,16,38,0,0,131,162,0,0,2,130, - 0,0,3,146,0,0,0,0,5,0,64,16, - 1,0,148,38,3,0,69,16,0,0,0,0, - 243,255,68,20,208,255,98,36,0,0,128,162, - 104,0,180,39,0,0,2,130,32,0,8,36, - 253,255,72,16,1,0,16,38,255,255,16,38, - 9,0,8,36,249,255,72,16,1,0,16,38, - 255,255,16,38,33,240,0,2,0,0,196,131, - 0,0,0,0,32,69,192,12,144,0,190,175, - 11,0,64,16,33,32,192,3,33,40,0,0, - 212,68,192,12,33,48,0,0,33,152,64,0, - 33,32,192,3,33,40,0,0,44,69,192,12, - 16,0,6,36,232,25,192,8,33,144,64,0, - 255,255,18,36,255,255,19,36,0,0,3,130, - 0,0,2,146,0,0,0,0,17,0,96,16, - 32,0,8,36,15,0,104,16,1,0,16,38, - 255,255,16,38,32,0,4,36,0,22,2,0, - 3,22,2,0,9,0,8,36,8,0,72,16, - 0,0,0,0,1,0,16,38,0,0,3,130, - 0,0,2,146,3,0,96,16,0,0,0,0, - 246,255,100,20,0,22,2,0,0,0,2,130, - 32,0,8,36,253,255,72,16,1,0,16,38, - 255,255,16,38,9,0,8,36,249,255,72,16, - 1,0,16,38,255,255,16,38,33,184,0,2, - 33,32,224,2,33,40,0,0,212,68,192,12, - 33,48,0,0,33,32,224,2,33,40,0,0, - 16,0,6,36,44,69,192,12,33,176,64,0, - 0,0,227,130,0,0,0,0,15,0,96,16, - 33,168,64,0,32,0,8,36,12,0,104,16, - 32,0,3,36,0,0,2,130,9,0,8,36, - 8,0,72,16,0,0,0,0,1,0,16,38, - 0,0,2,130,0,0,0,0,3,0,64,16, - 0,0,0,0,248,255,67,20,0,0,0,0, - 0,0,131,130,0,0,0,0,121,0,98,44, - 244,1,64,16,128,16,3,0,2,131,1,60, - 33,8,34,0,160,138,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,1,0,131,130, - 104,0,2,36,26,0,98,16,105,0,98,40, - 7,0,64,16,116,0,2,36,34,0,96,16, - 98,0,2,36,11,0,98,16,0,0,0,0, - 26,28,192,8,0,0,0,0,5,0,98,16, - 119,0,8,36,27,0,104,16,33,16,32,2, - 26,28,192,8,0,0,0,0,4,162,2,60, - 33,144,66,2,2,0,130,130,0,0,0,0, - 214,1,64,20,0,0,0,0,2,131,4,60, - 108,132,132,36,0,0,70,146,82,26,192,8, - 0,0,0,0,2,0,130,130,0,0,0,0, - 205,1,64,20,0,0,0,0,2,131,4,60, - 120,132,132,36,0,0,70,150,0,0,0,0, - 15,63,192,12,33,40,64,2,125,25,192,8, - 0,0,0,0,33,16,32,2,37,255,64,16, - 255,255,49,38,0,0,80,142,2,131,4,60, - 132,132,132,36,33,40,64,2,4,0,82,38, - 15,63,192,12,33,48,0,2,33,16,32,2, - 247,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,1,0,131,130,104,0,2,36, - 23,0,98,16,105,0,98,40,7,0,64,16, - 116,0,2,36,25,0,96,16,98,0,2,36, - 11,0,98,16,0,0,0,0,26,28,192,8, - 0,0,0,0,5,0,98,16,119,0,8,36, - 17,0,104,16,0,0,0,0,26,28,192,8, - 0,0,0,0,4,162,2,60,33,144,66,2, - 2,0,130,130,0,0,0,0,158,1,64,20, - 0,0,0,0,125,25,192,8,0,0,85,162, - 2,0,130,130,0,0,0,0,152,1,64,20, - 0,0,0,0,125,25,192,8,0,0,85,166, - 125,25,192,8,0,0,85,174,0,163,16,60, - 31,163,17,60,255,255,49,54,0,0,2,142, - 0,0,0,0,4,0,82,20,0,0,0,0, - 180,128,132,39,15,63,192,12,33,40,0,2, - 4,0,16,38,43,16,48,2,246,255,64,16, - 0,0,0,0,125,25,192,8,0,0,0,0, - 33,16,32,2,228,254,64,16,255,255,49,38, - 33,32,96,2,164,32,192,12,33,40,192,2, - 33,16,32,2,251,255,64,20,255,255,49,38, - 125,25,192,8,0,0,0,0,1,0,130,130, - 0,0,0,0,117,1,64,20,33,32,32,2, - 133,29,192,12,33,40,96,2,125,25,192,8, - 0,0,0,0,33,32,96,2,33,40,32,2, - 234,31,192,12,33,48,192,2,125,25,192,8, - 0,0,0,0,1,0,130,130,0,0,0,0, - 103,1,64,20,33,16,32,2,200,254,64,16, - 255,255,49,38,33,32,96,2,33,40,192,2, - 182,29,192,12,33,48,0,2,33,16,32,2, - 250,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,33,32,32,2,33,40,96,2, - 33,48,192,2,38,30,192,12,33,56,0,2, - 125,25,192,8,0,0,0,0,5,162,2,60, - 0,0,69,144,2,131,4,60,15,63,192,12, - 144,132,132,36,125,25,192,8,0,0,0,0, - 0,163,1,60,20,1,32,172,14,0,32,18, - 33,128,0,0,164,7,192,12,1,0,16,38, - 143,63,192,12,0,0,0,0,143,63,192,12, - 0,0,0,0,143,63,192,12,0,0,0,0, - 143,63,192,12,0,0,0,0,43,16,17,2, - 244,255,64,20,0,0,0,0,184,63,192,12, - 0,0,0,0,0,163,16,60,20,1,16,142, - 0,0,0,0,7,0,17,22,33,40,32,2, - 2,131,4,60,164,132,132,36,15,63,192,12, - 33,40,32,2,125,25,192,8,0,0,0,0, - 2,131,4,60,188,132,132,36,15,63,192,12, - 33,48,0,2,125,25,192,8,0,0,0,0, - 0,0,226,130,7,162,8,60,16,0,64,16, - 33,144,72,2,33,16,32,2,134,254,64,16, - 255,255,49,38,0,0,85,174,2,131,4,60, - 132,132,132,36,33,40,64,2,15,63,192,12, - 33,48,160,2,4,0,82,38,33,16,32,2, - 247,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,33,16,32,2,119,254,64,16, - 255,255,49,38,0,0,80,142,2,131,4,60, - 132,132,132,36,33,40,64,2,4,0,82,38, - 15,63,192,12,33,48,0,2,33,16,32,2, - 247,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,7,162,16,60,64,0,17,38, - 2,131,4,60,228,132,132,36,33,40,0,2, - 0,0,6,142,0,0,0,0,15,63,192,12, - 4,0,16,38,42,16,17,2,247,255,64,20, - 7,162,8,60,128,0,16,37,176,0,17,37, - 2,131,4,60,228,132,132,36,33,40,0,2, - 0,0,6,142,0,0,0,0,15,63,192,12, - 4,0,16,38,42,16,17,2,247,255,64,20, - 7,162,8,60,192,0,16,37,240,0,17,37, - 2,131,4,60,228,132,132,36,33,40,0,2, - 0,0,6,142,0,0,0,0,15,63,192,12, - 4,0,16,38,42,16,17,2,247,255,64,20, - 0,0,0,0,125,25,192,8,0,0,0,0, - 1,0,130,130,0,0,0,0,222,0,64,20, - 33,16,32,2,63,254,64,16,255,255,49,38, - 33,32,96,2,213,29,192,12,33,40,160,2, - 33,16,32,2,251,255,64,20,255,255,49,38, - 125,25,192,8,0,0,0,0,1,0,130,130, - 0,0,0,0,208,0,64,20,33,16,32,2, - 49,254,64,16,255,255,49,38,33,32,96,2, - 161,31,192,12,33,40,192,2,33,16,32,2, - 251,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,33,16,32,2,38,254,64,16, - 255,255,49,38,208,32,192,12,33,32,0,0, - 33,32,0,0,164,32,192,12,33,40,0,0, - 40,29,192,12,0,0,0,0,133,29,192,12, - 255,255,4,36,33,16,32,2,245,255,64,20, - 255,255,49,38,125,25,192,8,0,0,0,0, - 1,0,131,130,87,0,2,36,27,0,98,16, - 88,0,98,40,7,0,64,16,114,0,2,36, - 37,0,96,16,82,0,2,36,9,0,98,16, - 0,0,0,0,125,25,192,8,0,0,0,0, - 5,0,98,16,119,0,8,36,15,0,104,16, - 0,0,0,0,125,25,192,8,0,0,0,0, - 2,0,130,130,0,0,0,0,159,0,64,20, - 0,0,0,0,60,65,192,12,33,32,96,2, - 184,128,132,39,33,40,96,2,15,63,192,12, - 33,48,64,0,125,25,192,8,0,0,0,0, - 2,0,130,130,0,0,0,0,147,0,64,20, - 33,32,96,2,162,65,192,12,33,40,160,2, - 242,253,64,20,33,40,160,2,2,131,4,60, - 8,133,132,36,15,63,192,12,33,48,96,2, - 125,25,192,8,0,0,0,0,33,16,32,2, - 233,253,64,16,255,255,49,38,40,29,192,12, - 0,0,0,0,33,16,32,2,252,255,64,20, - 255,255,49,38,125,25,192,8,0,0,0,0, - 1,0,133,130,87,0,2,36,29,0,162,16, - 88,0,162,40,5,0,64,16,82,0,2,36, - 11,0,162,16,33,16,32,2,125,25,192,8, - 0,0,0,0,114,0,2,36,5,0,162,16, - 119,0,8,36,19,0,168,16,33,32,64,2, - 125,25,192,8,0,0,0,0,33,16,32,2, - 206,253,64,16,255,255,49,38,168,69,192,12, - 33,32,64,2,184,128,132,39,33,40,64,2, - 15,63,192,12,33,48,64,0,1,0,82,38, - 33,16,32,2,247,255,64,20,255,255,49,38, - 125,25,192,8,0,0,0,0,33,32,64,2, - 29,70,192,12,33,40,160,2,189,253,64,20, - 33,40,160,2,2,131,4,60,40,133,132,36, - 15,63,192,12,33,48,64,2,125,25,192,8, - 0,0,0,0,144,0,164,143,122,28,192,12, - 0,0,0,0,125,25,192,8,0,0,0,0, - 33,16,96,2,175,253,64,16,255,255,115,38, - 143,63,192,12,0,0,0,0,33,16,96,2, - 252,255,64,20,255,255,115,38,125,25,192,8, - 0,0,0,0,33,16,32,2,165,253,64,16, - 255,255,49,38,33,32,96,2,208,32,192,12, - 33,40,192,2,33,16,32,2,251,255,64,20, - 255,255,49,38,125,25,192,8,0,0,0,0, - 1,0,130,146,0,0,0,0,159,255,66,36, - 0,22,2,0,3,30,2,0,24,0,98,44, - 27,0,64,16,128,16,3,0,2,131,1,60, - 33,8,34,0,136,140,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,12,33,192,12, - 33,32,64,2,125,25,192,8,0,0,0,0, - 15,33,192,12,33,32,96,2,125,25,192,8, - 0,0,0,0,18,33,192,12,33,32,96,2, - 125,25,192,8,0,0,0,0,22,33,192,12, - 33,32,96,2,125,25,192,8,0,0,0,0, - 25,33,192,12,33,32,64,2,125,25,192,8, - 0,0,0,0,33,32,64,2,7,33,192,12, - 33,40,192,2,125,25,192,8,0,0,0,0, - 16,0,182,175,33,32,32,2,33,40,192,3, - 33,48,224,2,161,33,192,12,33,56,160,2, - 125,25,192,8,0,0,0,0,33,136,0,0, - 2,131,4,60,72,133,132,36,15,63,192,12, - 1,0,49,38,32,0,34,46,250,255,64,20, - 0,0,0,0,125,25,192,8,0,0,0,0, - 2,131,4,60,92,133,132,36,15,63,192,12, - 33,40,128,2,123,25,192,8,0,0,0,0, - 228,0,191,143,224,0,190,143,220,0,183,143, - 216,0,182,143,212,0,181,143,208,0,180,143, - 204,0,179,143,200,0,178,143,196,0,177,143, - 192,0,176,143,8,0,224,3,232,0,189,39, - 232,255,189,39,2,131,5,60,192,154,165,36, - 20,0,191,175,16,0,176,175,0,0,162,140, - 0,0,0,0,9,0,64,16,33,128,160,0, - 0,0,5,142,192,128,132,39,15,63,192,12, - 4,0,16,38,0,0,2,142,0,0,0,0, - 249,255,64,20,0,0,0,0,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 0,0,132,144,0,0,0,0,208,255,130,36, - 10,0,66,44,4,0,64,16,0,22,4,0, - 3,22,2,0,89,28,192,8,208,255,66,36, - 159,255,130,36,6,0,66,44,4,0,64,16, - 0,22,4,0,3,22,2,0,89,28,192,8, - 169,255,66,36,191,255,130,36,6,0,66,44, - 3,0,64,20,0,22,4,0,89,28,192,8, - 255,255,2,36,3,22,2,0,201,255,66,36, - 8,0,224,3,0,0,0,0,216,255,189,39, - 24,0,178,175,33,144,128,0,32,0,191,175, - 28,0,179,175,20,0,177,175,16,0,176,175, - 0,0,81,142,0,0,0,0,65,28,192,12, - 33,32,32,2,33,24,64,0,255,255,19,36, - 9,0,115,16,0,129,3,0,65,28,192,12, - 1,0,36,38,33,24,64,0,4,0,115,16, - 2,0,34,38,0,0,66,174,115,28,192,8, - 37,16,3,2,255,255,2,36,32,0,191,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 176,255,189,39,64,0,180,175,33,160,128,0, - 72,0,191,175,68,0,181,175,60,0,179,175, - 56,0,178,175,52,0,177,175,48,0,176,175, - 0,0,130,130,0,0,0,0,53,0,64,20, - 33,128,0,0,27,67,192,12,33,32,0,0, - 1,0,4,36,27,67,192,12,33,128,64,0, - 2,0,4,36,27,67,192,12,33,136,64,0, - 33,24,64,0,255,255,2,36,5,0,2,18, - 0,0,0,0,3,0,34,18,0,0,0,0, - 6,0,98,20,255,255,2,52,2,131,4,60, - 15,63,192,12,60,137,132,36,29,29,192,8, - 0,0,0,0,5,0,2,18,0,0,0,0, - 3,0,34,18,0,0,0,0,6,0,98,20, - 1,0,2,50,2,131,4,60,15,63,192,12, - 104,137,132,36,29,29,192,8,0,0,0,0, - 6,0,64,16,255,0,5,50,2,131,4,60, - 15,63,192,12,132,137,132,36,29,29,192,8, - 0,0,0,0,2,131,4,60,176,137,132,36, - 3,50,16,0,3,18,17,0,16,0,162,175, - 255,0,98,48,20,0,162,175,3,18,3,0, - 255,0,39,50,15,63,192,12,24,0,162,175, - 29,29,192,8,0,0,0,0,40,0,180,175, - 58,0,21,36,32,0,19,36,255,255,18,36, - 32,0,177,39,40,0,162,143,0,0,0,0, - 0,0,67,128,0,0,0,0,3,0,117,16, - 0,0,0,0,3,0,115,20,0,0,0,0, - 1,0,66,36,40,0,162,175,91,28,192,12, - 40,0,164,39,33,24,64,0,75,0,114,16, - 0,0,0,0,40,0,162,143,0,0,35,166, - 0,0,67,128,0,0,0,0,3,0,117,16, - 0,0,0,0,3,0,115,20,0,0,0,0, - 1,0,66,36,40,0,162,175,91,28,192,12, - 40,0,164,39,33,24,64,0,60,0,114,16, - 1,0,16,38,0,0,34,150,0,26,3,0, - 37,16,67,0,0,0,34,166,3,0,2,42, - 220,255,64,20,2,0,49,38,32,0,165,151, - 0,0,0,0,1,0,162,48,7,0,64,16, - 0,0,0,0,2,131,4,60,208,137,132,36, - 15,63,192,12,255,0,165,48,25,29,192,8, - 0,0,0,0,36,0,162,151,0,0,0,0, - 0,7,66,48,6,0,64,16,0,0,0,0, - 2,131,4,60,15,63,192,12,0,138,132,36, - 25,29,192,8,0,0,0,0,255,66,192,12, - 33,32,0,0,1,0,4,36,34,0,165,151, - 0,0,0,0,255,66,192,12,33,128,0,0, - 36,0,165,151,0,0,0,0,255,66,192,12, - 2,0,4,36,2,131,4,60,15,63,192,12, - 32,138,132,36,2,131,4,60,80,138,132,36, - 15,63,192,12,33,40,0,2,196,128,132,39, - 200,128,134,39,31,21,192,12,32,0,165,39, - 36,0,162,151,1,0,16,38,0,1,66,36, - 36,0,162,167,8,0,2,42,7,0,64,16, - 0,0,0,0,8,29,192,8,0,0,0,0, - 2,131,4,60,116,138,132,36,15,63,192,12, - 33,40,128,2,72,0,191,143,68,0,181,143, - 64,0,180,143,60,0,179,143,56,0,178,143, - 52,0,177,143,48,0,176,143,8,0,224,3, - 80,0,189,39,0,0,0,0,0,0,0,0, - 224,255,189,39,16,0,176,175,33,128,0,0, - 20,0,177,175,33,136,0,0,24,0,191,175, - 33,32,0,2,162,65,192,12,33,40,0,0, - 43,0,64,16,0,0,0,0,1,0,16,38, - 64,0,2,42,249,255,64,20,33,32,0,2, - 33,128,0,0,85,85,17,36,33,32,0,2, - 162,65,192,12,85,85,5,36,32,0,64,16, - 0,0,0,0,1,0,16,38,64,0,2,42, - 249,255,64,20,33,32,0,2,33,128,0,0, - 170,170,17,52,33,32,0,2,162,65,192,12, - 170,170,5,52,21,0,64,16,0,0,0,0, - 1,0,16,38,64,0,2,42,249,255,64,20, - 33,32,0,2,33,128,0,0,255,255,17,52, - 33,32,0,2,162,65,192,12,255,255,5,52, - 10,0,64,16,0,0,0,0,1,0,16,38, - 64,0,2,42,249,255,64,20,33,32,0,2, - 2,131,4,60,15,63,192,12,240,140,132,36, - 101,29,192,8,0,0,0,0,60,65,192,12, - 33,32,0,2,2,131,4,60,4,141,132,36, - 33,40,32,2,33,48,0,2,15,63,192,12, - 33,56,64,0,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 0,0,0,0,0,0,0,0,232,255,189,39, - 16,0,191,175,210,7,192,12,0,0,0,0, - 139,14,192,12,0,0,0,0,180,10,192,12, - 0,0,0,0,32,133,132,143,1,0,2,36, - 42,16,68,0,9,0,64,16,0,2,3,36, - 64,34,4,0,2,131,1,60,33,8,35,0, - 196,246,32,172,0,2,99,36,42,16,100,0, - 250,255,64,20,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 208,255,189,39,24,0,178,175,33,144,128,0, - 32,0,180,175,33,160,160,0,44,0,191,175, - 40,0,182,175,36,0,181,175,28,0,179,175, - 20,0,177,175,3,0,128,26,16,0,176,175, - 149,29,192,8,1,0,147,38,1,0,20,36, - 32,133,147,143,255,255,82,38,255,255,2,36, - 20,0,66,18,255,255,21,36,2,131,22,60, - 192,246,214,38,108,29,192,12,33,128,128,2, - 42,16,19,2,10,0,64,16,64,18,16,0, - 33,136,86,0,242,21,192,12,33,32,32,2, - 133,12,192,12,33,32,0,2,1,0,16,38, - 42,16,19,2,249,255,64,20,0,2,49,38, - 255,255,82,38,240,255,85,22,0,0,0,0, - 44,0,191,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 48,0,189,39,216,255,189,39,24,0,178,175, - 33,144,160,0,28,0,179,175,33,152,192,0, - 32,0,191,175,20,0,177,175,3,0,128,24, - 16,0,176,175,195,29,192,8,1,0,145,36, - 1,0,4,36,32,133,145,143,33,128,128,0, - 42,16,17,2,8,0,64,16,33,32,0,2, - 33,40,64,2,250,29,192,12,33,48,96,2, - 1,0,16,38,42,16,17,2,250,255,64,20, - 33,32,0,2,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,224,255,189,39, - 24,0,191,175,20,0,177,175,3,0,128,24, - 16,0,176,175,222,29,192,8,1,0,145,36, - 1,0,4,36,32,133,145,143,33,128,128,0, - 42,16,17,2,7,0,64,16,0,0,0,0, - 237,29,192,12,33,32,0,2,1,0,16,38, - 42,16,17,2,251,255,64,20,0,0,0,0, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,64,34,4,0, - 2,131,2,60,192,246,66,36,33,32,130,0, - 44,0,131,140,1,0,2,36,32,0,130,172, - 16,0,2,36,2,0,98,164,8,0,130,140, - 0,0,0,0,8,0,224,3,0,0,64,172, - 208,255,189,39,33,48,128,0,64,18,6,0, - 2,131,3,60,192,246,99,36,36,0,177,175, - 33,136,67,0,40,0,191,175,32,0,176,175, - 4,0,34,142,0,0,0,0,4,0,64,20, - 33,128,160,0,1,0,4,36,133,29,192,12, - 33,40,192,0,3,0,0,30,221,5,2,42, - 17,30,192,8,1,0,16,36,3,0,64,20, - 33,32,32,2,220,5,16,36,33,32,32,2, - 208,7,5,36,108,0,131,140,12,0,2,36, - 2,0,98,164,16,0,162,39,8,0,98,172, - 0,128,2,54,12,0,96,172,16,0,162,175, - 255,255,2,36,20,0,162,175,2,131,2,60, - 0,155,66,36,98,31,192,12,24,0,162,175, - 40,0,191,143,36,0,177,143,32,0,176,143, - 8,0,224,3,48,0,189,39,56,254,189,39, - 160,1,176,175,33,128,192,0,48,1,164,175, - 33,32,224,0,64,18,5,0,2,131,3,60, - 192,246,99,36,33,16,67,0,56,1,162,175, - 64,18,16,0,33,16,67,0,40,0,168,39, - 196,1,191,175,192,1,190,175,188,1,183,175, - 184,1,182,175,180,1,181,175,176,1,180,175, - 172,1,179,175,168,1,178,175,164,1,177,175, - 64,1,162,175,12,0,160,24,96,1,168,175, - 32,133,131,143,0,0,0,0,42,16,163,0, - 19,1,64,16,1,0,2,36,5,0,0,26, - 42,16,3,2,15,1,64,16,1,0,2,36, - 3,0,176,20,33,40,0,0,86,31,192,8, - 1,0,2,36,212,68,192,12,33,48,0,0, - 6,0,65,4,104,1,162,175,33,72,64,0, - 35,72,9,0,104,1,169,175,87,30,192,8, - 112,1,160,175,1,0,8,36,112,1,168,175, - 1,0,4,36,133,29,192,12,33,40,0,0, - 237,29,192,12,33,32,0,2,24,0,169,39, - 56,1,168,143,255,0,2,36,80,1,169,175, - 108,0,8,141,43,1,163,39,72,1,168,175, - 0,0,98,160,255,255,66,36,253,255,65,4, - 255,255,99,36,64,1,169,143,0,0,0,0, - 120,0,41,141,64,1,168,143,128,1,169,175, - 124,0,8,141,64,1,169,143,136,1,168,175, - 44,0,34,141,0,0,0,0,12,0,64,172, - 44,0,34,141,0,0,0,0,16,0,64,172, - 44,0,34,141,120,1,160,175,32,0,64,172, - 44,0,34,141,88,1,160,175,24,0,64,172, - 48,1,168,143,0,0,0,0,168,0,0,25, - 40,0,169,39,144,1,169,175,88,1,168,143, - 0,0,0,0,255,0,2,49,4,0,86,36, - 60,0,194,42,2,0,64,16,0,0,0,0, - 60,0,22,36,104,1,169,143,0,0,0,0, - 2,0,32,17,0,0,0,0,104,1,182,143, - 56,1,164,143,72,1,168,143,12,0,2,36, - 2,0,2,165,80,1,169,143,0,128,194,54, - 8,0,9,173,12,0,0,173,0,0,34,173, - 255,255,8,36,4,0,40,173,144,1,168,143, - 0,0,0,0,8,0,40,173,88,1,168,143, - 96,1,169,143,208,7,5,36,98,31,192,12, - 0,0,40,173,0,128,5,52,0,128,6,52, - 128,1,164,143,0,0,0,0,129,67,192,12, - 2,0,7,36,13,0,64,20,0,0,0,0, - 88,1,165,143,2,131,4,60,15,63,192,12, - 64,141,132,36,120,1,169,143,0,0,0,0, - 1,0,41,37,20,0,34,41,117,0,64,16, - 120,1,169,175,32,31,192,8,0,0,0,0, - 128,1,168,143,64,1,169,143,8,0,2,141, - 255,255,8,36,136,0,53,141,0,0,0,0, - 50,0,72,16,33,184,0,0,1,0,4,36, - 4,0,18,36,4,0,3,36,0,0,190,142, - 8,0,166,142,112,1,169,143,255,63,212,51, - 30,0,32,17,33,184,244,2,42,16,116,0, - 27,0,64,16,33,152,96,0,144,1,168,143, - 0,0,0,0,33,136,72,2,33,128,102,0, - 15,0,128,16,0,0,0,0,0,0,2,146, - 0,0,35,146,0,0,0,0,10,0,67,16, - 33,48,192,2,2,131,4,60,92,141,132,36, - 88,1,165,143,16,0,163,175,0,0,2,146, - 33,56,64,2,15,63,192,12,20,0,162,175, - 33,32,0,0,1,0,115,38,1,0,16,38, - 1,0,49,38,42,16,116,2,235,255,64,20, - 1,0,82,38,33,24,0,0,4,0,181,142, - 0,128,194,51,217,255,64,16,0,0,0,0, - 128,1,169,143,0,0,0,0,8,0,34,141, - 0,0,0,0,25,0,128,16,18,0,87,164, - 9,0,246,18,33,48,192,2,2,131,4,60, - 140,141,132,36,88,1,165,143,0,0,0,0, - 15,63,192,12,33,56,224,2,5,31,192,8, - 0,0,0,0,64,1,168,143,0,0,0,0, - 136,0,2,141,96,1,169,143,8,0,70,140, - 0,0,34,141,0,0,198,140,0,0,0,0, - 7,0,194,16,0,0,0,0,88,1,165,143, - 2,131,4,60,15,63,192,12,184,141,132,36, - 64,1,168,143,0,0,0,0,136,0,4,141, - 152,21,192,12,0,0,0,0,64,1,169,143, - 0,0,0,0,136,0,53,173,128,1,168,143, - 8,128,2,52,0,0,0,165,2,0,2,165, - 8,0,0,173,12,0,0,165,136,1,169,143, - 8,0,2,36,2,0,34,165,4,0,40,141, - 128,1,169,143,136,1,168,175,4,0,41,141, - 64,1,168,143,128,1,169,175,120,0,9,173, - 136,1,169,143,0,0,0,0,124,0,9,173, - 88,1,168,143,48,1,169,143,1,0,8,37, - 42,16,9,1,91,255,64,20,88,1,168,175, - 64,1,168,143,0,0,0,0,44,0,3,141, - 0,0,0,0,12,0,98,140,0,0,0,0, - 5,0,64,16,0,0,0,0,12,0,101,140, - 2,131,4,60,15,63,192,12,212,141,132,36, - 64,1,169,143,0,0,0,0,44,0,35,141, - 0,0,0,0,16,0,98,140,0,0,0,0, - 5,0,64,16,0,0,0,0,16,0,101,140, - 2,131,4,60,15,63,192,12,240,141,132,36, - 64,1,168,143,0,0,0,0,44,0,3,141, - 0,0,0,0,32,0,98,140,0,0,0,0, - 5,0,64,16,0,0,0,0,32,0,101,140, - 2,131,4,60,15,63,192,12,16,142,132,36, - 64,1,169,143,0,0,0,0,44,0,35,141, - 0,0,0,0,24,0,98,140,0,0,0,0, - 5,0,64,16,0,0,0,0,24,0,101,140, - 2,131,4,60,15,63,192,12,48,142,132,36, - 196,1,191,143,192,1,190,143,188,1,183,143, - 184,1,182,143,180,1,181,143,176,1,180,143, - 172,1,179,143,168,1,178,143,164,1,177,143, - 160,1,176,143,8,0,224,3,200,1,189,39, - 224,255,189,39,16,0,176,175,33,128,128,0, - 24,0,191,175,20,0,177,175,44,0,4,142, - 0,0,0,0,0,0,130,148,0,0,0,0, - 0,32,66,48,7,0,64,20,33,136,160,0, - 0,0,133,148,2,131,4,60,15,63,192,12, - 80,142,132,36,156,31,192,8,3,0,2,36, - 2,0,132,36,33,40,0,0,33,48,0,0, - 129,67,192,12,33,56,32,2,13,0,64,16, - 33,40,0,0,44,0,3,142,0,33,2,36, - 2,0,98,164,8,0,2,142,33,48,0,0, - 0,0,64,172,44,0,4,142,33,56,32,2, - 129,67,192,12,2,0,132,36,9,0,64,20, - 0,32,5,36,44,0,2,142,0,0,0,0, - 2,0,69,148,2,131,4,60,15,63,192,12, - 108,142,132,36,156,31,192,8,1,0,2,36, - 44,0,4,142,0,32,6,36,129,67,192,12, - 33,56,32,2,8,0,64,20,33,16,0,0, - 44,0,2,142,0,0,0,0,0,0,69,148, - 2,131,4,60,15,63,192,12,132,142,132,36, - 2,0,2,36,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 224,255,189,39,24,0,178,175,33,144,160,0, - 28,0,191,175,20,0,177,175,7,0,128,4, - 16,0,176,175,24,133,130,143,0,0,0,0, - 255,255,66,36,42,16,68,0,4,0,64,16, - 33,136,128,0,24,133,130,143,33,32,0,0, - 255,255,81,36,33,128,128,0,42,16,48,2, - 7,0,64,20,33,32,0,2,193,31,192,12, - 33,40,64,2,1,0,16,38,42,16,48,2, - 251,255,64,16,33,32,0,2,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,8,0,224,3, - 0,0,0,0,232,255,189,39,16,0,191,175, - 236,63,192,12,1,16,4,36,85,0,2,36, - 131,131,1,60,128,18,34,160,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 216,255,189,39,28,0,177,175,33,136,128,0, - 32,0,178,175,33,144,160,0,212,128,132,39, - 36,0,191,175,15,63,192,12,24,0,176,175, - 9,0,64,26,33,128,0,0,0,0,37,146, - 1,0,49,38,220,128,132,39,15,63,192,12, - 1,0,16,38,42,16,18,2,249,255,64,20, - 0,0,0,0,228,128,132,39,15,63,192,12, - 0,0,0,0,36,0,191,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,48,255,189,39,33,56,128,0, - 192,0,178,175,33,144,160,0,200,0,180,175, - 33,160,192,0,255,255,226,36,6,0,66,44, - 204,0,191,175,196,0,179,175,188,0,177,175, - 2,0,64,20,184,0,176,175,1,0,7,36, - 2,0,64,30,0,0,0,0,1,0,18,36, - 2,0,128,30,64,18,7,0,60,0,20,36, - 2,131,3,60,192,246,99,36,33,136,67,0, - 4,0,34,142,0,0,0,0,4,0,64,20, - 33,152,64,2,1,0,4,36,133,29,192,12, - 33,40,224,0,255,31,4,60,255,255,132,52, - 0,128,133,54,120,0,162,39,36,16,68,0, - 0,160,3,60,37,16,67,0,104,0,165,175, - 108,0,160,175,112,0,162,175,12,0,2,36, - 80,0,160,167,82,0,162,167,80,0,162,39, - 36,16,68,0,37,128,67,0,104,0,162,39, - 36,16,68,0,232,128,132,143,37,16,67,0, - 84,0,176,175,88,0,162,175,92,0,160,175, - 5,0,128,16,4,0,2,36,82,0,162,167, - 255,255,2,36,92,0,165,175,88,0,162,175, - 44,0,34,142,0,0,0,0,0,0,66,148, - 0,0,0,0,0,32,66,48,7,0,64,20, - 33,40,0,0,255,255,4,36,2,131,5,60, - 184,142,165,36,188,7,192,12,208,1,6,36, - 33,40,0,0,44,0,34,142,33,48,0,0, - 4,0,80,172,44,0,36,142,208,7,7,36, - 129,67,192,12,2,0,132,36,12,0,64,20, - 0,0,0,0,44,0,34,142,0,0,0,0, - 2,0,69,148,2,131,4,60,15,63,192,12, - 108,142,132,36,255,255,4,36,2,131,5,60, - 184,142,165,36,188,7,192,12,216,1,6,36, - 34,11,192,12,1,0,4,36,0,163,16,60, - 4,1,16,142,0,163,2,60,4,1,66,140, - 0,0,0,0,252,255,2,18,0,33,3,36, - 44,0,34,142,0,0,0,0,2,0,67,164, - 8,0,34,142,0,0,0,0,0,0,64,172, - 0,163,16,60,4,1,16,142,44,0,36,142, - 0,0,0,0,4,0,130,140,0,0,0,0, - 0,0,66,148,0,0,0,0,0,128,66,48, - 10,0,64,20,0,0,0,0,44,0,35,142, - 0,0,0,0,4,0,98,140,0,0,0,0, - 0,0,66,148,0,0,0,0,0,128,66,48, - 250,255,64,16,0,0,0,0,255,255,115,38, - 19,0,96,18,33,40,64,2,44,0,35,142, - 0,0,0,0,4,0,98,140,0,0,0,0, - 0,0,66,148,0,0,0,0,0,128,66,48, - 229,255,64,16,0,0,0,0,4,0,98,140, - 0,0,0,0,0,0,66,148,0,0,0,0, - 0,128,66,48,250,255,64,20,0,0,0,0, - 89,32,192,8,0,0,0,0,2,131,4,60, - 200,142,132,36,33,48,128,2,0,163,3,60, - 4,1,99,140,0,128,2,52,82,0,162,167, - 35,128,112,0,15,63,192,12,33,56,0,2, - 19,0,0,18,64,41,18,0,35,40,178,0, - 128,40,5,0,33,40,178,0,192,40,5,0, - 26,0,176,0,2,0,0,22,0,0,0,0, - 13,0,7,0,255,255,1,36,4,0,1,22, - 0,128,1,60,2,0,161,20,0,0,0,0, - 13,0,6,0,18,40,0,0,236,128,132,39, - 15,63,192,12,0,0,0,0,204,0,191,143, - 200,0,180,143,196,0,179,143,192,0,178,143, - 188,0,177,143,184,0,176,143,8,0,224,3, - 208,0,189,39,224,255,189,39,20,0,177,175, - 33,136,128,0,24,0,191,175,180,10,192,12, - 16,0,176,175,34,11,192,12,1,0,4,36, - 16,133,132,143,0,163,16,60,4,1,16,142, - 193,63,192,12,0,0,0,0,0,163,2,60, - 4,1,66,140,0,0,0,0,35,40,80,0, - 73,252,162,36,99,0,66,44,4,0,64,16, - 0,0,0,0,2,131,4,60,196,32,192,8, - 0,143,132,36,5,0,160,20,0,0,0,0, - 2,131,4,60,36,143,132,36,196,32,192,8, - 33,40,0,0,2,131,4,60,76,143,132,36, - 15,63,192,12,1,0,16,36,3,0,48,18, - 0,0,0,0,34,11,192,12,33,32,0,0, - 0,129,144,175,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 200,255,189,39,32,0,178,175,33,144,128,0, - 33,48,64,2,44,0,181,175,1,131,21,60, - 60,252,181,38,33,56,160,2,40,0,180,175, - 2,131,20,60,144,143,148,38,36,0,179,175, - 0,163,19,60,120,1,115,142,0,163,3,60, - 120,1,99,140,32,131,2,60,48,0,191,175, - 28,0,177,175,24,0,176,175,16,0,180,175, - 33,32,96,2,35,136,67,0,84,64,192,12, - 33,40,32,2,3,0,64,18,33,128,64,0, - 10,0,0,22,0,0,0,0,16,0,180,175, - 33,32,96,2,33,40,32,2,33,48,64,2, - 244,63,192,12,33,56,160,2,33,128,2,2, - 5,0,0,18,33,40,96,2,2,131,4,60, - 168,143,132,36,252,32,192,8,33,40,96,2, - 2,131,4,60,204,143,132,36,15,63,192,12, - 33,48,177,0,48,0,191,143,44,0,181,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 56,0,189,39,0,163,1,60,232,5,36,172, - 0,163,1,60,8,0,224,3,236,5,37,172, - 28,129,132,175,8,0,224,3,0,0,0,0, - 16,129,132,175,8,0,224,3,0,0,0,0, - 15,0,132,48,20,129,132,175,8,0,224,3, - 0,0,0,0,24,129,132,175,8,0,224,3, - 0,0,0,0,32,129,132,175,8,0,224,3, - 0,0,0,0,33,72,128,0,33,80,160,0, - 33,88,192,0,7,162,4,60,48,1,132,52, - 7,162,8,60,0,1,8,53,20,129,130,143, - 24,129,131,143,128,48,2,0,28,129,130,143, - 3,0,197,52,2,0,96,16,0,0,130,172, - 67,0,197,52,16,129,130,143,0,0,0,0, - 2,0,64,16,33,24,160,0,0,1,99,52, - 36,129,130,143,0,0,0,0,2,0,64,16, - 0,0,0,0,0,4,99,52,32,129,130,143, - 0,0,3,173,3,0,64,16,7,162,5,60, - 0,0,2,173,7,162,5,60,4,1,165,52, - 7,162,6,60,8,1,198,52,255,0,2,60, - 255,255,66,52,7,162,3,60,12,1,99,52, - 7,162,4,60,16,1,132,52,36,16,66,1, - 0,0,169,172,0,0,194,172,43,16,7,0, - 192,16,2,0,0,0,107,172,8,0,224,3, - 0,0,130,172,7,162,3,60,40,1,99,52, - 3,0,2,36,0,163,1,60,20,1,32,172, - 8,0,224,3,0,0,98,172,232,255,189,39, - 16,0,191,175,33,24,0,0,7,162,6,60, - 40,1,198,52,15,0,4,60,63,66,132,52, - 0,0,197,140,0,0,0,0,16,0,162,48, - 7,0,64,20,1,0,99,36,42,16,131,0, - 249,255,64,16,0,0,0,0,2,131,4,60, - 122,33,192,8,240,143,132,36,36,129,130,143, - 0,0,0,0,3,0,64,20,33,24,0,0, - 125,33,192,8,33,16,0,0,1,0,5,36, - 15,0,4,60,63,66,132,52,0,163,2,60, - 20,1,66,140,0,0,0,0,247,255,69,16, - 1,0,99,36,42,16,131,0,249,255,64,16, - 0,0,0,0,0,163,5,60,20,1,165,140, - 2,131,4,60,24,144,132,36,15,63,192,12, - 0,0,0,0,1,0,2,36,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 224,255,189,39,24,0,191,175,33,72,192,0, - 255,31,3,60,255,255,99,52,33,64,0,0, - 36,32,131,0,0,160,2,60,37,32,130,0, - 36,40,163,0,16,0,32,25,37,40,162,0, - 0,0,134,144,0,0,167,144,0,0,0,0, - 7,0,199,16,1,0,165,36,2,131,4,60, - 72,144,132,36,15,63,192,12,33,40,0,1, - 157,33,192,8,1,0,2,36,1,0,8,37, - 42,16,9,1,242,255,64,20,1,0,132,36, - 33,16,0,0,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,0,163,2,60, - 232,5,66,140,152,255,189,39,80,0,180,175, - 120,0,180,143,64,0,176,175,33,128,160,0, - 68,0,177,175,33,136,192,0,72,0,178,175, - 33,144,224,0,100,0,191,175,96,0,190,175, - 92,0,183,175,88,0,182,175,84,0,181,175, - 76,0,179,175,12,0,64,16,16,0,164,175, - 0,163,2,60,236,5,66,140,0,0,0,0, - 7,0,64,16,0,0,0,0,0,163,2,60, - 236,5,66,140,0,0,0,0,1,8,66,44, - 10,0,64,20,16,0,2,60,0,163,5,60, - 232,5,165,140,0,163,6,60,236,5,198,140, - 2,131,4,60,15,63,192,12,124,144,132,36, - 7,35,192,8,0,0,0,0,16,0,168,143, - 0,0,0,0,43,16,72,0,6,0,64,16, - 0,0,0,0,2,131,4,60,15,63,192,12, - 172,144,132,36,7,35,192,8,0,0,0,0, - 224,132,130,143,0,0,0,0,11,0,64,20, - 0,0,0,0,0,163,4,60,236,5,132,140, - 13,8,192,12,0,0,0,0,255,31,3,60, - 255,255,99,52,36,16,67,0,0,160,3,60, - 37,16,67,0,224,132,130,175,228,132,130,143, - 0,0,0,0,11,0,64,20,0,0,0,0, - 0,163,4,60,236,5,132,140,13,8,192,12, - 0,0,0,0,255,31,3,60,255,255,99,52, - 36,16,67,0,0,160,3,60,37,16,67,0, - 228,132,130,175,224,132,133,143,0,163,6,60, - 232,5,198,140,228,132,135,143,2,131,4,60, - 15,63,192,12,208,144,132,36,16,129,133,143, - 20,129,134,143,2,131,4,60,15,63,192,12, - 8,145,132,36,7,162,2,60,232,0,66,52, - 0,0,83,140,1,0,3,130,105,0,2,36, - 7,0,98,20,251,255,2,60,1,0,2,36, - 36,129,130,175,4,0,2,60,0,8,66,52, - 10,34,192,8,37,152,98,2,36,129,128,175, - 255,247,66,52,36,152,98,2,7,162,2,60, - 232,0,66,52,0,0,83,172,0,0,5,130, - 114,0,2,36,3,0,162,16,82,0,2,36, - 3,0,162,20,119,0,2,36,42,34,192,8, - 33,176,0,0,3,0,162,16,87,0,2,36, - 3,0,162,20,108,0,2,36,42,34,192,8, - 1,0,22,36,3,0,162,16,76,0,2,36, - 3,0,162,20,116,0,2,36,42,34,192,8, - 2,0,22,36,118,0,162,16,84,0,2,36, - 116,0,162,16,0,0,0,0,2,131,4,60, - 15,63,192,12,52,145,132,36,7,35,192,8, - 0,0,0,0,0,0,38,130,0,0,0,0, - 12,0,192,16,99,0,2,36,3,0,194,16, - 67,0,2,36,4,0,194,20,33,152,0,0, - 5,0,19,36,61,34,192,8,5,0,21,36, - 2,131,1,60,80,155,50,160,61,34,192,8, - 33,168,0,0,33,168,0,0,5,0,19,36, - 2,131,1,60,80,155,32,160,16,0,168,143, - 0,163,18,60,236,5,82,142,0,0,0,0, - 197,0,0,17,255,255,20,37,255,255,194,38, - 2,0,87,44,2,0,30,36,33,128,160,2, - 42,16,112,2,73,0,64,20,0,0,0,0, - 42,0,224,18,5,0,2,36,13,0,2,22, - 0,0,0,0,25,0,64,26,33,136,0,0, - 224,132,130,143,0,0,0,0,33,16,81,0, - 0,0,81,160,1,0,49,38,42,16,50,2, - 249,255,64,20,33,48,64,2,105,34,192,8, - 0,0,0,0,2,131,3,60,33,24,112,0, - 80,155,99,144,0,0,0,0,9,0,64,26, - 33,136,0,0,224,132,130,143,0,0,0,0, - 33,16,81,0,1,0,49,38,0,0,67,160, - 42,16,50,2,249,255,64,20,0,0,0,0, - 33,48,64,2,0,163,4,60,232,5,132,140, - 224,132,133,143,0,0,0,0,28,33,192,12, - 1,0,7,36,76,33,192,12,0,0,0,0, - 83,33,192,12,0,0,0,0,147,0,64,20, - 0,0,0,0,3,0,192,18,33,48,64,2, - 22,0,222,22,0,0,0,0,0,163,4,60, - 232,5,132,140,228,132,133,143,0,0,0,0, - 28,33,192,12,33,56,0,0,76,33,192,12, - 0,0,0,0,83,33,192,12,0,0,0,0, - 131,0,64,20,0,0,0,0,8,0,222,22, - 0,0,0,0,224,132,132,143,228,132,133,143, - 0,0,0,0,129,33,192,12,33,48,64,2, - 122,0,64,20,0,0,0,0,1,0,16,38, - 42,16,112,2,185,255,64,16,0,0,0,0, - 255,255,148,38,255,255,2,36,178,255,130,22, - 33,128,160,2,7,35,192,8,0,0,0,0, - 180,10,192,12,0,0,0,0,34,11,192,12, - 1,0,4,36,0,0,34,130,0,0,0,0, - 6,0,64,16,33,184,0,0,24,0,160,175, - 2,131,1,60,88,155,52,164,171,34,192,8, - 33,176,0,0,6,0,23,36,4,0,2,36, - 24,0,160,175,2,131,1,60,88,155,34,164, - 33,176,0,0,0,8,30,36,24,0,177,143, - 0,0,0,0,42,16,241,2,83,0,64,20, - 64,16,17,0,2,131,8,60,88,155,8,37, - 33,168,72,0,0,0,178,150,0,0,0,0, - 26,0,210,3,2,0,64,22,0,0,0,0, - 13,0,7,0,255,255,1,36,4,0,65,22, - 0,128,1,60,2,0,193,23,0,0,0,0, - 13,0,6,0,18,16,0,0,16,0,168,143, - 0,0,0,0,24,0,72,0,33,56,192,2, - 33,128,0,0,0,163,19,60,4,1,115,142, - 0,163,4,60,232,5,132,140,224,132,133,143, - 18,160,0,0,0,0,0,0,0,0,0,0, - 28,33,192,12,33,48,64,2,10,0,128,26, - 0,0,0,0,76,33,192,12,0,0,0,0, - 83,33,192,12,0,0,0,0,48,0,64,20, - 1,0,16,38,42,16,20,2,248,255,64,20, - 0,0,0,0,2,131,5,60,140,145,165,36, - 0,163,16,60,4,1,16,142,3,0,192,18, - 0,0,0,0,2,131,5,60,128,145,165,36, - 2,131,4,60,96,145,132,36,15,63,192,12, - 33,48,64,2,19,0,19,18,24,0,146,2, - 18,24,0,0,35,16,19,2,0,0,0,0, - 27,0,98,0,2,0,64,20,0,0,0,0, - 13,0,7,0,18,16,0,0,2,131,4,60, - 152,145,132,36,64,41,2,0,35,40,162,0, - 128,40,5,0,33,40,162,0,15,63,192,12, - 192,40,5,0,255,34,192,8,2,0,181,38, - 2,131,4,60,168,145,132,36,15,63,192,12, - 2,0,181,38,1,0,49,38,42,16,241,2, - 178,255,64,16,0,0,0,0,1,0,214,38, - 2,0,194,42,166,255,64,20,0,0,0,0, - 100,0,191,143,96,0,190,143,92,0,183,143, - 88,0,182,143,84,0,181,143,80,0,180,143, - 76,0,179,143,72,0,178,143,68,0,177,143, - 64,0,176,143,8,0,224,3,104,0,189,39, - 0,0,0,0,43,16,134,0,0,0,164,175, - 4,0,165,175,8,0,166,175,7,0,64,20, - 12,0,167,175,43,16,196,0,5,0,64,20, - 1,0,2,36,43,16,167,0,2,0,64,16, - 43,16,229,0,255,255,2,36,8,0,224,3, - 0,0,0,0,232,255,189,39,3,131,4,60, - 208,12,132,36,170,0,5,36,16,0,191,175, - 144,71,192,12,60,0,6,36,2,131,6,60, - 112,155,198,36,2,131,2,60,212,246,66,140, - 2,131,3,60,216,246,99,132,0,0,194,172, - 4,0,195,164,2,131,2,60,138,155,66,148, - 2,131,3,60,132,155,99,148,2,131,4,60, - 134,155,132,148,2,131,5,60,136,155,165,148, - 3,131,1,60,216,12,34,164,2,131,2,60, - 130,155,66,148,3,131,10,60,218,12,74,37, - 3,0,199,136,0,0,199,152,4,0,200,128, - 5,0,201,128,3,0,71,169,0,0,71,185, - 4,0,72,161,5,0,73,161,3,131,1,60, - 238,12,35,164,3,131,1,60,242,12,36,164, - 3,131,1,60,246,12,37,164,3,131,1,60, - 240,12,34,164,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,3,131,2,60, - 216,12,66,140,3,131,3,60,220,12,99,140, - 3,131,1,60,208,12,34,172,3,131,1,60, - 212,12,35,172,3,131,2,60,238,12,66,148, - 3,131,3,60,240,12,99,148,3,131,4,60, - 242,12,132,148,232,255,189,39,16,0,176,175, - 3,131,1,60,234,12,35,164,24,133,131,143, - 20,0,191,175,3,131,1,60,224,12,32,172, - 3,131,1,60,228,12,32,172,3,131,1,60, - 248,12,32,172,3,131,1,60,252,12,32,172, - 3,131,1,60,8,13,32,164,3,131,1,60, - 4,13,32,164,3,131,1,60,232,12,34,164, - 33,16,68,0,3,131,1,60,236,12,36,164, - 3,131,1,60,244,12,34,164,8,0,96,24, - 1,0,16,36,150,35,192,12,33,32,0,2, - 24,133,130,143,1,0,16,38,42,16,80,0, - 250,255,64,16,0,0,0,0,206,35,192,12, - 0,0,0,0,52,36,192,12,0,0,0,0, - 1,0,2,36,3,131,1,60,0,13,34,164, - 3,0,2,36,3,131,1,60,2,13,32,164, - 3,131,1,60,20,13,34,172,2,131,1,60, - 164,247,34,172,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,224,255,189,39, - 20,0,177,175,33,136,128,0,16,0,176,175, - 192,129,17,0,3,131,4,60,16,13,132,36, - 33,32,4,2,187,0,5,36,24,0,191,175, - 144,71,192,12,128,0,6,36,2,131,2,60, - 140,155,66,148,100,0,3,36,3,131,1,60, - 33,8,48,0,24,13,35,172,0,18,2,0, - 37,16,34,2,3,131,1,60,33,8,48,0, - 16,13,34,164,22,36,192,12,33,32,32,2, - 4,0,2,36,64,138,17,0,3,131,1,60, - 33,8,48,0,20,13,34,172,2,131,1,60, - 33,8,49,0,164,247,34,172,3,131,1,60, - 33,8,48,0,52,13,32,172,3,131,1,60, - 33,8,48,0,56,13,32,172,3,131,1,60, - 33,8,48,0,106,13,32,164,3,131,1,60, - 33,8,48,0,110,13,32,164,3,131,1,60, - 33,8,48,0,114,13,32,164,3,131,1,60, - 33,8,48,0,120,13,32,172,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,24,133,130,143,216,255,189,39, - 20,0,177,175,1,0,17,36,36,0,191,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 55,0,64,24,16,0,176,175,3,131,20,60, - 228,12,148,38,3,131,2,60,56,13,66,36, - 128,0,83,36,124,0,82,36,128,0,16,36, - 0,0,130,142,0,0,0,0,6,0,34,22, - 33,32,32,2,0,0,64,174,101,36,192,12, - 0,0,96,174,8,36,192,8,128,0,115,38, - 3,131,4,60,33,32,144,0,40,13,132,140, - 3,131,5,60,33,40,176,0,44,13,165,140, - 244,255,134,142,248,255,135,142,20,35,192,12, - 0,0,0,0,17,0,64,20,33,32,32,2, - 3,131,3,60,33,24,112,0,48,13,99,148, - 3,131,2,60,33,16,80,0,16,13,66,148, - 0,0,0,0,8,0,98,20,0,0,0,0, - 3,131,1,60,33,8,48,0,106,13,32,164, - 101,36,192,12,33,32,32,2,8,36,192,8, - 128,0,115,38,0,0,64,174,125,36,192,12, - 0,0,96,174,128,0,115,38,128,0,82,38, - 24,133,130,143,1,0,49,38,42,16,81,0, - 210,255,64,16,128,0,16,38,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,192,33,4,0,3,131,2,60, - 28,13,66,36,33,24,130,0,3,131,5,60, - 208,12,165,140,3,131,6,60,212,12,198,140, - 0,0,101,172,4,0,102,172,12,0,66,36, - 3,131,3,60,224,12,99,140,33,16,130,0, - 3,131,1,60,33,8,36,0,36,13,35,172, - 3,131,3,60,216,12,99,140,3,131,5,60, - 220,12,165,140,0,0,67,172,4,0,69,172, - 3,131,2,60,33,16,68,0,16,13,66,148, - 3,131,1,60,33,8,36,0,8,0,224,3, - 48,13,34,164,24,133,130,143,224,255,189,39, - 20,0,177,175,1,0,17,36,24,0,191,175, - 38,0,64,24,16,0,176,175,128,0,16,36, - 3,131,4,60,33,32,144,0,40,13,132,140, - 3,131,5,60,33,40,176,0,44,13,165,140, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,20,35,192,12,0,0,0,0, - 18,0,64,20,0,0,0,0,3,131,3,60, - 33,24,112,0,48,13,99,148,3,131,2,60, - 33,16,80,0,16,13,66,148,0,0,0,0, - 9,0,98,20,0,0,0,0,3,131,2,60, - 33,16,80,0,20,13,66,140,0,0,0,0, - 3,0,64,16,0,0,0,0,203,36,192,12, - 33,32,32,2,24,133,130,143,1,0,49,38, - 42,16,81,0,221,255,64,16,128,0,16,38, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,192,41,4,0, - 3,131,3,60,33,24,101,0,20,13,99,140, - 4,0,2,36,16,0,98,20,240,255,189,39, - 1,0,2,36,64,26,4,0,3,131,1,60, - 33,8,37,0,20,13,34,172,2,131,1,60, - 33,8,35,0,164,247,34,172,1,0,2,36, - 3,131,1,60,33,8,37,0,110,13,34,164, - 3,131,1,60,33,8,37,0,112,13,32,164, - 8,0,224,3,16,0,189,39,224,255,189,39, - 24,0,178,175,33,144,128,0,16,0,176,175, - 192,129,18,0,28,0,191,175,20,0,177,175, - 3,131,2,60,33,16,80,0,20,13,66,140, - 0,0,0,0,18,0,64,16,4,0,17,36, - 16,0,81,16,254,255,66,36,2,0,66,44, - 4,0,64,16,64,18,18,0,161,36,192,12, - 0,0,0,0,64,18,18,0,3,131,1,60, - 33,8,48,0,20,13,49,172,2,131,1,60, - 33,8,34,0,164,247,49,172,3,131,1,60, - 33,8,48,0,110,13,32,164,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,3,131,4,60, - 208,12,132,140,3,131,5,60,212,12,165,140, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,232,255,189,39,16,0,191,175, - 20,35,192,12,0,0,0,0,10,0,64,20, - 1,0,2,36,3,131,1,60,252,12,34,172, - 1,0,2,36,3,131,1,60,4,13,34,164, - 3,131,1,60,6,13,32,164,197,36,192,8, - 1,0,2,36,3,131,2,60,248,12,66,140, - 0,0,0,0,9,0,64,20,1,0,2,36, - 72,37,192,12,0,0,0,0,1,0,2,36, - 3,131,1,60,8,13,34,164,3,131,1,60, - 10,13,32,164,1,0,2,36,3,131,1,60, - 248,12,34,172,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,224,255,189,39, - 20,0,177,175,33,136,128,0,16,0,176,175, - 192,129,17,0,24,0,191,175,3,131,2,60, - 33,16,80,0,114,13,66,132,0,0,0,0, - 5,0,64,16,1,0,2,36,3,131,1,60, - 33,8,48,0,67,37,192,8,56,13,34,172, - 3,131,4,60,208,12,132,36,3,131,2,60, - 64,13,66,36,33,24,2,2,3,131,1,60, - 33,8,48,0,60,13,32,164,0,0,133,140, - 4,0,134,140,0,0,101,172,4,0,102,172, - 12,0,66,36,3,131,3,60,224,12,99,140, - 33,16,2,2,3,131,1,60,33,8,48,0, - 72,13,35,172,3,131,3,60,216,12,99,140, - 3,131,5,60,220,12,165,140,0,0,67,172, - 4,0,69,172,3,131,2,60,33,16,80,0, - 16,13,66,148,3,131,1,60,33,8,48,0, - 84,13,34,164,0,0,132,140,3,131,5,60, - 212,12,165,140,3,131,6,60,216,12,198,140, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,5,0,64,20,0,0,0,0, - 3,131,1,60,33,8,48,0,22,37,192,8, - 86,13,32,164,3,131,2,60,228,12,66,140, - 2,131,3,60,128,155,99,148,192,17,2,0, - 3,131,1,60,33,8,34,0,108,13,34,148, - 0,0,0,0,33,16,67,0,3,131,1,60, - 33,8,48,0,86,13,34,164,3,131,2,60, - 232,12,66,148,192,129,17,0,3,131,1,60, - 33,8,48,0,88,13,34,164,3,131,2,60, - 234,12,66,148,33,32,32,2,3,131,1,60, - 33,8,48,0,90,13,34,164,3,131,3,60, - 236,12,99,148,3,131,2,60,33,16,80,0, - 52,13,66,140,3,131,5,60,60,13,165,36, - 3,131,1,60,33,8,48,0,52,13,32,172, - 3,131,1,60,33,8,48,0,96,13,34,172, - 3,131,1,60,33,8,48,0,92,13,35,164, - 3,131,2,60,252,12,66,140,3,131,1,60, - 33,8,48,0,100,13,34,172,80,40,192,12, - 33,40,5,2,1,0,2,36,3,131,1,60, - 33,8,48,0,56,13,32,172,3,131,1,60, - 33,8,48,0,114,13,34,164,3,131,1,60, - 33,8,48,0,116,13,32,164,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,128,0,2,36, - 3,131,4,60,228,12,132,140,3,131,5,60, - 104,13,165,36,16,0,191,175,192,25,4,0, - 3,131,1,60,33,8,35,0,104,13,34,164, - 151,40,192,12,33,40,101,0,2,131,4,60, - 15,63,192,12,12,146,132,36,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,102,37,192,12, - 0,0,0,0,13,38,192,12,0,0,0,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,24,133,130,143,208,255,189,39, - 24,0,178,175,33,144,0,0,28,0,179,175, - 1,0,19,36,44,0,191,175,40,0,182,175, - 36,0,181,175,32,0,180,175,20,0,177,175, - 110,0,64,24,16,0,176,175,3,131,21,60, - 216,12,181,38,3,131,22,60,16,13,214,38, - 128,0,208,38,128,0,20,36,192,17,18,0, - 3,131,4,60,33,32,148,0,40,13,132,140, - 3,131,5,60,33,40,180,0,44,13,165,140, - 0,0,166,142,3,131,7,60,220,12,231,140, - 0,0,0,0,20,35,192,12,33,136,86,0, - 10,0,64,20,0,0,0,0,3,131,3,60, - 33,24,116,0,48,13,99,148,3,131,2,60, - 33,16,84,0,16,13,66,148,0,0,0,0, - 74,0,98,16,0,0,0,0,4,0,2,142, - 0,0,0,0,70,0,64,16,0,0,0,0, - 12,0,4,142,16,0,5,142,0,0,166,142, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,61,0,65,4,0,0,0,0, - 58,0,64,18,0,0,0,0,12,0,4,142, - 16,0,5,142,12,0,38,142,16,0,39,142, - 20,35,192,12,0,0,0,0,50,0,64,4, - 0,0,0,0,12,0,4,142,16,0,5,142, - 12,0,38,142,16,0,39,142,20,35,192,12, - 0,0,0,0,43,0,64,20,0,0,0,0, - 20,0,5,142,8,0,3,142,20,0,36,142, - 8,0,34,142,33,40,163,0,33,32,130,0, - 43,16,164,0,33,0,64,20,0,0,0,0, - 32,0,164,20,0,0,0,0,24,0,4,142, - 28,0,5,142,24,0,38,142,28,0,39,142, - 20,35,192,12,0,0,0,0,23,0,64,4, - 0,0,0,0,24,0,4,142,28,0,5,142, - 24,0,38,142,28,0,39,142,20,35,192,12, - 0,0,0,0,16,0,64,20,0,0,0,0, - 32,0,4,150,32,0,35,150,0,0,0,0, - 43,16,131,0,9,0,64,20,0,0,0,0, - 8,0,131,20,0,0,0,0,0,0,2,150, - 0,0,35,150,0,0,0,0,43,16,67,0, - 2,0,64,16,0,0,0,0,33,144,96,2, - 128,0,16,38,24,133,130,143,1,0,115,38, - 42,16,83,0,154,255,64,16,128,0,148,38, - 3,131,1,60,228,12,50,172,12,0,64,22, - 192,17,18,0,3,131,2,60,216,12,66,140, - 3,131,3,60,220,12,99,140,3,131,1,60, - 208,12,34,172,3,131,1,60,212,12,35,172, - 3,131,1,60,3,38,192,8,224,12,32,172, - 3,131,3,60,33,24,98,0,28,13,99,140, - 3,131,4,60,33,32,130,0,32,13,132,140, - 3,131,1,60,208,12,35,172,3,131,1,60, - 212,12,36,172,3,131,3,60,33,24,98,0, - 36,13,99,140,3,131,1,60,33,8,34,0, - 24,13,34,140,0,0,0,0,33,24,98,0, - 3,131,1,60,224,12,35,172,44,0,191,143, - 40,0,182,143,36,0,181,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,48,0,189,39, - 24,133,130,143,208,255,189,39,36,0,181,175, - 1,0,21,36,44,0,191,175,40,0,182,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 20,0,177,175,82,0,64,24,16,0,176,175, - 3,131,22,60,216,12,214,38,3,131,2,60, - 48,13,66,36,128,0,84,36,96,0,83,36, - 124,0,82,36,120,0,81,36,128,0,16,36, - 0,0,36,142,0,0,69,142,0,0,198,142, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,55,0,64,20,0,0,0,0, - 0,0,131,150,0,0,98,150,0,0,0,0, - 50,0,98,20,0,0,0,0,3,131,4,60, - 33,32,144,0,28,13,132,140,3,131,5,60, - 33,40,176,0,32,13,165,140,248,255,198,142, - 3,131,7,60,212,12,231,140,20,35,192,12, - 0,0,0,0,37,0,64,16,0,0,0,0, - 8,0,196,142,3,131,3,60,33,24,112,0, - 36,13,99,140,0,0,0,0,43,16,131,0, - 29,0,64,20,0,0,0,0,27,0,131,20, - 0,0,0,0,0,0,196,142,3,131,5,60, - 220,12,165,140,0,0,38,142,0,0,71,142, - 20,35,192,12,0,0,0,0,16,0,64,4, - 0,0,0,0,0,0,196,142,3,131,5,60, - 220,12,165,140,0,0,38,142,0,0,71,142, - 20,35,192,12,0,0,0,0,9,0,64,20, - 0,0,0,0,0,0,99,150,0,0,130,150, - 0,0,0,0,43,16,67,0,3,0,64,20, - 0,0,0,0,22,36,192,12,33,32,160,2, - 128,0,148,38,128,0,115,38,128,0,82,38, - 128,0,49,38,24,133,130,143,1,0,181,38, - 42,16,85,0,185,255,64,16,128,0,16,38, - 44,0,191,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 48,0,189,39,216,255,189,39,3,131,4,60, - 0,13,132,36,32,0,191,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 0,0,130,132,0,0,0,0,14,0,64,16, - 0,0,0,0,3,131,2,60,2,13,66,148, - 3,131,3,60,234,12,99,148,1,0,66,36, - 3,131,1,60,2,13,34,164,255,255,66,48, - 43,16,67,0,3,0,64,20,0,0,0,0, - 11,39,192,12,0,0,128,164,3,131,4,60, - 8,13,132,36,0,0,130,132,0,0,0,0, - 14,0,64,16,0,0,0,0,3,131,2,60, - 10,13,66,148,3,131,3,60,234,12,99,148, - 1,0,66,36,3,131,1,60,10,13,34,164, - 255,255,66,48,43,16,67,0,3,0,64,20, - 0,0,0,0,24,39,192,12,0,0,128,164, - 3,131,4,60,4,13,132,36,0,0,130,132, - 0,0,0,0,14,0,64,16,0,0,0,0, - 3,131,2,60,6,13,66,148,3,131,3,60, - 244,12,99,148,1,0,66,36,3,131,1,60, - 6,13,34,164,255,255,66,48,43,16,67,0, - 3,0,64,20,0,0,0,0,37,39,192,12, - 0,0,128,164,24,133,130,143,0,0,0,0, - 78,0,64,24,1,0,17,36,3,131,2,60, - 16,13,66,36,226,0,83,36,128,0,82,36, - 128,0,16,36,3,131,2,60,33,16,80,0, - 110,13,66,132,0,0,0,0,18,0,64,16, - 0,0,0,0,3,131,2,60,33,16,80,0, - 112,13,66,148,0,0,0,0,1,0,66,36, - 96,0,66,166,3,131,3,60,236,12,99,148, - 255,255,66,48,43,16,67,0,6,0,64,20, - 0,0,0,0,3,131,1,60,33,8,48,0, - 110,13,32,164,79,39,192,12,33,32,32,2, - 3,131,2,60,33,16,80,0,106,13,66,132, - 0,0,0,0,18,0,64,16,0,0,0,0, - 3,131,2,60,33,16,80,0,108,13,66,148, - 0,0,0,0,1,0,66,36,92,0,66,166, - 3,131,3,60,232,12,99,148,255,255,66,48, - 43,16,67,0,6,0,64,20,0,0,0,0, - 3,131,1,60,33,8,48,0,106,13,32,164, - 129,39,192,12,33,32,32,2,0,0,98,134, - 0,0,0,0,16,0,64,16,0,0,0,0, - 3,131,2,60,33,16,80,0,116,13,66,148, - 0,0,0,0,1,0,66,36,100,0,66,166, - 3,131,3,60,246,12,99,148,255,255,66,48, - 43,16,67,0,4,0,64,20,0,0,0,0, - 0,0,96,166,191,39,192,12,33,32,32,2, - 128,0,115,38,128,0,82,38,24,133,130,143, - 1,0,49,38,42,16,81,0,185,255,64,16, - 128,0,16,38,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,232,255,189,39, - 16,0,191,175,52,36,192,12,0,0,0,0, - 1,0,2,36,3,131,1,60,0,13,34,164, - 3,131,1,60,2,13,32,164,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,72,37,192,12, - 0,0,0,0,1,0,2,36,3,131,1,60, - 8,13,34,164,3,131,1,60,10,13,32,164, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,240,255,189,39,3,131,1,60, - 248,12,32,172,3,131,1,60,252,12,32,172, - 8,0,224,3,16,0,189,39,24,133,130,143, - 224,255,189,39,20,0,177,175,1,0,17,36, - 24,0,191,175,23,0,64,24,16,0,176,175, - 128,0,16,36,3,131,4,60,33,32,144,0, - 40,13,132,140,3,131,5,60,33,40,176,0, - 44,13,165,140,3,131,6,60,216,12,198,140, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,3,0,64,20,1,0,49,38, - 74,39,192,8,1,0,2,36,24,133,130,143, - 0,0,0,0,42,16,81,0,236,255,64,16, - 128,0,16,38,33,16,0,0,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,192,41,4,0, - 16,0,191,175,3,131,3,60,33,24,101,0, - 20,13,99,140,1,0,2,36,16,0,98,20, - 2,0,2,36,64,26,4,0,3,131,1,60, - 33,8,37,0,20,13,34,172,2,131,1,60, - 33,8,35,0,164,247,34,172,1,0,2,36, - 3,131,1,60,33,8,37,0,110,13,34,164, - 3,131,1,60,33,8,37,0,125,39,192,8, - 112,13,32,164,21,0,98,20,3,0,3,36, - 64,18,4,0,3,131,1,60,33,8,37,0, - 20,13,35,172,2,131,1,60,33,8,34,0, - 164,247,35,172,3,131,2,60,33,16,69,0, - 120,13,66,140,0,0,0,0,1,0,66,36, - 3,131,1,60,33,8,37,0,44,39,192,12, - 120,13,34,172,3,0,64,16,0,0,0,0, - 161,36,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 224,255,189,39,16,0,176,175,33,128,128,0, - 20,0,177,175,3,131,17,60,208,12,49,38, - 24,0,191,175,0,0,36,142,3,131,5,60, - 212,12,165,140,3,131,6,60,216,12,198,140, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,33,32,0,2,22,36,192,12, - 1,0,80,44,92,37,192,12,0,0,0,0, - 206,35,192,12,0,0,0,0,33,0,0,22, - 0,0,0,0,0,0,36,142,3,131,5,60, - 212,12,165,140,3,131,6,60,216,12,198,140, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,22,0,64,20,0,0,0,0, - 3,131,2,60,238,12,66,148,3,131,3,60, - 240,12,99,148,3,131,4,60,242,12,132,148, - 3,131,1,60,232,12,34,164,3,131,1,60, - 234,12,35,164,3,131,1,60,161,36,192,12, - 236,12,36,164,3,131,1,60,52,36,192,12, - 8,13,32,164,1,0,2,36,3,131,1,60, - 0,13,34,164,3,131,1,60,2,13,32,164, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,232,255,189,39, - 192,17,4,0,16,0,191,175,3,131,1,60, - 33,8,34,0,56,13,34,140,0,0,0,0, - 3,0,64,16,0,0,0,0,203,36,192,12, - 0,0,0,0,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,3,131,1,60, - 248,12,32,172,3,131,1,60,8,0,224,3, - 8,13,32,164,232,255,189,39,192,25,4,0, - 1,0,2,36,16,0,191,175,3,131,1,60, - 33,8,35,0,203,36,192,12,52,13,34,172, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,192,33,4,0,3,131,2,60, - 28,13,66,36,33,24,130,0,4,0,166,140, - 8,0,167,140,0,0,102,172,4,0,103,172, - 12,0,66,36,12,0,163,140,33,16,130,0, - 3,131,1,60,33,8,36,0,36,13,35,172, - 16,0,163,140,20,0,166,140,0,0,67,172, - 4,0,70,172,24,0,163,148,1,0,2,36, - 3,131,1,60,33,8,36,0,106,13,34,164, - 3,131,1,60,33,8,36,0,48,13,35,164, - 26,0,162,148,3,131,1,60,33,8,36,0, - 8,0,224,3,108,13,34,164,28,0,130,148, - 3,131,1,60,232,12,34,164,30,0,130,148, - 3,131,1,60,234,12,34,164,32,0,130,148, - 3,131,1,60,236,12,34,164,40,0,130,140, - 3,131,1,60,8,0,224,3,252,12,34,172, - 224,255,189,39,16,0,176,175,33,128,160,0, - 192,25,4,0,3,131,2,60,16,13,66,36, - 20,0,177,175,33,136,98,0,24,0,191,175, - 4,0,4,142,8,0,5,142,12,0,38,142, - 16,0,39,142,20,35,192,12,0,0,0,0, - 48,0,64,4,1,0,2,36,4,0,4,142, - 8,0,5,142,12,0,38,142,16,0,39,142, - 20,35,192,12,0,0,0,0,40,0,64,20, - 33,16,0,0,12,0,4,142,20,0,35,142, - 0,0,0,0,43,16,131,0,34,0,64,20, - 1,0,2,36,32,0,131,20,33,16,0,0, - 16,0,4,142,20,0,5,142,24,0,38,142, - 28,0,39,142,20,35,192,12,0,0,0,0, - 24,0,64,4,1,0,2,36,16,0,4,142, - 20,0,5,142,24,0,38,142,28,0,39,142, - 20,35,192,12,0,0,0,0,16,0,64,20, - 33,16,0,0,16,0,4,142,20,0,5,142, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,20,35,192,12,0,0,0,0, - 6,0,64,20,1,0,2,36,24,0,3,150, - 32,0,34,150,0,0,0,0,43,16,67,0, - 1,0,66,56,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 44,133,130,143,216,255,189,39,20,0,177,175, - 33,136,128,0,32,0,180,175,33,160,160,0, - 36,0,191,175,28,0,179,175,24,0,178,175, - 53,0,64,16,16,0,176,175,2,131,19,60, - 192,4,115,38,33,32,96,2,54,21,192,12, - 1,0,5,36,33,128,64,0,8,0,0,22, - 64,26,17,0,2,131,2,60,33,16,67,0, - 176,247,66,140,33,24,99,2,1,0,66,36, - 143,40,192,8,240,242,98,172,8,0,4,142, - 64,146,17,0,20,242,101,38,33,40,69,2, - 172,41,192,12,33,48,128,2,33,24,64,0, - 60,0,98,40,2,0,64,16,0,242,98,38, - 60,0,3,36,33,136,66,2,33,32,32,2, - 33,40,0,2,1,0,2,36,17,0,2,162, - 0,128,98,52,0,0,2,174,6,23,192,12, - 18,0,3,166,10,0,64,20,33,32,0,2, - 2,131,2,60,33,16,82,0,172,247,66,140, - 0,0,0,0,1,0,66,36,152,21,192,12, - 236,0,34,174,143,40,192,8,0,0,0,0, - 2,131,2,60,33,16,82,0,168,247,66,140, - 0,0,0,0,1,0,66,36,232,0,34,174, - 36,0,191,143,32,0,180,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,44,133,130,143, - 216,255,189,39,20,0,177,175,33,136,128,0, - 32,0,180,175,33,160,160,0,36,0,191,175, - 28,0,179,175,24,0,178,175,53,0,64,16, - 16,0,176,175,2,131,19,60,192,4,115,38, - 33,32,96,2,54,21,192,12,1,0,5,36, - 33,128,64,0,8,0,0,22,64,26,17,0, - 2,131,2,60,33,16,67,0,176,247,66,140, - 33,24,99,2,1,0,66,36,214,40,192,8, - 240,242,98,172,8,0,4,142,64,146,17,0, - 20,242,101,38,33,40,69,2,74,42,192,12, - 33,48,128,2,33,24,64,0,60,0,98,40, - 2,0,64,16,0,242,98,38,60,0,3,36, - 33,136,66,2,33,32,32,2,33,40,0,2, - 1,0,2,36,17,0,2,162,0,128,98,52, - 0,0,2,174,6,23,192,12,18,0,3,166, - 10,0,64,20,33,32,0,2,2,131,2,60, - 33,16,82,0,172,247,66,140,0,0,0,0, - 1,0,66,36,152,21,192,12,236,0,34,174, - 214,40,192,8,0,0,0,0,2,131,2,60, - 33,16,82,0,168,247,66,140,0,0,0,0, - 1,0,66,36,232,0,34,174,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,216,255,189,39,24,0,178,175, - 33,144,128,0,20,0,177,175,33,136,160,0, - 16,0,176,175,33,128,192,0,36,0,191,175, - 32,0,180,175,28,0,179,175,4,0,36,142, - 8,0,37,142,160,133,134,143,2,131,7,60, - 180,211,231,140,20,35,192,12,0,0,0,0, - 11,0,64,20,0,0,0,0,2,131,4,60, - 144,146,132,36,15,63,192,12,33,40,0,2, - 100,129,132,39,108,129,134,39,31,21,192,12, - 6,0,5,38,92,41,192,8,0,0,0,0, - 3,131,20,60,208,12,148,38,0,0,132,142, - 3,131,5,60,212,12,165,140,3,131,6,60, - 216,12,198,140,3,131,7,60,220,12,231,140, - 0,0,0,0,20,35,192,12,192,129,18,0, - 3,131,3,60,33,24,112,0,20,13,99,140, - 0,0,0,0,80,0,96,16,1,0,83,44, - 33,32,64,2,11,40,192,12,33,40,32,2, - 50,0,64,16,33,32,64,2,223,39,192,12, - 33,40,32,2,92,37,192,12,0,0,0,0, - 206,35,192,12,0,0,0,0,0,0,132,142, - 3,131,5,60,212,12,165,140,3,131,6,60, - 216,12,198,140,3,131,7,60,220,12,231,140, - 20,35,192,12,0,0,0,0,16,0,64,16, - 0,0,0,0,14,0,96,18,0,0,0,0, - 3,131,2,60,248,12,66,140,3,131,1,60, - 9,0,64,16,0,13,32,164,3,131,1,60, - 72,37,192,12,4,13,32,164,1,0,2,36, - 3,131,1,60,8,13,34,164,3,131,1,60, - 10,13,32,164,3,131,2,60,228,12,66,140, - 0,0,0,0,38,0,66,22,0,0,0,0, - 254,39,192,12,33,32,32,2,52,36,192,12, - 0,0,0,0,36,0,34,142,0,0,0,0, - 30,0,64,16,0,0,0,0,206,39,192,12, - 0,0,0,0,92,41,192,8,0,0,0,0, - 3,131,4,60,33,32,144,0,40,13,132,140, - 3,131,5,60,33,40,176,0,44,13,165,140, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,20,35,192,12,0,0,0,0, - 12,0,64,20,0,0,0,0,3,131,3,60, - 33,24,112,0,48,13,99,148,3,131,2,60, - 33,16,80,0,16,13,66,148,0,0,0,0, - 3,0,98,20,0,0,0,0,203,36,192,12, - 33,32,64,2,36,0,191,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 224,255,189,39,20,0,177,175,33,136,128,0, - 16,0,176,175,192,129,17,0,24,0,191,175, - 3,131,2,60,33,16,80,0,20,13,66,140, - 0,0,0,0,28,0,64,16,0,0,0,0, - 3,131,4,60,33,32,144,0,40,13,132,140, - 3,131,5,60,33,40,176,0,44,13,165,140, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,20,35,192,12,0,0,0,0, - 14,0,64,20,0,0,0,0,3,131,3,60, - 33,24,112,0,48,13,99,148,3,131,2,60, - 33,16,80,0,16,13,66,148,0,0,0,0, - 5,0,98,20,0,0,0,0,161,36,192,12, - 0,0,0,0,211,39,192,12,33,32,32,2, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,2,18,5,0, - 0,0,130,160,8,0,224,3,1,0,133,160, - 2,22,5,0,0,0,130,160,2,20,5,0, - 1,0,130,160,2,18,5,0,2,0,130,160, - 8,0,224,3,3,0,133,160,0,0,130,144, - 1,0,131,144,0,18,2,0,8,0,224,3, - 37,16,98,0,0,0,130,144,1,0,131,144, - 2,0,133,144,0,22,2,0,0,28,3,0, - 33,16,67,0,0,42,5,0,3,0,131,144, - 33,16,69,0,8,0,224,3,37,16,67,0, - 224,255,189,39,16,0,176,175,33,128,128,0, - 24,0,191,175,20,0,177,175,48,129,135,39, - 3,0,226,136,0,0,226,152,4,0,227,128, - 5,0,228,128,3,0,2,170,0,0,2,186, - 4,0,3,162,5,0,4,162,3,0,162,136, - 0,0,162,152,4,0,163,128,5,0,164,128, - 9,0,2,170,6,0,2,186,10,0,3,162, - 11,0,4,162,12,0,4,38,38,0,5,36, - 144,41,192,12,33,136,192,0,14,0,4,38, - 144,41,192,12,66,66,5,36,17,0,4,38, - 33,40,0,0,3,0,2,36,144,41,192,12, - 16,0,2,162,19,0,0,162,20,0,0,162, - 40,0,34,142,0,0,0,0,43,32,2,0, - 36,0,34,142,0,0,0,0,3,0,64,16, - 33,24,128,0,218,41,192,8,128,0,130,52, - 33,16,96,0,21,0,2,162,4,0,37,150, - 0,0,0,0,144,41,192,12,22,0,4,38, - 9,0,34,138,6,0,34,154,10,0,35,130, - 11,0,36,130,27,0,2,170,24,0,2,186, - 28,0,3,162,29,0,4,162,12,0,37,142, - 0,0,0,0,148,41,192,12,30,0,4,38, - 16,0,37,150,0,0,0,0,144,41,192,12, - 34,0,4,38,21,0,34,138,18,0,34,154, - 22,0,35,130,23,0,36,130,39,0,2,170, - 36,0,2,186,40,0,3,162,41,0,4,162, - 24,0,37,150,0,0,0,0,144,41,192,12, - 42,0,4,38,26,0,37,150,0,0,0,0, - 144,41,192,12,44,0,4,38,28,0,37,150, - 0,0,0,0,144,41,192,12,46,0,4,38, - 30,0,37,150,0,0,0,0,144,41,192,12, - 48,0,4,38,32,0,37,150,0,0,0,0, - 144,41,192,12,50,0,4,38,52,0,2,36, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,224,255,189,39, - 16,0,176,175,33,128,160,0,24,0,191,175, - 20,0,177,175,21,0,2,146,33,136,128,0, - 1,0,66,48,40,0,34,174,22,0,2,146, - 22,0,4,38,128,0,66,48,156,41,192,12, - 36,0,34,174,4,0,34,166,27,0,2,138, - 24,0,2,154,28,0,3,130,29,0,4,130, - 9,0,34,170,6,0,34,186,10,0,35,162, - 11,0,36,162,161,41,192,12,30,0,4,38, - 34,0,4,38,156,41,192,12,12,0,34,174, - 16,0,34,166,39,0,2,138,36,0,2,154, - 40,0,3,130,41,0,4,130,21,0,34,170, - 18,0,34,186,22,0,35,162,23,0,36,162, - 156,41,192,12,42,0,4,38,44,0,4,38, - 156,41,192,12,24,0,34,166,46,0,4,38, - 156,41,192,12,26,0,34,166,48,0,4,38, - 156,41,192,12,28,0,34,166,50,0,4,38, - 156,41,192,12,30,0,34,166,32,0,34,166, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,232,255,189,39, - 16,0,176,175,33,128,128,0,20,0,191,175, - 48,129,134,39,3,0,194,136,0,0,194,152, - 4,0,195,128,5,0,196,128,3,0,2,170, - 0,0,2,186,4,0,3,162,5,0,4,162, - 3,0,162,136,0,0,162,152,4,0,163,128, - 5,0,164,128,9,0,2,170,6,0,2,186, - 10,0,3,162,11,0,4,162,12,0,4,38, - 144,41,192,12,7,0,5,36,14,0,4,38, - 144,41,192,12,66,66,5,36,17,0,4,38, - 33,40,0,0,3,0,2,36,144,41,192,12, - 16,0,2,162,21,0,2,36,128,0,3,36, - 19,0,0,162,20,0,3,162,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 176,255,189,39,68,0,177,175,64,0,176,175, - 33,128,160,0,72,0,191,175,14,0,3,146, - 66,0,2,36,9,0,98,20,33,136,128,0, - 15,0,2,146,0,0,0,0,6,0,67,20, - 64,26,17,0,16,0,3,146,3,0,2,36, - 11,0,98,16,0,0,0,0,64,26,17,0, - 2,131,2,60,33,16,67,0,184,247,66,140, - 0,0,0,0,1,0,66,36,2,131,1,60, - 33,8,35,0,182,42,192,8,184,247,34,172, - 20,0,3,146,0,0,0,0,5,0,96,16, - 128,0,2,36,21,0,98,16,64,26,17,0, - 179,42,192,8,0,0,0,0,16,0,164,39, - 64,26,17,0,2,131,2,60,33,16,67,0, - 180,247,66,140,0,0,0,0,1,0,66,36, - 2,131,1,60,33,8,35,0,180,247,34,172, - 17,42,192,12,33,40,0,2,33,32,32,2, - 16,0,165,39,222,40,192,12,33,48,0,2, - 182,42,192,8,0,0,0,0,2,131,2,60, - 33,16,67,0,180,247,66,140,0,0,0,0, - 1,0,66,36,2,131,1,60,33,8,35,0, - 180,247,34,172,100,41,192,12,33,32,32,2, - 182,42,192,8,0,0,0,0,112,129,132,39, - 15,63,192,12,0,0,0,0,72,0,191,143, - 68,0,177,143,64,0,176,143,8,0,224,3, - 80,0,189,39,8,0,224,3,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,162,48,8,0,64,16,255,255,198,48, - 67,40,5,0,64,16,5,0,33,16,68,0, - 0,0,66,144,0,0,0,0,203,42,192,8, - 33,48,194,0,67,40,5,0,255,255,165,36, - 255,255,2,36,6,0,162,16,255,255,3,36, - 0,0,130,148,2,0,132,36,255,255,165,36, - 252,255,163,20,33,48,194,0,255,255,195,48, - 2,20,6,0,33,48,98,0,255,255,195,48, - 2,20,6,0,33,48,98,0,8,0,224,3, - 255,255,194,48,208,255,189,39,16,0,176,175, - 33,128,128,0,28,0,179,175,33,152,160,0, - 24,0,178,175,33,144,192,0,36,0,181,175, - 33,168,0,2,32,0,180,175,33,160,0,0, - 40,0,191,175,20,0,177,175,12,0,3,142, - 0,0,2,142,0,0,0,0,35,24,98,0, - 42,16,114,0,2,0,64,16,33,136,64,2, - 33,136,96,0,13,0,32,18,33,40,96,2, - 35,144,81,2,8,0,2,142,0,0,4,142, - 33,48,32,2,80,68,192,12,33,32,68,0, - 8,0,2,142,0,0,2,142,0,0,2,142, - 33,152,113,2,33,16,81,0,0,0,2,174, - 0,0,2,142,0,0,0,0,4,0,64,18, - 33,160,130,2,4,0,16,142,233,42,192,8, - 0,0,0,0,18,0,180,166,33,16,0,2, - 40,0,191,143,36,0,181,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,48,0,189,39, - 224,255,189,39,24,0,178,175,33,144,128,0, - 2,131,4,60,192,4,132,36,36,0,165,175, - 1,0,5,36,28,0,191,175,20,0,177,175, - 54,21,192,12,16,0,176,175,33,136,64,0, - 8,0,32,22,33,40,0,0,2,131,2,60, - 176,5,66,140,0,0,0,0,1,0,66,36, - 2,131,1,60,102,43,192,8,176,5,34,172, - 0,1,3,36,8,0,48,142,8,0,2,36, - 16,0,2,166,6,0,2,36,18,0,2,162, - 4,0,2,36,14,0,3,166,19,0,2,162, - 20,0,3,166,2,131,6,60,212,4,198,36, - 3,0,194,136,0,0,194,152,4,0,195,132, - 25,0,2,170,22,0,2,186,26,0,3,166, - 2,131,1,60,195,211,34,136,176,133,130,155, - 0,0,0,0,31,0,2,170,28,0,2,186, - 32,0,4,38,144,71,192,12,6,0,6,36, - 39,0,162,139,36,0,162,155,0,0,0,0, - 41,0,2,170,38,0,2,186,132,129,133,39, - 3,0,162,136,0,0,162,152,4,0,163,128, - 5,0,164,128,3,0,2,170,0,0,2,186, - 4,0,3,162,5,0,4,162,2,131,5,60, - 212,4,165,36,3,0,162,136,0,0,162,152, - 4,0,163,128,5,0,164,128,9,0,2,170, - 6,0,2,186,10,0,3,162,11,0,4,162, - 33,32,64,2,8,6,2,36,12,0,2,166, - 60,128,2,52,0,0,34,174,60,0,2,36, - 18,0,34,166,74,21,192,12,33,40,32,2, - 3,0,64,20,0,0,0,0,152,21,192,12, - 33,32,32,2,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,216,255,189,39,32,0,180,175, - 33,160,128,0,16,0,176,175,33,128,160,0, - 36,0,191,175,28,0,179,175,24,0,178,175, - 20,0,177,175,8,0,2,142,33,152,192,0, - 33,136,83,0,6,0,35,150,0,1,4,36, - 5,0,100,16,0,2,2,36,113,0,98,16, - 0,0,0,0,15,44,192,8,0,0,0,0, - 24,0,35,150,176,133,130,151,0,0,0,0, - 139,0,98,20,0,0,0,0,26,0,35,150, - 2,131,2,60,194,211,66,148,0,0,0,0, - 133,0,98,20,0,0,0,0,0,0,34,150, - 0,0,0,0,129,0,68,20,8,0,2,36, - 2,0,35,150,0,0,0,0,125,0,98,20, - 6,4,2,36,4,0,35,150,0,0,0,0, - 121,0,98,20,0,0,0,0,2,131,4,60, - 192,4,132,36,54,21,192,12,1,0,5,36, - 33,144,64,0,8,0,64,22,0,0,0,0, - 2,131,2,60,176,5,66,140,0,0,0,0, - 1,0,66,36,2,131,1,60,15,44,192,8, - 176,5,34,172,8,0,5,142,8,0,80,142, - 9,0,162,136,6,0,162,152,10,0,163,128, - 11,0,164,128,3,0,2,170,0,0,2,186, - 4,0,3,162,5,0,4,162,2,131,6,60, - 212,4,198,36,3,0,194,136,0,0,194,152, - 4,0,195,128,5,0,196,128,9,0,2,170, - 6,0,2,186,10,0,3,162,11,0,4,162, - 12,0,4,38,12,0,165,36,33,128,19,2, - 80,68,192,12,244,255,102,38,0,1,2,36, - 0,0,2,166,8,0,2,36,2,0,2,166, - 6,0,2,36,4,0,2,162,4,0,2,36, - 5,0,2,162,0,2,2,36,6,0,2,166, - 2,131,5,60,212,4,165,36,3,0,162,136, - 0,0,162,152,4,0,163,132,11,0,2,170, - 8,0,2,186,12,0,3,166,2,131,1,60, - 195,211,34,136,176,133,130,155,0,0,0,0, - 17,0,2,170,14,0,2,186,11,0,34,138, - 8,0,34,154,12,0,35,134,21,0,2,170, - 18,0,2,186,22,0,3,166,17,0,34,138, - 14,0,34,154,0,0,0,0,27,0,2,170, - 24,0,2,186,33,32,128,2,33,40,64,2, - 60,128,2,52,0,0,66,174,60,0,2,36, - 74,21,192,12,18,0,66,166,38,0,64,20, - 0,0,0,0,152,21,192,12,33,32,64,2, - 15,44,192,8,0,0,0,0,14,0,35,150, - 196,133,130,151,0,0,0,0,29,0,98,20, - 0,0,0,0,16,0,35,150,2,131,2,60, - 214,211,66,148,0,0,0,0,23,0,98,20, - 0,0,0,0,0,0,34,150,0,0,0,0, - 19,0,68,20,8,0,2,36,2,0,35,150, - 0,0,0,0,15,0,98,20,6,4,2,36, - 4,0,35,150,0,0,0,0,11,0,98,20, - 0,0,0,0,68,133,130,143,140,129,134,39, - 11,0,35,138,8,0,35,154,12,0,36,134, - 3,0,195,168,0,0,195,184,4,0,196,164, - 20,0,66,36,152,129,130,175,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,192,255,189,39,80,0,169,143, - 84,0,168,143,56,0,180,175,33,160,128,0, - 44,0,177,175,88,0,177,143,16,0,164,39, - 52,0,179,175,92,0,179,143,3,131,3,60, - 32,17,99,36,40,0,176,175,33,128,192,0, - 60,0,191,175,48,0,178,175,0,0,98,140, - 8,0,50,142,1,0,66,36,0,0,98,172, - 3,0,162,136,0,0,162,152,4,0,163,128, - 5,0,170,128,3,0,66,170,0,0,66,186, - 4,0,67,162,5,0,74,162,2,131,10,60, - 212,4,74,37,3,0,66,137,0,0,66,153, - 4,0,67,129,5,0,69,129,9,0,66,170, - 6,0,66,186,10,0,67,162,11,0,69,162, - 69,0,2,36,16,0,162,163,17,0,168,163, - 18,0,34,150,240,132,131,143,33,48,0,0, - 25,0,169,163,20,0,66,36,0,66,2,0, - 255,255,66,48,2,18,2,0,37,64,2,1, - 0,74,3,0,255,255,98,48,2,18,2,0, - 37,72,34,1,3,131,2,60,0,17,66,140, - 22,0,160,167,26,0,160,167,18,0,168,167, - 176,133,136,143,1,0,99,36,240,132,131,175, - 20,0,169,167,24,0,162,163,28,0,168,175, - 3,0,226,136,0,0,226,152,0,0,0,0, - 35,0,162,171,32,0,162,187,192,42,192,12, - 20,0,5,36,39,16,2,0,26,0,162,167, - 14,0,2,36,44,0,2,22,8,0,2,36, - 12,0,66,166,19,0,162,139,16,0,162,155, - 23,0,163,139,20,0,163,155,27,0,164,139, - 24,0,164,155,31,0,165,139,28,0,165,155, - 17,0,66,170,14,0,66,186,21,0,67,170, - 18,0,67,186,25,0,68,170,22,0,68,186, - 29,0,69,170,26,0,69,186,35,0,162,139, - 32,0,162,155,0,0,0,0,33,0,66,170, - 30,0,66,186,34,0,2,36,0,0,34,174, - 0,0,35,142,18,0,34,150,0,0,0,0, - 33,16,67,0,18,0,34,166,18,0,34,150, - 0,0,0,0,60,0,66,44,68,0,64,16, - 33,32,128,2,0,0,98,142,18,0,35,150, - 60,0,66,36,35,16,67,0,0,0,98,174, - 60,0,2,36,18,0,34,166,201,44,192,8, - 33,32,128,2,164,129,133,39,3,0,162,136, - 0,0,162,152,4,0,163,128,5,0,164,128, - 17,0,66,170,14,0,66,186,18,0,67,162, - 19,0,68,162,8,0,2,36,20,0,66,166, - 19,0,162,139,16,0,162,155,23,0,163,139, - 20,0,163,155,27,0,164,139,24,0,164,155, - 31,0,165,139,28,0,165,155,25,0,66,170, - 22,0,66,186,29,0,67,170,26,0,67,186, - 33,0,68,170,30,0,68,186,37,0,69,170, - 34,0,69,186,35,0,162,139,32,0,162,155, - 0,0,0,0,41,0,66,170,38,0,66,186, - 42,0,2,36,0,0,34,174,0,0,35,142, - 18,0,34,150,0,0,0,0,33,16,67,0, - 18,0,34,166,18,0,34,150,0,0,0,0, - 60,0,66,44,8,0,64,16,0,0,0,0, - 0,0,98,142,18,0,35,150,60,0,66,36, - 35,16,67,0,0,0,98,174,60,0,2,36, - 18,0,34,166,18,0,34,150,0,0,0,0, - 0,26,2,0,2,18,2,0,37,24,98,0, - 12,0,67,166,33,32,128,2,74,21,192,12, - 33,40,32,2,8,0,64,20,33,32,32,2, - 3,131,3,60,36,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,152,21,192,12, - 0,0,98,172,60,0,191,143,56,0,180,143, - 52,0,179,143,48,0,178,143,44,0,177,143, - 40,0,176,143,8,0,224,3,64,0,189,39, - 176,255,189,39,56,0,180,175,112,0,180,143, - 48,0,178,175,100,0,178,143,52,0,179,175, - 104,0,179,143,64,0,182,175,33,176,128,0, - 72,0,190,175,33,240,160,0,60,0,181,175, - 33,168,224,0,68,0,183,175,108,0,183,143, - 2,131,4,60,192,4,132,36,76,0,191,175, - 44,0,177,175,40,0,176,175,32,0,166,175, - 7,2,130,38,2,130,2,0,54,21,192,12, - 33,40,0,2,33,136,64,0,8,0,32,22, - 0,74,18,0,2,131,4,60,232,146,132,36, - 33,40,128,2,15,63,192,12,33,48,0,2, - 74,45,192,8,0,0,0,0,255,255,66,50, - 2,18,2,0,37,72,34,1,0,66,19,0, - 255,255,98,50,2,18,2,0,37,64,2,1, - 8,0,130,38,0,58,2,0,255,255,66,48, - 2,18,2,0,37,56,226,0,0,163,4,60, - 220,5,132,52,4,0,5,36,4,0,34,142, - 0,17,6,36,8,0,80,140,4,0,35,142, - 8,0,2,36,0,0,98,172,0,0,9,166, - 2,0,8,166,6,0,0,166,192,42,192,12, - 4,0,7,166,33,32,160,2,4,0,5,36, - 192,42,192,12,255,255,70,48,4,0,4,38, - 2,0,5,36,192,42,192,12,255,255,70,48, - 33,32,0,2,8,0,5,36,192,42,192,12, - 255,255,70,48,33,32,224,2,33,40,128,2, - 192,42,192,12,255,255,70,48,39,24,2,0, - 255,255,98,48,2,0,64,20,33,40,224,2, - 255,255,3,52,6,0,3,166,4,0,36,142, - 0,0,0,0,220,42,192,12,33,48,128,2, - 33,32,192,2,0,0,67,140,33,40,192,3, - 0,128,99,52,0,0,67,172,4,0,35,142, - 32,0,166,143,18,0,99,148,33,56,160,2, - 18,0,35,166,96,0,170,143,17,0,3,36, - 16,0,163,175,24,0,177,175,28,0,162,175, - 23,44,192,12,20,0,170,175,3,131,3,60, - 124,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,76,0,191,143, - 72,0,190,143,68,0,183,143,64,0,182,143, - 60,0,181,143,56,0,180,143,52,0,179,143, - 48,0,178,143,44,0,177,143,40,0,176,143, - 8,0,224,3,80,0,189,39,128,255,189,39, - 116,0,183,175,33,184,128,0,112,0,182,175, - 33,176,160,0,104,0,180,175,33,160,192,0, - 108,0,181,175,33,168,224,0,40,0,164,39, - 96,0,178,175,144,0,178,143,33,40,0,0, - 100,0,179,175,148,0,179,143,16,0,6,36, - 120,0,191,175,92,0,177,175,144,71,192,12, - 88,0,176,175,56,0,177,39,33,32,32,2, - 33,40,0,0,2,0,16,36,40,0,176,167, - 2,0,162,150,0,0,0,0,42,0,162,167, - 19,0,130,138,16,0,130,154,0,0,0,0, - 47,0,162,171,44,0,162,187,144,71,192,12, - 16,0,6,36,33,32,64,2,33,40,96,2, - 40,0,166,39,33,56,32,2,56,0,176,167, - 0,0,162,150,2,131,16,60,8,239,16,38, - 58,0,162,167,15,0,130,138,12,0,130,154, - 0,0,0,0,63,0,162,171,60,0,162,187, - 242,5,2,36,84,0,162,167,72,0,162,39, - 72,0,160,167,76,0,176,175,80,0,176,175, - 247,71,192,12,16,0,162,175,255,255,3,36, - 22,0,67,16,12,0,145,38,33,32,224,2, - 6,0,197,38,35,48,150,2,0,0,163,150, - 4,0,2,36,16,0,162,175,161,0,2,36, - 20,0,162,175,28,0,176,175,0,18,3,0, - 2,26,3,0,37,16,67,0,255,255,66,48, - 24,0,162,175,80,0,162,143,76,0,163,143, - 33,56,32,2,35,16,67,0,255,255,66,48, - 220,44,192,12,32,0,162,175,120,0,191,143, - 116,0,183,143,112,0,182,143,108,0,181,143, - 104,0,180,143,100,0,179,143,96,0,178,143, - 92,0,177,143,88,0,176,143,8,0,224,3, - 128,0,189,39,196,133,130,143,184,255,189,39, - 64,0,191,175,60,0,177,175,109,0,64,16, - 56,0,176,175,255,255,3,36,106,0,67,16, - 0,0,0,0,176,133,130,143,176,133,145,39, - 102,0,64,16,0,0,0,0,100,0,67,16, - 0,0,0,0,2,131,2,60,8,239,66,36, - 44,0,162,175,48,0,162,175,242,5,2,36, - 40,0,160,167,6,0,128,16,52,0,162,167, - 1,0,2,36,23,0,130,16,0,0,0,0, - 36,46,192,8,0,0,0,0,2,131,16,60, - 160,204,16,38,156,71,192,12,33,32,0,2, - 0,163,4,60,4,1,132,140,204,204,3,60, - 205,204,99,52,25,0,131,0,33,40,32,2, - 33,48,0,2,33,56,64,0,40,0,164,39, - 16,64,0,0,194,16,8,0,0,0,0,0, - 104,56,192,12,16,0,162,175,251,45,192,8, - 33,24,64,0,3,131,2,60,28,18,66,148, - 0,0,0,0,2,0,66,48,61,0,64,16, - 0,0,0,0,2,131,16,60,160,204,16,38, - 156,71,192,12,33,32,0,2,0,163,4,60, - 4,1,132,140,204,204,3,60,205,204,99,52, - 25,0,131,0,33,40,32,2,33,48,0,2, - 33,56,64,0,40,0,164,39,16,64,0,0, - 194,16,8,0,0,0,0,0,105,57,192,12, - 16,0,162,175,33,24,64,0,255,255,2,36, - 39,0,98,16,0,0,0,0,140,129,130,147, - 0,0,0,0,1,0,66,48,7,0,64,20, - 0,0,0,0,68,133,131,143,152,129,130,143, - 0,0,0,0,43,16,67,0,11,0,64,16, - 33,32,0,0,68,133,131,143,148,129,130,143, - 0,0,0,0,6,0,98,16,33,32,0,0, - 196,133,133,143,148,129,131,175,17,43,192,12, - 33,32,0,0,33,32,0,0,140,129,133,39, - 14,0,6,36,4,0,2,36,16,0,162,175, - 162,0,2,36,20,0,162,175,24,0,162,175, - 2,131,2,60,8,239,66,36,28,0,162,175, - 48,0,162,143,44,0,163,143,196,133,135,39, - 35,16,67,0,255,255,66,48,220,44,192,12, - 32,0,162,175,64,0,191,143,60,0,177,143, - 56,0,176,143,8,0,224,3,72,0,189,39, - 208,255,189,39,36,0,179,175,33,152,128,0, - 40,0,180,175,33,160,160,0,32,0,178,175, - 24,0,176,175,33,128,224,0,44,0,191,175, - 28,0,177,175,6,0,2,150,64,0,177,143, - 0,0,0,0,20,0,64,16,33,144,192,0, - 12,0,68,38,8,0,5,36,192,42,192,12, - 0,17,6,36,4,0,4,38,2,0,5,36, - 192,42,192,12,255,255,70,48,33,32,0,2, - 33,40,32,2,192,42,192,12,255,255,70,48, - 255,255,66,48,255,255,3,52,4,0,67,16, - 0,0,0,0,3,131,3,60,111,46,192,8, - 120,17,99,36,4,0,2,150,0,0,0,0, - 0,26,2,0,2,18,2,0,37,24,98,0, - 255,255,99,48,4,0,113,16,8,0,7,38, - 3,131,3,60,111,46,192,8,120,17,99,36, - 2,0,2,150,0,0,0,0,0,26,2,0, - 2,18,2,0,37,24,98,0,255,255,99,48, - 161,0,2,36,15,0,98,20,248,255,40,38, - 33,32,96,2,33,40,128,2,3,131,3,60, - 112,17,99,36,0,0,98,140,33,48,64,2, - 16,0,167,175,33,56,0,2,20,0,168,175, - 1,0,66,36,86,45,192,12,0,0,98,172, - 115,46,192,8,0,0,0,0,3,131,3,60, - 116,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,44,0,191,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 48,0,189,39,192,255,189,39,52,0,181,175, - 33,168,128,0,44,0,179,175,33,152,160,0, - 48,0,180,175,33,160,192,0,32,0,176,175, - 33,128,224,0,33,32,0,2,33,48,0,0, - 40,0,178,175,80,0,178,143,3,131,3,60, - 144,16,99,36,56,0,191,175,36,0,177,175, - 0,0,98,140,33,40,64,2,1,0,66,36, - 192,42,192,12,0,0,98,172,255,255,66,48, - 255,255,3,52,8,0,67,16,8,0,2,36, - 3,131,2,60,148,16,66,140,0,0,0,0, - 1,0,66,36,3,131,1,60,217,46,192,8, - 148,16,34,172,0,0,3,150,0,0,0,0, - 58,0,98,20,255,1,69,38,2,131,4,60, - 192,4,132,36,3,131,2,60,172,16,66,140, - 3,131,3,60,196,16,99,140,1,0,66,36, - 1,0,99,36,3,131,1,60,172,16,34,172, - 3,131,1,60,196,16,35,172,54,21,192,12, - 2,42,5,0,33,136,64,0,8,0,32,22, - 33,32,0,2,3,131,2,60,200,16,66,140, - 0,0,0,0,1,0,66,36,3,131,1,60, - 217,46,192,8,200,16,34,172,33,40,64,2, - 33,48,0,0,0,0,0,162,192,42,192,12, - 2,0,0,166,33,40,0,2,39,16,2,0, - 2,0,162,164,4,0,36,142,0,0,0,0, - 220,42,192,12,33,48,64,2,33,32,160,2, - 6,0,101,38,35,48,147,2,0,0,67,140, - 12,0,135,38,0,128,99,52,0,0,67,172, - 1,0,3,36,18,0,50,166,16,0,163,175, - 4,0,3,36,20,0,163,175,24,0,177,175, - 23,44,192,12,28,0,162,175,3,131,2,60, - 228,16,66,140,0,0,0,0,1,0,66,36, - 3,131,1,60,228,16,34,172,56,0,191,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,200,255,189,39, - 44,0,181,175,33,168,128,0,3,131,3,60, - 4,17,99,36,48,0,191,175,40,0,180,175, - 36,0,179,175,32,0,178,175,28,0,177,175, - 24,0,176,175,0,0,98,140,33,136,160,0, - 1,0,66,36,0,0,98,172,18,0,34,150, - 0,0,0,0,255,255,84,48,243,5,130,46, - 8,0,64,20,33,152,192,0,3,131,2,60, - 8,17,66,140,0,0,0,0,1,0,66,36, - 3,131,1,60,132,47,192,8,8,17,34,172, - 2,131,18,60,18,233,82,38,33,32,64,2, - 0,0,48,142,8,0,37,142,255,63,16,50, - 80,68,192,12,33,48,0,2,0,0,34,142, - 0,0,0,0,0,128,66,48,5,0,64,20, - 33,144,80,2,4,0,49,142,0,0,0,0, - 1,47,192,8,33,32,64,2,2,131,18,60, - 18,233,82,38,33,128,114,2,16,0,17,38, - 33,32,32,2,176,133,133,39,168,71,192,12, - 4,0,6,36,9,0,64,16,33,32,32,2, - 128,129,133,39,168,71,192,12,4,0,6,36, - 4,0,64,16,0,0,0,0,3,131,3,60, - 128,47,192,8,12,17,99,36,0,0,4,146, - 64,0,2,36,240,0,131,48,4,0,98,16, - 15,0,130,48,3,131,3,60,128,47,192,8, - 8,17,99,36,128,136,2,0,20,0,34,42, - 4,0,64,16,33,32,0,2,3,131,3,60, - 128,47,192,8,8,17,99,36,33,40,32,2, - 192,42,192,12,33,48,0,0,255,255,66,48, - 255,255,3,52,4,0,67,16,0,0,0,0, - 3,131,3,60,128,47,192,8,8,17,99,36, - 6,0,2,150,0,0,0,0,63,255,66,48, - 18,0,64,16,33,56,17,2,3,131,3,60, - 48,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,3,131,2,60, - 56,17,66,140,3,131,3,60,24,17,99,140, - 1,0,66,36,1,0,99,36,3,131,1,60, - 56,17,34,172,3,131,1,60,132,47,192,8, - 24,17,35,172,2,0,2,150,0,0,0,0, - 0,26,2,0,2,18,2,0,37,24,98,0, - 255,255,99,48,35,64,113,0,35,16,242,0, - 35,16,130,2,42,16,72,0,4,0,64,16, - 1,0,2,36,3,131,3,60,128,47,192,8, - 24,17,99,36,9,0,3,146,0,0,0,0, - 5,0,98,16,17,0,2,36,15,0,98,16, - 33,32,160,2,126,47,192,8,0,0,0,0, - 33,32,160,2,33,40,64,2,3,131,3,60, - 28,17,99,36,0,0,98,140,33,48,0,2, - 16,0,168,175,1,0,66,36,123,46,192,12, - 0,0,98,172,132,47,192,8,0,0,0,0, - 33,40,64,2,3,131,3,60,28,17,99,36, - 0,0,98,140,33,48,0,2,16,0,168,175, - 1,0,66,36,41,46,192,12,0,0,98,172, - 132,47,192,8,0,0,0,0,3,131,3,60, - 20,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,48,0,191,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,56,0,189,39,232,255,189,39, - 255,0,12,60,255,0,140,53,0,255,13,60, - 0,255,173,53,16,0,176,175,3,131,16,60, - 0,17,16,38,33,32,0,2,33,40,0,0, - 0,163,9,60,220,5,41,141,0,163,10,60, - 16,6,74,141,0,163,11,60,224,5,107,141, - 20,0,191,175,0,28,9,0,2,20,9,0, - 37,24,98,0,0,60,10,0,2,20,10,0, - 37,56,226,0,0,68,11,0,2,20,11,0, - 37,64,2,1,2,18,3,0,36,16,76,0, - 0,26,3,0,36,24,109,0,37,16,67,0, - 184,133,130,175,2,18,7,0,36,16,76,0, - 0,58,7,0,36,56,237,0,37,16,71,0, - 192,133,130,175,2,18,8,0,36,16,76,0, - 0,66,8,0,36,64,13,1,37,16,72,0, - 176,133,137,175,196,133,138,175,188,133,139,175, - 180,133,130,175,144,71,192,12,76,0,6,36, - 3,131,4,60,144,16,132,36,33,40,0,0, - 32,0,2,36,0,0,2,174,10,0,2,36, - 3,131,1,60,44,17,34,172,144,71,192,12, - 104,0,6,36,3,131,4,60,112,17,132,36, - 33,40,0,0,144,71,192,12,16,0,6,36, - 3,131,4,60,80,17,132,36,33,40,0,0, - 144,71,192,12,32,0,6,36,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 176,255,189,39,100,0,162,143,96,0,169,143, - 72,0,182,175,33,176,128,0,48,0,176,175, - 104,0,176,143,34,0,164,39,60,0,179,175, - 108,0,179,143,3,131,3,60,104,17,99,36, - 56,0,178,175,2,131,18,60,212,4,82,38, - 52,0,177,175,33,136,192,0,68,0,181,175, - 112,0,181,143,4,0,6,36,76,0,191,175, - 64,0,180,175,0,66,2,0,255,255,66,48, - 2,18,2,0,37,64,2,1,0,0,98,140, - 8,0,116,142,1,0,66,36,0,0,98,172, - 3,0,162,136,0,0,162,152,4,0,163,128, - 5,0,170,128,3,0,130,170,0,0,130,186, - 4,0,131,162,5,0,138,162,3,0,66,138, - 0,0,66,154,4,0,67,130,5,0,69,130, - 9,0,130,170,6,0,130,186,10,0,131,162, - 11,0,133,162,255,255,2,52,16,0,162,167, - 18,0,98,150,33,40,0,0,20,0,160,163, - 21,0,160,163,30,0,66,36,0,26,2,0, - 255,255,66,48,2,18,2,0,37,24,98,0, - 18,0,163,167,3,0,226,136,0,0,226,152, - 0,0,0,0,25,0,162,171,22,0,162,187, - 3,0,34,137,0,0,34,153,4,0,35,129, - 5,0,39,129,29,0,162,171,26,0,162,187, - 30,0,163,163,31,0,167,163,144,71,192,12, - 32,0,168,167,3,0,66,138,0,0,66,154, - 4,0,67,134,41,0,162,171,38,0,162,187, - 42,0,163,167,33,16,0,2,0,130,16,0, - 255,255,66,48,2,18,2,0,37,128,2,2, - 14,0,2,36,58,0,34,22,44,0,176,167, - 18,0,162,151,0,0,0,0,12,0,130,166, - 19,0,162,139,16,0,162,155,23,0,163,139, - 20,0,163,155,27,0,164,139,24,0,164,155, - 31,0,165,139,28,0,165,155,17,0,130,170, - 14,0,130,186,21,0,131,170,18,0,131,186, - 25,0,132,170,22,0,132,186,29,0,133,170, - 26,0,133,186,35,0,162,139,32,0,162,155, - 39,0,163,139,36,0,163,155,43,0,164,139, - 40,0,164,155,44,0,165,131,33,0,130,170, - 30,0,130,186,37,0,131,170,34,0,131,186, - 41,0,132,170,38,0,132,186,42,0,133,162, - 45,0,162,131,0,0,0,0,43,0,130,162, - 44,0,2,36,0,0,98,174,0,0,99,142, - 18,0,98,150,0,0,0,0,33,16,67,0, - 18,0,98,166,18,0,98,150,0,0,0,0, - 60,0,66,44,80,0,64,16,33,32,192,2, - 0,0,162,142,18,0,99,150,60,0,66,36, - 35,16,67,0,0,0,162,174,60,0,2,36, - 18,0,98,166,172,48,192,8,33,32,192,2, - 208,129,133,39,3,0,162,136,0,0,162,152, - 4,0,163,128,5,0,164,128,17,0,130,170, - 14,0,130,186,18,0,131,162,19,0,132,162, - 129,55,2,36,20,0,130,166,19,0,162,139, - 16,0,162,155,23,0,163,139,20,0,163,155, - 27,0,164,139,24,0,164,155,31,0,165,139, - 28,0,165,155,25,0,130,170,22,0,130,186, - 29,0,131,170,26,0,131,186,33,0,132,170, - 30,0,132,186,37,0,133,170,34,0,133,186, - 35,0,162,139,32,0,162,155,39,0,163,139, - 36,0,163,155,43,0,164,139,40,0,164,155, - 44,0,165,131,41,0,130,170,38,0,130,186, - 45,0,131,170,42,0,131,186,49,0,132,170, - 46,0,132,186,50,0,133,162,45,0,162,131, - 0,0,0,0,51,0,130,162,52,0,2,36, - 0,0,98,174,0,0,99,142,18,0,98,150, - 0,0,0,0,33,16,67,0,18,0,98,166, - 18,0,98,150,0,0,0,0,60,0,66,44, - 8,0,64,16,0,0,0,0,0,0,162,142, - 18,0,99,150,60,0,66,36,35,16,67,0, - 0,0,162,174,60,0,2,36,18,0,98,166, - 18,0,98,150,0,0,0,0,0,26,2,0, - 2,18,2,0,37,24,98,0,12,0,131,166, - 33,32,192,2,74,21,192,12,33,40,96,2, - 8,0,64,20,33,32,96,2,3,131,3,60, - 108,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,152,21,192,12,0,0,98,172, - 76,0,191,143,72,0,182,143,68,0,181,143, - 64,0,180,143,60,0,179,143,56,0,178,143, - 52,0,177,143,48,0,176,143,8,0,224,3, - 80,0,189,39,33,24,0,0,5,0,7,36, - 58,0,6,36,0,0,162,144,0,0,0,0, - 2,17,2,0,2,131,1,60,33,8,34,0, - 176,155,34,144,0,0,0,0,0,0,130,160, - 0,0,162,144,1,0,132,36,15,0,66,48, - 2,131,1,60,33,8,34,0,176,155,34,144, - 1,0,165,36,0,0,130,160,3,0,103,16, - 1,0,132,36,0,0,134,160,1,0,132,36, - 1,0,99,36,6,0,98,40,233,255,64,20, - 0,0,0,0,8,0,224,3,0,0,0,0, - 128,255,189,39,2,101,2,36,0,2,3,36, - 112,0,176,175,44,0,176,39,33,32,0,2, - 33,40,0,0,48,0,6,36,120,0,191,175, - 116,0,177,175,40,0,162,167,144,71,192,12, - 42,0,163,167,3,131,17,60,96,18,49,38, - 2,131,5,60,224,147,165,36,188,71,192,12, - 33,32,32,2,18,0,64,20,33,32,0,2, - 2,131,5,60,236,147,165,36,0,0,162,140, - 4,0,163,140,8,0,164,140,44,0,162,175, - 48,0,163,175,52,0,164,175,12,0,162,128, - 0,0,0,0,56,0,162,163,2,131,5,60, - 212,4,165,36,193,48,192,12,56,0,164,39, - 8,49,192,8,92,0,177,39,33,40,32,2, - 204,63,192,12,48,0,6,36,92,0,177,39, - 33,32,32,2,33,40,0,0,144,71,192,12, - 4,0,6,36,2,131,4,60,212,4,132,36, - 0,0,130,140,4,0,131,132,96,0,162,175, - 100,0,163,167,4,82,2,36,0,1,3,36, - 236,255,132,36,2,0,5,36,102,0,162,167, - 54,21,192,12,104,0,163,167,33,128,64,0, - 22,0,0,18,40,0,165,39,4,0,4,142, - 0,0,0,0,220,42,192,12,66,0,6,36, - 33,32,0,0,0,0,67,140,132,129,133,39, - 0,128,99,52,0,0,67,172,4,0,3,142, - 14,0,6,36,18,0,99,148,33,56,32,2, - 18,0,3,166,82,4,3,36,16,0,165,175, - 20,0,163,175,24,0,163,175,28,0,176,175, - 214,47,192,12,32,0,162,175,120,0,191,143, - 116,0,177,143,112,0,176,143,8,0,224,3, - 128,0,189,39,144,255,189,39,104,0,180,175, - 33,160,128,0,100,0,179,175,33,152,160,0, - 92,0,177,175,33,136,192,0,33,32,224,0, - 40,0,166,39,56,0,167,39,96,0,178,175, - 2,131,18,60,8,239,82,38,88,0,176,175, - 128,0,176,143,242,5,2,36,84,0,162,167, - 72,0,162,39,108,0,191,175,72,0,160,167, - 76,0,178,175,80,0,178,175,16,0,162,175, - 247,71,192,12,33,40,0,2,255,255,3,36, - 37,0,67,16,255,1,5,38,2,131,4,60, - 192,4,132,36,54,21,192,12,2,42,5,0, - 33,128,64,0,30,0,0,18,33,40,64,2, - 80,0,166,143,76,0,162,143,4,0,4,142, - 35,48,194,0,220,42,192,12,255,255,198,48, - 33,32,128,2,0,0,67,140,6,0,101,38, - 0,128,99,52,0,0,67,172,4,0,3,142, - 35,48,51,2,18,0,99,148,18,0,39,38, - 18,0,3,166,28,0,40,150,22,0,35,38, - 16,0,163,175,15,144,3,52,24,0,163,175, - 28,0,176,175,32,0,162,175,0,18,8,0, - 2,66,8,0,37,16,72,0,255,255,66,48, - 214,47,192,12,20,0,162,175,108,0,191,143, - 104,0,180,143,100,0,179,143,96,0,178,143, - 92,0,177,143,88,0,176,143,8,0,224,3, - 112,0,189,39,200,255,189,39,44,0,181,175, - 33,168,128,0,28,0,177,175,33,136,160,0, - 48,0,191,175,40,0,180,175,36,0,179,175, - 32,0,178,175,24,0,176,175,18,0,34,150, - 0,0,0,0,255,255,84,48,243,5,130,46, - 4,0,64,20,33,152,192,0,3,131,3,60, - 241,49,192,8,84,17,99,36,2,131,18,60, - 16,233,82,38,33,32,64,2,0,0,48,142, - 8,0,37,142,255,63,16,50,80,68,192,12, - 33,48,0,2,0,0,34,142,0,0,0,0, - 0,128,66,48,5,0,64,20,33,144,80,2, - 4,0,49,142,0,0,0,0,148,49,192,8, - 33,32,64,2,2,131,2,60,16,233,66,36, - 33,128,98,2,6,0,17,38,33,32,32,2, - 0,163,5,60,224,5,165,52,168,71,192,12, - 4,0,6,36,9,0,64,16,33,32,32,2, - 224,129,133,39,168,71,192,12,4,0,6,36, - 5,0,64,16,10,0,17,38,3,131,3,60, - 241,49,192,8,88,17,99,36,10,0,17,38, - 33,32,32,2,2,131,5,60,212,4,165,36, - 168,71,192,12,6,0,6,36,9,0,64,16, - 33,32,32,2,228,129,133,39,168,71,192,12, - 6,0,6,36,4,0,64,16,0,0,0,0, - 3,131,3,60,241,49,192,8,88,17,99,36, - 0,0,3,150,255,255,2,52,4,0,98,16, - 30,0,7,38,3,131,3,60,241,49,192,8, - 88,17,99,36,2,0,2,150,2,131,5,60, - 16,233,165,36,0,26,2,0,2,18,2,0, - 37,24,98,0,255,255,99,48,226,255,104,36, - 35,16,229,0,35,16,130,2,42,16,72,0, - 4,0,64,16,0,0,0,0,3,131,3,60, - 241,49,192,8,96,17,99,36,16,0,2,150, - 0,0,0,0,0,26,2,0,2,18,2,0, - 37,24,98,0,255,255,99,48,15,144,2,52, - 11,0,98,20,33,32,160,2,3,131,3,60, - 100,17,99,36,0,0,98,140,33,48,0,2, - 16,0,168,175,1,0,66,36,54,49,192,12, - 0,0,98,172,245,49,192,8,0,0,0,0, - 3,131,3,60,92,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,0,0,98,172, - 48,0,191,143,44,0,181,143,40,0,180,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,56,0,189,39, - 0,0,0,0,0,0,0,0,232,255,189,39, - 16,0,191,175,13,8,192,12,0,8,4,36, - 8,133,130,175,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,232,255,189,39, - 45,0,128,16,16,0,191,175,240,129,133,143, - 7,0,130,36,194,16,2,0,10,0,160,20, - 1,0,70,36,8,133,133,143,0,133,130,39, - 0,133,133,175,0,0,162,172,0,8,2,36, - 240,129,133,175,2,131,1,60,20,211,32,172, - 4,0,162,172,0,0,164,140,0,0,0,0, - 4,0,131,140,0,0,0,0,43,16,102,0, - 14,0,64,20,0,0,0,0,5,0,102,20, - 35,16,102,0,0,0,130,140,0,0,0,0, - 43,50,192,8,0,0,162,172,4,0,130,172, - 192,16,2,0,33,32,130,0,4,0,134,172, - 240,129,133,175,57,50,192,8,8,0,130,36, - 240,129,130,143,0,0,0,0,4,0,130,16, - 33,40,128,0,0,0,132,140,28,50,192,8, - 0,0,0,0,2,131,4,60,15,63,192,12, - 64,148,132,36,33,16,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 56,0,128,16,248,255,132,36,240,129,133,143, - 0,0,0,0,78,50,192,8,43,16,164,0, - 0,0,163,140,0,0,0,0,43,16,163,0, - 5,0,64,20,43,16,164,0,12,0,64,20, - 43,16,131,0,10,0,64,20,0,0,0,0, - 33,40,96,0,43,16,164,0,244,255,64,16, - 0,0,0,0,0,0,162,140,0,0,0,0, - 43,16,130,0,239,255,64,16,0,0,0,0, - 4,0,134,140,0,0,163,140,192,16,6,0, - 33,16,130,0,11,0,67,20,0,0,0,0, - 4,0,98,140,0,0,0,0,33,16,194,0, - 4,0,130,172,0,0,162,140,0,0,0,0, - 0,0,66,140,0,0,0,0,102,50,192,8, - 0,0,130,172,0,0,131,172,4,0,163,140, - 0,0,0,0,192,16,3,0,33,16,162,0, - 9,0,68,20,0,0,0,0,4,0,130,140, - 0,0,0,0,33,16,98,0,4,0,162,172, - 0,0,130,140,0,0,0,0,117,50,192,8, - 0,0,162,172,0,0,164,172,240,129,133,175, - 8,0,224,3,0,0,0,0,232,255,189,39, - 16,0,191,175,0,50,192,12,0,0,0,0, - 178,45,192,12,33,32,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 1,0,3,36,5,0,195,20,255,255,2,36, - 0,0,226,140,0,0,0,0,43,16,2,0, - 35,16,2,0,8,0,224,3,0,0,0,0, - 224,255,189,39,16,0,176,175,33,128,224,0, - 20,0,177,175,48,0,177,143,1,0,2,36, - 5,0,162,20,24,0,191,175,0,0,194,140, - 0,0,0,0,8,0,64,16,0,0,0,0, - 11,0,2,36,33,32,0,2,33,40,32,2, - 48,72,192,12,96,0,2,174,1,0,66,36, - 100,0,2,174,17,0,34,146,0,0,0,0, - 1,0,66,52,17,0,34,162,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,8,0,224,3,0,0,0,0, - 16,0,163,143,0,0,0,0,17,0,98,144, - 0,0,0,0,2,0,66,52,8,0,224,3, - 17,0,98,160,8,0,224,3,0,0,0,0, - 224,255,189,39,16,0,176,175,33,128,128,0, - 244,129,131,151,255,0,2,36,28,0,191,175, - 24,0,178,175,20,0,177,175,4,0,2,174, - 60,0,0,174,1,0,98,36,244,129,130,167, - 10,0,3,166,3,0,162,136,0,0,162,152, - 7,0,163,136,4,0,163,152,11,0,164,136, - 8,0,164,152,15,0,167,136,12,0,167,152, - 15,0,2,170,12,0,2,186,19,0,3,170, - 16,0,3,186,23,0,4,170,20,0,4,186, - 27,0,7,170,24,0,7,186,3,0,194,136, - 0,0,194,152,7,0,195,136,4,0,195,152, - 11,0,196,136,8,0,196,152,15,0,197,136, - 12,0,197,152,31,0,2,170,28,0,2,186, - 35,0,3,170,32,0,3,186,39,0,4,170, - 36,0,4,186,43,0,5,170,40,0,5,186, - 80,0,2,142,76,0,3,142,0,0,0,0, - 35,16,67,0,255,255,81,48,88,0,3,150, - 3,0,2,36,13,0,98,16,0,0,0,0, - 2,131,18,60,160,204,82,38,156,71,192,12, - 33,32,64,2,7,0,81,20,33,32,64,2, - 76,0,5,142,0,0,0,0,168,71,192,12, - 33,48,32,2,21,0,64,16,33,16,0,0, - 2,131,18,60,192,204,82,38,156,71,192,12, - 33,32,64,2,7,0,81,20,33,32,64,2, - 76,0,5,142,0,0,0,0,168,71,192,12, - 33,48,32,2,9,0,64,16,33,16,0,0, - 3,131,3,60,132,17,99,36,0,0,98,140, - 1,0,4,36,1,0,66,36,178,45,192,12, - 0,0,98,172,1,0,2,36,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,0,0,0,0, - 0,0,0,0,224,255,189,39,20,0,177,175, - 33,136,224,0,16,0,176,175,48,0,176,143, - 24,0,191,175,156,71,192,12,33,32,32,2, - 0,0,2,174,33,16,32,2,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,8,0,224,3,33,16,224,0, - 0,0,227,140,204,204,2,60,205,204,66,52, - 25,0,98,0,16,32,0,0,0,0,0,0, - 0,0,0,0,8,0,224,3,194,16,4,0, - 224,255,189,39,16,0,176,175,33,128,224,0, - 33,32,0,2,33,40,0,0,20,0,177,175, - 48,0,177,143,24,0,191,175,208,71,192,12, - 16,0,6,36,2,0,64,20,35,16,80,0, - 16,0,2,36,0,0,34,174,33,16,0,2, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,232,255,189,39, - 40,0,164,143,44,0,165,143,16,0,191,175, - 205,59,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,40,0,164,143,44,0,165,143, - 16,0,191,175,239,59,192,12,0,0,0,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,232,255,189,39,40,0,164,143, - 44,0,165,143,16,0,191,175,17,60,192,12, - 0,0,0,0,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,8,0,224,3, - 33,16,224,0,0,0,226,140,8,0,224,3, - 0,0,0,0,216,255,189,39,24,0,176,175, - 56,0,176,143,32,0,191,175,28,0,177,175, - 36,0,2,142,1,0,3,36,20,0,81,140, - 187,0,163,20,0,0,0,0,0,0,195,140, - 0,0,0,0,183,0,96,16,0,0,0,0, - 32,133,130,143,0,0,0,0,43,16,67,0, - 178,0,64,20,255,255,104,36,64,18,8,0, - 2,131,3,60,192,246,99,36,33,40,67,0, - 255,255,132,36,22,0,130,44,170,0,64,16, - 128,16,4,0,2,131,1,60,33,8,34,0, - 144,148,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,2,0,2,36,16,0,2,162, - 17,0,2,146,0,0,195,140,0,0,0,0, - 15,52,192,8,2,0,66,52,33,32,32,2, - 17,0,3,146,4,0,2,36,16,0,2,162, - 40,0,0,166,44,0,17,174,2,0,99,52, - 156,71,192,12,17,0,3,162,255,255,66,48, - 33,16,34,2,48,0,2,174,40,52,192,8, - 52,0,0,166,17,0,3,146,2,0,2,36, - 16,0,2,162,243,51,192,8,40,0,17,174, - 17,0,3,146,2,0,2,36,16,0,2,162, - 243,51,192,8,40,0,17,174,66,0,2,36, - 13,0,0,21,16,0,2,162,24,133,132,143, - 0,0,0,0,64,25,4,0,35,24,100,0, - 128,17,3,0,35,16,67,0,192,16,2,0, - 33,16,68,0,128,24,2,0,33,16,67,0, - 178,51,192,8,192,17,2,0,152,0,2,60, - 128,150,66,52,40,0,2,174,17,0,2,146, - 0,0,0,0,199,51,192,8,2,0,66,52, - 17,0,3,146,4,0,2,36,16,0,2,162, - 20,0,162,36,44,0,2,174,26,0,162,36, - 40,0,0,166,48,0,2,174,243,51,192,8, - 52,0,0,166,2,0,2,36,16,0,2,162, - 17,0,2,146,1,0,3,36,40,0,3,174, - 2,0,66,52,40,52,192,8,17,0,2,162, - 17,0,3,146,0,0,0,0,241,51,192,8, - 67,0,2,36,65,0,2,36,16,0,2,162, - 17,0,2,146,168,0,163,140,0,0,0,0, - 15,52,192,8,2,0,66,52,65,0,2,36, - 16,0,2,162,156,0,162,140,0,1,164,140, - 22,52,192,8,0,0,0,0,65,0,2,36, - 16,0,2,162,17,0,2,146,0,1,163,140, - 0,0,0,0,15,52,192,8,2,0,66,52, - 65,0,2,36,16,0,2,162,17,0,2,146, - 164,0,163,140,0,0,0,0,15,52,192,8, - 2,0,66,52,65,0,2,36,16,0,2,162, - 17,0,2,146,160,0,163,140,0,0,0,0, - 15,52,192,8,2,0,66,52,17,0,3,146, - 65,0,2,36,16,0,2,162,40,0,0,174, - 2,0,99,52,40,52,192,8,17,0,3,162, - 65,0,2,36,16,0,2,162,172,0,162,140, - 4,1,164,140,22,52,192,8,0,0,0,0, - 65,0,2,36,16,0,2,162,17,0,2,146, - 4,1,163,140,0,0,0,0,15,52,192,8, - 2,0,66,52,65,0,2,36,16,0,2,162, - 17,0,2,146,184,0,163,140,0,0,0,0, - 15,52,192,8,2,0,66,52,65,0,2,36, - 16,0,2,162,17,0,2,146,188,0,163,140, - 2,0,66,52,40,0,3,174,40,52,192,8, - 17,0,2,162,66,0,2,36,16,0,2,162, - 172,0,162,140,176,0,164,140,17,0,3,146, - 35,16,68,0,2,0,99,52,40,0,2,174, - 40,52,192,8,17,0,3,162,16,0,160,175, - 33,32,224,0,33,40,0,2,2,131,7,60, - 96,204,231,36,226,76,192,12,2,0,6,36, - 40,52,192,8,0,0,0,0,33,32,224,0, - 200,76,192,12,33,40,0,2,32,0,191,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,224,255,189,39,16,0,176,175, - 33,128,224,0,20,0,177,175,48,0,177,143, - 1,0,2,36,10,0,162,20,24,0,191,175, - 0,0,198,140,0,0,0,0,6,0,192,16, - 0,0,0,0,32,133,130,143,0,0,0,0, - 43,16,70,0,5,0,64,16,7,0,2,36, - 33,32,0,2,33,40,32,2,70,52,192,8, - 11,0,2,36,7,0,130,16,33,32,0,2, - 33,40,32,2,17,0,2,36,48,72,192,12, - 96,0,2,174,1,0,66,36,100,0,2,174, - 17,0,34,146,0,0,0,0,1,0,66,52, - 17,0,34,162,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 208,255,189,39,32,0,176,175,64,0,176,143, - 36,0,177,175,33,136,224,0,4,0,160,20, - 40,0,191,175,1,0,2,36,106,52,192,8, - 24,0,162,175,0,0,198,140,32,133,130,143, - 0,0,0,0,43,16,194,0,3,0,64,16, - 1,0,194,36,106,52,192,8,24,0,162,175, - 17,0,2,146,0,0,0,0,18,0,66,52, - 116,52,192,8,17,0,2,162,16,0,176,175, - 1,0,5,36,24,0,166,39,97,51,192,12, - 33,56,32,2,33,32,32,2,33,40,0,2, - 1,0,6,36,253,76,192,12,24,0,167,39, - 40,0,191,143,36,0,177,143,32,0,176,143, - 8,0,224,3,48,0,189,39,16,0,163,143, - 1,0,2,36,13,0,162,20,14,0,2,36, - 0,0,198,140,0,0,0,0,9,0,192,16, - 0,0,0,0,32,133,130,143,0,0,0,0, - 43,16,70,0,4,0,64,20,14,0,2,36, - 7,0,2,36,2,0,130,16,14,0,2,36, - 96,0,226,172,17,0,98,144,0,0,0,0, - 2,0,66,52,8,0,224,3,17,0,98,160, - 16,0,162,143,0,0,0,0,8,0,224,3, - 0,0,226,172,0,0,226,140,8,0,224,3, - 0,0,0,0,232,255,189,39,40,0,168,143, - 1,0,2,36,61,0,162,20,16,0,191,175, - 0,0,197,140,0,0,0,0,57,0,160,16, - 0,0,0,0,32,133,130,143,0,0,0,0, - 43,16,69,0,52,0,64,20,255,255,132,36, - 5,0,130,44,49,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,232,148,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 64,0,2,36,16,0,2,161,0,163,5,60, - 220,5,165,52,3,0,162,136,0,0,162,152, - 0,0,0,0,43,0,2,169,40,0,2,185, - 17,0,2,145,0,0,0,0,213,52,192,8, - 2,0,66,52,2,0,2,36,16,0,2,161, - 17,0,2,145,0,0,195,140,0,0,0,0, - 198,52,192,8,2,0,66,52,64,0,2,36, - 16,0,2,161,17,0,2,145,128,132,131,143, - 2,0,66,52,40,0,3,173,218,52,192,8, - 17,0,2,161,2,0,2,36,16,0,2,161, - 17,0,2,145,0,0,0,0,211,52,192,8, - 1,0,3,36,2,0,2,36,16,0,2,161, - 17,0,2,145,220,5,3,36,40,0,3,173, - 2,0,66,52,218,52,192,8,17,0,2,161, - 33,32,224,0,200,76,192,12,33,40,0,1, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,208,255,189,39,32,0,176,175, - 64,0,176,143,36,0,177,175,33,136,224,0, - 4,0,160,20,40,0,191,175,1,0,2,36, - 245,52,192,8,24,0,162,175,0,0,198,140, - 32,133,130,143,0,0,0,0,43,16,194,0, - 3,0,64,16,1,0,194,36,245,52,192,8, - 24,0,162,175,17,0,2,146,0,0,0,0, - 18,0,66,52,255,52,192,8,17,0,2,162, - 16,0,176,175,1,0,5,36,24,0,166,39, - 150,52,192,12,33,56,32,2,33,32,32,2, - 33,40,0,2,1,0,6,36,253,76,192,12, - 24,0,167,39,40,0,191,143,36,0,177,143, - 32,0,176,143,8,0,224,3,48,0,189,39, - 232,255,189,39,40,0,165,143,16,0,191,175, - 200,76,192,12,33,32,224,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 16,0,163,143,14,0,2,36,96,0,226,172, - 17,0,98,144,0,0,0,0,2,0,66,52, - 8,0,224,3,17,0,98,160,224,255,189,39, - 16,0,176,175,33,128,224,0,17,0,2,36, - 24,0,191,175,20,0,177,175,96,0,2,174, - 48,0,177,143,33,32,0,2,48,72,192,12, - 33,40,32,2,1,0,66,36,100,0,2,174, - 17,0,34,146,0,0,0,0,1,0,66,52, - 17,0,34,162,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 16,0,163,143,0,0,0,0,17,0,98,144, - 0,0,0,0,18,0,66,52,8,0,224,3, - 17,0,98,160,8,0,224,3,33,16,224,0, - 224,255,189,39,48,0,168,143,1,0,2,36, - 114,0,162,20,24,0,191,175,0,0,195,140, - 0,0,0,0,110,0,96,16,0,0,0,0, - 32,133,130,143,0,0,0,0,43,16,67,0, - 105,0,64,20,255,255,98,36,64,18,2,0, - 2,131,3,60,192,246,99,36,33,24,67,0, - 255,255,132,36,17,0,130,44,97,0,64,16, - 128,16,4,0,2,131,1,60,33,8,34,0, - 0,149,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,2,0,2,36,16,0,2,161, - 17,0,2,145,0,0,195,140,0,0,0,0, - 140,53,192,8,2,0,66,52,2,0,2,36, - 16,0,2,161,44,0,99,140,17,0,2,145, - 16,0,99,140,0,0,0,0,101,53,192,8, - 2,0,66,52,2,0,2,36,16,0,2,161, - 44,0,99,140,17,0,2,145,12,0,99,140, - 2,0,66,52,17,0,2,161,173,53,192,8, - 40,0,3,173,2,0,2,36,16,0,2,161, - 17,0,2,145,212,0,99,140,0,0,0,0, - 140,53,192,8,2,0,66,52,2,0,2,36, - 16,0,2,161,17,0,2,145,192,0,99,140, - 0,0,0,0,140,53,192,8,2,0,66,52, - 2,0,2,36,16,0,2,161,17,0,2,145, - 208,0,99,140,0,0,0,0,140,53,192,8, - 2,0,66,52,2,0,2,36,16,0,2,161, - 204,0,98,140,184,0,100,140,17,0,3,145, - 33,16,68,0,2,0,99,52,40,0,2,173, - 173,53,192,8,17,0,3,161,2,0,2,36, - 16,0,2,161,17,0,2,145,196,0,99,140, - 2,0,66,52,40,0,3,173,173,53,192,8, - 17,0,2,161,17,0,3,145,2,0,2,36, - 16,0,2,161,40,0,0,173,2,0,99,52, - 173,53,192,8,17,0,3,161,2,0,2,36, - 16,0,2,161,44,0,100,140,17,0,2,145, - 20,0,131,140,24,0,132,140,2,0,66,52, - 17,0,2,161,33,24,100,0,173,53,192,8, - 40,0,3,173,16,0,160,175,33,32,224,0, - 33,40,0,1,2,131,7,60,104,204,231,36, - 226,76,192,12,11,0,6,36,173,53,192,8, - 0,0,0,0,33,32,224,0,200,76,192,12, - 33,40,0,1,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,208,255,189,39, - 32,0,176,175,64,0,176,143,36,0,177,175, - 33,136,224,0,4,0,160,20,40,0,191,175, - 1,0,2,36,200,53,192,8,24,0,162,175, - 0,0,198,140,32,133,130,143,0,0,0,0, - 43,16,194,0,3,0,64,16,1,0,194,36, - 200,53,192,8,24,0,162,175,17,0,2,146, - 0,0,0,0,18,0,66,52,210,53,192,8, - 17,0,2,162,16,0,176,175,1,0,5,36, - 24,0,166,39,52,53,192,12,33,56,32,2, - 33,32,32,2,33,40,0,2,1,0,6,36, - 253,76,192,12,24,0,167,39,40,0,191,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 48,0,189,39,0,0,226,140,8,0,224,3, - 0,0,0,0,3,131,2,60,28,18,66,148, - 0,0,0,0,2,0,66,48,2,0,64,16, - 2,0,3,36,1,0,3,36,8,0,224,3, - 33,16,96,0,232,255,189,39,40,0,164,143, - 16,0,191,175,1,0,132,56,186,59,192,12, - 1,0,132,44,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,16,0,163,143, - 6,0,2,36,0,0,98,172,8,0,224,3, - 33,16,224,0,224,255,189,39,48,0,168,143, - 1,0,2,36,52,0,162,20,24,0,191,175, - 0,0,197,140,0,0,0,0,48,0,160,16, - 0,0,0,0,24,133,130,143,0,0,0,0, - 43,16,69,0,43,0,64,20,255,255,132,36, - 5,0,130,44,40,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,72,149,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 2,0,2,36,16,0,2,161,17,0,2,145, - 0,0,195,140,2,0,66,52,40,0,3,173, - 45,54,192,8,17,0,2,161,2,0,2,36, - 16,0,2,161,0,0,194,140,17,0,3,145, - 1,0,66,36,2,0,99,52,40,0,2,173, - 45,54,192,8,17,0,3,161,16,0,160,175, - 33,32,224,0,33,40,0,1,2,131,7,60, - 148,204,231,36,226,76,192,12,2,0,6,36, - 45,54,192,8,0,0,0,0,17,0,3,145, - 2,0,2,36,16,0,2,161,40,0,0,173, - 2,0,99,52,45,54,192,8,17,0,3,161, - 33,32,224,0,200,76,192,12,33,40,0,1, - 24,0,191,143,32,0,189,39,8,0,224,3, - 0,0,0,0,208,255,189,39,32,0,176,175, - 64,0,176,143,36,0,177,175,33,136,224,0, - 4,0,160,20,40,0,191,175,1,0,2,36, - 72,54,192,8,24,0,162,175,0,0,198,140, - 24,133,130,143,0,0,0,0,43,16,194,0, - 3,0,64,16,1,0,194,36,72,54,192,8, - 24,0,162,175,17,0,2,146,0,0,0,0, - 18,0,66,52,82,54,192,8,17,0,2,162, - 16,0,176,175,1,0,5,36,24,0,166,39, - 242,53,192,12,33,56,32,2,33,32,32,2, - 33,40,0,2,1,0,6,36,253,76,192,12, - 24,0,167,39,40,0,191,143,36,0,177,143, - 32,0,176,143,8,0,224,3,48,0,189,39, - 0,0,226,148,8,0,224,3,0,0,0,0, - 8,0,224,3,33,16,224,0,16,0,163,143, - 8,0,2,36,0,0,98,172,8,0,224,3, - 33,16,224,0,224,255,189,39,16,0,176,175, - 48,0,176,143,1,0,2,36,24,0,191,175, - 126,0,162,20,20,0,177,175,0,0,198,140, - 0,0,0,0,122,0,192,16,0,0,0,0, - 24,133,130,143,0,0,0,0,43,16,70,0, - 117,0,64,20,192,17,6,0,3,131,3,60, - 16,13,99,36,33,136,67,0,255,255,132,36, - 10,0,130,44,110,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,96,149,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 17,0,3,146,2,0,2,36,16,0,2,162, - 211,54,192,8,40,0,6,174,2,0,2,36, - 16,0,2,162,0,0,34,150,17,0,3,146, - 0,0,0,0,143,54,192,8,2,18,2,0, - 2,0,2,36,16,0,2,162,4,0,34,142, - 17,0,3,146,1,0,66,36,2,0,99,52, - 40,0,2,174,232,54,192,8,17,0,3,162, - 2,0,2,36,16,0,2,162,4,0,34,142, - 0,0,0,0,2,0,64,16,2,0,3,36, - 1,0,3,36,17,0,2,146,40,0,3,174, - 2,0,66,52,232,54,192,8,17,0,2,162, - 2,0,2,36,16,0,2,162,17,0,2,146, - 8,0,35,142,0,0,0,0,226,54,192,8, - 2,0,66,52,9,50,192,12,8,0,4,36, - 33,48,64,0,15,0,34,138,12,0,34,154, - 19,0,35,138,16,0,35,154,3,0,194,168, - 0,0,194,184,7,0,195,168,196,54,192,8, - 4,0,195,184,2,0,2,36,16,0,2,162, - 17,0,2,146,20,0,35,142,0,0,0,0, - 226,54,192,8,2,0,66,52,9,50,192,12, - 8,0,4,36,33,48,64,0,27,0,34,138, - 24,0,34,154,31,0,35,138,28,0,35,154, - 3,0,194,168,0,0,194,184,7,0,195,168, - 4,0,195,184,0,0,194,148,0,0,0,0, - 0,26,2,0,2,18,2,0,37,24,98,0, - 0,0,195,164,17,0,3,146,4,0,2,36, - 16,0,2,162,1,0,2,36,40,0,2,166, - 8,0,194,36,44,0,6,174,48,0,2,174, - 52,0,0,166,2,0,99,52,232,54,192,8, - 17,0,3,162,2,0,2,36,16,0,2,162, - 17,0,2,146,32,0,35,150,0,0,0,0, - 226,54,192,8,2,0,66,52,2,0,2,36, - 16,0,2,162,17,0,2,146,104,0,35,142, - 2,0,66,52,40,0,3,174,232,54,192,8, - 17,0,2,162,33,32,224,0,200,76,192,12, - 33,40,0,2,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 224,255,189,39,16,0,176,175,33,128,224,0, - 20,0,177,175,48,0,177,143,1,0,2,36, - 10,0,162,20,24,0,191,175,0,0,198,140, - 0,0,0,0,6,0,192,16,0,0,0,0, - 24,133,130,143,0,0,0,0,43,16,70,0, - 5,0,64,16,2,0,2,36,33,32,0,2, - 33,40,32,2,13,55,192,8,11,0,2,36, - 14,0,130,16,2,0,130,44,5,0,64,20, - 6,0,130,44,3,0,64,16,4,0,130,44, - 8,0,64,16,0,0,0,0,33,32,0,2, - 33,40,32,2,17,0,2,36,48,72,192,12, - 96,0,2,174,1,0,66,36,100,0,2,174, - 17,0,34,146,0,0,0,0,1,0,66,52, - 17,0,34,162,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 208,255,189,39,32,0,176,175,64,0,176,143, - 36,0,177,175,33,136,224,0,4,0,160,20, - 40,0,191,175,1,0,2,36,49,55,192,8, - 24,0,162,175,0,0,198,140,24,133,130,143, - 0,0,0,0,43,16,194,0,3,0,64,16, - 1,0,194,36,49,55,192,8,24,0,162,175, - 17,0,2,146,0,0,0,0,18,0,66,52, - 59,55,192,8,17,0,2,162,16,0,176,175, - 1,0,5,36,24,0,166,39,97,54,192,12, - 33,56,32,2,33,32,32,2,33,40,0,2, - 1,0,6,36,253,76,192,12,24,0,167,39, - 40,0,191,143,36,0,177,143,32,0,176,143, - 8,0,224,3,48,0,189,39,232,255,189,39, - 33,64,128,0,16,0,176,175,40,0,176,143, - 1,0,2,36,57,0,162,20,20,0,191,175, - 0,0,196,140,0,0,0,0,54,0,128,16, - 14,0,2,36,24,133,130,143,0,0,0,0, - 43,16,68,0,49,0,64,20,14,0,2,36, - 192,17,4,0,3,131,3,60,16,13,99,36, - 33,48,67,0,4,0,2,36,21,0,2,17, - 5,0,2,45,5,0,64,16,2,0,2,36, - 8,0,2,17,14,0,2,36,129,55,192,8, - 96,0,226,172,5,0,2,36,28,0,2,17, - 14,0,2,36,129,55,192,8,96,0,226,172, - 0,0,195,144,0,0,0,0,0,0,195,164, - 40,0,2,142,0,0,0,0,0,18,2,0, - 37,24,98,0,129,55,192,8,0,0,195,164, - 40,0,3,142,0,0,0,0,5,0,101,16, - 2,0,2,36,7,0,98,16,14,0,2,36, - 129,55,192,8,96,0,226,172,187,42,192,12, - 1,0,5,36,129,55,192,8,0,0,0,0, - 187,42,192,12,33,40,0,0,129,55,192,8, - 0,0,0,0,40,0,2,142,0,0,0,0, - 129,55,192,8,8,0,194,172,14,0,2,36, - 96,0,226,172,17,0,2,146,0,0,0,0, - 2,0,66,52,17,0,2,162,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 216,255,189,39,20,0,177,175,33,136,128,0, - 28,0,179,175,33,152,160,0,24,0,178,175, - 33,144,224,0,16,0,176,175,56,0,176,143, - 1,0,2,36,46,0,98,22,32,0,191,175, - 0,0,196,140,0,0,0,0,42,0,128,16, - 0,0,0,0,58,25,192,12,0,0,0,0, - 33,32,64,0,37,0,128,16,2,0,2,36, - 11,0,34,18,3,0,34,46,5,0,64,16, - 3,0,2,36,15,0,51,18,4,0,2,36, - 195,55,192,8,33,32,64,2,20,0,34,18, - 33,32,64,2,195,55,192,8,0,0,0,0, - 2,0,2,36,16,0,2,162,17,0,2,146, - 10,0,131,132,2,0,66,52,40,0,3,174, - 197,55,192,8,17,0,2,162,17,0,3,146, - 16,0,2,162,4,0,130,36,44,0,2,174, - 10,0,130,36,40,0,0,166,48,0,2,174, - 191,55,192,8,52,0,0,166,17,0,3,146, - 2,0,2,36,16,0,2,162,40,0,17,174, - 2,0,99,52,197,55,192,8,17,0,3,162, - 33,32,64,2,200,76,192,12,33,40,0,2, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,208,255,189,39,32,0,176,175, - 64,0,176,143,40,0,178,175,33,144,128,0, - 36,0,177,175,33,136,224,0,3,0,160,20, - 44,0,191,175,218,55,192,8,1,0,2,36, - 0,0,194,140,0,0,0,0,1,0,66,36, - 24,0,162,175,24,0,164,143,58,25,192,12, - 0,0,0,0,6,0,64,20,33,32,64,2, - 17,0,2,146,0,0,0,0,18,0,66,52, - 239,55,192,8,17,0,2,162,16,0,176,175, - 1,0,5,36,24,0,166,39,137,55,192,12, - 33,56,32,2,33,32,32,2,33,40,0,2, - 1,0,6,36,253,76,192,12,24,0,167,39, - 44,0,191,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,48,0,189,39, - 232,255,189,39,40,0,168,143,1,0,2,36, - 63,0,162,20,16,0,191,175,0,0,195,140, - 0,0,0,0,59,0,96,16,0,0,0,0, - 24,133,130,143,0,0,0,0,43,16,67,0, - 54,0,64,20,64,18,3,0,2,131,3,60, - 192,246,99,36,33,24,67,0,255,255,132,36, - 5,0,130,44,47,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,136,149,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 2,0,2,36,16,0,2,161,17,0,2,145, - 0,0,195,140,0,0,0,0,43,56,192,8, - 2,0,66,52,2,0,2,36,16,0,2,161, - 17,0,2,145,220,5,3,36,40,0,3,173, - 2,0,66,52,59,56,192,8,17,0,2,161, - 65,0,2,36,16,0,2,161,17,0,2,145, - 156,0,99,140,0,0,0,0,43,56,192,8, - 2,0,66,52,65,0,2,36,16,0,2,161, - 17,0,2,145,172,0,99,140,2,0,66,52, - 40,0,3,173,59,56,192,8,17,0,2,161, - 65,0,2,36,16,0,2,161,156,0,98,140, - 252,0,100,140,17,0,3,145,35,16,68,0, - 2,0,99,52,40,0,2,173,59,56,192,8, - 17,0,3,161,33,32,224,0,200,76,192,12, - 33,40,0,1,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,208,255,189,39, - 32,0,176,175,64,0,176,143,36,0,177,175, - 33,136,224,0,4,0,160,20,40,0,191,175, - 1,0,2,36,86,56,192,8,24,0,162,175, - 0,0,198,140,24,133,130,143,0,0,0,0, - 43,16,194,0,3,0,64,16,1,0,194,36, - 86,56,192,8,24,0,162,175,17,0,2,146, - 0,0,0,0,18,0,66,52,96,56,192,8, - 17,0,2,162,16,0,176,175,1,0,5,36, - 24,0,166,39,245,55,192,12,33,56,32,2, - 33,32,32,2,33,40,0,2,1,0,6,36, - 253,76,192,12,24,0,167,39,40,0,191,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 48,0,189,39,0,0,0,0,0,0,0,0, - 0,0,0,0,200,255,189,39,72,0,163,143, - 44,0,177,175,33,136,128,0,20,0,165,175, - 33,40,224,0,2,131,2,60,172,210,66,140, - 152,132,135,143,33,32,0,0,48,0,191,175, - 40,0,176,175,24,0,160,175,28,0,160,175, - 36,0,160,175,16,0,162,175,104,77,192,12, - 32,0,163,175,33,128,64,0,3,0,0,22, - 33,32,0,2,143,56,192,8,33,16,0,0, - 197,80,192,12,33,40,32,2,255,255,3,36, - 5,0,67,20,0,0,0,0,167,83,192,12, - 33,32,0,2,143,56,192,8,33,16,0,0, - 167,83,192,12,33,32,0,2,8,0,34,142, - 4,0,35,142,0,0,0,0,35,16,67,0, - 255,255,66,48,48,0,191,143,44,0,177,143, - 40,0,176,143,8,0,224,3,56,0,189,39, - 200,255,189,39,44,0,177,175,33,136,128,0, - 72,0,168,143,33,32,0,0,20,0,165,175, - 33,40,224,0,2,131,3,60,172,210,99,140, - 152,132,135,143,1,0,2,36,48,0,191,175, - 40,0,176,175,24,0,162,175,28,0,160,175, - 36,0,160,175,16,0,163,175,104,77,192,12, - 32,0,168,175,33,128,64,0,3,0,0,22, - 33,32,0,2,188,56,192,8,33,16,0,0, - 197,80,192,12,33,40,32,2,255,255,3,36, - 5,0,67,20,0,0,0,0,167,83,192,12, - 33,32,0,2,188,56,192,8,33,16,0,0, - 167,83,192,12,33,32,0,2,8,0,34,142, - 4,0,35,142,0,0,0,0,35,16,67,0, - 255,255,66,48,48,0,191,143,44,0,177,143, - 40,0,176,143,8,0,224,3,56,0,189,39, - 176,255,189,39,44,0,177,175,108,0,177,143, - 68,0,183,175,96,0,183,143,72,0,190,175, - 100,0,190,143,48,0,178,175,33,144,128,0, - 56,0,180,175,33,160,160,0,52,0,179,175, - 33,152,192,0,40,0,176,175,33,128,224,0, - 60,0,181,175,1,0,21,36,76,0,191,175, - 3,0,53,18,64,0,182,175,9,57,192,8, - 255,255,2,36,4,0,6,36,2,131,22,60, - 48,205,214,38,160,132,132,143,104,0,165,143, - 128,32,4,0,80,68,192,12,33,32,150,0, - 33,32,0,0,33,40,0,2,152,132,135,143, - 2,0,2,36,24,0,162,175,160,132,130,143, - 2,131,3,60,172,210,99,140,33,48,96,2, - 20,0,180,175,28,0,160,175,32,0,183,175, - 36,0,181,175,1,0,81,36,104,77,192,12, - 16,0,163,175,33,128,64,0,23,0,0,18, - 33,40,0,0,16,0,190,175,33,32,0,2, - 33,48,32,2,108,84,192,12,33,56,192,2, - 255,255,17,36,13,0,81,16,33,32,0,2, - 197,80,192,12,33,40,64,2,9,0,81,16, - 0,0,0,0,167,83,192,12,33,32,0,2, - 8,0,66,142,4,0,67,142,0,0,0,0, - 35,16,67,0,9,57,192,8,255,255,66,48, - 167,83,192,12,33,32,0,2,33,16,0,0, - 76,0,191,143,72,0,190,143,68,0,183,143, - 64,0,182,143,60,0,181,143,56,0,180,143, - 52,0,179,143,48,0,178,143,44,0,177,143, - 40,0,176,143,8,0,224,3,80,0,189,39, - 176,255,189,39,44,0,177,175,108,0,177,143, - 68,0,183,175,96,0,183,143,72,0,190,175, - 100,0,190,143,48,0,178,175,33,144,128,0, - 56,0,180,175,33,160,160,0,52,0,179,175, - 33,152,192,0,40,0,176,175,33,128,224,0, - 60,0,181,175,1,0,21,36,76,0,191,175, - 3,0,53,18,64,0,182,175,93,57,192,8, - 255,255,2,36,4,0,6,36,2,131,22,60, - 48,205,214,38,160,132,132,143,104,0,165,143, - 128,32,4,0,80,68,192,12,33,32,150,0, - 33,32,0,0,33,40,0,2,152,132,135,143, - 3,0,2,36,24,0,162,175,160,132,130,143, - 2,131,3,60,172,210,99,140,33,48,96,2, - 20,0,180,175,28,0,160,175,32,0,183,175, - 36,0,181,175,1,0,81,36,104,77,192,12, - 16,0,163,175,33,128,64,0,23,0,0,18, - 33,40,0,0,16,0,190,175,33,32,0,2, - 33,48,32,2,108,84,192,12,33,56,192,2, - 255,255,17,36,13,0,81,16,33,32,0,2, - 197,80,192,12,33,40,64,2,9,0,81,16, - 0,0,0,0,167,83,192,12,33,32,0,2, - 8,0,66,142,4,0,67,142,0,0,0,0, - 35,16,67,0,93,57,192,8,255,255,66,48, - 167,83,192,12,33,32,0,2,33,16,0,0, - 76,0,191,143,72,0,190,143,68,0,183,143, - 64,0,182,143,60,0,181,143,56,0,180,143, - 52,0,179,143,48,0,178,143,44,0,177,143, - 40,0,176,143,8,0,224,3,80,0,189,39, - 200,255,189,39,44,0,177,175,33,136,128,0, - 72,0,168,143,33,32,0,0,20,0,165,175, - 33,40,224,0,2,131,3,60,172,210,99,140, - 152,132,135,143,4,0,2,36,48,0,191,175, - 40,0,176,175,24,0,162,175,28,0,160,175, - 36,0,160,175,16,0,163,175,104,77,192,12, - 32,0,168,175,33,128,64,0,3,0,0,22, - 33,32,0,2,145,57,192,8,33,16,0,0, - 197,80,192,12,33,40,32,2,255,255,3,36, - 5,0,67,20,0,0,0,0,167,83,192,12, - 33,32,0,2,145,57,192,8,33,16,0,0, - 167,83,192,12,33,32,0,2,8,0,34,142, - 4,0,35,142,0,0,0,0,35,16,67,0, - 255,255,66,48,48,0,191,143,44,0,177,143, - 40,0,176,143,8,0,224,3,56,0,189,39, - 200,255,189,39,44,0,177,175,33,136,128,0, - 72,0,163,143,33,32,0,0,20,0,165,175, - 33,40,224,0,164,132,135,143,2,131,2,60, - 92,205,66,36,16,0,162,175,6,0,2,36, - 24,0,162,175,1,0,2,36,48,0,191,175, - 40,0,176,175,28,0,162,175,36,0,160,175, - 104,77,192,12,32,0,163,175,33,128,64,0, - 3,0,0,22,33,32,0,2,191,57,192,8, - 33,16,0,0,197,80,192,12,33,40,32,2, - 255,255,3,36,5,0,67,20,0,0,0,0, - 167,83,192,12,33,32,0,2,191,57,192,8, - 33,16,0,0,167,83,192,12,33,32,0,2, - 8,0,34,142,4,0,35,142,0,0,0,0, - 35,16,67,0,255,255,66,48,48,0,191,143, - 44,0,177,143,40,0,176,143,8,0,224,3, - 56,0,189,39,200,255,189,39,44,0,177,175, - 33,136,128,0,72,0,163,143,33,32,0,0, - 20,0,165,175,33,40,224,0,164,132,135,143, - 2,131,2,60,92,205,66,36,16,0,162,175, - 6,0,2,36,24,0,162,175,2,0,2,36, - 48,0,191,175,40,0,176,175,28,0,162,175, - 36,0,160,175,104,77,192,12,32,0,163,175, - 33,128,64,0,3,0,0,22,33,32,0,2, - 237,57,192,8,33,16,0,0,197,80,192,12, - 33,40,32,2,255,255,3,36,5,0,67,20, - 0,0,0,0,167,83,192,12,33,32,0,2, - 237,57,192,8,33,16,0,0,167,83,192,12, - 33,32,0,2,8,0,34,142,4,0,35,142, - 0,0,0,0,35,16,67,0,255,255,66,48, - 48,0,191,143,44,0,177,143,40,0,176,143, - 8,0,224,3,56,0,189,39,0,0,0,0, - 0,0,0,0,224,255,189,39,24,0,178,175, - 33,144,128,0,20,0,177,175,3,131,17,60, - 0,18,49,38,16,0,176,175,33,128,0,0, - 28,0,191,175,208,133,128,175,60,65,192,12, - 33,32,0,2,0,0,34,166,1,0,16,38, - 64,0,2,42,250,255,64,20,2,0,49,38, - 3,131,3,60,18,18,99,144,255,0,2,36, - 3,0,98,16,0,0,0,0,6,0,64,18, - 0,163,4,60,75,59,192,12,32,0,4,36, - 87,59,192,12,255,0,4,36,0,163,4,60, - 220,5,132,52,176,132,133,39,168,71,192,12, - 4,0,6,36,25,0,64,20,0,163,4,60, - 3,131,16,60,20,18,16,38,33,32,0,2, - 176,132,133,39,168,71,192,12,4,0,6,36, - 3,0,64,16,0,163,4,60,7,0,64,18, - 0,0,0,0,220,5,132,52,33,40,0,0, - 144,71,192,12,4,0,6,36,47,58,192,8, - 0,163,4,60,0,163,5,60,220,5,165,52, - 3,0,2,138,0,0,2,154,0,0,0,0, - 3,0,162,168,0,0,162,184,0,163,4,60, - 99,59,192,12,220,5,132,52,0,163,4,60, - 16,6,132,52,176,132,133,39,168,71,192,12, - 4,0,6,36,25,0,64,20,0,163,4,60, - 3,131,16,60,68,18,16,38,33,32,0,2, - 176,132,133,39,168,71,192,12,4,0,6,36, - 3,0,64,16,0,163,4,60,7,0,64,18, - 0,0,0,0,16,6,132,52,33,40,0,0, - 144,71,192,12,4,0,6,36,80,58,192,8, - 0,163,4,60,0,163,5,60,16,6,165,52, - 3,0,2,138,0,0,2,154,0,0,0,0, - 3,0,162,168,0,0,162,184,0,163,4,60, - 119,59,192,12,16,6,132,52,0,163,4,60, - 224,5,132,52,176,132,133,39,168,71,192,12, - 4,0,6,36,25,0,64,20,0,163,4,60, - 3,131,16,60,24,18,16,38,33,32,0,2, - 176,132,133,39,168,71,192,12,4,0,6,36, - 3,0,64,16,0,163,4,60,7,0,64,18, - 0,0,0,0,224,5,132,52,33,40,0,0, - 144,71,192,12,4,0,6,36,113,58,192,8, - 0,163,4,60,0,163,5,60,224,5,165,52, - 3,0,2,138,0,0,2,154,0,0,0,0, - 3,0,162,168,0,0,162,184,0,163,4,60, - 139,59,192,12,224,5,132,52,3,131,3,60, - 28,18,99,36,0,0,98,148,0,0,0,0, - 0,128,66,48,3,0,64,20,1,0,2,36, - 2,0,64,18,0,0,0,0,0,0,98,164, - 0,163,2,60,144,1,66,140,0,0,0,0, - 7,0,64,20,0,0,0,0,3,131,3,60, - 28,18,99,36,0,0,98,148,0,0,0,0, - 146,58,192,8,254,255,66,48,0,163,2,60, - 144,1,66,140,0,0,0,0,7,0,64,24, - 0,0,0,0,3,131,3,60,28,18,99,36, - 0,0,98,148,0,0,0,0,1,0,66,52, - 0,0,98,164,3,131,4,60,28,18,132,148, - 0,0,0,0,159,59,192,12,1,0,132,48, - 3,131,3,60,80,18,99,144,255,0,2,36, - 3,0,98,16,0,0,0,0,5,0,64,18, - 0,0,0,0,2,131,4,60,160,149,132,36, - 205,59,192,12,14,0,5,36,3,131,3,60, - 96,18,99,144,255,0,2,36,3,0,98,16, - 0,0,0,0,5,0,64,18,0,0,0,0, - 2,131,4,60,176,149,132,36,239,59,192,12, - 11,0,5,36,3,131,3,60,112,18,99,144, - 255,0,2,36,3,0,98,16,0,0,0,0, - 5,0,64,18,0,0,0,0,2,131,4,60, - 188,149,132,36,17,60,192,12,15,0,5,36, - 0,163,2,60,140,1,66,140,0,0,0,0, - 7,0,64,16,15,0,2,60,0,163,3,60, - 140,1,99,140,64,66,66,52,43,16,67,0, - 26,0,64,16,0,0,0,0,3,131,3,60, - 64,18,99,140,255,255,2,36,3,0,98,16, - 44,1,2,36,4,0,64,18,0,0,0,0, - 0,163,1,60,221,58,192,8,140,1,34,172, - 5,0,96,20,15,0,4,60,1,0,2,36, - 0,163,1,60,221,58,192,8,140,1,34,172, - 64,66,132,52,43,16,131,0,4,0,64,16, - 0,0,0,0,0,163,1,60,221,58,192,8, - 140,1,36,172,0,163,1,60,140,1,35,172, - 0,163,4,60,140,1,132,140,51,60,192,12, - 0,0,0,0,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,208,255,189,39,20,0,177,175, - 33,136,128,0,36,0,181,175,33,168,160,0, - 28,0,179,175,33,152,192,0,44,0,191,175, - 40,0,182,175,32,0,180,175,24,0,178,175, - 168,71,192,12,16,0,176,175,76,0,64,16, - 0,0,0,0,3,131,22,60,0,18,214,38, - 35,16,54,2,194,31,2,0,33,16,67,0, - 67,144,2,0,1,0,98,38,194,31,2,0, - 33,16,67,0,67,128,2,0,255,255,20,38, - 64,0,130,46,14,0,64,20,64,0,66,46, - 2,131,4,60,204,149,132,36,180,132,144,39, - 33,40,0,2,2,131,7,60,236,149,231,36, - 15,63,192,12,143,0,6,36,1,0,4,36, - 33,40,0,2,188,7,192,12,143,0,6,36, - 64,0,66,46,14,0,64,20,33,32,32,2, - 2,131,4,60,204,149,132,36,180,132,144,39, - 33,40,0,2,2,131,7,60,20,150,231,36, - 15,63,192,12,144,0,6,36,1,0,4,36, - 33,40,0,2,188,7,192,12,144,0,6,36, - 33,32,32,2,33,40,160,2,80,68,192,12, - 33,48,96,2,64,16,18,0,33,136,86,0, - 33,128,128,2,255,255,2,36,25,0,2,18, - 255,255,20,36,180,132,147,39,33,32,64,2, - 208,133,130,143,1,0,82,38,1,0,66,36, - 208,133,130,175,0,0,37,150,0,0,0,0, - 162,65,192,12,2,0,49,38,10,0,64,20, - 33,40,96,2,2,131,4,60,204,149,132,36, - 188,132,135,39,15,63,192,12,159,0,6,36, - 1,0,4,36,33,40,96,2,188,7,192,12, - 159,0,6,36,255,255,16,38,235,255,20,22, - 33,32,64,2,44,0,191,143,40,0,182,143, - 36,0,181,143,32,0,180,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,48,0,189,39,224,255,189,39, - 16,0,164,163,3,131,4,60,18,18,132,36, - 16,0,165,39,24,0,191,175,231,58,192,12, - 1,0,6,36,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,224,255,189,39, - 16,0,164,163,3,131,4,60,19,18,132,36, - 16,0,165,39,24,0,191,175,231,58,192,12, - 1,0,6,36,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,232,255,189,39, - 33,40,128,0,16,0,176,175,3,131,16,60, - 20,18,16,38,33,32,0,2,20,0,191,175, - 231,58,192,12,4,0,6,36,0,163,5,60, - 220,5,165,52,3,0,2,138,0,0,2,154, - 0,0,0,0,3,0,162,168,0,0,162,184, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,232,255,189,39,33,40,128,0, - 16,0,176,175,3,131,16,60,68,18,16,38, - 33,32,0,2,20,0,191,175,231,58,192,12, - 4,0,6,36,0,163,5,60,16,6,165,52, - 3,0,2,138,0,0,2,154,0,0,0,0, - 3,0,162,168,0,0,162,184,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,33,40,128,0,16,0,176,175, - 3,131,16,60,24,18,16,38,33,32,0,2, - 20,0,191,175,231,58,192,12,4,0,6,36, - 0,163,5,60,224,5,165,52,3,0,2,138, - 0,0,2,154,0,0,0,0,3,0,162,168, - 0,0,162,184,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,3,131,2,60, - 28,18,66,148,224,255,189,39,24,0,191,175, - 8,0,128,16,16,0,162,167,1,0,66,52, - 16,0,162,167,1,0,2,36,44,133,130,175, - 0,163,1,60,177,59,192,8,144,1,34,172, - 254,255,66,48,16,0,162,167,44,133,128,175, - 0,163,1,60,144,1,32,172,3,131,4,60, - 28,18,132,36,16,0,165,39,231,58,192,12, - 2,0,6,36,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,3,131,2,60, - 28,18,66,148,224,255,189,39,24,0,191,175, - 3,0,128,16,16,0,162,167,195,59,192,8, - 2,0,66,52,253,255,66,48,16,0,162,167, - 3,131,4,60,28,18,132,36,16,0,165,39, - 231,58,192,12,2,0,6,36,24,0,191,143, - 32,0,189,39,8,0,224,3,0,0,0,0, - 216,255,189,39,32,0,191,175,33,56,128,0, - 33,48,160,0,3,0,226,136,0,0,226,152, - 7,0,227,136,4,0,227,152,11,0,228,136, - 8,0,228,152,15,0,229,136,12,0,229,152, - 19,0,162,171,16,0,162,187,23,0,163,171, - 20,0,163,187,27,0,164,171,24,0,164,187, - 31,0,165,171,28,0,165,187,16,0,194,44, - 3,0,64,16,16,0,163,39,33,16,102,0, - 0,0,64,160,3,131,4,60,80,18,132,36, - 33,40,224,0,231,58,192,12,16,0,6,36, - 32,0,191,143,40,0,189,39,8,0,224,3, - 0,0,0,0,216,255,189,39,32,0,191,175, - 33,56,128,0,33,48,160,0,3,0,226,136, - 0,0,226,152,7,0,227,136,4,0,227,152, - 11,0,228,136,8,0,228,152,15,0,229,136, - 12,0,229,152,19,0,162,171,16,0,162,187, - 23,0,163,171,20,0,163,187,27,0,164,171, - 24,0,164,187,31,0,165,171,28,0,165,187, - 16,0,194,44,3,0,64,16,16,0,163,39, - 33,16,102,0,0,0,64,160,3,131,4,60, - 96,18,132,36,33,40,224,0,231,58,192,12, - 16,0,6,36,32,0,191,143,40,0,189,39, - 8,0,224,3,0,0,0,0,216,255,189,39, - 32,0,191,175,33,56,128,0,33,48,160,0, - 3,0,226,136,0,0,226,152,7,0,227,136, - 4,0,227,152,11,0,228,136,8,0,228,152, - 15,0,229,136,12,0,229,152,19,0,162,171, - 16,0,162,187,23,0,163,171,20,0,163,187, - 27,0,164,171,24,0,164,187,31,0,165,171, - 28,0,165,187,16,0,194,44,3,0,64,16, - 16,0,163,39,33,16,102,0,0,0,64,160, - 3,131,4,60,112,18,132,36,33,40,224,0, - 231,58,192,12,16,0,6,36,32,0,191,143, - 40,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,15,0,2,60,54,66,66,52, - 24,0,164,175,246,255,132,36,43,16,68,0, - 3,0,64,16,16,0,191,175,44,1,2,36, - 24,0,162,175,3,131,4,60,64,18,132,36, - 24,0,165,39,231,58,192,12,4,0,6,36, - 24,0,162,143,0,163,1,60,140,1,34,172, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,232,255,189,39,16,0,191,175, - 0,38,4,0,196,64,192,12,3,38,4,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,232,255,189,39,16,0,191,175, - 0,38,4,0,196,64,192,12,3,38,4,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,160,255,189,39,112,0,162,143, - 72,0,176,175,33,128,224,0,88,0,180,175, - 33,160,0,0,84,0,179,175,33,152,192,0, - 92,0,191,175,80,0,178,175,7,0,160,16, - 76,0,177,175,6,0,65,4,51,0,177,39, - 45,0,20,36,3,0,0,18,35,16,2,0, - 255,255,16,38,51,0,177,39,51,0,160,163, - 27,0,68,0,2,0,128,20,0,0,0,0, - 13,0,7,0,18,24,0,0,16,16,0,0, - 2,131,1,60,33,8,34,0,128,205,34,144, - 255,255,49,38,2,0,0,18,0,0,34,162, - 255,255,16,38,33,16,96,0,241,255,64,20, - 1,0,3,36,0,22,19,0,3,22,2,0, - 11,0,67,20,33,32,128,2,255,255,16,38, - 255,255,2,36,7,0,2,18,0,0,0,0, - 255,255,18,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,18,22,33,32,128,2, - 4,0,128,16,0,22,19,0,196,64,192,12, - 0,0,0,0,0,22,19,0,3,22,2,0, - 2,0,3,36,14,0,67,20,255,255,2,36, - 255,255,16,38,11,0,2,18,255,255,18,36, - 196,64,192,12,48,0,4,36,255,255,16,38, - 6,0,18,18,0,0,0,0,156,60,192,8, - 0,0,0,0,0,38,4,0,196,64,192,12, - 3,38,4,0,0,0,34,130,0,0,36,146, - 0,0,0,0,249,255,64,20,1,0,49,38, - 255,255,49,38,0,22,19,0,3,22,2,0, - 3,0,3,36,9,0,67,20,255,255,16,38, - 255,255,2,36,6,0,2,18,255,255,17,36, - 196,64,192,12,32,0,4,36,255,255,16,38, - 252,255,17,22,0,0,0,0,92,0,191,143, - 88,0,180,143,84,0,179,143,80,0,178,143, - 76,0,177,143,72,0,176,143,8,0,224,3, - 96,0,189,39,200,255,189,39,40,0,178,175, - 33,144,128,0,32,0,176,175,33,128,160,0, - 36,0,177,175,33,136,192,0,33,32,32,2, - 48,0,191,175,156,71,192,12,44,0,179,175, - 33,32,0,0,33,24,64,0,42,16,112,0, - 2,0,64,16,33,152,64,2,35,32,3,2, - 0,22,18,0,3,22,2,0,1,0,3,36, - 11,0,67,20,33,128,128,0,255,255,16,38, - 255,255,2,36,8,0,2,18,0,22,19,0, - 255,255,18,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,18,22,0,0,0,0, - 0,22,19,0,3,22,2,0,2,0,3,36, - 14,0,67,20,255,255,2,36,255,255,16,38, - 11,0,2,18,255,255,18,36,196,64,192,12, - 48,0,4,36,255,255,16,38,6,0,18,18, - 0,0,0,0,233,60,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,34,130,0,0,36,146,0,0,0,0, - 249,255,64,20,1,0,49,38,255,255,49,38, - 0,22,19,0,3,22,2,0,3,0,3,36, - 9,0,67,20,255,255,16,38,255,255,2,36, - 6,0,2,18,255,255,17,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,17,22, - 0,0,0,0,48,0,191,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,56,0,189,39,32,255,189,39, - 192,0,178,175,33,144,160,0,196,0,179,175, - 33,152,0,0,220,0,191,175,216,0,190,175, - 212,0,183,175,208,0,182,175,204,0,181,175, - 200,0,180,175,188,0,177,175,184,0,176,175, - 1,0,130,128,0,0,0,0,229,1,64,16, - 33,136,0,0,255,255,22,36,1,0,23,36, - 2,0,30,36,1,0,149,36,0,0,162,146, - 0,0,0,0,219,255,66,36,0,22,2,0, - 3,30,2,0,84,0,98,44,217,1,64,16, - 128,16,3,0,2,131,1,60,33,8,34,0, - 80,150,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,209,61,192,8,37,0,4,36, - 2,131,16,60,64,150,16,38,156,71,192,12, - 33,32,0,2,59,61,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,2,130,0,0,4,146,0,0,0,0, - 249,255,64,20,1,0,16,38,3,63,192,8, - 1,0,162,38,0,38,18,0,209,61,192,8, - 3,38,4,0,2,0,3,36,33,128,32,2, - 33,40,64,2,33,160,0,0,51,0,177,39, - 51,0,160,163,27,0,163,0,2,0,96,20, - 0,0,0,0,13,0,7,0,18,40,0,0, - 16,16,0,0,2,131,1,60,33,8,34,0, - 128,205,34,144,255,255,49,38,2,0,0,18, - 0,0,34,162,255,255,16,38,242,255,160,20, - 0,0,0,0,10,0,119,22,0,22,20,0, - 255,255,16,38,8,0,22,18,3,38,2,0, - 255,255,18,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,18,22,0,22,20,0, - 3,38,2,0,3,0,128,16,0,0,0,0, - 196,64,192,12,0,0,0,0,14,0,126,22, - 0,0,0,0,255,255,16,38,11,0,22,18, - 255,255,18,36,196,64,192,12,48,0,4,36, - 255,255,16,38,6,0,18,18,0,0,0,0, - 111,61,192,8,0,0,0,0,0,38,4,0, - 196,64,192,12,3,38,4,0,0,0,34,130, - 0,0,36,146,0,0,0,0,249,255,64,20, - 1,0,49,38,255,255,49,38,3,0,6,36, - 80,0,102,22,66,0,4,36,255,255,16,38, - 77,0,22,18,255,255,17,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,17,22, - 66,0,4,36,209,61,192,8,0,0,0,0, - 8,0,3,36,33,128,32,2,33,40,64,2, - 33,160,0,0,51,0,177,39,51,0,160,163, - 27,0,163,0,2,0,96,20,0,0,0,0, - 13,0,7,0,18,40,0,0,16,16,0,0, - 2,131,1,60,33,8,34,0,128,205,34,144, - 255,255,49,38,2,0,0,18,0,0,34,162, - 255,255,16,38,242,255,160,20,0,0,0,0, - 10,0,119,22,0,22,20,0,255,255,16,38, - 8,0,22,18,3,38,2,0,255,255,18,36, - 196,64,192,12,32,0,4,36,255,255,16,38, - 252,255,18,22,0,22,20,0,3,38,2,0, - 3,0,128,16,0,0,0,0,196,64,192,12, - 0,0,0,0,14,0,126,22,0,0,0,0, - 255,255,16,38,11,0,22,18,255,255,18,36, - 196,64,192,12,48,0,4,36,255,255,16,38, - 6,0,18,18,0,0,0,0,182,61,192,8, - 0,0,0,0,0,38,4,0,196,64,192,12, - 3,38,4,0,0,0,34,130,0,0,36,146, - 0,0,0,0,249,255,64,20,1,0,49,38, - 255,255,49,38,3,0,6,36,9,0,102,22, - 81,0,4,36,255,255,16,38,6,0,22,18, - 255,255,17,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,17,22,81,0,4,36, - 196,64,192,12,0,0,0,0,3,63,192,8, - 1,0,162,38,33,128,32,2,33,16,64,2, - 33,160,0,0,5,0,65,6,10,0,4,36, - 45,0,20,36,2,0,32,18,35,16,18,0, - 255,255,48,38,51,0,177,39,51,0,160,163, - 27,0,68,0,2,0,128,20,0,0,0,0, - 13,0,7,0,18,24,0,0,16,16,0,0, - 2,131,1,60,33,8,34,0,128,205,34,144, - 255,255,49,38,2,0,0,18,0,0,34,162, - 255,255,16,38,33,16,96,0,241,255,64,20, - 0,0,0,0,10,0,119,22,33,32,128,2, - 255,255,16,38,7,0,22,18,0,0,0,0, - 255,255,18,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,18,22,33,32,128,2, - 3,0,128,16,0,0,0,0,196,64,192,12, - 0,0,0,0,14,0,126,22,0,0,0,0, - 255,255,16,38,11,0,22,18,255,255,18,36, - 196,64,192,12,48,0,4,36,255,255,16,38, - 6,0,18,18,0,0,0,0,4,62,192,8, - 0,0,0,0,0,38,4,0,196,64,192,12, - 3,38,4,0,0,0,34,130,0,0,36,146, - 0,0,0,0,249,255,64,20,1,0,49,38, - 255,255,49,38,3,0,6,36,237,0,102,22, - 1,0,162,38,255,255,16,38,234,0,22,18, - 255,255,17,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,17,22,1,0,162,38, - 3,63,192,8,0,0,0,0,10,0,3,36, - 33,128,32,2,33,40,64,2,33,160,0,0, - 51,0,177,39,51,0,160,163,27,0,163,0, - 2,0,96,20,0,0,0,0,13,0,7,0, - 18,40,0,0,16,16,0,0,2,131,1,60, - 33,8,34,0,128,205,34,144,255,255,49,38, - 2,0,0,18,0,0,34,162,255,255,16,38, - 242,255,160,20,0,0,0,0,10,0,119,22, - 0,22,20,0,255,255,16,38,8,0,22,18, - 3,38,2,0,255,255,18,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,18,22, - 0,22,20,0,3,38,2,0,3,0,128,16, - 0,0,0,0,196,64,192,12,0,0,0,0, - 14,0,126,22,0,0,0,0,255,255,16,38, - 11,0,22,18,255,255,18,36,196,64,192,12, - 48,0,4,36,255,255,16,38,6,0,18,18, - 0,0,0,0,75,62,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,34,130,0,0,36,146,0,0,0,0, - 249,255,64,20,1,0,49,38,255,255,49,38, - 3,0,6,36,166,0,102,22,1,0,162,38, - 255,255,16,38,163,0,22,18,255,255,17,36, - 196,64,192,12,32,0,4,36,255,255,16,38, - 252,255,17,22,1,0,162,38,3,63,192,8, - 0,0,0,0,192,132,144,39,156,71,192,12, - 33,32,0,2,112,62,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,2,130,0,0,4,146,0,0,0,0, - 249,255,64,20,1,0,16,38,16,0,3,36, - 33,128,32,2,33,40,64,2,33,160,0,0, - 51,0,177,39,51,0,160,163,27,0,163,0, - 2,0,96,20,0,0,0,0,13,0,7,0, - 18,40,0,0,16,16,0,0,2,131,1,60, - 33,8,34,0,128,205,34,144,255,255,49,38, - 2,0,0,18,0,0,34,162,255,255,16,38, - 242,255,160,20,0,0,0,0,10,0,119,22, - 0,22,20,0,255,255,16,38,8,0,22,18, - 3,38,2,0,255,255,18,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,18,22, - 0,22,20,0,3,38,2,0,3,0,128,16, - 0,0,0,0,196,64,192,12,0,0,0,0, - 14,0,126,22,0,0,0,0,255,255,16,38, - 11,0,22,18,255,255,18,36,196,64,192,12, - 48,0,4,36,255,255,16,38,6,0,18,18, - 0,0,0,0,159,62,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,34,130,0,0,36,146,0,0,0,0, - 249,255,64,20,1,0,49,38,255,255,49,38, - 3,0,6,36,82,0,102,22,1,0,162,38, - 255,255,16,38,79,0,22,18,255,255,17,36, - 196,64,192,12,32,0,4,36,255,255,16,38, - 252,255,17,22,1,0,162,38,3,63,192,8, - 0,0,0,0,156,71,192,12,33,32,64,2, - 33,24,64,0,42,16,113,0,2,0,64,16, - 33,32,0,0,35,32,35,2,10,0,119,22, - 33,128,128,0,255,255,16,38,7,0,22,18, - 0,0,0,0,255,255,17,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,17,22, - 0,0,0,0,14,0,126,22,0,0,0,0, - 255,255,16,38,11,0,22,18,255,255,17,36, - 196,64,192,12,48,0,4,36,255,255,16,38, - 6,0,17,18,0,0,0,0,211,62,192,8, - 0,0,0,0,0,38,4,0,196,64,192,12, - 3,38,4,0,0,0,66,130,0,0,68,146, - 0,0,0,0,249,255,64,20,1,0,82,38, - 255,255,82,38,3,0,6,36,30,0,102,22, - 1,0,162,38,255,255,16,38,27,0,22,18, - 255,255,17,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,17,22,1,0,162,38, - 3,63,192,8,0,0,0,0,253,62,192,8, - 3,0,19,36,3,0,96,22,128,16,17,0, - 2,0,19,36,128,16,17,0,33,16,81,0, - 64,16,2,0,0,0,163,130,208,255,66,36, - 2,0,96,22,33,136,67,0,1,0,19,36, - 1,0,181,38,0,0,162,130,0,0,0,0, - 33,254,64,20,0,0,0,0,1,0,130,36, - 220,0,191,143,216,0,190,143,212,0,183,143, - 208,0,182,143,204,0,181,143,200,0,180,143, - 196,0,179,143,192,0,178,143,188,0,177,143, - 184,0,176,143,8,0,224,3,224,0,189,39, - 0,0,164,175,4,0,165,175,8,0,166,175, - 12,0,167,175,200,255,189,39,59,0,162,39, - 252,255,3,36,36,16,67,0,52,0,191,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,56,0,164,175, - 0,0,80,140,4,0,81,36,0,0,2,130, - 0,0,3,146,0,0,0,0,31,0,64,16, - 37,0,20,36,69,0,19,36,252,255,18,36, - 0,22,3,0,3,38,2,0,18,0,148,20, - 0,0,0,0,1,0,3,130,0,0,0,0, - 4,0,100,16,33,32,0,2,4,0,115,20, - 3,0,34,38,33,32,0,2,56,63,192,8, - 33,40,0,0,36,16,82,0,4,0,81,36, - 0,0,69,140,33,32,0,2,13,61,192,12, - 0,0,0,0,62,63,192,8,33,128,64,0, - 196,64,192,12,1,0,16,38,0,0,2,130, - 0,0,3,146,0,0,0,0,230,255,64,20, - 0,22,3,0,52,0,191,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,56,0,189,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,8,0,224,3,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 8,0,224,3,0,0,0,0,33,72,224,3, - 170,3,8,36,76,63,192,12,0,0,0,0, - 255,255,8,33,252,255,0,21,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,8,0,32,1, - 0,0,0,0,33,88,224,3,232,3,10,36, - 143,63,192,12,0,0,0,0,255,255,74,33, - 252,255,64,21,0,0,0,0,8,0,96,1, - 0,0,0,0,250,255,132,32,130,32,4,0, - 255,255,132,32,0,0,0,0,253,255,128,20, - 0,0,0,0,8,0,224,3,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 248,255,189,39,255,255,195,36,10,0,192,16, - 33,56,160,0,255,255,6,36,0,0,162,144, - 1,0,165,36,0,0,130,160,4,0,64,16, - 1,0,132,36,255,255,99,36,249,255,102,20, - 0,0,0,0,33,16,224,0,8,0,224,3, - 8,0,189,39,0,96,2,64,0,0,0,0, - 38,64,68,0,1,255,8,49,38,64,2,1, - 0,96,136,64,8,0,224,3,1,255,66,48, - 0,96,2,64,0,0,0,0,1,255,132,48, - 39,32,128,0,36,64,68,0,0,96,136,64, - 8,0,224,3,1,255,66,48,0,96,2,64, - 0,0,0,0,0,255,132,48,37,64,68,0, - 1,0,8,53,0,96,136,64,8,0,224,3, - 1,255,66,48,176,255,189,39,64,0,182,175, - 33,176,128,0,52,0,179,175,33,152,160,0, - 72,0,190,175,33,240,192,0,68,0,183,175, - 33,184,224,0,60,0,181,175,33,168,0,0, - 56,0,180,175,33,160,0,0,76,0,191,175, - 48,0,178,175,44,0,177,175,40,0,176,175, - 2,131,6,60,33,48,212,0,160,205,198,144, - 0,0,0,0,28,0,96,26,33,128,0,0, - 33,24,192,2,33,32,118,2,0,0,102,160, - 1,0,99,36,42,16,100,0,252,255,64,20, - 0,0,0,0,19,0,96,26,33,128,0,0, - 255,0,210,48,33,136,192,2,0,0,39,146, - 0,0,0,0,9,0,242,16,0,0,0,0, - 5,0,224,18,33,40,0,2,96,0,164,143, - 0,0,0,0,9,248,224,2,33,48,64,2, - 32,0,192,23,1,0,181,38,1,0,16,38, - 42,16,19,2,241,255,64,20,1,0,49,38, - 1,0,148,38,4,0,130,46,220,255,64,20, - 0,0,0,0,7,0,96,26,33,128,0,0, - 33,24,192,2,0,0,112,160,1,0,16,38, - 42,16,19,2,252,255,64,20,1,0,99,36, - 20,0,96,26,33,128,0,0,33,136,192,2, - 0,0,39,146,255,0,6,50,11,0,230,16, - 0,0,0,0,5,0,224,18,0,0,0,0, - 96,0,164,143,0,0,0,0,9,248,224,2, - 33,40,0,2,3,0,192,19,1,0,181,38, - 72,64,192,8,1,0,2,36,1,0,16,38, - 42,16,19,2,239,255,64,20,1,0,49,38, - 33,16,160,2,76,0,191,143,72,0,190,143, - 68,0,183,143,64,0,182,143,60,0,181,143, - 56,0,180,143,52,0,179,143,48,0,178,143, - 44,0,177,143,40,0,176,143,8,0,224,3, - 80,0,189,39,160,255,189,39,88,0,190,175, - 33,240,128,0,68,0,179,175,33,152,160,0, - 76,0,181,175,33,168,224,0,72,0,180,175, - 33,160,0,0,33,16,96,2,92,0,191,175, - 84,0,183,175,80,0,182,175,64,0,178,175, - 60,0,177,175,56,0,176,175,2,0,97,6, - 16,0,166,175,3,0,98,38,131,152,2,0, - 33,184,0,0,2,131,22,60,164,205,214,38, - 0,0,210,142,0,0,0,0,7,0,96,18, - 33,128,0,0,33,24,192,3,0,0,114,172, - 1,0,16,38,43,16,19,2,252,255,64,20, - 4,0,99,36,20,0,96,18,33,128,0,0, - 33,136,192,3,0,0,39,142,0,0,0,0, - 11,0,242,16,128,40,16,0,5,0,160,18, - 0,0,0,0,112,0,164,143,0,0,0,0, - 9,248,160,2,33,48,64,2,16,0,168,143, - 0,0,0,0,34,0,0,21,1,0,148,38, - 1,0,16,38,43,16,19,2,239,255,64,20, - 4,0,49,38,1,0,247,38,4,0,226,46, - 222,255,64,20,4,0,214,38,7,0,96,18, - 33,128,0,0,33,24,192,3,0,0,112,172, - 1,0,16,38,43,16,19,2,252,255,64,20, - 4,0,99,36,22,0,96,18,33,128,0,0, - 33,136,192,3,0,0,39,142,0,0,0,0, - 13,0,240,16,128,40,16,0,5,0,160,18, - 0,0,0,0,112,0,164,143,0,0,0,0, - 9,248,160,2,33,48,0,2,16,0,168,143, - 0,0,0,0,3,0,0,17,1,0,148,38, - 174,64,192,8,1,0,2,36,1,0,16,38, - 43,16,19,2,237,255,64,20,4,0,49,38, - 33,16,128,2,92,0,191,143,88,0,190,143, - 84,0,183,143,80,0,182,143,76,0,181,143, - 72,0,180,143,68,0,179,143,64,0,178,143, - 60,0,177,143,56,0,176,143,8,0,224,3, - 96,0,189,39,0,0,0,0,0,0,0,0, - 255,1,2,36,0,163,1,60,176,1,32,172, - 0,163,1,60,180,1,32,172,0,163,1,60, - 8,0,224,3,184,1,34,172,232,255,189,39, - 16,0,176,175,33,128,128,0,20,0,191,175, - 220,63,192,12,33,32,0,0,33,40,64,0, - 0,163,3,60,180,1,99,140,0,163,2,60, - 184,1,66,140,0,163,4,60,128,1,132,140, - 1,0,99,36,11,0,128,20,36,24,98,0, - 0,163,2,60,176,1,66,140,0,0,0,0, - 6,0,98,20,0,0,0,0,0,163,2,60, - 128,1,66,140,0,0,0,0,247,255,64,16, - 0,0,0,0,0,163,2,60,180,1,66,140, - 33,32,160,0,0,163,1,60,33,8,34,0, - 188,1,48,160,0,163,1,60,220,63,192,12, - 180,1,35,172,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,192,255,189,39,33,80,0,0, - 80,0,185,143,84,0,184,143,88,0,175,143, - 1,0,2,36,60,0,177,175,92,0,177,143, - 4,112,226,0,12,0,224,24,56,0,176,175, - 1,0,9,36,33,64,160,3,33,24,32,3, - 0,0,98,140,4,0,99,36,1,0,74,37, - 4,16,73,0,0,0,2,173,42,16,71,1, - 249,255,64,20,4,0,8,37,46,0,192,25, - 33,80,0,0,255,0,16,36,33,72,0,0, - 0,0,145,172,0,0,160,164,34,0,224,24, - 0,0,208,160,33,88,128,0,33,96,160,0, - 33,104,192,0,33,64,32,3,33,24,160,3, - 0,0,98,140,0,0,0,0,36,16,66,1, - 19,0,64,16,0,0,0,0,0,0,2,141, - 0,0,0,0,128,16,2,0,33,16,88,0, - 0,0,66,140,0,0,0,0,0,0,98,173, - 0,0,2,141,0,0,0,0,64,16,2,0, - 33,16,79,0,0,0,66,148,0,0,0,0, - 0,0,130,165,0,0,2,141,0,0,0,0, - 47,65,192,8,0,0,162,161,4,0,8,37, - 1,0,41,37,42,16,39,1,229,255,64,20, - 4,0,99,36,1,0,198,36,2,0,165,36, - 1,0,74,37,42,16,78,1,213,255,64,20, - 4,0,132,36,60,0,177,143,56,0,176,143, - 8,0,224,3,64,0,189,39,0,0,0,0, - 0,0,0,0,0,0,0,0,216,255,189,39, - 63,0,132,48,28,0,179,175,128,1,147,52, - 50,133,130,151,48,133,132,151,0,128,131,151, - 20,0,177,175,16,0,176,175,5,162,16,60, - 32,0,191,175,24,0,178,175,39,16,68,0, - 36,24,98,0,0,128,131,167,0,0,3,166, - 76,63,192,12,0,1,17,36,0,128,130,151, - 48,133,131,151,5,162,18,60,37,16,67,0, - 0,128,130,167,0,0,2,166,36,16,51,2, - 6,0,64,16,0,0,0,0,0,128,131,151, - 20,133,130,151,0,0,0,0,96,65,192,8, - 37,24,98,0,20,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 0,0,67,166,76,63,192,12,66,136,17,0, - 0,128,130,151,50,133,131,151,0,0,0,0, - 37,16,67,0,0,128,130,167,76,63,192,12, - 0,0,66,166,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,255,255,34,50, - 0,128,131,167,0,0,67,166,226,255,64,20, - 36,16,51,2,33,136,0,0,16,0,16,36, - 5,162,18,60,255,255,19,36,76,63,192,12, - 0,0,0,0,0,128,131,151,50,133,130,151, - 0,0,0,0,37,24,98,0,0,128,131,167, - 76,63,192,12,0,0,67,166,8,0,0,18, - 0,0,0,0,0,0,67,150,20,133,130,151, - 0,0,0,0,36,16,67,0,2,0,64,16, - 64,136,17,0,1,0,49,54,76,63,192,12, - 255,255,16,38,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 230,255,19,22,0,0,67,166,48,133,130,151, - 0,128,131,151,39,16,2,0,36,24,98,0, - 5,162,2,60,0,128,131,167,0,0,67,164, - 255,255,34,50,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,208,255,189,39, - 36,0,181,175,33,168,160,0,32,0,180,175, - 63,0,148,48,33,32,128,2,44,0,191,175, - 40,0,182,175,28,0,179,175,24,0,178,175, - 20,0,177,175,60,65,192,12,16,0,176,175, - 33,152,64,0,255,255,163,50,255,255,98,50, - 3,0,98,20,48,1,22,36,245,66,192,8, - 1,0,2,36,5,162,16,60,50,133,130,151, - 48,133,132,151,0,128,131,151,39,16,68,0, - 36,24,98,0,0,128,131,167,0,0,3,166, - 76,63,192,12,0,1,17,36,0,128,130,151, - 48,133,131,151,5,162,18,60,37,16,67,0, - 0,128,130,167,0,0,2,166,36,16,54,2, - 6,0,64,16,0,0,0,0,0,128,131,151, - 20,133,130,151,0,0,0,0,210,65,192,8, - 37,24,98,0,20,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 0,0,67,166,76,63,192,12,66,136,17,0, - 0,128,130,151,50,133,131,151,0,0,0,0, - 37,16,67,0,0,128,130,167,76,63,192,12, - 0,0,66,166,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,255,255,34,50, - 0,128,131,167,0,0,67,166,226,255,64,20, - 36,16,54,2,255,255,163,50,255,255,98,50, - 39,16,2,0,36,24,98,0,84,0,96,16, - 192,1,147,54,5,162,16,60,50,133,130,151, - 48,133,132,151,0,128,131,151,39,16,68,0, - 36,24,98,0,0,128,131,167,0,0,3,166, - 76,63,192,12,0,1,17,36,0,128,130,151, - 48,133,131,151,5,162,18,60,37,16,67,0, - 0,128,130,167,0,0,2,166,36,16,51,2, - 6,0,64,16,0,0,0,0,0,128,131,151, - 20,133,130,151,0,0,0,0,8,66,192,8, - 37,24,98,0,20,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 0,0,67,166,76,63,192,12,66,136,17,0, - 0,128,130,151,50,133,131,151,0,0,0,0, - 37,16,67,0,0,128,130,167,76,63,192,12, - 0,0,66,166,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,255,255,34,50, - 0,128,131,167,0,0,67,166,226,255,64,20, - 36,16,51,2,5,162,16,60,50,133,130,151, - 48,133,132,151,0,128,131,151,39,16,68,0, - 36,24,98,0,0,128,131,167,76,63,192,12, - 0,0,3,166,0,128,131,151,48,133,130,151, - 0,0,0,0,37,24,98,0,0,0,3,166, - 0,0,4,150,20,133,130,151,0,128,131,167, - 36,16,68,0,9,0,64,20,0,0,0,0, - 76,63,192,12,0,0,0,0,0,0,3,150, - 20,133,130,151,0,0,0,0,36,16,67,0, - 249,255,64,16,0,0,0,0,48,133,130,151, - 0,128,131,151,39,16,2,0,36,24,98,0, - 5,162,2,60,0,128,131,167,0,0,67,164, - 255,255,163,50,255,255,2,52,125,0,98,16, - 64,1,147,54,5,162,16,60,50,133,130,151, - 48,133,132,151,0,128,131,151,39,16,68,0, - 36,24,98,0,0,128,131,167,0,0,3,166, - 76,63,192,12,0,1,17,36,0,128,130,151, - 48,133,131,151,5,162,18,60,37,16,67,0, - 0,128,130,167,0,0,2,166,36,16,51,2, - 6,0,64,16,0,0,0,0,0,128,131,151, - 20,133,130,151,0,0,0,0,95,66,192,8, - 37,24,98,0,20,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 0,0,67,166,76,63,192,12,66,136,17,0, - 0,128,130,151,50,133,131,151,0,0,0,0, - 37,16,67,0,0,128,130,167,76,63,192,12, - 0,0,66,166,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,255,255,34,50, - 0,128,131,167,0,0,67,166,226,255,64,20, - 36,16,51,2,33,144,160,2,0,128,16,52, - 0,128,130,151,48,133,131,151,5,162,17,60, - 37,16,67,0,5,162,3,60,0,128,130,167, - 0,0,98,164,36,16,18,2,6,0,64,16, - 0,0,0,0,0,128,131,151,20,133,130,151, - 0,0,0,0,136,66,192,8,37,24,98,0, - 20,133,130,151,0,128,131,151,39,16,2,0, - 36,24,98,0,0,128,131,167,0,0,35,166, - 76,63,192,12,66,128,16,0,0,128,130,151, - 50,133,131,151,0,0,0,0,37,16,67,0, - 0,128,130,167,76,63,192,12,0,0,34,166, - 50,133,130,151,0,128,131,151,39,16,2,0, - 36,24,98,0,255,255,2,50,0,128,131,167, - 0,0,35,166,226,255,64,20,36,16,18,2, - 5,162,16,60,50,133,130,151,48,133,132,151, - 0,128,131,151,39,16,68,0,36,24,98,0, - 0,128,131,167,76,63,192,12,0,0,3,166, - 0,128,131,151,48,133,130,151,0,0,0,0, - 37,24,98,0,0,0,3,166,0,0,4,150, - 20,133,130,151,0,128,131,167,36,16,68,0, - 9,0,64,20,0,0,0,0,76,63,192,12, - 0,0,0,0,0,0,3,150,20,133,130,151, - 0,0,0,0,36,16,67,0,249,255,64,16, - 0,0,0,0,48,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,5,162,2,60, - 0,128,131,167,0,0,67,164,0,1,19,36, - 5,162,16,60,50,133,130,151,48,133,132,151, - 0,128,131,151,39,16,68,0,36,24,98,0, - 0,128,131,167,0,0,3,166,76,63,192,12, - 0,1,17,36,0,128,130,151,48,133,131,151, - 5,162,18,60,37,16,67,0,0,128,130,167, - 0,0,2,166,36,16,113,2,6,0,64,16, - 0,0,0,0,0,128,131,151,20,133,130,151, - 0,0,0,0,220,66,192,8,37,24,98,0, - 20,133,130,151,0,128,131,151,39,16,2,0, - 36,24,98,0,0,128,131,167,0,0,67,166, - 76,63,192,12,66,136,17,0,0,128,130,151, - 50,133,131,151,0,0,0,0,37,16,67,0, - 0,128,130,167,76,63,192,12,0,0,66,166, - 50,133,130,151,0,128,131,151,39,16,2,0, - 36,24,98,0,255,255,34,50,0,128,131,167, - 0,0,67,166,226,255,64,20,36,16,113,2, - 60,65,192,12,33,32,128,2,38,16,162,2, - 255,255,66,48,1,0,66,44,44,0,191,143, - 40,0,182,143,36,0,181,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,48,0,189,39, - 224,255,189,39,24,0,178,175,33,144,0,0, - 64,16,4,0,16,0,176,175,33,128,68,0, - 33,32,0,2,20,0,177,175,255,255,177,48, - 28,0,191,175,162,65,192,12,33,40,32,2, - 8,0,64,16,1,0,4,38,162,65,192,12, - 33,40,32,2,4,0,64,16,2,0,4,38, - 162,65,192,12,33,40,32,2,43,144,2,0, - 33,16,64,2,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,216,255,189,39,64,16,4,0, - 24,0,178,175,33,144,68,0,33,32,64,2, - 36,0,191,175,32,0,180,175,28,0,179,175, - 20,0,177,175,60,65,192,12,16,0,176,175, - 1,0,84,38,33,32,128,2,60,65,192,12, - 33,136,64,0,2,0,83,38,33,32,96,2, - 60,65,192,12,33,128,64,0,255,255,35,50, - 255,255,17,50,8,0,113,20,0,0,0,0, - 255,255,66,48,3,0,34,18,33,32,96,2, - 162,65,192,12,33,40,32,2,66,67,192,8, - 33,16,32,2,255,255,80,48,4,0,112,16, - 33,32,128,2,5,0,48,22,255,255,2,36, - 33,32,64,2,162,65,192,12,33,40,0,2, - 33,16,0,2,36,0,191,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 0,0,0,0,0,0,0,0,0,96,8,64, - 0,0,0,0,254,255,1,36,36,72,1,1, - 0,96,137,64,0,0,133,164,2,0,132,32, - 2,44,5,0,0,0,133,164,0,96,136,64, - 8,0,224,3,0,0,0,0,208,255,189,39, - 32,0,178,175,33,144,128,0,28,0,177,175, - 33,136,160,0,36,0,179,175,33,152,192,0, - 40,0,180,175,33,160,224,0,44,0,191,175, - 2,0,32,22,24,0,176,175,255,255,17,36, - 0,0,66,142,0,0,0,0,36,16,81,0, - 3,0,83,20,0,0,0,0,121,67,192,8, - 1,0,2,36,11,0,128,26,33,128,0,0, - 143,63,192,12,0,0,0,0,0,0,66,142, - 0,0,0,0,36,16,81,0,246,255,83,16, - 1,0,16,38,42,16,20,2,247,255,64,20, - 0,0,0,0,33,16,0,0,44,0,191,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 48,0,189,39,208,255,189,39,32,0,178,175, - 33,144,128,0,28,0,177,175,33,136,160,0, - 36,0,179,175,33,152,192,0,40,0,180,175, - 33,160,224,0,44,0,191,175,2,0,32,22, - 24,0,176,175,255,255,17,52,0,0,66,150, - 0,0,0,0,36,16,81,0,3,0,83,20, - 0,0,0,0,162,67,192,8,1,0,2,36, - 11,0,128,26,33,128,0,0,143,63,192,12, - 0,0,0,0,0,0,66,150,0,0,0,0, - 36,16,81,0,246,255,83,16,1,0,16,38, - 42,16,20,2,247,255,64,20,0,0,0,0, - 33,16,0,0,44,0,191,143,40,0,180,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,48,0,189,39, - 208,255,189,39,32,0,178,175,33,144,128,0, - 28,0,177,175,33,136,160,0,36,0,179,175, - 33,152,192,0,40,0,180,175,33,160,224,0, - 44,0,191,175,2,0,32,22,24,0,176,175, - 255,0,17,36,0,0,66,146,0,0,0,0, - 36,16,81,0,3,0,83,20,0,0,0,0, - 203,67,192,8,1,0,2,36,11,0,128,26, - 33,128,0,0,143,63,192,12,0,0,0,0, - 0,0,66,146,0,0,0,0,36,16,81,0, - 246,255,83,16,1,0,16,38,42,16,20,2, - 247,255,64,20,0,0,0,0,33,16,0,0, - 44,0,191,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,208,255,189,39, - 32,0,178,175,33,144,128,0,28,0,177,175, - 33,136,160,0,36,0,179,175,33,152,192,0, - 40,0,180,175,33,160,224,0,44,0,191,175, - 2,0,32,22,24,0,176,175,255,255,17,36, - 0,0,66,142,0,0,0,0,36,16,81,0, - 3,0,83,20,0,0,0,0,244,67,192,8, - 1,0,2,36,11,0,128,26,33,128,0,0, - 143,63,192,12,0,0,0,0,0,0,66,142, - 0,0,0,0,36,16,81,0,246,255,83,20, - 1,0,16,38,42,16,20,2,247,255,64,20, - 0,0,0,0,33,16,0,0,44,0,191,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 48,0,189,39,208,255,189,39,32,0,178,175, - 33,144,128,0,28,0,177,175,33,136,160,0, - 36,0,179,175,33,152,192,0,40,0,180,175, - 33,160,224,0,44,0,191,175,2,0,32,22, - 24,0,176,175,255,255,17,52,0,0,66,150, - 0,0,0,0,36,16,81,0,3,0,83,20, - 0,0,0,0,29,68,192,8,1,0,2,36, - 11,0,128,26,33,128,0,0,143,63,192,12, - 0,0,0,0,0,0,66,150,0,0,0,0, - 36,16,81,0,246,255,83,20,1,0,16,38, - 42,16,20,2,247,255,64,20,0,0,0,0, - 33,16,0,0,44,0,191,143,40,0,180,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,48,0,189,39, - 208,255,189,39,32,0,178,175,33,144,128,0, - 28,0,177,175,33,136,160,0,36,0,179,175, - 33,152,192,0,40,0,180,175,33,160,224,0, - 44,0,191,175,2,0,32,22,24,0,176,175, - 255,0,17,36,0,0,66,146,0,0,0,0, - 36,16,81,0,3,0,83,20,0,0,0,0, - 70,68,192,8,1,0,2,36,11,0,128,26, - 33,128,0,0,143,63,192,12,0,0,0,0, - 0,0,66,146,0,0,0,0,36,16,81,0, - 246,255,83,20,1,0,16,38,42,16,20,2, - 247,255,64,20,0,0,0,0,33,16,0,0, - 44,0,191,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,0,0,0,0, - 0,0,0,0,248,255,189,39,255,255,195,36, - 8,0,192,16,33,56,128,0,255,255,6,36, - 0,0,162,144,1,0,165,36,255,255,99,36, - 0,0,130,160,251,255,102,20,1,0,132,36, - 33,16,224,0,8,0,224,3,8,0,189,39, - 0,0,0,0,0,0,0,0,0,96,8,64, - 1,0,9,60,0,96,137,64,15,0,138,48, - 33,40,170,0,192,255,165,36,0,0,128,160, - 16,0,128,160,32,0,128,160,251,255,160,28, - 48,0,128,160,64,0,132,36,0,96,136,64, - 0,0,0,0,0,0,0,0,8,0,224,3, - 0,0,0,0,0,0,0,0,1,131,2,60, - 224,17,66,36,0,32,9,60,37,16,73,0, - 8,0,64,0,0,0,0,0,0,96,8,64, - 3,0,9,60,0,96,137,64,15,0,138,48, - 33,40,170,0,192,255,165,36,0,0,128,160, - 16,0,128,160,32,0,128,160,251,255,160,28, - 48,0,128,160,64,0,132,36,0,96,136,64, - 0,0,0,0,0,0,0,0,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,163,3,60,192,3,99,140, - 0,163,2,60,188,3,66,140,0,0,0,0, - 16,0,98,16,255,255,2,36,0,163,2,60, - 188,3,66,140,0,163,1,60,33,8,34,0, - 200,3,34,144,0,163,3,60,188,3,99,140, - 0,163,4,60,196,3,132,140,0,22,2,0, - 3,22,2,0,1,0,99,36,36,24,100,0, - 0,163,1,60,188,3,35,172,8,0,224,3, - 0,0,0,0,0,163,6,60,0,1,198,52, - 10,0,9,36,255,255,8,36,13,0,7,36, - 0,163,3,60,192,3,99,140,0,163,2,60, - 188,3,66,140,0,0,0,0,17,0,98,16, - 255,255,5,36,0,163,2,60,188,3,66,140, - 0,0,0,0,33,16,70,0,200,2,66,144, - 0,0,0,0,0,22,2,0,3,46,2,0, - 0,163,2,60,188,3,66,140,0,163,3,60, - 196,3,99,140,1,0,66,36,36,16,67,0, - 0,163,1,60,188,3,34,172,11,0,169,16, - 11,0,162,40,5,0,64,16,0,0,0,0, - 228,255,168,16,0,0,0,0,206,68,192,8, - 0,0,133,160,224,255,167,16,0,0,0,0, - 206,68,192,8,0,0,133,160,208,68,192,8, - 0,0,128,160,169,68,192,8,1,0,132,36, - 8,0,224,3,0,0,0,0,0,0,0,0, - 0,0,0,0,208,255,189,39,24,0,176,175, - 33,128,128,0,36,0,179,175,33,152,160,0, - 28,0,177,175,33,136,0,0,32,0,178,175, - 33,144,0,2,5,0,64,22,40,0,191,175, - 54,0,96,22,33,16,0,0,22,69,192,8, - 0,0,32,174,0,0,67,130,0,0,0,0, - 233,68,192,8,32,0,2,36,0,0,3,130, - 32,0,2,36,253,255,98,16,1,0,16,38, - 255,255,16,38,9,0,2,36,249,255,98,16, - 1,0,16,38,255,255,16,38,0,0,3,130, - 45,0,2,36,4,0,98,20,43,0,2,36, - 1,0,16,38,250,68,192,8,1,0,17,36, - 3,0,98,20,33,32,0,2,1,0,16,38, - 33,32,0,2,44,69,192,12,16,0,165,39, - 7,0,96,18,33,24,64,0,16,0,162,143, - 0,0,0,0,2,0,80,20,0,0,0,0, - 33,16,64,2,0,0,98,174,6,0,32,18, - 0,128,2,60,43,16,67,0,5,0,64,20, - 255,127,2,60,19,69,192,8,33,16,96,0, - 5,0,97,4,255,127,2,60,7,0,32,18, - 255,255,66,52,22,69,192,8,0,128,2,60, - 33,16,96,0,2,0,32,18,0,0,0,0, - 35,16,2,0,40,0,191,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,0,0,0,0, - 0,0,0,0,0,0,0,0,208,255,130,36, - 10,0,66,44,7,0,64,20,1,0,2,36, - 191,255,130,36,6,0,66,44,3,0,64,20, - 1,0,2,36,159,255,130,36,6,0,66,44, - 8,0,224,3,0,0,0,0,248,255,189,39, - 0,0,176,175,33,56,0,0,33,72,0,0, - 33,80,0,0,33,112,0,0,5,0,128,20, - 33,200,128,0,110,0,160,20,33,16,0,0, - 163,69,192,8,0,0,192,173,0,0,131,128, - 32,0,2,36,253,255,98,16,1,0,132,36, - 255,255,132,36,9,0,2,36,249,255,98,16, - 1,0,132,36,255,255,132,36,0,0,131,128, - 43,0,2,36,3,0,98,20,45,0,2,36, - 75,69,192,8,1,0,132,36,3,0,98,20, - 0,0,0,0,1,0,132,36,1,0,14,36, - 3,0,192,16,16,0,2,36,16,0,194,20, - 0,0,0,0,0,0,131,128,48,0,2,36, - 9,0,98,20,10,0,2,36,1,0,131,128, - 88,0,2,36,3,0,98,16,120,0,2,36, - 3,0,98,20,8,0,2,36,16,0,2,36, - 2,0,132,36,2,0,192,20,0,0,0,0, - 33,48,64,0,0,0,131,128,255,255,2,36, - 27,0,70,0,2,0,192,20,0,0,0,0, - 13,0,7,0,18,64,0,0,16,192,0,0, - 0,0,0,0,0,0,0,0,42,0,96,16, - 48,0,98,44,48,0,207,36,11,0,205,40, - 87,0,204,36,55,0,203,36,5,0,64,20, - 43,16,111,0,3,0,64,16,0,0,0,0, - 130,69,192,8,208,255,99,36,30,0,160,21, - 97,0,98,44,6,0,64,20,65,0,98,44, - 43,16,108,0,3,0,64,16,65,0,98,44, - 130,69,192,8,169,255,99,36,21,0,64,20, - 43,16,107,0,19,0,64,16,0,0,0,0, - 201,255,99,36,43,16,7,1,6,0,64,20, - 1,0,9,36,6,0,232,20,24,0,230,0, - 43,16,3,3,3,0,64,16,0,0,0,0, - 1,0,10,36,24,0,230,0,1,0,132,36, - 18,128,0,0,33,56,3,2,0,0,131,128, - 0,0,0,0,220,255,96,20,48,0,98,44, - 5,0,64,17,0,0,0,0,13,0,160,16, - 255,255,2,36,163,69,192,8,0,0,164,172, - 6,0,160,16,0,0,0,0,3,0,32,21, - 0,0,0,0,160,69,192,8,0,0,185,172, - 0,0,164,172,2,0,192,17,33,16,224,0, - 35,16,2,0,0,0,176,143,8,0,224,3, - 8,0,189,39,0,0,0,0,0,0,0,0, - 200,255,189,39,16,0,176,175,7,162,16,60, - 236,0,16,54,255,240,3,60,255,255,99,52, - 63,0,132,48,36,0,181,175,128,1,149,52, - 24,0,178,175,0,1,18,36,20,0,177,175, - 7,162,17,60,236,0,49,54,44,0,183,175, - 0,4,23,60,32,0,180,175,255,251,20,60, - 255,255,148,54,40,0,182,175,0,1,22,60, - 28,0,179,175,255,254,19,60,48,0,191,175, - 0,0,2,142,0,0,0,0,36,16,67,0, - 224,133,130,175,0,0,2,174,76,63,192,12, - 255,255,115,54,224,133,130,143,0,2,3,60, - 37,16,67,0,224,133,130,175,0,0,2,174, - 36,16,85,2,5,0,64,16,0,0,0,0, - 224,133,130,143,0,0,0,0,214,69,192,8, - 37,16,87,0,224,133,130,143,0,0,0,0, - 36,16,84,0,224,133,130,175,76,63,192,12, - 0,0,34,174,224,133,130,143,0,0,0,0, - 37,16,86,0,224,133,130,175,0,0,34,174, - 76,63,192,12,66,144,18,0,224,133,130,143, - 0,0,0,0,36,16,83,0,224,133,130,175, - 0,0,34,174,255,255,66,50,230,255,64,20, - 36,16,85,2,33,136,0,0,16,0,16,36, - 7,162,18,60,236,0,82,54,0,1,22,60, - 0,8,21,60,255,254,19,60,255,255,115,54, - 255,255,20,36,76,63,192,12,0,0,0,0, - 224,133,130,143,0,0,0,0,37,16,86,0, - 224,133,130,175,76,63,192,12,0,0,66,174, - 7,0,0,18,0,0,0,0,0,0,66,142, - 0,0,0,0,36,16,85,0,2,0,64,16, - 64,136,17,0,1,0,49,54,76,63,192,12, - 255,255,16,38,224,133,130,143,0,0,0,0, - 36,16,83,0,224,133,130,175,0,0,66,174, - 232,255,20,22,7,162,4,60,236,0,132,52, - 255,253,3,60,224,133,130,143,255,255,99,52, - 36,16,67,0,224,133,130,175,0,0,130,172, - 255,255,34,50,48,0,191,143,44,0,183,143, - 40,0,182,143,36,0,181,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,56,0,189,39, - 200,255,189,39,48,0,190,175,33,240,160,0, - 40,0,182,175,63,0,150,48,33,32,192,2, - 52,0,191,175,44,0,183,175,36,0,181,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 20,0,177,175,168,69,192,12,16,0,176,175, - 33,152,64,0,255,255,195,51,255,255,98,50, - 3,0,98,20,7,162,16,60,131,71,192,8, - 1,0,2,36,236,0,16,54,255,252,3,60, - 255,255,99,52,0,1,18,36,7,162,17,60, - 236,0,49,54,255,251,21,60,255,255,181,54, - 0,1,23,60,255,254,20,60,224,133,130,143, - 0,0,0,0,36,16,67,0,224,133,130,175, - 0,0,2,174,76,63,192,12,255,255,148,54, - 224,133,130,143,0,2,3,60,37,16,67,0, - 224,133,130,175,0,0,2,174,48,1,66,50, - 5,0,64,16,0,4,6,60,224,133,130,143, - 0,0,0,0,83,70,192,8,37,16,70,0, - 224,133,130,143,0,0,0,0,36,16,85,0, - 224,133,130,175,76,63,192,12,0,0,34,174, - 224,133,130,143,0,0,0,0,37,16,87,0, - 224,133,130,175,0,0,34,174,76,63,192,12, - 66,144,18,0,224,133,130,143,0,0,0,0, - 36,16,84,0,224,133,130,175,0,0,34,174, - 255,255,66,50,230,255,64,20,48,1,66,50, - 255,255,195,51,255,255,98,50,39,16,2,0, - 36,24,98,0,88,0,96,16,192,1,213,54, - 7,162,16,60,236,0,16,54,255,252,3,60, - 255,255,99,52,0,1,18,36,7,162,17,60, - 236,0,49,54,255,251,20,60,255,255,148,54, - 0,1,23,60,255,254,19,60,224,133,130,143, - 0,0,0,0,36,16,67,0,224,133,130,175, - 0,0,2,174,76,63,192,12,255,255,115,54, - 224,133,130,143,0,2,3,60,37,16,67,0, - 224,133,130,175,0,0,2,174,36,16,85,2, - 5,0,64,16,0,4,6,60,224,133,130,143, - 0,0,0,0,140,70,192,8,37,16,70,0, - 224,133,130,143,0,0,0,0,36,16,84,0, - 224,133,130,175,76,63,192,12,0,0,34,174, - 224,133,130,143,0,0,0,0,37,16,87,0, - 224,133,130,175,0,0,34,174,76,63,192,12, - 66,144,18,0,224,133,130,143,0,0,0,0, - 36,16,83,0,224,133,130,175,0,0,34,174, - 255,255,66,50,230,255,64,20,36,16,85,2, - 7,162,16,60,236,0,16,54,255,252,3,60, - 224,133,130,143,255,255,99,52,36,16,67,0, - 224,133,130,175,76,63,192,12,0,0,2,174, - 224,133,130,143,0,2,3,60,37,16,67,0, - 224,133,130,175,0,0,2,174,0,0,2,142, - 0,8,3,60,36,16,67,0,11,0,64,20, - 7,162,4,60,7,162,16,60,236,0,16,54, - 0,8,17,60,76,63,192,12,0,0,0,0, - 0,0,2,142,0,0,0,0,36,16,81,0, - 250,255,64,16,7,162,4,60,236,0,132,52, - 255,253,3,60,224,133,130,143,255,255,99,52, - 36,16,67,0,224,133,130,175,0,0,130,172, - 255,255,195,51,255,255,2,52,133,0,98,16, - 64,1,213,54,7,162,16,60,236,0,16,54, - 255,252,3,60,255,255,99,52,0,1,18,36, - 7,162,17,60,236,0,49,54,255,251,20,60, - 255,255,148,54,0,1,23,60,255,254,19,60, - 224,133,130,143,0,0,0,0,36,16,67,0, - 224,133,130,175,0,0,2,174,76,63,192,12, - 255,255,115,54,224,133,130,143,0,2,3,60, - 37,16,67,0,224,133,130,175,0,0,2,174, - 36,16,85,2,5,0,64,16,0,4,6,60, - 224,133,130,143,0,0,0,0,231,70,192,8, - 37,16,70,0,224,133,130,143,0,0,0,0, - 36,16,84,0,224,133,130,175,76,63,192,12, - 0,0,34,174,224,133,130,143,0,0,0,0, - 37,16,87,0,224,133,130,175,0,0,34,174, - 76,63,192,12,66,144,18,0,224,133,130,143, - 0,0,0,0,36,16,83,0,224,133,130,175, - 0,0,34,174,255,255,66,50,230,255,64,20, - 36,16,85,2,33,160,192,3,7,162,2,60, - 236,0,66,52,0,128,17,52,7,162,16,60, - 236,0,16,54,0,4,23,60,255,251,19,60, - 255,255,115,54,0,1,21,60,255,254,18,60, - 255,255,82,54,224,133,131,143,0,2,4,60, - 37,24,100,0,224,133,131,175,0,0,67,172, - 36,16,52,2,5,0,64,16,0,0,0,0, - 224,133,130,143,0,0,0,0,20,71,192,8, - 37,16,87,0,224,133,130,143,0,0,0,0, - 36,16,83,0,224,133,130,175,76,63,192,12, - 0,0,2,174,224,133,130,143,0,0,0,0, - 37,16,85,0,224,133,130,175,0,0,2,174, - 76,63,192,12,66,136,17,0,224,133,130,143, - 0,0,0,0,36,16,82,0,224,133,130,175, - 0,0,2,174,255,255,34,50,230,255,64,20, - 36,16,52,2,7,162,16,60,236,0,16,54, - 255,252,3,60,224,133,130,143,255,255,99,52, - 36,16,67,0,224,133,130,175,76,63,192,12, - 0,0,2,174,224,133,130,143,0,2,3,60, - 37,16,67,0,224,133,130,175,0,0,2,174, - 0,0,2,142,0,8,3,60,36,16,67,0, - 11,0,64,20,7,162,4,60,7,162,16,60, - 236,0,16,54,0,8,17,60,76,63,192,12, - 0,0,0,0,0,0,2,142,0,0,0,0, - 36,16,81,0,250,255,64,16,7,162,4,60, - 236,0,132,52,255,253,3,60,224,133,130,143, - 255,255,99,52,36,16,67,0,224,133,130,175, - 0,0,130,172,7,162,16,60,236,0,16,54, - 255,252,3,60,255,255,99,52,0,1,18,36, - 7,162,17,60,236,0,49,54,0,4,23,60, - 255,251,20,60,255,255,148,54,0,1,21,60, - 255,254,19,60,224,133,130,143,0,0,0,0, - 36,16,67,0,224,133,130,175,0,0,2,174, - 76,63,192,12,255,255,115,54,224,133,130,143, - 0,2,3,60,37,16,67,0,224,133,130,175, - 0,0,2,174,0,1,66,50,5,0,64,16, - 0,0,0,0,224,133,130,143,0,0,0,0, - 108,71,192,8,37,16,87,0,224,133,130,143, - 0,0,0,0,36,16,84,0,224,133,130,175, - 76,63,192,12,0,0,34,174,224,133,130,143, - 0,0,0,0,37,16,85,0,224,133,130,175, - 0,0,34,174,76,63,192,12,66,144,18,0, - 224,133,130,143,0,0,0,0,36,16,83,0, - 224,133,130,175,0,0,34,174,255,255,66,50, - 230,255,64,20,0,1,66,50,168,69,192,12, - 33,32,192,2,38,16,194,3,255,255,66,48, - 1,0,66,44,52,0,191,143,48,0,190,143, - 44,0,183,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 56,0,189,39,0,0,0,0,248,255,189,39, - 255,255,195,36,6,0,192,16,33,16,128,0, - 255,255,6,36,0,0,133,160,255,255,99,36, - 253,255,102,20,1,0,132,36,8,0,189,39, - 8,0,224,3,0,0,0,0,159,71,192,8, - 33,24,0,0,1,0,99,36,0,0,130,128, - 0,0,0,0,252,255,64,20,1,0,132,36, - 8,0,224,3,33,16,96,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,198,36, - 10,0,192,16,0,0,0,0,0,0,131,128, - 0,0,162,128,0,0,0,0,5,0,98,20, - 0,0,0,0,1,0,132,36,255,255,198,36, - 248,255,192,20,1,0,165,36,0,0,131,144, - 0,0,162,144,0,0,0,0,8,0,224,3, - 35,16,98,0,0,0,0,0,0,0,0,0, - 0,0,0,0,196,71,192,8,240,255,189,39, - 0,0,163,128,3,22,2,0,8,0,67,20, - 0,0,0,0,1,0,132,36,1,0,165,36, - 0,0,130,128,0,0,131,144,0,0,0,0, - 246,255,64,20,0,22,3,0,0,0,131,144, - 0,0,162,144,0,0,0,0,35,16,98,0, - 8,0,224,3,16,0,189,39,0,0,0,0, - 255,255,198,36,9,0,192,4,33,16,0,0, - 0,0,130,144,0,0,0,0,5,0,69,16, - 33,16,128,0,255,255,198,36,250,255,193,4, - 1,0,132,36,33,16,0,0,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,2,0,192,20,255,255,2,36, - 1,0,2,36,8,0,224,3,0,0,226,172, - 232,255,189,39,20,0,191,175,16,0,176,175, - 40,0,176,143,33,32,192,0,4,0,5,142, - 0,0,0,0,15,86,192,12,255,255,230,48, - 3,0,64,16,255,255,2,36,243,71,192,8, - 0,0,2,174,0,0,0,174,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 208,255,189,39,40,0,191,175,33,24,128,0, - 64,0,162,143,32,0,160,175,36,0,162,175, - 12,0,66,148,0,0,0,0,2,0,64,20, - 33,32,160,0,120,5,2,36,255,255,66,48, - 16,0,162,175,1,131,2,60,148,31,66,36, - 20,0,162,175,1,131,2,60,128,31,66,36, - 24,0,162,175,32,0,162,39,28,0,162,175, - 166,85,192,12,33,40,96,0,32,0,162,143, - 40,0,191,143,48,0,189,39,8,0,224,3, - 0,0,0,0,0,0,0,0,88,0,131,148, - 4,0,2,36,9,0,98,20,0,0,0,0, - 33,72,192,8,116,0,132,36,33,16,69,0, - 128,16,2,0,8,0,131,140,0,0,0,0, - 46,72,192,8,33,16,67,0,104,0,132,36, - 12,0,128,16,33,16,0,0,4,0,130,140, - 0,0,0,0,42,16,162,0,243,255,64,20, - 0,17,5,0,4,0,130,140,12,0,132,140, - 0,0,0,0,247,255,128,20,35,40,162,0, - 33,16,0,0,8,0,224,3,0,0,0,0, - 88,0,131,148,4,0,2,36,3,0,98,20, - 33,48,0,0,55,72,192,8,116,0,132,36, - 104,0,132,36,8,0,130,140,0,0,0,0, - 43,16,162,0,14,0,64,16,255,255,2,36, - 92,72,192,8,0,0,0,0,35,24,163,0, - 0,17,3,0,35,16,67,0,0,26,2,0, - 33,16,67,0,0,28,2,0,33,16,67,0, - 35,16,2,0,131,16,2,0,92,72,192,8, - 33,16,194,0,18,0,128,16,0,0,0,0, - 4,0,131,140,0,0,0,0,0,17,3,0, - 33,16,67,0,128,16,2,0,8,0,131,140, - 0,0,0,0,33,16,67,0,43,16,162,0, - 233,255,64,20,0,0,0,0,4,0,130,140, - 12,0,132,140,0,0,0,0,241,255,128,20, - 33,48,194,0,255,255,2,36,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 8,0,130,36,144,0,163,140,120,132,135,39, - 2,0,96,16,20,0,137,36,33,56,96,0, - 0,0,72,140,4,0,68,140,132,72,192,8, - 0,0,0,0,30,0,0,25,0,0,0,0, - 4,0,227,140,0,0,0,0,4,0,98,140, - 0,0,0,0,55,0,64,16,255,255,2,36, - 0,0,135,140,0,0,98,140,0,0,0,0, - 8,0,71,16,0,0,0,0,8,0,99,36, - 4,0,98,140,0,0,0,0,248,255,64,20, - 255,255,2,36,168,72,192,8,0,0,0,0, - 0,0,130,140,0,0,0,0,4,0,34,173, - 4,0,103,140,255,255,8,37,4,0,132,36, - 0,0,226,148,0,0,0,0,1,0,66,48, - 226,255,64,16,0,0,0,0,0,0,226,148, - 0,0,0,0,64,0,66,48,27,0,64,20, - 255,255,2,36,0,0,226,148,0,0,0,0, - 1,0,66,48,17,0,64,16,0,0,0,0, - 13,0,192,16,1,0,2,36,64,0,162,140, - 0,0,0,0,9,0,64,20,1,0,2,36, - 28,0,226,140,4,0,163,140,0,0,0,0, - 36,16,67,0,3,0,64,20,1,0,2,36, - 168,72,192,8,255,255,2,36,164,72,192,8, - 0,0,34,165,0,0,32,165,8,0,40,173, - 12,0,36,173,16,0,39,173,33,16,0,0, - 8,0,224,3,0,0,0,0,200,255,189,39, - 48,0,191,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,33,152,128,0, - 33,128,160,0,33,144,192,0,0,0,4,142, - 0,0,0,0,48,0,130,40,2,0,64,16, - 8,0,113,38,48,0,4,36,0,0,36,174, - 9,50,192,12,128,32,4,0,3,0,64,20, - 4,0,34,174,214,72,192,8,255,255,2,36, - 144,0,66,142,120,132,132,39,2,0,64,16, - 0,0,0,0,33,32,64,0,16,0,160,175, - 20,0,179,175,24,0,178,175,0,0,5,142, - 4,0,6,142,0,0,0,0,221,72,192,12, - 33,56,32,2,33,128,64,0,4,0,0,26, - 0,0,0,0,0,0,34,142,214,72,192,8, - 0,0,0,0,110,86,192,12,33,32,32,2, - 33,16,0,2,48,0,191,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,56,0,189,39,184,255,189,39, - 68,0,191,175,64,0,190,175,60,0,183,175, - 56,0,182,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,144,128,0,33,176,160,0, - 33,136,224,0,88,0,183,143,92,0,179,143, - 96,0,190,143,32,0,226,38,0,0,36,142, - 0,0,0,0,42,16,130,0,22,0,64,16, - 33,160,192,0,4,0,132,36,9,50,192,12, - 128,32,4,0,33,128,64,0,3,0,0,22, - 33,32,0,2,153,73,192,8,255,255,2,36, - 0,0,38,142,4,0,37,142,0,0,0,0, - 80,68,192,12,128,48,6,0,4,0,36,142, - 61,50,192,12,0,0,0,0,4,0,48,174, - 0,0,34,142,0,0,0,0,4,0,66,36, - 0,0,34,174,0,0,66,150,0,0,0,0, - 1,0,66,48,96,0,64,20,0,0,0,0, - 33,0,192,30,0,0,0,0,4,0,80,142, - 0,0,0,0,4,0,2,142,0,0,0,0, - 108,0,64,16,128,160,23,0,1,0,242,38, - 4,0,34,142,0,0,0,0,33,16,130,2, - 0,0,3,142,0,0,0,0,0,0,67,172, - 0,0,2,142,0,0,0,0,24,0,98,174, - 16,0,178,175,20,0,179,175,24,0,190,175, - 4,0,4,142,33,40,0,0,33,48,0,0, - 221,72,192,12,33,56,32,2,112,0,64,20, - 8,0,16,38,4,0,2,142,0,0,0,0, - 234,255,64,20,33,16,0,0,153,73,192,8, - 0,0,0,0,4,0,80,142,0,0,0,0, - 4,0,2,142,0,0,0,0,76,0,64,16, - 128,168,23,0,1,0,242,38,0,0,3,142, - 0,0,132,142,0,0,0,0,43,16,100,0, - 42,0,64,20,0,0,0,0,19,0,100,20, - 255,255,197,38,4,0,34,142,0,0,0,0, - 33,16,162,2,0,0,67,172,0,0,2,142, - 0,0,0,0,24,0,98,174,16,0,178,175, - 20,0,179,175,24,0,190,175,4,0,4,142, - 4,0,134,38,221,72,192,12,33,56,32,2, - 25,0,64,16,8,0,16,38,153,73,192,8, - 0,0,0,0,0,0,130,142,0,0,0,0, - 43,16,67,0,17,0,64,16,33,40,0,0, - 4,0,34,142,0,0,0,0,33,16,162,2, - 0,0,67,172,0,0,2,142,0,0,0,0, - 24,0,98,174,16,0,178,175,20,0,179,175, - 24,0,190,175,4,0,4,142,33,48,0,0, - 221,72,192,12,33,56,32,2,52,0,64,20, - 0,0,0,0,8,0,16,38,4,0,2,142, - 0,0,0,0,205,255,64,20,33,16,0,0, - 153,73,192,8,0,0,0,0,0,0,66,150, - 0,0,0,0,64,0,66,48,40,0,64,20, - 33,16,0,0,3,0,66,146,0,0,0,0, - 1,0,66,48,11,0,64,16,33,24,64,2, - 64,0,194,143,0,0,0,0,9,0,64,20, - 0,0,0,0,28,0,98,140,4,0,195,143, - 0,0,0,0,36,16,67,0,3,0,64,20, - 0,0,0,0,153,73,192,8,33,16,0,0, - 14,0,192,26,33,16,246,2,0,0,34,174, - 4,0,36,142,128,128,23,0,33,32,4,2, - 33,40,128,2,80,68,192,12,128,48,22,0, - 28,0,118,174,4,0,34,142,0,0,0,0, - 33,128,2,2,149,73,192,8,32,0,112,174, - 0,0,55,174,28,0,96,174,32,0,96,174, - 36,0,114,174,1,0,2,36,20,0,98,166, - 1,0,2,36,68,0,191,143,64,0,190,143, - 60,0,183,143,56,0,182,143,52,0,181,143, - 48,0,180,143,44,0,179,143,40,0,178,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 72,0,189,39,3,0,160,28,33,16,0,0, - 0,0,224,172,1,0,2,36,8,0,224,3, - 0,0,0,0,208,255,189,39,44,0,191,175, - 40,0,178,175,36,0,177,175,32,0,176,175, - 33,144,128,0,33,136,224,0,64,0,176,143, - 0,0,0,0,6,0,160,24,24,0,160,175, - 17,0,2,146,0,0,0,0,18,0,66,52, - 200,73,192,8,17,0,2,162,33,32,32,2, - 33,40,0,2,1,0,6,36,253,76,192,12, - 24,0,167,39,36,0,2,142,16,0,176,175, - 8,0,66,140,33,32,64,2,1,0,5,36, - 24,0,166,39,9,248,64,0,33,56,32,2, - 44,0,191,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,48,0,189,39, - 224,255,189,39,28,0,191,175,24,0,178,175, - 20,0,177,175,33,144,128,0,33,136,160,0, - 31,0,81,18,16,0,176,175,4,0,80,142, - 0,0,0,0,4,0,2,142,0,0,0,0, - 10,0,64,16,0,0,0,0,4,0,4,142, - 0,0,0,0,206,73,192,12,33,40,32,2, - 8,0,16,38,4,0,2,142,0,0,0,0, - 248,255,64,20,0,0,0,0,0,0,66,150, - 0,0,0,0,32,0,66,48,4,0,64,16, - 0,0,0,0,4,0,68,142,61,50,192,12, - 0,0,0,0,0,0,66,150,0,0,0,0, - 16,0,66,48,3,0,64,16,0,0,0,0, - 61,50,192,12,33,32,64,2,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,120,132,131,39, - 2,0,128,16,0,0,0,0,33,24,128,0, - 0,0,167,140,4,0,165,140,26,74,192,8, - 0,0,0,0,28,0,224,24,0,0,0,0, - 4,0,99,140,0,0,0,0,4,0,98,140, - 0,0,0,0,11,0,64,16,0,0,0,0, - 0,0,164,140,0,0,98,140,0,0,0,0, - 9,0,68,16,0,0,0,0,8,0,99,36, - 4,0,98,140,0,0,0,0,248,255,64,20, - 0,0,0,0,0,0,192,172,33,74,192,8, - 2,0,2,36,4,0,99,140,255,255,231,36, - 4,0,165,36,0,0,98,148,0,0,0,0, - 1,0,66,48,228,255,64,16,0,0,0,0, - 0,0,195,172,42,16,7,0,8,0,224,3, - 0,0,0,0,208,255,189,39,44,0,191,175, - 40,0,182,175,36,0,181,175,32,0,180,175, - 28,0,179,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,168,192,0,0,0,162,140, - 0,0,0,0,3,0,64,28,33,48,0,0, - 220,74,192,8,5,0,2,36,120,132,147,39, - 2,0,128,16,0,0,224,172,33,152,128,0, - 0,0,177,140,4,0,180,140,84,74,192,8, - 0,0,0,0,29,0,32,26,0,0,0,0, - 4,0,102,142,0,0,0,0,4,0,194,140, - 0,0,0,0,23,0,64,16,0,0,0,0, - 0,0,131,142,0,0,194,140,0,0,0,0, - 6,0,67,16,0,0,0,0,8,0,198,36, - 4,0,194,140,0,0,0,0,248,255,64,20, - 0,0,0,0,4,0,194,140,0,0,0,0, - 9,0,64,16,0,0,0,0,255,255,49,38, - 4,0,148,38,33,152,64,0,0,0,98,150, - 0,0,0,0,1,0,66,48,227,255,64,16, - 0,0,0,0,29,0,32,22,0,0,0,0, - 0,0,99,150,0,0,0,0,1,0,98,48, - 11,0,64,16,4,0,98,48,123,0,64,16, - 3,0,2,36,0,0,162,150,0,0,0,0, - 1,0,66,48,118,0,64,16,4,0,2,36, - 0,0,243,172,219,74,192,8,4,0,213,172, - 0,0,98,150,0,0,0,0,4,0,66,48, - 110,0,64,16,3,0,2,36,0,0,162,150, - 0,0,0,0,1,0,66,48,105,0,64,20, - 4,0,2,36,0,0,243,172,219,74,192,8, - 4,0,213,172,0,0,98,150,0,0,0,0, - 1,0,66,48,97,0,64,20,2,0,2,36, - 2,0,34,42,23,0,64,20,33,144,160,2, - 56,0,22,36,9,50,192,12,16,0,4,36, - 33,128,64,0,40,0,0,18,128,16,17,0, - 33,16,84,0,252,255,66,140,0,0,0,0, - 0,0,2,174,4,0,18,174,8,0,0,174, - 12,0,0,174,9,50,192,12,8,0,4,36, - 33,144,64,0,24,0,64,18,255,255,49,38, - 0,0,86,166,2,0,34,42,236,255,64,16, - 4,0,80,174,4,0,102,142,0,0,0,0, - 4,0,194,140,0,0,0,0,6,0,64,16, - 1,0,17,36,8,0,198,36,4,0,194,140, - 0,0,0,0,252,255,64,20,1,0,49,38, - 1,0,36,38,9,50,192,12,192,32,4,0, - 33,128,64,0,12,0,0,22,33,32,64,2, - 173,74,192,8,0,0,0,0,0,0,18,142, - 0,0,0,0,61,50,192,12,33,32,0,2, - 33,32,64,2,206,73,192,12,33,40,160,2, - 220,74,192,8,1,0,2,36,4,0,102,142, - 0,0,0,0,192,74,192,8,33,168,0,2, - 4,0,194,140,0,0,0,0,14,0,64,16, - 0,0,0,0,0,0,194,140,4,0,195,140, - 0,0,2,174,4,0,3,174,8,0,198,36, - 8,0,16,38,255,255,49,38,0,0,194,140, - 0,0,131,142,0,0,0,0,43,16,67,0, - 240,255,64,20,0,0,0,0,0,0,130,142, - 0,0,0,0,0,0,2,174,4,0,18,174, - 8,0,4,38,33,40,192,0,80,68,192,12, - 192,48,17,0,4,0,102,142,4,0,117,174, - 0,0,98,150,0,0,0,0,32,0,66,48, - 3,0,64,16,0,0,0,0,61,50,192,12, - 33,32,192,0,0,0,98,150,0,0,0,0, - 32,0,66,52,0,0,98,166,33,16,0,0, - 44,0,191,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 48,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,0,0,162,140,0,0,0,0, - 85,0,64,24,33,16,0,0,120,132,144,39, - 2,0,128,16,0,0,0,0,33,128,128,0, - 0,0,164,140,4,0,165,140,0,0,0,0, - 0,0,168,140,0,0,2,150,0,0,0,0, - 33,24,64,0,1,0,66,48,34,0,64,20, - 33,56,0,2,32,0,128,24,8,0,98,48, - 4,0,6,142,5,0,64,16,0,0,0,0, - 12,0,194,140,0,0,0,0,3,0,64,16, - 0,0,0,0,33,56,0,2,0,0,168,140, - 0,0,195,140,0,0,162,140,0,0,0,0, - 10,0,98,16,0,0,0,0,0,0,163,140, - 4,0,194,140,0,0,0,0,20,0,64,16, - 8,0,198,36,0,0,194,140,0,0,0,0, - 249,255,67,20,0,0,0,0,255,255,132,36, - 4,0,208,140,0,0,0,0,0,0,3,150, - 0,0,0,0,1,0,98,48,224,255,64,16, - 4,0,165,36,36,0,128,20,33,16,0,0, - 0,0,2,150,0,0,0,0,2,0,66,48, - 3,0,64,20,0,0,0,0,65,75,192,8, - 33,16,0,0,4,0,230,140,0,0,0,0, - 0,0,194,140,0,0,0,0,7,0,72,16, - 0,0,0,0,8,0,198,36,0,0,194,140, - 0,0,0,0,253,255,72,20,8,0,198,36, - 248,255,198,36,4,0,199,140,0,0,0,0, - 10,0,224,16,33,32,224,0,8,0,194,140, - 12,0,195,140,0,0,194,172,4,0,195,172, - 8,0,198,36,4,0,194,140,0,0,0,0, - 248,255,64,20,33,32,224,0,206,73,192,12, - 33,40,0,2,33,16,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 192,255,189,39,56,0,191,175,52,0,181,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,33,136,128,0, - 33,144,160,0,33,152,192,0,33,160,224,0, - 80,0,181,143,0,0,0,0,36,0,162,142, - 0,0,0,0,20,0,80,140,33,32,128,2, - 48,72,192,12,33,40,160,2,16,0,3,142, - 0,0,0,0,16,0,163,175,20,0,180,175, - 24,0,162,175,0,0,2,142,1,0,4,36, - 33,40,32,2,33,48,64,2,9,248,64,0, - 33,56,96,2,6,0,64,20,33,32,128,2, - 17,0,162,146,0,0,0,0,1,0,66,52, - 113,75,192,8,17,0,162,162,33,40,160,2, - 59,77,192,12,33,48,64,0,56,0,191,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,192,255,189,39, - 60,0,191,175,56,0,178,175,52,0,177,175, - 48,0,176,175,33,136,224,0,80,0,178,143, - 36,0,160,175,36,0,66,142,0,0,0,0, - 20,0,67,140,2,0,80,144,0,0,0,0, - 255,0,2,50,254,255,71,36,70,0,226,44, - 110,0,64,16,128,16,7,0,2,131,1,60, - 33,8,34,0,160,151,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,16,0,177,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,2,0,3,36,16,0,67,162, - 251,75,192,8,40,0,66,174,16,0,177,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,40,0,162,175,16,0,80,162, - 40,0,162,143,0,0,0,0,251,75,192,8, - 40,0,66,174,32,0,162,39,16,0,162,175, - 20,0,177,175,36,0,162,39,24,0,162,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,33,48,64,0,16,0,80,162, - 17,0,66,146,0,0,0,0,2,0,66,52, - 17,0,66,162,36,0,162,143,0,0,0,0, - 43,16,2,0,40,0,66,166,44,0,70,174, - 32,0,162,151,0,0,0,0,33,16,194,0, - 48,0,66,174,255,75,192,8,52,0,64,166, - 16,0,177,175,36,0,162,39,20,0,162,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,33,128,64,0,8,0,0,22, - 33,32,32,2,16,0,160,175,33,40,64,2, - 33,48,0,0,226,76,192,12,33,56,0,0, - 255,75,192,8,0,0,0,0,36,0,162,143, - 0,0,0,0,16,0,162,175,0,0,6,142, - 4,0,7,142,0,0,0,0,226,76,192,12, - 33,40,64,2,36,0,162,143,0,0,0,0, - 35,0,64,16,0,0,0,0,61,50,192,12, - 33,32,0,2,255,75,192,8,0,0,0,0, - 5,0,2,36,251,75,192,8,16,0,66,162, - 16,0,177,175,40,0,162,39,20,0,162,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,33,48,64,0,7,0,192,16, - 64,0,2,36,3,0,194,136,0,0,194,152, - 0,0,0,0,43,0,162,171,40,0,162,187, - 64,0,2,36,16,0,66,162,40,0,162,143, - 0,0,0,0,251,75,192,8,40,0,66,174, - 5,0,2,36,96,0,34,174,17,0,66,146, - 0,0,0,0,2,0,66,52,17,0,66,162, - 60,0,191,143,56,0,178,143,52,0,177,143, - 48,0,176,143,8,0,224,3,64,0,189,39, - 80,255,189,39,168,0,191,175,164,0,179,175, - 160,0,178,175,156,0,177,175,152,0,176,175, - 33,152,128,0,33,136,224,0,192,0,178,143, - 0,0,0,0,36,0,66,142,0,0,0,0, - 20,0,67,140,0,0,0,0,16,0,98,140, - 0,0,0,0,16,0,162,175,20,0,177,175, - 4,0,98,140,0,0,0,0,9,248,64,0, - 24,0,167,39,33,128,64,0,6,0,0,22, - 33,32,32,2,17,0,66,146,0,0,0,0, - 18,0,66,52,45,76,192,8,17,0,66,162, - 33,40,64,2,33,48,0,2,253,76,192,12, - 24,0,167,39,16,0,178,175,33,32,96,2, - 33,40,0,2,24,0,166,39,122,75,192,12, - 33,56,32,2,168,0,191,143,164,0,179,143, - 160,0,178,143,156,0,177,143,152,0,176,143, - 8,0,224,3,176,0,189,39,192,255,189,39, - 56,0,191,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,152,128,0,33,160,160,0, - 33,168,192,0,33,136,224,0,80,0,178,143, - 0,0,0,0,36,0,66,142,0,0,0,0, - 20,0,80,140,33,32,32,2,48,72,192,12, - 33,40,64,2,16,0,3,142,0,0,0,0, - 16,0,163,175,20,0,177,175,24,0,162,175, - 0,0,2,142,33,32,0,0,33,40,96,2, - 33,48,128,2,9,248,64,0,33,56,160,2, - 5,0,64,16,33,32,32,2,200,76,192,12, - 33,40,64,2,95,76,192,8,0,0,0,0, - 16,0,178,175,33,32,96,2,33,40,128,2, - 33,48,160,2,122,75,192,12,33,56,32,2, - 56,0,191,143,52,0,181,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,64,0,189,39, - 192,255,189,39,56,0,191,175,52,0,181,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,33,152,128,0, - 33,160,160,0,33,168,192,0,80,0,177,143, - 0,0,0,0,36,0,34,142,0,0,0,0, - 20,0,82,140,2,0,66,144,0,0,0,0, - 254,255,67,36,70,0,98,44,57,0,64,16, - 33,128,224,0,128,16,3,0,2,131,1,60, - 33,8,34,0,184,152,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,33,32,0,2, - 48,72,192,12,33,40,32,2,40,0,35,142, - 0,0,0,0,16,0,163,175,20,0,176,175, - 173,76,192,8,24,0,162,175,33,32,0,2, - 48,72,192,12,33,40,32,2,44,0,35,142, - 0,0,0,0,16,0,163,175,48,0,35,142, - 44,0,36,142,0,0,0,0,35,24,100,0, - 170,76,192,8,255,255,99,48,33,32,0,2, - 48,72,192,12,33,40,32,2,40,0,35,142, - 0,0,0,0,16,0,163,175,44,0,35,142, - 0,0,0,0,171,76,192,8,20,0,163,175, - 33,32,0,2,48,72,192,12,33,40,32,2, - 40,0,35,38,16,0,163,175,4,0,3,36, - 20,0,163,175,24,0,176,175,28,0,162,175, - 12,0,66,142,33,32,96,2,33,40,128,2, - 16,0,71,142,0,0,0,0,9,248,64,0, - 33,48,160,2,184,76,192,8,0,0,0,0, - 5,0,2,36,96,0,2,174,17,0,34,146, - 0,0,0,0,2,0,66,52,17,0,34,162, - 56,0,191,143,52,0,181,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,64,0,189,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 224,255,189,39,24,0,191,175,20,0,177,175, - 16,0,176,175,33,128,128,0,64,0,2,142, - 0,0,0,0,7,0,64,20,33,136,160,0, - 2,0,2,36,48,72,192,12,96,0,2,174, - 1,0,66,36,217,76,192,8,100,0,2,174, - 129,0,2,36,16,0,34,162,17,0,34,146, - 0,0,0,0,2,0,66,52,17,0,34,162, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 33,64,160,0,33,32,192,0,33,40,224,0, - 40,0,162,143,17,0,3,145,0,0,0,0, - 2,0,99,52,17,0,3,161,6,0,3,36, - 4,0,64,16,16,0,3,161,40,0,4,173, - 249,76,192,8,44,0,5,173,80,86,192,12, - 40,0,6,37,2,0,64,16,5,0,2,36, - 96,0,2,174,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,200,255,189,39, - 48,0,191,175,44,0,183,175,40,0,182,175, - 36,0,181,175,32,0,180,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,176,128,0,33,144,160,0,33,152,192,0, - 37,0,96,18,33,184,224,0,28,0,84,38, - 8,0,67,142,28,0,66,142,0,0,0,0, - 35,128,98,0,42,16,83,0,23,0,64,16, - 33,168,19,2,9,50,192,12,128,32,21,0, - 33,136,64,0,8,0,32,22,128,128,16,0, - 5,0,2,36,96,0,194,174,17,0,66,146, - 0,0,0,0,2,0,66,52,48,77,192,8, - 17,0,66,162,33,32,32,2,12,0,69,142, - 0,0,0,0,80,68,192,12,33,48,0,2, - 110,86,192,12,8,0,68,38,12,0,81,174, - 33,128,48,2,4,0,144,174,4,0,132,142, - 33,40,224,2,80,68,192,12,128,48,19,0, - 0,0,147,174,8,0,85,174,48,0,191,143, - 44,0,183,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 56,0,189,39,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,136,128,0, - 5,0,192,24,33,128,160,0,3,0,2,36, - 96,0,34,174,95,77,192,8,100,0,38,174, - 19,0,195,36,19,0,98,44,9,0,64,16, - 128,16,3,0,2,131,1,60,33,8,34,0, - 208,153,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,89,77,192,8,2,0,6,36, - 89,77,192,8,5,0,6,36,89,77,192,8, - 3,0,6,36,89,77,192,8,1,0,6,36, - 35,48,6,0,96,0,38,174,33,32,32,2, - 48,72,192,12,33,40,0,2,1,0,66,36, - 100,0,34,174,17,0,2,146,0,0,0,0, - 1,0,66,52,17,0,2,162,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,200,255,189,39,52,0,191,175, - 48,0,190,175,44,0,183,175,40,0,182,175, - 36,0,181,175,32,0,180,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,152,128,0,33,168,160,0,33,160,192,0, - 76,0,182,143,80,0,183,143,84,0,190,143, - 92,0,177,143,0,0,0,0,209,83,192,12, - 33,144,224,0,33,128,64,0,3,0,0,22, - 4,0,2,36,168,77,192,8,33,16,0,0, - 88,0,2,166,64,0,19,174,33,32,64,2, - 72,0,165,143,0,0,0,0,80,86,192,12, - 92,0,6,38,255,255,3,36,23,0,67,16, - 0,0,0,0,3,0,194,138,0,0,194,154, - 0,0,0,0,103,0,2,170,100,0,2,186, - 104,0,23,174,108,0,30,174,88,0,168,143, - 0,0,0,0,112,0,8,174,72,0,0,166, - 76,0,20,174,255,255,162,50,33,16,130,2, - 80,0,2,174,84,0,0,166,9,0,32,18, - 120,0,17,174,224,83,192,12,33,32,32,2, - 6,0,64,20,124,0,2,174,167,83,192,12, - 33,32,0,2,168,77,192,8,33,16,0,0, - 124,0,0,174,33,16,0,2,52,0,191,143, - 48,0,190,143,44,0,183,143,40,0,182,143, - 36,0,181,143,32,0,180,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,56,0,189,39,224,255,189,39, - 28,0,191,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,144,128,0,92,0,68,142, - 128,86,192,12,0,0,0,0,96,0,68,142, - 0,0,0,0,128,86,192,12,33,128,64,0, - 100,0,68,142,0,0,0,0,128,86,192,12, - 33,136,64,0,33,128,17,2,6,0,16,38, - 33,16,80,0,90,0,66,166,191,79,192,12, - 104,0,68,38,255,255,67,48,90,0,68,150, - 128,0,98,44,5,0,64,20,2,0,130,36, - 0,1,98,44,2,0,64,20,3,0,130,36, - 4,0,130,36,33,16,67,0,90,0,66,166, - 80,0,66,142,76,0,67,142,90,0,80,150, - 64,0,68,142,0,0,0,0,128,86,192,12, - 35,136,67,0,255,255,67,48,90,0,68,150, - 0,0,0,0,128,0,130,44,9,0,64,20, - 0,1,130,44,4,0,64,16,0,0,0,0, - 33,24,112,0,237,77,192,8,6,0,99,36, - 33,24,112,0,237,77,192,8,7,0,99,36, - 33,24,112,0,5,0,99,36,255,255,36,50, - 128,0,130,44,5,0,64,20,1,0,130,36, - 0,1,130,44,2,0,64,20,2,0,130,36, - 3,0,130,36,33,16,98,0,2,0,66,166, - 2,0,67,150,2,0,68,150,0,0,0,0, - 128,0,130,44,6,0,64,20,1,0,99,36, - 0,1,130,44,4,0,64,20,2,0,98,36, - 3,78,192,8,3,0,98,36,1,0,98,36, - 0,0,66,166,0,0,66,150,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,216,255,189,39, - 32,0,191,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,152,128,0, - 171,86,192,12,92,0,100,38,104,0,100,142, - 0,0,0,0,128,86,192,12,33,144,64,0, - 108,0,100,142,0,0,0,0,128,86,192,12, - 33,136,64,0,112,0,100,142,0,0,0,0, - 153,86,192,12,33,128,64,0,10,0,82,38, - 33,136,50,2,33,128,17,2,4,0,16,38, - 33,16,80,0,90,0,98,166,191,79,192,12, - 116,0,100,38,255,255,67,48,90,0,100,150, - 128,0,98,44,5,0,64,20,2,0,130,36, - 0,1,98,44,2,0,64,20,3,0,130,36, - 4,0,130,36,33,16,67,0,90,0,98,166, - 80,0,98,142,76,0,99,142,90,0,113,150, - 64,0,100,142,0,0,0,0,128,86,192,12, - 35,128,67,0,255,255,67,48,90,0,100,150, - 0,0,0,0,128,0,130,44,9,0,64,20, - 0,1,130,44,4,0,64,16,0,0,0,0, - 33,24,113,0,74,78,192,8,6,0,99,36, - 33,24,113,0,74,78,192,8,7,0,99,36, - 33,24,113,0,5,0,99,36,255,255,4,50, - 128,0,130,44,5,0,64,20,1,0,130,36, - 0,1,130,44,2,0,64,20,2,0,130,36, - 3,0,130,36,33,16,98,0,2,0,98,166, - 2,0,99,150,2,0,100,150,0,0,0,0, - 128,0,130,44,6,0,64,20,1,0,99,36, - 0,1,130,44,4,0,64,20,2,0,112,36, - 96,78,192,8,3,0,112,36,1,0,112,36, - 255,255,2,50,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,208,255,189,39, - 40,0,191,175,36,0,179,175,32,0,178,175, - 28,0,177,175,24,0,176,175,33,128,128,0, - 33,152,192,0,33,144,224,0,33,136,160,0, - 16,0,4,36,32,0,5,36,1,131,6,60, - 56,97,198,36,242,86,192,12,33,56,0,2, - 255,255,36,50,1,131,5,60,56,97,165,36, - 44,87,192,12,33,48,0,2,16,0,176,175, - 2,0,4,36,33,40,0,0,1,131,7,60, - 56,97,231,36,94,87,192,12,33,48,96,2, - 8,0,71,142,4,0,66,142,0,0,0,0, - 35,56,226,0,1,131,2,60,56,97,66,36, - 16,0,162,175,20,0,176,175,4,0,4,36, - 33,40,0,0,4,0,70,142,0,0,0,0, - 194,87,192,12,255,255,231,48,40,0,191,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,48,0,189,39, - 216,255,189,39,36,0,191,175,32,0,178,175, - 28,0,177,175,24,0,176,175,33,128,128,0, - 33,136,160,0,88,0,4,150,160,0,5,36, - 1,131,6,60,56,97,198,36,242,86,192,12, - 33,56,32,2,90,0,4,150,1,131,5,60, - 56,97,165,36,44,87,192,12,33,48,32,2, - 16,0,177,175,6,0,4,36,33,40,0,0, - 1,131,7,60,56,97,231,36,15,88,192,12, - 92,0,6,38,1,131,18,60,56,97,82,38, - 16,0,178,175,20,0,177,175,33,32,0,0, - 64,0,5,36,100,0,6,38,194,87,192,12, - 4,0,7,36,16,0,177,175,2,0,4,36, - 33,40,0,0,104,0,6,142,0,0,0,0, - 94,87,192,12,33,56,64,2,16,0,177,175, - 2,0,4,36,33,40,0,0,108,0,6,142, - 0,0,0,0,94,87,192,12,33,56,64,2, - 16,0,177,175,3,0,4,36,64,0,5,36, - 112,0,6,142,0,0,0,0,143,87,192,12, - 33,56,64,2,116,0,4,38,7,79,192,12, - 33,40,32,2,36,0,191,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,216,255,189,39,32,0,191,175, - 28,0,177,175,24,0,176,175,33,128,128,0, - 33,136,160,0,88,0,4,150,160,0,5,36, - 1,131,6,60,56,97,198,36,242,86,192,12, - 33,56,32,2,90,0,4,150,1,131,5,60, - 56,97,165,36,44,87,192,12,33,48,32,2, - 16,0,177,175,2,0,4,36,92,0,6,142, - 1,131,7,60,56,97,231,36,94,87,192,12, - 33,40,0,0,16,0,177,175,2,0,4,36, - 96,0,6,142,1,131,7,60,56,97,231,36, - 94,87,192,12,33,40,0,0,16,0,177,175, - 2,0,4,36,100,0,6,142,1,131,7,60, - 56,97,231,36,94,87,192,12,33,40,0,0, - 104,0,4,38,7,79,192,12,33,40,32,2, - 32,0,191,143,28,0,177,143,24,0,176,143, - 8,0,224,3,40,0,189,39,200,255,189,39, - 52,0,191,175,48,0,180,175,44,0,179,175, - 40,0,178,175,36,0,177,175,32,0,176,175, - 33,144,128,0,33,136,160,0,16,0,4,36, - 32,0,5,36,1,131,6,60,56,97,198,36, - 242,86,192,12,33,56,32,2,0,0,68,150, - 1,131,5,60,56,97,165,36,44,87,192,12, - 33,48,32,2,155,0,64,18,0,0,0,0, - 1,131,20,60,56,97,148,38,8,0,80,142, - 0,0,0,0,145,0,0,18,0,0,0,0, - 4,0,66,142,0,0,0,0,141,0,64,24, - 33,152,0,0,16,0,4,36,32,0,5,36, - 33,48,128,2,242,86,192,12,33,56,32,2, - 4,0,4,150,33,40,128,2,44,87,192,12, - 33,48,32,2,16,0,177,175,6,0,4,36, - 33,40,0,0,8,0,6,38,15,88,192,12, - 33,56,128,2,16,0,3,146,65,0,2,36, - 47,0,98,16,66,0,98,40,18,0,64,16, - 5,0,2,36,88,0,98,16,6,0,98,40, - 7,0,64,16,2,0,2,36,30,0,98,16, - 4,0,2,36,51,0,98,16,4,0,4,36, - 174,79,192,8,1,0,115,38,6,0,2,36, - 68,0,98,16,64,0,2,36,78,0,98,16, - 33,32,0,0,174,79,192,8,1,0,115,38, - 68,0,2,36,47,0,98,16,69,0,98,40, - 7,0,64,16,66,0,2,36,24,0,98,16, - 67,0,2,36,25,0,98,16,3,0,4,36, - 174,79,192,8,1,0,115,38,131,0,98,40, - 83,0,64,16,128,0,98,40,68,0,64,16, - 0,0,0,0,174,79,192,8,1,0,115,38, - 16,0,177,175,2,0,4,36,40,0,6,142, - 1,131,7,60,56,97,231,36,94,87,192,12, - 33,40,0,0,174,79,192,8,1,0,115,38, - 16,0,177,175,111,79,192,8,1,0,4,36, - 16,0,177,175,111,79,192,8,2,0,4,36, - 16,0,177,175,40,0,6,142,1,131,7,60, - 56,97,231,36,143,87,192,12,64,0,5,36, - 174,79,192,8,1,0,115,38,48,0,7,142, - 44,0,2,142,0,0,0,0,35,56,226,0, - 16,0,180,175,20,0,177,175,134,79,192,8, - 33,40,0,0,48,0,7,142,44,0,2,142, - 0,0,0,0,35,56,226,0,16,0,180,175, - 20,0,177,175,4,0,4,36,64,0,5,36, - 44,0,6,142,0,0,0,0,194,87,192,12, - 255,255,231,48,174,79,192,8,1,0,115,38, - 16,0,177,175,6,0,4,36,33,40,0,0, - 1,131,7,60,56,97,231,36,15,88,192,12, - 40,0,6,38,174,79,192,8,1,0,115,38, - 5,0,4,36,164,79,192,8,33,40,0,0, - 16,0,180,175,20,0,177,175,64,0,5,36, - 40,0,6,38,194,87,192,12,4,0,7,36, - 174,79,192,8,1,0,115,38,16,0,4,146, - 16,0,5,146,31,0,132,48,224,0,165,48, - 1,131,6,60,56,97,198,36,242,86,192,12, - 33,56,32,2,33,32,0,0,1,131,5,60, - 56,97,165,36,44,87,192,12,33,48,32,2, - 1,0,115,38,4,0,66,142,0,0,0,0, - 42,16,98,2,117,255,64,20,68,0,16,38, - 12,0,82,142,0,0,0,0,105,255,64,22, - 0,0,0,0,52,0,191,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,56,0,189,39, - 200,255,189,39,52,0,191,175,48,0,182,175, - 44,0,181,175,40,0,180,175,36,0,179,175, - 32,0,178,175,28,0,177,175,24,0,176,175, - 33,168,128,0,33,152,160,2,113,0,160,18, - 33,144,0,0,4,0,22,36,8,0,112,142, - 0,0,0,0,104,0,0,18,0,0,0,0, - 4,0,98,142,0,0,0,0,100,0,64,24, - 33,160,0,0,171,86,192,12,8,0,4,38, - 255,255,67,48,128,0,98,44,5,0,64,20, - 2,0,113,36,0,1,98,44,2,0,64,20, - 3,0,113,36,4,0,113,36,16,0,3,146, - 64,0,2,36,50,0,98,16,65,0,98,40, - 16,0,64,16,68,0,2,36,34,0,118,16, - 5,0,98,40,5,0,64,16,2,0,2,36, - 20,0,98,16,255,255,36,50,22,80,192,8, - 0,0,0,0,5,0,2,36,35,0,98,16, - 6,0,2,36,29,0,98,16,255,255,36,50, - 22,80,192,8,0,0,0,0,19,0,98,16, - 68,0,98,40,12,0,64,20,131,0,98,40, - 28,0,64,16,128,0,98,40,27,0,64,20, - 255,255,36,50,22,80,192,8,18,0,0,166, - 40,0,4,142,128,86,192,12,0,0,0,0, - 21,80,192,8,18,0,2,166,40,0,4,142, - 153,86,192,12,0,0,0,0,21,80,192,8, - 18,0,2,166,48,0,2,142,44,0,3,142, - 0,0,0,0,35,16,67,0,21,80,192,8, - 18,0,2,166,171,86,192,12,40,0,4,38, - 21,80,192,8,18,0,2,166,21,80,192,8, - 18,0,0,166,18,0,22,166,255,255,36,50, - 18,0,3,150,0,0,0,0,128,0,98,44, - 6,0,64,20,1,0,132,36,0,1,98,44, - 4,0,64,20,2,0,98,36,33,80,192,8, - 3,0,98,36,1,0,98,36,33,16,130,0, - 4,0,2,166,4,0,4,150,0,0,0,0, - 1,0,132,36,4,0,3,150,0,0,0,0, - 128,0,98,44,6,0,64,20,255,255,69,50, - 0,1,98,44,4,0,64,20,2,0,162,36, - 49,80,192,8,3,0,162,36,1,0,162,36, - 33,144,68,0,1,0,148,38,4,0,98,142, - 0,0,0,0,42,16,130,2,158,255,64,20, - 68,0,16,38,12,0,115,142,0,0,0,0, - 146,255,96,22,0,0,0,0,0,0,178,166, - 255,255,66,50,52,0,191,143,48,0,182,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,56,0,189,39,224,255,189,39, - 24,0,191,175,20,0,177,175,16,0,176,175, - 33,128,128,0,171,86,192,12,8,0,4,38, - 255,255,67,48,128,0,98,44,5,0,64,20, - 2,0,113,36,0,1,98,44,2,0,64,20, - 3,0,113,36,4,0,113,36,16,0,3,146, - 64,0,2,36,52,0,98,16,65,0,98,40, - 17,0,64,16,4,0,2,36,37,0,98,16, - 0,0,0,0,5,0,98,40,5,0,64,16, - 2,0,2,36,22,0,98,16,255,255,36,50, - 145,80,192,8,0,0,0,0,5,0,2,36, - 36,0,98,16,6,0,2,36,30,0,98,16, - 255,255,36,50,145,80,192,8,0,0,0,0, - 68,0,2,36,20,0,98,16,0,0,0,0, - 68,0,98,40,12,0,64,20,131,0,98,40, - 28,0,64,16,128,0,98,40,27,0,64,20, - 255,255,36,50,145,80,192,8,18,0,0,166, - 40,0,4,142,128,86,192,12,0,0,0,0, - 144,80,192,8,18,0,2,166,40,0,4,142, - 153,86,192,12,0,0,0,0,144,80,192,8, - 18,0,2,166,48,0,2,142,44,0,3,142, - 0,0,0,0,143,80,192,8,35,16,67,0, - 171,86,192,12,40,0,4,38,144,80,192,8, - 18,0,2,166,144,80,192,8,18,0,0,166, - 4,0,2,36,18,0,2,166,255,255,36,50, - 18,0,3,150,0,0,0,0,128,0,98,44, - 6,0,64,20,1,0,132,36,0,1,98,44, - 4,0,64,20,2,0,98,36,156,80,192,8, - 3,0,98,36,1,0,98,36,33,16,130,0, - 4,0,2,166,4,0,3,150,4,0,4,150, - 0,0,0,0,128,0,130,44,6,0,64,20, - 1,0,99,36,0,1,130,44,4,0,64,20, - 2,0,98,36,170,80,192,8,3,0,98,36, - 1,0,98,36,255,255,66,48,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,16,0,191,175, - 64,0,130,140,0,0,0,0,12,0,64,20, - 33,16,0,0,88,0,131,148,4,0,2,36, - 5,0,98,16,0,0,0,0,180,77,192,12, - 0,0,0,0,193,80,192,8,255,255,66,48, - 11,78,192,12,0,0,0,0,255,255,66,48, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,128,128,0, - 176,80,192,12,33,136,160,0,33,32,0,2, - 33,40,32,2,213,80,192,12,255,255,70,48, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,224,255,189,39, - 28,0,191,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,144,128,0,33,136,192,0, - 255,255,34,50,41,0,64,16,33,128,160,0, - 4,0,2,142,0,0,0,0,11,0,64,20, - 255,255,35,50,9,50,192,12,255,255,36,50, - 33,24,64,0,32,0,96,16,1,0,2,36, - 0,0,2,166,4,0,3,174,8,0,3,174, - 242,80,192,8,12,0,17,166,12,0,2,150, - 0,0,0,0,43,16,67,0,23,0,64,20, - 255,255,2,36,64,0,66,142,0,0,0,0, - 19,0,64,20,255,255,2,36,33,32,0,2, - 2,0,69,150,33,48,0,0,104,78,192,12, - 72,0,71,38,88,0,67,150,4,0,2,36, - 5,0,98,16,33,32,64,2,217,78,192,12, - 33,40,0,2,8,81,192,8,33,16,0,0, - 153,78,192,12,33,40,0,2,8,81,192,8, - 33,16,0,0,255,255,2,36,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,0,0,0,0, - 0,0,0,0,168,255,189,39,80,0,191,175, - 76,0,183,175,72,0,182,175,68,0,181,175, - 64,0,180,175,60,0,179,175,56,0,178,175, - 52,0,177,175,48,0,176,175,33,24,128,0, - 33,152,160,0,33,176,192,0,33,184,224,0, - 104,0,162,143,0,0,0,0,2,0,64,20, - 44,0,160,175,40,0,162,39,0,0,64,172, - 24,0,164,39,33,40,96,0,156,88,192,12, - 33,48,96,2,33,136,64,0,82,0,32,18, - 33,16,0,0,209,83,192,12,0,0,0,0, - 33,144,64,0,5,0,64,22,1,0,2,36, - 183,88,192,12,33,32,32,2,124,81,192,8, - 33,16,0,0,148,0,66,162,196,88,192,12, - 33,32,32,2,224,0,85,48,44,0,176,39, - 33,32,32,2,124,89,192,12,33,40,0,2, - 33,160,64,0,33,32,32,2,198,89,192,12, - 33,40,0,2,2,0,66,166,44,0,162,143, - 0,0,0,0,14,0,64,20,0,0,0,0, - 8,0,35,142,4,0,34,142,0,0,0,0, - 35,128,98,0,2,0,66,150,0,0,0,0, - 33,128,2,2,42,16,19,2,16,0,64,20, - 33,32,32,2,42,16,112,2,16,0,64,16, - 0,0,0,0,167,83,192,12,33,32,64,2, - 183,88,192,12,33,32,32,2,3,131,3,60, - 140,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,124,81,192,8, - 33,16,0,0,33,40,0,2,42,89,192,12, - 33,48,0,0,255,0,162,50,255,255,131,50, - 37,16,67,0,48,0,3,36,8,0,67,20, - 33,32,64,2,16,0,176,175,33,40,32,2, - 33,48,192,2,135,81,192,12,33,56,224,2, - 117,81,192,8,33,128,64,0,3,131,3,60, - 140,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,33,128,0,0, - 3,0,0,22,0,0,0,0,167,83,192,12, - 33,32,64,2,183,88,192,12,33,32,32,2, - 33,16,0,2,80,0,191,143,76,0,183,143, - 72,0,182,143,68,0,181,143,64,0,180,143, - 60,0,179,143,56,0,178,143,52,0,177,143, - 48,0,176,143,8,0,224,3,88,0,189,39, - 176,255,189,39,76,0,191,175,72,0,182,175, - 68,0,181,175,64,0,180,175,60,0,179,175, - 56,0,178,175,52,0,177,175,48,0,176,175, - 33,128,128,0,33,136,160,0,33,160,192,0, - 33,168,224,0,96,0,182,143,24,0,160,175, - 33,32,32,2,24,0,165,39,2,0,6,36, - 239,90,192,12,33,56,0,0,64,0,2,174, - 24,0,162,143,0,0,0,0,155,0,64,20, - 0,0,0,0,64,0,2,142,0,0,0,0, - 4,0,64,16,33,32,32,2,3,131,3,60, - 60,82,192,8,148,17,99,36,16,0,160,175, - 72,0,5,38,24,0,166,39,110,90,192,12, - 4,0,7,36,24,0,162,143,0,0,0,0, - 139,0,64,20,0,0,0,0,196,88,192,12, - 33,32,32,2,224,0,66,48,160,0,3,36, - 133,0,67,20,33,32,32,2,124,89,192,12, - 24,0,165,39,33,144,64,0,33,32,32,2, - 198,89,192,12,24,0,165,39,33,152,64,0, - 24,0,162,143,0,0,0,0,122,0,64,20, - 0,0,0,0,255,255,66,50,5,0,66,44, - 118,0,64,16,0,0,0,0,8,0,34,142, - 4,0,35,142,0,0,0,0,35,16,67,0, - 255,255,99,50,33,16,67,0,110,0,194,22, - 33,32,0,2,88,0,18,166,90,0,19,166, - 33,40,128,2,178,50,192,12,33,48,160,2, - 118,0,64,20,33,16,0,0,255,255,67,50, - 4,0,2,36,24,0,98,16,33,32,32,2, - 24,0,165,39,2,0,6,36,239,90,192,12, - 33,56,0,0,92,0,2,174,33,32,32,2, - 24,0,165,39,2,0,6,36,239,90,192,12, - 33,56,0,0,96,0,2,174,33,32,32,2, - 24,0,165,39,2,0,6,36,239,90,192,12, - 33,56,0,0,100,0,2,174,24,0,162,143, - 0,0,0,0,78,0,64,20,33,32,32,2, - 67,82,192,8,104,0,5,38,4,0,2,36, - 88,0,2,166,90,0,19,166,124,0,0,174, - 16,0,160,175,92,0,5,38,24,0,166,39, - 186,91,192,12,6,0,7,36,24,0,162,143, - 0,0,0,0,63,0,64,20,100,0,4,38, - 33,40,0,0,144,71,192,12,4,0,6,36, - 32,0,160,167,40,0,160,175,36,0,160,175, - 44,0,160,167,32,0,178,39,64,0,2,36, - 16,0,162,175,33,32,32,2,33,40,64,2, - 24,0,166,39,110,90,192,12,33,56,0,0, - 24,0,162,143,0,0,0,0,5,0,64,16, - 0,0,0,0,24,92,192,12,33,32,64,2, - 58,82,192,8,0,0,0,0,40,0,162,143, - 36,0,163,143,0,0,0,0,35,16,67,0, - 255,255,70,48,5,0,194,44,2,0,64,20, - 0,0,0,0,4,0,6,36,8,0,192,16, - 33,32,32,2,36,0,165,143,0,0,0,0, - 80,68,192,12,100,0,4,38,24,92,192,12, - 32,0,164,39,33,32,32,2,24,0,165,39, - 2,0,6,36,239,90,192,12,33,56,0,0, - 104,0,2,174,33,32,32,2,24,0,165,39, - 2,0,6,36,239,90,192,12,33,56,0,0, - 108,0,2,174,33,32,32,2,24,0,165,39, - 3,0,6,36,239,90,192,12,64,0,7,36, - 112,0,2,174,24,0,162,143,0,0,0,0, - 9,0,64,16,33,32,32,2,3,131,3,60, - 140,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,73,82,192,8, - 33,16,0,0,116,0,5,38,33,48,192,2, - 163,82,192,12,33,56,0,2,255,255,3,36, - 248,255,67,16,33,16,0,2,76,0,191,143, - 72,0,182,143,68,0,181,143,64,0,180,143, - 60,0,179,143,56,0,178,143,52,0,177,143, - 48,0,176,143,8,0,224,3,80,0,189,39, - 184,255,189,39,64,0,191,175,60,0,183,175, - 56,0,182,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,128,128,0,16,0,160,175, - 8,0,2,142,4,0,3,142,0,0,0,0, - 35,184,67,0,33,144,0,0,255,255,162,48, - 45,0,64,16,33,136,0,0,3,131,19,60, - 140,17,115,38,255,255,22,36,255,255,181,48, - 8,0,3,142,4,0,2,142,0,0,0,0, - 35,160,98,0,0,0,2,146,0,0,0,0, - 128,0,66,48,32,0,64,20,33,32,0,2, - 124,89,192,12,16,0,165,39,33,32,0,2, - 198,89,192,12,16,0,165,39,33,40,64,0, - 16,0,162,143,0,0,0,0,6,0,64,20, - 33,32,0,2,255,255,165,48,251,88,192,12, - 1,0,6,36,7,0,86,20,0,0,0,0, - 0,0,98,142,0,0,0,0,1,0,66,36, - 0,0,98,174,147,82,192,8,255,255,17,36, - 8,0,2,142,4,0,3,142,0,0,0,0, - 35,16,67,0,33,16,66,2,35,144,84,0, - 255,255,66,50,43,16,85,0,217,255,64,20, - 1,0,49,38,33,32,0,2,33,40,224,2, - 251,88,192,12,33,48,0,0,33,16,32,2, - 64,0,191,143,60,0,183,143,56,0,182,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,72,0,189,39,192,255,189,39, - 56,0,191,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,144,128,0,33,152,160,0, - 33,168,224,0,16,0,160,175,124,89,192,12, - 16,0,165,39,33,32,64,2,198,89,192,12, - 16,0,165,39,0,0,98,166,16,0,162,143, - 0,0,0,0,28,0,64,20,0,0,0,0, - 12,0,66,142,8,0,67,142,0,0,0,0, - 35,16,67,0,0,0,99,150,255,255,66,48, - 20,0,98,20,0,0,0,0,4,0,96,174, - 0,0,101,150,0,0,0,0,83,82,192,12, - 33,32,64,2,33,32,64,0,255,255,2,36, - 46,0,130,16,0,0,0,0,3,0,128,20, - 0,0,0,0,246,82,192,8,8,0,96,174, - 224,83,192,12,4,0,100,174,10,0,64,20, - 8,0,98,174,247,82,192,8,255,255,2,36, - 3,131,3,60,140,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,210,82,192,8, - 0,0,98,172,8,0,112,142,4,0,98,142, - 0,0,0,0,23,0,64,24,33,136,0,0, - 255,255,20,36,33,32,64,2,124,89,192,12, - 16,0,165,39,33,32,64,2,198,89,192,12, - 16,0,165,39,4,0,2,166,16,0,162,143, - 0,0,0,0,233,255,64,20,33,32,64,2, - 33,40,0,2,0,83,192,12,33,48,160,2, - 226,255,84,16,1,0,49,38,4,0,98,142, - 0,0,0,0,42,16,34,2,236,255,64,20, - 68,0,16,38,33,16,0,0,56,0,191,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,184,255,189,39, - 68,0,191,175,64,0,180,175,60,0,179,175, - 56,0,178,175,52,0,177,175,48,0,176,175, - 33,128,128,0,33,144,160,0,24,0,160,175, - 16,0,160,175,8,0,69,38,24,0,166,39, - 186,91,192,12,6,0,7,36,24,0,162,143, - 0,0,0,0,103,0,64,20,0,0,0,0, - 196,88,192,12,33,32,0,2,224,0,84,48, - 33,32,0,2,124,89,192,12,24,0,165,39, - 33,152,64,0,33,32,0,2,198,89,192,12, - 24,0,165,39,33,136,64,0,24,0,162,143, - 0,0,0,0,88,0,64,20,37,16,116,2, - 18,0,81,166,16,0,66,162,16,0,67,146, - 64,0,2,36,48,0,98,16,65,0,98,40, - 16,0,64,16,4,0,2,36,31,0,98,16, - 5,0,98,40,5,0,64,16,2,0,2,36, - 22,0,98,16,33,32,0,2,121,83,192,8, - 0,0,0,0,5,0,2,36,65,0,98,16, - 6,0,2,36,27,0,98,16,33,32,0,2, - 121,83,192,8,0,0,0,0,68,0,2,36, - 15,0,98,16,68,0,98,40,8,0,64,20, - 33,32,0,2,131,0,98,40,57,0,64,16, - 128,0,98,40,51,0,64,16,0,0,0,0, - 121,83,192,8,0,0,0,0,255,255,37,50, - 164,90,192,12,24,0,166,39,117,83,192,8, - 40,0,66,174,33,32,0,2,255,255,37,50, - 40,0,70,38,19,90,192,12,24,0,167,39, - 117,83,192,8,0,0,0,0,255,255,37,50, - 40,0,70,38,24,91,192,12,24,0,167,39, - 117,83,192,8,0,0,0,0,40,0,68,38, - 33,40,0,0,144,71,192,12,4,0,6,36, - 32,0,160,167,40,0,160,175,36,0,160,175, - 44,0,160,167,33,32,0,2,255,255,37,50, - 32,0,166,39,19,90,192,12,24,0,167,39, - 40,0,162,143,36,0,163,143,0,0,0,0, - 35,16,67,0,255,255,70,48,5,0,194,44, - 2,0,64,20,0,0,0,0,4,0,6,36, - 7,0,192,16,0,0,0,0,36,0,165,143, - 0,0,0,0,80,68,192,12,40,0,68,38, - 24,92,192,12,32,0,164,39,24,0,162,143, - 0,0,0,0,8,0,64,16,33,16,0,0, - 3,131,3,60,140,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,0,0,98,172, - 255,255,2,36,68,0,191,143,64,0,180,143, - 60,0,179,143,56,0,178,143,52,0,177,143, - 48,0,176,143,8,0,224,3,72,0,189,39, - 232,255,189,39,20,0,191,175,16,0,176,175, - 33,128,128,0,76,0,2,142,0,0,0,0, - 3,0,64,16,0,0,0,0,24,92,192,12, - 72,0,4,38,88,0,3,150,4,0,2,36, - 5,0,98,20,0,0,0,0,110,86,192,12, - 92,0,4,38,157,83,192,8,116,0,4,38, - 13,84,192,12,104,0,4,38,120,0,4,38, - 13,84,192,12,0,0,0,0,148,0,3,146, - 0,0,0,0,248,83,192,12,33,32,0,2, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,33,128,128,0,5,0,0,18, - 0,0,0,0,136,83,192,12,0,0,0,0, - 61,50,192,12,33,32,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 224,255,189,39,24,0,191,175,20,0,177,175, - 16,0,176,175,33,136,128,0,9,50,192,12, - 16,0,4,36,33,128,64,0,11,0,0,18, - 33,32,0,2,33,40,0,0,144,71,192,12, - 16,0,6,36,224,83,192,12,33,32,32,2, - 4,0,64,16,8,0,2,174,4,0,17,174, - 204,83,192,8,33,16,0,2,61,50,192,12, - 33,32,0,2,33,16,0,0,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,9,50,192,12,152,0,4,36, - 33,128,64,0,4,0,0,18,33,16,0,0, - 248,83,192,12,33,32,0,2,33,16,0,2, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,224,255,189,39,24,0,191,175, - 20,0,177,175,0,17,4,0,33,16,68,0, - 128,136,2,0,11,0,32,18,16,0,176,175, - 9,50,192,12,33,32,32,2,33,128,64,0, - 4,0,0,18,33,32,0,2,33,40,0,0, - 144,71,192,12,33,48,32,2,243,83,192,8, - 33,16,0,2,33,16,0,0,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,33,128,128,0,33,40,0,0, - 144,71,192,12,152,0,6,36,255,0,2,36, - 88,0,2,166,120,5,2,36,58,0,2,166, - 72,0,0,166,80,0,0,174,76,0,0,174, - 84,0,0,166,148,0,0,162,149,0,0,162, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,208,255,189,39,40,0,191,175, - 36,0,179,175,32,0,178,175,28,0,177,175, - 24,0,176,175,33,128,128,0,31,0,0,18, - 1,0,19,36,8,0,18,142,0,0,0,0, - 16,0,64,18,0,0,0,0,4,0,2,142, - 0,0,0,0,9,0,64,24,33,136,0,0, - 59,84,192,12,33,32,64,2,1,0,49,38, - 4,0,2,142,0,0,0,0,42,16,34,2, - 249,255,64,20,68,0,82,38,8,0,4,142, - 61,50,192,12,0,0,0,0,12,0,17,142, - 4,0,96,18,0,0,0,0,33,152,0,0, - 49,84,192,8,4,0,0,174,61,50,192,12, - 33,32,0,2,33,128,32,2,227,255,0,22, - 0,0,0,0,40,0,191,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 60,0,2,142,0,0,0,0,4,0,64,16, - 0,0,0,0,9,248,64,0,0,0,0,0, - 60,0,0,174,110,86,192,12,8,0,4,38, - 78,84,192,12,33,32,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,16,0,191,175,16,0,131,144, - 6,0,2,36,18,0,98,16,7,0,98,40, - 5,0,64,16,4,0,2,36,6,0,98,16, - 0,0,0,0,103,84,192,8,0,0,0,0, - 68,0,2,36,11,0,98,20,0,0,0,0, - 44,0,130,140,0,0,0,0,7,0,64,16, - 0,0,0,0,24,92,192,12,40,0,132,36, - 103,84,192,8,0,0,0,0,110,86,192,12, - 40,0,132,36,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,0,0,0,0, - 216,255,189,39,32,0,191,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,136,192,0,56,0,179,143,0,0,0,0, - 20,72,192,12,33,144,224,0,33,128,64,0, - 11,0,0,18,33,32,32,2,33,40,64,2, - 80,86,192,12,8,0,6,38,255,255,3,36, - 5,0,67,16,2,0,2,36,16,0,2,162, - 40,0,19,174,133,84,192,8,33,16,0,0, - 255,255,2,36,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,216,255,189,39, - 32,0,191,175,28,0,177,175,24,0,176,175, - 33,128,128,0,96,0,5,174,100,0,6,174, - 128,0,2,142,0,0,0,0,11,0,64,16, - 0,0,0,0,13,84,192,12,104,0,4,38, - 124,0,2,142,0,0,0,0,108,0,2,174, - 128,0,2,142,0,0,0,0,112,0,2,174, - 128,0,0,174,124,0,0,174,88,0,17,150, - 2,0,2,36,88,0,2,166,176,80,192,12, - 33,32,0,2,33,56,64,0,64,0,2,142, - 0,0,0,0,35,0,64,20,255,255,35,50, - 3,0,2,36,14,0,98,16,255,255,227,48, - 58,0,2,150,0,0,0,0,43,16,67,0, - 9,0,64,16,12,0,4,38,48,0,2,142, - 28,0,5,38,52,0,7,142,0,0,0,0, - 9,248,64,0,1,0,6,36,214,84,192,8, - 0,0,0,0,96,0,2,142,0,0,0,0, - 250,255,67,36,13,0,98,44,13,0,64,16, - 128,16,3,0,2,131,1,60,33,8,34,0, - 32,154,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,204,84,192,8,2,0,2,36, - 204,84,192,8,3,0,2,36,5,0,2,36, - 96,0,2,174,52,0,2,142,0,0,0,0, - 16,0,162,175,44,0,2,142,12,0,4,38, - 28,0,5,38,33,48,0,2,9,248,64,0, - 255,255,231,48,32,0,191,143,28,0,177,143, - 24,0,176,143,8,0,224,3,40,0,189,39, - 224,255,189,39,28,0,191,175,24,0,176,175, - 33,128,128,0,96,0,5,142,0,0,0,0, - 6,0,160,16,0,0,0,0,100,0,6,142, - 140,84,192,12,0,0,0,0,56,85,192,8, - 0,0,0,0,176,80,192,12,33,32,0,2, - 33,56,64,0,88,0,2,150,0,0,0,0, - 2,0,66,44,11,0,64,16,255,255,227,48, - 58,0,2,150,0,0,0,0,43,16,67,0, - 6,0,64,16,33,32,0,2,1,0,5,36, - 140,84,192,12,33,48,0,0,56,85,192,8, - 0,0,0,0,96,0,2,142,0,0,0,0, - 49,0,64,20,2,0,2,36,88,0,3,150, - 3,0,2,36,33,0,98,16,4,0,98,40, - 7,0,64,16,2,0,98,40,41,0,64,16, - 2,0,2,36,39,0,96,4,0,0,0,0, - 13,85,192,8,0,0,0,0,5,0,2,36, - 34,0,98,20,2,0,2,36,3,131,3,60, - 236,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,104,0,4,38,25,0,128,16, - 0,0,98,172,3,131,5,60,176,17,165,36, - 0,0,162,140,108,0,3,142,0,0,0,0, - 33,16,67,0,0,0,162,172,12,0,132,140, - 0,0,0,0,248,255,128,20,2,0,2,36, - 47,85,192,8,88,0,2,166,3,131,4,60, - 236,17,132,36,0,0,130,140,0,0,0,0, - 1,0,66,36,0,0,130,172,200,255,130,140, - 108,0,3,142,0,0,0,0,33,16,67,0, - 200,255,130,172,2,0,2,36,88,0,2,166, - 52,0,2,142,0,0,0,0,16,0,162,175, - 44,0,2,142,12,0,4,38,28,0,5,38, - 33,48,0,2,9,248,64,0,255,255,231,48, - 28,0,191,143,24,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,33,128,128,0,88,0,3,150, - 1,0,2,36,25,0,98,16,2,0,98,40, - 5,0,64,16,3,0,2,36,7,0,96,16, - 0,0,0,0,116,85,192,8,0,0,0,0, - 37,0,98,16,0,0,0,0,116,85,192,8, - 0,0,0,0,112,0,4,142,108,0,3,142, - 0,0,0,0,34,0,96,16,0,0,0,0, - 17,0,130,144,0,0,0,0,2,0,66,48, - 33,0,64,16,255,255,99,36,250,255,96,20, - 68,0,132,36,116,85,192,8,0,0,0,0, - 112,0,4,142,108,0,3,142,0,0,0,0, - 8,0,96,16,0,0,0,0,17,0,130,144, - 0,0,0,0,2,0,66,48,19,0,64,16, - 255,255,99,36,250,255,96,20,68,0,132,36, - 118,93,192,12,33,32,0,2,241,255,64,28, - 255,255,66,40,7,0,64,16,0,0,0,0, - 92,85,192,8,0,0,0,0,120,94,192,12, - 33,32,0,2,5,0,64,20,0,0,0,0, - 219,84,192,12,33,32,0,2,167,83,192,12, - 33,32,0,2,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 88,0,3,150,1,0,2,36,17,0,98,16, - 2,0,98,40,5,0,64,16,3,0,2,36, - 9,0,96,16,0,0,0,0,156,85,192,8, - 0,0,0,0,13,0,98,16,5,0,2,36, - 7,0,98,16,0,0,0,0,156,85,192,8, - 0,0,0,0,60,95,192,12,33,32,0,2, - 154,85,192,8,0,0,0,0,0,93,192,12, - 33,32,0,2,154,85,192,8,0,0,0,0, - 252,93,192,12,33,32,0,2,5,0,64,20, - 0,0,0,0,60,85,192,12,33,32,0,2, - 162,85,192,8,0,0,0,0,167,83,192,12, - 33,32,0,2,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,192,255,189,39, - 60,0,191,175,56,0,182,175,52,0,181,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,33,64,128,0, - 33,136,192,0,33,152,224,0,84,0,182,143, - 88,0,181,143,92,0,180,143,80,0,178,151, - 3,131,3,60,128,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,0,0,98,172, - 24,0,162,39,16,0,162,175,33,32,160,0, - 16,81,192,12,33,40,0,1,33,128,64,0, - 57,0,0,18,255,255,66,50,58,0,3,150, - 0,0,0,0,43,16,67,0,2,0,64,16, - 0,0,0,0,58,0,18,166,44,0,22,174, - 48,0,21,174,52,0,20,174,24,0,162,143, - 0,0,0,0,7,0,64,16,1,0,2,36, - 219,84,192,12,33,32,0,2,167,83,192,12, - 33,32,0,2,5,86,192,8,0,0,0,0, - 88,0,3,150,0,0,0,0,16,0,98,16, - 2,0,98,40,5,0,64,16,3,0,2,36, - 9,0,96,16,0,0,0,0,244,85,192,8, - 0,0,0,0,11,0,98,16,5,0,2,36, - 31,0,98,16,0,0,0,0,244,85,192,8, - 0,0,0,0,3,131,3,60,239,85,192,8, - 184,17,99,36,3,131,3,60,239,85,192,8, - 188,17,99,36,3,131,3,60,192,17,99,36, - 0,0,98,140,0,0,0,0,1,0,66,36, - 3,86,192,8,0,0,98,172,3,131,3,60, - 140,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,167,83,192,12, - 33,32,0,2,33,32,32,2,33,40,96,2, - 1,0,6,36,9,248,160,2,33,56,128,2, - 5,86,192,8,0,0,0,0,124,85,192,12, - 33,32,0,2,60,0,191,143,56,0,182,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 213,80,192,12,255,255,198,48,53,0,64,20, - 255,255,2,36,3,131,3,60,144,17,99,36, - 0,0,98,140,0,0,0,0,1,0,66,36, - 0,0,98,172,96,0,2,142,0,0,0,0, - 32,0,64,16,4,0,2,36,92,0,98,140, - 0,0,0,0,1,0,66,36,92,0,98,172, - 96,0,2,142,0,0,0,0,255,255,67,36, - 5,0,98,44,32,0,64,16,128,16,3,0, - 2,131,1,60,33,8,34,0,88,154,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 3,131,3,60,70,86,192,8,204,17,99,36, - 3,131,3,60,70,86,192,8,212,17,99,36, - 3,131,3,60,70,86,192,8,216,17,99,36, - 3,131,3,60,70,86,192,8,208,17,99,36, - 3,131,3,60,70,86,192,8,220,17,99,36, - 88,0,3,150,0,0,0,0,8,0,98,20, - 33,16,0,0,3,131,3,60,240,17,99,36, - 0,0,98,140,0,0,0,0,1,0,66,36, - 0,0,98,172,33,16,0,0,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 0,0,0,0,224,255,189,39,28,0,191,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,144,160,0,33,128,192,0,4,0,0,174, - 14,0,128,16,0,0,4,174,128,136,4,0, - 9,50,192,12,33,32,32,2,3,0,64,20, - 4,0,2,174,104,86,192,8,255,255,2,36, - 5,0,32,18,33,40,64,2,4,0,4,142, - 0,0,0,0,80,68,192,12,33,48,32,2, - 33,16,0,0,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,33,128,128,0,4,0,4,142, - 0,0,0,0,4,0,128,16,0,0,0,0, - 61,50,192,12,0,0,0,0,4,0,0,174, - 0,0,0,174,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,0,0,0,0, - 0,0,0,0,11,0,128,4,128,0,130,40, - 20,0,64,20,1,0,3,36,255,127,2,36, - 42,16,68,0,16,0,64,16,2,0,3,36, - 127,0,2,60,255,255,66,52,148,86,192,8, - 42,16,68,0,128,255,130,40,9,0,64,16, - 1,0,3,36,0,128,130,40,6,0,64,16, - 2,0,3,36,128,255,2,60,42,16,130,0, - 2,0,64,20,4,0,3,36,3,0,3,36, - 8,0,224,3,33,16,96,0,128,0,130,44, - 14,0,64,20,1,0,2,36,255,127,2,36, - 43,16,68,0,9,0,64,16,127,0,2,60, - 255,255,66,52,43,16,68,0,6,0,64,16, - 3,0,2,36,4,0,128,4,5,0,2,36, - 169,86,192,8,4,0,2,36,2,0,2,36, - 8,0,224,3,0,0,0,0,4,0,135,140, - 0,0,130,140,0,0,0,0,65,0,64,16, - 33,16,0,0,0,0,227,140,4,0,231,36, - 128,16,3,0,33,16,67,0,192,16,2,0, - 0,0,227,140,0,0,0,0,33,24,67,0, - 128,0,98,44,17,0,64,20,4,0,231,36, - 0,64,98,44,15,0,64,20,2,0,5,36, - 31,0,2,60,255,255,66,52,43,16,67,0, - 7,0,64,16,255,15,2,60,255,255,66,52, - 43,16,67,0,6,0,64,20,5,0,5,36, - 204,86,192,8,4,0,5,36,204,86,192,8, - 3,0,5,36,1,0,5,36,2,0,6,36, - 0,0,130,140,0,0,0,0,42,16,194,0, - 31,0,64,16,255,255,162,48,31,0,9,60, - 255,255,41,53,255,15,8,60,255,255,8,53, - 0,0,132,140,0,0,227,140,4,0,231,36, - 128,0,98,44,16,0,64,20,255,255,165,48, - 0,64,98,44,11,0,64,20,43,16,35,1, - 7,0,64,16,43,16,3,1,3,0,64,20, - 0,0,0,0,236,86,192,8,4,0,165,36, - 236,86,192,8,5,0,165,36,236,86,192,8, - 3,0,165,36,236,86,192,8,2,0,165,36, - 1,0,165,36,1,0,198,36,42,16,196,0, - 232,255,64,20,255,255,162,48,8,0,224,3, - 0,0,0,0,208,255,189,39,40,0,191,175, - 33,72,192,0,224,0,165,48,255,255,130,48, - 31,0,66,44,7,0,64,16,33,48,160,0, - 37,16,133,0,16,0,162,163,33,32,224,0, - 16,0,165,39,38,87,192,8,1,0,6,36, - 32,0,163,39,33,40,0,0,31,0,194,52, - 24,0,162,163,255,255,130,48,8,0,64,16, - 25,0,168,39,127,0,130,48,0,0,98,160, - 1,0,99,36,255,255,130,48,194,33,2,0, - 250,255,128,20,1,0,165,36,1,0,166,36, - 33,16,160,0,255,255,66,48,2,0,66,44, - 13,0,64,20,255,255,165,36,255,255,4,52, - 255,255,99,36,0,0,98,144,0,0,0,0, - 128,0,66,52,0,0,2,161,1,0,8,37, - 33,16,160,0,255,255,66,48,2,0,66,44, - 246,255,64,16,33,40,164,0,255,255,98,144, - 0,0,0,0,0,0,2,161,33,32,224,0, - 24,0,165,39,255,255,198,48,9,248,32,1, - 0,0,0,0,40,0,191,143,48,0,189,39, - 8,0,224,3,0,0,0,0,208,255,189,39, - 40,0,191,175,33,72,160,0,255,255,130,48, - 128,0,66,44,6,0,64,16,33,64,192,0, - 16,0,164,163,33,32,0,1,16,0,165,39, - 88,87,192,8,1,0,6,36,24,0,167,39, - 32,0,165,39,255,255,130,48,7,0,64,16, - 33,24,0,0,0,0,164,160,1,0,165,36, - 255,255,130,48,2,34,2,0,251,255,128,20, - 1,0,99,36,128,0,98,52,0,0,226,160, - 1,0,231,36,1,0,102,36,33,16,96,0, - 255,255,66,48,11,0,64,16,255,255,99,36, - 255,255,4,52,255,255,165,36,0,0,162,144, - 0,0,0,0,0,0,226,160,1,0,231,36, - 33,16,96,0,255,255,66,48,248,255,64,20, - 33,24,100,0,33,32,0,1,24,0,165,39, - 255,255,198,48,9,248,32,1,0,0,0,0, - 40,0,191,143,48,0,189,39,8,0,224,3, - 0,0,0,0,200,255,189,39,48,0,191,175, - 44,0,181,175,40,0,180,175,36,0,179,175, - 32,0,178,175,28,0,177,175,24,0,176,175, - 33,136,160,0,33,144,192,0,33,152,224,0, - 72,0,180,143,33,128,128,0,128,86,192,12, - 33,32,64,2,33,168,64,0,255,255,4,50, - 192,0,37,50,33,48,96,2,242,86,192,12, - 33,56,128,2,255,255,176,50,33,32,0,2, - 33,40,96,2,44,87,192,12,33,48,128,2, - 16,0,162,39,33,24,80,0,255,255,99,36, - 6,0,98,16,0,0,114,160,16,0,162,39, - 3,146,18,0,255,255,99,36,253,255,98,20, - 0,0,114,160,33,32,128,2,16,0,165,39, - 9,248,96,2,255,255,166,50,48,0,191,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,56,0,189,39,200,255,189,39, - 48,0,191,175,44,0,181,175,40,0,180,175, - 36,0,179,175,32,0,178,175,28,0,177,175, - 24,0,176,175,33,136,160,0,33,144,192,0, - 33,160,224,0,72,0,181,143,33,128,128,0, - 153,86,192,12,33,32,64,2,33,152,64,0, - 255,255,4,50,192,0,37,50,33,48,128,2, - 242,86,192,12,33,56,160,2,255,255,112,50, - 33,32,0,2,33,40,128,2,44,87,192,12, - 33,48,160,2,16,0,162,39,33,32,80,0, - 9,0,0,18,255,255,99,38,255,255,5,52, - 255,255,132,36,0,0,146,160,2,146,18,0, - 33,16,96,0,255,255,66,48,250,255,64,20, - 33,24,101,0,33,32,160,2,16,0,165,39, - 9,248,128,2,255,255,102,50,48,0,191,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,56,0,189,39,216,255,189,39, - 32,0,191,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,152,192,0, - 56,0,178,143,60,0,177,143,33,128,224,0, - 255,255,132,48,192,0,165,48,33,48,64,2, - 242,86,192,12,33,56,32,2,255,255,16,50, - 33,32,0,2,33,40,64,2,44,87,192,12, - 33,48,32,2,4,0,0,18,33,32,32,2, - 33,40,96,2,9,248,64,2,33,48,0,2, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,224,255,189,39,24,0,191,175, - 33,72,160,0,128,0,130,44,18,0,64,20, - 33,64,192,0,0,64,130,44,13,0,64,20, - 31,0,2,60,255,255,66,52,43,16,68,0, - 7,0,64,16,255,15,2,60,255,255,66,52, - 43,16,68,0,8,0,64,20,5,0,6,36, - 250,87,192,8,4,0,6,36,250,87,192,8, - 3,0,6,36,250,87,192,8,2,0,6,36, - 1,0,6,36,255,255,194,48,16,0,163,39, - 33,40,98,0,9,0,163,16,33,56,0,0, - 16,0,163,39,255,255,165,36,127,0,130,48, - 37,16,226,0,0,0,162,160,194,33,4,0, - 250,255,163,20,128,0,7,36,33,32,0,1, - 16,0,165,39,9,248,32,1,255,255,198,48, - 24,0,191,143,32,0,189,39,8,0,224,3, - 0,0,0,0,208,255,189,39,44,0,191,175, - 40,0,182,175,36,0,181,175,32,0,180,175, - 28,0,179,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,144,160,0,33,168,192,0, - 33,160,224,0,64,0,182,143,33,136,128,0, - 4,0,179,142,0,0,0,0,171,86,192,12, - 33,32,160,2,33,128,64,0,255,255,36,50, - 192,0,69,50,33,48,128,2,242,86,192,12, - 33,56,192,2,255,255,16,50,33,32,0,2, - 33,40,128,2,44,87,192,12,33,48,192,2, - 23,0,0,18,33,40,128,2,0,0,98,142, - 4,0,115,38,128,32,2,0,33,32,130,0, - 192,32,4,0,0,0,98,142,4,0,115,38, - 33,32,130,0,226,87,192,12,33,48,192,2, - 63,88,192,8,2,0,16,36,0,0,100,142, - 4,0,115,38,226,87,192,12,33,48,192,2, - 1,0,16,38,0,0,162,142,0,0,0,0, - 42,16,2,2,247,255,64,20,33,40,128,2, - 44,0,191,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 48,0,189,39,224,255,189,39,28,0,191,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,136,128,0,33,144,192,0,255,255,67,50, - 12,0,34,150,0,0,0,0,43,16,67,0, - 4,0,64,16,1,0,2,36,12,0,50,150, - 0,0,0,0,255,255,67,50,11,0,98,16, - 2,0,98,40,5,0,64,16,2,0,2,36, - 50,0,96,16,255,255,80,50,137,88,192,8, - 0,0,0,0,15,0,98,16,255,255,80,50, - 137,88,192,8,0,0,0,0,8,0,35,142, - 0,0,0,0,1,0,98,36,8,0,34,174, - 0,0,162,144,0,0,0,0,0,0,98,160, - 12,0,34,150,0,0,0,0,255,255,66,36, - 149,88,192,8,12,0,34,166,8,0,35,142, - 0,0,0,0,1,0,98,36,8,0,34,174, - 0,0,162,144,0,0,0,0,0,0,98,160, - 8,0,35,142,0,0,0,0,1,0,98,36, - 8,0,34,174,1,0,162,144,0,0,0,0, - 0,0,98,160,12,0,34,150,0,0,0,0, - 254,255,66,36,149,88,192,8,12,0,34,166, - 8,0,36,142,0,0,0,0,80,68,192,12, - 33,48,0,2,12,0,34,150,0,0,0,0, - 35,16,82,0,12,0,34,166,8,0,34,142, - 0,0,0,0,33,128,2,2,8,0,48,174, - 255,255,66,50,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,128,160,0, - 10,0,128,20,33,136,192,0,9,50,192,12, - 16,0,4,36,33,32,64,0,3,0,128,20, - 1,0,2,36,178,88,192,8,33,16,0,0, - 173,88,192,8,0,0,130,160,0,0,128,160, - 4,0,144,172,8,0,144,172,33,16,17,2, - 12,0,130,172,33,16,128,0,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,16,0,191,175, - 0,0,130,144,0,0,0,0,1,0,66,48, - 3,0,64,16,0,0,0,0,61,50,192,12, - 0,0,0,0,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,255,2,36,8,0,130,140,12,0,131,140, - 0,0,0,0,43,16,67,0,7,0,64,20, - 0,0,0,0,0,0,130,144,0,0,0,0, - 128,0,66,52,0,0,130,160,216,88,192,8, - 255,255,2,36,8,0,130,140,0,0,0,0, - 0,0,66,144,8,0,224,3,0,0,0,0, - 30,0,192,24,33,56,192,0,0,0,130,144, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,0,3,36,8,0,131,140,12,0,130,140, - 0,0,0,0,43,16,98,0,5,0,64,16, - 1,0,98,36,8,0,130,172,0,0,99,144, - 240,88,192,8,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,52,0,0,130,160, - 255,0,3,36,0,0,130,144,0,0,0,0, - 128,0,66,48,5,0,64,20,0,0,0,0, - 0,0,163,160,255,255,198,36,228,255,192,28, - 1,0,165,36,8,0,224,3,35,16,230,0, - 1,0,2,36,15,0,194,16,2,0,194,40, - 5,0,64,16,2,0,2,36,7,0,192,16, - 255,255,2,36,40,89,192,8,0,0,0,0, - 11,0,194,16,255,255,2,36,40,89,192,8, - 0,0,0,0,4,0,130,140,0,0,0,0, - 21,89,192,8,33,40,162,0,8,0,130,140, - 0,0,0,0,19,89,192,8,33,40,162,0, - 12,0,130,140,0,0,0,0,35,40,69,0, - 4,0,130,140,0,0,0,0,43,16,162,0, - 17,0,64,20,255,255,2,36,12,0,130,140, - 0,0,0,0,43,16,69,0,12,0,64,20, - 255,255,2,36,12,0,130,140,0,0,0,0, - 43,16,162,0,5,0,64,16,0,0,0,0, - 0,0,130,144,0,0,0,0,127,0,66,48, - 0,0,130,160,8,0,133,172,33,16,0,0, - 8,0,224,3,0,0,0,0,12,0,130,140, - 4,0,131,140,0,0,0,0,35,56,67,0, - 1,0,2,36,15,0,194,16,2,0,194,40, - 5,0,64,16,2,0,2,36,7,0,192,16, - 255,255,2,36,87,89,192,8,0,0,0,0, - 12,0,194,16,255,255,2,36,87,89,192,8, - 0,0,0,0,4,0,130,140,0,0,0,0, - 66,89,192,8,33,16,162,0,8,0,130,140, - 0,0,0,0,33,16,162,0,72,89,192,8, - 12,0,130,172,12,0,130,140,0,0,0,0, - 35,16,69,0,12,0,130,172,8,0,130,140, - 12,0,131,140,0,0,0,0,43,16,67,0, - 5,0,64,16,0,0,0,0,0,0,130,144, - 0,0,0,0,85,89,192,8,127,0,66,48, - 0,0,130,144,0,0,0,0,128,0,66,52, - 0,0,130,160,33,16,224,0,8,0,224,3, - 0,0,0,0,232,255,189,39,20,0,191,175, - 16,0,176,175,12,0,128,20,33,128,160,0, - 9,50,192,12,16,0,4,36,33,32,64,0, - 3,0,128,20,0,0,0,0,119,89,192,8, - 33,16,0,0,0,0,2,146,0,0,0,0, - 108,89,192,8,1,0,66,52,0,0,2,146, - 0,0,0,0,254,0,66,48,0,0,130,160, - 4,0,2,142,0,0,0,0,4,0,130,172, - 8,0,2,142,0,0,0,0,8,0,130,172, - 12,0,2,142,0,0,0,0,12,0,130,172, - 33,16,128,0,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,0,0,0,0, - 0,0,130,144,0,0,0,0,128,0,66,48, - 17,0,64,20,31,0,3,36,8,0,131,140, - 12,0,130,140,0,0,0,0,43,16,98,0, - 6,0,64,16,1,0,98,36,8,0,130,172, - 0,0,98,144,0,0,0,0,145,89,192,8, - 31,0,67,48,0,0,130,144,0,0,0,0, - 128,0,66,52,0,0,130,160,31,0,3,36, - 0,0,130,144,0,0,0,0,128,0,66,48, - 4,0,64,16,1,0,2,36,0,0,162,172, - 196,89,192,8,33,16,0,0,255,0,99,48, - 31,0,2,36,6,0,98,16,33,16,96,0, - 196,89,192,8,0,0,0,0,1,0,2,36, - 195,89,192,8,0,0,162,172,33,48,0,0, - 0,0,130,144,0,0,0,0,128,0,66,48, - 16,0,64,20,255,0,3,36,8,0,131,140, - 12,0,130,140,0,0,0,0,43,16,98,0, - 5,0,64,16,1,0,98,36,8,0,130,172, - 0,0,99,144,183,89,192,8,0,0,0,0, - 0,0,130,144,0,0,0,0,128,0,66,52, - 0,0,130,160,255,0,3,36,0,0,130,144, - 0,0,0,0,128,0,66,48,228,255,64,20, - 128,0,98,48,4,0,64,16,127,0,98,48, - 37,16,194,0,163,89,192,8,192,49,2,0, - 255,0,98,48,37,48,70,0,255,255,194,48, - 8,0,224,3,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,0,6,36,8,0,131,140,12,0,130,140, - 0,0,0,0,43,16,98,0,5,0,64,16, - 1,0,98,36,8,0,130,172,0,0,102,144, - 218,89,192,8,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,52,0,0,130,160, - 255,0,6,36,0,0,130,144,0,0,0,0, - 128,0,66,48,13,0,64,20,1,0,2,36, - 255,0,195,48,128,0,2,36,4,0,98,20, - 2,0,2,36,0,0,162,172,17,90,192,8, - 255,255,2,52,128,0,194,48,6,0,64,20, - 33,24,0,0,17,90,192,8,255,0,194,48, - 0,0,162,172,17,90,192,8,33,16,0,0, - 127,0,194,48,32,0,64,16,255,255,71,36, - 0,26,3,0,0,0,130,144,0,0,0,0, - 128,0,66,48,16,0,64,20,255,255,102,48, - 8,0,131,140,12,0,130,140,0,0,0,0, - 43,16,98,0,6,0,64,16,1,0,98,36, - 8,0,130,172,0,0,98,144,0,0,0,0, - 7,90,192,8,37,24,194,0,0,0,130,144, - 0,0,0,0,128,0,66,52,0,0,130,160, - 255,0,195,52,0,0,130,144,0,0,0,0, - 128,0,66,48,224,255,64,20,1,0,2,36, - 33,16,224,0,255,0,66,48,226,255,64,20, - 255,255,231,36,255,255,98,48,8,0,224,3, - 0,0,0,0,216,255,189,39,36,0,191,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,152,128,0, - 33,128,192,0,33,144,160,0,255,255,81,50, - 33,0,32,18,33,160,224,0,255,255,2,52, - 30,0,34,18,0,0,0,0,9,50,192,12, - 33,32,32,2,33,24,64,0,29,0,96,16, - 1,0,2,36,0,0,2,166,4,0,3,174, - 8,0,3,174,12,0,18,166,33,32,96,2, - 8,0,5,142,0,0,0,0,218,88,192,12, - 33,48,32,2,33,24,64,0,255,255,100,48, - 10,0,145,20,1,0,2,36,12,0,2,150, - 0,0,0,0,35,16,67,0,12,0,2,166, - 8,0,2,142,0,0,0,0,33,16,130,0, - 68,90,192,8,8,0,2,174,68,90,192,8, - 0,0,130,174,0,0,0,166,4,0,0,174, - 8,0,0,174,12,0,0,166,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,224,255,189,39,28,0,191,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,144,128,0,33,136,160,0,33,128,192,0, - 124,89,192,12,33,40,0,2,33,32,64,2, - 198,89,192,12,33,40,0,2,33,40,64,0, - 0,0,2,142,0,0,0,0,7,0,64,20, - 33,32,64,2,255,255,165,48,33,48,32,2, - 19,90,192,12,33,56,0,2,104,90,192,8, - 0,0,0,0,0,0,32,166,4,0,32,174, - 8,0,32,174,12,0,32,166,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,216,255,189,39, - 36,0,191,175,32,0,180,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,152,128,0,33,136,160,0,33,144,192,0, - 56,0,176,147,0,0,0,0,196,88,192,12, - 33,160,224,0,224,0,66,48,7,0,80,20, - 33,32,96,2,124,89,192,12,33,40,64,2, - 255,255,66,48,255,255,131,50,7,0,67,16, - 33,32,96,2,0,0,66,142,0,0,0,0, - 16,0,64,20,4,0,2,36,152,90,192,8, - 0,0,66,174,198,89,192,12,33,40,64,2, - 33,40,64,0,0,0,66,142,0,0,0,0, - 7,0,64,20,33,32,96,2,255,255,165,48, - 33,48,32,2,19,90,192,12,33,56,64,2, - 156,90,192,8,0,0,0,0,0,0,32,166, - 4,0,32,174,8,0,32,174,12,0,32,166, - 36,0,191,143,32,0,180,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,33,56,0,0, - 255,255,168,36,255,255,165,48,50,0,160,16, - 1,0,9,36,1,0,12,36,4,0,10,36, - 3,0,11,36,255,255,5,52,0,0,130,144, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,0,3,36,8,0,131,140,12,0,130,140, - 0,0,0,0,43,16,98,0,5,0,64,16, - 1,0,98,36,8,0,130,172,0,0,99,144, - 193,90,192,8,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,52,0,0,130,160, - 255,0,3,36,0,0,130,144,0,0,0,0, - 128,0,66,48,3,0,64,16,0,0,0,0, - 218,90,192,8,0,0,204,172,11,0,32,17, - 255,255,2,49,5,0,74,20,33,72,0,0, - 3,0,96,16,0,0,0,0,218,90,192,8, - 0,0,203,172,128,0,98,48,3,0,64,16, - 0,18,7,0,255,255,7,36,0,18,7,0, - 37,56,67,0,33,16,0,1,255,255,66,48, - 212,255,64,20,33,64,5,1,8,0,224,3, - 33,16,224,0,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,128,128,0, - 124,89,192,12,33,136,160,0,33,32,0,2, - 198,89,192,12,33,40,32,2,33,32,0,2, - 255,255,69,48,164,90,192,12,33,48,32,2, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,216,255,189,39, - 32,0,191,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,144,128,0, - 33,136,160,0,33,152,192,0,196,88,192,12, - 33,128,224,0,224,0,66,48,255,0,16,50, - 7,0,80,20,33,32,64,2,124,89,192,12, - 33,40,32,2,255,255,66,48,255,255,99,50, - 8,0,67,16,33,32,64,2,0,0,34,142, - 0,0,0,0,2,0,64,20,4,0,2,36, - 0,0,34,174,17,91,192,8,33,16,0,0, - 198,89,192,12,33,40,32,2,33,32,64,2, - 255,255,69,48,164,90,192,12,33,48,32,2, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,208,255,189,39,44,0,191,175, - 40,0,180,175,36,0,179,175,32,0,178,175, - 28,0,177,175,24,0,176,175,33,128,128,0, - 33,152,192,0,33,160,224,0,0,0,96,174, - 4,0,96,174,8,0,3,142,4,0,2,142, - 0,0,0,0,35,24,98,0,255,255,165,48, - 35,0,160,24,33,144,0,0,1,0,6,36, - 0,0,2,146,0,0,0,0,128,0,66,48, - 16,0,64,20,255,0,4,36,8,0,4,142, - 12,0,2,142,0,0,0,0,43,16,130,0, - 5,0,64,16,1,0,130,36,8,0,2,174, - 0,0,132,144,64,91,192,8,0,0,0,0, - 0,0,2,146,0,0,0,0,128,0,66,52, - 0,0,2,162,255,0,4,36,0,0,2,146, - 0,0,0,0,128,0,66,48,3,0,64,16, - 128,0,130,48,150,91,192,8,0,0,134,174, - 2,0,64,20,0,0,0,0,1,0,82,38, - 255,255,165,36,224,255,160,28,0,0,0,0, - 33,32,0,2,33,40,96,0,251,88,192,12, - 33,48,0,0,68,0,64,18,1,0,81,38, - 9,50,192,12,128,32,17,0,33,40,64,0, - 63,0,160,16,0,0,0,0,0,0,113,174, - 4,0,101,174,59,0,64,26,33,56,0,0, - 1,0,8,36,33,48,0,0,0,0,2,146, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,0,4,36,8,0,3,142,12,0,2,142, - 0,0,0,0,43,16,98,0,5,0,64,16, - 1,0,98,36,8,0,2,174,0,0,100,144, - 114,91,192,8,0,0,0,0,0,0,2,146, - 0,0,0,0,128,0,66,52,0,0,2,162, - 255,0,4,36,0,0,2,146,0,0,0,0, - 128,0,66,48,3,0,64,16,192,49,6,0, - 150,91,192,8,0,0,136,174,127,0,130,48, - 37,48,194,0,128,0,130,48,225,255,64,20, - 0,0,0,0,18,0,224,20,40,0,194,44, - 4,0,64,16,80,0,194,44,0,0,160,172, - 145,91,192,8,4,0,165,36,5,0,64,16, - 216,255,194,36,0,0,168,172,4,0,165,36, - 146,91,192,8,0,0,162,172,2,0,2,36, - 0,0,162,172,4,0,165,36,176,255,194,36, - 146,91,192,8,0,0,162,172,0,0,166,172, - 1,0,231,36,42,16,242,0,200,255,64,20, - 4,0,165,36,44,0,191,143,40,0,180,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,48,0,189,39, - 224,255,189,39,28,0,191,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,136,128,0, - 33,144,160,0,33,128,192,0,124,89,192,12, - 33,40,0,2,33,32,32,2,198,89,192,12, - 33,40,0,2,33,40,64,0,0,0,2,142, - 0,0,0,0,5,0,64,20,33,32,32,2, - 255,255,165,48,33,48,64,2,24,91,192,12, - 33,56,0,2,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,216,255,189,39,36,0,191,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,144,128,0, - 33,160,160,0,33,136,192,0,56,0,176,147, - 0,0,0,0,196,88,192,12,33,152,224,0, - 224,0,66,48,7,0,80,20,33,32,64,2, - 124,89,192,12,33,40,32,2,255,255,66,48, - 255,255,99,50,7,0,67,16,33,32,64,2, - 0,0,34,142,0,0,0,0,14,0,64,20, - 4,0,2,36,226,91,192,8,0,0,34,174, - 198,89,192,12,33,40,32,2,33,40,64,0, - 0,0,34,142,0,0,0,0,5,0,64,20, - 33,32,64,2,255,255,165,48,33,48,128,2, - 24,91,192,12,33,56,32,2,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,0,0,0,0,0,0,0,0, - 216,255,189,39,32,0,191,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,152,128,0,8,0,99,142,4,0,98,142, - 0,0,0,0,35,128,98,0,255,255,4,50, - 19,0,128,16,33,136,160,0,9,50,192,12, - 0,0,0,0,33,144,64,0,3,0,64,22, - 255,255,16,50,17,92,192,8,255,255,2,36, - 33,32,64,2,4,0,101,142,0,0,0,0, - 80,68,192,12,33,48,0,2,1,0,2,36, - 0,0,34,166,4,0,50,174,33,128,80,2, - 15,92,192,8,8,0,48,174,0,0,32,166, - 4,0,32,174,8,0,32,174,12,0,32,166, - 33,16,0,0,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 0,0,2,150,0,0,0,0,1,0,66,48, - 7,0,64,16,0,0,0,0,4,0,4,142, - 0,0,0,0,3,0,128,16,0,0,0,0, - 61,50,192,12,0,0,0,0,0,0,0,166, - 8,0,0,174,4,0,0,174,12,0,0,166, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,128,128,0, - 8,0,163,140,4,0,162,140,0,0,0,0, - 35,136,98,0,255,255,35,50,12,0,2,150, - 0,0,0,0,43,16,67,0,4,0,64,16, - 255,255,38,50,12,0,17,150,0,0,0,0, - 255,255,38,50,6,0,192,16,255,255,34,50, - 8,0,4,142,4,0,165,140,80,68,192,12, - 0,0,0,0,255,255,34,50,8,0,3,142, - 0,0,0,0,33,16,67,0,8,0,2,174, - 12,0,2,150,0,0,0,0,35,16,81,0, - 12,0,2,166,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 1,0,2,36,23,0,194,16,2,0,194,40, - 5,0,64,16,2,0,2,36,7,0,192,16, - 255,255,2,36,132,92,192,8,0,0,0,0, - 23,0,194,16,255,255,2,36,132,92,192,8, - 0,0,0,0,255,255,162,48,4,0,131,140, - 0,0,0,0,33,48,67,0,8,0,130,140, - 0,0,0,0,35,16,67,0,12,0,131,148, - 0,0,0,0,33,16,67,0,124,92,192,8, - 35,40,69,0,255,255,162,48,8,0,131,140, - 0,0,0,0,33,48,67,0,12,0,130,148, - 0,0,0,0,124,92,192,8,35,40,69,0, - 12,0,130,148,8,0,131,140,0,0,0,0, - 33,48,67,0,255,255,162,48,35,48,194,0, - 4,0,130,140,0,0,0,0,43,16,194,0, - 4,0,64,20,255,255,2,36,8,0,134,172, - 12,0,133,164,33,16,0,0,8,0,224,3, - 0,0,0,0,216,255,189,39,32,0,191,175, - 28,0,179,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,128,128,0,33,152,160,0, - 8,0,3,142,4,0,2,142,0,0,0,0, - 35,144,98,0,255,255,66,50,12,0,3,150, - 0,0,0,0,33,16,67,0,255,255,99,50, - 42,16,67,0,35,0,64,16,1,0,2,36, - 0,0,3,150,0,0,0,0,32,0,98,20, - 255,255,2,36,9,50,192,12,255,255,100,50, - 33,136,64,0,3,0,32,22,255,255,70,50, - 189,92,192,8,255,255,2,36,5,0,192,16, - 0,0,0,0,4,0,5,142,0,0,0,0, - 80,68,192,12,33,32,32,2,0,0,2,150, - 0,0,0,0,1,0,66,48,7,0,64,16, - 0,0,0,0,4,0,4,142,0,0,0,0, - 3,0,128,16,0,0,0,0,61,50,192,12, - 0,0,0,0,4,0,17,174,255,255,66,50, - 33,16,34,2,8,0,2,174,35,16,114,2, - 12,0,2,166,33,16,0,0,32,0,191,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 216,255,189,39,32,0,191,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,128,128,0,33,136,192,0,255,255,36,50, - 35,0,128,16,33,152,160,0,8,0,2,142, - 4,0,3,142,0,0,0,0,35,16,67,0, - 255,255,66,48,12,0,3,150,0,0,0,0, - 33,16,67,0,42,16,68,0,20,0,64,16, - 0,0,0,0,9,50,192,12,0,0,0,0, - 33,144,64,0,24,0,64,18,255,255,2,36, - 0,0,2,150,0,0,0,0,1,0,66,48, - 8,0,64,16,1,0,2,36,4,0,4,142, - 0,0,0,0,4,0,128,16,0,0,0,0, - 61,50,192,12,0,0,0,0,1,0,2,36, - 0,0,2,166,4,0,18,174,4,0,4,142, - 33,40,96,2,80,68,192,12,255,255,38,50, - 33,32,0,2,255,255,37,50,85,92,192,12, - 33,48,0,0,33,16,0,0,32,0,191,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 184,255,189,39,64,0,191,175,60,0,183,175, - 56,0,182,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,144,128,0,112,0,84,142, - 0,0,0,0,92,0,128,18,1,0,2,36, - 108,0,81,142,0,0,0,0,88,0,32,18, - 0,0,0,0,96,0,87,38,136,0,66,174, - 140,0,64,174,96,0,64,174,100,0,64,174, - 224,83,192,12,33,32,32,2,33,168,64,0, - 25,0,160,18,33,128,160,2,108,0,66,142, - 0,0,0,0,124,0,66,174,128,0,84,174, - 108,0,81,174,112,0,85,174,29,0,32,26, - 33,152,0,0,255,255,22,36,33,32,0,2, - 8,0,133,38,33,48,64,2,170,72,192,12, - 1,0,7,36,10,0,86,16,33,32,64,2, - 14,0,64,20,0,0,0,0,64,0,66,142, - 0,0,0,0,10,0,64,20,2,0,5,36, - 56,93,192,8,1,0,102,38,33,32,64,2, - 5,0,5,36,33,48,0,0,140,84,192,12, - 0,0,0,0,107,93,192,8,1,0,2,36, - 1,0,115,38,68,0,16,38,42,16,113,2, - 230,255,64,20,68,0,148,38,40,0,32,18, - 33,128,160,2,17,0,2,146,0,0,0,0, - 34,0,66,48,32,0,64,20,0,0,0,0, - 36,0,2,142,16,0,176,175,16,0,66,140, - 24,0,4,142,28,0,5,142,32,0,6,142, - 0,0,0,0,9,248,64,0,33,56,64,2, - 17,0,2,146,0,0,0,0,32,0,66,52, - 17,0,2,162,0,0,226,142,0,0,0,0, - 15,0,64,16,0,0,0,0,255,255,49,38, - 15,0,32,18,68,0,16,38,17,0,3,146, - 0,0,0,0,32,0,98,48,2,0,64,20, - 34,0,98,52,17,0,2,162,255,255,49,38, - 248,255,32,22,68,0,16,38,107,93,192,8, - 33,16,0,0,255,255,49,38,218,255,32,22, - 68,0,16,38,33,16,0,0,64,0,191,143, - 60,0,183,143,56,0,182,143,52,0,181,143, - 48,0,180,143,44,0,179,143,40,0,178,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 72,0,189,39,168,255,189,39,80,0,191,175, - 76,0,183,175,72,0,182,175,68,0,181,175, - 64,0,180,175,60,0,179,175,56,0,178,175, - 52,0,177,175,48,0,176,175,33,144,128,0, - 96,0,66,142,0,0,0,0,3,0,64,16, - 33,32,0,0,240,93,192,8,255,255,2,36, - 116,0,66,142,0,0,0,0,7,0,64,16, - 104,0,67,38,12,0,99,140,0,0,0,0, - 12,0,98,140,0,0,0,0,251,255,64,20, - 0,0,0,0,8,0,116,140,0,0,0,0, - 92,0,128,18,33,16,0,0,4,0,115,140, - 0,0,0,0,88,0,96,18,0,0,0,0, - 64,0,66,142,0,0,0,0,55,0,64,20, - 0,0,0,0,33,128,128,2,52,0,96,26, - 33,136,0,0,255,255,23,36,2,0,22,36, - 5,0,21,36,17,0,2,146,0,0,0,0, - 16,0,66,48,40,0,64,16,24,0,165,39, - 8,0,3,142,28,0,2,142,0,0,0,0, - 35,24,98,0,24,0,163,175,12,0,2,142, - 0,0,0,0,28,0,162,175,128,24,3,0, - 33,24,98,0,252,255,98,140,0,0,0,0, - 1,0,66,36,252,255,98,172,12,0,0,174, - 8,0,0,174,33,32,0,2,33,48,64,2, - 170,72,192,12,1,0,7,36,6,0,87,16, - 0,0,0,0,9,0,64,20,1,0,34,38, - 96,0,86,174,196,93,192,8,100,0,66,174, - 96,0,85,174,110,86,192,12,24,0,164,39, - 240,93,192,8,255,255,2,36,110,86,192,12, - 24,0,164,39,17,0,2,146,0,0,0,0, - 12,0,66,48,17,0,2,162,1,0,4,36, - 1,0,49,38,42,16,51,2,209,255,64,20, - 68,0,16,38,27,0,128,16,33,128,128,2, - 23,0,96,26,33,136,0,0,17,0,2,146, - 0,0,0,0,34,0,66,48,14,0,64,20, - 0,0,0,0,36,0,2,142,16,0,176,175, - 16,0,66,140,24,0,4,142,28,0,5,142, - 32,0,6,142,0,0,0,0,9,248,64,0, - 33,56,64,2,17,0,2,146,0,0,0,0, - 32,0,66,52,17,0,2,162,1,0,49,38, - 42,16,51,2,235,255,64,20,68,0,16,38, - 240,93,192,8,1,0,2,36,33,16,0,0, - 80,0,191,143,76,0,183,143,72,0,182,143, - 68,0,181,143,64,0,180,143,60,0,179,143, - 56,0,178,143,52,0,177,143,48,0,176,143, - 8,0,224,3,88,0,189,39,0,0,0,0, - 200,255,189,39,48,0,191,175,44,0,179,175, - 40,0,178,175,36,0,177,175,32,0,176,175, - 33,144,128,0,96,0,64,174,100,0,64,174, - 112,0,80,142,0,0,0,0,105,0,0,18, - 33,16,0,0,108,0,81,142,0,0,0,0, - 101,0,32,18,0,0,0,0,64,0,66,142, - 0,0,0,0,43,0,64,20,33,32,64,2, - 50,0,32,26,33,152,0,0,33,32,0,2, - 33,40,64,2,96,72,192,12,1,0,6,36, - 13,0,64,20,33,32,64,2,20,0,2,150, - 0,0,0,0,1,0,66,48,34,0,64,16, - 2,0,5,36,36,0,2,142,0,0,0,0, - 3,0,66,144,0,0,0,0,2,0,66,48, - 3,0,64,20,0,0,0,0,63,94,192,8, - 2,0,5,36,36,0,2,142,0,0,0,0, - 32,0,66,140,4,0,67,142,0,0,0,0, - 36,16,67,0,16,0,64,16,33,32,64,2, - 36,0,2,142,16,0,3,146,2,0,66,144, - 0,0,0,0,11,0,98,20,3,0,5,36, - 1,0,115,38,42,16,113,2,219,255,64,20, - 68,0,16,38,69,94,192,8,96,0,83,38, - 5,0,5,36,64,94,192,8,33,48,0,0, - 2,0,5,36,1,0,102,38,140,84,192,12, - 0,0,0,0,113,94,192,8,1,0,2,36, - 96,0,83,38,112,0,80,142,0,0,0,0, - 41,0,32,18,33,16,0,0,17,0,2,146, - 0,0,0,0,17,0,66,48,32,0,64,20, - 0,0,0,0,36,0,2,142,16,0,176,175, - 4,0,66,140,24,0,4,142,28,0,5,142, - 32,0,6,142,0,0,0,0,9,248,64,0, - 33,56,64,2,17,0,2,146,0,0,0,0, - 16,0,66,52,17,0,2,162,0,0,98,142, - 0,0,0,0,15,0,64,16,0,0,0,0, - 255,255,49,38,15,0,32,18,68,0,16,38, - 17,0,3,146,0,0,0,0,16,0,98,48, - 2,0,64,20,17,0,98,52,17,0,2,162, - 255,255,49,38,248,255,32,22,68,0,16,38, - 113,94,192,8,33,16,0,0,255,255,49,38, - 218,255,32,22,68,0,16,38,33,16,0,0, - 48,0,191,143,44,0,179,143,40,0,178,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 56,0,189,39,192,255,189,39,56,0,191,175, - 52,0,183,175,48,0,182,175,44,0,181,175, - 40,0,180,175,36,0,179,175,32,0,178,175, - 28,0,177,175,24,0,176,175,33,144,128,0, - 112,0,84,142,0,0,0,0,171,0,128,18, - 33,16,0,0,108,0,85,142,0,0,0,0, - 166,0,160,18,32,0,2,36,56,0,67,146, - 0,0,0,0,75,0,98,16,96,0,83,38, - 33,0,98,40,5,0,64,16,64,0,2,36, - 9,0,96,16,33,16,0,0,49,95,192,8, - 0,0,0,0,85,0,98,16,128,0,2,36, - 137,0,98,16,33,16,0,0,49,95,192,8, - 0,0,0,0,33,136,160,2,8,0,32,18, - 33,128,128,2,17,0,2,146,0,0,0,0, - 1,0,66,48,139,0,64,16,255,255,49,38, - 250,255,32,22,68,0,16,38,0,0,98,142, - 0,0,0,0,136,0,64,20,33,16,0,0, - 33,136,160,2,43,0,32,18,33,128,128,2, - 14,0,22,36,64,0,23,36,17,0,2,146, - 0,0,0,0,34,0,66,48,33,0,64,20, - 0,0,0,0,36,0,2,142,16,0,176,175, - 12,0,66,140,24,0,4,142,28,0,5,142, - 32,0,6,142,0,0,0,0,9,248,64,0, - 33,56,64,2,17,0,2,146,0,0,0,0, - 32,0,66,52,17,0,2,162,0,0,98,142, - 0,0,0,0,16,0,64,16,0,0,0,0, - 255,255,49,38,10,0,32,18,68,0,16,38, - 17,0,3,146,0,0,0,0,32,0,98,48, - 2,0,64,20,192,0,98,52,17,0,2,162, - 255,255,49,38,248,255,32,22,68,0,16,38, - 0,0,118,174,236,94,192,8,56,0,87,162, - 255,255,49,38,217,255,32,22,68,0,16,38, - 32,0,2,36,56,0,66,162,0,0,98,142, - 0,0,0,0,13,0,64,20,64,0,2,36, - 33,136,160,2,81,0,32,18,33,128,128,2, - 17,0,2,146,0,0,0,0,2,0,66,48, - 74,0,64,16,255,255,49,38,250,255,32,22, - 68,0,16,38,49,95,192,8,33,16,0,0, - 56,0,66,162,14,0,2,36,0,0,98,174, - 33,136,160,2,53,0,32,18,33,128,128,2, - 2,0,23,36,15,0,22,36,17,0,2,146, - 0,0,0,0,194,0,66,48,5,0,64,16, - 0,0,0,0,19,0,87,16,0,0,0,0, - 32,95,192,8,255,255,49,38,64,0,2,142, - 0,0,0,0,34,0,64,16,0,0,0,0, - 16,0,176,175,64,0,2,142,24,0,4,142, - 28,0,5,142,32,0,6,142,0,0,0,0, - 9,248,64,0,33,56,64,2,17,0,2,146, - 0,0,0,0,30,95,192,8,64,0,66,52, - 64,0,2,142,0,0,0,0,13,0,64,16, - 0,0,0,0,16,0,176,175,64,0,2,142, - 24,0,4,142,28,0,5,142,32,0,6,142, - 0,0,0,0,9,248,64,0,33,56,64,2, - 17,0,2,146,0,0,0,0,30,95,192,8, - 64,0,66,52,0,0,118,174,17,0,2,146, - 0,0,0,0,128,0,66,52,17,0,2,162, - 255,255,49,38,208,255,32,22,68,0,16,38, - 33,136,160,2,12,0,32,18,33,128,128,2, - 17,0,2,146,0,0,0,0,128,0,66,48, - 5,0,64,16,255,255,49,38,250,255,32,22, - 68,0,16,38,49,95,192,8,33,16,0,0, - 49,95,192,8,1,0,2,36,33,16,0,0, - 56,0,191,143,52,0,183,143,48,0,182,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,64,0,189,39,184,255,189,39, - 64,0,191,175,60,0,183,175,56,0,182,175, - 52,0,181,175,48,0,180,175,44,0,179,175, - 40,0,178,175,36,0,177,175,32,0,176,175, - 33,160,128,0,112,0,147,142,0,0,0,0, - 129,0,96,18,33,16,0,0,108,0,146,142, - 0,0,0,0,125,0,64,18,96,0,151,38, - 96,0,128,174,100,0,128,174,224,83,192,12, - 33,32,64,2,33,168,64,0,5,0,160,22, - 33,136,64,2,33,32,128,2,5,0,5,36, - 123,95,192,8,33,48,0,0,36,0,64,18, - 33,128,160,2,5,0,22,36,16,0,22,162, - 8,0,100,142,12,0,101,142,0,0,0,0, - 80,86,192,12,8,0,6,38,5,0,64,20, - 0,0,0,0,255,255,49,38,68,0,115,38, - 245,255,32,22,68,0,16,38,21,0,32,18, - 42,16,50,2,7,0,64,16,33,128,160,2, - 59,84,192,12,33,32,0,2,1,0,49,38, - 42,16,50,2,251,255,64,20,68,0,16,38, - 61,50,192,12,33,32,160,2,33,32,128,2, - 5,0,5,36,123,95,192,8,33,48,0,0, - 2,0,5,36,1,0,38,38,140,84,192,12, - 0,0,0,0,203,95,192,8,1,0,2,36, - 124,0,146,174,112,0,130,142,0,0,0,0, - 128,0,130,174,112,0,149,174,33,128,160,2, - 27,0,64,26,33,136,0,0,33,32,0,2, - 33,40,128,2,96,72,192,12,1,0,6,36, - 13,0,64,20,0,0,0,0,20,0,2,150, - 0,0,0,0,1,0,66,48,8,0,64,16, - 0,0,0,0,36,0,2,142,0,0,0,0, - 3,0,66,144,0,0,0,0,1,0,66,48, - 5,0,64,20,0,0,0,0,64,0,130,142, - 0,0,0,0,221,255,64,16,33,32,128,2, - 1,0,49,38,42,16,50,2,231,255,64,20, - 68,0,16,38,40,0,64,18,33,128,160,2, - 17,0,2,146,0,0,0,0,34,0,66,48, - 32,0,64,20,0,0,0,0,36,0,2,142, - 16,0,176,175,8,0,66,140,24,0,4,142, - 28,0,5,142,32,0,6,142,0,0,0,0, - 9,248,64,0,33,56,128,2,17,0,2,146, - 0,0,0,0,32,0,66,52,17,0,2,162, - 0,0,226,142,0,0,0,0,15,0,64,16, - 0,0,0,0,255,255,82,38,15,0,64,18, - 68,0,16,38,17,0,3,146,0,0,0,0, - 32,0,98,48,2,0,64,20,34,0,98,52, - 17,0,2,162,255,255,82,38,248,255,64,22, - 68,0,16,38,203,95,192,8,33,16,0,0, - 255,255,82,38,218,255,64,22,68,0,16,38, - 33,16,0,0,64,0,191,143,60,0,183,143, - 56,0,182,143,52,0,181,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,72,0,189,39, - 0,0,0,0,0,0,0,0,37,115,58,37, - 100,58,32,102,97,105,108,101,100,32,97,115, - 115,101,114,116,105,111,110,32,96,37,115,39, - 10,0,0,0,114,97,109,116,101,115,116,100, - 119,40,98,99,46,98,99,95,104,101,97,112, - 115,116,97,114,116,44,32,108,101,110,44,32, - 49,44,32,48,44,32,48,41,32,61,61,32, - 48,0,0,0,98,99,46,98,99,95,104,101, - 97,112,101,110,100,32,60,61,32,98,99,46, - 98,99,95,114,97,109,101,110,100,0,0,0, - 35,32,112,111,114,116,115,58,32,37,100,10, - 0,0,0,0,42,42,42,80,114,111,102,105, - 108,105,110,103,32,64,32,37,120,44,32,37, - 120,10,0,0,103,111,116,32,104,101,114,101, - 32,99,97,117,115,101,61,37,120,32,115,116, - 97,116,117,115,61,37,120,32,118,101,99,61, - 37,120,10,0,37,115,58,37,100,58,32,102, - 97,105,108,101,100,32,97,115,115,101,114,116, - 105,111,110,32,96,37,115,39,10,0,0,0, - 83,101,99,111,110,100,115,32,60,32,48,120, - 55,70,70,70,102,102,102,102,0,0,0,0, - 84,105,109,101,114,115,85,115,101,100,32,60, - 32,78,84,73,77,69,82,83,0,0,0,0, - 0,0,0,0,69,69,80,82,79,77,32,105, - 115,32,98,97,100,10,0,0,80,111,114,116, - 32,37,100,32,101,116,104,101,114,32,97,100, - 100,114,101,115,115,58,32,37,48,50,88,58, - 37,48,50,88,58,37,48,50,88,58,37,48, - 50,88,58,37,48,50,88,58,37,48,50,88, - 10,0,0,0,35,35,35,32,56,50,53,57, - 54,32,67,104,97,110,32,37,100,58,32,115, - 101,108,102,116,101,115,116,32,102,97,105,108, - 101,100,32,40,37,120,41,10,0,0,0,0, - 42,42,42,32,56,50,53,57,54,32,80,111, - 114,116,32,37,100,58,32,115,101,108,102,116, - 101,115,116,32,112,97,115,115,101,100,10,0, - 56,50,53,57,54,32,80,111,114,116,32,37, - 100,58,32,100,117,109,112,32,102,97,105,108, - 101,100,32,40,37,120,41,10,0,0,0,0, - 42,42,42,32,56,50,53,57,54,32,80,111, - 114,116,32,37,100,58,32,100,117,109,112,32, - 112,97,115,115,101,100,10,0,35,35,35,32, - 56,50,53,57,54,32,80,111,114,116,32,37, - 100,58,32,83,67,80,32,102,101,116,99,104, - 32,102,97,105,108,101,100,10,0,0,0,0, - 42,42,42,32,56,50,53,57,54,32,80,111, - 114,116,32,37,100,58,32,83,67,80,32,102, - 101,116,99,104,32,112,97,115,115,101,100,32, - 37,120,32,10,0,0,0,0,35,35,35,32, - 56,50,53,57,54,32,80,111,114,116,32,37, - 100,58,32,66,85,83,84,73,77,69,82,83, - 32,108,111,97,100,32,102,97,105,108,101,100, - 10,0,0,0,42,42,42,32,56,50,53,57, - 54,32,80,111,114,116,32,37,100,58,32,66, - 85,83,84,73,77,69,82,83,32,108,111,97, - 100,32,112,97,115,115,101,100,10,0,0,0, - 35,35,35,32,65,67,75,32,100,105,100,32, - 110,111,116,32,111,99,99,117,114,10,0,0, - 35,35,35,32,115,116,97,116,117,115,32,115, - 116,105,108,108,32,98,117,115,121,58,32,37, - 120,10,0,0,101,116,104,95,105,110,105,116, - 46,99,0,0,42,42,42,76,49,87,65,10, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,35,35,35,32,84,66,68,32, - 98,108,111,99,107,115,32,97,114,101,110,39, - 116,32,98,101,105,110,103,32,102,114,101,101, - 100,10,0,0,65,116,116,101,109,112,116,32, - 116,111,32,102,114,101,101,32,98,111,103,117, - 115,32,84,66,68,32,37,120,10,0,0,0, - 35,35,35,32,66,85,70,32,98,108,111,99, - 107,115,32,97,114,101,110,39,116,32,98,101, - 105,110,103,32,102,114,101,101,100,10,0,0, - 65,116,116,101,109,112,116,32,116,111,32,102, - 114,101,101,32,98,111,103,117,115,32,66,85, - 70,32,37,120,10,0,0,0,0,0,0,0, - 0,0,0,0,82,70,68,115,32,37,100,32, - 10,0,0,0,82,66,68,115,32,37,100,32, - 10,0,0,0,37,115,58,37,100,58,32,102, - 97,105,108,101,100,32,97,115,115,101,114,116, - 105,111,110,32,96,37,115,39,10,0,0,0, - 101,116,104,95,114,99,118,46,99,0,0,0, - 100,115,116,99,104,97,110,32,62,61,32,49, - 32,38,38,32,100,115,116,99,104,97,110,32, - 60,32,78,99,104,97,110,0,37,115,37,48, - 50,88,58,37,48,50,88,58,37,48,50,88, - 58,37,48,50,88,58,37,48,50,88,58,37, - 48,50,88,37,115,0,0,0,176,72,0,131, - 80,67,0,131,164,67,0,131,24,68,0,131, - 80,67,0,131,0,0,0,0,4,82,0,131, - 184,76,0,131,12,77,0,131,128,77,0,131, - 184,76,0,131,0,0,0,0,0,0,0,0, - 0,0,0,0,37,115,58,37,100,58,32,102, - 97,105,108,101,100,32,97,115,115,101,114,116, - 105,111,110,32,96,37,115,39,10,0,0,0, - 101,116,104,95,120,109,105,116,46,99,0,0, - 99,98,112,45,62,110,111,112,46,99,109,100, - 32,61,61,32,73,53,57,54,95,67,66,95, - 67,77,68,95,78,79,80,124,73,53,57,54, - 95,67,66,95,67,77,68,95,69,76,0,0, - 99,98,112,45,62,110,111,112,46,99,109,100, - 32,38,32,73,53,57,54,95,67,66,95,67, - 77,68,0,0,112,45,62,115,99,98,112,45, - 62,115,116,97,116,117,115,32,38,32,73,53, - 57,54,95,83,67,66,95,67,78,65,0,0, - 35,35,35,32,99,109,100,32,115,116,105,108, - 108,32,98,117,115,121,58,32,37,120,10,0, - 37,100,61,37,100,44,37,120,44,37,100,10, - 0,0,0,0,39,37,115,39,32,37,120,32, - 37,120,10,0,37,48,56,120,58,32,37,48, - 50,120,10,0,37,48,56,120,58,32,37,48, - 52,120,10,0,37,48,56,120,58,32,37,48, - 56,120,10,0,108,105,110,107,32,115,116,97, - 116,101,32,37,48,50,120,10,0,0,0,0, - 42,42,42,32,103,111,116,32,37,100,32,105, - 110,116,101,114,114,117,112,116,115,10,0,0, - 35,35,35,32,69,120,112,101,99,116,101,100, - 32,37,100,32,98,117,116,32,103,111,116,32, - 37,100,32,105,110,116,101,114,114,117,112,116, - 115,10,0,0,80,76,88,57,48,54,48,32, - 65,100,100,114,101,115,115,32,61,32,37,88, - 32,68,65,84,65,32,61,32,37,88,32,10, - 0,0,0,0,42,42,42,32,87,114,105,116, - 101,32,111,102,32,37,120,32,116,111,32,37, - 100,32,102,97,105,108,101,100,10,0,0,0, - 42,42,42,32,87,114,105,116,101,32,111,102, - 32,37,120,32,116,111,32,37,120,32,102,97, - 105,108,101,100,10,0,0,0,42,42,42,42, - 42,42,42,42,42,42,42,42,42,42,42,42, - 0,0,0,0,42,42,42,32,73,108,108,101, - 103,97,108,32,99,111,109,109,97,110,100,32, - 39,37,115,39,10,0,0,0,45,45,45,32, - 99,111,109,109,97,110,100,115,32,109,44,116, - 44,101,44,69,44,97,44,120,44,108,44,115, - 44,112,32,99,97,110,32,98,101,32,112,114, - 101,102,105,120,101,100,32,119,105,116,104,32, - 97,32,114,101,112,101,97,116,32,99,111,117, - 110,116,0,0,108,32,120,112,111,114,116,32, - 114,112,111,114,116,32,91,108,101,110,93,32, - 32,32,32,32,32,32,32,32,32,76,111,111, - 112,98,97,99,107,32,116,101,115,116,32,102, - 114,111,109,32,120,112,111,114,116,32,40,49, - 45,54,41,32,116,111,32,114,112,111,114,116, - 32,40,49,45,54,41,0,0,105,32,32,32, - 32,32,32,32,32,32,73,110,116,101,114,114, - 117,112,116,32,72,111,115,116,32,32,124,32, - 32,115,32,91,112,111,114,116,93,32,91,108, - 101,110,93,32,66,97,99,107,50,98,97,99, - 107,32,120,109,105,116,32,99,110,116,32,112, - 97,99,107,101,116,115,0,0,80,32,32,32, - 32,32,32,32,32,32,84,101,115,116,32,80, - 76,88,32,57,48,54,48,32,32,32,124,32, - 32,100,32,91,114,124,119,124,108,124,116,93, - 32,91,118,97,108,124,39,99,39,93,32,32, - 82,101,97,100,47,87,114,105,116,101,47,76, - 111,111,112,47,84,105,109,101,32,68,77,65, - 0,0,0,0,76,32,32,32,32,32,32,32, - 32,32,82,101,97,100,32,76,105,110,107,32, - 76,69,68,115,32,32,124,32,32,112,32,114, - 101,103,110,111,32,91,118,97,108,93,32,32, - 82,101,97,100,47,91,119,114,105,116,101,93, - 32,80,76,88,32,114,101,103,105,115,116,101, - 114,0,0,0,65,32,97,100,100,114,32,32, - 32,32,83,101,116,32,101,116,104,101,114,32, - 97,100,100,114,32,32,124,32,32,36,32,115, - 99,114,105,112,116,32,32,32,32,32,32,32, - 82,101,97,100,32,99,109,100,115,32,102,114, - 111,109,32,102,105,108,101,32,39,115,99,114, - 105,112,116,39,0,0,0,0,120,32,91,112, - 111,114,116,93,32,32,84,120,32,101,116,104, - 101,114,32,32,32,32,32,32,32,32,124,32, - 32,82,32,91,112,111,114,116,93,32,32,32, - 32,32,32,32,82,120,32,101,116,104,101,114, - 32,91,111,110,32,112,111,114,116,32,49,45, - 54,93,0,0,72,32,32,32,32,32,32,32, - 32,32,84,111,103,103,108,101,32,70,67,67, - 32,116,101,115,116,32,124,32,32,113,44,94, - 68,44,94,90,32,32,32,32,32,32,32,32, - 81,117,105,116,0,0,0,0,97,32,32,32, - 32,32,32,32,32,32,84,101,115,116,32,97, - 108,108,32,32,32,32,32,32,32,32,124,32, - 32,90,32,109,115,101,99,115,32,32,32,32, - 32,32,32,32,80,97,117,115,101,32,102,111, - 114,32,97,32,119,104,105,108,101,0,0,0, - 69,32,32,32,32,32,32,32,32,32,84,101, - 115,116,32,69,69,80,82,79,77,32,32,32, - 32,32,124,32,32,83,114,32,97,100,100,114, - 59,32,83,119,32,97,100,100,114,32,118,97, - 108,59,32,32,82,101,97,100,47,87,114,105, - 116,101,32,80,76,88,32,69,50,32,114,101, - 103,0,0,0,101,32,91,112,111,114,116,93, - 32,32,84,101,115,116,32,101,116,104,101,114, - 110,101,116,32,32,32,124,32,32,69,114,32, - 97,100,100,114,59,32,69,119,32,97,100,100, - 114,32,118,97,108,59,32,32,82,101,97,100, - 47,87,114,105,116,101,32,69,69,80,82,79, - 77,32,114,101,103,0,0,0,116,32,32,32, - 32,32,32,32,32,32,84,101,115,116,32,116, - 105,109,101,114,115,32,32,32,32,32,124,32, - 32,119,91,42,93,32,97,100,100,114,32,118, - 97,108,32,32,87,114,105,116,101,32,109,101, - 109,111,114,121,58,32,119,98,32,119,104,44, - 32,119,119,44,32,119,116,0,109,32,32,32, - 32,32,32,32,32,32,84,101,115,116,32,109, - 101,109,111,114,121,32,32,32,32,32,124,32, - 32,114,91,42,93,32,97,100,100,114,32,32, - 32,32,32,32,82,101,97,100,32,109,101,109, - 111,114,121,58,32,114,98,32,114,104,44,32, - 114,119,44,32,114,116,0,0,42,42,42,32, - 82,105,103,104,116,83,119,105,116,99,104,32, - 68,105,97,103,110,111,115,116,105,99,115,32, - 109,101,110,117,32,42,42,42,0,0,0,0, - 45,45,45,32,84,104,114,101,101,32,99,111, - 112,105,101,115,32,111,102,32,97,100,100,114, - 101,115,115,32,100,111,32,110,111,116,32,97, - 103,114,101,101,33,10,0,0,45,45,45,32, - 69,116,104,101,114,32,65,100,100,114,101,115, - 115,32,78,111,116,32,83,101,116,33,10,0, - 45,45,45,32,69,116,104,101,114,32,65,100, - 100,114,101,115,115,32,105,115,32,97,32,109, - 117,108,116,105,99,97,115,116,32,97,100,100, - 114,101,115,115,33,10,0,0,42,42,42,32, - 37,48,50,88,37,48,50,88,37,48,50,88, - 58,37,48,50,88,58,37,48,50,88,37,48, - 50,88,10,0,45,45,45,32,70,105,114,115, - 116,32,98,121,116,101,32,40,37,48,50,88, - 41,32,105,115,32,97,32,98,114,111,97,100, - 99,97,115,116,32,97,100,100,114,101,115,115, - 10,0,0,0,45,45,45,32,76,97,115,116, - 32,100,105,103,105,116,32,109,117,115,116,32, - 98,101,32,48,32,111,114,32,56,10,0,0, - 42,42,42,32,69,105,103,104,116,32,101,116, - 104,101,114,110,101,116,32,97,100,100,114,101, - 115,115,101,115,32,104,97,118,101,32,98,101, - 101,110,32,117,115,101,100,58,10,0,0,0, - 42,42,42,32,80,111,114,116,32,37,100,32, - 101,116,104,101,114,110,101,116,32,97,100,100, - 114,101,115,115,32,105,115,32,0,0,0,0, - 45,45,45,32,66,97,100,32,101,116,104,101, - 114,32,97,100,100,114,101,115,115,32,39,37, - 115,39,32,115,112,101,99,105,102,105,101,100, - 10,0,0,0,0,0,0,0,244,101,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,244,101,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,64,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,28,111,0,131,104,112,0,131, - 104,112,0,131,132,111,0,131,152,109,0,131, - 104,112,0,131,104,112,0,131,244,101,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 24,107,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,76,108,0,131,104,112,0,131, - 228,108,0,131,112,110,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 28,109,0,131,104,112,0,131,48,111,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 84,109,0,131,104,112,0,131,104,112,0,131, - 32,112,0,131,136,106,0,131,28,106,0,131, - 104,112,0,131,104,112,0,131,52,107,0,131, - 104,112,0,131,104,112,0,131,252,106,0,131, - 88,111,0,131,104,112,0,131,104,112,0,131, - 196,107,0,131,104,112,0,131,180,104,0,131, - 168,106,0,131,92,106,0,131,104,112,0,131, - 104,112,0,131,148,105,0,131,192,106,0,131, - 0,0,0,0,188,111,0,131,204,111,0,131, - 12,112,0,131,12,112,0,131,12,112,0,131, - 12,112,0,131,12,112,0,131,12,112,0,131, - 12,112,0,131,12,112,0,131,12,112,0,131, - 12,112,0,131,252,111,0,131,12,112,0,131, - 12,112,0,131,12,112,0,131,12,112,0,131, - 236,111,0,131,12,112,0,131,12,112,0,131, - 12,112,0,131,12,112,0,131,220,111,0,131, - 252,111,0,131,0,0,0,0,0,0,0,0, - 42,42,42,32,69,69,80,82,79,77,32,80, - 97,115,115,101,100,10,0,0,33,33,33,32, - 69,69,80,82,79,77,32,70,97,105,108,117, - 114,101,58,32,87,114,111,116,101,32,37,48, - 52,120,32,97,116,32,37,100,44,32,103,111, - 116,32,37,48,52,120,10,0,0,0,0,0, - 0,0,0,0,0,0,0,0,35,35,35,70, - 114,97,109,101,32,37,100,32,100,105,100,32, - 110,111,116,32,97,114,114,105,118,101,10,0, - 35,35,35,32,70,114,97,109,101,32,37,100, - 44,32,108,101,110,32,37,100,44,32,98,121, - 116,101,32,37,100,44,32,119,97,110,116,32, - 37,120,32,103,111,116,32,37,120,10,0,0, - 35,35,35,70,114,97,109,101,32,37,100,32, - 119,114,111,110,103,32,108,101,110,103,116,104, - 32,40,119,97,110,116,32,37,100,32,103,111, - 116,32,37,100,41,10,0,0,35,35,35,70, - 114,97,109,101,32,37,100,58,32,103,111,116, - 32,115,101,113,32,37,100,10,0,0,0,0, - 35,35,35,32,37,100,32,67,82,67,32,101, - 114,114,111,114,115,32,111,99,99,117,114,101, - 100,10,0,0,35,35,35,32,37,100,32,65, - 108,105,103,110,32,101,114,114,111,114,115,32, - 111,99,99,117,114,101,100,10,0,0,0,0, - 35,35,35,32,37,100,32,83,104,111,114,116, - 32,101,114,114,111,114,115,32,111,99,99,117, - 114,101,100,10,0,0,0,0,35,35,35,32, - 37,100,32,79,118,101,114,114,117,110,32,101, - 114,114,111,114,115,32,111,99,99,117,114,101, - 100,10,0,0,35,35,35,32,67,85,32,115, - 116,105,108,108,32,114,117,110,110,105,110,103, - 58,32,37,120,10,0,0,0,35,35,35,32, - 99,109,100,32,115,116,105,108,108,32,98,117, - 115,121,58,32,37,120,10,0,35,35,35,32, - 115,116,97,116,117,115,32,115,116,105,108,108, - 32,98,117,115,121,58,32,37,120,10,0,0, - 67,66,61,37,120,44,32,84,66,68,61,37, - 120,44,32,66,85,70,61,37,120,10,0,0, - 116,101,115,116,95,101,116,104,101,114,46,99, - 0,0,0,0,37,100,32,102,114,97,109,101, - 115,32,111,102,32,108,101,110,103,116,104,32, - 37,100,32,115,101,110,116,32,105,110,32,37, - 100,32,109,115,101,99,115,10,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 42,42,42,32,56,50,53,52,32,84,105,109, - 101,114,32,48,32,79,75,44,32,99,111,117, - 110,116,32,119,97,115,32,37,100,10,0,0, - 42,42,42,32,56,50,53,52,32,84,105,109, - 101,114,32,48,32,110,111,116,32,105,110,116, - 101,114,114,117,112,116,105,110,103,32,37,100, - 10,0,0,0,42,42,42,32,56,50,53,52, - 32,84,105,109,101,114,32,48,32,115,112,101, - 101,100,32,119,114,111,110,103,44,32,103,111, - 116,32,37,100,32,115,104,111,117,108,100,32, - 98,101,32,49,48,48,48,10,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 9,37,120,58,32,119,97,110,116,32,37,120, - 32,103,111,116,32,37,120,10,0,0,0,0, - 45,45,45,32,82,65,77,32,84,101,115,116, - 32,111,102,32,37,120,32,116,111,32,37,120, - 32,102,97,105,108,101,100,10,0,0,0,0, - 42,42,42,32,82,65,77,32,84,101,115,116, - 32,111,102,32,37,120,32,116,111,32,37,120, - 32,112,97,115,115,101,100,10,0,0,0,0, - 35,35,35,32,68,77,65,32,68,79,78,69, - 32,110,101,118,101,114,32,111,99,99,117,114, - 114,101,100,46,32,32,99,115,114,32,61,32, - 37,120,10,0,35,35,35,32,72,111,115,116, - 32,110,101,118,101,114,32,103,111,116,32,68, - 77,65,32,105,110,116,101,114,114,117,112,116, - 46,32,98,99,95,99,110,116,32,61,32,37, - 100,10,0,0,35,35,35,32,68,77,65,32, - 101,114,114,111,114,32,97,116,32,105,110,100, - 101,120,32,37,100,58,32,119,97,110,116,101, - 100,32,37,48,50,120,32,103,111,116,32,37, - 48,50,120,10,0,0,0,0,35,35,35,32, - 73,108,108,101,103,97,108,32,72,111,115,116, - 32,97,100,100,114,32,40,61,37,120,41,32, - 111,114,32,108,101,110,103,116,104,32,40,61, - 37,100,41,10,0,0,0,0,35,35,35,32, - 67,111,117,110,116,32,99,97,110,110,111,116, - 32,98,101,32,62,32,49,48,50,52,42,49, - 48,50,52,10,0,0,0,0,42,42,42,32, - 108,99,108,46,66,117,102,49,32,61,32,37, - 120,32,45,45,62,32,104,111,115,116,46,66, - 117,102,32,61,32,37,120,32,45,45,62,32, - 108,99,108,46,66,117,102,50,32,61,32,37, - 120,10,0,0,42,42,42,32,62,32,68,98, - 32,37,100,32,40,98,117,114,115,116,41,59, - 32,62,32,68,119,32,37,100,32,40,119,97, - 105,116,115,116,97,116,101,115,41,10,0,0, - 35,35,35,32,83,101,99,111,110,100,32,97, - 114,103,32,109,117,115,116,32,98,101,32,39, - 114,39,32,111,114,32,39,119,39,32,111,114, - 32,39,108,39,10,0,0,0,42,42,42,32, - 68,77,65,32,37,115,32,105,110,32,37,52, - 100,32,98,121,116,101,32,99,104,117,110,107, - 115,58,32,0,32,32,116,111,32,104,111,115, - 116,0,0,0,102,114,111,109,32,104,111,115, - 116,0,0,0,37,56,100,32,98,121,116,101, - 115,47,115,101,99,46,10,0,116,105,109,101, - 32,116,111,111,32,115,104,111,114,116,32,116, - 111,32,109,101,97,115,117,114,101,10,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 80,37,100,45,62,37,115,32,10,0,0,0, - 116,114,97,110,115,109,105,116,32,112,101,110, - 100,105,110,103,32,111,110,32,37,100,10,0, - 116,114,97,110,115,109,105,116,32,99,111,110, - 102,105,103,32,111,110,32,37,100,10,0,0, - 116,114,97,110,115,109,105,116,32,116,99,110, - 10,0,0,0,116,99,110,32,101,120,112,10, - 0,0,0,0,102,111,114,119,97,114,100,95, - 100,101,108,97,121,32,101,120,112,32,37,100, - 10,0,0,0,109,101,115,115,97,103,101,95, - 97,103,101,32,101,120,112,32,37,100,10,0, - 104,111,108,100,32,101,120,112,32,37,100,10, - 0,0,0,0,84,120,67,79,78,70,73,71, - 37,100,10,0,84,120,84,67,78,37,100,10, - 0,0,0,0,114,99,118,32,99,111,110,102, - 105,103,32,111,110,32,37,100,10,0,0,0, - 90,69,82,79,32,114,111,111,116,33,32,97, - 116,32,37,120,32,0,0,0,115,117,112,101, - 114,99,101,100,101,115,32,37,100,10,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 65,82,80,82,69,81,32,37,120,33,10,0, - 65,82,80,82,69,80,32,37,120,33,10,0, - 83,101,110,100,32,85,68,80,32,37,100,10, - 0,0,0,0,78,111,32,82,66,68,39,115, - 32,105,110,32,85,68,80,32,40,37,100,32, - 37,100,41,10,0,0,0,0,83,101,110,116, - 32,85,68,80,32,37,100,10,0,0,0,0, - 83,78,77,80,32,39,37,99,39,32,108,101, - 110,32,37,100,10,0,0,0,69,110,118,111, - 121,32,114,99,61,37,100,10,0,0,0,0, - 71,101,110,32,116,114,97,112,32,37,100,32, - 114,99,61,37,100,10,0,0,66,97,100,32, - 85,68,80,32,99,104,101,99,107,115,117,109, - 32,37,120,32,108,101,110,32,37,100,10,0, - 66,97,100,32,85,68,80,32,108,101,110,103, - 116,104,32,119,97,110,116,32,37,100,32,103, - 111,116,32,37,100,10,0,0,66,97,100,32, - 73,67,77,80,32,99,104,101,99,107,115,117, - 109,10,0,0,78,111,32,82,66,68,39,115, - 32,105,110,32,73,67,77,80,10,0,0,0, - 66,97,100,32,73,80,32,99,104,101,99,107, - 115,117,109,10,0,0,0,0,84,114,117,110, - 99,97,116,101,100,32,73,80,10,0,0,0, - 83,69,78,84,32,73,80,88,33,10,0,0, - 110,111,32,115,121,115,78,97,109,101,0,0, - 114,105,103,104,116,115,119,105,116,99,104,45, - 0,0,0,0,78,111,32,82,66,68,39,115, - 32,105,110,32,115,101,110,100,95,115,97,112, - 10,0,0,0,78,111,32,82,66,68,39,115, - 32,105,110,32,73,80,88,10,0,0,0,0, - 84,114,117,110,99,97,116,101,100,32,73,80, - 88,10,0,0,0,0,0,0,0,0,0,0, - 77,97,108,108,111,99,32,114,101,116,117,114, - 110,115,32,78,85,76,76,33,0,0,0,0, - 0,0,0,0,0,0,0,0,68,105,103,105, - 32,73,110,116,108,46,32,82,105,103,104,116, - 83,119,105,116,99,104,32,83,69,45,88,0, - 73,110,116,101,108,32,56,50,53,57,54,0, - 0,0,0,0,0,0,0,0,8,206,0,131, - 36,206,0,131,92,206,0,131,112,206,0,131, - 132,206,0,131,220,206,0,131,4,207,0,131, - 4,207,0,131,36,207,0,131,52,207,0,131, - 80,207,0,131,104,207,0,131,132,207,0,131, - 160,207,0,131,188,207,0,131,188,207,0,131, - 216,207,0,131,240,207,0,131,12,208,0,131, - 40,208,0,131,72,208,0,131,112,208,0,131, - 180,210,0,131,232,210,0,131,4,211,0,131, - 36,211,0,131,60,211,0,131,0,0,0,0, - 64,213,0,131,92,213,0,131,124,213,0,131, - 160,213,0,131,60,214,0,131,60,214,0,131, - 60,214,0,131,188,213,0,131,216,213,0,131, - 244,213,0,131,28,214,0,131,168,214,0,131, - 60,214,0,131,168,214,0,131,168,214,0,131, - 88,214,0,131,132,214,0,131,0,0,0,0, - 36,216,0,131,68,216,0,131,104,216,0,131, - 140,216,0,131,140,216,0,131,0,0,0,0, - 248,217,0,131,12,218,0,131,40,218,0,131, - 76,218,0,131,124,218,0,131,152,218,0,131, - 200,218,0,131,228,218,0,131,88,219,0,131, - 116,219,0,131,64,224,0,131,92,224,0,131, - 124,224,0,131,152,224,0,131,184,224,0,131, - 0,0,0,0,110,111,32,115,121,115,67,111, - 110,116,97,99,116,0,0,0,110,111,32,115, - 121,115,78,97,109,101,0,0,110,111,32,115, - 121,115,76,111,99,97,116,105,111,110,0,0, - 37,115,58,37,100,58,32,102,97,105,108,101, - 100,32,97,115,115,101,114,116,105,111,110,32, - 96,37,115,39,10,0,0,0,110,117,109,114, - 101,103,115,32,60,61,32,78,86,82,65,77, - 95,78,82,69,71,83,32,38,38,32,110,117, - 109,114,101,103,115,32,62,32,48,0,0,0, - 102,105,114,115,116,114,101,103,32,60,32,78, - 86,82,65,77,95,78,82,69,71,83,32,38, - 38,32,102,105,114,115,116,114,101,103,32,62, - 61,32,48,0,0,0,0,0,10,13,69,82, - 82,79,82,32,45,0,0,0,0,0,0,0, - 192,244,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,192,251,0,131, - 8,252,0,131,8,252,0,131,200,251,0,131, - 212,251,0,131,212,251,0,131,212,251,0,131, - 212,251,0,131,212,251,0,131,212,251,0,131, - 212,251,0,131,212,251,0,131,212,251,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,200,244,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 212,249,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,20,245,0,131,8,245,0,131, - 84,247,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,244,251,0,131, - 8,252,0,131,8,252,0,131,48,246,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 240,250,0,131,8,252,0,131,132,248,0,131, - 8,252,0,131,8,252,0,131,160,249,0,131, - 72,46,1,131,228,47,1,131,152,46,1,131, - 132,47,1,131,0,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,144,47,1,131, - 108,46,1,131,108,46,1,131,108,46,1,131, - 152,46,1,131,152,46,1,131,228,47,1,131, - 108,46,1,131,20,50,1,131,216,50,1,131, - 56,50,1,131,224,50,1,131,104,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 144,50,1,131,20,50,1,131,20,50,1,131, - 20,50,1,131,56,50,1,131,56,50,1,131, - 216,50,1,131,20,50,1,131,124,53,1,131, - 96,53,1,131,96,53,1,131,96,53,1,131, - 96,53,1,131,96,53,1,131,96,53,1,131, - 96,53,1,131,96,53,1,131,96,53,1,131, - 96,53,1,131,96,53,1,131,96,53,1,131, - 96,53,1,131,88,53,1,131,64,53,1,131, - 80,53,1,131,72,53,1,131,64,53,1,131, - 0,0,0,0,28,83,1,131,36,83,1,131, - 36,83,1,131,36,83,1,131,36,83,1,131, - 28,83,1,131,44,83,1,131,44,83,1,131, - 44,83,1,131,44,83,1,131,44,83,1,131, - 28,83,1,131,44,83,1,131,0,0,0,0, - 196,88,1,131,232,88,1,131,208,88,1,131, - 220,88,1,131,244,88,1,131,0,0,0,0, - 4,0,0,0,5,0,0,0,6,0,0,0, - 7,0,0,0,2,0,0,0,3,0,0,0, - 0,0,0,0,1,0,0,0,72,30,0,131, - 72,30,0,131,216,44,0,131,0,30,0,131, - 108,30,0,131,108,30,0,131,108,30,0,131, - 108,30,0,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,20,137,1,131, - 204,136,1,131,132,136,1,131,56,136,1,131, - 236,135,1,131,172,135,1,131,120,135,1,131, - 52,135,1,131,232,134,1,131,160,134,1,131, - 80,134,1,131,8,134,1,131,188,133,1,131, - 120,133,1,131,0,0,0,0,0,0,0,0, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,0,0,0,0,255,85,170, - 0,0,0,0,4,0,8,0,16,0,32,0, - 64,0,0,1,0,8,0,0,0,0,0,0, - 0,0,0,0,0,4,3,2,1,0,0,0, - 7,0,0,0,1,0,1,0,1,0,2,0, - 20,0,15,0,1,0,0,128,128,0,0,0, - 100,0,0,0,96,207,1,131,92,207,1,131, - 88,207,1,131,84,207,1,131,80,207,1,131, - 0,0,0,0,0,0,0,0,48,49,50,51, - 52,53,54,55,56,57,65,66,67,68,69,70, - 0,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,64,204,0,131,156,202,0,131, - 96,148,1,131,1,0,4,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 200,155,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,124,204,0,131,156,202,0,131, - 168,210,1,131,1,0,6,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 4,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,132,204,0,131,156,202,0,131, - 4,1,0,163,1,0,67,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 64,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,168,204,0,131,248,204,0,131, - 80,18,3,131,1,0,4,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 124,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,168,204,0,131,32,205,0,131, - 96,18,3,131,1,0,4,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 184,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,168,204,0,131,72,205,0,131, - 112,18,3,131,1,0,4,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 244,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,112,205,0,131,156,202,0,131, - 2,0,0,0,1,0,2,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 48,157,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 220,155,1,131,2,0,0,0,24,156,1,131, - 3,0,0,0,84,156,1,131,4,0,0,0, - 144,156,1,131,5,0,0,0,204,156,1,131, - 6,0,0,0,8,157,1,131,7,0,0,0, - 68,157,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,120,205,0,131, - 156,202,0,131,48,211,1,131,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,172,157,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,4,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 124,148,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,6,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,220,5,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,66,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,4,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,3,180,208,0,131,132,205,0,131, - 228,209,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,67,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,66,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,6,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,0,0,232,157,1,131, - 2,0,0,0,16,158,1,131,3,0,0,0, - 56,158,1,131,4,0,0,0,96,158,1,131, - 5,0,0,0,136,158,1,131,6,0,0,0, - 176,158,1,131,7,0,0,0,216,158,1,131, - 8,0,0,0,0,159,1,131,9,0,0,0, - 40,159,1,131,10,0,0,0,80,159,1,131, - 11,0,0,0,120,159,1,131,12,0,0,0, - 160,159,1,131,13,0,0,0,200,159,1,131, - 14,0,0,0,240,159,1,131,15,0,0,0, - 24,160,1,131,16,0,0,0,64,160,1,131, - 17,0,0,0,104,160,1,131,18,0,0,0, - 144,160,1,131,19,0,0,0,184,160,1,131, - 20,0,0,0,224,160,1,131,21,0,0,0, - 8,161,1,131,22,0,0,0,48,161,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 32,208,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,192,157,1,131,2,0,0,0, - 40,208,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,112,205,0,131, - 60,210,0,131,2,0,0,0,1,0,2,3, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,56,162,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,120,205,0,131, - 60,210,0,131,0,17,3,131,1,0,2,3, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,116,162,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,4,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,176,162,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,8,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,236,162,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,12,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,40,163,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,16,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,100,163,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,20,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,160,163,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,24,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,220,163,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,28,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,24,164,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,32,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,84,164,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,36,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,144,164,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,40,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,204,164,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,120,205,0,131, - 156,202,0,131,44,17,3,131,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,8,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,48,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,68,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,52,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,128,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,56,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,188,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,60,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,248,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,64,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,52,166,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,68,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,112,166,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,64,1,44,202,0,131,88,210,0,131, - 164,202,0,131,120,211,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 88,210,0,131,164,202,0,131,120,211,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,64,1, - 44,202,0,131,88,210,0,131,164,202,0,131, - 120,211,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,44,202,0,131,88,210,0,131, - 164,202,0,131,120,211,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 88,210,0,131,164,202,0,131,120,211,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 172,166,1,131,2,0,0,0,212,166,1,131, - 3,0,0,0,252,166,1,131,4,0,0,0, - 36,167,1,131,5,0,0,0,76,167,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 56,208,1,131,0,0,0,0,0,0,0,0, - 1,0,64,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 84,212,0,131,16,212,0,131,52,212,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 84,212,0,131,16,212,0,131,52,212,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,64,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,1, - 84,212,0,131,16,212,0,131,164,202,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,64,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 84,212,0,131,16,212,0,131,52,212,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,6,1,84,212,0,131,16,212,0,131, - 164,202,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,0,0,180,167,1,131, - 2,0,0,0,220,167,1,131,3,0,0,0, - 4,168,1,131,4,0,0,0,44,168,1,131, - 5,0,0,0,84,168,1,131,6,0,0,0, - 124,168,1,131,7,0,0,0,164,168,1,131, - 8,0,0,0,204,168,1,131,9,0,0,0, - 244,168,1,131,10,0,0,0,28,169,1,131, - 11,0,0,0,68,169,1,131,12,0,0,0, - 108,169,1,131,13,0,0,0,148,169,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 72,208,1,131,0,0,0,0,0,0,0,0, - 1,0,2,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,4,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,64,3, - 84,212,0,131,16,212,0,131,52,212,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,0,0,60,170,1,131, - 2,0,0,0,100,170,1,131,3,0,0,0, - 140,170,1,131,4,0,0,0,180,170,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 88,208,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,72,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,20,171,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,0,0,76,162,1,131,2,0,0,0, - 136,162,1,131,3,0,0,0,196,162,1,131, - 4,0,0,0,0,163,1,131,5,0,0,0, - 60,163,1,131,6,0,0,0,120,163,1,131, - 7,0,0,0,180,163,1,131,8,0,0,0, - 240,163,1,131,9,0,0,0,44,164,1,131, - 10,0,0,0,104,164,1,131,11,0,0,0, - 164,164,1,131,12,0,0,0,224,164,1,131, - 13,0,0,0,28,165,1,131,14,0,0,0, - 88,165,1,131,15,0,0,0,148,165,1,131, - 16,0,0,0,208,165,1,131,17,0,0,0, - 12,166,1,131,18,0,0,0,72,166,1,131, - 19,0,0,0,132,166,1,131,20,0,0,0, - 64,208,1,131,21,0,0,0,80,208,1,131, - 22,0,0,0,96,208,1,131,23,0,0,0, - 40,171,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,144,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,16,172,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,148,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,76,172,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,152,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,136,172,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,156,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,196,172,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,160,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,0,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,164,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,60,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,168,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,120,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,172,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,180,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,176,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,240,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,180,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,44,174,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,184,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,104,174,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,188,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,164,174,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,192,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,224,174,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,196,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,28,175,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,200,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,88,175,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,204,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,148,175,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,208,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,208,175,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,212,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,12,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,216,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,72,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,220,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,132,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,224,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,192,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,228,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,252,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,232,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,56,177,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,236,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,116,177,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,240,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,176,177,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,244,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,236,177,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,0,0,36,172,1,131,2,0,0,0, - 96,172,1,131,3,0,0,0,156,172,1,131, - 4,0,0,0,216,172,1,131,5,0,0,0, - 20,173,1,131,6,0,0,0,80,173,1,131, - 7,0,0,0,140,173,1,131,8,0,0,0, - 200,173,1,131,9,0,0,0,4,174,1,131, - 10,0,0,0,64,174,1,131,11,0,0,0, - 124,174,1,131,12,0,0,0,184,174,1,131, - 13,0,0,0,244,174,1,131,14,0,0,0, - 48,175,1,131,15,0,0,0,108,175,1,131, - 16,0,0,0,168,175,1,131,17,0,0,0, - 228,175,1,131,18,0,0,0,32,176,1,131, - 19,0,0,0,92,176,1,131,20,0,0,0, - 152,176,1,131,21,0,0,0,212,176,1,131, - 22,0,0,0,16,177,1,131,23,0,0,0, - 76,177,1,131,24,0,0,0,136,177,1,131, - 25,0,0,0,196,177,1,131,26,0,0,0, - 0,178,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,112,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,0,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,116,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,60,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,120,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,120,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,124,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,180,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,200,212,0,131, - 156,202,0,131,220,5,0,163,1,0,64,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,240,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,112,205,0,131, - 156,202,0,131,161,0,0,0,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,44,180,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,0,0,4,180,1,131,2,0,0,0, - 64,180,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,120,208,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,20,179,1,131, - 2,0,0,0,80,179,1,131,3,0,0,0, - 140,179,1,131,4,0,0,0,200,179,1,131, - 5,0,0,0,128,208,1,131,0,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,208,212,0,131, - 164,202,0,131,196,214,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,208,212,0,131, - 164,202,0,131,196,214,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,208,212,0,131, - 164,202,0,131,196,214,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,208,212,0,131, - 164,202,0,131,196,214,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,6,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,0,0,192,180,1,131,2,0,0,0, - 232,180,1,131,3,0,0,0,16,181,1,131, - 4,0,0,0,56,181,1,131,5,0,0,0, - 96,181,1,131,6,0,0,0,136,181,1,131, - 7,0,0,0,176,181,1,131,8,0,0,0, - 216,181,1,131,9,0,0,0,0,182,1,131, - 10,0,0,0,40,182,1,131,11,0,0,0, - 80,182,1,131,13,0,0,0,120,182,1,131, - 16,0,0,0,160,182,1,131,17,0,0,0, - 200,182,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,144,208,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 160,208,1,131,2,0,0,0,168,208,1,131, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,184,208,1,131,2,0,0,0, - 192,208,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,208,208,1,131,2,0,0,0, - 216,208,1,131,3,0,0,0,224,208,1,131, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,240,208,1,131,2,0,0,0, - 248,208,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 8,209,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,1,0,0,0,24,209,1,131, - 2,0,0,0,32,209,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,48,209,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,64,209,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,232,208,1,131, - 2,0,0,0,0,209,1,131,3,0,0,0, - 16,209,1,131,4,0,0,0,40,209,1,131, - 5,0,0,0,56,209,1,131,6,0,0,0, - 72,209,1,131,0,0,0,0,0,0,0,0, - 2,0,0,0,152,208,1,131,6,0,0,0, - 176,208,1,131,7,0,0,0,200,208,1,131, - 8,0,0,0,80,209,1,131,0,0,0,0, - 0,0,0,0,7,0,0,0,88,209,1,131, - 0,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 128,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 8,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 144,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 68,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 148,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 128,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 132,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 188,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 136,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 248,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 140,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 52,186,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 156,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 112,186,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 160,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 172,186,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 164,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 232,186,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 168,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 36,187,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 172,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 96,187,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 176,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 156,187,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 180,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 216,187,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 184,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 20,188,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 188,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 80,188,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 192,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 140,188,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 196,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 200,188,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 200,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 4,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 204,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 64,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 208,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 124,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 212,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 184,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 220,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 244,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 224,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 48,190,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 228,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 108,190,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 232,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 168,190,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 236,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 228,190,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 240,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 32,191,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,104,215,0,131,140,215,0,131, - 0,0,0,0,1,0,2,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 92,191,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 28,185,1,131,2,0,0,0,88,185,1,131, - 3,0,0,0,148,185,1,131,4,0,0,0, - 208,185,1,131,5,0,0,0,12,186,1,131, - 6,0,0,0,72,186,1,131,8,0,0,0, - 132,186,1,131,9,0,0,0,192,186,1,131, - 10,0,0,0,252,186,1,131,11,0,0,0, - 56,187,1,131,12,0,0,0,116,187,1,131, - 13,0,0,0,176,187,1,131,14,0,0,0, - 236,187,1,131,15,0,0,0,40,188,1,131, - 16,0,0,0,100,188,1,131,17,0,0,0, - 160,188,1,131,18,0,0,0,220,188,1,131, - 19,0,0,0,24,189,1,131,20,0,0,0, - 84,189,1,131,21,0,0,0,144,189,1,131, - 22,0,0,0,204,189,1,131,24,0,0,0, - 8,190,1,131,25,0,0,0,68,190,1,131, - 26,0,0,0,128,190,1,131,27,0,0,0, - 188,190,1,131,28,0,0,0,248,190,1,131, - 29,0,0,0,52,191,1,131,30,0,0,0, - 112,191,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,180,215,0,131, - 156,202,0,131,218,12,3,131,1,0,4,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,128,192,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,120,205,0,131, - 156,202,0,131,40,211,1,131,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,188,192,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,112,205,0,131, - 156,202,0,131,2,0,0,0,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,248,192,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,44,202,0,131,200,215,0,131, - 164,202,0,131,196,216,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 200,215,0,131,164,202,0,131,196,216,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,6,1, - 44,202,0,131,200,215,0,131,164,202,0,131, - 196,216,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,200,215,0,131, - 164,202,0,131,196,216,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 200,215,0,131,164,202,0,131,196,216,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 52,193,1,131,2,0,0,0,92,193,1,131, - 3,0,0,0,132,193,1,131,4,0,0,0, - 172,193,1,131,5,0,0,0,212,193,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 112,209,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,148,192,1,131,2,0,0,0, - 208,192,1,131,3,0,0,0,12,193,1,131, - 4,0,0,0,120,209,1,131,0,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 112,205,0,131,156,202,0,131,3,0,0,0, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,100,194,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,60,210,0,131,216,12,3,131, - 1,0,2,3,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,160,194,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 104,217,0,131,156,202,0,131,0,0,0,0, - 1,0,67,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,220,194,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 104,217,0,131,156,202,0,131,0,0,0,0, - 1,0,65,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,24,195,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 112,217,0,131,156,202,0,131,216,12,3,131, - 1,0,4,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,84,195,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 120,205,0,131,156,202,0,131,224,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,144,195,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 120,205,0,131,156,202,0,131,228,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,204,195,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,156,202,0,131,232,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,8,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,156,202,0,131,234,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,68,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,156,202,0,131,246,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,128,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,156,202,0,131,236,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,188,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,60,210,0,131,238,12,3,131, - 1,0,2,3,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,248,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,60,210,0,131,240,12,3,131, - 1,0,2,3,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,52,197,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,60,210,0,131,242,12,3,131, - 1,0,2,3,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,112,197,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,180,219,0,131, - 132,217,0,131,164,202,0,131,104,220,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 180,219,0,131,132,217,0,131,0,221,0,131, - 104,220,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,180,219,0,131,132,217,0,131, - 164,202,0,131,104,220,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,3,180,219,0,131, - 132,217,0,131,0,221,0,131,104,220,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 180,219,0,131,132,217,0,131,0,221,0,131, - 104,220,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,4,1,180,219,0,131,132,217,0,131, - 164,202,0,131,104,220,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,180,219,0,131, - 132,217,0,131,164,202,0,131,104,220,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,4,1, - 180,219,0,131,132,217,0,131,164,202,0,131, - 104,220,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,4,1,180,219,0,131,132,217,0,131, - 164,202,0,131,104,220,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,219,0,131, - 132,217,0,131,164,202,0,131,104,220,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 172,197,1,131,2,0,0,0,212,197,1,131, - 3,0,0,0,252,197,1,131,4,0,0,0, - 36,198,1,131,5,0,0,0,76,198,1,131, - 6,0,0,0,116,198,1,131,7,0,0,0, - 156,198,1,131,8,0,0,0,196,198,1,131, - 9,0,0,0,236,198,1,131,10,0,0,0, - 20,199,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,136,209,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,120,194,1,131, - 2,0,0,0,180,194,1,131,3,0,0,0, - 240,194,1,131,4,0,0,0,44,195,1,131, - 5,0,0,0,104,195,1,131,6,0,0,0, - 164,195,1,131,7,0,0,0,224,195,1,131, - 8,0,0,0,28,196,1,131,9,0,0,0, - 88,196,1,131,10,0,0,0,148,196,1,131, - 11,0,0,0,208,196,1,131,12,0,0,0, - 12,197,1,131,13,0,0,0,72,197,1,131, - 14,0,0,0,132,197,1,131,15,0,0,0, - 144,209,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,76,210,0,131,156,202,0,131, - 160,211,1,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 44,200,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,120,205,0,131,60,210,0,131, - 140,1,0,163,1,0,2,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 104,200,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,4,1, - 44,202,0,131,36,222,0,131,164,202,0,131, - 48,223,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,44,202,0,131,36,222,0,131, - 164,202,0,131,48,223,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 36,222,0,131,164,202,0,131,48,223,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 164,200,1,131,2,0,0,0,204,200,1,131, - 3,0,0,0,244,200,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,168,209,1,131, - 0,0,0,0,0,0,0,0,1,0,2,1, - 44,202,0,131,212,223,0,131,164,202,0,131, - 252,224,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,44,202,0,131,212,223,0,131, - 164,202,0,131,252,224,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 212,223,0,131,164,202,0,131,252,224,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,212,223,0,131,164,202,0,131, - 252,224,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,212,223,0,131, - 164,202,0,131,252,224,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,0,0,76,201,1,131, - 2,0,0,0,116,201,1,131,3,0,0,0, - 156,201,1,131,4,0,0,0,196,201,1,131, - 5,0,0,0,236,201,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,184,209,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 64,200,1,131,2,0,0,0,124,200,1,131, - 3,0,0,0,176,209,1,131,4,0,0,0, - 192,209,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,128,209,1,131,2,0,0,0, - 152,209,1,131,3,0,0,0,160,209,1,131, - 4,0,0,0,200,209,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,24,208,1,131, - 2,0,0,0,48,208,1,131,4,0,0,0, - 104,208,1,131,5,0,0,0,112,208,1,131, - 7,0,0,0,136,208,1,131,10,0,0,0, - 96,209,1,131,11,0,0,0,104,209,1,131, - 17,0,0,0,208,209,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,216,209,1,131, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,240,209,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,1,0,0,0,8,210,1,131, - 2,0,0,0,16,210,1,131,3,0,0,0, - 24,210,1,131,4,0,0,0,32,210,1,131, - 5,0,0,0,40,210,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 56,210,1,131,2,0,0,0,64,210,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 72,210,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 48,210,1,131,2,0,0,0,80,210,1,131, - 3,0,0,0,88,210,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,16,208,1,131, - 2,0,0,0,224,209,1,131,3,0,0,0, - 232,209,1,131,4,0,0,0,248,209,1,131, - 5,0,0,0,0,210,1,131,6,0,0,0, - 96,210,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,104,210,1,131,0,0,0,0, - 0,0,0,0,6,0,0,0,112,210,1,131, - 0,0,0,0,0,0,0,0,3,0,0,0, - 120,210,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,128,210,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,3,0,0,0,6,0,0,0, - 1,0,0,0,2,0,0,0,1,0,0,0, - 10,0,0,0,7,0,0,0,8,0,0,0, - 2,0,0,0,2,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,112,117,98,108, - 105,99,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,112,114,105,118,97,116,101,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 83,78,77,80,95,116,114,97,112,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 3,0,0,0,6,0,0,0,1,0,0,0, - 4,0,0,0,1,0,0,0,76,1,0,0, - 5,0,0,0,1,0,0,0,1,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 3,0,0,0,6,0,0,0,1,0,0,0, - 2,0,0,0,1,0,0,0,2,0,0,0, - 2,0,0,0,1,0,0,0,1,0,0,0, - 0,0,0,0,1,0,0,0,3,0,0,0, - 6,0,0,0,1,0,0,0,2,0,0,0, - 1,0,0,0,17,0,0,0,0,0,0,0, - 0,0,0,0,48,49,50,51,52,53,54,55, - 56,57,65,66,67,68,69,70,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 255,85,170,0,255,255,255,255,85,85,85,85, - 170,170,170,170,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,64,40,35,41, - 32,67,111,112,121,114,105,103,104,116,32,40, - 99,41,32,49,57,56,54,32,45,32,49,57, - 57,53,32,32,69,112,105,108,111,103,117,101, - 32,84,101,99,104,110,111,108,111,103,121,32, - 67,111,114,112,111,114,97,116,105,111,110,10, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,255,255, - 72,10,0,0,78,10,0,0,83,10,0,0, - 69,10,0,0,109,97,105,110,46,99,0,0, - 48,0,0,0,55,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 0,0,0,0,116,105,109,101,114,46,99,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 100,0,0,0,100,0,0,0,1,0,0,0, - 0,0,0,0,115,114,99,32,0,0,0,0, - 32,0,0,0,100,115,116,32,0,0,0,0, - 32,37,48,50,88,0,0,0,10,0,0,0, - 255,255,255,255,48,48,48,48,48,48,0,0, - 48,48,48,48,48,49,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,255,255, - 0,0,0,0,0,0,0,0,0,0,0,0, - 62,32,0,0,37,120,10,0,37,120,58,9, - 37,120,10,0,37,115,10,0,0,0,0,0, - 10,0,0,0,0,0,0,0,0,0,0,0, - 68,85,77,80,10,0,0,0,37,48,50,120, - 32,0,0,0,10,0,0,0,0,0,0,0, - 37,100,32,112,112,115,10,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0,1,0,0,0, - 119,119,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,128,194,0, - 0,0,0,0,1,128,194,0,0,16,0,0, - 66,76,75,0,70,87,68,0,76,82,78,0, - 76,73,83,0,68,73,83,0,72,69,76,76, - 79,10,0,0,116,99,32,101,120,112,10,0, - 102,114,111,109,32,0,0,0,10,0,0,0, - 87,101,105,114,100,0,0,0,0,0,0,0, - 0,0,0,0,255,255,255,255,255,255,255,255, - 255,255,0,0,255,255,255,255,255,255,0,0, - 0,0,0,0,0,0,0,0,80,65,68,37, - 100,10,0,0,170,170,3,0,0,0,0,0, - 83,69,78,84,33,10,0,0,85,68,80,10, - 0,0,0,0,73,67,77,80,10,0,0,0, - 69,67,72,79,10,0,0,0,73,80,10,0, - 170,170,3,0,0,0,0,0,73,80,88,33, - 10,0,0,0,0,0,0,0,255,255,255,255, - 255,255,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,192,155,1,131,0,0,0,0, - 108,157,1,131,0,0,0,0,88,161,1,131, - 0,0,0,0,16,162,1,131,0,0,0,0, - 32,162,1,131,0,0,0,0,116,167,1,131, - 0,0,0,0,164,167,1,131,0,0,0,0, - 188,169,1,131,0,0,0,0,44,170,1,131, - 0,0,0,0,220,170,1,131,0,0,0,0, - 4,171,1,131,0,0,0,0,80,171,1,131, - 0,0,0,0,40,178,1,131,0,0,0,0, - 104,180,1,131,0,0,0,0,128,180,1,131, - 0,0,0,0,144,180,1,131,0,0,0,0, - 240,182,1,131,0,0,0,0,104,183,1,131, - 0,0,0,0,120,183,1,131,0,0,0,0, - 128,183,1,131,0,0,0,0,136,183,1,131, - 0,0,0,0,160,183,1,131,0,0,0,0, - 168,183,1,131,0,0,0,0,176,183,1,131, - 0,0,0,0,200,183,1,131,0,0,0,0, - 208,183,1,131,0,0,0,0,216,183,1,131, - 0,0,0,0,224,183,1,131,0,0,0,0, - 0,184,1,131,0,0,0,0,8,184,1,131, - 0,0,0,0,16,184,1,131,0,0,0,0, - 40,184,1,131,0,0,0,0,48,184,1,131, - 0,0,0,0,64,184,1,131,0,0,0,0, - 72,184,1,131,0,0,0,0,80,184,1,131, - 0,0,0,0,104,184,1,131,0,0,0,0, - 112,184,1,131,0,0,0,0,128,184,1,131, - 0,0,0,0,136,184,1,131,0,0,0,0, - 152,184,1,131,0,0,0,0,208,184,1,131, - 0,0,0,0,248,184,1,131,0,0,0,0, - 152,191,1,131,0,0,0,0,252,193,1,131, - 0,0,0,0,44,194,1,131,0,0,0,0, - 60,194,1,131,0,0,0,0,60,199,1,131, - 0,0,0,0,148,199,1,131,0,0,0,0, - 164,199,1,131,0,0,0,0,36,200,1,131, - 0,0,0,0,28,201,1,131,0,0,0,0, - 60,201,1,131,0,0,0,0,20,202,1,131, - 0,0,0,0,68,202,1,131,0,0,0,0, - 84,202,1,131,0,0,0,0,124,202,1,131, - 0,0,0,0,164,202,1,131,0,0,0,0, - 236,202,1,131,0,0,0,0,252,202,1,131, - 0,0,0,0,4,203,1,131,0,0,0,0, - 12,203,1,131,0,0,0,0,28,203,1,131, - 0,0,0,0,36,203,1,131,0,0,0,0, - 44,203,1,131,0,0,0,0,52,203,1,131, - 0,0,0,0,60,203,1,131,0,0,0,0, - 68,203,1,131,0,0,0,0,76,203,1,131, - 0,0,0,0,124,203,1,131,0,0,0,0, - 132,203,1,131,0,0,0,0,140,203,1,131, - 0,0,0,0,164,203,1,131,0,0,0,0, - 180,203,1,131,0,0,0,0,188,203,1,131, - 0,0,0,0,220,203,1,131,0,0,0,0, - 20,204,1,131,0,0,0,0,36,204,1,131, - 0,0,0,0,52,204,1,131,0,0,0,0, - 68,204,1,131,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 10,0,0,0,10,0,0,0,0,205,1,131, - 10,0,0,0,7,0,0,0,0,0,0,0, - 0,0,0,0,255,255,255,255,110,118,114,97, - 109,46,99,0,114,99,0,0,48,120,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0 - } ; -static const int dgrs_ncode = 119520 ; diff --git a/drivers/net/dgrs_i82596.h b/drivers/net/dgrs_i82596.h deleted file mode 100644 index ac9217ad2138..000000000000 --- a/drivers/net/dgrs_i82596.h +++ /dev/null @@ -1,473 +0,0 @@ -/* - * i82596 ethernet controller bits and structures (little endian) - * - * $Id: i82596.h,v 1.8 1996/09/03 11:19:03 rick Exp $ - */ - -/************************************************************************/ -/* */ -/* PORT commands (p. 4-20). The least significant nibble is one */ -/* of these commands, the rest of the command is a memory address */ -/* aligned on a 16 byte boundary. Note that port commands must */ -/* be written to the PORT address and the PORT address+2 with two */ -/* halfword writes. Write the LSH first to PORT, then the MSH to */ -/* PORT+2. Blame Intel. */ -/* */ -/************************************************************************/ -#define I596_PORT_RESET 0x0 /* Reset. Wait 5 SysClks & 10 TxClks */ -#define I596_PORT_SELFTEST 0x1 /* Do a selftest */ -#define I596_PORT_SCP_ADDR 0x2 /* Set new SCP address */ -#define I596_PORT_DUMP 0x3 /* Dump internal data structures */ - -/* - * I596_ST: Selftest results (p. 4-21) - */ -typedef volatile struct -{ - ulong signature; /* ROM checksum */ - ulong result; /* Selftest results: non-zero is a failure */ -} I596_ST; - -#define I596_ST_SELFTEST_FAIL 0x1000 /* Selftest Failed */ -#define I596_ST_DIAGNOSE_FAIL 0x0020 /* Diagnose Failed */ -#define I596_ST_BUSTIMER_FAIL 0x0010 /* Bus Timer Failed */ -#define I596_ST_REGISTER_FAIL 0x0008 /* Register Failed */ -#define I596_ST_ROM_FAIL 0x0004 /* ROM Failed */ - -/* - * I596_DUMP: Dump results - */ -typedef volatile struct -{ - ulong dump[77]; -} I596_DUMP; - -/************************************************************************/ -/* */ -/* I596_TBD: Transmit Buffer Descriptor (p. 4-59) */ -/* */ -/************************************************************************/ -typedef volatile struct _I596_TBD -{ - ulong count; - vol struct _I596_TBD *next; - uchar *buf; - ushort unused1; - ushort unused2; -} I596_TBD; - -#define I596_TBD_NOLINK ((I596_TBD *) 0xffffffff) -#define I596_TBD_EOF 0x8000 -#define I596_TBD_COUNT_MASK 0x3fff - -/************************************************************************/ -/* */ -/* I596_TFD: Transmit Frame Descriptor (p. 4-56) */ -/* a.k.a. I596_CB_XMIT */ -/* */ -/************************************************************************/ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - I596_TBD *tbdp; - ulong count; /* for speed */ - - /* Application defined data follows structure... */ - -#if 0 /* We don't use these intel defined ones */ - uchar addr[6]; - ushort len; - uchar data[1]; -#else - ulong dstchan;/* Used by multi-NIC mode */ -#endif -} I596_TFD; - -#define I596_TFD_NOCRC 0x0010 /* cmd: No CRC insertion */ -#define I596_TFD_FLEX 0x0008 /* cmd: Flexible mode */ - -/************************************************************************/ -/* */ -/* I596_RBD: Receive Buffer Descriptor (p. 4-84) */ -/* */ -/************************************************************************/ -typedef volatile struct _I596_RBD -{ -#ifdef INTEL_RETENTIVE - ushort count; /* Length of data in buf */ - ushort offset; -#else - ulong count; /* Length of data in buf */ -#endif - vol struct _I596_RBD *next; /* Next buffer descriptor in list */ - uchar *buf; /* Data buffer */ -#ifdef INTEL_RETENTIVE - ushort size; /* Size of buf (constant) */ - ushort zero; -#else - ulong size; /* Size of buf (constant) */ -#endif - - /* Application defined data follows structure... */ - - uchar chan; - uchar refcnt; - ushort len; -} I596_RBD; - -#define I596_RBD_NOLINK ((I596_RBD *) 0xffffffff) -#define I596_RBD_EOF 0x8000 /* This is last buffer in a frame */ -#define I596_RBD_F 0x4000 /* The actual count is valid */ - -#define I596_RBD_EL 0x8000 /* Last buffer in list */ - -/************************************************************************/ -/* */ -/* I596_RFD: Receive Frame Descriptor (p. 4-79) */ -/* */ -/************************************************************************/ -typedef volatile struct _I596_RFD -{ - ushort status; - ushort cmd; - vol struct _I596_RFD *next; - vol struct _I596_RBD *rbdp; - ushort count; /* Len of data in RFD: always 0 */ - ushort size; /* Size of RFD buffer: always 0 */ - - /* Application defined data follows structure... */ - -# if 0 /* We don't use these intel defined ones */ - uchar addr[6]; - ushort len; - uchar data[1]; -# else - ulong dstchan;/* Used by multi-nic mode */ -# endif -} I596_RFD; - -#define I596_RFD_C 0x8000 /* status: frame complete */ -#define I596_RFD_B 0x4000 /* status: frame busy or waiting */ -#define I596_RFD_OK 0x2000 /* status: frame OK */ -#define I596_RFD_ERR_LENGTH 0x1000 /* status: length error */ -#define I596_RFD_ERR_CRC 0x0800 /* status: CRC error */ -#define I596_RFD_ERR_ALIGN 0x0400 /* status: alignment error */ -#define I596_RFD_ERR_NOBUFS 0x0200 /* status: resource error */ -#define I596_RFD_ERR_DMA 0x0100 /* status: DMA error */ -#define I596_RFD_ERR_SHORT 0x0080 /* status: too short error */ -#define I596_RFD_NOMATCH 0x0002 /* status: IA was not matched */ -#define I596_RFD_COLLISION 0x0001 /* status: collision during receive */ - -#define I596_RFD_EL 0x8000 /* cmd: end of RFD list */ -#define I596_RFD_FLEX 0x0008 /* cmd: Flexible mode */ -#define I596_RFD_EOF 0x8000 /* count: last buffer in the frame */ -#define I596_RFD_F 0x4000 /* count: The actual count is valid */ - -/************************************************************************/ -/* */ -/* Commands */ -/* */ -/************************************************************************/ - - /* values for cmd halfword in all the structs below */ -#define I596_CB_CMD 0x07 /* CB COMMANDS */ -#define I596_CB_CMD_NOP 0 -#define I596_CB_CMD_IA 1 -#define I596_CB_CMD_CONF 2 -#define I596_CB_CMD_MCAST 3 -#define I596_CB_CMD_XMIT 4 -#define I596_CB_CMD_TDR 5 -#define I596_CB_CMD_DUMP 6 -#define I596_CB_CMD_DIAG 7 - -#define I596_CB_CMD_EL 0x8000 /* CB is last in linked list */ -#define I596_CB_CMD_S 0x4000 /* Suspend after execution */ -#define I596_CB_CMD_I 0x2000 /* cause interrupt */ - - /* values for the status halfword in all the struct below */ -#define I596_CB_STATUS 0xF000 /* All four status bits */ -#define I596_CB_STATUS_C 0x8000 /* Command complete */ -#define I596_CB_STATUS_B 0x4000 /* Command busy executing */ -#define I596_CB_STATUS_C_OR_B 0xC000 /* Command complete or busy */ -#define I596_CB_STATUS_OK 0x2000 /* Command complete, no errors */ -#define I596_CB_STATUS_A 0x1000 /* Command busy executing */ - -#define I596_CB_NOLINK ((I596_CB *) 0xffffffff) - -/* - * I596_CB_NOP: NOP Command (p. 4-34) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; -} I596_CB_NOP; - -/* - * Same as above, but command and status in one ulong for speed - */ -typedef volatile struct -{ - ulong csr; - union _I596_CB *next; -} I596_CB_FAST; -#define FASTs(X) (X) -#define FASTc(X) ((X)<<16) - -/* - * I596_CB_IA: Individual (MAC) Address Command (p. 4-35) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - uchar addr[6]; -} I596_CB_IA; - -/* - * I596_CB_CONF: Configure Command (p. 4-37) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - uchar conf[14]; -} I596_CB_CONF; - -#define I596_CONF0_P 0x80 /* Enable RBD Prefetch Bit */ -#define I596_CONF0_COUNT 14 /* Count of configuration bytes */ - -#define I596_CONF1_MON_OFF 0xC0 /* Monitor mode: Monitor off */ -#define I596_CONF1_MON_ON 0x80 /* Monitor mode: Monitor on */ -#define I596_CONF1_TxFIFO(W) (W) /* TxFIFO trigger, in words */ - -#define I596_CONF2_SAVEBF 0x80 /* Save bad frames */ - -#define I596_CONF3_ADDRLEN(B) (B) /* Address length */ -#define I596_CONF3_NOSRCINSERT 0x08 /* Do not insert source address */ -#define I596_CONF3_PREAMBLE8 0x20 /* 8 byte preamble */ -#define I596_CONF3_LOOPOFF 0x00 /* Loopback: Off */ -#define I596_CONF3_LOOPINT 0x40 /* Loopback: internal */ -#define I596_CONF3_LOOPEXT 0xC0 /* Loopback: external */ - -#define I596_CONF4_LINPRI(ST) (ST) /* Linear priority: slot times */ -#define I596_CONF4_EXPPRI(ST) (ST) /* Exponential priority: slot times */ -#define I596_CONF4_IEEE_BOM 0 /* IEEE 802.3 backoff method */ - -#define I596_CONF5_IFS(X) (X) /* Interframe spacing in clocks */ - -#define I596_CONF6_ST_LOW(X) (X&255) /* Slot time, low byte */ - -#define I596_CONF7_ST_HI(X) (X>>8) /* Slot time, high bits */ -#define I596_CONF7_RETRY(X) (X<<4) /* Max retry number */ - -#define I596_CONF8_PROMISC 0x01 /* Rcv all frames */ -#define I596_CONF8_NOBROAD 0x02 -#define I596_CONF8_MANCHESTER 0x04 -#define I596_CONF8_TxNOCRS 0x08 -#define I596_CONF8_NOCRC 0x10 -#define I596_CONF8_CRC_CCITT 0x20 -#define I596_CONF8_BITSTUFFING 0x40 -#define I596_CONF8_PADDING 0x80 - -#define I596_CONF9_CSFILTER(X) (X) -#define I596_CONF9_CSINT(X) 0x08 -#define I596_CONF9_CDFILTER(X) (X<<4) -#define I596_CONF9_CDINT(X) 0x80 - -#define I596_CONF10_MINLEN(X) (X) /* Minimum frame length */ - -#define I596_CONF11_PRECRS_ 0x01 /* Preamble before carrier sense */ -#define I596_CONF11_LNGFLD_ 0x02 /* Padding in End of Carrier */ -#define I596_CONF11_CRCINM_ 0x04 /* CRC in memory */ -#define I596_CONF11_AUTOTX 0x08 /* Auto retransmit */ -#define I596_CONF11_CSBSAC_ 0x10 /* Collision detect by src addr cmp. */ -#define I596_CONF11_MCALL_ 0x20 /* Multicast all */ - -#define I596_CONF13_RESERVED 0x3f /* Reserved: must be ones */ -#define I596_CONF13_MULTIA 0x40 /* Enable multiple addr. reception */ -#define I596_CONF13_DISBOF 0x80 /* Disable backoff algorithm */ -/* - * I596_CB_MCAST: Multicast-Setup Command (p. 4-54) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - ushort count; /* Number of 6-byte addrs that follow */ - uchar addr[6][1]; -} I596_CB_MCAST; - -/* - * I596_CB_XMIT: Transmit Command (p. 4-56) - */ -typedef I596_TFD I596_CB_XMIT; - -#define I596_CB_XMIT_NOCRC 0x0010 /* cmd: No CRC insertion */ -#define I596_CB_XMIT_FLEX 0x0008 /* cmd: Flexible memory mode */ - -#define I596_CB_XMIT_ERR_LATE 0x0800 /* status: error: late collision */ -#define I596_CB_XMIT_ERR_NOCRS 0x0400 /* status: error: no carriers sense */ -#define I596_CB_XMIT_ERR_NOCTS 0x0200 /* status: error: loss of CTS */ -#define I596_CB_XMIT_ERR_UNDER 0x0100 /* status: error: DMA underrun */ -#define I596_CB_XMIT_ERR_MAXCOL 0x0020 /* status: error: maximum collisions */ -#define I596_CB_XMIT_COLLISIONS 0x000f /* status: number of collisions */ - -/* - * I596_CB_TDR: Time Domain Reflectometry Command (p. 4-63) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - ushort time; -} I596_CB_TDR; - -/* - * I596_CB_DUMP: Dump Command (p. 4-65) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - uchar *buf; -} I596_CB_DUMP; - -/* - * I596_CB_DIAG: Diagnose Command (p. 4-77) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; -} I596_CB_DIAG; - -/* - * I596_CB: Command Block - */ -typedef union _I596_CB -{ - I596_CB_NOP nop; - I596_CB_IA ia; - I596_CB_CONF conf; - I596_CB_MCAST mcast; - I596_CB_XMIT xmit; - I596_CB_TDR tdr; - I596_CB_DUMP dump; - I596_CB_DIAG diag; - - /* command and status in one ulong for speed... */ - I596_CB_FAST fast; -} I596_CB; - -/************************************************************************/ -/* */ -/* I596_SCB: System Configuration Block (p. 4-26) */ -/* */ -/************************************************************************/ -typedef volatile struct -{ - volatile ushort status; /* Status word */ - volatile ushort cmd; /* Command word */ - I596_CB *cbp; - I596_RFD *rfdp; - ulong crc_errs; - ulong align_errs; - ulong resource_errs; - ulong overrun_errs; - ulong rcvcdt_errs; - ulong short_errs; - ushort toff; - ushort ton; -} I596_SCB; - - /* cmd halfword values */ -#define I596_SCB_ACK 0xF000 /* ACKNOWLEDGMENTS */ -#define I596_SCB_ACK_CX 0x8000 /* Ack command completion */ -#define I596_SCB_ACK_FR 0x4000 /* Ack received frame */ -#define I596_SCB_ACK_CNA 0x2000 /* Ack command unit not active */ -#define I596_SCB_ACK_RNR 0x1000 /* Ack rcv unit not ready */ -#define I596_SCB_ACK_ALL 0xF000 /* Ack everything */ - -#define I596_SCB_CUC 0x0700 /* COMMAND UNIT COMMANDS */ -#define I596_SCB_CUC_NOP 0x0000 /* No operation */ -#define I596_SCB_CUC_START 0x0100 /* Start execution of first CB */ -#define I596_SCB_CUC_RESUME 0x0200 /* Resume execution */ -#define I596_SCB_CUC_SUSPEND 0x0300 /* Suspend after current CB */ -#define I596_SCB_CUC_ABORT 0x0400 /* Abort current CB immediately */ -#define I596_SCB_CUC_LOAD 0x0500 /* Load Bus throttle timers */ -#define I596_SCB_CUC_LOADIMM 0x0600 /* Load Bus throttle timers, now */ - -#define I596_SCB_RUC 0x0070 /* RECEIVE UNIT COMMANDS */ -#define I596_SCB_RUC_NOP 0x0000 /* No operation */ -#define I596_SCB_RUC_START 0x0010 /* Start reception */ -#define I596_SCB_RUC_RESUME 0x0020 /* Resume reception */ -#define I596_SCB_RUC_SUSPEND 0x0030 /* Suspend reception */ -#define I596_SCB_RUC_ABORT 0x0040 /* Abort reception */ - -#define I596_SCB_RESET 0x0080 /* Hard reset chip */ - - /* status halfword values */ -#define I596_SCB_STAT 0xF000 /* STATUS */ -#define I596_SCB_CX 0x8000 /* command completion */ -#define I596_SCB_FR 0x4000 /* received frame */ -#define I596_SCB_CNA 0x2000 /* command unit not active */ -#define I596_SCB_RNR 0x1000 /* rcv unit not ready */ - -#define I596_SCB_CUS 0x0700 /* COMMAND UNIT STATUS */ -#define I596_SCB_CUS_IDLE 0x0000 /* Idle */ -#define I596_SCB_CUS_SUSPENDED 0x0100 /* Suspended */ -#define I596_SCB_CUS_ACTIVE 0x0200 /* Active */ - -#define I596_SCB_RUS 0x00F0 /* RECEIVE UNIT STATUS */ -#define I596_SCB_RUS_IDLE 0x0000 /* Idle */ -#define I596_SCB_RUS_SUSPENDED 0x0010 /* Suspended */ -#define I596_SCB_RUS_NORES 0x0020 /* No Resources */ -#define I596_SCB_RUS_READY 0x0040 /* Ready */ -#define I596_SCB_RUS_NORBDS 0x0080 /* No more RBDs modifier */ - -#define I596_SCB_LOADED 0x0008 /* Bus timers loaded */ - -/************************************************************************/ -/* */ -/* I596_ISCP: Intermediate System Configuration Ptr (p 4-26) */ -/* */ -/************************************************************************/ -typedef volatile struct -{ - ulong busy; /* Set to 1; I596 clears it when scbp is read */ - I596_SCB *scbp; -} I596_ISCP; - -/************************************************************************/ -/* */ -/* I596_SCP: System Configuration Pointer (p. 4-23) */ -/* */ -/************************************************************************/ -typedef volatile struct -{ - ulong sysbus; - ulong dummy; - I596_ISCP *iscpp; -} I596_SCP; - - /* .sysbus values */ -#define I596_SCP_RESERVED 0x400000 /* Reserved bits must be set */ -#define I596_SCP_INTLOW 0x200000 /* Intr. Polarity active low */ -#define I596_SCP_INTHIGH 0 /* Intr. Polarity active high */ -#define I596_SCP_LOCKDIS 0x100000 /* Lock Function disabled */ -#define I596_SCP_LOCKEN 0 /* Lock Function enabled */ -#define I596_SCP_ETHROTTLE 0x080000 /* External Bus Throttle */ -#define I596_SCP_ITHROTTLE 0 /* Internal Bus Throttle */ -#define I596_SCP_LINEAR 0x040000 /* Linear Mode */ -#define I596_SCP_SEGMENTED 0x020000 /* Segmented Mode */ -#define I596_SCP_82586 0x000000 /* 82586 Mode */ diff --git a/drivers/net/dgrs_plx9060.h b/drivers/net/dgrs_plx9060.h deleted file mode 100644 index 6888ae0d0ce0..000000000000 --- a/drivers/net/dgrs_plx9060.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * PLX 9060 PCI Interface chip - */ - -/* - * PCI configuration registers, same offset on local and PCI sides, - * but on PCI side, must use PCI BIOS calls to read/write. - */ -#define PCI_PLXREGS_BASE_ADDR 0x10 - -#define PCI_PLXREGS_IO_ADDR 0x14 - -#define PCI_SPACE0_BASE_ADDR 0x18 - -#define PCI_ROM_BASE_ADDR 0x30 -# define PCI_ROM_ENABLED 0x00000001 - -#define PCI_INT_LINE 0x3C - -/* - * Registers accessible directly from PCI and local side. - * Offset is from PCI side. Add PLX_LCL_OFFSET for local address. - */ -#define PLX_LCL_OFFSET 0x80 /* Offset of regs from local side */ - -/* - * Local Configuration Registers - */ -#define PLX_SPACE0_RANGE 0x00 /* Range for PCI to Lcl Addr Space 0 */ -#define PLX_SPACE0_BASE_ADDR 0x04 /* Lcl Base address remap */ - -#define PLX_ROM_RANGE 0x10 /* Range for expansion ROM (DMA) */ -#define PLX_ROM_BASE_ADDR 0x14 /* Lcl base address remap for ROM */ - -#define PLX_BUS_REGION 0x18 /* Bus Region Descriptors */ - -/* - * Shared Run Time Registers - */ -#define PLX_MBOX0 0x40 -#define PLX_MBOX1 0x44 -#define PLX_MBOX2 0x48 -#define PLX_MBOX3 0x4C -#define PLX_MBOX4 0x50 -#define PLX_MBOX5 0x54 -#define PLX_MBOX6 0x58 -#define PLX_MBOX7 0x5C - -#define PLX_PCI2LCL_DOORBELL 0x60 - -#define PLX_LCL2PCI_DOORBELL 0x64 - -#define PLX_INT_CSR 0x68 /* Interrupt Control/Status */ -# define PLX_LSERR_ENABLE 0x00000001 -# define PLX_LSERR_PE 0x00000002 -# define PLX_SERR 0x00000004 -# undef PLX_UNUSED /* 0x00000008 */ -# undef PLX_UNUSED /* 0x00000010 */ -# undef PLX_UNUSED /* 0x00000020 */ -# undef PLX_UNUSED /* 0x00000040 */ -# undef PLX_UNUSED /* 0x00000080 */ -# define PLX_PCI_IE 0x00000100 -# define PLX_PCI_DOORBELL_IE 0x00000200 -# define PLX_PCI_ABORT_IE 0x00000400 -# define PLX_PCI_LOCAL_IE 0x00000800 -# define PLX_RETRY_ABORT_ENABLE 0x00001000 -# define PLX_PCI_DOORBELL_INT 0x00002000 -# define PLX_PCI_ABORT_INT 0x00004000 -# define PLX_PCI_LOCAL_INT 0x00008000 -# define PLX_LCL_IE 0x00010000 -# define PLX_LCL_DOORBELL_IE 0x00020000 -# define PLX_LCL_DMA0_IE 0x00040000 -# define PLX_LCL_DMA1_IE 0x00080000 -# define PLX_LCL_DOORBELL_INT 0x00100000 -# define PLX_LCL_DMA0_INT 0x00200000 -# define PLX_LCL_DMA1_INT 0x00400000 -# define PLX_LCL_BIST_INT 0x00800000 -# define PLX_BM_DIRECT_ 0x01000000 -# define PLX_BM_DMA0_ 0x02000000 -# define PLX_BM_DMA1_ 0x04000000 -# define PLX_BM_ABORT_ 0x08000000 -# undef PLX_UNUSED /* 0x10000000 */ -# undef PLX_UNUSED /* 0x20000000 */ -# undef PLX_UNUSED /* 0x40000000 */ -# undef PLX_UNUSED /* 0x80000000 */ - -#define PLX_MISC_CSR 0x6c /* EEPROM,PCI,User,Init Control/Status*/ -# define PLX_USEROUT 0x00010000 -# define PLX_USERIN 0x00020000 -# define PLX_EECK 0x01000000 -# define PLX_EECS 0x02000000 -# define PLX_EEWD 0x04000000 -# define PLX_EERD 0x08000000 - -/* - * DMA registers. Offset is from local side - */ -#define PLX_DMA0_MODE 0x100 -# define PLX_DMA_MODE_WIDTH32 0x00000003 -# define PLX_DMA_MODE_WAITSTATES(X) ((X)<<2) -# define PLX_DMA_MODE_NOREADY 0x00000000 -# define PLX_DMA_MODE_READY 0x00000040 -# define PLX_DMA_MODE_NOBTERM 0x00000000 -# define PLX_DMA_MODE_BTERM 0x00000080 -# define PLX_DMA_MODE_NOBURST 0x00000000 -# define PLX_DMA_MODE_BURST 0x00000100 -# define PLX_DMA_MODE_NOCHAIN 0x00000000 -# define PLX_DMA_MODE_CHAIN 0x00000200 -# define PLX_DMA_MODE_DONE_IE 0x00000400 -# define PLX_DMA_MODE_ADDR_HOLD 0x00000800 - -#define PLX_DMA0_PCI_ADDR 0x104 - /* non-chaining mode PCI address */ - -#define PLX_DMA0_LCL_ADDR 0x108 - /* non-chaining mode local address */ - -#define PLX_DMA0_SIZE 0x10C - /* non-chaining mode length */ - -#define PLX_DMA0_DESCRIPTOR 0x110 -# define PLX_DMA_DESC_EOC 0x00000002 -# define PLX_DMA_DESC_TC_IE 0x00000004 -# define PLX_DMA_DESC_TO_HOST 0x00000008 -# define PLX_DMA_DESC_TO_BOARD 0x00000000 -# define PLX_DMA_DESC_NEXTADDR 0xFFFFfff0 - -#define PLX_DMA1_MODE 0x114 -#define PLX_DMA1_PCI_ADDR 0x118 -#define PLX_DMA1_LCL_ADDR 0x11C -#define PLX_DMA1_SIZE 0x110 -#define PLX_DMA1_DESCRIPTOR 0x124 - -#define PLX_DMA_CSR 0x128 -# define PLX_DMA_CSR_0_ENABLE 0x00000001 -# define PLX_DMA_CSR_0_START 0x00000002 -# define PLX_DMA_CSR_0_ABORT 0x00000004 -# define PLX_DMA_CSR_0_CLR_INTR 0x00000008 -# define PLX_DMA_CSR_0_DONE 0x00000010 -# define PLX_DMA_CSR_1_ENABLE 0x00000100 -# define PLX_DMA_CSR_1_START 0x00000200 -# define PLX_DMA_CSR_1_ABORT 0x00000400 -# define PLX_DMA_CSR_1_CLR_INTR 0x00000800 -# define PLX_DMA_CSR_1_DONE 0x00001000 - -#define PLX_DMA_ARB0 0x12C -# define PLX_DMA_ARB0_LATENCY_T 0x000000FF -# define PLX_DMA_ARB0_PAUSE_T 0x0000FF00 -# define PLX_DMA_ARB0_LATENCY_EN 0x00010000 -# define PLX_DMA_ARB0_PAUSE_EN 0x00020000 -# define PLX_DMA_ARB0_BREQ_EN 0x00040000 -# define PLX_DMA_ARB0_PRI 0x00180000 -# define PLX_DMA_ARB0_PRI_ROUND 0x00000000 -# define PLX_DMA_ARB0_PRI_0 0x00080000 -# define PLX_DMA_ARB0_PRI_1 0x00100000 - -#define PLX_DMA_ARB1 0x130 - /* Chan 0: FIFO DEPTH=16 */ -# define PLX_DMA_ARB1_0_P2L_LW_TRIG(X) ( ((X)&15) << 0 ) -# define PLX_DMA_ARB1_0_L2P_LR_TRIG(X) ( ((X)&15) << 4 ) -# define PLX_DMA_ARB1_0_L2P_PW_TRIG(X) ( ((X)&15) << 8 ) -# define PLX_DMA_ARB1_0_P2L_PR_TRIG(X) ( ((X)&15) << 12 ) - /* Chan 1: FIFO DEPTH=8 */ -# define PLX_DMA_ARB1_1_P2L_LW_TRIG(X) ( ((X)& 7) << 16 ) -# define PLX_DMA_ARB1_1_L2P_LR_TRIG(X) ( ((X)& 7) << 20 ) -# define PLX_DMA_ARB1_1_L2P_PW_TRIG(X) ( ((X)& 7) << 24 ) -# define PLX_DMA_ARB1_1_P2L_PR_TRIG(X) ( ((X)& 7) << 28 ) - -typedef struct _dmachain -{ - ulong pciaddr; - ulong lcladdr; - ulong len; - ulong next; -} DMACHAIN; From 7a1f8104c4a477feaf8b4405429119276341a27e Mon Sep 17 00:00:00 2001 From: Roy Zang Date: Mon, 24 Sep 2007 16:57:42 +0800 Subject: [PATCH 1627/2804] Clean up redundant PHY write line for ULi526x Ethernet driver Clean up redundant PHY write line for ULi526x Ethernet Driver. Signed-off-by: Roy Zang Signed-off-by: Jeff Garzik --- drivers/net/tulip/uli526x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 53c7523960c4..e64bde46822e 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -1604,7 +1604,6 @@ static void uli526x_process_mode(struct uli526x_board_info *db) case ULI526X_100MFD: phy_reg = 0x2100; break; } phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); - phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); } } } From 7b5dfe1aa9faf9fab10960e027a7b1c932580f76 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Fri, 21 Sep 2007 09:41:15 -0700 Subject: [PATCH 1628/2804] e1000e: Do not allow requeue of freed skb Returning BUSY will make qdisc_restart enqueue the skb which was already freed. The bad skb was correctly freed and we should return NETDEV_TX_OK. First spotted by Jeff Garzik on 08/13/07. Signed-off-by: Krishna Kumar Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 885d9467f40d..4a21d7df1743 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3531,7 +3531,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* handle pci_map_single() error in e1000_tx_map */ dev_kfree_skb_any(skb); spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); - return NETDEV_TX_BUSY; + return NETDEV_TX_OK; } e1000_tx_queue(adapter, tx_flags, count); From ac1d49f8431bef861c7dd63e78be25e4c262eb52 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 29 Sep 2007 01:10:14 -0400 Subject: [PATCH 1629/2804] [netdrvr] sundance: fix phy scanning on IP100A Based on a based from Jesse Huang . Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index a37637ec9b77..ff98f5d597f1 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -466,7 +466,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, #else int bar = 1; #endif - int phy, phy_idx = 0; + int phy, phy_end, phy_idx = 0; DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ @@ -552,11 +552,19 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; + /* * It seems some phys doesn't deal well with address 0 being accessed - * first, so leave address zero to the end of the loop (32 & 31). + * first */ - for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) { + if (sundance_pci_tbl[np->chip_id].device == 0x0200) { + phy = 0; + phy_end = 31; + } else { + phy = 1; + phy_end = 32; /* wraps to zero, due to 'phy & 0x1f' */ + } + for (; phy <= phy_end && phy_idx < MII_CNT; phy++) { int phyx = phy & 0x1f; int mii_status = mdio_read(dev, phyx, MII_BMSR); if (mii_status != 0xffff && mii_status != 0x0000) { From 73d7396980176a5f4515be2f6e39ee417d2369ba Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 20 Sep 2007 19:14:01 +0100 Subject: [PATCH 1630/2804] sb1250-mac.c: De-typedef, de-volatile, de-etc... Remove typedefs, volatiles and convert kmalloc()/memset() pairs to kcalloc(). Also reformat the surrounding clutter. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 278 ++++++++++++++++++++------------------- 1 file changed, 142 insertions(+), 136 deletions(-) diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 6001ab47fba0..0cffd46724df 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -140,17 +140,17 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); ********************************************************************* */ -typedef enum { sbmac_speed_auto, sbmac_speed_10, - sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t; +enum sbmac_speed { sbmac_speed_auto, sbmac_speed_10, + sbmac_speed_100, sbmac_speed_1000 }; -typedef enum { sbmac_duplex_auto, sbmac_duplex_half, - sbmac_duplex_full } sbmac_duplex_t; +enum sbmac_duplex { sbmac_duplex_auto, sbmac_duplex_half, + sbmac_duplex_full }; -typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, - sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; +enum sbmac_fc { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, + sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; -typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, - sbmac_state_broken } sbmac_state_t; +enum sbmac_state { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, + sbmac_state_broken }; /********************************************************************** @@ -176,55 +176,61 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, * DMA Descriptor structure ********************************************************************* */ -typedef struct sbdmadscr_s { +struct sbdmadscr { uint64_t dscr_a; uint64_t dscr_b; -} sbdmadscr_t; - -typedef unsigned long paddr_t; +}; /********************************************************************** * DMA Controller structure ********************************************************************* */ -typedef struct sbmacdma_s { +struct sbmacdma { /* * This stuff is used to identify the channel and the registers * associated with it. */ - - struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ - int sbdma_channel; /* channel number */ - int sbdma_txdir; /* direction (1=transmit) */ - int sbdma_maxdescr; /* total # of descriptors in ring */ + struct sbmac_softc *sbdma_eth; /* back pointer to associated + MAC */ + int sbdma_channel; /* channel number */ + int sbdma_txdir; /* direction (1=transmit) */ + int sbdma_maxdescr; /* total # of descriptors + in ring */ #ifdef CONFIG_SBMAC_COALESCE - int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/ - int sbdma_int_timeout; /* # usec rx/tx interrupt */ + int sbdma_int_pktcnt; + /* # descriptors rx/tx + before interrupt */ + int sbdma_int_timeout; + /* # usec rx/tx interrupt */ #endif - - volatile void __iomem *sbdma_config0; /* DMA config register 0 */ - volatile void __iomem *sbdma_config1; /* DMA config register 1 */ - volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ - volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ - volatile void __iomem *sbdma_curdscr; /* current descriptor address */ - volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */ - + void __iomem *sbdma_config0; /* DMA config register 0 */ + void __iomem *sbdma_config1; /* DMA config register 1 */ + void __iomem *sbdma_dscrbase; + /* descriptor base address */ + void __iomem *sbdma_dscrcnt; /* descriptor count register */ + void __iomem *sbdma_curdscr; /* current descriptor + address */ + void __iomem *sbdma_oodpktlost; + /* pkt drop (rx only) */ /* * This stuff is for maintenance of the ring */ - - sbdmadscr_t *sbdma_dscrtable_unaligned; - sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ - sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ - - struct sk_buff **sbdma_ctxtable; /* context table, one per descr */ - - paddr_t sbdma_dscrtable_phys; /* and also the phys addr */ - sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */ - sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */ -} sbmacdma_t; + void *sbdma_dscrtable_unaligned; + struct sbdmadscr *sbdma_dscrtable; + /* base of descriptor table */ + struct sbdmadscr *sbdma_dscrtable_end; + /* end of descriptor table */ + struct sk_buff **sbdma_ctxtable; + /* context table, one + per descr */ + dma_addr_t sbdma_dscrtable_phys; + /* and also the phys addr */ + struct sbdmadscr *sbdma_addptr; /* next dscr for sw to add */ + struct sbdmadscr *sbdma_remptr; /* next dscr for sw + to remove */ +}; /********************************************************************** @@ -236,47 +242,45 @@ struct sbmac_softc { /* * Linux-specific things */ + struct net_device *sbm_dev; /* pointer to linux device */ + struct napi_struct napi; + spinlock_t sbm_lock; /* spin lock */ + struct timer_list sbm_timer; /* for monitoring MII */ + int sbm_devflags; /* current device flags */ - struct net_device *sbm_dev; /* pointer to linux device */ - struct napi_struct napi; - spinlock_t sbm_lock; /* spin lock */ - struct timer_list sbm_timer; /* for monitoring MII */ - int sbm_devflags; /* current device flags */ + int sbm_phy_oldbmsr; + int sbm_phy_oldanlpar; + int sbm_phy_oldk1stsr; + int sbm_phy_oldlinkstat; + int sbm_buffersize; - int sbm_phy_oldbmsr; - int sbm_phy_oldanlpar; - int sbm_phy_oldk1stsr; - int sbm_phy_oldlinkstat; - int sbm_buffersize; - - unsigned char sbm_phys[2]; + unsigned char sbm_phys[2]; /* * Controller-specific things */ + void __iomem *sbm_base; /* MAC's base address */ + enum sbmac_state sbm_state; /* current state */ - void __iomem *sbm_base; /* MAC's base address */ - sbmac_state_t sbm_state; /* current state */ + void __iomem *sbm_macenable; /* MAC Enable Register */ + void __iomem *sbm_maccfg; /* MAC Config Register */ + void __iomem *sbm_fifocfg; /* FIFO Config Register */ + void __iomem *sbm_framecfg; /* Frame Config Register */ + void __iomem *sbm_rxfilter; /* Receive Filter Register */ + void __iomem *sbm_isr; /* Interrupt Status Register */ + void __iomem *sbm_imr; /* Interrupt Mask Register */ + void __iomem *sbm_mdio; /* MDIO Register */ - volatile void __iomem *sbm_macenable; /* MAC Enable Register */ - volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */ - volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */ - volatile void __iomem *sbm_framecfg; /* Frame configuration register */ - volatile void __iomem *sbm_rxfilter; /* receive filter register */ - volatile void __iomem *sbm_isr; /* Interrupt status register */ - volatile void __iomem *sbm_imr; /* Interrupt mask register */ - volatile void __iomem *sbm_mdio; /* MDIO register */ + enum sbmac_speed sbm_speed; /* current speed */ + enum sbmac_duplex sbm_duplex; /* current duplex */ + enum sbmac_fc sbm_fc; /* cur. flow control setting */ - sbmac_speed_t sbm_speed; /* current speed */ - sbmac_duplex_t sbm_duplex; /* current duplex */ - sbmac_fc_t sbm_fc; /* current flow control setting */ + unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; - unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; - - sbmacdma_t sbm_txdma; /* for now, only use channel 0 */ - sbmacdma_t sbm_rxdma; - int rx_hw_checksum; - int sbe_idx; + struct sbmacdma sbm_txdma; /* only channel 0 for now */ + struct sbmacdma sbm_rxdma; + int rx_hw_checksum; + int sbe_idx; }; @@ -288,30 +292,31 @@ struct sbmac_softc { * Prototypes ********************************************************************* */ -static void sbdma_initctx(sbmacdma_t *d, - struct sbmac_softc *s, - int chan, - int txrx, - int maxdescr); -static void sbdma_channel_start(sbmacdma_t *d, int rxtx); -static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m); -static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m); -static void sbdma_emptyring(sbmacdma_t *d); -static void sbdma_fillring(sbmacdma_t *d); -static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll); -static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll); +static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, + int txrx, int maxdescr); +static void sbdma_channel_start(struct sbmacdma *d, int rxtx); +static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *m); +static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *m); +static void sbdma_emptyring(struct sbmacdma *d); +static void sbdma_fillring(struct sbmacdma *d); +static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d, + int work_to_do, int poll); +static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d, + int poll); static int sbmac_initctx(struct sbmac_softc *s); static void sbmac_channel_start(struct sbmac_softc *s); static void sbmac_channel_stop(struct sbmac_softc *s); -static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t); -static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff); +static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *, + enum sbmac_state); +static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff); static uint64_t sbmac_addr2reg(unsigned char *ptr); -static irqreturn_t sbmac_intr(int irq,void *dev_instance); +static irqreturn_t sbmac_intr(int irq, void *dev_instance); static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); static void sbmac_setmulti(struct sbmac_softc *sc); static int sbmac_init(struct net_device *dev, int idx); -static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed); -static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc); +static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed); +static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, + enum sbmac_fc fc); static int sbmac_open(struct net_device *dev); static void sbmac_timer(unsigned long data); @@ -321,13 +326,15 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); static int sbmac_poll(struct napi_struct *napi, int budget); -static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); +static int sbmac_mii_poll(struct sbmac_softc *s, int noisy); static int sbmac_mii_probe(struct net_device *dev); static void sbmac_mii_sync(struct sbmac_softc *s); -static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt); -static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx); -static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, +static void sbmac_mii_senddata(struct sbmac_softc *s, unsigned int data, + int bitcnt); +static unsigned int sbmac_mii_read(struct sbmac_softc *s, int phyaddr, + int regidx); +static void sbmac_mii_write(struct sbmac_softc *s, int phyaddr, int regidx, unsigned int regval); @@ -676,8 +683,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, * way. * * Input parameters: - * d - sbmacdma_t structure (DMA channel context) - * s - sbmac_softc structure (pointer to a MAC) + * d - struct sbmacdma (DMA channel context) + * s - struct sbmac_softc (pointer to a MAC) * chan - channel number (0..1 right now) * txrx - Identifies DMA_TX or DMA_RX for channel direction * maxdescr - number of descriptors @@ -686,11 +693,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, * nothing ********************************************************************* */ -static void sbdma_initctx(sbmacdma_t *d, - struct sbmac_softc *s, - int chan, - int txrx, - int maxdescr) +static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, + int txrx, int maxdescr) { #ifdef CONFIG_SBMAC_COALESCE int int_pktcnt, int_timeout; @@ -757,18 +761,17 @@ static void sbdma_initctx(sbmacdma_t *d, d->sbdma_maxdescr = maxdescr; - d->sbdma_dscrtable_unaligned = - d->sbdma_dscrtable = (sbdmadscr_t *) - kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); + d->sbdma_dscrtable_unaligned = kcalloc(d->sbdma_maxdescr + 1, + sizeof(*d->sbdma_dscrtable), + GFP_KERNEL); /* * The descriptor table must be aligned to at least 16 bytes or the * MAC will corrupt it. */ - d->sbdma_dscrtable = (sbdmadscr_t *) - ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t)); - - memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t)); + d->sbdma_dscrtable = (struct sbdmadscr *) + ALIGN((unsigned long)d->sbdma_dscrtable_unaligned, + sizeof(*d->sbdma_dscrtable)); d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr; @@ -779,7 +782,7 @@ static void sbdma_initctx(sbmacdma_t *d, */ d->sbdma_ctxtable = kcalloc(d->sbdma_maxdescr, - sizeof(struct sk_buff *), GFP_KERNEL); + sizeof(*d->sbdma_ctxtable), GFP_KERNEL); #ifdef CONFIG_SBMAC_COALESCE /* @@ -816,7 +819,7 @@ static void sbdma_initctx(sbmacdma_t *d, * nothing ********************************************************************* */ -static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) +static void sbdma_channel_start(struct sbmacdma *d, int rxtx) { /* * Turn on the DMA channel @@ -857,7 +860,7 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) * nothing ********************************************************************* */ -static void sbdma_channel_stop(sbmacdma_t *d) +static void sbdma_channel_stop(struct sbmacdma *d) { /* * Turn off the DMA channel @@ -906,10 +909,10 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) ********************************************************************* */ -static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) +static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb) { - sbdmadscr_t *dsc; - sbdmadscr_t *nextdsc; + struct sbdmadscr *dsc; + struct sbdmadscr *nextdsc; struct sk_buff *sb_new = NULL; int pktsize = ENET_PACKET_SIZE; @@ -1021,10 +1024,10 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) ********************************************************************* */ -static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) +static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *sb) { - sbdmadscr_t *dsc; - sbdmadscr_t *nextdsc; + struct sbdmadscr *dsc; + struct sbdmadscr *nextdsc; uint64_t phys; uint64_t ncb; int length; @@ -1110,7 +1113,7 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) * nothing ********************************************************************* */ -static void sbdma_emptyring(sbmacdma_t *d) +static void sbdma_emptyring(struct sbmacdma *d) { int idx; struct sk_buff *sb; @@ -1138,7 +1141,7 @@ static void sbdma_emptyring(sbmacdma_t *d) * nothing ********************************************************************* */ -static void sbdma_fillring(sbmacdma_t *d) +static void sbdma_fillring(struct sbmacdma *d) { int idx; @@ -1185,13 +1188,13 @@ static void sbmac_netpoll(struct net_device *netdev) * nothing ********************************************************************* */ -static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, - int work_to_do, int poll) +static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d, + int work_to_do, int poll) { struct net_device *dev = sc->sbm_dev; int curidx; int hwidx; - sbdmadscr_t *dsc; + struct sbdmadscr *dsc; struct sk_buff *sb; int len; int work_done = 0; @@ -1223,8 +1226,9 @@ again: prefetch(dsc); prefetch(&d->sbdma_ctxtable[curidx]); - hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); + hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / + sizeof(*d->sbdma_dscrtable); /* * If they're the same, that means we've processed all @@ -1348,12 +1352,13 @@ done: * nothing ********************************************************************* */ -static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) +static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d, + int poll) { struct net_device *dev = sc->sbm_dev; int curidx; int hwidx; - sbdmadscr_t *dsc; + struct sbdmadscr *dsc; struct sk_buff *sb; unsigned long flags; int packets_handled = 0; @@ -1363,8 +1368,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) if (d->sbdma_remptr == d->sbdma_addptr) goto end_unlock; - hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); + hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / sizeof(*d->sbdma_dscrtable); for (;;) { /* @@ -1501,7 +1506,7 @@ static int sbmac_initctx(struct sbmac_softc *s) } -static void sbdma_uninitctx(struct sbmacdma_s *d) +static void sbdma_uninitctx(struct sbmacdma *d) { if (d->sbdma_dscrtable_unaligned) { kfree(d->sbdma_dscrtable_unaligned); @@ -1537,7 +1542,7 @@ static void sbmac_uninitctx(struct sbmac_softc *sc) static void sbmac_channel_start(struct sbmac_softc *s) { uint64_t reg; - volatile void __iomem *port; + void __iomem *port; uint64_t cfg,fifo,framecfg; int idx, th_value; @@ -1800,10 +1805,10 @@ static void sbmac_channel_stop(struct sbmac_softc *s) * Return value: * old state ********************************************************************* */ -static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, - sbmac_state_t state) +static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *sc, + enum sbmac_state state) { - sbmac_state_t oldstate = sc->sbm_state; + enum sbmac_state oldstate = sc->sbm_state; /* * If same as previous state, return @@ -1938,14 +1943,14 @@ static uint64_t sbmac_addr2reg(unsigned char *ptr) * * Input parameters: * s - sbmac structure - * speed - speed to set MAC to (see sbmac_speed_t enum) + * speed - speed to set MAC to (see enum sbmac_speed) * * Return value: * 1 if successful * 0 indicates invalid parameters ********************************************************************* */ -static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) +static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed) { uint64_t cfg; uint64_t framecfg; @@ -2027,15 +2032,16 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) * * Input parameters: * s - sbmac structure - * duplex - duplex setting (see sbmac_duplex_t) - * fc - flow control setting (see sbmac_fc_t) + * duplex - duplex setting (see enum sbmac_duplex) + * fc - flow control setting (see enum sbmac_fc) * * Return value: * 1 if ok * 0 if an invalid parameter combination was specified ********************************************************************* */ -static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc) +static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, + enum sbmac_fc fc) { uint64_t cfg; @@ -2228,7 +2234,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) static void sbmac_setmulti(struct sbmac_softc *sc) { uint64_t reg; - volatile void __iomem *port; + void __iomem *port; int idx; struct dev_mc_list *mclist; struct net_device *dev = sc->sbm_dev; From f5279ffdce9bcff938451303126971098e23aab3 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 21 Sep 2007 12:52:10 +0100 Subject: [PATCH 1631/2804] sb1250-mac: Driver model & phylib update A driver model and phylib update. It includes the following changes: 1. Removal of unused module options. 2. Phylib support and the resulting removal of generic bits for handling the PHY. 3. Proper reserving of device resources and using ioremap()ped handles to access MAC registers rather than platform-specific macros. 4. Handling of the device using the driver model. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 1 + drivers/net/sb1250-mac.c | 1167 ++++++++++++++++++-------------------- 2 files changed, 544 insertions(+), 624 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 764325917f6a..9ff1cf46eaee 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2111,6 +2111,7 @@ config R8169_VLAN config SB1250_MAC tristate "SB1250 Gigabit Ethernet support" depends on SIBYTE_SB1xxx_SOC + select PHYLIB ---help--- This driver supports Gigabit Ethernet interfaces based on the Broadcom SiByte family of System-On-a-Chip parts. They include diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 0cffd46724df..7b53d658e337 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2001,2002,2003,2004 Broadcom Corporation + * Copyright (c) 2006, 2007 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,7 +19,12 @@ * * This driver is designed for the Broadcom SiByte SOC built-in * Ethernet controllers. Written by Mitch Lichtenberg at Broadcom Corp. + * + * Updated to the driver model and the PHY abstraction layer + * by Maciej W. Rozycki. */ + +#include #include #include #include @@ -32,9 +38,15 @@ #include #include #include -#include /* Processor type for cache alignment. */ -#include +#include +#include +#include +#include +#include + #include +#include +#include /* Processor type for cache alignment. */ /* This is only here until the firmware is ready. In that case, the firmware leaves the ethernet address in the register for us. */ @@ -48,7 +60,7 @@ /* These identify the driver base version and may not be removed. */ #if 0 -static char version1[] __devinitdata = +static char version1[] __initdata = "sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n"; #endif @@ -57,8 +69,6 @@ static char version1[] __devinitdata = #define CONFIG_SBMAC_COALESCE -#define MAX_UNITS 4 /* More are supported, limit only on options */ - /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2*HZ) @@ -74,26 +84,6 @@ static int debug = 1; module_param(debug, int, S_IRUGO); MODULE_PARM_DESC(debug, "Debug messages"); -/* mii status msgs */ -static int noisy_mii = 1; -module_param(noisy_mii, int, S_IRUGO); -MODULE_PARM_DESC(noisy_mii, "MII status messages"); - -/* Used to pass the media type, etc. - Both 'options[]' and 'full_duplex[]' should exist for driver - interoperability. - The media type is usually passed in 'options[]'. -*/ -#ifdef MODULE -static int options[MAX_UNITS] = {-1, -1, -1, -1}; -module_param_array(options, int, NULL, S_IRUGO); -MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS)); - -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1}; -module_param_array(full_duplex, int, NULL, S_IRUGO); -MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS)); -#endif - #ifdef CONFIG_SBMAC_COALESCE static int int_pktcnt_tx = 255; module_param(int_pktcnt_tx, int, S_IRUGO); @@ -112,6 +102,7 @@ module_param(int_timeout_rx, int, S_IRUGO); MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); #endif +#include #include #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) #include @@ -135,22 +126,43 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); #error invalid SiByte MAC configuation #endif +#ifdef K_INT_PHY +#define SBMAC_PHY_INT K_INT_PHY +#else +#define SBMAC_PHY_INT PHY_POLL +#endif + /********************************************************************** * Simple types ********************************************************************* */ +enum sbmac_speed { + sbmac_speed_none = 0, + sbmac_speed_10 = SPEED_10, + sbmac_speed_100 = SPEED_100, + sbmac_speed_1000 = SPEED_1000, +}; -enum sbmac_speed { sbmac_speed_auto, sbmac_speed_10, - sbmac_speed_100, sbmac_speed_1000 }; +enum sbmac_duplex { + sbmac_duplex_none = -1, + sbmac_duplex_half = DUPLEX_HALF, + sbmac_duplex_full = DUPLEX_FULL, +}; -enum sbmac_duplex { sbmac_duplex_auto, sbmac_duplex_half, - sbmac_duplex_full }; +enum sbmac_fc { + sbmac_fc_none, + sbmac_fc_disabled, + sbmac_fc_frame, + sbmac_fc_collision, + sbmac_fc_carrier, +}; -enum sbmac_fc { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, - sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; - -enum sbmac_state { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, - sbmac_state_broken }; +enum sbmac_state { + sbmac_state_uninit, + sbmac_state_off, + sbmac_state_on, + sbmac_state_broken, +}; /********************************************************************** @@ -244,18 +256,14 @@ struct sbmac_softc { */ struct net_device *sbm_dev; /* pointer to linux device */ struct napi_struct napi; + struct phy_device *phy_dev; /* the associated PHY device */ + struct mii_bus mii_bus; /* the MII bus */ + int phy_irq[PHY_MAX_ADDR]; spinlock_t sbm_lock; /* spin lock */ - struct timer_list sbm_timer; /* for monitoring MII */ int sbm_devflags; /* current device flags */ - int sbm_phy_oldbmsr; - int sbm_phy_oldanlpar; - int sbm_phy_oldk1stsr; - int sbm_phy_oldlinkstat; int sbm_buffersize; - unsigned char sbm_phys[2]; - /* * Controller-specific things */ @@ -274,6 +282,8 @@ struct sbmac_softc { enum sbmac_speed sbm_speed; /* current speed */ enum sbmac_duplex sbm_duplex; /* current duplex */ enum sbmac_fc sbm_fc; /* cur. flow control setting */ + int sbm_pause; /* current pause setting */ + int sbm_link; /* current link state */ unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; @@ -313,36 +323,37 @@ static uint64_t sbmac_addr2reg(unsigned char *ptr); static irqreturn_t sbmac_intr(int irq, void *dev_instance); static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); static void sbmac_setmulti(struct sbmac_softc *sc); -static int sbmac_init(struct net_device *dev, int idx); +static int sbmac_init(struct platform_device *pldev, long long base); static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed); static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, enum sbmac_fc fc); static int sbmac_open(struct net_device *dev); -static void sbmac_timer(unsigned long data); static void sbmac_tx_timeout (struct net_device *dev); static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); static int sbmac_poll(struct napi_struct *napi, int budget); -static int sbmac_mii_poll(struct sbmac_softc *s, int noisy); +static void sbmac_mii_poll(struct net_device *dev); static int sbmac_mii_probe(struct net_device *dev); -static void sbmac_mii_sync(struct sbmac_softc *s); -static void sbmac_mii_senddata(struct sbmac_softc *s, unsigned int data, +static void sbmac_mii_sync(void __iomem *sbm_mdio); +static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data, int bitcnt); -static unsigned int sbmac_mii_read(struct sbmac_softc *s, int phyaddr, - int regidx); -static void sbmac_mii_write(struct sbmac_softc *s, int phyaddr, int regidx, - unsigned int regval); +static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx); +static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx, + u16 val); /********************************************************************** * Globals ********************************************************************* */ -static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; +static char sbmac_string[] = "sb1250-mac"; +static char sbmac_pretty[] = "SB1250 MAC"; + +static char sbmac_mdio_string[] = "sb1250-mac-mdio"; /********************************************************************** @@ -354,185 +365,66 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; #define MII_COMMAND_WRITE 0x01 #define MII_COMMAND_ACK 0x02 -#define BMCR_RESET 0x8000 -#define BMCR_LOOPBACK 0x4000 -#define BMCR_SPEED0 0x2000 -#define BMCR_ANENABLE 0x1000 -#define BMCR_POWERDOWN 0x0800 -#define BMCR_ISOLATE 0x0400 -#define BMCR_RESTARTAN 0x0200 -#define BMCR_DUPLEX 0x0100 -#define BMCR_COLTEST 0x0080 -#define BMCR_SPEED1 0x0040 -#define BMCR_SPEED1000 BMCR_SPEED1 -#define BMCR_SPEED100 BMCR_SPEED0 -#define BMCR_SPEED10 0 - -#define BMSR_100BT4 0x8000 -#define BMSR_100BT_FDX 0x4000 -#define BMSR_100BT_HDX 0x2000 -#define BMSR_10BT_FDX 0x1000 -#define BMSR_10BT_HDX 0x0800 -#define BMSR_100BT2_FDX 0x0400 -#define BMSR_100BT2_HDX 0x0200 -#define BMSR_1000BT_XSR 0x0100 -#define BMSR_PRESUP 0x0040 -#define BMSR_ANCOMPLT 0x0020 -#define BMSR_REMFAULT 0x0010 -#define BMSR_AUTONEG 0x0008 -#define BMSR_LINKSTAT 0x0004 -#define BMSR_JABDETECT 0x0002 -#define BMSR_EXTCAPAB 0x0001 - -#define PHYIDR1 0x2000 -#define PHYIDR2 0x5C60 - -#define ANAR_NP 0x8000 -#define ANAR_RF 0x2000 -#define ANAR_ASYPAUSE 0x0800 -#define ANAR_PAUSE 0x0400 -#define ANAR_T4 0x0200 -#define ANAR_TXFD 0x0100 -#define ANAR_TXHD 0x0080 -#define ANAR_10FD 0x0040 -#define ANAR_10HD 0x0020 -#define ANAR_PSB 0x0001 - -#define ANLPAR_NP 0x8000 -#define ANLPAR_ACK 0x4000 -#define ANLPAR_RF 0x2000 -#define ANLPAR_ASYPAUSE 0x0800 -#define ANLPAR_PAUSE 0x0400 -#define ANLPAR_T4 0x0200 -#define ANLPAR_TXFD 0x0100 -#define ANLPAR_TXHD 0x0080 -#define ANLPAR_10FD 0x0040 -#define ANLPAR_10HD 0x0020 -#define ANLPAR_PSB 0x0001 /* 802.3 */ - -#define ANER_PDF 0x0010 -#define ANER_LPNPABLE 0x0008 -#define ANER_NPABLE 0x0004 -#define ANER_PAGERX 0x0002 -#define ANER_LPANABLE 0x0001 - -#define ANNPTR_NP 0x8000 -#define ANNPTR_MP 0x2000 -#define ANNPTR_ACK2 0x1000 -#define ANNPTR_TOGTX 0x0800 -#define ANNPTR_CODE 0x0008 - -#define ANNPRR_NP 0x8000 -#define ANNPRR_MP 0x2000 -#define ANNPRR_ACK3 0x1000 -#define ANNPRR_TOGTX 0x0800 -#define ANNPRR_CODE 0x0008 - -#define K1TCR_TESTMODE 0x0000 -#define K1TCR_MSMCE 0x1000 -#define K1TCR_MSCV 0x0800 -#define K1TCR_RPTR 0x0400 -#define K1TCR_1000BT_FDX 0x200 -#define K1TCR_1000BT_HDX 0x100 - -#define K1STSR_MSMCFLT 0x8000 -#define K1STSR_MSCFGRES 0x4000 -#define K1STSR_LRSTAT 0x2000 -#define K1STSR_RRSTAT 0x1000 -#define K1STSR_LP1KFD 0x0800 -#define K1STSR_LP1KHD 0x0400 -#define K1STSR_LPASMDIR 0x0200 - -#define K1SCR_1KX_FDX 0x8000 -#define K1SCR_1KX_HDX 0x4000 -#define K1SCR_1KT_FDX 0x2000 -#define K1SCR_1KT_HDX 0x1000 - -#define STRAP_PHY1 0x0800 -#define STRAP_NCMODE 0x0400 -#define STRAP_MANMSCFG 0x0200 -#define STRAP_ANENABLE 0x0100 -#define STRAP_MSVAL 0x0080 -#define STRAP_1KHDXADV 0x0010 -#define STRAP_1KFDXADV 0x0008 -#define STRAP_100ADV 0x0004 -#define STRAP_SPEEDSEL 0x0000 -#define STRAP_SPEED100 0x0001 - -#define PHYSUP_SPEED1000 0x10 -#define PHYSUP_SPEED100 0x08 -#define PHYSUP_SPEED10 0x00 -#define PHYSUP_LINKUP 0x04 -#define PHYSUP_FDX 0x02 - -#define MII_BMCR 0x00 /* Basic mode control register (rw) */ -#define MII_BMSR 0x01 /* Basic mode status register (ro) */ -#define MII_PHYIDR1 0x02 -#define MII_PHYIDR2 0x03 - -#define MII_K1STSR 0x0A /* 1K Status Register (ro) */ -#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ - - #define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */ #define ENABLE 1 #define DISABLE 0 /********************************************************************** - * SBMAC_MII_SYNC(s) + * SBMAC_MII_SYNC(sbm_mdio) * * Synchronize with the MII - send a pattern of bits to the MII * that will guarantee that it is ready to accept a command. * * Input parameters: - * s - sbmac structure + * sbm_mdio - address of the MAC's MDIO register * * Return value: * nothing ********************************************************************* */ -static void sbmac_mii_sync(struct sbmac_softc *s) +static void sbmac_mii_sync(void __iomem *sbm_mdio) { int cnt; uint64_t bits; int mac_mdio_genc; - mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); for (cnt = 0; cnt < 32; cnt++) { - __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); } } /********************************************************************** - * SBMAC_MII_SENDDATA(s,data,bitcnt) + * SBMAC_MII_SENDDATA(sbm_mdio, data, bitcnt) * * Send some bits to the MII. The bits to be sent are right- * justified in the 'data' parameter. * * Input parameters: - * s - sbmac structure - * data - data to send - * bitcnt - number of bits to send + * sbm_mdio - address of the MAC's MDIO register + * data - data to send + * bitcnt - number of bits to send ********************************************************************* */ -static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt) +static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data, + int bitcnt) { int i; uint64_t bits; unsigned int curmask; int mac_mdio_genc; - mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT; - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); curmask = 1 << (bitcnt - 1); @@ -540,9 +432,9 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc if (data & curmask) bits |= M_MAC_MDIO_OUT; else bits &= ~M_MAC_MDIO_OUT; - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); curmask >>= 1; } } @@ -550,21 +442,22 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc /********************************************************************** - * SBMAC_MII_READ(s,phyaddr,regidx) - * + * SBMAC_MII_READ(bus, phyaddr, regidx) * Read a PHY register. * * Input parameters: - * s - sbmac structure + * bus - MDIO bus handle * phyaddr - PHY's address - * regidx = index of register to read + * regnum - index of register to read * * Return value: - * value read, or 0 if an error occurred. + * value read, or 0xffff if an error occurred. ********************************************************************* */ -static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) +static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx) { + struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv; + void __iomem *sbm_mdio = sc->sbm_mdio; int idx; int error; int regval; @@ -574,8 +467,7 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * Synchronize ourselves so that the PHY knows the next * thing coming down is a command */ - - sbmac_mii_sync(s); + sbmac_mii_sync(sbm_mdio); /* * Send the data to the PHY. The sequence is @@ -584,37 +476,37 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * the PHY addr (5 bits) * the register index (5 bits) */ + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2); + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_READ, 2); + sbmac_mii_senddata(sbm_mdio, phyaddr, 5); + sbmac_mii_senddata(sbm_mdio, regidx, 5); - sbmac_mii_senddata(s,MII_COMMAND_START, 2); - sbmac_mii_senddata(s,MII_COMMAND_READ, 2); - sbmac_mii_senddata(s,phyaddr, 5); - sbmac_mii_senddata(s,regidx, 5); - - mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; /* * Switch the port around without a clock transition. */ - __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); /* * Send out a clock pulse to signal we want the status */ - - __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, + sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); /* * If an error occurred, the PHY will signal '1' back */ - error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN; + error = __raw_readq(sbm_mdio) & M_MAC_MDIO_IN; /* * Issue an 'idle' clock pulse, but keep the direction * the same. */ - __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, + sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); regval = 0; @@ -622,55 +514,60 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) regval <<= 1; if (error == 0) { - if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN) + if (__raw_readq(sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; } - __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, + sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); } /* Switch back to output */ - __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio); if (error == 0) return regval; - return 0; + return 0xffff; } /********************************************************************** - * SBMAC_MII_WRITE(s,phyaddr,regidx,regval) + * SBMAC_MII_WRITE(bus, phyaddr, regidx, regval) * * Write a value to a PHY register. * * Input parameters: - * s - sbmac structure + * bus - MDIO bus handle * phyaddr - PHY to use - * regidx - register within the PHY - * regval - data to write to register + * regidx - register within the PHY + * regval - data to write to register * * Return value: - * nothing + * 0 for success ********************************************************************* */ -static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, - unsigned int regval) +static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx, + u16 regval) { + struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv; + void __iomem *sbm_mdio = sc->sbm_mdio; int mac_mdio_genc; - sbmac_mii_sync(s); + sbmac_mii_sync(sbm_mdio); - sbmac_mii_senddata(s,MII_COMMAND_START,2); - sbmac_mii_senddata(s,MII_COMMAND_WRITE,2); - sbmac_mii_senddata(s,phyaddr, 5); - sbmac_mii_senddata(s,regidx, 5); - sbmac_mii_senddata(s,MII_COMMAND_ACK,2); - sbmac_mii_senddata(s,regval,16); + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2); + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_WRITE, 2); + sbmac_mii_senddata(sbm_mdio, phyaddr, 5); + sbmac_mii_senddata(sbm_mdio, regidx, 5); + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_ACK, 2); + sbmac_mii_senddata(sbm_mdio, regval, 16); - mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; - __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio); + + return 0; } @@ -713,27 +610,27 @@ static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING; #endif - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR))); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BYTES); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_COLLISIONS); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_LATE_COL); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_EX_COL); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_FCS_ERROR); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_ABORT); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BAD); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_GOOD); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_RUNT); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_OVERSIZE); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BYTES); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_MCAST); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BCAST); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BAD); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_GOOD); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_RUNT); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_OVERSIZE); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_FCS_ERROR); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_LENGTH_ERROR); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_CODE_ERROR); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_ALIGN_ERROR); /* * initialize register pointers @@ -953,7 +850,7 @@ static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb) if (sb == NULL) { sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN); if (sb_new == NULL) { - printk(KERN_INFO "%s: sk_buff allocation failed\n", + pr_info("%s: sk_buff allocation failed\n", d->sbdma_eth->sbm_dev->name); return -ENOBUFS; } @@ -1472,14 +1369,6 @@ static int sbmac_initctx(struct sbmac_softc *s) s->sbm_imr = s->sbm_base + R_MAC_INT_MASK; s->sbm_mdio = s->sbm_base + R_MAC_MDIO; - s->sbm_phys[0] = 1; - s->sbm_phys[1] = 0; - - s->sbm_phy_oldbmsr = 0; - s->sbm_phy_oldanlpar = 0; - s->sbm_phy_oldk1stsr = 0; - s->sbm_phy_oldlinkstat = 0; - /* * Initialize the DMA channels. Right now, only one per MAC is used * Note: Only do this _once_, as it allocates memory from the kernel! @@ -1494,14 +1383,6 @@ static int sbmac_initctx(struct sbmac_softc *s) s->sbm_state = sbmac_state_off; - /* - * Initial speed is (XXX TEMP) 10MBit/s HDX no FC - */ - - s->sbm_speed = sbmac_speed_10; - s->sbm_duplex = sbmac_duplex_half; - s->sbm_fc = sbmac_fc_disabled; - return 0; } @@ -2008,8 +1889,6 @@ static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed) cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN; break; - case sbmac_speed_auto: /* XXX not implemented */ - /* fall through */ default: return 0; } @@ -2083,8 +1962,6 @@ static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR; break; - case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ case sbmac_fc_frame: /* not valid in half duplex */ default: /* invalid selection */ return 0; @@ -2103,15 +1980,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, case sbmac_fc_collision: /* not valid in full duplex */ case sbmac_fc_carrier: /* not valid in full duplex */ - case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ default: return 0; } break; - case sbmac_duplex_auto: - /* XXX not implemented */ - break; + default: + return 0; } /* @@ -2390,7 +2264,7 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) if (new_mtu > ENET_PACKET_SIZE) return -EINVAL; _dev->mtu = new_mtu; - printk(KERN_INFO "changing the mtu to %d\n", new_mtu); + pr_info("changing the mtu to %d\n", new_mtu); return 0; } @@ -2406,20 +2280,17 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) * status ********************************************************************* */ -static int sbmac_init(struct net_device *dev, int idx) +static int sbmac_init(struct platform_device *pldev, long long base) { - struct sbmac_softc *sc; + struct net_device *dev = pldev->dev.driver_data; + int idx = pldev->id; + struct sbmac_softc *sc = netdev_priv(dev); unsigned char *eaddr; uint64_t ea_reg; int i; int err; DECLARE_MAC_BUF(mac); - sc = netdev_priv(dev); - - /* Determine controller base address */ - - sc->sbm_base = IOADDR(dev->base_addr); sc->sbm_dev = dev; sc->sbe_idx = idx; @@ -2476,43 +2347,55 @@ static int sbmac_init(struct net_device *dev, int idx) dev->poll_controller = sbmac_netpoll; #endif + dev->irq = UNIT_INT(idx); + /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); err = register_netdev(dev); - if (err) - goto out_uninit; - - if (sc->rx_hw_checksum == ENABLE) { - printk(KERN_INFO "%s: enabling TCP rcv checksum\n", - sc->sbm_dev->name); + if (err) { + printk(KERN_ERR "%s.%d: unable to register netdev\n", + sbmac_string, idx); + sbmac_uninitctx(sc); + return err; } + pr_info("%s.%d: registered as %s\n", sbmac_string, idx, dev->name); + + if (sc->rx_hw_checksum == ENABLE) + pr_info("%s: enabling TCP rcv checksum\n", dev->name); + /* * Display Ethernet address (this is called during the config * process so we need to finish off the config message that * was being displayed) */ - printk(KERN_INFO - "%s: SiByte Ethernet at 0x%08lX, address: %s\n", - dev->name, dev->base_addr, print_mac(mac, eaddr)); + pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n", + dev->name, base, print_mac(mac, eaddr)); + + sc->mii_bus.name = sbmac_mdio_string; + sc->mii_bus.id = idx; + sc->mii_bus.priv = sc; + sc->mii_bus.read = sbmac_mii_read; + sc->mii_bus.write = sbmac_mii_write; + sc->mii_bus.irq = sc->phy_irq; + for (i = 0; i < PHY_MAX_ADDR; ++i) + sc->mii_bus.irq[i] = SBMAC_PHY_INT; + + sc->mii_bus.dev = &pldev->dev; + dev_set_drvdata(&pldev->dev, &sc->mii_bus); return 0; - -out_uninit: - sbmac_uninitctx(sc); - - return err; } static int sbmac_open(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); + int err; - if (debug > 1) { - printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); - } + if (debug > 1) + pr_debug("%s: sbmac_open() irq %d.\n", dev->name, dev->irq); /* * map/route interrupt (clear status first, in case something @@ -2521,25 +2404,35 @@ static int sbmac_open(struct net_device *dev) */ __raw_readq(sc->sbm_isr); - if (request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev)) - return -EBUSY; - - /* - * Probe phy address - */ - - if(sbmac_mii_probe(dev) == -1) { - printk("%s: failed to probe PHY.\n", dev->name); - return -EINVAL; + err = request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev); + if (err) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, + dev->irq); + goto out_err; } - napi_enable(&sc->napi); + /* + * Probe PHY address + */ + err = mdiobus_register(&sc->mii_bus); + if (err) { + printk(KERN_ERR "%s: unable to register MDIO bus\n", + dev->name); + goto out_unirq; + } + + sc->sbm_speed = sbmac_speed_none; + sc->sbm_duplex = sbmac_duplex_none; + sc->sbm_fc = sbmac_fc_none; + sc->sbm_pause = -1; + sc->sbm_link = 0; /* - * Configure default speed + * Attach to the PHY */ - - sbmac_mii_poll(sc,noisy_mii); + err = sbmac_mii_probe(dev); + if (err) + goto out_unregister; /* * Turn on the channel @@ -2547,200 +2440,133 @@ static int sbmac_open(struct net_device *dev) sbmac_set_channel_state(sc,sbmac_state_on); - /* - * XXX Station address is in dev->dev_addr - */ - - if (dev->if_port == 0) - dev->if_port = 0; - netif_start_queue(dev); sbmac_set_rx_mode(dev); - /* Set the timer to check for link beat. */ - init_timer(&sc->sbm_timer); - sc->sbm_timer.expires = jiffies + 2 * HZ/100; - sc->sbm_timer.data = (unsigned long)dev; - sc->sbm_timer.function = &sbmac_timer; - add_timer(&sc->sbm_timer); + phy_start(sc->phy_dev); + + napi_enable(&sc->napi); return 0; + +out_unregister: + mdiobus_unregister(&sc->mii_bus); + +out_unirq: + free_irq(dev->irq, dev); + +out_err: + return err; } static int sbmac_mii_probe(struct net_device *dev) { - int i; - struct sbmac_softc *s = netdev_priv(dev); - u16 bmsr, id1, id2; - u32 vendor, device; - - for (i=1; i<31; i++) { - bmsr = sbmac_mii_read(s, i, MII_BMSR); - if (bmsr != 0) { - s->sbm_phys[0] = i; - id1 = sbmac_mii_read(s, i, MII_PHYIDR1); - id2 = sbmac_mii_read(s, i, MII_PHYIDR2); - vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f); - device = (id2 >> 4) & 0x3f; - - printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n", - dev->name, i, vendor, device); - return i; - } - } - return -1; -} - - -static int sbmac_mii_poll(struct sbmac_softc *s,int noisy) -{ - int bmsr,bmcr,k1stsr,anlpar; - int chg; - char buffer[100]; - char *p = buffer; - - /* Read the mode status and mode control registers. */ - bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR); - bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR); - - /* get the link partner status */ - anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR); - - /* if supported, read the 1000baseT register */ - if (bmsr & BMSR_1000BT_XSR) { - k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR); - } - else { - k1stsr = 0; - } - - chg = 0; - - if ((bmsr & BMSR_LINKSTAT) == 0) { - /* - * If link status is down, clear out old info so that when - * it comes back up it will force us to reconfigure speed - */ - s->sbm_phy_oldbmsr = 0; - s->sbm_phy_oldanlpar = 0; - s->sbm_phy_oldk1stsr = 0; - return 0; - } - - if ((s->sbm_phy_oldbmsr != bmsr) || - (s->sbm_phy_oldanlpar != anlpar) || - (s->sbm_phy_oldk1stsr != k1stsr)) { - if (debug > 1) { - printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n", - s->sbm_dev->name, - s->sbm_phy_oldbmsr,bmsr, - s->sbm_phy_oldanlpar,anlpar, - s->sbm_phy_oldk1stsr,k1stsr); - } - s->sbm_phy_oldbmsr = bmsr; - s->sbm_phy_oldanlpar = anlpar; - s->sbm_phy_oldk1stsr = k1stsr; - chg = 1; - } - - if (chg == 0) - return 0; - - p += sprintf(p,"Link speed: "); - - if (k1stsr & K1STSR_LP1KFD) { - s->sbm_speed = sbmac_speed_1000; - s->sbm_duplex = sbmac_duplex_full; - s->sbm_fc = sbmac_fc_frame; - p += sprintf(p,"1000BaseT FDX"); - } - else if (k1stsr & K1STSR_LP1KHD) { - s->sbm_speed = sbmac_speed_1000; - s->sbm_duplex = sbmac_duplex_half; - s->sbm_fc = sbmac_fc_disabled; - p += sprintf(p,"1000BaseT HDX"); - } - else if (anlpar & ANLPAR_TXFD) { - s->sbm_speed = sbmac_speed_100; - s->sbm_duplex = sbmac_duplex_full; - s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled; - p += sprintf(p,"100BaseT FDX"); - } - else if (anlpar & ANLPAR_TXHD) { - s->sbm_speed = sbmac_speed_100; - s->sbm_duplex = sbmac_duplex_half; - s->sbm_fc = sbmac_fc_disabled; - p += sprintf(p,"100BaseT HDX"); - } - else if (anlpar & ANLPAR_10FD) { - s->sbm_speed = sbmac_speed_10; - s->sbm_duplex = sbmac_duplex_full; - s->sbm_fc = sbmac_fc_frame; - p += sprintf(p,"10BaseT FDX"); - } - else if (anlpar & ANLPAR_10HD) { - s->sbm_speed = sbmac_speed_10; - s->sbm_duplex = sbmac_duplex_half; - s->sbm_fc = sbmac_fc_collision; - p += sprintf(p,"10BaseT HDX"); - } - else { - p += sprintf(p,"Unknown"); - } - - if (noisy) { - printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer); - } - - return 1; -} - - -static void sbmac_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; struct sbmac_softc *sc = netdev_priv(dev); - int next_tick = HZ; - int mii_status; + struct phy_device *phy_dev; + int i; - spin_lock_irq (&sc->sbm_lock); - - /* make IFF_RUNNING follow the MII status bit "Link established" */ - mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR); - - if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) { - sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT; - if (mii_status & BMSR_LINKSTAT) { - netif_carrier_on(dev); - } - else { - netif_carrier_off(dev); - } + for (i = 0; i < PHY_MAX_ADDR; i++) { + phy_dev = sc->mii_bus.phy_map[i]; + if (phy_dev) + break; + } + if (!phy_dev) { + printk(KERN_ERR "%s: no PHY found\n", dev->name); + return -ENXIO; } - /* - * Poll the PHY to see what speed we should be running at - */ - - if (sbmac_mii_poll(sc,noisy_mii)) { - if (sc->sbm_state != sbmac_state_off) { - /* - * something changed, restart the channel - */ - if (debug > 1) { - printk("%s: restarting channel because speed changed\n", - sc->sbm_dev->name); - } - sbmac_channel_stop(sc); - sbmac_channel_start(sc); - } + phy_dev = phy_connect(dev, phy_dev->dev.bus_id, &sbmac_mii_poll, 0, + PHY_INTERFACE_MODE_GMII); + if (IS_ERR(phy_dev)) { + printk(KERN_ERR "%s: could not attach to PHY\n", dev->name); + return PTR_ERR(phy_dev); } - spin_unlock_irq (&sc->sbm_lock); + /* Remove any features not supported by the controller */ + phy_dev->supported &= SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_MII | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause; + phy_dev->advertising = phy_dev->supported; - sc->sbm_timer.expires = jiffies + next_tick; - add_timer(&sc->sbm_timer); + pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + dev->name, phy_dev->drv->name, + phy_dev->dev.bus_id, phy_dev->irq); + + sc->phy_dev = phy_dev; + + return 0; +} + + +static void sbmac_mii_poll(struct net_device *dev) +{ + struct sbmac_softc *sc = netdev_priv(dev); + struct phy_device *phy_dev = sc->phy_dev; + unsigned long flags; + enum sbmac_fc fc; + int link_chg, speed_chg, duplex_chg, pause_chg, fc_chg; + + link_chg = (sc->sbm_link != phy_dev->link); + speed_chg = (sc->sbm_speed != phy_dev->speed); + duplex_chg = (sc->sbm_duplex != phy_dev->duplex); + pause_chg = (sc->sbm_pause != phy_dev->pause); + + if (!link_chg && !speed_chg && !duplex_chg && !pause_chg) + return; /* Hmmm... */ + + if (!phy_dev->link) { + if (link_chg) { + sc->sbm_link = phy_dev->link; + sc->sbm_speed = sbmac_speed_none; + sc->sbm_duplex = sbmac_duplex_none; + sc->sbm_fc = sbmac_fc_disabled; + sc->sbm_pause = -1; + pr_info("%s: link unavailable\n", dev->name); + } + return; + } + + if (phy_dev->duplex == DUPLEX_FULL) { + if (phy_dev->pause) + fc = sbmac_fc_frame; + else + fc = sbmac_fc_disabled; + } else + fc = sbmac_fc_collision; + fc_chg = (sc->sbm_fc != fc); + + pr_info("%s: link available: %dbase-%cD\n", dev->name, phy_dev->speed, + phy_dev->duplex == DUPLEX_FULL ? 'F' : 'H'); + + spin_lock_irqsave(&sc->sbm_lock, flags); + + sc->sbm_speed = phy_dev->speed; + sc->sbm_duplex = phy_dev->duplex; + sc->sbm_fc = fc; + sc->sbm_pause = phy_dev->pause; + sc->sbm_link = phy_dev->link; + + if ((speed_chg || duplex_chg || fc_chg) && + sc->sbm_state != sbmac_state_off) { + /* + * something changed, restart the channel + */ + if (debug > 1) + pr_debug("%s: restarting channel " + "because PHY state changed\n", dev->name); + sbmac_channel_stop(sc); + sbmac_channel_start(sc); + } + + spin_unlock_irqrestore(&sc->sbm_lock, flags); } @@ -2793,64 +2619,34 @@ static void sbmac_set_rx_mode(struct net_device *dev) static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct sbmac_softc *sc = netdev_priv(dev); - u16 *data = (u16 *)&rq->ifr_ifru; - unsigned long flags; - int retval; - spin_lock_irqsave(&sc->sbm_lock, flags); - retval = 0; + if (!netif_running(dev) || !sc->phy_dev) + return -EINVAL; - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = sc->sbm_phys[0] & 0x1f; - /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f); - break; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - break; - } - if (debug > 1) { - printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name, - data[0],data[1],data[2]); - } - sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]); - break; - default: - retval = -EOPNOTSUPP; - } - - spin_unlock_irqrestore(&sc->sbm_lock, flags); - return retval; + return phy_mii_ioctl(sc->phy_dev, if_mii(rq), cmd); } static int sbmac_close(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - unsigned long flags; - int irq; napi_disable(&sc->napi); - sbmac_set_channel_state(sc,sbmac_state_off); + phy_stop(sc->phy_dev); - del_timer_sync(&sc->sbm_timer); - - spin_lock_irqsave(&sc->sbm_lock, flags); + sbmac_set_channel_state(sc, sbmac_state_off); netif_stop_queue(dev); - if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name); - } + if (debug > 1) + pr_debug("%s: Shutting down ethercard\n", dev->name); - spin_unlock_irqrestore(&sc->sbm_lock, flags); + phy_disconnect(sc->phy_dev); + sc->phy_dev = NULL; - irq = dev->irq; - synchronize_irq(irq); - free_irq(irq, dev); + mdiobus_unregister(&sc->mii_bus); + + free_irq(dev->irq, dev); sbdma_emptyring(&(sc->sbm_txdma)); sbdma_emptyring(&(sc->sbm_rxdma)); @@ -2883,54 +2679,195 @@ static int sbmac_poll(struct napi_struct *napi, int budget) return work_done; } -#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) -static void -sbmac_setup_hwaddr(int chan,char *addr) + +static int __init sbmac_probe(struct platform_device *pldev) { + struct net_device *dev; + struct sbmac_softc *sc; + void __iomem *sbm_base; + struct resource *res; + u64 sbmac_orig_hwaddr; + int err; + + res = platform_get_resource(pldev, IORESOURCE_MEM, 0); + BUG_ON(!res); + sbm_base = ioremap_nocache(res->start, res->end - res->start + 1); + if (!sbm_base) { + printk(KERN_ERR "%s: unable to map device registers\n", + pldev->dev.bus_id); + err = -ENOMEM; + goto out_out; + } + + /* + * The R_MAC_ETHERNET_ADDR register will be set to some nonzero + * value for us by the firmware if we're going to use this MAC. + * If we find a zero, skip this MAC. + */ + sbmac_orig_hwaddr = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR); + pr_debug("%s: %sconfiguring MAC at 0x%08Lx\n", pldev->dev.bus_id, + sbmac_orig_hwaddr ? "" : "not ", (long long)res->start); + if (sbmac_orig_hwaddr == 0) { + err = 0; + goto out_unmap; + } + + /* + * Okay, cool. Initialize this MAC. + */ + dev = alloc_etherdev(sizeof(struct sbmac_softc)); + if (!dev) { + printk(KERN_ERR "%s: unable to allocate etherdev\n", + pldev->dev.bus_id); + err = -ENOMEM; + goto out_unmap; + } + + pldev->dev.driver_data = dev; + SET_NETDEV_DEV(dev, &pldev->dev); + + sc = netdev_priv(dev); + sc->sbm_base = sbm_base; + + err = sbmac_init(pldev, res->start); + if (err) + goto out_kfree; + + return 0; + +out_kfree: + free_netdev(dev); + __raw_writeq(sbmac_orig_hwaddr, sbm_base + R_MAC_ETHERNET_ADDR); + +out_unmap: + iounmap(sbm_base); + +out_out: + return err; +} + +static int __exit sbmac_remove(struct platform_device *pldev) +{ + struct net_device *dev = pldev->dev.driver_data; + struct sbmac_softc *sc = netdev_priv(dev); + + unregister_netdev(dev); + sbmac_uninitctx(sc); + iounmap(sc->sbm_base); + free_netdev(dev); + + return 0; +} + + +static struct platform_device **sbmac_pldev; +static int sbmac_max_units; + +#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) +static void __init sbmac_setup_hwaddr(int idx, char *addr) +{ + void __iomem *sbm_base; + unsigned long start, end; uint8_t eaddr[6]; uint64_t val; - unsigned long port; - port = A_MAC_CHANNEL_BASE(chan); - sbmac_parse_hwaddr(addr,eaddr); + if (idx >= sbmac_max_units) + return; + + start = A_MAC_CHANNEL_BASE(idx); + end = A_MAC_CHANNEL_BASE(idx + 1) - 1; + + sbm_base = ioremap_nocache(start, end - start + 1); + if (!sbm_base) { + printk(KERN_ERR "%s: unable to map device registers\n", + sbmac_string); + return; + } + + sbmac_parse_hwaddr(addr, eaddr); val = sbmac_addr2reg(eaddr); - __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR)); - val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); + __raw_writeq(val, sbm_base + R_MAC_ETHERNET_ADDR); + val = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR); + + iounmap(sbm_base); } #endif -static struct net_device *dev_sbmac[MAX_UNITS]; - -static int __init -sbmac_init_module(void) +static int __init sbmac_platform_probe_one(int idx) { - int idx; - struct net_device *dev; - unsigned long port; - int chip_max_units; + struct platform_device *pldev; + struct { + struct resource r; + char name[strlen(sbmac_pretty) + 4]; + } *res; + int err; + + res = kzalloc(sizeof(*res), GFP_KERNEL); + if (!res) { + printk(KERN_ERR "%s.%d: unable to allocate memory\n", + sbmac_string, idx); + err = -ENOMEM; + goto out_err; + } + + /* + * This is the base address of the MAC. + */ + snprintf(res->name, sizeof(res->name), "%s %d", sbmac_pretty, idx); + res->r.name = res->name; + res->r.flags = IORESOURCE_MEM; + res->r.start = A_MAC_CHANNEL_BASE(idx); + res->r.end = A_MAC_CHANNEL_BASE(idx + 1) - 1; + + pldev = platform_device_register_simple(sbmac_string, idx, &res->r, 1); + if (IS_ERR(pldev)) { + printk(KERN_ERR "%s.%d: unable to register platform device\n", + sbmac_string, idx); + err = PTR_ERR(pldev); + goto out_kfree; + } + + if (!pldev->dev.driver) { + err = 0; /* No hardware at this address. */ + goto out_unregister; + } + + sbmac_pldev[idx] = pldev; + return 0; + +out_unregister: + platform_device_unregister(pldev); + +out_kfree: + kfree(res); + +out_err: + return err; +} + +static void __init sbmac_platform_probe(void) +{ + int i; /* Set the number of available units based on the SOC type. */ switch (soc_type) { case K_SYS_SOC_TYPE_BCM1250: case K_SYS_SOC_TYPE_BCM1250_ALT: - chip_max_units = 3; + sbmac_max_units = 3; break; case K_SYS_SOC_TYPE_BCM1120: case K_SYS_SOC_TYPE_BCM1125: case K_SYS_SOC_TYPE_BCM1125H: - case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */ - chip_max_units = 2; + case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */ + sbmac_max_units = 2; break; case K_SYS_SOC_TYPE_BCM1x55: case K_SYS_SOC_TYPE_BCM1x80: - chip_max_units = 4; + sbmac_max_units = 4; break; default: - chip_max_units = 0; - break; + return; /* none */ } - if (chip_max_units > MAX_UNITS) - chip_max_units = MAX_UNITS; /* * For bringup when not using the firmware, we can pre-fill @@ -2938,89 +2875,71 @@ sbmac_init_module(void) * specified in this file (or maybe from the config file?) */ #ifdef SBMAC_ETH0_HWADDR - if (chip_max_units > 0) - sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR); + sbmac_setup_hwaddr(0, SBMAC_ETH0_HWADDR); #endif #ifdef SBMAC_ETH1_HWADDR - if (chip_max_units > 1) - sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR); + sbmac_setup_hwaddr(1, SBMAC_ETH1_HWADDR); #endif #ifdef SBMAC_ETH2_HWADDR - if (chip_max_units > 2) - sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR); + sbmac_setup_hwaddr(2, SBMAC_ETH2_HWADDR); #endif #ifdef SBMAC_ETH3_HWADDR - if (chip_max_units > 3) - sbmac_setup_hwaddr(3,SBMAC_ETH3_HWADDR); + sbmac_setup_hwaddr(3, SBMAC_ETH3_HWADDR); #endif + sbmac_pldev = kcalloc(sbmac_max_units, sizeof(*sbmac_pldev), + GFP_KERNEL); + if (!sbmac_pldev) { + printk(KERN_ERR "%s: unable to allocate memory\n", + sbmac_string); + return; + } + /* * Walk through the Ethernet controllers and find * those who have their MAC addresses set. */ - for (idx = 0; idx < chip_max_units; idx++) { - - /* - * This is the base address of the MAC. - */ - - port = A_MAC_CHANNEL_BASE(idx); - - /* - * The R_MAC_ETHERNET_ADDR register will be set to some nonzero - * value for us by the firmware if we are going to use this MAC. - * If we find a zero, skip this MAC. - */ - - sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); - if (sbmac_orig_hwaddr[idx] == 0) { - printk(KERN_DEBUG "sbmac: not configuring MAC at " - "%lx\n", port); - continue; - } - - /* - * Okay, cool. Initialize this MAC. - */ - - dev = alloc_etherdev(sizeof(struct sbmac_softc)); - if (!dev) - return -ENOMEM; - - printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); - - dev->irq = UNIT_INT(idx); - dev->base_addr = port; - dev->mem_end = 0; - if (sbmac_init(dev, idx)) { - port = A_MAC_CHANNEL_BASE(idx); - __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR)); - free_netdev(dev); - continue; - } - dev_sbmac[idx] = dev; - } - return 0; + for (i = 0; i < sbmac_max_units; i++) + if (sbmac_platform_probe_one(i)) + break; } -static void __exit -sbmac_cleanup_module(void) +static void __exit sbmac_platform_cleanup(void) { - struct net_device *dev; - int idx; + int i; - for (idx = 0; idx < MAX_UNITS; idx++) { - struct sbmac_softc *sc; - dev = dev_sbmac[idx]; - if (!dev) - continue; + for (i = 0; i < sbmac_max_units; i++) + platform_device_unregister(sbmac_pldev[i]); + kfree(sbmac_pldev); +} - sc = netdev_priv(dev); - unregister_netdev(dev); - sbmac_uninitctx(sc); - free_netdev(dev); - } + +static struct platform_driver sbmac_driver = { + .probe = sbmac_probe, + .remove = __exit_p(sbmac_remove), + .driver = { + .name = sbmac_string, + }, +}; + +static int __init sbmac_init_module(void) +{ + int err; + + err = platform_driver_register(&sbmac_driver); + if (err) + return err; + + sbmac_platform_probe(); + + return err; +} + +static void __exit sbmac_cleanup_module(void) +{ + sbmac_platform_cleanup(); + platform_driver_unregister(&sbmac_driver); } module_init(sbmac_init_module); From 501e4d247a7e35a4d3aa8e6973794b1586f6cb30 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Aug 2007 13:56:49 -0700 Subject: [PATCH 1632/2804] via-velocity: use standard VLAN interface (resend) The via-velocity is using a non-standard VLAN interface configured via module parameters (yuck). Replace with the standard acceleration interface. It solves a number of problems with being able to handle multiple vlans, and dynamically reconfigure. This is compile tested only, don't have this board. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/via-velocity.c | 71 +++++++++++++++++++++++--------------- drivers/net/via-velocity.h | 3 +- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 511a74c6e78b..fd1ff123efa0 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -111,15 +112,6 @@ VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors"); #define TX_DESC_DEF 64 VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors"); -#define VLAN_ID_MIN 0 -#define VLAN_ID_MAX 4095 -#define VLAN_ID_DEF 0 -/* VID_setting[] is used for setting the VID of NIC. - 0: default VID. - 1-4094: other VIDs. -*/ -VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID"); - #define RX_THRESH_MIN 0 #define RX_THRESH_MAX 3 #define RX_THRESH_DEF 0 @@ -147,13 +139,6 @@ VELOCITY_PARAM(rx_thresh, "Receive fifo threshold"); */ VELOCITY_PARAM(DMA_length, "DMA length"); -#define TAGGING_DEF 0 -/* enable_tagging[] is used for enabling 802.1Q VID tagging. - 0: disable VID seeting(default). - 1: enable VID setting. -*/ -VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging"); - #define IP_ALIG_DEF 0 /* IP_byte_align[] is used for IP header DWORD byte aligned 0: indicate the IP header won't be DWORD byte aligned.(Default) . @@ -442,8 +427,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname); velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname); velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname); - velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname); - velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname); + velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname); velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname); velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname); @@ -465,6 +449,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; + unsigned short vid; /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); @@ -477,13 +462,19 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); /* Enable first VCAM */ - if (vptr->flags & VELOCITY_FLAGS_TAGGING) { - /* If Tagging option is enabled and VLAN ID is not zero, then - turn on MCFG_RTGOPT also */ - if (vptr->options.vid != 0) - WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); + if (vptr->vlgrp) { + for (vid = 0; vid < VLAN_VID_MASK; vid++) { + if (vlan_group_get_device(vptr->vlgrp, vid)) { + /* If Tagging option is enabled and + VLAN ID is not zero, then + turn on MCFG_RTGOPT also */ + if (vid != 0) + WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); - mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM); + mac_set_cam(regs, 0, (u8 *) &vid, + VELOCITY_VLAN_ID_CAM); + } + } vptr->vCAMmask[0] |= 1; mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); } else { @@ -494,6 +485,26 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) } } +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); + velocity_init_cam_filter(vptr); + 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); + vlan_group_set_device(vptr->vlgrp, vid, NULL); + velocity_init_cam_filter(vptr); + spin_unlock_irq(&vptr->lock); +} + + /** * velocity_rx_reset - handle a receive reset * @vptr: velocity we are resetting @@ -790,13 +801,17 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->do_ioctl = velocity_ioctl; dev->ethtool_ops = &velocity_ethtool_ops; dev->change_mtu = velocity_change_mtu; + + dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid; + dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid; + #ifdef VELOCITY_ZERO_COPY_SUPPORT dev->features |= NETIF_F_SG; #endif + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER; - if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) { + if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) dev->features |= NETIF_F_IP_CSUM; - } ret = register_netdev(dev); if (ret < 0) @@ -1989,8 +2004,8 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) td_ptr->tdesc1.CMDZ = 2; } - if (vptr->flags & VELOCITY_FLAGS_TAGGING) { - td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff); + if (vptr->vlgrp && vlan_tx_tag_present(skb)) { + td_ptr->tdesc1.pqinf.VID = vlan_tx_tag_get(skb); td_ptr->tdesc1.pqinf.priority = 0; td_ptr->tdesc1.pqinf.CFI = 0; td_ptr->tdesc1.TCR |= TCR0_VETAG; diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index b9e114d36c0f..af17161286ae 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1701,7 +1701,7 @@ struct velocity_opt { int numrx; /* Number of RX descriptors */ int numtx; /* Number of TX descriptors */ enum speed_opt spd_dpx; /* Media link mode */ - int vid; /* vlan id */ + int DMA_length; /* DMA length */ int rx_thresh; /* RX_THRESH */ int flow_cntl; @@ -1727,6 +1727,7 @@ struct velocity_info { dma_addr_t tx_bufs_dma; u8 *tx_bufs; + struct vlan_group *vlgrp; u8 ip_addr[4]; enum chip_type chip_id; From 01faccbf866195831af202de59f37e29467a3d74 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Aug 2007 14:40:45 -0700 Subject: [PATCH 1633/2804] via-velocity: more cleanup Per Al's suggestion, get rid of the stupid stuff: Remove cam_type switch, And deinline things that aren't important for speed. And make big macro and inline. And remove some dead/unused code. And use const char * for chip name. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/via-velocity.c | 178 ++++++++++++++++++++++++++++++-- drivers/net/via-velocity.h | 206 ++----------------------------------- 2 files changed, 177 insertions(+), 207 deletions(-) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index fd1ff123efa0..4ae05799ac44 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -85,6 +85,163 @@ static int velocity_nics = 0; static int msglevel = MSG_LEVEL_INFO; +/** + * mac_get_cam_mask - Read a CAM mask + * @regs: register block for this velocity + * @mask: buffer to store mask + * + * 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; + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + writeb(0, ®s->CAMADDR); + + /* read mask */ + for (i = 0; i < 8; i++) + *mask++ = readb(&(regs->MARCAM[i])); + + /* disable CAMEN */ + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + +} + + +/** + * mac_set_cam_mask - Set a CAM mask + * @regs: register block for this velocity + * @mask: CAM mask to load + * + * Store a new mask into a CAM + */ + +static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +{ + int i; + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + writeb(CAMADDR_CAMEN, ®s->CAMADDR); + + for (i = 0; i < 8; i++) { + writeb(*mask++, &(regs->MARCAM[i])); + } + /* disable CAMEN */ + writeb(0, ®s->CAMADDR); + + /* Select mar */ + 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) +{ + int i; + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, ®s->CAMADDR); + + for (i = 0; i < 8; i++) { + writeb(*mask++, &(regs->MARCAM[i])); + } + /* disable CAMEN */ + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + +/** + * mac_set_cam - set CAM data + * @regs: register block of this velocity + * @idx: Cam index + * @addr: 2 or 6 bytes of CAM data + * + * 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; + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + idx &= (64 - 1); + + writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); + + for (i = 0; i < 6; i++) { + writeb(*addr++, &(regs->MARCAM[i])); + } + BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); + + udelay(10); + + writeb(0, ®s->CAMADDR); + + /* Select mar */ + 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, + const u8 *addr) +{ + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + idx &= (64 - 1); + + writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, ®s->CAMADDR); + writew(*((u16 *) addr), ®s->MARCAM[0]); + + BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); + + udelay(10); + + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + + +/** + * mac_wol_reset - reset WOL after exiting low power + * @regs: register block of this velocity + * + * Called after we drop out of wake on lan mode in order to + * 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) +{ + + /* Turn off SWPTAG right after leaving power mode */ + BYTE_REG_BITS_OFF(STICKHW_SWPTAG, ®s->STICKHW); + /* clear sticky bits */ + BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), ®s->STICKHW); + + BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, ®s->CHIPGCR); + BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); + /* disable force PME-enable */ + writeb(WOLCFG_PMEOVR, ®s->WOLCFGClr); + /* disable power-event config bit */ + writew(0xFFFF, ®s->WOLCRClr); + /* clear power status */ + 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; @@ -309,7 +466,7 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table); * a pointer a static string valid while the driver is loaded. */ -static char __devinit *get_chip_name(enum chip_type chip_id) +static const char __devinit *get_chip_name(enum chip_type chip_id) { int i; for (i = 0; chip_info_table[i].name != NULL; i++) @@ -458,8 +615,8 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) /* Disable all CAMs */ memset(vptr->vCAMmask, 0, sizeof(u8) * 8); memset(vptr->mCAMmask, 0, sizeof(u8) * 8); - mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); - mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + mac_set_vlan_cam_mask(regs, vptr->vCAMmask); + mac_set_cam_mask(regs, vptr->mCAMmask); /* Enable first VCAM */ if (vptr->vlgrp) { @@ -471,17 +628,16 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) if (vid != 0) WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); - mac_set_cam(regs, 0, (u8 *) &vid, - VELOCITY_VLAN_ID_CAM); + mac_set_vlan_cam(regs, 0, (u8 *) &vid); } } vptr->vCAMmask[0] |= 1; - mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); + mac_set_vlan_cam_mask(regs, vptr->vCAMmask); } else { u16 temp = 0; - mac_set_cam(regs, 0, (u8 *) &temp, VELOCITY_VLAN_ID_CAM); + mac_set_vlan_cam(regs, 0, (u8 *) &temp); temp = 1; - mac_set_cam_mask(regs, (u8 *) &temp, VELOCITY_VLAN_ID_CAM); + mac_set_vlan_cam_mask(regs, (u8 *) &temp); } } @@ -2131,14 +2287,14 @@ static void velocity_set_multi(struct net_device *dev) rx_mode = (RCR_AM | RCR_AB); } else { int offset = MCAM_SIZE - vptr->multicast_limit; - mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + mac_get_cam_mask(regs, vptr->mCAMmask); 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, VELOCITY_MULTICAST_CAM); + mac_set_cam(regs, i + offset, mclist->dmi_addr); vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); } - mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + mac_set_cam_mask(regs, vptr->mCAMmask); rx_mode = (RCR_AM | RCR_AB); } if (dev->mtu > 1500) diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index af17161286ae..aa9179623d90 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1173,7 +1173,7 @@ enum chip_type { struct velocity_info_tbl { enum chip_type chip_id; - char *name; + const char *name; int txqueue; u32 flags; }; @@ -1194,14 +1194,6 @@ struct velocity_info_tbl { #define mac_disable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Clr)) #define mac_enable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Set)) -#define mac_hw_mibs_read(regs, MIBs) {\ - int i;\ - BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\ - for (i=0;iMIBData));\ - }\ -} - #define mac_set_dma_length(regs, n) {\ BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\ } @@ -1226,195 +1218,17 @@ struct velocity_info_tbl { writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\ } -#define mac_eeprom_reload(regs) {\ - int i=0;\ - BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\ - do {\ - udelay(10);\ - if (i++>0x1000) {\ - break;\ - }\ - }while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\ +static inline void mac_eeprom_reload(struct mac_regs __iomem * regs) { + int i=0; + + BYTE_REG_BITS_ON(EECSR_RELOAD,&(regs->EECSR)); + do { + udelay(10); + if (i++>0x1000) + break; + } while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&(regs->EECSR))); } -enum velocity_cam_type { - VELOCITY_VLAN_ID_CAM = 0, - VELOCITY_MULTICAST_CAM -}; - -/** - * mac_get_cam_mask - Read a CAM mask - * @regs: register block for this velocity - * @mask: buffer to store mask - * @cam_type: CAM to fetch - * - * Fetch the mask bits of the selected CAM and store them into the - * provided mask buffer. - */ - -static inline void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type) -{ - int i; - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_VCAMSL, ®s->CAMADDR); - else - writeb(0, ®s->CAMADDR); - - /* read mask */ - for (i = 0; i < 8; i++) - *mask++ = readb(&(regs->MARCAM[i])); - - /* disable CAMEN */ - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - -} - -/** - * mac_set_cam_mask - Set a CAM mask - * @regs: register block for this velocity - * @mask: CAM mask to load - * @cam_type: CAM to store - * - * Store a new mask into a CAM - */ - -static inline void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type) -{ - int i; - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN, ®s->CAMADDR); - - for (i = 0; i < 8; i++) { - writeb(*mask++, &(regs->MARCAM[i])); - } - /* disable CAMEN */ - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); -} - -/** - * mac_set_cam - set CAM data - * @regs: register block of this velocity - * @idx: Cam index - * @addr: 2 or 6 bytes of CAM data - * @cam_type: CAM to load - * - * Load an address or vlan tag into a CAM - */ - -static inline void mac_set_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type) -{ - int i; - - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - - idx &= (64 - 1); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writew(*((u16 *) addr), ®s->MARCAM[0]); - else { - for (i = 0; i < 6; i++) { - writeb(*addr++, &(regs->MARCAM[i])); - } - } - BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); - - udelay(10); - - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); -} - -/** - * mac_get_cam - fetch CAM data - * @regs: register block of this velocity - * @idx: Cam index - * @addr: buffer to hold up to 6 bytes of CAM data - * @cam_type: CAM to load - * - * Load an address or vlan tag from a CAM into the buffer provided by - * the caller. VLAN tags are 2 bytes the address cam entries are 6. - */ - -static inline void mac_get_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type) -{ - int i; - - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - - idx &= (64 - 1); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); - - BYTE_REG_BITS_ON(CAMCR_CAMRD, ®s->CAMCR); - - udelay(10); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - *((u16 *) addr) = readw(&(regs->MARCAM[0])); - else - for (i = 0; i < 6; i++, addr++) - *((u8 *) addr) = readb(&(regs->MARCAM[i])); - - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); -} - -/** - * mac_wol_reset - reset WOL after exiting low power - * @regs: register block of this velocity - * - * Called after we drop out of wake on lan mode in order to - * reset the Wake on lan features. This function doesn't restore - * the rest of the logic from the result of sleep/wakeup - */ - -static inline void mac_wol_reset(struct mac_regs __iomem * regs) -{ - - /* Turn off SWPTAG right after leaving power mode */ - BYTE_REG_BITS_OFF(STICKHW_SWPTAG, ®s->STICKHW); - /* clear sticky bits */ - BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), ®s->STICKHW); - - BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, ®s->CHIPGCR); - BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); - /* disable force PME-enable */ - writeb(WOLCFG_PMEOVR, ®s->WOLCFGClr); - /* disable power-event config bit */ - writew(0xFFFF, ®s->WOLCRClr); - /* clear power status */ - writew(0xFFFF, ®s->WOLSRClr); -} - - /* * Header for WOL definitions. Used to compute hashes */ From cdcc520d7b73445c3552a70786afed9a2b22c010 Mon Sep 17 00:00:00 2001 From: Chris Snook Date: Thu, 20 Sep 2007 15:57:15 -0400 Subject: [PATCH 1634/2804] atl1: explain 32-bit DMA restriction Document the fact that atl1 uses a single shared register for the high 32 bits of 64-bit DMA addresses, making 64-bit DMA more trouble than it's worth. Signed-off-by: Chris Snook Signed-off-by: Jeff Garzik --- drivers/net/atl1/atl1_main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index e1a9223d0c18..4c728f1169c4 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -2209,8 +2209,14 @@ static int __devinit atl1_probe(struct pci_dev *pdev, return err; /* - * 64-bit DMA currently has data corruption problems, so let's just - * use 32-bit DMA for now. This is a big hack that is probably wrong. + * The atl1 chip can DMA to 64-bit addresses, but it uses a single + * shared register for the high 32 bits, so only a single, aligned, + * 4 GB physical address range can be used at a time. + * + * Supporting 64-bit DMA on this hardware is more trouble than it's + * worth. It is far easier to limit to 32-bit DMA than update + * various kernel subsystems to support the mechanics required by a + * fixed-high-32-bit system. */ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { From 7c32f470f4f6a0fdc6944cefcd22f288e59a0ae2 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Fri, 10 Aug 2007 14:05:16 -0700 Subject: [PATCH 1635/2804] PHY fixed driver: rework release path and update phy_id notation device_bind_driver() error code returning has been fixed. release() function has been written, so that to free resources in correct way; the release path is now clean. Before the rework, it used to cause Device 'fixed@100:1' does not have a release() function, it is broken and must be fixed. BUG: at drivers/base/core.c:104 device_release() Call Trace: [] kobject_cleanup+0x53/0x7e [] kobject_release+0x0/0x9 [] kref_put+0x74/0x81 [] fixed_mdio_register_device+0x230/0x265 [] fixed_init+0x1f/0x35 [] init+0x147/0x2fb [] schedule_tail+0x36/0x92 [] child_rip+0xa/0x12 [] acpi_ds_init_one_object+0x0/0x83 [] init+0x0/0x2fb [] child_rip+0x0/0x12 Also changed the notation of the fixed phy definition on mdio bus to the form of + to make it able to be used by gianfar and ucc_geth that define phy_id strictly as "%d:%d" and cleaned up the whitespace issues. Signed-off-by: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/Kconfig | 14 ++ drivers/net/phy/fixed.c | 310 +++++++++++++++++++------------------- include/linux/phy_fixed.h | 38 +++++ 3 files changed, 207 insertions(+), 155 deletions(-) create mode 100644 include/linux/phy_fixed.h diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index dd09011c7ee5..432c210513be 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -76,4 +76,18 @@ config FIXED_MII_100_FDX bool "Emulation for 100M Fdx fixed PHY behavior" depends on FIXED_PHY +config FIXED_MII_1000_FDX + bool "Emulation for 1000M Fdx fixed PHY behavior" + depends on FIXED_PHY + +config FIXED_MII_AMNT + int "Number of emulated PHYs to allocate " + depends on FIXED_PHY + default "1" + ---help--- + Sometimes it is required to have several independent emulated + PHYs on the bus (in case of multi-eth but phy-less HW for instance). + This control will have specified number allocated for each fixed + PHY type enabled. + endif # PHYLIB diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index bb966911a137..56191822fa26 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -30,53 +30,31 @@ #include #include #include +#include #include #include #include -#define MII_REGS_NUM 7 - -/* - The idea is to emulate normal phy behavior by responding with - pre-defined values to mii BMCR read, so that read_status hook could - take all the needed info. -*/ - -struct fixed_phy_status { - u8 link; - u16 speed; - u8 duplex; -}; - -/*----------------------------------------------------------------------------- - * Private information hoder for mii_bus - *-----------------------------------------------------------------------------*/ -struct fixed_info { - u16 *regs; - u8 regs_num; - struct fixed_phy_status phy_status; - struct phy_device *phydev; /* pointer to the container */ - /* link & speed cb */ - int(*link_update)(struct net_device*, struct fixed_phy_status*); - -}; +/* we need to track the allocated pointers in order to free them on exit */ +static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT]; /*----------------------------------------------------------------------------- * If something weird is required to be done with link/speed, * network driver is able to assign a function to implement this. * May be useful for PHY's that need to be software-driven. *-----------------------------------------------------------------------------*/ -int fixed_mdio_set_link_update(struct phy_device* phydev, - int(*link_update)(struct net_device*, struct fixed_phy_status*)) +int fixed_mdio_set_link_update(struct phy_device *phydev, + int (*link_update) (struct net_device *, + struct fixed_phy_status *)) { struct fixed_info *fixed; - if(link_update == NULL) + if (link_update == NULL) return -EINVAL; - if(phydev) { - if(phydev->bus) { + if (phydev) { + if (phydev->bus) { fixed = phydev->bus->priv; fixed->link_update = link_update; return 0; @@ -84,54 +62,64 @@ int fixed_mdio_set_link_update(struct phy_device* phydev, } return -EINVAL; } + EXPORT_SYMBOL(fixed_mdio_set_link_update); +struct fixed_info *fixed_mdio_get_phydev (int phydev_ind) +{ + if (phydev_ind >= MAX_PHY_AMNT) + return NULL; + return fixed_phy_ptrs[phydev_ind]; +} + +EXPORT_SYMBOL(fixed_mdio_get_phydev); + /*----------------------------------------------------------------------------- * This is used for updating internal mii regs from the status *-----------------------------------------------------------------------------*/ -#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) +#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX) static int fixed_mdio_update_regs(struct fixed_info *fixed) { u16 *regs = fixed->regs; u16 bmsr = 0; u16 bmcr = 0; - if(!regs) { + if (!regs) { printk(KERN_ERR "%s: regs not set up", __FUNCTION__); return -EINVAL; } - if(fixed->phy_status.link) + if (fixed->phy_status.link) bmsr |= BMSR_LSTATUS; - if(fixed->phy_status.duplex) { + if (fixed->phy_status.duplex) { bmcr |= BMCR_FULLDPLX; - switch ( fixed->phy_status.speed ) { + switch (fixed->phy_status.speed) { case 100: bmsr |= BMSR_100FULL; bmcr |= BMCR_SPEED100; - break; + break; case 10: bmsr |= BMSR_10FULL; - break; + break; } } else { - switch ( fixed->phy_status.speed ) { + switch (fixed->phy_status.speed) { case 100: bmsr |= BMSR_100HALF; bmcr |= BMCR_SPEED100; - break; + break; case 10: bmsr |= BMSR_100HALF; - break; + break; } } - regs[MII_BMCR] = bmcr; - regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/ + regs[MII_BMCR] = bmcr; + regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */ return 0; } @@ -141,29 +129,30 @@ static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location) struct fixed_info *fixed = bus->priv; /* if user has registered link update callback, use it */ - if(fixed->phydev) - if(fixed->phydev->attached_dev) { - if(fixed->link_update) { + if (fixed->phydev) + if (fixed->phydev->attached_dev) { + if (fixed->link_update) { fixed->link_update(fixed->phydev->attached_dev, - &fixed->phy_status); + &fixed->phy_status); fixed_mdio_update_regs(fixed); } - } + } if ((unsigned int)location >= fixed->regs_num) return -1; return fixed->regs[location]; } -static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) +static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, + u16 val) { - /* do nothing for now*/ + /* do nothing for now */ return 0; } static int fixed_mii_reset(struct mii_bus *bus) { - /*nothing here - no way/need to reset it*/ + /*nothing here - no way/need to reset it */ return 0; } #endif @@ -171,8 +160,8 @@ static int fixed_mii_reset(struct mii_bus *bus) static int fixed_config_aneg(struct phy_device *phydev) { /* :TODO:03/13/2006 09:45:37 PM:: - The full autoneg funcionality can be emulated, - but no need to have anything here for now + The full autoneg funcionality can be emulated, + but no need to have anything here for now */ return 0; } @@ -182,59 +171,79 @@ static int fixed_config_aneg(struct phy_device *phydev) * match will never return true... *-----------------------------------------------------------------------------*/ static struct phy_driver fixed_mdio_driver = { - .name = "Fixed PHY", - .features = PHY_BASIC_FEATURES, - .config_aneg = fixed_config_aneg, - .read_status = genphy_read_status, - .driver = { .owner = THIS_MODULE,}, + .name = "Fixed PHY", +#ifdef CONFIG_FIXED_MII_1000_FDX + .features = PHY_GBIT_FEATURES, +#else + .features = PHY_BASIC_FEATURES, +#endif + .config_aneg = fixed_config_aneg, + .read_status = genphy_read_status, + .driver = { .owner = THIS_MODULE, }, }; +static void fixed_mdio_release(struct device *dev) +{ + struct phy_device *phydev = container_of(dev, struct phy_device, dev); + struct mii_bus *bus = phydev->bus; + struct fixed_info *fixed = bus->priv; + + kfree(phydev); + kfree(bus->dev); + kfree(bus); + kfree(fixed->regs); + kfree(fixed); +} + /*----------------------------------------------------------------------------- * This func is used to create all the necessary stuff, bind * the fixed phy driver and register all it on the mdio_bus_type. - * speed is either 10 or 100, duplex is boolean. + * speed is either 10 or 100 or 1000, duplex is boolean. * number is used to create multiple fixed PHYs, so that several devices can * utilize them simultaneously. + * + * The device on mdio bus will look like [bus_id]:[phy_id], + * bus_id = number + * phy_id = speed+duplex. *-----------------------------------------------------------------------------*/ -#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) -static int fixed_mdio_register_device(int number, int speed, int duplex) +#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX) +struct fixed_info *fixed_mdio_register_device( + int bus_id, int speed, int duplex, u8 phy_id) { struct mii_bus *new_bus; struct fixed_info *fixed; struct phy_device *phydev; - int err = 0; + int err; - struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL); + struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; + if (dev == NULL) + goto err_dev_alloc; new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - if (NULL == new_bus) { - kfree(dev); - return -ENOMEM; - } + if (new_bus == NULL) + goto err_bus_alloc; + fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL); - if (NULL == fixed) { - kfree(dev); - kfree(new_bus); - return -ENOMEM; - } + if (fixed == NULL) + goto err_fixed_alloc; + + fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL); + if (NULL == fixed->regs) + goto err_fixed_regs_alloc; - fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL); fixed->regs_num = MII_REGS_NUM; fixed->phy_status.speed = speed; fixed->phy_status.duplex = duplex; fixed->phy_status.link = 1; - new_bus->name = "Fixed MII Bus", - new_bus->read = &fixed_mii_read, - new_bus->write = &fixed_mii_write, - new_bus->reset = &fixed_mii_reset, - - /*set up workspace*/ + new_bus->name = "Fixed MII Bus"; + new_bus->read = &fixed_mii_read; + new_bus->write = &fixed_mii_write; + new_bus->reset = &fixed_mii_reset; + /*set up workspace */ fixed_mdio_update_regs(fixed); new_bus->priv = fixed; @@ -243,119 +252,110 @@ static int fixed_mdio_register_device(int number, int speed, int duplex) /* create phy_device and register it on the mdio bus */ phydev = phy_device_create(new_bus, 0, 0); + if (phydev == NULL) + goto err_phy_dev_create; /* - Put the phydev pointer into the fixed pack so that bus read/write code could - be able to access for instance attached netdev. Well it doesn't have to do - so, only in case of utilizing user-specified link-update... + * Put the phydev pointer into the fixed pack so that bus read/write + * code could be able to access for instance attached netdev. Well it + * doesn't have to do so, only in case of utilizing user-specified + * link-update... */ - fixed->phydev = phydev; - if(NULL == phydev) { - err = -ENOMEM; - goto device_create_fail; - } + fixed->phydev = phydev; + phydev->speed = speed; + phydev->duplex = duplex; phydev->irq = PHY_IGNORE_INTERRUPT; phydev->dev.bus = &mdio_bus_type; - if(number) - snprintf(phydev->dev.bus_id, BUS_ID_SIZE, - "fixed_%d@%d:%d", number, speed, duplex); - else - snprintf(phydev->dev.bus_id, BUS_ID_SIZE, - "fixed@%d:%d", speed, duplex); + snprintf(phydev->dev.bus_id, BUS_ID_SIZE, + PHY_ID_FMT, bus_id, phy_id); + phydev->bus = new_bus; - err = device_register(&phydev->dev); - if(err) { - printk(KERN_ERR "Phy %s failed to register\n", - phydev->dev.bus_id); - goto bus_register_fail; - } - - /* - the mdio bus has phy_id match... In order not to do it - artificially, we are binding the driver here by hand; - it will be the same for all the fixed phys anyway. - */ phydev->dev.driver = &fixed_mdio_driver.driver; - + phydev->dev.release = fixed_mdio_release; err = phydev->dev.driver->probe(&phydev->dev); - if(err < 0) { - printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id); - goto probe_fail; + if (err < 0) { + printk(KERN_ERR "Phy %s: problems with fixed driver\n", + phydev->dev.bus_id); + goto err_out; } + err = device_register(&phydev->dev); + if (err) { + printk(KERN_ERR "Phy %s failed to register\n", + phydev->dev.bus_id); + goto err_out; + } + //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX + return fixed; - err = device_bind_driver(&phydev->dev); - if (err) - goto probe_fail; - - return 0; - -probe_fail: - device_unregister(&phydev->dev); -bus_register_fail: +err_out: kfree(phydev); -device_create_fail: - kfree(dev); - kfree(new_bus); +err_phy_dev_create: + kfree(fixed->regs); +err_fixed_regs_alloc: kfree(fixed); +err_fixed_alloc: + kfree(new_bus); +err_bus_alloc: + kfree(dev); +err_dev_alloc: + + return NULL; - return err; } #endif - MODULE_DESCRIPTION("Fixed PHY device & driver for PAL"); MODULE_AUTHOR("Vitaly Bordug"); MODULE_LICENSE("GPL"); static int __init fixed_init(void) { -#if 0 - int ret; - int duplex = 0; -#endif - - /* register on the bus... Not expected to be matched with anything there... */ + int cnt = 0; + int i; +/* register on the bus... Not expected to be matched + * with anything there... + * + */ phy_driver_register(&fixed_mdio_driver); - /* So let the fun begin... - We will create several mdio devices here, and will bound the upper - driver to them. - - Then the external software can lookup the phy bus by searching - fixed@speed:duplex, e.g. fixed@100:1, to be connected to the - virtual 100M Fdx phy. - - In case several virtual PHYs required, the bus_id will be in form - fixed_@:, which make it able even to define - driver-specific link control callback, if for instance PHY is completely - SW-driven. - - */ - -#ifdef CONFIG_FIXED_MII_DUPLEX -#if 0 - duplex = 1; +/* We will create several mdio devices here, and will bound the upper + * driver to them. + * + * Then the external software can lookup the phy bus by searching + * for 0:101, to be connected to the virtual 100M Fdx phy. + * + * In case several virtual PHYs required, the bus_id will be in form + * [num]:[duplex]+[speed], which make it able even to define + * driver-specific link control callback, if for instance PHY is + * completely SW-driven. + */ + for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) { +#ifdef CONFIG_FIXED_MII_1000_FDX + fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i); #endif -#endif - #ifdef CONFIG_FIXED_MII_100_FDX - fixed_mdio_register_device(0, 100, 1); + fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i); #endif - #ifdef CONFIG_FIXED_MII_10_FDX - fixed_mdio_register_device(0, 10, 1); + fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i); #endif + } + return 0; } static void __exit fixed_exit(void) { + int i; + phy_driver_unregister(&fixed_mdio_driver); - /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */ + for (i=0; i < MAX_PHY_AMNT; i++) + if ( fixed_phy_ptrs[i] ) + device_unregister(&fixed_phy_ptrs[i]->phydev->dev); } module_init(fixed_init); diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h new file mode 100644 index 000000000000..04ba70d49fb8 --- /dev/null +++ b/include/linux/phy_fixed.h @@ -0,0 +1,38 @@ +#ifndef __PHY_FIXED_H +#define __PHY_FIXED_H + +#define MII_REGS_NUM 29 + +/* max number of virtual phy stuff */ +#define MAX_PHY_AMNT 10 +/* + The idea is to emulate normal phy behavior by responding with + pre-defined values to mii BMCR read, so that read_status hook could + take all the needed info. +*/ + +struct fixed_phy_status { + u8 link; + u16 speed; + u8 duplex; +}; + +/*----------------------------------------------------------------------------- + * Private information hoder for mii_bus + *-----------------------------------------------------------------------------*/ +struct fixed_info { + u16 *regs; + u8 regs_num; + struct fixed_phy_status phy_status; + struct phy_device *phydev; /* pointer to the container */ + /* link & speed cb */ + int (*link_update) (struct net_device *, struct fixed_phy_status *); + +}; + + +int fixed_mdio_set_link_update(struct phy_device *, + int (*link_update) (struct net_device *, struct fixed_phy_status *)); +struct fixed_info *fixed_mdio_get_phydev (int phydev_ind); + +#endif /* __PHY_FIXED_H */ From 007755eb86c3953bb8615bd016246fc99056580c Mon Sep 17 00:00:00 2001 From: Peter Oruba Date: Fri, 28 Sep 2007 22:42:06 -0700 Subject: [PATCH 1636/2804] PCI-X/PCI-Express read control interfaces: use them in e1000 These driver changes incorporate the proposed PCI-X / PCI-Express read byte count interface. Reading and setting those valuse doesn't take place "manually", instead wrapping functions are called to allow quirks for some PCI bridges. Signed-off by: Peter Oruba Based on work by Stephen Hemminger Acked-by: Auke Kok Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 25 +++---------------------- drivers/net/e1000/e1000_hw.h | 2 ++ drivers/net/e1000/e1000_main.c | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 8604adbe351c..8fa0fe4009d5 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -871,10 +871,6 @@ e1000_init_hw(struct e1000_hw *hw) uint32_t ctrl; uint32_t i; int32_t ret_val; - uint16_t pcix_cmd_word; - uint16_t pcix_stat_hi_word; - uint16_t cmd_mmrbc; - uint16_t stat_mmrbc; uint32_t mta_size; uint32_t reg_data; uint32_t ctrl_ext; @@ -964,24 +960,9 @@ e1000_init_hw(struct e1000_hw *hw) break; default: /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */ - if (hw->bus_type == e1000_bus_type_pcix) { - e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word); - e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, - &pcix_stat_hi_word); - cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >> - PCIX_COMMAND_MMRBC_SHIFT; - stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >> - PCIX_STATUS_HI_MMRBC_SHIFT; - if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) - stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K; - if (cmd_mmrbc > stat_mmrbc) { - pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK; - pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; - e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, - &pcix_cmd_word); - } - } - break; + if (hw->bus_type == e1000_bus_type_pcix && e1000_pcix_get_mmrbc(hw) > 2048) + e1000_pcix_set_mmrbc(hw, 2048); + break; } /* More time needed for PHY to initialize */ diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 07f0ea73676e..a2a86c54a75c 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -424,6 +424,8 @@ void e1000_pci_clear_mwi(struct e1000_hw *hw); void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value); +void e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc); +int e1000_pcix_get_mmrbc(struct e1000_hw *hw); /* Port I/O is only supported on 82544 and newer */ void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); int32_t e1000_disable_pciex_master(struct e1000_hw *hw); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ad444c9a5d04..10505de00bcc 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4903,6 +4903,20 @@ e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) pci_write_config_word(adapter->pdev, reg, *value); } +int +e1000_pcix_get_mmrbc(struct e1000_hw *hw) +{ + struct e1000_adapter *adapter = hw->back; + return pcix_get_mmrbc(adapter->pdev); +} + +void +e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc) +{ + struct e1000_adapter *adapter = hw->back; + pcix_set_mmrbc(adapter->pdev, mmrbc); +} + int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) { From 0da18e3883d18ac716ad8cc07df9bd30933807ac Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 28 Sep 2007 22:42:06 -0700 Subject: [PATCH 1637/2804] drivers/net/cxgb3/xgmac.c: remove dead code This patch removes dead code ("tx_xcnt" can never be != 0 at this place) spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/xgmac.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index ff9e9dcbd87d..bcb5bc4e649b 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -522,10 +522,7 @@ int t3b2_mac_watchdog_task(struct cmac *mac) goto rxcheck; } - if (((tx_tcnt != mac->tx_tcnt) && - (tx_xcnt == 0) && (mac->tx_xcnt == 0)) || - ((mac->tx_mcnt == tx_mcnt) && - (tx_xcnt != 0) && (mac->tx_xcnt != 0))) { + if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { if (mac->toggle_cnt > 4) { status = 2; goto out; From bcfef8c3681fa59b653871682956a8fdf5c27c5a Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 28 Sep 2007 22:42:09 -0700 Subject: [PATCH 1638/2804] Avoid possible NULL pointer deref in 3c359 driver In xl_freemem(), if dev_if is NULL, the line struct xl_private *xl_priv =(struct xl_private *)dev->priv; will cause a NULL pointer dereference. (akpm: don't try to fix it: just delete the pointless test-for-null) Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tokenring/3c359.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 88d03c085d54..7224d368b2a7 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1045,11 +1045,6 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id) u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u16 intstatus, macstatus ; - if (!dev) { - printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ; - return IRQ_NONE; - } - intstatus = readw(xl_mmio + MMIO_INTSTATUS) ; if (!(intstatus & 1)) /* We didn't generate the interrupt */ From 13f7b8c011cd8d16ad3063409b9d969466c9e2f4 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 28 Sep 2007 22:42:10 -0700 Subject: [PATCH 1639/2804] skge: remove broken and unused PHY_M_PC_MDI_XMODE macro Signed-off-by: Mariusz Kozlowski Cc: Stephen Hemminger Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/skge.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/skge.h b/drivers/net/skge.h index dd0fd45c7155..1a57bdd1ddf1 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -1351,8 +1351,6 @@ enum { PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */ }; -#define PHY_M_PC_MDI_XMODE(x) ((((u16)(x)<<5) & PHY_M_PC_MDIX_MSK) - enum { PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */ PHY_M_PC_MAN_MDIX = 1, /* 01 = Manual MDIX configuration */ From 1f8f4559f8c5829348a010a9e0bbb423310060d1 Mon Sep 17 00:00:00 2001 From: Micah Gruber Date: Fri, 28 Sep 2007 22:42:11 -0700 Subject: [PATCH 1640/2804] Fix a potential NULL pointer dereference in uli526x_interrupt() in drivers/net/tulip/uli526x.c This patch fixes an apparent potential null dereference bug where we dereference dev before a null check. This patch simply remvoes the can't-happen test for a null pointer. Signed-off-by: Micah Gruber Cc: Grant Grundler Acked-by: Jeff Garzik Acked-by: Kyle McMartin Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tulip/uli526x.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index e64bde46822e..76e55612430b 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -664,11 +664,6 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id) unsigned long ioaddr = dev->base_addr; unsigned long flags; - if (!dev) { - ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0); - return IRQ_NONE; - } - spin_lock_irqsave(&db->lock, flags); outl(0, ioaddr + DCR7); From 9ff8c68b3c722f732c7a13d6631b149cca8c7091 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 28 Sep 2007 22:42:12 -0700 Subject: [PATCH 1641/2804] PHYLIB: Spinlock fixes for softirqs Use spin_lock_bh()/spin_unlock_bh() for the phydev lock throughout as it is used in phy_timer() that is called as a softirq and all the other operations may happen in the user context. There has been a change recently that did such a conversion for some of the operations on the lock, but some have been left intact. Many of them, perhaps all, may be called in the user context and I was able to trigger recursive spinlock acquisition indeed, so I think for the sake of long-term maintenance it is best to convert them all, even if unnecessarily for one or two -- better safe than sorry. Perhaps one in phy_timer() could actually be skipped as only called as a softirq -- I can send an update if that sounds like a good idea. Checked with checkpatch.pl and at the runtime. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/phy.c | 24 ++++++++++++------------ drivers/net/phy/phy_device.c | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 17c1e1555d80..4da993dfcfd8 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -424,7 +424,7 @@ int phy_start_aneg(struct phy_device *phydev) { int err; - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if (AUTONEG_DISABLE == phydev->autoneg) phy_sanitize_settings(phydev); @@ -445,7 +445,7 @@ int phy_start_aneg(struct phy_device *phydev) } out_unlock: - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); return err; } EXPORT_SYMBOL(phy_start_aneg); @@ -490,10 +490,10 @@ void phy_stop_machine(struct phy_device *phydev) { del_timer_sync(&phydev->phy_timer); - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if (phydev->state > PHY_UP) phydev->state = PHY_UP; - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); phydev->adjust_state = NULL; } @@ -537,9 +537,9 @@ static void phy_force_reduction(struct phy_device *phydev) */ void phy_error(struct phy_device *phydev) { - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); phydev->state = PHY_HALTED; - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); } /** @@ -690,10 +690,10 @@ static void phy_change(struct work_struct *work) if (err) goto phy_err; - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) phydev->state = PHY_CHANGELINK; - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); enable_irq(phydev->irq); @@ -718,7 +718,7 @@ phy_err: */ void phy_stop(struct phy_device *phydev) { - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if (PHY_HALTED == phydev->state) goto out_unlock; @@ -734,7 +734,7 @@ void phy_stop(struct phy_device *phydev) } out_unlock: - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); /* * Cannot call flush_scheduled_work() here as desired because @@ -782,7 +782,7 @@ static void phy_timer(unsigned long data) int needs_aneg = 0; int err = 0; - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if (phydev->adjust_state) phydev->adjust_state(phydev->attached_dev); @@ -948,7 +948,7 @@ static void phy_timer(unsigned long data) break; } - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); if (needs_aneg) err = phy_start_aneg(phydev); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 49328e050505..c0461217b108 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -670,9 +670,9 @@ static int phy_remove(struct device *dev) phydev = to_phy_device(dev); - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); phydev->state = PHY_DOWN; - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); if (phydev->drv->remove) phydev->drv->remove(phydev); From f7ab697d328b0a417d9e3cb891d45693ea89e83d Mon Sep 17 00:00:00 2001 From: Ed Swierk Date: Fri, 28 Sep 2007 22:42:13 -0700 Subject: [PATCH 1642/2804] forcedeth: "no link" is informational Log "no link during initialization" at KERN_INFO as it's not an error, and occurs every time the interface comes up (when the forcedeth-phy-power-down patch is applied). Signed-off-by: Ed Swierk Cc: Ayaz Abdulla Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 666de42e5a76..dae30b731342 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4917,7 +4917,7 @@ static int nv_open(struct net_device *dev) if (ret) { netif_carrier_on(dev); } else { - printk("%s: no link during initialization.\n", dev->name); + printk(KERN_INFO "%s: no link during initialization.\n", dev->name); netif_carrier_off(dev); } if (oom) From 0ac49527318bc388a881152d60f49d7951606024 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 28 Sep 2007 22:42:14 -0700 Subject: [PATCH 1643/2804] PHYLIB: IRQ event workqueue handling fixes Keep track of disable_irq_nosync() invocations and call enable_irq() the right number of times if work has been cancelled that would include them. Now that the call to flush_work_keventd() (problematic because of rtnl_mutex being held) has been replaced by cancel_work_sync() another issue has arisen and been left unresolved. As the MDIO bus cannot be accessed from the interrupt context the PHY interrupt handler uses disable_irq_nosync() to prevent from looping and schedules some work to be done as a softirq, which, apart from handling the state change of the originating PHY, is responsible for reenabling the interrupt. Now if the interrupt line is shared by another device and a call to the softirq handler has been cancelled, that call to enable_irq() never happens and the other device cannot use its interrupt anymore as its stuck disabled. I decided to use a counter rather than a flag because there may be more than one call to phy_change() cancelled in the queue -- a real one and a fake one triggered by free_irq() if DEBUG_SHIRQ is used, if nothing else. Therefore because of its nesting property enable_irq() has to be called the right number of times to match the number disable_irq_nosync() was called and restore the original state. This DEBUG_SHIRQ feature is also the reason why free_irq() has to be called before cancel_work_sync(). While at it I updated the comment about phy_stop_interrupts() being called from `keventd' -- this is no longer relevant as the use of cancel_work_sync() makes such an approach unnecessary. OTOH a similar comment referring to flush_scheduled_work() in phy_stop() still applies as using cancel_work_sync() there would be dangerous. Checked with checkpatch.pl and at the run time (with and without DEBUG_SHIRQ). Signed-off-by: Maciej W. Rozycki Cc: Andy Fleming Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/phy.c | 24 +++++++++++++++++++----- include/linux/phy.h | 3 +++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 4da993dfcfd8..5a314edc2744 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -7,7 +7,7 @@ * Author: Andy Fleming * * Copyright (c) 2004 Freescale Semiconductor, Inc. - * Copyright (c) 2006 Maciej W. Rozycki + * Copyright (c) 2006, 2007 Maciej W. Rozycki * * 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 @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -562,6 +563,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) * queue will write the PHY to disable and clear the * interrupt, and then reenable the irq line. */ disable_irq_nosync(irq); + atomic_inc(&phydev->irq_disable); schedule_work(&phydev->phy_queue); @@ -632,6 +634,7 @@ int phy_start_interrupts(struct phy_device *phydev) INIT_WORK(&phydev->phy_queue, phy_change); + atomic_set(&phydev->irq_disable, 0); if (request_irq(phydev->irq, phy_interrupt, IRQF_SHARED, "phy_interrupt", @@ -662,13 +665,22 @@ int phy_stop_interrupts(struct phy_device *phydev) if (err) phy_error(phydev); + free_irq(phydev->irq, phydev); + /* - * Finish any pending work; we might have been scheduled to be called - * from keventd ourselves, but cancel_work_sync() handles that. + * Cannot call flush_scheduled_work() here as desired because + * of rtnl_lock(), but we do not really care about what would + * be done, except from enable_irq(), so cancel any work + * possibly pending and take care of the matter below. */ cancel_work_sync(&phydev->phy_queue); - - free_irq(phydev->irq, phydev); + /* + * If work indeed has been cancelled, disable_irq() will have + * been left unbalanced from phy_interrupt() and enable_irq() + * has to be called so that other devices on the line work. + */ + while (atomic_dec_return(&phydev->irq_disable) >= 0) + enable_irq(phydev->irq); return err; } @@ -695,6 +707,7 @@ static void phy_change(struct work_struct *work) phydev->state = PHY_CHANGELINK; spin_unlock_bh(&phydev->lock); + atomic_dec(&phydev->irq_disable); enable_irq(phydev->irq); /* Reenable interrupts */ @@ -708,6 +721,7 @@ static void phy_change(struct work_struct *work) irq_enable_err: disable_irq(phydev->irq); + atomic_inc(&phydev->irq_disable); phy_err: phy_error(phydev); } diff --git a/include/linux/phy.h b/include/linux/phy.h index 2a659789f9ca..f0742b6aaa64 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -25,6 +25,8 @@ #include #include +#include + #define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ SUPPORTED_10baseT_Full | \ SUPPORTED_100baseT_Half | \ @@ -281,6 +283,7 @@ struct phy_device { /* Interrupt and Polling infrastructure */ struct work_struct phy_queue; struct timer_list phy_timer; + atomic_t irq_disable; spinlock_t lock; From 6daf65310374d24d888201b7a6eba90b44008b7b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 28 Sep 2007 22:42:15 -0700 Subject: [PATCH 1644/2804] PHYLIB: fix an interrupt loop potential when halting Ensure the PHY_HALTED state is not entered with the IRQ asserted as it could lead to an interrupt loop. There is a small window in phy_stop(), where the state of the PHY machine indicates it has been halted, but its interrupt output might still be unmasked. If an interrupt goes active right at this moment it will loop as the phy_interrupt() handler exits immediately with IRQ_NONE if the halted state is seen. It is unsafe to extend the phydev spinlock to cover phy_interrupt(). It is safe to swap the order of the actions though as all the competing places to unmask the interrupt output of the PHY, which are phy_change() and phy_timer() are already covered with the lock as is the sequence in question. Signed-off-by: Maciej W. Rozycki Cc: Andy Fleming Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 5a314edc2744..9bc11773705b 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -737,8 +737,6 @@ void phy_stop(struct phy_device *phydev) if (PHY_HALTED == phydev->state) goto out_unlock; - phydev->state = PHY_HALTED; - if (phydev->irq != PHY_POLL) { /* Disable PHY Interrupts */ phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); @@ -747,6 +745,8 @@ void phy_stop(struct phy_device *phydev) phy_clear_interrupt(phydev); } + phydev->state = PHY_HALTED; + out_unlock: spin_unlock_bh(&phydev->lock); From 89e536a190f90d038bae7905a0c582cb7089b739 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Fri, 28 Sep 2007 22:42:16 -0700 Subject: [PATCH 1645/2804] ax88796: add 93cx6 eeprom support Hook up the 93cx6 eeprom code to the ax88796 driver and modify the ax88796 driver to read out the mac address from the eeprom. We need this for the ax88796 on certain SuperH boards. The pin configuration used to connect the eeprom to the ax88796 on these boards is the same as pointed out by the ax88796 datasheet, so we can probably reuse this code for multiple platforms in the future. Signed-off-by: Magnus Damm Cc: Ben Dooks Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 7 ++++++ drivers/net/ax88796.c | 49 ++++++++++++++++++++++++++++++++++++ include/linux/eeprom_93cx6.h | 3 ++- include/net/ax88796.h | 1 + 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9ff1cf46eaee..45f6cf531566 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -240,6 +240,13 @@ config AX88796 AX88796 driver, using platform bus to provide chip detection and resources +config AX88796_93CX6 + bool "ASIX AX88796 external 93CX6 eeprom support" + depends on AX88796 + select EEPROM_93CX6 + help + Select this if your platform comes with an external 93CX6 eeprom. + config MACE tristate "MACE (Power Mac ethernet) support" depends on PPC_PMAC && PPC32 diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index 90e0734e6037..9fe0517cf893 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -582,6 +583,37 @@ static const struct ethtool_ops ax_ethtool_ops = { .get_link = ax_get_link, }; +#ifdef CONFIG_AX88796_93CX6 +static void ax_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct ei_device *ei_local = eeprom->data; + u8 reg = ei_inb(ei_local->mem + AX_MEMR); + + eeprom->reg_data_in = reg & AX_MEMR_EEI; + eeprom->reg_data_out = reg & AX_MEMR_EEO; /* Input pin */ + eeprom->reg_data_clock = reg & AX_MEMR_EECLK; + eeprom->reg_chip_select = reg & AX_MEMR_EECS; +} + +static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct ei_device *ei_local = eeprom->data; + u8 reg = ei_inb(ei_local->mem + AX_MEMR); + + reg &= ~(AX_MEMR_EEI | AX_MEMR_EECLK | AX_MEMR_EECS); + + if (eeprom->reg_data_in) + reg |= AX_MEMR_EEI; + if (eeprom->reg_data_clock) + reg |= AX_MEMR_EECLK; + if (eeprom->reg_chip_select) + reg |= AX_MEMR_EECS; + + ei_outb(reg, ei_local->mem + AX_MEMR); + udelay(10); +} +#endif + /* setup code */ static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local) @@ -640,6 +672,23 @@ static int ax_init_dev(struct net_device *dev, int first_init) memcpy(dev->dev_addr, SA_prom, 6); } +#ifdef CONFIG_AX88796_93CX6 + if (first_init && ax->plat->flags & AXFLG_HAS_93CX6) { + unsigned char mac_addr[6]; + struct eeprom_93cx6 eeprom; + + eeprom.data = ei_local; + eeprom.register_read = ax_eeprom_register_read; + eeprom.register_write = ax_eeprom_register_write; + eeprom.width = PCI_EEPROM_WIDTH_93C56; + + eeprom_93cx6_multiread(&eeprom, 0, + (__le16 __force *)mac_addr, + sizeof(mac_addr) >> 1); + + memcpy(dev->dev_addr, mac_addr, 6); + } +#endif if (ax->plat->wordlength == 2) { /* We must set the 8390 for word mode. */ ei_outb(ax->plat->dcr_val, ei_local->mem + EN0_DCFG); diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h index d774b7778c91..a55c873e8b66 100644 --- a/include/linux/eeprom_93cx6.h +++ b/include/linux/eeprom_93cx6.h @@ -21,13 +21,14 @@ /* Module: eeprom_93cx6 Abstract: EEPROM reader datastructures for 93cx6 chipsets. - Supported chipsets: 93c46 & 93c66. + Supported chipsets: 93c46, 93c56 and 93c66. */ /* * EEPROM operation defines. */ #define PCI_EEPROM_WIDTH_93C46 6 +#define PCI_EEPROM_WIDTH_93C56 8 #define PCI_EEPROM_WIDTH_93C66 8 #define PCI_EEPROM_WIDTH_OPCODE 3 #define PCI_EEPROM_WRITE_OPCODE 0x05 diff --git a/include/net/ax88796.h b/include/net/ax88796.h index ee786a043b3d..51329dae44e6 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -14,6 +14,7 @@ #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ +#define AXFLG_HAS_93CX6 (1<<2) /* use eeprom_93cx6 driver */ struct ax_plat_data { unsigned int flags; From b3448b0bde5f1a858397fe791f76632e978a1dc8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 Sep 2007 17:55:51 -0700 Subject: [PATCH 1646/2804] [BNX2]: factor out gzip unpacker This patch modifies gzip unpacking code in bnx2 driver so that it does not depend on bnx2 internals. I will move this code out of the driver and into zlib in follow-on patch. It can be useful in other drivers which need to store firmwares or any other relatively big binary blobs - fonts, cursor bitmaps, whatever. Patch is run tested by Michael Chan (driver author). Signed-off-by: Denys Vlasenko Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 160 +++++++++++++++-------------------------- drivers/net/bnx2.h | 5 +- drivers/net/bnx2_fw.h | 28 +++++--- drivers/net/bnx2_fw2.h | 15 ++-- 4 files changed, 86 insertions(+), 122 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 57f7d994c9c1..73d4a579790c 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -52,6 +52,8 @@ #include "bnx2_fw.h" #include "bnx2_fw2.h" +#define FW_BUF_SIZE 0x8000 + #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " #define DRV_MODULE_VERSION "1.6.5" @@ -2759,89 +2761,45 @@ bnx2_set_rx_mode(struct net_device *dev) spin_unlock_bh(&bp->phy_lock); } -#define FW_BUF_SIZE 0x8000 - +/* To be moved to generic lib/ */ static int -bnx2_gunzip_init(struct bnx2 *bp) +bnx2_gunzip(void *gunzip_buf, unsigned sz, u8 *zbuf, int len) { - if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL) - goto gunzip_nomem1; + struct z_stream_s *strm; + int rc; - if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL) + /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) + * is stripped */ + + rc = -ENOMEM; + strm = kmalloc(sizeof(*strm), GFP_KERNEL); + if (strm == NULL) goto gunzip_nomem2; - - bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (bp->strm->workspace == NULL) + strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (strm->workspace == NULL) goto gunzip_nomem3; - return 0; + strm->next_in = zbuf; + strm->avail_in = len; + strm->next_out = gunzip_buf; + strm->avail_out = sz; + rc = zlib_inflateInit2(strm, -MAX_WBITS); + if (rc == Z_OK) { + rc = zlib_inflate(strm, Z_FINISH); + /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ + if (rc == Z_STREAM_END) + rc = sz - strm->avail_out; + else + rc = -EINVAL; + zlib_inflateEnd(strm); + } else + rc = -EINVAL; + + kfree(strm->workspace); gunzip_nomem3: - kfree(bp->strm); - bp->strm = NULL; - + kfree(strm); gunzip_nomem2: - vfree(bp->gunzip_buf); - bp->gunzip_buf = NULL; - -gunzip_nomem1: - printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for " - "uncompression.\n", bp->dev->name); - return -ENOMEM; -} - -static void -bnx2_gunzip_end(struct bnx2 *bp) -{ - kfree(bp->strm->workspace); - - kfree(bp->strm); - bp->strm = NULL; - - if (bp->gunzip_buf) { - vfree(bp->gunzip_buf); - bp->gunzip_buf = NULL; - } -} - -static int -bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen) -{ - int n, rc; - - /* check gzip header */ - if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) - return -EINVAL; - - n = 10; - -#define FNAME 0x8 - if (zbuf[3] & FNAME) - while ((zbuf[n++] != 0) && (n < len)); - - bp->strm->next_in = zbuf + n; - bp->strm->avail_in = len - n; - bp->strm->next_out = bp->gunzip_buf; - bp->strm->avail_out = FW_BUF_SIZE; - - rc = zlib_inflateInit2(bp->strm, -MAX_WBITS); - if (rc != Z_OK) - return rc; - - rc = zlib_inflate(bp->strm, Z_FINISH); - - *outlen = FW_BUF_SIZE - bp->strm->avail_out; - *outbuf = bp->gunzip_buf; - - if ((rc != Z_OK) && (rc != Z_STREAM_END)) - printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n", - bp->dev->name, bp->strm->msg); - - zlib_inflateEnd(bp->strm); - - if (rc == Z_STREAM_END) - return 0; - return rc; } @@ -2894,22 +2852,21 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) /* Load the Text area. */ offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base); if (fw->gz_text) { - u32 text_len; - void *text; - - rc = bnx2_gunzip(bp, fw->gz_text, fw->gz_text_len, &text, - &text_len); - if (rc) - return rc; - - fw->text = text; - } - if (fw->gz_text) { + u32 *text; int j; + text = vmalloc(FW_BUF_SIZE); + if (!text) + return -ENOMEM; + rc = bnx2_gunzip(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len); + if (rc < 0) { + vfree(text); + return rc; + } for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { - REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j])); + REG_WR_IND(bp, offset, cpu_to_le32(text[j])); } + vfree(text); } /* Load the Data area. */ @@ -2971,27 +2928,27 @@ bnx2_init_cpus(struct bnx2 *bp) { struct cpu_reg cpu_reg; struct fw_info *fw; - int rc = 0; + int rc; void *text; - u32 text_len; - - if ((rc = bnx2_gunzip_init(bp)) != 0) - return rc; /* Initialize the RV2P processor. */ - rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text, - &text_len); - if (rc) + text = vmalloc(FW_BUF_SIZE); + if (!text) + return -ENOMEM; + rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); + if (rc < 0) { + vfree(text); goto init_cpu_err; + } + load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1); - load_rv2p_fw(bp, text, text_len, RV2P_PROC1); - - rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text, - &text_len); - if (rc) + rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); + if (rc < 0) { + vfree(text); goto init_cpu_err; - - load_rv2p_fw(bp, text, text_len, RV2P_PROC2); + } + load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2); + vfree(text); /* Initialize the RX Processor. */ cpu_reg.mode = BNX2_RXP_CPU_MODE; @@ -3107,7 +3064,6 @@ bnx2_init_cpus(struct bnx2 *bp) goto init_cpu_err; } init_cpu_err: - bnx2_gunzip_end(bp); return rc; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index fbae439db647..a717459cc8d4 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6681,9 +6681,6 @@ struct bnx2 { u32 flash_size; int status_stats_size; - - struct z_stream_s *strm; - void *gunzip_buf; }; static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset); @@ -6741,7 +6738,7 @@ struct fw_info { const u32 text_addr; const u32 text_len; const u32 text_index; - u32 *text; +/* u32 *text;*/ u8 *gz_text; const u32 gz_text_len; diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index b49f439e0f67..30f2f4052fc1 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -15,7 +15,8 @@ */ static u8 bnx2_COM_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5a, +/* 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, */ + 0xdc, 0x5a, 0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15, 0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96, 0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1, @@ -1085,8 +1086,9 @@ static struct fw_info bnx2_com_fw_06 = { }; static u8 bnx2_RXP_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5c, 0x6f, 0x6c, +/* 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xec, 0x5c, 0x6f, 0x6c, 0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x4e, 0xd4, 0x91, 0x5c, 0x1e, 0x4f, 0xf4, 0x49, 0x66, 0x94, 0x5d, 0x71, 0x25, 0x5e, 0x2d, 0xc6, 0x5d, 0x31, 0x57, 0x9b, 0x08, 0xce, 0xf1, 0x79, 0xef, 0x64, 0xb1, 0x86, 0x0a, @@ -1798,8 +1800,9 @@ static struct fw_info bnx2_rxp_fw_06 = { }; static u8 bnx2_rv2p_proc1[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x56, 0xcf, 0x6b, +/* 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xc5, 0x56, 0xcf, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xec, 0x6e, 0xb2, 0xdb, 0x74, 0xbb, 0x1b, 0x2b, 0xda, 0xa0, 0xb1, 0x8d, 0x51, 0x6a, 0x7f, 0xa4, 0xb4, 0x11, 0x0f, 0x82, 0x42, 0x25, 0x3d, 0x04, 0x54, 0x44, 0x7a, 0x28, 0x22, 0x82, 0x36, 0x8a, @@ -1877,8 +1880,9 @@ static u8 bnx2_rv2p_proc1[] = { 0x12, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00 }; static u8 bnx2_rv2p_proc2[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x58, 0x5b, 0x6c, +/* 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xcd, 0x58, 0x5b, 0x6c, 0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0x9d, 0xe9, 0xed, 0x9d, 0xf2, 0xb2, 0x03, 0xad, 0x08, 0xe5, 0xd1, 0x56, 0x29, 0xe8, 0x54, 0xab, 0x18, 0x15, 0x2c, 0x5a, 0x8c, 0x26, 0x68, 0xf0, 0xf9, 0x63, 0x14, 0x04, 0xda, @@ -2057,8 +2061,9 @@ static u8 bnx2_rv2p_proc2[] = { 0x17, 0x00, 0x00, 0x00 }; static u8 bnx2_TPAT_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x57, 0x4d, 0x68, +/* 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xc5, 0x57, 0x4d, 0x68, 0x1c, 0xe7, 0x19, 0x7e, 0xe7, 0x77, 0x47, 0x62, 0x25, 0x8d, 0x93, 0x3d, 0xac, 0x5d, 0xa5, 0x99, 0x91, 0x46, 0x3f, 0x54, 0x26, 0x9e, 0x84, 0xa5, 0x56, 0x61, 0x20, 0xe3, 0x99, 0x95, 0x2c, 0x0c, 0x05, 0x07, 0x42, 0x08, @@ -2290,8 +2295,9 @@ static struct fw_info bnx2_tpat_fw_06 = { }; static u8 bnx2_TXP_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xed, 0x5c, 0x6d, 0x6c, +/* 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xed, 0x5c, 0x6d, 0x6c, 0x1b, 0xf7, 0x79, 0x7f, 0xee, 0x85, 0xd2, 0x51, 0x96, 0xe9, 0x93, 0xc2, 0x78, 0x6c, 0xc0, 0xa6, 0x77, 0xd6, 0x51, 0x66, 0x20, 0xb5, 0xa0, 0x05, 0x36, 0x55, 0x87, 0x43, 0x73, 0x3e, 0x52, 0x2f, 0x4e, 0x5c, 0x57, 0x71, diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h index 2c067531f031..74f985d8fac7 100644 --- a/drivers/net/bnx2_fw2.h +++ b/drivers/net/bnx2_fw2.h @@ -15,7 +15,8 @@ */ static u8 bnx2_COM_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5b, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xdc, 0x5b, 0x6d, 0x70, 0x5c, 0xd5, 0x79, 0x7e, 0xef, 0xd9, 0xbb, 0xf2, 0x5a, 0x92, 0xe5, 0x6b, 0x79, 0x23, 0x16, 0x4b, 0xc0, 0xae, 0x75, 0x6d, 0x69, 0xb0, 0x43, 0x16, 0xa1, 0x80, 0x9a, 0xd9, 0xc0, 0xb2, 0x2b, 0x33, 0x9e, 0x0c, @@ -1083,7 +1084,8 @@ static struct fw_info bnx2_com_fw_09 = { }; static u8 bnx2_CP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xbd, 0x7d, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xbd, 0x7d, 0x0d, 0x74, 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x19, 0x49, 0x63, 0x59, 0x96, 0x9f, 0xe5, 0x89, 0x32, 0x51, 0x84, 0x3d, 0x23, 0x3d, 0xd9, 0x22, 0x12, 0xe1, 0xc5, 0x11, 0xac, 0xda, 0x2a, 0xe9, 0x30, 0x92, 0x3f, 0x12, @@ -2279,7 +2281,8 @@ static struct fw_info bnx2_cp_fw_09 = { }; static u8 bnx2_RXP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xec, 0x5c, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xec, 0x5c, 0x5d, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x6a, 0x49, 0xf1, 0x67, 0xb8, 0x5c, 0xb1, 0x2b, 0x99, 0x96, 0x77, 0xc9, 0x91, 0xc8, 0x58, 0x8a, 0x31, 0xa2, 0x09, 0x5b, 0x48, 0x17, 0xf6, 0x76, 0x76, 0x25, 0xb1, 0xb1, @@ -2988,7 +2991,8 @@ static struct fw_info bnx2_rxp_fw_09 = { }; static u8 bnx2_TPAT_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x58, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xcd, 0x58, 0x5d, 0x68, 0x1c, 0xd7, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0x52, 0x24, 0xeb, 0x5a, 0xd9, 0xa6, 0xeb, 0xa0, 0x34, 0x33, 0xda, 0x91, 0xac, 0x22, 0x13, 0x4f, 0x9d, 0x25, 0x16, 0x65, 0x21, 0x93, 0xd9, 0x91, 0xac, 0x98, 0x3c, @@ -3279,7 +3283,8 @@ static struct fw_info bnx2_tpat_fw_09 = { }; static u8 bnx2_TXP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x7c, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xcd, 0x7c, 0x6f, 0x70, 0x5b, 0xd7, 0x95, 0xdf, 0x79, 0xef, 0x81, 0x24, 0x48, 0xd1, 0xd4, 0x13, 0x17, 0x56, 0x60, 0x87, 0x71, 0x00, 0xf1, 0x81, 0x66, 0x42, 0xae, 0x04, 0x2b, 0x4c, 0xc2, 0x6d, 0xd1, 0xf8, 0x05, 0x00, 0x29, 0x48, From 8336793baf962163c9fab5a3f39614295fdbab27 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 Sep 2007 17:56:49 -0700 Subject: [PATCH 1647/2804] [ZLIB]: Move bnx2 driver gzip unpacker into zlib. Signed-off-by: Denys Vlasenko Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 48 ++-------------------------- include/linux/zlib.h | 6 +++- lib/zlib_inflate/inffast.c | 18 +++++------ lib/zlib_inflate/inflate.c | 55 ++++++++++++++++++++++++++++++--- lib/zlib_inflate/inflate_syms.c | 1 + 5 files changed, 69 insertions(+), 59 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 73d4a579790c..6d6ea56fe384 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2761,48 +2761,6 @@ bnx2_set_rx_mode(struct net_device *dev) spin_unlock_bh(&bp->phy_lock); } -/* To be moved to generic lib/ */ -static int -bnx2_gunzip(void *gunzip_buf, unsigned sz, u8 *zbuf, int len) -{ - struct z_stream_s *strm; - int rc; - - /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) - * is stripped */ - - rc = -ENOMEM; - strm = kmalloc(sizeof(*strm), GFP_KERNEL); - if (strm == NULL) - goto gunzip_nomem2; - strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (strm->workspace == NULL) - goto gunzip_nomem3; - - strm->next_in = zbuf; - strm->avail_in = len; - strm->next_out = gunzip_buf; - strm->avail_out = sz; - - rc = zlib_inflateInit2(strm, -MAX_WBITS); - if (rc == Z_OK) { - rc = zlib_inflate(strm, Z_FINISH); - /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ - if (rc == Z_STREAM_END) - rc = sz - strm->avail_out; - else - rc = -EINVAL; - zlib_inflateEnd(strm); - } else - rc = -EINVAL; - - kfree(strm->workspace); -gunzip_nomem3: - kfree(strm); -gunzip_nomem2: - return rc; -} - static void load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len, u32 rv2p_proc) @@ -2858,7 +2816,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) text = vmalloc(FW_BUF_SIZE); if (!text) return -ENOMEM; - rc = bnx2_gunzip(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len); + rc = zlib_inflate_blob(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len); if (rc < 0) { vfree(text); return rc; @@ -2935,14 +2893,14 @@ bnx2_init_cpus(struct bnx2 *bp) text = vmalloc(FW_BUF_SIZE); if (!text) return -ENOMEM; - rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); + rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); if (rc < 0) { vfree(text); goto init_cpu_err; } load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1); - rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); + rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); if (rc < 0) { vfree(text); goto init_cpu_err; diff --git a/include/linux/zlib.h b/include/linux/zlib.h index 9e3192a7dc6f..40c49cb3eb51 100644 --- a/include/linux/zlib.h +++ b/include/linux/zlib.h @@ -82,7 +82,7 @@ struct internal_state; typedef struct z_stream_s { - Byte *next_in; /* next input byte */ + const Byte *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total nb of input bytes read so far */ @@ -699,4 +699,8 @@ extern int zlib_inflateInit2(z_streamp strm, int windowBits); struct internal_state {int dummy;}; /* hack for buggy compilers */ #endif +/* Utility function: initialize zlib, unpack binary blob, clean up zlib, + * return len or negative error code. */ +extern int zlib_inflate_blob(void *dst, unsigned dst_sz, const void *src, unsigned src_sz); + #endif /* _ZLIB_H */ diff --git a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c index d84560c076d8..8550b0c05d00 100644 --- a/lib/zlib_inflate/inffast.c +++ b/lib/zlib_inflate/inffast.c @@ -69,22 +69,22 @@ void inflate_fast(z_streamp strm, unsigned start) { struct inflate_state *state; - unsigned char *in; /* local strm->next_in */ - unsigned char *last; /* while in < last, enough input available */ - unsigned char *out; /* local strm->next_out */ - unsigned char *beg; /* inflate()'s initial strm->next_out */ - unsigned char *end; /* while out < end, enough space available */ + const unsigned char *in; /* local strm->next_in */ + const unsigned char *last; /* while in < last, enough input available */ + unsigned char *out; /* local strm->next_out */ + unsigned char *beg; /* inflate()'s initial strm->next_out */ + unsigned char *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned write; /* window write index */ - unsigned char *window; /* allocated sliding window, if wsize != 0 */ + unsigned char *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ - code const *lcode; /* local strm->lencode */ - code const *dcode; /* local strm->distcode */ + code const *lcode; /* local strm->lencode */ + code const *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code this; /* retrieved table entry */ @@ -92,7 +92,7 @@ void inflate_fast(z_streamp strm, unsigned start) /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ - unsigned char *from; /* where to copy match from */ + unsigned char *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state *)strm->state; diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c index 7e1e3114a73e..0ad1ebf00947 100644 --- a/lib/zlib_inflate/inflate.c +++ b/lib/zlib_inflate/inflate.c @@ -332,14 +332,14 @@ static int zlib_inflateSyncPacket(z_streamp strm) int zlib_inflate(z_streamp strm, int flush) { struct inflate_state *state; - unsigned char *next; /* next input */ - unsigned char *put; /* next output */ + const unsigned char *next; /* next input */ + unsigned char *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ - unsigned char *from; /* where to copy match bytes from */ + unsigned char *from; /* where to copy match bytes from */ code this; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ @@ -897,7 +897,7 @@ int zlib_inflateIncomp(z_stream *z) /* Setup some variables to allow misuse of updateWindow */ z->avail_out = 0; - z->next_out = z->next_in + z->avail_in; + z->next_out = (unsigned char*)z->next_in + z->avail_in; zlib_updatewindow(z, z->avail_in); @@ -916,3 +916,50 @@ int zlib_inflateIncomp(z_stream *z) return Z_OK; } + +#include +#include +#include + +/* Utility function: initialize zlib, unpack binary blob, clean up zlib, + * return len or negative error code. */ +int zlib_inflate_blob(void *gunzip_buf, unsigned sz, const void *buf, unsigned len) +{ + const u8 *zbuf = buf; + struct z_stream_s *strm; + int rc; + + rc = -ENOMEM; + strm = kmalloc(sizeof(*strm), GFP_KERNEL); + if (strm == NULL) + goto gunzip_nomem1; + strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (strm->workspace == NULL) + goto gunzip_nomem2; + + /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) + * expected to be stripped from input */ + + strm->next_in = zbuf; + strm->avail_in = len; + strm->next_out = gunzip_buf; + strm->avail_out = sz; + + rc = zlib_inflateInit2(strm, -MAX_WBITS); + if (rc == Z_OK) { + rc = zlib_inflate(strm, Z_FINISH); + /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ + if (rc == Z_STREAM_END) + rc = sz - strm->avail_out; + else + rc = -EINVAL; + zlib_inflateEnd(strm); + } else + rc = -EINVAL; + + kfree(strm->workspace); +gunzip_nomem2: + kfree(strm); +gunzip_nomem1: + return rc; /* returns Z_OK (0) if successful */ +} diff --git a/lib/zlib_inflate/inflate_syms.c b/lib/zlib_inflate/inflate_syms.c index 2061d4f06765..67329fe9907e 100644 --- a/lib/zlib_inflate/inflate_syms.c +++ b/lib/zlib_inflate/inflate_syms.c @@ -16,4 +16,5 @@ EXPORT_SYMBOL(zlib_inflateInit2); EXPORT_SYMBOL(zlib_inflateEnd); EXPORT_SYMBOL(zlib_inflateReset); EXPORT_SYMBOL(zlib_inflateIncomp); +EXPORT_SYMBOL(zlib_inflate_blob); MODULE_LICENSE("GPL"); From dc86967b54aaf64fb053cce83c05a4476d48583b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 1 Oct 2007 15:27:19 -0700 Subject: [PATCH 1648/2804] [TCP]: No fackets_out/highest_sack tuning when SACK isn't enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was found due to bug report from Cedric Le Goater though it turned this turned out to be unrelated bug. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 94c80113df7e..6199abeb0f5e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -660,7 +660,7 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned static void tcp_adjust_fackets_out(struct tcp_sock *tp, struct sk_buff *skb, int decr) { - if (!tp->sacked_out) + if (!tp->sacked_out || tcp_is_reno(tp)) return; if (!before(tp->highest_sack, TCP_SKB_CB(skb)->seq)) @@ -712,7 +712,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; - if (tp->sacked_out && (TCP_SKB_CB(skb)->seq == tp->highest_sack)) + if (tcp_is_sack(tp) && tp->sacked_out && + (TCP_SKB_CB(skb)->seq == tp->highest_sack)) tp->highest_sack = TCP_SKB_CB(buff)->seq; /* PSH and FIN should only be set in the second packet. */ @@ -1718,7 +1719,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1); - if (WARN_ON(tp->sacked_out && + if (WARN_ON(tcp_is_sack(tp) && tp->sacked_out && (TCP_SKB_CB(next_skb)->seq == tp->highest_sack))) return; From 95eacd27e2a0924f1435654c06712cee6be099ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 1 Oct 2007 15:27:42 -0700 Subject: [PATCH 1649/2804] [TCP]: fix comments that got messed up during code move MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4b27739031fb..904289d2b6bb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1467,8 +1467,9 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ return flag; } -/* F-RTO can only be used if TCP has never retransmitted anything other than - * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here) +/* If we receive more dupacks than we expected counting segments + * in assumption of absent reordering, interpret this as reordering. + * The only another reason could be bug in receiver TCP. */ static void tcp_check_reno_reordering(struct sock *sk, const int addend) { @@ -1516,6 +1517,9 @@ static inline void tcp_reset_reno_sack(struct tcp_sock *tp) tp->sacked_out = 0; } +/* F-RTO can only be used if TCP has never retransmitted anything other than + * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here) + */ int tcp_use_frto(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); From 0e835331e3111e5a92eb3a852405ea71ca8fff97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 1 Oct 2007 15:28:17 -0700 Subject: [PATCH 1650/2804] [TCP]: Update comment of SACK block validator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just came across what RFC2018 states about generation of valid SACK blocks in case of reneging. Alter comment a bit to point out clearly. IMHO, there isn't any reason to change code because the validation is there for a purpose (counters will inform user about decision TCP made if this case ever surfaces). Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 904289d2b6bb..c1339d88bbf3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1027,8 +1027,15 @@ static void tcp_update_reordering(struct sock *sk, const int metric, * SACK block range validation checks that the received SACK block fits to * the expected sequence limits, i.e., it is between SND.UNA and SND.NXT. * Note that SND.UNA is not included to the range though being valid because - * it means that the receiver is rather inconsistent with itself (reports - * SACK reneging when it should advance SND.UNA). + * it means that the receiver is rather inconsistent with itself reporting + * SACK reneging when it should advance SND.UNA. Such SACK block this is + * perfectly valid, however, in light of RFC2018 which explicitly states + * that "SACK block MUST reflect the newest segment. Even if the newest + * segment is going to be discarded ...", not that it looks very clever + * in case of head skb. Due to potentional receiver driven attacks, we + * choose to avoid immediate execution of a walk in write queue due to + * reneging and defer head skb's loss recovery to standard loss recovery + * procedure that will eventually trigger (nothing forbids us doing this). * * Implements also blockage to start_seq wrap-around. Problem lies in the * fact that though start_seq (s) is before end_seq (i.e., not reversed), From 3de96471bd7fb76406e975ef6387abe3a0698149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 1 Oct 2007 15:28:48 -0700 Subject: [PATCH 1651/2804] [TCP]: Wrap-safed reordering detection FRTO check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case somebody has a suggestion about a better place for this check, which must guarantee execution "early enough" (i.e, before the wrap can occur), I'm very open to them. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c1339d88bbf3..7c1a92ffa083 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3027,6 +3027,9 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) /* See if we can take anything off of the retransmit queue. */ flag |= tcp_clean_rtx_queue(sk, &seq_rtt); + /* Guarantee sacktag reordering detection against wrap-arounds */ + if (before(tp->frto_highmark, tp->snd_una)) + tp->frto_highmark = 0; if (tp->frto_counter) frto_cwnd = tcp_process_frto(sk, flag); From 0fb300fa9d54118c6dce772a29362d896775eff2 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:17 -0500 Subject: [PATCH 1652/2804] fs_enet: Whitespace cleanup. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 75 ++++++++++++++---------------- drivers/net/fs_enet/fs_enet.h | 4 +- drivers/net/fs_enet/mac-fcc.c | 1 - drivers/net/fs_enet/mii-bitbang.c | 3 -- drivers/net/fs_enet/mii-fec.c | 1 - 5 files changed, 36 insertions(+), 48 deletions(-) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index dcbe83c773ee..a15345ba1e59 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -343,7 +343,6 @@ static void fs_enet_tx(struct net_device *dev) do_wake = do_restart = 0; while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { - dirtyidx = bdp - fep->tx_bd_base; if (fep->tx_free == fep->tx_ring) @@ -444,7 +443,6 @@ fs_enet_interrupt(int irq, void *dev_id) nr = 0; while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { - nr++; int_clr_events = int_events; @@ -700,45 +698,43 @@ static void fs_timeout(struct net_device *dev) *-----------------------------------------------------------------------------*/ static void generic_adjust_link(struct net_device *dev) { - struct fs_enet_private *fep = netdev_priv(dev); - struct phy_device *phydev = fep->phydev; - int new_state = 0; + struct fs_enet_private *fep = netdev_priv(dev); + struct phy_device *phydev = fep->phydev; + int new_state = 0; - if (phydev->link) { + if (phydev->link) { + /* adjust to duplex mode */ + if (phydev->duplex != fep->oldduplex) { + new_state = 1; + fep->oldduplex = phydev->duplex; + } - /* adjust to duplex mode */ - if (phydev->duplex != fep->oldduplex){ - new_state = 1; - fep->oldduplex = phydev->duplex; - } + if (phydev->speed != fep->oldspeed) { + new_state = 1; + fep->oldspeed = phydev->speed; + } - if (phydev->speed != fep->oldspeed) { - new_state = 1; - fep->oldspeed = phydev->speed; - } + if (!fep->oldlink) { + new_state = 1; + fep->oldlink = 1; + netif_schedule(dev); + netif_carrier_on(dev); + netif_start_queue(dev); + } - if (!fep->oldlink) { - new_state = 1; - fep->oldlink = 1; - netif_schedule(dev); - netif_carrier_on(dev); - netif_start_queue(dev); - } + if (new_state) + fep->ops->restart(dev); + } else if (fep->oldlink) { + new_state = 1; + fep->oldlink = 0; + fep->oldspeed = 0; + fep->oldduplex = -1; + netif_carrier_off(dev); + netif_stop_queue(dev); + } - if (new_state) - fep->ops->restart(dev); - - } else if (fep->oldlink) { - new_state = 1; - fep->oldlink = 0; - fep->oldspeed = 0; - fep->oldduplex = -1; - netif_carrier_off(dev); - netif_stop_queue(dev); - } - - if (new_state && netif_msg_link(fep)) - phy_print_status(phydev); + if (new_state && netif_msg_link(fep)) + phy_print_status(phydev); } @@ -782,7 +778,6 @@ static int fs_init_phy(struct net_device *dev) return 0; } - static int fs_enet_open(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); @@ -971,7 +966,7 @@ static struct net_device *fs_init_instance(struct device *dev, #endif #ifdef CONFIG_FS_ENET_HAS_SCC - if (fs_get_scc_index(fpi->fs_no) >=0 ) + if (fs_get_scc_index(fpi->fs_no) >=0) fep->ops = &fs_scc_ops; #endif @@ -1066,9 +1061,8 @@ static struct net_device *fs_init_instance(struct device *dev, return ndev; - err: +err: if (ndev != NULL) { - if (registered) unregister_netdev(ndev); @@ -1259,7 +1253,6 @@ static int __init fs_init(void) err: cleanup_immap(); return r; - } static void __exit fs_cleanup(void) diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 46d0606b1439..fbe2087d0d79 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -15,8 +15,8 @@ #include struct fec_info { - fec_t* fecp; - u32 mii_speed; + fec_t *fecp; + u32 mii_speed; }; #endif diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 64071514d7d5..1e1024a4d432 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -86,7 +86,6 @@ static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) { const struct fs_platform_info *fpi = fep->fpi; - cpm2_map_t *immap = fs_enet_immap; cpm_cpm2_t *cpmp = &immap->im_cpm; u32 v; diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 1a41ea60f982..422f82877873 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -12,7 +12,6 @@ * kind, whether express or implied. */ - #include #include #include @@ -308,7 +307,6 @@ static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platfor return 0; } - static int __devinit fs_enet_mdio_probe(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -371,7 +369,6 @@ bus_register_fail: return err; } - static int fs_enet_mdio_remove(struct device *dev) { struct mii_bus *bus = dev_get_drvdata(dev); diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 0a563a83016f..53db696b948f 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -113,7 +113,6 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) } return ret; - } static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) From b7336d3d886aaab6971773864c477210ef9b995a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:49 -0500 Subject: [PATCH 1653/2804] fs_enet: Include linux/string.h from linux/fs_enet_pd.h It is needed for strstr(). Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- include/linux/fs_enet_pd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h index 543cd3cd9e77..815c6f94378b 100644 --- a/include/linux/fs_enet_pd.h +++ b/include/linux/fs_enet_pd.h @@ -16,6 +16,7 @@ #ifndef FS_ENET_PD_H #define FS_ENET_PD_H +#include #include #define FS_ENET_NAME "fs_enet" From c6565331b7162a8348c70c37b4c33bedb6d4f02d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:50 -0500 Subject: [PATCH 1654/2804] fs_enet: mac-fcc: Eliminate __fcc-* macros. These macros accomplish nothing other than defeating type checking. This patch also fixes one instance of the wrong register size being used that was revealed by enabling type checking. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/mac-fcc.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 1e1024a4d432..e990f728d51b 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -48,28 +48,19 @@ /* FCC access macros */ -#define __fcc_out32(addr, x) out_be32((unsigned *)addr, x) -#define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x) -#define __fcc_out8(addr, x) out_8((unsigned char *)addr, x) -#define __fcc_in32(addr) in_be32((unsigned *)addr) -#define __fcc_in16(addr) in_be16((unsigned short *)addr) -#define __fcc_in8(addr) in_8((unsigned char *)addr) - -/* parameter space */ - /* write, read, set bits, clear bits */ -#define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v)) -#define R32(_p, _m) __fcc_in32(&(_p)->_m) +#define W32(_p, _m, _v) out_be32(&(_p)->_m, (_v)) +#define R32(_p, _m) in_be32(&(_p)->_m) #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) -#define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v)) -#define R16(_p, _m) __fcc_in16(&(_p)->_m) +#define W16(_p, _m, _v) out_be16(&(_p)->_m, (_v)) +#define R16(_p, _m) in_be16(&(_p)->_m) #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) -#define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v)) -#define R8(_p, _m) __fcc_in8(&(_p)->_m) +#define W8(_p, _m, _v) out_8(&(_p)->_m, (_v)) +#define R8(_p, _m) in_8(&(_p)->_m) #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) @@ -290,7 +281,7 @@ static void restart(struct net_device *dev) /* clear everything (slow & steady does it) */ for (i = 0; i < sizeof(*ep); i++) - __fcc_out8((char *)ep + i, 0); + out_8((char *)ep + i, 0); /* get physical address */ rx_bd_base_phys = fep->ring_mem_addr; @@ -495,7 +486,7 @@ static void tx_kickstart(struct net_device *dev) struct fs_enet_private *fep = netdev_priv(dev); fcc_t *fccp = fep->fcc.fccp; - S32(fccp, fcc_ftodr, 0x80); + S16(fccp, fcc_ftodr, 0x8000); } static u32 get_int_events(struct net_device *dev) From 0d0d9c150c046cbd3e507adcfa2d78db82f1f452 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:52 -0500 Subject: [PATCH 1655/2804] fs_enet: Align receive buffers. At least some hardware driven by this driver needs receive buffers to be aligned on a 16-byte boundary. This usually happens by chance, but it breaks if slab debugging is enabled. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 21 +++++++++++++++++++-- drivers/net/fs_enet/fs_enet.h | 3 ++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a15345ba1e59..7a0298687875 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -70,6 +70,14 @@ static void fs_set_multicast_list(struct net_device *dev) (*fep->ops->set_multicast_list)(dev); } +static void skb_align(struct sk_buff *skb, int align) +{ + int off = ((unsigned long)skb->data) & (align - 1); + + if (off) + skb_reserve(skb, align - off); +} + /* NAPI receive function */ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) { @@ -159,9 +167,13 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) skb = skbn; skbn = skbt; } - } else + } else { skbn = dev_alloc_skb(ENET_RX_FRSIZE); + if (skbn) + skb_align(skbn, ENET_RX_ALIGN); + } + if (skbn != NULL) { skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); @@ -290,9 +302,13 @@ static int fs_enet_rx_non_napi(struct net_device *dev) skb = skbn; skbn = skbt; } - } else + } else { skbn = dev_alloc_skb(ENET_RX_FRSIZE); + if (skbn) + skb_align(skbn, ENET_RX_ALIGN); + } + if (skbn != NULL) { skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); @@ -502,6 +518,7 @@ void fs_init_bds(struct net_device *dev) dev->name); break; } + skb_align(skb, ENET_RX_ALIGN); fep->rx_skbuff[i] = skb; CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index fbe2087d0d79..85571e49ec72 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -82,7 +82,8 @@ struct phy_info { /* Must be a multiple of 32 (to cover both FEC & FCC) */ #define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31) /* This is needed so that invalidate_xxx wont invalidate too much */ -#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE) +#define ENET_RX_ALIGN 16 +#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1) struct fs_enet_mii_bus { struct list_head list; From 976de6a8c304dcc43e38efcb8a0bace7866b6242 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 2 Oct 2007 10:55:58 -0500 Subject: [PATCH 1656/2804] fs_enet: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set. The existing OF glue code was crufty and broken. Rather than fix it, it will be removed, and the ethernet driver now talks to the device tree directly. The old, non-CONFIG_PPC_CPM_NEW_BINDING code can go away once CPM platforms are dropped from arch/ppc (which will hopefully be soon), and existing arch/powerpc boards that I wasn't able to test on for this patchset get converted (which should be even sooner). Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/Kconfig | 1 + drivers/net/fs_enet/fs_enet-main.c | 258 +++++++++++++++++++++++++-- drivers/net/fs_enet/fs_enet.h | 55 +----- drivers/net/fs_enet/mac-fcc.c | 89 +++++++--- drivers/net/fs_enet/mac-fec.c | 19 +- drivers/net/fs_enet/mac-scc.c | 53 ++++-- drivers/net/fs_enet/mii-bitbang.c | 271 +++++++++++++++++++++-------- drivers/net/fs_enet/mii-fec.c | 143 ++++++++++++++- include/linux/fs_enet_pd.h | 5 + 9 files changed, 715 insertions(+), 179 deletions(-) diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig index e27ee210b605..2765e49e07df 100644 --- a/drivers/net/fs_enet/Kconfig +++ b/drivers/net/fs_enet/Kconfig @@ -11,6 +11,7 @@ config FS_ENET_HAS_SCC config FS_ENET_HAS_FCC bool "Chip has an FCC usable for ethernet" depends on FS_ENET && CPM2 + select MDIO_BITBANG default y config FS_ENET_HAS_FEC diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 7a0298687875..fc4fda805d44 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -42,12 +42,18 @@ #include #include +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" /*************************************************/ +#ifndef CONFIG_PPC_CPM_NEW_BINDING static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; +#endif MODULE_AUTHOR("Pantelis Antoniou "); MODULE_DESCRIPTION("Freescale Ethernet Driver"); @@ -948,6 +954,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) extern int fs_mii_connect(struct net_device *dev); extern void fs_mii_disconnect(struct net_device *dev); +#ifndef CONFIG_PPC_CPM_NEW_BINDING static struct net_device *fs_init_instance(struct device *dev, struct fs_platform_info *fpi) { @@ -1129,6 +1136,7 @@ static int fs_cleanup_instance(struct net_device *ndev) return 0; } +#endif /**************************************************************************************/ @@ -1137,35 +1145,250 @@ void *fs_enet_immap = NULL; static int setup_immap(void) { - phys_addr_t paddr = 0; - unsigned long size = 0; - #ifdef CONFIG_CPM1 - paddr = IMAP_ADDR; - size = 0x10000; /* map 64K */ + fs_enet_immap = ioremap(IMAP_ADDR, 0x4000); + WARN_ON(!fs_enet_immap); +#elif defined(CONFIG_CPM2) + fs_enet_immap = cpm2_immr; #endif -#ifdef CONFIG_CPM2 - paddr = CPM_MAP_ADDR; - size = 0x40000; /* map 256 K */ -#endif - fs_enet_immap = ioremap(paddr, size); - if (fs_enet_immap == NULL) - return -EBADF; /* XXX ahem; maybe just BUG_ON? */ - return 0; } static void cleanup_immap(void) { - if (fs_enet_immap != NULL) { - iounmap(fs_enet_immap); - fs_enet_immap = NULL; - } +#if defined(CONFIG_CPM1) + iounmap(fs_enet_immap); +#endif } /**************************************************************************************/ +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static int __devinit find_phy(struct device_node *np, + struct fs_platform_info *fpi) +{ + struct device_node *phynode, *mdionode; + struct resource res; + int ret = 0, len; + + const u32 *data = of_get_property(np, "phy-handle", &len); + if (!data || len != 4) + return -EINVAL; + + phynode = of_find_node_by_phandle(*data); + if (!phynode) + return -EINVAL; + + mdionode = of_get_parent(phynode); + if (!mdionode) + goto out_put_phy; + + ret = of_address_to_resource(mdionode, 0, &res); + if (ret) + goto out_put_mdio; + + data = of_get_property(phynode, "reg", &len); + if (!data || len != 4) + goto out_put_mdio; + + snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data); + +out_put_mdio: + of_node_put(mdionode); +out_put_phy: + of_node_put(phynode); + return ret; +} + +#ifdef CONFIG_FS_ENET_HAS_FEC +#define IS_FEC(match) ((match)->data == &fs_fec_ops) +#else +#define IS_FEC(match) 0 +#endif + +static int __devinit fs_enet_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct net_device *ndev; + struct fs_enet_private *fep; + struct fs_platform_info *fpi; + const u32 *data; + const u8 *mac_addr; + int privsize, len, ret = -ENODEV; + + fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); + if (!fpi) + return -ENOMEM; + + if (!IS_FEC(match)) { + data = of_get_property(ofdev->node, "fsl,cpm-command", &len); + if (!data || len != 4) + goto out_free_fpi; + + fpi->cp_command = *data; + } + + fpi->rx_ring = 32; + fpi->tx_ring = 32; + fpi->rx_copybreak = 240; + fpi->use_napi = 0; + fpi->napi_weight = 17; + + ret = find_phy(ofdev->node, fpi); + if (ret) + goto out_free_fpi; + + privsize = sizeof(*fep) + + sizeof(struct sk_buff **) * + (fpi->rx_ring + fpi->tx_ring); + + ndev = alloc_etherdev(privsize); + if (!ndev) { + ret = -ENOMEM; + goto out_free_fpi; + } + + SET_MODULE_OWNER(ndev); + dev_set_drvdata(&ofdev->dev, ndev); + + fep = netdev_priv(ndev); + fep->dev = &ofdev->dev; + fep->fpi = fpi; + fep->ops = match->data; + + ret = fep->ops->setup_data(ndev); + if (ret) + goto out_free_dev; + + fep->rx_skbuff = (struct sk_buff **)&fep[1]; + fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; + + spin_lock_init(&fep->lock); + spin_lock_init(&fep->tx_lock); + + mac_addr = of_get_mac_address(ofdev->node); + if (mac_addr) + memcpy(ndev->dev_addr, mac_addr, 6); + + ret = fep->ops->allocate_bd(ndev); + if (ret) + goto out_cleanup_data; + + fep->rx_bd_base = fep->ring_base; + fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; + + fep->tx_ring = fpi->tx_ring; + fep->rx_ring = fpi->rx_ring; + + ndev->open = fs_enet_open; + ndev->hard_start_xmit = fs_enet_start_xmit; + ndev->tx_timeout = fs_timeout; + ndev->watchdog_timeo = 2 * HZ; + ndev->stop = fs_enet_close; + ndev->get_stats = fs_enet_get_stats; + ndev->set_multicast_list = fs_set_multicast_list; + if (fpi->use_napi) { + ndev->poll = fs_enet_rx_napi; + ndev->weight = fpi->napi_weight; + } + ndev->ethtool_ops = &fs_ethtool_ops; + ndev->do_ioctl = fs_ioctl; + + init_timer(&fep->phy_timer_list); + + netif_carrier_off(ndev); + + ret = register_netdev(ndev); + if (ret) + goto out_free_bd; + + printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, + ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], + ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + + return 0; + +out_free_bd: + fep->ops->free_bd(ndev); +out_cleanup_data: + fep->ops->cleanup_data(ndev); +out_free_dev: + free_netdev(ndev); + dev_set_drvdata(&ofdev->dev, NULL); +out_free_fpi: + kfree(fpi); + return ret; +} + +static int fs_enet_remove(struct of_device *ofdev) +{ + struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct fs_enet_private *fep = netdev_priv(ndev); + + unregister_netdev(ndev); + + fep->ops->free_bd(ndev); + fep->ops->cleanup_data(ndev); + dev_set_drvdata(fep->dev, NULL); + + free_netdev(ndev); + return 0; +} + +static struct of_device_id fs_enet_match[] = { +#ifdef CONFIG_FS_ENET_HAS_SCC + { + .compatible = "fsl,cpm1-scc-enet", + .data = (void *)&fs_scc_ops, + }, +#endif +#ifdef CONFIG_FS_ENET_HAS_FCC + { + .compatible = "fsl,cpm2-fcc-enet", + .data = (void *)&fs_fcc_ops, + }, +#endif +#ifdef CONFIG_FS_ENET_HAS_FEC + { + .compatible = "fsl,pq1-fec-enet", + .data = (void *)&fs_fec_ops, + }, +#endif + {} +}; + +static struct of_platform_driver fs_enet_driver = { + .name = "fs_enet", + .match_table = fs_enet_match, + .probe = fs_enet_probe, + .remove = fs_enet_remove, +}; + +static int __init fs_init(void) +{ + int r = setup_immap(); + if (r != 0) + return r; + + r = of_register_platform_driver(&fs_enet_driver); + if (r != 0) + goto out; + + return 0; + +out: + cleanup_immap(); + return r; +} + +static void __exit fs_cleanup(void) +{ + of_unregister_platform_driver(&fs_enet_driver); + cleanup_immap(); +} +#else static int __devinit fs_enet_probe(struct device *dev) { struct net_device *ndev; @@ -1279,6 +1502,7 @@ static void __exit fs_cleanup(void) driver_unregister(&fs_enet_scc_driver); cleanup_immap(); } +#endif #ifdef CONFIG_NET_POLL_CONTROLLER static void fs_enet_netpoll(struct net_device *dev) diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 85571e49ec72..5a5c9d18df2e 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -24,19 +24,6 @@ struct fec_info { #include #endif -/* This is used to operate with pins. - Note that the actual port size may - be different; cpm(s) handle it OK */ -struct bb_info { - u8 mdio_dat_msk; - u8 mdio_dir_msk; - u8 *mdio_dir; - u8 *mdio_dat; - u8 mdc_msk; - u8 *mdc_dat; - int delay; -}; - /* hw driver ops */ struct fs_ops { int (*setup_data)(struct net_device *dev); @@ -85,48 +72,12 @@ struct phy_info { #define ENET_RX_ALIGN 16 #define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1) -struct fs_enet_mii_bus { - struct list_head list; - spinlock_t mii_lock; - const struct fs_mii_bus_info *bus_info; - int refs; - u32 usage_map; - - int (*mii_read)(struct fs_enet_mii_bus *bus, - int phy_id, int location); - - void (*mii_write)(struct fs_enet_mii_bus *bus, - int phy_id, int location, int value); - - union { - struct { - unsigned int mii_speed; - void *fecp; - } fec; - - struct { - /* note that the actual port size may */ - /* be different; cpm(s) handle it OK */ - u8 mdio_msk; - u8 *mdio_dir; - u8 *mdio_dat; - u8 mdc_msk; - u8 *mdc_dir; - u8 *mdc_dat; - } bitbang; - - struct { - u16 lpa; - } fixed; - }; -}; - struct fs_enet_private { struct napi_struct napi; struct device *dev; /* pointer back to the device (must be initialized first) */ spinlock_t lock; /* during all ops except TX pckt processing */ spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ - const struct fs_platform_info *fpi; + struct fs_platform_info *fpi; const struct fs_ops *ops; int rx_ring, tx_ring; dma_addr_t ring_mem_addr; @@ -145,7 +96,6 @@ struct fs_enet_private { u32 msg_enable; struct mii_if_info mii_if; unsigned int last_mii_status; - struct fs_enet_mii_bus *mii_bus; int interrupt; struct phy_device *phydev; @@ -187,9 +137,10 @@ struct fs_enet_private { }; /***************************************************************************/ +#ifndef CONFIG_PPC_CPM_NEW_BINDING int fs_enet_mdio_bb_init(void); -int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); int fs_enet_mdio_fec_init(void); +#endif void fs_init_bds(struct net_device *dev); void fs_cleanup_bds(struct net_device *dev); diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index e990f728d51b..6094cbf542a2 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -42,6 +42,10 @@ #include #include +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" /*************************************************/ @@ -74,33 +78,64 @@ #define MAX_CR_CMD_LOOPS 10000 -static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) +static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op) { const struct fs_platform_info *fpi = fep->fpi; cpm2_map_t *immap = fs_enet_immap; cpm_cpm2_t *cpmp = &immap->im_cpm; - u32 v; int i; - /* Currently I don't know what feature call will look like. But - I guess there'd be something like do_cpm_cmd() which will require page & sblock */ - v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); - W32(cpmp, cp_cpcr, v | CPM_CR_FLG); + W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG); for (i = 0; i < MAX_CR_CMD_LOOPS; i++) if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) - break; + return 0; - if (i >= MAX_CR_CMD_LOOPS) { - printk(KERN_ERR "%s(): Not able to issue CPM command\n", - __FUNCTION__); - return 1; - } - - return 0; + printk(KERN_ERR "%s(): Not able to issue CPM command\n", + __FUNCTION__); + return 1; } static int do_pd_setup(struct fs_enet_private *fep) { +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct of_device *ofdev = to_of_device(fep->dev); + struct fs_platform_info *fpi = fep->fpi; + int ret = -EINVAL; + + fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL); + if (fep->interrupt == NO_IRQ) + goto out; + + fep->fcc.fccp = of_iomap(ofdev->node, 0); + if (!fep->fcc.fccp) + goto out; + + fep->fcc.ep = of_iomap(ofdev->node, 1); + if (!fep->fcc.ep) + goto out_fccp; + + fep->fcc.fcccp = of_iomap(ofdev->node, 2); + if (!fep->fcc.fcccp) + goto out_ep; + + fep->fcc.mem = (void *)cpm_dpalloc(128, 8); + fpi->dpram_offset = (u32)cpm2_immr; + if (IS_ERR_VALUE(fpi->dpram_offset)) { + ret = fpi->dpram_offset; + goto out_fcccp; + } + + return 0; + +out_fcccp: + iounmap(fep->fcc.fcccp); +out_ep: + iounmap(fep->fcc.ep); +out_fccp: + iounmap(fep->fcc.fccp); +out: + return ret; +#else struct platform_device *pdev = to_platform_device(fep->dev); struct resource *r; @@ -138,6 +173,7 @@ static int do_pd_setup(struct fs_enet_private *fep) return -EINVAL; return 0; +#endif } #define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) @@ -148,11 +184,17 @@ static int do_pd_setup(struct fs_enet_private *fep) static int setup_data(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; +#ifndef CONFIG_PPC_CPM_NEW_BINDING + struct fs_platform_info *fpi = fep->fpi; + + fpi->cp_command = (fpi->cp_page << 26) | + (fpi->cp_block << 21) | + (12 << 6); fep->fcc.idx = fs_get_fcc_index(fpi->fs_no); if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ return -EINVAL; +#endif if (do_pd_setup(fep) != 0) return -EINVAL; @@ -226,7 +268,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac) W16(ep, fen_taddrh, taddrh); W16(ep, fen_taddrm, taddrm); W16(ep, fen_taddrl, taddrl); - fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR); + fcc_cr_cmd(fep, CPM_CR_SET_GADDR); } static void set_multicast_finish(struct net_device *dev) @@ -281,7 +323,7 @@ static void restart(struct net_device *dev) /* clear everything (slow & steady does it) */ for (i = 0; i < sizeof(*ep); i++) - out_8((char *)ep + i, 0); + out_8((u8 __iomem *)ep + i, 0); /* get physical address */ rx_bd_base_phys = fep->ring_mem_addr; @@ -397,7 +439,7 @@ static void restart(struct net_device *dev) S8(fcccp, fcc_gfemr, 0x20); } - fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX); + fcc_cr_cmd(fep, CPM_CR_INIT_TRX); /* clear events */ W16(fccp, fcc_fcce, 0xffff); @@ -515,23 +557,22 @@ int get_regs(struct net_device *dev, void *p, int *sizep) { struct fs_enet_private *fep = netdev_priv(dev); - if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t)) + if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1) return -EINVAL; memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); p = (char *)p + sizeof(fcc_t); - memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t)); - p = (char *)p + sizeof(fcc_c_t); - memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); + p = (char *)p + sizeof(fcc_enet_t); + memcpy_fromio(p, fep->fcc.fcccp, 1); return 0; } int get_regs_len(struct net_device *dev) { - return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t); + return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1; } /* Some transmit errors cause the transmitter to shut @@ -551,7 +592,7 @@ void tx_restart(struct net_device *dev) udelay(10); S32(fccp, fcc_gfmr, FCC_GFMR_ENT); - fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX); + fcc_cr_cmd(fep, CPM_CR_RESTART_TX); } /*************************************************************************/ diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index cbdc17b743db..924d6617cd30 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -43,6 +43,10 @@ #include #endif +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" #include "fec.h" @@ -95,6 +99,19 @@ static int whack_reset(fec_t * fecp) static int do_pd_setup(struct fs_enet_private *fep) { +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct of_device *ofdev = to_of_device(fep->dev); + + fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL); + if (fep->interrupt == NO_IRQ) + return -EINVAL; + + fep->fec.fecp = of_iomap(ofdev->node, 0); + if (!fep->fcc.fccp) + return -EINVAL; + + return 0; +#else struct platform_device *pdev = to_platform_device(fep->dev); struct resource *r; @@ -110,7 +127,7 @@ static int do_pd_setup(struct fs_enet_private *fep) return -EINVAL; return 0; - +#endif } #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 6f32674a78e9..add9e32d4f47 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -43,6 +43,10 @@ #include #endif +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" /*************************************************/ @@ -89,27 +93,38 @@ static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) { - cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm; - u32 v, ch; - int i = 0; + const struct fs_platform_info *fpi = fep->fpi; + int i; - ch = fep->scc.idx << 2; - v = mk_cr_cmd(ch, op); - W16(cpmp, cp_cpcr, v | CPM_CR_FLG); + W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8)); for (i = 0; i < MAX_CR_CMD_LOOPS; i++) if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) - break; + return 0; - if (i >= MAX_CR_CMD_LOOPS) { - printk(KERN_ERR "%s(): Not able to issue CPM command\n", - __FUNCTION__); - return 1; - } - return 0; + printk(KERN_ERR "%s(): Not able to issue CPM command\n", + __FUNCTION__); + return 1; } static int do_pd_setup(struct fs_enet_private *fep) { +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct of_device *ofdev = to_of_device(fep->dev); + + fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL); + if (fep->interrupt == NO_IRQ) + return -EINVAL; + + fep->scc.sccp = of_iomap(ofdev->node, 0); + if (!fep->scc.sccp) + return -EINVAL; + + fep->scc.ep = of_iomap(ofdev->node, 1); + if (!fep->scc.ep) { + iounmap(fep->scc.sccp); + return -EINVAL; + } +#else struct platform_device *pdev = to_platform_device(fep->dev); struct resource *r; @@ -129,6 +144,7 @@ static int do_pd_setup(struct fs_enet_private *fep) if (fep->scc.ep == NULL) return -EINVAL; +#endif return 0; } @@ -141,12 +157,17 @@ static int do_pd_setup(struct fs_enet_private *fep) static int setup_data(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; + +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct fs_platform_info *fpi = fep->fpi; fep->scc.idx = fs_get_scc_index(fpi->fs_no); - if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */ + if ((unsigned int)fep->fcc.idx >= 4) /* max 4 SCCs */ return -EINVAL; + fpi->cp_command = fep->fcc.idx << 6; +#endif + do_pd_setup(fep); fep->scc.hthi = 0; @@ -154,7 +175,7 @@ static int setup_data(struct net_device *dev) fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; fep->ev_rx = SCC_RX_EVENT; - fep->ev_tx = SCC_TX_EVENT; + fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE; fep->ev_err = SCC_ERR_EVENT_MSK; return 0; diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 422f82877873..7cf132f0f952 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -13,11 +13,6 @@ */ #include -#include -#include -#include -#include -#include #include #include #include @@ -25,86 +20,77 @@ #include #include #include -#include -#include #include #include #include #include -#include -#include -#include +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif #include "fs_enet.h" -static int bitbang_prep_bit(u8 **datp, u8 *mskp, - struct fs_mii_bit *mii_bit) +struct bb_info { + __be32 __iomem *dir; + __be32 __iomem *dat; + u32 mdio_msk; + u32 mdc_msk; + int delay; +}; + +/* FIXME: If any other users of GPIO crop up, then these will have to + * have some sort of global synchronization to avoid races with other + * pins on the same port. The ideal solution would probably be to + * bind the ports to a GPIO driver, and have this be a client of it. + */ +static inline void bb_set(u32 __iomem *p, u32 m) { - void *dat; - int adv; - u8 msk; - - dat = (void*) mii_bit->offset; - - adv = mii_bit->bit >> 3; - dat = (char *)dat + adv; - - msk = 1 << (7 - (mii_bit->bit & 7)); - - *datp = dat; - *mskp = msk; - - return 0; + out_be32(p, in_be32(p) | m); } -static inline void bb_set(u8 *p, u8 m) +static inline void bb_clr(u32 __iomem *p, u32 m) { - out_8(p, in_8(p) | m); + out_be32(p, in_be32(p) & ~m); } -static inline void bb_clr(u8 *p, u8 m) +static inline int bb_read(u32 __iomem *p, u32 m) { - out_8(p, in_8(p) & ~m); -} - -static inline int bb_read(u8 *p, u8 m) -{ - return (in_8(p) & m) != 0; + return (in_be32(p) & m) != 0; } static inline void mdio_active(struct bb_info *bitbang) { - bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk); + bb_set(bitbang->dir, bitbang->mdio_msk); } -static inline void mdio_tristate(struct bb_info *bitbang ) +static inline void mdio_tristate(struct bb_info *bitbang) { - bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk); + bb_clr(bitbang->dir, bitbang->mdio_msk); } -static inline int mdio_read(struct bb_info *bitbang ) +static inline int mdio_read(struct bb_info *bitbang) { - return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk); + return bb_read(bitbang->dat, bitbang->mdio_msk); } -static inline void mdio(struct bb_info *bitbang , int what) +static inline void mdio(struct bb_info *bitbang, int what) { if (what) - bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk); + bb_set(bitbang->dat, bitbang->mdio_msk); else - bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk); + bb_clr(bitbang->dat, bitbang->mdio_msk); } -static inline void mdc(struct bb_info *bitbang , int what) +static inline void mdc(struct bb_info *bitbang, int what) { if (what) - bb_set(bitbang->mdc_dat, bitbang->mdc_msk); + bb_set(bitbang->dat, bitbang->mdc_msk); else - bb_clr(bitbang->mdc_dat, bitbang->mdc_msk); + bb_clr(bitbang->dat, bitbang->mdc_msk); } -static inline void mii_delay(struct bb_info *bitbang ) +static inline void mii_delay(struct bb_info *bitbang) { udelay(bitbang->delay); } @@ -280,30 +266,179 @@ static int fs_enet_mii_bb_reset(struct mii_bus *bus) return 0; } -static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi) +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, + struct device_node *np) { - int r; + struct resource res; + const u32 *data; + int mdio_pin, mdc_pin, len; + struct bb_info *bitbang = bus->priv; + int ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + if (res.end - res.start < 13) + return -ENODEV; + + /* This should really encode the pin number as well, but all + * we get is an int, and the odds of multiple bitbang mdio buses + * is low enough that it's not worth going too crazy. + */ + bus->id = res.start; + + data = of_get_property(np, "fsl,mdio-pin", &len); + if (!data || len != 4) + return -ENODEV; + mdio_pin = *data; + + data = of_get_property(np, "fsl,mdc-pin", &len); + if (!data || len != 4) + return -ENODEV; + mdc_pin = *data; + + bitbang->dir = ioremap(res.start, res.end - res.start + 1); + if (!bitbang->dir) + return -ENOMEM; + + bitbang->dat = bitbang->dir + 4; + bitbang->mdio_msk = 1 << (31 - mdio_pin); + bitbang->mdc_msk = 1 << (31 - mdc_pin); + bitbang->delay = 1; /* 1 us between operations */ + + return 0; +} + +static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) +{ + const u32 *data; + int len, id, irq; + + data = of_get_property(np, "reg", &len); + if (!data || len != 4) + return; + + id = *data; + bus->phy_mask &= ~(1 << id); + + irq = of_irq_to_resource(np, 0, NULL); + if (irq != NO_IRQ) + bus->irq[id] = irq; +} + +static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = NULL; + struct mii_bus *new_bus; + struct bb_info *bitbang; + int ret = -ENOMEM; + int i; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + if (!new_bus) + goto out; + + bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); + if (!bitbang) + goto out_free_bus; + + new_bus->priv = bitbang; + new_bus->name = "CPM2 Bitbanged MII", + new_bus->read = &fs_enet_mii_bb_read, + new_bus->write = &fs_enet_mii_bb_write, + new_bus->reset = &fs_enet_mii_bb_reset, + + ret = fs_mii_bitbang_init(new_bus, ofdev->node); + if (ret) + goto out_free_bitbang; + + new_bus->phy_mask = ~0; + new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!new_bus->irq) + goto out_unmap_regs; + + for (i = 0; i < PHY_MAX_ADDR; i++) + new_bus->irq[i] = -1; + + while ((np = of_get_next_child(ofdev->node, np))) + if (!strcmp(np->type, "ethernet-phy")) + add_phy(new_bus, np); + + new_bus->dev = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); + + ret = mdiobus_register(new_bus); + if (ret) + goto out_free_irqs; + + return 0; + +out_free_irqs: + dev_set_drvdata(&ofdev->dev, NULL); + kfree(new_bus->irq); +out_unmap_regs: + iounmap(bitbang->dir); +out_free_bitbang: + kfree(bitbang); +out_free_bus: + kfree(new_bus); +out: + return ret; +} + +static int fs_enet_mdio_remove(struct of_device *ofdev) +{ + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct bb_info *bitbang = bus->priv; + + mdiobus_unregister(bus); + dev_set_drvdata(&ofdev->dev, NULL); + kfree(bus->irq); + iounmap(bitbang->dir); + kfree(bitbang); + kfree(bus); + + return 0; +} + +static struct of_device_id fs_enet_mdio_bb_match[] = { + { + .compatible = "fsl,cpm2-mdio-bitbang", + }, + {}, +}; + +static struct of_platform_driver fs_enet_bb_mdio_driver = { + .name = "fsl-bb-mdio", + .match_table = fs_enet_mdio_bb_match, + .probe = fs_enet_mdio_probe, + .remove = fs_enet_mdio_remove, +}; + +int fs_enet_mdio_bb_init(void) +{ + return of_register_platform_driver(&fs_enet_bb_mdio_driver); +} + +void fs_enet_mdio_bb_exit(void) +{ + of_unregister_platform_driver(&fs_enet_bb_mdio_driver); +} + +module_init(fs_enet_mdio_bb_init); +module_exit(fs_enet_mdio_bb_exit); +#else +static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang, + struct fs_mii_bb_platform_info *fmpi) +{ + bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset; + bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset; + bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit); + bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit); bitbang->delay = fmpi->delay; - r = bitbang_prep_bit(&bitbang->mdio_dir, - &bitbang->mdio_dir_msk, - &fmpi->mdio_dir); - if (r != 0) - return r; - - r = bitbang_prep_bit(&bitbang->mdio_dat, - &bitbang->mdio_dat_msk, - &fmpi->mdio_dat); - if (r != 0) - return r; - - r = bitbang_prep_bit(&bitbang->mdc_dat, - &bitbang->mdc_msk, - &fmpi->mdc_dat); - if (r != 0) - return r; - return 0; } diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 53db696b948f..f91c38d0b57b 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -36,6 +36,10 @@ #include #include +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" #include "fec.h" @@ -47,6 +51,7 @@ #define FEC_MII_LOOPS 10000 +#ifndef CONFIG_PPC_CPM_NEW_BINDING static int match_has_phy (struct device *dev, void* data) { struct platform_device* pdev = container_of(dev, struct platform_device, dev); @@ -90,6 +95,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info return 0; } +#endif static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) { @@ -145,6 +151,141 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) return 0; } +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) +{ + const u32 *data; + int len, id, irq; + + data = of_get_property(np, "reg", &len); + if (!data || len != 4) + return; + + id = *data; + bus->phy_mask &= ~(1 << id); + + irq = of_irq_to_resource(np, 0, NULL); + if (irq != NO_IRQ) + bus->irq[id] = irq; +} + +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; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + if (!new_bus) + goto out; + + fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); + if (!fec) + goto out_mii; + + new_bus->priv = fec; + new_bus->name = "FEC MII Bus"; + new_bus->read = &fs_enet_fec_mii_read; + new_bus->write = &fs_enet_fec_mii_write; + new_bus->reset = &fs_enet_fec_mii_reset; + + ret = of_address_to_resource(ofdev->node, 0, &res); + if (ret) + return ret; + + new_bus->id = res.start; + + fec->fecp = ioremap(res.start, res.end - res.start + 1); + if (!fec->fecp) + goto out_fec; + + fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 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); + + new_bus->phy_mask = ~0; + new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!new_bus->irq) + goto out_unmap_regs; + + for (i = 0; i < PHY_MAX_ADDR; i++) + new_bus->irq[i] = -1; + + while ((np = of_get_next_child(ofdev->node, np))) + if (!strcmp(np->type, "ethernet-phy")) + add_phy(new_bus, np); + + new_bus->dev = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); + + ret = mdiobus_register(new_bus); + if (ret) + goto out_free_irqs; + + return 0; + +out_free_irqs: + dev_set_drvdata(&ofdev->dev, NULL); + kfree(new_bus->irq); +out_unmap_regs: + iounmap(fec->fecp); +out_fec: + kfree(fec); +out_mii: + kfree(new_bus); +out: + return ret; +} + +static int fs_enet_mdio_remove(struct of_device *ofdev) +{ + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct fec_info *fec = bus->priv; + + mdiobus_unregister(bus); + dev_set_drvdata(&ofdev->dev, NULL); + kfree(bus->irq); + iounmap(fec->fecp); + kfree(fec); + kfree(bus); + + return 0; +} + +static struct of_device_id fs_enet_mdio_fec_match[] = { + { + .compatible = "fsl,pq1-fec-mdio", + }, + {}, +}; + +static struct of_platform_driver fs_enet_fec_mdio_driver = { + .name = "fsl-fec-mdio", + .match_table = fs_enet_mdio_fec_match, + .probe = fs_enet_mdio_probe, + .remove = fs_enet_mdio_remove, +}; + +static int fs_enet_mdio_fec_init(void) +{ + return of_register_platform_driver(&fs_enet_fec_mdio_driver); +} + +static void fs_enet_mdio_fec_exit(void) +{ + of_unregister_platform_driver(&fs_enet_fec_mdio_driver); +} + +module_init(fs_enet_mdio_fec_init); +module_exit(fs_enet_mdio_fec_exit); +#else static int __devinit fs_enet_fec_mdio_probe(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -235,4 +376,4 @@ void fs_enet_mdio_fec_exit(void) { driver_unregister(&fs_enet_fec_mdio_driver); } - +#endif diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h index 815c6f94378b..9bc045b8c478 100644 --- a/include/linux/fs_enet_pd.h +++ b/include/linux/fs_enet_pd.h @@ -120,6 +120,7 @@ struct fs_platform_info { u32 cp_page; /* CPM page */ u32 cp_block; /* CPM sblock */ + u32 cp_command; /* CPM page/sblock/mcn */ u32 clk_trx; /* some stuff for pins & mux configuration*/ u32 clk_rx; @@ -134,7 +135,11 @@ struct fs_platform_info { u32 device_flags; int phy_addr; /* the phy address (-1 no phy) */ +#ifdef CONFIG_PPC_CPM_NEW_BINDING + char bus_id[16]; +#else const char* bus_id; +#endif int phy_irq; /* the phy irq (if it exists) */ const struct fs_mii_bus_info *bus_info; From e2ec4581adf7e288c193e981c39ca01cdb20a272 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:56 -0500 Subject: [PATCH 1657/2804] Generic bitbanged MDIO library Previously, bitbanged MDIO was only supported in individual hardware-specific drivers. This code factors out the higher level protocol implementation, reducing the hardware-specific portion to functions setting direction, data, and clock. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/phy/Kconfig | 9 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/mdio-bitbang.c | 187 +++++++++++++++++++++++++++++++++ include/linux/mdio-bitbang.h | 42 ++++++++ 4 files changed, 239 insertions(+) create mode 100644 drivers/net/phy/mdio-bitbang.c create mode 100644 include/linux/mdio-bitbang.h diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 432c210513be..54b2ba996640 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -90,4 +90,13 @@ config FIXED_MII_AMNT This control will have specified number allocated for each fixed PHY type enabled. +config MDIO_BITBANG + tristate "Support for bitbanged MDIO buses" + help + This module implements the MDIO bus protocol in software, + for use by low level drivers that export the ability to + drive the relevant pins. + + If in doubt, say N. + endif # PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 8885650647ff..3d6cc7b67a80 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_FIXED_PHY) += fixed.o +obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c new file mode 100644 index 000000000000..8cd243d92af3 --- /dev/null +++ b/drivers/net/phy/mdio-bitbang.c @@ -0,0 +1,187 @@ +/* + * Bitbanged MDIO support. + * + * Author: Scott Wood + * Copyright (c) 2007 Freescale Semiconductor + * + * Based on CPM2 MDIO code which is: + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#define MDIO_READ 1 +#define MDIO_WRITE 0 + +#define MDIO_SETUP_TIME 10 +#define MDIO_HOLD_TIME 10 + +/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY + * is done twice per period. + */ +#define MDIO_DELAY 250 + +/* The PHY may take up to 300 ns to produce data, plus some margin + * for error. + */ +#define MDIO_READ_DELAY 350 + +/* MDIO must already be configured as output. */ +static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val) +{ + const struct mdiobb_ops *ops = ctrl->ops; + + ops->set_mdio_data(ctrl, val); + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 1); + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 0); +} + +/* MDIO must already be configured as input. */ +static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl) +{ + const struct mdiobb_ops *ops = ctrl->ops; + + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 1); + ndelay(MDIO_READ_DELAY); + ops->set_mdc(ctrl, 0); + + return ops->get_mdio_data(ctrl); +} + +/* MDIO must already be configured as output. */ +static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits) +{ + int i; + + for (i = bits - 1; i >= 0; i--) + mdiobb_send_bit(ctrl, (val >> i) & 1); +} + +/* MDIO must already be configured as input. */ +static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits) +{ + int i; + u16 ret = 0; + + for (i = bits - 1; i >= 0; i--) { + ret <<= 1; + ret |= mdiobb_get_bit(ctrl); + } + + return ret; +} + +/* Utility to send the preamble, address, and + * register (common to read and write). + */ +static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg) +{ + const struct mdiobb_ops *ops = ctrl->ops; + int i; + + ops->set_mdio_dir(ctrl, 1); + + /* + * Send a 32 bit preamble ('1's) with an extra '1' bit for good + * measure. The IEEE spec says this is a PHY optional + * requirement. The AMD 79C874 requires one after power up and + * one after a MII communications error. This means that we are + * doing more preambles than we need, but it is safer and will be + * much more robust. + */ + + for (i = 0; i < 32; i++) + mdiobb_send_bit(ctrl, 1); + + /* send the start bit (01) and the read opcode (10) or write (10) */ + mdiobb_send_bit(ctrl, 0); + mdiobb_send_bit(ctrl, 1); + mdiobb_send_bit(ctrl, read); + mdiobb_send_bit(ctrl, !read); + + mdiobb_send_num(ctrl, phy, 5); + mdiobb_send_num(ctrl, reg, 5); +} + + +static int mdiobb_read(struct mii_bus *bus, int phy, int reg) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + int ret, i; + + mdiobb_cmd(ctrl, MDIO_READ, phy, reg); + ctrl->ops->set_mdio_dir(ctrl, 0); + + /* check the turnaround bit: the PHY should be driving it to zero */ + if (mdiobb_get_bit(ctrl) != 0) { + /* PHY didn't drive TA low -- flush any bits it + * may be trying to send. + */ + for (i = 0; i < 32; i++) + mdiobb_get_bit(ctrl); + + return 0xffff; + } + + ret = mdiobb_get_num(ctrl, 16); + mdiobb_get_bit(ctrl); + return ret; +} + +static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); + + /* send the turnaround (10) */ + mdiobb_send_bit(ctrl, 1); + mdiobb_send_bit(ctrl, 0); + + mdiobb_send_num(ctrl, val, 16); + + ctrl->ops->set_mdio_dir(ctrl, 0); + mdiobb_get_bit(ctrl); + return 0; +} + +struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) +{ + struct mii_bus *bus; + + bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + if (!bus) + return NULL; + + __module_get(ctrl->ops->owner); + + bus->read = mdiobb_read; + bus->write = mdiobb_write; + bus->priv = ctrl; + + return bus; +} + +void free_mdio_bitbang(struct mii_bus *bus) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + module_put(ctrl->ops->owner); + kfree(bus); +} diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h new file mode 100644 index 000000000000..8ea9a42a4c02 --- /dev/null +++ b/include/linux/mdio-bitbang.h @@ -0,0 +1,42 @@ +#ifndef __LINUX_MDIO_BITBANG_H +#define __LINUX_MDIO_BITBANG_H + +#include +#include + +struct mdiobb_ctrl; + +struct mdiobb_ops { + struct module *owner; + + /* Set the Management Data Clock high if level is one, + * low if level is zero. + */ + void (*set_mdc)(struct mdiobb_ctrl *ctrl, int level); + + /* Configure the Management Data I/O pin as an input if + * "output" is zero, or an output if "output" is one. + */ + void (*set_mdio_dir)(struct mdiobb_ctrl *ctrl, int output); + + /* Set the Management Data I/O pin high if value is one, + * low if "value" is zero. This may only be called + * when the MDIO pin is configured as an output. + */ + void (*set_mdio_data)(struct mdiobb_ctrl *ctrl, int value); + + /* Retrieve the state Management Data I/O pin. */ + int (*get_mdio_data)(struct mdiobb_ctrl *ctrl); +}; + +struct mdiobb_ctrl { + const struct mdiobb_ops *ops; +}; + +/* The returned bus is not yet registered with the phy layer. */ +struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl); + +/* The bus must already have been unregistered. */ +void free_mdio_bitbang(struct mii_bus *bus); + +#endif From 2b5b3a604a672be1d41728ed9e448ca3c9c23242 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:57 -0500 Subject: [PATCH 1658/2804] fs_enet: Convert mii-bitbang to use the generic bitbang MDIO code. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/mii-bitbang.c | 276 ++++++------------------------ 1 file changed, 57 insertions(+), 219 deletions(-) diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 7cf132f0f952..b8e4a736a130 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -15,15 +15,13 @@ #include #include #include -#include #include -#include +#include #include #include #include -#include -#include #include +#include #ifdef CONFIG_PPC_CPM_NEW_BINDING #include @@ -32,11 +30,11 @@ #include "fs_enet.h" struct bb_info { + struct mdiobb_ctrl ctrl; __be32 __iomem *dir; __be32 __iomem *dat; u32 mdio_msk; u32 mdc_msk; - int delay; }; /* FIXME: If any other users of GPIO crop up, then these will have to @@ -59,212 +57,58 @@ static inline int bb_read(u32 __iomem *p, u32 m) return (in_be32(p) & m) != 0; } -static inline void mdio_active(struct bb_info *bitbang) +static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) { - bb_set(bitbang->dir, bitbang->mdio_msk); + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + + if (dir) + bb_set(bitbang->dir, bitbang->mdio_msk); + else + bb_clr(bitbang->dir, bitbang->mdio_msk); + + /* Read back to flush the write. */ + in_be32(bitbang->dir); } -static inline void mdio_tristate(struct bb_info *bitbang) -{ - bb_clr(bitbang->dir, bitbang->mdio_msk); -} - -static inline int mdio_read(struct bb_info *bitbang) +static inline int mdio_read(struct mdiobb_ctrl *ctrl) { + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); return bb_read(bitbang->dat, bitbang->mdio_msk); } -static inline void mdio(struct bb_info *bitbang, int what) +static inline void mdio(struct mdiobb_ctrl *ctrl, int what) { + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + if (what) bb_set(bitbang->dat, bitbang->mdio_msk); else bb_clr(bitbang->dat, bitbang->mdio_msk); + + /* Read back to flush the write. */ + in_be32(bitbang->dat); } -static inline void mdc(struct bb_info *bitbang, int what) +static inline void mdc(struct mdiobb_ctrl *ctrl, int what) { + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + if (what) bb_set(bitbang->dat, bitbang->mdc_msk); else bb_clr(bitbang->dat, bitbang->mdc_msk); + + /* Read back to flush the write. */ + in_be32(bitbang->dat); } -static inline void mii_delay(struct bb_info *bitbang) -{ - udelay(bitbang->delay); -} - -/* Utility to send the preamble, address, and register (common to read and write). */ -static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg) -{ - int j; - - /* - * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. - * The IEEE spec says this is a PHY optional requirement. The AMD - * 79C874 requires one after power up and one after a MII communications - * error. This means that we are doing more preambles than we need, - * but it is safer and will be much more robust. - */ - - mdio_active(bitbang); - mdio(bitbang, 1); - for (j = 0; j < 32; j++) { - mdc(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - } - - /* send the start bit (01) and the read opcode (10) or write (10) */ - mdc(bitbang, 0); - mdio(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mdio(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mdio(bitbang, read); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mdio(bitbang, !read); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - - /* send the PHY address */ - for (j = 0; j < 5; j++) { - mdc(bitbang, 0); - mdio(bitbang, (addr & 0x10) != 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - addr <<= 1; - } - - /* send the register address */ - for (j = 0; j < 5; j++) { - mdc(bitbang, 0); - mdio(bitbang, (reg & 0x10) != 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - reg <<= 1; - } -} - -static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location) -{ - u16 rdreg; - int ret, j; - u8 addr = phy_id & 0xff; - u8 reg = location & 0xff; - struct bb_info* bitbang = bus->priv; - - bitbang_pre(bitbang, 1, addr, reg); - - /* tri-state our MDIO I/O pin so we can read */ - mdc(bitbang, 0); - mdio_tristate(bitbang); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - - /* check the turnaround bit: the PHY should be driving it to zero */ - if (mdio_read(bitbang) != 0) { - /* PHY didn't drive TA low */ - for (j = 0; j < 32; j++) { - mdc(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - } - ret = -1; - goto out; - } - - mdc(bitbang, 0); - mii_delay(bitbang); - - /* read 16 bits of register data, MSB first */ - rdreg = 0; - for (j = 0; j < 16; j++) { - mdc(bitbang, 1); - mii_delay(bitbang); - rdreg <<= 1; - rdreg |= mdio_read(bitbang); - mdc(bitbang, 0); - mii_delay(bitbang); - } - - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - - ret = rdreg; -out: - return ret; -} - -static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val) -{ - int j; - struct bb_info* bitbang = bus->priv; - - u8 addr = phy_id & 0xff; - u8 reg = location & 0xff; - u16 value = val & 0xffff; - - bitbang_pre(bitbang, 0, addr, reg); - - /* send the turnaround (10) */ - mdc(bitbang, 0); - mdio(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mdio(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - - /* write 16 bits of register data, MSB first */ - for (j = 0; j < 16; j++) { - mdc(bitbang, 0); - mdio(bitbang, (value & 0x8000) != 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - value <<= 1; - } - - /* - * Tri-state the MDIO line. - */ - mdio_tristate(bitbang); - mdc(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - return 0; -} - -static int fs_enet_mii_bb_reset(struct mii_bus *bus) -{ - /*nothing here - dunno how to reset it*/ - return 0; -} +static struct mdiobb_ops bb_ops = { + .owner = THIS_MODULE, + .set_mdc = mdc, + .set_mdio_dir = mdio_dir, + .set_mdio_data = mdio, + .get_mdio_data = mdio_read, +}; #ifdef CONFIG_PPC_CPM_NEW_BINDING static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, @@ -305,7 +149,6 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, bitbang->dat = bitbang->dir + 4; bitbang->mdio_msk = 1 << (31 - mdio_pin); bitbang->mdc_msk = 1 << (31 - mdc_pin); - bitbang->delay = 1; /* 1 us between operations */ return 0; } @@ -336,23 +179,21 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, int ret = -ENOMEM; int i; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - if (!new_bus) - goto out; - bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); if (!bitbang) - goto out_free_bus; + goto out; + + bitbang->ctrl.ops = &bb_ops; + + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + if (!new_bus) + goto out_free_priv; - new_bus->priv = bitbang; new_bus->name = "CPM2 Bitbanged MII", - new_bus->read = &fs_enet_mii_bb_read, - new_bus->write = &fs_enet_mii_bb_write, - new_bus->reset = &fs_enet_mii_bb_reset, ret = fs_mii_bitbang_init(new_bus, ofdev->node); if (ret) - goto out_free_bitbang; + goto out_free_bus; new_bus->phy_mask = ~0; new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); @@ -380,10 +221,10 @@ out_free_irqs: kfree(new_bus->irq); out_unmap_regs: iounmap(bitbang->dir); -out_free_bitbang: - kfree(bitbang); out_free_bus: kfree(new_bus); +out_free_priv: + free_mdio_bitbang(new_bus); out: return ret; } @@ -394,6 +235,7 @@ static int fs_enet_mdio_remove(struct of_device *ofdev) struct bb_info *bitbang = bus->priv; mdiobus_unregister(bus); + free_mdio_bitbang(bus); dev_set_drvdata(&ofdev->dev, NULL); kfree(bus->irq); iounmap(bitbang->dir); @@ -417,12 +259,12 @@ static struct of_platform_driver fs_enet_bb_mdio_driver = { .remove = fs_enet_mdio_remove, }; -int fs_enet_mdio_bb_init(void) +static int fs_enet_mdio_bb_init(void) { return of_register_platform_driver(&fs_enet_bb_mdio_driver); } -void fs_enet_mdio_bb_exit(void) +static void fs_enet_mdio_bb_exit(void) { of_unregister_platform_driver(&fs_enet_bb_mdio_driver); } @@ -437,7 +279,6 @@ static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang, bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset; bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit); bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit); - bitbang->delay = fmpi->delay; return 0; } @@ -453,20 +294,19 @@ static int __devinit fs_enet_mdio_probe(struct device *dev) if (NULL == dev) return -EINVAL; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - - if (NULL == new_bus) - return -ENOMEM; - bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); if (NULL == bitbang) return -ENOMEM; + bitbang->ctrl.ops = &bb_ops; + + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + + if (NULL == new_bus) + return -ENOMEM; + new_bus->name = "BB MII Bus", - new_bus->read = &fs_enet_mii_bb_read, - new_bus->write = &fs_enet_mii_bb_write, - new_bus->reset = &fs_enet_mii_bb_reset, new_bus->id = pdev->id; new_bus->phy_mask = ~0x9; @@ -498,8 +338,8 @@ static int __devinit fs_enet_mdio_probe(struct device *dev) return 0; bus_register_fail: + free_mdio_bitbang(new_bus); kfree(bitbang); - kfree(new_bus); return err; } @@ -512,9 +352,7 @@ static int fs_enet_mdio_remove(struct device *dev) dev_set_drvdata(dev, NULL); - iounmap((void *) (&bus->priv)); - bus->priv = NULL; - kfree(bus); + free_mdio_bitbang(bus); return 0; } @@ -535,4 +373,4 @@ void fs_enet_mdio_bb_exit(void) { driver_unregister(&fs_enet_bb_mdio_driver); } - +#endif From 31a5bb04d59931eb4657826213a439d37d12d4a9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:58 -0500 Subject: [PATCH 1659/2804] fs_enet: sparse fixes Mostly a bunch of __iomem annotations. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 18 ++++---- drivers/net/fs_enet/fs_enet.h | 30 ++++++------- drivers/net/fs_enet/mac-fcc.c | 71 ++++++++++++++++-------------- drivers/net/fs_enet/mac-fec.c | 34 +++++++------- drivers/net/fs_enet/mac-scc.c | 37 ++++++++-------- drivers/net/fs_enet/mii-fec.c | 8 ++-- 6 files changed, 103 insertions(+), 95 deletions(-) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index fc4fda805d44..04c6faec88d2 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -60,7 +60,7 @@ MODULE_DESCRIPTION("Freescale Ethernet Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); -int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ +static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ module_param(fs_enet_debug, int, 0); MODULE_PARM_DESC(fs_enet_debug, "Freescale bitmapped debugging message enable value"); @@ -90,7 +90,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); struct net_device *dev = to_net_dev(fep->dev); const struct fs_platform_info *fpi = fep->fpi; - cbd_t *bdp; + cbd_t __iomem *bdp; struct sk_buff *skb, *skbn, *skbt; int received = 0; u16 pkt_len, sc; @@ -230,7 +230,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - cbd_t *bdp; + cbd_t __iomem *bdp; struct sk_buff *skb, *skbn, *skbt; int received = 0; u16 pkt_len, sc; @@ -355,7 +355,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) static void fs_enet_tx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; + cbd_t __iomem *bdp; struct sk_buff *skb; int dirtyidx, do_wake, do_restart; u16 sc; @@ -503,7 +503,7 @@ fs_enet_interrupt(int irq, void *dev_id) void fs_init_bds(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; + cbd_t __iomem *bdp; struct sk_buff *skb; int i; @@ -557,7 +557,7 @@ void fs_cleanup_bds(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); struct sk_buff *skb; - cbd_t *bdp; + cbd_t __iomem *bdp; int i; /* @@ -598,7 +598,7 @@ void fs_cleanup_bds(struct net_device *dev) static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; + cbd_t __iomem *bdp; int curidx; u16 sc; unsigned long flags; @@ -1121,7 +1121,7 @@ static int fs_cleanup_instance(struct net_device *ndev) unregister_netdev(ndev); dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, fep->ring_mem_addr); + (void __force *)fep->ring_base, fep->ring_mem_addr); /* reset it */ (*fep->ops->cleanup_data)(ndev); @@ -1141,7 +1141,7 @@ static int fs_cleanup_instance(struct net_device *ndev) /**************************************************************************************/ /* handy pointer to the immap */ -void *fs_enet_immap = NULL; +void __iomem *fs_enet_immap = NULL; static int setup_immap(void) { diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 5a5c9d18df2e..baf6477165af 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -15,7 +15,7 @@ #include struct fec_info { - fec_t *fecp; + fec_t __iomem *fecp; u32 mii_speed; }; #endif @@ -81,14 +81,14 @@ struct fs_enet_private { const struct fs_ops *ops; int rx_ring, tx_ring; dma_addr_t ring_mem_addr; - void *ring_base; + void __iomem *ring_base; struct sk_buff **rx_skbuff; struct sk_buff **tx_skbuff; - cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ - cbd_t *tx_bd_base; - cbd_t *dirty_tx; /* ring entries to be free()ed. */ - cbd_t *cur_rx; - cbd_t *cur_tx; + cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t __iomem *tx_bd_base; + cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */ + cbd_t __iomem *cur_rx; + cbd_t __iomem *cur_tx; int tx_free; struct net_device_stats stats; struct timer_list phy_timer_list; @@ -113,23 +113,23 @@ struct fs_enet_private { union { struct { int idx; /* FEC1 = 0, FEC2 = 1 */ - void *fecp; /* hw registers */ + void __iomem *fecp; /* hw registers */ u32 hthi, htlo; /* state for multicast */ } fec; struct { int idx; /* FCC1-3 = 0-2 */ - void *fccp; /* hw registers */ - void *ep; /* parameter ram */ - void *fcccp; /* hw registers cont. */ - void *mem; /* FCC DPRAM */ + void __iomem *fccp; /* hw registers */ + void __iomem *ep; /* parameter ram */ + void __iomem *fcccp; /* hw registers cont. */ + void __iomem *mem; /* FCC DPRAM */ u32 gaddrh, gaddrl; /* group address */ } fcc; struct { int idx; /* FEC1 = 0, FEC2 = 1 */ - void *sccp; /* hw registers */ - void *ep; /* parameter ram */ + void __iomem *sccp; /* hw registers */ + void __iomem *ep; /* parameter ram */ u32 hthi, htlo; /* state for multicast */ } scc; @@ -200,7 +200,7 @@ extern const struct fs_ops fs_scc_ops; /*******************************************************************/ /* handy pointer to the immap */ -extern void *fs_enet_immap; +extern void __iomem *fs_enet_immap; /*******************************************************************/ diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 6094cbf542a2..da4efbca646e 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -81,8 +81,6 @@ static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op) { const struct fs_platform_info *fpi = fep->fpi; - cpm2_map_t *immap = fs_enet_immap; - cpm_cpm2_t *cpmp = &immap->im_cpm; int i; W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG); @@ -118,8 +116,8 @@ static int do_pd_setup(struct fs_enet_private *fep) if (!fep->fcc.fcccp) goto out_ep; - fep->fcc.mem = (void *)cpm_dpalloc(128, 8); - fpi->dpram_offset = (u32)cpm2_immr; + fep->fcc.mem = (void __iomem *)cpm2_immr; + fpi->dpram_offset = cpm_dpalloc(128, 8); if (IS_ERR_VALUE(fpi->dpram_offset)) { ret = fpi->dpram_offset; goto out_fcccp; @@ -146,29 +144,28 @@ out: /* Attach the memory for the FCC Parameter RAM */ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); - fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1); + fep->fcc.ep = ioremap(r->start, r->end - r->start + 1); if (fep->fcc.ep == NULL) return -EINVAL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); - fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1); + fep->fcc.fccp = ioremap(r->start, r->end - r->start + 1); if (fep->fcc.fccp == NULL) return -EINVAL; if (fep->fpi->fcc_regs_c) { - - fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; + fep->fcc.fcccp = (void __iomem *)fep->fpi->fcc_regs_c; } else { r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs_c"); - fep->fcc.fcccp = (void *)ioremap(r->start, + fep->fcc.fcccp = ioremap(r->start, r->end - r->start + 1); } if (fep->fcc.fcccp == NULL) return -EINVAL; - fep->fcc.mem = (void *)fep->fpi->mem_offset; + fep->fcc.mem = (void __iomem *)fep->fpi->mem_offset; if (fep->fcc.mem == NULL) return -EINVAL; @@ -212,7 +209,7 @@ static int allocate_bd(struct net_device *dev) struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - fep->ring_base = dma_alloc_coherent(fep->dev, + fep->ring_base = (void __iomem __force *)dma_alloc_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), &fep->ring_mem_addr, GFP_KERNEL); @@ -230,7 +227,7 @@ static void free_bd(struct net_device *dev) if (fep->ring_base) dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, fep->ring_mem_addr); + (void __force *)fep->ring_base, fep->ring_mem_addr); } static void cleanup_data(struct net_device *dev) @@ -241,7 +238,7 @@ static void cleanup_data(struct net_device *dev) static void set_promiscuous_mode(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); } @@ -249,7 +246,7 @@ static void set_promiscuous_mode(struct net_device *dev) static void set_multicast_start(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_enet_t *ep = fep->fcc.ep; + fcc_enet_t __iomem *ep = fep->fcc.ep; W32(ep, fen_gaddrh, 0); W32(ep, fen_gaddrl, 0); @@ -258,7 +255,7 @@ static void set_multicast_start(struct net_device *dev) static void set_multicast_one(struct net_device *dev, const u8 *mac) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_enet_t *ep = fep->fcc.ep; + fcc_enet_t __iomem *ep = fep->fcc.ep; u16 taddrh, taddrm, taddrl; taddrh = ((u16)mac[5] << 8) | mac[4]; @@ -274,8 +271,8 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac) static void set_multicast_finish(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - fcc_enet_t *ep = fep->fcc.ep; + fcc_t __iomem *fccp = fep->fcc.fccp; + fcc_enet_t __iomem *ep = fep->fcc.ep; /* clear promiscuous always */ C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); @@ -310,12 +307,14 @@ static void restart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - fcc_t *fccp = fep->fcc.fccp; - fcc_c_t *fcccp = fep->fcc.fcccp; - fcc_enet_t *ep = fep->fcc.ep; + fcc_t __iomem *fccp = fep->fcc.fccp; + fcc_c_t __iomem *fcccp = fep->fcc.fcccp; + fcc_enet_t __iomem *ep = fep->fcc.ep; dma_addr_t rx_bd_base_phys, tx_bd_base_phys; u16 paddrh, paddrm, paddrl; +#ifndef CONFIG_PPC_CPM_NEW_BINDING u16 mem_addr; +#endif const unsigned char *mac; int i; @@ -347,14 +346,22 @@ static void restart(struct net_device *dev) * this area. */ +#ifdef CONFIG_PPC_CPM_NEW_BINDING + W16(ep, fen_genfcc.fcc_riptr, fpi->dpram_offset); + W16(ep, fen_genfcc.fcc_tiptr, fpi->dpram_offset + 32); + + W16(ep, fen_padptr, fpi->dpram_offset + 64); +#else mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */ W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff)); W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff)); + W16(ep, fen_padptr, mem_addr + 64); +#endif /* fill with special symbol... */ - memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); + memset_io(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); W32(ep, fen_genfcc.fcc_rbptr, 0); W32(ep, fen_genfcc.fcc_tbptr, 0); @@ -470,7 +477,7 @@ static void restart(struct net_device *dev) static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; /* stop ethernet */ C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); @@ -497,7 +504,7 @@ static void post_free_irq(struct net_device *dev, int irq) static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); } @@ -505,7 +512,7 @@ static void napi_clear_rx_event(struct net_device *dev) static void napi_enable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); } @@ -513,7 +520,7 @@ static void napi_enable_rx(struct net_device *dev) static void napi_disable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); } @@ -526,7 +533,7 @@ static void rx_bd_done(struct net_device *dev) static void tx_kickstart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; S16(fccp, fcc_ftodr, 0x8000); } @@ -534,7 +541,7 @@ static void tx_kickstart(struct net_device *dev) static u32 get_int_events(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; return (u32)R16(fccp, fcc_fcce); } @@ -542,7 +549,7 @@ static u32 get_int_events(struct net_device *dev) static void clear_int_events(struct net_device *dev, u32 int_events) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; W16(fccp, fcc_fcce, int_events & 0xffff); } @@ -553,7 +560,7 @@ static void ev_error(struct net_device *dev, u32 int_events) ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events); } -int get_regs(struct net_device *dev, void *p, int *sizep) +static int get_regs(struct net_device *dev, void *p, int *sizep) { struct fs_enet_private *fep = netdev_priv(dev); @@ -570,7 +577,7 @@ int get_regs(struct net_device *dev, void *p, int *sizep) return 0; } -int get_regs_len(struct net_device *dev) +static int get_regs_len(struct net_device *dev) { return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1; } @@ -583,10 +590,10 @@ int get_regs_len(struct net_device *dev) * CPM37, we must disable and then re-enable the transmitter * following a Late Collision, Underrun, or Retry Limit error. */ -void tx_restart(struct net_device *dev) +static void tx_restart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; C32(fccp, fcc_gfmr, FCC_GFMR_ENT); udelay(10); diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 924d6617cd30..c1fee48517e3 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -83,7 +83,7 @@ */ #define FEC_RESET_DELAY 50 -static int whack_reset(fec_t * fecp) +static int whack_reset(fec_t __iomem *fecp) { int i; @@ -159,7 +159,7 @@ static int allocate_bd(struct net_device *dev) struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - fep->ring_base = dma_alloc_coherent(fep->dev, + fep->ring_base = (void __force __iomem *)dma_alloc_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), &fep->ring_mem_addr, GFP_KERNEL); @@ -177,7 +177,7 @@ static void free_bd(struct net_device *dev) if(fep->ring_base) dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, + (void __force *)fep->ring_base, fep->ring_mem_addr); } @@ -189,7 +189,7 @@ static void cleanup_data(struct net_device *dev) static void set_promiscuous_mode(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FS(fecp, r_cntrl, FEC_RCNTRL_PROM); } @@ -237,7 +237,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac) static void set_multicast_finish(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; /* if all multi or too many multicasts; just enable all */ if ((dev->flags & IFF_ALLMULTI) != 0 || @@ -271,7 +271,7 @@ static void restart(struct net_device *dev) u32 cptr; #endif struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; const struct fs_platform_info *fpi = fep->fpi; dma_addr_t rx_bd_base_phys, tx_bd_base_phys; int r; @@ -399,7 +399,7 @@ static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; struct fec_info* feci= fep->phydev->bus->priv; @@ -461,7 +461,7 @@ static void post_free_irq(struct net_device *dev, int irq) static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); } @@ -469,7 +469,7 @@ static void napi_clear_rx_event(struct net_device *dev) static void napi_enable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); } @@ -477,7 +477,7 @@ static void napi_enable_rx(struct net_device *dev) static void napi_disable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); } @@ -485,7 +485,7 @@ static void napi_disable_rx(struct net_device *dev) static void rx_bd_done(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FW(fecp, r_des_active, 0x01000000); } @@ -493,7 +493,7 @@ static void rx_bd_done(struct net_device *dev) static void tx_kickstart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FW(fecp, x_des_active, 0x01000000); } @@ -501,7 +501,7 @@ static void tx_kickstart(struct net_device *dev) static u32 get_int_events(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; return FR(fecp, ievent) & FR(fecp, imask); } @@ -509,7 +509,7 @@ static u32 get_int_events(struct net_device *dev) static void clear_int_events(struct net_device *dev, u32 int_events) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FW(fecp, ievent, int_events); } @@ -520,7 +520,7 @@ static void ev_error(struct net_device *dev, u32 int_events) ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events); } -int get_regs(struct net_device *dev, void *p, int *sizep) +static int get_regs(struct net_device *dev, void *p, int *sizep) { struct fs_enet_private *fep = netdev_priv(dev); @@ -532,12 +532,12 @@ int get_regs(struct net_device *dev, void *p, int *sizep) return 0; } -int get_regs_len(struct net_device *dev) +static int get_regs_len(struct net_device *dev) { return sizeof(fec_t); } -void tx_restart(struct net_device *dev) +static void tx_restart(struct net_device *dev) { /* nothing */ } diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index add9e32d4f47..03134f47a4eb 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -191,7 +191,8 @@ static int allocate_bd(struct net_device *dev) if (IS_ERR_VALUE(fep->ring_mem_addr)) return -ENOMEM; - fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr); + fep->ring_base = (void __iomem __force*) + cpm_dpram_addr(fep->ring_mem_addr); return 0; } @@ -212,7 +213,7 @@ static void cleanup_data(struct net_device *dev) static void set_promiscuous_mode(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; S16(sccp, scc_psmr, SCC_PSMR_PRO); } @@ -220,7 +221,7 @@ static void set_promiscuous_mode(struct net_device *dev) static void set_multicast_start(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_enet_t *ep = fep->scc.ep; + scc_enet_t __iomem *ep = fep->scc.ep; W16(ep, sen_gaddr1, 0); W16(ep, sen_gaddr2, 0); @@ -231,7 +232,7 @@ static void set_multicast_start(struct net_device *dev) static void set_multicast_one(struct net_device *dev, const u8 * mac) { struct fs_enet_private *fep = netdev_priv(dev); - scc_enet_t *ep = fep->scc.ep; + scc_enet_t __iomem *ep = fep->scc.ep; u16 taddrh, taddrm, taddrl; taddrh = ((u16) mac[5] << 8) | mac[4]; @@ -247,8 +248,8 @@ static void set_multicast_one(struct net_device *dev, const u8 * mac) static void set_multicast_finish(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - scc_enet_t *ep = fep->scc.ep; + scc_t __iomem *sccp = fep->scc.sccp; + scc_enet_t __iomem *ep = fep->scc.ep; /* clear promiscuous always */ C16(sccp, scc_psmr, SCC_PSMR_PRO); @@ -285,8 +286,8 @@ static void set_multicast_list(struct net_device *dev) static void restart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - scc_enet_t *ep = fep->scc.ep; + scc_t __iomem *sccp = fep->scc.sccp; + scc_enet_t __iomem *ep = fep->scc.ep; const struct fs_platform_info *fpi = fep->fpi; u16 paddrh, paddrm, paddrl; const unsigned char *mac; @@ -296,7 +297,7 @@ static void restart(struct net_device *dev) /* clear everything (slow & steady does it) */ for (i = 0; i < sizeof(*ep); i++) - __fs_out8((char *)ep + i, 0); + __fs_out8((u8 __iomem *)ep + i, 0); /* point to bds */ W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); @@ -397,7 +398,7 @@ static void restart(struct net_device *dev) static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; int i; for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) @@ -441,7 +442,7 @@ static void post_free_irq(struct net_device *dev, int irq) static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); } @@ -449,7 +450,7 @@ static void napi_clear_rx_event(struct net_device *dev) static void napi_enable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); } @@ -457,7 +458,7 @@ static void napi_enable_rx(struct net_device *dev) static void napi_disable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); } @@ -475,7 +476,7 @@ static void tx_kickstart(struct net_device *dev) static u32 get_int_events(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; return (u32) R16(sccp, scc_scce); } @@ -483,7 +484,7 @@ static u32 get_int_events(struct net_device *dev) static void clear_int_events(struct net_device *dev, u32 int_events) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; W16(sccp, scc_scce, int_events & 0xffff); } @@ -498,20 +499,20 @@ static int get_regs(struct net_device *dev, void *p, int *sizep) { struct fs_enet_private *fep = netdev_priv(dev); - if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t)) + if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t __iomem *)) return -EINVAL; memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); p = (char *)p + sizeof(scc_t); - memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t)); + memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t __iomem *)); return 0; } static int get_regs_len(struct net_device *dev) { - return sizeof(scc_t) + sizeof(scc_enet_t); + return sizeof(scc_t) + sizeof(scc_enet_t __iomem *); } static void tx_restart(struct net_device *dev) diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index f91c38d0b57b..a89cf15090b8 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -70,7 +70,7 @@ static int match_has_phy (struct device *dev, void* data) static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi) { struct resource *r; - fec_t *fecp; + fec_t __iomem *fecp; char* name = "fsl-cpm-fec"; /* we need fec in order to be useful */ @@ -85,7 +85,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs"); - fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t)); + fec->fecp = fecp = ioremap(r->start,sizeof(fec_t)); fec->mii_speed = fmpi->mii_speed; setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ @@ -100,7 +100,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) { struct fec_info* fec = bus->priv; - fec_t *fecp = fec->fecp; + fec_t __iomem *fecp = fec->fecp; int i, ret = -1; if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) @@ -124,7 +124,7 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) { struct fec_info* fec = bus->priv; - fec_t *fecp = fec->fecp; + fec_t __iomem *fecp = fec->fecp; int i; /* this must never happen */ From 2c69448bbcedebeb8409ddb05fbc7d3fe1cfbda7 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Mon, 1 Oct 2007 16:33:18 +0200 Subject: [PATCH 1660/2804] ehea: DLPAR memory add fix Due to stability issues in high load situations the HW queue handling has to be changed. The HW queues are now stopped and restarted again instead of destroying and allocating new HW queues. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea.h | 4 +- drivers/net/ehea/ehea_main.c | 278 +++++++++++++++++++++++++++++++---- drivers/net/ehea/ehea_phyp.h | 1 + drivers/net/ehea/ehea_qmr.c | 20 +-- drivers/net/ehea/ehea_qmr.h | 4 +- 5 files changed, 260 insertions(+), 47 deletions(-) diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index c0cbd949e336..30220894b01f 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,13 +40,13 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0074" +#define DRV_VERSION "EHEA_0077" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 #define DLPAR_MEM_ADD 2 #define DLPAR_MEM_REM 4 -#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM) +#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD) #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 62d6c1e5f9d3..5bc0a1530eb7 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -97,6 +97,7 @@ u64 ehea_driver_flags = 0; struct workqueue_struct *ehea_driver_wq; struct work_struct ehea_rereg_mr_task; +struct semaphore dlpar_mem_lock; static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, const struct of_device_id *id); @@ -177,16 +178,24 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes) struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr; struct net_device *dev = pr->port->netdev; int max_index_mask = pr->rq1_skba.len - 1; + int fill_wqes = pr->rq1_skba.os_skbs + nr_of_wqes; + int adder = 0; int i; - if (!nr_of_wqes) - return; + pr->rq1_skba.os_skbs = 0; - for (i = 0; i < nr_of_wqes; i++) { + if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { + pr->rq1_skba.index = index; + pr->rq1_skba.os_skbs = fill_wqes; + return; + } + + for (i = 0; i < fill_wqes; i++) { if (!skb_arr_rq1[index]) { skb_arr_rq1[index] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); if (!skb_arr_rq1[index]) { + pr->rq1_skba.os_skbs = fill_wqes - i; ehea_error("%s: no mem for skb/%d wqes filled", dev->name, i); break; @@ -194,9 +203,14 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes) } index--; index &= max_index_mask; + adder++; } + + if (adder == 0) + return; + /* Ring doorbell */ - ehea_update_rq1a(pr->qp, i); + ehea_update_rq1a(pr->qp, adder); } static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a) @@ -230,16 +244,21 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, struct sk_buff **skb_arr = q_skba->arr; struct ehea_rwqe *rwqe; int i, index, max_index_mask, fill_wqes; + int adder = 0; int ret = 0; fill_wqes = q_skba->os_skbs + num_wqes; + q_skba->os_skbs = 0; - if (!fill_wqes) + if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { + q_skba->os_skbs = fill_wqes; return ret; + } index = q_skba->index; max_index_mask = q_skba->len - 1; for (i = 0; i < fill_wqes; i++) { + u64 tmp_addr; struct sk_buff *skb = netdev_alloc_skb(dev, packet_size); if (!skb) { ehea_error("%s: no mem for skb/%d wqes filled", @@ -251,30 +270,37 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, skb_reserve(skb, NET_IP_ALIGN); skb_arr[index] = skb; + tmp_addr = ehea_map_vaddr(skb->data); + if (tmp_addr == -1) { + dev_kfree_skb(skb); + q_skba->os_skbs = fill_wqes - i; + ret = 0; + break; + } rwqe = ehea_get_next_rwqe(qp, rq_nr); rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type) | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index); rwqe->sg_list[0].l_key = pr->recv_mr.lkey; - rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); + rwqe->sg_list[0].vaddr = tmp_addr; rwqe->sg_list[0].len = packet_size; rwqe->data_segments = 1; index++; index &= max_index_mask; - - if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) - goto out; + adder++; } q_skba->index = index; + if (adder == 0) + goto out; /* Ring doorbell */ iosync(); if (rq_nr == 2) - ehea_update_rq2a(pr->qp, i); + ehea_update_rq2a(pr->qp, adder); else - ehea_update_rq3a(pr->qp, i); + ehea_update_rq3a(pr->qp, adder); out: return ret; } @@ -1967,11 +1993,12 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) ehea_dump(swqe, 512, "swqe"); } - if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) - goto out; + if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { + netif_stop_queue(dev); + swqe->tx_control |= EHEA_SWQE_PURGE; + } ehea_post_swqe(pr->qp, swqe); - pr->tx_packets++; if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { spin_lock_irqsave(&pr->netif_queue, flags); @@ -1984,7 +2011,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; spin_unlock(&pr->xmit_lock); -out: + return NETDEV_TX_OK; } @@ -2376,6 +2403,192 @@ static int ehea_stop(struct net_device *dev) return ret; } +void ehea_purge_sq(struct ehea_qp *orig_qp) +{ + struct ehea_qp qp = *orig_qp; + struct ehea_qp_init_attr *init_attr = &qp.init_attr; + struct ehea_swqe *swqe; + int wqe_index; + int i; + + for (i = 0; i < init_attr->act_nr_send_wqes; i++) { + swqe = ehea_get_swqe(&qp, &wqe_index); + swqe->tx_control |= EHEA_SWQE_PURGE; + } +} + +int ehea_stop_qps(struct net_device *dev) +{ + struct ehea_port *port = netdev_priv(dev); + struct ehea_adapter *adapter = port->adapter; + struct hcp_modify_qp_cb0* cb0; + int ret = -EIO; + int dret; + int i; + u64 hret; + u64 dummy64 = 0; + u16 dummy16 = 0; + + cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!cb0) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) { + struct ehea_port_res *pr = &port->port_res[i]; + struct ehea_qp *qp = pr->qp; + + /* Purge send queue */ + ehea_purge_sq(qp); + + /* Disable queue pair */ + hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), + cb0); + if (hret != H_SUCCESS) { + ehea_error("query_ehea_qp failed (1)"); + goto out; + } + + cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8; + cb0->qp_ctl_reg &= ~H_QP_CR_ENABLED; + + hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, + 1), cb0, &dummy64, + &dummy64, &dummy16, &dummy16); + if (hret != H_SUCCESS) { + ehea_error("modify_ehea_qp failed (1)"); + goto out; + } + + hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), + cb0); + if (hret != H_SUCCESS) { + ehea_error("query_ehea_qp failed (2)"); + goto out; + } + + /* deregister shared memory regions */ + dret = ehea_rem_smrs(pr); + if (dret) { + ehea_error("unreg shared memory region failed"); + goto out; + } + } + + ret = 0; +out: + kfree(cb0); + + return ret; +} + +void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res * pr) +{ + struct ehea_qp qp = *orig_qp; + struct ehea_qp_init_attr *init_attr = &qp.init_attr; + struct ehea_rwqe *rwqe; + struct sk_buff **skba_rq2 = pr->rq2_skba.arr; + struct sk_buff **skba_rq3 = pr->rq3_skba.arr; + struct sk_buff *skb; + u32 lkey = pr->recv_mr.lkey; + + + int i; + int index; + + for (i = 0; i < init_attr->act_nr_rwqes_rq2 + 1; i++) { + rwqe = ehea_get_next_rwqe(&qp, 2); + rwqe->sg_list[0].l_key = lkey; + index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id); + skb = skba_rq2[index]; + if (skb) + rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); + } + + for (i = 0; i < init_attr->act_nr_rwqes_rq3 + 1; i++) { + rwqe = ehea_get_next_rwqe(&qp, 3); + rwqe->sg_list[0].l_key = lkey; + index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id); + skb = skba_rq3[index]; + if (skb) + rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); + } +} + +int ehea_restart_qps(struct net_device *dev) +{ + struct ehea_port *port = netdev_priv(dev); + struct ehea_adapter *adapter = port->adapter; + int ret = 0; + int i; + + struct hcp_modify_qp_cb0* cb0; + u64 hret; + u64 dummy64 = 0; + u16 dummy16 = 0; + + cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!cb0) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) { + struct ehea_port_res *pr = &port->port_res[i]; + struct ehea_qp *qp = pr->qp; + + ret = ehea_gen_smrs(pr); + if (ret) { + ehea_error("creation of shared memory regions failed"); + goto out; + } + + ehea_update_rqs(qp, pr); + + /* Enable queue pair */ + hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), + cb0); + if (hret != H_SUCCESS) { + ehea_error("query_ehea_qp failed (1)"); + goto out; + } + + cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8; + cb0->qp_ctl_reg |= H_QP_CR_ENABLED; + + hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, + 1), cb0, &dummy64, + &dummy64, &dummy16, &dummy16); + if (hret != H_SUCCESS) { + ehea_error("modify_ehea_qp failed (1)"); + goto out; + } + + hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), + cb0); + if (hret != H_SUCCESS) { + ehea_error("query_ehea_qp failed (2)"); + goto out; + } + + /* refill entire queue */ + ehea_refill_rq1(pr, pr->rq1_skba.index, 0); + ehea_refill_rq2(pr, 0); + ehea_refill_rq3(pr, 0); + } +out: + kfree(cb0); + + return ret; +} + static void ehea_reset_port(struct work_struct *work) { int ret; @@ -2395,6 +2608,8 @@ static void ehea_reset_port(struct work_struct *work) if (ret) goto out; + ehea_set_multicast_list(dev); + if (netif_msg_timer(port)) ehea_info("Device %s resetted successfully", dev->name); @@ -2411,6 +2626,7 @@ static void ehea_rereg_mrs(struct work_struct *work) int ret, i; struct ehea_adapter *adapter; + down(&dlpar_mem_lock); ehea_info("LPAR memory enlarged - re-initializing driver"); list_for_each_entry(adapter, &adapter_list, list) @@ -2423,14 +2639,14 @@ static void ehea_rereg_mrs(struct work_struct *work) struct net_device *dev = port->netdev; if (dev->flags & IFF_UP) { - ehea_info("stopping %s", - dev->name); down(&port->port_lock); netif_stop_queue(dev); - + ret = ehea_stop_qps(dev); + if (ret) { + up(&port->port_lock); + goto out; + } port_napi_disable(port); - - ehea_down(dev); up(&port->port_lock); } } @@ -2446,10 +2662,11 @@ static void ehea_rereg_mrs(struct work_struct *work) } ehea_destroy_busmap(); - ret = ehea_create_busmap(); - if (ret) + if (ret) { + ehea_error("creating ehea busmap failed"); goto out; + } clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags); @@ -2471,21 +2688,18 @@ static void ehea_rereg_mrs(struct work_struct *work) struct net_device *dev = port->netdev; if (dev->flags & IFF_UP) { - ehea_info("restarting %s", - dev->name); down(&port->port_lock); - - ret = ehea_up(dev); - if (!ret) { - port_napi_enable(port); + port_napi_enable(port); + ret = ehea_restart_qps(dev); + if (!ret) netif_wake_queue(dev); - } - up(&port->port_lock); } } } } + up(&dlpar_mem_lock); + ehea_info("re-initializing driver complete"); out: return; } @@ -2494,7 +2708,8 @@ static void ehea_tx_watchdog(struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); - if (netif_carrier_ok(dev)) + if (netif_carrier_ok(dev) && + !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) queue_work(port->adapter->ehea_wq, &port->reset_task); } @@ -3139,6 +3354,7 @@ int __init ehea_module_init(void) ehea_driver_wq = create_workqueue("ehea_driver_wq"); INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs); + sema_init(&dlpar_mem_lock, 1); ret = check_module_parm(); if (ret) diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h index 89b63531ff26..faa191d23b86 100644 --- a/drivers/net/ehea/ehea_phyp.h +++ b/drivers/net/ehea/ehea_phyp.h @@ -126,6 +126,7 @@ struct hcp_modify_qp_cb0 { #define H_QP_CR_STATE_RDY2RCV 0x0000030000000000ULL /* Ready to recv */ #define H_QP_CR_STATE_RDY2SND 0x0000050000000000ULL /* Ready to send */ #define H_QP_CR_STATE_ERROR 0x0000800000000000ULL /* Error */ +#define H_QP_CR_RES_STATE 0x0000007F00000000ULL /* Resultant state */ struct hcp_modify_qp_cb1 { u32 qpn; /* 00 */ diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index c82e24596074..329a25248d75 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -563,8 +563,7 @@ int ehea_destroy_qp(struct ehea_qp *qp) int ehea_create_busmap( void ) { u64 vaddr = EHEA_BUSMAP_START; - unsigned long abs_max_pfn = 0; - unsigned long sec_max_pfn; + unsigned long high_section_index = 0; int i; /* @@ -574,14 +573,10 @@ int ehea_create_busmap( void ) ehea_bmap.valid_sections = 0; for (i = 0; i < NR_MEM_SECTIONS; i++) - if (valid_section_nr(i)) { - sec_max_pfn = section_nr_to_pfn(i); - if (sec_max_pfn > abs_max_pfn) - abs_max_pfn = sec_max_pfn; - ehea_bmap.valid_sections++; - } + if (valid_section_nr(i)) + high_section_index = i; - ehea_bmap.entries = abs_max_pfn / EHEA_PAGES_PER_SECTION + 1; + ehea_bmap.entries = high_section_index + 1; ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr)); if (!ehea_bmap.vaddr) @@ -593,6 +588,7 @@ int ehea_create_busmap( void ) if (pfn_valid(pfn)) { ehea_bmap.vaddr[i] = vaddr; vaddr += EHEA_SECTSIZE; + ehea_bmap.valid_sections++; } else ehea_bmap.vaddr[i] = 0; } @@ -637,7 +633,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE; - pt = kzalloc(EHEA_MAX_RPAGE * sizeof(u64), GFP_KERNEL); + pt = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!pt) { ehea_error("no mem"); ret = -ENOMEM; @@ -660,8 +656,8 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) void *sectbase = __va(i << SECTION_SIZE_BITS); unsigned long k = 0; - for (j = 0; j < (PAGES_PER_SECTION / EHEA_MAX_RPAGE); - j++) { + for (j = 0; j < (EHEA_PAGES_PER_SECTION / + EHEA_MAX_RPAGE); j++) { for (m = 0; m < EHEA_MAX_RPAGE; m++) { pg = sectbase + ((k++) * EHEA_PAGESIZE); diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index b71f8452a5e3..562de0ebdd85 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h @@ -39,7 +39,7 @@ #define EHEA_PAGESHIFT 12 #define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT) #define EHEA_SECTSIZE (1UL << 24) -#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> PAGE_SHIFT) +#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT) #if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE #error eHEA module can't work if kernel sectionsize < ehea sectionsize @@ -145,7 +145,7 @@ struct ehea_rwqe { #define EHEA_CQE_VLAN_TAG_XTRACT 0x0400 #define EHEA_CQE_TYPE_RQ 0x60 -#define EHEA_CQE_STAT_ERR_MASK 0x721F +#define EHEA_CQE_STAT_ERR_MASK 0x720F #define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F #define EHEA_CQE_STAT_ERR_TCP 0x4000 #define EHEA_CQE_STAT_ERR_IP 0x2000 From 726d722e41f1c329b7f04c5ee5aef02a60ac1991 Mon Sep 17 00:00:00 2001 From: Markus Brunner Date: Mon, 20 Aug 2007 08:36:50 +0200 Subject: [PATCH 1661/2804] smc911x irq sense request and MPR2 board support Hi, this are the changes to the smc911x driver, which were necessary to get it running on the Magic Panel R2 (smsc9115). It is a SH3-DSP based board. The other patches are available on the linuxsh-dev mailinglist. http://marc.info/?l=linuxsh-dev&r=1&b=200708&w=2 It was necessary to set the irq sense to low level. Therefor the SMC_IRQ_SENSE define was added. How are the chances for inclusion in 2.6.24? Signed-off by: Markus Brunner Signed-off by: Mark Jonas Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- drivers/net/smc911x.c | 2 +- drivers/net/smc911x.h | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 45f6cf531566..0e48b294200e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -944,7 +944,7 @@ config SMC911X tristate "SMSC LAN911[5678] support" select CRC32 select MII - depends on ARCH_PXA + depends on ARCH_PXA || SUPERH help This is a driver for SMSC's LAN911x series of Ethernet chipsets including the new LAN9115, LAN9116, LAN9117, and LAN9118. diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index c0276c04dece..7c60df46fc65 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -2063,7 +2063,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) /* Grab the IRQ */ retval = request_irq(dev->irq, &smc911x_interrupt, - IRQF_SHARED | IRQF_TRIGGER_FALLING, dev->name, dev); + IRQF_SHARED | SMC_IRQ_SENSE, dev->name, dev); if (retval) goto err_out; diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 962a710459fc..16a0edc078fd 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -36,6 +36,12 @@ #define SMC_USE_PXA_DMA 1 #define SMC_USE_16BIT 0 #define SMC_USE_32BIT 1 + #define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING +#elif CONFIG_SH_MAGIC_PANEL_R2 + #define SMC_USE_SH_DMA 0 + #define SMC_USE_16BIT 0 + #define SMC_USE_32BIT 1 + #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW #endif From 18ad4e700647a9f727fa82a7f8d1f31444abbdfb Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Wed, 19 Sep 2007 21:07:52 +0900 Subject: [PATCH 1662/2804] smc91x Hitachi Solution Engine (SuperH) Support Hi, all. This patch supports Hitachi Solution Engine (SuperH) of smc91x. Please apply this patch . regards, Nobuhiro -- Nobuhiro Iwamatsu E-Mail : iwamatsu@nigauri.org GPG ID : 3170EBE9 Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Jeff Garzik --- drivers/net/smc91x.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 6ff3a1627af8..af9e6bf59552 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -284,6 +284,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #elif defined(CONFIG_SUPERH) #ifdef CONFIG_SOLUTION_ENGINE +#define SMC_IRQ_FLAGS (0) #define SMC_CAN_USE_8BIT 0 #define SMC_CAN_USE_16BIT 1 #define SMC_CAN_USE_32BIT 0 From dad8c737962669240470923f951570ed716da1a1 Mon Sep 17 00:00:00 2001 From: Komuro Date: Sun, 30 Sep 2007 10:28:14 +0900 Subject: [PATCH 1663/2804] PCMCIA-NETDEV : add new id (axnet_cs, pcnet_cs) axnet_cs: Laneed LD-CDK/TX pcnet_cs: LEMEL LM-N89TX PRO Signed-off-by: Komuro Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/axnet_cs.c | 1 + drivers/net/pcmcia/pcnet_cs.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index de59313d10f5..a95a2cae6b23 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -772,6 +772,7 @@ static struct pcmcia_device_id axnet_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106), PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), + PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090), PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc), PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef), PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef), diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 6a647516c380..9d45e9696e16 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1662,6 +1662,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40), PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7), PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab), + PCMCIA_DEVICE_PROD_ID12("LEMEL", "LM-N89TX PRO", 0xbbefb52f, 0xd2897a97), PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78), PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11), PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d), From ea1f8d5c3a593a791463c2efc07e5dfebd056500 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 2 Oct 2007 16:27:35 -0700 Subject: [PATCH 1664/2804] [BNX2]: Optimize firmware loading. This is a follow up to the patches from Denys Vlasenkos to further optimize firmware loading. 1. In bnx2_init_cpus(), we allocate memory for decompression once and use it repeatedly instead of doing this for every firmware image. 2. We eliminate the BSS and SBSS firmware sections in bnx2_fw*.h since these are always zeros. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 40 +++++++++++++++++++--------------------- drivers/net/bnx2.h | 4 +--- drivers/net/bnx2_fw.h | 17 ----------------- drivers/net/bnx2_fw2.h | 20 -------------------- 4 files changed, 20 insertions(+), 61 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 6d6ea56fe384..00aef8b08da4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2810,21 +2810,16 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) /* Load the Text area. */ offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base); if (fw->gz_text) { - u32 *text; int j; - text = vmalloc(FW_BUF_SIZE); - if (!text) - return -ENOMEM; - rc = zlib_inflate_blob(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len); - if (rc < 0) { - vfree(text); + rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text, + fw->gz_text_len); + if (rc < 0) return rc; - } + for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { - REG_WR_IND(bp, offset, cpu_to_le32(text[j])); + REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j])); } - vfree(text); } /* Load the Data area. */ @@ -2839,21 +2834,21 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) /* Load the SBSS area. */ offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base); - if (fw->sbss) { + if (fw->sbss_len) { int j; for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) { - REG_WR_IND(bp, offset, fw->sbss[j]); + REG_WR_IND(bp, offset, 0); } } /* Load the BSS area. */ offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base); - if (fw->bss) { + if (fw->bss_len) { int j; for (j = 0; j < (fw->bss_len/4); j++, offset += 4) { - REG_WR_IND(bp, offset, fw->bss[j]); + REG_WR_IND(bp, offset, 0); } } @@ -2894,19 +2889,16 @@ bnx2_init_cpus(struct bnx2 *bp) if (!text) return -ENOMEM; rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); - if (rc < 0) { - vfree(text); + if (rc < 0) goto init_cpu_err; - } + load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1); rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); - if (rc < 0) { - vfree(text); + if (rc < 0) goto init_cpu_err; - } + load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2); - vfree(text); /* Initialize the RX Processor. */ cpu_reg.mode = BNX2_RXP_CPU_MODE; @@ -2927,6 +2919,7 @@ bnx2_init_cpus(struct bnx2 *bp) else fw = &bnx2_rxp_fw_06; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; @@ -2950,6 +2943,7 @@ bnx2_init_cpus(struct bnx2 *bp) else fw = &bnx2_txp_fw_06; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; @@ -2973,6 +2967,7 @@ bnx2_init_cpus(struct bnx2 *bp) else fw = &bnx2_tpat_fw_06; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; @@ -2996,6 +2991,7 @@ bnx2_init_cpus(struct bnx2 *bp) else fw = &bnx2_com_fw_06; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; @@ -3017,11 +3013,13 @@ bnx2_init_cpus(struct bnx2 *bp) if (CHIP_NUM(bp) == CHIP_NUM_5709) { fw = &bnx2_cp_fw_09; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; } init_cpu_err: + vfree(text); return rc; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index a717459cc8d4..56c190fc6de6 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6738,7 +6738,7 @@ struct fw_info { const u32 text_addr; const u32 text_len; const u32 text_index; -/* u32 *text;*/ + u32 *text; u8 *gz_text; const u32 gz_text_len; @@ -6752,13 +6752,11 @@ struct fw_info { const u32 sbss_addr; const u32 sbss_len; const u32 sbss_index; - const u32 *sbss; /* BSS section. */ const u32 bss_addr; const u32 bss_len; const u32 bss_index; - const u32 *bss; /* Read-only section. */ const u32 rodata_addr; diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index 30f2f4052fc1..a6d78243163b 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -1048,8 +1048,6 @@ static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = { 0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc, 0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140, 0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 }; -static const u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b06FwSbss[(0x60/4) + 1] = { 0x0 }; static struct fw_info bnx2_com_fw_06 = { .ver_major = 0x3, @@ -1072,12 +1070,10 @@ static struct fw_info bnx2_com_fw_06 = { .sbss_addr = 0x08007e00, .sbss_len = 0x60, .sbss_index = 0x0, - .sbss = bnx2_COM_b06FwSbss, .bss_addr = 0x08007e60, .bss_len = 0x88, .bss_index = 0x0, - .bss = bnx2_COM_b06FwBss, .rodata_addr = 0x08007d58, .rodata_len = 0x88, @@ -1762,9 +1758,6 @@ static u32 bnx2_RXP_b06FwRodata[(0x278/4) + 1] = { 0x08006030, 0x08006030, 0x08006018, 0x08006030, 0x08006030, 0x08006030, 0x08006024, 0x00000000, 0x00000000 }; -static u32 bnx2_RXP_b06FwBss[(0x13dc/4) + 1] = { 0x0 }; -static u32 bnx2_RXP_b06FwSbss[(0x2c/4) + 1] = { 0x0 }; - static struct fw_info bnx2_rxp_fw_06 = { .ver_major = 0x2, .ver_minor = 0x8, @@ -1786,12 +1779,10 @@ static struct fw_info bnx2_rxp_fw_06 = { .sbss_addr = 0x080069c0, .sbss_len = 0x2c, .sbss_index = 0x0, - .sbss = bnx2_RXP_b06FwSbss, .bss_addr = 0x080069f0, .bss_len = 0x13dc, .bss_index = 0x0, - .bss = bnx2_RXP_b06FwBss, .rodata_addr = 0x08006728, .rodata_len = 0x278, @@ -2257,8 +2248,6 @@ static u8 bnx2_TPAT_b06FwText[] = { static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 }; static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 }; -static u32 bnx2_TPAT_b06FwBss[(0x250/4) + 1] = { 0x0 }; -static u32 bnx2_TPAT_b06FwSbss[(0x34/4) + 1] = { 0x0 }; static struct fw_info bnx2_tpat_fw_06 = { .ver_major = 0x1, @@ -2281,12 +2270,10 @@ static struct fw_info bnx2_tpat_fw_06 = { .sbss_addr = 0x08001a60, .sbss_len = 0x34, .sbss_index = 0x0, - .sbss = bnx2_TPAT_b06FwSbss, .bss_addr = 0x08001aa0, .bss_len = 0x250, .bss_index = 0x0, - .bss = bnx2_TPAT_b06FwBss, .rodata_addr = 0x00000000, .rodata_len = 0x0, @@ -2714,8 +2701,6 @@ static u8 bnx2_TXP_b06FwText[] = { static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 }; static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 }; -static u32 bnx2_TXP_b06FwBss[(0x1c4/4) + 1] = { 0x0 }; -static u32 bnx2_TXP_b06FwSbss[(0x38/4) + 1] = { 0x0 }; static struct fw_info bnx2_txp_fw_06 = { .ver_major = 0x1, @@ -2738,12 +2723,10 @@ static struct fw_info bnx2_txp_fw_06 = { .sbss_addr = 0x08005760, .sbss_len = 0x38, .sbss_index = 0x0, - .sbss = bnx2_TXP_b06FwSbss, .bss_addr = 0x080057a0, .bss_len = 0x1c4, .bss_index = 0x0, - .bss = bnx2_TXP_b06FwBss, .rodata_addr = 0x00000000, .rodata_len = 0x0, diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h index 74f985d8fac7..5bd52bead9bf 100644 --- a/drivers/net/bnx2_fw2.h +++ b/drivers/net/bnx2_fw2.h @@ -1046,8 +1046,6 @@ static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = { 0x08002b3c, 0x08002b6c, 0x08002b9c, 0x00000000, 0x0800604c, 0x0800604c, 0x0800604c, 0x0800604c, 0x0800604c, 0x08006078, 0x08006078, 0x080060b8, 0x080060c4, 0x080060c4, 0x0800604c, 0x00000000, 0x00000000 }; -static const u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b09FwSbss[(0x60/4) + 1] = { 0x0 }; static struct fw_info bnx2_com_fw_09 = { .ver_major = 0x3, @@ -1070,12 +1068,10 @@ static struct fw_info bnx2_com_fw_09 = { .sbss_addr = 0x08007e60, .sbss_len = 0x60, .sbss_index = 0x0, - .sbss = bnx2_COM_b09FwSbss, .bss_addr = 0x08007ec0, .bss_len = 0x88, .bss_index = 0x0, - .bss = bnx2_COM_b09FwBss, .rodata_addr = 0x08007dc0, .rodata_len = 0x88, @@ -2243,8 +2239,6 @@ static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = { 0x080032e8, 0x08003300, 0x08003320, 0x08003358, 0x08003338, 0x08003338, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050fc, 0x080050fc, 0x08005124, 0x08005174, 0x08005144, 0x00000000 }; -static const u32 bnx2_CP_b09FwBss[(0x3b0/4) + 1] = { 0x0 }; -static const u32 bnx2_CP_b09FwSbss[(0xa1/4) + 1] = { 0x0 }; static struct fw_info bnx2_cp_fw_09 = { .ver_major = 0x3, @@ -2267,12 +2261,10 @@ static struct fw_info bnx2_cp_fw_09 = { .sbss_addr = 0x08007024, .sbss_len = 0xa1, .sbss_index = 0x0, - .sbss = bnx2_CP_b09FwSbss, .bss_addr = 0x080070d0, .bss_len = 0x3b0, .bss_index = 0x0, - .bss = bnx2_CP_b09FwBss, .rodata_addr = 0x08006ee8, .rodata_len = 0x118, @@ -2953,8 +2945,6 @@ static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = { 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006064, 0x00000000, 0x00000000 }; -static const u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 }; -static const u32 bnx2_RXP_b09FwSbss[(0x20/4) + 1] = { 0x0 }; static struct fw_info bnx2_rxp_fw_09 = { .ver_major = 0x3, @@ -2977,12 +2967,10 @@ static struct fw_info bnx2_rxp_fw_09 = { .sbss_addr = 0x08006a00, .sbss_len = 0x20, .sbss_index = 0x0, - .sbss = bnx2_RXP_b09FwSbss, .bss_addr = 0x08006a20, .bss_len = 0x13dc, .bss_index = 0x0, - .bss = bnx2_RXP_b09FwBss, .rodata_addr = 0x08006768, .rodata_len = 0x278, @@ -3245,8 +3233,6 @@ static u8 bnx2_TPAT_b09FwText[] = { static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_TPAT_b09FwBss[(0x850/4) + 1] = { 0x0 }; -static const u32 bnx2_TPAT_b09FwSbss[(0x2c/4) + 1] = { 0x0 }; static struct fw_info bnx2_tpat_fw_09 = { .ver_major = 0x3, @@ -3269,12 +3255,10 @@ static struct fw_info bnx2_tpat_fw_09 = { .sbss_addr = 0x08002088, .sbss_len = 0x2c, .sbss_index = 0x0, - .sbss = bnx2_TPAT_b09FwSbss, .bss_addr = 0x080020c0, .bss_len = 0x850, .bss_index = 0x0, - .bss = bnx2_TPAT_b09FwBss, .rodata_addr = 0x00000000, .rodata_len = 0x0, @@ -4060,8 +4044,6 @@ static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = { 0x08004060, 0x0800408c, 0x080040d4, 0x080040d4, 0x08003f60, 0x08003f8c, 0x08003f8c, 0x080040d4, 0x080040d4, 0x080040d4, 0x08003ff4, 0x00000000, 0x00000000 }; -static const u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 }; -static const u32 bnx2_TXP_b09FwSbss[(0x8c/4) + 1] = { 0x0 }; static struct fw_info bnx2_txp_fw_09 = { .ver_major = 0x3, @@ -4084,12 +4066,10 @@ static struct fw_info bnx2_txp_fw_09 = { .sbss_addr = 0x08004750, .sbss_len = 0x8c, .sbss_index = 0x0, - .sbss = bnx2_TXP_b09FwSbss, .bss_addr = 0x080047e0, .bss_len = 0xa20, .bss_index = 0x0, - .bss = bnx2_TXP_b09FwBss, .rodata_addr = 0x08004638, .rodata_len = 0x30, From f74347d7ac0aa175b2bbd85eb58a13fbe80a3785 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 2 Oct 2007 16:28:09 -0700 Subject: [PATCH 1665/2804] [BNX2]: Update version to 1.6.6. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 00aef8b08da4..0e4928c751ff 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.5" -#define DRV_MODULE_RELDATE "September 20, 2007" +#define DRV_MODULE_VERSION "1.6.6" +#define DRV_MODULE_RELDATE "October 2, 2007" #define RUN_AT(x) (jiffies + (x)) From 09703f5e79a64c744721b9c27502075232ba0ea2 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 26 Sep 2007 21:45:24 +0100 Subject: [PATCH 1666/2804] [HOSTAP]: set netdev type before registering AP interface As detailed at https://bugs.gentoo.org/159646 hostap with hostapd confuses udev by presenting 2 interfaces with the same MAC address. Also, at the time of detection, the 'type' attribute is 1, identical to other hostap interfaces. The AP interface is supposed to have type ARPHRD_IEEE80211 (801), but this is not set until after registration. Setting it before register_netdev() is called allows us to avoid this confusion. We can do this by propogating the HOSTAP_INTERFACE type through to hostap_setup_dev(). Signed-off-by: Daniel Drake Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/hostap/hostap.h | 2 +- drivers/net/wireless/hostap/hostap_hw.c | 2 +- drivers/net/wireless/hostap/hostap_main.c | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index 951df83702f9..547ba84dc797 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -34,7 +34,7 @@ extern const struct header_ops hostap_80211_ops; int hostap_80211_get_hdrlen(u16 fc); struct net_device_stats *hostap_get_stats(struct net_device *dev); void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int main_dev); + int type); void hostap_set_multicast_list_queue(struct work_struct *work); int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index b20bb013d57e..c592641e914e 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3257,7 +3257,7 @@ while (0) INIT_LIST_HEAD(&local->bss_list); - hostap_setup_dev(dev, local, 1); + hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER); dev->hard_start_xmit = hostap_master_start_xmit; dev->type = ARPHRD_IEEE80211; diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index b75cf9205ce0..17c58e9bdad5 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -73,7 +73,7 @@ struct net_device * hostap_add_interface(struct local_info *local, dev->mem_start = mdev->mem_start; dev->mem_end = mdev->mem_end; - hostap_setup_dev(dev, local, 0); + hostap_setup_dev(dev, local, type); dev->destructor = free_netdev; sprintf(dev->name, "%s%s", prefix, name); @@ -857,7 +857,7 @@ const struct header_ops hostap_80211_ops = { EXPORT_SYMBOL(hostap_80211_ops); void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int main_dev) + int type) { struct hostap_interface *iface; @@ -877,15 +877,22 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, dev->do_ioctl = hostap_ioctl; dev->open = prism2_open; dev->stop = prism2_close; - dev->hard_start_xmit = hostap_data_start_xmit; dev->set_mac_address = prism2_set_mac_address; dev->set_multicast_list = hostap_set_multicast_list; dev->change_mtu = prism2_change_mtu; dev->tx_timeout = prism2_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + if (type == HOSTAP_INTERFACE_AP) { + dev->hard_start_xmit = hostap_mgmt_start_xmit; + dev->type = ARPHRD_IEEE80211; + dev->header_ops = &hostap_80211_ops; + } else { + dev->hard_start_xmit = hostap_data_start_xmit; + } + dev->mtu = local->mtu; - if (!main_dev) { + if (type != HOSTAP_INTERFACE_MASTER) { /* use main radio device queue */ dev->tx_queue_len = 0; } @@ -910,10 +917,6 @@ static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) if (local->apdev == NULL) return -ENOMEM; - local->apdev->hard_start_xmit = hostap_mgmt_start_xmit; - local->apdev->type = ARPHRD_IEEE80211; - local->apdev->header_ops = &hostap_80211_ops; - return 0; } From 937a049dd903bd810d858d0303cf86af9eb08b6f Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Tue, 2 Oct 2007 18:36:53 +0100 Subject: [PATCH 1667/2804] [ZD1211RW]: Removed zd_util.c and zd_util.h The kernel now provides a generic hexdump implementation should we need it again, so we can remove it from zd1211rw. After removing that, only one single-user function is left in zd_util. Move that to zd_mac and remove zd_util. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/zd1211rw/Makefile | 2 +- drivers/net/wireless/zd1211rw/zd_chip.c | 1 - drivers/net/wireless/zd1211rw/zd_mac.c | 4 +- drivers/net/wireless/zd1211rw/zd_usb.c | 1 - drivers/net/wireless/zd1211rw/zd_util.c | 82 ------------------------- drivers/net/wireless/zd1211rw/zd_util.h | 29 --------- 6 files changed, 3 insertions(+), 116 deletions(-) delete mode 100644 drivers/net/wireless/zd1211rw/zd_util.c delete mode 100644 drivers/net/wireless/zd1211rw/zd_util.h diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index 4d505903352c..7a2f2a98edab 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -4,7 +4,7 @@ zd1211rw-objs := zd_chip.o zd_ieee80211.o \ zd_mac.o zd_netdev.o \ zd_rf_al2230.o zd_rf_rf2959.o \ zd_rf_al7230b.o zd_rf_uw2453.o \ - zd_rf.o zd_usb.o zd_util.o + zd_rf.o zd_usb.o ifeq ($(CONFIG_ZD1211RW_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 3d60c69b20e7..f831b68f1b9c 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -28,7 +28,6 @@ #include "zd_ieee80211.h" #include "zd_mac.h" #include "zd_rf.h" -#include "zd_util.h" void zd_chip_init(struct zd_chip *chip, struct net_device *netdev, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 06b342b39792..a903645e157a 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -28,7 +28,6 @@ #include "zd_ieee80211.h" #include "zd_netdev.h" #include "zd_rf.h" -#include "zd_util.h" static void ieee_init(struct ieee80211_device *ieee); static void softmac_init(struct ieee80211softmac_device *sm); @@ -1066,7 +1065,8 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats, { const struct rx_status *status; - *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); + *pstatus = status = (struct rx_status *) + (buffer + (length - sizeof(struct rx_status))); if (status->frame_status & ZD_RX_ERROR) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); ieee->stats.rx_errors++; diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 895ff8441874..721d737e8d21 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -31,7 +31,6 @@ #include "zd_netdev.h" #include "zd_mac.h" #include "zd_usb.h" -#include "zd_util.h" static struct usb_device_id usb_ids[] = { /* ZD1211 */ diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c deleted file mode 100644 index d20036c15d11..000000000000 --- a/drivers/net/wireless/zd1211rw/zd_util.c +++ /dev/null @@ -1,82 +0,0 @@ -/* zd_util.c - * - * 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 - * - * Utility program - */ - -#include "zd_def.h" -#include "zd_util.h" - -#ifdef DEBUG -static char hex(u8 v) -{ - v &= 0xf; - return (v < 10 ? '0' : 'a' - 10) + v; -} - -static char hex_print(u8 c) -{ - return (0x20 <= c && c < 0x7f) ? c : '.'; -} - -static void dump_line(const u8 *bytes, size_t size) -{ - char c; - size_t i; - - size = size <= 8 ? size : 8; - printk(KERN_DEBUG "zd1211 %p ", bytes); - for (i = 0; i < 8; i++) { - switch (i) { - case 1: - case 5: - c = '.'; - break; - case 3: - c = ':'; - break; - default: - c = ' '; - } - if (i < size) { - printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c); - } else { - printk(" %c", c); - } - } - - for (i = 0; i < size; i++) - printk("%c", hex_print(bytes[i])); - printk("\n"); -} - -void zd_hexdump(const void *bytes, size_t size) -{ - size_t i = 0; - - do { - dump_line((u8 *)bytes + i, size-i); - i += 8; - } while (i < size); -} -#endif /* DEBUG */ - -void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size) -{ - if (buffer_size < tail_size) - return NULL; - return (u8 *)buffer + (buffer_size - tail_size); -} diff --git a/drivers/net/wireless/zd1211rw/zd_util.h b/drivers/net/wireless/zd1211rw/zd_util.h deleted file mode 100644 index ce26f7adea92..000000000000 --- a/drivers/net/wireless/zd1211rw/zd_util.h +++ /dev/null @@ -1,29 +0,0 @@ -/* zd_util.h - * - * 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 - */ - -#ifndef _ZD_UTIL_H -#define _ZD_UTIL_H - -void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size); - -#ifdef DEBUG -void zd_hexdump(const void *bytes, size_t size); -#else -#define zd_hexdump(bytes, size) -#endif /* DEBUG */ - -#endif /* _ZD_UTIL_H */ From 135900c182c321a4888ec496b014e6707272faca Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 27 Sep 2007 21:33:12 +0200 Subject: [PATCH 1668/2804] [RFKILL]: Add support for an rfkill LED. This adds a LED trigger. Signed-off-by: Michael Buesch Acked-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/linux/rfkill.h | 21 +++++++++++++++++++++ net/rfkill/Kconfig | 7 +++++++ net/rfkill/rfkill.c | 42 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index d76397ca95ad..26fddea12c25 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -26,6 +26,7 @@ #include #include #include +#include /** * enum rfkill_type - type of rfkill switch. @@ -56,6 +57,7 @@ enum rfkill_state { * @data: Pointer to the RF button drivers private data which will be * passed along when toggling radio state. * @toggle_radio(): Mandatory handler to control state of the radio. + * @led_trigger: A LED trigger for this button's LED. * @dev: Device structure integrating the switch into device tree. * @node: Used to place switch into list of all switches known to the * the system. @@ -74,6 +76,10 @@ struct rfkill { void *data; int (*toggle_radio)(void *data, enum rfkill_state state); +#ifdef CONFIG_RFKILL_LEDS + struct led_trigger led_trigger; +#endif + struct device dev; struct list_head node; }; @@ -84,4 +90,19 @@ void rfkill_free(struct rfkill *rfkill); int rfkill_register(struct rfkill *rfkill); void rfkill_unregister(struct rfkill *rfkill); +/** + * rfkill_get_led_name - Get the LED trigger name for the button's LED. + * This function might return a NULL pointer if registering of the + * LED trigger failed. + * Use this as "default_trigger" for the LED. + */ +static inline char *rfkill_get_led_name(struct rfkill *rfkill) +{ +#ifdef CONFIG_RFKILL_LEDS + return (char *)(rfkill->led_trigger.name); +#else + return NULL; +#endif +} + #endif /* RFKILL_H */ diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index d28a6d9303e4..7f807b30cfbb 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -22,3 +22,10 @@ config RFKILL_INPUT To compile this driver as a module, choose M here: the module will be called rfkill-input. + +# LED trigger support +config RFKILL_LEDS + bool + depends on RFKILL && LEDS_TRIGGERS + default y + diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 637a9f0c7655..a8c5e0b914e4 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -37,6 +37,22 @@ static DEFINE_MUTEX(rfkill_mutex); static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; + +static void rfkill_led_trigger(struct rfkill *rfkill, + enum rfkill_state state) +{ +#ifdef CONFIG_RFKILL_LEDS + struct led_trigger *led = &rfkill->led_trigger; + + if (!led->name) + return; + if (state == RFKILL_STATE_OFF) + led_trigger_event(led, LED_OFF); + else + led_trigger_event(led, LED_FULL); +#endif /* CONFIG_RFKILL_LEDS */ +} + static int rfkill_toggle_radio(struct rfkill *rfkill, enum rfkill_state state) { @@ -48,8 +64,10 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, if (state != rfkill->state) { retval = rfkill->toggle_radio(rfkill->data, state); - if (!retval) + if (!retval) { rfkill->state = state; + rfkill_led_trigger(rfkill, state); + } } mutex_unlock(&rfkill->mutex); @@ -328,6 +346,26 @@ void rfkill_free(struct rfkill *rfkill) } EXPORT_SYMBOL(rfkill_free); +static void rfkill_led_trigger_register(struct rfkill *rfkill) +{ +#ifdef CONFIG_RFKILL_LEDS + int error; + + rfkill->led_trigger.name = rfkill->dev.bus_id; + error = led_trigger_register(&rfkill->led_trigger); + if (error) + rfkill->led_trigger.name = NULL; +#endif /* CONFIG_RFKILL_LEDS */ +} + +static void rfkill_led_trigger_unregister(struct rfkill *rfkill) +{ +#ifdef CONFIG_RFKILL_LEDS + if (rfkill->led_trigger.name) + led_trigger_unregister(&rfkill->led_trigger); +#endif +} + /** * rfkill_register - Register a rfkill structure. * @rfkill: rfkill structure to be registered @@ -357,6 +395,7 @@ int rfkill_register(struct rfkill *rfkill) rfkill_remove_switch(rfkill); return error; } + rfkill_led_trigger_register(rfkill); return 0; } @@ -372,6 +411,7 @@ EXPORT_SYMBOL(rfkill_register); */ void rfkill_unregister(struct rfkill *rfkill) { + rfkill_led_trigger_unregister(rfkill); device_del(&rfkill->dev); rfkill_remove_switch(rfkill); put_device(&rfkill->dev); From 20405c08412a4d89357870d7220f9fb1c458b286 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 27 Sep 2007 21:34:23 +0200 Subject: [PATCH 1669/2804] [RFKILL]: Add support for hardware-only rfkill buttons Buttons that work directly on hardware cannot support the "user_claim" functionality. Add a flag to signal this and return -EOPNOTSUPP in this case. b43 is such a device. Signed-off-by: Michael Buesch Acked-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/linux/rfkill.h | 3 +++ net/rfkill/rfkill.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 26fddea12c25..0ce5e0b52dbd 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -52,6 +52,8 @@ enum rfkill_state { * @type: Radio type which the button controls, the value stored * here should be a value from enum rfkill_type. * @state: State of the switch (on/off). + * @user_claim_unsupported: Whether the hardware supports exclusive + * RF-kill control by userspace. Set this before registering. * @user_claim: Set when the switch is controlled exlusively by userspace. * @mutex: Guards switch state transitions * @data: Pointer to the RF button drivers private data which will be @@ -69,6 +71,7 @@ struct rfkill { enum rfkill_type type; enum rfkill_state state; + bool user_claim_unsupported; bool user_claim; struct mutex mutex; diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index a8c5e0b914e4..51d151c0e962 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -190,6 +190,10 @@ static ssize_t rfkill_claim_store(struct device *dev, if (error) return error; + if (rfkill->user_claim_unsupported) { + error = -EOPNOTSUPP; + goto out_unlock; + } if (rfkill->user_claim != claim) { if (!claim) rfkill_toggle_radio(rfkill, @@ -197,9 +201,10 @@ static ssize_t rfkill_claim_store(struct device *dev, rfkill->user_claim = claim; } +out_unlock: mutex_unlock(&rfkill_mutex); - return count; + return error ? error : count; } static struct device_attribute rfkill_dev_attrs[] = { From 21954c367e4088c491122edd263964345bc1d3bf Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 27 Sep 2007 15:31:40 +0200 Subject: [PATCH 1670/2804] [B43]: LED triggers support Drive the LEDs through the generic LED triggers. Signed-off-by: Michael Buesch Cc: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/Kconfig | 6 + drivers/net/wireless/b43/Makefile | 3 +- drivers/net/wireless/b43/b43.h | 6 +- drivers/net/wireless/b43/leds.c | 397 +++++++++++++----------------- drivers/net/wireless/b43/leds.h | 63 +++-- drivers/net/wireless/b43/main.c | 51 ++-- 6 files changed, 230 insertions(+), 296 deletions(-) diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 4620119891f2..1575654556b0 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -61,6 +61,12 @@ config B43_PCMCIA If unsure, say N. +# LED support +config B43_LEDS + bool + depends on MAC80211_LEDS + default y + config B43_DEBUG bool "Broadcom 43xx debugging" depends on B43 diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 370935b84c5e..e6331414c4ca 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -3,9 +3,10 @@ b43-y += main.o b43-y += tables.o b43-y += phy.o b43-y += sysfs.o -b43-y += leds.o b43-y += xmit.o b43-y += lo.o +# b43 LED support +b43-$(CONFIG_B43_LEDS) += leds.o # b43 PCMCIA support b43-$(CONFIG_B43_PCMCIA) += pcmcia.o # b43 debugging diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 2c8fa1c3465e..6e6b59227e16 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -696,8 +696,10 @@ struct b43_wldev { /* Various statistics about the physical device. */ struct b43_stats stats; -#define B43_NR_LEDS 4 - struct b43_led leds[B43_NR_LEDS]; + /* The device LEDs. */ + struct b43_led led_tx; + struct b43_led led_rx; + struct b43_led led_assoc; /* Reason code of the last interrupt. */ u32 irq_reason; diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 0f155b4f34eb..ddab856f1140 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -1,12 +1,13 @@ /* Broadcom B43 wireless driver + LED control Copyright (c) 2005 Martin Langer , - Stefano Brivio - Michael Buesch - Danny van Dyk - Andreas Jaggi + Copyright (c) 2005 Stefano Brivio + Copyright (c) 2005-2007 Michael Buesch + Copyright (c) 2005 Danny van Dyk + Copyright (c) 2005 Andreas Jaggi 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 @@ -27,272 +28,204 @@ #include "b43.h" #include "leds.h" -#include "main.h" -static void b43_led_changestate(struct b43_led *led) + +static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, + bool activelow) { - struct b43_wldev *dev = led->dev; - const int index = led->index; - u16 ledctl; - - B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); - B43_WARN_ON(!led->blink_interval); - ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - ledctl ^= (1 << index); - b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); -} - -static void b43_led_blink(unsigned long d) -{ - struct b43_led *led = (struct b43_led *)d; - struct b43_wldev *dev = led->dev; + struct b43_wl *wl = dev->wl; unsigned long flags; + u16 ctl; - spin_lock_irqsave(&dev->wl->leds_lock, flags); - if (led->blink_interval) { - b43_led_changestate(led); - mod_timer(&led->blink_timer, jiffies + led->blink_interval); - } - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); + spin_lock_irqsave(&wl->leds_lock, flags); + ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + if (activelow) + ctl &= ~(1 << led_index); + else + ctl |= (1 << led_index); + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); + spin_unlock_irqrestore(&wl->leds_lock, flags); } -static void b43_led_blink_start(struct b43_led *led, unsigned long interval) +static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index, + bool activelow) { - if (led->blink_interval) - return; - led->blink_interval = interval; - b43_led_changestate(led); - led->blink_timer.expires = jiffies + interval; - add_timer(&led->blink_timer); + struct b43_wl *wl = dev->wl; + unsigned long flags; + u16 ctl; + + spin_lock_irqsave(&wl->leds_lock, flags); + ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + if (activelow) + ctl |= (1 << led_index); + else + ctl &= ~(1 << led_index); + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); + spin_unlock_irqrestore(&wl->leds_lock, flags); } -static void b43_led_blink_stop(struct b43_led *led, int sync) +/* Callback from the LED subsystem. */ +static void b43_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) { + struct b43_led *led = container_of(led_dev, struct b43_led, led_dev); struct b43_wldev *dev = led->dev; - const int index = led->index; - u16 ledctl; + bool radio_enabled; - if (!led->blink_interval) - return; - if (unlikely(sync)) - del_timer_sync(&led->blink_timer); - else - del_timer(&led->blink_timer); - led->blink_interval = 0; + /* Checking the radio-enabled status here is slightly racy, + * but we want to avoid the locking overhead and we don't care + * whether the LED has the wrong state for a second. */ + radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable); - /* Make sure the LED is turned off. */ - B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); - ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - if (led->activelow) - ledctl |= (1 << index); + if (brightness == LED_OFF || !radio_enabled) + b43_led_turn_off(dev, led->index, led->activelow); else - ledctl &= ~(1 << index); - b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); + b43_led_turn_on(dev, led->index, led->activelow); } -static void b43_led_init_hardcoded(struct b43_wldev *dev, - struct b43_led *led, int led_index) +static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, + const char *name, char *default_trigger, + u8 led_index, bool activelow) { - struct ssb_bus *bus = dev->dev->bus; + int err; - /* This function is called, if the behaviour (and activelow) - * information for a LED is missing in the SPROM. - * We hardcode the behaviour values for various devices here. - * Note that the B43_LED_TEST_XXX behaviour values can - * be used to figure out which led is mapped to which index. - */ + b43_led_turn_off(dev, led_index, activelow); + if (led->dev) + return -EEXIST; + if (!default_trigger) + return -EINVAL; + led->dev = dev; + led->index = led_index; + led->activelow = activelow; + strncpy(led->name, name, sizeof(led->name)); - switch (led_index) { - case 0: - led->behaviour = B43_LED_ACTIVITY; - led->activelow = 1; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) - led->behaviour = B43_LED_RADIO_ALL; + led->led_dev.name = led->name; + led->led_dev.default_trigger = default_trigger; + led->led_dev.brightness_set = b43_led_brightness_set; + + err = led_classdev_register(dev->dev->dev, &led->led_dev); + if (err) { + b43warn(dev->wl, "LEDs: Failed to register %s\n", name); + led->dev = NULL; + return err; + } + return 0; +} + +static void b43_unregister_led(struct b43_led *led) +{ + if (!led->dev) + return; + led_classdev_unregister(&led->led_dev); + b43_led_turn_off(led->dev, led->index, led->activelow); + led->dev = NULL; +} + +static void b43_map_led(struct b43_wldev *dev, + u8 led_index, + enum b43_led_behaviour behaviour, + bool activelow) +{ + struct ieee80211_hw *hw = dev->wl->hw; + char name[B43_LED_MAX_NAME_LEN + 1]; + + /* Map the b43 specific LED behaviour value to the + * generic LED triggers. */ + switch (behaviour) { + case B43_LED_INACTIVE: break; - case 1: - led->behaviour = B43_LED_RADIO_B; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) - led->behaviour = B43_LED_ASSOC; + case B43_LED_OFF: + b43_led_turn_off(dev, led_index, activelow); break; - case 2: - led->behaviour = B43_LED_RADIO_A; + case B43_LED_ON: + b43_led_turn_on(dev, led_index, activelow); break; - case 3: - led->behaviour = B43_LED_OFF; + case B43_LED_ACTIVITY: + case B43_LED_TRANSFER: + case B43_LED_APTRANSFER: + snprintf(name, sizeof(name), + "b43-%s:tx", wiphy_name(hw->wiphy)); + b43_register_led(dev, &dev->led_tx, name, + ieee80211_get_tx_led_name(hw), + led_index, activelow); + snprintf(name, sizeof(name), + "b43-%s:rx", wiphy_name(hw->wiphy)); + b43_register_led(dev, &dev->led_rx, name, + ieee80211_get_rx_led_name(hw), + led_index, activelow); + break; + /*FIXME: We need another trigger for the "radio-on" LEDs below. + * Wiggle that somehow into the rfkill subsystem. */ + case B43_LED_RADIO_ALL: + case B43_LED_RADIO_A: + case B43_LED_RADIO_B: + case B43_LED_MODE_BG: + case B43_LED_WEIRD: + case B43_LED_ASSOC: + snprintf(name, sizeof(name), + "b43-%s:assoc", wiphy_name(hw->wiphy)); + b43_register_led(dev, &dev->led_assoc, name, + ieee80211_get_assoc_led_name(hw), + led_index, activelow); break; default: - B43_WARN_ON(1); + b43warn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n", + behaviour); + break; } } -int b43_leds_init(struct b43_wldev *dev) +void b43_leds_init(struct b43_wldev *dev) { - struct b43_led *led; + struct ssb_bus *bus = dev->dev->bus; u8 sprom[4]; int i; + enum b43_led_behaviour behaviour; + bool activelow; - sprom[0] = dev->dev->bus->sprom.r1.gpio0; - sprom[1] = dev->dev->bus->sprom.r1.gpio1; - sprom[2] = dev->dev->bus->sprom.r1.gpio2; - sprom[3] = dev->dev->bus->sprom.r1.gpio3; - - for (i = 0; i < B43_NR_LEDS; i++) { - led = &(dev->leds[i]); - led->index = i; - led->dev = dev; - setup_timer(&led->blink_timer, - b43_led_blink, (unsigned long)led); + sprom[0] = bus->sprom.r1.gpio0; + sprom[1] = bus->sprom.r1.gpio1; + sprom[2] = bus->sprom.r1.gpio2; + sprom[3] = bus->sprom.r1.gpio3; + for (i = 0; i < 4; i++) { if (sprom[i] == 0xFF) { - b43_led_init_hardcoded(dev, led, i); + /* There is no LED information in the SPROM + * for this LED. Hardcode it here. */ + activelow = 0; + switch (i) { + case 0: + behaviour = B43_LED_ACTIVITY; + activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + behaviour = B43_LED_RADIO_ALL; + break; + case 1: + behaviour = B43_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + behaviour = B43_LED_ASSOC; + break; + case 2: + behaviour = B43_LED_RADIO_A; + break; + case 3: + behaviour = B43_LED_OFF; + break; + default: + B43_WARN_ON(1); + return; + } } else { - led->behaviour = sprom[i] & B43_LED_BEHAVIOUR; - led->activelow = !!(sprom[i] & B43_LED_ACTIVELOW); + behaviour = sprom[i] & B43_LED_BEHAVIOUR; + activelow = !!(sprom[i] & B43_LED_ACTIVELOW); } + b43_map_led(dev, i, behaviour, activelow); } - - return 0; } void b43_leds_exit(struct b43_wldev *dev) { - struct b43_led *led; - int i; - - for (i = 0; i < B43_NR_LEDS; i++) { - led = &(dev->leds[i]); - b43_led_blink_stop(led, 1); - } - b43_leds_switch_all(dev, 0); -} - -void b43_leds_update(struct b43_wldev *dev, int activity) -{ - struct b43_led *led; - struct b43_phy *phy = &dev->phy; - const int transferring = - (jiffies - dev->stats.last_tx) < B43_LED_XFER_THRES; - int i, turn_on; - unsigned long interval = 0; - u16 ledctl; - unsigned long flags; - bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); - - spin_lock_irqsave(&dev->wl->leds_lock, flags); - ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - for (i = 0; i < B43_NR_LEDS; i++) { - led = &(dev->leds[i]); - - turn_on = 0; - switch (led->behaviour) { - case B43_LED_INACTIVE: - continue; - case B43_LED_OFF: - break; - case B43_LED_ON: - turn_on = 1; - break; - case B43_LED_ACTIVITY: - turn_on = activity; - break; - case B43_LED_RADIO_ALL: - turn_on = radio_enabled; - break; - case B43_LED_RADIO_A: - turn_on = (radio_enabled && phy->type == B43_PHYTYPE_A); - break; - case B43_LED_RADIO_B: - turn_on = (radio_enabled && - (phy->type == B43_PHYTYPE_B - || phy->type == B43_PHYTYPE_G)); - break; - case B43_LED_MODE_BG: - if (phy->type == B43_PHYTYPE_G - && radio_enabled) - turn_on = 1; - break; - case B43_LED_TRANSFER: - if (transferring) - b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); - else - b43_led_blink_stop(led, 0); - continue; - case B43_LED_APTRANSFER: - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { - if (transferring) { - interval = B43_LEDBLINK_FAST; - turn_on = 1; - } - } else { - turn_on = 1; - if (0 /*TODO: not assoc */ ) - interval = B43_LEDBLINK_SLOW; - else if (transferring) - interval = B43_LEDBLINK_FAST; - else - turn_on = 0; - } - if (turn_on) - b43_led_blink_start(led, interval); - else - b43_led_blink_stop(led, 0); - continue; - case B43_LED_WEIRD: - //TODO - break; - case B43_LED_ASSOC: - if (1 /*dev->softmac->associated */ ) - turn_on = 1; - break; -#ifdef CONFIG_B43_DEBUG - case B43_LED_TEST_BLINKSLOW: - b43_led_blink_start(led, B43_LEDBLINK_SLOW); - continue; - case B43_LED_TEST_BLINKMEDIUM: - b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); - continue; - case B43_LED_TEST_BLINKFAST: - b43_led_blink_start(led, B43_LEDBLINK_FAST); - continue; -#endif /* CONFIG_B43_DEBUG */ - default: - B43_WARN_ON(1); - }; - - if (led->activelow) - turn_on = !turn_on; - if (turn_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); -} - -void b43_leds_switch_all(struct b43_wldev *dev, int on) -{ - struct b43_led *led; - u16 ledctl; - int i; - int bit_on; - unsigned long flags; - - spin_lock_irqsave(&dev->wl->leds_lock, flags); - ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - for (i = 0; i < B43_NR_LEDS; i++) { - led = &(dev->leds[i]); - if (led->behaviour == B43_LED_INACTIVE) - continue; - if (on) - bit_on = led->activelow ? 0 : 1; - else - bit_on = led->activelow ? 1 : 0; - if (bit_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); + b43_unregister_led(&dev->led_tx); + b43_unregister_led(&dev->led_rx); + b43_unregister_led(&dev->led_assoc); } diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h index d94851d291c0..b8b1dd521243 100644 --- a/drivers/net/wireless/b43/leds.h +++ b/drivers/net/wireless/b43/leds.h @@ -1,29 +1,33 @@ #ifndef B43_LEDS_H_ #define B43_LEDS_H_ +struct b43_wldev; + +#ifdef CONFIG_B43_LEDS + #include -#include +#include + + +#define B43_LED_MAX_NAME_LEN 31 struct b43_led { - u8 behaviour; - bool activelow; - /* Index in the "leds" array in b43_wldev */ - u8 index; struct b43_wldev *dev; - struct timer_list blink_timer; - unsigned long blink_interval; + /* The LED class device */ + struct led_classdev led_dev; + /* The index number of the LED. */ + u8 index; + /* If activelow is true, the LED is ON if the + * bit is switched off. */ + bool activelow; + /* The unique name string for this LED device. */ + char name[B43_LED_MAX_NAME_LEN + 1]; }; -/* Delay between state changes when blinking in jiffies */ -#define B43_LEDBLINK_SLOW (HZ / 1) -#define B43_LEDBLINK_MEDIUM (HZ / 4) -#define B43_LEDBLINK_FAST (HZ / 8) - -#define B43_LED_XFER_THRES (HZ / 100) - #define B43_LED_BEHAVIOUR 0x7F #define B43_LED_ACTIVELOW 0x80 -enum { /* LED behaviour values */ +/* LED behaviour values */ +enum b43_led_behaviour { B43_LED_OFF, B43_LED_ON, B43_LED_ACTIVITY, @@ -36,20 +40,25 @@ enum { /* LED behaviour values */ B43_LED_WEIRD, //FIXME B43_LED_ASSOC, B43_LED_INACTIVE, - - /* Behaviour values for testing. - * With these values it is easier to figure out - * the real behaviour of leds, in case the SPROM - * is missing information. - */ - B43_LED_TEST_BLINKSLOW, - B43_LED_TEST_BLINKMEDIUM, - B43_LED_TEST_BLINKFAST, }; -int b43_leds_init(struct b43_wldev *dev); +void b43_leds_init(struct b43_wldev *dev); void b43_leds_exit(struct b43_wldev *dev); -void b43_leds_update(struct b43_wldev *dev, int activity); -void b43_leds_switch_all(struct b43_wldev *dev, int on); + + +#else /* CONFIG_B43_LEDS */ +/* LED support disabled */ + +struct b43_led { + /* empty */ +}; + +static inline void b43_leds_init(struct b43_wldev *dev) +{ +} +static inline void b43_leds_exit(struct b43_wldev *dev) +{ +} +#endif /* CONFIG_B43_LEDS */ #endif /* B43_LEDS_H_ */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 72467c86f8d4..2b81bd6165d8 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -84,10 +84,6 @@ static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT; module_param_named(long_retry, modparam_long_retry, int, 0444); MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); -static int modparam_noleds; -module_param_named(noleds, modparam_noleds, int, 0444); -MODULE_PARM_DESC(noleds, "Turn off all LED activity"); - static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); @@ -1391,7 +1387,7 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) u32 reason; u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; - int i, activity = 0; + int i; unsigned long flags; spin_lock_irqsave(&dev->wl->irq_lock, flags); @@ -1444,8 +1440,9 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) handle_irq_beacon(dev); if (reason & B43_IRQ_PMQ) handle_irq_pmq(dev); - if (reason & B43_IRQ_TXFIFO_FLUSH_OK) ; - /*TODO*/ if (reason & B43_IRQ_NOISESAMPLE_OK) + if (reason & B43_IRQ_TXFIFO_FLUSH_OK) + ;/* TODO */ + if (reason & B43_IRQ_NOISESAMPLE_OK) handle_irq_noise(dev); /* Check the DMA reason registers for received data. */ @@ -1454,7 +1451,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) b43_pio_rx(dev->pio.queue0); else b43_dma_rx(dev->dma.rx_ring0); - /* We intentionally don't set "activity" to 1, here. */ } B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); @@ -1463,19 +1459,13 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) b43_pio_rx(dev->pio.queue3); else b43_dma_rx(dev->dma.rx_ring3); - activity = 1; } B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); - if (reason & B43_IRQ_TX_OK) { + if (reason & B43_IRQ_TX_OK) handle_irq_transmit_status(dev); - activity = 1; - //TODO: In AP mode, this also causes sending of powersave responses. - } - if (!modparam_noleds) - b43_leds_update(dev, activity); b43_interrupt_enable(dev, dev->irq_savedstate); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); @@ -1927,7 +1917,6 @@ static int b43_gpio_init(struct b43_wldev *dev) b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) & ~B43_MACCTL_GPOUTSMSK); - b43_leds_switch_all(dev, 0); b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 0x000F); @@ -2173,8 +2162,7 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) static void b43_chip_exit(struct b43_wldev *dev) { b43_radio_turn_off(dev); - if (!modparam_noleds) - b43_leds_exit(dev); + b43_leds_exit(dev); b43_gpio_cleanup(dev); /* firmware is released later */ } @@ -2202,9 +2190,11 @@ static int b43_chip_init(struct b43_wldev *dev) err = b43_gpio_init(dev); if (err) goto out; /* firmware is released later */ + b43_leds_init(dev); + err = b43_upload_initvals(dev); if (err) - goto err_gpio_cleanup; + goto err_leds_exit; b43_radio_turn_on(dev); b43_write16(dev, 0x03E6, 0x0000); @@ -2275,14 +2265,15 @@ static int b43_chip_init(struct b43_wldev *dev) err = 0; b43dbg(dev->wl, "Chip initialized\n"); - out: +out: return err; - err_radio_off: +err_radio_off: b43_radio_turn_off(dev); - err_gpio_cleanup: +err_leds_exit: + b43_leds_exit(dev); b43_gpio_cleanup(dev); - goto out; + return err; } static void b43_periodic_every120sec(struct b43_wldev *dev) @@ -2369,7 +2360,6 @@ static void b43_periodic_every1sec(struct b43_wldev *dev) dev->radio_hw_enable = radio_hw_enable; b43info(dev->wl, "Radio hardware status changed to %s\n", radio_hw_enable ? "ENABLED" : "DISABLED"); - b43_leds_update(dev, 0); } } @@ -3767,18 +3757,13 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } else have_bphy = 1; - /* Initialize LEDs structs. */ - err = b43_leds_init(dev); - if (err) - goto err_powerdown; - dev->phy.gmode = (have_gphy || have_bphy); tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; b43_wireless_core_reset(dev, tmp); err = b43_phy_versioning(dev); if (err) - goto err_leds_exit; + goto err_powerdown; /* Check if this device supports multiband. */ if (!pdev || (pdev->device != 0x4312 && @@ -3807,10 +3792,10 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) err = b43_validate_chipaccess(dev); if (err) - goto err_leds_exit; + goto err_powerdown; err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy); if (err) - goto err_leds_exit; + goto err_powerdown; /* Now set some default "current_dev" */ if (!wl->current_dev) @@ -3825,8 +3810,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) out: return err; -err_leds_exit: - b43_leds_exit(dev); err_powerdown: ssb_bus_may_powerdown(bus); return err; From 8e9f7529fdfe34ed519f048682eb404fbd8004e8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 27 Sep 2007 21:35:34 +0200 Subject: [PATCH 1671/2804] [B43]: RF-kill support This adds full support for the RFKILL button and the RFKILL LED trigger. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/Kconfig | 8 +- drivers/net/wireless/b43/Makefile | 2 + drivers/net/wireless/b43/b43.h | 5 + drivers/net/wireless/b43/leds.c | 8 +- drivers/net/wireless/b43/main.c | 18 ++-- drivers/net/wireless/b43/phy.c | 13 ++- drivers/net/wireless/b43/phy.h | 2 +- drivers/net/wireless/b43/rfkill.c | 155 ++++++++++++++++++++++++++++++ drivers/net/wireless/b43/rfkill.h | 49 ++++++++++ 9 files changed, 245 insertions(+), 15 deletions(-) create mode 100644 drivers/net/wireless/b43/rfkill.c create mode 100644 drivers/net/wireless/b43/rfkill.h diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 1575654556b0..968f0611ed49 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -64,7 +64,13 @@ config B43_PCMCIA # LED support config B43_LEDS bool - depends on MAC80211_LEDS + depends on B43 && MAC80211_LEDS + default y + +# RFKILL support +config B43_RFKILL + bool + depends on B43 && RFKILL default y config B43_DEBUG diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index e6331414c4ca..485e59e2dfab 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -5,6 +5,8 @@ b43-y += phy.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o +# b43 RFKILL button support +b43-$(CONFIG_B43_RFKILL) += rfkill.o # b43 LED support b43-$(CONFIG_B43_LEDS) += leds.o # b43 PCMCIA support diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 6e6b59227e16..a28ad230d63e 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -10,6 +10,7 @@ #include "debugfs.h" #include "leds.h" +#include "rfkill.h" #include "lo.h" #include "phy.h" @@ -625,6 +626,9 @@ struct b43_wl { u8 rng_initialized; char rng_name[30 + 1]; + /* The RF-kill button */ + struct b43_rfkill rfkill; + /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; @@ -700,6 +704,7 @@ struct b43_wldev { struct b43_led led_tx; struct b43_led led_rx; struct b43_led led_assoc; + struct b43_led led_radio; /* Reason code of the last interrupt. */ u32 irq_reason; diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index ddab856f1140..19e588582c7c 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -154,12 +154,16 @@ static void b43_map_led(struct b43_wldev *dev, ieee80211_get_rx_led_name(hw), led_index, activelow); break; - /*FIXME: We need another trigger for the "radio-on" LEDs below. - * Wiggle that somehow into the rfkill subsystem. */ case B43_LED_RADIO_ALL: case B43_LED_RADIO_A: case B43_LED_RADIO_B: case B43_LED_MODE_BG: + snprintf(name, sizeof(name), + "b43-%s:radio", wiphy_name(hw->wiphy)); + b43_register_led(dev, &dev->led_radio, name, + b43_rfkill_led_name(dev), + led_index, activelow); + break; case B43_LED_WEIRD: case B43_LED_ASSOC: snprintf(name, sizeof(name), diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2b81bd6165d8..a9f7148493f7 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2161,7 +2161,7 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 1); b43_leds_exit(dev); b43_gpio_cleanup(dev); /* firmware is released later */ @@ -2269,7 +2269,7 @@ out: return err; err_radio_off: - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 1); err_leds_exit: b43_leds_exit(dev); b43_gpio_cleanup(dev); @@ -2358,8 +2358,7 @@ static void b43_periodic_every1sec(struct b43_wldev *dev) radio_hw_enable = b43_is_hw_radio_enabled(dev); if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { dev->radio_hw_enable = radio_hw_enable; - b43info(dev->wl, "Radio hardware status changed to %s\n", - radio_hw_enable ? "ENABLED" : "DISABLED"); + b43_rfkill_toggled(dev, radio_hw_enable); } } @@ -2850,7 +2849,7 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) "Press the button to turn it on.\n"); } } else { - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 0); b43info(dev->wl, "Radio turned off by software\n"); } } @@ -3330,11 +3329,15 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) return; b43_set_status(dev, B43_STAT_UNINIT); + mutex_unlock(&dev->wl->mutex); + b43_rfkill_exit(dev); + mutex_lock(&dev->wl->mutex); + b43_rng_exit(dev->wl); b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); if (phy->dyn_tssi_tbl) kfree(phy->tssi2dbm); @@ -3458,6 +3461,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) memset(wl->mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); b43_security_init(dev); + b43_rfkill_init(dev); b43_rng_init(wl); b43_set_status(dev, B43_STAT_INITIALIZED); @@ -3802,7 +3806,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 354d18238752..5f7ffa0a76c0 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -4349,10 +4349,13 @@ void b43_radio_turn_on(struct b43_wldev *dev) phy->radio_on = 1; } -void b43_radio_turn_off(struct b43_wldev *dev) +void b43_radio_turn_off(struct b43_wldev *dev, bool force) { struct b43_phy *phy = &dev->phy; + if (!phy->radio_on && !force) + return; + if (phy->type == B43_PHYTYPE_A) { b43_radio_write16(dev, 0x0004, 0x00FF); b43_radio_write16(dev, 0x0005, 0x00FB); @@ -4364,9 +4367,11 @@ void b43_radio_turn_off(struct b43_wldev *dev) rfover = b43_phy_read(dev, B43_PHY_RFOVER); rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); - phy->radio_off_context.rfover = rfover; - phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; + if (!force) { + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + } b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); } else diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h index d1f623cb9b34..c64d74504fc0 100644 --- a/drivers/net/wireless/b43/phy.h +++ b/drivers/net/wireless/b43/phy.h @@ -267,7 +267,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev); void b43_radio_init2060(struct b43_wldev *dev); void b43_radio_turn_on(struct b43_wldev *dev); -void b43_radio_turn_off(struct b43_wldev *dev); +void b43_radio_turn_off(struct b43_wldev *dev, bool force); int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel, int synthetic_pu_workaround); diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c new file mode 100644 index 000000000000..c25fd9956a9c --- /dev/null +++ b/drivers/net/wireless/b43/rfkill.c @@ -0,0 +1,155 @@ +/* + + Broadcom B43 wireless driver + RFKILL support + + Copyright (c) 2007 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "rfkill.h" +#include "b43.h" + + +static void b43_notify_rfkill_press(struct work_struct *work) +{ + struct b43_rfkill *rfk = container_of(work, struct b43_rfkill, + notify_work); + struct b43_wl *wl = container_of(rfk, struct b43_wl, rfkill); + struct b43_wldev *dev; + enum rfkill_state state; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (b43_status(dev) < B43_STAT_INITIALIZED) { + mutex_unlock(&wl->mutex); + return; + } + if (dev->radio_hw_enable) + state = RFKILL_STATE_ON; + else + state = RFKILL_STATE_OFF; + b43info(wl, "Radio hardware status changed to %s\n", + dev->radio_hw_enable ? "ENABLED" : "DISABLED"); + mutex_unlock(&wl->mutex); + + if (rfk->rfkill) { + /* Be careful. This calls back into the software toggle routines. + * So we must unlock before calling. */ + rfkill_switch_all(rfk->rfkill->type, state); + } +} + +/* Called when the RFKILL toggled in hardware. + * This is called with the mutex locked. */ +void b43_rfkill_toggled(struct b43_wldev *dev, bool on) +{ + struct b43_wl *wl = dev->wl; + + B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED); + /* Update the RF status asynchronously, as rfkill will + * call back into the software toggle handler. + * This would deadlock if done synchronously. */ + queue_work(wl->hw->workqueue, &wl->rfkill.notify_work); +} + +/* Called when the RFKILL toggled in software. + * This is called without locking. */ +static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) +{ + struct b43_wldev *dev = data; + struct b43_wl *wl = dev->wl; + int err = 0; + + mutex_lock(&wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) + goto out_unlock; + + switch (state) { + case RFKILL_STATE_ON: + if (!dev->radio_hw_enable) { + /* No luck. We can't toggle the hardware RF-kill + * button from software. */ + err = -EBUSY; + goto out_unlock; + } + if (!dev->phy.radio_on) + b43_radio_turn_on(dev); + break; + case RFKILL_STATE_OFF: + if (dev->phy.radio_on) + b43_radio_turn_off(dev, 0); + break; + } + +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +char * b43_rfkill_led_name(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + + if (!wl->rfkill.rfkill) + return NULL; + return rfkill_get_led_name(wl->rfkill.rfkill); +} + +void b43_rfkill_init(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct b43_rfkill *rfk = &(wl->rfkill); + int err; + + snprintf(rfk->name, sizeof(rfk->name), + "b43-%s", wiphy_name(wl->hw->wiphy)); + rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); + if (!rfk->rfkill) + goto error; + rfk->rfkill->name = rfk->name; + rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->data = dev; + rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; + rfk->rfkill->user_claim_unsupported = 1; + + INIT_WORK(&rfk->notify_work, b43_notify_rfkill_press); + + err = rfkill_register(rfk->rfkill); + if (err) + goto error; + + return; +error: + b43warn(dev->wl, "Failed to initialize the RF-kill button\n"); + rfkill_free(rfk->rfkill); + rfk->rfkill = NULL; +} + +void b43_rfkill_exit(struct b43_wldev *dev) +{ + struct b43_rfkill *rfk = &(dev->wl->rfkill); + + if (!rfk->rfkill) + return; + cancel_work_sync(&rfk->notify_work); + rfkill_unregister(rfk->rfkill); + rfkill_free(rfk->rfkill); + rfk->rfkill = NULL; +} diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h new file mode 100644 index 000000000000..05db0d67a92e --- /dev/null +++ b/drivers/net/wireless/b43/rfkill.h @@ -0,0 +1,49 @@ +#ifndef B43_RFKILL_H_ +#define B43_RFKILL_H_ + +struct b43_wldev; + + +#ifdef CONFIG_B43_RFKILL + +#include + +struct b43_rfkill { + /* The RFKILL subsystem data structure */ + struct rfkill *rfkill; + /* The unique name of this rfkill switch */ + char name[32]; + /* Workqueue for asynchronous notification. */ + struct work_struct notify_work; +}; + +void b43_rfkill_init(struct b43_wldev *dev); +void b43_rfkill_exit(struct b43_wldev *dev); +void b43_rfkill_toggled(struct b43_wldev *dev, bool on); +char * b43_rfkill_led_name(struct b43_wldev *dev); + + +#else /* CONFIG_B43_RFKILL */ +/* No RFKILL support. */ + +struct b43_rfkill { + /* empty */ +}; + +static inline void b43_rfkill_init(struct b43_wldev *dev) +{ +} +static inline void b43_rfkill_exit(struct b43_wldev *dev) +{ +} +static inline void b43_rfkill_toggled(struct b43_wldev *dev, bool on) +{ +} +static inline char * b43_rfkill_led_name(struct b43_wldev *dev) +{ + return NULL; +} + +#endif /* CONFIG_B43_RFKILL */ + +#endif /* B43_RFKILL_H_ */ From 42bb4cd5ae320dd46630533fecb91b940d4468e2 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 28 Sep 2007 14:22:33 +0200 Subject: [PATCH 1672/2804] [B43]: Use input-polldev for the rfkill switch This removes the direct call to rfkill on an rfkill event and replaces it with an input device. This way userspace is also notified about the event. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/Kconfig | 2 +- drivers/net/wireless/b43/main.c | 53 +++--------- drivers/net/wireless/b43/rfkill.c | 135 ++++++++++++++++++------------ drivers/net/wireless/b43/rfkill.h | 21 +++-- 4 files changed, 110 insertions(+), 101 deletions(-) diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 968f0611ed49..e3c573e56b63 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -70,7 +70,7 @@ config B43_LEDS # RFKILL support config B43_RFKILL bool - depends on B43 && RFKILL + depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV default y config B43_DEBUG diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a9f7148493f7..a603a154d496 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2143,21 +2143,6 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); } -/* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) -{ - if (dev->phy.rev >= 3) { - if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) - & B43_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { - if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) - & B43_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; - } - return 0; -} - /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { @@ -2350,32 +2335,18 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) //TODO for APHY (temperature?) } -static void b43_periodic_every1sec(struct b43_wldev *dev) -{ - bool radio_hw_enable; - - /* check if radio hardware enabled status changed */ - radio_hw_enable = b43_is_hw_radio_enabled(dev); - if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { - dev->radio_hw_enable = radio_hw_enable; - b43_rfkill_toggled(dev, radio_hw_enable); - } -} - static void do_periodic_work(struct b43_wldev *dev) { unsigned int state; state = dev->periodic_state; - if (state % 120 == 0) + if (state % 8 == 0) b43_periodic_every120sec(dev); - if (state % 60 == 0) + if (state % 4 == 0) b43_periodic_every60sec(dev); - if (state % 30 == 0) + if (state % 2 == 0) b43_periodic_every30sec(dev); - if (state % 15 == 0) - b43_periodic_every15sec(dev); - b43_periodic_every1sec(dev); + b43_periodic_every15sec(dev); } /* Estimate a "Badness" value based on the periodic work @@ -2386,13 +2357,11 @@ static int estimate_periodic_work_badness(unsigned int state) { int badness = 0; - if (state % 120 == 0) /* every 120 sec */ + if (state % 8 == 0) /* every 120 sec */ badness += 10; - if (state % 60 == 0) /* every 60 sec */ + if (state % 4 == 0) /* every 60 sec */ badness += 5; - if (state % 30 == 0) /* every 30 sec */ - badness += 1; - if (state % 15 == 0) /* every 15 sec */ + if (state % 2 == 0) /* every 30 sec */ badness += 1; #define BADNESS_LIMIT 4 @@ -2443,13 +2412,13 @@ static void b43_periodic_work_handler(struct work_struct *work) spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } dev->periodic_state++; - out_requeue: +out_requeue: if (b43_debug(dev, B43_DBG_PWORK_FAST)) delay = msecs_to_jiffies(50); else - delay = round_jiffies(HZ); + delay = round_jiffies(HZ * 15); queue_delayed_work(dev->wl->hw->workqueue, &dev->periodic_work, delay); - out: +out: mutex_unlock(&dev->wl->mutex); } @@ -3720,6 +3689,7 @@ static int b43_setup_modes(struct b43_wldev *dev, static void b43_wireless_core_detach(struct b43_wldev *dev) { + b43_rfkill_free(dev); /* We release firmware that late to not be required to re-request * is all the time when we reinit the core. */ b43_release_firmware(dev); @@ -3805,6 +3775,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) if (!wl->current_dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); + b43_rfkill_alloc(dev); b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index c25fd9956a9c..800e0a61a7f5 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -26,46 +26,39 @@ #include "b43.h" -static void b43_notify_rfkill_press(struct work_struct *work) +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) { - struct b43_rfkill *rfk = container_of(work, struct b43_rfkill, - notify_work); - struct b43_wl *wl = container_of(rfk, struct b43_wl, rfkill); - struct b43_wldev *dev; - enum rfkill_state state; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (b43_status(dev) < B43_STAT_INITIALIZED) { - mutex_unlock(&wl->mutex); - return; - } - if (dev->radio_hw_enable) - state = RFKILL_STATE_ON; - else - state = RFKILL_STATE_OFF; - b43info(wl, "Radio hardware status changed to %s\n", - dev->radio_hw_enable ? "ENABLED" : "DISABLED"); - mutex_unlock(&wl->mutex); - - if (rfk->rfkill) { - /* Be careful. This calls back into the software toggle routines. - * So we must unlock before calling. */ - rfkill_switch_all(rfk->rfkill->type, state); + if (dev->phy.rev >= 3) { + if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) + & B43_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) + & B43_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; } + return 0; } -/* Called when the RFKILL toggled in hardware. - * This is called with the mutex locked. */ -void b43_rfkill_toggled(struct b43_wldev *dev, bool on) +/* The poll callback for the hardware button. */ +static void b43_rfkill_poll(struct input_polled_dev *poll_dev) { + struct b43_wldev *dev = poll_dev->private; struct b43_wl *wl = dev->wl; + bool enabled; + mutex_lock(&wl->mutex); B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED); - /* Update the RF status asynchronously, as rfkill will - * call back into the software toggle handler. - * This would deadlock if done synchronously. */ - queue_work(wl->hw->workqueue, &wl->rfkill.notify_work); + enabled = b43_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { + dev->radio_hw_enable = enabled; + b43info(wl, "Radio hardware status changed to %s\n", + enabled ? "ENABLED" : "DISABLED"); + mutex_unlock(&wl->mutex); + input_report_key(poll_dev->input, KEY_WLAN, enabled); + } else + mutex_unlock(&wl->mutex); } /* Called when the RFKILL toggled in software. @@ -118,38 +111,74 @@ void b43_rfkill_init(struct b43_wldev *dev) struct b43_rfkill *rfk = &(wl->rfkill); int err; - snprintf(rfk->name, sizeof(rfk->name), - "b43-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto error; - rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_ON; - rfk->rfkill->data = dev; - rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; - rfk->rfkill->user_claim_unsupported = 1; - - INIT_WORK(&rfk->notify_work, b43_notify_rfkill_press); - - err = rfkill_register(rfk->rfkill); - if (err) - goto error; + if (rfk->rfkill) { + err = rfkill_register(rfk->rfkill); + if (err) { + b43warn(wl, "Failed to register RF-kill button\n"); + goto err_free_rfk; + } + } + if (rfk->poll_dev) { + err = input_register_polled_device(rfk->poll_dev); + if (err) { + b43warn(wl, "Failed to register RF-kill polldev\n"); + goto err_free_polldev; + } + } return; -error: - b43warn(dev->wl, "Failed to initialize the RF-kill button\n"); +err_free_rfk: rfkill_free(rfk->rfkill); rfk->rfkill = NULL; +err_free_polldev: + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; } void b43_rfkill_exit(struct b43_wldev *dev) { struct b43_rfkill *rfk = &(dev->wl->rfkill); - if (!rfk->rfkill) + if (rfk->poll_dev) + input_unregister_polled_device(rfk->poll_dev); + if (rfk->rfkill) + rfkill_unregister(rfk->rfkill); +} + +void b43_rfkill_alloc(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct b43_rfkill *rfk = &(wl->rfkill); + + snprintf(rfk->name, sizeof(rfk->name), + "b43-%s", wiphy_name(wl->hw->wiphy)); + + rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); + if (!rfk->rfkill) { + b43warn(wl, "Failed to allocate RF-kill button\n"); return; - cancel_work_sync(&rfk->notify_work); - rfkill_unregister(rfk->rfkill); + } + rfk->rfkill->name = rfk->name; + rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->data = dev; + rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; + rfk->rfkill->user_claim_unsupported = 1; + + rfk->poll_dev = input_allocate_polled_device(); + if (rfk->poll_dev) { + rfk->poll_dev->private = dev; + rfk->poll_dev->poll = b43_rfkill_poll; + rfk->poll_dev->poll_interval = 1000; /* msecs */ + } else + b43warn(wl, "Failed to allocate RF-kill polldev\n"); +} + +void b43_rfkill_free(struct b43_wldev *dev) +{ + struct b43_rfkill *rfk = &(dev->wl->rfkill); + + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; rfkill_free(rfk->rfkill); rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index 05db0d67a92e..29544e8c9e5f 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h @@ -7,19 +7,25 @@ struct b43_wldev; #ifdef CONFIG_B43_RFKILL #include +#include + struct b43_rfkill { /* The RFKILL subsystem data structure */ struct rfkill *rfkill; + /* The poll device for the RFKILL input button */ + struct input_polled_dev *poll_dev; /* The unique name of this rfkill switch */ char name[32]; - /* Workqueue for asynchronous notification. */ - struct work_struct notify_work; }; +/* All the init functions return void, because we are not interested + * in failing the b43 init process when rfkill init failed. */ +void b43_rfkill_alloc(struct b43_wldev *dev); +void b43_rfkill_free(struct b43_wldev *dev); void b43_rfkill_init(struct b43_wldev *dev); void b43_rfkill_exit(struct b43_wldev *dev); -void b43_rfkill_toggled(struct b43_wldev *dev, bool on); + char * b43_rfkill_led_name(struct b43_wldev *dev); @@ -30,15 +36,18 @@ struct b43_rfkill { /* empty */ }; +static inline void b43_rfkill_alloc(struct b43_wldev *dev) +{ +} +static inline void b43_rfkill_free(struct b43_wldev *dev) +{ +} static inline void b43_rfkill_init(struct b43_wldev *dev) { } static inline void b43_rfkill_exit(struct b43_wldev *dev) { } -static inline void b43_rfkill_toggled(struct b43_wldev *dev, bool on) -{ -} static inline char * b43_rfkill_led_name(struct b43_wldev *dev) { return NULL; From 05b64b364822863974c0121359b01d7ba0f22205 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 28 Sep 2007 16:19:03 +0200 Subject: [PATCH 1673/2804] [B43]: Rewrite pwork locking policy. Implement much easier and more lightweight locking for the periodic work. This also removes the last big busywait loop and replaces it by a sleeping loop. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/main.c | 88 ++++++++++++--------------------- 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a603a154d496..6c80f2e2f4ee 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1976,6 +1976,7 @@ void b43_mac_enable(struct b43_wldev *dev) { dev->mac_suspended--; B43_WARN_ON(dev->mac_suspended < 0); + B43_WARN_ON(irqs_disabled()); if (dev->mac_suspended == 0) { b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) @@ -1986,6 +1987,11 @@ void b43_mac_enable(struct b43_wldev *dev) b43_read32(dev, B43_MMIO_MACCTL); b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); b43_power_saving_ctl_bits(dev, 0); + + /* Re-enable IRQs. */ + spin_lock_irq(&dev->wl->irq_lock); + b43_interrupt_enable(dev, dev->irq_savedstate); + spin_unlock_irq(&dev->wl->irq_lock); } } @@ -1995,23 +2001,34 @@ void b43_mac_suspend(struct b43_wldev *dev) int i; u32 tmp; + might_sleep(); + B43_WARN_ON(irqs_disabled()); B43_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + /* Mask IRQs before suspending MAC. Otherwise + * the MAC stays busy and won't suspend. */ + spin_lock_irq(&dev->wl->irq_lock); + tmp = b43_interrupt_disable(dev, B43_IRQ_ALL); + spin_unlock_irq(&dev->wl->irq_lock); + b43_synchronize_irq(dev); + dev->irq_savedstate = tmp; + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) & ~B43_MACCTL_ENABLED); /* force pci to flush the write */ b43_read32(dev, B43_MMIO_MACCTL); - for (i = 10000; i; i--) { + for (i = 40; i; i--) { tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (tmp & B43_IRQ_MAC_SUSPENDED) goto out; - udelay(1); + msleep(1); } b43err(dev->wl, "MAC suspend failed\n"); } - out: +out: dev->mac_suspended++; } @@ -2349,77 +2366,36 @@ static void do_periodic_work(struct b43_wldev *dev) b43_periodic_every15sec(dev); } -/* Estimate a "Badness" value based on the periodic work - * state-machine state. "Badness" is worse (bigger), if the - * periodic work will take longer. +/* Periodic work locking policy: + * The whole periodic work handler is protected by + * wl->mutex. If another lock is needed somewhere in the + * pwork callchain, it's aquired in-place, where it's needed. */ -static int estimate_periodic_work_badness(unsigned int state) -{ - int badness = 0; - - if (state % 8 == 0) /* every 120 sec */ - badness += 10; - if (state % 4 == 0) /* every 60 sec */ - badness += 5; - if (state % 2 == 0) /* every 30 sec */ - badness += 1; - -#define BADNESS_LIMIT 4 - return badness; -} - static void b43_periodic_work_handler(struct work_struct *work) { - struct b43_wldev *dev = - container_of(work, struct b43_wldev, periodic_work.work); - unsigned long flags, delay; - u32 savedirqs = 0; - int badness; + struct b43_wldev *dev = container_of(work, struct b43_wldev, + periodic_work.work); + struct b43_wl *wl = dev->wl; + unsigned long delay; - mutex_lock(&dev->wl->mutex); + mutex_lock(&wl->mutex); if (unlikely(b43_status(dev) != B43_STAT_STARTED)) goto out; if (b43_debug(dev, B43_DBG_PWORK_STOP)) goto out_requeue; - badness = estimate_periodic_work_badness(dev->periodic_state); - if (badness > BADNESS_LIMIT) { - spin_lock_irqsave(&dev->wl->irq_lock, flags); - /* Suspend TX as we don't want to transmit packets while - * we recalibrate the hardware. */ - b43_tx_suspend(dev); - savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); - /* Periodic work will take a long time, so we want it to - * be preemtible and release the spinlock. */ - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - b43_synchronize_irq(dev); + do_periodic_work(dev); - do_periodic_work(dev); - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - b43_interrupt_enable(dev, savedirqs); - b43_tx_resume(dev); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } else { - /* Take the global driver lock. This will lock any operation. */ - spin_lock_irqsave(&dev->wl->irq_lock, flags); - - do_periodic_work(dev); - - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } dev->periodic_state++; out_requeue: if (b43_debug(dev, B43_DBG_PWORK_FAST)) delay = msecs_to_jiffies(50); else delay = round_jiffies(HZ * 15); - queue_delayed_work(dev->wl->hw->workqueue, &dev->periodic_work, delay); + queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); out: - mutex_unlock(&dev->wl->mutex); + mutex_unlock(&wl->mutex); } static void b43_periodic_tasks_setup(struct b43_wldev *dev) From f7c4daed99fba15e4e48df464031f4ac7c32e4c9 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 24 Sep 2007 18:41:49 +0200 Subject: [PATCH 1674/2804] [MAC80211]: Check open_count before calling config callback. Also remove the check for ops->config!=NULL, as it can never be NULL. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 210319f9ea2f..62877a8f9f0f 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -678,7 +678,7 @@ int ieee80211_hw_config(struct ieee80211_local *local) local->hw.conf.phymode); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - if (local->ops->config) + if (local->open_count) ret = local->ops->config(local_to_hw(local), &local->hw.conf); return ret; From a28975525016ddcbdaab8225666df1cf2dc9cb2d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Sep 2007 14:01:25 +0200 Subject: [PATCH 1675/2804] [MAC80211]: add "invalid" interface type Since I cannot convince the lazy driver authors (hello Michael) to stop (ab)using the MGMT interface type internally in their drivers, this patch introduces a new _INVALID type especially for their use and changes all affected drivers to use it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/adm8211.c | 8 ++++---- drivers/net/wireless/p54common.c | 4 ++-- drivers/net/wireless/p54pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- include/net/mac80211.h | 3 +++ net/mac80211/ieee80211.c | 4 ++++ net/mac80211/ieee80211_iface.c | 4 ++++ net/mac80211/rx.c | 1 + 8 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index e4fdadb52503..5bf7913aadda 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1555,7 +1555,7 @@ static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_INVALID; priv->nar = 0; ADM8211_CSR_WRITE(NAR, 0); ADM8211_CSR_WRITE(IER, 0); @@ -1898,7 +1898,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_INVALID; /* Power-on issue. EEPROM won't read correctly without */ if (pdev->revision >= ADM8211_REV_BA) { @@ -1993,7 +1993,7 @@ 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 != IEEE80211_IF_TYPE_MGMT) { + if (priv->mode != IEEE80211_IF_TYPE_INVALID) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2011,7 +2011,7 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->mode != IEEE80211_IF_TYPE_INVALID) { adm8211_start(dev); ieee80211_start_queues(dev); } diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c index 9befd6cc7911..2c63cf0ad2cd 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -797,7 +797,7 @@ static void p54_stop(struct ieee80211_hw *dev) kfree_skb(skb); } priv->stop(dev); - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_INVALID; } static int p54_add_interface(struct ieee80211_hw *dev, @@ -949,7 +949,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) return NULL; priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_INVALID; skb_queue_head_init(&priv->tx_queue); memcpy(priv->channels, p54_channels, sizeof(p54_channels)); memcpy(priv->rates, p54_rates, sizeof(p54_rates)); diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c index 75927583f766..410b54387f23 100644 --- a/drivers/net/wireless/p54pci.c +++ b/drivers/net/wireless/p54pci.c @@ -640,7 +640,7 @@ static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct p54p_priv *priv = dev->priv; - if (priv->common.mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { ieee80211_stop_queues(dev); p54p_stop(dev); } @@ -658,7 +658,7 @@ static int p54p_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->common.mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { p54p_open(dev); ieee80211_start_queues(dev); } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 511c11c4edda..6262d4e47c56 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -297,7 +297,7 @@ struct interface { * When set to INVALID_INTERFACE, no interface is configured. */ int type; -#define INVALID_INTERFACE IEEE80211_IF_TYPE_MGMT +#define INVALID_INTERFACE IEEE80211_IF_TYPE_INVALID /* * MAC of the device. diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6ec12bd3a3ec..bd72f59e98fd 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -457,6 +457,8 @@ struct ieee80211_conf { /** * enum ieee80211_if_types - types of 802.11 network interfaces * + * @IEEE80211_IF_TYPE_INVALID: invalid interface type, not used + * by mac80211 itself * @IEEE80211_IF_TYPE_AP: interface in AP mode. * @IEEE80211_IF_TYPE_MGMT: special interface for communication with hostap * daemon. Drivers should never see this type. @@ -468,6 +470,7 @@ struct ieee80211_conf { * will never see this type. */ enum ieee80211_if_types { + IEEE80211_IF_TYPE_INVALID, IEEE80211_IF_TYPE_AP, IEEE80211_IF_TYPE_MGMT, IEEE80211_IF_TYPE_STA, diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 62877a8f9f0f..373e8b728782 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -351,6 +351,10 @@ static int ieee80211_open(struct net_device *dev) case IEEE80211_IF_TYPE_IBSS: /* no special treatment */ break; + case IEEE80211_IF_TYPE_INVALID: + /* cannot happen */ + WARN_ON(1); + break; } if (local->open_count == 0) { diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 08c1e188d4b8..ef618e947e2b 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -243,6 +243,10 @@ void ieee80211_if_reinit(struct net_device *dev) ieee80211_if_sdata_deinit(sdata); switch (sdata->type) { + case IEEE80211_IF_TYPE_INVALID: + /* cannot happen */ + WARN_ON(1); + break; case IEEE80211_IF_TYPE_MGMT: /* nothing to do */ break; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 03635fb3e9b6..b4a62fe3ccbd 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1453,6 +1453,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case IEEE80211_IF_TYPE_MNTR: /* take everything */ break; + case IEEE80211_IF_TYPE_INVALID: case IEEE80211_IF_TYPE_MGMT: /* should never get here */ WARN_ON(1); From f9d540ee5f7e480339911df8d7389ef4c435ab54 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Sep 2007 14:02:09 +0200 Subject: [PATCH 1676/2804] [MAC80211]: remove management interface Removes the management interface since it is only required for hostapd/userspace MLME, will not be in the final tree at least in this form and hostapd/userspace MLME currently do not work against this tree anyway. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 1 - net/mac80211/ieee80211.c | 181 +-------------------------------- net/mac80211/ieee80211_i.h | 9 -- net/mac80211/ieee80211_iface.c | 66 ------------ net/mac80211/ieee80211_rate.c | 3 +- net/mac80211/ieee80211_rate.h | 2 - net/mac80211/ieee80211_sta.c | 2 - net/mac80211/rx.c | 32 ++---- net/mac80211/tx.c | 14 +-- net/mac80211/wme.c | 10 +- 10 files changed, 14 insertions(+), 306 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index bd72f59e98fd..c143ac8965db 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -472,7 +472,6 @@ struct ieee80211_conf { enum ieee80211_if_types { IEEE80211_IF_TYPE_INVALID, IEEE80211_IF_TYPE_AP, - IEEE80211_IF_TYPE_MGMT, IEEE80211_IF_TYPE_STA, IEEE80211_IF_TYPE_IBSS, IEEE80211_IF_TYPE_MNTR, diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 373e8b728782..804da5e89bbf 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -24,7 +24,6 @@ #include #include -#include "ieee80211_common.h" #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "wep.h" @@ -123,151 +122,6 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev) ieee80211_configure_filter(local); } -/* management interface */ - -static void -ieee80211_fill_frame_info(struct ieee80211_local *local, - struct ieee80211_frame_info *fi, - struct ieee80211_rx_status *status) -{ - if (status) { - struct timespec ts; - struct ieee80211_rate *rate; - - jiffies_to_timespec(jiffies, &ts); - fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 + - ts.tv_nsec / 1000); - fi->mactime = cpu_to_be64(status->mactime); - switch (status->phymode) { - case MODE_IEEE80211A: - fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a); - break; - case MODE_IEEE80211B: - fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b); - break; - case MODE_IEEE80211G: - fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g); - break; - default: - fi->phytype = htonl(0xAAAAAAAA); - break; - } - fi->channel = htonl(status->channel); - rate = ieee80211_get_rate(local, status->phymode, - status->rate); - if (rate) { - fi->datarate = htonl(rate->rate); - if (rate->flags & IEEE80211_RATE_PREAMBLE2) { - if (status->rate == rate->val) - fi->preamble = htonl(2); /* long */ - else if (status->rate == rate->val2) - fi->preamble = htonl(1); /* short */ - } else - fi->preamble = htonl(0); - } else { - fi->datarate = htonl(0); - fi->preamble = htonl(0); - } - - fi->antenna = htonl(status->antenna); - fi->priority = htonl(0xffffffff); /* no clue */ - fi->ssi_type = htonl(ieee80211_ssi_raw); - fi->ssi_signal = htonl(status->ssi); - fi->ssi_noise = 0x00000000; - fi->encoding = 0; - } else { - /* clear everything because we really don't know. - * the msg_type field isn't present on monitor frames - * so we don't know whether it will be present or not, - * but it's ok to not clear it since it'll be assigned - * anyway */ - memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type)); - - fi->ssi_type = htonl(ieee80211_ssi_none); - } - fi->version = htonl(IEEE80211_FI_VERSION); - fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type)); -} - -/* this routine is actually not just for this, but also - * for pushing fake 'management' frames into userspace. - * it shall be replaced by a netlink-based system. */ -void -ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_rx_status *status, u32 msg_type) -{ - struct ieee80211_frame_info *fi; - const size_t hlen = sizeof(struct ieee80211_frame_info); - struct net_device *dev = local->apdev; - - skb->dev = dev; - - if (skb_headroom(skb) < hlen) { - I802_DEBUG_INC(local->rx_expand_skb_head); - if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return; - } - } - - fi = (struct ieee80211_frame_info *) skb_push(skb, hlen); - - ieee80211_fill_frame_info(local, fi, status); - fi->msg_type = htonl(msg_type); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - -static int ieee80211_mgmt_open(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (!netif_running(local->mdev)) - return -EOPNOTSUPP; - return 0; -} - -static int ieee80211_mgmt_stop(struct net_device *dev) -{ - return 0; -} - -static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu) -{ - /* FIX: what would be proper limits for MTU? - * This interface uses 802.11 frames. */ - if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) { - printk(KERN_WARNING "%s: invalid MTU %d\n", - dev->name, new_mtu); - return -EINVAL; - } - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - dev->mtu = new_mtu; - return 0; -} - -void ieee80211_if_mgmt_setup(struct net_device *dev) -{ - ether_setup(dev); - dev->hard_start_xmit = ieee80211_mgmt_start_xmit; - dev->change_mtu = ieee80211_change_mtu_apdev; - dev->open = ieee80211_mgmt_open; - dev->stop = ieee80211_mgmt_stop; - dev->type = ARPHRD_IEEE80211_PRISM; - dev->destructor = ieee80211_if_free; -} - /* regular interfaces */ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) @@ -345,7 +199,6 @@ static int ieee80211_open(struct net_device *dev) return -ENOLINK; break; case IEEE80211_IF_TYPE_AP: - case IEEE80211_IF_TYPE_MGMT: case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_IBSS: @@ -410,10 +263,6 @@ static int ieee80211_open(struct net_device *dev) if (local->open_count == 0) { res = dev_open(local->mdev); WARN_ON(res); - if (local->apdev) { - res = dev_open(local->apdev); - WARN_ON(res); - } tasklet_enable(&local->tx_pending_tasklet); tasklet_enable(&local->tasklet); } @@ -499,9 +348,6 @@ static int ieee80211_stop(struct net_device *dev) if (netif_running(local->mdev)) dev_close(local->mdev); - if (local->apdev) - dev_close(local->apdev); - if (local->ops->stop) local->ops->stop(local_to_hw(local)); @@ -550,7 +396,7 @@ static const struct header_ops ieee80211_header_ops = { .cache_update = eth_header_cache_update, }; -/* Must not be called for mdev and apdev */ +/* Must not be called for mdev */ void ieee80211_if_setup(struct net_device *dev) { ether_setup(dev); @@ -806,8 +652,6 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; if (control->flags & IEEE80211_TXCTL_REQUEUE) pkt_data->flags |= IEEE80211_TXPD_REQUEUE; - if (control->type == IEEE80211_IF_TYPE_MGMT) - pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; pkt_data->queue = control->queue; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -860,7 +704,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_local *local = hw_to_local(hw); u16 frag, type; - u32 msg_type; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; int monitors; @@ -975,29 +818,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, local->dot11FailedCount++; } - msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ? - ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail; - /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); - if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) && - local->apdev) { - if (local->monitors) { - skb2 = skb_clone(skb, GFP_ATOMIC); - } else { - skb2 = skb; - skb = NULL; - } - - if (skb2) - /* Send frame to hostapd */ - ieee80211_rx_mgmt(local, skb2, NULL, msg_type); - - if (!skb) - return; - } - if (!local->monitors) { dev_kfree_skb(skb); return; @@ -1344,8 +1167,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED); local->reg_state = IEEE80211_DEV_UNREGISTERED; - if (local->apdev) - ieee80211_if_del_mgmt(local); /* * At this point, interface list manipulations are fine diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9e3c365e3f03..d24b0574c436 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -141,7 +141,6 @@ struct ieee80211_txrx_data { * when using CTS protection with IEEE 802.11g. */ struct ieee80211_rate *last_frag_rate; int last_frag_hwrate; - int mgmt_interface; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -163,7 +162,6 @@ struct ieee80211_txrx_data { #define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) #define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) #define IEEE80211_TXPD_REQUEUE BIT(2) -#define IEEE80211_TXPD_MGMT_IFACE BIT(3) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { int ifindex; @@ -408,7 +406,6 @@ struct ieee80211_local { struct list_head modes_list; struct net_device *mdev; /* wmaster# - "master" 802.11 device */ - struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ int open_count; int monitors; unsigned int filter_flags; /* FIF_* */ @@ -704,14 +701,11 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); -void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_rx_status *status, u32 msg_type); void ieee80211_prepare_rates(struct ieee80211_local *local, struct ieee80211_hw_mode *mode); void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); -void ieee80211_if_mgmt_setup(struct net_device *dev); struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hwrate); @@ -778,8 +772,6 @@ void __ieee80211_if_del(struct ieee80211_local *local, int ieee80211_if_remove(struct net_device *dev, const char *name, int id); void ieee80211_if_free(struct net_device *dev); void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); -int ieee80211_if_add_mgmt(struct ieee80211_local *local); -void ieee80211_if_del_mgmt(struct ieee80211_local *local); /* regdomain.c */ void ieee80211_regdomain_init(void); @@ -796,7 +788,6 @@ 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); -int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); /* utility functions/constants */ extern void *mac80211_wiphy_privid; /* for wiphy privid */ diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index ef618e947e2b..be7e77f66fee 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -96,66 +96,6 @@ fail: return ret; } -int ieee80211_if_add_mgmt(struct ieee80211_local *local) -{ - struct net_device *ndev; - struct ieee80211_sub_if_data *nsdata; - int ret; - - ASSERT_RTNL(); - - ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d", - ieee80211_if_mgmt_setup); - if (!ndev) - return -ENOMEM; - ret = dev_alloc_name(ndev, ndev->name); - if (ret < 0) - goto fail; - - memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); - SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - - nsdata = IEEE80211_DEV_TO_SUB_IF(ndev); - ndev->ieee80211_ptr = &nsdata->wdev; - nsdata->wdev.wiphy = local->hw.wiphy; - nsdata->type = IEEE80211_IF_TYPE_MGMT; - nsdata->dev = ndev; - nsdata->local = local; - ieee80211_if_sdata_init(nsdata); - - ret = register_netdevice(ndev); - if (ret) - goto fail; - - /* - * Called even when register_netdevice fails, it would - * oops if assigned before initialising the rest. - */ - ndev->uninit = ieee80211_if_reinit; - - ieee80211_debugfs_add_netdev(nsdata); - - if (local->open_count > 0) - dev_open(ndev); - local->apdev = ndev; - return 0; - -fail: - free_netdev(ndev); - return ret; -} - -void ieee80211_if_del_mgmt(struct ieee80211_local *local) -{ - struct net_device *apdev; - - ASSERT_RTNL(); - apdev = local->apdev; - ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev)); - local->apdev = NULL; - unregister_netdevice(apdev); -} - void ieee80211_if_set_type(struct net_device *dev, int type) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -247,9 +187,6 @@ void ieee80211_if_reinit(struct net_device *dev) /* cannot happen */ WARN_ON(1); break; - case IEEE80211_IF_TYPE_MGMT: - /* nothing to do */ - break; case IEEE80211_IF_TYPE_AP: { /* Remove all virtual interfaces that use this BSS * as their sdata->bss */ @@ -357,11 +294,8 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id) void ieee80211_if_free(struct net_device *dev) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - /* local->apdev must be NULL when freeing management interface */ - BUG_ON(dev == local->apdev); ieee80211_if_sdata_deinit(sdata); free_netdev(dev); } diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index 91a9fe2cbad9..93abb8fff141 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c @@ -145,8 +145,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) || - (local->apdev && netif_running(local->apdev))) + if (local->open_count || netif_running(local->mdev)) return -EBUSY; ref = rate_control_alloc(name, local); diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index cac91a960ff4..7cd1ebab4f83 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h @@ -30,8 +30,6 @@ struct rate_control_extra { /* parameters from the caller to rate_control_get_rate(): */ struct ieee80211_hw_mode *mode; - int mgmt_data; /* this is data frame that is used for management - * (e.g., IEEE 802.1X EAPOL) */ u16 ethertype; }; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index cf50a7bfb970..bd9d7aa74083 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -473,8 +473,6 @@ static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = sdata->dev->ifindex; - if (sdata->type == IEEE80211_IF_TYPE_MGMT) - pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; if (!encrypt) pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b4a62fe3ccbd..7cd185e9dde4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -19,7 +19,6 @@ #include "ieee80211_i.h" #include "ieee80211_led.h" -#include "ieee80211_common.h" #include "wep.h" #include "wpa.h" #include "tkip.h" @@ -412,12 +411,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - if (!rx->local->apdev) - return TXRX_DROP; - - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_sta_not_assoc); - return TXRX_QUEUED; + return TXRX_DROP; } return TXRX_CONTINUE; @@ -983,15 +977,8 @@ ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) { if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && rx->sdata->type != IEEE80211_IF_TYPE_STA && - (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { - /* Pass both encrypted and unencrypted EAPOL frames to user - * space for processing. */ - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_normal); - return TXRX_QUEUED; - } + (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + return TXRX_CONTINUE; if (unlikely(rx->sdata->ieee802_1x && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && @@ -1233,15 +1220,11 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if ((sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) && - !rx->local->user_space_mlme) { + !rx->local->user_space_mlme) ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); - } else { - /* Management frames are sent to hostapd for processing */ - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_normal); - } + else + return TXRX_DROP; + return TXRX_QUEUED; } @@ -1454,7 +1437,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, /* take everything */ break; case IEEE80211_IF_TYPE_INVALID: - case IEEE80211_IF_TYPE_MGMT: /* should never get here */ WARN_ON(1); break; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 54e05392410d..8f0007a925a2 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -258,7 +258,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) return TXRX_CONTINUE; } - if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x && + if (unlikely(/* !injected && */ tx->sdata->ieee802_1x && !(sta_flags & WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG DECLARE_MAC_BUF(mac); @@ -570,8 +570,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) memset(&extra, 0, sizeof(extra)); extra.mode = tx->u.tx.mode; - extra.mgmt_data = tx->sdata && - tx->sdata->type == IEEE80211_IF_TYPE_MGMT; extra.ethertype = tx->ethertype; tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb, @@ -1069,7 +1067,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, } static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control, int mgmt) + struct ieee80211_tx_control *control) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; @@ -1099,7 +1097,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); sta = tx.sta; - tx.u.tx.mgmt_interface = mgmt; tx.u.tx.mode = local->hw.conf.mode; if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */ @@ -1250,8 +1247,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, control.flags |= IEEE80211_TXCTL_REQUEUE; control.queue = pkt_data->queue; - ret = ieee80211_tx(odev, skb, &control, - control.type == IEEE80211_IF_TYPE_MGMT); + ret = ieee80211_tx(odev, skb, &control); dev_put(odev); return ret; @@ -1496,8 +1492,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = dev->ifindex; - if (sdata->type == IEEE80211_IF_TYPE_MGMT) - pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; skb->dev = local->mdev; dev->stats.tx_packets++; @@ -1555,8 +1549,6 @@ int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = sdata->dev->ifindex; - if (sdata->type == IEEE80211_IF_TYPE_MGMT) - pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ skb->dev = sdata->local->mdev; diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index fcc8921722f4..5b8a157975a3 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -94,8 +94,6 @@ static inline int wme_downgrade_ac(struct sk_buff *skb) static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) { struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); int qos; @@ -108,12 +106,8 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) return IEEE80211_TX_QUEUE_DATA0; } - if (unlikely(pkt_data->flags & IEEE80211_TXPD_MGMT_IFACE)) { - /* Data frames from hostapd (mainly, EAPOL) use AC_VO - * and they will include QoS control fields if - * the target STA is using WME. */ - skb->priority = 7; - return ieee802_1d_to_ac[skb->priority]; + if (0 /* injected */) { + /* use AC from radiotap */ } /* is this a QoS frame? */ From 70f0876579ceeea9fd7bd4a20fade524a0b3bdda Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 17:53:14 +0200 Subject: [PATCH 1677/2804] [MAC80211]: move sta_process rx handler later This moves the sta_process RX handler to after decryption so that frames that cannot be decrypted don't influence statistics, it is likely that they were injected or something else is totally wrong. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/rx.c | 96 +++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7cd185e9dde4..6973d5c8e9e0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -512,6 +512,53 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; } +static ieee80211_txrx_result +ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) +{ + if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) || + (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || + !rx->key || rx->key->conf.alg != ALG_WEP || + !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + return TXRX_CONTINUE; + + /* Check for weak IVs, if hwaccel did not remove IV from the frame */ + if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || + !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) + if (ieee80211_wep_is_weak_iv(rx->skb, rx->key)) + rx->sta->wep_weak_iv_count++; + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) +{ + if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) + return TXRX_CONTINUE; + + if (!rx->key) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX protected frame," + " but have no key\n", rx->dev->name); + return TXRX_DROP; + } + + switch (rx->key->conf.alg) { + case ALG_WEP: + return ieee80211_crypto_wep_decrypt(rx); + case ALG_TKIP: + return ieee80211_crypto_tkip_decrypt(rx); + case ALG_CCMP: + return ieee80211_crypto_ccmp_decrypt(rx); + case ALG_NONE: + return TXRX_CONTINUE; + } + + /* not reached */ + WARN_ON(1); + return TXRX_DROP; +} + static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; @@ -637,53 +684,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; } /* ieee80211_rx_h_sta_process */ -static ieee80211_txrx_result -ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) -{ - if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - !rx->key || rx->key->conf.alg != ALG_WEP || - !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; - - /* Check for weak IVs, if hwaccel did not remove IV from the frame */ - if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || - !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) - if (ieee80211_wep_is_weak_iv(rx->skb, rx->key)) - rx->sta->wep_weak_iv_count++; - - return TXRX_CONTINUE; -} - -static ieee80211_txrx_result -ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) -{ - if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) - return TXRX_CONTINUE; - - if (!rx->key) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: RX protected frame," - " but have no key\n", rx->dev->name); - return TXRX_DROP; - } - - switch (rx->key->conf.alg) { - case ALG_WEP: - return ieee80211_crypto_wep_decrypt(rx); - case ALG_TKIP: - return ieee80211_crypto_tkip_decrypt(rx); - case ALG_CCMP: - return ieee80211_crypto_ccmp_decrypt(rx); - case ALG_NONE: - return TXRX_CONTINUE; - } - - /* not reached */ - WARN_ON(1); - return TXRX_DROP; -} - static inline struct ieee80211_fragment_entry * ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, unsigned int frag, unsigned int seq, int rx_queue, @@ -1349,9 +1349,9 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = ieee80211_rx_h_passive_scan, ieee80211_rx_h_check, ieee80211_rx_h_load_key, - ieee80211_rx_h_sta_process, ieee80211_rx_h_wep_weak_iv_detection, ieee80211_rx_h_decrypt, + ieee80211_rx_h_sta_process, ieee80211_rx_h_defragment, ieee80211_rx_h_ps_poll, ieee80211_rx_h_michael_mic_verify, From 1990af8d14e48445a0ddcca7765a177b6661d676 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 17:53:15 +0200 Subject: [PATCH 1678/2804] [MAC80211]: consolidate decryption more Currently, we have three RX handlers doing the decryption. This patch changes it to have only one handler doing everything, thereby getting rid of many duplicate checks. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller -- net/mac80211/rx.c | 46 ++++++++++++---------------------------------- 1 files changed, 12 insertions(+), 34 deletions(-) --- net/mac80211/rx.c | 46 ++++++++++++---------------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6973d5c8e9e0..d5ce5d3649f3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -419,7 +419,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) static ieee80211_txrx_result -ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; int keyidx; @@ -456,7 +456,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; /* - * No point in finding a key if the frame is neither + * No point in finding a key and decrypting if the frame is neither * addressed to us nor a multicast frame. */ if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) @@ -507,42 +507,21 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) if (rx->key) { rx->key->tx_rx_count++; /* TODO: add threshold stuff again */ - } - - return TXRX_CONTINUE; -} - -static ieee80211_txrx_result -ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) -{ - if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - !rx->key || rx->key->conf.alg != ALG_WEP || - !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; - - /* Check for weak IVs, if hwaccel did not remove IV from the frame */ - if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || - !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) - if (ieee80211_wep_is_weak_iv(rx->skb, rx->key)) - rx->sta->wep_weak_iv_count++; - - return TXRX_CONTINUE; -} - -static ieee80211_txrx_result -ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) -{ - if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) - return TXRX_CONTINUE; - - if (!rx->key) { + } else { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX protected frame," " but have no key\n", rx->dev->name); return TXRX_DROP; } + /* Check for weak IVs if possible */ + if (rx->sta && rx->key->conf.alg == ALG_WEP && + ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || + !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) && + ieee80211_wep_is_weak_iv(rx->skb, rx->key)) + rx->sta->wep_weak_iv_count++; + switch (rx->key->conf.alg) { case ALG_WEP: return ieee80211_crypto_wep_decrypt(rx); @@ -551,6 +530,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) case ALG_CCMP: return ieee80211_crypto_ccmp_decrypt(rx); case ALG_NONE: + WARN_ON(1); return TXRX_CONTINUE; } @@ -1348,8 +1328,6 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = ieee80211_rx_h_if_stats, ieee80211_rx_h_passive_scan, ieee80211_rx_h_check, - ieee80211_rx_h_load_key, - ieee80211_rx_h_wep_weak_iv_detection, ieee80211_rx_h_decrypt, ieee80211_rx_h_sta_process, ieee80211_rx_h_defragment, From 640845a5632390eaa9357cd818646c8f0ee3d47e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 17:53:16 +0200 Subject: [PATCH 1679/2804] [MAC80211]: use RX_FLAG_DECRYPTED for sw decrypted as well This makes mac80211 set the RX_FLAG_DECRYPTED flag for frames decrypted in software allowing us to handle some things more uniformly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/rx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d5ce5d3649f3..f5caa1a016ee 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -522,6 +522,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; + /* either the frame will be decrypted or dropped */ + rx->u.rx.status->flag |= RX_FLAG_DECRYPTED; + switch (rx->key->conf.alg) { case ALG_WEP: return ieee80211_crypto_wep_decrypt(rx); @@ -993,9 +996,8 @@ ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && - (rx->key || rx->sdata->drop_unencrypted) && - (rx->sdata->eapol == 0 || - !ieee80211_is_eapol(rx->skb)))) { + rx->sdata->drop_unencrypted && + (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " "encryption\n", rx->dev->name); From 628a140ba033ef201706a8c7e767c8a0c0f8326c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 17:53:17 +0200 Subject: [PATCH 1680/2804] [MAC80211]: remove ALG_NONE This "algorithm" is used only internally and is not useful. Signed-off-by: Johannes Berg Cc: Michael Buesch Acked-by: Zhu Yi Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/main.c | 3 --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ---- drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 ---- include/net/mac80211.h | 2 -- net/mac80211/ieee80211_ioctl.c | 19 +++++++++++-------- net/mac80211/key.c | 1 - net/mac80211/rx.c | 3 --- net/mac80211/tx.c | 2 -- 8 files changed, 11 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6c80f2e2f4ee..c141a264ac45 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2827,9 +2827,6 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev) return -ENODEV; switch (key->alg) { - case ALG_NONE: - algorithm = B43_SEC_ALGO_NONE; - break; case ALG_WEP: if (key->keylen == 5) algorithm = B43_SEC_ALGO_WEP40; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2cd7caa69e46..75e3b5c3f155 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2579,10 +2579,6 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, "with key %d\n", ctl->key_idx); break; - case ALG_NONE: - IWL_DEBUG_TX("Tx packet in the clear (encrypt requested).\n"); - break; - default: printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); break; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 5a8342664af1..b1a6e39f7821 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2663,10 +2663,6 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, "with key %d\n", ctl->key_idx); break; - case ALG_NONE: - IWL_DEBUG_TX("Tx packet in the clear (encrypt requested).\n"); - break; - default: printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); break; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c143ac8965db..1a2114b8d221 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -541,13 +541,11 @@ struct ieee80211_if_conf { /** * enum ieee80211_key_alg - key algorithm - * @ALG_NONE: Unset key algorithm, will never be passed to the driver * @ALG_WEP: WEP40 or WEP104 * @ALG_TKIP: TKIP * @ALG_CCMP: CCMP (AES) */ enum ieee80211_key_alg { - ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 48e68434b38a..6c8e73e0d29d 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -27,8 +27,9 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, - int idx, int alg, int set_tx_key, - const u8 *_key, size_t key_len) + int idx, int alg, int remove, + int set_tx_key, const u8 *_key, + size_t key_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int ret = 0; @@ -75,7 +76,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, key = sta->key; } - if (alg == ALG_NONE) { + if (remove) { ieee80211_key_free(key); key = NULL; } else { @@ -827,6 +828,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, struct ieee80211_sub_if_data *sdata; int idx, i, alg = ALG_WEP; u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + int remove = 0; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -845,7 +847,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, idx--; if (erq->flags & IW_ENCODE_DISABLED) - alg = ALG_NONE; + remove = 1; else if (erq->length == 0) { /* No key data - just set the default TX key index */ ieee80211_set_default_key(sdata, idx); @@ -854,7 +856,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, return ieee80211_set_encryption( dev, bcaddr, - idx, alg, + idx, alg, remove, !sdata->default_key, keybuf, erq->length); } @@ -1005,11 +1007,11 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int alg, idx, i; + int uninitialized_var(alg), idx, i, remove = 0; switch (ext->alg) { case IW_ENCODE_ALG_NONE: - alg = ALG_NONE; + remove = 1; break; case IW_ENCODE_ALG_WEP: alg = ALG_WEP; @@ -1025,7 +1027,7 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, } if (erq->flags & IW_ENCODE_DISABLED) - alg = ALG_NONE; + remove = 1; idx = erq->flags & IW_ENCODE_INDEX; if (idx < 1 || idx > 4) { @@ -1044,6 +1046,7 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, idx--; return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg, + remove, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, ext->key, ext->key_len); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f13d46b2c13c..0b2328f7d67c 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -121,7 +121,6 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, struct ieee80211_key *key; BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS); - BUG_ON(alg == ALG_NONE); key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); if (!key) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f5caa1a016ee..8c16574ec39c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -532,9 +532,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) return ieee80211_crypto_tkip_decrypt(rx); case ALG_CCMP: return ieee80211_crypto_ccmp_decrypt(rx); - case ALG_NONE: - WARN_ON(1); - return TXRX_CONTINUE; } /* not reached */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8f0007a925a2..47416b0645db 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -554,8 +554,6 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) return ieee80211_crypto_tkip_encrypt(tx); case ALG_CCMP: return ieee80211_crypto_ccmp_encrypt(tx); - case ALG_NONE: - return TXRX_CONTINUE; } /* not reached */ From 58d4185e36913d4fc94afa4b4daccb3c9aa01957 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 17:53:18 +0200 Subject: [PATCH 1681/2804] [MAC80211]: improve radiotap injection This improves radiotap injection by removing the shortcut over TX handlers that led to BUGS when injecting frames without setting a rate and also resulted in various other quirks. Now, TX handlers are run but some information that was present in the radiotap header is used instead of automatic settings. Signed-off-by: Johannes Berg Cc: Andy Green Signed-off-by: John W. Linville --- .../networking/mac80211-injection.txt | 32 ++- net/mac80211/ieee80211_i.h | 1 + net/mac80211/tx.c | 193 ++++++++++-------- 3 files changed, 130 insertions(+), 96 deletions(-) diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt index 53ef7a06f49c..84906ef3ed6e 100644 --- a/Documentation/networking/mac80211-injection.txt +++ b/Documentation/networking/mac80211-injection.txt @@ -13,15 +13,35 @@ The radiotap format is discussed in ./Documentation/networking/radiotap-headers.txt. Despite 13 radiotap argument types are currently defined, most only make sense -to appear on received packets. Currently three kinds of argument are used by -the injection code, although it knows to skip any other arguments that are -present (facilitating replay of captured radiotap headers directly): +to appear on received packets. The following information is parsed from the +radiotap headers and used to control injection: - - IEEE80211_RADIOTAP_RATE - u8 arg in 500kbps units (0x02 --> 1Mbps) + * IEEE80211_RADIOTAP_RATE - - IEEE80211_RADIOTAP_ANTENNA - u8 arg, 0x00 = ant1, 0x01 = ant2 + rate in 500kbps units, automatic if invalid or not present - - IEEE80211_RADIOTAP_DBM_TX_POWER - u8 arg, dBm + + * IEEE80211_RADIOTAP_ANTENNA + + antenna to use, automatic if not present + + + * IEEE80211_RADIOTAP_DBM_TX_POWER + + transmit power in dBm, automatic if not present + + + * IEEE80211_RADIOTAP_FLAGS + + IEEE80211_RADIOTAP_F_FCS: FCS will be removed and recalculated + IEEE80211_RADIOTAP_F_WEP: frame will be encrypted if key available + IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the + current fragmentation threshold. Note that + this flag is only reliable when software + fragmentation is enabled) + +The injection code can also skip all other currently defined radiotap fields +facilitating replay of captured radiotap headers directly. Here is an example valid radiotap header defining these three parameters diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d24b0574c436..0fe077747082 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -122,6 +122,7 @@ typedef enum { #define IEEE80211_TXRXD_RXIN_SCAN BIT(4) /* frame is destined to interface currently processed (incl. multicast frames) */ #define IEEE80211_TXRXD_RXRA_MATCH BIT(5) +#define IEEE80211_TXRXD_TX_INJECTED BIT(6) struct ieee80211_txrx_data { struct sk_buff *skb; struct net_device *dev; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 47416b0645db..1a531543bccb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -222,6 +222,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ u32 sta_flags; + if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) + return TXRX_CONTINUE; + if (unlikely(tx->local->sta_scanning != 0) && ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) @@ -566,22 +569,27 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) { struct rate_control_extra extra; - memset(&extra, 0, sizeof(extra)); - extra.mode = tx->u.tx.mode; - extra.ethertype = tx->ethertype; + if (likely(!tx->u.tx.rate)) { + memset(&extra, 0, sizeof(extra)); + extra.mode = tx->u.tx.mode; + extra.ethertype = tx->ethertype; - tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb, - &extra); - if (unlikely(extra.probe != NULL)) { - tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; - tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; - tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; - tx->u.tx.rate = extra.probe; - } else { + tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, + tx->skb, &extra); + if (unlikely(extra.probe != NULL)) { + tx->u.tx.control->flags |= + IEEE80211_TXCTL_RATE_CTRL_PROBE; + tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; + tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; + tx->u.tx.rate = extra.probe; + } else + tx->u.tx.control->alt_retry_rate = -1; + + if (!tx->u.tx.rate) + return TXRX_DROP; + } else tx->u.tx.control->alt_retry_rate = -1; - } - if (!tx->u.tx.rate) - return TXRX_DROP; + if (tx->u.tx.mode->mode == MODE_IEEE80211G && (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) { @@ -611,19 +619,24 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) struct ieee80211_tx_control *control = tx->u.tx.control; struct ieee80211_hw_mode *mode = tx->u.tx.mode; - if (!is_multicast_ether_addr(hdr->addr1)) { - if (tx->skb->len + FCS_LEN > tx->local->rts_threshold && - tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) { - control->flags |= IEEE80211_TXCTL_USE_RTS_CTS; - control->flags |= IEEE80211_TXCTL_LONG_RETRY_LIMIT; - control->retry_limit = - tx->local->long_retry_limit; + if (!control->retry_limit) { + if (!is_multicast_ether_addr(hdr->addr1)) { + if (tx->skb->len + FCS_LEN > tx->local->rts_threshold + && tx->local->rts_threshold < + IEEE80211_MAX_RTS_THRESHOLD) { + control->flags |= + IEEE80211_TXCTL_USE_RTS_CTS; + control->flags |= + IEEE80211_TXCTL_LONG_RETRY_LIMIT; + control->retry_limit = + tx->local->long_retry_limit; + } else { + control->retry_limit = + tx->local->short_retry_limit; + } } else { - control->retry_limit = - tx->local->short_retry_limit; + control->retry_limit = 1; } - } else { - control->retry_limit = 1; } if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { @@ -785,9 +798,8 @@ ieee80211_tx_handler ieee80211_tx_handlers[] = * with Radiotap Header -- only called for monitor mode interface */ static ieee80211_txrx_result -__ieee80211_parse_tx_radiotap( - struct ieee80211_txrx_data *tx, - struct sk_buff *skb, struct ieee80211_tx_control *control) +__ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, + struct sk_buff *skb) { /* * this is the moment to interpret and discard the radiotap header that @@ -802,18 +814,11 @@ __ieee80211_parse_tx_radiotap( (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); + struct ieee80211_tx_control *control = tx->u.tx.control; - /* - * default control situation for all injected packets - * FIXME: this does not suit all usage cases, expand to allow control - */ - - control->retry_limit = 1; /* no retry */ - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT); - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT | - IEEE80211_TXCTL_NO_ACK; - control->antenna_sel_tx = 0; /* default to default antenna */ + control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + tx->flags |= IEEE80211_TXRXD_TX_INJECTED; + tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; /* * for every radiotap entry that is present @@ -846,19 +851,10 @@ __ieee80211_parse_tx_radiotap( for (i = 0; i < mode->num_rates; i++) { struct ieee80211_rate *r = &mode->rates[i]; - if (r->rate > target_rate) - continue; - - control->rate = r; - - if (r->flags & IEEE80211_RATE_PREAMBLE2) - control->tx_rate = r->val2; - else - control->tx_rate = r->val; - - /* end on exact match */ - if (r->rate == target_rate) - i = mode->num_rates; + if (r->rate == target_rate) { + tx->u.tx.rate = r; + break; + } } break; @@ -888,8 +884,19 @@ __ieee80211_parse_tx_radiotap( skb_trim(skb, skb->len - FCS_LEN); } + if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) + control->flags &= + ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; + if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) + tx->flags |= IEEE80211_TXRXD_FRAGMENTED; break; + /* + * Please update the file + * Documentation/networking/mac80211-injection.txt + * when parsing new fields here. + */ + default: break; } @@ -908,14 +915,17 @@ __ieee80211_parse_tx_radiotap( return TXRX_CONTINUE; } -static ieee80211_txrx_result inline +/* + * initialises @tx + */ +static ieee80211_txrx_result __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct sk_buff *skb, struct net_device *dev, struct ieee80211_tx_control *control) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr; struct ieee80211_sub_if_data *sdata; ieee80211_txrx_result res = TXRX_CONTINUE; @@ -926,33 +936,31 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, tx->dev = dev; /* use original interface */ tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); - + tx->u.tx.control = control; /* - * set defaults for things that can be set by - * injected radiotap headers + * Set this flag (used below to indicate "automatic fragmentation"), + * it will be cleared/left by radiotap as desired. */ - control->power_level = local->hw.conf.power_level; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + tx->flags |= IEEE80211_TXRXD_FRAGMENTED; /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { - if (__ieee80211_parse_tx_radiotap(tx, skb, control) == - TXRX_DROP) { + if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP) return TXRX_DROP; - } + /* - * we removed the radiotap header after this point, - * we filled control with what we could use - * set to the actual ieee header now + * __ieee80211_parse_tx_radiotap has now removed + * the radiotap header that was present and pre-filled + * 'tx' with tx control information. */ - hdr = (struct ieee80211_hdr *) skb->data; - res = TXRX_QUEUED; /* indication it was monitor packet */ } + hdr = (struct ieee80211_hdr *) skb->data; + tx->sta = sta_info_get(local, hdr->addr1); tx->fc = le16_to_cpu(hdr->frame_control); - tx->u.tx.control = control; + if (is_multicast_ether_addr(hdr->addr1)) { tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; control->flags |= IEEE80211_TXCTL_NO_ACK; @@ -960,19 +968,23 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, tx->flags |= IEEE80211_TXRXD_TXUNICAST; control->flags &= ~IEEE80211_TXCTL_NO_ACK; } - if (local->fragmentation_threshold < IEEE80211_MAX_FRAG_THRESHOLD && - (tx->flags & IEEE80211_TXRXD_TXUNICAST) && - skb->len + FCS_LEN > local->fragmentation_threshold && - !local->ops->set_frag_threshold) - tx->flags |= IEEE80211_TXRXD_FRAGMENTED; - else - tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; + + if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { + if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) && + skb->len + FCS_LEN > local->fragmentation_threshold && + !local->ops->set_frag_threshold) + tx->flags |= IEEE80211_TXRXD_FRAGMENTED; + else + tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; + } + if (!tx->sta) control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; else if (tx->sta->clear_dst_mask) { control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; tx->sta->clear_dst_mask = 0; } + hdrlen = ieee80211_get_hdrlen(tx->fc); if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; @@ -984,11 +996,14 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } /* Device in tx->dev has a reference added; use dev_put(tx->dev) when - * finished with it. */ -static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, - struct sk_buff *skb, - struct net_device *mdev, - struct ieee80211_tx_control *control) + * finished with it. + * + * NB: @tx is uninitialised when passed in here + */ +static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, + struct sk_buff *skb, + struct net_device *mdev, + struct ieee80211_tx_control *control) { struct ieee80211_tx_packet_data *pkt_data; struct net_device *dev; @@ -1001,6 +1016,7 @@ static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } if (unlikely(!dev)) return -ENODEV; + /* initialises tx with control */ __ieee80211_tx_prepare(tx, skb, dev, control); return 0; } @@ -1081,6 +1097,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, return 0; } + /* initialises tx */ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); if (res_prepare == TXRX_DROP) { @@ -1097,15 +1114,11 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, sta = tx.sta; tx.u.tx.mode = local->hw.conf.mode; - if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */ - res = TXRX_CONTINUE; - } else { - for (handler = local->tx_handlers; *handler != NULL; - handler++) { - res = (*handler)(&tx); - if (res != TXRX_CONTINUE) - break; - } + for (handler = local->tx_handlers; *handler != NULL; + handler++) { + res = (*handler)(&tx); + if (res != TXRX_CONTINUE) + break; } skb = tx.skb; /* handlers are allowed to change skb */ @@ -1857,7 +1870,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, cpu_to_le16(IEEE80211_FCTL_MOREDATA); } - if (ieee80211_tx_prepare(&tx, skb, local->mdev, control) == 0) + if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control)) break; dev_kfree_skb_any(skb); } From ddd3d2be85e3207c47f2b3c431723e6c758b4b0d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 17:53:20 +0200 Subject: [PATCH 1682/2804] [MAC80211]: make userspace-mlme a per-interface setting Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/ieee80211.c | 2 +- net/mac80211/ieee80211_i.h | 3 +-- net/mac80211/ieee80211_ioctl.c | 14 ++++++-------- net/mac80211/rx.c | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 804da5e89bbf..f484ca7ade9c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -254,7 +254,7 @@ static int ieee80211_open(struct net_device *dev) ieee80211_enable_keys(sdata); if (sdata->type == IEEE80211_IF_TYPE_STA && - !local->user_space_mlme) + !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) netif_carrier_off(dev); else netif_carrier_on(dev); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0fe077747082..db80e1be1dcb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -287,6 +287,7 @@ struct ieee80211_if_sta { * generator reports that there are no present stations that cannot support short * preambles */ #define IEEE80211_SDATA_SHORT_PREAMBLE BIT(3) +#define IEEE80211_SDATA_USERSPACE_MLME BIT(4) struct ieee80211_sub_if_data { struct list_head list; enum ieee80211_if_types type; @@ -553,8 +554,6 @@ struct ieee80211_local { unsigned int hw_modes; /* bitfield of supported hardware modes; * (1 << MODE_*) */ - int user_space_mlme; - #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { struct dentry *channel; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 6c8e73e0d29d..f0224c2311d2 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -105,12 +105,12 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, struct iw_point *data, char *extra) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (local->user_space_mlme) - return -EOPNOTSUPP; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) + return -EOPNOTSUPP; + if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length); @@ -374,7 +374,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; size_t len = data->length; @@ -386,7 +385,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { int ret; - if (local->user_space_mlme) { + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; memcpy(sdata->u.sta.ssid, ssid, len); @@ -451,14 +450,13 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { int ret; - if (local->user_space_mlme) { + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, ETH_ALEN); return 0; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8c16574ec39c..4c046af237e3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1199,7 +1199,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if ((sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) && - !rx->local->user_space_mlme) + !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); else return TXRX_DROP; From 47f0c502209056da728e6a306a43d5e19a37f4fa Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 27 Sep 2007 15:10:44 +0200 Subject: [PATCH 1683/2804] [MAC80211]: Add association LED trigger Many devices have LEDs to indicate the link status. Export this functionality to drivers. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 11 ++++++ net/mac80211/ieee80211_i.h | 4 +-- net/mac80211/ieee80211_led.c | 67 +++++++++++++++++++++++++++--------- net/mac80211/ieee80211_led.h | 6 ++++ net/mac80211/ieee80211_sta.c | 5 ++- 5 files changed, 74 insertions(+), 19 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1a2114b8d221..eac670a22ef4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1069,6 +1069,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw); #ifdef CONFIG_MAC80211_LEDS extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); #endif /** * ieee80211_get_tx_led_name - get name of TX LED @@ -1108,6 +1109,16 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) #endif } +static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_assoc_led_name(hw); +#else + return NULL; +#endif +} + + /* Register a new hardware PHYMODE capability to the stack. */ int ieee80211_register_hwmode(struct ieee80211_hw *hw, struct ieee80211_hw_mode *mode); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index db80e1be1dcb..d34a9deca67a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -503,8 +503,8 @@ struct ieee80211_local { #ifdef CONFIG_MAC80211_LEDS int tx_led_counter, rx_led_counter; - struct led_trigger *tx_led, *rx_led; - char tx_led_name[32], rx_led_name[32]; + struct led_trigger *tx_led, *rx_led, *assoc_led; + char tx_led_name[32], rx_led_name[32], assoc_led_name[32]; #endif u32 channel_use; diff --git a/net/mac80211/ieee80211_led.c b/net/mac80211/ieee80211_led.c index 719d75b20707..4cf89af9d100 100644 --- a/net/mac80211/ieee80211_led.c +++ b/net/mac80211/ieee80211_led.c @@ -33,33 +33,58 @@ void ieee80211_led_tx(struct ieee80211_local *local, int q) led_trigger_event(local->tx_led, LED_FULL); } +void ieee80211_led_assoc(struct ieee80211_local *local, bool associated) +{ + if (unlikely(!local->assoc_led)) + return; + if (associated) + led_trigger_event(local->assoc_led, LED_FULL); + else + led_trigger_event(local->assoc_led, LED_OFF); +} + void ieee80211_led_init(struct ieee80211_local *local) { local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); - if (!local->rx_led) - return; - snprintf(local->rx_led_name, sizeof(local->rx_led_name), - "%srx", wiphy_name(local->hw.wiphy)); - local->rx_led->name = local->rx_led_name; - if (led_trigger_register(local->rx_led)) { - kfree(local->rx_led); - local->rx_led = NULL; + if (local->rx_led) { + snprintf(local->rx_led_name, sizeof(local->rx_led_name), + "%srx", wiphy_name(local->hw.wiphy)); + local->rx_led->name = local->rx_led_name; + if (led_trigger_register(local->rx_led)) { + kfree(local->rx_led); + local->rx_led = NULL; + } } local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); - if (!local->tx_led) - return; - snprintf(local->tx_led_name, sizeof(local->tx_led_name), - "%stx", wiphy_name(local->hw.wiphy)); - local->tx_led->name = local->tx_led_name; - if (led_trigger_register(local->tx_led)) { - kfree(local->tx_led); - local->tx_led = NULL; + if (local->tx_led) { + snprintf(local->tx_led_name, sizeof(local->tx_led_name), + "%stx", wiphy_name(local->hw.wiphy)); + local->tx_led->name = local->tx_led_name; + if (led_trigger_register(local->tx_led)) { + kfree(local->tx_led); + local->tx_led = NULL; + } + } + + local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->assoc_led) { + snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), + "%sassoc", wiphy_name(local->hw.wiphy)); + local->assoc_led->name = local->assoc_led_name; + if (led_trigger_register(local->assoc_led)) { + kfree(local->assoc_led); + local->assoc_led = NULL; + } } } void ieee80211_led_exit(struct ieee80211_local *local) { + if (local->assoc_led) { + led_trigger_unregister(local->assoc_led); + kfree(local->assoc_led); + } if (local->tx_led) { led_trigger_unregister(local->tx_led); kfree(local->tx_led); @@ -70,6 +95,16 @@ void ieee80211_led_exit(struct ieee80211_local *local) } } +char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (local->assoc_led) + return local->assoc_led_name; + return NULL; +} +EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); + char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/mac80211/ieee80211_led.h b/net/mac80211/ieee80211_led.h index 5c8ab8263878..0feb22619835 100644 --- a/net/mac80211/ieee80211_led.h +++ b/net/mac80211/ieee80211_led.h @@ -14,6 +14,8 @@ #ifdef CONFIG_MAC80211_LEDS extern void ieee80211_led_rx(struct ieee80211_local *local); extern void ieee80211_led_tx(struct ieee80211_local *local, int q); +extern void ieee80211_led_assoc(struct ieee80211_local *local, + bool associated); extern void ieee80211_led_init(struct ieee80211_local *local); extern void ieee80211_led_exit(struct ieee80211_local *local); #else @@ -23,6 +25,10 @@ static inline void ieee80211_led_rx(struct ieee80211_local *local) static inline void ieee80211_led_tx(struct ieee80211_local *local, int q) { } +static inline void ieee80211_led_assoc(struct ieee80211_local *local, + bool associated) +{ +} static inline void ieee80211_led_init(struct ieee80211_local *local) { } diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index bd9d7aa74083..1641e8fe44b7 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -31,6 +31,7 @@ #include #include "ieee80211_i.h" #include "ieee80211_rate.h" +#include "ieee80211_led.h" #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_MAX_TRIES 3 @@ -408,8 +409,9 @@ static void ieee80211_sta_send_associnfo(struct net_device *dev, static void ieee80211_set_associated(struct net_device *dev, struct ieee80211_if_sta *ifsta, - unsigned int assoc) + bool assoc) { + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); union iwreq_data wrqu; if (!!(ifsta->flags & IEEE80211_STA_ASSOCIATED) == assoc) @@ -447,6 +449,7 @@ static void ieee80211_set_associated(struct net_device *dev, wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); ifsta->last_probe = jiffies; + ieee80211_led_assoc(local, assoc); } static void ieee80211_set_disassoc(struct net_device *dev, From 42613db7605a68a70f97513137392bda9b27bb9e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Sep 2007 21:52:27 +0200 Subject: [PATCH 1684/2804] [MAC80211]: implement cfg80211's change_interface hook This implements the cfg80211 change_interface hook that changes the type of an interface and cleans up the code a bit. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/cfg.c | 75 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6981ba178e19..9e2bc1fd0237 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -13,31 +13,35 @@ #include "ieee80211_i.h" #include "cfg.h" +static enum ieee80211_if_types +nl80211_type_to_mac80211_type(enum nl80211_iftype type) +{ + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + return IEEE80211_IF_TYPE_STA; + case NL80211_IFTYPE_ADHOC: + return IEEE80211_IF_TYPE_IBSS; + case NL80211_IFTYPE_STATION: + return IEEE80211_IF_TYPE_STA; + case NL80211_IFTYPE_MONITOR: + return IEEE80211_IF_TYPE_MNTR; + default: + return IEEE80211_IF_TYPE_INVALID; + } +} + static int ieee80211_add_iface(struct wiphy *wiphy, char *name, enum nl80211_iftype type) { struct ieee80211_local *local = wiphy_priv(wiphy); - int itype; + enum ieee80211_if_types itype; if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) return -ENODEV; - switch (type) { - case NL80211_IFTYPE_UNSPECIFIED: - itype = IEEE80211_IF_TYPE_STA; - break; - case NL80211_IFTYPE_ADHOC: - itype = IEEE80211_IF_TYPE_IBSS; - break; - case NL80211_IFTYPE_STATION: - itype = IEEE80211_IF_TYPE_STA; - break; - case NL80211_IFTYPE_MONITOR: - itype = IEEE80211_IF_TYPE_MNTR; - break; - default: + itype = nl80211_type_to_mac80211_type(type); + if (itype == IEEE80211_IF_TYPE_INVALID) return -EINVAL; - } return ieee80211_if_add(local->mdev, name, NULL, itype); } @@ -51,17 +55,52 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) return -ENODEV; - dev = dev_get_by_index(&init_net, ifindex); + /* we're under RTNL */ + dev = __dev_get_by_index(&init_net, ifindex); if (!dev) return 0; name = dev->name; - dev_put(dev); return ieee80211_if_remove(local->mdev, name, -1); } +static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct net_device *dev; + enum ieee80211_if_types itype; + struct ieee80211_sub_if_data *sdata; + + if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) + return -ENODEV; + + /* we're under RTNL */ + dev = __dev_get_by_index(&init_net, ifindex); + if (!dev) + return -ENODEV; + + if (netif_running(dev)) + return -EBUSY; + + itype = nl80211_type_to_mac80211_type(type); + if (itype == IEEE80211_IF_TYPE_INVALID) + return -EINVAL; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->type == IEEE80211_IF_TYPE_VLAN) + return -EOPNOTSUPP; + + ieee80211_if_reinit(dev); + ieee80211_if_set_type(dev, itype); + + return 0; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, + .change_virtual_intf = ieee80211_change_iface, }; From 478f8d2ba56b40ad1c17e21c1503669b83c96e8e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 30 Sep 2007 13:52:37 +0200 Subject: [PATCH 1685/2804] [MAC80211]: add sta_notify callback This patch adds sta_notify callback and removes sta_table_notification which was not used by any driver. sta_notify() is essential for drivers that keeps notion of station internally and need to be notified about removal or addition of a station to the (I)BSS or assocation to an AP. This version adds interface id to the parameter list as suggested by Johannes Berg Signed-off-by: Tomas Winkler Acked-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 20 ++++++++++++++++---- net/mac80211/sta_info.c | 13 +++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index eac670a22ef4..9bc03f053af0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -613,6 +613,18 @@ enum set_key_cmd { SET_KEY, DISABLE_KEY, }; +/** + * enum sta_notify_cmd - sta notify command + * + * Used with the sta_notify() callback in &struct ieee80211_ops, this + * indicates addition and removal of a station to station table + * + * @STA_NOTIFY_ADD: a station was added to the station table + * @STA_NOTIFY_REMOVE: a station being removed from the station table + */ +enum sta_notify_cmd { + STA_NOTIFY_ADD, STA_NOTIFY_REMOVE +}; /** * enum ieee80211_hw_flags - hardware flags @@ -957,8 +969,8 @@ enum ieee80211_erp_change_flags { * * @set_retry_limit: Configuration of retry limits (if device needs it) * - * @sta_table_notification: Number of STAs in STA table notification. Must - * be atomic. + * @sta_notify: Notifies low level driver about addition or removal + * of assocaited station or AP. * * @erp_ie_changed: Handle ERP IE change notifications. Must be atomic. * @@ -1025,8 +1037,8 @@ struct ieee80211_ops { int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); int (*set_retry_limit)(struct ieee80211_hw *hw, u32 short_retry, u32 long_retr); - void (*sta_table_notification)(struct ieee80211_hw *hw, - int num_sta); + void (*sta_notify)(struct ieee80211_hw *hw, int if_id, + enum sta_notify_cmd, const u8 *addr); void (*erp_ie_changed)(struct ieee80211_hw *hw, u8 changes, int cts_protection, int preamble); int (*conf_tx)(struct ieee80211_hw *hw, int queue, diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7c7df87f673c..e8491554a5dc 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -159,9 +159,9 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, list_add(&sta->list, &local->sta_list); local->num_sta++; sta_info_hash_add(local, sta); - if (local->ops->sta_table_notification) - local->ops->sta_table_notification(local_to_hw(local), - local->num_sta); + if (local->ops->sta_notify) + local->ops->sta_notify(local_to_hw(local), dev->ifindex, + STA_NOTIFY_ADD, addr); write_unlock_bh(&local->sta_lock); #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -199,9 +199,6 @@ void sta_info_remove(struct sta_info *sta) local->num_sta--; sta_info_remove_aid_ptr(sta); - if (local->ops->sta_table_notification) - local->ops->sta_table_notification(local_to_hw(local), - local->num_sta); } void sta_info_free(struct sta_info *sta) @@ -232,6 +229,10 @@ void sta_info_free(struct sta_info *sta) ieee80211_key_free(sta->key); sta->key = NULL; + if (local->ops->sta_notify) + local->ops->sta_notify(local_to_hw(local), sta->dev->ifindex, + STA_NOTIFY_REMOVE, sta->addr); + rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); From 5ecc2a5d3e3c39535d2cc10dad15853e9e9b072d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 2 Oct 2007 12:17:56 +0200 Subject: [PATCH 1686/2804] [MAC80211]: Update beacon_update callback documentation Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/mac80211.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9bc03f053af0..5fcc4c104340 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -996,7 +996,14 @@ enum ieee80211_erp_change_flags { * * @beacon_update: Setup beacon data for IBSS beacons. Unlike access point, * IBSS uses a fixed beacon frame which is configured using this - * function. This handler is required only for IBSS mode. + * function. + * If the driver returns success (0) from this callback, it owns + * the skb. That means the driver is responsible to kfree_skb() it. + * The control structure is not dynamically allocated. That means the + * driver does not own the pointer and if it needs it somewhere + * outside of the context of this function, it must copy it + * somewhere else. + * This handler is required only for IBSS mode. * * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. * This is needed only for IBSS mode and the result of this function is From 69c29d89185dc1de7224f5f98588ddc061f1fad2 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:24:51 -0500 Subject: [PATCH 1687/2804] pasemi_mac: basic error checking pasemi_mac: basic error checking Add some rudimentary error checking to pasemi_mac. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 46 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c2d34a804d40..b297a67d2fbe 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -445,6 +445,38 @@ static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) } +static inline void pasemi_mac_rx_error(struct pasemi_mac *mac, u64 macrx) +{ + unsigned int rcmdsta, ccmdsta; + + if (!netif_msg_rx_err(mac)) + return; + + rcmdsta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + ccmdsta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + + printk(KERN_ERR "pasemi_mac: rx error. macrx %016lx, rx status %lx\n", + macrx, *mac->rx_status); + + printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n", + rcmdsta, ccmdsta); +} + +static inline void pasemi_mac_tx_error(struct pasemi_mac *mac, u64 mactx) +{ + unsigned int cmdsta; + + if (!netif_msg_tx_err(mac)) + return; + + cmdsta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); + + printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016lx, "\ + "tx status 0x%016lx\n", mactx, *mac->tx_status); + + printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta); +} + static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) { unsigned int n; @@ -468,10 +500,13 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) prefetchw(dp); macrx = dp->macrx; + if ((macrx & XCT_MACRX_E) || + (*mac->rx_status & PAS_STATUS_ERROR)) + pasemi_mac_rx_error(mac, macrx); + if (!(macrx & XCT_MACRX_O)) break; - info = NULL; /* We have to scan for our skb since there's no way @@ -563,6 +598,10 @@ restart: for (i = start; i < limit; i++) { dp = &TX_DESC(mac, i); + if ((dp->mactx & XCT_MACTX_E) || + (*mac->tx_status & PAS_STATUS_ERROR)) + pasemi_mac_tx_error(mac, dp->mactx); + if (unlikely(dp->mactx & XCT_MACTX_O)) /* Not yet transmitted */ break; @@ -607,9 +646,6 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) if (!(*mac->rx_status & PAS_STATUS_CAUSE_M)) return IRQ_NONE; - if (*mac->rx_status & PAS_STATUS_ERROR) - printk("rx_status reported error\n"); - /* Don't reset packet count so it won't fire again but clear * all others. */ @@ -1230,7 +1266,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n", err); goto out; - } else + } else if netif_msg_probe(mac) printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, " "hw addr %s\n", dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI", From 18eec695427ce1258fb5dad0ac180fa4d6f64af7 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:25:14 -0500 Subject: [PATCH 1688/2804] pasemi_mac: fix bug in receive buffer dma mapping pasemi_mac: fix bug in receive buffer dma mapping skb->len isn't actually set to the size of the allocated skb, so don't try to use it when figuring out how much to map. (This hasn't surfaced as a real bug because we effectively disable translation for the interface, but it still needs fixing for the future) Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index b297a67d2fbe..b2861e0df86c 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -396,7 +396,7 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) if (unlikely(!skb)) break; - dma = pci_map_single(mac->dma_pdev, skb->data, skb->len, + dma = pci_map_single(mac->dma_pdev, skb->data, BUF_SIZE, PCI_DMA_FROMDEVICE); if (unlikely(dma_mapping_error(dma))) { From fc9e4d2a93dab4a995e2e75725577b9a60154cbc Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:25:53 -0500 Subject: [PATCH 1689/2804] pasemi_mac: rework ring management pasemi_mac: rework ring management Rework ring management, switching to an opaque ring format instead of the struct-based descriptor+pointer setup, since it will be needed for SG support. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 211 +++++++++++++++++++-------------------- drivers/net/pasemi_mac.h | 23 +---- 2 files changed, 107 insertions(+), 127 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index b2861e0df86c..c2a3524a5411 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -63,10 +63,10 @@ NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR) -#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)]) -#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)]) -#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)]) -#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)]) +#define TX_RING(mac, num) ((mac)->tx->ring[(num) & (TX_RING_SIZE-1)]) +#define TX_RING_INFO(mac, num) ((mac)->tx->ring_info[(num) & (TX_RING_SIZE-1)]) +#define RX_RING(mac, num) ((mac)->rx->ring[(num) & (RX_RING_SIZE-1)]) +#define RX_RING_INFO(mac, num) ((mac)->rx->ring_info[(num) & (RX_RING_SIZE-1)]) #define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)]) #define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ @@ -174,22 +174,21 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) spin_lock_init(&ring->lock); ring->size = RX_RING_SIZE; - ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * + ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) * RX_RING_SIZE, GFP_KERNEL); - if (!ring->desc_info) - goto out_desc_info; + if (!ring->ring_info) + goto out_ring_info; /* Allocate descriptors */ - ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * - sizeof(struct pas_dma_xct_descr), + ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(u64), &ring->dma, GFP_KERNEL); - if (!ring->desc) - goto out_desc; + if (!ring->ring) + goto out_ring_desc; - memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); + memset(ring->ring, 0, RX_RING_SIZE * sizeof(u64)); ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), @@ -203,7 +202,7 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id), PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | - PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); + PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3)); write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), PAS_DMA_RXCHAN_CFG_HBU(2)); @@ -229,11 +228,11 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) out_buffers: dma_free_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(struct pas_dma_xct_descr), - mac->rx->desc, mac->rx->dma); -out_desc: - kfree(ring->desc_info); -out_desc_info: + RX_RING_SIZE * sizeof(u64), + mac->rx->ring, mac->rx->dma); +out_ring_desc: + kfree(ring->ring_info); +out_ring_info: kfree(ring); out_ring: return -ENOMEM; @@ -254,25 +253,24 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) spin_lock_init(&ring->lock); ring->size = TX_RING_SIZE; - ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * + ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) * TX_RING_SIZE, GFP_KERNEL); - if (!ring->desc_info) - goto out_desc_info; + if (!ring->ring_info) + goto out_ring_info; /* Allocate descriptors */ - ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev, - TX_RING_SIZE * - sizeof(struct pas_dma_xct_descr), + ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev, + TX_RING_SIZE * sizeof(u64), &ring->dma, GFP_KERNEL); - if (!ring->desc) - goto out_desc; + if (!ring->ring) + goto out_ring_desc; - memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); + memset(ring->ring, 0, TX_RING_SIZE * sizeof(u64)); write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id), PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); - val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); + val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3); write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val); @@ -291,9 +289,9 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) return 0; -out_desc: - kfree(ring->desc_info); -out_desc_info: +out_ring_desc: + kfree(ring->ring_info); +out_ring_info: kfree(ring); out_ring: return -ENOMEM; @@ -304,31 +302,27 @@ static void pasemi_mac_free_tx_resources(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); unsigned int i; struct pasemi_mac_buffer *info; - struct pas_dma_xct_descr *dp; - for (i = 0; i < TX_RING_SIZE; i++) { - info = &TX_DESC_INFO(mac, i); - dp = &TX_DESC(mac, i); - if (info->dma) { - if (info->skb) { - pci_unmap_single(mac->dma_pdev, - info->dma, - info->skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(info->skb); - } - info->dma = 0; - info->skb = NULL; - dp->mactx = 0; - dp->ptr = 0; + for (i = 0; i < TX_RING_SIZE; i += 2) { + info = &TX_RING_INFO(mac, i+1); + if (info->dma && info->skb) { + pci_unmap_single(mac->dma_pdev, + info->dma, + info->skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_any(info->skb); } + TX_RING(mac, i) = 0; + TX_RING(mac, i+1) = 0; + info->dma = 0; + info->skb = NULL; } dma_free_coherent(&mac->dma_pdev->dev, - TX_RING_SIZE * sizeof(struct pas_dma_xct_descr), - mac->tx->desc, mac->tx->dma); + TX_RING_SIZE * sizeof(u64), + mac->tx->ring, mac->tx->dma); - kfree(mac->tx->desc_info); + kfree(mac->tx->ring_info); kfree(mac->tx); mac->tx = NULL; } @@ -338,34 +332,31 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); unsigned int i; struct pasemi_mac_buffer *info; - struct pas_dma_xct_descr *dp; for (i = 0; i < RX_RING_SIZE; i++) { - info = &RX_DESC_INFO(mac, i); - dp = &RX_DESC(mac, i); - if (info->skb) { - if (info->dma) { - pci_unmap_single(mac->dma_pdev, - info->dma, - info->skb->len, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(info->skb); - } - info->dma = 0; - info->skb = NULL; - dp->macrx = 0; - dp->ptr = 0; + info = &RX_RING_INFO(mac, i); + if (info->skb && info->dma) { + pci_unmap_single(mac->dma_pdev, + info->dma, + info->skb->len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(info->skb); } + info->dma = 0; + info->skb = NULL; } + for (i = 0; i < RX_RING_SIZE; i++) + RX_RING(mac, i) = 0; + dma_free_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(struct pas_dma_xct_descr), - mac->rx->desc, mac->rx->dma); + RX_RING_SIZE * sizeof(u64), + mac->rx->ring, mac->rx->dma); dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), mac->rx->buffers, mac->rx->buf_dma); - kfree(mac->rx->desc_info); + kfree(mac->rx->ring_info); kfree(mac->rx); mac->rx = NULL; } @@ -373,20 +364,22 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) { struct pasemi_mac *mac = netdev_priv(dev); - unsigned int i; int start = mac->rx->next_to_fill; - int count; + unsigned int fill, count; if (limit <= 0) return; - i = start; + fill = start; for (count = 0; count < limit; count++) { - struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); - u64 *buff = &RX_BUFF(mac, i); + struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill); + u64 *buff = &RX_BUFF(mac, fill); struct sk_buff *skb; dma_addr_t dma; + /* Entry in use? */ + WARN_ON(*buff); + /* skb might still be in there for recycle on short receives */ if (info->skb) skb = info->skb; @@ -407,7 +400,7 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) info->skb = skb; info->dma = dma; *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma); - i++; + fill++; } wmb(); @@ -481,7 +474,6 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) { unsigned int n; int count; - struct pas_dma_xct_descr *dp; struct pasemi_mac_buffer *info; struct sk_buff *skb; unsigned int i, len; @@ -496,9 +488,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) rmb(); - dp = &RX_DESC(mac, n); - prefetchw(dp); - macrx = dp->macrx; + macrx = RX_RING(mac, n); if ((macrx & XCT_MACRX_E) || (*mac->rx_status & PAS_STATUS_ERROR)) @@ -516,12 +506,15 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) * interface ring. */ - dma = (dp->ptr & XCT_PTR_ADDR_M); - for (i = n; i < (n + RX_RING_SIZE); i++) { - info = &RX_DESC_INFO(mac, i); + dma = (RX_RING(mac, n+1) & XCT_PTR_ADDR_M); + for (i = mac->rx->next_to_fill; + i < (mac->rx->next_to_fill + RX_RING_SIZE); + i++) { + info = &RX_RING_INFO(mac, i); if (info->dma == dma) break; } + prefetchw(info); skb = info->skb; @@ -546,6 +539,11 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } else info->skb = NULL; + /* Need to zero it out since hardware doesn't, since the + * replenish loop uses it to tell when it's done. + */ + RX_BUFF(mac, i) = 0; + skb_put(skb, len); if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) { @@ -561,13 +559,13 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) skb->protocol = eth_type_trans(skb, mac->netdev); netif_receive_skb(skb); - dp->ptr = 0; - dp->macrx = 0; + RX_RING(mac, n) = 0; + RX_RING(mac, n+1) = 0; - n++; + n += 2; } - mac->rx->next_to_clean += limit - count; + mac->rx->next_to_clean = n; pasemi_mac_replenish_rx_ring(mac->netdev, limit-count); spin_unlock(&mac->rx->lock); @@ -579,7 +577,6 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) { int i; struct pasemi_mac_buffer *info; - struct pas_dma_xct_descr *dp; unsigned int start, count, limit; unsigned int total_count; unsigned long flags; @@ -595,29 +592,28 @@ restart: count = 0; - for (i = start; i < limit; i++) { - dp = &TX_DESC(mac, i); - - if ((dp->mactx & XCT_MACTX_E) || + for (i = start; i < limit; i += 2) { + u64 mactx = TX_RING(mac, i); + if ((mactx & XCT_MACTX_E) || (*mac->tx_status & PAS_STATUS_ERROR)) - pasemi_mac_tx_error(mac, dp->mactx); + pasemi_mac_tx_error(mac, mactx); - if (unlikely(dp->mactx & XCT_MACTX_O)) + if (unlikely(mactx & XCT_MACTX_O)) /* Not yet transmitted */ break; - info = &TX_DESC_INFO(mac, i); + info = &TX_RING_INFO(mac, i+1); skbs[count] = info->skb; dmas[count] = info->dma; - info->skb = NULL; info->dma = 0; - dp->mactx = 0; - dp->ptr = 0; + TX_RING(mac, i) = 0; + TX_RING(mac, i+1) = 0; + count++; } - mac->tx->next_to_clean += count; + mac->tx->next_to_clean += count * 2; spin_unlock_irqrestore(&mac->tx->lock, flags); netif_wake_queue(mac->netdev); @@ -1001,8 +997,6 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); struct pasemi_mac_txring *txring; - struct pasemi_mac_buffer *info; - struct pas_dma_xct_descr *dp; u64 dflags, mactx, ptr; dma_addr_t map; unsigned long flags; @@ -1038,13 +1032,13 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= 1) { + if (RING_AVAIL(txring) <= 2) { spin_unlock_irqrestore(&txring->lock, flags); pasemi_mac_clean_tx(mac); pasemi_mac_restart_tx_intr(mac); spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= 1) { + if (RING_AVAIL(txring) <= 2) { /* Still no room -- stop the queue and wait for tx * intr when there's room. */ @@ -1053,15 +1047,14 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - dp = &TX_DESC(mac, txring->next_to_fill); - info = &TX_DESC_INFO(mac, txring->next_to_fill); + TX_RING(mac, txring->next_to_fill) = mactx; + TX_RING(mac, txring->next_to_fill+1) = ptr; - dp->mactx = mactx; - dp->ptr = ptr; - info->dma = map; - info->skb = skb; + TX_RING_INFO(mac, txring->next_to_fill+1).dma = map; + TX_RING_INFO(mac, txring->next_to_fill+1).skb = skb; + + txring->next_to_fill += 2; - txring->next_to_fill++; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index c52cfcb6c4ca..5a896aa87a99 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -28,25 +28,25 @@ struct pasemi_mac_txring { spinlock_t lock; - struct pas_dma_xct_descr *desc; + u64 *ring; dma_addr_t dma; unsigned int size; unsigned int next_to_fill; unsigned int next_to_clean; - struct pasemi_mac_buffer *desc_info; + struct pasemi_mac_buffer *ring_info; char irq_name[10]; /* "eth%d tx" */ }; struct pasemi_mac_rxring { spinlock_t lock; - struct pas_dma_xct_descr *desc; /* RX channel descriptor ring */ + u64 *ring; /* RX channel descriptor ring */ dma_addr_t dma; u64 *buffers; /* RX interface buffer ring */ dma_addr_t buf_dma; unsigned int size; unsigned int next_to_fill; unsigned int next_to_clean; - struct pasemi_mac_buffer *desc_info; + struct pasemi_mac_buffer *ring_info; char irq_name[10]; /* "eth%d rx" */ }; @@ -88,7 +88,7 @@ struct pasemi_mac { char phy_id[BUS_ID_SIZE]; }; -/* Software status descriptor (desc_info) */ +/* Software status descriptor (ring_info) */ struct pasemi_mac_buffer { struct sk_buff *skb; dma_addr_t dma; @@ -101,20 +101,7 @@ struct pasdma_status { u64 tx_sta[20]; }; -/* descriptor structure */ -struct pas_dma_xct_descr { - union { - u64 mactx; - u64 macrx; - }; - union { - u64 ptr; - u64 rxb; - }; -}; - /* MAC CFG register offsets */ - enum { PAS_MAC_CFG_PCFG = 0x80, PAS_MAC_CFG_TXP = 0x98, From ad3c20d1ab586884f1815c315e3f303a8b8a7d7d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:26:13 -0500 Subject: [PATCH 1690/2804] pasemi_mac: implement sg support pasemi_mac: implement sg support Implement SG support for pasemi_mac Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 163 ++++++++++++++++++++++++++++----------- 1 file changed, 117 insertions(+), 46 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c2a3524a5411..5eb5e47120d0 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -160,6 +160,30 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac) return 0; } +static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac, + struct sk_buff *skb, + dma_addr_t *dmas) +{ + int f; + int nfrags = skb_shinfo(skb)->nr_frags; + + pci_unmap_single(mac->dma_pdev, dmas[0], skb_headlen(skb), + PCI_DMA_TODEVICE); + + for (f = 0; f < nfrags; f++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; + + pci_unmap_page(mac->dma_pdev, dmas[f+1], frag->size, + PCI_DMA_TODEVICE); + } + dev_kfree_skb_irq(skb); + + /* Freed descriptor slot + main SKB ptr + nfrags additional ptrs, + * aligned up to a power of 2 + */ + return (nfrags + 3) & ~1; +} + static int pasemi_mac_setup_rx_resources(struct net_device *dev) { struct pasemi_mac_rxring *ring; @@ -300,24 +324,24 @@ out_ring: static void pasemi_mac_free_tx_resources(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); - unsigned int i; + unsigned int i, j; struct pasemi_mac_buffer *info; + dma_addr_t dmas[MAX_SKB_FRAGS+1]; + int freed; - for (i = 0; i < TX_RING_SIZE; i += 2) { + for (i = 0; i < TX_RING_SIZE; i += freed) { info = &TX_RING_INFO(mac, i+1); if (info->dma && info->skb) { - pci_unmap_single(mac->dma_pdev, - info->dma, - info->skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(info->skb); - } - TX_RING(mac, i) = 0; - TX_RING(mac, i+1) = 0; - info->dma = 0; - info->skb = NULL; + for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) + dmas[j] = TX_RING_INFO(mac, i+1+j).dma; + freed = pasemi_mac_unmap_tx_skb(mac, info->skb, dmas); + } else + freed = 2; } + for (i = 0; i < TX_RING_SIZE; i++) + TX_RING(mac, i) = 0; + dma_free_coherent(&mac->dma_pdev->dev, TX_RING_SIZE * sizeof(u64), mac->tx->ring, mac->tx->dma); @@ -573,27 +597,34 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) return count; } +/* Can't make this too large or we blow the kernel stack limits */ +#define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS) + static int pasemi_mac_clean_tx(struct pasemi_mac *mac) { - int i; + int i, j; struct pasemi_mac_buffer *info; - unsigned int start, count, limit; + unsigned int start, descr_count, buf_count, limit; unsigned int total_count; unsigned long flags; - struct sk_buff *skbs[32]; - dma_addr_t dmas[32]; + struct sk_buff *skbs[TX_CLEAN_BATCHSIZE]; + dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1]; total_count = 0; + limit = TX_CLEAN_BATCHSIZE; restart: spin_lock_irqsave(&mac->tx->lock, flags); start = mac->tx->next_to_clean; - limit = min(mac->tx->next_to_fill, start+32); - count = 0; + buf_count = 0; + descr_count = 0; - for (i = start; i < limit; i += 2) { + for (i = start; + descr_count < limit && i < mac->tx->next_to_fill; + i += buf_count) { u64 mactx = TX_RING(mac, i); + if ((mactx & XCT_MACTX_E) || (*mac->tx_status & PAS_STATUS_ERROR)) pasemi_mac_tx_error(mac, mactx); @@ -603,30 +634,38 @@ restart: break; info = &TX_RING_INFO(mac, i+1); - skbs[count] = info->skb; - dmas[count] = info->dma; + skbs[descr_count] = info->skb; + + buf_count = 2 + skb_shinfo(info->skb)->nr_frags; + for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) + dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma; + info->dma = 0; TX_RING(mac, i) = 0; TX_RING(mac, i+1) = 0; + TX_RING_INFO(mac, i+1).skb = 0; + TX_RING_INFO(mac, i+1).dma = 0; - - count++; + /* Since we always fill with an even number of entries, make + * sure we skip any unused one at the end as well. + */ + if (buf_count & 1) + buf_count++; + descr_count++; } - mac->tx->next_to_clean += count * 2; + mac->tx->next_to_clean = i; + spin_unlock_irqrestore(&mac->tx->lock, flags); netif_wake_queue(mac->netdev); - for (i = 0; i < count; i++) { - pci_unmap_single(mac->dma_pdev, dmas[i], - skbs[i]->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skbs[i]); - } + for (i = 0; i < descr_count; i++) + pasemi_mac_unmap_tx_skb(mac, skbs[i], dmas[i]); - total_count += count; + total_count += descr_count; /* If the batch was full, try to clean more */ - if (count == 32) + if (descr_count == limit) goto restart; return total_count; @@ -997,9 +1036,11 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); struct pasemi_mac_txring *txring; - u64 dflags, mactx, ptr; - dma_addr_t map; + u64 dflags, mactx; + dma_addr_t map[MAX_SKB_FRAGS+1]; + unsigned int map_size[MAX_SKB_FRAGS+1]; unsigned long flags; + int i, nfrags; dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD; @@ -1020,25 +1061,40 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + nfrags = skb_shinfo(skb)->nr_frags; - if (dma_mapping_error(map)) - return NETDEV_TX_BUSY; + map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb), + PCI_DMA_TODEVICE); + map_size[0] = skb_headlen(skb); + if (dma_mapping_error(map[0])) + goto out_err_nolock; + + for (i = 0; i < nfrags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + map[i+1] = pci_map_page(mac->dma_pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + map_size[i+1] = frag->size; + if (dma_mapping_error(map[i+1])) { + nfrags = i; + goto out_err_nolock; + } + } mactx = dflags | XCT_MACTX_LLEN(skb->len); - ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map); txring = mac->tx; spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= 2) { + if (RING_AVAIL(txring) <= nfrags+3) { spin_unlock_irqrestore(&txring->lock, flags); pasemi_mac_clean_tx(mac); pasemi_mac_restart_tx_intr(mac); spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= 2) { + if (RING_AVAIL(txring) <= nfrags+3) { /* Still no room -- stop the queue and wait for tx * intr when there's room. */ @@ -1048,25 +1104,40 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } TX_RING(mac, txring->next_to_fill) = mactx; - TX_RING(mac, txring->next_to_fill+1) = ptr; + txring->next_to_fill++; + TX_RING_INFO(mac, txring->next_to_fill).skb = skb; + for (i = 0; i <= nfrags; i++) { + TX_RING(mac, txring->next_to_fill+i) = + XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]); + TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i]; + } - TX_RING_INFO(mac, txring->next_to_fill+1).dma = map; - TX_RING_INFO(mac, txring->next_to_fill+1).skb = skb; + /* We have to add an even number of 8-byte entries to the ring + * even if the last one is unused. That means always an odd number + * of pointers + one mactx descriptor. + */ + if (nfrags & 1) + nfrags++; + + txring->next_to_fill += nfrags + 1; - txring->next_to_fill += 2; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; spin_unlock_irqrestore(&txring->lock, flags); - write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1); + write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1); return NETDEV_TX_OK; out_err: spin_unlock_irqrestore(&txring->lock, flags); - pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE); +out_err_nolock: + while (nfrags--) + pci_unmap_single(mac->dma_pdev, map[nfrags], map_size[nfrags], + PCI_DMA_TODEVICE); + return NETDEV_TX_BUSY; } @@ -1202,7 +1273,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); - dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX; + dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX | NETIF_F_SG; /* These should come out of the device tree eventually */ mac->dma_txch = index; From 9a50bebda95745d312c69d3bb6d788067cbefb84 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:26:30 -0500 Subject: [PATCH 1691/2804] pasemi_mac: workaround for erratum 5971 pasemi_mac: workaround for erratum 5971 Implement workarounds for erratum 5971, where L2 hints aren't considered properly unless the way hint is enabled on the interface. Since L2 isn't setup to dedicate a way to headers, we need to reset the packet count by hand so it won't run out of credits. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 9 ++++++++- drivers/net/pasemi_mac.h | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 5eb5e47120d0..c538c66d4b4f 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -239,7 +239,9 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), - PAS_DMA_RXINT_CFG_DHL(2)); + PAS_DMA_RXINT_CFG_DHL(3) | + PAS_DMA_RXINT_CFG_L2 | + PAS_DMA_RXINT_CFG_LW); ring->next_to_fill = 0; ring->next_to_clean = 0; @@ -589,6 +591,11 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) n += 2; } + if (n > RX_RING_SIZE) { + /* Errata 5971 workaround: L2 target of headers */ + write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0); + n &= (RX_RING_SIZE-1); + } mac->rx->next_to_clean = n; pasemi_mac_replenish_rx_ring(mac->netdev, limit-count); diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 5a896aa87a99..db3393674ae7 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -210,6 +210,8 @@ enum { #define PAS_DMA_RXINT_CFG_DHL_S 24 #define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ PAS_DMA_RXINT_CFG_DHL_M) +#define PAS_DMA_RXINT_CFG_LW 0x00200000 +#define PAS_DMA_RXINT_CFG_L2 0x00100000 #define PAS_DMA_RXINT_CFG_WIF 0x00000002 #define PAS_DMA_RXINT_CFG_WIL 0x00000001 @@ -315,6 +317,12 @@ enum { #define PAS_STATUS_SOFT 0x4000000000000000ull #define PAS_STATUS_INT 0x8000000000000000ull +#define PAS_IOB_COM_PKTHDRCNT 0x120 +#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_M 0x0fff0000 +#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_S 16 +#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_M 0x00000fff +#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_S 0 + #define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4) #define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff #define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0 From 8dc121a4b620090e594945fd36f878836fc5a14a Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:26:53 -0500 Subject: [PATCH 1692/2804] pasemi_mac: add local skb alignment pasemi_mac: add local skb alignment Add local SKB alignment to pasemi_mac, since ppc64 in general has it at 0 because of design flaws in some of the IBM server bridge chips. However, for PWRficient doing the unaligned copies is more expensive than doing unaligned DMA so make sure the data is aligned instead. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c538c66d4b4f..b3994f5d2d2b 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -37,6 +37,12 @@ #include "pasemi_mac.h" +/* We have our own align, since ppc64 in general has it at 0 because + * of design flaws in some of the server bridge chips. However, for + * PWRficient doing the unaligned copies is more expensive than doing + * unaligned DMA, so make sure the data is aligned instead. + */ +#define LOCAL_SKB_ALIGN 2 /* TODO list * @@ -409,13 +415,16 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) /* skb might still be in there for recycle on short receives */ if (info->skb) skb = info->skb; - else + else { skb = dev_alloc_skb(BUF_SIZE); + skb_reserve(skb, LOCAL_SKB_ALIGN); + } if (unlikely(!skb)) break; - dma = pci_map_single(mac->dma_pdev, skb->data, BUF_SIZE, + dma = pci_map_single(mac->dma_pdev, skb->data, + BUF_SIZE - LOCAL_SKB_ALIGN, PCI_DMA_FROMDEVICE); if (unlikely(dma_mapping_error(dma))) { @@ -553,10 +562,12 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; if (len < 256) { - struct sk_buff *new_skb = - netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN); + struct sk_buff *new_skb; + + new_skb = netdev_alloc_skb(mac->netdev, + len + LOCAL_SKB_ALIGN); if (new_skb) { - skb_reserve(new_skb, NET_IP_ALIGN); + skb_reserve(new_skb, LOCAL_SKB_ALIGN); memcpy(new_skb->data, skb->data, len); /* save the skb in buffer_info as good */ skb = new_skb; From ad5da10a64bdca1ed39b25946727a1ce2659f3d4 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:27:15 -0500 Subject: [PATCH 1693/2804] pasemi_mac: further performance tweaks pasemi_mac: further performance tweaks Misc driver tweaks for pasemi_mac: * Increase ring size (really needed mostly on 10G) * Take out an unneeded barrier * Move around a few prefetches and reorder a few calls * Don't try to clean on full tx buffer, just let things take their course and stop the queue directly * Avoid filling on the same line as the interface is working on to reduce cache line bouncing * Avoid unneeded clearing of software state (and make the interface shutdown code handle it) * Fix up some of the tx ring wrap logic. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 92 ++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index b3994f5d2d2b..4a451f8c6f4d 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -56,8 +56,8 @@ /* Must be a power of two */ -#define RX_RING_SIZE 512 -#define TX_RING_SIZE 512 +#define RX_RING_SIZE 4096 +#define TX_RING_SIZE 4096 #define DEFAULT_MSG_ENABLE \ (NETIF_MSG_DRV | \ @@ -336,8 +336,16 @@ static void pasemi_mac_free_tx_resources(struct net_device *dev) struct pasemi_mac_buffer *info; dma_addr_t dmas[MAX_SKB_FRAGS+1]; int freed; + int start, limit; - for (i = 0; i < TX_RING_SIZE; i += freed) { + start = mac->tx->next_to_clean; + limit = mac->tx->next_to_fill; + + /* Compensate for when fill has wrapped and clean has not */ + if (start > limit) + limit += TX_RING_SIZE; + + for (i = start; i < limit; i += freed) { info = &TX_RING_INFO(mac, i+1); if (info->dma && info->skb) { for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) @@ -520,9 +528,6 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) n = mac->rx->next_to_clean; for (count = limit; count; count--) { - - rmb(); - macrx = RX_RING(mac, n); if ((macrx & XCT_MACRX_E) || @@ -550,14 +555,10 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) break; } - prefetchw(info); - skb = info->skb; - prefetchw(skb); - info->dma = 0; - pci_unmap_single(mac->dma_pdev, dma, skb->len, - PCI_DMA_FROMDEVICE); + prefetch(skb); + prefetch(&skb->data_len); len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; @@ -576,10 +577,9 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } else info->skb = NULL; - /* Need to zero it out since hardware doesn't, since the - * replenish loop uses it to tell when it's done. - */ - RX_BUFF(mac, i) = 0; + pci_unmap_single(mac->dma_pdev, dma, len, PCI_DMA_FROMDEVICE); + + info->dma = 0; skb_put(skb, len); @@ -599,6 +599,11 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) RX_RING(mac, n) = 0; RX_RING(mac, n+1) = 0; + /* Need to zero it out since hardware doesn't, since the + * replenish loop uses it to tell when it's done. + */ + RX_BUFF(mac, i) = 0; + n += 2; } @@ -621,27 +626,33 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) static int pasemi_mac_clean_tx(struct pasemi_mac *mac) { int i, j; - struct pasemi_mac_buffer *info; - unsigned int start, descr_count, buf_count, limit; + unsigned int start, descr_count, buf_count, batch_limit; + unsigned int ring_limit; unsigned int total_count; unsigned long flags; struct sk_buff *skbs[TX_CLEAN_BATCHSIZE]; dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1]; total_count = 0; - limit = TX_CLEAN_BATCHSIZE; + batch_limit = TX_CLEAN_BATCHSIZE; restart: spin_lock_irqsave(&mac->tx->lock, flags); start = mac->tx->next_to_clean; + ring_limit = mac->tx->next_to_fill; + + /* Compensate for when fill has wrapped but clean has not */ + if (start > ring_limit) + ring_limit += TX_RING_SIZE; buf_count = 0; descr_count = 0; for (i = start; - descr_count < limit && i < mac->tx->next_to_fill; + descr_count < batch_limit && i < ring_limit; i += buf_count) { u64 mactx = TX_RING(mac, i); + struct sk_buff *skb; if ((mactx & XCT_MACTX_E) || (*mac->tx_status & PAS_STATUS_ERROR)) @@ -651,19 +662,15 @@ restart: /* Not yet transmitted */ break; - info = &TX_RING_INFO(mac, i+1); - skbs[descr_count] = info->skb; + skb = TX_RING_INFO(mac, i+1).skb; + skbs[descr_count] = skb; - buf_count = 2 + skb_shinfo(info->skb)->nr_frags; - for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) + buf_count = 2 + skb_shinfo(skb)->nr_frags; + for (j = 0; j <= skb_shinfo(skb)->nr_frags; j++) dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma; - - info->dma = 0; TX_RING(mac, i) = 0; TX_RING(mac, i+1) = 0; - TX_RING_INFO(mac, i+1).skb = 0; - TX_RING_INFO(mac, i+1).dma = 0; /* Since we always fill with an even number of entries, make * sure we skip any unused one at the end as well. @@ -672,7 +679,7 @@ restart: buf_count++; descr_count++; } - mac->tx->next_to_clean = i; + mac->tx->next_to_clean = i & (TX_RING_SIZE-1); spin_unlock_irqrestore(&mac->tx->lock, flags); netif_wake_queue(mac->netdev); @@ -683,7 +690,7 @@ restart: total_count += descr_count; /* If the batch was full, try to clean more */ - if (descr_count == limit) + if (descr_count == batch_limit) goto restart; return total_count; @@ -1106,19 +1113,14 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= nfrags+3) { - spin_unlock_irqrestore(&txring->lock, flags); - pasemi_mac_clean_tx(mac); - pasemi_mac_restart_tx_intr(mac); - spin_lock_irqsave(&txring->lock, flags); - - if (RING_AVAIL(txring) <= nfrags+3) { - /* Still no room -- stop the queue and wait for tx - * intr when there's room. - */ - netif_stop_queue(dev); - goto out_err; - } + /* Avoid stepping on the same cache line that the DMA controller + * is currently about to send, so leave at least 8 words available. + * Total free space needed is mactx + fragments + 8 + */ + if (RING_AVAIL(txring) < nfrags + 10) { + /* no room -- stop the queue and wait for tx intr */ + netif_stop_queue(dev); + goto out_err; } TX_RING(mac, txring->next_to_fill) = mactx; @@ -1137,8 +1139,8 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) if (nfrags & 1) nfrags++; - txring->next_to_fill += nfrags + 1; - + txring->next_to_fill = (txring->next_to_fill + nfrags + 1) & + (TX_RING_SIZE-1); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; From 7ddeae2c6ceed7f786344731dda27d4277957780 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:27:28 -0500 Subject: [PATCH 1694/2804] pasemi_mac: update todo list pasemi_mac: update todo list Remove some stale todo items that have been taken care of. Add a couple of upcoming ones. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 4a451f8c6f4d..ef1ebb4b8af2 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -46,12 +46,10 @@ /* TODO list * - * - Get rid of pci_{read,write}_config(), map registers with ioremap - * for performance - * - PHY support * - Multicast support * - Large MTU support - * - Other performance improvements + * - SW LRO + * - Multiqueue RX/TX */ From 9e81d331f2ec65695e4366ce592e14f9700bae8b Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:27:39 -0500 Subject: [PATCH 1695/2804] pasemi_mac: clear out old errors on interface open pasemi_mac: clear out old errors on interface open Clear out any pending errors when an interface is brought up. Since the bits are sticky, they might be from interface shutdown time after firmware has used it, etc. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 57 +++++++++++++++++++++++++++++++--------- drivers/net/pasemi_mac.h | 7 +++++ 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index ef1ebb4b8af2..967ff8c96b0f 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -903,16 +903,27 @@ static int pasemi_mac_open(struct net_device *dev) /* enable rx if */ write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - PAS_DMA_RXINT_RCMDSTA_EN); + PAS_DMA_RXINT_RCMDSTA_EN | + PAS_DMA_RXINT_RCMDSTA_DROPS_M | + PAS_DMA_RXINT_RCMDSTA_BP | + PAS_DMA_RXINT_RCMDSTA_OO | + PAS_DMA_RXINT_RCMDSTA_BT); /* enable rx channel */ write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_EN | - PAS_DMA_RXCHAN_CCMDSTA_DU); + PAS_DMA_RXCHAN_CCMDSTA_DU | + PAS_DMA_RXCHAN_CCMDSTA_OD | + PAS_DMA_RXCHAN_CCMDSTA_FD | + PAS_DMA_RXCHAN_CCMDSTA_DT); /* enable tx channel */ write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - PAS_DMA_TXCHAN_TCMDSTA_EN); + PAS_DMA_TXCHAN_TCMDSTA_EN | + PAS_DMA_TXCHAN_TCMDSTA_SZ | + PAS_DMA_TXCHAN_TCMDSTA_DB | + PAS_DMA_TXCHAN_TCMDSTA_DE | + PAS_DMA_TXCHAN_TCMDSTA_DA); pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE); @@ -987,7 +998,7 @@ out_rx_resources: static int pasemi_mac_close(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); - unsigned int stat; + unsigned int sta; int retries; if (mac->phydev) { @@ -998,6 +1009,26 @@ static int pasemi_mac_close(struct net_device *dev) netif_stop_queue(dev); napi_disable(&mac->napi); + sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + if (sta & (PAS_DMA_RXINT_RCMDSTA_BP | + PAS_DMA_RXINT_RCMDSTA_OO | + PAS_DMA_RXINT_RCMDSTA_BT)) + printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta); + + sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU | + PAS_DMA_RXCHAN_CCMDSTA_OD | + PAS_DMA_RXCHAN_CCMDSTA_FD | + PAS_DMA_RXCHAN_CCMDSTA_DT)) + printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta); + + sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); + if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ | + PAS_DMA_TXCHAN_TCMDSTA_DB | + PAS_DMA_TXCHAN_TCMDSTA_DE | + PAS_DMA_TXCHAN_TCMDSTA_DA)) + printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta); + /* Clean out any pending buffers */ pasemi_mac_clean_tx(mac); pasemi_mac_clean_rx(mac, RX_RING_SIZE); @@ -1008,33 +1039,33 @@ static int pasemi_mac_close(struct net_device *dev) write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST); for (retries = 0; retries < MAX_RETRIES; retries++) { - stat = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); - if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) + sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); + if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)) break; cond_resched(); } - if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) + if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - stat = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); - if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) + sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)) break; cond_resched(); } - if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT) + if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - stat = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); - if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) + sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT)) break; cond_resched(); } - if (stat & PAS_DMA_RXINT_RCMDSTA_ACT) + if (sta & PAS_DMA_RXINT_RCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n"); /* Then, disable the channel. This must be done separately from diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index db3393674ae7..0bb3c487478d 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -241,6 +241,10 @@ enum { #define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */ #define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */ #define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */ +#define PAS_DMA_TXCHAN_TCMDSTA_SZ 0x00000800 +#define PAS_DMA_TXCHAN_TCMDSTA_DB 0x00000400 +#define PAS_DMA_TXCHAN_TCMDSTA_DE 0x00000200 +#define PAS_DMA_TXCHAN_TCMDSTA_DA 0x00000100 #define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE) #define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */ #define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c @@ -283,6 +287,9 @@ enum { #define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */ #define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */ #define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000 +#define PAS_DMA_RXCHAN_CCMDSTA_OD 0x00002000 +#define PAS_DMA_RXCHAN_CCMDSTA_FD 0x00001000 +#define PAS_DMA_RXCHAN_CCMDSTA_DT 0x00000800 #define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE) #define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380 #define PAS_DMA_RXCHAN_CFG_HBU_S 7 From b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:27:57 -0500 Subject: [PATCH 1696/2804] pasemi_mac: use buffer index pointer in clean_rx() pasemi_mac: use buffer index pointer in clean_rx() Use the new features in B0 for buffer ring index on the receive side. This means we no longer have to search in the ring for where the buffer came from. Also cleanup the RX cleaning side a little, while I was at it. Note: Pre-B0 hardware is no longer supported, and needs a pile of other workarounds that are not being submitted for mainline inclusion. So the fact that this breaks old hardware is not a problem at this time. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 60 ++++++++++++++++++++++------------------ drivers/net/pasemi_mac.h | 21 +++++++++++--- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 967ff8c96b0f..31ad2b9093a7 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -243,9 +243,9 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), - PAS_DMA_RXINT_CFG_DHL(3) | - PAS_DMA_RXINT_CFG_L2 | - PAS_DMA_RXINT_CFG_LW); + PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 | + PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP | + PAS_DMA_RXINT_CFG_HEN); ring->next_to_fill = 0; ring->next_to_clean = 0; @@ -402,13 +402,12 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) { struct pasemi_mac *mac = netdev_priv(dev); - int start = mac->rx->next_to_fill; - unsigned int fill, count; + int fill, count; if (limit <= 0) return; - fill = start; + fill = mac->rx->next_to_fill; for (count = 0; count < limit; count++) { struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill); u64 *buff = &RX_BUFF(mac, fill); @@ -446,10 +445,10 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) wmb(); - write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count); write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count); - mac->rx->next_to_fill += count; + mac->rx->next_to_fill = (mac->rx->next_to_fill + count) & + (RX_RING_SIZE - 1); } static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) @@ -517,15 +516,19 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) int count; struct pasemi_mac_buffer *info; struct sk_buff *skb; - unsigned int i, len; + unsigned int len; u64 macrx; dma_addr_t dma; + int buf_index; + u64 eval; spin_lock(&mac->rx->lock); n = mac->rx->next_to_clean; - for (count = limit; count; count--) { + prefetch(RX_RING(mac, n)); + + for (count = 0; count < limit; count++) { macrx = RX_RING(mac, n); if ((macrx & XCT_MACRX_E) || @@ -537,21 +540,14 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) info = NULL; - /* We have to scan for our skb since there's no way - * to back-map them from the descriptor, and if we - * have several receive channels then they might not - * show up in the same order as they were put on the - * interface ring. - */ + BUG_ON(!(macrx & XCT_MACRX_RR_8BRES)); - dma = (RX_RING(mac, n+1) & XCT_PTR_ADDR_M); - for (i = mac->rx->next_to_fill; - i < (mac->rx->next_to_fill + RX_RING_SIZE); - i++) { - info = &RX_RING_INFO(mac, i); - if (info->dma == dma) - break; - } + eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >> + XCT_RXRES_8B_EVAL_S; + buf_index = eval-1; + + dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M); + info = &RX_RING_INFO(mac, buf_index); skb = info->skb; @@ -600,9 +596,9 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) /* Need to zero it out since hardware doesn't, since the * replenish loop uses it to tell when it's done. */ - RX_BUFF(mac, i) = 0; + RX_BUFF(mac, buf_index) = 0; - n += 2; + n += 4; } if (n > RX_RING_SIZE) { @@ -610,8 +606,16 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0); n &= (RX_RING_SIZE-1); } + mac->rx->next_to_clean = n; - pasemi_mac_replenish_rx_ring(mac->netdev, limit-count); + + /* Increase is in number of 16-byte entries, and since each descriptor + * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with + * count*2. + */ + write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1); + + pasemi_mac_replenish_rx_ring(mac->netdev, count); spin_unlock(&mac->rx->lock); @@ -927,6 +931,8 @@ static int pasemi_mac_open(struct net_device *dev) pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE); + write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1); + flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 0bb3c487478d..1a120408cf3f 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -206,12 +206,15 @@ enum { #define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000 #define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17 #define PAS_DMA_RXINT_CFG(i) (0x204+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_CFG_RBP 0x80000000 +#define PAS_DMA_RXINT_CFG_ITRR 0x40000000 #define PAS_DMA_RXINT_CFG_DHL_M 0x07000000 #define PAS_DMA_RXINT_CFG_DHL_S 24 #define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ PAS_DMA_RXINT_CFG_DHL_M) #define PAS_DMA_RXINT_CFG_LW 0x00200000 #define PAS_DMA_RXINT_CFG_L2 0x00100000 +#define PAS_DMA_RXINT_CFG_HEN 0x00080000 #define PAS_DMA_RXINT_CFG_WIF 0x00000002 #define PAS_DMA_RXINT_CFG_WIL 0x00000001 @@ -425,10 +428,9 @@ enum { /* Receive descriptor fields */ #define XCT_MACRX_T 0x8000000000000000ull #define XCT_MACRX_ST 0x4000000000000000ull -#define XCT_MACRX_NORES 0x0000000000000000ull -#define XCT_MACRX_8BRES 0x1000000000000000ull -#define XCT_MACRX_24BRES 0x2000000000000000ull -#define XCT_MACRX_40BRES 0x3000000000000000ull +#define XCT_MACRX_RR_M 0x3000000000000000ull +#define XCT_MACRX_RR_NORES 0x0000000000000000ull +#define XCT_MACRX_RR_8BRES 0x1000000000000000ull #define XCT_MACRX_O 0x0400000000000000ull #define XCT_MACRX_E 0x0200000000000000ull #define XCT_MACRX_FF 0x0100000000000000ull @@ -476,6 +478,17 @@ enum { #define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \ XCT_PTR_ADDR_M) +/* Receive interface 8byte result fields */ +#define XCT_RXRES_8B_L4O_M 0xff00000000000000ull +#define XCT_RXRES_8B_L4O_S 56 +#define XCT_RXRES_8B_RULE_M 0x00ffff0000000000ull +#define XCT_RXRES_8B_RULE_S 40 +#define XCT_RXRES_8B_EVAL_M 0x000000ffff000000ull +#define XCT_RXRES_8B_EVAL_S 24 +#define XCT_RXRES_8B_HTYPE_M 0x0000000000f00000ull +#define XCT_RXRES_8B_HASH_M 0x00000000000fffffull +#define XCT_RXRES_8B_HASH_S 0 + /* Receive interface buffer fields */ #define XCT_RXB_LEN_M 0x0ffff00000000000ull #define XCT_RXB_LEN_S 44 From 1dad939ddbbd8d64e1edc7799df00a9e591b4197 Mon Sep 17 00:00:00 2001 From: trem Date: Tue, 2 Oct 2007 14:04:38 -0700 Subject: [PATCH 1697/2804] ipg.c doesn't compile with with CONFIG_HIGHMEM64G I've tried to compile 2.6.23-rc8-mm2, but it fails on ipg.c with the error : ERROR: "__udivdi3" [drivers/net/ipg.ko] undefined! I've instigated a bit, and I've found this code in ipg.c : static void ipg_nic_txfree(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; const unsigned int curr = ipg_r32(TFD_LIST_PTR_0) - (sp->txd_map / sizeof(struct ipg_tx)) - 1; unsigned int released, pending; sp->txd_map is an u64 because : dma_addr_t txd_map; And in asm-i386/types.h, I see : #ifdef CONFIG_HIGHMEM64G typedef u64 dma_addr_t; #else typedef u32 dma_addr_t; #endif I my config, I use CONFIG_HIGHMEM64G sizeof(struct ipg_tx) is an u32 So the div failed on i386 because of u64 / u32. [akpm@linux-foundation.org: cleanups] Cc: Sorbica Shieh Cc: Jesse Huang Cc: Jeff Garzik Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/ipg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index dfdc96fcadec..59898ce54dcf 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -25,6 +25,8 @@ #include #include +#include + #define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH) #define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH) #define IPG_RESET_MASK \ @@ -836,10 +838,14 @@ static void ipg_nic_txfree(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; - const unsigned int curr = ipg_r32(TFD_LIST_PTR_0) - - (sp->txd_map / sizeof(struct ipg_tx)) - 1; + unsigned int curr; + u64 txd_map; unsigned int released, pending; + txd_map = (u64)sp->txd_map; + curr = ipg_r32(TFD_LIST_PTR_0) - + do_div(txd_map, sizeof(struct ipg_tx)) - 1; + IPG_DEBUG_MSG("_nic_txfree\n"); pending = sp->tx_current - sp->tx_dirty; From 07c2c76e27e629fb5c9a539e249906802866abb8 Mon Sep 17 00:00:00 2001 From: "vbarshak@ru.mvista.com" Date: Tue, 2 Oct 2007 16:01:07 +0400 Subject: [PATCH 1698/2804] Fix typo in new EMAC driver. Fix an obvious typo in emac_xmit_finish. Signed-off-by: Valentine Barshak Signed-off-by: Jeff Garzik --- drivers/net/ibm_newemac/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 653bfdc291e0..ce127b9cafa4 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1232,9 +1232,9 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len) * instead */ if (emac_has_feature(dev, EMAC_FTR_EMAC4)) - out_be32(&p->tmr0, EMAC_TMR0_XMIT); - else out_be32(&p->tmr0, EMAC4_TMR0_XMIT); + else + out_be32(&p->tmr0, EMAC_TMR0_XMIT); if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { netif_stop_queue(ndev); From 9ddf7774b9d760dc3fa4d5ae7d7fd92d4c02150b Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 13:52:23 -0400 Subject: [PATCH 1699/2804] drivers/net/qla3xxx: trim trailing whitespace Also, hopefully, change the file permissions to 0644. Signed-off-by: Jeff Garzik --- drivers/net/qla3xxx.c | 128 +++++++++++++++++++++--------------------- drivers/net/qla3xxx.h | 6 +- 2 files changed, 67 insertions(+), 67 deletions(-) mode change 100755 => 100644 drivers/net/qla3xxx.c mode change 100755 => 100644 drivers/net/qla3xxx.h diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c old mode 100755 new mode 100644 index 48069ece4e51..30adf726743c --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -81,7 +81,7 @@ typedef enum { } PHY_DEVICE_et; typedef struct { - PHY_DEVICE_et phyDevice; + PHY_DEVICE_et phyDevice; u32 phyIdOUI; u16 phyIdModel; char *name; @@ -330,7 +330,7 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, PCI_DMA_FROMDEVICE); err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", qdev->ndev->name, err); dev_kfree_skb(lrg_buf_cb->skb); lrg_buf_cb->skb = NULL; @@ -884,14 +884,14 @@ static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev) u16 reg; /* Enable Auto-negotiation sense */ - ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, + ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, PHYAddr[qdev->mac_index]); reg |= PETBI_TBI_AUTO_SENSE; - ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, + ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, PHYAddr[qdev->mac_index]); ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER, - PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, + PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, PHYAddr[qdev->mac_index]); ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, @@ -945,7 +945,7 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr) ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr); /* Write new PHYAD w/bit 5 set */ ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr); - /* + /* * Disable diagnostic mode bit 2 = 0 * Power up device bit 11 = 0 * Link up (on) and activity (blink) @@ -955,18 +955,18 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr) ql_mii_write_reg(qdev, 0x1c, 0xfaf0); } -static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, +static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, u16 phyIdReg0, u16 phyIdReg1) { PHY_DEVICE_et result = PHY_TYPE_UNKNOWN; - u32 oui; + u32 oui; u16 model; - int i; + int i; if (phyIdReg0 == 0xffff) { return result; } - + if (phyIdReg1 == 0xffff) { return result; } @@ -984,7 +984,7 @@ static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, printk(KERN_INFO "%s: Phy: %s\n", qdev->ndev->name, PHY_DEVICES[i].name); - + break; } } @@ -1033,7 +1033,7 @@ static int ql_is_full_dup(struct ql3_adapter *qdev) { if (ql_mii_read_reg(qdev, 0x1A, ®)) return 0; - + return ((reg & 0x0080) && (reg & 0x1000)) != 0; } case PHY_VITESSE_VSC8211: @@ -1082,19 +1082,19 @@ static int PHY_Setup(struct ql3_adapter *qdev) /* Check if we have a Agere PHY */ if ((reg1 == 0xffff) || (reg2 == 0xffff)) { - /* Determine which MII address we should be using + /* Determine which MII address we should be using determined by the index of the card */ if (qdev->mac_index == 0) { miiAddr = MII_AGERE_ADDR_1; } else { miiAddr = MII_AGERE_ADDR_2; } - + err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, ®1, miiAddr); if(err != 0) { printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n", qdev->ndev->name); - return err; + return err; } err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, ®2, miiAddr); @@ -1103,9 +1103,9 @@ static int PHY_Setup(struct ql3_adapter *qdev) qdev->ndev->name); return err; } - + /* We need to remember to initialize the Agere PHY */ - agereAddrChangeNeeded = true; + agereAddrChangeNeeded = true; } /* Determine the particular PHY we have on board to apply @@ -1114,7 +1114,7 @@ static int PHY_Setup(struct ql3_adapter *qdev) if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) { /* need this here so address gets changed */ - phyAgereSpecificInit(qdev, miiAddr); + phyAgereSpecificInit(qdev, miiAddr); } else if (qdev->phyType == PHY_TYPE_UNKNOWN) { printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name); return -EIO; @@ -1427,7 +1427,7 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev) static void ql_phy_reset_ex(struct ql3_adapter *qdev) { - ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, + ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, PHYAddr[qdev->mac_index]); } @@ -1438,7 +1438,7 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) if(qdev->phyType == PHY_AGERE_ET1011C) { /* turn off external loopback */ - ql_mii_write_reg(qdev, 0x13, 0x0000); + ql_mii_write_reg(qdev, 0x13, 0x0000); } if(qdev->mac_index == 0) @@ -1452,23 +1452,23 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) portConfiguration = PORT_CONFIG_DEFAULT; /* Set the 1000 advertisements */ - ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, ®, + ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, ®, PHYAddr[qdev->mac_index]); reg &= ~PHY_GIG_ALL_PARAMS; - if(portConfiguration & + if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED & PORT_CONFIG_1000MB_SPEED) { reg |= PHY_GIG_ADV_1000F; } - - if(portConfiguration & + + if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED & PORT_CONFIG_1000MB_SPEED) { reg |= PHY_GIG_ADV_1000H; } - ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, + ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, PHYAddr[qdev->mac_index]); /* Set the 10/100 & pause negotiation advertisements */ @@ -1482,7 +1482,7 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) { if(portConfiguration & PORT_CONFIG_100MB_SPEED) reg |= PHY_NEG_ADV_100F; - + if(portConfiguration & PORT_CONFIG_10MB_SPEED) reg |= PHY_NEG_ADV_10F; } @@ -1490,22 +1490,22 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) { if(portConfiguration & PORT_CONFIG_100MB_SPEED) reg |= PHY_NEG_ADV_100H; - + if(portConfiguration & PORT_CONFIG_10MB_SPEED) reg |= PHY_NEG_ADV_10H; } if(portConfiguration & PORT_CONFIG_1000MB_SPEED) { - reg |= 1; + reg |= 1; } - ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, + ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, PHYAddr[qdev->mac_index]); ql_mii_read_reg_ex(qdev, CONTROL_REG, ®, PHYAddr[qdev->mac_index]); - - ql_mii_write_reg_ex(qdev, CONTROL_REG, + + ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG, PHYAddr[qdev->mac_index]); } @@ -1660,7 +1660,7 @@ static void ql_link_state_machine(struct ql3_adapter *qdev) "%s: Reset in progress, skip processing link " "state.\n", qdev->ndev->name); - spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); return; } @@ -1752,7 +1752,7 @@ static int ql_mii_setup(struct ql3_adapter *qdev) return -1; if (qdev->device_id == QL3032_DEVICE_ID) - ql_write_page0_reg(qdev, + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, 0x0f00000); /* Divide 125MHz clock by 28 to meet PHY timing requirements */ @@ -1936,7 +1936,7 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev) err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", qdev->ndev->name, err); dev_kfree_skb(lrg_buf_cb->skb); lrg_buf_cb->skb = NULL; @@ -2044,7 +2044,7 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) { printk(KERN_WARNING "Frame short but, frame was padded and sent.\n"); } - + tx_cb = &qdev->tx_buf[mac_rsp->transaction_id]; /* Check the transmit response flags for any errors */ @@ -2108,13 +2108,13 @@ static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) /* * The difference between 3022 and 3032 for inbound completions: - * 3022 uses two buffers per completion. The first buffer contains - * (some) header info, the second the remainder of the headers plus - * the data. For this chip we reserve some space at the top of the - * receive buffer so that the header info in buffer one can be - * prepended to the buffer two. Buffer two is the sent up while + * 3022 uses two buffers per completion. The first buffer contains + * (some) header info, the second the remainder of the headers plus + * the data. For this chip we reserve some space at the top of the + * receive buffer so that the header info in buffer one can be + * prepended to the buffer two. Buffer two is the sent up while * buffer one is returned to the hardware to be reused. - * 3032 receives all of it's data and headers in one buffer for a + * 3032 receives all of it's data and headers in one buffer for a * simpler process. 3032 also supports checksum verification as * can be seen in ql_process_macip_rx_intr(). */ @@ -2205,13 +2205,13 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, skb_push(skb2, size), size); } else { u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum); - if (checksum & - (IB_IP_IOCB_RSP_3032_ICE | - IB_IP_IOCB_RSP_3032_CE)) { + if (checksum & + (IB_IP_IOCB_RSP_3032_ICE | + IB_IP_IOCB_RSP_3032_CE)) { printk(KERN_ERR "%s: Bad checksum for this %s packet, checksum = %x.\n", __func__, - ((checksum & + ((checksum & IB_IP_IOCB_RSP_3032_TCP) ? "TCP" : "UDP"),checksum); } else if ((checksum & IB_IP_IOCB_RSP_3032_TCP) || @@ -2394,12 +2394,12 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) } /* - * Get the total number of segments needed for the + * Get the total number of segments needed for the * given number of fragments. This is necessary because * outbound address lists (OAL) will be used when more than - * two frags are given. Each address list has 5 addr/len + * two frags are given. Each address list has 5 addr/len * pairs. The 5th pair in each AOL is used to point to - * the next AOL if more frags are coming. + * the next AOL if more frags are coming. * That is why the frags:segment count ratio is not linear. */ static int ql_get_seg_count(struct ql3_adapter *qdev, @@ -2476,12 +2476,12 @@ static int ql_send_map(struct ql3_adapter *qdev, err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", qdev->ndev->name, err); return NETDEV_TX_BUSY; } - + oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); @@ -2511,7 +2511,7 @@ static int ql_send_map(struct ql3_adapter *qdev, err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n", + printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n", qdev->ndev->name, err); goto map_error; } @@ -2537,7 +2537,7 @@ static int ql_send_map(struct ql3_adapter *qdev, err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n", + printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n", qdev->ndev->name, err); goto map_error; } @@ -2558,10 +2558,10 @@ static int ql_send_map(struct ql3_adapter *qdev, map_error: /* A PCI mapping failed and now we will need to back out - * We need to traverse through the oal's and associated pages which + * We need to traverse through the oal's and associated pages which * have been mapped and now we must unmap them to clean up properly */ - + seg = 1; oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; oal = tx_cb->oal; @@ -2599,11 +2599,11 @@ map_error: * The difference between 3022 and 3032 sends: * 3022 only supports a simple single segment transmission. * 3032 supports checksumming and scatter/gather lists (fragments). - * The 3032 supports sglists by using the 3 addr/len pairs (ALP) - * in the IOCB plus a chain of outbound address lists (OAL) that - * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th) - * will used to point to an OAL when more ALP entries are required. - * The IOCB is always the top of the chain followed by one or more + * The 3032 supports sglists by using the 3 addr/len pairs (ALP) + * in the IOCB plus a chain of outbound address lists (OAL) that + * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th) + * will used to point to an OAL when more ALP entries are required. + * 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) @@ -2617,14 +2617,14 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) if (unlikely(atomic_read(&qdev->tx_count) < 2)) { return NETDEV_TX_BUSY; } - + tx_cb = &qdev->tx_buf[qdev->req_producer_index] ; if((tx_cb->seg_count = ql_get_seg_count(qdev, (skb_shinfo(skb)->nr_frags))) == -1) { printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__); return NETDEV_TX_OK; } - + mac_iocb_ptr = tx_cb->queue_entry; memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req)); mac_iocb_ptr->opcode = qdev->mac_ob_opcode; @@ -2636,12 +2636,12 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) if (qdev->device_id == QL3032_DEVICE_ID && skb->ip_summed == CHECKSUM_PARTIAL) ql_hw_csum_setup(skb, mac_iocb_ptr); - + if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) { printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__); return NETDEV_TX_BUSY; } - + wmb(); qdev->req_producer_index++; if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES) @@ -2739,7 +2739,7 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev) "%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name); return -ENOMEM; } - + qdev->lrg_buf_q_alloc_virt_addr = pci_alloc_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size, diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h old mode 100755 new mode 100644 index 483840f7fc10..fbcb0b949639 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -556,7 +556,7 @@ enum { IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007, IP_ADDR_INDEX_REG_6 = 0x0008, IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030, - IP_ADDR_INDEX_REG_E = 0x0040, + IP_ADDR_INDEX_REG_E = 0x0040, }; enum { QL3032_PORT_CONTROL_DS = 0x0001, @@ -1112,7 +1112,7 @@ struct ql_rcv_buf_cb { * OAL has 5 entries: * 1 thru 4 point to frags * fifth points to next oal. - */ + */ #define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1) struct oal_entry { @@ -1137,7 +1137,7 @@ struct ql_tx_buf_cb { struct ob_mac_iocb_req *queue_entry ; int seg_count; struct oal *oal; - struct map_list map[MAX_SKB_FRAGS+1]; + struct map_list map[MAX_SKB_FRAGS+1]; }; /* definitions for type field */ From af289e803fdf2fcd19cf4a57c3c896dba146c756 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 3 Oct 2007 13:03:54 -0500 Subject: [PATCH 1700/2804] pasemi_mac: enable iommu support pasemi_mac: enable iommu support Enable IOMMU support for pasemi_mac, but avoid using it on non-partitioned systems for performance reasons. The user can override this by selecting the PPC_PASEMI_IOMMU_DMA_FORCE configuration option. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- arch/powerpc/platforms/pasemi/Kconfig | 10 ++++++ arch/powerpc/platforms/pasemi/iommu.c | 15 +++++--- drivers/net/pasemi_mac.c | 50 ++++++++++++++++++++------- drivers/net/pasemi_mac.h | 8 +++-- 4 files changed, 63 insertions(+), 20 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index 95cd90fd81c7..e95261ef6f98 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -18,6 +18,16 @@ config PPC_PASEMI_IOMMU help IOMMU support for PA6T-1682M +config PPC_PASEMI_IOMMU_DMA_FORCE + bool "Force DMA engine to use IOMMU" + depends on PPC_PASEMI_IOMMU + help + This option forces the use of the IOMMU also for the + DMA engine. Otherwise the kernel will use it only when + running under a hypervisor. + + If in doubt, say "N". + config PPC_PASEMI_MDIO depends on PHYLIB tristate "MDIO support via GPIO" diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 9014d55c717b..a1111b5c6cb4 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -25,6 +25,7 @@ #include #include #include +#include #define IOBMAP_PAGE_SHIFT 12 @@ -175,13 +176,17 @@ static void pci_dma_dev_setup_pasemi(struct pci_dev *dev) { pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev)); - /* DMA device is untranslated, but all other PCI-e goes through - * the IOMMU +#if !defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE) + /* For non-LPAR environment, don't translate anything for the DMA + * engine. The exception to this is if the user has enabled + * CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE at build time. */ - if (dev->vendor == 0x1959 && dev->device == 0xa007) + if (dev->vendor == 0x1959 && dev->device == 0xa007 && + !firmware_has_feature(FW_FEATURE_LPAR)) dev->dev.archdata.dma_ops = &dma_direct_ops; - else - dev->dev.archdata.dma_data = &iommu_table_iobmap; +#endif + + dev->dev.archdata.dma_data = &iommu_table_iobmap; } static void pci_dma_bus_setup_null(struct pci_bus *b) { } diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 31ad2b9093a7..9f9a421c99b3 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -34,6 +34,7 @@ #include #include +#include #include "pasemi_mac.h" @@ -89,6 +90,15 @@ MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); static struct pasdma_status *dma_status; +static int translation_enabled(void) +{ +#if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE) + return 1; +#else + return firmware_has_feature(FW_FEATURE_LPAR); +#endif +} + static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { @@ -193,6 +203,7 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) struct pasemi_mac_rxring *ring; struct pasemi_mac *mac = netdev_priv(dev); int chan_id = mac->dma_rxch; + unsigned int cfg; ring = kzalloc(sizeof(*ring), GFP_KERNEL); @@ -232,20 +243,28 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3)); - write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), - PAS_DMA_RXCHAN_CFG_HBU(2)); + cfg = PAS_DMA_RXCHAN_CFG_HBU(2); + + if (translation_enabled()) + cfg |= PAS_DMA_RXCHAN_CFG_CTR; + + write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), cfg); write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if), - PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); + PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma)); write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if), - PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | + PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) | PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); - write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), - PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 | - PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP | - PAS_DMA_RXINT_CFG_HEN); + cfg = PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 | + PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP | + PAS_DMA_RXINT_CFG_HEN; + + if (translation_enabled()) + cfg |= PAS_DMA_RXINT_CFG_ITRR | PAS_DMA_RXINT_CFG_ITR; + + write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), cfg); ring->next_to_fill = 0; ring->next_to_clean = 0; @@ -275,6 +294,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) u32 val; int chan_id = mac->dma_txch; struct pasemi_mac_txring *ring; + unsigned int cfg; ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) @@ -304,11 +324,15 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val); - write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), - PAS_DMA_TXCHAN_CFG_TY_IFACE | - PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | - PAS_DMA_TXCHAN_CFG_UP | - PAS_DMA_TXCHAN_CFG_WT(2)); + cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE | + PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | + PAS_DMA_TXCHAN_CFG_UP | + PAS_DMA_TXCHAN_CFG_WT(2); + + if (translation_enabled()) + cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; + + write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), cfg); ring->next_to_fill = 0; ring->next_to_clean = 0; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 1a120408cf3f..60368df72634 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -212,6 +212,7 @@ enum { #define PAS_DMA_RXINT_CFG_DHL_S 24 #define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ PAS_DMA_RXINT_CFG_DHL_M) +#define PAS_DMA_RXINT_CFG_ITR 0x00400000 #define PAS_DMA_RXINT_CFG_LW 0x00200000 #define PAS_DMA_RXINT_CFG_L2 0x00100000 #define PAS_DMA_RXINT_CFG_HEN 0x00080000 @@ -258,9 +259,11 @@ enum { #define PAS_DMA_TXCHAN_CFG_WT_S 6 #define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \ PAS_DMA_TXCHAN_CFG_WT_M) -#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ -#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ +#define PAS_DMA_TXCHAN_CFG_TRD 0x00010000 /* translate data */ +#define PAS_DMA_TXCHAN_CFG_TRR 0x00008000 /* translate rings */ #define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */ +#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ +#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ #define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE) #define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE) #define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0 @@ -294,6 +297,7 @@ enum { #define PAS_DMA_RXCHAN_CCMDSTA_FD 0x00001000 #define PAS_DMA_RXCHAN_CCMDSTA_DT 0x00000800 #define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_CFG_CTR 0x00000400 #define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380 #define PAS_DMA_RXCHAN_CFG_HBU_S 7 #define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \ From bc8498721dfe3f7d537f4f75302be7dbe9c7b939 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:38:49 -0700 Subject: [PATCH 1701/2804] [DCCP]: Wait for CCID This performs a minor optimisation: when ccid_hc_tx_send_packet returns a value greater zero, then the same call previously was done again at the begin of the while loop in dccp_wait_for_ccid. This patch exploits the available information and schedule-timeouts directly instead. Documentation also added. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/output.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/net/dccp/output.c b/net/dccp/output.c index 6a334ed5e9d6..f49544618f20 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -177,34 +177,38 @@ void dccp_write_space(struct sock *sk) /** * dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet - * @sk: socket to wait for + * @sk: socket to wait for + * @skb: current skb to pass on for waiting + * @delay: sleep timeout in milliseconds (> 0) + * This function is called by default when the socket is closed, and + * when a non-zero linger time is set on the socket. For consistency */ -static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb) +static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay) { struct dccp_sock *dp = dccp_sk(sk); DEFINE_WAIT(wait); - unsigned long delay; + unsigned long jiffdelay; int rc; - while (1) { + do { + dccp_pr_debug("delayed send by %d msec\n", delay); + jiffdelay = msecs_to_jiffies(delay); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + sk->sk_write_pending++; + release_sock(sk); + schedule_timeout(jiffdelay); + lock_sock(sk); + sk->sk_write_pending--; + if (sk->sk_err) goto do_error; if (signal_pending(current)) goto do_interrupted; rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); - if (rc <= 0) - break; - dccp_pr_debug("delayed send by %d msec\n", rc); - delay = msecs_to_jiffies(rc); - sk->sk_write_pending++; - release_sock(sk); - schedule_timeout(delay); - lock_sock(sk); - sk->sk_write_pending--; - } + } while ((delay = rc) > 0); out: finish_wait(sk->sk_sleep, &wait); return rc; @@ -231,7 +235,7 @@ void dccp_write_xmit(struct sock *sk, int block) msecs_to_jiffies(err)+jiffies); break; } else - err = dccp_wait_for_ccid(sk, skb); + err = dccp_wait_for_ccid(sk, skb, err); if (err && err != -EINTR) DCCP_BUG("err=%d after dccp_wait_for_ccid", err); } From 7c559a9e44ee61faf2f339604ce708decb345a93 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:39:22 -0700 Subject: [PATCH 1702/2804] [DCCP]: Add socket option to query the current MPS This enables applications to query the current value of the Maximum Packet Size via a socket option, suggested as a SHOULD in (RFC 4340, p. 102). This socket option is useful to avoid the annoying bail-out via `-EMSGSIZE'. In particular, as fragmentation is not currently supported (and its use is partly discouraged in RFC 4340). With this option, it is possible to size buffers accordingly, e.g. int buflen = dccp_get_cur_mps(sockfd); /* or */ if (msgsize > dccp_get_cur_mps(sockfd)) die("message is too large for this path"); Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- Documentation/networking/dccp.txt | 3 +++ include/linux/dccp.h | 1 + net/dccp/proto.c | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 477026ae0ffb..f9157180f7d8 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -41,6 +41,9 @@ the socket will fall back to 0 (which means that no meaningful service code is present). Connecting sockets set at most one service option; for listening sockets, multiple service codes can be specified. +DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet +size (application payload size) in bytes, see RFC 4340, section 14. + DCCP_SOCKOPT_SEND_CSCOV and DCCP_SOCKOPT_RECV_CSCOV are used for setting the partial checksum coverage (RFC 4340, sec. 9.2). The default is that checksums always cover the entire packet and that only fully covered application data is diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 4ed82e2c9f65..0e44a3e5208d 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -202,6 +202,7 @@ struct dccp_so_feat { #define DCCP_SOCKOPT_SERVICE 2 #define DCCP_SOCKOPT_CHANGE_L 3 #define DCCP_SOCKOPT_CHANGE_R 4 +#define DCCP_SOCKOPT_GET_CUR_MPS 5 #define DCCP_SOCKOPT_SEND_CSCOV 10 #define DCCP_SOCKOPT_RECV_CSCOV 11 #define DCCP_SOCKOPT_CCID_RX_INFO 128 diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 7e4f54a4ecaf..c0b685efe245 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -587,6 +587,10 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, case DCCP_SOCKOPT_SERVICE: return dccp_getsockopt_service(sk, len, (__be32 __user *)optval, optlen); + case DCCP_SOCKOPT_GET_CUR_MPS: + val = dp->dccps_mss_cache; + len = sizeof(val); + break; case DCCP_SOCKOPT_SEND_CSCOV: val = dp->dccps_pcslen; len = sizeof(val); From 042d18f9f39a51716683b4e156fbee689314bb22 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:39:53 -0700 Subject: [PATCH 1703/2804] [DCCP]: Make all `debug' parameters bool This just sets the parameter to bool, since debugging messages are either on or off. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 2 +- net/dccp/ccids/ccid3.c | 2 +- net/dccp/proto.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index d29b88fe723c..c199f34c1940 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -835,7 +835,7 @@ static struct ccid_operations ccid2 = { }; #ifdef CONFIG_IP_DCCP_CCID2_DEBUG -module_param(ccid2_debug, int, 0444); +module_param(ccid2_debug, bool, 0444); MODULE_PARM_DESC(ccid2_debug, "Enable debug messages"); #endif diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index a4099398bcc8..25772c326172 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -1046,7 +1046,7 @@ static struct ccid_operations ccid3 = { }; #ifdef CONFIG_IP_DCCP_CCID3_DEBUG -module_param(ccid3_debug, int, 0444); +module_param(ccid3_debug, bool, 0444); MODULE_PARM_DESC(ccid3_debug, "Enable debug messages"); #endif diff --git a/net/dccp/proto.c b/net/dccp/proto.c index c0b685efe245..cc9bf1cb2646 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -992,7 +992,7 @@ MODULE_PARM_DESC(thash_entries, "Number of ehash buckets"); #ifdef CONFIG_IP_DCCP_DEBUG int dccp_debug; -module_param(dccp_debug, int, 0444); +module_param(dccp_debug, bool, 0444); MODULE_PARM_DESC(dccp_debug, "Enable debug messages"); EXPORT_SYMBOL_GPL(dccp_debug); From 126acd5bf769fcb80e38a5360ad12b842d6d29d4 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:40:22 -0700 Subject: [PATCH 1704/2804] [DCCP]: Update API documentation This adds documentation on the use of service codes on client and server. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- Documentation/networking/dccp.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index f9157180f7d8..fc8b4fa0b141 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -38,8 +38,10 @@ Socket options DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of service codes (RFC 4340, sec. 8.1.2); if this socket option is not set, the socket will fall back to 0 (which means that no meaningful service code -is present). Connecting sockets set at most one service option; for -listening sockets, multiple service codes can be specified. +is present). On active sockets this is set before connect(); specifying more +than one code has no effect (all subsequent service codes are ignored). The +case is different for passive sockets, where multiple service codes (up to 32) +can be set before calling bind(). DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet size (application payload size) in bytes, see RFC 4340, section 14. @@ -124,5 +126,5 @@ Notes ===== DCCP does not travel through NAT successfully at present on many boxes. This is -because the checksum covers the psuedo-header as per TCP and UDP. Linux NAT +because the checksum covers the pseudo-header as per TCP and UDP. Linux NAT support for DCCP has been added. From cd1f7d347c9e51f348119811bd41b74346ec57b8 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:41:00 -0700 Subject: [PATCH 1705/2804] [CCID2]: Simplify interface This patch simplifies the interface of ccid2_hc_tx_alloc_seq(): * ccid2_hc_tx_alloc_seq() is always called with an argument of CCID2_SEQBUF_LEN; * other code - ccid2_hc_tx_check_sanity() - even depends on the assumption that ccid2_hc_tx_alloc_seq() has been called with this particular size; * passing the `gfp_t' argument to ccid2_hc_tx_alloc_seq() is redundant with gfp_any(). Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index c199f34c1940..5c6b4f97a664 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -83,8 +83,7 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) #define ccid2_hc_tx_check_sanity(hctx) #endif -static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx, int num, - gfp_t gfp) +static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx) { struct ccid2_seq *seqp; int i; @@ -95,16 +94,16 @@ static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx, int num, return -ENOMEM; /* allocate buffer and initialize linked list */ - seqp = kmalloc(sizeof(*seqp) * num, gfp); + seqp = kmalloc(CCID2_SEQBUF_LEN * sizeof(struct ccid2_seq), gfp_any()); if (seqp == NULL) return -ENOMEM; - for (i = 0; i < (num - 1); i++) { + for (i = 0; i < (CCID2_SEQBUF_LEN - 1); i++) { seqp[i].ccid2s_next = &seqp[i + 1]; seqp[i + 1].ccid2s_prev = &seqp[i]; } - seqp[num - 1].ccid2s_next = seqp; - seqp->ccid2s_prev = &seqp[num - 1]; + seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = seqp; + seqp->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1]; /* This is the first allocation. Initiate the head and tail. */ if (hctx->ccid2hctx_seqbufc == 0) @@ -114,8 +113,8 @@ static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx, int num, hctx->ccid2hctx_seqh->ccid2s_next = seqp; seqp->ccid2s_prev = hctx->ccid2hctx_seqh; - hctx->ccid2hctx_seqt->ccid2s_prev = &seqp[num - 1]; - seqp[num - 1].ccid2s_next = hctx->ccid2hctx_seqt; + hctx->ccid2hctx_seqt->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1]; + seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = hctx->ccid2hctx_seqt; } /* store the original pointer to the buffer so we can free it */ @@ -298,7 +297,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) int rc; ccid2_pr_debug("allocating more space in history\n"); - rc = ccid2_hc_tx_alloc_seq(hctx, CCID2_SEQBUF_LEN, gfp_any()); + rc = ccid2_hc_tx_alloc_seq(hctx); BUG_ON(rc); /* XXX what do we do? */ next = hctx->ccid2hctx_seqh->ccid2s_next; @@ -771,7 +770,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) hctx->ccid2hctx_seqbufc = 0; /* XXX init ~ to window size... */ - if (ccid2_hc_tx_alloc_seq(hctx, CCID2_SEQBUF_LEN, GFP_ATOMIC) != 0) + if (ccid2_hc_tx_alloc_seq(hctx)) return -ENOMEM; hctx->ccid2hctx_sent = 0; From 7d9e8931f93683e575679e41f188d3b465269f08 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:41:26 -0700 Subject: [PATCH 1706/2804] [CCID2]: Remove ugly BUG_ON This removes an ugly BUG_ON which has been pointed out by Arnaldo. Instead of freezing up the machine, a `critical' message is now issued to the system log. There is potential of doing this more gracefully (eg. there are a few internal variables which could be updated despite the lack of memory), but that requires more complicated changes to the algorithm; thus a `FIXME' has been added. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 5c6b4f97a664..3e4fa6b6f251 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -294,12 +294,11 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) next = hctx->ccid2hctx_seqh->ccid2s_next; /* check if we need to alloc more space */ if (next == hctx->ccid2hctx_seqt) { - int rc; - - ccid2_pr_debug("allocating more space in history\n"); - rc = ccid2_hc_tx_alloc_seq(hctx); - BUG_ON(rc); /* XXX what do we do? */ - + if (ccid2_hc_tx_alloc_seq(hctx)) { + DCCP_CRIT("packet history - out of memory!"); + /* FIXME: find a more graceful way to bail out */ + return; + } next = hctx->ccid2hctx_seqh->ccid2s_next; BUG_ON(next == hctx->ccid2hctx_seqt); } From ee196c2186d24d82088c94962598470e5abc081f Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:41:55 -0700 Subject: [PATCH 1707/2804] [CCID2]: Remove redundant BUG_ON This removes a test for `val < 1' which would only have been triggered when val < 0, due to a preceding test for 0. Fixed by using an unsigned type for cwnd (as in TCP) instead. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 11 +++-------- net/dccp/ccids/ccid2.h | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 3e4fa6b6f251..5114a2d30bfd 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -179,16 +179,11 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, int val) dp->dccps_l_ack_ratio = val; } -static void ccid2_change_cwnd(struct ccid2_hc_tx_sock *hctx, int val) +static void ccid2_change_cwnd(struct ccid2_hc_tx_sock *hctx, u32 val) { - if (val == 0) - val = 1; - /* XXX do we need to change ack ratio? */ - ccid2_pr_debug("change cwnd to %d\n", val); - - BUG_ON(val < 1); - hctx->ccid2hctx_cwnd = val; + hctx->ccid2hctx_cwnd = val? : 1; + ccid2_pr_debug("changed cwnd to %u\n", hctx->ccid2hctx_cwnd); } static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hctx, long val) diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h index ebd79499c85a..d9daa534c9be 100644 --- a/net/dccp/ccids/ccid2.h +++ b/net/dccp/ccids/ccid2.h @@ -50,7 +50,7 @@ struct ccid2_seq { * @ccid2hctx_rpdupack - dupacks since rpseq */ struct ccid2_hc_tx_sock { - int ccid2hctx_cwnd; + u32 ccid2hctx_cwnd; int ccid2hctx_ssacks; int ccid2hctx_acks; unsigned int ccid2hctx_ssthresh; From 6c583248083c30c5305ec561e79f666ca465b376 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:42:19 -0700 Subject: [PATCH 1708/2804] [CCID2]: Remove redundant case block skb's passed to ccid2_hc_tx_send_packet() are headerless, the packet type is decided later, in dccp_write_xmit(). Therefore the first test of the switch/case block is always true, the others are never reached. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 5114a2d30bfd..1dff4188f3f5 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -126,19 +126,7 @@ static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx) static int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) { - struct ccid2_hc_tx_sock *hctx; - - switch (DCCP_SKB_CB(skb)->dccpd_type) { - case 0: /* XXX data packets from userland come through like this */ - case DCCP_PKT_DATA: - case DCCP_PKT_DATAACK: - break; - /* No congestion control on other packets */ - default: - return 0; - } - - hctx = ccid2_hc_tx_sk(sk); + struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); ccid2_pr_debug("pipe=%d cwnd=%d\n", hctx->ccid2hctx_pipe, hctx->ccid2hctx_cwnd); From 5e28599a6e45eb8ce7e50510b06c3a34ebf1a8fa Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:43:09 -0700 Subject: [PATCH 1709/2804] [CCID2]: Sequence number wraparound issues This replaces several uses of standard arithmetic with the DCCP sequence number arithmetic functions. The problem here is that the sequence number wrap-around was not taken into consideration. * Condition "seqp->ccid2s_seq <= prev->ccid2s_seq" has been replaced by dccp_delta_seqno(seqp->ccid2s_seq, prev->ccid2s_seq) >= 0 since if seqp is `before' prev, then the delta_seqno() is positive. * The test whether sequence numbers `a' and `b' are consecutive has the form dccp_delta_seqno(a, b) == 1 * Increment of ccid2hctx_rpseq could be done using dccp_inc_seqno(), but since here the incremented ccid2hctx_rpseq == seqno, used assignment instead. Signed-off-by: Gerrit Renker Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 1dff4188f3f5..426008e3b7e3 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -59,7 +59,8 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) pipe++; /* packets are sent sequentially */ - BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq); + BUG_ON(dccp_delta_seqno(seqp->ccid2s_seq, + prev->ccid2s_seq ) >= 0); BUG_ON(time_before(seqp->ccid2s_sent, prev->ccid2s_sent)); @@ -562,8 +563,8 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) hctx->ccid2hctx_rpseq = seqno; } else { /* check if packet is consecutive */ - if ((hctx->ccid2hctx_rpseq + 1) == seqno) - hctx->ccid2hctx_rpseq++; + if (dccp_delta_seqno(hctx->ccid2hctx_rpseq, seqno) == 1) + hctx->ccid2hctx_rpseq = seqno; /* it's a later packet */ else if (after48(seqno, hctx->ccid2hctx_rpseq)) { hctx->ccid2hctx_rpdupack++; From 451bc0473f010babeadd888ae8ec1015959fd1b2 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:43:42 -0700 Subject: [PATCH 1710/2804] [DCCP]: Tidy-up -- minisock initialisation This * removes a declaration of a non-existent function __dccp_minisock_init; * shifts the initialisation function dccp_minisock_init() from options.c to minisocks.c, where it is more naturally expected to be. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/linux/dccp.h | 1 - net/dccp/minisocks.c | 10 ++++++++++ net/dccp/options.c | 10 ---------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 0e44a3e5208d..f3fc4392e93d 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -391,7 +391,6 @@ struct dccp_opt_pend { struct dccp_opt_conf *dccpop_sc; }; -extern void __dccp_minisock_init(struct dccp_minisock *dmsk); extern void dccp_minisock_init(struct dccp_minisock *dmsk); extern int dccp_parse_options(struct sock *sk, struct sk_buff *skb); diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 91685990d57e..831b76e08d02 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -42,6 +42,16 @@ struct inet_timewait_death_row dccp_death_row = { EXPORT_SYMBOL_GPL(dccp_death_row); +void dccp_minisock_init(struct dccp_minisock *dmsk) +{ + dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window; + dmsk->dccpms_rx_ccid = sysctl_dccp_feat_rx_ccid; + dmsk->dccpms_tx_ccid = sysctl_dccp_feat_tx_ccid; + dmsk->dccpms_ack_ratio = sysctl_dccp_feat_ack_ratio; + dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector; + dmsk->dccpms_send_ndp_count = sysctl_dccp_feat_send_ndp_count; +} + void dccp_time_wait(struct sock *sk, int state, int timeo) { struct inet_timewait_sock *tw = NULL; diff --git a/net/dccp/options.c b/net/dccp/options.c index a57fcbd7d03c..172eb6ba8702 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -29,16 +29,6 @@ int sysctl_dccp_feat_ack_ratio = DCCPF_INITIAL_ACK_RATIO; int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR; int sysctl_dccp_feat_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT; -void dccp_minisock_init(struct dccp_minisock *dmsk) -{ - dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window; - dmsk->dccpms_rx_ccid = sysctl_dccp_feat_rx_ccid; - dmsk->dccpms_tx_ccid = sysctl_dccp_feat_tx_ccid; - dmsk->dccpms_ack_ratio = sysctl_dccp_feat_ack_ratio; - dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector; - dmsk->dccpms_send_ndp_count = sysctl_dccp_feat_send_ndp_count; -} - static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) { u32 value = 0; From dcad856fe8e0222012d9ae0e4dc6c6e5cce276e6 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:44:01 -0700 Subject: [PATCH 1711/2804] [DCCP]: Wrong format in printk The elapsed time uses u32, but printk was using %d, not %u. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dccp/options.c b/net/dccp/options.c index 172eb6ba8702..d361b5533309 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -179,7 +179,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) else elapsed_time = ntohl(*(__be32 *)(value + 4)); - dccp_pr_debug_cat(", ELAPSED_TIME=%d\n", elapsed_time); + dccp_pr_debug_cat(", ELAPSED_TIME=%u\n", elapsed_time); /* Give precedence to the biggest ELAPSED_TIME */ if (elapsed_time > opt_recv->dccpor_elapsed_time) From 2bfd754d1bf29d3324270e52ef11ce6367bb0685 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:50:57 -0700 Subject: [PATCH 1712/2804] [DCCP]: Correct documentation This corrects erroneous documentation of the socket API. Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- Documentation/networking/dccp.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index fc8b4fa0b141..afb66f9a8aff 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -55,12 +55,13 @@ be enabled at the receiver, too with suitable choice of CsCov. DCCP_SOCKOPT_SEND_CSCOV sets the sender checksum coverage. Values in the range 0..15 are acceptable. The default setting is 0 (full coverage), values between 1..15 indicate partial coverage. -DCCP_SOCKOPT_SEND_CSCOV is for the receiver and has a different meaning: it +DCCP_SOCKOPT_RECV_CSCOV is for the receiver and has a different meaning: it sets a threshold, where again values 0..15 are acceptable. The default of 0 means that all packets with a partial coverage will be discarded. Values in the range 1..15 indicate that packets with minimally such a coverage value are also acceptable. The higher the number, the more - restrictive this setting (see [RFC 4340, sec. 9.2.1]). + restrictive this setting (see [RFC 4340, sec. 9.2.1]). Partial coverage + settings are inherited to the child socket after accept(). The following two options apply to CCID 3 exclusively and are getsockopt()-only. In either case, a TFRC info struct (defined in ) is returned. From 4a5409a5a850c84505d658ddf36f98b2c542ec07 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Oct 2007 14:52:28 -0700 Subject: [PATCH 1713/2804] [DCCP]: Twice the wrong reset code in receiving connection-Requests This fixes two bugs in processing of connection-Requests in v{4,6}_conn_request: 1. Due to using the variable `reset_code', the Reset code generated internally by dccp_parse_options() is overwritten with the initialised value ("Too Busy") of reset_code, which is not what is intended. 2. When receiving a connection-Request on a multicast or broadcast address, no Reset should be generated, to avoid storms of such packets. Instead of jumping to the `drop' label, the v{4,6}_conn_request functions now return 0. Below is why in my understanding this is correct: When the conn_request function returns < 0, then the caller, dccp_rcv_state_process(), returns 1. In all instances where dccp_rcv_state_process is called (dccp_v4_do_rcv, dccp_v6_do_rcv, and dccp_child_process), a return value of != 0 from dccp_rcv_state_process() means that a Reset is generated. If on the other hand the conn_request function returns 0, the packet is discarded and no Reset is generated. Note: There may be a related problem when sending the Response, due to the following. if (dccp_v6_send_response(sk, req, NULL)) goto drop_and_free; /* ... */ drop_and_free: return -1; In this case, if send_response fails due to transmission errors, the next thing that is generated is a Reset with a code "Too Busy". I haven't been able to conjure up such a condition, but it might be good to change the behaviour here also (not done by this patch). Signed-off-by: Gerrit Renker Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 11 ++++------- net/dccp/ipv6.c | 7 +++---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2312b9f4d7af..44f6e17e105f 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -568,17 +568,14 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) struct dccp_request_sock *dreq; const __be32 service = dccp_hdr_request(skb)->dccph_req_service; struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); - __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ if (((struct rtable *)skb->dst)->rt_flags & - (RTCF_BROADCAST | RTCF_MULTICAST)) { - reset_code = DCCP_RESET_CODE_NO_CONNECTION; - goto drop; - } + (RTCF_BROADCAST | RTCF_MULTICAST)) + return 0; /* discard, don't send a reset here */ if (dccp_bad_service_code(sk, service)) { - reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; + dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; goto drop; } /* @@ -586,6 +583,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) * limitations, they conserve resources and peer is * evidently real one. */ + dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; if (inet_csk_reqsk_queue_is_full(sk)) goto drop; @@ -638,7 +636,6 @@ drop_and_free: reqsk_free(req); drop: DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); - dcb->dccpd_reset_code = reset_code; return -1; } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index b7c0f66e2834..006a3834fbcd 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -390,21 +390,21 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) struct ipv6_pinfo *np = inet6_sk(sk); const __be32 service = dccp_hdr_request(skb)->dccph_req_service; struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); - __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; if (skb->protocol == htons(ETH_P_IP)) return dccp_v4_conn_request(sk, skb); if (!ipv6_unicast_destination(skb)) - goto drop; + return 0; /* discard, don't send a reset here */ if (dccp_bad_service_code(sk, service)) { - reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; + dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; goto drop; } /* * There are no SYN attacks on IPv6, yet... */ + dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; if (inet_csk_reqsk_queue_is_full(sk)) goto drop; @@ -464,7 +464,6 @@ drop_and_free: reqsk_free(req); drop: DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); - dcb->dccpd_reset_code = reset_code; return -1; } From a3138df9f20e726c517f8df7387b5d83f5df5566 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Oct 2007 01:54:01 -0700 Subject: [PATCH 1714/2804] [NIU]: Add Sun Neptune ethernet driver. With cleanup suggestions and bugs spotted by Stephen Hemminger, Ingo Oeser, Matheos Worku, and Oliver Hartkopp. Signed-off-by: David S. Miller --- drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/niu.c | 7939 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/niu.h | 3222 +++++++++++++++++ 4 files changed, 11169 insertions(+) create mode 100644 drivers/net/niu.c create mode 100644 drivers/net/niu.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0e48b294200e..9c635a237a9d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2594,6 +2594,13 @@ config NETXEN_NIC help This enables the support for NetXen's Gigabit Ethernet card. +config NIU + tristate "Sun Neptune 10Gbit Ethernet support" + depends on PCI + help + This enables support for cards based upon Sun's + Neptune chipset. + config PASEMI_MAC tristate "PA Semi 1/10Gbit MAC" depends on PPC64 && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index eb5c655e26d5..d2e0f35da42e 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -241,3 +241,4 @@ obj-$(CONFIG_NETCONSOLE) += netconsole.o obj-$(CONFIG_FS_ENET) += fs_enet/ obj-$(CONFIG_NETXEN_NIC) += netxen/ +obj-$(CONFIG_NIU) += niu.o diff --git a/drivers/net/niu.c b/drivers/net/niu.c new file mode 100644 index 000000000000..43bfe7e6b6f5 --- /dev/null +++ b/drivers/net/niu.c @@ -0,0 +1,7939 @@ +/* niu.c: Neptune ethernet driver. + * + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_SPARC64 +#include +#endif + +#include "niu.h" + +#define DRV_MODULE_NAME "niu" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "0.5" +#define DRV_MODULE_RELDATE "October 5, 2007" + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_DESCRIPTION("NIU ethernet driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +#ifndef DMA_44BIT_MASK +#define DMA_44BIT_MASK 0x00000fffffffffffULL +#endif + +#ifndef readq +static u64 readq(void __iomem *reg) +{ + return (((u64)readl(reg + 0x4UL) << 32) | + (u64)readl(reg)); +} + +static void writeq(u64 val, void __iomem *reg) +{ + writel(val & 0xffffffff, reg); + writel(val >> 32, reg + 0x4UL); +} +#endif + +static struct pci_device_id niu_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)}, + {} +}; + +MODULE_DEVICE_TABLE(pci, niu_pci_tbl); + +#define NIU_TX_TIMEOUT (5 * HZ) + +#define nr64(reg) readq(np->regs + (reg)) +#define nw64(reg, val) writeq((val), np->regs + (reg)) + +#define nr64_mac(reg) readq(np->mac_regs + (reg)) +#define nw64_mac(reg, val) writeq((val), np->mac_regs + (reg)) + +#define nr64_ipp(reg) readq(np->regs + np->ipp_off + (reg)) +#define nw64_ipp(reg, val) writeq((val), np->regs + np->ipp_off + (reg)) + +#define nr64_pcs(reg) readq(np->regs + np->pcs_off + (reg)) +#define nw64_pcs(reg, val) writeq((val), np->regs + np->pcs_off + (reg)) + +#define nr64_xpcs(reg) readq(np->regs + np->xpcs_off + (reg)) +#define nw64_xpcs(reg, val) writeq((val), np->regs + np->xpcs_off + (reg)) + +#define NIU_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) + +static int niu_debug; +static int debug = -1; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "NIU debug level"); + +#define niudbg(TYPE, f, a...) \ +do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_DEBUG PFX f, ## a); \ +} while (0) + +#define niuinfo(TYPE, f, a...) \ +do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_INFO PFX f, ## a); \ +} while (0) + +#define niuwarn(TYPE, f, a...) \ +do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_WARNING PFX f, ## a); \ +} while (0) + +#define niu_lock_parent(np, flags) \ + spin_lock_irqsave(&np->parent->lock, flags) +#define niu_unlock_parent(np, flags) \ + spin_unlock_irqrestore(&np->parent->lock, flags) + +static int __niu_wait_bits_clear_mac(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay) +{ + while (--limit >= 0) { + u64 val = nr64_mac(reg); + + if (!(val & bits)) + break; + udelay(delay); + } + if (limit < 0) + return -ENODEV; + return 0; +} + +static int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay, + const char *reg_name) +{ + int err; + + nw64_mac(reg, bits); + err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay); + if (err) + dev_err(np->device, PFX "%s: bits (%llx) of register %s " + "would not clear, val[%llx]\n", + np->dev->name, (unsigned long long) bits, reg_name, + (unsigned long long) nr64_mac(reg)); + return err; +} + +#define niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \ +({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \ + __niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \ +}) + +static int __niu_wait_bits_clear_ipp(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay) +{ + while (--limit >= 0) { + u64 val = nr64_ipp(reg); + + if (!(val & bits)) + break; + udelay(delay); + } + if (limit < 0) + return -ENODEV; + return 0; +} + +static int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay, + const char *reg_name) +{ + int err; + u64 val; + + val = nr64_ipp(reg); + val |= bits; + nw64_ipp(reg, val); + + err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay); + if (err) + dev_err(np->device, PFX "%s: bits (%llx) of register %s " + "would not clear, val[%llx]\n", + np->dev->name, (unsigned long long) bits, reg_name, + (unsigned long long) nr64_ipp(reg)); + return err; +} + +#define niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \ +({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \ + __niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \ +}) + +static int __niu_wait_bits_clear(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay) +{ + while (--limit >= 0) { + u64 val = nr64(reg); + + if (!(val & bits)) + break; + udelay(delay); + } + if (limit < 0) + return -ENODEV; + return 0; +} + +#define niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY) \ +({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \ + __niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY); \ +}) + +static int __niu_set_and_wait_clear(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay, + const char *reg_name) +{ + int err; + + nw64(reg, bits); + err = __niu_wait_bits_clear(np, reg, bits, limit, delay); + if (err) + dev_err(np->device, PFX "%s: bits (%llx) of register %s " + "would not clear, val[%llx]\n", + np->dev->name, (unsigned long long) bits, reg_name, + (unsigned long long) nr64(reg)); + return err; +} + +#define niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \ +({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \ + __niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \ +}) + +static void niu_ldg_rearm(struct niu *np, struct niu_ldg *lp, int on) +{ + u64 val = (u64) lp->timer; + + if (on) + val |= LDG_IMGMT_ARM; + + nw64(LDG_IMGMT(lp->ldg_num), val); +} + +static int niu_ldn_irq_enable(struct niu *np, int ldn, int on) +{ + unsigned long mask_reg, bits; + u64 val; + + if (ldn < 0 || ldn > LDN_MAX) + return -EINVAL; + + if (ldn < 64) { + mask_reg = LD_IM0(ldn); + bits = LD_IM0_MASK; + } else { + mask_reg = LD_IM1(ldn - 64); + bits = LD_IM1_MASK; + } + + val = nr64(mask_reg); + if (on) + val &= ~bits; + else + val |= bits; + nw64(mask_reg, val); + + return 0; +} + +static int niu_enable_ldn_in_ldg(struct niu *np, struct niu_ldg *lp, int on) +{ + struct niu_parent *parent = np->parent; + int i; + + for (i = 0; i <= LDN_MAX; i++) { + int err; + + if (parent->ldg_map[i] != lp->ldg_num) + continue; + + err = niu_ldn_irq_enable(np, i, on); + if (err) + return err; + } + return 0; +} + +static int niu_enable_interrupts(struct niu *np, int on) +{ + int i; + + for (i = 0; i < np->num_ldg; i++) { + struct niu_ldg *lp = &np->ldg[i]; + int err; + + err = niu_enable_ldn_in_ldg(np, lp, on); + if (err) + return err; + } + for (i = 0; i < np->num_ldg; i++) + niu_ldg_rearm(np, &np->ldg[i], on); + + return 0; +} + +static u32 phy_encode(u32 type, int port) +{ + return (type << (port * 2)); +} + +static u32 phy_decode(u32 val, int port) +{ + return (val >> (port * 2)) & PORT_TYPE_MASK; +} + +static int mdio_wait(struct niu *np) +{ + int limit = 1000; + u64 val; + + while (--limit > 0) { + val = nr64(MIF_FRAME_OUTPUT); + if ((val >> MIF_FRAME_OUTPUT_TA_SHIFT) & 0x1) + return val & MIF_FRAME_OUTPUT_DATA; + + udelay(10); + } + + return -ENODEV; +} + +static int mdio_read(struct niu *np, int port, int dev, int reg) +{ + int err; + + nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg)); + err = mdio_wait(np); + if (err < 0) + return err; + + nw64(MIF_FRAME_OUTPUT, MDIO_READ_OP(port, dev)); + return mdio_wait(np); +} + +static int mdio_write(struct niu *np, int port, int dev, int reg, int data) +{ + int err; + + nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg)); + err = mdio_wait(np); + if (err < 0) + return err; + + nw64(MIF_FRAME_OUTPUT, MDIO_WRITE_OP(port, dev, data)); + err = mdio_wait(np); + if (err < 0) + return err; + + return 0; +} + +static int mii_read(struct niu *np, int port, int reg) +{ + nw64(MIF_FRAME_OUTPUT, MII_READ_OP(port, reg)); + return mdio_wait(np); +} + +static int mii_write(struct niu *np, int port, int reg, int data) +{ + int err; + + nw64(MIF_FRAME_OUTPUT, MII_WRITE_OP(port, reg, data)); + err = mdio_wait(np); + if (err < 0) + return err; + + return 0; +} + +static int esr2_set_tx_cfg(struct niu *np, unsigned long channel, u32 val) +{ + int err; + + err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_TX_CFG_L(channel), + val & 0xffff); + if (!err) + err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_TX_CFG_H(channel), + val >> 16); + return err; +} + +static int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val) +{ + int err; + + err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_RX_CFG_L(channel), + val & 0xffff); + if (!err) + err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_RX_CFG_H(channel), + val >> 16); + return err; +} + +/* Mode is always 10G fiber. */ +static int serdes_init_niu(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u32 tx_cfg, rx_cfg; + unsigned long i; + + tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV); + rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT | + PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH | + PLL_RX_CFG_EQ_LP_ADAPTIVE); + + if (lp->loopback_mode == LOOPBACK_PHY) { + u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS; + + mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_TEST_CFG_L, test_cfg); + + tx_cfg |= PLL_TX_CFG_ENTEST; + rx_cfg |= PLL_RX_CFG_ENTEST; + } + + /* Initialize all 4 lanes of the SERDES. */ + for (i = 0; i < 4; i++) { + int err = esr2_set_tx_cfg(np, i, tx_cfg); + if (err) + return err; + } + + for (i = 0; i < 4; i++) { + int err = esr2_set_rx_cfg(np, i, rx_cfg); + if (err) + return err; + } + + return 0; +} + +static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val) +{ + int err; + + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, ESR_RXTX_CTRL_L(chan)); + if (err >= 0) { + *val = (err & 0xffff); + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_CTRL_H(chan)); + if (err >= 0) + *val |= ((err & 0xffff) << 16); + err = 0; + } + return err; +} + +static int esr_read_glue0(struct niu *np, unsigned long chan, u32 *val) +{ + int err; + + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_GLUE_CTRL0_L(chan)); + if (err >= 0) { + *val = (err & 0xffff); + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_GLUE_CTRL0_H(chan)); + if (err >= 0) { + *val |= ((err & 0xffff) << 16); + err = 0; + } + } + return err; +} + +static int esr_read_reset(struct niu *np, u32 *val) +{ + int err; + + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_L); + if (err >= 0) { + *val = (err & 0xffff); + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_H); + if (err >= 0) { + *val |= ((err & 0xffff) << 16); + err = 0; + } + } + return err; +} + +static int esr_write_rxtx_ctrl(struct niu *np, unsigned long chan, u32 val) +{ + int err; + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_CTRL_L(chan), val & 0xffff); + if (!err) + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_CTRL_H(chan), (val >> 16)); + return err; +} + +static int esr_write_glue0(struct niu *np, unsigned long chan, u32 val) +{ + int err; + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_GLUE_CTRL0_L(chan), val & 0xffff); + if (!err) + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_GLUE_CTRL0_H(chan), (val >> 16)); + return err; +} + +static int esr_reset(struct niu *np) +{ + u32 reset; + int err; + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_L, 0x0000); + if (err) + return err; + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_H, 0xffff); + if (err) + return err; + udelay(200); + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_L, 0xffff); + if (err) + return err; + udelay(200); + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_H, 0x0000); + if (err) + return err; + udelay(200); + + err = esr_read_reset(np, &reset); + if (err) + return err; + if (reset != 0) { + dev_err(np->device, PFX "Port %u ESR_RESET " + "did not clear [%08x]\n", + np->port, reset); + return -ENODEV; + } + + return 0; +} + +static int serdes_init_10g(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + unsigned long ctrl_reg, test_cfg_reg, i; + u64 ctrl_val, test_cfg_val, sig, mask, val; + int err; + + switch (np->port) { + case 0: + ctrl_reg = ENET_SERDES_0_CTRL_CFG; + test_cfg_reg = ENET_SERDES_0_TEST_CFG; + break; + case 1: + ctrl_reg = ENET_SERDES_1_CTRL_CFG; + test_cfg_reg = ENET_SERDES_1_TEST_CFG; + break; + + default: + return -EINVAL; + } + ctrl_val = (ENET_SERDES_CTRL_SDET_0 | + ENET_SERDES_CTRL_SDET_1 | + ENET_SERDES_CTRL_SDET_2 | + ENET_SERDES_CTRL_SDET_3 | + (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) | + (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) | + (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) | + (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) | + (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) | + (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) | + (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) | + (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT)); + test_cfg_val = 0; + + if (lp->loopback_mode == LOOPBACK_PHY) { + test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK << + ENET_SERDES_TEST_MD_0_SHIFT) | + (ENET_TEST_MD_PAD_LOOPBACK << + ENET_SERDES_TEST_MD_1_SHIFT) | + (ENET_TEST_MD_PAD_LOOPBACK << + ENET_SERDES_TEST_MD_2_SHIFT) | + (ENET_TEST_MD_PAD_LOOPBACK << + ENET_SERDES_TEST_MD_3_SHIFT)); + } + + nw64(ctrl_reg, ctrl_val); + nw64(test_cfg_reg, test_cfg_val); + + /* Initialize all 4 lanes of the SERDES. */ + for (i = 0; i < 4; i++) { + u32 rxtx_ctrl, glue0; + + err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl); + if (err) + return err; + err = esr_read_glue0(np, i, &glue0); + if (err) + return err; + + rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO); + rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH | + (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT)); + + glue0 &= ~(ESR_GLUE_CTRL0_SRATE | + ESR_GLUE_CTRL0_THCNT | + ESR_GLUE_CTRL0_BLTIME); + glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB | + (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) | + (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) | + (BLTIME_300_CYCLES << + ESR_GLUE_CTRL0_BLTIME_SHIFT)); + + err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl); + if (err) + return err; + err = esr_write_glue0(np, i, glue0); + if (err) + return err; + } + + err = esr_reset(np); + if (err) + return err; + + sig = nr64(ESR_INT_SIGNALS); + switch (np->port) { + case 0: + mask = ESR_INT_SIGNALS_P0_BITS; + val = (ESR_INT_SRDY0_P0 | + ESR_INT_DET0_P0 | + ESR_INT_XSRDY_P0 | + ESR_INT_XDP_P0_CH3 | + ESR_INT_XDP_P0_CH2 | + ESR_INT_XDP_P0_CH1 | + ESR_INT_XDP_P0_CH0); + break; + + case 1: + mask = ESR_INT_SIGNALS_P1_BITS; + val = (ESR_INT_SRDY0_P1 | + ESR_INT_DET0_P1 | + ESR_INT_XSRDY_P1 | + ESR_INT_XDP_P1_CH3 | + ESR_INT_XDP_P1_CH2 | + ESR_INT_XDP_P1_CH1 | + ESR_INT_XDP_P1_CH0); + break; + + default: + return -EINVAL; + } + + if ((sig & mask) != val) { + dev_err(np->device, PFX "Port %u signal bits [%08x] are not " + "[%08x]\n", np->port, (int) (sig & mask), (int) val); + return -ENODEV; + } + + return 0; +} + +static int serdes_init_1g(struct niu *np) +{ + u64 val; + + val = nr64(ENET_SERDES_1_PLL_CFG); + val &= ~ENET_SERDES_PLL_FBDIV2; + switch (np->port) { + case 0: + val |= ENET_SERDES_PLL_HRATE0; + break; + case 1: + val |= ENET_SERDES_PLL_HRATE1; + break; + case 2: + val |= ENET_SERDES_PLL_HRATE2; + break; + case 3: + val |= ENET_SERDES_PLL_HRATE3; + break; + default: + return -EINVAL; + } + nw64(ENET_SERDES_1_PLL_CFG, val); + + return 0; +} + +static int bcm8704_reset(struct niu *np) +{ + int err, limit; + + err = mdio_read(np, np->phy_addr, + BCM8704_PHYXS_DEV_ADDR, MII_BMCR); + if (err < 0) + return err; + err |= BMCR_RESET; + err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, + MII_BMCR, err); + if (err) + return err; + + limit = 1000; + while (--limit >= 0) { + err = mdio_read(np, np->phy_addr, + BCM8704_PHYXS_DEV_ADDR, MII_BMCR); + if (err < 0) + return err; + if (!(err & BMCR_RESET)) + break; + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u PHY will not reset " + "(bmcr=%04x)\n", np->port, (err & 0xffff)); + return -ENODEV; + } + return 0; +} + +/* When written, certain PHY registers need to be read back twice + * in order for the bits to settle properly. + */ +static int bcm8704_user_dev3_readback(struct niu *np, int reg) +{ + int err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg); + if (err < 0) + return err; + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg); + if (err < 0) + return err; + return 0; +} + +static int bcm8704_init_user_dev3(struct niu *np) +{ + int err; + + err = mdio_write(np, np->phy_addr, + BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL, + (USER_CONTROL_OPTXRST_LVL | + USER_CONTROL_OPBIASFLT_LVL | + USER_CONTROL_OBTMPFLT_LVL | + USER_CONTROL_OPPRFLT_LVL | + USER_CONTROL_OPTXFLT_LVL | + USER_CONTROL_OPRXLOS_LVL | + USER_CONTROL_OPRXFLT_LVL | + USER_CONTROL_OPTXON_LVL | + (0x3f << USER_CONTROL_RES1_SHIFT))); + if (err) + return err; + + err = mdio_write(np, np->phy_addr, + BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL, + (USER_PMD_TX_CTL_XFP_CLKEN | + (1 << USER_PMD_TX_CTL_TX_DAC_TXD_SH) | + (2 << USER_PMD_TX_CTL_TX_DAC_TXCK_SH) | + USER_PMD_TX_CTL_TSCK_LPWREN)); + if (err) + return err; + + err = bcm8704_user_dev3_readback(np, BCM8704_USER_CONTROL); + if (err) + return err; + err = bcm8704_user_dev3_readback(np, BCM8704_USER_PMD_TX_CONTROL); + if (err) + return err; + + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_OPT_DIGITAL_CTRL); + if (err < 0) + return err; + err &= ~USER_ODIG_CTRL_GPIOS; + err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT); + err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_OPT_DIGITAL_CTRL, err); + if (err) + return err; + + mdelay(1000); + + return 0; +} + +static int xcvr_init_10g(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u16 analog_stat0, tx_alarm_status; + int err; + u64 val; + + val = nr64_mac(XMAC_CONFIG); + val &= ~XMAC_CONFIG_LED_POLARITY; + val |= XMAC_CONFIG_FORCE_LED_ON; + nw64_mac(XMAC_CONFIG, val); + + /* XXX shared resource, lock parent XXX */ + val = nr64(MIF_CONFIG); + val |= MIF_CONFIG_INDIRECT_MODE; + nw64(MIF_CONFIG, val); + + err = bcm8704_reset(np); + if (err) + return err; + + err = bcm8704_init_user_dev3(np); + if (err) + return err; + + err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, + MII_BMCR); + if (err < 0) + return err; + err &= ~BMCR_LOOPBACK; + + if (lp->loopback_mode == LOOPBACK_MAC) + err |= BMCR_LOOPBACK; + + err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, + MII_BMCR, err); + if (err) + return err; + +#if 1 + err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, + MII_STAT1000); + if (err < 0) + return err; + pr_info(PFX "Port %u PMA_PMD(MII_STAT1000) [%04x]\n", + np->port, err); + + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20); + if (err < 0) + return err; + pr_info(PFX "Port %u USER_DEV3(0x20) [%04x]\n", + np->port, err); + + err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, + MII_NWAYTEST); + if (err < 0) + return err; + pr_info(PFX "Port %u PHYXS(MII_NWAYTEST) [%04x]\n", + np->port, err); +#endif + + /* XXX dig this out it might not be so useful XXX */ + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_ANALOG_STATUS0); + if (err < 0) + return err; + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_ANALOG_STATUS0); + if (err < 0) + return err; + analog_stat0 = err; + + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_TX_ALARM_STATUS); + if (err < 0) + return err; + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_TX_ALARM_STATUS); + if (err < 0) + return err; + tx_alarm_status = err; + + if (analog_stat0 != 0x03fc) { + if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) { + pr_info(PFX "Port %u cable not connected " + "or bad cable.\n", np->port); + } else if (analog_stat0 == 0x639c) { + pr_info(PFX "Port %u optical module is bad " + "or missing.\n", np->port); + } + } + + return 0; +} + +static int mii_reset(struct niu *np) +{ + int limit, err; + + err = mii_write(np, np->phy_addr, MII_BMCR, BMCR_RESET); + if (err) + return err; + + limit = 1000; + while (--limit >= 0) { + udelay(500); + err = mii_read(np, np->phy_addr, MII_BMCR); + if (err < 0) + return err; + if (!(err & BMCR_RESET)) + break; + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u MII would not reset, " + "bmcr[%04x]\n", np->port, err); + return -ENODEV; + } + + return 0; +} + +static int mii_init_common(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u16 bmcr, bmsr, adv, estat; + int err; + + err = mii_reset(np); + if (err) + return err; + + err = mii_read(np, np->phy_addr, MII_BMSR); + if (err < 0) + return err; + bmsr = err; + + estat = 0; + if (bmsr & BMSR_ESTATEN) { + err = mii_read(np, np->phy_addr, MII_ESTATUS); + if (err < 0) + return err; + estat = err; + } + + bmcr = 0; + err = mii_write(np, np->phy_addr, MII_BMCR, bmcr); + if (err) + return err; + + if (lp->loopback_mode == LOOPBACK_MAC) { + bmcr |= BMCR_LOOPBACK; + if (lp->active_speed == SPEED_1000) + bmcr |= BMCR_SPEED1000; + if (lp->active_duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + } + + if (lp->loopback_mode == LOOPBACK_PHY) { + u16 aux; + + aux = (BCM5464R_AUX_CTL_EXT_LB | + BCM5464R_AUX_CTL_WRITE_1); + err = mii_write(np, np->phy_addr, BCM5464R_AUX_CTL, aux); + if (err) + return err; + } + + /* XXX configurable XXX */ + /* XXX for now don't advertise half-duplex or asym pause... XXX */ + adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; + if (bmsr & BMSR_10FULL) + adv |= ADVERTISE_10FULL; + if (bmsr & BMSR_100FULL) + adv |= ADVERTISE_100FULL; + err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv); + if (err) + return err; + + if (bmsr & BMSR_ESTATEN) { + u16 ctrl1000 = 0; + + if (estat & ESTATUS_1000_TFULL) + ctrl1000 |= ADVERTISE_1000FULL; + err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000); + if (err) + return err; + } + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + + err = mii_write(np, np->phy_addr, MII_BMCR, bmcr); + if (err) + return err; + + err = mii_read(np, np->phy_addr, MII_BMCR); + if (err < 0) + return err; + err = mii_read(np, np->phy_addr, MII_BMSR); + if (err < 0) + return err; +#if 0 + pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n", + np->port, bmcr, bmsr); +#endif + + return 0; +} + +static int xcvr_init_1g(struct niu *np) +{ + u64 val; + + /* XXX shared resource, lock parent XXX */ + val = nr64(MIF_CONFIG); + val &= ~MIF_CONFIG_INDIRECT_MODE; + nw64(MIF_CONFIG, val); + + return mii_init_common(np); +} + +static int niu_xcvr_init(struct niu *np) +{ + const struct niu_phy_ops *ops = np->phy_ops; + int err; + + err = 0; + if (ops->xcvr_init) + err = ops->xcvr_init(np); + + return err; +} + +static int niu_serdes_init(struct niu *np) +{ + const struct niu_phy_ops *ops = np->phy_ops; + int err; + + err = 0; + if (ops->serdes_init) + err = ops->serdes_init(np); + + return err; +} + +static void niu_init_xif(struct niu *); + +static int niu_link_status_common(struct niu *np, int link_up) +{ + struct niu_link_config *lp = &np->link_config; + struct net_device *dev = np->dev; + unsigned long flags; + + if (!netif_carrier_ok(dev) && link_up) { + niuinfo(LINK, "%s: Link is up at %s, %s duplex\n", + dev->name, + (lp->active_speed == SPEED_10000 ? + "10Gb/sec" : + (lp->active_speed == SPEED_1000 ? + "1Gb/sec" : + (lp->active_speed == SPEED_100 ? + "100Mbit/sec" : "10Mbit/sec"))), + (lp->active_duplex == DUPLEX_FULL ? + "full" : "half")); + + spin_lock_irqsave(&np->lock, flags); + niu_init_xif(np); + spin_unlock_irqrestore(&np->lock, flags); + + netif_carrier_on(dev); + } else if (netif_carrier_ok(dev) && !link_up) { + niuwarn(LINK, "%s: Link is down\n", dev->name); + netif_carrier_off(dev); + } + + return 0; +} + +static int link_status_10g(struct niu *np, int *link_up_p) +{ + unsigned long flags; + int err, link_up; + + link_up = 0; + + spin_lock_irqsave(&np->lock, flags); + + err = -EINVAL; + if (np->link_config.loopback_mode != LOOPBACK_DISABLED) + goto out; + + err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, + BCM8704_PMD_RCV_SIGDET); + if (err < 0) + goto out; + if (!(err & PMD_RCV_SIGDET_GLOBAL)) { + err = 0; + goto out; + } + + err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, + BCM8704_PCS_10G_R_STATUS); + if (err < 0) + goto out; + if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) { + err = 0; + goto out; + } + + err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, + BCM8704_PHYXS_XGXS_LANE_STAT); + if (err < 0) + goto out; + + if (err != (PHYXS_XGXS_LANE_STAT_ALINGED | + PHYXS_XGXS_LANE_STAT_MAGIC | + PHYXS_XGXS_LANE_STAT_LANE3 | + PHYXS_XGXS_LANE_STAT_LANE2 | + PHYXS_XGXS_LANE_STAT_LANE1 | + PHYXS_XGXS_LANE_STAT_LANE0)) { + err = 0; + goto out; + } + + link_up = 1; + np->link_config.active_speed = SPEED_10000; + np->link_config.active_duplex = DUPLEX_FULL; + err = 0; + +out: + spin_unlock_irqrestore(&np->lock, flags); + + *link_up_p = link_up; + return err; +} + +static int link_status_1g(struct niu *np, int *link_up_p) +{ + u16 current_speed, bmsr; + unsigned long flags; + u8 current_duplex; + int err, link_up; + + link_up = 0; + current_speed = SPEED_INVALID; + current_duplex = DUPLEX_INVALID; + + spin_lock_irqsave(&np->lock, flags); + + err = -EINVAL; + if (np->link_config.loopback_mode != LOOPBACK_DISABLED) + goto out; + + err = mii_read(np, np->phy_addr, MII_BMSR); + if (err < 0) + goto out; + + bmsr = err; + if (bmsr & BMSR_LSTATUS) { + u16 adv, lpa, common, estat; + + err = mii_read(np, np->phy_addr, MII_ADVERTISE); + if (err < 0) + goto out; + adv = err; + + err = mii_read(np, np->phy_addr, MII_LPA); + if (err < 0) + goto out; + lpa = err; + + common = adv & lpa; + + err = mii_read(np, np->phy_addr, MII_ESTATUS); + if (err < 0) + goto out; + estat = err; + + link_up = 1; + if (estat & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) { + current_speed = SPEED_1000; + if (estat & ESTATUS_1000_TFULL) + current_duplex = DUPLEX_FULL; + else + current_duplex = DUPLEX_HALF; + } else { + if (common & ADVERTISE_100BASE4) { + current_speed = SPEED_100; + current_duplex = DUPLEX_HALF; + } else if (common & ADVERTISE_100FULL) { + current_speed = SPEED_100; + current_duplex = DUPLEX_FULL; + } else if (common & ADVERTISE_100HALF) { + current_speed = SPEED_100; + current_duplex = DUPLEX_HALF; + } else if (common & ADVERTISE_10FULL) { + current_speed = SPEED_10; + current_duplex = DUPLEX_FULL; + } else if (common & ADVERTISE_10HALF) { + current_speed = SPEED_10; + current_duplex = DUPLEX_HALF; + } else + link_up = 0; + } + } + err = 0; + +out: + spin_unlock_irqrestore(&np->lock, flags); + + *link_up_p = link_up; + return err; +} + +static int niu_link_status(struct niu *np, int *link_up_p) +{ + const struct niu_phy_ops *ops = np->phy_ops; + int err; + + err = 0; + if (ops->link_status) + err = ops->link_status(np, link_up_p); + + return err; +} + +static void niu_timer(unsigned long __opaque) +{ + struct niu *np = (struct niu *) __opaque; + unsigned long off; + int err, link_up; + + err = niu_link_status(np, &link_up); + if (!err) + niu_link_status_common(np, link_up); + + if (netif_carrier_ok(np->dev)) + off = 5 * HZ; + else + off = 1 * HZ; + np->timer.expires = jiffies + off; + + add_timer(&np->timer); +} + +static const struct niu_phy_ops phy_ops_10g_fiber_niu = { + .serdes_init = serdes_init_niu, + .xcvr_init = xcvr_init_10g, + .link_status = link_status_10g, +}; + +static const struct niu_phy_ops phy_ops_10g_fiber = { + .serdes_init = serdes_init_10g, + .xcvr_init = xcvr_init_10g, + .link_status = link_status_10g, +}; + +static const struct niu_phy_ops phy_ops_10g_copper = { + .serdes_init = serdes_init_10g, + .link_status = link_status_10g, /* XXX */ +}; + +static const struct niu_phy_ops phy_ops_1g_fiber = { + .serdes_init = serdes_init_1g, + .xcvr_init = xcvr_init_1g, + .link_status = link_status_1g, +}; + +static const struct niu_phy_ops phy_ops_1g_copper = { + .xcvr_init = xcvr_init_1g, + .link_status = link_status_1g, +}; + +struct niu_phy_template { + const struct niu_phy_ops *ops; + u32 phy_addr_base; +}; + +static const struct niu_phy_template phy_template_niu = { + .ops = &phy_ops_10g_fiber_niu, + .phy_addr_base = 16, +}; + +static const struct niu_phy_template phy_template_10g_fiber = { + .ops = &phy_ops_10g_fiber, + .phy_addr_base = 8, +}; + +static const struct niu_phy_template phy_template_10g_copper = { + .ops = &phy_ops_10g_copper, + .phy_addr_base = 10, +}; + +static const struct niu_phy_template phy_template_1g_fiber = { + .ops = &phy_ops_1g_fiber, + .phy_addr_base = 0, +}; + +static const struct niu_phy_template phy_template_1g_copper = { + .ops = &phy_ops_1g_copper, + .phy_addr_base = 0, +}; + +static int niu_determine_phy_disposition(struct niu *np) +{ + struct niu_parent *parent = np->parent; + u8 plat_type = parent->plat_type; + const struct niu_phy_template *tp; + u32 phy_addr_off = 0; + + if (plat_type == PLAT_TYPE_NIU) { + tp = &phy_template_niu; + phy_addr_off += np->port; + } else { + switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) { + case 0: + /* 1G copper */ + tp = &phy_template_1g_copper; + if (plat_type == PLAT_TYPE_VF_P0) + phy_addr_off = 10; + else if (plat_type == PLAT_TYPE_VF_P1) + phy_addr_off = 26; + + phy_addr_off += (np->port ^ 0x3); + break; + + case NIU_FLAGS_10G: + /* 10G copper */ + tp = &phy_template_1g_copper; + break; + + case NIU_FLAGS_FIBER: + /* 1G fiber */ + tp = &phy_template_1g_fiber; + break; + + case NIU_FLAGS_10G | NIU_FLAGS_FIBER: + /* 10G fiber */ + tp = &phy_template_10g_fiber; + if (plat_type == PLAT_TYPE_VF_P0 || + plat_type == PLAT_TYPE_VF_P1) + phy_addr_off = 8; + phy_addr_off += np->port; + break; + + default: + return -EINVAL; + } + } + + np->phy_ops = tp->ops; + np->phy_addr = tp->phy_addr_base + phy_addr_off; + + return 0; +} + +static int niu_init_link(struct niu *np) +{ + struct niu_parent *parent = np->parent; + int err, ignore; + + if (parent->plat_type == PLAT_TYPE_NIU) { + err = niu_xcvr_init(np); + if (err) + return err; + msleep(200); + } + err = niu_serdes_init(np); + if (err) + return err; + msleep(200); + err = niu_xcvr_init(np); + if (!err) + niu_link_status(np, &ignore); + return 0; +} + +static void niu_set_primary_mac(struct niu *np, unsigned char *addr) +{ + u16 reg0 = addr[4] << 8 | addr[5]; + u16 reg1 = addr[2] << 8 | addr[3]; + u16 reg2 = addr[0] << 8 | addr[1]; + + if (np->flags & NIU_FLAGS_XMAC) { + nw64_mac(XMAC_ADDR0, reg0); + nw64_mac(XMAC_ADDR1, reg1); + nw64_mac(XMAC_ADDR2, reg2); + } else { + nw64_mac(BMAC_ADDR0, reg0); + nw64_mac(BMAC_ADDR1, reg1); + nw64_mac(BMAC_ADDR2, reg2); + } +} + +static int niu_num_alt_addr(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + return XMAC_NUM_ALT_ADDR; + else + return BMAC_NUM_ALT_ADDR; +} + +static int niu_set_alt_mac(struct niu *np, int index, unsigned char *addr) +{ + u16 reg0 = addr[4] << 8 | addr[5]; + u16 reg1 = addr[2] << 8 | addr[3]; + u16 reg2 = addr[0] << 8 | addr[1]; + + if (index >= niu_num_alt_addr(np)) + return -EINVAL; + + if (np->flags & NIU_FLAGS_XMAC) { + nw64_mac(XMAC_ALT_ADDR0(index), reg0); + nw64_mac(XMAC_ALT_ADDR1(index), reg1); + nw64_mac(XMAC_ALT_ADDR2(index), reg2); + } else { + nw64_mac(BMAC_ALT_ADDR0(index), reg0); + nw64_mac(BMAC_ALT_ADDR1(index), reg1); + nw64_mac(BMAC_ALT_ADDR2(index), reg2); + } + + return 0; +} + +static int niu_enable_alt_mac(struct niu *np, int index, int on) +{ + unsigned long reg; + u64 val, mask; + + if (index >= niu_num_alt_addr(np)) + return -EINVAL; + + if (np->flags & NIU_FLAGS_XMAC) + reg = XMAC_ADDR_CMPEN; + else + reg = BMAC_ADDR_CMPEN; + + mask = 1 << index; + + val = nr64_mac(reg); + if (on) + val |= mask; + else + val &= ~mask; + nw64_mac(reg, val); + + return 0; +} + +static void __set_rdc_table_num_hw(struct niu *np, unsigned long reg, + int num, int mac_pref) +{ + u64 val = nr64_mac(reg); + val &= ~(HOST_INFO_MACRDCTBLN | HOST_INFO_MPR); + val |= num; + if (mac_pref) + val |= HOST_INFO_MPR; + nw64_mac(reg, val); +} + +static int __set_rdc_table_num(struct niu *np, + int xmac_index, int bmac_index, + int rdc_table_num, int mac_pref) +{ + unsigned long reg; + + if (rdc_table_num & ~HOST_INFO_MACRDCTBLN) + return -EINVAL; + if (np->flags & NIU_FLAGS_XMAC) + reg = XMAC_HOST_INFO(xmac_index); + else + reg = BMAC_HOST_INFO(bmac_index); + __set_rdc_table_num_hw(np, reg, rdc_table_num, mac_pref); + return 0; +} + +static int niu_set_primary_mac_rdc_table(struct niu *np, int table_num, + int mac_pref) +{ + return __set_rdc_table_num(np, 17, 0, table_num, mac_pref); +} + +static int niu_set_multicast_mac_rdc_table(struct niu *np, int table_num, + int mac_pref) +{ + return __set_rdc_table_num(np, 16, 8, table_num, mac_pref); +} + +static int niu_set_alt_mac_rdc_table(struct niu *np, int idx, + int table_num, int mac_pref) +{ + if (idx >= niu_num_alt_addr(np)) + return -EINVAL; + return __set_rdc_table_num(np, idx, idx + 1, table_num, mac_pref); +} + +static u64 vlan_entry_set_parity(u64 reg_val) +{ + u64 port01_mask; + u64 port23_mask; + + port01_mask = 0x00ff; + port23_mask = 0xff00; + + if (hweight64(reg_val & port01_mask) & 1) + reg_val |= ENET_VLAN_TBL_PARITY0; + else + reg_val &= ~ENET_VLAN_TBL_PARITY0; + + if (hweight64(reg_val & port23_mask) & 1) + reg_val |= ENET_VLAN_TBL_PARITY1; + else + reg_val &= ~ENET_VLAN_TBL_PARITY1; + + return reg_val; +} + +static void vlan_tbl_write(struct niu *np, unsigned long index, + int port, int vpr, int rdc_table) +{ + u64 reg_val = nr64(ENET_VLAN_TBL(index)); + + reg_val &= ~((ENET_VLAN_TBL_VPR | + ENET_VLAN_TBL_VLANRDCTBLN) << + ENET_VLAN_TBL_SHIFT(port)); + if (vpr) + reg_val |= (ENET_VLAN_TBL_VPR << + ENET_VLAN_TBL_SHIFT(port)); + reg_val |= (rdc_table << ENET_VLAN_TBL_SHIFT(port)); + + reg_val = vlan_entry_set_parity(reg_val); + + nw64(ENET_VLAN_TBL(index), reg_val); +} + +static void vlan_tbl_clear(struct niu *np) +{ + int i; + + for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++) + nw64(ENET_VLAN_TBL(i), 0); +} + +static int tcam_wait_bit(struct niu *np, u64 bit) +{ + int limit = 1000; + + while (--limit > 0) { + if (nr64(TCAM_CTL) & bit) + break; + udelay(1); + } + if (limit < 0) + return -ENODEV; + + return 0; +} + +static int tcam_flush(struct niu *np, int index) +{ + nw64(TCAM_KEY_0, 0x00); + nw64(TCAM_KEY_MASK_0, 0xff); + nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index)); + + return tcam_wait_bit(np, TCAM_CTL_STAT); +} + +#if 0 +static int tcam_read(struct niu *np, int index, + u64 *key, u64 *mask) +{ + int err; + + nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_READ | index)); + err = tcam_wait_bit(np, TCAM_CTL_STAT); + if (!err) { + key[0] = nr64(TCAM_KEY_0); + key[1] = nr64(TCAM_KEY_1); + key[2] = nr64(TCAM_KEY_2); + key[3] = nr64(TCAM_KEY_3); + mask[0] = nr64(TCAM_KEY_MASK_0); + mask[1] = nr64(TCAM_KEY_MASK_1); + mask[2] = nr64(TCAM_KEY_MASK_2); + mask[3] = nr64(TCAM_KEY_MASK_3); + } + return err; +} +#endif + +static int tcam_write(struct niu *np, int index, + u64 *key, u64 *mask) +{ + nw64(TCAM_KEY_0, key[0]); + nw64(TCAM_KEY_1, key[1]); + nw64(TCAM_KEY_2, key[2]); + nw64(TCAM_KEY_3, key[3]); + nw64(TCAM_KEY_MASK_0, mask[0]); + nw64(TCAM_KEY_MASK_1, mask[1]); + nw64(TCAM_KEY_MASK_2, mask[2]); + nw64(TCAM_KEY_MASK_3, mask[3]); + nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index)); + + return tcam_wait_bit(np, TCAM_CTL_STAT); +} + +#if 0 +static int tcam_assoc_read(struct niu *np, int index, u64 *data) +{ + int err; + + nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_READ | index)); + err = tcam_wait_bit(np, TCAM_CTL_STAT); + if (!err) + *data = nr64(TCAM_KEY_1); + + return err; +} +#endif + +static int tcam_assoc_write(struct niu *np, int index, u64 assoc_data) +{ + nw64(TCAM_KEY_1, assoc_data); + nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_WRITE | index)); + + return tcam_wait_bit(np, TCAM_CTL_STAT); +} + +static void tcam_enable(struct niu *np, int on) +{ + u64 val = nr64(FFLP_CFG_1); + + if (on) + val &= ~FFLP_CFG_1_TCAM_DIS; + else + val |= FFLP_CFG_1_TCAM_DIS; + nw64(FFLP_CFG_1, val); +} + +static void tcam_set_lat_and_ratio(struct niu *np, u64 latency, u64 ratio) +{ + u64 val = nr64(FFLP_CFG_1); + + val &= ~(FFLP_CFG_1_FFLPINITDONE | + FFLP_CFG_1_CAMLAT | + FFLP_CFG_1_CAMRATIO); + val |= (latency << FFLP_CFG_1_CAMLAT_SHIFT); + val |= (ratio << FFLP_CFG_1_CAMRATIO_SHIFT); + nw64(FFLP_CFG_1, val); + + val = nr64(FFLP_CFG_1); + val |= FFLP_CFG_1_FFLPINITDONE; + nw64(FFLP_CFG_1, val); +} + +static int tcam_user_eth_class_enable(struct niu *np, unsigned long class, + int on) +{ + unsigned long reg; + u64 val; + + if (class < CLASS_CODE_ETHERTYPE1 || + class > CLASS_CODE_ETHERTYPE2) + return -EINVAL; + + reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1); + val = nr64(reg); + if (on) + val |= L2_CLS_VLD; + else + val &= ~L2_CLS_VLD; + nw64(reg, val); + + return 0; +} + +#if 0 +static int tcam_user_eth_class_set(struct niu *np, unsigned long class, + u64 ether_type) +{ + unsigned long reg; + u64 val; + + if (class < CLASS_CODE_ETHERTYPE1 || + class > CLASS_CODE_ETHERTYPE2 || + (ether_type & ~(u64)0xffff) != 0) + return -EINVAL; + + reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1); + val = nr64(reg); + val &= ~L2_CLS_ETYPE; + val |= (ether_type << L2_CLS_ETYPE_SHIFT); + nw64(reg, val); + + return 0; +} +#endif + +static int tcam_user_ip_class_enable(struct niu *np, unsigned long class, + int on) +{ + unsigned long reg; + u64 val; + + if (class < CLASS_CODE_USER_PROG1 || + class > CLASS_CODE_USER_PROG4) + return -EINVAL; + + reg = L3_CLS(class - CLASS_CODE_USER_PROG1); + val = nr64(reg); + if (on) + val |= L3_CLS_VALID; + else + val &= ~L3_CLS_VALID; + nw64(reg, val); + + return 0; +} + +#if 0 +static int tcam_user_ip_class_set(struct niu *np, unsigned long class, + int ipv6, u64 protocol_id, + u64 tos_mask, u64 tos_val) +{ + unsigned long reg; + u64 val; + + if (class < CLASS_CODE_USER_PROG1 || + class > CLASS_CODE_USER_PROG4 || + (protocol_id & ~(u64)0xff) != 0 || + (tos_mask & ~(u64)0xff) != 0 || + (tos_val & ~(u64)0xff) != 0) + return -EINVAL; + + reg = L3_CLS(class - CLASS_CODE_USER_PROG1); + val = nr64(reg); + val &= ~(L3_CLS_IPVER | L3_CLS_PID | + L3_CLS_TOSMASK | L3_CLS_TOS); + if (ipv6) + val |= L3_CLS_IPVER; + val |= (protocol_id << L3_CLS_PID_SHIFT); + val |= (tos_mask << L3_CLS_TOSMASK_SHIFT); + val |= (tos_val << L3_CLS_TOS_SHIFT); + nw64(reg, val); + + return 0; +} +#endif + +static int tcam_early_init(struct niu *np) +{ + unsigned long i; + int err; + + tcam_enable(np, 0); + tcam_set_lat_and_ratio(np, + DEFAULT_TCAM_LATENCY, + DEFAULT_TCAM_ACCESS_RATIO); + for (i = CLASS_CODE_ETHERTYPE1; i <= CLASS_CODE_ETHERTYPE2; i++) { + err = tcam_user_eth_class_enable(np, i, 0); + if (err) + return err; + } + for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_USER_PROG4; i++) { + err = tcam_user_ip_class_enable(np, i, 0); + if (err) + return err; + } + + return 0; +} + +static int tcam_flush_all(struct niu *np) +{ + unsigned long i; + + for (i = 0; i < np->parent->tcam_num_entries; i++) { + int err = tcam_flush(np, i); + if (err) + return err; + } + return 0; +} + +static u64 hash_addr_regval(unsigned long index, unsigned long num_entries) +{ + return ((u64)index | (num_entries == 1 ? + HASH_TBL_ADDR_AUTOINC : 0)); +} + +#if 0 +static int hash_read(struct niu *np, unsigned long partition, + unsigned long index, unsigned long num_entries, + u64 *data) +{ + u64 val = hash_addr_regval(index, num_entries); + unsigned long i; + + if (partition >= FCRAM_NUM_PARTITIONS || + index + num_entries > FCRAM_SIZE) + return -EINVAL; + + nw64(HASH_TBL_ADDR(partition), val); + for (i = 0; i < num_entries; i++) + data[i] = nr64(HASH_TBL_DATA(partition)); + + return 0; +} +#endif + +static int hash_write(struct niu *np, unsigned long partition, + unsigned long index, unsigned long num_entries, + u64 *data) +{ + u64 val = hash_addr_regval(index, num_entries); + unsigned long i; + + if (partition >= FCRAM_NUM_PARTITIONS || + index + (num_entries * 8) > FCRAM_SIZE) + return -EINVAL; + + nw64(HASH_TBL_ADDR(partition), val); + for (i = 0; i < num_entries; i++) + nw64(HASH_TBL_DATA(partition), data[i]); + + return 0; +} + +static void fflp_reset(struct niu *np) +{ + u64 val; + + nw64(FFLP_CFG_1, FFLP_CFG_1_PIO_FIO_RST); + udelay(10); + nw64(FFLP_CFG_1, 0); + + val = FFLP_CFG_1_FCRAMOUTDR_NORMAL | FFLP_CFG_1_FFLPINITDONE; + nw64(FFLP_CFG_1, val); +} + +static void fflp_set_timings(struct niu *np) +{ + u64 val = nr64(FFLP_CFG_1); + + val &= ~FFLP_CFG_1_FFLPINITDONE; + val |= (DEFAULT_FCRAMRATIO << FFLP_CFG_1_FCRAMRATIO_SHIFT); + nw64(FFLP_CFG_1, val); + + val = nr64(FFLP_CFG_1); + val |= FFLP_CFG_1_FFLPINITDONE; + nw64(FFLP_CFG_1, val); + + val = nr64(FCRAM_REF_TMR); + val &= ~(FCRAM_REF_TMR_MAX | FCRAM_REF_TMR_MIN); + val |= (DEFAULT_FCRAM_REFRESH_MAX << FCRAM_REF_TMR_MAX_SHIFT); + val |= (DEFAULT_FCRAM_REFRESH_MIN << FCRAM_REF_TMR_MIN_SHIFT); + nw64(FCRAM_REF_TMR, val); +} + +static int fflp_set_partition(struct niu *np, u64 partition, + u64 mask, u64 base, int enable) +{ + unsigned long reg; + u64 val; + + if (partition >= FCRAM_NUM_PARTITIONS || + (mask & ~(u64)0x1f) != 0 || + (base & ~(u64)0x1f) != 0) + return -EINVAL; + + reg = FLW_PRT_SEL(partition); + + val = nr64(reg); + val &= ~(FLW_PRT_SEL_EXT | FLW_PRT_SEL_MASK | FLW_PRT_SEL_BASE); + val |= (mask << FLW_PRT_SEL_MASK_SHIFT); + val |= (base << FLW_PRT_SEL_BASE_SHIFT); + if (enable) + val |= FLW_PRT_SEL_EXT; + nw64(reg, val); + + return 0; +} + +static int fflp_disable_all_partitions(struct niu *np) +{ + unsigned long i; + + for (i = 0; i < FCRAM_NUM_PARTITIONS; i++) { + int err = fflp_set_partition(np, 0, 0, 0, 0); + if (err) + return err; + } + return 0; +} + +static void fflp_llcsnap_enable(struct niu *np, int on) +{ + u64 val = nr64(FFLP_CFG_1); + + if (on) + val |= FFLP_CFG_1_LLCSNAP; + else + val &= ~FFLP_CFG_1_LLCSNAP; + nw64(FFLP_CFG_1, val); +} + +static void fflp_errors_enable(struct niu *np, int on) +{ + u64 val = nr64(FFLP_CFG_1); + + if (on) + val &= ~FFLP_CFG_1_ERRORDIS; + else + val |= FFLP_CFG_1_ERRORDIS; + nw64(FFLP_CFG_1, val); +} + +static int fflp_hash_clear(struct niu *np) +{ + struct fcram_hash_ipv4 ent; + unsigned long i; + + /* IPV4 hash entry with valid bit clear, rest is don't care. */ + memset(&ent, 0, sizeof(ent)); + ent.header = HASH_HEADER_EXT; + + for (i = 0; i < FCRAM_SIZE; i += sizeof(ent)) { + int err = hash_write(np, 0, i, 1, (u64 *) &ent); + if (err) + return err; + } + return 0; +} + +static int fflp_early_init(struct niu *np) +{ + struct niu_parent *parent; + unsigned long flags; + int err; + + niu_lock_parent(np, flags); + + parent = np->parent; + err = 0; + if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) { + niudbg(PROBE, "fflp_early_init: Initting hw on port %u\n", + np->port); + if (np->parent->plat_type != PLAT_TYPE_NIU) { + fflp_reset(np); + fflp_set_timings(np); + err = fflp_disable_all_partitions(np); + if (err) { + niudbg(PROBE, "fflp_disable_all_partitions " + "failed, err=%d\n", err); + goto out; + } + } + + err = tcam_early_init(np); + if (err) { + niudbg(PROBE, "tcam_early_init failed, err=%d\n", + err); + goto out; + } + fflp_llcsnap_enable(np, 1); + fflp_errors_enable(np, 0); + nw64(H1POLY, 0); + nw64(H2POLY, 0); + + err = tcam_flush_all(np); + if (err) { + niudbg(PROBE, "tcam_flush_all failed, err=%d\n", + err); + goto out; + } + if (np->parent->plat_type != PLAT_TYPE_NIU) { + err = fflp_hash_clear(np); + if (err) { + niudbg(PROBE, "fflp_hash_clear failed, " + "err=%d\n", err); + goto out; + } + } + + vlan_tbl_clear(np); + + niudbg(PROBE, "fflp_early_init: Success\n"); + parent->flags |= PARENT_FLGS_CLS_HWINIT; + } +out: + niu_unlock_parent(np, flags); + return err; +} + +static int niu_set_flow_key(struct niu *np, unsigned long class_code, u64 key) +{ + if (class_code < CLASS_CODE_USER_PROG1 || + class_code > CLASS_CODE_SCTP_IPV6) + return -EINVAL; + + nw64(FLOW_KEY(class_code - CLASS_CODE_USER_PROG1), key); + return 0; +} + +static int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key) +{ + if (class_code < CLASS_CODE_USER_PROG1 || + class_code > CLASS_CODE_SCTP_IPV6) + return -EINVAL; + + nw64(TCAM_KEY(class_code - CLASS_CODE_USER_PROG1), key); + return 0; +} + +static void niu_rx_skb_append(struct sk_buff *skb, struct page *page, + u32 offset, u32 size) +{ + int i = skb_shinfo(skb)->nr_frags; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + frag->page = page; + frag->page_offset = offset; + frag->size = size; + + skb->len += size; + skb->data_len += size; + skb->truesize += size; + + skb_shinfo(skb)->nr_frags = i + 1; +} + +static unsigned int niu_hash_rxaddr(struct rx_ring_info *rp, u64 a) +{ + a >>= PAGE_SHIFT; + a ^= (a >> ilog2(MAX_RBR_RING_SIZE)); + + return (a & (MAX_RBR_RING_SIZE - 1)); +} + +static struct page *niu_find_rxpage(struct rx_ring_info *rp, u64 addr, + struct page ***link) +{ + unsigned int h = niu_hash_rxaddr(rp, addr); + struct page *p, **pp; + + addr &= PAGE_MASK; + pp = &rp->rxhash[h]; + for (; (p = *pp) != NULL; pp = (struct page **) &p->mapping) { + if (p->index == addr) { + *link = pp; + break; + } + } + + return p; +} + +static void niu_hash_page(struct rx_ring_info *rp, struct page *page, u64 base) +{ + unsigned int h = niu_hash_rxaddr(rp, base); + + page->index = base; + page->mapping = (struct address_space *) rp->rxhash[h]; + rp->rxhash[h] = page; +} + +static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp, + gfp_t mask, int start_index) +{ + struct page *page; + u64 addr; + int i; + + page = alloc_page(mask); + if (!page) + return -ENOMEM; + + addr = np->ops->map_page(np->device, page, 0, + PAGE_SIZE, DMA_FROM_DEVICE); + + niu_hash_page(rp, page, addr); + if (rp->rbr_blocks_per_page > 1) + atomic_add(rp->rbr_blocks_per_page - 1, + &compound_head(page)->_count); + + for (i = 0; i < rp->rbr_blocks_per_page; i++) { + __le32 *rbr = &rp->rbr[start_index + i]; + + *rbr = cpu_to_le32(addr >> RBR_DESCR_ADDR_SHIFT); + addr += rp->rbr_block_size; + } + + return 0; +} + +static void niu_rbr_refill(struct niu *np, struct rx_ring_info *rp, gfp_t mask) +{ + int index = rp->rbr_index; + + rp->rbr_pending++; + if ((rp->rbr_pending % rp->rbr_blocks_per_page) == 0) { + int err = niu_rbr_add_page(np, rp, mask, index); + + if (unlikely(err)) { + rp->rbr_pending--; + return; + } + + rp->rbr_index += rp->rbr_blocks_per_page; + BUG_ON(rp->rbr_index > rp->rbr_table_size); + if (rp->rbr_index == rp->rbr_table_size) + rp->rbr_index = 0; + + if (rp->rbr_pending >= rp->rbr_kick_thresh) { + nw64(RBR_KICK(rp->rx_channel), rp->rbr_pending); + rp->rbr_pending = 0; + } + } +} + +static int niu_rx_pkt_ignore(struct niu *np, struct rx_ring_info *rp) +{ + unsigned int index = rp->rcr_index; + int num_rcr = 0; + + rp->rx_dropped++; + while (1) { + struct page *page, **link; + u64 addr, val; + u32 rcr_size; + + num_rcr++; + + val = le64_to_cpup(&rp->rcr[index]); + addr = (val & RCR_ENTRY_PKT_BUF_ADDR) << + RCR_ENTRY_PKT_BUF_ADDR_SHIFT; + page = niu_find_rxpage(rp, addr, &link); + + rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >> + RCR_ENTRY_PKTBUFSZ_SHIFT]; + if ((page->index + PAGE_SIZE) - rcr_size == addr) { + *link = (struct page *) page->mapping; + np->ops->unmap_page(np->device, page->index, + PAGE_SIZE, DMA_FROM_DEVICE); + page->index = 0; + page->mapping = NULL; + __free_page(page); + rp->rbr_refill_pending++; + } + + index = NEXT_RCR(rp, index); + if (!(val & RCR_ENTRY_MULTI)) + break; + + } + rp->rcr_index = index; + + return num_rcr; +} + +static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp) +{ + unsigned int index = rp->rcr_index; + struct sk_buff *skb; + int len, num_rcr; + + skb = netdev_alloc_skb(np->dev, RX_SKB_ALLOC_SIZE); + if (unlikely(!skb)) + return niu_rx_pkt_ignore(np, rp); + + num_rcr = 0; + while (1) { + struct page *page, **link; + u32 rcr_size, append_size; + u64 addr, val, off; + + num_rcr++; + + val = le64_to_cpup(&rp->rcr[index]); + + len = (val & RCR_ENTRY_L2_LEN) >> + RCR_ENTRY_L2_LEN_SHIFT; + len -= ETH_FCS_LEN; + + addr = (val & RCR_ENTRY_PKT_BUF_ADDR) << + RCR_ENTRY_PKT_BUF_ADDR_SHIFT; + page = niu_find_rxpage(rp, addr, &link); + + rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >> + RCR_ENTRY_PKTBUFSZ_SHIFT]; + + off = addr & ~PAGE_MASK; + append_size = rcr_size; + if (num_rcr == 1) { + int ptype; + + off += 2; + append_size -= 2; + + ptype = (val >> RCR_ENTRY_PKT_TYPE_SHIFT); + if ((ptype == RCR_PKT_TYPE_TCP || + ptype == RCR_PKT_TYPE_UDP) && + !(val & (RCR_ENTRY_NOPORT | + RCR_ENTRY_ERROR))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + } + if (!(val & RCR_ENTRY_MULTI)) + append_size = len - skb->len; + + niu_rx_skb_append(skb, page, off, append_size); + if ((page->index + rp->rbr_block_size) - rcr_size == addr) { + *link = (struct page *) page->mapping; + np->ops->unmap_page(np->device, page->index, + PAGE_SIZE, DMA_FROM_DEVICE); + page->index = 0; + page->mapping = NULL; + rp->rbr_refill_pending++; + } else + get_page(page); + + index = NEXT_RCR(rp, index); + if (!(val & RCR_ENTRY_MULTI)) + break; + + } + rp->rcr_index = index; + + skb_reserve(skb, NET_IP_ALIGN); + __pskb_pull_tail(skb, min(len, NIU_RXPULL_MAX)); + + rp->rx_packets++; + rp->rx_bytes += skb->len; + + skb->protocol = eth_type_trans(skb, np->dev); + netif_receive_skb(skb); + + return num_rcr; +} + +static int niu_rbr_fill(struct niu *np, struct rx_ring_info *rp, gfp_t mask) +{ + int blocks_per_page = rp->rbr_blocks_per_page; + int err, index = rp->rbr_index; + + err = 0; + while (index < (rp->rbr_table_size - blocks_per_page)) { + err = niu_rbr_add_page(np, rp, mask, index); + if (err) + break; + + index += blocks_per_page; + } + + rp->rbr_index = index; + return err; +} + +static void niu_rbr_free(struct niu *np, struct rx_ring_info *rp) +{ + int i; + + for (i = 0; i < MAX_RBR_RING_SIZE; i++) { + struct page *page; + + page = rp->rxhash[i]; + while (page) { + struct page *next = (struct page *) page->mapping; + u64 base = page->index; + + np->ops->unmap_page(np->device, base, PAGE_SIZE, + DMA_FROM_DEVICE); + page->index = 0; + page->mapping = NULL; + + __free_page(page); + + page = next; + } + } + + for (i = 0; i < rp->rbr_table_size; i++) + rp->rbr[i] = cpu_to_le32(0); + rp->rbr_index = 0; +} + +static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx) +{ + struct tx_buff_info *tb = &rp->tx_buffs[idx]; + struct sk_buff *skb = tb->skb; + struct tx_pkt_hdr *tp; + u64 tx_flags; + int i, len; + + tp = (struct tx_pkt_hdr *) skb->data; + tx_flags = le64_to_cpup(&tp->flags); + + rp->tx_packets++; + rp->tx_bytes += (((tx_flags & TXHDR_LEN) >> TXHDR_LEN_SHIFT) - + ((tx_flags & TXHDR_PAD) / 2)); + + len = skb_headlen(skb); + np->ops->unmap_single(np->device, tb->mapping, + len, DMA_TO_DEVICE); + + if (le64_to_cpu(rp->descr[idx]) & TX_DESC_MARK) + rp->mark_pending--; + + tb->skb = NULL; + do { + idx = NEXT_TX(rp, idx); + len -= MAX_TX_DESC_LEN; + } while (len > 0); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + tb = &rp->tx_buffs[idx]; + BUG_ON(tb->skb != NULL); + np->ops->unmap_page(np->device, tb->mapping, + skb_shinfo(skb)->frags[i].size, + DMA_TO_DEVICE); + idx = NEXT_TX(rp, idx); + } + + dev_kfree_skb(skb); + + return idx; +} + +#define NIU_TX_WAKEUP_THRESH(rp) ((rp)->pending / 4) + +static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) +{ + u16 pkt_cnt, tmp; + int cons; + u64 cs; + + cs = rp->tx_cs; + if (unlikely(!(cs & (TX_CS_MK | TX_CS_MMK)))) + goto out; + + tmp = pkt_cnt = (cs & TX_CS_PKT_CNT) >> TX_CS_PKT_CNT_SHIFT; + pkt_cnt = (pkt_cnt - rp->last_pkt_cnt) & + (TX_CS_PKT_CNT >> TX_CS_PKT_CNT_SHIFT); + + rp->last_pkt_cnt = tmp; + + cons = rp->cons; + + niudbg(TX_DONE, "%s: niu_tx_work() pkt_cnt[%u] cons[%d]\n", + np->dev->name, pkt_cnt, cons); + + while (pkt_cnt--) + cons = release_tx_packet(np, rp, cons); + + rp->cons = cons; + smp_mb(); + +out: + if (unlikely(netif_queue_stopped(np->dev) && + (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) { + netif_tx_lock(np->dev); + if (netif_queue_stopped(np->dev) && + (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp))) + netif_wake_queue(np->dev); + netif_tx_unlock(np->dev); + } +} + +static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) +{ + int qlen, rcr_done = 0, work_done = 0; + struct rxdma_mailbox *mbox = rp->mbox; + u64 stat; + +#if 1 + stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel)); + qlen = nr64(RCRSTAT_A(rp->rx_channel)) & RCRSTAT_A_QLEN; +#else + stat = le64_to_cpup(&mbox->rx_dma_ctl_stat); + qlen = (le64_to_cpup(&mbox->rcrstat_a) & RCRSTAT_A_QLEN); +#endif + mbox->rx_dma_ctl_stat = 0; + mbox->rcrstat_a = 0; + + niudbg(RX_STATUS, "%s: niu_rx_work(chan[%d]), stat[%llx] qlen=%d\n", + np->dev->name, rp->rx_channel, (unsigned long long) stat, qlen); + + rcr_done = work_done = 0; + qlen = min(qlen, budget); + while (work_done < qlen) { + rcr_done += niu_process_rx_pkt(np, rp); + work_done++; + } + + if (rp->rbr_refill_pending >= rp->rbr_kick_thresh) { + unsigned int i; + + for (i = 0; i < rp->rbr_refill_pending; i++) + niu_rbr_refill(np, rp, GFP_ATOMIC); + rp->rbr_refill_pending = 0; + } + + stat = (RX_DMA_CTL_STAT_MEX | + ((u64)work_done << RX_DMA_CTL_STAT_PKTREAD_SHIFT) | + ((u64)rcr_done << RX_DMA_CTL_STAT_PTRREAD_SHIFT)); + + nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat); + + return work_done; +} + +static int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget) +{ + u64 v0 = lp->v0; + u32 tx_vec = (v0 >> 32); + u32 rx_vec = (v0 & 0xffffffff); + int i, work_done = 0; + + niudbg(INTR, "%s: niu_poll_core() v0[%016llx]\n", + np->dev->name, (unsigned long long) v0); + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + if (tx_vec & (1 << rp->tx_channel)) + niu_tx_work(np, rp); + nw64(LD_IM0(LDN_TXDMA(rp->tx_channel)), 0); + } + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + if (rx_vec & (1 << rp->rx_channel)) { + int this_work_done; + + this_work_done = niu_rx_work(np, rp, + budget); + + budget -= this_work_done; + work_done += this_work_done; + } + nw64(LD_IM0(LDN_RXDMA(rp->rx_channel)), 0); + } + + return work_done; +} + +static int niu_poll(struct napi_struct *napi, int budget) +{ + struct niu_ldg *lp = container_of(napi, struct niu_ldg, napi); + struct niu *np = lp->np; + int work_done; + + work_done = niu_poll_core(np, lp, budget); + + if (work_done < budget) { + netif_rx_complete(np->dev, napi); + niu_ldg_rearm(np, lp, 1); + } + return work_done; +} + +static void niu_log_rxchan_errors(struct niu *np, struct rx_ring_info *rp, + u64 stat) +{ + dev_err(np->device, PFX "%s: RX channel %u errors ( ", + np->dev->name, rp->rx_channel); + + if (stat & RX_DMA_CTL_STAT_RBR_TMOUT) + printk("RBR_TMOUT "); + if (stat & RX_DMA_CTL_STAT_RSP_CNT_ERR) + printk("RSP_CNT "); + if (stat & RX_DMA_CTL_STAT_BYTE_EN_BUS) + printk("BYTE_EN_BUS "); + if (stat & RX_DMA_CTL_STAT_RSP_DAT_ERR) + printk("RSP_DAT "); + if (stat & RX_DMA_CTL_STAT_RCR_ACK_ERR) + printk("RCR_ACK "); + if (stat & RX_DMA_CTL_STAT_RCR_SHA_PAR) + printk("RCR_SHA_PAR "); + if (stat & RX_DMA_CTL_STAT_RBR_PRE_PAR) + printk("RBR_PRE_PAR "); + if (stat & RX_DMA_CTL_STAT_CONFIG_ERR) + printk("CONFIG "); + if (stat & RX_DMA_CTL_STAT_RCRINCON) + printk("RCRINCON "); + if (stat & RX_DMA_CTL_STAT_RCRFULL) + printk("RCRFULL "); + if (stat & RX_DMA_CTL_STAT_RBRFULL) + printk("RBRFULL "); + if (stat & RX_DMA_CTL_STAT_RBRLOGPAGE) + printk("RBRLOGPAGE "); + if (stat & RX_DMA_CTL_STAT_CFIGLOGPAGE) + printk("CFIGLOGPAGE "); + if (stat & RX_DMA_CTL_STAT_DC_FIFO_ERR) + printk("DC_FIDO "); + + printk(")\n"); +} + +static int niu_rx_error(struct niu *np, struct rx_ring_info *rp) +{ + u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel)); + int err = 0; + + dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n", + np->dev->name, rp->rx_channel, (unsigned long long) stat); + + niu_log_rxchan_errors(np, rp, stat); + + if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL | + RX_DMA_CTL_STAT_PORT_FATAL)) + err = -EINVAL; + + nw64(RX_DMA_CTL_STAT(rp->rx_channel), + stat & RX_DMA_CTL_WRITE_CLEAR_ERRS); + + return err; +} + +static void niu_log_txchan_errors(struct niu *np, struct tx_ring_info *rp, + u64 cs) +{ + dev_err(np->device, PFX "%s: TX channel %u errors ( ", + np->dev->name, rp->tx_channel); + + if (cs & TX_CS_MBOX_ERR) + printk("MBOX "); + if (cs & TX_CS_PKT_SIZE_ERR) + printk("PKT_SIZE "); + if (cs & TX_CS_TX_RING_OFLOW) + printk("TX_RING_OFLOW "); + if (cs & TX_CS_PREF_BUF_PAR_ERR) + printk("PREF_BUF_PAR "); + if (cs & TX_CS_NACK_PREF) + printk("NACK_PREF "); + if (cs & TX_CS_NACK_PKT_RD) + printk("NACK_PKT_RD "); + if (cs & TX_CS_CONF_PART_ERR) + printk("CONF_PART "); + if (cs & TX_CS_PKT_PRT_ERR) + printk("PKT_PTR "); + + printk(")\n"); +} + +static int niu_tx_error(struct niu *np, struct tx_ring_info *rp) +{ + u64 cs, logh, logl; + + cs = nr64(TX_CS(rp->tx_channel)); + logh = nr64(TX_RNG_ERR_LOGH(rp->tx_channel)); + logl = nr64(TX_RNG_ERR_LOGL(rp->tx_channel)); + + dev_err(np->device, PFX "%s: TX channel %u error, " + "cs[%llx] logh[%llx] logl[%llx]\n", + np->dev->name, rp->tx_channel, + (unsigned long long) cs, + (unsigned long long) logh, + (unsigned long long) logl); + + niu_log_txchan_errors(np, rp, cs); + + return -ENODEV; +} + +static int niu_mif_interrupt(struct niu *np) +{ + u64 mif_status = nr64(MIF_STATUS); + int phy_mdint = 0; + + if (np->flags & NIU_FLAGS_XMAC) { + u64 xrxmac_stat = nr64_mac(XRXMAC_STATUS); + + if (xrxmac_stat & XRXMAC_STATUS_PHY_MDINT) + phy_mdint = 1; + } + + dev_err(np->device, PFX "%s: MIF interrupt, " + "stat[%llx] phy_mdint(%d)\n", + np->dev->name, (unsigned long long) mif_status, phy_mdint); + + return -ENODEV; +} + +static void niu_xmac_interrupt(struct niu *np) +{ + struct niu_xmac_stats *mp = &np->mac_stats.xmac; + u64 val; + + val = nr64_mac(XTXMAC_STATUS); + if (val & XTXMAC_STATUS_FRAME_CNT_EXP) + mp->tx_frames += TXMAC_FRM_CNT_COUNT; + if (val & XTXMAC_STATUS_BYTE_CNT_EXP) + mp->tx_bytes += TXMAC_BYTE_CNT_COUNT; + if (val & XTXMAC_STATUS_TXFIFO_XFR_ERR) + mp->tx_fifo_errors++; + if (val & XTXMAC_STATUS_TXMAC_OFLOW) + mp->tx_overflow_errors++; + if (val & XTXMAC_STATUS_MAX_PSIZE_ERR) + mp->tx_max_pkt_size_errors++; + if (val & XTXMAC_STATUS_TXMAC_UFLOW) + mp->tx_underflow_errors++; + + val = nr64_mac(XRXMAC_STATUS); + if (val & XRXMAC_STATUS_LCL_FLT_STATUS) + mp->rx_local_faults++; + if (val & XRXMAC_STATUS_RFLT_DET) + mp->rx_remote_faults++; + if (val & XRXMAC_STATUS_LFLT_CNT_EXP) + mp->rx_link_faults += LINK_FAULT_CNT_COUNT; + if (val & XRXMAC_STATUS_ALIGNERR_CNT_EXP) + mp->rx_align_errors += RXMAC_ALIGN_ERR_CNT_COUNT; + if (val & XRXMAC_STATUS_RXFRAG_CNT_EXP) + mp->rx_frags += RXMAC_FRAG_CNT_COUNT; + if (val & XRXMAC_STATUS_RXMULTF_CNT_EXP) + mp->rx_mcasts += RXMAC_MC_FRM_CNT_COUNT; + if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP) + mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT; + if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP) + mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT; + if (val & XRXMAC_STATUS_RXHIST1_CNT_EXP) + mp->rx_hist_cnt1 += RXMAC_HIST_CNT1_COUNT; + if (val & XRXMAC_STATUS_RXHIST2_CNT_EXP) + mp->rx_hist_cnt2 += RXMAC_HIST_CNT2_COUNT; + if (val & XRXMAC_STATUS_RXHIST3_CNT_EXP) + mp->rx_hist_cnt3 += RXMAC_HIST_CNT3_COUNT; + if (val & XRXMAC_STATUS_RXHIST4_CNT_EXP) + mp->rx_hist_cnt4 += RXMAC_HIST_CNT4_COUNT; + if (val & XRXMAC_STATUS_RXHIST5_CNT_EXP) + mp->rx_hist_cnt5 += RXMAC_HIST_CNT5_COUNT; + if (val & XRXMAC_STATUS_RXHIST6_CNT_EXP) + 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) + mp->rx_octets += RXMAC_BT_CNT_COUNT; + if (val & XRXMAC_STATUS_CVIOLERR_CNT_EXP) + mp->rx_code_violations += RXMAC_CD_VIO_CNT_COUNT; + if (val & XRXMAC_STATUS_LENERR_CNT_EXP) + mp->rx_len_errors += RXMAC_MPSZER_CNT_COUNT; + if (val & XRXMAC_STATUS_CRCERR_CNT_EXP) + mp->rx_crc_errors += RXMAC_CRC_ER_CNT_COUNT; + if (val & XRXMAC_STATUS_RXUFLOW) + mp->rx_underflows++; + if (val & XRXMAC_STATUS_RXOFLOW) + mp->rx_overflows++; + + val = nr64_mac(XMAC_FC_STAT); + if (val & XMAC_FC_STAT_TX_MAC_NPAUSE) + mp->pause_off_state++; + if (val & XMAC_FC_STAT_TX_MAC_PAUSE) + mp->pause_on_state++; + if (val & XMAC_FC_STAT_RX_MAC_RPAUSE) + mp->pause_received++; +} + +static void niu_bmac_interrupt(struct niu *np) +{ + struct niu_bmac_stats *mp = &np->mac_stats.bmac; + u64 val; + + val = nr64_mac(BTXMAC_STATUS); + if (val & BTXMAC_STATUS_UNDERRUN) + mp->tx_underflow_errors++; + if (val & BTXMAC_STATUS_MAX_PKT_ERR) + mp->tx_max_pkt_size_errors++; + if (val & BTXMAC_STATUS_BYTE_CNT_EXP) + mp->tx_bytes += BTXMAC_BYTE_CNT_COUNT; + if (val & BTXMAC_STATUS_FRAME_CNT_EXP) + mp->tx_frames += BTXMAC_FRM_CNT_COUNT; + + val = nr64_mac(BRXMAC_STATUS); + if (val & BRXMAC_STATUS_OVERFLOW) + mp->rx_overflows++; + if (val & BRXMAC_STATUS_FRAME_CNT_EXP) + mp->rx_frames += BRXMAC_FRAME_CNT_COUNT; + if (val & BRXMAC_STATUS_ALIGN_ERR_EXP) + mp->rx_align_errors += BRXMAC_ALIGN_ERR_CNT_COUNT; + if (val & BRXMAC_STATUS_CRC_ERR_EXP) + mp->rx_crc_errors += BRXMAC_ALIGN_ERR_CNT_COUNT; + if (val & BRXMAC_STATUS_LEN_ERR_EXP) + mp->rx_len_errors += BRXMAC_CODE_VIOL_ERR_CNT_COUNT; + + val = nr64_mac(BMAC_CTRL_STATUS); + if (val & BMAC_CTRL_STATUS_NOPAUSE) + mp->pause_off_state++; + if (val & BMAC_CTRL_STATUS_PAUSE) + mp->pause_on_state++; + if (val & BMAC_CTRL_STATUS_PAUSE_RECV) + mp->pause_received++; +} + +static int niu_mac_interrupt(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_xmac_interrupt(np); + else + niu_bmac_interrupt(np); + + return 0; +} + +static void niu_log_device_error(struct niu *np, u64 stat) +{ + dev_err(np->device, PFX "%s: Core device errors ( ", + np->dev->name); + + if (stat & SYS_ERR_MASK_META2) + printk("META2 "); + if (stat & SYS_ERR_MASK_META1) + printk("META1 "); + if (stat & SYS_ERR_MASK_PEU) + printk("PEU "); + if (stat & SYS_ERR_MASK_TXC) + printk("TXC "); + if (stat & SYS_ERR_MASK_RDMC) + printk("RDMC "); + if (stat & SYS_ERR_MASK_TDMC) + printk("TDMC "); + if (stat & SYS_ERR_MASK_ZCP) + printk("ZCP "); + if (stat & SYS_ERR_MASK_FFLP) + printk("FFLP "); + if (stat & SYS_ERR_MASK_IPP) + printk("IPP "); + if (stat & SYS_ERR_MASK_MAC) + printk("MAC "); + if (stat & SYS_ERR_MASK_SMX) + printk("SMX "); + + printk(")\n"); +} + +static int niu_device_error(struct niu *np) +{ + u64 stat = nr64(SYS_ERR_STAT); + + dev_err(np->device, PFX "%s: Core device error, stat[%llx]\n", + np->dev->name, (unsigned long long) stat); + + niu_log_device_error(np, stat); + + return -ENODEV; +} + +static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp) +{ + u64 v0 = lp->v0; + u64 v1 = lp->v1; + u64 v2 = lp->v2; + int i, err = 0; + + if (v1 & 0x00000000ffffffffULL) { + u32 rx_vec = (v1 & 0xffffffff); + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + if (rx_vec & (1 << rp->rx_channel)) { + int r = niu_rx_error(np, rp); + if (r) + err = r; + } + } + } + if (v1 & 0x7fffffff00000000ULL) { + u32 tx_vec = (v1 >> 32) & 0x7fffffff; + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + if (tx_vec & (1 << rp->tx_channel)) { + int r = niu_tx_error(np, rp); + if (r) + err = r; + } + } + } + if ((v0 | v1) & 0x8000000000000000ULL) { + int r = niu_mif_interrupt(np); + if (r) + err = r; + } + if (v2) { + if (v2 & 0x01ef) { + int r = niu_mac_interrupt(np); + if (r) + err = r; + } + if (v2 & 0x0210) { + int r = niu_device_error(np); + if (r) + err = r; + } + } + + if (err) + niu_enable_interrupts(np, 0); + + return -EINVAL; +} + +static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp, + int ldn) +{ + struct rxdma_mailbox *mbox = rp->mbox; + u64 stat_write, stat = le64_to_cpup(&mbox->rx_dma_ctl_stat); + + stat_write = (RX_DMA_CTL_STAT_RCRTHRES | + RX_DMA_CTL_STAT_RCRTO); + nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat_write); + + niudbg(INTR, "%s: rxchan_intr stat[%llx]\n", + np->dev->name, (unsigned long long) stat); +} + +static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp, + int ldn) +{ + rp->tx_cs = nr64(TX_CS(rp->tx_channel)); + + niudbg(INTR, "%s: txchan_intr cs[%llx]\n", + np->dev->name, (unsigned long long) rp->tx_cs); +} + +static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0) +{ + struct niu_parent *parent = np->parent; + u32 rx_vec, tx_vec; + int i; + + tx_vec = (v0 >> 32); + rx_vec = (v0 & 0xffffffff); + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + int ldn = LDN_RXDMA(rp->rx_channel); + + if (parent->ldg_map[ldn] != ldg) + continue; + + nw64(LD_IM0(ldn), LD_IM0_MASK); + if (rx_vec & (1 << rp->rx_channel)) + niu_rxchan_intr(np, rp, ldn); + } + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + int ldn = LDN_TXDMA(rp->tx_channel); + + if (parent->ldg_map[ldn] != ldg) + continue; + + nw64(LD_IM0(ldn), LD_IM0_MASK); + if (tx_vec & (1 << rp->tx_channel)) + niu_txchan_intr(np, rp, ldn); + } +} + +static void niu_schedule_napi(struct niu *np, struct niu_ldg *lp, + u64 v0, u64 v1, u64 v2) +{ + if (likely(netif_rx_schedule_prep(np->dev, &lp->napi))) { + lp->v0 = v0; + lp->v1 = v1; + lp->v2 = v2; + __niu_fastpath_interrupt(np, lp->ldg_num, v0); + __netif_rx_schedule(np->dev, &lp->napi); + } +} + +static irqreturn_t niu_interrupt(int irq, void *dev_id) +{ + struct niu_ldg *lp = dev_id; + struct niu *np = lp->np; + int ldg = lp->ldg_num; + unsigned long flags; + u64 v0, v1, v2; + + if (netif_msg_intr(np)) + printk(KERN_DEBUG PFX "niu_interrupt() ldg[%p](%d) ", + lp, ldg); + + spin_lock_irqsave(&np->lock, flags); + + v0 = nr64(LDSV0(ldg)); + v1 = nr64(LDSV1(ldg)); + v2 = nr64(LDSV2(ldg)); + + if (netif_msg_intr(np)) + printk("v0[%llx] v1[%llx] v2[%llx]\n", + (unsigned long long) v0, + (unsigned long long) v1, + (unsigned long long) v2); + + if (unlikely(!v0 && !v1 && !v2)) { + spin_unlock_irqrestore(&np->lock, flags); + return IRQ_NONE; + } + + if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) { + int err = niu_slowpath_interrupt(np, lp); + if (err) + goto out; + } + if (likely(v0 & ~((u64)1 << LDN_MIF))) + niu_schedule_napi(np, lp, v0, v1, v2); + else + niu_ldg_rearm(np, lp, 1); +out: + spin_unlock_irqrestore(&np->lock, flags); + + return IRQ_HANDLED; +} + +static void niu_free_rx_ring_info(struct niu *np, struct rx_ring_info *rp) +{ + if (rp->mbox) { + np->ops->free_coherent(np->device, + sizeof(struct rxdma_mailbox), + rp->mbox, rp->mbox_dma); + rp->mbox = NULL; + } + if (rp->rcr) { + np->ops->free_coherent(np->device, + MAX_RCR_RING_SIZE * sizeof(__le64), + rp->rcr, rp->rcr_dma); + rp->rcr = NULL; + rp->rcr_table_size = 0; + rp->rcr_index = 0; + } + if (rp->rbr) { + niu_rbr_free(np, rp); + + np->ops->free_coherent(np->device, + MAX_RBR_RING_SIZE * sizeof(__le32), + rp->rbr, rp->rbr_dma); + rp->rbr = NULL; + rp->rbr_table_size = 0; + rp->rbr_index = 0; + } + kfree(rp->rxhash); + rp->rxhash = NULL; +} + +static void niu_free_tx_ring_info(struct niu *np, struct tx_ring_info *rp) +{ + if (rp->mbox) { + np->ops->free_coherent(np->device, + sizeof(struct txdma_mailbox), + rp->mbox, rp->mbox_dma); + rp->mbox = NULL; + } + if (rp->descr) { + int i; + + for (i = 0; i < MAX_TX_RING_SIZE; i++) { + if (rp->tx_buffs[i].skb) + (void) release_tx_packet(np, rp, i); + } + + np->ops->free_coherent(np->device, + MAX_TX_RING_SIZE * sizeof(__le64), + rp->descr, rp->descr_dma); + rp->descr = NULL; + rp->pending = 0; + rp->prod = 0; + rp->cons = 0; + rp->wrap_bit = 0; + } +} + +static void niu_free_channels(struct niu *np) +{ + int i; + + if (np->rx_rings) { + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + niu_free_rx_ring_info(np, rp); + } + kfree(np->rx_rings); + np->rx_rings = NULL; + np->num_rx_rings = 0; + } + + if (np->tx_rings) { + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + niu_free_tx_ring_info(np, rp); + } + kfree(np->tx_rings); + np->tx_rings = NULL; + np->num_tx_rings = 0; + } +} + +static int niu_alloc_rx_ring_info(struct niu *np, + struct rx_ring_info *rp) +{ + BUILD_BUG_ON(sizeof(struct rxdma_mailbox) != 64); + + rp->rxhash = kzalloc(MAX_RBR_RING_SIZE * sizeof(struct page *), + GFP_KERNEL); + if (!rp->rxhash) + return -ENOMEM; + + rp->mbox = np->ops->alloc_coherent(np->device, + sizeof(struct rxdma_mailbox), + &rp->mbox_dma, GFP_KERNEL); + if (!rp->mbox) + return -ENOMEM; + if ((unsigned long)rp->mbox & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "RXDMA mailbox %p\n", np->dev->name, rp->mbox); + return -EINVAL; + } + + rp->rcr = np->ops->alloc_coherent(np->device, + MAX_RCR_RING_SIZE * sizeof(__le64), + &rp->rcr_dma, GFP_KERNEL); + if (!rp->rcr) + return -ENOMEM; + if ((unsigned long)rp->rcr & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "RXDMA RCR table %p\n", np->dev->name, rp->rcr); + return -EINVAL; + } + rp->rcr_table_size = MAX_RCR_RING_SIZE; + rp->rcr_index = 0; + + rp->rbr = np->ops->alloc_coherent(np->device, + MAX_RBR_RING_SIZE * sizeof(__le32), + &rp->rbr_dma, GFP_KERNEL); + if (!rp->rbr) + return -ENOMEM; + if ((unsigned long)rp->rbr & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "RXDMA RBR table %p\n", np->dev->name, rp->rbr); + return -EINVAL; + } + rp->rbr_table_size = MAX_RBR_RING_SIZE; + rp->rbr_index = 0; + rp->rbr_pending = 0; + + return 0; +} + +static void niu_set_max_burst(struct niu *np, struct tx_ring_info *rp) +{ + int mtu = np->dev->mtu; + + /* These values are recommended by the HW designers for fair + * utilization of DRR amongst the rings. + */ + rp->max_burst = mtu + 32; + if (rp->max_burst > 4096) + rp->max_burst = 4096; +} + +static int niu_alloc_tx_ring_info(struct niu *np, + struct tx_ring_info *rp) +{ + BUILD_BUG_ON(sizeof(struct txdma_mailbox) != 64); + + rp->mbox = np->ops->alloc_coherent(np->device, + sizeof(struct txdma_mailbox), + &rp->mbox_dma, GFP_KERNEL); + if (!rp->mbox) + return -ENOMEM; + if ((unsigned long)rp->mbox & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "TXDMA mailbox %p\n", np->dev->name, rp->mbox); + return -EINVAL; + } + + rp->descr = np->ops->alloc_coherent(np->device, + MAX_TX_RING_SIZE * sizeof(__le64), + &rp->descr_dma, GFP_KERNEL); + if (!rp->descr) + return -ENOMEM; + if ((unsigned long)rp->descr & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "TXDMA descr table %p\n", np->dev->name, rp->descr); + return -EINVAL; + } + + rp->pending = MAX_TX_RING_SIZE; + rp->prod = 0; + rp->cons = 0; + rp->wrap_bit = 0; + + /* XXX make these configurable... XXX */ + rp->mark_freq = rp->pending / 4; + + niu_set_max_burst(np, rp); + + return 0; +} + +static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp) +{ + u16 bs; + + switch (PAGE_SIZE) { + case 4 * 1024: + case 8 * 1024: + case 16 * 1024: + case 32 * 1024: + rp->rbr_block_size = PAGE_SIZE; + rp->rbr_blocks_per_page = 1; + break; + + default: + if (PAGE_SIZE % (32 * 1024) == 0) + bs = 32 * 1024; + else if (PAGE_SIZE % (16 * 1024) == 0) + bs = 16 * 1024; + else if (PAGE_SIZE % (8 * 1024) == 0) + bs = 8 * 1024; + else if (PAGE_SIZE % (4 * 1024) == 0) + bs = 4 * 1024; + else + BUG(); + rp->rbr_block_size = bs; + rp->rbr_blocks_per_page = PAGE_SIZE / bs; + } + + rp->rbr_sizes[0] = 256; + rp->rbr_sizes[1] = 1024; + if (np->dev->mtu > ETH_DATA_LEN) { + switch (PAGE_SIZE) { + case 4 * 1024: + rp->rbr_sizes[2] = 4096; + break; + + default: + rp->rbr_sizes[2] = 8192; + break; + } + } else { + rp->rbr_sizes[2] = 2048; + } + rp->rbr_sizes[3] = rp->rbr_block_size; +} + +static int niu_alloc_channels(struct niu *np) +{ + struct niu_parent *parent = np->parent; + int first_rx_channel, first_tx_channel; + int i, port, err; + + port = np->port; + first_rx_channel = first_tx_channel = 0; + for (i = 0; i < port; i++) { + first_rx_channel += parent->rxchan_per_port[i]; + first_tx_channel += parent->txchan_per_port[i]; + } + + np->num_rx_rings = parent->rxchan_per_port[port]; + np->num_tx_rings = parent->txchan_per_port[port]; + + np->rx_rings = kzalloc(np->num_rx_rings * sizeof(struct rx_ring_info), + GFP_KERNEL); + err = -ENOMEM; + if (!np->rx_rings) + goto out_err; + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + rp->np = np; + rp->rx_channel = first_rx_channel + i; + + err = niu_alloc_rx_ring_info(np, rp); + if (err) + goto out_err; + + niu_size_rbr(np, rp); + + /* XXX better defaults, configurable, etc... XXX */ + rp->nonsyn_window = 64; + rp->nonsyn_threshold = rp->rcr_table_size - 64; + rp->syn_window = 64; + rp->syn_threshold = rp->rcr_table_size - 64; + rp->rcr_pkt_threshold = 16; + rp->rcr_timeout = 8; + rp->rbr_kick_thresh = RBR_REFILL_MIN; + if (rp->rbr_kick_thresh < rp->rbr_blocks_per_page) + rp->rbr_kick_thresh = rp->rbr_blocks_per_page; + + err = niu_rbr_fill(np, rp, GFP_KERNEL); + if (err) + return err; + } + + np->tx_rings = kzalloc(np->num_tx_rings * sizeof(struct tx_ring_info), + GFP_KERNEL); + err = -ENOMEM; + if (!np->tx_rings) + goto out_err; + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + rp->np = np; + rp->tx_channel = first_tx_channel + i; + + err = niu_alloc_tx_ring_info(np, rp); + if (err) + goto out_err; + } + + return 0; + +out_err: + niu_free_channels(np); + return err; +} + +static int niu_tx_cs_sng_poll(struct niu *np, int channel) +{ + int limit = 1000; + + while (--limit > 0) { + u64 val = nr64(TX_CS(channel)); + if (val & TX_CS_SNG_STATE) + return 0; + } + return -ENODEV; +} + +static int niu_tx_channel_stop(struct niu *np, int channel) +{ + u64 val = nr64(TX_CS(channel)); + + val |= TX_CS_STOP_N_GO; + nw64(TX_CS(channel), val); + + return niu_tx_cs_sng_poll(np, channel); +} + +static int niu_tx_cs_reset_poll(struct niu *np, int channel) +{ + int limit = 1000; + + while (--limit > 0) { + u64 val = nr64(TX_CS(channel)); + if (!(val & TX_CS_RST)) + return 0; + } + return -ENODEV; +} + +static int niu_tx_channel_reset(struct niu *np, int channel) +{ + u64 val = nr64(TX_CS(channel)); + int err; + + val |= TX_CS_RST; + nw64(TX_CS(channel), val); + + err = niu_tx_cs_reset_poll(np, channel); + if (!err) + nw64(TX_RING_KICK(channel), 0); + + return err; +} + +static int niu_tx_channel_lpage_init(struct niu *np, int channel) +{ + u64 val; + + nw64(TX_LOG_MASK1(channel), 0); + nw64(TX_LOG_VAL1(channel), 0); + nw64(TX_LOG_MASK2(channel), 0); + nw64(TX_LOG_VAL2(channel), 0); + nw64(TX_LOG_PAGE_RELO1(channel), 0); + nw64(TX_LOG_PAGE_RELO2(channel), 0); + nw64(TX_LOG_PAGE_HDL(channel), 0); + + val = (u64)np->port << TX_LOG_PAGE_VLD_FUNC_SHIFT; + val |= (TX_LOG_PAGE_VLD_PAGE0 | TX_LOG_PAGE_VLD_PAGE1); + nw64(TX_LOG_PAGE_VLD(channel), val); + + /* XXX TXDMA 32bit mode? XXX */ + + return 0; +} + +static void niu_txc_enable_port(struct niu *np, int on) +{ + unsigned long flags; + u64 val, mask; + + niu_lock_parent(np, flags); + val = nr64(TXC_CONTROL); + mask = (u64)1 << np->port; + if (on) { + val |= TXC_CONTROL_ENABLE | mask; + } else { + val &= ~mask; + if ((val & ~TXC_CONTROL_ENABLE) == 0) + val &= ~TXC_CONTROL_ENABLE; + } + nw64(TXC_CONTROL, val); + niu_unlock_parent(np, flags); +} + +static void niu_txc_set_imask(struct niu *np, u64 imask) +{ + unsigned long flags; + u64 val; + + niu_lock_parent(np, flags); + val = nr64(TXC_INT_MASK); + val &= ~TXC_INT_MASK_VAL(np->port); + val |= (imask << TXC_INT_MASK_VAL_SHIFT(np->port)); + niu_unlock_parent(np, flags); +} + +static void niu_txc_port_dma_enable(struct niu *np, int on) +{ + u64 val = 0; + + if (on) { + int i; + + for (i = 0; i < np->num_tx_rings; i++) + val |= (1 << np->tx_rings[i].tx_channel); + } + nw64(TXC_PORT_DMA(np->port), val); +} + +static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp) +{ + int err, channel = rp->tx_channel; + u64 val, ring_len; + + err = niu_tx_channel_stop(np, channel); + if (err) + return err; + + err = niu_tx_channel_reset(np, channel); + if (err) + return err; + + err = niu_tx_channel_lpage_init(np, channel); + if (err) + return err; + + nw64(TXC_DMA_MAX(channel), rp->max_burst); + nw64(TX_ENT_MSK(channel), 0); + + if (rp->descr_dma & ~(TX_RNG_CFIG_STADDR_BASE | + TX_RNG_CFIG_STADDR)) { + dev_err(np->device, PFX "%s: TX ring channel %d " + "DMA addr (%llx) is not aligned.\n", + np->dev->name, channel, + (unsigned long long) rp->descr_dma); + return -EINVAL; + } + + /* The length field in TX_RNG_CFIG is measured in 64-byte + * blocks. rp->pending is the number of TX descriptors in + * our ring, 8 bytes each, thus we divide by 8 bytes more + * to get the proper value the chip wants. + */ + ring_len = (rp->pending / 8); + + val = ((ring_len << TX_RNG_CFIG_LEN_SHIFT) | + rp->descr_dma); + nw64(TX_RNG_CFIG(channel), val); + + if (((rp->mbox_dma >> 32) & ~TXDMA_MBH_MBADDR) || + ((u32)rp->mbox_dma & ~TXDMA_MBL_MBADDR)) { + dev_err(np->device, PFX "%s: TX ring channel %d " + "MBOX addr (%llx) is has illegal bits.\n", + np->dev->name, channel, + (unsigned long long) rp->mbox_dma); + return -EINVAL; + } + nw64(TXDMA_MBH(channel), rp->mbox_dma >> 32); + nw64(TXDMA_MBL(channel), rp->mbox_dma & TXDMA_MBL_MBADDR); + + nw64(TX_CS(channel), 0); + + rp->last_pkt_cnt = 0; + + return 0; +} + +static void niu_init_rdc_groups(struct niu *np) +{ + struct niu_rdc_tables *tp = &np->parent->rdc_group_cfg[np->port]; + int i, first_table_num = tp->first_table_num; + + for (i = 0; i < tp->num_tables; i++) { + struct rdc_table *tbl = &tp->tables[i]; + int this_table = first_table_num + i; + int slot; + + for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) + nw64(RDC_TBL(this_table, slot), + tbl->rxdma_channel[slot]); + } + + nw64(DEF_RDC(np->port), np->parent->rdc_default[np->port]); +} + +static void niu_init_drr_weight(struct niu *np) +{ + int type = phy_decode(np->parent->port_phy, np->port); + u64 val; + + switch (type) { + case PORT_TYPE_10G: + val = PT_DRR_WEIGHT_DEFAULT_10G; + break; + + case PORT_TYPE_1G: + default: + val = PT_DRR_WEIGHT_DEFAULT_1G; + break; + } + nw64(PT_DRR_WT(np->port), val); +} + +static int niu_init_hostinfo(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port]; + int i, err, num_alt = niu_num_alt_addr(np); + int first_rdc_table = tp->first_table_num; + + err = niu_set_primary_mac_rdc_table(np, first_rdc_table, 1); + if (err) + return err; + + err = niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1); + if (err) + return err; + + for (i = 0; i < num_alt; i++) { + err = niu_set_alt_mac_rdc_table(np, i, first_rdc_table, 1); + if (err) + return err; + } + + return 0; +} + +static int niu_rx_channel_reset(struct niu *np, int channel) +{ + return niu_set_and_wait_clear(np, RXDMA_CFIG1(channel), + RXDMA_CFIG1_RST, 1000, 10, + "RXDMA_CFIG1"); +} + +static int niu_rx_channel_lpage_init(struct niu *np, int channel) +{ + u64 val; + + nw64(RX_LOG_MASK1(channel), 0); + nw64(RX_LOG_VAL1(channel), 0); + nw64(RX_LOG_MASK2(channel), 0); + nw64(RX_LOG_VAL2(channel), 0); + nw64(RX_LOG_PAGE_RELO1(channel), 0); + nw64(RX_LOG_PAGE_RELO2(channel), 0); + nw64(RX_LOG_PAGE_HDL(channel), 0); + + val = (u64)np->port << RX_LOG_PAGE_VLD_FUNC_SHIFT; + val |= (RX_LOG_PAGE_VLD_PAGE0 | RX_LOG_PAGE_VLD_PAGE1); + nw64(RX_LOG_PAGE_VLD(channel), val); + + return 0; +} + +static void niu_rx_channel_wred_init(struct niu *np, struct rx_ring_info *rp) +{ + u64 val; + + val = (((u64)rp->nonsyn_window << RDC_RED_PARA_WIN_SHIFT) | + ((u64)rp->nonsyn_threshold << RDC_RED_PARA_THRE_SHIFT) | + ((u64)rp->syn_window << RDC_RED_PARA_WIN_SYN_SHIFT) | + ((u64)rp->syn_threshold << RDC_RED_PARA_THRE_SYN_SHIFT)); + nw64(RDC_RED_PARA(rp->rx_channel), val); +} + +static int niu_compute_rbr_cfig_b(struct rx_ring_info *rp, u64 *ret) +{ + u64 val = 0; + + switch (rp->rbr_block_size) { + case 4 * 1024: + val |= (RBR_BLKSIZE_4K << RBR_CFIG_B_BLKSIZE_SHIFT); + break; + case 8 * 1024: + val |= (RBR_BLKSIZE_8K << RBR_CFIG_B_BLKSIZE_SHIFT); + break; + case 16 * 1024: + val |= (RBR_BLKSIZE_16K << RBR_CFIG_B_BLKSIZE_SHIFT); + break; + case 32 * 1024: + val |= (RBR_BLKSIZE_32K << RBR_CFIG_B_BLKSIZE_SHIFT); + break; + default: + return -EINVAL; + } + val |= RBR_CFIG_B_VLD2; + switch (rp->rbr_sizes[2]) { + case 2 * 1024: + val |= (RBR_BUFSZ2_2K << RBR_CFIG_B_BUFSZ2_SHIFT); + break; + case 4 * 1024: + val |= (RBR_BUFSZ2_4K << RBR_CFIG_B_BUFSZ2_SHIFT); + break; + case 8 * 1024: + val |= (RBR_BUFSZ2_8K << RBR_CFIG_B_BUFSZ2_SHIFT); + break; + case 16 * 1024: + val |= (RBR_BUFSZ2_16K << RBR_CFIG_B_BUFSZ2_SHIFT); + break; + + default: + return -EINVAL; + } + val |= RBR_CFIG_B_VLD1; + switch (rp->rbr_sizes[1]) { + case 1 * 1024: + val |= (RBR_BUFSZ1_1K << RBR_CFIG_B_BUFSZ1_SHIFT); + break; + case 2 * 1024: + val |= (RBR_BUFSZ1_2K << RBR_CFIG_B_BUFSZ1_SHIFT); + break; + case 4 * 1024: + val |= (RBR_BUFSZ1_4K << RBR_CFIG_B_BUFSZ1_SHIFT); + break; + case 8 * 1024: + val |= (RBR_BUFSZ1_8K << RBR_CFIG_B_BUFSZ1_SHIFT); + break; + + default: + return -EINVAL; + } + val |= RBR_CFIG_B_VLD0; + switch (rp->rbr_sizes[0]) { + case 256: + val |= (RBR_BUFSZ0_256 << RBR_CFIG_B_BUFSZ0_SHIFT); + break; + case 512: + val |= (RBR_BUFSZ0_512 << RBR_CFIG_B_BUFSZ0_SHIFT); + break; + case 1 * 1024: + val |= (RBR_BUFSZ0_1K << RBR_CFIG_B_BUFSZ0_SHIFT); + break; + case 2 * 1024: + val |= (RBR_BUFSZ0_2K << RBR_CFIG_B_BUFSZ0_SHIFT); + break; + + default: + return -EINVAL; + } + + *ret = val; + return 0; +} + +static int niu_enable_rx_channel(struct niu *np, int channel, int on) +{ + u64 val = nr64(RXDMA_CFIG1(channel)); + int limit; + + if (on) + val |= RXDMA_CFIG1_EN; + else + val &= ~RXDMA_CFIG1_EN; + nw64(RXDMA_CFIG1(channel), val); + + limit = 1000; + while (--limit > 0) { + if (nr64(RXDMA_CFIG1(channel)) & RXDMA_CFIG1_QST) + break; + udelay(10); + } + if (limit <= 0) + return -ENODEV; + return 0; +} + +static int niu_init_one_rx_channel(struct niu *np, struct rx_ring_info *rp) +{ + int err, channel = rp->rx_channel; + u64 val; + + err = niu_rx_channel_reset(np, channel); + if (err) + return err; + + err = niu_rx_channel_lpage_init(np, channel); + if (err) + return err; + + niu_rx_channel_wred_init(np, rp); + + nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_RBR_EMPTY); + nw64(RX_DMA_CTL_STAT(channel), + (RX_DMA_CTL_STAT_MEX | + RX_DMA_CTL_STAT_RCRTHRES | + RX_DMA_CTL_STAT_RCRTO | + RX_DMA_CTL_STAT_RBR_EMPTY)); + nw64(RXDMA_CFIG1(channel), rp->mbox_dma >> 32); + nw64(RXDMA_CFIG2(channel), (rp->mbox_dma & 0x00000000ffffffc0)); + nw64(RBR_CFIG_A(channel), + ((u64)rp->rbr_table_size << RBR_CFIG_A_LEN_SHIFT) | + (rp->rbr_dma & (RBR_CFIG_A_STADDR_BASE | RBR_CFIG_A_STADDR))); + err = niu_compute_rbr_cfig_b(rp, &val); + if (err) + return err; + nw64(RBR_CFIG_B(channel), val); + nw64(RCRCFIG_A(channel), + ((u64)rp->rcr_table_size << RCRCFIG_A_LEN_SHIFT) | + (rp->rcr_dma & (RCRCFIG_A_STADDR_BASE | RCRCFIG_A_STADDR))); + nw64(RCRCFIG_B(channel), + ((u64)rp->rcr_pkt_threshold << RCRCFIG_B_PTHRES_SHIFT) | + RCRCFIG_B_ENTOUT | + ((u64)rp->rcr_timeout << RCRCFIG_B_TIMEOUT_SHIFT)); + + err = niu_enable_rx_channel(np, channel, 1); + if (err) + return err; + + nw64(RBR_KICK(channel), rp->rbr_index); + + val = nr64(RX_DMA_CTL_STAT(channel)); + val |= RX_DMA_CTL_STAT_RBR_EMPTY; + nw64(RX_DMA_CTL_STAT(channel), val); + + return 0; +} + +static int niu_init_rx_channels(struct niu *np) +{ + unsigned long flags; + u64 seed = jiffies_64; + int err, i; + + niu_lock_parent(np, flags); + nw64(RX_DMA_CK_DIV, np->parent->rxdma_clock_divider); + nw64(RED_RAN_INIT, RED_RAN_INIT_OPMODE | (seed & RED_RAN_INIT_VAL)); + niu_unlock_parent(np, flags); + + /* XXX RXDMA 32bit mode? XXX */ + + niu_init_rdc_groups(np); + niu_init_drr_weight(np); + + err = niu_init_hostinfo(np); + if (err) + return err; + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + err = niu_init_one_rx_channel(np, rp); + if (err) + return err; + } + + return 0; +} + +static int niu_set_ip_frag_rule(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_classifier *cp = &np->clas; + struct niu_tcam_entry *tp; + int index, err; + + /* XXX fix this allocation scheme XXX */ + index = cp->tcam_index; + tp = &parent->tcam[index]; + + /* Note that the noport bit is the same in both ipv4 and + * ipv6 format TCAM entries. + */ + memset(tp, 0, sizeof(*tp)); + tp->key[1] = TCAM_V4KEY1_NOPORT; + tp->key_mask[1] = TCAM_V4KEY1_NOPORT; + tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET | + ((u64)0 << TCAM_ASSOCDATA_OFFSET_SHIFT)); + err = tcam_write(np, index, tp->key, tp->key_mask); + if (err) + return err; + err = tcam_assoc_write(np, index, tp->assoc_data); + if (err) + return err; + + return 0; +} + +static int niu_init_classifier_hw(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_classifier *cp = &np->clas; + int i, err; + + nw64(H1POLY, cp->h1_init); + nw64(H2POLY, cp->h2_init); + + err = niu_init_hostinfo(np); + if (err) + return err; + + for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++) { + struct niu_vlan_rdc *vp = &cp->vlan_mappings[i]; + + vlan_tbl_write(np, i, np->port, + vp->vlan_pref, vp->rdc_num); + } + + for (i = 0; i < cp->num_alt_mac_mappings; i++) { + struct niu_altmac_rdc *ap = &cp->alt_mac_mappings[i]; + + err = niu_set_alt_mac_rdc_table(np, ap->alt_mac_num, + ap->rdc_num, ap->mac_pref); + if (err) + return err; + } + + for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) { + int index = i - CLASS_CODE_USER_PROG1; + + err = niu_set_tcam_key(np, i, parent->tcam_key[index]); + if (err) + return err; + err = niu_set_flow_key(np, i, parent->flow_key[index]); + if (err) + return err; + } + + err = niu_set_ip_frag_rule(np); + if (err) + return err; + + tcam_enable(np, 1); + + return 0; +} + +static int niu_zcp_write(struct niu *np, int index, u64 *data) +{ + nw64(ZCP_RAM_DATA0, data[0]); + nw64(ZCP_RAM_DATA1, data[1]); + nw64(ZCP_RAM_DATA2, data[2]); + nw64(ZCP_RAM_DATA3, data[3]); + nw64(ZCP_RAM_DATA4, data[4]); + nw64(ZCP_RAM_BE, ZCP_RAM_BE_VAL); + nw64(ZCP_RAM_ACC, + (ZCP_RAM_ACC_WRITE | + (0 << ZCP_RAM_ACC_ZFCID_SHIFT) | + (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT))); + + return niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY, + 1000, 100); +} + +static int niu_zcp_read(struct niu *np, int index, u64 *data) +{ + int err; + + err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY, + 1000, 100); + if (err) { + dev_err(np->device, PFX "%s: ZCP read busy won't clear, " + "ZCP_RAM_ACC[%llx]\n", np->dev->name, + (unsigned long long) nr64(ZCP_RAM_ACC)); + return err; + } + + nw64(ZCP_RAM_ACC, + (ZCP_RAM_ACC_READ | + (0 << ZCP_RAM_ACC_ZFCID_SHIFT) | + (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT))); + + err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY, + 1000, 100); + if (err) { + dev_err(np->device, PFX "%s: ZCP read busy2 won't clear, " + "ZCP_RAM_ACC[%llx]\n", np->dev->name, + (unsigned long long) nr64(ZCP_RAM_ACC)); + return err; + } + + data[0] = nr64(ZCP_RAM_DATA0); + data[1] = nr64(ZCP_RAM_DATA1); + data[2] = nr64(ZCP_RAM_DATA2); + data[3] = nr64(ZCP_RAM_DATA3); + data[4] = nr64(ZCP_RAM_DATA4); + + return 0; +} + +static void niu_zcp_cfifo_reset(struct niu *np) +{ + u64 val = nr64(RESET_CFIFO); + + val |= RESET_CFIFO_RST(np->port); + nw64(RESET_CFIFO, val); + udelay(10); + + val &= ~RESET_CFIFO_RST(np->port); + nw64(RESET_CFIFO, val); +} + +static int niu_init_zcp(struct niu *np) +{ + u64 data[5], rbuf[5]; + int i, max, err; + + if (np->parent->plat_type != PLAT_TYPE_NIU) { + if (np->port == 0 || np->port == 1) + max = ATLAS_P0_P1_CFIFO_ENTRIES; + else + max = ATLAS_P2_P3_CFIFO_ENTRIES; + } else + max = NIU_CFIFO_ENTRIES; + + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + + for (i = 0; i < max; i++) { + err = niu_zcp_write(np, i, data); + if (err) + return err; + err = niu_zcp_read(np, i, rbuf); + if (err) + return err; + } + + niu_zcp_cfifo_reset(np); + nw64(CFIFO_ECC(np->port), 0); + nw64(ZCP_INT_STAT, ZCP_INT_STAT_ALL); + (void) nr64(ZCP_INT_STAT); + nw64(ZCP_INT_MASK, ZCP_INT_MASK_ALL); + + return 0; +} + +static void niu_ipp_write(struct niu *np, int index, u64 *data) +{ + u64 val = nr64_ipp(IPP_CFIG); + + nw64_ipp(IPP_CFIG, val | IPP_CFIG_DFIFO_PIO_W); + nw64_ipp(IPP_DFIFO_WR_PTR, index); + nw64_ipp(IPP_DFIFO_WR0, data[0]); + nw64_ipp(IPP_DFIFO_WR1, data[1]); + nw64_ipp(IPP_DFIFO_WR2, data[2]); + nw64_ipp(IPP_DFIFO_WR3, data[3]); + nw64_ipp(IPP_DFIFO_WR4, data[4]); + nw64_ipp(IPP_CFIG, val & ~IPP_CFIG_DFIFO_PIO_W); +} + +static void niu_ipp_read(struct niu *np, int index, u64 *data) +{ + nw64_ipp(IPP_DFIFO_RD_PTR, index); + data[0] = nr64_ipp(IPP_DFIFO_RD0); + data[1] = nr64_ipp(IPP_DFIFO_RD1); + data[2] = nr64_ipp(IPP_DFIFO_RD2); + data[3] = nr64_ipp(IPP_DFIFO_RD3); + data[4] = nr64_ipp(IPP_DFIFO_RD4); +} + +static int niu_ipp_reset(struct niu *np) +{ + return niu_set_and_wait_clear_ipp(np, IPP_CFIG, IPP_CFIG_SOFT_RST, + 1000, 100, "IPP_CFIG"); +} + +static int niu_init_ipp(struct niu *np) +{ + u64 data[5], rbuf[5], val; + int i, max, err; + + if (np->parent->plat_type != PLAT_TYPE_NIU) { + if (np->port == 0 || np->port == 1) + max = ATLAS_P0_P1_DFIFO_ENTRIES; + else + max = ATLAS_P2_P3_DFIFO_ENTRIES; + } else + max = NIU_DFIFO_ENTRIES; + + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + + for (i = 0; i < max; i++) { + niu_ipp_write(np, i, data); + niu_ipp_read(np, i, rbuf); + } + + (void) nr64_ipp(IPP_INT_STAT); + (void) nr64_ipp(IPP_INT_STAT); + + err = niu_ipp_reset(np); + if (err) + return err; + + (void) nr64_ipp(IPP_PKT_DIS); + (void) nr64_ipp(IPP_BAD_CS_CNT); + (void) nr64_ipp(IPP_ECC); + + (void) nr64_ipp(IPP_INT_STAT); + + nw64_ipp(IPP_MSK, ~IPP_MSK_ALL); + + val = nr64_ipp(IPP_CFIG); + val &= ~IPP_CFIG_IP_MAX_PKT; + val |= (IPP_CFIG_IPP_ENABLE | + IPP_CFIG_DFIFO_ECC_EN | + IPP_CFIG_DROP_BAD_CRC | + IPP_CFIG_CKSUM_EN | + (0x1ffff << IPP_CFIG_IP_MAX_PKT_SHIFT)); + nw64_ipp(IPP_CFIG, val); + + return 0; +} + +static void niu_init_xif_xmac(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u64 val; + + val = nr64_mac(XMAC_CONFIG); + + if ((np->flags & NIU_FLAGS_10G) != 0 && + (np->flags & NIU_FLAGS_FIBER) != 0) { + if (netif_carrier_ok(np->dev)) { + val |= XMAC_CONFIG_LED_POLARITY; + val &= ~XMAC_CONFIG_FORCE_LED_ON; + } else { + val |= XMAC_CONFIG_FORCE_LED_ON; + val &= ~XMAC_CONFIG_LED_POLARITY; + } + } + + val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC; + + val |= XMAC_CONFIG_TX_OUTPUT_EN; + + if (lp->loopback_mode == LOOPBACK_MAC) { + val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC; + val |= XMAC_CONFIG_LOOPBACK; + } else { + val &= ~XMAC_CONFIG_LOOPBACK; + } + + if (np->flags & NIU_FLAGS_10G) { + val &= ~XMAC_CONFIG_LFS_DISABLE; + } else { + val |= XMAC_CONFIG_LFS_DISABLE; + if (!(np->flags & NIU_FLAGS_FIBER)) + val |= XMAC_CONFIG_1G_PCS_BYPASS; + else + val &= ~XMAC_CONFIG_1G_PCS_BYPASS; + } + + val &= ~XMAC_CONFIG_10G_XPCS_BYPASS; + + if (lp->active_speed == SPEED_100) + val |= XMAC_CONFIG_SEL_CLK_25MHZ; + else + val &= ~XMAC_CONFIG_SEL_CLK_25MHZ; + + nw64_mac(XMAC_CONFIG, val); + + val = nr64_mac(XMAC_CONFIG); + val &= ~XMAC_CONFIG_MODE_MASK; + if (np->flags & NIU_FLAGS_10G) { + val |= XMAC_CONFIG_MODE_XGMII; + } else { + if (lp->active_speed == SPEED_100) + val |= XMAC_CONFIG_MODE_MII; + else + val |= XMAC_CONFIG_MODE_GMII; + } + + nw64_mac(XMAC_CONFIG, val); +} + +static void niu_init_xif_bmac(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u64 val; + + val = BMAC_XIF_CONFIG_TX_OUTPUT_EN; + + if (lp->loopback_mode == LOOPBACK_MAC) + val |= BMAC_XIF_CONFIG_MII_LOOPBACK; + else + val &= ~BMAC_XIF_CONFIG_MII_LOOPBACK; + + if (lp->active_speed == SPEED_1000) + val |= BMAC_XIF_CONFIG_GMII_MODE; + else + val &= ~BMAC_XIF_CONFIG_GMII_MODE; + + val &= ~(BMAC_XIF_CONFIG_LINK_LED | + BMAC_XIF_CONFIG_LED_POLARITY); + + if (!(np->flags & NIU_FLAGS_10G) && + !(np->flags & NIU_FLAGS_FIBER) && + lp->active_speed == SPEED_100) + val |= BMAC_XIF_CONFIG_25MHZ_CLOCK; + else + val &= ~BMAC_XIF_CONFIG_25MHZ_CLOCK; + + nw64_mac(BMAC_XIF_CONFIG, val); +} + +static void niu_init_xif(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_init_xif_xmac(np); + else + niu_init_xif_bmac(np); +} + +static void niu_pcs_mii_reset(struct niu *np) +{ + u64 val = nr64_pcs(PCS_MII_CTL); + val |= PCS_MII_CTL_RST; + nw64_pcs(PCS_MII_CTL, val); +} + +static void niu_xpcs_reset(struct niu *np) +{ + u64 val = nr64_xpcs(XPCS_CONTROL1); + val |= XPCS_CONTROL1_RESET; + nw64_xpcs(XPCS_CONTROL1, val); +} + +static int niu_init_pcs(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u64 val; + + switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) { + case NIU_FLAGS_FIBER: + /* 1G fiber */ + nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE); + nw64_pcs(PCS_DPATH_MODE, 0); + niu_pcs_mii_reset(np); + break; + + case NIU_FLAGS_10G: + case NIU_FLAGS_10G | NIU_FLAGS_FIBER: + if (!(np->flags & NIU_FLAGS_XMAC)) + return -EINVAL; + + /* 10G copper or fiber */ + val = nr64_mac(XMAC_CONFIG); + val &= ~XMAC_CONFIG_10G_XPCS_BYPASS; + nw64_mac(XMAC_CONFIG, val); + + niu_xpcs_reset(np); + + val = nr64_xpcs(XPCS_CONTROL1); + if (lp->loopback_mode == LOOPBACK_PHY) + val |= XPCS_CONTROL1_LOOPBACK; + else + val &= ~XPCS_CONTROL1_LOOPBACK; + nw64_xpcs(XPCS_CONTROL1, val); + + nw64_xpcs(XPCS_DESKEW_ERR_CNT, 0); + (void) nr64_xpcs(XPCS_SYMERR_CNT01); + (void) nr64_xpcs(XPCS_SYMERR_CNT23); + break; + + case 0: + /* 1G copper */ + nw64_pcs(PCS_DPATH_MODE, PCS_DPATH_MODE_MII); + niu_pcs_mii_reset(np); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int niu_reset_tx_xmac(struct niu *np) +{ + return niu_set_and_wait_clear_mac(np, XTXMAC_SW_RST, + (XTXMAC_SW_RST_REG_RS | + XTXMAC_SW_RST_SOFT_RST), + 1000, 100, "XTXMAC_SW_RST"); +} + +static int niu_reset_tx_bmac(struct niu *np) +{ + int limit; + + nw64_mac(BTXMAC_SW_RST, BTXMAC_SW_RST_RESET); + limit = 1000; + while (--limit >= 0) { + if (!(nr64_mac(BTXMAC_SW_RST) & BTXMAC_SW_RST_RESET)) + break; + udelay(100); + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u TX BMAC would not reset, " + "BTXMAC_SW_RST[%llx]\n", + np->port, + (unsigned long long) nr64_mac(BTXMAC_SW_RST)); + return -ENODEV; + } + + return 0; +} + +static int niu_reset_tx_mac(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + return niu_reset_tx_xmac(np); + else + return niu_reset_tx_bmac(np); +} + +static void niu_init_tx_xmac(struct niu *np, u64 min, u64 max) +{ + u64 val; + + val = nr64_mac(XMAC_MIN); + val &= ~(XMAC_MIN_TX_MIN_PKT_SIZE | + XMAC_MIN_RX_MIN_PKT_SIZE); + val |= (min << XMAC_MIN_RX_MIN_PKT_SIZE_SHFT); + val |= (min << XMAC_MIN_TX_MIN_PKT_SIZE_SHFT); + nw64_mac(XMAC_MIN, val); + + nw64_mac(XMAC_MAX, max); + + nw64_mac(XTXMAC_STAT_MSK, ~(u64)0); + + val = nr64_mac(XMAC_IPG); + if (np->flags & NIU_FLAGS_10G) { + val &= ~XMAC_IPG_IPG_XGMII; + val |= (IPG_12_15_XGMII << XMAC_IPG_IPG_XGMII_SHIFT); + } else { + val &= ~XMAC_IPG_IPG_MII_GMII; + val |= (IPG_12_MII_GMII << XMAC_IPG_IPG_MII_GMII_SHIFT); + } + nw64_mac(XMAC_IPG, val); + + val = nr64_mac(XMAC_CONFIG); + val &= ~(XMAC_CONFIG_ALWAYS_NO_CRC | + XMAC_CONFIG_STRETCH_MODE | + XMAC_CONFIG_VAR_MIN_IPG_EN | + XMAC_CONFIG_TX_ENABLE); + nw64_mac(XMAC_CONFIG, val); + + nw64_mac(TXMAC_FRM_CNT, 0); + nw64_mac(TXMAC_BYTE_CNT, 0); +} + +static void niu_init_tx_bmac(struct niu *np, u64 min, u64 max) +{ + u64 val; + + nw64_mac(BMAC_MIN_FRAME, min); + nw64_mac(BMAC_MAX_FRAME, max); + + nw64_mac(BTXMAC_STATUS_MASK, ~(u64)0); + nw64_mac(BMAC_CTRL_TYPE, 0x8808); + nw64_mac(BMAC_PREAMBLE_SIZE, 7); + + val = nr64_mac(BTXMAC_CONFIG); + val &= ~(BTXMAC_CONFIG_FCS_DISABLE | + BTXMAC_CONFIG_ENABLE); + nw64_mac(BTXMAC_CONFIG, val); +} + +static void niu_init_tx_mac(struct niu *np) +{ + u64 min, max; + + min = 64; + if (np->dev->mtu > ETH_DATA_LEN) + max = 9216; + else + max = 1522; + + /* The XMAC_MIN register only accepts values for TX min which + * have the low 3 bits cleared. + */ + BUILD_BUG_ON(min & 0x7); + + if (np->flags & NIU_FLAGS_XMAC) + niu_init_tx_xmac(np, min, max); + else + niu_init_tx_bmac(np, min, max); +} + +static int niu_reset_rx_xmac(struct niu *np) +{ + int limit; + + nw64_mac(XRXMAC_SW_RST, + XRXMAC_SW_RST_REG_RS | XRXMAC_SW_RST_SOFT_RST); + limit = 1000; + while (--limit >= 0) { + if (!(nr64_mac(XRXMAC_SW_RST) & (XRXMAC_SW_RST_REG_RS | + XRXMAC_SW_RST_SOFT_RST))) + break; + udelay(100); + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u RX XMAC would not reset, " + "XRXMAC_SW_RST[%llx]\n", + np->port, + (unsigned long long) nr64_mac(XRXMAC_SW_RST)); + return -ENODEV; + } + + return 0; +} + +static int niu_reset_rx_bmac(struct niu *np) +{ + int limit; + + nw64_mac(BRXMAC_SW_RST, BRXMAC_SW_RST_RESET); + limit = 1000; + while (--limit >= 0) { + if (!(nr64_mac(BRXMAC_SW_RST) & BRXMAC_SW_RST_RESET)) + break; + udelay(100); + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u RX BMAC would not reset, " + "BRXMAC_SW_RST[%llx]\n", + np->port, + (unsigned long long) nr64_mac(BRXMAC_SW_RST)); + return -ENODEV; + } + + return 0; +} + +static int niu_reset_rx_mac(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + return niu_reset_rx_xmac(np); + else + return niu_reset_rx_bmac(np); +} + +static void niu_init_rx_xmac(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port]; + int first_rdc_table = tp->first_table_num; + unsigned long i; + u64 val; + + nw64_mac(XMAC_ADD_FILT0, 0); + nw64_mac(XMAC_ADD_FILT1, 0); + nw64_mac(XMAC_ADD_FILT2, 0); + nw64_mac(XMAC_ADD_FILT12_MASK, 0); + nw64_mac(XMAC_ADD_FILT00_MASK, 0); + for (i = 0; i < MAC_NUM_HASH; i++) + nw64_mac(XMAC_HASH_TBL(i), 0); + nw64_mac(XRXMAC_STAT_MSK, ~(u64)0); + niu_set_primary_mac_rdc_table(np, first_rdc_table, 1); + niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1); + + val = nr64_mac(XMAC_CONFIG); + val &= ~(XMAC_CONFIG_RX_MAC_ENABLE | + XMAC_CONFIG_PROMISCUOUS | + XMAC_CONFIG_PROMISC_GROUP | + XMAC_CONFIG_ERR_CHK_DIS | + XMAC_CONFIG_RX_CRC_CHK_DIS | + XMAC_CONFIG_RESERVED_MULTICAST | + XMAC_CONFIG_RX_CODEV_CHK_DIS | + XMAC_CONFIG_ADDR_FILTER_EN | + XMAC_CONFIG_RCV_PAUSE_ENABLE | + XMAC_CONFIG_STRIP_CRC | + XMAC_CONFIG_PASS_FLOW_CTRL | + XMAC_CONFIG_MAC2IPP_PKT_CNT_EN); + val |= (XMAC_CONFIG_HASH_FILTER_EN); + nw64_mac(XMAC_CONFIG, val); + + nw64_mac(RXMAC_BT_CNT, 0); + nw64_mac(RXMAC_BC_FRM_CNT, 0); + nw64_mac(RXMAC_MC_FRM_CNT, 0); + nw64_mac(RXMAC_FRAG_CNT, 0); + nw64_mac(RXMAC_HIST_CNT1, 0); + nw64_mac(RXMAC_HIST_CNT2, 0); + nw64_mac(RXMAC_HIST_CNT3, 0); + nw64_mac(RXMAC_HIST_CNT4, 0); + nw64_mac(RXMAC_HIST_CNT5, 0); + nw64_mac(RXMAC_HIST_CNT6, 0); + nw64_mac(RXMAC_HIST_CNT7, 0); + nw64_mac(RXMAC_MPSZER_CNT, 0); + nw64_mac(RXMAC_CRC_ER_CNT, 0); + nw64_mac(RXMAC_CD_VIO_CNT, 0); + nw64_mac(LINK_FAULT_CNT, 0); +} + +static void niu_init_rx_bmac(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port]; + int first_rdc_table = tp->first_table_num; + unsigned long i; + u64 val; + + nw64_mac(BMAC_ADD_FILT0, 0); + nw64_mac(BMAC_ADD_FILT1, 0); + nw64_mac(BMAC_ADD_FILT2, 0); + nw64_mac(BMAC_ADD_FILT12_MASK, 0); + nw64_mac(BMAC_ADD_FILT00_MASK, 0); + for (i = 0; i < MAC_NUM_HASH; i++) + nw64_mac(BMAC_HASH_TBL(i), 0); + niu_set_primary_mac_rdc_table(np, first_rdc_table, 1); + niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1); + nw64_mac(BRXMAC_STATUS_MASK, ~(u64)0); + + val = nr64_mac(BRXMAC_CONFIG); + val &= ~(BRXMAC_CONFIG_ENABLE | + BRXMAC_CONFIG_STRIP_PAD | + BRXMAC_CONFIG_STRIP_FCS | + BRXMAC_CONFIG_PROMISC | + BRXMAC_CONFIG_PROMISC_GRP | + BRXMAC_CONFIG_ADDR_FILT_EN | + BRXMAC_CONFIG_DISCARD_DIS); + val |= (BRXMAC_CONFIG_HASH_FILT_EN); + nw64_mac(BRXMAC_CONFIG, val); + + val = nr64_mac(BMAC_ADDR_CMPEN); + val |= BMAC_ADDR_CMPEN_EN0; + nw64_mac(BMAC_ADDR_CMPEN, val); +} + +static void niu_init_rx_mac(struct niu *np) +{ + niu_set_primary_mac(np, np->dev->dev_addr); + + if (np->flags & NIU_FLAGS_XMAC) + niu_init_rx_xmac(np); + else + niu_init_rx_bmac(np); +} + +static void niu_enable_tx_xmac(struct niu *np, int on) +{ + u64 val = nr64_mac(XMAC_CONFIG); + + if (on) + val |= XMAC_CONFIG_TX_ENABLE; + else + val &= ~XMAC_CONFIG_TX_ENABLE; + nw64_mac(XMAC_CONFIG, val); +} + +static void niu_enable_tx_bmac(struct niu *np, int on) +{ + u64 val = nr64_mac(BTXMAC_CONFIG); + + if (on) + val |= BTXMAC_CONFIG_ENABLE; + else + val &= ~BTXMAC_CONFIG_ENABLE; + nw64_mac(BTXMAC_CONFIG, val); +} + +static void niu_enable_tx_mac(struct niu *np, int on) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_enable_tx_xmac(np, on); + else + niu_enable_tx_bmac(np, on); +} + +static void niu_enable_rx_xmac(struct niu *np, int on) +{ + u64 val = nr64_mac(XMAC_CONFIG); + + val &= ~(XMAC_CONFIG_HASH_FILTER_EN | + XMAC_CONFIG_PROMISCUOUS); + + if (np->flags & NIU_FLAGS_MCAST) + val |= XMAC_CONFIG_HASH_FILTER_EN; + if (np->flags & NIU_FLAGS_PROMISC) + val |= XMAC_CONFIG_PROMISCUOUS; + + if (on) + val |= XMAC_CONFIG_RX_MAC_ENABLE; + else + val &= ~XMAC_CONFIG_RX_MAC_ENABLE; + nw64_mac(XMAC_CONFIG, val); +} + +static void niu_enable_rx_bmac(struct niu *np, int on) +{ + u64 val = nr64_mac(BRXMAC_CONFIG); + + val &= ~(BRXMAC_CONFIG_HASH_FILT_EN | + BRXMAC_CONFIG_PROMISC); + + if (np->flags & NIU_FLAGS_MCAST) + val |= BRXMAC_CONFIG_HASH_FILT_EN; + if (np->flags & NIU_FLAGS_PROMISC) + val |= BRXMAC_CONFIG_PROMISC; + + if (on) + val |= BRXMAC_CONFIG_ENABLE; + else + val &= ~BRXMAC_CONFIG_ENABLE; + nw64_mac(BRXMAC_CONFIG, val); +} + +static void niu_enable_rx_mac(struct niu *np, int on) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_enable_rx_xmac(np, on); + else + niu_enable_rx_bmac(np, on); +} + +static int niu_init_mac(struct niu *np) +{ + int err; + + niu_init_xif(np); + err = niu_init_pcs(np); + if (err) + return err; + + err = niu_reset_tx_mac(np); + if (err) + return err; + niu_init_tx_mac(np); + err = niu_reset_rx_mac(np); + if (err) + return err; + niu_init_rx_mac(np); + + /* This looks hookey but the RX MAC reset we just did will + * undo some of the state we setup in niu_init_tx_mac() so we + * have to call it again. In particular, the RX MAC reset will + * set the XMAC_MAX register back to it's default value. + */ + niu_init_tx_mac(np); + niu_enable_tx_mac(np, 1); + + niu_enable_rx_mac(np, 1); + + return 0; +} + +static void niu_stop_one_tx_channel(struct niu *np, struct tx_ring_info *rp) +{ + (void) niu_tx_channel_stop(np, rp->tx_channel); +} + +static void niu_stop_tx_channels(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + niu_stop_one_tx_channel(np, rp); + } +} + +static void niu_reset_one_tx_channel(struct niu *np, struct tx_ring_info *rp) +{ + (void) niu_tx_channel_reset(np, rp->tx_channel); +} + +static void niu_reset_tx_channels(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + niu_reset_one_tx_channel(np, rp); + } +} + +static void niu_stop_one_rx_channel(struct niu *np, struct rx_ring_info *rp) +{ + (void) niu_enable_rx_channel(np, rp->rx_channel, 0); +} + +static void niu_stop_rx_channels(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + niu_stop_one_rx_channel(np, rp); + } +} + +static void niu_reset_one_rx_channel(struct niu *np, struct rx_ring_info *rp) +{ + int channel = rp->rx_channel; + + (void) niu_rx_channel_reset(np, channel); + nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_ALL); + nw64(RX_DMA_CTL_STAT(channel), 0); + (void) niu_enable_rx_channel(np, channel, 0); +} + +static void niu_reset_rx_channels(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + niu_reset_one_rx_channel(np, rp); + } +} + +static void niu_disable_ipp(struct niu *np) +{ + u64 rd, wr, val; + int limit; + + rd = nr64_ipp(IPP_DFIFO_RD_PTR); + wr = nr64_ipp(IPP_DFIFO_WR_PTR); + limit = 100; + while (--limit >= 0 && (rd != wr)) { + rd = nr64_ipp(IPP_DFIFO_RD_PTR); + wr = nr64_ipp(IPP_DFIFO_WR_PTR); + } + if (limit < 0 && + (rd != 0 && wr != 1)) { + dev_err(np->device, PFX "%s: IPP would not quiesce, " + "rd_ptr[%llx] wr_ptr[%llx]\n", + np->dev->name, + (unsigned long long) nr64_ipp(IPP_DFIFO_RD_PTR), + (unsigned long long) nr64_ipp(IPP_DFIFO_WR_PTR)); + } + + val = nr64_ipp(IPP_CFIG); + val &= ~(IPP_CFIG_IPP_ENABLE | + IPP_CFIG_DFIFO_ECC_EN | + IPP_CFIG_DROP_BAD_CRC | + IPP_CFIG_CKSUM_EN); + nw64_ipp(IPP_CFIG, val); + + (void) niu_ipp_reset(np); +} + +static int niu_init_hw(struct niu *np) +{ + int i, err; + + niudbg(IFUP, "%s: Initialize TXC\n", np->dev->name); + niu_txc_enable_port(np, 1); + niu_txc_port_dma_enable(np, 1); + niu_txc_set_imask(np, 0); + + niudbg(IFUP, "%s: Initialize TX channels\n", np->dev->name); + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + err = niu_init_one_tx_channel(np, rp); + if (err) + return err; + } + + niudbg(IFUP, "%s: Initialize RX channels\n", np->dev->name); + err = niu_init_rx_channels(np); + if (err) + goto out_uninit_tx_channels; + + niudbg(IFUP, "%s: Initialize classifier\n", np->dev->name); + err = niu_init_classifier_hw(np); + if (err) + goto out_uninit_rx_channels; + + niudbg(IFUP, "%s: Initialize ZCP\n", np->dev->name); + err = niu_init_zcp(np); + if (err) + goto out_uninit_rx_channels; + + niudbg(IFUP, "%s: Initialize IPP\n", np->dev->name); + err = niu_init_ipp(np); + if (err) + goto out_uninit_rx_channels; + + niudbg(IFUP, "%s: Initialize MAC\n", np->dev->name); + err = niu_init_mac(np); + if (err) + goto out_uninit_ipp; + + return 0; + +out_uninit_ipp: + niudbg(IFUP, "%s: Uninit IPP\n", np->dev->name); + niu_disable_ipp(np); + +out_uninit_rx_channels: + niudbg(IFUP, "%s: Uninit RX channels\n", np->dev->name); + niu_stop_rx_channels(np); + niu_reset_rx_channels(np); + +out_uninit_tx_channels: + niudbg(IFUP, "%s: Uninit TX channels\n", np->dev->name); + niu_stop_tx_channels(np); + niu_reset_tx_channels(np); + + return err; +} + +static void niu_stop_hw(struct niu *np) +{ + niudbg(IFDOWN, "%s: Disable interrupts\n", np->dev->name); + niu_enable_interrupts(np, 0); + + niudbg(IFDOWN, "%s: Disable RX MAC\n", np->dev->name); + niu_enable_rx_mac(np, 0); + + niudbg(IFDOWN, "%s: Disable IPP\n", np->dev->name); + niu_disable_ipp(np); + + niudbg(IFDOWN, "%s: Stop TX channels\n", np->dev->name); + niu_stop_tx_channels(np); + + niudbg(IFDOWN, "%s: Stop RX channels\n", np->dev->name); + niu_stop_rx_channels(np); + + niudbg(IFDOWN, "%s: Reset TX channels\n", np->dev->name); + niu_reset_tx_channels(np); + + niudbg(IFDOWN, "%s: Reset RX channels\n", np->dev->name); + niu_reset_rx_channels(np); +} + +static int niu_request_irq(struct niu *np) +{ + int i, j, err; + + err = 0; + for (i = 0; i < np->num_ldg; i++) { + struct niu_ldg *lp = &np->ldg[i]; + + err = request_irq(lp->irq, niu_interrupt, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, + np->dev->name, lp); + if (err) + goto out_free_irqs; + + } + + return 0; + +out_free_irqs: + for (j = 0; j < i; j++) { + struct niu_ldg *lp = &np->ldg[j]; + + free_irq(lp->irq, lp); + } + return err; +} + +static void niu_free_irq(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_ldg; i++) { + struct niu_ldg *lp = &np->ldg[i]; + + free_irq(lp->irq, lp); + } +} + +static void niu_enable_napi(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_ldg; i++) + napi_enable(&np->ldg[i].napi); +} + +static void niu_disable_napi(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_ldg; i++) + napi_disable(&np->ldg[i].napi); +} + +static int niu_open(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + int err; + + netif_carrier_off(dev); + + err = niu_alloc_channels(np); + if (err) + goto out_err; + + err = niu_enable_interrupts(np, 0); + if (err) + goto out_free_channels; + + err = niu_request_irq(np); + if (err) + goto out_free_channels; + + niu_enable_napi(np); + + spin_lock_irq(&np->lock); + + err = niu_init_hw(np); + if (!err) { + init_timer(&np->timer); + np->timer.expires = jiffies + HZ; + np->timer.data = (unsigned long) np; + np->timer.function = niu_timer; + + err = niu_enable_interrupts(np, 1); + if (err) + niu_stop_hw(np); + } + + spin_unlock_irq(&np->lock); + + if (err) { + niu_disable_napi(np); + goto out_free_irq; + } + + netif_start_queue(dev); + + if (np->link_config.loopback_mode != LOOPBACK_DISABLED) + netif_carrier_on(dev); + + add_timer(&np->timer); + + return 0; + +out_free_irq: + niu_free_irq(np); + +out_free_channels: + niu_free_channels(np); + +out_err: + return err; +} + +static void niu_full_shutdown(struct niu *np, struct net_device *dev) +{ + cancel_work_sync(&np->reset_task); + + niu_disable_napi(np); + netif_stop_queue(dev); + + del_timer_sync(&np->timer); + + spin_lock_irq(&np->lock); + + niu_stop_hw(np); + + spin_unlock_irq(&np->lock); +} + +static int niu_close(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + niu_full_shutdown(np, dev); + + niu_free_irq(np); + + niu_free_channels(np); + + return 0; +} + +static void niu_sync_xmac_stats(struct niu *np) +{ + struct niu_xmac_stats *mp = &np->mac_stats.xmac; + + mp->tx_frames += nr64_mac(TXMAC_FRM_CNT); + mp->tx_bytes += nr64_mac(TXMAC_BYTE_CNT); + + mp->rx_link_faults += nr64_mac(LINK_FAULT_CNT); + mp->rx_align_errors += nr64_mac(RXMAC_ALIGN_ERR_CNT); + mp->rx_frags += nr64_mac(RXMAC_FRAG_CNT); + mp->rx_mcasts += nr64_mac(RXMAC_MC_FRM_CNT); + mp->rx_bcasts += nr64_mac(RXMAC_BC_FRM_CNT); + mp->rx_hist_cnt1 += nr64_mac(RXMAC_HIST_CNT1); + mp->rx_hist_cnt2 += nr64_mac(RXMAC_HIST_CNT2); + mp->rx_hist_cnt3 += nr64_mac(RXMAC_HIST_CNT3); + mp->rx_hist_cnt4 += nr64_mac(RXMAC_HIST_CNT4); + mp->rx_hist_cnt5 += nr64_mac(RXMAC_HIST_CNT5); + mp->rx_hist_cnt6 += nr64_mac(RXMAC_HIST_CNT6); + mp->rx_hist_cnt7 += nr64_mac(RXMAC_HIST_CNT7); + mp->rx_octets += nr64_mac(RXMAC_BT_CNT); + mp->rx_code_violations += nr64_mac(RXMAC_CD_VIO_CNT); + mp->rx_len_errors += nr64_mac(RXMAC_MPSZER_CNT); + mp->rx_crc_errors += nr64_mac(RXMAC_CRC_ER_CNT); +} + +static void niu_sync_bmac_stats(struct niu *np) +{ + struct niu_bmac_stats *mp = &np->mac_stats.bmac; + + mp->tx_bytes += nr64_mac(BTXMAC_BYTE_CNT); + mp->tx_frames += nr64_mac(BTXMAC_FRM_CNT); + + mp->rx_frames += nr64_mac(BRXMAC_FRAME_CNT); + mp->rx_align_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT); + mp->rx_crc_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT); + mp->rx_len_errors += nr64_mac(BRXMAC_CODE_VIOL_ERR_CNT); +} + +static void niu_sync_mac_stats(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_sync_xmac_stats(np); + else + niu_sync_bmac_stats(np); +} + +static void niu_get_rx_stats(struct niu *np) +{ + unsigned long pkts, dropped, errors, bytes; + int i; + + pkts = dropped = errors = bytes = 0; + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + pkts += rp->rx_packets; + bytes += rp->rx_bytes; + dropped += rp->rx_dropped; + errors += rp->rx_errors; + } + np->net_stats.rx_packets = pkts; + np->net_stats.rx_bytes = bytes; + np->net_stats.rx_dropped = dropped; + np->net_stats.rx_errors = errors; +} + +static void niu_get_tx_stats(struct niu *np) +{ + unsigned long pkts, errors, bytes; + int i; + + pkts = errors = bytes = 0; + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + pkts += rp->tx_packets; + bytes += rp->tx_bytes; + errors += rp->tx_errors; + } + np->net_stats.tx_packets = pkts; + np->net_stats.tx_bytes = bytes; + np->net_stats.tx_errors = errors; +} + +static struct net_device_stats *niu_get_stats(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + niu_get_rx_stats(np); + niu_get_tx_stats(np); + + return &np->net_stats; +} + +static void niu_load_hash_xmac(struct niu *np, u16 *hash) +{ + int i; + + for (i = 0; i < 16; i++) + nw64_mac(XMAC_HASH_TBL(i), hash[i]); +} + +static void niu_load_hash_bmac(struct niu *np, u16 *hash) +{ + int i; + + for (i = 0; i < 16; i++) + nw64_mac(BMAC_HASH_TBL(i), hash[i]); +} + +static void niu_load_hash(struct niu *np, u16 *hash) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_load_hash_xmac(np, hash); + else + niu_load_hash_bmac(np, hash); +} + +static void niu_set_rx_mode(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + int i, alt_cnt, err; + struct dev_addr_list *addr; + unsigned long flags; + u16 hash[16] = { 0, }; + + spin_lock_irqsave(&np->lock, flags); + niu_enable_rx_mac(np, 0); + + np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC); + if (dev->flags & IFF_PROMISC) + np->flags |= NIU_FLAGS_PROMISC; + if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0)) + np->flags |= NIU_FLAGS_MCAST; + + alt_cnt = dev->uc_count; + if (alt_cnt > niu_num_alt_addr(np)) { + alt_cnt = 0; + np->flags |= NIU_FLAGS_PROMISC; + } + + if (alt_cnt) { + int index = 0; + + for (addr = dev->uc_list; addr; addr = addr->next) { + err = niu_set_alt_mac(np, index, + addr->da_addr); + if (err) + printk(KERN_WARNING PFX "%s: Error %d " + "adding alt mac %d\n", + dev->name, err, index); + err = niu_enable_alt_mac(np, index, 1); + if (err) + printk(KERN_WARNING PFX "%s: Error %d " + "enabling alt mac %d\n", + dev->name, err, index); + + index++; + } + } else { + for (i = 0; i < niu_num_alt_addr(np); i++) { + err = niu_enable_alt_mac(np, i, 0); + if (err) + printk(KERN_WARNING PFX "%s: Error %d " + "disabling alt mac %d\n", + dev->name, err, i); + } + } + if (dev->flags & IFF_ALLMULTI) { + for (i = 0; i < 16; i++) + hash[i] = 0xffff; + } else if (dev->mc_count > 0) { + for (addr = dev->mc_list; addr; addr = addr->next) { + u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr); + + crc >>= 24; + hash[crc >> 4] |= (1 << (15 - (crc & 0xf))); + } + } + + if (np->flags & NIU_FLAGS_MCAST) + niu_load_hash(np, hash); + + niu_enable_rx_mac(np, 1); + spin_unlock_irqrestore(&np->lock, flags); +} + +static int niu_set_mac_addr(struct net_device *dev, void *p) +{ + struct niu *np = netdev_priv(dev); + struct sockaddr *addr = p; + unsigned long flags; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + + if (!netif_running(dev)) + return 0; + + spin_lock_irqsave(&np->lock, flags); + niu_enable_rx_mac(np, 0); + niu_set_primary_mac(np, dev->dev_addr); + niu_enable_rx_mac(np, 1); + spin_unlock_irqrestore(&np->lock, flags); + + return 0; +} + +static int niu_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + return -EOPNOTSUPP; +} + +static void niu_netif_stop(struct niu *np) +{ + np->dev->trans_start = jiffies; /* prevent tx timeout */ + + niu_disable_napi(np); + + netif_tx_disable(np->dev); +} + +static void niu_netif_start(struct niu *np) +{ + /* NOTE: unconditional netif_wake_queue is only appropriate + * so long as all callers are assured to have free tx slots + * (such as after niu_init_hw). + */ + netif_wake_queue(np->dev); + + niu_enable_napi(np); + + niu_enable_interrupts(np, 1); +} + +static void niu_reset_task(struct work_struct *work) +{ + struct niu *np = container_of(work, struct niu, reset_task); + unsigned long flags; + int err; + + spin_lock_irqsave(&np->lock, flags); + if (!netif_running(np->dev)) { + spin_unlock_irqrestore(&np->lock, flags); + return; + } + + spin_unlock_irqrestore(&np->lock, flags); + + del_timer_sync(&np->timer); + + niu_netif_stop(np); + + spin_lock_irqsave(&np->lock, flags); + + niu_stop_hw(np); + + err = niu_init_hw(np); + if (!err) { + np->timer.expires = jiffies + HZ; + add_timer(&np->timer); + niu_netif_start(np); + } + + spin_unlock_irqrestore(&np->lock, flags); +} + +static void niu_tx_timeout(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + dev_err(np->device, PFX "%s: Transmit timed out, resetting\n", + dev->name); + + schedule_work(&np->reset_task); +} + +static void niu_set_txd(struct tx_ring_info *rp, int index, + u64 mapping, u64 len, u64 mark, + u64 n_frags) +{ + __le64 *desc = &rp->descr[index]; + + *desc = cpu_to_le64(mark | + (n_frags << TX_DESC_NUM_PTR_SHIFT) | + (len << TX_DESC_TR_LEN_SHIFT) | + (mapping & TX_DESC_SAD)); +} + +static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr, + u64 pad_bytes, u64 len) +{ + u16 eth_proto, eth_proto_inner; + u64 csum_bits, l3off, ihl, ret; + u8 ip_proto; + int ipv6; + + eth_proto = be16_to_cpu(ehdr->h_proto); + eth_proto_inner = eth_proto; + if (eth_proto == ETH_P_8021Q) { + struct vlan_ethhdr *vp = (struct vlan_ethhdr *) ehdr; + __be16 val = vp->h_vlan_encapsulated_proto; + + eth_proto_inner = be16_to_cpu(val); + } + + ipv6 = ihl = 0; + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + ip_proto = ip_hdr(skb)->protocol; + ihl = ip_hdr(skb)->ihl; + break; + case __constant_htons(ETH_P_IPV6): + ip_proto = ipv6_hdr(skb)->nexthdr; + ihl = (40 >> 2); + ipv6 = 1; + break; + default: + ip_proto = ihl = 0; + break; + } + + csum_bits = TXHDR_CSUM_NONE; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + u64 start, stuff; + + csum_bits = (ip_proto == IPPROTO_TCP ? + TXHDR_CSUM_TCP : + (ip_proto == IPPROTO_UDP ? + TXHDR_CSUM_UDP : TXHDR_CSUM_SCTP)); + + start = skb_transport_offset(skb) - + (pad_bytes + sizeof(struct tx_pkt_hdr)); + stuff = start + skb->csum_offset; + + csum_bits |= (start / 2) << TXHDR_L4START_SHIFT; + csum_bits |= (stuff / 2) << TXHDR_L4STUFF_SHIFT; + } + + l3off = skb_network_offset(skb) - + (pad_bytes + sizeof(struct tx_pkt_hdr)); + + ret = (((pad_bytes / 2) << TXHDR_PAD_SHIFT) | + (len << TXHDR_LEN_SHIFT) | + ((l3off / 2) << TXHDR_L3START_SHIFT) | + (ihl << TXHDR_IHL_SHIFT) | + ((eth_proto_inner < 1536) ? TXHDR_LLC : 0) | + ((eth_proto == ETH_P_8021Q) ? TXHDR_VLAN : 0) | + (ipv6 ? TXHDR_IP_VER : 0) | + csum_bits); + + return ret; +} + +static struct tx_ring_info *tx_ring_select(struct niu *np, struct sk_buff *skb) +{ + return &np->tx_rings[0]; +} + +static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + unsigned long align, headroom; + struct tx_ring_info *rp; + struct tx_pkt_hdr *tp; + unsigned int len, nfg; + struct ethhdr *ehdr; + int prod, i, tlen; + u64 mapping, mrk; + + rp = tx_ring_select(np, skb); + + if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) { + netif_stop_queue(dev); + dev_err(np->device, PFX "%s: BUG! Tx ring full when " + "queue awake!\n", dev->name); + rp->tx_errors++; + return NETDEV_TX_BUSY; + } + + if (skb->len < ETH_ZLEN) { + unsigned int pad_bytes = ETH_ZLEN - skb->len; + + if (skb_pad(skb, pad_bytes)) + goto out; + skb_put(skb, pad_bytes); + } + + len = sizeof(struct tx_pkt_hdr) + 15; + if (skb_headroom(skb) < len) { + struct sk_buff *skb_new; + + skb_new = skb_realloc_headroom(skb, len); + if (!skb_new) { + rp->tx_errors++; + goto out_drop; + } + kfree_skb(skb); + skb = skb_new; + } + + align = ((unsigned long) skb->data & (16 - 1)); + headroom = align + sizeof(struct tx_pkt_hdr); + + ehdr = (struct ethhdr *) skb->data; + tp = (struct tx_pkt_hdr *) skb_push(skb, headroom); + + len = skb->len - sizeof(struct tx_pkt_hdr); + tp->flags = cpu_to_le64(niu_compute_tx_flags(skb, ehdr, align, len)); + tp->resv = 0; + + len = skb_headlen(skb); + mapping = np->ops->map_single(np->device, skb->data, + len, DMA_TO_DEVICE); + + prod = rp->prod; + + rp->tx_buffs[prod].skb = skb; + rp->tx_buffs[prod].mapping = mapping; + + mrk = TX_DESC_SOP; + if (++rp->mark_counter == rp->mark_freq) { + rp->mark_counter = 0; + mrk |= TX_DESC_MARK; + rp->mark_pending++; + } + + tlen = len; + nfg = skb_shinfo(skb)->nr_frags; + while (tlen > 0) { + tlen -= MAX_TX_DESC_LEN; + nfg++; + } + + while (len > 0) { + unsigned int this_len = len; + + if (this_len > MAX_TX_DESC_LEN) + this_len = MAX_TX_DESC_LEN; + + niu_set_txd(rp, prod, mapping, this_len, mrk, nfg); + mrk = nfg = 0; + + prod = NEXT_TX(rp, prod); + mapping += this_len; + len -= this_len; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + len = frag->size; + mapping = np->ops->map_page(np->device, frag->page, + frag->page_offset, len, + DMA_TO_DEVICE); + + rp->tx_buffs[prod].skb = NULL; + rp->tx_buffs[prod].mapping = mapping; + + niu_set_txd(rp, prod, mapping, len, 0, 0); + + prod = NEXT_TX(rp, prod); + } + + if (prod < rp->prod) + rp->wrap_bit ^= TX_RING_KICK_WRAP; + rp->prod = prod; + + nw64(TX_RING_KICK(rp->tx_channel), rp->wrap_bit | (prod << 3)); + + if (unlikely(niu_tx_avail(rp) <= (MAX_SKB_FRAGS + 1))) { + netif_stop_queue(dev); + if (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)) + netif_wake_queue(dev); + } + + dev->trans_start = jiffies; + +out: + return NETDEV_TX_OK; + +out_drop: + rp->tx_errors++; + kfree_skb(skb); + goto out; +} + +static int niu_change_mtu(struct net_device *dev, int new_mtu) +{ + struct niu *np = netdev_priv(dev); + int err, orig_jumbo, new_jumbo; + + if (new_mtu < 68 || new_mtu > NIU_MAX_MTU) + return -EINVAL; + + orig_jumbo = (dev->mtu > ETH_DATA_LEN); + new_jumbo = (new_mtu > ETH_DATA_LEN); + + dev->mtu = new_mtu; + + if (!netif_running(dev) || + (orig_jumbo == new_jumbo)) + return 0; + + niu_full_shutdown(np, dev); + + niu_free_channels(np); + + niu_enable_napi(np); + + err = niu_alloc_channels(np); + if (err) + return err; + + spin_lock_irq(&np->lock); + + err = niu_init_hw(np); + if (!err) { + init_timer(&np->timer); + np->timer.expires = jiffies + HZ; + np->timer.data = (unsigned long) np; + np->timer.function = niu_timer; + + err = niu_enable_interrupts(np, 1); + if (err) + niu_stop_hw(np); + } + + spin_unlock_irq(&np->lock); + + if (!err) { + netif_start_queue(dev); + if (np->link_config.loopback_mode != LOOPBACK_DISABLED) + netif_carrier_on(dev); + + add_timer(&np->timer); + } + + return err; +} + +static void niu_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct niu *np = netdev_priv(dev); + struct niu_vpd *vpd = &np->vpd; + + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); + sprintf(info->fw_version, "%d.%d", + vpd->fcode_major, vpd->fcode_minor); + if (np->parent->plat_type != PLAT_TYPE_NIU) + strcpy(info->bus_info, pci_name(np->pdev)); +} + +static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct niu *np = netdev_priv(dev); + struct niu_link_config *lp; + + lp = &np->link_config; + + memset(cmd, 0, sizeof(*cmd)); + cmd->phy_address = np->phy_addr; + cmd->supported = lp->supported; + cmd->advertising = lp->advertising; + cmd->autoneg = lp->autoneg; + cmd->speed = lp->active_speed; + cmd->duplex = lp->active_duplex; + + return 0; +} + +static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + return -EINVAL; +} + +static u32 niu_get_msglevel(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + return np->msg_enable; +} + +static void niu_set_msglevel(struct net_device *dev, u32 value) +{ + struct niu *np = netdev_priv(dev); + np->msg_enable = value; +} + +static int niu_get_eeprom_len(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + return np->eeprom_len; +} + +static int niu_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct niu *np = netdev_priv(dev); + u32 offset, len, val; + + offset = eeprom->offset; + len = eeprom->len; + + if (offset + len < offset) + return -EINVAL; + if (offset >= np->eeprom_len) + return -EINVAL; + if (offset + len > np->eeprom_len) + len = eeprom->len = np->eeprom_len - offset; + + if (offset & 3) { + u32 b_offset, b_count; + + b_offset = offset & 3; + b_count = 4 - b_offset; + if (b_count > len) + b_count = len; + + val = nr64(ESPC_NCR((offset - b_offset) / 4)); + memcpy(data, ((char *)&val) + b_offset, b_count); + data += b_count; + len -= b_count; + offset += b_count; + } + while (len >= 4) { + val = nr64(ESPC_NCR(offset / 4)); + memcpy(data, &val, 4); + data += 4; + len -= 4; + offset += 4; + } + if (len) { + val = nr64(ESPC_NCR(offset / 4)); + memcpy(data, &val, len); + } + return 0; +} + +static const struct { + const char string[ETH_GSTRING_LEN]; +} niu_xmac_stat_keys[] = { + { "tx_frames" }, + { "tx_bytes" }, + { "tx_fifo_errors" }, + { "tx_overflow_errors" }, + { "tx_max_pkt_size_errors" }, + { "tx_underflow_errors" }, + { "rx_local_faults" }, + { "rx_remote_faults" }, + { "rx_link_faults" }, + { "rx_align_errors" }, + { "rx_frags" }, + { "rx_mcasts" }, + { "rx_bcasts" }, + { "rx_hist_cnt1" }, + { "rx_hist_cnt2" }, + { "rx_hist_cnt3" }, + { "rx_hist_cnt4" }, + { "rx_hist_cnt5" }, + { "rx_hist_cnt6" }, + { "rx_hist_cnt7" }, + { "rx_octets" }, + { "rx_code_violations" }, + { "rx_len_errors" }, + { "rx_crc_errors" }, + { "rx_underflows" }, + { "rx_overflows" }, + { "pause_off_state" }, + { "pause_on_state" }, + { "pause_received" }, +}; + +#define NUM_XMAC_STAT_KEYS ARRAY_SIZE(niu_xmac_stat_keys) + +static const struct { + const char string[ETH_GSTRING_LEN]; +} niu_bmac_stat_keys[] = { + { "tx_underflow_errors" }, + { "tx_max_pkt_size_errors" }, + { "tx_bytes" }, + { "tx_frames" }, + { "rx_overflows" }, + { "rx_frames" }, + { "rx_align_errors" }, + { "rx_crc_errors" }, + { "rx_len_errors" }, + { "pause_off_state" }, + { "pause_on_state" }, + { "pause_received" }, +}; + +#define NUM_BMAC_STAT_KEYS ARRAY_SIZE(niu_bmac_stat_keys) + +static const struct { + const char string[ETH_GSTRING_LEN]; +} niu_rxchan_stat_keys[] = { + { "rx_channel" }, + { "rx_packets" }, + { "rx_bytes" }, + { "rx_dropped" }, + { "rx_errors" }, +}; + +#define NUM_RXCHAN_STAT_KEYS ARRAY_SIZE(niu_rxchan_stat_keys) + +static const struct { + const char string[ETH_GSTRING_LEN]; +} niu_txchan_stat_keys[] = { + { "tx_channel" }, + { "tx_packets" }, + { "tx_bytes" }, + { "tx_errors" }, +}; + +#define NUM_TXCHAN_STAT_KEYS ARRAY_SIZE(niu_txchan_stat_keys) + +static void niu_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + struct niu *np = netdev_priv(dev); + int i; + + if (stringset != ETH_SS_STATS) + return; + + if (np->flags & NIU_FLAGS_XMAC) { + memcpy(data, niu_xmac_stat_keys, + sizeof(niu_xmac_stat_keys)); + data += sizeof(niu_xmac_stat_keys); + } else { + memcpy(data, niu_bmac_stat_keys, + sizeof(niu_bmac_stat_keys)); + data += sizeof(niu_bmac_stat_keys); + } + for (i = 0; i < np->num_rx_rings; i++) { + memcpy(data, niu_rxchan_stat_keys, + sizeof(niu_rxchan_stat_keys)); + data += sizeof(niu_rxchan_stat_keys); + } + for (i = 0; i < np->num_tx_rings; i++) { + memcpy(data, niu_txchan_stat_keys, + sizeof(niu_txchan_stat_keys)); + data += sizeof(niu_txchan_stat_keys); + } +} + +static int niu_get_stats_count(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + return ((np->flags & NIU_FLAGS_XMAC ? + NUM_XMAC_STAT_KEYS : + NUM_BMAC_STAT_KEYS) + + (np->num_rx_rings * NUM_RXCHAN_STAT_KEYS) + + (np->num_tx_rings * NUM_TXCHAN_STAT_KEYS)); +} + +static void niu_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct niu *np = netdev_priv(dev); + int i; + + niu_sync_mac_stats(np); + if (np->flags & NIU_FLAGS_XMAC) { + memcpy(data, &np->mac_stats.xmac, + sizeof(struct niu_xmac_stats)); + data += (sizeof(struct niu_xmac_stats) / sizeof(u64)); + } else { + memcpy(data, &np->mac_stats.bmac, + sizeof(struct niu_bmac_stats)); + data += (sizeof(struct niu_bmac_stats) / sizeof(u64)); + } + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + data[0] = rp->rx_channel; + data[1] = rp->rx_packets; + data[2] = rp->rx_bytes; + data[3] = rp->rx_dropped; + data[4] = rp->rx_errors; + data += 5; + } + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + data[0] = rp->tx_channel; + data[1] = rp->tx_packets; + data[2] = rp->tx_bytes; + data[3] = rp->tx_errors; + data += 4; + } +} + +static u64 niu_led_state_save(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + return nr64_mac(XMAC_CONFIG); + else + return nr64_mac(BMAC_XIF_CONFIG); +} + +static void niu_led_state_restore(struct niu *np, u64 val) +{ + if (np->flags & NIU_FLAGS_XMAC) + nw64_mac(XMAC_CONFIG, val); + else + nw64_mac(BMAC_XIF_CONFIG, val); +} + +static void niu_force_led(struct niu *np, int on) +{ + u64 val, reg, bit; + + if (np->flags & NIU_FLAGS_XMAC) { + reg = XMAC_CONFIG; + bit = XMAC_CONFIG_FORCE_LED_ON; + } else { + reg = BMAC_XIF_CONFIG; + bit = BMAC_XIF_CONFIG_LINK_LED; + } + + val = nr64_mac(reg); + if (on) + val |= bit; + else + val &= ~bit; + nw64_mac(reg, val); +} + +static int niu_phys_id(struct net_device *dev, u32 data) +{ + struct niu *np = netdev_priv(dev); + u64 orig_led_state; + int i; + + if (!netif_running(dev)) + return -EAGAIN; + + if (data == 0) + data = 2; + + orig_led_state = niu_led_state_save(np); + for (i = 0; i < (data * 2); i++) { + int on = ((i % 2) == 0); + + niu_force_led(np, on); + + if (msleep_interruptible(500)) + break; + } + niu_led_state_restore(np, orig_led_state); + + return 0; +} + +static const struct ethtool_ops niu_ethtool_ops = { + .get_drvinfo = niu_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = niu_get_msglevel, + .set_msglevel = niu_set_msglevel, + .get_eeprom_len = niu_get_eeprom_len, + .get_eeprom = niu_get_eeprom, + .get_settings = niu_get_settings, + .set_settings = niu_set_settings, + .get_strings = niu_get_strings, + .get_stats_count = niu_get_stats_count, + .get_ethtool_stats = niu_get_ethtool_stats, + .phys_id = niu_phys_id, +}; + +static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, + int ldg, int ldn) +{ + if (ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX) + return -EINVAL; + if (ldn < 0 || ldn > LDN_MAX) + return -EINVAL; + + parent->ldg_map[ldn] = ldg; + + if (np->parent->plat_type == PLAT_TYPE_NIU) { + /* On N2 NIU, the ldn-->ldg assignments are setup and fixed by + * the firmware, and we're not supposed to change them. + * Validate the mapping, because if it's wrong we probably + * won't get any interrupts and that's painful to debug. + */ + if (nr64(LDG_NUM(ldn)) != ldg) { + dev_err(np->device, PFX "Port %u, mis-matched " + "LDG assignment " + "for ldn %d, should be %d is %llu\n", + np->port, ldn, ldg, + (unsigned long long) nr64(LDG_NUM(ldn))); + return -EINVAL; + } + } else + nw64(LDG_NUM(ldn), ldg); + + return 0; +} + +static int niu_set_ldg_timer_res(struct niu *np, int res) +{ + if (res < 0 || res > LDG_TIMER_RES_VAL) + return -EINVAL; + + + nw64(LDG_TIMER_RES, res); + + return 0; +} + +static int niu_set_ldg_sid(struct niu *np, int ldg, int func, int vector) +{ + if ((ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX) || + (func < 0 || func > 3) || + (vector < 0 || vector > 0x1f)) + return -EINVAL; + + nw64(SID(ldg), (func << SID_FUNC_SHIFT) | vector); + + return 0; +} + +static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr) +{ + u64 frame, frame_base = (ESPC_PIO_STAT_READ_START | + (addr << ESPC_PIO_STAT_ADDR_SHIFT)); + int limit; + + if (addr > (ESPC_PIO_STAT_ADDR >> ESPC_PIO_STAT_ADDR_SHIFT)) + return -EINVAL; + + frame = frame_base; + nw64(ESPC_PIO_STAT, frame); + limit = 64; + do { + udelay(5); + frame = nr64(ESPC_PIO_STAT); + if (frame & ESPC_PIO_STAT_READ_END) + break; + } while (limit--); + if (!(frame & ESPC_PIO_STAT_READ_END)) { + dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n", + (unsigned long long) frame); + return -ENODEV; + } + + frame = frame_base; + nw64(ESPC_PIO_STAT, frame); + limit = 64; + do { + udelay(5); + frame = nr64(ESPC_PIO_STAT); + if (frame & ESPC_PIO_STAT_READ_END) + break; + } while (limit--); + if (!(frame & ESPC_PIO_STAT_READ_END)) { + dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n", + (unsigned long long) frame); + return -ENODEV; + } + + frame = nr64(ESPC_PIO_STAT); + return (frame & ESPC_PIO_STAT_DATA) >> ESPC_PIO_STAT_DATA_SHIFT; +} + +static int __devinit niu_pci_eeprom_read16(struct niu *np, u32 off) +{ + int err = niu_pci_eeprom_read(np, off); + u16 val; + + if (err < 0) + return err; + val = (err << 8); + err = niu_pci_eeprom_read(np, off + 1); + if (err < 0) + return err; + val |= (err & 0xff); + + return val; +} + +static int __devinit niu_pci_eeprom_read16_swp(struct niu *np, u32 off) +{ + int err = niu_pci_eeprom_read(np, off); + u16 val; + + if (err < 0) + return err; + + val = (err & 0xff); + err = niu_pci_eeprom_read(np, off + 1); + if (err < 0) + return err; + + val |= (err & 0xff) << 8; + + return val; +} + +static int __devinit niu_pci_vpd_get_propname(struct niu *np, + u32 off, + char *namebuf, + int namebuf_len) +{ + int i; + + for (i = 0; i < namebuf_len; i++) { + int err = niu_pci_eeprom_read(np, off + i); + if (err < 0) + return err; + *namebuf++ = err; + if (!err) + break; + } + if (i >= namebuf_len) + return -EINVAL; + + return i + 1; +} + +static void __devinit niu_vpd_parse_version(struct niu *np) +{ + struct niu_vpd *vpd = &np->vpd; + int len = strlen(vpd->version) + 1; + const char *s = vpd->version; + int i; + + for (i = 0; i < len - 5; i++) { + if (!strncmp(s + i, "FCode ", 5)) + break; + } + if (i >= len - 5) + return; + + s += i + 5; + sscanf(s, "%d.%d", &vpd->fcode_major, &vpd->fcode_minor); + + niudbg(PROBE, "VPD_SCAN: FCODE major(%d) minor(%d)\n", + vpd->fcode_major, vpd->fcode_minor); + if (vpd->fcode_major > NIU_VPD_MIN_MAJOR || + (vpd->fcode_major == NIU_VPD_MIN_MAJOR && + vpd->fcode_minor >= NIU_VPD_MIN_MINOR)) + np->flags |= NIU_FLAGS_VPD_VALID; +} + +/* ESPC_PIO_EN_ENABLE must be set */ +static int __devinit niu_pci_vpd_scan_props(struct niu *np, + u32 start, u32 end) +{ + unsigned int found_mask = 0; +#define FOUND_MASK_MODEL 0x00000001 +#define FOUND_MASK_BMODEL 0x00000002 +#define FOUND_MASK_VERS 0x00000004 +#define FOUND_MASK_MAC 0x00000008 +#define FOUND_MASK_NMAC 0x00000010 +#define FOUND_MASK_PHY 0x00000020 +#define FOUND_MASK_ALL 0x0000003f + + niudbg(PROBE, "VPD_SCAN: start[%x] end[%x]\n", + start, end); + while (start < end) { + int len, err, instance, type, prop_len; + char namebuf[64]; + u8 *prop_buf; + int max_len; + + if (found_mask == FOUND_MASK_ALL) { + niu_vpd_parse_version(np); + return 1; + } + + err = niu_pci_eeprom_read(np, start + 2); + if (err < 0) + return err; + len = err; + start += 3; + + instance = niu_pci_eeprom_read(np, start); + type = niu_pci_eeprom_read(np, start + 3); + prop_len = niu_pci_eeprom_read(np, start + 4); + err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64); + if (err < 0) + return err; + + prop_buf = NULL; + max_len = 0; + if (!strcmp(namebuf, "model")) { + prop_buf = np->vpd.model; + max_len = NIU_VPD_MODEL_MAX; + found_mask |= FOUND_MASK_MODEL; + } else if (!strcmp(namebuf, "board-model")) { + prop_buf = np->vpd.board_model; + max_len = NIU_VPD_BD_MODEL_MAX; + found_mask |= FOUND_MASK_BMODEL; + } else if (!strcmp(namebuf, "version")) { + prop_buf = np->vpd.version; + max_len = NIU_VPD_VERSION_MAX; + found_mask |= FOUND_MASK_VERS; + } else if (!strcmp(namebuf, "local-mac-address")) { + prop_buf = np->vpd.local_mac; + max_len = ETH_ALEN; + found_mask |= FOUND_MASK_MAC; + } else if (!strcmp(namebuf, "num-mac-addresses")) { + prop_buf = &np->vpd.mac_num; + max_len = 1; + found_mask |= FOUND_MASK_NMAC; + } else if (!strcmp(namebuf, "phy-type")) { + prop_buf = np->vpd.phy_type; + max_len = NIU_VPD_PHY_TYPE_MAX; + found_mask |= FOUND_MASK_PHY; + } + + if (max_len && prop_len > max_len) { + dev_err(np->device, PFX "Property '%s' length (%d) is " + "too long.\n", namebuf, prop_len); + return -EINVAL; + } + + if (prop_buf) { + u32 off = start + 5 + err; + int i; + + niudbg(PROBE, "VPD_SCAN: Reading in property [%s] " + "len[%d]\n", namebuf, prop_len); + for (i = 0; i < prop_len; i++) + *prop_buf++ = niu_pci_eeprom_read(np, off + i); + } + + start += len; + } + + return 0; +} + +/* ESPC_PIO_EN_ENABLE must be set */ +static void __devinit niu_pci_vpd_fetch(struct niu *np, u32 start) +{ + u32 offset; + int err; + + err = niu_pci_eeprom_read16_swp(np, start + 1); + if (err < 0) + return; + + offset = err + 3; + + while (start + offset < ESPC_EEPROM_SIZE) { + u32 here = start + offset; + u32 end; + + err = niu_pci_eeprom_read(np, here); + if (err != 0x90) + return; + + err = niu_pci_eeprom_read16_swp(np, here + 1); + if (err < 0) + return; + + here = start + offset + 3; + end = start + offset + err; + + offset += err; + + err = niu_pci_vpd_scan_props(np, here, end); + if (err < 0 || err == 1) + return; + } +} + +/* ESPC_PIO_EN_ENABLE must be set */ +static u32 __devinit niu_pci_vpd_offset(struct niu *np) +{ + u32 start = 0, end = ESPC_EEPROM_SIZE, ret; + int err; + + while (start < end) { + ret = start; + + /* ROM header signature? */ + err = niu_pci_eeprom_read16(np, start + 0); + if (err != 0x55aa) + return 0; + + /* Apply offset to PCI data structure. */ + err = niu_pci_eeprom_read16(np, start + 23); + if (err < 0) + return 0; + start += err; + + /* Check for "PCIR" signature. */ + err = niu_pci_eeprom_read16(np, start + 0); + if (err != 0x5043) + return 0; + err = niu_pci_eeprom_read16(np, start + 2); + if (err != 0x4952) + return 0; + + /* Check for OBP image type. */ + err = niu_pci_eeprom_read(np, start + 20); + if (err < 0) + return 0; + if (err != 0x01) { + err = niu_pci_eeprom_read(np, ret + 2); + if (err < 0) + return 0; + + start = ret + (err * 512); + continue; + } + + err = niu_pci_eeprom_read16_swp(np, start + 8); + if (err < 0) + return err; + ret += err; + + err = niu_pci_eeprom_read(np, ret + 0); + if (err != 0x82) + return 0; + + return ret; + } + + return 0; +} + +static int __devinit niu_phy_type_prop_decode(struct niu *np, + const char *phy_prop) +{ + if (!strcmp(phy_prop, "mif")) { + /* 1G copper, MII */ + np->flags &= ~(NIU_FLAGS_FIBER | + NIU_FLAGS_10G); + np->mac_xcvr = MAC_XCVR_MII; + } else if (!strcmp(phy_prop, "xgf")) { + /* 10G fiber, XPCS */ + np->flags |= (NIU_FLAGS_10G | + NIU_FLAGS_FIBER); + np->mac_xcvr = MAC_XCVR_XPCS; + } else if (!strcmp(phy_prop, "pcs")) { + /* 1G fiber, PCS */ + np->flags &= ~NIU_FLAGS_10G; + np->flags |= NIU_FLAGS_FIBER; + np->mac_xcvr = MAC_XCVR_PCS; + } else if (!strcmp(phy_prop, "xgc")) { + /* 10G copper, XPCS */ + np->flags |= NIU_FLAGS_10G; + np->flags &= ~NIU_FLAGS_FIBER; + np->mac_xcvr = MAC_XCVR_XPCS; + } else { + return -EINVAL; + } + return 0; +} + +static void __devinit niu_pci_vpd_validate(struct niu *np) +{ + struct net_device *dev = np->dev; + struct niu_vpd *vpd = &np->vpd; + u8 val8; + + if (!is_valid_ether_addr(&vpd->local_mac[0])) { + dev_err(np->device, PFX "VPD MAC invalid, " + "falling back to SPROM.\n"); + + np->flags &= ~NIU_FLAGS_VPD_VALID; + return; + } + + if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) { + dev_err(np->device, PFX "Illegal phy string [%s].\n", + np->vpd.phy_type); + dev_err(np->device, PFX "Falling back to SPROM.\n"); + np->flags &= ~NIU_FLAGS_VPD_VALID; + return; + } + + memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN); + + val8 = dev->perm_addr[5]; + dev->perm_addr[5] += np->port; + if (dev->perm_addr[5] < val8) + dev->perm_addr[4]++; + + memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len); +} + +static int __devinit niu_pci_probe_sprom(struct niu *np) +{ + struct net_device *dev = np->dev; + int len, i; + u64 val, sum; + u8 val8; + + val = (nr64(ESPC_VER_IMGSZ) & ESPC_VER_IMGSZ_IMGSZ); + val >>= ESPC_VER_IMGSZ_IMGSZ_SHIFT; + len = val / 4; + + np->eeprom_len = len; + + niudbg(PROBE, "SPROM: Image size %llu\n", (unsigned long long) val); + + sum = 0; + for (i = 0; i < len; i++) { + val = nr64(ESPC_NCR(i)); + sum += (val >> 0) & 0xff; + sum += (val >> 8) & 0xff; + sum += (val >> 16) & 0xff; + sum += (val >> 24) & 0xff; + } + niudbg(PROBE, "SPROM: Checksum %x\n", (int)(sum & 0xff)); + if ((sum & 0xff) != 0xab) { + dev_err(np->device, PFX "Bad SPROM checksum " + "(%x, should be 0xab)\n", (int) (sum & 0xff)); + return -EINVAL; + } + + val = nr64(ESPC_PHY_TYPE); + switch (np->port) { + case 0: + val = (val & ESPC_PHY_TYPE_PORT0) >> + ESPC_PHY_TYPE_PORT0_SHIFT; + break; + case 1: + val = (val & ESPC_PHY_TYPE_PORT1) >> + ESPC_PHY_TYPE_PORT1_SHIFT; + break; + case 2: + val = (val & ESPC_PHY_TYPE_PORT2) >> + ESPC_PHY_TYPE_PORT2_SHIFT; + break; + case 3: + val = (val & ESPC_PHY_TYPE_PORT3) >> + ESPC_PHY_TYPE_PORT3_SHIFT; + break; + default: + dev_err(np->device, PFX "Bogus port number %u\n", + np->port); + return -EINVAL; + } + niudbg(PROBE, "SPROM: PHY type %llx\n", (unsigned long long) val); + + switch (val) { + case ESPC_PHY_TYPE_1G_COPPER: + /* 1G copper, MII */ + np->flags &= ~(NIU_FLAGS_FIBER | + NIU_FLAGS_10G); + np->mac_xcvr = MAC_XCVR_MII; + break; + + case ESPC_PHY_TYPE_1G_FIBER: + /* 1G fiber, PCS */ + np->flags &= ~NIU_FLAGS_10G; + np->flags |= NIU_FLAGS_FIBER; + np->mac_xcvr = MAC_XCVR_PCS; + break; + + case ESPC_PHY_TYPE_10G_COPPER: + /* 10G copper, XPCS */ + np->flags |= NIU_FLAGS_10G; + np->flags &= ~NIU_FLAGS_FIBER; + np->mac_xcvr = MAC_XCVR_XPCS; + break; + + case ESPC_PHY_TYPE_10G_FIBER: + /* 10G fiber, XPCS */ + np->flags |= (NIU_FLAGS_10G | + NIU_FLAGS_FIBER); + np->mac_xcvr = MAC_XCVR_XPCS; + break; + + default: + dev_err(np->device, PFX "Bogus SPROM phy type %llu\n", + (unsigned long long) val); + return -EINVAL; + } + + val = nr64(ESPC_MAC_ADDR0); + niudbg(PROBE, "SPROM: MAC_ADDR0[%08llx]\n", + (unsigned long long) val); + dev->perm_addr[0] = (val >> 0) & 0xff; + dev->perm_addr[1] = (val >> 8) & 0xff; + dev->perm_addr[2] = (val >> 16) & 0xff; + dev->perm_addr[3] = (val >> 24) & 0xff; + + val = nr64(ESPC_MAC_ADDR1); + niudbg(PROBE, "SPROM: MAC_ADDR1[%08llx]\n", + (unsigned long long) val); + dev->perm_addr[4] = (val >> 0) & 0xff; + dev->perm_addr[5] = (val >> 8) & 0xff; + + if (!is_valid_ether_addr(&dev->perm_addr[0])) { + dev_err(np->device, PFX "SPROM MAC address invalid\n"); + dev_err(np->device, PFX "[ \n"); + for (i = 0; i < 6; i++) + printk("%02x ", dev->perm_addr[i]); + printk("]\n"); + return -EINVAL; + } + + val8 = dev->perm_addr[5]; + dev->perm_addr[5] += np->port; + if (dev->perm_addr[5] < val8) + dev->perm_addr[4]++; + + memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len); + + val = nr64(ESPC_MOD_STR_LEN); + niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n", + (unsigned long long) val); + if (val > 8 * 4) + return -EINVAL; + + for (i = 0; i < val; i += 4) { + u64 tmp = nr64(ESPC_NCR(5 + (i / 4))); + + np->vpd.model[i + 3] = (tmp >> 0) & 0xff; + np->vpd.model[i + 2] = (tmp >> 8) & 0xff; + np->vpd.model[i + 1] = (tmp >> 16) & 0xff; + np->vpd.model[i + 0] = (tmp >> 24) & 0xff; + } + np->vpd.model[val] = '\0'; + + val = nr64(ESPC_BD_MOD_STR_LEN); + niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n", + (unsigned long long) val); + if (val > 4 * 4) + return -EINVAL; + + for (i = 0; i < val; i += 4) { + u64 tmp = nr64(ESPC_NCR(14 + (i / 4))); + + np->vpd.board_model[i + 3] = (tmp >> 0) & 0xff; + np->vpd.board_model[i + 2] = (tmp >> 8) & 0xff; + np->vpd.board_model[i + 1] = (tmp >> 16) & 0xff; + np->vpd.board_model[i + 0] = (tmp >> 24) & 0xff; + } + np->vpd.board_model[val] = '\0'; + + np->vpd.mac_num = + nr64(ESPC_NUM_PORTS_MACS) & ESPC_NUM_PORTS_MACS_VAL; + niudbg(PROBE, "SPROM: NUM_PORTS_MACS[%d]\n", + np->vpd.mac_num); + + return 0; +} + +static int __devinit niu_get_and_validate_port(struct niu *np) +{ + struct niu_parent *parent = np->parent; + + if (np->port <= 1) + np->flags |= NIU_FLAGS_XMAC; + + if (!parent->num_ports) { + if (parent->plat_type == PLAT_TYPE_NIU) { + parent->num_ports = 2; + } else { + parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) & + ESPC_NUM_PORTS_MACS_VAL; + + if (!parent->num_ports) + parent->num_ports = 4; + } + } + + niudbg(PROBE, "niu_get_and_validate_port: port[%d] num_ports[%d]\n", + np->port, parent->num_ports); + if (np->port >= parent->num_ports) + return -ENODEV; + + return 0; +} + +static int __devinit phy_record(struct niu_parent *parent, + struct phy_probe_info *p, + int dev_id_1, int dev_id_2, u8 phy_port, + int type) +{ + u32 id = (dev_id_1 << 16) | dev_id_2; + u8 idx; + + if (dev_id_1 < 0 || dev_id_2 < 0) + return 0; + if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) { + if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) + return 0; + } else { + if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R) + return 0; + } + + pr_info("niu%d: Found PHY %08x type %s at phy_port %u\n", + parent->index, id, + (type == PHY_TYPE_PMA_PMD ? + "PMA/PMD" : + (type == PHY_TYPE_PCS ? + "PCS" : "MII")), + phy_port); + + if (p->cur[type] >= NIU_MAX_PORTS) { + printk(KERN_ERR PFX "Too many PHY ports.\n"); + return -EINVAL; + } + idx = p->cur[type]; + p->phy_id[type][idx] = id; + p->phy_port[type][idx] = phy_port; + p->cur[type] = idx + 1; + return 0; +} + +static int __devinit port_has_10g(struct phy_probe_info *p, int port) +{ + int i; + + for (i = 0; i < p->cur[PHY_TYPE_PMA_PMD]; i++) { + if (p->phy_port[PHY_TYPE_PMA_PMD][i] == port) + return 1; + } + for (i = 0; i < p->cur[PHY_TYPE_PCS]; i++) { + if (p->phy_port[PHY_TYPE_PCS][i] == port) + return 1; + } + + return 0; +} + +static int __devinit count_10g_ports(struct phy_probe_info *p, int *lowest) +{ + int port, cnt; + + cnt = 0; + *lowest = 32; + for (port = 8; port < 32; port++) { + if (port_has_10g(p, port)) { + if (!cnt) + *lowest = port; + cnt++; + } + } + + return cnt; +} + +static int __devinit count_1g_ports(struct phy_probe_info *p, int *lowest) +{ + *lowest = 32; + if (p->cur[PHY_TYPE_MII]) + *lowest = p->phy_port[PHY_TYPE_MII][0]; + + return p->cur[PHY_TYPE_MII]; +} + +static void __devinit niu_n2_divide_channels(struct niu_parent *parent) +{ + int num_ports = parent->num_ports; + int i; + + for (i = 0; i < num_ports; i++) { + parent->rxchan_per_port[i] = (16 / num_ports); + parent->txchan_per_port[i] = (16 / num_ports); + + pr_info(PFX "niu%d: Port %u [%u RX chans] " + "[%u TX chans]\n", + parent->index, i, + parent->rxchan_per_port[i], + parent->txchan_per_port[i]); + } +} + +static void __devinit niu_divide_channels(struct niu_parent *parent, + int num_10g, int num_1g) +{ + int num_ports = parent->num_ports; + int rx_chans_per_10g, rx_chans_per_1g; + int tx_chans_per_10g, tx_chans_per_1g; + int i, tot_rx, tot_tx; + + if (!num_10g || !num_1g) { + rx_chans_per_10g = rx_chans_per_1g = + (NIU_NUM_RXCHAN / num_ports); + tx_chans_per_10g = tx_chans_per_1g = + (NIU_NUM_TXCHAN / num_ports); + } else { + rx_chans_per_1g = NIU_NUM_RXCHAN / 8; + rx_chans_per_10g = (NIU_NUM_RXCHAN - + (rx_chans_per_1g * num_1g)) / + num_10g; + + tx_chans_per_1g = NIU_NUM_TXCHAN / 6; + tx_chans_per_10g = (NIU_NUM_TXCHAN - + (tx_chans_per_1g * num_1g)) / + num_10g; + } + + tot_rx = tot_tx = 0; + for (i = 0; i < num_ports; i++) { + int type = phy_decode(parent->port_phy, i); + + if (type == PORT_TYPE_10G) { + parent->rxchan_per_port[i] = rx_chans_per_10g; + parent->txchan_per_port[i] = tx_chans_per_10g; + } else { + parent->rxchan_per_port[i] = rx_chans_per_1g; + parent->txchan_per_port[i] = tx_chans_per_1g; + } + pr_info(PFX "niu%d: Port %u [%u RX chans] " + "[%u TX chans]\n", + parent->index, i, + parent->rxchan_per_port[i], + parent->txchan_per_port[i]); + tot_rx += parent->rxchan_per_port[i]; + tot_tx += parent->txchan_per_port[i]; + } + + if (tot_rx > NIU_NUM_RXCHAN) { + printk(KERN_ERR PFX "niu%d: Too many RX channels (%d), " + "resetting to one per port.\n", + parent->index, tot_rx); + for (i = 0; i < num_ports; i++) + parent->rxchan_per_port[i] = 1; + } + if (tot_tx > NIU_NUM_TXCHAN) { + printk(KERN_ERR PFX "niu%d: Too many TX channels (%d), " + "resetting to one per port.\n", + parent->index, tot_tx); + for (i = 0; i < num_ports; i++) + parent->txchan_per_port[i] = 1; + } + if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) { + printk(KERN_WARNING PFX "niu%d: Driver bug, wasted channels, " + "RX[%d] TX[%d]\n", + parent->index, tot_rx, tot_tx); + } +} + +static void __devinit niu_divide_rdc_groups(struct niu_parent *parent, + int num_10g, int num_1g) +{ + int i, num_ports = parent->num_ports; + int rdc_group, rdc_groups_per_port; + int rdc_channel_base; + + rdc_group = 0; + rdc_groups_per_port = NIU_NUM_RDC_TABLES / num_ports; + + rdc_channel_base = 0; + + for (i = 0; i < num_ports; i++) { + struct niu_rdc_tables *tp = &parent->rdc_group_cfg[i]; + int grp, num_channels = parent->rxchan_per_port[i]; + int this_channel_offset; + + tp->first_table_num = rdc_group; + tp->num_tables = rdc_groups_per_port; + this_channel_offset = 0; + for (grp = 0; grp < tp->num_tables; grp++) { + struct rdc_table *rt = &tp->tables[grp]; + int slot; + + pr_info(PFX "niu%d: Port %d RDC tbl(%d) [ ", + parent->index, i, tp->first_table_num + grp); + for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) { + rt->rxdma_channel[slot] = + rdc_channel_base + this_channel_offset; + + printk("%d ", rt->rxdma_channel[slot]); + + if (++this_channel_offset == num_channels) + this_channel_offset = 0; + } + printk("]\n"); + } + + parent->rdc_default[i] = rdc_channel_base; + + rdc_channel_base += num_channels; + rdc_group += rdc_groups_per_port; + } +} + +static int __devinit fill_phy_probe_info(struct niu *np, + struct niu_parent *parent, + struct phy_probe_info *info) +{ + unsigned long flags; + int port, err; + + memset(info, 0, sizeof(*info)); + + /* Port 0 to 7 are reserved for onboard Serdes, probe the rest. */ + niu_lock_parent(np, flags); + err = 0; + for (port = 8; port < 32; port++) { + int dev_id_1, dev_id_2; + + dev_id_1 = mdio_read(np, port, + NIU_PMA_PMD_DEV_ADDR, MII_PHYSID1); + dev_id_2 = mdio_read(np, port, + NIU_PMA_PMD_DEV_ADDR, MII_PHYSID2); + err = phy_record(parent, info, dev_id_1, dev_id_2, port, + PHY_TYPE_PMA_PMD); + if (err) + break; + dev_id_1 = mdio_read(np, port, + NIU_PCS_DEV_ADDR, MII_PHYSID1); + dev_id_2 = mdio_read(np, port, + NIU_PCS_DEV_ADDR, MII_PHYSID2); + err = phy_record(parent, info, dev_id_1, dev_id_2, port, + PHY_TYPE_PCS); + if (err) + break; + dev_id_1 = mii_read(np, port, MII_PHYSID1); + dev_id_2 = mii_read(np, port, MII_PHYSID2); + err = phy_record(parent, info, dev_id_1, dev_id_2, port, + PHY_TYPE_MII); + if (err) + break; + } + niu_unlock_parent(np, flags); + + return err; +} + +static int __devinit walk_phys(struct niu *np, struct niu_parent *parent) +{ + struct phy_probe_info *info = &parent->phy_probe_info; + int lowest_10g, lowest_1g; + int num_10g, num_1g; + u32 val; + int err; + + err = fill_phy_probe_info(np, parent, info); + if (err) + return err; + + num_10g = count_10g_ports(info, &lowest_10g); + num_1g = count_1g_ports(info, &lowest_1g); + + switch ((num_10g << 4) | num_1g) { + case 0x24: + if (lowest_1g == 10) + parent->plat_type = PLAT_TYPE_VF_P0; + else if (lowest_1g == 26) + parent->plat_type = PLAT_TYPE_VF_P1; + else + goto unknown_vg_1g_port; + + /* fallthru */ + case 0x22: + val = (phy_encode(PORT_TYPE_10G, 0) | + phy_encode(PORT_TYPE_10G, 1) | + phy_encode(PORT_TYPE_1G, 2) | + phy_encode(PORT_TYPE_1G, 3)); + break; + + case 0x20: + val = (phy_encode(PORT_TYPE_10G, 0) | + phy_encode(PORT_TYPE_10G, 1)); + break; + + case 0x10: + val = phy_encode(PORT_TYPE_10G, np->port); + break; + + case 0x14: + if (lowest_1g == 10) + parent->plat_type = PLAT_TYPE_VF_P0; + else if (lowest_1g == 26) + parent->plat_type = PLAT_TYPE_VF_P1; + else + goto unknown_vg_1g_port; + + /* fallthru */ + case 0x13: + if ((lowest_10g & 0x7) == 0) + val = (phy_encode(PORT_TYPE_10G, 0) | + phy_encode(PORT_TYPE_1G, 1) | + phy_encode(PORT_TYPE_1G, 2) | + phy_encode(PORT_TYPE_1G, 3)); + else + val = (phy_encode(PORT_TYPE_1G, 0) | + phy_encode(PORT_TYPE_10G, 1) | + phy_encode(PORT_TYPE_1G, 2) | + phy_encode(PORT_TYPE_1G, 3)); + break; + + case 0x04: + if (lowest_1g == 10) + parent->plat_type = PLAT_TYPE_VF_P0; + else if (lowest_1g == 26) + parent->plat_type = PLAT_TYPE_VF_P1; + else + goto unknown_vg_1g_port; + + val = (phy_encode(PORT_TYPE_1G, 0) | + phy_encode(PORT_TYPE_1G, 1) | + phy_encode(PORT_TYPE_1G, 2) | + phy_encode(PORT_TYPE_1G, 3)); + break; + + default: + printk(KERN_ERR PFX "Unsupported port config " + "10G[%d] 1G[%d]\n", + num_10g, num_1g); + return -EINVAL; + } + + parent->port_phy = val; + + if (parent->plat_type == PLAT_TYPE_NIU) + niu_n2_divide_channels(parent); + else + niu_divide_channels(parent, num_10g, num_1g); + + niu_divide_rdc_groups(parent, num_10g, num_1g); + + return 0; + +unknown_vg_1g_port: + printk(KERN_ERR PFX "Cannot identify platform type, 1gport=%d\n", + lowest_1g); + return -EINVAL; +} + +static int __devinit niu_probe_ports(struct niu *np) +{ + struct niu_parent *parent = np->parent; + int err, i; + + niudbg(PROBE, "niu_probe_ports(): port_phy[%08x]\n", + parent->port_phy); + + if (parent->port_phy == PORT_PHY_UNKNOWN) { + err = walk_phys(np, parent); + if (err) + return err; + + niu_set_ldg_timer_res(np, 2); + for (i = 0; i <= LDN_MAX; i++) + niu_ldn_irq_enable(np, i, 0); + } + + if (parent->port_phy == PORT_PHY_INVALID) + return -EINVAL; + + return 0; +} + +static int __devinit niu_classifier_swstate_init(struct niu *np) +{ + struct niu_classifier *cp = &np->clas; + + niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n", + np->parent->tcam_num_entries); + + cp->tcam_index = (u16) np->port; + cp->h1_init = 0xffffffff; + cp->h2_init = 0xffff; + + return fflp_early_init(np); +} + +static void __devinit niu_link_config_init(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + + lp->advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full | + ADVERTISED_Autoneg); + lp->speed = lp->active_speed = SPEED_INVALID; + lp->duplex = lp->active_duplex = DUPLEX_INVALID; +#if 0 + lp->loopback_mode = LOOPBACK_MAC; + lp->active_speed = SPEED_10000; + lp->active_duplex = DUPLEX_FULL; +#else + lp->loopback_mode = LOOPBACK_DISABLED; +#endif +} + +static int __devinit niu_init_mac_ipp_pcs_base(struct niu *np) +{ + switch (np->port) { + case 0: + np->mac_regs = np->regs + XMAC_PORT0_OFF; + np->ipp_off = 0x00000; + np->pcs_off = 0x04000; + np->xpcs_off = 0x02000; + break; + + case 1: + np->mac_regs = np->regs + XMAC_PORT1_OFF; + np->ipp_off = 0x08000; + np->pcs_off = 0x0a000; + np->xpcs_off = 0x08000; + break; + + case 2: + np->mac_regs = np->regs + BMAC_PORT2_OFF; + np->ipp_off = 0x04000; + np->pcs_off = 0x0e000; + np->xpcs_off = ~0UL; + break; + + case 3: + np->mac_regs = np->regs + BMAC_PORT3_OFF; + np->ipp_off = 0x0c000; + np->pcs_off = 0x12000; + np->xpcs_off = ~0UL; + break; + + default: + dev_err(np->device, PFX "Port %u is invalid, cannot " + "compute MAC block offset.\n", np->port); + return -EINVAL; + } + + return 0; +} + +static void __devinit niu_try_msix(struct niu *np, u8 *ldg_num_map) +{ + struct msix_entry msi_vec[NIU_NUM_LDG]; + struct niu_parent *parent = np->parent; + struct pci_dev *pdev = np->pdev; + int i, num_irqs, err; + u8 first_ldg; + + first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port; + for (i = 0; i < (NIU_NUM_LDG / parent->num_ports); i++) + ldg_num_map[i] = first_ldg + i; + + num_irqs = (parent->rxchan_per_port[np->port] + + parent->txchan_per_port[np->port] + + (np->port == 0 ? 3 : 1)); + BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports)); + +retry: + for (i = 0; i < num_irqs; i++) { + msi_vec[i].vector = 0; + msi_vec[i].entry = i; + } + + err = pci_enable_msix(pdev, msi_vec, num_irqs); + if (err < 0) { + np->flags &= ~NIU_FLAGS_MSIX; + return; + } + if (err > 0) { + num_irqs = err; + goto retry; + } + + np->flags |= NIU_FLAGS_MSIX; + for (i = 0; i < num_irqs; i++) + np->ldg[i].irq = msi_vec[i].vector; + np->num_ldg = num_irqs; +} + +static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map) +{ +#ifdef CONFIG_SPARC64 + struct of_device *op = np->op; + const u32 *int_prop; + int i; + + int_prop = of_get_property(op->node, "interrupts", NULL); + if (!int_prop) + return -ENODEV; + + for (i = 0; i < op->num_irqs; i++) { + ldg_num_map[i] = int_prop[i]; + np->ldg[i].irq = op->irqs[i]; + } + + np->num_ldg = op->num_irqs; + + return 0; +#else + return -EINVAL; +#endif +} + +static int __devinit niu_ldg_init(struct niu *np) +{ + struct niu_parent *parent = np->parent; + u8 ldg_num_map[NIU_NUM_LDG]; + int first_chan, num_chan; + int i, err, ldg_rotor; + u8 port; + + np->num_ldg = 1; + np->ldg[0].irq = np->dev->irq; + if (parent->plat_type == PLAT_TYPE_NIU) { + err = niu_n2_irq_init(np, ldg_num_map); + if (err) + return err; + } else + niu_try_msix(np, ldg_num_map); + + port = np->port; + for (i = 0; i < np->num_ldg; i++) { + struct niu_ldg *lp = &np->ldg[i]; + + netif_napi_add(np->dev, &lp->napi, niu_poll, 64); + + lp->np = np; + lp->ldg_num = ldg_num_map[i]; + lp->timer = 2; /* XXX */ + + /* On N2 NIU the firmware has setup the SID mappings so they go + * to the correct values that will route the LDG to the proper + * interrupt in the NCU interrupt table. + */ + if (np->parent->plat_type != PLAT_TYPE_NIU) { + err = niu_set_ldg_sid(np, lp->ldg_num, port, i); + if (err) + return err; + } + } + + /* We adopt the LDG assignment ordering used by the N2 NIU + * 'interrupt' properties because that simplifies a lot of + * things. This ordering is: + * + * MAC + * MIF (if port zero) + * SYSERR (if port zero) + * RX channels + * TX channels + */ + + ldg_rotor = 0; + + err = niu_ldg_assign_ldn(np, parent, ldg_num_map[ldg_rotor], + LDN_MAC(port)); + if (err) + return err; + + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + + if (port == 0) { + err = niu_ldg_assign_ldn(np, parent, + ldg_num_map[ldg_rotor], + LDN_MIF); + if (err) + return err; + + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + + err = niu_ldg_assign_ldn(np, parent, + ldg_num_map[ldg_rotor], + LDN_DEVICE_ERROR); + if (err) + return err; + + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + + } + + first_chan = 0; + for (i = 0; i < port; i++) + first_chan += parent->rxchan_per_port[port]; + num_chan = parent->rxchan_per_port[port]; + + for (i = first_chan; i < (first_chan + num_chan); i++) { + err = niu_ldg_assign_ldn(np, parent, + ldg_num_map[ldg_rotor], + LDN_RXDMA(i)); + if (err) + return err; + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + } + + first_chan = 0; + for (i = 0; i < port; i++) + first_chan += parent->txchan_per_port[port]; + num_chan = parent->txchan_per_port[port]; + for (i = first_chan; i < (first_chan + num_chan); i++) { + err = niu_ldg_assign_ldn(np, parent, + ldg_num_map[ldg_rotor], + LDN_TXDMA(i)); + if (err) + return err; + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + } + + return 0; +} + +static void __devexit niu_ldg_free(struct niu *np) +{ + if (np->flags & NIU_FLAGS_MSIX) + pci_disable_msix(np->pdev); +} + +static int __devinit niu_get_of_props(struct niu *np) +{ +#ifdef CONFIG_SPARC64 + struct net_device *dev = np->dev; + struct device_node *dp; + const char *phy_type; + const u8 *mac_addr; + int prop_len; + + if (np->parent->plat_type == PLAT_TYPE_NIU) + dp = np->op->node; + else + dp = pci_device_to_OF_node(np->pdev); + + phy_type = of_get_property(dp, "phy-type", &prop_len); + if (!phy_type) { + dev_err(np->device, PFX "%s: OF node lacks " + "phy-type property\n", + dp->full_name); + return -EINVAL; + } + + if (!strcmp(phy_type, "none")) + return -ENODEV; + + strcpy(np->vpd.phy_type, phy_type); + + if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) { + dev_err(np->device, PFX "%s: Illegal phy string [%s].\n", + dp->full_name, np->vpd.phy_type); + return -EINVAL; + } + + mac_addr = of_get_property(dp, "local-mac-address", &prop_len); + if (!mac_addr) { + dev_err(np->device, PFX "%s: OF node lacks " + "local-mac-address property\n", + dp->full_name); + return -EINVAL; + } + if (prop_len != dev->addr_len) { + dev_err(np->device, PFX "%s: OF MAC address prop len (%d) " + "is wrong.\n", + dp->full_name, prop_len); + } + memcpy(dev->perm_addr, mac_addr, dev->addr_len); + if (!is_valid_ether_addr(&dev->perm_addr[0])) { + int i; + + dev_err(np->device, PFX "%s: OF MAC address is invalid\n", + dp->full_name); + dev_err(np->device, PFX "%s: [ \n", + dp->full_name); + for (i = 0; i < 6; i++) + printk("%02x ", dev->perm_addr[i]); + printk("]\n"); + return -EINVAL; + } + + memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len); + + return 0; +#else + return -EINVAL; +#endif +} + +static int __devinit niu_get_invariants(struct niu *np) +{ + int err, have_props; + u32 offset; + + err = niu_get_of_props(np); + if (err == -ENODEV) + return err; + + have_props = !err; + + err = niu_get_and_validate_port(np); + if (err) + return err; + + err = niu_init_mac_ipp_pcs_base(np); + if (err) + return err; + + if (!have_props) { + if (np->parent->plat_type == PLAT_TYPE_NIU) + return -EINVAL; + + nw64(ESPC_PIO_EN, ESPC_PIO_EN_ENABLE); + offset = niu_pci_vpd_offset(np); + niudbg(PROBE, "niu_get_invariants: VPD offset [%08x]\n", + offset); + if (offset) + niu_pci_vpd_fetch(np, offset); + nw64(ESPC_PIO_EN, 0); + + if (np->flags & NIU_FLAGS_VPD_VALID) + niu_pci_vpd_validate(np); + + if (!(np->flags & NIU_FLAGS_VPD_VALID)) { + err = niu_pci_probe_sprom(np); + if (err) + return err; + } + } + + err = niu_probe_ports(np); + if (err) + return err; + + niu_ldg_init(np); + + niu_classifier_swstate_init(np); + niu_link_config_init(np); + + err = niu_determine_phy_disposition(np); + if (!err) + err = niu_init_link(np); + + return err; +} + +static LIST_HEAD(niu_parent_list); +static DEFINE_MUTEX(niu_parent_lock); +static int niu_parent_index; + +static ssize_t show_port_phy(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct niu_parent *p = plat_dev->dev.platform_data; + u32 port_phy = p->port_phy; + char *orig_buf = buf; + int i; + + if (port_phy == PORT_PHY_UNKNOWN || + port_phy == PORT_PHY_INVALID) + return 0; + + for (i = 0; i < p->num_ports; i++) { + const char *type_str; + int type; + + type = phy_decode(port_phy, i); + if (type == PORT_TYPE_10G) + type_str = "10G"; + else + type_str = "1G"; + buf += sprintf(buf, + (i == 0) ? "%s" : " %s", + type_str); + } + buf += sprintf(buf, "\n"); + return buf - orig_buf; +} + +static ssize_t show_plat_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct niu_parent *p = plat_dev->dev.platform_data; + const char *type_str; + + switch (p->plat_type) { + case PLAT_TYPE_ATLAS: + type_str = "atlas"; + break; + case PLAT_TYPE_NIU: + type_str = "niu"; + break; + case PLAT_TYPE_VF_P0: + type_str = "vf_p0"; + break; + case PLAT_TYPE_VF_P1: + type_str = "vf_p1"; + break; + default: + type_str = "unknown"; + break; + } + + return sprintf(buf, "%s\n", type_str); +} + +static ssize_t __show_chan_per_port(struct device *dev, + struct device_attribute *attr, char *buf, + int rx) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct niu_parent *p = plat_dev->dev.platform_data; + char *orig_buf = buf; + u8 *arr; + int i; + + arr = (rx ? p->rxchan_per_port : p->txchan_per_port); + + for (i = 0; i < p->num_ports; i++) { + buf += sprintf(buf, + (i == 0) ? "%d" : " %d", + arr[i]); + } + buf += sprintf(buf, "\n"); + + return buf - orig_buf; +} + +static ssize_t show_rxchan_per_port(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return __show_chan_per_port(dev, attr, buf, 1); +} + +static ssize_t show_txchan_per_port(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return __show_chan_per_port(dev, attr, buf, 1); +} + +static ssize_t show_num_ports(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct niu_parent *p = plat_dev->dev.platform_data; + + return sprintf(buf, "%d\n", p->num_ports); +} + +static struct device_attribute niu_parent_attributes[] = { + __ATTR(port_phy, S_IRUGO, show_port_phy, NULL), + __ATTR(plat_type, S_IRUGO, show_plat_type, NULL), + __ATTR(rxchan_per_port, S_IRUGO, show_rxchan_per_port, NULL), + __ATTR(txchan_per_port, S_IRUGO, show_txchan_per_port, NULL), + __ATTR(num_ports, S_IRUGO, show_num_ports, NULL), + {} +}; + +static struct niu_parent * __devinit niu_new_parent(struct niu *np, + union niu_parent_id *id, + u8 ptype) +{ + struct platform_device *plat_dev; + struct niu_parent *p; + int i; + + niudbg(PROBE, "niu_new_parent: Creating new parent.\n"); + + plat_dev = platform_device_register_simple("niu", niu_parent_index, + NULL, 0); + if (!plat_dev) + return NULL; + + for (i = 0; attr_name(niu_parent_attributes[i]); i++) { + int err = device_create_file(&plat_dev->dev, + &niu_parent_attributes[i]); + if (err) + goto fail_unregister; + } + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto fail_unregister; + + p->index = niu_parent_index++; + + plat_dev->dev.platform_data = p; + p->plat_dev = plat_dev; + + memcpy(&p->id, id, sizeof(*id)); + p->plat_type = ptype; + INIT_LIST_HEAD(&p->list); + atomic_set(&p->refcnt, 0); + list_add(&p->list, &niu_parent_list); + spin_lock_init(&p->lock); + + p->rxdma_clock_divider = 7500; + + p->tcam_num_entries = NIU_PCI_TCAM_ENTRIES; + if (p->plat_type == PLAT_TYPE_NIU) + p->tcam_num_entries = NIU_NONPCI_TCAM_ENTRIES; + + for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) { + int index = i - CLASS_CODE_USER_PROG1; + + p->tcam_key[index] = TCAM_KEY_TSEL; + p->flow_key[index] = (FLOW_KEY_IPSA | + FLOW_KEY_IPDA | + FLOW_KEY_PROTO | + (FLOW_KEY_L4_BYTE12 << + FLOW_KEY_L4_0_SHIFT) | + (FLOW_KEY_L4_BYTE12 << + FLOW_KEY_L4_1_SHIFT)); + } + + for (i = 0; i < LDN_MAX + 1; i++) + p->ldg_map[i] = LDG_INVALID; + + return p; + +fail_unregister: + platform_device_unregister(plat_dev); + return NULL; +} + +static struct niu_parent * __devinit niu_get_parent(struct niu *np, + union niu_parent_id *id, + u8 ptype) +{ + struct niu_parent *p, *tmp; + int port = np->port; + + niudbg(PROBE, "niu_get_parent: platform_type[%u] port[%u]\n", + ptype, port); + + mutex_lock(&niu_parent_lock); + p = NULL; + list_for_each_entry(tmp, &niu_parent_list, list) { + if (!memcmp(id, &tmp->id, sizeof(*id))) { + p = tmp; + break; + } + } + if (!p) + p = niu_new_parent(np, id, ptype); + + if (p) { + char port_name[6]; + int err; + + sprintf(port_name, "port%d", port); + err = sysfs_create_link(&p->plat_dev->dev.kobj, + &np->device->kobj, + port_name); + if (!err) { + p->ports[port] = np; + atomic_inc(&p->refcnt); + } + } + mutex_unlock(&niu_parent_lock); + + return p; +} + +static void niu_put_parent(struct niu *np) +{ + struct niu_parent *p = np->parent; + u8 port = np->port; + char port_name[6]; + + BUG_ON(!p || p->ports[port] != np); + + niudbg(PROBE, "niu_put_parent: port[%u]\n", port); + + sprintf(port_name, "port%d", port); + + mutex_lock(&niu_parent_lock); + + sysfs_remove_link(&p->plat_dev->dev.kobj, port_name); + + p->ports[port] = NULL; + np->parent = NULL; + + if (atomic_dec_and_test(&p->refcnt)) { + list_del(&p->list); + platform_device_unregister(p->plat_dev); + } + + mutex_unlock(&niu_parent_lock); +} + +static void *niu_pci_alloc_coherent(struct device *dev, size_t size, + u64 *handle, gfp_t flag) +{ + dma_addr_t dh; + void *ret; + + ret = dma_alloc_coherent(dev, size, &dh, flag); + if (ret) + *handle = dh; + return ret; +} + +static void niu_pci_free_coherent(struct device *dev, size_t size, + void *cpu_addr, u64 handle) +{ + dma_free_coherent(dev, size, cpu_addr, handle); +} + +static u64 niu_pci_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + return dma_map_page(dev, page, offset, size, direction); +} + +static void niu_pci_unmap_page(struct device *dev, u64 dma_address, + size_t size, enum dma_data_direction direction) +{ + return dma_unmap_page(dev, dma_address, size, direction); +} + +static u64 niu_pci_map_single(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction) +{ + return dma_map_single(dev, cpu_addr, size, direction); +} + +static void niu_pci_unmap_single(struct device *dev, u64 dma_address, + size_t size, + enum dma_data_direction direction) +{ + dma_unmap_single(dev, dma_address, size, direction); +} + +static const struct niu_ops niu_pci_ops = { + .alloc_coherent = niu_pci_alloc_coherent, + .free_coherent = niu_pci_free_coherent, + .map_page = niu_pci_map_page, + .unmap_page = niu_pci_unmap_page, + .map_single = niu_pci_map_single, + .unmap_single = niu_pci_unmap_single, +}; + +static void __devinit niu_driver_version(void) +{ + static int niu_version_printed; + + if (niu_version_printed++ == 0) + pr_info("%s", version); +} + +static struct net_device * __devinit niu_alloc_and_init( + struct device *gen_dev, struct pci_dev *pdev, + struct of_device *op, const struct niu_ops *ops, + u8 port) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct niu)); + struct niu *np; + + if (!dev) { + dev_err(gen_dev, PFX "Etherdev alloc failed, aborting.\n"); + return NULL; + } + + SET_NETDEV_DEV(dev, gen_dev); + + np = netdev_priv(dev); + np->dev = dev; + np->pdev = pdev; + np->op = op; + np->device = gen_dev; + np->ops = ops; + + np->msg_enable = niu_debug; + + spin_lock_init(&np->lock); + INIT_WORK(&np->reset_task, niu_reset_task); + + np->port = port; + + return dev; +} + +static void __devinit niu_assign_netdev_ops(struct net_device *dev) +{ + dev->open = niu_open; + dev->stop = niu_close; + dev->get_stats = niu_get_stats; + dev->set_multicast_list = niu_set_rx_mode; + dev->set_mac_address = niu_set_mac_addr; + dev->do_ioctl = niu_ioctl; + dev->tx_timeout = niu_tx_timeout; + dev->hard_start_xmit = niu_start_xmit; + dev->ethtool_ops = &niu_ethtool_ops; + dev->watchdog_timeo = NIU_TX_TIMEOUT; + dev->change_mtu = niu_change_mtu; +} + +static void __devinit niu_device_announce(struct niu *np) +{ + struct net_device *dev = np->dev; + int i; + + pr_info("%s: NIU Ethernet ", dev->name); + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], + i == 5 ? '\n' : ':'); + + pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n", + dev->name, + (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"), + (np->flags & NIU_FLAGS_10G ? "10G" : "1G"), + (np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"), + (np->mac_xcvr == MAC_XCVR_MII ? "MII" : + (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")), + np->vpd.phy_type); +} + +static int __devinit niu_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + unsigned long niureg_base, niureg_len; + union niu_parent_id parent_id; + struct net_device *dev; + struct niu *np; + int err, pos; + u64 dma_mask; + u16 val16; + + niu_driver_version(); + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, PFX "Cannot enable PCI device, " + "aborting.\n"); + return err; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || + !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, PFX "Cannot find proper PCI device " + "base addresses, aborting.\n"); + err = -ENODEV; + goto err_out_disable_pdev; + } + + err = pci_request_regions(pdev, DRV_MODULE_NAME); + if (err) { + dev_err(&pdev->dev, PFX "Cannot obtain PCI resources, " + "aborting.\n"); + goto err_out_disable_pdev; + } + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (pos <= 0) { + dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, " + "aborting.\n"); + goto err_out_free_res; + } + + dev = niu_alloc_and_init(&pdev->dev, pdev, NULL, + &niu_pci_ops, PCI_FUNC(pdev->devfn)); + if (!dev) { + err = -ENOMEM; + goto err_out_free_res; + } + np = netdev_priv(dev); + + memset(&parent_id, 0, sizeof(parent_id)); + parent_id.pci.domain = pci_domain_nr(pdev->bus); + parent_id.pci.bus = pdev->bus->number; + parent_id.pci.device = PCI_SLOT(pdev->devfn); + + np->parent = niu_get_parent(np, &parent_id, + PLAT_TYPE_ATLAS); + if (!np->parent) { + err = -ENOMEM; + goto err_out_free_dev; + } + + pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16); + val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN; + val16 |= (PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_URRE | + PCI_EXP_DEVCTL_RELAX_EN); + pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16); + + dma_mask = DMA_44BIT_MASK; + err = pci_set_dma_mask(pdev, dma_mask); + if (!err) { + dev->features |= NETIF_F_HIGHDMA; + err = pci_set_consistent_dma_mask(pdev, dma_mask); + if (err) { + dev_err(&pdev->dev, PFX "Unable to obtain 44 bit " + "DMA for consistent allocations, " + "aborting.\n"); + goto err_out_release_parent; + } + } + if (err || dma_mask == DMA_32BIT_MASK) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + dev_err(&pdev->dev, PFX "No usable DMA configuration, " + "aborting.\n"); + goto err_out_release_parent; + } + } + + dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM); + + niureg_base = pci_resource_start(pdev, 0); + niureg_len = pci_resource_len(pdev, 0); + + np->regs = ioremap_nocache(niureg_base, niureg_len); + if (!np->regs) { + dev_err(&pdev->dev, PFX "Cannot map device registers, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_release_parent; + } + + pci_set_master(pdev); + pci_save_state(pdev); + + dev->irq = pdev->irq; + + niu_assign_netdev_ops(dev); + + err = niu_get_invariants(np); + if (err) { + if (err != -ENODEV) + dev_err(&pdev->dev, PFX "Problem fetching invariants " + "of chip, aborting.\n"); + goto err_out_iounmap; + } + + err = register_netdev(dev); + if (err) { + dev_err(&pdev->dev, PFX "Cannot register net device, " + "aborting.\n"); + goto err_out_iounmap; + } + + pci_set_drvdata(pdev, dev); + + niu_device_announce(np); + + return 0; + +err_out_iounmap: + if (np->regs) { + iounmap(np->regs); + np->regs = NULL; + } + +err_out_release_parent: + niu_put_parent(np); + +err_out_free_dev: + free_netdev(dev); + +err_out_free_res: + pci_release_regions(pdev); + +err_out_disable_pdev: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + return err; +} + +static void __devexit niu_pci_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + struct niu *np = netdev_priv(dev); + + unregister_netdev(dev); + if (np->regs) { + iounmap(np->regs); + np->regs = NULL; + } + + niu_ldg_free(np); + + niu_put_parent(np); + + free_netdev(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +static int niu_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct niu *np = netdev_priv(dev); + unsigned long flags; + + if (!netif_running(dev)) + return 0; + + flush_scheduled_work(); + niu_netif_stop(np); + + del_timer_sync(&np->timer); + + spin_lock_irqsave(&np->lock, flags); + niu_enable_interrupts(np, 0); + spin_unlock_irqrestore(&np->lock, flags); + + netif_device_detach(dev); + + spin_lock_irqsave(&np->lock, flags); + niu_stop_hw(np); + spin_unlock_irqrestore(&np->lock, flags); + + pci_save_state(pdev); + + return 0; +} + +static int niu_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct niu *np = netdev_priv(dev); + unsigned long flags; + int err; + + if (!netif_running(dev)) + return 0; + + pci_restore_state(pdev); + + netif_device_attach(dev); + + spin_lock_irqsave(&np->lock, flags); + + err = niu_init_hw(np); + if (!err) { + np->timer.expires = jiffies + HZ; + add_timer(&np->timer); + niu_netif_start(np); + } + + spin_unlock_irqrestore(&np->lock, flags); + + return err; +} + +static struct pci_driver niu_pci_driver = { + .name = DRV_MODULE_NAME, + .id_table = niu_pci_tbl, + .probe = niu_pci_init_one, + .remove = __devexit_p(niu_pci_remove_one), + .suspend = niu_suspend, + .resume = niu_resume, +}; + +#ifdef CONFIG_SPARC64 +static void *niu_phys_alloc_coherent(struct device *dev, size_t size, + u64 *dma_addr, gfp_t flag) +{ + unsigned long order = get_order(size); + unsigned long page = __get_free_pages(flag, order); + + if (page == 0UL) + return NULL; + memset((char *)page, 0, PAGE_SIZE << order); + *dma_addr = __pa(page); + + return (void *) page; +} + +static void niu_phys_free_coherent(struct device *dev, size_t size, + void *cpu_addr, u64 handle) +{ + unsigned long order = get_order(size); + + free_pages((unsigned long) cpu_addr, order); +} + +static u64 niu_phys_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + return page_to_phys(page) + offset; +} + +static void niu_phys_unmap_page(struct device *dev, u64 dma_address, + size_t size, enum dma_data_direction direction) +{ + /* Nothing to do. */ +} + +static u64 niu_phys_map_single(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction) +{ + return __pa(cpu_addr); +} + +static void niu_phys_unmap_single(struct device *dev, u64 dma_address, + size_t size, + enum dma_data_direction direction) +{ + /* Nothing to do. */ +} + +static const struct niu_ops niu_phys_ops = { + .alloc_coherent = niu_phys_alloc_coherent, + .free_coherent = niu_phys_free_coherent, + .map_page = niu_phys_map_page, + .unmap_page = niu_phys_unmap_page, + .map_single = niu_phys_map_single, + .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) +{ + union niu_parent_id parent_id; + struct net_device *dev; + struct niu *np; + const u32 *reg; + int err; + + niu_driver_version(); + + reg = of_get_property(op->node, "reg", NULL); + if (!reg) { + dev_err(&op->dev, PFX "%s: No 'reg' property, aborting.\n", + op->node->full_name); + return -ENODEV; + } + + dev = niu_alloc_and_init(&op->dev, NULL, op, + &niu_phys_ops, reg[0] & 0x1); + if (!dev) { + err = -ENOMEM; + goto err_out; + } + np = netdev_priv(dev); + + memset(&parent_id, 0, sizeof(parent_id)); + parent_id.of = of_get_parent(op->node); + + np->parent = niu_get_parent(np, &parent_id, + PLAT_TYPE_NIU); + if (!np->parent) { + err = -ENOMEM; + goto err_out_free_dev; + } + + dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM); + + np->regs = of_ioremap(&op->resource[1], 0, + res_size(&op->resource[1]), + "niu regs"); + if (!np->regs) { + dev_err(&op->dev, PFX "Cannot map device registers, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_release_parent; + } + + np->vir_regs_1 = of_ioremap(&op->resource[2], 0, + res_size(&op->resource[2]), + "niu vregs-1"); + if (!np->vir_regs_1) { + dev_err(&op->dev, PFX "Cannot map device vir registers 1, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_iounmap; + } + + np->vir_regs_2 = of_ioremap(&op->resource[3], 0, + res_size(&op->resource[3]), + "niu vregs-2"); + if (!np->vir_regs_2) { + dev_err(&op->dev, PFX "Cannot map device vir registers 2, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_iounmap; + } + + niu_assign_netdev_ops(dev); + + err = niu_get_invariants(np); + if (err) { + if (err != -ENODEV) + dev_err(&op->dev, PFX "Problem fetching invariants " + "of chip, aborting.\n"); + goto err_out_iounmap; + } + + err = register_netdev(dev); + if (err) { + dev_err(&op->dev, PFX "Cannot register net device, " + "aborting.\n"); + goto err_out_iounmap; + } + + dev_set_drvdata(&op->dev, dev); + + niu_device_announce(np); + + return 0; + +err_out_iounmap: + if (np->vir_regs_1) { + of_iounmap(&op->resource[2], np->vir_regs_1, + res_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])); + np->vir_regs_2 = NULL; + } + + if (np->regs) { + of_iounmap(&op->resource[1], np->regs, + res_size(&op->resource[1])); + np->regs = NULL; + } + +err_out_release_parent: + niu_put_parent(np); + +err_out_free_dev: + free_netdev(dev); + +err_out: + return err; +} + +static int __devexit niu_of_remove(struct of_device *op) +{ + struct net_device *dev = dev_get_drvdata(&op->dev); + + if (dev) { + struct niu *np = netdev_priv(dev); + + unregister_netdev(dev); + + if (np->vir_regs_1) { + of_iounmap(&op->resource[2], np->vir_regs_1, + res_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])); + np->vir_regs_2 = NULL; + } + + if (np->regs) { + of_iounmap(&op->resource[1], np->regs, + res_size(&op->resource[1])); + np->regs = NULL; + } + + niu_ldg_free(np); + + niu_put_parent(np); + + free_netdev(dev); + dev_set_drvdata(&op->dev, NULL); + } + return 0; +} + +static struct of_device_id niu_match[] = { + { + .name = "network", + .compatible = "SUNW,niusl", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, niu_match); + +static struct of_platform_driver niu_of_driver = { + .name = "niu", + .match_table = niu_match, + .probe = niu_of_probe, + .remove = __devexit_p(niu_of_remove), +}; + +#endif /* CONFIG_SPARC64 */ + +static int __init niu_init(void) +{ + int err = 0; + + BUILD_BUG_ON((PAGE_SIZE < 4 * 1024) || + ((PAGE_SIZE > 32 * 1024) && + ((PAGE_SIZE % (32 * 1024)) != 0 && + (PAGE_SIZE % (16 * 1024)) != 0 && + (PAGE_SIZE % (8 * 1024)) != 0 && + (PAGE_SIZE % (4 * 1024)) != 0))); + + niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT); + +#ifdef CONFIG_SPARC64 + err = of_register_driver(&niu_of_driver, &of_bus_type); +#endif + + if (!err) { + err = pci_register_driver(&niu_pci_driver); +#ifdef CONFIG_SPARC64 + if (err) + of_unregister_driver(&niu_of_driver); +#endif + } + + return err; +} + +static void __exit niu_exit(void) +{ + pci_unregister_driver(&niu_pci_driver); +#ifdef CONFIG_SPARC64 + of_unregister_driver(&niu_of_driver); +#endif +} + +module_init(niu_init); +module_exit(niu_exit); diff --git a/drivers/net/niu.h b/drivers/net/niu.h new file mode 100644 index 000000000000..10e3f111b6d5 --- /dev/null +++ b/drivers/net/niu.h @@ -0,0 +1,3222 @@ +/* niu.h: Definitions for Neptune ethernet driver. + * + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + */ + +#ifndef _NIU_H +#define _NIU_H + +#define PIO 0x000000UL +#define FZC_PIO 0x080000UL +#define FZC_MAC 0x180000UL +#define FZC_IPP 0x280000UL +#define FFLP 0x300000UL +#define FZC_FFLP 0x380000UL +#define PIO_VADDR 0x400000UL +#define ZCP 0x500000UL +#define FZC_ZCP 0x580000UL +#define DMC 0x600000UL +#define FZC_DMC 0x680000UL +#define TXC 0x700000UL +#define FZC_TXC 0x780000UL +#define PIO_LDSV 0x800000UL +#define PIO_PIO_LDGIM 0x900000UL +#define PIO_IMASK0 0xa00000UL +#define PIO_IMASK1 0xb00000UL +#define FZC_PROM 0xc80000UL +#define FZC_PIM 0xd80000UL + +#define LDSV0(LDG) (PIO_LDSV + 0x00000UL + (LDG) * 0x2000UL) +#define LDSV1(LDG) (PIO_LDSV + 0x00008UL + (LDG) * 0x2000UL) +#define LDSV2(LDG) (PIO_LDSV + 0x00010UL + (LDG) * 0x2000UL) + +#define LDG_IMGMT(LDG) (PIO_LDSV + 0x00018UL + (LDG) * 0x2000UL) +#define LDG_IMGMT_ARM 0x0000000080000000ULL +#define LDG_IMGMT_TIMER 0x000000000000003fULL + +#define LD_IM0(IDX) (PIO_IMASK0 + 0x00000UL + (IDX) * 0x2000UL) +#define LD_IM0_MASK 0x0000000000000003ULL + +#define LD_IM1(IDX) (PIO_IMASK1 + 0x00000UL + (IDX) * 0x2000UL) +#define LD_IM1_MASK 0x0000000000000003ULL + +#define LDG_TIMER_RES (FZC_PIO + 0x00008UL) +#define LDG_TIMER_RES_VAL 0x00000000000fffffULL + +#define DIRTY_TID_CTL (FZC_PIO + 0x00010UL) +#define DIRTY_TID_CTL_NPTHRED 0x00000000003f0000ULL +#define DIRTY_TID_CTL_RDTHRED 0x00000000000003f0ULL +#define DIRTY_TID_CTL_DTIDCLR 0x0000000000000002ULL +#define DIRTY_TID_CTL_DTIDENAB 0x0000000000000001ULL + +#define DIRTY_TID_STAT (FZC_PIO + 0x00018UL) +#define DIRTY_TID_STAT_NPWSTAT 0x0000000000003f00ULL +#define DIRTY_TID_STAT_RDSTAT 0x000000000000003fULL + +#define RST_CTL (FZC_PIO + 0x00038UL) +#define RST_CTL_MAC_RST3 0x0000000000400000ULL +#define RST_CTL_MAC_RST2 0x0000000000200000ULL +#define RST_CTL_MAC_RST1 0x0000000000100000ULL +#define RST_CTL_MAC_RST0 0x0000000000080000ULL +#define RST_CTL_ACK_TO_EN 0x0000000000000800ULL +#define RST_CTL_ACK_TO_VAL 0x00000000000007feULL + +#define SMX_CFIG_DAT (FZC_PIO + 0x00040UL) +#define SMX_CFIG_DAT_RAS_DET 0x0000000080000000ULL +#define SMX_CFIG_DAT_RAS_INJ 0x0000000040000000ULL +#define SMX_CFIG_DAT_XACT_TO 0x000000000fffffffULL + +#define SMX_INT_STAT (FZC_PIO + 0x00048UL) +#define SMX_INT_STAT_STAT 0x00000000ffffffffULL + +#define SMX_CTL (FZC_PIO + 0x00050UL) +#define SMX_CTL_CTL 0x00000000ffffffffULL + +#define SMX_DBG_VEC (FZC_PIO + 0x00058UL) +#define SMX_DBG_VEC_VEC 0x00000000ffffffffULL + +#define PIO_DBG_SEL (FZC_PIO + 0x00060UL) +#define PIO_DBG_SEL_SEL 0x000000000000003fULL + +#define PIO_TRAIN_VEC (FZC_PIO + 0x00068UL) +#define PIO_TRAIN_VEC_VEC 0x00000000ffffffffULL + +#define PIO_ARB_CTL (FZC_PIO + 0x00070UL) +#define PIO_ARB_CTL_CTL 0x00000000ffffffffULL + +#define PIO_ARB_DBG_VEC (FZC_PIO + 0x00078UL) +#define PIO_ARB_DBG_VEC_VEC 0x00000000ffffffffULL + +#define SYS_ERR_MASK (FZC_PIO + 0x00090UL) +#define SYS_ERR_MASK_META2 0x0000000000000400ULL +#define SYS_ERR_MASK_META1 0x0000000000000200ULL +#define SYS_ERR_MASK_PEU 0x0000000000000100ULL +#define SYS_ERR_MASK_TXC 0x0000000000000080ULL +#define SYS_ERR_MASK_RDMC 0x0000000000000040ULL +#define SYS_ERR_MASK_TDMC 0x0000000000000020ULL +#define SYS_ERR_MASK_ZCP 0x0000000000000010ULL +#define SYS_ERR_MASK_FFLP 0x0000000000000008ULL +#define SYS_ERR_MASK_IPP 0x0000000000000004ULL +#define SYS_ERR_MASK_MAC 0x0000000000000002ULL +#define SYS_ERR_MASK_SMX 0x0000000000000001ULL + +#define SYS_ERR_STAT (FZC_PIO + 0x00098UL) +#define SYS_ERR_STAT_META2 0x0000000000000400ULL +#define SYS_ERR_STAT_META1 0x0000000000000200ULL +#define SYS_ERR_STAT_PEU 0x0000000000000100ULL +#define SYS_ERR_STAT_TXC 0x0000000000000080ULL +#define SYS_ERR_STAT_RDMC 0x0000000000000040ULL +#define SYS_ERR_STAT_TDMC 0x0000000000000020ULL +#define SYS_ERR_STAT_ZCP 0x0000000000000010ULL +#define SYS_ERR_STAT_FFLP 0x0000000000000008ULL +#define SYS_ERR_STAT_IPP 0x0000000000000004ULL +#define SYS_ERR_STAT_MAC 0x0000000000000002ULL +#define SYS_ERR_STAT_SMX 0x0000000000000001ULL + +#define SID(LDG) (FZC_PIO + 0x10200UL + (LDG) * 8UL) +#define SID_FUNC 0x0000000000000060ULL +#define SID_FUNC_SHIFT 5 +#define SID_VECTOR 0x000000000000001fULL +#define SID_VECTOR_SHIFT 0 + +#define LDG_NUM(LDN) (FZC_PIO + 0x20000UL + (LDN) * 8UL) + +#define XMAC_PORT0_OFF (FZC_MAC + 0x000000) +#define XMAC_PORT1_OFF (FZC_MAC + 0x006000) +#define BMAC_PORT2_OFF (FZC_MAC + 0x00c000) +#define BMAC_PORT3_OFF (FZC_MAC + 0x010000) + +/* XMAC registers, offset from np->mac_regs */ + +#define XTXMAC_SW_RST 0x00000UL +#define XTXMAC_SW_RST_REG_RS 0x0000000000000002ULL +#define XTXMAC_SW_RST_SOFT_RST 0x0000000000000001ULL + +#define XRXMAC_SW_RST 0x00008UL +#define XRXMAC_SW_RST_REG_RS 0x0000000000000002ULL +#define XRXMAC_SW_RST_SOFT_RST 0x0000000000000001ULL + +#define XTXMAC_STATUS 0x00020UL +#define XTXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000800ULL +#define XTXMAC_STATUS_BYTE_CNT_EXP 0x0000000000000400ULL +#define XTXMAC_STATUS_TXFIFO_XFR_ERR 0x0000000000000010ULL +#define XTXMAC_STATUS_TXMAC_OFLOW 0x0000000000000008ULL +#define XTXMAC_STATUS_MAX_PSIZE_ERR 0x0000000000000004ULL +#define XTXMAC_STATUS_TXMAC_UFLOW 0x0000000000000002ULL +#define XTXMAC_STATUS_FRAME_XMITED 0x0000000000000001ULL + +#define XRXMAC_STATUS 0x00028UL +#define XRXMAC_STATUS_RXHIST7_CNT_EXP 0x0000000000100000ULL +#define XRXMAC_STATUS_LCL_FLT_STATUS 0x0000000000080000ULL +#define XRXMAC_STATUS_RFLT_DET 0x0000000000040000ULL +#define XRXMAC_STATUS_LFLT_CNT_EXP 0x0000000000020000ULL +#define XRXMAC_STATUS_PHY_MDINT 0x0000000000010000ULL +#define XRXMAC_STATUS_ALIGNERR_CNT_EXP 0x0000000000010000ULL +#define XRXMAC_STATUS_RXFRAG_CNT_EXP 0x0000000000008000ULL +#define XRXMAC_STATUS_RXMULTF_CNT_EXP 0x0000000000004000ULL +#define XRXMAC_STATUS_RXBCAST_CNT_EXP 0x0000000000002000ULL +#define XRXMAC_STATUS_RXHIST6_CNT_EXP 0x0000000000001000ULL +#define XRXMAC_STATUS_RXHIST5_CNT_EXP 0x0000000000000800ULL +#define XRXMAC_STATUS_RXHIST4_CNT_EXP 0x0000000000000400ULL +#define XRXMAC_STATUS_RXHIST3_CNT_EXP 0x0000000000000200ULL +#define XRXMAC_STATUS_RXHIST2_CNT_EXP 0x0000000000000100ULL +#define XRXMAC_STATUS_RXHIST1_CNT_EXP 0x0000000000000080ULL +#define XRXMAC_STATUS_RXOCTET_CNT_EXP 0x0000000000000040ULL +#define XRXMAC_STATUS_CVIOLERR_CNT_EXP 0x0000000000000020ULL +#define XRXMAC_STATUS_LENERR_CNT_EXP 0x0000000000000010ULL +#define XRXMAC_STATUS_CRCERR_CNT_EXP 0x0000000000000008ULL +#define XRXMAC_STATUS_RXUFLOW 0x0000000000000004ULL +#define XRXMAC_STATUS_RXOFLOW 0x0000000000000002ULL +#define XRXMAC_STATUS_FRAME_RCVD 0x0000000000000001ULL + +#define XMAC_FC_STAT 0x00030UL +#define XMAC_FC_STAT_RX_RCV_PAUSE_TIME 0x00000000ffff0000ULL +#define XMAC_FC_STAT_TX_MAC_NPAUSE 0x0000000000000004ULL +#define XMAC_FC_STAT_TX_MAC_PAUSE 0x0000000000000002ULL +#define XMAC_FC_STAT_RX_MAC_RPAUSE 0x0000000000000001ULL + +#define XTXMAC_STAT_MSK 0x00040UL +#define XTXMAC_STAT_MSK_FRAME_CNT_EXP 0x0000000000000800ULL +#define XTXMAC_STAT_MSK_BYTE_CNT_EXP 0x0000000000000400ULL +#define XTXMAC_STAT_MSK_TXFIFO_XFR_ERR 0x0000000000000010ULL +#define XTXMAC_STAT_MSK_TXMAC_OFLOW 0x0000000000000008ULL +#define XTXMAC_STAT_MSK_MAX_PSIZE_ERR 0x0000000000000004ULL +#define XTXMAC_STAT_MSK_TXMAC_UFLOW 0x0000000000000002ULL +#define XTXMAC_STAT_MSK_FRAME_XMITED 0x0000000000000001ULL + +#define XRXMAC_STAT_MSK 0x00048UL +#define XRXMAC_STAT_MSK_LCL_FLT_STAT_MSK 0x0000000000080000ULL +#define XRXMAC_STAT_MSK_RFLT_DET 0x0000000000040000ULL +#define XRXMAC_STAT_MSK_LFLT_CNT_EXP 0x0000000000020000ULL +#define XRXMAC_STAT_MSK_PHY_MDINT 0x0000000000010000ULL +#define XRXMAC_STAT_MSK_RXFRAG_CNT_EXP 0x0000000000008000ULL +#define XRXMAC_STAT_MSK_RXMULTF_CNT_EXP 0x0000000000004000ULL +#define XRXMAC_STAT_MSK_RXBCAST_CNT_EXP 0x0000000000002000ULL +#define XRXMAC_STAT_MSK_RXHIST6_CNT_EXP 0x0000000000001000ULL +#define XRXMAC_STAT_MSK_RXHIST5_CNT_EXP 0x0000000000000800ULL +#define XRXMAC_STAT_MSK_RXHIST4_CNT_EXP 0x0000000000000400ULL +#define XRXMAC_STAT_MSK_RXHIST3_CNT_EXP 0x0000000000000200ULL +#define XRXMAC_STAT_MSK_RXHIST2_CNT_EXP 0x0000000000000100ULL +#define XRXMAC_STAT_MSK_RXHIST1_CNT_EXP 0x0000000000000080ULL +#define XRXMAC_STAT_MSK_RXOCTET_CNT_EXP 0x0000000000000040ULL +#define XRXMAC_STAT_MSK_CVIOLERR_CNT_EXP 0x0000000000000020ULL +#define XRXMAC_STAT_MSK_LENERR_CNT_EXP 0x0000000000000010ULL +#define XRXMAC_STAT_MSK_CRCERR_CNT_EXP 0x0000000000000008ULL +#define XRXMAC_STAT_MSK_RXUFLOW_CNT_EXP 0x0000000000000004ULL +#define XRXMAC_STAT_MSK_RXOFLOW_CNT_EXP 0x0000000000000002ULL +#define XRXMAC_STAT_MSK_FRAME_RCVD 0x0000000000000001ULL + +#define XMAC_FC_MSK 0x00050UL +#define XMAC_FC_MSK_TX_MAC_NPAUSE 0x0000000000000004ULL +#define XMAC_FC_MSK_TX_MAC_PAUSE 0x0000000000000002ULL +#define XMAC_FC_MSK_RX_MAC_RPAUSE 0x0000000000000001ULL + +#define XMAC_CONFIG 0x00060UL +#define XMAC_CONFIG_SEL_CLK_25MHZ 0x0000000080000000ULL +#define XMAC_CONFIG_1G_PCS_BYPASS 0x0000000040000000ULL +#define XMAC_CONFIG_10G_XPCS_BYPASS 0x0000000020000000ULL +#define XMAC_CONFIG_MODE_MASK 0x0000000018000000ULL +#define XMAC_CONFIG_MODE_XGMII 0x0000000000000000ULL +#define XMAC_CONFIG_MODE_GMII 0x0000000008000000ULL +#define XMAC_CONFIG_MODE_MII 0x0000000010000000ULL +#define XMAC_CONFIG_LFS_DISABLE 0x0000000004000000ULL +#define XMAC_CONFIG_LOOPBACK 0x0000000002000000ULL +#define XMAC_CONFIG_TX_OUTPUT_EN 0x0000000001000000ULL +#define XMAC_CONFIG_SEL_POR_CLK_SRC 0x0000000000800000ULL +#define XMAC_CONFIG_LED_POLARITY 0x0000000000400000ULL +#define XMAC_CONFIG_FORCE_LED_ON 0x0000000000200000ULL +#define XMAC_CONFIG_PASS_FLOW_CTRL 0x0000000000100000ULL +#define XMAC_CONFIG_RCV_PAUSE_ENABLE 0x0000000000080000ULL +#define XMAC_CONFIG_MAC2IPP_PKT_CNT_EN 0x0000000000040000ULL +#define XMAC_CONFIG_STRIP_CRC 0x0000000000020000ULL +#define XMAC_CONFIG_ADDR_FILTER_EN 0x0000000000010000ULL +#define XMAC_CONFIG_HASH_FILTER_EN 0x0000000000008000ULL +#define XMAC_CONFIG_RX_CODEV_CHK_DIS 0x0000000000004000ULL +#define XMAC_CONFIG_RESERVED_MULTICAST 0x0000000000002000ULL +#define XMAC_CONFIG_RX_CRC_CHK_DIS 0x0000000000001000ULL +#define XMAC_CONFIG_ERR_CHK_DIS 0x0000000000000800ULL +#define XMAC_CONFIG_PROMISC_GROUP 0x0000000000000400ULL +#define XMAC_CONFIG_PROMISCUOUS 0x0000000000000200ULL +#define XMAC_CONFIG_RX_MAC_ENABLE 0x0000000000000100ULL +#define XMAC_CONFIG_WARNING_MSG_EN 0x0000000000000080ULL +#define XMAC_CONFIG_ALWAYS_NO_CRC 0x0000000000000008ULL +#define XMAC_CONFIG_VAR_MIN_IPG_EN 0x0000000000000004ULL +#define XMAC_CONFIG_STRETCH_MODE 0x0000000000000002ULL +#define XMAC_CONFIG_TX_ENABLE 0x0000000000000001ULL + +#define XMAC_IPG 0x00080UL +#define XMAC_IPG_STRETCH_CONST 0x0000000000e00000ULL +#define XMAC_IPG_STRETCH_CONST_SHIFT 21 +#define XMAC_IPG_STRETCH_RATIO 0x00000000001f0000ULL +#define XMAC_IPG_STRETCH_RATIO_SHIFT 16 +#define XMAC_IPG_IPG_MII_GMII 0x000000000000ff00ULL +#define XMAC_IPG_IPG_MII_GMII_SHIFT 8 +#define XMAC_IPG_IPG_XGMII 0x0000000000000007ULL +#define XMAC_IPG_IPG_XGMII_SHIFT 0 + +#define IPG_12_15_XGMII 3 +#define IPG_16_19_XGMII 4 +#define IPG_20_23_XGMII 5 +#define IPG_12_MII_GMII 10 +#define IPG_13_MII_GMII 11 +#define IPG_14_MII_GMII 12 +#define IPG_15_MII_GMII 13 +#define IPG_16_MII_GMII 14 + +#define XMAC_MIN 0x00088UL +#define XMAC_MIN_RX_MIN_PKT_SIZE 0x000000003ff00000ULL +#define XMAC_MIN_RX_MIN_PKT_SIZE_SHFT 20 +#define XMAC_MIN_SLOT_TIME 0x000000000003fc00ULL +#define XMAC_MIN_SLOT_TIME_SHFT 10 +#define XMAC_MIN_TX_MIN_PKT_SIZE 0x00000000000003ffULL +#define XMAC_MIN_TX_MIN_PKT_SIZE_SHFT 0 + +#define XMAC_MAX 0x00090UL +#define XMAC_MAX_FRAME_SIZE 0x0000000000003fffULL +#define XMAC_MAX_FRAME_SIZE_SHFT 0 + +#define XMAC_ADDR0 0x000a0UL +#define XMAC_ADDR0_ADDR0 0x000000000000ffffULL + +#define XMAC_ADDR1 0x000a8UL +#define XMAC_ADDR1_ADDR1 0x000000000000ffffULL + +#define XMAC_ADDR2 0x000b0UL +#define XMAC_ADDR2_ADDR2 0x000000000000ffffULL + +#define XMAC_ADDR_CMPEN 0x00208UL +#define XMAC_ADDR_CMPEN_EN15 0x0000000000008000ULL +#define XMAC_ADDR_CMPEN_EN14 0x0000000000004000ULL +#define XMAC_ADDR_CMPEN_EN13 0x0000000000002000ULL +#define XMAC_ADDR_CMPEN_EN12 0x0000000000001000ULL +#define XMAC_ADDR_CMPEN_EN11 0x0000000000000800ULL +#define XMAC_ADDR_CMPEN_EN10 0x0000000000000400ULL +#define XMAC_ADDR_CMPEN_EN9 0x0000000000000200ULL +#define XMAC_ADDR_CMPEN_EN8 0x0000000000000100ULL +#define XMAC_ADDR_CMPEN_EN7 0x0000000000000080ULL +#define XMAC_ADDR_CMPEN_EN6 0x0000000000000040ULL +#define XMAC_ADDR_CMPEN_EN5 0x0000000000000020ULL +#define XMAC_ADDR_CMPEN_EN4 0x0000000000000010ULL +#define XMAC_ADDR_CMPEN_EN3 0x0000000000000008ULL +#define XMAC_ADDR_CMPEN_EN2 0x0000000000000004ULL +#define XMAC_ADDR_CMPEN_EN1 0x0000000000000002ULL +#define XMAC_ADDR_CMPEN_EN0 0x0000000000000001ULL + +#define XMAC_NUM_ALT_ADDR 16 + +#define XMAC_ALT_ADDR0(NUM) (0x00218UL + (NUM)*0x18UL) +#define XMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL + +#define XMAC_ALT_ADDR1(NUM) (0x00220UL + (NUM)*0x18UL) +#define XMAC_ALT_ADDR1_ADDR1 0x000000000000ffffULL + +#define XMAC_ALT_ADDR2(NUM) (0x00228UL + (NUM)*0x18UL) +#define XMAC_ALT_ADDR2_ADDR2 0x000000000000ffffULL + +#define XMAC_ADD_FILT0 0x00818UL +#define XMAC_ADD_FILT0_FILT0 0x000000000000ffffULL + +#define XMAC_ADD_FILT1 0x00820UL +#define XMAC_ADD_FILT1_FILT1 0x000000000000ffffULL + +#define XMAC_ADD_FILT2 0x00828UL +#define XMAC_ADD_FILT2_FILT2 0x000000000000ffffULL + +#define XMAC_ADD_FILT12_MASK 0x00830UL +#define XMAC_ADD_FILT12_MASK_VAL 0x00000000000000ffULL + +#define XMAC_ADD_FILT00_MASK 0x00838UL +#define XMAC_ADD_FILT00_MASK_VAL 0x000000000000ffffULL + +#define XMAC_HASH_TBL(NUM) (0x00840UL + (NUM) * 0x8UL) +#define XMAC_HASH_TBL_VAL 0x000000000000ffffULL + +#define XMAC_NUM_HOST_INFO 20 + +#define XMAC_HOST_INFO(NUM) (0x00900UL + (NUM) * 0x8UL) + +#define XMAC_PA_DATA0 0x00b80UL +#define XMAC_PA_DATA0_VAL 0x00000000ffffffffULL + +#define XMAC_PA_DATA1 0x00b88UL +#define XMAC_PA_DATA1_VAL 0x00000000ffffffffULL + +#define XMAC_DEBUG_SEL 0x00b90UL +#define XMAC_DEBUG_SEL_XMAC 0x0000000000000078ULL +#define XMAC_DEBUG_SEL_MAC 0x0000000000000007ULL + +#define XMAC_TRAIN_VEC 0x00b98UL +#define XMAC_TRAIN_VEC_VAL 0x00000000ffffffffULL + +#define RXMAC_BT_CNT 0x00100UL +#define RXMAC_BT_CNT_COUNT 0x00000000ffffffffULL + +#define RXMAC_BC_FRM_CNT 0x00108UL +#define RXMAC_BC_FRM_CNT_COUNT 0x00000000001fffffULL + +#define RXMAC_MC_FRM_CNT 0x00110UL +#define RXMAC_MC_FRM_CNT_COUNT 0x00000000001fffffULL + +#define RXMAC_FRAG_CNT 0x00118UL +#define RXMAC_FRAG_CNT_COUNT 0x00000000001fffffULL + +#define RXMAC_HIST_CNT1 0x00120UL +#define RXMAC_HIST_CNT1_COUNT 0x00000000001fffffULL + +#define RXMAC_HIST_CNT2 0x00128UL +#define RXMAC_HIST_CNT2_COUNT 0x00000000001fffffULL + +#define RXMAC_HIST_CNT3 0x00130UL +#define RXMAC_HIST_CNT3_COUNT 0x00000000000fffffULL + +#define RXMAC_HIST_CNT4 0x00138UL +#define RXMAC_HIST_CNT4_COUNT 0x000000000007ffffULL + +#define RXMAC_HIST_CNT5 0x00140UL +#define RXMAC_HIST_CNT5_COUNT 0x000000000003ffffULL + +#define RXMAC_HIST_CNT6 0x00148UL +#define RXMAC_HIST_CNT6_COUNT 0x000000000000ffffULL + +#define RXMAC_MPSZER_CNT 0x00150UL +#define RXMAC_MPSZER_CNT_COUNT 0x00000000000000ffULL + +#define RXMAC_CRC_ER_CNT 0x00158UL +#define RXMAC_CRC_ER_CNT_COUNT 0x00000000000000ffULL + +#define RXMAC_CD_VIO_CNT 0x00160UL +#define RXMAC_CD_VIO_CNT_COUNT 0x00000000000000ffULL + +#define RXMAC_ALIGN_ERR_CNT 0x00168UL +#define RXMAC_ALIGN_ERR_CNT_COUNT 0x00000000000000ffULL + +#define TXMAC_FRM_CNT 0x00170UL +#define TXMAC_FRM_CNT_COUNT 0x00000000ffffffffULL + +#define TXMAC_BYTE_CNT 0x00178UL +#define TXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL + +#define LINK_FAULT_CNT 0x00180UL +#define LINK_FAULT_CNT_COUNT 0x00000000000000ffULL + +#define RXMAC_HIST_CNT7 0x00188UL +#define RXMAC_HIST_CNT7_COUNT 0x0000000007ffffffULL + +#define XMAC_SM_REG 0x001a8UL +#define XMAC_SM_REG_STATE 0x00000000ffffffffULL + +#define XMAC_INTER1 0x001b0UL +#define XMAC_INTERN1_SIGNALS1 0x00000000ffffffffULL + +#define XMAC_INTER2 0x001b8UL +#define XMAC_INTERN2_SIGNALS2 0x00000000ffffffffULL + +/* BMAC registers, offset from np->mac_regs */ + +#define BTXMAC_SW_RST 0x00000UL +#define BTXMAC_SW_RST_RESET 0x0000000000000001ULL + +#define BRXMAC_SW_RST 0x00008UL +#define BRXMAC_SW_RST_RESET 0x0000000000000001ULL + +#define BMAC_SEND_PAUSE 0x00010UL +#define BMAC_SEND_PAUSE_SEND 0x0000000000010000ULL +#define BMAC_SEND_PAUSE_TIME 0x000000000000ffffULL + +#define BTXMAC_STATUS 0x00020UL +#define BTXMAC_STATUS_XMIT 0x0000000000000001ULL +#define BTXMAC_STATUS_UNDERRUN 0x0000000000000002ULL +#define BTXMAC_STATUS_MAX_PKT_ERR 0x0000000000000004ULL +#define BTXMAC_STATUS_BYTE_CNT_EXP 0x0000000000000400ULL +#define BTXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000800ULL + +#define BRXMAC_STATUS 0x00028UL +#define BRXMAC_STATUS_RX_PKT 0x0000000000000001ULL +#define BRXMAC_STATUS_OVERFLOW 0x0000000000000002ULL +#define BRXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000004ULL +#define BRXMAC_STATUS_ALIGN_ERR_EXP 0x0000000000000008ULL +#define BRXMAC_STATUS_CRC_ERR_EXP 0x0000000000000010ULL +#define BRXMAC_STATUS_LEN_ERR_EXP 0x0000000000000020ULL + +#define BMAC_CTRL_STATUS 0x00030UL +#define BMAC_CTRL_STATUS_PAUSE_RECV 0x0000000000000001ULL +#define BMAC_CTRL_STATUS_PAUSE 0x0000000000000002ULL +#define BMAC_CTRL_STATUS_NOPAUSE 0x0000000000000004ULL +#define BMAC_CTRL_STATUS_TIME 0x00000000ffff0000ULL +#define BMAC_CTRL_STATUS_TIME_SHIFT 16 + +#define BTXMAC_STATUS_MASK 0x00040UL +#define BRXMAC_STATUS_MASK 0x00048UL +#define BMAC_CTRL_STATUS_MASK 0x00050UL + +#define BTXMAC_CONFIG 0x00060UL +#define BTXMAC_CONFIG_ENABLE 0x0000000000000001ULL +#define BTXMAC_CONFIG_FCS_DISABLE 0x0000000000000002ULL + +#define BRXMAC_CONFIG 0x00068UL +#define BRXMAC_CONFIG_DISCARD_DIS 0x0000000000000080ULL +#define BRXMAC_CONFIG_ADDR_FILT_EN 0x0000000000000040ULL +#define BRXMAC_CONFIG_HASH_FILT_EN 0x0000000000000020ULL +#define BRXMAC_CONFIG_PROMISC_GRP 0x0000000000000010ULL +#define BRXMAC_CONFIG_PROMISC 0x0000000000000008ULL +#define BRXMAC_CONFIG_STRIP_FCS 0x0000000000000004ULL +#define BRXMAC_CONFIG_STRIP_PAD 0x0000000000000002ULL +#define BRXMAC_CONFIG_ENABLE 0x0000000000000001ULL + +#define BMAC_CTRL_CONFIG 0x00070UL +#define BMAC_CTRL_CONFIG_TX_PAUSE_EN 0x0000000000000001ULL +#define BMAC_CTRL_CONFIG_RX_PAUSE_EN 0x0000000000000002ULL +#define BMAC_CTRL_CONFIG_PASS_CTRL 0x0000000000000004ULL + +#define BMAC_XIF_CONFIG 0x00078UL +#define BMAC_XIF_CONFIG_TX_OUTPUT_EN 0x0000000000000001ULL +#define BMAC_XIF_CONFIG_MII_LOOPBACK 0x0000000000000002ULL +#define BMAC_XIF_CONFIG_GMII_MODE 0x0000000000000008ULL +#define BMAC_XIF_CONFIG_LINK_LED 0x0000000000000020ULL +#define BMAC_XIF_CONFIG_LED_POLARITY 0x0000000000000040ULL +#define BMAC_XIF_CONFIG_25MHZ_CLOCK 0x0000000000000080ULL + +#define BMAC_MIN_FRAME 0x000a0UL +#define BMAC_MIN_FRAME_VAL 0x00000000000003ffULL + +#define BMAC_MAX_FRAME 0x000a8UL +#define BMAC_MAX_FRAME_MAX_BURST 0x000000003fff0000ULL +#define BMAC_MAX_FRAME_MAX_BURST_SHIFT 16 +#define BMAC_MAX_FRAME_MAX_FRAME 0x0000000000003fffULL +#define BMAC_MAX_FRAME_MAX_FRAME_SHIFT 0 + +#define BMAC_PREAMBLE_SIZE 0x000b0UL +#define BMAC_PREAMBLE_SIZE_VAL 0x00000000000003ffULL + +#define BMAC_CTRL_TYPE 0x000c8UL + +#define BMAC_ADDR0 0x00100UL +#define BMAC_ADDR0_ADDR0 0x000000000000ffffULL + +#define BMAC_ADDR1 0x00108UL +#define BMAC_ADDR1_ADDR1 0x000000000000ffffULL + +#define BMAC_ADDR2 0x00110UL +#define BMAC_ADDR2_ADDR2 0x000000000000ffffULL + +#define BMAC_NUM_ALT_ADDR 7 + +#define BMAC_ALT_ADDR0(NUM) (0x00118UL + (NUM)*0x18UL) +#define BMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL + +#define BMAC_ALT_ADDR1(NUM) (0x00120UL + (NUM)*0x18UL) +#define BMAC_ALT_ADDR1_ADDR1 0x000000000000ffffULL + +#define BMAC_ALT_ADDR2(NUM) (0x00128UL + (NUM)*0x18UL) +#define BMAC_ALT_ADDR2_ADDR2 0x000000000000ffffULL + +#define BMAC_FC_ADDR0 0x00268UL +#define BMAC_FC_ADDR0_ADDR0 0x000000000000ffffULL + +#define BMAC_FC_ADDR1 0x00270UL +#define BMAC_FC_ADDR1_ADDR1 0x000000000000ffffULL + +#define BMAC_FC_ADDR2 0x00278UL +#define BMAC_FC_ADDR2_ADDR2 0x000000000000ffffULL + +#define BMAC_ADD_FILT0 0x00298UL +#define BMAC_ADD_FILT0_FILT0 0x000000000000ffffULL + +#define BMAC_ADD_FILT1 0x002a0UL +#define BMAC_ADD_FILT1_FILT1 0x000000000000ffffULL + +#define BMAC_ADD_FILT2 0x002a8UL +#define BMAC_ADD_FILT2_FILT2 0x000000000000ffffULL + +#define BMAC_ADD_FILT12_MASK 0x002b0UL +#define BMAC_ADD_FILT12_MASK_VAL 0x00000000000000ffULL + +#define BMAC_ADD_FILT00_MASK 0x002b8UL +#define BMAC_ADD_FILT00_MASK_VAL 0x000000000000ffffULL + +#define BMAC_HASH_TBL(NUM) (0x002c0UL + (NUM) * 0x8UL) +#define BMAC_HASH_TBL_VAL 0x000000000000ffffULL + +#define BRXMAC_FRAME_CNT 0x00370 +#define BRXMAC_FRAME_CNT_COUNT 0x000000000000ffffULL + +#define BRXMAC_MAX_LEN_ERR_CNT 0x00378 + +#define BRXMAC_ALIGN_ERR_CNT 0x00380 +#define BRXMAC_ALIGN_ERR_CNT_COUNT 0x000000000000ffffULL + +#define BRXMAC_CRC_ERR_CNT 0x00388 +#define BRXMAC_ALIGN_ERR_CNT_COUNT 0x000000000000ffffULL + +#define BRXMAC_CODE_VIOL_ERR_CNT 0x00390 +#define BRXMAC_CODE_VIOL_ERR_CNT_COUNT 0x000000000000ffffULL + +#define BMAC_STATE_MACHINE 0x003a0 + +#define BMAC_ADDR_CMPEN 0x003f8UL +#define BMAC_ADDR_CMPEN_EN15 0x0000000000008000ULL +#define BMAC_ADDR_CMPEN_EN14 0x0000000000004000ULL +#define BMAC_ADDR_CMPEN_EN13 0x0000000000002000ULL +#define BMAC_ADDR_CMPEN_EN12 0x0000000000001000ULL +#define BMAC_ADDR_CMPEN_EN11 0x0000000000000800ULL +#define BMAC_ADDR_CMPEN_EN10 0x0000000000000400ULL +#define BMAC_ADDR_CMPEN_EN9 0x0000000000000200ULL +#define BMAC_ADDR_CMPEN_EN8 0x0000000000000100ULL +#define BMAC_ADDR_CMPEN_EN7 0x0000000000000080ULL +#define BMAC_ADDR_CMPEN_EN6 0x0000000000000040ULL +#define BMAC_ADDR_CMPEN_EN5 0x0000000000000020ULL +#define BMAC_ADDR_CMPEN_EN4 0x0000000000000010ULL +#define BMAC_ADDR_CMPEN_EN3 0x0000000000000008ULL +#define BMAC_ADDR_CMPEN_EN2 0x0000000000000004ULL +#define BMAC_ADDR_CMPEN_EN1 0x0000000000000002ULL +#define BMAC_ADDR_CMPEN_EN0 0x0000000000000001ULL + +#define BMAC_NUM_HOST_INFO 9 + +#define BMAC_HOST_INFO(NUM) (0x00400UL + (NUM) * 0x8UL) + +#define BTXMAC_BYTE_CNT 0x00448UL +#define BTXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL + +#define BTXMAC_FRM_CNT 0x00450UL +#define BTXMAC_FRM_CNT_COUNT 0x00000000ffffffffULL + +#define BRXMAC_BYTE_CNT 0x00458UL +#define BRXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL + +#define HOST_INFO_MPR 0x0000000000000100ULL +#define HOST_INFO_MACRDCTBLN 0x0000000000000007ULL + +/* XPCS registers, offset from np->regs + np->xpcs_off */ + +#define XPCS_CONTROL1 (FZC_MAC + 0x00000UL) +#define XPCS_CONTROL1_RESET 0x0000000000008000ULL +#define XPCS_CONTROL1_LOOPBACK 0x0000000000004000ULL +#define XPCS_CONTROL1_SPEED_SELECT3 0x0000000000002000ULL +#define XPCS_CONTROL1_CSR_LOW_PWR 0x0000000000000800ULL +#define XPCS_CONTROL1_CSR_SPEED1 0x0000000000000040ULL +#define XPCS_CONTROL1_CSR_SPEED0 0x000000000000003cULL + +#define XPCS_STATUS1 (FZC_MAC + 0x00008UL) +#define XPCS_STATUS1_CSR_FAULT 0x0000000000000080ULL +#define XPCS_STATUS1_CSR_RXLNK_STAT 0x0000000000000004ULL +#define XPCS_STATUS1_CSR_LPWR_ABLE 0x0000000000000002ULL + +#define XPCS_DEVICE_IDENTIFIER (FZC_MAC + 0x00010UL) +#define XPCS_DEVICE_IDENTIFIER_VAL 0x00000000ffffffffULL + +#define XPCS_SPEED_ABILITY (FZC_MAC + 0x00018UL) +#define XPCS_SPEED_ABILITY_10GIG 0x0000000000000001ULL + +#define XPCS_DEV_IN_PKG (FZC_MAC + 0x00020UL) +#define XPCS_DEV_IN_PKG_CSR_VEND2 0x0000000080000000ULL +#define XPCS_DEV_IN_PKG_CSR_VEND1 0x0000000040000000ULL +#define XPCS_DEV_IN_PKG_DTE_XS 0x0000000000000020ULL +#define XPCS_DEV_IN_PKG_PHY_XS 0x0000000000000010ULL +#define XPCS_DEV_IN_PKG_PCS 0x0000000000000008ULL +#define XPCS_DEV_IN_PKG_WIS 0x0000000000000004ULL +#define XPCS_DEV_IN_PKG_PMD_PMA 0x0000000000000002ULL +#define XPCS_DEV_IN_PKG_CLS22 0x0000000000000001ULL + +#define XPCS_CONTROL2 (FZC_MAC + 0x00028UL) +#define XPCS_CONTROL2_CSR_PSC_SEL 0x0000000000000003ULL + +#define XPCS_STATUS2 (FZC_MAC + 0x00030UL) +#define XPCS_STATUS2_CSR_DEV_PRES 0x000000000000c000ULL +#define XPCS_STATUS2_CSR_TX_FAULT 0x0000000000000800ULL +#define XPCS_STATUS2_CSR_RCV_FAULT 0x0000000000000400ULL +#define XPCS_STATUS2_TEN_GBASE_W 0x0000000000000004ULL +#define XPCS_STATUS2_TEN_GBASE_X 0x0000000000000002ULL +#define XPCS_STATUS2_TEN_GBASE_R 0x0000000000000001ULL + +#define XPCS_PKG_ID (FZC_MAC + 0x00038UL) +#define XPCS_PKG_ID_VAL 0x00000000ffffffffULL + +#define XPCS_STATUS(IDX) (FZC_MAC + 0x00040UL) +#define XPCS_STATUS_CSR_LANE_ALIGN 0x0000000000001000ULL +#define XPCS_STATUS_CSR_PATTEST_CAP 0x0000000000000800ULL +#define XPCS_STATUS_CSR_LANE3_SYNC 0x0000000000000008ULL +#define XPCS_STATUS_CSR_LANE2_SYNC 0x0000000000000004ULL +#define XPCS_STATUS_CSR_LANE1_SYNC 0x0000000000000002ULL +#define XPCS_STATUS_CSR_LANE0_SYNC 0x0000000000000001ULL + +#define XPCS_TEST_CONTROL (FZC_MAC + 0x00048UL) +#define XPCS_TEST_CONTROL_TXTST_EN 0x0000000000000004ULL +#define XPCS_TEST_CONTROL_TPAT_SEL 0x0000000000000003ULL + +#define XPCS_CFG_VENDOR1 (FZC_MAC + 0x00050UL) +#define XPCS_CFG_VENDOR1_DBG_IOTST 0x0000000000000080ULL +#define XPCS_CFG_VENDOR1_DBG_SEL 0x0000000000000078ULL +#define XPCS_CFG_VENDOR1_BYPASS_DET 0x0000000000000004ULL +#define XPCS_CFG_VENDOR1_TXBUF_EN 0x0000000000000002ULL +#define XPCS_CFG_VENDOR1_XPCS_EN 0x0000000000000001ULL + +#define XPCS_DIAG_VENDOR2 (FZC_MAC + 0x00058UL) +#define XPCS_DIAG_VENDOR2_SSM_LANE3 0x0000000001e00000ULL +#define XPCS_DIAG_VENDOR2_SSM_LANE2 0x00000000001e0000ULL +#define XPCS_DIAG_VENDOR2_SSM_LANE1 0x000000000001e000ULL +#define XPCS_DIAG_VENDOR2_SSM_LANE0 0x0000000000001e00ULL +#define XPCS_DIAG_VENDOR2_EBUF_SM 0x00000000000001feULL +#define XPCS_DIAG_VENDOR2_RCV_SM 0x0000000000000001ULL + +#define XPCS_MASK1 (FZC_MAC + 0x00060UL) +#define XPCS_MASK1_FAULT_MASK 0x0000000000000080ULL +#define XPCS_MASK1_RXALIGN_STAT_MSK 0x0000000000000004ULL + +#define XPCS_PKT_COUNT (FZC_MAC + 0x00068UL) +#define XPCS_PKT_COUNT_TX 0x00000000ffff0000ULL +#define XPCS_PKT_COUNT_RX 0x000000000000ffffULL + +#define XPCS_TX_SM (FZC_MAC + 0x00070UL) +#define XPCS_TX_SM_VAL 0x000000000000000fULL + +#define XPCS_DESKEW_ERR_CNT (FZC_MAC + 0x00078UL) +#define XPCS_DESKEW_ERR_CNT_VAL 0x00000000000000ffULL + +#define XPCS_SYMERR_CNT01 (FZC_MAC + 0x00080UL) +#define XPCS_SYMERR_CNT01_LANE1 0x00000000ffff0000ULL +#define XPCS_SYMERR_CNT01_LANE0 0x000000000000ffffULL + +#define XPCS_SYMERR_CNT23 (FZC_MAC + 0x00088UL) +#define XPCS_SYMERR_CNT23_LANE3 0x00000000ffff0000ULL +#define XPCS_SYMERR_CNT23_LANE2 0x000000000000ffffULL + +#define XPCS_TRAINING_VECTOR (FZC_MAC + 0x00090UL) +#define XPCS_TRAINING_VECTOR_VAL 0x00000000ffffffffULL + +/* PCS registers, offset from np->regs + np->pcs_off */ + +#define PCS_MII_CTL (FZC_MAC + 0x00000UL) +#define PCS_MII_CTL_RST 0x0000000000008000ULL +#define PCS_MII_CTL_10_100_SPEED 0x0000000000002000ULL +#define PCS_MII_AUTONEG_EN 0x0000000000001000ULL +#define PCS_MII_PWR_DOWN 0x0000000000000800ULL +#define PCS_MII_ISOLATE 0x0000000000000400ULL +#define PCS_MII_AUTONEG_RESTART 0x0000000000000200ULL +#define PCS_MII_DUPLEX 0x0000000000000100ULL +#define PCS_MII_COLL_TEST 0x0000000000000080ULL +#define PCS_MII_1000MB_SPEED 0x0000000000000040ULL + +#define PCS_MII_STAT (FZC_MAC + 0x00008UL) +#define PCS_MII_STAT_EXT_STATUS 0x0000000000000100ULL +#define PCS_MII_STAT_AUTONEG_DONE 0x0000000000000020ULL +#define PCS_MII_STAT_REMOTE_FAULT 0x0000000000000010ULL +#define PCS_MII_STAT_AUTONEG_ABLE 0x0000000000000008ULL +#define PCS_MII_STAT_LINK_STATUS 0x0000000000000004ULL +#define PCS_MII_STAT_JABBER_DET 0x0000000000000002ULL +#define PCS_MII_STAT_EXT_CAP 0x0000000000000001ULL + +#define PCS_MII_ADV (FZC_MAC + 0x00010UL) +#define PCS_MII_ADV_NEXT_PAGE 0x0000000000008000ULL +#define PCS_MII_ADV_ACK 0x0000000000004000ULL +#define PCS_MII_ADV_REMOTE_FAULT 0x0000000000003000ULL +#define PCS_MII_ADV_ASM_DIR 0x0000000000000100ULL +#define PCS_MII_ADV_PAUSE 0x0000000000000080ULL +#define PCS_MII_ADV_HALF_DUPLEX 0x0000000000000040ULL +#define PCS_MII_ADV_FULL_DUPLEX 0x0000000000000020ULL + +#define PCS_MII_PARTNER (FZC_MAC + 0x00018UL) +#define PCS_MII_PARTNER_NEXT_PAGE 0x0000000000008000ULL +#define PCS_MII_PARTNER_ACK 0x0000000000004000ULL +#define PCS_MII_PARTNER_REMOTE_FAULT 0x0000000000002000ULL +#define PCS_MII_PARTNER_PAUSE 0x0000000000000180ULL +#define PCS_MII_PARTNER_HALF_DUPLEX 0x0000000000000040ULL +#define PCS_MII_PARTNER_FULL_DUPLEX 0x0000000000000020ULL + +#define PCS_CONF (FZC_MAC + 0x00020UL) +#define PCS_CONF_MASK 0x0000000000000040ULL +#define PCS_CONF_10MS_TMR_OVERRIDE 0x0000000000000020ULL +#define PCS_CONF_JITTER_STUDY 0x0000000000000018ULL +#define PCS_CONF_SIGDET_ACTIVE_LOW 0x0000000000000004ULL +#define PCS_CONF_SIGDET_OVERRIDE 0x0000000000000002ULL +#define PCS_CONF_ENABLE 0x0000000000000001ULL + +#define PCS_STATE (FZC_MAC + 0x00028UL) +#define PCS_STATE_D_PARTNER_FAIL 0x0000000020000000ULL +#define PCS_STATE_D_WAIT_C_CODES_ACK 0x0000000010000000ULL +#define PCS_STATE_D_SYNC_LOSS 0x0000000008000000ULL +#define PCS_STATE_D_NO_GOOD_C_CODES 0x0000000004000000ULL +#define PCS_STATE_D_SERDES 0x0000000002000000ULL +#define PCS_STATE_D_BREAKLINK_C_CODES 0x0000000001000000ULL +#define PCS_STATE_L_SIGDET 0x0000000000400000ULL +#define PCS_STATE_L_SYNC_LOSS 0x0000000000200000ULL +#define PCS_STATE_L_C_CODES 0x0000000000100000ULL +#define PCS_STATE_LINK_CFG_STATE 0x000000000001e000ULL +#define PCS_STATE_SEQ_DET_STATE 0x0000000000001800ULL +#define PCS_STATE_WORD_SYNC_STATE 0x0000000000000700ULL +#define PCS_STATE_NO_IDLE 0x000000000000000fULL + +#define PCS_INTERRUPT (FZC_MAC + 0x00030UL) +#define PCS_INTERRUPT_LSTATUS 0x0000000000000004ULL + +#define PCS_DPATH_MODE (FZC_MAC + 0x000a0UL) +#define PCS_DPATH_MODE_PCS 0x0000000000000000ULL +#define PCS_DPATH_MODE_MII 0x0000000000000002ULL +#define PCS_DPATH_MODE_LINKUP_F_ENAB 0x0000000000000001ULL + +#define PCS_PKT_CNT (FZC_MAC + 0x000c0UL) +#define PCS_PKT_CNT_RX 0x0000000007ff0000ULL +#define PCS_PKT_CNT_TX 0x00000000000007ffULL + +#define MIF_BB_MDC (FZC_MAC + 0x16000UL) +#define MIF_BB_MDC_CLK 0x0000000000000001ULL + +#define MIF_BB_MDO (FZC_MAC + 0x16008UL) +#define MIF_BB_MDO_DAT 0x0000000000000001ULL + +#define MIF_BB_MDO_EN (FZC_MAC + 0x16010UL) +#define MIF_BB_MDO_EN_VAL 0x0000000000000001ULL + +#define MIF_FRAME_OUTPUT (FZC_MAC + 0x16018UL) +#define MIF_FRAME_OUTPUT_ST 0x00000000c0000000ULL +#define MIF_FRAME_OUTPUT_ST_SHIFT 30 +#define MIF_FRAME_OUTPUT_OP_ADDR 0x0000000000000000ULL +#define MIF_FRAME_OUTPUT_OP_WRITE 0x0000000010000000ULL +#define MIF_FRAME_OUTPUT_OP_READ_INC 0x0000000020000000ULL +#define MIF_FRAME_OUTPUT_OP_READ 0x0000000030000000ULL +#define MIF_FRAME_OUTPUT_OP_SHIFT 28 +#define MIF_FRAME_OUTPUT_PORT 0x000000000f800000ULL +#define MIF_FRAME_OUTPUT_PORT_SHIFT 23 +#define MIF_FRAME_OUTPUT_REG 0x00000000007c0000ULL +#define MIF_FRAME_OUTPUT_REG_SHIFT 18 +#define MIF_FRAME_OUTPUT_TA 0x0000000000030000ULL +#define MIF_FRAME_OUTPUT_TA_SHIFT 16 +#define MIF_FRAME_OUTPUT_DATA 0x000000000000ffffULL +#define MIF_FRAME_OUTPUT_DATA_SHIFT 0 + +#define MDIO_ADDR_OP(port, dev, reg) \ + ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + MIF_FRAME_OUTPUT_OP_ADDR | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \ + (reg << MIF_FRAME_OUTPUT_DATA_SHIFT)) + +#define MDIO_READ_OP(port, dev) \ + ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + MIF_FRAME_OUTPUT_OP_READ | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT)) + +#define MDIO_WRITE_OP(port, dev, data) \ + ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + MIF_FRAME_OUTPUT_OP_WRITE | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \ + (data << MIF_FRAME_OUTPUT_DATA_SHIFT)) + +#define MII_READ_OP(port, reg) \ + ((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + (2 << MIF_FRAME_OUTPUT_OP_SHIFT) | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT)) + +#define MII_WRITE_OP(port, reg, data) \ + ((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + (1 << MIF_FRAME_OUTPUT_OP_SHIFT) | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \ + (data << MIF_FRAME_OUTPUT_DATA_SHIFT)) + +#define MIF_CONFIG (FZC_MAC + 0x16020UL) +#define MIF_CONFIG_ATCA_GE 0x0000000000010000ULL +#define MIF_CONFIG_INDIRECT_MODE 0x0000000000008000ULL +#define MIF_CONFIG_POLL_PRT_PHYADDR 0x0000000000003c00ULL +#define MIF_CONFIG_POLL_DEV_REG_ADDR 0x00000000000003e0ULL +#define MIF_CONFIG_BB_MODE 0x0000000000000010ULL +#define MIF_CONFIG_POLL_EN 0x0000000000000008ULL +#define MIF_CONFIG_BB_SER_SEL 0x0000000000000006ULL +#define MIF_CONFIG_MANUAL_MODE 0x0000000000000001ULL + +#define MIF_POLL_STATUS (FZC_MAC + 0x16028UL) +#define MIF_POLL_STATUS_DATA 0x00000000ffff0000ULL +#define MIF_POLL_STATUS_STAT 0x000000000000ffffULL + +#define MIF_POLL_MASK (FZC_MAC + 0x16030UL) +#define MIF_POLL_MASK_VAL 0x000000000000ffffULL + +#define MIF_SM (FZC_MAC + 0x16038UL) +#define MIF_SM_PORT_ADDR 0x00000000001f0000ULL +#define MIF_SM_MDI_1 0x0000000000004000ULL +#define MIF_SM_MDI_0 0x0000000000002400ULL +#define MIF_SM_MDCLK 0x0000000000001000ULL +#define MIF_SM_MDO_EN 0x0000000000000800ULL +#define MIF_SM_MDO 0x0000000000000400ULL +#define MIF_SM_MDI 0x0000000000000200ULL +#define MIF_SM_CTL 0x00000000000001c0ULL +#define MIF_SM_EX 0x000000000000003fULL + +#define MIF_STATUS (FZC_MAC + 0x16040UL) +#define MIF_STATUS_MDINT1 0x0000000000000020ULL +#define MIF_STATUS_MDINT0 0x0000000000000010ULL + +#define MIF_MASK (FZC_MAC + 0x16048UL) +#define MIF_MASK_MDINT1 0x0000000000000020ULL +#define MIF_MASK_MDINT0 0x0000000000000010ULL +#define MIF_MASK_PEU_ERR 0x0000000000000008ULL +#define MIF_MASK_YC 0x0000000000000004ULL +#define MIF_MASK_XGE_ERR0 0x0000000000000002ULL +#define MIF_MASK_MIF_INIT_DONE 0x0000000000000001ULL + +#define ENET_SERDES_RESET (FZC_MAC + 0x14000UL) +#define ENET_SERDES_RESET_1 0x0000000000000002ULL +#define ENET_SERDES_RESET_0 0x0000000000000001ULL + +#define ENET_SERDES_CFG (FZC_MAC + 0x14008UL) +#define ENET_SERDES_BE_LOOPBACK 0x0000000000000002ULL +#define ENET_SERDES_CFG_FORCE_RDY 0x0000000000000001ULL + +#define ENET_SERDES_0_PLL_CFG (FZC_MAC + 0x14010UL) +#define ENET_SERDES_PLL_FBDIV0 0x0000000000000001ULL +#define ENET_SERDES_PLL_FBDIV1 0x0000000000000002ULL +#define ENET_SERDES_PLL_FBDIV2 0x0000000000000004ULL +#define ENET_SERDES_PLL_HRATE0 0x0000000000000008ULL +#define ENET_SERDES_PLL_HRATE1 0x0000000000000010ULL +#define ENET_SERDES_PLL_HRATE2 0x0000000000000020ULL +#define ENET_SERDES_PLL_HRATE3 0x0000000000000040ULL + +#define ENET_SERDES_0_CTRL_CFG (FZC_MAC + 0x14018UL) +#define ENET_SERDES_CTRL_SDET_0 0x0000000000000001ULL +#define ENET_SERDES_CTRL_SDET_1 0x0000000000000002ULL +#define ENET_SERDES_CTRL_SDET_2 0x0000000000000004ULL +#define ENET_SERDES_CTRL_SDET_3 0x0000000000000008ULL +#define ENET_SERDES_CTRL_EMPH_0 0x0000000000000070ULL +#define ENET_SERDES_CTRL_EMPH_0_SHIFT 4 +#define ENET_SERDES_CTRL_EMPH_1 0x0000000000000380ULL +#define ENET_SERDES_CTRL_EMPH_1_SHIFT 7 +#define ENET_SERDES_CTRL_EMPH_2 0x0000000000001c00ULL +#define ENET_SERDES_CTRL_EMPH_2_SHIFT 10 +#define ENET_SERDES_CTRL_EMPH_3 0x000000000000e000ULL +#define ENET_SERDES_CTRL_EMPH_3_SHIFT 13 +#define ENET_SERDES_CTRL_LADJ_0 0x0000000000070000ULL +#define ENET_SERDES_CTRL_LADJ_0_SHIFT 16 +#define ENET_SERDES_CTRL_LADJ_1 0x0000000000380000ULL +#define ENET_SERDES_CTRL_LADJ_1_SHIFT 19 +#define ENET_SERDES_CTRL_LADJ_2 0x0000000001c00000ULL +#define ENET_SERDES_CTRL_LADJ_2_SHIFT 22 +#define ENET_SERDES_CTRL_LADJ_3 0x000000000e000000ULL +#define ENET_SERDES_CTRL_LADJ_3_SHIFT 25 +#define ENET_SERDES_CTRL_RXITERM_0 0x0000000010000000ULL +#define ENET_SERDES_CTRL_RXITERM_1 0x0000000020000000ULL +#define ENET_SERDES_CTRL_RXITERM_2 0x0000000040000000ULL +#define ENET_SERDES_CTRL_RXITERM_3 0x0000000080000000ULL + +#define ENET_SERDES_0_TEST_CFG (FZC_MAC + 0x14020UL) +#define ENET_SERDES_TEST_MD_0 0x0000000000000003ULL +#define ENET_SERDES_TEST_MD_0_SHIFT 0 +#define ENET_SERDES_TEST_MD_1 0x000000000000000cULL +#define ENET_SERDES_TEST_MD_1_SHIFT 2 +#define ENET_SERDES_TEST_MD_2 0x0000000000000030ULL +#define ENET_SERDES_TEST_MD_2_SHIFT 4 +#define ENET_SERDES_TEST_MD_3 0x00000000000000c0ULL +#define ENET_SERDES_TEST_MD_3_SHIFT 6 + +#define ENET_TEST_MD_NO_LOOPBACK 0x0 +#define ENET_TEST_MD_EWRAP 0x1 +#define ENET_TEST_MD_PAD_LOOPBACK 0x2 +#define ENET_TEST_MD_REV_LOOPBACK 0x3 + +#define ENET_SERDES_1_PLL_CFG (FZC_MAC + 0x14028UL) +#define ENET_SERDES_1_CTRL_CFG (FZC_MAC + 0x14030UL) +#define ENET_SERDES_1_TEST_CFG (FZC_MAC + 0x14038UL) + +#define ENET_RGMII_CFG_REG (FZC_MAC + 0x14040UL) + +#define ESR_INT_SIGNALS (FZC_MAC + 0x14800UL) +#define ESR_INT_SIGNALS_ALL 0x00000000ffffffffULL +#define ESR_INT_SIGNALS_P0_BITS 0x0000000033e0000fULL +#define ESR_INT_SIGNALS_P1_BITS 0x000000000c1f00f0ULL +#define ESR_INT_SRDY0_P0 0x0000000020000000ULL +#define ESR_INT_DET0_P0 0x0000000010000000ULL +#define ESR_INT_SRDY0_P1 0x0000000008000000ULL +#define ESR_INT_DET0_P1 0x0000000004000000ULL +#define ESR_INT_XSRDY_P0 0x0000000002000000ULL +#define ESR_INT_XDP_P0_CH3 0x0000000001000000ULL +#define ESR_INT_XDP_P0_CH2 0x0000000000800000ULL +#define ESR_INT_XDP_P0_CH1 0x0000000000400000ULL +#define ESR_INT_XDP_P0_CH0 0x0000000000200000ULL +#define ESR_INT_XSRDY_P1 0x0000000000100000ULL +#define ESR_INT_XDP_P1_CH3 0x0000000000080000ULL +#define ESR_INT_XDP_P1_CH2 0x0000000000040000ULL +#define ESR_INT_XDP_P1_CH1 0x0000000000020000ULL +#define ESR_INT_XDP_P1_CH0 0x0000000000010000ULL +#define ESR_INT_SLOSS_P1_CH3 0x0000000000000080ULL +#define ESR_INT_SLOSS_P1_CH2 0x0000000000000040ULL +#define ESR_INT_SLOSS_P1_CH1 0x0000000000000020ULL +#define ESR_INT_SLOSS_P1_CH0 0x0000000000000010ULL +#define ESR_INT_SLOSS_P0_CH3 0x0000000000000008ULL +#define ESR_INT_SLOSS_P0_CH2 0x0000000000000004ULL +#define ESR_INT_SLOSS_P0_CH1 0x0000000000000002ULL +#define ESR_INT_SLOSS_P0_CH0 0x0000000000000001ULL + +#define ESR_DEBUG_SEL (FZC_MAC + 0x14808UL) +#define ESR_DEBUG_SEL_VAL 0x000000000000003fULL + +/* SerDes registers behind MIF */ +#define NIU_ESR_DEV_ADDR 0x1e +#define ESR_BASE 0x0000 + +#define ESR_RXTX_COMM_CTRL_L (ESR_BASE + 0x0000) +#define ESR_RXTX_COMM_CTRL_H (ESR_BASE + 0x0001) + +#define ESR_RXTX_RESET_CTRL_L (ESR_BASE + 0x0002) +#define ESR_RXTX_RESET_CTRL_H (ESR_BASE + 0x0003) + +#define ESR_RX_POWER_CTRL_L (ESR_BASE + 0x0004) +#define ESR_RX_POWER_CTRL_H (ESR_BASE + 0x0005) + +#define ESR_TX_POWER_CTRL_L (ESR_BASE + 0x0006) +#define ESR_TX_POWER_CTRL_H (ESR_BASE + 0x0007) + +#define ESR_MISC_POWER_CTRL_L (ESR_BASE + 0x0008) +#define ESR_MISC_POWER_CTRL_H (ESR_BASE + 0x0009) + +#define ESR_RXTX_CTRL_L(CHAN) (ESR_BASE + 0x0080 + (CHAN) * 0x10) +#define ESR_RXTX_CTRL_H(CHAN) (ESR_BASE + 0x0081 + (CHAN) * 0x10) +#define ESR_RXTX_CTRL_BIASCNTL 0x80000000 +#define ESR_RXTX_CTRL_RESV1 0x7c000000 +#define ESR_RXTX_CTRL_TDENFIFO 0x02000000 +#define ESR_RXTX_CTRL_TDWS20 0x01000000 +#define ESR_RXTX_CTRL_VMUXLO 0x00c00000 +#define ESR_RXTX_CTRL_VMUXLO_SHIFT 22 +#define ESR_RXTX_CTRL_VPULSELO 0x00300000 +#define ESR_RXTX_CTRL_VPULSELO_SHIFT 20 +#define ESR_RXTX_CTRL_RESV2 0x000f0000 +#define ESR_RXTX_CTRL_RESV3 0x0000c000 +#define ESR_RXTX_CTRL_RXPRESWIN 0x00003000 +#define ESR_RXTX_CTRL_RXPRESWIN_SHIFT 12 +#define ESR_RXTX_CTRL_RESV4 0x00000800 +#define ESR_RXTX_CTRL_RISEFALL 0x00000700 +#define ESR_RXTX_CTRL_RISEFALL_SHIFT 8 +#define ESR_RXTX_CTRL_RESV5 0x000000fe +#define ESR_RXTX_CTRL_ENSTRETCH 0x00000001 + +#define ESR_RXTX_TUNING_L(CHAN) (ESR_BASE + 0x0082 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING_H(CHAN) (ESR_BASE + 0x0083 + (CHAN) * 0x10) + +#define ESR_RX_SYNCCHAR_L(CHAN) (ESR_BASE + 0x0084 + (CHAN) * 0x10) +#define ESR_RX_SYNCCHAR_H(CHAN) (ESR_BASE + 0x0085 + (CHAN) * 0x10) + +#define ESR_RXTX_TEST_L(CHAN) (ESR_BASE + 0x0086 + (CHAN) * 0x10) +#define ESR_RXTX_TEST_H(CHAN) (ESR_BASE + 0x0087 + (CHAN) * 0x10) + +#define ESR_GLUE_CTRL0_L(CHAN) (ESR_BASE + 0x0088 + (CHAN) * 0x10) +#define ESR_GLUE_CTRL0_H(CHAN) (ESR_BASE + 0x0089 + (CHAN) * 0x10) +#define ESR_GLUE_CTRL0_RESV1 0xf8000000 +#define ESR_GLUE_CTRL0_BLTIME 0x07000000 +#define ESR_GLUE_CTRL0_BLTIME_SHIFT 24 +#define ESR_GLUE_CTRL0_RESV2 0x00ff0000 +#define ESR_GLUE_CTRL0_RXLOS_TEST 0x00008000 +#define ESR_GLUE_CTRL0_RESV3 0x00004000 +#define ESR_GLUE_CTRL0_RXLOSENAB 0x00002000 +#define ESR_GLUE_CTRL0_FASTRESYNC 0x00001000 +#define ESR_GLUE_CTRL0_SRATE 0x00000f00 +#define ESR_GLUE_CTRL0_SRATE_SHIFT 8 +#define ESR_GLUE_CTRL0_THCNT 0x000000ff +#define ESR_GLUE_CTRL0_THCNT_SHIFT 0 + +#define BLTIME_64_CYCLES 0 +#define BLTIME_128_CYCLES 1 +#define BLTIME_256_CYCLES 2 +#define BLTIME_300_CYCLES 3 +#define BLTIME_384_CYCLES 4 +#define BLTIME_512_CYCLES 5 +#define BLTIME_1024_CYCLES 6 +#define BLTIME_2048_CYCLES 7 + +#define ESR_GLUE_CTRL1_L(CHAN) (ESR_BASE + 0x008a + (CHAN) * 0x10) +#define ESR_GLUE_CTRL1_H(CHAN) (ESR_BASE + 0x008b + (CHAN) * 0x10) +#define ESR_RXTX_TUNING1_L(CHAN) (ESR_BASE + 0x00c2 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING1_H(CHAN) (ESR_BASE + 0x00c2 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING2_L(CHAN) (ESR_BASE + 0x0102 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING2_H(CHAN) (ESR_BASE + 0x0102 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING3_L(CHAN) (ESR_BASE + 0x0142 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING3_H(CHAN) (ESR_BASE + 0x0142 + (CHAN) * 0x10) + +#define NIU_ESR2_DEV_ADDR 0x1e +#define ESR2_BASE 0x8000 + +#define ESR2_TI_PLL_CFG_L (ESR2_BASE + 0x000) +#define ESR2_TI_PLL_CFG_H (ESR2_BASE + 0x001) +#define PLL_CFG_STD 0x00000c00 +#define PLL_CFG_STD_SHIFT 10 +#define PLL_CFG_LD 0x00000300 +#define PLL_CFG_LD_SHIFT 8 +#define PLL_CFG_MPY 0x0000001e +#define PLL_CFG_MPY_SHIFT 1 +#define PLL_CFG_ENPLL 0x00000001 + +#define ESR2_TI_PLL_STS_L (ESR2_BASE + 0x002) +#define ESR2_TI_PLL_STS_H (ESR2_BASE + 0x003) +#define PLL_STS_LOCK 0x00000001 + +#define ESR2_TI_PLL_TEST_CFG_L (ESR2_BASE + 0x004) +#define ESR2_TI_PLL_TEST_CFG_H (ESR2_BASE + 0x005) +#define PLL_TEST_INVPATT 0x00004000 +#define PLL_TEST_RATE 0x00003000 +#define PLL_TEST_RATE_SHIFT 12 +#define PLL_TEST_CFG_ENBSAC 0x00000400 +#define PLL_TEST_CFG_ENBSRX 0x00000200 +#define PLL_TEST_CFG_ENBSTX 0x00000100 +#define PLL_TEST_CFG_LOOPBACK_PAD 0x00000040 +#define PLL_TEST_CFG_LOOPBACK_CML_DIS 0x00000080 +#define PLL_TEST_CFG_LOOPBACK_CML_EN 0x000000c0 +#define PLL_TEST_CFG_CLKBYP 0x00000030 +#define PLL_TEST_CFG_CLKBYP_SHIFT 4 +#define PLL_TEST_CFG_EN_RXPATT 0x00000008 +#define PLL_TEST_CFG_EN_TXPATT 0x00000004 +#define PLL_TEST_CFG_TPATT 0x00000003 +#define PLL_TEST_CFG_TPATT_SHIFT 0 + +#define ESR2_TI_PLL_TX_CFG_L(CHAN) (ESR2_BASE + 0x100 + (CHAN) * 4) +#define ESR2_TI_PLL_TX_CFG_H(CHAN) (ESR2_BASE + 0x101 + (CHAN) * 4) +#define PLL_TX_CFG_RDTCT 0x00600000 +#define PLL_TX_CFG_RDTCT_SHIFT 21 +#define PLL_TX_CFG_ENIDL 0x00100000 +#define PLL_TX_CFG_BSTX 0x00020000 +#define PLL_TX_CFG_ENFTP 0x00010000 +#define PLL_TX_CFG_DE 0x0000f000 +#define PLL_TX_CFG_DE_SHIFT 12 +#define PLL_TX_CFG_SWING_125MV 0x00000000 +#define PLL_TX_CFG_SWING_250MV 0x00000200 +#define PLL_TX_CFG_SWING_500MV 0x00000400 +#define PLL_TX_CFG_SWING_625MV 0x00000600 +#define PLL_TX_CFG_SWING_750MV 0x00000800 +#define PLL_TX_CFG_SWING_1000MV 0x00000a00 +#define PLL_TX_CFG_SWING_1250MV 0x00000c00 +#define PLL_TX_CFG_SWING_1375MV 0x00000e00 +#define PLL_TX_CFG_CM 0x00000100 +#define PLL_TX_CFG_INVPAIR 0x00000080 +#define PLL_TX_CFG_RATE 0x00000060 +#define PLL_TX_CFG_RATE_SHIFT 5 +#define PLL_TX_CFG_BUSWIDTH 0x0000001c +#define PLL_TX_CFG_BUSWIDTH_SHIFT 2 +#define PLL_TX_CFG_ENTEST 0x00000002 +#define PLL_TX_CFG_ENTX 0x00000001 + +#define ESR2_TI_PLL_TX_STS_L(CHAN) (ESR2_BASE + 0x102 + (CHAN) * 4) +#define ESR2_TI_PLL_TX_STS_H(CHAN) (ESR2_BASE + 0x103 + (CHAN) * 4) +#define PLL_TX_STS_RDTCTIP 0x00000002 +#define PLL_TX_STS_TESTFAIL 0x00000001 + +#define ESR2_TI_PLL_RX_CFG_L(CHAN) (ESR2_BASE + 0x120 + (CHAN) * 4) +#define ESR2_TI_PLL_RX_CFG_H(CHAN) (ESR2_BASE + 0x121 + (CHAN) * 4) +#define PLL_RX_CFG_BSINRXN 0x02000000 +#define PLL_RX_CFG_BSINRXP 0x01000000 +#define PLL_RX_CFG_EQ_MAX_LF 0x00000000 +#define PLL_RX_CFG_EQ_LP_ADAPTIVE 0x00080000 +#define PLL_RX_CFG_EQ_LP_1084MHZ 0x00400000 +#define PLL_RX_CFG_EQ_LP_805MHZ 0x00480000 +#define PLL_RX_CFG_EQ_LP_573MHZ 0x00500000 +#define PLL_RX_CFG_EQ_LP_402MHZ 0x00580000 +#define PLL_RX_CFG_EQ_LP_304MHZ 0x00600000 +#define PLL_RX_CFG_EQ_LP_216MHZ 0x00680000 +#define PLL_RX_CFG_EQ_LP_156MHZ 0x00700000 +#define PLL_RX_CFG_EQ_LP_135MHZ 0x00780000 +#define PLL_RX_CFG_EQ_SHIFT 19 +#define PLL_RX_CFG_CDR 0x00070000 +#define PLL_RX_CFG_CDR_SHIFT 16 +#define PLL_RX_CFG_LOS_DIS 0x00000000 +#define PLL_RX_CFG_LOS_HTHRESH 0x00004000 +#define PLL_RX_CFG_LOS_LTHRESH 0x00008000 +#define PLL_RX_CFG_ALIGN_DIS 0x00000000 +#define PLL_RX_CFG_ALIGN_ENA 0x00001000 +#define PLL_RX_CFG_ALIGN_JOG 0x00002000 +#define PLL_RX_CFG_TERM_VDDT 0x00000000 +#define PLL_RX_CFG_TERM_0P8VDDT 0x00000100 +#define PLL_RX_CFG_TERM_FLOAT 0x00000300 +#define PLL_RX_CFG_INVPAIR 0x00000080 +#define PLL_RX_CFG_RATE 0x00000060 +#define PLL_RX_CFG_RATE_SHIFT 5 +#define PLL_RX_CFG_BUSWIDTH 0x0000001c +#define PLL_RX_CFG_BUSWIDTH_SHIFT 2 +#define PLL_RX_CFG_ENTEST 0x00000002 +#define PLL_RX_CFG_ENRX 0x00000001 + +#define ESR2_TI_PLL_RX_STS_L(CHAN) (ESR2_BASE + 0x122 + (CHAN) * 4) +#define ESR2_TI_PLL_RX_STS_H(CHAN) (ESR2_BASE + 0x123 + (CHAN) * 4) +#define PLL_RX_STS_CRCIDTCT 0x00000200 +#define PLL_RX_STS_CWDTCT 0x00000100 +#define PLL_RX_STS_BSRXN 0x00000020 +#define PLL_RX_STS_BSRXP 0x00000010 +#define PLL_RX_STS_LOSDTCT 0x00000008 +#define PLL_RX_STS_ODDCG 0x00000004 +#define PLL_RX_STS_SYNC 0x00000002 +#define PLL_RX_STS_TESTFAIL 0x00000001 + +#define ENET_VLAN_TBL(IDX) (FZC_FFLP + 0x00000UL + (IDX) * 8UL) +#define ENET_VLAN_TBL_PARITY1 0x0000000000020000ULL +#define ENET_VLAN_TBL_PARITY0 0x0000000000010000ULL +#define ENET_VLAN_TBL_VPR 0x0000000000000008ULL +#define ENET_VLAN_TBL_VLANRDCTBLN 0x0000000000000007ULL +#define ENET_VLAN_TBL_SHIFT(PORT) ((PORT) * 4) + +#define ENET_VLAN_TBL_NUM_ENTRIES 4096 + +#define FFLP_VLAN_PAR_ERR (FZC_FFLP + 0x0800UL) +#define FFLP_VLAN_PAR_ERR_ERR 0x0000000080000000ULL +#define FFLP_VLAN_PAR_ERR_M_ERR 0x0000000040000000ULL +#define FFLP_VLAN_PAR_ERR_ADDR 0x000000003ffc0000ULL +#define FFLP_VLAN_PAR_ERR_DATA 0x000000000003ffffULL + +#define L2_CLS(IDX) (FZC_FFLP + 0x20000UL + (IDX) * 8UL) +#define L2_CLS_VLD 0x0000000000010000ULL +#define L2_CLS_ETYPE 0x000000000000ffffULL +#define L2_CLS_ETYPE_SHIFT 0 + +#define L3_CLS(IDX) (FZC_FFLP + 0x20010UL + (IDX) * 8UL) +#define L3_CLS_VALID 0x0000000002000000ULL +#define L3_CLS_IPVER 0x0000000001000000ULL +#define L3_CLS_PID 0x0000000000ff0000ULL +#define L3_CLS_PID_SHIFT 16 +#define L3_CLS_TOSMASK 0x000000000000ff00ULL +#define L3_CLS_TOSMASK_SHIFT 8 +#define L3_CLS_TOS 0x00000000000000ffULL +#define L3_CLS_TOS_SHIFT 0 + +#define TCAM_KEY(IDX) (FZC_FFLP + 0x20030UL + (IDX) * 8UL) +#define TCAM_KEY_DISC 0x0000000000000008ULL +#define TCAM_KEY_TSEL 0x0000000000000004ULL +#define TCAM_KEY_IPADDR 0x0000000000000001ULL + +#define TCAM_KEY_0 (FZC_FFLP + 0x20090UL) +#define TCAM_KEY_0_KEY 0x00000000000000ffULL /* bits 192-199 */ + +#define TCAM_KEY_1 (FZC_FFLP + 0x20098UL) +#define TCAM_KEY_1_KEY 0xffffffffffffffffULL /* bits 128-191 */ + +#define TCAM_KEY_2 (FZC_FFLP + 0x200a0UL) +#define TCAM_KEY_2_KEY 0xffffffffffffffffULL /* bits 64-127 */ + +#define TCAM_KEY_3 (FZC_FFLP + 0x200a8UL) +#define TCAM_KEY_3_KEY 0xffffffffffffffffULL /* bits 0-63 */ + +#define TCAM_KEY_MASK_0 (FZC_FFLP + 0x200b0UL) +#define TCAM_KEY_MASK_0_KEY_SEL 0x00000000000000ffULL /* bits 192-199 */ + +#define TCAM_KEY_MASK_1 (FZC_FFLP + 0x200b8UL) +#define TCAM_KEY_MASK_1_KEY_SEL 0xffffffffffffffffULL /* bits 128-191 */ + +#define TCAM_KEY_MASK_2 (FZC_FFLP + 0x200c0UL) +#define TCAM_KEY_MASK_2_KEY_SEL 0xffffffffffffffffULL /* bits 64-127 */ + +#define TCAM_KEY_MASK_3 (FZC_FFLP + 0x200c8UL) +#define TCAM_KEY_MASK_3_KEY_SEL 0xffffffffffffffffULL /* bits 0-63 */ + +#define TCAM_CTL (FZC_FFLP + 0x200d0UL) +#define TCAM_CTL_RWC 0x00000000001c0000ULL +#define TCAM_CTL_RWC_TCAM_WRITE 0x0000000000000000ULL +#define TCAM_CTL_RWC_TCAM_READ 0x0000000000040000ULL +#define TCAM_CTL_RWC_TCAM_COMPARE 0x0000000000080000ULL +#define TCAM_CTL_RWC_RAM_WRITE 0x0000000000100000ULL +#define TCAM_CTL_RWC_RAM_READ 0x0000000000140000ULL +#define TCAM_CTL_STAT 0x0000000000020000ULL +#define TCAM_CTL_MATCH 0x0000000000010000ULL +#define TCAM_CTL_LOC 0x00000000000003ffULL + +#define TCAM_ERR (FZC_FFLP + 0x200d8UL) +#define TCAM_ERR_ERR 0x0000000080000000ULL +#define TCAM_ERR_P_ECC 0x0000000040000000ULL +#define TCAM_ERR_MULT 0x0000000020000000ULL +#define TCAM_ERR_ADDR 0x0000000000ff0000ULL +#define TCAM_ERR_SYNDROME 0x000000000000ffffULL + +#define HASH_LOOKUP_ERR_LOG1 (FZC_FFLP + 0x200e0UL) +#define HASH_LOOKUP_ERR_LOG1_ERR 0x0000000000000008ULL +#define HASH_LOOKUP_ERR_LOG1_MULT_LK 0x0000000000000004ULL +#define HASH_LOOKUP_ERR_LOG1_CU 0x0000000000000002ULL +#define HASH_LOOKUP_ERR_LOG1_MULT_BIT 0x0000000000000001ULL + +#define HASH_LOOKUP_ERR_LOG2 (FZC_FFLP + 0x200e8UL) +#define HASH_LOOKUP_ERR_LOG2_H1 0x000000007ffff800ULL +#define HASH_LOOKUP_ERR_LOG2_SUBAREA 0x0000000000000700ULL +#define HASH_LOOKUP_ERR_LOG2_SYNDROME 0x00000000000000ffULL + +#define FFLP_CFG_1 (FZC_FFLP + 0x20100UL) +#define FFLP_CFG_1_TCAM_DIS 0x0000000004000000ULL +#define FFLP_CFG_1_PIO_DBG_SEL 0x0000000003800000ULL +#define FFLP_CFG_1_PIO_FIO_RST 0x0000000000400000ULL +#define FFLP_CFG_1_PIO_FIO_LAT 0x0000000000300000ULL +#define FFLP_CFG_1_CAMLAT 0x00000000000f0000ULL +#define FFLP_CFG_1_CAMLAT_SHIFT 16 +#define FFLP_CFG_1_CAMRATIO 0x000000000000f000ULL +#define FFLP_CFG_1_CAMRATIO_SHIFT 12 +#define FFLP_CFG_1_FCRAMRATIO 0x0000000000000f00ULL +#define FFLP_CFG_1_FCRAMRATIO_SHIFT 8 +#define FFLP_CFG_1_FCRAMOUTDR_MASK 0x00000000000000f0ULL +#define FFLP_CFG_1_FCRAMOUTDR_NORMAL 0x0000000000000000ULL +#define FFLP_CFG_1_FCRAMOUTDR_STRONG 0x0000000000000050ULL +#define FFLP_CFG_1_FCRAMOUTDR_WEAK 0x00000000000000a0ULL +#define FFLP_CFG_1_FCRAMQS 0x0000000000000008ULL +#define FFLP_CFG_1_ERRORDIS 0x0000000000000004ULL +#define FFLP_CFG_1_FFLPINITDONE 0x0000000000000002ULL +#define FFLP_CFG_1_LLCSNAP 0x0000000000000001ULL + +#define DEFAULT_FCRAMRATIO 10 + +#define DEFAULT_TCAM_LATENCY 4 +#define DEFAULT_TCAM_ACCESS_RATIO 10 + +#define TCP_CFLAG_MSK (FZC_FFLP + 0x20108UL) +#define TCP_CFLAG_MSK_MASK 0x0000000000000fffULL + +#define FCRAM_REF_TMR (FZC_FFLP + 0x20110UL) +#define FCRAM_REF_TMR_MAX 0x00000000ffff0000ULL +#define FCRAM_REF_TMR_MAX_SHIFT 16 +#define FCRAM_REF_TMR_MIN 0x000000000000ffffULL +#define FCRAM_REF_TMR_MIN_SHIFT 0 + +#define DEFAULT_FCRAM_REFRESH_MAX 512 +#define DEFAULT_FCRAM_REFRESH_MIN 512 + +#define FCRAM_FIO_ADDR (FZC_FFLP + 0x20118UL) +#define FCRAM_FIO_ADDR_ADDR 0x00000000000000ffULL + +#define FCRAM_FIO_DAT (FZC_FFLP + 0x20120UL) +#define FCRAM_FIO_DAT_DATA 0x000000000000ffffULL + +#define FCRAM_ERR_TST0 (FZC_FFLP + 0x20128UL) +#define FCRAM_ERR_TST0_SYND 0x00000000000000ffULL + +#define FCRAM_ERR_TST1 (FZC_FFLP + 0x20130UL) +#define FCRAM_ERR_TST1_DAT 0x00000000ffffffffULL + +#define FCRAM_ERR_TST2 (FZC_FFLP + 0x20138UL) +#define FCRAM_ERR_TST2_DAT 0x00000000ffffffffULL + +#define FFLP_ERR_MASK (FZC_FFLP + 0x20140UL) +#define FFLP_ERR_MASK_HSH_TBL_DAT 0x00000000000007f8ULL +#define FFLP_ERR_MASK_HSH_TBL_LKUP 0x0000000000000004ULL +#define FFLP_ERR_MASK_TCAM 0x0000000000000002ULL +#define FFLP_ERR_MASK_VLAN 0x0000000000000001ULL + +#define FFLP_DBG_TRAIN_VCT (FZC_FFLP + 0x20148UL) +#define FFLP_DBG_TRAIN_VCT_VECTOR 0x00000000ffffffffULL + +#define FCRAM_PHY_RD_LAT (FZC_FFLP + 0x20150UL) +#define FCRAM_PHY_RD_LAT_LAT 0x00000000000000ffULL + +/* Ethernet TCAM format */ +#define TCAM_ETHKEY0_RESV1 0xffffffffffffff00ULL +#define TCAM_ETHKEY0_CLASS_CODE 0x00000000000000f8ULL +#define TCAM_ETHKEY0_CLASS_CODE_SHIFT 3 +#define TCAM_ETHKEY0_RESV2 0x0000000000000007ULL +#define TCAM_ETHKEY1_FRAME_BYTE0_7(NUM) (0xff << ((7 - NUM) * 8)) +#define TCAM_ETHKEY2_FRAME_BYTE8 0xff00000000000000ULL +#define TCAM_ETHKEY2_FRAME_BYTE8_SHIFT 56 +#define TCAM_ETHKEY2_FRAME_BYTE9 0x00ff000000000000ULL +#define TCAM_ETHKEY2_FRAME_BYTE9_SHIFT 48 +#define TCAM_ETHKEY2_FRAME_BYTE10 0x0000ff0000000000ULL +#define TCAM_ETHKEY2_FRAME_BYTE10_SHIFT 40 +#define TCAM_ETHKEY2_FRAME_RESV 0x000000ffffffffffULL +#define TCAM_ETHKEY3_FRAME_RESV 0xffffffffffffffffULL + +/* IPV4 TCAM format */ +#define TCAM_V4KEY0_RESV1 0xffffffffffffff00ULL +#define TCAM_V4KEY0_CLASS_CODE 0x00000000000000f8ULL +#define TCAM_V4KEY0_CLASS_CODE_SHIFT 3 +#define TCAM_V4KEY0_RESV2 0x0000000000000007ULL +#define TCAM_V4KEY1_L2RDCNUM 0xf800000000000000ULL +#define TCAM_V4KEY1_L2RDCNUM_SHIFT 59 +#define TCAM_V4KEY1_NOPORT 0x0400000000000000ULL +#define TCAM_V4KEY1_RESV 0x03ffffffffffffffULL +#define TCAM_V4KEY2_RESV 0xffff000000000000ULL +#define TCAM_V4KEY2_TOS 0x0000ff0000000000ULL +#define TCAM_V4KEY2_TOS_SHIFT 40 +#define TCAM_V4KEY2_PROTO 0x000000ff00000000ULL +#define TCAM_V4KEY2_PROTO_SHIFT 32 +#define TCAM_V4KEY2_PORT_SPI 0x00000000ffffffffULL +#define TCAM_V4KEY2_PORT_SPI_SHIFT 0 +#define TCAM_V4KEY3_SADDR 0xffffffff00000000ULL +#define TCAM_V4KEY3_SADDR_SHIFT 32 +#define TCAM_V4KEY3_DADDR 0x00000000ffffffffULL +#define TCAM_V4KEY3_DADDR_SHIFT 0 + +/* IPV6 TCAM format */ +#define TCAM_V6KEY0_RESV1 0xffffffffffffff00ULL +#define TCAM_V6KEY0_CLASS_CODE 0x00000000000000f8ULL +#define TCAM_V6KEY0_CLASS_CODE_SHIFT 3 +#define TCAM_V6KEY0_RESV2 0x0000000000000007ULL +#define TCAM_V6KEY1_L2RDCNUM 0xf800000000000000ULL +#define TCAM_V6KEY1_L2RDCNUM_SHIFT 59 +#define TCAM_V6KEY1_NOPORT 0x0400000000000000ULL +#define TCAM_V6KEY1_RESV 0x03ff000000000000ULL +#define TCAM_V6KEY1_TOS 0x0000ff0000000000ULL +#define TCAM_V6KEY1_TOS_SHIFT 40 +#define TCAM_V6KEY1_NEXT_HDR 0x000000ff00000000ULL +#define TCAM_V6KEY1_NEXT_HDR_SHIFT 32 +#define TCAM_V6KEY1_PORT_SPI 0x00000000ffffffffULL +#define TCAM_V6KEY1_PORT_SPI_SHIFT 0 +#define TCAM_V6KEY2_ADDR_HIGH 0xffffffffffffffffULL +#define TCAM_V6KEY3_ADDR_LOW 0xffffffffffffffffULL + +#define TCAM_ASSOCDATA_SYNDROME 0x000003fffc000000ULL +#define TCAM_ASSOCDATA_SYNDROME_SHIFT 26 +#define TCAM_ASSOCDATA_ZFID 0x0000000003ffc000ULL +#define TCAM_ASSOCDATA_ZFID_SHIFT 14 +#define TCAM_ASSOCDATA_V4_ECC_OK 0x0000000000002000ULL +#define TCAM_ASSOCDATA_DISC 0x0000000000001000ULL +#define TCAM_ASSOCDATA_TRES_MASK 0x0000000000000c00ULL +#define TCAM_ASSOCDATA_TRES_USE_L2RDC 0x0000000000000000ULL +#define TCAM_ASSOCDATA_TRES_USE_OFFSET 0x0000000000000400ULL +#define TCAM_ASSOCDATA_TRES_OVR_RDC 0x0000000000000800ULL +#define TCAM_ASSOCDATA_TRES_OVR_RDC_OFF 0x0000000000000c00ULL +#define TCAM_ASSOCDATA_RDCTBL 0x0000000000000380ULL +#define TCAM_ASSOCDATA_RDCTBL_SHIFT 7 +#define TCAM_ASSOCDATA_OFFSET 0x000000000000007cULL +#define TCAM_ASSOCDATA_OFFSET_SHIFT 2 +#define TCAM_ASSOCDATA_ZFVLD 0x0000000000000002ULL +#define TCAM_ASSOCDATA_AGE 0x0000000000000001ULL + +#define FLOW_KEY(IDX) (FZC_FFLP + 0x40000UL + (IDX) * 8UL) +#define FLOW_KEY_PORT 0x0000000000000200ULL +#define FLOW_KEY_L2DA 0x0000000000000100ULL +#define FLOW_KEY_VLAN 0x0000000000000080ULL +#define FLOW_KEY_IPSA 0x0000000000000040ULL +#define FLOW_KEY_IPDA 0x0000000000000020ULL +#define FLOW_KEY_PROTO 0x0000000000000010ULL +#define FLOW_KEY_L4_0 0x000000000000000cULL +#define FLOW_KEY_L4_0_SHIFT 2 +#define FLOW_KEY_L4_1 0x0000000000000003ULL +#define FLOW_KEY_L4_1_SHIFT 0 + +#define FLOW_KEY_L4_NONE 0x0 +#define FLOW_KEY_L4_RESV 0x1 +#define FLOW_KEY_L4_BYTE12 0x2 +#define FLOW_KEY_L4_BYTE56 0x3 + +#define H1POLY (FZC_FFLP + 0x40060UL) +#define H1POLY_INITVAL 0x00000000ffffffffULL + +#define H2POLY (FZC_FFLP + 0x40068UL) +#define H2POLY_INITVAL 0x000000000000ffffULL + +#define FLW_PRT_SEL(IDX) (FZC_FFLP + 0x40070UL + (IDX) * 8UL) +#define FLW_PRT_SEL_EXT 0x0000000000010000ULL +#define FLW_PRT_SEL_MASK 0x0000000000001f00ULL +#define FLW_PRT_SEL_MASK_SHIFT 8 +#define FLW_PRT_SEL_BASE 0x000000000000001fULL +#define FLW_PRT_SEL_BASE_SHIFT 0 + +#define HASH_TBL_ADDR(IDX) (FFLP + 0x00000UL + (IDX) * 8192UL) +#define HASH_TBL_ADDR_AUTOINC 0x0000000000800000ULL +#define HASH_TBL_ADDR_ADDR 0x00000000007fffffULL + +#define HASH_TBL_DATA(IDX) (FFLP + 0x00008UL + (IDX) * 8192UL) +#define HASH_TBL_DATA_DATA 0xffffffffffffffffULL + +/* FCRAM hash table entries are up to 8 64-bit words in size. + * The layout of each entry is determined by the settings in the + * first word, which is the header. + * + * The indexing is controllable per partition (there is one partition + * per RDC group, thus a total of eight) using the BASE and MASK fields + * of FLW_PRT_SEL above. + */ +#define FCRAM_SIZE 0x800000 +#define FCRAM_NUM_PARTITIONS 8 + +/* Generic HASH entry header, used for all non-optimized formats. */ +#define HASH_HEADER_FMT 0x8000000000000000ULL +#define HASH_HEADER_EXT 0x4000000000000000ULL +#define HASH_HEADER_VALID 0x2000000000000000ULL +#define HASH_HEADER_RESVD 0x1000000000000000ULL +#define HASH_HEADER_L2_DADDR 0x0ffffffffffff000ULL +#define HASH_HEADER_L2_DADDR_SHIFT 12 +#define HASH_HEADER_VLAN 0x0000000000000fffULL +#define HASH_HEADER_VLAN_SHIFT 0 + +/* Optimized format, just a header with a special layout defined below. + * Set FMT and EXT both to zero to indicate this layout is being used. + */ +#define HASH_OPT_HEADER_FMT 0x8000000000000000ULL +#define HASH_OPT_HEADER_EXT 0x4000000000000000ULL +#define HASH_OPT_HEADER_VALID 0x2000000000000000ULL +#define HASH_OPT_HEADER_RDCOFF 0x1f00000000000000ULL +#define HASH_OPT_HEADER_RDCOFF_SHIFT 56 +#define HASH_OPT_HEADER_HASH2 0x00ffff0000000000ULL +#define HASH_OPT_HEADER_HASH2_SHIFT 40 +#define HASH_OPT_HEADER_RESVD 0x000000ff00000000ULL +#define HASH_OPT_HEADER_USERINFO 0x00000000ffffffffULL +#define HASH_OPT_HEADER_USERINFO_SHIFT 0 + +/* Port and protocol word used for ipv4 and ipv6 layouts. */ +#define HASH_PORT_DPORT 0xffff000000000000ULL +#define HASH_PORT_DPORT_SHIFT 48 +#define HASH_PORT_SPORT 0x0000ffff00000000ULL +#define HASH_PORT_SPORT_SHIFT 32 +#define HASH_PORT_PROTO 0x00000000ff000000ULL +#define HASH_PORT_PROTO_SHIFT 24 +#define HASH_PORT_PORT_OFF 0x0000000000c00000ULL +#define HASH_PORT_PORT_OFF_SHIFT 22 +#define HASH_PORT_PORT_RESV 0x00000000003fffffULL + +/* Action word used for ipv4 and ipv6 layouts. */ +#define HASH_ACTION_RESV1 0xe000000000000000ULL +#define HASH_ACTION_RDCOFF 0x1f00000000000000ULL +#define HASH_ACTION_RDCOFF_SHIFT 56 +#define HASH_ACTION_ZFVALID 0x0080000000000000ULL +#define HASH_ACTION_RESV2 0x0070000000000000ULL +#define HASH_ACTION_ZFID 0x000fff0000000000ULL +#define HASH_ACTION_ZFID_SHIFT 40 +#define HASH_ACTION_RESV3 0x000000ff00000000ULL +#define HASH_ACTION_USERINFO 0x00000000ffffffffULL +#define HASH_ACTION_USERINFO_SHIFT 0 + +/* IPV4 address word. Addresses are in network endian. */ +#define HASH_IP4ADDR_SADDR 0xffffffff00000000ULL +#define HASH_IP4ADDR_SADDR_SHIFT 32 +#define HASH_IP4ADDR_DADDR 0x00000000ffffffffULL +#define HASH_IP4ADDR_DADDR_SHIFT 0 + +/* IPV6 address layout is 4 words, first two are saddr, next two + * are daddr. Addresses are in network endian. + */ + +struct fcram_hash_opt { + u64 header; +}; + +/* EXT=1, FMT=0 */ +struct fcram_hash_ipv4 { + u64 header; + u64 addrs; + u64 ports; + u64 action; +}; + +/* EXT=1, FMT=1 */ +struct fcram_hash_ipv6 { + u64 header; + u64 addrs[4]; + u64 ports; + u64 action; +}; + +#define HASH_TBL_DATA_LOG(IDX) (FFLP + 0x00010UL + (IDX) * 8192UL) +#define HASH_TBL_DATA_LOG_ERR 0x0000000080000000ULL +#define HASH_TBL_DATA_LOG_ADDR 0x000000007fffff00ULL +#define HASH_TBL_DATA_LOG_SYNDROME 0x00000000000000ffULL + +#define RX_DMA_CK_DIV (FZC_DMC + 0x00000UL) +#define RX_DMA_CK_DIV_CNT 0x000000000000ffffULL + +#define DEF_RDC(IDX) (FZC_DMC + 0x00008UL + (IDX) * 0x8UL) +#define DEF_RDC_VAL 0x000000000000001fULL + +#define PT_DRR_WT(IDX) (FZC_DMC + 0x00028UL + (IDX) * 0x8UL) +#define PT_DRR_WT_VAL 0x000000000000ffffULL + +#define PT_DRR_WEIGHT_DEFAULT_10G 0x0400 +#define PT_DRR_WEIGHT_DEFAULT_1G 0x0066 + +#define PT_USE(IDX) (FZC_DMC + 0x00048UL + (IDX) * 0x8UL) +#define PT_USE_CNT 0x00000000000fffffULL + +#define RED_RAN_INIT (FZC_DMC + 0x00068UL) +#define RED_RAN_INIT_OPMODE 0x0000000000010000ULL +#define RED_RAN_INIT_VAL 0x000000000000ffffULL + +#define RX_ADDR_MD (FZC_DMC + 0x00070UL) +#define RX_ADDR_MD_DBG_PT_MUX_SEL 0x000000000000000cULL +#define RX_ADDR_MD_RAM_ACC 0x0000000000000002ULL +#define RX_ADDR_MD_MODE32 0x0000000000000001ULL + +#define RDMC_PRE_PAR_ERR (FZC_DMC + 0x00078UL) +#define RDMC_PRE_PAR_ERR_ERR 0x0000000000008000ULL +#define RDMC_PRE_PAR_ERR_MERR 0x0000000000004000ULL +#define RDMC_PRE_PAR_ERR_ADDR 0x00000000000000ffULL + +#define RDMC_SHA_PAR_ERR (FZC_DMC + 0x00080UL) +#define RDMC_SHA_PAR_ERR_ERR 0x0000000000008000ULL +#define RDMC_SHA_PAR_ERR_MERR 0x0000000000004000ULL +#define RDMC_SHA_PAR_ERR_ADDR 0x00000000000000ffULL + +#define RDMC_MEM_ADDR (FZC_DMC + 0x00088UL) +#define RDMC_MEM_ADDR_PRE_SHAD 0x0000000000000100ULL +#define RDMC_MEM_ADDR_ADDR 0x00000000000000ffULL + +#define RDMC_MEM_DAT0 (FZC_DMC + 0x00090UL) +#define RDMC_MEM_DAT0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define RDMC_MEM_DAT1 (FZC_DMC + 0x00098UL) +#define RDMC_MEM_DAT1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define RDMC_MEM_DAT2 (FZC_DMC + 0x000a0UL) +#define RDMC_MEM_DAT2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define RDMC_MEM_DAT3 (FZC_DMC + 0x000a8UL) +#define RDMC_MEM_DAT3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define RDMC_MEM_DAT4 (FZC_DMC + 0x000b0UL) +#define RDMC_MEM_DAT4_DATA 0x00000000000fffffULL /* bits 147:128 */ + +#define RX_CTL_DAT_FIFO_STAT (FZC_DMC + 0x000b8UL) +#define RX_CTL_DAT_FIFO_STAT_ID_MISMATCH 0x0000000000000100ULL +#define RX_CTL_DAT_FIFO_STAT_ZCP_EOP_ERR 0x00000000000000f0ULL +#define RX_CTL_DAT_FIFO_STAT_IPP_EOP_ERR 0x000000000000000fULL + +#define RX_CTL_DAT_FIFO_MASK (FZC_DMC + 0x000c0UL) +#define RX_CTL_DAT_FIFO_MASK_ID_MISMATCH 0x0000000000000100ULL +#define RX_CTL_DAT_FIFO_MASK_ZCP_EOP_ERR 0x00000000000000f0ULL +#define RX_CTL_DAT_FIFO_MASK_IPP_EOP_ERR 0x000000000000000fULL + +#define RDMC_TRAINING_VECTOR (FZC_DMC + 0x000c8UL) +#define RDMC_TRAINING_VECTOR_TRAINING_VECTOR 0x00000000ffffffffULL + +#define RX_CTL_DAT_FIFO_STAT_DBG (FZC_DMC + 0x000d0UL) +#define RX_CTL_DAT_FIFO_STAT_DBG_ID_MISMATCH 0x0000000000000100ULL +#define RX_CTL_DAT_FIFO_STAT_DBG_ZCP_EOP_ERR 0x00000000000000f0ULL +#define RX_CTL_DAT_FIFO_STAT_DBG_IPP_EOP_ERR 0x000000000000000fULL + +#define RDC_TBL(TBL,SLOT) (FZC_ZCP + 0x10000UL + \ + (TBL) * (8UL * 16UL) + \ + (SLOT) * 8UL) +#define RDC_TBL_RDC 0x000000000000000fULL + +#define RX_LOG_PAGE_VLD(IDX) (FZC_DMC + 0x20000UL + (IDX) * 0x40UL) +#define RX_LOG_PAGE_VLD_FUNC 0x000000000000000cULL +#define RX_LOG_PAGE_VLD_FUNC_SHIFT 2 +#define RX_LOG_PAGE_VLD_PAGE1 0x0000000000000002ULL +#define RX_LOG_PAGE_VLD_PAGE0 0x0000000000000001ULL + +#define RX_LOG_MASK1(IDX) (FZC_DMC + 0x20008UL + (IDX) * 0x40UL) +#define RX_LOG_MASK1_MASK 0x00000000ffffffffULL + +#define RX_LOG_VAL1(IDX) (FZC_DMC + 0x20010UL + (IDX) * 0x40UL) +#define RX_LOG_VAL1_VALUE 0x00000000ffffffffULL + +#define RX_LOG_MASK2(IDX) (FZC_DMC + 0x20018UL + (IDX) * 0x40UL) +#define RX_LOG_MASK2_MASK 0x00000000ffffffffULL + +#define RX_LOG_VAL2(IDX) (FZC_DMC + 0x20020UL + (IDX) * 0x40UL) +#define RX_LOG_VAL2_VALUE 0x00000000ffffffffULL + +#define RX_LOG_PAGE_RELO1(IDX) (FZC_DMC + 0x20028UL + (IDX) * 0x40UL) +#define RX_LOG_PAGE_RELO1_RELO 0x00000000ffffffffULL + +#define RX_LOG_PAGE_RELO2(IDX) (FZC_DMC + 0x20030UL + (IDX) * 0x40UL) +#define RX_LOG_PAGE_RELO2_RELO 0x00000000ffffffffULL + +#define RX_LOG_PAGE_HDL(IDX) (FZC_DMC + 0x20038UL + (IDX) * 0x40UL) +#define RX_LOG_PAGE_HDL_HANDLE 0x00000000000fffffULL + +#define TX_LOG_PAGE_VLD(IDX) (FZC_DMC + 0x40000UL + (IDX) * 0x200UL) +#define TX_LOG_PAGE_VLD_FUNC 0x000000000000000cULL +#define TX_LOG_PAGE_VLD_FUNC_SHIFT 2 +#define TX_LOG_PAGE_VLD_PAGE1 0x0000000000000002ULL +#define TX_LOG_PAGE_VLD_PAGE0 0x0000000000000001ULL + +#define TX_LOG_MASK1(IDX) (FZC_DMC + 0x40008UL + (IDX) * 0x200UL) +#define TX_LOG_MASK1_MASK 0x00000000ffffffffULL + +#define TX_LOG_VAL1(IDX) (FZC_DMC + 0x40010UL + (IDX) * 0x200UL) +#define TX_LOG_VAL1_VALUE 0x00000000ffffffffULL + +#define TX_LOG_MASK2(IDX) (FZC_DMC + 0x40018UL + (IDX) * 0x200UL) +#define TX_LOG_MASK2_MASK 0x00000000ffffffffULL + +#define TX_LOG_VAL2(IDX) (FZC_DMC + 0x40020UL + (IDX) * 0x200UL) +#define TX_LOG_VAL2_VALUE 0x00000000ffffffffULL + +#define TX_LOG_PAGE_RELO1(IDX) (FZC_DMC + 0x40028UL + (IDX) * 0x200UL) +#define TX_LOG_PAGE_RELO1_RELO 0x00000000ffffffffULL + +#define TX_LOG_PAGE_RELO2(IDX) (FZC_DMC + 0x40030UL + (IDX) * 0x200UL) +#define TX_LOG_PAGE_RELO2_RELO 0x00000000ffffffffULL + +#define TX_LOG_PAGE_HDL(IDX) (FZC_DMC + 0x40038UL + (IDX) * 0x200UL) +#define TX_LOG_PAGE_HDL_HANDLE 0x00000000000fffffULL + +#define TX_ADDR_MD (FZC_DMC + 0x45000UL) +#define TX_ADDR_MD_MODE32 0x0000000000000001ULL + +#define RDC_RED_PARA(IDX) (FZC_DMC + 0x30000UL + (IDX) * 0x40UL) +#define RDC_RED_PARA_THRE_SYN 0x00000000fff00000ULL +#define RDC_RED_PARA_THRE_SYN_SHIFT 20 +#define RDC_RED_PARA_WIN_SYN 0x00000000000f0000ULL +#define RDC_RED_PARA_WIN_SYN_SHIFT 16 +#define RDC_RED_PARA_THRE 0x000000000000fff0ULL +#define RDC_RED_PARA_THRE_SHIFT 4 +#define RDC_RED_PARA_WIN 0x000000000000000fULL +#define RDC_RED_PARA_WIN_SHIFT 0 + +#define RED_DIS_CNT(IDX) (FZC_DMC + 0x30008UL + (IDX) * 0x40UL) +#define RED_DIS_CNT_OFLOW 0x0000000000010000ULL +#define RED_DIS_CNT_COUNT 0x000000000000ffffULL + +#define IPP_CFIG (FZC_IPP + 0x00000UL) +#define IPP_CFIG_SOFT_RST 0x0000000080000000ULL +#define IPP_CFIG_IP_MAX_PKT 0x0000000001ffff00ULL +#define IPP_CFIG_IP_MAX_PKT_SHIFT 8 +#define IPP_CFIG_FFLP_CS_PIO_W 0x0000000000000080ULL +#define IPP_CFIG_PFIFO_PIO_W 0x0000000000000040ULL +#define IPP_CFIG_DFIFO_PIO_W 0x0000000000000020ULL +#define IPP_CFIG_CKSUM_EN 0x0000000000000010ULL +#define IPP_CFIG_DROP_BAD_CRC 0x0000000000000008ULL +#define IPP_CFIG_DFIFO_ECC_EN 0x0000000000000004ULL +#define IPP_CFIG_DEBUG_BUS_OUT_EN 0x0000000000000002ULL +#define IPP_CFIG_IPP_ENABLE 0x0000000000000001ULL + +#define IPP_PKT_DIS (FZC_IPP + 0x00020UL) +#define IPP_PKT_DIS_COUNT 0x0000000000003fffULL + +#define IPP_BAD_CS_CNT (FZC_IPP + 0x00028UL) +#define IPP_BAD_CS_CNT_COUNT 0x0000000000003fffULL + +#define IPP_ECC (FZC_IPP + 0x00030UL) +#define IPP_ECC_COUNT 0x00000000000000ffULL + +#define IPP_INT_STAT (FZC_IPP + 0x00040UL) +#define IPP_INT_STAT_SOP_MISS 0x0000000080000000ULL +#define IPP_INT_STAT_EOP_MISS 0x0000000040000000ULL +#define IPP_INT_STAT_DFIFO_UE 0x0000000030000000ULL +#define IPP_INT_STAT_DFIFO_CE 0x000000000c000000ULL +#define IPP_INT_STAT_DFIFO_ECC 0x0000000003000000ULL +#define IPP_INT_STAT_DFIFO_ECC_IDX 0x00000000007ff000ULL +#define IPP_INT_STAT_PFIFO_PERR 0x0000000000000800ULL +#define IPP_INT_STAT_ECC_ERR_MAX 0x0000000000000400ULL +#define IPP_INT_STAT_PFIFO_ERR_IDX 0x00000000000003f0ULL +#define IPP_INT_STAT_PFIFO_OVER 0x0000000000000008ULL +#define IPP_INT_STAT_PFIFO_UND 0x0000000000000004ULL +#define IPP_INT_STAT_BAD_CS_MX 0x0000000000000002ULL +#define IPP_INT_STAT_PKT_DIS_MX 0x0000000000000001ULL +#define IPP_INT_STAT_ALL 0x00000000ff7fffffULL + +#define IPP_MSK (FZC_IPP + 0x00048UL) +#define IPP_MSK_ECC_ERR_MX 0x0000000000000080ULL +#define IPP_MSK_DFIFO_EOP_SOP 0x0000000000000040ULL +#define IPP_MSK_DFIFO_UC 0x0000000000000020ULL +#define IPP_MSK_PFIFO_PAR 0x0000000000000010ULL +#define IPP_MSK_PFIFO_OVER 0x0000000000000008ULL +#define IPP_MSK_PFIFO_UND 0x0000000000000004ULL +#define IPP_MSK_BAD_CS 0x0000000000000002ULL +#define IPP_MSK_PKT_DIS_CNT 0x0000000000000001ULL +#define IPP_MSK_ALL 0x00000000000000ffULL + +#define IPP_PFIFO_RD0 (FZC_IPP + 0x00060UL) +#define IPP_PFIFO_RD0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define IPP_PFIFO_RD1 (FZC_IPP + 0x00068UL) +#define IPP_PFIFO_RD1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define IPP_PFIFO_RD2 (FZC_IPP + 0x00070UL) +#define IPP_PFIFO_RD2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define IPP_PFIFO_RD3 (FZC_IPP + 0x00078UL) +#define IPP_PFIFO_RD3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define IPP_PFIFO_RD4 (FZC_IPP + 0x00080UL) +#define IPP_PFIFO_RD4_DATA 0x00000000ffffffffULL /* bits 145:128 */ + +#define IPP_PFIFO_WR0 (FZC_IPP + 0x00088UL) +#define IPP_PFIFO_WR0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define IPP_PFIFO_WR1 (FZC_IPP + 0x00090UL) +#define IPP_PFIFO_WR1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define IPP_PFIFO_WR2 (FZC_IPP + 0x00098UL) +#define IPP_PFIFO_WR2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define IPP_PFIFO_WR3 (FZC_IPP + 0x000a0UL) +#define IPP_PFIFO_WR3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define IPP_PFIFO_WR4 (FZC_IPP + 0x000a8UL) +#define IPP_PFIFO_WR4_DATA 0x00000000ffffffffULL /* bits 145:128 */ + +#define IPP_PFIFO_RD_PTR (FZC_IPP + 0x000b0UL) +#define IPP_PFIFO_RD_PTR_PTR 0x000000000000003fULL + +#define IPP_PFIFO_WR_PTR (FZC_IPP + 0x000b8UL) +#define IPP_PFIFO_WR_PTR_PTR 0x000000000000007fULL + +#define IPP_DFIFO_RD0 (FZC_IPP + 0x000c0UL) +#define IPP_DFIFO_RD0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define IPP_DFIFO_RD1 (FZC_IPP + 0x000c8UL) +#define IPP_DFIFO_RD1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define IPP_DFIFO_RD2 (FZC_IPP + 0x000d0UL) +#define IPP_DFIFO_RD2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define IPP_DFIFO_RD3 (FZC_IPP + 0x000d8UL) +#define IPP_DFIFO_RD3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define IPP_DFIFO_RD4 (FZC_IPP + 0x000e0UL) +#define IPP_DFIFO_RD4_DATA 0x00000000ffffffffULL /* bits 145:128 */ + +#define IPP_DFIFO_WR0 (FZC_IPP + 0x000e8UL) +#define IPP_DFIFO_WR0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define IPP_DFIFO_WR1 (FZC_IPP + 0x000f0UL) +#define IPP_DFIFO_WR1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define IPP_DFIFO_WR2 (FZC_IPP + 0x000f8UL) +#define IPP_DFIFO_WR2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define IPP_DFIFO_WR3 (FZC_IPP + 0x00100UL) +#define IPP_DFIFO_WR3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define IPP_DFIFO_WR4 (FZC_IPP + 0x00108UL) +#define IPP_DFIFO_WR4_DATA 0x00000000ffffffffULL /* bits 145:128 */ + +#define IPP_DFIFO_RD_PTR (FZC_IPP + 0x00110UL) +#define IPP_DFIFO_RD_PTR_PTR 0x0000000000000fffULL + +#define IPP_DFIFO_WR_PTR (FZC_IPP + 0x00118UL) +#define IPP_DFIFO_WR_PTR_PTR 0x0000000000000fffULL + +#define IPP_SM (FZC_IPP + 0x00120UL) +#define IPP_SM_SM 0x00000000ffffffffULL + +#define IPP_CS_STAT (FZC_IPP + 0x00128UL) +#define IPP_CS_STAT_BCYC_CNT 0x00000000ff000000ULL +#define IPP_CS_STAT_IP_LEN 0x0000000000fff000ULL +#define IPP_CS_STAT_CS_FAIL 0x0000000000000800ULL +#define IPP_CS_STAT_TERM 0x0000000000000400ULL +#define IPP_CS_STAT_BAD_NUM 0x0000000000000200ULL +#define IPP_CS_STAT_CS_STATE 0x00000000000001ffULL + +#define IPP_FFLP_CS_INFO (FZC_IPP + 0x00130UL) +#define IPP_FFLP_CS_INFO_PKT_ID 0x0000000000003c00ULL +#define IPP_FFLP_CS_INFO_L4_PROTO 0x0000000000000300ULL +#define IPP_FFLP_CS_INFO_V4_HD_LEN 0x00000000000000f0ULL +#define IPP_FFLP_CS_INFO_L3_VER 0x000000000000000cULL +#define IPP_FFLP_CS_INFO_L2_OP 0x0000000000000003ULL + +#define IPP_DBG_SEL (FZC_IPP + 0x00138UL) +#define IPP_DBG_SEL_SEL 0x000000000000000fULL + +#define IPP_DFIFO_ECC_SYND (FZC_IPP + 0x00140UL) +#define IPP_DFIFO_ECC_SYND_SYND 0x000000000000ffffULL + +#define IPP_DFIFO_EOP_RD_PTR (FZC_IPP + 0x00148UL) +#define IPP_DFIFO_EOP_RD_PTR_PTR 0x0000000000000fffULL + +#define IPP_ECC_CTL (FZC_IPP + 0x00150UL) +#define IPP_ECC_CTL_DIS_DBL 0x0000000080000000ULL +#define IPP_ECC_CTL_COR_DBL 0x0000000000020000ULL +#define IPP_ECC_CTL_COR_SNG 0x0000000000010000ULL +#define IPP_ECC_CTL_COR_ALL 0x0000000000000400ULL +#define IPP_ECC_CTL_COR_1 0x0000000000000100ULL +#define IPP_ECC_CTL_COR_LST 0x0000000000000004ULL +#define IPP_ECC_CTL_COR_SND 0x0000000000000002ULL +#define IPP_ECC_CTL_COR_FSR 0x0000000000000001ULL + +#define NIU_DFIFO_ENTRIES 1024 +#define ATLAS_P0_P1_DFIFO_ENTRIES 2048 +#define ATLAS_P2_P3_DFIFO_ENTRIES 1024 + +#define ZCP_CFIG (FZC_ZCP + 0x00000UL) +#define ZCP_CFIG_ZCP_32BIT_MODE 0x0000000001000000ULL +#define ZCP_CFIG_ZCP_DEBUG_SEL 0x0000000000ff0000ULL +#define ZCP_CFIG_DMA_TH 0x000000000000ffe0ULL +#define ZCP_CFIG_ECC_CHK_DIS 0x0000000000000010ULL +#define ZCP_CFIG_PAR_CHK_DIS 0x0000000000000008ULL +#define ZCP_CFIG_DIS_BUFF_RSP_IF 0x0000000000000004ULL +#define ZCP_CFIG_DIS_BUFF_REQ_IF 0x0000000000000002ULL +#define ZCP_CFIG_ZC_ENABLE 0x0000000000000001ULL + +#define ZCP_INT_STAT (FZC_ZCP + 0x00008UL) +#define ZCP_INT_STAT_RRFIFO_UNDERRUN 0x0000000000008000ULL +#define ZCP_INT_STAT_RRFIFO_OVERRUN 0x0000000000004000ULL +#define ZCP_INT_STAT_RSPFIFO_UNCOR_ERR 0x0000000000001000ULL +#define ZCP_INT_STAT_BUFFER_OVERFLOW 0x0000000000000800ULL +#define ZCP_INT_STAT_STAT_TBL_PERR 0x0000000000000400ULL +#define ZCP_INT_STAT_DYN_TBL_PERR 0x0000000000000200ULL +#define ZCP_INT_STAT_BUF_TBL_PERR 0x0000000000000100ULL +#define ZCP_INT_STAT_TT_PROGRAM_ERR 0x0000000000000080ULL +#define ZCP_INT_STAT_RSP_TT_INDEX_ERR 0x0000000000000040ULL +#define ZCP_INT_STAT_SLV_TT_INDEX_ERR 0x0000000000000020ULL +#define ZCP_INT_STAT_ZCP_TT_INDEX_ERR 0x0000000000000010ULL +#define ZCP_INT_STAT_CFIFO_ECC3 0x0000000000000008ULL +#define ZCP_INT_STAT_CFIFO_ECC2 0x0000000000000004ULL +#define ZCP_INT_STAT_CFIFO_ECC1 0x0000000000000002ULL +#define ZCP_INT_STAT_CFIFO_ECC0 0x0000000000000001ULL +#define ZCP_INT_STAT_ALL 0x000000000000ffffULL + +#define ZCP_INT_MASK (FZC_ZCP + 0x00010UL) +#define ZCP_INT_MASK_RRFIFO_UNDERRUN 0x0000000000008000ULL +#define ZCP_INT_MASK_RRFIFO_OVERRUN 0x0000000000004000ULL +#define ZCP_INT_MASK_LOJ 0x0000000000002000ULL +#define ZCP_INT_MASK_RSPFIFO_UNCOR_ERR 0x0000000000001000ULL +#define ZCP_INT_MASK_BUFFER_OVERFLOW 0x0000000000000800ULL +#define ZCP_INT_MASK_STAT_TBL_PERR 0x0000000000000400ULL +#define ZCP_INT_MASK_DYN_TBL_PERR 0x0000000000000200ULL +#define ZCP_INT_MASK_BUF_TBL_PERR 0x0000000000000100ULL +#define ZCP_INT_MASK_TT_PROGRAM_ERR 0x0000000000000080ULL +#define ZCP_INT_MASK_RSP_TT_INDEX_ERR 0x0000000000000040ULL +#define ZCP_INT_MASK_SLV_TT_INDEX_ERR 0x0000000000000020ULL +#define ZCP_INT_MASK_ZCP_TT_INDEX_ERR 0x0000000000000010ULL +#define ZCP_INT_MASK_CFIFO_ECC3 0x0000000000000008ULL +#define ZCP_INT_MASK_CFIFO_ECC2 0x0000000000000004ULL +#define ZCP_INT_MASK_CFIFO_ECC1 0x0000000000000002ULL +#define ZCP_INT_MASK_CFIFO_ECC0 0x0000000000000001ULL +#define ZCP_INT_MASK_ALL 0x000000000000ffffULL + +#define BAM4BUF (FZC_ZCP + 0x00018UL) +#define BAM4BUF_LOJ 0x0000000080000000ULL +#define BAM4BUF_EN_CK 0x0000000040000000ULL +#define BAM4BUF_IDX_END0 0x000000003ff00000ULL +#define BAM4BUF_IDX_ST0 0x00000000000ffc00ULL +#define BAM4BUF_OFFSET0 0x00000000000003ffULL + +#define BAM8BUF (FZC_ZCP + 0x00020UL) +#define BAM8BUF_LOJ 0x0000000080000000ULL +#define BAM8BUF_EN_CK 0x0000000040000000ULL +#define BAM8BUF_IDX_END1 0x000000003ff00000ULL +#define BAM8BUF_IDX_ST1 0x00000000000ffc00ULL +#define BAM8BUF_OFFSET1 0x00000000000003ffULL + +#define BAM16BUF (FZC_ZCP + 0x00028UL) +#define BAM16BUF_LOJ 0x0000000080000000ULL +#define BAM16BUF_EN_CK 0x0000000040000000ULL +#define BAM16BUF_IDX_END2 0x000000003ff00000ULL +#define BAM16BUF_IDX_ST2 0x00000000000ffc00ULL +#define BAM16BUF_OFFSET2 0x00000000000003ffULL + +#define BAM32BUF (FZC_ZCP + 0x00030UL) +#define BAM32BUF_LOJ 0x0000000080000000ULL +#define BAM32BUF_EN_CK 0x0000000040000000ULL +#define BAM32BUF_IDX_END3 0x000000003ff00000ULL +#define BAM32BUF_IDX_ST3 0x00000000000ffc00ULL +#define BAM32BUF_OFFSET3 0x00000000000003ffULL + +#define DST4BUF (FZC_ZCP + 0x00038UL) +#define DST4BUF_DS_OFFSET0 0x00000000000003ffULL + +#define DST8BUF (FZC_ZCP + 0x00040UL) +#define DST8BUF_DS_OFFSET1 0x00000000000003ffULL + +#define DST16BUF (FZC_ZCP + 0x00048UL) +#define DST16BUF_DS_OFFSET2 0x00000000000003ffULL + +#define DST32BUF (FZC_ZCP + 0x00050UL) +#define DST32BUF_DS_OFFSET3 0x00000000000003ffULL + +#define ZCP_RAM_DATA0 (FZC_ZCP + 0x00058UL) +#define ZCP_RAM_DATA0_DAT0 0x00000000ffffffffULL + +#define ZCP_RAM_DATA1 (FZC_ZCP + 0x00060UL) +#define ZCP_RAM_DAT10_DAT1 0x00000000ffffffffULL + +#define ZCP_RAM_DATA2 (FZC_ZCP + 0x00068UL) +#define ZCP_RAM_DATA2_DAT2 0x00000000ffffffffULL + +#define ZCP_RAM_DATA3 (FZC_ZCP + 0x00070UL) +#define ZCP_RAM_DATA3_DAT3 0x00000000ffffffffULL + +#define ZCP_RAM_DATA4 (FZC_ZCP + 0x00078UL) +#define ZCP_RAM_DATA4_DAT4 0x00000000000000ffULL + +#define ZCP_RAM_BE (FZC_ZCP + 0x00080UL) +#define ZCP_RAM_BE_VAL 0x000000000001ffffULL + +#define ZCP_RAM_ACC (FZC_ZCP + 0x00088UL) +#define ZCP_RAM_ACC_BUSY 0x0000000080000000ULL +#define ZCP_RAM_ACC_READ 0x0000000040000000ULL +#define ZCP_RAM_ACC_WRITE 0x0000000000000000ULL +#define ZCP_RAM_ACC_LOJ 0x0000000020000000ULL +#define ZCP_RAM_ACC_ZFCID 0x000000001ffe0000ULL +#define ZCP_RAM_ACC_ZFCID_SHIFT 17 +#define ZCP_RAM_ACC_RAM_SEL 0x000000000001f000ULL +#define ZCP_RAM_ACC_RAM_SEL_SHIFT 12 +#define ZCP_RAM_ACC_CFIFOADDR 0x0000000000000fffULL +#define ZCP_RAM_ACC_CFIFOADDR_SHIFT 0 + +#define ZCP_RAM_SEL_BAM(INDEX) (0x00 + (INDEX)) +#define ZCP_RAM_SEL_TT_STATIC 0x08 +#define ZCP_RAM_SEL_TT_DYNAMIC 0x09 +#define ZCP_RAM_SEL_CFIFO(PORT) (0x10 + (PORT)) + +#define NIU_CFIFO_ENTRIES 1024 +#define ATLAS_P0_P1_CFIFO_ENTRIES 2048 +#define ATLAS_P2_P3_CFIFO_ENTRIES 1024 + +#define CHK_BIT_DATA (FZC_ZCP + 0x00090UL) +#define CHK_BIT_DATA_DATA 0x000000000000ffffULL + +#define RESET_CFIFO (FZC_ZCP + 0x00098UL) +#define RESET_CFIFO_RST(PORT) (0x1 << (PORT)) + +#define CFIFO_ECC(PORT) (FZC_ZCP + 0x000a0UL + (PORT) * 8UL) +#define CFIFO_ECC_DIS_DBLBIT_ERR 0x0000000080000000ULL +#define CFIFO_ECC_DBLBIT_ERR 0x0000000000020000ULL +#define CFIFO_ECC_SINGLEBIT_ERR 0x0000000000010000ULL +#define CFIFO_ECC_ALL_PKT 0x0000000000000400ULL +#define CFIFO_ECC_LAST_LINE 0x0000000000000004ULL +#define CFIFO_ECC_2ND_LINE 0x0000000000000002ULL +#define CFIFO_ECC_1ST_LINE 0x0000000000000001ULL + +#define ZCP_TRAINING_VECTOR (FZC_ZCP + 0x000c0UL) +#define ZCP_TRAINING_VECTOR_VECTOR 0x00000000ffffffffULL + +#define ZCP_STATE_MACHINE (FZC_ZCP + 0x000c8UL) +#define ZCP_STATE_MACHINE_SM 0x00000000ffffffffULL + +/* Same bits as ZCP_INT_STAT */ +#define ZCP_INT_STAT_TEST (FZC_ZCP + 0x00108UL) + +#define RXDMA_CFIG1(IDX) (DMC + 0x00000UL + (IDX) * 0x200UL) +#define RXDMA_CFIG1_EN 0x0000000080000000ULL +#define RXDMA_CFIG1_RST 0x0000000040000000ULL +#define RXDMA_CFIG1_QST 0x0000000020000000ULL +#define RXDMA_CFIG1_MBADDR_H 0x0000000000000fffULL /* mboxaddr 43:32 */ + +#define RXDMA_CFIG2(IDX) (DMC + 0x00008UL + (IDX) * 0x200UL) +#define RXDMA_CFIG2_MBADDR_L 0x00000000ffffffc0ULL /* mboxaddr 31:6 */ +#define RXDMA_CFIG2_OFFSET 0x0000000000000006ULL +#define RXDMA_CFIG2_OFFSET_SHIFT 1 +#define RXDMA_CFIG2_FULL_HDR 0x0000000000000001ULL + +#define RBR_CFIG_A(IDX) (DMC + 0x00010UL + (IDX) * 0x200UL) +#define RBR_CFIG_A_LEN 0xffff000000000000ULL +#define RBR_CFIG_A_LEN_SHIFT 48 +#define RBR_CFIG_A_STADDR_BASE 0x00000ffffffc0000ULL +#define RBR_CFIG_A_STADDR 0x000000000003ffc0ULL + +#define RBR_CFIG_B(IDX) (DMC + 0x00018UL + (IDX) * 0x200UL) +#define RBR_CFIG_B_BLKSIZE 0x0000000003000000ULL +#define RBR_CFIG_B_BLKSIZE_SHIFT 24 +#define RBR_CFIG_B_VLD2 0x0000000000800000ULL +#define RBR_CFIG_B_BUFSZ2 0x0000000000030000ULL +#define RBR_CFIG_B_BUFSZ2_SHIFT 16 +#define RBR_CFIG_B_VLD1 0x0000000000008000ULL +#define RBR_CFIG_B_BUFSZ1 0x0000000000000300ULL +#define RBR_CFIG_B_BUFSZ1_SHIFT 8 +#define RBR_CFIG_B_VLD0 0x0000000000000080ULL +#define RBR_CFIG_B_BUFSZ0 0x0000000000000003ULL +#define RBR_CFIG_B_BUFSZ0_SHIFT 0 + +#define RBR_BLKSIZE_4K 0x0 +#define RBR_BLKSIZE_8K 0x1 +#define RBR_BLKSIZE_16K 0x2 +#define RBR_BLKSIZE_32K 0x3 +#define RBR_BUFSZ2_2K 0x0 +#define RBR_BUFSZ2_4K 0x1 +#define RBR_BUFSZ2_8K 0x2 +#define RBR_BUFSZ2_16K 0x3 +#define RBR_BUFSZ1_1K 0x0 +#define RBR_BUFSZ1_2K 0x1 +#define RBR_BUFSZ1_4K 0x2 +#define RBR_BUFSZ1_8K 0x3 +#define RBR_BUFSZ0_256 0x0 +#define RBR_BUFSZ0_512 0x1 +#define RBR_BUFSZ0_1K 0x2 +#define RBR_BUFSZ0_2K 0x3 + +#define RBR_KICK(IDX) (DMC + 0x00020UL + (IDX) * 0x200UL) +#define RBR_KICK_BKADD 0x000000000000ffffULL + +#define RBR_STAT(IDX) (DMC + 0x00028UL + (IDX) * 0x200UL) +#define RBR_STAT_QLEN 0x000000000000ffffULL + +#define RBR_HDH(IDX) (DMC + 0x00030UL + (IDX) * 0x200UL) +#define RBR_HDH_HEAD_H 0x0000000000000fffULL + +#define RBR_HDL(IDX) (DMC + 0x00038UL + (IDX) * 0x200UL) +#define RBR_HDL_HEAD_L 0x00000000fffffffcULL + +#define RCRCFIG_A(IDX) (DMC + 0x00040UL + (IDX) * 0x200UL) +#define RCRCFIG_A_LEN 0xffff000000000000ULL +#define RCRCFIG_A_LEN_SHIFT 48 +#define RCRCFIG_A_STADDR_BASE 0x00000ffffff80000ULL +#define RCRCFIG_A_STADDR 0x000000000007ffc0ULL + +#define RCRCFIG_B(IDX) (DMC + 0x00048UL + (IDX) * 0x200UL) +#define RCRCFIG_B_PTHRES 0x00000000ffff0000ULL +#define RCRCFIG_B_PTHRES_SHIFT 16 +#define RCRCFIG_B_ENTOUT 0x0000000000008000ULL +#define RCRCFIG_B_TIMEOUT 0x000000000000003fULL +#define RCRCFIG_B_TIMEOUT_SHIFT 0 + +#define RCRSTAT_A(IDX) (DMC + 0x00050UL + (IDX) * 0x200UL) +#define RCRSTAT_A_QLEN 0x000000000000ffffULL + +#define RCRSTAT_B(IDX) (DMC + 0x00058UL + (IDX) * 0x200UL) +#define RCRSTAT_B_TIPTR_H 0x0000000000000fffULL + +#define RCRSTAT_C(IDX) (DMC + 0x00060UL + (IDX) * 0x200UL) +#define RCRSTAT_C_TIPTR_L 0x00000000fffffff8ULL + +#define RX_DMA_CTL_STAT(IDX) (DMC + 0x00070UL + (IDX) * 0x200UL) +#define RX_DMA_CTL_STAT_RBR_TMOUT 0x0020000000000000ULL +#define RX_DMA_CTL_STAT_RSP_CNT_ERR 0x0010000000000000ULL +#define RX_DMA_CTL_STAT_BYTE_EN_BUS 0x0008000000000000ULL +#define RX_DMA_CTL_STAT_RSP_DAT_ERR 0x0004000000000000ULL +#define RX_DMA_CTL_STAT_RCR_ACK_ERR 0x0002000000000000ULL +#define RX_DMA_CTL_STAT_DC_FIFO_ERR 0x0001000000000000ULL +#define RX_DMA_CTL_STAT_MEX 0x0000800000000000ULL +#define RX_DMA_CTL_STAT_RCRTHRES 0x0000400000000000ULL +#define RX_DMA_CTL_STAT_RCRTO 0x0000200000000000ULL +#define RX_DMA_CTL_STAT_RCR_SHA_PAR 0x0000100000000000ULL +#define RX_DMA_CTL_STAT_RBR_PRE_PAR 0x0000080000000000ULL +#define RX_DMA_CTL_STAT_PORT_DROP_PKT 0x0000040000000000ULL +#define RX_DMA_CTL_STAT_WRED_DROP 0x0000020000000000ULL +#define RX_DMA_CTL_STAT_RBR_PRE_EMTY 0x0000010000000000ULL +#define RX_DMA_CTL_STAT_RCRSHADOW_FULL 0x0000008000000000ULL +#define RX_DMA_CTL_STAT_CONFIG_ERR 0x0000004000000000ULL +#define RX_DMA_CTL_STAT_RCRINCON 0x0000002000000000ULL +#define RX_DMA_CTL_STAT_RCRFULL 0x0000001000000000ULL +#define RX_DMA_CTL_STAT_RBR_EMPTY 0x0000000800000000ULL +#define RX_DMA_CTL_STAT_RBRFULL 0x0000000400000000ULL +#define RX_DMA_CTL_STAT_RBRLOGPAGE 0x0000000200000000ULL +#define RX_DMA_CTL_STAT_CFIGLOGPAGE 0x0000000100000000ULL +#define RX_DMA_CTL_STAT_PTRREAD 0x00000000ffff0000ULL +#define RX_DMA_CTL_STAT_PTRREAD_SHIFT 16 +#define RX_DMA_CTL_STAT_PKTREAD 0x000000000000ffffULL +#define RX_DMA_CTL_STAT_PKTREAD_SHIFT 0 + +#define RX_DMA_CTL_STAT_CHAN_FATAL (RX_DMA_CTL_STAT_RBR_TMOUT | \ + RX_DMA_CTL_STAT_RSP_CNT_ERR | \ + RX_DMA_CTL_STAT_BYTE_EN_BUS | \ + RX_DMA_CTL_STAT_RSP_DAT_ERR | \ + RX_DMA_CTL_STAT_RCR_ACK_ERR | \ + RX_DMA_CTL_STAT_RCR_SHA_PAR | \ + RX_DMA_CTL_STAT_RBR_PRE_PAR | \ + RX_DMA_CTL_STAT_CONFIG_ERR | \ + RX_DMA_CTL_STAT_RCRINCON | \ + RX_DMA_CTL_STAT_RCRFULL | \ + RX_DMA_CTL_STAT_RBRFULL | \ + RX_DMA_CTL_STAT_RBRLOGPAGE | \ + RX_DMA_CTL_STAT_CFIGLOGPAGE) + +#define RX_DMA_CTL_STAT_PORT_FATAL (RX_DMA_CTL_STAT_DC_FIFO_ERR) + +#define RX_DMA_CTL_WRITE_CLEAR_ERRS (RX_DMA_CTL_STAT_RBR_EMPTY | \ + RX_DMA_CTL_STAT_RCRSHADOW_FULL | \ + RX_DMA_CTL_STAT_RBR_PRE_EMTY | \ + RX_DMA_CTL_STAT_WRED_DROP | \ + RX_DMA_CTL_STAT_PORT_DROP_PKT | \ + RX_DMA_CTL_STAT_RCRTO | \ + RX_DMA_CTL_STAT_RCRTHRES | \ + RX_DMA_CTL_STAT_DC_FIFO_ERR) + +#define RCR_FLSH(IDX) (DMC + 0x00078UL + (IDX) * 0x200UL) +#define RCR_FLSH_FLSH 0x0000000000000001ULL + +#define RXMISC(IDX) (DMC + 0x00090UL + (IDX) * 0x200UL) +#define RXMISC_OFLOW 0x0000000000010000ULL +#define RXMISC_COUNT 0x000000000000ffffULL + +#define RX_DMA_CTL_STAT_DBG(IDX) (DMC + 0x00098UL + (IDX) * 0x200UL) +#define RX_DMA_CTL_STAT_DBG_RBR_TMOUT 0x0020000000000000ULL +#define RX_DMA_CTL_STAT_DBG_RSP_CNT_ERR 0x0010000000000000ULL +#define RX_DMA_CTL_STAT_DBG_BYTE_EN_BUS 0x0008000000000000ULL +#define RX_DMA_CTL_STAT_DBG_RSP_DAT_ERR 0x0004000000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCR_ACK_ERR 0x0002000000000000ULL +#define RX_DMA_CTL_STAT_DBG_DC_FIFO_ERR 0x0001000000000000ULL +#define RX_DMA_CTL_STAT_DBG_MEX 0x0000800000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRTHRES 0x0000400000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRTO 0x0000200000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCR_SHA_PAR 0x0000100000000000ULL +#define RX_DMA_CTL_STAT_DBG_RBR_PRE_PAR 0x0000080000000000ULL +#define RX_DMA_CTL_STAT_DBG_PORT_DROP_PKT 0x0000040000000000ULL +#define RX_DMA_CTL_STAT_DBG_WRED_DROP 0x0000020000000000ULL +#define RX_DMA_CTL_STAT_DBG_RBR_PRE_EMTY 0x0000010000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRSHADOW_FULL 0x0000008000000000ULL +#define RX_DMA_CTL_STAT_DBG_CONFIG_ERR 0x0000004000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRINCON 0x0000002000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRFULL 0x0000001000000000ULL +#define RX_DMA_CTL_STAT_DBG_RBR_EMPTY 0x0000000800000000ULL +#define RX_DMA_CTL_STAT_DBG_RBRFULL 0x0000000400000000ULL +#define RX_DMA_CTL_STAT_DBG_RBRLOGPAGE 0x0000000200000000ULL +#define RX_DMA_CTL_STAT_DBG_CFIGLOGPAGE 0x0000000100000000ULL +#define RX_DMA_CTL_STAT_DBG_PTRREAD 0x00000000ffff0000ULL +#define RX_DMA_CTL_STAT_DBG_PKTREAD 0x000000000000ffffULL + +#define RX_DMA_ENT_MSK(IDX) (DMC + 0x00068UL + (IDX) * 0x200UL) +#define RX_DMA_ENT_MSK_RBR_TMOUT 0x0000000000200000ULL +#define RX_DMA_ENT_MSK_RSP_CNT_ERR 0x0000000000100000ULL +#define RX_DMA_ENT_MSK_BYTE_EN_BUS 0x0000000000080000ULL +#define RX_DMA_ENT_MSK_RSP_DAT_ERR 0x0000000000040000ULL +#define RX_DMA_ENT_MSK_RCR_ACK_ERR 0x0000000000020000ULL +#define RX_DMA_ENT_MSK_DC_FIFO_ERR 0x0000000000010000ULL +#define RX_DMA_ENT_MSK_RCRTHRES 0x0000000000004000ULL +#define RX_DMA_ENT_MSK_RCRTO 0x0000000000002000ULL +#define RX_DMA_ENT_MSK_RCR_SHA_PAR 0x0000000000001000ULL +#define RX_DMA_ENT_MSK_RBR_PRE_PAR 0x0000000000000800ULL +#define RX_DMA_ENT_MSK_PORT_DROP_PKT 0x0000000000000400ULL +#define RX_DMA_ENT_MSK_WRED_DROP 0x0000000000000200ULL +#define RX_DMA_ENT_MSK_RBR_PRE_EMTY 0x0000000000000100ULL +#define RX_DMA_ENT_MSK_RCR_SHADOW_FULL 0x0000000000000080ULL +#define RX_DMA_ENT_MSK_CONFIG_ERR 0x0000000000000040ULL +#define RX_DMA_ENT_MSK_RCRINCON 0x0000000000000020ULL +#define RX_DMA_ENT_MSK_RCRFULL 0x0000000000000010ULL +#define RX_DMA_ENT_MSK_RBR_EMPTY 0x0000000000000008ULL +#define RX_DMA_ENT_MSK_RBRFULL 0x0000000000000004ULL +#define RX_DMA_ENT_MSK_RBRLOGPAGE 0x0000000000000002ULL +#define RX_DMA_ENT_MSK_CFIGLOGPAGE 0x0000000000000001ULL +#define RX_DMA_ENT_MSK_ALL 0x00000000003f7fffULL + +#define TX_RNG_CFIG(IDX) (DMC + 0x40000UL + (IDX) * 0x200UL) +#define TX_RNG_CFIG_LEN 0x1fff000000000000ULL +#define TX_RNG_CFIG_LEN_SHIFT 48 +#define TX_RNG_CFIG_STADDR_BASE 0x00000ffffff80000ULL +#define TX_RNG_CFIG_STADDR 0x000000000007ffc0ULL + +#define TX_RING_HDL(IDX) (DMC + 0x40010UL + (IDX) * 0x200UL) +#define TX_RING_HDL_WRAP 0x0000000000080000ULL +#define TX_RING_HDL_HEAD 0x000000000007fff8ULL +#define TX_RING_HDL_HEAD_SHIFT 3 + +#define TX_RING_KICK(IDX) (DMC + 0x40018UL + (IDX) * 0x200UL) +#define TX_RING_KICK_WRAP 0x0000000000080000ULL +#define TX_RING_KICK_TAIL 0x000000000007fff8ULL + +#define TX_ENT_MSK(IDX) (DMC + 0x40020UL + (IDX) * 0x200UL) +#define TX_ENT_MSK_MK 0x0000000000008000ULL +#define TX_ENT_MSK_MBOX_ERR 0x0000000000000080ULL +#define TX_ENT_MSK_PKT_SIZE_ERR 0x0000000000000040ULL +#define TX_ENT_MSK_TX_RING_OFLOW 0x0000000000000020ULL +#define TX_ENT_MSK_PREF_BUF_ECC_ERR 0x0000000000000010ULL +#define TX_ENT_MSK_NACK_PREF 0x0000000000000008ULL +#define TX_ENT_MSK_NACK_PKT_RD 0x0000000000000004ULL +#define TX_ENT_MSK_CONF_PART_ERR 0x0000000000000002ULL +#define TX_ENT_MSK_PKT_PRT_ERR 0x0000000000000001ULL + +#define TX_CS(IDX) (DMC + 0x40028UL + (IDX)*0x200UL) +#define TX_CS_PKT_CNT 0x0fff000000000000ULL +#define TX_CS_PKT_CNT_SHIFT 48 +#define TX_CS_LASTMARK 0x00000fff00000000ULL +#define TX_CS_LASTMARK_SHIFT 32 +#define TX_CS_RST 0x0000000080000000ULL +#define TX_CS_RST_STATE 0x0000000040000000ULL +#define TX_CS_MB 0x0000000020000000ULL +#define TX_CS_STOP_N_GO 0x0000000010000000ULL +#define TX_CS_SNG_STATE 0x0000000008000000ULL +#define TX_CS_MK 0x0000000000008000ULL +#define TX_CS_MMK 0x0000000000004000ULL +#define TX_CS_MBOX_ERR 0x0000000000000080ULL +#define TX_CS_PKT_SIZE_ERR 0x0000000000000040ULL +#define TX_CS_TX_RING_OFLOW 0x0000000000000020ULL +#define TX_CS_PREF_BUF_PAR_ERR 0x0000000000000010ULL +#define TX_CS_NACK_PREF 0x0000000000000008ULL +#define TX_CS_NACK_PKT_RD 0x0000000000000004ULL +#define TX_CS_CONF_PART_ERR 0x0000000000000002ULL +#define TX_CS_PKT_PRT_ERR 0x0000000000000001ULL + +#define TXDMA_MBH(IDX) (DMC + 0x40030UL + (IDX) * 0x200UL) +#define TXDMA_MBH_MBADDR 0x0000000000000fffULL + +#define TXDMA_MBL(IDX) (DMC + 0x40038UL + (IDX) * 0x200UL) +#define TXDMA_MBL_MBADDR 0x00000000ffffffc0ULL + +#define TX_DMA_PRE_ST(IDX) (DMC + 0x40040UL + (IDX) * 0x200UL) +#define TX_DMA_PRE_ST_SHADOW_HD 0x000000000007ffffULL + +#define TX_RNG_ERR_LOGH(IDX) (DMC + 0x40048UL + (IDX) * 0x200UL) +#define TX_RNG_ERR_LOGH_ERR 0x0000000080000000ULL +#define TX_RNG_ERR_LOGH_MERR 0x0000000040000000ULL +#define TX_RNG_ERR_LOGH_ERRCODE 0x0000000038000000ULL +#define TX_RNG_ERR_LOGH_ERRADDR 0x0000000000000fffULL + +#define TX_RNG_ERR_LOGL(IDX) (DMC + 0x40050UL + (IDX) * 0x200UL) +#define TX_RNG_ERR_LOGL_ERRADDR 0x00000000ffffffffULL + +#define TDMC_INTR_DBG(IDX) (DMC + 0x40060UL + (IDX) * 0x200UL) +#define TDMC_INTR_DBG_MK 0x0000000000008000ULL +#define TDMC_INTR_DBG_MBOX_ERR 0x0000000000000080ULL +#define TDMC_INTR_DBG_PKT_SIZE_ERR 0x0000000000000040ULL +#define TDMC_INTR_DBG_TX_RING_OFLOW 0x0000000000000020ULL +#define TDMC_INTR_DBG_PREF_BUF_PAR_ERR 0x0000000000000010ULL +#define TDMC_INTR_DBG_NACK_PREF 0x0000000000000008ULL +#define TDMC_INTR_DBG_NACK_PKT_RD 0x0000000000000004ULL +#define TDMC_INTR_DBG_CONF_PART_ERR 0x0000000000000002ULL +#define TDMC_INTR_DBG_PKT_PART_ERR 0x0000000000000001ULL + +#define TX_CS_DBG(IDX) (DMC + 0x40068UL + (IDX) * 0x200UL) +#define TX_CS_DBG_PKT_CNT 0x0fff000000000000ULL + +#define TDMC_INJ_PAR_ERR(IDX) (DMC + 0x45040UL + (IDX) * 0x200UL) +#define TDMC_INJ_PAR_ERR_VAL 0x000000000000ffffULL + +#define TDMC_DBG_SEL(IDX) (DMC + 0x45080UL + (IDX) * 0x200UL) +#define TDMC_DBG_SEL_DBG_SEL 0x000000000000003fULL + +#define TDMC_TRAINING_VECTOR(IDX) (DMC + 0x45088UL + (IDX) * 0x200UL) +#define TDMC_TRAINING_VECTOR_VEC 0x00000000ffffffffULL + +#define TXC_DMA_MAX(CHAN) (FZC_TXC + 0x00000UL + (CHAN)*0x1000UL) +#define TXC_DMA_MAX_LEN(CHAN) (FZC_TXC + 0x00008UL + (CHAN)*0x1000UL) + +#define TXC_CONTROL (FZC_TXC + 0x20000UL) +#define TXC_CONTROL_ENABLE 0x0000000000000010ULL +#define TXC_CONTROL_PORT_ENABLE(X) (1 << (X)) + +#define TXC_TRAINING_VEC (FZC_TXC + 0x20008UL) +#define TXC_TRAINING_VEC_MASK 0x00000000ffffffffULL + +#define TXC_DEBUG (FZC_TXC + 0x20010UL) +#define TXC_DEBUG_SELECT 0x000000000000003fULL + +#define TXC_MAX_REORDER (FZC_TXC + 0x20018UL) +#define TXC_MAX_REORDER_PORT3 0x000000000f000000ULL +#define TXC_MAX_REORDER_PORT2 0x00000000000f0000ULL +#define TXC_MAX_REORDER_PORT1 0x0000000000000f00ULL +#define TXC_MAX_REORDER_PORT0 0x000000000000000fULL + +#define TXC_PORT_CTL(PORT) (FZC_TXC + 0x20020UL + (PORT)*0x100UL) +#define TXC_PORT_CTL_CLR_ALL_STAT 0x0000000000000001ULL + +#define TXC_PKT_STUFFED(PORT) (FZC_TXC + 0x20030UL + (PORT)*0x100UL) +#define TXC_PKT_STUFFED_PP_REORDER 0x00000000ffff0000ULL +#define TXC_PKT_STUFFED_PP_PACKETASSY 0x000000000000ffffULL + +#define TXC_PKT_XMIT(PORT) (FZC_TXC + 0x20038UL + (PORT)*0x100UL) +#define TXC_PKT_XMIT_BYTES 0x00000000ffff0000ULL +#define TXC_PKT_XMIT_PKTS 0x000000000000ffffULL + +#define TXC_ROECC_CTL(PORT) (FZC_TXC + 0x20040UL + (PORT)*0x100UL) +#define TXC_ROECC_CTL_DISABLE_UE 0x0000000080000000ULL +#define TXC_ROECC_CTL_DBL_BIT_ERR 0x0000000000020000ULL +#define TXC_ROECC_CTL_SNGL_BIT_ERR 0x0000000000010000ULL +#define TXC_ROECC_CTL_ALL_PKTS 0x0000000000000400ULL +#define TXC_ROECC_CTL_ALT_PKTS 0x0000000000000200ULL +#define TXC_ROECC_CTL_ONE_PKT_ONLY 0x0000000000000100ULL +#define TXC_ROECC_CTL_LST_PKT_LINE 0x0000000000000004ULL +#define TXC_ROECC_CTL_2ND_PKT_LINE 0x0000000000000002ULL +#define TXC_ROECC_CTL_1ST_PKT_LINE 0x0000000000000001ULL + +#define TXC_ROECC_ST(PORT) (FZC_TXC + 0x20048UL + (PORT)*0x100UL) +#define TXC_ROECC_CLR_ST 0x0000000080000000ULL +#define TXC_ROECC_CE 0x0000000000020000ULL +#define TXC_ROECC_UE 0x0000000000010000ULL +#define TXC_ROECC_ST_ECC_ADDR 0x00000000000003ffULL + +#define TXC_RO_DATA0(PORT) (FZC_TXC + 0x20050UL + (PORT)*0x100UL) +#define TXC_RO_DATA0_DATA0 0x00000000ffffffffULL /* bits 31:0 */ + +#define TXC_RO_DATA1(PORT) (FZC_TXC + 0x20058UL + (PORT)*0x100UL) +#define TXC_RO_DATA1_DATA1 0x00000000ffffffffULL /* bits 63:32 */ + +#define TXC_RO_DATA2(PORT) (FZC_TXC + 0x20060UL + (PORT)*0x100UL) +#define TXC_RO_DATA2_DATA2 0x00000000ffffffffULL /* bits 95:64 */ + +#define TXC_RO_DATA3(PORT) (FZC_TXC + 0x20068UL + (PORT)*0x100UL) +#define TXC_RO_DATA3_DATA3 0x00000000ffffffffULL /* bits 127:96 */ + +#define TXC_RO_DATA4(PORT) (FZC_TXC + 0x20070UL + (PORT)*0x100UL) +#define TXC_RO_DATA4_DATA4 0x0000000000ffffffULL /* bits 151:128 */ + +#define TXC_SFECC_CTL(PORT) (FZC_TXC + 0x20078UL + (PORT)*0x100UL) +#define TXC_SFECC_CTL_DISABLE_UE 0x0000000080000000ULL +#define TXC_SFECC_CTL_DBL_BIT_ERR 0x0000000000020000ULL +#define TXC_SFECC_CTL_SNGL_BIT_ERR 0x0000000000010000ULL +#define TXC_SFECC_CTL_ALL_PKTS 0x0000000000000400ULL +#define TXC_SFECC_CTL_ALT_PKTS 0x0000000000000200ULL +#define TXC_SFECC_CTL_ONE_PKT_ONLY 0x0000000000000100ULL +#define TXC_SFECC_CTL_LST_PKT_LINE 0x0000000000000004ULL +#define TXC_SFECC_CTL_2ND_PKT_LINE 0x0000000000000002ULL +#define TXC_SFECC_CTL_1ST_PKT_LINE 0x0000000000000001ULL + +#define TXC_SFECC_ST(PORT) (FZC_TXC + 0x20080UL + (PORT)*0x100UL) +#define TXC_SFECC_ST_CLR_ST 0x0000000080000000ULL +#define TXC_SFECC_ST_CE 0x0000000000020000ULL +#define TXC_SFECC_ST_UE 0x0000000000010000ULL +#define TXC_SFECC_ST_ECC_ADDR 0x00000000000003ffULL + +#define TXC_SF_DATA0(PORT) (FZC_TXC + 0x20088UL + (PORT)*0x100UL) +#define TXC_SF_DATA0_DATA0 0x00000000ffffffffULL /* bits 31:0 */ + +#define TXC_SF_DATA1(PORT) (FZC_TXC + 0x20090UL + (PORT)*0x100UL) +#define TXC_SF_DATA1_DATA1 0x00000000ffffffffULL /* bits 63:32 */ + +#define TXC_SF_DATA2(PORT) (FZC_TXC + 0x20098UL + (PORT)*0x100UL) +#define TXC_SF_DATA2_DATA2 0x00000000ffffffffULL /* bits 95:64 */ + +#define TXC_SF_DATA3(PORT) (FZC_TXC + 0x200a0UL + (PORT)*0x100UL) +#define TXC_SF_DATA3_DATA3 0x00000000ffffffffULL /* bits 127:96 */ + +#define TXC_SF_DATA4(PORT) (FZC_TXC + 0x200a8UL + (PORT)*0x100UL) +#define TXC_SF_DATA4_DATA4 0x0000000000ffffffULL /* bits 151:128 */ + +#define TXC_RO_TIDS(PORT) (FZC_TXC + 0x200b0UL + (PORT)*0x100UL) +#define TXC_RO_TIDS_IN_USE 0x00000000ffffffffULL + +#define TXC_RO_STATE0(PORT) (FZC_TXC + 0x200b8UL + (PORT)*0x100UL) +#define TXC_RO_STATE0_DUPLICATE_TID 0x00000000ffffffffULL + +#define TXC_RO_STATE1(PORT) (FZC_TXC + 0x200c0UL + (PORT)*0x100UL) +#define TXC_RO_STATE1_UNUSED_TID 0x00000000ffffffffULL + +#define TXC_RO_STATE2(PORT) (FZC_TXC + 0x200c8UL + (PORT)*0x100UL) +#define TXC_RO_STATE2_TRANS_TIMEOUT 0x00000000ffffffffULL + +#define TXC_RO_STATE3(PORT) (FZC_TXC + 0x200d0UL + (PORT)*0x100UL) +#define TXC_RO_STATE3_ENAB_SPC_WMARK 0x0000000080000000ULL +#define TXC_RO_STATE3_RO_SPC_WMARK 0x000000007fe00000ULL +#define TXC_RO_STATE3_ROFIFO_SPC_AVAIL 0x00000000001ff800ULL +#define TXC_RO_STATE3_ENAB_RO_WMARK 0x0000000000000100ULL +#define TXC_RO_STATE3_HIGH_RO_USED 0x00000000000000f0ULL +#define TXC_RO_STATE3_NUM_RO_USED 0x000000000000000fULL + +#define TXC_RO_CTL(PORT) (FZC_TXC + 0x200d8UL + (PORT)*0x100UL) +#define TXC_RO_CTL_CLR_FAIL_STATE 0x0000000080000000ULL +#define TXC_RO_CTL_RO_ADDR 0x000000000f000000ULL +#define TXC_RO_CTL_ADDR_FAILED 0x0000000000400000ULL +#define TXC_RO_CTL_DMA_FAILED 0x0000000000200000ULL +#define TXC_RO_CTL_LEN_FAILED 0x0000000000100000ULL +#define TXC_RO_CTL_CAPT_ADDR_FAILED 0x0000000000040000ULL +#define TXC_RO_CTL_CAPT_DMA_FAILED 0x0000000000020000ULL +#define TXC_RO_CTL_CAPT_LEN_FAILED 0x0000000000010000ULL +#define TXC_RO_CTL_RO_STATE_RD_DONE 0x0000000000000080ULL +#define TXC_RO_CTL_RO_STATE_WR_DONE 0x0000000000000040ULL +#define TXC_RO_CTL_RO_STATE_RD 0x0000000000000020ULL +#define TXC_RO_CTL_RO_STATE_WR 0x0000000000000010ULL +#define TXC_RO_CTL_RO_STATE_ADDR 0x000000000000000fULL + +#define TXC_RO_ST_DATA0(PORT) (FZC_TXC + 0x200e0UL + (PORT)*0x100UL) +#define TXC_RO_ST_DATA0_DATA0 0x00000000ffffffffULL + +#define TXC_RO_ST_DATA1(PORT) (FZC_TXC + 0x200e8UL + (PORT)*0x100UL) +#define TXC_RO_ST_DATA1_DATA1 0x00000000ffffffffULL + +#define TXC_RO_ST_DATA2(PORT) (FZC_TXC + 0x200f0UL + (PORT)*0x100UL) +#define TXC_RO_ST_DATA2_DATA2 0x00000000ffffffffULL + +#define TXC_RO_ST_DATA3(PORT) (FZC_TXC + 0x200f8UL + (PORT)*0x100UL) +#define TXC_RO_ST_DATA3_DATA3 0x00000000ffffffffULL + +#define TXC_PORT_PACKET_REQ(PORT) (FZC_TXC + 0x20100UL + (PORT)*0x100UL) +#define TXC_PORT_PACKET_REQ_GATHER_REQ 0x00000000f0000000ULL +#define TXC_PORT_PACKET_REQ_PKT_REQ 0x000000000fff0000ULL +#define TXC_PORT_PACKET_REQ_PERR_ABRT 0x000000000000ffffULL + + /* bits are same as TXC_INT_STAT */ +#define TXC_INT_STAT_DBG (FZC_TXC + 0x20420UL) + +#define TXC_INT_STAT (FZC_TXC + 0x20428UL) +#define TXC_INT_STAT_VAL_SHIFT(PORT) ((PORT) * 8) +#define TXC_INT_STAT_VAL(PORT) (0x3f << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_SF_CE(PORT) (0x01 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_SF_UE(PORT) (0x02 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_RO_CE(PORT) (0x04 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_RO_UE(PORT) (0x08 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_REORDER_ERR(PORT) (0x10 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_PKTASM_DEAD(PORT) (0x20 << TXC_INT_STAT_VAL_SHIFT(PORT)) + +#define TXC_INT_MASK (FZC_TXC + 0x20430UL) +#define TXC_INT_MASK_VAL_SHIFT(PORT) ((PORT) * 8) +#define TXC_INT_MASK_VAL(PORT) (0x3f << TXC_INT_STAT_VAL_SHIFT(PORT)) + +#define TXC_INT_MASK_SF_CE 0x01 +#define TXC_INT_MASK_SF_UE 0x02 +#define TXC_INT_MASK_RO_CE 0x04 +#define TXC_INT_MASK_RO_UE 0x08 +#define TXC_INT_MASK_REORDER_ERR 0x10 +#define TXC_INT_MASK_PKTASM_DEAD 0x20 +#define TXC_INT_MASK_ALL 0x3f + +#define TXC_PORT_DMA(IDX) (FZC_TXC + 0x20028UL + (IDX)*0x100UL) + +#define ESPC_PIO_EN (FZC_PROM + 0x40000UL) +#define ESPC_PIO_EN_ENABLE 0x0000000000000001ULL + +#define ESPC_PIO_STAT (FZC_PROM + 0x40008UL) +#define ESPC_PIO_STAT_READ_START 0x0000000080000000ULL +#define ESPC_PIO_STAT_READ_END 0x0000000040000000ULL +#define ESPC_PIO_STAT_WRITE_INIT 0x0000000020000000ULL +#define ESPC_PIO_STAT_WRITE_END 0x0000000010000000ULL +#define ESPC_PIO_STAT_ADDR 0x0000000003ffff00ULL +#define ESPC_PIO_STAT_ADDR_SHIFT 8 +#define ESPC_PIO_STAT_DATA 0x00000000000000ffULL +#define ESPC_PIO_STAT_DATA_SHIFT 0 + +#define ESPC_NCR(IDX) (FZC_PROM + 0x40020UL + (IDX)*0x8UL) +#define ESPC_NCR_VAL 0x00000000ffffffffULL + +#define ESPC_MAC_ADDR0 ESPC_NCR(0) +#define ESPC_MAC_ADDR1 ESPC_NCR(1) +#define ESPC_NUM_PORTS_MACS ESPC_NCR(2) +#define ESPC_NUM_PORTS_MACS_VAL 0x00000000000000ffULL +#define ESPC_MOD_STR_LEN ESPC_NCR(4) +#define ESPC_MOD_STR_1 ESPC_NCR(5) +#define ESPC_MOD_STR_2 ESPC_NCR(6) +#define ESPC_MOD_STR_3 ESPC_NCR(7) +#define ESPC_MOD_STR_4 ESPC_NCR(8) +#define ESPC_MOD_STR_5 ESPC_NCR(9) +#define ESPC_MOD_STR_6 ESPC_NCR(10) +#define ESPC_MOD_STR_7 ESPC_NCR(11) +#define ESPC_MOD_STR_8 ESPC_NCR(12) +#define ESPC_BD_MOD_STR_LEN ESPC_NCR(13) +#define ESPC_BD_MOD_STR_1 ESPC_NCR(14) +#define ESPC_BD_MOD_STR_2 ESPC_NCR(15) +#define ESPC_BD_MOD_STR_3 ESPC_NCR(16) +#define ESPC_BD_MOD_STR_4 ESPC_NCR(17) + +#define ESPC_PHY_TYPE ESPC_NCR(18) +#define ESPC_PHY_TYPE_PORT0 0x00000000ff000000ULL +#define ESPC_PHY_TYPE_PORT0_SHIFT 24 +#define ESPC_PHY_TYPE_PORT1 0x0000000000ff0000ULL +#define ESPC_PHY_TYPE_PORT1_SHIFT 16 +#define ESPC_PHY_TYPE_PORT2 0x000000000000ff00ULL +#define ESPC_PHY_TYPE_PORT2_SHIFT 8 +#define ESPC_PHY_TYPE_PORT3 0x00000000000000ffULL +#define ESPC_PHY_TYPE_PORT3_SHIFT 0 + +#define ESPC_PHY_TYPE_1G_COPPER 3 +#define ESPC_PHY_TYPE_1G_FIBER 2 +#define ESPC_PHY_TYPE_10G_COPPER 1 +#define ESPC_PHY_TYPE_10G_FIBER 0 + +#define ESPC_MAX_FM_SZ ESPC_NCR(19) + +#define ESPC_INTR_NUM ESPC_NCR(20) +#define ESPC_INTR_NUM_PORT0 0x00000000ff000000ULL +#define ESPC_INTR_NUM_PORT1 0x0000000000ff0000ULL +#define ESPC_INTR_NUM_PORT2 0x000000000000ff00ULL +#define ESPC_INTR_NUM_PORT3 0x00000000000000ffULL + +#define ESPC_VER_IMGSZ ESPC_NCR(21) +#define ESPC_VER_IMGSZ_IMGSZ 0x00000000ffff0000ULL +#define ESPC_VER_IMGSZ_IMGSZ_SHIFT 16 +#define ESPC_VER_IMGSZ_VER 0x000000000000ffffULL +#define ESPC_VER_IMGSZ_VER_SHIFT 0 + +#define ESPC_CHKSUM ESPC_NCR(22) +#define ESPC_CHKSUM_SUM 0x00000000000000ffULL + +#define ESPC_EEPROM_SIZE 0x100000 + +#define CLASS_CODE_UNRECOG 0x00 +#define CLASS_CODE_DUMMY1 0x01 +#define CLASS_CODE_ETHERTYPE1 0x02 +#define CLASS_CODE_ETHERTYPE2 0x03 +#define CLASS_CODE_USER_PROG1 0x04 +#define CLASS_CODE_USER_PROG2 0x05 +#define CLASS_CODE_USER_PROG3 0x06 +#define CLASS_CODE_USER_PROG4 0x07 +#define CLASS_CODE_TCP_IPV4 0x08 +#define CLASS_CODE_UDP_IPV4 0x09 +#define CLASS_CODE_AH_ESP_IPV4 0x0a +#define CLASS_CODE_SCTP_IPV4 0x0b +#define CLASS_CODE_TCP_IPV6 0x0c +#define CLASS_CODE_UDP_IPV6 0x0d +#define CLASS_CODE_AH_ESP_IPV6 0x0e +#define CLASS_CODE_SCTP_IPV6 0x0f +#define CLASS_CODE_ARP 0x10 +#define CLASS_CODE_RARP 0x11 +#define CLASS_CODE_DUMMY2 0x12 +#define CLASS_CODE_DUMMY3 0x13 +#define CLASS_CODE_DUMMY4 0x14 +#define CLASS_CODE_DUMMY5 0x15 +#define CLASS_CODE_DUMMY6 0x16 +#define CLASS_CODE_DUMMY7 0x17 +#define CLASS_CODE_DUMMY8 0x18 +#define CLASS_CODE_DUMMY9 0x19 +#define CLASS_CODE_DUMMY10 0x1a +#define CLASS_CODE_DUMMY11 0x1b +#define CLASS_CODE_DUMMY12 0x1c +#define CLASS_CODE_DUMMY13 0x1d +#define CLASS_CODE_DUMMY14 0x1e +#define CLASS_CODE_DUMMY15 0x1f + +/* Logical devices and device groups */ +#define LDN_RXDMA(CHAN) (0 + (CHAN)) +#define LDN_RESV1(OFF) (16 + (OFF)) +#define LDN_TXDMA(CHAN) (32 + (CHAN)) +#define LDN_RESV2(OFF) (56 + (OFF)) +#define LDN_MIF 63 +#define LDN_MAC(PORT) (64 + (PORT)) +#define LDN_DEVICE_ERROR 68 +#define LDN_MAX LDN_DEVICE_ERROR + +#define NIU_LDG_MIN 0 +#define NIU_LDG_MAX 63 +#define NIU_NUM_LDG 64 +#define LDG_INVALID 0xff + +/* PHY stuff */ +#define NIU_PMA_PMD_DEV_ADDR 1 +#define NIU_PCS_DEV_ADDR 3 + +#define NIU_PHY_ID_MASK 0xfffff0f0 +#define NIU_PHY_ID_BCM8704 0x00206030 +#define NIU_PHY_ID_BCM5464R 0x002060b0 + +#define BCM8704_PMA_PMD_DEV_ADDR 1 +#define BCM8704_PCS_DEV_ADDR 2 +#define BCM8704_USER_DEV3_ADDR 3 +#define BCM8704_PHYXS_DEV_ADDR 4 +#define BCM8704_USER_DEV4_ADDR 4 + +#define BCM8704_PMD_RCV_SIGDET 0x000a +#define PMD_RCV_SIGDET_LANE3 0x0010 +#define PMD_RCV_SIGDET_LANE2 0x0008 +#define PMD_RCV_SIGDET_LANE1 0x0004 +#define PMD_RCV_SIGDET_LANE0 0x0002 +#define PMD_RCV_SIGDET_GLOBAL 0x0001 + +#define BCM8704_PCS_10G_R_STATUS 0x0020 +#define PCS_10G_R_STATUS_LINKSTAT 0x1000 +#define PCS_10G_R_STATUS_PRBS31_ABLE 0x0004 +#define PCS_10G_R_STATUS_HI_BER 0x0002 +#define PCS_10G_R_STATUS_BLK_LOCK 0x0001 + +#define BCM8704_USER_CONTROL 0xc800 +#define USER_CONTROL_OPTXENB_LVL 0x8000 +#define USER_CONTROL_OPTXRST_LVL 0x4000 +#define USER_CONTROL_OPBIASFLT_LVL 0x2000 +#define USER_CONTROL_OBTMPFLT_LVL 0x1000 +#define USER_CONTROL_OPPRFLT_LVL 0x0800 +#define USER_CONTROL_OPTXFLT_LVL 0x0400 +#define USER_CONTROL_OPRXLOS_LVL 0x0200 +#define USER_CONTROL_OPRXFLT_LVL 0x0100 +#define USER_CONTROL_OPTXON_LVL 0x0080 +#define USER_CONTROL_RES1 0x007f +#define USER_CONTROL_RES1_SHIFT 0 + +#define BCM8704_USER_ANALOG_CLK 0xc801 +#define BCM8704_USER_PMD_RX_CONTROL 0xc802 + +#define BCM8704_USER_PMD_TX_CONTROL 0xc803 +#define USER_PMD_TX_CTL_RES1 0xfe00 +#define USER_PMD_TX_CTL_XFP_CLKEN 0x0100 +#define USER_PMD_TX_CTL_TX_DAC_TXD 0x00c0 +#define USER_PMD_TX_CTL_TX_DAC_TXD_SH 6 +#define USER_PMD_TX_CTL_TX_DAC_TXCK 0x0030 +#define USER_PMD_TX_CTL_TX_DAC_TXCK_SH 4 +#define USER_PMD_TX_CTL_TSD_LPWREN 0x0008 +#define USER_PMD_TX_CTL_TSCK_LPWREN 0x0004 +#define USER_PMD_TX_CTL_CMU_LPWREN 0x0002 +#define USER_PMD_TX_CTL_SFIFORST 0x0001 + +#define BCM8704_USER_ANALOG_STATUS0 0xc804 +#define BCM8704_USER_OPT_DIGITAL_CTRL 0xc808 +#define BCM8704_USER_TX_ALARM_STATUS 0x9004 + +#define USER_ODIG_CTRL_FMODE 0x8000 +#define USER_ODIG_CTRL_TX_PDOWN 0x4000 +#define USER_ODIG_CTRL_RX_PDOWN 0x2000 +#define USER_ODIG_CTRL_EFILT_EN 0x1000 +#define USER_ODIG_CTRL_OPT_RST 0x0800 +#define USER_ODIG_CTRL_PCS_TIB 0x0400 +#define USER_ODIG_CTRL_PCS_RI 0x0200 +#define USER_ODIG_CTRL_RESV1 0x0180 +#define USER_ODIG_CTRL_GPIOS 0x0060 +#define USER_ODIG_CTRL_GPIOS_SHIFT 5 +#define USER_ODIG_CTRL_RESV2 0x0010 +#define USER_ODIG_CTRL_LB_ERR_DIS 0x0008 +#define USER_ODIG_CTRL_RESV3 0x0006 +#define USER_ODIG_CTRL_TXONOFF_PD_DIS 0x0001 + +#define BCM8704_PHYXS_XGXS_LANE_STAT 0x0018 +#define PHYXS_XGXS_LANE_STAT_ALINGED 0x1000 +#define PHYXS_XGXS_LANE_STAT_PATTEST 0x0800 +#define PHYXS_XGXS_LANE_STAT_MAGIC 0x0400 +#define PHYXS_XGXS_LANE_STAT_LANE3 0x0008 +#define PHYXS_XGXS_LANE_STAT_LANE2 0x0004 +#define PHYXS_XGXS_LANE_STAT_LANE1 0x0002 +#define PHYXS_XGXS_LANE_STAT_LANE0 0x0001 + +#define BCM5464R_AUX_CTL 24 +#define BCM5464R_AUX_CTL_EXT_LB 0x8000 +#define BCM5464R_AUX_CTL_EXT_PLEN 0x4000 +#define BCM5464R_AUX_CTL_ER1000 0x3000 +#define BCM5464R_AUX_CTL_ER1000_SHIFT 12 +#define BCM5464R_AUX_CTL_RESV1 0x0800 +#define BCM5464R_AUX_CTL_WRITE_1 0x0400 +#define BCM5464R_AUX_CTL_RESV2 0x0300 +#define BCM5464R_AUX_CTL_PRESP_DIS 0x0080 +#define BCM5464R_AUX_CTL_RESV3 0x0040 +#define BCM5464R_AUX_CTL_ER100 0x0030 +#define BCM5464R_AUX_CTL_ER100_SHIFT 4 +#define BCM5464R_AUX_CTL_DIAG_MODE 0x0008 +#define BCM5464R_AUX_CTL_SR_SEL 0x0007 +#define BCM5464R_AUX_CTL_SR_SEL_SHIFT 0 + +#define BCM5464R_CTRL1000_AS_MASTER 0x0800 +#define BCM5464R_CTRL1000_ENABLE_AS_MASTER 0x1000 + +#define RCR_ENTRY_MULTI 0x8000000000000000ULL +#define RCR_ENTRY_PKT_TYPE 0x6000000000000000ULL +#define RCR_ENTRY_PKT_TYPE_SHIFT 61 +#define RCR_ENTRY_ZERO_COPY 0x1000000000000000ULL +#define RCR_ENTRY_NOPORT 0x0800000000000000ULL +#define RCR_ENTRY_PROMISC 0x0400000000000000ULL +#define RCR_ENTRY_ERROR 0x0380000000000000ULL +#define RCR_ENTRY_DCF_ERR 0x0040000000000000ULL +#define RCR_ENTRY_L2_LEN 0x003fff0000000000ULL +#define RCR_ENTRY_L2_LEN_SHIFT 40 +#define RCR_ENTRY_PKTBUFSZ 0x000000c000000000ULL +#define RCR_ENTRY_PKTBUFSZ_SHIFT 38 +#define RCR_ENTRY_PKT_BUF_ADDR 0x0000003fffffffffULL /* bits 43:6 */ +#define RCR_ENTRY_PKT_BUF_ADDR_SHIFT 6 + +#define RCR_PKT_TYPE_OTHER 0x0 +#define RCR_PKT_TYPE_TCP 0x1 +#define RCR_PKT_TYPE_UDP 0x2 +#define RCR_PKT_TYPE_SCTP 0x3 + +#define NIU_RXPULL_MAX ETH_HLEN + +struct rx_pkt_hdr0 { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 inputport:2, + maccheck:1, + class:4; + u8 vlan:1, + llcsnap:1, + noport:1, + badip:1, + tcamhit:1, + tres:2, + tzfvld:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 class:4, + maccheck:1, + inputport:2; + u8 tzfvld:1, + tres:2, + tcamhit:1, + badip:1, + noport:1, + llcsnap:1, + vlan:1; +#endif +}; + +struct rx_pkt_hdr1 { + u8 hwrsvd1; + u8 tcammatch; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 hwrsvd2:2, + hashit:1, + exact:1, + hzfvld:1, + hashsidx:3; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 hashsidx:3, + hzfvld:1, + exact:1, + hashit:1, + hwrsvd2:2; +#endif + u8 zcrsvd; + + /* Bits 11:8 of zero copy flow ID. */ +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 hwrsvd3:4, zflowid0:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 zflowid0:4, hwrsvd3:4; +#endif + + /* Bits 7:0 of zero copy flow ID. */ + u8 zflowid1; + + /* Bits 15:8 of hash value, H2. */ + u8 hashval2_0; + + /* Bits 7:0 of hash value, H2. */ + u8 hashval2_1; + + /* Bits 19:16 of hash value, H1. */ +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 hwrsvd4:4, hashval1_0:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 hashval1_0:4, hwrsvd4:4; +#endif + + /* Bits 15:8 of hash value, H1. */ + u8 hashval1_1; + + /* Bits 7:0 of hash value, H1. */ + u8 hashval1_2; + + u8 usrdata_0; /* Bits 39:32 of user data. */ + u8 usrdata_1; /* Bits 31:24 of user data. */ + u8 usrdata_2; /* Bits 23:16 of user data. */ + u8 usrdata_3; /* Bits 15:8 of user data. */ + u8 usrdata_4; /* Bits 7:0 of user data. */ +}; + +struct tx_dma_mbox { + u64 tx_dma_pre_st; + u64 tx_cs; + u64 tx_ring_kick; + u64 tx_ring_hdl; + u64 resv1; + u32 tx_rng_err_logl; + u32 tx_rng_err_logh; + u64 resv2; + u64 resv3; +}; + +struct tx_pkt_hdr { + __le64 flags; +#define TXHDR_PAD 0x0000000000000007ULL +#define TXHDR_PAD_SHIFT 0 +#define TXHDR_LEN 0x000000003fff0000ULL +#define TXHDR_LEN_SHIFT 16 +#define TXHDR_L4STUFF 0x0000003f00000000ULL +#define TXHDR_L4STUFF_SHIFT 32 +#define TXHDR_L4START 0x00003f0000000000ULL +#define TXHDR_L4START_SHIFT 40 +#define TXHDR_L3START 0x000f000000000000ULL +#define TXHDR_L3START_SHIFT 48 +#define TXHDR_IHL 0x00f0000000000000ULL +#define TXHDR_IHL_SHIFT 52 +#define TXHDR_VLAN 0x0100000000000000ULL +#define TXHDR_LLC 0x0200000000000000ULL +#define TXHDR_IP_VER 0x2000000000000000ULL +#define TXHDR_CSUM_NONE 0x0000000000000000ULL +#define TXHDR_CSUM_TCP 0x4000000000000000ULL +#define TXHDR_CSUM_UDP 0x8000000000000000ULL +#define TXHDR_CSUM_SCTP 0xc000000000000000ULL + __le64 resv; +}; + +#define TX_DESC_SOP 0x8000000000000000ULL +#define TX_DESC_MARK 0x4000000000000000ULL +#define TX_DESC_NUM_PTR 0x3c00000000000000ULL +#define TX_DESC_NUM_PTR_SHIFT 58 +#define TX_DESC_TR_LEN 0x01fff00000000000ULL +#define TX_DESC_TR_LEN_SHIFT 44 +#define TX_DESC_SAD 0x00000fffffffffffULL +#define TX_DESC_SAD_SHIFT 0 + +struct tx_buff_info { + struct sk_buff *skb; + u64 mapping; +}; + +struct txdma_mailbox { + __le64 tx_dma_pre_st; + __le64 tx_cs; + __le64 tx_ring_kick; + __le64 tx_ring_hdl; + __le64 resv1; + __le32 tx_rng_err_logl; + __le32 tx_rng_err_logh; + __le64 resv2[2]; +} __attribute__((aligned(64))); + +#define MAX_TX_RING_SIZE 256 +#define MAX_TX_DESC_LEN 4076 + +struct tx_ring_info { + struct tx_buff_info tx_buffs[MAX_TX_RING_SIZE]; + struct niu *np; + u64 tx_cs; + int pending; + int prod; + int cons; + int wrap_bit; + u16 last_pkt_cnt; + u16 tx_channel; + u16 mark_counter; + u16 mark_freq; + u16 mark_pending; + u16 __pad; + struct txdma_mailbox *mbox; + __le64 *descr; + + u64 tx_packets; + u64 tx_bytes; + u64 tx_errors; + + u64 mbox_dma; + u64 descr_dma; + int max_burst; +}; + +#define NEXT_TX(tp, index) \ + (((index) + 1) < (tp)->pending ? ((index) + 1) : 0) + +static inline u32 niu_tx_avail(struct tx_ring_info *tp) +{ + return (tp->pending - + ((tp->prod - tp->cons) & (MAX_TX_RING_SIZE - 1))); +} + +struct rxdma_mailbox { + __le64 rx_dma_ctl_stat; + __le64 rbr_stat; + __le32 rbr_hdl; + __le32 rbr_hdh; + __le64 resv1; + __le32 rcrstat_c; + __le32 rcrstat_b; + __le64 rcrstat_a; + __le64 resv2[2]; +} __attribute__((aligned(64))); + +#define MAX_RBR_RING_SIZE 128 +#define MAX_RCR_RING_SIZE (MAX_RBR_RING_SIZE * 2) + +#define RBR_REFILL_MIN 16 + +#define RX_SKB_ALLOC_SIZE 128 + NET_IP_ALIGN + +struct rx_ring_info { + struct niu *np; + int rx_channel; + u16 rbr_block_size; + u16 rbr_blocks_per_page; + u16 rbr_sizes[4]; + unsigned int rcr_index; + unsigned int rcr_table_size; + unsigned int rbr_index; + unsigned int rbr_pending; + unsigned int rbr_refill_pending; + unsigned int rbr_kick_thresh; + unsigned int rbr_table_size; + struct page **rxhash; + struct rxdma_mailbox *mbox; + __le64 *rcr; + __le32 *rbr; +#define RBR_DESCR_ADDR_SHIFT 12 + + u64 rx_packets; + u64 rx_bytes; + u64 rx_dropped; + u64 rx_errors; + + u64 mbox_dma; + u64 rcr_dma; + u64 rbr_dma; + + /* WRED */ + int nonsyn_window; + int nonsyn_threshold; + int syn_window; + int syn_threshold; + + /* interrupt mitigation */ + int rcr_pkt_threshold; + int rcr_timeout; +}; + +#define NEXT_RCR(rp, index) \ + (((index) + 1) < (rp)->rcr_table_size ? ((index) + 1) : 0) +#define NEXT_RBR(rp, index) \ + (((index) + 1) < (rp)->rbr_table_size ? ((index) + 1) : 0) + +#define NIU_MAX_PORTS 4 +#define NIU_NUM_RXCHAN 16 +#define NIU_NUM_TXCHAN 24 +#define MAC_NUM_HASH 16 + +#define NIU_MAX_MTU 9216 + +#define NIU_VPD_MIN_MAJOR 3 +#define NIU_VPD_MIN_MINOR 4 + +#define NIU_VPD_MODEL_MAX 32 +#define NIU_VPD_BD_MODEL_MAX 16 +#define NIU_VPD_VERSION_MAX 64 +#define NIU_VPD_PHY_TYPE_MAX 8 + +struct niu_vpd { + char model[NIU_VPD_MODEL_MAX]; + char board_model[NIU_VPD_BD_MODEL_MAX]; + char version[NIU_VPD_VERSION_MAX]; + char phy_type[NIU_VPD_PHY_TYPE_MAX]; + u8 mac_num; + u8 __pad; + u8 local_mac[6]; + int fcode_major; + int fcode_minor; +}; + +struct niu_altmac_rdc { + u8 alt_mac_num; + u8 rdc_num; + u8 mac_pref; +}; + +struct niu_vlan_rdc { + u8 rdc_num; + u8 vlan_pref; +}; + +struct niu_classifier { + struct niu_altmac_rdc alt_mac_mappings[16]; + struct niu_vlan_rdc vlan_mappings[ENET_VLAN_TBL_NUM_ENTRIES]; + + u16 tcam_index; + u16 num_alt_mac_mappings; + + u32 h1_init; + u16 h2_init; +}; + +#define NIU_NUM_RDC_TABLES 8 +#define NIU_RDC_TABLE_SLOTS 16 + +struct rdc_table { + u8 rxdma_channel[NIU_RDC_TABLE_SLOTS]; +}; + +struct niu_rdc_tables { + struct rdc_table tables[NIU_NUM_RDC_TABLES]; + int first_table_num; + int num_tables; +}; + +#define PHY_TYPE_PMA_PMD 0 +#define PHY_TYPE_PCS 1 +#define PHY_TYPE_MII 2 +#define PHY_TYPE_MAX 3 + +struct phy_probe_info { + u32 phy_id[PHY_TYPE_MAX][NIU_MAX_PORTS]; + u8 phy_port[PHY_TYPE_MAX][NIU_MAX_PORTS]; + u8 cur[PHY_TYPE_MAX]; + + struct device_attribute phy_port_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS]; + struct device_attribute phy_type_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS]; + struct device_attribute phy_id_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS]; +}; + +struct niu_tcam_entry { + u64 key[4]; + u64 key_mask[4]; + u64 assoc_data; +}; + +struct device_node; +union niu_parent_id { + struct { + int domain; + int bus; + int device; + } pci; + struct device_node *of; +}; + +struct niu; +struct niu_parent { + struct platform_device *plat_dev; + int index; + + union niu_parent_id id; + + struct niu *ports[NIU_MAX_PORTS]; + + atomic_t refcnt; + struct list_head list; + + spinlock_t lock; + + u32 flags; +#define PARENT_FLGS_CLS_HWINIT 0x00000001 + + u32 port_phy; +#define PORT_PHY_UNKNOWN 0x00000000 +#define PORT_PHY_INVALID 0xffffffff +#define PORT_TYPE_10G 0x01 +#define PORT_TYPE_1G 0x02 +#define PORT_TYPE_MASK 0x03 + + u8 rxchan_per_port[NIU_MAX_PORTS]; + u8 txchan_per_port[NIU_MAX_PORTS]; + + struct niu_rdc_tables rdc_group_cfg[NIU_MAX_PORTS]; + u8 rdc_default[NIU_MAX_PORTS]; + + u8 ldg_map[LDN_MAX + 1]; + + u8 plat_type; +#define PLAT_TYPE_INVALID 0x00 +#define PLAT_TYPE_ATLAS 0x01 +#define PLAT_TYPE_NIU 0x02 +#define PLAT_TYPE_VF_P0 0x03 +#define PLAT_TYPE_VF_P1 0x04 + + u8 num_ports; + + u16 tcam_num_entries; +#define NIU_PCI_TCAM_ENTRIES 256 +#define NIU_NONPCI_TCAM_ENTRIES 128 +#define NIU_TCAM_ENTRIES_MAX 256 + + int rxdma_clock_divider; + + struct phy_probe_info phy_probe_info; + + struct niu_tcam_entry tcam[NIU_TCAM_ENTRIES_MAX]; + u64 l2_cls[2]; + u64 l3_cls[4]; + u64 tcam_key[12]; + u64 flow_key[12]; +}; + +struct niu_ops { + void *(*alloc_coherent)(struct device *dev, size_t size, + u64 *handle, gfp_t flag); + void (*free_coherent)(struct device *dev, size_t size, + void *cpu_addr, u64 handle); + u64 (*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, u64 dma_address, + size_t size, enum dma_data_direction direction); + u64 (*map_single)(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction); + void (*unmap_single)(struct device *dev, u64 dma_address, + size_t size, enum dma_data_direction direction); +}; + +struct niu_link_config { + /* Describes what we're trying to get. */ + u32 advertising; + u32 supported; + u16 speed; + u8 duplex; + u8 autoneg; + + /* Describes what we actually have. */ + u16 active_speed; + u8 active_duplex; +#define SPEED_INVALID 0xffff +#define DUPLEX_INVALID 0xff +#define AUTONEG_INVALID 0xff + + u8 loopback_mode; +#define LOOPBACK_DISABLED 0x00 +#define LOOPBACK_PHY 0x01 +#define LOOPBACK_MAC 0x02 +}; + +struct niu_ldg { + struct napi_struct napi; + struct niu *np; + u8 ldg_num; + u8 timer; + u64 v0, v1, v2; + unsigned int irq; +}; + +struct niu_xmac_stats { + u64 tx_frames; + u64 tx_bytes; + u64 tx_fifo_errors; + u64 tx_overflow_errors; + u64 tx_max_pkt_size_errors; + u64 tx_underflow_errors; + + u64 rx_local_faults; + u64 rx_remote_faults; + u64 rx_link_faults; + u64 rx_align_errors; + u64 rx_frags; + u64 rx_mcasts; + u64 rx_bcasts; + u64 rx_hist_cnt1; + u64 rx_hist_cnt2; + u64 rx_hist_cnt3; + u64 rx_hist_cnt4; + u64 rx_hist_cnt5; + u64 rx_hist_cnt6; + u64 rx_hist_cnt7; + u64 rx_octets; + u64 rx_code_violations; + u64 rx_len_errors; + u64 rx_crc_errors; + u64 rx_underflows; + u64 rx_overflows; + + u64 pause_off_state; + u64 pause_on_state; + u64 pause_received; +}; + +struct niu_bmac_stats { + u64 tx_underflow_errors; + u64 tx_max_pkt_size_errors; + u64 tx_bytes; + u64 tx_frames; + + u64 rx_overflows; + u64 rx_frames; + u64 rx_align_errors; + u64 rx_crc_errors; + u64 rx_len_errors; + + u64 pause_off_state; + u64 pause_on_state; + u64 pause_received; +}; + +union niu_mac_stats { + struct niu_xmac_stats xmac; + struct niu_bmac_stats bmac; +}; + +struct niu_phy_ops { + int (*serdes_init)(struct niu *np); + int (*xcvr_init)(struct niu *np); + int (*link_status)(struct niu *np, int *); +}; + +struct of_device; +struct niu { + void __iomem *regs; + struct net_device *dev; + struct pci_dev *pdev; + struct device *device; + struct niu_parent *parent; + + u32 flags; +#define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */ +#define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */ +#define NIU_FLAGS_PROMISC 0x00100000 /* PROMISC enabled */ +#define NIU_FLAGS_VPD_VALID 0x00080000 /* VPD has valid version */ +#define NIU_FLAGS_10G 0x00040000 /* 0=1G 1=10G */ +#define NIU_FLAGS_FIBER 0x00020000 /* 0=COPPER 1=FIBER */ +#define NIU_FLAGS_XMAC 0x00010000 /* 0=BMAC 1=XMAC */ + + u32 msg_enable; + + /* Protects hw programming, and ring state. */ + spinlock_t lock; + + const struct niu_ops *ops; + struct net_device_stats net_stats; + union niu_mac_stats mac_stats; + + struct rx_ring_info *rx_rings; + struct tx_ring_info *tx_rings; + int num_rx_rings; + int num_tx_rings; + + struct niu_ldg ldg[NIU_NUM_LDG]; + int num_ldg; + + void __iomem *mac_regs; + unsigned long ipp_off; + unsigned long pcs_off; + unsigned long xpcs_off; + + struct timer_list timer; + const struct niu_phy_ops *phy_ops; + int phy_addr; + + struct niu_link_config link_config; + + struct work_struct reset_task; + + u8 port; + u8 mac_xcvr; +#define MAC_XCVR_MII 1 +#define MAC_XCVR_PCS 2 +#define MAC_XCVR_XPCS 3 + + struct niu_classifier clas; + + struct niu_vpd vpd; + u32 eeprom_len; + + struct of_device *op; + void __iomem *vir_regs_1; + void __iomem *vir_regs_2; +}; + +#endif /* _NIU_H */ From bc4b2b497aa61c79e3f3444237a4003a254ea565 Mon Sep 17 00:00:00 2001 From: "Klaus D. Wacker" Date: Fri, 5 Oct 2007 16:45:44 +0200 Subject: [PATCH 1715/2804] qeth: HiperSockets layer-3 interface drop non IPv4 or non IPv6 packets HiperSockets infrastructure (layer-3 mode) supports only IPv4 or IPv6 packets. Sending other packet types disturbs TCP/IP on z/VM, which issues messages about invalid packets. Qeth send routine will detect packet type on sending over a HiperSockets interface (in layer-3 mode) and drop non IP packets. The error and drop count of the interface is incremented. Signed-off-by: Klaus D. Wacker Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 778ddfb99077..b41a53816e92 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -4719,8 +4719,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) rc = qeth_do_send_packet(card, queue, new_skb, hdr, elements_needed, ctx); else { - if ((skb->protocol == htons(ETH_P_ARP)) && - (card->dev->flags & IFF_NOARP)) { + if ((!card->options.layer2) && + (ipv == 0)) { __qeth_free_new_skb(skb, new_skb); return -EPERM; } From 6570ebc4f57ad0761104f769576ae5652d9b8d64 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Fri, 5 Oct 2007 16:45:45 +0200 Subject: [PATCH 1716/2804] qeth: EDDP does not work on large MTUs Fix filling the qdio buffers in EDDP mode. Signed-off-by: Frank Blaschka Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_eddp.c | 16 +++++++++------- drivers/s390/net/qeth_main.c | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c index 70108fb16906..e3c268cfbffe 100644 --- a/drivers/s390/net/qeth_eddp.c +++ b/drivers/s390/net/qeth_eddp.c @@ -159,13 +159,15 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue, buffer = buf->buffer; /* fill one skb into buffer */ for (i = 0; i < ctx->elements_per_skb; ++i){ - buffer->element[buf->next_element_to_fill].addr = - ctx->elements[element].addr; - buffer->element[buf->next_element_to_fill].length = - ctx->elements[element].length; - buffer->element[buf->next_element_to_fill].flags = - ctx->elements[element].flags; - buf->next_element_to_fill++; + if (ctx->elements[element].length != 0) { + buffer->element[buf->next_element_to_fill]. + addr = ctx->elements[element].addr; + buffer->element[buf->next_element_to_fill]. + length = ctx->elements[element].length; + buffer->element[buf->next_element_to_fill]. + flags = ctx->elements[element].flags; + buf->next_element_to_fill++; + } element++; elements--; } diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index b41a53816e92..fe6164795eda 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -4508,7 +4508,8 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, /* check if we have enough elements (including following * free buffers) to handle eddp context */ if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){ - printk("eddp tx_dropped 1\n"); + if (net_ratelimit()) + PRINT_WARN("eddp tx_dropped 1\n"); rc = -EBUSY; goto out; } From d8fae9c2f2642ffe411424ed2e4677f959168152 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 5 Oct 2007 16:45:46 +0200 Subject: [PATCH 1717/2804] qeth: avoid duplicate deletion of multicast addresses if qeth_set_multicast_list() is performed on 2 CPUs in parallel, card->ip_list may end corrupted. Solution: In function __qeth_delete_all_mc() remove card->ip_list entry before invoking qeth_deregister_addr_entry(). Thus a 2nd invocation of qeth_set_multicast_list() cannot try to remove the same entry twice. Signed-off-by Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index fe6164795eda..6d7b79e2ba92 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -823,14 +823,15 @@ __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags) again: list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) { if (addr->is_multicast) { + list_del(&addr->entry); spin_unlock_irqrestore(&card->ip_lock, *flags); rc = qeth_deregister_addr_entry(card, addr); spin_lock_irqsave(&card->ip_lock, *flags); if (!rc) { - list_del(&addr->entry); kfree(addr); goto again; - } + } else + list_add(&addr->entry, &card->ip_list); } } } From 59579da329b22bcddc5da0c22c61d6dc1f9eb96a Mon Sep 17 00:00:00 2001 From: "Klaus D. Wacker" Date: Fri, 5 Oct 2007 16:45:47 +0200 Subject: [PATCH 1718/2804] lcs: Channel errors drive lcs_recovery which leads to kernel panic. When the lcs irq routine detects channel failures it drives device recovery. After this event the device is no longer usable for shutdown requests, because the lcs_irq routine may get wrong channel status information. In such a case the lcs_irq routine marks the channel in 'error' state. The channel state comes back to 'running' after restarting the channels. Signed-off-by: Klaus D. Wacker Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/lcs.c | 11 ++++++++--- drivers/s390/net/lcs.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index e4b11afbbc9f..0fd663b23d76 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1400,11 +1400,14 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n", cdev->dev.bus_id, dstat, cstat); if (rc) { - lcs_schedule_recovery(card); - wake_up(&card->wait_q); - return; + channel->state = LCS_CH_STATE_ERROR; } } + if (channel->state == LCS_CH_STATE_ERROR) { + lcs_schedule_recovery(card); + wake_up(&card->wait_q); + return; + } /* How far in the ccw chain have we processed? */ if ((channel->state != LCS_CH_STATE_INIT) && (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { @@ -1708,6 +1711,8 @@ lcs_stopcard(struct lcs_card *card) if (card->read.state != LCS_CH_STATE_STOPPED && card->write.state != LCS_CH_STATE_STOPPED && + card->read.state != LCS_CH_STATE_ERROR && + card->write.state != LCS_CH_STATE_ERROR && card->state == DEV_STATE_UP) { lcs_clear_multicast_list(card); rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index 0e1e4a0a88f0..8976fb0b070a 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -138,6 +138,7 @@ enum lcs_channel_states { LCS_CH_STATE_RUNNING, LCS_CH_STATE_SUSPENDED, LCS_CH_STATE_CLEARED, + LCS_CH_STATE_ERROR, }; /** From 28692ec45e58f40a998beb155fe1c0d3e1167485 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 5 Oct 2007 16:45:48 +0200 Subject: [PATCH 1719/2804] qeth: discard inbound packets with unknown header id Debugging statements are added for inbound packets with unknown header id. Those packets are discarded and no longer processed as osn-packets. Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 6d7b79e2ba92..c67e7dfd56cc 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -2702,10 +2702,15 @@ qeth_process_inbound_buffer(struct qeth_card *card, qeth_layer2_rebuild_skb(card, skb, hdr); else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3) vlan_tag = qeth_rebuild_skb(card, skb, hdr); - else { /*in case of OSN*/ + else if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) { skb_push(skb, sizeof(struct qeth_hdr)); skb_copy_to_linear_data(skb, hdr, sizeof(struct qeth_hdr)); + } else { /* unknown header type */ + dev_kfree_skb_any(skb); + QETH_DBF_TEXT(trace, 3, "inbunkno"); + QETH_DBF_HEX(control, 3, hdr, QETH_DBF_CONTROL_LEN); + continue; } /* is device UP ? */ if (!(card->dev->flags & IFF_UP)){ From 589c085f2734537dce4a8b59a1d49006479e33d1 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 4 Oct 2007 11:38:43 -0700 Subject: [PATCH 1720/2804] e1000e: fix debugging printout code A small bug crawled in the -DDEBUG enabled code. Fix this to properly call the backreference device name. Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/hw.h | 2 +- drivers/net/e1000e/netdev.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 848217a38259..aa82f1afb7fb 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -852,7 +852,7 @@ struct e1000_hw { #ifdef DEBUG #define hw_dbg(hw, format, arg...) \ - printk(KERN_DEBUG, "%s: " format, e1000_get_hw_dev_name(hw), ##arg); + printk(KERN_DEBUG, "%s: " format, e1000e_get_hw_dev_name(hw), ##arg); #else static inline int __attribute__ ((format (printf, 2, 3))) hw_dbg(struct e1000_hw *hw, const char *format, ...) diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 4a21d7df1743..3a0bb2afe387 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -66,9 +66,7 @@ static const struct e1000_info *e1000_info_tbl[] = { **/ char *e1000e_get_hw_dev_name(struct e1000_hw *hw) { - struct e1000_adapter *adapter = hw->back; - struct net_device *netdev = adapter->netdev; - return netdev->name; + return hw->adapter->netdev->name; } #endif From 8658251dc3fed54b09991a2c5e0a7084755157d7 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 4 Oct 2007 15:00:08 -0700 Subject: [PATCH 1721/2804] e1000e: Fix ethtool register test code A merge/cleanup code accidentally dropped 8254x code in and removed 8257x code here. Undo this mistake and use the pci-e relevant register test similar as to what is in e1000. Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/ethtool.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 3423f33769b7..2e8218fb0579 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -784,10 +784,16 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB); REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000); - REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x01FFFFFF); - REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFF000, 0xFFFFFFFF); - REG_PATTERN_TEST(E1000_TXCW, 0x0000FFFF, 0x0000FFFF); - REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFF000, 0xFFFFFFFF); + REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + if ((mac->type != e1000_ich8lan) && + (mac->type != e1000_ich9lan)) + REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); + for (i = 0; i < mac->rar_entry_count; i++) + REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), + 0x8003FFFF, 0xFFFFFFFF); for (i = 0; i < mac->mta_reg_count; i++) REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); From 9974a356b204833b32173210ca25edfdc24dcdd5 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 7 Oct 2007 23:27:28 -0700 Subject: [PATCH 1722/2804] [TG3]: Walk PCI capability lists. Newer tg3 devices shuffle around the registers in PCI configuration space. This patch changes the way the driver accesses the PCI capabilities registers. Hardcoded register locations are replaced with offsets from pci_find_capability() return values. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 48 +++++++++++++++++++++++++++++----------- drivers/net/tg3.h | 28 ++--------------------- include/linux/pci_regs.h | 13 +++++++++++ 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d4ac6e9ef6db..4f9fbe268ec9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4865,9 +4865,15 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd); /* Make sure PCI-X relaxed ordering bit is clear. */ - pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val); - val &= ~PCIX_CAPS_RELAXED_ORDERING; - pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); + if (tp->pcix_cap) { + u16 pcix_cmd; + + pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, + &pcix_cmd); + pcix_cmd &= ~PCI_X_CMD_ERO; + pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, + pcix_cmd); + } if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { @@ -6574,16 +6580,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(WDMAC_MODE, val); udelay(40); - if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) { - val = tr32(TG3PCI_X_CAPS); + if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + u16 pcix_cmd; + + pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, + &pcix_cmd); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) { - val &= ~PCIX_CAPS_BURST_MASK; - val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT); + pcix_cmd &= ~PCI_X_CMD_MAX_READ; + pcix_cmd |= PCI_X_CMD_READ_2K; } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { - val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK); - val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT); + pcix_cmd &= ~(PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ); + pcix_cmd |= PCI_X_CMD_READ_2K; } - tw32(TG3PCI_X_CAPS, val); + pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, + pcix_cmd); } tw32_f(RDMAC_MODE, rdmac_mode); @@ -10712,10 +10722,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) cacheline_sz_reg); } + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX); + if (!tp->pcix_cap) { + printk(KERN_ERR PFX "Cannot find PCI-X " + "capability, aborting.\n"); + return -EIO; + } + } + pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); - if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) { + if (tp->pcix_cap && (pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) { tp->tg3_flags |= TG3_FLAG_PCIX_MODE; /* If this is a 5700 BX chipset, and we are in PCI-X @@ -10733,11 +10753,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * space registers clobbered due to this bug. * So explicitly force the chip into D0 here. */ - pci_read_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT, + pci_read_config_dword(tp->pdev, + tp->pm_cap + PCI_PM_CTRL, &pm_reg); pm_reg &= ~PCI_PM_CTRL_STATE_MASK; pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */; - pci_write_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT, + pci_write_config_dword(tp->pdev, + tp->pm_cap + PCI_PM_CTRL, pm_reg); /* Also, force SERR#/PERR# in PCI command. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a6a23bbcdfee..c4f845dd1e8b 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -57,32 +57,7 @@ #define TG3PCI_IRQ_PIN 0x0000003d #define TG3PCI_MIN_GNT 0x0000003e #define TG3PCI_MAX_LAT 0x0000003f -#define TG3PCI_X_CAPS 0x00000040 -#define PCIX_CAPS_RELAXED_ORDERING 0x00020000 -#define PCIX_CAPS_SPLIT_MASK 0x00700000 -#define PCIX_CAPS_SPLIT_SHIFT 20 -#define PCIX_CAPS_BURST_MASK 0x000c0000 -#define PCIX_CAPS_BURST_SHIFT 18 -#define PCIX_CAPS_MAX_BURST_CPIOB 2 -#define TG3PCI_PM_CAP_PTR 0x00000041 -#define TG3PCI_X_COMMAND 0x00000042 -#define TG3PCI_X_STATUS 0x00000044 -#define TG3PCI_PM_CAP_ID 0x00000048 -#define TG3PCI_VPD_CAP_PTR 0x00000049 -#define TG3PCI_PM_CAPS 0x0000004a -#define TG3PCI_PM_CTRL_STAT 0x0000004c -#define TG3PCI_BR_SUPP_EXT 0x0000004e -#define TG3PCI_PM_DATA 0x0000004f -#define TG3PCI_VPD_CAP_ID 0x00000050 -#define TG3PCI_MSI_CAP_PTR 0x00000051 -#define TG3PCI_VPD_ADDR_FLAG 0x00000052 -#define VPD_ADDR_FLAG_WRITE 0x00008000 -#define TG3PCI_VPD_DATA 0x00000054 -#define TG3PCI_MSI_CAP_ID 0x00000058 -#define TG3PCI_NXT_CAP_PTR 0x00000059 -#define TG3PCI_MSI_CTRL 0x0000005a -#define TG3PCI_MSI_ADDR_LOW 0x0000005c -#define TG3PCI_MSI_ADDR_HIGH 0x00000060 +/* 0x40 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ #define TG3PCI_MISC_HOST_CTRL 0x00000068 @@ -2318,6 +2293,7 @@ struct tg3 { int pm_cap; int msi_cap; + int pcix_cap; /* PHY info */ u32 phy_id; diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 495d368390e0..423d592c55d5 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -316,7 +316,20 @@ #define PCI_X_CMD 2 /* Modes & Features */ #define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ #define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ +#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ +#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ +#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ +#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ #define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ + /* Max # of outstanding split transactions */ +#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ +#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ +#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ +#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ +#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ +#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ +#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ +#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ #define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ #define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ #define PCI_X_STATUS 4 /* PCI-X capabilities */ From 795d01c523dd9f22acc70fe86ed30e605e00024d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 7 Oct 2007 23:28:17 -0700 Subject: [PATCH 1723/2804] [TG3]: ASIC decoding and basic CPMU support. Newer products change the way the ASIC revision is obtained. This patch implements how the driver will extract the revision number. This patch also adds preliminary CPMU support. CPMU stands for Central Power Management Unit. The CPMU's role is to put the chip into lower power states when the operating conditions allow it. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 21 ++++++++++++++++----- drivers/net/tg3.h | 9 ++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4f9fbe268ec9..482b7df55247 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -595,7 +595,8 @@ static void tg3_switch_clocks(struct tg3 *tp) u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); u32 orig_clock_ctrl; - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) return; orig_clock_ctrl = clock_ctrl; @@ -1400,6 +1401,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133, 40); } else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) { /* do nothing */ } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && @@ -6147,11 +6149,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* 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 - * chips. + * chips and don't even touch the clocks if the CPMU is present. */ - if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) - tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT; - tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); + if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) { + if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) + tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT; + tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); + } if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { @@ -10527,6 +10531,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_chip_rev_id = (misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT); + 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); + tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK; + } /* Wrong chip ID in 5752 A0. This code can be removed later * as A0 is not in production. diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index c4f845dd1e8b..79ce68cf836b 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -121,6 +121,7 @@ #define ASIC_REV_5755 0x0a #define ASIC_REV_5787 0x0b #define ASIC_REV_5906 0x0c +#define ASIC_REV_USE_PROD_ID_REG 0x0f #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -214,7 +215,9 @@ #define TG3PCI_DUAL_MAC_CTRL 0x000000b8 #define DUAL_MAC_CTRL_CH_MASK 0x00000003 #define DUAL_MAC_CTRL_ID 0x00000004 -/* 0xbc --> 0x100 unused */ +#define TG3PCI_PRODID_ASICREV 0x000000bc +#define PROD_ID_ASIC_REV_MASK 0x0fffffff +/* 0xc0 --> 0x100 unused */ /* 0x100 --> 0x200 unused */ @@ -2213,7 +2216,7 @@ struct tg3 { #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 - +#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 @@ -2285,7 +2288,7 @@ struct tg3 { u32 pwrmgmt_thresh; /* PCI block */ - u16 pci_chip_rev_id; + u32 pci_chip_rev_id; u8 pci_cacheline_sz; u8 pci_lat_timer; u8 pci_hdr_type; From d30cdd28fba556143a4bb0d1a6097ebcc2891477 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 7 Oct 2007 23:28:35 -0700 Subject: [PATCH 1724/2804] [TG3]: Add 5784 and 5764 support. This patch adds the support for 5784 and 5764 devices. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 53 ++++++++++++++++++++++++++++++++--------- drivers/net/tg3.h | 14 ++++++++++- include/linux/pci_ids.h | 2 ++ 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 482b7df55247..2378ea3f357a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -198,6 +198,8 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)}, {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)}, @@ -4921,7 +4923,8 @@ static int tg3_chip_reset(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || 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_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) tw32(GRC_FASTBOOT_PC, 0); /* @@ -6146,6 +6149,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_write_sig_legacy(tp, RESET_KIND_INIT); + if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0) { + val = tr32(TG3_CPMU_CTRL); + val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE); + tw32(TG3_CPMU_CTRL, 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 @@ -6180,10 +6189,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - /* This value is determined during the probe time DMA - * engine test, tg3_test_dma. - */ - tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) { + /* This value is determined during the probe time DMA + * engine test, tg3_test_dma. + */ + tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + } tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS | GRC_MODE_4X_NIC_SEND_RINGS | @@ -6417,6 +6428,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | RDMAC_MODE_LNGREAD_ENAB); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB | + RDMAC_MODE_MBUF_RBD_CRPT_ENAB | + RDMAC_MODE_MBUF_SBD_CRPT_ENAB; + /* If statement applies to 5705 and 5750 PCI devices only */ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || @@ -6578,7 +6594,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Enable host coalescing bug fix */ 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_5787) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)) val |= (1 << 29); tw32_f(WDMAC_MODE, val); @@ -8353,7 +8370,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) } 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_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ethtool_op_set_tx_ipv6_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -8849,7 +8867,8 @@ static int tg3_test_memory(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { 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_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; @@ -9600,7 +9619,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_5752_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tg3_get_5755_nvram_info(tp); - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) tg3_get_5787_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_get_5906_nvram_info(tp); @@ -9913,6 +9933,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) && (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) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -10657,6 +10678,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || 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 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -10676,6 +10698,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) 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 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; @@ -10693,6 +10716,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && 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 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; @@ -10868,6 +10892,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tg3_get_eeprom_hw_cfg(tp); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; + /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). * GPIO1 driven high will bring 5700's external PHY out of reset. * It is also used as eeprom write protect on LOMs. @@ -10934,7 +10961,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { 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_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) { if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 && tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; @@ -11077,6 +11105,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ 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 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->dev->hard_start_xmit = tg3_start_xmit; else @@ -11698,6 +11727,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5780: return "5780"; case PHY_ID_BCM5755: return "5755"; case PHY_ID_BCM5787: return "5787"; + case PHY_ID_BCM5784: return "5784"; case PHY_ID_BCM5756: return "5722/5756"; case PHY_ID_BCM5906: return "5906"; case PHY_ID_BCM8002: return "8002/serdes"; @@ -12042,7 +12072,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; 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_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) dev->features |= NETIF_F_IPV6_CSUM; tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 79ce68cf836b..d8e829f6fcb2 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -108,6 +108,7 @@ #define CHIPREV_ID_5752_A1 0x6001 #define CHIPREV_ID_5714_A2 0x9002 #define CHIPREV_ID_5906_A1 0xc001 +#define CHIPREV_ID_5784_A0 0x5784000 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -122,6 +123,7 @@ #define ASIC_REV_5787 0x0b #define ASIC_REV_5906 0x0c #define ASIC_REV_USE_PROD_ID_REG 0x0f +#define ASIC_REV_5784 0x5784 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -843,7 +845,13 @@ #define RCVLSC_MODE_ATTN_ENABLE 0x00000004 #define RCVLSC_STATUS 0x00003404 #define RCVLSC_STATUS_ERROR_ATTN 0x00000004 -/* 0x3408 --> 0x3800 unused */ +/* 0x3408 --> 0x3600 unused */ + +/* CPMU registers */ +#define TG3_CPMU_CTRL 0x00003600 +#define CPMU_CTRL_LINK_IDLE_MODE 0x00000200 +#define CPMU_CTRL_LINK_AWARE_MODE 0x00000400 +/* 0x3604 --> 0x3800 unused */ /* Mbuf cluster free registers */ #define MBFREE_MODE 0x00003800 @@ -1023,7 +1031,10 @@ #define RDMAC_MODE_FIFOOREAD_ENAB 0x00000100 #define RDMAC_MODE_LNGREAD_ENAB 0x00000200 #define RDMAC_MODE_SPLIT_ENABLE 0x00000800 +#define RDMAC_MODE_BD_SBD_CRPT_ENAB 0x00000800 #define RDMAC_MODE_SPLIT_RESET 0x00001000 +#define RDMAC_MODE_MBUF_RBD_CRPT_ENAB 0x00001000 +#define RDMAC_MODE_MBUF_SBD_CRPT_ENAB 0x00002000 #define RDMAC_MODE_FIFO_SIZE_128 0x00020000 #define RDMAC_MODE_FIFO_LONG_BURST 0x00030000 #define RDMAC_STATUS 0x00004804 @@ -2315,6 +2326,7 @@ struct tg3 { #define PHY_ID_BCM5755 0xbc050cc0 #define PHY_ID_BCM5787 0xbc050ce0 #define PHY_ID_BCM5756 0xbc050ed0 +#define PHY_ID_BCM5784 0xbc050fa0 #define PHY_ID_BCM5906 0xdc00ac40 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9ebc2c70c5d4..6f5fa39c8290 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1950,8 +1950,10 @@ #define PCI_DEVICE_ID_TIGON3_5751M 0x167d #define PCI_DEVICE_ID_TIGON3_5751F 0x167e #define PCI_DEVICE_ID_TIGON3_5787F 0x167f +#define PCI_DEVICE_ID_TIGON3_5764 0x1684 #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_5786 0x169a #define PCI_DEVICE_ID_TIGON3_5787 0x169b #define PCI_DEVICE_ID_TIGON3_5788 0x169c From 182f6ed5188ccb46d1c54c3334943a54110d0118 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 7 Oct 2007 23:29:06 -0700 Subject: [PATCH 1725/2804] [TG3]: Update version to 3.82. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2378ea3f357a..b1e5660baf4a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.81" -#define DRV_MODULE_RELDATE "September 5, 2007" +#define DRV_MODULE_VERSION "3.82" +#define DRV_MODULE_RELDATE "October 5, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 From 29d0a309d11bac9e57af914d0d6a35cde0080861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sun, 7 Oct 2007 23:36:41 -0700 Subject: [PATCH 1726/2804] [TCP]: Fix two off-by-one errors in fackets_out adjusting logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1) Passing wrong skb to tcp_adjust_fackets_out could corrupt fastpath_cnt_hint as tcp_skb_pcount(next_skb) is not included to it if hint points exactly to the next_skb (it's lagging behind, see sacktag). 2) When fastpath_skb_hint is put backwards to avoid dangling skb reference, the skb's pcount must also be removed from count (not included like above). Reported by Cedric Le Goater Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 6199abeb0f5e..53296753b0bd 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1755,14 +1755,16 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m if (tcp_is_reno(tp) && tp->sacked_out) tcp_dec_pcount_approx(&tp->sacked_out, next_skb); - tcp_adjust_fackets_out(tp, skb, tcp_skb_pcount(next_skb)); + tcp_adjust_fackets_out(tp, next_skb, tcp_skb_pcount(next_skb)); tp->packets_out -= tcp_skb_pcount(next_skb); /* changed transmit queue under us so clear hints */ tcp_clear_retrans_hints_partial(tp); /* manually tune sacktag skb hint */ - if (tp->fastpath_skb_hint == next_skb) + if (tp->fastpath_skb_hint == next_skb) { tp->fastpath_skb_hint = skb; + tp->fastpath_cnt_hint -= tcp_skb_pcount(skb); + } sk_stream_free_skb(sk, next_skb); } From c79e3357166a2ca39fd7613b0eb7f493c1ac5e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sun, 7 Oct 2007 23:37:25 -0700 Subject: [PATCH 1727/2804] [TCP]: Comment fastpath_cnt_hint off-by-one trap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/linux/tcp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index f8cf090e8f49..9ff456e8d6c7 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -343,7 +343,8 @@ struct tcp_sock { struct sk_buff *forward_skb_hint; struct sk_buff *fastpath_skb_hint; - int fastpath_cnt_hint; + int fastpath_cnt_hint; /* Lags behind by current skb's pcount + * compared to respective fackets_out */ int lost_cnt_hint; int retransmit_cnt_hint; From de83c058af25aa97ed4864abab11e90e8dead6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sun, 7 Oct 2007 23:37:55 -0700 Subject: [PATCH 1728/2804] [TCP]: "Annotate" another fackets_out state reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should no longer be necessary because fackets_out is accurate. It indicates bugs elsewhere, thus report it. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7c1a92ffa083..4268cd13ff9a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1160,7 +1160,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ int first_sack_index; if (!tp->sacked_out) { - tp->fackets_out = 0; + if (WARN_ON(tp->fackets_out)) + tp->fackets_out = 0; tp->highest_sack = tp->snd_una; } prior_fackets = tp->fackets_out; From cfcabdcc2d5a810208e5bb3974121b7ed60119aa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Oct 2007 01:59:42 -0700 Subject: [PATCH 1729/2804] [NET]: sparse warning fixes Fix a bunch of sparse warnings. Mostly about 0 used as NULL pointer, and shadowed variable declarations. One notable case was that hash size should have been unsigned. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/inet_hashtables.h | 2 +- include/net/sock.h | 22 +++++++++++----------- net/appletalk/aarp.c | 2 -- net/atm/signaling.c | 2 +- net/core/dev.c | 4 ++-- net/core/pktgen.c | 30 ++++++++++++++---------------- net/core/scm.c | 9 ++++++--- net/ipv4/igmp.c | 5 ++--- net/ipv4/inet_lro.c | 2 +- net/ipv4/ip_sockglue.c | 6 +++--- net/ipv4/proc.c | 2 +- net/ipv4/route.c | 4 ++-- net/ipv4/tcp_input.c | 2 +- net/ipv6/anycast.c | 2 +- net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/mcast.c | 4 ++-- net/ipv6/ndisc.c | 2 +- net/sched/cls_u32.c | 2 +- net/socket.c | 2 +- 19 files changed, 52 insertions(+), 54 deletions(-) diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index d27ee8c0da3f..8228b57eb18f 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -107,7 +107,7 @@ struct inet_hashinfo { */ struct inet_bind_hashbucket *bhash; - int bhash_size; + unsigned int bhash_size; unsigned int ehash_size; /* All sockets in TCP_LISTEN state will be in here. This is the only diff --git a/include/net/sock.h b/include/net/sock.h index 74e1f7d90d73..453c79d0915b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -485,17 +485,17 @@ static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb) skb->next = NULL; } -#define sk_wait_event(__sk, __timeo, __condition) \ -({ int rc; \ - release_sock(__sk); \ - rc = __condition; \ - if (!rc) { \ - *(__timeo) = schedule_timeout(*(__timeo)); \ - } \ - lock_sock(__sk); \ - rc = __condition; \ - rc; \ -}) +#define sk_wait_event(__sk, __timeo, __condition) \ + ({ int __rc; \ + release_sock(__sk); \ + __rc = __condition; \ + if (!__rc) { \ + *(__timeo) = schedule_timeout(*(__timeo)); \ + } \ + lock_sock(__sk); \ + __rc = __condition; \ + __rc; \ + }) extern int sk_stream_wait_connect(struct sock *sk, long *timeo_p); extern int sk_stream_wait_memory(struct sock *sk, long *timeo_p); diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 92cd74973c97..6c5c6dc098ec 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -822,8 +822,6 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, * address. So as a precaution flush any * entries we have for this address. */ - struct aarp_entry *a; - a = __aarp_find_entry(resolved[sa.s_node % (AARP_HASH_SIZE - 1)], skb->dev, &sa); diff --git a/net/atm/signaling.c b/net/atm/signaling.c index bced78b77f12..229921400522 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -230,7 +230,7 @@ static void sigd_close(struct atm_vcc *vcc) struct hlist_head *head = &vcc_hash[i]; sk_for_each(s, node, head) { - struct atm_vcc *vcc = atm_sk(s); + vcc = atm_sk(s); purge_vcc(vcc); } diff --git a/net/core/dev.c b/net/core/dev.c index d99864662582..13a1bc5d3bfd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -780,7 +780,7 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf) int i = 0; const char *p; const int max_netdevices = 8*PAGE_SIZE; - long *inuse; + unsigned long *inuse; struct net_device *d; p = strnchr(name, IFNAMSIZ-1, '%'); @@ -794,7 +794,7 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf) return -EINVAL; /* Use one page as a bit array of possible slots */ - inuse = (long *) get_zeroed_page(GFP_ATOMIC); + inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC); if (!inuse) return -ENOMEM; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index f07bd590f8f9..2100c734b102 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1563,15 +1563,17 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "mpls")) { - unsigned n, offset; + unsigned n, cnt; + len = get_labels(&user_buffer[i], pkt_dev); - if (len < 0) { return len; } + if (len < 0) + return len; i += len; - offset = sprintf(pg_result, "OK: mpls="); + cnt = sprintf(pg_result, "OK: mpls="); for (n = 0; n < pkt_dev->nr_labels; n++) - offset += sprintf(pg_result + offset, - "%08x%s", ntohl(pkt_dev->labels[n]), - n == pkt_dev->nr_labels-1 ? "" : ","); + cnt += sprintf(pg_result + cnt, + "%08x%s", ntohl(pkt_dev->labels[n]), + n == pkt_dev->nr_labels-1 ? "" : ","); if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ @@ -2731,6 +2733,7 @@ static unsigned int scan_ip6(const char *s, char ip[16]) unsigned int prefixlen = 0; unsigned int suffixlen = 0; __be32 tmp; + char *pos; for (i = 0; i < 16; i++) ip[i] = 0; @@ -2745,12 +2748,9 @@ static unsigned int scan_ip6(const char *s, char ip[16]) } s++; } - { - char *tmp; - u = simple_strtoul(s, &tmp, 16); - i = tmp - s; - } + u = simple_strtoul(s, &pos, 16); + i = pos - s; if (!i) return 0; if (prefixlen == 12 && s[i] == '.') { @@ -2778,11 +2778,9 @@ static unsigned int scan_ip6(const char *s, char ip[16]) len++; } else if (suffixlen != 0) break; - { - char *tmp; - u = simple_strtol(s, &tmp, 16); - i = tmp - s; - } + + u = simple_strtol(s, &pos, 16); + i = pos - s; if (!i) { if (*s) len--; diff --git a/net/core/scm.c b/net/core/scm.c index 44c4ec2c8769..530bee8d9ed9 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -167,7 +167,8 @@ error: int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data) { - struct cmsghdr __user *cm = (struct cmsghdr __user *)msg->msg_control; + struct cmsghdr __user *cm + = (__force struct cmsghdr __user *)msg->msg_control; struct cmsghdr cmhdr; int cmlen = CMSG_LEN(len); int err; @@ -202,7 +203,8 @@ out: void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) { - struct cmsghdr __user *cm = (struct cmsghdr __user*)msg->msg_control; + struct cmsghdr __user *cm + = (__force struct cmsghdr __user*)msg->msg_control; int fdmax = 0; int fdnum = scm->fp->count; @@ -222,7 +224,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) if (fdnum < fdmax) fdmax = fdnum; - for (i=0, cmfptr=(int __user *)CMSG_DATA(cm); isfcount[MCAST_EXCLUDE] != 0)) { #ifdef CONFIG_IP_MULTICAST - struct in_device *in_dev = pmc->interface; struct ip_sf_list *psf; + in_dev = pmc->interface; #endif /* filter mode change */ @@ -1799,7 +1799,7 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, { int err; - if (iml->sflist == 0) { + if (iml->sflist == NULL) { /* any-source empty exclude case */ return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, iml->sfmode, 0, NULL, 0); @@ -2167,7 +2167,6 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, return -EFAULT; } for (i=0; itcp_next_seq != ntohl(tcph->seq)) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index b2b3053dfef7..f51f20e487c8 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -659,7 +659,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, break; } msf = kmalloc(optlen, GFP_KERNEL); - if (msf == 0) { + if (!msf) { err = -ENOBUFS; break; } @@ -816,7 +816,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, break; } gsf = kmalloc(optlen,GFP_KERNEL); - if (gsf == 0) { + if (!gsf) { err = -ENOBUFS; break; } @@ -836,7 +836,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, } msize = IP_MSFILTER_SIZE(gsf->gf_numsrc); msf = kmalloc(msize,GFP_KERNEL); - if (msf == 0) { + if (!msf) { err = -ENOBUFS; goto mc_msf_out; } diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 9dee70e1cf0d..e5b05b039101 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -144,7 +144,7 @@ static struct { { "TimestampReps", ICMP_TIMESTAMPREPLY }, { "AddrMasks", ICMP_ADDRESS }, { "AddrMaskReps", ICMP_ADDRESSREPLY }, - { 0, 0 } + { NULL, 0 } }; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2a9b363e820c..307e1f1107ca 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -246,7 +246,7 @@ static spinlock_t *rt_hash_locks; static struct rt_hash_bucket *rt_hash_table; static unsigned rt_hash_mask; -static int rt_hash_log; +static unsigned int rt_hash_log; static unsigned int rt_hash_rnd; static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); @@ -593,7 +593,7 @@ static void rt_check_expire(struct work_struct *work) i = (i + 1) & rt_hash_mask; rthp = &rt_hash_table[i].chain; - if (*rthp == 0) + if (*rthp == NULL) continue; spin_lock_bh(rt_hash_lock_addr(i)); while ((rth = *rthp) != NULL) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4268cd13ff9a..e8c39488cf58 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2704,7 +2704,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p) BUG_TRAP((int)tp->lost_out >= 0); BUG_TRAP((int)tp->retrans_out >= 0); if (!tp->packets_out && tcp_is_sack(tp)) { - const struct inet_connection_sock *icsk = inet_csk(sk); + icsk = inet_csk(sk); if (tp->lost_out) { printk(KERN_DEBUG "Leak l=%u %d\n", tp->lost_out, icsk->icsk_ca_state); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index d407992c1481..5810852c558a 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -414,7 +414,7 @@ static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr) break; read_unlock_bh(&idev->lock); in6_dev_put(idev); - return aca != 0; + return aca != NULL; } return 0; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index eb330a44bacd..532425db11fe 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -663,7 +663,7 @@ done: break; } gsf = kmalloc(optlen,GFP_KERNEL); - if (gsf == 0) { + if (!gsf) { retv = -ENOBUFS; break; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 8668ab3af32e..cc8d4e2a9531 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1407,7 +1407,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) /* we assume size > sizeof(ra) here */ skb = sock_alloc_send_skb(sk, size + LL_RESERVED_SPACE(dev), 1, &err); - if (skb == 0) + if (!skb) return NULL; skb_reserve(skb, LL_RESERVED_SPACE(dev)); @@ -2144,7 +2144,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, /* callers have the socket lock and a write lock on ipv6_sk_mc_lock, * so no other readers or writers of iml or its sflist */ - if (iml->sflist == 0) { + if (!iml->sflist) { /* any-source empty exclude case */ return ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0); } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index b761dbed8cec..d4acd283111b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -256,7 +256,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, break; case ND_OPT_PREFIX_INFO: ndopts->nd_opts_pi_end = nd_opt; - if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) + if (!ndopts->nd_opt_array[nd_opt->nd_opt_type]) ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; break; #ifdef CONFIG_IPV6_ROUTE_INFO diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index d4d5d2f271d2..9e98c6e567dd 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -592,7 +592,7 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, } else handle = gen_new_kid(ht, htid); - if (tb[TCA_U32_SEL-1] == 0 || + if (tb[TCA_U32_SEL-1] == NULL || RTA_PAYLOAD(tb[TCA_U32_SEL-1]) < sizeof(struct tc_u32_sel)) return -EINVAL; diff --git a/net/socket.c b/net/socket.c index bc16eee4dc80..d2336472f494 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1929,7 +1929,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, * kernel msghdr to use the kernel address space) */ - uaddr = (void __user *)msg_sys.msg_name; + uaddr = (__force void __user *)msg_sys.msg_name; uaddr_len = COMPAT_NAMELEN(msg); if (MSG_CMSG_COMPAT & flags) { err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE); From 14e3e07979c4384e45e751882292d3b38477e855 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 8 Oct 2007 00:06:32 -0700 Subject: [PATCH 1730/2804] [NET]: split dev_ifsioc() according to locking This always bugged me: dev_ioctl() called dev_ifsioc() either inside read_lock(dev_base_lock) or rtnl_lock(), depending on the ioctl being executed. This change moves the ioctls executed inside dev_base_lock to a new function, dev_ifsioc_locked(). Now the locking context is completely clear to the reader. Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- net/core/dev.c | 88 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 30 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 13a1bc5d3bfd..1aa07047826e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3083,9 +3083,9 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) } /* - * Perform the SIOCxIFxxx calls. + * Perform the SIOCxIFxxx calls, inside read_lock(dev_base_lock) */ -static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) +static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd) { int err; struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); @@ -3098,25 +3098,15 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) ifr->ifr_flags = dev_get_flags(dev); return 0; - case SIOCSIFFLAGS: /* Set interface flags */ - return dev_change_flags(dev, ifr->ifr_flags); - case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ifr->ifr_metric = 0; return 0; - case SIOCSIFMETRIC: /* Set the metric on the interface - (currently unused) */ - return -EOPNOTSUPP; - case SIOCGIFMTU: /* Get the MTU of a device */ ifr->ifr_mtu = dev->mtu; return 0; - case SIOCSIFMTU: /* Set the MTU of a device */ - return dev_set_mtu(dev, ifr->ifr_mtu); - case SIOCGIFHWADDR: if (!dev->addr_len) memset(ifr->ifr_hwaddr.sa_data, 0, sizeof ifr->ifr_hwaddr.sa_data); @@ -3126,6 +3116,61 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) ifr->ifr_hwaddr.sa_family = dev->type; return 0; + 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 SIOCGIFINDEX: + ifr->ifr_ifindex = dev->ifindex; + 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; + + } + return err; +} + +/* + * Perform the SIOCxIFxxx calls, inside rtnl_lock() + */ +static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) +{ + int err; + struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); + + if (!dev) + return -ENODEV; + + 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 SIOCSIFHWADDR: return dev_set_mac_address(dev, &ifr->ifr_hwaddr); @@ -3137,15 +3182,6 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); 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 SIOCSIFMAP: if (dev->set_config) { if (!netif_device_present(dev)) @@ -3172,14 +3208,6 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) return dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data, dev->addr_len, 1); - case SIOCGIFINDEX: - ifr->ifr_ifindex = dev->ifindex; - return 0; - - case SIOCGIFTXQLEN: - ifr->ifr_qlen = dev->tx_queue_len; - return 0; - case SIOCSIFTXQLEN: if (ifr->ifr_qlen < 0) return -EINVAL; @@ -3290,7 +3318,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) case SIOCGIFTXQLEN: dev_load(net, ifr.ifr_name); read_lock(&dev_base_lock); - ret = dev_ifsioc(net, &ifr, cmd); + ret = dev_ifsioc_locked(net, &ifr, cmd); read_unlock(&dev_base_lock); if (!ret) { if (colon) From 630e499724bda4ecb62b1f6652656e886f04197f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Villac=C3=ADs=20Lasso?= Date: Mon, 8 Oct 2007 01:07:28 -0700 Subject: [PATCH 1731/2804] [IRDA]: Oops fix for ksdazzle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a kernel oops triggered by the ksdazzle SIR driver. We need more space for input frames, and 2048 should be plenty of it. Signed-off-by: Alex Villacรญs Lasso Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/ksdazzle-sir.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index af60f2435a38..d01a28593ce2 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -1,7 +1,7 @@ /***************************************************************************** * * Filename: ksdazzle.c -* Version: 0.1.1 +* Version: 0.1.2 * Description: Irda KingSun Dazzle USB Dongle * Status: Experimental * Author: Alex Villacรญs Lasso @@ -113,6 +113,7 @@ MODULE_DEVICE_TABLE(usb, dongles); #define KINGSUN_REQ_SEND 0x09 #define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ +#define KINGSUN_RCV_MAX 2048 /* Max transfer we can receive */ struct ksdazzle_speedparams { __le32 baudrate; /* baud rate, little endian */ @@ -150,7 +151,7 @@ struct ksdazzle_cb { __u8 tx_payload[8]; struct urb *rx_urb; - __u8 rx_payload[8]; + __u8 *rx_buf; iobuff_t rx_unwrap_buff; struct usb_ctrlrequest *speed_setuprequest; @@ -440,7 +441,8 @@ static int ksdazzle_net_open(struct net_device *netdev) /* Start reception. */ usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), - kingsun->rx_payload, 8, ksdazzle_rcv_irq, kingsun, 1); + kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq, + kingsun, 1); kingsun->rx_urb->status = 0; err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); if (err) { @@ -641,6 +643,7 @@ static int ksdazzle_probe(struct usb_interface *intf, kingsun->tx_buf_clear_sent = 0; kingsun->rx_urb = NULL; + kingsun->rx_buf = NULL; kingsun->rx_unwrap_buff.in_frame = FALSE; kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; kingsun->rx_unwrap_buff.skb = NULL; @@ -651,6 +654,11 @@ static int ksdazzle_probe(struct usb_interface *intf, kingsun->speed_urb = NULL; kingsun->speedparams.baudrate = 0; + /* Allocate input buffer */ + kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL); + if (!kingsun->rx_buf) + goto free_mem; + /* Allocate output buffer */ kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); if (!kingsun->tx_buf_clear) @@ -714,6 +722,7 @@ static int ksdazzle_probe(struct usb_interface *intf, free_mem: kfree(kingsun->speed_setuprequest); kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_buf); free_netdev(net); err_out1: return ret; @@ -746,6 +755,7 @@ static void ksdazzle_disconnect(struct usb_interface *intf) kfree(kingsun->speed_setuprequest); kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_buf); free_netdev(kingsun->netdev); usb_set_intfdata(intf, NULL); From 405d8e5cbbe5aca20cc745046b70831bfc5e4a8f Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Mon, 8 Oct 2007 01:08:47 -0700 Subject: [PATCH 1732/2804] [TG3]: Fix ethtool autonegotiate flags. I recently noticed that when calling: # ethtool -s eth0 autoneg on on a 5722 (though I'm sure it's not specific to that card) that subsequent checks of the cards status looked like this: # ethtool eth0 Settings for eth0: Supported ports: [ MII ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Half 1000baseT/Full Supports auto-negotiation: Yes Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Half 1000baseT/Full Advertised auto-negotiation: No <---- This seems odd?!? Speed: 1000Mb/s Duplex: Full Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: on Supports Wake-on: g Wake-on: d Current message level: 0x000000ff (255) Link detected: yes I noticed that the following commit: commit 3600d918d870456ea8e7bb9d47f327de5c20f3d6 Author: Michael Chan Date: Thu Dec 7 00:21:48 2006 -0800 [TG3]: Allow partial speed advertisement. Honor the advertisement bitmask from ethtool. We used to always advertise the full capability when autoneg was set to on. changed things around so that ethtool speed settings were strictly followed. Unfortunately ethtool doesn't seem to set ADVERTISED_Autoneg in the advertising field (and maybe it shouldn't have to). I'd vote that it should be fixed there, but it should also be added here just in case someone using ethtool ioctls in their own application gets what they want. Adding that flag in tg3_set_settings seemed like the most logical place since the driver works fine on boot. This is just an issue when re-enabling autonegotiation, so we should probably nip it there. Signed-off-by: Andy Gospodarek Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b1e5660baf4a..1e0c9e0dc394 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8101,7 +8101,8 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->link_config.autoneg = cmd->autoneg; if (cmd->autoneg == AUTONEG_ENABLE) { - tp->link_config.advertising = cmd->advertising; + tp->link_config.advertising = (cmd->advertising | + ADVERTISED_Autoneg); tp->link_config.speed = SPEED_INVALID; tp->link_config.duplex = DUPLEX_INVALID; } else { From 57f20448032158ad00b1e74f479515c689998be9 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 8 Oct 2007 02:02:52 -0700 Subject: [PATCH 1733/2804] [AF_IUCV]: remove static declarations from header file. Signed-off-by: Heiko Carstens Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- include/net/iucv/af_iucv.h | 20 -------------------- net/iucv/af_iucv.c | 3 +++ 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index c661c6fd6fd5..2ce0c901eadf 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -74,28 +74,8 @@ struct iucv_sock_list { atomic_t autobind_name; }; -static void iucv_sock_destruct(struct sock *sk); -static void iucv_sock_cleanup_listen(struct sock *parent); -static void iucv_sock_kill(struct sock *sk); -static void iucv_sock_close(struct sock *sk); -static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, - int addr_len); -static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, - int alen, int flags); -static int iucv_sock_listen(struct socket *sock, int backlog); -static int iucv_sock_accept(struct socket *sock, struct socket *newsock, - int flags); -static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr, - int *len, int peer); -static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len); -static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len, int flags); unsigned int iucv_sock_poll(struct file *file, struct socket *sock, poll_table *wait); -static int iucv_sock_release(struct socket *sock); -static int iucv_sock_shutdown(struct socket *sock, int how); - void iucv_sock_link(struct iucv_sock_list *l, struct sock *s); void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *s); int iucv_sock_wait_state(struct sock *sk, int state, int state2, diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 53668585e947..65358722c397 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -41,6 +41,9 @@ static struct proto iucv_proto = { .obj_size = sizeof(struct iucv_sock), }; +static void iucv_sock_kill(struct sock *sk); +static void iucv_sock_close(struct sock *sk); + /* Call Back functions */ static void iucv_callback_rx(struct iucv_path *, struct iucv_message *); static void iucv_callback_txdone(struct iucv_path *, struct iucv_message *); From f0703c80e5156406ad947cb67fe277725b48080f Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Mon, 8 Oct 2007 02:03:31 -0700 Subject: [PATCH 1734/2804] [AF_IUCV]: postpone receival of iucv-packets AF_IUCV socket programs may waste Linux storage, because af_iucv allocates an skb whenever posted by the receive callback routine and receives the message immediately. Message receival is now postponed if data from previous callbacks has not yet been transferred to the receiving socket program. Instead a message handle is saved in a message queue as a reminder. Once messages could be given to the receiving socket program, there is an additional checking for entries in the message queue, followed by skb allocation and message receival if applicable. Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- include/net/iucv/af_iucv.h | 7 ++ net/iucv/af_iucv.c | 211 ++++++++++++++++++++++--------------- 2 files changed, 132 insertions(+), 86 deletions(-) diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index 2ce0c901eadf..85f80eadfa35 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -50,6 +50,12 @@ struct sockaddr_iucv { /* Common socket structures and functions */ +struct sock_msg_q { + struct iucv_path *path; + struct iucv_message msg; + struct list_head list; + spinlock_t lock; +}; #define iucv_sk(__sk) ((struct iucv_sock *) __sk) @@ -65,6 +71,7 @@ struct iucv_sock { struct iucv_path *path; struct sk_buff_head send_skb_q; struct sk_buff_head backlog_skb_q; + struct sock_msg_q message_q; unsigned int send_tag; }; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 65358722c397..43e01c8d382b 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -224,6 +224,8 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) INIT_LIST_HEAD(&iucv_sk(sk)->accept_q); spin_lock_init(&iucv_sk(sk)->accept_q_lock); skb_queue_head_init(&iucv_sk(sk)->send_skb_q); + INIT_LIST_HEAD(&iucv_sk(sk)->message_q.list); + spin_lock_init(&iucv_sk(sk)->message_q.lock); skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q); iucv_sk(sk)->send_tag = 0; @@ -673,6 +675,90 @@ out: return err; } +static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len) +{ + int dataleft, size, copied = 0; + struct sk_buff *nskb; + + dataleft = len; + while (dataleft) { + if (dataleft >= sk->sk_rcvbuf / 4) + size = sk->sk_rcvbuf / 4; + else + size = dataleft; + + nskb = alloc_skb(size, GFP_ATOMIC | GFP_DMA); + if (!nskb) + return -ENOMEM; + + memcpy(nskb->data, skb->data + copied, size); + copied += size; + dataleft -= size; + + skb_reset_transport_header(nskb); + skb_reset_network_header(nskb); + nskb->len = size; + + skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, nskb); + } + + return 0; +} + +static void iucv_process_message(struct sock *sk, struct sk_buff *skb, + struct iucv_path *path, + struct iucv_message *msg) +{ + int rc; + + if (msg->flags & IPRMDATA) { + skb->data = NULL; + skb->len = 0; + } else { + rc = iucv_message_receive(path, msg, 0, skb->data, + msg->length, NULL); + if (rc) { + kfree_skb(skb); + return; + } + if (skb->truesize >= sk->sk_rcvbuf / 4) { + rc = iucv_fragment_skb(sk, skb, msg->length); + kfree_skb(skb); + skb = NULL; + if (rc) { + iucv_path_sever(path, NULL); + return; + } + skb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q); + } else { + skb_reset_transport_header(skb); + skb_reset_network_header(skb); + skb->len = msg->length; + } + } + + if (sock_queue_rcv_skb(sk, skb)) + skb_queue_head(&iucv_sk(sk)->backlog_skb_q, skb); +} + +static void iucv_process_message_q(struct sock *sk) +{ + struct iucv_sock *iucv = iucv_sk(sk); + struct sk_buff *skb; + struct sock_msg_q *p, *n; + + list_for_each_entry_safe(p, n, &iucv->message_q.list, list) { + skb = alloc_skb(p->msg.length, GFP_ATOMIC | GFP_DMA); + if (!skb) + break; + iucv_process_message(sk, skb, p->path, &p->msg); + list_del(&p->list); + kfree(p); + if (!skb_queue_empty(&iucv->backlog_skb_q)) + break; + } +} + static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags) { @@ -684,8 +770,9 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, int err = 0; if ((sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED) && - skb_queue_empty(&iucv->backlog_skb_q) && - skb_queue_empty(&sk->sk_receive_queue)) + skb_queue_empty(&iucv->backlog_skb_q) && + skb_queue_empty(&sk->sk_receive_queue) && + list_empty(&iucv->message_q.list)) return 0; if (flags & (MSG_OOB)) @@ -724,16 +811,23 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, kfree_skb(skb); /* Queue backlog skbs */ - rskb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q); + rskb = skb_dequeue(&iucv->backlog_skb_q); while (rskb) { if (sock_queue_rcv_skb(sk, rskb)) { - skb_queue_head(&iucv_sk(sk)->backlog_skb_q, + skb_queue_head(&iucv->backlog_skb_q, rskb); break; } else { - rskb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q); + rskb = skb_dequeue(&iucv->backlog_skb_q); } } + if (skb_queue_empty(&iucv->backlog_skb_q)) { + spin_lock_bh(&iucv->message_q.lock); + if (!list_empty(&iucv->message_q.list)) + iucv_process_message_q(sk); + spin_unlock_bh(&iucv->message_q.lock); + } + } else skb_queue_head(&sk->sk_receive_queue, skb); @@ -975,99 +1069,44 @@ static void iucv_callback_connack(struct iucv_path *path, u8 ipuser[16]) sk->sk_state_change(sk); } -static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len, - struct sk_buff_head *fragmented_skb_q) -{ - int dataleft, size, copied = 0; - struct sk_buff *nskb; - - dataleft = len; - while (dataleft) { - if (dataleft >= sk->sk_rcvbuf / 4) - size = sk->sk_rcvbuf / 4; - else - size = dataleft; - - nskb = alloc_skb(size, GFP_ATOMIC | GFP_DMA); - if (!nskb) - return -ENOMEM; - - memcpy(nskb->data, skb->data + copied, size); - copied += size; - dataleft -= size; - - skb_reset_transport_header(nskb); - skb_reset_network_header(nskb); - nskb->len = size; - - skb_queue_tail(fragmented_skb_q, nskb); - } - - return 0; -} - static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg) { struct sock *sk = path->private; struct iucv_sock *iucv = iucv_sk(sk); - struct sk_buff *skb, *fskb; - struct sk_buff_head fragmented_skb_q; - int rc; - - skb_queue_head_init(&fragmented_skb_q); + struct sk_buff *skb; + struct sock_msg_q *save_msg; + int len; if (sk->sk_shutdown & RCV_SHUTDOWN) return; + if (!list_empty(&iucv->message_q.list) || + !skb_queue_empty(&iucv->backlog_skb_q)) + goto save_message; + + len = atomic_read(&sk->sk_rmem_alloc); + len += msg->length + sizeof(struct sk_buff); + if (len > sk->sk_rcvbuf) + goto save_message; + skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA); - if (!skb) { - iucv_path_sever(path, NULL); - return; - } + if (!skb) + goto save_message; - if (msg->flags & IPRMDATA) { - skb->data = NULL; - skb->len = 0; - } else { - rc = iucv_message_receive(path, msg, 0, skb->data, - msg->length, NULL); - if (rc) { - kfree_skb(skb); - return; - } - if (skb->truesize >= sk->sk_rcvbuf / 4) { - rc = iucv_fragment_skb(sk, skb, msg->length, - &fragmented_skb_q); - kfree_skb(skb); - skb = NULL; - if (rc) { - iucv_path_sever(path, NULL); - return; - } - } else { - skb_reset_transport_header(skb); - skb_reset_network_header(skb); - skb->len = msg->length; - } - } - /* Queue the fragmented skb */ - fskb = skb_dequeue(&fragmented_skb_q); - while (fskb) { - if (!skb_queue_empty(&iucv->backlog_skb_q)) - skb_queue_tail(&iucv->backlog_skb_q, fskb); - else if (sock_queue_rcv_skb(sk, fskb)) - skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, fskb); - fskb = skb_dequeue(&fragmented_skb_q); - } + spin_lock(&iucv->message_q.lock); + iucv_process_message(sk, skb, path, msg); + spin_unlock(&iucv->message_q.lock); - /* Queue the original skb if it exists (was not fragmented) */ - if (skb) { - if (!skb_queue_empty(&iucv->backlog_skb_q)) - skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, skb); - else if (sock_queue_rcv_skb(sk, skb)) - skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, skb); - } + return; +save_message: + save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA); + save_msg->path = path; + save_msg->msg = *msg; + + spin_lock(&iucv->message_q.lock); + list_add_tail(&save_msg->list, &iucv->message_q.list); + spin_unlock(&iucv->message_q.lock); } static void iucv_callback_txdone(struct iucv_path *path, From 4b7137ff8fb49d7bf22dfa248baa0d02ace2c43d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 8 Oct 2007 17:13:44 -0700 Subject: [PATCH 1735/2804] [IPSEC] esp: Remove keys from esp_data structure The keys are only used during initialisation so we don't need to carry them in esp_data. Since we don't have to allocate them again, there is no need to place a limit on the authentication key length anymore. This patch also kills the unused auth.icv member. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/esp.h | 7 ------- net/ipv4/esp4.c | 16 +++++----------- net/ipv6/esp6.c | 15 ++++----------- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/include/net/esp.h b/include/net/esp.h index d05d8d2c78f4..e793d769430e 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -13,8 +13,6 @@ struct esp_data /* Confidentiality */ struct { - u8 *key; /* Key */ - int key_len; /* Key length */ int padlen; /* 0..255 */ /* ivlen is offset from enc_data, where encrypted data start. * It is logically different of crypto_tfm_alg_ivsize(tfm). @@ -28,14 +26,9 @@ struct esp_data /* Integrity. It is active when icv_full_len != 0 */ struct { - u8 *key; /* Key */ - int key_len; /* Length of the key */ u8 *work_icv; int icv_full_len; int icv_trunc_len; - void (*icv)(struct esp_data*, - struct sk_buff *skb, - int offset, int len, u8 *icv); struct crypto_hash *tfm; } auth; }; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 98767a4f1185..d233e2e62500 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -343,11 +343,6 @@ static int esp_init_state(struct xfrm_state *x) struct crypto_blkcipher *tfm; u32 align; - /* null auth and encryption can have zero length keys */ - if (x->aalg) { - if (x->aalg->alg_key_len > 512) - goto error; - } if (x->ealg == NULL) goto error; @@ -359,15 +354,14 @@ static int esp_init_state(struct xfrm_state *x) struct xfrm_algo_desc *aalg_desc; struct crypto_hash *hash; - esp->auth.key = x->aalg->alg_key; - esp->auth.key_len = (x->aalg->alg_key_len+7)/8; hash = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(hash)) goto error; esp->auth.tfm = hash; - if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len)) + if (crypto_hash_setkey(hash, x->aalg->alg_key, + (x->aalg->alg_key_len + 7) / 8)) goto error; aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); @@ -389,8 +383,7 @@ static int esp_init_state(struct xfrm_state *x) if (!esp->auth.work_icv) goto error; } - esp->conf.key = x->ealg->alg_key; - esp->conf.key_len = (x->ealg->alg_key_len+7)/8; + tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) goto error; @@ -403,7 +396,8 @@ static int esp_init_state(struct xfrm_state *x) goto error; esp->conf.ivinitted = 0; } - if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) + if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key, + (x->ealg->alg_key_len + 7) / 8)) goto error; x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; if (x->props.mode == XFRM_MODE_TUNNEL) diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 2db31ce3c7e6..77281068d0f9 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -297,11 +297,6 @@ static int esp6_init_state(struct xfrm_state *x) struct esp_data *esp = NULL; struct crypto_blkcipher *tfm; - /* null auth and encryption can have zero length keys */ - if (x->aalg) { - if (x->aalg->alg_key_len > 512) - goto error; - } if (x->ealg == NULL) goto error; @@ -316,15 +311,14 @@ static int esp6_init_state(struct xfrm_state *x) struct xfrm_algo_desc *aalg_desc; struct crypto_hash *hash; - esp->auth.key = x->aalg->alg_key; - esp->auth.key_len = (x->aalg->alg_key_len+7)/8; hash = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(hash)) goto error; esp->auth.tfm = hash; - if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len)) + if (crypto_hash_setkey(hash, x->aalg->alg_key, + (x->aalg->alg_key_len + 7) / 8)) goto error; aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); @@ -346,8 +340,6 @@ static int esp6_init_state(struct xfrm_state *x) if (!esp->auth.work_icv) goto error; } - esp->conf.key = x->ealg->alg_key; - esp->conf.key_len = (x->ealg->alg_key_len+7)/8; tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) goto error; @@ -360,7 +352,8 @@ static int esp6_init_state(struct xfrm_state *x) goto error; esp->conf.ivinitted = 0; } - if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) + if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key, + (x->ealg->alg_key_len + 7) / 8)) goto error; x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; if (x->props.mode == XFRM_MODE_TUNNEL) From bc31d3b2c7d7f2a03721a05cb3c9a3ce8b1e2e5a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 8 Oct 2007 17:14:34 -0700 Subject: [PATCH 1736/2804] [IPSEC] ah: Remove keys from ah_data structure The keys are only used during initialisation so we don't need to carry them in esp_data. Since we don't have to allocate them again, there is no need to place a limit on the authentication key length anymore. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/ah.h | 2 -- net/ipv4/ah4.c | 9 ++------- net/ipv6/ah6.c | 9 ++------- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/include/net/ah.h b/include/net/ah.h index 8f257c159902..5e758c2b5dd5 100644 --- a/include/net/ah.h +++ b/include/net/ah.h @@ -9,8 +9,6 @@ struct ah_data { - u8 *key; - int key_len; u8 *work_icv; int icv_full_len; int icv_trunc_len; diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 39f6211f1496..dc1d8e871b24 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -219,10 +219,6 @@ static int ah_init_state(struct xfrm_state *x) if (!x->aalg) goto error; - /* null auth can use a zero length key */ - if (x->aalg->alg_key_len > 512) - goto error; - if (x->encap) goto error; @@ -230,14 +226,13 @@ static int ah_init_state(struct xfrm_state *x) if (ahp == NULL) return -ENOMEM; - ahp->key = x->aalg->alg_key; - ahp->key_len = (x->aalg->alg_key_len+7)/8; tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) goto error; ahp->tfm = tfm; - if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len)) + if (crypto_hash_setkey(tfm, x->aalg->alg_key, + (x->aalg->alg_key_len + 7) / 8)) goto error; /* diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 53f46ab6af70..69a2030407b8 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -429,10 +429,6 @@ static int ah6_init_state(struct xfrm_state *x) if (!x->aalg) goto error; - /* null auth can use a zero length key */ - if (x->aalg->alg_key_len > 512) - goto error; - if (x->encap) goto error; @@ -440,14 +436,13 @@ static int ah6_init_state(struct xfrm_state *x) if (ahp == NULL) return -ENOMEM; - ahp->key = x->aalg->alg_key; - ahp->key_len = (x->aalg->alg_key_len+7)/8; tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) goto error; ahp->tfm = tfm; - if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len)) + if (crypto_hash_setkey(tfm, x->aalg->alg_key, + (x->aalg->alg_key_len + 7) / 8)) goto error; /* From 406ef77c893ebd882209be4e393d64b01fe72054 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 8 Oct 2007 17:16:30 -0700 Subject: [PATCH 1737/2804] [IPSEC]: Move common output code to xfrm_output Most of the code in xfrm4_output_one and xfrm6_output_one are identical so this patch moves them into a common xfrm_output function which will live in net/xfrm. In fact this would seem to fix a bug as on IPv4 we never reset the network header after a transform which may upset netfilter later on. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/xfrm.h | 1 + net/ipv4/xfrm4_output.c | 40 +++------------------- net/ipv6/xfrm6_output.c | 45 +++---------------------- net/xfrm/Makefile | 2 +- net/xfrm/xfrm_output.c | 73 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 77 deletions(-) create mode 100644 net/xfrm/xfrm_output.c diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 760d2432be6b..f5147ddb818e 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1016,6 +1016,7 @@ extern void xfrm_replay_notify(struct xfrm_state *x, int event); extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); extern int xfrm_init_state(struct xfrm_state *x); +extern int xfrm_output(struct sk_buff *skb); extern int xfrm4_rcv(struct sk_buff *skb); extern int xfrm4_output(struct sk_buff *skb); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 44ef208a75cb..04805c7d79c3 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -41,58 +40,27 @@ out: return ret; } -static int xfrm4_output_one(struct sk_buff *skb) +static inline int xfrm4_output_one(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; int err; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - err = skb_checksum_help(skb); - if (err) - goto error_nolock; - } - if (x->props.mode == XFRM_MODE_TUNNEL) { err = xfrm4_tunnel_check_size(skb); if (err) goto error_nolock; } - do { - spin_lock_bh(&x->lock); - err = xfrm_state_check(x, skb); - if (err) - goto error; - - err = x->mode->output(x, skb); - if (err) - goto error; - - err = x->type->output(x, skb); - if (err) - goto error; - - x->curlft.bytes += skb->len; - x->curlft.packets++; - - spin_unlock_bh(&x->lock); - - if (!(skb->dst = dst_pop(dst))) { - err = -EHOSTUNREACH; - goto error_nolock; - } - dst = skb->dst; - x = dst->xfrm; - } while (x && (x->props.mode != XFRM_MODE_TUNNEL)); + err = xfrm_output(skb); + if (err) + goto error_nolock; IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; err = 0; out_exit: return err; -error: - spin_unlock_bh(&x->lock); error_nolock: kfree_skb(skb); goto out_exit; diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 56364a5f676a..f21596f89984 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -9,9 +9,9 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include -#include #include #include #include @@ -43,62 +43,27 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) return ret; } -static int xfrm6_output_one(struct sk_buff *skb) +static inline int xfrm6_output_one(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; int err; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - err = skb_checksum_help(skb); - if (err) - goto error_nolock; - } - if (x->props.mode == XFRM_MODE_TUNNEL) { err = xfrm6_tunnel_check_size(skb); if (err) goto error_nolock; } - do { - spin_lock_bh(&x->lock); - err = xfrm_state_check(x, skb); - if (err) - goto error; - - err = x->mode->output(x, skb); - if (err) - goto error; - - err = x->type->output(x, skb); - if (err) - goto error; - - x->curlft.bytes += skb->len; - x->curlft.packets++; - if (x->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) - x->lastused = get_seconds(); - - spin_unlock_bh(&x->lock); - - skb_reset_network_header(skb); - - if (!(skb->dst = dst_pop(dst))) { - err = -EHOSTUNREACH; - goto error_nolock; - } - dst = skb->dst; - x = dst->xfrm; - } while (x && (x->props.mode != XFRM_MODE_TUNNEL)); + err = xfrm_output(skb); + if (err) + goto error_nolock; IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; err = 0; out_exit: return err; -error: - spin_unlock_bh(&x->lock); error_nolock: kfree_skb(skb); goto out_exit; diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index de3c1a625a46..45744a3d3a51 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile @@ -3,6 +3,6 @@ # obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ - xfrm_input.o xfrm_algo.o + xfrm_input.o xfrm_output.o xfrm_algo.o obj-$(CONFIG_XFRM_USER) += xfrm_user.o diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c new file mode 100644 index 000000000000..75f289b488a7 --- /dev/null +++ b/net/xfrm/xfrm_output.c @@ -0,0 +1,73 @@ +/* + * xfrm_output.c - Common IPsec encapsulation code. + * + * Copyright (c) 2007 Herbert Xu + * + * 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 + +int xfrm_output(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + int err; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + err = skb_checksum_help(skb); + if (err) + goto error_nolock; + } + + do { + spin_lock_bh(&x->lock); + err = xfrm_state_check(x, skb); + if (err) + goto error; + + err = x->mode->output(x, skb); + if (err) + goto error; + + err = x->type->output(x, skb); + if (err) + goto error; + + x->curlft.bytes += skb->len; + x->curlft.packets++; + + if (x->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) + x->lastused = get_seconds(); + + spin_unlock_bh(&x->lock); + + skb_reset_network_header(skb); + + if (!(skb->dst = dst_pop(dst))) { + err = -EHOSTUNREACH; + goto error_nolock; + } + dst = skb->dst; + x = dst->xfrm; + } while (x && (x->props.mode != XFRM_MODE_TUNNEL)); + + err = 0; + +error_nolock: + return err; +error: + spin_unlock_bh(&x->lock); + goto error_nolock; +} +EXPORT_SYMBOL_GPL(xfrm_output); From 83815dea47cf3e98ccbb6aecda08cba1ba91208f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 8 Oct 2007 17:25:08 -0700 Subject: [PATCH 1738/2804] [IPSEC]: Move xfrm_state_check into xfrm_output.c The functions xfrm_state_check and xfrm_state_check_space are only used by the output code in xfrm_output.c so we can move them over. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/xfrm.h | 1 - net/xfrm/xfrm_output.c | 22 ++++++++++++++++++++++ net/xfrm/xfrm_state.c | 23 ----------------------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index f5147ddb818e..bb9193434eb3 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1013,7 +1013,6 @@ extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si); extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq); extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq); extern void xfrm_replay_notify(struct xfrm_state *x, int event); -extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); extern int xfrm_init_state(struct xfrm_state *x); extern int xfrm_output(struct sk_buff *skb); diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 75f289b488a7..5b1c978a323c 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -18,6 +18,28 @@ #include #include +static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) +{ + int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev) + - skb_headroom(skb); + + if (nhead > 0) + return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); + + /* Check tail too... */ + return 0; +} + +static int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb) +{ + int err = xfrm_state_check_expire(x); + if (err < 0) + goto err; + err = xfrm_state_check_space(x, skb); +err: + return err; +} + int xfrm_output(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 15734adc9367..0ecec34d265a 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1152,29 +1152,6 @@ int xfrm_state_check_expire(struct xfrm_state *x) } EXPORT_SYMBOL(xfrm_state_check_expire); -static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) -{ - int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev) - - skb_headroom(skb); - - if (nhead > 0) - return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); - - /* Check tail too... */ - return 0; -} - -int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb) -{ - int err = xfrm_state_check_expire(x); - if (err < 0) - goto err; - err = xfrm_state_check_space(x, skb); -err: - return err; -} -EXPORT_SYMBOL(xfrm_state_check); - struct xfrm_state * xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) From 436a0a402203d5a47d2edf7e4dde6c08a7257983 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 8 Oct 2007 17:25:53 -0700 Subject: [PATCH 1739/2804] [IPSEC]: Move output replay code into xfrm_output The replay counter is one of only two remaining things in the output code that requires a lock on the xfrm state (the other being the crypto). This patch moves it into the generic xfrm_output so we can remove the lock from the transforms themselves. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/xfrm.h | 20 +++++++++++++++++++- net/ipv4/ah4.c | 4 ++-- net/ipv4/esp4.c | 4 ++-- net/ipv6/ah6.c | 4 ++-- net/ipv6/esp6.c | 4 ++-- net/xfrm/xfrm_output.c | 5 +++++ 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index bb9193434eb3..a267725f9753 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -2,7 +2,6 @@ #define _NET_XFRM_H #include -#include #include #include #include @@ -16,6 +15,7 @@ #include #include +#include #include #include #include @@ -279,6 +279,7 @@ struct xfrm_type __u8 proto; __u8 flags; #define XFRM_TYPE_NON_FRAGMENT 1 +#define XFRM_TYPE_REPLAY_PROT 2 int (*init_state)(struct xfrm_state *x); void (*destructor)(struct xfrm_state *); @@ -419,6 +420,23 @@ extern int xfrm_unregister_km(struct xfrm_mgr *km); extern unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; +/* + * This structure is used for the duration where packets are being + * transformed by IPsec. As soon as the packet leaves IPsec the + * area beyond the generic IP part may be overwritten. + */ +struct xfrm_skb_cb { + union { + struct inet_skb_parm h4; + struct inet6_skb_parm h6; + } header; + + /* Sequence number for replay protection. */ + u64 seq; +}; + +#define XFRM_SKB_CB(__skb) ((struct xfrm_skb_cb *)&((__skb)->cb[0])) + /* Audit Information */ struct xfrm_audit { diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index dc1d8e871b24..58af298e1941 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -96,8 +96,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) ah->reserved = 0; ah->spi = x->id.spi; - ah->seq_no = htonl(++x->replay.oseq); - xfrm_aevent_doreplay(x); + ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) goto error; @@ -297,6 +296,7 @@ static struct xfrm_type ah_type = .description = "AH4", .owner = THIS_MODULE, .proto = IPPROTO_AH, + .flags = XFRM_TYPE_REPLAY_PROT, .init_state = ah_init_state, .destructor = ah_destroy, .input = ah_input, diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index d233e2e62500..0f62af9a7f15 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -95,8 +95,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->protocol = IPPROTO_ESP; esph->spi = x->id.spi; - esph->seq_no = htonl(++x->replay.oseq); - xfrm_aevent_doreplay(x); + esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); if (esp->conf.ivlen) { if (unlikely(!esp->conf.ivinitted)) { @@ -437,6 +436,7 @@ static struct xfrm_type esp_type = .description = "ESP4", .owner = THIS_MODULE, .proto = IPPROTO_ESP, + .flags = XFRM_TYPE_REPLAY_PROT, .init_state = esp_init_state, .destructor = esp_destroy, .get_mtu = esp4_get_mtu, diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 69a2030407b8..ae68a900f605 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -283,8 +283,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) ah->reserved = 0; ah->spi = x->id.spi; - ah->seq_no = htonl(++x->replay.oseq); - xfrm_aevent_doreplay(x); + ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); err = ah_mac_digest(ahp, skb, ah->auth_data); if (err) goto error_free_iph; @@ -506,6 +505,7 @@ static struct xfrm_type ah6_type = .description = "AH6", .owner = THIS_MODULE, .proto = IPPROTO_AH, + .flags = XFRM_TYPE_REPLAY_PROT, .init_state = ah6_init_state, .destructor = ah6_destroy, .input = ah6_input, diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 77281068d0f9..0c5fb81451b7 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -95,8 +95,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) *skb_network_header(skb) = IPPROTO_ESP; esph->spi = x->id.spi; - esph->seq_no = htonl(++x->replay.oseq); - xfrm_aevent_doreplay(x); + esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); if (esp->conf.ivlen) { if (unlikely(!esp->conf.ivinitted)) { @@ -373,6 +372,7 @@ static struct xfrm_type esp6_type = .description = "ESP6", .owner = THIS_MODULE, .proto = IPPROTO_ESP, + .flags = XFRM_TYPE_REPLAY_PROT, .init_state = esp6_init_state, .destructor = esp6_destroy, .get_mtu = esp6_get_mtu, diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 5b1c978a323c..20e789d8c63e 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -58,6 +58,11 @@ int xfrm_output(struct sk_buff *skb) if (err) goto error; + if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { + XFRM_SKB_CB(skb)->seq = ++x->replay.oseq; + xfrm_aevent_doreplay(x); + } + err = x->mode->output(x, skb); if (err) goto error; From cdf7e668d4327a33e11be04c4cb9bcc604eaaa0f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 8 Oct 2007 17:26:34 -0700 Subject: [PATCH 1740/2804] [IPSEC]: Unexport xfrm_replay_notify Now that the only callers of xfrm_replay_notify are in xfrm, we can remove the export. This patch also removes xfrm_aevent_doreplay since it's now called in just one spot. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/xfrm.h | 6 ------ net/xfrm/xfrm_output.c | 3 ++- net/xfrm/xfrm_state.c | 1 - 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index a267725f9753..064a4ca63476 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1163,12 +1163,6 @@ static inline int xfrm_aevent_is_on(void) return ret; } -static inline void xfrm_aevent_doreplay(struct xfrm_state *x) -{ - if (xfrm_aevent_is_on()) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); -} - #ifdef CONFIG_XFRM_MIGRATE static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig) { diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 20e789d8c63e..40d75eccddda 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -60,7 +60,8 @@ int xfrm_output(struct sk_buff *skb) if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { XFRM_SKB_CB(skb)->seq = ++x->replay.oseq; - xfrm_aevent_doreplay(x); + if (xfrm_aevent_is_on()) + xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); } err = x->mode->output(x, skb); diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 0ecec34d265a..a00745abaad3 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1397,7 +1397,6 @@ void xfrm_replay_notify(struct xfrm_state *x, int event) !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) x->xflags &= ~XFRM_TIME_DEFER; } -EXPORT_SYMBOL(xfrm_replay_notify); static void xfrm_replay_timer_handler(unsigned long data) { From 45b17f48eaf5e5ff4202454985557b3240141caa Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 8 Oct 2007 17:27:19 -0700 Subject: [PATCH 1741/2804] [IPSEC]: Move RO-specific output code into xfrm6_mode_ro.c The lastused update check in xfrm_output can be done just as well in the mode output function which is specific to RO. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv6/xfrm6_mode_ro.c | 4 ++++ net/xfrm/xfrm_output.c | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c index 6ad6d7ac6bd7..a15637384b20 100644 --- a/net/ipv6/xfrm6_mode_ro.c +++ b/net/ipv6/xfrm6_mode_ro.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,9 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) (prevhdr - x->props.header_len) - skb->data); skb_set_transport_header(skb, hdr_len); memmove(skb->data, iph, hdr_len); + + x->lastused = get_seconds(); + return 0; } diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 40d75eccddda..8c852119d190 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -75,9 +74,6 @@ int xfrm_output(struct sk_buff *skb) x->curlft.bytes += skb->len; x->curlft.packets++; - if (x->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) - x->lastused = get_seconds(); - spin_unlock_bh(&x->lock); skb_reset_network_header(skb); From 3607c44676583e80122c1fed23f34d003cdd6979 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Mon, 8 Oct 2007 20:28:47 -0700 Subject: [PATCH 1742/2804] [8021Q]: transfer dev_id from real device A net_device struct provides field dev_id. It is used for unique ipv6 generation in case of shared network cards (as for the OSA network cards of IBM System z). If VLAN devices are built on top of such shared network cards, this dev_id information needs to be transferred to the VLAN device. Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- net/8021q/vlan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index f2bee234d361..3fe4fc86055f 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -331,6 +331,9 @@ static int vlan_dev_init(struct net_device *dev) (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); + /* ipv6 shared card related stuff */ + dev->dev_id = real_dev->dev_id; + if (is_zero_ether_addr(dev->dev_addr)) memcpy(dev->dev_addr, real_dev->dev_addr, dev->addr_len); if (is_zero_ether_addr(dev->broadcast)) From d62a38d1ab350f787e4941e42a3d3e97971e38f5 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Mon, 8 Oct 2007 20:37:11 -0700 Subject: [PATCH 1743/2804] [ISDN]: Change I4L to use alloc_netdev(). Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/i4l/isdn_net.c | 169 +++++++++++++++++++----------------- drivers/isdn/i4l/isdn_ppp.c | 6 +- include/linux/isdn.h | 2 +- 3 files changed, 92 insertions(+), 85 deletions(-) diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 54546604656d..7c9cb7e19f2e 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -77,7 +77,7 @@ static __inline__ int isdn_net_device_started(isdn_net_dev *n) if (lp->master) dev = lp->master; else - dev = &n->dev; + dev = n->dev; return netif_running(dev); } @@ -90,7 +90,7 @@ static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp) if (lp->master) netif_wake_queue(lp->master); else - netif_wake_queue(&lp->netdev->dev); + netif_wake_queue(lp->netdev->dev); } /* @@ -102,7 +102,7 @@ static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp) if (lp->master) netif_stop_queue(lp->master); else - netif_stop_queue(&lp->netdev->dev); + netif_stop_queue(lp->netdev->dev); } /* @@ -287,7 +287,7 @@ isdn_net_unbind_channel(isdn_net_local * lp) BEWARE! This chunk of code cannot be called from hardware interrupt handler. I hope it is true. --ANK */ - qdisc_reset(lp->netdev->dev.qdisc); + qdisc_reset(lp->netdev->dev->qdisc); } lp->dialstate = 0; dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; @@ -345,27 +345,27 @@ isdn_net_autohup(void) l->chargetime += l->chargeint; if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) if (l->outgoing || l->hupflags & ISDN_INHUP) - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } else if (l->outgoing) { if (l->hupflags & ISDN_CHARGEHUP) { if (l->hupflags & ISDN_WAITCHARGE) { printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", l->name, l->hupflags); - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } else if (time_after(jiffies, l->chargetime + l->chargeint)) { printk(KERN_DEBUG "isdn_net: %s: chtime = %lu, chint = %d\n", l->name, l->chargetime, l->chargeint); - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } } else - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } else if (l->hupflags & ISDN_INHUP) - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) { - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); break; } } @@ -579,7 +579,7 @@ isdn_net_dial(void) if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", lp->name); - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); break; } anymore = 1; @@ -616,8 +616,8 @@ isdn_net_dial(void) s = "dial suppressed: isdn system stopped"; else s = "dial suppressed: dialmode `off'"; - isdn_net_unreachable(&p->dev, NULL, s); - isdn_net_hangup(&p->dev); + isdn_net_unreachable(p->dev, NULL, s); + isdn_net_hangup(p->dev); break; } cmd.driver = lp->isdn_device; @@ -633,7 +633,7 @@ isdn_net_dial(void) if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", lp->name); - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); break; } if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { @@ -644,8 +644,8 @@ isdn_net_dial(void) if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, NULL, "dial: timed out"); - isdn_net_hangup(&p->dev); + isdn_net_unreachable(p->dev, NULL, "dial: timed out"); + isdn_net_hangup(p->dev); break; } @@ -674,9 +674,9 @@ isdn_net_dial(void) if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, NULL, "dial: tried all numbers dialmax times"); + isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times"); } - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); break; } } @@ -758,7 +758,7 @@ isdn_net_dial(void) cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); isdn_command(&cmd); if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15) - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); else { anymore = 1; lp->dialstate++; @@ -781,7 +781,7 @@ isdn_net_dial(void) printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); #endif if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); else anymore = 1; break; @@ -1618,7 +1618,7 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) __be32 addr = 0; /* local ipv4 address */ __be32 mask = 0; /* local netmask */ - if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) { + if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) { /* take primary(first) address of interface */ struct in_ifaddr *ifa = in_dev->ifa_list; if (ifa != NULL) { @@ -1866,7 +1866,7 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb) isdn_net_local *lp = p->local; if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { - isdn_net_receive(&p->dev, skb); + isdn_net_receive(p->dev, skb); return 1; } } @@ -2506,6 +2506,42 @@ isdn_net_force_dial(char *name) return (isdn_net_force_dial_lp(p->local)); } +/* + * Helper for alloc_netdev() + */ +static void _isdn_setup(struct net_device *dev) +{ + isdn_net_local *lp = dev->priv; + + dev->flags = IFF_NOARP | IFF_POINTOPOINT; + lp->p_encap = ISDN_NET_ENCAP_RAWIP; + lp->magic = ISDN_NET_MAGIC; + lp->last = lp; + lp->next = lp; + lp->isdn_device = -1; + lp->isdn_channel = -1; + lp->pre_device = -1; + lp->pre_channel = -1; + lp->exclusive = -1; + lp->ppp_slot = -1; + lp->pppbind = -1; + skb_queue_head_init(&lp->super_tx_queue); + lp->l2_proto = ISDN_PROTO_L2_X75I; + lp->l3_proto = ISDN_PROTO_L3_TRANS; + lp->triggercps = 6000; + lp->slavedelay = 10 * HZ; + lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ + lp->onhtime = 10; /* Default hangup-time for saving costs */ + lp->dialmax = 1; + /* Hangup before Callback, manual dial */ + lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; + lp->cbdelay = 25; /* Wait 5 secs before Callback */ + lp->dialtimeout = -1; /* Infinite Dial-Timeout */ + lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ + lp->dialstarted = 0; /* Jiffies of last dial-start */ + lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ +} + /* * Allocate a new network-interface and initialize its data structures. */ @@ -2519,23 +2555,21 @@ isdn_net_new(char *name, struct net_device *master) printk(KERN_WARNING "isdn_net: interface %s already exists\n", name); return NULL; } + if (name == NULL) + name = " "; if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) { printk(KERN_WARNING "isdn_net: Could not allocate net-device\n"); return NULL; } - if (!(netdev->local = kzalloc(sizeof(isdn_net_local), GFP_KERNEL))) { - printk(KERN_WARNING "isdn_net: Could not allocate device locals\n"); + netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, _isdn_setup); + if (!netdev->dev) { + printk(KERN_WARNING "isdn_net: Could not allocate network device\n"); kfree(netdev); return NULL; } - if (name == NULL) - strcpy(netdev->local->name, " "); - else - strcpy(netdev->local->name, name); - strcpy(netdev->dev.name, netdev->local->name); - netdev->dev.priv = netdev->local; - netdev->dev.init = isdn_net_init; - netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP; + netdev->local = netdev->dev->priv; + strcpy(netdev->local->name, netdev->dev->name); + netdev->dev->init = isdn_net_init; if (master) { /* Device shall be a slave */ struct net_device *p = (((isdn_net_local *) master->priv)->slave); @@ -2547,60 +2581,33 @@ isdn_net_new(char *name, struct net_device *master) q = p; p = (((isdn_net_local *) p->priv)->slave); } - ((isdn_net_local *) q->priv)->slave = &(netdev->dev); + ((isdn_net_local *) q->priv)->slave = netdev->dev; } else { /* Device shall be a master */ /* * Watchdog timer (currently) for master only. */ - netdev->dev.tx_timeout = isdn_net_tx_timeout; - netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT; - if (register_netdev(&netdev->dev) != 0) { + netdev->dev->tx_timeout = isdn_net_tx_timeout; + netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT; + if (register_netdev(netdev->dev) != 0) { printk(KERN_WARNING "isdn_net: Could not register net-device\n"); - kfree(netdev->local); + free_netdev(netdev->dev); kfree(netdev); return NULL; } } - netdev->local->magic = ISDN_NET_MAGIC; - netdev->queue = netdev->local; spin_lock_init(&netdev->queue_lock); - netdev->local->last = netdev->local; netdev->local->netdev = netdev; - netdev->local->next = netdev->local; INIT_WORK(&netdev->local->tqueue, isdn_net_softint); spin_lock_init(&netdev->local->xmit_lock); - netdev->local->isdn_device = -1; - netdev->local->isdn_channel = -1; - netdev->local->pre_device = -1; - netdev->local->pre_channel = -1; - netdev->local->exclusive = -1; - netdev->local->ppp_slot = -1; - netdev->local->pppbind = -1; - skb_queue_head_init(&netdev->local->super_tx_queue); - netdev->local->l2_proto = ISDN_PROTO_L2_X75I; - netdev->local->l3_proto = ISDN_PROTO_L3_TRANS; - netdev->local->triggercps = 6000; - netdev->local->slavedelay = 10 * HZ; - netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ - netdev->local->onhtime = 10; /* Default hangup-time for saving costs - of those who forget configuring this */ - netdev->local->dialmax = 1; - netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */ - netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */ - netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */ - netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ - netdev->local->dialstarted = 0; /* Jiffies of last dial-start */ - netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ - /* Put into to netdev-chain */ netdev->next = (void *) dev->netdev; dev->netdev = netdev; - return netdev->dev.name; + return netdev->dev->name; } char * @@ -2625,7 +2632,7 @@ isdn_net_newslave(char *parm) /* Master must not be started yet */ if (isdn_net_device_started(n)) return NULL; - return (isdn_net_new(newname, &(n->dev))); + return (isdn_net_new(newname, n->dev)); } return NULL; } @@ -2694,9 +2701,9 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) lp->name); return -EINVAL; #else - p->dev.type = ARPHRD_PPP; /* change ARP type */ - p->dev.addr_len = 0; - p->dev.do_ioctl = isdn_ppp_dev_ioctl; + p->dev->type = ARPHRD_PPP; /* change ARP type */ + p->dev->addr_len = 0; + p->dev->do_ioctl = isdn_ppp_dev_ioctl; #endif break; case ISDN_NET_ENCAP_X25IFACE: @@ -2705,12 +2712,12 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) p->local->name); return -EINVAL; #else - p->dev.type = ARPHRD_X25; /* change ARP type */ - p->dev.addr_len = 0; + p->dev->type = ARPHRD_X25; /* change ARP type */ + p->dev->addr_len = 0; #endif break; case ISDN_NET_ENCAP_CISCOHDLCK: - p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl; + p->dev->do_ioctl = isdn_ciscohdlck_dev_ioctl; break; default: if( cfg->p_encap >= 0 && @@ -2837,14 +2844,14 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) } if (cfg->p_encap != lp->p_encap) { if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { - p->dev.header_ops = NULL; - p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; + p->dev->header_ops = NULL; + p->dev->flags = IFF_NOARP|IFF_POINTOPOINT; } else { - p->dev.header_ops = &isdn_header_ops; + p->dev->header_ops = &isdn_header_ops; if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) - p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; + p->dev->flags = IFF_BROADCAST | IFF_MULTICAST; else - p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; + p->dev->flags = IFF_NOARP|IFF_POINTOPOINT; } } lp->p_encap = cfg->p_encap; @@ -3064,7 +3071,7 @@ isdn_net_force_hangup(char *name) isdn_net_hangup(q); q = (((isdn_net_local *) q->priv)->slave); } - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); return 0; } return -ENODEV; @@ -3092,11 +3099,11 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel); if (p->local->master) { /* It's a slave-device, so update master's slave-pointer if necessary */ - if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev) + if (((isdn_net_local *) (p->local->master->priv))->slave == p->dev) ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave; } else { /* Unregister only if it's a master-device */ - unregister_netdev(&p->dev); + unregister_netdev(p->dev); } /* Unlink device from chain */ spin_lock_irqsave(&dev->lock, flags); @@ -3124,7 +3131,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) /* If no more net-devices remain, disable auto-hangup timer */ if (dev->netdev == NULL) isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); - kfree(p->local); + free_netdev(p->dev); kfree(p); return 0; diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 387392cb3d68..0e5e59f84344 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -360,7 +360,7 @@ isdn_ppp_release(int min, struct file *file) * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon() */ - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } for (i = 0; i < NUM_RCV_BUFFS; i++) { kfree(is->rq[i].buf); @@ -531,7 +531,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) if (lp) { /* OK .. we are ready to send buffers */ is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */ - netif_wake_queue(&lp->netdev->dev); + netif_wake_queue(lp->netdev->dev); break; } } @@ -1023,7 +1023,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto) { - struct net_device *dev = &net_dev->dev; + struct net_device *dev = net_dev->dev; struct ippp_struct *is, *mis; isdn_net_local *mlp = NULL; int slot; diff --git a/include/linux/isdn.h b/include/linux/isdn.h index a6fb366748bb..ad09506554a3 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -382,7 +382,7 @@ typedef struct isdn_net_dev_s { online */ spinlock_t queue_lock; /* lock to protect queue */ void *next; /* Pointer to next isdn-interface */ - struct net_device dev; /* interface to upper levels */ + struct net_device *dev; /* interface to upper levels */ #ifdef CONFIG_ISDN_PPP ippp_bundle * pb; /* pointer to the common bundle structure * with the per-bundle data */ From 4665079cbb2a3e17de82f2ab2940b9f97f37d65e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 8 Oct 2007 20:38:39 -0700 Subject: [PATCH 1744/2804] [NETNS]: Move some code into __init section when CONFIG_NET_NS=n With the net namespaces many code leaved the __init section, thus making the kernel occupy more memory than it did before. Since we have a config option that prohibits the namespace creation, the functions that initialize/finalize some netns stuff are simply not needed and can be freed after the boot. Currently, this is almost not noticeable, since few calls are no longer in __init, but when the namespaces will be merged it will be possible to free more code. I propose to use the __net_init, __net_exit and __net_initdata "attributes" for functions/variables that are not used if the CONFIG_NET_NS is not set to save more space in memory. The exiting functions cannot just reside in the __exit section, as noticed by David, since the init section will have references on it and the compilation will fail due to modpost checks. These references can exist, since the init namespace never dies and the exit callbacks are never called. So I introduce the __exit_refok attribute just like it is already done with the __init_refok. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- drivers/net/loopback.c | 6 +++--- fs/proc/proc_net.c | 8 ++++---- include/linux/init.h | 1 + include/net/net_namespace.h | 9 +++++++++ net/core/dev.c | 16 ++++++++-------- net/core/dev_mcast.c | 6 +++--- net/netlink/af_netlink.c | 6 +++--- scripts/mod/modpost.c | 1 + 8 files changed, 32 insertions(+), 21 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index d6997aec45dd..be25aa33971c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -250,7 +250,7 @@ static void loopback_setup(struct net_device *dev) } /* Setup and register the loopback device. */ -static int loopback_net_init(struct net *net) +static __net_init int loopback_net_init(struct net *net) { struct net_device *dev; int err; @@ -278,14 +278,14 @@ out_free_netdev: goto out; } -static void loopback_net_exit(struct net *net) +static __net_exit void loopback_net_exit(struct net *net) { struct net_device *dev = net->loopback_dev; unregister_netdev(dev); } -static struct pernet_operations loopback_net_ops = { +static struct pernet_operations __net_initdata loopback_net_ops = { .init = loopback_net_init, .exit = loopback_net_exit, }; diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 85cc8e8bb862..2e91fb756e9a 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -140,7 +140,7 @@ static struct inode_operations proc_net_dir_inode_operations = { .setattr = proc_net_setattr, }; -static int proc_net_ns_init(struct net *net) +static __net_init int proc_net_ns_init(struct net *net) { struct proc_dir_entry *root, *netd, *net_statd; int err; @@ -178,19 +178,19 @@ free_root: goto out; } -static void proc_net_ns_exit(struct net *net) +static __net_exit void proc_net_ns_exit(struct net *net) { remove_proc_entry("stat", net->proc_net); remove_proc_entry("net", net->proc_net_root); kfree(net->proc_net_root); } -struct pernet_operations proc_net_ns_ops = { +struct pernet_operations __net_initdata proc_net_ns_ops = { .init = proc_net_ns_init, .exit = proc_net_ns_exit, }; -int proc_net_init(void) +int __init proc_net_init(void) { proc_net_shadow = proc_mkdir("net", NULL); proc_net_shadow->proc_iops = &proc_net_dir_inode_operations; diff --git a/include/linux/init.h b/include/linux/init.h index 74b1f43bf982..f8d9d0b5cffc 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -57,6 +57,7 @@ * The markers follow same syntax rules as __init / __initdata. */ #define __init_refok noinline __attribute__ ((__section__ (".text.init.refok"))) #define __initdata_refok __attribute__ ((__section__ (".data.init.refok"))) +#define __exit_refok noinline __attribute__ ((__section__ (".exit.text.refok"))) #ifdef MODULE #define __exit __attribute__ ((__section__(".exit.text"))) __cold diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 934c840b5941..93aa87d32804 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -99,6 +99,15 @@ static inline void release_net(struct net *net) #define for_each_net(VAR) \ list_for_each_entry(VAR, &net_namespace_list, list) +#ifdef CONFIG_NET_NS +#define __net_init +#define __net_exit +#define __net_initdata +#else +#define __net_init __init +#define __net_exit __exit_refok +#define __net_initdata __initdata +#endif struct pernet_operations { struct list_head list; diff --git a/net/core/dev.c b/net/core/dev.c index 1aa07047826e..e7e728aea9f3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2611,7 +2611,7 @@ static const struct file_operations ptype_seq_fops = { }; -static int dev_proc_net_init(struct net *net) +static int __net_init dev_proc_net_init(struct net *net) { int rc = -ENOMEM; @@ -2636,7 +2636,7 @@ out_dev: goto out; } -static void dev_proc_net_exit(struct net *net) +static void __net_exit dev_proc_net_exit(struct net *net) { wext_proc_exit(net); @@ -2645,7 +2645,7 @@ static void dev_proc_net_exit(struct net *net) proc_net_remove(net, "dev"); } -static struct pernet_operations dev_proc_ops = { +static struct pernet_operations __net_initdata dev_proc_ops = { .init = dev_proc_net_init, .exit = dev_proc_net_exit, }; @@ -4278,7 +4278,7 @@ static struct hlist_head *netdev_create_hash(void) } /* Initialize per network namespace state */ -static int netdev_init(struct net *net) +static int __net_init netdev_init(struct net *net) { INIT_LIST_HEAD(&net->dev_base_head); rwlock_init(&dev_base_lock); @@ -4299,18 +4299,18 @@ err_name: return -ENOMEM; } -static void netdev_exit(struct net *net) +static void __net_exit netdev_exit(struct net *net) { kfree(net->dev_name_head); kfree(net->dev_index_head); } -static struct pernet_operations netdev_net_ops = { +static struct pernet_operations __net_initdata netdev_net_ops = { .init = netdev_init, .exit = netdev_exit, }; -static void default_device_exit(struct net *net) +static void __net_exit default_device_exit(struct net *net) { struct net_device *dev, *next; /* @@ -4336,7 +4336,7 @@ static void default_device_exit(struct net *net) rtnl_unlock(); } -static struct pernet_operations default_device_ops = { +static struct pernet_operations __net_initdata default_device_ops = { .exit = default_device_exit, }; diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 896b0ca5aed7..15241cf48af8 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -273,19 +273,19 @@ static const struct file_operations dev_mc_seq_fops = { #endif -static int dev_mc_net_init(struct net *net) +static int __net_init dev_mc_net_init(struct net *net) { if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops)) return -ENOMEM; return 0; } -static void dev_mc_net_exit(struct net *net) +static void __net_exit dev_mc_net_exit(struct net *net) { proc_net_remove(net, "dev_mcast"); } -static struct pernet_operations dev_mc_net_ops = { +static struct pernet_operations __net_initdata dev_mc_net_ops = { .init = dev_mc_net_init, .exit = dev_mc_net_exit, }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 46eb5ea1fbd7..3ef32825da71 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1924,7 +1924,7 @@ static struct net_proto_family netlink_family_ops = { .owner = THIS_MODULE, /* for consistency 8) */ }; -static int netlink_net_init(struct net *net) +static int __net_init netlink_net_init(struct net *net) { #ifdef CONFIG_PROC_FS if (!proc_net_fops_create(net, "netlink", 0, &netlink_seq_fops)) @@ -1933,14 +1933,14 @@ static int netlink_net_init(struct net *net) return 0; } -static void netlink_net_exit(struct net *net) +static void __net_exit netlink_net_exit(struct net *net) { #ifdef CONFIG_PROC_FS proc_net_remove(net, "netlink"); #endif } -static struct pernet_operations netlink_net_ops = { +static struct pernet_operations __net_initdata netlink_net_ops = { .init = netlink_net_init, .exit = netlink_net_exit, }; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 6c145d6e89de..0a4051fbd34e 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -709,6 +709,7 @@ static int secref_whitelist(const char *modname, const char *tosec, /* Check for pattern 0 */ if ((strncmp(fromsec, ".text.init.refok", strlen(".text.init.refok")) == 0) || + (strncmp(fromsec, ".exit.text.refok", strlen(".exit.text.refok")) == 0) || (strncmp(fromsec, ".data.init.refok", strlen(".data.init.refok")) == 0)) return 1; From 0a8891a0a419d43ea06c8ded0849f0820c6a873b Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Mon, 8 Oct 2007 20:39:36 -0700 Subject: [PATCH 1745/2804] [IPv6]: use container_of() macro in fib6_clean_node() In ip6_fib.c, fib6_clean_node() casts a fib6_walker_t pointer to a fib6_cleaner_t pointer assuming a struct fib6_walker_t (field 'w') is the first field in struct fib6_walker_t. To prevent any future problems that may occur if one day a field is inadvertently inserted before the 'w' field in struct fib6_cleaner_t, (and to improve readability), this patch uses the container_of() macro. Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 6a612a701eaa..946cf389ab95 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1313,7 +1313,7 @@ static int fib6_clean_node(struct fib6_walker_t *w) { int res; struct rt6_info *rt; - struct fib6_cleaner_t *c = (struct fib6_cleaner_t*)w; + struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w); for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) { res = c->func(rt, c->arg); From 32f0c4cbe495d121c09ed14d9c84f9e1b9574415 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 9 Oct 2007 13:02:17 -0700 Subject: [PATCH 1746/2804] [NETNS]: Don't memset() netns to zero manually The newly created net namespace is set to 0 with memset() in setup_net(). The setup_net() is also called for the init_net_ns(), which is zeroed naturally as a global var. So remove this memset and allocate new nets with the kmem_cache_zalloc(). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/core/net_namespace.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 0e0ca6d06fa5..6f71db8c4428 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -24,7 +24,7 @@ EXPORT_SYMBOL_GPL(init_net); static struct net *net_alloc(void) { - return kmem_cache_alloc(net_cachep, GFP_KERNEL); + return kmem_cache_zalloc(net_cachep, GFP_KERNEL); } static void net_free(struct net *net) @@ -90,7 +90,6 @@ static int setup_net(struct net *net) struct pernet_operations *ops; int error; - memset(net, 0, sizeof(struct net)); atomic_set(&net->count, 1); atomic_set(&net->use_count, 0); From 1ecafede835321ebdc396531245adc37d22366f7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 Oct 2007 13:24:07 -0700 Subject: [PATCH 1747/2804] [IPSEC]: Remove bogus ref count in xfrm_secpath_reject Constructs of the form xfrm_state_hold(x); foo(x); xfrm_state_put(x); tend to be broken because foo is either synchronous where this is totally unnecessary or if foo is asynchronous then the reference count is in the wrong spot. In the case of xfrm_secpath_reject, the function is synchronous and therefore we should just kill the reference count. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_policy.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 76f172f13f90..af27c193697c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1682,17 +1682,13 @@ static inline int xfrm_secpath_reject(int idx, struct sk_buff *skb, struct flowi *fl) { struct xfrm_state *x; - int err; if (!skb->sp || idx < 0 || idx >= skb->sp->len) return 0; x = skb->sp->xvec[idx]; if (!x->type->reject) return 0; - xfrm_state_hold(x); - err = x->type->reject(x, skb, fl); - xfrm_state_put(x); - return err; + return x->type->reject(x, skb, fl); } /* When skb is transformed back to its "native" form, we have to From 007f0211a8872f32381f5d44becf8eb2f27f3c30 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 Oct 2007 13:25:59 -0700 Subject: [PATCH 1748/2804] [IPSEC]: Store IPv6 nh pointer in mac_header on output Current the x->mode->output functions store the IPv6 nh pointer in the skb network header. This is inconvenient because the network header then has to be fixed up before the packet can leave the IPsec stack. The mac header field is unused on output so we can use that to store this instead. This patch does that and removes the network header fix-up in xfrm_output. It also uses ipv6_hdr where appropriate in the x->type->output functions. There is also a minor clean-up in esp4 to make it use the same code as esp6 to help any subsequent effort to merge the two. Lastly it kills two redundant skb_set_* statements in BEET that were simply copied over from transport mode. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/esp4.c | 2 +- net/ipv6/ah6.c | 6 +++--- net/ipv6/esp6.c | 7 ++++--- net/ipv6/ipcomp6.c | 6 +++--- net/ipv6/mip6.c | 12 ++++++------ net/ipv6/xfrm6_mode_beet.c | 16 +++++++--------- net/ipv6/xfrm6_mode_ro.c | 13 +++++++------ net/ipv6/xfrm6_mode_transport.c | 13 +++++++------ net/ipv6/xfrm6_mode_tunnel.c | 13 +++++++------ net/ipv6/xfrm6_tunnel.c | 2 +- net/xfrm/xfrm_output.c | 2 -- 11 files changed, 46 insertions(+), 46 deletions(-) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 0f62af9a7f15..ffd565350411 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -59,7 +59,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) tail[clen - skb->len - 2] = (clen - skb->len) - 2; pskb_put(skb, trailer, clen - skb->len); - __skb_push(skb, skb->data - skb_network_header(skb)); + __skb_push(skb, -skb_network_offset(skb)); top_iph = ip_hdr(skb); esph = (struct ip_esp_hdr *)(skb_network_header(skb) + top_iph->ihl * 4); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index ae68a900f605..ff904a711f3a 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -235,11 +235,11 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) char hdrs[0]; } *tmp_ext; - top_iph = (struct ipv6hdr *)skb->data; + top_iph = ipv6_hdr(skb); top_iph->payload_len = htons(skb->len - sizeof(*top_iph)); - nexthdr = *skb_network_header(skb); - *skb_network_header(skb) = IPPROTO_AH; + nexthdr = *skb_mac_header(skb); + *skb_mac_header(skb) = IPPROTO_AH; /* When there are no extension headers, we only need to save the first * 8 bytes of the base IP header. diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 0c5fb81451b7..9fc19400b851 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -88,11 +88,12 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) tail[clen-skb->len - 2] = (clen - skb->len) - 2; pskb_put(skb, trailer, clen - skb->len); - top_iph = (struct ipv6hdr *)__skb_push(skb, hdr_len); + __skb_push(skb, -skb_network_offset(skb)); + top_iph = ipv6_hdr(skb); esph = (struct ipv6_esp_hdr *)skb_transport_header(skb); top_iph->payload_len = htons(skb->len + alen - sizeof(*top_iph)); - *(skb_tail_pointer(trailer) - 1) = *skb_network_header(skb); - *skb_network_header(skb) = IPPROTO_ESP; + *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb); + *skb_mac_header(skb) = IPPROTO_ESP; esph->spi = x->id.spi; esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 91b2a75b7d09..71a14c09975c 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -157,15 +157,15 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) pskb_trim(skb, hdr_len + dlen + sizeof(struct ip_comp_hdr)); /* insert ipcomp header and replace datagram */ - top_iph = (struct ipv6hdr *)skb->data; + top_iph = ipv6_hdr(skb); top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); ipch = (struct ipv6_comp_hdr *)start; - ipch->nexthdr = *skb_network_header(skb); + ipch->nexthdr = *skb_mac_header(skb); ipch->flags = 0; ipch->cpi = htons((u16 )ntohl(x->id.spi)); - *skb_network_header(skb) = IPPROTO_COMP; + *skb_mac_header(skb) = IPPROTO_COMP; out_ok: return 0; diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 8a1399ce38ce..7261c29898cb 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -153,11 +153,11 @@ static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) u8 nexthdr; int len; - iph = (struct ipv6hdr *)skb->data; + iph = ipv6_hdr(skb); iph->payload_len = htons(skb->len - sizeof(*iph)); - nexthdr = *skb_network_header(skb); - *skb_network_header(skb) = IPPROTO_DSTOPTS; + nexthdr = *skb_mac_header(skb); + *skb_mac_header(skb) = IPPROTO_DSTOPTS; dstopt = (struct ipv6_destopt_hdr *)skb_transport_header(skb); dstopt->nexthdr = nexthdr; @@ -365,11 +365,11 @@ static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb) struct rt2_hdr *rt2; u8 nexthdr; - iph = (struct ipv6hdr *)skb->data; + iph = ipv6_hdr(skb); iph->payload_len = htons(skb->len - sizeof(*iph)); - nexthdr = *skb_network_header(skb); - *skb_network_header(skb) = IPPROTO_ROUTING; + nexthdr = *skb_mac_header(skb); + *skb_mac_header(skb) = IPPROTO_ROUTING; rt2 = (struct rt2_hdr *)skb_transport_header(skb); rt2->rt_hdr.nexthdr = nexthdr; diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index 2e61d6ddece3..65e6b2a7fb31 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c @@ -26,10 +26,11 @@ * payload_len * * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and skb->nh will be set to the nextheader field - * of the extension header directly preceding the encapsulation header, or in - * its absence, that of the top IP header. The value of skb->data will always - * point to the top IP header. + * filled in by x->type->output and the mac header will be set to the + * nextheader field of the extension header directly preceding the + * encapsulation header, or in its absence, that of the top IP header. + * The value of skb->data and the network header will always point to the + * top IP header. */ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -41,15 +42,12 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) iph = ipv6_hdr(skb); hdr_len = ip6_find_1stfragopt(skb, &prevhdr); - skb_set_network_header(skb, - (prevhdr - x->props.header_len) - skb->data); - skb_set_transport_header(skb, hdr_len); memmove(skb->data, iph, hdr_len); + skb_set_mac_header(skb, offsetof(struct ipv6hdr, nexthdr)); skb_reset_network_header(skb); + skb_set_transport_header(skb, sizeof(struct ipv6hdr)); top_iph = ipv6_hdr(skb); - skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); - skb->network_header += offsetof(struct ipv6hdr, nexthdr); ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c index a15637384b20..25758048af54 100644 --- a/net/ipv6/xfrm6_mode_ro.c +++ b/net/ipv6/xfrm6_mode_ro.c @@ -39,10 +39,11 @@ * space for the route optimization header. * * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and skb->nh will be set to the nextheader field - * of the extension header directly preceding the encapsulation header, or in - * its absence, that of the top IP header. The value of skb->data will always - * point to the top IP header. + * filled in by x->type->output and the mac header will be set to the + * nextheader field of the extension header directly preceding the + * encapsulation header, or in its absence, that of the top IP header. + * The value of skb->data and the network header will always point to the + * top IP header. */ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -54,8 +55,8 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) iph = ipv6_hdr(skb); hdr_len = x->type->hdr_offset(x, skb, &prevhdr); - skb_set_network_header(skb, - (prevhdr - x->props.header_len) - skb->data); + skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); + skb_reset_network_header(skb); skb_set_transport_header(skb, hdr_len); memmove(skb->data, iph, hdr_len); diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c index c026bfea820a..65c166b5d72c 100644 --- a/net/ipv6/xfrm6_mode_transport.c +++ b/net/ipv6/xfrm6_mode_transport.c @@ -20,10 +20,11 @@ * space for the encapsulation header. * * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and skb->nh will be set to the nextheader field - * of the extension header directly preceding the encapsulation header, or in - * its absence, that of the top IP header. The value of skb->data will always - * point to the top IP header. + * filled in by x->type->output and the mac header will be set to the + * nextheader field of the extension header directly preceding the + * encapsulation header, or in its absence, that of the top IP header. + * The value of skb->data and the network header will always point to the + * top IP header. */ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -35,8 +36,8 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) iph = ipv6_hdr(skb); hdr_len = x->type->hdr_offset(x, skb, &prevhdr); - skb_set_network_header(skb, - (prevhdr - x->props.header_len) - skb->data); + skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); + skb_reset_network_header(skb); skb_set_transport_header(skb, hdr_len); memmove(skb->data, iph, hdr_len); return 0; diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 9fc95bc6509f..3dd40af75e81 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -38,10 +38,11 @@ static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb) * payload_len * * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and skb->nh will be set to the nextheader field - * of the extension header directly preceding the encapsulation header, or in - * its absence, that of the top IP header. The value of skb->data will always - * point to the top IP header. + * filled in by x->type->output and the mac header will be set to the + * nextheader field of the extension header directly preceding the + * encapsulation header, or in its absence, that of the top IP header. + * The value of skb->data and the network header will always point to the + * top IP header. */ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -53,10 +54,10 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, x->props.header_len); iph = ipv6_hdr(skb); + skb_set_mac_header(skb, offsetof(struct ipv6hdr, nexthdr)); skb_reset_network_header(skb); + skb_set_transport_header(skb, sizeof(struct ipv6hdr)); top_iph = ipv6_hdr(skb); - skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); - skb->network_header += offsetof(struct ipv6hdr, nexthdr); top_iph->version = 6; if (xdst->route->ops->family == AF_INET6) { diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 30f3236c402a..aeb06076fdd0 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -244,7 +244,7 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *top_iph; - top_iph = (struct ipv6hdr *)skb->data; + top_iph = ipv6_hdr(skb); top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); return 0; diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 8c852119d190..9847baec4094 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -76,8 +76,6 @@ int xfrm_output(struct sk_buff *skb) spin_unlock_bh(&x->lock); - skb_reset_network_header(skb); - if (!(skb->dst = dst_pop(dst))) { err = -EHOSTUNREACH; goto error_nolock; From 75ba28c633952f7994a7117c98ae6515b58f8d30 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 Oct 2007 13:27:27 -0700 Subject: [PATCH 1749/2804] [IPSEC]: Remove gratuitous km wake-up events on ACQUIRE There is no point in waking people up when creating/updating larval states because they'll just go back to sleep again as larval states by definition cannot be found by xfrm_state_find. We should only wake them up when the larvals mature or die. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_state.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index a00745abaad3..0d07f6b92d26 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -848,7 +848,6 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re hlist_add_head(&x->bydst, xfrm_state_bydst+h); h = xfrm_src_hash(daddr, saddr, family); hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); - wake_up(&km_waitq); xfrm_state_num++; @@ -1311,7 +1310,6 @@ xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi) h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); hlist_add_head(&x->byspi, xfrm_state_byspi+h); spin_unlock_bh(&xfrm_state_lock); - wake_up(&km_waitq); } } EXPORT_SYMBOL(xfrm_alloc_spi); From 658b219e9379d75fbdc578b9630b598098471258 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 Oct 2007 13:29:52 -0700 Subject: [PATCH 1750/2804] [IPSEC]: Move common code into xfrm_alloc_spi This patch moves some common code that conceptually belongs to the xfrm core from af_key/xfrm_user into xfrm_alloc_spi. In particular, the spin lock on the state is now taken inside xfrm_alloc_spi. Previously it also protected the construction of the response PF_KEY/XFRM messages to user-space. This is inconsistent as other identical constructions are not protected by the state lock. This is bad because they in fact should be protected but only in certain spots (so as not to hold the lock for too long which may cause packet drops). The SPI byte order conversion has also been moved. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/xfrm.h | 2 +- net/key/af_key.c | 29 ++++++++++++----------------- net/xfrm/xfrm_state.c | 26 ++++++++++++++++++++------ net/xfrm/xfrm_user.c | 13 ++++--------- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 064a4ca63476..1c116dc03e0e 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1084,7 +1084,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete, int *err); int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); u32 xfrm_get_acqseq(void); -void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi); +extern int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family); diff --git a/net/key/af_key.c b/net/key/af_key.c index ff5c3d03005e..143d46f6329a 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1253,8 +1253,11 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h struct sadb_x_sa2 *sa2; struct sadb_address *saddr, *daddr; struct sadb_msg *out_hdr; + struct sadb_spirange *range; struct xfrm_state *x = NULL; int mode; + int err; + u32 min_spi, max_spi; u32 reqid; u8 proto; unsigned short family; @@ -1309,25 +1312,17 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h if (x == NULL) return -ENOENT; - resp_skb = ERR_PTR(-ENOENT); + min_spi = 0x100; + max_spi = 0x0fffffff; - spin_lock_bh(&x->lock); - if (x->km.state != XFRM_STATE_DEAD) { - struct sadb_spirange *range = ext_hdrs[SADB_EXT_SPIRANGE-1]; - u32 min_spi, max_spi; - - if (range != NULL) { - min_spi = range->sadb_spirange_min; - max_spi = range->sadb_spirange_max; - } else { - min_spi = 0x100; - max_spi = 0x0fffffff; - } - xfrm_alloc_spi(x, htonl(min_spi), htonl(max_spi)); - if (x->id.spi) - resp_skb = pfkey_xfrm_state2msg(x, 0, 3); + range = ext_hdrs[SADB_EXT_SPIRANGE-1]; + if (range) { + min_spi = range->sadb_spirange_min; + max_spi = range->sadb_spirange_max; } - spin_unlock_bh(&x->lock); + + err = xfrm_alloc_spi(x, min_spi, max_spi); + resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x, 0, 3); if (IS_ERR(resp_skb)) { xfrm_state_put(x); diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 0d07f6b92d26..344f0a6abec5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1275,26 +1275,33 @@ u32 xfrm_get_acqseq(void) } EXPORT_SYMBOL(xfrm_get_acqseq); -void -xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi) +int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) { unsigned int h; struct xfrm_state *x0; + int err = -ENOENT; + __be32 minspi = htonl(low); + __be32 maxspi = htonl(high); + spin_lock_bh(&x->lock); + if (x->km.state == XFRM_STATE_DEAD) + goto unlock; + + err = 0; if (x->id.spi) - return; + goto unlock; + + err = -ENOENT; if (minspi == maxspi) { x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); if (x0) { xfrm_state_put(x0); - return; + goto unlock; } x->id.spi = minspi; } else { u32 spi = 0; - u32 low = ntohl(minspi); - u32 high = ntohl(maxspi); for (h=0; hid.daddr, htonl(spi), x->id.proto, x->props.family); @@ -1310,7 +1317,14 @@ xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi) h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); hlist_add_head(&x->byspi, xfrm_state_byspi+h); spin_unlock_bh(&xfrm_state_lock); + + err = 0; } + +unlock: + spin_unlock_bh(&x->lock); + + return err; } EXPORT_SYMBOL(xfrm_alloc_spi); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 8e10e9098a83..52c7fce54641 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -784,16 +784,11 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, if (x == NULL) goto out_noput; - resp_skb = ERR_PTR(-ENOENT); - - spin_lock_bh(&x->lock); - if (x->km.state != XFRM_STATE_DEAD) { - xfrm_alloc_spi(x, htonl(p->min), htonl(p->max)); - if (x->id.spi) - resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); - } - spin_unlock_bh(&x->lock); + err = xfrm_alloc_spi(x, p->min, p->max); + if (err) + goto out; + resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); goto out; From 68325d3b12ad5bce650c2883bb878257f197efff Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 Oct 2007 13:30:57 -0700 Subject: [PATCH 1751/2804] [XFRM] user: Move attribute copying code into copy_to_user_state_extra Here's a good example of code duplication leading to code rot. The notification patch did its own netlink message creation for xfrm states. It duplicated code that was already in dump_one_state. Guess what, the next time (and the time after) when someone updated dump_one_state the notification path got zilch. This patch moves that code from dump_one_state to copy_to_user_state_extra and uses it in xfrm_notify_sa too. Unfortunately whoever updates this still needs to update xfrm_sa_len since the notification path wants to know the exact size for allocation. At least I've added a comment saying so and if someone still forgest, we'll have a WARN_ON telling us so. I also changed the security size calculation to use xfrm_user_sec_ctx since that's what we actually put into the skb. However it makes no practical difference since it has the same size as xfrm_sec_ctx. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 76 +++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 52c7fce54641..2cbbe5e93a7b 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -483,9 +483,9 @@ struct xfrm_dump_info { static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) { - int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; struct xfrm_user_sec_ctx *uctx; struct nlattr *attr; + int ctx_size = sizeof(*uctx) + s->ctx_len; attr = nla_reserve(skb, XFRMA_SEC_CTX, ctx_size); if (attr == NULL) @@ -502,23 +502,11 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) return 0; } -static int dump_one_state(struct xfrm_state *x, int count, void *ptr) +/* Don't change this without updating xfrm_sa_len! */ +static int copy_to_user_state_extra(struct xfrm_state *x, + struct xfrm_usersa_info *p, + struct sk_buff *skb) { - struct xfrm_dump_info *sp = ptr; - struct sk_buff *in_skb = sp->in_skb; - struct sk_buff *skb = sp->out_skb; - struct xfrm_usersa_info *p; - struct nlmsghdr *nlh; - - if (sp->this_idx < sp->start_idx) - goto out; - - nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, - XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); - if (nlh == NULL) - return -EMSGSIZE; - - p = nlmsg_data(nlh); copy_to_user_state(x, p); if (x->aalg) @@ -540,6 +528,35 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) if (x->lastused) NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int dump_one_state(struct xfrm_state *x, int count, void *ptr) +{ + struct xfrm_dump_info *sp = ptr; + struct sk_buff *in_skb = sp->in_skb; + struct sk_buff *skb = sp->out_skb; + struct xfrm_usersa_info *p; + struct nlmsghdr *nlh; + int err; + + if (sp->this_idx < sp->start_idx) + goto out; + + nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, + XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); + if (nlh == NULL) + return -EMSGSIZE; + + p = nlmsg_data(nlh); + + err = copy_to_user_state_extra(x, p, skb); + if (err) + goto nla_put_failure; + nlmsg_end(skb, nlh); out: sp->this_idx++; @@ -547,7 +564,7 @@ out: nla_put_failure: nlmsg_cancel(skb, nlh); - return -EMSGSIZE; + return err; } static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) @@ -1973,6 +1990,14 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) l += nla_total_size(sizeof(*x->calg)); if (x->encap) l += nla_total_size(sizeof(*x->encap)); + if (x->security) + l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + + x->security->ctx_len); + if (x->coaddr) + l += nla_total_size(sizeof(*x->coaddr)); + + /* Must count this as this may become non-zero behind our back. */ + l += nla_total_size(sizeof(x->lastused)); return l; } @@ -2018,23 +2043,16 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) p = nla_data(attr); } - copy_to_user_state(x, p); - - if (x->aalg) - NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg); - if (x->ealg) - NLA_PUT(skb, XFRMA_ALG_CRYPT, alg_len(x->ealg), x->ealg); - if (x->calg) - NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); - - if (x->encap) - NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); + if (copy_to_user_state_extra(x, p, skb)) + goto nla_put_failure; nlmsg_end(skb, nlh); return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); nla_put_failure: + /* Somebody screwed up with xfrm_sa_len! */ + WARN_ON(1); kfree_skb(skb); return -1; } From 050f009e16f908932070313c1745d09dc69fd62b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 Oct 2007 13:31:47 -0700 Subject: [PATCH 1752/2804] [IPSEC]: Lock state when copying non-atomic fields to user-space This patch adds locking so that when we're copying non-atomic fields such as life-time or coaddr to user-space we don't get a partial result. For af_key I've changed every instance of pfkey_xfrm_state2msg apart from expiration notification to include the keys and life-times. This is in-line with XFRM behaviour. The actual cases affected are: * pfkey_getspi: No change as we don't have any keys to copy. * key_notify_sa: + ADD/UPD: This wouldn't work otherwise. + DEL: It can't hurt. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/key/af_key.c | 35 +++++++++++++++++++++++++---------- net/xfrm/xfrm_user.c | 14 ++++++++------ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/net/key/af_key.c b/net/key/af_key.c index 143d46f6329a..7969f8a716df 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -655,7 +655,8 @@ static inline int pfkey_mode_to_xfrm(int mode) } } -static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc) +static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, + int add_keys, int hsc) { struct sk_buff *skb; struct sadb_msg *hdr; @@ -1009,6 +1010,24 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, return skb; } + +static inline struct sk_buff *pfkey_xfrm_state2msg(struct xfrm_state *x) +{ + struct sk_buff *skb; + + spin_lock_bh(&x->lock); + skb = __pfkey_xfrm_state2msg(x, 1, 3); + spin_unlock_bh(&x->lock); + + return skb; +} + +static inline struct sk_buff *pfkey_xfrm_state2msg_expire(struct xfrm_state *x, + int hsc) +{ + return __pfkey_xfrm_state2msg(x, 0, hsc); +} + static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, void **ext_hdrs) { @@ -1322,7 +1341,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h } err = xfrm_alloc_spi(x, min_spi, max_spi); - resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x, 0, 3); + resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x); if (IS_ERR(resp_skb)) { xfrm_state_put(x); @@ -1412,12 +1431,8 @@ static int key_notify_sa(struct xfrm_state *x, struct km_event *c) { struct sk_buff *skb; struct sadb_msg *hdr; - int hsc = 3; - if (c->event == XFRM_MSG_DELSA) - hsc = 0; - - skb = pfkey_xfrm_state2msg(x, 0, hsc); + skb = pfkey_xfrm_state2msg(x); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1529,7 +1544,7 @@ static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, if (x == NULL) return -ESRCH; - out_skb = pfkey_xfrm_state2msg(x, 1, 3); + out_skb = pfkey_xfrm_state2msg(x); proto = x->id.proto; xfrm_state_put(x); if (IS_ERR(out_skb)) @@ -1709,7 +1724,7 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr) struct sk_buff *out_skb; struct sadb_msg *out_hdr; - out_skb = pfkey_xfrm_state2msg(x, 1, 3); + out_skb = pfkey_xfrm_state2msg(x); if (IS_ERR(out_skb)) return PTR_ERR(out_skb); @@ -2910,7 +2925,7 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) else hsc = 1; - out_skb = pfkey_xfrm_state2msg(x, 0, hsc); + out_skb = pfkey_xfrm_state2msg_expire(x, hsc); if (IS_ERR(out_skb)) return PTR_ERR(out_skb); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 2cbbe5e93a7b..5238f6a8dfad 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -507,8 +507,16 @@ static int copy_to_user_state_extra(struct xfrm_state *x, struct xfrm_usersa_info *p, struct sk_buff *skb) { + spin_lock_bh(&x->lock); copy_to_user_state(x, p); + if (x->coaddr) + NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); + + if (x->lastused) + NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); + spin_unlock_bh(&x->lock); + if (x->aalg) NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg); if (x->ealg) @@ -522,12 +530,6 @@ static int copy_to_user_state_extra(struct xfrm_state *x, if (x->security && copy_sec_ctx(x->security, skb) < 0) goto nla_put_failure; - if (x->coaddr) - NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); - - if (x->lastused) - NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); - return 0; nla_put_failure: From b7c6538cd84f8072fad43bfce530f5bf695edbba Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 Oct 2007 13:33:35 -0700 Subject: [PATCH 1753/2804] [IPSEC]: Move state lock into x->type->output This patch releases the lock on the state before calling x->type->output. It also adds the lock to the spots where they're currently needed. Most of those places (all except mip6) are expected to disappear with async crypto. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ah4.c | 7 ++++++- net/ipv4/esp4.c | 10 ++++++++-- net/ipv6/ah6.c | 9 ++++++--- net/ipv6/esp6.c | 10 ++++++++-- net/ipv6/mip6.c | 4 ++++ net/xfrm/xfrm_output.c | 8 ++++---- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 58af298e1941..3513149c3843 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -97,10 +98,14 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + + spin_lock_bh(&x->lock); err = ah_mac_digest(ahp, skb, ah->auth_data); + memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); + spin_unlock_bh(&x->lock); + if (err) goto error; - memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index ffd565350411..452910dae89f 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,8 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->tot_len = htons(skb->len + alen); *(skb_tail_pointer(trailer) - 1) = top_iph->protocol; + spin_lock_bh(&x->lock); + /* this is non-NULL only with UDP Encapsulation */ if (x->encap) { struct xfrm_encap_tmpl *encap = x->encap; @@ -111,7 +114,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) - goto error; + goto unlock; } skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); err = crypto_blkcipher_encrypt(&desc, sg, sg, clen); @@ -120,7 +123,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) } while (0); if (unlikely(err)) - goto error; + goto unlock; if (esp->conf.ivlen) { memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen); @@ -133,6 +136,9 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen); } +unlock: + spin_unlock_bh(&x->lock); + ip_send_check(top_iph); error: diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index ff904a711f3a..c51d77564b44 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -284,12 +285,14 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + + spin_lock_bh(&x->lock); err = ah_mac_digest(ahp, skb, ah->auth_data); + memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); + spin_unlock_bh(&x->lock); + if (err) goto error_free_iph; - memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); - - err = 0; memcpy(top_iph, tmp_base, sizeof(tmp_base)); if (tmp_ext) { diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 9fc19400b851..7355bb0345e2 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) esph->spi = x->id.spi; esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + spin_lock_bh(&x->lock); + if (esp->conf.ivlen) { if (unlikely(!esp->conf.ivinitted)) { get_random_bytes(esp->conf.ivec, esp->conf.ivlen); @@ -112,7 +115,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) - goto error; + goto unlock; } skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); err = crypto_blkcipher_encrypt(&desc, sg, sg, clen); @@ -121,7 +124,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) } while (0); if (unlikely(err)) - goto error; + goto unlock; if (esp->conf.ivlen) { memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen); @@ -134,6 +137,9 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen); } +unlock: + spin_unlock_bh(&x->lock); + error: return err; } diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 7261c29898cb..6475baca63d2 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -172,7 +172,9 @@ static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) len = ((char *)hao - (char *)dstopt) + sizeof(*hao); memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr)); + spin_lock_bh(&x->lock); memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr)); + spin_unlock_bh(&x->lock); BUG_TRAP(len == x->props.header_len); dstopt->hdrlen = (x->props.header_len >> 3) - 1; @@ -381,7 +383,9 @@ static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb) BUG_TRAP(rt2->rt_hdr.hdrlen == 2); memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr)); + spin_lock_bh(&x->lock); memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr)); + spin_unlock_bh(&x->lock); return 0; } diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 9847baec4094..0eb3377602e9 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -67,15 +67,15 @@ int xfrm_output(struct sk_buff *skb) if (err) goto error; - err = x->type->output(x, skb); - if (err) - goto error; - x->curlft.bytes += skb->len; x->curlft.packets++; spin_unlock_bh(&x->lock); + err = x->type->output(x, skb); + if (err) + goto error_nolock; + if (!(skb->dst = dst_pop(dst))) { err = -EHOSTUNREACH; goto error_nolock; From 46232d29f4088d87cdc2ee94cc911aadbdf00d32 Mon Sep 17 00:00:00 2001 From: Stefan Lippers-Hollmann Date: Fri, 5 Oct 2007 23:42:51 +0200 Subject: [PATCH 1754/2804] [PATCH] hostap_cs: Add device ID for Telekom T-Sinus 111card This adds the PCMCIA device ID for the Deutsche Telekom T-Sinus 111card to hostap_cs. $ /sbin/lspcmcia -v [...] Socket 0 Device 0: [hostap_cs] (bus ID: 0.0) Configuration: state: on Product Name: T-Sinus 111card 2.0.0 Identification: manf_id: 0x01bf card_id: 0x3301 function: 6 (network) prod_id(1): "T-Sinus" (0x8c389dc1) prod_id(2): "111card" (0x6a23ac17) prod_id(3): --- (---) prod_id(4): "2.0.0" (0x92b9effb) Signed-off-by: Stefan Lippers-Hollmann Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index f9cf22bda42e..2f8ea077a9ea 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -822,6 +822,7 @@ static struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), + PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), From 61ef6062801b5ee8dcf18a90789713fbed249f1b Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 7 Oct 2007 16:24:26 +0100 Subject: [PATCH 1755/2804] [PATCH] zd1211rw: Add ID for TalkTalk SNU5630NS/05 Tested by Su-Jong You zd1211b chip 0471:1237 v4810 high 00-12-bf AL2230_RF pa0 g--N Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 721d737e8d21..b0684f965761 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(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 }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, From 04dd9d39b48636d2698049304fdfb9ca59a88b54 Mon Sep 17 00:00:00 2001 From: Marcin Juszkiewicz Date: Sun, 7 Oct 2007 20:51:08 +0200 Subject: [PATCH 1756/2804] [PATCH] Add Linksys card to HostAP driver Socket 1: product info: "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", "RevA" manfid: 0x0274, 0x3301 Signed-off-by: Marcin Juszkiewicz Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_cs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 2f8ea077a9ea..877d3bdd37a0 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -890,6 +890,10 @@ static struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_PROD_ID123( "corega", "WL PCCL-11", "ISL37300P", 0xa21501a, 0x59868926, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID1234( + "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", + "RevA", + 0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194), PCMCIA_DEVICE_NULL }; MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); From 0b5316769774d1dc2fdd702e095f9e6992af269a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 9 Oct 2007 13:55:24 -0400 Subject: [PATCH 1757/2804] [PATCH] ipw2200: batch non-user-requested scan result notifications ipw2200 makes extensive use of background scanning when unassociated or down. Unfortunately, the firmware sends scan completed events many times per second, which the driver pushes directly up to userspace. This needlessly wakes up processes listening for wireless events many times per second. Batch together scan completed events for non-user-requested scans and send them up to userspace every 4 seconds. Scan completed events resulting from an SIOCSIWSCAN call are pushed up without delay. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 56 ++++++++++++++++++++++++++++------ drivers/net/wireless/ipw2200.h | 3 ++ 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 2119a79dcc86..feb8fcbab2d5 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1740,8 +1740,10 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) if (disable_radio) { priv->status |= STATUS_RF_KILL_SW; - if (priv->workqueue) + if (priv->workqueue) { cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->scan_event); + } queue_work(priv->workqueue, &priv->down); } else { priv->status &= ~STATUS_RF_KILL_SW; @@ -1992,6 +1994,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) wake_up_interruptible(&priv->wait_command_queue); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->scan_event); schedule_work(&priv->link_down); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); handled |= IPW_INTA_BIT_RF_KILL_DONE; @@ -4343,6 +4346,37 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); } +static void ipw_scan_event(struct work_struct *work) +{ + union iwreq_data wrqu; + + struct ipw_priv *priv = + container_of(work, struct ipw_priv, scan_event.work); + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); +} + +static void handle_scan_event(struct ipw_priv *priv) +{ + /* Only userspace-requested scan completion events go out immediately */ + if (!priv->user_requested_scan) { + if (!delayed_work_pending(&priv->scan_event)) + queue_delayed_work(priv->workqueue, &priv->scan_event, + round_jiffies(msecs_to_jiffies(4000))); + } else { + union iwreq_data wrqu; + + priv->user_requested_scan = 0; + cancel_delayed_work(&priv->scan_event); + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); + } +} + /** * Handle host notification packet. * Called from interrupt routine @@ -4705,14 +4739,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, * on how the scan was initiated. User space can just * sync on periodic scan to get fresh data... * Jean II */ - if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) { - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->net_dev, SIOCGIWSCAN, - &wrqu, NULL); - } + if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) + handle_scan_event(priv); break; } @@ -9490,6 +9518,10 @@ static int ipw_wx_set_scan(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); struct iw_scan_req *req = (struct iw_scan_req *)extra; + mutex_lock(&priv->mutex); + priv->user_requested_scan = 1; + mutex_unlock(&priv->mutex); + if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { ipw_request_direct_scan(priv, req->essid, @@ -10668,6 +10700,7 @@ static void ipw_link_up(struct ipw_priv *priv) } cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->scan_event); ipw_reset_stats(priv); /* Ensure the rate is updated immediately */ priv->last_rate = ipw_get_current_rate(priv); @@ -10705,7 +10738,8 @@ static void ipw_link_down(struct ipw_priv *priv) if (!(priv->status & STATUS_EXIT_PENDING)) { /* Queue up another scan... */ queue_delayed_work(priv->workqueue, &priv->request_scan, 0); - } + } else + cancel_delayed_work(&priv->scan_event); } static void ipw_bg_link_down(struct work_struct *work) @@ -10735,6 +10769,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->up, ipw_bg_up); INIT_WORK(&priv->down, ipw_bg_down); INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); + INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event); INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan); INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); @@ -11766,6 +11801,7 @@ static void ipw_pci_remove(struct pci_dev *pdev) cancel_delayed_work(&priv->adhoc_check); cancel_delayed_work(&priv->gather_stats); cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->scan_event); cancel_delayed_work(&priv->rf_kill); cancel_delayed_work(&priv->scan_check); destroy_workqueue(priv->workqueue); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 9c973b96bb42..bec8e37a1738 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1287,6 +1287,8 @@ struct ipw_priv { struct iw_public_data wireless_data; + int user_requested_scan; + struct workqueue_struct *workqueue; struct delayed_work adhoc_check; @@ -1295,6 +1297,7 @@ struct ipw_priv { struct work_struct system_config; struct work_struct rx_replenish; struct delayed_work request_scan; + struct delayed_work scan_event; struct work_struct request_passive_scan; struct work_struct adapter_restart; struct delayed_work rf_kill; From c3cf60a97fa4258599d308c74e2ee7c502b72e2a Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Thu, 4 Oct 2007 00:04:07 -0400 Subject: [PATCH 1758/2804] [PATCH] rtl8187: Add device ID for HP wireless print kit usb dongle This adds the device ID for the HP wireless print kit usb dongle. Thanks to Thierry Merle for the patch to the original rtl8187 driver. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index b0a92f543da4..0ef887dd2867 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -36,6 +36,8 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { /* Netgear */ {USB_DEVICE(0x0846, 0x6100)}, {USB_DEVICE(0x0846, 0x6a00)}, + /* HP */ + {USB_DEVICE(0x03f0, 0xca02)}, {} }; From c109810318ef4d37e495f740e624b1a15b7a0818 Mon Sep 17 00:00:00 2001 From: Martti Huttunen Date: Thu, 4 Oct 2007 00:06:00 -0400 Subject: [PATCH 1759/2804] [PATCH] p54usb: Add device ID for Linksys WUSB54AG Add the device ID for Linksys WUSB54AG. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/p54usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c index 7446c39ce5d0..755482a5a938 100644 --- a/drivers/net/wireless/p54usb.c +++ b/drivers/net/wireless/p54usb.c @@ -62,6 +62,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ + {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ From 4abee4bbd771ce42b9a0a19be11264721aa0e3ed Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:11:46 +0200 Subject: [PATCH 1760/2804] [PATCH] rt2x00: Remove duplicate code in MAC & BSSID handling The various drivers contained duplicate code to handle the MAC and BSSID initialization correctly. This moves the address copy to little endian variables to rt2x00config. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 30 +++++-------------- drivers/net/wireless/rt2x00/rt2500pci.c | 30 +++++-------------- drivers/net/wireless/rt2x00/rt2500usb.c | 30 +++++-------------- drivers/net/wireless/rt2x00/rt2x00.h | 4 +-- drivers/net/wireless/rt2x00/rt2x00config.c | 32 ++++++++++++++++++-- drivers/net/wireless/rt2x00/rt61pci.c | 34 +++++++--------------- drivers/net/wireless/rt2x00/rt73usb.c | 34 +++++++--------------- 7 files changed, 76 insertions(+), 118 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index faa47111a579..7b2a85ade135 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -249,32 +249,18 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, + __le32 *mac) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, CSR3, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, + (2 * sizeof(__le32))); } -static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, + __le32 *bssid) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid, + (2 * sizeof(__le32))); } static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 842da900d7c1..63a7b3cdf0cd 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -249,32 +249,18 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, + __le32 *mac) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, CSR3, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, + (2 * sizeof(__le32))); } -static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, + __le32 *bssid) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid, + (2 * sizeof(__le32))); } static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 7aacc7b5c1b2..973f653ecfc2 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -254,32 +254,18 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { /* * Configuration handlers. */ -static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, + __le32 *mac) { - __le16 reg[3]; - - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, &mac, + (3 * sizeof(__le16))); } -static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, + __le32 *bssid) { - __le16 reg[3]; - - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg)); + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid, + (3 * sizeof(__le16))); } static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 6262d4e47c56..5d30ca6680b6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -408,8 +408,8 @@ struct rt2x00lib_ops { /* * Configuration handlers. */ - void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, u8 *mac); - void (*config_bssid) (struct rt2x00_dev *rt2x00dev, u8 *bssid); + void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac); + void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); void (*config_packet_filter) (struct rt2x00_dev *rt2x00dev, const unsigned int filter); void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 13b510687bcb..aeeaa0c14245 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -34,16 +34,44 @@ #include "rt2x00.h" #include "rt2x00lib.h" + +/* + * The MAC and BSSID addressess are simple array of bytes, + * these arrays are little endian, so when sending the addressess + * to the drivers, copy the it into a endian-signed variable. + * + * Note that all devices (except rt2500usb) have 32 bits + * register word sizes. This means that whatever variable we + * pass _must_ be a multiple of 32 bits. Otherwise the device + * might not accept what we are sending to it. + * This will also make it easier for the driver to write + * the data to the device. + * + * Also note that when NULL is passed as address the + * we will send 00:00:00:00:00 to the device to clear the address. + * This will prevent the device being confused when it wants + * to ACK frames or consideres itself associated. + */ void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac) { + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); if (mac) - rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, mac); + memcpy(®, mac, ETH_ALEN); + + rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, ®[0]); } void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) { + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); if (bssid) - rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid); + memcpy(®, bssid, ETH_ALEN); + + rt2x00dev->ops->lib->config_bssid(rt2x00dev, ®[0]); } void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 6aa517645b6a..5d31ced11149 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -274,42 +274,28 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac) { - __le32 reg[2]; u32 tmp; - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - tmp = le32_to_cpu(reg[1]); + tmp = le32_to_cpu(mac[1]); rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); - reg[1] = cpu_to_le32(tmp); + mac[1] = cpu_to_le32(tmp); - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, mac, + (2 * sizeof(__le32))); } -static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) { - __le32 reg[2]; u32 tmp; - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - tmp = le32_to_cpu(reg[1]); + tmp = le32_to_cpu(bssid[1]); rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); - reg[1] = cpu_to_le32(tmp); + bssid[1] = cpu_to_le32(tmp); - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid, + (2 * sizeof(__le32))); } static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ffed3ec5fb99..5fa697bfaa14 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -255,42 +255,28 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { /* * Configuration handlers. */ -static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac) { - __le32 reg[2]; u32 tmp; - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - tmp = le32_to_cpu(reg[1]); + tmp = le32_to_cpu(mac[1]); rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); - reg[1] = cpu_to_le32(tmp); + mac[1] = cpu_to_le32(tmp); - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac, + (2 * sizeof(__le32))); } -static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) { - __le32 reg[2]; u32 tmp; - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - tmp = le32_to_cpu(reg[1]); + tmp = le32_to_cpu(bssid[1]); rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); - reg[1] = cpu_to_le32(tmp); + bssid[1] = cpu_to_le32(tmp); - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid, + (2 * sizeof(__le32))); } static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) From 3a84732a5c9758a4bd59088787cac23508ef8b62 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:12:13 +0200 Subject: [PATCH 1761/2804] [PATCH] rt2x00: Remove radio check from rt2x00lib_toggle_rx Don't check if the radio is enabled in rt2x00lib_toggle_rx, this is required since the link tuner should be disabled when shutting down the device. The remaining calls inside the rt2x00lib_toggle_rx handler should deliver no problems when called while the radio is done. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0216096c88cd..b6a5c3481126 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -164,9 +164,6 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) { enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) - return; - /* * When we are disabling the RX, we should also stop the link tuner. */ From 6d7f9877a66a3abe0b04b63d1de4659919e21a92 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:12:42 +0200 Subject: [PATCH 1762/2804] [PATCH] rt2x00: Store "STARTED" state during suspend Store the started state into a new flag DEVICE_STARTED_SUSPEND and set this when suspending while the device was started. We can't check for is_interface_present() since only mac80211 knows if there are monitor interfaces present. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 5d30ca6680b6..d280d0ec9042 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -508,6 +508,7 @@ struct rt2x00_dev { #define CONFIG_EXTERNAL_LNA_BG 13 #define CONFIG_DOUBLE_ANTENNA 14 #define CONFIG_DISABLE_LINK_TUNING 15 +#define DEVICE_STARTED_SUSPEND 16 /* * Chipset identification. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b6a5c3481126..f25475318c9b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1088,12 +1088,13 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) */ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) goto exit; + __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); /* * Disable radio and unitialize all items * that must be recreated on resume. */ - rt2x00lib_disable_radio(rt2x00dev); + rt2x00mac_stop(rt2x00dev->hw); rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); @@ -1123,9 +1124,9 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) rt2x00debug_register(rt2x00dev); /* - * Only continue if mac80211 has open interfaces. + * Only continue if mac80211 had open interfaces. */ - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags)) return 0; /* From 483272f5ee968b25172b80bd2d27e37fef1dcc3a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:13:06 +0200 Subject: [PATCH 1763/2804] [PATCH] rt2x00: Move rt2x00dev flags into enumeration By putting the flags into a enumeration we can make it easier maintable since we don't have to assign numbers for each flag. This makes it easier to insert and remove flags. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 49 +++++++++++++++++++--------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index d280d0ec9042..82dfcd95bb26 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -440,6 +440,39 @@ struct rt2x00_ops { #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; +/* + * rt2x00 device flags + */ +enum rt2x00_flags { + /* + * Device state flags + */ + DEVICE_PRESENT, + DEVICE_REGISTERED_HW, + DEVICE_INITIALIZED, + DEVICE_STARTED, + DEVICE_STARTED_SUSPEND, + DEVICE_ENABLED_RADIO, + DEVICE_ENABLED_RADIO_HW, + + /* + * Driver features + */ + DRIVER_REQUIRE_FIRMWARE, + DRIVER_REQUIRE_BEACON_RING, + + /* + * Driver configuration + */ + CONFIG_SUPPORT_HW_BUTTON, + CONFIG_FRAME_TYPE, + CONFIG_RF_SEQUENCE, + CONFIG_EXTERNAL_LNA_A, + CONFIG_EXTERNAL_LNA_BG, + CONFIG_DOUBLE_ANTENNA, + CONFIG_DISABLE_LINK_TUNING, +}; + /* * rt2x00 device structure. */ @@ -493,22 +526,6 @@ struct rt2x00_dev { * of the device capabilities are stored. */ unsigned long flags; -#define DEVICE_PRESENT 1 -#define DEVICE_REGISTERED_HW 2 -#define DEVICE_INITIALIZED 3 -#define DEVICE_STARTED 4 -#define DEVICE_ENABLED_RADIO 5 -#define DEVICE_ENABLED_RADIO_HW 6 -#define DRIVER_REQUIRE_FIRMWARE 7 -#define DRIVER_REQUIRE_BEACON_RING 8 -#define CONFIG_SUPPORT_HW_BUTTON 9 -#define CONFIG_FRAME_TYPE 10 -#define CONFIG_RF_SEQUENCE 11 -#define CONFIG_EXTERNAL_LNA_A 12 -#define CONFIG_EXTERNAL_LNA_BG 13 -#define CONFIG_DOUBLE_ANTENNA 14 -#define CONFIG_DISABLE_LINK_TUNING 15 -#define DEVICE_STARTED_SUSPEND 16 /* * Chipset identification. From 5886d0dbf5b4226c6b6c8c44c555c5dd83c67b02 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:13:38 +0200 Subject: [PATCH 1764/2804] [PATCH] rt2x00: Don't use changed_flags inside configure_packet_filter We shouldn't use changed_flags when configuring the packet filter, we work directly with the total_flags which is safe enough since we already check if something has changed after we applied our packet filtering flag rules. Also make sure that when the packet filter is scheduled, the rt2x00dev->interface.filter is cleared to make sure the drivers will update the packet filter instead of failing at the check: *total_flags == rt2x00dev->interface.filter Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt2500pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt2500usb.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00.h | 2 -- drivers/net/wireless/rt2x00/rt2x00dev.c | 13 ++++++++++--- drivers/net/wireless/rt2x00/rt61pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt73usb.c | 4 ++-- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 7b2a85ade135..e3cac0f26d7b 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1497,8 +1497,8 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw, * - Some filters are set based on interface type. */ *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 63a7b3cdf0cd..5d982316b854 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1830,8 +1830,8 @@ static void rt2500pci_configure_filter(struct ieee80211_hw *hw, */ if (mc_count) *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 973f653ecfc2..3dbd381f1428 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1602,8 +1602,8 @@ static void rt2500usb_configure_filter(struct ieee80211_hw *hw, */ if (mc_count) *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 82dfcd95bb26..9bb5fb964a21 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -410,8 +410,6 @@ struct rt2x00lib_ops { */ void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac); void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); - void (*config_packet_filter) (struct rt2x00_dev *rt2x00dev, - const unsigned int filter); void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type); void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, struct ieee80211_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f25475318c9b..1e07c3938cb3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -276,11 +276,18 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, filter_work); + unsigned int filter = rt2x00dev->interface.filter; + + /* + * Since we had stored the filter inside interface.filter, + * we should now clear that field. Otherwise the driver will + * assume nothing has changed (*total_flags will be compared + * to interface.filter to determine if any action is required). + */ + rt2x00dev->interface.filter = 0; rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw, - rt2x00dev->interface.filter, - &rt2x00dev->interface.filter, - 0, NULL); + filter, &filter, 0, NULL); } /* diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 5d31ced11149..588b22b16419 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2389,8 +2389,8 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw, */ if (mc_count) *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 5fa697bfaa14..6d1635b5cd07 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1856,8 +1856,8 @@ static void rt73usb_configure_filter(struct ieee80211_hw *hw, */ if (mc_count) *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; From 81873e9ccd5731ca77027bdb32b34904e7af25d0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:14:06 +0200 Subject: [PATCH 1765/2804] [PATCH] rt2x00: Fix rfkill handling As reported by Modestas Vainius, enabling rkfill in 1 driver and disabling it in a second could cause a NULL pointer exception when the rfkill-disabled driver still sets the CONFIG_SUPPORT_HW_BUTTON flag. Furthermore, rfkill expects the timeout as a value in milliseconds instead of jiffies. Also increase the timeout to a second, since this 250ms would be overkill. Also the flag DEVICE_ENABLED_RADIO_HW is causing problems for devices which do not support the hardware button while rfkill is enabled in the driver. To remidy this we should inverse the flag and its meaning, rename the flag to DEVICE_DISABLED_RADIO_HW this means that by default the radio is enabled by the hardware button (if present) and can only be disabled explicitely. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 6 ++++-- drivers/net/wireless/rt2x00/rt2500pci.c | 6 ++++-- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00lib.h | 10 ++-------- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 4 ++-- drivers/net/wireless/rt2x00/rt61pci.c | 6 ++++-- 7 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index e3cac0f26d7b..28999ffaba2e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -244,6 +244,8 @@ 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_RT2400PCI_RFKILL */ /* @@ -1359,8 +1361,10 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ +#ifdef CONFIG_RT2400PCI_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); +#endif /* CONFIG_RT2400PCI_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1625,9 +1629,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, .set_device_state = rt2400pci_set_device_state, -#ifdef CONFIG_RT2400PCI_RFKILL .rfkill_poll = rt2400pci_rfkill_poll, -#endif /* CONFIG_RT2400PCI_RFKILL */ .link_stats = rt2400pci_link_stats, .reset_tuner = rt2400pci_reset_tuner, .link_tuner = rt2400pci_link_tuner, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 5d982316b854..9d9b4377a6f2 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -244,6 +244,8 @@ 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_RT2500PCI_RFKILL */ /* @@ -1530,8 +1532,10 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ +#ifdef CONFIG_RT2500PCI_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); +#endif /* CONFIG_RT2500PCI_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1937,9 +1941,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, .set_device_state = rt2500pci_set_device_state, -#ifdef CONFIG_RT2500PCI_RFKILL .rfkill_poll = rt2500pci_rfkill_poll, -#endif /* CONFIG_RT2500PCI_RFKILL */ .link_stats = rt2500pci_link_stats, .reset_tuner = rt2500pci_reset_tuner, .link_tuner = rt2500pci_link_tuner, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9bb5fb964a21..235e5ad21908 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -451,7 +451,7 @@ enum rt2x00_flags { DEVICE_STARTED, DEVICE_STARTED_SUSPEND, DEVICE_ENABLED_RADIO, - DEVICE_ENABLED_RADIO_HW, + DEVICE_DISABLED_RADIO_HW, /* * Driver features diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 1e07c3938cb3..6dc4f63aef0a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -104,8 +104,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * And check if the hardware button has been disabled. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && - !test_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags))) + test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags)) return 0; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 6dd92eb2b223..0ab39cad3cc8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -28,9 +28,10 @@ /* * Interval defines + * Both the link tuner as the rfkill will be called once per second. */ #define LINK_TUNE_INTERVAL ( round_jiffies(HZ) ) -#define RFKILL_POLL_INTERVAL ( HZ / 4 ) +#define RFKILL_POLL_INTERVAL ( 1000 ) /* * Radio control handlers. @@ -98,13 +99,6 @@ void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); #else static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { - /* - * Force enable this flag, this will assure that - * devices with a hardware button but without rfkill support - * can still use their hardware. - */ - __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); - return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 06af01451cde..a0f8b8e0a24b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -52,11 +52,11 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) if (state == RFKILL_STATE_ON) { INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); - __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); retval = rt2x00lib_enable_radio(rt2x00dev); } else if (state == RFKILL_STATE_OFF) { INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); - __clear_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); rt2x00lib_disable_radio(rt2x00dev); } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 588b22b16419..1c3937a3f9dc 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -269,6 +269,8 @@ 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_RT61PCI_RFKILL */ /* @@ -2090,8 +2092,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ +#ifdef CONFIG_RT61PCI_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); +#endif /* CONFIG_RT61PCI_RFKILL */ /* * Read frequency offset and RF programming sequence. @@ -2531,9 +2535,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, .set_device_state = rt61pci_set_device_state, -#ifdef CONFIG_RT61PCI_RFKILL .rfkill_poll = rt61pci_rfkill_poll, -#endif /* CONFIG_RT61PCI_RFKILL */ .link_stats = rt61pci_link_stats, .reset_tuner = rt61pci_reset_tuner, .link_tuner = rt61pci_link_tuner, From feb24691e3e87a740caec4568be1a202db786f20 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:14:29 +0200 Subject: [PATCH 1766/2804] [PATCH] rt2x00: Move TSF sync values into rt2x00config All drivers use the same values for TSF sync, this will move the value determination into rt2x00config.c, and the definition for the values to rt2x00reg.h Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 12 +++--------- drivers/net/wireless/rt2x00/rt2500pci.c | 12 +++--------- drivers/net/wireless/rt2x00/rt2500usb.c | 14 ++++---------- drivers/net/wireless/rt2x00/rt2x00.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00config.c | 20 +++++++++++++++++--- drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +- drivers/net/wireless/rt2x00/rt2x00reg.h | 9 +++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 12 +++--------- drivers/net/wireless/rt2x00/rt73usb.c | 12 +++--------- 9 files changed, 45 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 28999ffaba2e..0e345659f421 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -265,9 +265,9 @@ static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, (2 * sizeof(__le32))); } -static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) +static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); @@ -287,13 +287,7 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else - rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); + rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 9d9b4377a6f2..fa8669f5c965 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -265,9 +265,9 @@ static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, (2 * sizeof(__le32))); } -static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); @@ -291,13 +291,7 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else - rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); + rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3dbd381f1428..6d5444b58e6c 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -268,9 +268,9 @@ static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, (3 * sizeof(__le16))); } -static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u16 reg; rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); @@ -281,7 +281,7 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); - if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) + if (type == IEEE80211_IF_TYPE_STA) rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); else rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2); @@ -298,13 +298,7 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1); - else - rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, tsf_sync); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 235e5ad21908..27bec6ec33df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -410,7 +410,8 @@ struct rt2x00lib_ops { */ void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac); void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); - void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type); + void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync); void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, struct ieee80211_conf *conf); #define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index aeeaa0c14245..f8e87aa86335 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -74,10 +74,24 @@ void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00dev->ops->lib->config_bssid(rt2x00dev, ®[0]); } -void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) +void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) { - if (type != INVALID_INTERFACE) - rt2x00dev->ops->lib->config_type(rt2x00dev, type); + int tsf_sync; + + switch (type) { + case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_AP: + tsf_sync = TSF_SYNC_BEACON; + break; + case IEEE80211_IF_TYPE_STA: + tsf_sync = TSF_SYNC_INFRA; + break; + default: + tsf_sync = TSF_SYNC_NONE; + break; + } + + rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync); } void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 0ab39cad3cc8..29ca932d77ab 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -52,7 +52,7 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); */ void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); -void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); +void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config); diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 7927d5f7bcc7..838421216da0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -58,6 +58,15 @@ enum led_mode { LED_MODE_ALPHA = 4, }; +/* + * TSF sync values + */ +enum tsf_sync { + TSF_SYNC_NONE = 0, + TSF_SYNC_INFRA = 1, + TSF_SYNC_BEACON = 2, +}; + /* * Device states */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 1c3937a3f9dc..1c0789f2a411 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -300,9 +300,9 @@ static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) (2 * sizeof(__le32))); } -static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -324,13 +324,7 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6d1635b5cd07..919cca593bc1 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -279,9 +279,9 @@ static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) (2 * sizeof(__le32))); } -static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -303,13 +303,7 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } From a137e202b0e47bca301d2315cca5c08140409ed7 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:14:58 +0200 Subject: [PATCH 1767/2804] [PATCH] rt2x00: get_duration expects values in 100kbs get_duration expects all speeds to be passed in 100kbs, this means that passing 2 is incorrect and should be raised to 20 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0e345659f421..bfab5a165b76 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -277,7 +277,7 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); rt2x00_set_field32(®, BCNCSR1_PRELOAD, - PREAMBLE + get_duration(IEEE80211_HEADER, 2)); + PREAMBLE + get_duration(IEEE80211_HEADER, 20)); rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index fa8669f5c965..c8c6a848be97 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -277,7 +277,7 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); rt2x00_set_field32(®, BCNCSR1_PRELOAD, - PREAMBLE + get_duration(IEEE80211_HEADER, 2)); + PREAMBLE + get_duration(IEEE80211_HEADER, 20)); rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 6d5444b58e6c..c70c677b3f73 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -280,7 +280,7 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, - (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); + (PREAMBLE + get_duration(IEEE80211_HEADER, 20)) >> 6); if (type == IEEE80211_IF_TYPE_STA) rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); else From 9ee8f57e0adfd929759fee1ec6a7900ae6851bc5 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:15:20 +0200 Subject: [PATCH 1768/2804] [PATCH] rt2x00: Cut lines down to 80 characters rt61pci contained 1 line of 88 characters width, this needs to be cut down. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 1c0789f2a411..8011523962a6 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2497,7 +2497,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0, skb->data, skb->len); + rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0, + skb->data, skb->len); rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); return 0; From dd9fa2d21aebbb618318954867c5dfe3751328be Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:15:46 +0200 Subject: [PATCH 1769/2804] [PATCH] rt2x00: Add get_tx_data_len callback function The TX datalen must always be converted to a value rt73 and rt2500usb understand. Both require to use a different size then skb->len. First off this is required because the descriptor must be added, but the second is because the value must be a multiple of either 2 or 4, and it should not be a multiple of the USB packetmax Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 32 ++++++++++++++++--------- drivers/net/wireless/rt2x00/rt2x00.h | 2 ++ drivers/net/wireless/rt2x00/rt2x00usb.c | 29 ++++++++++++---------- drivers/net/wireless/rt2x00/rt73usb.c | 16 +++++++++++++ 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c70c677b3f73..f536ff1b5c47 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1057,6 +1057,21 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 0, word); } +static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, + int maxpacket, struct sk_buff *skb) +{ + int length; + + /* + * The length _must_ be a multiple of 2, + * but it must _not_ be a multiple of the USB packet size. + */ + length = roundup(skb->len, 2); + length += (2 * !(length % maxpacket)); + + return length; +} + /* * TX data initialization */ @@ -1653,6 +1668,8 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); struct data_entry *beacon; struct data_entry *guardian; + int pipe = usb_sndbulkpipe(usb_dev, 1); + int max_packet = usb_maxpacket(usb_dev, pipe, 1); int length; /* @@ -1679,16 +1696,9 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, ring->desc_size), skb->len - ring->desc_size, control); - /* - * Length passed to usb_fill_urb cannot be an odd number, - * so add 1 byte to make it even. - */ - length = skb->len; - if (length % 2) - length++; + length = rt2500usb_get_tx_data_len(rt2x00dev, max_packet, skb); - usb_fill_bulk_urb(beacon->priv, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_fill_bulk_urb(beacon->priv, usb_dev, pipe, skb->data, length, rt2500usb_beacondone, beacon); beacon->skb = skb; @@ -1699,8 +1709,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * the 'flags' field we are not using for beacons. */ guardian->flags = 0; - usb_fill_bulk_urb(guardian->priv, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_fill_bulk_urb(guardian->priv, usb_dev, pipe, &guardian->flags, 1, rt2500usb_beacondone, guardian); /* @@ -1741,6 +1750,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .link_tuner = rt2500usb_link_tuner, .write_tx_desc = rt2500usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, + .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2500usb_kick_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, .config_mac_addr = rt2500usb_config_mac_addr, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 27bec6ec33df..a392e2a9d087 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -396,6 +396,8 @@ struct rt2x00lib_ops { int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, struct data_ring *ring, struct sk_buff *skb, struct ieee80211_tx_control *control); + int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, int maxpacket, + struct sk_buff *skb); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, unsigned int queue); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 66e47615f2a6..73cc726c4046 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -157,9 +157,10 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, { struct usb_device *usb_dev = interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; struct data_entry *entry = rt2x00_get_data_entry(ring); - u32 length = skb->len; + int pipe = usb_sndbulkpipe(usb_dev, 1); + int max_packet = usb_maxpacket(usb_dev, pipe, 1); + u32 length; if (rt2x00_ring_full(ring)) { ieee80211_stop_queue(rt2x00dev->hw, control->queue); @@ -178,25 +179,29 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, /* * Add the descriptor in front of the skb. */ - skb_push(skb, rt2x00dev->hw->extra_tx_headroom); - memset(skb->data, 0x00, rt2x00dev->hw->extra_tx_headroom); + skb_push(skb, ring->desc_size); + memset(skb->data, 0, ring->desc_size); rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, - ieee80211hdr, length, control); + (struct ieee80211_hdr *)(skb->data + + ring->desc_size), + skb->len - ring->desc_size, control); memcpy(&entry->tx_status.control, control, sizeof(*control)); entry->skb = skb; /* - * Length passed to usb_fill_urb cannot be an odd number, - * so add 1 byte to make it even. + * USB devices cannot blindly pass the skb->len as the + * length of the data to usb_fill_bulk_urb. Pass the skb + * to the driver to determine what the length should be. */ - length += rt2x00dev->hw->extra_tx_headroom; - if (length % 2) - length++; + length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, + max_packet, skb); + /* + * Initialize URB and send the frame to the device. + */ __set_bit(ENTRY_OWNER_NIC, &entry->flags); - usb_fill_bulk_urb(entry->priv, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_fill_bulk_urb(entry->priv, usb_dev, pipe, skb->data, length, rt2x00usb_interrupt_txdone, entry); usb_submit_urb(entry->priv, GFP_ATOMIC); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 919cca593bc1..4a78ca79c94a 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1286,6 +1286,21 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 0, word); } +static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, + int maxpacket, struct sk_buff *skb) +{ + int length; + + /* + * The length _must_ be a multiple of 4, + * but it must _not_ be a multiple of the USB packet size. + */ + length = roundup(skb->len, 4); + length += (4 * !(length % maxpacket)); + + return length; +} + /* * TX data initialization */ @@ -2012,6 +2027,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .link_tuner = rt73usb_link_tuner, .write_tx_desc = rt73usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, + .get_tx_data_len = rt73usb_get_tx_data_len, .kick_tx_queue = rt73usb_kick_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, .config_mac_addr = rt73usb_config_mac_addr, From 5cbf830e137d1b6057cb6b553a8ebbb7d1b9343f Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:16:09 +0200 Subject: [PATCH 1770/2804] [PATCH] rt2x00: Pass dev_state to rt2x00lib_toggle_rx Directly pass a value from the enum dev_state with rt2x00lib_toggle_rx, this will save us a ? : statement, and it is clearer then passing a 1 0 argument. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 13 ++++++------- drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 6dc4f63aef0a..e14104869172 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -120,7 +120,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Enable RX. */ - rt2x00lib_toggle_rx(rt2x00dev, 1); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); /* * Start the TX queues. @@ -151,7 +151,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Disable RX. */ - rt2x00lib_toggle_rx(rt2x00dev, 0); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); /* * Disable radio. @@ -159,14 +159,12 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF); } -void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF; - /* * When we are disabling the RX, we should also stop the link tuner. */ - if (!enable) + if (state == STATE_RADIO_RX_OFF) rt2x00lib_stop_link_tuner(rt2x00dev); rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); @@ -174,7 +172,8 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) /* * When we are enabling the RX, we should also start the link tuner. */ - if (enable && is_interface_present(&rt2x00dev->interface)) + if (state == STATE_RADIO_RX_ON && + is_interface_present(&rt2x00dev->interface)) rt2x00lib_start_link_tuner(rt2x00dev); } diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 29ca932d77ab..298faa9d3f61 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -38,7 +38,7 @@ */ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev); void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev); -void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable); +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state); void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index e98d013a189f..f519d7396848 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -272,7 +272,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (!conf->radio_enabled) rt2x00lib_disable_radio(rt2x00dev); else - rt2x00lib_toggle_rx(rt2x00dev, 0); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); } rt2x00lib_config(rt2x00dev, conf, 0); @@ -281,7 +281,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * Reenable RX only if the radio should be on. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) - rt2x00lib_toggle_rx(rt2x00dev, 1); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); else if (conf->radio_enabled) return rt2x00lib_enable_radio(rt2x00dev); From 4f5af6eb3d17f8e343597ea99d97eb2f2905b2fb Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:16:30 +0200 Subject: [PATCH 1771/2804] [PATCH] rt2x00: Small optimizations Make some small optimizations by removing some simple if-statements. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 6 ++---- drivers/net/wireless/rt2x00/rt61pci.c | 6 ++---- drivers/net/wireless/rt2x00/rt73usb.c | 19 +++++++++---------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index f536ff1b5c47..ef8dffbdffed 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -326,10 +326,8 @@ static void rt2500usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); - if (preamble == SHORT_PREAMBLE) - rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 1); - else - rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 0); + rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, + (preamble == SHORT_PREAMBLE)); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8011523962a6..cd22817cced5 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -357,10 +357,8 @@ static void rt61pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); - if (preamble == SHORT_PREAMBLE) - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 1); - else - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 0); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, + (preamble == SHORT_PREAMBLE)); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4a78ca79c94a..9e1bf4d77e10 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -195,12 +195,13 @@ rf_write: reg = 0; rt2x00_set_field32(®, PHY_CSR4_VALUE, value); - if (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)) - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); - else - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 20); - + /* + * RF5225 and RF2527 contain 21 bits per RF register value, + * all others contain 20 bits. + */ + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, + 20 + !!(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527))); rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); @@ -331,10 +332,8 @@ static void rt73usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); - if (preamble == SHORT_PREAMBLE) - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 1); - else - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 0); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, + (preamble == SHORT_PREAMBLE)); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); } From 5c58ee51ff8c0aca74c225e0263bc5dd2b917781 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 13:34:52 +0200 Subject: [PATCH 1772/2804] [PATCH] rt2x00: Reorganize configuration handler Reorganize configuration handling by creating a extra structure which contains precalculated values based on the mac80211 values which are usefull for all individual drivers. This also fixes the preamble configuration problem, up untill now preamble was never configured since by default the rate->val value was used when changing the mode. Now rate->val will only be used to set the basic rate mask. The preamble configuration will now be done correctly through the erp_ie_changed callback function. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 132 ++++++++---------- drivers/net/wireless/rt2x00/rt2500pci.c | 147 +++++++++------------ drivers/net/wireless/rt2x00/rt2500usb.c | 112 +++++++--------- drivers/net/wireless/rt2x00/rt2x00.h | 32 ++++- drivers/net/wireless/rt2x00/rt2x00config.c | 61 ++++++++- drivers/net/wireless/rt2x00/rt2x00dev.c | 13 ++ drivers/net/wireless/rt2x00/rt2x00mac.c | 34 +++++ drivers/net/wireless/rt2x00/rt61pci.c | 101 ++++---------- drivers/net/wireless/rt2x00/rt73usb.c | 103 +++++---------- 9 files changed, 358 insertions(+), 377 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index bfab5a165b76..31c1dd271627 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -291,90 +291,67 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2x00pci_register_write(rt2x00dev, CSR14, reg); } -static void rt2400pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + int preamble_mask; u32 reg; - u32 preamble; - u16 value; - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - rt2x00pci_register_write(rt2x00dev, ARCSR1, reg); + /* + * When short preamble is enabled, we should set bit 0x08 + */ + preamble_mask = short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, value); - value = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, value); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, ack_consume_time); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); - preamble = DEVICE_GET_RATE_FIELD(rate, PREAMBLE) ? 0x08 : 0x00; - rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); - rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble); + rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble_mask); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); - rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble); + rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); - rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble); + rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); - rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble); + rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); } static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - - rt2x00dev->curr_hwmode = HWMODE_B; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt2400pci_config_rate(rt2x00dev, rate->val2); + rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); } static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel) + struct rf_channel *rf) { - struct rf_channel reg; - - /* - * Fill rf_reg structure. - */ - memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); - /* * Switch on tuning bits. */ - rt2x00_set_field32(®.rf1, RF1_TUNER, 1); - rt2x00_set_field32(®.rf3, RF3_TUNER, 1); + rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1); + rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1); - rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2400pci_rf_write(rt2x00dev, 2, reg.rf2); - rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2400pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); /* * RF2420 chipset don't need any additional actions. @@ -387,31 +364,31 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, * reference clock rate to activate auto_tune. * After that we set the value back to the correct channel. */ - rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); rt2400pci_rf_write(rt2x00dev, 2, 0x000c2a32); - rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); msleep(1); - rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2400pci_rf_write(rt2x00dev, 2, reg.rf2); - rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2400pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); msleep(1); /* * Switch off tuning bits. */ - rt2x00_set_field32(®.rf1, RF1_TUNER, 0); - rt2x00_set_field32(®.rf3, RF3_TUNER, 0); + rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0); + rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0); - rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); /* * Clear false CRC during channel switch. */ - rt2x00pci_register_read(rt2x00dev, CNT0, ®.rf1); + rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1); } static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) @@ -465,25 +442,22 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, - int short_slot_time, int beacon_int) + struct rt2x00lib_conf *libconf) { u32 reg; rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); rt2x00pci_register_write(rt2x00dev, CSR11, reg); rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, SIFS); - rt2x00_set_field32(®, CSR18_PIFS, - short_slot_time ? SHORT_PIFS : PIFS); + rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); + rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); rt2x00pci_register_write(rt2x00dev, CSR18, reg); rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, - short_slot_time ? SHORT_DIFS : DIFS); - rt2x00_set_field32(®, CSR19_EIFS, EIFS); + rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); + rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); rt2x00pci_register_write(rt2x00dev, CSR19, reg); rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); @@ -492,30 +466,30 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, CSR12, ®); - rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, beacon_int * 16); - rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, beacon_int * 16); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, + libconf->conf->beacon_int * 16); rt2x00pci_register_write(rt2x00dev, CSR12, reg); } static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt2400pci_config_phymode(rt2x00dev, conf->phymode); + rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt2400pci_config_channel(rt2x00dev, conf->channel_val, - conf->channel); + rt2400pci_config_channel(rt2x00dev, &libconf->rf); if (flags & CONFIG_UPDATE_TXPOWER) - rt2400pci_config_txpower(rt2x00dev, conf->power_level); + rt2400pci_config_txpower(rt2x00dev, + libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2400pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt2400pci_config_antenna(rt2x00dev, + libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt2400pci_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt2400pci_config_duration(rt2x00dev, libconf); } static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev, @@ -1609,6 +1583,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .configure_filter = rt2400pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2400pci_set_retry_limit, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2400pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2400pci_get_tsf, @@ -1634,6 +1609,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .config_mac_addr = rt2400pci_config_mac_addr, .config_bssid = rt2400pci_config_bssid, .config_type = rt2400pci_config_type, + .config_preamble = rt2400pci_config_preamble, .config = rt2400pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c8c6a848be97..ff2d63267b19 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -295,100 +295,72 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2x00pci_register_write(rt2x00dev, CSR14, reg); } -static void rt2500pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + int preamble_mask; u32 reg; - u32 preamble; - u16 value; - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - rt2x00pci_register_write(rt2x00dev, ARCSR1, reg); + /* + * When short preamble is enabled, we should set bit 0x08 + */ + preamble_mask = short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, value); - value = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, value); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, ack_consume_time); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); - preamble = DEVICE_GET_RATE_FIELD(rate, PREAMBLE) ? 0x08 : 0x00; - rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); - rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble); + rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble_mask); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); - rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble); + rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); - rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble); + rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); - rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble); + rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); } static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - - if (phymode == MODE_IEEE80211A) - rt2x00dev->curr_hwmode = HWMODE_A; - else if (phymode == MODE_IEEE80211B) - rt2x00dev->curr_hwmode = HWMODE_B; - else - rt2x00dev->curr_hwmode = HWMODE_G; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt2500pci_config_rate(rt2x00dev, rate->val2); + rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); } static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel, - const int txpower) + struct rf_channel *rf, const int txpower) { - struct rf_channel reg; u8 r70; - /* - * Fill rf_reg structure. - */ - memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); - /* * Set TXpower. */ - rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); /* * Switch on tuning bits. * For RT2523 devices we do not need to update the R1 register. */ if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) - rt2x00_set_field32(®.rf1, RF1_TUNER, 1); - rt2x00_set_field32(®.rf3, RF3_TUNER, 1); + rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1); + rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1); /* * For RT2525 we should first set the channel to half band higher. @@ -401,24 +373,24 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, 0x00080d2e, 0x00080d3a }; - rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2500pci_rf_write(rt2x00dev, 2, vals[channel - 1]); - rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); - if (reg.rf4) - rt2500pci_rf_write(rt2x00dev, 4, reg.rf4); + rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2500pci_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); + rt2500pci_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500pci_rf_write(rt2x00dev, 4, rf->rf4); } - rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2500pci_rf_write(rt2x00dev, 2, reg.rf2); - rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); - if (reg.rf4) - rt2500pci_rf_write(rt2x00dev, 4, reg.rf4); + rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2500pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2500pci_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500pci_rf_write(rt2x00dev, 4, rf->rf4); /* * Channel 14 requires the Japan filter bit to be set. */ r70 = 0x46; - rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, channel == 14); + rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, rf->channel == 14); rt2500pci_bbp_write(rt2x00dev, 70, r70); msleep(1); @@ -428,17 +400,17 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, * For RT2523 devices we do not need to update the R1 register. */ if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) { - rt2x00_set_field32(®.rf1, RF1_TUNER, 0); - rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0); + rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); } - rt2x00_set_field32(®.rf3, RF3_TUNER, 0); - rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0); + rt2500pci_rf_write(rt2x00dev, 3, rf->rf3); /* * Clear false CRC during channel switch. */ - rt2x00pci_register_read(rt2x00dev, CNT0, ®.rf1); + rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1); } static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, @@ -525,26 +497,22 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, - const int short_slot_time, - const int beacon_int) + struct rt2x00lib_conf *libconf) { u32 reg; rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); rt2x00pci_register_write(rt2x00dev, CSR11, reg); rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, SIFS); - rt2x00_set_field32(®, CSR18_PIFS, - short_slot_time ? SHORT_PIFS : PIFS); + rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); + rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); rt2x00pci_register_write(rt2x00dev, CSR18, reg); rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, - short_slot_time ? SHORT_DIFS : DIFS); - rt2x00_set_field32(®, CSR19_EIFS, EIFS); + rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); + rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); rt2x00pci_register_write(rt2x00dev, CSR19, reg); rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); @@ -553,30 +521,31 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, CSR12, ®); - rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, beacon_int * 16); - rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, beacon_int * 16); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, + libconf->conf->beacon_int * 16); rt2x00pci_register_write(rt2x00dev, CSR12, reg); } static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500pci_config_phymode(rt2x00dev, conf->phymode); + rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt2500pci_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->power_level); + rt2500pci_config_channel(rt2x00dev, &libconf->rf, + libconf->conf->power_level); if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) - rt2500pci_config_txpower(rt2x00dev, conf->power_level); + rt2500pci_config_txpower(rt2x00dev, + libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2500pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt2500pci_config_antenna(rt2x00dev, + libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt2500pci_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt2500pci_config_duration(rt2x00dev, libconf); } /* @@ -1921,6 +1890,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .configure_filter = rt2500pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2500pci_set_retry_limit, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2500pci_get_tsf, @@ -1946,6 +1916,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .config_mac_addr = rt2500pci_config_mac_addr, .config_bssid = rt2500pci_config_bssid, .config_type = rt2500pci_config_type, + .config_preamble = rt2500pci_config_preamble, .config = rt2500pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index ef8dffbdffed..45f8f744a12d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -302,54 +302,39 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } -static void rt2500usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; u16 reg; - u16 value; - u16 preamble; - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - - rt2500usb_register_write(rt2x00dev, TXRX_CSR11, reg); + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); + return; + } rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, value); + rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, ack_timeout); rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, - (preamble == SHORT_PREAMBLE)); + !!short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); } static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int phymode, + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; + rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask); - if (phymode == MODE_IEEE80211A) - rt2x00dev->curr_hwmode = HWMODE_A; - else if (phymode == MODE_IEEE80211B) - rt2x00dev->curr_hwmode = HWMODE_B; - else - rt2x00dev->curr_hwmode = HWMODE_G; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt2500usb_config_rate(rt2x00dev, rate->val2); - - if (phymode == MODE_IEEE80211B) { + if (phymode == HWMODE_B) { rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b); rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040); } else { @@ -359,20 +344,12 @@ static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, } static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel, - const int txpower) + struct rf_channel *rf, const int txpower) { - struct rf_channel reg; - - /* - * Fill rf_reg structure. - */ - memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); - /* * Set TXpower. */ - rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); /* * For RT2525E we should first set the channel to half band higher. @@ -385,16 +362,16 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, 0x00000902, 0x00000906 }; - rt2500usb_rf_write(rt2x00dev, 2, vals[channel - 1]); - if (reg.rf4) - rt2500usb_rf_write(rt2x00dev, 4, reg.rf4); + rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); } - rt2500usb_rf_write(rt2x00dev, 1, reg.rf1); - rt2500usb_rf_write(rt2x00dev, 2, reg.rf2); - rt2500usb_rf_write(rt2x00dev, 3, reg.rf3); - if (reg.rf4) - rt2500usb_rf_write(rt2x00dev, 4, reg.rf4); + rt2500usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2500usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2500usb_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); } static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, @@ -484,38 +461,37 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, - const int short_slot_time, - const int beacon_int) + struct rt2x00lib_conf *libconf) { u16 reg; - rt2500usb_register_write(rt2x00dev, MAC_CSR10, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time); rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); - rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, beacon_int * 4); + rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, + libconf->conf->beacon_int * 4); rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); } static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500usb_config_phymode(rt2x00dev, conf->phymode); + rt2500usb_config_phymode(rt2x00dev, libconf->phymode, + libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt2500usb_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->power_level); + rt2500usb_config_channel(rt2x00dev, &libconf->rf, + libconf->conf->power_level); if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) - rt2500usb_config_txpower(rt2x00dev, conf->power_level); + rt2500usb_config_txpower(rt2x00dev, + libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2500usb_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt2500usb_config_antenna(rt2x00dev, + libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt2500usb_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt2500usb_config_duration(rt2x00dev, libconf); } /* @@ -1733,6 +1709,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2500usb_configure_filter, .get_stats = rt2x00mac_get_stats, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .beacon_update = rt2500usb_beacon_update, @@ -1754,6 +1731,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .config_mac_addr = rt2500usb_config_mac_addr, .config_bssid = rt2500usb_config_bssid, .config_type = rt2500usb_config_type, + .config_preamble = rt2500usb_config_preamble, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index a392e2a9d087..aabbe425470f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -351,6 +351,28 @@ struct hw_mode_spec { const struct rf_channel *channels; }; +/* + * Configuration structure wrapper around the + * mac80211 configuration structure. + * When mac80211 configures the driver, rt2x00lib + * can precalculate values which are equal for all + * rt2x00 drivers. Those values can be stored in here. + */ +struct rt2x00lib_conf { + struct ieee80211_conf *conf; + struct rf_channel rf; + + int phymode; + + int basic_rates; + int slot_time; + + short sifs; + short pifs; + short difs; + short eifs; +}; + /* * rt2x00lib callback functions. */ @@ -414,8 +436,12 @@ struct rt2x00lib_ops { void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type, const int tsf_sync); + void (*config_preamble) (struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time); void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf); + struct rt2x00lib_conf *libconf); #define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) #define CONFIG_UPDATE_CHANNEL ( 1 << 2 ) #define CONFIG_UPDATE_TXPOWER ( 1 << 3 ) @@ -472,6 +498,7 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, + CONFIG_SHORT_PREAMBLE, }; /* @@ -612,6 +639,7 @@ struct rt2x00_dev { */ struct work_struct beacon_work; struct work_struct filter_work; + struct work_struct config_work; /* * Data ring arrays for RX, TX and Beacon. @@ -792,6 +820,8 @@ int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); +void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes, + int cts_protection, int preamble); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f8e87aa86335..12914cf7156c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -97,7 +97,11 @@ void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config) { + struct rt2x00lib_conf libconf; + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; int flags = 0; + int short_slot_time; /* * In some situations we want to force all configurations @@ -128,8 +132,62 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, flags |= CONFIG_UPDATE_SLOT_TIME; flags |= CONFIG_UPDATE_BEACON_INT; + /* + * We have determined what options should be updated, + * now precalculate device configuration values depending + * on what configuration options need to be updated. + */ config: - rt2x00dev->ops->lib->config(rt2x00dev, flags, conf); + memset(&libconf, 0, sizeof(libconf)); + + if (flags & CONFIG_UPDATE_PHYMODE) { + switch (conf->phymode) { + case MODE_IEEE80211A: + libconf.phymode = HWMODE_A; + break; + case MODE_IEEE80211B: + libconf.phymode = HWMODE_B; + break; + case MODE_IEEE80211G: + libconf.phymode = HWMODE_G; + break; + default: + ERROR(rt2x00dev, + "Attempt to configure unsupported mode (%d)" + "Defaulting to 802.11b", conf->phymode); + libconf.phymode = HWMODE_B; + } + + mode = &rt2x00dev->hwmodes[libconf.phymode]; + rate = &mode->rates[mode->num_rates - 1]; + + libconf.basic_rates = + DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK; + } + + if (flags & CONFIG_UPDATE_CHANNEL) { + memcpy(&libconf.rf, + &rt2x00dev->spec.channels[conf->channel_val], + sizeof(libconf.rf)); + } + + if (flags & CONFIG_UPDATE_SLOT_TIME) { + short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + libconf.slot_time = + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME; + libconf.sifs = SIFS; + libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; + libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; + libconf.eifs = EIFS; + } + + libconf.conf = conf; + + /* + * Start configuration. + */ + rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf); /* * Some configuration changes affect the link quality @@ -138,6 +196,7 @@ config: if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) rt2x00lib_reset_link_tuner(rt2x00dev); + rt2x00dev->curr_hwmode = libconf.phymode; rt2x00dev->rx_status.phymode = conf->phymode; rt2x00dev->rx_status.freq = conf->freq; rt2x00dev->rx_status.channel = conf->channel; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e14104869172..bb6f46cfbb9f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -142,6 +142,8 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) cancel_work_sync(&rt2x00dev->beacon_work); if (work_pending(&rt2x00dev->filter_work)) cancel_work_sync(&rt2x00dev->filter_work); + if (work_pending(&rt2x00dev->config_work)) + cancel_work_sync(&rt2x00dev->config_work); /* * Stop the TX queues. @@ -288,6 +290,16 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) filter, &filter, 0, NULL); } +static void rt2x00lib_configuration_scheduled(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, config_work); + int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + + rt2x00mac_erp_ie_changed(rt2x00dev->hw, + IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble); +} + /* * Interrupt context handlers. */ @@ -990,6 +1002,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); + INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index f519d7396848..4a6a0bd01ff1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -365,6 +365,40 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); +void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes, + int cts_protection, int preamble) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int short_preamble; + int ack_timeout; + int ack_consume_time; + int difs; + + /* + * We only support changing preamble mode. + */ + if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE)) + return; + + short_preamble = !preamble; + preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE; + + difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS; + ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10); + + ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + + if (short_preamble) + __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + else + __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + + rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble, + ack_timeout, ack_consume_time); +} +EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed); + int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params) { diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index cd22817cced5..1a869a5cbe91 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -328,62 +328,31 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } -static void rt61pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; u32 reg; - u32 value; - u32 preamble; - - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - - /* - * Extract the allowed ratemask from the device specific rate value, - * We need to set TXRX_CSR5 to the basic rate mask so we need to mask - * off the non-basic rates. - */ - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - - rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, value); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, - (preamble == SHORT_PREAMBLE)); + !!short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); } static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - - if (phymode == MODE_IEEE80211A) - rt2x00dev->curr_hwmode = HWMODE_A; - else if (phymode == MODE_IEEE80211B) - rt2x00dev->curr_hwmode = HWMODE_B; - else - rt2x00dev->curr_hwmode = HWMODE_G; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt61pci_config_rate(rt2x00dev, rate->val2); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); } -static void rt61pci_config_lock_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, - const int txpower) +static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) { u8 r3; u8 r94; @@ -428,20 +397,6 @@ static void rt61pci_config_lock_channel(struct rt2x00_dev *rt2x00dev, msleep(1); } -static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel, - const int txpower) -{ - struct rf_channel rf; - - /* - * Fill rf_reg structure. - */ - memcpy(&rf, &rt2x00dev->spec.channels[index], sizeof(rf)); - - rt61pci_config_lock_channel(rt2x00dev, &rf, txpower); -} - static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, const int txpower) { @@ -452,7 +407,7 @@ static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); - rt61pci_config_lock_channel(rt2x00dev, &rf, txpower); + rt61pci_config_channel(rt2x00dev, &rf, txpower); } static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -714,20 +669,18 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, - const int short_slot_time, - const int beacon_int) + struct rt2x00lib_conf *libconf) { u32 reg; rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, SIFS); + rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, EIFS); + rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); @@ -739,29 +692,27 @@ static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, beacon_int * 16); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } static void rt61pci_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt61pci_config_phymode(rt2x00dev, conf->phymode); + rt61pci_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt61pci_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->power_level); + rt61pci_config_channel(rt2x00dev, &libconf->rf, + libconf->conf->power_level); if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) - rt61pci_config_txpower(rt2x00dev, conf->power_level); + rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt61pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt61pci_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt61pci_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt61pci_config_duration(rt2x00dev, libconf); } /* @@ -2513,6 +2464,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .configure_filter = rt61pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, @@ -2539,6 +2491,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .config_mac_addr = rt61pci_config_mac_addr, .config_bssid = rt61pci_config_bssid, .config_type = rt61pci_config_type, + .config_preamble = rt61pci_config_preamble, .config = rt61pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 9e1bf4d77e10..984117fe1f5e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -308,57 +308,40 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } -static void rt73usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; u32 reg; - u32 value; - u32 preamble; - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - - rt73usb_register_write(rt2x00dev, TXRX_CSR5, reg); + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); + return; + } rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, value); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, - (preamble == SHORT_PREAMBLE)); + !!short_preamble); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); } static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - - if (phymode == MODE_IEEE80211A) - rt2x00dev->curr_hwmode = HWMODE_A; - else if (phymode == MODE_IEEE80211B) - rt2x00dev->curr_hwmode = HWMODE_B; - else - rt2x00dev->curr_hwmode = HWMODE_G; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt73usb_config_rate(rt2x00dev, rate->val2); + rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); } -static void rt73usb_config_lock_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, - const int txpower) +static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) { u8 r3; u8 r94; @@ -399,20 +382,6 @@ static void rt73usb_config_lock_channel(struct rt2x00_dev *rt2x00dev, udelay(10); } -static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel, - const int txpower) -{ - struct rf_channel rf; - - /* - * Fill rf_reg structure. - */ - memcpy(&rf, &rt2x00dev->spec.channels[index], sizeof(rf)); - - rt73usb_config_lock_channel(rt2x00dev, &rf, txpower); -} - static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, const int txpower) { @@ -423,7 +392,7 @@ static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); - rt73usb_config_lock_channel(rt2x00dev, &rf, txpower); + rt73usb_config_channel(rt2x00dev, &rf, txpower); } static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -577,20 +546,18 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, - const int short_slot_time, - const int beacon_int) + struct rt2x00lib_conf *libconf) { u32 reg; rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, SIFS); + rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, EIFS); + rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); @@ -602,29 +569,27 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, beacon_int * 16); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } static void rt73usb_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt73usb_config_phymode(rt2x00dev, conf->phymode); + rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt73usb_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->power_level); + rt73usb_config_channel(rt2x00dev, &libconf->rf, + libconf->conf->power_level); if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) - rt73usb_config_txpower(rt2x00dev, conf->power_level); + rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt73usb_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt73usb_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt73usb_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt73usb_config_duration(rt2x00dev, libconf); } /* @@ -2002,6 +1967,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .configure_filter = rt73usb_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, #if 0 @@ -2032,6 +1998,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .config_mac_addr = rt73usb_config_mac_addr, .config_bssid = rt73usb_config_bssid, .config_type = rt73usb_config_type, + .config_preamble = rt73usb_config_preamble, .config = rt73usb_config, }; From 37894473fb0d07e1e015781f7ae1b9b1762d49be Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:18:00 +0200 Subject: [PATCH 1773/2804] [PATCH] rt2x00: Clean disabling of rt73usb_get_tsf By defining rt73usb_get_tsf to NULL we only have 1 location that needs to be edited when rt73usb_get_tsf can be enabled again. This also reduces the number of #ifdefs in the code which is also a "good thing" Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 984117fe1f5e..67a1e3750d4d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1910,6 +1910,8 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) return tsf; } +#else +#define rt73usb_get_tsf NULL #endif static void rt73usb_reset_tsf(struct ieee80211_hw *hw) @@ -1970,12 +1972,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, -#if 0 -/* - * See comment at the rt73usb_get_tsf function. - */ .get_tsf = rt73usb_get_tsf, -#endif .reset_tsf = rt73usb_reset_tsf, .beacon_update = rt73usb_beacon_update, }; From c22eb87b5723b3d66665ca2ffa87428e0e489b16 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:18:22 +0200 Subject: [PATCH 1774/2804] [PATCH] rt2x00: Allways memset memory obtained from skb_push() When skb_push() is used we should memset the memory before usage. This will prevent bugs which could occur when the data is treated as TX descriptor. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 2 ++ drivers/net/wireless/rt2x00/rt61pci.c | 2 ++ drivers/net/wireless/rt2x00/rt73usb.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 45f8f744a12d..7cdc80a122bb 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1665,6 +1665,8 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * First we create the beacon. */ skb_push(skb, ring->desc_size); + memset(skb->data, 0, ring->desc_size); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, (struct ieee80211_hdr *)(skb->data + ring->desc_size), diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 1a869a5cbe91..01dbef19d651 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2437,6 +2437,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * First we create the beacon. */ skb_push(skb, TXD_DESC_SIZE); + memset(skb->data, 0, TXD_DESC_SIZE); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, (struct ieee80211_hdr *)(skb->data + TXD_DESC_SIZE), diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 67a1e3750d4d..3e42759473c3 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1939,6 +1939,8 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * First we create the beacon. */ skb_push(skb, TXD_DESC_SIZE); + memset(skb->data, 0, TXD_DESC_SIZE); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, (struct ieee80211_hdr *)(skb->data + TXD_DESC_SIZE), From 515ea2492cfc93233ba31402d1992a435aa78f37 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:18:41 +0200 Subject: [PATCH 1775/2804] [PATCH] rt2x00: Release 2.0.10 Version bump Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index aabbe425470f..9845e584b731 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -42,7 +42,7 @@ * Module information. * DRV_NAME should be set within the individual module source files. */ -#define DRV_VERSION "2.0.9" +#define DRV_VERSION "2.0.10" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* From 2bcde51d095490c223bb4ade351cb7981c367934 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 3 Oct 2007 10:37:45 -0400 Subject: [PATCH 1776/2804] [PATCH] libertas: problems setting wpa keys The 88w8385 chip, using SDIO interface and firmware release 5.0.11p0, has problems when both unicast and multicast WPA keys are set in one command. This patch ensures the keys are set independently. The original author of this patch is Marc Pignat Signed-off-by: Marc Pignat Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 35 +++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 2c6ddb1f0072..b61b176e9d07 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -374,15 +374,40 @@ static int assoc_helper_wpa_keys(wlan_private *priv, struct assoc_request * assoc_req) { int ret = 0; + unsigned int flags = assoc_req->flags; lbs_deb_enter(LBS_DEB_ASSOC); - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_KEY_MATERIAL, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - 0, assoc_req); + /* Work around older firmware bug where WPA unicast and multicast + * keys must be set independently. Seen in SDIO parts with firmware + * version 5.0.11p0. + */ + if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { + clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); + ret = libertas_prepare_and_send_command(priv, + CMD_802_11_KEY_MATERIAL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, + 0, assoc_req); + assoc_req->flags = flags; + } + + if (ret) + goto out; + + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { + clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); + + ret = libertas_prepare_and_send_command(priv, + CMD_802_11_KEY_MATERIAL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, + 0, assoc_req); + assoc_req->flags = flags; + } + +out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } From 6470a89de90167cc1ff8a0312197ca422f5fe35f Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Mon, 8 Oct 2007 11:07:27 +0200 Subject: [PATCH 1777/2804] [PATCH] libertas: fix u8 constant Don't write constants that are (per documentation and struct) u8 as 0x0001, use 0x01 instead. Also remove an useless cast. Signed-off-by: Holger Schurig Acked-By: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 4 ++-- drivers/net/wireless/libertas/host.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 33dbed09fc72..1cbbd96fdbde 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -181,13 +181,13 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, switch (pkey->len) { case KEY_LEN_WEP_40: - wep->keytype[i] = (u8)CMD_TYPE_WEP_40_BIT; + wep->keytype[i] = CMD_TYPE_WEP_40_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); break; case KEY_LEN_WEP_104: - wep->keytype[i] = (u8)CMD_TYPE_WEP_104_BIT; + wep->keytype[i] = CMD_TYPE_WEP_104_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 68fa11b3a2dc..b37ddbca969f 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -138,8 +138,8 @@ #define CMD_ACT_REMOVE 0x0004 #define CMD_ACT_USE_DEFAULT 0x0008 -#define CMD_TYPE_WEP_40_BIT 0x0001 -#define CMD_TYPE_WEP_104_BIT 0x0002 +#define CMD_TYPE_WEP_40_BIT 0x01 +#define CMD_TYPE_WEP_104_BIT 0x02 #define CMD_NUM_OF_WEP_KEYS 4 From d8b0fb51ef1563c631d26cb649a5479b5cc4899c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 8 Oct 2007 09:43:02 +0200 Subject: [PATCH 1778/2804] [PATCH] libertas link error due to gcc `smartness' Some versions of gcc replace strstr() calls with a single-character `needle' parameter by strchr() behind our back. This causes a link error if strchr() is defined as an inline function in (e.g. on m68k): | drivers/built-in.o: In function `libertas_parse_chan': | linux/drivers/net/wireless/libertas/debugfs.c:209: undefined reference to `strchr' | drivers/built-in.o: In function `libertas_parse_ssid': | linux/drivers/net/wireless/libertas/debugfs.c:260: undefined reference to `strchr' Avoid this by explicitly calling strchr() instead. Also include , because this file calls lots of str*() routines. Signed-off-by: Geert Uytterhoeven Acked-By: Holger Schurig Acked-By: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index cb00b080409e..0bda0b511910 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "dev.h" @@ -205,7 +206,7 @@ static int libertas_parse_chan(char *buf, size_t count, if (!start) return -EINVAL; start += 5; - end = strstr(start, " "); + end = strchr(start, ' '); if (!end) end = buf + count; hold = kzalloc((end - start)+1, GFP_KERNEL); @@ -256,7 +257,7 @@ static void libertas_parse_ssid(char *buf, size_t count, if (!hold) return; hold += 5; - end = strstr(hold, " "); + end = strchr(hold, ' '); if (!end) end = buf + count - 1; From 8b17d7234c7039b668739e1868f3d5544d79a4c0 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Mon, 8 Oct 2007 11:09:30 +0200 Subject: [PATCH 1779/2804] [PATCH] libertas: fix a debug statement Fix a debug statement Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index fe70e30b1f3c..8f90892ea22e 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -148,7 +148,7 @@ static int wlan_ret_reg_access(wlan_private * priv, ret = -1; } - lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } From 314a886f08d689cdcf10bd8e4777a3d9f483bb53 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Mon, 8 Oct 2007 12:20:04 +0200 Subject: [PATCH 1780/2804] [PATCH] libertas: fix "warning: Using plain integer as NULL pointer" sparse warnings This fixes three "warning: Using plain integer as NULL pointer" sparse warnings. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index fab93d8fe9c7..dcce354e904c 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -578,7 +578,7 @@ static int wlan_scan_channel_list(wlan_private * priv, lbs_deb_enter(LBS_DEB_ASSOC); - if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) { + if (!pscancfgout || !pchantlvout || !pscanchanlist) { lbs_deb_scan("Scan: Null detect: %p, %p, %p\n", pscancfgout, pchantlvout, pscanchanlist); return -1; From e56188ac4163cb276b7650949c1e8e20fb2f9c73 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 9 Oct 2007 14:15:19 +0200 Subject: [PATCH 1781/2804] [PATCH] libertas: clean up scan debug messages * make scan debug output cleaner * change some LBS_DEB_ASSOC messages to LBS_DEB_SCAN, which is more correct * move helper functions together * print function return value in the tracing code at one central location Signed-off-by: Holger Schurig Acked-By: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 2 - drivers/net/wireless/libertas/scan.c | 221 +++++++++++++++++++-------- 2 files changed, 155 insertions(+), 68 deletions(-) diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 8dcff00574f3..dc24a05c9447 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -800,8 +800,6 @@ int libertas_ret_80211_associate(wlan_private * priv, netif_wake_queue(priv->mesh_dev); } - lbs_deb_join("ASSOC_RESP: Associated \n"); - memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index dcce354e904c..ad1e67d984ce 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -65,6 +65,15 @@ static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + + +/*********************************************************************/ +/* */ +/* Misc helper functions */ +/* */ +/*********************************************************************/ + static inline void clear_bss_descriptor (struct bss_descriptor * bss) { /* Don't blow away ->list, just BSS data */ @@ -165,7 +174,7 @@ static int is_network_compatible(wlan_adapter * adapter, { int matched = 0; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); if (bss->mode != mode) goto done; @@ -214,13 +223,41 @@ static int is_network_compatible(wlan_adapter * adapter, (bss->capability & WLAN_CAPABILITY_PRIVACY)); done: - lbs_deb_leave(LBS_DEB_SCAN); + lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched); return matched; } +/** + * @brief Compare two SSIDs + * + * @param ssid1 A pointer to ssid to compare + * @param ssid2 A pointer to ssid to compare + * + * @return 0--ssid is same, otherwise is different + */ +int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) +{ + if (ssid1_len != ssid2_len) + return -1; + + return memcmp(ssid1, ssid2, ssid1_len); +} + + + + +/*********************************************************************/ +/* */ +/* Main scanning support */ +/* */ +/*********************************************************************/ + + /** * @brief Create a channel list for the driver to scan based on region info * + * Only used from wlan_scan_setup_scan_config() + * * Use the driver region/band information to construct a comprehensive list * of channels to scan. This routine is used for any scan that is not * provided a specific channel list to scan. @@ -248,6 +285,8 @@ static void wlan_scan_create_channel_list(wlan_private * priv, int nextchan; u8 scantype; + lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan); + chanidx = 0; /* Set the default scan type to the user specified type, will later @@ -384,6 +423,8 @@ wlan_scan_setup_scan_config(wlan_private * priv, int channel; int radiotype; + lbs_deb_enter(LBS_DEB_SCAN); + pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); if (pscancfgout == NULL) goto out; @@ -481,13 +522,12 @@ wlan_scan_setup_scan_config(wlan_private * priv, if (!puserscanin || !puserscanin->chanlist[0].channumber) { /* Create a default channel scan list */ - lbs_deb_scan("Scan: Creating full region channel list\n"); + lbs_deb_scan("creating full region channel list\n"); wlan_scan_create_channel_list(priv, pscanchanlist, *pfilteredscan); goto out; } - lbs_deb_scan("Scan: Using supplied channel list\n"); for (chanidx = 0; chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX && puserscanin->chanlist[chanidx].channumber; chanidx++) { @@ -529,7 +569,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, (puserscanin->chanlist[0].channumber == priv->adapter->curbssparams.channel)) { *pscancurrentonly = 1; - lbs_deb_scan("Scan: Scanning current channel only"); + lbs_deb_scan("scanning current channel only"); } out: @@ -539,6 +579,8 @@ out: /** * @brief Construct and send multiple scan config commands to the firmware * + * Only used from wlan_scan_networks() + * * Previous routines have created a wlan_scan_cmd_config with any requested * TLVs. This function splits the channel TLV into maxchanperscan lists * and sends the portion of the channel TLV along with the other TLVs @@ -576,12 +618,14 @@ static int wlan_scan_channel_list(wlan_private * priv, int scanned = 0; union iwreq_data wrqu; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, " + "full_scan %d", maxchanperscan, filteredscan, full_scan); if (!pscancfgout || !pchantlvout || !pscanchanlist) { - lbs_deb_scan("Scan: Null detect: %p, %p, %p\n", - pscancfgout, pchantlvout, pscanchanlist); - return -1; + lbs_deb_scan("pscancfgout, pchantlvout or " + "pscanchanlist is NULL\n"); + ret = -1; + goto out; } pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); @@ -613,9 +657,10 @@ static int wlan_scan_channel_list(wlan_private * priv, while (tlvidx < maxchanperscan && ptmpchan->channumber && !doneearly && scanned < 2) { - lbs_deb_scan("Scan: Chan(%3d), Radio(%d), mode(%d,%d), " - "Dur(%d)\n", - ptmpchan->channumber, ptmpchan->radiotype, + lbs_deb_scan("channel %d, radio %d, passive %d, " + "dischanflt %d, maxscantime %d\n", + ptmpchan->channumber, + ptmpchan->radiotype, ptmpchan->chanscanmode.passivescan, ptmpchan->chanscanmode.disablechanfilt, ptmpchan->maxscantime); @@ -700,20 +745,25 @@ done: wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); } +out: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } -static void -clear_selected_scan_list_entries(wlan_adapter * adapter, - const struct wlan_ioctl_user_scan_cfg * scan_cfg) +/* + * Only used from wlan_scan_networks() +*/ +static void clear_selected_scan_list_entries(wlan_adapter *adapter, + const struct wlan_ioctl_user_scan_cfg *scan_cfg) { - struct bss_descriptor * bss; - struct bss_descriptor * safe; + struct bss_descriptor *bss; + struct bss_descriptor *safe; u32 clear_ssid_flag = 0, clear_bssid_flag = 0; + lbs_deb_enter(LBS_DEB_SCAN); + if (!scan_cfg) - return; + goto out; if (scan_cfg->clear_ssid && scan_cfg->ssid_len) clear_ssid_flag = 1; @@ -725,7 +775,7 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, } if (!clear_ssid_flag && !clear_bssid_flag) - return; + goto out; mutex_lock(&adapter->lock); list_for_each_entry_safe (bss, safe, &adapter->network_list, list) { @@ -748,12 +798,16 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, } } mutex_unlock(&adapter->lock); +out: + lbs_deb_leave(LBS_DEB_SCAN); } /** * @brief Internal function used to start a scan based on an input config * + * Also used from debugfs + * * Use the input user scan configuration information when provided in * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table @@ -761,6 +815,7 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, * @param priv A pointer to wlan_private structure * @param puserscanin Pointer to the input configuration for the requested * scan. + * @param full_scan ??? * * @return 0 or < 0 if error */ @@ -782,7 +837,7 @@ int wlan_scan_networks(wlan_private * priv, DECLARE_MAC_BUF(mac); #endif - lbs_deb_enter(LBS_DEB_SCAN); + lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); /* Cancel any partial outstanding partial scans if this scan * is a full scan. @@ -833,8 +888,9 @@ int wlan_scan_networks(wlan_private * priv, #ifdef CONFIG_LIBERTAS_DEBUG /* Dump the scan table */ mutex_lock(&adapter->lock); + lbs_deb_scan("The scan table contains:\n"); list_for_each_entry (iter_bss, &adapter->network_list, list) { - lbs_deb_scan("Scan:(%02d) %s, RSSI[%03d], SSID[%s]\n", + lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n", i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi, escape_essid(iter_bss->ssid, iter_bss->ssid_len)); } @@ -886,7 +942,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, u16 beaconsize = 0; int ret; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ @@ -898,7 +954,8 @@ static int libertas_process_bss(struct bss_descriptor * bss, if (beaconsize == 0 || beaconsize > *bytesleft) { *pbeaconinfo += *bytesleft; *bytesleft = 0; - return -1; + ret = -1; + goto done; } /* Initialize the current working beacon pointer for this BSS iteration */ @@ -915,7 +972,8 @@ static int libertas_process_bss(struct bss_descriptor * bss, if ((end - pos) < 12) { lbs_deb_scan("process_bss: Not enough bytes left\n"); - return -1; + ret = -1; + goto done; } /* @@ -1090,39 +1148,27 @@ done: return ret; } -/** - * @brief Compare two SSIDs - * - * @param ssid1 A pointer to ssid to compare - * @param ssid2 A pointer to ssid to compare - * - * @return 0--ssid is same, otherwise is different - */ -int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) -{ - if (ssid1_len != ssid2_len) - return -1; - - return memcmp(ssid1, ssid2, ssid1_len); -} - /** * @brief This function finds a specific compatible BSSID in the scan list * + * Used in association code + * * @param adapter A pointer to wlan_adapter * @param bssid BSSID to find in the scan list * @param mode Network mode: Infrastructure or IBSS * * @return index in BSSID list, or error return code (< 0) */ -struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, +struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, u8 * bssid, u8 mode) { struct bss_descriptor * iter_bss; struct bss_descriptor * found_bss = NULL; + lbs_deb_enter(LBS_DEB_SCAN); + if (!bssid) - return NULL; + goto out; lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); @@ -1149,12 +1195,16 @@ struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, } mutex_unlock(&adapter->lock); +out: + lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); return found_bss; } /** * @brief This function finds ssid in ssid list. * + * Used in association code + * * @param adapter A pointer to wlan_adapter * @param ssid SSID to find in the list * @param bssid BSSID to qualify the SSID selection (if provided) @@ -1171,6 +1221,8 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, struct bss_descriptor * found_bss = NULL; struct bss_descriptor * tmp_oldest = NULL; + lbs_deb_enter(LBS_DEB_SCAN); + mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { @@ -1215,6 +1267,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, out: mutex_unlock(&adapter->lock); + lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); return found_bss; } @@ -1235,6 +1288,8 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad struct bss_descriptor * iter_bss; struct bss_descriptor * best_bss = NULL; + lbs_deb_enter(LBS_DEB_SCAN); + mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { @@ -1259,12 +1314,15 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad } mutex_unlock(&adapter->lock); + lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); return best_bss; } /** * @brief Find the AP with specific ssid in the scan list * + * Used from association worker. + * * @param priv A pointer to wlan_private structure * @param pSSID A pointer to AP's ssid * @@ -1277,11 +1335,11 @@ int libertas_find_best_network_ssid(wlan_private * priv, int ret = -1; struct bss_descriptor * found; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); wlan_scan_networks(priv, NULL, 1); if (adapter->surpriseremoved) - return -1; + goto out; wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); @@ -1293,6 +1351,7 @@ int libertas_find_best_network_ssid(wlan_private * priv, ret = 0; } +out: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } @@ -1327,10 +1386,17 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, return 0; } + /** * @brief Send a scan command for all available channels filtered on a spec * + * Used in association code and from debugfs + * * @param priv A pointer to wlan_private structure + * @param ssid A pointer to the SSID to scan for + * @param ssid_len Length of the SSID + * @param clear_ssid Should existing scan results with this SSID + * be cleared? * @param prequestedssid A pointer to AP's ssid * @param keeppreviousscan Flag used to save/clear scan table before scan * @@ -1343,7 +1409,8 @@ int libertas_send_specific_ssid_scan(wlan_private * priv, struct wlan_ioctl_user_scan_cfg scancfg; int ret = 0; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", + escape_essid(ssid, ssid_len), clear_ssid); if (!ssid_len) goto out; @@ -1354,15 +1421,26 @@ int libertas_send_specific_ssid_scan(wlan_private * priv, scancfg.clear_ssid = clear_ssid; wlan_scan_networks(priv, &scancfg, 1); - if (adapter->surpriseremoved) - return -1; + if (adapter->surpriseremoved) { + ret = -1; + goto out; + } wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); out: - lbs_deb_leave(LBS_DEB_ASSOC); + lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } + + + +/*********************************************************************/ +/* */ +/* Support for Wireless Extensions */ +/* */ +/*********************************************************************/ + #define MAX_CUSTOM_LEN 64 static inline char *libertas_translate_scan(wlan_private *priv, @@ -1379,10 +1457,13 @@ static inline char *libertas_translate_scan(wlan_private *priv, #define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) u8 rssi; + lbs_deb_enter(LBS_DEB_SCAN); + cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel); if (!cfp) { lbs_deb_scan("Invalid channel number %d\n", bss->channel); - return NULL; + start = NULL; + goto out; } /* First entry *MUST* be the AP BSSID */ @@ -1510,11 +1591,13 @@ static inline char *libertas_translate_scan(wlan_private *priv, start = iwe_stream_add_point(start, stop, &iwe, custom); } +out: + lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start); return start; } /** - * @brief Retrieve the scan table entries via wireless tools IOCTL call + * @brief Handle Retrieve scan table ioctl * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -1535,7 +1618,7 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, struct bss_descriptor * iter_bss; struct bss_descriptor * safe; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); /* Update RSSI if current BSS is a locally created ad-hoc BSS */ if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { @@ -1577,19 +1660,27 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, dwrq->length = (ev - extra); dwrq->flags = 0; - lbs_deb_leave(LBS_DEB_ASSOC); + lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err); return err; } + + + +/*********************************************************************/ +/* */ +/* Command execution */ +/* */ +/*********************************************************************/ + + /** * @brief Prepare a scan command to be sent to the firmware * - * Use the wlan_scan_cmd_config sent to the command processing module in - * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command - * struct to send to firmware. + * Called from libertas_prepare_and_send_command() in cmd.c * - * The fixed fields specifying the BSS type and BSSID filters as well as a - * variable number/length of TLVs are sent in the command to firmware. + * Sends a fixed lenght data part (specifying the BSS type and BSSID filters) + * as well as a variable number/length of TLVs to the firmware. * * @param priv A pointer to wlan_private structure * @param cmd A pointer to cmd_ds_command structure to be sent to @@ -1598,18 +1689,14 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, * to set the fields/TLVs for the command sent to firmware * * @return 0 or -1 - * - * @sa wlan_scan_create_channel_list */ int libertas_cmd_80211_scan(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf) { struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; - struct wlan_scan_cmd_config *pscancfg; + struct wlan_scan_cmd_config *pscancfg = pdata_buf; - lbs_deb_enter(LBS_DEB_ASSOC); - - pscancfg = pdata_buf; + lbs_deb_enter(LBS_DEB_SCAN); /* Set fixed field variables in scan command */ pscan->bsstype = pscancfg->bsstype; @@ -1622,11 +1709,11 @@ int libertas_cmd_80211_scan(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN + pscancfg->tlvbufferlen + S_DS_GEN); - lbs_deb_scan("SCAN_CMD: command=%x, size=%x, seqnum=%x\n", + lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n", le16_to_cpu(cmd->command), le16_to_cpu(cmd->size), le16_to_cpu(cmd->seqnum)); - lbs_deb_leave(LBS_DEB_ASSOC); + lbs_deb_leave(LBS_DEB_SCAN); return 0; } @@ -1645,6 +1732,8 @@ static inline int is_same_network(struct bss_descriptor *src, /** * @brief This function handles the command response of scan * + * Called from handle_cmd_response() in cmdrespc. + * * The response buffer for the scan command has the following * memory layout: * @@ -1679,7 +1768,7 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) int tlvbufsize; int ret; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); /* Prune old entries from scan table */ list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { From cc32613792b9789cebb40240a56bd4a7675b86fc Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 9 Oct 2007 14:30:10 +0200 Subject: [PATCH 1782/2804] [PATCH] libertas: remove one superfluous include This makes scripts/checkincludes.pl happy. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 8a3c70e54075..cb59f46ed126 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -15,7 +15,6 @@ #include "defs.h" #include "dev.h" #include "if_usb.h" -#include "decl.h" #define MESSAGE_HEADER_LEN 4 From 04799fae8ecb42b2c687fa85fe32ff79ea0e9dc9 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 9 Oct 2007 15:04:14 +0200 Subject: [PATCH 1783/2804] [PATCH] libertas: let get nick return what set nick has set Make the get-nickname wireless extension actually work. Before this patch, I could do "iwconfig eth1 nick BLAH" but "iwconfig eth1" would have still showed "MRVL-USB8388" to me. Hey, and that was wrong anyway, I'm on a CF card, not on USB :-) Signed-off-by: Holger Schurig Acked-By: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 34 ++++++---------------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 0b2103e0af57..c6f5aa3cb465 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -237,37 +237,16 @@ static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - const char *cp; - char comm[6] = { "COMM-" }; - char mrvl[6] = { "MRVL-" }; - int cnt; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_WEXT); - /* - * Nick Name is not used internally in this mode, - * therefore return something useful instead. Jean II - */ + dwrq->length = strlen(adapter->nodename); + memcpy(extra, adapter->nodename, dwrq->length); + extra[dwrq->length] = '\0'; - strcpy(extra, mrvl); - - cp = strstr(libertas_driver_version, comm); - if (cp == libertas_driver_version) //skip leading "COMM-" - cp = libertas_driver_version + strlen(comm); - else - cp = libertas_driver_version; - - cnt = strlen(mrvl); - extra += cnt; - while (cnt < 16 && (*cp != '-')) { - *extra++ = toupper(*cp++); - cnt++; - } - - /* - * Push it out ! - */ - dwrq->length = cnt; + dwrq->flags = 1; /* active */ lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -297,6 +276,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, lbs_deb_leave(LBS_DEB_WEXT); return 0; } + static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { From 0654ff055c6ce5642eed88ba22915b0e56666794 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 4 Oct 2007 14:04:40 -0400 Subject: [PATCH 1784/2804] [PATCH] ieee80211_if_set_type: make check for master dev more explicit Problem description by Daniel Drake : "This sequence of events causes loss of connectivity: ifconfig eth7 down iwconfig eth7 mode monitor ifconfig eth7 up ifconfig eth7 down iwconfig eth7 mode managed At this point you are associated but TX does not work. This is because the eth7 hard_start_xmit is still ieee80211_monitor_start_xmit." The problem is caused by ieee80211_if_set_type checking for a non-zero hard_start_xmit pointer value in order to avoid changing that value for master devices. The fix is to make that check more explicitly linked to master devices rather than simply checking if the value has been previously set. CC: Daniel Drake Acked-by: Michael Wu Signed-off-by: John W. Linville --- net/mac80211/ieee80211_iface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index be7e77f66fee..43e505d29452 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -106,7 +106,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) * which already has a hard_start_xmit routine assigned * which must not be changed. */ - if (!dev->hard_start_xmit) + if (dev != sdata->local->mdev) dev->hard_start_xmit = ieee80211_subif_start_xmit; /* From e2f036da2f8f72894988670953a1141da785e4f5 Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Sun, 7 Oct 2007 16:35:31 +0200 Subject: [PATCH 1785/2804] [PATCH] mac80211: Defer setting of RX_FLAG_DECRYPTED. The decryption handlers will skip the frame if the RX_FLAG_DECRYPTED flag is set, so the early flag setting introduced by Johannes breaks decryption. To work around this, call the handlers first and then set the flag. Signed-off-by: Mattias Nissler Signed-off-by: John W. Linville --- net/mac80211/rx.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4c046af237e3..ece77766ea2b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -424,6 +424,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; int keyidx; int hdrlen; + ieee80211_txrx_result result = TXRX_DROP; struct ieee80211_key *stakey = NULL; /* @@ -522,21 +523,22 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; - /* either the frame will be decrypted or dropped */ - rx->u.rx.status->flag |= RX_FLAG_DECRYPTED; - switch (rx->key->conf.alg) { case ALG_WEP: - return ieee80211_crypto_wep_decrypt(rx); + result = ieee80211_crypto_wep_decrypt(rx); + break; case ALG_TKIP: - return ieee80211_crypto_tkip_decrypt(rx); + result = ieee80211_crypto_tkip_decrypt(rx); + break; case ALG_CCMP: - return ieee80211_crypto_ccmp_decrypt(rx); + result = ieee80211_crypto_ccmp_decrypt(rx); + break; } - /* not reached */ - WARN_ON(1); - return TXRX_DROP; + /* either the frame has been decrypted or will be dropped */ + rx->u.rx.status->flag |= RX_FLAG_DECRYPTED; + + return result; } static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) From 6d1e3aa7bd47faacc08fdda8f58896bfd13ad90a Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Fri, 5 Oct 2007 14:15:16 -0700 Subject: [PATCH 1786/2804] e1000: Simple optimizations in e1000_xmit_frame Some simple optimizations in e1000_xmit_frame. Signed-off-by: Krishna Kumar Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 10505de00bcc..047263830e6a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3261,14 +3261,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; - unsigned int len = skb->len; + unsigned int len = skb->len - skb->data_len; unsigned long flags; - unsigned int nr_frags = 0; - unsigned int mss = 0; + unsigned int nr_frags; + unsigned int mss; int count = 0; int tso; unsigned int f; - len -= skb->data_len; /* This goes back to the question of how to logically map a tx queue * to a flow. Right now, performance is impacted slightly negatively @@ -3302,7 +3301,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) * points to just header, pull a few bytes of payload from * frags into skb->data */ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); - if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { + if (skb->data_len && hdr_len == len) { switch (adapter->hw.mac_type) { unsigned int pull_size; case e1000_82544: From 4e6c709c5ab886be0ddbc96c4f96534e55920e68 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 5 Oct 2007 14:15:23 -0700 Subject: [PATCH 1787/2804] e1000e: Simple optimizations in e1000_xmit_frame After an e1000 patch from Krishna Kumar . Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/netdev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 3a0bb2afe387..600538bc932f 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3424,14 +3424,13 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int max_per_txd = E1000_MAX_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; - unsigned int len = skb->len; + unsigned int len = skb->len - skb->data_len; unsigned long irq_flags; - unsigned int nr_frags = 0; - unsigned int mss = 0; + unsigned int nr_frags; + unsigned int mss; int count = 0; int tso; unsigned int f; - len -= skb->data_len; if (test_bit(__E1000_DOWN, &adapter->state)) { dev_kfree_skb_any(skb); @@ -3459,7 +3458,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) * points to just header, pull a few bytes of payload from * frags into skb->data */ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); - if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { + if (skb->data_len && (hdr_len == len)) { unsigned int pull_size; pull_size = min((unsigned int)4, skb->data_len); From 309af40b5f4c2065c9a5f74a360ad3d3b0c9c9cd Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 5 Oct 2007 15:22:02 -0700 Subject: [PATCH 1788/2804] e1000e: restore flow control settings properly After a cable unplug the forced flow control settings were lost accidentally and the flow control settings fell back to the default EEPROM determined values. This breaks for people who want to run without fc enabled - after a cable reset the driver would refuse to run with fc disabled. Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/ethtool.c | 1 + drivers/net/e1000e/lib.c | 12 +++++++++--- drivers/net/e1000e/netdev.c | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 2e8218fb0579..b7a7e2ae5e13 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -301,6 +301,7 @@ static int e1000_set_pauseparam(struct net_device *netdev, hw->mac.original_fc = hw->mac.fc; if (adapter->fc_autoneg == AUTONEG_ENABLE) { + hw->mac.fc = e1000_fc_default; if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 3bbfe605e111..0bdeca30c75f 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -639,9 +639,15 @@ s32 e1000e_setup_link(struct e1000_hw *hw) if (e1000_check_reset_block(hw)) return 0; - ret_val = e1000_set_default_fc_generic(hw); - if (ret_val) - return ret_val; + /* + * If flow control is set to default, set flow control based on + * the EEPROM flow control settings. + */ + if (mac->fc == e1000_fc_default) { + ret_val = e1000_set_default_fc_generic(hw); + if (ret_val) + return ret_val; + } /* We want to save off the original Flow Control configuration just * in case we get disconnected and then reconnected into a different diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 600538bc932f..033e124d1c1f 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4195,6 +4195,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; + adapter->fc_autoneg = 1; adapter->hw.mac.original_fc = e1000_fc_default; adapter->hw.mac.fc = e1000_fc_default; adapter->hw.phy.autoneg_advertised = 0x2f; From 43b7c451a03fe5f615710e26e8e2a3dd70eaa5b1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 5 Oct 2007 12:39:21 -0700 Subject: [PATCH 1789/2804] s2io: sparse warnings fix (rev2) Fix warnings from sparse checker about shadowed definition and improperly formatted ethtool_strings. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 97 ++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 203cc1e87de0..22e4054d4fcb 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -38,7 +38,7 @@ * Tx descriptors that can be associated with each corresponding FIFO. * intr_type: This defines the type of interrupt. The values can be 0(INTA), * 2(MSI_X). Default value is '2(MSI_X)' - * lro: Specifies whether to enable Large Receive Offload (LRO) or not. + * lro_enable: Specifies whether to enable Large Receive Offload (LRO) or not. * Possible values '1' for enable '0' for disable. Default is '0' * lro_max_pkts: This parameter defines maximum number of packets can be * aggregated as a single large packet @@ -276,46 +276,46 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { {"ring_5_full_cnt"}, {"ring_6_full_cnt"}, {"ring_7_full_cnt"}, - ("alarm_transceiver_temp_high"), - ("alarm_transceiver_temp_low"), - ("alarm_laser_bias_current_high"), - ("alarm_laser_bias_current_low"), - ("alarm_laser_output_power_high"), - ("alarm_laser_output_power_low"), - ("warn_transceiver_temp_high"), - ("warn_transceiver_temp_low"), - ("warn_laser_bias_current_high"), - ("warn_laser_bias_current_low"), - ("warn_laser_output_power_high"), - ("warn_laser_output_power_low"), - ("lro_aggregated_pkts"), - ("lro_flush_both_count"), - ("lro_out_of_sequence_pkts"), - ("lro_flush_due_to_max_pkts"), - ("lro_avg_aggr_pkts"), - ("mem_alloc_fail_cnt"), - ("pci_map_fail_cnt"), - ("watchdog_timer_cnt"), - ("mem_allocated"), - ("mem_freed"), - ("link_up_cnt"), - ("link_down_cnt"), - ("link_up_time"), - ("link_down_time"), - ("tx_tcode_buf_abort_cnt"), - ("tx_tcode_desc_abort_cnt"), - ("tx_tcode_parity_err_cnt"), - ("tx_tcode_link_loss_cnt"), - ("tx_tcode_list_proc_err_cnt"), - ("rx_tcode_parity_err_cnt"), - ("rx_tcode_abort_cnt"), - ("rx_tcode_parity_abort_cnt"), - ("rx_tcode_rda_fail_cnt"), - ("rx_tcode_unkn_prot_cnt"), - ("rx_tcode_fcs_err_cnt"), - ("rx_tcode_buf_size_err_cnt"), - ("rx_tcode_rxd_corrupt_cnt"), - ("rx_tcode_unkn_err_cnt"), + {"alarm_transceiver_temp_high"}, + {"alarm_transceiver_temp_low"}, + {"alarm_laser_bias_current_high"}, + {"alarm_laser_bias_current_low"}, + {"alarm_laser_output_power_high"}, + {"alarm_laser_output_power_low"}, + {"warn_transceiver_temp_high"}, + {"warn_transceiver_temp_low"}, + {"warn_laser_bias_current_high"}, + {"warn_laser_bias_current_low"}, + {"warn_laser_output_power_high"}, + {"warn_laser_output_power_low"}, + {"lro_aggregated_pkts"}, + {"lro_flush_both_count"}, + {"lro_out_of_sequence_pkts"}, + {"lro_flush_due_to_max_pkts"}, + {"lro_avg_aggr_pkts"}, + {"mem_alloc_fail_cnt"}, + {"pci_map_fail_cnt"}, + {"watchdog_timer_cnt"}, + {"mem_allocated"}, + {"mem_freed"}, + {"link_up_cnt"}, + {"link_down_cnt"}, + {"link_up_time"}, + {"link_down_time"}, + {"tx_tcode_buf_abort_cnt"}, + {"tx_tcode_desc_abort_cnt"}, + {"tx_tcode_parity_err_cnt"}, + {"tx_tcode_link_loss_cnt"}, + {"tx_tcode_list_proc_err_cnt"}, + {"rx_tcode_parity_err_cnt"}, + {"rx_tcode_abort_cnt"}, + {"rx_tcode_parity_abort_cnt"}, + {"rx_tcode_rda_fail_cnt"}, + {"rx_tcode_unkn_prot_cnt"}, + {"rx_tcode_fcs_err_cnt"}, + {"rx_tcode_buf_size_err_cnt"}, + {"rx_tcode_rxd_corrupt_cnt"}, + {"rx_tcode_unkn_err_cnt"}, {"tda_err_cnt"}, {"pfc_err_cnt"}, {"pcc_err_cnt"}, @@ -468,7 +468,9 @@ S2IO_PARM_INT(rxsync_frequency, 3); /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ S2IO_PARM_INT(intr_type, 2); /* Large receive offload feature */ -S2IO_PARM_INT(lro, 0); +static unsigned int lro_enable; +module_param_named(lro, lro_enable, uint, 0); + /* Max pkts to be aggregated by LRO at one time. If not specified, * aggregation happens until we hit max IP pkt size(64K) */ @@ -1759,7 +1761,7 @@ static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr) writeq(temp64, addr); } -void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) +static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) { struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 gen_int_mask = 0; @@ -4228,7 +4230,7 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) * 1 - if alarm bit set * 0 - if alarm bit is not set */ -int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, +static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, unsigned long long *cnt) { u64 val64; @@ -7135,7 +7137,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) int ret = 0; ret = s2io_club_tcp_session(skb->data, &tcp, - &tcp_len, &lro, rxdp, sp); + &tcp_len, &lro, + rxdp, sp); switch (ret) { case 3: /* Begin anew */ lro->parent = skb; @@ -7451,7 +7454,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) else sp->device_type = XFRAME_I_DEVICE; - sp->lro = lro; + sp->lro = lro_enable; /* Initialize some PCI/PCI-X fields of the NIC. */ s2io_init_pci(sp); @@ -7798,7 +7801,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) * the module loadable parameters and initializes PCI configuration space. */ -int __init s2io_starter(void) +static int __init s2io_starter(void) { return pci_register_driver(&s2io_driver); } From ddfce6bb43c6bf1c9956e7a65ce1b2e19a156bd2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 5 Oct 2007 17:19:47 -0700 Subject: [PATCH 1790/2804] network drivers: sparse warning fixes Fix some of the easy warnings in network device drivers. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/acenic.c | 37 ++++++++++++++++++------------------ drivers/net/atl1/atl1_main.c | 5 +++-- drivers/net/dl2k.c | 8 ++++---- drivers/net/e100.c | 2 +- drivers/net/hamachi.c | 3 +-- drivers/net/natsemi.c | 6 +++--- drivers/net/tehuti.c | 4 +--- 7 files changed, 32 insertions(+), 33 deletions(-) diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 2c2ed6dc98bc..6c192650d349 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -406,7 +406,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl); #define DEF_STAT (2 * TICKS_PER_SEC) -static int link[ACE_MAX_MOD_PARMS]; +static int link_state[ACE_MAX_MOD_PARMS]; static int trace[ACE_MAX_MOD_PARMS]; static int tx_coal_tick[ACE_MAX_MOD_PARMS]; static int rx_coal_tick[ACE_MAX_MOD_PARMS]; @@ -419,7 +419,7 @@ MODULE_AUTHOR("Jes Sorensen "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); -module_param_array(link, int, NULL, 0); +module_param_array_named(link, link_state, int, NULL, 0); module_param_array(trace, int, NULL, 0); module_param_array(tx_coal_tick, int, NULL, 0); module_param_array(max_tx_desc, int, NULL, 0); @@ -987,27 +987,27 @@ static int __devinit ace_init(struct net_device *dev) mac1 = 0; for(i = 0; i < 4; i++) { - int tmp; + int t; mac1 = mac1 << 8; - tmp = read_eeprom_byte(dev, 0x8c+i); - if (tmp < 0) { + t = read_eeprom_byte(dev, 0x8c+i); + if (t < 0) { ecode = -EIO; goto init_error; } else - mac1 |= (tmp & 0xff); + mac1 |= (t & 0xff); } mac2 = 0; for(i = 4; i < 8; i++) { - int tmp; + int t; mac2 = mac2 << 8; - tmp = read_eeprom_byte(dev, 0x8c+i); - if (tmp < 0) { + t = read_eeprom_byte(dev, 0x8c+i); + if (t < 0) { ecode = -EIO; goto init_error; } else - mac2 |= (tmp & 0xff); + mac2 |= (t & 0xff); } writel(mac1, ®s->MacAddrHi); @@ -1305,10 +1305,10 @@ static int __devinit ace_init(struct net_device *dev) writel(TX_RING_BASE, ®s->WinBase); if (ACE_IS_TIGON_I(ap)) { - ap->tx_ring = (struct tx_desc *) regs->Window; + ap->tx_ring = (__force struct tx_desc *) regs->Window; for (i = 0; i < (TIGON_I_TX_RING_ENTRIES * sizeof(struct tx_desc)) / sizeof(u32); i++) - writel(0, (void __iomem *)ap->tx_ring + i * 4); + writel(0, (__force void __iomem *)ap->tx_ring + i * 4); set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE); } else { @@ -1394,8 +1394,8 @@ static int __devinit ace_init(struct net_device *dev) /* * Override link default parameters */ - if ((board_idx >= 0) && link[board_idx]) { - int option = link[board_idx]; + if ((board_idx >= 0) && link_state[board_idx]) { + int option = link_state[board_idx]; tmp = LNK_ENABLE; @@ -2383,8 +2383,9 @@ static int ace_close(struct net_device *dev) if (mapping) { if (ACE_IS_TIGON_I(ap)) { - struct tx_desc __iomem *tx - = (struct tx_desc __iomem *) &ap->tx_ring[i]; + /* NB: TIGON_1 is special, tx_ring is in io space */ + struct tx_desc __iomem *tx; + tx = (__force struct tx_desc __iomem *) &ap->tx_ring[i]; writel(0, &tx->addr.addrhi); writel(0, &tx->addr.addrlo); writel(0, &tx->flagsize); @@ -2444,7 +2445,7 @@ ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr, #endif if (ACE_IS_TIGON_I(ap)) { - struct tx_desc __iomem *io = (struct tx_desc __iomem *) desc; + struct tx_desc __iomem *io = (__force struct tx_desc __iomem *) desc; writel(addr >> 32, &io->addr.addrhi); writel(addr & 0xffffffff, &io->addr.addrlo); writel(flagsize, &io->flagsize); @@ -2936,7 +2937,7 @@ static void __devinit ace_clear(struct ace_regs __iomem *regs, u32 dest, int siz * This operation requires the NIC to be halted and is performed with * interrupts disabled and with the spinlock hold. */ -int __devinit ace_load_firmware(struct net_device *dev) +static int __devinit ace_load_firmware(struct net_device *dev) { struct ace_private *ap = netdev_priv(dev); struct ace_regs __iomem *regs = ap->regs; diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 4c728f1169c4..35b0a7dd4ef4 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -1367,7 +1367,6 @@ rrd_ok: if (count) { u32 tpd_next_to_use; u32 rfd_next_to_use; - u32 rrd_next_to_clean; spin_lock(&adapter->mb_lock); @@ -1512,7 +1511,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, unsigned int f; u16 tpd_next_to_use; u16 proto_hdr_len; - u16 i, m, len12; + u16 len12; first_buf_len -= skb->data_len; nr_frags = skb_shinfo(skb)->nr_frags; @@ -1536,6 +1535,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, tpd_next_to_use = 0; if (first_buf_len > proto_hdr_len) { + int i, m; + len12 = first_buf_len - proto_hdr_len; m = (len12 + ATL1_MAX_TX_BUF_LEN - 1) / ATL1_MAX_TX_BUF_LEN; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index e91b7096838a..5066beb2e7bc 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -290,7 +290,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) return err; } -int +static int find_miiphy (struct net_device *dev) { int i, phy_found = 0; @@ -314,7 +314,7 @@ find_miiphy (struct net_device *dev) return 0; } -int +static int parse_eeprom (struct net_device *dev) { int i, j; @@ -1096,7 +1096,7 @@ clear_stats (struct net_device *dev) } -int +static int change_mtu (struct net_device *dev, int new_mtu) { struct netdev_private *np = netdev_priv(dev); @@ -1331,7 +1331,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) #define EEP_BUSY 0x8000 /* Read the EEPROM word */ /* We use I/O instruction to read/write eeprom to avoid fail on some machines */ -int +static int read_eeprom (long ioaddr, int eep_addr) { int i = 1000; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 7bd960402687..64f35e20fd48 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1990,7 +1990,7 @@ static int e100_poll(struct napi_struct *napi, int budget) { struct nic *nic = container_of(napi, struct nic, napi); struct net_device *netdev = nic->netdev; - int work_done = 0; + unsigned int work_done = 0; int tx_cleaned; e100_rx_clean(nic, &work_done, budget); diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 015ed3a4057f..ed407c85708f 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1017,7 +1017,7 @@ static inline int hamachi_tx(struct net_device *dev) break; /* Free the original skb. */ skb = hmp->tx_skbuff[entry]; - if (skb != 0) { + if (skb) { pci_unmap_single(hmp->pci_dev, hmp->tx_ring[entry].addr, skb->len, PCI_DMA_TODEVICE); @@ -1069,7 +1069,6 @@ static void hamachi_tx_timeout(struct net_device *dev) " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); { - int i; printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index ea38da6d31ff..322d16974000 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1615,7 +1615,7 @@ static void do_cable_magic(struct net_device *dev) * (these values all come from National) */ if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) { - struct netdev_private *np = netdev_priv(dev); + np = netdev_priv(dev); /* the bug has been triggered - fix the coefficient */ writew(TSTDAT_FIXED, ioaddr + TSTDAT); @@ -2502,8 +2502,8 @@ static void __set_rx_mode(struct net_device *dev) memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - int i = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; - mc_filter[i/8] |= (1 << (i & 0x07)); + int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; + mc_filter[b/8] |= (1 << (b & 0x07)); } rx_mode = RxFilterEnable | AcceptBroadcast | AcceptMulticast | AcceptMyPhys; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 248343177356..8d04654f0c59 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -750,7 +750,6 @@ bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp) */ static int bdx_change_mtu(struct net_device *ndev, int new_mtu) { - BDX_ASSERT(ndev == 0); ENTER; if (new_mtu == ndev->mtu) @@ -1002,7 +1001,7 @@ static inline void bdx_rxdb_free_elem(struct rxdb *db, int n) static int bdx_rx_init(struct bdx_priv *priv) { ENTER; - BDX_ASSERT(priv == 0); + if (bdx_fifo_init(priv, &priv->rxd_fifo0.m, priv->rxd_size, regRXD_CFG0_0, regRXD_CFG1_0, regRXD_RPTR_0, regRXD_WPTR_0)) @@ -1747,7 +1746,6 @@ static void bdx_tx_cleanup(struct bdx_priv *priv) tx_level -= db->rptr->len; /* '-' koz len is negative */ /* now should come skb pointer - free it */ - BDX_ASSERT(db->rptr->addr.skb == 0); dev_kfree_skb_irq(db->rptr->addr.skb); bdx_tx_db_inc_rptr(db); } From 3bf76b81608479a10077bd6b55972d40db782067 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Mon, 8 Oct 2007 16:01:33 +0200 Subject: [PATCH 1791/2804] ehea: use kernel event queue eHEA recovery and DLPAR functions are called seldomly. The eHEA workqueues are replaced by the kernel event queue. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea.h | 3 +-- drivers/net/ehea/ehea_main.c | 28 ++++++++-------------------- drivers/net/ehea/ehea_qmr.c | 3 +-- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 30220894b01f..ac21526b6de8 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0077" +#define DRV_VERSION "EHEA_0078" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 @@ -391,7 +391,6 @@ struct ehea_adapter { struct ibmebus_dev *ebus_dev; struct ehea_port *port[EHEA_MAX_PORTS]; struct ehea_eq *neq; /* notification event queue */ - struct workqueue_struct *ehea_wq; struct tasklet_struct neq_tasklet; struct ehea_mr mr; u32 pd; /* protection domain */ diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 5bc0a1530eb7..2ba57e6ace4d 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -94,7 +94,6 @@ MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, " static int port_name_cnt = 0; static LIST_HEAD(adapter_list); u64 ehea_driver_flags = 0; -struct workqueue_struct *ehea_driver_wq; struct work_struct ehea_rereg_mr_task; struct semaphore dlpar_mem_lock; @@ -421,7 +420,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) { ehea_error("Critical receive error. Resetting port."); - queue_work(pr->port->adapter->ehea_wq, &pr->port->reset_task); + schedule_work(&pr->port->reset_task); return 1; } @@ -596,8 +595,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) ehea_error("Send Completion Error: Resetting port"); if (netif_msg_tx_err(pr->port)) ehea_dump(cqe, sizeof(*cqe), "Send CQE"); - queue_work(pr->port->adapter->ehea_wq, - &pr->port->reset_task); + schedule_work(&pr->port->reset_task); break; } @@ -716,7 +714,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) eqe = ehea_poll_eq(port->qp_eq); } - queue_work(port->adapter->ehea_wq, &port->reset_task); + schedule_work(&port->reset_task); return IRQ_HANDLED; } @@ -2395,7 +2393,7 @@ static int ehea_stop(struct net_device *dev) if (netif_msg_ifdown(port)) ehea_info("disabling port %s", dev->name); - flush_workqueue(port->adapter->ehea_wq); + flush_scheduled_work(); down(&port->port_lock); netif_stop_queue(dev); ret = ehea_down(dev); @@ -2710,7 +2708,7 @@ static void ehea_tx_watchdog(struct net_device *dev) if (netif_carrier_ok(dev) && !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) - queue_work(port->adapter->ehea_wq, &port->reset_task); + schedule_work(&port->reset_task); } int ehea_sense_adapter_attr(struct ehea_adapter *adapter) @@ -3243,15 +3241,9 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, goto out_kill_eq; } - adapter->ehea_wq = create_workqueue("ehea_wq"); - if (!adapter->ehea_wq) { - ret = -EIO; - goto out_free_irq; - } - ret = ehea_create_device_sysfs(dev); if (ret) - goto out_kill_wq; + goto out_free_irq; ret = ehea_setup_ports(adapter); if (ret) { @@ -3265,9 +3257,6 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, out_rem_dev_sysfs: ehea_remove_device_sysfs(dev); -out_kill_wq: - destroy_workqueue(adapter->ehea_wq); - out_free_irq: ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); @@ -3293,7 +3282,7 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev) ehea_remove_device_sysfs(dev); - destroy_workqueue(adapter->ehea_wq); + flush_scheduled_work(); ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); tasklet_kill(&adapter->neq_tasklet); @@ -3351,7 +3340,6 @@ int __init ehea_module_init(void) printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n", DRV_VERSION); - ehea_driver_wq = create_workqueue("ehea_driver_wq"); INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs); sema_init(&dlpar_mem_lock, 1); @@ -3385,7 +3373,7 @@ out: static void __exit ehea_module_exit(void) { - destroy_workqueue(ehea_driver_wq); + flush_scheduled_work(); driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities); ibmebus_unregister_driver(&ehea_driver); ehea_destroy_busmap(); diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 329a25248d75..83b76432b41a 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -34,7 +34,6 @@ struct ehea_busmap ehea_bmap = { 0, 0, NULL }; extern u64 ehea_driver_flags; -extern struct workqueue_struct *ehea_driver_wq; extern struct work_struct ehea_rereg_mr_task; @@ -618,7 +617,7 @@ u64 ehea_map_vaddr(void *caddr) if (unlikely(mapped_addr == -1)) if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) - queue_work(ehea_driver_wq, &ehea_rereg_mr_task); + schedule_work(&ehea_rereg_mr_task); return mapped_addr; } From 33a85aa1c915c2f114bdac9b6d1ec00cc0fbc485 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 Oct 2007 16:19:10 -0700 Subject: [PATCH 1792/2804] chelsio: sparse warning fixes (old cxgb2) Fix problems detected by sparse: 1. whole chunk of MAC code was for defined and never used 2. hook for running ext intr in workqueue wasn't being used Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/chelsio/Makefile | 2 +- drivers/net/chelsio/common.h | 1 + drivers/net/chelsio/mac.c | 368 ----------------------------------- drivers/net/chelsio/subr.c | 2 +- 4 files changed, 3 insertions(+), 370 deletions(-) delete mode 100644 drivers/net/chelsio/mac.c diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile index 743ad8b41b5e..57a4b262fd3f 100644 --- a/drivers/net/chelsio/Makefile +++ b/drivers/net/chelsio/Makefile @@ -4,6 +4,6 @@ obj-$(CONFIG_CHELSIO_T1) += cxgb.o -cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o +cxgb-$(CONFIG_CHELSIO_T1_1G) += mv88e1xxx.o vsc7326.o cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ mv88x201x.o my3126.o $(cxgb-y) diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index b5de4452cf24..846ca5383d3c 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -372,6 +372,7 @@ extern void t1_interrupts_enable(adapter_t *adapter); extern void t1_interrupts_disable(adapter_t *adapter); extern void t1_interrupts_clear(adapter_t *adapter); extern int t1_elmer0_ext_intr_handler(adapter_t *adapter); +extern void t1_elmer0_ext_intr(adapter_t *adapter); extern int t1_slow_intr_handler(adapter_t *adapter); extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c deleted file mode 100644 index 1d972825eac3..000000000000 --- a/drivers/net/chelsio/mac.c +++ /dev/null @@ -1,368 +0,0 @@ -/* $Date: 2005/10/22 00:42:59 $ $RCSfile: mac.c,v $ $Revision: 1.32 $ */ -#include "gmac.h" -#include "regs.h" -#include "fpga_defs.h" - -#define MAC_CSR_INTERFACE_GMII 0x0 -#define MAC_CSR_INTERFACE_TBI 0x1 -#define MAC_CSR_INTERFACE_MII 0x2 -#define MAC_CSR_INTERFACE_RMII 0x3 - -/* Chelsio's MAC statistics. */ -struct mac_statistics { - - /* Transmit */ - u32 TxFramesTransmittedOK; - u32 TxReserved1; - u32 TxReserved2; - u32 TxOctetsTransmittedOK; - u32 TxFramesWithDeferredXmissions; - u32 TxLateCollisions; - u32 TxFramesAbortedDueToXSCollisions; - u32 TxFramesLostDueToIntMACXmitError; - u32 TxReserved3; - u32 TxMulticastFrameXmittedOK; - u32 TxBroadcastFramesXmittedOK; - u32 TxFramesWithExcessiveDeferral; - u32 TxPAUSEMACCtrlFramesTransmitted; - - /* Receive */ - u32 RxFramesReceivedOK; - u32 RxFrameCheckSequenceErrors; - u32 RxAlignmentErrors; - u32 RxOctetsReceivedOK; - u32 RxFramesLostDueToIntMACRcvError; - u32 RxMulticastFramesReceivedOK; - u32 RxBroadcastFramesReceivedOK; - u32 RxInRangeLengthErrors; - u32 RxTxOutOfRangeLengthField; - u32 RxFrameTooLongErrors; - u32 RxPAUSEMACCtrlFramesReceived; -}; - -static int static_aPorts[] = { - FPGA_GMAC_INTERRUPT_PORT0, - FPGA_GMAC_INTERRUPT_PORT1, - FPGA_GMAC_INTERRUPT_PORT2, - FPGA_GMAC_INTERRUPT_PORT3 -}; - -struct _cmac_instance { - u32 index; -}; - -static int mac_intr_enable(struct cmac *mac) -{ - u32 mac_intr; - - if (t1_is_asic(mac->adapter)) { - /* ASIC */ - - /* We don't use the on chip MAC for ASIC products. */ - } else { - /* FPGA */ - - /* Set parent gmac interrupt. */ - mac_intr = readl(mac->adapter->regs + A_PL_ENABLE); - mac_intr |= FPGA_PCIX_INTERRUPT_GMAC; - writel(mac_intr, mac->adapter->regs + A_PL_ENABLE); - - mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); - mac_intr |= static_aPorts[mac->instance->index]; - writel(mac_intr, - mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); - } - - return 0; -} - -static int mac_intr_disable(struct cmac *mac) -{ - u32 mac_intr; - - if (t1_is_asic(mac->adapter)) { - /* ASIC */ - - /* We don't use the on chip MAC for ASIC products. */ - } else { - /* FPGA */ - - /* Set parent gmac interrupt. */ - mac_intr = readl(mac->adapter->regs + A_PL_ENABLE); - mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC; - writel(mac_intr, mac->adapter->regs + A_PL_ENABLE); - - mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); - mac_intr &= ~(static_aPorts[mac->instance->index]); - writel(mac_intr, - mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); - } - - return 0; -} - -static int mac_intr_clear(struct cmac *mac) -{ - u32 mac_intr; - - if (t1_is_asic(mac->adapter)) { - /* ASIC */ - - /* We don't use the on chip MAC for ASIC products. */ - } else { - /* FPGA */ - - /* Set parent gmac interrupt. */ - writel(FPGA_PCIX_INTERRUPT_GMAC, - mac->adapter->regs + A_PL_CAUSE); - mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); - mac_intr |= (static_aPorts[mac->instance->index]); - writel(mac_intr, - mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); - } - - return 0; -} - -static int mac_get_address(struct cmac *mac, u8 addr[6]) -{ - u32 data32_lo, data32_hi; - - data32_lo = readl(mac->adapter->regs - + MAC_REG_IDLO(mac->instance->index)); - data32_hi = readl(mac->adapter->regs - + MAC_REG_IDHI(mac->instance->index)); - - addr[0] = (u8) ((data32_hi >> 8) & 0xFF); - addr[1] = (u8) ((data32_hi) & 0xFF); - addr[2] = (u8) ((data32_lo >> 24) & 0xFF); - addr[3] = (u8) ((data32_lo >> 16) & 0xFF); - addr[4] = (u8) ((data32_lo >> 8) & 0xFF); - addr[5] = (u8) ((data32_lo) & 0xFF); - return 0; -} - -static int mac_reset(struct cmac *mac) -{ - u32 data32; - int mac_in_reset, time_out = 100; - int idx = mac->instance->index; - - data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx)); - writel(data32 | F_MAC_RESET, - mac->adapter->regs + MAC_REG_CSR(idx)); - - do { - data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx)); - - mac_in_reset = data32 & F_MAC_RESET; - if (mac_in_reset) - udelay(1); - } while (mac_in_reset && --time_out); - - if (mac_in_reset) { - CH_ERR("%s: MAC %d reset timed out\n", - mac->adapter->name, idx); - return 2; - } - - return 0; -} - -static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) -{ - u32 val; - - val = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE); - val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0); - val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0); - writel(val, - mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); - - return 0; -} - -static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, - int fc) -{ - u32 data32; - - data32 = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) | - V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE | - F_MAC_RX_PAUSE_ENABLE); - - switch (speed) { - case SPEED_10: - case SPEED_100: - data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII); - data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1); - break; - case SPEED_1000: - data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII); - data32 |= V_MAC_SPEED(2); - break; - } - - if (duplex >= 0) - data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF); - - if (fc >= 0) { - data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0); - data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0); - } - - writel(data32, - mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); - return 0; -} - -static int mac_enable(struct cmac *mac, int which) -{ - u32 val; - - val = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - if (which & MAC_DIRECTION_RX) - val |= F_MAC_RX_ENABLE; - if (which & MAC_DIRECTION_TX) - val |= F_MAC_TX_ENABLE; - writel(val, - mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); - return 0; -} - -static int mac_disable(struct cmac *mac, int which) -{ - u32 val; - - val = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - if (which & MAC_DIRECTION_RX) - val &= ~F_MAC_RX_ENABLE; - if (which & MAC_DIRECTION_TX) - val &= ~F_MAC_TX_ENABLE; - writel(val, - mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); - return 0; -} - -#if 0 -static int mac_set_ifs(struct cmac *mac, u32 mode) -{ - t1_write_reg_4(mac->adapter, - MAC_REG_IFS(mac->instance->index), - mode); - return 0; -} - -static int mac_enable_isl(struct cmac *mac) -{ - u32 data32 = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE; - t1_write_reg_4(mac->adapter, - MAC_REG_CSR(mac->instance->index), - data32); - return 0; -} -#endif - -static int mac_set_mtu(struct cmac *mac, int mtu) -{ - if (mtu > 9600) - return -EINVAL; - writel(mtu + ETH_HLEN + VLAN_HLEN, - mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index)); - - return 0; -} - -static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, - int flag) -{ - struct mac_statistics st; - u32 *p = (u32 *) & st, i; - - writel(0, - mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index)); - - for (i = 0; i < sizeof(st) / sizeof(u32); i++) - *p++ = readl(mac->adapter->regs - + MAC_REG_RMDATA(mac->instance->index)); - - /* XXX convert stats */ - return &mac->stats; -} - -static void mac_destroy(struct cmac *mac) -{ - kfree(mac); -} - -static struct cmac_ops chelsio_mac_ops = { - .destroy = mac_destroy, - .reset = mac_reset, - .interrupt_enable = mac_intr_enable, - .interrupt_disable = mac_intr_disable, - .interrupt_clear = mac_intr_clear, - .enable = mac_enable, - .disable = mac_disable, - .set_mtu = mac_set_mtu, - .set_rx_mode = mac_set_rx_mode, - .set_speed_duplex_fc = mac_set_speed_duplex_fc, - .macaddress_get = mac_get_address, - .statistics_update = mac_update_statistics, -}; - -static struct cmac *mac_create(adapter_t *adapter, int index) -{ - struct cmac *mac; - u32 data32; - - if (index >= 4) - return NULL; - - mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); - if (!mac) - return NULL; - - mac->ops = &chelsio_mac_ops; - mac->instance = (cmac_instance *) (mac + 1); - - mac->instance->index = index; - mac->adapter = adapter; - - data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index)); - data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC | - F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE); - data32 |= F_MAC_JUMBO_ENABLE; - writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index)); - - /* Initialize the random backoff seed. */ - data32 = 0x55aa + (3 * index); - writel(data32, - adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index)); - - /* Check to see if the mac address needs to be set manually. */ - data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index)); - if (data32 == 0 || data32 == 0xffffffff) { - /* - * Add a default MAC address if we can't read one. - */ - writel(0x43FFFFFF - index, - adapter->regs + MAC_REG_IDLO(mac->instance->index)); - writel(0x0007, - adapter->regs + MAC_REG_IDHI(mac->instance->index)); - } - - (void) mac_set_mtu(mac, 1500); - return mac; -} - -const struct gmac t1_chelsio_mac_ops = { - .create = mac_create -}; diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 7de9a611e1f7..dc50151bed81 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -884,7 +884,7 @@ static int asic_slow_intr(adapter_t *adapter) if (cause & F_PL_INTR_PCIX) t1_pci_intr_handler(adapter); if (cause & F_PL_INTR_EXT) - t1_elmer0_ext_intr_handler(adapter); + t1_elmer0_ext_intr(adapter); /* Clear the interrupts just processed. */ writel(cause, adapter->regs + A_PL_CAUSE); From 9265fabf0d4c3d0a52e169d4b9149d52fd91db69 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 Oct 2007 16:22:29 -0700 Subject: [PATCH 1793/2804] cxgb3 sparse warning fixes Fix warnings from sparse related to shadowed variables and routines that should be declared static. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_main.c | 4 +-- drivers/net/cxgb3/cxgb3_offload.c | 44 +++++++++++++++---------------- drivers/net/cxgb3/sge.c | 6 ++--- drivers/net/cxgb3/t3_hw.c | 8 +++--- drivers/net/cxgb3/xgmac.c | 2 +- 5 files changed, 31 insertions(+), 33 deletions(-) diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index e22d06531051..61ffc925eae7 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -740,7 +740,7 @@ static inline char t3rev2char(struct adapter *adapter) return rev; } -int update_tpsram(struct adapter *adap) +static int update_tpsram(struct adapter *adap) { const struct firmware *tpsram; char buf[64]; @@ -1769,7 +1769,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } case CHELSIO_SET_QSET_NUM:{ struct ch_reg edata; - struct port_info *pi = netdev_priv(dev); unsigned int i, first_qset = 0, other_qsets = 0; if (!capable(CAP_NET_ADMIN)) @@ -1801,7 +1800,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } case CHELSIO_GET_QSET_NUM:{ struct ch_reg edata; - struct port_info *pi = netdev_priv(dev); edata.cmd = CHELSIO_GET_QSET_NUM; edata.val = pi->nqsets; diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 1c8eec38bde3..bd25421bc12a 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -222,32 +222,32 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) int ret = 0; switch (req) { - case RDMA_GET_PARAMS:{ - struct rdma_info *req = data; + case RDMA_GET_PARAMS: { + struct rdma_info *rdma = data; struct pci_dev *pdev = adapter->pdev; - req->udbell_physbase = pci_resource_start(pdev, 2); - req->udbell_len = pci_resource_len(pdev, 2); - req->tpt_base = + rdma->udbell_physbase = pci_resource_start(pdev, 2); + rdma->udbell_len = pci_resource_len(pdev, 2); + rdma->tpt_base = t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT); - req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); - req->pbl_base = + rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); + rdma->pbl_base = t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT); - req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); - req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); - req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); - req->kdb_addr = adapter->regs + A_SG_KDOORBELL; - req->pdev = pdev; + rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); + rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); + rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); + rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL; + rdma->pdev = pdev; break; } case RDMA_CQ_OP:{ unsigned long flags; - struct rdma_cq_op *req = data; + struct rdma_cq_op *rdma = data; /* may be called in any context */ spin_lock_irqsave(&adapter->sge.reg_lock, flags); - ret = t3_sge_cqcntxt_op(adapter, req->id, req->op, - req->credits); + ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op, + rdma->credits); spin_unlock_irqrestore(&adapter->sge.reg_lock, flags); break; } @@ -274,15 +274,15 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) break; } case RDMA_CQ_SETUP:{ - struct rdma_cq_setup *req = data; + struct rdma_cq_setup *rdma = data; spin_lock_irq(&adapter->sge.reg_lock); ret = - t3_sge_init_cqcntxt(adapter, req->id, - req->base_addr, req->size, + t3_sge_init_cqcntxt(adapter, rdma->id, + rdma->base_addr, rdma->size, ASYNC_NOTIF_RSPQ, - req->ovfl_mode, req->credits, - req->credit_thres); + rdma->ovfl_mode, rdma->credits, + rdma->credit_thres); spin_unlock_irq(&adapter->sge.reg_lock); break; } @@ -292,13 +292,13 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) spin_unlock_irq(&adapter->sge.reg_lock); break; case RDMA_CTRL_QP_SETUP:{ - struct rdma_ctrlqp_setup *req = data; + struct rdma_ctrlqp_setup *rdma = data; spin_lock_irq(&adapter->sge.reg_lock); ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0, SGE_CNTXT_RDMA, ASYNC_NOTIF_RSPQ, - req->base_addr, req->size, + rdma->base_addr, rdma->size, FW_RI_TID_START, 1, 0); spin_unlock_irq(&adapter->sge.reg_lock); break; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 77f3ec5ff8a7..994b5d6404df 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -544,7 +544,7 @@ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, * as HW contexts, packet buffers, and descriptor rings. Traffic to the * queue set must be quiesced prior to calling this. */ -void t3_free_qset(struct adapter *adapter, struct sge_qset *q) +static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) { int i; struct pci_dev *pdev = adapter->pdev; @@ -2215,7 +2215,7 @@ irqreturn_t t3_sge_intr_msix(int irq, void *cookie) * The MSI-X interrupt handler for an SGE response queue for the NAPI case * (i.e., response queue serviced by NAPI polling). */ -irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) +static irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) { struct sge_qset *qs = cookie; struct sge_rspq *q = &qs->rspq; @@ -2284,7 +2284,7 @@ static int rspq_check_napi(struct sge_qset *qs) * one SGE response queue per port in this mode and protect all response * queues with queue 0's lock. */ -irqreturn_t t3_intr_msi_napi(int irq, void *cookie) +static irqreturn_t t3_intr_msi_napi(int irq, void *cookie) { int new_packets; struct adapter *adap = cookie; diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 058329321440..d4ee00d32219 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -119,9 +119,9 @@ void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, * Reads registers that are accessed indirectly through an address/data * register pair. */ -void t3_read_indirect(struct adapter *adap, unsigned int addr_reg, - unsigned int data_reg, u32 *vals, unsigned int nregs, - unsigned int start_idx) +static void t3_read_indirect(struct adapter *adap, unsigned int addr_reg, + unsigned int data_reg, u32 *vals, + unsigned int nregs, unsigned int start_idx) { while (nregs--) { t3_write_reg(adap, addr_reg, start_idx); @@ -3407,7 +3407,7 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai) * Older PCIe cards lose their config space during reset, PCI-X * ones don't. */ -int t3_reset_adapter(struct adapter *adapter) +static int t3_reset_adapter(struct adapter *adapter) { int i, save_and_restore_pcie = adapter->params.rev < T3_REV_B2 && is_pcie(adapter); diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index bcb5bc4e649b..eeb766aeced9 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -142,7 +142,7 @@ int t3_mac_reset(struct cmac *mac) return 0; } -int t3b2_mac_reset(struct cmac *mac) +static int t3b2_mac_reset(struct cmac *mac) { struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; From f2cade13371f3ca80c5479c284e6455c681c8a0c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Oct 2007 22:57:39 +0100 Subject: [PATCH 1794/2804] natsemi: Use NATSEMI_TIMER_FREQ consistently The natsemi driver has a define NATSEMI_TIMER_FREQ which looks like it controls the normal frequency of the chip poll timer but in fact only takes effect for the first run of the timer. Adjust the value of the define to match that used by the timer and use the define consistently. Signed-off-by: Mark Brown Signed-off-by: Jeff Garzik --- drivers/net/natsemi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 322d16974000..527f9dcc7f69 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -108,7 +108,7 @@ static int full_duplex[MAX_UNITS]; #define TX_TIMEOUT (2*HZ) #define NATSEMI_HW_TIMEOUT 400 -#define NATSEMI_TIMER_FREQ 3*HZ +#define NATSEMI_TIMER_FREQ 5*HZ #define NATSEMI_PG0_NREGS 64 #define NATSEMI_RFDR_NREGS 8 #define NATSEMI_PG1_NREGS 4 @@ -1798,7 +1798,7 @@ static void netdev_timer(unsigned long data) struct net_device *dev = (struct net_device *)data; struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); - int next_tick = 5*HZ; + int next_tick = NATSEMI_TIMER_FREQ; if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, From 9153f66a5b8e63c61374df4e6a4cbd0056e45178 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 15:46:13 -0700 Subject: [PATCH 1795/2804] IPoIB: Fix unused variable warning The conversion to use netdevice internal stats left an unused variable in ipoib_neigh_free(), since there's no longer any reason to get netdev_priv() in order to increment dropped packets. Delete the unused priv variable. Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 6b1b4b2ec5ba..855c9deca8b7 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -854,7 +854,6 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh) { - struct ipoib_dev_priv *priv = netdev_priv(dev); struct sk_buff *skb; *to_ipoib_neigh(neigh->neighbour) = NULL; while ((skb = __skb_dequeue(&neigh->queue))) { From bfe13f54f5028cff034e3b6247e9f433908f4f4f Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 15:47:37 -0700 Subject: [PATCH 1796/2804] ibm_emac: Convert to use napi_struct independent of struct net_device Commit da3dedd9 ("[NET]: Make NAPI polling independent of struct net_device objects.") changed the interface to NAPI polling. Fix up the ibm_emac driver so that it works with this new interface. This is actually a nice cleanup because ibm_emac is one of the drivers that wants to have multiple NAPI structures for a single net_device. Tested with the internal MAC of a PowerPC 440SPe SoC with an AMCC 'Yucca' evaluation board. Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/net/ibm_emac/ibm_emac_mal.c | 48 ++++++++++------------------- drivers/net/ibm_emac/ibm_emac_mal.h | 2 +- include/linux/netdevice.h | 10 ++++++ 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c index cabd9846a5ee..4e49e8c4f871 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -207,10 +207,10 @@ static irqreturn_t mal_serr(int irq, void *dev_instance) static inline void mal_schedule_poll(struct ibm_ocp_mal *mal) { - if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { + if (likely(napi_schedule_prep(&mal->napi))) { MAL_DBG2("%d: schedule_poll" NL, mal->def->index); mal_disable_eob_irq(mal); - __netif_rx_schedule(&mal->poll_dev); + __napi_schedule(&mal->napi); } else MAL_DBG2("%d: already in poll" NL, mal->def->index); } @@ -273,11 +273,11 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance) return IRQ_HANDLED; } -static int mal_poll(struct net_device *ndev, int *budget) +static int mal_poll(struct napi_struct *napi, int budget) { - struct ibm_ocp_mal *mal = ndev->priv; + struct ibm_ocp_mal *mal = container_of(napi, struct ibm_ocp_mal, napi); struct list_head *l; - int rx_work_limit = min(ndev->quota, *budget), received = 0, done; + int received = 0; MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget, rx_work_limit); @@ -295,38 +295,34 @@ static int mal_poll(struct net_device *ndev, int *budget) list_for_each(l, &mal->poll_list) { struct mal_commac *mc = list_entry(l, struct mal_commac, poll_list); - int n = mc->ops->poll_rx(mc->dev, rx_work_limit); + int n = mc->ops->poll_rx(mc->dev, budget); if (n) { received += n; - rx_work_limit -= n; - if (rx_work_limit <= 0) { - done = 0; + budget -= n; + if (budget <= 0) goto more_work; // XXX What if this is the last one ? - } } } /* We need to disable IRQs to protect from RXDE IRQ here */ local_irq_disable(); - __netif_rx_complete(ndev); + __napi_complete(napi); mal_enable_eob_irq(mal); local_irq_enable(); - done = 1; - /* Check for "rotting" packet(s) */ list_for_each(l, &mal->poll_list) { struct mal_commac *mc = list_entry(l, struct mal_commac, poll_list); if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) { MAL_DBG2("%d: rotting packet" NL, mal->def->index); - if (netif_rx_reschedule(ndev, received)) + if (napi_reschedule(napi)) mal_disable_eob_irq(mal); else MAL_DBG2("%d: already in poll list" NL, mal->def->index); - if (rx_work_limit > 0) + if (budget > 0) goto again; else goto more_work; @@ -335,12 +331,8 @@ static int mal_poll(struct net_device *ndev, int *budget) } more_work: - ndev->quota -= received; - *budget -= received; - - MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, *budget, - done ? 0 : 1); - return done ? 0 : 1; + MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, budget, received); + return received; } static void mal_reset(struct ibm_ocp_mal *mal) @@ -425,11 +417,8 @@ static int __init mal_probe(struct ocp_device *ocpdev) mal->def = ocpdev->def; INIT_LIST_HEAD(&mal->poll_list); - set_bit(__LINK_STATE_START, &mal->poll_dev.state); - mal->poll_dev.weight = CONFIG_IBM_EMAC_POLL_WEIGHT; - mal->poll_dev.poll = mal_poll; - mal->poll_dev.priv = mal; - atomic_set(&mal->poll_dev.refcnt, 1); + mal->napi.weight = CONFIG_IBM_EMAC_POLL_WEIGHT; + mal->napi.poll = mal_poll; INIT_LIST_HEAD(&mal->list); @@ -520,11 +509,8 @@ static void __exit mal_remove(struct ocp_device *ocpdev) MAL_DBG("%d: remove" NL, mal->def->index); - /* Syncronize with scheduled polling, - stolen from net/core/dev.c:dev_close() - */ - clear_bit(__LINK_STATE_START, &mal->poll_dev.state); - netif_poll_disable(&mal->poll_dev); + /* Synchronize with scheduled polling */ + napi_disable(&mal->napi); if (!list_empty(&mal->list)) { /* This is *very* bad */ diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h index 64bc338acc6c..8f54d621994d 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.h +++ b/drivers/net/ibm_emac/ibm_emac_mal.h @@ -195,7 +195,7 @@ struct ibm_ocp_mal { dcr_host_t dcrhost; struct list_head poll_list; - struct net_device poll_dev; + struct napi_struct napi; struct list_head list; u32 tx_chan_mask; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 91cd3f3db507..4848c7afa4e7 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -349,6 +349,16 @@ static inline void napi_schedule(struct napi_struct *n) __napi_schedule(n); } +/* Try to reschedule poll. Called by dev->poll() after napi_complete(). */ +static inline int napi_reschedule(struct napi_struct *napi) +{ + if (napi_schedule_prep(napi)) { + __napi_schedule(napi); + return 1; + } + return 0; +} + /** * napi_complete - NAPI processing complete * @n: napi context From 61ba5b3c14b4956493d1180e0a860e941108393e Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 15:47:59 -0700 Subject: [PATCH 1797/2804] ibm_new_emac: Nuke SET_MODULE_OWNER() use Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/net/ibm_newemac/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index ce127b9cafa4..8ea500961871 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2549,7 +2549,6 @@ static int __devinit emac_probe(struct of_device *ofdev, dev->ndev = ndev; dev->ofdev = ofdev; dev->blist = blist; - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &ofdev->dev); /* Initialize some embedded data structures */ From 59e90b2d22500f2e9cc635793562154abc8f4621 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 15:48:56 -0700 Subject: [PATCH 1798/2804] ibm_emac: Convert to use napi_struct independent of struct net_device Commit da3dedd9 ("[NET]: Make NAPI polling independent of struct net_device objects.") changed the interface to NAPI polling. Fix up the ibm_newemac driver so that it works with this new interface. This is actually a nice cleanup because ibm_newemac is one of the drivers that wants to have multiple NAPI structures for a single net_device. Compile-tested only as I don't have a system that uses the ibm_newemac driver. This conversion the conversion for the ibm_emac driver that was tested on real PowerPC 440SPe hardware. Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/net/ibm_newemac/mal.c | 55 ++++++++++++----------------------- drivers/net/ibm_newemac/mal.h | 2 +- 2 files changed, 20 insertions(+), 37 deletions(-) diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index c4335b7d308c..58854117b1a9 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c @@ -235,10 +235,10 @@ static irqreturn_t mal_serr(int irq, void *dev_instance) static inline void mal_schedule_poll(struct mal_instance *mal) { - if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { + if (likely(napi_schedule_prep(&mal->napi))) { MAL_DBG2(mal, "schedule_poll" NL); mal_disable_eob_irq(mal); - __netif_rx_schedule(&mal->poll_dev); + __napi_schedule(&mal->napi); } else MAL_DBG2(mal, "already in poll" NL); } @@ -318,8 +318,7 @@ void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac) msleep(1); /* Synchronize with the MAL NAPI poller. */ - while (test_bit(__LINK_STATE_RX_SCHED, &mal->poll_dev.state)) - msleep(1); + napi_disable(&mal->napi); } void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac) @@ -330,11 +329,11 @@ void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac) // XXX might want to kick a poll now... } -static int mal_poll(struct net_device *ndev, int *budget) +static int mal_poll(struct napi_struct *napi, int budget) { - struct mal_instance *mal = netdev_priv(ndev); + struct mal_instance *mal = container_of(napi, struct mal_instance, napi); struct list_head *l; - int rx_work_limit = min(ndev->quota, *budget), received = 0, done; + int received = 0; unsigned long flags; MAL_DBG2(mal, "poll(%d) %d ->" NL, *budget, @@ -358,26 +357,21 @@ static int mal_poll(struct net_device *ndev, int *budget) int n; if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags))) continue; - n = mc->ops->poll_rx(mc->dev, rx_work_limit); + n = mc->ops->poll_rx(mc->dev, budget); if (n) { received += n; - rx_work_limit -= n; - if (rx_work_limit <= 0) { - done = 0; - // XXX What if this is the last one ? - goto more_work; - } + budget -= n; + if (budget <= 0) + goto more_work; // XXX What if this is the last one ? } } /* We need to disable IRQs to protect from RXDE IRQ here */ spin_lock_irqsave(&mal->lock, flags); - __netif_rx_complete(ndev); + __napi_complete(napi); mal_enable_eob_irq(mal); spin_unlock_irqrestore(&mal->lock, flags); - done = 1; - /* Check for "rotting" packet(s) */ list_for_each(l, &mal->poll_list) { struct mal_commac *mc = @@ -387,12 +381,12 @@ static int mal_poll(struct net_device *ndev, int *budget) if (unlikely(mc->ops->peek_rx(mc->dev) || test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) { MAL_DBG2(mal, "rotting packet" NL); - if (netif_rx_reschedule(ndev, received)) + if (napi_reschedule(napi)) mal_disable_eob_irq(mal); else MAL_DBG2(mal, "already in poll list" NL); - if (rx_work_limit > 0) + if (budget > 0) goto again; else goto more_work; @@ -401,13 +395,8 @@ static int mal_poll(struct net_device *ndev, int *budget) } more_work: - ndev->quota -= received; - *budget -= received; - - MAL_DBG2(mal, "poll() %d <- %d" NL, *budget, - done ? 0 : 1); - - return done ? 0 : 1; + MAL_DBG2(mal, "poll() %d <- %d" NL, budget, received); + return received; } static void mal_reset(struct mal_instance *mal) @@ -538,11 +527,8 @@ static int __devinit mal_probe(struct of_device *ofdev, } INIT_LIST_HEAD(&mal->poll_list); - set_bit(__LINK_STATE_START, &mal->poll_dev.state); - mal->poll_dev.weight = CONFIG_IBM_NEW_EMAC_POLL_WEIGHT; - mal->poll_dev.poll = mal_poll; - mal->poll_dev.priv = mal; - atomic_set(&mal->poll_dev.refcnt, 1); + mal->napi.weight = CONFIG_IBM_NEW_EMAC_POLL_WEIGHT; + mal->napi.poll = mal_poll; INIT_LIST_HEAD(&mal->list); spin_lock_init(&mal->lock); @@ -653,11 +639,8 @@ static int __devexit mal_remove(struct of_device *ofdev) MAL_DBG(mal, "remove" NL); - /* Syncronize with scheduled polling, - stolen from net/core/dev.c:dev_close() - */ - clear_bit(__LINK_STATE_START, &mal->poll_dev.state); - netif_poll_disable(&mal->poll_dev); + /* Synchronize with scheduled polling */ + napi_disable(&mal->napi); if (!list_empty(&mal->list)) { /* This is *very* bad */ diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h index 57b69dc32e9d..cb1a16d589fe 100644 --- a/drivers/net/ibm_newemac/mal.h +++ b/drivers/net/ibm_newemac/mal.h @@ -197,7 +197,7 @@ struct mal_instance { int serr_irq; /* MAL System Error IRQ */ struct list_head poll_list; - struct net_device poll_dev; + struct napi_struct napi; struct list_head list; u32 tx_chan_mask; From 39699037a5c94d7cd1363dfe48a50c78c643fd9a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 10 Oct 2007 02:28:42 -0700 Subject: [PATCH 1799/2804] [FS] seq_file: Introduce the seq_open_private() This function allocates the zeroed chunk of memory and call seq_open(). The __seq_open_private() helper returns the allocated memory to make it possible for the caller to initialize it. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- fs/seq_file.c | 33 +++++++++++++++++++++++++++++++++ include/linux/seq_file.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/fs/seq_file.c b/fs/seq_file.c index bbb19be260ce..ca71c115bdaa 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -429,6 +429,39 @@ int seq_release_private(struct inode *inode, struct file *file) } EXPORT_SYMBOL(seq_release_private); +void *__seq_open_private(struct file *f, const struct seq_operations *ops, + int psize) +{ + int rc; + void *private; + struct seq_file *seq; + + private = kzalloc(psize, GFP_KERNEL); + if (private == NULL) + goto out; + + rc = seq_open(f, ops); + if (rc < 0) + goto out_free; + + seq = f->private_data; + seq->private = private; + return private; + +out_free: + kfree(private); +out: + return NULL; +} +EXPORT_SYMBOL(__seq_open_private); + +int seq_open_private(struct file *filp, const struct seq_operations *ops, + int psize) +{ + return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM; +} +EXPORT_SYMBOL(seq_open_private); + int seq_putc(struct seq_file *m, char c) { if (m->count < m->size) { diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 83783ab0f552..8bf1e05115b4 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -46,6 +46,8 @@ int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *); int single_open(struct file *, int (*)(struct seq_file *, void *), void *); int single_release(struct inode *, struct file *); +void *__seq_open_private(struct file *, const struct seq_operations *, int); +int seq_open_private(struct file *, const struct seq_operations *, int); int seq_release_private(struct inode *, struct file *); #define SEQ_START_TOKEN ((void *)1) From cf7732e4cc14b56d593ff53352673e1fd5e3ba52 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 10 Oct 2007 02:29:29 -0700 Subject: [PATCH 1800/2804] [NET]: Make core networking code use seq_open_private This concerns the ipv4 and ipv6 code mostly, but also the netlink and unix sockets. The netlink code is an example of how to use the __seq_open_private() call - it saves the net namespace on this private. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/arp.c | 20 ++---------------- net/ipv4/fib_hash.c | 20 ++---------------- net/ipv4/fib_trie.c | 42 ++++---------------------------------- net/ipv4/igmp.c | 38 ++++------------------------------ net/ipv4/ipmr.c | 43 ++++----------------------------------- net/ipv4/ipvs/ip_vs_ctl.c | 20 ++---------------- net/ipv4/raw.c | 20 ++---------------- net/ipv4/route.c | 19 ++--------------- net/ipv6/addrconf.c | 20 ++---------------- net/ipv6/anycast.c | 20 ++---------------- net/ipv6/ip6_flowlabel.c | 20 ++---------------- net/ipv6/mcast.c | 40 ++++-------------------------------- net/ipv6/raw.c | 17 ++-------------- net/netlink/af_netlink.c | 13 ++---------- net/unix/af_unix.c | 20 +----------------- 15 files changed, 37 insertions(+), 335 deletions(-) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index d8248198bcd7..36d6798947b5 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1378,24 +1378,8 @@ static const struct seq_operations arp_seq_ops = { static int arp_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct neigh_seq_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &arp_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &arp_seq_ops, + sizeof(struct neigh_seq_state)); } static const struct file_operations arp_seq_fops = { diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 9fafbeea8fe6..527a6e0af5b6 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -1039,24 +1039,8 @@ static const struct seq_operations fib_seq_ops = { static int fib_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct fib_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &fib_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &fib_seq_ops, + sizeof(struct fib_iter_state)); } static const struct file_operations fib_seq_fops = { diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index be34bd556d58..81a8285d6d6a 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2379,25 +2379,8 @@ static const struct seq_operations fib_trie_seq_ops = { static int fib_trie_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &fib_trie_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; - memset(s, 0, sizeof(*s)); -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &fib_trie_seq_ops, + sizeof(struct fib_trie_iter)); } static const struct file_operations fib_trie_fops = { @@ -2500,25 +2483,8 @@ static const struct seq_operations fib_route_seq_ops = { static int fib_route_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &fib_route_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; - memset(s, 0, sizeof(*s)); -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &fib_route_seq_ops, + sizeof(struct fib_trie_iter)); } static const struct file_operations fib_route_fops = { diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 2b6e59c4c0d0..7dbc282d4f9f 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2410,23 +2410,8 @@ static const struct seq_operations igmp_mc_seq_ops = { static int igmp_mc_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct igmp_mc_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - rc = seq_open(file, &igmp_mc_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &igmp_mc_seq_ops, + sizeof(struct igmp_mc_iter_state)); } static const struct file_operations igmp_mc_seq_fops = { @@ -2584,23 +2569,8 @@ static const struct seq_operations igmp_mcf_seq_ops = { static int igmp_mcf_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct igmp_mcf_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - rc = seq_open(file, &igmp_mcf_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &igmp_mcf_seq_ops, + sizeof(struct igmp_mcf_iter_state)); } static const struct file_operations igmp_mcf_seq_fops = { diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index b8b4b497fb57..37bb497d92af 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1714,26 +1714,8 @@ static const struct seq_operations ipmr_vif_seq_ops = { static int ipmr_vif_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct ipmr_vif_iter *s = kmalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &ipmr_vif_seq_ops); - if (rc) - goto out_kfree; - - s->ct = 0; - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; - + return seq_open_private(file, &ipmr_vif_seq_ops, + sizeof(struct ipmr_vif_iter)); } static const struct file_operations ipmr_vif_fops = { @@ -1877,25 +1859,8 @@ static const struct seq_operations ipmr_mfc_seq_ops = { static int ipmr_mfc_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct ipmr_mfc_iter *s = kmalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &ipmr_mfc_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; - + return seq_open_private(file, &ipmr_mfc_seq_ops, + sizeof(struct ipmr_mfc_iter)); } static const struct file_operations ipmr_mfc_fops = { diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index 61d023d58b5d..7345fc252a23 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -1792,24 +1792,8 @@ static const struct seq_operations ip_vs_info_seq_ops = { static int ip_vs_info_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct ip_vs_iter *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &ip_vs_info_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &ip_vs_info_seq_ops, + sizeof(struct ip_vs_iter)); } static const struct file_operations ip_vs_info_fops = { diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 07070c7067f3..3916faca3afe 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -902,24 +902,8 @@ static const struct seq_operations raw_seq_ops = { static int raw_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct raw_iter_state *s; - - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - goto out; - rc = seq_open(file, &raw_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &raw_seq_ops, + sizeof(struct raw_iter_state)); } static const struct file_operations raw_seq_fops = { diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 307e1f1107ca..21b12de9e653 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -375,23 +375,8 @@ static const struct seq_operations rt_cache_seq_ops = { static int rt_cache_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct rt_cache_iter_state *s; - - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - goto out; - rc = seq_open(file, &rt_cache_seq_ops); - if (rc) - goto out_kfree; - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &rt_cache_seq_ops, + sizeof(struct rt_cache_iter_state)); } static const struct file_operations rt_cache_seq_fops = { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6d5c3c299148..8b2d760ddf26 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2806,24 +2806,8 @@ static const struct seq_operations if6_seq_ops = { static int if6_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct if6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &if6_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &if6_seq_ops, + sizeof(struct if6_iter_state)); } static const struct file_operations if6_fops = { diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 5810852c558a..f915c4df9820 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -549,24 +549,8 @@ static const struct seq_operations ac6_seq_ops = { static int ac6_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct ac6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &ac6_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &ac6_seq_ops, + sizeof(struct ac6_iter_state)); } static const struct file_operations ac6_seq_fops = { diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 1791399c7f10..217d60f9fc80 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -658,24 +658,8 @@ static const struct seq_operations ip6fl_seq_ops = { static int ip6fl_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct ip6fl_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &ip6fl_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &ip6fl_seq_ops, + sizeof(struct ip6fl_iter_state)); } static const struct file_operations ip6fl_seq_fops = { diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index cc8d4e2a9531..331d728c2035 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2426,24 +2426,8 @@ static const struct seq_operations igmp6_mc_seq_ops = { static int igmp6_mc_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct igmp6_mc_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &igmp6_mc_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &igmp6_mc_seq_ops, + sizeof(struct igmp6_mc_iter_state)); } static const struct file_operations igmp6_mc_seq_fops = { @@ -2600,24 +2584,8 @@ static const struct seq_operations igmp6_mcf_seq_ops = { static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct igmp6_mcf_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &igmp6_mcf_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &igmp6_mcf_seq_ops, + sizeof(struct igmp6_mcf_iter_state)); } static const struct file_operations igmp6_mcf_seq_fops = { diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index bdd0974e6775..ca24ef19cd8f 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1289,21 +1289,8 @@ static const struct seq_operations raw6_seq_ops = { static int raw6_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct raw6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - goto out; - rc = seq_open(file, &raw6_seq_ops); - if (rc) - goto out_kfree; - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &raw6_seq_ops, + sizeof(struct raw6_iter_state)); } static const struct file_operations raw6_seq_fops = { diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3ef32825da71..f934f54fbfd5 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1845,27 +1845,18 @@ static const struct seq_operations netlink_seq_ops = { static int netlink_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; struct nl_seq_iter *iter; - int err; - iter = kzalloc(sizeof(*iter), GFP_KERNEL); + iter = __seq_open_private(file, &netlink_seq_ops, sizeof(*iter)); if (!iter) return -ENOMEM; - err = seq_open(file, &netlink_seq_ops); - if (err) { - kfree(iter); - return err; - } - - seq = file->private_data; - seq->private = iter; iter->net = get_proc_net(inode); if (!iter->net) { seq_release_private(inode, file); return -ENXIO; } + return 0; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 10e73122c34c..2b57eaf66abc 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2086,25 +2086,7 @@ static const struct seq_operations unix_seq_ops = { static int unix_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - int *iter = kmalloc(sizeof(int), GFP_KERNEL); - - if (!iter) - goto out; - - rc = seq_open(file, &unix_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = iter; - *iter = 0; -out: - return rc; -out_kfree: - kfree(iter); - goto out; + return seq_open_private(file, &unix_seq_ops, sizeof(int)); } static const struct file_operations unix_seq_fops = { From e2da59133880976586b2d9d81d798222ecafa566 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 10 Oct 2007 02:29:58 -0700 Subject: [PATCH 1801/2804] [NETFILTER]: Make netfilter code use the seq_open_private Just switch to the consolidated calls. ipt_recent() has to initialize the private, so use the __seq_open_private() helper. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_recent.c | 15 ++------ .../nf_conntrack_l3proto_ipv4_compat.c | 36 +++---------------- net/netfilter/nf_conntrack_expect.c | 18 ++-------- net/netfilter/nf_conntrack_standalone.c | 18 ++-------- net/netfilter/nfnetlink_log.c | 18 ++-------- net/netfilter/nfnetlink_queue.c | 18 ++-------- 6 files changed, 14 insertions(+), 109 deletions(-) diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index db2a79889f9a..11d39fb5f38b 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c @@ -381,25 +381,14 @@ static const struct seq_operations recent_seq_ops = { static int recent_seq_open(struct inode *inode, struct file *file) { struct proc_dir_entry *pde = PDE(inode); - struct seq_file *seq; struct recent_iter_state *st; - int ret; - st = kzalloc(sizeof(*st), GFP_KERNEL); + st = __seq_open_private(file, &recent_seq_ops, sizeof(*st)); if (st == NULL) return -ENOMEM; - ret = seq_open(file, &recent_seq_ops); - if (ret) { - kfree(st); - goto out; - } - st->table = pde->data; - seq = file->private_data; - seq->private = st; -out: - return ret; + return 0; } static ssize_t recent_proc_write(struct file *file, const char __user *input, diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index a5ae2eabf0f3..741f3dfaa5a1 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c @@ -174,22 +174,8 @@ static const struct seq_operations ct_seq_ops = { static int ct_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - struct ct_iter_state *st; - int ret; - - st = kzalloc(sizeof(struct ct_iter_state), GFP_KERNEL); - if (st == NULL) - return -ENOMEM; - ret = seq_open(file, &ct_seq_ops); - if (ret) - goto out_free; - seq = file->private_data; - seq->private = st; - return ret; -out_free: - kfree(st); - return ret; + return seq_open_private(file, &ct_seq_ops, + sizeof(struct ct_iter_state)); } static const struct file_operations ct_file_ops = { @@ -291,22 +277,8 @@ static const struct seq_operations exp_seq_ops = { static int exp_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - struct ct_expect_iter_state *st; - int ret; - - st = kzalloc(sizeof(struct ct_expect_iter_state), GFP_KERNEL); - if (!st) - return -ENOMEM; - ret = seq_open(file, &exp_seq_ops); - if (ret) - goto out_free; - seq = file->private_data; - seq->private = st; - return ret; -out_free: - kfree(st); - return ret; + return seq_open_private(file, &exp_seq_ops, + sizeof(struct ct_expect_iter_state)); } static const struct file_operations ip_exp_file_ops = { diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 7a0ae36c9b47..175c8d1a1992 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -472,22 +472,8 @@ static const struct seq_operations exp_seq_ops = { static int exp_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - struct ct_expect_iter_state *st; - int ret; - - st = kzalloc(sizeof(struct ct_expect_iter_state), GFP_KERNEL); - if (!st) - return -ENOMEM; - ret = seq_open(file, &exp_seq_ops); - if (ret) - goto out_free; - seq = file->private_data; - seq->private = st; - return ret; -out_free: - kfree(st); - return ret; + return seq_open_private(file, &exp_seq_ops, + sizeof(struct ct_expect_iter_state)); } static const struct file_operations exp_file_ops = { diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 2a19c5f1240f..9efdd37fc195 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -195,22 +195,8 @@ static const struct seq_operations ct_seq_ops = { static int ct_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - struct ct_iter_state *st; - int ret; - - st = kzalloc(sizeof(struct ct_iter_state), GFP_KERNEL); - if (st == NULL) - return -ENOMEM; - ret = seq_open(file, &ct_seq_ops); - if (ret) - goto out_free; - seq = file->private_data; - seq->private = st; - return ret; -out_free: - kfree(st); - return ret; + return seq_open_private(file, &ct_seq_ops, + sizeof(struct ct_iter_state)); } static const struct file_operations ct_file_ops = { diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 2135926199ca..2c7bd2eb0294 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -951,22 +951,8 @@ static const struct seq_operations nful_seq_ops = { static int nful_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - struct iter_state *is; - int ret; - - is = kzalloc(sizeof(*is), GFP_KERNEL); - if (!is) - return -ENOMEM; - ret = seq_open(file, &nful_seq_ops); - if (ret < 0) - goto out_free; - seq = file->private_data; - seq->private = is; - return ret; -out_free: - kfree(is); - return ret; + return seq_open_private(file, &nful_seq_ops, + sizeof(struct iter_state)); } static const struct file_operations nful_file_ops = { diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 48e095a7de2d..49f0480afe09 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -1051,22 +1051,8 @@ static const struct seq_operations nfqnl_seq_ops = { static int nfqnl_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - struct iter_state *is; - int ret; - - is = kzalloc(sizeof(*is), GFP_KERNEL); - if (!is) - return -ENOMEM; - ret = seq_open(file, &nfqnl_seq_ops); - if (ret < 0) - goto out_free; - seq = file->private_data; - seq->private = is; - return ret; -out_free: - kfree(is); - return ret; + return seq_open_private(file, &nfqnl_seq_ops, + sizeof(struct iter_state)); } static const struct file_operations nfqnl_file_ops = { From 31164088d72e1420e53f742b6c0c06f7343551dc Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 10 Oct 2007 02:30:23 -0700 Subject: [PATCH 1802/2804] [DECNET]: Make decnet code use the seq_open_private() Just switch to the consolidated code. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/decnet/dn_neigh.c | 20 ++------------------ net/decnet/dn_route.c | 19 ++----------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index b66e3be3eb84..e851b143cca3 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -580,24 +580,8 @@ static const struct seq_operations dn_neigh_seq_ops = { static int dn_neigh_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct neigh_seq_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &dn_neigh_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &dn_neigh_seq_ops, + sizeof(struct neigh_seq_state)); } static const struct file_operations dn_neigh_seq_fops = { diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index b7ebf9947ebd..97eee5e8fbbe 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1739,23 +1739,8 @@ static const struct seq_operations dn_rt_cache_seq_ops = { static int dn_rt_cache_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct dn_rt_cache_iter_state *s; - - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - goto out; - rc = seq_open(file, &dn_rt_cache_seq_ops); - if (rc) - goto out_kfree; - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &dn_rt_cache_seq_ops, + sizeof(struct dn_rt_cache_iter_state)); } static const struct file_operations dn_rt_cache_seq_fops = { From a662d4cb50d3976d2c9c9bac34119d0036e31d21 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 10 Oct 2007 02:30:45 -0700 Subject: [PATCH 1803/2804] [IRDA]: Make the IRDA use the seq_open_private() Just switch to the consolidated code Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/irda/irlap.c | 26 ++++---------------------- net/irda/irlmp.c | 21 ++------------------- net/irda/irttp.c | 21 ++------------------- 3 files changed, 8 insertions(+), 60 deletions(-) diff --git a/net/irda/irlap.c b/net/irda/irlap.c index 3d76aafdb2e5..f3236acc8d22 100644 --- a/net/irda/irlap.c +++ b/net/irda/irlap.c @@ -1219,29 +1219,11 @@ static const struct seq_operations irlap_seq_ops = { static int irlap_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct irlap_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); + if (irlap == NULL) + return -EINVAL; - if (!s) - goto out; - - if (irlap == NULL) { - rc = -EINVAL; - goto out_kfree; - } - - rc = seq_open(file, &irlap_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &irlap_seq_ops, + sizeof(struct irlap_iter_state)); } const struct file_operations irlap_seq_fops = { diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c index 7efa930ed684..7db92ced2c02 100644 --- a/net/irda/irlmp.c +++ b/net/irda/irlmp.c @@ -2003,27 +2003,10 @@ static const struct seq_operations irlmp_seq_ops = { static int irlmp_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct irlmp_iter_state *s; - IRDA_ASSERT(irlmp != NULL, return -EINVAL;); - s = kmalloc(sizeof(*s), GFP_KERNEL); - if (!s) - goto out; - - rc = seq_open(file, &irlmp_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &irlmp_seq_ops, + sizeof(struct irlmp_iter_state)); } const struct file_operations irlmp_seq_fops = { diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 3d7ab03fb131..1311976c9dfe 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -1884,25 +1884,8 @@ static const struct seq_operations irttp_seq_ops = { static int irttp_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct irttp_iter_state *s; - - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - goto out; - - rc = seq_open(file, &irttp_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &irttp_seq_ops, + sizeof(struct irttp_iter_state)); } const struct file_operations irttp_seq_fops = { From ec931035194709d0cde647d1c347bbf9634eec25 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 10 Oct 2007 02:31:07 -0700 Subject: [PATCH 1804/2804] [SUNRPC]: Make the sunrpc use the seq_open_private() Just switch to the consolidated code. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/sunrpc/cache.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index ebe344f34d1a..8e05557414ce 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1218,23 +1218,15 @@ static const struct seq_operations cache_content_op = { static int content_open(struct inode *inode, struct file *file) { - int res; struct handle *han; struct cache_detail *cd = PDE(inode)->data; - han = kmalloc(sizeof(*han), GFP_KERNEL); + han = __seq_open_private(file, &cache_content_op, sizeof(*han)); if (han == NULL) return -ENOMEM; han->cd = cd; - - res = seq_open(file, &cache_content_op); - if (res) - kfree(han); - else - ((struct seq_file *)file->private_data)->private = han; - - return res; + return 0; } static const struct file_operations content_file_operations = { From a349365e5e0e0590cf68957abd2ead1e5249fdef Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 17 Jul 2007 20:31:34 +0800 Subject: [PATCH 1805/2804] [CRYPTO] Kconfig: Remove "default m"s Other options requiring specific block cipher algorithms already have the appropriate select's. Signed-off-by: Adrian Bunk Signed-off-by: Herbert Xu --- crypto/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 3d1a1e27944f..ec8369cff322 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -146,7 +146,6 @@ config CRYPTO_ECB tristate "ECB support" select CRYPTO_BLKCIPHER select CRYPTO_MANAGER - default m help ECB: Electronic CodeBook mode This is the simplest block cipher algorithm. It simply encrypts @@ -156,7 +155,6 @@ config CRYPTO_CBC tristate "CBC support" select CRYPTO_BLKCIPHER select CRYPTO_MANAGER - default m help CBC: Cipher Block Chaining mode This block cipher algorithm is required for IPSec. @@ -165,7 +163,6 @@ config CRYPTO_PCBC tristate "PCBC support" select CRYPTO_BLKCIPHER select CRYPTO_MANAGER - default m help PCBC: Propagating Cipher Block Chaining mode This block cipher algorithm is required for RxRPC. From 44db25ca127281036817f861593389d7cfe950f5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 17 Jul 2007 20:33:16 +0800 Subject: [PATCH 1806/2804] [CRYPTO] drivers/Kconfig: Remove "default m"s Hardware drivers shouldn't default to m. Signed-off-by: Adrian Bunk Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index c0fc4aeb8596..5fd6688a444a 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -14,7 +14,6 @@ config CRYPTO_DEV_PADLOCK tristate "Support for VIA PadLock ACE" depends on X86_32 select CRYPTO_ALGAPI - default m help Some VIA processors come with an integrated crypto engine (so called VIA PadLock ACE, Advanced Cryptography Engine) @@ -28,7 +27,6 @@ config CRYPTO_DEV_PADLOCK_AES tristate "PadLock driver for AES algorithm" depends on CRYPTO_DEV_PADLOCK select CRYPTO_BLKCIPHER - default m help Use VIA PadLock for AES algorithm. @@ -42,7 +40,6 @@ config CRYPTO_DEV_PADLOCK_SHA depends on CRYPTO_DEV_PADLOCK select CRYPTO_SHA1 select CRYPTO_SHA256 - default m help Use VIA PadLock for SHA1/SHA256 algorithms. @@ -58,7 +55,6 @@ config CRYPTO_DEV_GEODE depends on X86_32 && PCI select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER - default m help Say 'Y' here to use the AMD Geode LX processor on-board AES engine for the CryptoAPI AES algorithm. @@ -70,7 +66,6 @@ config ZCRYPT tristate "Support for PCI-attached cryptographic adapters" depends on S390 select ZCRYPT_MONOLITHIC if ZCRYPT="y" - default "m" help Select this option if you want to use a PCI-attached cryptographic adapter like: From aa379a6ab17ff5b06552c52360ce6d9f8c7c209a Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Thu, 2 Aug 2007 20:41:53 +0800 Subject: [PATCH 1807/2804] [CRYPTO] api: Add crypto_ablkcipher_ctx_aligned This is function does the same thing for ablkcipher that is done for blkcipher by crypto_blkcipher_ctx_aligned(): it returns an aligned address of the private ctx. Signed-off-by: Sebastian Siewior Signed-off-by: Herbert Xu --- include/crypto/algapi.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index b2b1e6efd812..8081294e4328 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -160,6 +160,11 @@ static inline void *crypto_ablkcipher_ctx(struct crypto_ablkcipher *tfm) return crypto_tfm_ctx(&tfm->base); } +static inline void *crypto_ablkcipher_ctx_aligned(struct crypto_ablkcipher *tfm) +{ + return crypto_tfm_ctx_aligned(&tfm->base); +} + static inline struct crypto_blkcipher *crypto_spawn_blkcipher( struct crypto_spawn *spawn) { From e2ee95b8c69e542d6afef3f6f38ea598cc146ba7 Mon Sep 17 00:00:00 2001 From: Hye-Shik Chang Date: Tue, 21 Aug 2007 20:01:03 +0800 Subject: [PATCH 1808/2804] [CRYPTO] seed: New cipher algorithm This patch adds support for the SEED cipher (RFC4269). This patch have been used in few VPN appliance vendors in Korea for several years. And it was verified by KISA, who developed the algorithm itself. As its importance in Korean banking industry, it would be great if linux incorporates the support. Signed-off-by: Hye-Shik Chang Signed-off-by: Herbert Xu --- crypto/Kconfig | 14 ++ crypto/Makefile | 1 + crypto/seed.c | 479 ++++++++++++++++++++++++++++++++++++++++++++++++ crypto/tcrypt.c | 8 +- crypto/tcrypt.h | 90 +++++++++ 5 files changed, 591 insertions(+), 1 deletion(-) create mode 100644 crypto/seed.c diff --git a/crypto/Kconfig b/crypto/Kconfig index ec8369cff322..981497c89752 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -412,6 +412,20 @@ config CRYPTO_ANUBIS +config CRYPTO_SEED + tristate "SEED cipher algorithm" + select CRYPTO_ALGAPI + help + SEED cipher algorithm (RFC4269). + + SEED is a 128-bit symmetric key block cipher that has been + developed by KISA (Korea Information Security Agency) as a + national standard encryption algorithm of the Republic of Korea. + It is a 16 round block cipher with the key size of 128 bit. + + See also: + + config CRYPTO_DEFLATE tristate "Deflate compression algorithm" diff --git a/crypto/Makefile b/crypto/Makefile index 0cf17f1ea151..a070dcc074ff 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_TEA) += tea.o obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o +obj-$(CONFIG_CRYPTO_SEED) += seed.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o diff --git a/crypto/seed.c b/crypto/seed.c new file mode 100644 index 000000000000..d3e422f60556 --- /dev/null +++ b/crypto/seed.c @@ -0,0 +1,479 @@ +/* + * Cryptographic API. + * + * SEED Cipher Algorithm. + * + * 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. + * + * Documentation of SEED can be found in RFC 4269. + * Copyright (C) 2007 Korea Information Security Agency (KISA). + */ + +#include +#include +#include +#include +#include +#include + +#define SEED_NUM_KCONSTANTS 16 +#define SEED_KEY_SIZE 16 +#define SEED_BLOCK_SIZE 16 +#define SEED_KEYSCHED_LEN 32 + +/* + * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) + */ +static inline u8 +byte(const u32 x, const unsigned n) +{ + return x >> (n << 3); +} + +struct seed_ctx { + u32 keysched[SEED_KEYSCHED_LEN]; +}; + +static const u32 SS0[256] = { + 0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, + 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124, + 0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, + 0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360, + 0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, + 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314, + 0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, + 0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec, + 0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, + 0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074, + 0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, + 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100, + 0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, + 0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8, + 0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, + 0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8, + 0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, + 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c, + 0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, + 0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4, + 0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, + 0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008, + 0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, + 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0, + 0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, + 0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8, + 0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, + 0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208, + 0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, + 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064, + 0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, + 0x06060204, 0x21012120, 0x2b4b6368, 0x26466264, + 0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, + 0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0, + 0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, + 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc, + 0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, + 0x36063234, 0x15051114, 0x22022220, 0x38083038, + 0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, + 0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394, + 0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, + 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188, + 0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, + 0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4, + 0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, + 0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8, + 0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, + 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4, + 0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, + 0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040, + 0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, + 0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154, + 0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, + 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254, + 0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, + 0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8, + 0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, + 0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0, + 0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, + 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088, + 0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, + 0x22426260, 0x29092128, 0x07070304, 0x33033330, + 0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, + 0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298, +}; + +static const u32 SS1[256] = { + 0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, + 0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0, + 0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, + 0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53, + 0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, + 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3, + 0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, + 0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43, + 0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, + 0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0, + 0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, + 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890, + 0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, + 0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3, + 0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, + 0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272, + 0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, + 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83, + 0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, + 0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430, + 0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, + 0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0, + 0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, + 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1, + 0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, + 0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1, + 0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, + 0x20220222, 0x04040400, 0x68284860, 0x70314171, + 0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, + 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951, + 0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, + 0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0, + 0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, + 0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3, + 0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, + 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41, + 0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, + 0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62, + 0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, + 0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0, + 0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, + 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303, + 0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, + 0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901, + 0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, + 0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501, + 0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, + 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343, + 0x84058581, 0x14140410, 0x88098981, 0x981b8b93, + 0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971, + 0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, + 0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53, + 0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, + 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642, + 0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, + 0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1, + 0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, + 0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70, + 0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, + 0x30320232, 0x84048480, 0x68294961, 0x90138393, + 0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, + 0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783, + 0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, + 0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3, +}; + +static const u32 SS2[256] = { + 0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, + 0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505, + 0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, + 0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343, + 0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, + 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707, + 0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, + 0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece, + 0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, + 0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444, + 0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, + 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101, + 0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, + 0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9, + 0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, + 0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9, + 0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, + 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f, + 0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, + 0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5, + 0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, + 0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808, + 0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, + 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1, + 0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, + 0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b, + 0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, + 0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a, + 0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, + 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444, + 0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, + 0x02040606, 0x21202101, 0x63682b4b, 0x62642646, + 0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, + 0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0, + 0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, + 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf, + 0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, + 0x32343606, 0x11141505, 0x22202202, 0x30383808, + 0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, + 0x81800181, 0xe1e829c9, 0x80840484, 0x93941787, + 0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, + 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989, + 0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, + 0x90941484, 0x51581949, 0x82800282, 0xc0c404c4, + 0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, + 0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888, + 0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, + 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484, + 0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, + 0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040, + 0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, + 0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545, + 0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, + 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646, + 0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, + 0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca, + 0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, + 0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282, + 0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, + 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888, + 0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, + 0x62602242, 0x21282909, 0x03040707, 0x33303303, + 0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, + 0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a, +}; + +static const u32 SS3[256] = { + 0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, + 0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838, + 0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, + 0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b, + 0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, + 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427, + 0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, + 0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b, + 0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, + 0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434, + 0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, + 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818, + 0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, + 0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f, + 0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, + 0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032, + 0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, + 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b, + 0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, + 0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434, + 0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, + 0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838, + 0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, + 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839, + 0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, + 0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031, + 0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, + 0x02222022, 0x04000404, 0x48606828, 0x41717031, + 0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, + 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819, + 0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, + 0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010, + 0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, + 0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f, + 0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, + 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d, + 0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, + 0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e, + 0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, + 0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c, + 0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, + 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003, + 0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, + 0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809, + 0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, + 0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405, + 0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, + 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003, + 0x85818405, 0x04101414, 0x89818809, 0x8b93981b, + 0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839, + 0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, + 0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f, + 0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, + 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406, + 0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, + 0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d, + 0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, + 0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c, + 0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, + 0x02323032, 0x84808404, 0x49616829, 0x83939013, + 0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, + 0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407, + 0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, + 0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437, +}; + +static const u32 KC[SEED_NUM_KCONSTANTS] = { + 0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc, + 0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf, + 0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1, + 0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b, +}; + +#define OP(X1, X2, X3, X4, rbase) \ + t0 = X3 ^ ks[rbase]; \ + t1 = X4 ^ ks[rbase+1]; \ + t1 ^= t0; \ + t1 = SS0[byte(t1, 0)] ^ SS1[byte(t1, 1)] ^ \ + SS2[byte(t1, 2)] ^ SS3[byte(t1, 3)]; \ + t0 += t1; \ + t0 = SS0[byte(t0, 0)] ^ SS1[byte(t0, 1)] ^ \ + SS2[byte(t0, 2)] ^ SS3[byte(t0, 3)]; \ + t1 += t0; \ + t1 = SS0[byte(t1, 0)] ^ SS1[byte(t1, 1)] ^ \ + SS2[byte(t1, 2)] ^ SS3[byte(t1, 3)]; \ + t0 += t1; \ + X1 ^= t0; \ + X2 ^= t1; + +static int seed_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct seed_ctx *ctx = crypto_tfm_ctx(tfm); + u32 *keyout = ctx->keysched; + const __be32 *key = (const __be32 *)in_key; + u32 i, t0, t1, x1, x2, x3, x4; + + x1 = be32_to_cpu(key[0]); + x2 = be32_to_cpu(key[1]); + x3 = be32_to_cpu(key[2]); + x4 = be32_to_cpu(key[3]); + + for (i = 0; i < SEED_NUM_KCONSTANTS; i++) { + t0 = x1 + x3 - KC[i]; + t1 = x2 + KC[i] - x4; + *(keyout++) = SS0[byte(t0, 0)] ^ SS1[byte(t0, 1)] ^ + SS2[byte(t0, 2)] ^ SS3[byte(t0, 3)]; + *(keyout++) = SS0[byte(t1, 0)] ^ SS1[byte(t1, 1)] ^ + SS2[byte(t1, 2)] ^ SS3[byte(t1, 3)]; + + if (i % 2 == 0) { + t0 = x1; + x1 = (x1 >> 8) ^ (x2 << 24); + x2 = (x2 >> 8) ^ (t0 << 24); + } else { + t0 = x3; + x3 = (x3 << 8) ^ (x4 >> 24); + x4 = (x4 << 8) ^ (t0 >> 24); + } + } + + return 0; +} + +/* encrypt a block of text */ + +static void seed_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + const struct seed_ctx *ctx = crypto_tfm_ctx(tfm); + const __be32 *src = (const __be32 *)in; + __be32 *dst = (__be32 *)out; + u32 x1, x2, x3, x4, t0, t1; + const u32 *ks = ctx->keysched; + + x1 = be32_to_cpu(src[0]); + x2 = be32_to_cpu(src[1]); + x3 = be32_to_cpu(src[2]); + x4 = be32_to_cpu(src[3]); + + OP(x1, x2, x3, x4, 0); + OP(x3, x4, x1, x2, 2); + OP(x1, x2, x3, x4, 4); + OP(x3, x4, x1, x2, 6); + OP(x1, x2, x3, x4, 8); + OP(x3, x4, x1, x2, 10); + OP(x1, x2, x3, x4, 12); + OP(x3, x4, x1, x2, 14); + OP(x1, x2, x3, x4, 16); + OP(x3, x4, x1, x2, 18); + OP(x1, x2, x3, x4, 20); + OP(x3, x4, x1, x2, 22); + OP(x1, x2, x3, x4, 24); + OP(x3, x4, x1, x2, 26); + OP(x1, x2, x3, x4, 28); + OP(x3, x4, x1, x2, 30); + + dst[0] = cpu_to_be32(x3); + dst[1] = cpu_to_be32(x4); + dst[2] = cpu_to_be32(x1); + dst[3] = cpu_to_be32(x2); +} + +/* decrypt a block of text */ + +static void seed_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + const struct seed_ctx *ctx = crypto_tfm_ctx(tfm); + const __be32 *src = (const __be32 *)in; + __be32 *dst = (__be32 *)out; + u32 x1, x2, x3, x4, t0, t1; + const u32 *ks = ctx->keysched; + + x1 = be32_to_cpu(src[0]); + x2 = be32_to_cpu(src[1]); + x3 = be32_to_cpu(src[2]); + x4 = be32_to_cpu(src[3]); + + OP(x1, x2, x3, x4, 30); + OP(x3, x4, x1, x2, 28); + OP(x1, x2, x3, x4, 26); + OP(x3, x4, x1, x2, 24); + OP(x1, x2, x3, x4, 22); + OP(x3, x4, x1, x2, 20); + OP(x1, x2, x3, x4, 18); + OP(x3, x4, x1, x2, 16); + OP(x1, x2, x3, x4, 14); + OP(x3, x4, x1, x2, 12); + OP(x1, x2, x3, x4, 10); + OP(x3, x4, x1, x2, 8); + OP(x1, x2, x3, x4, 6); + OP(x3, x4, x1, x2, 4); + OP(x1, x2, x3, x4, 2); + OP(x3, x4, x1, x2, 0); + + dst[0] = cpu_to_be32(x3); + dst[1] = cpu_to_be32(x4); + dst[2] = cpu_to_be32(x1); + dst[3] = cpu_to_be32(x2); +} + + +static struct crypto_alg seed_alg = { + .cra_name = "seed", + .cra_driver_name = "seed-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = SEED_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct seed_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(seed_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = SEED_KEY_SIZE, + .cia_max_keysize = SEED_KEY_SIZE, + .cia_setkey = seed_set_key, + .cia_encrypt = seed_encrypt, + .cia_decrypt = seed_decrypt + } + } +}; + +static int __init seed_init(void) +{ + return crypto_register_alg(&seed_alg); +} + +static void __exit seed_fini(void) +{ + crypto_unregister_alg(&seed_alg); +} + +module_init(seed_init); +module_exit(seed_fini); + +MODULE_DESCRIPTION("SEED Cipher Algorithm"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Hye-Shik Chang , Kim Hyun "); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 11f935953816..de6435ea9bf8 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -78,7 +78,7 @@ static char *check[] = { "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt", - "camellia", NULL + "camellia", "seed", NULL }; static void hexdump(unsigned char *buf, unsigned int len) @@ -1029,6 +1029,12 @@ static void do_test(void) camellia_cbc_dec_tv_template, CAMELLIA_CBC_DEC_TEST_VECTORS); + //SEED + test_cipher("ecb(seed)", ENCRYPT, seed_enc_tv_template, + SEED_ENC_TEST_VECTORS); + test_cipher("ecb(seed)", DECRYPT, seed_dec_tv_template, + SEED_DEC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index 887527bd5bc6..beab3f345584 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -3831,6 +3831,96 @@ static struct cipher_testvec camellia_cbc_dec_tv_template[] = { }, }; +/* + * SEED test vectors + */ +#define SEED_ENC_TEST_VECTORS 4 +#define SEED_DEC_TEST_VECTORS 4 + +static struct cipher_testvec seed_enc_tv_template[] = { + { + .key = { [0 ... 15] = 0x00 }, + .klen = 16, + .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .ilen = 16, + .result = { 0x5e, 0xba, 0xc6, 0xe0, 0x05, 0x4e, 0x16, 0x68, + 0x19, 0xaf, 0xf1, 0xcc, 0x6d, 0x34, 0x6c, 0xdb }, + .rlen = 16, + }, { + .key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .klen = 16, + .input = { [0 ... 15] = 0x00 }, + .ilen = 16, + .result = { 0xc1, 0x1f, 0x22, 0xf2, 0x01, 0x40, 0x50, 0x50, + 0x84, 0x48, 0x35, 0x97, 0xe4, 0x37, 0x0f, 0x43 }, + .rlen = 16, + }, { + .key = { 0x47, 0x06, 0x48, 0x08, 0x51, 0xe6, 0x1b, 0xe8, + 0x5d, 0x74, 0xbf, 0xb3, 0xfd, 0x95, 0x61, 0x85 }, + .klen = 16, + .input = { 0x83, 0xa2, 0xf8, 0xa2, 0x88, 0x64, 0x1f, 0xb9, + 0xa4, 0xe9, 0xa5, 0xcc, 0x2f, 0x13, 0x1c, 0x7d }, + .ilen = 16, + .result = { 0xee, 0x54, 0xd1, 0x3e, 0xbc, 0xae, 0x70, 0x6d, + 0x22, 0x6b, 0xc3, 0x14, 0x2c, 0xd4, 0x0d, 0x4a }, + .rlen = 16, + }, { + .key = { 0x28, 0xdb, 0xc3, 0xbc, 0x49, 0xff, 0xd8, 0x7d, + 0xcf, 0xa5, 0x09, 0xb1, 0x1d, 0x42, 0x2b, 0xe7 }, + .klen = 16, + .input = { 0xb4, 0x1e, 0x6b, 0xe2, 0xeb, 0xa8, 0x4a, 0x14, + 0x8e, 0x2e, 0xed, 0x84, 0x59, 0x3c, 0x5e, 0xc7 }, + .ilen = 16, + .result = { 0x9b, 0x9b, 0x7b, 0xfc, 0xd1, 0x81, 0x3c, 0xb9, + 0x5d, 0x0b, 0x36, 0x18, 0xf4, 0x0f, 0x51, 0x22 }, + .rlen = 16, + } +}; + +static struct cipher_testvec seed_dec_tv_template[] = { + { + .key = { [0 ... 15] = 0x00 }, + .klen = 16, + .input = { 0x5e, 0xba, 0xc6, 0xe0, 0x05, 0x4e, 0x16, 0x68, + 0x19, 0xaf, 0xf1, 0xcc, 0x6d, 0x34, 0x6c, 0xdb }, + .ilen = 16, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .rlen = 16, + }, { + .key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .klen = 16, + .input = { 0xc1, 0x1f, 0x22, 0xf2, 0x01, 0x40, 0x50, 0x50, + 0x84, 0x48, 0x35, 0x97, 0xe4, 0x37, 0x0f, 0x43 }, + .ilen = 16, + .result = { [0 ... 15] = 0x00 }, + .rlen = 16, + }, { + .key = { 0x47, 0x06, 0x48, 0x08, 0x51, 0xe6, 0x1b, 0xe8, + 0x5d, 0x74, 0xbf, 0xb3, 0xfd, 0x95, 0x61, 0x85 }, + .klen = 16, + .input = { 0xee, 0x54, 0xd1, 0x3e, 0xbc, 0xae, 0x70, 0x6d, + 0x22, 0x6b, 0xc3, 0x14, 0x2c, 0xd4, 0x0d, 0x4a }, + .ilen = 16, + .result = { 0x83, 0xa2, 0xf8, 0xa2, 0x88, 0x64, 0x1f, 0xb9, + 0xa4, 0xe9, 0xa5, 0xcc, 0x2f, 0x13, 0x1c, 0x7d }, + .rlen = 16, + }, { + .key = { 0x28, 0xdb, 0xc3, 0xbc, 0x49, 0xff, 0xd8, 0x7d, + 0xcf, 0xa5, 0x09, 0xb1, 0x1d, 0x42, 0x2b, 0xe7 }, + .klen = 16, + .input = { 0x9b, 0x9b, 0x7b, 0xfc, 0xd1, 0x81, 0x3c, 0xb9, + 0x5d, 0x0b, 0x36, 0x18, 0xf4, 0x0f, 0x51, 0x22 }, + .ilen = 16, + .result = { 0xb4, 0x1e, 0x6b, 0xe2, 0xeb, 0xa8, 0x4a, 0x14, + 0x8e, 0x2e, 0xed, 0x84, 0x59, 0x3c, 0x5e, 0xc7 }, + .rlen = 16, + } +}; + /* * Compression stuff. */ From 1ae978208e2ee9ba1b01d309164bc5e590cd242d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Aug 2007 15:36:14 +0800 Subject: [PATCH 1809/2804] [CRYPTO] api: Add aead crypto type This patch adds crypto_aead which is the interface for AEAD (Authenticated Encryption with Associated Data) algorithms. AEAD algorithms perform authentication and encryption in one step. Traditionally users (such as IPsec) would use two different crypto algorithms to perform these. With AEAD this comes down to one algorithm and one operation. Of course if traditional algorithms were used we'd still be doing two operations underneath. However, real AEAD algorithms may allow the underlying operations to be optimised as well. Signed-off-by: Herbert Xu --- crypto/Kconfig | 4 + crypto/Makefile | 1 + crypto/aead.c | 101 ++++++++++++++++++++ include/crypto/algapi.h | 6 ++ include/linux/crypto.h | 200 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+) create mode 100644 crypto/aead.c diff --git a/crypto/Kconfig b/crypto/Kconfig index 981497c89752..f42bc7715f48 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -28,6 +28,10 @@ config CRYPTO_ABLKCIPHER tristate select CRYPTO_BLKCIPHER +config CRYPTO_AEAD + tristate + select CRYPTO_ALGAPI + config CRYPTO_BLKCIPHER tristate select CRYPTO_ALGAPI diff --git a/crypto/Makefile b/crypto/Makefile index a070dcc074ff..9821c5ba054e 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -9,6 +9,7 @@ crypto_algapi-objs := algapi.o $(crypto_algapi-y) obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o +obj-$(CONFIG_CRYPTO_AEAD) += aead.o obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o crypto_hash-objs := hash.o diff --git a/crypto/aead.c b/crypto/aead.c new file mode 100644 index 000000000000..84a3501fb478 --- /dev/null +++ b/crypto/aead.c @@ -0,0 +1,101 @@ +/* + * AEAD: Authenticated Encryption with Associated Data + * + * This file provides API support for AEAD algorithms. + * + * Copyright (c) 2007 Herbert Xu + * + * 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 + +static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, + unsigned int keylen) +{ + struct aead_alg *aead = crypto_aead_alg(tfm); + unsigned long alignmask = crypto_aead_alignmask(tfm); + int ret; + u8 *buffer, *alignbuffer; + unsigned long absize; + + absize = keylen + alignmask; + buffer = kmalloc(absize, GFP_ATOMIC); + if (!buffer) + return -ENOMEM; + + alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + memcpy(alignbuffer, key, keylen); + ret = aead->setkey(tfm, alignbuffer, keylen); + memset(alignbuffer, 0, keylen); + kfree(buffer); + return ret; +} + +static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) +{ + struct aead_alg *aead = crypto_aead_alg(tfm); + unsigned long alignmask = crypto_aead_alignmask(tfm); + + if ((unsigned long)key & alignmask) + return setkey_unaligned(tfm, key, keylen); + + return aead->setkey(tfm, key, keylen); +} + +static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) +{ + return alg->cra_ctxsize; +} + +static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +{ + struct aead_alg *alg = &tfm->__crt_alg->cra_aead; + struct aead_tfm *crt = &tfm->crt_aead; + + if (max(alg->authsize, alg->ivsize) > PAGE_SIZE / 8) + return -EINVAL; + + crt->setkey = setkey; + crt->encrypt = alg->encrypt; + crt->decrypt = alg->decrypt; + crt->ivsize = alg->ivsize; + crt->authsize = alg->authsize; + + return 0; +} + +static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) +{ + struct aead_alg *aead = &alg->cra_aead; + + seq_printf(m, "type : aead\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "ivsize : %u\n", aead->ivsize); + seq_printf(m, "authsize : %u\n", aead->authsize); +} + +const struct crypto_type crypto_aead_type = { + .ctxsize = crypto_aead_ctxsize, + .init = crypto_init_aead_ops, +#ifdef CONFIG_PROC_FS + .show = crypto_aead_show, +#endif +}; +EXPORT_SYMBOL_GPL(crypto_aead_type); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 8081294e4328..290bce0c5bd5 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -94,6 +94,7 @@ struct blkcipher_walk { }; extern const struct crypto_type crypto_ablkcipher_type; +extern const struct crypto_type crypto_aead_type; extern const struct crypto_type crypto_blkcipher_type; extern const struct crypto_type crypto_hash_type; @@ -165,6 +166,11 @@ static inline void *crypto_ablkcipher_ctx_aligned(struct crypto_ablkcipher *tfm) return crypto_tfm_ctx_aligned(&tfm->base); } +static inline struct aead_alg *crypto_aead_alg(struct crypto_aead *tfm) +{ + return &crypto_aead_tfm(tfm)->__crt_alg->cra_aead; +} + static inline struct crypto_blkcipher *crypto_spawn_blkcipher( struct crypto_spawn *spawn) { diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 357e8cfedc37..1072f9abaef6 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -34,6 +34,7 @@ #define CRYPTO_ALG_TYPE_HASH 0x00000003 #define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 #define CRYPTO_ALG_TYPE_COMPRESS 0x00000005 +#define CRYPTO_ALG_TYPE_AEAD 0x00000006 #define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e @@ -91,6 +92,7 @@ struct scatterlist; struct crypto_ablkcipher; struct crypto_async_request; +struct crypto_aead; struct crypto_blkcipher; struct crypto_hash; struct crypto_queue; @@ -121,6 +123,32 @@ struct ablkcipher_request { void *__ctx[] CRYPTO_MINALIGN_ATTR; }; +/** + * struct aead_request - AEAD request + * @base: Common attributes for async crypto requests + * @assoclen: Length in bytes of associated data for authentication + * @cryptlen: Length of data to be encrypted or decrypted + * @iv: Initialisation vector + * @assoc: Associated data + * @src: Source data + * @dst: Destination data + * @__ctx: Start of private context data + */ +struct aead_request { + struct crypto_async_request base; + + unsigned int assoclen; + unsigned int cryptlen; + + u8 *iv; + + struct scatterlist *assoc; + struct scatterlist *src; + struct scatterlist *dst; + + void *__ctx[] CRYPTO_MINALIGN_ATTR; +}; + struct blkcipher_desc { struct crypto_blkcipher *tfm; void *info; @@ -157,6 +185,16 @@ struct ablkcipher_alg { unsigned int ivsize; }; +struct aead_alg { + int (*setkey)(struct crypto_aead *tfm, const u8 *key, + unsigned int keylen); + int (*encrypt)(struct aead_request *req); + int (*decrypt)(struct aead_request *req); + + unsigned int ivsize; + unsigned int authsize; +}; + struct blkcipher_alg { int (*setkey)(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen); @@ -212,6 +250,7 @@ struct compress_alg { }; #define cra_ablkcipher cra_u.ablkcipher +#define cra_aead cra_u.aead #define cra_blkcipher cra_u.blkcipher #define cra_cipher cra_u.cipher #define cra_digest cra_u.digest @@ -237,6 +276,7 @@ struct crypto_alg { union { struct ablkcipher_alg ablkcipher; + struct aead_alg aead; struct blkcipher_alg blkcipher; struct cipher_alg cipher; struct digest_alg digest; @@ -284,6 +324,16 @@ struct ablkcipher_tfm { unsigned int reqsize; }; +struct aead_tfm { + int (*setkey)(struct crypto_aead *tfm, const u8 *key, + unsigned int keylen); + int (*encrypt)(struct aead_request *req); + int (*decrypt)(struct aead_request *req); + unsigned int ivsize; + unsigned int authsize; + unsigned int reqsize; +}; + struct blkcipher_tfm { void *iv; int (*setkey)(struct crypto_tfm *tfm, const u8 *key, @@ -323,6 +373,7 @@ struct compress_tfm { }; #define crt_ablkcipher crt_u.ablkcipher +#define crt_aead crt_u.aead #define crt_blkcipher crt_u.blkcipher #define crt_cipher crt_u.cipher #define crt_hash crt_u.hash @@ -334,6 +385,7 @@ struct crypto_tfm { union { struct ablkcipher_tfm ablkcipher; + struct aead_tfm aead; struct blkcipher_tfm blkcipher; struct cipher_tfm cipher; struct hash_tfm hash; @@ -349,6 +401,10 @@ struct crypto_ablkcipher { struct crypto_tfm base; }; +struct crypto_aead { + struct crypto_tfm base; +}; + struct crypto_blkcipher { struct crypto_tfm base; }; @@ -619,6 +675,150 @@ static inline void ablkcipher_request_set_crypt( req->info = iv; } +static inline struct crypto_aead *__crypto_aead_cast(struct crypto_tfm *tfm) +{ + return (struct crypto_aead *)tfm; +} + +static inline struct crypto_aead *crypto_alloc_aead(const char *alg_name, + u32 type, u32 mask) +{ + type &= ~CRYPTO_ALG_TYPE_MASK; + type |= CRYPTO_ALG_TYPE_AEAD; + mask |= CRYPTO_ALG_TYPE_MASK; + + return __crypto_aead_cast(crypto_alloc_base(alg_name, type, mask)); +} + +static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm) +{ + return &tfm->base; +} + +static inline void crypto_free_aead(struct crypto_aead *tfm) +{ + crypto_free_tfm(crypto_aead_tfm(tfm)); +} + +static inline struct aead_tfm *crypto_aead_crt(struct crypto_aead *tfm) +{ + return &crypto_aead_tfm(tfm)->crt_aead; +} + +static inline unsigned int crypto_aead_ivsize(struct crypto_aead *tfm) +{ + return crypto_aead_crt(tfm)->ivsize; +} + +static inline unsigned int crypto_aead_authsize(struct crypto_aead *tfm) +{ + return crypto_aead_crt(tfm)->authsize; +} + +static inline unsigned int crypto_aead_blocksize(struct crypto_aead *tfm) +{ + return crypto_tfm_alg_blocksize(crypto_aead_tfm(tfm)); +} + +static inline unsigned int crypto_aead_alignmask(struct crypto_aead *tfm) +{ + return crypto_tfm_alg_alignmask(crypto_aead_tfm(tfm)); +} + +static inline u32 crypto_aead_get_flags(struct crypto_aead *tfm) +{ + return crypto_tfm_get_flags(crypto_aead_tfm(tfm)); +} + +static inline void crypto_aead_set_flags(struct crypto_aead *tfm, u32 flags) +{ + crypto_tfm_set_flags(crypto_aead_tfm(tfm), flags); +} + +static inline void crypto_aead_clear_flags(struct crypto_aead *tfm, u32 flags) +{ + crypto_tfm_clear_flags(crypto_aead_tfm(tfm), flags); +} + +static inline int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, + unsigned int keylen) +{ + return crypto_aead_crt(tfm)->setkey(tfm, key, keylen); +} + +static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req) +{ + return __crypto_aead_cast(req->base.tfm); +} + +static inline int crypto_aead_encrypt(struct aead_request *req) +{ + return crypto_aead_crt(crypto_aead_reqtfm(req))->encrypt(req); +} + +static inline int crypto_aead_decrypt(struct aead_request *req) +{ + return crypto_aead_crt(crypto_aead_reqtfm(req))->decrypt(req); +} + +static inline int crypto_aead_reqsize(struct crypto_aead *tfm) +{ + return crypto_aead_crt(tfm)->reqsize; +} + +static inline void aead_request_set_tfm(struct aead_request *req, + struct crypto_aead *tfm) +{ + req->base.tfm = crypto_aead_tfm(tfm); +} + +static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm, + gfp_t gfp) +{ + struct aead_request *req; + + req = kmalloc(sizeof(*req) + crypto_aead_reqsize(tfm), gfp); + + if (likely(req)) + aead_request_set_tfm(req, tfm); + + return req; +} + +static inline void aead_request_free(struct aead_request *req) +{ + kfree(req); +} + +static inline void aead_request_set_callback(struct aead_request *req, + u32 flags, + crypto_completion_t complete, + void *data) +{ + req->base.complete = complete; + req->base.data = data; + req->base.flags = flags; +} + +static inline void aead_request_set_crypt(struct aead_request *req, + struct scatterlist *src, + struct scatterlist *dst, + unsigned int cryptlen, u8 *iv) +{ + req->src = src; + req->dst = dst; + req->cryptlen = cryptlen; + req->iv = iv; +} + +static inline void aead_request_set_assoc(struct aead_request *req, + struct scatterlist *assoc, + unsigned int assoclen) +{ + req->assoc = assoc; + req->assoclen = assoclen; +} + static inline struct crypto_blkcipher *__crypto_blkcipher_cast( struct crypto_tfm *tfm) { From 39e1ee011f42dbbcb0210c73ea728ae54cf63b06 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 29 Aug 2007 19:27:26 +0800 Subject: [PATCH 1810/2804] [CRYPTO] api: Add support for multiple template parameters This patch adds support for having multiple parameters to a template, separated by a comma. It also adds support for integer parameters in addition to the current algorithm parameter type. This will be used by the authenc template which will have four parameters: the authentication algorithm, the encryption algorithm, the authentication size and the encryption key length. Signed-off-by: Herbert Xu --- crypto/algapi.c | 8 +++- crypto/cryptomgr.c | 93 +++++++++++++++++++++++++++++++----------- include/linux/crypto.h | 8 ++++ 3 files changed, 83 insertions(+), 26 deletions(-) diff --git a/crypto/algapi.c b/crypto/algapi.c index 38aa9e994703..d9559609b525 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -439,13 +439,15 @@ EXPORT_SYMBOL_GPL(crypto_unregister_notifier); struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb) { - struct rtattr *rta = tb[CRYPTOA_TYPE - 1]; + struct rtattr *rta = tb[0]; struct crypto_attr_type *algt; if (!rta) return ERR_PTR(-ENOENT); if (RTA_PAYLOAD(rta) < sizeof(*algt)) return ERR_PTR(-EINVAL); + if (rta->rta_type != CRYPTOA_TYPE) + return ERR_PTR(-EINVAL); algt = RTA_DATA(rta); @@ -470,13 +472,15 @@ EXPORT_SYMBOL_GPL(crypto_check_attr_type); struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask) { - struct rtattr *rta = tb[CRYPTOA_ALG - 1]; + struct rtattr *rta = tb[1]; struct crypto_attr_alg *alga; if (!rta) return ERR_PTR(-ENOENT); if (RTA_PAYLOAD(rta) < sizeof(*alga)) return ERR_PTR(-EINVAL); + if (rta->rta_type != CRYPTOA_ALG) + return ERR_PTR(-EINVAL); alga = RTA_DATA(rta); alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0; diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c index e5fb7cca5107..c83884fec5f9 100644 --- a/crypto/cryptomgr.c +++ b/crypto/cryptomgr.c @@ -24,22 +24,26 @@ #include "internal.h" struct cryptomgr_param { - struct rtattr *tb[CRYPTOA_MAX]; + struct rtattr *tb[CRYPTO_MAX_ATTRS + 2]; struct { struct rtattr attr; struct crypto_attr_type data; } type; - struct { + union { struct rtattr attr; - struct crypto_attr_alg data; - } alg; - - struct { - char name[CRYPTO_MAX_ALG_NAME]; - } larval; + struct { + struct rtattr attr; + struct crypto_attr_alg data; + } alg; + struct { + struct rtattr attr; + struct crypto_attr_u32 data; + } nu32; + } attrs[CRYPTO_MAX_ATTRS]; + char larval[CRYPTO_MAX_ALG_NAME]; char template[CRYPTO_MAX_ALG_NAME]; }; @@ -72,7 +76,7 @@ out: module_put_and_exit(0); err: - crypto_larval_error(param->larval.name, param->type.data.type, + crypto_larval_error(param->larval, param->type.data.type, param->type.data.mask); goto out; } @@ -84,6 +88,7 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) const char *name = larval->alg.cra_name; const char *p; unsigned int len; + int i; if (!try_module_get(THIS_MODULE)) goto err; @@ -101,33 +106,73 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) memcpy(param->template, name, len); - name = p + 1; - len = 0; - for (p = name; *p; p++) { - for (; isalnum(*p) || *p == '-' || *p == '_' || *p == '('; p++) - ; + i = 0; + for (;;) { + int notnum = 0; - if (*p != ')') - goto err_free_param; + name = ++p; + len = 0; + + for (; isalnum(*p) || *p == '-' || *p == '_'; p++) + notnum |= !isdigit(*p); + + if (*p == '(') { + int recursion = 0; + + for (;;) { + if (!*++p) + goto err_free_param; + if (*p == '(') + recursion++; + else if (*p == ')' && !recursion--) + break; + } + + notnum = 1; + } len = p - name; + if (!len) + goto err_free_param; + + if (notnum) { + param->attrs[i].alg.attr.rta_len = + sizeof(param->attrs[i].alg); + param->attrs[i].alg.attr.rta_type = CRYPTOA_ALG; + memcpy(param->attrs[i].alg.data.name, name, len); + } else { + param->attrs[i].nu32.attr.rta_len = + sizeof(param->attrs[i].nu32); + param->attrs[i].nu32.attr.rta_type = CRYPTOA_U32; + param->attrs[i].nu32.data.num = + simple_strtol(name, NULL, 0); + } + + param->tb[i + 1] = ¶m->attrs[i].attr; + i++; + + if (WARN_ON(i >= CRYPTO_MAX_ATTRS)) + goto err_free_param; + + if (*p == ')') + break; + + if (*p != ',') + goto err_free_param; } - if (!len || name[len + 1]) + if (!i) goto err_free_param; + param->tb[i + 1] = NULL; + param->type.attr.rta_len = sizeof(param->type); param->type.attr.rta_type = CRYPTOA_TYPE; param->type.data.type = larval->alg.cra_flags; param->type.data.mask = larval->mask; - param->tb[CRYPTOA_TYPE - 1] = ¶m->type.attr; + param->tb[0] = ¶m->type.attr; - param->alg.attr.rta_len = sizeof(param->alg); - param->alg.attr.rta_type = CRYPTOA_ALG; - memcpy(param->alg.data.name, name, len); - param->tb[CRYPTOA_ALG - 1] = ¶m->alg.attr; - - memcpy(param->larval.name, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME); + memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME); thread = kthread_run(cryptomgr_probe, param, "cryptomgr"); if (IS_ERR(thread)) diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 1072f9abaef6..da09b4ac3ae9 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -425,11 +425,15 @@ enum { CRYPTOA_UNSPEC, CRYPTOA_ALG, CRYPTOA_TYPE, + CRYPTOA_U32, __CRYPTOA_MAX, }; #define CRYPTOA_MAX (__CRYPTOA_MAX - 1) +/* Maximum number of (rtattr) parameters for each template. */ +#define CRYPTO_MAX_ATTRS 32 + struct crypto_attr_alg { char name[CRYPTO_MAX_ALG_NAME]; }; @@ -439,6 +443,10 @@ struct crypto_attr_type { u32 mask; }; +struct crypto_attr_u32 { + u32 num; +}; + /* * Transform user interface. */ From 791b4d5f73cbc16ee532ebac5bd82d51524d4f99 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 23 Aug 2007 16:23:01 +0800 Subject: [PATCH 1811/2804] [CRYPTO] api: Add missing headers for setkey_unaligned This patch ensures that kernel.h and slab.h are included for the setkey_unaligned function. It also breaks a couple of long lines. Signed-off-by: Herbert Xu --- crypto/ablkcipher.c | 5 ++++- crypto/blkcipher.c | 6 +++--- crypto/cipher.c | 5 +++-- crypto/hash.c | 3 ++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 3dbb1cc6eab5..47438b650c92 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -16,10 +16,13 @@ #include #include #include +#include #include +#include #include -static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) +static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) { struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm); unsigned long alignmask = crypto_ablkcipher_alignmask(tfm); diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index d8f8ec320213..5991c53eabac 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -339,7 +339,8 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc, return blkcipher_walk_next(desc, walk); } -static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) { struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher; unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); @@ -360,8 +361,7 @@ static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int return ret; } -static int setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) +static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher; unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); diff --git a/crypto/cipher.c b/crypto/cipher.c index fc6b46f2a9b0..9a1a7316eeac 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -16,11 +16,12 @@ #include #include #include -#include +#include #include #include "internal.h" -static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) { struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); diff --git a/crypto/hash.c b/crypto/hash.c index 4fd470bd729b..7dcff671c19b 100644 --- a/crypto/hash.c +++ b/crypto/hash.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "internal.h" @@ -46,7 +47,7 @@ static int hash_setkey_unaligned(struct crypto_hash *crt, const u8 *key, } static int hash_setkey(struct crypto_hash *crt, const u8 *key, - unsigned int keylen) + unsigned int keylen) { struct crypto_tfm *tfm = crypto_hash_tfm(crt); struct hash_alg *alg = &tfm->__crt_alg->cra_hash; From 2de98e75449fc1c43d2fbb857668ae62d4f5eece Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 26 Aug 2007 19:12:47 +0800 Subject: [PATCH 1812/2804] [CRYPTO] ablkcipher: Remove queue pointer from common alg object Since not everyone needs a queue pointer and those who need it can always get it from the context anyway the queue pointer in the common alg object is redundant. Signed-off-by: Herbert Xu --- crypto/ablkcipher.c | 4 ---- crypto/cryptd.c | 7 +++---- include/crypto/algapi.h | 14 +++++++------- include/linux/crypto.h | 3 --- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 47438b650c92..2731acb86e7d 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -94,10 +94,6 @@ static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); - if (ablkcipher->queue) { - seq_printf(m, "qlen : %u\n", ablkcipher->queue->qlen); - seq_printf(m, "max qlen : %u\n", ablkcipher->queue->max_qlen); - } } const struct crypto_type crypto_ablkcipher_type = { diff --git a/crypto/cryptd.c b/crypto/cryptd.c index ac6dce2e7596..8bf2da835f7b 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -131,7 +131,7 @@ static int cryptd_blkcipher_enqueue(struct ablkcipher_request *req, req->base.complete = complete; spin_lock_bh(&state->lock); - err = ablkcipher_enqueue_request(crypto_ablkcipher_alg(tfm), req); + err = ablkcipher_enqueue_request(&state->queue, req); spin_unlock_bh(&state->lock); wake_up_process(state->task); @@ -173,7 +173,8 @@ static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm) int active; mutex_lock(&state->mutex); - active = ablkcipher_tfm_in_queue(__crypto_ablkcipher_cast(tfm)); + active = ablkcipher_tfm_in_queue(&state->queue, + __crypto_ablkcipher_cast(tfm)); mutex_unlock(&state->mutex); BUG_ON(active); @@ -251,8 +252,6 @@ 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; - inst->alg.cra_ablkcipher.queue = &state->queue; - out_put_alg: crypto_mod_put(alg); return inst; diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 290bce0c5bd5..cd721a7ce78f 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -234,16 +234,16 @@ static inline struct crypto_async_request *crypto_get_backlog( container_of(queue->backlog, struct crypto_async_request, list); } -static inline int ablkcipher_enqueue_request(struct ablkcipher_alg *alg, +static inline int ablkcipher_enqueue_request(struct crypto_queue *queue, struct ablkcipher_request *request) { - return crypto_enqueue_request(alg->queue, &request->base); + return crypto_enqueue_request(queue, &request->base); } static inline struct ablkcipher_request *ablkcipher_dequeue_request( - struct ablkcipher_alg *alg) + struct crypto_queue *queue) { - return ablkcipher_request_cast(crypto_dequeue_request(alg->queue)); + return ablkcipher_request_cast(crypto_dequeue_request(queue)); } static inline void *ablkcipher_request_ctx(struct ablkcipher_request *req) @@ -251,10 +251,10 @@ static inline void *ablkcipher_request_ctx(struct ablkcipher_request *req) return req->__ctx; } -static inline int ablkcipher_tfm_in_queue(struct crypto_ablkcipher *tfm) +static inline int ablkcipher_tfm_in_queue(struct crypto_queue *queue, + struct crypto_ablkcipher *tfm) { - return crypto_tfm_in_queue(crypto_ablkcipher_alg(tfm)->queue, - crypto_ablkcipher_tfm(tfm)); + return crypto_tfm_in_queue(queue, crypto_ablkcipher_tfm(tfm)); } #endif /* _CRYPTO_ALGAPI_H */ diff --git a/include/linux/crypto.h b/include/linux/crypto.h index da09b4ac3ae9..b1c7f4187c5b 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -95,7 +95,6 @@ struct crypto_async_request; struct crypto_aead; struct crypto_blkcipher; struct crypto_hash; -struct crypto_queue; struct crypto_tfm; struct crypto_type; @@ -178,8 +177,6 @@ struct ablkcipher_alg { int (*encrypt)(struct ablkcipher_request *req); int (*decrypt)(struct ablkcipher_request *req); - struct crypto_queue *queue; - unsigned int min_keysize; unsigned int max_keysize; unsigned int ivsize; From e962a653f3146330d99aefa5adadeaed60bc9bb5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 29 Aug 2007 16:06:15 +0800 Subject: [PATCH 1813/2804] [CRYPTO] api: Move scatterwalk into algapi The scatterwalk code is only used by algorithms that can be built as a module. Therefore we can move it into algapi. Signed-off-by: Herbert Xu --- crypto/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/Makefile b/crypto/Makefile index 9821c5ba054e..7e1d5b899033 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -2,10 +2,10 @@ # Cryptographic API # -obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o +obj-$(CONFIG_CRYPTO) += api.o cipher.o digest.o compress.o crypto_algapi-$(CONFIG_PROC_FS) += proc.o -crypto_algapi-objs := algapi.o $(crypto_algapi-y) +crypto_algapi-objs := algapi.o scatterwalk.o $(crypto_algapi-y) obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o From 5fa0fea27461f5ff7fad07687618db08272e9502 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 29 Aug 2007 16:31:34 +0800 Subject: [PATCH 1814/2804] [CRYPTO] scatterwalk: Add scatterwalk_map_and_copy This patch adds the function scatterwalk_map_and_copy which reads or writes a chunk of data from a scatterlist at a given offset. It will be used by authenc which would read/write the authentication data at the end of the cipher/plain text. Signed-off-by: Herbert Xu --- crypto/scatterwalk.c | 22 ++++++++++++++++++++++ crypto/scatterwalk.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index 81afd1790a1d..e93a8f6f35d4 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -107,3 +107,25 @@ void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, } } EXPORT_SYMBOL_GPL(scatterwalk_copychunks); + +void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, + unsigned int start, unsigned int nbytes, int out) +{ + struct scatter_walk walk; + unsigned int offset = 0; + + for (;;) { + scatterwalk_start(&walk, sg); + + if (start < offset + sg->length) + break; + + offset += sg->length; + sg = sg_next(sg); + } + + scatterwalk_advance(&walk, start - offset); + scatterwalk_copychunks(buf, &walk, nbytes, out); + scatterwalk_done(&walk, out, 0); +} +EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy); diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h index f1592cc2d0f4..500a220ad908 100644 --- a/crypto/scatterwalk.h +++ b/crypto/scatterwalk.h @@ -74,4 +74,7 @@ void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, void *scatterwalk_map(struct scatter_walk *walk, int out); void scatterwalk_done(struct scatter_walk *walk, int out, int more); +void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, + unsigned int start, unsigned int nbytes, int out); + #endif /* _CRYPTO_SCATTERWALK_H */ From b16c3a2e2c0307f5370b2b5e18bcbe1437b5f3d8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 29 Aug 2007 19:02:04 +0800 Subject: [PATCH 1815/2804] [CRYPTO] api: Fixed crypto_*_reqsize return type This patch changes the return type of crypto_*_reqsize from int to unsigned int which matches what the underlying type is (and should be). Signed-off-by: Herbert Xu --- include/linux/crypto.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/crypto.h b/include/linux/crypto.h index b1c7f4187c5b..fc32694287e2 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -624,7 +624,8 @@ static inline int crypto_ablkcipher_decrypt(struct ablkcipher_request *req) return crt->decrypt(req); } -static inline int crypto_ablkcipher_reqsize(struct crypto_ablkcipher *tfm) +static inline unsigned int crypto_ablkcipher_reqsize( + struct crypto_ablkcipher *tfm) { return crypto_ablkcipher_crt(tfm)->reqsize; } @@ -766,7 +767,7 @@ static inline int crypto_aead_decrypt(struct aead_request *req) return crypto_aead_crt(crypto_aead_reqtfm(req))->decrypt(req); } -static inline int crypto_aead_reqsize(struct crypto_aead *tfm) +static inline unsigned int crypto_aead_reqsize(struct crypto_aead *tfm) { return crypto_aead_crt(tfm)->reqsize; } From 3c09f17c3d11f3e98928f55b600e6de22f58017a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Aug 2007 16:24:15 +0800 Subject: [PATCH 1816/2804] [CRYPTO] aead: Add authenc This patch adds the authenc algorithm which constructs an AEAD algorithm from an asynchronous block cipher and a hash. The construction is done by concatenating the encrypted result from the cipher with the output from the hash, as is used by the IPsec ESP protocol. The authenc algorithm exists as a template with four parameters: authenc(auth, authsize, enc, enckeylen). The authentication algorithm, the authentication size (i.e., truncating the output of the authentication algorithm), the encryption algorithm, and the encryption key length. Both the size field and the key length field are in bytes. For example, AES-128 with SHA1-HMAC would be represented by authenc(hmac(sha1), 12, cbc(aes), 16) The key for the authenc algorithm is the concatenation of the keys for the authentication algorithm with the encryption algorithm. For the above example, if a key of length 36 bytes is given, then hmac(sha1) would receive the first 20 bytes while the last 16 would be given to cbc(aes). Signed-off-by: Herbert Xu --- crypto/Kconfig | 8 + crypto/Makefile | 1 + crypto/algapi.c | 23 ++- crypto/authenc.c | 400 ++++++++++++++++++++++++++++++++++++++++ include/crypto/algapi.h | 44 ++++- 5 files changed, 472 insertions(+), 4 deletions(-) create mode 100644 crypto/authenc.c diff --git a/crypto/Kconfig b/crypto/Kconfig index f42bc7715f48..05f46dfdf185 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -483,6 +483,14 @@ config CRYPTO_TEST help Quick & dirty crypto test module. +config CRYPTO_AUTHENC + tristate "Authenc support" + select CRYPTO_AEAD + select CRYPTO_MANAGER + help + Authenc: Combined mode wrapper for IPsec. + This is required for IPSec. + source "drivers/crypto/Kconfig" endif # if CRYPTO diff --git a/crypto/Makefile b/crypto/Makefile index 7e1d5b899033..da256665aae9 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_CRYPTO_SEED) += seed.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o +obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o diff --git a/crypto/algapi.c b/crypto/algapi.c index d9559609b525..d891f56f0e8c 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -470,9 +470,8 @@ int crypto_check_attr_type(struct rtattr **tb, u32 type) } EXPORT_SYMBOL_GPL(crypto_check_attr_type); -struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask) +struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask) { - struct rtattr *rta = tb[1]; struct crypto_attr_alg *alga; if (!rta) @@ -487,7 +486,25 @@ struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask) return crypto_alg_mod_lookup(alga->name, type, mask); } -EXPORT_SYMBOL_GPL(crypto_get_attr_alg); +EXPORT_SYMBOL_GPL(crypto_attr_alg); + +int crypto_attr_u32(struct rtattr *rta, u32 *num) +{ + struct crypto_attr_u32 *nu32; + + if (!rta) + return -ENOENT; + if (RTA_PAYLOAD(rta) < sizeof(*nu32)) + return -EINVAL; + if (rta->rta_type != CRYPTOA_U32) + return -EINVAL; + + nu32 = RTA_DATA(rta); + *num = nu32->num; + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_attr_u32); struct crypto_instance *crypto_alloc_instance(const char *name, struct crypto_alg *alg) diff --git a/crypto/authenc.c b/crypto/authenc.c new file mode 100644 index 000000000000..86b3ac88eab7 --- /dev/null +++ b/crypto/authenc.c @@ -0,0 +1,400 @@ +/* + * Authenc: Simple AEAD wrapper for IPsec + * + * Copyright (c) 2007 Herbert Xu + * + * 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 "scatterwalk.h" + +struct authenc_instance_ctx { + struct crypto_spawn auth; + struct crypto_spawn enc; + + unsigned int authsize; + unsigned int enckeylen; +}; + +struct crypto_authenc_ctx { + spinlock_t auth_lock; + struct crypto_hash *auth; + struct crypto_ablkcipher *enc; +}; + +static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, + unsigned int keylen) +{ + struct authenc_instance_ctx *ictx = + crypto_instance_ctx(crypto_aead_alg_instance(authenc)); + unsigned int enckeylen = ictx->enckeylen; + unsigned int authkeylen; + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct crypto_hash *auth = ctx->auth; + struct crypto_ablkcipher *enc = ctx->enc; + int err = -EINVAL; + + if (keylen < enckeylen) { + crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN); + goto out; + } + authkeylen = keylen - enckeylen; + + crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); + crypto_hash_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) & + CRYPTO_TFM_RES_MASK); + + if (err) + goto out; + + crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK); + crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc) & + CRYPTO_TFM_REQ_MASK); + err = crypto_ablkcipher_setkey(enc, key + authkeylen, enckeylen); + crypto_aead_set_flags(authenc, crypto_ablkcipher_get_flags(enc) & + CRYPTO_TFM_RES_MASK); + +out: + return err; +} + +static int crypto_authenc_hash(struct aead_request *req) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct authenc_instance_ctx *ictx = + crypto_instance_ctx(crypto_aead_alg_instance(authenc)); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct crypto_hash *auth = ctx->auth; + struct hash_desc desc = { + .tfm = auth, + }; + u8 *hash = aead_request_ctx(req); + struct scatterlist *dst; + unsigned int cryptlen; + int err; + + hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth), + crypto_hash_alignmask(auth) + 1); + + spin_lock_bh(&ctx->auth_lock); + err = crypto_hash_init(&desc); + if (err) + goto auth_unlock; + + err = crypto_hash_update(&desc, req->assoc, req->assoclen); + if (err) + goto auth_unlock; + + cryptlen = req->cryptlen; + dst = req->dst; + err = crypto_hash_update(&desc, dst, cryptlen); + if (err) + goto auth_unlock; + + err = crypto_hash_final(&desc, hash); +auth_unlock: + spin_unlock_bh(&ctx->auth_lock); + + if (err) + return err; + + scatterwalk_map_and_copy(hash, dst, cryptlen, ictx->authsize, 1); + return 0; +} + +static void crypto_authenc_encrypt_done(struct crypto_async_request *req, + int err) +{ + if (!err) + err = crypto_authenc_hash(req->data); + + aead_request_complete(req->data, err); +} + +static int crypto_authenc_encrypt(struct aead_request *req) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct ablkcipher_request *abreq = aead_request_ctx(req); + int err; + + ablkcipher_request_set_tfm(abreq, ctx->enc); + ablkcipher_request_set_callback(abreq, aead_request_flags(req), + crypto_authenc_encrypt_done, req); + ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen, + req->iv); + + err = crypto_ablkcipher_encrypt(abreq); + if (err) + return err; + + return crypto_authenc_hash(req); +} + +static int crypto_authenc_verify(struct aead_request *req) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct authenc_instance_ctx *ictx = + crypto_instance_ctx(crypto_aead_alg_instance(authenc)); + 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), + }; + u8 *ohash = aead_request_ctx(req); + u8 *ihash; + struct scatterlist *src; + unsigned int cryptlen; + unsigned int authsize; + int err; + + ohash = (u8 *)ALIGN((unsigned long)ohash + crypto_hash_alignmask(auth), + crypto_hash_alignmask(auth) + 1); + ihash = ohash + crypto_hash_digestsize(auth); + + spin_lock_bh(&ctx->auth_lock); + err = crypto_hash_init(&desc); + if (err) + goto auth_unlock; + + err = crypto_hash_update(&desc, req->assoc, req->assoclen); + if (err) + goto auth_unlock; + + cryptlen = req->cryptlen; + src = req->src; + err = crypto_hash_update(&desc, src, cryptlen); + if (err) + goto auth_unlock; + + err = crypto_hash_final(&desc, ohash); +auth_unlock: + spin_unlock_bh(&ctx->auth_lock); + + if (err) + return err; + + authsize = ictx->authsize; + scatterwalk_map_and_copy(ihash, src, cryptlen, authsize, 0); + return memcmp(ihash, ohash, authsize) ? -EINVAL : 0; +} + +static void crypto_authenc_decrypt_done(struct crypto_async_request *req, + int err) +{ + aead_request_complete(req->data, err); +} + +static int crypto_authenc_decrypt(struct aead_request *req) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct ablkcipher_request *abreq = aead_request_ctx(req); + int err; + + err = crypto_authenc_verify(req); + if (err) + return err; + + ablkcipher_request_set_tfm(abreq, ctx->enc); + ablkcipher_request_set_callback(abreq, aead_request_flags(req), + crypto_authenc_decrypt_done, req); + ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen, + req->iv); + + return crypto_ablkcipher_decrypt(abreq); +} + +static int crypto_authenc_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct authenc_instance_ctx *ictx = crypto_instance_ctx(inst); + struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_hash *auth; + struct crypto_ablkcipher *enc; + unsigned int digestsize; + int err; + + auth = crypto_spawn_hash(&ictx->auth); + if (IS_ERR(auth)) + return PTR_ERR(auth); + + err = -EINVAL; + digestsize = crypto_hash_digestsize(auth); + if (ictx->authsize > digestsize) + goto err_free_hash; + + enc = crypto_spawn_ablkcipher(&ictx->enc); + err = PTR_ERR(enc); + if (IS_ERR(enc)) + goto err_free_hash; + + ctx->auth = auth; + ctx->enc = enc; + tfm->crt_aead.reqsize = max_t(unsigned int, + (crypto_hash_alignmask(auth) & + ~(crypto_tfm_ctx_alignment() - 1)) + + digestsize * 2, + sizeof(struct ablkcipher_request) + + crypto_ablkcipher_reqsize(enc)); + + spin_lock_init(&ctx->auth_lock); + + return 0; + +err_free_hash: + crypto_free_hash(auth); + return err; +} + +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_ablkcipher(ctx->enc); +} + +static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + struct crypto_alg *auth; + struct crypto_alg *enc; + struct authenc_instance_ctx *ctx; + unsigned int authsize; + unsigned int enckeylen; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD); + if (err) + return ERR_PTR(err); + + auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH, + CRYPTO_ALG_TYPE_HASH_MASK); + if (IS_ERR(auth)) + return ERR_PTR(PTR_ERR(auth)); + + err = crypto_attr_u32(tb[2], &authsize); + inst = ERR_PTR(err); + if (err) + goto out_put_auth; + + enc = crypto_attr_alg(tb[3], CRYPTO_ALG_TYPE_BLKCIPHER, + CRYPTO_ALG_TYPE_MASK); + inst = ERR_PTR(PTR_ERR(enc)); + if (IS_ERR(enc)) + goto out_put_auth; + + err = crypto_attr_u32(tb[4], &enckeylen); + if (err) + goto out_put_enc; + + inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); + err = -ENOMEM; + if (!inst) + goto out_put_enc; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, + "authenc(%s, %u, %s, %u)", auth->cra_name, authsize, + enc->cra_name, enckeylen) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "authenc(%s, %u, %s, %u)", auth->cra_driver_name, + authsize, enc->cra_driver_name, enckeylen) >= + CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + ctx = crypto_instance_ctx(inst); + ctx->authsize = authsize; + ctx->enckeylen = enckeylen; + + err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK); + if (err) + goto err_free_inst; + + err = crypto_init_spawn(&ctx->enc, enc, inst, CRYPTO_ALG_TYPE_MASK); + if (err) + goto err_drop_auth; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; + inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority; + inst->alg.cra_blocksize = enc->cra_blocksize; + inst->alg.cra_alignmask = max(auth->cra_alignmask, enc->cra_alignmask); + inst->alg.cra_type = &crypto_aead_type; + + inst->alg.cra_aead.ivsize = enc->cra_blkcipher.ivsize; + inst->alg.cra_aead.authsize = authsize; + + inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx); + + inst->alg.cra_init = crypto_authenc_init_tfm; + inst->alg.cra_exit = crypto_authenc_exit_tfm; + + inst->alg.cra_aead.setkey = crypto_authenc_setkey; + inst->alg.cra_aead.encrypt = crypto_authenc_encrypt; + inst->alg.cra_aead.decrypt = crypto_authenc_decrypt; + +out: + crypto_mod_put(enc); +out_put_auth: + crypto_mod_put(auth); + return inst; + +err_drop_auth: + crypto_drop_spawn(&ctx->auth); +err_free_inst: + kfree(inst); +out_put_enc: + inst = ERR_PTR(err); + goto out; +} + +static void crypto_authenc_free(struct crypto_instance *inst) +{ + struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst); + + crypto_drop_spawn(&ctx->enc); + crypto_drop_spawn(&ctx->auth); + kfree(inst); +} + +static struct crypto_template crypto_authenc_tmpl = { + .name = "authenc", + .alloc = crypto_authenc_alloc, + .free = crypto_authenc_free, + .module = THIS_MODULE, +}; + +static int __init crypto_authenc_module_init(void) +{ + return crypto_register_template(&crypto_authenc_tmpl); +} + +static void __exit crypto_authenc_module_exit(void) +{ + crypto_unregister_template(&crypto_authenc_tmpl); +} + +module_init(crypto_authenc_module_init); +module_exit(crypto_authenc_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simple AEAD wrapper for IPsec"); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index cd721a7ce78f..4af72dc21202 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -112,7 +112,8 @@ struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb); int crypto_check_attr_type(struct rtattr **tb, u32 type); -struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask); +struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask); +int crypto_attr_u32(struct rtattr *rta, u32 *num); struct crypto_instance *crypto_alloc_instance(const char *name, struct crypto_alg *alg); @@ -171,6 +172,26 @@ static inline struct aead_alg *crypto_aead_alg(struct crypto_aead *tfm) return &crypto_aead_tfm(tfm)->__crt_alg->cra_aead; } +static inline void *crypto_aead_ctx(struct crypto_aead *tfm) +{ + return crypto_tfm_ctx(&tfm->base); +} + +static inline struct crypto_instance *crypto_aead_alg_instance( + struct crypto_aead *aead) +{ + return crypto_tfm_alg_instance(&aead->base); +} + +static inline struct crypto_ablkcipher *crypto_spawn_ablkcipher( + struct crypto_spawn *spawn) +{ + u32 type = CRYPTO_ALG_TYPE_BLKCIPHER; + u32 mask = CRYPTO_ALG_TYPE_MASK; + + return __crypto_ablkcipher_cast(crypto_spawn_tfm(spawn, type, mask)); +} + static inline struct crypto_blkcipher *crypto_spawn_blkcipher( struct crypto_spawn *spawn) { @@ -257,5 +278,26 @@ static inline int ablkcipher_tfm_in_queue(struct crypto_queue *queue, return crypto_tfm_in_queue(queue, crypto_ablkcipher_tfm(tfm)); } +static inline void *aead_request_ctx(struct aead_request *req) +{ + return req->__ctx; +} + +static inline void aead_request_complete(struct aead_request *req, int err) +{ + req->base.complete(&req->base, err); +} + +static inline u32 aead_request_flags(struct aead_request *req) +{ + return req->base.flags; +} + +static inline struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, + u32 type, u32 mask) +{ + return crypto_attr_alg(tb[1], type, mask); +} + #endif /* _CRYPTO_ALGAPI_H */ From 70dec235d8ac8cfb56ed2a3597e7d6c5b801f018 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 1 Sep 2007 16:52:13 +0800 Subject: [PATCH 1817/2804] [CRYPTO] api: Kill crypto_km_types When scatterwalk is built as a module digest.c was broken because it requires the crypto_km_types structure which is in scatterwalk. This patch removes the crypto_km_types structure by encoding the logic into crypto_kmap_type directly. In fact, this even saves a few bytes of code (not to mention the data structure itself) on i386 which is about the only place where it's needed. Signed-off-by: Herbert Xu --- crypto/internal.h | 11 ++++++++--- crypto/scatterwalk.c | 8 -------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/crypto/internal.h b/crypto/internal.h index 60acad9788c5..abb01f71f817 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -50,11 +50,16 @@ extern struct list_head crypto_alg_list; extern struct rw_semaphore crypto_alg_sem; extern struct blocking_notifier_head crypto_chain; -extern enum km_type crypto_km_types[]; - static inline enum km_type crypto_kmap_type(int out) { - return crypto_km_types[(in_softirq() ? 2 : 0) + out]; + enum km_type type; + + if (in_softirq()) + type = out * (KM_SOFTIRQ1 - KM_SOFTIRQ0) + KM_SOFTIRQ0; + else + type = out * (KM_USER1 - KM_USER0) + KM_USER0; + + return type; } static inline void *crypto_kmap(struct page *page, int out) diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index e93a8f6f35d4..3052f6507f53 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -23,14 +23,6 @@ #include "internal.h" #include "scatterwalk.h" -enum km_type crypto_km_types[] = { - KM_USER0, - KM_USER1, - KM_SOFTIRQ0, - KM_SOFTIRQ1, -}; -EXPORT_SYMBOL_GPL(crypto_km_types); - static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) { void *src = out ? buf : sgdata; From 5aaff0c8f7dd3515c9f1ca57f86463f30779acc7 Mon Sep 17 00:00:00 2001 From: Ingo Oeser Date: Wed, 19 Sep 2007 19:11:41 +0800 Subject: [PATCH 1818/2804] [CRYPTO] blkcipher: Use max() in blkcipher_get_spot() to state the intention Use max in blkcipher_get_spot() instead of open coding it. Signed-off-by: Ingo Oeser Signed-off-by: Herbert Xu --- crypto/blkcipher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 5991c53eabac..9c49770837c2 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -65,7 +65,7 @@ static inline void blkcipher_unmap_dst(struct blkcipher_walk *walk) static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len) { u8 *end_page = (u8 *)(((unsigned long)(start + len - 1)) & PAGE_MASK); - return start > end_page ? start : end_page; + return max(start, end_page); } static inline unsigned int blkcipher_done_slow(struct crypto_blkcipher *tfm, From f19f5111c94053ba4931892f5c01c806de33942e Mon Sep 17 00:00:00 2001 From: Rik Snel Date: Wed, 19 Sep 2007 20:23:13 +0800 Subject: [PATCH 1819/2804] [CRYPTO] xts: XTS blockcipher mode implementation without partial blocks XTS currently considered to be the successor of the LRW mode by the IEEE1619 workgroup. LRW was discarded, because it was not secure if the encyption key itself is encrypted with LRW. XTS does not have this problem. The implementation is pretty straightforward, a new function was added to gf128mul to handle GF(128) elements in ble format. Four testvectors from the specification http://grouper.ieee.org/groups/1619/email/pdf00086.pdf were added, and they verify on my system. Signed-off-by: Rik Snel Signed-off-by: Herbert Xu --- crypto/Kconfig | 11 + crypto/Makefile | 1 + crypto/gf128mul.c | 11 + crypto/tcrypt.c | 12 ++ crypto/tcrypt.h | 417 ++++++++++++++++++++++++++++++++++++++ crypto/xts.c | 292 ++++++++++++++++++++++++++ include/crypto/gf128mul.h | 2 + 7 files changed, 746 insertions(+) create mode 100644 crypto/xts.c diff --git a/crypto/Kconfig b/crypto/Kconfig index 05f46dfdf185..083d2e1dfc21 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -184,6 +184,17 @@ config CRYPTO_LRW The first 128, 192 or 256 bits in the key are used for AES and the rest is used to tie each cipher block to its logical position. +config CRYPTO_XTS + tristate "XTS support (EXPERIMENTAL)" + depends on EXPERIMENTAL + select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER + select CRYPTO_GF128MUL + help + XTS: IEEE1619/D16 narrow block cipher use with aes-xts-plain, + key size 256, 384 or 512 bits. This implementation currently + can't handle a sectorsize which is not a multiple of 16 bytes. + config CRYPTO_CRYPTD tristate "Software async crypto daemon" select CRYPTO_ABLKCIPHER diff --git a/crypto/Makefile b/crypto/Makefile index da256665aae9..e96a07e16bf2 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_CRYPTO_ECB) += ecb.o obj-$(CONFIG_CRYPTO_CBC) += cbc.o obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o +obj-$(CONFIG_CRYPTO_XTS) += xts.o obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o obj-$(CONFIG_CRYPTO_DES) += des.o obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o diff --git a/crypto/gf128mul.c b/crypto/gf128mul.c index 0a2aadfa1d85..ecbeaa1f17e1 100644 --- a/crypto/gf128mul.c +++ b/crypto/gf128mul.c @@ -142,6 +142,17 @@ static void gf128mul_x_bbe(be128 *r, const be128 *x) r->b = cpu_to_be64((b << 1) ^ _tt); } +void gf128mul_x_ble(be128 *r, const be128 *x) +{ + u64 a = le64_to_cpu(x->a); + u64 b = le64_to_cpu(x->b); + u64 _tt = gf128mul_table_bbe[b >> 63]; + + r->a = cpu_to_le64((a << 1) ^ _tt); + r->b = cpu_to_le64((b << 1) | (a >> 63)); +} +EXPORT_SYMBOL(gf128mul_x_ble); + static void gf128mul_x8_lle(be128 *x) { u64 a = be64_to_cpu(x->a); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index de6435ea9bf8..18d489c8b935 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -955,6 +955,10 @@ static void do_test(void) AES_LRW_ENC_TEST_VECTORS); test_cipher("lrw(aes)", DECRYPT, aes_lrw_dec_tv_template, AES_LRW_DEC_TEST_VECTORS); + test_cipher("xts(aes)", ENCRYPT, aes_xts_enc_tv_template, + AES_XTS_ENC_TEST_VECTORS); + test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template, + AES_XTS_DEC_TEST_VECTORS); //CAST5 test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template, @@ -1138,6 +1142,10 @@ static void do_test(void) AES_LRW_ENC_TEST_VECTORS); test_cipher("lrw(aes)", DECRYPT, aes_lrw_dec_tv_template, AES_LRW_DEC_TEST_VECTORS); + test_cipher("xts(aes)", ENCRYPT, aes_xts_enc_tv_template, + AES_XTS_ENC_TEST_VECTORS); + test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template, + AES_XTS_DEC_TEST_VECTORS); break; case 11: @@ -1313,6 +1321,10 @@ static void do_test(void) aes_lrw_speed_template); test_cipher_speed("lrw(aes)", DECRYPT, sec, NULL, 0, aes_lrw_speed_template); + test_cipher_speed("xts(aes)", ENCRYPT, sec, NULL, 0, + aes_xts_speed_template); + test_cipher_speed("xts(aes)", DECRYPT, sec, NULL, 0, + aes_xts_speed_template); break; case 201: diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index beab3f345584..ec861388d9a0 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -2144,6 +2144,8 @@ static struct cipher_testvec cast6_dec_tv_template[] = { #define AES_CBC_DEC_TEST_VECTORS 2 #define AES_LRW_ENC_TEST_VECTORS 8 #define AES_LRW_DEC_TEST_VECTORS 8 +#define AES_XTS_ENC_TEST_VECTORS 4 +#define AES_XTS_DEC_TEST_VECTORS 4 static struct cipher_testvec aes_enc_tv_template[] = { { /* From FIPS-197 */ @@ -2784,6 +2786,400 @@ static struct cipher_testvec aes_lrw_dec_tv_template[] = { } }; +static struct cipher_testvec aes_xts_enc_tv_template[] = { + /* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */ + { /* XTS-AES 1 */ + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 32, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 32, + .result = { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, + 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, + 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e }, + .rlen = 32, + }, { /* XTS-AES 2 */ + .key = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + .klen = 32, + .iv = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + .ilen = 32, + .result = { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e, + 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b, + 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4, + 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 }, + .rlen = 32, + }, { /* XTS-AES 3 */ + .key = { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + .klen = 32, + .iv = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + .ilen = 32, + .result = { 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a, + 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2, + 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53, + 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 }, + .rlen = 32, + }, { /* XTS-AES 4 */ + .key = { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, + 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, + 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, + 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95 }, + .klen = 32, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }, + .ilen = 512, + .result = { 0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76, + 0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2, + 0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25, + 0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c, + 0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f, + 0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00, + 0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad, + 0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12, + 0x32, 0x80, 0x63, 0xfd, 0x2a, 0xab, 0x53, 0xe5, + 0xea, 0x1e, 0x0a, 0x9f, 0x33, 0x25, 0x00, 0xa5, + 0xdf, 0x94, 0x87, 0xd0, 0x7a, 0x5c, 0x92, 0xcc, + 0x51, 0x2c, 0x88, 0x66, 0xc7, 0xe8, 0x60, 0xce, + 0x93, 0xfd, 0xf1, 0x66, 0xa2, 0x49, 0x12, 0xb4, + 0x22, 0x97, 0x61, 0x46, 0xae, 0x20, 0xce, 0x84, + 0x6b, 0xb7, 0xdc, 0x9b, 0xa9, 0x4a, 0x76, 0x7a, + 0xae, 0xf2, 0x0c, 0x0d, 0x61, 0xad, 0x02, 0x65, + 0x5e, 0xa9, 0x2d, 0xc4, 0xc4, 0xe4, 0x1a, 0x89, + 0x52, 0xc6, 0x51, 0xd3, 0x31, 0x74, 0xbe, 0x51, + 0xa1, 0x0c, 0x42, 0x11, 0x10, 0xe6, 0xd8, 0x15, + 0x88, 0xed, 0xe8, 0x21, 0x03, 0xa2, 0x52, 0xd8, + 0xa7, 0x50, 0xe8, 0x76, 0x8d, 0xef, 0xff, 0xed, + 0x91, 0x22, 0x81, 0x0a, 0xae, 0xb9, 0x9f, 0x91, + 0x72, 0xaf, 0x82, 0xb6, 0x04, 0xdc, 0x4b, 0x8e, + 0x51, 0xbc, 0xb0, 0x82, 0x35, 0xa6, 0xf4, 0x34, + 0x13, 0x32, 0xe4, 0xca, 0x60, 0x48, 0x2a, 0x4b, + 0xa1, 0xa0, 0x3b, 0x3e, 0x65, 0x00, 0x8f, 0xc5, + 0xda, 0x76, 0xb7, 0x0b, 0xf1, 0x69, 0x0d, 0xb4, + 0xea, 0xe2, 0x9c, 0x5f, 0x1b, 0xad, 0xd0, 0x3c, + 0x5c, 0xcf, 0x2a, 0x55, 0xd7, 0x05, 0xdd, 0xcd, + 0x86, 0xd4, 0x49, 0x51, 0x1c, 0xeb, 0x7e, 0xc3, + 0x0b, 0xf1, 0x2b, 0x1f, 0xa3, 0x5b, 0x91, 0x3f, + 0x9f, 0x74, 0x7a, 0x8a, 0xfd, 0x1b, 0x13, 0x0e, + 0x94, 0xbf, 0xf9, 0x4e, 0xff, 0xd0, 0x1a, 0x91, + 0x73, 0x5c, 0xa1, 0x72, 0x6a, 0xcd, 0x0b, 0x19, + 0x7c, 0x4e, 0x5b, 0x03, 0x39, 0x36, 0x97, 0xe1, + 0x26, 0x82, 0x6f, 0xb6, 0xbb, 0xde, 0x8e, 0xcc, + 0x1e, 0x08, 0x29, 0x85, 0x16, 0xe2, 0xc9, 0xed, + 0x03, 0xff, 0x3c, 0x1b, 0x78, 0x60, 0xf6, 0xde, + 0x76, 0xd4, 0xce, 0xcd, 0x94, 0xc8, 0x11, 0x98, + 0x55, 0xef, 0x52, 0x97, 0xca, 0x67, 0xe9, 0xf3, + 0xe7, 0xff, 0x72, 0xb1, 0xe9, 0x97, 0x85, 0xca, + 0x0a, 0x7e, 0x77, 0x20, 0xc5, 0xb3, 0x6d, 0xc6, + 0xd7, 0x2c, 0xac, 0x95, 0x74, 0xc8, 0xcb, 0xbc, + 0x2f, 0x80, 0x1e, 0x23, 0xe5, 0x6f, 0xd3, 0x44, + 0xb0, 0x7f, 0x22, 0x15, 0x4b, 0xeb, 0xa0, 0xf0, + 0x8c, 0xe8, 0x89, 0x1e, 0x64, 0x3e, 0xd9, 0x95, + 0xc9, 0x4d, 0x9a, 0x69, 0xc9, 0xf1, 0xb5, 0xf4, + 0x99, 0x02, 0x7a, 0x78, 0x57, 0x2a, 0xee, 0xbd, + 0x74, 0xd2, 0x0c, 0xc3, 0x98, 0x81, 0xc2, 0x13, + 0xee, 0x77, 0x0b, 0x10, 0x10, 0xe4, 0xbe, 0xa7, + 0x18, 0x84, 0x69, 0x77, 0xae, 0x11, 0x9f, 0x7a, + 0x02, 0x3a, 0xb5, 0x8c, 0xca, 0x0a, 0xd7, 0x52, + 0xaf, 0xe6, 0x56, 0xbb, 0x3c, 0x17, 0x25, 0x6a, + 0x9f, 0x6e, 0x9b, 0xf1, 0x9f, 0xdd, 0x5a, 0x38, + 0xfc, 0x82, 0xbb, 0xe8, 0x72, 0xc5, 0x53, 0x9e, + 0xdb, 0x60, 0x9e, 0xf4, 0xf7, 0x9c, 0x20, 0x3e, + 0xbb, 0x14, 0x0f, 0x2e, 0x58, 0x3c, 0xb2, 0xad, + 0x15, 0xb4, 0xaa, 0x5b, 0x65, 0x50, 0x16, 0xa8, + 0x44, 0x92, 0x77, 0xdb, 0xd4, 0x77, 0xef, 0x2c, + 0x8d, 0x6c, 0x01, 0x7d, 0xb7, 0x38, 0xb1, 0x8d, + 0xeb, 0x4a, 0x42, 0x7d, 0x19, 0x23, 0xce, 0x3f, + 0xf2, 0x62, 0x73, 0x57, 0x79, 0xa4, 0x18, 0xf2, + 0x0a, 0x28, 0x2d, 0xf9, 0x20, 0x14, 0x7b, 0xea, + 0xbe, 0x42, 0x1e, 0xe5, 0x31, 0x9d, 0x05, 0x68 }, + .rlen = 512, + } +}; + +static struct cipher_testvec aes_xts_dec_tv_template[] = { + /* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */ + { /* XTS-AES 1 */ + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 32, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, + 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, + 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e }, + .ilen = 32, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 32, + }, { /* XTS-AES 2 */ + .key = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + .klen = 32, + .iv = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e, + 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b, + 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4, + 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 }, + .ilen = 32, + .result = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + .rlen = 32, + }, { /* XTS-AES 3 */ + .key = { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + .klen = 32, + .iv = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a, + 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2, + 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53, + 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 }, + .ilen = 32, + .result = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + .rlen = 32, + }, { /* XTS-AES 4 */ + .key = { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, + 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, + 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, + 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95 }, + .klen = 32, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76, + 0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2, + 0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25, + 0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c, + 0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f, + 0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00, + 0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad, + 0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12, + 0x32, 0x80, 0x63, 0xfd, 0x2a, 0xab, 0x53, 0xe5, + 0xea, 0x1e, 0x0a, 0x9f, 0x33, 0x25, 0x00, 0xa5, + 0xdf, 0x94, 0x87, 0xd0, 0x7a, 0x5c, 0x92, 0xcc, + 0x51, 0x2c, 0x88, 0x66, 0xc7, 0xe8, 0x60, 0xce, + 0x93, 0xfd, 0xf1, 0x66, 0xa2, 0x49, 0x12, 0xb4, + 0x22, 0x97, 0x61, 0x46, 0xae, 0x20, 0xce, 0x84, + 0x6b, 0xb7, 0xdc, 0x9b, 0xa9, 0x4a, 0x76, 0x7a, + 0xae, 0xf2, 0x0c, 0x0d, 0x61, 0xad, 0x02, 0x65, + 0x5e, 0xa9, 0x2d, 0xc4, 0xc4, 0xe4, 0x1a, 0x89, + 0x52, 0xc6, 0x51, 0xd3, 0x31, 0x74, 0xbe, 0x51, + 0xa1, 0x0c, 0x42, 0x11, 0x10, 0xe6, 0xd8, 0x15, + 0x88, 0xed, 0xe8, 0x21, 0x03, 0xa2, 0x52, 0xd8, + 0xa7, 0x50, 0xe8, 0x76, 0x8d, 0xef, 0xff, 0xed, + 0x91, 0x22, 0x81, 0x0a, 0xae, 0xb9, 0x9f, 0x91, + 0x72, 0xaf, 0x82, 0xb6, 0x04, 0xdc, 0x4b, 0x8e, + 0x51, 0xbc, 0xb0, 0x82, 0x35, 0xa6, 0xf4, 0x34, + 0x13, 0x32, 0xe4, 0xca, 0x60, 0x48, 0x2a, 0x4b, + 0xa1, 0xa0, 0x3b, 0x3e, 0x65, 0x00, 0x8f, 0xc5, + 0xda, 0x76, 0xb7, 0x0b, 0xf1, 0x69, 0x0d, 0xb4, + 0xea, 0xe2, 0x9c, 0x5f, 0x1b, 0xad, 0xd0, 0x3c, + 0x5c, 0xcf, 0x2a, 0x55, 0xd7, 0x05, 0xdd, 0xcd, + 0x86, 0xd4, 0x49, 0x51, 0x1c, 0xeb, 0x7e, 0xc3, + 0x0b, 0xf1, 0x2b, 0x1f, 0xa3, 0x5b, 0x91, 0x3f, + 0x9f, 0x74, 0x7a, 0x8a, 0xfd, 0x1b, 0x13, 0x0e, + 0x94, 0xbf, 0xf9, 0x4e, 0xff, 0xd0, 0x1a, 0x91, + 0x73, 0x5c, 0xa1, 0x72, 0x6a, 0xcd, 0x0b, 0x19, + 0x7c, 0x4e, 0x5b, 0x03, 0x39, 0x36, 0x97, 0xe1, + 0x26, 0x82, 0x6f, 0xb6, 0xbb, 0xde, 0x8e, 0xcc, + 0x1e, 0x08, 0x29, 0x85, 0x16, 0xe2, 0xc9, 0xed, + 0x03, 0xff, 0x3c, 0x1b, 0x78, 0x60, 0xf6, 0xde, + 0x76, 0xd4, 0xce, 0xcd, 0x94, 0xc8, 0x11, 0x98, + 0x55, 0xef, 0x52, 0x97, 0xca, 0x67, 0xe9, 0xf3, + 0xe7, 0xff, 0x72, 0xb1, 0xe9, 0x97, 0x85, 0xca, + 0x0a, 0x7e, 0x77, 0x20, 0xc5, 0xb3, 0x6d, 0xc6, + 0xd7, 0x2c, 0xac, 0x95, 0x74, 0xc8, 0xcb, 0xbc, + 0x2f, 0x80, 0x1e, 0x23, 0xe5, 0x6f, 0xd3, 0x44, + 0xb0, 0x7f, 0x22, 0x15, 0x4b, 0xeb, 0xa0, 0xf0, + 0x8c, 0xe8, 0x89, 0x1e, 0x64, 0x3e, 0xd9, 0x95, + 0xc9, 0x4d, 0x9a, 0x69, 0xc9, 0xf1, 0xb5, 0xf4, + 0x99, 0x02, 0x7a, 0x78, 0x57, 0x2a, 0xee, 0xbd, + 0x74, 0xd2, 0x0c, 0xc3, 0x98, 0x81, 0xc2, 0x13, + 0xee, 0x77, 0x0b, 0x10, 0x10, 0xe4, 0xbe, 0xa7, + 0x18, 0x84, 0x69, 0x77, 0xae, 0x11, 0x9f, 0x7a, + 0x02, 0x3a, 0xb5, 0x8c, 0xca, 0x0a, 0xd7, 0x52, + 0xaf, 0xe6, 0x56, 0xbb, 0x3c, 0x17, 0x25, 0x6a, + 0x9f, 0x6e, 0x9b, 0xf1, 0x9f, 0xdd, 0x5a, 0x38, + 0xfc, 0x82, 0xbb, 0xe8, 0x72, 0xc5, 0x53, 0x9e, + 0xdb, 0x60, 0x9e, 0xf4, 0xf7, 0x9c, 0x20, 0x3e, + 0xbb, 0x14, 0x0f, 0x2e, 0x58, 0x3c, 0xb2, 0xad, + 0x15, 0xb4, 0xaa, 0x5b, 0x65, 0x50, 0x16, 0xa8, + 0x44, 0x92, 0x77, 0xdb, 0xd4, 0x77, 0xef, 0x2c, + 0x8d, 0x6c, 0x01, 0x7d, 0xb7, 0x38, 0xb1, 0x8d, + 0xeb, 0x4a, 0x42, 0x7d, 0x19, 0x23, 0xce, 0x3f, + 0xf2, 0x62, 0x73, 0x57, 0x79, 0xa4, 0x18, 0xf2, + 0x0a, 0x28, 0x2d, 0xf9, 0x20, 0x14, 0x7b, 0xea, + 0xbe, 0x42, 0x1e, 0xe5, 0x31, 0x9d, 0x05, 0x68 }, + .ilen = 512, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }, + .rlen = 512, + } +}; + /* Cast5 test vectors from RFC 2144 */ #define CAST5_ENC_TEST_VECTORS 3 #define CAST5_DEC_TEST_VECTORS 3 @@ -4283,6 +4679,27 @@ static struct cipher_speed aes_lrw_speed_template[] = { { .klen = 0, .blen = 0, } }; +static struct cipher_speed aes_xts_speed_template[] = { + { .klen = 32, .blen = 16, }, + { .klen = 32, .blen = 64, }, + { .klen = 32, .blen = 256, }, + { .klen = 32, .blen = 1024, }, + { .klen = 32, .blen = 8192, }, + { .klen = 48, .blen = 16, }, + { .klen = 48, .blen = 64, }, + { .klen = 48, .blen = 256, }, + { .klen = 48, .blen = 1024, }, + { .klen = 48, .blen = 8192, }, + { .klen = 64, .blen = 16, }, + { .klen = 64, .blen = 64, }, + { .klen = 64, .blen = 256, }, + { .klen = 64, .blen = 1024, }, + { .klen = 64, .blen = 8192, }, + + /* End marker */ + { .klen = 0, .blen = 0, } +}; + static struct cipher_speed des3_ede_speed_template[] = { { .klen = 24, .blen = 16, }, { .klen = 24, .blen = 64, }, diff --git a/crypto/xts.c b/crypto/xts.c new file mode 100644 index 000000000000..8eb08bfaf7c0 --- /dev/null +++ b/crypto/xts.c @@ -0,0 +1,292 @@ +/* XTS: as defined in IEEE1619/D16 + * http://grouper.ieee.org/groups/1619/email/pdf00086.pdf + * (sector sizes which are not a multiple of 16 bytes are, + * however currently unsupported) + * + * Copyright (c) 2007 Rik Snel + * + * Based om ecb.c + * Copyright (c) 2006 Herbert Xu + * + * 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 + +struct priv { + struct crypto_cipher *child; + struct crypto_cipher *tweak; +}; + +static int setkey(struct crypto_tfm *parent, const u8 *key, + unsigned int keylen) +{ + struct priv *ctx = crypto_tfm_ctx(parent); + struct crypto_cipher *child = ctx->tweak; + u32 *flags = &parent->crt_flags; + int err; + + /* key consists of keys of equal size concatenated, therefore + * the length must be even */ + if (keylen % 2) { + /* tell the user why there was an error */ + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* we need two cipher instances: one to compute the inital 'tweak' + * by encrypting the IV (usually the 'plain' iv) and the other + * one to encrypt and decrypt the data */ + + /* tweak cipher, uses Key2 i.e. the second half of *key */ + crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(child, key + keylen/2, keylen/2); + if (err) + return err; + + crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + + child = ctx->child; + + /* data cipher, uses Key1 i.e. the first half of *key */ + crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(child, key, keylen/2); + if (err) + return err; + + crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + + return 0; +} + +struct sinfo { + be128 t; + struct crypto_tfm *tfm; + void (*fn)(struct crypto_tfm *, u8 *, const u8 *); +}; + +static inline void xts_round(struct sinfo *s, void *dst, const void *src) +{ + be128_xor(dst, &s->t, src); /* PP <- T xor P */ + s->fn(s->tfm, dst, dst); /* CC <- E(Key1,PP) */ + be128_xor(dst, dst, &s->t); /* C <- T xor CC */ +} + +static int crypt(struct blkcipher_desc *d, + struct blkcipher_walk *w, struct priv *ctx, + void (*tw)(struct crypto_tfm *, u8 *, const u8 *), + void (*fn)(struct crypto_tfm *, u8 *, const u8 *)) +{ + int err; + unsigned int avail; + const int bs = crypto_cipher_blocksize(ctx->child); + struct sinfo s = { + .tfm = crypto_cipher_tfm(ctx->child), + .fn = fn + }; + be128 *iv; + u8 *wsrc; + u8 *wdst; + + err = blkcipher_walk_virt(d, w); + if (!w->nbytes) + return err; + + avail = w->nbytes; + + wsrc = w->src.virt.addr; + wdst = w->dst.virt.addr; + + /* calculate first value of T */ + iv = (be128 *)w->iv; + tw(crypto_cipher_tfm(ctx->tweak), (void *)&s.t, w->iv); + + goto first; + + for (;;) { + do { + gf128mul_x_ble(&s.t, &s.t); + +first: + xts_round(&s, wdst, wsrc); + + wsrc += bs; + wdst += bs; + } while ((avail -= bs) >= bs); + + err = blkcipher_walk_done(d, w, avail); + if (!w->nbytes) + break; + + avail = w->nbytes; + + wsrc = w->src.virt.addr; + wdst = w->dst.virt.addr; + } + + return err; +} + +static int encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct priv *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk w; + + blkcipher_walk_init(&w, dst, src, nbytes); + return crypt(desc, &w, ctx, crypto_cipher_alg(ctx->tweak)->cia_encrypt, + crypto_cipher_alg(ctx->child)->cia_encrypt); +} + +static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct priv *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk w; + + blkcipher_walk_init(&w, dst, src, nbytes); + return crypt(desc, &w, ctx, crypto_cipher_alg(ctx->tweak)->cia_encrypt, + crypto_cipher_alg(ctx->child)->cia_decrypt); +} + +static int 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 priv *ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + if (crypto_cipher_blocksize(cipher) != 16) { + *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; + crypto_free_cipher(cipher); + return -EINVAL; + } + + ctx->child = cipher; + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) { + crypto_free_cipher(ctx->child); + return PTR_ERR(cipher); + } + + /* this check isn't really needed, leave it here just in case */ + if (crypto_cipher_blocksize(cipher) != 16) { + crypto_free_cipher(cipher); + crypto_free_cipher(ctx->child); + *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; + return -EINVAL; + } + + ctx->tweak = cipher; + + return 0; +} + +static void exit_tfm(struct crypto_tfm *tfm) +{ + struct priv *ctx = crypto_tfm_ctx(tfm); + crypto_free_cipher(ctx->child); + crypto_free_cipher(ctx->tweak); +} + +static struct crypto_instance *alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); + + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); + if (IS_ERR(alg)) + return ERR_PTR(PTR_ERR(alg)); + + inst = crypto_alloc_instance("xts", alg); + if (IS_ERR(inst)) + goto out_put_alg; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = alg->cra_blocksize; + + if (alg->cra_alignmask < 7) + inst->alg.cra_alignmask = 7; + else + inst->alg.cra_alignmask = alg->cra_alignmask; + + inst->alg.cra_type = &crypto_blkcipher_type; + + inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize; + inst->alg.cra_blkcipher.min_keysize = + 2 * alg->cra_cipher.cia_min_keysize; + inst->alg.cra_blkcipher.max_keysize = + 2 * alg->cra_cipher.cia_max_keysize; + + inst->alg.cra_ctxsize = sizeof(struct priv); + + inst->alg.cra_init = init_tfm; + inst->alg.cra_exit = exit_tfm; + + inst->alg.cra_blkcipher.setkey = setkey; + inst->alg.cra_blkcipher.encrypt = encrypt; + inst->alg.cra_blkcipher.decrypt = decrypt; + +out_put_alg: + crypto_mod_put(alg); + return inst; +} + +static void free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_tmpl = { + .name = "xts", + .alloc = alloc, + .free = free, + .module = THIS_MODULE, +}; + +static int __init crypto_module_init(void) +{ + return crypto_register_template(&crypto_tmpl); +} + +static void __exit crypto_module_exit(void) +{ + crypto_unregister_template(&crypto_tmpl); +} + +module_init(crypto_module_init); +module_exit(crypto_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("XTS block cipher mode"); diff --git a/include/crypto/gf128mul.h b/include/crypto/gf128mul.h index 4fd315202442..4086b8ebfafe 100644 --- a/include/crypto/gf128mul.h +++ b/include/crypto/gf128mul.h @@ -161,6 +161,8 @@ void gf128mul_lle(be128 *a, const be128 *b); void gf128mul_bbe(be128 *a, const be128 *b); +/* multiply by x in ble format, needed by XTS */ +void gf128mul_x_ble(be128 *a, const be128 *b); /* 4k table optimization */ From 720a650f8ab3166d32fc5da64961e8d2158b9452 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 28 Sep 2007 09:06:11 +0800 Subject: [PATCH 1820/2804] [CRYPTO] cryptomgr: Fix parsing of recursive algorithms As Joy Latten points out, inner algorithm parameters will miss the closing bracket which will also cause the outer algorithm to terminate prematurely. This patch fixes that also kills the WARN_ON if the number of parameters exceed the maximum as that is a user error. Signed-off-by: Herbert Xu --- crypto/cryptomgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c index c83884fec5f9..e5e3cf848d42 100644 --- a/crypto/cryptomgr.c +++ b/crypto/cryptomgr.c @@ -129,6 +129,7 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) } notnum = 1; + p++; } len = p - name; @@ -151,7 +152,7 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) param->tb[i + 1] = ¶m->attrs[i].attr; i++; - if (WARN_ON(i >= CRYPTO_MAX_ATTRS)) + if (i >= CRYPTO_MAX_ATTRS) goto err_free_param; if (*p == ')') From e4c5c6c9b0d04a7dac19027260f7421305a34856 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 28 Sep 2007 09:07:12 +0800 Subject: [PATCH 1821/2804] [CRYPTO] authenc: Kill spaces in algorithm names We do not allow spaces in algorithm names or parameters. Thanks to Joy Latten for pointing this out. Signed-off-by: Herbert Xu --- crypto/authenc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/authenc.c b/crypto/authenc.c index 86b3ac88eab7..0b29a6ae673d 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -312,12 +312,12 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) err = -ENAMETOOLONG; if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, - "authenc(%s, %u, %s, %u)", auth->cra_name, authsize, + "authenc(%s,%u,%s,%u)", auth->cra_name, authsize, enc->cra_name, enckeylen) >= CRYPTO_MAX_ALG_NAME) goto err_free_inst; if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "authenc(%s, %u, %s, %u)", auth->cra_driver_name, + "authenc(%s,%u,%s,%u)", auth->cra_driver_name, authsize, enc->cra_driver_name, enckeylen) >= CRYPTO_MAX_ALG_NAME) goto err_free_inst; From 70613783fc0f6e37b442d79e8417f71a2b71ed93 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 29 Sep 2007 21:24:23 +0800 Subject: [PATCH 1822/2804] [CRYPTO] blkcipher: Remove alignment restriction on block size Previously we assumed for convenience that the block size is a multiple of the algorithm's required alignment. With the pending addition of CTR this will no longer be the case as the block size will be 1 due to it being a stream cipher. However, the alignment requirement will be that of the underlying implementation which will most likely be greater than 1. Signed-off-by: Herbert Xu --- crypto/algapi.c | 3 --- crypto/blkcipher.c | 13 ++++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crypto/algapi.c b/crypto/algapi.c index d891f56f0e8c..58cc19164801 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -63,9 +63,6 @@ static int crypto_check_alg(struct crypto_alg *alg) if (alg->cra_alignmask & (alg->cra_alignmask + 1)) return -EINVAL; - if (alg->cra_alignmask & alg->cra_blocksize) - return -EINVAL; - if (alg->cra_blocksize > PAGE_SIZE / 8) return -EINVAL; diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 9c49770837c2..a3c87da23f1e 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -149,6 +149,7 @@ static inline int blkcipher_next_slow(struct blkcipher_desc *desc, unsigned int alignmask) { unsigned int n; + unsigned aligned_bsize = ALIGN(bsize, alignmask + 1); if (walk->buffer) goto ok; @@ -167,8 +168,8 @@ ok: walk->dst.virt.addr = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1); walk->dst.virt.addr = blkcipher_get_spot(walk->dst.virt.addr, bsize); - walk->src.virt.addr = blkcipher_get_spot(walk->dst.virt.addr + bsize, - bsize); + walk->src.virt.addr = blkcipher_get_spot(walk->dst.virt.addr + + aligned_bsize, bsize); scatterwalk_copychunks(walk->src.virt.addr, &walk->in, bsize, 0); @@ -278,7 +279,9 @@ static inline int blkcipher_copy_iv(struct blkcipher_walk *walk, { unsigned bs = crypto_blkcipher_blocksize(tfm); unsigned int ivsize = crypto_blkcipher_ivsize(tfm); - unsigned int size = bs * 2 + ivsize + max(bs, ivsize) - (alignmask + 1); + unsigned aligned_bs = ALIGN(bs, alignmask + 1); + unsigned int size = aligned_bs * 2 + ivsize + max(aligned_bs, ivsize) - + (alignmask + 1); u8 *iv; size += alignmask & ~(crypto_tfm_ctx_alignment() - 1); @@ -287,8 +290,8 @@ static inline int blkcipher_copy_iv(struct blkcipher_walk *walk, return -ENOMEM; iv = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1); - iv = blkcipher_get_spot(iv, bs) + bs; - iv = blkcipher_get_spot(iv, bs) + bs; + iv = blkcipher_get_spot(iv, bs) + aligned_bs; + iv = blkcipher_get_spot(iv, bs) + aligned_bs; iv = blkcipher_get_spot(iv, ivsize); walk->iv = memcpy(iv, walk->iv, ivsize); From d8058480b35dbc3d1e6085b3f13b80af27def09e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 2 Oct 2007 22:27:29 +0800 Subject: [PATCH 1823/2804] [CRYPTO] api: Explain the comparison on larval cra_name This patch adds a comment to explain why we compare the cra_driver_name of the algorithm being registered against the cra_name of a larval as opposed to the cra_driver_name of the larval. In fact larvals have only one name, cra_name which is the name that was requested by the user. The test here is simply trying to find out whether the algorithm being registered can or can not satisfy the larval. Signed-off-by: Herbert Xu --- crypto/algapi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crypto/algapi.c b/crypto/algapi.c index 58cc19164801..8ff8c2656d9c 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -149,6 +149,11 @@ static int __crypto_register_alg(struct crypto_alg *alg, if (crypto_is_larval(q)) { struct crypto_larval *larval = (void *)q; + /* + * Check to see if either our generic name or + * specific name can satisfy the name requested + * by the larval entry q. + */ if (strcmp(alg->cra_name, q->cra_name) && strcmp(alg->cra_driver_name, q->cra_name)) continue; From 2614de1b9af5a9e49cda64b394e1348159565bd5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 4 Oct 2007 14:49:00 +0800 Subject: [PATCH 1824/2804] [CRYPTO] blkcipher: Increase kmalloc amount to aligned block size Now that the block size is no longer a multiple of the alignment, we need to increase the kmalloc amount in blkcipher_next_slow to use the aligned block size. Signed-off-by: Herbert Xu --- crypto/blkcipher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index a3c87da23f1e..3d05586a8f34 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -158,7 +158,7 @@ static inline int blkcipher_next_slow(struct blkcipher_desc *desc, if (walk->buffer) goto ok; - n = bsize * 3 - (alignmask + 1) + + n = aligned_bsize * 3 - (alignmask + 1) + (alignmask & ~(crypto_tfm_ctx_alignment() - 1)); walk->buffer = kmalloc(n, GFP_ATOMIC); if (!walk->buffer) From 7607bd8ff03b8af5af887931318cb2bb20361856 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 4 Oct 2007 15:24:05 +0800 Subject: [PATCH 1825/2804] [CRYPTO] blkcipher: Added blkcipher_walk_virt_block This patch adds the helper blkcipher_walk_virt_block which is similar to blkcipher_walk_virt but uses a supplied block size instead of the block size of the block cipher. This is useful for CTR where the block size is 1 but we still want to walk by the block size of the underlying cipher. Signed-off-by: Herbert Xu --- crypto/blkcipher.c | 34 ++++++++++++++++++++++++---------- include/crypto/algapi.h | 4 ++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 3d05586a8f34..f6c67f9d4e5c 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -84,8 +84,6 @@ static inline unsigned int blkcipher_done_slow(struct crypto_blkcipher *tfm, static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, unsigned int n) { - n = walk->nbytes - n; - if (walk->flags & BLKCIPHER_WALK_COPY) { blkcipher_map_dst(walk); memcpy(walk->dst.virt.addr, walk->page, n); @@ -109,13 +107,15 @@ int blkcipher_walk_done(struct blkcipher_desc *desc, unsigned int nbytes = 0; if (likely(err >= 0)) { - unsigned int bsize = crypto_blkcipher_blocksize(tfm); - unsigned int n; + unsigned int n = walk->nbytes - err; if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) - n = blkcipher_done_fast(walk, err); - else - n = blkcipher_done_slow(tfm, walk, bsize); + n = blkcipher_done_fast(walk, n); + else if (WARN_ON(err)) { + err = -EINVAL; + goto err; + } else + n = blkcipher_done_slow(tfm, walk, n); nbytes = walk->total - n; err = 0; @@ -132,6 +132,7 @@ int blkcipher_walk_done(struct blkcipher_desc *desc, return blkcipher_walk_next(desc, walk); } +err: if (walk->iv != desc->info) memcpy(desc->info, walk->iv, crypto_blkcipher_ivsize(tfm)); if (walk->buffer != walk->page) @@ -225,12 +226,12 @@ static int blkcipher_walk_next(struct blkcipher_desc *desc, { struct crypto_blkcipher *tfm = desc->tfm; unsigned int alignmask = crypto_blkcipher_alignmask(tfm); - unsigned int bsize = crypto_blkcipher_blocksize(tfm); + unsigned int bsize; unsigned int n; int err; n = walk->total; - if (unlikely(n < bsize)) { + if (unlikely(n < crypto_blkcipher_blocksize(tfm))) { desc->flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; return blkcipher_walk_done(desc, walk, -EINVAL); } @@ -247,6 +248,7 @@ static int blkcipher_walk_next(struct blkcipher_desc *desc, } } + bsize = min(walk->blocksize, n); n = scatterwalk_clamp(&walk->in, n); n = scatterwalk_clamp(&walk->out, n); @@ -277,7 +279,7 @@ static inline int blkcipher_copy_iv(struct blkcipher_walk *walk, struct crypto_blkcipher *tfm, unsigned int alignmask) { - unsigned bs = crypto_blkcipher_blocksize(tfm); + unsigned bs = walk->blocksize; unsigned int ivsize = crypto_blkcipher_ivsize(tfm); unsigned aligned_bs = ALIGN(bs, alignmask + 1); unsigned int size = aligned_bs * 2 + ivsize + max(aligned_bs, ivsize) - @@ -302,6 +304,7 @@ int blkcipher_walk_virt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { walk->flags &= ~BLKCIPHER_WALK_PHYS; + walk->blocksize = crypto_blkcipher_blocksize(desc->tfm); return blkcipher_walk_first(desc, walk); } EXPORT_SYMBOL_GPL(blkcipher_walk_virt); @@ -310,6 +313,7 @@ int blkcipher_walk_phys(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { walk->flags |= BLKCIPHER_WALK_PHYS; + walk->blocksize = crypto_blkcipher_blocksize(desc->tfm); return blkcipher_walk_first(desc, walk); } EXPORT_SYMBOL_GPL(blkcipher_walk_phys); @@ -342,6 +346,16 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc, return blkcipher_walk_next(desc, walk); } +int blkcipher_walk_virt_block(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + unsigned int blocksize) +{ + walk->flags &= ~BLKCIPHER_WALK_PHYS; + walk->blocksize = blocksize; + return blkcipher_walk_first(desc, walk); +} +EXPORT_SYMBOL_GPL(blkcipher_walk_virt_block); + static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 4af72dc21202..b9b05d399d2b 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -91,6 +91,7 @@ struct blkcipher_walk { u8 *iv; int flags; + unsigned int blocksize; }; extern const struct crypto_type crypto_ablkcipher_type; @@ -129,6 +130,9 @@ int blkcipher_walk_virt(struct blkcipher_desc *desc, struct blkcipher_walk *walk); int blkcipher_walk_phys(struct blkcipher_desc *desc, struct blkcipher_walk *walk); +int blkcipher_walk_virt_block(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + unsigned int blocksize); static inline void *crypto_tfm_ctx_aligned(struct crypto_tfm *tfm) { From c5a511f1cd6f90a98ad11dd97e2313c7c787deb2 Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Fri, 5 Oct 2007 16:42:03 +0800 Subject: [PATCH 1826/2804] [CRYPTO] des: Rename des to des-generic Loading the crypto algorithm by the alias instead of by module directly has the advantage that all possible implementations of this algorithm are loaded automatically and the crypto API can choose the best one depending on its priority. Signed-off-by: Sebastian Siewior Signed-off-by: Herbert Xu --- crypto/Makefile | 2 +- crypto/{des.c => des_generic.c} | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) rename crypto/{des.c => des_generic.c} (99%) diff --git a/crypto/Makefile b/crypto/Makefile index e96a07e16bf2..a624cbc188fc 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o obj-$(CONFIG_CRYPTO_XTS) += xts.o obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o -obj-$(CONFIG_CRYPTO_DES) += des.o +obj-$(CONFIG_CRYPTO_DES) += des_generic.o obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o diff --git a/crypto/des.c b/crypto/des_generic.c similarity index 99% rename from crypto/des.c rename to crypto/des_generic.c index 1df3a714fa47..59966d14b8e0 100644 --- a/crypto/des.c +++ b/crypto/des_generic.c @@ -1009,3 +1009,4 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); MODULE_AUTHOR("Dag Arne Osvik "); +MODULE_ALIAS("des"); From f8246af005d56b73f4f04304fc5b6fd9878af4ef Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Fri, 5 Oct 2007 16:52:01 +0800 Subject: [PATCH 1827/2804] [CRYPTO] aes: Rename aes to aes-generic Loading the crypto algorithm by the alias instead of by module directly has the advantage that all possible implementations of this algorithm are loaded automatically and the crypto API can choose the best one depending on its priority. Additionally it ensures that the generic implementation as well as the HW driver (if available) is loaded in case the HW driver needs the generic version as fallback in corner cases. Signed-off-by: Sebastian Siewior Signed-off-by: Herbert Xu --- arch/s390/crypto/aes_s390.c | 2 +- crypto/Makefile | 2 +- crypto/{aes.c => aes_generic.c} | 2 +- drivers/crypto/geode-aes.c | 1 + drivers/crypto/padlock-aes.c | 4 ++-- 5 files changed, 6 insertions(+), 5 deletions(-) rename crypto/{aes.c => aes_generic.c} (99%) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 3660ca6a3306..512669691ad0 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -7,7 +7,7 @@ * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * - * Derived from "crypto/aes.c" + * Derived from "crypto/aes_generic.c" * * 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 diff --git a/crypto/Makefile b/crypto/Makefile index a624cbc188fc..b6ef5e4f1ab4 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -39,7 +39,7 @@ obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o -obj-$(CONFIG_CRYPTO_AES) += aes.o +obj-$(CONFIG_CRYPTO_AES) += aes_generic.o obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o diff --git a/crypto/aes.c b/crypto/aes_generic.c similarity index 99% rename from crypto/aes.c rename to crypto/aes_generic.c index e2440773878c..9401dca85e87 100644 --- a/crypto/aes.c +++ b/crypto/aes_generic.c @@ -453,4 +453,4 @@ module_exit(aes_fini); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); MODULE_LICENSE("Dual BSD/GPL"); - +MODULE_ALIAS("aes"); diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 6a86958b577f..f9a34abbf4fa 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -473,6 +473,7 @@ geode_aes_exit(void) MODULE_AUTHOR("Advanced Micro Devices, Inc."); MODULE_DESCRIPTION("Geode LX Hardware AES driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("aes"); module_init(geode_aes_init); module_exit(geode_aes_exit); diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index d4501dc7e650..abbcff0762b1 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -5,7 +5,7 @@ * * Copyright (c) 2004 Michal Ludvig * - * Key expansion routine taken from crypto/aes.c + * Key expansion routine taken from crypto/aes_generic.c * * 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 @@ -660,4 +660,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Ludvig"); -MODULE_ALIAS("aes-padlock"); +MODULE_ALIAS("aes"); From ad5d27899fdbe7a66e57fdf1af883dbd7ff88dac Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Mon, 8 Oct 2007 11:45:10 +0800 Subject: [PATCH 1828/2804] [CRYPTO] sha: Load the SHA[1|256] module by an alias Loading the crypto algorithm by the alias instead of by module directly has the advantage that all possible implementations of this algorithm are loaded automatically and the crypto API can choose the best one depending on its priority. Additionally it ensures that the generic implementation as well as the HW driver (if available) is loaded in case the HW driver needs the generic version as fallback in corner cases. Also remove the probe for sha1 in padlock's init code. Quote from Herbert: The probe is actually pointless since we can always probe when the algorithm is actually used which does not lead to dead-locks like this. Signed-off-by: Sebastian Siewior Signed-off-by: Herbert Xu --- arch/s390/crypto/sha1_s390.c | 2 +- arch/s390/crypto/sha256_s390.c | 2 +- crypto/Makefile | 4 ++-- crypto/{sha1.c => sha1_generic.c} | 2 +- crypto/{sha256.c => sha256_generic.c} | 2 +- drivers/crypto/padlock-sha.c | 17 ++--------------- 6 files changed, 8 insertions(+), 21 deletions(-) rename crypto/{sha1.c => sha1_generic.c} (99%) rename crypto/{sha256.c => sha256_generic.c} (99%) diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index af4460ec381f..8ebd3cd6bd1f 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -12,7 +12,7 @@ * Author(s): Thomas Spatzier * Jan Glauber (jan.glauber@de.ibm.com) * - * Derived from "crypto/sha1.c" + * Derived from "crypto/sha1_generic.c" * Copyright (c) Alan Smithee. * Copyright (c) Andrew McDonald * Copyright (c) Jean-Francois Dive diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 2ced3330bce0..c728bd0ae1ed 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -7,7 +7,7 @@ * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * - * Derived from "crypto/sha256.c" + * Derived from "crypto/sha256_generic.c" * and "arch/s390/crypto/sha1_s390.c" * * This program is free software; you can redistribute it and/or modify it diff --git a/crypto/Makefile b/crypto/Makefile index b6ef5e4f1ab4..43c2a0dc9936 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -21,8 +21,8 @@ obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o obj-$(CONFIG_CRYPTO_MD4) += md4.o obj-$(CONFIG_CRYPTO_MD5) += md5.o -obj-$(CONFIG_CRYPTO_SHA1) += sha1.o -obj-$(CONFIG_CRYPTO_SHA256) += sha256.o +obj-$(CONFIG_CRYPTO_SHA1) += sha1_generic.o +obj-$(CONFIG_CRYPTO_SHA256) += sha256_generic.o obj-$(CONFIG_CRYPTO_SHA512) += sha512.o obj-$(CONFIG_CRYPTO_WP512) += wp512.o obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o diff --git a/crypto/sha1.c b/crypto/sha1_generic.c similarity index 99% rename from crypto/sha1.c rename to crypto/sha1_generic.c index 1bba551e5b45..70364dd5c45a 100644 --- a/crypto/sha1.c +++ b/crypto/sha1_generic.c @@ -139,4 +139,4 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); -MODULE_ALIAS("sha1-generic"); +MODULE_ALIAS("sha1"); diff --git a/crypto/sha256.c b/crypto/sha256_generic.c similarity index 99% rename from crypto/sha256.c rename to crypto/sha256_generic.c index 716195bb54f2..74bf2f95f4e5 100644 --- a/crypto/sha256.c +++ b/crypto/sha256_generic.c @@ -339,4 +339,4 @@ module_exit(fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm"); -MODULE_ALIAS("sha256-generic"); +MODULE_ALIAS("sha256"); diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index a781fd23b607..f3857bbbfae3 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -253,19 +253,6 @@ static struct crypto_alg sha256_alg = { } }; -static void __init padlock_sha_check_fallbacks(void) -{ - if (!crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK)) - printk(KERN_WARNING PFX - "Couldn't load fallback module for sha1.\n"); - - if (!crypto_has_hash("sha256", 0, CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK)) - printk(KERN_WARNING PFX - "Couldn't load fallback module for sha256.\n"); -} - static int __init padlock_init(void) { int rc = -ENODEV; @@ -280,8 +267,6 @@ static int __init padlock_init(void) return -ENODEV; } - padlock_sha_check_fallbacks(); - rc = crypto_register_alg(&sha1_alg); if (rc) goto out; @@ -314,5 +299,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support."); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Ludvig"); +MODULE_ALIAS("sha1"); +MODULE_ALIAS("sha256"); MODULE_ALIAS("sha1-padlock"); MODULE_ALIAS("sha256-padlock"); From 5265eeb2b036835021591173ac64e624baaff55c Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 9 Oct 2007 22:43:13 +0800 Subject: [PATCH 1829/2804] [CRYPTO] sha: Add header file for SHA definitions There are currently several SHA implementations that all define their own initialization vectors and size values. Since this values are idential move them to a header file under include/crypto. Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu --- arch/s390/crypto/sha1_s390.c | 14 ++++---- arch/s390/crypto/sha256_s390.c | 20 +++++------ crypto/sha1_generic.c | 8 ++--- crypto/sha256_generic.c | 31 ++++++----------- crypto/sha512.c | 63 ++++++++++------------------------ drivers/crypto/padlock-sha.c | 36 +++++++++---------- include/crypto/sha.h | 53 ++++++++++++++++++++++++++++ 7 files changed, 116 insertions(+), 109 deletions(-) create mode 100644 include/crypto/sha.h diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index 8ebd3cd6bd1f..5a834f6578ab 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -26,12 +26,10 @@ #include #include #include +#include #include "crypt_s390.h" -#define SHA1_DIGEST_SIZE 20 -#define SHA1_BLOCK_SIZE 64 - struct s390_sha1_ctx { u64 count; /* message length */ u32 state[5]; @@ -42,11 +40,11 @@ static void sha1_init(struct crypto_tfm *tfm) { struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = 0x67452301; - sctx->state[1] = 0xEFCDAB89; - sctx->state[2] = 0x98BADCFE; - sctx->state[3] = 0x10325476; - sctx->state[4] = 0xC3D2E1F0; + sctx->state[0] = SHA1_H0; + sctx->state[1] = SHA1_H1; + sctx->state[2] = SHA1_H2; + sctx->state[3] = SHA1_H3; + sctx->state[4] = SHA1_H4; sctx->count = 0; } diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index c728bd0ae1ed..ccf8633c4f65 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -19,12 +19,10 @@ #include #include #include +#include #include "crypt_s390.h" -#define SHA256_DIGEST_SIZE 32 -#define SHA256_BLOCK_SIZE 64 - struct s390_sha256_ctx { u64 count; /* message length */ u32 state[8]; @@ -35,14 +33,14 @@ static void sha256_init(struct crypto_tfm *tfm) { struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = 0x6a09e667; - sctx->state[1] = 0xbb67ae85; - sctx->state[2] = 0x3c6ef372; - sctx->state[3] = 0xa54ff53a; - sctx->state[4] = 0x510e527f; - sctx->state[5] = 0x9b05688c; - sctx->state[6] = 0x1f83d9ab; - sctx->state[7] = 0x5be0cd19; + sctx->state[0] = SHA256_H0; + sctx->state[1] = SHA256_H1; + sctx->state[2] = SHA256_H2; + sctx->state[3] = SHA256_H3; + sctx->state[4] = SHA256_H4; + sctx->state[5] = SHA256_H5; + sctx->state[6] = SHA256_H6; + sctx->state[7] = SHA256_H7; sctx->count = 0; } diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c index 70364dd5c45a..48a3c3e0bf5f 100644 --- a/crypto/sha1_generic.c +++ b/crypto/sha1_generic.c @@ -22,12 +22,10 @@ #include #include #include +#include #include #include -#define SHA1_DIGEST_SIZE 20 -#define SHA1_HMAC_BLOCK_SIZE 64 - struct sha1_ctx { u64 count; u32 state[5]; @@ -39,7 +37,7 @@ static void sha1_init(struct crypto_tfm *tfm) struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); static const struct sha1_ctx initstate = { 0, - { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, + { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, { 0, } }; @@ -111,7 +109,7 @@ static struct crypto_alg alg = { .cra_name = "sha1", .cra_driver_name= "sha1-generic", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct sha1_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index 74bf2f95f4e5..5f4332edcf6b 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -21,12 +21,10 @@ #include #include #include +#include #include #include -#define SHA256_DIGEST_SIZE 32 -#define SHA256_HMAC_BLOCK_SIZE 64 - struct sha256_ctx { u32 count[2]; u32 state[8]; @@ -48,15 +46,6 @@ static inline u32 Maj(u32 x, u32 y, u32 z) #define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3)) #define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10)) -#define H0 0x6a09e667 -#define H1 0xbb67ae85 -#define H2 0x3c6ef372 -#define H3 0xa54ff53a -#define H4 0x510e527f -#define H5 0x9b05688c -#define H6 0x1f83d9ab -#define H7 0x5be0cd19 - static inline void LOAD_OP(int I, u32 *W, const u8 *input) { W[I] = __be32_to_cpu( ((__be32*)(input))[I] ); @@ -233,14 +222,14 @@ static void sha256_transform(u32 *state, const u8 *input) static void sha256_init(struct crypto_tfm *tfm) { struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = H0; - sctx->state[1] = H1; - sctx->state[2] = H2; - sctx->state[3] = H3; - sctx->state[4] = H4; - sctx->state[5] = H5; - sctx->state[6] = H6; - sctx->state[7] = H7; + sctx->state[0] = SHA256_H0; + sctx->state[1] = SHA256_H1; + sctx->state[2] = SHA256_H2; + sctx->state[3] = SHA256_H3; + sctx->state[4] = SHA256_H4; + sctx->state[5] = SHA256_H5; + sctx->state[6] = SHA256_H6; + sctx->state[7] = SHA256_H7; sctx->count[0] = sctx->count[1] = 0; } @@ -311,7 +300,7 @@ static struct crypto_alg alg = { .cra_name = "sha256", .cra_driver_name= "sha256-generic", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA256_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct sha256_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, diff --git a/crypto/sha512.c b/crypto/sha512.c index 15eab9db9be4..e736596ca574 100644 --- a/crypto/sha512.c +++ b/crypto/sha512.c @@ -13,20 +13,15 @@ #include #include - #include #include #include #include +#include #include #include -#define SHA384_DIGEST_SIZE 48 -#define SHA512_DIGEST_SIZE 64 -#define SHA384_HMAC_BLOCK_SIZE 128 -#define SHA512_HMAC_BLOCK_SIZE 128 - struct sha512_ctx { u64 state[8]; u32 count[4]; @@ -84,26 +79,6 @@ static const u64 sha512_K[80] = { #define s0(x) (RORu64(x, 1) ^ RORu64(x, 8) ^ (x >> 7)) #define s1(x) (RORu64(x,19) ^ RORu64(x,61) ^ (x >> 6)) -/* H* initial state for SHA-512 */ -#define H0 0x6a09e667f3bcc908ULL -#define H1 0xbb67ae8584caa73bULL -#define H2 0x3c6ef372fe94f82bULL -#define H3 0xa54ff53a5f1d36f1ULL -#define H4 0x510e527fade682d1ULL -#define H5 0x9b05688c2b3e6c1fULL -#define H6 0x1f83d9abfb41bd6bULL -#define H7 0x5be0cd19137e2179ULL - -/* H'* initial state for SHA-384 */ -#define HP0 0xcbbb9d5dc1059ed8ULL -#define HP1 0x629a292a367cd507ULL -#define HP2 0x9159015a3070dd17ULL -#define HP3 0x152fecd8f70e5939ULL -#define HP4 0x67332667ffc00b31ULL -#define HP5 0x8eb44a8768581511ULL -#define HP6 0xdb0c2e0d64f98fa7ULL -#define HP7 0x47b5481dbefa4fa4ULL - static inline void LOAD_OP(int I, u64 *W, const u8 *input) { W[I] = __be64_to_cpu( ((__be64*)(input))[I] ); @@ -164,14 +139,14 @@ static void sha512_init(struct crypto_tfm *tfm) { struct sha512_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = H0; - sctx->state[1] = H1; - sctx->state[2] = H2; - sctx->state[3] = H3; - sctx->state[4] = H4; - sctx->state[5] = H5; - sctx->state[6] = H6; - sctx->state[7] = H7; + sctx->state[0] = SHA512_H0; + sctx->state[1] = SHA512_H1; + sctx->state[2] = SHA512_H2; + sctx->state[3] = SHA512_H3; + sctx->state[4] = SHA512_H4; + 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; } @@ -179,14 +154,14 @@ static void sha384_init(struct crypto_tfm *tfm) { struct sha512_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = HP0; - sctx->state[1] = HP1; - sctx->state[2] = HP2; - sctx->state[3] = HP3; - sctx->state[4] = HP4; - sctx->state[5] = HP5; - sctx->state[6] = HP6; - sctx->state[7] = HP7; + sctx->state[0] = SHA384_H0; + sctx->state[1] = SHA384_H1; + sctx->state[2] = SHA384_H2; + sctx->state[3] = SHA384_H3; + sctx->state[4] = SHA384_H4; + 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; } @@ -275,7 +250,7 @@ static void sha384_final(struct crypto_tfm *tfm, u8 *hash) static struct crypto_alg sha512 = { .cra_name = "sha512", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA512_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA512_BLOCK_SIZE, .cra_ctxsize = sizeof(struct sha512_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, @@ -291,7 +266,7 @@ static struct crypto_alg sha512 = { static struct crypto_alg sha384 = { .cra_name = "sha384", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA384_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA384_BLOCK_SIZE, .cra_ctxsize = sizeof(struct sha512_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index f3857bbbfae3..4e8de162fc12 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -24,12 +25,7 @@ #include "padlock.h" #define SHA1_DEFAULT_FALLBACK "sha1-generic" -#define SHA1_DIGEST_SIZE 20 -#define SHA1_HMAC_BLOCK_SIZE 64 - #define SHA256_DEFAULT_FALLBACK "sha256-generic" -#define SHA256_DIGEST_SIZE 32 -#define SHA256_HMAC_BLOCK_SIZE 64 struct padlock_sha_ctx { char *data; @@ -107,11 +103,11 @@ static void padlock_do_sha1(const char *in, char *out, int count) char buf[128+16]; char *result = NEAREST_ALIGNED(buf); - ((uint32_t *)result)[0] = 0x67452301; - ((uint32_t *)result)[1] = 0xEFCDAB89; - ((uint32_t *)result)[2] = 0x98BADCFE; - ((uint32_t *)result)[3] = 0x10325476; - ((uint32_t *)result)[4] = 0xC3D2E1F0; + ((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; asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */ : "+S"(in), "+D"(result) @@ -128,14 +124,14 @@ static void padlock_do_sha256(const char *in, char *out, int count) char buf[128+16]; char *result = NEAREST_ALIGNED(buf); - ((uint32_t *)result)[0] = 0x6A09E667; - ((uint32_t *)result)[1] = 0xBB67AE85; - ((uint32_t *)result)[2] = 0x3C6EF372; - ((uint32_t *)result)[3] = 0xA54FF53A; - ((uint32_t *)result)[4] = 0x510E527F; - ((uint32_t *)result)[5] = 0x9B05688C; - ((uint32_t *)result)[6] = 0x1F83D9AB; - ((uint32_t *)result)[7] = 0x5BE0CD19; + ((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; asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */ : "+S"(in), "+D"(result) @@ -215,7 +211,7 @@ static struct crypto_alg sha1_alg = { .cra_priority = PADLOCK_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST | CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, + .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), @@ -237,7 +233,7 @@ static struct crypto_alg sha256_alg = { .cra_priority = PADLOCK_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST | CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA256_HMAC_BLOCK_SIZE, + .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), diff --git a/include/crypto/sha.h b/include/crypto/sha.h new file mode 100644 index 000000000000..0686e1f7a24b --- /dev/null +++ b/include/crypto/sha.h @@ -0,0 +1,53 @@ +/* + * Common values for SHA algorithms + */ + +#ifndef _CRYPTO_SHA_H +#define _CRYPTO_SHA_H + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +#define SHA384_DIGEST_SIZE 48 +#define SHA384_BLOCK_SIZE 128 + +#define SHA512_DIGEST_SIZE 64 +#define SHA512_BLOCK_SIZE 128 + +#define SHA1_H0 0x67452301UL +#define SHA1_H1 0xefcdab89UL +#define SHA1_H2 0x98badcfeUL +#define SHA1_H3 0x10325476UL +#define SHA1_H4 0xc3d2e1f0UL + +#define SHA256_H0 0x6a09e667UL +#define SHA256_H1 0xbb67ae85UL +#define SHA256_H2 0x3c6ef372UL +#define SHA256_H3 0xa54ff53aUL +#define SHA256_H4 0x510e527fUL +#define SHA256_H5 0x9b05688cUL +#define SHA256_H6 0x1f83d9abUL +#define SHA256_H7 0x5be0cd19UL + +#define SHA384_H0 0xcbbb9d5dc1059ed8ULL +#define SHA384_H1 0x629a292a367cd507ULL +#define SHA384_H2 0x9159015a3070dd17ULL +#define SHA384_H3 0x152fecd8f70e5939ULL +#define SHA384_H4 0x67332667ffc00b31ULL +#define SHA384_H5 0x8eb44a8768581511ULL +#define SHA384_H6 0xdb0c2e0d64f98fa7ULL +#define SHA384_H7 0x47b5481dbefa4fa4ULL + +#define SHA512_H0 0x6a09e667f3bcc908ULL +#define SHA512_H1 0xbb67ae8584caa73bULL +#define SHA512_H2 0x3c6ef372fe94f82bULL +#define SHA512_H3 0xa54ff53a5f1d36f1ULL +#define SHA512_H4 0x510e527fade682d1ULL +#define SHA512_H5 0x9b05688c2b3e6c1fULL +#define SHA512_H6 0x1f83d9abfb41bd6bULL +#define SHA512_H7 0x5be0cd19137e2179ULL + +#endif From 1c1e87edb9aa38b9e1ae807a6d88fcfd350a55c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Wed, 10 Oct 2007 02:45:32 -0700 Subject: [PATCH 1830/2804] [TCP]: Separate lost_retrans loop into own function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follows own function for each task principle, this is really somewhat separate task being done in sacktag. Also reduces indentation. In addition, added ack_seq local var to break some long lines & fixed coding style things. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 80 ++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e8c39488cf58..101054cb13e9 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1106,6 +1106,47 @@ static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack, return !before(start_seq, end_seq - tp->max_window); } +/* Check for lost retransmit. This superb idea is borrowed from "ratehalving". + * Event "C". Later note: FACK people cheated me again 8), we have to account + * for reordering! Ugly, but should help. + */ +static int tcp_mark_lost_retrans(struct sock *sk, u32 lost_retrans) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb; + int flag = 0; + + tcp_for_write_queue(skb, sk) { + u32 ack_seq = TCP_SKB_CB(skb)->ack_seq; + + if (skb == tcp_send_head(sk)) + break; + if (after(TCP_SKB_CB(skb)->seq, lost_retrans)) + break; + if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) + continue; + + if ((TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) && + after(lost_retrans, ack_seq) && + (tcp_is_fack(tp) || + !before(lost_retrans, + ack_seq + tp->reordering * tp->mss_cache))) { + TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; + tp->retrans_out -= tcp_skb_pcount(skb); + + /* clear lost hint */ + tp->retransmit_skb_hint = NULL; + + if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) { + tp->lost_out += tcp_skb_pcount(skb); + TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; + flag |= FLAG_DATA_SACKED; + NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); + } + } + } + return flag; +} static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, struct tcp_sack_block_wire *sp, int num_sacks, @@ -1422,43 +1463,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ } } - /* Check for lost retransmit. This superb idea is - * borrowed from "ratehalving". Event "C". - * Later note: FACK people cheated me again 8), - * we have to account for reordering! Ugly, - * but should help. - */ - if (lost_retrans && icsk->icsk_ca_state == TCP_CA_Recovery) { - struct sk_buff *skb; - - tcp_for_write_queue(skb, sk) { - if (skb == tcp_send_head(sk)) - break; - if (after(TCP_SKB_CB(skb)->seq, lost_retrans)) - break; - if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) - continue; - if ((TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) && - after(lost_retrans, TCP_SKB_CB(skb)->ack_seq) && - (tcp_is_fack(tp) || - !before(lost_retrans, - TCP_SKB_CB(skb)->ack_seq + tp->reordering * - tp->mss_cache))) { - TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; - tp->retrans_out -= tcp_skb_pcount(skb); - - /* clear lost hint */ - tp->retransmit_skb_hint = NULL; - - if (!(TCP_SKB_CB(skb)->sacked&(TCPCB_LOST|TCPCB_SACKED_ACKED))) { - tp->lost_out += tcp_skb_pcount(skb); - TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; - flag |= FLAG_DATA_SACKED; - NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); - } - } - } - } + if (lost_retrans && icsk->icsk_ca_state == TCP_CA_Recovery) + flag |= tcp_mark_lost_retrans(sk, lost_retrans); tcp_verify_left_out(tp); From 9b7726523523472ead660b1d45df29dcaf6cc5c0 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 10 Oct 2007 02:49:09 -0700 Subject: [PATCH 1831/2804] [NET]: Remove double dev->flags checking when calling dev_close() The unregister_netdevice() and dev_change_net_namespace() both check for dev->flags to be IFF_UP before calling the dev_close(), but the dev_close() checks for IFF_UP itself, so remove those unneeded checks. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/core/dev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index e7e728aea9f3..1e169a541ce7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3893,8 +3893,7 @@ void unregister_netdevice(struct net_device *dev) BUG_ON(dev->reg_state != NETREG_REGISTERED); /* If device is running, close it first. */ - if (dev->flags & IFF_UP) - dev_close(dev); + dev_close(dev); /* And unlink it from device chain. */ unlist_netdevice(dev); @@ -4018,8 +4017,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char */ /* If device is running close it first. */ - if (dev->flags & IFF_UP) - dev_close(dev); + dev_close(dev); /* And unlink it from device chain */ err = -ENODEV; From f24e3d658cf382f11a7aa7887fa99147bdc6fe0b Mon Sep 17 00:00:00 2001 From: Mitsuru Chinen Date: Wed, 10 Oct 2007 02:53:43 -0700 Subject: [PATCH 1832/2804] [IPV6]: Defer IPv6 device initialization until a valid qdisc is specified To judge the timing for DAD, netif_carrier_ok() is used. However, there is a possibility that dev->qdisc stays noop_qdisc even if netif_carrier_ok() returns true. In that case, DAD NS is not sent out. We need to defer the IPv6 device initialization until a valid qdisc is specified. Signed-off-by: Mitsuru Chinen Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 8b2d760ddf26..52d10d213217 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -74,6 +74,7 @@ #include #include #include +#include #include #include @@ -213,6 +214,12 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; +/* Check if a valid qdisc is available */ +static inline int addrconf_qdisc_ok(struct net_device *dev) +{ + return (dev->qdisc != &noop_qdisc); +} + static void addrconf_del_timer(struct inet6_ifaddr *ifp) { if (del_timer(&ifp->timer)) @@ -384,7 +391,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) } #endif - if (netif_running(dev) && netif_carrier_ok(dev)) + if (netif_running(dev) && addrconf_qdisc_ok(dev)) ndev->if_flags |= IF_READY; ipv6_mc_init_dev(ndev); @@ -2283,7 +2290,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, break; if (event == NETDEV_UP) { - if (!netif_carrier_ok(dev)) { + if (!addrconf_qdisc_ok(dev)) { /* device is not ready yet. */ printk(KERN_INFO "ADDRCONF(NETDEV_UP): %s: " @@ -2295,7 +2302,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, if (idev) idev->if_flags |= IF_READY; } else { - if (!netif_carrier_ok(dev)) { + if (!addrconf_qdisc_ok(dev)) { /* device is still not ready. */ break; } From 8bd170750400bfa5e14c3dd2e2d0f305e1ab0e57 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 10 Oct 2007 15:41:41 -0700 Subject: [PATCH 1833/2804] [IPSEC] esp: Remove NAT-T checksum invalidation for BEET I pointed this out back when this patch was first proposed but it looks like it got lost along the way. The checksum only needs to be ignored for NAT-T in transport mode where we lose the original inner addresses due to NAT. With BEET the inner addresses will be intact so the checksum remains valid. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/esp4.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 452910dae89f..1af332df72d9 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -261,8 +261,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) * as per draft-ietf-ipsec-udp-encaps-06, * section 3.1.2 */ - if (x->props.mode == XFRM_MODE_TRANSPORT || - x->props.mode == XFRM_MODE_BEET) + if (x->props.mode == XFRM_MODE_TRANSPORT) skb->ip_summed = CHECKSUM_UNNECESSARY; } From bee0b40c0621396326d1c17b81833f59118a2d80 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 10 Oct 2007 15:42:23 -0700 Subject: [PATCH 1834/2804] [IPSEC] beet: Fix extension header support on output The beet output function completely kills any extension headers by replacing them with the IPv6 header. This is because it essentially ignores the result of ip6_find_1stfragopt by simply acting as if there aren't any extension headers. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv6/xfrm6_mode_beet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index 65e6b2a7fb31..d9366dfbf868 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c @@ -44,9 +44,9 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) hdr_len = ip6_find_1stfragopt(skb, &prevhdr); memmove(skb->data, iph, hdr_len); - skb_set_mac_header(skb, offsetof(struct ipv6hdr, nexthdr)); + skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); skb_reset_network_header(skb); - skb_set_transport_header(skb, sizeof(struct ipv6hdr)); + skb_set_transport_header(skb, hdr_len); top_iph = ipv6_hdr(skb); ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); From 7b277b1a5fb147cb828e5d8b9780cee60f31a9bf Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 10 Oct 2007 15:44:06 -0700 Subject: [PATCH 1835/2804] [IPSEC]: Set skb->data to payload in x->mode->output This patch changes the calling convention so that on entry from x->mode->output and before entry into x->type->output skb->data will point to the payload instead of the IP header. This is essentially a redistribution of skb_push/skb_pull calls with the aim of minimising them on the common path of tunnel + ESP. It'll also let us use the same calling convention between IPv4 and IPv6 with the next patch. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ah4.c | 1 + net/ipv4/esp4.c | 6 ++---- net/ipv4/ipcomp.c | 1 + net/ipv4/xfrm4_mode_beet.c | 5 +++-- net/ipv4/xfrm4_mode_transport.c | 4 ++-- net/ipv4/xfrm4_mode_tunnel.c | 3 +-- net/ipv4/xfrm4_tunnel.c | 1 + net/ipv6/ah6.c | 1 + net/ipv6/esp6.c | 9 ++------- net/ipv6/ipcomp6.c | 5 ++++- net/ipv6/mip6.c | 2 ++ net/ipv6/xfrm6_mode_beet.c | 13 +++++++------ net/ipv6/xfrm6_mode_ro.c | 12 ++++++------ net/ipv6/xfrm6_mode_transport.c | 12 ++++++------ net/ipv6/xfrm6_mode_tunnel.c | 13 +++++++------ net/ipv6/xfrm6_tunnel.c | 1 + 16 files changed, 47 insertions(+), 42 deletions(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 3513149c3843..dbb1f11721e4 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -66,6 +66,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) char buf[60]; } tmp_iph; + skb_push(skb, -skb_network_offset(skb)); top_iph = ip_hdr(skb); iph = &tmp_iph.iph; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 1af332df72d9..0f5e8387ccb4 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -28,9 +28,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) int alen; int nfrags; - /* Strip IP+ESP header. */ - __skb_pull(skb, skb_transport_offset(skb)); - /* Now skb is pure payload to encrypt */ + /* skb is pure payload to encrypt */ err = -ENOMEM; @@ -60,7 +58,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) tail[clen - skb->len - 2] = (clen - skb->len) - 2; pskb_put(skb, trailer, clen - skb->len); - __skb_push(skb, -skb_network_offset(skb)); + skb_push(skb, -skb_network_offset(skb)); top_iph = ip_hdr(skb); esph = (struct ip_esp_hdr *)(skb_network_header(skb) + top_iph->ihl * 4); diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index e787044a8514..1929d451dab5 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -134,6 +134,7 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb) int hdr_len = 0; struct iphdr *iph = ip_hdr(skb); + skb_push(skb, -skb_network_offset(skb)); iph->tot_len = htons(skb->len); hdr_len = iph->ihl * 4; if ((skb->len - hdr_len) < ipcd->threshold) { diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c index a73e710740c2..77888f596737 100644 --- a/net/ipv4/xfrm4_mode_beet.c +++ b/net/ipv4/xfrm4_mode_beet.c @@ -40,10 +40,11 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) if (unlikely(optlen)) hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); - skb_push(skb, x->props.header_len - IPV4_BEET_PHMAXLEN + hdrlen); - skb_reset_network_header(skb); + skb_set_network_header(skb, IPV4_BEET_PHMAXLEN - x->props.header_len - + hdrlen); top_iph = ip_hdr(skb); skb->transport_header += sizeof(*iph) - hdrlen; + __skb_pull(skb, sizeof(*iph) - hdrlen); memmove(top_iph, iph, sizeof(*iph)); if (unlikely(optlen)) { diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c index 601047161ea6..10499d2ec65e 100644 --- a/net/ipv4/xfrm4_mode_transport.c +++ b/net/ipv4/xfrm4_mode_transport.c @@ -27,8 +27,8 @@ static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb) int ihl = iph->ihl * 4; skb->transport_header = skb->network_header + ihl; - skb_push(skb, x->props.header_len); - skb_reset_network_header(skb); + skb_set_network_header(skb, -x->props.header_len); + __skb_pull(skb, ihl); memmove(skb_network_header(skb), iph, ihl); return 0; } diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 9963700e74c1..bac1a91f0cbe 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -49,8 +49,7 @@ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) iph = ip_hdr(skb); skb->transport_header = skb->network_header; - skb_push(skb, x->props.header_len); - skb_reset_network_header(skb); + skb_set_network_header(skb, -x->props.header_len); top_iph = ip_hdr(skb); top_iph->ihl = 5; diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 9275c79119b6..be572f918b5e 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -14,6 +14,7 @@ static int ipip_output(struct xfrm_state *x, struct sk_buff *skb) { struct iphdr *iph = ip_hdr(skb); + skb_push(skb, -skb_network_offset(skb)); iph->tot_len = htons(skb->len); ip_send_check(iph); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index c51d77564b44..ac6bae17a13b 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -236,6 +236,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) char hdrs[0]; } *tmp_ext; + skb_push(skb, -skb_network_offset(skb)); top_iph = ipv6_hdr(skb); top_iph->payload_len = htons(skb->len - sizeof(*top_iph)); diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 7355bb0345e2..21c93f026dbc 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -54,13 +54,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) int nfrags; u8 *tail; struct esp_data *esp = x->data; - int hdr_len = (skb_transport_offset(skb) + - sizeof(*esph) + esp->conf.ivlen); - /* Strip IP+ESP header. */ - __skb_pull(skb, hdr_len); - - /* Now skb is pure payload to encrypt */ + /* skb is pure payload to encrypt */ err = -ENOMEM; /* Round to block size */ @@ -89,7 +84,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) tail[clen-skb->len - 2] = (clen - skb->len) - 2; pskb_put(skb, trailer, clen - skb->len); - __skb_push(skb, -skb_network_offset(skb)); + skb_push(skb, -skb_network_offset(skb)); top_iph = ipv6_hdr(skb); esph = (struct ipv6_esp_hdr *)skb_transport_header(skb); top_iph->payload_len = htons(skb->len + alen - sizeof(*top_iph)); diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 71a14c09975c..87e6407ebf97 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -128,7 +128,10 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) u8 *start, *scratch; struct crypto_comp *tfm; int cpu; - int hdr_len = skb_transport_offset(skb); + int hdr_len; + + skb_push(skb, -skb_network_offset(skb)); + hdr_len = skb_transport_offset(skb); /* check whether datagram len is larger than threshold */ if ((skb->len - hdr_len) < ipcd->threshold) { diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 6475baca63d2..0e7a60f7393a 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -153,6 +153,7 @@ static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) u8 nexthdr; int len; + skb_push(skb, -skb_network_offset(skb)); iph = ipv6_hdr(skb); iph->payload_len = htons(skb->len - sizeof(*iph)); @@ -367,6 +368,7 @@ static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb) struct rt2_hdr *rt2; u8 nexthdr; + skb_push(skb, -skb_network_offset(skb)); iph = ipv6_hdr(skb); iph->payload_len = htons(skb->len - sizeof(*iph)); diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index d9366dfbf868..bca018d19ec6 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c @@ -29,8 +29,8 @@ * filled in by x->type->output and the mac header will be set to the * nextheader field of the extension header directly preceding the * encapsulation header, or in its absence, that of the top IP header. - * The value of skb->data and the network header will always point to the - * top IP header. + * The value of the network header will always point to the top IP header + * while skb->data will point to the payload. */ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -38,16 +38,17 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) u8 *prevhdr; int hdr_len; - skb_push(skb, x->props.header_len); iph = ipv6_hdr(skb); hdr_len = ip6_find_1stfragopt(skb, &prevhdr); - memmove(skb->data, iph, hdr_len); skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); - skb_reset_network_header(skb); - skb_set_transport_header(skb, hdr_len); + skb_set_network_header(skb, -x->props.header_len); + skb_set_transport_header(skb, hdr_len - x->props.header_len); + __skb_pull(skb, hdr_len); + top_iph = ipv6_hdr(skb); + memmove(top_iph, iph, hdr_len); ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c index 25758048af54..5c29b367b432 100644 --- a/net/ipv6/xfrm6_mode_ro.c +++ b/net/ipv6/xfrm6_mode_ro.c @@ -42,8 +42,8 @@ * filled in by x->type->output and the mac header will be set to the * nextheader field of the extension header directly preceding the * encapsulation header, or in its absence, that of the top IP header. - * The value of skb->data and the network header will always point to the - * top IP header. + * The value of the network header will always point to the top IP header + * while skb->data will point to the payload. */ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -51,14 +51,14 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) u8 *prevhdr; int hdr_len; - skb_push(skb, x->props.header_len); iph = ipv6_hdr(skb); hdr_len = x->type->hdr_offset(x, skb, &prevhdr); skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); - skb_reset_network_header(skb); - skb_set_transport_header(skb, hdr_len); - memmove(skb->data, iph, hdr_len); + skb_set_network_header(skb, -x->props.header_len); + skb_set_transport_header(skb, hdr_len - x->props.header_len); + __skb_pull(skb, hdr_len); + memmove(ipv6_hdr(skb), iph, hdr_len); x->lastused = get_seconds(); diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c index 65c166b5d72c..f2ee186494ed 100644 --- a/net/ipv6/xfrm6_mode_transport.c +++ b/net/ipv6/xfrm6_mode_transport.c @@ -23,8 +23,8 @@ * filled in by x->type->output and the mac header will be set to the * nextheader field of the extension header directly preceding the * encapsulation header, or in its absence, that of the top IP header. - * The value of skb->data and the network header will always point to the - * top IP header. + * The value of the network header will always point to the top IP header + * while skb->data will point to the payload. */ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -32,14 +32,14 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) u8 *prevhdr; int hdr_len; - skb_push(skb, x->props.header_len); iph = ipv6_hdr(skb); hdr_len = x->type->hdr_offset(x, skb, &prevhdr); skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); - skb_reset_network_header(skb); - skb_set_transport_header(skb, hdr_len); - memmove(skb->data, iph, hdr_len); + skb_set_network_header(skb, -x->props.header_len); + skb_set_transport_header(skb, hdr_len - x->props.header_len); + __skb_pull(skb, hdr_len); + memmove(ipv6_hdr(skb), iph, hdr_len); return 0; } diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 3dd40af75e81..01bd7d11ea1b 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -41,8 +41,8 @@ static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb) * filled in by x->type->output and the mac header will be set to the * nextheader field of the extension header directly preceding the * encapsulation header, or in its absence, that of the top IP header. - * The value of skb->data and the network header will always point to the - * top IP header. + * The value of the network header will always point to the top IP header + * while skb->data will point to the payload. */ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -51,12 +51,13 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) struct ipv6hdr *iph, *top_iph; int dsfield; - skb_push(skb, x->props.header_len); iph = ipv6_hdr(skb); - skb_set_mac_header(skb, offsetof(struct ipv6hdr, nexthdr)); - skb_reset_network_header(skb); - skb_set_transport_header(skb, sizeof(struct ipv6hdr)); + skb_set_mac_header(skb, offsetof(struct ipv6hdr, nexthdr) - + x->props.header_len); + skb_set_network_header(skb, -x->props.header_len); + skb_set_transport_header(skb, sizeof(struct ipv6hdr) - + x->props.header_len); top_iph = ipv6_hdr(skb); top_iph->version = 6; diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index aeb06076fdd0..00a1a3e5237c 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -244,6 +244,7 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *top_iph; + skb_push(skb, -skb_network_offset(skb)); top_iph = ipv6_hdr(skb); top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); From 37fedd3aab6517daec628764c5d66dd8761fbe5f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 10 Oct 2007 15:44:44 -0700 Subject: [PATCH 1836/2804] [IPSEC]: Use IPv6 calling convention as the convention for x->mode->output The IPv6 calling convention for x->mode->output is more general and could help an eventual protocol-generic x->type->output implementation. This patch adopts it for IPv4 as well and modifies the IPv4 type output functions accordingly. It also rewrites the IPv6 mac/transport header calculation to be based off the network header where practical. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/xfrm.h | 12 ++++++++++++ net/ipv4/ah4.c | 6 +++--- net/ipv4/esp4.c | 11 +++++------ net/ipv4/ipcomp.c | 10 +++++----- net/ipv4/xfrm4_mode_beet.c | 17 +++++++---------- net/ipv4/xfrm4_mode_transport.c | 7 +++---- net/ipv4/xfrm4_mode_tunnel.c | 7 +++---- net/ipv6/xfrm6_mode_beet.c | 9 +-------- net/ipv6/xfrm6_mode_ro.c | 9 +-------- net/ipv6/xfrm6_mode_transport.c | 9 +-------- net/ipv6/xfrm6_mode_tunnel.c | 14 +++----------- 11 files changed, 44 insertions(+), 67 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 1c116dc03e0e..77be396ca633 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -300,6 +300,18 @@ extern void xfrm_put_type(struct xfrm_type *type); struct xfrm_mode { int (*input)(struct xfrm_state *x, struct sk_buff *skb); + + /* + * Add encapsulation header. + * + * On exit, the transport header will be set to the start of the + * encapsulation header to be filled in by x->type->output and + * the mac header will be set to the nextheader (protocol for + * IPv4) field of the extension header directly preceding the + * encapsulation header, or in its absence, that of the top IP + * header. The value of the network header will always point + * to the top IP header while skb->data will point to the payload. + */ int (*output)(struct xfrm_state *x,struct sk_buff *skb); struct module *owner; diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index dbb1f11721e4..e4f7aa39978d 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -82,14 +82,14 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) goto error; } - ah = (struct ip_auth_hdr *)((char *)top_iph+top_iph->ihl*4); - ah->nexthdr = top_iph->protocol; + ah = (struct ip_auth_hdr *)skb_transport_header(skb); + ah->nexthdr = *skb_mac_header(skb); + *skb_mac_header(skb) = IPPROTO_AH; top_iph->tos = 0; top_iph->tot_len = htons(skb->len); top_iph->frag_off = 0; top_iph->ttl = 0; - top_iph->protocol = IPPROTO_AH; top_iph->check = 0; ahp = x->data; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 0f5e8387ccb4..93153d105619 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -60,10 +60,10 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, -skb_network_offset(skb)); top_iph = ip_hdr(skb); - esph = (struct ip_esp_hdr *)(skb_network_header(skb) + - top_iph->ihl * 4); + esph = (struct ip_esp_hdr *)skb_transport_header(skb); top_iph->tot_len = htons(skb->len + alen); - *(skb_tail_pointer(trailer) - 1) = top_iph->protocol; + *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb); + *skb_mac_header(skb) = IPPROTO_ESP; spin_lock_bh(&x->lock); @@ -91,9 +91,8 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) break; } - top_iph->protocol = IPPROTO_UDP; - } else - top_iph->protocol = IPPROTO_ESP; + *skb_mac_header(skb) = IPPROTO_UDP; + } esph->spi = x->id.spi; esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 1929d451dab5..bf74f64fe5fb 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -98,10 +98,10 @@ out: static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb) { struct ipcomp_data *ipcd = x->data; - const int ihlen = ip_hdrlen(skb); + const int ihlen = skb_transport_offset(skb); const int plen = skb->len - ihlen; int dlen = IPCOMP_SCRATCH_SIZE; - u8 *start = skb->data + ihlen; + u8 *start = skb_transport_header(skb); const int cpu = get_cpu(); u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); @@ -154,11 +154,11 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb) /* Install ipcomp header, convert into ipcomp datagram. */ iph->tot_len = htons(skb->len); - ipch = (struct ip_comp_hdr *)((char *)iph + iph->ihl * 4); - ipch->nexthdr = iph->protocol; + ipch = (struct ip_comp_hdr *)skb_transport_header(skb); + ipch->nexthdr = *skb_mac_header(skb); ipch->flags = 0; ipch->cpi = htons((u16 )ntohl(x->id.spi)); - iph->protocol = IPPROTO_COMP; + *skb_mac_header(skb) = IPPROTO_COMP; ip_send_check(iph); return 0; diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c index 77888f596737..7226c6486c01 100644 --- a/net/ipv4/xfrm4_mode_beet.c +++ b/net/ipv4/xfrm4_mode_beet.c @@ -23,17 +23,14 @@ * The following fields in it shall be filled in by x->type->output: * tot_len * check - * - * On exit, skb->h will be set to the start of the payload to be processed - * by x->type->output and skb->nh will be set to the top IP header. */ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) { + struct ip_beet_phdr *ph; struct iphdr *iph, *top_iph; int hdrlen, optlen; iph = ip_hdr(skb); - skb->transport_header = skb->network_header; hdrlen = 0; optlen = iph->ihl * 4 - sizeof(*iph); @@ -42,17 +39,17 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) skb_set_network_header(skb, IPV4_BEET_PHMAXLEN - x->props.header_len - hdrlen); - top_iph = ip_hdr(skb); - skb->transport_header += sizeof(*iph) - hdrlen; - __skb_pull(skb, sizeof(*iph) - hdrlen); + skb->mac_header = skb->network_header + + offsetof(struct iphdr, protocol); + skb->transport_header = skb->network_header + sizeof(*iph); + ph = (struct ip_beet_phdr *)__skb_pull(skb, sizeof(*iph) - hdrlen); + + top_iph = ip_hdr(skb); memmove(top_iph, iph, sizeof(*iph)); if (unlikely(optlen)) { - struct ip_beet_phdr *ph; - BUG_ON(optlen < 0); - ph = (struct ip_beet_phdr *)skb_transport_header(skb); ph->padlen = 4 - (optlen & 4); ph->hdrlen = optlen / 8; ph->nexthdr = top_iph->protocol; diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c index 10499d2ec65e..fd840c7d75ea 100644 --- a/net/ipv4/xfrm4_mode_transport.c +++ b/net/ipv4/xfrm4_mode_transport.c @@ -17,17 +17,16 @@ * * The IP header will be moved forward to make space for the encapsulation * header. - * - * On exit, skb->h will be set to the start of the payload to be processed - * by x->type->output and skb->nh will be set to the top IP header. */ static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb) { struct iphdr *iph = ip_hdr(skb); int ihl = iph->ihl * 4; - skb->transport_header = skb->network_header + ihl; skb_set_network_header(skb, -x->props.header_len); + skb->mac_header = skb->network_header + + offsetof(struct iphdr, protocol); + skb->transport_header = skb->network_header + ihl; __skb_pull(skb, ihl); memmove(skb_network_header(skb), iph, ihl); return 0; diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index bac1a91f0cbe..f1d41ea34785 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -35,9 +35,6 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) * in it shall be filled in by x->type->output: * tot_len * check - * - * On exit, skb->h will be set to the start of the payload to be processed - * by x->type->output and skb->nh will be set to the top IP header. */ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -47,9 +44,11 @@ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) int flags; iph = ip_hdr(skb); - skb->transport_header = skb->network_header; skb_set_network_header(skb, -x->props.header_len); + skb->mac_header = skb->network_header + + offsetof(struct iphdr, protocol); + skb->transport_header = skb->network_header + sizeof(*iph); top_iph = ip_hdr(skb); top_iph->ihl = 5; diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index bca018d19ec6..42c6ef839e59 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c @@ -24,13 +24,6 @@ * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. * The following fields in it shall be filled in by x->type->output: * payload_len - * - * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and the mac header will be set to the - * nextheader field of the extension header directly preceding the - * encapsulation header, or in its absence, that of the top IP header. - * The value of the network header will always point to the top IP header - * while skb->data will point to the payload. */ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -44,7 +37,7 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); skb_set_network_header(skb, -x->props.header_len); - skb_set_transport_header(skb, hdr_len - x->props.header_len); + skb->transport_header = skb->network_header + hdr_len; __skb_pull(skb, hdr_len); top_iph = ipv6_hdr(skb); diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c index 5c29b367b432..957ae36b6695 100644 --- a/net/ipv6/xfrm6_mode_ro.c +++ b/net/ipv6/xfrm6_mode_ro.c @@ -37,13 +37,6 @@ * * The IP header and mutable extension headers will be moved forward to make * space for the route optimization header. - * - * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and the mac header will be set to the - * nextheader field of the extension header directly preceding the - * encapsulation header, or in its absence, that of the top IP header. - * The value of the network header will always point to the top IP header - * while skb->data will point to the payload. */ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -56,7 +49,7 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) hdr_len = x->type->hdr_offset(x, skb, &prevhdr); skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); skb_set_network_header(skb, -x->props.header_len); - skb_set_transport_header(skb, hdr_len - x->props.header_len); + skb->transport_header = skb->network_header + hdr_len; __skb_pull(skb, hdr_len); memmove(ipv6_hdr(skb), iph, hdr_len); diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c index f2ee186494ed..4e344105b3fd 100644 --- a/net/ipv6/xfrm6_mode_transport.c +++ b/net/ipv6/xfrm6_mode_transport.c @@ -18,13 +18,6 @@ * * The IP header and mutable extension headers will be moved forward to make * space for the encapsulation header. - * - * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and the mac header will be set to the - * nextheader field of the extension header directly preceding the - * encapsulation header, or in its absence, that of the top IP header. - * The value of the network header will always point to the top IP header - * while skb->data will point to the payload. */ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -37,7 +30,7 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) hdr_len = x->type->hdr_offset(x, skb, &prevhdr); skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); skb_set_network_header(skb, -x->props.header_len); - skb_set_transport_header(skb, hdr_len - x->props.header_len); + skb->transport_header = skb->network_header + hdr_len; __skb_pull(skb, hdr_len); memmove(ipv6_hdr(skb), iph, hdr_len); return 0; diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 01bd7d11ea1b..e79c6bdf71c1 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -36,13 +36,6 @@ static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb) * The top IP header will be constructed per RFC 2401. The following fields * in it shall be filled in by x->type->output: * payload_len - * - * On exit, skb->h will be set to the start of the encapsulation header to be - * filled in by x->type->output and the mac header will be set to the - * nextheader field of the extension header directly preceding the - * encapsulation header, or in its absence, that of the top IP header. - * The value of the network header will always point to the top IP header - * while skb->data will point to the payload. */ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { @@ -53,11 +46,10 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) iph = ipv6_hdr(skb); - skb_set_mac_header(skb, offsetof(struct ipv6hdr, nexthdr) - - x->props.header_len); skb_set_network_header(skb, -x->props.header_len); - skb_set_transport_header(skb, sizeof(struct ipv6hdr) - - x->props.header_len); + skb->mac_header = skb->network_header + + offsetof(struct ipv6hdr, nexthdr); + skb->transport_header = skb->network_header + sizeof(*iph); top_iph = ipv6_hdr(skb); top_iph->version = 6; From 87bdc48d304191313203df9b98d783e1ab5a55ab Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 10 Oct 2007 15:45:25 -0700 Subject: [PATCH 1837/2804] [IPSEC]: Get rid of ipv6_{auth,esp,comp}_hdr This patch removes the duplicate ipv6_{auth,esp,comp}_hdr structures since they're identical to the IPv4 versions. Duplicating them would only create problems for ourselves later when we need to add things like extended sequence numbers. I've also added transport header type conversion headers for these types which are now used by the transforms. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/ipv6.h | 21 --------------------- include/net/ah.h | 7 +++++++ include/net/esp.h | 7 +++++++ include/net/ipcomp.h | 11 ++++++++++- net/ipv4/ah4.c | 18 +++++++++--------- net/ipv4/esp4.c | 10 +++++----- net/ipv4/ipcomp.c | 2 +- net/ipv6/ah6.c | 16 ++++++++-------- net/ipv6/esp6.c | 18 +++++++++--------- net/ipv6/ipcomp6.c | 17 ++++++++--------- 10 files changed, 64 insertions(+), 63 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 4ca60c3320fb..5d35a4cc3bff 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -96,27 +96,6 @@ struct ipv6_destopt_hao { struct in6_addr addr; } __attribute__ ((__packed__)); -struct ipv6_auth_hdr { - __u8 nexthdr; - __u8 hdrlen; /* This one is measured in 32 bit units! */ - __be16 reserved; - __be32 spi; - __be32 seq_no; /* Sequence number */ - __u8 auth_data[0]; /* Length variable but >=4. Mind the 64 bit alignment! */ -}; - -struct ipv6_esp_hdr { - __be32 spi; - __be32 seq_no; /* Sequence number */ - __u8 enc_data[0]; /* Length variable but >=8. Mind the 64 bit alignment! */ -}; - -struct ipv6_comp_hdr { - __u8 nexthdr; - __u8 flags; - __be16 cpi; -}; - /* * IPv6 fixed header * diff --git a/include/net/ah.h b/include/net/ah.h index 5e758c2b5dd5..ae1c322f4242 100644 --- a/include/net/ah.h +++ b/include/net/ah.h @@ -38,4 +38,11 @@ out: return err; } +struct ip_auth_hdr; + +static inline struct ip_auth_hdr *ip_auth_hdr(const struct sk_buff *skb) +{ + return (struct ip_auth_hdr *)skb_transport_header(skb); +} + #endif diff --git a/include/net/esp.h b/include/net/esp.h index e793d769430e..c1bc529809da 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -53,4 +53,11 @@ static inline int esp_mac_digest(struct esp_data *esp, struct sk_buff *skb, return crypto_hash_final(&desc, esp->auth.work_icv); } +struct ip_esp_hdr; + +static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) +{ + return (struct ip_esp_hdr *)skb_transport_header(skb); +} + #endif diff --git a/include/net/ipcomp.h b/include/net/ipcomp.h index 87c1af3e5e82..330b74e813a9 100644 --- a/include/net/ipcomp.h +++ b/include/net/ipcomp.h @@ -1,14 +1,23 @@ #ifndef _NET_IPCOMP_H #define _NET_IPCOMP_H -#include #include #define IPCOMP_SCRATCH_SIZE 65400 +struct crypto_comp; + struct ipcomp_data { u16 threshold; struct crypto_comp **tfms; }; +struct ip_comp_hdr; +struct sk_buff; + +static inline struct ip_comp_hdr *ip_comp_hdr(const struct sk_buff *skb) +{ + return (struct ip_comp_hdr *)skb_transport_header(skb); +} + #endif diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index e4f7aa39978d..d69706405d58 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -82,7 +82,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) goto error; } - ah = (struct ip_auth_hdr *)skb_transport_header(skb); + ah = ip_auth_hdr(skb); ah->nexthdr = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_AH; @@ -93,8 +93,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->check = 0; ahp = x->data; - ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + - ahp->icv_trunc_len) >> 2) - 2; + ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; ah->reserved = 0; ah->spi = x->id.spi; @@ -134,15 +133,15 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) struct ah_data *ahp; char work_buf[60]; - if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) + if (!pskb_may_pull(skb, sizeof(*ah))) goto out; - ah = (struct ip_auth_hdr*)skb->data; + ah = (struct ip_auth_hdr *)skb->data; ahp = x->data; ah_hlen = (ah->hdrlen + 2) << 2; - if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && - ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) + if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) && + ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len)) goto out; if (!pskb_may_pull(skb, ah_hlen)) @@ -156,7 +155,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) skb->ip_summed = CHECKSUM_NONE; - ah = (struct ip_auth_hdr*)skb->data; + ah = (struct ip_auth_hdr *)skb->data; iph = ip_hdr(skb); ihl = skb->data - skb_network_header(skb); @@ -266,7 +265,8 @@ static int ah_init_state(struct xfrm_state *x) if (!ahp->work_icv) goto error; - x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); + x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + + ahp->icv_trunc_len); if (x->props.mode == XFRM_MODE_TUNNEL) x->props.header_len += sizeof(struct iphdr); x->data = ahp; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 93153d105619..66eb4968b910 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -60,7 +60,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, -skb_network_offset(skb)); top_iph = ip_hdr(skb); - esph = (struct ip_esp_hdr *)skb_transport_header(skb); + esph = ip_esp_hdr(skb); top_iph->tot_len = htons(skb->len + alen); *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_ESP; @@ -157,7 +157,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) struct sk_buff *trailer; int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); int alen = esp->auth.icv_trunc_len; - int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; + int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen; int nfrags; int ihl; u8 nexthdr[2]; @@ -165,7 +165,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) int padlen; int err; - if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) + if (!pskb_may_pull(skb, sizeof(*esph))) goto out; if (elen <= 0 || (elen & (blksize-1))) @@ -193,7 +193,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) skb->ip_summed = CHECKSUM_NONE; - esph = (struct ip_esp_hdr*)skb->data; + esph = (struct ip_esp_hdr *)skb->data; /* Get ivec. This can be wrong, check against another impls. */ if (esp->conf.ivlen) @@ -206,7 +206,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) if (!sg) goto out; } - skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); + skb_to_sgvec(skb, sg, sizeof(*esph) + esp->conf.ivlen, elen); err = crypto_blkcipher_decrypt(&desc, sg, sg, elen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index bf74f64fe5fb..78d6ddb02d1d 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -154,7 +154,7 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb) /* Install ipcomp header, convert into ipcomp datagram. */ iph->tot_len = htons(skb->len); - ipch = (struct ip_comp_hdr *)skb_transport_header(skb); + ipch = ip_comp_hdr(skb); ipch->nexthdr = *skb_mac_header(skb); ipch->flags = 0; ipch->cpi = htons((u16 )ntohl(x->id.spi)); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index ac6bae17a13b..f9f689162692 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -270,7 +270,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) goto error_free_iph; } - ah = (struct ip_auth_hdr *)skb_transport_header(skb); + ah = ip_auth_hdr(skb); ah->nexthdr = nexthdr; top_iph->priority = 0; @@ -280,8 +280,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->hop_limit = 0; ahp = x->data; - ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + - ahp->icv_trunc_len) >> 2) - 2; + ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; ah->reserved = 0; ah->spi = x->id.spi; @@ -327,7 +326,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) * There is offset of AH before IPv6 header after the process. */ - struct ipv6_auth_hdr *ah; + struct ip_auth_hdr *ah; struct ipv6hdr *ip6h; struct ah_data *ahp; unsigned char *tmp_hdr = NULL; @@ -346,13 +345,13 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) goto out; hdr_len = skb->data - skb_network_header(skb); - ah = (struct ipv6_auth_hdr*)skb->data; + ah = (struct ip_auth_hdr *)skb->data; ahp = x->data; nexthdr = ah->nexthdr; ah_hlen = (ah->hdrlen + 2) << 2; - if (ah_hlen != XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_full_len) && - ah_hlen != XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len)) + if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) && + ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len)) goto out; if (!pskb_may_pull(skb, ah_hlen)) @@ -474,7 +473,8 @@ static int ah6_init_state(struct xfrm_state *x) if (!ahp->work_icv) goto error; - x->props.header_len = XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len); + x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + + ahp->icv_trunc_len); if (x->props.mode == XFRM_MODE_TUNNEL) x->props.header_len += sizeof(struct ipv6hdr); x->data = ahp; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 21c93f026dbc..a64295d164ea 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -44,7 +44,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) { int err; struct ipv6hdr *top_iph; - struct ipv6_esp_hdr *esph; + struct ip_esp_hdr *esph; struct crypto_blkcipher *tfm; struct blkcipher_desc desc; struct sk_buff *trailer; @@ -86,7 +86,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, -skb_network_offset(skb)); top_iph = ipv6_hdr(skb); - esph = (struct ipv6_esp_hdr *)skb_transport_header(skb); + esph = ip_esp_hdr(skb); top_iph->payload_len = htons(skb->len + alen - sizeof(*top_iph)); *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_ESP; @@ -142,19 +142,19 @@ error: static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *iph; - struct ipv6_esp_hdr *esph; + struct ip_esp_hdr *esph; struct esp_data *esp = x->data; struct crypto_blkcipher *tfm = esp->conf.tfm; struct blkcipher_desc desc = { .tfm = tfm }; struct sk_buff *trailer; int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); int alen = esp->auth.icv_trunc_len; - int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen; + int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen; int hdr_len = skb_network_header_len(skb); int nfrags; int ret = 0; - if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) { + if (!pskb_may_pull(skb, sizeof(*esph))) { ret = -EINVAL; goto out; } @@ -189,7 +189,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) skb->ip_summed = CHECKSUM_NONE; - esph = (struct ipv6_esp_hdr*)skb->data; + esph = (struct ip_esp_hdr *)skb->data; iph = ipv6_hdr(skb); /* Get ivec. This can be wrong, check against another impls. */ @@ -208,7 +208,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) goto out; } } - skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen); + skb_to_sgvec(skb, sg, sizeof(*esph) + esp->conf.ivlen, elen); ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); @@ -260,7 +260,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info) { struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; - struct ipv6_esp_hdr *esph = (struct ipv6_esp_hdr*)(skb->data+offset); + struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset); struct xfrm_state *x; if (type != ICMPV6_DEST_UNREACH && @@ -356,7 +356,7 @@ static int esp6_init_state(struct xfrm_state *x) if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8)) goto error; - x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; + x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; if (x->props.mode == XFRM_MODE_TUNNEL) x->props.header_len += sizeof(struct ipv6hdr); x->data = esp; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 87e6407ebf97..8f3f32faaf4c 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -65,7 +65,7 @@ static LIST_HEAD(ipcomp6_tfms_list); static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) { int err = -ENOMEM; - struct ipv6_comp_hdr *ipch; + struct ip_comp_hdr *ipch; int plen, dlen; struct ipcomp_data *ipcd = x->data; u8 *start, *scratch; @@ -92,12 +92,10 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) tfm = *per_cpu_ptr(ipcd->tfms, cpu); err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen); - if (err) { - err = -EINVAL; + if (err) goto out_put_cpu; - } - if (dlen < (plen + sizeof(struct ipv6_comp_hdr))) { + if (dlen < (plen + sizeof(*ipch))) { err = -EINVAL; goto out_put_cpu; } @@ -122,7 +120,7 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) { int err; struct ipv6hdr *top_iph; - struct ipv6_comp_hdr *ipch; + struct ip_comp_hdr *ipch; struct ipcomp_data *ipcd = x->data; int plen, dlen; u8 *start, *scratch; @@ -151,7 +149,7 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) tfm = *per_cpu_ptr(ipcd->tfms, cpu); err = crypto_comp_compress(tfm, start, plen, scratch, &dlen); - if (err || (dlen + sizeof(struct ipv6_comp_hdr)) >= plen) { + if (err || (dlen + sizeof(*ipch)) >= plen) { put_cpu(); goto out_ok; } @@ -164,7 +162,7 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); - ipch = (struct ipv6_comp_hdr *)start; + ipch = ip_comp_hdr(skb); ipch->nexthdr = *skb_mac_header(skb); ipch->flags = 0; ipch->cpi = htons((u16 )ntohl(x->id.spi)); @@ -179,7 +177,8 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, { __be32 spi; struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; - struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset); + struct ip_comp_hdr *ipcomph = + (struct ip_comp_hdr *)(skb->data + offset); struct xfrm_state *x; if (type != ICMPV6_DEST_UNREACH && type != ICMPV6_PKT_TOOBIG) From ceb1eec8291175686d0208e66595ff83bc0624e2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 10 Oct 2007 15:45:52 -0700 Subject: [PATCH 1838/2804] [IPSEC]: Move IP length/checksum setting out of transforms This patch moves the setting of the IP length and checksum fields out of the transforms and into the xfrmX_output functions. This would help future efforts in merging the transforms themselves. It also adds an optimisation to ipcomp due to the fact that the transport offset is guaranteed to be zero. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ah4.c | 2 -- net/ipv4/esp4.c | 7 +------ net/ipv4/ipcomp.c | 22 +++++----------------- net/ipv4/xfrm4_mode_beet.c | 3 --- net/ipv4/xfrm4_mode_tunnel.c | 5 +---- net/ipv4/xfrm4_output.c | 5 +++++ net/ipv4/xfrm4_tunnel.c | 5 ----- net/ipv6/esp6.c | 3 --- net/ipv6/ipcomp6.c | 19 ++++++------------- net/ipv6/mip6.c | 2 -- net/ipv6/xfrm6_mode_beet.c | 2 -- net/ipv6/xfrm6_mode_tunnel.c | 4 +--- net/ipv6/xfrm6_output.c | 4 ++++ net/ipv6/xfrm6_tunnel.c | 5 ----- 14 files changed, 23 insertions(+), 65 deletions(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index d69706405d58..60925fedbf16 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -115,8 +115,6 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); } - ip_send_check(top_iph); - err = 0; error: diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 66eb4968b910..8377bedf3f66 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -16,7 +16,6 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) { int err; - struct iphdr *top_iph; struct ip_esp_hdr *esph; struct crypto_blkcipher *tfm; struct blkcipher_desc desc; @@ -59,9 +58,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) pskb_put(skb, trailer, clen - skb->len); skb_push(skb, -skb_network_offset(skb)); - top_iph = ip_hdr(skb); esph = ip_esp_hdr(skb); - top_iph->tot_len = htons(skb->len + alen); *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_ESP; @@ -76,7 +73,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) uh = (struct udphdr *)esph; uh->source = encap->encap_sport; uh->dest = encap->encap_dport; - uh->len = htons(skb->len + alen - top_iph->ihl*4); + uh->len = htons(skb->len + alen - skb_transport_offset(skb)); uh->check = 0; switch (encap->encap_type) { @@ -136,8 +133,6 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) unlock: spin_unlock_bh(&x->lock); - ip_send_check(top_iph); - error: return err; } diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 78d6ddb02d1d..32b02deca2ec 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -98,10 +98,9 @@ out: static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb) { struct ipcomp_data *ipcd = x->data; - const int ihlen = skb_transport_offset(skb); - const int plen = skb->len - ihlen; + const int plen = skb->len; int dlen = IPCOMP_SCRATCH_SIZE; - u8 *start = skb_transport_header(skb); + u8 *start = skb->data; const int cpu = get_cpu(); u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); @@ -118,7 +117,7 @@ static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb) memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen); put_cpu(); - pskb_trim(skb, ihlen + dlen + sizeof(struct ip_comp_hdr)); + pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr)); return 0; out: @@ -131,13 +130,8 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb) int err; struct ip_comp_hdr *ipch; struct ipcomp_data *ipcd = x->data; - int hdr_len = 0; - struct iphdr *iph = ip_hdr(skb); - skb_push(skb, -skb_network_offset(skb)); - iph->tot_len = htons(skb->len); - hdr_len = iph->ihl * 4; - if ((skb->len - hdr_len) < ipcd->threshold) { + if (skb->len < ipcd->threshold) { /* Don't bother compressing */ goto out_ok; } @@ -146,25 +140,19 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb) goto out_ok; err = ipcomp_compress(x, skb); - iph = ip_hdr(skb); if (err) { goto out_ok; } /* Install ipcomp header, convert into ipcomp datagram. */ - iph->tot_len = htons(skb->len); ipch = ip_comp_hdr(skb); ipch->nexthdr = *skb_mac_header(skb); ipch->flags = 0; ipch->cpi = htons((u16 )ntohl(x->id.spi)); *skb_mac_header(skb) = IPPROTO_COMP; - ip_send_check(iph); - return 0; - out_ok: - if (x->props.mode == XFRM_MODE_TUNNEL) - ip_send_check(iph); + skb_push(skb, -skb_network_offset(skb)); return 0; } diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c index 7226c6486c01..73d2338bec55 100644 --- a/net/ipv4/xfrm4_mode_beet.c +++ b/net/ipv4/xfrm4_mode_beet.c @@ -20,9 +20,6 @@ /* Add encapsulation header. * * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. - * The following fields in it shall be filled in by x->type->output: - * tot_len - * check */ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) { diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index f1d41ea34785..1ae9d32276f0 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -31,10 +31,7 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) /* Add encapsulation header. * - * The top IP header will be constructed per RFC 2401. The following fields - * in it shall be filled in by x->type->output: - * tot_len - * check + * The top IP header will be constructed per RFC 2401. */ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 04805c7d79c3..434ef302ba83 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -44,6 +44,7 @@ static inline int xfrm4_output_one(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; + struct iphdr *iph; int err; if (x->props.mode == XFRM_MODE_TUNNEL) { @@ -56,6 +57,10 @@ static inline int xfrm4_output_one(struct sk_buff *skb) if (err) goto error_nolock; + iph = ip_hdr(skb); + iph->tot_len = htons(skb->len); + ip_send_check(iph); + IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; err = 0; diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index be572f918b5e..e1fafc1562d8 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -12,12 +12,7 @@ static int ipip_output(struct xfrm_state *x, struct sk_buff *skb) { - struct iphdr *iph = ip_hdr(skb); - skb_push(skb, -skb_network_offset(skb)); - iph->tot_len = htons(skb->len); - ip_send_check(iph); - return 0; } diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index a64295d164ea..9eb928598351 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -43,7 +43,6 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) { int err; - struct ipv6hdr *top_iph; struct ip_esp_hdr *esph; struct crypto_blkcipher *tfm; struct blkcipher_desc desc; @@ -85,9 +84,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) pskb_put(skb, trailer, clen - skb->len); skb_push(skb, -skb_network_offset(skb)); - top_iph = ipv6_hdr(skb); esph = ip_esp_hdr(skb); - top_iph->payload_len = htons(skb->len + alen - sizeof(*top_iph)); *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_ESP; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 8f3f32faaf4c..28fc8edfdc3a 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -119,20 +119,15 @@ out: static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) { int err; - struct ipv6hdr *top_iph; struct ip_comp_hdr *ipch; struct ipcomp_data *ipcd = x->data; int plen, dlen; u8 *start, *scratch; struct crypto_comp *tfm; int cpu; - int hdr_len; - - skb_push(skb, -skb_network_offset(skb)); - hdr_len = skb_transport_offset(skb); /* check whether datagram len is larger than threshold */ - if ((skb->len - hdr_len) < ipcd->threshold) { + if (skb->len < ipcd->threshold) { goto out_ok; } @@ -140,9 +135,9 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) goto out_ok; /* compression */ - plen = skb->len - hdr_len; + plen = skb->len; dlen = IPCOMP_SCRATCH_SIZE; - start = skb_transport_header(skb); + start = skb->data; cpu = get_cpu(); scratch = *per_cpu_ptr(ipcomp6_scratches, cpu); @@ -155,13 +150,9 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) } memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen); put_cpu(); - pskb_trim(skb, hdr_len + dlen + sizeof(struct ip_comp_hdr)); + pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr)); /* insert ipcomp header and replace datagram */ - top_iph = ipv6_hdr(skb); - - top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); - ipch = ip_comp_hdr(skb); ipch->nexthdr = *skb_mac_header(skb); ipch->flags = 0; @@ -169,6 +160,8 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) *skb_mac_header(skb) = IPPROTO_COMP; out_ok: + skb_push(skb, -skb_network_offset(skb)); + return 0; } diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 0e7a60f7393a..7fd841d41019 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -155,7 +155,6 @@ static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, -skb_network_offset(skb)); iph = ipv6_hdr(skb); - iph->payload_len = htons(skb->len - sizeof(*iph)); nexthdr = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_DSTOPTS; @@ -370,7 +369,6 @@ static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, -skb_network_offset(skb)); iph = ipv6_hdr(skb); - iph->payload_len = htons(skb->len - sizeof(*iph)); nexthdr = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_ROUTING; diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index 42c6ef839e59..13bb1e856764 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c @@ -22,8 +22,6 @@ /* Add encapsulation header. * * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. - * The following fields in it shall be filled in by x->type->output: - * payload_len */ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) { diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index e79c6bdf71c1..ea2283879112 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -33,9 +33,7 @@ static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb) /* Add encapsulation header. * - * The top IP header will be constructed per RFC 2401. The following fields - * in it shall be filled in by x->type->output: - * payload_len + * The top IP header will be constructed per RFC 2401. */ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index f21596f89984..4618c18e611d 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -47,6 +47,7 @@ static inline int xfrm6_output_one(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; + struct ipv6hdr *iph; int err; if (x->props.mode == XFRM_MODE_TUNNEL) { @@ -59,6 +60,9 @@ static inline int xfrm6_output_one(struct sk_buff *skb) if (err) goto error_nolock; + iph = ipv6_hdr(skb); + iph->payload_len = htons(skb->len - sizeof(*iph)); + IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; err = 0; diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 00a1a3e5237c..3f8a3abde67e 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -242,12 +242,7 @@ EXPORT_SYMBOL(xfrm6_tunnel_free_spi); static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { - struct ipv6hdr *top_iph; - skb_push(skb, -skb_network_offset(skb)); - top_iph = ipv6_hdr(skb); - top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); - return 0; } From 631a6698d09e57cadc069914d613899609a0ae83 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 10 Oct 2007 15:46:21 -0700 Subject: [PATCH 1839/2804] [IPSEC]: Move IP protocol setting from transforms into xfrm4_input.c This patch makes the IPv4 x->type->input functions return the next protocol instead of setting it directly. This is identical to how we do things in IPv6 and will help us merge common code on the input path. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ah4.c | 5 +++-- net/ipv4/esp4.c | 3 +-- net/ipv4/ipcomp.c | 7 ++++--- net/ipv4/xfrm4_input.c | 7 ++++++- net/ipv4/xfrm4_tunnel.c | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 60925fedbf16..4e8e3b079f5b 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -125,6 +125,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) { int ah_hlen; int ihl; + int nexthdr; int err = -EINVAL; struct iphdr *iph; struct ip_auth_hdr *ah; @@ -136,6 +137,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) ah = (struct ip_auth_hdr *)skb->data; ahp = x->data; + nexthdr = ah->nexthdr; ah_hlen = (ah->hdrlen + 2) << 2; if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) && @@ -182,13 +184,12 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) goto out; } } - ((struct iphdr*)work_buf)->protocol = ah->nexthdr; skb->network_header += ah_hlen; memcpy(skb_network_header(skb), work_buf, ihl); skb->transport_header = skb->network_header; __skb_pull(skb, ah_hlen + ihl); - return 0; + return nexthdr; out: return err; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 8377bedf3f66..6b1a31a74cf2 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -257,12 +257,11 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) skb->ip_summed = CHECKSUM_UNNECESSARY; } - iph->protocol = nexthdr[1]; pskb_trim(skb, skb->len - alen - padlen - 2); __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen); skb_set_transport_header(skb, -ihl); - return 0; + return nexthdr[1]; out: return -EINVAL; diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 32b02deca2ec..0bfeb02a5f87 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -75,7 +75,6 @@ out: static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb) { int err = -ENOMEM; - struct iphdr *iph; struct ip_comp_hdr *ipch; if (skb_linearize_cow(skb)) @@ -84,12 +83,14 @@ static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb) skb->ip_summed = CHECKSUM_NONE; /* Remove ipcomp header and decompress original payload */ - iph = ip_hdr(skb); ipch = (void *)skb->data; - iph->protocol = ipch->nexthdr; skb->transport_header = skb->network_header + sizeof(*ipch); __skb_pull(skb, sizeof(*ipch)); err = ipcomp_decompress(x, skb); + if (err) + goto out; + + err = ipch->nexthdr; out: return err; diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 2fa108245413..e9bbfde19ac3 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -54,12 +54,14 @@ static int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) int xfrm_nr = 0; int decaps = 0; int err = xfrm4_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq); + unsigned int nhoff = offsetof(struct iphdr, protocol); if (err != 0) goto drop; do { const struct iphdr *iph = ip_hdr(skb); + int nexthdr; if (xfrm_nr == XFRM_MAX_DEPTH) goto drop; @@ -82,9 +84,12 @@ static int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) if (xfrm_state_check_expire(x)) goto drop_unlock; - if (x->type->input(x, skb)) + nexthdr = x->type->input(x, skb); + if (nexthdr <= 0) goto drop_unlock; + skb_network_header(skb)[nhoff] = nexthdr; + /* only the first xfrm gets the encap type */ encap_type = 0; diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index e1fafc1562d8..1312417608e2 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -18,7 +18,7 @@ static int ipip_output(struct xfrm_state *x, struct sk_buff *skb) static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb) { - return 0; + return IPPROTO_IP; } static int ipip_init_state(struct xfrm_state *x) From 489310a440e606512b1fd79d8562d1da6b715448 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 10 Oct 2007 16:16:31 -0700 Subject: [PATCH 1840/2804] [BNX2]: Fix remote PHY media detection problems. The remote PHY media type and link status can change between ->probe() and ->open(). For correct operation, we need to get the new status again during ->open(). The ethtool link test and loopback test are also fixed to work with remote PHY. PHY loopback is simply skipped when remote PHY is present. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 0e4928c751ff..21493e0cbd42 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3776,12 +3776,6 @@ bnx2_init_remote_phy(struct bnx2 *bp) return; if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) { - if (netif_running(bp->dev)) { - val = BNX2_DRV_ACK_CAP_SIGNATURE | - BNX2_FW_CAP_REMOTE_PHY_CAPABLE; - REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB, - val); - } bp->phy_flags |= REMOTE_PHY_CAP_FLAG; val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS); @@ -3789,6 +3783,22 @@ bnx2_init_remote_phy(struct bnx2 *bp) bp->phy_port = PORT_FIBRE; else bp->phy_port = PORT_TP; + + if (netif_running(bp->dev)) { + u32 sig; + + if (val & BNX2_LINK_STATUS_LINK_UP) { + bp->link_up = 1; + netif_carrier_on(bp->dev); + } else { + bp->link_up = 0; + netif_carrier_off(bp->dev); + } + sig = BNX2_DRV_ACK_CAP_SIGNATURE | + BNX2_FW_CAP_REMOTE_PHY_CAPABLE; + REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB, + sig); + } } } @@ -3797,6 +3807,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) { u32 val; int i, rc = 0; + u8 old_port; /* Wait for the current PCI transaction to complete before * issuing a reset. */ @@ -3875,8 +3886,9 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) return rc; spin_lock_bh(&bp->phy_lock); + old_port = bp->phy_port; bnx2_init_remote_phy(bp); - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if ((bp->phy_flags & REMOTE_PHY_CAP_FLAG) && old_port != bp->phy_port) bnx2_set_default_remote_link(bp); spin_unlock_bh(&bp->phy_lock); @@ -4565,6 +4577,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) bnx2_set_mac_loopback(bp); } else if (loopback_mode == BNX2_PHY_LOOPBACK) { + if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + return 0; + bp->loopback = PHY_LOOPBACK; bnx2_set_phy_loopback(bp); } @@ -4733,6 +4748,11 @@ bnx2_test_link(struct bnx2 *bp) { u32 bmsr; + if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) { + if (bp->link_up) + return 0; + return -ENODEV; + } spin_lock_bh(&bp->phy_lock); bnx2_enable_bmsr1(bp); bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); From 846f5c622fe033520c775cc2c40c06f3e2adea85 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 10 Oct 2007 16:16:51 -0700 Subject: [PATCH 1841/2804] [BNX2]: Fix default WoL setting. Change the default WoL setting to match the NVRAM's setting. It always defaulted to WoL disabled before and caused a lot of confusion for users. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 20 ++++++++++++++------ drivers/net/bnx2.h | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 21493e0cbd42..574d043cdfcd 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6569,8 +6569,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if (i != 2) bp->fw_version[j++] = '.'; } - if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) & - BNX2_PORT_FEATURE_ASF_ENABLED) { + reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE); + if (reg & BNX2_PORT_FEATURE_WOL_ENABLED) + bp->wol = 1; + + if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) { bp->flags |= ASF_ENABLE_FLAG; for (i = 0; i < 30; i++) { @@ -6640,11 +6643,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->phy_port = PORT_TP; if (bp->phy_flags & PHY_SERDES_FLAG) { bp->phy_port = PORT_FIBRE; - bp->flags |= NO_WOL_FLAG; + reg = REG_RD_IND(bp, bp->shmem_base + + BNX2_SHARED_HW_CFG_CONFIG); + if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) { + bp->flags |= NO_WOL_FLAG; + bp->wol = 0; + } if (CHIP_NUM(bp) != CHIP_NUM_5706) { bp->phy_addr = 2; - reg = REG_RD_IND(bp, bp->shmem_base + - BNX2_SHARED_HW_CFG_CONFIG); if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G) bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG; } @@ -6659,8 +6665,10 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || (CHIP_ID(bp) == CHIP_ID_5708_B0) || - (CHIP_ID(bp) == CHIP_ID_5708_B1)) + (CHIP_ID(bp) == CHIP_ID_5708_B1)) { bp->flags |= NO_WOL_FLAG; + bp->wol = 0; + } if (CHIP_ID(bp) == CHIP_ID_5706_A0) { bp->tx_quick_cons_trip_int = diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 56c190fc6de6..1dce0d1a2581 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6908,6 +6908,7 @@ struct fw_info { #define BNX2_SHARED_HW_CFG_LED_MODE_MAC 0 #define BNX2_SHARED_HW_CFG_LED_MODE_GPHY1 0x100 #define BNX2_SHARED_HW_CFG_LED_MODE_GPHY2 0x200 +#define BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX 0x8000 #define BNX2_SHARED_HW_CFG_CONFIG2 0x00000040 #define BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK 0x00fff000 From 32d1316b91424423d7b44944f18cdaca268f3db2 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 10 Oct 2007 16:17:11 -0700 Subject: [PATCH 1842/2804] [BNX2]: Update version to 1.6.7. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 574d043cdfcd..bbfbdafb4ae5 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.6" -#define DRV_MODULE_RELDATE "October 2, 2007" +#define DRV_MODULE_VERSION "1.6.7" +#define DRV_MODULE_RELDATE "October 10, 2007" #define RUN_AT(x) (jiffies + (x)) From 3c0cfc135829b98f7a4894938652f9ef78e24237 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 10 Oct 2007 16:32:41 -0700 Subject: [PATCH 1843/2804] [NET_SCHED]: Show timer resolution instead of clock resolution in /proc/net/psched The fourth parameter of /proc/net/psched is supposed to show the timer resultion and is used by HTB userspace to calculate the necessary burst rate. Currently we show the clock resolution, which results in a too low burst rate when the two differ. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_api.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 39d32780c80b..8ae137e3522b 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1226,10 +1226,13 @@ EXPORT_SYMBOL(tcf_destroy_chain); #ifdef CONFIG_PROC_FS static int psched_show(struct seq_file *seq, void *v) { + struct timespec ts; + + hrtimer_get_res(CLOCK_MONOTONIC, &ts); seq_printf(seq, "%08x %08x %08x %08x\n", (u32)NSEC_PER_USEC, (u32)PSCHED_US2NS(1), 1000000, - (u32)NSEC_PER_SEC/(u32)ktime_to_ns(KTIME_MONOTONIC_RES)); + (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts))); return 0; } From 06393009000779b00a558fd2f280882cc7dc2008 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 10 Oct 2007 17:30:18 -0700 Subject: [PATCH 1844/2804] [SCTP]: port randomization Add port randomization rather than a simple fixed rover for use with SCTP. This makes it act similar to TCP, UDP, DCCP when allocating ports. No longer need port_alloc_lock as well (suggestion by Brian Haley). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 2 -- net/sctp/protocol.c | 3 --- net/sctp/socket.c | 21 +++++---------------- 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 448f713a0205..ef892e00c833 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -197,8 +197,6 @@ extern struct sctp_globals { /* This is the sctp port control hash. */ int port_hashsize; - int port_rover; - spinlock_t port_alloc_lock; /* Protects port_rover. */ struct sctp_bind_hashbucket *port_hashtable; /* This is the global local address list. diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 4e6b59e8b695..81b26c5ffd4b 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1172,9 +1172,6 @@ SCTP_STATIC __init int sctp_init(void) sctp_port_hashtable[i].chain = NULL; } - spin_lock_init(&sctp_port_alloc_lock); - sctp_port_rover = sysctl_local_port_range[0] - 1; - printk(KERN_INFO "SCTP: Hash tables configured " "(established %d bind %d)\n", sctp_assoc_hashsize, sctp_port_hashsize); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index f3e1a9c811ad..7cd58ef84eda 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5314,22 +5314,13 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) sctp_local_bh_disable(); if (snum == 0) { - /* Search for an available port. - * - * 'sctp_port_rover' was the last port assigned, so - * we start to search from 'sctp_port_rover + - * 1'. What we do is first check if port 'rover' is - * already in the hash table; if not, we use that; if - * it is, we try next. - */ - int low = sysctl_local_port_range[0]; - int high = sysctl_local_port_range[1]; - int remaining = (high - low) + 1; - int rover; + /* Search for an available port. */ + unsigned int low = sysctl_local_port_range[0]; + unsigned int high = sysctl_local_port_range[1]; + unsigned int remaining = (high - low) + 1; + unsigned int rover = net_random() % remaining + low; int index; - sctp_spin_lock(&sctp_port_alloc_lock); - rover = sctp_port_rover; do { rover++; if ((rover < low) || (rover > high)) @@ -5344,8 +5335,6 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) next: sctp_spin_unlock(&head->lock); } while (--remaining > 0); - sctp_port_rover = rover; - sctp_spin_unlock(&sctp_port_alloc_lock); /* Exhausted local port range during search? */ ret = 1; From 227b60f5102cda4e4ab792b526a59c8cb20cd9f8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 10 Oct 2007 17:30:46 -0700 Subject: [PATCH 1845/2804] [INET]: local port range robustness Expansion of original idea from Denis V. Lunev Add robustness and locking to the local_port_range sysctl. 1. Enforce that low < high when setting. 2. Use seqlock to ensure atomic update. The locking might seem like overkill, but there are cases where sysadmin might want to change value in the middle of a DoS attack. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/infiniband/core/cma.c | 22 +++++----- include/net/ip.h | 3 +- net/ipv4/inet_connection_sock.c | 22 ++++++++-- net/ipv4/inet_hashtables.c | 13 +++--- net/ipv4/sysctl_net_ipv4.c | 75 +++++++++++++++++++++++++++++++-- net/ipv4/tcp_ipv4.c | 1 - net/ipv4/udp.c | 6 +-- net/ipv6/inet6_hashtables.c | 12 +++--- net/sctp/socket.c | 11 ++--- security/selinux/hooks.c | 39 +++++++++-------- 10 files changed, 146 insertions(+), 58 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9ffb9987450a..2e641b255db4 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1866,13 +1866,14 @@ err1: static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) { struct rdma_bind_list *bind_list; - int port, ret; + int port, ret, low, high; bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); if (!bind_list) return -ENOMEM; retry: + /* FIXME: add proper port randomization per like inet_csk_get_port */ do { ret = idr_get_new_above(ps, bind_list, next_port, &port); } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); @@ -1880,18 +1881,19 @@ retry: if (ret) goto err1; - if (port > sysctl_local_port_range[1]) { - if (next_port != sysctl_local_port_range[0]) { + inet_get_local_port_range(&low, &high); + if (port > high) { + if (next_port != low) { idr_remove(ps, port); - next_port = sysctl_local_port_range[0]; + next_port = low; goto retry; } ret = -EADDRNOTAVAIL; goto err2; } - if (port == sysctl_local_port_range[1]) - next_port = sysctl_local_port_range[0]; + if (port == high) + next_port = low; else next_port = port + 1; @@ -2769,12 +2771,12 @@ static void cma_remove_one(struct ib_device *device) static int cma_init(void) { - int ret; + int ret, low, high; get_random_bytes(&next_port, sizeof next_port); - next_port = ((unsigned int) next_port % - (sysctl_local_port_range[1] - sysctl_local_port_range[0])) + - sysctl_local_port_range[0]; + inet_get_local_port_range(&low, &high); + next_port = ((unsigned int) next_port % (high - low)) + low; + cma_wq = create_singlethread_workqueue("rdma_cm"); if (!cma_wq) return -ENOMEM; diff --git a/include/net/ip.h b/include/net/ip.h index abf2820a1125..3af3ed9d320b 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -171,7 +171,8 @@ extern unsigned long snmp_fold_field(void *mib[], int offt); extern int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign); extern void snmp_mib_free(void *ptr[2]); -extern int sysctl_local_port_range[2]; +extern void inet_get_local_port_range(int *low, int *high); + extern int sysctl_ip_default_ttl; extern int sysctl_ip_nonlocal_bind; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index fbe7714f21d0..3cef12835c4b 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -33,6 +33,19 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg); * This array holds the first and last local port number. */ int sysctl_local_port_range[2] = { 32768, 61000 }; +DEFINE_SEQLOCK(sysctl_port_range_lock); + +void inet_get_local_port_range(int *low, int *high) +{ + unsigned seq; + do { + seq = read_seqbegin(&sysctl_port_range_lock); + + *low = sysctl_local_port_range[0]; + *high = sysctl_local_port_range[1]; + } while (read_seqretry(&sysctl_port_range_lock, seq)); +} +EXPORT_SYMBOL(inet_get_local_port_range); int inet_csk_bind_conflict(const struct sock *sk, const struct inet_bind_bucket *tb) @@ -77,10 +90,11 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo, local_bh_disable(); if (!snum) { - int low = sysctl_local_port_range[0]; - int high = sysctl_local_port_range[1]; - int remaining = (high - low) + 1; - int rover = net_random() % (high - low) + low; + int remaining, rover, low, high; + + inet_get_local_port_range(&low, &high); + remaining = high - low; + rover = net_random() % remaining + low; do { head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)]; diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index fb662621c54e..fac6398e4367 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -279,19 +279,18 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row, int ret; if (!snum) { - int low = sysctl_local_port_range[0]; - int high = sysctl_local_port_range[1]; - int range = high - low; - int i; - int port; + int i, remaining, low, high, port; static u32 hint; u32 offset = hint + inet_sk_port_offset(sk); struct hlist_node *node; struct inet_timewait_sock *tw = NULL; + inet_get_local_port_range(&low, &high); + remaining = high - low; + local_bh_disable(); - for (i = 1; i <= range; i++) { - port = low + (i + offset) % range; + for (i = 1; i <= remaining; i++) { + port = low + (i + offset) % remaining; head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; spin_lock(&head->lock); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 53ef0f4bbdaa..eb286abcf5dc 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,74 @@ static int ipv4_sysctl_forward_strategy(ctl_table *table, return 1; } +extern seqlock_t sysctl_port_range_lock; +extern int sysctl_local_port_range[2]; + +/* Update system visible IP port range */ +static void set_local_port_range(int range[2]) +{ + write_seqlock(&sysctl_port_range_lock); + sysctl_local_port_range[0] = range[0]; + sysctl_local_port_range[1] = range[1]; + write_sequnlock(&sysctl_port_range_lock); +} + +/* Validate changes from /proc interface. */ +static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + int ret; + int range[2] = { sysctl_local_port_range[0], + sysctl_local_port_range[1] }; + ctl_table tmp = { + .data = &range, + .maxlen = sizeof(range), + .mode = table->mode, + .extra1 = &ip_local_port_range_min, + .extra2 = &ip_local_port_range_max, + }; + + ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos); + + if (write && ret == 0) { + if (range[1] <= range[0]) + ret = -EINVAL; + else + set_local_port_range(range); + } + + return ret; +} + +/* Validate changes from sysctl interface. */ +static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name, + int nlen, void __user *oldval, + size_t __user *oldlenp, + void __user *newval, size_t newlen) +{ + int ret; + int range[2] = { sysctl_local_port_range[0], + sysctl_local_port_range[1] }; + ctl_table tmp = { + .data = &range, + .maxlen = sizeof(range), + .mode = table->mode, + .extra1 = &ip_local_port_range_min, + .extra2 = &ip_local_port_range_max, + }; + + ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen); + if (ret == 0 && newval && newlen) { + if (range[1] <= range[0]) + ret = -EINVAL; + else + set_local_port_range(range); + } + return ret; +} + + static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -427,10 +496,8 @@ ctl_table ipv4_table[] = { .data = &sysctl_local_port_range, .maxlen = sizeof(sysctl_local_port_range), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = ip_local_port_range_min, - .extra2 = ip_local_port_range_max + .proc_handler = &ipv4_local_port_range, + .strategy = &ipv4_sysctl_local_port_range, }, { .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8855e640e958..38cf73a56731 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2470,6 +2470,5 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock); EXPORT_SYMBOL(tcp_proc_register); EXPORT_SYMBOL(tcp_proc_unregister); #endif -EXPORT_SYMBOL(sysctl_local_port_range); EXPORT_SYMBOL(sysctl_tcp_low_latency); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ef4d901ee9ad..cb9fc58efb2f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -147,11 +147,11 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, write_lock_bh(&udp_hash_lock); if (!snum) { - int i; - int low = sysctl_local_port_range[0]; - int high = sysctl_local_port_range[1]; + int i, low, high; unsigned rover, best, best_size_so_far; + inet_get_local_port_range(&low, &high); + best_size_so_far = UINT_MAX; best = rover = net_random() % (high - low) + low; diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index ae6b0e7eb488..1c2c27655435 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -254,18 +254,18 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row, int ret; if (snum == 0) { - const int low = sysctl_local_port_range[0]; - const int high = sysctl_local_port_range[1]; - const int range = high - low; - int i, port; + int i, port, low, high, remaining; static u32 hint; const u32 offset = hint + inet6_sk_port_offset(sk); struct hlist_node *node; struct inet_timewait_sock *tw = NULL; + inet_get_local_port_range(&low, &high); + remaining = high - low; + local_bh_disable(); - for (i = 1; i <= range; i++) { - port = low + (i + offset) % range; + for (i = 1; i <= remaining; i++) { + port = low + (i + offset) % remaining; head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; spin_lock(&head->lock); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 7cd58ef84eda..9c6a4b5f6264 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5315,11 +5315,12 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) if (snum == 0) { /* Search for an available port. */ - unsigned int low = sysctl_local_port_range[0]; - unsigned int high = sysctl_local_port_range[1]; - unsigned int remaining = (high - low) + 1; - unsigned int rover = net_random() % remaining + low; - int index; + int low, high, remaining, index; + unsigned int rover; + + inet_get_local_port_range(&low, &high); + remaining = (high - low) + 1; + rover = net_random() % remaining + low; do { rover++; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 0753b20e23fe..3c3fff33d1ce 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -47,7 +47,7 @@ #include #include #include -#include /* for sysctl_local_port_range[] */ +#include /* for local_port_range[] */ #include /* struct or_callable used in sock_rcv_skb */ #include #include @@ -3232,8 +3232,6 @@ static int selinux_socket_post_create(struct socket *sock, int family, /* Range of port numbers used to automatically bind. Need to determine whether we should perform a name_bind permission check between the socket and the port number. */ -#define ip_local_port_range_0 sysctl_local_port_range[0] -#define ip_local_port_range_1 sysctl_local_port_range[1] static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { @@ -3276,20 +3274,27 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in addrp = (char *)&addr6->sin6_addr.s6_addr; } - if (snum&&(snum < max(PROT_SOCK,ip_local_port_range_0) || - snum > ip_local_port_range_1)) { - err = security_port_sid(sk->sk_family, sk->sk_type, - sk->sk_protocol, snum, &sid); - if (err) - goto out; - AVC_AUDIT_DATA_INIT(&ad,NET); - ad.u.net.sport = htons(snum); - ad.u.net.family = family; - err = avc_has_perm(isec->sid, sid, - isec->sclass, - SOCKET__NAME_BIND, &ad); - if (err) - goto out; + if (snum) { + int low, high; + + inet_get_local_port_range(&low, &high); + + if (snum < max(PROT_SOCK, low) || snum > high) { + err = security_port_sid(sk->sk_family, + sk->sk_type, + sk->sk_protocol, snum, + &sid); + if (err) + goto out; + AVC_AUDIT_DATA_INIT(&ad,NET); + ad.u.net.sport = htons(snum); + ad.u.net.family = family; + err = avc_has_perm(isec->sid, sid, + isec->sclass, + SOCKET__NAME_BIND, &ad); + if (err) + goto out; + } } switch(isec->sclass) { From 6b91fa02796292c322b20572188c74c1ef5bb02b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:01:09 -0700 Subject: [PATCH 1846/2804] [TG3]: Add new 5761 NVRAM decode routines This patch adds a new 5761-specific NVRAM strapping decode routine. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/tg3.h | 25 +++++++++++++-- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1e0c9e0dc394..3200c9c5ff5e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9581,6 +9581,81 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) } } +static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1, protect = 0; + + nvcfg1 = tr32(NVRAM_CFG1); + + /* NVRAM protection for TPM */ + if (nvcfg1 & (1 << 27)) { + tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM; + protect = 1; + } + + 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; + } + + 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 = 0x100000; + 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 = 0x80000; + 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 = 0x40000; + 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 = 0x20000; + break; + } + } +} + static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp) { tp->nvram_jedecnum = JEDEC_ATMEL; @@ -9623,6 +9698,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) tg3_get_5787_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + tg3_get_5761_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_get_5906_nvram_info(tp); else @@ -9700,6 +9777,7 @@ static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) if ((tp->tg3_flags & TG3_FLAG_NVRAM) && (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && (tp->tg3_flags2 & TG3_FLG2_FLASH) && + !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && (tp->nvram_jedecnum == JEDEC_ATMEL)) addr = ((addr / tp->nvram_pagesize) << @@ -9714,6 +9792,7 @@ static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr) if ((tp->tg3_flags & TG3_FLAG_NVRAM) && (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && (tp->tg3_flags2 & TG3_FLG2_FLASH) && + !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && (tp->nvram_jedecnum == JEDEC_ATMEL)) addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) * diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d8e829f6fcb2..88d08f3ede03 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -124,6 +124,7 @@ #define ASIC_REV_5906 0x0c #define ASIC_REV_USE_PROD_ID_REG 0x0f #define ASIC_REV_5784 0x5784 +#define ASIC_REV_5761 0x5761 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -1463,6 +1464,22 @@ #define FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ 0x03000002 #define FLASH_5787VENDOR_MICRO_EEPROM_64KHZ 0x03000000 #define FLASH_5787VENDOR_MICRO_EEPROM_376KHZ 0x02000000 +#define FLASH_5761VENDOR_ATMEL_MDB021D 0x00800003 +#define FLASH_5761VENDOR_ATMEL_MDB041D 0x00800000 +#define FLASH_5761VENDOR_ATMEL_MDB081D 0x00800002 +#define FLASH_5761VENDOR_ATMEL_MDB161D 0x00800001 +#define FLASH_5761VENDOR_ATMEL_ADB021D 0x00000003 +#define FLASH_5761VENDOR_ATMEL_ADB041D 0x00000000 +#define FLASH_5761VENDOR_ATMEL_ADB081D 0x00000002 +#define FLASH_5761VENDOR_ATMEL_ADB161D 0x00000001 +#define FLASH_5761VENDOR_ST_M_M45PE20 0x02800001 +#define FLASH_5761VENDOR_ST_M_M45PE40 0x02800000 +#define FLASH_5761VENDOR_ST_M_M45PE80 0x02800002 +#define FLASH_5761VENDOR_ST_M_M45PE16 0x02800003 +#define FLASH_5761VENDOR_ST_A_M45PE20 0x02000001 +#define FLASH_5761VENDOR_ST_A_M45PE40 0x02000000 +#define FLASH_5761VENDOR_ST_A_M45PE80 0x02000002 +#define FLASH_5761VENDOR_ST_A_M45PE16 0x02000003 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 @@ -1493,9 +1510,11 @@ #define ACCESS_ENABLE 0x00000001 #define ACCESS_WR_ENABLE 0x00000002 #define NVRAM_WRITE1 0x00007028 -/* 0x702c --> 0x7400 unused */ +/* 0x702c unused */ + +#define NVRAM_ADDR_LOCKOUT 0x00007030 +/* 0x7034 --> 0x7c00 unused */ -/* 0x7400 --> 0x7c00 unused */ #define PCIE_TRANSACTION_CFG 0x00007c04 #define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000 #define PCIE_TRANS_CFG_LOM 0x00000020 @@ -2269,6 +2288,8 @@ struct tg3 { #define TG3_FLG2_PHY_JITTER_BUG 0x20000000 #define TG3_FLG2_NO_FWARE_REPORTED 0x40000000 #define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000 + u32 tg3_flags3; +#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001 struct timer_list timer; u16 timer_counter; From 0d3031d9e674cddd4c09731123ad252294cdf15f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:02:43 -0700 Subject: [PATCH 1847/2804] [TG3]: Add 5761 APE support This patch adds support for the new APE block, present in 5761 chips. APE stands for Application Processing Engine. The primary function of the APE is to process manageability traffic, such as ASF. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 232 +++++++++++++++++++++++++++++++++++++++++++++- drivers/net/tg3.h | 46 +++++++++ 2 files changed, 274 insertions(+), 4 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3200c9c5ff5e..5b6c1b286e92 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -314,6 +314,16 @@ static u32 tg3_read32(struct tg3 *tp, u32 off) return (readl(tp->regs + off)); } +static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val) +{ + writel(val, tp->aperegs + off); +} + +static u32 tg3_ape_read32(struct tg3 *tp, u32 off) +{ + return (readl(tp->aperegs + off)); +} + static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) { unsigned long flags; @@ -500,6 +510,73 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) spin_unlock_irqrestore(&tp->indirect_lock, flags); } +static void tg3_ape_lock_init(struct tg3 *tp) +{ + int i; + + /* Make sure the driver hasn't any stale locks. */ + for (i = 0; i < 8; i++) + tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i, + APE_LOCK_GRANT_DRIVER); +} + +static int tg3_ape_lock(struct tg3 *tp, int locknum) +{ + int i, off; + int ret = 0; + u32 status; + + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + return 0; + + switch (locknum) { + case TG3_APE_LOCK_MEM: + break; + default: + return -EINVAL; + } + + off = 4 * locknum; + + tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER); + + /* Wait for up to 1 millisecond to acquire lock. */ + for (i = 0; i < 100; i++) { + status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off); + if (status == APE_LOCK_GRANT_DRIVER) + break; + udelay(10); + } + + if (status != APE_LOCK_GRANT_DRIVER) { + /* Revoke the lock request. */ + tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, + APE_LOCK_GRANT_DRIVER); + + ret = -EBUSY; + } + + return ret; +} + +static void tg3_ape_unlock(struct tg3 *tp, int locknum) +{ + int off; + + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + return; + + switch (locknum) { + case TG3_APE_LOCK_MEM: + break; + default: + return; + } + + off = 4 * locknum; + tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER); +} + static void tg3_disable_ints(struct tg3 *tp) { tw32(TG3PCI_MISC_HOST_CTRL, @@ -1448,7 +1525,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && + !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) tg3_power_down_phy(tp); tg3_frob_aux_power(tp); @@ -4726,6 +4804,80 @@ static void tg3_disable_nvram_access(struct tg3 *tp) } } +static void tg3_ape_send_event(struct tg3 *tp, u32 event) +{ + int i; + u32 apedata; + + apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG); + if (apedata != APE_SEG_SIG_MAGIC) + return; + + apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS); + if (apedata != APE_FW_STATUS_READY) + return; + + /* Wait for up to 1 millisecond for APE to service previous event. */ + for (i = 0; i < 10; i++) { + if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM)) + return; + + apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS); + + if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING)) + tg3_ape_write32(tp, TG3_APE_EVENT_STATUS, + event | APE_EVENT_STATUS_EVENT_PENDING); + + tg3_ape_unlock(tp, TG3_APE_LOCK_MEM); + + if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING)) + break; + + udelay(100); + } + + if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING)) + tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1); +} + +static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) +{ + u32 event; + u32 apedata; + + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + return; + + switch (kind) { + case RESET_KIND_INIT: + tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, + APE_HOST_SEG_SIG_MAGIC); + tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN, + APE_HOST_SEG_LEN_MAGIC); + apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT); + tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata); + tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID, + APE_HOST_DRIVER_ID_MAGIC); + tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR, + APE_HOST_BEHAV_NO_PHYLOCK); + + event = APE_EVENT_STATUS_STATE_START; + break; + case RESET_KIND_SHUTDOWN: + event = APE_EVENT_STATUS_STATE_UNLOAD; + break; + case RESET_KIND_SUSPEND: + event = APE_EVENT_STATUS_STATE_SUSPEND; + break; + default: + return; + } + + event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE; + + tg3_ape_send_event(tp, event); +} + /* tp->lock is held. */ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) { @@ -4753,6 +4905,10 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) break; }; } + + if (kind == RESET_KIND_INIT || + kind == RESET_KIND_SUSPEND) + tg3_ape_driver_state_change(tp, kind); } /* tp->lock is held. */ @@ -4774,6 +4930,9 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind) break; }; } + + if (kind == RESET_KIND_SHUTDOWN) + tg3_ape_driver_state_change(tp, kind); } /* tp->lock is held. */ @@ -4864,6 +5023,10 @@ static void tg3_restore_pci_state(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) val |= PCISTATE_RETRY_SAME_DMA; + /* Allow reads and writes to the APE register and memory space. */ + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + val |= PCISTATE_ALLOW_APE_CTLSPC_WR | + PCISTATE_ALLOW_APE_SHMEM_WR; pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val); pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd); @@ -5092,7 +5255,8 @@ static int tg3_chip_reset(struct tg3 *tp) /* tp->lock is held. */ static void tg3_stop_fw(struct tg3 *tp) { - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && + !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { u32 val; int i; @@ -6173,6 +6337,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3PCI_PCISTATE, val); } + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + /* Allow reads and writes to the + * APE register and memory space. + */ + val = tr32(TG3PCI_PCISTATE); + val |= PCISTATE_ALLOW_APE_CTLSPC_WR | + PCISTATE_ALLOW_APE_SHMEM_WR; + tw32(TG3PCI_PCISTATE, val); + } + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) { /* Enable some hw fixes. */ val = tr32(TG3PCI_MSI_DATA); @@ -6780,6 +6954,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) break; }; + /* Write our heartbeat update interval to APE. */ + tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, + APE_HOST_HEARTBEAT_INT_DISABLE); + tg3_write_sig_post_reset(tp, RESET_KIND_INIT); return 0; @@ -10302,6 +10480,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } + if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) + tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE; if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES && !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; @@ -10334,7 +10514,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) * firwmare access to the PHY hardware. */ err = 0; - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || + (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID; } else { /* Now read the physical PHY_ID from the chip and verify @@ -10381,6 +10562,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) } if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) && + !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) && !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { u32 bmsr, adv_reg, tg3_ctrl, mask; @@ -10972,6 +11154,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tg3_get_eeprom_hw_cfg(tp); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + /* Allow reads and writes to the + * APE register and memory space. + */ + pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR | + PCISTATE_ALLOW_APE_SHMEM_WR; + pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, + pci_state_reg); + } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; @@ -12165,13 +12357,35 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_init_coal(tp); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + printk(KERN_ERR PFX "Cannot find proper PCI device " + "base address for APE, aborting.\n"); + err = -ENODEV; + goto err_out_iounmap; + } + + tg3reg_base = pci_resource_start(pdev, 2); + tg3reg_len = pci_resource_len(pdev, 2); + + tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len); + if (tp->aperegs == 0UL) { + printk(KERN_ERR PFX "Cannot map APE registers, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_iounmap; + } + + tg3_ape_lock_init(tp); + } + pci_set_drvdata(pdev, dev); err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register net device, " "aborting.\n"); - goto err_out_iounmap; + goto err_out_apeunmap; } printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ", @@ -12204,6 +12418,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, return 0; +err_out_apeunmap: + if (tp->aperegs) { + iounmap(tp->aperegs); + tp->aperegs = NULL; + } + err_out_iounmap: if (tp->regs) { iounmap(tp->regs); @@ -12231,6 +12451,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) flush_scheduled_work(); unregister_netdev(dev); + if (tp->aperegs) { + iounmap(tp->aperegs); + tp->aperegs = NULL; + } if (tp->regs) { iounmap(tp->regs); tp->regs = NULL; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 88d08f3ede03..632c2f084c52 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -192,6 +192,8 @@ #define PCISTATE_ROM_RETRY_ENABLE 0x00000040 #define PCISTATE_FLAT_VIEW 0x00000100 #define PCISTATE_RETRY_SAME_DMA 0x00002000 +#define PCISTATE_ALLOW_APE_CTLSPC_WR 0x00010000 +#define PCISTATE_ALLOW_APE_SHMEM_WR 0x00020000 #define TG3PCI_CLOCK_CTRL 0x00000074 #define CLOCK_CTRL_CORECLK_DISABLE 0x00000200 #define CLOCK_CTRL_RXCLK_DISABLE 0x00000400 @@ -1560,6 +1562,7 @@ #define NIC_SRAM_DATA_CFG_MINI_PCI 0x00001000 #define NIC_SRAM_DATA_CFG_FIBER_WOL 0x00004000 #define NIC_SRAM_DATA_CFG_NO_GPIO2 0x00100000 +#define NIC_SRAM_DATA_CFG_APE_ENABLE 0x00200000 #define NIC_SRAM_DATA_VER 0x00000b5c #define NIC_SRAM_DATA_VER_SHIFT 16 @@ -1688,6 +1691,47 @@ #define MII_TG3_TEST1_TRIM_EN 0x0010 #define MII_TG3_TEST1_CRC_EN 0x8000 +/* APE registers. Accessible through BAR1 */ +#define TG3_APE_EVENT 0x000c +#define APE_EVENT_1 0x00000001 +#define TG3_APE_LOCK_REQ 0x002c +#define APE_LOCK_REQ_DRIVER 0x00001000 +#define TG3_APE_LOCK_GRANT 0x004c +#define APE_LOCK_GRANT_DRIVER 0x00001000 +#define TG3_APE_SEG_SIG 0x4000 +#define APE_SEG_SIG_MAGIC 0x41504521 + +/* APE shared memory. Accessible through BAR1 */ +#define TG3_APE_FW_STATUS 0x400c +#define APE_FW_STATUS_READY 0x00000100 +#define TG3_APE_HOST_SEG_SIG 0x4200 +#define APE_HOST_SEG_SIG_MAGIC 0x484f5354 +#define TG3_APE_HOST_SEG_LEN 0x4204 +#define APE_HOST_SEG_LEN_MAGIC 0x0000001c +#define TG3_APE_HOST_INIT_COUNT 0x4208 +#define TG3_APE_HOST_DRIVER_ID 0x420c +#define APE_HOST_DRIVER_ID_MAGIC 0xf0035100 +#define TG3_APE_HOST_BEHAVIOR 0x4210 +#define APE_HOST_BEHAV_NO_PHYLOCK 0x00000001 +#define TG3_APE_HOST_HEARTBEAT_INT_MS 0x4214 +#define APE_HOST_HEARTBEAT_INT_DISABLE 0 +#define APE_HOST_HEARTBEAT_INT_5SEC 5000 +#define TG3_APE_HOST_HEARTBEAT_COUNT 0x4218 + +#define TG3_APE_EVENT_STATUS 0x4300 + +#define APE_EVENT_STATUS_DRIVER_EVNT 0x00000010 +#define APE_EVENT_STATUS_STATE_CHNGE 0x00000500 +#define APE_EVENT_STATUS_STATE_START 0x00010000 +#define APE_EVENT_STATUS_STATE_UNLOAD 0x00020000 +#define APE_EVENT_STATUS_STATE_WOL 0x00030000 +#define APE_EVENT_STATUS_STATE_SUSPEND 0x00040000 +#define APE_EVENT_STATUS_EVENT_PENDING 0x80000000 + +/* APE convenience enumerations. */ +#define TG3_APE_LOCK_MEM 4 + + /* There are two ways to manage the TX descriptors on the tigon3. * Either the descriptors are in host DMA'able memory, or they * exist only in the cards on-chip SRAM. All 16 send bds are under @@ -2163,6 +2207,7 @@ struct tg3 { void (*write32_mbox) (struct tg3 *, u32, u32); void __iomem *regs; + void __iomem *aperegs; struct net_device *dev; struct pci_dev *pdev; @@ -2290,6 +2335,7 @@ struct tg3 { #define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000 u32 tg3_flags3; #define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001 +#define TG3_FLG3_ENABLE_APE 0x00000002 struct timer_list timer; u16 timer_counter; From 9936bcf68a7e4d33f080bba9ee03d156c75c91ee Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:03:07 -0700 Subject: [PATCH 1848/2804] [TG3]: Add 5761 support This patch adds rest of the miscellaneous code required to support the 5761. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 86 ++++++++++++++++++++++++++++++++++------- drivers/net/tg3.h | 14 ++++++- include/linux/pci_ids.h | 2 + 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5b6c1b286e92..65aeca8e5147 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -200,6 +200,8 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, {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)}, @@ -5087,7 +5089,8 @@ static int tg3_chip_reset(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || 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) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) tw32(GRC_FASTBOOT_PC, 0); /* @@ -6363,7 +6366,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -6769,7 +6773,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Enable host coalescing bug fix */ 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)) + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)) val |= (1 << 29); tw32_f(WDMAC_MODE, val); @@ -6797,7 +6802,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) tw32(MBFREE_MODE, MBFREE_MODE_ENABLE); - tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + tw32(SNDDATAC_MODE, + SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY); + else + tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE); + tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE); tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ); @@ -6824,7 +6835,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(100); tp->rx_mode = RX_MODE_ENABLE; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; tw32_f(MAC_RX_MODE, tp->rx_mode); @@ -8368,10 +8380,12 @@ static int tg3_set_tso(struct net_device *dev, u32 value) } if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) { - if (value) + if (value) { dev->features |= NETIF_F_TSO6; - else - dev->features &= ~NETIF_F_TSO6; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + dev->features |= NETIF_F_TSO_ECN; + } else + dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); } return ethtool_op_set_tso(dev, value); } @@ -8550,7 +8564,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) 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) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) ethtool_op_set_tx_ipv6_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -9047,7 +9062,8 @@ static int tg3_test_memory(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { 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) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; @@ -9244,6 +9260,7 @@ out: static int tg3_test_loopback(struct tg3 *tp) { int err = 0; + u32 cpmuctrl = 0; if (!netif_running(tp->dev)) return TG3_LOOPBACK_FAILED; @@ -9252,8 +9269,40 @@ static int tg3_test_loopback(struct tg3 *tp) if (err) return TG3_LOOPBACK_FAILED; + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { + int i; + u32 status; + + tw32(TG3_CPMU_MUTEX_REQ, CPMU_MUTEX_REQ_DRIVER); + + /* Wait for up to 40 microseconds to acquire lock. */ + for (i = 0; i < 4; i++) { + status = tr32(TG3_CPMU_MUTEX_GNT); + if (status == CPMU_MUTEX_GNT_DRIVER) + break; + udelay(10); + } + + if (status != CPMU_MUTEX_GNT_DRIVER) + return TG3_LOOPBACK_FAILED; + + cpmuctrl = tr32(TG3_CPMU_CTRL); + + /* Turn off power management based on link speed. */ + tw32(TG3_CPMU_CTRL, + cpmuctrl & ~CPMU_CTRL_LINK_SPEED_MODE); + } + if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK)) err |= TG3_MAC_LOOPBACK_FAILED; + + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { + tw32(TG3_CPMU_CTRL, cpmuctrl); + + /* Release the mutex */ + tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER); + } + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK)) err |= TG3_PHY_LOOPBACK_FAILED; @@ -10192,6 +10241,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, (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) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -10941,6 +10991,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) 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 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -10961,6 +11012,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) 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 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; @@ -10979,6 +11031,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) 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 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; @@ -11164,7 +11217,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_state_reg); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). @@ -11234,7 +11288,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { 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) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) { if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 && tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; @@ -11378,6 +11433,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) 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 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->dev->hard_start_xmit = tg3_start_xmit; else @@ -12002,6 +12058,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5784: return "5784"; case PHY_ID_BCM5756: return "5722/5756"; case PHY_ID_BCM5906: return "5906"; + case PHY_ID_BCM5761: return "5761"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; @@ -12304,6 +12361,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) dev->features |= NETIF_F_TSO6; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + dev->features |= NETIF_F_TSO_ECN; } @@ -12345,7 +12404,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; 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) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) dev->features |= NETIF_F_IPV6_CSUM; tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 632c2f084c52..d1f5fa394ea7 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -666,6 +666,7 @@ #define SNDDATAC_MODE 0x00001000 #define SNDDATAC_MODE_RESET 0x00000001 #define SNDDATAC_MODE_ENABLE 0x00000002 +#define SNDDATAC_MODE_CDELAY 0x00000010 /* 0x1004 --> 0x1400 unused */ /* Send BD ring selector */ @@ -854,7 +855,14 @@ #define TG3_CPMU_CTRL 0x00003600 #define CPMU_CTRL_LINK_IDLE_MODE 0x00000200 #define CPMU_CTRL_LINK_AWARE_MODE 0x00000400 -/* 0x3604 --> 0x3800 unused */ +#define CPMU_CTRL_LINK_SPEED_MODE 0x00004000 +/* 0x3604 --> 0x365c unused */ + +#define TG3_CPMU_MUTEX_REQ 0x0000365c +#define CPMU_MUTEX_REQ_DRIVER 0x00001000 +#define TG3_CPMU_MUTEX_GNT 0x00003660 +#define CPMU_MUTEX_GNT_DRIVER 0x00001000 +/* 0x3664 --> 0x3800 unused */ /* Mbuf cluster free registers */ #define MBFREE_MODE 0x00003800 @@ -2394,6 +2402,7 @@ struct tg3 { #define PHY_ID_BCM5787 0xbc050ce0 #define PHY_ID_BCM5756 0xbc050ed0 #define PHY_ID_BCM5784 0xbc050fa0 +#define PHY_ID_BCM5761 0xbc050fd0 #define PHY_ID_BCM5906 0xdc00ac40 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2423,7 +2432,8 @@ struct tg3 { (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \ - (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \ + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6f5fa39c8290..27363bf29791 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1950,6 +1950,8 @@ #define PCI_DEVICE_ID_TIGON3_5751M 0x167d #define PCI_DEVICE_ID_TIGON3_5751F 0x167e #define PCI_DEVICE_ID_TIGON3_5787F 0x167f +#define PCI_DEVICE_ID_TIGON3_5761E 0x1680 +#define PCI_DEVICE_ID_TIGON3_5761 0x1681 #define PCI_DEVICE_ID_TIGON3_5764 0x1684 #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 From 0527ba358aa7594731e627842d493ae7f009dd57 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:03:30 -0700 Subject: [PATCH 1849/2804] [TG3]: WOL defaults This patch enables WOL by default if out-of-box WOL is enabled in the NVRAM. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 15 +++++++++------ drivers/net/tg3.h | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 65aeca8e5147..0eec84382b56 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10412,8 +10412,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; tp->tg3_flags2 |= TG3_FLG2_IS_NIC; } - if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC) + val = tr32(VCPU_CFGSHDW); + if (val & VCPU_CFGSHDW_ASPM_DBNC) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; + if ((val & VCPU_CFGSHDW_WOL_ENABLE) && + (val & VCPU_CFGSHDW_WOL_MAGPKT)) + tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; return; } @@ -10536,6 +10540,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; + if (tp->tg3_flags & TG3_FLAG_WOL_CAP && + nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) + tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + if (cfg2 & (1 << 17)) tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING; @@ -11454,11 +11462,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tp->rx_std_max_post = 8; - /* By default, disable wake-on-lan. User can change this - * using ETHTOOL_SWOL. - */ - tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; - if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) & PCIE_PWR_MGMT_L1_THRESH_MSK; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d1f5fa394ea7..6dbdad2b8f88 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1151,6 +1151,8 @@ #define VCPU_STATUS_DRV_RESET 0x08000000 #define VCPU_CFGSHDW 0x00005104 +#define VCPU_CFGSHDW_WOL_ENABLE 0x00000001 +#define VCPU_CFGSHDW_WOL_MAGPKT 0x00000004 #define VCPU_CFGSHDW_ASPM_DBNC 0x00001000 /* Mailboxes */ From 414c66e00e9fb4572e38bd14e6cc570eae8c5a61 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:03:56 -0700 Subject: [PATCH 1850/2804] [TG3]: Update version to 3.83 Update to version 3.83. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0eec84382b56..d2b30fb0b318 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.82" -#define DRV_MODULE_RELDATE "October 5, 2007" +#define DRV_MODULE_VERSION "3.83" +#define DRV_MODULE_RELDATE "October 10, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 From fa8705b00aeca19d91a1437b8a5cf865999b28f6 Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Wed, 10 Oct 2007 21:09:04 -0700 Subject: [PATCH 1851/2804] [NET]: sanitize kernel_accept() error path If kernel_accept() returns an error, it may pass back a pointer to freed memory (which the caller should ignore). Make it pass back NULL instead for better safety. Signed-off-by: Tony Battersby Signed-off-by: David S. Miller --- net/socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/socket.c b/net/socket.c index d2336472f494..379b3a390755 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2235,6 +2235,7 @@ int kernel_accept(struct socket *sock, struct socket **newsock, int flags) err = sock->ops->accept(sock, *newsock, flags); if (err < 0) { sock_release(*newsock); + *newsock = NULL; goto done; } From d1ec3b772233826bf156284170632563790dbabf Mon Sep 17 00:00:00 2001 From: Pierre Ynard Date: Wed, 10 Oct 2007 21:09:48 -0700 Subject: [PATCH 1852/2804] [NETLINK]: Fix typos in comments in netlink.h This patch fixes a few typos in comments in include/net/netlink.h Signed-off-by: Pierre Ynard Signed-off-by: David S. Miller --- include/net/netlink.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 83113dfcbd04..1afd3e837d23 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -84,7 +84,7 @@ * nla_next(nla)-----------------------------' * * Data Structures: - * struct nlattr netlink attribtue header + * struct nlattr netlink attribute header * * Attribute Construction: * nla_reserve(skb, type, len) reserve room for an attribute @@ -706,7 +706,7 @@ static inline int nla_ok(const struct nlattr *nla, int remaining) } /** - * nla_next - next netlink attribte in attribute stream + * nla_next - next netlink attribute in attribute stream * @nla: netlink attribute * @remaining: number of bytes remaining in attribute stream * @@ -782,7 +782,7 @@ static inline int __nla_parse_nested_compat(struct nlattr *tb[], int maxtype, ({ data = nla_len(nla) >= len ? nla_data(nla) : NULL; \ __nla_parse_nested_compat(tb, maxtype, nla, policy, len); }) /** - * nla_put_u8 - Add a u16 netlink attribute to a socket buffer + * nla_put_u8 - Add a u8 netlink attribute to a socket buffer * @skb: socket buffer to add attribute to * @attrtype: attribute type * @value: numeric value @@ -998,7 +998,7 @@ static inline struct nlattr *nla_nest_start(struct sk_buff *skb, int attrtype) /** * nla_nest_end - Finalize nesting of attributes - * @skb: socket buffer the attribtues are stored in + * @skb: socket buffer the attributes are stored in * @start: container attribute * * Corrects the container attribute header to include the all @@ -1041,7 +1041,7 @@ static inline struct nlattr *nla_nest_compat_start(struct sk_buff *skb, /** * nla_nest_compat_end - Finalize nesting of compat attributes - * @skb: socket buffer the attribtues are stored in + * @skb: socket buffer the attributes are stored in * @start: container attribute * * Corrects the container attribute header to include the all From 1536cc0d55a2820b71daf912060fe43ec15630c2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 10 Oct 2007 21:12:58 -0700 Subject: [PATCH 1853/2804] [NET]: rtnl_unlock cleanups There is no need to process outstanding netlink user->kernel packets during rtnl_unlock now. There is no rtnl_trylock in the rtnetlink_rcv anymore. Normal code path is the following: netlink_sendmsg netlink_unicast netlink_sendskb skb_queue_tail netlink_data_ready rtnetlink_rcv mutex_lock(&rtnl_mutex); netlink_run_queue(sk, qlen, &rtnetlink_rcv_msg); mutex_unlock(&rtnl_mutex); So, it is possible, that packets can be present in the rtnl->sk_receive_queue during rtnl_unlock, but there is no need to process them at that moment as rtnetlink_rcv for that packet is pending. Signed-off-by: Denis V. Lunev Acked-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 739fbad15c6a..471d2d9f8eae 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -75,8 +75,6 @@ void __rtnl_unlock(void) void rtnl_unlock(void) { mutex_unlock(&rtnl_mutex); - if (rtnl && rtnl->sk_receive_queue.qlen) - rtnl->sk_data_ready(rtnl, 0); netdev_run_todo(); } @@ -1319,11 +1317,9 @@ static void rtnetlink_rcv(struct sock *sk, int len) unsigned int qlen = 0; do { - mutex_lock(&rtnl_mutex); + rtnl_lock(); qlen = netlink_run_queue(sk, qlen, &rtnetlink_rcv_msg); - mutex_unlock(&rtnl_mutex); - - netdev_run_todo(); + rtnl_unlock(); } while (qlen); } From 3b71535f357a2e5d013a44a06b0c26a6a8d8fb5b Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 10 Oct 2007 21:13:32 -0700 Subject: [PATCH 1854/2804] [NET]: Make netlink processing routines semi-synchronious (inspired by rtnl) v2 The code in netfilter/nfnetlink.c and in ./net/netlink/genetlink.c looks like outdated copy/paste from rtnetlink.c. Push them into sync with the original. Changes from v1: - deleted comment in nfnetlink_rcv_msg by request of Patrick McHardy Signed-off-by: Denis V. Lunev Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink.c | 25 +++++-------------------- net/netlink/genetlink.c | 15 +++------------ 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index cb41990f92e0..99775af19ff4 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -44,28 +44,16 @@ static struct sock *nfnl = NULL; static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; static DEFINE_MUTEX(nfnl_mutex); -static void nfnl_lock(void) +static inline void nfnl_lock(void) { mutex_lock(&nfnl_mutex); } -static int nfnl_trylock(void) -{ - return !mutex_trylock(&nfnl_mutex); -} - -static void __nfnl_unlock(void) +static inline void nfnl_unlock(void) { mutex_unlock(&nfnl_mutex); } -static void nfnl_unlock(void) -{ - mutex_unlock(&nfnl_mutex); - if (nfnl->sk_receive_queue.qlen) - nfnl->sk_data_ready(nfnl, 0); -} - int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n) { nfnl_lock(); @@ -147,9 +135,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ss = nfnetlink_get_subsys(type); if (!ss) { #ifdef CONFIG_KMOD - /* don't call nfnl_unlock, since it would reenter - * with further packet processing */ - __nfnl_unlock(); + nfnl_unlock(); request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); nfnl_lock(); ss = nfnetlink_get_subsys(type); @@ -188,10 +174,9 @@ static void nfnetlink_rcv(struct sock *sk, int len) unsigned int qlen = 0; do { - if (nfnl_trylock()) - return; + nfnl_lock(); qlen = netlink_run_queue(sk, qlen, nfnetlink_rcv_msg); - __nfnl_unlock(); + nfnl_unlock(); } while (qlen); } diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 07ef5d204a0f..3f1104dc128b 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -22,22 +22,14 @@ struct sock *genl_sock = NULL; static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ -static void genl_lock(void) +static inline void genl_lock(void) { mutex_lock(&genl_mutex); } -static int genl_trylock(void) -{ - return !mutex_trylock(&genl_mutex); -} - -static void genl_unlock(void) +static inline void genl_unlock(void) { mutex_unlock(&genl_mutex); - - if (genl_sock && genl_sock->sk_receive_queue.qlen) - genl_sock->sk_data_ready(genl_sock, 0); } #define GENL_FAM_TAB_SIZE 16 @@ -483,8 +475,7 @@ static void genl_rcv(struct sock *sk, int len) unsigned int qlen = 0; do { - if (genl_trylock()) - return; + genl_lock(); qlen = netlink_run_queue(sk, qlen, genl_rcv_msg); genl_unlock(); } while (qlen && genl_sock && genl_sock->sk_receive_queue.qlen); From 7ee015e0fa3c856416e9477aac4b850ec6f09017 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 10 Oct 2007 21:14:03 -0700 Subject: [PATCH 1855/2804] [NET]: cleanup 3rd argument in netlink_sendskb netlink_sendskb does not use third argument. Clean it and save a couple of bytes. Signed-off-by: Denis V. Lunev Acked-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- include/linux/netlink.h | 2 +- ipc/mqueue.c | 5 ++--- net/netlink/af_netlink.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index e638256ce472..7b552b6c2c19 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -194,7 +194,7 @@ struct sock *netlink_getsockbyfilp(struct file *filp); int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long timeo, struct sock *ssk); void netlink_detachskb(struct sock *sk, struct sk_buff *skb); -int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); +int netlink_sendskb(struct sock *sk, struct sk_buff *skb); /* * skb should fit one page. This choice is good for headerless malloc. diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 145d5a0d299f..24df3347ad4b 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -521,8 +521,7 @@ static void __do_notify(struct mqueue_inode_info *info) break; case SIGEV_THREAD: set_cookie(info->notify_cookie, NOTIFY_WOKENUP); - netlink_sendskb(info->notify_sock, - info->notify_cookie, 0); + netlink_sendskb(info->notify_sock, info->notify_cookie); break; } /* after notification unregisters process */ @@ -568,7 +567,7 @@ static void remove_notification(struct mqueue_inode_info *info) if (info->notify_owner != NULL && info->notify.sigev_notify == SIGEV_THREAD) { set_cookie(info->notify_cookie, NOTIFY_REMOVED); - netlink_sendskb(info->notify_sock, info->notify_cookie, 0); + netlink_sendskb(info->notify_sock, info->notify_cookie); } put_pid(info->notify_owner); info->notify_owner = NULL; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index f934f54fbfd5..a5bd63ca86bc 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -791,7 +791,7 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, return 0; } -int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol) +int netlink_sendskb(struct sock *sk, struct sk_buff *skb) { int len = skb->len; @@ -853,7 +853,7 @@ retry: if (err) return err; - return netlink_sendskb(sk, skb, ssk->sk_protocol); + return netlink_sendskb(sk, skb); } int netlink_has_listeners(struct sock *sk, unsigned int group) From aed815601f3f95281ab3a01f7e2cbe1bd54285a0 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 10 Oct 2007 21:14:32 -0700 Subject: [PATCH 1856/2804] [NET]: unify netlink kernel socket recognition There are currently two ways to determine whether the netlink socket is a kernel one or a user one. This patch creates a single inline call for this purpose and unifies all the calls in the af_netlink.c No similar calls are found outside af_netlink.c. Signed-off-by: Denis V. Lunev Acked-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a5bd63ca86bc..4ce7dcbcb6ef 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -92,6 +92,11 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk) return container_of(sk, struct netlink_sock, sk); } +static inline int netlink_is_kernel(struct sock *sk) +{ + return nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET; +} + struct nl_pid_hash { struct hlist_head *table; unsigned long rehash_time; @@ -489,7 +494,7 @@ static int netlink_release(struct socket *sock) module_put(nlk->module); netlink_table_grab(); - if (nlk->flags & NETLINK_KERNEL_SOCKET) { + if (netlink_is_kernel(sk)) { kfree(nl_table[sk->sk_protocol].listeners); nl_table[sk->sk_protocol].module = NULL; nl_table[sk->sk_protocol].registered = 0; @@ -716,7 +721,7 @@ static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) /* Don't bother queuing skb if kernel socket has no input function */ nlk = nlk_sk(sock); - if ((nlk->pid == 0 && !nlk->data_ready) || + if ((netlink_is_kernel(sock) && !nlk->data_ready) || (sock->sk_state == NETLINK_CONNECTED && nlk->dst_pid != nlk_sk(ssk)->pid)) { sock_put(sock); @@ -762,7 +767,7 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, test_bit(0, &nlk->state)) { DECLARE_WAITQUEUE(wait, current); if (!timeo) { - if (!ssk || nlk_sk(ssk)->pid == 0) + if (!ssk || netlink_is_kernel(ssk)) netlink_overrun(sk); sock_put(sk); kfree_skb(skb); @@ -861,7 +866,7 @@ int netlink_has_listeners(struct sock *sk, unsigned int group) int res = 0; unsigned long *listeners; - BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET)); + BUG_ON(!netlink_is_kernel(sk)); rcu_read_lock(); listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); From cd40b7d3983c708aabe3d3008ec64ffce56d33b0 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 10 Oct 2007 21:15:29 -0700 Subject: [PATCH 1857/2804] [NET]: make netlink user -> kernel interface synchronious This patch make processing netlink user -> kernel messages synchronious. This change was inspired by the talk with Alexey Kuznetsov about current netlink messages processing. He says that he was badly wrong when introduced asynchronious user -> kernel communication. The call netlink_unicast is the only path to send message to the kernel netlink socket. But, unfortunately, it is also used to send data to the user. Before this change the user message has been attached to the socket queue and sk->sk_data_ready was called. The process has been blocked until all pending messages were processed. The bad thing is that this processing may occur in the arbitrary process context. This patch changes nlk->data_ready callback to get 1 skb and force packet processing right in the netlink_unicast. Kernel -> user path in netlink_unicast remains untouched. EINTR processing for in netlink_run_queue was changed. It forces rtnl_lock drop, but the process remains in the cycle until the message will be fully processed. So, there is no need to use this kludges now. Signed-off-by: Denis V. Lunev Acked-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- drivers/connector/connector.c | 14 +-- drivers/scsi/scsi_netlink.c | 25 +---- drivers/scsi/scsi_transport_iscsi.c | 82 +++++++-------- fs/ecryptfs/netlink.c | 14 +-- include/linux/connector.h | 2 +- include/linux/netlink.h | 2 +- include/net/netlink.h | 6 +- kernel/audit.c | 12 +-- net/core/rtnetlink.c | 12 +-- net/decnet/netfilter/dn_rtmsg.c | 14 +-- net/ipv4/fib_frontend.c | 9 +- net/ipv4/inet_diag.c | 12 +-- net/ipv4/netfilter/ip_queue.c | 17 +--- net/ipv6/netfilter/ip6_queue.c | 19 +--- net/netfilter/nfnetlink.c | 12 +-- net/netlink/af_netlink.c | 152 +++++++++------------------- net/netlink/genetlink.c | 12 +-- net/xfrm/xfrm_user.c | 13 +-- 18 files changed, 130 insertions(+), 299 deletions(-) diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 569070997cc1..0e328d387af4 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -234,18 +234,6 @@ out: kfree_skb(__skb); } -/* - * Netlink socket input callback - dequeues the skbs and calls the - * main netlink receiving function. - */ -static void cn_input(struct sock *sk, int len) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) - cn_rx_skb(skb); -} - /* * Notification routing. * @@ -442,7 +430,7 @@ static int __devinit cn_init(void) struct cn_dev *dev = &cdev; int err; - dev->input = cn_input; + dev->input = cn_rx_skb; dev->id.idx = cn_idx; dev->id.val = cn_val; diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 163acf6ad2d3..40579edca101 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -64,7 +64,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { err = -EBADMSG; - goto next_msg; + return; } hdr = NLMSG_DATA(nlh); @@ -98,27 +98,6 @@ next_msg: } -/** - * scsi_nl_rcv_msg - - * Receive handler for a socket. Extracts a received message buffer from - * the socket, and starts message processing. - * - * @sk: socket - * @len: unused - * - **/ -static void -scsi_nl_rcv(struct sock *sk, int len) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&sk->sk_receive_queue))) { - scsi_nl_rcv_msg(skb); - kfree_skb(skb); - } -} - - /** * scsi_nl_rcv_event - * Event handler for a netlink socket. @@ -168,7 +147,7 @@ scsi_netlink_init(void) } scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, - SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL, + SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL, THIS_MODULE); if (!scsi_nl_sock) { printk(KERN_ERR "%s: register of recieve handler failed\n", diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 4916f01230dc..5428d15f23c6 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1097,61 +1097,49 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) } /* - * Get message from skb (based on rtnetlink_rcv_skb). Each message is - * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or - * invalid creds are discarded silently. + * Get message from skb. Each message is processed by iscsi_if_recv_msg. + * Malformed skbs with wrong lengths or invalid creds are not processed. */ static void -iscsi_if_rx(struct sock *sk, int len) +iscsi_if_rx(struct sk_buff *skb) { - struct sk_buff *skb; - mutex_lock(&rx_queue_mutex); - while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { - if (NETLINK_CREDS(skb)->uid) { - skb_pull(skb, skb->len); - goto free_skb; + while (skb->len >= NLMSG_SPACE(0)) { + int err; + uint32_t rlen; + struct nlmsghdr *nlh; + struct iscsi_uevent *ev; + + nlh = nlmsg_hdr(skb); + if (nlh->nlmsg_len < sizeof(*nlh) || + skb->len < nlh->nlmsg_len) { + break; } - while (skb->len >= NLMSG_SPACE(0)) { - int err; - uint32_t rlen; - struct nlmsghdr *nlh; - struct iscsi_uevent *ev; + ev = NLMSG_DATA(nlh); + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen = skb->len; - nlh = nlmsg_hdr(skb); - if (nlh->nlmsg_len < sizeof(*nlh) || - skb->len < nlh->nlmsg_len) { + err = iscsi_if_recv_msg(skb, nlh); + if (err) { + ev->type = ISCSI_KEVENT_IF_ERROR; + ev->iferror = err; + } + do { + /* + * special case for GET_STATS: + * on success - sending reply and stats from + * inside of if_recv_msg(), + * on error - fall through. + */ + if (ev->type == ISCSI_UEVENT_GET_STATS && !err) break; - } - - ev = NLMSG_DATA(nlh); - rlen = NLMSG_ALIGN(nlh->nlmsg_len); - if (rlen > skb->len) - rlen = skb->len; - - err = iscsi_if_recv_msg(skb, nlh); - if (err) { - ev->type = ISCSI_KEVENT_IF_ERROR; - ev->iferror = err; - } - do { - /* - * special case for GET_STATS: - * on success - sending reply and stats from - * inside of if_recv_msg(), - * on error - fall through. - */ - if (ev->type == ISCSI_UEVENT_GET_STATS && !err) - break; - err = iscsi_if_send_reply( - NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, - nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); - } while (err < 0 && err != -ECONNREFUSED); - skb_pull(skb, rlen); - } -free_skb: - kfree_skb(skb); + err = iscsi_if_send_reply( + NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, + nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); + } while (err < 0 && err != -ECONNREFUSED); + skb_pull(skb, rlen); } mutex_unlock(&rx_queue_mutex); } diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c index 056519cd92bc..9aa345121e09 100644 --- a/fs/ecryptfs/netlink.c +++ b/fs/ecryptfs/netlink.c @@ -165,22 +165,10 @@ static int ecryptfs_process_nl_quit(struct sk_buff *skb) * it to its desired netlink context element and wake up the process * that is waiting for a response. */ -static void ecryptfs_receive_nl_message(struct sock *sk, int len) +static void ecryptfs_receive_nl_message(struct sk_buff *skb) { - struct sk_buff *skb; struct nlmsghdr *nlh; - int rc = 0; /* skb_recv_datagram requires this */ -receive: - skb = skb_recv_datagram(sk, 0, 0, &rc); - if (rc == -EINTR) - goto receive; - else if (rc < 0) { - ecryptfs_printk(KERN_ERR, "Error occurred while " - "receiving eCryptfs netlink message; " - "rc = [%d]\n", rc); - return; - } nlh = nlmsg_hdr(skb); if (!NLMSG_OK(nlh, skb->len)) { ecryptfs_printk(KERN_ERR, "Received corrupt netlink " diff --git a/include/linux/connector.h b/include/linux/connector.h index 10eb56b2940a..b62f823e90cf 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -153,7 +153,7 @@ struct cn_dev { u32 seq, groups; struct sock *nls; - void (*input) (struct sock * sk, int len); + void (*input) (struct sk_buff *skb); struct cn_queue_dev *cbdev; }; diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 7b552b6c2c19..7c1f3b1d2ee5 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -175,7 +175,7 @@ struct netlink_skb_parms extern struct sock *netlink_kernel_create(struct net *net, int unit,unsigned int groups, - void (*input)(struct sock *sk, int len), + void (*input)(struct sk_buff *skb), struct mutex *cb_mutex, struct module *module); extern int netlink_change_ngroups(struct sock *sk, unsigned int groups); diff --git a/include/net/netlink.h b/include/net/netlink.h index 1afd3e837d23..9298218c07f9 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -220,9 +220,9 @@ struct nl_info { u32 pid; }; -extern unsigned int netlink_run_queue(struct sock *sk, unsigned int qlen, - int (*cb)(struct sk_buff *, - struct nlmsghdr *)); +extern int netlink_rcv_skb(struct sk_buff *skb, + int (*cb)(struct sk_buff *, + struct nlmsghdr *)); extern int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, unsigned int group, int report, gfp_t flags); diff --git a/kernel/audit.c b/kernel/audit.c index f3c390f6c0b4..2924251a6547 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -847,18 +847,10 @@ static void audit_receive_skb(struct sk_buff *skb) } /* Receive messages from netlink socket. */ -static void audit_receive(struct sock *sk, int length) +static void audit_receive(struct sk_buff *skb) { - struct sk_buff *skb; - unsigned int qlen; - mutex_lock(&audit_cmd_mutex); - - for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { - skb = skb_dequeue(&sk->sk_receive_queue); - audit_receive_skb(skb); - kfree_skb(skb); - } + audit_receive_skb(skb); mutex_unlock(&audit_cmd_mutex); } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 471d2d9f8eae..1072d16696c3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1312,15 +1312,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return doit(skb, nlh, (void *)&rta_buf[0]); } -static void rtnetlink_rcv(struct sock *sk, int len) +static void rtnetlink_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - rtnl_lock(); - qlen = netlink_run_queue(sk, qlen, &rtnetlink_rcv_msg); - rtnl_unlock(); - } while (qlen); + rtnl_lock(); + netlink_rcv_skb(skb, &rtnetlink_rcv_msg); + rtnl_unlock(); } static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index ebb38feb4df3..f7fba7721e63 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -115,17 +115,6 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb) RCV_SKB_FAIL(-EINVAL); } -static void dnrmg_receive_user_sk(struct sock *sk, int len) -{ - struct sk_buff *skb; - unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); - - for (; qlen && (skb = skb_dequeue(&sk->sk_receive_queue)); qlen--) { - dnrmg_receive_user_skb(skb); - kfree_skb(skb); - } -} - static struct nf_hook_ops dnrmg_ops = { .hook = dnrmg_hook, .pf = PF_DECnet, @@ -139,7 +128,8 @@ static int __init dn_rtmsg_init(void) dnrmg = netlink_kernel_create(&init_net, NETLINK_DNRTMSG, DNRNG_NLGRP_MAX, - dnrmg_receive_user_sk, NULL, THIS_MODULE); + dnrmg_receive_user_skb, + NULL, THIS_MODULE); if (dnrmg == NULL) { printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket"); return -ENOMEM; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index f823ca34cb12..a5cba2349605 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -62,6 +62,9 @@ static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; #define FIB_TABLE_HASHSZ 256 static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; +static struct sock *fibnl = NULL; + + struct fib_table *fib_new_table(u32 id) { struct fib_table *tb; @@ -811,13 +814,13 @@ static void nl_fib_input(struct sock *sk, int len) pid = NETLINK_CB(skb).pid; /* pid of sending process */ NETLINK_CB(skb).pid = 0; /* from kernel */ NETLINK_CB(skb).dst_group = 0; /* unicast */ - netlink_unicast(sk, skb, pid, MSG_DONTWAIT); + netlink_unicast(fibnl, skb, pid, MSG_DONTWAIT); } static void nl_fib_lookup_init(void) { - netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0, nl_fib_input, - NULL, THIS_MODULE); + fibnl = netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0, + nl_fib_input, NULL, THIS_MODULE); } static void fib_disable_ip(struct net_device *dev, int force) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index b04a6ee5a9a1..7eb83ebed2ec 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -839,15 +839,11 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) static DEFINE_MUTEX(inet_diag_mutex); -static void inet_diag_rcv(struct sock *sk, int len) +static void inet_diag_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - mutex_lock(&inet_diag_mutex); - qlen = netlink_run_queue(sk, qlen, &inet_diag_rcv_msg); - mutex_unlock(&inet_diag_mutex); - } while (qlen); + mutex_lock(&inet_diag_mutex); + netlink_rcv_skb(skb, &inet_diag_rcv_msg); + mutex_unlock(&inet_diag_mutex); } static DEFINE_SPINLOCK(inet_diag_register_lock); diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index aaa3f5c56761..23cbfc7c80fd 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -475,7 +475,7 @@ ipq_dev_drop(int ifindex) #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) static inline void -ipq_rcv_skb(struct sk_buff *skb) +__ipq_rcv_skb(struct sk_buff *skb) { int status, type, pid, flags, nlmsglen, skblen; struct nlmsghdr *nlh; @@ -533,19 +533,10 @@ ipq_rcv_skb(struct sk_buff *skb) } static void -ipq_rcv_sk(struct sock *sk, int len) +ipq_rcv_skb(struct sk_buff *skb) { - struct sk_buff *skb; - unsigned int qlen; - mutex_lock(&ipqnl_mutex); - - for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { - skb = skb_dequeue(&sk->sk_receive_queue); - ipq_rcv_skb(skb); - kfree_skb(skb); - } - + __ipq_rcv_skb(skb); mutex_unlock(&ipqnl_mutex); } @@ -670,7 +661,7 @@ static int __init ip_queue_init(void) netlink_register_notifier(&ipq_nl_notifier); ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0, - ipq_rcv_sk, NULL, THIS_MODULE); + ipq_rcv_skb, NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index c75f467a8f51..0473145ac534 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -464,7 +464,7 @@ ipq_dev_drop(int ifindex) #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) static inline void -ipq_rcv_skb(struct sk_buff *skb) +__ipq_rcv_skb(struct sk_buff *skb) { int status, type, pid, flags, nlmsglen, skblen; struct nlmsghdr *nlh; @@ -522,19 +522,10 @@ ipq_rcv_skb(struct sk_buff *skb) } static void -ipq_rcv_sk(struct sock *sk, int len) +ipq_rcv_skb(struct sk_buff *skb) { - struct sk_buff *skb; - unsigned int qlen; - mutex_lock(&ipqnl_mutex); - - for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { - skb = skb_dequeue(&sk->sk_receive_queue); - ipq_rcv_skb(skb); - kfree_skb(skb); - } - + __ipq_rcv_skb(skb); mutex_unlock(&ipqnl_mutex); } @@ -658,8 +649,8 @@ static int __init ip6_queue_init(void) struct proc_dir_entry *proc; netlink_register_notifier(&ipq_nl_notifier); - ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, ipq_rcv_sk, - NULL, THIS_MODULE); + ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, + ipq_rcv_skb, NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip6_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 99775af19ff4..2128542995f7 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -169,15 +169,11 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) } } -static void nfnetlink_rcv(struct sock *sk, int len) +static void nfnetlink_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - nfnl_lock(); - qlen = netlink_run_queue(sk, qlen, nfnetlink_rcv_msg); - nfnl_unlock(); - } while (qlen); + nfnl_lock(); + netlink_rcv_skb(skb, &nfnetlink_rcv_msg); + nfnl_unlock(); } static void __exit nfnetlink_exit(void) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 4ce7dcbcb6ef..c776bcd9f825 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -80,7 +80,7 @@ struct netlink_sock { struct netlink_callback *cb; struct mutex *cb_mutex; struct mutex cb_def_mutex; - void (*data_ready)(struct sock *sk, int bytes); + void (*netlink_rcv)(struct sk_buff *skb); struct module *module; }; @@ -127,7 +127,6 @@ static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); static int netlink_dump(struct sock *sk); static void netlink_destroy_callback(struct netlink_callback *cb); -static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb); static DEFINE_RWLOCK(nl_table_lock); static atomic_t nl_table_users = ATOMIC_INIT(0); @@ -709,21 +708,17 @@ static void netlink_overrun(struct sock *sk) static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) { - int protocol = ssk->sk_protocol; - struct net *net; struct sock *sock; struct netlink_sock *nlk; - net = ssk->sk_net; - sock = netlink_lookup(net, protocol, pid); + sock = netlink_lookup(ssk->sk_net, ssk->sk_protocol, pid); if (!sock) return ERR_PTR(-ECONNREFUSED); /* Don't bother queuing skb if kernel socket has no input function */ nlk = nlk_sk(sock); - if ((netlink_is_kernel(sock) && !nlk->data_ready) || - (sock->sk_state == NETLINK_CONNECTED && - nlk->dst_pid != nlk_sk(ssk)->pid)) { + if (sock->sk_state == NETLINK_CONNECTED && + nlk->dst_pid != nlk_sk(ssk)->pid) { sock_put(sock); return ERR_PTR(-ECONNREFUSED); } @@ -837,7 +832,34 @@ static inline struct sk_buff *netlink_trim(struct sk_buff *skb, return skb; } -int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock) +static inline void netlink_rcv_wake(struct sock *sk) +{ + struct netlink_sock *nlk = nlk_sk(sk); + + if (skb_queue_empty(&sk->sk_receive_queue)) + clear_bit(0, &nlk->state); + if (!test_bit(0, &nlk->state)) + wake_up_interruptible(&nlk->wait); +} + +static inline int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb) +{ + int ret; + struct netlink_sock *nlk = nlk_sk(sk); + + ret = -ECONNREFUSED; + if (nlk->netlink_rcv != NULL) { + ret = skb->len; + skb_set_owner_r(skb, sk); + nlk->netlink_rcv(skb); + } + kfree_skb(skb); + sock_put(sk); + return ret; +} + +int netlink_unicast(struct sock *ssk, struct sk_buff *skb, + u32 pid, int nonblock) { struct sock *sk; int err; @@ -852,6 +874,9 @@ retry: kfree_skb(skb); return PTR_ERR(sk); } + if (netlink_is_kernel(sk)) + return netlink_unicast_kernel(sk, skb); + err = netlink_attachskb(sk, skb, nonblock, timeo, ssk); if (err == 1) goto retry; @@ -1151,16 +1176,6 @@ static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); } -static inline void netlink_rcv_wake(struct sock *sk) -{ - struct netlink_sock *nlk = nlk_sk(sk); - - if (skb_queue_empty(&sk->sk_receive_queue)) - clear_bit(0, &nlk->state); - if (!test_bit(0, &nlk->state)) - wake_up_interruptible(&nlk->wait); -} - static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg, size_t len) { @@ -1308,11 +1323,7 @@ out: static void netlink_data_ready(struct sock *sk, int len) { - struct netlink_sock *nlk = nlk_sk(sk); - - if (nlk->data_ready) - nlk->data_ready(sk, len); - netlink_rcv_wake(sk); + BUG(); } /* @@ -1323,7 +1334,7 @@ static void netlink_data_ready(struct sock *sk, int len) struct sock * netlink_kernel_create(struct net *net, int unit, unsigned int groups, - void (*input)(struct sock *sk, int len), + void (*input)(struct sk_buff *skb), struct mutex *cb_mutex, struct module *module) { struct socket *sock; @@ -1352,7 +1363,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, sk = sock->sk; sk->sk_data_ready = netlink_data_ready; if (input) - nlk_sk(sk)->data_ready = input; + nlk_sk(sk)->netlink_rcv = input; if (netlink_insert(sk, net, 0)) goto out_sock_release; @@ -1552,12 +1563,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, netlink_dump(sk); sock_put(sk); - - /* We successfully started a dump, by returning -EINTR we - * signal the queue mangement to interrupt processing of - * any netlink messages so userspace gets a chance to read - * the results. */ - return -EINTR; + return 0; } void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) @@ -1594,13 +1600,15 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); } -static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, +int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, struct nlmsghdr *)) { struct nlmsghdr *nlh; int err; while (skb->len >= nlmsg_total_size(0)) { + int msglen; + nlh = nlmsg_hdr(skb); err = 0; @@ -1616,85 +1624,19 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, goto skip; err = cb(skb, nlh); - if (err == -EINTR) { - /* Not an error, but we interrupt processing */ - netlink_queue_skip(nlh, skb); - return err; - } skip: if (nlh->nlmsg_flags & NLM_F_ACK || err) netlink_ack(skb, nlh, err); - netlink_queue_skip(nlh, skb); + msglen = NLMSG_ALIGN(nlh->nlmsg_len); + if (msglen > skb->len) + msglen = skb->len; + skb_pull(skb, msglen); } return 0; } -/** - * nelink_run_queue - Process netlink receive queue. - * @sk: Netlink socket containing the queue - * @qlen: Initial queue length - * @cb: Callback function invoked for each netlink message found - * - * Processes as much as there was in the queue upon entry and invokes - * a callback function for each netlink message found. The callback - * function may refuse a message by returning a negative error code - * but setting the error pointer to 0 in which case this function - * returns with a qlen != 0. - * - * qlen must be initialized to 0 before the initial entry, afterwards - * the function may be called repeatedly until the returned qlen is 0. - * - * The callback function may return -EINTR to signal that processing - * of netlink messages shall be interrupted. In this case the message - * currently being processed will NOT be requeued onto the receive - * queue. - */ -unsigned int netlink_run_queue(struct sock *sk, unsigned int qlen, - int (*cb)(struct sk_buff *, struct nlmsghdr *)) -{ - struct sk_buff *skb; - - if (!qlen || qlen > skb_queue_len(&sk->sk_receive_queue)) - qlen = skb_queue_len(&sk->sk_receive_queue); - - for (; qlen; qlen--) { - skb = skb_dequeue(&sk->sk_receive_queue); - if (netlink_rcv_skb(skb, cb)) { - if (skb->len) - skb_queue_head(&sk->sk_receive_queue, skb); - else { - kfree_skb(skb); - qlen--; - } - break; - } - - kfree_skb(skb); - } - - return qlen; -} - -/** - * netlink_queue_skip - Skip netlink message while processing queue. - * @nlh: Netlink message to be skipped - * @skb: Socket buffer containing the netlink messages. - * - * Pulls the given netlink message off the socket buffer so the next - * call to netlink_queue_run() will not reconsider the message. - */ -static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) -{ - int msglen = NLMSG_ALIGN(nlh->nlmsg_len); - - if (msglen > skb->len) - msglen = skb->len; - - skb_pull(skb, msglen); -} - /** * nlmsg_notify - send a notification netlink message * @sk: netlink socket to use @@ -1998,7 +1940,7 @@ panic: core_initcall(netlink_proto_init); EXPORT_SYMBOL(netlink_ack); -EXPORT_SYMBOL(netlink_run_queue); +EXPORT_SYMBOL(netlink_rcv_skb); EXPORT_SYMBOL(netlink_broadcast); EXPORT_SYMBOL(netlink_dump_start); EXPORT_SYMBOL(netlink_kernel_create); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 3f1104dc128b..150579a21469 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -470,15 +470,11 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return ops->doit(skb, &info); } -static void genl_rcv(struct sock *sk, int len) +static void genl_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - genl_lock(); - qlen = netlink_run_queue(sk, qlen, genl_rcv_msg); - genl_unlock(); - } while (qlen && genl_sock && genl_sock->sk_receive_queue.qlen); + genl_lock(); + netlink_rcv_skb(skb, &genl_rcv_msg); + genl_unlock(); } /************************************************************************** diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5238f6a8dfad..d41588d101d0 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1895,16 +1895,11 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return link->doit(skb, nlh, attrs); } -static void xfrm_netlink_rcv(struct sock *sk, int len) +static void xfrm_netlink_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - mutex_lock(&xfrm_cfg_mutex); - qlen = netlink_run_queue(sk, qlen, &xfrm_user_rcv_msg); - mutex_unlock(&xfrm_cfg_mutex); - - } while (qlen); + mutex_lock(&xfrm_cfg_mutex); + netlink_rcv_skb(skb, &xfrm_user_rcv_msg); + mutex_unlock(&xfrm_cfg_mutex); } static inline size_t xfrm_expire_msgsize(void) From 9ef4429b31b86d486b56b6c179fe52b5c7152f13 Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Wed, 10 Oct 2007 21:18:17 -0700 Subject: [PATCH 1858/2804] [NET]: Fix dev_put() and dev_hold() comments Trivial fix: Swap comments for dev_put() and dev_hold() to get them at the right place. Typo introduced by 4fa57c9ea9f36f9ca852f3a88ca5d2f1aebbc960. Signed-of-by: Benjamin Thery Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4848c7afa4e7..5a11f889e56a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1064,7 +1064,7 @@ extern void netdev_run_todo(void); * dev_put - release reference to device * @dev: network device * - * Hold reference to device to keep it from being freed. + * Release reference to device to allow it to be freed. */ static inline void dev_put(struct net_device *dev) { @@ -1075,7 +1075,7 @@ static inline void dev_put(struct net_device *dev) * dev_hold - get reference to device * @dev: network device * - * Release reference to device to allow it to be freed. + * Hold reference to device to keep it from being freed. */ static inline void dev_hold(struct net_device *dev) { From 092e9d93b3728d484a4e73df9852dc4002cf9923 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 10 Oct 2007 21:19:28 -0700 Subject: [PATCH 1859/2804] [9P]: build fix with !CONFIG_SYSCTL found via make randconfig build testing: net/built-in.o: In function `init_p9': mod.c:(.init.text+0x3b39): undefined reference to `p9_sysctl_register' net/built-in.o: In function `exit_p9': mod.c:(.exit.text+0x36b): undefined reference to `p9_sysctl_unregister' Signed-off-by: Ingo Molnar Signed-off-by: David S. Miller --- include/net/9p/9p.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 88884d39f28f..7726ff41c3e6 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -412,6 +412,18 @@ int p9_idpool_check(int id, struct p9_idpool *p); int p9_error_init(void); int p9_errstr2errno(char *, int); + +#ifdef CONFIG_SYSCTL int __init p9_sysctl_register(void); void __exit p9_sysctl_unregister(void); +#else +static inline int p9_sysctl_register(void) +{ + return 0; +} +static inline void p9_sysctl_unregister(void) +{ +} +#endif + #endif /* NET_9P_H */ From 31910575a9de61e78065e93846e8e7a4894a18bf Mon Sep 17 00:00:00 2001 From: Pierre Ynard Date: Wed, 10 Oct 2007 21:22:05 -0700 Subject: [PATCH 1860/2804] [IPv6]: Export userland ND options through netlink (RDNSS support) As discussed before, this patch provides userland with a way to access relevant options in Router Advertisements, after they are processed and validated by the kernel. Extra options are processed in a generic way; this patch only exports RDNSS options described in RFC5006, but support to control which options are exported could be easily added. A new rtnetlink message type is defined, to transport Neighbor Discovery options, along with optional context information. At the moment only the address of the router sending an RDNSS option is included, but additional attributes may be later defined, if needed by new use cases. Signed-off-by: Pierre Ynard Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 29 +++++++++++ include/net/ndisc.h | 1 + net/ipv6/ndisc.c | 103 ++++++++++++++++++++++++++++++++++---- 3 files changed, 124 insertions(+), 9 deletions(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index dff3192374f8..5bf618241ab9 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -97,6 +97,9 @@ enum { RTM_SETNEIGHTBL, #define RTM_SETNEIGHTBL RTM_SETNEIGHTBL + RTM_NEWNDUSEROPT = 68, +#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -479,6 +482,30 @@ enum #define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg)))) #define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg)) +/******************************************************************** + * Neighbor Discovery userland options + ****/ + +struct nduseroptmsg +{ + unsigned char nduseropt_family; + unsigned char nduseropt_pad1; + unsigned short nduseropt_opts_len; /* Total length of options */ + __u8 nduseropt_icmp_type; + __u8 nduseropt_icmp_code; + unsigned short nduseropt_pad2; + /* Followed by one or more ND options */ +}; + +enum +{ + NDUSEROPT_UNSPEC, + NDUSEROPT_SRCADDR, + __NDUSEROPT_MAX +}; + +#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) + #ifndef __KERNEL__ /* RTnetlink multicast groups - backwards compatibility for userspace */ #define RTMGRP_LINK 1 @@ -542,6 +569,8 @@ enum rtnetlink_groups { #define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_RULE, #define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE + RTNLGRP_ND_USEROPT, +#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 475b10c575b3..6684f7efbeeb 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -24,6 +24,7 @@ enum { ND_OPT_MTU = 5, /* RFC2461 */ __ND_OPT_ARRAY_MAX, ND_OPT_ROUTE_INFO = 24, /* RFC4191 */ + ND_OPT_RDNSS = 25, /* RFC5006 */ __ND_OPT_MAX }; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index d4acd283111b..6cc33dc83d1c 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -15,9 +15,10 @@ /* * Changes: * + * Pierre Ynard : export userland ND options + * through netlink (RDNSS support) * Lars Fenneberg : fixed MTU setting on receipt * of an RA. - * * Janos Farkas : kmalloc failure checks * Alexey Kuznetsov : state machine reworked * and moved to net/core. @@ -78,6 +79,9 @@ #include #include +#include +#include + #include #include #include @@ -161,6 +165,8 @@ struct ndisc_options { struct nd_opt_hdr *nd_opts_ri; struct nd_opt_hdr *nd_opts_ri_end; #endif + struct nd_opt_hdr *nd_useropts; + struct nd_opt_hdr *nd_useropts_end; }; #define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] @@ -225,6 +231,22 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, return (cur <= end && cur->nd_opt_type == type ? cur : NULL); } +static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) +{ + return (opt->nd_opt_type == ND_OPT_RDNSS); +} + +static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, + struct nd_opt_hdr *end) +{ + if (!cur || !end || cur >= end) + return NULL; + do { + cur = ((void *)cur) + (cur->nd_opt_len << 3); + } while(cur < end && !ndisc_is_useropt(cur)); + return (cur <= end && ndisc_is_useropt(cur) ? cur : NULL); +} + static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, struct ndisc_options *ndopts) { @@ -267,14 +289,21 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, break; #endif default: - /* - * Unknown options must be silently ignored, - * to accommodate future extension to the protocol. - */ - ND_PRINTK2(KERN_NOTICE - "%s(): ignored unsupported option; type=%d, len=%d\n", - __FUNCTION__, - nd_opt->nd_opt_type, nd_opt->nd_opt_len); + if (ndisc_is_useropt(nd_opt)) { + ndopts->nd_useropts_end = nd_opt; + if (!ndopts->nd_useropts) + ndopts->nd_useropts = nd_opt; + } else { + /* + * Unknown options must be silently ignored, + * to accommodate future extension to the + * protocol. + */ + ND_PRINTK2(KERN_NOTICE + "%s(): ignored unsupported option; type=%d, len=%d\n", + __FUNCTION__, + nd_opt->nd_opt_type, nd_opt->nd_opt_len); + } } opt_len -= l; nd_opt = ((void *)nd_opt) + l; @@ -984,6 +1013,53 @@ out: in6_dev_put(idev); } +static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) +{ + struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra); + struct sk_buff *skb; + struct nlmsghdr *nlh; + struct nduseroptmsg *ndmsg; + int err; + int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) + + (opt->nd_opt_len << 3)); + size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr)); + + skb = nlmsg_new(msg_size, GFP_ATOMIC); + if (skb == NULL) { + err = -ENOBUFS; + goto errout; + } + + nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0); + if (nlh == NULL) { + goto nla_put_failure; + } + + ndmsg = nlmsg_data(nlh); + ndmsg->nduseropt_family = AF_INET6; + ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type; + ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code; + ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3; + + memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3); + + NLA_PUT(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr), + &ipv6_hdr(ra)->saddr); + nlmsg_end(skb, nlh); + + err = rtnl_notify(skb, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC); + if (err < 0) + goto errout; + + return; + +nla_put_failure: + nlmsg_free(skb); + err = -EMSGSIZE; +errout: + rtnl_set_sk_err(RTNLGRP_ND_USEROPT, err); +} + static void ndisc_router_discovery(struct sk_buff *skb) { struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); @@ -1216,6 +1292,15 @@ skip_defrtr: } } + if (ndopts.nd_useropts) { + struct nd_opt_hdr *opt; + for (opt = ndopts.nd_useropts; + opt; + opt = ndisc_next_useropt(opt, ndopts.nd_useropts_end)) { + ndisc_ra_useropt(skb, opt); + } + } + if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) { ND_PRINTK2(KERN_WARNING "ICMPv6 RA: invalid RA options"); From 28f7b0360f46eeb9eeee63d03bb5484918a54837 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 10 Oct 2007 21:32:39 -0700 Subject: [PATCH 1861/2804] [NETLINK]: fib_frontend build fixes 1) fibnl needs to be declared outside of config ifdefs, and also should not be explicitly initialized to NULL 2) nl_fib_input() args are wrong for netlink_kernel_create() input method Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index a5cba2349605..78b514ba1414 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -49,6 +49,8 @@ #define FFprint(a...) printk(KERN_DEBUG a) +static struct sock *fibnl; + #ifndef CONFIG_IP_MULTIPLE_TABLES struct fib_table *ip_fib_local_table; @@ -62,9 +64,6 @@ static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; #define FIB_TABLE_HASHSZ 256 static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; -static struct sock *fibnl = NULL; - - struct fib_table *fib_new_table(u32 id) { struct fib_table *tb; @@ -787,17 +786,12 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) } } -static void nl_fib_input(struct sock *sk, int len) +static void nl_fib_input(struct sk_buff *skb) { - struct sk_buff *skb = NULL; - struct nlmsghdr *nlh = NULL; struct fib_result_nl *frn; - u32 pid; + struct nlmsghdr *nlh; struct fib_table *tb; - - skb = skb_dequeue(&sk->sk_receive_queue); - if (skb == NULL) - return; + u32 pid; nlh = nlmsg_hdr(skb); if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len || From 46b45b10f1425d02819b525e3805ddacd9ad4f29 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 9 Oct 2007 17:03:57 +1000 Subject: [PATCH 1862/2804] [POWERPC] Align the sys_call_table Our _GLOBAL macro does a ".align 2" so the alignment is fine for 32 bit, but on 64 bit it is possible for it to end up only 4 byte aligned. I don't know if it matters, but it can't hurt to 8 byte align it. It also means that when we build with --emit_relocs, none of our 64 bit relocations are to misaligned places. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/systbl.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 579de70e0b4d..93219c34af32 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -39,6 +39,8 @@ #ifdef CONFIG_PPC64 #define sys_sigpending sys_ni_syscall #define sys_old_getrlimit sys_ni_syscall + + .p2align 3 #endif _GLOBAL(sys_call_table) From 04c17170abe6da6679ab99b4b4a9730ba34ec30a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:32 +0200 Subject: [PATCH 1863/2804] x86_64: simplify oprofile build Instead of copying the i386 Makefile and handling path substitutions just use the i386 oprofile Makefile. Signed-off-by: Thomas Gleixner --- arch/x86_64/Makefile | 2 +- arch/x86_64/oprofile/Makefile | 19 ------------------- 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 arch/x86_64/oprofile/Makefile diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index b024e4a86895..c76351c13bdd 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -80,7 +80,7 @@ core-y += arch/x86_64/kernel/ \ arch/x86_64/vdso/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ drivers-$(CONFIG_PCI) += arch/x86_64/pci/ -drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/ +drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ boot := arch/x86_64/boot diff --git a/arch/x86_64/oprofile/Makefile b/arch/x86_64/oprofile/Makefile deleted file mode 100644 index 6be32683e1bc..000000000000 --- a/arch/x86_64/oprofile/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# -# oprofile for x86-64. -# Just reuse the one from i386. -# - -obj-$(CONFIG_OPROFILE) += oprofile.o - -DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ - oprof.o cpu_buffer.o buffer_sync.o \ - event_buffer.o oprofile_files.o \ - oprofilefs.o oprofile_stats.o \ - timer_int.o ) - -OPROFILE-y := init.o backtrace.o -OPROFILE-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o op_model_p4.o \ - op_model_ppro.o -OPROFILE-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o - -oprofile-y = $(DRIVER_OBJS) $(addprefix ../../i386/oprofile/, $(OPROFILE-y)) From f4b927a242a9d770947dd651d52f5f325a87a2d3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:33 +0200 Subject: [PATCH 1864/2804] x86_64: simplify cpufreq build Instead of copying the i386 Makefile and handling path substitutions just use the i386 cpufreq Makefile. Signed-off-by: Thomas Gleixner --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/cpufreq/Makefile | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 arch/x86_64/kernel/cpufreq/Makefile diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index ff5d8c9b96d9..59b16dcc5249 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += suspend.o obj-$(CONFIG_HIBERNATION) += suspend_asm.o -obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary.o tce.o diff --git a/arch/x86_64/kernel/cpufreq/Makefile b/arch/x86_64/kernel/cpufreq/Makefile deleted file mode 100644 index 753ce1dd418e..000000000000 --- a/arch/x86_64/kernel/cpufreq/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# -# Reuse the i386 cpufreq drivers -# - -SRCDIR := ../../../i386/kernel/cpu/cpufreq - -obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o -obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o -obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o -obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o -obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o - -powernow-k8-objs := ${SRCDIR}/powernow-k8.o -speedstep-centrino-objs := ${SRCDIR}/speedstep-centrino.o -acpi-cpufreq-objs := ${SRCDIR}/acpi-cpufreq.o -p4-clockmod-objs := ${SRCDIR}/p4-clockmod.o -speedstep-lib-objs := ${SRCDIR}/speedstep-lib.o From d7394fe57adbbd030c5a56f5f4579fe0478cdb9b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:35 +0200 Subject: [PATCH 1865/2804] i386: use full path for mach-xxx make rules To simplify the scripted move of the mach-xxx directories, change the makerules to the full arch/.... path. Signed-off-by: Thomas Gleixner --- arch/i386/Makefile | 18 +++++++++--------- arch/i386/mach-generic/Makefile | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 52b932478c6d..1bada3d878b7 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -61,36 +61,36 @@ AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONF CFLAGS += $(cflags-y) # Default subarch .c files -mcore-y := mach-default +mcore-y := arch/i386/mach-default # Voyager subarch support mflags-$(CONFIG_X86_VOYAGER) := -Iinclude/asm-i386/mach-voyager -mcore-$(CONFIG_X86_VOYAGER) := mach-voyager +mcore-$(CONFIG_X86_VOYAGER) := arch/i386/mach-voyager # VISWS subarch support mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-i386/mach-visws -mcore-$(CONFIG_X86_VISWS) := mach-visws +mcore-$(CONFIG_X86_VISWS) := arch/i386/mach-visws # NUMAQ subarch support mflags-$(CONFIG_X86_NUMAQ) := -Iinclude/asm-i386/mach-numaq -mcore-$(CONFIG_X86_NUMAQ) := mach-default +mcore-$(CONFIG_X86_NUMAQ) := arch/i386/mach-default # BIGSMP subarch support mflags-$(CONFIG_X86_BIGSMP) := -Iinclude/asm-i386/mach-bigsmp -mcore-$(CONFIG_X86_BIGSMP) := mach-default +mcore-$(CONFIG_X86_BIGSMP) := arch/i386/mach-default #Summit subarch support mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit -mcore-$(CONFIG_X86_SUMMIT) := mach-default +mcore-$(CONFIG_X86_SUMMIT) := arch/i386/mach-default # generic subarchitecture mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic -mcore-$(CONFIG_X86_GENERICARCH) := mach-default +mcore-$(CONFIG_X86_GENERICARCH) := arch/i386/mach-default core-$(CONFIG_X86_GENERICARCH) += arch/i386/mach-generic/ # ES7000 subarch support mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-i386/mach-es7000 -mcore-$(CONFIG_X86_ES7000) := mach-default +mcore-$(CONFIG_X86_ES7000) := arch/i386/mach-default core-$(CONFIG_X86_ES7000) := arch/i386/mach-es7000/ # Xen paravirtualization support @@ -104,7 +104,7 @@ head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o libs-y += arch/i386/lib/ core-y += arch/i386/kernel/ \ arch/i386/mm/ \ - arch/i386/$(mcore-y)/ \ + $(mcore-y)/ \ arch/i386/crypto/ drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/ drivers-$(CONFIG_PCI) += arch/i386/pci/ diff --git a/arch/i386/mach-generic/Makefile b/arch/i386/mach-generic/Makefile index 6914485c0d85..2f216f55b2dd 100644 --- a/arch/i386/mach-generic/Makefile +++ b/arch/i386/mach-generic/Makefile @@ -4,4 +4,5 @@ EXTRA_CFLAGS := -Iarch/i386/kernel -obj-y := probe.o summit.o bigsmp.o es7000.o default.o ../mach-es7000/ +obj-y := probe.o summit.o bigsmp.o es7000.o default.o +obj-y += ../../i386/mach-es7000/ From 6752ed90da032af72f2f1fa23d1abf0889b56db0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:36 +0200 Subject: [PATCH 1866/2804] Kbuild: allow arch/xxx to use a different source path Preparatory patch for the source merge of arch/i386 and arch/x86_64 into arch/x86. This allows to keep the original arch directories as stubs for the main Makefiles, Kconfigs et. al during the transition phase while having the code in the new arch/x86 directory. Signed-off-by: Thomas Gleixner --- Kbuild | 6 +++--- Makefile | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Kbuild b/Kbuild index 56b8edf6a3bc..2d403cfa4b16 100644 --- a/Kbuild +++ b/Kbuild @@ -12,7 +12,7 @@ offsets-file := include/asm-$(ARCH)/asm-offsets.h always := $(offsets-file) targets := $(offsets-file) -targets += arch/$(ARCH)/kernel/asm-offsets.s +targets += arch/$(SRCARCH)/kernel/asm-offsets.s clean-files := $(addprefix $(objtree)/,$(targets)) # Default sed regexp - multiline due to syntax constraints @@ -40,11 +40,11 @@ define cmd_offsets endef # We use internal kbuild rules to avoid the "is up to date" message from make -arch/$(ARCH)/kernel/asm-offsets.s: arch/$(ARCH)/kernel/asm-offsets.c FORCE +arch/$(SRCARCH)/kernel/asm-offsets.s: arch/$(SRCARCH)/kernel/asm-offsets.c FORCE $(Q)mkdir -p $(dir $@) $(call if_changed_dep,cc_s_c) -$(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild +$(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s Kbuild $(Q)mkdir -p $(dir $@) $(call cmd,offsets) diff --git a/Makefile b/Makefile index 4635a64da36c..61e178ff0c1b 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,8 @@ ARCH ?= $(SUBARCH) CROSS_COMPILE ?= # Architecture as present in compile.h -UTS_MACHINE := $(ARCH) +UTS_MACHINE := $(ARCH) +SRCARCH := $(ARCH) KCONFIG_CONFIG ?= .config @@ -322,7 +323,7 @@ KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION -export ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC +export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC export CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS @@ -609,7 +610,7 @@ libs-y := $(libs-y1) $(libs-y2) vmlinux-init := $(head-y) $(init-y) vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y) vmlinux-all := $(vmlinux-init) $(vmlinux-main) -vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds +vmlinux-lds := arch/$(SRCARCH)/kernel/vmlinux.lds export KBUILD_VMLINUX_OBJS := $(vmlinux-all) # Rule to link vmlinux - also used during CONFIG_KALLSYMS From 2eb4c95094d927f2eb094f720222cc5a9cc22fd3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:38 +0200 Subject: [PATCH 1867/2804] Kbuild: prepare scope and tags for arch/x86 Preparatory patch for the source merge of arch/i386 and arch/x86_64 into arch/x86. Make scope and tags aware of SRCARCH Signed-off-by: Thomas Gleixner --- Makefile | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 61e178ff0c1b..f2067e337d4d 100644 --- a/Makefile +++ b/Makefile @@ -1293,18 +1293,23 @@ ifeq ($(ALLSOURCE_ARCHS),) ifeq ($(ARCH),um) ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH) else -ALLINCLUDE_ARCHS := $(ARCH) +ALLINCLUDE_ARCHS := $(SRCARCH) endif else #Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behavour. ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS) endif +# Take care of arch/x86 +ifeq ($(ARCH), $(SRCARCH)) ALLSOURCE_ARCHS := $(ARCH) +else +ALLSOURCE_ARCHS := $(ARCH) $(SRCARCH) +endif define find-sources ( for ARCH in $(ALLSOURCE_ARCHS) ; do \ - find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \ + find $(__srctree)arch/$${SRCARCH} $(RCS_FIND_IGNORE) \ -name $1 -print; \ done ; \ find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \ @@ -1313,7 +1318,7 @@ define find-sources \( -name config -o -name 'asm-*' \) -prune \ -o -name $1 -print; \ for ARCH in $(ALLINCLUDE_ARCHS) ; do \ - find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \ + find $(__srctree)include/asm-$${SRCARCH} $(RCS_FIND_IGNORE) \ -name $1 -print; \ done ; \ find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \ From b7d331281488193621e255f47773e42f406b939d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:39 +0200 Subject: [PATCH 1868/2804] i386: remove module.h include from termios.h Signed-off-by: Thomas Gleixner --- include/asm-i386/termios.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/asm-i386/termios.h b/include/asm-i386/termios.h index f520b7c16fa2..6fdb2c841b73 100644 --- a/include/asm-i386/termios.h +++ b/include/asm-i386/termios.h @@ -40,7 +40,6 @@ struct termio { /* 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 From c339dd68c53ad3e0b94081c771e70132512d5377 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:39 +0200 Subject: [PATCH 1869/2804] x86_64: remove unused header file: Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- include/asm-x86_64/node.h | 1 - 1 file changed, 1 deletion(-) delete mode 100644 include/asm-x86_64/node.h diff --git a/include/asm-x86_64/node.h b/include/asm-x86_64/node.h deleted file mode 100644 index 0ee6f88db048..000000000000 --- a/include/asm-x86_64/node.h +++ /dev/null @@ -1 +0,0 @@ -#include From 6a273b2b46f9e57bd0bc1f4b905e28d2f947588d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:41 +0200 Subject: [PATCH 1870/2804] i386: prepare shared crypto/twofish.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/crypto/Makefile | 2 +- arch/i386/crypto/{twofish.c => twofish_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/crypto/{twofish.c => twofish_32.c} (100%) diff --git a/arch/i386/crypto/Makefile b/arch/i386/crypto/Makefile index 3fd19af18e34..57fcb333c9c1 100644 --- a/arch/i386/crypto/Makefile +++ b/arch/i386/crypto/Makefile @@ -8,5 +8,5 @@ obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o aes-i586-y := aes-i586-asm.o aes.o -twofish-i586-y := twofish-i586-asm.o twofish.o +twofish-i586-y := twofish-i586-asm.o twofish_32.o diff --git a/arch/i386/crypto/twofish.c b/arch/i386/crypto/twofish_32.c similarity index 100% rename from arch/i386/crypto/twofish.c rename to arch/i386/crypto/twofish_32.c From 018977f6e7f11b08a5928641454f4c43a9b1ca43 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:42 +0200 Subject: [PATCH 1871/2804] i386: prepare shared crypto/aes-i586-asm.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/crypto/Makefile | 2 +- arch/i386/crypto/{aes-i586-asm.S => aes-i586-asm_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/crypto/{aes-i586-asm.S => aes-i586-asm_32.S} (100%) diff --git a/arch/i386/crypto/Makefile b/arch/i386/crypto/Makefile index 57fcb333c9c1..cd1038a22dd3 100644 --- a/arch/i386/crypto/Makefile +++ b/arch/i386/crypto/Makefile @@ -7,6 +7,6 @@ obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o -aes-i586-y := aes-i586-asm.o aes.o +aes-i586-y := aes-i586-asm_32.o aes.o twofish-i586-y := twofish-i586-asm.o twofish_32.o diff --git a/arch/i386/crypto/aes-i586-asm.S b/arch/i386/crypto/aes-i586-asm_32.S similarity index 100% rename from arch/i386/crypto/aes-i586-asm.S rename to arch/i386/crypto/aes-i586-asm_32.S From fff7c9a4f6689243db004b8f6d8d4ba696796f81 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:44 +0200 Subject: [PATCH 1872/2804] i386: prepare shared crypto/twofish-i586-asm.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/crypto/Makefile | 2 +- arch/i386/crypto/{twofish-i586-asm.S => twofish-i586-asm_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/crypto/{twofish-i586-asm.S => twofish-i586-asm_32.S} (100%) diff --git a/arch/i386/crypto/Makefile b/arch/i386/crypto/Makefile index cd1038a22dd3..22671a442958 100644 --- a/arch/i386/crypto/Makefile +++ b/arch/i386/crypto/Makefile @@ -8,5 +8,5 @@ obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o aes-i586-y := aes-i586-asm_32.o aes.o -twofish-i586-y := twofish-i586-asm.o twofish_32.o +twofish-i586-y := twofish-i586-asm_32.o twofish_32.o diff --git a/arch/i386/crypto/twofish-i586-asm.S b/arch/i386/crypto/twofish-i586-asm_32.S similarity index 100% rename from arch/i386/crypto/twofish-i586-asm.S rename to arch/i386/crypto/twofish-i586-asm_32.S From e980b6d9dee73e879e9c4731d0ef8a3c9d44e6ed Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:45 +0200 Subject: [PATCH 1873/2804] i386: prepare shared crypto/aes.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/crypto/Makefile | 2 +- arch/i386/crypto/{aes.c => aes_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/crypto/{aes.c => aes_32.c} (100%) diff --git a/arch/i386/crypto/Makefile b/arch/i386/crypto/Makefile index 22671a442958..7154b14cd950 100644 --- a/arch/i386/crypto/Makefile +++ b/arch/i386/crypto/Makefile @@ -7,6 +7,6 @@ obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o -aes-i586-y := aes-i586-asm_32.o aes.o +aes-i586-y := aes-i586-asm_32.o aes_32.o twofish-i586-y := twofish-i586-asm_32.o twofish_32.o diff --git a/arch/i386/crypto/aes.c b/arch/i386/crypto/aes_32.c similarity index 100% rename from arch/i386/crypto/aes.c rename to arch/i386/crypto/aes_32.c From b673187cba8a5bcd28455b8540d8542df1d85d9b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:46 +0200 Subject: [PATCH 1874/2804] i386: prepare shared crypto/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/crypto/Makefile | 17 +++++------------ arch/i386/crypto/Makefile_32 | 12 ++++++++++++ 2 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 arch/i386/crypto/Makefile_32 diff --git a/arch/i386/crypto/Makefile b/arch/i386/crypto/Makefile index 7154b14cd950..fbd34ac2cda2 100644 --- a/arch/i386/crypto/Makefile +++ b/arch/i386/crypto/Makefile @@ -1,12 +1,5 @@ -# -# i386/crypto/Makefile -# -# Arch-specific CryptoAPI modules. -# - -obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o -obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o - -aes-i586-y := aes-i586-asm_32.o aes_32.o -twofish-i586-y := twofish-i586-asm_32.o twofish_32.o - +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/crypto/Makefile_32 +else +include ${srctree}/arch/x86_64/crypto/Makefile_64 +endif diff --git a/arch/i386/crypto/Makefile_32 b/arch/i386/crypto/Makefile_32 new file mode 100644 index 000000000000..7154b14cd950 --- /dev/null +++ b/arch/i386/crypto/Makefile_32 @@ -0,0 +1,12 @@ +# +# i386/crypto/Makefile +# +# Arch-specific CryptoAPI modules. +# + +obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o +obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o + +aes-i586-y := aes-i586-asm_32.o aes_32.o +twofish-i586-y := twofish-i586-asm_32.o twofish_32.o + From 311d64ab6dab57a4e8b012aa0da0240cf1c167e4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:47 +0200 Subject: [PATCH 1875/2804] i386: prepare shared kernel/traps.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{traps.c => traps_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{traps.c => traps_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 9d33b00de659..bd44e20d2cd9 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o init_task.o vmlinux.lds -obj-y := process.o signal.o entry.o traps.o irq.o \ +obj-y := process.o signal.o entry.o traps_32.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o bootflag.o e820.o\ quirks.o i8237.o topology.o alternative.o i8253.o tsc.o diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps_32.c similarity index 100% rename from arch/i386/kernel/traps.c rename to arch/i386/kernel/traps_32.c From 6513b15625b19abf8397a1a7099a61c453783e01 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:49 +0200 Subject: [PATCH 1876/2804] i386: prepare shared kernel/io_apic.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{io_apic.c => io_apic_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{io_apic.c => io_apic_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index bd44e20d2cd9..a0bd5aa66e15 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_SMP) += smpcommon.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o -obj-$(CONFIG_X86_IO_APIC) += io_apic.o +obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic_32.c similarity index 100% rename from arch/i386/kernel/io_apic.c rename to arch/i386/kernel/io_apic_32.c From d07ec74041a48f2ce47aa254e716e1e2c17a1191 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:50 +0200 Subject: [PATCH 1877/2804] i386: prepare shared kernel/i8253.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{i8253.c => i8253_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{i8253.c => i8253_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a0bd5aa66e15..0d09d8812238 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps_32.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o bootflag.o e820.o\ - quirks.o i8237.o topology.o alternative.o i8253.o tsc.o + quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253_32.c similarity index 100% rename from arch/i386/kernel/i8253.c rename to arch/i386/kernel/i8253_32.c From 6000e8231e177c43dac15e09a310598031631b5c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:52 +0200 Subject: [PATCH 1878/2804] i386: prepare shared kernel/srat.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{srat.c => srat_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{srat.c => srat_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 0d09d8812238..d1375fa831e6 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -32,7 +32,7 @@ obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o -obj-$(CONFIG_ACPI_SRAT) += srat.o +obj-$(CONFIG_ACPI_SRAT) += srat_32.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o obj-$(CONFIG_VM86) += vm86.o diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat_32.c similarity index 100% rename from arch/i386/kernel/srat.c rename to arch/i386/kernel/srat_32.c From dd11bb664ca533825bf9454714a9635268321882 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:53 +0200 Subject: [PATCH 1879/2804] i386: prepare shared kernel/vmiclock.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{vmiclock.c => vmiclock_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{vmiclock.c => vmiclock_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index d1375fa831e6..dd172402a4a0 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -41,7 +41,7 @@ obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_MGEODE_LX) += geode.o -obj-$(CONFIG_VMI) += vmi.o vmiclock.o +obj-$(CONFIG_VMI) += vmi.o vmiclock_32.o obj-$(CONFIG_PARAVIRT) += paravirt.o obj-y += pcspeaker.o diff --git a/arch/i386/kernel/vmiclock.c b/arch/i386/kernel/vmiclock_32.c similarity index 100% rename from arch/i386/kernel/vmiclock.c rename to arch/i386/kernel/vmiclock_32.c From de1afdd27e8d78cb53f9886202176abe3f3f950b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:54 +0200 Subject: [PATCH 1880/2804] i386: prepare shared kernel/pci-dma.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{pci-dma.c => pci-dma_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{pci-dma.c => pci-dma_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index dd172402a4a0..c9dcdc0d7778 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps_32.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ - pci-dma.o i386_ksyms.o i387.o bootflag.o e820.o\ + pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma_32.c similarity index 100% rename from arch/i386/kernel/pci-dma.c rename to arch/i386/kernel/pci-dma_32.c From b4ab0cfd7df6e74283ce6eae8d1dd6d63e28bcee Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:56 +0200 Subject: [PATCH 1881/2804] i386: prepare shared kernel/i8259.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{i8259.c => i8259_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{i8259.c => i8259_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index c9dcdc0d7778..6f3a7f211811 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps_32.o irq.o \ - ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ + ptrace.o time.o ioport.o ldt.o setup.o i8259_32.o sys_i386.o \ pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259_32.c similarity index 100% rename from arch/i386/kernel/i8259.c rename to arch/i386/kernel/i8259_32.c From 185bfbf6fac3e5bf8cd19c84aa520438a7d70022 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:57 +0200 Subject: [PATCH 1882/2804] i386: prepare shared kernel/vmi.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{vmi.c => vmi_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{vmi.c => vmi_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 6f3a7f211811..559f1f77185b 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -41,7 +41,7 @@ obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_MGEODE_LX) += geode.o -obj-$(CONFIG_VMI) += vmi.o vmiclock_32.o +obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o obj-$(CONFIG_PARAVIRT) += paravirt.o obj-y += pcspeaker.o diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi_32.c similarity index 100% rename from arch/i386/kernel/vmi.c rename to arch/i386/kernel/vmi_32.c From 5250d969f281b9f1ca581245a8797a5b7055c959 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:11:59 +0200 Subject: [PATCH 1883/2804] i386: prepare shared kernel/relocate_kernel.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{relocate_kernel.S => relocate_kernel_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{relocate_kernel.S => relocate_kernel_32.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 559f1f77185b..a677aaba33cd 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o diff --git a/arch/i386/kernel/relocate_kernel.S b/arch/i386/kernel/relocate_kernel_32.S similarity index 100% rename from arch/i386/kernel/relocate_kernel.S rename to arch/i386/kernel/relocate_kernel_32.S From 541054d935a1ec89916977cbf0d16ddb71b3ff5c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:00 +0200 Subject: [PATCH 1884/2804] i386: prepare shared kernel/syscall_table.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/entry.S | 2 +- arch/i386/kernel/{syscall_table.S => syscall_table_32.S} | 0 arch/um/sys-i386/sys_call_table.S | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/i386/kernel/{syscall_table.S => syscall_table_32.S} (100%) diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index a714d6b43506..290b7bc82da3 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -1107,6 +1107,6 @@ ENDPROC(xen_failsafe_callback) #endif /* CONFIG_XEN */ .section .rodata,"a" -#include "syscall_table.S" +#include "syscall_table_32.S" syscall_table_size=(.-sys_call_table) diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table_32.S similarity index 100% rename from arch/i386/kernel/syscall_table.S rename to arch/i386/kernel/syscall_table_32.S diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S index 2497554b7b95..4c1f17d7986d 100644 --- a/arch/um/sys-i386/sys_call_table.S +++ b/arch/um/sys-i386/sys_call_table.S @@ -9,4 +9,4 @@ #define old_mmap old_mmap_i386 -#include "../../i386/kernel/syscall_table.S" +#include "../../i386/kernel/syscall_table_32.S" From 2b91e94a6b59b63175440795b25afcd4cbfbe5e5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:02 +0200 Subject: [PATCH 1885/2804] i386: prepare shared kernel/vsyscall.lds.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 8 ++++---- arch/i386/kernel/{vsyscall.lds.S => vsyscall_32.lds.S} | 0 2 files changed, 4 insertions(+), 4 deletions(-) rename arch/i386/kernel/{vsyscall.lds.S => vsyscall_32.lds.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a677aaba33cd..a4f047cb87a6 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -52,14 +52,14 @@ obj-$(CONFIG_SCx200) += scx200.o # Note: kbuild does not track this dependency due to usage of .incbin $(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) -targets += vsyscall-note.o vsyscall.lds +targets += vsyscall-note.o vsyscall_32.lds # The DSO images are built using a special linker script. quiet_cmd_syscall = SYSCALL $@ cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \ -Wl,-T,$(filter-out FORCE,$^) -o $@ -export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH) +export CPPFLAGS_vsyscall_32.lds += -P -C -U$(ARCH) vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ $(call ld-option, -Wl$(comma)--hash-style=sysv) @@ -67,7 +67,7 @@ SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \ -$(obj)/vsyscall-%.so: $(src)/vsyscall.lds \ +$(obj)/vsyscall-%.so: $(src)/vsyscall_32.lds \ $(obj)/vsyscall-%.o $(obj)/vsyscall-note.o FORCE $(call if_changed,syscall) @@ -79,7 +79,7 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o SYSCFLAGS_vsyscall-syms.o = -r -$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \ +$(obj)/vsyscall-syms.o: $(src)/vsyscall_32.lds \ $(obj)/vsyscall-sysenter.o $(obj)/vsyscall-note.o FORCE $(call if_changed,syscall) diff --git a/arch/i386/kernel/vsyscall.lds.S b/arch/i386/kernel/vsyscall_32.lds.S similarity index 100% rename from arch/i386/kernel/vsyscall.lds.S rename to arch/i386/kernel/vsyscall_32.lds.S From 5924be937acbd1b11adb7be9b9bfab7ceda49050 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:03 +0200 Subject: [PATCH 1886/2804] i386: prepare shared kernel/smp.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{smp.c => smp_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{smp.c => smp_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a4f047cb87a6..fff92c718b62 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_APM) += apm.o -obj-$(CONFIG_X86_SMP) += smp.o smpboot.o tsc_sync.o +obj-$(CONFIG_X86_SMP) += smp_32.o smpboot.o tsc_sync.o obj-$(CONFIG_SMP) += smpcommon.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp_32.c similarity index 100% rename from arch/i386/kernel/smp.c rename to arch/i386/kernel/smp_32.c From 7338d4357bb2c8f20e400432e1fe04a22cb868ad Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:05 +0200 Subject: [PATCH 1887/2804] i386: prepare shared kernel/vm86.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{vm86.c => vm86_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{vm86.c => vm86_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index fff92c718b62..52b0041583cf 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -35,7 +35,7 @@ obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o -obj-$(CONFIG_VM86) += vm86.o +obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86_32.c similarity index 100% rename from arch/i386/kernel/vm86.c rename to arch/i386/kernel/vm86_32.c From f797f57a60514eea6fc03644c14e80691dd25727 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:06 +0200 Subject: [PATCH 1888/2804] i386: prepare shared kernel/efi_stub.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{efi_stub.S => efi_stub_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{efi_stub.S => efi_stub_32.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 52b0041583cf..f31a7f039e94 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o -obj-$(CONFIG_EFI) += efi.o efi_stub.o +obj-$(CONFIG_EFI) += efi.o efi_stub_32.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/i386/kernel/efi_stub.S b/arch/i386/kernel/efi_stub_32.S similarity index 100% rename from arch/i386/kernel/efi_stub.S rename to arch/i386/kernel/efi_stub_32.S From 08eafb9b2808d8684e55c204609513e924e2da3c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:07 +0200 Subject: [PATCH 1889/2804] i386: prepare shared kernel/crash.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{crash.c => crash_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{crash.c => crash_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index f31a7f039e94..199060e588dc 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash_32.c similarity index 100% rename from arch/i386/kernel/crash.c rename to arch/i386/kernel/crash_32.c From 8d0d37cfb8039939f51dd2a1da98aff3b50a4e84 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:08 +0200 Subject: [PATCH 1890/2804] i386: prepare shared kernel/asm-offsets.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/asm-offsets.c | 150 +----------------------------- arch/i386/kernel/asm-offsets_32.c | 147 +++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 146 deletions(-) create mode 100644 arch/i386/kernel/asm-offsets_32.c diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c index 7288ac88d746..cfa82c899f47 100644 --- a/arch/i386/kernel/asm-offsets.c +++ b/arch/i386/kernel/asm-offsets.c @@ -1,147 +1,5 @@ -/* - * Generate definitions needed by assembly language modules. - * This code generates raw asm output which is post-processed - * to extract and format the required data. - */ - -#include -#include -#include -#include -#include -#include -#include "sigframe.h" -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_LGUEST_GUEST -#include -#include "../../../drivers/lguest/lg.h" +#ifdef CONFIG_X86_32 +# include "asm-offsets_32.c" +#else +# include "asm-offsets_64.c" #endif - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define BLANK() asm volatile("\n->" : : ) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -/* workaround for a warning with -Wmissing-prototypes */ -void foo(void); - -void foo(void) -{ - OFFSET(SIGCONTEXT_eax, sigcontext, eax); - OFFSET(SIGCONTEXT_ebx, sigcontext, ebx); - OFFSET(SIGCONTEXT_ecx, sigcontext, ecx); - OFFSET(SIGCONTEXT_edx, sigcontext, edx); - OFFSET(SIGCONTEXT_esi, sigcontext, esi); - OFFSET(SIGCONTEXT_edi, sigcontext, edi); - OFFSET(SIGCONTEXT_ebp, sigcontext, ebp); - OFFSET(SIGCONTEXT_esp, sigcontext, esp); - OFFSET(SIGCONTEXT_eip, sigcontext, eip); - BLANK(); - - OFFSET(CPUINFO_x86, cpuinfo_x86, x86); - OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor); - OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model); - OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask); - OFFSET(CPUINFO_hard_math, cpuinfo_x86, hard_math); - OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level); - OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability); - OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id); - BLANK(); - - OFFSET(TI_task, thread_info, task); - OFFSET(TI_exec_domain, thread_info, exec_domain); - OFFSET(TI_flags, thread_info, flags); - OFFSET(TI_status, thread_info, status); - OFFSET(TI_preempt_count, thread_info, preempt_count); - OFFSET(TI_addr_limit, thread_info, addr_limit); - OFFSET(TI_restart_block, thread_info, restart_block); - OFFSET(TI_sysenter_return, thread_info, sysenter_return); - OFFSET(TI_cpu, thread_info, cpu); - BLANK(); - - OFFSET(GDS_size, Xgt_desc_struct, size); - OFFSET(GDS_address, Xgt_desc_struct, address); - OFFSET(GDS_pad, Xgt_desc_struct, pad); - BLANK(); - - OFFSET(PT_EBX, pt_regs, ebx); - OFFSET(PT_ECX, pt_regs, ecx); - OFFSET(PT_EDX, pt_regs, edx); - OFFSET(PT_ESI, pt_regs, esi); - OFFSET(PT_EDI, pt_regs, edi); - OFFSET(PT_EBP, pt_regs, ebp); - OFFSET(PT_EAX, pt_regs, eax); - OFFSET(PT_DS, pt_regs, xds); - OFFSET(PT_ES, pt_regs, xes); - OFFSET(PT_FS, pt_regs, xfs); - OFFSET(PT_ORIG_EAX, pt_regs, orig_eax); - OFFSET(PT_EIP, pt_regs, eip); - OFFSET(PT_CS, pt_regs, xcs); - OFFSET(PT_EFLAGS, pt_regs, eflags); - OFFSET(PT_OLDESP, pt_regs, esp); - OFFSET(PT_OLDSS, pt_regs, xss); - BLANK(); - - OFFSET(EXEC_DOMAIN_handler, exec_domain, handler); - OFFSET(RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext); - BLANK(); - - OFFSET(pbe_address, pbe, address); - OFFSET(pbe_orig_address, pbe, orig_address); - OFFSET(pbe_next, pbe, next); - - /* Offset from the sysenter stack to tss.esp0 */ - DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, x86_tss.esp0) - - sizeof(struct tss_struct)); - - DEFINE(PAGE_SIZE_asm, PAGE_SIZE); - DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT); - DEFINE(PTRS_PER_PTE, PTRS_PER_PTE); - DEFINE(PTRS_PER_PMD, PTRS_PER_PMD); - DEFINE(PTRS_PER_PGD, PTRS_PER_PGD); - - DEFINE(VDSO_PRELINK_asm, VDSO_PRELINK); - - OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); - -#ifdef CONFIG_PARAVIRT - BLANK(); - OFFSET(PARAVIRT_enabled, paravirt_ops, paravirt_enabled); - OFFSET(PARAVIRT_irq_disable, paravirt_ops, irq_disable); - OFFSET(PARAVIRT_irq_enable, paravirt_ops, irq_enable); - OFFSET(PARAVIRT_irq_enable_sysexit, paravirt_ops, irq_enable_sysexit); - OFFSET(PARAVIRT_iret, paravirt_ops, iret); - OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0); -#endif - -#ifdef CONFIG_XEN - BLANK(); - OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask); - OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending); -#endif - -#ifdef CONFIG_LGUEST_GUEST - BLANK(); - OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled); - OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc); - OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc); - OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3); - OFFSET(LGUEST_PAGES_host_sp, lguest_pages, state.host_sp); - OFFSET(LGUEST_PAGES_guest_gdt_desc, lguest_pages,state.guest_gdt_desc); - OFFSET(LGUEST_PAGES_guest_idt_desc, lguest_pages,state.guest_idt_desc); - OFFSET(LGUEST_PAGES_guest_gdt, lguest_pages, state.guest_gdt); - OFFSET(LGUEST_PAGES_regs_trapnum, lguest_pages, regs.trapnum); - OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode); - OFFSET(LGUEST_PAGES_regs, lguest_pages, regs); -#endif -} diff --git a/arch/i386/kernel/asm-offsets_32.c b/arch/i386/kernel/asm-offsets_32.c new file mode 100644 index 000000000000..7288ac88d746 --- /dev/null +++ b/arch/i386/kernel/asm-offsets_32.c @@ -0,0 +1,147 @@ +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed + * to extract and format the required data. + */ + +#include +#include +#include +#include +#include +#include +#include "sigframe.h" +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_LGUEST_GUEST +#include +#include "../../../drivers/lguest/lg.h" +#endif + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +#define OFFSET(sym, str, mem) \ + DEFINE(sym, offsetof(struct str, mem)); + +/* workaround for a warning with -Wmissing-prototypes */ +void foo(void); + +void foo(void) +{ + OFFSET(SIGCONTEXT_eax, sigcontext, eax); + OFFSET(SIGCONTEXT_ebx, sigcontext, ebx); + OFFSET(SIGCONTEXT_ecx, sigcontext, ecx); + OFFSET(SIGCONTEXT_edx, sigcontext, edx); + OFFSET(SIGCONTEXT_esi, sigcontext, esi); + OFFSET(SIGCONTEXT_edi, sigcontext, edi); + OFFSET(SIGCONTEXT_ebp, sigcontext, ebp); + OFFSET(SIGCONTEXT_esp, sigcontext, esp); + OFFSET(SIGCONTEXT_eip, sigcontext, eip); + BLANK(); + + OFFSET(CPUINFO_x86, cpuinfo_x86, x86); + OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor); + OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model); + OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask); + OFFSET(CPUINFO_hard_math, cpuinfo_x86, hard_math); + OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level); + OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability); + OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id); + BLANK(); + + OFFSET(TI_task, thread_info, task); + OFFSET(TI_exec_domain, thread_info, exec_domain); + OFFSET(TI_flags, thread_info, flags); + OFFSET(TI_status, thread_info, status); + OFFSET(TI_preempt_count, thread_info, preempt_count); + OFFSET(TI_addr_limit, thread_info, addr_limit); + OFFSET(TI_restart_block, thread_info, restart_block); + OFFSET(TI_sysenter_return, thread_info, sysenter_return); + OFFSET(TI_cpu, thread_info, cpu); + BLANK(); + + OFFSET(GDS_size, Xgt_desc_struct, size); + OFFSET(GDS_address, Xgt_desc_struct, address); + OFFSET(GDS_pad, Xgt_desc_struct, pad); + BLANK(); + + OFFSET(PT_EBX, pt_regs, ebx); + OFFSET(PT_ECX, pt_regs, ecx); + OFFSET(PT_EDX, pt_regs, edx); + OFFSET(PT_ESI, pt_regs, esi); + OFFSET(PT_EDI, pt_regs, edi); + OFFSET(PT_EBP, pt_regs, ebp); + OFFSET(PT_EAX, pt_regs, eax); + OFFSET(PT_DS, pt_regs, xds); + OFFSET(PT_ES, pt_regs, xes); + OFFSET(PT_FS, pt_regs, xfs); + OFFSET(PT_ORIG_EAX, pt_regs, orig_eax); + OFFSET(PT_EIP, pt_regs, eip); + OFFSET(PT_CS, pt_regs, xcs); + OFFSET(PT_EFLAGS, pt_regs, eflags); + OFFSET(PT_OLDESP, pt_regs, esp); + OFFSET(PT_OLDSS, pt_regs, xss); + BLANK(); + + OFFSET(EXEC_DOMAIN_handler, exec_domain, handler); + OFFSET(RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext); + BLANK(); + + OFFSET(pbe_address, pbe, address); + OFFSET(pbe_orig_address, pbe, orig_address); + OFFSET(pbe_next, pbe, next); + + /* Offset from the sysenter stack to tss.esp0 */ + DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, x86_tss.esp0) - + sizeof(struct tss_struct)); + + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT); + DEFINE(PTRS_PER_PTE, PTRS_PER_PTE); + DEFINE(PTRS_PER_PMD, PTRS_PER_PMD); + DEFINE(PTRS_PER_PGD, PTRS_PER_PGD); + + DEFINE(VDSO_PRELINK_asm, VDSO_PRELINK); + + OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); + +#ifdef CONFIG_PARAVIRT + BLANK(); + OFFSET(PARAVIRT_enabled, paravirt_ops, paravirt_enabled); + OFFSET(PARAVIRT_irq_disable, paravirt_ops, irq_disable); + OFFSET(PARAVIRT_irq_enable, paravirt_ops, irq_enable); + OFFSET(PARAVIRT_irq_enable_sysexit, paravirt_ops, irq_enable_sysexit); + OFFSET(PARAVIRT_iret, paravirt_ops, iret); + OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0); +#endif + +#ifdef CONFIG_XEN + BLANK(); + OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask); + OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending); +#endif + +#ifdef CONFIG_LGUEST_GUEST + BLANK(); + OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled); + OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc); + OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc); + OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3); + OFFSET(LGUEST_PAGES_host_sp, lguest_pages, state.host_sp); + OFFSET(LGUEST_PAGES_guest_gdt_desc, lguest_pages,state.guest_gdt_desc); + OFFSET(LGUEST_PAGES_guest_idt_desc, lguest_pages,state.guest_idt_desc); + OFFSET(LGUEST_PAGES_guest_gdt, lguest_pages, state.guest_gdt); + OFFSET(LGUEST_PAGES_regs_trapnum, lguest_pages, regs.trapnum); + OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode); + OFFSET(LGUEST_PAGES_regs, lguest_pages, regs); +#endif +} From f9a4ddc72107a30a2999d717479efd93689a54bb Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:09 +0200 Subject: [PATCH 1891/2804] i386: prepare shared kernel/efi.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{efi.c => efi_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{efi.c => efi_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 199060e588dc..75b201b56074 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o -obj-$(CONFIG_EFI) += efi.o efi_stub_32.o +obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi_32.c similarity index 100% rename from arch/i386/kernel/efi.c rename to arch/i386/kernel/efi_32.c From caadc5e249a19596b1c8400bf8e71320e4f0a14f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:11 +0200 Subject: [PATCH 1892/2804] i386: prepare shared kernel/module.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{module.c => module_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{module.c => module_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 75b201b56074..1f82d76447d6 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o obj-$(CONFIG_KPROBES) += kprobes.o -obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_MODULES) += module_32.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o diff --git a/arch/i386/kernel/module.c b/arch/i386/kernel/module_32.c similarity index 100% rename from arch/i386/kernel/module.c rename to arch/i386/kernel/module_32.c From a60b778b5a813c6b3663db9244f5a886f0f91027 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:11 +0200 Subject: [PATCH 1893/2804] i386: prepare shared kernel/vmlinux.lds.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/vmlinux.lds.S | 216 +----------------------------- arch/i386/kernel/vmlinux_32.lds.S | 213 +++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 212 deletions(-) create mode 100644 arch/i386/kernel/vmlinux_32.lds.S diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index 7d72cce00529..849ee611f013 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S @@ -1,213 +1,5 @@ -/* ld script to make i386 Linux kernel - * Written by Martin Mares ; - * - * Don't define absolute symbols until and unless you know that symbol - * value is should remain constant even if kernel image is relocated - * at run time. Absolute symbols are not relocated. If symbol value should - * change if kernel is relocated, make the symbol section relative and - * put it inside the section definition. - */ - -/* Don't define absolute symbols until and unless you know that symbol - * value is should remain constant even if kernel image is relocated - * at run time. Absolute symbols are not relocated. If symbol value should - * change if kernel is relocated, make the symbol section relative and - * put it inside the section definition. - */ -#define LOAD_OFFSET __PAGE_OFFSET - -#include -#include -#include -#include -#include - -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -ENTRY(phys_startup_32) -jiffies = jiffies_64; - -PHDRS { - text PT_LOAD FLAGS(5); /* R_E */ - data PT_LOAD FLAGS(7); /* RWE */ - note PT_NOTE FLAGS(0); /* ___ */ -} -SECTIONS -{ - . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; - phys_startup_32 = startup_32 - LOAD_OFFSET; - - .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { - _text = .; /* Text and read-only data */ - *(.text.head) - } :text = 0x9090 - - /* read-only */ - .text : AT(ADDR(.text) - LOAD_OFFSET) { - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) - *(.gnu.warning) - _etext = .; /* End of text section */ - } :text = 0x9090 - - . = ALIGN(16); /* Exception table */ - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } - - NOTES :text :note - - BUG_TABLE :text - - . = ALIGN(4); - .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { - __tracedata_start = .; - *(.tracedata) - __tracedata_end = .; - } - - RODATA - - /* writeable */ - . = ALIGN(4096); - .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ - DATA_DATA - CONSTRUCTORS - } :data - - . = ALIGN(4096); - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { - __nosave_begin = .; - *(.data.nosave) - . = ALIGN(4096); - __nosave_end = .; - } - - . = ALIGN(4096); - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { - *(.data.page_aligned) - *(.data.idt) - } - - . = ALIGN(32); - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { - *(.data.cacheline_aligned) - } - - /* rarely changed data like cpu maps */ - . = ALIGN(32); - .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { - *(.data.read_mostly) - _edata = .; /* End of data section */ - } - - . = ALIGN(THREAD_SIZE); /* init_task */ - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { - *(.data.init_task) - } - - /* might get freed after init */ - . = ALIGN(4096); - .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { - __smp_locks = .; - *(.smp_locks) - __smp_locks_end = .; - } - /* will be freed after init - * Following ALIGN() is required to make sure no other data falls on the - * same page where __smp_alt_end is pointing as that page might be freed - * after boot. Always make sure that ALIGN() directive is present after - * the section which contains __smp_alt_end. - */ - . = ALIGN(4096); - - /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ - .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { - __init_begin = .; - _sinittext = .; - *(.init.text) - _einittext = .; - } - .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } - . = ALIGN(16); - .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { - __setup_start = .; - *(.init.setup) - __setup_end = .; - } - .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { - __initcall_start = .; - INITCALLS - __initcall_end = .; - } - .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { - __con_initcall_start = .; - *(.con_initcall.init) - __con_initcall_end = .; - } - SECURITY_INIT - . = ALIGN(4); - .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { - __alt_instructions = .; - *(.altinstructions) - __alt_instructions_end = .; - } - .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { - *(.altinstr_replacement) - } - . = ALIGN(4); - .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { - __parainstructions = .; - *(.parainstructions) - __parainstructions_end = .; - } - /* .exit.text is discard at runtime, not link time, to deal with references - from .altinstructions and .eh_frame */ - .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } - .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } -#if defined(CONFIG_BLK_DEV_INITRD) - . = ALIGN(4096); - .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { - __initramfs_start = .; - *(.init.ramfs) - __initramfs_end = .; - } +#ifdef CONFIG_X86_32 +# include "vmlinux_32.lds.S" +#else +# include "vmlinux_64.lds.S" #endif - . = ALIGN(4096); - .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { - __per_cpu_start = .; - *(.data.percpu) - *(.data.percpu.shared_aligned) - __per_cpu_end = .; - } - . = ALIGN(4096); - /* freed after init ends here */ - - .bss : AT(ADDR(.bss) - LOAD_OFFSET) { - __init_end = .; - __bss_start = .; /* BSS */ - *(.bss.page_aligned) - *(.bss) - . = ALIGN(4); - __bss_stop = .; - _end = . ; - /* This is where the kernel creates the early boot page tables */ - . = ALIGN(4096); - pg0 = . ; - } - - /* Sections to be discarded */ - /DISCARD/ : { - *(.exitcall.exit) - } - - STABS_DEBUG - - DWARF_DEBUG -} diff --git a/arch/i386/kernel/vmlinux_32.lds.S b/arch/i386/kernel/vmlinux_32.lds.S new file mode 100644 index 000000000000..7d72cce00529 --- /dev/null +++ b/arch/i386/kernel/vmlinux_32.lds.S @@ -0,0 +1,213 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + * + * Don't define absolute symbols until and unless you know that symbol + * value is should remain constant even if kernel image is relocated + * at run time. Absolute symbols are not relocated. If symbol value should + * change if kernel is relocated, make the symbol section relative and + * put it inside the section definition. + */ + +/* Don't define absolute symbols until and unless you know that symbol + * value is should remain constant even if kernel image is relocated + * at run time. Absolute symbols are not relocated. If symbol value should + * change if kernel is relocated, make the symbol section relative and + * put it inside the section definition. + */ +#define LOAD_OFFSET __PAGE_OFFSET + +#include +#include +#include +#include +#include + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(phys_startup_32) +jiffies = jiffies_64; + +PHDRS { + text PT_LOAD FLAGS(5); /* R_E */ + data PT_LOAD FLAGS(7); /* RWE */ + note PT_NOTE FLAGS(0); /* ___ */ +} +SECTIONS +{ + . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; + phys_startup_32 = startup_32 - LOAD_OFFSET; + + .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { + _text = .; /* Text and read-only data */ + *(.text.head) + } :text = 0x9090 + + /* read-only */ + .text : AT(ADDR(.text) - LOAD_OFFSET) { + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + *(.fixup) + *(.gnu.warning) + _etext = .; /* End of text section */ + } :text = 0x9090 + + . = ALIGN(16); /* Exception table */ + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } + + NOTES :text :note + + BUG_TABLE :text + + . = ALIGN(4); + .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { + __tracedata_start = .; + *(.tracedata) + __tracedata_end = .; + } + + RODATA + + /* writeable */ + . = ALIGN(4096); + .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ + DATA_DATA + CONSTRUCTORS + } :data + + . = ALIGN(4096); + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { + __nosave_begin = .; + *(.data.nosave) + . = ALIGN(4096); + __nosave_end = .; + } + + . = ALIGN(4096); + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + *(.data.page_aligned) + *(.data.idt) + } + + . = ALIGN(32); + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { + *(.data.cacheline_aligned) + } + + /* rarely changed data like cpu maps */ + . = ALIGN(32); + .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { + *(.data.read_mostly) + _edata = .; /* End of data section */ + } + + . = ALIGN(THREAD_SIZE); /* init_task */ + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) + } + + /* might get freed after init */ + . = ALIGN(4096); + .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { + __smp_locks = .; + *(.smp_locks) + __smp_locks_end = .; + } + /* will be freed after init + * Following ALIGN() is required to make sure no other data falls on the + * same page where __smp_alt_end is pointing as that page might be freed + * after boot. Always make sure that ALIGN() directive is present after + * the section which contains __smp_alt_end. + */ + . = ALIGN(4096); + + /* will be freed after init */ + . = ALIGN(4096); /* Init code and data */ + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { + __init_begin = .; + _sinittext = .; + *(.init.text) + _einittext = .; + } + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } + . = ALIGN(16); + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { + __initcall_start = .; + INITCALLS + __initcall_end = .; + } + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + } + SECURITY_INIT + . = ALIGN(4); + .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { + __alt_instructions = .; + *(.altinstructions) + __alt_instructions_end = .; + } + .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { + *(.altinstr_replacement) + } + . = ALIGN(4); + .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { + __parainstructions = .; + *(.parainstructions) + __parainstructions_end = .; + } + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } + .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } +#if defined(CONFIG_BLK_DEV_INITRD) + . = ALIGN(4096); + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } +#endif + . = ALIGN(4096); + .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { + __per_cpu_start = .; + *(.data.percpu) + *(.data.percpu.shared_aligned) + __per_cpu_end = .; + } + . = ALIGN(4096); + /* freed after init ends here */ + + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { + __init_end = .; + __bss_start = .; /* BSS */ + *(.bss.page_aligned) + *(.bss) + . = ALIGN(4); + __bss_stop = .; + _end = . ; + /* This is where the kernel creates the early boot page tables */ + . = ALIGN(4096); + pg0 = . ; + } + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exitcall.exit) + } + + STABS_DEBUG + + DWARF_DEBUG +} From cde82b404831aecccf2a1828b2dc643e0ac0e7ce Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:13 +0200 Subject: [PATCH 1894/2804] i386: prepare shared kernel/vsyscall.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 6 +++--- arch/i386/kernel/{vsyscall.S => vsyscall_32.S} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename arch/i386/kernel/{vsyscall.S => vsyscall_32.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 1f82d76447d6..f502c141c1df 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module_32.o -obj-y += sysenter.o vsyscall.o +obj-y += sysenter.o vsyscall_32.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o @@ -47,10 +47,10 @@ obj-y += pcspeaker.o obj-$(CONFIG_SCx200) += scx200.o -# vsyscall.o contains the vsyscall DSO images as __initdata. +# vsyscall_32.o contains the vsyscall DSO images as __initdata. # We must build both images before we can assemble it. # Note: kbuild does not track this dependency due to usage of .incbin -$(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so +$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) targets += vsyscall-note.o vsyscall_32.lds diff --git a/arch/i386/kernel/vsyscall.S b/arch/i386/kernel/vsyscall_32.S similarity index 100% rename from arch/i386/kernel/vsyscall.S rename to arch/i386/kernel/vsyscall_32.S From b9fe30ac5cdfc4337a672a498a4ba4e8d5e18728 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:14 +0200 Subject: [PATCH 1895/2804] i386: prepare shared kernel/paravirt.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{paravirt.c => paravirt_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{paravirt.c => paravirt_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index f502c141c1df..b37e2d200430 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -42,7 +42,7 @@ obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_MGEODE_LX) += geode.o obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o -obj-$(CONFIG_PARAVIRT) += paravirt.o +obj-$(CONFIG_PARAVIRT) += paravirt_32.o obj-y += pcspeaker.o obj-$(CONFIG_SCx200) += scx200.o diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt_32.c similarity index 100% rename from arch/i386/kernel/paravirt.c rename to arch/i386/kernel/paravirt_32.c From 0cc369a273ac6bacee9614b643de1fa283967a68 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:16 +0200 Subject: [PATCH 1896/2804] i386: prepare shared kernel/apic.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{apic.c => apic_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{apic.c => apic_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index b37e2d200430..a239a5e401a2 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_X86_SMP) += smp_32.o smpboot.o tsc_sync.o obj-$(CONFIG_SMP) += smpcommon.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o -obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o +obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic_32.c similarity index 100% rename from arch/i386/kernel/apic.c rename to arch/i386/kernel/apic_32.c From 45da5aa2352153c7523dd42bb54e9378995b2194 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:17 +0200 Subject: [PATCH 1897/2804] i386: prepare shared kernel/sys_i386.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{sys_i386.c => sys_i386_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{sys_i386.c => sys_i386_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a239a5e401a2..2d22e13ecfd8 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps_32.o irq.o \ - ptrace.o time.o ioport.o ldt.o setup.o i8259_32.o sys_i386.o \ + ptrace.o time.o ioport.o ldt.o setup.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386_32.c similarity index 100% rename from arch/i386/kernel/sys_i386.c rename to arch/i386/kernel/sys_i386_32.c From 77399ad90a8bd05f4b16da2ee398062d89f1719c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:19 +0200 Subject: [PATCH 1898/2804] i386: prepare shared kernel/nmi.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{nmi.c => nmi_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{nmi.c => nmi_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 2d22e13ecfd8..4967012119ae 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_X86_SMP) += smp_32.o smpboot.o tsc_sync.o obj-$(CONFIG_SMP) += smpcommon.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o -obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi.o +obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi_32.c similarity index 100% rename from arch/i386/kernel/nmi.c rename to arch/i386/kernel/nmi_32.c From ae47fd49c73b7f4875bd1bf06f02f4209d5d2470 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:20 +0200 Subject: [PATCH 1899/2804] i386: prepare shared kernel/hpet.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{hpet.c => hpet_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{hpet.c => hpet_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 4967012119ae..8bd7e8730046 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -37,7 +37,7 @@ obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_HPET_TIMER) += hpet.o +obj-$(CONFIG_HPET_TIMER) += hpet_32.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_MGEODE_LX) += geode.o diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet_32.c similarity index 100% rename from arch/i386/kernel/hpet.c rename to arch/i386/kernel/hpet_32.c From a6424facfa0fceb57982df3a6d7e6166c94c22be Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:21 +0200 Subject: [PATCH 1900/2804] i386: prepare shared kernel/sysenter.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{sysenter.c => sysenter_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{sysenter.c => sysenter_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 8bd7e8730046..ed9f4f49a6a2 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module_32.o -obj-y += sysenter.o vsyscall_32.o +obj-y += sysenter_32.o vsyscall_32.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter_32.c similarity index 100% rename from arch/i386/kernel/sysenter.c rename to arch/i386/kernel/sysenter_32.c From 5d43542f0c223e3643d88adb05ed466e6f0c8337 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:23 +0200 Subject: [PATCH 1901/2804] i386: prepare shared kernel/e820.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{e820.c => e820_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{e820.c => e820_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index ed9f4f49a6a2..670bfdf57b6c 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps_32.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259_32.o sys_i386_32.o \ - pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820.o\ + pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820_32.c similarity index 100% rename from arch/i386/kernel/e820.c rename to arch/i386/kernel/e820_32.c From 0273be2dcee34d3b955348cebef92cd796f06717 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:24 +0200 Subject: [PATCH 1902/2804] i386: prepare shared kernel/smpboot.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{smpboot.c => smpboot_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{smpboot.c => smpboot_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 670bfdf57b6c..3b7a82d23950 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_APM) += apm.o -obj-$(CONFIG_X86_SMP) += smp_32.o smpboot.o tsc_sync.o +obj-$(CONFIG_X86_SMP) += smp_32.o smpboot_32.o tsc_sync.o obj-$(CONFIG_SMP) += smpcommon.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot_32.c similarity index 100% rename from arch/i386/kernel/smpboot.c rename to arch/i386/kernel/smpboot_32.c From 016f8118b4f333cf88237918245be94788f0c51a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:26 +0200 Subject: [PATCH 1903/2804] i386: prepare shared kernel/geode.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{geode.c => geode_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{geode.c => geode_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 3b7a82d23950..4809425113f4 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -39,7 +39,7 @@ obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_HPET_TIMER) += hpet_32.o obj-$(CONFIG_K8_NB) += k8.o -obj-$(CONFIG_MGEODE_LX) += geode.o +obj-$(CONFIG_MGEODE_LX) += geode_32.o obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o obj-$(CONFIG_PARAVIRT) += paravirt_32.o diff --git a/arch/i386/kernel/geode.c b/arch/i386/kernel/geode_32.c similarity index 100% rename from arch/i386/kernel/geode.c rename to arch/i386/kernel/geode_32.c From 549c64ac41fd37236543143a4e92699958a3972e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:27 +0200 Subject: [PATCH 1904/2804] i386: prepare shared kernel/setup.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{setup.c => setup_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{setup.c => setup_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 4809425113f4..a832c417b1e7 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps_32.o irq.o \ - ptrace.o time.o ioport.o ldt.o setup.o i8259_32.o sys_i386_32.o \ + ptrace.o time.o ioport.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup_32.c similarity index 100% rename from arch/i386/kernel/setup.c rename to arch/i386/kernel/setup_32.c From d4c3a41e9a1f72bb995a6fb89ad028eda9a14c3d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:29 +0200 Subject: [PATCH 1905/2804] i386: prepare shared kernel/ioport.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{ioport.c => ioport_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{ioport.c => ioport_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a832c417b1e7..38d2b469a891 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal.o entry.o traps_32.o irq.o \ - ptrace.o time.o ioport.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ + ptrace.o time.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport_32.c similarity index 100% rename from arch/i386/kernel/ioport.c rename to arch/i386/kernel/ioport_32.c From 24f5b95bb91a6edac5dfdc7ddcbd6cabe0b30430 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:30 +0200 Subject: [PATCH 1906/2804] i386: prepare shared kernel/vsyscall-int80.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 6 +++--- arch/i386/kernel/{vsyscall-int80.S => vsyscall-int80_32.S} | 0 arch/i386/kernel/vsyscall_32.S | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename arch/i386/kernel/{vsyscall-int80.S => vsyscall-int80_32.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 38d2b469a891..84297d470df2 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_SCx200) += scx200.o # vsyscall_32.o contains the vsyscall DSO images as __initdata. # We must build both images before we can assemble it. # Note: kbuild does not track this dependency due to usage of .incbin -$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so +$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter.so targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) targets += vsyscall-note.o vsyscall_32.lds @@ -64,9 +64,9 @@ export CPPFLAGS_vsyscall_32.lds += -P -C -U$(ARCH) vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ $(call ld-option, -Wl$(comma)--hash-style=sysv) SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) -SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) +SYSCFLAGS_vsyscall-int80_32.so = $(vsyscall-flags) -$(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \ +$(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter.so: \ $(obj)/vsyscall-%.so: $(src)/vsyscall_32.lds \ $(obj)/vsyscall-%.o $(obj)/vsyscall-note.o FORCE $(call if_changed,syscall) diff --git a/arch/i386/kernel/vsyscall-int80.S b/arch/i386/kernel/vsyscall-int80_32.S similarity index 100% rename from arch/i386/kernel/vsyscall-int80.S rename to arch/i386/kernel/vsyscall-int80_32.S diff --git a/arch/i386/kernel/vsyscall_32.S b/arch/i386/kernel/vsyscall_32.S index b403890fe39b..033074479fca 100644 --- a/arch/i386/kernel/vsyscall_32.S +++ b/arch/i386/kernel/vsyscall_32.S @@ -4,12 +4,12 @@ __INITDATA .globl vsyscall_int80_start, vsyscall_int80_end vsyscall_int80_start: - .incbin "arch/i386/kernel/vsyscall-int80.so" + .incbin "arch/i386/kernel/vsyscall-int80_32.so" vsyscall_int80_end: .globl vsyscall_sysenter_start, vsyscall_sysenter_end vsyscall_sysenter_start: - .incbin "arch/i386/kernel/vsyscall-sysenter.so" + .incbin "arch/i386/kernel/vsyscall-sysenter_32.so" vsyscall_sysenter_end: __FINIT From a584dfcc686c5ed89a234f2166ddaf73ec22f31a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:31 +0200 Subject: [PATCH 1907/2804] i386: prepare shared kernel/summit.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{summit.c => summit_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{summit.c => summit_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 84297d470df2..838f347c2580 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_X86_NUMAQ) += numaq.o -obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o +obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module_32.o obj-y += sysenter_32.o vsyscall_32.o diff --git a/arch/i386/kernel/summit.c b/arch/i386/kernel/summit_32.c similarity index 100% rename from arch/i386/kernel/summit.c rename to arch/i386/kernel/summit_32.c From 2512e7c5c1851951ba4a625b84b4400bf6150625 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:33 +0200 Subject: [PATCH 1908/2804] i386: prepare shared kernel/signal.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{signal.c => signal_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{signal.c => signal_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 838f347c2580..4ff5e93d23c9 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o init_task.o vmlinux.lds -obj-y := process.o signal.o entry.o traps_32.o irq.o \ +obj-y := process.o signal_32.o entry.o traps_32.o irq.o \ ptrace.o time.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal_32.c similarity index 100% rename from arch/i386/kernel/signal.c rename to arch/i386/kernel/signal_32.c From 24d8d25f1563f25c365cc6895bfc88af0b90ee40 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:34 +0200 Subject: [PATCH 1909/2804] i386: prepare shared kernel/reboot_fixups.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{reboot_fixups.c => reboot_fixups_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{reboot_fixups.c => reboot_fixups_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 4ff5e93d23c9..57b41c4d5fde 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o -obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o +obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_X86_NUMAQ) += numaq.o diff --git a/arch/i386/kernel/reboot_fixups.c b/arch/i386/kernel/reboot_fixups_32.c similarity index 100% rename from arch/i386/kernel/reboot_fixups.c rename to arch/i386/kernel/reboot_fixups_32.c From eea21b3055b76705a718b6864152d8ec85cbe942 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:36 +0200 Subject: [PATCH 1910/2804] i386: prepare shared kernel/i387.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{i387.c => i387_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{i387.c => i387_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 57b41c4d5fde..70820d5622bd 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal_32.o entry.o traps_32.o irq.o \ ptrace.o time.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ - pci-dma_32.o i386_ksyms.o i387.o bootflag.o e820_32.o\ + pci-dma_32.o i386_ksyms.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387_32.c similarity index 100% rename from arch/i386/kernel/i387.c rename to arch/i386/kernel/i387_32.c From 30271a74772402764997e84cc5f6cab57d36418d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:37 +0200 Subject: [PATCH 1911/2804] i386: prepare shared kernel/numaq.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{numaq.c => numaq_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{numaq.c => numaq_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 70820d5622bd..c731008620da 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o -obj-$(CONFIG_X86_NUMAQ) += numaq.o +obj-$(CONFIG_X86_NUMAQ) += numaq_32.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module_32.o diff --git a/arch/i386/kernel/numaq.c b/arch/i386/kernel/numaq_32.c similarity index 100% rename from arch/i386/kernel/numaq.c rename to arch/i386/kernel/numaq_32.c From 4f09b00fce5ba7bc00425f91860e81571472fbe8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:39 +0200 Subject: [PATCH 1912/2804] i386: prepare shared kernel/smpcommon.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{smpcommon.c => smpcommon_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{smpcommon.c => smpcommon_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index c731008620da..65ce290d7387 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_X86_SMP) += smp_32.o smpboot_32.o tsc_sync.o -obj-$(CONFIG_SMP) += smpcommon.o +obj-$(CONFIG_SMP) += smpcommon_32.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o diff --git a/arch/i386/kernel/smpcommon.c b/arch/i386/kernel/smpcommon_32.c similarity index 100% rename from arch/i386/kernel/smpcommon.c rename to arch/i386/kernel/smpcommon_32.c From aeb369d26ecfdde242f29d16c41bed562410e392 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:40 +0200 Subject: [PATCH 1913/2804] i386: prepare shared kernel/mca.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{mca.c => mca_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{mca.c => mca_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 65ce290d7387..a1dcc9d5a900 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ obj-y += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o -obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o diff --git a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca_32.c similarity index 100% rename from arch/i386/kernel/mca.c rename to arch/i386/kernel/mca_32.c From f14ff3c8f151ac0ed487df18be01b0b32d70dd5e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:41 +0200 Subject: [PATCH 1914/2804] i386: prepare shared kernel/i386_ksyms.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{i386_ksyms.c => i386_ksyms_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{i386_ksyms.c => i386_ksyms_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a1dcc9d5a900..a2a072623c9a 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal_32.o entry.o traps_32.o irq.o \ ptrace.o time.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ - pci-dma_32.o i386_ksyms.o i387_32.o bootflag.o e820_32.o\ + pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms_32.c similarity index 100% rename from arch/i386/kernel/i386_ksyms.c rename to arch/i386/kernel/i386_ksyms_32.c From 128ffcdab2e74292ead956f257e10d288a215e06 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:43 +0200 Subject: [PATCH 1915/2804] i386: prepare shared kernel/doublefault.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{doublefault.c => doublefault_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{doublefault.c => doublefault_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a2a072623c9a..8c739b03eff8 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_MODULES) += module_32.o obj-y += sysenter_32.o vsyscall_32.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o -obj-$(CONFIG_DOUBLEFAULT) += doublefault.o +obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_HPET_TIMER) += hpet_32.o diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault_32.c similarity index 100% rename from arch/i386/kernel/doublefault.c rename to arch/i386/kernel/doublefault_32.c From 5bdef8fd610b8b07cf58ad2139f1f76bf127ad5d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:44 +0200 Subject: [PATCH 1916/2804] i386: prepare shared kernel/vsyscall-sysenter.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 8 ++++---- .../{vsyscall-sysenter.S => vsyscall-sysenter_32.S} | 0 2 files changed, 4 insertions(+), 4 deletions(-) rename arch/i386/kernel/{vsyscall-sysenter.S => vsyscall-sysenter_32.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 8c739b03eff8..4e4b1fa96157 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_SCx200) += scx200.o # vsyscall_32.o contains the vsyscall DSO images as __initdata. # We must build both images before we can assemble it. # Note: kbuild does not track this dependency due to usage of .incbin -$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter.so +$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) targets += vsyscall-note.o vsyscall_32.lds @@ -63,10 +63,10 @@ export CPPFLAGS_vsyscall_32.lds += -P -C -U$(ARCH) vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ $(call ld-option, -Wl$(comma)--hash-style=sysv) -SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) +SYSCFLAGS_vsyscall-sysenter_32.so = $(vsyscall-flags) SYSCFLAGS_vsyscall-int80_32.so = $(vsyscall-flags) -$(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter.so: \ +$(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so: \ $(obj)/vsyscall-%.so: $(src)/vsyscall_32.lds \ $(obj)/vsyscall-%.o $(obj)/vsyscall-note.o FORCE $(call if_changed,syscall) @@ -80,7 +80,7 @@ $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o SYSCFLAGS_vsyscall-syms.o = -r $(obj)/vsyscall-syms.o: $(src)/vsyscall_32.lds \ - $(obj)/vsyscall-sysenter.o $(obj)/vsyscall-note.o FORCE + $(obj)/vsyscall-sysenter_32.o $(obj)/vsyscall-note.o FORCE $(call if_changed,syscall) k8-y += ../../x86_64/kernel/k8.o diff --git a/arch/i386/kernel/vsyscall-sysenter.S b/arch/i386/kernel/vsyscall-sysenter_32.S similarity index 100% rename from arch/i386/kernel/vsyscall-sysenter.S rename to arch/i386/kernel/vsyscall-sysenter_32.S From 56cc623cd7e9a36ae57fbf43f85adc11cff13042 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:46 +0200 Subject: [PATCH 1917/2804] i386: prepare shared kernel/sigframe.h Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/asm-offsets_32.c | 2 +- arch/i386/kernel/{sigframe.h => sigframe_32.h} | 0 arch/i386/kernel/signal_32.c | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/i386/kernel/{sigframe.h => sigframe_32.h} (100%) diff --git a/arch/i386/kernel/asm-offsets_32.c b/arch/i386/kernel/asm-offsets_32.c index 7288ac88d746..8029742c0fc1 100644 --- a/arch/i386/kernel/asm-offsets_32.c +++ b/arch/i386/kernel/asm-offsets_32.c @@ -10,7 +10,7 @@ #include #include #include -#include "sigframe.h" +#include "sigframe_32.h" #include #include #include diff --git a/arch/i386/kernel/sigframe.h b/arch/i386/kernel/sigframe_32.h similarity index 100% rename from arch/i386/kernel/sigframe.h rename to arch/i386/kernel/sigframe_32.h diff --git a/arch/i386/kernel/signal_32.c b/arch/i386/kernel/signal_32.c index f5dd85656c18..c03570f7fe8e 100644 --- a/arch/i386/kernel/signal_32.c +++ b/arch/i386/kernel/signal_32.c @@ -25,7 +25,7 @@ #include #include #include -#include "sigframe.h" +#include "sigframe_32.h" #define DEBUG_SIG 0 From ee8b55e53c106e6325e1f8a36d7274da43546255 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:47 +0200 Subject: [PATCH 1918/2804] i386: prepare shared kernel/mpparse.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{mpparse.c => mpparse_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{mpparse.c => mpparse_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 4e4b1fa96157..e96419b6821d 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_X86_SMP) += smp_32.o smpboot_32.o tsc_sync.o obj-$(CONFIG_SMP) += smpcommon_32.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o -obj-$(CONFIG_X86_MPPARSE) += mpparse.o +obj-$(CONFIG_X86_MPPARSE) += mpparse_32.o obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse_32.c similarity index 100% rename from arch/i386/kernel/mpparse.c rename to arch/i386/kernel/mpparse_32.c From f5a08b90f0089604be7a03c569ad8a44085bc363 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:49 +0200 Subject: [PATCH 1919/2804] i386: prepare shared kernel/time.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{time.c => time_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{time.c => time_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index e96419b6821d..31c4541c4e14 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal_32.o entry.o traps_32.o irq.o \ - ptrace.o time.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ + ptrace.o time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time_32.c similarity index 100% rename from arch/i386/kernel/time.c rename to arch/i386/kernel/time_32.c From bb2c787b41d0cffd372865b474903f7b3cfcdd7e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:50 +0200 Subject: [PATCH 1920/2804] i386: prepare shared kernel/scx200.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{scx200.c => scx200_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{scx200.c => scx200_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 31c4541c4e14..0d329e12a039 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -45,7 +45,7 @@ obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o obj-$(CONFIG_PARAVIRT) += paravirt_32.o obj-y += pcspeaker.o -obj-$(CONFIG_SCx200) += scx200.o +obj-$(CONFIG_SCx200) += scx200_32.o # vsyscall_32.o contains the vsyscall DSO images as __initdata. # We must build both images before we can assemble it. diff --git a/arch/i386/kernel/scx200.c b/arch/i386/kernel/scx200_32.c similarity index 100% rename from arch/i386/kernel/scx200.c rename to arch/i386/kernel/scx200_32.c From a0d557e2c28623c58e645c29f309a823edd7a1bf Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:52 +0200 Subject: [PATCH 1921/2804] i386: prepare shared kernel/apm.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{apm.c => apm_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{apm.c => apm_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 0d329e12a039..ce8dd0ad8a79 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o -obj-$(CONFIG_APM) += apm.o +obj-$(CONFIG_APM) += apm_32.o obj-$(CONFIG_X86_SMP) += smp_32.o smpboot_32.o tsc_sync.o obj-$(CONFIG_SMP) += smpcommon_32.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm_32.c similarity index 100% rename from arch/i386/kernel/apm.c rename to arch/i386/kernel/apm_32.c From 8260dc37916c12b36e9732a8fa5bfa8c5fa8f0c4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:53 +0200 Subject: [PATCH 1922/2804] i386: prepare shared kernel/ptrace.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{ptrace.c => ptrace_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{ptrace.c => ptrace_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index ce8dd0ad8a79..b3a8c9aae0ab 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal_32.o entry.o traps_32.o irq.o \ - ptrace.o time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ + ptrace_32.o time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace_32.c similarity index 100% rename from arch/i386/kernel/ptrace.c rename to arch/i386/kernel/ptrace_32.c From b352b7fe2271c48600a71f50546b8a3567a0e7fe Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:54 +0200 Subject: [PATCH 1923/2804] i386: prepare shared kernel/irq.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{irq.c => irq_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{irq.c => irq_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index b3a8c9aae0ab..c718afe95457 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o init_task.o vmlinux.lds -obj-y := process.o signal_32.o entry.o traps_32.o irq.o \ +obj-y := process.o signal_32.o entry.o traps_32.o irq_32.o \ ptrace_32.o time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq_32.c similarity index 100% rename from arch/i386/kernel/irq.c rename to arch/i386/kernel/irq_32.c From 826c0e9e6ced6c1bb2d3f067ddff93d706b86446 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:56 +0200 Subject: [PATCH 1924/2804] i386: prepare shared kernel/trampoline.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{trampoline.S => trampoline_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{trampoline.S => trampoline_32.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index c718afe95457..4d7a8e8dc44e 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -20,7 +20,7 @@ obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_APM) += apm_32.o obj-$(CONFIG_X86_SMP) += smp_32.o smpboot_32.o tsc_sync.o obj-$(CONFIG_SMP) += smpcommon_32.o -obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o +obj-$(CONFIG_X86_TRAMPOLINE) += trampoline_32.o obj-$(CONFIG_X86_MPPARSE) += mpparse_32.o obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline_32.S similarity index 100% rename from arch/i386/kernel/trampoline.S rename to arch/i386/kernel/trampoline_32.S From c94905c5c184686bffde7d0c23cadb64dfce17af Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:57 +0200 Subject: [PATCH 1925/2804] i386: prepare shared kernel/reboot.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{reboot.c => reboot_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{reboot.c => reboot_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 4d7a8e8dc44e..863f68d10d69 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := process.o signal_32.o entry.o traps_32.o irq_32.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ obj-y += acpi/ -obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o +obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot_32.c similarity index 100% rename from arch/i386/kernel/reboot.c rename to arch/i386/kernel/reboot_32.c From 26ab6533a683e92129cfa5f2365924d007c119f3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:12:59 +0200 Subject: [PATCH 1926/2804] i386: prepare shared kernel/crash_dump.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{crash_dump.c => crash_dump_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{crash_dump.c => crash_dump_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 863f68d10d69..3cf5ca824a6c 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o -obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +obj-$(CONFIG_CRASH_DUMP) += crash_dump_32.o obj-$(CONFIG_X86_NUMAQ) += numaq_32.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o obj-$(CONFIG_KPROBES) += kprobes.o diff --git a/arch/i386/kernel/crash_dump.c b/arch/i386/kernel/crash_dump_32.c similarity index 100% rename from arch/i386/kernel/crash_dump.c rename to arch/i386/kernel/crash_dump_32.c From 0c67e102ea427341ca51e0943eb3c5a911d05301 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:00 +0200 Subject: [PATCH 1927/2804] i386: prepare shared kernel/ldt.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{ldt.c => ldt_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{ldt.c => ldt_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 3cf5ca824a6c..e0ea18f12071 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o signal_32.o entry.o traps_32.o irq_32.o \ - ptrace_32.o time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ + ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt_32.c similarity index 100% rename from arch/i386/kernel/ldt.c rename to arch/i386/kernel/ldt_32.c From 6ddf19584021f3c5774823278d42ee3f3124b650 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:02 +0200 Subject: [PATCH 1928/2804] i386: prepare shared kernel/init_task.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{init_task.c => init_task_32.c} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/i386/kernel/{init_task.c => init_task_32.c} (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 1bada3d878b7..56ea4250f982 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -99,7 +99,7 @@ core-$(CONFIG_XEN) += arch/i386/xen/ # default subarch .h files mflags-y += -Iinclude/asm-i386/mach-default -head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o +head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task_32.o libs-y += arch/i386/lib/ core-y += arch/i386/kernel/ \ diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index e0ea18f12071..71138e9731f7 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o init_task.o vmlinux.lds +extra-y := head.o init_task_32.o vmlinux.lds obj-y := process.o signal_32.o entry.o traps_32.o irq_32.o \ ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task_32.c similarity index 100% rename from arch/i386/kernel/init_task.c rename to arch/i386/kernel/init_task_32.c From e012a7b6000a955f1d706cab288e938207c74ba7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:03 +0200 Subject: [PATCH 1929/2804] i386: prepare shared kernel/vsyscall-sigreturn.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/vsyscall-int80_32.S | 2 +- .../kernel/{vsyscall-sigreturn.S => vsyscall-sigreturn_32.S} | 0 arch/i386/kernel/vsyscall-sysenter_32.S | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/i386/kernel/{vsyscall-sigreturn.S => vsyscall-sigreturn_32.S} (100%) diff --git a/arch/i386/kernel/vsyscall-int80_32.S b/arch/i386/kernel/vsyscall-int80_32.S index 530d0525e5e2..103cab6aa7c0 100644 --- a/arch/i386/kernel/vsyscall-int80_32.S +++ b/arch/i386/kernel/vsyscall-int80_32.S @@ -50,4 +50,4 @@ __kernel_vsyscall: /* * Get the common code for the sigreturn entry points. */ -#include "vsyscall-sigreturn.S" +#include "vsyscall-sigreturn_32.S" diff --git a/arch/i386/kernel/vsyscall-sigreturn.S b/arch/i386/kernel/vsyscall-sigreturn_32.S similarity index 100% rename from arch/i386/kernel/vsyscall-sigreturn.S rename to arch/i386/kernel/vsyscall-sigreturn_32.S diff --git a/arch/i386/kernel/vsyscall-sysenter_32.S b/arch/i386/kernel/vsyscall-sysenter_32.S index 1a36d26e15eb..ed879bf42995 100644 --- a/arch/i386/kernel/vsyscall-sysenter_32.S +++ b/arch/i386/kernel/vsyscall-sysenter_32.S @@ -119,4 +119,4 @@ SYSENTER_RETURN: /* * Get the common code for the sigreturn entry points. */ -#include "vsyscall-sigreturn.S" +#include "vsyscall-sigreturn_32.S" From b4f127b931e66aeb4740d2cff36bc2e893af427e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:05 +0200 Subject: [PATCH 1930/2804] i386: prepare shared kernel/process.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{process.c => process_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{process.c => process_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 71138e9731f7..1efdb4714981 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o init_task_32.o vmlinux.lds -obj-y := process.o signal_32.o entry.o traps_32.o irq_32.o \ +obj-y := process_32.o signal_32.o entry.o traps_32.o irq_32.o \ ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process_32.c similarity index 100% rename from arch/i386/kernel/process.c rename to arch/i386/kernel/process_32.c From 930eed490ca02aaad6aa1bd10614a2b70cf621c6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:06 +0200 Subject: [PATCH 1931/2804] i386: prepare shared kernel/kprobes.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{kprobes.c => kprobes_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{kprobes.c => kprobes_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 1efdb4714981..0af9b0c11cb8 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -29,7 +29,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_32.o obj-$(CONFIG_X86_NUMAQ) += numaq_32.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o -obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KPROBES) += kprobes_32.o obj-$(CONFIG_MODULES) += module_32.o obj-y += sysenter_32.o vsyscall_32.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes_32.c similarity index 100% rename from arch/i386/kernel/kprobes.c rename to arch/i386/kernel/kprobes_32.c From 668a3bf76e56f019fee46210531f94cf6b418bbd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:07 +0200 Subject: [PATCH 1932/2804] i386: prepare shared kernel/entry.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{entry.S => entry_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{entry.S => entry_32.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 0af9b0c11cb8..ff2909a97441 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o init_task_32.o vmlinux.lds -obj-y := process_32.o signal_32.o entry.o traps_32.o irq_32.o \ +obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry_32.S similarity index 100% rename from arch/i386/kernel/entry.S rename to arch/i386/kernel/entry_32.S From 76ea2ec68b54acc13ee1bfbb9a4e3aad370a374f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:09 +0200 Subject: [PATCH 1933/2804] i386: prepare shared kernel/tsc.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{tsc.c => tsc_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{tsc.c => tsc_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index ff2909a97441..d5367aa2510d 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := head.o init_task_32.o vmlinux.lds obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ - quirks.o i8237.o topology.o alternative.o i8253_32.o tsc.o + quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc_32.c similarity index 100% rename from arch/i386/kernel/tsc.c rename to arch/i386/kernel/tsc_32.c From deb8677148fef3aea11edd4e980f6eb9c564f3cd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:10 +0200 Subject: [PATCH 1934/2804] i386: prepare shared kernel/head.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{head.S => head_32.S} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/i386/kernel/{head.S => head_32.S} (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 56ea4250f982..45409c13f6ef 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -99,7 +99,7 @@ core-$(CONFIG_XEN) += arch/i386/xen/ # default subarch .h files mflags-y += -Iinclude/asm-i386/mach-default -head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task_32.o +head-y := arch/i386/kernel/head_32.o arch/i386/kernel/init_task_32.o libs-y += arch/i386/lib/ core-y += arch/i386/kernel/ \ diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index d5367aa2510d..6ecf97da63b0 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o init_task_32.o vmlinux.lds +extra-y := head_32.o init_task_32.o vmlinux.lds obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head_32.S similarity index 100% rename from arch/i386/kernel/head.S rename to arch/i386/kernel/head_32.S From fcaf15d788dc0c8354dbcf449e260cb303120b75 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:12 +0200 Subject: [PATCH 1935/2804] i386: prepare shared kernel/machine_kexec.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/{machine_kexec.c => machine_kexec_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/{machine_kexec.c => machine_kexec_32.c} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 6ecf97da63b0..8d80220932f8 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse_32.o obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_32.o crash_32.o +obj-$(CONFIG_KEXEC) += machine_kexec_32.o relocate_kernel_32.o crash_32.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_32.o obj-$(CONFIG_X86_NUMAQ) += numaq_32.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o diff --git a/arch/i386/kernel/machine_kexec.c b/arch/i386/kernel/machine_kexec_32.c similarity index 100% rename from arch/i386/kernel/machine_kexec.c rename to arch/i386/kernel/machine_kexec_32.c From 565b56cc9929fd4e682850df960f0766c8363383 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:13 +0200 Subject: [PATCH 1936/2804] i386: prepare shared kernel/vsyscall-note.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 6 +++--- arch/i386/kernel/{vsyscall-note.S => vsyscall-note_32.S} | 0 arch/x86_64/ia32/vsyscall-sigreturn.S | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename arch/i386/kernel/{vsyscall-note.S => vsyscall-note_32.S} (100%) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 8d80220932f8..d9dd3d677b72 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -52,7 +52,7 @@ obj-$(CONFIG_SCx200) += scx200_32.o # Note: kbuild does not track this dependency due to usage of .incbin $(obj)/vsyscall_32.o: $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) -targets += vsyscall-note.o vsyscall_32.lds +targets += vsyscall-note_32.o vsyscall_32.lds # The DSO images are built using a special linker script. quiet_cmd_syscall = SYSCALL $@ @@ -68,7 +68,7 @@ SYSCFLAGS_vsyscall-int80_32.so = $(vsyscall-flags) $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so: \ $(obj)/vsyscall-%.so: $(src)/vsyscall_32.lds \ - $(obj)/vsyscall-%.o $(obj)/vsyscall-note.o FORCE + $(obj)/vsyscall-%.o $(obj)/vsyscall-note_32.o FORCE $(call if_changed,syscall) # We also create a special relocatable object that should mirror the symbol @@ -80,7 +80,7 @@ $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o SYSCFLAGS_vsyscall-syms.o = -r $(obj)/vsyscall-syms.o: $(src)/vsyscall_32.lds \ - $(obj)/vsyscall-sysenter_32.o $(obj)/vsyscall-note.o FORCE + $(obj)/vsyscall-sysenter_32.o $(obj)/vsyscall-note_32.o FORCE $(call if_changed,syscall) k8-y += ../../x86_64/kernel/k8.o diff --git a/arch/i386/kernel/vsyscall-note.S b/arch/i386/kernel/vsyscall-note_32.S similarity index 100% rename from arch/i386/kernel/vsyscall-note.S rename to arch/i386/kernel/vsyscall-note_32.S diff --git a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S index 1384367cdbe1..83e7fd683c3d 100644 --- a/arch/x86_64/ia32/vsyscall-sigreturn.S +++ b/arch/x86_64/ia32/vsyscall-sigreturn.S @@ -139,5 +139,5 @@ __kernel_rt_sigreturn: .align 4 .LENDFDE3: -#include "../../i386/kernel/vsyscall-note.S" +#include "../../i386/kernel/vsyscall-note_32.S" From e1589cd4cba22e374b54f49385703fc766a11e7f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:14 +0200 Subject: [PATCH 1937/2804] i386: prepare shared kernel/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile | 93 ++---------------------------------- arch/i386/kernel/Makefile_32 | 88 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 88 deletions(-) create mode 100644 arch/i386/kernel/Makefile_32 diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index d9dd3d677b72..d3ebd1699826 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -1,88 +1,5 @@ -# -# Makefile for the linux kernel. -# - -extra-y := head_32.o init_task_32.o vmlinux.lds - -obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ - ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ - pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ - quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o - -obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-y += cpu/ -obj-y += acpi/ -obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o -obj-$(CONFIG_MCA) += mca_32.o -obj-$(CONFIG_X86_MSR) += msr.o -obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_MICROCODE) += microcode.o -obj-$(CONFIG_APM) += apm_32.o -obj-$(CONFIG_X86_SMP) += smp_32.o smpboot_32.o tsc_sync.o -obj-$(CONFIG_SMP) += smpcommon_32.o -obj-$(CONFIG_X86_TRAMPOLINE) += trampoline_32.o -obj-$(CONFIG_X86_MPPARSE) += mpparse_32.o -obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o -obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o -obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o -obj-$(CONFIG_KEXEC) += machine_kexec_32.o relocate_kernel_32.o crash_32.o -obj-$(CONFIG_CRASH_DUMP) += crash_dump_32.o -obj-$(CONFIG_X86_NUMAQ) += numaq_32.o -obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o -obj-$(CONFIG_KPROBES) += kprobes_32.o -obj-$(CONFIG_MODULES) += module_32.o -obj-y += sysenter_32.o vsyscall_32.o -obj-$(CONFIG_ACPI_SRAT) += srat_32.o -obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o -obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o -obj-$(CONFIG_VM86) += vm86_32.o -obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_HPET_TIMER) += hpet_32.o -obj-$(CONFIG_K8_NB) += k8.o -obj-$(CONFIG_MGEODE_LX) += geode_32.o - -obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o -obj-$(CONFIG_PARAVIRT) += paravirt_32.o -obj-y += pcspeaker.o - -obj-$(CONFIG_SCx200) += scx200_32.o - -# vsyscall_32.o contains the vsyscall DSO images as __initdata. -# We must build both images before we can assemble it. -# Note: kbuild does not track this dependency due to usage of .incbin -$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so -targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) -targets += vsyscall-note_32.o vsyscall_32.lds - -# The DSO images are built using a special linker script. -quiet_cmd_syscall = SYSCALL $@ - cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \ - -Wl,-T,$(filter-out FORCE,$^) -o $@ - -export CPPFLAGS_vsyscall_32.lds += -P -C -U$(ARCH) - -vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ - $(call ld-option, -Wl$(comma)--hash-style=sysv) -SYSCFLAGS_vsyscall-sysenter_32.so = $(vsyscall-flags) -SYSCFLAGS_vsyscall-int80_32.so = $(vsyscall-flags) - -$(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so: \ -$(obj)/vsyscall-%.so: $(src)/vsyscall_32.lds \ - $(obj)/vsyscall-%.o $(obj)/vsyscall-note_32.o FORCE - $(call if_changed,syscall) - -# We also create a special relocatable object that should mirror the symbol -# table and layout of the linked DSO. With ld -R we can then refer to -# these symbols in the kernel code rather than hand-coded addresses. -extra-y += vsyscall-syms.o -$(obj)/built-in.o: $(obj)/vsyscall-syms.o -$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o - -SYSCFLAGS_vsyscall-syms.o = -r -$(obj)/vsyscall-syms.o: $(src)/vsyscall_32.lds \ - $(obj)/vsyscall-sysenter_32.o $(obj)/vsyscall-note_32.o FORCE - $(call if_changed,syscall) - -k8-y += ../../x86_64/kernel/k8.o -stacktrace-y += ../../x86_64/kernel/stacktrace.o - +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/kernel/Makefile_32 +else +include ${srctree}/arch/x86_64/kernel/Makefile_64 +endif diff --git a/arch/i386/kernel/Makefile_32 b/arch/i386/kernel/Makefile_32 new file mode 100644 index 000000000000..d9dd3d677b72 --- /dev/null +++ b/arch/i386/kernel/Makefile_32 @@ -0,0 +1,88 @@ +# +# Makefile for the linux kernel. +# + +extra-y := head_32.o init_task_32.o vmlinux.lds + +obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ + ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ + pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ + quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o + +obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-y += cpu/ +obj-y += acpi/ +obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o +obj-$(CONFIG_MCA) += mca_32.o +obj-$(CONFIG_X86_MSR) += msr.o +obj-$(CONFIG_X86_CPUID) += cpuid.o +obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_APM) += apm_32.o +obj-$(CONFIG_X86_SMP) += smp_32.o smpboot_32.o tsc_sync.o +obj-$(CONFIG_SMP) += smpcommon_32.o +obj-$(CONFIG_X86_TRAMPOLINE) += trampoline_32.o +obj-$(CONFIG_X86_MPPARSE) += mpparse_32.o +obj-$(CONFIG_X86_LOCAL_APIC) += apic_32.o nmi_32.o +obj-$(CONFIG_X86_IO_APIC) += io_apic_32.o +obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o +obj-$(CONFIG_KEXEC) += machine_kexec_32.o relocate_kernel_32.o crash_32.o +obj-$(CONFIG_CRASH_DUMP) += crash_dump_32.o +obj-$(CONFIG_X86_NUMAQ) += numaq_32.o +obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o +obj-$(CONFIG_KPROBES) += kprobes_32.o +obj-$(CONFIG_MODULES) += module_32.o +obj-y += sysenter_32.o vsyscall_32.o +obj-$(CONFIG_ACPI_SRAT) += srat_32.o +obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o +obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o +obj-$(CONFIG_VM86) += vm86_32.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_HPET_TIMER) += hpet_32.o +obj-$(CONFIG_K8_NB) += k8.o +obj-$(CONFIG_MGEODE_LX) += geode_32.o + +obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o +obj-$(CONFIG_PARAVIRT) += paravirt_32.o +obj-y += pcspeaker.o + +obj-$(CONFIG_SCx200) += scx200_32.o + +# vsyscall_32.o contains the vsyscall DSO images as __initdata. +# We must build both images before we can assemble it. +# Note: kbuild does not track this dependency due to usage of .incbin +$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so +targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) +targets += vsyscall-note_32.o vsyscall_32.lds + +# The DSO images are built using a special linker script. +quiet_cmd_syscall = SYSCALL $@ + cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \ + -Wl,-T,$(filter-out FORCE,$^) -o $@ + +export CPPFLAGS_vsyscall_32.lds += -P -C -U$(ARCH) + +vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ + $(call ld-option, -Wl$(comma)--hash-style=sysv) +SYSCFLAGS_vsyscall-sysenter_32.so = $(vsyscall-flags) +SYSCFLAGS_vsyscall-int80_32.so = $(vsyscall-flags) + +$(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so: \ +$(obj)/vsyscall-%.so: $(src)/vsyscall_32.lds \ + $(obj)/vsyscall-%.o $(obj)/vsyscall-note_32.o FORCE + $(call if_changed,syscall) + +# We also create a special relocatable object that should mirror the symbol +# table and layout of the linked DSO. With ld -R we can then refer to +# these symbols in the kernel code rather than hand-coded addresses. +extra-y += vsyscall-syms.o +$(obj)/built-in.o: $(obj)/vsyscall-syms.o +$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o + +SYSCFLAGS_vsyscall-syms.o = -r +$(obj)/vsyscall-syms.o: $(src)/vsyscall_32.lds \ + $(obj)/vsyscall-sysenter_32.o $(obj)/vsyscall-note_32.o FORCE + $(call if_changed,syscall) + +k8-y += ../../x86_64/kernel/k8.o +stacktrace-y += ../../x86_64/kernel/stacktrace.o + From 193aa5d7efc827f1c4edc6ecaf3b4596e720f82f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:15 +0200 Subject: [PATCH 1938/2804] i386: prepare shared kernel/acpi/wakeup.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/acpi/Makefile | 2 +- arch/i386/kernel/acpi/{wakeup.S => wakeup_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/acpi/{wakeup.S => wakeup_32.S} (100%) diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile index 7f7be01f44e6..fb602cd51924 100644 --- a/arch/i386/kernel/acpi/Makefile +++ b/arch/i386/kernel/acpi/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_ACPI) += boot.o ifneq ($(CONFIG_PCI),) obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o endif -obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_32.o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += cstate.o processor.o diff --git a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup_32.S similarity index 100% rename from arch/i386/kernel/acpi/wakeup.S rename to arch/i386/kernel/acpi/wakeup_32.S From bf79503a14c2d7c8b27dec60dae60af69c509a77 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:17 +0200 Subject: [PATCH 1939/2804] i386: prepare shared kernel/acpi/sleep.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/acpi/Makefile | 2 +- arch/i386/kernel/acpi/{sleep.c => sleep_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/acpi/{sleep.c => sleep_32.c} (100%) diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile index fb602cd51924..cfbc7d8d66e2 100644 --- a/arch/i386/kernel/acpi/Makefile +++ b/arch/i386/kernel/acpi/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_ACPI) += boot.o ifneq ($(CONFIG_PCI),) obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o endif -obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_32.o +obj-$(CONFIG_ACPI_SLEEP) += sleep_32.o wakeup_32.o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += cstate.o processor.o diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep_32.c similarity index 100% rename from arch/i386/kernel/acpi/sleep.c rename to arch/i386/kernel/acpi/sleep_32.c From 84629d8d3695cab7177e9a04ccc212727280bdd8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:18 +0200 Subject: [PATCH 1940/2804] i386: prepare shared kernel/acpi/earlyquirk.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/acpi/Makefile | 2 +- arch/i386/kernel/acpi/{earlyquirk.c => earlyquirk_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/kernel/acpi/{earlyquirk.c => earlyquirk_32.c} (100%) diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile index cfbc7d8d66e2..a4852a2e9190 100644 --- a/arch/i386/kernel/acpi/Makefile +++ b/arch/i386/kernel/acpi/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_ACPI) += boot.o ifneq ($(CONFIG_PCI),) -obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o +obj-$(CONFIG_X86_IO_APIC) += earlyquirk_32.o endif obj-$(CONFIG_ACPI_SLEEP) += sleep_32.o wakeup_32.o diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk_32.c similarity index 100% rename from arch/i386/kernel/acpi/earlyquirk.c rename to arch/i386/kernel/acpi/earlyquirk_32.c From 96c4d6e71d27a2de591d185aa897d2d215f8588e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:19 +0200 Subject: [PATCH 1941/2804] i386: prepare shared kernel/acpi/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/acpi/Makefile | 13 ++++--------- arch/i386/kernel/acpi/Makefile_32 | 10 ++++++++++ 2 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 arch/i386/kernel/acpi/Makefile_32 diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile index a4852a2e9190..6e00bfeb59a9 100644 --- a/arch/i386/kernel/acpi/Makefile +++ b/arch/i386/kernel/acpi/Makefile @@ -1,10 +1,5 @@ -obj-$(CONFIG_ACPI) += boot.o -ifneq ($(CONFIG_PCI),) -obj-$(CONFIG_X86_IO_APIC) += earlyquirk_32.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/kernel/acpi/Makefile_32 +else +include ${srctree}/arch/x86_64/kernel/acpi/Makefile_64 endif -obj-$(CONFIG_ACPI_SLEEP) += sleep_32.o wakeup_32.o - -ifneq ($(CONFIG_ACPI_PROCESSOR),) -obj-y += cstate.o processor.o -endif - diff --git a/arch/i386/kernel/acpi/Makefile_32 b/arch/i386/kernel/acpi/Makefile_32 new file mode 100644 index 000000000000..a4852a2e9190 --- /dev/null +++ b/arch/i386/kernel/acpi/Makefile_32 @@ -0,0 +1,10 @@ +obj-$(CONFIG_ACPI) += boot.o +ifneq ($(CONFIG_PCI),) +obj-$(CONFIG_X86_IO_APIC) += earlyquirk_32.o +endif +obj-$(CONFIG_ACPI_SLEEP) += sleep_32.o wakeup_32.o + +ifneq ($(CONFIG_ACPI_PROCESSOR),) +obj-y += cstate.o processor.o +endif + From 31834147ef934140c9d41afe130ac8606c2d7a81 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:20 +0200 Subject: [PATCH 1942/2804] i386: prepare shared lib/checksum.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{checksum.S => checksum_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{checksum.S => checksum_32.S} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 4d105fdfe817..afbc99d2ee88 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -3,7 +3,7 @@ # -lib-y = checksum.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \ +lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \ bitops.o semaphore.o string.o lib-$(CONFIG_X86_USE_3DNOW) += mmx.o diff --git a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum_32.S similarity index 100% rename from arch/i386/lib/checksum.S rename to arch/i386/lib/checksum_32.S From 2be2056cee405f3e3ca07e197ecd803e81cf5cb6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:21 +0200 Subject: [PATCH 1943/2804] i386: prepare shared lib/strstr.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{strstr.c => strstr_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{strstr.c => strstr_32.c} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index afbc99d2ee88..4d3ae15445d2 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -3,7 +3,7 @@ # -lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \ +lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr_32.o \ bitops.o semaphore.o string.o lib-$(CONFIG_X86_USE_3DNOW) += mmx.o diff --git a/arch/i386/lib/strstr.c b/arch/i386/lib/strstr_32.c similarity index 100% rename from arch/i386/lib/strstr.c rename to arch/i386/lib/strstr_32.c From 282317dc1570c392d1593869ded36baeee8f1d54 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:23 +0200 Subject: [PATCH 1944/2804] i386: prepare shared lib/string.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{string.c => string_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{string.c => string_32.c} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 4d3ae15445d2..1bd9b85b03cc 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -4,7 +4,7 @@ lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr_32.o \ - bitops.o semaphore.o string.o + bitops.o semaphore.o string_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx.o diff --git a/arch/i386/lib/string.c b/arch/i386/lib/string_32.c similarity index 100% rename from arch/i386/lib/string.c rename to arch/i386/lib/string_32.c From bb3871daf6d95101220969dc2634456cf2c503da Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:24 +0200 Subject: [PATCH 1945/2804] i386: prepare shared lib/semaphore.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{semaphore.S => semaphore_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{semaphore.S => semaphore_32.S} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 1bd9b85b03cc..dce510d443aa 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -4,7 +4,7 @@ lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr_32.o \ - bitops.o semaphore.o string_32.o + bitops.o semaphore_32.o string_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx.o diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore_32.S similarity index 100% rename from arch/i386/lib/semaphore.S rename to arch/i386/lib/semaphore_32.S From 1bbad2b6f10e1f1a171edae545ea2f84dca8c2da Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:26 +0200 Subject: [PATCH 1946/2804] i386: prepare shared lib/memcpy.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{memcpy.c => memcpy_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{memcpy.c => memcpy_32.c} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index dce510d443aa..af7f9435d203 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -3,7 +3,7 @@ # -lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr_32.o \ +lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy_32.o strstr_32.o \ bitops.o semaphore_32.o string_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx.o diff --git a/arch/i386/lib/memcpy.c b/arch/i386/lib/memcpy_32.c similarity index 100% rename from arch/i386/lib/memcpy.c rename to arch/i386/lib/memcpy_32.c From e585d9617a4c2c8f4d1d19def80158bca2853be8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:27 +0200 Subject: [PATCH 1947/2804] i386: prepare shared lib/mmx.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{mmx.c => mmx_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{mmx.c => mmx_32.c} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index af7f9435d203..553c41d2d79b 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -6,6 +6,6 @@ lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy_32.o strstr_32.o \ bitops.o semaphore_32.o string_32.o -lib-$(CONFIG_X86_USE_3DNOW) += mmx.o +lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o obj-$(CONFIG_SMP) += msr-on-cpu.o diff --git a/arch/i386/lib/mmx.c b/arch/i386/lib/mmx_32.c similarity index 100% rename from arch/i386/lib/mmx.c rename to arch/i386/lib/mmx_32.c From 8b7fd47bdf84086914180b88a41d2f7c1ada5917 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:29 +0200 Subject: [PATCH 1948/2804] i386: prepare shared lib/getuser.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{getuser.S => getuser_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{getuser.S => getuser_32.S} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 553c41d2d79b..968d2e51d39a 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -3,7 +3,7 @@ # -lib-y = checksum_32.o delay.o usercopy.o getuser.o putuser.o memcpy_32.o strstr_32.o \ +lib-y = checksum_32.o delay.o usercopy.o getuser_32.o putuser.o memcpy_32.o strstr_32.o \ bitops.o semaphore_32.o string_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o diff --git a/arch/i386/lib/getuser.S b/arch/i386/lib/getuser_32.S similarity index 100% rename from arch/i386/lib/getuser.S rename to arch/i386/lib/getuser_32.S From 81f52936d34570f7db3f09bf5e01339b640438ef Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:30 +0200 Subject: [PATCH 1949/2804] i386: prepare shared lib/usercopy.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{usercopy.c => usercopy_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{usercopy.c => usercopy_32.c} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 968d2e51d39a..2ec0fbf6c1ca 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -3,7 +3,7 @@ # -lib-y = checksum_32.o delay.o usercopy.o getuser_32.o putuser.o memcpy_32.o strstr_32.o \ +lib-y = checksum_32.o delay.o usercopy_32.o getuser_32.o putuser.o memcpy_32.o strstr_32.o \ bitops.o semaphore_32.o string_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy_32.c similarity index 100% rename from arch/i386/lib/usercopy.c rename to arch/i386/lib/usercopy_32.c From 6d1f5420f0d4bd6f391295bb632ae65920983162 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:31 +0200 Subject: [PATCH 1950/2804] i386: prepare shared lib/bitops.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{bitops.c => bitops_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{bitops.c => bitops_32.c} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 2ec0fbf6c1ca..246a775940ff 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -4,7 +4,7 @@ lib-y = checksum_32.o delay.o usercopy_32.o getuser_32.o putuser.o memcpy_32.o strstr_32.o \ - bitops.o semaphore_32.o string_32.o + bitops_32.o semaphore_32.o string_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o diff --git a/arch/i386/lib/bitops.c b/arch/i386/lib/bitops_32.c similarity index 100% rename from arch/i386/lib/bitops.c rename to arch/i386/lib/bitops_32.c From 6e696842484ffcf018bba6a46610091ff68f49a8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:33 +0200 Subject: [PATCH 1951/2804] i386: prepare shared lib/putuser.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{putuser.S => putuser_32.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{putuser.S => putuser_32.S} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 246a775940ff..c2de356c6935 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -3,7 +3,7 @@ # -lib-y = checksum_32.o delay.o usercopy_32.o getuser_32.o putuser.o memcpy_32.o strstr_32.o \ +lib-y = checksum_32.o delay.o usercopy_32.o getuser_32.o putuser_32.o memcpy_32.o strstr_32.o \ bitops_32.o semaphore_32.o string_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o diff --git a/arch/i386/lib/putuser.S b/arch/i386/lib/putuser_32.S similarity index 100% rename from arch/i386/lib/putuser.S rename to arch/i386/lib/putuser_32.S From d779d8f9f8419e8492959adc267cdf5478bc4748 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:34 +0200 Subject: [PATCH 1952/2804] i386: prepare shared lib/delay.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 2 +- arch/i386/lib/{delay.c => delay_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/lib/{delay.c => delay_32.c} (100%) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index c2de356c6935..98d1f1e2e2ef 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -3,7 +3,7 @@ # -lib-y = checksum_32.o delay.o usercopy_32.o getuser_32.o putuser_32.o memcpy_32.o strstr_32.o \ +lib-y = checksum_32.o delay_32.o usercopy_32.o getuser_32.o putuser_32.o memcpy_32.o strstr_32.o \ bitops_32.o semaphore_32.o string_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay_32.c similarity index 100% rename from arch/i386/lib/delay.c rename to arch/i386/lib/delay_32.c From 5fde34fddcb58af7bd08c143389ed074f8715f9f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:35 +0200 Subject: [PATCH 1953/2804] i386: prepare shared lib/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/lib/Makefile | 16 +++++----------- arch/i386/lib/Makefile_32 | 11 +++++++++++ 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 arch/i386/lib/Makefile_32 diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 98d1f1e2e2ef..2b1547e0ac6b 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -1,11 +1,5 @@ -# -# Makefile for i386-specific library files.. -# - - -lib-y = checksum_32.o delay_32.o usercopy_32.o getuser_32.o putuser_32.o memcpy_32.o strstr_32.o \ - bitops_32.o semaphore_32.o string_32.o - -lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o - -obj-$(CONFIG_SMP) += msr-on-cpu.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/lib/Makefile_32 +else +include ${srctree}/arch/x86_64/lib/Makefile_64 +endif diff --git a/arch/i386/lib/Makefile_32 b/arch/i386/lib/Makefile_32 new file mode 100644 index 000000000000..98d1f1e2e2ef --- /dev/null +++ b/arch/i386/lib/Makefile_32 @@ -0,0 +1,11 @@ +# +# Makefile for i386-specific library files.. +# + + +lib-y = checksum_32.o delay_32.o usercopy_32.o getuser_32.o putuser_32.o memcpy_32.o strstr_32.o \ + bitops_32.o semaphore_32.o string_32.o + +lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o + +obj-$(CONFIG_SMP) += msr-on-cpu.o From e32c44c8349dbdf7712a7d868fdbff75599c9005 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:36 +0200 Subject: [PATCH 1954/2804] i386: prepare shared pci/mmconfig.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/pci/Makefile | 2 +- arch/i386/pci/{mmconfig.c => mmconfig_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/pci/{mmconfig.c => mmconfig_32.c} (100%) diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile index 44650e03308b..cdd6828b5abb 100644 --- a/arch/i386/pci/Makefile +++ b/arch/i386/pci/Makefile @@ -1,7 +1,7 @@ obj-y := i386.o init.o obj-$(CONFIG_PCI_BIOS) += pcbios.o -obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o obj-$(CONFIG_PCI_DIRECT) += direct.o pci-y := fixup.o diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig_32.c similarity index 100% rename from arch/i386/pci/mmconfig.c rename to arch/i386/pci/mmconfig_32.c From 5fa25bee6cee459ee3d08f7544cca5a9fb016c8b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:37 +0200 Subject: [PATCH 1955/2804] i386: prepare shared pci/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/pci/Makefile | 19 +++++-------------- arch/i386/pci/Makefile_32 | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 arch/i386/pci/Makefile_32 diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile index cdd6828b5abb..d04d8f976d1c 100644 --- a/arch/i386/pci/Makefile +++ b/arch/i386/pci/Makefile @@ -1,14 +1,5 @@ -obj-y := i386.o init.o - -obj-$(CONFIG_PCI_BIOS) += pcbios.o -obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o -obj-$(CONFIG_PCI_DIRECT) += direct.o - -pci-y := fixup.o -pci-$(CONFIG_ACPI) += acpi.o -pci-y += legacy.o irq.o - -pci-$(CONFIG_X86_VISWS) := visws.o fixup.o -pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o - -obj-y += $(pci-y) common.o early.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/pci/Makefile_32 +else +include ${srctree}/arch/x86_64/pci/Makefile_64 +endif diff --git a/arch/i386/pci/Makefile_32 b/arch/i386/pci/Makefile_32 new file mode 100644 index 000000000000..cdd6828b5abb --- /dev/null +++ b/arch/i386/pci/Makefile_32 @@ -0,0 +1,14 @@ +obj-y := i386.o init.o + +obj-$(CONFIG_PCI_BIOS) += pcbios.o +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o +obj-$(CONFIG_PCI_DIRECT) += direct.o + +pci-y := fixup.o +pci-$(CONFIG_ACPI) += acpi.o +pci-y += legacy.o irq.o + +pci-$(CONFIG_X86_VISWS) := visws.o fixup.o +pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o + +obj-y += $(pci-y) common.o early.o From c1c85a52c755c86840f83669bbab63962ab231ff Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:38 +0200 Subject: [PATCH 1956/2804] i386: prepare shared boot/compressed/misc.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/boot/compressed/Makefile | 4 ++-- arch/i386/boot/compressed/{misc.c => misc_32.c} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/i386/boot/compressed/{misc.c => misc_32.c} (100%) diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile index 189fa1dbefcc..c4533eadc7a5 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -4,7 +4,7 @@ # create a compressed vmlinux image from the original vmlinux # -targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o \ +targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc_32.o piggy.o \ vmlinux.bin.all vmlinux.relocs EXTRA_AFLAGS := -traditional @@ -17,7 +17,7 @@ CFLAGS := -m32 -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ $(call cc-option,-fno-stack-protector) LDFLAGS := -m elf_i386 -$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc_32.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc_32.c similarity index 100% rename from arch/i386/boot/compressed/misc.c rename to arch/i386/boot/compressed/misc_32.c From e2ec98525d815d6e68dd509e5a4c9b93e55d622d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:40 +0200 Subject: [PATCH 1957/2804] i386: prepare shared boot/compressed/vmlinux.lds Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/boot/compressed/Makefile | 2 +- arch/i386/boot/compressed/{vmlinux.lds => vmlinux_32.lds} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/boot/compressed/{vmlinux.lds => vmlinux_32.lds} (100%) diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile index c4533eadc7a5..aa7f87318349 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -17,7 +17,7 @@ CFLAGS := -m32 -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ $(call cc-option,-fno-stack-protector) LDFLAGS := -m elf_i386 -$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc_32.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux_32.lds $(obj)/head.o $(obj)/misc_32.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: diff --git a/arch/i386/boot/compressed/vmlinux.lds b/arch/i386/boot/compressed/vmlinux_32.lds similarity index 100% rename from arch/i386/boot/compressed/vmlinux.lds rename to arch/i386/boot/compressed/vmlinux_32.lds From 20e482b6421cffa92942e2c4970c113667451205 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:41 +0200 Subject: [PATCH 1958/2804] i386: prepare shared boot/compressed/vmlinux.scr Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/boot/compressed/Makefile | 2 +- arch/i386/boot/compressed/{vmlinux.scr => vmlinux_32.scr} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/boot/compressed/{vmlinux.scr => vmlinux_32.scr} (100%) diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile index aa7f87318349..3f4289143e39 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -46,5 +46,5 @@ endif LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T -$(obj)/piggy.o: $(src)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE +$(obj)/piggy.o: $(src)/vmlinux_32.scr $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld) diff --git a/arch/i386/boot/compressed/vmlinux.scr b/arch/i386/boot/compressed/vmlinux_32.scr similarity index 100% rename from arch/i386/boot/compressed/vmlinux.scr rename to arch/i386/boot/compressed/vmlinux_32.scr From 16ae1544b763b33673f82d667b0f7699dd1274b9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:43 +0200 Subject: [PATCH 1959/2804] i386: prepare shared boot/compressed/head.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/boot/compressed/Makefile | 4 ++-- arch/i386/boot/compressed/{head.S => head_32.S} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/i386/boot/compressed/{head.S => head_32.S} (100%) diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile index 3f4289143e39..0c64c314eadb 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -4,7 +4,7 @@ # create a compressed vmlinux image from the original vmlinux # -targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc_32.o piggy.o \ +targets := vmlinux vmlinux.bin vmlinux.bin.gz head_32.o misc_32.o piggy.o \ vmlinux.bin.all vmlinux.relocs EXTRA_AFLAGS := -traditional @@ -17,7 +17,7 @@ CFLAGS := -m32 -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ $(call cc-option,-fno-stack-protector) LDFLAGS := -m elf_i386 -$(obj)/vmlinux: $(src)/vmlinux_32.lds $(obj)/head.o $(obj)/misc_32.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux_32.lds $(obj)/head_32.o $(obj)/misc_32.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head_32.S similarity index 100% rename from arch/i386/boot/compressed/head.S rename to arch/i386/boot/compressed/head_32.S From 9b88467687550507cca30b49217518e8ba8cda4e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:43 +0200 Subject: [PATCH 1960/2804] i386: prepare shared boot/compressed/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/boot/compressed/Makefile | 51 ++------------------------- arch/i386/boot/compressed/Makefile_32 | 50 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 48 deletions(-) create mode 100644 arch/i386/boot/compressed/Makefile_32 diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile index 0c64c314eadb..78514f3f626f 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -1,50 +1,5 @@ -# -# linux/arch/i386/boot/compressed/Makefile -# -# create a compressed vmlinux image from the original vmlinux -# - -targets := vmlinux vmlinux.bin vmlinux.bin.gz head_32.o misc_32.o piggy.o \ - vmlinux.bin.all vmlinux.relocs -EXTRA_AFLAGS := -traditional - -LDFLAGS_vmlinux := -T -hostprogs-y := relocs - -CFLAGS := -m32 -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ - -fno-strict-aliasing -fPIC \ - $(call cc-option,-ffreestanding) \ - $(call cc-option,-fno-stack-protector) -LDFLAGS := -m elf_i386 - -$(obj)/vmlinux: $(src)/vmlinux_32.lds $(obj)/head_32.o $(obj)/misc_32.o $(obj)/piggy.o FORCE - $(call if_changed,ld) - @: - -$(obj)/vmlinux.bin: vmlinux FORCE - $(call if_changed,objcopy) - -quiet_cmd_relocs = RELOCS $@ - cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $< -$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE - $(call if_changed,relocs) - -vmlinux.bin.all-y := $(obj)/vmlinux.bin -vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs -quiet_cmd_relocbin = BUILD $@ - cmd_relocbin = cat $(filter-out FORCE,$^) > $@ -$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE - $(call if_changed,relocbin) - -ifdef CONFIG_RELOCATABLE -$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE - $(call if_changed,gzip) +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/boot/compressed/Makefile_32 else -$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE - $(call if_changed,gzip) +include ${srctree}/arch/x86_64/boot/compressed/Makefile_64 endif - -LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T - -$(obj)/piggy.o: $(src)/vmlinux_32.scr $(obj)/vmlinux.bin.gz FORCE - $(call if_changed,ld) diff --git a/arch/i386/boot/compressed/Makefile_32 b/arch/i386/boot/compressed/Makefile_32 new file mode 100644 index 000000000000..0c64c314eadb --- /dev/null +++ b/arch/i386/boot/compressed/Makefile_32 @@ -0,0 +1,50 @@ +# +# linux/arch/i386/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +targets := vmlinux vmlinux.bin vmlinux.bin.gz head_32.o misc_32.o piggy.o \ + vmlinux.bin.all vmlinux.relocs +EXTRA_AFLAGS := -traditional + +LDFLAGS_vmlinux := -T +hostprogs-y := relocs + +CFLAGS := -m32 -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ + -fno-strict-aliasing -fPIC \ + $(call cc-option,-ffreestanding) \ + $(call cc-option,-fno-stack-protector) +LDFLAGS := -m elf_i386 + +$(obj)/vmlinux: $(src)/vmlinux_32.lds $(obj)/head_32.o $(obj)/misc_32.o $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +quiet_cmd_relocs = RELOCS $@ + cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $< +$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE + $(call if_changed,relocs) + +vmlinux.bin.all-y := $(obj)/vmlinux.bin +vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs +quiet_cmd_relocbin = BUILD $@ + cmd_relocbin = cat $(filter-out FORCE,$^) > $@ +$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE + $(call if_changed,relocbin) + +ifdef CONFIG_RELOCATABLE +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE + $(call if_changed,gzip) +else +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) +endif + +LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T + +$(obj)/piggy.o: $(src)/vmlinux_32.scr $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) From 1fd10ed659d6840850311e991ee3ba78e9e5a4a4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:45 +0200 Subject: [PATCH 1961/2804] i386: prepare shared mm/ioremap.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 4 ++-- arch/i386/mm/{ioremap.c => ioremap_32.c} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/i386/mm/{ioremap.c => ioremap_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index 80908b5aa60f..f4ff3aca1a90 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -2,9 +2,9 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o mmap.o +obj-y := init.o pgtable.o fault.o ioremap_32.o extable.o pageattr.o mmap.o obj-$(CONFIG_NUMA) += discontig.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_HIGHMEM) += highmem.o -obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap.o +obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap_32.o diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap_32.c similarity index 100% rename from arch/i386/mm/ioremap.c rename to arch/i386/mm/ioremap_32.c From 6e5191ef150947ed6e42751010e4932436e70ec9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:46 +0200 Subject: [PATCH 1962/2804] i386: prepare shared mm/discontig.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 2 +- arch/i386/mm/{discontig.c => discontig_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/mm/{discontig.c => discontig_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index f4ff3aca1a90..643b57b82f3b 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -4,7 +4,7 @@ obj-y := init.o pgtable.o fault.o ioremap_32.o extable.o pageattr.o mmap.o -obj-$(CONFIG_NUMA) += discontig.o +obj-$(CONFIG_NUMA) += discontig_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap_32.o diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig_32.c similarity index 100% rename from arch/i386/mm/discontig.c rename to arch/i386/mm/discontig_32.c From afb5ce0671f8b14f15525fd3e952b4a989c94a6b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:47 +0200 Subject: [PATCH 1963/2804] i386: prepare shared mm/init.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 2 +- arch/i386/mm/{init.c => init_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/mm/{init.c => init_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index 643b57b82f3b..fb0a4f3bbdf8 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init.o pgtable.o fault.o ioremap_32.o extable.o pageattr.o mmap.o +obj-y := init_32.o pgtable.o fault.o ioremap_32.o extable.o pageattr.o mmap.o obj-$(CONFIG_NUMA) += discontig_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init_32.c similarity index 100% rename from arch/i386/mm/init.c rename to arch/i386/mm/init_32.c From 0b690a40d30ff6924953888d43ab8e90d401fcc7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:49 +0200 Subject: [PATCH 1964/2804] i386: prepare shared mm/mmap.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 2 +- arch/i386/mm/{mmap.c => mmap_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/mm/{mmap.c => mmap_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index fb0a4f3bbdf8..969769a036c5 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init_32.o pgtable.o fault.o ioremap_32.o extable.o pageattr.o mmap.o +obj-y := init_32.o pgtable.o fault.o ioremap_32.o extable.o pageattr.o mmap_32.o obj-$(CONFIG_NUMA) += discontig_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/i386/mm/mmap.c b/arch/i386/mm/mmap_32.c similarity index 100% rename from arch/i386/mm/mmap.c rename to arch/i386/mm/mmap_32.c From 7099ec6e17b3d207f1c622cff023209acc6ba47a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:50 +0200 Subject: [PATCH 1965/2804] i386: prepare shared mm/boot_ioremap.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/{boot_ioremap.c => boot_ioremap_32.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename arch/i386/mm/{boot_ioremap.c => boot_ioremap_32.c} (100%) diff --git a/arch/i386/mm/boot_ioremap.c b/arch/i386/mm/boot_ioremap_32.c similarity index 100% rename from arch/i386/mm/boot_ioremap.c rename to arch/i386/mm/boot_ioremap_32.c From 94577c112487d68db4f258bd19cfc7100480d0cc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:52 +0200 Subject: [PATCH 1966/2804] i386: prepare shared mm/extable.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 2 +- arch/i386/mm/{extable.c => extable_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/mm/{extable.c => extable_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index 969769a036c5..c5ae6432203d 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init_32.o pgtable.o fault.o ioremap_32.o extable.o pageattr.o mmap_32.o +obj-y := init_32.o pgtable.o fault.o ioremap_32.o extable_32.o pageattr.o mmap_32.o obj-$(CONFIG_NUMA) += discontig_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/i386/mm/extable.c b/arch/i386/mm/extable_32.c similarity index 100% rename from arch/i386/mm/extable.c rename to arch/i386/mm/extable_32.c From 1c9541c7bc437c4d1bcad1e56770622c24e634a1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:53 +0200 Subject: [PATCH 1967/2804] i386: prepare shared mm/pgtable.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 2 +- arch/i386/mm/{pgtable.c => pgtable_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/mm/{pgtable.c => pgtable_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index c5ae6432203d..78c242ccaed0 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init_32.o pgtable.o fault.o ioremap_32.o extable_32.o pageattr.o mmap_32.o +obj-y := init_32.o pgtable_32.o fault.o ioremap_32.o extable_32.o pageattr.o mmap_32.o obj-$(CONFIG_NUMA) += discontig_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable_32.c similarity index 100% rename from arch/i386/mm/pgtable.c rename to arch/i386/mm/pgtable_32.c From b0aeae21da297caad0d6d0608b197e6ef97faf6d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:55 +0200 Subject: [PATCH 1968/2804] i386: prepare shared mm/highmem.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 2 +- arch/i386/mm/{highmem.c => highmem_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/mm/{highmem.c => highmem_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index 78c242ccaed0..2c81ad14a62b 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -6,5 +6,5 @@ obj-y := init_32.o pgtable_32.o fault.o ioremap_32.o extable_32.o pageattr.o mma obj-$(CONFIG_NUMA) += discontig_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_HIGHMEM) += highmem.o +obj-$(CONFIG_HIGHMEM) += highmem_32.o obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap_32.o diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem_32.c similarity index 100% rename from arch/i386/mm/highmem.c rename to arch/i386/mm/highmem_32.c From 55f98f1a26ff6cbed6189ec90143cc5c428d5b78 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:56 +0200 Subject: [PATCH 1969/2804] i386: prepare shared mm/pageattr.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 2 +- arch/i386/mm/{pageattr.c => pageattr_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/mm/{pageattr.c => pageattr_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index 2c81ad14a62b..4d7c5af4765d 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init_32.o pgtable_32.o fault.o ioremap_32.o extable_32.o pageattr.o mmap_32.o +obj-y := init_32.o pgtable_32.o fault.o ioremap_32.o extable_32.o pageattr_32.o mmap_32.o obj-$(CONFIG_NUMA) += discontig_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr_32.c similarity index 100% rename from arch/i386/mm/pageattr.c rename to arch/i386/mm/pageattr_32.c From 359fd6de61fc8777316709fb79047c480b3eae0d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:57 +0200 Subject: [PATCH 1970/2804] i386: prepare shared mm/fault.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 2 +- arch/i386/mm/{fault.c => fault_32.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/i386/mm/{fault.c => fault_32.c} (100%) diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index 4d7c5af4765d..362b4ad082de 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init_32.o pgtable_32.o fault.o ioremap_32.o extable_32.o pageattr_32.o mmap_32.o +obj-y := init_32.o pgtable_32.o fault_32.o ioremap_32.o extable_32.o pageattr_32.o mmap_32.o obj-$(CONFIG_NUMA) += discontig_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault_32.c similarity index 100% rename from arch/i386/mm/fault.c rename to arch/i386/mm/fault_32.c From 82606d5738f29d3026159ebabba687facd25276e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:58 +0200 Subject: [PATCH 1971/2804] i386: prepare shared mm/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/mm/Makefile | 15 +++++---------- arch/i386/mm/Makefile_32 | 10 ++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 arch/i386/mm/Makefile_32 diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index 362b4ad082de..4042f8563a16 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -1,10 +1,5 @@ -# -# Makefile for the linux i386-specific parts of the memory manager. -# - -obj-y := init_32.o pgtable_32.o fault_32.o ioremap_32.o extable_32.o pageattr_32.o mmap_32.o - -obj-$(CONFIG_NUMA) += discontig_32.o -obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_HIGHMEM) += highmem_32.o -obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap_32.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/mm/Makefile_32 +else +include ${srctree}/arch/x86_64/mm/Makefile_64 +endif diff --git a/arch/i386/mm/Makefile_32 b/arch/i386/mm/Makefile_32 new file mode 100644 index 000000000000..362b4ad082de --- /dev/null +++ b/arch/i386/mm/Makefile_32 @@ -0,0 +1,10 @@ +# +# Makefile for the linux i386-specific parts of the memory manager. +# + +obj-y := init_32.o pgtable_32.o fault_32.o ioremap_32.o extable_32.o pageattr_32.o mmap_32.o + +obj-$(CONFIG_NUMA) += discontig_32.o +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o +obj-$(CONFIG_HIGHMEM) += highmem_32.o +obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap_32.o From e444d14d632a1d379c1793147c61a95a24ed976a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:13:59 +0200 Subject: [PATCH 1972/2804] x86_64: prepare shared crypto/twofish.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/crypto/Makefile | 2 +- arch/x86_64/crypto/{twofish.c => twofish_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/crypto/{twofish.c => twofish_64.c} (100%) diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile index 15b538a8b7f7..7f73d22b4527 100644 --- a/arch/x86_64/crypto/Makefile +++ b/arch/x86_64/crypto/Makefile @@ -8,5 +8,5 @@ obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o aes-x86_64-y := aes-x86_64-asm.o aes.o -twofish-x86_64-y := twofish-x86_64-asm.o twofish.o +twofish-x86_64-y := twofish-x86_64-asm.o twofish_64.o diff --git a/arch/x86_64/crypto/twofish.c b/arch/x86_64/crypto/twofish_64.c similarity index 100% rename from arch/x86_64/crypto/twofish.c rename to arch/x86_64/crypto/twofish_64.c From 4d2920c9c03b9044c82da16f98eb2d536d240c4e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:01 +0200 Subject: [PATCH 1973/2804] x86_64: prepare shared crypto/aes-x86_64-asm.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/crypto/Makefile | 2 +- arch/x86_64/crypto/{aes-x86_64-asm.S => aes-x86_64-asm_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/crypto/{aes-x86_64-asm.S => aes-x86_64-asm_64.S} (100%) diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile index 7f73d22b4527..176f5bb6b511 100644 --- a/arch/x86_64/crypto/Makefile +++ b/arch/x86_64/crypto/Makefile @@ -7,6 +7,6 @@ obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o -aes-x86_64-y := aes-x86_64-asm.o aes.o +aes-x86_64-y := aes-x86_64-asm_64.o aes.o twofish-x86_64-y := twofish-x86_64-asm.o twofish_64.o diff --git a/arch/x86_64/crypto/aes-x86_64-asm.S b/arch/x86_64/crypto/aes-x86_64-asm_64.S similarity index 100% rename from arch/x86_64/crypto/aes-x86_64-asm.S rename to arch/x86_64/crypto/aes-x86_64-asm_64.S From e4bd76e1c561e843fd7cd1f99fc295b64e261894 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:02 +0200 Subject: [PATCH 1974/2804] x86_64: prepare shared crypto/twofish-x86_64-asm.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/crypto/Makefile | 2 +- .../crypto/{twofish-x86_64-asm.S => twofish-x86_64-asm_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/crypto/{twofish-x86_64-asm.S => twofish-x86_64-asm_64.S} (100%) diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile index 176f5bb6b511..37ed30fabda2 100644 --- a/arch/x86_64/crypto/Makefile +++ b/arch/x86_64/crypto/Makefile @@ -8,5 +8,5 @@ obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o aes-x86_64-y := aes-x86_64-asm_64.o aes.o -twofish-x86_64-y := twofish-x86_64-asm.o twofish_64.o +twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_64.o diff --git a/arch/x86_64/crypto/twofish-x86_64-asm.S b/arch/x86_64/crypto/twofish-x86_64-asm_64.S similarity index 100% rename from arch/x86_64/crypto/twofish-x86_64-asm.S rename to arch/x86_64/crypto/twofish-x86_64-asm_64.S From d685249a33eb729d1dbe7ee54d63cb81fdee53da Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:04 +0200 Subject: [PATCH 1975/2804] x86_64: prepare shared crypto/aes.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/crypto/Makefile | 2 +- arch/x86_64/crypto/{aes.c => aes_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/crypto/{aes.c => aes_64.c} (100%) diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile index 37ed30fabda2..c96faeb842c8 100644 --- a/arch/x86_64/crypto/Makefile +++ b/arch/x86_64/crypto/Makefile @@ -7,6 +7,6 @@ obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o -aes-x86_64-y := aes-x86_64-asm_64.o aes.o +aes-x86_64-y := aes-x86_64-asm_64.o aes_64.o twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_64.o diff --git a/arch/x86_64/crypto/aes.c b/arch/x86_64/crypto/aes_64.c similarity index 100% rename from arch/x86_64/crypto/aes.c rename to arch/x86_64/crypto/aes_64.c From 3900b170baf0fa2bfe5ed43592e9acc95521fe0a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:04 +0200 Subject: [PATCH 1976/2804] x86_64: prepare shared crypto/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/crypto/Makefile | 17 +++++------------ arch/x86_64/crypto/Makefile_64 | 12 ++++++++++++ 2 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 arch/x86_64/crypto/Makefile_64 diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile index c96faeb842c8..fbd34ac2cda2 100644 --- a/arch/x86_64/crypto/Makefile +++ b/arch/x86_64/crypto/Makefile @@ -1,12 +1,5 @@ -# -# x86_64/crypto/Makefile -# -# Arch-specific CryptoAPI modules. -# - -obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o -obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o - -aes-x86_64-y := aes-x86_64-asm_64.o aes_64.o -twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_64.o - +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/crypto/Makefile_32 +else +include ${srctree}/arch/x86_64/crypto/Makefile_64 +endif diff --git a/arch/x86_64/crypto/Makefile_64 b/arch/x86_64/crypto/Makefile_64 new file mode 100644 index 000000000000..c96faeb842c8 --- /dev/null +++ b/arch/x86_64/crypto/Makefile_64 @@ -0,0 +1,12 @@ +# +# x86_64/crypto/Makefile +# +# Arch-specific CryptoAPI modules. +# + +obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o +obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o + +aes-x86_64-y := aes-x86_64-asm_64.o aes_64.o +twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_64.o + From 76acb5c02fce49c6efcaa30dd9374753191b3f8e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:06 +0200 Subject: [PATCH 1977/2804] x86_64: prepare shared kernel/traps.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{traps.c => traps_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{traps.c => traps_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 59b16dcc5249..b865ce6e94f2 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional -obj-y := process.o signal.o entry.o traps.o irq.o \ +obj-y := process.o signal.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps_64.c similarity index 100% rename from arch/x86_64/kernel/traps.c rename to arch/x86_64/kernel/traps_64.c From 6ba77c2d762ccac01dc9302c63e21605552f177e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:07 +0200 Subject: [PATCH 1978/2804] x86_64: prepare shared kernel/aperture.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{aperture.c => aperture_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{aperture.c => aperture_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index b865ce6e94f2..175d6045d36b 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -29,7 +29,7 @@ obj-$(CONFIG_PM) += suspend.o obj-$(CONFIG_HIBERNATION) += suspend_asm.o obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_IOMMU) += pci-gart.o aperture.o +obj-$(CONFIG_IOMMU) += pci-gart.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary.o tce.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o obj-$(CONFIG_KPROBES) += kprobes.o diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture_64.c similarity index 100% rename from arch/x86_64/kernel/aperture.c rename to arch/x86_64/kernel/aperture_64.c From cc7de6036cd93d5ca7228fe8ca921b6dc9050c83 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:09 +0200 Subject: [PATCH 1979/2804] x86_64: prepare shared kernel/io_apic.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{io_apic.c => io_apic_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{io_apic.c => io_apic_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 175d6045d36b..89a62b75dca4 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o tsc_sync.o obj-y += apic.o nmi.o -obj-y += io_apic.o mpparse.o genapic.o genapic_flat.o +obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += suspend.o diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic_64.c similarity index 100% rename from arch/x86_64/kernel/io_apic.c rename to arch/x86_64/kernel/io_apic_64.c From 2a8eb13a0689439eb9c34be062e6a5284832bb02 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:10 +0200 Subject: [PATCH 1980/2804] x86_64: prepare shared kernel/pci-calgary.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{pci-calgary.c => pci-calgary_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{pci-calgary.c => pci-calgary_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 89a62b75dca4..d71bbfb2dd10 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_HIBERNATION) += suspend_asm.o obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart.o aperture_64.o -obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary.o tce.o +obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary_64.c similarity index 100% rename from arch/x86_64/kernel/pci-calgary.c rename to arch/x86_64/kernel/pci-calgary_64.c From b34ab7a13d18e2f6ef1241db1a6209fb43478aa3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:11 +0200 Subject: [PATCH 1981/2804] x86_64: prepare shared kernel/pci-dma.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{pci-dma.c => pci-dma_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{pci-dma.c => pci-dma_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index d71bbfb2dd10..8501605ec26a 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -8,7 +8,7 @@ obj-y := process.o signal.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ - pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o bugs.o \ + pci-dma_64.o pci-nommu.o alternative.o hpet.o tsc.o bugs.o \ perfctr-watchdog.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma_64.c similarity index 100% rename from arch/x86_64/kernel/pci-dma.c rename to arch/x86_64/kernel/pci-dma_64.c From 8d7083f3b038c0196ae0f9f161f8a49e85cde164 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:13 +0200 Subject: [PATCH 1982/2804] x86_64: prepare shared kernel/i8259.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{i8259.c => i8259_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{i8259.c => i8259_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 8501605ec26a..12b3ff88f2bf 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal.o entry.o traps_64.o irq.o \ - ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ + ptrace.o time.o ioport.o ldt.o setup.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ pci-dma_64.o pci-nommu.o alternative.o hpet.o tsc.o bugs.o \ diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259_64.c similarity index 100% rename from arch/x86_64/kernel/i8259.c rename to arch/x86_64/kernel/i8259_64.c From 7d75d20c61641fe0915c7a7c9c414e5e2c6f3318 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:14 +0200 Subject: [PATCH 1983/2804] x86_64: prepare shared kernel/mce_amd.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{mce_amd.c => mce_amd_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{mce_amd.c => mce_amd_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 12b3ff88f2bf..0a03b62d7077 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -14,7 +14,7 @@ obj-y := process.o signal.o entry.o traps_64.o irq.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_X86_MCE) += mce.o therm_throt.o obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o -obj-$(CONFIG_X86_MCE_AMD) += mce_amd.o +obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd_64.c similarity index 100% rename from arch/x86_64/kernel/mce_amd.c rename to arch/x86_64/kernel/mce_amd_64.c From 2e53e9012068eab25406d014618eef8993584ff1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:16 +0200 Subject: [PATCH 1984/2804] x86_64: prepare shared kernel/relocate_kernel.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{relocate_kernel.S => relocate_kernel_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{relocate_kernel.S => relocate_kernel_64.S} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 0a03b62d7077..08115643c2e4 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o tsc_sync.o obj-y += apic.o nmi.o obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += suspend.o obj-$(CONFIG_HIBERNATION) += suspend_asm.o diff --git a/arch/x86_64/kernel/relocate_kernel.S b/arch/x86_64/kernel/relocate_kernel_64.S similarity index 100% rename from arch/x86_64/kernel/relocate_kernel.S rename to arch/x86_64/kernel/relocate_kernel_64.S From 1e272fd4a2291ad8cac52752e0753e165cfe819f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:17 +0200 Subject: [PATCH 1985/2804] x86_64: prepare shared kernel/smp.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{smp.c => smp_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{smp.c => smp_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 08115643c2e4..c17099e70954 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -20,7 +20,7 @@ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o tsc_sync.o +obj-$(CONFIG_SMP) += smp_64.o smpboot.o trampoline.o tsc_sync.o obj-y += apic.o nmi.o obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash.o diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp_64.c similarity index 100% rename from arch/x86_64/kernel/smp.c rename to arch/x86_64/kernel/smp_64.c From 8b6f65ed7a216ff4591604ffe8d718981bad1224 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:19 +0200 Subject: [PATCH 1986/2804] x86_64: prepare shared kernel/crash.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{crash.c => crash_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{crash.c => crash_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index c17099e70954..5ddd94b34b2c 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp_64.o smpboot.o trampoline.o tsc_sync.o obj-y += apic.o nmi.o obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += suspend.o obj-$(CONFIG_HIBERNATION) += suspend_asm.o diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash_64.c similarity index 100% rename from arch/x86_64/kernel/crash.c rename to arch/x86_64/kernel/crash_64.c From c3ca5f30b607298c6c33bfc5318de1cf542c50ef Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:19 +0200 Subject: [PATCH 1987/2804] x86_64: prepare shared kernel/asm-offsets.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/asm-offsets.c | 88 ++--------------------------- arch/x86_64/kernel/asm-offsets_64.c | 85 ++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 84 deletions(-) create mode 100644 arch/x86_64/kernel/asm-offsets_64.c diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c index 778953bc636c..cfa82c899f47 100644 --- a/arch/x86_64/kernel/asm-offsets.c +++ b/arch/x86_64/kernel/asm-offsets.c @@ -1,85 +1,5 @@ -/* - * Generate definitions needed by assembly language modules. - * This code generates raw asm output which is post-processed to extract - * and format the required data. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define BLANK() asm volatile("\n->" : : ) - -#define __NO_STUBS 1 -#undef __SYSCALL -#undef _ASM_X86_64_UNISTD_H_ -#define __SYSCALL(nr, sym) [nr] = 1, -static char syscalls[] = { -#include -}; - -int main(void) -{ -#define ENTRY(entry) DEFINE(tsk_ ## entry, offsetof(struct task_struct, entry)) - ENTRY(state); - ENTRY(flags); - ENTRY(thread); - ENTRY(pid); - BLANK(); -#undef ENTRY -#define ENTRY(entry) DEFINE(threadinfo_ ## entry, offsetof(struct thread_info, entry)) - ENTRY(flags); - ENTRY(addr_limit); - ENTRY(preempt_count); - ENTRY(status); - BLANK(); -#undef ENTRY -#define ENTRY(entry) DEFINE(pda_ ## entry, offsetof(struct x8664_pda, entry)) - ENTRY(kernelstack); - ENTRY(oldrsp); - ENTRY(pcurrent); - ENTRY(irqcount); - ENTRY(cpunumber); - ENTRY(irqstackptr); - ENTRY(data_offset); - BLANK(); -#undef ENTRY -#ifdef CONFIG_IA32_EMULATION -#define ENTRY(entry) DEFINE(IA32_SIGCONTEXT_ ## entry, offsetof(struct sigcontext_ia32, entry)) - ENTRY(eax); - ENTRY(ebx); - ENTRY(ecx); - ENTRY(edx); - ENTRY(esi); - ENTRY(edi); - ENTRY(ebp); - ENTRY(esp); - ENTRY(eip); - BLANK(); -#undef ENTRY - DEFINE(IA32_RT_SIGFRAME_sigcontext, - offsetof (struct rt_sigframe32, uc.uc_mcontext)); - BLANK(); +#ifdef CONFIG_X86_32 +# include "asm-offsets_32.c" +#else +# include "asm-offsets_64.c" #endif - DEFINE(pbe_address, offsetof(struct pbe, address)); - DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); - DEFINE(pbe_next, offsetof(struct pbe, next)); - BLANK(); - DEFINE(TSS_ist, offsetof(struct tss_struct, ist)); - BLANK(); - DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); - BLANK(); - DEFINE(__NR_syscall_max, sizeof(syscalls) - 1); - return 0; -} diff --git a/arch/x86_64/kernel/asm-offsets_64.c b/arch/x86_64/kernel/asm-offsets_64.c new file mode 100644 index 000000000000..778953bc636c --- /dev/null +++ b/arch/x86_64/kernel/asm-offsets_64.c @@ -0,0 +1,85 @@ +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed to extract + * and format the required data. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +#define __NO_STUBS 1 +#undef __SYSCALL +#undef _ASM_X86_64_UNISTD_H_ +#define __SYSCALL(nr, sym) [nr] = 1, +static char syscalls[] = { +#include +}; + +int main(void) +{ +#define ENTRY(entry) DEFINE(tsk_ ## entry, offsetof(struct task_struct, entry)) + ENTRY(state); + ENTRY(flags); + ENTRY(thread); + ENTRY(pid); + BLANK(); +#undef ENTRY +#define ENTRY(entry) DEFINE(threadinfo_ ## entry, offsetof(struct thread_info, entry)) + ENTRY(flags); + ENTRY(addr_limit); + ENTRY(preempt_count); + ENTRY(status); + BLANK(); +#undef ENTRY +#define ENTRY(entry) DEFINE(pda_ ## entry, offsetof(struct x8664_pda, entry)) + ENTRY(kernelstack); + ENTRY(oldrsp); + ENTRY(pcurrent); + ENTRY(irqcount); + ENTRY(cpunumber); + ENTRY(irqstackptr); + ENTRY(data_offset); + BLANK(); +#undef ENTRY +#ifdef CONFIG_IA32_EMULATION +#define ENTRY(entry) DEFINE(IA32_SIGCONTEXT_ ## entry, offsetof(struct sigcontext_ia32, entry)) + ENTRY(eax); + ENTRY(ebx); + ENTRY(ecx); + ENTRY(edx); + ENTRY(esi); + ENTRY(edi); + ENTRY(ebp); + ENTRY(esp); + ENTRY(eip); + BLANK(); +#undef ENTRY + DEFINE(IA32_RT_SIGFRAME_sigcontext, + offsetof (struct rt_sigframe32, uc.uc_mcontext)); + BLANK(); +#endif + DEFINE(pbe_address, offsetof(struct pbe, address)); + DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); + DEFINE(pbe_next, offsetof(struct pbe, next)); + BLANK(); + DEFINE(TSS_ist, offsetof(struct tss_struct, ist)); + BLANK(); + DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); + BLANK(); + DEFINE(__NR_syscall_max, sizeof(syscalls) - 1); + return 0; +} From 0856268597a2ce7efc30390695d655d3dee05ca8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:21 +0200 Subject: [PATCH 1988/2804] x86_64: prepare shared kernel/module.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{module.c => module_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{module.c => module_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 5ddd94b34b2c..8c48cd7b399c 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -38,7 +38,7 @@ obj-$(CONFIG_X86_VSMP) += vsmp.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_AUDIT) += audit.o -obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_MODULES) += module_64.o obj-$(CONFIG_PCI) += early-quirks.o obj-y += topology.o diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module_64.c similarity index 100% rename from arch/x86_64/kernel/module.c rename to arch/x86_64/kernel/module_64.c From 13a9cd42466e12113859c4d7b41561e8bbcaf09d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:21 +0200 Subject: [PATCH 1989/2804] x86_64: prepare shared kernel/vmlinux.lds.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/vmlinux.lds.S | 238 +--------------------------- arch/x86_64/kernel/vmlinux_64.lds.S | 235 +++++++++++++++++++++++++++ 2 files changed, 239 insertions(+), 234 deletions(-) create mode 100644 arch/x86_64/kernel/vmlinux_64.lds.S diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S index ba8ea97abd21..849ee611f013 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -1,235 +1,5 @@ -/* ld script to make x86-64 Linux kernel - * Written by Martin Mares ; - */ - -#define LOAD_OFFSET __START_KERNEL_map - -#include -#include - -#undef i386 /* in case the preprocessor is a 32bit one */ - -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") -OUTPUT_ARCH(i386:x86-64) -ENTRY(phys_startup_64) -jiffies_64 = jiffies; -_proxy_pda = 1; -PHDRS { - text PT_LOAD FLAGS(5); /* R_E */ - data PT_LOAD FLAGS(7); /* RWE */ - user PT_LOAD FLAGS(7); /* RWE */ - data.init PT_LOAD FLAGS(7); /* RWE */ - note PT_NOTE FLAGS(4); /* R__ */ -} -SECTIONS -{ - . = __START_KERNEL; - phys_startup_64 = startup_64 - LOAD_OFFSET; - _text = .; /* Text and read-only data */ - .text : AT(ADDR(.text) - LOAD_OFFSET) { - /* First the code that has to be first for bootstrapping */ - *(.text.head) - _stext = .; - /* Then the rest */ - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) - *(.gnu.warning) - } :text = 0x9090 - /* out-of-line lock text */ - .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) } - - _etext = .; /* End of text section */ - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } - __stop___ex_table = .; - - NOTES :text :note - - BUG_TABLE :text - - RODATA - - . = ALIGN(4); - .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { - __tracedata_start = .; - *(.tracedata) - __tracedata_end = .; - } - - . = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */ - /* Data */ - .data : AT(ADDR(.data) - LOAD_OFFSET) { - DATA_DATA - CONSTRUCTORS - } :data - - _edata = .; /* End of data section */ - - . = ALIGN(PAGE_SIZE); - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { - *(.data.cacheline_aligned) - } - . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES); - .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { - *(.data.read_mostly) - } - -#define VSYSCALL_ADDR (-10*1024*1024) -#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) -#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) - -#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR) -#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) - -#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR) -#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) - - . = VSYSCALL_ADDR; - .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user - __vsyscall_0 = VSYSCALL_VIRT_ADDR; - - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { *(.vsyscall_fn) } - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) - { *(.vsyscall_gtod_data) } - vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data); - .vsyscall_clock : AT(VLOAD(.vsyscall_clock)) - { *(.vsyscall_clock) } - vsyscall_clock = VVIRT(.vsyscall_clock); - - - .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) - { *(.vsyscall_1) } - .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) - { *(.vsyscall_2) } - - .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) } - vgetcpu_mode = VVIRT(.vgetcpu_mode); - - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) } - jiffies = VVIRT(.jiffies); - - .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) - { *(.vsyscall_3) } - - . = VSYSCALL_VIRT_ADDR + 4096; - -#undef VSYSCALL_ADDR -#undef VSYSCALL_PHYS_ADDR -#undef VSYSCALL_VIRT_ADDR -#undef VLOAD_OFFSET -#undef VLOAD -#undef VVIRT_OFFSET -#undef VVIRT - - . = ALIGN(8192); /* init_task */ - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { - *(.data.init_task) - }:data.init - - . = ALIGN(4096); - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { - *(.data.page_aligned) - } - - /* might get freed after init */ - . = ALIGN(4096); - __smp_alt_begin = .; - __smp_locks = .; - .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { - *(.smp_locks) - } - __smp_locks_end = .; - . = ALIGN(4096); - __smp_alt_end = .; - - . = ALIGN(4096); /* Init code and data */ - __init_begin = .; - .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { - _sinittext = .; - *(.init.text) - _einittext = .; - } - __initdata_begin = .; - .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } - __initdata_end = .; - . = ALIGN(16); - __setup_start = .; - .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) } - __setup_end = .; - __initcall_start = .; - .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { - INITCALLS - } - __initcall_end = .; - __con_initcall_start = .; - .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { - *(.con_initcall.init) - } - __con_initcall_end = .; - SECURITY_INIT - . = ALIGN(8); - __alt_instructions = .; - .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { - *(.altinstructions) - } - __alt_instructions_end = .; - .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { - *(.altinstr_replacement) - } - /* .exit.text is discard at runtime, not link time, to deal with references - from .altinstructions and .eh_frame */ - .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } - .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } - -/* vdso blob that is mapped into user space */ - vdso_start = . ; - .vdso : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) } - . = ALIGN(4096); - vdso_end = .; - -#ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(4096); - __initramfs_start = .; - .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) } - __initramfs_end = .; +#ifdef CONFIG_X86_32 +# include "vmlinux_32.lds.S" +#else +# include "vmlinux_64.lds.S" #endif - - PERCPU(4096) - - . = ALIGN(4096); - __init_end = .; - - . = ALIGN(4096); - __nosave_begin = .; - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } - . = ALIGN(4096); - __nosave_end = .; - - __bss_start = .; /* BSS */ - .bss : AT(ADDR(.bss) - LOAD_OFFSET) { - *(.bss.page_aligned) - *(.bss) - } - __bss_stop = .; - - _end = . ; - - /* Sections to be discarded */ - /DISCARD/ : { - *(.exitcall.exit) - *(.eh_frame) - } - - STABS_DEBUG - - DWARF_DEBUG -} diff --git a/arch/x86_64/kernel/vmlinux_64.lds.S b/arch/x86_64/kernel/vmlinux_64.lds.S new file mode 100644 index 000000000000..ba8ea97abd21 --- /dev/null +++ b/arch/x86_64/kernel/vmlinux_64.lds.S @@ -0,0 +1,235 @@ +/* ld script to make x86-64 Linux kernel + * Written by Martin Mares ; + */ + +#define LOAD_OFFSET __START_KERNEL_map + +#include +#include + +#undef i386 /* in case the preprocessor is a 32bit one */ + +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(phys_startup_64) +jiffies_64 = jiffies; +_proxy_pda = 1; +PHDRS { + text PT_LOAD FLAGS(5); /* R_E */ + data PT_LOAD FLAGS(7); /* RWE */ + user PT_LOAD FLAGS(7); /* RWE */ + data.init PT_LOAD FLAGS(7); /* RWE */ + note PT_NOTE FLAGS(4); /* R__ */ +} +SECTIONS +{ + . = __START_KERNEL; + phys_startup_64 = startup_64 - LOAD_OFFSET; + _text = .; /* Text and read-only data */ + .text : AT(ADDR(.text) - LOAD_OFFSET) { + /* First the code that has to be first for bootstrapping */ + *(.text.head) + _stext = .; + /* Then the rest */ + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + *(.fixup) + *(.gnu.warning) + } :text = 0x9090 + /* out-of-line lock text */ + .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) } + + _etext = .; /* End of text section */ + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } + __stop___ex_table = .; + + NOTES :text :note + + BUG_TABLE :text + + RODATA + + . = ALIGN(4); + .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { + __tracedata_start = .; + *(.tracedata) + __tracedata_end = .; + } + + . = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */ + /* Data */ + .data : AT(ADDR(.data) - LOAD_OFFSET) { + DATA_DATA + CONSTRUCTORS + } :data + + _edata = .; /* End of data section */ + + . = ALIGN(PAGE_SIZE); + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { + *(.data.cacheline_aligned) + } + . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES); + .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { + *(.data.read_mostly) + } + +#define VSYSCALL_ADDR (-10*1024*1024) +#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) +#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) + +#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR) +#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) + +#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR) +#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) + + . = VSYSCALL_ADDR; + .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user + __vsyscall_0 = VSYSCALL_VIRT_ADDR; + + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { *(.vsyscall_fn) } + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) + { *(.vsyscall_gtod_data) } + vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data); + .vsyscall_clock : AT(VLOAD(.vsyscall_clock)) + { *(.vsyscall_clock) } + vsyscall_clock = VVIRT(.vsyscall_clock); + + + .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) + { *(.vsyscall_1) } + .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) + { *(.vsyscall_2) } + + .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) } + vgetcpu_mode = VVIRT(.vgetcpu_mode); + + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) } + jiffies = VVIRT(.jiffies); + + .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) + { *(.vsyscall_3) } + + . = VSYSCALL_VIRT_ADDR + 4096; + +#undef VSYSCALL_ADDR +#undef VSYSCALL_PHYS_ADDR +#undef VSYSCALL_VIRT_ADDR +#undef VLOAD_OFFSET +#undef VLOAD +#undef VVIRT_OFFSET +#undef VVIRT + + . = ALIGN(8192); /* init_task */ + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) + }:data.init + + . = ALIGN(4096); + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + *(.data.page_aligned) + } + + /* might get freed after init */ + . = ALIGN(4096); + __smp_alt_begin = .; + __smp_locks = .; + .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { + *(.smp_locks) + } + __smp_locks_end = .; + . = ALIGN(4096); + __smp_alt_end = .; + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { + _sinittext = .; + *(.init.text) + _einittext = .; + } + __initdata_begin = .; + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } + __initdata_end = .; + . = ALIGN(16); + __setup_start = .; + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) } + __setup_end = .; + __initcall_start = .; + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { + INITCALLS + } + __initcall_end = .; + __con_initcall_start = .; + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + *(.con_initcall.init) + } + __con_initcall_end = .; + SECURITY_INIT + . = ALIGN(8); + __alt_instructions = .; + .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { + *(.altinstructions) + } + __alt_instructions_end = .; + .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { + *(.altinstr_replacement) + } + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } + .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } + +/* vdso blob that is mapped into user space */ + vdso_start = . ; + .vdso : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) } + . = ALIGN(4096); + vdso_end = .; + +#ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(4096); + __initramfs_start = .; + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) } + __initramfs_end = .; +#endif + + PERCPU(4096) + + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(4096); + __nosave_begin = .; + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } + . = ALIGN(4096); + __nosave_end = .; + + __bss_start = .; /* BSS */ + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { + *(.bss.page_aligned) + *(.bss) + } + __bss_stop = .; + + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exitcall.exit) + *(.eh_frame) + } + + STABS_DEBUG + + DWARF_DEBUG +} From bd751ae043e89e2e44e6af784df5a70694b1c9b7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:23 +0200 Subject: [PATCH 1990/2804] x86_64: prepare shared kernel/apic.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{apic.c => apic_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{apic.c => apic_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 8c48cd7b399c..b4e36e69150e 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp_64.o smpboot.o trampoline.o tsc_sync.o -obj-y += apic.o nmi.o +obj-y += apic_64.o nmi.o obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic_64.c similarity index 100% rename from arch/x86_64/kernel/apic.c rename to arch/x86_64/kernel/apic_64.c From 5b8d883929091c647635392bafc8fc0962d4b43f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:24 +0200 Subject: [PATCH 1991/2804] x86_64: prepare shared kernel/nmi.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{nmi.c => nmi_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{nmi.c => nmi_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index b4e36e69150e..fbaba5335b66 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp_64.o smpboot.o trampoline.o tsc_sync.o -obj-y += apic_64.o nmi.o +obj-y += apic_64.o nmi_64.o obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi_64.c similarity index 100% rename from arch/x86_64/kernel/nmi.c rename to arch/x86_64/kernel/nmi_64.c From 3940abdf5e7f62bf47c4117f9201c121fbb0ab16 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:26 +0200 Subject: [PATCH 1992/2804] x86_64: prepare shared kernel/hpet.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{hpet.c => hpet_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{hpet.c => hpet_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index fbaba5335b66..e717a324bd8a 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -8,7 +8,7 @@ obj-y := process.o signal.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ - pci-dma_64.o pci-nommu.o alternative.o hpet.o tsc.o bugs.o \ + pci-dma_64.o pci-nommu.o alternative.o hpet_64.o tsc.o bugs.o \ perfctr-watchdog.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/x86_64/kernel/hpet.c b/arch/x86_64/kernel/hpet_64.c similarity index 100% rename from arch/x86_64/kernel/hpet.c rename to arch/x86_64/kernel/hpet_64.c From b43312c45e51aa79d76850f85a5731f24c1b0d8d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:27 +0200 Subject: [PATCH 1993/2804] x86_64: prepare shared kernel/e820.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{e820.c => e820_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{e820.c => e820_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index e717a324bd8a..e290dfa84004 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -7,7 +7,7 @@ EXTRA_AFLAGS := -traditional obj-y := process.o signal.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ - setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ + setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ pci-dma_64.o pci-nommu.o alternative.o hpet_64.o tsc.o bugs.o \ perfctr-watchdog.o diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820_64.c similarity index 100% rename from arch/x86_64/kernel/e820.c rename to arch/x86_64/kernel/e820_64.c From 36e54eec6871634a2f8f12d42a3a1c08ed0cbca5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:28 +0200 Subject: [PATCH 1994/2804] x86_64: prepare shared kernel/mce_intel.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{mce_intel.c => mce_intel_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{mce_intel.c => mce_intel_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index e290dfa84004..79e1685ecb33 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -13,7 +13,7 @@ obj-y := process.o signal.o entry.o traps_64.o irq.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_X86_MCE) += mce.o therm_throt.o -obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o +obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ obj-$(CONFIG_ACPI) += acpi/ diff --git a/arch/x86_64/kernel/mce_intel.c b/arch/x86_64/kernel/mce_intel_64.c similarity index 100% rename from arch/x86_64/kernel/mce_intel.c rename to arch/x86_64/kernel/mce_intel_64.c From 7b022a67921723774a2d2fa018dfd9a5e5c3c90f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:30 +0200 Subject: [PATCH 1995/2804] x86_64: prepare shared kernel/smpboot.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{smpboot.c => smpboot_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{smpboot.c => smpboot_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 79e1685ecb33..fce6f3f3b4d6 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -20,7 +20,7 @@ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_SMP) += smp_64.o smpboot.o trampoline.o tsc_sync.o +obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline.o tsc_sync.o obj-y += apic_64.o nmi_64.o obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot_64.c similarity index 100% rename from arch/x86_64/kernel/smpboot.c rename to arch/x86_64/kernel/smpboot_64.c From c30501e798fad2be81379bac98b6cfe731308f94 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:31 +0200 Subject: [PATCH 1996/2804] x86_64: prepare shared kernel/setup.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{setup.c => setup_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{setup.c => setup_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index fce6f3f3b4d6..14316a259aea 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal.o entry.o traps_64.o irq.o \ - ptrace.o time.o ioport.o ldt.o setup.o i8259_64.o sys_x86_64.o \ + ptrace.o time.o ioport.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ pci-dma_64.o pci-nommu.o alternative.o hpet_64.o tsc.o bugs.o \ diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup_64.c similarity index 100% rename from arch/x86_64/kernel/setup.c rename to arch/x86_64/kernel/setup_64.c From 21a44007745783d8997ed115852a42fb2613bf9a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:33 +0200 Subject: [PATCH 1997/2804] x86_64: prepare shared kernel/vsyscall.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 4 ++-- arch/x86_64/kernel/{vsyscall.c => vsyscall_64.c} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/x86_64/kernel/{vsyscall.c => vsyscall_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 14316a259aea..a5ff38d5097c 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ - x8664_ksyms.o i387.o syscall.o vsyscall.o \ + x8664_ksyms.o i387.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ pci-dma_64.o pci-nommu.o alternative.o hpet_64.o tsc.o bugs.o \ perfctr-watchdog.o @@ -46,7 +46,7 @@ obj-y += intel_cacheinfo.o obj-y += addon_cpuid_features.o obj-y += pcspeaker.o -CFLAGS_vsyscall.o := $(PROFILING) -g0 +CFLAGS_vsyscall_64.o := $(PROFILING) -g0 therm_throt-y += ../../i386/kernel/cpu/mcheck/therm_throt.o bootflag-y += ../../i386/kernel/bootflag.o diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall_64.c similarity index 100% rename from arch/x86_64/kernel/vsyscall.c rename to arch/x86_64/kernel/vsyscall_64.c From 2cf08fa82161bf398c1a6321d738a45730b0acd2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:34 +0200 Subject: [PATCH 1998/2804] x86_64: prepare shared kernel/ioport.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{ioport.c => ioport_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{ioport.c => ioport_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index a5ff38d5097c..7918fee8b9b3 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal.o entry.o traps_64.o irq.o \ - ptrace.o time.o ioport.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ + ptrace.o time.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ pci-dma_64.o pci-nommu.o alternative.o hpet_64.o tsc.o bugs.o \ diff --git a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport_64.c similarity index 100% rename from arch/x86_64/kernel/ioport.c rename to arch/x86_64/kernel/ioport_64.c From e86a989de27d4c0226928d6132f284f6156f30f7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:36 +0200 Subject: [PATCH 1999/2804] x86_64: prepare shared kernel/tce.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{tce.c => tce_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{tce.c => tce_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 7918fee8b9b3..4702333f93b1 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_HIBERNATION) += suspend_asm.o obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart.o aperture_64.o -obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce.o +obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce_64.c similarity index 100% rename from arch/x86_64/kernel/tce.c rename to arch/x86_64/kernel/tce_64.c From ba733ec4725df406a6ff5c5c1e6c447f42bbf39d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:37 +0200 Subject: [PATCH 2000/2804] x86_64: prepare shared kernel/suspend_asm.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{suspend_asm.S => suspend_asm_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{suspend_asm.S => suspend_asm_64.S} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 4702333f93b1..9799e58c243a 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -26,7 +26,7 @@ obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += suspend.o -obj-$(CONFIG_HIBERNATION) += suspend_asm.o +obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart.o aperture_64.o diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm_64.S similarity index 100% rename from arch/x86_64/kernel/suspend_asm.S rename to arch/x86_64/kernel/suspend_asm_64.S From c4fbd8a94697ff1186130542f36d7b520b288001 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:38 +0200 Subject: [PATCH 2001/2804] x86_64: prepare shared kernel/pci-nommu.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{pci-nommu.c => pci-nommu_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{pci-nommu.c => pci-nommu_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 9799e58c243a..e74f4ddba1cd 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -8,7 +8,7 @@ obj-y := process.o signal.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ - pci-dma_64.o pci-nommu.o alternative.o hpet_64.o tsc.o bugs.o \ + pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs.o \ perfctr-watchdog.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu_64.c similarity index 100% rename from arch/x86_64/kernel/pci-nommu.c rename to arch/x86_64/kernel/pci-nommu_64.c From 4c1c61c408ce5e8024298259831d71d6079a9a6d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:40 +0200 Subject: [PATCH 2002/2804] x86_64: prepare shared kernel/signal.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{signal.c => signal_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{signal.c => signal_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index e74f4ddba1cd..d2233775e2f7 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional -obj-y := process.o signal.o entry.o traps_64.o irq.o \ +obj-y := process.o signal_64.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal_64.c similarity index 100% rename from arch/x86_64/kernel/signal.c rename to arch/x86_64/kernel/signal_64.c From eb102ecb73dffbbbdfccd0ea582f405b0c0cc1fe Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:41 +0200 Subject: [PATCH 2003/2804] x86_64: prepare shared kernel/i387.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{i387.c => i387_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{i387.c => i387_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index d2233775e2f7..5aadea3093bc 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal_64.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ - x8664_ksyms.o i387.o syscall.o vsyscall_64.o \ + x8664_ksyms.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs.o \ perfctr-watchdog.o diff --git a/arch/x86_64/kernel/i387.c b/arch/x86_64/kernel/i387_64.c similarity index 100% rename from arch/x86_64/kernel/i387.c rename to arch/x86_64/kernel/i387_64.c From 4f1124c5bcc5e0b139930d98687db80fd4d67a1c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:43 +0200 Subject: [PATCH 2004/2804] x86_64: prepare shared kernel/pci-swiotlb.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{pci-swiotlb.c => pci-swiotlb_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{pci-swiotlb.c => pci-swiotlb_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 5aadea3093bc..c6c9eb25f873 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o -obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o +obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o obj-$(CONFIG_X86_VSMP) += vsmp.o diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb_64.c similarity index 100% rename from arch/x86_64/kernel/pci-swiotlb.c rename to arch/x86_64/kernel/pci-swiotlb_64.c From 3b69915deee81842ba192c251573141ac3af86db Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:44 +0200 Subject: [PATCH 2005/2804] x86_64: prepare shared kernel/bugs.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{bugs.c => bugs_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{bugs.c => bugs_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index c6c9eb25f873..a6b3ea5805cb 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -8,7 +8,7 @@ obj-y := process.o signal_64.o entry.o traps_64.o irq.o \ ptrace.o time.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ - pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs.o \ + pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs_64.o \ perfctr-watchdog.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/x86_64/kernel/bugs.c b/arch/x86_64/kernel/bugs_64.c similarity index 100% rename from arch/x86_64/kernel/bugs.c rename to arch/x86_64/kernel/bugs_64.c From 198a071dff9ee61973edf8c58f22ecd5bc4892c8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:46 +0200 Subject: [PATCH 2006/2804] x86_64: prepare shared kernel/genapic.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{genapic.c => genapic_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{genapic.c => genapic_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index a6b3ea5805cb..edf4c88a98d4 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline.o tsc_sync.o obj-y += apic_64.o nmi_64.o -obj-y += io_apic_64.o mpparse.o genapic.o genapic_flat.o +obj-y += io_apic_64.o mpparse.o genapic_64.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += suspend.o diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic_64.c similarity index 100% rename from arch/x86_64/kernel/genapic.c rename to arch/x86_64/kernel/genapic_64.c From a6d83df15c53a5f503c50e3d824c1cf3f89ebb1a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:47 +0200 Subject: [PATCH 2007/2804] x86_64: prepare shared kernel/vsmp.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{vsmp.c => vsmp_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{vsmp.c => vsmp_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index edf4c88a98d4..959bb68959af 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o -obj-$(CONFIG_X86_VSMP) += vsmp.o +obj-$(CONFIG_X86_VSMP) += vsmp_64.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_AUDIT) += audit.o diff --git a/arch/x86_64/kernel/vsmp.c b/arch/x86_64/kernel/vsmp_64.c similarity index 100% rename from arch/x86_64/kernel/vsmp.c rename to arch/x86_64/kernel/vsmp_64.c From 1a333ab079458b8ca58ebb761ebca48b7fc9ab5c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:49 +0200 Subject: [PATCH 2008/2804] x86_64: prepare shared kernel/early-quirks.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{early-quirks.c => early-quirks_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{early-quirks.c => early-quirks_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 959bb68959af..1af0839b8d3f 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -39,7 +39,7 @@ obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_MODULES) += module_64.o -obj-$(CONFIG_PCI) += early-quirks.o +obj-$(CONFIG_PCI) += early-quirks_64.o obj-y += topology.o obj-y += intel_cacheinfo.o diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks_64.c similarity index 100% rename from arch/x86_64/kernel/early-quirks.c rename to arch/x86_64/kernel/early-quirks_64.c From 93de1ef4543e80a1a9bfdb7a854d155f6530df2e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:50 +0200 Subject: [PATCH 2009/2804] x86_64: prepare shared kernel/pmtimer.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{pmtimer.c => pmtimer_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{pmtimer.c => pmtimer_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 1af0839b8d3f..9939968285ed 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_IOMMU) += pci-gart.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o obj-$(CONFIG_KPROBES) += kprobes.o -obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o +obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o obj-$(CONFIG_X86_VSMP) += vsmp_64.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_AUDIT) += audit.o diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer_64.c similarity index 100% rename from arch/x86_64/kernel/pmtimer.c rename to arch/x86_64/kernel/pmtimer_64.c From 1d56734f9e51b21a92a02f526c278c037de65822 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:51 +0200 Subject: [PATCH 2010/2804] x86_64: prepare shared kernel/mpparse.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{mpparse.c => mpparse_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{mpparse.c => mpparse_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 9939968285ed..fc8d1319e911 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline.o tsc_sync.o obj-y += apic_64.o nmi_64.o -obj-y += io_apic_64.o mpparse.o genapic_64.o genapic_flat.o +obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += suspend.o diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse_64.c similarity index 100% rename from arch/x86_64/kernel/mpparse.c rename to arch/x86_64/kernel/mpparse_64.c From 96a6674c5ad6a6f596aab6ac826b93f5cd846749 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:53 +0200 Subject: [PATCH 2011/2804] x86_64: prepare shared kernel/mce.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{mce.c => mce_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{mce.c => mce_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index fc8d1319e911..b0a29b510427 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := process.o signal_64.o entry.o traps_64.o irq.o \ perfctr-watchdog.o obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-$(CONFIG_X86_MCE) += mce.o therm_throt.o +obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce_64.c similarity index 100% rename from arch/x86_64/kernel/mce.c rename to arch/x86_64/kernel/mce_64.c From abb11834c6515161babea211a7be1fc6dcb893dc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:54 +0200 Subject: [PATCH 2012/2804] x86_64: prepare shared kernel/time.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{time.c => time_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{time.c => time_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index b0a29b510427..1c9ae60f0bf5 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal_64.o entry.o traps_64.o irq.o \ - ptrace.o time.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ + ptrace.o time_64.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs_64.o \ diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time_64.c similarity index 100% rename from arch/x86_64/kernel/time.c rename to arch/x86_64/kernel/time_64.c From e877d83a8e2643a026559a60ac6d1ee9fb827677 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:56 +0200 Subject: [PATCH 2013/2804] x86_64: prepare shared kernel/audit.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{audit.c => audit_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{audit.c => audit_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 1c9ae60f0bf5..edd3ad7995d6 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -36,7 +36,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o obj-$(CONFIG_X86_VSMP) += vsmp_64.o obj-$(CONFIG_K8_NB) += k8.o -obj-$(CONFIG_AUDIT) += audit.o +obj-$(CONFIG_AUDIT) += audit_64.o obj-$(CONFIG_MODULES) += module_64.o obj-$(CONFIG_PCI) += early-quirks_64.o diff --git a/arch/x86_64/kernel/audit.c b/arch/x86_64/kernel/audit_64.c similarity index 100% rename from arch/x86_64/kernel/audit.c rename to arch/x86_64/kernel/audit_64.c From 2c7de090f86d9972a741a313de76996865814b74 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:57 +0200 Subject: [PATCH 2014/2804] x86_64: prepare shared kernel/suspend.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{suspend.c => suspend_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{suspend.c => suspend_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index edd3ad7995d6..2da29ed79c13 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -25,7 +25,7 @@ obj-y += apic_64.o nmi_64.o obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o -obj-$(CONFIG_PM) += suspend.o +obj-$(CONFIG_PM) += suspend_64.o obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend_64.c similarity index 100% rename from arch/x86_64/kernel/suspend.c rename to arch/x86_64/kernel/suspend_64.c From 7950ca5d01f6cb5ec99ccd8548ef6a55c9ea2690 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:14:59 +0200 Subject: [PATCH 2015/2804] x86_64: prepare shared kernel/ptrace.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{ptrace.c => ptrace_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{ptrace.c => ptrace_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 2da29ed79c13..6905cdfe75fb 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal_64.o entry.o traps_64.o irq.o \ - ptrace.o time_64.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ + ptrace_64.o time_64.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs_64.o \ diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace_64.c similarity index 100% rename from arch/x86_64/kernel/ptrace.c rename to arch/x86_64/kernel/ptrace_64.c From 201962c9d38bc57b4764ecd03068902f8d2ad54c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:00 +0200 Subject: [PATCH 2016/2804] x86_64: prepare shared kernel/irq.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{irq.c => irq_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{irq.c => irq_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 6905cdfe75fb..7a71d0e7d48a 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional -obj-y := process.o signal_64.o entry.o traps_64.o irq.o \ +obj-y := process.o signal_64.o entry.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq_64.c similarity index 100% rename from arch/x86_64/kernel/irq.c rename to arch/x86_64/kernel/irq_64.c From 32404da2ac967a8776083259e05afc4ea6567cea Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:01 +0200 Subject: [PATCH 2017/2804] x86_64: prepare shared kernel/trampoline.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{trampoline.S => trampoline_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{trampoline.S => trampoline_64.S} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 7a71d0e7d48a..2bbe7df19daa 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -20,7 +20,7 @@ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline.o tsc_sync.o +obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline_64.o tsc_sync.o obj-y += apic_64.o nmi_64.o obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o diff --git a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline_64.S similarity index 100% rename from arch/x86_64/kernel/trampoline.S rename to arch/x86_64/kernel/trampoline_64.S From 1cce595a8394105ea56499f94373dd8d5b0d3b51 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:03 +0200 Subject: [PATCH 2018/2804] x86_64: prepare shared kernel/reboot.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{reboot.c => reboot_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{reboot.c => reboot_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 2bbe7df19daa..bb043aee7f4a 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -7,7 +7,7 @@ EXTRA_AFLAGS := -traditional obj-y := process.o signal_64.o entry.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387_64.o syscall.o vsyscall_64.o \ - setup64.o bootflag.o e820_64.o reboot.o quirks.o i8237.o \ + setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs_64.o \ perfctr-watchdog.o diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot_64.c similarity index 100% rename from arch/x86_64/kernel/reboot.c rename to arch/x86_64/kernel/reboot_64.c From 0c45a7730bbad8a3770da2698243e45b117092be Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:04 +0200 Subject: [PATCH 2019/2804] x86_64: prepare shared kernel/crash_dump.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{crash_dump.c => crash_dump_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{crash_dump.c => crash_dump_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index bb043aee7f4a..71e90bb88e42 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline_64.o tsc_sync.o obj-y += apic_64.o nmi_64.o obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o -obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +obj-$(CONFIG_CRASH_DUMP) += crash_dump_64.o obj-$(CONFIG_PM) += suspend_64.o obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ diff --git a/arch/x86_64/kernel/crash_dump.c b/arch/x86_64/kernel/crash_dump_64.c similarity index 100% rename from arch/x86_64/kernel/crash_dump.c rename to arch/x86_64/kernel/crash_dump_64.c From c76e79e010a8c48a95cfa947e192c40cdae23f7e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:06 +0200 Subject: [PATCH 2020/2804] x86_64: prepare shared kernel/ldt.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{ldt.c => ldt_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{ldt.c => ldt_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 71e90bb88e42..ddc3154b7c29 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -5,7 +5,7 @@ extra-y := head.o head64.o init_task.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal_64.o entry.o traps_64.o irq_64.o \ - ptrace_64.o time_64.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \ + ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs_64.o \ diff --git a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt_64.c similarity index 100% rename from arch/x86_64/kernel/ldt.c rename to arch/x86_64/kernel/ldt_64.c From 5d0c9ec6dd7204e5895260d83a90c5a0d64143f7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:07 +0200 Subject: [PATCH 2021/2804] x86_64: prepare shared kernel/init_task.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/Makefile | 2 +- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{init_task.c => init_task_64.c} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/x86_64/kernel/{init_task.c => init_task_64.c} (100%) diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index c76351c13bdd..97de9cbd3b7f 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -71,7 +71,7 @@ CFLAGS += $(cflags-y) CFLAGS_KERNEL += $(cflags-kernel-y) AFLAGS += -m64 -head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o +head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task_64.o libs-y += arch/x86_64/lib/ core-y += arch/x86_64/kernel/ \ diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index ddc3154b7c29..ce02b64bb261 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o head64.o init_task.o vmlinux.lds +extra-y := head.o head64.o init_task_64.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal_64.o entry.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ diff --git a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task_64.c similarity index 100% rename from arch/x86_64/kernel/init_task.c rename to arch/x86_64/kernel/init_task_64.c From e6505ca668b2c21c06abb7bb96a8272a6f83411f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:09 +0200 Subject: [PATCH 2022/2804] x86_64: prepare shared kernel/x8664_ksyms.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{x8664_ksyms.c => x8664_ksyms_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{x8664_ksyms.c => x8664_ksyms_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index ce02b64bb261..d50ba296437c 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o head64.o init_task_64.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process.o signal_64.o entry.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ - x8664_ksyms.o i387_64.o syscall.o vsyscall_64.o \ + x8664_ksyms_64.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs_64.o \ perfctr-watchdog.o diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms_64.c similarity index 100% rename from arch/x86_64/kernel/x8664_ksyms.c rename to arch/x86_64/kernel/x8664_ksyms_64.c From bd4c1b5baacbc7e4257c00f087abfd3f7aef2dfb Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:10 +0200 Subject: [PATCH 2023/2804] x86_64: prepare shared kernel/process.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{process.c => process_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{process.c => process_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index d50ba296437c..976ea5e7222b 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o head64.o init_task_64.o vmlinux.lds EXTRA_AFLAGS := -traditional -obj-y := process.o signal_64.o entry.o traps_64.o irq_64.o \ +obj-y := process_64.o signal_64.o entry.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms_64.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process_64.c similarity index 100% rename from arch/x86_64/kernel/process.c rename to arch/x86_64/kernel/process_64.c From 81656390b8dec51ba7b4713a321b353fb2d3ccb1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:12 +0200 Subject: [PATCH 2024/2804] x86_64: prepare shared kernel/kprobes.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{kprobes.c => kprobes_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{kprobes.c => kprobes_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 976ea5e7222b..fd19c73a8da0 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -32,7 +32,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o -obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KPROBES) += kprobes_64.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o obj-$(CONFIG_X86_VSMP) += vsmp_64.o obj-$(CONFIG_K8_NB) += k8.o diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes_64.c similarity index 100% rename from arch/x86_64/kernel/kprobes.c rename to arch/x86_64/kernel/kprobes_64.c From 2a232a7656c085ecde659dc1dbaf65cc4fbf7ed7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:13 +0200 Subject: [PATCH 2025/2804] x86_64: prepare shared kernel/genapic_flat.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{genapic_flat.c => genapic_flat_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{genapic_flat.c => genapic_flat_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index fd19c73a8da0..da65eb3a6b53 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline_64.o tsc_sync.o obj-y += apic_64.o nmi_64.o -obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat.o +obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat_64.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_64.o obj-$(CONFIG_PM) += suspend_64.o diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat_64.c similarity index 100% rename from arch/x86_64/kernel/genapic_flat.c rename to arch/x86_64/kernel/genapic_flat_64.c From 8e59c31a0af824ddb158a7007faa66fc8ca4dbe4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:14 +0200 Subject: [PATCH 2026/2804] x86_64: prepare shared kernel/entry.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{entry.S => entry_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{entry.S => entry_64.S} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index da65eb3a6b53..402885029106 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o head64.o init_task_64.o vmlinux.lds EXTRA_AFLAGS := -traditional -obj-y := process_64.o signal_64.o entry.o traps_64.o irq_64.o \ +obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms_64.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry_64.S similarity index 100% rename from arch/x86_64/kernel/entry.S rename to arch/x86_64/kernel/entry_64.S From 13c4896799d1610956f307534aa22d644b92bee7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:16 +0200 Subject: [PATCH 2027/2804] x86_64: prepare shared kernel/tsc.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{tsc.c => tsc_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{tsc.c => tsc_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 402885029106..2c0e778e8acf 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -8,7 +8,7 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms_64.o i387_64.o syscall.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ - pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc.o bugs_64.o \ + pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \ perfctr-watchdog.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc_64.c similarity index 100% rename from arch/x86_64/kernel/tsc.c rename to arch/x86_64/kernel/tsc_64.c From 977d5654cb630d6845b84a984fb5698e839f20f2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:17 +0200 Subject: [PATCH 2028/2804] x86_64: prepare shared kernel/head.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/Makefile | 2 +- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{head.S => head_64.S} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/x86_64/kernel/{head.S => head_64.S} (100%) diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 97de9cbd3b7f..c556b6661514 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -71,7 +71,7 @@ CFLAGS += $(cflags-y) CFLAGS_KERNEL += $(cflags-kernel-y) AFLAGS += -m64 -head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task_64.o +head-y := arch/x86_64/kernel/head_64.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task_64.o libs-y += arch/x86_64/lib/ core-y += arch/x86_64/kernel/ \ diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 2c0e778e8acf..b65abc2a15a4 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -extra-y := head.o head64.o init_task_64.o vmlinux.lds +extra-y := head_64.o head64.o init_task_64.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head_64.S similarity index 100% rename from arch/x86_64/kernel/head.S rename to arch/x86_64/kernel/head_64.S From e0a84f689b4373cbaa6d3a5bc5c52a613005fed1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:19 +0200 Subject: [PATCH 2029/2804] x86_64: prepare shared kernel/verify_cpu.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/boot/compressed/head.S | 2 +- arch/x86_64/kernel/acpi/wakeup.S | 2 +- arch/x86_64/kernel/trampoline_64.S | 2 +- arch/x86_64/kernel/{verify_cpu.S => verify_cpu_64.S} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename arch/x86_64/kernel/{verify_cpu.S => verify_cpu_64.S} (100%) diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S index 9fd8030cc54f..49467640751f 100644 --- a/arch/x86_64/boot/compressed/head.S +++ b/arch/x86_64/boot/compressed/head.S @@ -174,7 +174,7 @@ no_longmode: hlt jmp 1b -#include "../../kernel/verify_cpu.S" +#include "../../kernel/verify_cpu_64.S" /* Be careful here startup_64 needs to be at a predictable * address so I can export it in an ELF header. Bootloaders diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S index a06f2bcabef9..8b4357e1efe0 100644 --- a/arch/x86_64/kernel/acpi/wakeup.S +++ b/arch/x86_64/kernel/acpi/wakeup.S @@ -269,7 +269,7 @@ no_longmode: movb $0xbc,%al ; outb %al,$0x80 jmp no_longmode -#include "../verify_cpu.S" +#include "../verify_cpu_64.S" /* This code uses an extended set of video mode numbers. These include: * Aliases for standard modes diff --git a/arch/x86_64/kernel/trampoline_64.S b/arch/x86_64/kernel/trampoline_64.S index e7e2764c461b..607983b0d27b 100644 --- a/arch/x86_64/kernel/trampoline_64.S +++ b/arch/x86_64/kernel/trampoline_64.S @@ -126,7 +126,7 @@ startup_64: no_longmode: hlt jmp no_longmode -#include "verify_cpu.S" +#include "verify_cpu_64.S" # Careful these need to be in the same 64K segment as the above; tidt: diff --git a/arch/x86_64/kernel/verify_cpu.S b/arch/x86_64/kernel/verify_cpu_64.S similarity index 100% rename from arch/x86_64/kernel/verify_cpu.S rename to arch/x86_64/kernel/verify_cpu_64.S From 6e04c835f1b9f1adde05b7439eaa1a4fff9ce8c7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:21 +0200 Subject: [PATCH 2030/2804] x86_64: prepare shared kernel/machine_kexec.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{machine_kexec.c => machine_kexec_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{machine_kexec.c => machine_kexec_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index b65abc2a15a4..991a36e6873d 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline_64.o tsc_sync.o obj-y += apic_64.o nmi_64.o obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat_64.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_64.o crash_64.o +obj-$(CONFIG_KEXEC) += machine_kexec_64.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_64.o obj-$(CONFIG_PM) += suspend_64.o obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec_64.c similarity index 100% rename from arch/x86_64/kernel/machine_kexec.c rename to arch/x86_64/kernel/machine_kexec_64.c From f328f81b54ecc19d2d13710dca01e5f01f1ff449 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:22 +0200 Subject: [PATCH 2031/2804] x86_64: prepare shared kernel/syscall.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{syscall.c => syscall_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{syscall.c => syscall_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 991a36e6873d..2336f1cb654c 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head_64.o head64.o init_task_64.o vmlinux.lds EXTRA_AFLAGS := -traditional obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ - x8664_ksyms_64.o i387_64.o syscall.o vsyscall_64.o \ + x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \ perfctr-watchdog.o diff --git a/arch/x86_64/kernel/syscall.c b/arch/x86_64/kernel/syscall_64.c similarity index 100% rename from arch/x86_64/kernel/syscall.c rename to arch/x86_64/kernel/syscall_64.c From 46b4c119b4b67dfab3f1e644d6f8bdbf28f18411 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:23 +0200 Subject: [PATCH 2032/2804] x86_64: prepare shared kernel/pci-gart.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/{pci-gart.c => pci-gart_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/{pci-gart.c => pci-gart_64.c} (100%) diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 2336f1cb654c..8253617af12e 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -29,7 +29,7 @@ obj-$(CONFIG_PM) += suspend_64.o obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_IOMMU) += pci-gart.o aperture_64.o +obj-$(CONFIG_IOMMU) += pci-gart_64.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o obj-$(CONFIG_KPROBES) += kprobes_64.o diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart_64.c similarity index 100% rename from arch/x86_64/kernel/pci-gart.c rename to arch/x86_64/kernel/pci-gart_64.c From a7a67e0e2db47cb8cfa2c550aaedf168b8275cce Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:24 +0200 Subject: [PATCH 2033/2804] x86_64: prepare shared kernel/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/Makefile | 68 +++------------------------------- arch/x86_64/kernel/Makefile_64 | 63 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 63 deletions(-) create mode 100644 arch/x86_64/kernel/Makefile_64 diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 8253617af12e..d3ebd1699826 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -1,63 +1,5 @@ -# -# Makefile for the linux kernel. -# - -extra-y := head_64.o head64.o init_task_64.o vmlinux.lds -EXTRA_AFLAGS := -traditional -obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ - ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ - x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ - setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ - pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \ - perfctr-watchdog.o - -obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o -obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o -obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o -obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ -obj-$(CONFIG_ACPI) += acpi/ -obj-$(CONFIG_X86_MSR) += msr.o -obj-$(CONFIG_MICROCODE) += microcode.o -obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline_64.o tsc_sync.o -obj-y += apic_64.o nmi_64.o -obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat_64.o -obj-$(CONFIG_KEXEC) += machine_kexec_64.o relocate_kernel_64.o crash_64.o -obj-$(CONFIG_CRASH_DUMP) += crash_dump_64.o -obj-$(CONFIG_PM) += suspend_64.o -obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o -obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ -obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_IOMMU) += pci-gart_64.o aperture_64.o -obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o -obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o -obj-$(CONFIG_KPROBES) += kprobes_64.o -obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o -obj-$(CONFIG_X86_VSMP) += vsmp_64.o -obj-$(CONFIG_K8_NB) += k8.o -obj-$(CONFIG_AUDIT) += audit_64.o - -obj-$(CONFIG_MODULES) += module_64.o -obj-$(CONFIG_PCI) += early-quirks_64.o - -obj-y += topology.o -obj-y += intel_cacheinfo.o -obj-y += addon_cpuid_features.o -obj-y += pcspeaker.o - -CFLAGS_vsyscall_64.o := $(PROFILING) -g0 - -therm_throt-y += ../../i386/kernel/cpu/mcheck/therm_throt.o -bootflag-y += ../../i386/kernel/bootflag.o -cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o -topology-y += ../../i386/kernel/topology.o -microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o -intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o -addon_cpuid_features-y += ../../i386/kernel/cpu/addon_cpuid_features.o -quirks-y += ../../i386/kernel/quirks.o -i8237-y += ../../i386/kernel/i8237.o -msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o -alternative-y += ../../i386/kernel/alternative.o -pcspeaker-y += ../../i386/kernel/pcspeaker.o -perfctr-watchdog-y += ../../i386/kernel/cpu/perfctr-watchdog.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/kernel/Makefile_32 +else +include ${srctree}/arch/x86_64/kernel/Makefile_64 +endif diff --git a/arch/x86_64/kernel/Makefile_64 b/arch/x86_64/kernel/Makefile_64 new file mode 100644 index 000000000000..8253617af12e --- /dev/null +++ b/arch/x86_64/kernel/Makefile_64 @@ -0,0 +1,63 @@ +# +# Makefile for the linux kernel. +# + +extra-y := head_64.o head64.o init_task_64.o vmlinux.lds +EXTRA_AFLAGS := -traditional +obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ + ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ + x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ + setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ + pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \ + perfctr-watchdog.o + +obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o +obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o +obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o +obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ +obj-$(CONFIG_ACPI) += acpi/ +obj-$(CONFIG_X86_MSR) += msr.o +obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_X86_CPUID) += cpuid.o +obj-$(CONFIG_SMP) += smp_64.o smpboot_64.o trampoline_64.o tsc_sync.o +obj-y += apic_64.o nmi_64.o +obj-y += io_apic_64.o mpparse_64.o genapic_64.o genapic_flat_64.o +obj-$(CONFIG_KEXEC) += machine_kexec_64.o relocate_kernel_64.o crash_64.o +obj-$(CONFIG_CRASH_DUMP) += crash_dump_64.o +obj-$(CONFIG_PM) += suspend_64.o +obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o +obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_IOMMU) += pci-gart_64.o aperture_64.o +obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o +obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o +obj-$(CONFIG_KPROBES) += kprobes_64.o +obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o +obj-$(CONFIG_X86_VSMP) += vsmp_64.o +obj-$(CONFIG_K8_NB) += k8.o +obj-$(CONFIG_AUDIT) += audit_64.o + +obj-$(CONFIG_MODULES) += module_64.o +obj-$(CONFIG_PCI) += early-quirks_64.o + +obj-y += topology.o +obj-y += intel_cacheinfo.o +obj-y += addon_cpuid_features.o +obj-y += pcspeaker.o + +CFLAGS_vsyscall_64.o := $(PROFILING) -g0 + +therm_throt-y += ../../i386/kernel/cpu/mcheck/therm_throt.o +bootflag-y += ../../i386/kernel/bootflag.o +cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o +topology-y += ../../i386/kernel/topology.o +microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o +intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o +addon_cpuid_features-y += ../../i386/kernel/cpu/addon_cpuid_features.o +quirks-y += ../../i386/kernel/quirks.o +i8237-y += ../../i386/kernel/i8237.o +msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o +alternative-y += ../../i386/kernel/alternative.o +pcspeaker-y += ../../i386/kernel/pcspeaker.o +perfctr-watchdog-y += ../../i386/kernel/cpu/perfctr-watchdog.o From a9c0350568b93ba7204a56644031a2332c9517d1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:25 +0200 Subject: [PATCH 2034/2804] x86_64: prepare shared kernel/acpi/wakeup.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/acpi/Makefile | 2 +- arch/x86_64/kernel/acpi/{wakeup.S => wakeup_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/acpi/{wakeup.S => wakeup_64.S} (100%) diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile index 080b9963f1bc..fe34bbec1cf0 100644 --- a/arch/x86_64/kernel/acpi/Makefile +++ b/arch/x86_64/kernel/acpi/Makefile @@ -1,6 +1,6 @@ obj-y := boot.o boot-y := ../../../i386/kernel/acpi/boot.o -obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_64.o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += processor.o diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup_64.S similarity index 100% rename from arch/x86_64/kernel/acpi/wakeup.S rename to arch/x86_64/kernel/acpi/wakeup_64.S From 08c81f47fcba935d937e45a592ad7b00e9296a2f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:27 +0200 Subject: [PATCH 2035/2804] x86_64: prepare shared kernel/acpi/sleep.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/acpi/Makefile | 2 +- arch/x86_64/kernel/acpi/{sleep.c => sleep_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/kernel/acpi/{sleep.c => sleep_64.c} (100%) diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile index fe34bbec1cf0..c24fe95b0d94 100644 --- a/arch/x86_64/kernel/acpi/Makefile +++ b/arch/x86_64/kernel/acpi/Makefile @@ -1,6 +1,6 @@ obj-y := boot.o boot-y := ../../../i386/kernel/acpi/boot.o -obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_64.o +obj-$(CONFIG_ACPI_SLEEP) += sleep_64.o wakeup_64.o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += processor.o diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep_64.c similarity index 100% rename from arch/x86_64/kernel/acpi/sleep.c rename to arch/x86_64/kernel/acpi/sleep_64.c From f11cfb424c78ef8a6d9fc80922577756cec00282 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:27 +0200 Subject: [PATCH 2036/2804] x86_64: prepare shared kernel/acpi/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/kernel/acpi/Makefile | 12 ++++-------- arch/x86_64/kernel/acpi/Makefile_64 | 9 +++++++++ 2 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 arch/x86_64/kernel/acpi/Makefile_64 diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile index c24fe95b0d94..6e00bfeb59a9 100644 --- a/arch/x86_64/kernel/acpi/Makefile +++ b/arch/x86_64/kernel/acpi/Makefile @@ -1,9 +1,5 @@ -obj-y := boot.o -boot-y := ../../../i386/kernel/acpi/boot.o -obj-$(CONFIG_ACPI_SLEEP) += sleep_64.o wakeup_64.o - -ifneq ($(CONFIG_ACPI_PROCESSOR),) -obj-y += processor.o -processor-y := ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/kernel/acpi/Makefile_32 +else +include ${srctree}/arch/x86_64/kernel/acpi/Makefile_64 endif - diff --git a/arch/x86_64/kernel/acpi/Makefile_64 b/arch/x86_64/kernel/acpi/Makefile_64 new file mode 100644 index 000000000000..c24fe95b0d94 --- /dev/null +++ b/arch/x86_64/kernel/acpi/Makefile_64 @@ -0,0 +1,9 @@ +obj-y := boot.o +boot-y := ../../../i386/kernel/acpi/boot.o +obj-$(CONFIG_ACPI_SLEEP) += sleep_64.o wakeup_64.o + +ifneq ($(CONFIG_ACPI_PROCESSOR),) +obj-y += processor.o +processor-y := ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o +endif + From 426458d004001ed323073c67b46963f024880ec1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:29 +0200 Subject: [PATCH 2037/2804] x86_64: prepare shared lib/thunk.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{thunk.S => thunk_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{thunk.S => thunk_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index c94327178398..0ac00335b763 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -9,5 +9,5 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ - thunk.o clear_page.o copy_page.o bitstr.o bitops.o + thunk_64.o clear_page.o copy_page.o bitstr.o bitops.o lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o copy_user_nocache.o diff --git a/arch/x86_64/lib/thunk.S b/arch/x86_64/lib/thunk_64.S similarity index 100% rename from arch/x86_64/lib/thunk.S rename to arch/x86_64/lib/thunk_64.S From 201c943463f9581ed7aac02db5ab6bc3091f5c03 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:30 +0200 Subject: [PATCH 2038/2804] x86_64: prepare shared lib/iomap_copy.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{iomap_copy.S => iomap_copy_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{iomap_copy.S => iomap_copy_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 0ac00335b763..ea20b1077ff0 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -4,7 +4,7 @@ CFLAGS_csum-partial.o := -funroll-loops -obj-y := io.o iomap_copy.o +obj-y := io.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ diff --git a/arch/x86_64/lib/iomap_copy.S b/arch/x86_64/lib/iomap_copy_64.S similarity index 100% rename from arch/x86_64/lib/iomap_copy.S rename to arch/x86_64/lib/iomap_copy_64.S From 7d96027379c0f43f7169019c814cadca7487d507 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:32 +0200 Subject: [PATCH 2039/2804] x86_64: prepare shared lib/copy_page.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{copy_page.S => copy_page_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{copy_page.S => copy_page_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index ea20b1077ff0..c22087f66d5f 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -9,5 +9,5 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ - thunk_64.o clear_page.o copy_page.o bitstr.o bitops.o + thunk_64.o clear_page.o copy_page_64.o bitstr.o bitops.o lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o copy_user_nocache.o diff --git a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page_64.S similarity index 100% rename from arch/x86_64/lib/copy_page.S rename to arch/x86_64/lib/copy_page_64.S From 3b405f4ed4df8f9c9ff765c9e81996ba46e79844 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:33 +0200 Subject: [PATCH 2040/2804] x86_64: prepare shared lib/bitstr.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{bitstr.c => bitstr_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{bitstr.c => bitstr_64.c} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index c22087f66d5f..30eede7e18fd 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -9,5 +9,5 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ - thunk_64.o clear_page.o copy_page_64.o bitstr.o bitops.o + thunk_64.o clear_page.o copy_page_64.o bitstr_64.o bitops.o lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o copy_user_nocache.o diff --git a/arch/x86_64/lib/bitstr.c b/arch/x86_64/lib/bitstr_64.c similarity index 100% rename from arch/x86_64/lib/bitstr.c rename to arch/x86_64/lib/bitstr_64.c From c9954d39e7d8b2f12517aa02d4d7b96eb4761a1d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:35 +0200 Subject: [PATCH 2041/2804] x86_64: prepare shared lib/csum-copy.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{csum-copy.S => csum-copy_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{csum-copy.S => csum-copy_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 30eede7e18fd..4ecc6181db4d 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -7,7 +7,7 @@ CFLAGS_csum-partial.o := -funroll-loops obj-y := io.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o -lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ +lib-y := csum-partial.o csum-copy_64.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ thunk_64.o clear_page.o copy_page_64.o bitstr_64.o bitops.o lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o copy_user_nocache.o diff --git a/arch/x86_64/lib/csum-copy.S b/arch/x86_64/lib/csum-copy_64.S similarity index 100% rename from arch/x86_64/lib/csum-copy.S rename to arch/x86_64/lib/csum-copy_64.S From 0068f260578fc54aa7d10bb3e4a25118287f00f7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:36 +0200 Subject: [PATCH 2042/2804] x86_64: prepare shared lib/clear_page.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{clear_page.S => clear_page_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{clear_page.S => clear_page_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 4ecc6181db4d..4611996706a3 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -9,5 +9,5 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ - thunk_64.o clear_page.o copy_page_64.o bitstr_64.o bitops.o + thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o copy_user_nocache.o diff --git a/arch/x86_64/lib/clear_page.S b/arch/x86_64/lib/clear_page_64.S similarity index 100% rename from arch/x86_64/lib/clear_page.S rename to arch/x86_64/lib/clear_page_64.S From 42421ce3468d46cd875acd3d87384528f9fe8a39 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:37 +0200 Subject: [PATCH 2043/2804] x86_64: prepare shared lib/rwlock.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{rwlock.S => rwlock_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{rwlock.S => rwlock_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 4611996706a3..d9d715d3ec9c 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -10,4 +10,4 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o -lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o copy_user_nocache.o +lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock_64.o copy_user_nocache.o diff --git a/arch/x86_64/lib/rwlock.S b/arch/x86_64/lib/rwlock_64.S similarity index 100% rename from arch/x86_64/lib/rwlock.S rename to arch/x86_64/lib/rwlock_64.S From ff8e90da7c3ccf2e74e7ab4a57a0ff6e0de027b0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:39 +0200 Subject: [PATCH 2044/2804] x86_64: prepare shared lib/memcpy.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{memcpy.S => memcpy_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{memcpy.S => memcpy_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index d9d715d3ec9c..dce49348cebe 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -10,4 +10,4 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o -lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock_64.o copy_user_nocache.o +lib-y += memcpy_64.o memmove.o memset.o copy_user.o rwlock_64.o copy_user_nocache.o diff --git a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy_64.S similarity index 100% rename from arch/x86_64/lib/memcpy.S rename to arch/x86_64/lib/memcpy_64.S From 79c67e5356db9dbf2974962fe589d7482e463dc5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:40 +0200 Subject: [PATCH 2045/2804] x86_64: prepare shared lib/copy_user_nocache.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{copy_user_nocache.S => copy_user_nocache_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{copy_user_nocache.S => copy_user_nocache_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index dce49348cebe..67133edf7d29 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -10,4 +10,4 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o -lib-y += memcpy_64.o memmove.o memset.o copy_user.o rwlock_64.o copy_user_nocache.o +lib-y += memcpy_64.o memmove.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/copy_user_nocache.S b/arch/x86_64/lib/copy_user_nocache_64.S similarity index 100% rename from arch/x86_64/lib/copy_user_nocache.S rename to arch/x86_64/lib/copy_user_nocache_64.S From 5fa2ae8e9e6c5a23e0e3955d3c0d55c1e08e603f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:42 +0200 Subject: [PATCH 2046/2804] x86_64: prepare shared lib/memmove.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{memmove.c => memmove_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{memmove.c => memmove_64.c} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 67133edf7d29..ca4df1ee6539 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -10,4 +10,4 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o -lib-y += memcpy_64.o memmove.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o +lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/memmove.c b/arch/x86_64/lib/memmove_64.c similarity index 100% rename from arch/x86_64/lib/memmove.c rename to arch/x86_64/lib/memmove_64.c From 83aaddb721364e55b4df373073019cfdf170a7be Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:43 +0200 Subject: [PATCH 2047/2804] x86_64: prepare shared lib/csum-wrappers.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{csum-wrappers.c => csum-wrappers_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{csum-wrappers.c => csum-wrappers_64.c} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index ca4df1ee6539..01a4178b6ea7 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -7,7 +7,7 @@ CFLAGS_csum-partial.o := -funroll-loops obj-y := io.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o -lib-y := csum-partial.o csum-copy_64.o csum-wrappers.o delay.o \ +lib-y := csum-partial.o csum-copy_64.o csum-wrappers_64.o delay.o \ usercopy.o getuser.o putuser.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/csum-wrappers.c b/arch/x86_64/lib/csum-wrappers_64.c similarity index 100% rename from arch/x86_64/lib/csum-wrappers.c rename to arch/x86_64/lib/csum-wrappers_64.c From 4529a0f636cd77909fb1f10c25edc52a22950366 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:45 +0200 Subject: [PATCH 2048/2804] x86_64: prepare shared lib/getuser.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{getuser.S => getuser_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{getuser.S => getuser_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 01a4178b6ea7..9212301b6427 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -8,6 +8,6 @@ obj-y := io.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers_64.o delay.o \ - usercopy.o getuser.o putuser.o \ + usercopy.o getuser_64.o putuser.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/getuser.S b/arch/x86_64/lib/getuser_64.S similarity index 100% rename from arch/x86_64/lib/getuser.S rename to arch/x86_64/lib/getuser_64.S From 584d92415b5c4e93e2bc3d18756815758f2a1f07 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:46 +0200 Subject: [PATCH 2049/2804] x86_64: prepare shared lib/usercopy.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{usercopy.c => usercopy_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{usercopy.c => usercopy_64.c} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 9212301b6427..7157801093af 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -8,6 +8,6 @@ obj-y := io.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers_64.o delay.o \ - usercopy.o getuser_64.o putuser.o \ + usercopy_64.o getuser_64.o putuser.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/usercopy.c b/arch/x86_64/lib/usercopy_64.c similarity index 100% rename from arch/x86_64/lib/usercopy.c rename to arch/x86_64/lib/usercopy_64.c From d7eb5e98f45e88762676744f1ab0f7f4c1354fb9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:48 +0200 Subject: [PATCH 2050/2804] x86_64: prepare shared lib/bitops.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{bitops.c => bitops_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{bitops.c => bitops_64.c} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 7157801093af..3e12aa58d453 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -9,5 +9,5 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers_64.o delay.o \ usercopy_64.o getuser_64.o putuser.o \ - thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops.o + thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops_64.o lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/bitops.c b/arch/x86_64/lib/bitops_64.c similarity index 100% rename from arch/x86_64/lib/bitops.c rename to arch/x86_64/lib/bitops_64.c From a856413e26785ea5585c06b1aa773ed44bc116aa Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:49 +0200 Subject: [PATCH 2051/2804] x86_64: prepare shared lib/putuser.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{putuser.S => putuser_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{putuser.S => putuser_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 3e12aa58d453..430be2c1a59b 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -8,6 +8,6 @@ obj-y := io.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial.o csum-copy_64.o csum-wrappers_64.o delay.o \ - usercopy_64.o getuser_64.o putuser.o \ + usercopy_64.o getuser_64.o putuser_64.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops_64.o lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/putuser.S b/arch/x86_64/lib/putuser_64.S similarity index 100% rename from arch/x86_64/lib/putuser.S rename to arch/x86_64/lib/putuser_64.S From dcd30b189cc3879278285db616c7baecf5f6493f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:50 +0200 Subject: [PATCH 2052/2804] x86_64: prepare shared lib/delay.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{delay.c => delay_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{delay.c => delay_64.c} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 430be2c1a59b..373615a594f4 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -7,7 +7,7 @@ CFLAGS_csum-partial.o := -funroll-loops obj-y := io.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o -lib-y := csum-partial.o csum-copy_64.o csum-wrappers_64.o delay.o \ +lib-y := csum-partial.o csum-copy_64.o csum-wrappers_64.o delay_64.o \ usercopy_64.o getuser_64.o putuser_64.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops_64.o lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay_64.c similarity index 100% rename from arch/x86_64/lib/delay.c rename to arch/x86_64/lib/delay_64.c From 21767fad2ba94675bcf49c0796b4b2a65702c974 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:52 +0200 Subject: [PATCH 2053/2804] x86_64: prepare shared lib/csum-partial.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 4 ++-- arch/x86_64/lib/{csum-partial.c => csum-partial_64.c} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/x86_64/lib/{csum-partial.c => csum-partial_64.c} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 373615a594f4..6b510f97cab5 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -2,12 +2,12 @@ # Makefile for x86_64-specific library files. # -CFLAGS_csum-partial.o := -funroll-loops +CFLAGS_csum-partial_64.o := -funroll-loops obj-y := io.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o -lib-y := csum-partial.o csum-copy_64.o csum-wrappers_64.o delay_64.o \ +lib-y := csum-partial_64.o csum-copy_64.o csum-wrappers_64.o delay_64.o \ usercopy_64.o getuser_64.o putuser_64.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops_64.o lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/csum-partial.c b/arch/x86_64/lib/csum-partial_64.c similarity index 100% rename from arch/x86_64/lib/csum-partial.c rename to arch/x86_64/lib/csum-partial_64.c From e72ba5136d3c56eaf6a9654e2f8545354c196efc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:53 +0200 Subject: [PATCH 2054/2804] x86_64: prepare shared lib/io.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{io.c => io_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{io.c => io_64.c} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 6b510f97cab5..6bdf7d824f4c 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -4,7 +4,7 @@ CFLAGS_csum-partial_64.o := -funroll-loops -obj-y := io.o iomap_copy_64.o +obj-y := io_64.o iomap_copy_64.o obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial_64.o csum-copy_64.o csum-wrappers_64.o delay_64.o \ diff --git a/arch/x86_64/lib/io.c b/arch/x86_64/lib/io_64.c similarity index 100% rename from arch/x86_64/lib/io.c rename to arch/x86_64/lib/io_64.c From 2a6c7b6bbfefbe37dbbc31a209dbf0166ee51a07 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:55 +0200 Subject: [PATCH 2055/2804] x86_64: prepare shared lib/memset.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{memset.S => memset_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{memset.S => memset_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 6bdf7d824f4c..09c1ffa974a9 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -10,4 +10,4 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial_64.o csum-copy_64.o csum-wrappers_64.o delay_64.o \ usercopy_64.o getuser_64.o putuser_64.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops_64.o -lib-y += memcpy_64.o memmove_64.o memset.o copy_user.o rwlock_64.o copy_user_nocache_64.o +lib-y += memcpy_64.o memmove_64.o memset_64.o copy_user.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset_64.S similarity index 100% rename from arch/x86_64/lib/memset.S rename to arch/x86_64/lib/memset_64.S From 6e7873f6ff38bca29bc65cb8c96fd7f557215755 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:56 +0200 Subject: [PATCH 2056/2804] x86_64: prepare shared lib/copy_user.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/{copy_user.S => copy_user_64.S} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/lib/{copy_user.S => copy_user_64.S} (100%) diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 09c1ffa974a9..bbabad3c9335 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -10,4 +10,4 @@ obj-$(CONFIG_SMP) += msr-on-cpu.o lib-y := csum-partial_64.o csum-copy_64.o csum-wrappers_64.o delay_64.o \ usercopy_64.o getuser_64.o putuser_64.o \ thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops_64.o -lib-y += memcpy_64.o memmove_64.o memset_64.o copy_user.o rwlock_64.o copy_user_nocache_64.o +lib-y += memcpy_64.o memmove_64.o memset_64.o copy_user_64.o rwlock_64.o copy_user_nocache_64.o diff --git a/arch/x86_64/lib/copy_user.S b/arch/x86_64/lib/copy_user_64.S similarity index 100% rename from arch/x86_64/lib/copy_user.S rename to arch/x86_64/lib/copy_user_64.S From 4dc55b8696bc17c8e4315bce50d9bfe9ef2dc05f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:57 +0200 Subject: [PATCH 2057/2804] x86_64: prepare shared lib/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/lib/Makefile | 18 +++++------------- arch/x86_64/lib/Makefile_64 | 13 +++++++++++++ 2 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 arch/x86_64/lib/Makefile_64 diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index bbabad3c9335..2b1547e0ac6b 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -1,13 +1,5 @@ -# -# Makefile for x86_64-specific library files. -# - -CFLAGS_csum-partial_64.o := -funroll-loops - -obj-y := io_64.o iomap_copy_64.o -obj-$(CONFIG_SMP) += msr-on-cpu.o - -lib-y := csum-partial_64.o csum-copy_64.o csum-wrappers_64.o delay_64.o \ - usercopy_64.o getuser_64.o putuser_64.o \ - thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops_64.o -lib-y += memcpy_64.o memmove_64.o memset_64.o copy_user_64.o rwlock_64.o copy_user_nocache_64.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/lib/Makefile_32 +else +include ${srctree}/arch/x86_64/lib/Makefile_64 +endif diff --git a/arch/x86_64/lib/Makefile_64 b/arch/x86_64/lib/Makefile_64 new file mode 100644 index 000000000000..bbabad3c9335 --- /dev/null +++ b/arch/x86_64/lib/Makefile_64 @@ -0,0 +1,13 @@ +# +# Makefile for x86_64-specific library files. +# + +CFLAGS_csum-partial_64.o := -funroll-loops + +obj-y := io_64.o iomap_copy_64.o +obj-$(CONFIG_SMP) += msr-on-cpu.o + +lib-y := csum-partial_64.o csum-copy_64.o csum-wrappers_64.o delay_64.o \ + usercopy_64.o getuser_64.o putuser_64.o \ + thunk_64.o clear_page_64.o copy_page_64.o bitstr_64.o bitops_64.o +lib-y += memcpy_64.o memmove_64.o memset_64.o copy_user_64.o rwlock_64.o copy_user_nocache_64.o From 08d4759ee7d50d3a77061c13d246a28266655800 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:15:58 +0200 Subject: [PATCH 2058/2804] x86_64: prepare shared pci/k8-bus.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/pci/Makefile | 2 +- arch/x86_64/pci/{k8-bus.c => k8-bus_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/pci/{k8-bus.c => k8-bus_64.c} (100%) diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile index c9eddc8859c0..482b2945a472 100644 --- a/arch/x86_64/pci/Makefile +++ b/arch/x86_64/pci/Makefile @@ -13,7 +13,7 @@ obj-y += legacy.o irq.o common.o early.o # mmconfig has a 64bit special obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o -obj-$(CONFIG_NUMA) += k8-bus.o +obj-$(CONFIG_NUMA) += k8-bus_64.o direct-y += ../../i386/pci/direct.o acpi-y += ../../i386/pci/acpi.o diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus_64.c similarity index 100% rename from arch/x86_64/pci/k8-bus.c rename to arch/x86_64/pci/k8-bus_64.c From e0915fb261707f4e3ba460871b5454c7d4726df6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:00 +0200 Subject: [PATCH 2059/2804] x86_64: prepare shared pci/mmconfig.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/pci/Makefile | 2 +- arch/x86_64/pci/{mmconfig.c => mmconfig_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/pci/{mmconfig.c => mmconfig_64.c} (100%) diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile index 482b2945a472..77b1b9abedc2 100644 --- a/arch/x86_64/pci/Makefile +++ b/arch/x86_64/pci/Makefile @@ -11,7 +11,7 @@ obj-y += fixup.o init.o obj-$(CONFIG_ACPI) += acpi.o obj-y += legacy.o irq.o common.o early.o # mmconfig has a 64bit special -obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o obj-$(CONFIG_NUMA) += k8-bus_64.o diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig_64.c similarity index 100% rename from arch/x86_64/pci/mmconfig.c rename to arch/x86_64/pci/mmconfig_64.c From 7b06e6c58cf71c4c1a930905e395ea73130aa6e0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:00 +0200 Subject: [PATCH 2060/2804] x86_64: prepare shared pci/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/pci/Makefile | 32 +++++--------------------------- arch/x86_64/pci/Makefile_64 | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 27 deletions(-) create mode 100644 arch/x86_64/pci/Makefile_64 diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile index 77b1b9abedc2..d04d8f976d1c 100644 --- a/arch/x86_64/pci/Makefile +++ b/arch/x86_64/pci/Makefile @@ -1,27 +1,5 @@ -# -# Makefile for X86_64 specific PCI routines -# -# Reuse the i386 PCI subsystem -# -EXTRA_CFLAGS += -Iarch/i386/pci - -obj-y := i386.o -obj-$(CONFIG_PCI_DIRECT)+= direct.o -obj-y += fixup.o init.o -obj-$(CONFIG_ACPI) += acpi.o -obj-y += legacy.o irq.o common.o early.o -# mmconfig has a 64bit special -obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o - -obj-$(CONFIG_NUMA) += k8-bus_64.o - -direct-y += ../../i386/pci/direct.o -acpi-y += ../../i386/pci/acpi.o -legacy-y += ../../i386/pci/legacy.o -irq-y += ../../i386/pci/irq.o -common-y += ../../i386/pci/common.o -fixup-y += ../../i386/pci/fixup.o -i386-y += ../../i386/pci/i386.o -init-y += ../../i386/pci/init.o -early-y += ../../i386/pci/early.o -mmconfig-shared-y += ../../i386/pci/mmconfig-shared.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/pci/Makefile_32 +else +include ${srctree}/arch/x86_64/pci/Makefile_64 +endif diff --git a/arch/x86_64/pci/Makefile_64 b/arch/x86_64/pci/Makefile_64 new file mode 100644 index 000000000000..77b1b9abedc2 --- /dev/null +++ b/arch/x86_64/pci/Makefile_64 @@ -0,0 +1,27 @@ +# +# Makefile for X86_64 specific PCI routines +# +# Reuse the i386 PCI subsystem +# +EXTRA_CFLAGS += -Iarch/i386/pci + +obj-y := i386.o +obj-$(CONFIG_PCI_DIRECT)+= direct.o +obj-y += fixup.o init.o +obj-$(CONFIG_ACPI) += acpi.o +obj-y += legacy.o irq.o common.o early.o +# mmconfig has a 64bit special +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o + +obj-$(CONFIG_NUMA) += k8-bus_64.o + +direct-y += ../../i386/pci/direct.o +acpi-y += ../../i386/pci/acpi.o +legacy-y += ../../i386/pci/legacy.o +irq-y += ../../i386/pci/irq.o +common-y += ../../i386/pci/common.o +fixup-y += ../../i386/pci/fixup.o +i386-y += ../../i386/pci/i386.o +init-y += ../../i386/pci/init.o +early-y += ../../i386/pci/early.o +mmconfig-shared-y += ../../i386/pci/mmconfig-shared.o From 6f80a03f0c7f03142219d5fafe4c7232b34eab9c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:01 +0200 Subject: [PATCH 2061/2804] x86_64: prepare shared boot/compressed/misc.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/boot/compressed/Makefile | 4 ++-- arch/x86_64/boot/compressed/{misc.c => misc_64.c} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/x86_64/boot/compressed/{misc.c => misc_64.c} (100%) diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile index 877c0bdbbc67..fe623b77991f 100644 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile @@ -4,7 +4,7 @@ # create a compressed vmlinux image from the original vmlinux # -targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o +targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc_64.o piggy.o CFLAGS := -m64 -D__KERNEL__ $(LINUXINCLUDE) -O2 \ -fno-strict-aliasing -fPIC -mcmodel=small \ @@ -14,7 +14,7 @@ AFLAGS := $(CFLAGS) -D__ASSEMBLY__ LDFLAGS := -m elf_x86_64 LDFLAGS_vmlinux := -T -$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc_64.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc_64.c similarity index 100% rename from arch/x86_64/boot/compressed/misc.c rename to arch/x86_64/boot/compressed/misc_64.c From 4290fcfd7391886c84e7e28ef2ac1125c15154f8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:03 +0200 Subject: [PATCH 2062/2804] x86_64: prepare shared boot/compressed/vmlinux.lds Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/boot/compressed/Makefile | 2 +- arch/x86_64/boot/compressed/{vmlinux.lds => vmlinux_64.lds} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/boot/compressed/{vmlinux.lds => vmlinux_64.lds} (100%) diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile index fe623b77991f..6b2fb9906664 100644 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile @@ -14,7 +14,7 @@ AFLAGS := $(CFLAGS) -D__ASSEMBLY__ LDFLAGS := -m elf_x86_64 LDFLAGS_vmlinux := -T -$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc_64.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux_64.lds $(obj)/head.o $(obj)/misc_64.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: diff --git a/arch/x86_64/boot/compressed/vmlinux.lds b/arch/x86_64/boot/compressed/vmlinux_64.lds similarity index 100% rename from arch/x86_64/boot/compressed/vmlinux.lds rename to arch/x86_64/boot/compressed/vmlinux_64.lds From e5e96ef2899fb9d6009a53f83952e00cad2a97ab Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:04 +0200 Subject: [PATCH 2063/2804] x86_64: prepare shared boot/compressed/vmlinux.scr Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/boot/compressed/Makefile | 2 +- arch/x86_64/boot/compressed/{vmlinux.scr => vmlinux_64.scr} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/boot/compressed/{vmlinux.scr => vmlinux_64.scr} (100%) diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile index 6b2fb9906664..6fb949582b23 100644 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile @@ -26,5 +26,5 @@ $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T -$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE +$(obj)/piggy.o: $(obj)/vmlinux_64.scr $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld) diff --git a/arch/x86_64/boot/compressed/vmlinux.scr b/arch/x86_64/boot/compressed/vmlinux_64.scr similarity index 100% rename from arch/x86_64/boot/compressed/vmlinux.scr rename to arch/x86_64/boot/compressed/vmlinux_64.scr From 16cfc182fd3749644a35a134316766dcef5f0d24 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:06 +0200 Subject: [PATCH 2064/2804] x86_64: prepare shared boot/compressed/head.S Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/boot/compressed/Makefile | 4 ++-- arch/x86_64/boot/compressed/{head.S => head_64.S} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/x86_64/boot/compressed/{head.S => head_64.S} (100%) diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile index 6fb949582b23..5bfd108f29d3 100644 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile @@ -4,7 +4,7 @@ # create a compressed vmlinux image from the original vmlinux # -targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc_64.o piggy.o +targets := vmlinux vmlinux.bin vmlinux.bin.gz head_64.o misc_64.o piggy.o CFLAGS := -m64 -D__KERNEL__ $(LINUXINCLUDE) -O2 \ -fno-strict-aliasing -fPIC -mcmodel=small \ @@ -14,7 +14,7 @@ AFLAGS := $(CFLAGS) -D__ASSEMBLY__ LDFLAGS := -m elf_x86_64 LDFLAGS_vmlinux := -T -$(obj)/vmlinux: $(src)/vmlinux_64.lds $(obj)/head.o $(obj)/misc_64.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux_64.lds $(obj)/head_64.o $(obj)/misc_64.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head_64.S similarity index 100% rename from arch/x86_64/boot/compressed/head.S rename to arch/x86_64/boot/compressed/head_64.S From b9fe6ce1c0dd85b57f3e350b566c389d16681254 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:06 +0200 Subject: [PATCH 2065/2804] x86_64: prepare shared boot/compressed/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/boot/compressed/Makefile | 35 ++++--------------------- arch/x86_64/boot/compressed/Makefile_64 | 30 +++++++++++++++++++++ 2 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 arch/x86_64/boot/compressed/Makefile_64 diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile index 5bfd108f29d3..78514f3f626f 100644 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile @@ -1,30 +1,5 @@ -# -# linux/arch/x86_64/boot/compressed/Makefile -# -# create a compressed vmlinux image from the original vmlinux -# - -targets := vmlinux vmlinux.bin vmlinux.bin.gz head_64.o misc_64.o piggy.o - -CFLAGS := -m64 -D__KERNEL__ $(LINUXINCLUDE) -O2 \ - -fno-strict-aliasing -fPIC -mcmodel=small \ - $(call cc-option, -ffreestanding) \ - $(call cc-option, -fno-stack-protector) -AFLAGS := $(CFLAGS) -D__ASSEMBLY__ -LDFLAGS := -m elf_x86_64 - -LDFLAGS_vmlinux := -T -$(obj)/vmlinux: $(src)/vmlinux_64.lds $(obj)/head_64.o $(obj)/misc_64.o $(obj)/piggy.o FORCE - $(call if_changed,ld) - @: - -$(obj)/vmlinux.bin: vmlinux FORCE - $(call if_changed,objcopy) - -$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE - $(call if_changed,gzip) - -LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T - -$(obj)/piggy.o: $(obj)/vmlinux_64.scr $(obj)/vmlinux.bin.gz FORCE - $(call if_changed,ld) +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/boot/compressed/Makefile_32 +else +include ${srctree}/arch/x86_64/boot/compressed/Makefile_64 +endif diff --git a/arch/x86_64/boot/compressed/Makefile_64 b/arch/x86_64/boot/compressed/Makefile_64 new file mode 100644 index 000000000000..5bfd108f29d3 --- /dev/null +++ b/arch/x86_64/boot/compressed/Makefile_64 @@ -0,0 +1,30 @@ +# +# linux/arch/x86_64/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +targets := vmlinux vmlinux.bin vmlinux.bin.gz head_64.o misc_64.o piggy.o + +CFLAGS := -m64 -D__KERNEL__ $(LINUXINCLUDE) -O2 \ + -fno-strict-aliasing -fPIC -mcmodel=small \ + $(call cc-option, -ffreestanding) \ + $(call cc-option, -fno-stack-protector) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ +LDFLAGS := -m elf_x86_64 + +LDFLAGS_vmlinux := -T +$(obj)/vmlinux: $(src)/vmlinux_64.lds $(obj)/head_64.o $(obj)/misc_64.o $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T + +$(obj)/piggy.o: $(obj)/vmlinux_64.scr $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) From de48b0466641eb505426a6a18eb0b5490f3e6571 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:08 +0200 Subject: [PATCH 2066/2804] x86_64: prepare shared mm/srat.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{srat.c => srat_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{srat.c => srat_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index d25ac86fe27a..f5fbb8053acd 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -6,6 +6,6 @@ obj-y := init.o fault.o ioremap.o extable.o pageattr.o mmap.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_K8_NUMA) += k8topology.o -obj-$(CONFIG_ACPI_NUMA) += srat.o +obj-$(CONFIG_ACPI_NUMA) += srat_64.o hugetlbpage-y = ../../i386/mm/hugetlbpage.o diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat_64.c similarity index 100% rename from arch/x86_64/mm/srat.c rename to arch/x86_64/mm/srat_64.c From f3ba86d98a4c985788269b93ca8133c991a2e09a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:09 +0200 Subject: [PATCH 2067/2804] x86_64: prepare shared mm/ioremap.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{ioremap.c => ioremap_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{ioremap.c => ioremap_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index f5fbb8053acd..c400b1983785 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux x86_64-specific parts of the memory manager. # -obj-y := init.o fault.o ioremap.o extable.o pageattr.o mmap.o +obj-y := init.o fault.o ioremap_64.o extable.o pageattr.o mmap.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_K8_NUMA) += k8topology.o diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap_64.c similarity index 100% rename from arch/x86_64/mm/ioremap.c rename to arch/x86_64/mm/ioremap_64.c From 4391e4cc250a61e925bec05f11f9b1c0a8277ec4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:11 +0200 Subject: [PATCH 2068/2804] x86_64: prepare shared mm/init.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{init.c => init_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{init.c => init_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index c400b1983785..1e2ccf009d4c 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux x86_64-specific parts of the memory manager. # -obj-y := init.o fault.o ioremap_64.o extable.o pageattr.o mmap.o +obj-y := init_64.o fault.o ioremap_64.o extable.o pageattr.o mmap.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_K8_NUMA) += k8topology.o diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init_64.c similarity index 100% rename from arch/x86_64/mm/init.c rename to arch/x86_64/mm/init_64.c From b2110a17787f1eb6a60f52e12b119d2ef3013bc2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:12 +0200 Subject: [PATCH 2069/2804] x86_64: prepare shared mm/mmap.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{mmap.c => mmap_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{mmap.c => mmap_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index 1e2ccf009d4c..a7fedc9cbb05 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux x86_64-specific parts of the memory manager. # -obj-y := init_64.o fault.o ioremap_64.o extable.o pageattr.o mmap.o +obj-y := init_64.o fault.o ioremap_64.o extable.o pageattr.o mmap_64.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_K8_NUMA) += k8topology.o diff --git a/arch/x86_64/mm/mmap.c b/arch/x86_64/mm/mmap_64.c similarity index 100% rename from arch/x86_64/mm/mmap.c rename to arch/x86_64/mm/mmap_64.c From 4d381b582896529c3ab0f5ba815b8133a4e6d5fa Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:14 +0200 Subject: [PATCH 2070/2804] x86_64: prepare shared mm/numa.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{numa.c => numa_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{numa.c => numa_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index a7fedc9cbb05..921b756ed7c0 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -4,7 +4,7 @@ obj-y := init_64.o fault.o ioremap_64.o extable.o pageattr.o mmap_64.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_NUMA) += numa.o +obj-$(CONFIG_NUMA) += numa_64.o obj-$(CONFIG_K8_NUMA) += k8topology.o obj-$(CONFIG_ACPI_NUMA) += srat_64.o diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa_64.c similarity index 100% rename from arch/x86_64/mm/numa.c rename to arch/x86_64/mm/numa_64.c From c559b6fdd148b28358862c68d835e67dab997080 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:15 +0200 Subject: [PATCH 2071/2804] x86_64: prepare shared mm/extable.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{extable.c => extable_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{extable.c => extable_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index 921b756ed7c0..7dbe4f9f57b6 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux x86_64-specific parts of the memory manager. # -obj-y := init_64.o fault.o ioremap_64.o extable.o pageattr.o mmap_64.o +obj-y := init_64.o fault.o ioremap_64.o extable_64.o pageattr.o mmap_64.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa_64.o obj-$(CONFIG_K8_NUMA) += k8topology.o diff --git a/arch/x86_64/mm/extable.c b/arch/x86_64/mm/extable_64.c similarity index 100% rename from arch/x86_64/mm/extable.c rename to arch/x86_64/mm/extable_64.c From 5140b4f77d75debc47ccb9b77e00d2e1c68e1a3e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:16 +0200 Subject: [PATCH 2072/2804] x86_64: prepare shared mm/k8topology.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{k8topology.c => k8topology_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{k8topology.c => k8topology_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index 7dbe4f9f57b6..d44c092f6069 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -5,7 +5,7 @@ obj-y := init_64.o fault.o ioremap_64.o extable_64.o pageattr.o mmap_64.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa_64.o -obj-$(CONFIG_K8_NUMA) += k8topology.o +obj-$(CONFIG_K8_NUMA) += k8topology_64.o obj-$(CONFIG_ACPI_NUMA) += srat_64.o hugetlbpage-y = ../../i386/mm/hugetlbpage.o diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology_64.c similarity index 100% rename from arch/x86_64/mm/k8topology.c rename to arch/x86_64/mm/k8topology_64.c From 4ec0f73f27cbcf728311d8da7994477c1bd4edbb Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:18 +0200 Subject: [PATCH 2073/2804] x86_64: prepare shared mm/pageattr.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{pageattr.c => pageattr_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{pageattr.c => pageattr_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index d44c092f6069..019f5895fee7 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux x86_64-specific parts of the memory manager. # -obj-y := init_64.o fault.o ioremap_64.o extable_64.o pageattr.o mmap_64.o +obj-y := init_64.o fault.o ioremap_64.o extable_64.o pageattr_64.o mmap_64.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa_64.o obj-$(CONFIG_K8_NUMA) += k8topology_64.o diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr_64.c similarity index 100% rename from arch/x86_64/mm/pageattr.c rename to arch/x86_64/mm/pageattr_64.c From 9c89b008ca6ec2c1b75b1e9c698a0cc4dcbf5e4e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:19 +0200 Subject: [PATCH 2074/2804] x86_64: prepare shared mm/fault.c Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/{fault.c => fault_64.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/x86_64/mm/{fault.c => fault_64.c} (100%) diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index 019f5895fee7..2e209885fce6 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux x86_64-specific parts of the memory manager. # -obj-y := init_64.o fault.o ioremap_64.o extable_64.o pageattr_64.o mmap_64.o +obj-y := init_64.o fault_64.o ioremap_64.o extable_64.o pageattr_64.o mmap_64.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NUMA) += numa_64.o obj-$(CONFIG_K8_NUMA) += k8topology_64.o diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault_64.c similarity index 100% rename from arch/x86_64/mm/fault.c rename to arch/x86_64/mm/fault_64.c From af49d41e8c0e6649b3966470aa6319585144f8e8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:20 +0200 Subject: [PATCH 2075/2804] x86_64: prepare shared mm/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/mm/Makefile | 16 +++++----------- arch/x86_64/mm/Makefile_64 | 11 +++++++++++ 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 arch/x86_64/mm/Makefile_64 diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index 2e209885fce6..4042f8563a16 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -1,11 +1,5 @@ -# -# Makefile for the linux x86_64-specific parts of the memory manager. -# - -obj-y := init_64.o fault_64.o ioremap_64.o extable_64.o pageattr_64.o mmap_64.o -obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_NUMA) += numa_64.o -obj-$(CONFIG_K8_NUMA) += k8topology_64.o -obj-$(CONFIG_ACPI_NUMA) += srat_64.o - -hugetlbpage-y = ../../i386/mm/hugetlbpage.o +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/i386/mm/Makefile_32 +else +include ${srctree}/arch/x86_64/mm/Makefile_64 +endif diff --git a/arch/x86_64/mm/Makefile_64 b/arch/x86_64/mm/Makefile_64 new file mode 100644 index 000000000000..2e209885fce6 --- /dev/null +++ b/arch/x86_64/mm/Makefile_64 @@ -0,0 +1,11 @@ +# +# Makefile for the linux x86_64-specific parts of the memory manager. +# + +obj-y := init_64.o fault_64.o ioremap_64.o extable_64.o pageattr_64.o mmap_64.o +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o +obj-$(CONFIG_NUMA) += numa_64.o +obj-$(CONFIG_K8_NUMA) += k8topology_64.o +obj-$(CONFIG_ACPI_NUMA) += srat_64.o + +hugetlbpage-y = ../../i386/mm/hugetlbpage.o From 9c2019421511a1bc646981d55528334ae46464c0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:21 +0200 Subject: [PATCH 2076/2804] i386: move crypto Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/crypto/Makefile | 2 +- arch/{i386 => x86}/crypto/Makefile_32 | 2 +- arch/{i386 => x86}/crypto/aes-i586-asm_32.S | 0 arch/{i386 => x86}/crypto/aes_32.c | 0 arch/{i386 => x86}/crypto/twofish-i586-asm_32.S | 0 arch/{i386 => x86}/crypto/twofish_32.c | 0 arch/x86_64/crypto/Makefile | 2 +- 8 files changed, 4 insertions(+), 4 deletions(-) rename arch/{i386 => x86}/crypto/Makefile (64%) rename arch/{i386 => x86}/crypto/Makefile_32 (90%) rename arch/{i386 => x86}/crypto/aes-i586-asm_32.S (100%) rename arch/{i386 => x86}/crypto/aes_32.c (100%) rename arch/{i386 => x86}/crypto/twofish-i586-asm_32.S (100%) rename arch/{i386 => x86}/crypto/twofish_32.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 45409c13f6ef..dca07ae933d7 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -105,7 +105,7 @@ libs-y += arch/i386/lib/ core-y += arch/i386/kernel/ \ arch/i386/mm/ \ $(mcore-y)/ \ - arch/i386/crypto/ + arch/x86/crypto/ drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/ drivers-$(CONFIG_PCI) += arch/i386/pci/ # must be linked after kernel/ diff --git a/arch/i386/crypto/Makefile b/arch/x86/crypto/Makefile similarity index 64% rename from arch/i386/crypto/Makefile rename to arch/x86/crypto/Makefile index fbd34ac2cda2..b1bcf7c63028 100644 --- a/arch/i386/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/crypto/Makefile_32 +include ${srctree}/arch/x86/crypto/Makefile_32 else include ${srctree}/arch/x86_64/crypto/Makefile_64 endif diff --git a/arch/i386/crypto/Makefile_32 b/arch/x86/crypto/Makefile_32 similarity index 90% rename from arch/i386/crypto/Makefile_32 rename to arch/x86/crypto/Makefile_32 index 7154b14cd950..2d873a2388ed 100644 --- a/arch/i386/crypto/Makefile_32 +++ b/arch/x86/crypto/Makefile_32 @@ -1,5 +1,5 @@ # -# i386/crypto/Makefile +# x86/crypto/Makefile # # Arch-specific CryptoAPI modules. # diff --git a/arch/i386/crypto/aes-i586-asm_32.S b/arch/x86/crypto/aes-i586-asm_32.S similarity index 100% rename from arch/i386/crypto/aes-i586-asm_32.S rename to arch/x86/crypto/aes-i586-asm_32.S diff --git a/arch/i386/crypto/aes_32.c b/arch/x86/crypto/aes_32.c similarity index 100% rename from arch/i386/crypto/aes_32.c rename to arch/x86/crypto/aes_32.c diff --git a/arch/i386/crypto/twofish-i586-asm_32.S b/arch/x86/crypto/twofish-i586-asm_32.S similarity index 100% rename from arch/i386/crypto/twofish-i586-asm_32.S rename to arch/x86/crypto/twofish-i586-asm_32.S diff --git a/arch/i386/crypto/twofish_32.c b/arch/x86/crypto/twofish_32.c similarity index 100% rename from arch/i386/crypto/twofish_32.c rename to arch/x86/crypto/twofish_32.c diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile index fbd34ac2cda2..b1bcf7c63028 100644 --- a/arch/x86_64/crypto/Makefile +++ b/arch/x86_64/crypto/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/crypto/Makefile_32 +include ${srctree}/arch/x86/crypto/Makefile_32 else include ${srctree}/arch/x86_64/crypto/Makefile_64 endif From 23d6f82bd1f07886b3a974c5193baa715475dd37 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:23 +0200 Subject: [PATCH 2077/2804] i386: move kernel/acpi Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile_32 | 2 +- arch/{i386 => x86}/kernel/acpi/Makefile | 2 +- arch/{i386 => x86}/kernel/acpi/Makefile_32 | 0 arch/{i386 => x86}/kernel/acpi/boot.c | 0 arch/{i386 => x86}/kernel/acpi/cstate.c | 0 arch/{i386 => x86}/kernel/acpi/earlyquirk_32.c | 0 arch/{i386 => x86}/kernel/acpi/processor.c | 0 arch/{i386 => x86}/kernel/acpi/sleep_32.c | 0 arch/{i386 => x86}/kernel/acpi/wakeup_32.S | 0 arch/x86_64/kernel/acpi/Makefile | 2 +- arch/x86_64/kernel/acpi/Makefile_64 | 4 ++-- 11 files changed, 5 insertions(+), 5 deletions(-) rename arch/{i386 => x86}/kernel/acpi/Makefile (63%) rename arch/{i386 => x86}/kernel/acpi/Makefile_32 (100%) rename arch/{i386 => x86}/kernel/acpi/boot.c (100%) rename arch/{i386 => x86}/kernel/acpi/cstate.c (100%) rename arch/{i386 => x86}/kernel/acpi/earlyquirk_32.c (100%) rename arch/{i386 => x86}/kernel/acpi/processor.c (100%) rename arch/{i386 => x86}/kernel/acpi/sleep_32.c (100%) rename arch/{i386 => x86}/kernel/acpi/wakeup_32.S (100%) diff --git a/arch/i386/kernel/Makefile_32 b/arch/i386/kernel/Makefile_32 index d9dd3d677b72..af8304b921de 100644 --- a/arch/i386/kernel/Makefile_32 +++ b/arch/i386/kernel/Makefile_32 @@ -11,7 +11,7 @@ obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ -obj-y += acpi/ +obj-y += ../../x86/kernel/acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_X86_MSR) += msr.o diff --git a/arch/i386/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile similarity index 63% rename from arch/i386/kernel/acpi/Makefile rename to arch/x86/kernel/acpi/Makefile index 6e00bfeb59a9..dd4eb7cef2b4 100644 --- a/arch/i386/kernel/acpi/Makefile +++ b/arch/x86/kernel/acpi/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/kernel/acpi/Makefile_32 +include ${srctree}/arch/x86/kernel/acpi/Makefile_32 else include ${srctree}/arch/x86_64/kernel/acpi/Makefile_64 endif diff --git a/arch/i386/kernel/acpi/Makefile_32 b/arch/x86/kernel/acpi/Makefile_32 similarity index 100% rename from arch/i386/kernel/acpi/Makefile_32 rename to arch/x86/kernel/acpi/Makefile_32 diff --git a/arch/i386/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c similarity index 100% rename from arch/i386/kernel/acpi/boot.c rename to arch/x86/kernel/acpi/boot.c diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c similarity index 100% rename from arch/i386/kernel/acpi/cstate.c rename to arch/x86/kernel/acpi/cstate.c diff --git a/arch/i386/kernel/acpi/earlyquirk_32.c b/arch/x86/kernel/acpi/earlyquirk_32.c similarity index 100% rename from arch/i386/kernel/acpi/earlyquirk_32.c rename to arch/x86/kernel/acpi/earlyquirk_32.c diff --git a/arch/i386/kernel/acpi/processor.c b/arch/x86/kernel/acpi/processor.c similarity index 100% rename from arch/i386/kernel/acpi/processor.c rename to arch/x86/kernel/acpi/processor.c diff --git a/arch/i386/kernel/acpi/sleep_32.c b/arch/x86/kernel/acpi/sleep_32.c similarity index 100% rename from arch/i386/kernel/acpi/sleep_32.c rename to arch/x86/kernel/acpi/sleep_32.c diff --git a/arch/i386/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S similarity index 100% rename from arch/i386/kernel/acpi/wakeup_32.S rename to arch/x86/kernel/acpi/wakeup_32.S diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile index 6e00bfeb59a9..dd4eb7cef2b4 100644 --- a/arch/x86_64/kernel/acpi/Makefile +++ b/arch/x86_64/kernel/acpi/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/kernel/acpi/Makefile_32 +include ${srctree}/arch/x86/kernel/acpi/Makefile_32 else include ${srctree}/arch/x86_64/kernel/acpi/Makefile_64 endif diff --git a/arch/x86_64/kernel/acpi/Makefile_64 b/arch/x86_64/kernel/acpi/Makefile_64 index c24fe95b0d94..fc377c87e0b0 100644 --- a/arch/x86_64/kernel/acpi/Makefile_64 +++ b/arch/x86_64/kernel/acpi/Makefile_64 @@ -1,9 +1,9 @@ obj-y := boot.o -boot-y := ../../../i386/kernel/acpi/boot.o +boot-y := ../../../x86/kernel/acpi/boot.o obj-$(CONFIG_ACPI_SLEEP) += sleep_64.o wakeup_64.o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += processor.o -processor-y := ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o +processor-y := ../../../x86/kernel/acpi/processor.o ../../../x86/kernel/acpi/cstate.o endif From c18db0d7e299791c73d4dbe5ae7905b2ab8ba332 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:25 +0200 Subject: [PATCH 2078/2804] i386: move kernel/cpu/mcheck Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/cpu/Makefile | 2 +- arch/{i386 => x86}/kernel/cpu/mcheck/Makefile | 0 arch/{i386 => x86}/kernel/cpu/mcheck/k7.c | 0 arch/{i386 => x86}/kernel/cpu/mcheck/mce.c | 0 arch/{i386 => x86}/kernel/cpu/mcheck/mce.h | 0 arch/{i386 => x86}/kernel/cpu/mcheck/non-fatal.c | 0 arch/{i386 => x86}/kernel/cpu/mcheck/p4.c | 0 arch/{i386 => x86}/kernel/cpu/mcheck/p5.c | 0 arch/{i386 => x86}/kernel/cpu/mcheck/p6.c | 0 arch/{i386 => x86}/kernel/cpu/mcheck/therm_throt.c | 0 arch/{i386 => x86}/kernel/cpu/mcheck/winchip.c | 0 arch/x86_64/kernel/Makefile_64 | 2 +- 12 files changed, 2 insertions(+), 2 deletions(-) rename arch/{i386 => x86}/kernel/cpu/mcheck/Makefile (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/k7.c (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/mce.c (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/mce.h (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/non-fatal.c (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/p4.c (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/p5.c (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/p6.c (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/therm_throt.c (100%) rename arch/{i386 => x86}/kernel/cpu/mcheck/winchip.c (100%) diff --git a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile index 778396c78d65..09effc02e35a 100644 --- a/arch/i386/kernel/cpu/Makefile +++ b/arch/i386/kernel/cpu/Makefile @@ -12,7 +12,7 @@ obj-y += intel.o intel_cacheinfo.o addon_cpuid_features.o obj-y += nexgen.o obj-y += umc.o -obj-$(CONFIG_X86_MCE) += mcheck/ +obj-$(CONFIG_X86_MCE) += ../../../x86/kernel/cpu/mcheck/ obj-$(CONFIG_MTRR) += mtrr/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ diff --git a/arch/i386/kernel/cpu/mcheck/Makefile b/arch/x86/kernel/cpu/mcheck/Makefile similarity index 100% rename from arch/i386/kernel/cpu/mcheck/Makefile rename to arch/x86/kernel/cpu/mcheck/Makefile diff --git a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/x86/kernel/cpu/mcheck/k7.c similarity index 100% rename from arch/i386/kernel/cpu/mcheck/k7.c rename to arch/x86/kernel/cpu/mcheck/k7.c diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c similarity index 100% rename from arch/i386/kernel/cpu/mcheck/mce.c rename to arch/x86/kernel/cpu/mcheck/mce.c diff --git a/arch/i386/kernel/cpu/mcheck/mce.h b/arch/x86/kernel/cpu/mcheck/mce.h similarity index 100% rename from arch/i386/kernel/cpu/mcheck/mce.h rename to arch/x86/kernel/cpu/mcheck/mce.h diff --git a/arch/i386/kernel/cpu/mcheck/non-fatal.c b/arch/x86/kernel/cpu/mcheck/non-fatal.c similarity index 100% rename from arch/i386/kernel/cpu/mcheck/non-fatal.c rename to arch/x86/kernel/cpu/mcheck/non-fatal.c diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/x86/kernel/cpu/mcheck/p4.c similarity index 100% rename from arch/i386/kernel/cpu/mcheck/p4.c rename to arch/x86/kernel/cpu/mcheck/p4.c diff --git a/arch/i386/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c similarity index 100% rename from arch/i386/kernel/cpu/mcheck/p5.c rename to arch/x86/kernel/cpu/mcheck/p5.c diff --git a/arch/i386/kernel/cpu/mcheck/p6.c b/arch/x86/kernel/cpu/mcheck/p6.c similarity index 100% rename from arch/i386/kernel/cpu/mcheck/p6.c rename to arch/x86/kernel/cpu/mcheck/p6.c diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c similarity index 100% rename from arch/i386/kernel/cpu/mcheck/therm_throt.c rename to arch/x86/kernel/cpu/mcheck/therm_throt.c diff --git a/arch/i386/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c similarity index 100% rename from arch/i386/kernel/cpu/mcheck/winchip.c rename to arch/x86/kernel/cpu/mcheck/winchip.c diff --git a/arch/x86_64/kernel/Makefile_64 b/arch/x86_64/kernel/Makefile_64 index 8253617af12e..1c9de796fa14 100644 --- a/arch/x86_64/kernel/Makefile_64 +++ b/arch/x86_64/kernel/Makefile_64 @@ -48,7 +48,7 @@ obj-y += pcspeaker.o CFLAGS_vsyscall_64.o := $(PROFILING) -g0 -therm_throt-y += ../../i386/kernel/cpu/mcheck/therm_throt.o +therm_throt-y += ../../x86/kernel/cpu/mcheck/therm_throt.o bootflag-y += ../../i386/kernel/bootflag.o cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o topology-y += ../../i386/kernel/topology.o From ee580dc91efd83e6b55955e7261e8ad2a0e08d1a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:27 +0200 Subject: [PATCH 2079/2804] i386: move kernel/cpu/cpufreq Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Kconfig | 2 +- arch/i386/kernel/cpu/Makefile | 2 +- arch/{i386 => x86}/kernel/cpu/cpufreq/Kconfig | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/Makefile | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/acpi-cpufreq.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/cpufreq-nforce2.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/e_powersaver.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/elanfreq.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/gx-suspmod.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/longhaul.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/longhaul.h | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/longrun.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/p4-clockmod.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k6.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k7.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k7.h | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k8.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k8.h | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/sc520_freq.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-centrino.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-ich.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-lib.c | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-lib.h | 0 arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-smi.c | 0 arch/x86_64/kernel/Makefile_64 | 2 +- 25 files changed, 3 insertions(+), 3 deletions(-) rename arch/{i386 => x86}/kernel/cpu/cpufreq/Kconfig (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/Makefile (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/acpi-cpufreq.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/cpufreq-nforce2.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/e_powersaver.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/elanfreq.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/gx-suspmod.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/longhaul.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/longhaul.h (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/longrun.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/p4-clockmod.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k6.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k7.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k7.h (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k8.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/powernow-k8.h (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/sc520_freq.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-centrino.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-ich.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-lib.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-lib.h (100%) rename arch/{i386 => x86}/kernel/cpu/cpufreq/speedstep-smi.c (100%) diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 97b64d7d6bf6..fc86d41d2528 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -1067,7 +1067,7 @@ config APM_REAL_MODE_POWER_OFF endif # APM -source "arch/i386/kernel/cpu/cpufreq/Kconfig" +source "arch/x86/kernel/cpu/cpufreq/Kconfig" endmenu diff --git a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile index 09effc02e35a..8d9ce0232ada 100644 --- a/arch/i386/kernel/cpu/Makefile +++ b/arch/i386/kernel/cpu/Makefile @@ -15,6 +15,6 @@ obj-y += umc.o obj-$(CONFIG_X86_MCE) += ../../../x86/kernel/cpu/mcheck/ obj-$(CONFIG_MTRR) += mtrr/ -obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_CPU_FREQ) += ../../../x86/kernel/cpu/cpufreq/ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/x86/kernel/cpu/cpufreq/Kconfig similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/Kconfig rename to arch/x86/kernel/cpu/cpufreq/Kconfig diff --git a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/x86/kernel/cpu/cpufreq/Makefile similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/Makefile rename to arch/x86/kernel/cpu/cpufreq/Makefile diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c rename to arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c diff --git a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c rename to arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c diff --git a/arch/i386/kernel/cpu/cpufreq/e_powersaver.c b/arch/x86/kernel/cpu/cpufreq/e_powersaver.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/e_powersaver.c rename to arch/x86/kernel/cpu/cpufreq/e_powersaver.c diff --git a/arch/i386/kernel/cpu/cpufreq/elanfreq.c b/arch/x86/kernel/cpu/cpufreq/elanfreq.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/elanfreq.c rename to arch/x86/kernel/cpu/cpufreq/elanfreq.c diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/gx-suspmod.c rename to arch/x86/kernel/cpu/cpufreq/gx-suspmod.c diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/longhaul.c rename to arch/x86/kernel/cpu/cpufreq/longhaul.c diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.h b/arch/x86/kernel/cpu/cpufreq/longhaul.h similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/longhaul.h rename to arch/x86/kernel/cpu/cpufreq/longhaul.h diff --git a/arch/i386/kernel/cpu/cpufreq/longrun.c b/arch/x86/kernel/cpu/cpufreq/longrun.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/longrun.c rename to arch/x86/kernel/cpu/cpufreq/longrun.c diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/p4-clockmod.c rename to arch/x86/kernel/cpu/cpufreq/p4-clockmod.c diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/powernow-k6.c rename to arch/x86/kernel/cpu/cpufreq/powernow-k6.c diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/powernow-k7.c rename to arch/x86/kernel/cpu/cpufreq/powernow-k7.c diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.h b/arch/x86/kernel/cpu/cpufreq/powernow-k7.h similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/powernow-k7.h rename to arch/x86/kernel/cpu/cpufreq/powernow-k7.h diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/powernow-k8.c rename to arch/x86/kernel/cpu/cpufreq/powernow-k8.c diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/powernow-k8.h rename to arch/x86/kernel/cpu/cpufreq/powernow-k8.h diff --git a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/sc520_freq.c rename to arch/x86/kernel/cpu/cpufreq/sc520_freq.c diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c rename to arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/speedstep-ich.c rename to arch/x86/kernel/cpu/cpufreq/speedstep-ich.c diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/speedstep-lib.c rename to arch/x86/kernel/cpu/cpufreq/speedstep-lib.c diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/speedstep-lib.h rename to arch/x86/kernel/cpu/cpufreq/speedstep-lib.h diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c similarity index 100% rename from arch/i386/kernel/cpu/cpufreq/speedstep-smi.c rename to arch/x86/kernel/cpu/cpufreq/speedstep-smi.c diff --git a/arch/x86_64/kernel/Makefile_64 b/arch/x86_64/kernel/Makefile_64 index 1c9de796fa14..a6d8216084ad 100644 --- a/arch/x86_64/kernel/Makefile_64 +++ b/arch/x86_64/kernel/Makefile_64 @@ -27,7 +27,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec_64.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_64.o obj-$(CONFIG_PM) += suspend_64.o obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o -obj-$(CONFIG_CPU_FREQ) += ../../i386/kernel/cpu/cpufreq/ +obj-$(CONFIG_CPU_FREQ) += ../../x86/kernel/cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart_64.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o From 2ec1df4130c60d1eb49dc0fa0ed15858fede6b05 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:28 +0200 Subject: [PATCH 2080/2804] i386: move kernel/cpu/mtrr Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/cpu/Makefile | 2 +- arch/{i386 => x86}/kernel/cpu/mtrr/Makefile | 0 arch/{i386 => x86}/kernel/cpu/mtrr/amd.c | 0 arch/{i386 => x86}/kernel/cpu/mtrr/centaur.c | 0 arch/{i386 => x86}/kernel/cpu/mtrr/cyrix.c | 0 arch/{i386 => x86}/kernel/cpu/mtrr/generic.c | 0 arch/{i386 => x86}/kernel/cpu/mtrr/if.c | 0 arch/{i386 => x86}/kernel/cpu/mtrr/main.c | 0 arch/{i386 => x86}/kernel/cpu/mtrr/mtrr.h | 0 arch/{i386 => x86}/kernel/cpu/mtrr/state.c | 0 arch/x86_64/kernel/Makefile_64 | 2 +- 11 files changed, 2 insertions(+), 2 deletions(-) rename arch/{i386 => x86}/kernel/cpu/mtrr/Makefile (100%) rename arch/{i386 => x86}/kernel/cpu/mtrr/amd.c (100%) rename arch/{i386 => x86}/kernel/cpu/mtrr/centaur.c (100%) rename arch/{i386 => x86}/kernel/cpu/mtrr/cyrix.c (100%) rename arch/{i386 => x86}/kernel/cpu/mtrr/generic.c (100%) rename arch/{i386 => x86}/kernel/cpu/mtrr/if.c (100%) rename arch/{i386 => x86}/kernel/cpu/mtrr/main.c (100%) rename arch/{i386 => x86}/kernel/cpu/mtrr/mtrr.h (100%) rename arch/{i386 => x86}/kernel/cpu/mtrr/state.c (100%) diff --git a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile index 8d9ce0232ada..6687f6d5ad2f 100644 --- a/arch/i386/kernel/cpu/Makefile +++ b/arch/i386/kernel/cpu/Makefile @@ -14,7 +14,7 @@ obj-y += umc.o obj-$(CONFIG_X86_MCE) += ../../../x86/kernel/cpu/mcheck/ -obj-$(CONFIG_MTRR) += mtrr/ +obj-$(CONFIG_MTRR) += ../../../x86/kernel/cpu/mtrr/ obj-$(CONFIG_CPU_FREQ) += ../../../x86/kernel/cpu/cpufreq/ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o diff --git a/arch/i386/kernel/cpu/mtrr/Makefile b/arch/x86/kernel/cpu/mtrr/Makefile similarity index 100% rename from arch/i386/kernel/cpu/mtrr/Makefile rename to arch/x86/kernel/cpu/mtrr/Makefile diff --git a/arch/i386/kernel/cpu/mtrr/amd.c b/arch/x86/kernel/cpu/mtrr/amd.c similarity index 100% rename from arch/i386/kernel/cpu/mtrr/amd.c rename to arch/x86/kernel/cpu/mtrr/amd.c diff --git a/arch/i386/kernel/cpu/mtrr/centaur.c b/arch/x86/kernel/cpu/mtrr/centaur.c similarity index 100% rename from arch/i386/kernel/cpu/mtrr/centaur.c rename to arch/x86/kernel/cpu/mtrr/centaur.c diff --git a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c similarity index 100% rename from arch/i386/kernel/cpu/mtrr/cyrix.c rename to arch/x86/kernel/cpu/mtrr/cyrix.c diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c similarity index 100% rename from arch/i386/kernel/cpu/mtrr/generic.c rename to arch/x86/kernel/cpu/mtrr/generic.c diff --git a/arch/i386/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c similarity index 100% rename from arch/i386/kernel/cpu/mtrr/if.c rename to arch/x86/kernel/cpu/mtrr/if.c diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c similarity index 100% rename from arch/i386/kernel/cpu/mtrr/main.c rename to arch/x86/kernel/cpu/mtrr/main.c diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h similarity index 100% rename from arch/i386/kernel/cpu/mtrr/mtrr.h rename to arch/x86/kernel/cpu/mtrr/mtrr.h diff --git a/arch/i386/kernel/cpu/mtrr/state.c b/arch/x86/kernel/cpu/mtrr/state.c similarity index 100% rename from arch/i386/kernel/cpu/mtrr/state.c rename to arch/x86/kernel/cpu/mtrr/state.c diff --git a/arch/x86_64/kernel/Makefile_64 b/arch/x86_64/kernel/Makefile_64 index a6d8216084ad..e74805091034 100644 --- a/arch/x86_64/kernel/Makefile_64 +++ b/arch/x86_64/kernel/Makefile_64 @@ -15,7 +15,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o -obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ +obj-$(CONFIG_MTRR) += ../../x86/kernel/cpu/mtrr/ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o From da957e111bb0c189a4a3bf8a00caaecb59ed94ca Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:31 +0200 Subject: [PATCH 2081/2804] i386: move math-emu Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Kconfig | 2 +- arch/i386/Makefile | 2 +- arch/{i386 => x86}/math-emu/Makefile | 0 arch/{i386 => x86}/math-emu/README | 0 arch/{i386 => x86}/math-emu/control_w.h | 0 arch/{i386 => x86}/math-emu/div_Xsig.S | 0 arch/{i386 => x86}/math-emu/div_small.S | 0 arch/{i386 => x86}/math-emu/errors.c | 0 arch/{i386 => x86}/math-emu/exception.h | 0 arch/{i386 => x86}/math-emu/fpu_arith.c | 0 arch/{i386 => x86}/math-emu/fpu_asm.h | 0 arch/{i386 => x86}/math-emu/fpu_aux.c | 0 arch/{i386 => x86}/math-emu/fpu_emu.h | 0 arch/{i386 => x86}/math-emu/fpu_entry.c | 0 arch/{i386 => x86}/math-emu/fpu_etc.c | 0 arch/{i386 => x86}/math-emu/fpu_proto.h | 0 arch/{i386 => x86}/math-emu/fpu_system.h | 0 arch/{i386 => x86}/math-emu/fpu_tags.c | 0 arch/{i386 => x86}/math-emu/fpu_trig.c | 0 arch/{i386 => x86}/math-emu/get_address.c | 0 arch/{i386 => x86}/math-emu/load_store.c | 0 arch/{i386 => x86}/math-emu/mul_Xsig.S | 0 arch/{i386 => x86}/math-emu/poly.h | 0 arch/{i386 => x86}/math-emu/poly_2xm1.c | 0 arch/{i386 => x86}/math-emu/poly_atan.c | 0 arch/{i386 => x86}/math-emu/poly_l2.c | 0 arch/{i386 => x86}/math-emu/poly_sin.c | 0 arch/{i386 => x86}/math-emu/poly_tan.c | 0 arch/{i386 => x86}/math-emu/polynom_Xsig.S | 0 arch/{i386 => x86}/math-emu/reg_add_sub.c | 0 arch/{i386 => x86}/math-emu/reg_compare.c | 0 arch/{i386 => x86}/math-emu/reg_constant.c | 0 arch/{i386 => x86}/math-emu/reg_constant.h | 0 arch/{i386 => x86}/math-emu/reg_convert.c | 0 arch/{i386 => x86}/math-emu/reg_divide.c | 0 arch/{i386 => x86}/math-emu/reg_ld_str.c | 0 arch/{i386 => x86}/math-emu/reg_mul.c | 0 arch/{i386 => x86}/math-emu/reg_norm.S | 0 arch/{i386 => x86}/math-emu/reg_round.S | 0 arch/{i386 => x86}/math-emu/reg_u_add.S | 0 arch/{i386 => x86}/math-emu/reg_u_div.S | 0 arch/{i386 => x86}/math-emu/reg_u_mul.S | 0 arch/{i386 => x86}/math-emu/reg_u_sub.S | 0 arch/{i386 => x86}/math-emu/round_Xsig.S | 0 arch/{i386 => x86}/math-emu/shr_Xsig.S | 0 arch/{i386 => x86}/math-emu/status_w.h | 0 arch/{i386 => x86}/math-emu/version.h | 0 arch/{i386 => x86}/math-emu/wm_shrx.S | 0 arch/{i386 => x86}/math-emu/wm_sqrt.S | 0 49 files changed, 2 insertions(+), 2 deletions(-) rename arch/{i386 => x86}/math-emu/Makefile (100%) rename arch/{i386 => x86}/math-emu/README (100%) rename arch/{i386 => x86}/math-emu/control_w.h (100%) rename arch/{i386 => x86}/math-emu/div_Xsig.S (100%) rename arch/{i386 => x86}/math-emu/div_small.S (100%) rename arch/{i386 => x86}/math-emu/errors.c (100%) rename arch/{i386 => x86}/math-emu/exception.h (100%) rename arch/{i386 => x86}/math-emu/fpu_arith.c (100%) rename arch/{i386 => x86}/math-emu/fpu_asm.h (100%) rename arch/{i386 => x86}/math-emu/fpu_aux.c (100%) rename arch/{i386 => x86}/math-emu/fpu_emu.h (100%) rename arch/{i386 => x86}/math-emu/fpu_entry.c (100%) rename arch/{i386 => x86}/math-emu/fpu_etc.c (100%) rename arch/{i386 => x86}/math-emu/fpu_proto.h (100%) rename arch/{i386 => x86}/math-emu/fpu_system.h (100%) rename arch/{i386 => x86}/math-emu/fpu_tags.c (100%) rename arch/{i386 => x86}/math-emu/fpu_trig.c (100%) rename arch/{i386 => x86}/math-emu/get_address.c (100%) rename arch/{i386 => x86}/math-emu/load_store.c (100%) rename arch/{i386 => x86}/math-emu/mul_Xsig.S (100%) rename arch/{i386 => x86}/math-emu/poly.h (100%) rename arch/{i386 => x86}/math-emu/poly_2xm1.c (100%) rename arch/{i386 => x86}/math-emu/poly_atan.c (100%) rename arch/{i386 => x86}/math-emu/poly_l2.c (100%) rename arch/{i386 => x86}/math-emu/poly_sin.c (100%) rename arch/{i386 => x86}/math-emu/poly_tan.c (100%) rename arch/{i386 => x86}/math-emu/polynom_Xsig.S (100%) rename arch/{i386 => x86}/math-emu/reg_add_sub.c (100%) rename arch/{i386 => x86}/math-emu/reg_compare.c (100%) rename arch/{i386 => x86}/math-emu/reg_constant.c (100%) rename arch/{i386 => x86}/math-emu/reg_constant.h (100%) rename arch/{i386 => x86}/math-emu/reg_convert.c (100%) rename arch/{i386 => x86}/math-emu/reg_divide.c (100%) rename arch/{i386 => x86}/math-emu/reg_ld_str.c (100%) rename arch/{i386 => x86}/math-emu/reg_mul.c (100%) rename arch/{i386 => x86}/math-emu/reg_norm.S (100%) rename arch/{i386 => x86}/math-emu/reg_round.S (100%) rename arch/{i386 => x86}/math-emu/reg_u_add.S (100%) rename arch/{i386 => x86}/math-emu/reg_u_div.S (100%) rename arch/{i386 => x86}/math-emu/reg_u_mul.S (100%) rename arch/{i386 => x86}/math-emu/reg_u_sub.S (100%) rename arch/{i386 => x86}/math-emu/round_Xsig.S (100%) rename arch/{i386 => x86}/math-emu/shr_Xsig.S (100%) rename arch/{i386 => x86}/math-emu/status_w.h (100%) rename arch/{i386 => x86}/math-emu/version.h (100%) rename arch/{i386 => x86}/math-emu/wm_shrx.S (100%) rename arch/{i386 => x86}/math-emu/wm_sqrt.S (100%) diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index fc86d41d2528..561cc21914b2 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -707,7 +707,7 @@ config MATH_EMULATION intend to use this kernel on different machines. More information about the internals of the Linux math coprocessor - emulation can be found in . + emulation can be found in . If you are not sure, say Y; apart from resulting in a 66 KB bigger kernel, it won't hurt. diff --git a/arch/i386/Makefile b/arch/i386/Makefile index dca07ae933d7..fe374b654302 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -106,7 +106,7 @@ core-y += arch/i386/kernel/ \ arch/i386/mm/ \ $(mcore-y)/ \ arch/x86/crypto/ -drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/ +drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ drivers-$(CONFIG_PCI) += arch/i386/pci/ # must be linked after kernel/ drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ diff --git a/arch/i386/math-emu/Makefile b/arch/x86/math-emu/Makefile similarity index 100% rename from arch/i386/math-emu/Makefile rename to arch/x86/math-emu/Makefile diff --git a/arch/i386/math-emu/README b/arch/x86/math-emu/README similarity index 100% rename from arch/i386/math-emu/README rename to arch/x86/math-emu/README diff --git a/arch/i386/math-emu/control_w.h b/arch/x86/math-emu/control_w.h similarity index 100% rename from arch/i386/math-emu/control_w.h rename to arch/x86/math-emu/control_w.h diff --git a/arch/i386/math-emu/div_Xsig.S b/arch/x86/math-emu/div_Xsig.S similarity index 100% rename from arch/i386/math-emu/div_Xsig.S rename to arch/x86/math-emu/div_Xsig.S diff --git a/arch/i386/math-emu/div_small.S b/arch/x86/math-emu/div_small.S similarity index 100% rename from arch/i386/math-emu/div_small.S rename to arch/x86/math-emu/div_small.S diff --git a/arch/i386/math-emu/errors.c b/arch/x86/math-emu/errors.c similarity index 100% rename from arch/i386/math-emu/errors.c rename to arch/x86/math-emu/errors.c diff --git a/arch/i386/math-emu/exception.h b/arch/x86/math-emu/exception.h similarity index 100% rename from arch/i386/math-emu/exception.h rename to arch/x86/math-emu/exception.h diff --git a/arch/i386/math-emu/fpu_arith.c b/arch/x86/math-emu/fpu_arith.c similarity index 100% rename from arch/i386/math-emu/fpu_arith.c rename to arch/x86/math-emu/fpu_arith.c diff --git a/arch/i386/math-emu/fpu_asm.h b/arch/x86/math-emu/fpu_asm.h similarity index 100% rename from arch/i386/math-emu/fpu_asm.h rename to arch/x86/math-emu/fpu_asm.h diff --git a/arch/i386/math-emu/fpu_aux.c b/arch/x86/math-emu/fpu_aux.c similarity index 100% rename from arch/i386/math-emu/fpu_aux.c rename to arch/x86/math-emu/fpu_aux.c diff --git a/arch/i386/math-emu/fpu_emu.h b/arch/x86/math-emu/fpu_emu.h similarity index 100% rename from arch/i386/math-emu/fpu_emu.h rename to arch/x86/math-emu/fpu_emu.h diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c similarity index 100% rename from arch/i386/math-emu/fpu_entry.c rename to arch/x86/math-emu/fpu_entry.c diff --git a/arch/i386/math-emu/fpu_etc.c b/arch/x86/math-emu/fpu_etc.c similarity index 100% rename from arch/i386/math-emu/fpu_etc.c rename to arch/x86/math-emu/fpu_etc.c diff --git a/arch/i386/math-emu/fpu_proto.h b/arch/x86/math-emu/fpu_proto.h similarity index 100% rename from arch/i386/math-emu/fpu_proto.h rename to arch/x86/math-emu/fpu_proto.h diff --git a/arch/i386/math-emu/fpu_system.h b/arch/x86/math-emu/fpu_system.h similarity index 100% rename from arch/i386/math-emu/fpu_system.h rename to arch/x86/math-emu/fpu_system.h diff --git a/arch/i386/math-emu/fpu_tags.c b/arch/x86/math-emu/fpu_tags.c similarity index 100% rename from arch/i386/math-emu/fpu_tags.c rename to arch/x86/math-emu/fpu_tags.c diff --git a/arch/i386/math-emu/fpu_trig.c b/arch/x86/math-emu/fpu_trig.c similarity index 100% rename from arch/i386/math-emu/fpu_trig.c rename to arch/x86/math-emu/fpu_trig.c diff --git a/arch/i386/math-emu/get_address.c b/arch/x86/math-emu/get_address.c similarity index 100% rename from arch/i386/math-emu/get_address.c rename to arch/x86/math-emu/get_address.c diff --git a/arch/i386/math-emu/load_store.c b/arch/x86/math-emu/load_store.c similarity index 100% rename from arch/i386/math-emu/load_store.c rename to arch/x86/math-emu/load_store.c diff --git a/arch/i386/math-emu/mul_Xsig.S b/arch/x86/math-emu/mul_Xsig.S similarity index 100% rename from arch/i386/math-emu/mul_Xsig.S rename to arch/x86/math-emu/mul_Xsig.S diff --git a/arch/i386/math-emu/poly.h b/arch/x86/math-emu/poly.h similarity index 100% rename from arch/i386/math-emu/poly.h rename to arch/x86/math-emu/poly.h diff --git a/arch/i386/math-emu/poly_2xm1.c b/arch/x86/math-emu/poly_2xm1.c similarity index 100% rename from arch/i386/math-emu/poly_2xm1.c rename to arch/x86/math-emu/poly_2xm1.c diff --git a/arch/i386/math-emu/poly_atan.c b/arch/x86/math-emu/poly_atan.c similarity index 100% rename from arch/i386/math-emu/poly_atan.c rename to arch/x86/math-emu/poly_atan.c diff --git a/arch/i386/math-emu/poly_l2.c b/arch/x86/math-emu/poly_l2.c similarity index 100% rename from arch/i386/math-emu/poly_l2.c rename to arch/x86/math-emu/poly_l2.c diff --git a/arch/i386/math-emu/poly_sin.c b/arch/x86/math-emu/poly_sin.c similarity index 100% rename from arch/i386/math-emu/poly_sin.c rename to arch/x86/math-emu/poly_sin.c diff --git a/arch/i386/math-emu/poly_tan.c b/arch/x86/math-emu/poly_tan.c similarity index 100% rename from arch/i386/math-emu/poly_tan.c rename to arch/x86/math-emu/poly_tan.c diff --git a/arch/i386/math-emu/polynom_Xsig.S b/arch/x86/math-emu/polynom_Xsig.S similarity index 100% rename from arch/i386/math-emu/polynom_Xsig.S rename to arch/x86/math-emu/polynom_Xsig.S diff --git a/arch/i386/math-emu/reg_add_sub.c b/arch/x86/math-emu/reg_add_sub.c similarity index 100% rename from arch/i386/math-emu/reg_add_sub.c rename to arch/x86/math-emu/reg_add_sub.c diff --git a/arch/i386/math-emu/reg_compare.c b/arch/x86/math-emu/reg_compare.c similarity index 100% rename from arch/i386/math-emu/reg_compare.c rename to arch/x86/math-emu/reg_compare.c diff --git a/arch/i386/math-emu/reg_constant.c b/arch/x86/math-emu/reg_constant.c similarity index 100% rename from arch/i386/math-emu/reg_constant.c rename to arch/x86/math-emu/reg_constant.c diff --git a/arch/i386/math-emu/reg_constant.h b/arch/x86/math-emu/reg_constant.h similarity index 100% rename from arch/i386/math-emu/reg_constant.h rename to arch/x86/math-emu/reg_constant.h diff --git a/arch/i386/math-emu/reg_convert.c b/arch/x86/math-emu/reg_convert.c similarity index 100% rename from arch/i386/math-emu/reg_convert.c rename to arch/x86/math-emu/reg_convert.c diff --git a/arch/i386/math-emu/reg_divide.c b/arch/x86/math-emu/reg_divide.c similarity index 100% rename from arch/i386/math-emu/reg_divide.c rename to arch/x86/math-emu/reg_divide.c diff --git a/arch/i386/math-emu/reg_ld_str.c b/arch/x86/math-emu/reg_ld_str.c similarity index 100% rename from arch/i386/math-emu/reg_ld_str.c rename to arch/x86/math-emu/reg_ld_str.c diff --git a/arch/i386/math-emu/reg_mul.c b/arch/x86/math-emu/reg_mul.c similarity index 100% rename from arch/i386/math-emu/reg_mul.c rename to arch/x86/math-emu/reg_mul.c diff --git a/arch/i386/math-emu/reg_norm.S b/arch/x86/math-emu/reg_norm.S similarity index 100% rename from arch/i386/math-emu/reg_norm.S rename to arch/x86/math-emu/reg_norm.S diff --git a/arch/i386/math-emu/reg_round.S b/arch/x86/math-emu/reg_round.S similarity index 100% rename from arch/i386/math-emu/reg_round.S rename to arch/x86/math-emu/reg_round.S diff --git a/arch/i386/math-emu/reg_u_add.S b/arch/x86/math-emu/reg_u_add.S similarity index 100% rename from arch/i386/math-emu/reg_u_add.S rename to arch/x86/math-emu/reg_u_add.S diff --git a/arch/i386/math-emu/reg_u_div.S b/arch/x86/math-emu/reg_u_div.S similarity index 100% rename from arch/i386/math-emu/reg_u_div.S rename to arch/x86/math-emu/reg_u_div.S diff --git a/arch/i386/math-emu/reg_u_mul.S b/arch/x86/math-emu/reg_u_mul.S similarity index 100% rename from arch/i386/math-emu/reg_u_mul.S rename to arch/x86/math-emu/reg_u_mul.S diff --git a/arch/i386/math-emu/reg_u_sub.S b/arch/x86/math-emu/reg_u_sub.S similarity index 100% rename from arch/i386/math-emu/reg_u_sub.S rename to arch/x86/math-emu/reg_u_sub.S diff --git a/arch/i386/math-emu/round_Xsig.S b/arch/x86/math-emu/round_Xsig.S similarity index 100% rename from arch/i386/math-emu/round_Xsig.S rename to arch/x86/math-emu/round_Xsig.S diff --git a/arch/i386/math-emu/shr_Xsig.S b/arch/x86/math-emu/shr_Xsig.S similarity index 100% rename from arch/i386/math-emu/shr_Xsig.S rename to arch/x86/math-emu/shr_Xsig.S diff --git a/arch/i386/math-emu/status_w.h b/arch/x86/math-emu/status_w.h similarity index 100% rename from arch/i386/math-emu/status_w.h rename to arch/x86/math-emu/status_w.h diff --git a/arch/i386/math-emu/version.h b/arch/x86/math-emu/version.h similarity index 100% rename from arch/i386/math-emu/version.h rename to arch/x86/math-emu/version.h diff --git a/arch/i386/math-emu/wm_shrx.S b/arch/x86/math-emu/wm_shrx.S similarity index 100% rename from arch/i386/math-emu/wm_shrx.S rename to arch/x86/math-emu/wm_shrx.S diff --git a/arch/i386/math-emu/wm_sqrt.S b/arch/x86/math-emu/wm_sqrt.S similarity index 100% rename from arch/i386/math-emu/wm_sqrt.S rename to arch/x86/math-emu/wm_sqrt.S From 44f0257fc316ff4b33aa3438dd8d891b7d6d72b9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:33 +0200 Subject: [PATCH 2082/2804] i386: move lib Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/lib/Makefile | 2 +- arch/{i386 => x86}/lib/Makefile_32 | 0 arch/{i386 => x86}/lib/bitops_32.c | 0 arch/{i386 => x86}/lib/checksum_32.S | 0 arch/{i386 => x86}/lib/delay_32.c | 0 arch/{i386 => x86}/lib/getuser_32.S | 0 arch/{i386 => x86}/lib/memcpy_32.c | 0 arch/{i386 => x86}/lib/mmx_32.c | 0 arch/{i386 => x86}/lib/msr-on-cpu.c | 0 arch/{i386 => x86}/lib/putuser_32.S | 0 arch/{i386 => x86}/lib/semaphore_32.S | 0 arch/{i386 => x86}/lib/string_32.c | 0 arch/{i386 => x86}/lib/strstr_32.c | 0 arch/{i386 => x86}/lib/usercopy_32.c | 0 arch/x86_64/lib/Makefile | 2 +- arch/x86_64/lib/msr-on-cpu.c | 2 +- 17 files changed, 4 insertions(+), 4 deletions(-) rename arch/{i386 => x86}/lib/Makefile (65%) rename arch/{i386 => x86}/lib/Makefile_32 (100%) rename arch/{i386 => x86}/lib/bitops_32.c (100%) rename arch/{i386 => x86}/lib/checksum_32.S (100%) rename arch/{i386 => x86}/lib/delay_32.c (100%) rename arch/{i386 => x86}/lib/getuser_32.S (100%) rename arch/{i386 => x86}/lib/memcpy_32.c (100%) rename arch/{i386 => x86}/lib/mmx_32.c (100%) rename arch/{i386 => x86}/lib/msr-on-cpu.c (100%) rename arch/{i386 => x86}/lib/putuser_32.S (100%) rename arch/{i386 => x86}/lib/semaphore_32.S (100%) rename arch/{i386 => x86}/lib/string_32.c (100%) rename arch/{i386 => x86}/lib/strstr_32.c (100%) rename arch/{i386 => x86}/lib/usercopy_32.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index fe374b654302..93492b37061c 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -101,7 +101,7 @@ mflags-y += -Iinclude/asm-i386/mach-default head-y := arch/i386/kernel/head_32.o arch/i386/kernel/init_task_32.o -libs-y += arch/i386/lib/ +libs-y += arch/x86/lib/ core-y += arch/i386/kernel/ \ arch/i386/mm/ \ $(mcore-y)/ \ diff --git a/arch/i386/lib/Makefile b/arch/x86/lib/Makefile similarity index 65% rename from arch/i386/lib/Makefile rename to arch/x86/lib/Makefile index 2b1547e0ac6b..2d7d724a2a6a 100644 --- a/arch/i386/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/lib/Makefile_32 +include ${srctree}/arch/x86/lib/Makefile_32 else include ${srctree}/arch/x86_64/lib/Makefile_64 endif diff --git a/arch/i386/lib/Makefile_32 b/arch/x86/lib/Makefile_32 similarity index 100% rename from arch/i386/lib/Makefile_32 rename to arch/x86/lib/Makefile_32 diff --git a/arch/i386/lib/bitops_32.c b/arch/x86/lib/bitops_32.c similarity index 100% rename from arch/i386/lib/bitops_32.c rename to arch/x86/lib/bitops_32.c diff --git a/arch/i386/lib/checksum_32.S b/arch/x86/lib/checksum_32.S similarity index 100% rename from arch/i386/lib/checksum_32.S rename to arch/x86/lib/checksum_32.S diff --git a/arch/i386/lib/delay_32.c b/arch/x86/lib/delay_32.c similarity index 100% rename from arch/i386/lib/delay_32.c rename to arch/x86/lib/delay_32.c diff --git a/arch/i386/lib/getuser_32.S b/arch/x86/lib/getuser_32.S similarity index 100% rename from arch/i386/lib/getuser_32.S rename to arch/x86/lib/getuser_32.S diff --git a/arch/i386/lib/memcpy_32.c b/arch/x86/lib/memcpy_32.c similarity index 100% rename from arch/i386/lib/memcpy_32.c rename to arch/x86/lib/memcpy_32.c diff --git a/arch/i386/lib/mmx_32.c b/arch/x86/lib/mmx_32.c similarity index 100% rename from arch/i386/lib/mmx_32.c rename to arch/x86/lib/mmx_32.c diff --git a/arch/i386/lib/msr-on-cpu.c b/arch/x86/lib/msr-on-cpu.c similarity index 100% rename from arch/i386/lib/msr-on-cpu.c rename to arch/x86/lib/msr-on-cpu.c diff --git a/arch/i386/lib/putuser_32.S b/arch/x86/lib/putuser_32.S similarity index 100% rename from arch/i386/lib/putuser_32.S rename to arch/x86/lib/putuser_32.S diff --git a/arch/i386/lib/semaphore_32.S b/arch/x86/lib/semaphore_32.S similarity index 100% rename from arch/i386/lib/semaphore_32.S rename to arch/x86/lib/semaphore_32.S diff --git a/arch/i386/lib/string_32.c b/arch/x86/lib/string_32.c similarity index 100% rename from arch/i386/lib/string_32.c rename to arch/x86/lib/string_32.c diff --git a/arch/i386/lib/strstr_32.c b/arch/x86/lib/strstr_32.c similarity index 100% rename from arch/i386/lib/strstr_32.c rename to arch/x86/lib/strstr_32.c diff --git a/arch/i386/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c similarity index 100% rename from arch/i386/lib/usercopy_32.c rename to arch/x86/lib/usercopy_32.c diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 2b1547e0ac6b..2d7d724a2a6a 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/lib/Makefile_32 +include ${srctree}/arch/x86/lib/Makefile_32 else include ${srctree}/arch/x86_64/lib/Makefile_64 endif diff --git a/arch/x86_64/lib/msr-on-cpu.c b/arch/x86_64/lib/msr-on-cpu.c index 47e0ec47c376..5672d4190fbe 100644 --- a/arch/x86_64/lib/msr-on-cpu.c +++ b/arch/x86_64/lib/msr-on-cpu.c @@ -1 +1 @@ -#include "../../i386/lib/msr-on-cpu.c" +#include "../../x86/lib/msr-on-cpu.c" From 4b60eb8380a0b588a03b6052d7ac93e1964c75b8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:34 +0200 Subject: [PATCH 2083/2804] i386: move power Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/power/Makefile | 0 arch/{i386 => x86}/power/cpu.c | 0 arch/{i386 => x86}/power/suspend.c | 0 arch/{i386 => x86}/power/swsusp.S | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename arch/{i386 => x86}/power/Makefile (100%) rename arch/{i386 => x86}/power/cpu.c (100%) rename arch/{i386 => x86}/power/suspend.c (100%) rename arch/{i386 => x86}/power/swsusp.S (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 93492b37061c..da64799484a7 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -110,7 +110,7 @@ drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ drivers-$(CONFIG_PCI) += arch/i386/pci/ # must be linked after kernel/ drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ -drivers-$(CONFIG_PM) += arch/i386/power/ +drivers-$(CONFIG_PM) += arch/x86/power/ drivers-$(CONFIG_FB) += arch/i386/video/ CFLAGS += $(mflags-y) diff --git a/arch/i386/power/Makefile b/arch/x86/power/Makefile similarity index 100% rename from arch/i386/power/Makefile rename to arch/x86/power/Makefile diff --git a/arch/i386/power/cpu.c b/arch/x86/power/cpu.c similarity index 100% rename from arch/i386/power/cpu.c rename to arch/x86/power/cpu.c diff --git a/arch/i386/power/suspend.c b/arch/x86/power/suspend.c similarity index 100% rename from arch/i386/power/suspend.c rename to arch/x86/power/suspend.c diff --git a/arch/i386/power/swsusp.S b/arch/x86/power/swsusp.S similarity index 100% rename from arch/i386/power/swsusp.S rename to arch/x86/power/swsusp.S From fb9aa6f1d4a1e11e66a680460b2c2b2b10b62f79 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:36 +0200 Subject: [PATCH 2084/2804] i386: move pci Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/pci/Makefile | 2 +- arch/{i386 => x86}/pci/Makefile_32 | 0 arch/{i386 => x86}/pci/acpi.c | 0 arch/{i386 => x86}/pci/common.c | 0 arch/{i386 => x86}/pci/direct.c | 0 arch/{i386 => x86}/pci/early.c | 0 arch/{i386 => x86}/pci/fixup.c | 0 arch/{i386 => x86}/pci/i386.c | 0 arch/{i386 => x86}/pci/init.c | 0 arch/{i386 => x86}/pci/irq.c | 0 arch/{i386 => x86}/pci/legacy.c | 0 arch/{i386 => x86}/pci/mmconfig-shared.c | 0 arch/{i386 => x86}/pci/mmconfig_32.c | 0 arch/{i386 => x86}/pci/numa.c | 0 arch/{i386 => x86}/pci/pcbios.c | 0 arch/{i386 => x86}/pci/pci.h | 0 arch/{i386 => x86}/pci/visws.c | 0 arch/x86_64/pci/Makefile | 2 +- arch/x86_64/pci/Makefile_64 | 22 +++++++++++----------- drivers/pci/hotplug/cpqphp_core.c | 2 +- drivers/pci/hotplug/cpqphp_pci.c | 2 +- drivers/pci/hotplug/ibmphp_core.c | 2 +- 23 files changed, 17 insertions(+), 17 deletions(-) rename arch/{i386 => x86}/pci/Makefile (65%) rename arch/{i386 => x86}/pci/Makefile_32 (100%) rename arch/{i386 => x86}/pci/acpi.c (100%) rename arch/{i386 => x86}/pci/common.c (100%) rename arch/{i386 => x86}/pci/direct.c (100%) rename arch/{i386 => x86}/pci/early.c (100%) rename arch/{i386 => x86}/pci/fixup.c (100%) rename arch/{i386 => x86}/pci/i386.c (100%) rename arch/{i386 => x86}/pci/init.c (100%) rename arch/{i386 => x86}/pci/irq.c (100%) rename arch/{i386 => x86}/pci/legacy.c (100%) rename arch/{i386 => x86}/pci/mmconfig-shared.c (100%) rename arch/{i386 => x86}/pci/mmconfig_32.c (100%) rename arch/{i386 => x86}/pci/numa.c (100%) rename arch/{i386 => x86}/pci/pcbios.c (100%) rename arch/{i386 => x86}/pci/pci.h (100%) rename arch/{i386 => x86}/pci/visws.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index da64799484a7..87c959d5f354 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -107,7 +107,7 @@ core-y += arch/i386/kernel/ \ $(mcore-y)/ \ arch/x86/crypto/ drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ -drivers-$(CONFIG_PCI) += arch/i386/pci/ +drivers-$(CONFIG_PCI) += arch/x86/pci/ # must be linked after kernel/ drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ drivers-$(CONFIG_PM) += arch/x86/power/ diff --git a/arch/i386/pci/Makefile b/arch/x86/pci/Makefile similarity index 65% rename from arch/i386/pci/Makefile rename to arch/x86/pci/Makefile index d04d8f976d1c..b3e54c45d408 100644 --- a/arch/i386/pci/Makefile +++ b/arch/x86/pci/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/pci/Makefile_32 +include ${srctree}/arch/x86/pci/Makefile_32 else include ${srctree}/arch/x86_64/pci/Makefile_64 endif diff --git a/arch/i386/pci/Makefile_32 b/arch/x86/pci/Makefile_32 similarity index 100% rename from arch/i386/pci/Makefile_32 rename to arch/x86/pci/Makefile_32 diff --git a/arch/i386/pci/acpi.c b/arch/x86/pci/acpi.c similarity index 100% rename from arch/i386/pci/acpi.c rename to arch/x86/pci/acpi.c diff --git a/arch/i386/pci/common.c b/arch/x86/pci/common.c similarity index 100% rename from arch/i386/pci/common.c rename to arch/x86/pci/common.c diff --git a/arch/i386/pci/direct.c b/arch/x86/pci/direct.c similarity index 100% rename from arch/i386/pci/direct.c rename to arch/x86/pci/direct.c diff --git a/arch/i386/pci/early.c b/arch/x86/pci/early.c similarity index 100% rename from arch/i386/pci/early.c rename to arch/x86/pci/early.c diff --git a/arch/i386/pci/fixup.c b/arch/x86/pci/fixup.c similarity index 100% rename from arch/i386/pci/fixup.c rename to arch/x86/pci/fixup.c diff --git a/arch/i386/pci/i386.c b/arch/x86/pci/i386.c similarity index 100% rename from arch/i386/pci/i386.c rename to arch/x86/pci/i386.c diff --git a/arch/i386/pci/init.c b/arch/x86/pci/init.c similarity index 100% rename from arch/i386/pci/init.c rename to arch/x86/pci/init.c diff --git a/arch/i386/pci/irq.c b/arch/x86/pci/irq.c similarity index 100% rename from arch/i386/pci/irq.c rename to arch/x86/pci/irq.c diff --git a/arch/i386/pci/legacy.c b/arch/x86/pci/legacy.c similarity index 100% rename from arch/i386/pci/legacy.c rename to arch/x86/pci/legacy.c diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c similarity index 100% rename from arch/i386/pci/mmconfig-shared.c rename to arch/x86/pci/mmconfig-shared.c diff --git a/arch/i386/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c similarity index 100% rename from arch/i386/pci/mmconfig_32.c rename to arch/x86/pci/mmconfig_32.c diff --git a/arch/i386/pci/numa.c b/arch/x86/pci/numa.c similarity index 100% rename from arch/i386/pci/numa.c rename to arch/x86/pci/numa.c diff --git a/arch/i386/pci/pcbios.c b/arch/x86/pci/pcbios.c similarity index 100% rename from arch/i386/pci/pcbios.c rename to arch/x86/pci/pcbios.c diff --git a/arch/i386/pci/pci.h b/arch/x86/pci/pci.h similarity index 100% rename from arch/i386/pci/pci.h rename to arch/x86/pci/pci.h diff --git a/arch/i386/pci/visws.c b/arch/x86/pci/visws.c similarity index 100% rename from arch/i386/pci/visws.c rename to arch/x86/pci/visws.c diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile index d04d8f976d1c..b3e54c45d408 100644 --- a/arch/x86_64/pci/Makefile +++ b/arch/x86_64/pci/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/pci/Makefile_32 +include ${srctree}/arch/x86/pci/Makefile_32 else include ${srctree}/arch/x86_64/pci/Makefile_64 endif diff --git a/arch/x86_64/pci/Makefile_64 b/arch/x86_64/pci/Makefile_64 index 77b1b9abedc2..79b618b9e9d4 100644 --- a/arch/x86_64/pci/Makefile_64 +++ b/arch/x86_64/pci/Makefile_64 @@ -3,7 +3,7 @@ # # Reuse the i386 PCI subsystem # -EXTRA_CFLAGS += -Iarch/i386/pci +EXTRA_CFLAGS += -Iarch/x86/pci obj-y := i386.o obj-$(CONFIG_PCI_DIRECT)+= direct.o @@ -15,13 +15,13 @@ obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o obj-$(CONFIG_NUMA) += k8-bus_64.o -direct-y += ../../i386/pci/direct.o -acpi-y += ../../i386/pci/acpi.o -legacy-y += ../../i386/pci/legacy.o -irq-y += ../../i386/pci/irq.o -common-y += ../../i386/pci/common.o -fixup-y += ../../i386/pci/fixup.o -i386-y += ../../i386/pci/i386.o -init-y += ../../i386/pci/init.o -early-y += ../../i386/pci/early.o -mmconfig-shared-y += ../../i386/pci/mmconfig-shared.o +direct-y += ../../x86/pci/direct.o +acpi-y += ../../x86/pci/acpi.o +legacy-y += ../../x86/pci/legacy.o +irq-y += ../../x86/pci/irq.o +common-y += ../../x86/pci/common.o +fixup-y += ../../x86/pci/fixup.o +i386-y += ../../x86/pci/i386.o +init-y += ../../x86/pci/init.o +early-y += ../../x86/pci/early.o +mmconfig-shared-y += ../../x86/pci/mmconfig-shared.o diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index d590a99930fa..2305cc450a45 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -45,7 +45,7 @@ #include "cpqphp.h" #include "cpqphp_nvram.h" -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ +#include "../../../arch/x86/pci/pci.h" /* horrible hack showing how processor dependent we are... */ /* Global variables */ diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index fc7c74d72595..3f6cd20e95d2 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -37,7 +37,7 @@ #include "../pci.h" #include "cpqphp.h" #include "cpqphp_nvram.h" -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ +#include "../../../arch/x86/pci/pci.h" /* horrible hack showing how processor dependent we are... */ u8 cpqhp_nic_irq; diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 0316eeaaeb29..a90c28d0c69d 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -35,7 +35,7 @@ #include #include #include "../pci.h" -#include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */ +#include "../../../arch/x86/pci/pci.h" /* for struct irq_routing_table */ #include "ibmphp.h" #define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) From c2b84d8d1a66a0a886de51f1bfef5c4f16c0c784 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:38 +0200 Subject: [PATCH 2085/2804] i386: move mach-visws Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/mach-visws/Makefile | 0 arch/{i386 => x86}/mach-visws/mpparse.c | 0 arch/{i386 => x86}/mach-visws/reboot.c | 0 arch/{i386 => x86}/mach-visws/setup.c | 0 arch/{i386 => x86}/mach-visws/traps.c | 0 arch/{i386 => x86}/mach-visws/visws_apic.c | 0 7 files changed, 1 insertion(+), 1 deletion(-) rename arch/{i386 => x86}/mach-visws/Makefile (100%) rename arch/{i386 => x86}/mach-visws/mpparse.c (100%) rename arch/{i386 => x86}/mach-visws/reboot.c (100%) rename arch/{i386 => x86}/mach-visws/setup.c (100%) rename arch/{i386 => x86}/mach-visws/traps.c (100%) rename arch/{i386 => x86}/mach-visws/visws_apic.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 87c959d5f354..191e171b3672 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -69,7 +69,7 @@ mcore-$(CONFIG_X86_VOYAGER) := arch/i386/mach-voyager # VISWS subarch support mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-i386/mach-visws -mcore-$(CONFIG_X86_VISWS) := arch/i386/mach-visws +mcore-$(CONFIG_X86_VISWS) := arch/x86/mach-visws # NUMAQ subarch support mflags-$(CONFIG_X86_NUMAQ) := -Iinclude/asm-i386/mach-numaq diff --git a/arch/i386/mach-visws/Makefile b/arch/x86/mach-visws/Makefile similarity index 100% rename from arch/i386/mach-visws/Makefile rename to arch/x86/mach-visws/Makefile diff --git a/arch/i386/mach-visws/mpparse.c b/arch/x86/mach-visws/mpparse.c similarity index 100% rename from arch/i386/mach-visws/mpparse.c rename to arch/x86/mach-visws/mpparse.c diff --git a/arch/i386/mach-visws/reboot.c b/arch/x86/mach-visws/reboot.c similarity index 100% rename from arch/i386/mach-visws/reboot.c rename to arch/x86/mach-visws/reboot.c diff --git a/arch/i386/mach-visws/setup.c b/arch/x86/mach-visws/setup.c similarity index 100% rename from arch/i386/mach-visws/setup.c rename to arch/x86/mach-visws/setup.c diff --git a/arch/i386/mach-visws/traps.c b/arch/x86/mach-visws/traps.c similarity index 100% rename from arch/i386/mach-visws/traps.c rename to arch/x86/mach-visws/traps.c diff --git a/arch/i386/mach-visws/visws_apic.c b/arch/x86/mach-visws/visws_apic.c similarity index 100% rename from arch/i386/mach-visws/visws_apic.c rename to arch/x86/mach-visws/visws_apic.c From c750a66b0ebfcd8f4cb353ab37b286c8cd93ad10 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:39 +0200 Subject: [PATCH 2086/2804] i386: move mach-generic Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/mach-generic/Makefile | 0 arch/{i386 => x86}/mach-generic/bigsmp.c | 0 arch/{i386 => x86}/mach-generic/default.c | 0 arch/{i386 => x86}/mach-generic/es7000.c | 0 arch/{i386 => x86}/mach-generic/probe.c | 0 arch/{i386 => x86}/mach-generic/summit.c | 0 7 files changed, 1 insertion(+), 1 deletion(-) rename arch/{i386 => x86}/mach-generic/Makefile (100%) rename arch/{i386 => x86}/mach-generic/bigsmp.c (100%) rename arch/{i386 => x86}/mach-generic/default.c (100%) rename arch/{i386 => x86}/mach-generic/es7000.c (100%) rename arch/{i386 => x86}/mach-generic/probe.c (100%) rename arch/{i386 => x86}/mach-generic/summit.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 191e171b3672..510df782f940 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -86,7 +86,7 @@ mcore-$(CONFIG_X86_SUMMIT) := arch/i386/mach-default # generic subarchitecture mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic mcore-$(CONFIG_X86_GENERICARCH) := arch/i386/mach-default -core-$(CONFIG_X86_GENERICARCH) += arch/i386/mach-generic/ +core-$(CONFIG_X86_GENERICARCH) += arch/x86/mach-generic/ # ES7000 subarch support mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-i386/mach-es7000 diff --git a/arch/i386/mach-generic/Makefile b/arch/x86/mach-generic/Makefile similarity index 100% rename from arch/i386/mach-generic/Makefile rename to arch/x86/mach-generic/Makefile diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/x86/mach-generic/bigsmp.c similarity index 100% rename from arch/i386/mach-generic/bigsmp.c rename to arch/x86/mach-generic/bigsmp.c diff --git a/arch/i386/mach-generic/default.c b/arch/x86/mach-generic/default.c similarity index 100% rename from arch/i386/mach-generic/default.c rename to arch/x86/mach-generic/default.c diff --git a/arch/i386/mach-generic/es7000.c b/arch/x86/mach-generic/es7000.c similarity index 100% rename from arch/i386/mach-generic/es7000.c rename to arch/x86/mach-generic/es7000.c diff --git a/arch/i386/mach-generic/probe.c b/arch/x86/mach-generic/probe.c similarity index 100% rename from arch/i386/mach-generic/probe.c rename to arch/x86/mach-generic/probe.c diff --git a/arch/i386/mach-generic/summit.c b/arch/x86/mach-generic/summit.c similarity index 100% rename from arch/i386/mach-generic/summit.c rename to arch/x86/mach-generic/summit.c From 19d8d79ccfd2fb67b1eb86e3c634a2e68a4c4b11 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:41 +0200 Subject: [PATCH 2087/2804] i386: move boot Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/{i386 => x86}/boot/tools/.gitignore | 0 arch/{i386 => x86}/boot/tools/build.c | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename arch/{i386 => x86}/boot/tools/.gitignore (100%) rename arch/{i386 => x86}/boot/tools/build.c (100%) diff --git a/arch/i386/boot/tools/.gitignore b/arch/x86/boot/tools/.gitignore similarity index 100% rename from arch/i386/boot/tools/.gitignore rename to arch/x86/boot/tools/.gitignore diff --git a/arch/i386/boot/tools/build.c b/arch/x86/boot/tools/build.c similarity index 100% rename from arch/i386/boot/tools/build.c rename to arch/x86/boot/tools/build.c From 0530bf37cebcf22a73652937c2340bc1ebd92000 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:43 +0200 Subject: [PATCH 2088/2804] i386: move boot Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/{i386 => x86}/boot/compressed/.gitignore | 0 arch/{i386 => x86}/boot/compressed/Makefile | 2 +- arch/{i386 => x86}/boot/compressed/Makefile_32 | 2 +- arch/{i386 => x86}/boot/compressed/head_32.S | 0 arch/{i386 => x86}/boot/compressed/misc_32.c | 0 arch/{i386 => x86}/boot/compressed/relocs.c | 0 arch/{i386 => x86}/boot/compressed/vmlinux_32.lds | 0 arch/{i386 => x86}/boot/compressed/vmlinux_32.scr | 0 arch/x86_64/boot/compressed/Makefile | 2 +- 9 files changed, 3 insertions(+), 3 deletions(-) rename arch/{i386 => x86}/boot/compressed/.gitignore (100%) rename arch/{i386 => x86}/boot/compressed/Makefile (62%) rename arch/{i386 => x86}/boot/compressed/Makefile_32 (97%) rename arch/{i386 => x86}/boot/compressed/head_32.S (100%) rename arch/{i386 => x86}/boot/compressed/misc_32.c (100%) rename arch/{i386 => x86}/boot/compressed/relocs.c (100%) rename arch/{i386 => x86}/boot/compressed/vmlinux_32.lds (100%) rename arch/{i386 => x86}/boot/compressed/vmlinux_32.scr (100%) diff --git a/arch/i386/boot/compressed/.gitignore b/arch/x86/boot/compressed/.gitignore similarity index 100% rename from arch/i386/boot/compressed/.gitignore rename to arch/x86/boot/compressed/.gitignore diff --git a/arch/i386/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile similarity index 62% rename from arch/i386/boot/compressed/Makefile rename to arch/x86/boot/compressed/Makefile index 78514f3f626f..76ab5caddf9a 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/boot/compressed/Makefile_32 +include ${srctree}/arch/x86/boot/compressed/Makefile_32 else include ${srctree}/arch/x86_64/boot/compressed/Makefile_64 endif diff --git a/arch/i386/boot/compressed/Makefile_32 b/arch/x86/boot/compressed/Makefile_32 similarity index 97% rename from arch/i386/boot/compressed/Makefile_32 rename to arch/x86/boot/compressed/Makefile_32 index 0c64c314eadb..22613c652d22 100644 --- a/arch/i386/boot/compressed/Makefile_32 +++ b/arch/x86/boot/compressed/Makefile_32 @@ -1,5 +1,5 @@ # -# linux/arch/i386/boot/compressed/Makefile +# linux/arch/x86/boot/compressed/Makefile # # create a compressed vmlinux image from the original vmlinux # diff --git a/arch/i386/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S similarity index 100% rename from arch/i386/boot/compressed/head_32.S rename to arch/x86/boot/compressed/head_32.S diff --git a/arch/i386/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c similarity index 100% rename from arch/i386/boot/compressed/misc_32.c rename to arch/x86/boot/compressed/misc_32.c diff --git a/arch/i386/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c similarity index 100% rename from arch/i386/boot/compressed/relocs.c rename to arch/x86/boot/compressed/relocs.c diff --git a/arch/i386/boot/compressed/vmlinux_32.lds b/arch/x86/boot/compressed/vmlinux_32.lds similarity index 100% rename from arch/i386/boot/compressed/vmlinux_32.lds rename to arch/x86/boot/compressed/vmlinux_32.lds diff --git a/arch/i386/boot/compressed/vmlinux_32.scr b/arch/x86/boot/compressed/vmlinux_32.scr similarity index 100% rename from arch/i386/boot/compressed/vmlinux_32.scr rename to arch/x86/boot/compressed/vmlinux_32.scr diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile index 78514f3f626f..76ab5caddf9a 100644 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/boot/compressed/Makefile_32 +include ${srctree}/arch/x86/boot/compressed/Makefile_32 else include ${srctree}/arch/x86_64/boot/compressed/Makefile_64 endif From 96ae6ea0be1b902c28b3b463c27da42b41e2b63a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:45 +0200 Subject: [PATCH 2089/2804] i386: move boot Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 9 ++++++--- arch/{i386 => x86}/boot/.gitignore | 0 arch/{i386 => x86}/boot/Makefile | 2 +- arch/{i386 => x86}/boot/a20.c | 0 arch/{i386 => x86}/boot/apm.c | 0 arch/{i386 => x86}/boot/bitops.h | 0 arch/{i386 => x86}/boot/boot.h | 0 arch/{i386 => x86}/boot/cmdline.c | 0 arch/{i386 => x86}/boot/code16gcc.h | 0 arch/{i386 => x86}/boot/copy.S | 0 arch/{i386 => x86}/boot/cpu.c | 0 arch/{i386 => x86}/boot/cpucheck.c | 0 arch/{i386 => x86}/boot/edd.c | 0 arch/{i386 => x86}/boot/header.S | 0 arch/{i386 => x86}/boot/install.sh | 0 arch/{i386 => x86}/boot/main.c | 0 arch/{i386 => x86}/boot/mca.c | 0 arch/{i386 => x86}/boot/memory.c | 0 arch/{i386 => x86}/boot/mtools.conf.in | 0 arch/{i386 => x86}/boot/pm.c | 0 arch/{i386 => x86}/boot/pmjump.S | 0 arch/{i386 => x86}/boot/printf.c | 0 arch/{i386 => x86}/boot/setup.ld | 0 arch/{i386 => x86}/boot/string.c | 0 arch/{i386 => x86}/boot/tty.c | 0 arch/{i386 => x86}/boot/version.c | 0 arch/{i386 => x86}/boot/vesa.h | 0 arch/{i386 => x86}/boot/video-bios.c | 0 arch/{i386 => x86}/boot/video-vesa.c | 0 arch/{i386 => x86}/boot/video-vga.c | 0 arch/{i386 => x86}/boot/video.c | 0 arch/{i386 => x86}/boot/video.h | 0 arch/{i386 => x86}/boot/voyager.c | 0 arch/x86_64/boot/Makefile | 2 +- 34 files changed, 8 insertions(+), 5 deletions(-) rename arch/{i386 => x86}/boot/.gitignore (100%) rename arch/{i386 => x86}/boot/Makefile (99%) rename arch/{i386 => x86}/boot/a20.c (100%) rename arch/{i386 => x86}/boot/apm.c (100%) rename arch/{i386 => x86}/boot/bitops.h (100%) rename arch/{i386 => x86}/boot/boot.h (100%) rename arch/{i386 => x86}/boot/cmdline.c (100%) rename arch/{i386 => x86}/boot/code16gcc.h (100%) rename arch/{i386 => x86}/boot/copy.S (100%) rename arch/{i386 => x86}/boot/cpu.c (100%) rename arch/{i386 => x86}/boot/cpucheck.c (100%) rename arch/{i386 => x86}/boot/edd.c (100%) rename arch/{i386 => x86}/boot/header.S (100%) rename arch/{i386 => x86}/boot/install.sh (100%) rename arch/{i386 => x86}/boot/main.c (100%) rename arch/{i386 => x86}/boot/mca.c (100%) rename arch/{i386 => x86}/boot/memory.c (100%) rename arch/{i386 => x86}/boot/mtools.conf.in (100%) rename arch/{i386 => x86}/boot/pm.c (100%) rename arch/{i386 => x86}/boot/pmjump.S (100%) rename arch/{i386 => x86}/boot/printf.c (100%) rename arch/{i386 => x86}/boot/setup.ld (100%) rename arch/{i386 => x86}/boot/string.c (100%) rename arch/{i386 => x86}/boot/tty.c (100%) rename arch/{i386 => x86}/boot/version.c (100%) rename arch/{i386 => x86}/boot/vesa.h (100%) rename arch/{i386 => x86}/boot/video-bios.c (100%) rename arch/{i386 => x86}/boot/video-vesa.c (100%) rename arch/{i386 => x86}/boot/video-vga.c (100%) rename arch/{i386 => x86}/boot/video.c (100%) rename arch/{i386 => x86}/boot/video.h (100%) rename arch/{i386 => x86}/boot/voyager.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 510df782f940..776d8dcf2340 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -116,7 +116,7 @@ drivers-$(CONFIG_FB) += arch/i386/video/ CFLAGS += $(mflags-y) AFLAGS += $(mflags-y) -boot := arch/i386/boot +boot := arch/x86/boot PHONY += zImage bzImage compressed zlilo bzlilo \ zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install @@ -125,9 +125,11 @@ all: bzImage # KBUILD_IMAGE specify target image being built KBUILD_IMAGE := $(boot)/bzImage -zImage zlilo zdisk: KBUILD_IMAGE := arch/i386/boot/zImage +zImage zlilo zdisk: KBUILD_IMAGE := arch/x86/boot/zImage zImage bzImage: vmlinux + $(Q)mkdir -p $(objtree)/arch/i386/boot + $(Q)ln -fsn $(objtree)/arch/x86/boot/bzImage $(objtree)/arch/i386/boot/bzImage $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE) compressed: zImage @@ -145,7 +147,8 @@ install: $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install archclean: - $(Q)$(MAKE) $(clean)=arch/i386/boot + $(Q)rm -rf $(objtree)/arch/i386/boot + $(Q)$(MAKE) $(clean)=arch/x86/boot define archhelp echo '* bzImage - Compressed kernel image (arch/$(ARCH)/boot/bzImage)' diff --git a/arch/i386/boot/.gitignore b/arch/x86/boot/.gitignore similarity index 100% rename from arch/i386/boot/.gitignore rename to arch/x86/boot/.gitignore diff --git a/arch/i386/boot/Makefile b/arch/x86/boot/Makefile similarity index 99% rename from arch/i386/boot/Makefile rename to arch/x86/boot/Makefile index 93386a4e40b4..cb1035f2b7e9 100644 --- a/arch/i386/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -1,5 +1,5 @@ # -# arch/i386/boot/Makefile +# arch/x86/boot/Makefile # # 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 diff --git a/arch/i386/boot/a20.c b/arch/x86/boot/a20.c similarity index 100% rename from arch/i386/boot/a20.c rename to arch/x86/boot/a20.c diff --git a/arch/i386/boot/apm.c b/arch/x86/boot/apm.c similarity index 100% rename from arch/i386/boot/apm.c rename to arch/x86/boot/apm.c diff --git a/arch/i386/boot/bitops.h b/arch/x86/boot/bitops.h similarity index 100% rename from arch/i386/boot/bitops.h rename to arch/x86/boot/bitops.h diff --git a/arch/i386/boot/boot.h b/arch/x86/boot/boot.h similarity index 100% rename from arch/i386/boot/boot.h rename to arch/x86/boot/boot.h diff --git a/arch/i386/boot/cmdline.c b/arch/x86/boot/cmdline.c similarity index 100% rename from arch/i386/boot/cmdline.c rename to arch/x86/boot/cmdline.c diff --git a/arch/i386/boot/code16gcc.h b/arch/x86/boot/code16gcc.h similarity index 100% rename from arch/i386/boot/code16gcc.h rename to arch/x86/boot/code16gcc.h diff --git a/arch/i386/boot/copy.S b/arch/x86/boot/copy.S similarity index 100% rename from arch/i386/boot/copy.S rename to arch/x86/boot/copy.S diff --git a/arch/i386/boot/cpu.c b/arch/x86/boot/cpu.c similarity index 100% rename from arch/i386/boot/cpu.c rename to arch/x86/boot/cpu.c diff --git a/arch/i386/boot/cpucheck.c b/arch/x86/boot/cpucheck.c similarity index 100% rename from arch/i386/boot/cpucheck.c rename to arch/x86/boot/cpucheck.c diff --git a/arch/i386/boot/edd.c b/arch/x86/boot/edd.c similarity index 100% rename from arch/i386/boot/edd.c rename to arch/x86/boot/edd.c diff --git a/arch/i386/boot/header.S b/arch/x86/boot/header.S similarity index 100% rename from arch/i386/boot/header.S rename to arch/x86/boot/header.S diff --git a/arch/i386/boot/install.sh b/arch/x86/boot/install.sh similarity index 100% rename from arch/i386/boot/install.sh rename to arch/x86/boot/install.sh diff --git a/arch/i386/boot/main.c b/arch/x86/boot/main.c similarity index 100% rename from arch/i386/boot/main.c rename to arch/x86/boot/main.c diff --git a/arch/i386/boot/mca.c b/arch/x86/boot/mca.c similarity index 100% rename from arch/i386/boot/mca.c rename to arch/x86/boot/mca.c diff --git a/arch/i386/boot/memory.c b/arch/x86/boot/memory.c similarity index 100% rename from arch/i386/boot/memory.c rename to arch/x86/boot/memory.c diff --git a/arch/i386/boot/mtools.conf.in b/arch/x86/boot/mtools.conf.in similarity index 100% rename from arch/i386/boot/mtools.conf.in rename to arch/x86/boot/mtools.conf.in diff --git a/arch/i386/boot/pm.c b/arch/x86/boot/pm.c similarity index 100% rename from arch/i386/boot/pm.c rename to arch/x86/boot/pm.c diff --git a/arch/i386/boot/pmjump.S b/arch/x86/boot/pmjump.S similarity index 100% rename from arch/i386/boot/pmjump.S rename to arch/x86/boot/pmjump.S diff --git a/arch/i386/boot/printf.c b/arch/x86/boot/printf.c similarity index 100% rename from arch/i386/boot/printf.c rename to arch/x86/boot/printf.c diff --git a/arch/i386/boot/setup.ld b/arch/x86/boot/setup.ld similarity index 100% rename from arch/i386/boot/setup.ld rename to arch/x86/boot/setup.ld diff --git a/arch/i386/boot/string.c b/arch/x86/boot/string.c similarity index 100% rename from arch/i386/boot/string.c rename to arch/x86/boot/string.c diff --git a/arch/i386/boot/tty.c b/arch/x86/boot/tty.c similarity index 100% rename from arch/i386/boot/tty.c rename to arch/x86/boot/tty.c diff --git a/arch/i386/boot/version.c b/arch/x86/boot/version.c similarity index 100% rename from arch/i386/boot/version.c rename to arch/x86/boot/version.c diff --git a/arch/i386/boot/vesa.h b/arch/x86/boot/vesa.h similarity index 100% rename from arch/i386/boot/vesa.h rename to arch/x86/boot/vesa.h diff --git a/arch/i386/boot/video-bios.c b/arch/x86/boot/video-bios.c similarity index 100% rename from arch/i386/boot/video-bios.c rename to arch/x86/boot/video-bios.c diff --git a/arch/i386/boot/video-vesa.c b/arch/x86/boot/video-vesa.c similarity index 100% rename from arch/i386/boot/video-vesa.c rename to arch/x86/boot/video-vesa.c diff --git a/arch/i386/boot/video-vga.c b/arch/x86/boot/video-vga.c similarity index 100% rename from arch/i386/boot/video-vga.c rename to arch/x86/boot/video-vga.c diff --git a/arch/i386/boot/video.c b/arch/x86/boot/video.c similarity index 100% rename from arch/i386/boot/video.c rename to arch/x86/boot/video.c diff --git a/arch/i386/boot/video.h b/arch/x86/boot/video.h similarity index 100% rename from arch/i386/boot/video.h rename to arch/x86/boot/video.h diff --git a/arch/i386/boot/voyager.c b/arch/x86/boot/voyager.c similarity index 100% rename from arch/i386/boot/voyager.c rename to arch/x86/boot/voyager.c diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile index 67096389de1f..0f7b6c2cfa58 100644 --- a/arch/x86_64/boot/Makefile +++ b/arch/x86_64/boot/Makefile @@ -5,5 +5,5 @@ # So tell kbuild that we fetch the code from i386 and include the # Makefile from i386 too. -src := arch/i386/boot +src := arch/x86/boot include $(src)/Makefile From ad757b6aa5801b81dec609d87753604a06313c53 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:47 +0200 Subject: [PATCH 2090/2804] i386: move mm Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/mm/Makefile | 2 +- arch/{i386 => x86}/mm/Makefile_32 | 0 arch/{i386 => x86}/mm/boot_ioremap_32.c | 0 arch/{i386 => x86}/mm/discontig_32.c | 0 arch/{i386 => x86}/mm/extable_32.c | 0 arch/{i386 => x86}/mm/fault_32.c | 0 arch/{i386 => x86}/mm/highmem_32.c | 0 arch/{i386 => x86}/mm/hugetlbpage.c | 0 arch/{i386 => x86}/mm/init_32.c | 0 arch/{i386 => x86}/mm/ioremap_32.c | 0 arch/{i386 => x86}/mm/mmap_32.c | 0 arch/{i386 => x86}/mm/pageattr_32.c | 0 arch/{i386 => x86}/mm/pgtable_32.c | 0 arch/x86_64/mm/Makefile | 2 +- arch/x86_64/mm/Makefile_64 | 2 +- 16 files changed, 4 insertions(+), 4 deletions(-) rename arch/{i386 => x86}/mm/Makefile (65%) rename arch/{i386 => x86}/mm/Makefile_32 (100%) rename arch/{i386 => x86}/mm/boot_ioremap_32.c (100%) rename arch/{i386 => x86}/mm/discontig_32.c (100%) rename arch/{i386 => x86}/mm/extable_32.c (100%) rename arch/{i386 => x86}/mm/fault_32.c (100%) rename arch/{i386 => x86}/mm/highmem_32.c (100%) rename arch/{i386 => x86}/mm/hugetlbpage.c (100%) rename arch/{i386 => x86}/mm/init_32.c (100%) rename arch/{i386 => x86}/mm/ioremap_32.c (100%) rename arch/{i386 => x86}/mm/mmap_32.c (100%) rename arch/{i386 => x86}/mm/pageattr_32.c (100%) rename arch/{i386 => x86}/mm/pgtable_32.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 776d8dcf2340..cbdc14fddc3a 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -103,7 +103,7 @@ head-y := arch/i386/kernel/head_32.o arch/i386/kernel/init_task_32.o libs-y += arch/x86/lib/ core-y += arch/i386/kernel/ \ - arch/i386/mm/ \ + arch/x86/mm/ \ $(mcore-y)/ \ arch/x86/crypto/ drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ diff --git a/arch/i386/mm/Makefile b/arch/x86/mm/Makefile similarity index 65% rename from arch/i386/mm/Makefile rename to arch/x86/mm/Makefile index 4042f8563a16..7317648e6587 100644 --- a/arch/i386/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/mm/Makefile_32 +include ${srctree}/arch/x86/mm/Makefile_32 else include ${srctree}/arch/x86_64/mm/Makefile_64 endif diff --git a/arch/i386/mm/Makefile_32 b/arch/x86/mm/Makefile_32 similarity index 100% rename from arch/i386/mm/Makefile_32 rename to arch/x86/mm/Makefile_32 diff --git a/arch/i386/mm/boot_ioremap_32.c b/arch/x86/mm/boot_ioremap_32.c similarity index 100% rename from arch/i386/mm/boot_ioremap_32.c rename to arch/x86/mm/boot_ioremap_32.c diff --git a/arch/i386/mm/discontig_32.c b/arch/x86/mm/discontig_32.c similarity index 100% rename from arch/i386/mm/discontig_32.c rename to arch/x86/mm/discontig_32.c diff --git a/arch/i386/mm/extable_32.c b/arch/x86/mm/extable_32.c similarity index 100% rename from arch/i386/mm/extable_32.c rename to arch/x86/mm/extable_32.c diff --git a/arch/i386/mm/fault_32.c b/arch/x86/mm/fault_32.c similarity index 100% rename from arch/i386/mm/fault_32.c rename to arch/x86/mm/fault_32.c diff --git a/arch/i386/mm/highmem_32.c b/arch/x86/mm/highmem_32.c similarity index 100% rename from arch/i386/mm/highmem_32.c rename to arch/x86/mm/highmem_32.c diff --git a/arch/i386/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c similarity index 100% rename from arch/i386/mm/hugetlbpage.c rename to arch/x86/mm/hugetlbpage.c diff --git a/arch/i386/mm/init_32.c b/arch/x86/mm/init_32.c similarity index 100% rename from arch/i386/mm/init_32.c rename to arch/x86/mm/init_32.c diff --git a/arch/i386/mm/ioremap_32.c b/arch/x86/mm/ioremap_32.c similarity index 100% rename from arch/i386/mm/ioremap_32.c rename to arch/x86/mm/ioremap_32.c diff --git a/arch/i386/mm/mmap_32.c b/arch/x86/mm/mmap_32.c similarity index 100% rename from arch/i386/mm/mmap_32.c rename to arch/x86/mm/mmap_32.c diff --git a/arch/i386/mm/pageattr_32.c b/arch/x86/mm/pageattr_32.c similarity index 100% rename from arch/i386/mm/pageattr_32.c rename to arch/x86/mm/pageattr_32.c diff --git a/arch/i386/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c similarity index 100% rename from arch/i386/mm/pgtable_32.c rename to arch/x86/mm/pgtable_32.c diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile index 4042f8563a16..7317648e6587 100644 --- a/arch/x86_64/mm/Makefile +++ b/arch/x86_64/mm/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/mm/Makefile_32 +include ${srctree}/arch/x86/mm/Makefile_32 else include ${srctree}/arch/x86_64/mm/Makefile_64 endif diff --git a/arch/x86_64/mm/Makefile_64 b/arch/x86_64/mm/Makefile_64 index 2e209885fce6..5c2883cad11b 100644 --- a/arch/x86_64/mm/Makefile_64 +++ b/arch/x86_64/mm/Makefile_64 @@ -8,4 +8,4 @@ obj-$(CONFIG_NUMA) += numa_64.o obj-$(CONFIG_K8_NUMA) += k8topology_64.o obj-$(CONFIG_ACPI_NUMA) += srat_64.o -hugetlbpage-y = ../../i386/mm/hugetlbpage.o +hugetlbpage-y = ../../x86/mm/hugetlbpage.o From d629e03b64c469245ceb07d05460e1e2eefa7585 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:48 +0200 Subject: [PATCH 2091/2804] i386: move mach-default Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 12 ++++++------ arch/{i386 => x86}/mach-default/Makefile | 0 arch/{i386 => x86}/mach-default/setup.c | 0 3 files changed, 6 insertions(+), 6 deletions(-) rename arch/{i386 => x86}/mach-default/Makefile (100%) rename arch/{i386 => x86}/mach-default/setup.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index cbdc14fddc3a..223c5e252ec1 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -61,7 +61,7 @@ AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONF CFLAGS += $(cflags-y) # Default subarch .c files -mcore-y := arch/i386/mach-default +mcore-y := arch/x86/mach-default # Voyager subarch support mflags-$(CONFIG_X86_VOYAGER) := -Iinclude/asm-i386/mach-voyager @@ -73,24 +73,24 @@ mcore-$(CONFIG_X86_VISWS) := arch/x86/mach-visws # NUMAQ subarch support mflags-$(CONFIG_X86_NUMAQ) := -Iinclude/asm-i386/mach-numaq -mcore-$(CONFIG_X86_NUMAQ) := arch/i386/mach-default +mcore-$(CONFIG_X86_NUMAQ) := arch/x86/mach-default # BIGSMP subarch support mflags-$(CONFIG_X86_BIGSMP) := -Iinclude/asm-i386/mach-bigsmp -mcore-$(CONFIG_X86_BIGSMP) := arch/i386/mach-default +mcore-$(CONFIG_X86_BIGSMP) := arch/x86/mach-default #Summit subarch support mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit -mcore-$(CONFIG_X86_SUMMIT) := arch/i386/mach-default +mcore-$(CONFIG_X86_SUMMIT) := arch/x86/mach-default # generic subarchitecture mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic -mcore-$(CONFIG_X86_GENERICARCH) := arch/i386/mach-default +mcore-$(CONFIG_X86_GENERICARCH) := arch/x86/mach-default core-$(CONFIG_X86_GENERICARCH) += arch/x86/mach-generic/ # ES7000 subarch support mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-i386/mach-es7000 -mcore-$(CONFIG_X86_ES7000) := arch/i386/mach-default +mcore-$(CONFIG_X86_ES7000) := arch/x86/mach-default core-$(CONFIG_X86_ES7000) := arch/i386/mach-es7000/ # Xen paravirtualization support diff --git a/arch/i386/mach-default/Makefile b/arch/x86/mach-default/Makefile similarity index 100% rename from arch/i386/mach-default/Makefile rename to arch/x86/mach-default/Makefile diff --git a/arch/i386/mach-default/setup.c b/arch/x86/mach-default/setup.c similarity index 100% rename from arch/i386/mach-default/setup.c rename to arch/x86/mach-default/setup.c From 334e621a01f86d5bc25e4f742e1eaae6e2d2a97a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:50 +0200 Subject: [PATCH 2092/2804] i386: move mach-es7000 Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/mach-es7000/Makefile | 0 arch/{i386 => x86}/mach-es7000/es7000.h | 0 arch/{i386 => x86}/mach-es7000/es7000plat.c | 0 arch/x86/mach-generic/Makefile | 2 +- 5 files changed, 2 insertions(+), 2 deletions(-) rename arch/{i386 => x86}/mach-es7000/Makefile (100%) rename arch/{i386 => x86}/mach-es7000/es7000.h (100%) rename arch/{i386 => x86}/mach-es7000/es7000plat.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 223c5e252ec1..c462803a4db2 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -91,7 +91,7 @@ core-$(CONFIG_X86_GENERICARCH) += arch/x86/mach-generic/ # ES7000 subarch support mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-i386/mach-es7000 mcore-$(CONFIG_X86_ES7000) := arch/x86/mach-default -core-$(CONFIG_X86_ES7000) := arch/i386/mach-es7000/ +core-$(CONFIG_X86_ES7000) := arch/x86/mach-es7000/ # Xen paravirtualization support core-$(CONFIG_XEN) += arch/i386/xen/ diff --git a/arch/i386/mach-es7000/Makefile b/arch/x86/mach-es7000/Makefile similarity index 100% rename from arch/i386/mach-es7000/Makefile rename to arch/x86/mach-es7000/Makefile diff --git a/arch/i386/mach-es7000/es7000.h b/arch/x86/mach-es7000/es7000.h similarity index 100% rename from arch/i386/mach-es7000/es7000.h rename to arch/x86/mach-es7000/es7000.h diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/x86/mach-es7000/es7000plat.c similarity index 100% rename from arch/i386/mach-es7000/es7000plat.c rename to arch/x86/mach-es7000/es7000plat.c diff --git a/arch/x86/mach-generic/Makefile b/arch/x86/mach-generic/Makefile index 2f216f55b2dd..08f489a7f1f5 100644 --- a/arch/x86/mach-generic/Makefile +++ b/arch/x86/mach-generic/Makefile @@ -5,4 +5,4 @@ EXTRA_CFLAGS := -Iarch/i386/kernel obj-y := probe.o summit.o bigsmp.o es7000.o default.o -obj-y += ../../i386/mach-es7000/ +obj-y += ../../x86/mach-es7000/ From 9702785a747aa27baf46ff504beab6528f21f2dd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:51 +0200 Subject: [PATCH 2093/2804] i386: move xen Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Kconfig | 2 +- arch/i386/Makefile | 2 +- arch/i386/kernel/head_32.S | 2 +- arch/i386/kernel/vsyscall-note_32.S | 2 +- arch/{i386 => x86}/xen/Kconfig | 0 arch/{i386 => x86}/xen/Makefile | 0 arch/{i386 => x86}/xen/enlighten.c | 0 arch/{i386 => x86}/xen/events.c | 0 arch/{i386 => x86}/xen/features.c | 0 arch/{i386 => x86}/xen/manage.c | 0 arch/{i386 => x86}/xen/mmu.c | 0 arch/{i386 => x86}/xen/mmu.h | 0 arch/{i386 => x86}/xen/multicalls.c | 0 arch/{i386 => x86}/xen/multicalls.h | 0 arch/{i386 => x86}/xen/setup.c | 0 arch/{i386 => x86}/xen/smp.c | 0 arch/{i386 => x86}/xen/time.c | 0 arch/{i386 => x86}/xen/vdso.h | 0 arch/{i386 => x86}/xen/xen-asm.S | 0 arch/{i386 => x86}/xen/xen-head.S | 0 arch/{i386 => x86}/xen/xen-ops.h | 0 21 files changed, 4 insertions(+), 4 deletions(-) rename arch/{i386 => x86}/xen/Kconfig (100%) rename arch/{i386 => x86}/xen/Makefile (100%) rename arch/{i386 => x86}/xen/enlighten.c (100%) rename arch/{i386 => x86}/xen/events.c (100%) rename arch/{i386 => x86}/xen/features.c (100%) rename arch/{i386 => x86}/xen/manage.c (100%) rename arch/{i386 => x86}/xen/mmu.c (100%) rename arch/{i386 => x86}/xen/mmu.h (100%) rename arch/{i386 => x86}/xen/multicalls.c (100%) rename arch/{i386 => x86}/xen/multicalls.h (100%) rename arch/{i386 => x86}/xen/setup.c (100%) rename arch/{i386 => x86}/xen/smp.c (100%) rename arch/{i386 => x86}/xen/time.c (100%) rename arch/{i386 => x86}/xen/vdso.h (100%) rename arch/{i386 => x86}/xen/xen-asm.S (100%) rename arch/{i386 => x86}/xen/xen-head.S (100%) rename arch/{i386 => x86}/xen/xen-ops.h (100%) diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 561cc21914b2..0f6186f03034 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -226,7 +226,7 @@ config PARAVIRT However, when run without a hypervisor the kernel is theoretically slower. If in doubt, say N. -source "arch/i386/xen/Kconfig" +source "arch/x86/xen/Kconfig" config VMI bool "VMI Paravirt-ops support" diff --git a/arch/i386/Makefile b/arch/i386/Makefile index c462803a4db2..fc85d6674fcb 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -94,7 +94,7 @@ mcore-$(CONFIG_X86_ES7000) := arch/x86/mach-default core-$(CONFIG_X86_ES7000) := arch/x86/mach-es7000/ # Xen paravirtualization support -core-$(CONFIG_XEN) += arch/i386/xen/ +core-$(CONFIG_XEN) += arch/x86/xen/ # default subarch .h files mflags-y += -Iinclude/asm-i386/mach-default diff --git a/arch/i386/kernel/head_32.S b/arch/i386/kernel/head_32.S index 8f0382161c91..9150ca9b5f80 100644 --- a/arch/i386/kernel/head_32.S +++ b/arch/i386/kernel/head_32.S @@ -537,7 +537,7 @@ fault_msg: .ascii "Int %d: CR2 %p err %p EIP %p CS %p flags %p\n" .asciz "Stack: %p %p %p %p %p %p %p %p\n" -#include "../xen/xen-head.S" +#include "../../x86/xen/xen-head.S" /* * The IDT and GDT 'descriptors' are a strange 48-bit object diff --git a/arch/i386/kernel/vsyscall-note_32.S b/arch/i386/kernel/vsyscall-note_32.S index 07c0daf78237..fcf376a37f79 100644 --- a/arch/i386/kernel/vsyscall-note_32.S +++ b/arch/i386/kernel/vsyscall-note_32.S @@ -33,7 +33,7 @@ ELFNOTE_END * at boot time we set VDSO_NOTE_NONEGSEG_BIT if running under Xen. */ -#include "../xen/vdso.h" /* Defines VDSO_NOTE_NONEGSEG_BIT. */ +#include "../../x86/xen/vdso.h" /* Defines VDSO_NOTE_NONEGSEG_BIT. */ .globl VDSO_NOTE_MASK ELFNOTE_START(GNU, 2, "a") diff --git a/arch/i386/xen/Kconfig b/arch/x86/xen/Kconfig similarity index 100% rename from arch/i386/xen/Kconfig rename to arch/x86/xen/Kconfig diff --git a/arch/i386/xen/Makefile b/arch/x86/xen/Makefile similarity index 100% rename from arch/i386/xen/Makefile rename to arch/x86/xen/Makefile diff --git a/arch/i386/xen/enlighten.c b/arch/x86/xen/enlighten.c similarity index 100% rename from arch/i386/xen/enlighten.c rename to arch/x86/xen/enlighten.c diff --git a/arch/i386/xen/events.c b/arch/x86/xen/events.c similarity index 100% rename from arch/i386/xen/events.c rename to arch/x86/xen/events.c diff --git a/arch/i386/xen/features.c b/arch/x86/xen/features.c similarity index 100% rename from arch/i386/xen/features.c rename to arch/x86/xen/features.c diff --git a/arch/i386/xen/manage.c b/arch/x86/xen/manage.c similarity index 100% rename from arch/i386/xen/manage.c rename to arch/x86/xen/manage.c diff --git a/arch/i386/xen/mmu.c b/arch/x86/xen/mmu.c similarity index 100% rename from arch/i386/xen/mmu.c rename to arch/x86/xen/mmu.c diff --git a/arch/i386/xen/mmu.h b/arch/x86/xen/mmu.h similarity index 100% rename from arch/i386/xen/mmu.h rename to arch/x86/xen/mmu.h diff --git a/arch/i386/xen/multicalls.c b/arch/x86/xen/multicalls.c similarity index 100% rename from arch/i386/xen/multicalls.c rename to arch/x86/xen/multicalls.c diff --git a/arch/i386/xen/multicalls.h b/arch/x86/xen/multicalls.h similarity index 100% rename from arch/i386/xen/multicalls.h rename to arch/x86/xen/multicalls.h diff --git a/arch/i386/xen/setup.c b/arch/x86/xen/setup.c similarity index 100% rename from arch/i386/xen/setup.c rename to arch/x86/xen/setup.c diff --git a/arch/i386/xen/smp.c b/arch/x86/xen/smp.c similarity index 100% rename from arch/i386/xen/smp.c rename to arch/x86/xen/smp.c diff --git a/arch/i386/xen/time.c b/arch/x86/xen/time.c similarity index 100% rename from arch/i386/xen/time.c rename to arch/x86/xen/time.c diff --git a/arch/i386/xen/vdso.h b/arch/x86/xen/vdso.h similarity index 100% rename from arch/i386/xen/vdso.h rename to arch/x86/xen/vdso.h diff --git a/arch/i386/xen/xen-asm.S b/arch/x86/xen/xen-asm.S similarity index 100% rename from arch/i386/xen/xen-asm.S rename to arch/x86/xen/xen-asm.S diff --git a/arch/i386/xen/xen-head.S b/arch/x86/xen/xen-head.S similarity index 100% rename from arch/i386/xen/xen-head.S rename to arch/x86/xen/xen-head.S diff --git a/arch/i386/xen/xen-ops.h b/arch/x86/xen/xen-ops.h similarity index 100% rename from arch/i386/xen/xen-ops.h rename to arch/x86/xen/xen-ops.h From 9402e12b8fef1efe9cf949fc020dcda22d9d8667 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:53 +0200 Subject: [PATCH 2094/2804] i386: move mach-voyager Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/mach-voyager/Makefile | 0 arch/{i386 => x86}/mach-voyager/setup.c | 0 arch/{i386 => x86}/mach-voyager/voyager_basic.c | 0 arch/{i386 => x86}/mach-voyager/voyager_cat.c | 0 arch/{i386 => x86}/mach-voyager/voyager_smp.c | 0 arch/{i386 => x86}/mach-voyager/voyager_thread.c | 0 7 files changed, 1 insertion(+), 1 deletion(-) rename arch/{i386 => x86}/mach-voyager/Makefile (100%) rename arch/{i386 => x86}/mach-voyager/setup.c (100%) rename arch/{i386 => x86}/mach-voyager/voyager_basic.c (100%) rename arch/{i386 => x86}/mach-voyager/voyager_cat.c (100%) rename arch/{i386 => x86}/mach-voyager/voyager_smp.c (100%) rename arch/{i386 => x86}/mach-voyager/voyager_thread.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index fc85d6674fcb..e03c47e56c76 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -65,7 +65,7 @@ mcore-y := arch/x86/mach-default # Voyager subarch support mflags-$(CONFIG_X86_VOYAGER) := -Iinclude/asm-i386/mach-voyager -mcore-$(CONFIG_X86_VOYAGER) := arch/i386/mach-voyager +mcore-$(CONFIG_X86_VOYAGER) := arch/x86/mach-voyager # VISWS subarch support mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-i386/mach-visws diff --git a/arch/i386/mach-voyager/Makefile b/arch/x86/mach-voyager/Makefile similarity index 100% rename from arch/i386/mach-voyager/Makefile rename to arch/x86/mach-voyager/Makefile diff --git a/arch/i386/mach-voyager/setup.c b/arch/x86/mach-voyager/setup.c similarity index 100% rename from arch/i386/mach-voyager/setup.c rename to arch/x86/mach-voyager/setup.c diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/x86/mach-voyager/voyager_basic.c similarity index 100% rename from arch/i386/mach-voyager/voyager_basic.c rename to arch/x86/mach-voyager/voyager_basic.c diff --git a/arch/i386/mach-voyager/voyager_cat.c b/arch/x86/mach-voyager/voyager_cat.c similarity index 100% rename from arch/i386/mach-voyager/voyager_cat.c rename to arch/x86/mach-voyager/voyager_cat.c diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c similarity index 100% rename from arch/i386/mach-voyager/voyager_smp.c rename to arch/x86/mach-voyager/voyager_smp.c diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/x86/mach-voyager/voyager_thread.c similarity index 100% rename from arch/i386/mach-voyager/voyager_thread.c rename to arch/x86/mach-voyager/voyager_thread.c From ff4395654dc6a3a5e35611940047114d4f3d0a7a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:55 +0200 Subject: [PATCH 2095/2804] i386: move oprofile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Kconfig | 2 +- arch/i386/Makefile | 2 +- arch/{i386 => x86}/oprofile/Kconfig | 0 arch/{i386 => x86}/oprofile/Makefile | 0 arch/{i386 => x86}/oprofile/backtrace.c | 0 arch/{i386 => x86}/oprofile/init.c | 0 arch/{i386 => x86}/oprofile/nmi_int.c | 0 arch/{i386 => x86}/oprofile/nmi_timer_int.c | 0 arch/{i386 => x86}/oprofile/op_counter.h | 0 arch/{i386 => x86}/oprofile/op_model_athlon.c | 0 arch/{i386 => x86}/oprofile/op_model_p4.c | 0 arch/{i386 => x86}/oprofile/op_model_ppro.c | 0 arch/{i386 => x86}/oprofile/op_x86_model.h | 0 arch/x86_64/Makefile | 2 +- 14 files changed, 3 insertions(+), 3 deletions(-) rename arch/{i386 => x86}/oprofile/Kconfig (100%) rename arch/{i386 => x86}/oprofile/Makefile (100%) rename arch/{i386 => x86}/oprofile/backtrace.c (100%) rename arch/{i386 => x86}/oprofile/init.c (100%) rename arch/{i386 => x86}/oprofile/nmi_int.c (100%) rename arch/{i386 => x86}/oprofile/nmi_timer_int.c (100%) rename arch/{i386 => x86}/oprofile/op_counter.h (100%) rename arch/{i386 => x86}/oprofile/op_model_athlon.c (100%) rename arch/{i386 => x86}/oprofile/op_model_p4.c (100%) rename arch/{i386 => x86}/oprofile/op_model_ppro.c (100%) rename arch/{i386 => x86}/oprofile/op_x86_model.h (100%) diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 0f6186f03034..2d85e4b87307 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -1240,7 +1240,7 @@ menuconfig INSTRUMENTATION if INSTRUMENTATION -source "arch/i386/oprofile/Kconfig" +source "arch/x86/oprofile/Kconfig" config KPROBES bool "Kprobes" diff --git a/arch/i386/Makefile b/arch/i386/Makefile index e03c47e56c76..4d1c0015e443 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -109,7 +109,7 @@ core-y += arch/i386/kernel/ \ drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ drivers-$(CONFIG_PCI) += arch/x86/pci/ # must be linked after kernel/ -drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ +drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ drivers-$(CONFIG_PM) += arch/x86/power/ drivers-$(CONFIG_FB) += arch/i386/video/ diff --git a/arch/i386/oprofile/Kconfig b/arch/x86/oprofile/Kconfig similarity index 100% rename from arch/i386/oprofile/Kconfig rename to arch/x86/oprofile/Kconfig diff --git a/arch/i386/oprofile/Makefile b/arch/x86/oprofile/Makefile similarity index 100% rename from arch/i386/oprofile/Makefile rename to arch/x86/oprofile/Makefile diff --git a/arch/i386/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c similarity index 100% rename from arch/i386/oprofile/backtrace.c rename to arch/x86/oprofile/backtrace.c diff --git a/arch/i386/oprofile/init.c b/arch/x86/oprofile/init.c similarity index 100% rename from arch/i386/oprofile/init.c rename to arch/x86/oprofile/init.c diff --git a/arch/i386/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c similarity index 100% rename from arch/i386/oprofile/nmi_int.c rename to arch/x86/oprofile/nmi_int.c diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/x86/oprofile/nmi_timer_int.c similarity index 100% rename from arch/i386/oprofile/nmi_timer_int.c rename to arch/x86/oprofile/nmi_timer_int.c diff --git a/arch/i386/oprofile/op_counter.h b/arch/x86/oprofile/op_counter.h similarity index 100% rename from arch/i386/oprofile/op_counter.h rename to arch/x86/oprofile/op_counter.h diff --git a/arch/i386/oprofile/op_model_athlon.c b/arch/x86/oprofile/op_model_athlon.c similarity index 100% rename from arch/i386/oprofile/op_model_athlon.c rename to arch/x86/oprofile/op_model_athlon.c diff --git a/arch/i386/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c similarity index 100% rename from arch/i386/oprofile/op_model_p4.c rename to arch/x86/oprofile/op_model_p4.c diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c similarity index 100% rename from arch/i386/oprofile/op_model_ppro.c rename to arch/x86/oprofile/op_model_ppro.c diff --git a/arch/i386/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h similarity index 100% rename from arch/i386/oprofile/op_x86_model.h rename to arch/x86/oprofile/op_x86_model.h diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index c556b6661514..0416dd2f2dbc 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -80,7 +80,7 @@ core-y += arch/x86_64/kernel/ \ arch/x86_64/vdso/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ drivers-$(CONFIG_PCI) += arch/x86_64/pci/ -drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ +drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ boot := arch/x86_64/boot From 4ac24f63fd203bc12a841a88a2034dccd358d0d1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:56 +0200 Subject: [PATCH 2096/2804] i386: move video Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/{i386 => x86}/video/Makefile | 0 arch/{i386 => x86}/video/fbdev.c | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename arch/{i386 => x86}/video/Makefile (100%) rename arch/{i386 => x86}/video/fbdev.c (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 4d1c0015e443..397cfedb4b19 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -111,7 +111,7 @@ drivers-$(CONFIG_PCI) += arch/x86/pci/ # must be linked after kernel/ drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ drivers-$(CONFIG_PM) += arch/x86/power/ -drivers-$(CONFIG_FB) += arch/i386/video/ +drivers-$(CONFIG_FB) += arch/x86/video/ CFLAGS += $(mflags-y) AFLAGS += $(mflags-y) diff --git a/arch/i386/video/Makefile b/arch/x86/video/Makefile similarity index 100% rename from arch/i386/video/Makefile rename to arch/x86/video/Makefile diff --git a/arch/i386/video/fbdev.c b/arch/x86/video/fbdev.c similarity index 100% rename from arch/i386/video/fbdev.c rename to arch/x86/video/fbdev.c From f7627e2513987bb5d4e8cb13c4e0a478352141ac Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:58 +0200 Subject: [PATCH 2097/2804] i386: move kernel/cpu Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/kernel/Makefile_32 | 2 +- arch/{i386 => x86}/kernel/cpu/Makefile | 0 arch/{i386 => x86}/kernel/cpu/addon_cpuid_features.c | 0 arch/{i386 => x86}/kernel/cpu/amd.c | 0 arch/{i386 => x86}/kernel/cpu/bugs.c | 0 arch/{i386 => x86}/kernel/cpu/centaur.c | 0 arch/{i386 => x86}/kernel/cpu/common.c | 0 arch/{i386 => x86}/kernel/cpu/cpu.h | 0 arch/{i386 => x86}/kernel/cpu/cyrix.c | 0 arch/{i386 => x86}/kernel/cpu/intel.c | 0 arch/{i386 => x86}/kernel/cpu/intel_cacheinfo.c | 0 arch/{i386 => x86}/kernel/cpu/nexgen.c | 0 arch/{i386 => x86}/kernel/cpu/perfctr-watchdog.c | 0 arch/{i386 => x86}/kernel/cpu/proc.c | 0 arch/{i386 => x86}/kernel/cpu/transmeta.c | 0 arch/{i386 => x86}/kernel/cpu/umc.c | 0 arch/x86_64/kernel/Makefile_64 | 6 +++--- 17 files changed, 4 insertions(+), 4 deletions(-) rename arch/{i386 => x86}/kernel/cpu/Makefile (100%) rename arch/{i386 => x86}/kernel/cpu/addon_cpuid_features.c (100%) rename arch/{i386 => x86}/kernel/cpu/amd.c (100%) rename arch/{i386 => x86}/kernel/cpu/bugs.c (100%) rename arch/{i386 => x86}/kernel/cpu/centaur.c (100%) rename arch/{i386 => x86}/kernel/cpu/common.c (100%) rename arch/{i386 => x86}/kernel/cpu/cpu.h (100%) rename arch/{i386 => x86}/kernel/cpu/cyrix.c (100%) rename arch/{i386 => x86}/kernel/cpu/intel.c (100%) rename arch/{i386 => x86}/kernel/cpu/intel_cacheinfo.c (100%) rename arch/{i386 => x86}/kernel/cpu/nexgen.c (100%) rename arch/{i386 => x86}/kernel/cpu/perfctr-watchdog.c (100%) rename arch/{i386 => x86}/kernel/cpu/proc.c (100%) rename arch/{i386 => x86}/kernel/cpu/transmeta.c (100%) rename arch/{i386 => x86}/kernel/cpu/umc.c (100%) diff --git a/arch/i386/kernel/Makefile_32 b/arch/i386/kernel/Makefile_32 index af8304b921de..5096f486d389 100644 --- a/arch/i386/kernel/Makefile_32 +++ b/arch/i386/kernel/Makefile_32 @@ -10,7 +10,7 @@ obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-y += cpu/ +obj-y += ../../x86/kernel/cpu/ obj-y += ../../x86/kernel/acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o obj-$(CONFIG_MCA) += mca_32.o diff --git a/arch/i386/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile similarity index 100% rename from arch/i386/kernel/cpu/Makefile rename to arch/x86/kernel/cpu/Makefile diff --git a/arch/i386/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/addon_cpuid_features.c similarity index 100% rename from arch/i386/kernel/cpu/addon_cpuid_features.c rename to arch/x86/kernel/cpu/addon_cpuid_features.c diff --git a/arch/i386/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c similarity index 100% rename from arch/i386/kernel/cpu/amd.c rename to arch/x86/kernel/cpu/amd.c diff --git a/arch/i386/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c similarity index 100% rename from arch/i386/kernel/cpu/bugs.c rename to arch/x86/kernel/cpu/bugs.c diff --git a/arch/i386/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c similarity index 100% rename from arch/i386/kernel/cpu/centaur.c rename to arch/x86/kernel/cpu/centaur.c diff --git a/arch/i386/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c similarity index 100% rename from arch/i386/kernel/cpu/common.c rename to arch/x86/kernel/cpu/common.c diff --git a/arch/i386/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h similarity index 100% rename from arch/i386/kernel/cpu/cpu.h rename to arch/x86/kernel/cpu/cpu.h diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c similarity index 100% rename from arch/i386/kernel/cpu/cyrix.c rename to arch/x86/kernel/cpu/cyrix.c diff --git a/arch/i386/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c similarity index 100% rename from arch/i386/kernel/cpu/intel.c rename to arch/x86/kernel/cpu/intel.c diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c similarity index 100% rename from arch/i386/kernel/cpu/intel_cacheinfo.c rename to arch/x86/kernel/cpu/intel_cacheinfo.c diff --git a/arch/i386/kernel/cpu/nexgen.c b/arch/x86/kernel/cpu/nexgen.c similarity index 100% rename from arch/i386/kernel/cpu/nexgen.c rename to arch/x86/kernel/cpu/nexgen.c diff --git a/arch/i386/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c similarity index 100% rename from arch/i386/kernel/cpu/perfctr-watchdog.c rename to arch/x86/kernel/cpu/perfctr-watchdog.c diff --git a/arch/i386/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c similarity index 100% rename from arch/i386/kernel/cpu/proc.c rename to arch/x86/kernel/cpu/proc.c diff --git a/arch/i386/kernel/cpu/transmeta.c b/arch/x86/kernel/cpu/transmeta.c similarity index 100% rename from arch/i386/kernel/cpu/transmeta.c rename to arch/x86/kernel/cpu/transmeta.c diff --git a/arch/i386/kernel/cpu/umc.c b/arch/x86/kernel/cpu/umc.c similarity index 100% rename from arch/i386/kernel/cpu/umc.c rename to arch/x86/kernel/cpu/umc.c diff --git a/arch/x86_64/kernel/Makefile_64 b/arch/x86_64/kernel/Makefile_64 index e74805091034..690aebf37c37 100644 --- a/arch/x86_64/kernel/Makefile_64 +++ b/arch/x86_64/kernel/Makefile_64 @@ -53,11 +53,11 @@ bootflag-y += ../../i386/kernel/bootflag.o cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o topology-y += ../../i386/kernel/topology.o microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o -intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o -addon_cpuid_features-y += ../../i386/kernel/cpu/addon_cpuid_features.o +intel_cacheinfo-y += ../../x86/kernel/cpu/intel_cacheinfo.o +addon_cpuid_features-y += ../../x86/kernel/cpu/addon_cpuid_features.o quirks-y += ../../i386/kernel/quirks.o i8237-y += ../../i386/kernel/i8237.o msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o alternative-y += ../../i386/kernel/alternative.o pcspeaker-y += ../../i386/kernel/pcspeaker.o -perfctr-watchdog-y += ../../i386/kernel/cpu/perfctr-watchdog.o +perfctr-watchdog-y += ../../x86/kernel/cpu/perfctr-watchdog.o From 9a163ed8e0552fdcffe405d2ea7134819a81456e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:01 +0200 Subject: [PATCH 2098/2804] i386: move kernel Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 11 +++++++++-- arch/um/sys-i386/sys_call_table.S | 2 +- arch/{i386 => x86}/kernel/.gitignore | 0 arch/{i386 => x86}/kernel/Makefile | 2 +- arch/{i386 => x86}/kernel/Makefile_32 | 0 arch/{i386 => x86}/kernel/alternative.c | 0 arch/{i386 => x86}/kernel/apic_32.c | 0 arch/{i386 => x86}/kernel/apm_32.c | 0 arch/{i386 => x86}/kernel/asm-offsets.c | 0 arch/{i386 => x86}/kernel/asm-offsets_32.c | 0 arch/{i386 => x86}/kernel/bootflag.c | 0 arch/{i386 => x86}/kernel/cpuid.c | 0 arch/{i386 => x86}/kernel/crash_32.c | 0 arch/{i386 => x86}/kernel/crash_dump_32.c | 0 arch/{i386 => x86}/kernel/doublefault_32.c | 0 arch/{i386 => x86}/kernel/e820_32.c | 0 arch/{i386 => x86}/kernel/early_printk.c | 0 arch/{i386 => x86}/kernel/efi_32.c | 0 arch/{i386 => x86}/kernel/efi_stub_32.S | 0 arch/{i386 => x86}/kernel/entry_32.S | 0 arch/{i386 => x86}/kernel/geode_32.c | 0 arch/{i386 => x86}/kernel/head_32.S | 0 arch/{i386 => x86}/kernel/hpet_32.c | 0 arch/{i386 => x86}/kernel/i386_ksyms_32.c | 0 arch/{i386 => x86}/kernel/i387_32.c | 0 arch/{i386 => x86}/kernel/i8237.c | 0 arch/{i386 => x86}/kernel/i8253_32.c | 0 arch/{i386 => x86}/kernel/i8259_32.c | 0 arch/{i386 => x86}/kernel/init_task_32.c | 0 arch/{i386 => x86}/kernel/io_apic_32.c | 0 arch/{i386 => x86}/kernel/ioport_32.c | 0 arch/{i386 => x86}/kernel/irq_32.c | 0 arch/{i386 => x86}/kernel/kprobes_32.c | 0 arch/{i386 => x86}/kernel/ldt_32.c | 0 arch/{i386 => x86}/kernel/machine_kexec_32.c | 0 arch/{i386 => x86}/kernel/mca_32.c | 0 arch/{i386 => x86}/kernel/microcode.c | 0 arch/{i386 => x86}/kernel/module_32.c | 0 arch/{i386 => x86}/kernel/mpparse_32.c | 0 arch/{i386 => x86}/kernel/msr.c | 0 arch/{i386 => x86}/kernel/nmi_32.c | 0 arch/{i386 => x86}/kernel/numaq_32.c | 0 arch/{i386 => x86}/kernel/paravirt_32.c | 0 arch/{i386 => x86}/kernel/pci-dma_32.c | 0 arch/{i386 => x86}/kernel/pcspeaker.c | 0 arch/{i386 => x86}/kernel/process_32.c | 0 arch/{i386 => x86}/kernel/ptrace_32.c | 0 arch/{i386 => x86}/kernel/quirks.c | 0 arch/{i386 => x86}/kernel/reboot_32.c | 0 arch/{i386 => x86}/kernel/reboot_fixups_32.c | 0 arch/{i386 => x86}/kernel/relocate_kernel_32.S | 0 arch/{i386 => x86}/kernel/scx200_32.c | 0 arch/{i386 => x86}/kernel/setup_32.c | 0 arch/{i386 => x86}/kernel/sigframe_32.h | 0 arch/{i386 => x86}/kernel/signal_32.c | 0 arch/{i386 => x86}/kernel/smp_32.c | 0 arch/{i386 => x86}/kernel/smpboot_32.c | 0 arch/{i386 => x86}/kernel/smpcommon_32.c | 0 arch/{i386 => x86}/kernel/srat_32.c | 0 arch/{i386 => x86}/kernel/summit_32.c | 0 arch/{i386 => x86}/kernel/sys_i386_32.c | 0 arch/{i386 => x86}/kernel/syscall_table_32.S | 0 arch/{i386 => x86}/kernel/sysenter_32.c | 0 arch/{i386 => x86}/kernel/time_32.c | 0 arch/{i386 => x86}/kernel/topology.c | 0 arch/{i386 => x86}/kernel/trampoline_32.S | 0 arch/{i386 => x86}/kernel/traps_32.c | 0 arch/{i386 => x86}/kernel/tsc_32.c | 0 arch/{i386 => x86}/kernel/tsc_sync.c | 0 arch/{i386 => x86}/kernel/vm86_32.c | 0 arch/{i386 => x86}/kernel/vmi_32.c | 0 arch/{i386 => x86}/kernel/vmiclock_32.c | 0 arch/{i386 => x86}/kernel/vmlinux.lds.S | 0 arch/{i386 => x86}/kernel/vmlinux_32.lds.S | 0 arch/{i386 => x86}/kernel/vsyscall-int80_32.S | 0 arch/{i386 => x86}/kernel/vsyscall-note_32.S | 0 .../kernel/vsyscall-sigreturn_32.S | 0 .../kernel/vsyscall-sysenter_32.S | 0 arch/{i386 => x86}/kernel/vsyscall_32.S | 4 ++-- arch/{i386 => x86}/kernel/vsyscall_32.lds.S | 0 arch/x86/mach-generic/Makefile | 2 +- arch/x86/mach-voyager/Makefile | 2 +- arch/x86_64/ia32/vsyscall-sigreturn.S | 2 +- arch/x86_64/kernel/Makefile | 2 +- arch/x86_64/kernel/Makefile_64 | 18 +++++++++--------- 85 files changed, 26 insertions(+), 19 deletions(-) rename arch/{i386 => x86}/kernel/.gitignore (100%) rename arch/{i386 => x86}/kernel/Makefile (64%) rename arch/{i386 => x86}/kernel/Makefile_32 (100%) rename arch/{i386 => x86}/kernel/alternative.c (100%) rename arch/{i386 => x86}/kernel/apic_32.c (100%) rename arch/{i386 => x86}/kernel/apm_32.c (100%) rename arch/{i386 => x86}/kernel/asm-offsets.c (100%) rename arch/{i386 => x86}/kernel/asm-offsets_32.c (100%) rename arch/{i386 => x86}/kernel/bootflag.c (100%) rename arch/{i386 => x86}/kernel/cpuid.c (100%) rename arch/{i386 => x86}/kernel/crash_32.c (100%) rename arch/{i386 => x86}/kernel/crash_dump_32.c (100%) rename arch/{i386 => x86}/kernel/doublefault_32.c (100%) rename arch/{i386 => x86}/kernel/e820_32.c (100%) rename arch/{i386 => x86}/kernel/early_printk.c (100%) rename arch/{i386 => x86}/kernel/efi_32.c (100%) rename arch/{i386 => x86}/kernel/efi_stub_32.S (100%) rename arch/{i386 => x86}/kernel/entry_32.S (100%) rename arch/{i386 => x86}/kernel/geode_32.c (100%) rename arch/{i386 => x86}/kernel/head_32.S (100%) rename arch/{i386 => x86}/kernel/hpet_32.c (100%) rename arch/{i386 => x86}/kernel/i386_ksyms_32.c (100%) rename arch/{i386 => x86}/kernel/i387_32.c (100%) rename arch/{i386 => x86}/kernel/i8237.c (100%) rename arch/{i386 => x86}/kernel/i8253_32.c (100%) rename arch/{i386 => x86}/kernel/i8259_32.c (100%) rename arch/{i386 => x86}/kernel/init_task_32.c (100%) rename arch/{i386 => x86}/kernel/io_apic_32.c (100%) rename arch/{i386 => x86}/kernel/ioport_32.c (100%) rename arch/{i386 => x86}/kernel/irq_32.c (100%) rename arch/{i386 => x86}/kernel/kprobes_32.c (100%) rename arch/{i386 => x86}/kernel/ldt_32.c (100%) rename arch/{i386 => x86}/kernel/machine_kexec_32.c (100%) rename arch/{i386 => x86}/kernel/mca_32.c (100%) rename arch/{i386 => x86}/kernel/microcode.c (100%) rename arch/{i386 => x86}/kernel/module_32.c (100%) rename arch/{i386 => x86}/kernel/mpparse_32.c (100%) rename arch/{i386 => x86}/kernel/msr.c (100%) rename arch/{i386 => x86}/kernel/nmi_32.c (100%) rename arch/{i386 => x86}/kernel/numaq_32.c (100%) rename arch/{i386 => x86}/kernel/paravirt_32.c (100%) rename arch/{i386 => x86}/kernel/pci-dma_32.c (100%) rename arch/{i386 => x86}/kernel/pcspeaker.c (100%) rename arch/{i386 => x86}/kernel/process_32.c (100%) rename arch/{i386 => x86}/kernel/ptrace_32.c (100%) rename arch/{i386 => x86}/kernel/quirks.c (100%) rename arch/{i386 => x86}/kernel/reboot_32.c (100%) rename arch/{i386 => x86}/kernel/reboot_fixups_32.c (100%) rename arch/{i386 => x86}/kernel/relocate_kernel_32.S (100%) rename arch/{i386 => x86}/kernel/scx200_32.c (100%) rename arch/{i386 => x86}/kernel/setup_32.c (100%) rename arch/{i386 => x86}/kernel/sigframe_32.h (100%) rename arch/{i386 => x86}/kernel/signal_32.c (100%) rename arch/{i386 => x86}/kernel/smp_32.c (100%) rename arch/{i386 => x86}/kernel/smpboot_32.c (100%) rename arch/{i386 => x86}/kernel/smpcommon_32.c (100%) rename arch/{i386 => x86}/kernel/srat_32.c (100%) rename arch/{i386 => x86}/kernel/summit_32.c (100%) rename arch/{i386 => x86}/kernel/sys_i386_32.c (100%) rename arch/{i386 => x86}/kernel/syscall_table_32.S (100%) rename arch/{i386 => x86}/kernel/sysenter_32.c (100%) rename arch/{i386 => x86}/kernel/time_32.c (100%) rename arch/{i386 => x86}/kernel/topology.c (100%) rename arch/{i386 => x86}/kernel/trampoline_32.S (100%) rename arch/{i386 => x86}/kernel/traps_32.c (100%) rename arch/{i386 => x86}/kernel/tsc_32.c (100%) rename arch/{i386 => x86}/kernel/tsc_sync.c (100%) rename arch/{i386 => x86}/kernel/vm86_32.c (100%) rename arch/{i386 => x86}/kernel/vmi_32.c (100%) rename arch/{i386 => x86}/kernel/vmiclock_32.c (100%) rename arch/{i386 => x86}/kernel/vmlinux.lds.S (100%) rename arch/{i386 => x86}/kernel/vmlinux_32.lds.S (100%) rename arch/{i386 => x86}/kernel/vsyscall-int80_32.S (100%) rename arch/{i386 => x86}/kernel/vsyscall-note_32.S (100%) rename arch/{i386 => x86}/kernel/vsyscall-sigreturn_32.S (100%) rename arch/{i386 => x86}/kernel/vsyscall-sysenter_32.S (100%) rename arch/{i386 => x86}/kernel/vsyscall_32.S (70%) rename arch/{i386 => x86}/kernel/vsyscall_32.lds.S (100%) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 397cfedb4b19..9c1da722964d 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -17,6 +17,13 @@ # 20050320 Kianusch Sayah Karadji # Added support for GEODE CPU +# Fill in SRCARCH +SRCARCH := x86 + +archprepare: + @mkdir -p ${objtree}/arch/x86/kernel + + HAS_BIARCH := $(call cc-option-yn, -m32) ifeq ($(HAS_BIARCH),y) AS := $(AS) --32 @@ -99,10 +106,10 @@ core-$(CONFIG_XEN) += arch/x86/xen/ # default subarch .h files mflags-y += -Iinclude/asm-i386/mach-default -head-y := arch/i386/kernel/head_32.o arch/i386/kernel/init_task_32.o +head-y := arch/x86/kernel/head_32.o arch/x86/kernel/init_task_32.o libs-y += arch/x86/lib/ -core-y += arch/i386/kernel/ \ +core-y += arch/x86/kernel/ \ arch/x86/mm/ \ $(mcore-y)/ \ arch/x86/crypto/ diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S index 4c1f17d7986d..12d4148dba39 100644 --- a/arch/um/sys-i386/sys_call_table.S +++ b/arch/um/sys-i386/sys_call_table.S @@ -9,4 +9,4 @@ #define old_mmap old_mmap_i386 -#include "../../i386/kernel/syscall_table_32.S" +#include "../../x86/kernel/syscall_table_32.S" diff --git a/arch/i386/kernel/.gitignore b/arch/x86/kernel/.gitignore similarity index 100% rename from arch/i386/kernel/.gitignore rename to arch/x86/kernel/.gitignore diff --git a/arch/i386/kernel/Makefile b/arch/x86/kernel/Makefile similarity index 64% rename from arch/i386/kernel/Makefile rename to arch/x86/kernel/Makefile index d3ebd1699826..577d08f4b8bb 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/kernel/Makefile_32 +include ${srctree}/arch/x86/kernel/Makefile_32 else include ${srctree}/arch/x86_64/kernel/Makefile_64 endif diff --git a/arch/i386/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 similarity index 100% rename from arch/i386/kernel/Makefile_32 rename to arch/x86/kernel/Makefile_32 diff --git a/arch/i386/kernel/alternative.c b/arch/x86/kernel/alternative.c similarity index 100% rename from arch/i386/kernel/alternative.c rename to arch/x86/kernel/alternative.c diff --git a/arch/i386/kernel/apic_32.c b/arch/x86/kernel/apic_32.c similarity index 100% rename from arch/i386/kernel/apic_32.c rename to arch/x86/kernel/apic_32.c diff --git a/arch/i386/kernel/apm_32.c b/arch/x86/kernel/apm_32.c similarity index 100% rename from arch/i386/kernel/apm_32.c rename to arch/x86/kernel/apm_32.c diff --git a/arch/i386/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c similarity index 100% rename from arch/i386/kernel/asm-offsets.c rename to arch/x86/kernel/asm-offsets.c diff --git a/arch/i386/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c similarity index 100% rename from arch/i386/kernel/asm-offsets_32.c rename to arch/x86/kernel/asm-offsets_32.c diff --git a/arch/i386/kernel/bootflag.c b/arch/x86/kernel/bootflag.c similarity index 100% rename from arch/i386/kernel/bootflag.c rename to arch/x86/kernel/bootflag.c diff --git a/arch/i386/kernel/cpuid.c b/arch/x86/kernel/cpuid.c similarity index 100% rename from arch/i386/kernel/cpuid.c rename to arch/x86/kernel/cpuid.c diff --git a/arch/i386/kernel/crash_32.c b/arch/x86/kernel/crash_32.c similarity index 100% rename from arch/i386/kernel/crash_32.c rename to arch/x86/kernel/crash_32.c diff --git a/arch/i386/kernel/crash_dump_32.c b/arch/x86/kernel/crash_dump_32.c similarity index 100% rename from arch/i386/kernel/crash_dump_32.c rename to arch/x86/kernel/crash_dump_32.c diff --git a/arch/i386/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c similarity index 100% rename from arch/i386/kernel/doublefault_32.c rename to arch/x86/kernel/doublefault_32.c diff --git a/arch/i386/kernel/e820_32.c b/arch/x86/kernel/e820_32.c similarity index 100% rename from arch/i386/kernel/e820_32.c rename to arch/x86/kernel/e820_32.c diff --git a/arch/i386/kernel/early_printk.c b/arch/x86/kernel/early_printk.c similarity index 100% rename from arch/i386/kernel/early_printk.c rename to arch/x86/kernel/early_printk.c diff --git a/arch/i386/kernel/efi_32.c b/arch/x86/kernel/efi_32.c similarity index 100% rename from arch/i386/kernel/efi_32.c rename to arch/x86/kernel/efi_32.c diff --git a/arch/i386/kernel/efi_stub_32.S b/arch/x86/kernel/efi_stub_32.S similarity index 100% rename from arch/i386/kernel/efi_stub_32.S rename to arch/x86/kernel/efi_stub_32.S diff --git a/arch/i386/kernel/entry_32.S b/arch/x86/kernel/entry_32.S similarity index 100% rename from arch/i386/kernel/entry_32.S rename to arch/x86/kernel/entry_32.S diff --git a/arch/i386/kernel/geode_32.c b/arch/x86/kernel/geode_32.c similarity index 100% rename from arch/i386/kernel/geode_32.c rename to arch/x86/kernel/geode_32.c diff --git a/arch/i386/kernel/head_32.S b/arch/x86/kernel/head_32.S similarity index 100% rename from arch/i386/kernel/head_32.S rename to arch/x86/kernel/head_32.S diff --git a/arch/i386/kernel/hpet_32.c b/arch/x86/kernel/hpet_32.c similarity index 100% rename from arch/i386/kernel/hpet_32.c rename to arch/x86/kernel/hpet_32.c diff --git a/arch/i386/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c similarity index 100% rename from arch/i386/kernel/i386_ksyms_32.c rename to arch/x86/kernel/i386_ksyms_32.c diff --git a/arch/i386/kernel/i387_32.c b/arch/x86/kernel/i387_32.c similarity index 100% rename from arch/i386/kernel/i387_32.c rename to arch/x86/kernel/i387_32.c diff --git a/arch/i386/kernel/i8237.c b/arch/x86/kernel/i8237.c similarity index 100% rename from arch/i386/kernel/i8237.c rename to arch/x86/kernel/i8237.c diff --git a/arch/i386/kernel/i8253_32.c b/arch/x86/kernel/i8253_32.c similarity index 100% rename from arch/i386/kernel/i8253_32.c rename to arch/x86/kernel/i8253_32.c diff --git a/arch/i386/kernel/i8259_32.c b/arch/x86/kernel/i8259_32.c similarity index 100% rename from arch/i386/kernel/i8259_32.c rename to arch/x86/kernel/i8259_32.c diff --git a/arch/i386/kernel/init_task_32.c b/arch/x86/kernel/init_task_32.c similarity index 100% rename from arch/i386/kernel/init_task_32.c rename to arch/x86/kernel/init_task_32.c diff --git a/arch/i386/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c similarity index 100% rename from arch/i386/kernel/io_apic_32.c rename to arch/x86/kernel/io_apic_32.c diff --git a/arch/i386/kernel/ioport_32.c b/arch/x86/kernel/ioport_32.c similarity index 100% rename from arch/i386/kernel/ioport_32.c rename to arch/x86/kernel/ioport_32.c diff --git a/arch/i386/kernel/irq_32.c b/arch/x86/kernel/irq_32.c similarity index 100% rename from arch/i386/kernel/irq_32.c rename to arch/x86/kernel/irq_32.c diff --git a/arch/i386/kernel/kprobes_32.c b/arch/x86/kernel/kprobes_32.c similarity index 100% rename from arch/i386/kernel/kprobes_32.c rename to arch/x86/kernel/kprobes_32.c diff --git a/arch/i386/kernel/ldt_32.c b/arch/x86/kernel/ldt_32.c similarity index 100% rename from arch/i386/kernel/ldt_32.c rename to arch/x86/kernel/ldt_32.c diff --git a/arch/i386/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c similarity index 100% rename from arch/i386/kernel/machine_kexec_32.c rename to arch/x86/kernel/machine_kexec_32.c diff --git a/arch/i386/kernel/mca_32.c b/arch/x86/kernel/mca_32.c similarity index 100% rename from arch/i386/kernel/mca_32.c rename to arch/x86/kernel/mca_32.c diff --git a/arch/i386/kernel/microcode.c b/arch/x86/kernel/microcode.c similarity index 100% rename from arch/i386/kernel/microcode.c rename to arch/x86/kernel/microcode.c diff --git a/arch/i386/kernel/module_32.c b/arch/x86/kernel/module_32.c similarity index 100% rename from arch/i386/kernel/module_32.c rename to arch/x86/kernel/module_32.c diff --git a/arch/i386/kernel/mpparse_32.c b/arch/x86/kernel/mpparse_32.c similarity index 100% rename from arch/i386/kernel/mpparse_32.c rename to arch/x86/kernel/mpparse_32.c diff --git a/arch/i386/kernel/msr.c b/arch/x86/kernel/msr.c similarity index 100% rename from arch/i386/kernel/msr.c rename to arch/x86/kernel/msr.c diff --git a/arch/i386/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c similarity index 100% rename from arch/i386/kernel/nmi_32.c rename to arch/x86/kernel/nmi_32.c diff --git a/arch/i386/kernel/numaq_32.c b/arch/x86/kernel/numaq_32.c similarity index 100% rename from arch/i386/kernel/numaq_32.c rename to arch/x86/kernel/numaq_32.c diff --git a/arch/i386/kernel/paravirt_32.c b/arch/x86/kernel/paravirt_32.c similarity index 100% rename from arch/i386/kernel/paravirt_32.c rename to arch/x86/kernel/paravirt_32.c diff --git a/arch/i386/kernel/pci-dma_32.c b/arch/x86/kernel/pci-dma_32.c similarity index 100% rename from arch/i386/kernel/pci-dma_32.c rename to arch/x86/kernel/pci-dma_32.c diff --git a/arch/i386/kernel/pcspeaker.c b/arch/x86/kernel/pcspeaker.c similarity index 100% rename from arch/i386/kernel/pcspeaker.c rename to arch/x86/kernel/pcspeaker.c diff --git a/arch/i386/kernel/process_32.c b/arch/x86/kernel/process_32.c similarity index 100% rename from arch/i386/kernel/process_32.c rename to arch/x86/kernel/process_32.c diff --git a/arch/i386/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c similarity index 100% rename from arch/i386/kernel/ptrace_32.c rename to arch/x86/kernel/ptrace_32.c diff --git a/arch/i386/kernel/quirks.c b/arch/x86/kernel/quirks.c similarity index 100% rename from arch/i386/kernel/quirks.c rename to arch/x86/kernel/quirks.c diff --git a/arch/i386/kernel/reboot_32.c b/arch/x86/kernel/reboot_32.c similarity index 100% rename from arch/i386/kernel/reboot_32.c rename to arch/x86/kernel/reboot_32.c diff --git a/arch/i386/kernel/reboot_fixups_32.c b/arch/x86/kernel/reboot_fixups_32.c similarity index 100% rename from arch/i386/kernel/reboot_fixups_32.c rename to arch/x86/kernel/reboot_fixups_32.c diff --git a/arch/i386/kernel/relocate_kernel_32.S b/arch/x86/kernel/relocate_kernel_32.S similarity index 100% rename from arch/i386/kernel/relocate_kernel_32.S rename to arch/x86/kernel/relocate_kernel_32.S diff --git a/arch/i386/kernel/scx200_32.c b/arch/x86/kernel/scx200_32.c similarity index 100% rename from arch/i386/kernel/scx200_32.c rename to arch/x86/kernel/scx200_32.c diff --git a/arch/i386/kernel/setup_32.c b/arch/x86/kernel/setup_32.c similarity index 100% rename from arch/i386/kernel/setup_32.c rename to arch/x86/kernel/setup_32.c diff --git a/arch/i386/kernel/sigframe_32.h b/arch/x86/kernel/sigframe_32.h similarity index 100% rename from arch/i386/kernel/sigframe_32.h rename to arch/x86/kernel/sigframe_32.h diff --git a/arch/i386/kernel/signal_32.c b/arch/x86/kernel/signal_32.c similarity index 100% rename from arch/i386/kernel/signal_32.c rename to arch/x86/kernel/signal_32.c diff --git a/arch/i386/kernel/smp_32.c b/arch/x86/kernel/smp_32.c similarity index 100% rename from arch/i386/kernel/smp_32.c rename to arch/x86/kernel/smp_32.c diff --git a/arch/i386/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c similarity index 100% rename from arch/i386/kernel/smpboot_32.c rename to arch/x86/kernel/smpboot_32.c diff --git a/arch/i386/kernel/smpcommon_32.c b/arch/x86/kernel/smpcommon_32.c similarity index 100% rename from arch/i386/kernel/smpcommon_32.c rename to arch/x86/kernel/smpcommon_32.c diff --git a/arch/i386/kernel/srat_32.c b/arch/x86/kernel/srat_32.c similarity index 100% rename from arch/i386/kernel/srat_32.c rename to arch/x86/kernel/srat_32.c diff --git a/arch/i386/kernel/summit_32.c b/arch/x86/kernel/summit_32.c similarity index 100% rename from arch/i386/kernel/summit_32.c rename to arch/x86/kernel/summit_32.c diff --git a/arch/i386/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c similarity index 100% rename from arch/i386/kernel/sys_i386_32.c rename to arch/x86/kernel/sys_i386_32.c diff --git a/arch/i386/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S similarity index 100% rename from arch/i386/kernel/syscall_table_32.S rename to arch/x86/kernel/syscall_table_32.S diff --git a/arch/i386/kernel/sysenter_32.c b/arch/x86/kernel/sysenter_32.c similarity index 100% rename from arch/i386/kernel/sysenter_32.c rename to arch/x86/kernel/sysenter_32.c diff --git a/arch/i386/kernel/time_32.c b/arch/x86/kernel/time_32.c similarity index 100% rename from arch/i386/kernel/time_32.c rename to arch/x86/kernel/time_32.c diff --git a/arch/i386/kernel/topology.c b/arch/x86/kernel/topology.c similarity index 100% rename from arch/i386/kernel/topology.c rename to arch/x86/kernel/topology.c diff --git a/arch/i386/kernel/trampoline_32.S b/arch/x86/kernel/trampoline_32.S similarity index 100% rename from arch/i386/kernel/trampoline_32.S rename to arch/x86/kernel/trampoline_32.S diff --git a/arch/i386/kernel/traps_32.c b/arch/x86/kernel/traps_32.c similarity index 100% rename from arch/i386/kernel/traps_32.c rename to arch/x86/kernel/traps_32.c diff --git a/arch/i386/kernel/tsc_32.c b/arch/x86/kernel/tsc_32.c similarity index 100% rename from arch/i386/kernel/tsc_32.c rename to arch/x86/kernel/tsc_32.c diff --git a/arch/i386/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c similarity index 100% rename from arch/i386/kernel/tsc_sync.c rename to arch/x86/kernel/tsc_sync.c diff --git a/arch/i386/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c similarity index 100% rename from arch/i386/kernel/vm86_32.c rename to arch/x86/kernel/vm86_32.c diff --git a/arch/i386/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c similarity index 100% rename from arch/i386/kernel/vmi_32.c rename to arch/x86/kernel/vmi_32.c diff --git a/arch/i386/kernel/vmiclock_32.c b/arch/x86/kernel/vmiclock_32.c similarity index 100% rename from arch/i386/kernel/vmiclock_32.c rename to arch/x86/kernel/vmiclock_32.c diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S similarity index 100% rename from arch/i386/kernel/vmlinux.lds.S rename to arch/x86/kernel/vmlinux.lds.S diff --git a/arch/i386/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S similarity index 100% rename from arch/i386/kernel/vmlinux_32.lds.S rename to arch/x86/kernel/vmlinux_32.lds.S diff --git a/arch/i386/kernel/vsyscall-int80_32.S b/arch/x86/kernel/vsyscall-int80_32.S similarity index 100% rename from arch/i386/kernel/vsyscall-int80_32.S rename to arch/x86/kernel/vsyscall-int80_32.S diff --git a/arch/i386/kernel/vsyscall-note_32.S b/arch/x86/kernel/vsyscall-note_32.S similarity index 100% rename from arch/i386/kernel/vsyscall-note_32.S rename to arch/x86/kernel/vsyscall-note_32.S diff --git a/arch/i386/kernel/vsyscall-sigreturn_32.S b/arch/x86/kernel/vsyscall-sigreturn_32.S similarity index 100% rename from arch/i386/kernel/vsyscall-sigreturn_32.S rename to arch/x86/kernel/vsyscall-sigreturn_32.S diff --git a/arch/i386/kernel/vsyscall-sysenter_32.S b/arch/x86/kernel/vsyscall-sysenter_32.S similarity index 100% rename from arch/i386/kernel/vsyscall-sysenter_32.S rename to arch/x86/kernel/vsyscall-sysenter_32.S diff --git a/arch/i386/kernel/vsyscall_32.S b/arch/x86/kernel/vsyscall_32.S similarity index 70% rename from arch/i386/kernel/vsyscall_32.S rename to arch/x86/kernel/vsyscall_32.S index 033074479fca..a5ab3dc4fd25 100644 --- a/arch/i386/kernel/vsyscall_32.S +++ b/arch/x86/kernel/vsyscall_32.S @@ -4,12 +4,12 @@ __INITDATA .globl vsyscall_int80_start, vsyscall_int80_end vsyscall_int80_start: - .incbin "arch/i386/kernel/vsyscall-int80_32.so" + .incbin "arch/x86/kernel/vsyscall-int80_32.so" vsyscall_int80_end: .globl vsyscall_sysenter_start, vsyscall_sysenter_end vsyscall_sysenter_start: - .incbin "arch/i386/kernel/vsyscall-sysenter_32.so" + .incbin "arch/x86/kernel/vsyscall-sysenter_32.so" vsyscall_sysenter_end: __FINIT diff --git a/arch/i386/kernel/vsyscall_32.lds.S b/arch/x86/kernel/vsyscall_32.lds.S similarity index 100% rename from arch/i386/kernel/vsyscall_32.lds.S rename to arch/x86/kernel/vsyscall_32.lds.S diff --git a/arch/x86/mach-generic/Makefile b/arch/x86/mach-generic/Makefile index 08f489a7f1f5..19d6d407737b 100644 --- a/arch/x86/mach-generic/Makefile +++ b/arch/x86/mach-generic/Makefile @@ -2,7 +2,7 @@ # Makefile for the generic architecture # -EXTRA_CFLAGS := -Iarch/i386/kernel +EXTRA_CFLAGS := -Iarch/x86/kernel obj-y := probe.o summit.o bigsmp.o es7000.o default.o obj-y += ../../x86/mach-es7000/ diff --git a/arch/x86/mach-voyager/Makefile b/arch/x86/mach-voyager/Makefile index 33b74cf0dd22..15c250b371d3 100644 --- a/arch/x86/mach-voyager/Makefile +++ b/arch/x86/mach-voyager/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -EXTRA_CFLAGS := -Iarch/i386/kernel +EXTRA_CFLAGS := -Iarch/x86/kernel obj-y := setup.o voyager_basic.o voyager_thread.o obj-$(CONFIG_SMP) += voyager_smp.o voyager_cat.o diff --git a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S index 83e7fd683c3d..b383be00baec 100644 --- a/arch/x86_64/ia32/vsyscall-sigreturn.S +++ b/arch/x86_64/ia32/vsyscall-sigreturn.S @@ -139,5 +139,5 @@ __kernel_rt_sigreturn: .align 4 .LENDFDE3: -#include "../../i386/kernel/vsyscall-note_32.S" +#include "../../x86/kernel/vsyscall-note_32.S" diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index d3ebd1699826..577d08f4b8bb 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/kernel/Makefile_32 +include ${srctree}/arch/x86/kernel/Makefile_32 else include ${srctree}/arch/x86_64/kernel/Makefile_64 endif diff --git a/arch/x86_64/kernel/Makefile_64 b/arch/x86_64/kernel/Makefile_64 index 690aebf37c37..3a204cc599d7 100644 --- a/arch/x86_64/kernel/Makefile_64 +++ b/arch/x86_64/kernel/Makefile_64 @@ -49,15 +49,15 @@ obj-y += pcspeaker.o CFLAGS_vsyscall_64.o := $(PROFILING) -g0 therm_throt-y += ../../x86/kernel/cpu/mcheck/therm_throt.o -bootflag-y += ../../i386/kernel/bootflag.o -cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o -topology-y += ../../i386/kernel/topology.o -microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o +bootflag-y += ../../x86/kernel/bootflag.o +cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../x86/kernel/cpuid.o +topology-y += ../../x86/kernel/topology.o +microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../x86/kernel/microcode.o intel_cacheinfo-y += ../../x86/kernel/cpu/intel_cacheinfo.o addon_cpuid_features-y += ../../x86/kernel/cpu/addon_cpuid_features.o -quirks-y += ../../i386/kernel/quirks.o -i8237-y += ../../i386/kernel/i8237.o -msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o -alternative-y += ../../i386/kernel/alternative.o -pcspeaker-y += ../../i386/kernel/pcspeaker.o +quirks-y += ../../x86/kernel/quirks.o +i8237-y += ../../x86/kernel/i8237.o +msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../x86/kernel/msr.o +alternative-y += ../../x86/kernel/alternative.o +pcspeaker-y += ../../x86/kernel/pcspeaker.o perfctr-watchdog-y += ../../x86/kernel/cpu/perfctr-watchdog.o From 987c75d7170686804b404b7f917b9e4b703702ff Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:03 +0200 Subject: [PATCH 2099/2804] x86_64: move crypto Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/crypto/Makefile | 2 +- arch/{x86_64 => x86}/crypto/Makefile_64 | 2 +- arch/{x86_64 => x86}/crypto/aes-x86_64-asm_64.S | 0 arch/{x86_64 => x86}/crypto/aes_64.c | 0 arch/{x86_64 => x86}/crypto/twofish-x86_64-asm_64.S | 0 arch/{x86_64 => x86}/crypto/twofish_64.c | 0 arch/x86_64/Makefile | 2 +- arch/x86_64/crypto/Makefile | 5 ----- 8 files changed, 3 insertions(+), 8 deletions(-) rename arch/{x86_64 => x86}/crypto/Makefile_64 (90%) rename arch/{x86_64 => x86}/crypto/aes-x86_64-asm_64.S (100%) rename arch/{x86_64 => x86}/crypto/aes_64.c (100%) rename arch/{x86_64 => x86}/crypto/twofish-x86_64-asm_64.S (100%) rename arch/{x86_64 => x86}/crypto/twofish_64.c (100%) delete mode 100644 arch/x86_64/crypto/Makefile diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index b1bcf7c63028..18dcdc6fb7aa 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) include ${srctree}/arch/x86/crypto/Makefile_32 else -include ${srctree}/arch/x86_64/crypto/Makefile_64 +include ${srctree}/arch/x86/crypto/Makefile_64 endif diff --git a/arch/x86_64/crypto/Makefile_64 b/arch/x86/crypto/Makefile_64 similarity index 90% rename from arch/x86_64/crypto/Makefile_64 rename to arch/x86/crypto/Makefile_64 index c96faeb842c8..b40896276e93 100644 --- a/arch/x86_64/crypto/Makefile_64 +++ b/arch/x86/crypto/Makefile_64 @@ -1,5 +1,5 @@ # -# x86_64/crypto/Makefile +# x86/crypto/Makefile # # Arch-specific CryptoAPI modules. # diff --git a/arch/x86_64/crypto/aes-x86_64-asm_64.S b/arch/x86/crypto/aes-x86_64-asm_64.S similarity index 100% rename from arch/x86_64/crypto/aes-x86_64-asm_64.S rename to arch/x86/crypto/aes-x86_64-asm_64.S diff --git a/arch/x86_64/crypto/aes_64.c b/arch/x86/crypto/aes_64.c similarity index 100% rename from arch/x86_64/crypto/aes_64.c rename to arch/x86/crypto/aes_64.c diff --git a/arch/x86_64/crypto/twofish-x86_64-asm_64.S b/arch/x86/crypto/twofish-x86_64-asm_64.S similarity index 100% rename from arch/x86_64/crypto/twofish-x86_64-asm_64.S rename to arch/x86/crypto/twofish-x86_64-asm_64.S diff --git a/arch/x86_64/crypto/twofish_64.c b/arch/x86/crypto/twofish_64.c similarity index 100% rename from arch/x86_64/crypto/twofish_64.c rename to arch/x86/crypto/twofish_64.c diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 0416dd2f2dbc..265484c17234 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -76,7 +76,7 @@ head-y := arch/x86_64/kernel/head_64.o arch/x86_64/kernel/head64.o arch/x86_64/k libs-y += arch/x86_64/lib/ core-y += arch/x86_64/kernel/ \ arch/x86_64/mm/ \ - arch/x86_64/crypto/ \ + arch/x86/crypto/ \ arch/x86_64/vdso/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ drivers-$(CONFIG_PCI) += arch/x86_64/pci/ diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile deleted file mode 100644 index b1bcf7c63028..000000000000 --- a/arch/x86_64/crypto/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/x86/crypto/Makefile_32 -else -include ${srctree}/arch/x86_64/crypto/Makefile_64 -endif From e8d08eb1b59bf6dda44fffe63cce1250d87a8b56 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:05 +0200 Subject: [PATCH 2100/2804] x86_64: move kernel/acpi Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/acpi/Makefile | 2 +- arch/x86/kernel/acpi/Makefile_64 | 7 +++++++ arch/{x86_64 => x86}/kernel/acpi/sleep_64.c | 0 arch/{x86_64 => x86}/kernel/acpi/wakeup_64.S | 2 +- arch/x86_64/kernel/Makefile_64 | 2 +- arch/x86_64/kernel/acpi/Makefile | 5 ----- arch/x86_64/kernel/acpi/Makefile_64 | 9 --------- 7 files changed, 10 insertions(+), 17 deletions(-) create mode 100644 arch/x86/kernel/acpi/Makefile_64 rename arch/{x86_64 => x86}/kernel/acpi/sleep_64.c (100%) rename arch/{x86_64 => x86}/kernel/acpi/wakeup_64.S (99%) delete mode 100644 arch/x86_64/kernel/acpi/Makefile delete mode 100644 arch/x86_64/kernel/acpi/Makefile_64 diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile index dd4eb7cef2b4..3d5671939542 100644 --- a/arch/x86/kernel/acpi/Makefile +++ b/arch/x86/kernel/acpi/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) include ${srctree}/arch/x86/kernel/acpi/Makefile_32 else -include ${srctree}/arch/x86_64/kernel/acpi/Makefile_64 +include ${srctree}/arch/x86/kernel/acpi/Makefile_64 endif diff --git a/arch/x86/kernel/acpi/Makefile_64 b/arch/x86/kernel/acpi/Makefile_64 new file mode 100644 index 000000000000..629425bc002d --- /dev/null +++ b/arch/x86/kernel/acpi/Makefile_64 @@ -0,0 +1,7 @@ +obj-y := boot.o +obj-$(CONFIG_ACPI_SLEEP) += sleep_64.o wakeup_64.o + +ifneq ($(CONFIG_ACPI_PROCESSOR),) +obj-y += processor.o cstate.o +endif + diff --git a/arch/x86_64/kernel/acpi/sleep_64.c b/arch/x86/kernel/acpi/sleep_64.c similarity index 100% rename from arch/x86_64/kernel/acpi/sleep_64.c rename to arch/x86/kernel/acpi/sleep_64.c diff --git a/arch/x86_64/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S similarity index 99% rename from arch/x86_64/kernel/acpi/wakeup_64.S rename to arch/x86/kernel/acpi/wakeup_64.S index 8b4357e1efe0..5e3b3f5496c5 100644 --- a/arch/x86_64/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -269,7 +269,7 @@ no_longmode: movb $0xbc,%al ; outb %al,$0x80 jmp no_longmode -#include "../verify_cpu_64.S" +#include "../../../x86_64/kernel/verify_cpu_64.S" /* This code uses an extended set of video mode numbers. These include: * Aliases for standard modes diff --git a/arch/x86_64/kernel/Makefile_64 b/arch/x86_64/kernel/Makefile_64 index 3a204cc599d7..120d4e51fd4d 100644 --- a/arch/x86_64/kernel/Makefile_64 +++ b/arch/x86_64/kernel/Makefile_64 @@ -16,7 +16,7 @@ obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o obj-$(CONFIG_MTRR) += ../../x86/kernel/cpu/mtrr/ -obj-$(CONFIG_ACPI) += acpi/ +obj-$(CONFIG_ACPI) += ../../x86/kernel/acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile deleted file mode 100644 index dd4eb7cef2b4..000000000000 --- a/arch/x86_64/kernel/acpi/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/x86/kernel/acpi/Makefile_32 -else -include ${srctree}/arch/x86_64/kernel/acpi/Makefile_64 -endif diff --git a/arch/x86_64/kernel/acpi/Makefile_64 b/arch/x86_64/kernel/acpi/Makefile_64 deleted file mode 100644 index fc377c87e0b0..000000000000 --- a/arch/x86_64/kernel/acpi/Makefile_64 +++ /dev/null @@ -1,9 +0,0 @@ -obj-y := boot.o -boot-y := ../../../x86/kernel/acpi/boot.o -obj-$(CONFIG_ACPI_SLEEP) += sleep_64.o wakeup_64.o - -ifneq ($(CONFIG_ACPI_PROCESSOR),) -obj-y += processor.o -processor-y := ../../../x86/kernel/acpi/processor.o ../../../x86/kernel/acpi/cstate.o -endif - From 51b2833060f26258ea2da091c7b9c6a358ac9dd2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:06 +0200 Subject: [PATCH 2101/2804] x86_64: move kernel/cpufreq Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/{x86_64 => x86}/kernel/cpufreq/Kconfig | 0 arch/x86_64/Kconfig | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/{x86_64 => x86}/kernel/cpufreq/Kconfig (100%) diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86/kernel/cpufreq/Kconfig similarity index 100% rename from arch/x86_64/kernel/cpufreq/Kconfig rename to arch/x86/kernel/cpufreq/Kconfig diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index b4d9089a6a06..17d57617a41d 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -704,7 +704,7 @@ source kernel/power/Kconfig source "drivers/acpi/Kconfig" -source "arch/x86_64/kernel/cpufreq/Kconfig" +source "arch/x86/kernel/cpufreq/Kconfig" endmenu From 185f3d38900f750a4566f87cde6a178f3595a115 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:08 +0200 Subject: [PATCH 2102/2804] x86_64: move lib Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/lib/Makefile | 2 +- arch/{x86_64 => x86}/lib/Makefile_64 | 0 arch/{x86_64 => x86}/lib/bitops_64.c | 0 arch/{x86_64 => x86}/lib/bitstr_64.c | 0 arch/{x86_64 => x86}/lib/clear_page_64.S | 0 arch/{x86_64 => x86}/lib/copy_page_64.S | 0 arch/{x86_64 => x86}/lib/copy_user_64.S | 0 arch/{x86_64 => x86}/lib/copy_user_nocache_64.S | 0 arch/{x86_64 => x86}/lib/csum-copy_64.S | 0 arch/{x86_64 => x86}/lib/csum-partial_64.c | 0 arch/{x86_64 => x86}/lib/csum-wrappers_64.c | 0 arch/{x86_64 => x86}/lib/delay_64.c | 0 arch/{x86_64 => x86}/lib/getuser_64.S | 0 arch/{x86_64 => x86}/lib/io_64.c | 0 arch/{x86_64 => x86}/lib/iomap_copy_64.S | 0 arch/{x86_64 => x86}/lib/memcpy_64.S | 0 arch/{x86_64 => x86}/lib/memmove_64.c | 0 arch/{x86_64 => x86}/lib/memset_64.S | 0 arch/{x86_64 => x86}/lib/putuser_64.S | 0 arch/{x86_64 => x86}/lib/rwlock_64.S | 0 arch/{x86_64 => x86}/lib/thunk_64.S | 0 arch/{x86_64 => x86}/lib/usercopy_64.c | 0 arch/x86_64/Makefile | 2 +- arch/x86_64/lib/Makefile | 5 ----- arch/x86_64/lib/msr-on-cpu.c | 1 - 25 files changed, 2 insertions(+), 8 deletions(-) rename arch/{x86_64 => x86}/lib/Makefile_64 (100%) rename arch/{x86_64 => x86}/lib/bitops_64.c (100%) rename arch/{x86_64 => x86}/lib/bitstr_64.c (100%) rename arch/{x86_64 => x86}/lib/clear_page_64.S (100%) rename arch/{x86_64 => x86}/lib/copy_page_64.S (100%) rename arch/{x86_64 => x86}/lib/copy_user_64.S (100%) rename arch/{x86_64 => x86}/lib/copy_user_nocache_64.S (100%) rename arch/{x86_64 => x86}/lib/csum-copy_64.S (100%) rename arch/{x86_64 => x86}/lib/csum-partial_64.c (100%) rename arch/{x86_64 => x86}/lib/csum-wrappers_64.c (100%) rename arch/{x86_64 => x86}/lib/delay_64.c (100%) rename arch/{x86_64 => x86}/lib/getuser_64.S (100%) rename arch/{x86_64 => x86}/lib/io_64.c (100%) rename arch/{x86_64 => x86}/lib/iomap_copy_64.S (100%) rename arch/{x86_64 => x86}/lib/memcpy_64.S (100%) rename arch/{x86_64 => x86}/lib/memmove_64.c (100%) rename arch/{x86_64 => x86}/lib/memset_64.S (100%) rename arch/{x86_64 => x86}/lib/putuser_64.S (100%) rename arch/{x86_64 => x86}/lib/rwlock_64.S (100%) rename arch/{x86_64 => x86}/lib/thunk_64.S (100%) rename arch/{x86_64 => x86}/lib/usercopy_64.c (100%) delete mode 100644 arch/x86_64/lib/Makefile delete mode 100644 arch/x86_64/lib/msr-on-cpu.c diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 2d7d724a2a6a..329da276c6f1 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) include ${srctree}/arch/x86/lib/Makefile_32 else -include ${srctree}/arch/x86_64/lib/Makefile_64 +include ${srctree}/arch/x86/lib/Makefile_64 endif diff --git a/arch/x86_64/lib/Makefile_64 b/arch/x86/lib/Makefile_64 similarity index 100% rename from arch/x86_64/lib/Makefile_64 rename to arch/x86/lib/Makefile_64 diff --git a/arch/x86_64/lib/bitops_64.c b/arch/x86/lib/bitops_64.c similarity index 100% rename from arch/x86_64/lib/bitops_64.c rename to arch/x86/lib/bitops_64.c diff --git a/arch/x86_64/lib/bitstr_64.c b/arch/x86/lib/bitstr_64.c similarity index 100% rename from arch/x86_64/lib/bitstr_64.c rename to arch/x86/lib/bitstr_64.c diff --git a/arch/x86_64/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S similarity index 100% rename from arch/x86_64/lib/clear_page_64.S rename to arch/x86/lib/clear_page_64.S diff --git a/arch/x86_64/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S similarity index 100% rename from arch/x86_64/lib/copy_page_64.S rename to arch/x86/lib/copy_page_64.S diff --git a/arch/x86_64/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S similarity index 100% rename from arch/x86_64/lib/copy_user_64.S rename to arch/x86/lib/copy_user_64.S diff --git a/arch/x86_64/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S similarity index 100% rename from arch/x86_64/lib/copy_user_nocache_64.S rename to arch/x86/lib/copy_user_nocache_64.S diff --git a/arch/x86_64/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S similarity index 100% rename from arch/x86_64/lib/csum-copy_64.S rename to arch/x86/lib/csum-copy_64.S diff --git a/arch/x86_64/lib/csum-partial_64.c b/arch/x86/lib/csum-partial_64.c similarity index 100% rename from arch/x86_64/lib/csum-partial_64.c rename to arch/x86/lib/csum-partial_64.c diff --git a/arch/x86_64/lib/csum-wrappers_64.c b/arch/x86/lib/csum-wrappers_64.c similarity index 100% rename from arch/x86_64/lib/csum-wrappers_64.c rename to arch/x86/lib/csum-wrappers_64.c diff --git a/arch/x86_64/lib/delay_64.c b/arch/x86/lib/delay_64.c similarity index 100% rename from arch/x86_64/lib/delay_64.c rename to arch/x86/lib/delay_64.c diff --git a/arch/x86_64/lib/getuser_64.S b/arch/x86/lib/getuser_64.S similarity index 100% rename from arch/x86_64/lib/getuser_64.S rename to arch/x86/lib/getuser_64.S diff --git a/arch/x86_64/lib/io_64.c b/arch/x86/lib/io_64.c similarity index 100% rename from arch/x86_64/lib/io_64.c rename to arch/x86/lib/io_64.c diff --git a/arch/x86_64/lib/iomap_copy_64.S b/arch/x86/lib/iomap_copy_64.S similarity index 100% rename from arch/x86_64/lib/iomap_copy_64.S rename to arch/x86/lib/iomap_copy_64.S diff --git a/arch/x86_64/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S similarity index 100% rename from arch/x86_64/lib/memcpy_64.S rename to arch/x86/lib/memcpy_64.S diff --git a/arch/x86_64/lib/memmove_64.c b/arch/x86/lib/memmove_64.c similarity index 100% rename from arch/x86_64/lib/memmove_64.c rename to arch/x86/lib/memmove_64.c diff --git a/arch/x86_64/lib/memset_64.S b/arch/x86/lib/memset_64.S similarity index 100% rename from arch/x86_64/lib/memset_64.S rename to arch/x86/lib/memset_64.S diff --git a/arch/x86_64/lib/putuser_64.S b/arch/x86/lib/putuser_64.S similarity index 100% rename from arch/x86_64/lib/putuser_64.S rename to arch/x86/lib/putuser_64.S diff --git a/arch/x86_64/lib/rwlock_64.S b/arch/x86/lib/rwlock_64.S similarity index 100% rename from arch/x86_64/lib/rwlock_64.S rename to arch/x86/lib/rwlock_64.S diff --git a/arch/x86_64/lib/thunk_64.S b/arch/x86/lib/thunk_64.S similarity index 100% rename from arch/x86_64/lib/thunk_64.S rename to arch/x86/lib/thunk_64.S diff --git a/arch/x86_64/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c similarity index 100% rename from arch/x86_64/lib/usercopy_64.c rename to arch/x86/lib/usercopy_64.c diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 265484c17234..ae48f179d719 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -73,7 +73,7 @@ AFLAGS += -m64 head-y := arch/x86_64/kernel/head_64.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task_64.o -libs-y += arch/x86_64/lib/ +libs-y += arch/x86/lib/ core-y += arch/x86_64/kernel/ \ arch/x86_64/mm/ \ arch/x86/crypto/ \ diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile deleted file mode 100644 index 2d7d724a2a6a..000000000000 --- a/arch/x86_64/lib/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/x86/lib/Makefile_32 -else -include ${srctree}/arch/x86_64/lib/Makefile_64 -endif diff --git a/arch/x86_64/lib/msr-on-cpu.c b/arch/x86_64/lib/msr-on-cpu.c deleted file mode 100644 index 5672d4190fbe..000000000000 --- a/arch/x86_64/lib/msr-on-cpu.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../x86/lib/msr-on-cpu.c" From 7648b1330c335601b7c09c25f77a03cda128fcab Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:10 +0200 Subject: [PATCH 2103/2804] x86_64: move vdso Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/{x86_64 => x86}/vdso/.gitignore | 0 arch/{x86_64 => x86}/vdso/Makefile | 0 arch/{x86_64 => x86}/vdso/vclock_gettime.c | 0 arch/{x86_64 => x86}/vdso/vdso-note.S | 0 arch/{x86_64 => x86}/vdso/vdso-start.S | 0 arch/x86/vdso/vdso.S | 2 ++ arch/{x86_64 => x86}/vdso/vdso.lds.S | 0 arch/{x86_64 => x86}/vdso/vextern.h | 0 arch/{x86_64 => x86}/vdso/vgetcpu.c | 0 arch/{x86_64 => x86}/vdso/vma.c | 0 arch/{x86_64 => x86}/vdso/voffset.h | 0 arch/{x86_64 => x86}/vdso/vvar.c | 0 arch/x86_64/Makefile | 2 +- arch/x86_64/vdso/vdso.S | 2 -- 14 files changed, 3 insertions(+), 3 deletions(-) rename arch/{x86_64 => x86}/vdso/.gitignore (100%) rename arch/{x86_64 => x86}/vdso/Makefile (100%) rename arch/{x86_64 => x86}/vdso/vclock_gettime.c (100%) rename arch/{x86_64 => x86}/vdso/vdso-note.S (100%) rename arch/{x86_64 => x86}/vdso/vdso-start.S (100%) create mode 100644 arch/x86/vdso/vdso.S rename arch/{x86_64 => x86}/vdso/vdso.lds.S (100%) rename arch/{x86_64 => x86}/vdso/vextern.h (100%) rename arch/{x86_64 => x86}/vdso/vgetcpu.c (100%) rename arch/{x86_64 => x86}/vdso/vma.c (100%) rename arch/{x86_64 => x86}/vdso/voffset.h (100%) rename arch/{x86_64 => x86}/vdso/vvar.c (100%) delete mode 100644 arch/x86_64/vdso/vdso.S diff --git a/arch/x86_64/vdso/.gitignore b/arch/x86/vdso/.gitignore similarity index 100% rename from arch/x86_64/vdso/.gitignore rename to arch/x86/vdso/.gitignore diff --git a/arch/x86_64/vdso/Makefile b/arch/x86/vdso/Makefile similarity index 100% rename from arch/x86_64/vdso/Makefile rename to arch/x86/vdso/Makefile diff --git a/arch/x86_64/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c similarity index 100% rename from arch/x86_64/vdso/vclock_gettime.c rename to arch/x86/vdso/vclock_gettime.c diff --git a/arch/x86_64/vdso/vdso-note.S b/arch/x86/vdso/vdso-note.S similarity index 100% rename from arch/x86_64/vdso/vdso-note.S rename to arch/x86/vdso/vdso-note.S diff --git a/arch/x86_64/vdso/vdso-start.S b/arch/x86/vdso/vdso-start.S similarity index 100% rename from arch/x86_64/vdso/vdso-start.S rename to arch/x86/vdso/vdso-start.S diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S new file mode 100644 index 000000000000..4b1620a1529e --- /dev/null +++ b/arch/x86/vdso/vdso.S @@ -0,0 +1,2 @@ + .section ".vdso","a" + .incbin "arch/x86/vdso/vdso.so" diff --git a/arch/x86_64/vdso/vdso.lds.S b/arch/x86/vdso/vdso.lds.S similarity index 100% rename from arch/x86_64/vdso/vdso.lds.S rename to arch/x86/vdso/vdso.lds.S diff --git a/arch/x86_64/vdso/vextern.h b/arch/x86/vdso/vextern.h similarity index 100% rename from arch/x86_64/vdso/vextern.h rename to arch/x86/vdso/vextern.h diff --git a/arch/x86_64/vdso/vgetcpu.c b/arch/x86/vdso/vgetcpu.c similarity index 100% rename from arch/x86_64/vdso/vgetcpu.c rename to arch/x86/vdso/vgetcpu.c diff --git a/arch/x86_64/vdso/vma.c b/arch/x86/vdso/vma.c similarity index 100% rename from arch/x86_64/vdso/vma.c rename to arch/x86/vdso/vma.c diff --git a/arch/x86_64/vdso/voffset.h b/arch/x86/vdso/voffset.h similarity index 100% rename from arch/x86_64/vdso/voffset.h rename to arch/x86/vdso/voffset.h diff --git a/arch/x86_64/vdso/vvar.c b/arch/x86/vdso/vvar.c similarity index 100% rename from arch/x86_64/vdso/vvar.c rename to arch/x86/vdso/vvar.c diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index ae48f179d719..d322592e38ab 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -77,7 +77,7 @@ libs-y += arch/x86/lib/ core-y += arch/x86_64/kernel/ \ arch/x86_64/mm/ \ arch/x86/crypto/ \ - arch/x86_64/vdso/ + arch/x86/vdso/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ drivers-$(CONFIG_PCI) += arch/x86_64/pci/ drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ diff --git a/arch/x86_64/vdso/vdso.S b/arch/x86_64/vdso/vdso.S deleted file mode 100644 index 92e80c1972a7..000000000000 --- a/arch/x86_64/vdso/vdso.S +++ /dev/null @@ -1,2 +0,0 @@ - .section ".vdso","a" - .incbin "arch/x86_64/vdso/vdso.so" From f68c065491ceda1ad00f8dc493e274a79b8c2ba4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:12 +0200 Subject: [PATCH 2104/2804] x86_64: move pci Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/pci/Makefile | 2 +- arch/{x86_64 => x86}/pci/Makefile_64 | 10 ---------- arch/{x86_64 => x86}/pci/k8-bus_64.c | 0 arch/{x86_64 => x86}/pci/mmconfig_64.c | 0 arch/x86_64/Makefile | 2 +- arch/x86_64/pci/Makefile | 5 ----- 6 files changed, 2 insertions(+), 17 deletions(-) rename arch/{x86_64 => x86}/pci/Makefile_64 (53%) rename arch/{x86_64 => x86}/pci/k8-bus_64.c (100%) rename arch/{x86_64 => x86}/pci/mmconfig_64.c (100%) delete mode 100644 arch/x86_64/pci/Makefile diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index b3e54c45d408..c5c8e485fc44 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) include ${srctree}/arch/x86/pci/Makefile_32 else -include ${srctree}/arch/x86_64/pci/Makefile_64 +include ${srctree}/arch/x86/pci/Makefile_64 endif diff --git a/arch/x86_64/pci/Makefile_64 b/arch/x86/pci/Makefile_64 similarity index 53% rename from arch/x86_64/pci/Makefile_64 rename to arch/x86/pci/Makefile_64 index 79b618b9e9d4..7d8c467bf143 100644 --- a/arch/x86_64/pci/Makefile_64 +++ b/arch/x86/pci/Makefile_64 @@ -15,13 +15,3 @@ obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o obj-$(CONFIG_NUMA) += k8-bus_64.o -direct-y += ../../x86/pci/direct.o -acpi-y += ../../x86/pci/acpi.o -legacy-y += ../../x86/pci/legacy.o -irq-y += ../../x86/pci/irq.o -common-y += ../../x86/pci/common.o -fixup-y += ../../x86/pci/fixup.o -i386-y += ../../x86/pci/i386.o -init-y += ../../x86/pci/init.o -early-y += ../../x86/pci/early.o -mmconfig-shared-y += ../../x86/pci/mmconfig-shared.o diff --git a/arch/x86_64/pci/k8-bus_64.c b/arch/x86/pci/k8-bus_64.c similarity index 100% rename from arch/x86_64/pci/k8-bus_64.c rename to arch/x86/pci/k8-bus_64.c diff --git a/arch/x86_64/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c similarity index 100% rename from arch/x86_64/pci/mmconfig_64.c rename to arch/x86/pci/mmconfig_64.c diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index d322592e38ab..c10c8233a893 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -79,7 +79,7 @@ core-y += arch/x86_64/kernel/ \ arch/x86/crypto/ \ arch/x86/vdso/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ -drivers-$(CONFIG_PCI) += arch/x86_64/pci/ +drivers-$(CONFIG_PCI) += arch/x86/pci/ drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ boot := arch/x86_64/boot diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile deleted file mode 100644 index b3e54c45d408..000000000000 --- a/arch/x86_64/pci/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/x86/pci/Makefile_32 -else -include ${srctree}/arch/x86_64/pci/Makefile_64 -endif From aadfb679c8eb9b83125833f03b5221889595b67c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:13 +0200 Subject: [PATCH 2105/2804] x86_64: move boot Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/boot/tools/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 arch/x86_64/boot/tools/.gitignore diff --git a/arch/x86_64/boot/tools/.gitignore b/arch/x86_64/boot/tools/.gitignore deleted file mode 100644 index 378eac25d311..000000000000 --- a/arch/x86_64/boot/tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build From 9e9b4573e4411ac5fcfb6ba04ad360d3de6414ba Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:15 +0200 Subject: [PATCH 2106/2804] x86_64: move boot Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/Makefile | 2 +- arch/{x86_64 => x86}/boot/compressed/Makefile_64 | 2 +- arch/{x86_64 => x86}/boot/compressed/head_64.S | 2 +- arch/{x86_64 => x86}/boot/compressed/misc_64.c | 0 arch/{x86_64 => x86}/boot/compressed/vmlinux_64.lds | 0 arch/{x86_64 => x86}/boot/compressed/vmlinux_64.scr | 0 arch/x86_64/boot/compressed/Makefile | 5 ----- 7 files changed, 3 insertions(+), 8 deletions(-) rename arch/{x86_64 => x86}/boot/compressed/Makefile_64 (94%) rename arch/{x86_64 => x86}/boot/compressed/head_64.S (99%) rename arch/{x86_64 => x86}/boot/compressed/misc_64.c (100%) rename arch/{x86_64 => x86}/boot/compressed/vmlinux_64.lds (100%) rename arch/{x86_64 => x86}/boot/compressed/vmlinux_64.scr (100%) delete mode 100644 arch/x86_64/boot/compressed/Makefile diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 76ab5caddf9a..52c1db854520 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) include ${srctree}/arch/x86/boot/compressed/Makefile_32 else -include ${srctree}/arch/x86_64/boot/compressed/Makefile_64 +include ${srctree}/arch/x86/boot/compressed/Makefile_64 endif diff --git a/arch/x86_64/boot/compressed/Makefile_64 b/arch/x86/boot/compressed/Makefile_64 similarity index 94% rename from arch/x86_64/boot/compressed/Makefile_64 rename to arch/x86/boot/compressed/Makefile_64 index 5bfd108f29d3..dc6b3380cc45 100644 --- a/arch/x86_64/boot/compressed/Makefile_64 +++ b/arch/x86/boot/compressed/Makefile_64 @@ -1,5 +1,5 @@ # -# linux/arch/x86_64/boot/compressed/Makefile +# linux/arch/x86/boot/compressed/Makefile # # create a compressed vmlinux image from the original vmlinux # diff --git a/arch/x86_64/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S similarity index 99% rename from arch/x86_64/boot/compressed/head_64.S rename to arch/x86/boot/compressed/head_64.S index 49467640751f..cff3d1dc5dd4 100644 --- a/arch/x86_64/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -174,7 +174,7 @@ no_longmode: hlt jmp 1b -#include "../../kernel/verify_cpu_64.S" +#include "../../../x86_64/kernel/verify_cpu_64.S" /* Be careful here startup_64 needs to be at a predictable * address so I can export it in an ELF header. Bootloaders diff --git a/arch/x86_64/boot/compressed/misc_64.c b/arch/x86/boot/compressed/misc_64.c similarity index 100% rename from arch/x86_64/boot/compressed/misc_64.c rename to arch/x86/boot/compressed/misc_64.c diff --git a/arch/x86_64/boot/compressed/vmlinux_64.lds b/arch/x86/boot/compressed/vmlinux_64.lds similarity index 100% rename from arch/x86_64/boot/compressed/vmlinux_64.lds rename to arch/x86/boot/compressed/vmlinux_64.lds diff --git a/arch/x86_64/boot/compressed/vmlinux_64.scr b/arch/x86/boot/compressed/vmlinux_64.scr similarity index 100% rename from arch/x86_64/boot/compressed/vmlinux_64.scr rename to arch/x86/boot/compressed/vmlinux_64.scr diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile deleted file mode 100644 index 76ab5caddf9a..000000000000 --- a/arch/x86_64/boot/compressed/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/x86/boot/compressed/Makefile_32 -else -include ${srctree}/arch/x86_64/boot/compressed/Makefile_64 -endif From 2a6c8d5a7e92a3e8db30fa0c5956a29c79d7e5a3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:16 +0200 Subject: [PATCH 2107/2804] x86_64: move boot Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/Makefile | 7 +++++-- arch/x86_64/boot/.gitignore | 5 ----- arch/x86_64/boot/Makefile | 9 --------- 3 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 arch/x86_64/boot/.gitignore delete mode 100644 arch/x86_64/boot/Makefile diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index c10c8233a893..11ef2c37ba57 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -82,7 +82,7 @@ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ drivers-$(CONFIG_PCI) += arch/x86/pci/ drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ -boot := arch/x86_64/boot +boot := arch/x86/boot PHONY += bzImage bzlilo install archmrproper \ fdimage fdimage144 fdimage288 isoimage archclean @@ -90,10 +90,12 @@ PHONY += bzImage bzlilo install archmrproper \ #Default target when executing "make" all: bzImage -BOOTIMAGE := arch/x86_64/boot/bzImage +BOOTIMAGE := arch/x86/boot/bzImage KBUILD_IMAGE := $(BOOTIMAGE) bzImage: vmlinux + $(Q)mkdir -p $(objtree)/arch/x86_64/boot + $(Q)ln -fsn $(objtree)/arch/x86/boot/bzImage $(objtree)/arch/x86_64/boot/bzImage $(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE) bzlilo: vmlinux @@ -109,6 +111,7 @@ install: $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@ archclean: + $(Q)rm -rf $(objtree)/arch/x86_64/boot $(Q)$(MAKE) $(clean)=$(boot) define archhelp diff --git a/arch/x86_64/boot/.gitignore b/arch/x86_64/boot/.gitignore deleted file mode 100644 index 18465143cfa2..000000000000 --- a/arch/x86_64/boot/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -bootsect -bzImage -setup -setup.bin -setup.elf diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile deleted file mode 100644 index 0f7b6c2cfa58..000000000000 --- a/arch/x86_64/boot/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# arch/x86_64/boot/Makefile -# -# The actual boot code is shared with i386 including the Makefile. -# So tell kbuild that we fetch the code from i386 and include the -# Makefile from i386 too. - -src := arch/x86/boot -include $(src)/Makefile From 95119fbd87aabc263746731462062af5a38c0222 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:18 +0200 Subject: [PATCH 2108/2804] x86_64: move mm Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/mm/Makefile | 2 +- arch/{x86_64 => x86}/mm/Makefile_64 | 1 - arch/{x86_64 => x86}/mm/extable_64.c | 0 arch/{x86_64 => x86}/mm/fault_64.c | 0 arch/{x86_64 => x86}/mm/init_64.c | 0 arch/{x86_64 => x86}/mm/ioremap_64.c | 0 arch/{x86_64 => x86}/mm/k8topology_64.c | 0 arch/{x86_64 => x86}/mm/mmap_64.c | 0 arch/{x86_64 => x86}/mm/numa_64.c | 0 arch/{x86_64 => x86}/mm/pageattr_64.c | 0 arch/{x86_64 => x86}/mm/srat_64.c | 0 arch/x86_64/Makefile | 2 +- arch/x86_64/mm/Makefile | 5 ----- 13 files changed, 2 insertions(+), 8 deletions(-) rename arch/{x86_64 => x86}/mm/Makefile_64 (87%) rename arch/{x86_64 => x86}/mm/extable_64.c (100%) rename arch/{x86_64 => x86}/mm/fault_64.c (100%) rename arch/{x86_64 => x86}/mm/init_64.c (100%) rename arch/{x86_64 => x86}/mm/ioremap_64.c (100%) rename arch/{x86_64 => x86}/mm/k8topology_64.c (100%) rename arch/{x86_64 => x86}/mm/mmap_64.c (100%) rename arch/{x86_64 => x86}/mm/numa_64.c (100%) rename arch/{x86_64 => x86}/mm/pageattr_64.c (100%) rename arch/{x86_64 => x86}/mm/srat_64.c (100%) delete mode 100644 arch/x86_64/mm/Makefile diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 7317648e6587..983291096848 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) include ${srctree}/arch/x86/mm/Makefile_32 else -include ${srctree}/arch/x86_64/mm/Makefile_64 +include ${srctree}/arch/x86/mm/Makefile_64 endif diff --git a/arch/x86_64/mm/Makefile_64 b/arch/x86/mm/Makefile_64 similarity index 87% rename from arch/x86_64/mm/Makefile_64 rename to arch/x86/mm/Makefile_64 index 5c2883cad11b..6bcb47945b87 100644 --- a/arch/x86_64/mm/Makefile_64 +++ b/arch/x86/mm/Makefile_64 @@ -8,4 +8,3 @@ obj-$(CONFIG_NUMA) += numa_64.o obj-$(CONFIG_K8_NUMA) += k8topology_64.o obj-$(CONFIG_ACPI_NUMA) += srat_64.o -hugetlbpage-y = ../../x86/mm/hugetlbpage.o diff --git a/arch/x86_64/mm/extable_64.c b/arch/x86/mm/extable_64.c similarity index 100% rename from arch/x86_64/mm/extable_64.c rename to arch/x86/mm/extable_64.c diff --git a/arch/x86_64/mm/fault_64.c b/arch/x86/mm/fault_64.c similarity index 100% rename from arch/x86_64/mm/fault_64.c rename to arch/x86/mm/fault_64.c diff --git a/arch/x86_64/mm/init_64.c b/arch/x86/mm/init_64.c similarity index 100% rename from arch/x86_64/mm/init_64.c rename to arch/x86/mm/init_64.c diff --git a/arch/x86_64/mm/ioremap_64.c b/arch/x86/mm/ioremap_64.c similarity index 100% rename from arch/x86_64/mm/ioremap_64.c rename to arch/x86/mm/ioremap_64.c diff --git a/arch/x86_64/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c similarity index 100% rename from arch/x86_64/mm/k8topology_64.c rename to arch/x86/mm/k8topology_64.c diff --git a/arch/x86_64/mm/mmap_64.c b/arch/x86/mm/mmap_64.c similarity index 100% rename from arch/x86_64/mm/mmap_64.c rename to arch/x86/mm/mmap_64.c diff --git a/arch/x86_64/mm/numa_64.c b/arch/x86/mm/numa_64.c similarity index 100% rename from arch/x86_64/mm/numa_64.c rename to arch/x86/mm/numa_64.c diff --git a/arch/x86_64/mm/pageattr_64.c b/arch/x86/mm/pageattr_64.c similarity index 100% rename from arch/x86_64/mm/pageattr_64.c rename to arch/x86/mm/pageattr_64.c diff --git a/arch/x86_64/mm/srat_64.c b/arch/x86/mm/srat_64.c similarity index 100% rename from arch/x86_64/mm/srat_64.c rename to arch/x86/mm/srat_64.c diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 11ef2c37ba57..4208a0ded529 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -75,7 +75,7 @@ head-y := arch/x86_64/kernel/head_64.o arch/x86_64/kernel/head64.o arch/x86_64/k libs-y += arch/x86/lib/ core-y += arch/x86_64/kernel/ \ - arch/x86_64/mm/ \ + arch/x86/mm/ \ arch/x86/crypto/ \ arch/x86/vdso/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ diff --git a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile deleted file mode 100644 index 7317648e6587..000000000000 --- a/arch/x86_64/mm/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/x86/mm/Makefile_32 -else -include ${srctree}/arch/x86_64/mm/Makefile_64 -endif From 33fc6d51336046bd6e8c7d1a42faff881fa6fb45 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:19 +0200 Subject: [PATCH 2109/2804] x86_64: move oprofile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86_64/Kconfig | 2 +- arch/x86_64/oprofile/Kconfig | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 arch/x86_64/oprofile/Kconfig diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 17d57617a41d..b1b98e614f7c 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -778,7 +778,7 @@ source fs/Kconfig menu "Instrumentation Support" depends on EXPERIMENTAL -source "arch/x86_64/oprofile/Kconfig" +source "arch/x86/oprofile/Kconfig" config KPROBES bool "Kprobes" diff --git a/arch/x86_64/oprofile/Kconfig b/arch/x86_64/oprofile/Kconfig deleted file mode 100644 index d8a84088471a..000000000000 --- a/arch/x86_64/oprofile/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config PROFILING - bool "Profiling support (EXPERIMENTAL)" - help - Say Y here to enable the extended profiling support mechanisms used - by profilers such as OProfile. - - -config OPROFILE - tristate "OProfile system profiling (EXPERIMENTAL)" - depends on PROFILING - help - OProfile is a profiling system capable of profiling the - whole system, include the kernel, kernel modules, libraries, - and applications. - - If unsure, say N. - From 2db55d344e529492545cb3b755c7e9ba8e4fa94e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:21 +0200 Subject: [PATCH 2110/2804] x86_64: move ia32 Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/{x86_64 => x86}/ia32/Makefile | 0 arch/{x86_64 => x86}/ia32/audit.c | 0 arch/{x86_64 => x86}/ia32/fpu32.c | 0 arch/{x86_64 => x86}/ia32/ia32_aout.c | 0 arch/{x86_64 => x86}/ia32/ia32_binfmt.c | 0 arch/{x86_64 => x86}/ia32/ia32_signal.c | 0 arch/{x86_64 => x86}/ia32/ia32entry.S | 0 arch/{x86_64 => x86}/ia32/ipc32.c | 0 arch/{x86_64 => x86}/ia32/mmap32.c | 0 arch/{x86_64 => x86}/ia32/ptrace32.c | 0 arch/{x86_64 => x86}/ia32/sys_ia32.c | 0 arch/{x86_64 => x86}/ia32/syscall32.c | 0 arch/{x86_64 => x86}/ia32/syscall32_syscall.S | 4 ++-- arch/{x86_64 => x86}/ia32/tls32.c | 0 arch/{x86_64 => x86}/ia32/vsyscall-sigreturn.S | 0 arch/{x86_64 => x86}/ia32/vsyscall-syscall.S | 0 arch/{x86_64 => x86}/ia32/vsyscall-sysenter.S | 0 arch/{x86_64 => x86}/ia32/vsyscall.lds | 0 arch/x86_64/Makefile | 2 +- 19 files changed, 3 insertions(+), 3 deletions(-) rename arch/{x86_64 => x86}/ia32/Makefile (100%) rename arch/{x86_64 => x86}/ia32/audit.c (100%) rename arch/{x86_64 => x86}/ia32/fpu32.c (100%) rename arch/{x86_64 => x86}/ia32/ia32_aout.c (100%) rename arch/{x86_64 => x86}/ia32/ia32_binfmt.c (100%) rename arch/{x86_64 => x86}/ia32/ia32_signal.c (100%) rename arch/{x86_64 => x86}/ia32/ia32entry.S (100%) rename arch/{x86_64 => x86}/ia32/ipc32.c (100%) rename arch/{x86_64 => x86}/ia32/mmap32.c (100%) rename arch/{x86_64 => x86}/ia32/ptrace32.c (100%) rename arch/{x86_64 => x86}/ia32/sys_ia32.c (100%) rename arch/{x86_64 => x86}/ia32/syscall32.c (100%) rename arch/{x86_64 => x86}/ia32/syscall32_syscall.S (73%) rename arch/{x86_64 => x86}/ia32/tls32.c (100%) rename arch/{x86_64 => x86}/ia32/vsyscall-sigreturn.S (100%) rename arch/{x86_64 => x86}/ia32/vsyscall-syscall.S (100%) rename arch/{x86_64 => x86}/ia32/vsyscall-sysenter.S (100%) rename arch/{x86_64 => x86}/ia32/vsyscall.lds (100%) diff --git a/arch/x86_64/ia32/Makefile b/arch/x86/ia32/Makefile similarity index 100% rename from arch/x86_64/ia32/Makefile rename to arch/x86/ia32/Makefile diff --git a/arch/x86_64/ia32/audit.c b/arch/x86/ia32/audit.c similarity index 100% rename from arch/x86_64/ia32/audit.c rename to arch/x86/ia32/audit.c diff --git a/arch/x86_64/ia32/fpu32.c b/arch/x86/ia32/fpu32.c similarity index 100% rename from arch/x86_64/ia32/fpu32.c rename to arch/x86/ia32/fpu32.c diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c similarity index 100% rename from arch/x86_64/ia32/ia32_aout.c rename to arch/x86/ia32/ia32_aout.c diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86/ia32/ia32_binfmt.c similarity index 100% rename from arch/x86_64/ia32/ia32_binfmt.c rename to arch/x86/ia32/ia32_binfmt.c diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c similarity index 100% rename from arch/x86_64/ia32/ia32_signal.c rename to arch/x86/ia32/ia32_signal.c diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S similarity index 100% rename from arch/x86_64/ia32/ia32entry.S rename to arch/x86/ia32/ia32entry.S diff --git a/arch/x86_64/ia32/ipc32.c b/arch/x86/ia32/ipc32.c similarity index 100% rename from arch/x86_64/ia32/ipc32.c rename to arch/x86/ia32/ipc32.c diff --git a/arch/x86_64/ia32/mmap32.c b/arch/x86/ia32/mmap32.c similarity index 100% rename from arch/x86_64/ia32/mmap32.c rename to arch/x86/ia32/mmap32.c diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86/ia32/ptrace32.c similarity index 100% rename from arch/x86_64/ia32/ptrace32.c rename to arch/x86/ia32/ptrace32.c diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c similarity index 100% rename from arch/x86_64/ia32/sys_ia32.c rename to arch/x86/ia32/sys_ia32.c diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86/ia32/syscall32.c similarity index 100% rename from arch/x86_64/ia32/syscall32.c rename to arch/x86/ia32/syscall32.c diff --git a/arch/x86_64/ia32/syscall32_syscall.S b/arch/x86/ia32/syscall32_syscall.S similarity index 73% rename from arch/x86_64/ia32/syscall32_syscall.S rename to arch/x86/ia32/syscall32_syscall.S index 8f8271bdf135..933f0f08b1cf 100644 --- a/arch/x86_64/ia32/syscall32_syscall.S +++ b/arch/x86/ia32/syscall32_syscall.S @@ -6,12 +6,12 @@ .globl syscall32_syscall_end syscall32_syscall: - .incbin "arch/x86_64/ia32/vsyscall-syscall.so" + .incbin "arch/x86/ia32/vsyscall-syscall.so" syscall32_syscall_end: .globl syscall32_sysenter .globl syscall32_sysenter_end syscall32_sysenter: - .incbin "arch/x86_64/ia32/vsyscall-sysenter.so" + .incbin "arch/x86/ia32/vsyscall-sysenter.so" syscall32_sysenter_end: diff --git a/arch/x86_64/ia32/tls32.c b/arch/x86/ia32/tls32.c similarity index 100% rename from arch/x86_64/ia32/tls32.c rename to arch/x86/ia32/tls32.c diff --git a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86/ia32/vsyscall-sigreturn.S similarity index 100% rename from arch/x86_64/ia32/vsyscall-sigreturn.S rename to arch/x86/ia32/vsyscall-sigreturn.S diff --git a/arch/x86_64/ia32/vsyscall-syscall.S b/arch/x86/ia32/vsyscall-syscall.S similarity index 100% rename from arch/x86_64/ia32/vsyscall-syscall.S rename to arch/x86/ia32/vsyscall-syscall.S diff --git a/arch/x86_64/ia32/vsyscall-sysenter.S b/arch/x86/ia32/vsyscall-sysenter.S similarity index 100% rename from arch/x86_64/ia32/vsyscall-sysenter.S rename to arch/x86/ia32/vsyscall-sysenter.S diff --git a/arch/x86_64/ia32/vsyscall.lds b/arch/x86/ia32/vsyscall.lds similarity index 100% rename from arch/x86_64/ia32/vsyscall.lds rename to arch/x86/ia32/vsyscall.lds diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 4208a0ded529..189d80d3a891 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -78,7 +78,7 @@ core-y += arch/x86_64/kernel/ \ arch/x86/mm/ \ arch/x86/crypto/ \ arch/x86/vdso/ -core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ +core-$(CONFIG_IA32_EMULATION) += arch/x86/ia32/ drivers-$(CONFIG_PCI) += arch/x86/pci/ drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ From 250c22777fe1ccd7ac588579a6c16db4c0161cc5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:24 +0200 Subject: [PATCH 2111/2804] x86_64: move kernel Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/head_64.S | 2 +- arch/x86/kernel/Makefile | 2 +- arch/x86/kernel/Makefile_32 | 2 - arch/{x86_64 => x86}/kernel/Makefile_64 | 9 - arch/x86/kernel/acpi/wakeup_64.S | 2 +- arch/{x86_64 => x86}/kernel/aperture_64.c | 0 arch/{x86_64 => x86}/kernel/apic_64.c | 0 arch/{x86_64 => x86}/kernel/asm-offsets_64.c | 0 arch/{x86_64 => x86}/kernel/audit_64.c | 0 arch/{x86_64 => x86}/kernel/bugs_64.c | 0 arch/{x86_64 => x86}/kernel/crash_64.c | 0 arch/{x86_64 => x86}/kernel/crash_dump_64.c | 0 arch/{x86_64 => x86}/kernel/e820_64.c | 0 arch/{x86_64 => x86}/kernel/early-quirks_64.c | 0 arch/x86/kernel/early_printk.c | 259 +++++++++++++++++- arch/{x86_64 => x86}/kernel/entry_64.S | 0 arch/{x86_64 => x86}/kernel/genapic_64.c | 0 arch/{x86_64 => x86}/kernel/genapic_flat_64.c | 0 arch/{x86_64 => x86}/kernel/head64.c | 0 arch/{x86_64 => x86}/kernel/head_64.S | 0 arch/{x86_64 => x86}/kernel/hpet_64.c | 0 arch/{x86_64 => x86}/kernel/i387_64.c | 0 arch/{x86_64 => x86}/kernel/i8259_64.c | 0 arch/{x86_64 => x86}/kernel/init_task_64.c | 0 arch/{x86_64 => x86}/kernel/io_apic_64.c | 0 arch/{x86_64 => x86}/kernel/ioport_64.c | 0 arch/{x86_64 => x86}/kernel/irq_64.c | 0 arch/{x86_64 => x86}/kernel/k8.c | 0 arch/{x86_64 => x86}/kernel/kprobes_64.c | 0 arch/{x86_64 => x86}/kernel/ldt_64.c | 0 .../{x86_64 => x86}/kernel/machine_kexec_64.c | 0 arch/{x86_64 => x86}/kernel/mce_64.c | 0 arch/{x86_64 => x86}/kernel/mce_amd_64.c | 0 arch/{x86_64 => x86}/kernel/mce_intel_64.c | 0 arch/{x86_64 => x86}/kernel/module_64.c | 0 arch/{x86_64 => x86}/kernel/mpparse_64.c | 0 arch/{x86_64 => x86}/kernel/nmi_64.c | 0 arch/{x86_64 => x86}/kernel/pci-calgary_64.c | 0 arch/{x86_64 => x86}/kernel/pci-dma_64.c | 0 arch/{x86_64 => x86}/kernel/pci-gart_64.c | 0 arch/{x86_64 => x86}/kernel/pci-nommu_64.c | 0 arch/{x86_64 => x86}/kernel/pci-swiotlb_64.c | 0 arch/{x86_64 => x86}/kernel/pmtimer_64.c | 0 arch/{x86_64 => x86}/kernel/process_64.c | 0 arch/{x86_64 => x86}/kernel/ptrace_64.c | 0 arch/{x86_64 => x86}/kernel/reboot_64.c | 0 .../kernel/relocate_kernel_64.S | 0 arch/{x86_64 => x86}/kernel/setup64.c | 0 arch/{x86_64 => x86}/kernel/setup_64.c | 0 arch/{x86_64 => x86}/kernel/signal_64.c | 0 arch/{x86_64 => x86}/kernel/smp_64.c | 0 arch/{x86_64 => x86}/kernel/smpboot_64.c | 0 arch/{x86_64 => x86}/kernel/stacktrace.c | 0 arch/{x86_64 => x86}/kernel/suspend_64.c | 0 arch/{x86_64 => x86}/kernel/suspend_asm_64.S | 0 arch/{x86_64 => x86}/kernel/sys_x86_64.c | 0 arch/{x86_64 => x86}/kernel/syscall_64.c | 0 arch/{x86_64 => x86}/kernel/tce_64.c | 0 arch/{x86_64 => x86}/kernel/time_64.c | 0 arch/{x86_64 => x86}/kernel/trampoline_64.S | 0 arch/{x86_64 => x86}/kernel/traps_64.c | 0 arch/{x86_64 => x86}/kernel/tsc_64.c | 0 arch/x86/kernel/tsc_sync.c | 188 ++++++++++++- arch/{x86_64 => x86}/kernel/verify_cpu_64.S | 0 arch/{x86_64 => x86}/kernel/vmlinux_64.lds.S | 0 arch/{x86_64 => x86}/kernel/vsmp_64.c | 0 arch/{x86_64 => x86}/kernel/vsyscall_64.c | 0 arch/{x86_64 => x86}/kernel/x8664_ksyms_64.c | 0 arch/x86_64/Makefile | 11 +- arch/x86_64/kernel/Makefile | 5 - arch/x86_64/kernel/asm-offsets.c | 5 - arch/x86_64/kernel/early_printk.c | 259 ------------------ arch/x86_64/kernel/tsc_sync.c | 187 ------------- arch/x86_64/kernel/vmlinux.lds.S | 5 - 74 files changed, 457 insertions(+), 479 deletions(-) rename arch/{x86_64 => x86}/kernel/Makefile_64 (81%) rename arch/{x86_64 => x86}/kernel/aperture_64.c (100%) rename arch/{x86_64 => x86}/kernel/apic_64.c (100%) rename arch/{x86_64 => x86}/kernel/asm-offsets_64.c (100%) rename arch/{x86_64 => x86}/kernel/audit_64.c (100%) rename arch/{x86_64 => x86}/kernel/bugs_64.c (100%) rename arch/{x86_64 => x86}/kernel/crash_64.c (100%) rename arch/{x86_64 => x86}/kernel/crash_dump_64.c (100%) rename arch/{x86_64 => x86}/kernel/e820_64.c (100%) rename arch/{x86_64 => x86}/kernel/early-quirks_64.c (100%) rename arch/{x86_64 => x86}/kernel/entry_64.S (100%) rename arch/{x86_64 => x86}/kernel/genapic_64.c (100%) rename arch/{x86_64 => x86}/kernel/genapic_flat_64.c (100%) rename arch/{x86_64 => x86}/kernel/head64.c (100%) rename arch/{x86_64 => x86}/kernel/head_64.S (100%) rename arch/{x86_64 => x86}/kernel/hpet_64.c (100%) rename arch/{x86_64 => x86}/kernel/i387_64.c (100%) rename arch/{x86_64 => x86}/kernel/i8259_64.c (100%) rename arch/{x86_64 => x86}/kernel/init_task_64.c (100%) rename arch/{x86_64 => x86}/kernel/io_apic_64.c (100%) rename arch/{x86_64 => x86}/kernel/ioport_64.c (100%) rename arch/{x86_64 => x86}/kernel/irq_64.c (100%) rename arch/{x86_64 => x86}/kernel/k8.c (100%) rename arch/{x86_64 => x86}/kernel/kprobes_64.c (100%) rename arch/{x86_64 => x86}/kernel/ldt_64.c (100%) rename arch/{x86_64 => x86}/kernel/machine_kexec_64.c (100%) rename arch/{x86_64 => x86}/kernel/mce_64.c (100%) rename arch/{x86_64 => x86}/kernel/mce_amd_64.c (100%) rename arch/{x86_64 => x86}/kernel/mce_intel_64.c (100%) rename arch/{x86_64 => x86}/kernel/module_64.c (100%) rename arch/{x86_64 => x86}/kernel/mpparse_64.c (100%) rename arch/{x86_64 => x86}/kernel/nmi_64.c (100%) rename arch/{x86_64 => x86}/kernel/pci-calgary_64.c (100%) rename arch/{x86_64 => x86}/kernel/pci-dma_64.c (100%) rename arch/{x86_64 => x86}/kernel/pci-gart_64.c (100%) rename arch/{x86_64 => x86}/kernel/pci-nommu_64.c (100%) rename arch/{x86_64 => x86}/kernel/pci-swiotlb_64.c (100%) rename arch/{x86_64 => x86}/kernel/pmtimer_64.c (100%) rename arch/{x86_64 => x86}/kernel/process_64.c (100%) rename arch/{x86_64 => x86}/kernel/ptrace_64.c (100%) rename arch/{x86_64 => x86}/kernel/reboot_64.c (100%) rename arch/{x86_64 => x86}/kernel/relocate_kernel_64.S (100%) rename arch/{x86_64 => x86}/kernel/setup64.c (100%) rename arch/{x86_64 => x86}/kernel/setup_64.c (100%) rename arch/{x86_64 => x86}/kernel/signal_64.c (100%) rename arch/{x86_64 => x86}/kernel/smp_64.c (100%) rename arch/{x86_64 => x86}/kernel/smpboot_64.c (100%) rename arch/{x86_64 => x86}/kernel/stacktrace.c (100%) rename arch/{x86_64 => x86}/kernel/suspend_64.c (100%) rename arch/{x86_64 => x86}/kernel/suspend_asm_64.S (100%) rename arch/{x86_64 => x86}/kernel/sys_x86_64.c (100%) rename arch/{x86_64 => x86}/kernel/syscall_64.c (100%) rename arch/{x86_64 => x86}/kernel/tce_64.c (100%) rename arch/{x86_64 => x86}/kernel/time_64.c (100%) rename arch/{x86_64 => x86}/kernel/trampoline_64.S (100%) rename arch/{x86_64 => x86}/kernel/traps_64.c (100%) rename arch/{x86_64 => x86}/kernel/tsc_64.c (100%) rename arch/{x86_64 => x86}/kernel/verify_cpu_64.S (100%) rename arch/{x86_64 => x86}/kernel/vmlinux_64.lds.S (100%) rename arch/{x86_64 => x86}/kernel/vsmp_64.c (100%) rename arch/{x86_64 => x86}/kernel/vsyscall_64.c (100%) rename arch/{x86_64 => x86}/kernel/x8664_ksyms_64.c (100%) delete mode 100644 arch/x86_64/kernel/Makefile delete mode 100644 arch/x86_64/kernel/asm-offsets.c delete mode 100644 arch/x86_64/kernel/early_printk.c delete mode 100644 arch/x86_64/kernel/tsc_sync.c delete mode 100644 arch/x86_64/kernel/vmlinux.lds.S diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index cff3d1dc5dd4..49467640751f 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -174,7 +174,7 @@ no_longmode: hlt jmp 1b -#include "../../../x86_64/kernel/verify_cpu_64.S" +#include "../../kernel/verify_cpu_64.S" /* Be careful here startup_64 needs to be at a predictable * address so I can export it in an ELF header. Bootloaders diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 577d08f4b8bb..45855c97923e 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) include ${srctree}/arch/x86/kernel/Makefile_32 else -include ${srctree}/arch/x86_64/kernel/Makefile_64 +include ${srctree}/arch/x86/kernel/Makefile_64 endif diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 index 5096f486d389..cb25523026a6 100644 --- a/arch/x86/kernel/Makefile_32 +++ b/arch/x86/kernel/Makefile_32 @@ -83,6 +83,4 @@ $(obj)/vsyscall-syms.o: $(src)/vsyscall_32.lds \ $(obj)/vsyscall-sysenter_32.o $(obj)/vsyscall-note_32.o FORCE $(call if_changed,syscall) -k8-y += ../../x86_64/kernel/k8.o -stacktrace-y += ../../x86_64/kernel/stacktrace.o diff --git a/arch/x86_64/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64 similarity index 81% rename from arch/x86_64/kernel/Makefile_64 rename to arch/x86/kernel/Makefile_64 index 120d4e51fd4d..6e6b5909e465 100644 --- a/arch/x86_64/kernel/Makefile_64 +++ b/arch/x86/kernel/Makefile_64 @@ -49,15 +49,6 @@ obj-y += pcspeaker.o CFLAGS_vsyscall_64.o := $(PROFILING) -g0 therm_throt-y += ../../x86/kernel/cpu/mcheck/therm_throt.o -bootflag-y += ../../x86/kernel/bootflag.o -cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../x86/kernel/cpuid.o -topology-y += ../../x86/kernel/topology.o -microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../x86/kernel/microcode.o intel_cacheinfo-y += ../../x86/kernel/cpu/intel_cacheinfo.o addon_cpuid_features-y += ../../x86/kernel/cpu/addon_cpuid_features.o -quirks-y += ../../x86/kernel/quirks.o -i8237-y += ../../x86/kernel/i8237.o -msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../x86/kernel/msr.o -alternative-y += ../../x86/kernel/alternative.o -pcspeaker-y += ../../x86/kernel/pcspeaker.o perfctr-watchdog-y += ../../x86/kernel/cpu/perfctr-watchdog.o diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 5e3b3f5496c5..8b4357e1efe0 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -269,7 +269,7 @@ no_longmode: movb $0xbc,%al ; outb %al,$0x80 jmp no_longmode -#include "../../../x86_64/kernel/verify_cpu_64.S" +#include "../verify_cpu_64.S" /* This code uses an extended set of video mode numbers. These include: * Aliases for standard modes diff --git a/arch/x86_64/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c similarity index 100% rename from arch/x86_64/kernel/aperture_64.c rename to arch/x86/kernel/aperture_64.c diff --git a/arch/x86_64/kernel/apic_64.c b/arch/x86/kernel/apic_64.c similarity index 100% rename from arch/x86_64/kernel/apic_64.c rename to arch/x86/kernel/apic_64.c diff --git a/arch/x86_64/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c similarity index 100% rename from arch/x86_64/kernel/asm-offsets_64.c rename to arch/x86/kernel/asm-offsets_64.c diff --git a/arch/x86_64/kernel/audit_64.c b/arch/x86/kernel/audit_64.c similarity index 100% rename from arch/x86_64/kernel/audit_64.c rename to arch/x86/kernel/audit_64.c diff --git a/arch/x86_64/kernel/bugs_64.c b/arch/x86/kernel/bugs_64.c similarity index 100% rename from arch/x86_64/kernel/bugs_64.c rename to arch/x86/kernel/bugs_64.c diff --git a/arch/x86_64/kernel/crash_64.c b/arch/x86/kernel/crash_64.c similarity index 100% rename from arch/x86_64/kernel/crash_64.c rename to arch/x86/kernel/crash_64.c diff --git a/arch/x86_64/kernel/crash_dump_64.c b/arch/x86/kernel/crash_dump_64.c similarity index 100% rename from arch/x86_64/kernel/crash_dump_64.c rename to arch/x86/kernel/crash_dump_64.c diff --git a/arch/x86_64/kernel/e820_64.c b/arch/x86/kernel/e820_64.c similarity index 100% rename from arch/x86_64/kernel/e820_64.c rename to arch/x86/kernel/e820_64.c diff --git a/arch/x86_64/kernel/early-quirks_64.c b/arch/x86/kernel/early-quirks_64.c similarity index 100% rename from arch/x86_64/kernel/early-quirks_64.c rename to arch/x86/kernel/early-quirks_64.c diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index 92f812ba275c..fd9aff3f3890 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -1,2 +1,259 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "../../x86_64/kernel/early_printk.c" +/* Simple VGA output */ + +#ifdef __i386__ +#include +#else +#include +#endif +#define VGABASE (__ISA_IO_base + 0xb8000) + +static int max_ypos = 25, max_xpos = 80; +static int current_ypos = 25, current_xpos = 0; + +static void early_vga_write(struct console *con, const char *str, unsigned n) +{ + char c; + int i, k, j; + + while ((c = *str++) != '\0' && n-- > 0) { + if (current_ypos >= max_ypos) { + /* scroll 1 line up */ + for (k = 1, j = 0; k < max_ypos; k++, j++) { + for (i = 0; i < max_xpos; i++) { + writew(readw(VGABASE+2*(max_xpos*k+i)), + VGABASE + 2*(max_xpos*j + i)); + } + } + for (i = 0; i < max_xpos; i++) + writew(0x720, VGABASE + 2*(max_xpos*j + i)); + current_ypos = max_ypos-1; + } + if (c == '\n') { + current_xpos = 0; + current_ypos++; + } else if (c != '\r') { + writew(((0x7 << 8) | (unsigned short) c), + VGABASE + 2*(max_xpos*current_ypos + + current_xpos++)); + if (current_xpos >= max_xpos) { + current_xpos = 0; + current_ypos++; + } + } + } +} + +static struct console early_vga_console = { + .name = "earlyvga", + .write = early_vga_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* Serial functions loosely based on a similar package from Klaus P. Gerlicher */ + +static int early_serial_base = 0x3f8; /* ttyS0 */ + +#define XMTRDY 0x20 + +#define DLAB 0x80 + +#define TXR 0 /* Transmit register (WRITE) */ +#define RXR 0 /* Receive register (READ) */ +#define IER 1 /* Interrupt Enable */ +#define IIR 2 /* Interrupt ID */ +#define FCR 2 /* FIFO control */ +#define LCR 3 /* Line control */ +#define MCR 4 /* Modem control */ +#define LSR 5 /* Line Status */ +#define MSR 6 /* Modem Status */ +#define DLL 0 /* Divisor Latch Low */ +#define DLH 1 /* Divisor latch High */ + +static int early_serial_putc(unsigned char ch) +{ + unsigned timeout = 0xffff; + while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) + cpu_relax(); + outb(ch, early_serial_base + TXR); + return timeout ? 0 : -1; +} + +static void early_serial_write(struct console *con, const char *s, unsigned n) +{ + while (*s && n-- > 0) { + if (*s == '\n') + early_serial_putc('\r'); + early_serial_putc(*s); + s++; + } +} + +#define DEFAULT_BAUD 9600 + +static __init void early_serial_init(char *s) +{ + unsigned char c; + unsigned divisor; + unsigned baud = DEFAULT_BAUD; + char *e; + + if (*s == ',') + ++s; + + if (*s) { + unsigned port; + if (!strncmp(s,"0x",2)) { + early_serial_base = simple_strtoul(s, &e, 16); + } else { + static int bases[] = { 0x3f8, 0x2f8 }; + + if (!strncmp(s,"ttyS",4)) + s += 4; + port = simple_strtoul(s, &e, 10); + if (port > 1 || s == e) + port = 0; + early_serial_base = bases[port]; + } + s += strcspn(s, ","); + if (*s == ',') + s++; + } + + outb(0x3, early_serial_base + LCR); /* 8n1 */ + outb(0, early_serial_base + IER); /* no interrupt */ + outb(0, early_serial_base + FCR); /* no fifo */ + outb(0x3, early_serial_base + MCR); /* DTR + RTS */ + + if (*s) { + baud = simple_strtoul(s, &e, 0); + if (baud == 0 || s == e) + baud = DEFAULT_BAUD; + } + + divisor = 115200 / baud; + c = inb(early_serial_base + LCR); + outb(c | DLAB, early_serial_base + LCR); + outb(divisor & 0xff, early_serial_base + DLL); + outb((divisor >> 8) & 0xff, early_serial_base + DLH); + outb(c & ~DLAB, early_serial_base + LCR); +} + +static struct console early_serial_console = { + .name = "earlyser", + .write = early_serial_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* Console interface to a host file on AMD's SimNow! */ + +static int simnow_fd; + +enum { + MAGIC1 = 0xBACCD00A, + MAGIC2 = 0xCA110000, + XOPEN = 5, + XWRITE = 4, +}; + +static noinline long simnow(long cmd, long a, long b, long c) +{ + long ret; + asm volatile("cpuid" : + "=a" (ret) : + "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); + return ret; +} + +static void __init simnow_init(char *str) +{ + char *fn = "klog"; + if (*str == '=') + fn = ++str; + /* error ignored */ + simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644); +} + +static void simnow_write(struct console *con, const char *s, unsigned n) +{ + simnow(XWRITE, simnow_fd, (unsigned long)s, n); +} + +static struct console simnow_console = { + .name = "simnow", + .write = simnow_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* Direct interface for emergencies */ +struct console *early_console = &early_vga_console; +static int early_console_initialized = 0; + +void early_printk(const char *fmt, ...) +{ + char buf[512]; + int n; + va_list ap; + + va_start(ap,fmt); + n = vscnprintf(buf,512,fmt,ap); + early_console->write(early_console,buf,n); + va_end(ap); +} + +static int __initdata keep_early; + +static int __init setup_early_printk(char *buf) +{ + if (!buf) + return 0; + + if (early_console_initialized) + return 0; + early_console_initialized = 1; + + if (strstr(buf, "keep")) + keep_early = 1; + + if (!strncmp(buf, "serial", 6)) { + early_serial_init(buf + 6); + early_console = &early_serial_console; + } else if (!strncmp(buf, "ttyS", 4)) { + early_serial_init(buf); + early_console = &early_serial_console; + } else if (!strncmp(buf, "vga", 3) + && SCREEN_INFO.orig_video_isVGA == 1) { + max_xpos = SCREEN_INFO.orig_video_cols; + max_ypos = SCREEN_INFO.orig_video_lines; + current_ypos = SCREEN_INFO.orig_y; + early_console = &early_vga_console; + } else if (!strncmp(buf, "simnow", 6)) { + simnow_init(buf + 6); + early_console = &simnow_console; + keep_early = 1; +#ifdef CONFIG_HVC_XEN + } else if (!strncmp(buf, "xen", 3)) { + early_console = &xenboot_console; +#endif + } + + if (keep_early) + early_console->flags &= ~CON_BOOT; + else + early_console->flags |= CON_BOOT; + register_console(early_console); + return 0; +} +early_param("earlyprintk", setup_early_printk); diff --git a/arch/x86_64/kernel/entry_64.S b/arch/x86/kernel/entry_64.S similarity index 100% rename from arch/x86_64/kernel/entry_64.S rename to arch/x86/kernel/entry_64.S diff --git a/arch/x86_64/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c similarity index 100% rename from arch/x86_64/kernel/genapic_64.c rename to arch/x86/kernel/genapic_64.c diff --git a/arch/x86_64/kernel/genapic_flat_64.c b/arch/x86/kernel/genapic_flat_64.c similarity index 100% rename from arch/x86_64/kernel/genapic_flat_64.c rename to arch/x86/kernel/genapic_flat_64.c diff --git a/arch/x86_64/kernel/head64.c b/arch/x86/kernel/head64.c similarity index 100% rename from arch/x86_64/kernel/head64.c rename to arch/x86/kernel/head64.c diff --git a/arch/x86_64/kernel/head_64.S b/arch/x86/kernel/head_64.S similarity index 100% rename from arch/x86_64/kernel/head_64.S rename to arch/x86/kernel/head_64.S diff --git a/arch/x86_64/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c similarity index 100% rename from arch/x86_64/kernel/hpet_64.c rename to arch/x86/kernel/hpet_64.c diff --git a/arch/x86_64/kernel/i387_64.c b/arch/x86/kernel/i387_64.c similarity index 100% rename from arch/x86_64/kernel/i387_64.c rename to arch/x86/kernel/i387_64.c diff --git a/arch/x86_64/kernel/i8259_64.c b/arch/x86/kernel/i8259_64.c similarity index 100% rename from arch/x86_64/kernel/i8259_64.c rename to arch/x86/kernel/i8259_64.c diff --git a/arch/x86_64/kernel/init_task_64.c b/arch/x86/kernel/init_task_64.c similarity index 100% rename from arch/x86_64/kernel/init_task_64.c rename to arch/x86/kernel/init_task_64.c diff --git a/arch/x86_64/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c similarity index 100% rename from arch/x86_64/kernel/io_apic_64.c rename to arch/x86/kernel/io_apic_64.c diff --git a/arch/x86_64/kernel/ioport_64.c b/arch/x86/kernel/ioport_64.c similarity index 100% rename from arch/x86_64/kernel/ioport_64.c rename to arch/x86/kernel/ioport_64.c diff --git a/arch/x86_64/kernel/irq_64.c b/arch/x86/kernel/irq_64.c similarity index 100% rename from arch/x86_64/kernel/irq_64.c rename to arch/x86/kernel/irq_64.c diff --git a/arch/x86_64/kernel/k8.c b/arch/x86/kernel/k8.c similarity index 100% rename from arch/x86_64/kernel/k8.c rename to arch/x86/kernel/k8.c diff --git a/arch/x86_64/kernel/kprobes_64.c b/arch/x86/kernel/kprobes_64.c similarity index 100% rename from arch/x86_64/kernel/kprobes_64.c rename to arch/x86/kernel/kprobes_64.c diff --git a/arch/x86_64/kernel/ldt_64.c b/arch/x86/kernel/ldt_64.c similarity index 100% rename from arch/x86_64/kernel/ldt_64.c rename to arch/x86/kernel/ldt_64.c diff --git a/arch/x86_64/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c similarity index 100% rename from arch/x86_64/kernel/machine_kexec_64.c rename to arch/x86/kernel/machine_kexec_64.c diff --git a/arch/x86_64/kernel/mce_64.c b/arch/x86/kernel/mce_64.c similarity index 100% rename from arch/x86_64/kernel/mce_64.c rename to arch/x86/kernel/mce_64.c diff --git a/arch/x86_64/kernel/mce_amd_64.c b/arch/x86/kernel/mce_amd_64.c similarity index 100% rename from arch/x86_64/kernel/mce_amd_64.c rename to arch/x86/kernel/mce_amd_64.c diff --git a/arch/x86_64/kernel/mce_intel_64.c b/arch/x86/kernel/mce_intel_64.c similarity index 100% rename from arch/x86_64/kernel/mce_intel_64.c rename to arch/x86/kernel/mce_intel_64.c diff --git a/arch/x86_64/kernel/module_64.c b/arch/x86/kernel/module_64.c similarity index 100% rename from arch/x86_64/kernel/module_64.c rename to arch/x86/kernel/module_64.c diff --git a/arch/x86_64/kernel/mpparse_64.c b/arch/x86/kernel/mpparse_64.c similarity index 100% rename from arch/x86_64/kernel/mpparse_64.c rename to arch/x86/kernel/mpparse_64.c diff --git a/arch/x86_64/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c similarity index 100% rename from arch/x86_64/kernel/nmi_64.c rename to arch/x86/kernel/nmi_64.c diff --git a/arch/x86_64/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c similarity index 100% rename from arch/x86_64/kernel/pci-calgary_64.c rename to arch/x86/kernel/pci-calgary_64.c diff --git a/arch/x86_64/kernel/pci-dma_64.c b/arch/x86/kernel/pci-dma_64.c similarity index 100% rename from arch/x86_64/kernel/pci-dma_64.c rename to arch/x86/kernel/pci-dma_64.c diff --git a/arch/x86_64/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c similarity index 100% rename from arch/x86_64/kernel/pci-gart_64.c rename to arch/x86/kernel/pci-gart_64.c diff --git a/arch/x86_64/kernel/pci-nommu_64.c b/arch/x86/kernel/pci-nommu_64.c similarity index 100% rename from arch/x86_64/kernel/pci-nommu_64.c rename to arch/x86/kernel/pci-nommu_64.c diff --git a/arch/x86_64/kernel/pci-swiotlb_64.c b/arch/x86/kernel/pci-swiotlb_64.c similarity index 100% rename from arch/x86_64/kernel/pci-swiotlb_64.c rename to arch/x86/kernel/pci-swiotlb_64.c diff --git a/arch/x86_64/kernel/pmtimer_64.c b/arch/x86/kernel/pmtimer_64.c similarity index 100% rename from arch/x86_64/kernel/pmtimer_64.c rename to arch/x86/kernel/pmtimer_64.c diff --git a/arch/x86_64/kernel/process_64.c b/arch/x86/kernel/process_64.c similarity index 100% rename from arch/x86_64/kernel/process_64.c rename to arch/x86/kernel/process_64.c diff --git a/arch/x86_64/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c similarity index 100% rename from arch/x86_64/kernel/ptrace_64.c rename to arch/x86/kernel/ptrace_64.c diff --git a/arch/x86_64/kernel/reboot_64.c b/arch/x86/kernel/reboot_64.c similarity index 100% rename from arch/x86_64/kernel/reboot_64.c rename to arch/x86/kernel/reboot_64.c diff --git a/arch/x86_64/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S similarity index 100% rename from arch/x86_64/kernel/relocate_kernel_64.S rename to arch/x86/kernel/relocate_kernel_64.S diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86/kernel/setup64.c similarity index 100% rename from arch/x86_64/kernel/setup64.c rename to arch/x86/kernel/setup64.c diff --git a/arch/x86_64/kernel/setup_64.c b/arch/x86/kernel/setup_64.c similarity index 100% rename from arch/x86_64/kernel/setup_64.c rename to arch/x86/kernel/setup_64.c diff --git a/arch/x86_64/kernel/signal_64.c b/arch/x86/kernel/signal_64.c similarity index 100% rename from arch/x86_64/kernel/signal_64.c rename to arch/x86/kernel/signal_64.c diff --git a/arch/x86_64/kernel/smp_64.c b/arch/x86/kernel/smp_64.c similarity index 100% rename from arch/x86_64/kernel/smp_64.c rename to arch/x86/kernel/smp_64.c diff --git a/arch/x86_64/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c similarity index 100% rename from arch/x86_64/kernel/smpboot_64.c rename to arch/x86/kernel/smpboot_64.c diff --git a/arch/x86_64/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c similarity index 100% rename from arch/x86_64/kernel/stacktrace.c rename to arch/x86/kernel/stacktrace.c diff --git a/arch/x86_64/kernel/suspend_64.c b/arch/x86/kernel/suspend_64.c similarity index 100% rename from arch/x86_64/kernel/suspend_64.c rename to arch/x86/kernel/suspend_64.c diff --git a/arch/x86_64/kernel/suspend_asm_64.S b/arch/x86/kernel/suspend_asm_64.S similarity index 100% rename from arch/x86_64/kernel/suspend_asm_64.S rename to arch/x86/kernel/suspend_asm_64.S diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c similarity index 100% rename from arch/x86_64/kernel/sys_x86_64.c rename to arch/x86/kernel/sys_x86_64.c diff --git a/arch/x86_64/kernel/syscall_64.c b/arch/x86/kernel/syscall_64.c similarity index 100% rename from arch/x86_64/kernel/syscall_64.c rename to arch/x86/kernel/syscall_64.c diff --git a/arch/x86_64/kernel/tce_64.c b/arch/x86/kernel/tce_64.c similarity index 100% rename from arch/x86_64/kernel/tce_64.c rename to arch/x86/kernel/tce_64.c diff --git a/arch/x86_64/kernel/time_64.c b/arch/x86/kernel/time_64.c similarity index 100% rename from arch/x86_64/kernel/time_64.c rename to arch/x86/kernel/time_64.c diff --git a/arch/x86_64/kernel/trampoline_64.S b/arch/x86/kernel/trampoline_64.S similarity index 100% rename from arch/x86_64/kernel/trampoline_64.S rename to arch/x86/kernel/trampoline_64.S diff --git a/arch/x86_64/kernel/traps_64.c b/arch/x86/kernel/traps_64.c similarity index 100% rename from arch/x86_64/kernel/traps_64.c rename to arch/x86/kernel/traps_64.c diff --git a/arch/x86_64/kernel/tsc_64.c b/arch/x86/kernel/tsc_64.c similarity index 100% rename from arch/x86_64/kernel/tsc_64.c rename to arch/x86/kernel/tsc_64.c diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c index 12424629af87..355f5f506c81 100644 --- a/arch/x86/kernel/tsc_sync.c +++ b/arch/x86/kernel/tsc_sync.c @@ -1 +1,187 @@ -#include "../../x86_64/kernel/tsc_sync.c" +/* + * arch/x86_64/kernel/tsc_sync.c: check TSC synchronization. + * + * Copyright (C) 2006, Red Hat, Inc., Ingo Molnar + * + * We check whether all boot CPUs have their TSC's synchronized, + * print a warning if not and turn off the TSC clock-source. + * + * The warp-check is point-to-point between two CPUs, the CPU + * initiating the bootup is the 'source CPU', the freshly booting + * CPU is the 'target CPU'. + * + * Only two CPUs may participate - they can enter in any order. + * ( The serial nature of the boot logic and the CPU hotplug lock + * protects against more than 2 CPUs entering this code. ) + */ +#include +#include +#include +#include +#include +#include + +/* + * Entry/exit counters that make sure that both CPUs + * run the measurement code at once: + */ +static __cpuinitdata atomic_t start_count; +static __cpuinitdata atomic_t stop_count; + +/* + * We use a raw spinlock in this exceptional case, because + * we want to have the fastest, inlined, non-debug version + * of a critical section, to be able to prove TSC time-warps: + */ +static __cpuinitdata raw_spinlock_t sync_lock = __RAW_SPIN_LOCK_UNLOCKED; +static __cpuinitdata cycles_t last_tsc; +static __cpuinitdata cycles_t max_warp; +static __cpuinitdata int nr_warps; + +/* + * TSC-warp measurement loop running on both CPUs: + */ +static __cpuinit void check_tsc_warp(void) +{ + cycles_t start, now, prev, end; + int i; + + start = get_cycles_sync(); + /* + * The measurement runs for 20 msecs: + */ + end = start + tsc_khz * 20ULL; + now = start; + + for (i = 0; ; i++) { + /* + * We take the global lock, measure TSC, save the + * previous TSC that was measured (possibly on + * another CPU) and update the previous TSC timestamp. + */ + __raw_spin_lock(&sync_lock); + prev = last_tsc; + now = get_cycles_sync(); + last_tsc = now; + __raw_spin_unlock(&sync_lock); + + /* + * Be nice every now and then (and also check whether + * measurement is done [we also insert a 100 million + * loops safety exit, so we dont lock up in case the + * TSC readout is totally broken]): + */ + if (unlikely(!(i & 7))) { + if (now > end || i > 100000000) + break; + cpu_relax(); + touch_nmi_watchdog(); + } + /* + * Outside the critical section we can now see whether + * we saw a time-warp of the TSC going backwards: + */ + if (unlikely(prev > now)) { + __raw_spin_lock(&sync_lock); + max_warp = max(max_warp, prev - now); + nr_warps++; + __raw_spin_unlock(&sync_lock); + } + + } +} + +/* + * Source CPU calls into this - it waits for the freshly booted + * target CPU to arrive and then starts the measurement: + */ +void __cpuinit check_tsc_sync_source(int cpu) +{ + int cpus = 2; + + /* + * No need to check if we already know that the TSC is not + * synchronized: + */ + if (unsynchronized_tsc()) + return; + + printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", + smp_processor_id(), cpu); + + /* + * Reset it - in case this is a second bootup: + */ + atomic_set(&stop_count, 0); + + /* + * Wait for the target to arrive: + */ + while (atomic_read(&start_count) != cpus-1) + cpu_relax(); + /* + * Trigger the target to continue into the measurement too: + */ + atomic_inc(&start_count); + + check_tsc_warp(); + + while (atomic_read(&stop_count) != cpus-1) + cpu_relax(); + + /* + * Reset it - just in case we boot another CPU later: + */ + atomic_set(&start_count, 0); + + if (nr_warps) { + printk("\n"); + printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs," + " turning off TSC clock.\n", max_warp); + mark_tsc_unstable("check_tsc_sync_source failed"); + nr_warps = 0; + max_warp = 0; + last_tsc = 0; + } else { + printk(" passed.\n"); + } + + /* + * Let the target continue with the bootup: + */ + atomic_inc(&stop_count); +} + +/* + * Freshly booted CPUs call into this: + */ +void __cpuinit check_tsc_sync_target(void) +{ + int cpus = 2; + + if (unsynchronized_tsc()) + return; + + /* + * Register this CPU's participation and wait for the + * source CPU to start the measurement: + */ + atomic_inc(&start_count); + while (atomic_read(&start_count) != cpus) + cpu_relax(); + + check_tsc_warp(); + + /* + * Ok, we are done: + */ + atomic_inc(&stop_count); + + /* + * Wait for the source CPU to print stuff: + */ + while (atomic_read(&stop_count) != cpus) + cpu_relax(); +} +#undef NR_LOOPS + diff --git a/arch/x86_64/kernel/verify_cpu_64.S b/arch/x86/kernel/verify_cpu_64.S similarity index 100% rename from arch/x86_64/kernel/verify_cpu_64.S rename to arch/x86/kernel/verify_cpu_64.S diff --git a/arch/x86_64/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S similarity index 100% rename from arch/x86_64/kernel/vmlinux_64.lds.S rename to arch/x86/kernel/vmlinux_64.lds.S diff --git a/arch/x86_64/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c similarity index 100% rename from arch/x86_64/kernel/vsmp_64.c rename to arch/x86/kernel/vsmp_64.c diff --git a/arch/x86_64/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c similarity index 100% rename from arch/x86_64/kernel/vsyscall_64.c rename to arch/x86/kernel/vsyscall_64.c diff --git a/arch/x86_64/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c similarity index 100% rename from arch/x86_64/kernel/x8664_ksyms_64.c rename to arch/x86/kernel/x8664_ksyms_64.c diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 189d80d3a891..afaf0f998878 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -21,6 +21,13 @@ # # $Id: Makefile,v 1.31 2002/03/22 15:56:07 ak Exp $ +# Fill in SRCARCH +SRCARCH := x86 + +archprepare: + @mkdir -p ${objtree}/arch/x86/kernel + + LDFLAGS := -m elf_x86_64 OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := @@ -71,10 +78,10 @@ CFLAGS += $(cflags-y) CFLAGS_KERNEL += $(cflags-kernel-y) AFLAGS += -m64 -head-y := arch/x86_64/kernel/head_64.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task_64.o +head-y := arch/x86/kernel/head_64.o arch/x86/kernel/head64.o arch/x86/kernel/init_task_64.o libs-y += arch/x86/lib/ -core-y += arch/x86_64/kernel/ \ +core-y += arch/x86/kernel/ \ arch/x86/mm/ \ arch/x86/crypto/ \ arch/x86/vdso/ diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile deleted file mode 100644 index 577d08f4b8bb..000000000000 --- a/arch/x86_64/kernel/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/x86/kernel/Makefile_32 -else -include ${srctree}/arch/x86_64/kernel/Makefile_64 -endif diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c deleted file mode 100644 index cfa82c899f47..000000000000 --- a/arch/x86_64/kernel/asm-offsets.c +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef CONFIG_X86_32 -# include "asm-offsets_32.c" -#else -# include "asm-offsets_64.c" -#endif diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c deleted file mode 100644 index fd9aff3f3890..000000000000 --- a/arch/x86_64/kernel/early_printk.c +++ /dev/null @@ -1,259 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Simple VGA output */ - -#ifdef __i386__ -#include -#else -#include -#endif -#define VGABASE (__ISA_IO_base + 0xb8000) - -static int max_ypos = 25, max_xpos = 80; -static int current_ypos = 25, current_xpos = 0; - -static void early_vga_write(struct console *con, const char *str, unsigned n) -{ - char c; - int i, k, j; - - while ((c = *str++) != '\0' && n-- > 0) { - if (current_ypos >= max_ypos) { - /* scroll 1 line up */ - for (k = 1, j = 0; k < max_ypos; k++, j++) { - for (i = 0; i < max_xpos; i++) { - writew(readw(VGABASE+2*(max_xpos*k+i)), - VGABASE + 2*(max_xpos*j + i)); - } - } - for (i = 0; i < max_xpos; i++) - writew(0x720, VGABASE + 2*(max_xpos*j + i)); - current_ypos = max_ypos-1; - } - if (c == '\n') { - current_xpos = 0; - current_ypos++; - } else if (c != '\r') { - writew(((0x7 << 8) | (unsigned short) c), - VGABASE + 2*(max_xpos*current_ypos + - current_xpos++)); - if (current_xpos >= max_xpos) { - current_xpos = 0; - current_ypos++; - } - } - } -} - -static struct console early_vga_console = { - .name = "earlyvga", - .write = early_vga_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* Serial functions loosely based on a similar package from Klaus P. Gerlicher */ - -static int early_serial_base = 0x3f8; /* ttyS0 */ - -#define XMTRDY 0x20 - -#define DLAB 0x80 - -#define TXR 0 /* Transmit register (WRITE) */ -#define RXR 0 /* Receive register (READ) */ -#define IER 1 /* Interrupt Enable */ -#define IIR 2 /* Interrupt ID */ -#define FCR 2 /* FIFO control */ -#define LCR 3 /* Line control */ -#define MCR 4 /* Modem control */ -#define LSR 5 /* Line Status */ -#define MSR 6 /* Modem Status */ -#define DLL 0 /* Divisor Latch Low */ -#define DLH 1 /* Divisor latch High */ - -static int early_serial_putc(unsigned char ch) -{ - unsigned timeout = 0xffff; - while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) - cpu_relax(); - outb(ch, early_serial_base + TXR); - return timeout ? 0 : -1; -} - -static void early_serial_write(struct console *con, const char *s, unsigned n) -{ - while (*s && n-- > 0) { - if (*s == '\n') - early_serial_putc('\r'); - early_serial_putc(*s); - s++; - } -} - -#define DEFAULT_BAUD 9600 - -static __init void early_serial_init(char *s) -{ - unsigned char c; - unsigned divisor; - unsigned baud = DEFAULT_BAUD; - char *e; - - if (*s == ',') - ++s; - - if (*s) { - unsigned port; - if (!strncmp(s,"0x",2)) { - early_serial_base = simple_strtoul(s, &e, 16); - } else { - static int bases[] = { 0x3f8, 0x2f8 }; - - if (!strncmp(s,"ttyS",4)) - s += 4; - port = simple_strtoul(s, &e, 10); - if (port > 1 || s == e) - port = 0; - early_serial_base = bases[port]; - } - s += strcspn(s, ","); - if (*s == ',') - s++; - } - - outb(0x3, early_serial_base + LCR); /* 8n1 */ - outb(0, early_serial_base + IER); /* no interrupt */ - outb(0, early_serial_base + FCR); /* no fifo */ - outb(0x3, early_serial_base + MCR); /* DTR + RTS */ - - if (*s) { - baud = simple_strtoul(s, &e, 0); - if (baud == 0 || s == e) - baud = DEFAULT_BAUD; - } - - divisor = 115200 / baud; - c = inb(early_serial_base + LCR); - outb(c | DLAB, early_serial_base + LCR); - outb(divisor & 0xff, early_serial_base + DLL); - outb((divisor >> 8) & 0xff, early_serial_base + DLH); - outb(c & ~DLAB, early_serial_base + LCR); -} - -static struct console early_serial_console = { - .name = "earlyser", - .write = early_serial_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* Console interface to a host file on AMD's SimNow! */ - -static int simnow_fd; - -enum { - MAGIC1 = 0xBACCD00A, - MAGIC2 = 0xCA110000, - XOPEN = 5, - XWRITE = 4, -}; - -static noinline long simnow(long cmd, long a, long b, long c) -{ - long ret; - asm volatile("cpuid" : - "=a" (ret) : - "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); - return ret; -} - -static void __init simnow_init(char *str) -{ - char *fn = "klog"; - if (*str == '=') - fn = ++str; - /* error ignored */ - simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644); -} - -static void simnow_write(struct console *con, const char *s, unsigned n) -{ - simnow(XWRITE, simnow_fd, (unsigned long)s, n); -} - -static struct console simnow_console = { - .name = "simnow", - .write = simnow_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* Direct interface for emergencies */ -struct console *early_console = &early_vga_console; -static int early_console_initialized = 0; - -void early_printk(const char *fmt, ...) -{ - char buf[512]; - int n; - va_list ap; - - va_start(ap,fmt); - n = vscnprintf(buf,512,fmt,ap); - early_console->write(early_console,buf,n); - va_end(ap); -} - -static int __initdata keep_early; - -static int __init setup_early_printk(char *buf) -{ - if (!buf) - return 0; - - if (early_console_initialized) - return 0; - early_console_initialized = 1; - - if (strstr(buf, "keep")) - keep_early = 1; - - if (!strncmp(buf, "serial", 6)) { - early_serial_init(buf + 6); - early_console = &early_serial_console; - } else if (!strncmp(buf, "ttyS", 4)) { - early_serial_init(buf); - early_console = &early_serial_console; - } else if (!strncmp(buf, "vga", 3) - && SCREEN_INFO.orig_video_isVGA == 1) { - max_xpos = SCREEN_INFO.orig_video_cols; - max_ypos = SCREEN_INFO.orig_video_lines; - current_ypos = SCREEN_INFO.orig_y; - early_console = &early_vga_console; - } else if (!strncmp(buf, "simnow", 6)) { - simnow_init(buf + 6); - early_console = &simnow_console; - keep_early = 1; -#ifdef CONFIG_HVC_XEN - } else if (!strncmp(buf, "xen", 3)) { - early_console = &xenboot_console; -#endif - } - - if (keep_early) - early_console->flags &= ~CON_BOOT; - else - early_console->flags |= CON_BOOT; - register_console(early_console); - return 0; -} -early_param("earlyprintk", setup_early_printk); diff --git a/arch/x86_64/kernel/tsc_sync.c b/arch/x86_64/kernel/tsc_sync.c deleted file mode 100644 index 355f5f506c81..000000000000 --- a/arch/x86_64/kernel/tsc_sync.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * arch/x86_64/kernel/tsc_sync.c: check TSC synchronization. - * - * Copyright (C) 2006, Red Hat, Inc., Ingo Molnar - * - * We check whether all boot CPUs have their TSC's synchronized, - * print a warning if not and turn off the TSC clock-source. - * - * The warp-check is point-to-point between two CPUs, the CPU - * initiating the bootup is the 'source CPU', the freshly booting - * CPU is the 'target CPU'. - * - * Only two CPUs may participate - they can enter in any order. - * ( The serial nature of the boot logic and the CPU hotplug lock - * protects against more than 2 CPUs entering this code. ) - */ -#include -#include -#include -#include -#include -#include - -/* - * Entry/exit counters that make sure that both CPUs - * run the measurement code at once: - */ -static __cpuinitdata atomic_t start_count; -static __cpuinitdata atomic_t stop_count; - -/* - * We use a raw spinlock in this exceptional case, because - * we want to have the fastest, inlined, non-debug version - * of a critical section, to be able to prove TSC time-warps: - */ -static __cpuinitdata raw_spinlock_t sync_lock = __RAW_SPIN_LOCK_UNLOCKED; -static __cpuinitdata cycles_t last_tsc; -static __cpuinitdata cycles_t max_warp; -static __cpuinitdata int nr_warps; - -/* - * TSC-warp measurement loop running on both CPUs: - */ -static __cpuinit void check_tsc_warp(void) -{ - cycles_t start, now, prev, end; - int i; - - start = get_cycles_sync(); - /* - * The measurement runs for 20 msecs: - */ - end = start + tsc_khz * 20ULL; - now = start; - - for (i = 0; ; i++) { - /* - * We take the global lock, measure TSC, save the - * previous TSC that was measured (possibly on - * another CPU) and update the previous TSC timestamp. - */ - __raw_spin_lock(&sync_lock); - prev = last_tsc; - now = get_cycles_sync(); - last_tsc = now; - __raw_spin_unlock(&sync_lock); - - /* - * Be nice every now and then (and also check whether - * measurement is done [we also insert a 100 million - * loops safety exit, so we dont lock up in case the - * TSC readout is totally broken]): - */ - if (unlikely(!(i & 7))) { - if (now > end || i > 100000000) - break; - cpu_relax(); - touch_nmi_watchdog(); - } - /* - * Outside the critical section we can now see whether - * we saw a time-warp of the TSC going backwards: - */ - if (unlikely(prev > now)) { - __raw_spin_lock(&sync_lock); - max_warp = max(max_warp, prev - now); - nr_warps++; - __raw_spin_unlock(&sync_lock); - } - - } -} - -/* - * Source CPU calls into this - it waits for the freshly booted - * target CPU to arrive and then starts the measurement: - */ -void __cpuinit check_tsc_sync_source(int cpu) -{ - int cpus = 2; - - /* - * No need to check if we already know that the TSC is not - * synchronized: - */ - if (unsynchronized_tsc()) - return; - - printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", - smp_processor_id(), cpu); - - /* - * Reset it - in case this is a second bootup: - */ - atomic_set(&stop_count, 0); - - /* - * Wait for the target to arrive: - */ - while (atomic_read(&start_count) != cpus-1) - cpu_relax(); - /* - * Trigger the target to continue into the measurement too: - */ - atomic_inc(&start_count); - - check_tsc_warp(); - - while (atomic_read(&stop_count) != cpus-1) - cpu_relax(); - - /* - * Reset it - just in case we boot another CPU later: - */ - atomic_set(&start_count, 0); - - if (nr_warps) { - printk("\n"); - printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs," - " turning off TSC clock.\n", max_warp); - mark_tsc_unstable("check_tsc_sync_source failed"); - nr_warps = 0; - max_warp = 0; - last_tsc = 0; - } else { - printk(" passed.\n"); - } - - /* - * Let the target continue with the bootup: - */ - atomic_inc(&stop_count); -} - -/* - * Freshly booted CPUs call into this: - */ -void __cpuinit check_tsc_sync_target(void) -{ - int cpus = 2; - - if (unsynchronized_tsc()) - return; - - /* - * Register this CPU's participation and wait for the - * source CPU to start the measurement: - */ - atomic_inc(&start_count); - while (atomic_read(&start_count) != cpus) - cpu_relax(); - - check_tsc_warp(); - - /* - * Ok, we are done: - */ - atomic_inc(&stop_count); - - /* - * Wait for the source CPU to print stuff: - */ - while (atomic_read(&stop_count) != cpus) - cpu_relax(); -} -#undef NR_LOOPS - diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S deleted file mode 100644 index 849ee611f013..000000000000 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef CONFIG_X86_32 -# include "vmlinux_32.lds.S" -#else -# include "vmlinux_64.lds.S" -#endif From c668ce14f59db28a3551792763a0107caf3b9820 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:25 +0200 Subject: [PATCH 2112/2804] x86: sanitize pathes arch/x86/kernel/Makefile_32 Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/Makefile_32 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 index cb25523026a6..c624193740fd 100644 --- a/arch/x86/kernel/Makefile_32 +++ b/arch/x86/kernel/Makefile_32 @@ -10,8 +10,8 @@ obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-y += ../../x86/kernel/cpu/ -obj-y += ../../x86/kernel/acpi/ +obj-y += cpu/ +obj-y += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_X86_MSR) += msr.o From 45bc6cd11953a5729508a92be24b35cd4df9c967 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:25 +0200 Subject: [PATCH 2113/2804] x86: sanitize pathes arch/x86/kernel/Makefile_64 Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/Makefile_64 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64 index 6e6b5909e465..3ab017a0a3b9 100644 --- a/arch/x86/kernel/Makefile_64 +++ b/arch/x86/kernel/Makefile_64 @@ -15,8 +15,8 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o -obj-$(CONFIG_MTRR) += ../../x86/kernel/cpu/mtrr/ -obj-$(CONFIG_ACPI) += ../../x86/kernel/acpi/ +obj-$(CONFIG_MTRR) += cpu/mtrr/ +obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o @@ -27,7 +27,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec_64.o relocate_kernel_64.o crash_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_64.o obj-$(CONFIG_PM) += suspend_64.o obj-$(CONFIG_HIBERNATION) += suspend_asm_64.o -obj-$(CONFIG_CPU_FREQ) += ../../x86/kernel/cpu/cpufreq/ +obj-$(CONFIG_CPU_FREQ) += cpu/cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart_64.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o @@ -48,7 +48,7 @@ obj-y += pcspeaker.o CFLAGS_vsyscall_64.o := $(PROFILING) -g0 -therm_throt-y += ../../x86/kernel/cpu/mcheck/therm_throt.o -intel_cacheinfo-y += ../../x86/kernel/cpu/intel_cacheinfo.o -addon_cpuid_features-y += ../../x86/kernel/cpu/addon_cpuid_features.o -perfctr-watchdog-y += ../../x86/kernel/cpu/perfctr-watchdog.o +therm_throt-y += cpu/mcheck/therm_throt.o +intel_cacheinfo-y += cpu/intel_cacheinfo.o +addon_cpuid_features-y += cpu/addon_cpuid_features.o +perfctr-watchdog-y += cpu/perfctr-watchdog.o From 27bd0c955648646abf2a353a8371d28c37bcd982 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:17:26 +0200 Subject: [PATCH 2114/2804] x86: sanitize pathes arch/x86/kernel/cpu/Makefile Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 6687f6d5ad2f..778396c78d65 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -12,9 +12,9 @@ obj-y += intel.o intel_cacheinfo.o addon_cpuid_features.o obj-y += nexgen.o obj-y += umc.o -obj-$(CONFIG_X86_MCE) += ../../../x86/kernel/cpu/mcheck/ +obj-$(CONFIG_X86_MCE) += mcheck/ -obj-$(CONFIG_MTRR) += ../../../x86/kernel/cpu/mtrr/ -obj-$(CONFIG_CPU_FREQ) += ../../../x86/kernel/cpu/cpufreq/ +obj-$(CONFIG_MTRR) += mtrr/ +obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o From 96a388de5dc53a8b234b3fd41f3ae2cedc9ffd42 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:20:03 +0200 Subject: [PATCH 2115/2804] i386/x86_64: move headers to include/asm-x86 Move the headers to include/asm-x86 and fixup the header install make rules Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- Documentation/lguest/lguest.c | 2 +- Kbuild | 2 +- Makefile | 17 ++-- arch/i386/Makefile | 16 ++-- arch/ia64/ia32/audit.c | 2 +- arch/um/sys-x86_64/syscall_table.c | 4 +- arch/x86/ia32/audit.c | 2 +- arch/x86/ia32/ipc32.c | 2 +- arch/x86/kernel/cpu/mtrr/state.c | 2 +- arch/x86/kernel/syscall_64.c | 4 +- include/asm-i386/Kbuild | 12 --- include/asm-i386/k8.h | 1 - include/asm-i386/pci-direct.h | 1 - include/asm-i386/stacktrace.h | 1 - include/asm-sh/mpc1211/mc146818rtc.h | 2 +- include/asm-x86/8253pit.h | 5 ++ .../8253pit.h => asm-x86/8253pit_32.h} | 0 .../8253pit.h => asm-x86/8253pit_64.h} | 0 include/asm-x86/Kbuild | 88 +++++++++++++++++++ include/asm-x86/a.out.h | 13 +++ .../{asm-i386/a.out.h => asm-x86/a.out_32.h} | 0 .../a.out.h => asm-x86/a.out_64.h} | 0 include/asm-x86/acpi.h | 5 ++ .../{asm-i386/acpi.h => asm-x86/acpi_32.h} | 0 .../{asm-x86_64/acpi.h => asm-x86/acpi_64.h} | 0 include/asm-x86/agp.h | 5 ++ include/{asm-i386/agp.h => asm-x86/agp_32.h} | 0 .../{asm-x86_64/agp.h => asm-x86/agp_64.h} | 0 include/asm-x86/alternative-asm.i | 5 ++ .../alternative-asm_32.i} | 0 .../alternative-asm_64.i} | 0 include/asm-x86/alternative.h | 5 ++ .../alternative_32.h} | 0 .../alternative_64.h} | 0 include/asm-x86/apic.h | 5 ++ .../{asm-i386/apic.h => asm-x86/apic_32.h} | 0 .../{asm-x86_64/apic.h => asm-x86/apic_64.h} | 0 include/asm-x86/apicdef.h | 5 ++ .../apicdef.h => asm-x86/apicdef_32.h} | 0 .../apicdef.h => asm-x86/apicdef_64.h} | 0 include/{asm-i386 => asm-x86}/arch_hooks.h | 0 include/asm-x86/atomic.h | 5 ++ .../atomic.h => asm-x86/atomic_32.h} | 0 .../atomic.h => asm-x86/atomic_64.h} | 0 include/asm-x86/auxvec.h | 13 +++ .../auxvec.h => asm-x86/auxvec_32.h} | 0 .../auxvec.h => asm-x86/auxvec_64.h} | 0 include/asm-x86/bitops.h | 5 ++ .../bitops.h => asm-x86/bitops_32.h} | 0 .../bitops.h => asm-x86/bitops_64.h} | 0 include/{asm-i386 => asm-x86}/boot.h | 0 include/{asm-i386 => asm-x86}/bootparam.h | 0 include/{asm-x86_64 => asm-x86}/bootsetup.h | 0 include/asm-x86/bug.h | 5 ++ include/{asm-i386/bug.h => asm-x86/bug_32.h} | 0 .../{asm-x86_64/bug.h => asm-x86/bug_64.h} | 0 include/asm-x86/bugs.h | 5 ++ .../{asm-i386/bugs.h => asm-x86/bugs_32.h} | 0 .../{asm-x86_64/bugs.h => asm-x86/bugs_64.h} | 0 include/asm-x86/byteorder.h | 13 +++ .../byteorder.h => asm-x86/byteorder_32.h} | 0 .../byteorder.h => asm-x86/byteorder_64.h} | 0 include/asm-x86/cache.h | 5 ++ .../{asm-i386/cache.h => asm-x86/cache_32.h} | 0 .../cache.h => asm-x86/cache_64.h} | 0 include/asm-x86/cacheflush.h | 5 ++ .../cacheflush.h => asm-x86/cacheflush_32.h} | 0 .../cacheflush.h => asm-x86/cacheflush_64.h} | 0 include/{asm-x86_64 => asm-x86}/calgary.h | 0 include/{asm-x86_64 => asm-x86}/calling.h | 0 include/asm-x86/checksum.h | 5 ++ .../checksum.h => asm-x86/checksum_32.h} | 0 .../checksum.h => asm-x86/checksum_64.h} | 0 include/asm-x86/cmpxchg.h | 5 ++ .../cmpxchg.h => asm-x86/cmpxchg_32.h} | 0 .../cmpxchg.h => asm-x86/cmpxchg_64.h} | 0 include/{asm-x86_64 => asm-x86}/compat.h | 0 include/{asm-i386 => asm-x86}/cpu.h | 0 include/asm-x86/cpufeature.h | 5 ++ .../cpufeature.h => asm-x86/cpufeature_32.h} | 0 .../cpufeature.h => asm-x86/cpufeature_64.h} | 4 +- include/asm-x86/cputime.h | 5 ++ .../cputime.h => asm-x86/cputime_32.h} | 0 .../cputime.h => asm-x86/cputime_64.h} | 0 include/asm-x86/current.h | 5 ++ .../current.h => asm-x86/current_32.h} | 0 .../current.h => asm-x86/current_64.h} | 0 include/asm-x86/debugreg.h | 13 +++ .../debugreg.h => asm-x86/debugreg_32.h} | 0 .../debugreg.h => asm-x86/debugreg_64.h} | 0 include/asm-x86/delay.h | 5 ++ .../{asm-i386/delay.h => asm-x86/delay_32.h} | 0 .../delay.h => asm-x86/delay_64.h} | 0 include/asm-x86/desc.h | 5 ++ .../{asm-i386/desc.h => asm-x86/desc_32.h} | 0 .../{asm-x86_64/desc.h => asm-x86/desc_64.h} | 0 include/{asm-x86_64 => asm-x86}/desc_defs.h | 0 include/asm-x86/device.h | 5 ++ .../device.h => asm-x86/device_32.h} | 0 .../device.h => asm-x86/device_64.h} | 0 include/asm-x86/div64.h | 5 ++ .../{asm-i386/div64.h => asm-x86/div64_32.h} | 0 .../div64.h => asm-x86/div64_64.h} | 0 include/asm-x86/dma-mapping.h | 5 ++ .../dma-mapping_32.h} | 0 .../dma-mapping_64.h} | 0 include/asm-x86/dma.h | 5 ++ include/{asm-i386/dma.h => asm-x86/dma_32.h} | 0 .../{asm-x86_64/dma.h => asm-x86/dma_64.h} | 0 include/asm-x86/dmi.h | 5 ++ include/{asm-i386/dmi.h => asm-x86/dmi_32.h} | 0 .../{asm-x86_64/dmi.h => asm-x86/dmi_64.h} | 0 include/asm-x86/dwarf2.h | 5 ++ .../dwarf2.h => asm-x86/dwarf2_32.h} | 0 .../dwarf2.h => asm-x86/dwarf2_64.h} | 0 include/asm-x86/e820.h | 5 ++ .../{asm-i386/e820.h => asm-x86/e820_32.h} | 0 .../{asm-x86_64/e820.h => asm-x86/e820_64.h} | 0 include/asm-x86/edac.h | 5 ++ .../{asm-i386/edac.h => asm-x86/edac_32.h} | 0 .../{asm-x86_64/edac.h => asm-x86/edac_64.h} | 0 include/asm-x86/elf.h | 13 +++ include/{asm-i386/elf.h => asm-x86/elf_32.h} | 0 .../{asm-x86_64/elf.h => asm-x86/elf_64.h} | 0 .../{asm-i386 => asm-x86}/emergency-restart.h | 0 include/asm-x86/errno.h | 13 +++ .../{asm-i386/errno.h => asm-x86/errno_32.h} | 0 .../errno.h => asm-x86/errno_64.h} | 0 include/asm-x86/fb.h | 5 ++ include/{asm-i386/fb.h => asm-x86/fb_32.h} | 0 include/{asm-x86_64/fb.h => asm-x86/fb_64.h} | 0 include/{asm-i386 => asm-x86}/fcntl.h | 0 include/asm-x86/fixmap.h | 5 ++ .../fixmap.h => asm-x86/fixmap_32.h} | 0 .../fixmap.h => asm-x86/fixmap_64.h} | 0 include/asm-x86/floppy.h | 5 ++ .../floppy.h => asm-x86/floppy_32.h} | 0 .../floppy.h => asm-x86/floppy_64.h} | 0 include/{asm-x86_64 => asm-x86}/fpu32.h | 0 include/{asm-i386 => asm-x86}/frame.i | 0 include/asm-x86/futex.h | 5 ++ .../{asm-i386/futex.h => asm-x86/futex_32.h} | 0 .../futex.h => asm-x86/futex_64.h} | 0 include/asm-x86/genapic.h | 5 ++ .../genapic.h => asm-x86/genapic_32.h} | 0 .../genapic.h => asm-x86/genapic_64.h} | 0 include/{asm-i386 => asm-x86}/geode.h | 0 include/asm-x86/hardirq.h | 5 ++ .../hardirq.h => asm-x86/hardirq_32.h} | 0 .../hardirq.h => asm-x86/hardirq_64.h} | 0 include/{asm-i386 => asm-x86}/highmem.h | 0 include/asm-x86/hpet.h | 5 ++ .../{asm-i386/hpet.h => asm-x86/hpet_32.h} | 0 .../{asm-x86_64/hpet.h => asm-x86/hpet_64.h} | 2 +- include/asm-x86/hw_irq.h | 5 ++ .../hw_irq.h => asm-x86/hw_irq_32.h} | 0 .../hw_irq.h => asm-x86/hw_irq_64.h} | 0 .../{asm-i386 => asm-x86}/hypertransport.h | 0 include/asm-x86/i387.h | 5 ++ .../{asm-i386/i387.h => asm-x86/i387_32.h} | 0 .../{asm-x86_64/i387.h => asm-x86/i387_64.h} | 0 include/asm-x86/i8253.h | 5 ++ .../{asm-i386/i8253.h => asm-x86/i8253_32.h} | 0 .../i8253.h => asm-x86/i8253_64.h} | 0 include/{asm-i386 => asm-x86}/i8259.h | 0 include/{asm-x86_64 => asm-x86}/ia32.h | 0 include/{asm-x86_64 => asm-x86}/ia32_unistd.h | 0 include/{asm-i386 => asm-x86}/ide.h | 0 include/{asm-x86_64 => asm-x86}/idle.h | 0 include/asm-x86/intel_arch_perfmon.h | 5 ++ .../intel_arch_perfmon_32.h} | 0 .../intel_arch_perfmon_64.h} | 0 include/asm-x86/io.h | 5 ++ include/{asm-i386/io.h => asm-x86/io_32.h} | 0 include/{asm-x86_64/io.h => asm-x86/io_64.h} | 0 include/asm-x86/io_apic.h | 5 ++ .../io_apic.h => asm-x86/io_apic_32.h} | 0 .../io_apic.h => asm-x86/io_apic_64.h} | 0 include/{asm-i386 => asm-x86}/ioctl.h | 0 include/asm-x86/ioctls.h | 13 +++ .../ioctls.h => asm-x86/ioctls_32.h} | 0 .../ioctls.h => asm-x86/ioctls_64.h} | 0 include/{asm-x86_64 => asm-x86}/iommu.h | 0 include/{asm-i386 => asm-x86}/ipc.h | 0 include/asm-x86/ipcbuf.h | 13 +++ .../ipcbuf.h => asm-x86/ipcbuf_32.h} | 0 .../ipcbuf.h => asm-x86/ipcbuf_64.h} | 0 include/{asm-x86_64 => asm-x86}/ipi.h | 0 include/asm-x86/irq.h | 5 ++ include/{asm-i386/irq.h => asm-x86/irq_32.h} | 0 .../{asm-x86_64/irq.h => asm-x86/irq_64.h} | 0 include/asm-x86/irq_regs.h | 5 ++ .../irq_regs.h => asm-x86/irq_regs_32.h} | 0 .../irq_regs.h => asm-x86/irq_regs_64.h} | 0 include/asm-x86/irqflags.h | 5 ++ .../irqflags.h => asm-x86/irqflags_32.h} | 0 .../irqflags.h => asm-x86/irqflags_64.h} | 0 include/{asm-i386 => asm-x86}/ist.h | 0 include/{asm-x86_64 => asm-x86}/k8.h | 0 include/asm-x86/kdebug.h | 5 ++ .../kdebug.h => asm-x86/kdebug_32.h} | 0 .../kdebug.h => asm-x86/kdebug_64.h} | 0 include/asm-x86/kexec.h | 5 ++ .../{asm-i386/kexec.h => asm-x86/kexec_32.h} | 0 .../kexec.h => asm-x86/kexec_64.h} | 0 include/asm-x86/kmap_types.h | 5 ++ .../kmap_types.h => asm-x86/kmap_types_32.h} | 0 .../kmap_types.h => asm-x86/kmap_types_64.h} | 0 include/asm-x86/kprobes.h | 5 ++ .../kprobes.h => asm-x86/kprobes_32.h} | 0 .../kprobes.h => asm-x86/kprobes_64.h} | 0 include/asm-x86/ldt.h | 13 +++ include/{asm-i386/ldt.h => asm-x86/ldt_32.h} | 0 .../{asm-x86_64/ldt.h => asm-x86/ldt_64.h} | 0 include/asm-x86/linkage.h | 5 ++ .../linkage.h => asm-x86/linkage_32.h} | 0 .../linkage.h => asm-x86/linkage_64.h} | 0 include/asm-x86/local.h | 5 ++ .../{asm-i386/local.h => asm-x86/local_32.h} | 0 .../local.h => asm-x86/local_64.h} | 0 .../mach-bigsmp/mach_apic.h | 0 .../mach-bigsmp/mach_apicdef.h | 0 .../mach-bigsmp/mach_ipi.h | 0 .../mach-bigsmp/mach_mpspec.h | 0 .../{asm-i386 => asm-x86}/mach-default/apm.h | 0 .../mach-default/bios_ebda.h | 0 .../mach-default/do_timer.h | 0 .../mach-default/entry_arch.h | 0 .../mach-default/io_ports.h | 0 .../mach-default/irq_vectors.h | 0 .../mach-default/irq_vectors_limits.h | 0 .../mach-default/mach_apic.h | 0 .../mach-default/mach_apicdef.h | 0 .../mach-default/mach_ipi.h | 0 .../mach-default/mach_mpparse.h | 0 .../mach-default/mach_mpspec.h | 0 .../mach-default/mach_reboot.h | 0 .../mach-default/mach_time.h | 0 .../mach-default/mach_timer.h | 0 .../mach-default/mach_traps.h | 0 .../mach-default/mach_wakecpu.h | 0 .../mach-default/pci-functions.h | 0 .../mach-default/setup_arch.h | 0 .../mach-default/smpboot_hooks.h | 0 .../mach-es7000/mach_apic.h | 0 .../mach-es7000/mach_apicdef.h | 0 .../mach-es7000/mach_ipi.h | 0 .../mach-es7000/mach_mpparse.h | 0 .../mach-es7000/mach_mpspec.h | 0 .../mach-es7000/mach_wakecpu.h | 0 .../mach-generic/irq_vectors_limits.h | 0 .../mach-generic/mach_apic.h | 0 .../mach-generic/mach_apicdef.h | 0 .../mach-generic/mach_ipi.h | 0 .../mach-generic/mach_mpparse.h | 0 .../mach-generic/mach_mpspec.h | 0 .../mach-numaq/mach_apic.h | 0 .../mach-numaq/mach_apicdef.h | 0 .../mach-numaq/mach_ipi.h | 0 .../mach-numaq/mach_mpparse.h | 0 .../mach-numaq/mach_mpspec.h | 0 .../mach-numaq/mach_wakecpu.h | 0 .../mach-summit/irq_vectors_limits.h | 0 .../mach-summit/mach_apic.h | 0 .../mach-summit/mach_apicdef.h | 0 .../mach-summit/mach_ipi.h | 0 .../mach-summit/mach_mpparse.h | 0 .../mach-summit/mach_mpspec.h | 0 .../{asm-i386 => asm-x86}/mach-visws/cobalt.h | 0 .../mach-visws/entry_arch.h | 0 .../mach-visws/irq_vectors.h | 0 .../mach-visws/lithium.h | 0 .../mach-visws/mach_apic.h | 0 .../mach-visws/mach_apicdef.h | 0 .../{asm-i386 => asm-x86}/mach-visws/piix4.h | 0 .../mach-visws/setup_arch.h | 0 .../mach-visws/smpboot_hooks.h | 0 .../mach-voyager/do_timer.h | 0 .../mach-voyager/entry_arch.h | 0 .../mach-voyager/irq_vectors.h | 0 .../mach-voyager/setup_arch.h | 0 include/{asm-x86_64 => asm-x86}/mach_apic.h | 0 include/{asm-i386 => asm-x86}/math_emu.h | 0 include/asm-x86/mc146818rtc.h | 5 ++ .../mc146818rtc_32.h} | 0 .../mc146818rtc_64.h} | 0 include/{asm-i386 => asm-x86}/mca.h | 0 include/{asm-i386 => asm-x86}/mca_dma.h | 0 include/asm-x86/mce.h | 5 ++ include/{asm-i386/mce.h => asm-x86/mce_32.h} | 0 .../{asm-x86_64/mce.h => asm-x86/mce_64.h} | 0 include/asm-x86/mman.h | 13 +++ .../{asm-i386/mman.h => asm-x86/mman_32.h} | 0 .../{asm-x86_64/mman.h => asm-x86/mman_64.h} | 0 include/{asm-x86_64 => asm-x86}/mmsegment.h | 0 include/asm-x86/mmu.h | 5 ++ include/{asm-i386/mmu.h => asm-x86/mmu_32.h} | 0 .../{asm-x86_64/mmu.h => asm-x86/mmu_64.h} | 0 include/asm-x86/mmu_context.h | 5 ++ .../mmu_context_32.h} | 0 .../mmu_context_64.h} | 0 include/{asm-i386 => asm-x86}/mmx.h | 0 include/asm-x86/mmzone.h | 5 ++ .../mmzone.h => asm-x86/mmzone_32.h} | 0 .../mmzone.h => asm-x86/mmzone_64.h} | 0 include/asm-x86/module.h | 5 ++ .../module.h => asm-x86/module_32.h} | 0 .../module.h => asm-x86/module_64.h} | 0 include/asm-x86/mpspec.h | 5 ++ .../mpspec.h => asm-x86/mpspec_32.h} | 0 .../mpspec.h => asm-x86/mpspec_64.h} | 0 include/{asm-i386 => asm-x86}/mpspec_def.h | 0 include/asm-x86/msgbuf.h | 13 +++ .../msgbuf.h => asm-x86/msgbuf_32.h} | 0 .../msgbuf.h => asm-x86/msgbuf_64.h} | 0 include/{asm-i386 => asm-x86}/msidef.h | 0 include/{asm-i386 => asm-x86}/msr-index.h | 0 include/asm-x86/msr.h | 13 +++ include/{asm-i386/msr.h => asm-x86/msr_32.h} | 0 .../{asm-x86_64/msr.h => asm-x86/msr_64.h} | 0 include/asm-x86/mtrr.h | 13 +++ .../{asm-i386/mtrr.h => asm-x86/mtrr_32.h} | 0 .../{asm-x86_64/mtrr.h => asm-x86/mtrr_64.h} | 0 include/asm-x86/mutex.h | 5 ++ .../{asm-i386/mutex.h => asm-x86/mutex_32.h} | 0 .../mutex.h => asm-x86/mutex_64.h} | 0 include/asm-x86/namei.h | 5 ++ .../{asm-i386/namei.h => asm-x86/namei_32.h} | 0 .../namei.h => asm-x86/namei_64.h} | 0 include/asm-x86/nmi.h | 5 ++ include/{asm-i386/nmi.h => asm-x86/nmi_32.h} | 0 .../{asm-x86_64/nmi.h => asm-x86/nmi_64.h} | 0 include/asm-x86/numa.h | 5 ++ .../{asm-i386/numa.h => asm-x86/numa_32.h} | 0 .../{asm-x86_64/numa.h => asm-x86/numa_64.h} | 0 include/{asm-i386 => asm-x86}/numaq.h | 0 include/asm-x86/page.h | 13 +++ .../{asm-i386/page.h => asm-x86/page_32.h} | 0 .../{asm-x86_64/page.h => asm-x86/page_64.h} | 0 include/asm-x86/param.h | 13 +++ .../{asm-i386/param.h => asm-x86/param_32.h} | 0 .../param.h => asm-x86/param_64.h} | 0 include/{asm-i386 => asm-x86}/paravirt.h | 0 include/asm-x86/parport.h | 5 ++ .../parport.h => asm-x86/parport_32.h} | 0 .../parport.h => asm-x86/parport_64.h} | 0 include/{asm-x86_64 => asm-x86}/pci-direct.h | 0 include/asm-x86/pci.h | 5 ++ include/{asm-i386/pci.h => asm-x86/pci_32.h} | 0 .../{asm-x86_64/pci.h => asm-x86/pci_64.h} | 0 include/{asm-x86_64 => asm-x86}/pda.h | 0 include/asm-x86/percpu.h | 5 ++ .../percpu.h => asm-x86/percpu_32.h} | 0 .../percpu.h => asm-x86/percpu_64.h} | 0 include/asm-x86/pgalloc.h | 5 ++ .../pgalloc.h => asm-x86/pgalloc_32.h} | 0 .../pgalloc.h => asm-x86/pgalloc_64.h} | 0 .../pgtable-2level-defs.h | 0 .../{asm-i386 => asm-x86}/pgtable-2level.h | 0 .../pgtable-3level-defs.h | 0 .../{asm-i386 => asm-x86}/pgtable-3level.h | 0 include/asm-x86/pgtable.h | 5 ++ .../pgtable.h => asm-x86/pgtable_32.h} | 0 .../pgtable.h => asm-x86/pgtable_64.h} | 0 include/{asm-i386 => asm-x86}/poll.h | 0 include/asm-x86/posix_types.h | 13 +++ .../posix_types_32.h} | 0 .../posix_types_64.h} | 0 include/{asm-x86_64 => asm-x86}/prctl.h | 0 .../{asm-i386 => asm-x86}/processor-cyrix.h | 0 .../{asm-i386 => asm-x86}/processor-flags.h | 0 include/asm-x86/processor.h | 5 ++ .../processor.h => asm-x86/processor_32.h} | 0 .../processor.h => asm-x86/processor_64.h} | 0 include/{asm-x86_64 => asm-x86}/proto.h | 0 include/asm-x86/ptrace-abi.h | 13 +++ .../ptrace-abi.h => asm-x86/ptrace-abi_32.h} | 0 .../ptrace-abi.h => asm-x86/ptrace-abi_64.h} | 0 include/asm-x86/ptrace.h | 13 +++ .../ptrace.h => asm-x86/ptrace_32.h} | 0 .../ptrace.h => asm-x86/ptrace_64.h} | 0 include/{asm-i386 => asm-x86}/reboot.h | 0 include/{asm-i386 => asm-x86}/reboot_fixups.h | 0 include/asm-x86/required-features.h | 5 ++ .../required-features_32.h} | 0 .../required-features_64.h} | 0 include/asm-x86/resource.h | 13 +++ .../resource.h => asm-x86/resource_32.h} | 0 .../resource.h => asm-x86/resource_64.h} | 0 include/asm-x86/resume-trace.h | 5 ++ .../resume-trace_32.h} | 0 .../resume-trace_64.h} | 0 include/{asm-x86_64 => asm-x86}/rio.h | 0 include/asm-x86/rtc.h | 5 ++ include/{asm-i386/rtc.h => asm-x86/rtc_32.h} | 0 .../{asm-x86_64/rtc.h => asm-x86/rtc_64.h} | 0 include/asm-x86/rwlock.h | 5 ++ .../rwlock.h => asm-x86/rwlock_32.h} | 0 .../rwlock.h => asm-x86/rwlock_64.h} | 0 include/{asm-i386 => asm-x86}/rwsem.h | 0 include/asm-x86/scatterlist.h | 5 ++ .../scatterlist_32.h} | 0 .../scatterlist_64.h} | 0 include/asm-x86/seccomp.h | 5 ++ .../seccomp.h => asm-x86/seccomp_32.h} | 0 .../seccomp.h => asm-x86/seccomp_64.h} | 0 include/asm-x86/sections.h | 5 ++ .../sections.h => asm-x86/sections_32.h} | 0 .../sections.h => asm-x86/sections_64.h} | 0 include/asm-x86/segment.h | 5 ++ .../segment.h => asm-x86/segment_32.h} | 0 .../segment.h => asm-x86/segment_64.h} | 0 include/asm-x86/semaphore.h | 5 ++ .../semaphore.h => asm-x86/semaphore_32.h} | 0 .../semaphore.h => asm-x86/semaphore_64.h} | 0 include/asm-x86/sembuf.h | 13 +++ .../sembuf.h => asm-x86/sembuf_32.h} | 0 .../sembuf.h => asm-x86/sembuf_64.h} | 0 include/asm-x86/serial.h | 5 ++ .../serial.h => asm-x86/serial_32.h} | 0 .../serial.h => asm-x86/serial_64.h} | 0 include/asm-x86/setup.h | 13 +++ .../{asm-i386/setup.h => asm-x86/setup_32.h} | 0 .../setup.h => asm-x86/setup_64.h} | 0 include/asm-x86/shmbuf.h | 13 +++ .../shmbuf.h => asm-x86/shmbuf_32.h} | 0 .../shmbuf.h => asm-x86/shmbuf_64.h} | 0 include/asm-x86/shmparam.h | 13 +++ .../shmparam.h => asm-x86/shmparam_32.h} | 0 .../shmparam.h => asm-x86/shmparam_64.h} | 0 include/asm-x86/sigcontext.h | 13 +++ .../{asm-x86_64 => asm-x86}/sigcontext32.h | 0 .../sigcontext.h => asm-x86/sigcontext_32.h} | 0 .../sigcontext.h => asm-x86/sigcontext_64.h} | 0 include/asm-x86/siginfo.h | 13 +++ .../siginfo.h => asm-x86/siginfo_32.h} | 0 .../siginfo.h => asm-x86/siginfo_64.h} | 0 include/asm-x86/signal.h | 13 +++ .../signal.h => asm-x86/signal_32.h} | 0 .../signal.h => asm-x86/signal_64.h} | 0 include/asm-x86/smp.h | 5 ++ include/{asm-i386/smp.h => asm-x86/smp_32.h} | 0 .../{asm-x86_64/smp.h => asm-x86/smp_64.h} | 0 include/{asm-i386 => asm-x86}/socket.h | 0 include/asm-x86/sockios.h | 13 +++ .../sockios.h => asm-x86/sockios_32.h} | 0 .../sockios.h => asm-x86/sockios_64.h} | 0 include/asm-x86/sparsemem.h | 5 ++ .../sparsemem.h => asm-x86/sparsemem_32.h} | 0 .../sparsemem.h => asm-x86/sparsemem_64.h} | 0 include/asm-x86/spinlock.h | 5 ++ .../spinlock.h => asm-x86/spinlock_32.h} | 0 .../spinlock.h => asm-x86/spinlock_64.h} | 0 .../{asm-i386 => asm-x86}/spinlock_types.h | 0 include/{asm-i386 => asm-x86}/srat.h | 0 include/{asm-x86_64 => asm-x86}/stacktrace.h | 0 include/asm-x86/stat.h | 13 +++ .../{asm-i386/stat.h => asm-x86/stat_32.h} | 0 .../{asm-x86_64/stat.h => asm-x86/stat_64.h} | 0 include/asm-x86/statfs.h | 13 +++ .../statfs.h => asm-x86/statfs_32.h} | 0 .../statfs.h => asm-x86/statfs_64.h} | 0 include/asm-x86/string.h | 5 ++ .../string.h => asm-x86/string_32.h} | 0 .../string.h => asm-x86/string_64.h} | 0 include/asm-x86/suspend.h | 5 ++ .../suspend.h => asm-x86/suspend_32.h} | 0 .../suspend.h => asm-x86/suspend_64.h} | 0 include/{asm-x86_64 => asm-x86}/swiotlb.h | 0 include/{asm-i386 => asm-x86}/sync_bitops.h | 0 include/asm-x86/system.h | 5 ++ .../system.h => asm-x86/system_32.h} | 0 .../system.h => asm-x86/system_64.h} | 0 include/{asm-x86_64 => asm-x86}/tce.h | 0 include/asm-x86/termbits.h | 13 +++ .../termbits.h => asm-x86/termbits_32.h} | 0 .../termbits.h => asm-x86/termbits_64.h} | 0 include/asm-x86/termios.h | 13 +++ .../termios.h => asm-x86/termios_32.h} | 0 .../termios.h => asm-x86/termios_64.h} | 0 include/{asm-i386 => asm-x86}/therm_throt.h | 0 include/asm-x86/thread_info.h | 5 ++ .../thread_info_32.h} | 0 .../thread_info_64.h} | 0 include/{asm-i386 => asm-x86}/time.h | 0 include/{asm-i386 => asm-x86}/timer.h | 0 include/asm-x86/timex.h | 5 ++ .../{asm-i386/timex.h => asm-x86/timex_32.h} | 0 .../timex.h => asm-x86/timex_64.h} | 0 include/asm-x86/tlb.h | 5 ++ include/{asm-i386/tlb.h => asm-x86/tlb_32.h} | 0 .../{asm-x86_64/tlb.h => asm-x86/tlb_64.h} | 0 include/asm-x86/tlbflush.h | 5 ++ .../tlbflush.h => asm-x86/tlbflush_32.h} | 0 .../tlbflush.h => asm-x86/tlbflush_64.h} | 0 include/asm-x86/topology.h | 5 ++ .../topology.h => asm-x86/topology_32.h} | 0 .../topology.h => asm-x86/topology_64.h} | 0 include/{asm-i386 => asm-x86}/tsc.h | 0 include/asm-x86/types.h | 13 +++ .../{asm-i386/types.h => asm-x86/types_32.h} | 0 .../types.h => asm-x86/types_64.h} | 0 include/asm-x86/uaccess.h | 5 ++ .../uaccess.h => asm-x86/uaccess_32.h} | 0 .../uaccess.h => asm-x86/uaccess_64.h} | 0 include/asm-x86/ucontext.h | 13 +++ .../ucontext.h => asm-x86/ucontext_32.h} | 0 .../ucontext.h => asm-x86/ucontext_64.h} | 0 include/asm-x86/unaligned.h | 5 ++ .../unaligned.h => asm-x86/unaligned_32.h} | 0 .../unaligned.h => asm-x86/unaligned_64.h} | 0 include/asm-x86/unistd.h | 13 +++ .../unistd.h => asm-x86/unistd_32.h} | 0 .../unistd.h => asm-x86/unistd_64.h} | 0 include/asm-x86/unwind.h | 5 ++ .../unwind.h => asm-x86/unwind_32.h} | 0 .../unwind.h => asm-x86/unwind_64.h} | 0 include/asm-x86/user.h | 13 +++ include/{asm-x86_64 => asm-x86}/user32.h | 0 .../{asm-i386/user.h => asm-x86/user_32.h} | 0 .../{asm-x86_64/user.h => asm-x86/user_64.h} | 0 include/{asm-i386 => asm-x86}/vga.h | 0 include/{asm-x86_64 => asm-x86}/vgtod.h | 0 include/{asm-i386 => asm-x86}/vic.h | 0 include/{asm-i386 => asm-x86}/vm86.h | 0 include/{asm-i386 => asm-x86}/vmi.h | 0 include/{asm-i386 => asm-x86}/vmi_time.h | 0 include/{asm-i386 => asm-x86}/voyager.h | 0 include/{asm-x86_64 => asm-x86}/vsyscall.h | 0 include/{asm-x86_64 => asm-x86}/vsyscall32.h | 0 include/{asm-i386 => asm-x86}/xen/hypercall.h | 0 .../{asm-i386 => asm-x86}/xen/hypervisor.h | 0 include/{asm-i386 => asm-x86}/xen/interface.h | 0 include/asm-x86/xor.h | 5 ++ include/{asm-i386/xor.h => asm-x86/xor_32.h} | 0 .../{asm-x86_64/xor.h => asm-x86/xor_64.h} | 0 include/asm-x86_64/Kbuild | 21 ----- include/asm-x86_64/boot.h | 1 - include/asm-x86_64/bootparam.h | 1 - include/asm-x86_64/cpu.h | 1 - include/asm-x86_64/emergency-restart.h | 6 -- include/asm-x86_64/fcntl.h | 1 - include/asm-x86_64/hypertransport.h | 1 - include/asm-x86_64/ide.h | 1 - include/asm-x86_64/ioctl.h | 1 - include/asm-x86_64/ist.h | 1 - include/asm-x86_64/msidef.h | 1 - include/asm-x86_64/msr-index.h | 1 - include/asm-x86_64/poll.h | 1 - include/asm-x86_64/processor-flags.h | 1 - include/asm-x86_64/socket.h | 55 ------------ include/asm-x86_64/spinlock_types.h | 20 ----- include/asm-x86_64/therm_throt.h | 1 - include/asm-x86_64/tsc.h | 1 - include/asm-x86_64/vga.h | 20 ----- scripts/checksyscalls.sh | 2 +- 556 files changed, 1035 insertions(+), 182 deletions(-) delete mode 100644 include/asm-i386/Kbuild delete mode 100644 include/asm-i386/k8.h delete mode 100644 include/asm-i386/pci-direct.h delete mode 100644 include/asm-i386/stacktrace.h create mode 100644 include/asm-x86/8253pit.h rename include/{asm-i386/8253pit.h => asm-x86/8253pit_32.h} (100%) rename include/{asm-x86_64/8253pit.h => asm-x86/8253pit_64.h} (100%) create mode 100644 include/asm-x86/Kbuild create mode 100644 include/asm-x86/a.out.h rename include/{asm-i386/a.out.h => asm-x86/a.out_32.h} (100%) rename include/{asm-x86_64/a.out.h => asm-x86/a.out_64.h} (100%) create mode 100644 include/asm-x86/acpi.h rename include/{asm-i386/acpi.h => asm-x86/acpi_32.h} (100%) rename include/{asm-x86_64/acpi.h => asm-x86/acpi_64.h} (100%) create mode 100644 include/asm-x86/agp.h rename include/{asm-i386/agp.h => asm-x86/agp_32.h} (100%) rename include/{asm-x86_64/agp.h => asm-x86/agp_64.h} (100%) create mode 100644 include/asm-x86/alternative-asm.i rename include/{asm-i386/alternative-asm.i => asm-x86/alternative-asm_32.i} (100%) rename include/{asm-x86_64/alternative-asm.i => asm-x86/alternative-asm_64.i} (100%) create mode 100644 include/asm-x86/alternative.h rename include/{asm-i386/alternative.h => asm-x86/alternative_32.h} (100%) rename include/{asm-x86_64/alternative.h => asm-x86/alternative_64.h} (100%) create mode 100644 include/asm-x86/apic.h rename include/{asm-i386/apic.h => asm-x86/apic_32.h} (100%) rename include/{asm-x86_64/apic.h => asm-x86/apic_64.h} (100%) create mode 100644 include/asm-x86/apicdef.h rename include/{asm-i386/apicdef.h => asm-x86/apicdef_32.h} (100%) rename include/{asm-x86_64/apicdef.h => asm-x86/apicdef_64.h} (100%) rename include/{asm-i386 => asm-x86}/arch_hooks.h (100%) create mode 100644 include/asm-x86/atomic.h rename include/{asm-i386/atomic.h => asm-x86/atomic_32.h} (100%) rename include/{asm-x86_64/atomic.h => asm-x86/atomic_64.h} (100%) create mode 100644 include/asm-x86/auxvec.h rename include/{asm-i386/auxvec.h => asm-x86/auxvec_32.h} (100%) rename include/{asm-x86_64/auxvec.h => asm-x86/auxvec_64.h} (100%) create mode 100644 include/asm-x86/bitops.h rename include/{asm-i386/bitops.h => asm-x86/bitops_32.h} (100%) rename include/{asm-x86_64/bitops.h => asm-x86/bitops_64.h} (100%) rename include/{asm-i386 => asm-x86}/boot.h (100%) rename include/{asm-i386 => asm-x86}/bootparam.h (100%) rename include/{asm-x86_64 => asm-x86}/bootsetup.h (100%) create mode 100644 include/asm-x86/bug.h rename include/{asm-i386/bug.h => asm-x86/bug_32.h} (100%) rename include/{asm-x86_64/bug.h => asm-x86/bug_64.h} (100%) create mode 100644 include/asm-x86/bugs.h rename include/{asm-i386/bugs.h => asm-x86/bugs_32.h} (100%) rename include/{asm-x86_64/bugs.h => asm-x86/bugs_64.h} (100%) create mode 100644 include/asm-x86/byteorder.h rename include/{asm-i386/byteorder.h => asm-x86/byteorder_32.h} (100%) rename include/{asm-x86_64/byteorder.h => asm-x86/byteorder_64.h} (100%) create mode 100644 include/asm-x86/cache.h rename include/{asm-i386/cache.h => asm-x86/cache_32.h} (100%) rename include/{asm-x86_64/cache.h => asm-x86/cache_64.h} (100%) create mode 100644 include/asm-x86/cacheflush.h rename include/{asm-i386/cacheflush.h => asm-x86/cacheflush_32.h} (100%) rename include/{asm-x86_64/cacheflush.h => asm-x86/cacheflush_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/calgary.h (100%) rename include/{asm-x86_64 => asm-x86}/calling.h (100%) create mode 100644 include/asm-x86/checksum.h rename include/{asm-i386/checksum.h => asm-x86/checksum_32.h} (100%) rename include/{asm-x86_64/checksum.h => asm-x86/checksum_64.h} (100%) create mode 100644 include/asm-x86/cmpxchg.h rename include/{asm-i386/cmpxchg.h => asm-x86/cmpxchg_32.h} (100%) rename include/{asm-x86_64/cmpxchg.h => asm-x86/cmpxchg_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/compat.h (100%) rename include/{asm-i386 => asm-x86}/cpu.h (100%) create mode 100644 include/asm-x86/cpufeature.h rename include/{asm-i386/cpufeature.h => asm-x86/cpufeature_32.h} (100%) rename include/{asm-x86_64/cpufeature.h => asm-x86/cpufeature_64.h} (91%) create mode 100644 include/asm-x86/cputime.h rename include/{asm-i386/cputime.h => asm-x86/cputime_32.h} (100%) rename include/{asm-x86_64/cputime.h => asm-x86/cputime_64.h} (100%) create mode 100644 include/asm-x86/current.h rename include/{asm-i386/current.h => asm-x86/current_32.h} (100%) rename include/{asm-x86_64/current.h => asm-x86/current_64.h} (100%) create mode 100644 include/asm-x86/debugreg.h rename include/{asm-i386/debugreg.h => asm-x86/debugreg_32.h} (100%) rename include/{asm-x86_64/debugreg.h => asm-x86/debugreg_64.h} (100%) create mode 100644 include/asm-x86/delay.h rename include/{asm-i386/delay.h => asm-x86/delay_32.h} (100%) rename include/{asm-x86_64/delay.h => asm-x86/delay_64.h} (100%) create mode 100644 include/asm-x86/desc.h rename include/{asm-i386/desc.h => asm-x86/desc_32.h} (100%) rename include/{asm-x86_64/desc.h => asm-x86/desc_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/desc_defs.h (100%) create mode 100644 include/asm-x86/device.h rename include/{asm-i386/device.h => asm-x86/device_32.h} (100%) rename include/{asm-x86_64/device.h => asm-x86/device_64.h} (100%) create mode 100644 include/asm-x86/div64.h rename include/{asm-i386/div64.h => asm-x86/div64_32.h} (100%) rename include/{asm-x86_64/div64.h => asm-x86/div64_64.h} (100%) create mode 100644 include/asm-x86/dma-mapping.h rename include/{asm-i386/dma-mapping.h => asm-x86/dma-mapping_32.h} (100%) rename include/{asm-x86_64/dma-mapping.h => asm-x86/dma-mapping_64.h} (100%) create mode 100644 include/asm-x86/dma.h rename include/{asm-i386/dma.h => asm-x86/dma_32.h} (100%) rename include/{asm-x86_64/dma.h => asm-x86/dma_64.h} (100%) create mode 100644 include/asm-x86/dmi.h rename include/{asm-i386/dmi.h => asm-x86/dmi_32.h} (100%) rename include/{asm-x86_64/dmi.h => asm-x86/dmi_64.h} (100%) create mode 100644 include/asm-x86/dwarf2.h rename include/{asm-i386/dwarf2.h => asm-x86/dwarf2_32.h} (100%) rename include/{asm-x86_64/dwarf2.h => asm-x86/dwarf2_64.h} (100%) create mode 100644 include/asm-x86/e820.h rename include/{asm-i386/e820.h => asm-x86/e820_32.h} (100%) rename include/{asm-x86_64/e820.h => asm-x86/e820_64.h} (100%) create mode 100644 include/asm-x86/edac.h rename include/{asm-i386/edac.h => asm-x86/edac_32.h} (100%) rename include/{asm-x86_64/edac.h => asm-x86/edac_64.h} (100%) create mode 100644 include/asm-x86/elf.h rename include/{asm-i386/elf.h => asm-x86/elf_32.h} (100%) rename include/{asm-x86_64/elf.h => asm-x86/elf_64.h} (100%) rename include/{asm-i386 => asm-x86}/emergency-restart.h (100%) create mode 100644 include/asm-x86/errno.h rename include/{asm-i386/errno.h => asm-x86/errno_32.h} (100%) rename include/{asm-x86_64/errno.h => asm-x86/errno_64.h} (100%) create mode 100644 include/asm-x86/fb.h rename include/{asm-i386/fb.h => asm-x86/fb_32.h} (100%) rename include/{asm-x86_64/fb.h => asm-x86/fb_64.h} (100%) rename include/{asm-i386 => asm-x86}/fcntl.h (100%) create mode 100644 include/asm-x86/fixmap.h rename include/{asm-i386/fixmap.h => asm-x86/fixmap_32.h} (100%) rename include/{asm-x86_64/fixmap.h => asm-x86/fixmap_64.h} (100%) create mode 100644 include/asm-x86/floppy.h rename include/{asm-i386/floppy.h => asm-x86/floppy_32.h} (100%) rename include/{asm-x86_64/floppy.h => asm-x86/floppy_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/fpu32.h (100%) rename include/{asm-i386 => asm-x86}/frame.i (100%) create mode 100644 include/asm-x86/futex.h rename include/{asm-i386/futex.h => asm-x86/futex_32.h} (100%) rename include/{asm-x86_64/futex.h => asm-x86/futex_64.h} (100%) create mode 100644 include/asm-x86/genapic.h rename include/{asm-i386/genapic.h => asm-x86/genapic_32.h} (100%) rename include/{asm-x86_64/genapic.h => asm-x86/genapic_64.h} (100%) rename include/{asm-i386 => asm-x86}/geode.h (100%) create mode 100644 include/asm-x86/hardirq.h rename include/{asm-i386/hardirq.h => asm-x86/hardirq_32.h} (100%) rename include/{asm-x86_64/hardirq.h => asm-x86/hardirq_64.h} (100%) rename include/{asm-i386 => asm-x86}/highmem.h (100%) create mode 100644 include/asm-x86/hpet.h rename include/{asm-i386/hpet.h => asm-x86/hpet_32.h} (100%) rename include/{asm-x86_64/hpet.h => asm-x86/hpet_64.h} (93%) create mode 100644 include/asm-x86/hw_irq.h rename include/{asm-i386/hw_irq.h => asm-x86/hw_irq_32.h} (100%) rename include/{asm-x86_64/hw_irq.h => asm-x86/hw_irq_64.h} (100%) rename include/{asm-i386 => asm-x86}/hypertransport.h (100%) create mode 100644 include/asm-x86/i387.h rename include/{asm-i386/i387.h => asm-x86/i387_32.h} (100%) rename include/{asm-x86_64/i387.h => asm-x86/i387_64.h} (100%) create mode 100644 include/asm-x86/i8253.h rename include/{asm-i386/i8253.h => asm-x86/i8253_32.h} (100%) rename include/{asm-x86_64/i8253.h => asm-x86/i8253_64.h} (100%) rename include/{asm-i386 => asm-x86}/i8259.h (100%) rename include/{asm-x86_64 => asm-x86}/ia32.h (100%) rename include/{asm-x86_64 => asm-x86}/ia32_unistd.h (100%) rename include/{asm-i386 => asm-x86}/ide.h (100%) rename include/{asm-x86_64 => asm-x86}/idle.h (100%) create mode 100644 include/asm-x86/intel_arch_perfmon.h rename include/{asm-i386/intel_arch_perfmon.h => asm-x86/intel_arch_perfmon_32.h} (100%) rename include/{asm-x86_64/intel_arch_perfmon.h => asm-x86/intel_arch_perfmon_64.h} (100%) create mode 100644 include/asm-x86/io.h rename include/{asm-i386/io.h => asm-x86/io_32.h} (100%) rename include/{asm-x86_64/io.h => asm-x86/io_64.h} (100%) create mode 100644 include/asm-x86/io_apic.h rename include/{asm-i386/io_apic.h => asm-x86/io_apic_32.h} (100%) rename include/{asm-x86_64/io_apic.h => asm-x86/io_apic_64.h} (100%) rename include/{asm-i386 => asm-x86}/ioctl.h (100%) create mode 100644 include/asm-x86/ioctls.h rename include/{asm-i386/ioctls.h => asm-x86/ioctls_32.h} (100%) rename include/{asm-x86_64/ioctls.h => asm-x86/ioctls_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/iommu.h (100%) rename include/{asm-i386 => asm-x86}/ipc.h (100%) create mode 100644 include/asm-x86/ipcbuf.h rename include/{asm-i386/ipcbuf.h => asm-x86/ipcbuf_32.h} (100%) rename include/{asm-x86_64/ipcbuf.h => asm-x86/ipcbuf_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/ipi.h (100%) create mode 100644 include/asm-x86/irq.h rename include/{asm-i386/irq.h => asm-x86/irq_32.h} (100%) rename include/{asm-x86_64/irq.h => asm-x86/irq_64.h} (100%) create mode 100644 include/asm-x86/irq_regs.h rename include/{asm-i386/irq_regs.h => asm-x86/irq_regs_32.h} (100%) rename include/{asm-x86_64/irq_regs.h => asm-x86/irq_regs_64.h} (100%) create mode 100644 include/asm-x86/irqflags.h rename include/{asm-i386/irqflags.h => asm-x86/irqflags_32.h} (100%) rename include/{asm-x86_64/irqflags.h => asm-x86/irqflags_64.h} (100%) rename include/{asm-i386 => asm-x86}/ist.h (100%) rename include/{asm-x86_64 => asm-x86}/k8.h (100%) create mode 100644 include/asm-x86/kdebug.h rename include/{asm-i386/kdebug.h => asm-x86/kdebug_32.h} (100%) rename include/{asm-x86_64/kdebug.h => asm-x86/kdebug_64.h} (100%) create mode 100644 include/asm-x86/kexec.h rename include/{asm-i386/kexec.h => asm-x86/kexec_32.h} (100%) rename include/{asm-x86_64/kexec.h => asm-x86/kexec_64.h} (100%) create mode 100644 include/asm-x86/kmap_types.h rename include/{asm-i386/kmap_types.h => asm-x86/kmap_types_32.h} (100%) rename include/{asm-x86_64/kmap_types.h => asm-x86/kmap_types_64.h} (100%) create mode 100644 include/asm-x86/kprobes.h rename include/{asm-i386/kprobes.h => asm-x86/kprobes_32.h} (100%) rename include/{asm-x86_64/kprobes.h => asm-x86/kprobes_64.h} (100%) create mode 100644 include/asm-x86/ldt.h rename include/{asm-i386/ldt.h => asm-x86/ldt_32.h} (100%) rename include/{asm-x86_64/ldt.h => asm-x86/ldt_64.h} (100%) create mode 100644 include/asm-x86/linkage.h rename include/{asm-i386/linkage.h => asm-x86/linkage_32.h} (100%) rename include/{asm-x86_64/linkage.h => asm-x86/linkage_64.h} (100%) create mode 100644 include/asm-x86/local.h rename include/{asm-i386/local.h => asm-x86/local_32.h} (100%) rename include/{asm-x86_64/local.h => asm-x86/local_64.h} (100%) rename include/{asm-i386 => asm-x86}/mach-bigsmp/mach_apic.h (100%) rename include/{asm-i386 => asm-x86}/mach-bigsmp/mach_apicdef.h (100%) rename include/{asm-i386 => asm-x86}/mach-bigsmp/mach_ipi.h (100%) rename include/{asm-i386 => asm-x86}/mach-bigsmp/mach_mpspec.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/apm.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/bios_ebda.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/do_timer.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/entry_arch.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/io_ports.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/irq_vectors.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/irq_vectors_limits.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_apic.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_apicdef.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_ipi.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_mpparse.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_mpspec.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_reboot.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_time.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_timer.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_traps.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/mach_wakecpu.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/pci-functions.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/setup_arch.h (100%) rename include/{asm-i386 => asm-x86}/mach-default/smpboot_hooks.h (100%) rename include/{asm-i386 => asm-x86}/mach-es7000/mach_apic.h (100%) rename include/{asm-i386 => asm-x86}/mach-es7000/mach_apicdef.h (100%) rename include/{asm-i386 => asm-x86}/mach-es7000/mach_ipi.h (100%) rename include/{asm-i386 => asm-x86}/mach-es7000/mach_mpparse.h (100%) rename include/{asm-i386 => asm-x86}/mach-es7000/mach_mpspec.h (100%) rename include/{asm-i386 => asm-x86}/mach-es7000/mach_wakecpu.h (100%) rename include/{asm-i386 => asm-x86}/mach-generic/irq_vectors_limits.h (100%) rename include/{asm-i386 => asm-x86}/mach-generic/mach_apic.h (100%) rename include/{asm-i386 => asm-x86}/mach-generic/mach_apicdef.h (100%) rename include/{asm-i386 => asm-x86}/mach-generic/mach_ipi.h (100%) rename include/{asm-i386 => asm-x86}/mach-generic/mach_mpparse.h (100%) rename include/{asm-i386 => asm-x86}/mach-generic/mach_mpspec.h (100%) rename include/{asm-i386 => asm-x86}/mach-numaq/mach_apic.h (100%) rename include/{asm-i386 => asm-x86}/mach-numaq/mach_apicdef.h (100%) rename include/{asm-i386 => asm-x86}/mach-numaq/mach_ipi.h (100%) rename include/{asm-i386 => asm-x86}/mach-numaq/mach_mpparse.h (100%) rename include/{asm-i386 => asm-x86}/mach-numaq/mach_mpspec.h (100%) rename include/{asm-i386 => asm-x86}/mach-numaq/mach_wakecpu.h (100%) rename include/{asm-i386 => asm-x86}/mach-summit/irq_vectors_limits.h (100%) rename include/{asm-i386 => asm-x86}/mach-summit/mach_apic.h (100%) rename include/{asm-i386 => asm-x86}/mach-summit/mach_apicdef.h (100%) rename include/{asm-i386 => asm-x86}/mach-summit/mach_ipi.h (100%) rename include/{asm-i386 => asm-x86}/mach-summit/mach_mpparse.h (100%) rename include/{asm-i386 => asm-x86}/mach-summit/mach_mpspec.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/cobalt.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/entry_arch.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/irq_vectors.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/lithium.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/mach_apic.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/mach_apicdef.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/piix4.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/setup_arch.h (100%) rename include/{asm-i386 => asm-x86}/mach-visws/smpboot_hooks.h (100%) rename include/{asm-i386 => asm-x86}/mach-voyager/do_timer.h (100%) rename include/{asm-i386 => asm-x86}/mach-voyager/entry_arch.h (100%) rename include/{asm-i386 => asm-x86}/mach-voyager/irq_vectors.h (100%) rename include/{asm-i386 => asm-x86}/mach-voyager/setup_arch.h (100%) rename include/{asm-x86_64 => asm-x86}/mach_apic.h (100%) rename include/{asm-i386 => asm-x86}/math_emu.h (100%) create mode 100644 include/asm-x86/mc146818rtc.h rename include/{asm-i386/mc146818rtc.h => asm-x86/mc146818rtc_32.h} (100%) rename include/{asm-x86_64/mc146818rtc.h => asm-x86/mc146818rtc_64.h} (100%) rename include/{asm-i386 => asm-x86}/mca.h (100%) rename include/{asm-i386 => asm-x86}/mca_dma.h (100%) create mode 100644 include/asm-x86/mce.h rename include/{asm-i386/mce.h => asm-x86/mce_32.h} (100%) rename include/{asm-x86_64/mce.h => asm-x86/mce_64.h} (100%) create mode 100644 include/asm-x86/mman.h rename include/{asm-i386/mman.h => asm-x86/mman_32.h} (100%) rename include/{asm-x86_64/mman.h => asm-x86/mman_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/mmsegment.h (100%) create mode 100644 include/asm-x86/mmu.h rename include/{asm-i386/mmu.h => asm-x86/mmu_32.h} (100%) rename include/{asm-x86_64/mmu.h => asm-x86/mmu_64.h} (100%) create mode 100644 include/asm-x86/mmu_context.h rename include/{asm-i386/mmu_context.h => asm-x86/mmu_context_32.h} (100%) rename include/{asm-x86_64/mmu_context.h => asm-x86/mmu_context_64.h} (100%) rename include/{asm-i386 => asm-x86}/mmx.h (100%) create mode 100644 include/asm-x86/mmzone.h rename include/{asm-i386/mmzone.h => asm-x86/mmzone_32.h} (100%) rename include/{asm-x86_64/mmzone.h => asm-x86/mmzone_64.h} (100%) create mode 100644 include/asm-x86/module.h rename include/{asm-i386/module.h => asm-x86/module_32.h} (100%) rename include/{asm-x86_64/module.h => asm-x86/module_64.h} (100%) create mode 100644 include/asm-x86/mpspec.h rename include/{asm-i386/mpspec.h => asm-x86/mpspec_32.h} (100%) rename include/{asm-x86_64/mpspec.h => asm-x86/mpspec_64.h} (100%) rename include/{asm-i386 => asm-x86}/mpspec_def.h (100%) create mode 100644 include/asm-x86/msgbuf.h rename include/{asm-i386/msgbuf.h => asm-x86/msgbuf_32.h} (100%) rename include/{asm-x86_64/msgbuf.h => asm-x86/msgbuf_64.h} (100%) rename include/{asm-i386 => asm-x86}/msidef.h (100%) rename include/{asm-i386 => asm-x86}/msr-index.h (100%) create mode 100644 include/asm-x86/msr.h rename include/{asm-i386/msr.h => asm-x86/msr_32.h} (100%) rename include/{asm-x86_64/msr.h => asm-x86/msr_64.h} (100%) create mode 100644 include/asm-x86/mtrr.h rename include/{asm-i386/mtrr.h => asm-x86/mtrr_32.h} (100%) rename include/{asm-x86_64/mtrr.h => asm-x86/mtrr_64.h} (100%) create mode 100644 include/asm-x86/mutex.h rename include/{asm-i386/mutex.h => asm-x86/mutex_32.h} (100%) rename include/{asm-x86_64/mutex.h => asm-x86/mutex_64.h} (100%) create mode 100644 include/asm-x86/namei.h rename include/{asm-i386/namei.h => asm-x86/namei_32.h} (100%) rename include/{asm-x86_64/namei.h => asm-x86/namei_64.h} (100%) create mode 100644 include/asm-x86/nmi.h rename include/{asm-i386/nmi.h => asm-x86/nmi_32.h} (100%) rename include/{asm-x86_64/nmi.h => asm-x86/nmi_64.h} (100%) create mode 100644 include/asm-x86/numa.h rename include/{asm-i386/numa.h => asm-x86/numa_32.h} (100%) rename include/{asm-x86_64/numa.h => asm-x86/numa_64.h} (100%) rename include/{asm-i386 => asm-x86}/numaq.h (100%) create mode 100644 include/asm-x86/page.h rename include/{asm-i386/page.h => asm-x86/page_32.h} (100%) rename include/{asm-x86_64/page.h => asm-x86/page_64.h} (100%) create mode 100644 include/asm-x86/param.h rename include/{asm-i386/param.h => asm-x86/param_32.h} (100%) rename include/{asm-x86_64/param.h => asm-x86/param_64.h} (100%) rename include/{asm-i386 => asm-x86}/paravirt.h (100%) create mode 100644 include/asm-x86/parport.h rename include/{asm-i386/parport.h => asm-x86/parport_32.h} (100%) rename include/{asm-x86_64/parport.h => asm-x86/parport_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/pci-direct.h (100%) create mode 100644 include/asm-x86/pci.h rename include/{asm-i386/pci.h => asm-x86/pci_32.h} (100%) rename include/{asm-x86_64/pci.h => asm-x86/pci_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/pda.h (100%) create mode 100644 include/asm-x86/percpu.h rename include/{asm-i386/percpu.h => asm-x86/percpu_32.h} (100%) rename include/{asm-x86_64/percpu.h => asm-x86/percpu_64.h} (100%) create mode 100644 include/asm-x86/pgalloc.h rename include/{asm-i386/pgalloc.h => asm-x86/pgalloc_32.h} (100%) rename include/{asm-x86_64/pgalloc.h => asm-x86/pgalloc_64.h} (100%) rename include/{asm-i386 => asm-x86}/pgtable-2level-defs.h (100%) rename include/{asm-i386 => asm-x86}/pgtable-2level.h (100%) rename include/{asm-i386 => asm-x86}/pgtable-3level-defs.h (100%) rename include/{asm-i386 => asm-x86}/pgtable-3level.h (100%) create mode 100644 include/asm-x86/pgtable.h rename include/{asm-i386/pgtable.h => asm-x86/pgtable_32.h} (100%) rename include/{asm-x86_64/pgtable.h => asm-x86/pgtable_64.h} (100%) rename include/{asm-i386 => asm-x86}/poll.h (100%) create mode 100644 include/asm-x86/posix_types.h rename include/{asm-i386/posix_types.h => asm-x86/posix_types_32.h} (100%) rename include/{asm-x86_64/posix_types.h => asm-x86/posix_types_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/prctl.h (100%) rename include/{asm-i386 => asm-x86}/processor-cyrix.h (100%) rename include/{asm-i386 => asm-x86}/processor-flags.h (100%) create mode 100644 include/asm-x86/processor.h rename include/{asm-i386/processor.h => asm-x86/processor_32.h} (100%) rename include/{asm-x86_64/processor.h => asm-x86/processor_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/proto.h (100%) create mode 100644 include/asm-x86/ptrace-abi.h rename include/{asm-i386/ptrace-abi.h => asm-x86/ptrace-abi_32.h} (100%) rename include/{asm-x86_64/ptrace-abi.h => asm-x86/ptrace-abi_64.h} (100%) create mode 100644 include/asm-x86/ptrace.h rename include/{asm-i386/ptrace.h => asm-x86/ptrace_32.h} (100%) rename include/{asm-x86_64/ptrace.h => asm-x86/ptrace_64.h} (100%) rename include/{asm-i386 => asm-x86}/reboot.h (100%) rename include/{asm-i386 => asm-x86}/reboot_fixups.h (100%) create mode 100644 include/asm-x86/required-features.h rename include/{asm-i386/required-features.h => asm-x86/required-features_32.h} (100%) rename include/{asm-x86_64/required-features.h => asm-x86/required-features_64.h} (100%) create mode 100644 include/asm-x86/resource.h rename include/{asm-i386/resource.h => asm-x86/resource_32.h} (100%) rename include/{asm-x86_64/resource.h => asm-x86/resource_64.h} (100%) create mode 100644 include/asm-x86/resume-trace.h rename include/{asm-i386/resume-trace.h => asm-x86/resume-trace_32.h} (100%) rename include/{asm-x86_64/resume-trace.h => asm-x86/resume-trace_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/rio.h (100%) create mode 100644 include/asm-x86/rtc.h rename include/{asm-i386/rtc.h => asm-x86/rtc_32.h} (100%) rename include/{asm-x86_64/rtc.h => asm-x86/rtc_64.h} (100%) create mode 100644 include/asm-x86/rwlock.h rename include/{asm-i386/rwlock.h => asm-x86/rwlock_32.h} (100%) rename include/{asm-x86_64/rwlock.h => asm-x86/rwlock_64.h} (100%) rename include/{asm-i386 => asm-x86}/rwsem.h (100%) create mode 100644 include/asm-x86/scatterlist.h rename include/{asm-i386/scatterlist.h => asm-x86/scatterlist_32.h} (100%) rename include/{asm-x86_64/scatterlist.h => asm-x86/scatterlist_64.h} (100%) create mode 100644 include/asm-x86/seccomp.h rename include/{asm-i386/seccomp.h => asm-x86/seccomp_32.h} (100%) rename include/{asm-x86_64/seccomp.h => asm-x86/seccomp_64.h} (100%) create mode 100644 include/asm-x86/sections.h rename include/{asm-i386/sections.h => asm-x86/sections_32.h} (100%) rename include/{asm-x86_64/sections.h => asm-x86/sections_64.h} (100%) create mode 100644 include/asm-x86/segment.h rename include/{asm-i386/segment.h => asm-x86/segment_32.h} (100%) rename include/{asm-x86_64/segment.h => asm-x86/segment_64.h} (100%) create mode 100644 include/asm-x86/semaphore.h rename include/{asm-i386/semaphore.h => asm-x86/semaphore_32.h} (100%) rename include/{asm-x86_64/semaphore.h => asm-x86/semaphore_64.h} (100%) create mode 100644 include/asm-x86/sembuf.h rename include/{asm-i386/sembuf.h => asm-x86/sembuf_32.h} (100%) rename include/{asm-x86_64/sembuf.h => asm-x86/sembuf_64.h} (100%) create mode 100644 include/asm-x86/serial.h rename include/{asm-i386/serial.h => asm-x86/serial_32.h} (100%) rename include/{asm-x86_64/serial.h => asm-x86/serial_64.h} (100%) create mode 100644 include/asm-x86/setup.h rename include/{asm-i386/setup.h => asm-x86/setup_32.h} (100%) rename include/{asm-x86_64/setup.h => asm-x86/setup_64.h} (100%) create mode 100644 include/asm-x86/shmbuf.h rename include/{asm-i386/shmbuf.h => asm-x86/shmbuf_32.h} (100%) rename include/{asm-x86_64/shmbuf.h => asm-x86/shmbuf_64.h} (100%) create mode 100644 include/asm-x86/shmparam.h rename include/{asm-i386/shmparam.h => asm-x86/shmparam_32.h} (100%) rename include/{asm-x86_64/shmparam.h => asm-x86/shmparam_64.h} (100%) create mode 100644 include/asm-x86/sigcontext.h rename include/{asm-x86_64 => asm-x86}/sigcontext32.h (100%) rename include/{asm-i386/sigcontext.h => asm-x86/sigcontext_32.h} (100%) rename include/{asm-x86_64/sigcontext.h => asm-x86/sigcontext_64.h} (100%) create mode 100644 include/asm-x86/siginfo.h rename include/{asm-i386/siginfo.h => asm-x86/siginfo_32.h} (100%) rename include/{asm-x86_64/siginfo.h => asm-x86/siginfo_64.h} (100%) create mode 100644 include/asm-x86/signal.h rename include/{asm-i386/signal.h => asm-x86/signal_32.h} (100%) rename include/{asm-x86_64/signal.h => asm-x86/signal_64.h} (100%) create mode 100644 include/asm-x86/smp.h rename include/{asm-i386/smp.h => asm-x86/smp_32.h} (100%) rename include/{asm-x86_64/smp.h => asm-x86/smp_64.h} (100%) rename include/{asm-i386 => asm-x86}/socket.h (100%) create mode 100644 include/asm-x86/sockios.h rename include/{asm-i386/sockios.h => asm-x86/sockios_32.h} (100%) rename include/{asm-x86_64/sockios.h => asm-x86/sockios_64.h} (100%) create mode 100644 include/asm-x86/sparsemem.h rename include/{asm-i386/sparsemem.h => asm-x86/sparsemem_32.h} (100%) rename include/{asm-x86_64/sparsemem.h => asm-x86/sparsemem_64.h} (100%) create mode 100644 include/asm-x86/spinlock.h rename include/{asm-i386/spinlock.h => asm-x86/spinlock_32.h} (100%) rename include/{asm-x86_64/spinlock.h => asm-x86/spinlock_64.h} (100%) rename include/{asm-i386 => asm-x86}/spinlock_types.h (100%) rename include/{asm-i386 => asm-x86}/srat.h (100%) rename include/{asm-x86_64 => asm-x86}/stacktrace.h (100%) create mode 100644 include/asm-x86/stat.h rename include/{asm-i386/stat.h => asm-x86/stat_32.h} (100%) rename include/{asm-x86_64/stat.h => asm-x86/stat_64.h} (100%) create mode 100644 include/asm-x86/statfs.h rename include/{asm-i386/statfs.h => asm-x86/statfs_32.h} (100%) rename include/{asm-x86_64/statfs.h => asm-x86/statfs_64.h} (100%) create mode 100644 include/asm-x86/string.h rename include/{asm-i386/string.h => asm-x86/string_32.h} (100%) rename include/{asm-x86_64/string.h => asm-x86/string_64.h} (100%) create mode 100644 include/asm-x86/suspend.h rename include/{asm-i386/suspend.h => asm-x86/suspend_32.h} (100%) rename include/{asm-x86_64/suspend.h => asm-x86/suspend_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/swiotlb.h (100%) rename include/{asm-i386 => asm-x86}/sync_bitops.h (100%) create mode 100644 include/asm-x86/system.h rename include/{asm-i386/system.h => asm-x86/system_32.h} (100%) rename include/{asm-x86_64/system.h => asm-x86/system_64.h} (100%) rename include/{asm-x86_64 => asm-x86}/tce.h (100%) create mode 100644 include/asm-x86/termbits.h rename include/{asm-i386/termbits.h => asm-x86/termbits_32.h} (100%) rename include/{asm-x86_64/termbits.h => asm-x86/termbits_64.h} (100%) create mode 100644 include/asm-x86/termios.h rename include/{asm-i386/termios.h => asm-x86/termios_32.h} (100%) rename include/{asm-x86_64/termios.h => asm-x86/termios_64.h} (100%) rename include/{asm-i386 => asm-x86}/therm_throt.h (100%) create mode 100644 include/asm-x86/thread_info.h rename include/{asm-i386/thread_info.h => asm-x86/thread_info_32.h} (100%) rename include/{asm-x86_64/thread_info.h => asm-x86/thread_info_64.h} (100%) rename include/{asm-i386 => asm-x86}/time.h (100%) rename include/{asm-i386 => asm-x86}/timer.h (100%) create mode 100644 include/asm-x86/timex.h rename include/{asm-i386/timex.h => asm-x86/timex_32.h} (100%) rename include/{asm-x86_64/timex.h => asm-x86/timex_64.h} (100%) create mode 100644 include/asm-x86/tlb.h rename include/{asm-i386/tlb.h => asm-x86/tlb_32.h} (100%) rename include/{asm-x86_64/tlb.h => asm-x86/tlb_64.h} (100%) create mode 100644 include/asm-x86/tlbflush.h rename include/{asm-i386/tlbflush.h => asm-x86/tlbflush_32.h} (100%) rename include/{asm-x86_64/tlbflush.h => asm-x86/tlbflush_64.h} (100%) create mode 100644 include/asm-x86/topology.h rename include/{asm-i386/topology.h => asm-x86/topology_32.h} (100%) rename include/{asm-x86_64/topology.h => asm-x86/topology_64.h} (100%) rename include/{asm-i386 => asm-x86}/tsc.h (100%) create mode 100644 include/asm-x86/types.h rename include/{asm-i386/types.h => asm-x86/types_32.h} (100%) rename include/{asm-x86_64/types.h => asm-x86/types_64.h} (100%) create mode 100644 include/asm-x86/uaccess.h rename include/{asm-i386/uaccess.h => asm-x86/uaccess_32.h} (100%) rename include/{asm-x86_64/uaccess.h => asm-x86/uaccess_64.h} (100%) create mode 100644 include/asm-x86/ucontext.h rename include/{asm-i386/ucontext.h => asm-x86/ucontext_32.h} (100%) rename include/{asm-x86_64/ucontext.h => asm-x86/ucontext_64.h} (100%) create mode 100644 include/asm-x86/unaligned.h rename include/{asm-i386/unaligned.h => asm-x86/unaligned_32.h} (100%) rename include/{asm-x86_64/unaligned.h => asm-x86/unaligned_64.h} (100%) create mode 100644 include/asm-x86/unistd.h rename include/{asm-i386/unistd.h => asm-x86/unistd_32.h} (100%) rename include/{asm-x86_64/unistd.h => asm-x86/unistd_64.h} (100%) create mode 100644 include/asm-x86/unwind.h rename include/{asm-i386/unwind.h => asm-x86/unwind_32.h} (100%) rename include/{asm-x86_64/unwind.h => asm-x86/unwind_64.h} (100%) create mode 100644 include/asm-x86/user.h rename include/{asm-x86_64 => asm-x86}/user32.h (100%) rename include/{asm-i386/user.h => asm-x86/user_32.h} (100%) rename include/{asm-x86_64/user.h => asm-x86/user_64.h} (100%) rename include/{asm-i386 => asm-x86}/vga.h (100%) rename include/{asm-x86_64 => asm-x86}/vgtod.h (100%) rename include/{asm-i386 => asm-x86}/vic.h (100%) rename include/{asm-i386 => asm-x86}/vm86.h (100%) rename include/{asm-i386 => asm-x86}/vmi.h (100%) rename include/{asm-i386 => asm-x86}/vmi_time.h (100%) rename include/{asm-i386 => asm-x86}/voyager.h (100%) rename include/{asm-x86_64 => asm-x86}/vsyscall.h (100%) rename include/{asm-x86_64 => asm-x86}/vsyscall32.h (100%) rename include/{asm-i386 => asm-x86}/xen/hypercall.h (100%) rename include/{asm-i386 => asm-x86}/xen/hypervisor.h (100%) rename include/{asm-i386 => asm-x86}/xen/interface.h (100%) create mode 100644 include/asm-x86/xor.h rename include/{asm-i386/xor.h => asm-x86/xor_32.h} (100%) rename include/{asm-x86_64/xor.h => asm-x86/xor_64.h} (100%) delete mode 100644 include/asm-x86_64/Kbuild delete mode 100644 include/asm-x86_64/boot.h delete mode 100644 include/asm-x86_64/bootparam.h delete mode 100644 include/asm-x86_64/cpu.h delete mode 100644 include/asm-x86_64/emergency-restart.h delete mode 100644 include/asm-x86_64/fcntl.h delete mode 100644 include/asm-x86_64/hypertransport.h delete mode 100644 include/asm-x86_64/ide.h delete mode 100644 include/asm-x86_64/ioctl.h delete mode 100644 include/asm-x86_64/ist.h delete mode 100644 include/asm-x86_64/msidef.h delete mode 100644 include/asm-x86_64/msr-index.h delete mode 100644 include/asm-x86_64/poll.h delete mode 100644 include/asm-x86_64/processor-flags.h delete mode 100644 include/asm-x86_64/socket.h delete mode 100644 include/asm-x86_64/spinlock_types.h delete mode 100644 include/asm-x86_64/therm_throt.h delete mode 100644 include/asm-x86_64/tsc.h delete mode 100644 include/asm-x86_64/vga.h diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index 73c5f1f3d5d2..103e346c8b6a 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c @@ -46,7 +46,7 @@ typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8; #include "../../include/linux/lguest_launcher.h" -#include "../../include/asm-i386/e820.h" +#include "../../include/asm-x86/e820_32.h" /*:*/ #define PAGE_PRESENT 0x7 /* Present, RW, Execute */ diff --git a/Kbuild b/Kbuild index 2d403cfa4b16..1570d248ad92 100644 --- a/Kbuild +++ b/Kbuild @@ -8,7 +8,7 @@ # 1) Generate asm-offsets.h # -offsets-file := include/asm-$(ARCH)/asm-offsets.h +offsets-file := include/asm-$(SRCARCH)/asm-offsets.h always := $(offsets-file) targets := $(offsets-file) diff --git a/Makefile b/Makefile index f2067e337d4d..2a30f5fd8294 100644 --- a/Makefile +++ b/Makefile @@ -863,7 +863,7 @@ ifneq ($(KBUILD_SRC),) /bin/false; \ fi; $(Q)if [ ! -d include2 ]; then mkdir -p include2; fi; - $(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm + $(Q)ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm endif # prepare2 creates a makefile if using a separate output directory @@ -895,9 +895,9 @@ export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH) # before switching between archs anyway. include/asm: - @echo ' SYMLINK $@ -> include/asm-$(ARCH)' + @echo ' SYMLINK $@ -> include/asm-$(SRCARCH)' $(Q)if [ ! -d include ]; then mkdir -p include; fi; - @ln -fsn asm-$(ARCH) $@ + @ln -fsn asm-$(SRCARCH) $@ # Generate some files # --------------------------------------------------------------------------- @@ -937,7 +937,8 @@ depend dep: INSTALL_HDR_PATH=$(objtree)/usr export INSTALL_HDR_PATH -HDRARCHES=$(filter-out generic,$(patsubst $(srctree)/include/asm-%/Kbuild,%,$(wildcard $(srctree)/include/asm-*/Kbuild))) +HDRFILTER=generic i386 x86_64 +HDRARCHES=$(filter-out $(HDRFILTER),$(patsubst $(srctree)/include/asm-%/Kbuild,%,$(wildcard $(srctree)/include/asm-*/Kbuild))) PHONY += headers_install_all headers_install_all: include/linux/version.h scripts_basic FORCE @@ -948,11 +949,11 @@ headers_install_all: include/linux/version.h scripts_basic FORCE PHONY += headers_install headers_install: include/linux/version.h scripts_basic FORCE - @if [ ! -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \ - echo '*** Error: Headers not exportable for this architecture ($(ARCH))'; \ + @if [ ! -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \ + echo '*** Error: Headers not exportable for this architecture ($(SRCARCH))'; \ exit 1 ; fi $(Q)$(MAKE) $(build)=scripts scripts/unifdef - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst obj=include + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst ARCH=$(SRCARCH) obj=include PHONY += headers_check_all headers_check_all: headers_install_all @@ -962,7 +963,7 @@ headers_check_all: headers_install_all PHONY += headers_check headers_check: headers_install - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst obj=include HDRCHECK=1 + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst ARCH=$(SRCARCH) obj=include HDRCHECK=1 # --------------------------------------------------------------------------- # Modules diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 9c1da722964d..b433dae1ac7d 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -71,32 +71,32 @@ CFLAGS += $(cflags-y) mcore-y := arch/x86/mach-default # Voyager subarch support -mflags-$(CONFIG_X86_VOYAGER) := -Iinclude/asm-i386/mach-voyager +mflags-$(CONFIG_X86_VOYAGER) := -Iinclude/asm-x86/mach-voyager mcore-$(CONFIG_X86_VOYAGER) := arch/x86/mach-voyager # VISWS subarch support -mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-i386/mach-visws +mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-x86/mach-visws mcore-$(CONFIG_X86_VISWS) := arch/x86/mach-visws # NUMAQ subarch support -mflags-$(CONFIG_X86_NUMAQ) := -Iinclude/asm-i386/mach-numaq +mflags-$(CONFIG_X86_NUMAQ) := -Iinclude/asm-x86/mach-numaq mcore-$(CONFIG_X86_NUMAQ) := arch/x86/mach-default # BIGSMP subarch support -mflags-$(CONFIG_X86_BIGSMP) := -Iinclude/asm-i386/mach-bigsmp +mflags-$(CONFIG_X86_BIGSMP) := -Iinclude/asm-x86/mach-bigsmp mcore-$(CONFIG_X86_BIGSMP) := arch/x86/mach-default #Summit subarch support -mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit +mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-x86/mach-summit mcore-$(CONFIG_X86_SUMMIT) := arch/x86/mach-default # generic subarchitecture -mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic +mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-x86/mach-generic mcore-$(CONFIG_X86_GENERICARCH) := arch/x86/mach-default core-$(CONFIG_X86_GENERICARCH) += arch/x86/mach-generic/ # ES7000 subarch support -mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-i386/mach-es7000 +mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-x86/mach-es7000 mcore-$(CONFIG_X86_ES7000) := arch/x86/mach-default core-$(CONFIG_X86_ES7000) := arch/x86/mach-es7000/ @@ -104,7 +104,7 @@ core-$(CONFIG_X86_ES7000) := arch/x86/mach-es7000/ core-$(CONFIG_XEN) += arch/x86/xen/ # default subarch .h files -mflags-y += -Iinclude/asm-i386/mach-default +mflags-y += -Iinclude/asm-x86/mach-default head-y := arch/x86/kernel/head_32.o arch/x86/kernel/init_task_32.o diff --git a/arch/ia64/ia32/audit.c b/arch/ia64/ia32/audit.c index 8850fe40ea34..5e901c75df1b 100644 --- a/arch/ia64/ia32/audit.c +++ b/arch/ia64/ia32/audit.c @@ -1,4 +1,4 @@ -#include +#include unsigned ia32_dir_class[] = { #include diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c index 5133988d3610..71b2ae4ad5de 100644 --- a/arch/um/sys-x86_64/syscall_table.c +++ b/arch/um/sys-x86_64/syscall_table.c @@ -36,7 +36,7 @@ #define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; #undef _ASM_X86_64_UNISTD_H_ -#include +#include #undef __SYSCALL #define __SYSCALL(nr, sym) [ nr ] = sym, @@ -49,5 +49,5 @@ extern void sys_ni_syscall(void); sys_call_ptr_t sys_call_table[UM_NR_syscall_max+1] __cacheline_aligned = { /* Smells like a like a compiler bug -- it doesn't work when the & below is removed. */ [0 ... UM_NR_syscall_max] = &sys_ni_syscall, -#include +#include }; diff --git a/arch/x86/ia32/audit.c b/arch/x86/ia32/audit.c index 8850fe40ea34..91b7b5922dfa 100644 --- a/arch/x86/ia32/audit.c +++ b/arch/x86/ia32/audit.c @@ -1,4 +1,4 @@ -#include +#include unsigned ia32_dir_class[] = { #include diff --git a/arch/x86/ia32/ipc32.c b/arch/x86/ia32/ipc32.c index 369151dc3213..2e1869ec4db4 100644 --- a/arch/x86/ia32/ipc32.c +++ b/arch/x86/ia32/ipc32.c @@ -9,7 +9,7 @@ #include #include -#include +#include asmlinkage long sys32_ipc(u32 call, int first, int second, int third, diff --git a/arch/x86/kernel/cpu/mtrr/state.c b/arch/x86/kernel/cpu/mtrr/state.c index c9014ca4a575..49e20c2afcdf 100644 --- a/arch/x86/kernel/cpu/mtrr/state.c +++ b/arch/x86/kernel/cpu/mtrr/state.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "mtrr.h" diff --git a/arch/x86/kernel/syscall_64.c b/arch/x86/kernel/syscall_64.c index 63d592c276cc..9d498c2f8eea 100644 --- a/arch/x86/kernel/syscall_64.c +++ b/arch/x86/kernel/syscall_64.c @@ -9,7 +9,7 @@ #define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; #undef _ASM_X86_64_UNISTD_H_ -#include +#include #undef __SYSCALL #define __SYSCALL(nr, sym) [ nr ] = sym, @@ -22,5 +22,5 @@ extern void sys_ni_syscall(void); const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { /* Smells like a like a compiler bug -- it doesn't work when the & below is removed. */ [0 ... __NR_syscall_max] = &sys_ni_syscall, -#include +#include }; diff --git a/include/asm-i386/Kbuild b/include/asm-i386/Kbuild deleted file mode 100644 index cbf6e8f1087b..000000000000 --- a/include/asm-i386/Kbuild +++ /dev/null @@ -1,12 +0,0 @@ -include include/asm-generic/Kbuild.asm - -header-y += boot.h -header-y += debugreg.h -header-y += ldt.h -header-y += msr-index.h -header-y += ptrace-abi.h -header-y += ucontext.h - -unifdef-y += msr.h -unifdef-y += mtrr.h -unifdef-y += vm86.h diff --git a/include/asm-i386/k8.h b/include/asm-i386/k8.h deleted file mode 100644 index dfd88a6e6040..000000000000 --- a/include/asm-i386/k8.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-i386/pci-direct.h b/include/asm-i386/pci-direct.h deleted file mode 100644 index 4f6738b08206..000000000000 --- a/include/asm-i386/pci-direct.h +++ /dev/null @@ -1 +0,0 @@ -#include "asm-x86_64/pci-direct.h" diff --git a/include/asm-i386/stacktrace.h b/include/asm-i386/stacktrace.h deleted file mode 100644 index 7d1f6a5cbfca..000000000000 --- a/include/asm-i386/stacktrace.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-sh/mpc1211/mc146818rtc.h b/include/asm-sh/mpc1211/mc146818rtc.h index 0ec78f66cea4..e245f2a3cd78 100644 --- a/include/asm-sh/mpc1211/mc146818rtc.h +++ b/include/asm-sh/mpc1211/mc146818rtc.h @@ -1,6 +1,6 @@ /* * MPC1211 uses PC/AT style RTC definitions. */ -#include +#include diff --git a/include/asm-x86/8253pit.h b/include/asm-x86/8253pit.h new file mode 100644 index 000000000000..d3c2b38a6618 --- /dev/null +++ b/include/asm-x86/8253pit.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "8253pit_32.h" +#else +# include "8253pit_64.h" +#endif diff --git a/include/asm-i386/8253pit.h b/include/asm-x86/8253pit_32.h similarity index 100% rename from include/asm-i386/8253pit.h rename to include/asm-x86/8253pit_32.h diff --git a/include/asm-x86_64/8253pit.h b/include/asm-x86/8253pit_64.h similarity index 100% rename from include/asm-x86_64/8253pit.h rename to include/asm-x86/8253pit_64.h diff --git a/include/asm-x86/Kbuild b/include/asm-x86/Kbuild new file mode 100644 index 000000000000..c5e43cb39874 --- /dev/null +++ b/include/asm-x86/Kbuild @@ -0,0 +1,88 @@ +include include/asm-generic/Kbuild.asm + +header-y += boot.h +header-y += bootsetup.h +header-y += debugreg_32.h +header-y += debugreg_64.h +header-y += debugreg.h +header-y += ldt_32.h +header-y += ldt_64.h +header-y += ldt.h +header-y += msr-index.h +header-y += prctl.h +header-y += ptrace-abi_32.h +header-y += ptrace-abi_64.h +header-y += ptrace-abi.h +header-y += sigcontext32.h +header-y += ucontext_32.h +header-y += ucontext_64.h +header-y += ucontext.h +header-y += vsyscall32.h + +unifdef-y += a.out_32.h +unifdef-y += a.out_64.h +unifdef-y += auxvec_32.h +unifdef-y += auxvec_64.h +unifdef-y += byteorder_32.h +unifdef-y += byteorder_64.h +unifdef-y += elf_32.h +unifdef-y += elf_64.h +unifdef-y += errno_32.h +unifdef-y += errno_64.h +unifdef-y += ioctls_32.h +unifdef-y += ioctls_64.h +unifdef-y += ipcbuf_32.h +unifdef-y += ipcbuf_64.h +unifdef-y += mce.h +unifdef-y += mman_32.h +unifdef-y += mman_64.h +unifdef-y += msgbuf_32.h +unifdef-y += msgbuf_64.h +unifdef-y += msr_32.h +unifdef-y += msr_64.h +unifdef-y += msr.h +unifdef-y += mtrr_32.h +unifdef-y += mtrr_64.h +unifdef-y += mtrr.h +unifdef-y += page_32.h +unifdef-y += page_64.h +unifdef-y += param_32.h +unifdef-y += param_64.h +unifdef-y += posix_types_32.h +unifdef-y += posix_types_64.h +unifdef-y += ptrace_32.h +unifdef-y += ptrace_64.h +unifdef-y += resource_32.h +unifdef-y += resource_64.h +unifdef-y += sembuf_32.h +unifdef-y += sembuf_64.h +unifdef-y += setup_32.h +unifdef-y += setup_64.h +unifdef-y += shmbuf_32.h +unifdef-y += shmbuf_64.h +unifdef-y += shmparam_32.h +unifdef-y += shmparam_64.h +unifdef-y += sigcontext_32.h +unifdef-y += sigcontext_64.h +unifdef-y += siginfo_32.h +unifdef-y += siginfo_64.h +unifdef-y += signal_32.h +unifdef-y += signal_64.h +unifdef-y += sockios_32.h +unifdef-y += sockios_64.h +unifdef-y += stat_32.h +unifdef-y += stat_64.h +unifdef-y += statfs_32.h +unifdef-y += statfs_64.h +unifdef-y += termbits_32.h +unifdef-y += termbits_64.h +unifdef-y += termios_32.h +unifdef-y += termios_64.h +unifdef-y += types_32.h +unifdef-y += types_64.h +unifdef-y += unistd_32.h +unifdef-y += unistd_64.h +unifdef-y += user_32.h +unifdef-y += user_64.h +unifdef-y += vm86.h +unifdef-y += vsyscall.h diff --git a/include/asm-x86/a.out.h b/include/asm-x86/a.out.h new file mode 100644 index 000000000000..5bc9b1d3b227 --- /dev/null +++ b/include/asm-x86/a.out.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "a.out_32.h" +# else +# include "a.out_64.h" +# endif +#else +# ifdef __i386__ +# include "a.out_32.h" +# else +# include "a.out_64.h" +# endif +#endif diff --git a/include/asm-i386/a.out.h b/include/asm-x86/a.out_32.h similarity index 100% rename from include/asm-i386/a.out.h rename to include/asm-x86/a.out_32.h diff --git a/include/asm-x86_64/a.out.h b/include/asm-x86/a.out_64.h similarity index 100% rename from include/asm-x86_64/a.out.h rename to include/asm-x86/a.out_64.h diff --git a/include/asm-x86/acpi.h b/include/asm-x86/acpi.h new file mode 100644 index 000000000000..0693689d4146 --- /dev/null +++ b/include/asm-x86/acpi.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "acpi_32.h" +#else +# include "acpi_64.h" +#endif diff --git a/include/asm-i386/acpi.h b/include/asm-x86/acpi_32.h similarity index 100% rename from include/asm-i386/acpi.h rename to include/asm-x86/acpi_32.h diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86/acpi_64.h similarity index 100% rename from include/asm-x86_64/acpi.h rename to include/asm-x86/acpi_64.h diff --git a/include/asm-x86/agp.h b/include/asm-x86/agp.h new file mode 100644 index 000000000000..9348f1e4f6f1 --- /dev/null +++ b/include/asm-x86/agp.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "agp_32.h" +#else +# include "agp_64.h" +#endif diff --git a/include/asm-i386/agp.h b/include/asm-x86/agp_32.h similarity index 100% rename from include/asm-i386/agp.h rename to include/asm-x86/agp_32.h diff --git a/include/asm-x86_64/agp.h b/include/asm-x86/agp_64.h similarity index 100% rename from include/asm-x86_64/agp.h rename to include/asm-x86/agp_64.h diff --git a/include/asm-x86/alternative-asm.i b/include/asm-x86/alternative-asm.i new file mode 100644 index 000000000000..4f360cd3c888 --- /dev/null +++ b/include/asm-x86/alternative-asm.i @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "alternative-asm_32.i" +#else +# include "alternative-asm_64.i" +#endif diff --git a/include/asm-i386/alternative-asm.i b/include/asm-x86/alternative-asm_32.i similarity index 100% rename from include/asm-i386/alternative-asm.i rename to include/asm-x86/alternative-asm_32.i diff --git a/include/asm-x86_64/alternative-asm.i b/include/asm-x86/alternative-asm_64.i similarity index 100% rename from include/asm-x86_64/alternative-asm.i rename to include/asm-x86/alternative-asm_64.i diff --git a/include/asm-x86/alternative.h b/include/asm-x86/alternative.h new file mode 100644 index 000000000000..9eef6a32a130 --- /dev/null +++ b/include/asm-x86/alternative.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "alternative_32.h" +#else +# include "alternative_64.h" +#endif diff --git a/include/asm-i386/alternative.h b/include/asm-x86/alternative_32.h similarity index 100% rename from include/asm-i386/alternative.h rename to include/asm-x86/alternative_32.h diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86/alternative_64.h similarity index 100% rename from include/asm-x86_64/alternative.h rename to include/asm-x86/alternative_64.h diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h new file mode 100644 index 000000000000..9fbcc0bd2ac4 --- /dev/null +++ b/include/asm-x86/apic.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "apic_32.h" +#else +# include "apic_64.h" +#endif diff --git a/include/asm-i386/apic.h b/include/asm-x86/apic_32.h similarity index 100% rename from include/asm-i386/apic.h rename to include/asm-x86/apic_32.h diff --git a/include/asm-x86_64/apic.h b/include/asm-x86/apic_64.h similarity index 100% rename from include/asm-x86_64/apic.h rename to include/asm-x86/apic_64.h diff --git a/include/asm-x86/apicdef.h b/include/asm-x86/apicdef.h new file mode 100644 index 000000000000..4542c220bf4d --- /dev/null +++ b/include/asm-x86/apicdef.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "apicdef_32.h" +#else +# include "apicdef_64.h" +#endif diff --git a/include/asm-i386/apicdef.h b/include/asm-x86/apicdef_32.h similarity index 100% rename from include/asm-i386/apicdef.h rename to include/asm-x86/apicdef_32.h diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86/apicdef_64.h similarity index 100% rename from include/asm-x86_64/apicdef.h rename to include/asm-x86/apicdef_64.h diff --git a/include/asm-i386/arch_hooks.h b/include/asm-x86/arch_hooks.h similarity index 100% rename from include/asm-i386/arch_hooks.h rename to include/asm-x86/arch_hooks.h diff --git a/include/asm-x86/atomic.h b/include/asm-x86/atomic.h new file mode 100644 index 000000000000..4e1b8873c474 --- /dev/null +++ b/include/asm-x86/atomic.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "atomic_32.h" +#else +# include "atomic_64.h" +#endif diff --git a/include/asm-i386/atomic.h b/include/asm-x86/atomic_32.h similarity index 100% rename from include/asm-i386/atomic.h rename to include/asm-x86/atomic_32.h diff --git a/include/asm-x86_64/atomic.h b/include/asm-x86/atomic_64.h similarity index 100% rename from include/asm-x86_64/atomic.h rename to include/asm-x86/atomic_64.h diff --git a/include/asm-x86/auxvec.h b/include/asm-x86/auxvec.h new file mode 100644 index 000000000000..7ff866f829ca --- /dev/null +++ b/include/asm-x86/auxvec.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "auxvec_32.h" +# else +# include "auxvec_64.h" +# endif +#else +# ifdef __i386__ +# include "auxvec_32.h" +# else +# include "auxvec_64.h" +# endif +#endif diff --git a/include/asm-i386/auxvec.h b/include/asm-x86/auxvec_32.h similarity index 100% rename from include/asm-i386/auxvec.h rename to include/asm-x86/auxvec_32.h diff --git a/include/asm-x86_64/auxvec.h b/include/asm-x86/auxvec_64.h similarity index 100% rename from include/asm-x86_64/auxvec.h rename to include/asm-x86/auxvec_64.h diff --git a/include/asm-x86/bitops.h b/include/asm-x86/bitops.h new file mode 100644 index 000000000000..07e3f6d4fe47 --- /dev/null +++ b/include/asm-x86/bitops.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "bitops_32.h" +#else +# include "bitops_64.h" +#endif diff --git a/include/asm-i386/bitops.h b/include/asm-x86/bitops_32.h similarity index 100% rename from include/asm-i386/bitops.h rename to include/asm-x86/bitops_32.h diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86/bitops_64.h similarity index 100% rename from include/asm-x86_64/bitops.h rename to include/asm-x86/bitops_64.h diff --git a/include/asm-i386/boot.h b/include/asm-x86/boot.h similarity index 100% rename from include/asm-i386/boot.h rename to include/asm-x86/boot.h diff --git a/include/asm-i386/bootparam.h b/include/asm-x86/bootparam.h similarity index 100% rename from include/asm-i386/bootparam.h rename to include/asm-x86/bootparam.h diff --git a/include/asm-x86_64/bootsetup.h b/include/asm-x86/bootsetup.h similarity index 100% rename from include/asm-x86_64/bootsetup.h rename to include/asm-x86/bootsetup.h diff --git a/include/asm-x86/bug.h b/include/asm-x86/bug.h new file mode 100644 index 000000000000..c655d7f3a5e0 --- /dev/null +++ b/include/asm-x86/bug.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "bug_32.h" +#else +# include "bug_64.h" +#endif diff --git a/include/asm-i386/bug.h b/include/asm-x86/bug_32.h similarity index 100% rename from include/asm-i386/bug.h rename to include/asm-x86/bug_32.h diff --git a/include/asm-x86_64/bug.h b/include/asm-x86/bug_64.h similarity index 100% rename from include/asm-x86_64/bug.h rename to include/asm-x86/bug_64.h diff --git a/include/asm-x86/bugs.h b/include/asm-x86/bugs.h new file mode 100644 index 000000000000..ddf42d36dd50 --- /dev/null +++ b/include/asm-x86/bugs.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "bugs_32.h" +#else +# include "bugs_64.h" +#endif diff --git a/include/asm-i386/bugs.h b/include/asm-x86/bugs_32.h similarity index 100% rename from include/asm-i386/bugs.h rename to include/asm-x86/bugs_32.h diff --git a/include/asm-x86_64/bugs.h b/include/asm-x86/bugs_64.h similarity index 100% rename from include/asm-x86_64/bugs.h rename to include/asm-x86/bugs_64.h diff --git a/include/asm-x86/byteorder.h b/include/asm-x86/byteorder.h new file mode 100644 index 000000000000..eb14b1870ed7 --- /dev/null +++ b/include/asm-x86/byteorder.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "byteorder_32.h" +# else +# include "byteorder_64.h" +# endif +#else +# ifdef __i386__ +# include "byteorder_32.h" +# else +# include "byteorder_64.h" +# endif +#endif diff --git a/include/asm-i386/byteorder.h b/include/asm-x86/byteorder_32.h similarity index 100% rename from include/asm-i386/byteorder.h rename to include/asm-x86/byteorder_32.h diff --git a/include/asm-x86_64/byteorder.h b/include/asm-x86/byteorder_64.h similarity index 100% rename from include/asm-x86_64/byteorder.h rename to include/asm-x86/byteorder_64.h diff --git a/include/asm-x86/cache.h b/include/asm-x86/cache.h new file mode 100644 index 000000000000..c36d190ac9d8 --- /dev/null +++ b/include/asm-x86/cache.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "cache_32.h" +#else +# include "cache_64.h" +#endif diff --git a/include/asm-i386/cache.h b/include/asm-x86/cache_32.h similarity index 100% rename from include/asm-i386/cache.h rename to include/asm-x86/cache_32.h diff --git a/include/asm-x86_64/cache.h b/include/asm-x86/cache_64.h similarity index 100% rename from include/asm-x86_64/cache.h rename to include/asm-x86/cache_64.h diff --git a/include/asm-x86/cacheflush.h b/include/asm-x86/cacheflush.h new file mode 100644 index 000000000000..e2df3b55034a --- /dev/null +++ b/include/asm-x86/cacheflush.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "cacheflush_32.h" +#else +# include "cacheflush_64.h" +#endif diff --git a/include/asm-i386/cacheflush.h b/include/asm-x86/cacheflush_32.h similarity index 100% rename from include/asm-i386/cacheflush.h rename to include/asm-x86/cacheflush_32.h diff --git a/include/asm-x86_64/cacheflush.h b/include/asm-x86/cacheflush_64.h similarity index 100% rename from include/asm-x86_64/cacheflush.h rename to include/asm-x86/cacheflush_64.h diff --git a/include/asm-x86_64/calgary.h b/include/asm-x86/calgary.h similarity index 100% rename from include/asm-x86_64/calgary.h rename to include/asm-x86/calgary.h diff --git a/include/asm-x86_64/calling.h b/include/asm-x86/calling.h similarity index 100% rename from include/asm-x86_64/calling.h rename to include/asm-x86/calling.h diff --git a/include/asm-x86/checksum.h b/include/asm-x86/checksum.h new file mode 100644 index 000000000000..848850fd7d62 --- /dev/null +++ b/include/asm-x86/checksum.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "checksum_32.h" +#else +# include "checksum_64.h" +#endif diff --git a/include/asm-i386/checksum.h b/include/asm-x86/checksum_32.h similarity index 100% rename from include/asm-i386/checksum.h rename to include/asm-x86/checksum_32.h diff --git a/include/asm-x86_64/checksum.h b/include/asm-x86/checksum_64.h similarity index 100% rename from include/asm-x86_64/checksum.h rename to include/asm-x86/checksum_64.h diff --git a/include/asm-x86/cmpxchg.h b/include/asm-x86/cmpxchg.h new file mode 100644 index 000000000000..a460fa088d4c --- /dev/null +++ b/include/asm-x86/cmpxchg.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "cmpxchg_32.h" +#else +# include "cmpxchg_64.h" +#endif diff --git a/include/asm-i386/cmpxchg.h b/include/asm-x86/cmpxchg_32.h similarity index 100% rename from include/asm-i386/cmpxchg.h rename to include/asm-x86/cmpxchg_32.h diff --git a/include/asm-x86_64/cmpxchg.h b/include/asm-x86/cmpxchg_64.h similarity index 100% rename from include/asm-x86_64/cmpxchg.h rename to include/asm-x86/cmpxchg_64.h diff --git a/include/asm-x86_64/compat.h b/include/asm-x86/compat.h similarity index 100% rename from include/asm-x86_64/compat.h rename to include/asm-x86/compat.h diff --git a/include/asm-i386/cpu.h b/include/asm-x86/cpu.h similarity index 100% rename from include/asm-i386/cpu.h rename to include/asm-x86/cpu.h diff --git a/include/asm-x86/cpufeature.h b/include/asm-x86/cpufeature.h new file mode 100644 index 000000000000..b7160a4598d7 --- /dev/null +++ b/include/asm-x86/cpufeature.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "cpufeature_32.h" +#else +# include "cpufeature_64.h" +#endif diff --git a/include/asm-i386/cpufeature.h b/include/asm-x86/cpufeature_32.h similarity index 100% rename from include/asm-i386/cpufeature.h rename to include/asm-x86/cpufeature_32.h diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86/cpufeature_64.h similarity index 91% rename from include/asm-x86_64/cpufeature.h rename to include/asm-x86/cpufeature_64.h index 8baefc3beb2e..2983501e8b3e 100644 --- a/include/asm-x86_64/cpufeature.h +++ b/include/asm-x86/cpufeature_64.h @@ -1,5 +1,5 @@ /* - * cpufeature.h + * cpufeature_32.h * * Defines x86 CPU feature bits */ @@ -7,7 +7,7 @@ #ifndef __ASM_X8664_CPUFEATURE_H #define __ASM_X8664_CPUFEATURE_H -#include +#include #undef cpu_has_vme #define cpu_has_vme 0 diff --git a/include/asm-x86/cputime.h b/include/asm-x86/cputime.h new file mode 100644 index 000000000000..87c37cf6b707 --- /dev/null +++ b/include/asm-x86/cputime.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "cputime_32.h" +#else +# include "cputime_64.h" +#endif diff --git a/include/asm-i386/cputime.h b/include/asm-x86/cputime_32.h similarity index 100% rename from include/asm-i386/cputime.h rename to include/asm-x86/cputime_32.h diff --git a/include/asm-x86_64/cputime.h b/include/asm-x86/cputime_64.h similarity index 100% rename from include/asm-x86_64/cputime.h rename to include/asm-x86/cputime_64.h diff --git a/include/asm-x86/current.h b/include/asm-x86/current.h new file mode 100644 index 000000000000..d2526d3f7346 --- /dev/null +++ b/include/asm-x86/current.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "current_32.h" +#else +# include "current_64.h" +#endif diff --git a/include/asm-i386/current.h b/include/asm-x86/current_32.h similarity index 100% rename from include/asm-i386/current.h rename to include/asm-x86/current_32.h diff --git a/include/asm-x86_64/current.h b/include/asm-x86/current_64.h similarity index 100% rename from include/asm-x86_64/current.h rename to include/asm-x86/current_64.h diff --git a/include/asm-x86/debugreg.h b/include/asm-x86/debugreg.h new file mode 100644 index 000000000000..b6ce7e4fa002 --- /dev/null +++ b/include/asm-x86/debugreg.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "debugreg_32.h" +# else +# include "debugreg_64.h" +# endif +#else +# ifdef __i386__ +# include "debugreg_32.h" +# else +# include "debugreg_64.h" +# endif +#endif diff --git a/include/asm-i386/debugreg.h b/include/asm-x86/debugreg_32.h similarity index 100% rename from include/asm-i386/debugreg.h rename to include/asm-x86/debugreg_32.h diff --git a/include/asm-x86_64/debugreg.h b/include/asm-x86/debugreg_64.h similarity index 100% rename from include/asm-x86_64/debugreg.h rename to include/asm-x86/debugreg_64.h diff --git a/include/asm-x86/delay.h b/include/asm-x86/delay.h new file mode 100644 index 000000000000..10f2c71d622b --- /dev/null +++ b/include/asm-x86/delay.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "delay_32.h" +#else +# include "delay_64.h" +#endif diff --git a/include/asm-i386/delay.h b/include/asm-x86/delay_32.h similarity index 100% rename from include/asm-i386/delay.h rename to include/asm-x86/delay_32.h diff --git a/include/asm-x86_64/delay.h b/include/asm-x86/delay_64.h similarity index 100% rename from include/asm-x86_64/delay.h rename to include/asm-x86/delay_64.h diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h new file mode 100644 index 000000000000..6065c5092265 --- /dev/null +++ b/include/asm-x86/desc.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "desc_32.h" +#else +# include "desc_64.h" +#endif diff --git a/include/asm-i386/desc.h b/include/asm-x86/desc_32.h similarity index 100% rename from include/asm-i386/desc.h rename to include/asm-x86/desc_32.h diff --git a/include/asm-x86_64/desc.h b/include/asm-x86/desc_64.h similarity index 100% rename from include/asm-x86_64/desc.h rename to include/asm-x86/desc_64.h diff --git a/include/asm-x86_64/desc_defs.h b/include/asm-x86/desc_defs.h similarity index 100% rename from include/asm-x86_64/desc_defs.h rename to include/asm-x86/desc_defs.h diff --git a/include/asm-x86/device.h b/include/asm-x86/device.h new file mode 100644 index 000000000000..e2bcf7c7dcee --- /dev/null +++ b/include/asm-x86/device.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "device_32.h" +#else +# include "device_64.h" +#endif diff --git a/include/asm-i386/device.h b/include/asm-x86/device_32.h similarity index 100% rename from include/asm-i386/device.h rename to include/asm-x86/device_32.h diff --git a/include/asm-x86_64/device.h b/include/asm-x86/device_64.h similarity index 100% rename from include/asm-x86_64/device.h rename to include/asm-x86/device_64.h diff --git a/include/asm-x86/div64.h b/include/asm-x86/div64.h new file mode 100644 index 000000000000..8ac7da6ca284 --- /dev/null +++ b/include/asm-x86/div64.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "div64_32.h" +#else +# include "div64_64.h" +#endif diff --git a/include/asm-i386/div64.h b/include/asm-x86/div64_32.h similarity index 100% rename from include/asm-i386/div64.h rename to include/asm-x86/div64_32.h diff --git a/include/asm-x86_64/div64.h b/include/asm-x86/div64_64.h similarity index 100% rename from include/asm-x86_64/div64.h rename to include/asm-x86/div64_64.h diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h new file mode 100644 index 000000000000..58f790f4df52 --- /dev/null +++ b/include/asm-x86/dma-mapping.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "dma-mapping_32.h" +#else +# include "dma-mapping_64.h" +#endif diff --git a/include/asm-i386/dma-mapping.h b/include/asm-x86/dma-mapping_32.h similarity index 100% rename from include/asm-i386/dma-mapping.h rename to include/asm-x86/dma-mapping_32.h diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86/dma-mapping_64.h similarity index 100% rename from include/asm-x86_64/dma-mapping.h rename to include/asm-x86/dma-mapping_64.h diff --git a/include/asm-x86/dma.h b/include/asm-x86/dma.h new file mode 100644 index 000000000000..9f936c61a4e5 --- /dev/null +++ b/include/asm-x86/dma.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "dma_32.h" +#else +# include "dma_64.h" +#endif diff --git a/include/asm-i386/dma.h b/include/asm-x86/dma_32.h similarity index 100% rename from include/asm-i386/dma.h rename to include/asm-x86/dma_32.h diff --git a/include/asm-x86_64/dma.h b/include/asm-x86/dma_64.h similarity index 100% rename from include/asm-x86_64/dma.h rename to include/asm-x86/dma_64.h diff --git a/include/asm-x86/dmi.h b/include/asm-x86/dmi.h new file mode 100644 index 000000000000..c9e4e8ebc270 --- /dev/null +++ b/include/asm-x86/dmi.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "dmi_32.h" +#else +# include "dmi_64.h" +#endif diff --git a/include/asm-i386/dmi.h b/include/asm-x86/dmi_32.h similarity index 100% rename from include/asm-i386/dmi.h rename to include/asm-x86/dmi_32.h diff --git a/include/asm-x86_64/dmi.h b/include/asm-x86/dmi_64.h similarity index 100% rename from include/asm-x86_64/dmi.h rename to include/asm-x86/dmi_64.h diff --git a/include/asm-x86/dwarf2.h b/include/asm-x86/dwarf2.h new file mode 100644 index 000000000000..b3cbb0ccae18 --- /dev/null +++ b/include/asm-x86/dwarf2.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "dwarf2_32.h" +#else +# include "dwarf2_64.h" +#endif diff --git a/include/asm-i386/dwarf2.h b/include/asm-x86/dwarf2_32.h similarity index 100% rename from include/asm-i386/dwarf2.h rename to include/asm-x86/dwarf2_32.h diff --git a/include/asm-x86_64/dwarf2.h b/include/asm-x86/dwarf2_64.h similarity index 100% rename from include/asm-x86_64/dwarf2.h rename to include/asm-x86/dwarf2_64.h diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h new file mode 100644 index 000000000000..5d4d2183e5db --- /dev/null +++ b/include/asm-x86/e820.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "e820_32.h" +#else +# include "e820_64.h" +#endif diff --git a/include/asm-i386/e820.h b/include/asm-x86/e820_32.h similarity index 100% rename from include/asm-i386/e820.h rename to include/asm-x86/e820_32.h diff --git a/include/asm-x86_64/e820.h b/include/asm-x86/e820_64.h similarity index 100% rename from include/asm-x86_64/e820.h rename to include/asm-x86/e820_64.h diff --git a/include/asm-x86/edac.h b/include/asm-x86/edac.h new file mode 100644 index 000000000000..f8b888e140b0 --- /dev/null +++ b/include/asm-x86/edac.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "edac_32.h" +#else +# include "edac_64.h" +#endif diff --git a/include/asm-i386/edac.h b/include/asm-x86/edac_32.h similarity index 100% rename from include/asm-i386/edac.h rename to include/asm-x86/edac_32.h diff --git a/include/asm-x86_64/edac.h b/include/asm-x86/edac_64.h similarity index 100% rename from include/asm-x86_64/edac.h rename to include/asm-x86/edac_64.h diff --git a/include/asm-x86/elf.h b/include/asm-x86/elf.h new file mode 100644 index 000000000000..ed6bb6e546b9 --- /dev/null +++ b/include/asm-x86/elf.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "elf_32.h" +# else +# include "elf_64.h" +# endif +#else +# ifdef __i386__ +# include "elf_32.h" +# else +# include "elf_64.h" +# endif +#endif diff --git a/include/asm-i386/elf.h b/include/asm-x86/elf_32.h similarity index 100% rename from include/asm-i386/elf.h rename to include/asm-x86/elf_32.h diff --git a/include/asm-x86_64/elf.h b/include/asm-x86/elf_64.h similarity index 100% rename from include/asm-x86_64/elf.h rename to include/asm-x86/elf_64.h diff --git a/include/asm-i386/emergency-restart.h b/include/asm-x86/emergency-restart.h similarity index 100% rename from include/asm-i386/emergency-restart.h rename to include/asm-x86/emergency-restart.h diff --git a/include/asm-x86/errno.h b/include/asm-x86/errno.h new file mode 100644 index 000000000000..9d511be8e573 --- /dev/null +++ b/include/asm-x86/errno.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "errno_32.h" +# else +# include "errno_64.h" +# endif +#else +# ifdef __i386__ +# include "errno_32.h" +# else +# include "errno_64.h" +# endif +#endif diff --git a/include/asm-i386/errno.h b/include/asm-x86/errno_32.h similarity index 100% rename from include/asm-i386/errno.h rename to include/asm-x86/errno_32.h diff --git a/include/asm-x86_64/errno.h b/include/asm-x86/errno_64.h similarity index 100% rename from include/asm-x86_64/errno.h rename to include/asm-x86/errno_64.h diff --git a/include/asm-x86/fb.h b/include/asm-x86/fb.h new file mode 100644 index 000000000000..238c7ca45877 --- /dev/null +++ b/include/asm-x86/fb.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "fb_32.h" +#else +# include "fb_64.h" +#endif diff --git a/include/asm-i386/fb.h b/include/asm-x86/fb_32.h similarity index 100% rename from include/asm-i386/fb.h rename to include/asm-x86/fb_32.h diff --git a/include/asm-x86_64/fb.h b/include/asm-x86/fb_64.h similarity index 100% rename from include/asm-x86_64/fb.h rename to include/asm-x86/fb_64.h diff --git a/include/asm-i386/fcntl.h b/include/asm-x86/fcntl.h similarity index 100% rename from include/asm-i386/fcntl.h rename to include/asm-x86/fcntl.h diff --git a/include/asm-x86/fixmap.h b/include/asm-x86/fixmap.h new file mode 100644 index 000000000000..382eb271a892 --- /dev/null +++ b/include/asm-x86/fixmap.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "fixmap_32.h" +#else +# include "fixmap_64.h" +#endif diff --git a/include/asm-i386/fixmap.h b/include/asm-x86/fixmap_32.h similarity index 100% rename from include/asm-i386/fixmap.h rename to include/asm-x86/fixmap_32.h diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86/fixmap_64.h similarity index 100% rename from include/asm-x86_64/fixmap.h rename to include/asm-x86/fixmap_64.h diff --git a/include/asm-x86/floppy.h b/include/asm-x86/floppy.h new file mode 100644 index 000000000000..aecbb6dca21d --- /dev/null +++ b/include/asm-x86/floppy.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "floppy_32.h" +#else +# include "floppy_64.h" +#endif diff --git a/include/asm-i386/floppy.h b/include/asm-x86/floppy_32.h similarity index 100% rename from include/asm-i386/floppy.h rename to include/asm-x86/floppy_32.h diff --git a/include/asm-x86_64/floppy.h b/include/asm-x86/floppy_64.h similarity index 100% rename from include/asm-x86_64/floppy.h rename to include/asm-x86/floppy_64.h diff --git a/include/asm-x86_64/fpu32.h b/include/asm-x86/fpu32.h similarity index 100% rename from include/asm-x86_64/fpu32.h rename to include/asm-x86/fpu32.h diff --git a/include/asm-i386/frame.i b/include/asm-x86/frame.i similarity index 100% rename from include/asm-i386/frame.i rename to include/asm-x86/frame.i diff --git a/include/asm-x86/futex.h b/include/asm-x86/futex.h new file mode 100644 index 000000000000..1f4610e0c613 --- /dev/null +++ b/include/asm-x86/futex.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "futex_32.h" +#else +# include "futex_64.h" +#endif diff --git a/include/asm-i386/futex.h b/include/asm-x86/futex_32.h similarity index 100% rename from include/asm-i386/futex.h rename to include/asm-x86/futex_32.h diff --git a/include/asm-x86_64/futex.h b/include/asm-x86/futex_64.h similarity index 100% rename from include/asm-x86_64/futex.h rename to include/asm-x86/futex_64.h diff --git a/include/asm-x86/genapic.h b/include/asm-x86/genapic.h new file mode 100644 index 000000000000..d48bee663a6f --- /dev/null +++ b/include/asm-x86/genapic.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "genapic_32.h" +#else +# include "genapic_64.h" +#endif diff --git a/include/asm-i386/genapic.h b/include/asm-x86/genapic_32.h similarity index 100% rename from include/asm-i386/genapic.h rename to include/asm-x86/genapic_32.h diff --git a/include/asm-x86_64/genapic.h b/include/asm-x86/genapic_64.h similarity index 100% rename from include/asm-x86_64/genapic.h rename to include/asm-x86/genapic_64.h diff --git a/include/asm-i386/geode.h b/include/asm-x86/geode.h similarity index 100% rename from include/asm-i386/geode.h rename to include/asm-x86/geode.h diff --git a/include/asm-x86/hardirq.h b/include/asm-x86/hardirq.h new file mode 100644 index 000000000000..314434d664e7 --- /dev/null +++ b/include/asm-x86/hardirq.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "hardirq_32.h" +#else +# include "hardirq_64.h" +#endif diff --git a/include/asm-i386/hardirq.h b/include/asm-x86/hardirq_32.h similarity index 100% rename from include/asm-i386/hardirq.h rename to include/asm-x86/hardirq_32.h diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86/hardirq_64.h similarity index 100% rename from include/asm-x86_64/hardirq.h rename to include/asm-x86/hardirq_64.h diff --git a/include/asm-i386/highmem.h b/include/asm-x86/highmem.h similarity index 100% rename from include/asm-i386/highmem.h rename to include/asm-x86/highmem.h diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h new file mode 100644 index 000000000000..9eff48601254 --- /dev/null +++ b/include/asm-x86/hpet.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "hpet_32.h" +#else +# include "hpet_64.h" +#endif diff --git a/include/asm-i386/hpet.h b/include/asm-x86/hpet_32.h similarity index 100% rename from include/asm-i386/hpet.h rename to include/asm-x86/hpet_32.h diff --git a/include/asm-x86_64/hpet.h b/include/asm-x86/hpet_64.h similarity index 93% rename from include/asm-x86_64/hpet.h rename to include/asm-x86/hpet_64.h index 79bb950f82c5..fd4decac93a8 100644 --- a/include/asm-x86_64/hpet.h +++ b/include/asm-x86/hpet_64.h @@ -1,7 +1,7 @@ #ifndef _ASM_X8664_HPET_H #define _ASM_X8664_HPET_H 1 -#include +#include #define HPET_TICK_RATE (HZ * 100000UL) diff --git a/include/asm-x86/hw_irq.h b/include/asm-x86/hw_irq.h new file mode 100644 index 000000000000..bf025399d939 --- /dev/null +++ b/include/asm-x86/hw_irq.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "hw_irq_32.h" +#else +# include "hw_irq_64.h" +#endif diff --git a/include/asm-i386/hw_irq.h b/include/asm-x86/hw_irq_32.h similarity index 100% rename from include/asm-i386/hw_irq.h rename to include/asm-x86/hw_irq_32.h diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86/hw_irq_64.h similarity index 100% rename from include/asm-x86_64/hw_irq.h rename to include/asm-x86/hw_irq_64.h diff --git a/include/asm-i386/hypertransport.h b/include/asm-x86/hypertransport.h similarity index 100% rename from include/asm-i386/hypertransport.h rename to include/asm-x86/hypertransport.h diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h new file mode 100644 index 000000000000..a8bbed349664 --- /dev/null +++ b/include/asm-x86/i387.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "i387_32.h" +#else +# include "i387_64.h" +#endif diff --git a/include/asm-i386/i387.h b/include/asm-x86/i387_32.h similarity index 100% rename from include/asm-i386/i387.h rename to include/asm-x86/i387_32.h diff --git a/include/asm-x86_64/i387.h b/include/asm-x86/i387_64.h similarity index 100% rename from include/asm-x86_64/i387.h rename to include/asm-x86/i387_64.h diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h new file mode 100644 index 000000000000..b2a4f995a33f --- /dev/null +++ b/include/asm-x86/i8253.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "i8253_32.h" +#else +# include "i8253_64.h" +#endif diff --git a/include/asm-i386/i8253.h b/include/asm-x86/i8253_32.h similarity index 100% rename from include/asm-i386/i8253.h rename to include/asm-x86/i8253_32.h diff --git a/include/asm-x86_64/i8253.h b/include/asm-x86/i8253_64.h similarity index 100% rename from include/asm-x86_64/i8253.h rename to include/asm-x86/i8253_64.h diff --git a/include/asm-i386/i8259.h b/include/asm-x86/i8259.h similarity index 100% rename from include/asm-i386/i8259.h rename to include/asm-x86/i8259.h diff --git a/include/asm-x86_64/ia32.h b/include/asm-x86/ia32.h similarity index 100% rename from include/asm-x86_64/ia32.h rename to include/asm-x86/ia32.h diff --git a/include/asm-x86_64/ia32_unistd.h b/include/asm-x86/ia32_unistd.h similarity index 100% rename from include/asm-x86_64/ia32_unistd.h rename to include/asm-x86/ia32_unistd.h diff --git a/include/asm-i386/ide.h b/include/asm-x86/ide.h similarity index 100% rename from include/asm-i386/ide.h rename to include/asm-x86/ide.h diff --git a/include/asm-x86_64/idle.h b/include/asm-x86/idle.h similarity index 100% rename from include/asm-x86_64/idle.h rename to include/asm-x86/idle.h diff --git a/include/asm-x86/intel_arch_perfmon.h b/include/asm-x86/intel_arch_perfmon.h new file mode 100644 index 000000000000..4f6d4e6bf57e --- /dev/null +++ b/include/asm-x86/intel_arch_perfmon.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "intel_arch_perfmon_32.h" +#else +# include "intel_arch_perfmon_64.h" +#endif diff --git a/include/asm-i386/intel_arch_perfmon.h b/include/asm-x86/intel_arch_perfmon_32.h similarity index 100% rename from include/asm-i386/intel_arch_perfmon.h rename to include/asm-x86/intel_arch_perfmon_32.h diff --git a/include/asm-x86_64/intel_arch_perfmon.h b/include/asm-x86/intel_arch_perfmon_64.h similarity index 100% rename from include/asm-x86_64/intel_arch_perfmon.h rename to include/asm-x86/intel_arch_perfmon_64.h diff --git a/include/asm-x86/io.h b/include/asm-x86/io.h new file mode 100644 index 000000000000..5a58b176dd61 --- /dev/null +++ b/include/asm-x86/io.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "io_32.h" +#else +# include "io_64.h" +#endif diff --git a/include/asm-i386/io.h b/include/asm-x86/io_32.h similarity index 100% rename from include/asm-i386/io.h rename to include/asm-x86/io_32.h diff --git a/include/asm-x86_64/io.h b/include/asm-x86/io_64.h similarity index 100% rename from include/asm-x86_64/io.h rename to include/asm-x86/io_64.h diff --git a/include/asm-x86/io_apic.h b/include/asm-x86/io_apic.h new file mode 100644 index 000000000000..88494966beeb --- /dev/null +++ b/include/asm-x86/io_apic.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "io_apic_32.h" +#else +# include "io_apic_64.h" +#endif diff --git a/include/asm-i386/io_apic.h b/include/asm-x86/io_apic_32.h similarity index 100% rename from include/asm-i386/io_apic.h rename to include/asm-x86/io_apic_32.h diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86/io_apic_64.h similarity index 100% rename from include/asm-x86_64/io_apic.h rename to include/asm-x86/io_apic_64.h diff --git a/include/asm-i386/ioctl.h b/include/asm-x86/ioctl.h similarity index 100% rename from include/asm-i386/ioctl.h rename to include/asm-x86/ioctl.h diff --git a/include/asm-x86/ioctls.h b/include/asm-x86/ioctls.h new file mode 100644 index 000000000000..1e0fd48f18bc --- /dev/null +++ b/include/asm-x86/ioctls.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "ioctls_32.h" +# else +# include "ioctls_64.h" +# endif +#else +# ifdef __i386__ +# include "ioctls_32.h" +# else +# include "ioctls_64.h" +# endif +#endif diff --git a/include/asm-i386/ioctls.h b/include/asm-x86/ioctls_32.h similarity index 100% rename from include/asm-i386/ioctls.h rename to include/asm-x86/ioctls_32.h diff --git a/include/asm-x86_64/ioctls.h b/include/asm-x86/ioctls_64.h similarity index 100% rename from include/asm-x86_64/ioctls.h rename to include/asm-x86/ioctls_64.h diff --git a/include/asm-x86_64/iommu.h b/include/asm-x86/iommu.h similarity index 100% rename from include/asm-x86_64/iommu.h rename to include/asm-x86/iommu.h diff --git a/include/asm-i386/ipc.h b/include/asm-x86/ipc.h similarity index 100% rename from include/asm-i386/ipc.h rename to include/asm-x86/ipc.h diff --git a/include/asm-x86/ipcbuf.h b/include/asm-x86/ipcbuf.h new file mode 100644 index 000000000000..eb2e448c6e28 --- /dev/null +++ b/include/asm-x86/ipcbuf.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "ipcbuf_32.h" +# else +# include "ipcbuf_64.h" +# endif +#else +# ifdef __i386__ +# include "ipcbuf_32.h" +# else +# include "ipcbuf_64.h" +# endif +#endif diff --git a/include/asm-i386/ipcbuf.h b/include/asm-x86/ipcbuf_32.h similarity index 100% rename from include/asm-i386/ipcbuf.h rename to include/asm-x86/ipcbuf_32.h diff --git a/include/asm-x86_64/ipcbuf.h b/include/asm-x86/ipcbuf_64.h similarity index 100% rename from include/asm-x86_64/ipcbuf.h rename to include/asm-x86/ipcbuf_64.h diff --git a/include/asm-x86_64/ipi.h b/include/asm-x86/ipi.h similarity index 100% rename from include/asm-x86_64/ipi.h rename to include/asm-x86/ipi.h diff --git a/include/asm-x86/irq.h b/include/asm-x86/irq.h new file mode 100644 index 000000000000..7ba905465a53 --- /dev/null +++ b/include/asm-x86/irq.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "irq_32.h" +#else +# include "irq_64.h" +#endif diff --git a/include/asm-i386/irq.h b/include/asm-x86/irq_32.h similarity index 100% rename from include/asm-i386/irq.h rename to include/asm-x86/irq_32.h diff --git a/include/asm-x86_64/irq.h b/include/asm-x86/irq_64.h similarity index 100% rename from include/asm-x86_64/irq.h rename to include/asm-x86/irq_64.h diff --git a/include/asm-x86/irq_regs.h b/include/asm-x86/irq_regs.h new file mode 100644 index 000000000000..89c898ab298b --- /dev/null +++ b/include/asm-x86/irq_regs.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "irq_regs_32.h" +#else +# include "irq_regs_64.h" +#endif diff --git a/include/asm-i386/irq_regs.h b/include/asm-x86/irq_regs_32.h similarity index 100% rename from include/asm-i386/irq_regs.h rename to include/asm-x86/irq_regs_32.h diff --git a/include/asm-x86_64/irq_regs.h b/include/asm-x86/irq_regs_64.h similarity index 100% rename from include/asm-x86_64/irq_regs.h rename to include/asm-x86/irq_regs_64.h diff --git a/include/asm-x86/irqflags.h b/include/asm-x86/irqflags.h new file mode 100644 index 000000000000..1b695ff52687 --- /dev/null +++ b/include/asm-x86/irqflags.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "irqflags_32.h" +#else +# include "irqflags_64.h" +#endif diff --git a/include/asm-i386/irqflags.h b/include/asm-x86/irqflags_32.h similarity index 100% rename from include/asm-i386/irqflags.h rename to include/asm-x86/irqflags_32.h diff --git a/include/asm-x86_64/irqflags.h b/include/asm-x86/irqflags_64.h similarity index 100% rename from include/asm-x86_64/irqflags.h rename to include/asm-x86/irqflags_64.h diff --git a/include/asm-i386/ist.h b/include/asm-x86/ist.h similarity index 100% rename from include/asm-i386/ist.h rename to include/asm-x86/ist.h diff --git a/include/asm-x86_64/k8.h b/include/asm-x86/k8.h similarity index 100% rename from include/asm-x86_64/k8.h rename to include/asm-x86/k8.h diff --git a/include/asm-x86/kdebug.h b/include/asm-x86/kdebug.h new file mode 100644 index 000000000000..38479106c259 --- /dev/null +++ b/include/asm-x86/kdebug.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "kdebug_32.h" +#else +# include "kdebug_64.h" +#endif diff --git a/include/asm-i386/kdebug.h b/include/asm-x86/kdebug_32.h similarity index 100% rename from include/asm-i386/kdebug.h rename to include/asm-x86/kdebug_32.h diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86/kdebug_64.h similarity index 100% rename from include/asm-x86_64/kdebug.h rename to include/asm-x86/kdebug_64.h diff --git a/include/asm-x86/kexec.h b/include/asm-x86/kexec.h new file mode 100644 index 000000000000..718ddbfb9516 --- /dev/null +++ b/include/asm-x86/kexec.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "kexec_32.h" +#else +# include "kexec_64.h" +#endif diff --git a/include/asm-i386/kexec.h b/include/asm-x86/kexec_32.h similarity index 100% rename from include/asm-i386/kexec.h rename to include/asm-x86/kexec_32.h diff --git a/include/asm-x86_64/kexec.h b/include/asm-x86/kexec_64.h similarity index 100% rename from include/asm-x86_64/kexec.h rename to include/asm-x86/kexec_64.h diff --git a/include/asm-x86/kmap_types.h b/include/asm-x86/kmap_types.h new file mode 100644 index 000000000000..e4ec724b298e --- /dev/null +++ b/include/asm-x86/kmap_types.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "kmap_types_32.h" +#else +# include "kmap_types_64.h" +#endif diff --git a/include/asm-i386/kmap_types.h b/include/asm-x86/kmap_types_32.h similarity index 100% rename from include/asm-i386/kmap_types.h rename to include/asm-x86/kmap_types_32.h diff --git a/include/asm-x86_64/kmap_types.h b/include/asm-x86/kmap_types_64.h similarity index 100% rename from include/asm-x86_64/kmap_types.h rename to include/asm-x86/kmap_types_64.h diff --git a/include/asm-x86/kprobes.h b/include/asm-x86/kprobes.h new file mode 100644 index 000000000000..b7bbd25ba2a6 --- /dev/null +++ b/include/asm-x86/kprobes.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "kprobes_32.h" +#else +# include "kprobes_64.h" +#endif diff --git a/include/asm-i386/kprobes.h b/include/asm-x86/kprobes_32.h similarity index 100% rename from include/asm-i386/kprobes.h rename to include/asm-x86/kprobes_32.h diff --git a/include/asm-x86_64/kprobes.h b/include/asm-x86/kprobes_64.h similarity index 100% rename from include/asm-x86_64/kprobes.h rename to include/asm-x86/kprobes_64.h diff --git a/include/asm-x86/ldt.h b/include/asm-x86/ldt.h new file mode 100644 index 000000000000..3d9cc20d2ba4 --- /dev/null +++ b/include/asm-x86/ldt.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "ldt_32.h" +# else +# include "ldt_64.h" +# endif +#else +# ifdef __i386__ +# include "ldt_32.h" +# else +# include "ldt_64.h" +# endif +#endif diff --git a/include/asm-i386/ldt.h b/include/asm-x86/ldt_32.h similarity index 100% rename from include/asm-i386/ldt.h rename to include/asm-x86/ldt_32.h diff --git a/include/asm-x86_64/ldt.h b/include/asm-x86/ldt_64.h similarity index 100% rename from include/asm-x86_64/ldt.h rename to include/asm-x86/ldt_64.h diff --git a/include/asm-x86/linkage.h b/include/asm-x86/linkage.h new file mode 100644 index 000000000000..94b257fa8701 --- /dev/null +++ b/include/asm-x86/linkage.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "linkage_32.h" +#else +# include "linkage_64.h" +#endif diff --git a/include/asm-i386/linkage.h b/include/asm-x86/linkage_32.h similarity index 100% rename from include/asm-i386/linkage.h rename to include/asm-x86/linkage_32.h diff --git a/include/asm-x86_64/linkage.h b/include/asm-x86/linkage_64.h similarity index 100% rename from include/asm-x86_64/linkage.h rename to include/asm-x86/linkage_64.h diff --git a/include/asm-x86/local.h b/include/asm-x86/local.h new file mode 100644 index 000000000000..c7a1b1c66c96 --- /dev/null +++ b/include/asm-x86/local.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "local_32.h" +#else +# include "local_64.h" +#endif diff --git a/include/asm-i386/local.h b/include/asm-x86/local_32.h similarity index 100% rename from include/asm-i386/local.h rename to include/asm-x86/local_32.h diff --git a/include/asm-x86_64/local.h b/include/asm-x86/local_64.h similarity index 100% rename from include/asm-x86_64/local.h rename to include/asm-x86/local_64.h diff --git a/include/asm-i386/mach-bigsmp/mach_apic.h b/include/asm-x86/mach-bigsmp/mach_apic.h similarity index 100% rename from include/asm-i386/mach-bigsmp/mach_apic.h rename to include/asm-x86/mach-bigsmp/mach_apic.h diff --git a/include/asm-i386/mach-bigsmp/mach_apicdef.h b/include/asm-x86/mach-bigsmp/mach_apicdef.h similarity index 100% rename from include/asm-i386/mach-bigsmp/mach_apicdef.h rename to include/asm-x86/mach-bigsmp/mach_apicdef.h diff --git a/include/asm-i386/mach-bigsmp/mach_ipi.h b/include/asm-x86/mach-bigsmp/mach_ipi.h similarity index 100% rename from include/asm-i386/mach-bigsmp/mach_ipi.h rename to include/asm-x86/mach-bigsmp/mach_ipi.h diff --git a/include/asm-i386/mach-bigsmp/mach_mpspec.h b/include/asm-x86/mach-bigsmp/mach_mpspec.h similarity index 100% rename from include/asm-i386/mach-bigsmp/mach_mpspec.h rename to include/asm-x86/mach-bigsmp/mach_mpspec.h diff --git a/include/asm-i386/mach-default/apm.h b/include/asm-x86/mach-default/apm.h similarity index 100% rename from include/asm-i386/mach-default/apm.h rename to include/asm-x86/mach-default/apm.h diff --git a/include/asm-i386/mach-default/bios_ebda.h b/include/asm-x86/mach-default/bios_ebda.h similarity index 100% rename from include/asm-i386/mach-default/bios_ebda.h rename to include/asm-x86/mach-default/bios_ebda.h diff --git a/include/asm-i386/mach-default/do_timer.h b/include/asm-x86/mach-default/do_timer.h similarity index 100% rename from include/asm-i386/mach-default/do_timer.h rename to include/asm-x86/mach-default/do_timer.h diff --git a/include/asm-i386/mach-default/entry_arch.h b/include/asm-x86/mach-default/entry_arch.h similarity index 100% rename from include/asm-i386/mach-default/entry_arch.h rename to include/asm-x86/mach-default/entry_arch.h diff --git a/include/asm-i386/mach-default/io_ports.h b/include/asm-x86/mach-default/io_ports.h similarity index 100% rename from include/asm-i386/mach-default/io_ports.h rename to include/asm-x86/mach-default/io_ports.h diff --git a/include/asm-i386/mach-default/irq_vectors.h b/include/asm-x86/mach-default/irq_vectors.h similarity index 100% rename from include/asm-i386/mach-default/irq_vectors.h rename to include/asm-x86/mach-default/irq_vectors.h diff --git a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-x86/mach-default/irq_vectors_limits.h similarity index 100% rename from include/asm-i386/mach-default/irq_vectors_limits.h rename to include/asm-x86/mach-default/irq_vectors_limits.h diff --git a/include/asm-i386/mach-default/mach_apic.h b/include/asm-x86/mach-default/mach_apic.h similarity index 100% rename from include/asm-i386/mach-default/mach_apic.h rename to include/asm-x86/mach-default/mach_apic.h diff --git a/include/asm-i386/mach-default/mach_apicdef.h b/include/asm-x86/mach-default/mach_apicdef.h similarity index 100% rename from include/asm-i386/mach-default/mach_apicdef.h rename to include/asm-x86/mach-default/mach_apicdef.h diff --git a/include/asm-i386/mach-default/mach_ipi.h b/include/asm-x86/mach-default/mach_ipi.h similarity index 100% rename from include/asm-i386/mach-default/mach_ipi.h rename to include/asm-x86/mach-default/mach_ipi.h diff --git a/include/asm-i386/mach-default/mach_mpparse.h b/include/asm-x86/mach-default/mach_mpparse.h similarity index 100% rename from include/asm-i386/mach-default/mach_mpparse.h rename to include/asm-x86/mach-default/mach_mpparse.h diff --git a/include/asm-i386/mach-default/mach_mpspec.h b/include/asm-x86/mach-default/mach_mpspec.h similarity index 100% rename from include/asm-i386/mach-default/mach_mpspec.h rename to include/asm-x86/mach-default/mach_mpspec.h diff --git a/include/asm-i386/mach-default/mach_reboot.h b/include/asm-x86/mach-default/mach_reboot.h similarity index 100% rename from include/asm-i386/mach-default/mach_reboot.h rename to include/asm-x86/mach-default/mach_reboot.h diff --git a/include/asm-i386/mach-default/mach_time.h b/include/asm-x86/mach-default/mach_time.h similarity index 100% rename from include/asm-i386/mach-default/mach_time.h rename to include/asm-x86/mach-default/mach_time.h diff --git a/include/asm-i386/mach-default/mach_timer.h b/include/asm-x86/mach-default/mach_timer.h similarity index 100% rename from include/asm-i386/mach-default/mach_timer.h rename to include/asm-x86/mach-default/mach_timer.h diff --git a/include/asm-i386/mach-default/mach_traps.h b/include/asm-x86/mach-default/mach_traps.h similarity index 100% rename from include/asm-i386/mach-default/mach_traps.h rename to include/asm-x86/mach-default/mach_traps.h diff --git a/include/asm-i386/mach-default/mach_wakecpu.h b/include/asm-x86/mach-default/mach_wakecpu.h similarity index 100% rename from include/asm-i386/mach-default/mach_wakecpu.h rename to include/asm-x86/mach-default/mach_wakecpu.h diff --git a/include/asm-i386/mach-default/pci-functions.h b/include/asm-x86/mach-default/pci-functions.h similarity index 100% rename from include/asm-i386/mach-default/pci-functions.h rename to include/asm-x86/mach-default/pci-functions.h diff --git a/include/asm-i386/mach-default/setup_arch.h b/include/asm-x86/mach-default/setup_arch.h similarity index 100% rename from include/asm-i386/mach-default/setup_arch.h rename to include/asm-x86/mach-default/setup_arch.h diff --git a/include/asm-i386/mach-default/smpboot_hooks.h b/include/asm-x86/mach-default/smpboot_hooks.h similarity index 100% rename from include/asm-i386/mach-default/smpboot_hooks.h rename to include/asm-x86/mach-default/smpboot_hooks.h diff --git a/include/asm-i386/mach-es7000/mach_apic.h b/include/asm-x86/mach-es7000/mach_apic.h similarity index 100% rename from include/asm-i386/mach-es7000/mach_apic.h rename to include/asm-x86/mach-es7000/mach_apic.h diff --git a/include/asm-i386/mach-es7000/mach_apicdef.h b/include/asm-x86/mach-es7000/mach_apicdef.h similarity index 100% rename from include/asm-i386/mach-es7000/mach_apicdef.h rename to include/asm-x86/mach-es7000/mach_apicdef.h diff --git a/include/asm-i386/mach-es7000/mach_ipi.h b/include/asm-x86/mach-es7000/mach_ipi.h similarity index 100% rename from include/asm-i386/mach-es7000/mach_ipi.h rename to include/asm-x86/mach-es7000/mach_ipi.h diff --git a/include/asm-i386/mach-es7000/mach_mpparse.h b/include/asm-x86/mach-es7000/mach_mpparse.h similarity index 100% rename from include/asm-i386/mach-es7000/mach_mpparse.h rename to include/asm-x86/mach-es7000/mach_mpparse.h diff --git a/include/asm-i386/mach-es7000/mach_mpspec.h b/include/asm-x86/mach-es7000/mach_mpspec.h similarity index 100% rename from include/asm-i386/mach-es7000/mach_mpspec.h rename to include/asm-x86/mach-es7000/mach_mpspec.h diff --git a/include/asm-i386/mach-es7000/mach_wakecpu.h b/include/asm-x86/mach-es7000/mach_wakecpu.h similarity index 100% rename from include/asm-i386/mach-es7000/mach_wakecpu.h rename to include/asm-x86/mach-es7000/mach_wakecpu.h diff --git a/include/asm-i386/mach-generic/irq_vectors_limits.h b/include/asm-x86/mach-generic/irq_vectors_limits.h similarity index 100% rename from include/asm-i386/mach-generic/irq_vectors_limits.h rename to include/asm-x86/mach-generic/irq_vectors_limits.h diff --git a/include/asm-i386/mach-generic/mach_apic.h b/include/asm-x86/mach-generic/mach_apic.h similarity index 100% rename from include/asm-i386/mach-generic/mach_apic.h rename to include/asm-x86/mach-generic/mach_apic.h diff --git a/include/asm-i386/mach-generic/mach_apicdef.h b/include/asm-x86/mach-generic/mach_apicdef.h similarity index 100% rename from include/asm-i386/mach-generic/mach_apicdef.h rename to include/asm-x86/mach-generic/mach_apicdef.h diff --git a/include/asm-i386/mach-generic/mach_ipi.h b/include/asm-x86/mach-generic/mach_ipi.h similarity index 100% rename from include/asm-i386/mach-generic/mach_ipi.h rename to include/asm-x86/mach-generic/mach_ipi.h diff --git a/include/asm-i386/mach-generic/mach_mpparse.h b/include/asm-x86/mach-generic/mach_mpparse.h similarity index 100% rename from include/asm-i386/mach-generic/mach_mpparse.h rename to include/asm-x86/mach-generic/mach_mpparse.h diff --git a/include/asm-i386/mach-generic/mach_mpspec.h b/include/asm-x86/mach-generic/mach_mpspec.h similarity index 100% rename from include/asm-i386/mach-generic/mach_mpspec.h rename to include/asm-x86/mach-generic/mach_mpspec.h diff --git a/include/asm-i386/mach-numaq/mach_apic.h b/include/asm-x86/mach-numaq/mach_apic.h similarity index 100% rename from include/asm-i386/mach-numaq/mach_apic.h rename to include/asm-x86/mach-numaq/mach_apic.h diff --git a/include/asm-i386/mach-numaq/mach_apicdef.h b/include/asm-x86/mach-numaq/mach_apicdef.h similarity index 100% rename from include/asm-i386/mach-numaq/mach_apicdef.h rename to include/asm-x86/mach-numaq/mach_apicdef.h diff --git a/include/asm-i386/mach-numaq/mach_ipi.h b/include/asm-x86/mach-numaq/mach_ipi.h similarity index 100% rename from include/asm-i386/mach-numaq/mach_ipi.h rename to include/asm-x86/mach-numaq/mach_ipi.h diff --git a/include/asm-i386/mach-numaq/mach_mpparse.h b/include/asm-x86/mach-numaq/mach_mpparse.h similarity index 100% rename from include/asm-i386/mach-numaq/mach_mpparse.h rename to include/asm-x86/mach-numaq/mach_mpparse.h diff --git a/include/asm-i386/mach-numaq/mach_mpspec.h b/include/asm-x86/mach-numaq/mach_mpspec.h similarity index 100% rename from include/asm-i386/mach-numaq/mach_mpspec.h rename to include/asm-x86/mach-numaq/mach_mpspec.h diff --git a/include/asm-i386/mach-numaq/mach_wakecpu.h b/include/asm-x86/mach-numaq/mach_wakecpu.h similarity index 100% rename from include/asm-i386/mach-numaq/mach_wakecpu.h rename to include/asm-x86/mach-numaq/mach_wakecpu.h diff --git a/include/asm-i386/mach-summit/irq_vectors_limits.h b/include/asm-x86/mach-summit/irq_vectors_limits.h similarity index 100% rename from include/asm-i386/mach-summit/irq_vectors_limits.h rename to include/asm-x86/mach-summit/irq_vectors_limits.h diff --git a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-x86/mach-summit/mach_apic.h similarity index 100% rename from include/asm-i386/mach-summit/mach_apic.h rename to include/asm-x86/mach-summit/mach_apic.h diff --git a/include/asm-i386/mach-summit/mach_apicdef.h b/include/asm-x86/mach-summit/mach_apicdef.h similarity index 100% rename from include/asm-i386/mach-summit/mach_apicdef.h rename to include/asm-x86/mach-summit/mach_apicdef.h diff --git a/include/asm-i386/mach-summit/mach_ipi.h b/include/asm-x86/mach-summit/mach_ipi.h similarity index 100% rename from include/asm-i386/mach-summit/mach_ipi.h rename to include/asm-x86/mach-summit/mach_ipi.h diff --git a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-x86/mach-summit/mach_mpparse.h similarity index 100% rename from include/asm-i386/mach-summit/mach_mpparse.h rename to include/asm-x86/mach-summit/mach_mpparse.h diff --git a/include/asm-i386/mach-summit/mach_mpspec.h b/include/asm-x86/mach-summit/mach_mpspec.h similarity index 100% rename from include/asm-i386/mach-summit/mach_mpspec.h rename to include/asm-x86/mach-summit/mach_mpspec.h diff --git a/include/asm-i386/mach-visws/cobalt.h b/include/asm-x86/mach-visws/cobalt.h similarity index 100% rename from include/asm-i386/mach-visws/cobalt.h rename to include/asm-x86/mach-visws/cobalt.h diff --git a/include/asm-i386/mach-visws/entry_arch.h b/include/asm-x86/mach-visws/entry_arch.h similarity index 100% rename from include/asm-i386/mach-visws/entry_arch.h rename to include/asm-x86/mach-visws/entry_arch.h diff --git a/include/asm-i386/mach-visws/irq_vectors.h b/include/asm-x86/mach-visws/irq_vectors.h similarity index 100% rename from include/asm-i386/mach-visws/irq_vectors.h rename to include/asm-x86/mach-visws/irq_vectors.h diff --git a/include/asm-i386/mach-visws/lithium.h b/include/asm-x86/mach-visws/lithium.h similarity index 100% rename from include/asm-i386/mach-visws/lithium.h rename to include/asm-x86/mach-visws/lithium.h diff --git a/include/asm-i386/mach-visws/mach_apic.h b/include/asm-x86/mach-visws/mach_apic.h similarity index 100% rename from include/asm-i386/mach-visws/mach_apic.h rename to include/asm-x86/mach-visws/mach_apic.h diff --git a/include/asm-i386/mach-visws/mach_apicdef.h b/include/asm-x86/mach-visws/mach_apicdef.h similarity index 100% rename from include/asm-i386/mach-visws/mach_apicdef.h rename to include/asm-x86/mach-visws/mach_apicdef.h diff --git a/include/asm-i386/mach-visws/piix4.h b/include/asm-x86/mach-visws/piix4.h similarity index 100% rename from include/asm-i386/mach-visws/piix4.h rename to include/asm-x86/mach-visws/piix4.h diff --git a/include/asm-i386/mach-visws/setup_arch.h b/include/asm-x86/mach-visws/setup_arch.h similarity index 100% rename from include/asm-i386/mach-visws/setup_arch.h rename to include/asm-x86/mach-visws/setup_arch.h diff --git a/include/asm-i386/mach-visws/smpboot_hooks.h b/include/asm-x86/mach-visws/smpboot_hooks.h similarity index 100% rename from include/asm-i386/mach-visws/smpboot_hooks.h rename to include/asm-x86/mach-visws/smpboot_hooks.h diff --git a/include/asm-i386/mach-voyager/do_timer.h b/include/asm-x86/mach-voyager/do_timer.h similarity index 100% rename from include/asm-i386/mach-voyager/do_timer.h rename to include/asm-x86/mach-voyager/do_timer.h diff --git a/include/asm-i386/mach-voyager/entry_arch.h b/include/asm-x86/mach-voyager/entry_arch.h similarity index 100% rename from include/asm-i386/mach-voyager/entry_arch.h rename to include/asm-x86/mach-voyager/entry_arch.h diff --git a/include/asm-i386/mach-voyager/irq_vectors.h b/include/asm-x86/mach-voyager/irq_vectors.h similarity index 100% rename from include/asm-i386/mach-voyager/irq_vectors.h rename to include/asm-x86/mach-voyager/irq_vectors.h diff --git a/include/asm-i386/mach-voyager/setup_arch.h b/include/asm-x86/mach-voyager/setup_arch.h similarity index 100% rename from include/asm-i386/mach-voyager/setup_arch.h rename to include/asm-x86/mach-voyager/setup_arch.h diff --git a/include/asm-x86_64/mach_apic.h b/include/asm-x86/mach_apic.h similarity index 100% rename from include/asm-x86_64/mach_apic.h rename to include/asm-x86/mach_apic.h diff --git a/include/asm-i386/math_emu.h b/include/asm-x86/math_emu.h similarity index 100% rename from include/asm-i386/math_emu.h rename to include/asm-x86/math_emu.h diff --git a/include/asm-x86/mc146818rtc.h b/include/asm-x86/mc146818rtc.h new file mode 100644 index 000000000000..5c2bb66caf17 --- /dev/null +++ b/include/asm-x86/mc146818rtc.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "mc146818rtc_32.h" +#else +# include "mc146818rtc_64.h" +#endif diff --git a/include/asm-i386/mc146818rtc.h b/include/asm-x86/mc146818rtc_32.h similarity index 100% rename from include/asm-i386/mc146818rtc.h rename to include/asm-x86/mc146818rtc_32.h diff --git a/include/asm-x86_64/mc146818rtc.h b/include/asm-x86/mc146818rtc_64.h similarity index 100% rename from include/asm-x86_64/mc146818rtc.h rename to include/asm-x86/mc146818rtc_64.h diff --git a/include/asm-i386/mca.h b/include/asm-x86/mca.h similarity index 100% rename from include/asm-i386/mca.h rename to include/asm-x86/mca.h diff --git a/include/asm-i386/mca_dma.h b/include/asm-x86/mca_dma.h similarity index 100% rename from include/asm-i386/mca_dma.h rename to include/asm-x86/mca_dma.h diff --git a/include/asm-x86/mce.h b/include/asm-x86/mce.h new file mode 100644 index 000000000000..cc8ca389912e --- /dev/null +++ b/include/asm-x86/mce.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "mce_32.h" +#else +# include "mce_64.h" +#endif diff --git a/include/asm-i386/mce.h b/include/asm-x86/mce_32.h similarity index 100% rename from include/asm-i386/mce.h rename to include/asm-x86/mce_32.h diff --git a/include/asm-x86_64/mce.h b/include/asm-x86/mce_64.h similarity index 100% rename from include/asm-x86_64/mce.h rename to include/asm-x86/mce_64.h diff --git a/include/asm-x86/mman.h b/include/asm-x86/mman.h new file mode 100644 index 000000000000..322db07e82c3 --- /dev/null +++ b/include/asm-x86/mman.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "mman_32.h" +# else +# include "mman_64.h" +# endif +#else +# ifdef __i386__ +# include "mman_32.h" +# else +# include "mman_64.h" +# endif +#endif diff --git a/include/asm-i386/mman.h b/include/asm-x86/mman_32.h similarity index 100% rename from include/asm-i386/mman.h rename to include/asm-x86/mman_32.h diff --git a/include/asm-x86_64/mman.h b/include/asm-x86/mman_64.h similarity index 100% rename from include/asm-x86_64/mman.h rename to include/asm-x86/mman_64.h diff --git a/include/asm-x86_64/mmsegment.h b/include/asm-x86/mmsegment.h similarity index 100% rename from include/asm-x86_64/mmsegment.h rename to include/asm-x86/mmsegment.h diff --git a/include/asm-x86/mmu.h b/include/asm-x86/mmu.h new file mode 100644 index 000000000000..9c628cd70e23 --- /dev/null +++ b/include/asm-x86/mmu.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "mmu_32.h" +#else +# include "mmu_64.h" +#endif diff --git a/include/asm-i386/mmu.h b/include/asm-x86/mmu_32.h similarity index 100% rename from include/asm-i386/mmu.h rename to include/asm-x86/mmu_32.h diff --git a/include/asm-x86_64/mmu.h b/include/asm-x86/mmu_64.h similarity index 100% rename from include/asm-x86_64/mmu.h rename to include/asm-x86/mmu_64.h diff --git a/include/asm-x86/mmu_context.h b/include/asm-x86/mmu_context.h new file mode 100644 index 000000000000..6598450da6c6 --- /dev/null +++ b/include/asm-x86/mmu_context.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "mmu_context_32.h" +#else +# include "mmu_context_64.h" +#endif diff --git a/include/asm-i386/mmu_context.h b/include/asm-x86/mmu_context_32.h similarity index 100% rename from include/asm-i386/mmu_context.h rename to include/asm-x86/mmu_context_32.h diff --git a/include/asm-x86_64/mmu_context.h b/include/asm-x86/mmu_context_64.h similarity index 100% rename from include/asm-x86_64/mmu_context.h rename to include/asm-x86/mmu_context_64.h diff --git a/include/asm-i386/mmx.h b/include/asm-x86/mmx.h similarity index 100% rename from include/asm-i386/mmx.h rename to include/asm-x86/mmx.h diff --git a/include/asm-x86/mmzone.h b/include/asm-x86/mmzone.h new file mode 100644 index 000000000000..64217ea16a36 --- /dev/null +++ b/include/asm-x86/mmzone.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "mmzone_32.h" +#else +# include "mmzone_64.h" +#endif diff --git a/include/asm-i386/mmzone.h b/include/asm-x86/mmzone_32.h similarity index 100% rename from include/asm-i386/mmzone.h rename to include/asm-x86/mmzone_32.h diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86/mmzone_64.h similarity index 100% rename from include/asm-x86_64/mmzone.h rename to include/asm-x86/mmzone_64.h diff --git a/include/asm-x86/module.h b/include/asm-x86/module.h new file mode 100644 index 000000000000..2b2f18d8a531 --- /dev/null +++ b/include/asm-x86/module.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "module_32.h" +#else +# include "module_64.h" +#endif diff --git a/include/asm-i386/module.h b/include/asm-x86/module_32.h similarity index 100% rename from include/asm-i386/module.h rename to include/asm-x86/module_32.h diff --git a/include/asm-x86_64/module.h b/include/asm-x86/module_64.h similarity index 100% rename from include/asm-x86_64/module.h rename to include/asm-x86/module_64.h diff --git a/include/asm-x86/mpspec.h b/include/asm-x86/mpspec.h new file mode 100644 index 000000000000..8f268e8fd2e9 --- /dev/null +++ b/include/asm-x86/mpspec.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "mpspec_32.h" +#else +# include "mpspec_64.h" +#endif diff --git a/include/asm-i386/mpspec.h b/include/asm-x86/mpspec_32.h similarity index 100% rename from include/asm-i386/mpspec.h rename to include/asm-x86/mpspec_32.h diff --git a/include/asm-x86_64/mpspec.h b/include/asm-x86/mpspec_64.h similarity index 100% rename from include/asm-x86_64/mpspec.h rename to include/asm-x86/mpspec_64.h diff --git a/include/asm-i386/mpspec_def.h b/include/asm-x86/mpspec_def.h similarity index 100% rename from include/asm-i386/mpspec_def.h rename to include/asm-x86/mpspec_def.h diff --git a/include/asm-x86/msgbuf.h b/include/asm-x86/msgbuf.h new file mode 100644 index 000000000000..154f7d64e862 --- /dev/null +++ b/include/asm-x86/msgbuf.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "msgbuf_32.h" +# else +# include "msgbuf_64.h" +# endif +#else +# ifdef __i386__ +# include "msgbuf_32.h" +# else +# include "msgbuf_64.h" +# endif +#endif diff --git a/include/asm-i386/msgbuf.h b/include/asm-x86/msgbuf_32.h similarity index 100% rename from include/asm-i386/msgbuf.h rename to include/asm-x86/msgbuf_32.h diff --git a/include/asm-x86_64/msgbuf.h b/include/asm-x86/msgbuf_64.h similarity index 100% rename from include/asm-x86_64/msgbuf.h rename to include/asm-x86/msgbuf_64.h diff --git a/include/asm-i386/msidef.h b/include/asm-x86/msidef.h similarity index 100% rename from include/asm-i386/msidef.h rename to include/asm-x86/msidef.h diff --git a/include/asm-i386/msr-index.h b/include/asm-x86/msr-index.h similarity index 100% rename from include/asm-i386/msr-index.h rename to include/asm-x86/msr-index.h diff --git a/include/asm-x86/msr.h b/include/asm-x86/msr.h new file mode 100644 index 000000000000..2f87ce007002 --- /dev/null +++ b/include/asm-x86/msr.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "msr_32.h" +# else +# include "msr_64.h" +# endif +#else +# ifdef __i386__ +# include "msr_32.h" +# else +# include "msr_64.h" +# endif +#endif diff --git a/include/asm-i386/msr.h b/include/asm-x86/msr_32.h similarity index 100% rename from include/asm-i386/msr.h rename to include/asm-x86/msr_32.h diff --git a/include/asm-x86_64/msr.h b/include/asm-x86/msr_64.h similarity index 100% rename from include/asm-x86_64/msr.h rename to include/asm-x86/msr_64.h diff --git a/include/asm-x86/mtrr.h b/include/asm-x86/mtrr.h new file mode 100644 index 000000000000..34f633b3e00c --- /dev/null +++ b/include/asm-x86/mtrr.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "mtrr_32.h" +# else +# include "mtrr_64.h" +# endif +#else +# ifdef __i386__ +# include "mtrr_32.h" +# else +# include "mtrr_64.h" +# endif +#endif diff --git a/include/asm-i386/mtrr.h b/include/asm-x86/mtrr_32.h similarity index 100% rename from include/asm-i386/mtrr.h rename to include/asm-x86/mtrr_32.h diff --git a/include/asm-x86_64/mtrr.h b/include/asm-x86/mtrr_64.h similarity index 100% rename from include/asm-x86_64/mtrr.h rename to include/asm-x86/mtrr_64.h diff --git a/include/asm-x86/mutex.h b/include/asm-x86/mutex.h new file mode 100644 index 000000000000..a731b9c573a6 --- /dev/null +++ b/include/asm-x86/mutex.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "mutex_32.h" +#else +# include "mutex_64.h" +#endif diff --git a/include/asm-i386/mutex.h b/include/asm-x86/mutex_32.h similarity index 100% rename from include/asm-i386/mutex.h rename to include/asm-x86/mutex_32.h diff --git a/include/asm-x86_64/mutex.h b/include/asm-x86/mutex_64.h similarity index 100% rename from include/asm-x86_64/mutex.h rename to include/asm-x86/mutex_64.h diff --git a/include/asm-x86/namei.h b/include/asm-x86/namei.h new file mode 100644 index 000000000000..732f8f0b3dcd --- /dev/null +++ b/include/asm-x86/namei.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "namei_32.h" +#else +# include "namei_64.h" +#endif diff --git a/include/asm-i386/namei.h b/include/asm-x86/namei_32.h similarity index 100% rename from include/asm-i386/namei.h rename to include/asm-x86/namei_32.h diff --git a/include/asm-x86_64/namei.h b/include/asm-x86/namei_64.h similarity index 100% rename from include/asm-x86_64/namei.h rename to include/asm-x86/namei_64.h diff --git a/include/asm-x86/nmi.h b/include/asm-x86/nmi.h new file mode 100644 index 000000000000..53ccac14cead --- /dev/null +++ b/include/asm-x86/nmi.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "nmi_32.h" +#else +# include "nmi_64.h" +#endif diff --git a/include/asm-i386/nmi.h b/include/asm-x86/nmi_32.h similarity index 100% rename from include/asm-i386/nmi.h rename to include/asm-x86/nmi_32.h diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86/nmi_64.h similarity index 100% rename from include/asm-x86_64/nmi.h rename to include/asm-x86/nmi_64.h diff --git a/include/asm-x86/numa.h b/include/asm-x86/numa.h new file mode 100644 index 000000000000..27da400d3138 --- /dev/null +++ b/include/asm-x86/numa.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "numa_32.h" +#else +# include "numa_64.h" +#endif diff --git a/include/asm-i386/numa.h b/include/asm-x86/numa_32.h similarity index 100% rename from include/asm-i386/numa.h rename to include/asm-x86/numa_32.h diff --git a/include/asm-x86_64/numa.h b/include/asm-x86/numa_64.h similarity index 100% rename from include/asm-x86_64/numa.h rename to include/asm-x86/numa_64.h diff --git a/include/asm-i386/numaq.h b/include/asm-x86/numaq.h similarity index 100% rename from include/asm-i386/numaq.h rename to include/asm-x86/numaq.h diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h new file mode 100644 index 000000000000..a757eb26141d --- /dev/null +++ b/include/asm-x86/page.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "page_32.h" +# else +# include "page_64.h" +# endif +#else +# ifdef __i386__ +# include "page_32.h" +# else +# include "page_64.h" +# endif +#endif diff --git a/include/asm-i386/page.h b/include/asm-x86/page_32.h similarity index 100% rename from include/asm-i386/page.h rename to include/asm-x86/page_32.h diff --git a/include/asm-x86_64/page.h b/include/asm-x86/page_64.h similarity index 100% rename from include/asm-x86_64/page.h rename to include/asm-x86/page_64.h diff --git a/include/asm-x86/param.h b/include/asm-x86/param.h new file mode 100644 index 000000000000..640851bab124 --- /dev/null +++ b/include/asm-x86/param.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "param_32.h" +# else +# include "param_64.h" +# endif +#else +# ifdef __i386__ +# include "param_32.h" +# else +# include "param_64.h" +# endif +#endif diff --git a/include/asm-i386/param.h b/include/asm-x86/param_32.h similarity index 100% rename from include/asm-i386/param.h rename to include/asm-x86/param_32.h diff --git a/include/asm-x86_64/param.h b/include/asm-x86/param_64.h similarity index 100% rename from include/asm-x86_64/param.h rename to include/asm-x86/param_64.h diff --git a/include/asm-i386/paravirt.h b/include/asm-x86/paravirt.h similarity index 100% rename from include/asm-i386/paravirt.h rename to include/asm-x86/paravirt.h diff --git a/include/asm-x86/parport.h b/include/asm-x86/parport.h new file mode 100644 index 000000000000..2a31157349c9 --- /dev/null +++ b/include/asm-x86/parport.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "parport_32.h" +#else +# include "parport_64.h" +#endif diff --git a/include/asm-i386/parport.h b/include/asm-x86/parport_32.h similarity index 100% rename from include/asm-i386/parport.h rename to include/asm-x86/parport_32.h diff --git a/include/asm-x86_64/parport.h b/include/asm-x86/parport_64.h similarity index 100% rename from include/asm-x86_64/parport.h rename to include/asm-x86/parport_64.h diff --git a/include/asm-x86_64/pci-direct.h b/include/asm-x86/pci-direct.h similarity index 100% rename from include/asm-x86_64/pci-direct.h rename to include/asm-x86/pci-direct.h diff --git a/include/asm-x86/pci.h b/include/asm-x86/pci.h new file mode 100644 index 000000000000..a8cac8c2cde7 --- /dev/null +++ b/include/asm-x86/pci.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "pci_32.h" +#else +# include "pci_64.h" +#endif diff --git a/include/asm-i386/pci.h b/include/asm-x86/pci_32.h similarity index 100% rename from include/asm-i386/pci.h rename to include/asm-x86/pci_32.h diff --git a/include/asm-x86_64/pci.h b/include/asm-x86/pci_64.h similarity index 100% rename from include/asm-x86_64/pci.h rename to include/asm-x86/pci_64.h diff --git a/include/asm-x86_64/pda.h b/include/asm-x86/pda.h similarity index 100% rename from include/asm-x86_64/pda.h rename to include/asm-x86/pda.h diff --git a/include/asm-x86/percpu.h b/include/asm-x86/percpu.h new file mode 100644 index 000000000000..a1aaad274cca --- /dev/null +++ b/include/asm-x86/percpu.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "percpu_32.h" +#else +# include "percpu_64.h" +#endif diff --git a/include/asm-i386/percpu.h b/include/asm-x86/percpu_32.h similarity index 100% rename from include/asm-i386/percpu.h rename to include/asm-x86/percpu_32.h diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86/percpu_64.h similarity index 100% rename from include/asm-x86_64/percpu.h rename to include/asm-x86/percpu_64.h diff --git a/include/asm-x86/pgalloc.h b/include/asm-x86/pgalloc.h new file mode 100644 index 000000000000..5886eed05886 --- /dev/null +++ b/include/asm-x86/pgalloc.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "pgalloc_32.h" +#else +# include "pgalloc_64.h" +#endif diff --git a/include/asm-i386/pgalloc.h b/include/asm-x86/pgalloc_32.h similarity index 100% rename from include/asm-i386/pgalloc.h rename to include/asm-x86/pgalloc_32.h diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86/pgalloc_64.h similarity index 100% rename from include/asm-x86_64/pgalloc.h rename to include/asm-x86/pgalloc_64.h diff --git a/include/asm-i386/pgtable-2level-defs.h b/include/asm-x86/pgtable-2level-defs.h similarity index 100% rename from include/asm-i386/pgtable-2level-defs.h rename to include/asm-x86/pgtable-2level-defs.h diff --git a/include/asm-i386/pgtable-2level.h b/include/asm-x86/pgtable-2level.h similarity index 100% rename from include/asm-i386/pgtable-2level.h rename to include/asm-x86/pgtable-2level.h diff --git a/include/asm-i386/pgtable-3level-defs.h b/include/asm-x86/pgtable-3level-defs.h similarity index 100% rename from include/asm-i386/pgtable-3level-defs.h rename to include/asm-x86/pgtable-3level-defs.h diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-x86/pgtable-3level.h similarity index 100% rename from include/asm-i386/pgtable-3level.h rename to include/asm-x86/pgtable-3level.h diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h new file mode 100644 index 000000000000..1039140652af --- /dev/null +++ b/include/asm-x86/pgtable.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "pgtable_32.h" +#else +# include "pgtable_64.h" +#endif diff --git a/include/asm-i386/pgtable.h b/include/asm-x86/pgtable_32.h similarity index 100% rename from include/asm-i386/pgtable.h rename to include/asm-x86/pgtable_32.h diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86/pgtable_64.h similarity index 100% rename from include/asm-x86_64/pgtable.h rename to include/asm-x86/pgtable_64.h diff --git a/include/asm-i386/poll.h b/include/asm-x86/poll.h similarity index 100% rename from include/asm-i386/poll.h rename to include/asm-x86/poll.h diff --git a/include/asm-x86/posix_types.h b/include/asm-x86/posix_types.h new file mode 100644 index 000000000000..bb7133dc155d --- /dev/null +++ b/include/asm-x86/posix_types.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "posix_types_32.h" +# else +# include "posix_types_64.h" +# endif +#else +# ifdef __i386__ +# include "posix_types_32.h" +# else +# include "posix_types_64.h" +# endif +#endif diff --git a/include/asm-i386/posix_types.h b/include/asm-x86/posix_types_32.h similarity index 100% rename from include/asm-i386/posix_types.h rename to include/asm-x86/posix_types_32.h diff --git a/include/asm-x86_64/posix_types.h b/include/asm-x86/posix_types_64.h similarity index 100% rename from include/asm-x86_64/posix_types.h rename to include/asm-x86/posix_types_64.h diff --git a/include/asm-x86_64/prctl.h b/include/asm-x86/prctl.h similarity index 100% rename from include/asm-x86_64/prctl.h rename to include/asm-x86/prctl.h diff --git a/include/asm-i386/processor-cyrix.h b/include/asm-x86/processor-cyrix.h similarity index 100% rename from include/asm-i386/processor-cyrix.h rename to include/asm-x86/processor-cyrix.h diff --git a/include/asm-i386/processor-flags.h b/include/asm-x86/processor-flags.h similarity index 100% rename from include/asm-i386/processor-flags.h rename to include/asm-x86/processor-flags.h diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h new file mode 100644 index 000000000000..46e1c04e309c --- /dev/null +++ b/include/asm-x86/processor.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "processor_32.h" +#else +# include "processor_64.h" +#endif diff --git a/include/asm-i386/processor.h b/include/asm-x86/processor_32.h similarity index 100% rename from include/asm-i386/processor.h rename to include/asm-x86/processor_32.h diff --git a/include/asm-x86_64/processor.h b/include/asm-x86/processor_64.h similarity index 100% rename from include/asm-x86_64/processor.h rename to include/asm-x86/processor_64.h diff --git a/include/asm-x86_64/proto.h b/include/asm-x86/proto.h similarity index 100% rename from include/asm-x86_64/proto.h rename to include/asm-x86/proto.h diff --git a/include/asm-x86/ptrace-abi.h b/include/asm-x86/ptrace-abi.h new file mode 100644 index 000000000000..6824c49def1c --- /dev/null +++ b/include/asm-x86/ptrace-abi.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "ptrace-abi_32.h" +# else +# include "ptrace-abi_64.h" +# endif +#else +# ifdef __i386__ +# include "ptrace-abi_32.h" +# else +# include "ptrace-abi_64.h" +# endif +#endif diff --git a/include/asm-i386/ptrace-abi.h b/include/asm-x86/ptrace-abi_32.h similarity index 100% rename from include/asm-i386/ptrace-abi.h rename to include/asm-x86/ptrace-abi_32.h diff --git a/include/asm-x86_64/ptrace-abi.h b/include/asm-x86/ptrace-abi_64.h similarity index 100% rename from include/asm-x86_64/ptrace-abi.h rename to include/asm-x86/ptrace-abi_64.h diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h new file mode 100644 index 000000000000..bc4d64a87689 --- /dev/null +++ b/include/asm-x86/ptrace.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "ptrace_32.h" +# else +# include "ptrace_64.h" +# endif +#else +# ifdef __i386__ +# include "ptrace_32.h" +# else +# include "ptrace_64.h" +# endif +#endif diff --git a/include/asm-i386/ptrace.h b/include/asm-x86/ptrace_32.h similarity index 100% rename from include/asm-i386/ptrace.h rename to include/asm-x86/ptrace_32.h diff --git a/include/asm-x86_64/ptrace.h b/include/asm-x86/ptrace_64.h similarity index 100% rename from include/asm-x86_64/ptrace.h rename to include/asm-x86/ptrace_64.h diff --git a/include/asm-i386/reboot.h b/include/asm-x86/reboot.h similarity index 100% rename from include/asm-i386/reboot.h rename to include/asm-x86/reboot.h diff --git a/include/asm-i386/reboot_fixups.h b/include/asm-x86/reboot_fixups.h similarity index 100% rename from include/asm-i386/reboot_fixups.h rename to include/asm-x86/reboot_fixups.h diff --git a/include/asm-x86/required-features.h b/include/asm-x86/required-features.h new file mode 100644 index 000000000000..8b64f3ea2b78 --- /dev/null +++ b/include/asm-x86/required-features.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "required-features_32.h" +#else +# include "required-features_64.h" +#endif diff --git a/include/asm-i386/required-features.h b/include/asm-x86/required-features_32.h similarity index 100% rename from include/asm-i386/required-features.h rename to include/asm-x86/required-features_32.h diff --git a/include/asm-x86_64/required-features.h b/include/asm-x86/required-features_64.h similarity index 100% rename from include/asm-x86_64/required-features.h rename to include/asm-x86/required-features_64.h diff --git a/include/asm-x86/resource.h b/include/asm-x86/resource.h new file mode 100644 index 000000000000..732410a8c02a --- /dev/null +++ b/include/asm-x86/resource.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "resource_32.h" +# else +# include "resource_64.h" +# endif +#else +# ifdef __i386__ +# include "resource_32.h" +# else +# include "resource_64.h" +# endif +#endif diff --git a/include/asm-i386/resource.h b/include/asm-x86/resource_32.h similarity index 100% rename from include/asm-i386/resource.h rename to include/asm-x86/resource_32.h diff --git a/include/asm-x86_64/resource.h b/include/asm-x86/resource_64.h similarity index 100% rename from include/asm-x86_64/resource.h rename to include/asm-x86/resource_64.h diff --git a/include/asm-x86/resume-trace.h b/include/asm-x86/resume-trace.h new file mode 100644 index 000000000000..9b6dd093a9f7 --- /dev/null +++ b/include/asm-x86/resume-trace.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "resume-trace_32.h" +#else +# include "resume-trace_64.h" +#endif diff --git a/include/asm-i386/resume-trace.h b/include/asm-x86/resume-trace_32.h similarity index 100% rename from include/asm-i386/resume-trace.h rename to include/asm-x86/resume-trace_32.h diff --git a/include/asm-x86_64/resume-trace.h b/include/asm-x86/resume-trace_64.h similarity index 100% rename from include/asm-x86_64/resume-trace.h rename to include/asm-x86/resume-trace_64.h diff --git a/include/asm-x86_64/rio.h b/include/asm-x86/rio.h similarity index 100% rename from include/asm-x86_64/rio.h rename to include/asm-x86/rio.h diff --git a/include/asm-x86/rtc.h b/include/asm-x86/rtc.h new file mode 100644 index 000000000000..1f0c98eb2e38 --- /dev/null +++ b/include/asm-x86/rtc.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "rtc_32.h" +#else +# include "rtc_64.h" +#endif diff --git a/include/asm-i386/rtc.h b/include/asm-x86/rtc_32.h similarity index 100% rename from include/asm-i386/rtc.h rename to include/asm-x86/rtc_32.h diff --git a/include/asm-x86_64/rtc.h b/include/asm-x86/rtc_64.h similarity index 100% rename from include/asm-x86_64/rtc.h rename to include/asm-x86/rtc_64.h diff --git a/include/asm-x86/rwlock.h b/include/asm-x86/rwlock.h new file mode 100644 index 000000000000..a3be7d8364af --- /dev/null +++ b/include/asm-x86/rwlock.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "rwlock_32.h" +#else +# include "rwlock_64.h" +#endif diff --git a/include/asm-i386/rwlock.h b/include/asm-x86/rwlock_32.h similarity index 100% rename from include/asm-i386/rwlock.h rename to include/asm-x86/rwlock_32.h diff --git a/include/asm-x86_64/rwlock.h b/include/asm-x86/rwlock_64.h similarity index 100% rename from include/asm-x86_64/rwlock.h rename to include/asm-x86/rwlock_64.h diff --git a/include/asm-i386/rwsem.h b/include/asm-x86/rwsem.h similarity index 100% rename from include/asm-i386/rwsem.h rename to include/asm-x86/rwsem.h diff --git a/include/asm-x86/scatterlist.h b/include/asm-x86/scatterlist.h new file mode 100644 index 000000000000..3a1e76257a27 --- /dev/null +++ b/include/asm-x86/scatterlist.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "scatterlist_32.h" +#else +# include "scatterlist_64.h" +#endif diff --git a/include/asm-i386/scatterlist.h b/include/asm-x86/scatterlist_32.h similarity index 100% rename from include/asm-i386/scatterlist.h rename to include/asm-x86/scatterlist_32.h diff --git a/include/asm-x86_64/scatterlist.h b/include/asm-x86/scatterlist_64.h similarity index 100% rename from include/asm-x86_64/scatterlist.h rename to include/asm-x86/scatterlist_64.h diff --git a/include/asm-x86/seccomp.h b/include/asm-x86/seccomp.h new file mode 100644 index 000000000000..c62e58a5a90d --- /dev/null +++ b/include/asm-x86/seccomp.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "seccomp_32.h" +#else +# include "seccomp_64.h" +#endif diff --git a/include/asm-i386/seccomp.h b/include/asm-x86/seccomp_32.h similarity index 100% rename from include/asm-i386/seccomp.h rename to include/asm-x86/seccomp_32.h diff --git a/include/asm-x86_64/seccomp.h b/include/asm-x86/seccomp_64.h similarity index 100% rename from include/asm-x86_64/seccomp.h rename to include/asm-x86/seccomp_64.h diff --git a/include/asm-x86/sections.h b/include/asm-x86/sections.h new file mode 100644 index 000000000000..ae6c69d9be3f --- /dev/null +++ b/include/asm-x86/sections.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "sections_32.h" +#else +# include "sections_64.h" +#endif diff --git a/include/asm-i386/sections.h b/include/asm-x86/sections_32.h similarity index 100% rename from include/asm-i386/sections.h rename to include/asm-x86/sections_32.h diff --git a/include/asm-x86_64/sections.h b/include/asm-x86/sections_64.h similarity index 100% rename from include/asm-x86_64/sections.h rename to include/asm-x86/sections_64.h diff --git a/include/asm-x86/segment.h b/include/asm-x86/segment.h new file mode 100644 index 000000000000..605068280e28 --- /dev/null +++ b/include/asm-x86/segment.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "segment_32.h" +#else +# include "segment_64.h" +#endif diff --git a/include/asm-i386/segment.h b/include/asm-x86/segment_32.h similarity index 100% rename from include/asm-i386/segment.h rename to include/asm-x86/segment_32.h diff --git a/include/asm-x86_64/segment.h b/include/asm-x86/segment_64.h similarity index 100% rename from include/asm-x86_64/segment.h rename to include/asm-x86/segment_64.h diff --git a/include/asm-x86/semaphore.h b/include/asm-x86/semaphore.h new file mode 100644 index 000000000000..572c0b67a6b0 --- /dev/null +++ b/include/asm-x86/semaphore.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "semaphore_32.h" +#else +# include "semaphore_64.h" +#endif diff --git a/include/asm-i386/semaphore.h b/include/asm-x86/semaphore_32.h similarity index 100% rename from include/asm-i386/semaphore.h rename to include/asm-x86/semaphore_32.h diff --git a/include/asm-x86_64/semaphore.h b/include/asm-x86/semaphore_64.h similarity index 100% rename from include/asm-x86_64/semaphore.h rename to include/asm-x86/semaphore_64.h diff --git a/include/asm-x86/sembuf.h b/include/asm-x86/sembuf.h new file mode 100644 index 000000000000..e42c971e383f --- /dev/null +++ b/include/asm-x86/sembuf.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "sembuf_32.h" +# else +# include "sembuf_64.h" +# endif +#else +# ifdef __i386__ +# include "sembuf_32.h" +# else +# include "sembuf_64.h" +# endif +#endif diff --git a/include/asm-i386/sembuf.h b/include/asm-x86/sembuf_32.h similarity index 100% rename from include/asm-i386/sembuf.h rename to include/asm-x86/sembuf_32.h diff --git a/include/asm-x86_64/sembuf.h b/include/asm-x86/sembuf_64.h similarity index 100% rename from include/asm-x86_64/sembuf.h rename to include/asm-x86/sembuf_64.h diff --git a/include/asm-x86/serial.h b/include/asm-x86/serial.h new file mode 100644 index 000000000000..cf1b05227b29 --- /dev/null +++ b/include/asm-x86/serial.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "serial_32.h" +#else +# include "serial_64.h" +#endif diff --git a/include/asm-i386/serial.h b/include/asm-x86/serial_32.h similarity index 100% rename from include/asm-i386/serial.h rename to include/asm-x86/serial_32.h diff --git a/include/asm-x86_64/serial.h b/include/asm-x86/serial_64.h similarity index 100% rename from include/asm-x86_64/serial.h rename to include/asm-x86/serial_64.h diff --git a/include/asm-x86/setup.h b/include/asm-x86/setup.h new file mode 100644 index 000000000000..81c0d98bb1c8 --- /dev/null +++ b/include/asm-x86/setup.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "setup_32.h" +# else +# include "setup_64.h" +# endif +#else +# ifdef __i386__ +# include "setup_32.h" +# else +# include "setup_64.h" +# endif +#endif diff --git a/include/asm-i386/setup.h b/include/asm-x86/setup_32.h similarity index 100% rename from include/asm-i386/setup.h rename to include/asm-x86/setup_32.h diff --git a/include/asm-x86_64/setup.h b/include/asm-x86/setup_64.h similarity index 100% rename from include/asm-x86_64/setup.h rename to include/asm-x86/setup_64.h diff --git a/include/asm-x86/shmbuf.h b/include/asm-x86/shmbuf.h new file mode 100644 index 000000000000..e85f1cb11217 --- /dev/null +++ b/include/asm-x86/shmbuf.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "shmbuf_32.h" +# else +# include "shmbuf_64.h" +# endif +#else +# ifdef __i386__ +# include "shmbuf_32.h" +# else +# include "shmbuf_64.h" +# endif +#endif diff --git a/include/asm-i386/shmbuf.h b/include/asm-x86/shmbuf_32.h similarity index 100% rename from include/asm-i386/shmbuf.h rename to include/asm-x86/shmbuf_32.h diff --git a/include/asm-x86_64/shmbuf.h b/include/asm-x86/shmbuf_64.h similarity index 100% rename from include/asm-x86_64/shmbuf.h rename to include/asm-x86/shmbuf_64.h diff --git a/include/asm-x86/shmparam.h b/include/asm-x86/shmparam.h new file mode 100644 index 000000000000..165627cc5345 --- /dev/null +++ b/include/asm-x86/shmparam.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "shmparam_32.h" +# else +# include "shmparam_64.h" +# endif +#else +# ifdef __i386__ +# include "shmparam_32.h" +# else +# include "shmparam_64.h" +# endif +#endif diff --git a/include/asm-i386/shmparam.h b/include/asm-x86/shmparam_32.h similarity index 100% rename from include/asm-i386/shmparam.h rename to include/asm-x86/shmparam_32.h diff --git a/include/asm-x86_64/shmparam.h b/include/asm-x86/shmparam_64.h similarity index 100% rename from include/asm-x86_64/shmparam.h rename to include/asm-x86/shmparam_64.h diff --git a/include/asm-x86/sigcontext.h b/include/asm-x86/sigcontext.h new file mode 100644 index 000000000000..0d16ceff1599 --- /dev/null +++ b/include/asm-x86/sigcontext.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "sigcontext_32.h" +# else +# include "sigcontext_64.h" +# endif +#else +# ifdef __i386__ +# include "sigcontext_32.h" +# else +# include "sigcontext_64.h" +# endif +#endif diff --git a/include/asm-x86_64/sigcontext32.h b/include/asm-x86/sigcontext32.h similarity index 100% rename from include/asm-x86_64/sigcontext32.h rename to include/asm-x86/sigcontext32.h diff --git a/include/asm-i386/sigcontext.h b/include/asm-x86/sigcontext_32.h similarity index 100% rename from include/asm-i386/sigcontext.h rename to include/asm-x86/sigcontext_32.h diff --git a/include/asm-x86_64/sigcontext.h b/include/asm-x86/sigcontext_64.h similarity index 100% rename from include/asm-x86_64/sigcontext.h rename to include/asm-x86/sigcontext_64.h diff --git a/include/asm-x86/siginfo.h b/include/asm-x86/siginfo.h new file mode 100644 index 000000000000..0b8e4bb47d25 --- /dev/null +++ b/include/asm-x86/siginfo.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "siginfo_32.h" +# else +# include "siginfo_64.h" +# endif +#else +# ifdef __i386__ +# include "siginfo_32.h" +# else +# include "siginfo_64.h" +# endif +#endif diff --git a/include/asm-i386/siginfo.h b/include/asm-x86/siginfo_32.h similarity index 100% rename from include/asm-i386/siginfo.h rename to include/asm-x86/siginfo_32.h diff --git a/include/asm-x86_64/siginfo.h b/include/asm-x86/siginfo_64.h similarity index 100% rename from include/asm-x86_64/siginfo.h rename to include/asm-x86/siginfo_64.h diff --git a/include/asm-x86/signal.h b/include/asm-x86/signal.h new file mode 100644 index 000000000000..bf5a63f457da --- /dev/null +++ b/include/asm-x86/signal.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "signal_32.h" +# else +# include "signal_64.h" +# endif +#else +# ifdef __i386__ +# include "signal_32.h" +# else +# include "signal_64.h" +# endif +#endif diff --git a/include/asm-i386/signal.h b/include/asm-x86/signal_32.h similarity index 100% rename from include/asm-i386/signal.h rename to include/asm-x86/signal_32.h diff --git a/include/asm-x86_64/signal.h b/include/asm-x86/signal_64.h similarity index 100% rename from include/asm-x86_64/signal.h rename to include/asm-x86/signal_64.h diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h new file mode 100644 index 000000000000..f2e8319a6b0b --- /dev/null +++ b/include/asm-x86/smp.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "smp_32.h" +#else +# include "smp_64.h" +#endif diff --git a/include/asm-i386/smp.h b/include/asm-x86/smp_32.h similarity index 100% rename from include/asm-i386/smp.h rename to include/asm-x86/smp_32.h diff --git a/include/asm-x86_64/smp.h b/include/asm-x86/smp_64.h similarity index 100% rename from include/asm-x86_64/smp.h rename to include/asm-x86/smp_64.h diff --git a/include/asm-i386/socket.h b/include/asm-x86/socket.h similarity index 100% rename from include/asm-i386/socket.h rename to include/asm-x86/socket.h diff --git a/include/asm-x86/sockios.h b/include/asm-x86/sockios.h new file mode 100644 index 000000000000..5a134fc70b9c --- /dev/null +++ b/include/asm-x86/sockios.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "sockios_32.h" +# else +# include "sockios_64.h" +# endif +#else +# ifdef __i386__ +# include "sockios_32.h" +# else +# include "sockios_64.h" +# endif +#endif diff --git a/include/asm-i386/sockios.h b/include/asm-x86/sockios_32.h similarity index 100% rename from include/asm-i386/sockios.h rename to include/asm-x86/sockios_32.h diff --git a/include/asm-x86_64/sockios.h b/include/asm-x86/sockios_64.h similarity index 100% rename from include/asm-x86_64/sockios.h rename to include/asm-x86/sockios_64.h diff --git a/include/asm-x86/sparsemem.h b/include/asm-x86/sparsemem.h new file mode 100644 index 000000000000..3f203b1d9ee8 --- /dev/null +++ b/include/asm-x86/sparsemem.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "sparsemem_32.h" +#else +# include "sparsemem_64.h" +#endif diff --git a/include/asm-i386/sparsemem.h b/include/asm-x86/sparsemem_32.h similarity index 100% rename from include/asm-i386/sparsemem.h rename to include/asm-x86/sparsemem_32.h diff --git a/include/asm-x86_64/sparsemem.h b/include/asm-x86/sparsemem_64.h similarity index 100% rename from include/asm-x86_64/sparsemem.h rename to include/asm-x86/sparsemem_64.h diff --git a/include/asm-x86/spinlock.h b/include/asm-x86/spinlock.h new file mode 100644 index 000000000000..d74d85e71dcb --- /dev/null +++ b/include/asm-x86/spinlock.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "spinlock_32.h" +#else +# include "spinlock_64.h" +#endif diff --git a/include/asm-i386/spinlock.h b/include/asm-x86/spinlock_32.h similarity index 100% rename from include/asm-i386/spinlock.h rename to include/asm-x86/spinlock_32.h diff --git a/include/asm-x86_64/spinlock.h b/include/asm-x86/spinlock_64.h similarity index 100% rename from include/asm-x86_64/spinlock.h rename to include/asm-x86/spinlock_64.h diff --git a/include/asm-i386/spinlock_types.h b/include/asm-x86/spinlock_types.h similarity index 100% rename from include/asm-i386/spinlock_types.h rename to include/asm-x86/spinlock_types.h diff --git a/include/asm-i386/srat.h b/include/asm-x86/srat.h similarity index 100% rename from include/asm-i386/srat.h rename to include/asm-x86/srat.h diff --git a/include/asm-x86_64/stacktrace.h b/include/asm-x86/stacktrace.h similarity index 100% rename from include/asm-x86_64/stacktrace.h rename to include/asm-x86/stacktrace.h diff --git a/include/asm-x86/stat.h b/include/asm-x86/stat.h new file mode 100644 index 000000000000..3ff6b50ef833 --- /dev/null +++ b/include/asm-x86/stat.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "stat_32.h" +# else +# include "stat_64.h" +# endif +#else +# ifdef __i386__ +# include "stat_32.h" +# else +# include "stat_64.h" +# endif +#endif diff --git a/include/asm-i386/stat.h b/include/asm-x86/stat_32.h similarity index 100% rename from include/asm-i386/stat.h rename to include/asm-x86/stat_32.h diff --git a/include/asm-x86_64/stat.h b/include/asm-x86/stat_64.h similarity index 100% rename from include/asm-x86_64/stat.h rename to include/asm-x86/stat_64.h diff --git a/include/asm-x86/statfs.h b/include/asm-x86/statfs.h new file mode 100644 index 000000000000..327fb5d7a148 --- /dev/null +++ b/include/asm-x86/statfs.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "statfs_32.h" +# else +# include "statfs_64.h" +# endif +#else +# ifdef __i386__ +# include "statfs_32.h" +# else +# include "statfs_64.h" +# endif +#endif diff --git a/include/asm-i386/statfs.h b/include/asm-x86/statfs_32.h similarity index 100% rename from include/asm-i386/statfs.h rename to include/asm-x86/statfs_32.h diff --git a/include/asm-x86_64/statfs.h b/include/asm-x86/statfs_64.h similarity index 100% rename from include/asm-x86_64/statfs.h rename to include/asm-x86/statfs_64.h diff --git a/include/asm-x86/string.h b/include/asm-x86/string.h new file mode 100644 index 000000000000..6dfd6d9373a0 --- /dev/null +++ b/include/asm-x86/string.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "string_32.h" +#else +# include "string_64.h" +#endif diff --git a/include/asm-i386/string.h b/include/asm-x86/string_32.h similarity index 100% rename from include/asm-i386/string.h rename to include/asm-x86/string_32.h diff --git a/include/asm-x86_64/string.h b/include/asm-x86/string_64.h similarity index 100% rename from include/asm-x86_64/string.h rename to include/asm-x86/string_64.h diff --git a/include/asm-x86/suspend.h b/include/asm-x86/suspend.h new file mode 100644 index 000000000000..9bd521fe4570 --- /dev/null +++ b/include/asm-x86/suspend.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "suspend_32.h" +#else +# include "suspend_64.h" +#endif diff --git a/include/asm-i386/suspend.h b/include/asm-x86/suspend_32.h similarity index 100% rename from include/asm-i386/suspend.h rename to include/asm-x86/suspend_32.h diff --git a/include/asm-x86_64/suspend.h b/include/asm-x86/suspend_64.h similarity index 100% rename from include/asm-x86_64/suspend.h rename to include/asm-x86/suspend_64.h diff --git a/include/asm-x86_64/swiotlb.h b/include/asm-x86/swiotlb.h similarity index 100% rename from include/asm-x86_64/swiotlb.h rename to include/asm-x86/swiotlb.h diff --git a/include/asm-i386/sync_bitops.h b/include/asm-x86/sync_bitops.h similarity index 100% rename from include/asm-i386/sync_bitops.h rename to include/asm-x86/sync_bitops.h diff --git a/include/asm-x86/system.h b/include/asm-x86/system.h new file mode 100644 index 000000000000..692562b48f2a --- /dev/null +++ b/include/asm-x86/system.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "system_32.h" +#else +# include "system_64.h" +#endif diff --git a/include/asm-i386/system.h b/include/asm-x86/system_32.h similarity index 100% rename from include/asm-i386/system.h rename to include/asm-x86/system_32.h diff --git a/include/asm-x86_64/system.h b/include/asm-x86/system_64.h similarity index 100% rename from include/asm-x86_64/system.h rename to include/asm-x86/system_64.h diff --git a/include/asm-x86_64/tce.h b/include/asm-x86/tce.h similarity index 100% rename from include/asm-x86_64/tce.h rename to include/asm-x86/tce.h diff --git a/include/asm-x86/termbits.h b/include/asm-x86/termbits.h new file mode 100644 index 000000000000..69f3080e2a1d --- /dev/null +++ b/include/asm-x86/termbits.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "termbits_32.h" +# else +# include "termbits_64.h" +# endif +#else +# ifdef __i386__ +# include "termbits_32.h" +# else +# include "termbits_64.h" +# endif +#endif diff --git a/include/asm-i386/termbits.h b/include/asm-x86/termbits_32.h similarity index 100% rename from include/asm-i386/termbits.h rename to include/asm-x86/termbits_32.h diff --git a/include/asm-x86_64/termbits.h b/include/asm-x86/termbits_64.h similarity index 100% rename from include/asm-x86_64/termbits.h rename to include/asm-x86/termbits_64.h diff --git a/include/asm-x86/termios.h b/include/asm-x86/termios.h new file mode 100644 index 000000000000..a4f4ae20a591 --- /dev/null +++ b/include/asm-x86/termios.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "termios_32.h" +# else +# include "termios_64.h" +# endif +#else +# ifdef __i386__ +# include "termios_32.h" +# else +# include "termios_64.h" +# endif +#endif diff --git a/include/asm-i386/termios.h b/include/asm-x86/termios_32.h similarity index 100% rename from include/asm-i386/termios.h rename to include/asm-x86/termios_32.h diff --git a/include/asm-x86_64/termios.h b/include/asm-x86/termios_64.h similarity index 100% rename from include/asm-x86_64/termios.h rename to include/asm-x86/termios_64.h diff --git a/include/asm-i386/therm_throt.h b/include/asm-x86/therm_throt.h similarity index 100% rename from include/asm-i386/therm_throt.h rename to include/asm-x86/therm_throt.h diff --git a/include/asm-x86/thread_info.h b/include/asm-x86/thread_info.h new file mode 100644 index 000000000000..d5fd12f2abdb --- /dev/null +++ b/include/asm-x86/thread_info.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "thread_info_32.h" +#else +# include "thread_info_64.h" +#endif diff --git a/include/asm-i386/thread_info.h b/include/asm-x86/thread_info_32.h similarity index 100% rename from include/asm-i386/thread_info.h rename to include/asm-x86/thread_info_32.h diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86/thread_info_64.h similarity index 100% rename from include/asm-x86_64/thread_info.h rename to include/asm-x86/thread_info_64.h diff --git a/include/asm-i386/time.h b/include/asm-x86/time.h similarity index 100% rename from include/asm-i386/time.h rename to include/asm-x86/time.h diff --git a/include/asm-i386/timer.h b/include/asm-x86/timer.h similarity index 100% rename from include/asm-i386/timer.h rename to include/asm-x86/timer.h diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h new file mode 100644 index 000000000000..d01c18cfccef --- /dev/null +++ b/include/asm-x86/timex.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "timex_32.h" +#else +# include "timex_64.h" +#endif diff --git a/include/asm-i386/timex.h b/include/asm-x86/timex_32.h similarity index 100% rename from include/asm-i386/timex.h rename to include/asm-x86/timex_32.h diff --git a/include/asm-x86_64/timex.h b/include/asm-x86/timex_64.h similarity index 100% rename from include/asm-x86_64/timex.h rename to include/asm-x86/timex_64.h diff --git a/include/asm-x86/tlb.h b/include/asm-x86/tlb.h new file mode 100644 index 000000000000..7d55c3762b43 --- /dev/null +++ b/include/asm-x86/tlb.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "tlb_32.h" +#else +# include "tlb_64.h" +#endif diff --git a/include/asm-i386/tlb.h b/include/asm-x86/tlb_32.h similarity index 100% rename from include/asm-i386/tlb.h rename to include/asm-x86/tlb_32.h diff --git a/include/asm-x86_64/tlb.h b/include/asm-x86/tlb_64.h similarity index 100% rename from include/asm-x86_64/tlb.h rename to include/asm-x86/tlb_64.h diff --git a/include/asm-x86/tlbflush.h b/include/asm-x86/tlbflush.h new file mode 100644 index 000000000000..9af4cc83a1af --- /dev/null +++ b/include/asm-x86/tlbflush.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "tlbflush_32.h" +#else +# include "tlbflush_64.h" +#endif diff --git a/include/asm-i386/tlbflush.h b/include/asm-x86/tlbflush_32.h similarity index 100% rename from include/asm-i386/tlbflush.h rename to include/asm-x86/tlbflush_32.h diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86/tlbflush_64.h similarity index 100% rename from include/asm-x86_64/tlbflush.h rename to include/asm-x86/tlbflush_64.h diff --git a/include/asm-x86/topology.h b/include/asm-x86/topology.h new file mode 100644 index 000000000000..b10fde9798ea --- /dev/null +++ b/include/asm-x86/topology.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "topology_32.h" +#else +# include "topology_64.h" +#endif diff --git a/include/asm-i386/topology.h b/include/asm-x86/topology_32.h similarity index 100% rename from include/asm-i386/topology.h rename to include/asm-x86/topology_32.h diff --git a/include/asm-x86_64/topology.h b/include/asm-x86/topology_64.h similarity index 100% rename from include/asm-x86_64/topology.h rename to include/asm-x86/topology_64.h diff --git a/include/asm-i386/tsc.h b/include/asm-x86/tsc.h similarity index 100% rename from include/asm-i386/tsc.h rename to include/asm-x86/tsc.h diff --git a/include/asm-x86/types.h b/include/asm-x86/types.h new file mode 100644 index 000000000000..a777a9b83974 --- /dev/null +++ b/include/asm-x86/types.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "types_32.h" +# else +# include "types_64.h" +# endif +#else +# ifdef __i386__ +# include "types_32.h" +# else +# include "types_64.h" +# endif +#endif diff --git a/include/asm-i386/types.h b/include/asm-x86/types_32.h similarity index 100% rename from include/asm-i386/types.h rename to include/asm-x86/types_32.h diff --git a/include/asm-x86_64/types.h b/include/asm-x86/types_64.h similarity index 100% rename from include/asm-x86_64/types.h rename to include/asm-x86/types_64.h diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h new file mode 100644 index 000000000000..9fefd2947e78 --- /dev/null +++ b/include/asm-x86/uaccess.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "uaccess_32.h" +#else +# include "uaccess_64.h" +#endif diff --git a/include/asm-i386/uaccess.h b/include/asm-x86/uaccess_32.h similarity index 100% rename from include/asm-i386/uaccess.h rename to include/asm-x86/uaccess_32.h diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86/uaccess_64.h similarity index 100% rename from include/asm-x86_64/uaccess.h rename to include/asm-x86/uaccess_64.h diff --git a/include/asm-x86/ucontext.h b/include/asm-x86/ucontext.h new file mode 100644 index 000000000000..175c8cb59731 --- /dev/null +++ b/include/asm-x86/ucontext.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "ucontext_32.h" +# else +# include "ucontext_64.h" +# endif +#else +# ifdef __i386__ +# include "ucontext_32.h" +# else +# include "ucontext_64.h" +# endif +#endif diff --git a/include/asm-i386/ucontext.h b/include/asm-x86/ucontext_32.h similarity index 100% rename from include/asm-i386/ucontext.h rename to include/asm-x86/ucontext_32.h diff --git a/include/asm-x86_64/ucontext.h b/include/asm-x86/ucontext_64.h similarity index 100% rename from include/asm-x86_64/ucontext.h rename to include/asm-x86/ucontext_64.h diff --git a/include/asm-x86/unaligned.h b/include/asm-x86/unaligned.h new file mode 100644 index 000000000000..68067150fbcb --- /dev/null +++ b/include/asm-x86/unaligned.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "unaligned_32.h" +#else +# include "unaligned_64.h" +#endif diff --git a/include/asm-i386/unaligned.h b/include/asm-x86/unaligned_32.h similarity index 100% rename from include/asm-i386/unaligned.h rename to include/asm-x86/unaligned_32.h diff --git a/include/asm-x86_64/unaligned.h b/include/asm-x86/unaligned_64.h similarity index 100% rename from include/asm-x86_64/unaligned.h rename to include/asm-x86/unaligned_64.h diff --git a/include/asm-x86/unistd.h b/include/asm-x86/unistd.h new file mode 100644 index 000000000000..2a58ed3e51d8 --- /dev/null +++ b/include/asm-x86/unistd.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "unistd_32.h" +# else +# include "unistd_64.h" +# endif +#else +# ifdef __i386__ +# include "unistd_32.h" +# else +# include "unistd_64.h" +# endif +#endif diff --git a/include/asm-i386/unistd.h b/include/asm-x86/unistd_32.h similarity index 100% rename from include/asm-i386/unistd.h rename to include/asm-x86/unistd_32.h diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86/unistd_64.h similarity index 100% rename from include/asm-x86_64/unistd.h rename to include/asm-x86/unistd_64.h diff --git a/include/asm-x86/unwind.h b/include/asm-x86/unwind.h new file mode 100644 index 000000000000..7e4d7ad55208 --- /dev/null +++ b/include/asm-x86/unwind.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "unwind_32.h" +#else +# include "unwind_64.h" +#endif diff --git a/include/asm-i386/unwind.h b/include/asm-x86/unwind_32.h similarity index 100% rename from include/asm-i386/unwind.h rename to include/asm-x86/unwind_32.h diff --git a/include/asm-x86_64/unwind.h b/include/asm-x86/unwind_64.h similarity index 100% rename from include/asm-x86_64/unwind.h rename to include/asm-x86/unwind_64.h diff --git a/include/asm-x86/user.h b/include/asm-x86/user.h new file mode 100644 index 000000000000..484715abe74a --- /dev/null +++ b/include/asm-x86/user.h @@ -0,0 +1,13 @@ +#ifdef __KERNEL__ +# ifdef CONFIG_X86_32 +# include "user_32.h" +# else +# include "user_64.h" +# endif +#else +# ifdef __i386__ +# include "user_32.h" +# else +# include "user_64.h" +# endif +#endif diff --git a/include/asm-x86_64/user32.h b/include/asm-x86/user32.h similarity index 100% rename from include/asm-x86_64/user32.h rename to include/asm-x86/user32.h diff --git a/include/asm-i386/user.h b/include/asm-x86/user_32.h similarity index 100% rename from include/asm-i386/user.h rename to include/asm-x86/user_32.h diff --git a/include/asm-x86_64/user.h b/include/asm-x86/user_64.h similarity index 100% rename from include/asm-x86_64/user.h rename to include/asm-x86/user_64.h diff --git a/include/asm-i386/vga.h b/include/asm-x86/vga.h similarity index 100% rename from include/asm-i386/vga.h rename to include/asm-x86/vga.h diff --git a/include/asm-x86_64/vgtod.h b/include/asm-x86/vgtod.h similarity index 100% rename from include/asm-x86_64/vgtod.h rename to include/asm-x86/vgtod.h diff --git a/include/asm-i386/vic.h b/include/asm-x86/vic.h similarity index 100% rename from include/asm-i386/vic.h rename to include/asm-x86/vic.h diff --git a/include/asm-i386/vm86.h b/include/asm-x86/vm86.h similarity index 100% rename from include/asm-i386/vm86.h rename to include/asm-x86/vm86.h diff --git a/include/asm-i386/vmi.h b/include/asm-x86/vmi.h similarity index 100% rename from include/asm-i386/vmi.h rename to include/asm-x86/vmi.h diff --git a/include/asm-i386/vmi_time.h b/include/asm-x86/vmi_time.h similarity index 100% rename from include/asm-i386/vmi_time.h rename to include/asm-x86/vmi_time.h diff --git a/include/asm-i386/voyager.h b/include/asm-x86/voyager.h similarity index 100% rename from include/asm-i386/voyager.h rename to include/asm-x86/voyager.h diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86/vsyscall.h similarity index 100% rename from include/asm-x86_64/vsyscall.h rename to include/asm-x86/vsyscall.h diff --git a/include/asm-x86_64/vsyscall32.h b/include/asm-x86/vsyscall32.h similarity index 100% rename from include/asm-x86_64/vsyscall32.h rename to include/asm-x86/vsyscall32.h diff --git a/include/asm-i386/xen/hypercall.h b/include/asm-x86/xen/hypercall.h similarity index 100% rename from include/asm-i386/xen/hypercall.h rename to include/asm-x86/xen/hypercall.h diff --git a/include/asm-i386/xen/hypervisor.h b/include/asm-x86/xen/hypervisor.h similarity index 100% rename from include/asm-i386/xen/hypervisor.h rename to include/asm-x86/xen/hypervisor.h diff --git a/include/asm-i386/xen/interface.h b/include/asm-x86/xen/interface.h similarity index 100% rename from include/asm-i386/xen/interface.h rename to include/asm-x86/xen/interface.h diff --git a/include/asm-x86/xor.h b/include/asm-x86/xor.h new file mode 100644 index 000000000000..11b3bb86e17b --- /dev/null +++ b/include/asm-x86/xor.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_32 +# include "xor_32.h" +#else +# include "xor_64.h" +#endif diff --git a/include/asm-i386/xor.h b/include/asm-x86/xor_32.h similarity index 100% rename from include/asm-i386/xor.h rename to include/asm-x86/xor_32.h diff --git a/include/asm-x86_64/xor.h b/include/asm-x86/xor_64.h similarity index 100% rename from include/asm-x86_64/xor.h rename to include/asm-x86/xor_64.h diff --git a/include/asm-x86_64/Kbuild b/include/asm-x86_64/Kbuild deleted file mode 100644 index 75a2deffca68..000000000000 --- a/include/asm-x86_64/Kbuild +++ /dev/null @@ -1,21 +0,0 @@ -include include/asm-generic/Kbuild.asm - -ALTARCH := i386 -ARCHDEF := defined __x86_64__ -ALTARCHDEF := defined __i386__ - -header-y += boot.h -header-y += bootsetup.h -header-y += debugreg.h -header-y += ldt.h -header-y += msr-index.h -header-y += prctl.h -header-y += ptrace-abi.h -header-y += sigcontext32.h -header-y += ucontext.h -header-y += vsyscall32.h - -unifdef-y += mce.h -unifdef-y += msr.h -unifdef-y += mtrr.h -unifdef-y += vsyscall.h diff --git a/include/asm-x86_64/boot.h b/include/asm-x86_64/boot.h deleted file mode 100644 index 3c46cea8db7f..000000000000 --- a/include/asm-x86_64/boot.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/bootparam.h b/include/asm-x86_64/bootparam.h deleted file mode 100644 index aa82e5238d82..000000000000 --- a/include/asm-x86_64/bootparam.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/cpu.h b/include/asm-x86_64/cpu.h deleted file mode 100644 index 8eea076525a4..000000000000 --- a/include/asm-x86_64/cpu.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/emergency-restart.h b/include/asm-x86_64/emergency-restart.h deleted file mode 100644 index 680c39563345..000000000000 --- a/include/asm-x86_64/emergency-restart.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_EMERGENCY_RESTART_H -#define _ASM_EMERGENCY_RESTART_H - -extern void machine_emergency_restart(void); - -#endif /* _ASM_EMERGENCY_RESTART_H */ diff --git a/include/asm-x86_64/fcntl.h b/include/asm-x86_64/fcntl.h deleted file mode 100644 index 46ab12db5739..000000000000 --- a/include/asm-x86_64/fcntl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/hypertransport.h b/include/asm-x86_64/hypertransport.h deleted file mode 100644 index 5cbf9fa5e0b5..000000000000 --- a/include/asm-x86_64/hypertransport.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/ide.h b/include/asm-x86_64/ide.h deleted file mode 100644 index 4cef0ef61878..000000000000 --- a/include/asm-x86_64/ide.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/ioctl.h b/include/asm-x86_64/ioctl.h deleted file mode 100644 index b279fe06dfe5..000000000000 --- a/include/asm-x86_64/ioctl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/ist.h b/include/asm-x86_64/ist.h deleted file mode 100644 index 338857ecbc68..000000000000 --- a/include/asm-x86_64/ist.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/msidef.h b/include/asm-x86_64/msidef.h deleted file mode 100644 index 083ad5827e48..000000000000 --- a/include/asm-x86_64/msidef.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/msr-index.h b/include/asm-x86_64/msr-index.h deleted file mode 100644 index d77a63f1ddf2..000000000000 --- a/include/asm-x86_64/msr-index.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/poll.h b/include/asm-x86_64/poll.h deleted file mode 100644 index c98509d3149e..000000000000 --- a/include/asm-x86_64/poll.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/processor-flags.h b/include/asm-x86_64/processor-flags.h deleted file mode 100644 index ec99a57b2c6a..000000000000 --- a/include/asm-x86_64/processor-flags.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/socket.h b/include/asm-x86_64/socket.h deleted file mode 100644 index 90af60cf3c0e..000000000000 --- a/include/asm-x86_64/socket.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _ASM_SOCKET_H -#define _ASM_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 - -#endif /* _ASM_SOCKET_H */ diff --git a/include/asm-x86_64/spinlock_types.h b/include/asm-x86_64/spinlock_types.h deleted file mode 100644 index 4da9345c1500..000000000000 --- a/include/asm-x86_64/spinlock_types.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __ASM_SPINLOCK_TYPES_H -#define __ASM_SPINLOCK_TYPES_H - -#ifndef __LINUX_SPINLOCK_TYPES_H -# error "please don't include this file directly" -#endif - -typedef struct { - unsigned int slock; -} raw_spinlock_t; - -#define __RAW_SPIN_LOCK_UNLOCKED { 1 } - -typedef struct { - unsigned int lock; -} raw_rwlock_t; - -#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } - -#endif diff --git a/include/asm-x86_64/therm_throt.h b/include/asm-x86_64/therm_throt.h deleted file mode 100644 index 5aac059007ba..000000000000 --- a/include/asm-x86_64/therm_throt.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/tsc.h b/include/asm-x86_64/tsc.h deleted file mode 100644 index d66ba6ef25f6..000000000000 --- a/include/asm-x86_64/tsc.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/vga.h b/include/asm-x86_64/vga.h deleted file mode 100644 index 0ecf68ac03aa..000000000000 --- a/include/asm-x86_64/vga.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Access to VGA videoram - * - * (c) 1998 Martin Mares - */ - -#ifndef _LINUX_ASM_VGA_H_ -#define _LINUX_ASM_VGA_H_ - -/* - * On the PC, we can just recalculate addresses and then - * access the videoram directly without any black magic. - */ - -#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) - -#define vga_readb(x) (*(x)) -#define vga_writeb(x,y) (*(y) = (x)) - -#endif diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index 0dcc01ce45a6..366f8c7f62bf 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -119,5 +119,5 @@ sed -n -e '/^\#define/ { s/[^_]*__NR_\([^[:space:]]*\).*/\ \#endif/p }' $1 } -(ignore_list && syscall_list ${srctree}/include/asm-i386/unistd.h) | \ +(ignore_list && syscall_list ${srctree}/include/asm-x86/unistd_32.h) | \ $* -E -x c - > /dev/null From 914d97fd9925639574d22fc9cdfac7ddd8f325d6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:20:05 +0200 Subject: [PATCH 2116/2804] x86: Add feature-removal entry for bzImage symlinks The i386/x86_64 merge provides a symlink to the old bzImage location. This is just a transitional migration helper. Remove it after a 6 month grace period. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- Documentation/feature-removal-schedule.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 00928d2ecfb2..675f75601ae6 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -306,3 +306,11 @@ Why: In kernel tree version of driver is unmaintained. Sk98lin driver Who: Stephen Hemminger --------------------------- + +What: i386/x86_64 bzImage symlinks +When: April 2008 + +Why: The i386/x86_64 merge provides a symlink to the old bzImage + location so not yet updated user space tools, e.g. package + scripts, do not break. +Who: Thomas Gleixner From 754090fb438b423c953b0db82505184d7738e0d1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:20:06 +0200 Subject: [PATCH 2117/2804] x86: remove migration makefile tweaks The makefile tweaks to allow the build during the move of code from arch/i386 and arch/x86_64 are not longer necessary. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 4 ---- arch/x86_64/Makefile | 4 ---- 2 files changed, 8 deletions(-) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index b433dae1ac7d..5e50dbf00f3e 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -20,10 +20,6 @@ # Fill in SRCARCH SRCARCH := x86 -archprepare: - @mkdir -p ${objtree}/arch/x86/kernel - - HAS_BIARCH := $(call cc-option-yn, -m32) ifeq ($(HAS_BIARCH),y) AS := $(AS) --32 diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index afaf0f998878..8bffb94c71b5 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -24,10 +24,6 @@ # Fill in SRCARCH SRCARCH := x86 -archprepare: - @mkdir -p ${objtree}/arch/x86/kernel - - LDFLAGS := -m elf_x86_64 OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := From 2417a130bd4013f804983c62cb116bc9ec7f8e2d Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 16 Aug 2007 11:12:47 +0200 Subject: [PATCH 2118/2804] [AVR32] Move AT32_PM_BASE definition into pm.h We don't want to redefine this in every file that needs to access the PM. Signed-off-by: Haavard Skinnemoen --- arch/avr32/mach-at32ap/at32ap7000.c | 6 ------ arch/avr32/mach-at32ap/pm.h | 8 ++++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 64cc5583ddfb..373242aab976 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -25,12 +25,6 @@ #include "pio.h" #include "pm.h" -/* - * We can reduce the code size a bit by using a constant here. Since - * this file is completely chip-specific, it's safe to not use - * ioremap. Generic drivers should of course never do this. - */ -#define AT32_PM_BASE 0xfff00000 #define PBMEM(base) \ { \ diff --git a/arch/avr32/mach-at32ap/pm.h b/arch/avr32/mach-at32ap/pm.h index a1f8aced0a8c..47efd0d1951f 100644 --- a/arch/avr32/mach-at32ap/pm.h +++ b/arch/avr32/mach-at32ap/pm.h @@ -4,6 +4,14 @@ #ifndef __ARCH_AVR32_MACH_AT32AP_PM_H__ #define __ARCH_AVR32_MACH_AT32AP_PM_H__ +/* + * We can reduce the code size a bit by using a constant here. Since + * this file is only used on AVR32 AP CPUs with segmentation enabled, + * it's safe to not use ioremap. Generic drivers should of course + * never do this. + */ +#define AT32_PM_BASE 0xfff00000 + /* PM register offsets */ #define PM_MCCTRL 0x0000 #define PM_CKSEL 0x0004 From d938b89392bd3ff64e0610d8c4e0d3f7091d98db Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 9 Aug 2007 20:56:07 -0700 Subject: [PATCH 2119/2804] [AVR32] /sys/kernel/debug/at32ap_clk When debugfs is available, /sys/kernel/debug/at32ap_clk will provide a dump of the power manager registers and of the current clock tree. This can help sorting out various surprises, and when making runtime PM work. Signed-off-by: David Brownell Signed-off-by: Haavard Skinnemoen --- arch/avr32/mach-at32ap/clock.c | 116 +++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c index 0f8c89c9f832..4642117cc9ab 100644 --- a/arch/avr32/mach-at32ap/clock.c +++ b/arch/avr32/mach-at32ap/clock.c @@ -150,3 +150,119 @@ struct clk *clk_get_parent(struct clk *clk) return clk->parent; } EXPORT_SYMBOL(clk_get_parent); + + + +#ifdef CONFIG_DEBUG_FS + +/* /sys/kernel/debug/at32ap_clk */ + +#include +#include +#include +#include "pm.h" + + +#define NEST_DELTA 2 +#define NEST_MAX 6 + +struct clkinf { + struct seq_file *s; + unsigned nest; +}; + +static void +dump_clock(struct clk *parent, struct clkinf *r) +{ + unsigned nest = r->nest; + char buf[16 + NEST_MAX]; + struct clk *clk; + unsigned i; + + /* skip clocks coupled to devices that aren't registered */ + if (parent->dev && !parent->dev->bus_id[0] && !parent->users) + return; + + /* name */ + memset(buf, ' ', sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; + i = strlen(parent->name); + memcpy(buf + nest, parent->name, + min(i, (unsigned)(sizeof(buf) - 1 - nest))); + + seq_printf(r->s, "%s%c users=%2d %-3s %9ld Hz", + buf, parent->set_parent ? '*' : ' ', + parent->users, + parent->users ? "on" : "off", /* NOTE: not-paranoid!! */ + clk_get_rate(parent)); + if (parent->dev) + seq_printf(r->s, ", for %s", parent->dev->bus_id); + seq_printf(r->s, "\n"); + + /* cost of this scan is small, but not linear... */ + r->nest = nest + NEST_DELTA; + for (i = 3; i < at32_nr_clocks; i++) { + clk = at32_clock_list[i]; + if (clk->parent == parent) + dump_clock(clk, r); + } + r->nest = nest; +} + +static int clk_show(struct seq_file *s, void *unused) +{ + struct clkinf r; + int i; + + /* show all the power manager registers */ + seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL)); + seq_printf(s, "CKSEL = %8x\n", pm_readl(CKSEL)); + seq_printf(s, "CPUMASK = %8x\n", pm_readl(CPU_MASK)); + seq_printf(s, "HSBMASK = %8x\n", pm_readl(HSB_MASK)); + seq_printf(s, "PBAMASK = %8x\n", pm_readl(PBA_MASK)); + seq_printf(s, "PBBMASK = %8x\n", pm_readl(PBB_MASK)); + seq_printf(s, "PLL0 = %8x\n", pm_readl(PLL0)); + seq_printf(s, "PLL1 = %8x\n", pm_readl(PLL1)); + seq_printf(s, "IMR = %8x\n", pm_readl(IMR)); + for (i = 0; i < 8; i++) { + if (i == 5) + continue; + seq_printf(s, "GCCTRL%d = %8x\n", i, pm_readl(GCCTRL(i))); + } + + seq_printf(s, "\n"); + + /* show clock tree as derived from the three oscillators + * we "know" are at the head of the list + */ + r.s = s; + r.nest = 0; + dump_clock(at32_clock_list[0], &r); + dump_clock(at32_clock_list[1], &r); + dump_clock(at32_clock_list[2], &r); + + return 0; +} + +static int clk_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_show, NULL); +} + +static const struct file_operations clk_operations = { + .open = clk_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init clk_debugfs_init(void) +{ + (void) debugfs_create_file("at32ap_clk", S_IFREG | S_IRUGO, + NULL, NULL, &clk_operations); + + return 0; +} +postcore_initcall(clk_debugfs_init); + +#endif From 7808fa4853728a776d7e76d68fb406f515a4119c Mon Sep 17 00:00:00 2001 From: Matteo Vit Date: Thu, 9 Aug 2007 14:55:34 +0200 Subject: [PATCH 2120/2804] [AVR32] add multidrive support for pio driver This patch add multidrive support for pio driver Signed-off-by: Matteo Vit - Dave S.r.l. Signed-off-by: Haavard Skinnemoen --- arch/avr32/mach-at32ap/pio.c | 4 ++++ include/asm-avr32/arch-at32ap/portmux.h | 1 + 2 files changed, 5 insertions(+) diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index 1eb99b814f5b..d61a02da898c 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -110,6 +110,10 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags) pio_writel(pio, SODR, mask); else pio_writel(pio, CODR, mask); + if (flags & AT32_GPIOF_MULTIDRV) + pio_writel(pio, MDER, mask); + else + pio_writel(pio, MDDR, mask); pio_writel(pio, PUDR, mask); pio_writel(pio, OER, mask); } else { diff --git a/include/asm-avr32/arch-at32ap/portmux.h b/include/asm-avr32/arch-at32ap/portmux.h index 9930871decde..b1abe6b4e4ef 100644 --- a/include/asm-avr32/arch-at32ap/portmux.h +++ b/include/asm-avr32/arch-at32ap/portmux.h @@ -19,6 +19,7 @@ #define AT32_GPIOF_OUTPUT 0x00000002 /* (OUT) Enable output driver */ #define AT32_GPIOF_HIGH 0x00000004 /* (OUT) Set output high */ #define AT32_GPIOF_DEGLITCH 0x00000008 /* (IN) Filter glitches */ +#define AT32_GPIOF_MULTIDRV 0x00000010 /* Enable multidriver option */ void at32_select_periph(unsigned int pin, unsigned int periph, unsigned long flags); From 6fcf0615117dcfa126083f2163c4dcea3098bbe3 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 14 Jun 2007 17:37:31 +0200 Subject: [PATCH 2121/2804] [AVR32] Wire up USBA device Implement at32_add_device_usba() and use it to wire up the USBA device on ATSTK1000 and ATNGW100. Signed-off-by: Haavard Skinnemoen --- arch/avr32/boards/atngw100/setup.c | 1 + arch/avr32/boards/atstk1000/atstk1002.c | 1 + arch/avr32/mach-at32ap/at32ap7000.c | 68 +++++++++++++++++++++++++ include/asm-avr32/arch-at32ap/board.h | 8 +++ 4 files changed, 78 insertions(+) diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index ef801563bbf5..6e180f435253 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -154,6 +154,7 @@ static int __init atngw100_init(void) set_hw_addr(at32_add_device_eth(1, ð_data[1])); at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); + at32_add_device_usba(0, NULL); for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) { at32_select_gpio(ngw_leds[i].gpio, diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c index c9981b731efa..6b9e466104ad 100644 --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -241,6 +241,7 @@ static int __init atstk1002_init(void) at32_add_device_lcdc(0, &atstk1000_lcdc_data, fbmem_start, fbmem_size); #endif + at32_add_device_usba(0, NULL); #ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM at32_add_device_ssc(0, ATMEL_SSC_TX); #endif diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 373242aab976..f6d154ca4d24 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -1161,6 +1161,72 @@ at32_add_device_ssc(unsigned int id, unsigned int flags) return pdev; } +/* -------------------------------------------------------------------- + * USB Device Controller + * -------------------------------------------------------------------- */ +static struct resource usba0_resource[] __initdata = { + { + .start = 0xff300000, + .end = 0xff3fffff, + .flags = IORESOURCE_MEM, + }, { + .start = 0xfff03000, + .end = 0xfff033ff, + .flags = IORESOURCE_MEM, + }, + IRQ(31), +}; +static struct clk usba0_pclk = { + .name = "pclk", + .parent = &pbb_clk, + .mode = pbb_clk_mode, + .get_rate = pbb_clk_get_rate, + .index = 12, +}; +static struct clk usba0_hclk = { + .name = "hclk", + .parent = &hsb_clk, + .mode = hsb_clk_mode, + .get_rate = hsb_clk_get_rate, + .index = 6, +}; + +struct platform_device *__init +at32_add_device_usba(unsigned int id, struct usba_platform_data *data) +{ + struct platform_device *pdev; + + if (id != 0) + return NULL; + + pdev = platform_device_alloc("atmel_usba_udc", 0); + if (!pdev) + return NULL; + + if (platform_device_add_resources(pdev, usba0_resource, + ARRAY_SIZE(usba0_resource))) + goto out_free_pdev; + + if (data) { + if (platform_device_add_data(pdev, data, sizeof(*data))) + goto out_free_pdev; + + if (data->vbus_pin != GPIO_PIN_NONE) + at32_select_gpio(data->vbus_pin, 0); + } + + usba0_pclk.dev = &pdev->dev; + usba0_hclk.dev = &pdev->dev; + + platform_device_add(pdev); + + return pdev; + +out_free_pdev: + platform_device_put(pdev); + return NULL; +} + /* -------------------------------------------------------------------- * GCLK * -------------------------------------------------------------------- */ @@ -1246,6 +1312,8 @@ struct clk *at32_clock_list[] = { &ssc0_pclk, &ssc1_pclk, &ssc2_pclk, + &usba0_hclk, + &usba0_pclk, &gclk0, &gclk1, &gclk2, diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h index 0215965dc586..7dbd603c38cc 100644 --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h @@ -6,6 +6,8 @@ #include +#define GPIO_PIN_NONE (-1) + /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */ void at32_add_system_devices(void); @@ -36,6 +38,12 @@ struct platform_device * at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, unsigned long fbmem_start, unsigned long fbmem_len); +struct usba_platform_data { + int vbus_pin; +}; +struct platform_device * +at32_add_device_usba(unsigned int id, struct usba_platform_data *data); + /* depending on what's hooked up, not all SSC pins will be used */ #define ATMEL_SSC_TK 0x01 #define ATMEL_SSC_TF 0x02 From d71fce6b932d83e0a1caa49dfa5a536fd50f07c9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 11 Oct 2007 02:44:23 -0700 Subject: [PATCH 2122/2804] [QETH]: fix qeth_main.c drivers/s390/net/qeth_main.c: In function 'qeth_hard_header_parse': drivers/s390/net/qeth_main.c:6584: error: 'dev' undeclared (first use in this function) drivers/s390/net/qeth_main.c:6584: error: (Each undeclared identifier is reported only once drivers/s390/net/qeth_main.c:6584: error: for each function it appears in.) Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/s390/net/qeth_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index c67e7dfd56cc..a2d08c9ba3c4 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -6580,11 +6580,12 @@ qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr) { const struct qeth_card *card; const struct ethhdr *eth; + struct net_device *dev = skb->dev; if (dev->type != ARPHRD_IEEE802_TR) return 0; - card = qeth_get_card_from_dev(skb->dev); + card = qeth_get_card_from_dev(dev); if (card->options.layer2) goto haveheader; #ifdef CONFIG_QETH_IPV6 From 0367d89274d47941b1bc02e35ddad24077de3ce7 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Jan 2006 16:58:49 +0100 Subject: [PATCH 2123/2804] [AVR32] checkstack support Add regexes to recognize stack frame adjustments in AVR32 code. Signed-off-by: Haavard Skinnemoen --- scripts/checkstack.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index f7844f6aa487..663158627155 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -12,6 +12,7 @@ # sh64 port by Paul Mundt # Random bits by Matt Mackall # M68k port by Geert Uytterhoeven and Andreas Schwab +# AVR32 port by Haavard Skinnemoen # # Usage: # objdump -d vmlinux | stackcheck.pl [arch] @@ -37,6 +38,10 @@ my (@stack, $re, $x, $xs); if ($arch eq 'arm') { #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'avr32') { + #8000008a: 20 1d sub sp,4 + #80000ca8: fa cd 05 b0 sub sp,sp,1456 + $re = qr/^.*sub.*sp.*,([0-9]{1,8})/o; } elsif ($arch =~ /^i[3456]86$/) { #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o; From fe57f84efe3165a1e2ec477b256870f3d43b698a Mon Sep 17 00:00:00 2001 From: Matteo Vit Date: Wed, 29 Aug 2007 10:19:40 +0200 Subject: [PATCH 2124/2804] [AVR32] fix command line parsing in early_parse_fbmem Signed-off-by: Matteo Vit - Dave S.r.l. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index d08b0bc6b2bb..4b4c1884e1c5 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c @@ -248,7 +248,7 @@ static int __init early_parse_fbmem(char *p) fbmem_size = memparse(p, &p); if (*p == '@') { - fbmem_start = memparse(p, &p); + fbmem_start = memparse(p + 1, &p); ret = add_reserved_region(fbmem_start, fbmem_start + fbmem_size - 1, "Framebuffer"); From 4e59629bf68e8a6f19b806f8ace3d0f31221c4a4 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 15 Sep 2007 22:47:02 +0200 Subject: [PATCH 2125/2804] [AVR32] rename vmlinux.lds Rename vmlinux.lds to a .S file to match other architectures. Simplify Makefile to match the rename and deleted the unused USE_STANDARD_AS_RULE Signed-off-by: Sam Ravnborg Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/Makefile | 5 ----- arch/avr32/kernel/{vmlinux.lds.c => vmlinux.lds.S} | 0 2 files changed, 5 deletions(-) rename arch/avr32/kernel/{vmlinux.lds.c => vmlinux.lds.S} (100%) diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile index 90e5afff54a2..989fcd1fef7e 100644 --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile @@ -11,8 +11,3 @@ obj-y += signal.o sys_avr32.o process.o time.o obj-y += init_task.o switch_to.o cpu.o obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o obj-$(CONFIG_KPROBES) += kprobes.o - -USE_STANDARD_AS_RULE := true - -%.lds: %.lds.c FORCE - $(call if_changed_dep,cpp_lds_S) diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.S similarity index 100% rename from arch/avr32/kernel/vmlinux.lds.c rename to arch/avr32/kernel/vmlinux.lds.S From 7cf6ac2ae240e02ebdd2717a09d083d47cb60251 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Mon, 17 Sep 2007 11:08:28 +0200 Subject: [PATCH 2126/2804] [AVR32] Kill a few hardcoded constants in vmlinux.lds Use PAGE_SIZE, THREAD_SIZE and L1_CACHE_BYTES instead of harcoded constants in places where that's what we really mean. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/vmlinux.lds.S | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S index db0438f35c00..fef0e6d322f1 100644 --- a/arch/avr32/kernel/vmlinux.lds.S +++ b/arch/avr32/kernel/vmlinux.lds.S @@ -9,6 +9,8 @@ */ #define LOAD_OFFSET 0x00000000 #include +#include +#include OUTPUT_FORMAT("elf32-avr32", "elf32-avr32", "elf32-avr32") OUTPUT_ARCH(avr32) @@ -58,7 +60,7 @@ SECTIONS *(.init.ramfs) __initramfs_end = .; #endif - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); __init_end = .; } @@ -96,7 +98,7 @@ SECTIONS RODATA - . = ALIGN(8192); + . = ALIGN(THREAD_SIZE); .data : AT(ADDR(.data) - LOAD_OFFSET) { _data = .; @@ -107,7 +109,7 @@ SECTIONS *(.data.init_task) /* Then, the cacheline aligned data */ - . = ALIGN(32); + . = ALIGN(L1_CACHE_BYTES); *(.data.cacheline_aligned) /* And the rest... */ From 0d2372e5d61ccc1c618aaf5099700c8dc76e234a Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Mon, 17 Sep 2007 11:13:45 +0200 Subject: [PATCH 2127/2804] [AVR32] Remove unneeded 8K alignment of .text section __init_end, which comes immediately before .text, is already page aligned, and that should be more than enough for the .text section. The reason why we need to align the .text section is because the interrupt handler offset is ORed with EVBA, so we need to provide enough alignment of EVBA that this OR operation works as an ADD. Currently, the last interrupt handler is not nearly a full page away from EVBA, so it won't be a problem. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/vmlinux.lds.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S index fef0e6d322f1..ce9ac9659883 100644 --- a/arch/avr32/kernel/vmlinux.lds.S +++ b/arch/avr32/kernel/vmlinux.lds.S @@ -64,7 +64,6 @@ SECTIONS __init_end = .; } - . = ALIGN(8192); .text : AT(ADDR(.text) - LOAD_OFFSET) { _evba = .; _text = .; From b5a8e7362a0a5088ac080086d41cd98a54e0791b Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 7 Sep 2007 16:00:25 +0100 Subject: [PATCH 2128/2804] [AVR32] Make dma_sync_*_for_cpu no-ops I don't think the dma_sync_*_for_cpu ever did anything useful. We flush the relevant cache lines when mapping the buffer or when calling dma_sync_*_for_device(), and the CPU isn't allowed to touch the buffer after that. In other words, if these functions actually have anything to flush from the caches, we're already in trouble. Signed-off-by: Haavard Skinnemoen --- include/asm-avr32/dma-mapping.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/include/asm-avr32/dma-mapping.h b/include/asm-avr32/dma-mapping.h index 21bb60bbb9a1..81e342636ac4 100644 --- a/include/asm-avr32/dma-mapping.h +++ b/include/asm-avr32/dma-mapping.h @@ -264,7 +264,11 @@ 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_cache_sync(dev, bus_to_virt(dma_handle), size, direction); + /* + * No need to do anything since the CPU isn't supposed to + * touch this memory after we flushed it at mapping- or + * sync-for-device time. + */ } static inline void @@ -309,12 +313,11 @@ static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction) { - int i; - - for (i = 0; i < nents; i++) { - dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset, - sg[i].length, direction); - } + /* + * No need to do anything since the CPU isn't supposed to + * touch this memory after we flushed it at mapping- or + * sync-for-device time. + */ } static inline void From 193fdd1a99db8623697cb18a13dbcaa4eadbb1f2 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 19 Sep 2007 08:43:42 -0400 Subject: [PATCH 2129/2804] [AVR32] Drop support for redundant "keepinitrd" boot-time parm. Given the existing "retain_initrd" boot-time parameter defined in init/initramfs.c, there appears to be no need for the equivalent "keepinitrd" parameter. Signed-off-by: Robert P. J. Day Signed-off-by: Haavard Skinnemoen --- arch/avr32/mm/init.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c index 82cf70854b90..480760bde63f 100644 --- a/arch/avr32/mm/init.c +++ b/arch/avr32/mm/init.c @@ -224,19 +224,9 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD -static int keep_initrd; - void free_initrd_mem(unsigned long start, unsigned long end) { - if (!keep_initrd) - free_area(start, end, "initrd"); + free_area(start, end, "initrd"); } -static int __init keepinitrd_setup(char *__unused) -{ - keep_initrd = 1; - return 1; -} - -__setup("keepinitrd", keepinitrd_setup); #endif From dc9b43d0f706852fc4abce5bf28958db41524328 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Wed, 10 Oct 2007 08:36:18 +1000 Subject: [PATCH 2130/2804] [POWERPC] Disable vDSO support for ARCH=ppc where it's not implemented Signed-off-by: Wolfgang Denk Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vdso.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 213fa31ac537..2322ba5cce4c 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -766,7 +766,9 @@ static int __init vdso_init(void) return 0; } +#ifdef CONFIG_PPC_MERGE arch_initcall(vdso_init); +#endif int in_gate_area_no_task(unsigned long addr) { From 38db7e740ade7f07f6315e3a3b1172d7e456b793 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:48:18 +1000 Subject: [PATCH 2131/2804] [POWERPC] Only call ppc_md.setup_arch() if it is provided This allows platforms which don't have anything to do at setup_arch time (like a bunch of the 4xx platforms) to eliminate an empty setup_arch hook. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_32.c | 3 ++- arch/powerpc/kernel/setup_64.c | 3 ++- include/asm-powerpc/machdep.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 7474502dace5..cd870a823d18 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -290,7 +290,8 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con; #endif - ppc_md.setup_arch(); + if (ppc_md.setup_arch) + ppc_md.setup_arch(); if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); paging_init(); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 3089eaed3256..008ab6823b02 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -530,7 +530,8 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con; #endif - ppc_md.setup_arch(); + if (ppc_md.setup_arch) + ppc_md.setup_arch(); paging_init(); ppc64_boot_msg(0x15, "Setup Done"); diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 71c6e7eb2a26..cc7c17f16a9a 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -99,7 +99,7 @@ struct machdep_calls { #endif /* CONFIG_PPC64 */ int (*probe)(void); - void (*setup_arch)(void); + void (*setup_arch)(void); /* Optional, may be NULL */ void (*init_early)(void); /* Optional, may be NULL. */ void (*show_cpuinfo)(struct seq_file *m); From d27c1cedc0e4faed2c0fce9d82d4c17695e43e90 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:48:23 +1000 Subject: [PATCH 2132/2804] [POWERPC] Remove empty ppc_md.setup_arch hooks Signed-off-by: Grant Likely Acked-by: Josh Boyer Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/40x/virtex.c | 5 ----- arch/powerpc/platforms/40x/walnut.c | 5 ----- arch/powerpc/platforms/44x/bamboo.c | 5 ----- arch/powerpc/platforms/44x/ebony.c | 5 ----- arch/powerpc/platforms/44x/sequoia.c | 5 ----- 5 files changed, 25 deletions(-) diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c index b52aa94abd78..14bbc328170f 100644 --- a/arch/powerpc/platforms/40x/virtex.c +++ b/arch/powerpc/platforms/40x/virtex.c @@ -36,14 +36,9 @@ static int __init virtex_probe(void) return 1; } -static void __init virtex_setup_arch(void) -{ -} - define_machine(virtex) { .name = "Xilinx Virtex", .probe = virtex_probe, - .setup_arch = virtex_setup_arch, .init_IRQ = xilinx_intc_init_tree, .get_irq = xilinx_intc_get_irq, .calibrate_decr = generic_calibrate_decr, diff --git a/arch/powerpc/platforms/40x/walnut.c b/arch/powerpc/platforms/40x/walnut.c index c17fdf23b492..eb0c136b1c44 100644 --- a/arch/powerpc/platforms/40x/walnut.c +++ b/arch/powerpc/platforms/40x/walnut.c @@ -53,14 +53,9 @@ static int __init walnut_probe(void) return 1; } -static void __init walnut_setup_arch(void) -{ -} - define_machine(walnut) { .name = "Walnut", .probe = walnut_probe, - .setup_arch = walnut_setup_arch, .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c index 9bc45dea078f..470e1a3fd755 100644 --- a/arch/powerpc/platforms/44x/bamboo.c +++ b/arch/powerpc/platforms/44x/bamboo.c @@ -50,14 +50,9 @@ static int __init bamboo_probe(void) return 1; } -static void __init bamboo_setup_arch(void) -{ -} - define_machine(bamboo) { .name = "Bamboo", .probe = bamboo_probe, - .setup_arch = bamboo_setup_arch, .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c index 5a7fec8d10d3..40e18fcb666c 100644 --- a/arch/powerpc/platforms/44x/ebony.c +++ b/arch/powerpc/platforms/44x/ebony.c @@ -57,14 +57,9 @@ static int __init ebony_probe(void) return 1; } -static void __init ebony_setup_arch(void) -{ -} - define_machine(ebony) { .name = "Ebony", .probe = ebony_probe, - .setup_arch = ebony_setup_arch, .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, diff --git a/arch/powerpc/platforms/44x/sequoia.c b/arch/powerpc/platforms/44x/sequoia.c index 7d0d9d567d25..30700b31d43b 100644 --- a/arch/powerpc/platforms/44x/sequoia.c +++ b/arch/powerpc/platforms/44x/sequoia.c @@ -50,14 +50,9 @@ static int __init sequoia_probe(void) return 1; } -static void __init sequoia_setup_arch(void) -{ -} - define_machine(sequoia) { .name = "Sequoia", .probe = sequoia_probe, - .setup_arch = sequoia_setup_arch, .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, From 745e1027751acbc1f14f8bbef378b491242b9c83 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:48:28 +1000 Subject: [PATCH 2133/2804] [POWERPC] Platforms shouldn't mess with ROOT_DEV There is no good reason for board platform code to mess with the ROOT_DEV. Remove it from all in-tree platforms except powermac. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/52xx/efika.c | 9 --------- arch/powerpc/platforms/cell/setup.c | 5 ----- arch/powerpc/platforms/celleb/setup.c | 5 ----- arch/powerpc/platforms/chrp/setup.c | 10 ---------- arch/powerpc/platforms/pseries/setup.c | 5 ----- 5 files changed, 34 deletions(-) diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 4263158b3274..0b1e60a010ba 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -197,15 +197,6 @@ static void __init efika_setup_arch(void) { rtas_initialize(); -#ifdef CONFIG_BLK_DEV_INITRD - initrd_below_start_ok = 1; - - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif - ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ - efika_pcisetup(); #ifdef CONFIG_PM diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 5343e3844e2a..98e7ef8e6fc6 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -171,11 +171,6 @@ static void __init cell_setup_arch(void) /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000; - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/hda2\n"); - ROOT_DEV = Root_HDA2; - } - /* Find and initialize PCI host bridges */ init_pci_config_tokens(); find_and_init_phbs(); diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c index 0f1dddb81cd2..1769d755eff3 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/celleb/setup.c @@ -101,11 +101,6 @@ static void __init celleb_setup_arch(void) /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000; - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/hda2\n"); - ROOT_DEV = Root_HDA2; - } - #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 96498ad7b943..59306261f5b2 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -290,16 +290,6 @@ void __init chrp_setup_arch(void) ppc_md.set_rtc_time = rtas_set_rtc_time; } -#ifdef CONFIG_BLK_DEV_INITRD - /* this is fine for chrp */ - initrd_below_start_ok = 1; - - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif - ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ - /* On pegasos, enable the L2 cache if not already done by OF */ pegasos_set_l2cr(); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f0b7146a110f..fdb9b1c8f977 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -257,11 +257,6 @@ static void __init pSeries_setup_arch(void) /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000; - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/sda2\n"); - ROOT_DEV = Root_SDA2; - } - fwnmi_init(); /* Find and initialize PCI host bridges */ From b707f517d2c72c6b340ba762ed8a7de2b22935e9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:48:24 +1000 Subject: [PATCH 2134/2804] [POWERPC] Clean up vio.h Remove vio_dma_ops declaration (since it no longer exists) and some unused fields from struct vio_driver. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 11 ----------- include/asm-powerpc/vio.h | 5 ----- 2 files changed, 16 deletions(-) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 1d7b272b3737..fd631d4d1602 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -168,16 +168,6 @@ static int vio_bus_remove(struct device *dev) return 1; } -/* convert from struct device to struct vio_dev and pass to driver. */ -static void vio_bus_shutdown(struct device *dev) -{ - struct vio_dev *viodev = to_vio_dev(dev); - struct vio_driver *viodrv = to_vio_driver(dev->driver); - - if (dev->driver && viodrv->shutdown) - viodrv->shutdown(viodev); -} - /** * vio_register_driver: - Register a new vio driver * @drv: The vio_driver structure to be registered. @@ -397,7 +387,6 @@ static struct bus_type vio_bus_type = { .match = vio_bus_match, .probe = vio_bus_probe, .remove = vio_bus_remove, - .shutdown = vio_bus_shutdown, }; /** diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h index 598d111e8098..9204c15839c5 100644 --- a/include/asm-powerpc/vio.h +++ b/include/asm-powerpc/vio.h @@ -53,17 +53,12 @@ struct vio_dev { }; struct vio_driver { - struct list_head node; const struct vio_device_id *id_table; int (*probe)(struct vio_dev *dev, const struct vio_device_id *id); int (*remove)(struct vio_dev *dev); - void (*shutdown)(struct vio_dev *dev); - unsigned long driver_data; struct device_driver driver; }; -extern struct dma_mapping_ops vio_dma_ops; - extern int vio_register_driver(struct vio_driver *drv); extern void vio_unregister_driver(struct vio_driver *drv); From 73be7d5267774b8fef1d83ebffc070cd090c4398 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:50:55 +1000 Subject: [PATCH 2135/2804] [POWERPC] iSeries: Simplify viocd initialisation We don't need to keep a lump of dma coherent memory around for the life of the module. Signed-off-by: Stephen Rothwell Acked-by: Jens Axboe Signed-off-by: Paul Mackerras --- drivers/cdrom/viocd.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index e51550db1575..b88fdebe77f6 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -136,17 +136,12 @@ struct cdrom_info { char type[4]; char model[3]; }; -/* - * This needs to be allocated since it is passed to the - * Hypervisor and we may be a module. - */ -static struct cdrom_info *viocd_unitinfo; -static dma_addr_t unitinfo_dmaaddr; struct disk_info { struct gendisk *viocd_disk; struct cdrom_device_info viocd_info; struct device *dev; + struct cdrom_info unitinfo; }; static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; @@ -164,9 +159,9 @@ static int proc_viocd_show(struct seq_file *m, void *v) for (i = 0; i < viocd_numdev; i++) { seq_printf(m, "viocd device %d is iSeries resource %10.10s" "type %4.4s, model %3.3s\n", - i, viocd_unitinfo[i].rsrcname, - viocd_unitinfo[i].type, - viocd_unitinfo[i].model); + i, viocd_diskinfo[i].unitinfo.rsrcname, + viocd_diskinfo[i].unitinfo.type, + viocd_diskinfo[i].unitinfo.model); } return 0; } @@ -222,6 +217,8 @@ static void __init get_viocd_info(void) HvLpEvent_Rc hvrc; int i; struct viocd_waitevent we; + struct cdrom_info *viocd_unitinfo; + dma_addr_t unitinfo_dmaaddr; viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, @@ -259,16 +256,15 @@ static void __init get_viocd_info(void) goto error_ret; } - for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) + for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) { + viocd_diskinfo[viocd_numdev].unitinfo = viocd_unitinfo[i]; viocd_numdev++; + } error_ret: - if (viocd_numdev == 0) { - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); - viocd_unitinfo = NULL; - } + dma_free_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + viocd_unitinfo, unitinfo_dmaaddr); } static int viocd_open(struct cdrom_device_info *cdi, int purpose) @@ -674,7 +670,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) d = &viocd_diskinfo[deviceno]; c = &d->viocd_info; - ci = &viocd_unitinfo[deviceno]; + ci = &d->unitinfo; c->ops = &viocd_dops; c->speed = 4; @@ -816,9 +812,6 @@ static int __init viocd_init(void) return 0; out_free_info: - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); vio_clearHandler(viomajorsubtype_cdio); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); out_unregister: @@ -830,10 +823,6 @@ static void __exit viocd_exit(void) { remove_proc_entry("iSeries/viocd", NULL); vio_unregister_driver(&viocd_driver); - if (viocd_unitinfo != NULL) - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); vio_clearHandler(viomajorsubtype_cdio); unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); From 1670b2b2716b98541765da94be1332ad5c314b7a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:53:32 +1000 Subject: [PATCH 2136/2804] [POWERPC] Remove iSeries_vio_dev It was only being used to carry around dma_iommu_ops and vio_iommu_table which we can use directly instead. This also means that vio_bus_device doesn't need to refer to them either. Signed-off-by: Stephen Rothwell Acked-by: Jens Axboe Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 7 +---- arch/powerpc/platforms/iseries/iommu.c | 30 +++++++++++++++++++++ arch/powerpc/platforms/iseries/mf.c | 23 +++++++--------- arch/powerpc/platforms/iseries/viopath.c | 6 ++--- drivers/cdrom/viocd.c | 5 ++-- drivers/char/viotape.c | 7 +++-- include/asm-powerpc/iseries/hv_call_event.h | 10 +++++++ include/asm-powerpc/iseries/vio.h | 4 --- 8 files changed, 57 insertions(+), 35 deletions(-) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index fd631d4d1602..eaf7f6992a2f 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -49,11 +49,8 @@ static struct vio_dev vio_bus_device = { /* fake "parent" device */ }; #ifdef CONFIG_PPC_ISERIES -struct device *iSeries_vio_dev = &vio_bus_device.dev; -EXPORT_SYMBOL(iSeries_vio_dev); - static struct iommu_table veth_iommu_table; -static struct iommu_table vio_iommu_table; +struct iommu_table vio_iommu_table; static void __init iommu_vio_init(void) { @@ -66,8 +63,6 @@ static void __init iommu_vio_init(void) printk("Virtual Bus VETH TCE table failed.\n"); if (!iommu_init_table(&vio_iommu_table, -1)) printk("Virtual Bus VIO TCE table failed.\n"); - vio_bus_device.dev.archdata.dma_ops = &dma_iommu_ops; - vio_bus_device.dev.archdata.dma_data = &vio_iommu_table; } #else static void __init iommu_vio_init(void) diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 3b6a9666c2c0..3281f10bbd16 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, @@ -189,6 +191,34 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn) } #endif +extern struct iommu_table vio_iommu_table; + +void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) +{ + return iommu_alloc_coherent(&vio_iommu_table, size, dma_handle, + DMA_32BIT_MASK, flag, -1); +} +EXPORT_SYMBOL_GPL(iseries_hv_alloc); + +void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle) +{ + iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle); +} +EXPORT_SYMBOL_GPL(iseries_hv_free); + +dma_addr_t iseries_hv_map(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + return iommu_map_single(&vio_iommu_table, vaddr, size, + DMA_32BIT_MASK, direction); +} + +void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction); +} + void iommu_init_early_iSeries(void) { ppc_md.tce_build = tce_build_iSeries; diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index b1187d95e3b2..c0f2433bc16e 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -39,9 +39,9 @@ #include #include #include -#include #include #include +#include #include #include "setup.h" @@ -870,8 +870,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off, if ((off + count) > 256) count = 256 - off; - dma_addr = dma_map_single(iSeries_vio_dev, page, off + count, - DMA_FROM_DEVICE); + dma_addr = iseries_hv_map(page, off + count, DMA_FROM_DEVICE); if (dma_mapping_error(dma_addr)) return -ENOMEM; memset(page, 0, off + count); @@ -883,8 +882,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off, vsp_cmd.sub_data.kern.length = off + count; mb(); rc = signal_vsp_instruction(&vsp_cmd); - dma_unmap_single(iSeries_vio_dev, dma_addr, off + count, - DMA_FROM_DEVICE); + iseries_hv_unmap(dma_addr, off + count, DMA_FROM_DEVICE); if (rc) return rc; if (vsp_cmd.result_code != 0) @@ -919,8 +917,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) int len = *size; dma_addr_t dma_addr; - dma_addr = dma_map_single(iSeries_vio_dev, buffer, len, - DMA_FROM_DEVICE); + dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE); memset(buffer, 0, len); memset(&vsp_cmd, 0, sizeof(vsp_cmd)); vsp_cmd.cmd = 32; @@ -938,7 +935,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) rc = -ENOMEM; } - dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE); + iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE); return rc; } @@ -1149,8 +1146,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, goto out; dma_addr = 0; - page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, - GFP_ATOMIC); + page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); ret = -ENOMEM; if (page == NULL) goto out; @@ -1170,7 +1166,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, ret = count; out_free: - dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); + iseries_hv_free(count, page, dma_addr); out: return ret; } @@ -1190,8 +1186,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file, goto out; dma_addr = 0; - page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, - GFP_ATOMIC); + page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); rc = -ENOMEM; if (page == NULL) { printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); @@ -1219,7 +1214,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file, *ppos += count; rc = count; out_free: - dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); + iseries_hv_free(count, page, dma_addr); out: return rc; } diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index 45f2fe39c87e..df23331eb25c 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c @@ -124,8 +124,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) if (!buf) return 0; - handle = dma_map_single(iSeries_vio_dev, buf, HW_PAGE_SIZE, - DMA_FROM_DEVICE); + handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, @@ -146,8 +145,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) buf[HW_PAGE_SIZE-1] = '\0'; seq_printf(m, "%s", buf); - dma_unmap_single(iSeries_vio_dev, handle, HW_PAGE_SIZE, - DMA_FROM_DEVICE); + iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE); kfree(buf); seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index b88fdebe77f6..c081e5400ce0 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -220,7 +220,7 @@ static void __init get_viocd_info(void) struct cdrom_info *viocd_unitinfo; dma_addr_t unitinfo_dmaaddr; - viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev, + viocd_unitinfo = iseries_hv_alloc( sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, &unitinfo_dmaaddr, GFP_ATOMIC); if (viocd_unitinfo == NULL) { @@ -262,8 +262,7 @@ static void __init get_viocd_info(void) } error_ret: - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + iseries_hv_free(sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, viocd_unitinfo, unitinfo_dmaaddr); } diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index e12275df6ea2..064c09195215 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -392,8 +392,8 @@ static int get_viotape_info(void) if (op == NULL) return -ENOMEM; - viotape_unitinfo = dma_alloc_coherent(iSeries_vio_dev, len, - &viotape_unitinfo_token, GFP_ATOMIC); + viotape_unitinfo = iseries_hv_alloc(len, &viotape_unitinfo_token, + GFP_ATOMIC); if (viotape_unitinfo == NULL) { free_op_struct(op); return -ENOMEM; @@ -1103,8 +1103,7 @@ static void __exit viotap_exit(void) class_destroy(tape_class); unregister_chrdev(VIOTAPE_MAJOR, "viotape"); if (viotape_unitinfo) - dma_free_coherent(iSeries_vio_dev, - sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, + iseries_hv_free(sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, viotape_unitinfo, viotape_unitinfo_token); viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); vio_clearHandler(viomajorsubtype_tape); diff --git a/include/asm-powerpc/iseries/hv_call_event.h b/include/asm-powerpc/iseries/hv_call_event.h index 4cec4762076d..cc029d388e11 100644 --- a/include/asm-powerpc/iseries/hv_call_event.h +++ b/include/asm-powerpc/iseries/hv_call_event.h @@ -21,6 +21,9 @@ #ifndef _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H #define _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H +#include +#include + #include #include #include @@ -113,6 +116,13 @@ static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, eventData3, eventData4, eventData5); } +extern void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag); +extern void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle); +extern dma_addr_t iseries_hv_map(void *vaddr, size_t size, + enum dma_data_direction direction); +extern void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event) { return HvCall1(HvCallEventAckLpEvent, virt_to_abs(event)); diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index 7a95d296abd1..5a5cd0f0c095 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h @@ -150,8 +150,4 @@ enum viochar_rc { viochar_rc_ebusy = 1 }; -struct device; - -extern struct device *iSeries_vio_dev; - #endif /* _ASM_POWERPC_ISERIES_VIO_H */ From dd9b67ab37d57da67840276d28957498512d4dd8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:55:02 +1000 Subject: [PATCH 2137/2804] [POWERPC] Remove more iSeries-specific stuff from vio.c Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 68 ++++++++------------------ arch/powerpc/platforms/iseries/iommu.c | 24 ++++++++- include/asm-powerpc/iseries/iommu.h | 4 ++ 3 files changed, 47 insertions(+), 49 deletions(-) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index eaf7f6992a2f..b7c9e44ef180 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -48,61 +48,33 @@ static struct vio_dev vio_bus_device = { /* fake "parent" device */ .dev.bus = &vio_bus_type, }; -#ifdef CONFIG_PPC_ISERIES -static struct iommu_table veth_iommu_table; -struct iommu_table vio_iommu_table; - -static void __init iommu_vio_init(void) -{ - iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); - veth_iommu_table.it_size /= 2; - vio_iommu_table = veth_iommu_table; - vio_iommu_table.it_offset += veth_iommu_table.it_size; - - if (!iommu_init_table(&veth_iommu_table, -1)) - printk("Virtual Bus VETH TCE table failed.\n"); - if (!iommu_init_table(&vio_iommu_table, -1)) - printk("Virtual Bus VIO TCE table failed.\n"); -} -#else -static void __init iommu_vio_init(void) -{ -} -#endif - static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) { -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES)) { - if (strcmp(dev->type, "network") == 0) - return &veth_iommu_table; - return &vio_iommu_table; - } else -#endif - { - const unsigned char *dma_window; - struct iommu_table *tbl; - unsigned long offset, size; + const unsigned char *dma_window; + struct iommu_table *tbl; + unsigned long offset, size; - dma_window = of_get_property(dev->dev.archdata.of_node, - "ibm,my-dma-window", NULL); - if (!dma_window) - return NULL; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return vio_build_iommu_table_iseries(dev); - tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); + dma_window = of_get_property(dev->dev.archdata.of_node, + "ibm,my-dma-window", NULL); + if (!dma_window) + return NULL; - of_parse_dma_window(dev->dev.archdata.of_node, dma_window, - &tbl->it_index, &offset, &size); + tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); - /* TCE table size - measured in tce entries */ - tbl->it_size = size >> IOMMU_PAGE_SHIFT; - /* offset for VIO should always be 0 */ - tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; - tbl->it_busno = 0; - tbl->it_type = TCE_VB; + of_parse_dma_window(dev->dev.archdata.of_node, dma_window, + &tbl->it_index, &offset, &size); - return iommu_init_table(tbl, -1); - } + /* TCE table size - measured in tce entries */ + tbl->it_size = size >> IOMMU_PAGE_SHIFT; + /* offset for VIO should always be 0 */ + tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; + tbl->it_busno = 0; + tbl->it_type = TCE_VB; + + return iommu_init_table(tbl, -1); } /** diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 3281f10bbd16..49e9c664ea89 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -191,7 +192,8 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn) } #endif -extern struct iommu_table vio_iommu_table; +static struct iommu_table veth_iommu_table; +static struct iommu_table vio_iommu_table; void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) { @@ -219,6 +221,26 @@ void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction); } +void __init iommu_vio_init(void) +{ + iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); + veth_iommu_table.it_size /= 2; + vio_iommu_table = veth_iommu_table; + vio_iommu_table.it_offset += veth_iommu_table.it_size; + + if (!iommu_init_table(&veth_iommu_table, -1)) + printk("Virtual Bus VETH TCE table failed.\n"); + if (!iommu_init_table(&vio_iommu_table, -1)) + printk("Virtual Bus VIO TCE table failed.\n"); +} + +struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev) +{ + if (strcmp(dev->type, "network") == 0) + return &veth_iommu_table; + return &vio_iommu_table; +} + void iommu_init_early_iSeries(void) { ppc_md.tce_build = tce_build_iSeries; diff --git a/include/asm-powerpc/iseries/iommu.h b/include/asm-powerpc/iseries/iommu.h index 6e323a13ac30..c59ee7e4bed1 100644 --- a/include/asm-powerpc/iseries/iommu.h +++ b/include/asm-powerpc/iseries/iommu.h @@ -22,6 +22,7 @@ */ struct pci_dev; +struct vio_dev; struct device_node; struct iommu_table; @@ -34,4 +35,7 @@ extern void iommu_table_getparms_iSeries(unsigned long busno, unsigned char slotno, unsigned char virtbus, struct iommu_table *tbl); +extern struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev); +extern void iommu_vio_init(void); + #endif /* _ASM_POWERPC_ISERIES_IOMMU_H */ From b833b481c10cf591b15cc674948cc514e55d3b94 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:57:26 +1000 Subject: [PATCH 2138/2804] [POWERPC] iSeries: Move detection of virtual cdroms Now we will only have entries in the device tree for the actual existing devices (including their OS/400 properties). This way viocd.c gets all the information about the devices from the device tree. Signed-off-by: Stephen Rothwell Acked-by: Jens Axboe Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 3 - arch/powerpc/platforms/iseries/Makefile | 2 +- arch/powerpc/platforms/iseries/dt.c | 4 - arch/powerpc/platforms/iseries/vio.c | 317 ++++++++++++++++++++++++ drivers/cdrom/viocd.c | 116 ++------- include/asm-powerpc/iseries/vio.h | 24 ++ 6 files changed, 361 insertions(+), 105 deletions(-) create mode 100644 arch/powerpc/platforms/iseries/vio.c diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index b7c9e44ef180..cb22a3557c4e 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -247,9 +247,6 @@ static int __init vio_bus_init(void) int err; struct device_node *node_vroot; - if (firmware_has_feature(FW_FEATURE_ISERIES)) - iommu_vio_init(); - err = bus_register(&vio_bus_type); if (err) { printk(KERN_ERR "failed to register VIO bus\n"); diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 60db509638f1..a65f1b44abf8 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -7,7 +7,7 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o misc.o irq.o obj-$(CONFIG_PCI) += pci.o vpdinfo.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_VIOPATH) += viopath.o +obj-$(CONFIG_VIOPATH) += viopath.o vio.o obj-$(CONFIG_MODULES) += ksyms.o quiet_cmd_dt_strings = DT_STR $@ diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 9e8a334a518a..84fcee15eb25 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -381,10 +381,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, "IBM,iSeries-viodasd", 1); reg += HVMAXARCHITECTEDVIRTUALDISKS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) - dt_do_vdevice(dt, "viocd", reg, i, device_type_block, - "IBM,iSeries-viocd", 1); reg += HVMAXARCHITECTEDVIRTUALCDROMS; for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c new file mode 100644 index 000000000000..f61a97441c3d --- /dev/null +++ b/arch/powerpc/platforms/iseries/vio.c @@ -0,0 +1,317 @@ +/* + * Legacy iSeries specific vio initialisation + * that needs to be built in (not a module). + * + * ร‚ยฉ Copyright 2007 IBM Corporation + * Author: Stephen Rothwell + * Some parts collected from various other files + * + * 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 + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define FIRST_VTY 0 +#define NUM_VTYS 1 +#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS) +#define NUM_VSCSIS 1 +#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS) +#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS +#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS) +#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS +#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS) +#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS +#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) +#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES + +static struct property * __init new_property(const char *name, int length, + const void *value) +{ + struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, + GFP_KERNEL); + + if (!np) + return NULL; + np->name = (char *)(np + 1); + np->value = np->name + strlen(name) + 1; + strcpy(np->name, name); + memcpy(np->value, value, length); + np->length = length; + return np; +} + +static void __init free_property(struct property *np) +{ + kfree(np); +} + +static struct device_node * __init new_node(const char *path, + struct device_node *parent) +{ + struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); + + if (!np) + return NULL; + np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL); + if (!np->full_name) { + kfree(np); + return NULL; + } + strcpy(np->full_name, path); + of_node_set_flag(np, OF_DYNAMIC); + kref_init(&np->kref); + np->parent = of_node_get(parent); + return np; +} + +static void __init free_node(struct device_node *np) +{ + struct property *next; + struct property *prop; + + next = np->properties; + while (next) { + prop = next; + next = prop->next; + free_property(prop); + } + of_node_put(np->parent); + kfree(np->full_name); + kfree(np); +} + +static int __init add_string_property(struct device_node *np, const char *name, + const char *value) +{ + struct property *nprop = new_property(name, strlen(value) + 1, value); + + if (!nprop) + return 0; + prom_add_property(np, nprop); + return 1; +} + +static int __init add_raw_property(struct device_node *np, const char *name, + int length, const void *value) +{ + struct property *nprop = new_property(name, length, value); + + if (!nprop) + return 0; + prom_add_property(np, nprop); + return 1; +} + +struct viocd_waitevent { + struct completion com; + int rc; + u16 sub_result; +}; + +struct cdrom_info { + char rsrcname[10]; + char type[4]; + char model[3]; +}; + +static void __init handle_cd_event(struct HvLpEvent *event) +{ + struct viocdlpevent *bevent; + struct viocd_waitevent *pwe; + + if (!event) + /* Notification that a partition went away! */ + return; + + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + bevent = (struct viocdlpevent *)event; + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viocdgetinfo: + pwe = (struct viocd_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + + default: + printk(KERN_WARNING "handle_cd_event: " + "message with unexpected subtype %0x04X!\n", + event->xSubtype & VIOMINOR_SUBTYPE_MASK); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static void __init get_viocd_info(struct device_node *vio_root) +{ + HvLpEvent_Rc hvrc; + u32 unit; + struct viocd_waitevent we; + struct cdrom_info *unitinfo; + dma_addr_t unitinfo_dmaaddr; + int ret; + + ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2); + if (ret) { + printk(KERN_WARNING + "get_viocd_info: error opening path to host partition %d\n", + viopath_hostLp); + return; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_cdio, handle_cd_event); + + unitinfo = iseries_hv_alloc( + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, + &unitinfo_dmaaddr, GFP_ATOMIC); + if (!unitinfo) { + printk(KERN_WARNING + "get_viocd_info: error allocating unitinfo\n"); + goto clear_handler; + } + + memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS); + + init_completion(&we.com); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdgetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING + "get_viocd_info: cdrom error sending event. rc %d\n", + (int)hvrc); + goto hv_free; + } + + wait_for_completion(&we.com); + + if (we.rc) { + printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n", + we.rc, we.sub_result); + goto hv_free; + } + + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && + unitinfo[unit].rsrcname[0]; unit++) { + struct device_node *np; + char name[64]; + u32 reg = FIRST_VIOCD + unit; + + snprintf(name, sizeof(name), "/vdevice/viocd@%08x", reg); + np = new_node(name, vio_root); + if (!np) + goto hv_free; + if (!add_string_property(np, "name", "viocd") || + !add_string_property(np, "device_type", "block") || + !add_string_property(np, "compatible", + "IBM,iSeries-viocd") || + !add_raw_property(np, "reg", sizeof(reg), ®) || + !add_raw_property(np, "linux,unit_address", + sizeof(unit), &unit) || + !add_raw_property(np, "linux,vio_rsrcname", + sizeof(unitinfo[unit].rsrcname), + unitinfo[unit].rsrcname) || + !add_raw_property(np, "linux,vio_type", + sizeof(unitinfo[unit].type), + unitinfo[unit].type) || + !add_raw_property(np, "linux,vio_model", + sizeof(unitinfo[unit].model), + unitinfo[unit].model)) + goto node_free; + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + of_attach_node(np); +#ifdef CONFIG_PROC_DEVICETREE + if (vio_root->pde) { + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(np->full_name, '/') + 1, + vio_root->pde); + if (ent) + proc_device_tree_add_node(np, ent); + } +#endif + continue; + + node_free: + free_node(np); + break; + } + + hv_free: + iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, + unitinfo, unitinfo_dmaaddr); + clear_handler: + vio_clearHandler(viomajorsubtype_cdio); + viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); +} + +static int __init iseries_vio_init(void) +{ + struct device_node *vio_root; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + + iommu_vio_init(); + + vio_root = of_find_node_by_path("/vdevice"); + if (!vio_root) + return -ENODEV; + + if (viopath_hostLp == HvLpIndexInvalid) { + vio_set_hostlp(); + /* If we don't have a host, bail out */ + if (viopath_hostLp == HvLpIndexInvalid) + goto put_node; + } + + get_viocd_info(vio_root); + + return 0; + + put_node: + of_node_put(vio_root); + return -ENODEV; +} +arch_initcall(iseries_vio_init); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index c081e5400ce0..880b5dce3a62 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -56,30 +56,6 @@ #define VIOCD_KERN_WARNING KERN_WARNING "viocd: " #define VIOCD_KERN_INFO KERN_INFO "viocd: " -struct viocdlpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_result; - u16 disk; - u16 flags; - u32 token; - u64 offset; /* On open, max number of disks */ - u64 len; /* On open, size of the disk */ - u32 block_size; /* Only set on open */ - u32 media_size; /* Only set on open */ -}; - -enum viocdsubtype { - viocdopen = 0x0001, - viocdclose = 0x0002, - viocdread = 0x0003, - viocdwrite = 0x0004, - viocdlockdoor = 0x0005, - viocdgetinfo = 0x0006, - viocdcheck = 0x0007 -}; - /* * Should probably make this a module parameter....sigh */ @@ -131,17 +107,13 @@ static struct capability_entry capability_table[] __initdata = { /* These are our internal structures for keeping track of devices */ static int viocd_numdev; -struct cdrom_info { - char rsrcname[10]; - char type[4]; - char model[3]; -}; - struct disk_info { struct gendisk *viocd_disk; struct cdrom_device_info viocd_info; struct device *dev; - struct cdrom_info unitinfo; + const char *rsrcname; + const char *type; + const char *model; }; static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; @@ -159,9 +131,9 @@ static int proc_viocd_show(struct seq_file *m, void *v) for (i = 0; i < viocd_numdev; i++) { seq_printf(m, "viocd device %d is iSeries resource %10.10s" "type %4.4s, model %3.3s\n", - i, viocd_diskinfo[i].unitinfo.rsrcname, - viocd_diskinfo[i].unitinfo.type, - viocd_diskinfo[i].unitinfo.model); + i, viocd_diskinfo[i].rsrcname, + viocd_diskinfo[i].type, + viocd_diskinfo[i].model); } return 0; } @@ -211,61 +183,6 @@ struct block_device_operations viocd_fops = { .media_changed = viocd_blk_media_changed, }; -/* Get info on CD devices from OS/400 */ -static void __init get_viocd_info(void) -{ - HvLpEvent_Rc hvrc; - int i; - struct viocd_waitevent we; - struct cdrom_info *viocd_unitinfo; - dma_addr_t unitinfo_dmaaddr; - - viocd_unitinfo = iseries_hv_alloc( - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - &unitinfo_dmaaddr, GFP_ATOMIC); - if (viocd_unitinfo == NULL) { - printk(VIOCD_KERN_WARNING "error allocating unitinfo\n"); - return; - } - - memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD); - - init_completion(&we.com); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_cdio | viocdgetinfo, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0); - if (hvrc != HvLpEvent_Rc_Good) { - printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n", - (int)hvrc); - goto error_ret; - } - - wait_for_completion(&we.com); - - if (we.rc) { - const struct vio_error_entry *err = - vio_lookup_rc(viocd_err_table, we.sub_result); - printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n", - we.rc, we.sub_result, err->msg); - goto error_ret; - } - - for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) { - viocd_diskinfo[viocd_numdev].unitinfo = viocd_unitinfo[i]; - viocd_numdev++; - } - -error_ret: - iseries_hv_free(sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); -} - static int viocd_open(struct cdrom_device_info *cdi, int purpose) { struct disk_info *diskinfo = cdi->handle; @@ -576,7 +493,6 @@ static void vio_handle_cd_event(struct HvLpEvent *event) bevent->block_size / 512); } /* FALLTHROUGH !! */ - case viocdgetinfo: case viocdlockdoor: pwe = (struct viocd_waitevent *)event->xCorrelationToken; return_complete: @@ -660,22 +576,30 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) int deviceno; struct disk_info *d; struct cdrom_device_info *c; - struct cdrom_info *ci; struct request_queue *q; + struct device_node *node = vdev->dev.archdata.of_node; deviceno = vdev->unit_address; - if (deviceno >= viocd_numdev) + if (deviceno > VIOCD_MAX_CD) + return -ENODEV; + if (!node) return -ENODEV; + if (deviceno >= viocd_numdev) + viocd_numdev = deviceno + 1; + d = &viocd_diskinfo[deviceno]; + d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL); + d->type = of_get_property(node, "linux,vio_type", NULL); + d->model = of_get_property(node, "linux,vio_model", NULL); + c = &d->viocd_info; - ci = &d->unitinfo; c->ops = &viocd_dops; c->speed = 4; c->capacity = 1; c->handle = d; - c->mask = ~find_capability(ci->type); + c->mask = ~find_capability(d->type); sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); if (register_cdrom(c) != 0) { @@ -685,7 +609,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) } printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " "type %4.4s, model %3.3s\n", - c->name, ci->rsrcname, ci->type, ci->model); + c->name, d->rsrcname, d->type, d->model); q = blk_init_queue(do_viocd_request, &viocd_reqlock); if (q == NULL) { printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n", @@ -794,8 +718,6 @@ static int __init viocd_init(void) /* Initialize our request handler */ vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); - get_viocd_info(); - spin_lock_init(&viocd_reqlock); ret = vio_register_driver(&viocd_driver); diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index 5a5cd0f0c095..e5a405b8d461 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h @@ -51,6 +51,30 @@ */ #define VIO_MAX_SUBTYPES 8 +struct viocdlpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_result; + u16 disk; + u16 flags; + u32 token; + u64 offset; /* On open, max number of disks */ + u64 len; /* On open, size of the disk */ + u32 block_size; /* Only set on open */ + u32 media_size; /* Only set on open */ +}; + +enum viocdsubtype { + viocdopen = 0x0001, + viocdclose = 0x0002, + viocdread = 0x0003, + viocdwrite = 0x0004, + viocdlockdoor = 0x0005, + viocdgetinfo = 0x0006, + viocdcheck = 0x0007 +}; + /* * Each subtype can register a handler to process their events. * The handler must have this interface. From 7465ce0db310d2fa29f721da7e3aacd1dad7090f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:58:31 +1000 Subject: [PATCH 2139/2804] [POWERPC] iSeries: Move detection of virtual tapes Now we will only have entries in the device tree for the actual existing devices (including their OS/400 properties). This way viotape.c gets all the information about the devices from the device tree. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/dt.c | 7 -- arch/powerpc/platforms/iseries/vio.c | 149 ++++++++++++++++++++++++--- drivers/char/viotape.c | 124 ++++------------------ include/asm-powerpc/iseries/vio.h | 41 ++++++++ 4 files changed, 192 insertions(+), 129 deletions(-) diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 84fcee15eb25..2e4ad6b34506 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -73,7 +73,6 @@ static char __initdata device_type_memory[] = "memory"; static char __initdata device_type_serial[] = "serial"; static char __initdata device_type_network[] = "network"; static char __initdata device_type_block[] = "block"; -static char __initdata device_type_byte[] = "byte"; static char __initdata device_type_pci[] = "pci"; static char __initdata device_type_vdevice[] = "vdevice"; static char __initdata device_type_vscsi[] = "vscsi"; @@ -380,12 +379,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, "IBM,iSeries-viodasd", 1); - reg += HVMAXARCHITECTEDVIRTUALDISKS; - reg += HVMAXARCHITECTEDVIRTUALCDROMS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) - dt_do_vdevice(dt, "viotape", reg, i, device_type_byte, - "IBM,iSeries-viotape", 1); dt_end_node(dt); } diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index f61a97441c3d..a4cc990a26a0 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c @@ -45,6 +45,18 @@ #define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) #define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES +struct vio_waitevent { + struct completion com; + int rc; + u16 sub_result; +}; + +struct vio_resource { + char rsrcname[10]; + char type[4]; + char model[3]; +}; + static struct property * __init new_property(const char *name, int length, const void *value) { @@ -123,22 +135,10 @@ static int __init add_raw_property(struct device_node *np, const char *name, return 1; } -struct viocd_waitevent { - struct completion com; - int rc; - u16 sub_result; -}; - -struct cdrom_info { - char rsrcname[10]; - char type[4]; - char model[3]; -}; - static void __init handle_cd_event(struct HvLpEvent *event) { struct viocdlpevent *bevent; - struct viocd_waitevent *pwe; + struct vio_waitevent *pwe; if (!event) /* Notification that a partition went away! */ @@ -158,7 +158,7 @@ static void __init handle_cd_event(struct HvLpEvent *event) switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { case viocdgetinfo: - pwe = (struct viocd_waitevent *)event->xCorrelationToken; + pwe = (struct vio_waitevent *)event->xCorrelationToken; pwe->rc = event->xRc; pwe->sub_result = bevent->sub_result; complete(&pwe->com); @@ -179,8 +179,8 @@ static void __init get_viocd_info(struct device_node *vio_root) { HvLpEvent_Rc hvrc; u32 unit; - struct viocd_waitevent we; - struct cdrom_info *unitinfo; + struct vio_waitevent we; + struct vio_resource *unitinfo; dma_addr_t unitinfo_dmaaddr; int ret; @@ -286,6 +286,122 @@ static void __init get_viocd_info(struct device_node *vio_root) viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); } +/* Handle interrupt events for tape */ +static void __init handle_tape_event(struct HvLpEvent *event) +{ + struct vio_waitevent *we; + struct viotapelpevent *tevent = (struct viotapelpevent *)event; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + + we = (struct vio_waitevent *)event->xCorrelationToken; + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viotapegetinfo: + we->rc = tevent->sub_type_result; + complete(&we->com); + break; + default: + printk(KERN_WARNING "handle_tape_event: weird ack\n"); + } +} + +static void __init get_viotape_info(struct device_node *vio_root) +{ + HvLpEvent_Rc hvrc; + u32 unit; + struct vio_resource *unitinfo; + dma_addr_t unitinfo_dmaaddr; + size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES; + struct vio_waitevent we; + int ret; + + ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); + if (ret) { + printk(KERN_WARNING "get_viotape_info: " + "error on viopath_open to hostlp %d\n", ret); + return; + } + + vio_setHandler(viomajorsubtype_tape, handle_tape_event); + + unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC); + if (!unitinfo) + goto clear_handler; + + memset(unitinfo, 0, len); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapegetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + unitinfo_dmaaddr, len, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING "get_viotape_info: hv error on op %d\n", + (int)hvrc); + goto hv_free; + } + + wait_for_completion(&we.com); + + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && + unitinfo[unit].rsrcname[0]; unit++) { + struct device_node *np; + char name[64]; + u32 reg = FIRST_VIOTAPE + unit; + + snprintf(name, sizeof(name), "/vdevice/viotape@%08x", reg); + np = new_node(name, vio_root); + if (!np) + goto hv_free; + if (!add_string_property(np, "name", "viotape") || + !add_string_property(np, "device_type", "byte") || + !add_string_property(np, "compatible", + "IBM,iSeries-viotape") || + !add_raw_property(np, "reg", sizeof(reg), ®) || + !add_raw_property(np, "linux,unit_address", + sizeof(unit), &unit) || + !add_raw_property(np, "linux,vio_rsrcname", + sizeof(unitinfo[unit].rsrcname), + unitinfo[unit].rsrcname) || + !add_raw_property(np, "linux,vio_type", + sizeof(unitinfo[unit].type), + unitinfo[unit].type) || + !add_raw_property(np, "linux,vio_model", + sizeof(unitinfo[unit].model), + unitinfo[unit].model)) + goto node_free; + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + of_attach_node(np); +#ifdef CONFIG_PROC_DEVICETREE + if (vio_root->pde) { + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(np->full_name, '/') + 1, + vio_root->pde); + if (ent) + proc_device_tree_add_node(np, ent); + } +#endif + continue; + + node_free: + free_node(np); + break; + } + + hv_free: + iseries_hv_free(len, unitinfo, unitinfo_dmaaddr); + clear_handler: + vio_clearHandler(viomajorsubtype_tape); + viopath_close(viopath_hostLp, viomajorsubtype_tape, 2); +} + static int __init iseries_vio_init(void) { struct device_node *vio_root; @@ -307,6 +423,7 @@ static int __init iseries_vio_init(void) } get_viocd_info(vio_root); + get_viotape_info(vio_root); return 0; diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 064c09195215..f1d60f0cef8f 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -92,47 +92,6 @@ struct viot_devinfo_struct { #define VIOTAPOP_SETPART 14 #define VIOTAPOP_UNLOAD 15 -struct viotapelpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_type_result; - u16 tape; - u16 flags; - u32 token; - u64 len; - union { - struct { - u32 tape_op; - u32 count; - } op; - struct { - u32 type; - u32 resid; - u32 dsreg; - u32 gstat; - u32 erreg; - u32 file_no; - u32 block_no; - } get_status; - struct { - u32 block_no; - } get_pos; - } u; -}; - -enum viotapesubtype { - viotapeopen = 0x0001, - viotapeclose = 0x0002, - viotaperead = 0x0003, - viotapewrite = 0x0004, - viotapegetinfo = 0x0005, - viotapeop = 0x0006, - viotapegetpos = 0x0007, - viotapesetpos = 0x0008, - viotapegetstatus = 0x0009 -}; - enum viotaperc { viotape_InvalidRange = 0x0601, viotape_InvalidToken = 0x0602, @@ -223,14 +182,11 @@ static const struct vio_error_entry viotape_err_table[] = { #define VIOT_WRITING 2 /* Our info on the tapes */ -struct tape_descr { - char rsrcname[10]; - char type[4]; - char model[3]; -}; - -static struct tape_descr *viotape_unitinfo; -static dma_addr_t viotape_unitinfo_token; +static struct { + const char *rsrcname; + const char *type; + const char *model; +} viotape_unitinfo[VIOTAPE_MAX_TAPE]; static struct mtget viomtget[VIOTAPE_MAX_TAPE]; @@ -381,53 +337,6 @@ int tape_rc_to_errno(int tape_rc, char *operation, int tapeno) return -err->errno; } -/* Get info on all tapes from OS/400 */ -static int get_viotape_info(void) -{ - HvLpEvent_Rc hvrc; - int i; - size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE; - struct op_struct *op = get_op_struct(); - - if (op == NULL) - return -ENOMEM; - - viotape_unitinfo = iseries_hv_alloc(len, &viotape_unitinfo_token, - GFP_ATOMIC); - if (viotape_unitinfo == NULL) { - free_op_struct(op); - return -ENOMEM; - } - - memset(viotape_unitinfo, 0, len); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_tape | viotapegetinfo, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64) (unsigned long) op, VIOVERSION << 16, - viotape_unitinfo_token, len, 0, 0); - if (hvrc != HvLpEvent_Rc_Good) { - printk(VIOTAPE_KERN_WARN "hv error on op %d\n", - (int)hvrc); - free_op_struct(op); - return -EIO; - } - - wait_for_completion(&op->com); - - free_op_struct(op); - - for (i = 0; - ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0])); - i++) - viotape_numdev++; - return 0; -} - - /* Write */ static ssize_t viotap_write(struct file *file, const char *buf, size_t count, loff_t * ppos) @@ -899,7 +808,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event) tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; op = (struct op_struct *)event->xCorrelationToken; switch (tapeminor) { - case viotapegetinfo: case viotapeopen: case viotapeclose: op->rc = tevent->sub_type_result; @@ -942,11 +850,23 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) { int i = vdev->unit_address; int j; + struct device_node *node = vdev->dev.archdata.of_node; - if (i >= viotape_numdev) + if (i > VIOTAPE_MAX_TAPE) + return -ENODEV; + if (!node) return -ENODEV; + if (i >= viotape_numdev) + viotape_numdev = i + 1; + tape_device[i] = &vdev->dev; + viotape_unitinfo[i].rsrcname = of_get_property(node, + "linux,vio_rsrcname", NULL); + viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type", + NULL); + viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model", + NULL); state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) @@ -1044,11 +964,6 @@ int __init viotap_init(void) goto unreg_chrdev; } - if ((ret = get_viotape_info()) < 0) { - printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information"); - goto unreg_class; - } - ret = vio_register_driver(&viotape_driver); if (ret) goto unreg_class; @@ -1102,9 +1017,6 @@ static void __exit viotap_exit(void) vio_unregister_driver(&viotape_driver); class_destroy(tape_class); unregister_chrdev(VIOTAPE_MAJOR, "viotape"); - if (viotape_unitinfo) - iseries_hv_free(sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, - viotape_unitinfo, viotape_unitinfo_token); viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); vio_clearHandler(viomajorsubtype_tape); clear_op_struct_pool(); diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index e5a405b8d461..2555dfd6fac6 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h @@ -75,6 +75,47 @@ enum viocdsubtype { viocdcheck = 0x0007 }; +struct viotapelpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_type_result; + u16 tape; + u16 flags; + u32 token; + u64 len; + union { + struct { + u32 tape_op; + u32 count; + } op; + struct { + u32 type; + u32 resid; + u32 dsreg; + u32 gstat; + u32 erreg; + u32 file_no; + u32 block_no; + } get_status; + struct { + u32 block_no; + } get_pos; + } u; +}; + +enum viotapesubtype { + viotapeopen = 0x0001, + viotapeclose = 0x0002, + viotaperead = 0x0003, + viotapewrite = 0x0004, + viotapegetinfo = 0x0005, + viotapeop = 0x0006, + viotapegetpos = 0x0007, + viotapesetpos = 0x0008, + viotapegetstatus = 0x0009 +}; + /* * Each subtype can register a handler to process their events. * The handler must have this interface. From 8251b4c481bca72568e9c1042ea11189838e5f6d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:59:54 +1000 Subject: [PATCH 2140/2804] [POWERPC] iSeries: Move viodasd probing This way we only have entries in the device tree for disks that actually exist. A slight complication is that disks may be attached to LPARs at runtime. Signed-off-by: Stephen Rothwell Acked-by: Jens Axboe Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/dt.c | 6 - arch/powerpc/platforms/iseries/vio.c | 301 +++++++++++++++++++-------- drivers/block/viodasd.c | 77 +++---- include/asm-powerpc/iseries/vio.h | 47 +++++ 4 files changed, 282 insertions(+), 149 deletions(-) diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 2e4ad6b34506..4543c4bc3a56 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -72,7 +72,6 @@ static char __initdata device_type_cpu[] = "cpu"; static char __initdata device_type_memory[] = "memory"; static char __initdata device_type_serial[] = "serial"; static char __initdata device_type_network[] = "network"; -static char __initdata device_type_block[] = "block"; static char __initdata device_type_pci[] = "pci"; static char __initdata device_type_vdevice[] = "vdevice"; static char __initdata device_type_vscsi[] = "vscsi"; @@ -374,11 +373,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) dt_end_node(dt); } - reg += HVMAXARCHITECTEDVIRTUALLANS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) - dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, - "IBM,iSeries-viodasd", 1); dt_end_node(dt); } diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index a4cc990a26a0..910b00b4703e 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c @@ -25,8 +25,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -57,7 +59,7 @@ struct vio_resource { char model[3]; }; -static struct property * __init new_property(const char *name, int length, +static struct property *new_property(const char *name, int length, const void *value) { struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, @@ -78,7 +80,7 @@ static void __init free_property(struct property *np) kfree(np); } -static struct device_node * __init new_node(const char *path, +static struct device_node *new_node(const char *path, struct device_node *parent) { struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); @@ -97,7 +99,7 @@ static struct device_node * __init new_node(const char *path, return np; } -static void __init free_node(struct device_node *np) +static void free_node(struct device_node *np) { struct property *next; struct property *prop; @@ -113,7 +115,7 @@ static void __init free_node(struct device_node *np) kfree(np); } -static int __init add_string_property(struct device_node *np, const char *name, +static int add_string_property(struct device_node *np, const char *name, const char *value) { struct property *nprop = new_property(name, strlen(value) + 1, value); @@ -124,7 +126,7 @@ static int __init add_string_property(struct device_node *np, const char *name, return 1; } -static int __init add_raw_property(struct device_node *np, const char *name, +static int add_raw_property(struct device_node *np, const char *name, int length, const void *value) { struct property *nprop = new_property(name, length, value); @@ -135,6 +137,201 @@ static int __init add_raw_property(struct device_node *np, const char *name, return 1; } +static struct device_node *do_device_node(struct device_node *parent, + const char *name, u32 reg, u32 unit, const char *type, + const char *compat, struct vio_resource *res) +{ + struct device_node *np; + char path[32]; + + snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg); + np = new_node(path, parent); + if (!np) + return NULL; + if (!add_string_property(np, "name", name) || + !add_string_property(np, "device_type", type) || + !add_string_property(np, "compatible", compat) || + !add_raw_property(np, "reg", sizeof(reg), ®) || + !add_raw_property(np, "linux,unit_address", + sizeof(unit), &unit)) { + goto node_free; + } + if (res) { + if (!add_raw_property(np, "linux,vio_rsrcname", + sizeof(res->rsrcname), res->rsrcname) || + !add_raw_property(np, "linux,vio_type", + sizeof(res->type), res->type) || + !add_raw_property(np, "linux,vio_model", + sizeof(res->model), res->model)) + goto node_free; + } + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + of_attach_node(np); +#ifdef CONFIG_PROC_DEVICETREE + if (parent->pde) { + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde); + if (ent) + proc_device_tree_add_node(np, ent); + } +#endif + return np; + + node_free: + free_node(np); + return NULL; +} + +/* + * This is here so that we can dynamically add viodasd + * devices without exposing all the above infrastructure. + */ +struct vio_dev *vio_create_viodasd(u32 unit) +{ + struct device_node *vio_root; + struct device_node *np; + struct vio_dev *vdev = NULL; + + vio_root = of_find_node_by_path("/vdevice"); + if (!vio_root) + return NULL; + np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, + "block", "IBM,iSeries-viodasd", NULL); + of_node_put(vio_root); + if (np) { + vdev = vio_register_device_node(np); + if (!vdev) + free_node(np); + } + return vdev; +} +EXPORT_SYMBOL_GPL(vio_create_viodasd); + +static void __init handle_block_event(struct HvLpEvent *event) +{ + struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; + struct vio_waitevent *pwe; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + printk(KERN_WARNING "handle_viod_request: " + "Yikes! got an int in viodasd event handler!\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case vioblockopen: + /* + * Handle a response to an open request. We get all the + * disk information in the response, so update it. The + * correlation token contains a pointer to a waitevent + * structure that has a completion in it. update the + * return code in the waitevent structure and post the + * completion to wake up the guy who sent the request + */ + pwe = (struct vio_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + case vioblockclose: + break; + default: + printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static void __init probe_disk(struct device_node *vio_root, u32 unit) +{ + HvLpEvent_Rc hvrc; + struct vio_waitevent we; + u16 flags = 0; + +retry: + init_completion(&we.com); + + /* Send the open event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + ((u64)unit << 48) | ((u64)flags<< 32), + 0, 0, 0); + if (hvrc != 0) { + printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n", + (int)hvrc); + return; + } + + wait_for_completion(&we.com); + + if (we.rc != 0) { + if (flags != 0) + return; + /* try again with read only flag set */ + flags = vioblockflags_ro; + goto retry; + } + + /* Send the close event to OS/400. We DON'T expect a response */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockclose, + HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, VIOVERSION << 16, + ((u64)unit << 48) | ((u64)flags << 32), + 0, 0, 0); + if (hvrc != 0) { + printk(KERN_WARNING "probe_disk: " + "bad rc sending event to OS/400 %d\n", (int)hvrc); + return; + } + + do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, + "block", "IBM,iSeries-viodasd", NULL); +} + +static void __init get_viodasd_info(struct device_node *vio_root) +{ + int rc; + u32 unit; + + rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2); + if (rc) { + printk(KERN_WARNING "get_viodasd_info: " + "error opening path to host partition %d\n", + viopath_hostLp); + return; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_blockio, handle_block_event); + + for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++) + probe_disk(vio_root, unit); + + vio_clearHandler(viomajorsubtype_blockio); + viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2); +} + static void __init handle_cd_event(struct HvLpEvent *event) { struct viocdlpevent *bevent; @@ -233,49 +430,9 @@ static void __init get_viocd_info(struct device_node *vio_root) for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && unitinfo[unit].rsrcname[0]; unit++) { - struct device_node *np; - char name[64]; - u32 reg = FIRST_VIOCD + unit; - - snprintf(name, sizeof(name), "/vdevice/viocd@%08x", reg); - np = new_node(name, vio_root); - if (!np) - goto hv_free; - if (!add_string_property(np, "name", "viocd") || - !add_string_property(np, "device_type", "block") || - !add_string_property(np, "compatible", - "IBM,iSeries-viocd") || - !add_raw_property(np, "reg", sizeof(reg), ®) || - !add_raw_property(np, "linux,unit_address", - sizeof(unit), &unit) || - !add_raw_property(np, "linux,vio_rsrcname", - sizeof(unitinfo[unit].rsrcname), - unitinfo[unit].rsrcname) || - !add_raw_property(np, "linux,vio_type", - sizeof(unitinfo[unit].type), - unitinfo[unit].type) || - !add_raw_property(np, "linux,vio_model", - sizeof(unitinfo[unit].model), - unitinfo[unit].model)) - goto node_free; - np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); - of_attach_node(np); -#ifdef CONFIG_PROC_DEVICETREE - if (vio_root->pde) { - struct proc_dir_entry *ent; - - ent = proc_mkdir(strrchr(np->full_name, '/') + 1, - vio_root->pde); - if (ent) - proc_device_tree_add_node(np, ent); - } -#endif - continue; - - node_free: - free_node(np); - break; + if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit, + "block", "IBM,iSeries-viocd", &unitinfo[unit])) + break; } hv_free: @@ -350,49 +507,10 @@ static void __init get_viotape_info(struct device_node *vio_root) for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && unitinfo[unit].rsrcname[0]; unit++) { - struct device_node *np; - char name[64]; - u32 reg = FIRST_VIOTAPE + unit; - - snprintf(name, sizeof(name), "/vdevice/viotape@%08x", reg); - np = new_node(name, vio_root); - if (!np) - goto hv_free; - if (!add_string_property(np, "name", "viotape") || - !add_string_property(np, "device_type", "byte") || - !add_string_property(np, "compatible", - "IBM,iSeries-viotape") || - !add_raw_property(np, "reg", sizeof(reg), ®) || - !add_raw_property(np, "linux,unit_address", - sizeof(unit), &unit) || - !add_raw_property(np, "linux,vio_rsrcname", - sizeof(unitinfo[unit].rsrcname), - unitinfo[unit].rsrcname) || - !add_raw_property(np, "linux,vio_type", - sizeof(unitinfo[unit].type), - unitinfo[unit].type) || - !add_raw_property(np, "linux,vio_model", - sizeof(unitinfo[unit].model), - unitinfo[unit].model)) - goto node_free; - np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); - of_attach_node(np); -#ifdef CONFIG_PROC_DEVICETREE - if (vio_root->pde) { - struct proc_dir_entry *ent; - - ent = proc_mkdir(strrchr(np->full_name, '/') + 1, - vio_root->pde); - if (ent) - proc_device_tree_add_node(np, ent); - } -#endif - continue; - - node_free: - free_node(np); - break; + if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit, + unit, "byte", "IBM,iSeries-viotape", + &unitinfo[unit])) + break; } hv_free: @@ -422,6 +540,7 @@ static int __init iseries_vio_init(void) goto put_node; } + get_viodasd_info(vio_root); get_viocd_info(vio_root); get_viotape_info(vio_root); diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index af3969a9c963..e824b672e05a 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -74,53 +74,9 @@ enum { static DEFINE_SPINLOCK(viodasd_spinlock); #define VIOMAXREQ 16 -#define VIOMAXBLOCKDMA 12 #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0]) -struct open_data { - u64 disk_size; - u16 max_disk; - u16 cylinders; - u16 tracks; - u16 sectors; - u16 bytes_per_sector; -}; - -struct rw_data { - u64 offset; - struct { - u32 token; - u32 reserved; - u64 len; - } dma_info[VIOMAXBLOCKDMA]; -}; - -struct vioblocklpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_result; - u16 disk; - u16 flags; - union { - struct open_data open_data; - struct rw_data rw_data; - u64 changed; - } u; -}; - -#define vioblockflags_ro 0x0001 - -enum vioblocksubtype { - vioblockopen = 0x0001, - vioblockclose = 0x0002, - vioblockread = 0x0003, - vioblockwrite = 0x0004, - vioblockflush = 0x0005, - vioblockcheck = 0x0007 -}; - struct viodasd_waitevent { struct completion com; int rc; @@ -429,7 +385,7 @@ static void do_viodasd_request(struct request_queue *q) * Probe a single disk and fill in the viodasd_device structure * for it. */ -static void probe_disk(struct viodasd_device *d) +static int probe_disk(struct viodasd_device *d) { HvLpEvent_Rc hvrc; struct viodasd_waitevent we; @@ -453,14 +409,14 @@ retry: 0, 0, 0); if (hvrc != 0) { printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc); - return; + return 0; } wait_for_completion(&we.com); if (we.rc != 0) { if (flags != 0) - return; + return 0; /* try again with read only flag set */ flags = vioblockflags_ro; goto retry; @@ -490,15 +446,32 @@ retry: if (hvrc != 0) { printk(VIOD_KERN_WARNING "bad rc sending event to OS/400 %d\n", (int)hvrc); - return; + return 0; } + + if (d->dev == NULL) { + /* this is when we reprobe for new disks */ + if (vio_create_viodasd(dev_no) == NULL) { + printk(VIOD_KERN_WARNING + "cannot allocate virtual device for disk %d\n", + dev_no); + return 0; + } + /* + * The vio_create_viodasd will have recursed into this + * routine with d->dev set to the new vio device and + * will finish the setup of the disk below. + */ + return 1; + } + /* create the request queue for the disk */ spin_lock_init(&d->q_lock); q = blk_init_queue(do_viodasd_request, &d->q_lock); if (q == NULL) { printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n", dev_no); - return; + return 0; } g = alloc_disk(1 << PARTITION_SHIFT); if (g == NULL) { @@ -506,7 +479,7 @@ retry: "cannot allocate disk structure for disk %d\n", dev_no); blk_cleanup_queue(q); - return; + return 0; } d->disk = g; @@ -538,6 +511,7 @@ retry: /* register us in the global list */ add_disk(g); + return 1; } /* returns the total number of scatterlist elements converted */ @@ -718,8 +692,7 @@ static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id) struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; d->dev = &vdev->dev; - probe_disk(d); - if (d->disk == NULL) + if (!probe_disk(d)) return -ENODEV; return 0; } diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index 2555dfd6fac6..f9ac0d00b951 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h @@ -51,6 +51,51 @@ */ #define VIO_MAX_SUBTYPES 8 +#define VIOMAXBLOCKDMA 12 + +struct open_data { + u64 disk_size; + u16 max_disk; + u16 cylinders; + u16 tracks; + u16 sectors; + u16 bytes_per_sector; +}; + +struct rw_data { + u64 offset; + struct { + u32 token; + u32 reserved; + u64 len; + } dma_info[VIOMAXBLOCKDMA]; +}; + +struct vioblocklpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_result; + u16 disk; + u16 flags; + union { + struct open_data open_data; + struct rw_data rw_data; + u64 changed; + } u; +}; + +#define vioblockflags_ro 0x0001 + +enum vioblocksubtype { + vioblockopen = 0x0001, + vioblockclose = 0x0002, + vioblockread = 0x0003, + vioblockwrite = 0x0004, + vioblockflush = 0x0005, + vioblockcheck = 0x0007 +}; + struct viocdlpevent { struct HvLpEvent event; u32 reserved; @@ -133,6 +178,8 @@ extern void vio_set_hostlp(void); extern void *vio_get_event_buffer(int subtype); extern void vio_free_event_buffer(int subtype, void *buffer); +extern struct vio_dev *vio_create_viodasd(u32 unit); + extern HvLpIndex viopath_hostLp; extern HvLpIndex viopath_ourLp; From 84dd4676f5519b86aee3bfaf1b230be2cb43f69b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 15:19:03 +1000 Subject: [PATCH 2141/2804] [POWERPC] Move of_platform_driver initialisations: arch/powerpc We no longer initialise the name and owner fields of the of_platform_driver, but use the fields of the embedded device_driver's name field instead. Signed-off-by: Stephen Rothwell Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/gpio_mdio.c | 4 +++- arch/powerpc/sysdev/axonram.c | 8 +++++--- arch/powerpc/sysdev/pmi.c | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index c91a33593bb8..dae9f658122e 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -320,10 +320,12 @@ static struct of_device_id gpio_mdio_match[] = static struct of_platform_driver gpio_mdio_driver = { - .name = "gpio-mdio-bitbang", .match_table = gpio_mdio_match, .probe = gpio_mdio_probe, .remove = gpio_mdio_remove, + .driver = { + .name = "gpio-mdio-bitbang", + }, }; int gpio_mdio_init(void) diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index ab037a3a40db..4d3ba63bba79 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -324,11 +324,13 @@ static struct of_device_id axon_ram_device_id[] = { }; static struct of_platform_driver axon_ram_driver = { - .owner = THIS_MODULE, - .name = AXON_RAM_MODULE_NAME, .match_table = axon_ram_device_id, .probe = axon_ram_probe, - .remove = axon_ram_remove + .remove = axon_ram_remove, + .driver = { + .owner = THIS_MODULE, + .name = AXON_RAM_MODULE_NAME, + }, }; /** diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c index 2f91b55b7754..20edd1e94eff 100644 --- a/arch/powerpc/sysdev/pmi.c +++ b/arch/powerpc/sysdev/pmi.c @@ -205,10 +205,12 @@ static int pmi_of_remove(struct of_device *dev) } static struct of_platform_driver pmi_of_platform_driver = { - .name = "pmi", .match_table = pmi_match, .probe = pmi_of_probe, - .remove = pmi_of_remove + .remove = pmi_of_remove, + .driver = { + .name = "pmi", + }, }; static int __init pmi_module_init(void) From 64f2758514e3bad19cab03d22851ab37654399a4 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 10 Oct 2007 10:38:24 +1000 Subject: [PATCH 2142/2804] [POWERPC] Don't enable cpu hotplug on pSeries machines with MPIC Don't allow cpu hotplug on systems lacking XICS interrupt controller (i.e. with an MPIC interrupt controller), since the current pSeries platform code is hardcoded for XICS. This works around the bug reported by Paul Mackerras where the disable_nonboot_cpus() call recently added to the shutdown path will cause an oops on older pSeries machines. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/hotplug-cpu.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 9711eb0d5496..fc48b96c81bf 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -252,6 +252,20 @@ static struct notifier_block pseries_smp_nb = { static int __init pseries_cpu_hotplug_init(void) { + struct device_node *np; + const char *typep; + + for_each_node_by_name(np, "interrupt-controller") { + typep = of_get_property(np, "compatible", NULL); + if (strstr(typep, "open-pic")) { + of_node_put(np); + + printk(KERN_INFO "CPU Hotplug not supported on " + "systems using MPIC\n"); + return 0; + } + } + rtas_stop_self_args.token = rtas_token("stop-self"); qcss_tok = rtas_token("query-cpu-stopped-state"); From af8184718a322ae589efa583aa69ffdae61bf266 Mon Sep 17 00:00:00 2001 From: Kristoffer Nyborg Gregertsen Date: Fri, 17 Aug 2007 16:59:57 +0200 Subject: [PATCH 2143/2804] [AVR32] SMC configuration in clock cycles This patch makes the SMC configuration take timings in clock cycles instead of nanoseconds. A function to calculate timings in clock cycles is added. This patch removes the rounding troubles of the previous SMC configuration method. [hskinnemoen@atmel.com: fix atstk1002/atngw100 flash config] Signed-off-by: Kristoffer Nyborg Gregertsen Signed-off-by: Haavard Skinnemoen --- arch/avr32/boards/atngw100/flash.c | 5 +- arch/avr32/boards/atstk1000/flash.c | 5 +- arch/avr32/mach-at32ap/hsmc.c | 131 ++++++++++++++++++++++++---- include/asm-avr32/arch-at32ap/smc.h | 53 ++++++++--- 4 files changed, 163 insertions(+), 31 deletions(-) diff --git a/arch/avr32/boards/atngw100/flash.c b/arch/avr32/boards/atngw100/flash.c index f9b32a8eab9b..b07ae63aa548 100644 --- a/arch/avr32/boards/atngw100/flash.c +++ b/arch/avr32/boards/atngw100/flash.c @@ -15,7 +15,7 @@ #include -static struct smc_config flash_config __initdata = { +static struct smc_timing flash_timing __initdata = { .ncs_read_setup = 0, .nrd_setup = 40, .ncs_write_setup = 0, @@ -28,7 +28,9 @@ static struct smc_config flash_config __initdata = { .read_cycle = 120, .write_cycle = 120, +}; +static struct smc_config flash_config __initdata = { .bus_width = 2, .nrd_controlled = 1, .nwe_controlled = 1, @@ -82,6 +84,7 @@ static int __init atngw100_flash_init(void) { int ret; + smc_set_timing(&flash_config, &flash_timing); ret = smc_set_configuration(0, &flash_config); if (ret < 0) { printk(KERN_ERR "atngw100: failed to set NOR flash timing\n"); diff --git a/arch/avr32/boards/atstk1000/flash.c b/arch/avr32/boards/atstk1000/flash.c index aac4300cca12..3d0a102ad45e 100644 --- a/arch/avr32/boards/atstk1000/flash.c +++ b/arch/avr32/boards/atstk1000/flash.c @@ -15,7 +15,7 @@ #include -static struct smc_config flash_config __initdata = { +static struct smc_timing flash_timing __initdata = { .ncs_read_setup = 0, .nrd_setup = 40, .ncs_write_setup = 0, @@ -28,7 +28,9 @@ static struct smc_config flash_config __initdata = { .read_cycle = 120, .write_cycle = 120, +}; +static struct smc_config flash_config __initdata = { .bus_width = 2, .nrd_controlled = 1, .nwe_controlled = 1, @@ -82,6 +84,7 @@ static int __init atstk1000_flash_init(void) { int ret; + smc_set_timing(&flash_config, &flash_timing); ret = smc_set_configuration(0, &flash_config); if (ret < 0) { printk(KERN_ERR "atstk1000: failed to set NOR flash timing\n"); diff --git a/arch/avr32/mach-at32ap/hsmc.c b/arch/avr32/mach-at32ap/hsmc.c index 5e22a750632b..704607fbcc69 100644 --- a/arch/avr32/mach-at32ap/hsmc.c +++ b/arch/avr32/mach-at32ap/hsmc.c @@ -29,16 +29,25 @@ struct hsmc { static struct hsmc *hsmc; -int smc_set_configuration(int cs, const struct smc_config *config) +void smc_set_timing(struct smc_config *config, + const struct smc_timing *timing) { - unsigned long mul; - unsigned long offset; - u32 setup, pulse, cycle, mode; + int recover; + int cycle; - if (!hsmc) - return -ENODEV; - if (cs >= NR_CHIP_SELECTS) - return -EINVAL; + unsigned long mul; + + /* Reset all SMC timings */ + config->ncs_read_setup = 0; + config->nrd_setup = 0; + config->ncs_write_setup = 0; + config->nwe_setup = 0; + config->ncs_read_pulse = 0; + config->nrd_pulse = 0; + config->ncs_write_pulse = 0; + config->nwe_pulse = 0; + config->read_cycle = 0; + config->write_cycle = 0; /* * cycles = x / T = x * f @@ -50,16 +59,102 @@ int smc_set_configuration(int cs, const struct smc_config *config) #define ns2cyc(x) ((((x) * mul) + 65535) >> 16) - setup = (HSMC_BF(NWE_SETUP, ns2cyc(config->nwe_setup)) - | HSMC_BF(NCS_WR_SETUP, ns2cyc(config->ncs_write_setup)) - | HSMC_BF(NRD_SETUP, ns2cyc(config->nrd_setup)) - | HSMC_BF(NCS_RD_SETUP, ns2cyc(config->ncs_read_setup))); - pulse = (HSMC_BF(NWE_PULSE, ns2cyc(config->nwe_pulse)) - | HSMC_BF(NCS_WR_PULSE, ns2cyc(config->ncs_write_pulse)) - | HSMC_BF(NRD_PULSE, ns2cyc(config->nrd_pulse)) - | HSMC_BF(NCS_RD_PULSE, ns2cyc(config->ncs_read_pulse))); - cycle = (HSMC_BF(NWE_CYCLE, ns2cyc(config->write_cycle)) - | HSMC_BF(NRD_CYCLE, ns2cyc(config->read_cycle))); + if (timing->ncs_read_setup > 0) + config->ncs_read_setup = ns2cyc(timing->ncs_read_setup); + + if (timing->nrd_setup > 0) + config->nrd_setup = ns2cyc(timing->nrd_setup); + + if (timing->ncs_write_setup > 0) + config->ncs_write_setup = ns2cyc(timing->ncs_write_setup); + + if (timing->nwe_setup > 0) + config->nwe_setup = ns2cyc(timing->nwe_setup); + + if (timing->ncs_read_pulse > 0) + config->ncs_read_pulse = ns2cyc(timing->ncs_read_pulse); + + if (timing->nrd_pulse > 0) + config->nrd_pulse = ns2cyc(timing->nrd_pulse); + + if (timing->ncs_write_pulse > 0) + config->ncs_write_pulse = ns2cyc(timing->ncs_write_pulse); + + if (timing->nwe_pulse > 0) + config->nwe_pulse = ns2cyc(timing->nwe_pulse); + + if (timing->read_cycle > 0) + config->read_cycle = ns2cyc(timing->read_cycle); + + if (timing->write_cycle > 0) + config->write_cycle = ns2cyc(timing->write_cycle); + + /* Extend read cycle in needed */ + if (timing->ncs_read_recover > 0) + recover = ns2cyc(timing->ncs_read_recover); + else + recover = 1; + + cycle = config->ncs_read_setup + config->ncs_read_pulse + recover; + + if (config->read_cycle < cycle) + config->read_cycle = cycle; + + /* Extend read cycle in needed */ + if (timing->nrd_recover > 0) + recover = ns2cyc(timing->nrd_recover); + else + recover = 1; + + cycle = config->nrd_setup + config->nrd_pulse + recover; + + if (config->read_cycle < cycle) + config->read_cycle = cycle; + + /* Extend write cycle in needed */ + if (timing->ncs_write_recover > 0) + recover = ns2cyc(timing->ncs_write_recover); + else + recover = 1; + + cycle = config->ncs_write_setup + config->ncs_write_pulse + recover; + + if (config->write_cycle < cycle) + config->write_cycle = cycle; + + /* Extend write cycle in needed */ + if (timing->nwe_recover > 0) + recover = ns2cyc(timing->nwe_recover); + else + recover = 1; + + cycle = config->nwe_setup + config->nwe_pulse + recover; + + if (config->write_cycle < cycle) + config->write_cycle = cycle; +} +EXPORT_SYMBOL(smc_set_timing); + +int smc_set_configuration(int cs, const struct smc_config *config) +{ + unsigned long offset; + u32 setup, pulse, cycle, mode; + + if (!hsmc) + return -ENODEV; + if (cs >= NR_CHIP_SELECTS) + return -EINVAL; + + setup = (HSMC_BF(NWE_SETUP, config->nwe_setup) + | HSMC_BF(NCS_WR_SETUP, config->ncs_write_setup) + | HSMC_BF(NRD_SETUP, config->nrd_setup) + | HSMC_BF(NCS_RD_SETUP, config->ncs_read_setup)); + pulse = (HSMC_BF(NWE_PULSE, config->nwe_pulse) + | HSMC_BF(NCS_WR_PULSE, config->ncs_write_pulse) + | HSMC_BF(NRD_PULSE, config->nrd_pulse) + | HSMC_BF(NCS_RD_PULSE, config->ncs_read_pulse)); + cycle = (HSMC_BF(NWE_CYCLE, config->write_cycle) + | HSMC_BF(NRD_CYCLE, config->read_cycle)); switch (config->bus_width) { case 1: diff --git a/include/asm-avr32/arch-at32ap/smc.h b/include/asm-avr32/arch-at32ap/smc.h index 07152b7fd9c9..c98eea44a70a 100644 --- a/include/asm-avr32/arch-at32ap/smc.h +++ b/include/asm-avr32/arch-at32ap/smc.h @@ -15,22 +15,50 @@ /* * All timing parameters are in nanoseconds. */ -struct smc_config { +struct smc_timing { /* Delay from address valid to assertion of given strobe */ - u16 ncs_read_setup; - u16 nrd_setup; - u16 ncs_write_setup; - u16 nwe_setup; + int ncs_read_setup; + int nrd_setup; + int ncs_write_setup; + int nwe_setup; /* Pulse length of given strobe */ - u16 ncs_read_pulse; - u16 nrd_pulse; - u16 ncs_write_pulse; - u16 nwe_pulse; + int ncs_read_pulse; + int nrd_pulse; + int ncs_write_pulse; + int nwe_pulse; /* Total cycle length of given operation */ - u16 read_cycle; - u16 write_cycle; + int read_cycle; + int write_cycle; + + /* Minimal recovery times, will extend cycle if needed */ + int ncs_read_recover; + int nrd_recover; + int ncs_write_recover; + int nwe_recover; +}; + +/* + * All timing parameters are in clock cycles. + */ +struct smc_config { + + /* Delay from address valid to assertion of given strobe */ + u8 ncs_read_setup; + u8 nrd_setup; + u8 ncs_write_setup; + u8 nwe_setup; + + /* Pulse length of given strobe */ + u8 ncs_read_pulse; + u8 nrd_pulse; + u8 ncs_write_pulse; + u8 nwe_pulse; + + /* Total cycle length of given operation */ + u8 read_cycle; + u8 write_cycle; /* Bus width in bytes */ u8 bus_width; @@ -76,6 +104,9 @@ struct smc_config { unsigned int tdf_mode:1; }; +extern void smc_set_timing(struct smc_config *config, + const struct smc_timing *timing); + extern int smc_set_configuration(int cs, const struct smc_config *config); extern struct smc_config *smc_get_configuration(int cs); From a7ff43b808f077e7aae2772b2f1a06a39e6b0cf8 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Sat, 22 Sep 2007 23:31:39 +0200 Subject: [PATCH 2144/2804] [AVR32] Ignore a few irrelevant syscalls Ignore a few syscalls that are irrelevant because they're either old, depends on NUMA or depends on SMP. Signed-off-by: Haavard Skinnemoen --- include/asm-avr32/unistd.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h index 3b4e35b55c82..de09009593f8 100644 --- a/include/asm-avr32/unistd.h +++ b/include/asm-avr32/unistd.h @@ -303,6 +303,19 @@ #ifdef __KERNEL__ #define NR_syscalls 282 +/* Old stuff */ +#define __IGNORE_uselib +#define __IGNORE_mmap + +/* NUMA stuff */ +#define __IGNORE_mbind +#define __IGNORE_get_mempolicy +#define __IGNORE_set_mempolicy +#define __IGNORE_migrate_pages +#define __IGNORE_move_pages + +/* SMP stuff */ +#define __IGNORE_getcpu #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_STAT64 From 82c54f864fea26c4c44f27e2b4c4d9a811dde299 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 25 Sep 2007 07:17:48 -0700 Subject: [PATCH 2145/2804] [AVR32] ngw100 i2c-gpio tweaks Make the NGW100 bitbang i2c use open drain signaling. Also, speed it up, so it's closer to 100 kHz ... the code paths seem to be long enough that the udelay isn't dominating bit times. The peak bit rate I observed was around 125 kHz, but that's with large delays (usually before ACK/NAK) which hold the overall rate down to around 80 kHz (call it 100 usec/byte on average). Signed-off-by: David Brownell Signed-off-by: Haavard Skinnemoen --- arch/avr32/boards/atngw100/setup.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index 6e180f435253..52987c81d668 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -125,8 +125,11 @@ static struct platform_device ngw_gpio_leds = { }; static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PIN_PA(6), - .scl_pin = GPIO_PIN_PA(7), + .sda_pin = GPIO_PIN_PA(6), + .scl_pin = GPIO_PIN_PA(7), + .sda_is_open_drain = 1, + .scl_is_open_drain = 1, + .udelay = 2, /* close to 100 kHz */ }; static struct platform_device i2c_gpio_device = { @@ -162,8 +165,10 @@ static int __init atngw100_init(void) } platform_device_register(&ngw_gpio_leds); - at32_select_gpio(i2c_gpio_data.sda_pin, 0); - at32_select_gpio(i2c_gpio_data.scl_pin, 0); + at32_select_gpio(i2c_gpio_data.sda_pin, + AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + at32_select_gpio(i2c_gpio_data.scl_pin, + AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); platform_device_register(&i2c_gpio_device); return 0; From bb7aa6d47fcd4f9ab18b4ade2ba078f7719f74ca Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 3 Oct 2007 15:05:20 +0200 Subject: [PATCH 2146/2804] [AVR32] Don't use __builtin_xchg() The implementation of __builtin_xchg() in at least some versions of avr32 gcc is buggy. Rather than find out exactly which versions that have this bug, let's just avoid the problem altogether by implementing xchg() in inline assembly. Also, in most architectures, xchg() seems to imply a memory barrier, while the existing avr32 implementation did not. This patch also fixes that discrepancy. Signed-off-by: Haavard Skinnemoen --- include/asm-avr32/system.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/asm-avr32/system.h b/include/asm-avr32/system.h index a8236bacc878..dc2d527cef41 100644 --- a/include/asm-avr32/system.h +++ b/include/asm-avr32/system.h @@ -73,11 +73,16 @@ extern struct task_struct *__switch_to(struct task_struct *, extern void __xchg_called_with_bad_pointer(void); -#ifdef __CHECKER__ -extern unsigned long __builtin_xchg(void *ptr, unsigned long x); -#endif +static inline unsigned long xchg_u32(u32 val, volatile u32 *m) +{ + u32 ret; -#define xchg_u32(val, m) __builtin_xchg((void *)m, val) + asm volatile("xchg %[ret], %[m], %[val]" + : [ret] "=&r"(ret), "=m"(*m) + : "m"(*m), [m] "r"(m), [val] "r"(val) + : "memory"); + return ret; +} static inline unsigned long __xchg(unsigned long x, volatile void *ptr, From a7e30b8d91d3291de4543d97849193ebc3ec4c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20R=C3=A9tornaz?= Date: Wed, 10 Oct 2007 18:52:24 -0400 Subject: [PATCH 2147/2804] [AVR32] Fix random segfault with preemption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As explained on: http://www.avrfreaks.net/index.php?nameรฟphpBB2&fileรฟewtopic&tS307 If the current process is preempted before it can copy RAR_SUP and RSR_SUP both register are lost and the process will segfault as soon as it return from the syscall since the return adress will be corrupted. This patch disable IRQ as soon as we enter the syscall path and reenable them when the copy is done. In the interrupt handlers, check if we are interrupting the srrf instruction, if so disable interrupts and return. The interrupt handler will be re-called immediatly when the interrupts are reenabled. After some stressing workload: - find / > /dev/null in loop - top (in ssh) - ping -f avr32 The segfaults are not seen anymore. Signed-off-by: Philippe Rรฉtornaz Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/entry-avr32b.S | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 42657f1703b2..ccadfd9b438d 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S @@ -159,11 +159,18 @@ handle_vmalloc_miss: .section .scall.text,"ax",@progbits system_call: +#ifdef CONFIG_PREEMPT + mask_interrupts +#endif pushm r12 /* r12_orig */ stmts --sp, r0-lr - zero_fp + mfsr r0, SYSREG_RAR_SUP mfsr r1, SYSREG_RSR_SUP +#ifdef CONFIG_PREEMPT + unmask_interrupts +#endif + zero_fp stm --sp, r0-r1 /* check for syscall tracing */ @@ -638,6 +645,13 @@ irq_level\level: stmts --sp,r0-lr mfsr r8, rar_int\level mfsr r9, rsr_int\level + +#ifdef CONFIG_PREEMPT + sub r11, pc, (. - system_call) + cp.w r11, r8 + breq 4f +#endif + pushm r8-r9 mov r11, sp @@ -668,6 +682,16 @@ irq_level\level: sub sp, -4 /* ignore r12_orig */ rete +#ifdef CONFIG_PREEMPT +4: mask_interrupts + mfsr r8, rsr_int\level + sbr r8, 16 + mtsr rsr_int\level, r8 + ldmts sp++, r0-lr + sub sp, -4 /* ignore r12_orig */ + rete +#endif + 2: get_thread_info r0 ld.w r1, r0[TI_flags] bld r1, TIF_CPU_GOING_TO_SLEEP From 87a72f9e171e558a0288aa83ef1dc6ae4af32224 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 4 Oct 2007 14:18:01 +1000 Subject: [PATCH 2148/2804] [POWERPC] Fix performance monitor on machines with logical PVR Some IBM machines supply a "logical" PVR (processor version register) value in the device tree in the cpu nodes rather than the real PVR. This is used for instance to indicate that the processors in a POWER6 partition have been configured by the hypervisor to run in POWER5+ mode rather than POWER6 mode. To cope with this, we call identify_cpu a second time with the logical PVR value (the first call is with the real PVR value in the very early setup code). However, POWER5+ machines can also supply a logical PVR value, and use the same value (the value that indicates a v2.04 architecture compliant processor). This causes problems for code that uses the performance monitor (such as oprofile), because the PMU registers are different in POWER6 (even in POWER5+ mode) from the real POWER5+. This change works around this problem by taking out the PMU information from the cputable entries for the logical PVR values, and changing identify_cpu so that the second call to it won't overwrite the PMU information that was established by the first call (the one with the real PVR), but does update the other fields. Specifically, if the cputable entry for the logical PVR value has num_pmcs == 0, none of the PMU-related fields get used. So that we can create a mixed cputable entry, we now make cur_cpu_spec point to a single static struct cpu_spec, and copy stuff from cpu_specs[i] into it. This has the side-effect that we can now make cpu_specs[] be initdata. Ultimately it would be good to move the PMU-related fields out to a separate structure, pointed to by the cputable entries, and change identify_cpu so that it saves the PMU info pointer, copies the whole structure, and restores the PMU info pointer, rather than identify_cpu having to list all the fields that are *not* PMU-related. Signed-off-by: Paul Mackerras Acked-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/cputable.c | 45 ++++++++++++++++++---------------- include/asm-powerpc/cputable.h | 1 + 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index b03a442b7888..8662cf053fa0 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -71,7 +71,7 @@ extern void __restore_cpu_ppc970(void); #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ PPC_FEATURE_BOOKE) -static struct cpu_spec cpu_specs[] = { +static struct cpu_spec __initdata cpu_specs[] = { #ifdef CONFIG_PPC64 { /* Power3 */ .pvr_mask = 0xffff0000, @@ -327,14 +327,6 @@ static struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_POWER5_PLUS, .icache_bsize = 128, .dcache_bsize = 128, - .num_pmcs = 6, - .pmc_type = PPC_PMC_IBM, - .oprofile_cpu_type = "ppc64/power6", - .oprofile_type = PPC_OPROFILE_POWER4, - .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, - .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR, - .oprofile_mmcra_clear = POWER6_MMCRA_THRM | - POWER6_MMCRA_OTHER, .platform = "power5+", }, { /* Power6 */ @@ -364,14 +356,6 @@ static struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_POWER6, .icache_bsize = 128, .dcache_bsize = 128, - .num_pmcs = 6, - .pmc_type = PPC_PMC_IBM, - .oprofile_cpu_type = "ppc64/power6", - .oprofile_type = PPC_OPROFILE_POWER4, - .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, - .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR, - .oprofile_mmcra_clear = POWER6_MMCRA_THRM | - POWER6_MMCRA_OTHER, .platform = "power6", }, { /* Cell Broadband Engine */ @@ -1316,18 +1300,37 @@ static struct cpu_spec cpu_specs[] = { #endif /* CONFIG_PPC32 */ }; -struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr) +static struct cpu_spec the_cpu_spec; + +struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr) { struct cpu_spec *s = cpu_specs; - struct cpu_spec **cur = &cur_cpu_spec; + struct cpu_spec *t = &the_cpu_spec; int i; s = PTRRELOC(s); - cur = PTRRELOC(cur); + t = PTRRELOC(t); for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) if ((pvr & s->pvr_mask) == s->pvr_value) { - *cur = cpu_specs + i; + /* + * If we are overriding a previous value derived + * from the real PVR with a new value obtained + * using a logical PVR value, don't modify the + * performance monitor fields. + */ + if (t->num_pmcs && !s->num_pmcs) { + t->cpu_name = s->cpu_name; + t->cpu_features = s->cpu_features; + t->cpu_user_features = s->cpu_user_features; + t->icache_bsize = s->icache_bsize; + t->dcache_bsize = s->dcache_bsize; + t->cpu_setup = s->cpu_setup; + t->cpu_restore = s->cpu_restore; + t->platform = s->platform; + } else + *t = *s; + *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec; #if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE) /* ppc64 and booke expect identify_cpu to also call * setup_cpu for that processor. I will consolidate diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index c9b8f64bbb45..d913f460e710 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -57,6 +57,7 @@ enum powerpc_pmc_type { PPC_PMC_PA6T = 2, }; +/* NOTE WELL: Update identify_cpu() if fields are added or removed! */ struct cpu_spec { /* CPU is matched via (PVR & pvr_mask) == pvr_value */ unsigned int pvr_mask; From d968014b7280e2c447b20363e576999040ac72ef Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 9 Oct 2007 09:59:17 +1000 Subject: [PATCH 2149/2804] [POWERPC] Prevent decrementer clockevents from firing early On old powermacs, we sometimes set the decrementer to 1 in order to trigger a decrementer interrupt, which we use to handle an interrupt that was pending at the time when it was re-enabled. This was causing the decrementer clock event device to call the event function for the next event early, which was causing problems when high-res timers were not enabled. This fixes the problem by recording the timebase value at which the next event should occur, and checking the current timebase against the recorded value in timer_interrupt. If it isn't time for the next event, it just reprograms the decrementer and returns. This also subtracts 1 from the value stored into the decrementer, which is appropriate because the decrementer interrupts on the transition from 0 to -1, not when the decrementer reaches 0. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index d20947cf1735..64b503c82a31 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -118,6 +118,7 @@ static struct clock_event_device decrementer_clockevent = { static DEFINE_PER_CPU(struct clock_event_device, decrementers); void init_decrementer_clockevent(void); +static DEFINE_PER_CPU(u64, decrementer_next_tb); #ifdef CONFIG_PPC_ISERIES static unsigned long __initdata iSeries_recal_titan; @@ -541,6 +542,7 @@ void timer_interrupt(struct pt_regs * regs) struct pt_regs *old_regs; int cpu = smp_processor_id(); struct clock_event_device *evt = &per_cpu(decrementers, cpu); + u64 now; /* Ensure a positive value is written to the decrementer, or else * some CPUs will continuue to take decrementer exceptions */ @@ -551,6 +553,14 @@ void timer_interrupt(struct pt_regs * regs) do_IRQ(regs); #endif + now = get_tb_or_rtc(); + if (now < per_cpu(decrementer_next_tb, cpu)) { + /* not time for this event yet */ + now = per_cpu(decrementer_next_tb, cpu) - now; + if (now <= DECREMENTER_MAX) + set_dec((unsigned int)now - 1); + return; + } old_regs = set_irq_regs(regs); irq_enter(); @@ -797,6 +807,10 @@ void __init clocksource_init(void) static int decrementer_set_next_event(unsigned long evt, struct clock_event_device *dev) { + __get_cpu_var(decrementer_next_tb) = get_tb_or_rtc() + evt; + /* The decrementer interrupts on the 0 -> -1 transition */ + if (evt) + --evt; set_dec(evt); return 0; } From cdec12aebe1b10aa58bebaa05bb697843154f7f9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 11 Oct 2007 21:46:45 +1000 Subject: [PATCH 2150/2804] [POWERPC] Make clockevents work on PPC601 processors In testing the new clocksource and clockevent code on a PPC601 processor, I discovered that the clockevent multiplier value for the decrementer clockevent was overflowing. Because the RTCL register in the 601 effectively counts at 1GHz (it doesn't actually, but it increases by 128 every 128ns), and the shift value was 32, that meant the multiplier value had to be 2^32, which won't fit in an unsigned long on 32-bit. The same problem would arise on any platform where the timebase frequency was 1GHz or more (not that we actually have any such machines today). This fixes it by reducing the shift value to 16. Doing the calculations with a resolution of 2^-16 nanoseconds (15 femtoseconds) should be quite adequate. :) Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 64b503c82a31..9368da371f36 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -108,7 +108,7 @@ static void decrementer_set_mode(enum clock_event_mode mode, static struct clock_event_device decrementer_clockevent = { .name = "decrementer", .rating = 200, - .shift = 32, + .shift = 16, .mult = 0, /* To be filled in */ .irq = 0, .set_next_event = decrementer_set_next_event, From 52aff9f93e452b3a55be74018dc90eb0ddde0a9c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 8 Oct 2007 16:08:29 -0500 Subject: [PATCH 2151/2804] [POWERPC] mpc8272ads: Remove muram from the CPM reg property. This is described by the muram node now. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8272ads.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts index 188179df0845..7285ca1325fd 100644 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -121,7 +121,7 @@ #address-cells = <1>; #size-cells = <1>; compatible = "fsl,mpc8272-cpm", "fsl,cpm2"; - reg = <119c0 30 0 2000>; + reg = <119c0 30>; ranges; muram@0 { From 8abc8f5f1eda7a34394c8006fe1cb4c13ffca682 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 8 Oct 2007 16:08:51 -0500 Subject: [PATCH 2152/2804] [POWERPC] 85xx: Convert mpc8560ads to the new CPM binding. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8560ads.dts | 82 ++++++----- arch/powerpc/platforms/85xx/Kconfig | 1 + arch/powerpc/platforms/85xx/mpc85xx_ads.c | 165 ++++++++++++---------- 3 files changed, 133 insertions(+), 115 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index 5577ec1f312b..6b362f8222c1 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -138,15 +138,31 @@ device_type = "open-pic"; }; - cpm@e0000000 { + cpm@919c0 { #address-cells = <1>; #size-cells = <1>; - device_type = "cpm"; - model = "CPM2"; - ranges = <0 0 c0000>; - reg = <80000 40000>; - command-proc = <919c0>; - brg-frequency = <9d5b340>; + compatible = "fsl,mpc8560-cpm", "fsl,cpm2"; + reg = <919c0 30>; + ranges; + + muram@80000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 80000 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 4000 9000 2000>; + }; + }; + + brg@919f0 { + compatible = "fsl,mpc8560-brg", + "fsl,cpm2-brg", + "fsl,cpm-brg"; + reg = <919f0 10 915f0 10>; + clock-frequency = ; + }; cpmpic: pic@90c00 { interrupt-controller; @@ -155,43 +171,38 @@ interrupts = <2e 2>; interrupt-parent = <&mpic>; reg = <90c00 80>; - device_type = "cpm-pic"; + compatible = "fsl,mpc8560-cpm-pic", "fsl,cpm2-pic"; }; - scc@91a00 { + serial@91a00 { device_type = "serial"; - compatible = "cpm_uart"; - model = "SCC"; - device-id = <1>; + compatible = "fsl,mpc8560-scc-uart", + "fsl,cpm2-scc-uart"; reg = <91a00 20 88000 100>; - clock-setup = <00ffffff 0>; - rx-clock = <1>; - tx-clock = <1>; + fsl,cpm-brg = <1>; + fsl,cpm-command = <00800000>; current-speed = <1c200>; interrupts = <28 8>; interrupt-parent = <&cpmpic>; }; - scc@91a20 { + serial@91a20 { device_type = "serial"; - compatible = "cpm_uart"; - model = "SCC"; - device-id = <2>; + compatible = "fsl,mpc8560-scc-uart", + "fsl,cpm2-scc-uart"; reg = <91a20 20 88100 100>; - clock-setup = ; - rx-clock = <2>; - tx-clock = <2>; + fsl,cpm-brg = <2>; + fsl,cpm-command = <04a00000>; current-speed = <1c200>; interrupts = <29 8>; interrupt-parent = <&cpmpic>; }; - fcc@91320 { + ethernet@91320 { device_type = "network"; - compatible = "fs_enet"; - model = "FCC"; - device-id = <2>; - reg = <91320 20 88500 100 913a0 30>; + compatible = "fsl,mpc8560-fcc-enet", + "fsl,cpm2-fcc-enet"; + reg = <91320 20 88500 100 913b0 1>; /* * mac-address is deprecated and will be removed * in 2.6.25. Only recent versions of @@ -199,20 +210,17 @@ */ mac-address = [ 00 00 00 00 00 00 ]; local-mac-address = [ 00 00 00 00 00 00 ]; - clock-setup = ; - rx-clock = <15>; - tx-clock = <16>; + fsl,cpm-command = <16200300>; interrupts = <21 8>; interrupt-parent = <&cpmpic>; phy-handle = <&phy2>; }; - fcc@91340 { + ethernet@91340 { device_type = "network"; - compatible = "fs_enet"; - model = "FCC"; - device-id = <3>; - reg = <91340 20 88600 100 913d0 30>; + compatible = "fsl,mpc8560-fcc-enet", + "fsl,cpm2-fcc-enet"; + reg = <91340 20 88600 100 913d0 1>; /* * mac-address is deprecated and will be removed * in 2.6.25. Only recent versions of @@ -220,9 +228,7 @@ */ mac-address = [ 00 00 00 00 00 00 ]; local-mac-address = [ 00 00 00 00 00 00 ]; - clock-setup = ; - rx-clock = <17>; - tx-clock = <18>; + fsl,cpm-command = <1a400300>; interrupts = <22 8>; interrupt-parent = <&cpmpic>; phy-handle = <&phy3>; diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index cf815b22b9fb..7748a3a426db 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -12,6 +12,7 @@ config MPC8540_ADS config MPC8560_ADS bool "Freescale MPC8560 ADS" select DEFAULT_UIMAGE + select PPC_CPM_NEW_BINDING help This option enables support for the MPC 8560 ADS board diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 378a244b3bac..509d46beee11 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -17,13 +17,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -32,10 +32,8 @@ #include #ifdef CONFIG_CPM2 -#include #include #include -#include #endif #ifdef CONFIG_PCI @@ -95,10 +93,10 @@ static void __init mpc85xx_ads_pic_init(void) #ifdef CONFIG_CPM2 /* Setup CPM2 PIC */ - np = of_find_node_by_type(NULL, "cpm-pic"); + np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); if (np == NULL) { - printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); - return; + printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); + return; } irq = irq_of_parse_and_map(np, 0); @@ -111,81 +109,75 @@ static void __init mpc85xx_ads_pic_init(void) * Setup the architecture */ #ifdef CONFIG_CPM2 -void init_fcc_ioports(struct fs_platform_info *fpi) +struct cpm_pin { + int port, pin, flags; +}; + +static struct cpm_pin mpc8560_ads_pins[] = { + /* SCC1 */ + {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* SCC2 */ + {3, 26, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC2 */ + {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK14 */ + {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK13 */ + + /* FCC3 */ + {1, 4, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 6, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 7, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 12, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 13, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 14, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 15, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 16, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK16 */ + {2, 17, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK15 */ +}; + +static void __init init_ioports(void) { - struct io_port *io = cpm2_map(im_ioport); - int fcc_no = fs_get_fcc_index(fpi->fs_no); - int target; - u32 tempval; + int i; - switch(fcc_no) { - case 1: - tempval = in_be32(&io->iop_pdirb); - tempval &= ~PB2_DIRB0; - tempval |= PB2_DIRB1; - out_be32(&io->iop_pdirb, tempval); - - tempval = in_be32(&io->iop_psorb); - tempval &= ~PB2_PSORB0; - tempval |= PB2_PSORB1; - out_be32(&io->iop_psorb, tempval); - - tempval = in_be32(&io->iop_pparb); - tempval |= (PB2_DIRB0 | PB2_DIRB1); - out_be32(&io->iop_pparb, tempval); - - target = CPM_CLK_FCC2; - break; - case 2: - tempval = in_be32(&io->iop_pdirb); - tempval &= ~PB3_DIRB0; - tempval |= PB3_DIRB1; - out_be32(&io->iop_pdirb, tempval); - - tempval = in_be32(&io->iop_psorb); - tempval &= ~PB3_PSORB0; - tempval |= PB3_PSORB1; - out_be32(&io->iop_psorb, tempval); - - tempval = in_be32(&io->iop_pparb); - tempval |= (PB3_DIRB0 | PB3_DIRB1); - out_be32(&io->iop_pparb, tempval); - - tempval = in_be32(&io->iop_pdirc); - tempval |= PC3_DIRC1; - out_be32(&io->iop_pdirc, tempval); - - tempval = in_be32(&io->iop_pparc); - tempval |= PC3_DIRC1; - out_be32(&io->iop_pparc, tempval); - - target = CPM_CLK_FCC3; - break; - default: - printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n"); - return; + for (i = 0; i < ARRAY_SIZE(mpc8560_ads_pins); i++) { + struct cpm_pin *pin = &mpc8560_ads_pins[i]; + cpm2_set_pin(pin->port, pin->pin, pin->flags); } - /* Port C has clocks...... */ - tempval = in_be32(&io->iop_psorc); - tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); - out_be32(&io->iop_psorc, tempval); - - tempval = in_be32(&io->iop_pdirc); - tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); - out_be32(&io->iop_pdirc, tempval); - tempval = in_be32(&io->iop_pparc); - tempval |= (PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); - out_be32(&io->iop_pparc, tempval); - - cpm2_unmap(io); - - /* Configure Serial Interface clock routing. - * First, clear FCC bits to zero, - * then set the ones we want. - */ - cpm2_clk_setup(target, fpi->clk_rx, CPM_CLK_RX); - cpm2_clk_setup(target, fpi->clk_tx, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK15, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK16, CPM_CLK_TX); } #endif @@ -200,6 +192,7 @@ static void __init mpc85xx_ads_setup_arch(void) #ifdef CONFIG_CPM2 cpm2_reset(); + init_ioports(); #endif #ifdef CONFIG_PCI @@ -231,6 +224,24 @@ static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); } +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .type = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + if (!machine_is(mpc85xx_ads)) + return 0; + + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} +device_initcall(declare_of_platform_devices); + /* * Called very early, device-tree isn't unflattened */ From ab9683ca8162f9d4b38e04b956278d8cc647dcfc Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 8 Oct 2007 16:08:52 -0500 Subject: [PATCH 2153/2804] [POWERPC] 85xx: Add cpm nodes for 8541/8555 CDS We don't use any CPM devices on these boards, but the muram node on these chips is different from the 8560, so it's helpful to people working with custom boards based on these chips. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8541cds.dts | 36 ++++++++++++++++++++++++++++ arch/powerpc/boot/dts/mpc8555cds.dts | 36 ++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index 6633e07d9f4d..f3f4d79deb63 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts @@ -145,6 +145,42 @@ device_type = "open-pic"; big-endian; }; + + cpm@919c0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8541-cpm", "fsl,cpm2"; + reg = <919c0 30>; + ranges; + + muram@80000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 80000 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9000 1000>; + }; + }; + + brg@919f0 { + compatible = "fsl,mpc8541-brg", + "fsl,cpm2-brg", + "fsl,cpm-brg"; + reg = <919f0 10 915f0 10>; + }; + + cpmpic: pic@90c00 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupts = <2e 2>; + interrupt-parent = <&mpic>; + reg = <90c00 80>; + compatible = "fsl,mpc8541-cpm-pic", "fsl,cpm2-pic"; + }; + }; }; pci1: pci@e0008000 { diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index 99199295147e..57029cca32b2 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts @@ -145,6 +145,42 @@ device_type = "open-pic"; big-endian; }; + + cpm@919c0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8555-cpm", "fsl,cpm2"; + reg = <919c0 30>; + ranges; + + muram@80000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 80000 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9000 1000>; + }; + }; + + brg@919f0 { + compatible = "fsl,mpc8555-brg", + "fsl,cpm2-brg", + "fsl,cpm-brg"; + reg = <919f0 10 915f0 10>; + }; + + cpmpic: pic@90c00 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupts = <2e 2>; + interrupt-parent = <&mpic>; + reg = <90c00 80>; + compatible = "fsl,mpc8555-cpm-pic", "fsl,cpm2-pic"; + }; + }; }; pci1: pci@e0008000 { From 0bfd5df53a99809f60e12bda9c5ef5d8f14ef2e3 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 11 Oct 2007 09:13:41 -0500 Subject: [PATCH 2154/2804] [POWERPC] 85xx: Killed asm-powerpc/mpc85xx.h was really a hold over from arch/ppc. Now that more decoupling has occurred we can remove and some of its legacy. As part of this we moved the definition of CPM_MAP_ADDR into cpm2.h for 85xx platforms. This is a stop gap until drivers stop using CPM_MAP_ADDR. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc8540_ads.h | 35 ------------- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_ads.h | 60 ----------------------- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 10 +++- arch/powerpc/platforms/85xx/mpc85xx_cds.h | 43 ---------------- arch/powerpc/platforms/85xx/mpc85xx_ds.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_mds.c | 1 - include/asm-powerpc/cpm2.h | 4 ++ include/asm-powerpc/fs_pd.h | 2 - include/asm-powerpc/mpc85xx.h | 45 ----------------- 10 files changed, 13 insertions(+), 189 deletions(-) delete mode 100644 arch/powerpc/platforms/85xx/mpc8540_ads.h delete mode 100644 arch/powerpc/platforms/85xx/mpc85xx_ads.h delete mode 100644 arch/powerpc/platforms/85xx/mpc85xx_cds.h delete mode 100644 include/asm-powerpc/mpc85xx.h diff --git a/arch/powerpc/platforms/85xx/mpc8540_ads.h b/arch/powerpc/platforms/85xx/mpc8540_ads.h deleted file mode 100644 index da82f4c0fdac..000000000000 --- a/arch/powerpc/platforms/85xx/mpc8540_ads.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * arch/powerpc/platforms/85xx/mpc8540_ads.h - * - * MPC8540ADS board definitions - * - * Maintainer: Kumar Gala - * - * Copyright 2004 Freescale Semiconductor 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. - * - */ - -#ifndef __MACH_MPC8540ADS_H__ -#define __MACH_MPC8540ADS_H__ - -#include - -#define BOARD_CCSRBAR ((uint)0xe0000000) -#define BCSR_ADDR ((uint)0xf8000000) -#define BCSR_SIZE ((uint)(32 * 1024)) - -/* PCI interrupt controller */ -#define PIRQA MPC85xx_IRQ_EXT1 -#define PIRQB MPC85xx_IRQ_EXT2 -#define PIRQC MPC85xx_IRQ_EXT3 -#define PIRQD MPC85xx_IRQ_EXT4 - -/* Offset of CPM register space */ -#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET) - -#endif /* __MACH_MPC8540ADS_H__ */ diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 509d46beee11..bccdc25f83a2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.h b/arch/powerpc/platforms/85xx/mpc85xx_ads.h deleted file mode 100644 index 46c3532992aa..000000000000 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * MPC85xx ADS board definitions - * - * Maintainer: Kumar Gala - * - * Copyright 2004 Freescale Semiconductor Inc. - * - * 2006 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * 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 __MACH_MPC85XXADS_H -#define __MACH_MPC85XXADS_H - -#include -#include - -#define BCSR_ADDR ((uint)0xf8000000) -#define BCSR_SIZE ((uint)(32 * 1024)) - -#ifdef CONFIG_CPM2 - -#define MPC85xx_CPM_OFFSET (0x80000) - -#define CPM_MAP_ADDR (get_immrbase() + MPC85xx_CPM_OFFSET) -#define CPM_IRQ_OFFSET 60 - -#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET) -#define SIU_INT_SMC2 ((uint)0x05+CPM_IRQ_OFFSET) -#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET) -#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET) -#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) -#define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET) - -/* FCC1 Clock Source Configuration. These can be - * redefined in the board specific file. - * Can only choose from CLK9-12 */ -#define F1_RXCLK 12 -#define F1_TXCLK 11 - -/* FCC2 Clock Source Configuration. These can be - * redefined in the board specific file. - * Can only choose from CLK13-16 */ -#define F2_RXCLK 13 -#define F2_TXCLK 14 - -/* FCC3 Clock Source Configuration. These can be - * redefined in the board specific file. - * Can only choose from CLK13-16 */ -#define F3_RXCLK 15 -#define F3_TXCLK 16 - -#endif /* CONFIG_CPM2 */ -#endif /* __MACH_MPC85XXADS_H */ diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index afe5868cd975..4d063eec6210 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +46,15 @@ #include #include +/* CADMUS info */ +/* xxx - galak, move into device tree */ +#define CADMUS_BASE (0xf8004000) +#define CADMUS_SIZE (256) +#define CM_VER (0) +#define CM_CSR (1) +#define CM_RST (2) + + static int cds_pci_slot = 2; static volatile u8 *cadmus; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.h b/arch/powerpc/platforms/85xx/mpc85xx_cds.h deleted file mode 100644 index b251c9feb3dc..000000000000 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * arch/powerpc/platforms/85xx/mpc85xx_cds.h - * - * MPC85xx CDS board definitions - * - * Maintainer: Kumar Gala - * - * Copyright 2004 Freescale Semiconductor, 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. - * - */ - -#ifndef __MACH_MPC85XX_CDS_H__ -#define __MACH_MPC85XX_CDS_H__ - -/* CADMUS info */ -#define CADMUS_BASE (0xf8004000) -#define CADMUS_SIZE (256) -#define CM_VER (0) -#define CM_CSR (1) -#define CM_RST (2) - -/* CDS NVRAM/RTC */ -#define CDS_RTC_ADDR (0xf8000000) -#define CDS_RTC_SIZE (8 * 1024) - -/* PCI interrupt controller */ -#define PIRQ0A MPC85xx_IRQ_EXT0 -#define PIRQ0B MPC85xx_IRQ_EXT1 -#define PIRQ0C MPC85xx_IRQ_EXT2 -#define PIRQ0D MPC85xx_IRQ_EXT3 -#define PIRQ1A MPC85xx_IRQ_EXT11 - -#define NR_8259_INTS 16 -#define CPM_IRQ_OFFSET NR_8259_INTS - -#define MPC85xx_OPENPIC_IRQ_OFFSET 80 - -#endif /* __MACH_MPC85XX_CDS_H__ */ diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 772e8de9310e..59c121a97ac7 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 6913e99c1279..61b3eedf41b9 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h index e698b1d09dcf..f1112c15ef96 100644 --- a/include/asm-powerpc/cpm2.h +++ b/include/asm-powerpc/cpm2.h @@ -13,6 +13,10 @@ #include #include +#ifdef CONFIG_PPC_85xx +#define CPM_MAP_ADDR (get_immrbase() + 0x80000) +#endif + /* CPM Command register. */ #define CPM_CR_RST ((uint)0x80000000) diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h index 64706a0532d3..9361cd5342cc 100644 --- a/include/asm-powerpc/fs_pd.h +++ b/include/asm-powerpc/fs_pd.h @@ -19,8 +19,6 @@ #if defined(CONFIG_8260) #include -#elif defined(CONFIG_85xx) -#include #endif #define cpm2_map(member) (&cpm2_immr->member) diff --git a/include/asm-powerpc/mpc85xx.h b/include/asm-powerpc/mpc85xx.h deleted file mode 100644 index 54142997a584..000000000000 --- a/include/asm-powerpc/mpc85xx.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * include/asm-powerpc/mpc85xx.h - * - * MPC85xx definitions - * - * Maintainer: Kumar Gala - * - * Copyright 2004 Freescale Semiconductor, 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. - */ - -#ifdef __KERNEL__ -#ifndef __ASM_MPC85xx_H__ -#define __ASM_MPC85xx_H__ - -#include - -#ifdef CONFIG_85xx - -#if defined(CONFIG_MPC8540_ADS) || defined(CONFIG_MPC8560_ADS) -#include -#endif -#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS) -#include -#endif -#ifdef CONFIG_MPC85xx_CDS -#include -#endif - -/* Let modules/drivers get at CCSRBAR */ -extern phys_addr_t get_ccsrbar(void); - -#ifdef MODULE -#define CCSRBAR get_ccsrbar() -#else -#define CCSRBAR BOARD_CCSRBAR -#endif - -#endif /* CONFIG_85xx */ -#endif /* __ASM_MPC85xx_H__ */ -#endif /* __KERNEL__ */ From f5d7d13cd96313a90f8d13fa5d6e0704f6d534ba Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 11 Oct 2007 09:17:22 -0500 Subject: [PATCH 2155/2804] [POWERPC] 85xx: Enable FP emulation in MPC8560 ADS defconfig Signed-off-by: Kumar Gala --- arch/powerpc/configs/mpc8560_ads_defconfig | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/configs/mpc8560_ads_defconfig b/arch/powerpc/configs/mpc8560_ads_defconfig index 0fb54c775cf9..3d68c65212cf 100644 --- a/arch/powerpc/configs/mpc8560_ads_defconfig +++ b/arch/powerpc/configs/mpc8560_ads_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.23-rc4 -# Tue Aug 28 21:24:43 2007 +# Linux kernel version: 2.6.23-rc9 +# Thu Oct 11 09:16:32 2007 # # CONFIG_PPC64 is not set @@ -22,8 +22,13 @@ CONFIG_FSL_BOOKE=y CONFIG_SPE=y # CONFIG_PPC_MM_SLICES is not set CONFIG_PPC32=y +CONFIG_WORD_SIZE=32 CONFIG_PPC_MERGE=y CONFIG_MMU=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_HARDIRQS=y CONFIG_IRQ_PER_CPU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y @@ -86,7 +91,6 @@ CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y -CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y @@ -128,7 +132,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" CONFIG_MPC8560_ADS=y # CONFIG_MPC85xx_CDS is not set # CONFIG_MPC85xx_MDS is not set -# CONFIG_MPC8544_DS is not set +# CONFIG_MPC85xx_DS is not set CONFIG_MPC8560=y CONFIG_MPC85xx=y CONFIG_MPIC=y @@ -142,12 +146,17 @@ CONFIG_MPIC=y # CONFIG_GENERIC_IOMAP is not set # CONFIG_CPU_FREQ is not set CONFIG_CPM2=y +CONFIG_PPC_CPM_NEW_BINDING=y # CONFIG_FSL_ULI1575 is not set +CONFIG_CPM=y # # Kernel options # # CONFIG_HIGHMEM is not set +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set # CONFIG_HZ_100 is not set CONFIG_HZ_250=y # CONFIG_HZ_300 is not set @@ -158,7 +167,7 @@ CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT is not set CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y -# CONFIG_MATH_EMULATION is not set +CONFIG_MATH_EMULATION=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_POPULATES_NODE_MAP=y @@ -177,6 +186,8 @@ CONFIG_VIRT_TO_BUS=y # CONFIG_PROC_DEVICETREE is not set # CONFIG_CMDLINE_BOOL is not set # CONFIG_PM is not set +CONFIG_SUSPEND_UP_POSSIBLE=y +CONFIG_HIBERNATION_UP_POSSIBLE=y # CONFIG_SECCOMP is not set CONFIG_WANT_DEVICE_TREE=y CONFIG_DEVICE_TREE="" @@ -415,6 +426,7 @@ CONFIG_E1000_NAPI=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set @@ -807,3 +819,4 @@ CONFIG_FORCED_INLINING=y # CONFIG_KEYS is not set # CONFIG_SECURITY is not set # CONFIG_CRYPTO is not set +# CONFIG_PPC_CLOCK is not set From 91e034eff1a79835739c6494e9b90796ee43300c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 17:53:52 +0200 Subject: [PATCH 2156/2804] x86: Fix the $(ARCH) dependent help output in the top Makefile Change the $(ARCH) dependency to $(SRCARCH) to honor the x86 namespace for i386 and x86_64. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2a30f5fd8294..1274084c9090 100644 --- a/Makefile +++ b/Makefile @@ -1141,7 +1141,7 @@ help: @echo ' cscope - Generate cscope index' @echo ' kernelrelease - Output the release version string' @echo ' kernelversion - Output the version stored in Makefile' - @if [ -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \ + @if [ -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \ echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \ echo ' (default: $(INSTALL_HDR_PATH))'; \ fi @@ -1149,7 +1149,7 @@ help: @echo 'Static analysers' @echo ' checkstack - Generate a list of stack hogs' @echo ' namespacecheck - Name space analysis on compiled kernel' - @if [ -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \ + @if [ -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \ echo ' headers_check - Sanity check on exported headers'; \ fi @echo '' From d2c75f2f4b8be1c78f275c49e399d5a9b21ce924 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 17:56:02 +0200 Subject: [PATCH 2157/2804] x86: fixup the x86 namespace change in scripts/namespace.pl Let namespace.pl look at the correct files. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- scripts/namespace.pl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/namespace.pl b/scripts/namespace.pl index f34373853ef8..c6e88c652c2f 100755 --- a/scripts/namespace.pl +++ b/scripts/namespace.pl @@ -105,7 +105,7 @@ sub linux_objects if (/.*\.o$/ && ! ( m:/built-in.o$: - || m:arch/i386/kernel/vsyscall-syms.o$: + || m:arch/x86/kernel/vsyscall-syms.o$: || m:arch/ia64/ia32/ia32.o$: || m:arch/ia64/kernel/gate-syms.o$: || m:arch/ia64/lib/__divdi3.o$: @@ -328,9 +328,9 @@ sub list_multiply_defined } # Special case for i386 entry code if ($#{$def{$name}} == 1 && $name =~ /^__kernel_/ && - $def{$name}[0] eq "arch/i386/kernel/vsyscall-int80.o" && - $def{$name}[1] eq "arch/i386/kernel/vsyscall-sysenter.o") { - &drop_def("arch/i386/kernel/vsyscall-sysenter.o", $name); + $def{$name}[0] eq "arch/x86/kernel/vsyscall-int80_32.o" && + $def{$name}[1] eq "arch/x86/kernel/vsyscall-sysenter_32.o") { + &drop_def("arch/x86/kernel/vsyscall-sysenter_32.o", $name); next; } printf "$name is multiply defined in :-\n"; From 019a5f56ec195aceadada18aaaad0f67294bdaef Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 11 Oct 2007 01:06:03 -0400 Subject: [PATCH 2158/2804] mmc: don't use weight32() Using weight32() to determine if a value is a power of 2 is a rather heavi weight solution. The classic idiom is (x & (x - 1)) == 0, but the kernel already provide a is_power_of_2 function for it. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/mmci.c | 3 ++- drivers/mmc/host/tifm_sd.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 4a72772f4fe4..d0eb0a2abf4d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -391,7 +392,7 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); - if (mrq->data && (hweight32(mrq->data->blksz) > 1)) { + if (mrq->data && !is_power_of_2(mrq->data->blksz)) { printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", mmc_hostname(mmc), mrq->data->blksz); mrq->cmd->error = -EINVAL; diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 951392d2ce37..9b904795eb77 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #define DRIVER_NAME "tifm_sd" @@ -637,7 +638,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) goto err_out; } - if (mrq->data && (hweight32(mrq->data->blksz) > 1)) { + if (mrq->data && !is_power_of_2(mrq->data->blksz)) { printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", sock->dev.bus_id, mrq->data->blksz); mrq->cmd->error = -EINVAL; From 8a13c4f972e6c107d8cff54de647544c00e25b41 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 11 Oct 2007 13:36:52 -0500 Subject: [PATCH 2159/2804] [POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers Move to using PAGE_OFFSET instead of TASK_SIZE or KERNELBASE value on 6xx/40x/44x/fsl-booke to determine if the faulting address is a kernel or user space address. This mimics how the macro is_kernel_addr() works. Signed-off-by: Kumar Gala --- arch/powerpc/kernel/head_32.S | 18 +++++++++--------- arch/powerpc/kernel/head_40x.S | 6 +++--- arch/powerpc/kernel/head_44x.S | 6 +++--- arch/powerpc/kernel/head_fsl_booke.S | 11 ++++------- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index d83f04e5a599..a5b13ae7fd20 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -469,12 +469,12 @@ InstructionTLBMiss: mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r3,SPRN_IMISS - lis r1,KERNELBASE@h /* check if kernel address */ - cmplw 0,r3,r1 + lis r1,PAGE_OFFSET@h /* check if kernel address */ + cmplw 0,r1,r3 mfspr r2,SPRN_SPRG3 li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ lwz r2,PGDIR(r2) - blt+ 112f + bge- 112f mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ lis r2,swapper_pg_dir@ha /* if kernel address, use */ @@ -543,12 +543,12 @@ DataLoadTLBMiss: mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r3,SPRN_DMISS - lis r1,KERNELBASE@h /* check if kernel address */ - cmplw 0,r3,r1 + lis r1,PAGE_OFFSET@h /* check if kernel address */ + cmplw 0,r1,r3 mfspr r2,SPRN_SPRG3 li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ lwz r2,PGDIR(r2) - blt+ 112f + bge- 112f mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ lis r2,swapper_pg_dir@ha /* if kernel address, use */ @@ -615,12 +615,12 @@ DataStoreTLBMiss: mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r3,SPRN_DMISS - lis r1,KERNELBASE@h /* check if kernel address */ - cmplw 0,r3,r1 + lis r1,PAGE_OFFSET@h /* check if kernel address */ + cmplw 0,r1,r3 mfspr r2,SPRN_SPRG3 li r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */ lwz r2,PGDIR(r2) - blt+ 112f + bge- 112f mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ lis r2,swapper_pg_dir@ha /* if kernel address, use */ diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index e312824bdd98..cfefc2df8f2a 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -289,7 +289,7 @@ label: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h + lis r11, PAGE_OFFSET@h cmplw r10, r11 blt+ 3f lis r11, swapper_pg_dir@h @@ -481,7 +481,7 @@ label: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h + lis r11, PAGE_OFFSET@h cmplw r10, r11 blt+ 3f lis r11, swapper_pg_dir@h @@ -581,7 +581,7 @@ label: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h + lis r11, PAGE_OFFSET@h cmplw r10, r11 blt+ 3f lis r11, swapper_pg_dir@h diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 864d63fbb204..409db6123924 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -319,7 +319,7 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h + lis r11, PAGE_OFFSET@h cmplw r10, r11 blt+ 3f lis r11, swapper_pg_dir@h @@ -458,7 +458,7 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h + lis r11, PAGE_OFFSET@h cmplw r10, r11 blt+ 3f lis r11, swapper_pg_dir@h @@ -528,7 +528,7 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h + lis r11, PAGE_OFFSET@h cmplw r10, r11 blt+ 3f lis r11, swapper_pg_dir@h diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index ee33ddd97ef3..4b9822728aea 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -461,8 +461,7 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h - ori r11, r11, TASK_SIZE@l + lis r11, PAGE_OFFSET@h cmplw 0, r10, r11 bge 2f @@ -584,8 +583,7 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h - ori r11, r11, TASK_SIZE@l + lis r11, PAGE_OFFSET@h cmplw 5, r10, r11 blt 5, 3f lis r11, swapper_pg_dir@h @@ -645,8 +643,7 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - lis r11, TASK_SIZE@h - ori r11, r11, TASK_SIZE@l + lis r11, PAGE_OFFSET@h cmplw 5, r10, r11 blt 5, 3f lis r11, swapper_pg_dir@h @@ -744,7 +741,7 @@ data_access: * r10 - EA of fault * r11 - TLB (info from Linux PTE) * r12, r13 - available to use - * CR5 - results of addr < TASK_SIZE + * CR5 - results of addr >= PAGE_OFFSET * MAS0, MAS1 - loaded with proper value when we get here * MAS2, MAS3 - will need additional info from Linux PTE * Upon exit, we reload everything and RFI. From 4d9e55103aec1ba7d0617cfd88412ec39e1e2d32 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 11 Oct 2007 13:40:21 -0500 Subject: [PATCH 2160/2804] [POWERPC] Adjust TASK_SIZE on ppc32 systems to 3GB that are capable All ppc32 systems except PReP and 8xx are capable of handling 3G of user address space. Old legacy had set this to 2GB and no one has bothered to fix it. 8xx could be bumped up to 3GB if its SW TLB miss handlers were fixed up to properly determine kernel/user addresses. Signed-off-by: Kumar Gala --- arch/powerpc/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 31804575dd5e..037664d496d7 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -599,7 +599,8 @@ config TASK_SIZE_BOOL config TASK_SIZE hex "Size of user task space" if TASK_SIZE_BOOL - default "0x80000000" + default "0x80000000" if PPC_PREP || PPC_8xx + default "0xc0000000" config CONSISTENT_START_BOOL bool "Set custom consistent memory pool address" From 780513ecb80ea0934fc6833efc4f5ed9ab4ff9bb Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Thu, 11 Oct 2007 21:26:08 +0200 Subject: [PATCH 2161/2804] [BLOCK] Fix failing compile with BLK_DEV_IO_TRACE=n I get a compilation error in sglist-arch branch with BLK_DEV_IO_TRACE=n: CC block/compat_ioctl.o /usr0/export/dev/bharrosh/git/pub/linux-2.6-block/block/compat_ioctl.c: In function ?compat_blk_trace_setup?: /usr0/export/dev/bharrosh/git/pub/linux-2.6-block/block/compat_ioctl.c:568: error: expected expression before ?do? make[2]: *** [block/compat_ioctl.o] Error 1 Signed-off-by: Jens Axboe --- include/linux/blktrace_api.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index 972093bf1853..2e105a12fe29 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -290,7 +290,12 @@ static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio, #define blk_add_trace_generic(q, rq, rw, what) do { } while (0) #define blk_add_trace_pdu_int(q, what, bio, pdu) do { } while (0) #define blk_add_trace_remap(q, bio, dev, f, t) do {} while (0) -#define do_blk_trace_setup(q, bdev, buts) do {} while (0) +static inline int do_blk_trace_setup(struct request_queue *q, + struct block_device *bdev, + struct blk_user_trace_setup *buts) +{ + return 0; +} #endif /* CONFIG_BLK_DEV_IO_TRACE */ #endif /* __KERNEL__ */ #endif From 5d8476c8fab2a51475983af26e220ee84a3964f8 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 11 Oct 2007 22:08:14 +1000 Subject: [PATCH 2162/2804] [POWERPC] 4xx: Add AMCC 405EX support to cputable.c Signed-off-by: Stefan Roese Signed-off-by: Josh Boyer --- arch/powerpc/kernel/cputable.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 8662cf053fa0..d3fb7d0c6c1c 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1087,6 +1087,17 @@ static struct cpu_spec __initdata cpu_specs[] = { .dcache_bsize = 32, .platform = "ppc405", }, + { /* 405EX */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x12910000, + .cpu_name = "405EX", + .cpu_features = CPU_FTRS_40X, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + .icache_bsize = 32, + .dcache_bsize = 32, + .platform = "ppc405", + }, #endif /* CONFIG_40x */ #ifdef CONFIG_44x From 37b31f9a1192120edbe1e8b7ff691dfde96673da Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 11 Oct 2007 22:08:21 +1000 Subject: [PATCH 2163/2804] [POWERPC] 4xx: Add AMCC Kilauea eval board support to platforms/40x This patch adds basic support for the new 405EX and the AMCC eval board Kilauea to arch/powerpc. Signed-off-by: Stefan Roese Signed-off-by: Josh Boyer --- arch/powerpc/platforms/40x/Kconfig | 7 ++++ arch/powerpc/platforms/40x/Makefile | 5 ++- arch/powerpc/platforms/40x/kilauea.c | 58 ++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/platforms/40x/kilauea.c diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index a0a50b16b8a9..47b3b0a3864a 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -29,6 +29,13 @@ # help # This option enables support for the extra features of the EP405PC board. +config KILAUEA + bool "Kilauea" + depends on 40x + default n + help + This option enables support for the AMCC PPC405EX evaluation board. + #config REDWOOD_5 # bool "Redwood-5" # depends on 40x diff --git a/arch/powerpc/platforms/40x/Makefile b/arch/powerpc/platforms/40x/Makefile index 0a3cfe99a7ed..51dadeee6fc6 100644 --- a/arch/powerpc/platforms/40x/Makefile +++ b/arch/powerpc/platforms/40x/Makefile @@ -1,2 +1,3 @@ -obj-$(CONFIG_WALNUT) += walnut.o -obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o +obj-$(CONFIG_KILAUEA) += kilauea.o +obj-$(CONFIG_WALNUT) += walnut.o +obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o diff --git a/arch/powerpc/platforms/40x/kilauea.c b/arch/powerpc/platforms/40x/kilauea.c new file mode 100644 index 000000000000..1bffdbdd21b1 --- /dev/null +++ b/arch/powerpc/platforms/40x/kilauea.c @@ -0,0 +1,58 @@ +/* + * Kilauea board specific routines + * + * Copyright 2007 DENX Software Engineering, Stefan Roese + * + * Based on the Walnut code by + * Josh Boyer + * Copyright 2007 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 + +static struct of_device_id kilauea_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init kilauea_device_probe(void) +{ + if (!machine_is(kilauea)) + return 0; + + of_platform_bus_probe(NULL, kilauea_of_bus, NULL); + + return 0; +} +device_initcall(kilauea_device_probe); + +static int __init kilauea_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "amcc,kilauea")) + return 0; + + return 1; +} + +define_machine(kilauea) { + .name = "Kilauea", + .probe = kilauea_probe, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; From a62f48de13b7496ede99e9980840c03e2d1dab86 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 11 Oct 2007 22:08:27 +1000 Subject: [PATCH 2164/2804] [POWERPC] 4xx: Kilauea DTS Signed-off-by: Stefan Roese Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/kilauea.dts | 252 ++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 arch/powerpc/boot/dts/kilauea.dts diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts new file mode 100644 index 000000000000..c824e8f06454 --- /dev/null +++ b/arch/powerpc/boot/dts/kilauea.dts @@ -0,0 +1,252 @@ +/* + * Device Tree Source for AMCC Kilauea (405EX) + * + * Copyright 2007 DENX Software Engineering, Stefan Roese + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/ { + #address-cells = <1>; + #size-cells = <1>; + model = "amcc,kilauea"; + compatible = "amcc,kilauea"; + dcr-parent = <&/cpus/PowerPC,405EX@0>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,405EX@0 { + device_type = "cpu"; + reg = <0>; + clock-frequency = <0>; /* Filled in by U-Boot */ + timebase-frequency = <0>; /* Filled in by U-Boot */ + i-cache-line-size = <20>; + d-cache-line-size = <20>; + i-cache-size = <4000>; /* 16 kB */ + d-cache-size = <4000>; /* 16 kB */ + dcr-controller; + dcr-access-method = "native"; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0>; /* Filled in by U-Boot */ + }; + + UIC0: interrupt-controller { + compatible = "ibm,uic-405ex", "ibm,uic"; + interrupt-controller; + cell-index = <0>; + dcr-reg = <0c0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + }; + + UIC1: interrupt-controller1 { + compatible = "ibm,uic-405ex","ibm,uic"; + interrupt-controller; + cell-index = <1>; + dcr-reg = <0d0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <1e 4 1f 4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + UIC2: interrupt-controller2 { + compatible = "ibm,uic-405ex","ibm,uic"; + interrupt-controller; + cell-index = <2>; + dcr-reg = <0e0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <1c 4 1d 4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + plb { + compatible = "ibm,plb-405ex", "ibm,plb4"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + clock-frequency = <0>; /* Filled in by U-Boot */ + + SDRAM0: memory-controller { + compatible = "ibm,sdram-405ex"; + dcr-reg = <010 2>; + }; + + MAL0: mcmal { + compatible = "ibm,mcmal-405ex", "ibm,mcmal2"; + dcr-reg = <180 62>; + num-tx-chans = <2>; + num-rx-chans = <2>; + interrupt-parent = <&MAL0>; + interrupts = <0 1 2 3 4>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = ; + interrupt-map-mask = ; + }; + + POB0: opb { + compatible = "ibm,opb-405ex", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <80000000 80000000 10000000 + ef600000 ef600000 a00000 + f0000000 f0000000 10000000>; + dcr-reg = <0a0 5>; + clock-frequency = <0>; /* Filled in by U-Boot */ + + EBC0: ebc { + compatible = "ibm,ebc-405ex", "ibm,ebc"; + dcr-reg = <012 2>; + #address-cells = <2>; + #size-cells = <1>; + clock-frequency = <0>; /* Filled in by U-Boot */ + /* ranges property is supplied by U-Boot */ + interrupts = <5 1>; + interrupt-parent = <&UIC1>; + + nor_flash@0,0 { + compatible = "amd,s29gl512n", "cfi-flash"; + bank-width = <2>; + reg = <0 000000 4000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "kernel"; + reg = <0 200000>; + }; + partition@200000 { + label = "root"; + reg = <200000 200000>; + }; + partition@400000 { + label = "user"; + reg = <400000 3b60000>; + }; + partition@3f60000 { + label = "env"; + reg = <3f60000 40000>; + }; + partition@3fa0000 { + label = "u-boot"; + reg = <3fa0000 60000>; + }; + }; + }; + + UART0: serial@ef600200 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; /* Filled in by U-Boot */ + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <1a 4>; + }; + + UART1: serial@ef600300 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; /* Filled in by U-Boot */ + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <1 4>; + }; + + IIC0: i2c@ef600400 { + device_type = "i2c"; + compatible = "ibm,iic-405ex", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <2 4>; + }; + + IIC1: i2c@ef600500 { + device_type = "i2c"; + compatible = "ibm,iic-405ex", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <7 4>; + }; + + + RGMII0: emac-rgmii@ef600b00 { + device_type = "rgmii-interface"; + compatible = "ibm,rgmii-405ex", "ibm,rgmii"; + reg = ; + }; + + EMAC0: ethernet@ef600900 { + linux,network-index = <0>; + device_type = "network"; + compatible = "ibm,emac-405ex", "ibm,emac4"; + interrupt-parent = <&EMAC0>; + interrupts = <0 1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = ; + reg = ; + local-mac-address = [000000000000]; /* Filled in by U-Boot */ + mal-device = <&MAL0>; + mal-tx-channel = <0>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rgmii"; + phy-map = <00000000>; + rgmii-device = <&RGMII0>; + rgmii-channel = <0>; + }; + + EMAC1: ethernet@ef600a00 { + linux,network-index = <1>; + device_type = "network"; + compatible = "ibm,emac-405ex", "ibm,emac4"; + interrupt-parent = <&EMAC1>; + interrupts = <0 1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = ; + reg = ; + local-mac-address = [000000000000]; /* Filled in by U-Boot */ + mal-device = <&MAL0>; + mal-tx-channel = <1>; + mal-rx-channel = <1>; + cell-index = <1>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rgmii"; + phy-map = <00000000>; + rgmii-device = <&RGMII0>; + rgmii-channel = <1>; + }; + }; + }; +}; From ad656887e22390c64276e0a0057541aec701422c Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 12 Oct 2007 03:18:14 +1000 Subject: [PATCH 2165/2804] [POWERPC] 4xx: Kilauea defconfig file Signed-off-by: Stefan Roese Signed-off-by: Josh Boyer --- arch/powerpc/configs/kilauea_defconfig | 768 +++++++++++++++++++++++++ 1 file changed, 768 insertions(+) create mode 100644 arch/powerpc/configs/kilauea_defconfig diff --git a/arch/powerpc/configs/kilauea_defconfig b/arch/powerpc/configs/kilauea_defconfig new file mode 100644 index 000000000000..31790d329269 --- /dev/null +++ b/arch/powerpc/configs/kilauea_defconfig @@ -0,0 +1,768 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc9 +# Thu Oct 11 19:05:15 2007 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +CONFIG_40x=y +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_4xx=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_WORD_SIZE=32 +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set +CONFIG_PPC_DCR_NATIVE=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_DCR=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +CONFIG_KILAUEA=y +# CONFIG_WALNUT is not set +# CONFIG_XILINX_VIRTEX_GENERIC_BOARD is not set +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPM2 is not set +# CONFIG_FSL_ULI1575 is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SUSPEND_UP_POSSIBLE=y +CONFIG_HIBERNATION_UP_POSSIBLE=y +CONFIG_SECCOMP=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="kilauea.dts" +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x00400000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=35000 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_XILINX_SYSACE is not set +# CONFIG_MISC_DEVICES is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_ETHERNET is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_HW=y +# CONFIG_PPC_CLOCK is not set From f3b6b6cd00d294d50e1c3eee85964c69d898de45 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Fri, 21 Sep 2007 00:02:47 +0100 Subject: [PATCH 2166/2804] leds: Rename leds-cobalt driver The leds-cobalt driver only supports the Coable Qube series (not included in Cobalt Raq series). Rename the driver and update Kconfig/Makefile. Signed-off-by: Yoichi Yuasa Acked-by: Florian Fainelli Signed-off-by: Richard Purdie --- drivers/leds/Kconfig | 6 +++--- drivers/leds/Makefile | 2 +- drivers/leds/{leds-cobalt.c => leds-cobalt-qube.c} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename drivers/leds/{leds-cobalt.c => leds-cobalt-qube.c} (100%) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 4468cb3a8d24..9b79bcd9bf11 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -87,11 +87,11 @@ config LEDS_H1940 help This option enables support for the LEDs on the h1940. -config LEDS_COBALT - tristate "LED Support for Cobalt Server front LED" +config LEDS_COBALT_QUBE + tristate "LED Support for the Cobalt Qube series front LED" depends on LEDS_CLASS && MIPS_COBALT help - This option enables support for the front LED on Cobalt Server + This option enables support for the front LED on Cobalt Qube series config LEDS_GPIO tristate "LED Support for GPIO connected LEDs" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index f8995c9bc2ea..9b2684a20888 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o -obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o +obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o # LED Triggers diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt-qube.c similarity index 100% rename from drivers/leds/leds-cobalt.c rename to drivers/leds/leds-cobalt-qube.c From 97da7aaf46fedcf1a38a88e5ffc2c40df23e8013 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 27 Sep 2007 17:51:05 +0900 Subject: [PATCH 2167/2804] leds: Add Cobalt Raq series LEDs support Add Cobalt Raq series LEDs support. Signed-off-by: Yoichi Yuasa Acked-by: Ralf Baechle Signed-off-by: Richard Purdie --- drivers/leds/Kconfig | 7 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-cobalt-raq.c | 138 +++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 drivers/leds/leds-cobalt-raq.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9b79bcd9bf11..3cb23210b912 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -93,6 +93,13 @@ config LEDS_COBALT_QUBE help This option enables support for the front LED on Cobalt Qube series +config LEDS_COBALT_RAQ + bool "LED Support for the Cobalt Raq series" + depends on LEDS_CLASS && MIPS_COBALT + select LEDS_TRIGGERS + help + This option enables support for the Cobalt Raq series LEDs. + config LEDS_GPIO tristate "LED Support for GPIO connected LEDs" depends on LEDS_CLASS && GENERIC_GPIO diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 9b2684a20888..d2ca1abbc3d2 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o +obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o # LED Triggers diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c new file mode 100644 index 000000000000..6ebfff341e6c --- /dev/null +++ b/drivers/leds/leds-cobalt-raq.c @@ -0,0 +1,138 @@ +/* + * LEDs driver for the Cobalt Raq series. + * + * Copyright (C) 2007 Yoichi Yuasa + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#define LED_WEB 0x04 +#define LED_POWER_OFF 0x08 + +static void __iomem *led_port; +static u8 led_value; +static DEFINE_SPINLOCK(led_value_lock); + +static void raq_web_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + unsigned long flags; + + spin_lock_irqsave(&led_value_lock, flags); + + if (brightness) + led_value |= LED_WEB; + else + led_value &= ~LED_WEB; + writeb(led_value, led_port); + + spin_unlock_irqrestore(&led_value_lock, flags); +} + +static struct led_classdev raq_web_led = { + .name = "raq-web", + .brightness_set = raq_web_led_set, +}; + +static void raq_power_off_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + unsigned long flags; + + spin_lock_irqsave(&led_value_lock, flags); + + if (brightness) + led_value |= LED_POWER_OFF; + else + led_value &= ~LED_POWER_OFF; + writeb(led_value, led_port); + + spin_unlock_irqrestore(&led_value_lock, flags); +} + +static struct led_classdev raq_power_off_led = { + .name = "raq-power-off", + .brightness_set = raq_power_off_led_set, + .default_trigger = "power-off", +}; + +static int __devinit cobalt_raq_led_probe(struct platform_device *pdev) +{ + struct resource *res; + int retval; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EBUSY; + + led_port = ioremap(res->start, res->end - res->start + 1); + if (!led_port) + return -ENOMEM; + + retval = led_classdev_register(&pdev->dev, &raq_power_off_led); + if (retval) + goto err_iounmap; + + retval = led_classdev_register(&pdev->dev, &raq_web_led); + if (retval) + goto err_unregister; + + return 0; + +err_unregister: + led_classdev_unregister(&raq_power_off_led); + +err_iounmap: + iounmap(led_port); + led_port = NULL; + + return retval; +} + +static int __devexit cobalt_raq_led_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&raq_power_off_led); + led_classdev_unregister(&raq_web_led); + + if (led_port) { + iounmap(led_port); + led_port = NULL; + } + + return 0; +} + +static struct platform_driver cobalt_raq_led_driver = { + .probe = cobalt_raq_led_probe, + .remove = __devexit_p(cobalt_raq_led_remove), + .driver = { + .name = "cobalt-raq-leds", + .owner = THIS_MODULE, + }, +}; + +static int __init cobalt_raq_led_init(void) +{ + return platform_driver_register(&cobalt_raq_led_driver); +} + +module_init(cobalt_raq_led_init); From 4276fd7349bfd4f557d9777100fdcf1140771b4e Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 27 Sep 2007 17:51:17 +0900 Subject: [PATCH 2168/2804] leds: Update Cobalt Qube series front LED support Update Cobalt Qube series front LED support. Signed-off-by: Yoichi Yuasa Acked-by: Ralf Baechle Signed-off-by: Richard Purdie --- drivers/leds/leds-cobalt-qube.c | 97 ++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 19 deletions(-) diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c index d16439ce5da7..d2b54b53d80a 100644 --- a/drivers/leds/leds-cobalt-qube.c +++ b/drivers/leds/leds-cobalt-qube.c @@ -3,40 +3,99 @@ * * Control the Cobalt Qube/RaQ front LED */ - -#include -#include -#include -#include +#include +#include +#include #include -#include +#include +#include +#include -static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) +#define LED_FRONT_LEFT 0x01 +#define LED_FRONT_RIGHT 0x02 + +static void __iomem *led_port; +static u8 led_value; + +static void qube_front_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { if (brightness) - COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT; + led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT; else - COBALT_LED_PORT = 0; + led_value = ~(LED_FRONT_LEFT | LED_FRONT_RIGHT); + writeb(led_value, led_port); } -static struct led_classdev cobalt_led = { - .name = "cobalt-front-led", - .brightness_set = cobalt_led_set, - .default_trigger = "ide-disk", +static struct led_classdev qube_front_led = { + .name = "qube-front", + .brightness = LED_FULL, + .brightness_set = qube_front_led_set, + .default_trigger = "ide-disk", }; -static int __init cobalt_led_init(void) +static int __devinit cobalt_qube_led_probe(struct platform_device *pdev) { - return led_classdev_register(NULL, &cobalt_led); + struct resource *res; + int retval; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EBUSY; + + led_port = ioremap(res->start, res->end - res->start + 1); + if (!led_port) + return -ENOMEM; + + led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT; + writeb(led_value, led_port); + + retval = led_classdev_register(&pdev->dev, &qube_front_led); + if (retval) + goto err_iounmap; + + return 0; + +err_iounmap: + iounmap(led_port); + led_port = NULL; + + return retval; } -static void __exit cobalt_led_exit(void) +static int __devexit cobalt_qube_led_remove(struct platform_device *pdev) { - led_classdev_unregister(&cobalt_led); + led_classdev_unregister(&qube_front_led); + + if (led_port) { + iounmap(led_port); + led_port = NULL; + } + + return 0; } -module_init(cobalt_led_init); -module_exit(cobalt_led_exit); +static struct platform_driver cobalt_qube_led_driver = { + .probe = cobalt_qube_led_probe, + .remove = __devexit_p(cobalt_qube_led_remove), + .driver = { + .name = "cobalt-qube-leds", + .owner = THIS_MODULE, + }, +}; + +static int __init cobalt_qube_led_init(void) +{ + return platform_driver_register(&cobalt_qube_led_driver); +} + +static void __exit cobalt_qube_led_exit(void) +{ + platform_driver_unregister(&cobalt_qube_led_driver); +} + +module_init(cobalt_qube_led_init); +module_exit(cobalt_qube_led_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Front LED support for Cobalt Server"); From 0ad90efde278866a4ba7510e6e1fbd9626da1689 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 11 Aug 2007 10:27:19 +0100 Subject: [PATCH 2169/2804] backlight/leds: Make two structs static This patch makes two needlessly global structs static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/backlight.c | 2 +- drivers/video/backlight/lcd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index b26de8cf3112..4840fe217e4d 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -164,7 +164,7 @@ static ssize_t backlight_show_actual_brightness(struct device *dev, return rc; } -struct class *backlight_class; +static struct class *backlight_class; static void bl_device_release(struct device *dev) { diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 6f652c65fae1..299fd318dd45 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -149,7 +149,7 @@ static ssize_t lcd_show_max_contrast(struct device *dev, return sprintf(buf, "%d\n", ld->props.max_contrast); } -struct class *lcd_class; +static struct class *lcd_class; static void lcd_device_release(struct device *dev) { From 0b75f2dfa2a67012ff6996b322117e1d7e45abe1 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 11 Aug 2007 10:29:59 +0100 Subject: [PATCH 2170/2804] backlight: Fix cr_bllcd allocations and error paths After fixing the too small memory allocation in cr_backlight_probe() from drivers/video/backlight/cr_bllcd.c (commit e3bbb3f05339de438faf54124f25c92e6fe4ac2e) I noticed that the Coverity checker also thought there were a few memory leaks in there. I took a closer look and confirmed that there were indeed several leaks. At the start of the function we allocate storage for a 'struct cr_panel' and store the pointer in a variable named 'crp'. Then we call pci_get_device() and pci_read_config_byte() and if either of them fail we return without freeing the memory allocated for the 'struct cr_panel'. These two leaks are easy to fix since we don't even use 'crp' for anything up to this point, so I simply moved the allocation further down in the function so it only happens just before we actually need it. A bit further down we call backlight_device_register() and store the result in 'crp->cr_backlight_device'. In case of error we return 'crp->cr_backlight_device' from the function, thus leaking 'crp' itself. The same thing happens with the call to lcd_device_register(). To fix these two leaks I declare two new pointers to hold the return values, so that in case of error we can return the pointer (as before) but without leaking 'crp'. This version of the patch also adds missing backlight_device_unregister() / lcd_device_unregister() / pci_dev_put() calls to error paths. Thanks to Richard Purdie for noticing. Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/cr_bllcd.c | 35 +++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index b7904da51b23..92e201e81fbd 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -171,13 +171,11 @@ static struct lcd_ops cr_lcd_ops = { static int cr_backlight_probe(struct platform_device *pdev) { + struct backlight_device *bdp; + struct lcd_device *ldp; struct cr_panel *crp; u8 dev_en; - crp = kzalloc(sizeof(*crp), GFP_KERNEL); - if (crp == NULL) - return -ENOMEM; - lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL, CRVML_DEVICE_LPC, NULL); if (!lpc_dev) { @@ -193,27 +191,34 @@ static int cr_backlight_probe(struct platform_device *pdev) return -ENODEV; } - crp->cr_backlight_device = backlight_device_register("cr-backlight", - &pdev->dev, NULL, - &cr_backlight_ops); - if (IS_ERR(crp->cr_backlight_device)) { + bdp = backlight_device_register("cr-backlight", + &pdev->dev, NULL, &cr_backlight_ops); + if (IS_ERR(bdp)) { pci_dev_put(lpc_dev); - return PTR_ERR(crp->cr_backlight_device); + return PTR_ERR(bdp); } - crp->cr_lcd_device = lcd_device_register("cr-lcd", - &pdev->dev, NULL, - &cr_lcd_ops); - - if (IS_ERR(crp->cr_lcd_device)) { + ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops); + if (IS_ERR(ldp)) { + backlight_device_unregister(bdp); pci_dev_put(lpc_dev); - return PTR_ERR(crp->cr_backlight_device); + return PTR_ERR(bdp); } pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR, &gpio_bar); gpio_bar &= ~0x3F; + crp = kzalloc(sizeof(*crp), GFP_KERNEL); + if (!crp) { + lcd_device_unregister(ldp); + backlight_device_unregister(bdp); + pci_dev_put(lpc_dev); + return -ENOMEM; + } + + crp->cr_backlight_device = bdp; + crp->cr_lcd_device = ldp; crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK; crp->cr_backlight_device->props.brightness = 0; crp->cr_backlight_device->props.max_brightness = 0; From 18f65c793a5106b9f99822ef248e71582db03386 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Sun, 2 Sep 2007 23:15:49 +0100 Subject: [PATCH 2171/2804] backlight: Add Samsung LTV350QV LCD driver This patch adds support for powering on and off the Samsung LTV350QV LCD panel via SPI. The driver responds to framebuffer power management, it powers off the panel on reboot/halt/poweroff. It can also be controlled through sysfs. The panel is powered up when the module is loaded, and off when the module is unloaded. Verified on AVR32 STK1000. Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Richard Purdie --- drivers/video/backlight/Kconfig | 12 ++ drivers/video/backlight/Makefile | 2 + drivers/video/backlight/ltv350qv.c | 330 +++++++++++++++++++++++++++++ drivers/video/backlight/ltv350qv.h | 95 +++++++++ 4 files changed, 439 insertions(+) create mode 100644 drivers/video/backlight/ltv350qv.c create mode 100644 drivers/video/backlight/ltv350qv.h diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 2580f5fa2486..b6f936a09185 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -24,6 +24,18 @@ config LCD_CLASS_DEVICE To have support for your specific LCD panel you will have to select the proper drivers which depend on this option. +config LCD_LTV350QV + tristate "Samsung LTV350QV LCD Panel" + depends on LCD_CLASS_DEVICE && SPI_MASTER + default n + help + If you have a Samsung LTV350QV LCD panel, say y to include a + power control driver for it. The panel starts up in power + off state, so you need this driver in order to see any + output. + + The LTV350QV panel is present on all ATSTK1000 boards. + # # Backlight # diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index c6e2266f63e2..965a78b18118 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -1,6 +1,8 @@ # Backlight & LCD drivers obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o +obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o + obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c new file mode 100644 index 000000000000..2eb206bf73e6 --- /dev/null +++ b/drivers/video/backlight/ltv350qv.c @@ -0,0 +1,330 @@ +/* + * Power control for Samsung LTV350QV Quarter VGA LCD Panel + * + * Copyright (C) 2006, 2007 Atmel 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. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "ltv350qv.h" + +#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) + +struct ltv350qv { + struct spi_device *spi; + u8 *buffer; + int power; + struct lcd_device *ld; +}; + +/* + * The power-on and power-off sequences are taken from the + * LTV350QV-F04 data sheet from Samsung. The register definitions are + * taken from the S6F2002 command list also from Samsung. Both + * documents are distributed with the AVR32 Linux BSP CD from Atmel. + * + * There's still some voodoo going on here, but it's a lot better than + * in the first incarnation of the driver where all we had was the raw + * numbers from the initialization sequence. + */ +static int ltv350qv_write_reg(struct ltv350qv *lcd, u8 reg, u16 val) +{ + struct spi_message msg; + struct spi_transfer index_xfer = { + .len = 3, + .cs_change = 1, + }; + struct spi_transfer value_xfer = { + .len = 3, + }; + + spi_message_init(&msg); + + /* register index */ + lcd->buffer[0] = LTV_OPC_INDEX; + lcd->buffer[1] = 0x00; + lcd->buffer[2] = reg & 0x7f; + index_xfer.tx_buf = lcd->buffer; + spi_message_add_tail(&index_xfer, &msg); + + /* register value */ + lcd->buffer[4] = LTV_OPC_DATA; + lcd->buffer[5] = val >> 8; + lcd->buffer[6] = val; + value_xfer.tx_buf = lcd->buffer + 4; + spi_message_add_tail(&value_xfer, &msg); + + return spi_sync(lcd->spi, &msg); +} + +/* The comments are taken straight from the data sheet */ +static int ltv350qv_power_on(struct ltv350qv *lcd) +{ + int ret; + + /* Power On Reset Display off State */ + if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000)) + goto err; + msleep(15); + + /* Power Setting Function 1 */ + if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE)) + goto err; + if (ltv350qv_write_reg(lcd, LTV_PWRCTL2, LTV_VCOML_ENABLE)) + goto err_power1; + + /* Power Setting Function 2 */ + if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, + LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5) + | LTV_SUPPLY_CURRENT(5))) + goto err_power2; + + msleep(55); + + /* Instruction Setting */ + ret = ltv350qv_write_reg(lcd, LTV_IFCTL, + LTV_NMD | LTV_REV | LTV_NL(0x1d)); + ret |= ltv350qv_write_reg(lcd, LTV_DATACTL, + LTV_DS_SAME | LTV_CHS_480 + | LTV_DF_RGB | LTV_RGB_BGR); + ret |= ltv350qv_write_reg(lcd, LTV_ENTRY_MODE, + LTV_VSPL_ACTIVE_LOW + | LTV_HSPL_ACTIVE_LOW + | LTV_DPL_SAMPLE_RISING + | LTV_EPL_ACTIVE_LOW + | LTV_SS_RIGHT_TO_LEFT); + ret |= ltv350qv_write_reg(lcd, LTV_GATECTL1, LTV_CLW(3)); + ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2, + LTV_NW_INV_1LINE | LTV_FWI(3)); + ret |= ltv350qv_write_reg(lcd, LTV_VBP, 0x000a); + ret |= ltv350qv_write_reg(lcd, LTV_HBP, 0x0021); + ret |= ltv350qv_write_reg(lcd, LTV_SOTCTL, LTV_SDT(3) | LTV_EQ(0)); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(0), 0x0103); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(1), 0x0301); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(2), 0x1f0f); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(3), 0x1f0f); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(4), 0x0707); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(5), 0x0307); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(6), 0x0707); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(7), 0x0000); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(8), 0x0004); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(9), 0x0000); + if (ret) + goto err_settings; + + /* Wait more than 2 frames */ + msleep(20); + + /* Display On Sequence */ + ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1, + LTV_VCOM_DISABLE | LTV_VCOMOUT_ENABLE + | LTV_POWER_ON | LTV_DRIVE_CURRENT(5) + | LTV_SUPPLY_CURRENT(5)); + ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2, + LTV_NW_INV_1LINE | LTV_DSC | LTV_FWI(3)); + if (ret) + goto err_disp_on; + + /* Display should now be ON. Phew. */ + return 0; + +err_disp_on: + /* + * Try to recover. Error handling probably isn't very useful + * at this point, just make a best effort to switch the panel + * off. + */ + ltv350qv_write_reg(lcd, LTV_PWRCTL1, + LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5) + | LTV_SUPPLY_CURRENT(5)); + ltv350qv_write_reg(lcd, LTV_GATECTL2, + LTV_NW_INV_1LINE | LTV_FWI(3)); +err_settings: +err_power2: +err_power1: + ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); + msleep(1); +err: + ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); + return -EIO; +} + +static int ltv350qv_power_off(struct ltv350qv *lcd) +{ + int ret; + + /* Display Off Sequence */ + ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1, + LTV_VCOM_DISABLE + | LTV_DRIVE_CURRENT(5) + | LTV_SUPPLY_CURRENT(5)); + ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2, + LTV_NW_INV_1LINE | LTV_FWI(3)); + + /* Power down setting 1 */ + ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); + + /* Wait at least 1 ms */ + msleep(1); + + /* Power down setting 2 */ + ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); + + /* + * No point in trying to recover here. If we can't switch the + * panel off, what are we supposed to do other than inform the + * user about the failure? + */ + if (ret) + return -EIO; + + /* Display power should now be OFF */ + return 0; +} + +static int ltv350qv_power(struct ltv350qv *lcd, int power) +{ + int ret = 0; + + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) + ret = ltv350qv_power_on(lcd); + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) + ret = ltv350qv_power_off(lcd); + + if (!ret) + lcd->power = power; + + return ret; +} + +static int ltv350qv_set_power(struct lcd_device *ld, int power) +{ + struct ltv350qv *lcd = lcd_get_data(ld); + + return ltv350qv_power(lcd, power); +} + +static int ltv350qv_get_power(struct lcd_device *ld) +{ + struct ltv350qv *lcd = lcd_get_data(ld); + + return lcd->power; +} + +static struct lcd_ops ltv_ops = { + .get_power = ltv350qv_get_power, + .set_power = ltv350qv_set_power, +}; + +static int __devinit ltv350qv_probe(struct spi_device *spi) +{ + struct ltv350qv *lcd; + struct lcd_device *ld; + int ret; + + lcd = kzalloc(sizeof(struct ltv350qv), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + lcd->spi = spi; + lcd->power = FB_BLANK_POWERDOWN; + lcd->buffer = kzalloc(8, GFP_KERNEL); + + ld = lcd_device_register("ltv350qv", &spi->dev, lcd, <v_ops); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + lcd->ld = ld; + + ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK); + if (ret) + goto out_unregister; + + dev_set_drvdata(&spi->dev, lcd); + + return 0; + +out_unregister: + lcd_device_unregister(ld); +out_free_lcd: + kfree(lcd); + return ret; +} + +static int __devexit ltv350qv_remove(struct spi_device *spi) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + ltv350qv_power(lcd, FB_BLANK_POWERDOWN); + lcd_device_unregister(lcd->ld); + kfree(lcd); + + return 0; +} + +#ifdef CONFIG_PM +static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + return ltv350qv_power(lcd, FB_BLANK_POWERDOWN); +} + +static int ltv350qv_resume(struct spi_device *spi) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + return ltv350qv_power(lcd, FB_BLANK_UNBLANK); +} +#else +#define ltv350qv_suspend NULL +#define ltv350qv_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt */ +static void ltv350qv_shutdown(struct spi_device *spi) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + ltv350qv_power(lcd, FB_BLANK_POWERDOWN); +} + +static struct spi_driver ltv350qv_driver = { + .driver = { + .name = "ltv350qv", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = ltv350qv_probe, + .remove = __devexit_p(ltv350qv_remove), + .shutdown = ltv350qv_shutdown, + .suspend = ltv350qv_suspend, + .resume = ltv350qv_resume, +}; + +static int __init ltv350qv_init(void) +{ + return spi_register_driver(<v350qv_driver); +} + +static void __exit ltv350qv_exit(void) +{ + spi_unregister_driver(<v350qv_driver); +} +module_init(ltv350qv_init); +module_exit(ltv350qv_exit); + +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/ltv350qv.h b/drivers/video/backlight/ltv350qv.h new file mode 100644 index 000000000000..189112e3fc7a --- /dev/null +++ b/drivers/video/backlight/ltv350qv.h @@ -0,0 +1,95 @@ +/* + * Register definitions for Samsung LTV350QV Quarter VGA LCD Panel + * + * Copyright (C) 2006, 2007 Atmel 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. + */ +#ifndef __LTV350QV_H +#define __LTV350QV_H + +#define LTV_OPC_INDEX 0x74 +#define LTV_OPC_DATA 0x76 + +#define LTV_ID 0x00 /* ID Read */ +#define LTV_IFCTL 0x01 /* Display Interface Control */ +#define LTV_DATACTL 0x02 /* Display Data Control */ +#define LTV_ENTRY_MODE 0x03 /* Entry Mode */ +#define LTV_GATECTL1 0x04 /* Gate Control 1 */ +#define LTV_GATECTL2 0x05 /* Gate Control 2 */ +#define LTV_VBP 0x06 /* Vertical Back Porch */ +#define LTV_HBP 0x07 /* Horizontal Back Porch */ +#define LTV_SOTCTL 0x08 /* Source Output Timing Control */ +#define LTV_PWRCTL1 0x09 /* Power Control 1 */ +#define LTV_PWRCTL2 0x0a /* Power Control 2 */ +#define LTV_GAMMA(x) (0x10 + (x)) /* Gamma control */ + +/* Bit definitions for LTV_IFCTL */ +#define LTV_IM (1 << 15) +#define LTV_NMD (1 << 14) +#define LTV_SSMD (1 << 13) +#define LTV_REV (1 << 7) +#define LTV_NL(x) (((x) & 0x001f) << 0) + +/* Bit definitions for LTV_DATACTL */ +#define LTV_DS_SAME (0 << 12) +#define LTV_DS_D_TO_S (1 << 12) +#define LTV_DS_S_TO_D (2 << 12) +#define LTV_CHS_384 (0 << 9) +#define LTV_CHS_480 (1 << 9) +#define LTV_CHS_492 (2 << 9) +#define LTV_DF_RGB (0 << 6) +#define LTV_DF_RGBX (1 << 6) +#define LTV_DF_XRGB (2 << 6) +#define LTV_RGB_RGB (0 << 2) +#define LTV_RGB_BGR (1 << 2) +#define LTV_RGB_GRB (2 << 2) +#define LTV_RGB_RBG (3 << 2) + +/* Bit definitions for LTV_ENTRY_MODE */ +#define LTV_VSPL_ACTIVE_LOW (0 << 15) +#define LTV_VSPL_ACTIVE_HIGH (1 << 15) +#define LTV_HSPL_ACTIVE_LOW (0 << 14) +#define LTV_HSPL_ACTIVE_HIGH (1 << 14) +#define LTV_DPL_SAMPLE_RISING (0 << 13) +#define LTV_DPL_SAMPLE_FALLING (1 << 13) +#define LTV_EPL_ACTIVE_LOW (0 << 12) +#define LTV_EPL_ACTIVE_HIGH (1 << 12) +#define LTV_SS_LEFT_TO_RIGHT (0 << 8) +#define LTV_SS_RIGHT_TO_LEFT (1 << 8) +#define LTV_STB (1 << 1) + +/* Bit definitions for LTV_GATECTL1 */ +#define LTV_CLW(x) (((x) & 0x0007) << 12) +#define LTV_GAON (1 << 5) +#define LTV_SDR (1 << 3) + +/* Bit definitions for LTV_GATECTL2 */ +#define LTV_NW_INV_FRAME (0 << 14) +#define LTV_NW_INV_1LINE (1 << 14) +#define LTV_NW_INV_2LINE (2 << 14) +#define LTV_DSC (1 << 12) +#define LTV_GIF (1 << 8) +#define LTV_FHN (1 << 7) +#define LTV_FTI(x) (((x) & 0x0003) << 4) +#define LTV_FWI(x) (((x) & 0x0003) << 0) + +/* Bit definitions for LTV_SOTCTL */ +#define LTV_SDT(x) (((x) & 0x0007) << 10) +#define LTV_EQ(x) (((x) & 0x0007) << 2) + +/* Bit definitions for LTV_PWRCTL1 */ +#define LTV_VCOM_DISABLE (1 << 14) +#define LTV_VCOMOUT_ENABLE (1 << 11) +#define LTV_POWER_ON (1 << 9) +#define LTV_DRIVE_CURRENT(x) (((x) & 0x0007) << 4) /* 0=off, 5=max */ +#define LTV_SUPPLY_CURRENT(x) (((x) & 0x0007) << 0) /* 0=off, 5=max */ + +/* Bit definitions for LTV_PWRCTL2 */ +#define LTV_VCOML_ENABLE (1 << 13) +#define LTV_VCOML_VOLTAGE(x) (((x) & 0x001f) << 8) /* 0=1V, 31=-1V */ +#define LTV_VCOMH_VOLTAGE(x) (((x) & 0x001f) << 0) /* 0=3V, 31=4.5V */ + +#endif /* __LTV350QV_H */ From c3f8f65046127f471d0b6193a1923185b354c011 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 3 Sep 2007 00:27:00 +0100 Subject: [PATCH 2172/2804] backlight: Convert corgi backlight driver into a more generic driver Convert the corgi backlight driver to a more generic version so it can be reused by other code rather than being Zaurus/PXA specific. Signed-off-by: Richard Purdie --- arch/arm/mach-pxa/corgi.c | 18 ++++++++++++++++-- arch/arm/mach-pxa/spitz.c | 18 ++++++++++++++++-- drivers/video/backlight/Kconfig | 11 ++++++----- drivers/video/backlight/corgi_bl.c | 22 ++++++++++------------ include/asm-arm/arch-pxa/sharpsl.h | 6 ------ include/linux/backlight.h | 9 +++++++++ 6 files changed, 57 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index aab27297b3c6..2363cc64fe07 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -142,15 +143,28 @@ struct corgissp_machinfo corgi_ssp_machinfo = { /* * Corgi Backlight Device */ -static struct corgibl_machinfo corgi_bl_machinfo = { +static void corgi_bl_kick_battery(void) +{ + void (*kick_batt)(void); + + kick_batt = symbol_get(sharpsl_battery_kick); + if (kick_batt) { + kick_batt(); + symbol_put(sharpsl_battery_kick); + } +} + +static struct generic_bl_info corgi_bl_machinfo = { + .name = "corgi-bl", .max_intensity = 0x2f, .default_intensity = 0x1f, .limit_mask = 0x0b, .set_bl_intensity = corgi_bl_set_intensity, + .kick_battery = corgi_bl_kick_battery, }; static struct platform_device corgibl_device = { - .name = "corgi-bl", + .name = "generic-bl", .dev = { .parent = &corgifb_device.dev, .platform_data = &corgi_bl_machinfo, diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index bae47e145de8..2d78199d24af 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -222,14 +223,27 @@ struct corgissp_machinfo spitz_ssp_machinfo = { /* * Spitz Backlight Device */ -static struct corgibl_machinfo spitz_bl_machinfo = { +static void spitz_bl_kick_battery(void) +{ + void (*kick_batt)(void); + + kick_batt = symbol_get(sharpsl_battery_kick); + if (kick_batt) { + kick_batt(); + symbol_put(sharpsl_battery_kick); + } +} + +static struct generic_bl_info spitz_bl_machinfo = { + .name = "corgi-bl", .default_intensity = 0x1f, .limit_mask = 0x0b, .max_intensity = 0x2f, + .kick_battery = spitz_bl_kick_battery, }; static struct platform_device spitzbl_device = { - .name = "corgi-bl", + .name = "generic-bl", .dev = { .platform_data = &spitz_bl_machinfo, }, diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index b6f936a09185..9609a6c676be 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -51,12 +51,13 @@ config BACKLIGHT_CLASS_DEVICE select the proper drivers which depend on this option. config BACKLIGHT_CORGI - tristate "Sharp Corgi Backlight Driver (SL Series)" - depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL - default y + tristate "Generic (aka Sharp Corgi) Backlight Driver" + depends on BACKLIGHT_CLASS_DEVICE + default n help - If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the - backlight driver. + Say y to enable the generic platform backlight driver previously + known as the Corgi backlight driver. If you have a Sharp Zaurus + SL-C7xx, SL-Cxx00 or SL-6000x say y. Most users can say n. config BACKLIGHT_LOCOMO tristate "Sharp LOCOMO LCD/Backlight Driver" diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index ce00e18a4e5d..4d4d037e3ec9 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -18,13 +18,11 @@ #include #include #include -#include -#include static int corgibl_intensity; static struct backlight_properties corgibl_data; static struct backlight_device *corgi_backlight_device; -static struct corgibl_machinfo *bl_machinfo; +static struct generic_bl_info *bl_machinfo; static unsigned long corgibl_flags; #define CORGIBL_SUSPENDED 0x01 @@ -32,7 +30,6 @@ static unsigned long corgibl_flags; static int corgibl_send_intensity(struct backlight_device *bd) { - void (*corgi_kick_batt)(void); int intensity = bd->props.brightness; if (bd->props.power != FB_BLANK_UNBLANK) @@ -48,11 +45,8 @@ static int corgibl_send_intensity(struct backlight_device *bd) corgibl_intensity = intensity; - corgi_kick_batt = symbol_get(sharpsl_battery_kick); - if (corgi_kick_batt) { - corgi_kick_batt(); - symbol_put(sharpsl_battery_kick); - } + if (bl_machinfo->kick_battery) + bl_machinfo->kick_battery(); return 0; } @@ -107,13 +101,17 @@ static struct backlight_ops corgibl_ops = { static int corgibl_probe(struct platform_device *pdev) { - struct corgibl_machinfo *machinfo = pdev->dev.platform_data; + struct generic_bl_info *machinfo = pdev->dev.platform_data; + const char *name = "generic-bl"; bl_machinfo = machinfo; if (!machinfo->limit_mask) machinfo->limit_mask = -1; - corgi_backlight_device = backlight_device_register ("corgi-bl", + if (machinfo->name) + name = machinfo->name; + + corgi_backlight_device = backlight_device_register (name, &pdev->dev, NULL, &corgibl_ops); if (IS_ERR (corgi_backlight_device)) return PTR_ERR (corgi_backlight_device); @@ -149,7 +147,7 @@ static struct platform_driver corgibl_driver = { .suspend = corgibl_suspend, .resume = corgibl_resume, .driver = { - .name = "corgi-bl", + .name = "generic-bl", }, }; diff --git a/include/asm-arm/arch-pxa/sharpsl.h b/include/asm-arm/arch-pxa/sharpsl.h index 94cb4982af82..2b0fe773213a 100644 --- a/include/asm-arm/arch-pxa/sharpsl.h +++ b/include/asm-arm/arch-pxa/sharpsl.h @@ -25,12 +25,6 @@ struct corgits_machinfo { /* * SharpSL Backlight */ -struct corgibl_machinfo { - int max_intensity; - int default_intensity; - int limit_mask; - void (*set_bl_intensity)(int intensity); -}; extern void corgibl_limit_intensity(int limit); diff --git a/include/linux/backlight.h b/include/linux/backlight.h index c897c7b03858..1ee9488ca2e4 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -92,4 +92,13 @@ static inline void * bl_get_data(struct backlight_device *bl_dev) return dev_get_drvdata(&bl_dev->dev); } +struct generic_bl_info { + const char *name; + int max_intensity; + int default_intensity; + int limit_mask; + void (*set_bl_intensity)(int intensity); + void (*kick_battery)(void); +}; + #endif From 17311393f969090ab060540bd9dbe7dc885a76d5 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 11 Oct 2007 14:35:52 -0700 Subject: [PATCH 2173/2804] [NETFILTER]: nf_conntrack_tcp: fix connection reopening With your description I could reproduce the bug and actually you were completely right: the code above is incorrect. Somehow I was able to misread RFC1122 and mixed the roles :-(: When a connection is >>closed actively<<, it MUST linger in TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime). However, it MAY >>accept<< a new SYN from the remote TCP to reopen the connection directly from TIME-WAIT state, if it: [...] The fix is as follows: if the receiver initiated an active close, then the sender may reopen the connection - otherwise try to figure out if we hold a dead connection. Signed-off-by: Jozsef Kadlecsik Tested-by: Krzysztof Piotr Oledzki Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_proto_tcp.c | 35 +++++++++++--------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index df718e7c7ee4..c7075345971b 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -831,6 +831,20 @@ static int tcp_packet(struct nf_conn *conntrack, tuple = &conntrack->tuplehash[dir].tuple; switch (new_state) { + case TCP_CONNTRACK_SYN_SENT: + if (old_state < TCP_CONNTRACK_TIME_WAIT) + break; + if (conntrack->proto.tcp.seen[!dir].flags & + IP_CT_TCP_FLAG_CLOSE_INIT) { + /* Attempt to reopen a closed connection. + * Delete this connection and look up again. */ + write_unlock_bh(&tcp_lock); + if (del_timer(&conntrack->timeout)) + conntrack->timeout.function((unsigned long) + conntrack); + return -NF_REPEAT; + } + /* Fall through */ case TCP_CONNTRACK_IGNORE: /* Ignored packets: * @@ -879,27 +893,6 @@ static int tcp_packet(struct nf_conn *conntrack, nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: invalid state "); return -NF_ACCEPT; - case TCP_CONNTRACK_SYN_SENT: - if (old_state < TCP_CONNTRACK_TIME_WAIT) - break; - if ((conntrack->proto.tcp.seen[dir].flags & - IP_CT_TCP_FLAG_CLOSE_INIT) - || after(ntohl(th->seq), - conntrack->proto.tcp.seen[dir].td_end)) { - /* Attempt to reopen a closed connection. - * Delete this connection and look up again. */ - write_unlock_bh(&tcp_lock); - if (del_timer(&conntrack->timeout)) - conntrack->timeout.function((unsigned long) - conntrack); - return -NF_REPEAT; - } else { - write_unlock_bh(&tcp_lock); - if (LOG_INVALID(IPPROTO_TCP)) - nf_log_packet(pf, 0, skb, NULL, NULL, - NULL, "nf_ct_tcp: invalid SYN"); - return -NF_ACCEPT; - } case TCP_CONNTRACK_CLOSE: if (index == TCP_RST_SET && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) From 73aaf9355b71d295fd72dc0b93fcdd275c56648f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 11 Oct 2007 14:36:40 -0700 Subject: [PATCH 2174/2804] [NETFILTER]: x_tables: add missing ip6t_modulename aliases The patch will add MODULE_ALIAS("ip6t_") where missing, otherwise you will get ip6tables: No chain/target/match by that name when xt_ is not already loaded. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/xt_CLASSIFY.c | 1 + net/netfilter/xt_CONNMARK.c | 1 + net/netfilter/xt_NOTRACK.c | 1 + net/netfilter/xt_connbytes.c | 1 + net/netfilter/xt_connmark.c | 1 + net/netfilter/xt_dccp.c | 1 + net/netfilter/xt_sctp.c | 1 + net/netfilter/xt_tcpmss.c | 1 + 8 files changed, 8 insertions(+) diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c index 519428566829..07a1b9665005 100644 --- a/net/netfilter/xt_CLASSIFY.c +++ b/net/netfilter/xt_CLASSIFY.c @@ -24,6 +24,7 @@ MODULE_AUTHOR("Patrick McHardy "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("iptables qdisc classification target module"); MODULE_ALIAS("ipt_CLASSIFY"); +MODULE_ALIAS("ip6t_CLASSIFY"); static unsigned int target(struct sk_buff **pskb, diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c index 5a00c5444334..7043c2757e09 100644 --- a/net/netfilter/xt_CONNMARK.c +++ b/net/netfilter/xt_CONNMARK.c @@ -27,6 +27,7 @@ MODULE_AUTHOR("Henrik Nordstrom "); MODULE_DESCRIPTION("IP tables CONNMARK matching module"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_CONNMARK"); +MODULE_ALIAS("ip6t_CONNMARK"); #include #include diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c index b7d6312fccc7..fec1aefb1c32 100644 --- a/net/netfilter/xt_NOTRACK.c +++ b/net/netfilter/xt_NOTRACK.c @@ -9,6 +9,7 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_NOTRACK"); +MODULE_ALIAS("ip6t_NOTRACK"); static unsigned int target(struct sk_buff **pskb, diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c index dd4d79b8fc9d..af79423bc8e8 100644 --- a/net/netfilter/xt_connbytes.c +++ b/net/netfilter/xt_connbytes.c @@ -14,6 +14,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection"); MODULE_ALIAS("ipt_connbytes"); +MODULE_ALIAS("ip6t_connbytes"); static bool match(const struct sk_buff *skb, diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index e73fa9b46cf7..1071fc54d6d3 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c @@ -29,6 +29,7 @@ MODULE_AUTHOR("Henrik Nordstrom "); MODULE_DESCRIPTION("IP tables connmark match module"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_connmark"); +MODULE_ALIAS("ip6t_connmark"); static bool match(const struct sk_buff *skb, diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c index 83224ec89cc0..c2b1b24ee335 100644 --- a/net/netfilter/xt_dccp.c +++ b/net/netfilter/xt_dccp.c @@ -24,6 +24,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Match for DCCP protocol packets"); MODULE_ALIAS("ipt_dccp"); +MODULE_ALIAS("ip6t_dccp"); #define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \ || (!!((invflag) & (option)) ^ (cond))) diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index c002153b80ab..f907770fd4e9 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c @@ -13,6 +13,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kiran Kumar Immidi"); MODULE_DESCRIPTION("Match for SCTP protocol packets"); MODULE_ALIAS("ipt_sctp"); +MODULE_ALIAS("ip6t_sctp"); #ifdef DEBUG_SCTP #define duprintf(format, args...) printk(format , ## args) diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c index cd5f6d758c68..84d401bfafad 100644 --- a/net/netfilter/xt_tcpmss.c +++ b/net/netfilter/xt_tcpmss.c @@ -22,6 +22,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Boucher "); MODULE_DESCRIPTION("iptables TCP MSS match module"); MODULE_ALIAS("ipt_tcpmss"); +MODULE_ALIAS("ip6t_tcpmss"); static bool match(const struct sk_buff *skb, From 4953f0fcc06a125f87874743d968c0e185c8b296 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Thu, 11 Oct 2007 14:39:29 -0700 Subject: [PATCH 2175/2804] [IPv6]: Update setsockopt(IPV6_MULTICAST_IF) to support RFC 3493, try2 From RFC 3493, Section 5.2: IPV6_MULTICAST_IF Set the interface to use for outgoing multicast packets. The argument is the index of the interface to use. If the interface index is specified as zero, the system selects the interface (for example, by looking up the address in a routing table and using the resulting interface). This patch adds support for (index == 0) to reset the value to it's original state, allowing the system to choose the best interface. IPv4 already behaves this way. Signed-off-by: Brian Haley Acked-by: David L Stevens Signed-off-by: David S. Miller --- net/ipv6/ipv6_sockglue.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 532425db11fe..1334fc174bcf 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -539,12 +539,15 @@ done: case IPV6_MULTICAST_IF: if (sk->sk_type == SOCK_STREAM) goto e_inval; - if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) - goto e_inval; - if (__dev_get_by_index(&init_net, val) == NULL) { - retv = -ENODEV; - break; + if (val) { + if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) + goto e_inval; + + if (__dev_get_by_index(&init_net, val) == NULL) { + retv = -ENODEV; + break; + } } np->mcast_oif = val; retv = 0; From 7cfa7168f7a7730abf1aa2af4a7596d24edd4c21 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: [PATCH 2176/2804] atiixp: SB700 contains more than one IDE channel SB700 supports one physical IDE channel, but SB700 SATA controller supports combined mode. When the SATA combined mode is enabled, two SATA ports (port4 and port5) share one IDE channel from IDE controller, and PATA will share the other IDE channel. Our previous patch adding SB700 IDE device ID only supports one IDE channel, which contains bug. The attached patch fixes the bug. Signed-off-by: "Shane Huang" Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/atiixp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 1725aa402d98..679eb92b8920 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -325,7 +325,7 @@ static struct pci_device_id atiixp_pci_tbl[] = { { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); From b4e44369a380c1836d0983c2a5011099b7b26eb1 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: [PATCH 2177/2804] hpt366: MWDMA filter for SATA cards (take 2) The Marvell bridge chips used on HighPoint SATA cards do not seem to support the MWDMA modes (at least that could be seen in their so-called drivers :-), so the driver needs to account for this -- to achieve this: - add mdma_filter() method from the original patch by Bartlomiej Zolnierkiewicz with his consent; - install the method for all chips to only return empty mask if a SATA drive is detected on HPT372{AN]/374 chips... Signed-off-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-dma.c | 9 +++++++-- drivers/ide/ide.c | 1 + drivers/ide/pci/hpt366.c | 23 +++++++++++++++++++++-- include/linux/ide.h | 1 + 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index ff644a5e12cd..097d6e9865bc 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -673,8 +673,13 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) mask &= 0x07; break; case XFER_MW_DMA_0: - if (id->field_valid & 2) - mask = id->dma_mword & hwif->mwdma_mask; + if ((id->field_valid & 2) == 0) + break; + if (hwif->mdma_filter) + mask = hwif->mdma_filter(drive); + else + mask = hwif->mwdma_mask; + mask &= id->dma_mword; break; case XFER_SW_DMA_0: if (id->field_valid & 2) { diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 5e88a060df06..de54306789a1 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -398,6 +398,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->tuneproc = tmp_hwif->tuneproc; hwif->speedproc = tmp_hwif->speedproc; + hwif->mdma_filter = tmp_hwif->mdma_filter; hwif->udma_filter = tmp_hwif->udma_filter; hwif->selectproc = tmp_hwif->selectproc; hwif->reset_poll = tmp_hwif->reset_poll; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 39f1c89f7c86..3d8d6b2ee41a 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 1.12 Aug 19, 2007 + * linux/drivers/ide/pci/hpt366.c Version 1.13 Sep 29, 2007 * * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. @@ -114,7 +114,7 @@ * unify HPT36x/37x timing setup code and the speedproc handlers by joining * the register setting lists into the table indexed by the clock selected * - set the correct hwif->ultra_mask for each individual chip - * - add UltraDMA mode filtering for the HPT37[24] based SATA cards + * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards * Sergei Shtylyov, or */ @@ -562,6 +562,24 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive) return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask; } +static u8 hpt3xx_mdma_filter(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); + + switch (info->chip_type) { + case HPT372 : + case HPT372A: + case HPT372N: + case HPT374 : + if (ide_dev_is_sata(drive->id)) + return 0x00; + /* Fall thru */ + default: + return 0x07; + } +} + static u32 get_speed_setting(u8 speed, struct hpt_info *info) { int i; @@ -1257,6 +1275,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) hwif->busproc = &hpt3xx_busproc; hwif->udma_filter = &hpt3xx_udma_filter; + hwif->mdma_filter = &hpt3xx_mdma_filter; /* * HPT3xxN chips have some complications: diff --git a/include/linux/ide.h b/include/linux/ide.h index b9f66c10caa0..0665428356d3 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -723,6 +723,7 @@ typedef struct hwif_s { /* driver soft-power interface */ int (*busproc)(ide_drive_t *, int); #endif + u8 (*mdma_filter)(ide_drive_t *); u8 (*udma_filter)(ide_drive_t *); void (*ata_input_data)(ide_drive_t *, void *, u32); From 8cb1f567f4c0a2fde9cbf77c2af888a28cab3423 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: [PATCH 2178/2804] ide: Platform IDE driver This is now very similar to pata_platform.c, they both use same platform data structure and same resources. To achieve that, byte_lanes_swapping platform data variable and platform specified iops removed from that driver. It's fine, since those were never used anyway. pata_platform and ide_platform are carrying same driver names, to easily switch between these drivers, without need to touch platform code. Bart: - build fix from Andrew Morton Signed-off-by: Anton Vorontsov Signed-off-by: Vitaly Bordug Cc: Sergei Shtylyov Acked-by: Alan Cox Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 8 ++ drivers/ide/legacy/Makefile | 2 + drivers/ide/legacy/ide_platform.c | 182 ++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 drivers/ide/legacy/ide_platform.c diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 4200251ff635..75b2737510a6 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -308,6 +308,14 @@ config IDE_GENERIC help If unsure, say N. +config BLK_DEV_PLATFORM + tristate "Platform driver for IDE interfaces" + help + This is the platform IDE driver, used mostly for Memory Mapped + IDE devices, like Compact Flashes running in True IDE mode. + + If unsure, say N. + config BLK_DEV_CMD640 bool "CMD640 chipset bugfix/support" depends on X86 diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile index c7971061767e..409822349f10 100644 --- a/drivers/ide/legacy/Makefile +++ b/drivers/ide/legacy/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o +obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o + # Last of all obj-$(CONFIG_BLK_DEV_HD) += hd.o diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c new file mode 100644 index 000000000000..ccfb9893a467 --- /dev/null +++ b/drivers/ide/legacy/ide_platform.c @@ -0,0 +1,182 @@ +/* + * Platform IDE driver + * + * Copyright (C) 2007 MontaVista Software + * + * Maintainer: Kumar Gala + * + * 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 + +static struct { + void __iomem *plat_ide_mapbase; + void __iomem *plat_ide_alt_mapbase; + ide_hwif_t *hwif; + int index; +} hwif_prop; + +static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base, + void __iomem *ctrl, struct pata_platform_info *pdata, int irq, + int mmio) +{ + unsigned long port = (unsigned long)base; + ide_hwif_t *hwif; + int index, i; + + for (index = 0; index < MAX_HWIFS; ++index) { + hwif = ide_hwifs + index; + if (hwif->io_ports[IDE_DATA_OFFSET] == port) + goto found; + } + + for (index = 0; index < MAX_HWIFS; ++index) { + hwif = ide_hwifs + index; + if (hwif->io_ports[IDE_DATA_OFFSET] == 0) + goto found; + } + + return NULL; + +found: + + hwif->hw.io_ports[IDE_DATA_OFFSET] = port; + + port += (1 << pdata->ioport_shift); + for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; + i++, port += (1 << pdata->ioport_shift)) + hwif->hw.io_ports[i] = port; + + hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; + + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); + hwif->hw.irq = hwif->irq = irq; + + hwif->hw.dma = NO_DMA; + hwif->hw.chipset = ide_generic; + + if (mmio) { + hwif->mmio = 1; + default_hwif_mmiops(hwif); + } + + hwif_prop.hwif = hwif; + hwif_prop.index = index; + + return hwif; +} + +static int __devinit plat_ide_probe(struct platform_device *pdev) +{ + struct resource *res_base, *res_alt, *res_irq; + ide_hwif_t *hwif; + struct pata_platform_info *pdata; + int ret = 0; + int mmio = 0; + + pdata = pdev->dev.platform_data; + + /* get a pointer to the register memory */ + res_base = platform_get_resource(pdev, IORESOURCE_IO, 0); + res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1); + + if (!res_base || !res_alt) { + res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res_base || !res_alt) { + ret = -ENOMEM; + goto out; + } + mmio = 1; + } + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_irq) { + ret = -EINVAL; + goto out; + } + + if (mmio) { + hwif_prop.plat_ide_mapbase = devm_ioremap(&pdev->dev, + res_base->start, res_base->end - res_base->start + 1); + hwif_prop.plat_ide_alt_mapbase = devm_ioremap(&pdev->dev, + res_alt->start, res_alt->end - res_alt->start + 1); + } else { + hwif_prop.plat_ide_mapbase = devm_ioport_map(&pdev->dev, + res_base->start, res_base->end - res_base->start + 1); + hwif_prop.plat_ide_alt_mapbase = devm_ioport_map(&pdev->dev, + res_alt->start, res_alt->end - res_alt->start + 1); + } + + hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase, + hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio); + + if (!hwif) { + ret = -ENODEV; + goto out; + } + hwif->gendev.parent = &pdev->dev; + hwif->noprobe = 0; + + probe_hwif_init(hwif); + + platform_set_drvdata(pdev, hwif); + ide_proc_register_port(hwif); + + return 0; + +out: + return ret; +} + +static int __devexit plat_ide_remove(struct platform_device *pdev) +{ + ide_hwif_t *hwif = pdev->dev.driver_data; + + if (hwif != hwif_prop.hwif) { + dev_printk(KERN_DEBUG, &pdev->dev, "%s: hwif value error", + pdev->name); + } else { + ide_unregister(hwif_prop.index); + hwif_prop.index = 0; + hwif_prop.hwif = NULL; + } + + return 0; +} + +static struct platform_driver platform_ide_driver = { + .driver = { + .name = "pata_platform", + }, + .probe = plat_ide_probe, + .remove = __devexit_p(plat_ide_remove), +}; + +static int __init platform_ide_init(void) +{ + return platform_driver_register(&platform_ide_driver); +} + +static void __exit platform_ide_exit(void) +{ + platform_driver_unregister(&platform_ide_driver); +} + +MODULE_DESCRIPTION("Platform IDE driver"); +MODULE_LICENSE("GPL"); + +module_init(platform_ide_init); +module_exit(platform_ide_exit); From 5e32132befa5d2cefadf3141fee0bbb40cd11f0e Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: [PATCH 2179/2804] ide: hook ACPI _PSx method to IDE power on/off ACPI spec defines the sequence of IDE power on/off: Powering down: Call _GTM. Power down drive (calls _PS3 method and turns off power planes). Powering up: Power up drive (calls _PS0 method if present and turns on power planes). Call _STM passing info from _GTM (possibly modified), with ID data from each drive. Initialize the channel. May modify the results of _GTF. For each drive: Call _GTF. Execute task file (possibly modified). This patch adds the missed _PS0/_PS3 methods call. Signed-off-by: Shaohua Li Acked-by: Len Brown Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/acpi/bus.c | 4 +++- drivers/ide/ide-acpi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ drivers/ide/ide.c | 14 ++++++++++++-- include/linux/ide.h | 2 ++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9ba778a2b484..feab124d8e05 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -262,10 +262,12 @@ int acpi_bus_set_power(acpi_handle handle, int state) printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n", device->pnp.bus_id, state); - else + else { + device->power.state = state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to D%d\n", device->pnp.bus_id, state)); + } return result; } diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 17aea65d7dd2..6bff81a58bf3 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -611,6 +611,46 @@ void ide_acpi_push_timing(ide_hwif_t *hwif) } EXPORT_SYMBOL_GPL(ide_acpi_push_timing); +/** + * ide_acpi_set_state - set the channel power state + * @hwif: target IDE interface + * @on: state, on/off + * + * This function executes the _PS0/_PS3 ACPI method to set the power state. + * ACPI spec requires _PS0 when IDE power on and _PS3 when power off + */ +void ide_acpi_set_state(ide_hwif_t *hwif, int on) +{ + int unit; + + if (ide_noacpi) + return; + + DEBPRINT("ENTER:\n"); + + if (!hwif->acpidata) { + DEBPRINT("no ACPI data for %s\n", hwif->name); + return; + } + /* channel first and then drives for power on and verse versa for power off */ + if (on) + acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0); + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + + if (!drive->acpidata->obj_handle) + drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive); + + if (drive->acpidata->obj_handle && drive->present) { + acpi_bus_set_power(drive->acpidata->obj_handle, + on? ACPI_STATE_D0: ACPI_STATE_D3); + } + } + if (!on) + acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3); +} +EXPORT_SYMBOL_GPL(ide_acpi_set_state); + /** * ide_acpi_init - initialize the ACPI link for an IDE interface * @hwif: target IDE interface (channel) @@ -679,6 +719,8 @@ void ide_acpi_init(ide_hwif_t *hwif) return; } + /* ACPI _PS0 before _STM */ + ide_acpi_set_state(hwif, 1); /* * ACPI requires us to call _STM on startup */ diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index de54306789a1..9fdc1fe1b299 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -915,6 +915,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) struct request rq; struct request_pm_state rqpm; ide_task_t args; + int ret; /* Call ACPI _GTM only once */ if (!(drive->dn % 2)) @@ -931,7 +932,14 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) mesg.event = PM_EVENT_FREEZE; rqpm.pm_state = mesg.event; - return ide_do_drive_cmd(drive, &rq, ide_wait); + ret = ide_do_drive_cmd(drive, &rq, ide_wait); + /* only call ACPI _PS3 after both drivers are suspended */ + if (!ret && (((drive->dn % 2) && hwif->drives[0].present + && hwif->drives[1].present) + || !hwif->drives[0].present + || !hwif->drives[1].present)) + ide_acpi_set_state(hwif, 0); + return ret; } static int generic_ide_resume(struct device *dev) @@ -944,8 +952,10 @@ static int generic_ide_resume(struct device *dev) int err; /* Call ACPI _STM only once */ - if (!(drive->dn % 2)) + if (!(drive->dn % 2)) { + ide_acpi_set_state(hwif, 1); ide_acpi_push_timing(hwif); + } ide_acpi_exec_tfs(drive); diff --git a/include/linux/ide.h b/include/linux/ide.h index 0665428356d3..80ea946282d7 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1338,11 +1338,13 @@ extern int ide_acpi_exec_tfs(ide_drive_t *drive); extern void ide_acpi_get_timing(ide_hwif_t *hwif); extern void ide_acpi_push_timing(ide_hwif_t *hwif); extern void ide_acpi_init(ide_hwif_t *hwif); +extern void ide_acpi_set_state(ide_hwif_t *hwif, int on); #else static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; } static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; } static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; } static inline void ide_acpi_init(ide_hwif_t *hwif) { ; } +static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {} #endif extern int ide_hwif_request_regions(ide_hwif_t *hwif); From 07047935795917f21dc532c0c17811213cbc2e97 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: [PATCH 2180/2804] pdc202xx_new: switch to using pci_get_slot() (take 2) Switch to using pci_get_slot() in init_setup_pdc20270() to get to the mate chip behind DC21150 bridge as there's no need for the driver itself to walk the list of the PCI devices (and the driver didn't check the bus # of the found device). While at it, make it emit warning about IRQ # being fixed up (just like hpt366.c does) and "beautify" this whole function as well as init_setup_pdc20276()... Signed-off-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/pdc202xx_new.c | 60 +++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 7b0e479c355c..7c5544d10b9a 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -524,44 +524,52 @@ static int __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d) return ide_setup_pci_device(dev, d); } -static int __devinit init_setup_pdc20270(struct pci_dev *dev, - ide_pci_device_t *d) +static int __devinit init_setup_pdc20270(struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *findev = NULL; - int ret; + struct pci_dev *bridge = dev->bus->self; + + if (bridge != NULL && + bridge->vendor == PCI_VENDOR_ID_DEC && + bridge->device == PCI_DEVICE_ID_DEC_21150) { + struct pci_dev *dev2; - if ((dev->bus->self && - dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && - (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) { if (PCI_SLOT(dev->devfn) & 2) return -ENODEV; - while ((findev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - (PCI_SLOT(findev->devfn) & 2)) { - if (findev->irq != dev->irq) { - findev->irq = dev->irq; - } - ret = ide_setup_pci_devices(dev, findev, d); - if (ret < 0) - pci_dev_put(findev); - return ret; + dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 2, + PCI_FUNC(dev->devfn))); + if (dev2 != NULL && + dev2->vendor == dev->vendor && + dev2->device == dev->device) { + int ret; + + if (dev2->irq != dev->irq) { + dev2->irq = dev->irq; + + printk(KERN_WARNING "%s: PCI config space " + "interrupt fixed.\n", d->name); } + + ret = ide_setup_pci_devices(dev, dev2, d); + if (ret < 0) + pci_dev_put(dev2); + return ret; } } return ide_setup_pci_device(dev, d); } -static int __devinit init_setup_pdc20276(struct pci_dev *dev, - ide_pci_device_t *d) +static int __devinit init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d) { - if ((dev->bus->self) && - (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) && - ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) || - (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) { - printk(KERN_INFO "ide: Skipping Promise PDC20276 " - "attached to I2O RAID controller.\n"); + struct pci_dev *bridge = dev->bus->self; + + if (bridge != NULL && + bridge->vendor == PCI_VENDOR_ID_INTEL && + (bridge->device == PCI_DEVICE_ID_INTEL_I960 || + bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) { + + printk(KERN_INFO "%s: attached to I2O RAID controller, " + "skipping.\n", d->name); return -ENODEV; } return ide_setup_pci_device(dev, d); From bda7970c27b1033de0afa737cd8e5abf9c55c3d2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: [PATCH 2181/2804] ide: make jmicron match vendor and device class PATA part of all current JMB controllers behave the same way and JMicron confirms that all future ones will stay compatible. Matching vendor and device class is enough. For backward compatibility, jmicron still needs to match 361,3,5,6,8 DIDs regardless of device class if libata is not configured but won't need further DID update from this point. Bart: cosmetic fixes to jmicron_chipset Signed-off-by: Tejun Heo Cc: Ethan Hsiao Cc: Justin Tsai Cc: Alan Cox Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/jmicron.c | 65 +++++++++++++++------------------------ 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 65a0ff352b98..17490d255758 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -160,22 +160,13 @@ fallback: return; } -#define DECLARE_JMB_DEV(name_str) \ - { \ - .name = name_str, \ - .init_hwif = init_hwif_jmicron, \ - .autodma = AUTODMA, \ - .bootable = ON_BOARD, \ - .enablebits = { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \ - .pio_mask = ATA_PIO5, \ - } - -static ide_pci_device_t jmicron_chipsets[] __devinitdata = { - /* 0 */ DECLARE_JMB_DEV("JMB361"), - /* 1 */ DECLARE_JMB_DEV("JMB363"), - /* 2 */ DECLARE_JMB_DEV("JMB365"), - /* 3 */ DECLARE_JMB_DEV("JMB366"), - /* 4 */ DECLARE_JMB_DEV("JMB368"), +static ide_pci_device_t jmicron_chipset __devinitdata = { + .name = "JMB", + .init_hwif = init_hwif_jmicron, + .autodma = AUTODMA, + .bootable = ON_BOARD, + .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } }, + .pio_mask = ATA_PIO5, }; /** @@ -189,35 +180,29 @@ static ide_pci_device_t jmicron_chipsets[] __devinitdata = { static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &jmicron_chipsets[id->driver_data]); + ide_setup_pci_device(dev, &jmicron_chipset); return 0; } -/* If libata is configured, jmicron PCI quirk will configure it such - * that the SATA ports are in AHCI function while the PATA ports are - * in a separate IDE function. In such cases, match device class and - * attach only to IDE. If libata isn't configured, keep the old - * behavior for backward compatibility. +/* All JMB PATA controllers have and will continue to have the same + * interface. Matching vendor and device class is enough for all + * current and future controllers if the controller is programmed + * properly. + * + * If libata is configured, jmicron PCI quirk programs the controller + * into the correct mode. If libata isn't configured, match known + * device IDs too to maintain backward compatibility. */ -#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE) -#define JMB_CLASS PCI_CLASS_STORAGE_IDE << 8 -#define JMB_CLASS_MASK 0xffff00 -#else -#define JMB_CLASS 0 -#define JMB_CLASS_MASK 0 -#endif - static struct pci_device_id jmicron_pci_tbl[] = { - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 0}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 1}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 2}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 3}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 4}, +#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE) + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) }, +#endif + { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, { 0, }, }; From 851dd33bcf23655eede62730c029e4f608f4084f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: [PATCH 2182/2804] ide: call udma_filter() before resorting to the UltraDMA mask Give the udma_filter() method call precedence over using the mode masks. Signed-off-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-dma.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 097d6e9865bc..f073ea35da00 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -664,10 +664,11 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) if ((id->field_valid & 4) == 0) break; - mask = id->dma_ultra & hwif->ultra_mask; - if (hwif->udma_filter) - mask &= hwif->udma_filter(drive); + mask = hwif->udma_filter(drive); + else + mask = hwif->ultra_mask; + mask &= id->dma_ultra; if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) mask &= 0x07; From a8028fcb485522c0d7de9c5423812de9224b37c9 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: [PATCH 2183/2804] ide: add missing ide_rate_filter() calls to ->speedproc()-s * Fix icside, cris-ide, au1xxx-ide, amd74xx, via82cxxx and pmac host drivers to use ide_rate_filter(). This results in the following modes (from user requests) being clipped down: - invalid modes (values 0x46-0xFF) [ for all hosts ] - unsupported by a host UDMA modes [ for hosts which support UDMA] - all UDMA modes and MWDMA3-4 modes [ for hosts which don't support UDMA ] - invalid modes (values 0x25-0x39) [ for hosts which don't support UDMA ] * Host driver specific changes in behavior: icside: - no change cris-ide - clip unsupported UDMA3-6 modes down - fix BUG() on trying to set unsupported UDMA3-6 modes au1xxx-ide/pmac - clip unsupported UDMA modes down amd74xx/via82cxxx - clip unsupported UDMA modes down - fix random PIO timings being set for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * While at it remove no longer needed checks from pmac.c driver. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/icside.c | 3 +-- drivers/ide/cris/ide-cris.c | 2 ++ drivers/ide/mips/au1xxx-ide.c | 2 ++ drivers/ide/pci/amd74xx.c | 2 ++ drivers/ide/pci/via82cxxx.c | 2 ++ drivers/ide/ppc/pmac.c | 10 ++-------- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 8a9b98fcb66d..28f910b5aa5d 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -255,8 +255,7 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) /* * Limit the transfer speed to MW_DMA_2. */ - if (xfer_mode > XFER_MW_DMA_2) - xfer_mode = XFER_MW_DMA_2; + xfer_mode = ide_rate_filter(drive, xfer_mode); switch (xfer_mode) { case XFER_MW_DMA_2: diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 04636f7eaae7..e08782ac88e0 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -726,6 +726,8 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed) { int cyc = 0, dvs = 0, strobe = 0, hold = 0; + speed = ide_rate_filter(drive, speed); + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { tune_cris_ide(drive, speed - XFER_PIO_0); return ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 2ba6a054b861..0d5e4c67fa54 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -180,6 +180,8 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) int mem_sttime; int mem_stcfg; + speed = ide_rate_filter(drive, speed); + mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 06c15a6a3e7d..3c0bb1e79514 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -240,6 +240,8 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed) struct ide_timing t, p; int T, UT; + speed = ide_rate_filter(drive, speed); + if (speed != XFER_PIO_SLOW) ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index a7be7795e6af..ec9ad6e0e1f6 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -165,6 +165,8 @@ static int via_set_drive(ide_drive_t *drive, u8 speed) struct ide_timing t, p; unsigned int T, UT; + speed = ide_rate_filter(drive, speed); + if (speed != XFER_PIO_SLOW) ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 2fb047b898aa..222adcb54823 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -928,6 +928,8 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; u32 *timings, *timings2; + speed = ide_rate_filter(drive, speed); + if (pmif == NULL) return 1; @@ -937,17 +939,9 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC case XFER_UDMA_6: - if (pmif->kind != controller_sh_ata6) - return 1; case XFER_UDMA_5: - if (pmif->kind != controller_un_ata6 && - pmif->kind != controller_k2_ata6 && - pmif->kind != controller_sh_ata6) - return 1; case XFER_UDMA_4: case XFER_UDMA_3: - if (drive->hwif->cbl != ATA_CBL_PATA80) - return 1; case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: From 7670df73fba373d19471a2ebedb3302ea0607be0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: [PATCH 2184/2804] ide: mode limiting fixes for user requested speed changes * Add an extra argument to ide_max_dma_mode() for passing requested transfer mode. Use it as an upper limit when finding the best DMA for device/host. * Rename ide_max_dma_mode() to ide_find_dma_mode() and at the same time add ide_max_dma_mode() wrapper which passes XFER_UDMA_6 as a requested mode to ide_find_dma_mode(). Also add inline ide_find_dma_mode() version for CONFIG_BLK_DEV_IDEDMA=n case. * Pass requested transfer mode from ide_find_dma_mode() to ide_get_mode_mask() to avoid false warning from eighty_ninty_three(). * Use ide_find_dma_mode() to limit the user requested transfer mode in ide_rate_filter(). Also limit the requested mode by host max PIO mode. Above changes make ide_rate_filter() to: * Clip desired transfer mode down if it is invalid (values 0x0F, 0x13-0x19 and 0x25-0x39, values > 0x46 were already clipped down, same for values 0x25-0x39 but iff UDMA was not supported by the host). * Clip desired transfer mode down if it is currently unsupported by IDE core (PIO6 and MWDMA3-4, the latter were already clipped down but iff UDMA was not supported by the host). * Clip desired transfer mode down according to the host capabilities (UDMA modes were already clipped down but MWDMA/SWDMA/PIO weren't, also ->atapi_dma flag was not respected). * Clip desired transfer mode down according to the device capabilities (except PIO modes for now which require mode work) - shouldn't be a problem since ide_set_xfer_rate() is called _after_ device has accepted given transfer mode. and also result in a number of host driver specific bugfixes: * icside - clip unsupported PIO5 mode down - fix unsupported/invalid modes being set in drive->current_speed * ide-cris - clip unsupported PIO5 and SWDMA0-2 modes down - clip DMA modes down for ATAPI devices - fix BUG() on unsupported/invalid modes * au1xxx-ide - clip unsupported PIO5, SWDMA0-2 and MWDMA0-2 (if BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=n) modes down * aec62xx - clip unsupported PIO5 and SWDMA0-2 modes down - clip DMA modes down for ATAPI devices - fix 0x00 being programmed as PIO timing for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * alim15x3 - clip DMA modes down for ATAPI devices (chipset revision == 0x20 only) - fix theoretical OOPS for 0x0F mode - fix unsupported/invalid modes being set on the device * amd74xx - clip unsupported SWDMA0-2 (on COBRA_7401 revs <= 7) modes down - fix random PIO timings being set for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * atiixp - clip unsupported PIO5 and SWDMA0-2 modes down - fix cached MWDMA mode being cleared for unsupported/invalid modes - fix PIO{0,2} timings being programmed for unsupported/invalid modes - fix theoretical OOPS for PIO5-6 and 0x0F modes - fix unsupported/invalid modes being set on the device * cmd64x - clip unsupported SWDMA0-2 modes down * cs5530 - clip unsupported PIO5 and SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device - fix BUG() on unsupported/invalid modes (which happened if the device accepted the setting) * cs5535 - clip unsupported PIO5 and SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device - fix theoretical OOPS for PIO5-6 and 0x0F modes * hpt34x - clip DMA modes down for ATAPI devices - fix invalid timings being programmed for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * hpt366 - clip unsupported PIO5 and SWDMA0-2 modes down - fix PIO0 timings being programmed for unsupported/invalid modes - fix DMA timings being cleared for MWDMA3-4 and 0x25-0x39 modes - fix unsupported/invalid modes being set on the device * it8213 - clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down * it821x - clip unsupported PIO5 and SWDMA0-2 modes down - clip DMA modes down for ATAPI devices (chipset in smart mode and revision 0x10 in pass-through mode) * jmicron - clip unsupported SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device * pdc202xx_new - clip unsupported PIO5 and SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device * pdc202xx_old - clip unsupported PIO5 mode down - fix incorrect timings being set for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * piix - clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down * sc1200 - clip unsupported PIO5 and SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device - fix BUG() on unsupported/invalid modes (which happened if the device accepted the setting) * scc_pata - clip unsupported PIO5, SWDMA0-2 and MWDMA0-2 modes down * serverworks - clip unsupported PIO5 and SWDMA0-2 modes down - fix DMA/UDMA timings/settings being cleared for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * siimage - clip unsupported PIO5 and SWDMA0-2 modes down - clip DMA modes down for ATAPI devices (SATA chipsets) * sis5513 - clip unsupported PIO5 mode down - fix BUG() on unsupported/invalid modes * sl82c105 - clip unsupported SWDMA0-2 modes down * slc90e66 - clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down * tc86c001 - clip unsupported PIO5 and SWDMA0-2 modes down - fix PIO0 timings being programmed for PIO5/0x0F/SWDMA0-2/0x13-0x19 modes - fix invalid 0x00 DMA timing being programmed for MWDMA3-4/0x25-0x39 modes - fix unsupported/invalid modes being set on the device * triflex - clip unsupported PIO5 mode down * via82cxxx - fix random PIO timings being set for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * pmac - clip unsupported PIO5 and SWDMA0-2 modes down * cmd640/ht6560b - clip DMA modes down (if CONFIG_BLK_DEV_IDEDMA=y) - fix PIO5 being clipped to PIO4 (if CONFIG_BLK_DEV_IDEDMA=n) * opti621 - clip DMA modes down (if CONFIG_BLK_DEV_IDEDMA=y) - clip unsupported PIO4 to PIO3 (if CONFIG_BLK_DEV_IDEDMA=n) While at it: * Use ide_rate_filter() in cs5520.c::cs5520_tune_chipset(). * Remove no longer needed checks from hpt366.c::hpt3{6,7}x_tune_chipset(). Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-dma.c | 32 +++++++++++++++++++++----------- drivers/ide/ide-lib.c | 27 +++++++-------------------- drivers/ide/pci/cs5520.c | 2 +- drivers/ide/pci/hpt366.c | 8 -------- include/linux/ide.h | 10 +++++++++- 5 files changed, 38 insertions(+), 41 deletions(-) diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index f073ea35da00..6000c08f51ba 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -653,7 +653,7 @@ static const u8 xfer_mode_bases[] = { XFER_SW_DMA_0, }; -static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) +static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = drive->hwif; @@ -670,8 +670,13 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) mask = hwif->ultra_mask; mask &= id->dma_ultra; - if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) - mask &= 0x07; + /* + * avoid false cable warning from eighty_ninty_three() + */ + if (req_mode > XFER_UDMA_2) { + if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) + mask &= 0x07; + } break; case XFER_MW_DMA_0: if ((id->field_valid & 2) == 0) @@ -709,15 +714,18 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) } /** - * ide_max_dma_mode - compute DMA speed + * ide_find_dma_mode - compute DMA speed * @drive: IDE device + * @req_mode: requested mode * - * Checks the drive capabilities and returns the speed to use - * for the DMA transfer. Returns 0 if the drive is incapable - * of DMA transfers. + * Checks the drive/host capabilities and finds the speed to use for + * the DMA transfer. The speed is then limited by the requested mode. + * + * Returns 0 if the drive/host combination is incapable of DMA transfers + * or if the requested mode is not a DMA mode. */ -u8 ide_max_dma_mode(ide_drive_t *drive) +u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) { ide_hwif_t *hwif = drive->hwif; unsigned int mask; @@ -728,7 +736,9 @@ u8 ide_max_dma_mode(ide_drive_t *drive) return 0; for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) { - mask = ide_get_mode_mask(drive, xfer_mode_bases[i]); + if (req_mode < xfer_mode_bases[i]) + continue; + mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode); x = fls(mask) - 1; if (x >= 0) { mode = xfer_mode_bases[i] + x; @@ -738,10 +748,10 @@ u8 ide_max_dma_mode(ide_drive_t *drive) printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode); - return mode; + return min(mode, req_mode); } -EXPORT_SYMBOL_GPL(ide_max_dma_mode); +EXPORT_SYMBOL_GPL(ide_find_dma_mode); int ide_tune_dma(ide_drive_t *drive) { diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 92a6c7bcf527..41a128f52112 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -76,37 +76,24 @@ EXPORT_SYMBOL(ide_xfer_verbose); * Given the available transfer modes this function returns * the best available speed at or below the speed requested. * - * FIXME: filter also PIO/SWDMA/MWDMA modes + * TODO: check device PIO capabilities */ u8 ide_rate_filter(ide_drive_t *drive, u8 speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA ide_hwif_t *hwif = drive->hwif; - u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2; + u8 mode = ide_find_dma_mode(drive, speed); - if (hwif->udma_filter) - mask = hwif->udma_filter(drive); - - /* - * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false - * cable warning from eighty_ninty_three(), moving ide_rate_filter() - * calls from ->speedproc to core code will make this hack go away - */ - if (speed > XFER_UDMA_2) { - if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) - mask &= 0x07; + if (mode == 0) { + if (hwif->pio_mask) + mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0; + else + mode = XFER_PIO_4; } - if (mask) - mode = fls(mask) - 1 + XFER_UDMA_0; - // printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed); return min(speed, mode); -#else /* !CONFIG_BLK_DEV_IDEDMA */ - return min(speed, (u8)XFER_PIO_4); -#endif /* CONFIG_BLK_DEV_IDEDMA */ } EXPORT_SYMBOL(ide_rate_filter); diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index b89e81656875..507981042c82 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -70,7 +70,7 @@ static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *pdev = hwif->pci_dev; - u8 speed = min((u8)XFER_PIO_4, xferspeed); + u8 speed = ide_rate_filter(drive, xferspeed); int pio = speed; u8 reg; int controller = drive->dn > 1 ? 1 : 0; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 3d8d6b2ee41a..18c8ad091eb3 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -610,10 +610,6 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) u32 old_itr = 0; u32 itr_mask, new_itr; - /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */ - if (drive->media != ide_disk) - speed = min_t(u8, speed, XFER_PIO_4); - itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 : (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff); @@ -642,10 +638,6 @@ static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed) u32 old_itr = 0; u32 itr_mask, new_itr; - /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */ - if (drive->media != ide_disk) - speed = min_t(u8, speed, XFER_PIO_4); - itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 : (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff); diff --git a/include/linux/ide.h b/include/linux/ide.h index 80ea946282d7..a3f9c216615e 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1296,7 +1296,14 @@ int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *); #ifdef CONFIG_BLK_DEV_IDEDMA int __ide_dma_bad_drive(ide_drive_t *); int __ide_dma_good_drive(ide_drive_t *); -u8 ide_max_dma_mode(ide_drive_t *); + +u8 ide_find_dma_mode(ide_drive_t *, u8); + +static inline u8 ide_max_dma_mode(ide_drive_t *drive) +{ + return ide_find_dma_mode(drive, XFER_UDMA_6); +} + int ide_tune_dma(ide_drive_t *); void ide_dma_off(ide_drive_t *); void ide_dma_verbose(ide_drive_t *); @@ -1322,6 +1329,7 @@ extern void ide_dma_timeout(ide_drive_t *); #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ #else +static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; } static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; } static inline int ide_tune_dma(ide_drive_t *drive) { return 0; } static inline void ide_dma_off(ide_drive_t *drive) { ; } From 3160d5416f39da9d9221fec7cb9d64399b706bbc Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: [PATCH 2185/2804] sis5513: add ->udma_filter method for chipset_family >= ATA_133 * Add sis5513_ata133_udma_filter() for chipset_family >= ATA_133, use it to filter UDMA6 mode if ATA133 bit is disabled. * Remove no longer needed UDMA6 limiting logic from sis5513_tune_chipset(). * Bump driver version. There should be no functionality changes caused by this patch. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sis5513.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 26f24802d3e8..1da037f1394e 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/sis5513.c Version 0.25 Jun 10, 2007 + * linux/drivers/ide/pci/sis5513.c Version 0.26 Jul 7, 2007 * * Copyright (C) 1999-2000 Andre Hedrick * Copyright (C) 2002 Lionel Bouton , Maintainer @@ -582,9 +582,6 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; } else { - /* if ATA133 disable, we should not set speed above UDMA5 */ - if (speed > XFER_UDMA_5) - speed = XFER_UDMA_5; regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; } @@ -640,6 +637,20 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive) return -1; } +static u8 sis5513_ata133_udma_filter(ide_drive_t *drive) +{ + struct pci_dev *dev = drive->hwif->pci_dev; + int drive_pci; + u32 reg54 = 0, regdw = 0; + + pci_read_config_dword(dev, 0x54, ®54); + drive_pci = ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4; + pci_read_config_dword(dev, drive_pci, ®dw); + + /* if ATA133 disable, we should not set speed above UDMA5 */ + return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5; +} + /* Chip detection and general config */ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name) { @@ -847,6 +858,9 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif) hwif->tuneproc = &sis5513_tuneproc; hwif->speedproc = &sis5513_tune_chipset; + if (chipset_family >= ATA_133) + hwif->udma_filter = sis5513_ata133_udma_filter; + if (!(hwif->dma_base)) { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; From f212ff28f08e4ddcef9f25b13463c45cc4204a0c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: [PATCH 2186/2804] ide: move ide_rate_filter() calls to the upper layer (take 2) * Move ide_rate_filter() calls from host drivers to IDE core. * Make ide_rate_filter() static. * Make 'speed' argument of ->speedproc const. v2: * Fix it8213_tune_chipset() comment. There should be no functionality changes caused by this patch. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/icside.c | 7 +------ drivers/ide/cris/ide-cris.c | 4 +--- drivers/ide/ide-lib.c | 17 ++++++++--------- drivers/ide/mips/au1xxx-ide.c | 4 +--- drivers/ide/pci/aec62xx.c | 6 ++---- drivers/ide/pci/alim15x3.c | 7 +++---- drivers/ide/pci/amd74xx.c | 4 +--- drivers/ide/pci/atiixp.c | 8 +++----- drivers/ide/pci/cmd64x.c | 4 +--- drivers/ide/pci/cs5520.c | 5 ++--- drivers/ide/pci/cs5530.c | 4 +--- drivers/ide/pci/cs5535.c | 3 +-- drivers/ide/pci/hpt34x.c | 3 +-- drivers/ide/pci/hpt366.c | 6 ++---- drivers/ide/pci/it8213.c | 10 +++------- drivers/ide/pci/it821x.c | 10 +++------- drivers/ide/pci/jmicron.c | 9 +++------ drivers/ide/pci/pdc202xx_new.c | 4 +--- drivers/ide/pci/pdc202xx_old.c | 3 +-- drivers/ide/pci/piix.c | 7 +++---- drivers/ide/pci/sc1200.c | 4 +--- drivers/ide/pci/scc_pata.c | 5 ++--- drivers/ide/pci/serverworks.c | 3 +-- drivers/ide/pci/siimage.c | 11 ++++------- drivers/ide/pci/sis5513.c | 7 ++----- drivers/ide/pci/sl82c105.c | 4 +--- drivers/ide/pci/slc90e66.c | 3 +-- drivers/ide/pci/tc86c001.c | 4 +--- drivers/ide/pci/triflex.c | 3 +-- drivers/ide/pci/via82cxxx.c | 4 +--- drivers/ide/ppc/pmac.c | 6 +----- include/linux/ide.h | 3 +-- 32 files changed, 59 insertions(+), 123 deletions(-) diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 28f910b5aa5d..99a27f2dc03a 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -248,15 +248,10 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq) * MW1 80 50 50 150 C * MW2 70 25 25 120 C */ -static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) +static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) { int on = 0, cycle_time = 0, use_dma_info = 0; - /* - * Limit the transfer speed to MW_DMA_2. - */ - xfer_mode = ide_rate_filter(drive, xfer_mode); - switch (xfer_mode) { case XFER_MW_DMA_2: cycle_time = 250; diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index e08782ac88e0..67cec8916fcd 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -722,12 +722,10 @@ static void tune_cris_ide(ide_drive_t *drive, u8 pio) (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int speed_cris_ide(ide_drive_t *drive, u8 speed) +static int speed_cris_ide(ide_drive_t *drive, const u8 speed) { int cyc = 0, dvs = 0, strobe = 0, hold = 0; - speed = ide_rate_filter(drive, speed); - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { tune_cris_ide(drive, speed - XFER_PIO_0); return ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 41a128f52112..957618849540 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -79,7 +79,7 @@ EXPORT_SYMBOL(ide_xfer_verbose); * TODO: check device PIO capabilities */ -u8 ide_rate_filter(ide_drive_t *drive, u8 speed) +static u8 ide_rate_filter(ide_drive_t *drive, u8 speed) { ide_hwif_t *hwif = drive->hwif; u8 mode = ide_find_dma_mode(drive, speed); @@ -96,8 +96,6 @@ u8 ide_rate_filter(ide_drive_t *drive, u8 speed) return min(speed, mode); } -EXPORT_SYMBOL(ide_rate_filter); - int ide_use_fast_pio(ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -364,13 +362,14 @@ void ide_toggle_bounce(ide_drive_t *drive, int on) int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) { -#ifndef CONFIG_BLK_DEV_IDEDMA - rate = min(rate, (u8) XFER_PIO_4); -#endif - if(HWIF(drive)->speedproc) - return HWIF(drive)->speedproc(drive, rate); - else + ide_hwif_t *hwif = drive->hwif; + + if (hwif->speedproc == NULL) return -1; + + rate = ide_rate_filter(drive, rate); + + return hwif->speedproc(drive, rate); } static void ide_dump_opcode(ide_drive_t *drive) diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 0d5e4c67fa54..b04db9ff1938 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -175,13 +175,11 @@ static void auide_tune_drive(ide_drive_t *drive, byte pio) ide_config_drive_speed(drive, speed); } -static int auide_tune_chipset (ide_drive_t *drive, u8 speed) +static int auide_tune_chipset(ide_drive_t *drive, const u8 speed) { int mem_sttime; int mem_stcfg; - speed = ide_rate_filter(drive, speed); - mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index 74432830abf7..a827ea2ab989 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -87,12 +87,11 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr return chipset_table->ultra_settings; } -static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u16 d_conf = 0; - u8 speed = ide_rate_filter(drive, xferspeed); u8 ultra = 0, ultra_conf = 0; u8 tmp0 = 0, tmp1 = 0, tmp2 = 0; unsigned long flags; @@ -115,11 +114,10 @@ static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed) return(ide_config_drive_speed(drive, speed)); } -static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); u8 unit = (drive->select.b.unit & 0x01); u8 tmp1 = 0, tmp2 = 0; u8 ultra = 0, drive_conf = 0, ultra_conf = 0; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 11ecb618007c..37ecd726aa40 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -409,17 +409,16 @@ static u8 ali_udma_filter(ide_drive_t *drive) /** * ali15x3_tune_chipset - set up chipset/drive for new speed * @drive: drive to configure for - * @xferspeed: desired speed + * @speed: desired speed * * Configure the hardware for the desired IDE transfer mode. * We also do the needed drive configuration through helpers */ - -static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed) + +static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); u8 speed1 = speed; u8 unit = (drive->select.b.unit & 0x01); u8 tmpbyte = 0x00; diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 3c0bb1e79514..9abbde3c7984 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -234,14 +234,12 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi * by upper layers. */ -static int amd_set_drive(ide_drive_t *drive, u8 speed) +static int amd_set_drive(ide_drive_t *drive, const u8 speed) { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); struct ide_timing t, p; int T, UT; - speed = ide_rate_filter(drive, speed); - if (speed != XFER_PIO_SLOW) ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 679eb92b8920..e05e88298500 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -163,23 +163,21 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio) /** * atiixp_tune_chipset - tune a ATIIXP interface * @drive: IDE drive to tune - * @xferspeed: speed to configure + * @speed: speed to configure * * Set a ATIIXP interface channel to the desired speeds. This involves * requires the right timing data into the ATIIXP configuration space * then setting the drive parameters appropriately */ -static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed) +static int atiixp_speedproc(ide_drive_t *drive, const u8 speed) { struct pci_dev *dev = drive->hwif->pci_dev; unsigned long flags; int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; u32 tmp32; u16 tmp16; - u8 speed, pio; - - speed = ide_rate_filter(drive, xferspeed); + u8 pio; if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { atiixp_tune_pio(drive, speed - XFER_PIO_0); diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 0e3b5de26e69..5fe50a234ce1 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -288,15 +288,13 @@ static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio) (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed) +static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 unit = drive->dn & 0x01; u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; - speed = ide_rate_filter(drive, speed); - if (speed >= XFER_SW_DMA_0) { (void) pci_read_config_byte(dev, pciU, ®U); regU &= ~(unit ? 0xCA : 0x35); diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 507981042c82..af67438328a8 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -66,16 +66,15 @@ static struct pio_clocks cs5520_pio_clocks[]={ {1, 2, 1} }; -static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *pdev = hwif->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); int pio = speed; u8 reg; int controller = drive->dn > 1 ? 1 : 0; int error; - + switch(speed) { case XFER_PIO_4: diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index e5949b1d3fb0..518f430c1529 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -143,13 +143,11 @@ static int cs5530_config_dma(ide_drive_t *drive) return 1; } -static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode) +static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode) { unsigned long basereg; unsigned int reg, timings = 0; - mode = ide_rate_filter(drive, mode); - /* * Tell the drive to switch to the new mode; abort on failure. */ diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index 082ca7da2cbc..bc00e7b62151 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -75,7 +75,7 @@ static unsigned int cs5535_udma_timings[5] = * * cs5535_set_speed() configures the chipset to a new speed. */ -static void cs5535_set_speed(ide_drive_t *drive, u8 speed) +static void cs5535_set_speed(ide_drive_t *drive, const u8 speed) { u32 reg = 0, dummy; @@ -141,7 +141,6 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed) */ static int cs5535_set_drive(ide_drive_t *drive, u8 speed) { - speed = ide_rate_filter(drive, speed); ide_config_drive_speed(drive, speed); cs5535_set_speed(drive, speed); diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index cb8fe5643d3b..ba982d66ff73 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -43,10 +43,9 @@ #define HPT343_DEBUG_DRIVE_INFO 0 -static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed) { struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0; u8 hi_speed, lo_speed; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 18c8ad091eb3..67127ac3a14a 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -600,12 +600,11 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info) return (*info->settings)[i]; } -static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; struct hpt_info *info = pci_get_drvdata(dev); - u8 speed = ide_rate_filter(drive, xferspeed); u8 itr_addr = drive->dn ? 0x44 : 0x40; u32 old_itr = 0; u32 itr_mask, new_itr; @@ -628,12 +627,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) return ide_config_drive_speed(drive, speed); } -static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; struct hpt_info *info = pci_get_drvdata(dev); - u8 speed = ide_rate_filter(drive, xferspeed); u8 itr_addr = 0x40 + (drive->dn * 4); u32 old_itr = 0; u32 itr_mask, new_itr; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 70b3245dbf62..6fa955749aec 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -115,20 +115,16 @@ static void it8213_tuneproc(ide_drive_t *drive, u8 pio) /** * it8213_tune_chipset - set controller timings * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * - * Tune the ITE chipset for the desired mode. If we can't achieve - * the desired mode then tune for a lower one, but ultimately - * make the thing work. + * Tune the ITE chipset for the desired mode. */ -static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 maslave = 0x40; - u8 speed = ide_rate_filter(drive, xferspeed); int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; int v_flag = 0x01 << drive->dn; diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 9286c99e2ff0..a756e61bcb32 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -405,23 +405,19 @@ static int it821x_dma_end(ide_drive_t *drive) return ret; } - /** * it821x_tune_chipset - set controller timings * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * - * Tune the ITE chipset for the desired mode. If we can't achieve - * the desired mode then tune for a lower one, but ultimately - * make the thing work. + * Tune the ITE chipset for the desired mode. */ -static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed) +static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); - u8 speed = ide_rate_filter(drive, xferspeed); switch (speed) { case XFER_PIO_4: diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 17490d255758..7bac87fb481a 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -92,17 +92,14 @@ static void jmicron_tuneproc(ide_drive_t *drive, u8 pio) /** * jmicron_tune_chipset - set controller timings * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * * As the JMicron snoops for timings all we actually need to do is - * make sure we don't set an invalid mode. We do need to honour - * the cable detect here. + * set the transfer mode on the device. */ -static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed) +static int jmicron_tune_chipset(ide_drive_t *drive, const u8 speed) { - u8 speed = ide_rate_filter(drive, xferspeed); - return ide_config_drive_speed(drive, speed); } diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 7c5544d10b9a..3787194a2249 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -146,14 +146,12 @@ static struct udma_timing { { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ }; -static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed) +static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; int err; - speed = ide_rate_filter(drive, speed); - /* * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will * automatically set the timing registers based on 100 MHz PLL output. diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index e19a891171cb..e7a5e3014c09 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -63,12 +63,11 @@ static const char *pdc_quirk_drives[] = { static void pdc_old_disable_66MHz_clock(ide_hwif_t *); -static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 drive_pci = 0x60 + (drive->dn << 2); - u8 speed = ide_rate_filter(drive, xferspeed); u8 AP = 0, BP = 0, CP = 0; u8 TA = 0, TB = 0, TC = 0; diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 5cfa9378bbb8..b66f9d1411b3 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -221,19 +221,18 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) /** * piix_tune_chipset - tune a PIIX interface * @drive: IDE drive to tune - * @xferspeed: speed to configure + * @speed: speed to configure * * Set a PIIX interface channel to the desired speeds. This involves * requires the right timing data into the PIIX configuration space * then setting the drive parameters appropriately */ - -static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed) + +static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 maslave = hwif->channel ? 0x42 : 0x40; - u8 speed = ide_rate_filter(drive, xferspeed); int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; int v_flag = 0x01 << drive->dn; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 9bdc9694d50d..059071cd2d49 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -138,7 +138,7 @@ out: return mask; } -static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode) +static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) { ide_hwif_t *hwif = HWIF(drive); int unit = drive->select.b.unit; @@ -146,8 +146,6 @@ static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode) unsigned short pci_clock; unsigned int basereg = hwif->channel ? 0x50 : 0x40; - mode = ide_rate_filter(drive, mode); - /* * Tell the drive to switch to the new mode; abort on failure. */ diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index eeb0a6d434aa..a19687caf65a 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -231,16 +231,15 @@ static void scc_tuneproc(ide_drive_t *drive, u8 pio) /** * scc_tune_chipset - tune a drive DMA mode * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * * Load the timing settings for this device mode into the * controller. */ -static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed) +static int scc_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - u8 speed = ide_rate_filter(drive, xferspeed); struct scc_ports *ports = ide_get_hwifdata(hwif); unsigned long ctl_base = ports->ctl; unsigned long cckctrl_port = ctl_base + 0xff0; diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index 9fead2e7d4c8..b51133bb58af 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -145,7 +145,7 @@ static void svwks_tune_pio(ide_drive_t *drive, const u8 pio) } } -static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed) { static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; static const u8 dma_modes[] = { 0x77, 0x21, 0x20 }; @@ -153,7 +153,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); u8 unit = (drive->select.b.unit & 0x01); u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 50f6d172ef77..4c1f3bc7e179 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -229,14 +229,12 @@ static void sil_tuneproc(ide_drive_t *drive, u8 pio) /** * siimage_tune_chipset - set controller timings * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * - * Tune the SII chipset for the desired mode. If we can't achieve - * the desired mode then tune for a lower one, but ultimately - * make the thing work. + * Tune the SII chipset for the desired mode. */ - -static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) + +static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) { u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; @@ -245,7 +243,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) ide_hwif_t *hwif = HWIF(drive); u16 ultra = 0, multi = 0; u8 mode = 0, unit = drive->select.b.unit; - u8 speed = ide_rate_filter(drive, xferspeed); unsigned long base = (unsigned long)hwif->hwif_data; u8 scsc = 0, addr_mask = ((hwif->channel) ? ((hwif->mmio) ? 0xF4 : 0x84) : diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 1da037f1394e..fed582b4b32f 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -531,15 +531,12 @@ static void sis5513_tuneproc(ide_drive_t *drive, u8 pio) (void)sis5513_tune_drive(drive, pio); } -static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - - u8 drive_pci, reg, speed; u32 regdw; - - speed = ide_rate_filter(drive, xferspeed); + u8 drive_pci, reg; /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 0947cab00595..9f425b0b5721 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -113,7 +113,7 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio) /* * Configure the drive and chipset for a new transfer speed. */ -static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed) +static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed) { static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200}; u16 drv_ctrl; @@ -121,8 +121,6 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed) DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n", drive->name, ide_xfer_verbose(speed))); - speed = ide_rate_filter(drive, speed); - switch (speed) { case XFER_MW_DMA_2: case XFER_MW_DMA_1: diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 628b0664f576..cc9353565070 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -102,12 +102,11 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 maslave = hwif->channel ? 0x42 : 0x40; - u8 speed = ide_rate_filter(drive, xferspeed); int sitre = 0, a_speed = 7 << (drive->dn * 4); int u_speed = 0, u_flag = 1 << drive->dn; u16 reg4042, reg44, reg48, reg4a; diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index ec79bacc30c2..e5425772622f 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -13,14 +13,12 @@ #include #include -static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed) +static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00); u16 mode, scr = hwif->INW(scr_port); - speed = ide_rate_filter(drive, speed); - switch (speed) { case XFER_UDMA_4: mode = 0x00c0; break; case XFER_UDMA_3: mode = 0x00b0; break; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index 098692a6d615..47cf89be4dfc 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -40,7 +40,7 @@ #include #include -static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -48,7 +48,6 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed) u16 timing = 0; u32 triflex_timings = 0; u8 unit = (drive->select.b.unit & 0x01); - u8 speed = ide_rate_filter(drive, xferspeed); pci_read_config_dword(dev, channel_offset, &triflex_timings); diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index ec9ad6e0e1f6..e3bf90736332 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -158,15 +158,13 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) * by upper layers. */ -static int via_set_drive(ide_drive_t *drive, u8 speed) +static int via_set_drive(ide_drive_t *drive, const u8 speed) { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev); struct ide_timing t, p; unsigned int T, UT; - speed = ide_rate_filter(drive, speed); - if (speed != XFER_PIO_SLOW) ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 222adcb54823..284bb7c39b87 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -411,7 +411,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time) static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif); static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq); -static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed); static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio); static void pmac_ide_selectproc(ide_drive_t *drive); static void pmac_ide_kauai_selectproc(ide_drive_t *drive); @@ -920,16 +919,13 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, * our dedicated function is more precise as it uses the drive provided * cycle time value. We should probably fix this one to deal with that too... */ -static int -pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) +static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) { int unit = (drive->select.b.unit & 0x01); int ret = 0; pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; u32 *timings, *timings2; - speed = ide_rate_filter(drive, speed); - if (pmif == NULL) return 1; diff --git a/include/linux/ide.h b/include/linux/ide.h index a3f9c216615e..81736cb7ef3d 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -705,7 +705,7 @@ typedef struct hwif_s { /* routine to tune PIO mode for drives */ void (*tuneproc)(ide_drive_t *, u8); /* routine to retune DMA modes for drives */ - int (*speedproc)(ide_drive_t *, u8); + int (*speedproc)(ide_drive_t *, const u8); /* tweaks hardware to select drive */ void (*selectproc)(ide_drive_t *); /* chipset polling based on hba specifics */ @@ -1378,7 +1378,6 @@ static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data) } /* ide-lib.c */ -u8 ide_rate_filter(ide_drive_t *, u8); extern char *ide_xfer_verbose(u8 xfer_rate); extern void ide_toggle_bounce(ide_drive_t *drive, int on); extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate); From 842c19ad6fc0dbd9ac9d2f8527466201802934cf Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: [PATCH 2187/2804] ide: Kconfig face-lift * Convert config options for PCI host drivers to select BLK_DEV_IDEPCI. * Same for BLK_DEV_IDEDMA_PCI and PCI DMA host drivers, also make this config option select BLK_DEV_IDEPCI. * Remove no longer needed help for BLK_DEV_IDEPCI and BLK_DEV_IDEDMA_PCI. * Remove redundant IDE_CHIPSETS config option. As a result of this patch users have now three less config options to worry about and can just select host drivers that they need (IDE config menu is "flatter"). Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 102 ++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 75b2737510a6..aa0e0c9f74c5 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -359,17 +359,16 @@ config BLK_DEV_IDEPNP would like the kernel to automatically detect and activate it, say Y here. +if PCI + +comment "PCI IDE chipsets support" + config BLK_DEV_IDEPCI - bool "PCI IDE chipset support" if PCI - default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDEDMA_PMAC - help - Say Y here for PCI systems which use IDE drive(s). - This option helps the IDE driver to automatically detect and - configure all PCI-based IDE interfaces in your system. + bool config IDEPCI_SHARE_IRQ bool "Sharing PCI IDE interrupts support" - depends on PCI && BLK_DEV_IDEPCI + depends on BLK_DEV_IDEPCI help Some ATA/IDE chipsets have hardware support which allows for sharing a single IRQ with other cards. To enable support for @@ -379,11 +378,11 @@ config IDEPCI_SHARE_IRQ If unsure, say N. config IDEPCI_PCIBUS_ORDER - def_bool PCI && BLK_DEV_IDE=y && BLK_DEV_IDEPCI + def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI config BLK_DEV_OFFBOARD bool "Boot off-board chipsets first support" - depends on PCI && BLK_DEV_IDEPCI + depends on BLK_DEV_IDEPCI help Normally, IDE controllers built into the motherboard (on-board controllers) are assigned to ide0 and ide1 while those on add-in PCI @@ -406,21 +405,23 @@ config BLK_DEV_OFFBOARD config BLK_DEV_GENERIC tristate "Generic PCI IDE Chipset Support" - depends on BLK_DEV_IDEPCI + select BLK_DEV_IDEPCI help This option provides generic support for various PCI IDE Chipsets which otherwise might not be supported. config BLK_DEV_OPTI621 tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)" - depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL + depends on EXPERIMENTAL + select BLK_DEV_IDEPCI help This is a driver for the OPTi 82C621 EIDE controller. Please read the comments at the top of . config BLK_DEV_RZ1000 tristate "RZ1000 chipset bugfix/support" - depends on PCI && BLK_DEV_IDEPCI && X86 + depends on X86 + select BLK_DEV_IDEPCI help The PC-Technologies RZ1000 IDE chip is used on many common 486 and Pentium motherboards, usually along with the "Neptune" chipset. @@ -431,35 +432,21 @@ config BLK_DEV_RZ1000 things will operate 100% reliably. config BLK_DEV_IDEDMA_PCI - bool "Generic PCI bus-master DMA support" - depends on PCI && BLK_DEV_IDEPCI - ---help--- - If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and - is capable of bus-master DMA operation (most Pentium PCI systems), - you will want to say Y here to reduce CPU overhead. You can then use - the "hdparm" utility to enable DMA for drives for which it was not - enabled automatically. By default, DMA is not enabled automatically - for these drives, but you can change that by saying Y to the - following question "Use DMA by default when available". You can get - the latest version of the hdparm utility from - . - - Read the comments at the beginning of - and the file for more information. - - It is safe to say Y to this question. - -if BLK_DEV_IDEDMA_PCI + bool + select BLK_DEV_IDEPCI config BLK_DEV_IDEDMA_FORCED bool "Force enable legacy 2.0.X HOSTS to use DMA" + depends on BLK_DEV_IDEDMA_PCI help This is an old piece of lost code from Linux 2.0 Kernels. Generally say N here. +# TODO: remove it config IDEDMA_ONLYDISK bool "Enable DMA only for disks " + depends on BLK_DEV_IDEDMA_PCI help This is used if you know your ATAPI Devices are going to fail DMA Transfers. @@ -468,6 +455,7 @@ config IDEDMA_ONLYDISK config BLK_DEV_AEC62XX tristate "AEC62XX chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for Acard AEC62xx (Artop ATP8xx) IDE controllers. This allows the kernel to change PIO, DMA and UDMA @@ -475,6 +463,7 @@ config BLK_DEV_AEC62XX config BLK_DEV_ALI15X3 tristate "ALI M15x3 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C onboard chipsets. It also tests for Simplex mode and enables @@ -503,6 +492,7 @@ config WDC_ALI15X3 config BLK_DEV_AMD74XX tristate "AMD and nVidia IDE support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for AMD-7xx and AMD-8111 chips and also for the nVidia nForce chip. This allows the kernel to @@ -512,6 +502,7 @@ config BLK_DEV_AMD74XX config BLK_DEV_ATIIXP tristate "ATI IXP chipset IDE support" depends on X86 + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for ATI IXP chipset. This allows the kernel to change PIO, DMA and UDMA speeds @@ -521,18 +512,21 @@ config BLK_DEV_ATIIXP config BLK_DEV_CMD64X tristate "CMD64{3|6|8|9} chipset support" + select BLK_DEV_IDEDMA_PCI help Say Y here if you have an IDE controller which uses any of these chipsets: CMD643, CMD646, or CMD648. config BLK_DEV_TRIFLEX tristate "Compaq Triflex IDE support" + select BLK_DEV_IDEDMA_PCI help Say Y here if you have a Compaq Triflex IDE controller, such as those commonly found on Compaq Pentium-Pro systems config BLK_DEV_CY82C693 tristate "CY82C693 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds detection and support for the CY82C693 chipset used on Digital's PC-Alpha 164SX boards. @@ -543,6 +537,7 @@ config BLK_DEV_CY82C693 config BLK_DEV_CS5520 tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)" depends on EXPERIMENTAL + select BLK_DEV_IDEDMA_PCI help Include support for PIO tuning and virtual DMA on the Cyrix MediaGX 5510/5520 chipset. This will automatically be detected and @@ -552,6 +547,7 @@ config BLK_DEV_CS5520 config BLK_DEV_CS5530 tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support" + select BLK_DEV_IDEDMA_PCI help Include support for UDMA on the Cyrix MediaGX 5530 chipset. This will automatically be detected and configured if found. @@ -561,6 +557,7 @@ config BLK_DEV_CS5530 config BLK_DEV_CS5535 tristate "AMD CS5535 chipset support" depends on X86 && !X86_64 + select BLK_DEV_IDEDMA_PCI help Include support for UDMA on the NSC/AMD CS5535 companion chipset. This will automatically be detected and configured if found. @@ -569,6 +566,7 @@ config BLK_DEV_CS5535 config BLK_DEV_HPT34X tristate "HPT34X chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds up to 4 more EIDE devices sharing a single interrupt. The HPT343 chipset in its current form is a non-bootable @@ -589,7 +587,8 @@ config HPT34X_AUTODMA config BLK_DEV_HPT366 tristate "HPT36X/37X chipset support" - ---help--- + select BLK_DEV_IDEDMA_PCI + help HPT366 is an Ultra DMA chipset for ATA-66. HPT368 is an Ultra DMA chipset for ATA-66 RAID Based. HPT370 is an Ultra DMA chipset for ATA-100. @@ -613,18 +612,21 @@ config BLK_DEV_HPT366 config BLK_DEV_JMICRON tristate "JMicron JMB36x support" + select BLK_DEV_IDEDMA_PCI help Basic support for the JMicron ATA controllers. For full support use the libata drivers. config BLK_DEV_SC1200 tristate "National SCx200 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for the built in IDE on the National SCx200 series of embedded x86 "Geode" systems config BLK_DEV_PIIX tristate "Intel PIIXn chipsets support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for Intel PIIX and ICH chips and also for the Efar Victory66 (slc90e66) chip. This allows @@ -633,17 +635,20 @@ config BLK_DEV_PIIX config BLK_DEV_IT8213 tristate "IT8213 IDE support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for the ITE 8213 IDE controller. config BLK_DEV_IT821X tristate "IT821X IDE support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for the ITE 8211 IDE controller and the IT 8212 IDE RAID controller in both RAID and pass-through mode. config BLK_DEV_NS87415 tristate "NS87415 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds detection and support for the NS87415 chip (used mainly on SPARC64 and PA-RISC machines). @@ -652,6 +657,7 @@ config BLK_DEV_NS87415 config BLK_DEV_PDC202XX_OLD tristate "PROMISE PDC202{46|62|65|67} support" + select BLK_DEV_IDEDMA_PCI help Promise Ultra33 or PDC20246 Promise Ultra66 or PDC20262 @@ -693,9 +699,11 @@ config PDC202XX_BURST config BLK_DEV_PDC202XX_NEW tristate "PROMISE PDC202{68|69|70|71|75|76|77} support" + select BLK_DEV_IDEDMA_PCI config BLK_DEV_SVWKS tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support" + select BLK_DEV_IDEDMA_PCI help This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5 chipsets. @@ -704,6 +712,7 @@ config BLK_DEV_SGIIOC4 tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 select IDEPCI_SHARE_IRQ + select BLK_DEV_IDEDMA_PCI help This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 chipset, which has one channel and can support two devices. @@ -711,6 +720,7 @@ config BLK_DEV_SGIIOC4 config BLK_DEV_SIIMAGE tristate "Silicon Image chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds PIO/(U)DMA support for the SI CMD680 and SII 3112 (Serial ATA) chips. @@ -718,7 +728,8 @@ config BLK_DEV_SIIMAGE config BLK_DEV_SIS5513 tristate "SiS5513 chipset support" depends on X86 - ---help--- + select BLK_DEV_IDEDMA_PCI + help This driver ensures (U)DMA support for SIS5513 chipset family based mainboards. @@ -737,6 +748,7 @@ config BLK_DEV_SIS5513 config BLK_DEV_SL82C105 tristate "Winbond SL82c105 support" depends on (PPC || ARM) + select BLK_DEV_IDEDMA_PCI help If you have a Winbond SL82c105 IDE controller, say Y here to enable special configuration for this chip. This is common on various CHRP @@ -744,6 +756,7 @@ config BLK_DEV_SL82C105 config BLK_DEV_SLC90E66 tristate "SLC90E66 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver ensures (U)DMA support for Victory66 SouthBridges for SMsC with Intel NorthBridges. This is an Ultra66 based chipset. @@ -759,6 +772,7 @@ config BLK_DEV_SLC90E66 config BLK_DEV_TRM290 tristate "Tekram TRM290 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for bus master DMA transfers using the Tekram TRM290 PCI IDE chip. Volunteers are @@ -767,6 +781,7 @@ config BLK_DEV_TRM290 config BLK_DEV_VIA82CXXX tristate "VIA82CXXX chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for VIA BusMastering IDE chips. This allows the kernel to change PIO, DMA and UDMA speeds and to @@ -774,12 +789,14 @@ config BLK_DEV_VIA82CXXX config BLK_DEV_TC86C001 tristate "Toshiba TC86C001 support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for Toshiba TC86C001 GOKU-S chip. config BLK_DEV_CELLEB tristate "Toshiba's Cell Reference Set IDE support" depends on PPC_CELLEB + select BLK_DEV_IDEDMA_PCI help This driver provides support for the built-in IDE controller on Toshiba Cell Reference Board. @@ -993,24 +1010,9 @@ config IDE_EXT_DIRECT endchoice # no isa -> no vlb -config IDE_CHIPSETS - bool "Other IDE chipset support" - depends on ISA - ---help--- - Say Y here if you want to include enhanced support for various IDE - interface chipsets used on motherboards and add-on cards. You can - then pick your particular IDE chip from among the following options. - This enhanced support may be necessary for Linux to be able to - access the 3rd/4th drives in some systems. It may also enable - setting of higher speed I/O rates to improve system performance with - these chipsets. Most of these also require special kernel boot - parameters to actually turn on the support at runtime; you can find - a list of these in the file . - - People with SCSI-only systems can say N here. - -if IDE_CHIPSETS +if ISA +comment "Other IDE chipsets support" comment "Note: most of these also require special kernel boot parameters" config BLK_DEV_4DRIVES From 26bcb879c03254545a19c6700fe5bcef6f21e7b1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: [PATCH 2188/2804] ide: add ide_set{_max}_pio() (take 4) * Add IDE_HFLAG_ABUSE_{PREFETCH,FAST_DEVSEL,DMA_MODES} flags and set them in ht6560, cmd640, cmd64x and sc1200 host drivers. * Add set_pio_mode_abuse() for checking if host driver has a non-standard ->tuneproc() implementation and use it in do_special(). * Add ide_set_pio() for setting PIO mode (it uses hwif->pio_mask to find the maximum PIO mode supported by the host), also add ide_set_max_pio() wrapper for ide_set_pio() to use for auto-tuning. Convert users of ->tuneproc to use ide_set{_max}_pio() where possible. This leaves only do_special(), set_using_pio(), ide_hwif_restore() and ide_set_pio() as a direct users of ->tuneproc. * Remove no longer needed ide_get_best_pio_mode() calls and printk-s reporting PIO mode selected from ->tuneproc implementations. * Rename ->tuneproc hook to ->set_pio_mode and make 'pio' argument const. * Remove stale comment from ide_config_drive_speed(). v2: * Fix "ata_" prefix (Noticed by Jeff). v3: * Minor cleanups/fixups per Sergei's suggestions. v4: * Fix compile problem in drivers/ide/pci/cmd640.c (Noticed by Andrew Morton). * Improve some ->set_pio_mode comments. Reviewed-by: Sergei Shtylyov Cc: Jeff Garzik Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/cris/ide-cris.c | 8 ++--- drivers/ide/ide-io.c | 39 +++++++++++++++++++--- drivers/ide/ide-iops.c | 6 ---- drivers/ide/ide-lib.c | 29 ++++++++++++++++ drivers/ide/ide-probe.c | 6 ++-- drivers/ide/ide.c | 5 +-- drivers/ide/legacy/ali14xx.c | 10 ++---- drivers/ide/legacy/dtc2278.c | 6 ++-- drivers/ide/legacy/ht6560b.c | 11 ++++--- drivers/ide/legacy/qd65xx.c | 60 +++++++++++++++++++--------------- drivers/ide/legacy/umc8672.c | 7 ++-- drivers/ide/mips/au1xxx-ide.c | 12 ++----- drivers/ide/pci/aec62xx.c | 7 ++-- drivers/ide/pci/alim15x3.c | 32 ++++++++---------- drivers/ide/pci/amd74xx.c | 14 +++----- drivers/ide/pci/atiixp.c | 7 ++-- drivers/ide/pci/cmd640.c | 35 ++++++++++---------- drivers/ide/pci/cmd64x.c | 39 +++++++++++----------- drivers/ide/pci/cs5520.c | 11 +++---- drivers/ide/pci/cs5530.c | 15 ++++----- drivers/ide/pci/cs5535.c | 16 ++++----- drivers/ide/pci/cy82c693.c | 20 ++---------- drivers/ide/pci/hpt34x.c | 7 ++-- drivers/ide/pci/hpt366.c | 7 ++-- drivers/ide/pci/it8213.c | 7 ++-- drivers/ide/pci/it821x.c | 7 ++-- drivers/ide/pci/jmicron.c | 7 ++-- drivers/ide/pci/opti621.c | 19 ++++++----- drivers/ide/pci/pdc202xx_new.c | 8 ++--- drivers/ide/pci/pdc202xx_old.c | 14 ++++---- drivers/ide/pci/piix.c | 21 ++++++------ drivers/ide/pci/sc1200.c | 14 ++++---- drivers/ide/pci/scc_pata.c | 7 ++-- drivers/ide/pci/serverworks.c | 7 ++-- drivers/ide/pci/sgiioc4.c | 2 +- drivers/ide/pci/siimage.c | 7 ++-- drivers/ide/pci/sis5513.c | 11 +++---- drivers/ide/pci/sl82c105.c | 17 +++------- drivers/ide/pci/slc90e66.c | 7 ++-- drivers/ide/pci/tc86c001.c | 7 ++-- drivers/ide/pci/triflex.c | 9 +++-- drivers/ide/pci/via82cxxx.c | 17 ++++------ drivers/ide/ppc/mpc8xx.c | 21 +++--------- drivers/ide/ppc/pmac.c | 8 ++--- include/linux/ide.h | 18 ++++++++-- 45 files changed, 318 insertions(+), 326 deletions(-) diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 67cec8916fcd..7c90218e9319 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -680,12 +680,10 @@ static void cris_dma_off(ide_drive_t *drive) { } -static void tune_cris_ide(ide_drive_t *drive, u8 pio) +static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio) { int setup, strobe, hold; - pio = ide_get_best_pio_mode(drive, pio, 4); - switch(pio) { case 0: @@ -727,7 +725,7 @@ static int speed_cris_ide(ide_drive_t *drive, const u8 speed) int cyc = 0, dvs = 0, strobe = 0, hold = 0; if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - tune_cris_ide(drive, speed - XFER_PIO_0); + cris_set_pio_mode(drive, speed - XFER_PIO_0); return ide_config_drive_speed(drive, speed); } @@ -797,7 +795,7 @@ init_e100_ide (void) ide_register_hw(&hw, 1, &hwif); hwif->mmio = 1; hwif->chipset = ide_etrax100; - hwif->tuneproc = &tune_cris_ide; + hwif->set_pio_mode = &cris_set_pio_mode; hwif->speedproc = &speed_cris_ide; hwif->ata_input_data = &cris_ide_input_data; hwif->ata_output_data = &cris_ide_output_data; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index aa9f5f0b1e67..9560a8f4a86c 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -201,8 +201,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * return do_rw_taskfile(drive, args); case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */ - if (drive->hwif->tuneproc != NULL) - drive->hwif->tuneproc(drive, 255); + ide_set_max_pio(drive); /* * skip idedisk_pm_idle for ATAPI devices */ @@ -788,6 +787,30 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive) return ide_started; } +/* + * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away + */ +static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) +{ + switch (req_pio) { + case 202: + case 201: + case 200: + case 102: + case 101: + case 100: + return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; + case 9: + case 8: + return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; + case 7: + case 6: + return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; + default: + return 0; + } +} + /** * do_special - issue some special commands * @drive: drive the command is for @@ -805,9 +828,17 @@ static ide_startstop_t do_special (ide_drive_t *drive) printk("%s: do_special: 0x%02x\n", drive->name, s->all); #endif if (s->b.set_tune) { + ide_hwif_t *hwif = drive->hwif; + u8 req_pio = drive->tune_req; + s->b.set_tune = 0; - if (HWIF(drive)->tuneproc != NULL) - HWIF(drive)->tuneproc(drive, drive->tune_req); + + if (set_pio_mode_abuse(drive->hwif, req_pio)) { + if (hwif->set_pio_mode) + hwif->set_pio_mode(drive, req_pio); + } else + ide_set_pio(drive, req_pio); + return ide_stopped; } else { if (drive->media == ide_disk) diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 646a54e233d3..cf0678b61161 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -780,12 +780,6 @@ int ide_driveid_update (ide_drive_t *drive) /* * Similar to ide_wait_stat(), except it never calls ide_error internally. - * This is a kludge to handle the new ide_config_drive_speed() function, - * and should not otherwise be used anywhere. Eventually, the tuneproc's - * should be updated to return ide_startstop_t, in which case we can get - * rid of this abomination again. :) -ml - * - * It is gone.......... * * const char *msg == consider adding for verbose errors. */ diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 957618849540..8400b1b4aa1b 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -325,6 +325,35 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode) EXPORT_SYMBOL_GPL(ide_get_best_pio_mode); +/* req_pio == "255" for auto-tune */ +void ide_set_pio(ide_drive_t *drive, u8 req_pio) +{ + ide_hwif_t *hwif = drive->hwif; + u8 host_pio, pio; + + if (hwif->set_pio_mode == NULL) + return; + + BUG_ON(hwif->pio_mask == 0x00); + + host_pio = fls(hwif->pio_mask) - 1; + + pio = ide_get_best_pio_mode(drive, req_pio, host_pio); + + /* + * TODO: + * - report device max PIO mode + * - check req_pio != 255 against device max PIO mode + */ + printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n", + drive->name, host_pio, req_pio, + req_pio == 255 ? "(auto-tune)" : "", pio); + + hwif->set_pio_mode(drive, pio); +} + +EXPORT_SYMBOL_GPL(ide_set_pio); + /** * ide_toggle_bounce - handle bounce buffering * @drive: drive to update diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 3a2a9a338fd9..b4c9f63a3854 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -827,10 +827,8 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)) ide_drive_t *drive = &hwif->drives[unit]; if (drive->present) { - if (hwif->tuneproc != NULL && - drive->autotune == IDE_TUNE_AUTO) - /* auto-tune PIO mode */ - hwif->tuneproc(drive, 255); + if (drive->autotune == IDE_TUNE_AUTO) + ide_set_max_pio(drive); if (drive->autotune != IDE_TUNE_DEFAULT && drive->autotune != IDE_TUNE_AUTO) diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9fdc1fe1b299..e96212ce5729 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -396,7 +396,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->cds = tmp_hwif->cds; #endif - hwif->tuneproc = tmp_hwif->tuneproc; + hwif->set_pio_mode = tmp_hwif->set_pio_mode; hwif->speedproc = tmp_hwif->speedproc; hwif->mdma_filter = tmp_hwif->mdma_filter; hwif->udma_filter = tmp_hwif->udma_filter; @@ -867,8 +867,9 @@ int set_pio_mode(ide_drive_t *drive, int arg) if (arg < 0 || arg > 255) return -EINVAL; - if (!HWIF(drive)->tuneproc) + if (drive->hwif->set_pio_mode == NULL) return -ENOSYS; + if (drive->special.b.set_tune) return -EBUSY; ide_init_drive_cmd(&rq); diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c index 9b9c4761cb7d..2f0ef9b44033 100644 --- a/drivers/ide/legacy/ali14xx.c +++ b/drivers/ide/legacy/ali14xx.c @@ -68,8 +68,6 @@ static RegInitializer initData[] __initdata = { {0x35, 0x03}, {0x00, 0x00} }; -#define ALI_MAX_PIO 4 - /* timing parameter registers for each drive */ static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = { {0x03, 0x26, 0x04, 0x27}, /* drive 0 */ @@ -109,7 +107,7 @@ static void outReg (u8 data, u8 reg) * This function computes timing parameters * and sets controller registers accordingly. */ -static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio) +static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { int driveNum; int time1, time2; @@ -117,8 +115,6 @@ static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio) unsigned long flags; int bus_speed = system_bus_clock(); - pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO); - /* calculate timing, according to PIO mode */ time1 = ide_pio_cycle_time(drive, pio); time2 = ide_pio_timings[pio].active_time; @@ -212,12 +208,12 @@ static int __init ali14xx_probe(void) hwif->chipset = ide_ali14xx; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = &ali14xx_tune_drive; + hwif->set_pio_mode = &ali14xx_set_pio_mode; hwif->mate = mate; mate->chipset = ide_ali14xx; mate->pio_mask = ATA_PIO4; - mate->tuneproc = &ali14xx_tune_drive; + mate->set_pio_mode = &ali14xx_set_pio_mode; mate->mate = hwif; mate->channel = 1; diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c index 6c01d951d074..f16521254867 100644 --- a/drivers/ide/legacy/dtc2278.c +++ b/drivers/ide/legacy/dtc2278.c @@ -67,12 +67,10 @@ static void sub22 (char b, char c) } } -static void tune_dtc2278 (ide_drive_t *drive, u8 pio) +static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio) { unsigned long flags; - pio = ide_get_best_pio_mode(drive, pio, 4); - if (pio >= 3) { spin_lock_irqsave(&ide_lock, flags); /* @@ -124,7 +122,7 @@ static int __init dtc2278_probe(void) hwif->serialized = 1; hwif->chipset = ide_dtc2278; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = &tune_dtc2278; + hwif->set_pio_mode = &dtc2278_set_pio_mode; hwif->drives[0].no_unmask = 1; hwif->drives[1].no_unmask = 1; hwif->mate = mate; diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index bfaa2025173b..2e5a9cc5c0f7 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -199,7 +199,7 @@ static int __init try_to_init_ht6560b(void) return 1; } -static u8 ht_pio2timings(ide_drive_t *drive, u8 pio) +static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio) { int active_time, recovery_time; int active_cycles, recovery_cycles; @@ -208,7 +208,6 @@ static u8 ht_pio2timings(ide_drive_t *drive, u8 pio) if (pio) { unsigned int cycle_time; - pio = ide_get_best_pio_mode(drive, pio, 5); cycle_time = ide_pio_cycle_time(drive, pio); /* @@ -277,7 +276,7 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state) #endif } -static void tune_ht6560b (ide_drive_t *drive, u8 pio) +static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio) { unsigned long flags; u8 timing; @@ -333,15 +332,17 @@ int __init ht6560b_init(void) hwif->chipset = ide_ht6560b; hwif->selectproc = &ht6560b_selectproc; + hwif->host_flags = IDE_HFLAG_ABUSE_PREFETCH; hwif->pio_mask = ATA_PIO5; - hwif->tuneproc = &tune_ht6560b; + hwif->set_pio_mode = &ht6560b_set_pio_mode; hwif->serialized = 1; /* is this needed? */ hwif->mate = mate; mate->chipset = ide_ht6560b; mate->selectproc = &ht6560b_selectproc; + mate->host_flags = IDE_HFLAG_ABUSE_PREFETCH; mate->pio_mask = ATA_PIO5; - mate->tuneproc = &tune_ht6560b; + mate->set_pio_mode = &ht6560b_set_pio_mode; mate->serialized = 1; /* is this needed? */ mate->mate = hwif; mate->channel = 1; diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c index 8b87a424094a..0c81d2d0b941 100644 --- a/drivers/ide/legacy/qd65xx.c +++ b/drivers/ide/legacy/qd65xx.c @@ -224,15 +224,14 @@ static void qd_set_timing (ide_drive_t *drive, u8 timing) printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); } -/* - * qd6500_tune_drive - */ - -static void qd6500_tune_drive (ide_drive_t *drive, u8 pio) +static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio) { int active_time = 175; int recovery_time = 415; /* worst case values from the dos driver */ + /* + * FIXME: use "pio" value + */ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time) && drive->id->tPIO && (drive->id->field_valid & 0x02) && drive->id->eide_pio >= 240) { @@ -246,11 +245,7 @@ static void qd6500_tune_drive (ide_drive_t *drive, u8 pio) qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time)); } -/* - * qd6580_tune_drive - */ - -static void qd6580_tune_drive (ide_drive_t *drive, u8 pio) +static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio) { int base = HWIF(drive)->select_data; unsigned int cycle_time; @@ -258,7 +253,6 @@ static void qd6580_tune_drive (ide_drive_t *drive, u8 pio) int recovery_time = 415; /* worst case values from the dos driver */ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { - pio = ide_get_best_pio_mode(drive, pio, 4); cycle_time = ide_pio_cycle_time(drive, pio); switch (pio) { @@ -335,8 +329,7 @@ static int __init qd_testreg(int port) */ static void __init qd_setup(ide_hwif_t *hwif, int base, int config, - unsigned int data0, unsigned int data1, - void (*tuneproc) (ide_drive_t *, u8 pio)) + unsigned int data0, unsigned int data1) { hwif->chipset = ide_qd65xx; hwif->channel = hwif->index; @@ -347,8 +340,6 @@ static void __init qd_setup(ide_hwif_t *hwif, int base, int config, hwif->drives[0].io_32bit = hwif->drives[1].io_32bit = 1; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = tuneproc; - probe_hwif_init(hwif); } /* @@ -361,7 +352,7 @@ static void __exit qd_unsetup(ide_hwif_t *hwif) { u8 config = hwif->config_data; int base = hwif->select_data; - void *tuneproc = (void *) hwif->tuneproc; + void *set_pio_mode = (void *)hwif->set_pio_mode; if (hwif->chipset != ide_qd65xx) return; @@ -369,12 +360,12 @@ static void __exit qd_unsetup(ide_hwif_t *hwif) printk(KERN_NOTICE "%s: back to defaults\n", hwif->name); hwif->selectproc = NULL; - hwif->tuneproc = NULL; + hwif->set_pio_mode = NULL; - if (tuneproc == (void *) qd6500_tune_drive) { + if (set_pio_mode == (void *)qd6500_set_pio_mode) { // will do it for both qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0])); - } else if (tuneproc == (void *) qd6580_tune_drive) { + } else if (set_pio_mode == (void *)qd6580_set_pio_mode) { if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) { qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1])); @@ -424,8 +415,11 @@ static int __init qd_probe(int base) return 1; } - qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA, - &qd6500_tune_drive); + qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA); + + hwif->set_pio_mode = &qd6500_set_pio_mode; + + probe_hwif_init(hwif); ide_proc_register_port(hwif); @@ -455,8 +449,12 @@ static int __init qd_probe(int base) printk(KERN_INFO "%s: qd6580: single IDE board\n", hwif->name); qd_setup(hwif, base, config | (control << 8), - QD6580_DEF_DATA, QD6580_DEF_DATA2, - &qd6580_tune_drive); + QD6580_DEF_DATA, QD6580_DEF_DATA2); + + hwif->set_pio_mode = &qd6580_set_pio_mode; + + probe_hwif_init(hwif); + qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT); ide_proc_register_port(hwif); @@ -472,11 +470,19 @@ static int __init qd_probe(int base) hwif->name, mate->name); qd_setup(hwif, base, config | (control << 8), - QD6580_DEF_DATA, QD6580_DEF_DATA, - &qd6580_tune_drive); + QD6580_DEF_DATA, QD6580_DEF_DATA); + + hwif->set_pio_mode = &qd6580_set_pio_mode; + + probe_hwif_init(hwif); + qd_setup(mate, base, config | (control << 8), - QD6580_DEF_DATA2, QD6580_DEF_DATA2, - &qd6580_tune_drive); + QD6580_DEF_DATA2, QD6580_DEF_DATA2); + + mate->set_pio_mode = &qd6580_set_pio_mode; + + probe_hwif_init(mate); + qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT); ide_proc_register_port(hwif); diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c index d2862e638bc5..1151c92dd531 100644 --- a/drivers/ide/legacy/umc8672.c +++ b/drivers/ide/legacy/umc8672.c @@ -105,12 +105,11 @@ static void umc_set_speeds (u8 speeds[]) speeds[0], speeds[1], speeds[2], speeds[3]); } -static void tune_umc (ide_drive_t *drive, u8 pio) +static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio) { unsigned long flags; ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup; - pio = ide_get_best_pio_mode(drive, pio, 4); printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); spin_lock_irqsave(&ide_lock, flags); @@ -150,12 +149,12 @@ static int __init umc8672_probe(void) hwif->chipset = ide_umc8672; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = &tune_umc; + hwif->set_pio_mode = &umc_set_pio_mode; hwif->mate = mate; mate->chipset = ide_umc8672; mate->pio_mask = ATA_PIO4; - mate->tuneproc = &tune_umc; + mate->set_pio_mode = &umc_set_pio_mode; mate->mate = hwif; mate->channel = 1; diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index b04db9ff1938..670cb748481f 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -99,18 +99,12 @@ void auide_outsw(unsigned long port, void *addr, u32 count) #endif -static void auide_tune_drive(ide_drive_t *drive, byte pio) +static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio) { int mem_sttime; int mem_stcfg; u8 speed; - /* get the best pio mode for the drive */ - pio = ide_get_best_pio_mode(drive, pio, 4); - - printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n", - drive->name, pio); - mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); @@ -184,7 +178,7 @@ static int auide_tune_chipset(ide_drive_t *drive, const u8 speed) mem_stcfg = au_readl(MEM_STCFG2); if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - auide_tune_drive(drive, speed - XFER_PIO_0); + au1xxx_set_pio_mode(drive, speed - XFER_PIO_0); return 0; } @@ -712,7 +706,7 @@ static int au_ide_probe(struct device *dev) hwif->OUTSW = auide_outsw; #endif - hwif->tuneproc = &auide_tune_drive; + hwif->set_pio_mode = &au1xxx_set_pio_mode; hwif->speedproc = &auide_tune_chipset; #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index a827ea2ab989..0d5f62c5dfae 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -138,9 +138,8 @@ static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed) return(ide_config_drive_speed(drive, speed)); } -static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio) +static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0); } @@ -150,7 +149,7 @@ static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - aec62xx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -201,7 +200,7 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) u8 reg54 = 0, mask = hwif->channel ? 0xf0 : 0x0f; unsigned long flags; - hwif->tuneproc = &aec62xx_tune_drive; + hwif->set_pio_mode = &aec_set_pio_mode; if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { if(hwif->mate) diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 37ecd726aa40..005402ab748b 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -283,17 +283,14 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count) #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */ /** - * ali15x3_tune_pio - set up chipset for PIO mode - * @drive: drive to tune - * @pio: desired mode + * ali_tune_pio - set host controller for PIO mode + * @drive: drive + * @pio: PIO mode number * - * Select the best PIO mode for the drive in question. - * Then program the controller for this mode. - * - * Returns the PIO mode programmed. + * Program the controller for the given PIO mode. */ - -static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio) + +static void ali_tune_pio(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -306,7 +303,6 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio) u8 cd_dma_fifo = 0; int unit = drive->select.b.unit & 1; - pio = ide_get_best_pio_mode(drive, pio, 5); s_time = ide_pio_timings[pio].setup_time; a_time = ide_pio_timings[pio].active_time; if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) @@ -359,22 +355,20 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio) * { 25, 70, 25 }, PIO Mode 4 with IORDY ns * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) */ - - return pio; } /** - * ali15x3_tune_drive - set up drive for PIO mode + * ali_set_pio_mode - set up drive for PIO mode * @drive: drive to tune * @pio: desired mode * - * Program the controller with the best PIO timing for the given drive. + * Program the controller with the desired PIO timing for the given drive. * Then set up the drive itself. */ -static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio) +static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ali15x3_tune_pio(drive, pio); + ali_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -437,7 +431,7 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, m5229_udma, tmpbyte); if (speed < XFER_SW_DMA_0) - (void) ali15x3_tune_pio(drive, speed - XFER_PIO_0); + ali_tune_pio(drive, speed - XFER_PIO_0); } else { pci_read_config_byte(dev, m5229_udma, &tmpbyte); tmpbyte &= (0x0f << ((1-unit) << 2)); @@ -470,7 +464,7 @@ static int ali15x3_config_drive_for_dma(ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - ali15x3_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -700,7 +694,7 @@ static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif) static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif) { hwif->autodma = 0; - hwif->tuneproc = &ali15x3_tune_drive; + hwif->set_pio_mode = &ali_set_pio_mode; hwif->speedproc = &ali15x3_tune_chipset; hwif->udma_filter = &ali_udma_filter; diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 9abbde3c7984..1088ba86cd1d 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -266,16 +266,12 @@ static int amd_set_drive(ide_drive_t *drive, const u8 speed) } /* - * amd74xx_tune_drive() is a callback from upper layers for - * PIO-only tuning. + * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning. */ -static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio) +static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio) { - if (pio == 255) - pio = ide_get_best_pio_mode(drive, 255, 5); - - amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5)); + amd_set_drive(drive, XFER_PIO_0 + pio); } static int amd74xx_ide_dma_check(ide_drive_t *drive) @@ -283,7 +279,7 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive) u8 speed = ide_max_dma_mode(drive); if (speed == 0) { - amd74xx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -409,7 +405,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) hwif->autodma = 0; - hwif->tuneproc = &amd74xx_tune_drive; + hwif->set_pio_mode = &amd_set_pio_mode; hwif->speedproc = &amd_set_drive; for (i = 0; i < 2; i++) { diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index e05e88298500..b9f66f53f9a6 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -153,9 +153,8 @@ static void atiixp_tune_pio(ide_drive_t *drive, u8 pio) spin_unlock_irqrestore(&atiixp_lock, flags); } -static void atiixp_tuneproc(ide_drive_t *drive, u8 pio) +static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); atiixp_tune_pio(drive, pio); (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -231,7 +230,7 @@ static int atiixp_dma_check(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - atiixp_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -254,7 +253,7 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) hwif->irq = ch ? 15 : 14; hwif->autodma = 0; - hwif->tuneproc = &atiixp_tuneproc; + hwif->set_pio_mode = &atiixp_set_pio_mode; hwif->speedproc = &atiixp_speedproc; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index 9689494efa24..f369645e4d16 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -628,45 +628,40 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle program_drive_counts (index); } -/* - * Drive PIO mode selection: - */ -static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted) +static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) { unsigned int index = 0, cycle_time; u8 b; while (drive != cmd_drives[index]) { if (++index > 3) { - printk("%s: bad news in cmd640_tune_drive\n", drive->name); + printk(KERN_ERR "%s: bad news in %s\n", + drive->name, __FUNCTION__); return; } } - switch (mode_wanted) { + switch (pio) { case 6: /* set fast-devsel off */ case 7: /* set fast-devsel on */ - mode_wanted &= 1; b = get_cmd640_reg(CNTRL) & ~0x27; - if (mode_wanted) + if (pio & 1) b |= 0x27; put_cmd640_reg(CNTRL, b); - printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis"); + printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, (pio & 1) ? "en" : "dis"); return; case 8: /* set prefetch off */ case 9: /* set prefetch on */ - mode_wanted &= 1; - set_prefetch_mode(index, mode_wanted); - printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis"); + set_prefetch_mode(index, pio & 1); + printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis"); return; } - mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 5); - cycle_time = ide_pio_cycle_time(drive, mode_wanted); - cmd640_set_mode(index, mode_wanted, cycle_time); + cycle_time = ide_pio_cycle_time(drive, pio); + cmd640_set_mode(index, pio, cycle_time); printk("%s: selected cmd640 PIO mode%d (%dns)", - drive->name, mode_wanted, cycle_time); + drive->name, pio, cycle_time); display_clocks(index); } @@ -766,8 +761,10 @@ int __init ide_probe_for_cmd640x (void) cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr); cmd_hwif0->chipset = ide_cmd640; #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + cmd_hwif0->host_flags = IDE_HFLAG_ABUSE_PREFETCH | + IDE_HFLAG_ABUSE_FAST_DEVSEL; cmd_hwif0->pio_mask = ATA_PIO5; - cmd_hwif0->tuneproc = &cmd640_tune_drive; + cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ /* @@ -822,8 +819,10 @@ int __init ide_probe_for_cmd640x (void) cmd_hwif1->mate = cmd_hwif0; cmd_hwif1->channel = 1; #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + cmd_hwif1->host_flags = IDE_HFLAG_ABUSE_PREFETCH | + IDE_HFLAG_ABUSE_FAST_DEVSEL; cmd_hwif1->pio_mask = ATA_PIO5; - cmd_hwif1->tuneproc = &cmd640_tune_drive; + cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ } printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name, diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 5fe50a234ce1..85f5e42eb831 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -214,28 +214,25 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_ } /* - * This routine selects drive's best PIO mode and writes into the chipset - * registers setup/active/recovery timings. + * This routine writes into the chipset registers + * PIO setup/active/recovery timings. */ -static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted) +static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; unsigned int cycle_time; - u8 pio_mode, setup_count, arttim = 0; + u8 setup_count, arttim = 0; + static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; - pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5); - cycle_time = ide_pio_cycle_time(drive, pio_mode); - - cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)\n", - drive->name, mode_wanted, pio_mode, cycle_time); + cycle_time = ide_pio_cycle_time(drive, pio); program_cycle_times(drive, cycle_time, - ide_pio_timings[pio_mode].active_time); + ide_pio_timings[pio].active_time); - setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time, + setup_count = quantize_timing(ide_pio_timings[pio].setup_time, 1000 / system_bus_clock()); /* @@ -266,16 +263,14 @@ static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted) arttim |= setup_values[setup_count]; (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim); cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]); - - return pio_mode; } /* * Attempts to set drive's PIO mode. - * Special cases are 8: prefetch off, 9: prefetch on (both never worked), - * and 255: auto-select best mode (used at boot time). + * Special cases are 8: prefetch off, 9: prefetch on (both never worked) */ -static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio) + +static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio) { /* * Filter out the prefetch control values @@ -284,7 +279,7 @@ static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio) if (pio == 8 || pio == 9) return; - pio = cmd64x_tune_pio(drive, pio); + cmd64x_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -334,7 +329,7 @@ static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_2: case XFER_PIO_1: case XFER_PIO_0: - (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0); + cmd64x_tune_pio(drive, speed - XFER_PIO_0); break; default: return 1; @@ -352,7 +347,7 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - cmd64x_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -536,7 +531,7 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) pci_read_config_byte(dev, PCI_REVISION_ID, &rev); - hwif->tuneproc = &cmd64x_tune_drive; + hwif->set_pio_mode = &cmd64x_set_pio_mode; hwif->speedproc = &cmd64x_tune_chipset; hwif->drives[0].autotune = hwif->drives[1].autotune = 1; @@ -620,6 +615,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { .autodma = AUTODMA, .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .udma_mask = 0x00, /* no udma */ },{ /* 1 */ @@ -630,6 +626,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { .autodma = AUTODMA, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .udma_mask = 0x07, /* udma0-2 */ },{ /* 2 */ @@ -640,6 +637,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { .autodma = AUTODMA, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .udma_mask = 0x1f, /* udma0-4 */ },{ /* 3 */ @@ -650,6 +648,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { .autodma = AUTODMA, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .udma_mask = 0x3f, /* udma0-5 */ } diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index af67438328a8..a73c318ff086 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -122,17 +122,16 @@ static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) return error; } - -static void cs5520_tune_drive(ide_drive_t *drive, u8 pio) + +static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); - cs5520_tune_chipset(drive, (XFER_PIO_0 + pio)); + cs5520_tune_chipset(drive, XFER_PIO_0 + pio); } static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) { /* Tune the drive for PIO modes up to PIO 4 */ - cs5520_tune_drive(drive, 255); + ide_set_max_pio(drive); /* Then tell the core to use DMA operations */ return 0; @@ -164,7 +163,7 @@ static int cs5520_dma_on(ide_drive_t *drive) static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) { - hwif->tuneproc = &cs5520_tune_drive; + hwif->set_pio_mode = &cs5520_set_pio_mode; hwif->speedproc = &cs5520_tune_chipset; hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; hwif->ide_dma_on = &cs5520_dma_on; diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 518f430c1529..1588a323c5d0 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -71,19 +71,18 @@ static void cs5530_tunepio(ide_drive_t *drive, u8 pio) } /** - * cs5530_tuneproc - select/set PIO modes + * cs5530_set_pio_mode - set PIO mode + * @drive: drive + * @pio: PIO mode number * - * cs5530_tuneproc() handles selection/setting of PIO modes - * for both the chipset and drive. + * Handles setting of PIO mode for both the chipset and drive. * - * The ide_init_cs5530() routine guarantees that all drives + * The init_hwif_cs5530() routine guarantees that all drives * will have valid default PIO timings set up before we get here. */ -static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */ +static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); - if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0) cs5530_tunepio(drive, pio); } @@ -306,7 +305,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif) if (hwif->mate) hwif->serialized = hwif->mate->serialized = 1; - hwif->tuneproc = &cs5530_tuneproc; + hwif->set_pio_mode = &cs5530_set_pio_mode; hwif->speedproc = &cs5530_tune_chipset; basereg = CS5530_BASEREG(hwif); diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index bc00e7b62151..383b7eccbcbb 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -147,16 +147,16 @@ static int cs5535_set_drive(ide_drive_t *drive, u8 speed) return 0; } -/**** - * cs5535_tuneproc - PIO setup - * @drive: drive to set up - * @pio: mode to use (255 for 'best possible') +/** + * cs5535_set_pio_mode - PIO setup + * @drive: drive + * @pio: PIO mode number * * A callback from the upper layers for PIO-only tuning. */ -static void cs5535_tuneproc(ide_drive_t *drive, u8 pio) + +static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); ide_config_drive_speed(drive, XFER_PIO_0 + pio); cs5535_set_speed(drive, XFER_PIO_0 + pio); } @@ -169,7 +169,7 @@ static int cs5535_dma_check(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - cs5535_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -198,7 +198,7 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif) hwif->autodma = 0; - hwif->tuneproc = &cs5535_tuneproc; + hwif->set_pio_mode = &cs5535_set_pio_mode; hwif->speedproc = &cs5535_set_drive; hwif->ide_dma_check = &cs5535_dma_check; diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index daa36fcbc8ef..dc278025d318 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -97,9 +97,6 @@ #define CY82_INDEX_CHANNEL1 0x31 #define CY82_INDEX_TIMEOUT 0x32 -/* the max PIO mode - from datasheet */ -#define CY82C693_MAX_PIO 4 - /* the min and max PCI bus speed in MHz - from datasheet */ #define CY82C963_MIN_BUS_SPEED 25 #define CY82C963_MAX_BUS_SPEED 33 @@ -148,9 +145,6 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk) * so you can play with the idebus=xx parameter */ - if (pio > CY82C693_MAX_PIO) - pio = CY82C693_MAX_PIO; - /* let's calc the address setup time clocks */ p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed); @@ -269,10 +263,7 @@ static int cy82c693_ide_dma_on (ide_drive_t *drive) return __ide_dma_on(drive); } -/* - * tune ide drive - set PIO mode - */ -static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio) +static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -329,13 +320,6 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio) addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); #endif /* CY82C693_DEBUG_LOGS */ - /* first let's calc the pio modes */ - pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO); - -#if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio); -#endif /* CY82C693_DEBUG_INFO */ - /* let's calc the values for this PIO mode */ compute_clocks(pio, &pclk); @@ -447,7 +431,7 @@ static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif) hwif->autodma = 0; hwif->chipset = ide_cy82c693; - hwif->tuneproc = &cy82c693_tune_drive; + hwif->set_pio_mode = &cy82c693_set_pio_mode; if (!hwif->dma_base) { hwif->drives[0].autotune = 1; diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index ba982d66ff73..a1bb10188fe5 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -77,9 +77,8 @@ static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed) return(ide_config_drive_speed(drive, speed)); } -static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio) +static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 5); (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio)); } @@ -91,7 +90,7 @@ static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive) return -1; if (ide_use_fast_pio(drive)) - hpt34x_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -145,7 +144,7 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) hwif->autodma = 0; - hwif->tuneproc = &hpt34x_tune_drive; + hwif->set_pio_mode = &hpt34x_set_pio_mode; hwif->speedproc = &hpt34x_tune_chipset; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 67127ac3a14a..0e7d3b60d43c 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -662,9 +662,8 @@ static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed) return hpt36x_tune_chipset(drive, speed); } -static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio) +static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio); } @@ -726,7 +725,7 @@ static int hpt366_config_drive_xfer_rate(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - hpt3xx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -1257,7 +1256,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) /* Cache the channel's MISC. control registers' offset */ hwif->select_data = hwif->channel ? 0x54 : 0x50; - hwif->tuneproc = &hpt3xx_tune_drive; + hwif->set_pio_mode = &hpt3xx_set_pio_mode; hwif->speedproc = &hpt3xx_tune_chipset; hwif->quirkproc = &hpt3xx_quirkproc; hwif->intrproc = &hpt3xx_intrproc; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 6fa955749aec..d07771e06b2d 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -105,9 +105,8 @@ static void it8213_tune_pio(ide_drive_t *drive, const u8 pio) spin_unlock_irqrestore(&tune_lock, flags); } -static void it8213_tuneproc(ide_drive_t *drive, u8 pio) +static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); it8213_tune_pio(drive, pio); ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -212,7 +211,7 @@ static int it8213_config_drive_for_dma (ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - it8213_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -231,7 +230,7 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif) u8 reg42h = 0; hwif->speedproc = &it8213_tune_chipset; - hwif->tuneproc = &it8213_tuneproc; + hwif->set_pio_mode = &it8213_set_pio_mode; hwif->autodma = 0; diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index a756e61bcb32..0cce4a7f5e46 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -274,9 +274,8 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio) return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio); } -static void it821x_tuneproc(ide_drive_t *drive, u8 pio) +static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void)it821x_tunepio(drive, pio); } @@ -473,7 +472,7 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - it821x_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -640,7 +639,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif) } hwif->speedproc = &it821x_tune_chipset; - hwif->tuneproc = &it821x_tuneproc; + hwif->set_pio_mode = &it821x_set_pio_mode; /* MWDMA/PIO clock switching for pass through mode */ if(!idev->smart) { diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 7bac87fb481a..d379fbaf6743 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -83,9 +83,8 @@ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif) return ATA_CBL_PATA80; } -static void jmicron_tuneproc(ide_drive_t *drive, u8 pio) +static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 5); ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -116,7 +115,7 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - jmicron_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -131,7 +130,7 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive) static void __devinit init_hwif_jmicron(ide_hwif_t *hwif) { hwif->speedproc = &jmicron_tune_chipset; - hwif->tuneproc = &jmicron_tuneproc; + hwif->set_pio_mode = &jmicron_set_pio_mode; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 3a2bb2723515..9fa06393469a 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -47,7 +47,7 @@ * The main problem with OPTi is that some timings for master * and slave must be the same. For example, if you have master * PIO 3 and slave PIO 0, driver have to set some timings of - * master for PIO 0. Second problem is that opti621_tune_drive + * master for PIO 0. Second problem is that opti621_set_pio_mode * got only one drive to set, but have to set both drives. * This is solved in compute_pios. If you don't set * the second drive, compute_pios use ide_get_best_pio_mode @@ -103,7 +103,7 @@ #include -#define OPTI621_MAX_PIO 3 +//#define OPTI621_MAX_PIO 3 /* In fact, I do not have any PIO 4 drive * (address: 25 ns, data: 70 ns, recovery: 35 ns), * but OPTi 82C621 is programmable and it can do (minimal values): @@ -136,8 +136,8 @@ static int reg_base; #define PIO_NOT_EXIST 254 #define PIO_DONT_KNOW 255 -/* there are stored pio numbers from other calls of opti621_tune_drive */ -static void compute_pios(ide_drive_t *drive, u8 pio) +/* there are stored pio numbers from other calls of opti621_set_pio_mode */ +static void compute_pios(ide_drive_t *drive, const u8 pio) /* Store values into drive->drive_data * second_contr - 0 for primary controller, 1 for secondary * slave_drive - 0 -> pio is for master, 1 -> pio is for slave @@ -147,12 +147,13 @@ static void compute_pios(ide_drive_t *drive, u8 pio) int d; ide_hwif_t *hwif = HWIF(drive); - drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO); + drive->drive_data = pio; + for (d = 0; d < 2; ++d) { drive = &hwif->drives[d]; if (drive->present) { if (drive->drive_data == PIO_DONT_KNOW) - drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO); + drive->drive_data = ide_get_best_pio_mode(drive, 255, 3); #ifdef OPTI621_DEBUG printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data); @@ -240,8 +241,7 @@ static void compute_clocks(int pio, pio_clocks_t *clks) } -/* Main tune procedure, called from tuneproc. */ -static void opti621_tune_drive (ide_drive_t *drive, u8 pio) +static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) { /* primary and secondary drives share some registers, * so we have to program both drives @@ -331,7 +331,8 @@ static void __devinit init_hwif_opti621 (ide_hwif_t *hwif) hwif->autodma = 0; hwif->drives[0].drive_data = PIO_DONT_KNOW; hwif->drives[1].drive_data = PIO_DONT_KNOW; - hwif->tuneproc = &opti621_tune_drive; + + hwif->set_pio_mode = &opti621_set_pio_mode; if (!(hwif->dma_base)) return; diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 3787194a2249..5fb1eedc8194 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -215,9 +215,8 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed) return err; } -static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio) +static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio); } @@ -237,7 +236,7 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - pdcnew_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -490,7 +489,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) { hwif->autodma = 0; - hwif->tuneproc = &pdcnew_tune_drive; + hwif->set_pio_mode = &pdcnew_set_pio_mode; + hwif->quirkproc = &pdcnew_quirkproc; hwif->speedproc = &pdcnew_tune_chipset; hwif->resetproc = &pdcnew_reset; diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index e7a5e3014c09..b578307fad51 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -142,9 +142,8 @@ static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed) return ide_config_drive_speed(drive, speed); } -static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio) +static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio); } @@ -190,7 +189,7 @@ static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - pdc202xx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -306,10 +305,11 @@ static void pdc202xx_reset (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *mate = hwif->mate; - + pdc202xx_reset_host(hwif); pdc202xx_reset_host(mate); - pdc202xx_tune_drive(drive, 255); + + ide_set_max_pio(drive); } static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, @@ -328,7 +328,9 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) hwif->rqsize = 256; hwif->autodma = 0; - hwif->tuneproc = &pdc202xx_tune_drive; + + hwif->set_pio_mode = &pdc202xx_set_pio_mode; + hwif->quirkproc = &pdc202xx_quirkproc; if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index b66f9d1411b3..07492d71c602 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -17,11 +17,11 @@ * 41 * 43 * - * | PIO 0 | c0 | 80 | 0 | piix_tune_drive(drive, 0); - * | PIO 2 | SW2 | d0 | 90 | 4 | piix_tune_drive(drive, 2); - * | PIO 3 | MW1 | e1 | a1 | 9 | piix_tune_drive(drive, 3); - * | PIO 4 | MW2 | e3 | a3 | b | piix_tune_drive(drive, 4); - * + * | PIO 0 | c0 | 80 | 0 | + * | PIO 2 | SW2 | d0 | 90 | 4 | + * | PIO 3 | MW1 | e1 | a1 | 9 | + * | PIO 4 | MW2 | e3 | a3 | b | + * * sitre = word40 & 0x4000; primary * sitre = word42 & 0x4000; secondary * @@ -204,16 +204,16 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio) } /** - * piix_tune_drive - tune a drive attached to PIIX + * piix_set_pio_mode - set PIO mode * @drive: drive to tune * @pio: desired PIO mode * * Set the drive's PIO mode (might be useful if drive is not registered * in CMOS for any reason). */ -static void piix_tune_drive (ide_drive_t *drive, u8 pio) + +static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); piix_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -317,7 +317,7 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - piix_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -454,7 +454,8 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) } hwif->autodma = 0; - hwif->tuneproc = &piix_tune_drive; + + hwif->set_pio_mode = &piix_set_pio_mode; hwif->speedproc = &piix_tune_chipset; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 059071cd2d49..f9f5ed906577 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -272,19 +272,20 @@ static int sc1200_ide_dma_end (ide_drive_t *drive) } /* - * sc1200_tuneproc() handles selection/setting of PIO modes + * sc1200_set_pio_mode() handles setting of PIO modes * for both the chipset and drive. * * All existing BIOSs for this chipset guarantee that all drives * will have valid default PIO timings set up before we get here. */ -static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "autotune" */ + +static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); int mode = -1; /* - * bad abuse of ->tuneproc interface + * bad abuse of ->set_pio_mode interface */ switch (pio) { case 200: mode = XFER_UDMA_0; break; @@ -302,9 +303,6 @@ static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "au return; } - pio = ide_get_best_pio_mode(drive, pio, 4); - printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio); - if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0) sc1200_tunepio(drive, pio); } @@ -420,7 +418,8 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif) hwif->ide_dma_end = &sc1200_ide_dma_end; if (!noautodma) hwif->autodma = 1; - hwif->tuneproc = &sc1200_tuneproc; + + hwif->set_pio_mode = &sc1200_set_pio_mode; hwif->speedproc = &sc1200_tune_chipset; } hwif->atapi_dma = 1; @@ -436,6 +435,7 @@ static ide_pci_device_t sc1200_chipset __devinitdata = { .init_hwif = init_hwif_sc1200, .autodma = AUTODMA, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_DMA_MODES, .pio_mask = ATA_PIO4, }; diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index a19687caf65a..3505d57eda18 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -221,9 +221,8 @@ static void scc_tune_pio(ide_drive_t *drive, const u8 pio) out_be32((void __iomem *)pioct_port, reg); } -static void scc_tuneproc(ide_drive_t *drive, u8 pio) +static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); scc_tune_pio(drive, pio); ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -316,7 +315,7 @@ static int scc_config_drive_for_dma(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - scc_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -717,7 +716,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif) hwif->dma_setup = scc_dma_setup; hwif->ide_dma_end = scc_ide_dma_end; hwif->speedproc = scc_tune_chipset; - hwif->tuneproc = scc_tuneproc; + hwif->set_pio_mode = scc_set_pio_mode; hwif->ide_dma_check = scc_config_drive_for_dma; hwif->ide_dma_test_irq = scc_dma_test_irq; hwif->udma_filter = scc_udma_filter; diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index b51133bb58af..f4e08abf0fee 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -202,9 +202,8 @@ static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed) return (ide_config_drive_speed(drive, speed)); } -static void svwks_tune_drive (ide_drive_t *drive, u8 pio) +static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); svwks_tune_pio(drive, pio); (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -217,7 +216,7 @@ static int svwks_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - svwks_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -389,7 +388,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; - hwif->tuneproc = &svwks_tune_drive; + hwif->set_pio_mode = &svwks_set_pio_mode; hwif->speedproc = &svwks_tune_chipset; hwif->udma_filter = &svwks_udma_filter; diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 57145767c3df..38f63d19c3b9 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -587,7 +587,7 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */ hwif->swdma_mask = 0x2; hwif->pio_mask = 0x00; - hwif->tuneproc = NULL; /* Sets timing for PIO mode */ + hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */ hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */ hwif->selectproc = NULL;/* Use the default routine to select drive */ hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */ diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 4c1f3bc7e179..e07c991d91b9 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -219,9 +219,8 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) } } -static void sil_tuneproc(ide_drive_t *drive, u8 pio) +static void sil_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); sil_tune_pio(drive, pio); (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -328,7 +327,7 @@ static int siimage_config_drive_for_dma (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - sil_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -899,7 +898,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif) hwif->resetproc = &siimage_reset; hwif->speedproc = &siimage_tune_chipset; - hwif->tuneproc = &sil_tuneproc; + hwif->set_pio_mode = &sil_set_pio_mode; hwif->reset_poll = &siimage_reset_poll; hwif->pre_reset = &siimage_pre_reset; hwif->udma_filter = &sil_udma_filter; diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index fed582b4b32f..7455bf357ed9 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -519,14 +519,13 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) } } -static int sis5513_tune_drive(ide_drive_t *drive, u8 pio) +static int sis5513_tune_drive(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); config_art_rwp_pio(drive, pio); return ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static void sis5513_tuneproc(ide_drive_t *drive, u8 pio) +static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) { (void)sis5513_tune_drive(drive, pio); } @@ -621,7 +620,7 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive) /* * TODO: always set PIO mode and remove this */ - sis5513_tuneproc(drive, 255); + ide_set_max_pio(drive); drive->init_speed = 0; @@ -629,7 +628,7 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - sis5513_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -852,7 +851,7 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif) if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; - hwif->tuneproc = &sis5513_tuneproc; + hwif->set_pio_mode = &sis_set_pio_mode; hwif->speedproc = &sis5513_tune_chipset; if (chipset_family >= ATA_133) diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 9f425b0b5721..131e91ca1d82 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -75,16 +75,12 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) /* * Configure the chipset for PIO mode. */ -static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio) +static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio) { struct pci_dev *dev = HWIF(drive)->pci_dev; int reg = 0x44 + drive->dn * 4; u16 drv_ctrl; - DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio)); - - pio = ide_get_best_pio_mode(drive, pio, 5); - drv_ctrl = get_pio_timings(drive, pio); /* @@ -106,8 +102,6 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio) printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name, ide_xfer_verbose(pio + XFER_PIO_0), ide_pio_cycle_time(drive, pio), drv_ctrl); - - return pio; } /* @@ -151,7 +145,7 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_2: case XFER_PIO_1: case XFER_PIO_0: - (void) sl82c105_tune_pio(drive, speed - XFER_PIO_0); + sl82c105_tune_pio(drive, speed - XFER_PIO_0); break; default: return -1; @@ -325,11 +319,10 @@ static void sl82c105_resetproc(ide_drive_t *drive) * We only deal with PIO mode here - DMA mode 'using_dma' is not * initialised at the point that this function is called. */ -static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio) +static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) { - DBG(("sl82c105_tune_drive(drive:%s, pio:%u)\n", drive->name, pio)); + sl82c105_tune_pio(drive, pio); - pio = sl82c105_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -397,7 +390,7 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index)); - hwif->tuneproc = &sl82c105_tune_drive; + hwif->set_pio_mode = &sl82c105_set_pio_mode; hwif->speedproc = &sl82c105_tune_chipset; hwif->selectproc = &sl82c105_selectproc; hwif->resetproc = &sl82c105_resetproc; diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index cc9353565070..214d396fc31f 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -95,9 +95,8 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio) spin_unlock_irqrestore(&ide_lock, flags); } -static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) +static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); slc90e66_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -166,7 +165,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - slc90e66_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -182,7 +181,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) hwif->irq = hwif->channel ? 15 : 14; hwif->speedproc = &slc90e66_tune_chipset; - hwif->tuneproc = &slc90e66_tune_drive; + hwif->set_pio_mode = &slc90e66_set_pio_mode; pci_read_config_byte(hwif->pci_dev, 0x47, ®47); diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index e5425772622f..e23b9cfb6eb4 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -43,9 +43,8 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed) return ide_config_drive_speed(drive, speed); } -static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio) +static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio); } @@ -171,7 +170,7 @@ static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - tc86c001_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -193,7 +192,7 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) /* Store the system control register base for convenience... */ hwif->config_data = sc_base; - hwif->tuneproc = &tc86c001_tune_drive; + hwif->set_pio_mode = &tc86c001_set_pio_mode; hwif->speedproc = &tc86c001_tune_chipset; hwif->busproc = &tc86c001_busproc; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index 47cf89be4dfc..c3ff066eea5a 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -93,10 +93,9 @@ static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed) return (ide_config_drive_speed(drive, speed)); } -static void triflex_tune_drive(ide_drive_t *drive, u8 pio) +static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio) { - int use_pio = ide_get_best_pio_mode(drive, pio, 4); - (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio)); + (void)triflex_tune_chipset(drive, XFER_PIO_0 + pio); } static int triflex_config_drive_xfer_rate(ide_drive_t *drive) @@ -104,14 +103,14 @@ static int triflex_config_drive_xfer_rate(ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - triflex_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } static void __devinit init_hwif_triflex(ide_hwif_t *hwif) { - hwif->tuneproc = &triflex_tune_drive; + hwif->set_pio_mode = &triflex_set_pio_mode; hwif->speedproc = &triflex_tune_chipset; if (hwif->dma_base == 0) diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index e3bf90736332..2fc4f8835f19 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -195,19 +195,16 @@ static int via_set_drive(ide_drive_t *drive, const u8 speed) } /** - * via82cxxx_tune_drive - PIO setup - * @drive: drive to set up - * @pio: mode to use (255 for 'best possible') + * via_set_pio_mode - PIO setup + * @drive: drive + * @pio: PIO mode number * * A callback from the upper layers for PIO-only tuning. */ -static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio) +static void via_set_pio_mode(ide_drive_t *drive, const u8 pio) { - if (pio == 255) - pio = ide_get_best_pio_mode(drive, 255, 5); - - via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5)); + via_set_drive(drive, XFER_PIO_0 + pio); } /** @@ -223,7 +220,7 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive) u8 speed = ide_max_dma_mode(drive); if (speed == 0) { - via82cxxx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -465,7 +462,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif) hwif->autodma = 0; - hwif->tuneproc = &via82cxxx_tune_drive; + hwif->set_pio_mode = &via_set_pio_mode; hwif->speedproc = &via_set_drive; diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c index dab79afa9b22..df2e92034f5d 100644 --- a/drivers/ide/ppc/mpc8xx.c +++ b/drivers/ide/ppc/mpc8xx.c @@ -45,7 +45,7 @@ static void print_funcid (int func); static int check_ide_device (unsigned long base); static void ide_interrupt_ack (void *dev); -static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio); +static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio); typedef struct ide_ioport_desc { unsigned long base_off; /* Offset to PCMCIA memory */ @@ -314,9 +314,8 @@ m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, #endif /* CONFIG_IDE_8xx_PCCARD */ } - /* register routine to tune PIO mode */ ide_hwifs[data_port].pio_mask = ATA_PIO4; - ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; + ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode; hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack; /* Enable Harddisk Interrupt, @@ -401,9 +400,8 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw, *irq = ioport_dsc[data_port].irq; } - /* register routine to tune PIO mode */ ide_hwifs[data_port].pio_mask = ATA_PIO4; - ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; + ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode; hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack; /* Enable Harddisk Interrupt, @@ -427,24 +425,13 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw, #define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */ #endif - /* Calculate PIO timings */ -static void -m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio) +static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) { #if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) volatile pcmconf8xx_t *pcmp; ulong timing, mask, reg; -#endif - pio = ide_get_best_pio_mode(drive, pio, 4); - -#if 1 - printk("%s[%d] %s: best PIO mode: %d\n", - __FILE__,__LINE__,__FUNCTION__, pio); -#endif - -#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia)); mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF)); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 284bb7c39b87..beafdf3c1124 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -411,7 +411,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time) static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif); static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq); -static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio); static void pmac_ide_selectproc(ide_drive_t *drive); static void pmac_ide_kauai_selectproc(ide_drive_t *drive); @@ -615,7 +614,7 @@ out: * Old tuning functions (called on hdparm -p), sets up drive PIO timings */ static void -pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) +pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) { u32 *timings; unsigned accessTicks, recTicks; @@ -629,7 +628,6 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) /* which drive is it ? */ timings = &pmif->timings[drive->select.b.unit & 0x01]; - pio = ide_get_best_pio_mode(drive, pio, 4); cycle_time = ide_pio_cycle_time(drive, pio); switch (pmif->kind) { @@ -966,7 +964,7 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_2: case XFER_PIO_1: case XFER_PIO_0: - pmac_ide_tuneproc(drive, speed & 0x07); + pmac_ide_set_pio_mode(drive, speed & 0x07); break; default: ret = 1; @@ -1241,7 +1239,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->drives[0].unmask = 1; hwif->drives[1].unmask = 1; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = pmac_ide_tuneproc; + hwif->set_pio_mode = pmac_ide_set_pio_mode; if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6 || pmif->kind == controller_sh_ata6) diff --git a/include/linux/ide.h b/include/linux/ide.h index 81736cb7ef3d..85d448b4abec 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -634,7 +634,7 @@ typedef struct ide_drive_s { unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int cyl; /* "real" number of cyls */ - unsigned int drive_data; /* use by tuneproc/selectproc */ + unsigned int drive_data; /* used by set_pio_mode/selectproc */ unsigned int failures; /* current failure count */ unsigned int max_failures; /* maximum allowed failure count */ u64 probed_capacity;/* initial reported media capacity (ide-cd only currently) */ @@ -702,8 +702,8 @@ typedef struct hwif_s { #if 0 ide_hwif_ops_t *hwifops; #else - /* routine to tune PIO mode for drives */ - void (*tuneproc)(ide_drive_t *, u8); + /* routine to set PIO mode for drives */ + void (*set_pio_mode)(ide_drive_t *, const u8); /* routine to retune DMA modes for drives */ int (*speedproc)(ide_drive_t *, const u8); /* tweaks hardware to select drive */ @@ -1256,6 +1256,12 @@ enum { IDE_HFLAG_PIO_NO_BLACKLIST = (1 << 2), /* don't use conservative PIO "downgrade" */ IDE_HFLAG_PIO_NO_DOWNGRADE = (1 << 3), + /* use PIO8/9 for prefetch off/on */ + IDE_HFLAG_ABUSE_PREFETCH = (1 << 4), + /* use PIO6/7 for fast-devsel off/on */ + IDE_HFLAG_ABUSE_FAST_DEVSEL = (1 << 5), + /* use 100-102 and 200-202 PIO values to set DMA modes */ + IDE_HFLAG_ABUSE_DMA_MODES = (1 << 6), }; typedef struct ide_pci_device_s { @@ -1414,6 +1420,12 @@ unsigned int ide_pio_cycle_time(ide_drive_t *, u8); u8 ide_get_best_pio_mode(ide_drive_t *, u8, u8); extern const ide_pio_timings_t ide_pio_timings[6]; +void ide_set_pio(ide_drive_t *, u8); + +static inline void ide_set_max_pio(ide_drive_t *drive) +{ + ide_set_pio(drive, 255); +} extern spinlock_t ide_lock; extern struct mutex ide_cfg_mtx; From 55f17e8da1f02ce0a36303a3f266c45045004cf5 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: [PATCH 2189/2804] amd74xx/via82cxxx: use ide_tune_dma() * Use ide_tune_dma() in amd74xx/via82cxxx driver, this fixes following bugs: - DMA capability bit not being checked on the device - DMA blacklist not being checked - DMA mode being programmed even if drive->autodma == 0 (thus possibly destroying PIO timings) * Bump driver version. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/amd74xx.c | 15 ++++----------- drivers/ide/pci/via82cxxx.c | 15 ++++----------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 1088ba86cd1d..513205e52ad2 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -1,5 +1,5 @@ /* - * Version 2.21 + * Version 2.22 * * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04 * IDE driver for Linux. @@ -276,18 +276,11 @@ static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio) static int amd74xx_ide_dma_check(ide_drive_t *drive) { - u8 speed = ide_max_dma_mode(drive); - - if (speed == 0) { - ide_set_max_pio(drive); - return -1; - } - - amd_set_drive(drive, speed); - - if (drive->autodma) + if (ide_tune_dma(drive)) return 0; + ide_set_max_pio(drive); + return -1; } diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 2fc4f8835f19..3611ca6b13b7 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -1,6 +1,6 @@ /* * - * Version 3.47 + * Version 3.48 * * VIA IDE driver for Linux. Supported southbridges: * @@ -217,18 +217,11 @@ static void via_set_pio_mode(ide_drive_t *drive, const u8 pio) static int via82cxxx_ide_dma_check (ide_drive_t *drive) { - u8 speed = ide_max_dma_mode(drive); - - if (speed == 0) { - ide_set_max_pio(drive); - return -1; - } - - via_set_drive(drive, speed); - - if (drive->autodma) + if (ide_tune_dma(drive)) return 0; + ide_set_max_pio(drive); + return -1; } From ca1997c1f35891b9e5d6c71ac587f97216886194 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: [PATCH 2190/2804] sgiioc4: use ide_tune_dma() * Add DRV_NAME define and use it instead of sgiioc4_chipset.name. * Remove no longer needed sgiioc4_chipset. * Remove needless clearing of ->atapi_dma from ide_dma_sgiioc4(). * Fix ide_dma_sgiioc4() to return success/failure. Check return value in sgiioc4_ide_setup_pci_device() and set hwif->autodma accordingly. Also add missing setting of drive->autodma. * Add sgiioc4_speedproc() (implementation of ->speedproc method). * Fix ->mwdma_mask (MWDMA2 mask is 0x04 not 0x02) and remove incorrect ->swdma_mask. Also remove needless initialization of ->ultra_mask. * Use ide_tune_dma() in sgiioc4_ide_dma_check(), this fixes following bugs: - DMA capability bit not being checked on the device - DMA blacklist not being checked - MWDMA2 mode support by device not being checked Acked-by: Sergei Shtylyov Signed-off-by: Jeremy Higdon Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sgiioc4.c | 86 +++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 38f63d19c3b9..c292e1de1d56 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -34,6 +34,8 @@ #include +#define DRV_NAME "SGIIOC4" + /* IOC4 Specific Definitions */ #define IOC4_CMD_OFFSET 0x100 #define IOC4_CTRL_OFFSET 0x120 @@ -289,15 +291,26 @@ static void sgiioc4_dma_off_quietly(ide_drive_t *drive) drive->hwif->dma_host_off(drive); } +static int sgiioc4_speedproc(ide_drive_t *drive, const u8 speed) +{ + if (speed != XFER_MW_DMA_2) + return 1; + + return ide_config_drive_speed(drive, speed); +} + static int sgiioc4_ide_dma_check(ide_drive_t *drive) { - /* FIXME: check for available DMA modes */ - if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) { - printk(KERN_WARNING "%s: couldn't set MWDMA2 mode, " - "using PIO instead\n", drive->name); - return -1; - } else + if (ide_tune_dma(drive)) return 0; + + /* + * ->set_pio_mode is not implemented currently + * so this is just for the completness + */ + ide_set_max_pio(drive); + + return -1; } /* returns 1 if dma irq issued, 0 otherwise */ @@ -353,7 +366,7 @@ sgiioc4_INB(unsigned long port) } /* Creates a dma map for the scatter-gather list entries */ -static void __devinit +static int __devinit ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) { void __iomem *virt_dma_base; @@ -369,7 +382,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) "ALREADY in use\n", __FUNCTION__, hwif->name, (void *) dma_base, (void *) dma_base + num_ports - 1); - goto dma_alloc_failure; + return -1; } virt_dma_base = ioremap(dma_base, num_ports); @@ -395,7 +408,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) if (pad) { ide_set_hwifdata(hwif, pad); - return; + return 0; } pci_free_consistent(hwif->pci_dev, @@ -413,10 +426,7 @@ dma_pci_alloc_failure: dma_remap_failure: release_mem_region(dma_base, num_ports); -dma_alloc_failure: - /* Disable DMA because we couldnot allocate any DMA maps */ - hwif->autodma = 0; - hwif->atapi_dma = 0; + return -1; } /* Initializes the IOC4 DMA Engine */ @@ -581,14 +591,11 @@ static void __devinit ide_init_sgiioc4(ide_hwif_t * hwif) { hwif->mmio = 1; - hwif->autodma = 1; hwif->atapi_dma = 1; - hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ - hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */ - hwif->swdma_mask = 0x2; + hwif->mwdma_mask = 0x04; hwif->pio_mask = 0x00; hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */ - hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */ + hwif->speedproc = &sgiioc4_speedproc; hwif->selectproc = NULL;/* Use the default routine to select drive */ hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */ hwif->pre_reset = NULL; /* No HBA specific pre_set needed */ @@ -615,7 +622,7 @@ ide_init_sgiioc4(ide_hwif_t * hwif) } static int __devinit -sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) +sgiioc4_ide_setup_pci_device(struct pci_dev *dev) { unsigned long cmd_base, dma_base, irqport; unsigned long bar0, cmd_phys_base, ctl; @@ -632,7 +639,8 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) break; } if (h == MAX_HWIFS) { - printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", d->name); + printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", + DRV_NAME); return -ENOMEM; } @@ -641,7 +649,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) virt_base = ioremap(bar0, pci_resource_len(dev, 0)); if (virt_base == NULL) { printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n", - d->name, bar0); + DRV_NAME, bar0); return -ENOMEM; } cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET; @@ -672,7 +680,6 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) hwif->chipset = ide_pci; hwif->pci_dev = dev; hwif->channel = 0; /* Single Channel chip */ - hwif->cds = (struct ide_pci_device_s *) d; hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */ /* The IOC4 uses MMIO rather than Port IO. */ @@ -683,11 +690,14 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) ide_init_sgiioc4(hwif); - if (dma_base) - ide_dma_sgiioc4(hwif, dma_base); - else + hwif->autodma = 0; + + if (dma_base && ide_dma_sgiioc4(hwif, dma_base) == 0) { + hwif->autodma = 1; + hwif->drives[1].autodma = hwif->drives[0].autodma = 1; + } else printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n", - hwif->name, d->name); + hwif->name, DRV_NAME); if (probe_hwif_init(hwif)) return -EIO; @@ -699,7 +709,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) } static unsigned int __devinit -pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d) +pci_init_sgiioc4(struct pci_dev *dev) { unsigned int class_rev; int ret; @@ -707,30 +717,20 @@ pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d) pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n", - d->name, pci_name(dev), class_rev); + DRV_NAME, pci_name(dev), class_rev); if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) { printk(KERN_ERR "Skipping %s IDE controller in slot %s: " - "firmware is obsolete - please upgrade to revision" - "46 or higher\n", d->name, pci_name(dev)); + "firmware is obsolete - please upgrade to " + "revision46 or higher\n", + DRV_NAME, pci_name(dev)); ret = -EAGAIN; goto out; } - ret = sgiioc4_ide_setup_pci_device(dev, d); + ret = sgiioc4_ide_setup_pci_device(dev); out: return ret; } -static ide_pci_device_t sgiioc4_chipset __devinitdata = { - /* Channel 0 */ - .name = "SGIIOC4", - .init_hwif = ide_init_sgiioc4, - .init_dma = ide_dma_sgiioc4, - .autodma = AUTODMA, - /* SGI IOC4 doesn't have enablebits. */ - .bootable = ON_BOARD, - .host_flags = IDE_HFLAG_SINGLE, -}; - int ioc4_ide_attach_one(struct ioc4_driver_data *idd) { @@ -740,7 +740,7 @@ ioc4_ide_attach_one(struct ioc4_driver_data *idd) if (idd->idd_variant == IOC4_VARIANT_PCI_RT) return 0; - return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipset); + return pci_init_sgiioc4(idd->idd_pdev); } static struct ioc4_submodule ioc4_ide_submodule = { From f44ae58a273b1b051122784a159ad608b7205afd Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: [PATCH 2191/2804] icside: fix ->speedproc to return on unsupported modes (take 5) * All other implementations of ->speedproc return zero on success and non-zero on failure. Currently it doesn't matter for icside host driver and isn't a bug per se since: - ide_set_xfer_rate() return value is ignored by all IDE core users - icside doesn't (yet!) use ide_tune_dma() in icside_dma_check() but sooner or later we will need to fix anyway - so lets do it now. * icside_set_speed() happily accepts unsupported transfer modes which results in drive->drive_data being set to the maximum value (480) and drive->current_speed being set to the unsupported transfer mode. Fix it. v2: * The initial version of the patch was broken because it didn't take into the account (the different from usual) return values of icside_set_speed() (Noticed by Russell). v3: * Remove no longer needed initialization/checking of cycle_time (Noticed by Sergei). * No need to set drive->drive_data if DMA is not going to be used (Noticed by Sergei). * Remove incorrect setting of drive->current_speed (Noticed by Sergei). * Move ide_config_drive_speed() at the end of icside_set_speed(). v4: * If DMA mode is not found in icside_dma_check() then just return "-1" and don't call icside_set_speed() (v3 got it wrong and "1" was returned instead). v5: * Return "-1"/"0" in icside_set_speed() instead of icside_dma_check() return value (just like it was before this patch). Cc: Russell King Cc: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/icside.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 99a27f2dc03a..7912a471f10d 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -250,7 +250,7 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq) */ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) { - int on = 0, cycle_time = 0, use_dma_info = 0; + int cycle_time, use_dma_info = 0; switch (xfer_mode) { case XFER_MW_DMA_2: @@ -272,6 +272,8 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) case XFER_SW_DMA_0: cycle_time = 480; break; + default: + return 1; } /* @@ -283,17 +285,10 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) drive->drive_data = cycle_time; - if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0) - on = 1; - else - drive->drive_data = 480; - printk("%s: %s selected (peak %dMB/s)\n", drive->name, ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); - drive->current_speed = xfer_mode; - - return on; + return ide_config_drive_speed(drive, xfer_mode); } static void icside_dma_host_off(ide_drive_t *drive) @@ -320,8 +315,7 @@ static int icside_dma_check(ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - int xfer_mode = XFER_PIO_2; - int on; + int xfer_mode = 0; if (!(id->capability & 1) || !hwif->autodma) goto out; @@ -350,9 +344,10 @@ static int icside_dma_check(ide_drive_t *drive) } out: - on = icside_set_speed(drive, xfer_mode); + if (xfer_mode == 0) + return -1; - return on ? 0 : -1; + return icside_set_speed(drive, xfer_mode) ? -1 : 0; } static int icside_dma_end(ide_drive_t *drive) From c15d5d43e6eed180e275f1db296eab5560a1bf59 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: [PATCH 2192/2804] ide-pmac: PIO mode setup fixes (take 3) * Add { 0, 0 } entry to {kauai,shasta}_pio_timings[] so kauai_lookup_timing() always returns a valid PIO timing (fixes PIO timing not being set for devices with minimum PIO cycle <= 120ns). * Add setting transfer mode on the device to pmac_ide_set_pio_mode(). * Fix pmac_ide_set_pio() to always program chipset for given PIO timing instead of only when the device we want to program PIO timing for is the currently selected one. * Now that pmac_ide_set_pio() is fixed there is no need to set transfer mode on the device and program chipset for PIO in pmac_ide_tune_chipset() (returning 0 == success is not entirely correct but is OK for now since the upper layers are only checking ->speedproc return value for DMA modes). v2: * s/speed/XFER_PIO_0 + pio/ in pmac_ide_set_pio_mode() so it actually compiles. * Removal of kauai_lookup_timing() return value checking went to separate patch. v3: * Use XFER_PIO_0 not XFER_PIO. (Noticed by Ben) Cc: Benjamin Herrenschmidt Cc: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ppc/pmac.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index beafdf3c1124..4da251882cc1 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -6,6 +6,7 @@ * for doing DMA. * * Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -311,7 +312,8 @@ static struct kauai_timing kauai_pio_timings[] = { 240 , 0x0800038b }, { 239 , 0x0800030c }, { 180 , 0x05000249 }, - { 120 , 0x04000148 } + { 120 , 0x04000148 }, + { 0 , 0 }, }; static struct kauai_timing kauai_mdma_timings[] = @@ -351,7 +353,8 @@ static struct kauai_timing shasta_pio_timings[] = { 240 , 0x040003cd }, { 239 , 0x040003cd }, { 180 , 0x0400028b }, - { 120 , 0x0400010a } + { 120 , 0x0400010a }, + { 0 , 0 }, }; static struct kauai_timing shasta_mdma_timings[] = @@ -695,8 +698,10 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) drive->name, pio, *timings); #endif - if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG)) - pmac_ide_do_update_timings(drive); + if (pmac_ide_do_setfeature(drive, XFER_PIO_0 + pio)) + return; + + pmac_ide_do_update_timings(drive); } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC @@ -965,7 +970,7 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_1: case XFER_PIO_0: pmac_ide_set_pio_mode(drive, speed & 0x07); - break; + return 0; default: ret = 1; } From fabe1510568acd5194f630dbbcf77a34610d7e9e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: [PATCH 2193/2804] sc1200: remove redundant warning message from sc1200_tune_chipset() ide_config_drive_speed() called by sc1200_set_xfer_mode() already gives a meaningful warning message in case of failure. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sc1200.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index f9f5ed906577..d46627eced91 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -149,10 +149,8 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) /* * Tell the drive to switch to the new mode; abort on failure. */ - if (sc1200_set_xfer_mode(drive, mode)) { - printk("SC1200: set xfer mode failure\n"); + if (sc1200_set_xfer_mode(drive, mode)) return 1; /* failure */ - } switch (mode) { case XFER_PIO_4: From 326d72f437b0a9216290ad8f10817e1e363fd813 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: [PATCH 2194/2804] cs5520: don't enable VDMA in ->speedproc There is no need to do it in cs5520_tune_chipset() (->speedproc method) since it is correctly handled by cs5520_dma_on() (->ide_dma_on method). Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/cs5520.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index a73c318ff086..e6af534a7190 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -73,7 +73,6 @@ static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) int pio = speed; u8 reg; int controller = drive->dn > 1 ? 1 : 0; - int error; switch(speed) { @@ -114,14 +113,9 @@ static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) reg = inb(hwif->dma_base + 0x02 + 8*controller); reg |= 1<<((drive->dn&1)+5); outb(reg, hwif->dma_base + 0x02 + 8*controller); - - error = ide_config_drive_speed(drive, speed); - /* ATAPI is harder so leave it for now */ - if(!error && drive->media == ide_disk) - error = hwif->ide_dma_on(drive); - return error; -} + return ide_config_drive_speed(drive, speed); +} static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) { @@ -177,7 +171,8 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) hwif->drives[1].autotune = 1; return; } - + + /* ATAPI is harder so leave it for now */ hwif->atapi_dma = 0; hwif->ultra_mask = 0; hwif->swdma_mask = 0; From ffe5415c3d6138aff412af7e455b3df4d53c0aa0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: [PATCH 2195/2804] siimage: fix ->set_pio_mode method to select PIO data transfer * Remember to select PIO data transfer (with IORDY monitored) in sil_tune_pio() (->set_pio_mode method) so the controller is always programmed correctly for PIO transfers (this is important if DMA is not going to be used). * Don't set DMA/UDMA timings for PIO modes in siimage_tune_chipset(). * Bump driver version. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/siimage.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index e07c991d91b9..c526c70d65a4 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.15 Jun 29 2007 + * linux/drivers/ide/pci/siimage.c Version 1.16 Jul 13 2007 * * Copyright (C) 2001-2002 Andre Hedrick * Copyright (C) 2003 Red Hat @@ -185,7 +185,12 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) u16 speedp = 0; unsigned long addr = siimage_seldev(drive, 0x04); unsigned long tfaddr = siimage_selreg(hwif, 0x02); + unsigned long base = (unsigned long)hwif->hwif_data; u8 tf_pio = pio; + u8 addr_mask = hwif->channel ? (hwif->mmio ? 0xF4 : 0x84) + : (hwif->mmio ? 0xB4 : 0x80); + u8 mode = 0; + u8 unit = drive->select.b.unit; /* trim *taskfile* PIO to the slowest of the master/slave */ if (pair->present) { @@ -207,6 +212,11 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); else hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); + + mode = hwif->INB(base + addr_mask); + mode &= ~(unit ? 0x30 : 0x03); + mode |= (unit ? 0x10 : 0x01); + hwif->OUTB(mode, base + addr_mask); } else { pci_write_config_word(hwif->pci_dev, addr, speedp); pci_write_config_word(hwif->pci_dev, tfaddr, speedt); @@ -216,6 +226,11 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) if (pio > 2) speedp |= 0x200; pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp); + + pci_read_config_byte(hwif->pci_dev, addr_mask, &mode); + mode &= ~(unit ? 0x30 : 0x03); + mode |= (unit ? 0x10 : 0x01); + pci_write_config_byte(hwif->pci_dev, addr_mask, mode); } } @@ -275,8 +290,7 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_1: case XFER_PIO_0: sil_tune_pio(drive, speed - XFER_PIO_0); - mode |= ((unit) ? 0x10 : 0x01); - break; + return ide_config_drive_speed(drive, speed); case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: From a6fe837ed63aa812bea029a24b7aafc72ba8de88 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: [PATCH 2196/2804] alim15x3: PIO mode setup fixes * Return failure in ->speedproc method for unsupported/invalid transfer modes passed from user-space (fixes theoretical OOPS in ali_tune_pio() and/or setting random PIO timings on host controller + disabling UDMA bit + setting unsupported/invalid transfer mode on the device). * Don't disable UDMA bit when programming PIO modes. * Add FIXME about DMA timings never being set. * Bump driver version. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/alim15x3.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 005402ab748b..f15c8879d2c1 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/alim15x3.c Version 0.25 Jun 9 2007 + * linux/drivers/ide/pci/alim15x3.c Version 0.26 Jul 14 2007 * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer @@ -418,6 +418,14 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) u8 tmpbyte = 0x00; int m5229_udma = (hwif->channel) ? 0x57 : 0x56; + if (speed < XFER_PIO_0) + return 1; + + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_5) { + ali_tune_pio(drive, speed - XFER_PIO_0); + return ide_config_drive_speed(drive, speed); + } + if (speed == XFER_UDMA_6) speed1 = 0x47; @@ -430,8 +438,9 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) tmpbyte &= ultra_enable; pci_write_config_byte(dev, m5229_udma, tmpbyte); - if (speed < XFER_SW_DMA_0) - ali_tune_pio(drive, speed - XFER_PIO_0); + /* + * FIXME: Oh, my... DMA timings are never set. + */ } else { pci_read_config_byte(dev, m5229_udma, &tmpbyte); tmpbyte &= (0x0f << ((1-unit) << 2)); From 90986028c98be10807bb6f48e883f33fa20e5499 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: [PATCH 2197/2804] it8213/piix/slc90e66: don't change DMA settings when programming PIO Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/it8213.c | 16 ++++++---------- drivers/ide/pci/piix.c | 17 +++++++---------- drivers/ide/pci/slc90e66.c | 17 +++++++---------- 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index d07771e06b2d..24ef091ec5b9 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -132,6 +132,11 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) u16 reg4042, reg4a; u8 reg48, reg54, reg55; + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { + it8213_tune_pio(drive, speed - XFER_PIO_0); + return ide_config_drive_speed(drive, speed); + } + pci_read_config_word(dev, maslave, ®4042); pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); @@ -151,12 +156,6 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - break; default: return -1; } @@ -188,10 +187,7 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if (speed > XFER_PIO_4) - it8213_tune_pio(drive, it8213_dma_2_pio(speed)); - else - it8213_tune_pio(drive, speed - XFER_PIO_0); + it8213_tune_pio(drive, it8213_dma_2_pio(speed)); return ide_config_drive_speed(drive, speed); } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 07492d71c602..860b929f6e58 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/piix.c Version 0.51 Jul 6, 2007 + * linux/drivers/ide/pci/piix.c Version 0.52 Jul 14, 2007 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick @@ -242,6 +242,11 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) u16 reg4042, reg4a; u8 reg48, reg54, reg55; + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { + piix_tune_pio(drive, speed - XFER_PIO_0); + return ide_config_drive_speed(drive, speed); + } + pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_byte(dev, 0x48, ®48); @@ -259,11 +264,6 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: break; default: return -1; } @@ -293,10 +293,7 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if (speed > XFER_PIO_4) - piix_tune_pio(drive, piix_dma_2_pio(speed)); - else - piix_tune_pio(drive, speed - XFER_PIO_0); + piix_tune_pio(drive, piix_dma_2_pio(speed)); return ide_config_drive_speed(drive, speed); } diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 214d396fc31f..967b939e9d2e 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/slc90e66.c Version 0.15 Jul 6, 2007 + * linux/drivers/ide/pci/slc90e66.c Version 0.16 Jul 14, 2007 * * Copyright (C) 2000-2002 Andre Hedrick * Copyright (C) 2006-2007 MontaVista Software, Inc. @@ -110,6 +110,11 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) int u_speed = 0, u_flag = 1 << drive->dn; u16 reg4042, reg44, reg48, reg4a; + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { + slc90e66_tune_pio(drive, speed - XFER_PIO_0); + return ide_config_drive_speed(drive, speed); + } + pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_word(dev, 0x44, ®44); @@ -125,11 +130,6 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: break; default: return -1; } @@ -149,10 +149,7 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); } - if (speed > XFER_PIO_4) - slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed)); - else - slc90e66_tune_pio(drive, speed - XFER_PIO_0); + slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed)); return ide_config_drive_speed(drive, speed); } From 0d3be723cb6432e384267d0fe83ee0bae5e17846 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: [PATCH 2198/2804] sis5513: don't change UDMA settings when programming PIO Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sis5513.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 7455bf357ed9..3a8cb1468a76 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/sis5513.c Version 0.26 Jul 7, 2007 + * linux/drivers/ide/pci/sis5513.c Version 0.27 Jul 14, 2007 * * Copyright (C) 1999-2000 Andre Hedrick * Copyright (C) 2002 Lionel Bouton , Maintainer @@ -537,6 +537,9 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) u32 regdw; u8 drive_pci, reg; + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) + return sis5513_tune_drive(drive, speed - XFER_PIO_0); + /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { @@ -601,12 +604,6 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_SW_DMA_1: case XFER_SW_DMA_0: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - return sis5513_tune_drive(drive, speed - XFER_PIO_0); default: BUG(); break; From 8f4dd2e42637fd61a6366d2cace69091926eaa15 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:02 +0200 Subject: [PATCH 2199/2804] ide: use only ->set_pio_mode method for programming PIO modes (take 2) Use ->set_pio_mode method to program PIO modes in ide_set_xfer_rate() (the only place which used ->speedproc to program PIO modes) and remove handling of PIO modes from all ->speedproc implementations. v2: * Fix pmac_ide_tune_chipset() comment. There should be no functionality changes caused by this patch. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/cris/ide-cris.c | 5 ----- drivers/ide/ide-lib.c | 12 ++++++++++++ drivers/ide/mips/au1xxx-ide.c | 5 ----- drivers/ide/pci/alim15x3.c | 5 ----- drivers/ide/pci/atiixp.c | 5 ----- drivers/ide/pci/cmd64x.c | 8 -------- drivers/ide/pci/cs5520.c | 36 ++++++++++++++--------------------- drivers/ide/pci/cs5530.c | 7 ------- drivers/ide/pci/it8213.c | 5 ----- drivers/ide/pci/it821x.c | 9 --------- drivers/ide/pci/piix.c | 5 ----- drivers/ide/pci/sc1200.c | 10 ---------- drivers/ide/pci/scc_pata.c | 7 ------- drivers/ide/pci/serverworks.c | 5 ----- drivers/ide/pci/siimage.c | 7 ------- drivers/ide/pci/sis5513.c | 12 ++---------- drivers/ide/pci/sl82c105.c | 8 -------- drivers/ide/pci/slc90e66.c | 5 ----- drivers/ide/ppc/pmac.c | 9 +-------- 19 files changed, 29 insertions(+), 136 deletions(-) diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 7c90218e9319..4bb42b30bfc0 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -724,11 +724,6 @@ static int speed_cris_ide(ide_drive_t *drive, const u8 speed) { int cyc = 0, dvs = 0, strobe = 0, hold = 0; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - cris_set_pio_mode(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - switch(speed) { case XFER_UDMA_0: diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 8400b1b4aa1b..d97390c0543b 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -398,6 +398,18 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) rate = ide_rate_filter(drive, rate); + if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) { + if (hwif->set_pio_mode) + hwif->set_pio_mode(drive, rate - XFER_PIO_0); + + /* + * FIXME: this is incorrect to return zero here but + * since all users of ide_set_xfer_rate() ignore + * the return value it is not a problem currently + */ + return 0; + } + return hwif->speedproc(drive, rate); } diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 670cb748481f..85819ae20602 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -177,11 +177,6 @@ static int auide_tune_chipset(ide_drive_t *drive, const u8 speed) mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - au1xxx_set_pio_mode(drive, speed - XFER_PIO_0); - return 0; - } - switch(speed) { #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA case XFER_MW_DMA_2: diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index f15c8879d2c1..80013d2bb039 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -421,11 +421,6 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) if (speed < XFER_PIO_0) return 1; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_5) { - ali_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - if (speed == XFER_UDMA_6) speed1 = 0x47; diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index b9f66f53f9a6..178876a3afca 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -178,11 +178,6 @@ static int atiixp_speedproc(ide_drive_t *drive, const u8 speed) u16 tmp16; u8 pio; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - atiixp_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - spin_lock_irqsave(&atiixp_lock, flags); save_mdma_mode[drive->dn] = 0; diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 85f5e42eb831..0b568c60f926 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -323,14 +323,6 @@ static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_0: program_cycle_times(drive, 480, 215); break; - case XFER_PIO_5: - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - cmd64x_tune_pio(drive, speed - XFER_PIO_0); - break; default: return 1; } diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index e6af534a7190..1217d2a747fb 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -66,30 +66,13 @@ static struct pio_clocks cs5520_pio_clocks[]={ {1, 2, 1} }; -static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) +static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *pdev = hwif->pci_dev; - int pio = speed; - u8 reg; int controller = drive->dn > 1 ? 1 : 0; + u8 reg; - switch(speed) - { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - pio -= XFER_PIO_0; - break; - default: - pio = 0; - printk(KERN_ERR "cs55x0: bad ide timing.\n"); - } - - printk("PIO clocking = %d\n", pio); - /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */ /* 8bit CAT/CRT - 8bit command timing for channel */ @@ -114,12 +97,21 @@ static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) reg |= 1<<((drive->dn&1)+5); outb(reg, hwif->dma_base + 0x02 + 8*controller); - return ide_config_drive_speed(drive, speed); + (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) +static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) { - cs5520_tune_chipset(drive, XFER_PIO_0 + pio); + printk(KERN_ERR "cs55x0: bad ide timing.\n"); + + cs5520_set_pio_mode(drive, 0); + + /* + * FIXME: this is incorrect to return zero here but + * since all users of ide_set_xfer_rate() ignore + * the return value it is not a problem currently + */ + return 0; } static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 1588a323c5d0..741507b4cd93 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -163,13 +163,6 @@ static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode) case XFER_MW_DMA_0: timings = 0x00077771; break; case XFER_MW_DMA_1: timings = 0x00012121; break; case XFER_MW_DMA_2: timings = 0x00002020; break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - cs5530_tunepio(drive, mode - XFER_PIO_0); - return 0; default: BUG(); break; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 24ef091ec5b9..76e91ff9420b 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -132,11 +132,6 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) u16 reg4042, reg4a; u8 reg48, reg54, reg55; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - it8213_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - pci_read_config_word(dev, maslave, ®4042); pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 0cce4a7f5e46..758a98230cc5 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -418,15 +418,6 @@ static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed) ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); - switch (speed) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - return it821x_tunepio(drive, speed - XFER_PIO_0); - } - if (itdev->smart == 0) { switch (speed) { /* MWDMA tuning is really hard because our MWDMA and PIO diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 860b929f6e58..fd8214a7ab98 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -242,11 +242,6 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) u16 reg4042, reg4a; u8 reg48, reg54, reg55; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - piix_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_byte(dev, 0x48, ®48); diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index d46627eced91..79ecab689489 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -152,16 +152,6 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) if (sc1200_set_xfer_mode(drive, mode)) return 1; /* failure */ - switch (mode) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - sc1200_tunepio(drive, mode - XFER_PIO_0); - return 0; - } - pci_clock = sc1200_get_pci_clock(); /* diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index 3505d57eda18..66a526e0ece4 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -270,13 +270,6 @@ static int scc_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_UDMA_0: idx = speed - XFER_UDMA_0; break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - scc_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); default: return 1; } diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index f4e08abf0fee..0351cf210427 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -157,11 +157,6 @@ static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed) u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - svwks_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - /* If we are about to put a disk into UDMA mode we screwed up. Our code assumes we never _ever_ do this on an OSB4 */ diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index c526c70d65a4..5d1e5e52a044 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -284,13 +284,6 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) scsc = is_sata(hwif) ? 1 : scsc; switch(speed) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - sil_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 3a8cb1468a76..3e18899de631 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -519,15 +519,10 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) } } -static int sis5513_tune_drive(ide_drive_t *drive, const u8 pio) -{ - config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) { - (void)sis5513_tune_drive(drive, pio); + config_art_rwp_pio(drive, pio); + (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) @@ -537,9 +532,6 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) u32 regdw; u8 drive_pci, reg; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) - return sis5513_tune_drive(drive, speed - XFER_PIO_0); - /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 131e91ca1d82..f492318ba797 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -139,14 +139,6 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_word(dev, reg, drv_ctrl); } break; - case XFER_PIO_5: - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - sl82c105_tune_pio(drive, speed - XFER_PIO_0); - break; default: return -1; } diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 967b939e9d2e..ae8e91324577 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -110,11 +110,6 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) int u_speed = 0, u_flag = 1 << drive->dn; u16 reg4042, reg44, reg48, reg4a; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - slc90e66_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_word(dev, 0x44, ®44); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 4da251882cc1..f759a5397865 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -917,7 +917,7 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, /* * Speedproc. This function is called by the core to set any of the standard - * timing (PIO, MDMA or UDMA) to both the drive and the controller. + * DMA timing (MDMA or UDMA) to both the drive and the controller. * You may notice we don't use this function on normal "dma check" operation, * our dedicated function is more precise as it uses the drive provided * cycle time value. We should probably fix this one to deal with that too... @@ -964,13 +964,6 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_SW_DMA_0: return 1; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - pmac_ide_set_pio_mode(drive, speed & 0x07); - return 0; default: ret = 1; } From f571eff0a24ed97a919f2b61bb4afdeab4b43002 Mon Sep 17 00:00:00 2001 From: "Kevin D. Kissell" Date: Fri, 3 Aug 2007 19:38:03 +0200 Subject: [PATCH 2200/2804] [MIPS] IRQ Affinity Support for SMTC on Malta Platform Signed-off-by: Kevin D. Kissell Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 13 +++++ arch/mips/kernel/i8259.c | 3 ++ arch/mips/kernel/smtc.c | 63 ++++++++++++++++++++++ arch/mips/mips-boards/malta/malta_smtc.c | 50 ++++++++++++++++++ include/asm-mips/irq.h | 67 +++++++++++++++++++++++- include/asm-mips/smtc_ipi.h | 1 + 6 files changed, 195 insertions(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3b807b4bc7cd..b09eee2281c5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1378,6 +1378,19 @@ config MIPS_MT_SMTC_IM_BACKSTOP impact on interrupt service overhead. Disable it only if you know what you are doing. +config MIPS_MT_SMTC_IRQAFF + bool "Support IRQ affinity API" + depends on MIPS_MT_SMTC + default n + help + Enables SMP IRQ affinity API (/proc/irq/*/smp_affinity, etc.) + for SMTC Linux kernel. Requires platform support, of which + an example can be found in the MIPS kernel i8259 and Malta + platform code. It is recommended that MIPS_MT_SMTC_INSTANT_REPLAY + be enabled if MIPS_MT_SMTC_IRQAFF is used. Adds overhead to + interrupt dispatch, and should be used only if you know what + you are doing. + config MIPS_VPE_LOADER_TOM bool "Load VPE program into memory hidden from linux" depends on MIPS_VPE_LOADER diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 3a2d255361bc..4f4359bfd180 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -39,6 +39,9 @@ static struct irq_chip i8259A_chip = { .disable = disable_8259A_irq, .unmask = enable_8259A_irq, .mask_ack = mask_and_ack_8259A, +#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF + .set_affinity = plat_set_irq_affinity, +#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ }; /* diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index f09404377ef1..fe22387d58b1 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -606,6 +606,60 @@ int setup_irq_smtc(unsigned int irq, struct irqaction * new, return setup_irq(irq, new); } +#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF +/* + * Support for IRQ affinity to TCs + */ + +void smtc_set_irq_affinity(unsigned int irq, cpumask_t affinity) +{ + /* + * If a "fast path" cache of quickly decodable affinity state + * is maintained, this is where it gets done, on a call up + * from the platform affinity code. + */ +} + +void smtc_forward_irq(unsigned int irq) +{ + int target; + + /* + * OK wise guy, now figure out how to get the IRQ + * to be serviced on an authorized "CPU". + * + * Ideally, to handle the situation where an IRQ has multiple + * eligible CPUS, we would maintain state per IRQ that would + * allow a fair distribution of service requests. Since the + * expected use model is any-or-only-one, for simplicity + * and efficiency, we just pick the easiest one to find. + */ + + target = first_cpu(irq_desc[irq].affinity); + + /* + * We depend on the platform code to have correctly processed + * IRQ affinity change requests to ensure that the IRQ affinity + * mask has been purged of bits corresponding to nonexistent and + * offline "CPUs", and to TCs bound to VPEs other than the VPE + * connected to the physical interrupt input for the interrupt + * in question. Otherwise we have a nasty problem with interrupt + * mask management. This is best handled in non-performance-critical + * platform IRQ affinity setting code, to minimize interrupt-time + * checks. + */ + + /* If no one is eligible, service locally */ + if (target >= NR_CPUS) { + do_IRQ_no_affinity(irq); + return; + } + + smtc_send_ipi(target, IRQ_AFFINITY_IPI, irq); +} + +#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ + /* * IPI model for SMTC is tricky, because interrupts aren't TC-specific. * Within a VPE one TC can interrupt another by different approaches. @@ -830,6 +884,15 @@ void ipi_decode(struct smtc_ipi *pipi) break; } break; +#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF + case IRQ_AFFINITY_IPI: + /* + * Accept a "forwarded" interrupt that was initially + * taken by a TC who doesn't have affinity for the IRQ. + */ + do_IRQ_no_affinity((int)arg_copy); + break; +#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ default: printk("Impossible SMTC IPI Type 0x%x\n", type_copy); break; diff --git a/arch/mips/mips-boards/malta/malta_smtc.c b/arch/mips/mips-boards/malta/malta_smtc.c index ae05d058cb37..5c980f4a48fe 100644 --- a/arch/mips/mips-boards/malta/malta_smtc.c +++ b/arch/mips/mips-boards/malta/malta_smtc.c @@ -88,3 +88,53 @@ void __cpuinit prom_smp_finish(void) void prom_cpus_done(void) { } + +#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF +/* + * IRQ affinity hook + */ + + +void plat_set_irq_affinity(unsigned int irq, cpumask_t affinity) +{ + cpumask_t tmask = affinity; + int cpu = 0; + void smtc_set_irq_affinity(unsigned int irq, cpumask_t aff); + + /* + * On the legacy Malta development board, all I/O interrupts + * are routed through the 8259 and combined in a single signal + * to the CPU daughterboard, and on the CoreFPGA2/3 34K models, + * that signal is brought to IP2 of both VPEs. To avoid racing + * concurrent interrupt service events, IP2 is enabled only on + * one VPE, by convention VPE0. So long as no bits are ever + * cleared in the affinity mask, there will never be any + * interrupt forwarding. But as soon as a program or operator + * sets affinity for one of the related IRQs, we need to make + * sure that we don't ever try to forward across the VPE boundry, + * at least not until we engineer a system where the interrupt + * _ack() or _end() function can somehow know that it corresponds + * to an interrupt taken on another VPE, and perform the appropriate + * restoration of Status.IM state using MFTR/MTTR instead of the + * normal local behavior. We also ensure that no attempt will + * be made to forward to an offline "CPU". + */ + + for_each_cpu_mask(cpu, affinity) { + if ((cpu_data[cpu].vpe_id != 0) || !cpu_online(cpu)) + cpu_clear(cpu, tmask); + } + irq_desc[irq].affinity = tmask; + + if (cpus_empty(tmask)) + /* + * We could restore a default mask here, but the + * runtime code can anyway deal with the null set + */ + printk(KERN_WARNING + "IRQ affinity leaves no legal CPU for IRQ %d\n", irq); + + /* Do any generic SMTC IRQ affinity setup */ + smtc_set_irq_affinity(irq, tmask); +} +#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h index 2cb52cf8bd4e..a58f0eecc68f 100644 --- a/include/asm-mips/irq.h +++ b/include/asm-mips/irq.h @@ -46,6 +46,38 @@ static inline void smtc_im_ack_irq(unsigned int irq) #endif /* CONFIG_MIPS_MT_SMTC */ +#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF +#include + +extern void plat_set_irq_affinity(unsigned int irq, cpumask_t affinity); +extern void smtc_forward_irq(unsigned int irq); + +/* + * IRQ affinity hook invoked at the beginning of interrupt dispatch + * if option is enabled. + * + * Up through Linux 2.6.22 (at least) cpumask operations are very + * inefficient on MIPS. Initial prototypes of SMTC IRQ affinity + * used a "fast path" per-IRQ-descriptor cache of affinity information + * to reduce latency. As there is a project afoot to optimize the + * cpumask implementations, this version is optimistically assuming + * that cpumask.h macro overhead is reasonable during interrupt dispatch. + */ +#define IRQ_AFFINITY_HOOK(irq) \ +do { \ + if (!cpu_isset(smp_processor_id(), irq_desc[irq].affinity)) { \ + smtc_forward_irq(irq); \ + irq_exit(); \ + return; \ + } \ +} while (0) + +#else /* Not doing SMTC affinity */ + +#define IRQ_AFFINITY_HOOK(irq) do { } while (0) + +#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ + #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP /* @@ -56,13 +88,27 @@ static inline void smtc_im_ack_irq(unsigned int irq) */ #define __DO_IRQ_SMTC_HOOK(irq) \ do { \ + IRQ_AFFINITY_HOOK(irq); \ if (irq_hwmask[irq] & 0x0000ff00) \ write_c0_tccontext(read_c0_tccontext() & \ - ~(irq_hwmask[irq] & 0x0000ff00)); \ + ~(irq_hwmask[irq] & 0x0000ff00)); \ } while (0) + +#define __NO_AFFINITY_IRQ_SMTC_HOOK(irq) \ +do { \ + if (irq_hwmask[irq] & 0x0000ff00) \ + write_c0_tccontext(read_c0_tccontext() & \ + ~(irq_hwmask[irq] & 0x0000ff00)); \ +} while (0) + #else -#define __DO_IRQ_SMTC_HOOK(irq) do { } while (0) +#define __DO_IRQ_SMTC_HOOK(irq) \ +do { \ + IRQ_AFFINITY_HOOK(irq); \ +} while (0) +#define __NO_AFFINITY_IRQ_SMTC_HOOK(irq) do { } while (0) + #endif /* @@ -81,6 +127,23 @@ do { \ irq_exit(); \ } while (0) +#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF +/* + * To avoid inefficient and in some cases pathological re-checking of + * IRQ affinity, we have this variant that skips the affinity check. + */ + + +#define do_IRQ_no_affinity(irq) \ +do { \ + irq_enter(); \ + __NO_AFFINITY_IRQ_SMTC_HOOK(irq); \ + generic_handle_irq(irq); \ + irq_exit(); \ +} while (0) + +#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ + extern void arch_init_irq(void); extern void spurious_interrupt(void); diff --git a/include/asm-mips/smtc_ipi.h b/include/asm-mips/smtc_ipi.h index a52a4a7a36e0..e09131a6127d 100644 --- a/include/asm-mips/smtc_ipi.h +++ b/include/asm-mips/smtc_ipi.h @@ -34,6 +34,7 @@ struct smtc_ipi { #define LINUX_SMP_IPI 1 #define SMTC_CLOCK_TICK 2 +#define IRQ_AFFINITY_IPI 3 /* * A queue of IPI messages From 61a33168bebb6ce5343a5f34ab421971dbfae9fa Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 7 Aug 2007 00:09:17 +0900 Subject: [PATCH 2201/2804] [MIPS] vr41xx: add cpu_wait Add cpu_wait for NEC VR41xx Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/vr41xx/common/pmu.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c index 5e469796413f..e0ffbe9a9844 100644 --- a/arch/mips/vr41xx/common/pmu.c +++ b/arch/mips/vr41xx/common/pmu.c @@ -1,7 +1,7 @@ /* * pmu.c, Power Management Unit routines for NEC VR4100 series. * - * Copyright (C) 2003-2005 Yoichi Yuasa + * Copyright (C) 2003-2007 Yoichi Yuasa * * 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 @@ -22,11 +22,12 @@ #include #include #include -#include +#include #include #include #include +#include #include #include @@ -44,6 +45,18 @@ static void __iomem *pmu_base; #define pmu_read(offset) readw(pmu_base + (offset)) #define pmu_write(offset, value) writew((value), pmu_base + (offset)) +static void vr41xx_cpu_wait(void) +{ + local_irq_disable(); + if (!need_resched()) + /* + * "standby" sets IE bit of the CP0_STATUS to 1. + */ + __asm__("standby;\n"); + else + local_irq_enable(); +} + static inline void software_reset(void) { uint16_t pmucnt2; @@ -113,6 +126,7 @@ static int __init vr41xx_pmu_init(void) return -EBUSY; } + cpu_wait = vr41xx_cpu_wait; _machine_restart = vr41xx_restart; _machine_halt = vr41xx_halt; pm_power_off = vr41xx_power_off; From d87d0c930a1591617e4c7c78296b4ba029150188 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:45:58 +0100 Subject: [PATCH 2202/2804] [MIPS] SMTC: Microoptimize atomic_postincrement for non-weak consistency. Signed-off-by: Ralf Baechle --- arch/mips/kernel/smtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index fe22387d58b1..137183bba54f 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -713,7 +713,7 @@ static __inline__ int atomic_postincrement(unsigned int *pv) " addu %1, %0, 1 \n" " sc %1, %2 \n" " beqz %1, 1b \n" - " sync \n" + __WEAK_LLSC_MB : "=&r" (result), "=&r" (temp), "=m" (*pv) : "m" (*pv) : "memory"); From 8c67316e706cabc2145d6c8e97f0bd8f2a86d8a1 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 15 Feb 2007 12:06:47 +0100 Subject: [PATCH 2203/2804] [MIPS] Remove '-mno-explicit-relocs' option when CONFIG_BUILD_ELF64 This patch removes '-mno-explicit-relocs' usage when CONFIG_BUILD_ELF64 is set since this option was only required with the old hack to truncate addresses at the assembly level where "-mabi=64 -Wa,-mabi=32" was used. This should yield a small code size improvement for inline assembly, where the R constraint is used. The idea is coming from Maciej . Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 32c1c8fb6f98..d5d5831b6e24 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -60,9 +60,7 @@ vmlinux-32 = vmlinux.32 vmlinux-64 = vmlinux cflags-y += -mabi=64 -ifdef CONFIG_BUILD_ELF64 -cflags-y += $(call cc-option,-mno-explicit-relocs) -else +ifndef CONFIG_BUILD_ELF64 cflags-y += $(call cc-option,-msym32) endif endif From adff90a9333004d5459823665e8bcf6cb9214f79 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 15 Feb 2007 12:06:48 +0100 Subject: [PATCH 2204/2804] [MIPS] Automatically set CONFIG_BUILD_ELF64 We do not rely on user anymore to setup this config correctly. Instead we make our choice depending on the load address. If we want to force Kbuild to use ELF64 format whatever the load address we can still do: $ make BUILD_ELF32=no Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 15 --------------- arch/mips/Makefile | 23 ++++++++++++++++++++--- include/asm-mips/page.h | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b09eee2281c5..492f581fe6ba 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1853,21 +1853,6 @@ source "fs/Kconfig.binfmt" config TRAD_SIGNALS bool -config BUILD_ELF64 - bool "Use 64-bit ELF format for building" - depends on 64BIT - help - A 64-bit kernel is usually built using the 64-bit ELF binary object - format as it's one that allows arbitrary 64-bit constructs. For - kernels that are loaded within the KSEG compatibility segments the - 32-bit ELF format can optionally be used resulting in a somewhat - smaller binary, but this option is not explicitly supported by the - toolchain and since binutils 2.14 it does not even work at all. - - Say Y to use the 64-bit format or N to use the 32-bit one. - - If unsure say Y. - config BINFMT_IRIX bool "Include IRIX binary compatibility" depends on CPU_BIG_ENDIAN && 32BIT && BROKEN diff --git a/arch/mips/Makefile b/arch/mips/Makefile index d5d5831b6e24..4337c492ed1b 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -60,9 +60,6 @@ vmlinux-32 = vmlinux.32 vmlinux-64 = vmlinux cflags-y += -mabi=64 -ifndef CONFIG_BUILD_ELF64 -cflags-y += $(call cc-option,-msym32) -endif endif all-$(CONFIG_BOOT_ELF32) := $(vmlinux-32) @@ -576,6 +573,26 @@ else JIFFIES = jiffies_64 endif +# +# Automatically detect the build format. By default we choose +# the elf format according to the load address. +# We can always force a build with a 64-bits symbol format by +# passing 'BUILD_ELF32=no' option to the make's command line. +# +ifdef CONFIG_64BIT + ifndef BUILD_ELF32 + ifeq ($(shell expr $(load-y) \< 0xffffffff80000000), 0) + BUILD_ELF32 = y + endif + endif + + ifeq ($(BUILD_ELF32), y) + cflags-y += -msym32 + else + cflags-y += -DCONFIG_BUILD_ELF64 + endif +endif + AFLAGS += $(cflags-y) CFLAGS += $(cflags-y) \ -D"VMLINUX_LOAD_ADDRESS=$(load-y)" diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index e3301e54d559..b92dd8c760da 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -142,7 +142,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; /* * __pa()/__va() should be used only during mem init. */ -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64) #define __pa(x) \ ({ \ unsigned long __x = (unsigned long)(x); \ From 054c51b4368648406f487f54b7ed6ba75bbb3f8b Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 15 Feb 2007 14:21:36 +0100 Subject: [PATCH 2205/2804] [MIPS] Rename CONFIG_BUILD_ELF64 into KBUILD_64BIT_SYM32 This patch renames it for 3 reasons: - "CONFIG" pattern is used by Kconfig. Now this macro is no more defined by Kconfig but by Kbuild itself make this clear by translating "CONFIG" into "KBUILD". - "ELF32" word is improper because it is irrelevant to ELF format and it makes confusion with CONFIG_BOOT_ELF32. So translate it with SYM32. - Add "64BIT" part to make clear that this macro implies a 64 bits kernel. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 12 +++++------- include/asm-mips/page.h | 2 +- include/asm-mips/pgtable-64.h | 2 +- include/asm-mips/stackframe.h | 12 ++++++------ 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 4337c492ed1b..ce7e02e613a7 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -577,19 +577,17 @@ endif # Automatically detect the build format. By default we choose # the elf format according to the load address. # We can always force a build with a 64-bits symbol format by -# passing 'BUILD_ELF32=no' option to the make's command line. +# passing 'KBUILD_SYM32=no' option to the make's command line. # ifdef CONFIG_64BIT - ifndef BUILD_ELF32 + ifndef KBUILD_SYM32 ifeq ($(shell expr $(load-y) \< 0xffffffff80000000), 0) - BUILD_ELF32 = y + KBUILD_SYM32 = y endif endif - ifeq ($(BUILD_ELF32), y) - cflags-y += -msym32 - else - cflags-y += -DCONFIG_BUILD_ELF64 + ifeq ($(KBUILD_SYM32), y) + cflags-y += -msym32 -DKBUILD_64BIT_SYM32 endif endif diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index b92dd8c760da..c90fe560a0d9 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -142,7 +142,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; /* * __pa()/__va() should be used only during mem init. */ -#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64) +#ifdef KBUILD_64BIT_SYM32 #define __pa(x) \ ({ \ unsigned long __x = (unsigned long)(x); \ diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h index 49f5a1a2dfcd..a8aed9c6a159 100644 --- a/include/asm-mips/pgtable-64.h +++ b/include/asm-mips/pgtable-64.h @@ -104,7 +104,7 @@ #define VMALLOC_START MAP_BASE #define VMALLOC_END \ (VMALLOC_START + PTRS_PER_PGD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE) -#if defined(CONFIG_MODULES) && !defined(CONFIG_BUILD_ELF64) && \ +#if defined(CONFIG_MODULES) && defined(KBUILD_64BIT_SYM32) && \ VMALLOC_START != CKSSEG /* Load modules into 32bit-compatible segment. */ #define MODULE_START CKSSEG diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h index ed33366b85b8..59334f598b78 100644 --- a/include/asm-mips/stackframe.h +++ b/include/asm-mips/stackframe.h @@ -91,14 +91,14 @@ #else MFC0 k0, CP0_CONTEXT #endif -#if defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_64BIT) && __GNUC__ < 4) +#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) + lui k1, %hi(kernelsp) +#else lui k1, %highest(kernelsp) daddiu k1, %higher(kernelsp) dsll k1, 16 daddiu k1, %hi(kernelsp) dsll k1, 16 -#else - lui k1, %hi(kernelsp) #endif LONG_SRL k0, PTEBASE_SHIFT LONG_ADDU k1, k0 @@ -116,14 +116,14 @@ .endm #else .macro get_saved_sp /* Uniprocessor variation */ -#if defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_64BIT) && __GNUC__ < 4) +#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) + lui k1, %hi(kernelsp) +#else lui k1, %highest(kernelsp) daddiu k1, %higher(kernelsp) dsll k1, k1, 16 daddiu k1, %hi(kernelsp) dsll k1, k1, 16 -#else - lui k1, %hi(kernelsp) #endif LONG_L k1, %lo(kernelsp)(k1) .endm From 2f2a2d9987c4836493bfb2a80960056ef86742d2 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 16 Aug 2007 22:20:11 +0900 Subject: [PATCH 2206/2804] [MIPS] VR41xx: Add default restart routine. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/vr41xx/common/pmu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c index e0ffbe9a9844..ba0a4f6483a2 100644 --- a/arch/mips/vr41xx/common/pmu.c +++ b/arch/mips/vr41xx/common/pmu.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,11 @@ static inline void software_reset(void) pmu_write(PMUCNT2REG, pmucnt2); break; default: + set_c0_status(ST0_BEV | ST0_ERL); + change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_c0_wired(0); + __asm__("jr %0"::"r"(0xbfc00000)); break; } } @@ -78,7 +84,6 @@ static void vr41xx_restart(char *command) { local_irq_disable(); software_reset(); - printk(KERN_NOTICE "\nYou can reset your system\n"); while (1) ; } From fa41780606e7a5999a9096269c0ad8e7cee2b95b Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 16 Aug 2007 22:27:05 +0900 Subject: [PATCH 2207/2804] [MIPS] VR41xx: replace infinite loop with hibernate Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/vr41xx/common/pmu.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c index ba0a4f6483a2..ad5b6db53396 100644 --- a/arch/mips/vr41xx/common/pmu.c +++ b/arch/mips/vr41xx/common/pmu.c @@ -91,14 +91,7 @@ static void vr41xx_halt(void) { local_irq_disable(); printk(KERN_NOTICE "\nYou can turn off the power supply\n"); - while (1) ; -} - -static void vr41xx_power_off(void) -{ - local_irq_disable(); - printk(KERN_NOTICE "\nYou can turn off the power supply\n"); - while (1) ; + __asm__("hibernate;\n"); } static int __init vr41xx_pmu_init(void) @@ -134,7 +127,7 @@ static int __init vr41xx_pmu_init(void) cpu_wait = vr41xx_cpu_wait; _machine_restart = vr41xx_restart; _machine_halt = vr41xx_halt; - pm_power_off = vr41xx_power_off; + pm_power_off = vr41xx_halt; return 0; } From ddcf4efb7a5a38c2d82decbdfd99c43bbf226551 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 16 Aug 2007 22:54:02 +0900 Subject: [PATCH 2208/2804] [MIPS] IP27: remove duplicate extern dump_tlb_all() prototype Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/sgi-ip27/ip27-berr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/mips/sgi-ip27/ip27-berr.c b/arch/mips/sgi-ip27/ip27-berr.c index 123141ab21a2..7d05e68fdc77 100644 --- a/arch/mips/sgi-ip27/ip27-berr.c +++ b/arch/mips/sgi-ip27/ip27-berr.c @@ -21,8 +21,6 @@ #include #include -extern void dump_tlb_all(void); - static void dump_hub_information(unsigned long errst0, unsigned long errst1) { static char *err_type[2][8] = { From 4c6d0fc2f6ce44161f3fac3b34d262c0dd06cf0c Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 16 Aug 2007 22:56:04 +0900 Subject: [PATCH 2209/2804] [MIPS] remove unused include/asm-mips/ip32/machine.h Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- include/asm-mips/ip32/machine.h | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 include/asm-mips/ip32/machine.h diff --git a/include/asm-mips/ip32/machine.h b/include/asm-mips/ip32/machine.h deleted file mode 100644 index 1b631b8da6f8..000000000000 --- a/include/asm-mips/ip32/machine.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * machine.h -- Machine/group probing for ip32 - * - * Copyright (C) 2001 Keith M Wesolowski - * - * 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. - */ -#ifndef _ASM_IP32_MACHINE_H -#define _ASM_IP32_MACHINE_H - - -#ifdef CONFIG_SGI_IP32 - -#define SGI_MACH_O2 0x3201 - -#endif /* CONFIG_SGI_IP32 */ - -#endif /* _ASM_SGI_MACHINE_H */ From 0caf583398309398ec05fc76bff15c711e9f936d Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 16 Aug 2007 23:15:42 +0900 Subject: [PATCH 2210/2804] [MIPS] fix ABI check in include/asm-mips/arv/hinv.h Fix ABI check in include/asm-mips/arv/hinv.h Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- include/asm-mips/arc/hinv.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/asm-mips/arc/hinv.h b/include/asm-mips/arc/hinv.h index ee792bf04002..1862912ab148 100644 --- a/include/asm-mips/arc/hinv.h +++ b/include/asm-mips/arc/hinv.h @@ -4,6 +4,7 @@ #ifndef _ASM_ARC_HINV_H #define _ASM_ARC_HINV_H +#include #include /* configuration query defines */ @@ -110,7 +111,7 @@ union key_u { ULONG FullKey; }; -#if _MIPS_SIM == _ABI64 +#if _MIPS_SIM == _MIPS_SIM_ABI64 #define SGI_ARCS_VERS 64 /* sgi 64-bit version */ #define SGI_ARCS_REV 0 /* rev .00 */ #else From 1f21d2bde0046e959b53756f74d96dfd040a803b Mon Sep 17 00:00:00 2001 From: Brian Murphy Date: Tue, 21 Aug 2007 22:34:16 +0200 Subject: [PATCH 2211/2804] [MIPS] Add back support for LASAT platforms Signed-off-by: Brian Murphy Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 18 + arch/mips/Makefile | 13 + arch/mips/configs/lasat_defconfig | 828 +++++++++++++++++++++ arch/mips/lasat/Kconfig | 15 + arch/mips/lasat/Makefile | 16 + arch/mips/lasat/at93c.c | 149 ++++ arch/mips/lasat/at93c.h | 18 + arch/mips/lasat/ds1603.c | 183 +++++ arch/mips/lasat/ds1603.h | 33 + arch/mips/lasat/image/Makefile | 54 ++ arch/mips/lasat/image/head.S | 31 + arch/mips/lasat/image/romscript.normal | 23 + arch/mips/lasat/interrupt.c | 130 ++++ arch/mips/lasat/lasat_board.c | 280 +++++++ arch/mips/lasat/lasat_models.h | 67 ++ arch/mips/lasat/picvue.c | 244 ++++++ arch/mips/lasat/picvue.h | 48 ++ arch/mips/lasat/picvue_proc.c | 191 +++++ arch/mips/lasat/prom.c | 128 ++++ arch/mips/lasat/prom.h | 7 + arch/mips/lasat/reset.c | 61 ++ arch/mips/lasat/serial.c | 94 +++ arch/mips/lasat/setup.c | 158 ++++ arch/mips/lasat/sysctl.c | 454 +++++++++++ arch/mips/lasat/sysctl.h | 24 + arch/mips/pci/Makefile | 2 + arch/mips/pci/ops-nile4.c | 147 ++++ arch/mips/pci/pci-lasat.c | 91 +++ include/asm-mips/bootinfo.h | 7 + include/asm-mips/lasat/ds1603.h | 18 + include/asm-mips/lasat/eeprom.h | 17 + include/asm-mips/lasat/head.h | 22 + include/asm-mips/lasat/lasat.h | 256 +++++++ include/asm-mips/lasat/lasatint.h | 12 + include/asm-mips/lasat/picvue.h | 15 + include/asm-mips/lasat/serial.h | 13 + include/asm-mips/mach-lasat/mach-gt64120.h | 27 + include/asm-mips/nile4.h | 310 ++++++++ 38 files changed, 4204 insertions(+) create mode 100644 arch/mips/configs/lasat_defconfig create mode 100644 arch/mips/lasat/Kconfig create mode 100644 arch/mips/lasat/Makefile create mode 100644 arch/mips/lasat/at93c.c create mode 100644 arch/mips/lasat/at93c.h create mode 100644 arch/mips/lasat/ds1603.c create mode 100644 arch/mips/lasat/ds1603.h create mode 100644 arch/mips/lasat/image/Makefile create mode 100644 arch/mips/lasat/image/head.S create mode 100644 arch/mips/lasat/image/romscript.normal create mode 100644 arch/mips/lasat/interrupt.c create mode 100644 arch/mips/lasat/lasat_board.c create mode 100644 arch/mips/lasat/lasat_models.h create mode 100644 arch/mips/lasat/picvue.c create mode 100644 arch/mips/lasat/picvue.h create mode 100644 arch/mips/lasat/picvue_proc.c create mode 100644 arch/mips/lasat/prom.c create mode 100644 arch/mips/lasat/prom.h create mode 100644 arch/mips/lasat/reset.c create mode 100644 arch/mips/lasat/serial.c create mode 100644 arch/mips/lasat/setup.c create mode 100644 arch/mips/lasat/sysctl.c create mode 100644 arch/mips/lasat/sysctl.h create mode 100644 arch/mips/pci/ops-nile4.c create mode 100644 arch/mips/pci/pci-lasat.c create mode 100644 include/asm-mips/lasat/ds1603.h create mode 100644 include/asm-mips/lasat/eeprom.h create mode 100644 include/asm-mips/lasat/head.h create mode 100644 include/asm-mips/lasat/lasat.h create mode 100644 include/asm-mips/lasat/lasatint.h create mode 100644 include/asm-mips/lasat/picvue.h create mode 100644 include/asm-mips/lasat/serial.h create mode 100644 include/asm-mips/mach-lasat/mach-gt64120.h create mode 100644 include/asm-mips/nile4.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 492f581fe6ba..bb3fb4018602 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -107,6 +107,20 @@ config MACH_JAZZ Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and Olivetti M700-10 workstations. +config LASAT + bool "LASAT Networks platforms" + select DMA_NONCOHERENT + select SYS_HAS_EARLY_PRINTK + select HW_HAS_PCI + select PCI_GT64XXX_PCI0 + select MIPS_NILE4 + select R5000_CPU_SCACHE + select SYS_HAS_CPU_R5000 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL if BROKEN + select SYS_SUPPORTS_LITTLE_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ + config LEMOTE_FULONG bool "Lemote Fulong mini-PC" select ARCH_SPARSEMEM_ENABLE @@ -599,6 +613,7 @@ endchoice source "arch/mips/au1000/Kconfig" source "arch/mips/jazz/Kconfig" +source "arch/mips/lasat/Kconfig" source "arch/mips/pmc-sierra/Kconfig" source "arch/mips/sgi-ip27/Kconfig" source "arch/mips/sibyte/Kconfig" @@ -706,6 +721,9 @@ config MIPS_BONITO64 config MIPS_MSC bool +config MIPS_NILE4 + bool + config MIPS_DISABLE_OBSOLETE_IDE bool diff --git a/arch/mips/Makefile b/arch/mips/Makefile index ce7e02e613a7..6dcdbfb15ce3 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -361,6 +361,13 @@ core-$(CONFIG_BASLER_EXCITE) += arch/mips/basler/excite/ cflags-$(CONFIG_BASLER_EXCITE) += -Iinclude/asm-mips/mach-excite load-$(CONFIG_BASLER_EXCITE) += 0x80100000 +# +# LASAT platforms +# +core-$(CONFIG_LASAT) += arch/mips/lasat/ +cflags-$(CONFIG_LASAT) += -Iinclude/asm-mips/mach-lasat +load-$(CONFIG_LASAT) += 0xffffffff80000000 + # # Common VR41xx # @@ -628,6 +635,11 @@ core-y += arch/mips/kernel/ arch/mips/mm/ arch/mips/math-emu/ drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/ +ifdef CONFIG_LASAT +rom.bin rom.sw: vmlinux + $(Q)$(MAKE) $(build)=arch/mips/lasat/image $@ +endif + # # Some machines like the Indy need 32-bit ELF binaries for booting purposes. # Other need ECOFF, so we build a 32-bit ELF binary for them which we then @@ -671,6 +683,7 @@ endif archclean: @$(MAKE) $(clean)=arch/mips/boot + @$(MAKE) $(clean)=arch/mips/lasat define archhelp echo ' vmlinux.ecoff - ECOFF boot image' diff --git a/arch/mips/configs/lasat_defconfig b/arch/mips/configs/lasat_defconfig new file mode 100644 index 000000000000..2c665fcef089 --- /dev/null +++ b/arch/mips/configs/lasat_defconfig @@ -0,0 +1,828 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc3 +# Sat Aug 18 17:37:58 2007 +# +CONFIG_MIPS=y + +# +# Machine selection +# +# CONFIG_MACH_ALCHEMY is not set +# CONFIG_BASLER_EXCITE is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +CONFIG_LASAT=y +# CONFIG_LEMOTE_FULONG is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MARKEINS is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_QEMU is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_PTSWARM is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SNI_RM is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_TOSHIBA_RBTX4938 is not set +# CONFIG_WR_PPMC is not set +CONFIG_PICVUE=y +CONFIG_PICVUE_PROC=y +CONFIG_DS1603=y +CONFIG_LASAT_SYSCTL=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +CONFIG_EARLY_PRINTK=y +CONFIG_SYS_HAS_EARLY_PRINTK=y +# CONFIG_HOTPLUG_CPU is not set +CONFIG_MIPS_NILE4=y +# CONFIG_NO_IOPORT is not set +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_PCI_GT64XXX_PCI0=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +# CONFIG_CPU_LOONGSON2 is not set +# CONFIG_CPU_MIPS32_R1 is not set +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +CONFIG_CPU_R5000=y +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_SYS_HAS_CPU_R5000=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y + +# +# Kernel type +# +CONFIG_32BIT=y +# CONFIG_64BIT is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_BOARD_SCACHE=y +CONFIG_R5000_CPU_SCACHE=y +CONFIG_MIPS_MT_DISABLED=y +# CONFIG_MIPS_MT_SMP is not set +# CONFIG_MIPS_MT_SMTC is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +CONFIG_HZ_1000=y +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=1000 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +# CONFIG_KEXEC is not set +# CONFIG_SECCOMP is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_SIGNALFD is not set +# CONFIG_TIMERFD is not set +# CONFIG_EVENTFD is not set +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_MMU=y + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_TRAD_SIGNALS=y + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_LASAT=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_PCIBUS_ORDER=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_DM9000 is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=y +# CONFIG_PCNET32_NAPI is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_TC35815 is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_LIBPS2 is not set +CONFIG_SERIO_RAW=y +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +CONFIG_CONFIGFS_FS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_CROSSCOMPILE=y +CONFIG_CMDLINE="" + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/mips/lasat/Kconfig b/arch/mips/lasat/Kconfig new file mode 100644 index 000000000000..1d2ee8a9be13 --- /dev/null +++ b/arch/mips/lasat/Kconfig @@ -0,0 +1,15 @@ +config PICVUE + tristate "PICVUE LCD display driver" + depends on LASAT + +config PICVUE_PROC + tristate "PICVUE LCD display driver /proc interface" + depends on PICVUE + +config DS1603 + bool "DS1603 RTC driver" + depends on LASAT + +config LASAT_SYSCTL + bool "LASAT sysctl interface" + depends on LASAT diff --git a/arch/mips/lasat/Makefile b/arch/mips/lasat/Makefile new file mode 100644 index 000000000000..33791609fe99 --- /dev/null +++ b/arch/mips/lasat/Makefile @@ -0,0 +1,16 @@ +# +# Makefile for the LASAT specific kernel interface routines under Linux. +# + +obj-y += reset.o setup.o prom.o lasat_board.o \ + at93c.o interrupt.o serial.o + +obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o +obj-$(CONFIG_DS1603) += ds1603.o +obj-$(CONFIG_PICVUE) += picvue.o +obj-$(CONFIG_PICVUE_PROC) += picvue_proc.o + +clean: + make -C image clean + +EXTRA_CFLAGS += -Werror diff --git a/arch/mips/lasat/at93c.c b/arch/mips/lasat/at93c.c new file mode 100644 index 000000000000..793e234719a6 --- /dev/null +++ b/arch/mips/lasat/at93c.c @@ -0,0 +1,149 @@ +/* + * Atmel AT93C46 serial eeprom driver + * + * Brian Murphy + * + */ +#include +#include +#include +#include +#include + +#include "at93c.h" + +#define AT93C_ADDR_SHIFT 7 +#define AT93C_ADDR_MAX ((1 << AT93C_ADDR_SHIFT) - 1) +#define AT93C_RCMD (0x6 << AT93C_ADDR_SHIFT) +#define AT93C_WCMD (0x5 << AT93C_ADDR_SHIFT) +#define AT93C_WENCMD 0x260 +#define AT93C_WDSCMD 0x200 + +struct at93c_defs *at93c; + +static void at93c_reg_write(u32 val) +{ + *at93c->reg = val; +} + +static u32 at93c_reg_read(void) +{ + u32 tmp = *at93c->reg; + return tmp; +} + +static u32 at93c_datareg_read(void) +{ + u32 tmp = *at93c->rdata_reg; + return tmp; +} + +static void at93c_cycle_clk(u32 data) +{ + at93c_reg_write(data | at93c->clk); + lasat_ndelay(250); + at93c_reg_write(data & ~at93c->clk); + lasat_ndelay(250); +} + +static void at93c_write_databit(u8 bit) +{ + u32 data = at93c_reg_read(); + if (bit) + data |= 1 << at93c->wdata_shift; + else + data &= ~(1 << at93c->wdata_shift); + + at93c_reg_write(data); + lasat_ndelay(100); + at93c_cycle_clk(data); +} + +static unsigned int at93c_read_databit(void) +{ + u32 data; + + at93c_cycle_clk(at93c_reg_read()); + data = (at93c_datareg_read() >> at93c->rdata_shift) & 1; + return data; +} + +static u8 at93c_read_byte(void) +{ + int i; + u8 data = 0; + + for (i = 0; i <= 7; i++) { + data <<= 1; + data |= at93c_read_databit(); + } + return data; +} + +static void at93c_write_bits(u32 data, int size) +{ + int i; + int shift = size - 1; + u32 mask = (1 << shift); + + for (i = 0; i < size; i++) { + at93c_write_databit((data & mask) >> shift); + data <<= 1; + } +} + +static void at93c_init_op(void) +{ + at93c_reg_write((at93c_reg_read() | at93c->cs) & + ~at93c->clk & ~(1 << at93c->rdata_shift)); + lasat_ndelay(50); +} + +static void at93c_end_op(void) +{ + at93c_reg_write(at93c_reg_read() & ~at93c->cs); + lasat_ndelay(250); +} + +static void at93c_wait(void) +{ + at93c_init_op(); + while (!at93c_read_databit()) + ; + at93c_end_op(); +}; + +static void at93c_disable_wp(void) +{ + at93c_init_op(); + at93c_write_bits(AT93C_WENCMD, 10); + at93c_end_op(); +} + +static void at93c_enable_wp(void) +{ + at93c_init_op(); + at93c_write_bits(AT93C_WDSCMD, 10); + at93c_end_op(); +} + +u8 at93c_read(u8 addr) +{ + u8 byte; + at93c_init_op(); + at93c_write_bits((addr & AT93C_ADDR_MAX)|AT93C_RCMD, 10); + byte = at93c_read_byte(); + at93c_end_op(); + return byte; +} + +void at93c_write(u8 addr, u8 data) +{ + at93c_disable_wp(); + at93c_init_op(); + at93c_write_bits((addr & AT93C_ADDR_MAX)|AT93C_WCMD, 10); + at93c_write_bits(data, 8); + at93c_end_op(); + at93c_wait(); + at93c_enable_wp(); +} diff --git a/arch/mips/lasat/at93c.h b/arch/mips/lasat/at93c.h new file mode 100644 index 000000000000..cfe2f99b1d44 --- /dev/null +++ b/arch/mips/lasat/at93c.h @@ -0,0 +1,18 @@ +/* + * Atmel AT93C46 serial eeprom driver + * + * Brian Murphy + * + */ + +extern struct at93c_defs { + volatile u32 *reg; + volatile u32 *rdata_reg; + int rdata_shift; + int wdata_shift; + u32 cs; + u32 clk; +} *at93c; + +u8 at93c_read(u8 addr); +void at93c_write(u8 addr, u8 data); diff --git a/arch/mips/lasat/ds1603.c b/arch/mips/lasat/ds1603.c new file mode 100644 index 000000000000..0b315f51d62c --- /dev/null +++ b/arch/mips/lasat/ds1603.c @@ -0,0 +1,183 @@ +/* + * Dallas Semiconductors 1603 RTC driver + * + * Brian Murphy + * + */ +#include +#include +#include +#include +#include + +#include "ds1603.h" + +#define READ_TIME_CMD 0x81 +#define SET_TIME_CMD 0x80 +#define TRIMMER_SET_CMD 0xC0 +#define TRIMMER_VALUE_MASK 0x38 +#define TRIMMER_SHIFT 3 + +struct ds_defs *ds1603; + +/* HW specific register functions */ +static void rtc_reg_write(unsigned long val) +{ + *ds1603->reg = val; +} + +static unsigned long rtc_reg_read(void) +{ + unsigned long tmp = *ds1603->reg; + return tmp; +} + +static unsigned long rtc_datareg_read(void) +{ + unsigned long tmp = *ds1603->data_reg; + return tmp; +} + +static void rtc_nrst_high(void) +{ + rtc_reg_write(rtc_reg_read() | ds1603->rst); +} + +static void rtc_nrst_low(void) +{ + rtc_reg_write(rtc_reg_read() & ~ds1603->rst); +} + +static void rtc_cycle_clock(unsigned long data) +{ + data |= ds1603->clk; + rtc_reg_write(data); + lasat_ndelay(250); + if (ds1603->data_reversed) + data &= ~ds1603->data; + else + data |= ds1603->data; + data &= ~ds1603->clk; + rtc_reg_write(data); + lasat_ndelay(250 + ds1603->huge_delay); +} + +static void rtc_write_databit(unsigned int bit) +{ + unsigned long data = rtc_reg_read(); + if (ds1603->data_reversed) + bit = !bit; + if (bit) + data |= ds1603->data; + else + data &= ~ds1603->data; + + rtc_reg_write(data); + lasat_ndelay(50 + ds1603->huge_delay); + rtc_cycle_clock(data); +} + +static unsigned int rtc_read_databit(void) +{ + unsigned int data; + + data = (rtc_datareg_read() & (1 << ds1603->data_read_shift)) + >> ds1603->data_read_shift; + rtc_cycle_clock(rtc_reg_read()); + return data; +} + +static void rtc_write_byte(unsigned int byte) +{ + int i; + + for (i = 0; i <= 7; i++) { + rtc_write_databit(byte & 1L); + byte >>= 1; + } +} + +static void rtc_write_word(unsigned long word) +{ + int i; + + for (i = 0; i <= 31; i++) { + rtc_write_databit(word & 1L); + word >>= 1; + } +} + +static unsigned long rtc_read_word(void) +{ + int i; + unsigned long word = 0; + unsigned long shift = 0; + + for (i = 0; i <= 31; i++) { + word |= rtc_read_databit() << shift; + shift++; + } + return word; +} + +static void rtc_init_op(void) +{ + rtc_nrst_high(); + + rtc_reg_write(rtc_reg_read() & ~ds1603->clk); + + lasat_ndelay(50); +} + +static void rtc_end_op(void) +{ + rtc_nrst_low(); + lasat_ndelay(1000); +} + +/* interface */ +unsigned long ds1603_read(void) +{ + unsigned long word; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + rtc_init_op(); + rtc_write_byte(READ_TIME_CMD); + word = rtc_read_word(); + rtc_end_op(); + spin_unlock_irqrestore(&rtc_lock, flags); + return word; +} + +int ds1603_set(unsigned long time) +{ + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + rtc_init_op(); + rtc_write_byte(SET_TIME_CMD); + rtc_write_word(time); + rtc_end_op(); + spin_unlock_irqrestore(&rtc_lock, flags); + + return 0; +} + +void ds1603_set_trimmer(unsigned int trimval) +{ + rtc_init_op(); + rtc_write_byte(((trimval << TRIMMER_SHIFT) & TRIMMER_VALUE_MASK) + | (TRIMMER_SET_CMD)); + rtc_end_op(); +} + +void ds1603_disable(void) +{ + ds1603_set_trimmer(TRIMMER_DISABLE_RTC); +} + +void ds1603_enable(void) +{ + ds1603_set_trimmer(TRIMMER_DEFAULT); +} diff --git a/arch/mips/lasat/ds1603.h b/arch/mips/lasat/ds1603.h new file mode 100644 index 000000000000..c2e5c76a379d --- /dev/null +++ b/arch/mips/lasat/ds1603.h @@ -0,0 +1,33 @@ +/* + * Dallas Semiconductors 1603 RTC driver + * + * Brian Murphy + * + */ +#ifndef __DS1603_H +#define __DS1603_H + +struct ds_defs { + volatile u32 *reg; + volatile u32 *data_reg; + u32 rst; + u32 clk; + u32 data; + u32 data_read_shift; + char data_reversed; + u32 huge_delay; +}; + +extern struct ds_defs *ds1603; + +unsigned long ds1603_read(void); +int ds1603_set(unsigned long); +void ds1603_set_trimmer(unsigned int); +void ds1603_enable(void); +void ds1603_disable(void); +void ds1603_init(struct ds_defs *); + +#define TRIMMER_DEFAULT 3 +#define TRIMMER_DISABLE_RTC 0 + +#endif diff --git a/arch/mips/lasat/image/Makefile b/arch/mips/lasat/image/Makefile new file mode 100644 index 000000000000..5332449ec040 --- /dev/null +++ b/arch/mips/lasat/image/Makefile @@ -0,0 +1,54 @@ +# +# MAKEFILE FOR THE MIPS LINUX BOOTLOADER AND ROM DEBUGGER +# +# i-data Networks +# +# Author: Thomas Horsten +# + +ifndef Version + Version = "$(USER)-test" +endif + +MKLASATIMG = mklasatimg +MKLASATIMG_ARCH = mq2,mqpro,sp100,sp200 +KERNEL_IMAGE = $(TOPDIR)/vmlinux +KERNEL_START = $(shell $(NM) $(KERNEL_IMAGE) | grep " _text" | cut -f1 -d\ ) +KERNEL_ENTRY = $(shell $(NM) $(KERNEL_IMAGE) | grep kernel_entry | cut -f1 -d\ ) + +LDSCRIPT= -L$(obj) -Tromscript.normal + +HEAD_DEFINES := -D_kernel_start=0x$(KERNEL_START) \ + -D_kernel_entry=0x$(KERNEL_ENTRY) \ + -D VERSION="\"$(Version)\"" \ + -D TIMESTAMP=$(shell date +%s) + +$(obj)/head.o: $(obj)/head.S $(KERNEL_IMAGE) + $(CC) -fno-pic $(HEAD_DEFINES) -I$(TOPDIR)/include -c -o $@ $< + +OBJECTS = head.o kImage.o + +rom.sw: $(obj)/rom.sw +rom.bin: $(obj)/rom.bin + +$(obj)/rom.sw: $(obj)/rom.bin + $(MKLASATIMG) -o $@ -k $^ -m $(MKLASATIMG_ARCH) + +$(obj)/rom.bin: $(obj)/rom + $(OBJCOPY) -O binary -S $^ $@ + +# Rule to make the bootloader +$(obj)/rom: $(addprefix $(obj)/,$(OBJECTS)) + $(LD) $(LDFLAGS) $(LDSCRIPT) -o $@ $^ + +$(obj)/%.o: $(obj)/%.gz + $(LD) -r -o $@ -b binary $< + +$(obj)/%.gz: $(obj)/%.bin + gzip -cf -9 $< > $@ + +$(obj)/kImage.bin: $(KERNEL_IMAGE) + $(OBJCOPY) -O binary -S $^ $@ + +clean: + rm -f rom rom.bin rom.sw kImage.bin kImage.o diff --git a/arch/mips/lasat/image/head.S b/arch/mips/lasat/image/head.S new file mode 100644 index 000000000000..efb95f2609c2 --- /dev/null +++ b/arch/mips/lasat/image/head.S @@ -0,0 +1,31 @@ +#include + + .text + .section .text.start, "ax" + .set noreorder + .set mips3 + + /* Magic words identifying a software image */ + .word LASAT_K_MAGIC0_VAL + .word LASAT_K_MAGIC1_VAL + + /* Image header version */ + .word 0x00000002 + + /* image start and size */ + .word _image_start + .word _image_size + + /* start of kernel and entrypoint in uncompressed image */ + .word _kernel_start + .word _kernel_entry + + /* Here we have room for future flags */ + + .org 0x40 +reldate: + .word TIMESTAMP + + .org 0x50 +release: + .string VERSION diff --git a/arch/mips/lasat/image/romscript.normal b/arch/mips/lasat/image/romscript.normal new file mode 100644 index 000000000000..988f8ad189cb --- /dev/null +++ b/arch/mips/lasat/image/romscript.normal @@ -0,0 +1,23 @@ +OUTPUT_ARCH(mips) + +SECTIONS +{ + .text : + { + *(.text.start) + } + + /* Data in ROM */ + + .data ALIGN(0x10) : + { + *(.data) + } + _image_start = ADDR(.data); + _image_size = SIZEOF(.data); + + .other : + { + *(.*) + } +} diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c new file mode 100644 index 000000000000..5f35289bfff5 --- /dev/null +++ b/arch/mips/lasat/interrupt.c @@ -0,0 +1,130 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute 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 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. + * + * Routines for generic manipulation of the interrupts found on the + * Lasat boards. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static volatile int *lasat_int_status; +static volatile int *lasat_int_mask; +static volatile int lasat_int_mask_shift; + +void disable_lasat_irq(unsigned int irq_nr) +{ + *lasat_int_mask &= ~(1 << irq_nr) << lasat_int_mask_shift; +} + +void enable_lasat_irq(unsigned int irq_nr) +{ + *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift; +} + +static struct irq_chip lasat_irq_type = { + .name = "Lasat", + .ack = disable_lasat_irq, + .mask = disable_lasat_irq, + .mask_ack = disable_lasat_irq, + .unmask = enable_lasat_irq, +}; + +static inline int ls1bit32(unsigned int x) +{ + int b = 31, s; + + s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; + s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; + s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; + s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; + s = 1; if (x << 1 == 0) s = 0; b -= s; + + return b; +} + +static unsigned long (*get_int_status)(void); + +static unsigned long get_int_status_100(void) +{ + return *lasat_int_status & *lasat_int_mask; +} + +static unsigned long get_int_status_200(void) +{ + unsigned long int_status; + + int_status = *lasat_int_status; + int_status &= (int_status >> LASATINT_MASK_SHIFT_200) & 0xffff; + return int_status; +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned long int_status; + unsigned int cause = read_c0_cause(); + int irq; + + if (cause & CAUSEF_IP7) { /* R4000 count / compare IRQ */ + ll_timer_interrupt(7); + return; + } + + int_status = get_int_status(); + + /* if int_status == 0, then the interrupt has already been cleared */ + if (int_status) { + irq = ls1bit32(int_status); + + do_IRQ(irq); + } +} + +void __init arch_init_irq(void) +{ + int i; + + switch (mips_machtype) { + case MACH_LASAT_100: + lasat_int_status = (void *)LASAT_INT_STATUS_REG_100; + lasat_int_mask = (void *)LASAT_INT_MASK_REG_100; + lasat_int_mask_shift = LASATINT_MASK_SHIFT_100; + get_int_status = get_int_status_100; + *lasat_int_mask = 0; + break; + case MACH_LASAT_200: + lasat_int_status = (void *)LASAT_INT_STATUS_REG_200; + lasat_int_mask = (void *)LASAT_INT_MASK_REG_200; + lasat_int_mask_shift = LASATINT_MASK_SHIFT_200; + get_int_status = get_int_status_200; + *lasat_int_mask &= 0xffff; + break; + default: + panic("arch_init_irq: mips_machtype incorrect"); + } + + for (i = 0; i <= LASATINT_END; i++) + set_irq_chip_and_handler(i, &lasat_irq_type, handle_level_irq); +} diff --git a/arch/mips/lasat/lasat_board.c b/arch/mips/lasat/lasat_board.c new file mode 100644 index 000000000000..ec2f658c3709 --- /dev/null +++ b/arch/mips/lasat/lasat_board.c @@ -0,0 +1,280 @@ +/* + * Thomas Horsten + * Copyright (C) 2000 LASAT Networks A/S. + * + * This program is free software; you can distribute 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 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. + * + * Routines specific to the LASAT boards + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "at93c.h" +/* New model description table */ +#include "lasat_models.h" + +#define EEPROM_CRC(data, len) (~crc32(~0, data, len)) + +struct lasat_info lasat_board_info; + +void update_bcastaddr(void); + +int EEPROMRead(unsigned int pos, unsigned char *data, int len) +{ + int i; + + for (i = 0; i < len; i++) + *data++ = at93c_read(pos++); + + return 0; +} + +int EEPROMWrite(unsigned int pos, unsigned char *data, int len) +{ + int i; + + for (i = 0; i < len; i++) + at93c_write(pos++, *data++); + + return 0; +} + +static void init_flash_sizes(void) +{ + unsigned long *lb = lasat_board_info.li_flashpart_base; + unsigned long *ls = lasat_board_info.li_flashpart_size; + int i; + + ls[LASAT_MTD_BOOTLOADER] = 0x40000; + ls[LASAT_MTD_SERVICE] = 0xC0000; + ls[LASAT_MTD_NORMAL] = 0x100000; + + if (mips_machtype == MACH_LASAT_100) { + lasat_board_info.li_flash_base = 0x1e000000; + + lb[LASAT_MTD_BOOTLOADER] = 0x1e400000; + + if (lasat_board_info.li_flash_size > 0x200000) { + ls[LASAT_MTD_CONFIG] = 0x100000; + ls[LASAT_MTD_FS] = 0x500000; + } + } else { + lasat_board_info.li_flash_base = 0x10000000; + + if (lasat_board_info.li_flash_size < 0x1000000) { + lb[LASAT_MTD_BOOTLOADER] = 0x10000000; + ls[LASAT_MTD_CONFIG] = 0x100000; + if (lasat_board_info.li_flash_size >= 0x400000) + ls[LASAT_MTD_FS] = + lasat_board_info.li_flash_size - 0x300000; + } + } + + for (i = 1; i < LASAT_MTD_LAST; i++) + lb[i] = lb[i-1] + ls[i-1]; +} + +int lasat_init_board_info(void) +{ + int c; + unsigned long crc; + unsigned long cfg0, cfg1; + const struct product_info *ppi; + int i_n_base_models = N_BASE_MODELS; + const char * const * i_txt_base_models = txt_base_models; + int i_n_prids = N_PRIDS; + + memset(&lasat_board_info, 0, sizeof(lasat_board_info)); + + /* First read the EEPROM info */ + EEPROMRead(0, (unsigned char *)&lasat_board_info.li_eeprom_info, + sizeof(struct lasat_eeprom_struct)); + + /* Check the CRC */ + crc = EEPROM_CRC((unsigned char *)(&lasat_board_info.li_eeprom_info), + sizeof(struct lasat_eeprom_struct) - 4); + + if (crc != lasat_board_info.li_eeprom_info.crc32) { + printk(KERN_WARNING "WARNING...\nWARNING...\nEEPROM CRC does " + "not match calculated, attempting to soldier on...\n"); + } + + if (lasat_board_info.li_eeprom_info.version != LASAT_EEPROM_VERSION) { + printk(KERN_WARNING "WARNING...\nWARNING...\nEEPROM version " + "%d, wanted version %d, attempting to soldier on...\n", + (unsigned int)lasat_board_info.li_eeprom_info.version, + LASAT_EEPROM_VERSION); + } + + cfg0 = lasat_board_info.li_eeprom_info.cfg[0]; + cfg1 = lasat_board_info.li_eeprom_info.cfg[1]; + + if (LASAT_W0_DSCTYPE(cfg0) != 1) { + printk(KERN_WARNING "WARNING...\nWARNING...\n" + "Invalid configuration read from EEPROM, attempting to " + "soldier on..."); + } + /* We have a valid configuration */ + + switch (LASAT_W0_SDRAMBANKSZ(cfg0)) { + case 0: + lasat_board_info.li_memsize = 0x0800000; + break; + case 1: + lasat_board_info.li_memsize = 0x1000000; + break; + case 2: + lasat_board_info.li_memsize = 0x2000000; + break; + case 3: + lasat_board_info.li_memsize = 0x4000000; + break; + case 4: + lasat_board_info.li_memsize = 0x8000000; + break; + default: + lasat_board_info.li_memsize = 0; + } + + switch (LASAT_W0_SDRAMBANKS(cfg0)) { + case 0: + break; + case 1: + lasat_board_info.li_memsize *= 2; + break; + default: + break; + } + + switch (LASAT_W0_BUSSPEED(cfg0)) { + case 0x0: + lasat_board_info.li_bus_hz = 60000000; + break; + case 0x1: + lasat_board_info.li_bus_hz = 66000000; + break; + case 0x2: + lasat_board_info.li_bus_hz = 66666667; + break; + case 0x3: + lasat_board_info.li_bus_hz = 80000000; + break; + case 0x4: + lasat_board_info.li_bus_hz = 83333333; + break; + case 0x5: + lasat_board_info.li_bus_hz = 100000000; + break; + } + + switch (LASAT_W0_CPUCLK(cfg0)) { + case 0x0: + lasat_board_info.li_cpu_hz = + lasat_board_info.li_bus_hz; + break; + case 0x1: + lasat_board_info.li_cpu_hz = + lasat_board_info.li_bus_hz + + (lasat_board_info.li_bus_hz >> 1); + break; + case 0x2: + lasat_board_info.li_cpu_hz = + lasat_board_info.li_bus_hz + + lasat_board_info.li_bus_hz; + break; + case 0x3: + lasat_board_info.li_cpu_hz = + lasat_board_info.li_bus_hz + + lasat_board_info.li_bus_hz + + (lasat_board_info.li_bus_hz >> 1); + break; + case 0x4: + lasat_board_info.li_cpu_hz = + lasat_board_info.li_bus_hz + + lasat_board_info.li_bus_hz + + lasat_board_info.li_bus_hz; + break; + } + + /* Flash size */ + switch (LASAT_W1_FLASHSIZE(cfg1)) { + case 0: + lasat_board_info.li_flash_size = 0x200000; + break; + case 1: + lasat_board_info.li_flash_size = 0x400000; + break; + case 2: + lasat_board_info.li_flash_size = 0x800000; + break; + case 3: + lasat_board_info.li_flash_size = 0x1000000; + break; + case 4: + lasat_board_info.li_flash_size = 0x2000000; + break; + } + + init_flash_sizes(); + + lasat_board_info.li_bmid = LASAT_W0_BMID(cfg0); + lasat_board_info.li_prid = lasat_board_info.li_eeprom_info.prid; + if (lasat_board_info.li_prid == 0xffff || lasat_board_info.li_prid == 0) + lasat_board_info.li_prid = lasat_board_info.li_bmid; + + /* Base model stuff */ + if (lasat_board_info.li_bmid > i_n_base_models) + lasat_board_info.li_bmid = i_n_base_models; + strcpy(lasat_board_info.li_bmstr, + i_txt_base_models[lasat_board_info.li_bmid]); + + /* Product ID dependent values */ + c = lasat_board_info.li_prid; + if (c >= i_n_prids) { + strcpy(lasat_board_info.li_namestr, "Unknown Model"); + strcpy(lasat_board_info.li_typestr, "Unknown Type"); + } else { + ppi = &vendor_info_table[0].vi_product_info[c]; + strcpy(lasat_board_info.li_namestr, ppi->pi_name); + if (ppi->pi_type) + strcpy(lasat_board_info.li_typestr, ppi->pi_type); + else + sprintf(lasat_board_info.li_typestr, "%d", 10 * c); + } + +#if defined(CONFIG_INET) && defined(CONFIG_SYSCTL) + update_bcastaddr(); +#endif + + return 0; +} + +void lasat_write_eeprom_info(void) +{ + unsigned long crc; + + /* Generate the CRC */ + crc = EEPROM_CRC((unsigned char *)(&lasat_board_info.li_eeprom_info), + sizeof(struct lasat_eeprom_struct) - 4); + lasat_board_info.li_eeprom_info.crc32 = crc; + + /* Write the EEPROM info */ + EEPROMWrite(0, (unsigned char *)&lasat_board_info.li_eeprom_info, + sizeof(struct lasat_eeprom_struct)); +} diff --git a/arch/mips/lasat/lasat_models.h b/arch/mips/lasat/lasat_models.h new file mode 100644 index 000000000000..e1cbd26ae1b3 --- /dev/null +++ b/arch/mips/lasat/lasat_models.h @@ -0,0 +1,67 @@ +/* + * Model description tables + */ +#include + +struct product_info { + const char *pi_name; + const char *pi_type; +}; + +struct vendor_info { + const char *vi_name; + const struct product_info *vi_product_info; +}; + +/* + * Base models + */ +static const char * const txt_base_models[] = { + "MQ 2", "MQ Pro", "SP 25", "SP 50", "SP 100", "SP 5000", "SP 7000", + "SP 1000", "Unknown" +}; +#define N_BASE_MODELS (ARRAY_SIZE(txt_base_models) - 1) + +/* + * Eicon Networks + */ +static const char txt_en_mq[] = "Masquerade"; +static const char txt_en_sp[] = "Safepipe"; + +static const struct product_info product_info_eicon[] = { + { txt_en_mq, "II" }, /* 0 */ + { txt_en_mq, "Pro" }, /* 1 */ + { txt_en_sp, "25" }, /* 2 */ + { txt_en_sp, "50" }, /* 3 */ + { txt_en_sp, "100" }, /* 4 */ + { txt_en_sp, "5000" }, /* 5 */ + { txt_en_sp, "7000" }, /* 6 */ + { txt_en_sp, "30" }, /* 7 */ + { txt_en_sp, "5100" }, /* 8 */ + { txt_en_sp, "7100" }, /* 9 */ + { txt_en_sp, "1110" }, /* 10 */ + { txt_en_sp, "3020" }, /* 11 */ + { txt_en_sp, "3030" }, /* 12 */ + { txt_en_sp, "5020" }, /* 13 */ + { txt_en_sp, "5030" }, /* 14 */ + { txt_en_sp, "1120" }, /* 15 */ + { txt_en_sp, "1130" }, /* 16 */ + { txt_en_sp, "6010" }, /* 17 */ + { txt_en_sp, "6110" }, /* 18 */ + { txt_en_sp, "6210" }, /* 19 */ + { txt_en_sp, "1020" }, /* 20 */ + { txt_en_sp, "1040" }, /* 21 */ + { txt_en_sp, "1050" }, /* 22 */ + { txt_en_sp, "1060" }, /* 23 */ +}; + +#define N_PRIDS ARRAY_SIZE(product_info_eicon) + +/* + * The vendor table + */ +static struct vendor_info const vendor_info_table[] = { + { "Eicon Networks", product_info_eicon }, +}; + +#define N_VENDORS ARRAY_SIZE(vendor_info_table) diff --git a/arch/mips/lasat/picvue.c b/arch/mips/lasat/picvue.c new file mode 100644 index 000000000000..6471d0663fd8 --- /dev/null +++ b/arch/mips/lasat/picvue.c @@ -0,0 +1,244 @@ +/* + * Picvue PVC160206 display driver + * + * Brian Murphy + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "picvue.h" + +#define PVC_BUSY 0x80 +#define PVC_NLINES 2 +#define PVC_DISPMEM 80 +#define PVC_LINELEN PVC_DISPMEM / PVC_NLINES + +struct pvc_defs *picvue; + +DECLARE_MUTEX(pvc_sem); + +static void pvc_reg_write(u32 val) +{ + *picvue->reg = val; +} + +static u32 pvc_reg_read(void) +{ + u32 tmp = *picvue->reg; + return tmp; +} + +static void pvc_write_byte(u32 data, u8 byte) +{ + data |= picvue->e; + pvc_reg_write(data); + data &= ~picvue->data_mask; + data |= byte << picvue->data_shift; + pvc_reg_write(data); + ndelay(220); + pvc_reg_write(data & ~picvue->e); + ndelay(220); +} + +static u8 pvc_read_byte(u32 data) +{ + u8 byte; + + data |= picvue->e; + pvc_reg_write(data); + ndelay(220); + byte = (pvc_reg_read() & picvue->data_mask) >> picvue->data_shift; + data &= ~picvue->e; + pvc_reg_write(data); + ndelay(220); + return byte; +} + +static u8 pvc_read_data(void) +{ + u32 data = pvc_reg_read(); + u8 byte; + data |= picvue->rw; + data &= ~picvue->rs; + pvc_reg_write(data); + ndelay(40); + byte = pvc_read_byte(data); + data |= picvue->rs; + pvc_reg_write(data); + return byte; +} + +#define TIMEOUT 1000 +static int pvc_wait(void) +{ + int i = TIMEOUT; + int err = 0; + + while ((pvc_read_data() & PVC_BUSY) && i) + i--; + if (i == 0) + err = -ETIME; + + return err; +} + +#define MODE_INST 0 +#define MODE_DATA 1 +static void pvc_write(u8 byte, int mode) +{ + u32 data = pvc_reg_read(); + data &= ~picvue->rw; + if (mode == MODE_DATA) + data |= picvue->rs; + else + data &= ~picvue->rs; + pvc_reg_write(data); + ndelay(40); + pvc_write_byte(data, byte); + if (mode == MODE_DATA) + data &= ~picvue->rs; + else + data |= picvue->rs; + pvc_reg_write(data); + pvc_wait(); +} + +void pvc_write_string(const unsigned char *str, u8 addr, int line) +{ + int i = 0; + + if (line > 0 && (PVC_NLINES > 1)) + addr += 0x40 * line; + pvc_write(0x80 | addr, MODE_INST); + + while (*str != 0 && i < PVC_LINELEN) { + pvc_write(*str++, MODE_DATA); + i++; + } +} + +void pvc_write_string_centered(const unsigned char *str, int line) +{ + int len = strlen(str); + u8 addr; + + if (len > PVC_VISIBLE_CHARS) + addr = 0; + else + addr = (PVC_VISIBLE_CHARS - strlen(str))/2; + + pvc_write_string(str, addr, line); +} + +void pvc_dump_string(const unsigned char *str) +{ + int len = strlen(str); + + pvc_write_string(str, 0, 0); + if (len > PVC_VISIBLE_CHARS) + pvc_write_string(&str[PVC_VISIBLE_CHARS], 0, 1); +} + +#define BM_SIZE 8 +#define MAX_PROGRAMMABLE_CHARS 8 +int pvc_program_cg(int charnum, u8 bitmap[BM_SIZE]) +{ + int i; + int addr; + + if (charnum > MAX_PROGRAMMABLE_CHARS) + return -ENOENT; + + addr = charnum * 8; + pvc_write(0x40 | addr, MODE_INST); + + for (i = 0; i < BM_SIZE; i++) + pvc_write(bitmap[i], MODE_DATA); + return 0; +} + +#define FUNC_SET_CMD 0x20 +#define EIGHT_BYTE (1 << 4) +#define FOUR_BYTE 0 +#define TWO_LINES (1 << 3) +#define ONE_LINE 0 +#define LARGE_FONT (1 << 2) +#define SMALL_FONT 0 + +static void pvc_funcset(u8 cmd) +{ + pvc_write(FUNC_SET_CMD | (cmd & (EIGHT_BYTE|TWO_LINES|LARGE_FONT)), + MODE_INST); +} + +#define ENTRYMODE_CMD 0x4 +#define AUTO_INC (1 << 1) +#define AUTO_DEC 0 +#define CURSOR_FOLLOWS_DISP (1 << 0) + +static void pvc_entrymode(u8 cmd) +{ + pvc_write(ENTRYMODE_CMD | (cmd & (AUTO_INC|CURSOR_FOLLOWS_DISP)), + MODE_INST); +} + +#define DISP_CNT_CMD 0x08 +#define DISP_OFF 0 +#define DISP_ON (1 << 2) +#define CUR_ON (1 << 1) +#define CUR_BLINK (1 << 0) +void pvc_dispcnt(u8 cmd) +{ + pvc_write(DISP_CNT_CMD | (cmd & (DISP_ON|CUR_ON|CUR_BLINK)), MODE_INST); +} + +#define MOVE_CMD 0x10 +#define DISPLAY (1 << 3) +#define CURSOR 0 +#define RIGHT (1 << 2) +#define LEFT 0 +void pvc_move(u8 cmd) +{ + pvc_write(MOVE_CMD | (cmd & (DISPLAY|RIGHT)), MODE_INST); +} + +#define CLEAR_CMD 0x1 +void pvc_clear(void) +{ + pvc_write(CLEAR_CMD, MODE_INST); +} + +#define HOME_CMD 0x2 +void pvc_home(void) +{ + pvc_write(HOME_CMD, MODE_INST); +} + +int pvc_init(void) +{ + u8 cmd = EIGHT_BYTE; + + if (PVC_NLINES == 2) + cmd |= (SMALL_FONT|TWO_LINES); + else + cmd |= (LARGE_FONT|ONE_LINE); + pvc_funcset(cmd); + pvc_dispcnt(DISP_ON); + pvc_entrymode(AUTO_INC); + + pvc_clear(); + pvc_write_string_centered("Display", 0); + pvc_write_string_centered("Initialized", 1); + + return 0; +} + +module_init(pvc_init); +MODULE_LICENSE("GPL"); diff --git a/arch/mips/lasat/picvue.h b/arch/mips/lasat/picvue.h new file mode 100644 index 000000000000..2a96bf971897 --- /dev/null +++ b/arch/mips/lasat/picvue.h @@ -0,0 +1,48 @@ +/* + * Picvue PVC160206 display driver + * + * Brian Murphy + * + */ +#include + +struct pvc_defs { + volatile u32 *reg; + u32 data_shift; + u32 data_mask; + u32 e; + u32 rw; + u32 rs; +}; + +extern struct pvc_defs *picvue; + +#define PVC_NLINES 2 +#define PVC_DISPMEM 80 +#define PVC_LINELEN PVC_DISPMEM / PVC_NLINES +#define PVC_VISIBLE_CHARS 16 + +void pvc_write_string(const unsigned char *str, u8 addr, int line); +void pvc_write_string_centered(const unsigned char *str, int line); +void pvc_dump_string(const unsigned char *str); + +#define BM_SIZE 8 +#define MAX_PROGRAMMABLE_CHARS 8 +int pvc_program_cg(int charnum, u8 bitmap[BM_SIZE]); + +void pvc_dispcnt(u8 cmd); +#define DISP_OFF 0 +#define DISP_ON (1 << 2) +#define CUR_ON (1 << 1) +#define CUR_BLINK (1 << 0) + +void pvc_move(u8 cmd); +#define DISPLAY (1 << 3) +#define CURSOR 0 +#define RIGHT (1 << 2) +#define LEFT 0 + +void pvc_clear(void); +void pvc_home(void); + +extern struct semaphore pvc_sem; diff --git a/arch/mips/lasat/picvue_proc.c b/arch/mips/lasat/picvue_proc.c new file mode 100644 index 000000000000..9947c1525822 --- /dev/null +++ b/arch/mips/lasat/picvue_proc.c @@ -0,0 +1,191 @@ +/* + * Picvue PVC160206 display driver + * + * Brian Murphy + * + */ +#include +#include +#include +#include + +#include +#include + +#include + +#include "picvue.h" + +static char pvc_lines[PVC_NLINES][PVC_LINELEN+1]; +static int pvc_linedata[PVC_NLINES]; +static struct proc_dir_entry *pvc_display_dir; +static char *pvc_linename[PVC_NLINES] = {"line1", "line2"}; +#define DISPLAY_DIR_NAME "display" +static int scroll_dir, scroll_interval; + +static struct timer_list timer; + +static void pvc_display(unsigned long data) +{ + int i; + + pvc_clear(); + for (i = 0; i < PVC_NLINES; i++) + pvc_write_string(pvc_lines[i], 0, i); +} + +static DECLARE_TASKLET(pvc_display_tasklet, &pvc_display, 0); + +static int pvc_proc_read_line(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + char *origpage = page; + int lineno = *(int *)data; + + if (lineno < 0 || lineno > PVC_NLINES) { + printk(KERN_WARNING "proc_read_line: invalid lineno %d\n", lineno); + return 0; + } + + down(&pvc_sem); + page += sprintf(page, "%s\n", pvc_lines[lineno]); + up(&pvc_sem); + + return page - origpage; +} + +static int pvc_proc_write_line(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int origcount = count; + int lineno = *(int *)data; + + if (lineno < 0 || lineno > PVC_NLINES) { + printk(KERN_WARNING "proc_write_line: invalid lineno %d\n", + lineno); + return origcount; + } + + if (count > PVC_LINELEN) + count = PVC_LINELEN; + + if (buffer[count-1] == '\n') + count--; + + down(&pvc_sem); + strncpy(pvc_lines[lineno], buffer, count); + pvc_lines[lineno][count] = '\0'; + up(&pvc_sem); + + tasklet_schedule(&pvc_display_tasklet); + + return origcount; +} + +static int pvc_proc_write_scroll(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int origcount = count; + int cmd = simple_strtol(buffer, NULL, 10); + + down(&pvc_sem); + if (scroll_interval != 0) + del_timer(&timer); + + if (cmd == 0) { + scroll_dir = 0; + scroll_interval = 0; + } else { + if (cmd < 0) { + scroll_dir = -1; + scroll_interval = -cmd; + } else { + scroll_dir = 1; + scroll_interval = cmd; + } + add_timer(&timer); + } + up(&pvc_sem); + + return origcount; +} + +static int pvc_proc_read_scroll(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + char *origpage = page; + + down(&pvc_sem); + page += sprintf(page, "%d\n", scroll_dir * scroll_interval); + up(&pvc_sem); + + return page - origpage; +} + + +void pvc_proc_timerfunc(unsigned long data) +{ + if (scroll_dir < 0) + pvc_move(DISPLAY|RIGHT); + else if (scroll_dir > 0) + pvc_move(DISPLAY|LEFT); + + timer.expires = jiffies + scroll_interval; + add_timer(&timer); +} + +static void pvc_proc_cleanup(void) +{ + int i; + for (i = 0; i < PVC_NLINES; i++) + remove_proc_entry(pvc_linename[i], pvc_display_dir); + remove_proc_entry("scroll", pvc_display_dir); + remove_proc_entry(DISPLAY_DIR_NAME, NULL); + + del_timer(&timer); +} + +static int __init pvc_proc_init(void) +{ + struct proc_dir_entry *proc_entry; + int i; + + pvc_display_dir = proc_mkdir(DISPLAY_DIR_NAME, NULL); + if (pvc_display_dir == NULL) + goto error; + + for (i = 0; i < PVC_NLINES; i++) { + strcpy(pvc_lines[i], ""); + pvc_linedata[i] = i; + } + for (i = 0; i < PVC_NLINES; i++) { + proc_entry = create_proc_entry(pvc_linename[i], 0644, + pvc_display_dir); + if (proc_entry == NULL) + goto error; + + proc_entry->read_proc = pvc_proc_read_line; + proc_entry->write_proc = pvc_proc_write_line; + proc_entry->data = &pvc_linedata[i]; + } + proc_entry = create_proc_entry("scroll", 0644, pvc_display_dir); + if (proc_entry == NULL) + goto error; + + proc_entry->write_proc = pvc_proc_write_scroll; + proc_entry->read_proc = pvc_proc_read_scroll; + + init_timer(&timer); + timer.function = pvc_proc_timerfunc; + + return 0; +error: + pvc_proc_cleanup(); + return -ENOMEM; +} + +module_init(pvc_proc_init); +module_exit(pvc_proc_cleanup); +MODULE_LICENSE("GPL"); diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c new file mode 100644 index 000000000000..4b80fffcf262 --- /dev/null +++ b/arch/mips/lasat/prom.c @@ -0,0 +1,128 @@ +/* + * PROM interface routines. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "at93c.h" +#include +#include "prom.h" + +#define RESET_VECTOR 0xbfc00000 +#define PROM_JUMP_TABLE_ENTRY(n) (*((u32 *)(RESET_VECTOR + 0x20) + n)) +#define PROM_DISPLAY_ADDR PROM_JUMP_TABLE_ENTRY(0) +#define PROM_PUTC_ADDR PROM_JUMP_TABLE_ENTRY(1) +#define PROM_MONITOR_ADDR PROM_JUMP_TABLE_ENTRY(2) + +static void null_prom_display(const char *string, int pos, int clear) +{ +} + +static void null_prom_monitor(void) +{ +} + +static void null_prom_putc(char c) +{ +} + +/* these are functions provided by the bootloader */ +static void (*__prom_putc)(char c) = null_prom_putc; + +void prom_putchar(char c) +{ + __prom_putc(c); +} + +void (*prom_display)(const char *string, int pos, int clear) = + null_prom_display; +void (*prom_monitor)(void) = null_prom_monitor; + +unsigned int lasat_ndelay_divider; + +static void setup_prom_vectors(void) +{ + u32 version = *(u32 *)(RESET_VECTOR + 0x90); + + if (version >= 307) { + prom_display = (void *)PROM_DISPLAY_ADDR; + __prom_putc = (void *)PROM_PUTC_ADDR; + prom_monitor = (void *)PROM_MONITOR_ADDR; + } + printk(KERN_DEBUG "prom vectors set up\n"); +} + +static struct at93c_defs at93c_defs[N_MACHTYPES] = { + { + .reg = (void *)AT93C_REG_100, + .rdata_reg = (void *)AT93C_RDATA_REG_100, + .rdata_shift = AT93C_RDATA_SHIFT_100, + .wdata_shift = AT93C_WDATA_SHIFT_100, + .cs = AT93C_CS_M_100, + .clk = AT93C_CLK_M_100 + }, { + .reg = (void *)AT93C_REG_200, + .rdata_reg = (void *)AT93C_RDATA_REG_200, + .rdata_shift = AT93C_RDATA_SHIFT_200, + .wdata_shift = AT93C_WDATA_SHIFT_200, + .cs = AT93C_CS_M_200, + .clk = AT93C_CLK_M_200 + }, +}; + +void __init prom_init(void) +{ + int argc = fw_arg0; + char **argv = (char **) fw_arg1; + + setup_prom_vectors(); + + if (current_cpu_data.cputype == CPU_R5000) { + printk(KERN_INFO "LASAT 200 board\n"); + mips_machtype = MACH_LASAT_200; + lasat_ndelay_divider = LASAT_200_DIVIDER; + } else { + printk(KERN_INFO "LASAT 100 board\n"); + mips_machtype = MACH_LASAT_100; + lasat_ndelay_divider = LASAT_100_DIVIDER; + } + + at93c = &at93c_defs[mips_machtype]; + + lasat_init_board_info(); /* Read info from EEPROM */ + + mips_machgroup = MACH_GROUP_LASAT; + + /* Get the command line */ + if (argc > 0) { + strncpy(arcs_cmdline, argv[0], CL_SIZE-1); + arcs_cmdline[CL_SIZE-1] = '\0'; + } + + /* Set the I/O base address */ + set_io_port_base(KSEG1); + + /* Set memory regions */ + ioport_resource.start = 0; + ioport_resource.end = 0xffffffff; /* Wrong, fixme. */ + + add_memory_region(0, lasat_board_info.li_memsize, BOOT_MEM_RAM); +} + +void __init prom_free_prom_memory(void) +{ +} + +const char *get_system_type(void) +{ + return lasat_board_info.li_bmstr; +} diff --git a/arch/mips/lasat/prom.h b/arch/mips/lasat/prom.h new file mode 100644 index 000000000000..337acbc27442 --- /dev/null +++ b/arch/mips/lasat/prom.h @@ -0,0 +1,7 @@ +#ifndef __PROM_H +#define __PROM_H + +extern void (*prom_display)(const char *string, int pos, int clear); +extern void (*prom_monitor)(void); + +#endif /* __PROM_H */ diff --git a/arch/mips/lasat/reset.c b/arch/mips/lasat/reset.c new file mode 100644 index 000000000000..b1e7a89fb730 --- /dev/null +++ b/arch/mips/lasat/reset.c @@ -0,0 +1,61 @@ +/* + * Thomas Horsten + * Copyright (C) 2000 LASAT Networks A/S. + * + * This program is free software; you can distribute 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 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. + * + * Reset the LASAT board. + */ +#include +#include + +#include +#include +#include + +#include "picvue.h" +#include "prom.h" + +static void lasat_machine_restart(char *command); +static void lasat_machine_halt(void); + +/* Used to set machine to boot in service mode via /proc interface */ +int lasat_boot_to_service; + +static void lasat_machine_restart(char *command) +{ + local_irq_disable(); + + if (lasat_boot_to_service) { + *(volatile unsigned int *)0xa0000024 = 0xdeadbeef; + *(volatile unsigned int *)0xa00000fc = 0xfedeabba; + } + *lasat_misc->reset_reg = 0xbedead; + for (;;) ; +} + +static void lasat_machine_halt(void) +{ + local_irq_disable(); + + prom_monitor(); + for (;;) ; +} + +void lasat_reboot_setup(void) +{ + _machine_restart = lasat_machine_restart; + _machine_halt = lasat_machine_halt; + pm_power_off = lasat_machine_halt; +} diff --git a/arch/mips/lasat/serial.c b/arch/mips/lasat/serial.c new file mode 100644 index 000000000000..205bd397d75b --- /dev/null +++ b/arch/mips/lasat/serial.c @@ -0,0 +1,94 @@ +/* + * Registration of Lasat UART platform device. + * + * Copyright (C) 2007 Brian Murphy + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct resource lasat_serial_res[2] __initdata; + +static struct plat_serial8250_port lasat_serial8250_port[] = { + { + .iotype = UPIO_MEM, + .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | + UPF_SKIP_TEST, + }, + {}, +}; + +static __init int lasat_uart_add(void) +{ + struct platform_device *pdev; + int retval; + + pdev = platform_device_alloc("serial8250", -1); + if (!pdev) + return -ENOMEM; + + if (mips_machtype == MACH_LASAT_100) { + lasat_serial_res[0].start = KSEG1ADDR(LASAT_UART_REGS_BASE_100); + lasat_serial_res[0].end = lasat_serial_res[0].start + LASAT_UART_REGS_SHIFT_100 * 8 - 1; + lasat_serial_res[0].flags = IORESOURCE_MEM; + lasat_serial_res[1].start = LASATINT_UART_100; + lasat_serial_res[1].end = LASATINT_UART_100; + lasat_serial_res[1].flags = IORESOURCE_IRQ; + + lasat_serial8250_port[0].mapbase = LASAT_UART_REGS_BASE_100; + lasat_serial8250_port[0].uartclk = LASAT_BASE_BAUD_100 * 16; + lasat_serial8250_port[0].regshift = LASAT_UART_REGS_SHIFT_100; + lasat_serial8250_port[0].irq = LASATINT_UART_100; + } else { + lasat_serial_res[0].start = KSEG1ADDR(LASAT_UART_REGS_BASE_200); + lasat_serial_res[0].end = lasat_serial_res[0].start + LASAT_UART_REGS_SHIFT_200 * 8 - 1; + lasat_serial_res[0].flags = IORESOURCE_MEM; + lasat_serial_res[1].start = LASATINT_UART_200; + lasat_serial_res[1].end = LASATINT_UART_200; + lasat_serial_res[1].flags = IORESOURCE_IRQ; + + lasat_serial8250_port[0].mapbase = LASAT_UART_REGS_BASE_200; + lasat_serial8250_port[0].uartclk = LASAT_BASE_BAUD_200 * 16; + lasat_serial8250_port[0].regshift = LASAT_UART_REGS_SHIFT_200; + lasat_serial8250_port[0].irq = LASATINT_UART_200; + } + + pdev->id = PLAT8250_DEV_PLATFORM; + pdev->dev.platform_data = lasat_serial8250_port; + + retval = platform_device_add_resources(pdev, lasat_serial_res, ARRAY_SIZE(lasat_serial_res)); + if (retval) + goto err_free_device; + + retval = platform_device_add(pdev); + if (retval) + goto err_free_device; + + return 0; + +err_free_device: + platform_device_put(pdev); + + return retval; +} +device_initcall(lasat_uart_add); diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c new file mode 100644 index 000000000000..187e37821d93 --- /dev/null +++ b/arch/mips/lasat/setup.c @@ -0,0 +1,158 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999 MIPS Technologies, Inc. All rights reserved. + * + * Thomas Horsten + * Copyright (C) 2000 LASAT Networks A/S. + * + * Brian Murphy + * + * This program is free software; you can distribute 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 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. + * + * Lasat specific setup. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PICVUE +#include +#endif + +#include "ds1603.h" +#include +#include +#include + +#include "prom.h" + +int lasat_command_line; +void lasatint_init(void); + +extern void lasat_reboot_setup(void); +extern void pcisetup(void); +extern void edhac_init(void *, void *, void *); +extern void addrflt_init(void); + +struct lasat_misc lasat_misc_info[N_MACHTYPES] = { + { + .reset_reg = (void *)KSEG1ADDR(0x1c840000), + .flash_wp_reg = (void *)KSEG1ADDR(0x1c800000), 2 + }, { + .reset_reg = (void *)KSEG1ADDR(0x11080000), + .flash_wp_reg = (void *)KSEG1ADDR(0x11000000), 6 + } +}; + +struct lasat_misc *lasat_misc; + +#ifdef CONFIG_DS1603 +static struct ds_defs ds_defs[N_MACHTYPES] = { + { (void *)DS1603_REG_100, (void *)DS1603_REG_100, + DS1603_RST_100, DS1603_CLK_100, DS1603_DATA_100, + DS1603_DATA_SHIFT_100, 0, 0 }, + { (void *)DS1603_REG_200, (void *)DS1603_DATA_REG_200, + DS1603_RST_200, DS1603_CLK_200, DS1603_DATA_200, + DS1603_DATA_READ_SHIFT_200, 1, 2000 } +}; +#endif + +#ifdef CONFIG_PICVUE +#include "picvue.h" +static struct pvc_defs pvc_defs[N_MACHTYPES] = { + { (void *)PVC_REG_100, PVC_DATA_SHIFT_100, PVC_DATA_M_100, + PVC_E_100, PVC_RW_100, PVC_RS_100 }, + { (void *)PVC_REG_200, PVC_DATA_SHIFT_200, PVC_DATA_M_200, + PVC_E_200, PVC_RW_200, PVC_RS_200 } +}; +#endif + +static int lasat_panic_display(struct notifier_block *this, + unsigned long event, void *ptr) +{ +#ifdef CONFIG_PICVUE + unsigned char *string = ptr; + if (string == NULL) + string = "Kernel Panic"; + pvc_dump_string(string); +#endif + return NOTIFY_DONE; +} + +static int lasat_panic_prom_monitor(struct notifier_block *this, + unsigned long event, void *ptr) +{ + prom_monitor(); + return NOTIFY_DONE; +} + +static struct notifier_block lasat_panic_block[] = +{ + { + .notifier_call = lasat_panic_display, + .priority = INT_MAX + }, { + .notifier_call = lasat_panic_prom_monitor, + .priority = INT_MIN + } +}; + +static void lasat_time_init(void) +{ + mips_hpt_frequency = lasat_board_info.li_cpu_hz / 2; +} + +void __init plat_timer_setup(struct irqaction *irq) +{ + change_c0_status(ST0_IM, IE_IRQ0 | IE_IRQ5); +} + +void __init plat_mem_setup(void) +{ + int i; + lasat_misc = &lasat_misc_info[mips_machtype]; +#ifdef CONFIG_PICVUE + picvue = &pvc_defs[mips_machtype]; +#endif + + /* Set up panic notifier */ + for (i = 0; i < ARRAY_SIZE(lasat_panic_block); i++) + atomic_notifier_chain_register(&panic_notifier_list, + &lasat_panic_block[i]); + + lasat_reboot_setup(); + + board_time_init = lasat_time_init; + +#ifdef CONFIG_DS1603 + ds1603 = &ds_defs[mips_machtype]; + rtc_mips_get_time = ds1603_read; + rtc_mips_set_time = ds1603_set; +#endif + +#ifdef DYNAMIC_SERIAL_INIT + serial_init(); +#endif + + pr_info("Lasat specific initialization complete\n"); +} diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c new file mode 100644 index 000000000000..4575a829766d --- /dev/null +++ b/arch/mips/lasat/sysctl.c @@ -0,0 +1,454 @@ +/* + * Thomas Horsten + * Copyright (C) 2000 LASAT Networks A/S. + * + * This program is free software; you can distribute 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 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. + * + * Routines specific to the LASAT boards + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysctl.h" +#include "ds1603.h" + +static DEFINE_MUTEX(lasat_info_mutex); + +/* Strategy function to write EEPROM after changing string entry */ +int sysctl_lasatstring(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen) +{ + int r; + + mutex_lock(&lasat_info_mutex); + r = sysctl_string(table, name, + nlen, oldval, oldlenp, newval, newlen); + if (r < 0) { + mutex_unlock(&lasat_info_mutex); + return r; + } + if (newval && newlen) + lasat_write_eeprom_info(); + mutex_unlock(&lasat_info_mutex); + + return 1; +} + + +/* And the same for proc */ +int proc_dolasatstring(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) +{ + int r; + + mutex_lock(&lasat_info_mutex); + r = proc_dostring(table, write, filp, buffer, lenp, ppos); + if ((!write) || r) { + mutex_unlock(&lasat_info_mutex); + return r; + } + lasat_write_eeprom_info(); + mutex_unlock(&lasat_info_mutex); + + return 0; +} + +/* proc function to write EEPROM after changing int entry */ +int proc_dolasatint(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) +{ + int r; + + mutex_lock(&lasat_info_mutex); + r = proc_dointvec(table, write, filp, buffer, lenp, ppos); + if ((!write) || r) { + mutex_unlock(&lasat_info_mutex); + return r; + } + lasat_write_eeprom_info(); + mutex_unlock(&lasat_info_mutex); + + return 0; +} + +static int rtctmp; + +#ifdef CONFIG_DS1603 +/* proc function to read/write RealTime Clock */ +int proc_dolasatrtc(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) +{ + int r; + + mutex_lock(&lasat_info_mutex); + if (!write) { + rtctmp = ds1603_read(); + /* check for time < 0 and set to 0 */ + if (rtctmp < 0) + rtctmp = 0; + } + r = proc_dointvec(table, write, filp, buffer, lenp, ppos); + if ((!write) || r) { + mutex_unlock(&lasat_info_mutex); + return r; + } + ds1603_set(rtctmp); + mutex_unlock(&lasat_info_mutex); + + return 0; +} +#endif + +/* Sysctl for setting the IP addresses */ +int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen) +{ + int r; + + mutex_lock(&lasat_info_mutex); + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); + if (r < 0) { + mutex_unlock(&lasat_info_mutex); + return r; + } + if (newval && newlen) + lasat_write_eeprom_info(); + mutex_unlock(&lasat_info_mutex); + + return 1; +} + +#ifdef CONFIG_DS1603 +/* Same for RTC */ +int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen) +{ + int r; + + mutex_lock(&lasat_info_mutex); + rtctmp = ds1603_read(); + if (rtctmp < 0) + rtctmp = 0; + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); + if (r < 0) { + mutex_unlock(&lasat_info_mutex); + return r; + } + if (newval && newlen) + ds1603_set(rtctmp); + mutex_unlock(&lasat_info_mutex); + + return 1; +} +#endif + +#ifdef CONFIG_INET +static char lasat_bcastaddr[16]; + +void update_bcastaddr(void) +{ + unsigned int ip; + + ip = (lasat_board_info.li_eeprom_info.ipaddr & + lasat_board_info.li_eeprom_info.netmask) | + ~lasat_board_info.li_eeprom_info.netmask; + + sprintf(lasat_bcastaddr, "%d.%d.%d.%d", + (ip) & 0xff, + (ip >> 8) & 0xff, + (ip >> 16) & 0xff, + (ip >> 24) & 0xff); +} + +static char proc_lasat_ipbuf[32]; + +/* Parsing of IP address */ +int proc_lasat_ip(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) +{ + unsigned int ip; + char *p, c; + int len; + + if (!table->data || !table->maxlen || !*lenp || + (*ppos && !write)) { + *lenp = 0; + return 0; + } + + mutex_lock(&lasat_info_mutex); + if (write) { + len = 0; + p = buffer; + while (len < *lenp) { + if (get_user(c, p++)) { + mutex_unlock(&lasat_info_mutex); + return -EFAULT; + } + if (c == 0 || c == '\n') + break; + len++; + } + if (len >= sizeof(proc_lasat_ipbuf)-1) + len = sizeof(proc_lasat_ipbuf) - 1; + if (copy_from_user(proc_lasat_ipbuf, buffer, len)) { + mutex_unlock(&lasat_info_mutex); + return -EFAULT; + } + proc_lasat_ipbuf[len] = 0; + *ppos += *lenp; + /* Now see if we can convert it to a valid IP */ + ip = in_aton(proc_lasat_ipbuf); + *(unsigned int *)(table->data) = ip; + lasat_write_eeprom_info(); + } else { + ip = *(unsigned int *)(table->data); + sprintf(proc_lasat_ipbuf, "%d.%d.%d.%d", + (ip) & 0xff, + (ip >> 8) & 0xff, + (ip >> 16) & 0xff, + (ip >> 24) & 0xff); + len = strlen(proc_lasat_ipbuf); + if (len > *lenp) + len = *lenp; + if (len) + if (copy_to_user(buffer, proc_lasat_ipbuf, len)) { + mutex_unlock(&lasat_info_mutex); + return -EFAULT; + } + if (len < *lenp) { + if (put_user('\n', ((char *) buffer) + len)) { + mutex_unlock(&lasat_info_mutex); + return -EFAULT; + } + len++; + } + *lenp = len; + *ppos += len; + } + update_bcastaddr(); + mutex_unlock(&lasat_info_mutex); + + return 0; +} +#endif /* defined(CONFIG_INET) */ + +static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen) +{ + int r; + + mutex_lock(&lasat_info_mutex); + r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); + if (r < 0) { + mutex_unlock(&lasat_info_mutex); + return r; + } + + if (newval && newlen) { + if (name && *name == LASAT_PRID) + lasat_board_info.li_eeprom_info.prid = *(int *)newval; + + lasat_write_eeprom_info(); + lasat_init_board_info(); + } + mutex_unlock(&lasat_info_mutex); + + return 0; +} + +int proc_lasat_eeprom_value(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) +{ + int r; + + mutex_lock(&lasat_info_mutex); + r = proc_dointvec(table, write, filp, buffer, lenp, ppos); + if ((!write) || r) { + mutex_unlock(&lasat_info_mutex); + return r; + } + if (filp && filp->f_path.dentry) { + if (!strcmp(filp->f_path.dentry->d_name.name, "prid")) + lasat_board_info.li_eeprom_info.prid = + lasat_board_info.li_prid; + if (!strcmp(filp->f_path.dentry->d_name.name, "debugaccess")) + lasat_board_info.li_eeprom_info.debugaccess = + lasat_board_info.li_debugaccess; + } + lasat_write_eeprom_info(); + mutex_unlock(&lasat_info_mutex); + + return 0; +} + +extern int lasat_boot_to_service; + +#ifdef CONFIG_SYSCTL + +static ctl_table lasat_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "cpu-hz", + .data = &lasat_board_info.li_cpu_hz, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bus-hz", + .data = &lasat_board_info.li_bus_hz, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bmid", + .data = &lasat_board_info.li_bmid, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "prid", + .data = &lasat_board_info.li_prid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_eeprom_value, + .strategy = &sysctl_lasat_eeprom_value + }, +#ifdef CONFIG_INET + { + .ctl_name = CTL_UNNUMBERED, + .procname = "ipaddr", + .data = &lasat_board_info.li_eeprom_info.ipaddr, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_ip, + .strategy = &sysctl_lasat_intvec + }, + { + .ctl_name = LASAT_NETMASK, + .procname = "netmask", + .data = &lasat_board_info.li_eeprom_info.netmask, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_ip, + .strategy = &sysctl_lasat_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bcastaddr", + .data = &lasat_bcastaddr, + .maxlen = sizeof(lasat_bcastaddr), + .mode = 0600, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, +#endif + { + .ctl_name = CTL_UNNUMBERED, + .procname = "passwd_hash", + .data = &lasat_board_info.li_eeprom_info.passwd_hash, + .maxlen = + sizeof(lasat_board_info.li_eeprom_info.passwd_hash), + .mode = 0600, + .proc_handler = &proc_dolasatstring, + .strategy = &sysctl_lasatstring + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "boot-service", + .data = &lasat_boot_to_service, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, +#ifdef CONFIG_DS1603 + { + .ctl_name = CTL_UNNUMBERED, + .procname = "rtc", + .data = &rtctmp, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dolasatrtc, + .strategy = &sysctl_lasat_rtc + }, +#endif + { + .ctl_name = CTL_UNNUMBERED, + .procname = "namestr", + .data = &lasat_board_info.li_namestr, + .maxlen = sizeof(lasat_board_info.li_namestr), + .mode = 0444, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "typestr", + .data = &lasat_board_info.li_typestr, + .maxlen = sizeof(lasat_board_info.li_typestr), + .mode = 0444, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, + {} +}; + +static ctl_table lasat_root_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "lasat", + .mode = 0555, + .child = lasat_table + }, + {} +}; + +static int __init lasat_register_sysctl(void) +{ + struct ctl_table_header *lasat_table_header; + + lasat_table_header = + register_sysctl_table(lasat_root_table); + + return 0; +} + +__initcall(lasat_register_sysctl); +#endif /* CONFIG_SYSCTL */ diff --git a/arch/mips/lasat/sysctl.h b/arch/mips/lasat/sysctl.h new file mode 100644 index 000000000000..341b97933423 --- /dev/null +++ b/arch/mips/lasat/sysctl.h @@ -0,0 +1,24 @@ +/* + * LASAT sysctl values + */ + +#ifndef _LASAT_SYSCTL_H +#define _LASAT_SYSCTL_H + +/* /proc/sys/lasat */ +enum { + LASAT_CPU_HZ = 1, + LASAT_BUS_HZ, + LASAT_MODEL, + LASAT_PRID, + LASAT_IPADDR, + LASAT_NETMASK, + LASAT_BCAST, + LASAT_PASSWORD, + LASAT_SBOOT, + LASAT_RTC, + LASAT_NAMESTR, + LASAT_TYPESTR, +}; + +#endif /* _LASAT_SYSCTL_H */ diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 4ee6800e67e6..ed0c07622baa 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -10,6 +10,7 @@ obj-y += pci.o obj-$(CONFIG_MIPS_BONITO64) += ops-bonito64.o obj-$(CONFIG_PCI_GT64XXX_PCI0) += ops-gt64xxx_pci0.o obj-$(CONFIG_MIPS_MSC) += ops-msc.o +obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o obj-$(CONFIG_MIPS_TX3927) += ops-tx3927.o obj-$(CONFIG_PCI_VR41XX) += ops-vr41xx.o pci-vr41xx.o obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o @@ -19,6 +20,7 @@ obj-$(CONFIG_MARKEINS) += ops-emma2rh.o pci-emma2rh.o fixup-emma2rh.o # These are still pretty much in the old state, watch, go blind. # obj-$(CONFIG_BASLER_EXCITE) += ops-titan.o pci-excite.o fixup-excite.o +obj-$(CONFIG_LASAT) += pci-lasat.o obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o obj-$(CONFIG_SOC_AU1500) += fixup-au1000.o ops-au1000.o diff --git a/arch/mips/pci/ops-nile4.c b/arch/mips/pci/ops-nile4.c new file mode 100644 index 000000000000..b7f0fb0210f4 --- /dev/null +++ b/arch/mips/pci/ops-nile4.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include + +#include +#include +#include + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +#define LO(reg) (reg / 4) +#define HI(reg) (reg / 4 + 1) + +volatile unsigned long *const vrc_pciregs = (void *) Vrc5074_BASE; + +static DEFINE_SPINLOCK(nile4_pci_lock); + +static int nile4_pcibios_config_access(unsigned char access_type, + struct pci_bus *bus, unsigned int devfn, int where, u32 *val) +{ + unsigned char busnum = bus->number; + u32 adr, mask, err; + + if ((busnum == 0) && (PCI_SLOT(devfn) > 8)) + /* The addressing scheme chosen leaves room for just + * 8 devices on the first busnum (besides the PCI + * controller itself) */ + return PCIBIOS_DEVICE_NOT_FOUND; + + if ((busnum == 0) && (devfn == PCI_DEVFN(0, 0))) { + /* Access controller registers directly */ + if (access_type == PCI_ACCESS_WRITE) { + vrc_pciregs[(0x200 + where) >> 2] = *val; + } else { + *val = vrc_pciregs[(0x200 + where) >> 2]; + } + return PCIBIOS_SUCCESSFUL; + } + + /* Temporarily map PCI Window 1 to config space */ + mask = vrc_pciregs[LO(NILE4_PCIINIT1)]; + vrc_pciregs[LO(NILE4_PCIINIT1)] = 0x0000001a | (busnum ? 0x200 : 0); + + /* Clear PCI Error register. This also clears the Error Type + * bits in the Control register */ + vrc_pciregs[LO(NILE4_PCIERR)] = 0; + vrc_pciregs[HI(NILE4_PCIERR)] = 0; + + /* Setup address */ + if (busnum == 0) + adr = + KSEG1ADDR(PCI_WINDOW1) + + ((1 << (PCI_SLOT(devfn) + 15)) | (PCI_FUNC(devfn) << 8) + | (where & ~3)); + else + adr = KSEG1ADDR(PCI_WINDOW1) | (busnum << 16) | (devfn << 8) | + (where & ~3); + + if (access_type == PCI_ACCESS_WRITE) + *(u32 *) adr = *val; + else + *val = *(u32 *) adr; + + /* Check for master or target abort */ + err = (vrc_pciregs[HI(NILE4_PCICTRL)] >> 5) & 0x7; + + /* Restore PCI Window 1 */ + vrc_pciregs[LO(NILE4_PCIINIT1)] = mask; + + if (err) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + unsigned long flags; + u32 data = 0; + int err; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + spin_lock_irqsave(&nile4_pci_lock, flags); + err = nile4_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, + &data); + spin_unlock_irqrestore(&nile4_pci_lock, flags); + + if (err) + return err; + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + unsigned long flags; + u32 data = 0; + int err; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + spin_lock_irqsave(&nile4_pci_lock, flags); + err = nile4_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, + &data); + spin_unlock_irqrestore(&nile4_pci_lock, flags); + + if (err) + return err; + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else + data = val; + + if (nile4_pcibios_config_access + (PCI_ACCESS_WRITE, bus, devfn, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops nile4_pci_ops = { + .read = nile4_pcibios_read, + .write = nile4_pcibios_write, +}; diff --git a/arch/mips/pci/pci-lasat.c b/arch/mips/pci/pci-lasat.c new file mode 100644 index 000000000000..5abd5c7119be --- /dev/null +++ b/arch/mips/pci/pci-lasat.c @@ -0,0 +1,91 @@ +/* + * 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. + * + * Copyright (C) 2000, 2001, 04 Keith M Wesolowski + */ +#include +#include +#include +#include +#include + +extern struct pci_ops nile4_pci_ops; +extern struct pci_ops gt64xxx_pci0_ops; +static struct resource lasat_pci_mem_resource = { + .name = "LASAT PCI MEM", + .start = 0x18000000, + .end = 0x19ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct resource lasat_pci_io_resource = { + .name = "LASAT PCI IO", + .start = 0x1a000000, + .end = 0x1bffffff, + .flags = IORESOURCE_IO, +}; + +static struct pci_controller lasat_pci_controller = { + .mem_resource = &lasat_pci_mem_resource, + .io_resource = &lasat_pci_io_resource, +}; + +static int __init lasat_pci_setup(void) +{ + printk(KERN_DEBUG "PCI: starting\n"); + + switch (mips_machtype) { + case MACH_LASAT_100: + lasat_pci_controller.pci_ops = >64xxx_pci0_ops; + break; + case MACH_LASAT_200: + lasat_pci_controller.pci_ops = &nile4_pci_ops; + break; + default: + panic("pcibios_init: mips_machtype incorrect"); + } + + register_pci_controller(&lasat_pci_controller); + + return 0; +} + +arch_initcall(lasat_pci_setup); + +#define LASATINT_ETH1 0 +#define LASATINT_ETH0 1 +#define LASATINT_HDC 2 +#define LASATINT_COMP 3 +#define LASATINT_HDLC 4 +#define LASATINT_PCIA 5 +#define LASATINT_PCIB 6 +#define LASATINT_PCIC 7 +#define LASATINT_PCID 8 + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + switch (slot) { + case 1: + case 2: + case 3: + return LASATINT_PCIA + (((slot-1) + (pin-1)) % 4); + case 4: + return LASATINT_ETH1; /* Ethernet 1 (LAN 2) */ + case 5: + return LASATINT_ETH0; /* Ethernet 0 (LAN 1) */ + case 6: + return LASATINT_HDC; /* IDE controller */ + default: + return 0xff; /* Illegal */ + } + + return -1; +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index c0f052b37b9e..1bb4bf657701 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -174,6 +174,13 @@ #define MACH_GROUP_HP_LJ 20 /* Hewlett Packard LaserJet */ #define MACH_HP_LASERJET 1 +/* + * Valid machtype for group LASAT + */ +#define MACH_GROUP_LASAT 21 +#define MACH_LASAT_100 0 /* Masquerade II/SP100/SP50/SP25 */ +#define MACH_LASAT_200 1 /* Masquerade PRO/SP200 */ + /* * Valid machtype for group TITAN */ diff --git a/include/asm-mips/lasat/ds1603.h b/include/asm-mips/lasat/ds1603.h new file mode 100644 index 000000000000..edcd7544b358 --- /dev/null +++ b/include/asm-mips/lasat/ds1603.h @@ -0,0 +1,18 @@ +#include + +/* Lasat 100 */ +#define DS1603_REG_100 (KSEG1ADDR(0x1c810000)) +#define DS1603_RST_100 (1 << 2) +#define DS1603_CLK_100 (1 << 0) +#define DS1603_DATA_SHIFT_100 1 +#define DS1603_DATA_100 (1 << DS1603_DATA_SHIFT_100) + +/* Lasat 200 */ +#define DS1603_REG_200 (KSEG1ADDR(0x11000000)) +#define DS1603_RST_200 (1 << 3) +#define DS1603_CLK_200 (1 << 4) +#define DS1603_DATA_200 (1 << 5) + +#define DS1603_DATA_REG_200 (DS1603_REG_200 + 0x10000) +#define DS1603_DATA_READ_SHIFT_200 9 +#define DS1603_DATA_READ_200 (1 << DS1603_DATA_READ_SHIFT_200) diff --git a/include/asm-mips/lasat/eeprom.h b/include/asm-mips/lasat/eeprom.h new file mode 100644 index 000000000000..3dac203697fa --- /dev/null +++ b/include/asm-mips/lasat/eeprom.h @@ -0,0 +1,17 @@ +#include + +/* lasat 100 */ +#define AT93C_REG_100 KSEG1ADDR(0x1c810000) +#define AT93C_RDATA_REG_100 AT93C_REG_100 +#define AT93C_RDATA_SHIFT_100 4 +#define AT93C_WDATA_SHIFT_100 4 +#define AT93C_CS_M_100 (1 << 5) +#define AT93C_CLK_M_100 (1 << 3) + +/* lasat 200 */ +#define AT93C_REG_200 KSEG1ADDR(0x11000000) +#define AT93C_RDATA_REG_200 (AT93C_REG_200+0x10000) +#define AT93C_RDATA_SHIFT_200 8 +#define AT93C_WDATA_SHIFT_200 2 +#define AT93C_CS_M_200 (1 << 0) +#define AT93C_CLK_M_200 (1 << 1) diff --git a/include/asm-mips/lasat/head.h b/include/asm-mips/lasat/head.h new file mode 100644 index 000000000000..f5589f31a197 --- /dev/null +++ b/include/asm-mips/lasat/head.h @@ -0,0 +1,22 @@ +/* + * Image header stuff + */ +#ifndef _HEAD_H +#define _HEAD_H + +#define LASAT_K_MAGIC0_VAL 0xfedeabba +#define LASAT_K_MAGIC1_VAL 0x00bedead + +#ifndef _LANGUAGE_ASSEMBLY +#include +struct bootloader_header { + u32 magic[2]; + u32 version; + u32 image_start; + u32 image_size; + u32 kernel_start; + u32 kernel_entry; +}; +#endif + +#endif /* _HEAD_H */ diff --git a/include/asm-mips/lasat/lasat.h b/include/asm-mips/lasat/lasat.h new file mode 100644 index 000000000000..ea04d9262edc --- /dev/null +++ b/include/asm-mips/lasat/lasat.h @@ -0,0 +1,256 @@ +/* + * lasat.h + * + * Thomas Horsten + * Copyright (C) 2000 LASAT Networks A/S. + * + * This program is free software; you can distribute 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 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. + * + * Configuration for LASAT boards, loads the appropriate include files. + */ +#ifndef _LASAT_H +#define _LASAT_H + +#ifndef _LANGUAGE_ASSEMBLY + +extern struct lasat_misc { + volatile u32 *reset_reg; + volatile u32 *flash_wp_reg; + u32 flash_wp_bit; +} *lasat_misc; + +enum lasat_mtdparts { + LASAT_MTD_BOOTLOADER, + LASAT_MTD_SERVICE, + LASAT_MTD_NORMAL, + LASAT_MTD_CONFIG, + LASAT_MTD_FS, + LASAT_MTD_LAST +}; + +/* + * The format of the data record in the EEPROM. + * See Documentation/LASAT/eeprom.txt for a detailed description + * of the fields in this struct, and the LASAT Hardware Configuration + * field specification for a detailed description of the config + * field. + */ +#include + +#define LASAT_EEPROM_VERSION 7 +struct lasat_eeprom_struct { + unsigned int version; + unsigned int cfg[3]; + unsigned char hwaddr[6]; + unsigned char print_partno[12]; + unsigned char term0; + unsigned char print_serial[14]; + unsigned char term1; + unsigned char prod_partno[12]; + unsigned char term2; + unsigned char prod_serial[14]; + unsigned char term3; + unsigned char passwd_hash[16]; + unsigned char pwdnull; + unsigned char vendid; + unsigned char ts_ref; + unsigned char ts_signoff; + unsigned char reserved[11]; + unsigned char debugaccess; + unsigned short prid; + unsigned int serviceflag; + unsigned int ipaddr; + unsigned int netmask; + unsigned int crc32; +}; + +struct lasat_eeprom_struct_pre7 { + unsigned int version; + unsigned int flags[3]; + unsigned char hwaddr0[6]; + unsigned char hwaddr1[6]; + unsigned char print_partno[9]; + unsigned char term0; + unsigned char print_serial[14]; + unsigned char term1; + unsigned char prod_partno[9]; + unsigned char term2; + unsigned char prod_serial[14]; + unsigned char term3; + unsigned char passwd_hash[24]; + unsigned char pwdnull; + unsigned char vendor; + unsigned char ts_ref; + unsigned char ts_signoff; + unsigned char reserved[6]; + unsigned int writecount; + unsigned int ipaddr; + unsigned int netmask; + unsigned int crc32; +}; + +/* Configuration descriptor encoding - see the doc for details */ + +#define LASAT_W0_DSCTYPE(v) (((v)) & 0xf) +#define LASAT_W0_BMID(v) (((v) >> 0x04) & 0xf) +#define LASAT_W0_CPUTYPE(v) (((v) >> 0x08) & 0xf) +#define LASAT_W0_BUSSPEED(v) (((v) >> 0x0c) & 0xf) +#define LASAT_W0_CPUCLK(v) (((v) >> 0x10) & 0xf) +#define LASAT_W0_SDRAMBANKSZ(v) (((v) >> 0x14) & 0xf) +#define LASAT_W0_SDRAMBANKS(v) (((v) >> 0x18) & 0xf) +#define LASAT_W0_L2CACHE(v) (((v) >> 0x1c) & 0xf) + +#define LASAT_W1_EDHAC(v) (((v)) & 0xf) +#define LASAT_W1_HIFN(v) (((v) >> 0x04) & 0x1) +#define LASAT_W1_ISDN(v) (((v) >> 0x05) & 0x1) +#define LASAT_W1_IDE(v) (((v) >> 0x06) & 0x1) +#define LASAT_W1_HDLC(v) (((v) >> 0x07) & 0x1) +#define LASAT_W1_USVERSION(v) (((v) >> 0x08) & 0x1) +#define LASAT_W1_4MACS(v) (((v) >> 0x09) & 0x1) +#define LASAT_W1_EXTSERIAL(v) (((v) >> 0x0a) & 0x1) +#define LASAT_W1_FLASHSIZE(v) (((v) >> 0x0c) & 0xf) +#define LASAT_W1_PCISLOTS(v) (((v) >> 0x10) & 0xf) +#define LASAT_W1_PCI1OPT(v) (((v) >> 0x14) & 0xf) +#define LASAT_W1_PCI2OPT(v) (((v) >> 0x18) & 0xf) +#define LASAT_W1_PCI3OPT(v) (((v) >> 0x1c) & 0xf) + +/* Routines specific to LASAT boards */ + +#define LASAT_BMID_MASQUERADE2 0 +#define LASAT_BMID_MASQUERADEPRO 1 +#define LASAT_BMID_SAFEPIPE25 2 +#define LASAT_BMID_SAFEPIPE50 3 +#define LASAT_BMID_SAFEPIPE100 4 +#define LASAT_BMID_SAFEPIPE5000 5 +#define LASAT_BMID_SAFEPIPE7000 6 +#define LASAT_BMID_SAFEPIPE1000 7 +#if 0 +#define LASAT_BMID_SAFEPIPE30 7 +#define LASAT_BMID_SAFEPIPE5100 8 +#define LASAT_BMID_SAFEPIPE7100 9 +#endif +#define LASAT_BMID_UNKNOWN 0xf +#define LASAT_MAX_BMID_NAMES 9 /* no larger than 15! */ + +#define LASAT_HAS_EDHAC (1 << 0) +#define LASAT_EDHAC_FAST (1 << 1) +#define LASAT_HAS_EADI (1 << 2) +#define LASAT_HAS_HIFN (1 << 3) +#define LASAT_HAS_ISDN (1 << 4) +#define LASAT_HAS_LEASEDLINE_IF (1 << 5) +#define LASAT_HAS_HDC (1 << 6) + +#define LASAT_PRID_MASQUERADE2 0 +#define LASAT_PRID_MASQUERADEPRO 1 +#define LASAT_PRID_SAFEPIPE25 2 +#define LASAT_PRID_SAFEPIPE50 3 +#define LASAT_PRID_SAFEPIPE100 4 +#define LASAT_PRID_SAFEPIPE5000 5 +#define LASAT_PRID_SAFEPIPE7000 6 +#define LASAT_PRID_SAFEPIPE30 7 +#define LASAT_PRID_SAFEPIPE5100 8 +#define LASAT_PRID_SAFEPIPE7100 9 + +#define LASAT_PRID_SAFEPIPE1110 10 +#define LASAT_PRID_SAFEPIPE3020 11 +#define LASAT_PRID_SAFEPIPE3030 12 +#define LASAT_PRID_SAFEPIPE5020 13 +#define LASAT_PRID_SAFEPIPE5030 14 +#define LASAT_PRID_SAFEPIPE1120 15 +#define LASAT_PRID_SAFEPIPE1130 16 +#define LASAT_PRID_SAFEPIPE6010 17 +#define LASAT_PRID_SAFEPIPE6110 18 +#define LASAT_PRID_SAFEPIPE6210 19 +#define LASAT_PRID_SAFEPIPE1020 20 +#define LASAT_PRID_SAFEPIPE1040 21 +#define LASAT_PRID_SAFEPIPE1060 22 + +struct lasat_info { + unsigned int li_cpu_hz; + unsigned int li_bus_hz; + unsigned int li_bmid; + unsigned int li_memsize; + unsigned int li_flash_size; + unsigned int li_prid; + unsigned char li_bmstr[16]; + unsigned char li_namestr[32]; + unsigned char li_typestr[16]; + /* Info on the Flash layout */ + unsigned int li_flash_base; + unsigned long li_flashpart_base[LASAT_MTD_LAST]; + unsigned long li_flashpart_size[LASAT_MTD_LAST]; + struct lasat_eeprom_struct li_eeprom_info; + unsigned int li_eeprom_upgrade_version; + unsigned int li_debugaccess; +}; + +extern struct lasat_info lasat_board_info; + +static inline unsigned long lasat_flash_partition_start(int partno) +{ + if (partno < 0 || partno >= LASAT_MTD_LAST) + return 0; + + return lasat_board_info.li_flashpart_base[partno]; +} + +static inline unsigned long lasat_flash_partition_size(int partno) +{ + if (partno < 0 || partno >= LASAT_MTD_LAST) + return 0; + + return lasat_board_info.li_flashpart_size[partno]; +} + +/* Called from setup() to initialize the global board_info struct */ +extern int lasat_init_board_info(void); + +/* Write the modified EEPROM info struct */ +extern void lasat_write_eeprom_info(void); + +#define N_MACHTYPES 2 +/* for calibration of delays */ + +/* the lasat_ndelay function is necessary because it is used at an + * early stage of the boot process where ndelay is not calibrated. + * It is used for the bit-banging rtc and eeprom drivers */ + +#include + +/* calculating with the slowest board with 100 MHz clock */ +#define LASAT_100_DIVIDER 20 +/* All 200's run at 250 MHz clock */ +#define LASAT_200_DIVIDER 8 + +extern unsigned int lasat_ndelay_divider; + +static inline void lasat_ndelay(unsigned int ns) +{ + __delay(ns / lasat_ndelay_divider); +} + +#endif /* !defined (_LANGUAGE_ASSEMBLY) */ + +#define LASAT_SERVICEMODE_MAGIC_1 0xdeadbeef +#define LASAT_SERVICEMODE_MAGIC_2 0xfedeabba + +/* Lasat 100 boards */ +#define LASAT_GT_BASE (KSEG1ADDR(0x14000000)) + +/* Lasat 200 boards */ +#define Vrc5074_PHYS_BASE 0x1fa00000 +#define Vrc5074_BASE (KSEG1ADDR(Vrc5074_PHYS_BASE)) +#define PCI_WINDOW1 0x1a000000 + +#endif /* _LASAT_H */ diff --git a/include/asm-mips/lasat/lasatint.h b/include/asm-mips/lasat/lasatint.h new file mode 100644 index 000000000000..065474feeccc --- /dev/null +++ b/include/asm-mips/lasat/lasatint.h @@ -0,0 +1,12 @@ +#define LASATINT_END 16 + +/* lasat 100 */ +#define LASAT_INT_STATUS_REG_100 (KSEG1ADDR(0x1c880000)) +#define LASAT_INT_MASK_REG_100 (KSEG1ADDR(0x1c890000)) +#define LASATINT_MASK_SHIFT_100 0 + +/* lasat 200 */ +#define LASAT_INT_STATUS_REG_200 (KSEG1ADDR(0x1104003c)) +#define LASAT_INT_MASK_REG_200 (KSEG1ADDR(0x1104003c)) +#define LASATINT_MASK_SHIFT_200 16 + diff --git a/include/asm-mips/lasat/picvue.h b/include/asm-mips/lasat/picvue.h new file mode 100644 index 000000000000..42a492edc40e --- /dev/null +++ b/include/asm-mips/lasat/picvue.h @@ -0,0 +1,15 @@ +/* Lasat 100 */ +#define PVC_REG_100 KSEG1ADDR(0x1c820000) +#define PVC_DATA_SHIFT_100 0 +#define PVC_DATA_M_100 0xFF +#define PVC_E_100 (1 << 8) +#define PVC_RW_100 (1 << 9) +#define PVC_RS_100 (1 << 10) + +/* Lasat 200 */ +#define PVC_REG_200 KSEG1ADDR(0x11000000) +#define PVC_DATA_SHIFT_200 24 +#define PVC_DATA_M_200 (0xFF << PVC_DATA_SHIFT_200) +#define PVC_E_200 (1 << 16) +#define PVC_RW_200 (1 << 17) +#define PVC_RS_200 (1 << 18) diff --git a/include/asm-mips/lasat/serial.h b/include/asm-mips/lasat/serial.h new file mode 100644 index 000000000000..bafe68b10614 --- /dev/null +++ b/include/asm-mips/lasat/serial.h @@ -0,0 +1,13 @@ +#include + +/* Lasat 100 boards serial configuration */ +#define LASAT_BASE_BAUD_100 (7372800 / 16) +#define LASAT_UART_REGS_BASE_100 0x1c8b0000 +#define LASAT_UART_REGS_SHIFT_100 2 +#define LASATINT_UART_100 8 + +/* * LASAT 200 boards serial configuration */ +#define LASAT_BASE_BAUD_200 (100000000 / 16 / 12) +#define LASAT_UART_REGS_BASE_200 (Vrc5074_PHYS_BASE + 0x0300) +#define LASAT_UART_REGS_SHIFT_200 3 +#define LASATINT_UART_200 13 diff --git a/include/asm-mips/mach-lasat/mach-gt64120.h b/include/asm-mips/mach-lasat/mach-gt64120.h new file mode 100644 index 000000000000..1a9ad45cc135 --- /dev/null +++ b/include/asm-mips/mach-lasat/mach-gt64120.h @@ -0,0 +1,27 @@ +/* + * This is a direct copy of the ev96100.h file, with a global + * search and replace. The numbers are the same. + * + * The reason I'm duplicating this is so that the 64120/96100 + * defines won't be confusing in the source code. + */ +#ifndef _ASM_GT64120_LASAT_GT64120_DEP_H +#define _ASM_GT64120_LASAT_GT64120_DEP_H + +/* + * GT64120 config space base address on Lasat 100 + */ +#define GT64120_BASE (KSEG1ADDR(0x14000000)) + +/* + * PCI Bus allocation + * + * (Guessing ...) + */ +#define GT_PCI_MEM_BASE 0x12000000UL +#define GT_PCI_MEM_SIZE 0x02000000UL +#define GT_PCI_IO_BASE 0x10000000UL +#define GT_PCI_IO_SIZE 0x02000000UL +#define GT_ISA_IO_BASE PCI_IO_BASE + +#endif /* _ASM_GT64120_LASAT_GT64120_DEP_H */ diff --git a/include/asm-mips/nile4.h b/include/asm-mips/nile4.h new file mode 100644 index 000000000000..c3ca959aa4d9 --- /dev/null +++ b/include/asm-mips/nile4.h @@ -0,0 +1,310 @@ +/* + * asm-mips/nile4.h -- NEC Vrc-5074 Nile 4 definitions + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Software Development Center Europe (SDCE), Brussels + * + * This file is based on the following documentation: + * + * NEC Vrc 5074 System Controller Data Sheet, June 1998 + */ + +#ifndef _ASM_NILE4_H +#define _ASM_NILE4_H + +#define NILE4_BASE 0xbfa00000 +#define NILE4_SIZE 0x00200000 /* 2 MB */ + + + /* + * Physical Device Address Registers (PDARs) + */ + +#define NILE4_SDRAM0 0x0000 /* SDRAM Bank 0 [R/W] */ +#define NILE4_SDRAM1 0x0008 /* SDRAM Bank 1 [R/W] */ +#define NILE4_DCS2 0x0010 /* Device Chip-Select 2 [R/W] */ +#define NILE4_DCS3 0x0018 /* Device Chip-Select 3 [R/W] */ +#define NILE4_DCS4 0x0020 /* Device Chip-Select 4 [R/W] */ +#define NILE4_DCS5 0x0028 /* Device Chip-Select 5 [R/W] */ +#define NILE4_DCS6 0x0030 /* Device Chip-Select 6 [R/W] */ +#define NILE4_DCS7 0x0038 /* Device Chip-Select 7 [R/W] */ +#define NILE4_DCS8 0x0040 /* Device Chip-Select 8 [R/W] */ +#define NILE4_PCIW0 0x0060 /* PCI Address Window 0 [R/W] */ +#define NILE4_PCIW1 0x0068 /* PCI Address Window 1 [R/W] */ +#define NILE4_INTCS 0x0070 /* Controller Internal Registers and Devices */ + /* [R/W] */ +#define NILE4_BOOTCS 0x0078 /* Boot ROM Chip-Select [R/W] */ + + + /* + * CPU Interface Registers + */ + +#define NILE4_CPUSTAT 0x0080 /* CPU Status [R/W] */ +#define NILE4_INTCTRL 0x0088 /* Interrupt Control [R/W] */ +#define NILE4_INTSTAT0 0x0090 /* Interrupt Status 0 [R] */ +#define NILE4_INTSTAT1 0x0098 /* Interrupt Status 1 and CPU Interrupt */ + /* Enable [R/W] */ +#define NILE4_INTCLR 0x00A0 /* Interrupt Clear [R/W] */ +#define NILE4_INTPPES 0x00A8 /* PCI Interrupt Control [R/W] */ + + + /* + * Memory-Interface Registers + */ + +#define NILE4_MEMCTRL 0x00C0 /* Memory Control */ +#define NILE4_ACSTIME 0x00C8 /* Memory Access Timing [R/W] */ +#define NILE4_CHKERR 0x00D0 /* Memory Check Error Status [R] */ + + + /* + * PCI-Bus Registers + */ + +#define NILE4_PCICTRL 0x00E0 /* PCI Control [R/W] */ +#define NILE4_PCIARB 0x00E8 /* PCI Arbiter [R/W] */ +#define NILE4_PCIINIT0 0x00F0 /* PCI Master (Initiator) 0 [R/W] */ +#define NILE4_PCIINIT1 0x00F8 /* PCI Master (Initiator) 1 [R/W] */ +#define NILE4_PCIERR 0x00B8 /* PCI Error [R/W] */ + + + /* + * Local-Bus Registers + */ + +#define NILE4_LCNFG 0x0100 /* Local Bus Configuration [R/W] */ +#define NILE4_LCST2 0x0110 /* Local Bus Chip-Select Timing 2 [R/W] */ +#define NILE4_LCST3 0x0118 /* Local Bus Chip-Select Timing 3 [R/W] */ +#define NILE4_LCST4 0x0120 /* Local Bus Chip-Select Timing 4 [R/W] */ +#define NILE4_LCST5 0x0128 /* Local Bus Chip-Select Timing 5 [R/W] */ +#define NILE4_LCST6 0x0130 /* Local Bus Chip-Select Timing 6 [R/W] */ +#define NILE4_LCST7 0x0138 /* Local Bus Chip-Select Timing 7 [R/W] */ +#define NILE4_LCST8 0x0140 /* Local Bus Chip-Select Timing 8 [R/W] */ +#define NILE4_DCSFN 0x0150 /* Device Chip-Select Muxing and Output */ + /* Enables [R/W] */ +#define NILE4_DCSIO 0x0158 /* Device Chip-Selects As I/O Bits [R/W] */ +#define NILE4_BCST 0x0178 /* Local Boot Chip-Select Timing [R/W] */ + + + /* + * DMA Registers + */ + +#define NILE4_DMACTRL0 0x0180 /* DMA Control 0 [R/W] */ +#define NILE4_DMASRCA0 0x0188 /* DMA Source Address 0 [R/W] */ +#define NILE4_DMADESA0 0x0190 /* DMA Destination Address 0 [R/W] */ +#define NILE4_DMACTRL1 0x0198 /* DMA Control 1 [R/W] */ +#define NILE4_DMASRCA1 0x01A0 /* DMA Source Address 1 [R/W] */ +#define NILE4_DMADESA1 0x01A8 /* DMA Destination Address 1 [R/W] */ + + + /* + * Timer Registers + */ + +#define NILE4_T0CTRL 0x01C0 /* SDRAM Refresh Control [R/W] */ +#define NILE4_T0CNTR 0x01C8 /* SDRAM Refresh Counter [R/W] */ +#define NILE4_T1CTRL 0x01D0 /* CPU-Bus Read Time-Out Control [R/W] */ +#define NILE4_T1CNTR 0x01D8 /* CPU-Bus Read Time-Out Counter [R/W] */ +#define NILE4_T2CTRL 0x01E0 /* General-Purpose Timer Control [R/W] */ +#define NILE4_T2CNTR 0x01E8 /* General-Purpose Timer Counter [R/W] */ +#define NILE4_T3CTRL 0x01F0 /* Watchdog Timer Control [R/W] */ +#define NILE4_T3CNTR 0x01F8 /* Watchdog Timer Counter [R/W] */ + + + /* + * PCI Configuration Space Registers + */ + +#define NILE4_PCI_BASE 0x0200 + +#define NILE4_VID 0x0200 /* PCI Vendor ID [R] */ +#define NILE4_DID 0x0202 /* PCI Device ID [R] */ +#define NILE4_PCICMD 0x0204 /* PCI Command [R/W] */ +#define NILE4_PCISTS 0x0206 /* PCI Status [R/W] */ +#define NILE4_REVID 0x0208 /* PCI Revision ID [R] */ +#define NILE4_CLASS 0x0209 /* PCI Class Code [R] */ +#define NILE4_CLSIZ 0x020C /* PCI Cache Line Size [R/W] */ +#define NILE4_MLTIM 0x020D /* PCI Latency Timer [R/W] */ +#define NILE4_HTYPE 0x020E /* PCI Header Type [R] */ +#define NILE4_BIST 0x020F /* BIST [R] (unimplemented) */ +#define NILE4_BARC 0x0210 /* PCI Base Address Register Control [R/W] */ +#define NILE4_BAR0 0x0218 /* PCI Base Address Register 0 [R/W] */ +#define NILE4_BAR1 0x0220 /* PCI Base Address Register 1 [R/W] */ +#define NILE4_CIS 0x0228 /* PCI Cardbus CIS Pointer [R] */ + /* (unimplemented) */ +#define NILE4_SSVID 0x022C /* PCI Sub-System Vendor ID [R/W] */ +#define NILE4_SSID 0x022E /* PCI Sub-System ID [R/W] */ +#define NILE4_ROM 0x0230 /* Expansion ROM Base Address [R] */ + /* (unimplemented) */ +#define NILE4_INTLIN 0x023C /* PCI Interrupt Line [R/W] */ +#define NILE4_INTPIN 0x023D /* PCI Interrupt Pin [R] */ +#define NILE4_MINGNT 0x023E /* PCI Min_Gnt [R] (unimplemented) */ +#define NILE4_MAXLAT 0x023F /* PCI Max_Lat [R] (unimplemented) */ +#define NILE4_BAR2 0x0240 /* PCI Base Address Register 2 [R/W] */ +#define NILE4_BAR3 0x0248 /* PCI Base Address Register 3 [R/W] */ +#define NILE4_BAR4 0x0250 /* PCI Base Address Register 4 [R/W] */ +#define NILE4_BAR5 0x0258 /* PCI Base Address Register 5 [R/W] */ +#define NILE4_BAR6 0x0260 /* PCI Base Address Register 6 [R/W] */ +#define NILE4_BAR7 0x0268 /* PCI Base Address Register 7 [R/W] */ +#define NILE4_BAR8 0x0270 /* PCI Base Address Register 8 [R/W] */ +#define NILE4_BARB 0x0278 /* PCI Base Address Register BOOT [R/W] */ + + + /* + * Serial-Port Registers + */ + +#define NILE4_UART_BASE 0x0300 + +#define NILE4_UARTRBR 0x0300 /* UART Receiver Data Buffer [R] */ +#define NILE4_UARTTHR 0x0300 /* UART Transmitter Data Holding [W] */ +#define NILE4_UARTIER 0x0308 /* UART Interrupt Enable [R/W] */ +#define NILE4_UARTDLL 0x0300 /* UART Divisor Latch LSB [R/W] */ +#define NILE4_UARTDLM 0x0308 /* UART Divisor Latch MSB [R/W] */ +#define NILE4_UARTIIR 0x0310 /* UART Interrupt ID [R] */ +#define NILE4_UARTFCR 0x0310 /* UART FIFO Control [W] */ +#define NILE4_UARTLCR 0x0318 /* UART Line Control [R/W] */ +#define NILE4_UARTMCR 0x0320 /* UART Modem Control [R/W] */ +#define NILE4_UARTLSR 0x0328 /* UART Line Status [R/W] */ +#define NILE4_UARTMSR 0x0330 /* UART Modem Status [R/W] */ +#define NILE4_UARTSCR 0x0338 /* UART Scratch [R/W] */ + +#define NILE4_UART_BASE_BAUD 520833 /* 100 MHz / 12 / 16 */ + + + /* + * Interrupt Lines + */ + +#define NILE4_INT_CPCE 0 /* CPU-Interface Parity-Error Interrupt */ +#define NILE4_INT_CNTD 1 /* CPU No-Target Decode Interrupt */ +#define NILE4_INT_MCE 2 /* Memory-Check Error Interrupt */ +#define NILE4_INT_DMA 3 /* DMA Controller Interrupt */ +#define NILE4_INT_UART 4 /* UART Interrupt */ +#define NILE4_INT_WDOG 5 /* Watchdog Timer Interrupt */ +#define NILE4_INT_GPT 6 /* General-Purpose Timer Interrupt */ +#define NILE4_INT_LBRTD 7 /* Local-Bus Ready Timer Interrupt */ +#define NILE4_INT_INTA 8 /* PCI Interrupt Signal INTA# */ +#define NILE4_INT_INTB 9 /* PCI Interrupt Signal INTB# */ +#define NILE4_INT_INTC 10 /* PCI Interrupt Signal INTC# */ +#define NILE4_INT_INTD 11 /* PCI Interrupt Signal INTD# */ +#define NILE4_INT_INTE 12 /* PCI Interrupt Signal INTE# (ISA cascade) */ +#define NILE4_INT_RESV 13 /* Reserved */ +#define NILE4_INT_PCIS 14 /* PCI SERR# Interrupt */ +#define NILE4_INT_PCIE 15 /* PCI Internal Error Interrupt */ + + + /* + * Nile 4 Register Access + */ + +static inline void nile4_sync(void) +{ + volatile u32 *p = (volatile u32 *)0xbfc00000; + (void)(*p); +} + +static inline void nile4_out32(u32 offset, u32 val) +{ + *(volatile u32 *)(NILE4_BASE+offset) = val; + nile4_sync(); +} + +static inline u32 nile4_in32(u32 offset) +{ + u32 val = *(volatile u32 *)(NILE4_BASE+offset); + nile4_sync(); + return val; +} + +static inline void nile4_out16(u32 offset, u16 val) +{ + *(volatile u16 *)(NILE4_BASE+offset) = val; + nile4_sync(); +} + +static inline u16 nile4_in16(u32 offset) +{ + u16 val = *(volatile u16 *)(NILE4_BASE+offset); + nile4_sync(); + return val; +} + +static inline void nile4_out8(u32 offset, u8 val) +{ + *(volatile u8 *)(NILE4_BASE+offset) = val; + nile4_sync(); +} + +static inline u8 nile4_in8(u32 offset) +{ + u8 val = *(volatile u8 *)(NILE4_BASE+offset); + nile4_sync(); + return val; +} + + + /* + * Physical Device Address Registers + */ + +extern void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, + int on_memory_bus, int visible); + + + /* + * PCI Master Registers + */ + +#define NILE4_PCICMD_IACK 0 /* PCI Interrupt Acknowledge */ +#define NILE4_PCICMD_IO 1 /* PCI I/O Space */ +#define NILE4_PCICMD_MEM 3 /* PCI Memory Space */ +#define NILE4_PCICMD_CFG 5 /* PCI Configuration Space */ + + + /* + * PCI Address Spaces + * + * Note that these are multiplexed using PCIINIT[01]! + */ + +#define NILE4_PCI_IO_BASE 0xa6000000 +#define NILE4_PCI_MEM_BASE 0xa8000000 +#define NILE4_PCI_CFG_BASE NILE4_PCI_MEM_BASE +#define NILE4_PCI_IACK_BASE NILE4_PCI_IO_BASE + + +extern void nile4_set_pmr(u32 pmr, u32 type, u32 addr); + + + /* + * Interrupt Programming + */ + +#define NUM_I8259_INTERRUPTS 16 +#define NUM_NILE4_INTERRUPTS 16 + +#define IRQ_I8259_CASCADE NILE4_INT_INTE +#define is_i8259_irq(irq) ((irq) < NUM_I8259_INTERRUPTS) +#define nile4_to_irq(n) ((n)+NUM_I8259_INTERRUPTS) +#define irq_to_nile4(n) ((n)-NUM_I8259_INTERRUPTS) + +extern void nile4_map_irq(int nile4_irq, int cpu_irq); +extern void nile4_map_irq_all(int cpu_irq); +extern void nile4_enable_irq(unsigned int nile4_irq); +extern void nile4_disable_irq(unsigned int nile4_irq); +extern void nile4_disable_irq_all(void); +extern u16 nile4_get_irq_stat(int cpu_irq); +extern void nile4_enable_irq_output(int cpu_irq); +extern void nile4_disable_irq_output(int cpu_irq); +extern void nile4_set_pci_irq_polarity(int pci_irq, int high); +extern void nile4_set_pci_irq_level_or_edge(int pci_irq, int level); +extern void nile4_clear_irq(int nile4_irq); +extern void nile4_clear_irq_mask(u32 mask); +extern u8 nile4_i8259_iack(void); +extern void nile4_dump_irq_status(void); /* Debug */ + +#endif + From ea202c632a52c4a83f1bd82d8d06bc8e04f2689a Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Sat, 25 Aug 2007 11:01:50 +0200 Subject: [PATCH 2212/2804] [MIPS] JAZZ fixes - restructured irq handling - switched vdma to use memory allocated via get_free_pages - setup platform devices for serial, jazz_esp and jazzsonic - fixed cmos rtc access Signed-off-by: Thomas Bogendoerfer Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/jazz/Makefile | 2 +- arch/mips/jazz/irq.c | 94 ++++++------------ arch/mips/jazz/jazz-platform.c | 60 ------------ arch/mips/jazz/jazzdma.c | 47 ++++----- arch/mips/jazz/setup.c | 115 ++++++++++++++++++++++- include/asm-mips/jazz.h | 38 +++----- include/asm-mips/jazzdma.h | 1 - include/asm-mips/mach-jazz/mc146818rtc.h | 10 +- 9 files changed, 181 insertions(+), 187 deletions(-) delete mode 100644 arch/mips/jazz/jazz-platform.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index bb3fb4018602..a8bdc084e10c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -93,6 +93,7 @@ config MACH_JAZZ select ARC32 select ARCH_MAY_HAVE_PC_FDC select GENERIC_ISA_DMA + select IRQ_CPU select I8259 select ISA select PCSPEAKER diff --git a/arch/mips/jazz/Makefile b/arch/mips/jazz/Makefile index 575a9442bc82..5aee0c266d18 100644 --- a/arch/mips/jazz/Makefile +++ b/arch/mips/jazz/Makefile @@ -2,6 +2,6 @@ # Makefile for the Jazz family specific parts of the kernel # -obj-y := irq.o jazzdma.o jazz-platform.o reset.o setup.o +obj-y := irq.o jazzdma.o reset.o setup.o EXTRA_CFLAGS += -Werror diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index 015cf4bb51dd..56235412cbb7 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -11,15 +11,17 @@ #include #include +#include #include #include #include +#include static DEFINE_SPINLOCK(r4030_lock); static void enable_r4030_irq(unsigned int irq) { - unsigned int mask = 1 << (irq - JAZZ_PARALLEL_IRQ); + unsigned int mask = 1 << (irq - JAZZ_IRQ_START); unsigned long flags; spin_lock_irqsave(&r4030_lock, flags); @@ -30,7 +32,7 @@ static void enable_r4030_irq(unsigned int irq) void disable_r4030_irq(unsigned int irq) { - unsigned int mask = ~(1 << (irq - JAZZ_PARALLEL_IRQ)); + unsigned int mask = ~(1 << (irq - JAZZ_IRQ_START)); unsigned long flags; spin_lock_irqsave(&r4030_lock, flags); @@ -51,7 +53,7 @@ void __init init_r4030_ints(void) { int i; - for (i = JAZZ_PARALLEL_IRQ; i <= JAZZ_TIMER_IRQ; i++) + for (i = JAZZ_IRQ_START; i <= JAZZ_IRQ_END; i++) set_irq_chip_and_handler(i, &r4030_irq_type, handle_level_irq); r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0); @@ -66,82 +68,40 @@ void __init init_r4030_ints(void) */ void __init arch_init_irq(void) { + /* + * this is a hack to get back the still needed wired mapping + * killed by init_mm() + */ + + /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ + add_wired_entry(0x02000017, 0x03c00017, 0xe0000000, PM_64K); + /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ + add_wired_entry(0x02400017, 0x02440017, 0xe2000000, PM_16M); + /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ + add_wired_entry(0x01800017, 0x01000017, 0xe4000000, PM_4M); + init_i8259_irqs(); /* Integrated i8259 */ + mips_cpu_irq_init(); init_r4030_ints(); - change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1); -} - -static void loc_call(unsigned int irq, unsigned int mask) -{ - r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, - r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask); - do_IRQ(irq); - r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, - r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask); -} - -static void ll_local_dev(void) -{ - switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) { - case 0: - panic("Unimplemented loc_no_irq handler"); - break; - case 4: - loc_call(JAZZ_PARALLEL_IRQ, JAZZ_IE_PARALLEL); - break; - case 8: - loc_call(JAZZ_PARALLEL_IRQ, JAZZ_IE_FLOPPY); - break; - case 12: - panic("Unimplemented loc_sound handler"); - break; - case 16: - panic("Unimplemented loc_video handler"); - break; - case 20: - loc_call(JAZZ_ETHERNET_IRQ, JAZZ_IE_ETHERNET); - break; - case 24: - loc_call(JAZZ_SCSI_IRQ, JAZZ_IE_SCSI); - break; - case 28: - loc_call(JAZZ_KEYBOARD_IRQ, JAZZ_IE_KEYBOARD); - break; - case 32: - loc_call(JAZZ_MOUSE_IRQ, JAZZ_IE_MOUSE); - break; - case 36: - loc_call(JAZZ_SERIAL1_IRQ, JAZZ_IE_SERIAL1); - break; - case 40: - loc_call(JAZZ_SERIAL2_IRQ, JAZZ_IE_SERIAL2); - break; - } + change_c0_status(ST0_IM, IE_IRQ2 | IE_IRQ1); } asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status(); + unsigned int irq; - if (pending & IE_IRQ5) - write_c0_compare(0); - else if (pending & IE_IRQ4) { + if (pending & IE_IRQ4) { r4030_read_reg32(JAZZ_TIMER_REGISTER); do_IRQ(JAZZ_TIMER_IRQ); - } else if (pending & IE_IRQ3) - panic("Unimplemented ISA NMI handler"); - else if (pending & IE_IRQ2) + } else if (pending & IE_IRQ2) do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK)); else if (pending & IE_IRQ1) { - ll_local_dev(); - } else if (unlikely(pending & IE_IRQ0)) - panic("Unimplemented local_dma handler"); - else if (pending & IE_SW1) { - clear_c0_cause(IE_SW1); - panic("Unimplemented sw1 handler"); - } else if (pending & IE_SW0) { - clear_c0_cause(IE_SW0); - panic("Unimplemented sw0 handler"); + irq = *(volatile u8 *)JAZZ_IO_IRQ_SOURCE >> 2; + if (likely(irq > 0)) + do_IRQ(irq + JAZZ_IRQ_START - 1); + else + panic("Unimplemented loc_no_irq handler"); } } diff --git a/arch/mips/jazz/jazz-platform.c b/arch/mips/jazz/jazz-platform.c deleted file mode 100644 index fd736703eef2..000000000000 --- a/arch/mips/jazz/jazz-platform.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) - */ -#include -#include -#include - -#include - -/* - * Confusion ... It seems the original Microsoft Jazz machine used to have a - * 4.096MHz clock for its UART while the MIPS Magnum and Millenium systems - * had 8MHz. The Olivetti M700-10 and the Acer PICA have 1.8432MHz like PCs. - */ -#ifdef CONFIG_OLIVETTI_M700 -#define JAZZ_BASE_BAUD 1843200 -#else -#define JAZZ_BASE_BAUD 8000000 /* 3072000 */ -#endif - -#define JAZZ_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP) - -#define JAZZ_PORT(base, int) \ -{ \ - .mapbase = base, \ - .irq = int, \ - .uartclk = JAZZ_BASE_BAUD, \ - .iotype = UPIO_MEM, \ - .flags = JAZZ_UART_FLAGS, \ - .regshift = 0, \ -} - -static struct plat_serial8250_port uart8250_data[] = { - JAZZ_PORT(JAZZ_SERIAL1_BASE, JAZZ_SERIAL1_IRQ), - JAZZ_PORT(JAZZ_SERIAL2_BASE, JAZZ_SERIAL2_IRQ), - { }, -}; - -static struct platform_device uart8250_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = uart8250_data, - }, -}; - -static int __init uart8250_init(void) -{ - return platform_device_register(&uart8250_device); -} - -module_init(uart8250_init); - -MODULE_AUTHOR("Ralf Baechle "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("8250 UART probe driver for the Jazz family"); diff --git a/arch/mips/jazz/jazzdma.c b/arch/mips/jazz/jazzdma.c index e8e0ffb9354d..c672c08d49e5 100644 --- a/arch/mips/jazz/jazzdma.c +++ b/arch/mips/jazz/jazzdma.c @@ -27,7 +27,7 @@ */ #define CONF_DEBUG_VDMA 0 -static unsigned long vdma_pagetable_start; +static VDMA_PGTBL_ENTRY *pgtbl; static DEFINE_SPINLOCK(vdma_lock); @@ -46,7 +46,6 @@ static int debuglvl = 3; */ static inline void vdma_pgtbl_init(void) { - VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *) vdma_pagetable_start; unsigned long paddr = 0; int i; @@ -60,31 +59,31 @@ static inline void vdma_pgtbl_init(void) /* * Initialize the Jazz R4030 dma controller */ -void __init vdma_init(void) +static int __init vdma_init(void) { /* * Allocate 32k of memory for DMA page tables. This needs to be page * aligned and should be uncached to avoid cache flushing after every * update. */ - vdma_pagetable_start = - (unsigned long) alloc_bootmem_low_pages(VDMA_PGTBL_SIZE); - if (!vdma_pagetable_start) + pgtbl = (VDMA_PGTBL_ENTRY *)__get_free_pages(GFP_KERNEL | GFP_DMA, + get_order(VDMA_PGTBL_SIZE)); + if (!pgtbl) BUG(); - dma_cache_wback_inv(vdma_pagetable_start, VDMA_PGTBL_SIZE); - vdma_pagetable_start = KSEG1ADDR(vdma_pagetable_start); + dma_cache_wback_inv((unsigned long)pgtbl, VDMA_PGTBL_SIZE); + pgtbl = (VDMA_PGTBL_ENTRY *)KSEG1ADDR(pgtbl); /* * Clear the R4030 translation table */ vdma_pgtbl_init(); - r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE, - CPHYSADDR(vdma_pagetable_start)); + r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE, CPHYSADDR(pgtbl)); r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM, VDMA_PGTBL_SIZE); r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0); - printk("VDMA: R4030 DMA pagetables initialized.\n"); + printk(KERN_INFO "VDMA: R4030 DMA pagetables initialized.\n"); + return 0; } /* @@ -92,7 +91,6 @@ void __init vdma_init(void) */ unsigned long vdma_alloc(unsigned long paddr, unsigned long size) { - VDMA_PGTBL_ENTRY *entry = (VDMA_PGTBL_ENTRY *) vdma_pagetable_start; int first, last, pages, frame, i; unsigned long laddr, flags; @@ -114,10 +112,10 @@ unsigned long vdma_alloc(unsigned long paddr, unsigned long size) /* * Find free chunk */ - pages = (size + 4095) >> 12; /* no. of pages to allocate */ + pages = VDMA_PAGE(paddr + size) - VDMA_PAGE(paddr) + 1; first = 0; while (1) { - while (entry[first].owner != VDMA_PAGE_EMPTY && + while (pgtbl[first].owner != VDMA_PAGE_EMPTY && first < VDMA_PGTBL_ENTRIES) first++; if (first + pages > VDMA_PGTBL_ENTRIES) { /* nothing free */ spin_unlock_irqrestore(&vdma_lock, flags); @@ -125,12 +123,13 @@ unsigned long vdma_alloc(unsigned long paddr, unsigned long size) } last = first + 1; - while (entry[last].owner == VDMA_PAGE_EMPTY + while (pgtbl[last].owner == VDMA_PAGE_EMPTY && last - first < pages) last++; if (last - first == pages) break; /* found */ + first = last + 1; } /* @@ -140,8 +139,8 @@ unsigned long vdma_alloc(unsigned long paddr, unsigned long size) frame = paddr & ~(VDMA_PAGESIZE - 1); for (i = first; i < last; i++) { - entry[i].frame = frame; - entry[i].owner = laddr; + pgtbl[i].frame = frame; + pgtbl[i].owner = laddr; frame += VDMA_PAGESIZE; } @@ -160,10 +159,10 @@ unsigned long vdma_alloc(unsigned long paddr, unsigned long size) printk("%08x ", i << 12); printk("\nPADDR: "); for (i = first; i < last; i++) - printk("%08x ", entry[i].frame); + printk("%08x ", pgtbl[i].frame); printk("\nOWNER: "); for (i = first; i < last; i++) - printk("%08x ", entry[i].owner); + printk("%08x ", pgtbl[i].owner); printk("\n"); } @@ -181,7 +180,6 @@ EXPORT_SYMBOL(vdma_alloc); */ int vdma_free(unsigned long laddr) { - VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *) vdma_pagetable_start; int i; i = laddr >> 12; @@ -213,8 +211,6 @@ EXPORT_SYMBOL(vdma_free); */ int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size) { - VDMA_PGTBL_ENTRY *pgtbl = - (VDMA_PGTBL_ENTRY *) vdma_pagetable_start; int first, pages, npages; if (laddr > 0xffffff) { @@ -289,8 +285,6 @@ unsigned long vdma_phys2log(unsigned long paddr) { int i; int frame; - VDMA_PGTBL_ENTRY *pgtbl = - (VDMA_PGTBL_ENTRY *) vdma_pagetable_start; frame = paddr & ~(VDMA_PAGESIZE - 1); @@ -312,9 +306,6 @@ EXPORT_SYMBOL(vdma_phys2log); */ unsigned long vdma_log2phys(unsigned long laddr) { - VDMA_PGTBL_ENTRY *pgtbl = - (VDMA_PGTBL_ENTRY *) vdma_pagetable_start; - return pgtbl[laddr >> 12].frame + (laddr & (VDMA_PAGESIZE - 1)); } @@ -564,3 +555,5 @@ int vdma_get_enable(int channel) return enable; } + +arch_initcall(vdma_init); diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 798279e06691..5c6271ab927f 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -7,6 +7,7 @@ * * Copyright (C) 1996, 1997, 1998, 2001 by Ralf Baechle * Copyright (C) 2001 MIPS Technologies, Inc. + * Copyright (C) 2007 by Thomas Bogendoerfer */ #include #include @@ -20,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -30,6 +33,7 @@ #include #include #include +#include extern asmlinkage void jazz_handle_int(void); @@ -72,10 +76,8 @@ void __init plat_mem_setup(void) /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K); - /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M); - /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M); @@ -94,6 +96,7 @@ void __init plat_mem_setup(void) _machine_restart = jazz_machine_restart; +#ifdef CONFIG_VT screen_info = (struct screen_info) { 0, 0, /* orig-x, orig-y */ 0, /* unused */ @@ -105,6 +108,112 @@ void __init plat_mem_setup(void) 0, /* orig_video_isVGA */ 16 /* orig_video_points */ }; +#endif - vdma_init(); + add_preferred_console("ttyS", 0, "9600"); } + +#ifdef CONFIG_OLIVETTI_M700 +#define UART_CLK 1843200 +#else +/* Some Jazz machines seem to have an 8MHz crystal clock but I don't know + exactly which ones ... XXX */ +#define UART_CLK (8000000 / 16) /* ( 3072000 / 16) */ +#endif + +#define MEMPORT(_base, _irq) \ + { \ + .mapbase = (_base), \ + .membase = (void *)(_base), \ + .irq = (_irq), \ + .uartclk = UART_CLK, \ + .iotype = UPIO_MEM, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port jazz_serial_data[] = { + MEMPORT(JAZZ_SERIAL1_BASE, JAZZ_SERIAL1_IRQ), + MEMPORT(JAZZ_SERIAL2_BASE, JAZZ_SERIAL2_IRQ), + { }, +}; + +static struct platform_device jazz_serial8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = jazz_serial_data, + }, +}; + +static struct resource jazz_esp_rsrc[] = { + { + .start = JAZZ_SCSI_BASE, + .end = JAZZ_SCSI_BASE + 31, + .flags = IORESOURCE_MEM + }, + { + .start = JAZZ_SCSI_DMA, + .end = JAZZ_SCSI_DMA, + .flags = IORESOURCE_MEM + }, + { + .start = JAZZ_SCSI_IRQ, + .end = JAZZ_SCSI_IRQ, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device jazz_esp_pdev = { + .name = "jazz_esp", + .num_resources = ARRAY_SIZE(jazz_esp_rsrc), + .resource = jazz_esp_rsrc +}; + +static struct resource jazz_sonic_rsrc[] = { + { + .start = JAZZ_ETHERNET_BASE, + .end = JAZZ_ETHERNET_BASE + 0xff, + .flags = IORESOURCE_MEM + }, + { + .start = JAZZ_ETHERNET_IRQ, + .end = JAZZ_ETHERNET_IRQ, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device jazz_sonic_pdev = { + .name = "jazzsonic", + .num_resources = ARRAY_SIZE(jazz_sonic_rsrc), + .resource = jazz_sonic_rsrc +}; + +static struct resource jazz_cmos_rsrc[] = { + { + .start = 0x70, + .end = 0x71, + .flags = IORESOURCE_IO + }, + { + .start = 8, + .end = 8, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device jazz_cmos_pdev = { + .name = "rtc_cmos", + .num_resources = ARRAY_SIZE(jazz_cmos_rsrc), + .resource = jazz_cmos_rsrc +}; + +static int __init jazz_setup_devinit(void) +{ + platform_device_register(&jazz_serial8250_device); + platform_device_register(&jazz_esp_pdev); + platform_device_register(&jazz_sonic_pdev); + platform_device_register(&jazz_cmos_pdev); + return 0; +} + +device_initcall(jazz_setup_devinit); diff --git a/include/asm-mips/jazz.h b/include/asm-mips/jazz.h index 81cbf004fd13..83f449dec95e 100644 --- a/include/asm-mips/jazz.h +++ b/include/asm-mips/jazz.h @@ -184,38 +184,26 @@ typedef struct { #define JAZZ_IO_IRQ_SOURCE 0xe0010000 #define JAZZ_IO_IRQ_ENABLE 0xe0010002 -/* - * JAZZ interrupt enable bits - */ -#define JAZZ_IE_PARALLEL (1 << 0) -#define JAZZ_IE_FLOPPY (1 << 1) -#define JAZZ_IE_SOUND (1 << 2) -#define JAZZ_IE_VIDEO (1 << 3) -#define JAZZ_IE_ETHERNET (1 << 4) -#define JAZZ_IE_SCSI (1 << 5) -#define JAZZ_IE_KEYBOARD (1 << 6) -#define JAZZ_IE_MOUSE (1 << 7) -#define JAZZ_IE_SERIAL1 (1 << 8) -#define JAZZ_IE_SERIAL2 (1 << 9) - /* * JAZZ Interrupt Level definitions * * This is somewhat broken. For reasons which nobody can remember anymore * we remap the Jazz interrupts to the usual ISA style interrupt numbers. */ -#define JAZZ_PARALLEL_IRQ 16 -#define JAZZ_FLOPPY_IRQ 17 -#define JAZZ_SOUND_IRQ 18 -#define JAZZ_VIDEO_IRQ 19 -#define JAZZ_ETHERNET_IRQ 20 -#define JAZZ_SCSI_IRQ 21 -#define JAZZ_KEYBOARD_IRQ 22 -#define JAZZ_MOUSE_IRQ 23 -#define JAZZ_SERIAL1_IRQ 24 -#define JAZZ_SERIAL2_IRQ 25 +#define JAZZ_IRQ_START 24 +#define JAZZ_IRQ_END (24 + 9) +#define JAZZ_PARALLEL_IRQ (JAZZ_IRQ_START + 0) +#define JAZZ_FLOPPY_IRQ (JAZZ_IRQ_START + 1) +#define JAZZ_SOUND_IRQ (JAZZ_IRQ_START + 2) +#define JAZZ_VIDEO_IRQ (JAZZ_IRQ_START + 3) +#define JAZZ_ETHERNET_IRQ (JAZZ_IRQ_START + 4) +#define JAZZ_SCSI_IRQ (JAZZ_IRQ_START + 5) +#define JAZZ_KEYBOARD_IRQ (JAZZ_IRQ_START + 6) +#define JAZZ_MOUSE_IRQ (JAZZ_IRQ_START + 7) +#define JAZZ_SERIAL1_IRQ (JAZZ_IRQ_START + 8) +#define JAZZ_SERIAL2_IRQ (JAZZ_IRQ_START + 9) -#define JAZZ_TIMER_IRQ 31 +#define JAZZ_TIMER_IRQ (MIPS_CPU_IRQ_BASE+6) /* diff --git a/include/asm-mips/jazzdma.h b/include/asm-mips/jazzdma.h index 0a205b77e505..8bb37bba68f0 100644 --- a/include/asm-mips/jazzdma.h +++ b/include/asm-mips/jazzdma.h @@ -7,7 +7,6 @@ /* * Prototypes and macros */ -extern void vdma_init(void); extern unsigned long vdma_alloc(unsigned long paddr, unsigned long size); extern int vdma_free(unsigned long laddr); extern int vdma_remap(unsigned long laddr, unsigned long paddr, diff --git a/include/asm-mips/mach-jazz/mc146818rtc.h b/include/asm-mips/mach-jazz/mc146818rtc.h index f44fdba1998b..987f727afe25 100644 --- a/include/asm-mips/mach-jazz/mc146818rtc.h +++ b/include/asm-mips/mach-jazz/mc146818rtc.h @@ -4,12 +4,15 @@ * for more details. * * Copyright (C) 1998, 2001, 03 by Ralf Baechle + * Copyright (C) 2007 Thomas Bogendoerfer * * RTC routines for Jazz style attached Dallas chip. */ #ifndef __ASM_MACH_JAZZ_MC146818RTC_H #define __ASM_MACH_JAZZ_MC146818RTC_H +#include + #include #include @@ -19,16 +22,17 @@ static inline unsigned char CMOS_READ(unsigned long addr) { outb_p(addr, RTC_PORT(0)); - - return *(char *)JAZZ_RTC_BASE; + return *(volatile char *)JAZZ_RTC_BASE; } static inline void CMOS_WRITE(unsigned char data, unsigned long addr) { outb_p(addr, RTC_PORT(0)); - *(char *)JAZZ_RTC_BASE = data; + *(volatile char *)JAZZ_RTC_BASE = data; } #define RTC_ALWAYS_BCD 0 +#define mc146818_decode_year(year) ((year) + 1980) + #endif /* __ASM_MACH_JAZZ_MC146818RTC_H */ From 1c0c13eb935c95fd2ca0b0aca6dd4860487fb242 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 25 Sep 2007 15:40:12 +0200 Subject: [PATCH 2213/2804] [MIPS] Add support for BCM47XX CPUs. Note that the BCM4710 does not support the wait instruction, this is not a mistake in the code. It originally comes from the OpenWrt patches. Cc: Michael Buesch Cc: Felix Fietkau Cc: Florian Schirmer Signed-off-by: Aurelien Jarno Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 14 +++++ arch/mips/Makefile | 7 +++ arch/mips/bcm47xx/Makefile | 6 ++ arch/mips/bcm47xx/irq.c | 55 +++++++++++++++++ arch/mips/bcm47xx/prom.c | 49 +++++++++++++++ arch/mips/bcm47xx/serial.c | 52 ++++++++++++++++ arch/mips/bcm47xx/setup.c | 79 +++++++++++++++++++++++++ arch/mips/bcm47xx/time.c | 56 ++++++++++++++++++ arch/mips/kernel/cpu-probe.c | 20 +++++++ arch/mips/kernel/proc.c | 2 + arch/mips/mm/tlbex.c | 2 + include/asm-mips/bootinfo.h | 6 ++ include/asm-mips/cpu.h | 12 +++- include/asm-mips/mach-bcm47xx/bcm47xx.h | 27 +++++++++ 14 files changed, 385 insertions(+), 2 deletions(-) create mode 100644 arch/mips/bcm47xx/Makefile create mode 100644 arch/mips/bcm47xx/irq.c create mode 100644 arch/mips/bcm47xx/prom.c create mode 100644 arch/mips/bcm47xx/serial.c create mode 100644 arch/mips/bcm47xx/setup.c create mode 100644 arch/mips/bcm47xx/time.c create mode 100644 include/asm-mips/mach-bcm47xx/bcm47xx.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a8bdc084e10c..6648f9b914e7 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -44,6 +44,20 @@ config BASLER_EXCITE_PROTOTYPE note that a kernel built with this option selected will not be able to run on normal units. +config BCM47XX + bool "BCM47XX based boards" + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select SYS_HAS_CPU_MIPS32_R1 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SSB + select SSB_DRIVER_MIPS + select GENERIC_GPIO + help + Support for BCM47XX based boards + config MIPS_COBALT bool "Cobalt Server" select DMA_NONCOHERENT diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 6dcdbfb15ce3..7b936edd2c16 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -534,6 +534,13 @@ load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000 libs-$(CONFIG_SIBYTE_BIGSUR) += arch/mips/sibyte/swarm/ load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000 +# +# Broadcom BCM47XX boards +# +core-$(CONFIG_BCM47XX) += arch/mips/bcm47xx/ +cflags-$(CONFIG_BCM47XX) += -Iinclude/asm-mips/mach-bcm47xx +load-$(CONFIG_BCM47XX) := 0xffffffff80001000 + # # SNI RM # diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile new file mode 100644 index 000000000000..dc035f90d363 --- /dev/null +++ b/arch/mips/bcm47xx/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the BCM47XX specific kernel interface routines +# under Linux. +# + +obj-y := irq.o prom.o serial.o setup.o time.o diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c new file mode 100644 index 000000000000..325757acd020 --- /dev/null +++ b/arch/mips/bcm47xx/irq.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004 Florian Schirmer + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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 + +void plat_irq_dispatch(void) +{ + u32 cause; + + cause = read_c0_cause() & read_c0_status() & CAUSEF_IP; + + clear_c0_status(cause); + + if (cause & CAUSEF_IP7) + do_IRQ(7); + if (cause & CAUSEF_IP2) + do_IRQ(2); + if (cause & CAUSEF_IP3) + do_IRQ(3); + if (cause & CAUSEF_IP4) + do_IRQ(4); + if (cause & CAUSEF_IP5) + do_IRQ(5); + if (cause & CAUSEF_IP6) + do_IRQ(6); +} + +void __init arch_init_irq(void) +{ + mips_cpu_irq_init(); +} diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c new file mode 100644 index 000000000000..41ac9dd88bde --- /dev/null +++ b/arch/mips/bcm47xx/prom.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004 Florian Schirmer + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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 + +const char *get_system_type(void) +{ + return "Broadcom BCM47XX"; +} + +void __init prom_init(void) +{ + unsigned long mem; + + /* Figure out memory size by finding aliases */ + for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { + if (*(unsigned long *)((unsigned long)(prom_init) + mem) == + *(unsigned long *)(prom_init)) + break; + } + + add_memory_region(0, mem, BOOT_MEM_RAM); +} + +void __init prom_free_prom_memory(void) +{ +} diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c new file mode 100644 index 000000000000..59c11afdb2ab --- /dev/null +++ b/arch/mips/bcm47xx/serial.c @@ -0,0 +1,52 @@ +/* + * 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. + * + * Copyright (C) 2007 Aurelien Jarno + */ + +#include +#include +#include +#include +#include +#include + +static struct plat_serial8250_port uart8250_data[5]; + +static struct platform_device uart8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = uart8250_data, + }, +}; + +static int __init uart8250_init(void) +{ + int i; + struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore); + + memset(&uart8250_data, 0, sizeof(uart8250_data)); + + for (i = 0; i < mcore->nr_serial_ports; i++) { + struct plat_serial8250_port *p = &(uart8250_data[i]); + struct ssb_serial_port *ssb_port = &(mcore->serial_ports[i]); + + p->mapbase = (unsigned int) ssb_port->regs; + p->membase = (void *) ssb_port->regs; + p->irq = ssb_port->irq + 2; + p->uartclk = ssb_port->baud_base; + p->regshift = ssb_port->reg_shift; + p->iotype = UPIO_MEM; + p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + } + return platform_device_register(&uart8250_device); +} + +module_init(uart8250_init); + +MODULE_AUTHOR("Aurelien Jarno "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("8250 UART probe driver for the BCM47XX platforms"); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c new file mode 100644 index 000000000000..dfc580aae958 --- /dev/null +++ b/arch/mips/bcm47xx/setup.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2004 Florian Schirmer + * Copyright (C) 2005 Waldemar Brodkorb + * Copyright (C) 2006 Felix Fietkau + * Copyright (C) 2006 Michael Buesch + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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 + +struct ssb_bus ssb_bcm47xx; +EXPORT_SYMBOL(ssb_bcm47xx); + +static void bcm47xx_machine_restart(char *command) +{ + printk(KERN_ALERT "Please stand by while rebooting the system...\n"); + local_irq_disable(); + /* Set the watchdog timer to reset immediately */ + ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 1); + while (1) + cpu_relax(); +} + +static void bcm47xx_machine_halt(void) +{ + /* Disable interrupts and watchdog and spin forever */ + local_irq_disable(); + ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 0); + while (1) + cpu_relax(); +} + +static int bcm47xx_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + /* TODO: fill ssb_init_invariants using boardtype/boardrev + * CFE environment variables. + */ + return 0; +} + +void __init plat_mem_setup(void) +{ + int err; + + err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, + bcm47xx_get_invariants); + if (err) + panic("Failed to initialize SSB bus (err %d)\n", err); + + _machine_restart = bcm47xx_machine_restart; + _machine_halt = bcm47xx_machine_halt; + pm_power_off = bcm47xx_machine_halt; + board_time_init = bcm47xx_time_init; +} + diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c new file mode 100644 index 000000000000..b27d07f29059 --- /dev/null +++ b/arch/mips/bcm47xx/time.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2004 Florian Schirmer + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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 + +void __init +bcm47xx_time_init(void) +{ + unsigned long hz; + + /* + * Use deterministic values for initial counter interrupt + * so that calibrate delay avoids encountering a counter wrap. + */ + write_c0_count(0); + write_c0_compare(0xffff); + + hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2; + if (!hz) + hz = 100000000; + + /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */ + mips_hpt_frequency = hz; +} + +void __init +plat_timer_setup(struct irqaction *irq) +{ + /* Enable the timer interrupt */ + setup_irq(7, irq); +} diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 3e004161ebd5..97c03865c06a 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -159,6 +159,7 @@ static inline void check_wait(void) case CPU_5KC: case CPU_25KF: case CPU_PR4450: + case CPU_BCM3302: cpu_wait = r4k_wait; break; @@ -793,6 +794,22 @@ static inline void cpu_probe_philips(struct cpuinfo_mips *c) } +static inline void cpu_probe_broadcom(struct cpuinfo_mips *c) +{ + decode_configs(c); + switch (c->processor_id & 0xff00) { + case PRID_IMP_BCM3302: + c->cputype = CPU_BCM3302; + break; + case PRID_IMP_BCM4710: + c->cputype = CPU_BCM4710; + break; + default: + c->cputype = CPU_UNKNOWN; + break; + } +} + __init void cpu_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -815,6 +832,9 @@ __init void cpu_probe(void) case PRID_COMP_SIBYTE: cpu_probe_sibyte(c); break; + case PRID_COMP_BROADCOM: + cpu_probe_broadcom(c); + break; case PRID_COMP_SANDCRAFT: cpu_probe_sandcraft(c); break; diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index ec04f5a1a5ea..accd5201d0e1 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -82,6 +82,8 @@ static const char *cpu_name[] = { [CPU_VR4181] = "NEC VR4181", [CPU_VR4181A] = "NEC VR4181A", [CPU_SR71000] = "Sandcraft SR71000", + [CPU_BCM3302] = "Broadcom BCM3302", + [CPU_BCM4710] = "Broadcom BCM4710", [CPU_PR4450] = "Philips PR4450", [CPU_LOONGSON2] = "ICT Loongson-2", }; diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 6c425b052442..b2c6b9e47564 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -908,6 +908,8 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l, case CPU_4KSC: case CPU_20KC: case CPU_25KF: + case CPU_BCM3302: + case CPU_BCM4710: case CPU_LOONGSON2: if (m4kc_tlbp_war()) i_nop(p); diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index 1bb4bf657701..efa8158f61eb 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -215,6 +215,12 @@ #define MACH_GROUP_WINDRIVER 28 /* Windriver boards */ #define MACH_WRPPMC 1 +/* + * Valid machtype for group Broadcom + */ +#define MACH_GROUP_BRCM 23 /* Broadcom */ +#define MACH_BCM47XX 1 /* Broadcom BCM47XX */ + #define CL_SIZE COMMAND_LINE_SIZE const char *get_system_type(void); diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h index 3857358fb6de..d67f43b09964 100644 --- a/include/asm-mips/cpu.h +++ b/include/asm-mips/cpu.h @@ -105,6 +105,13 @@ #define PRID_IMP_SR71000 0x0400 +/* + * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM + */ + +#define PRID_IMP_BCM4710 0x4000 +#define PRID_IMP_BCM3302 0x9000 + /* * Definitions for 7:0 on legacy processors */ @@ -217,8 +224,9 @@ #define CPU_R14000 64 #define CPU_LOONGSON1 65 #define CPU_LOONGSON2 66 - -#define CPU_LAST 66 +#define CPU_BCM3302 67 +#define CPU_BCM4710 68 +#define CPU_LAST 68 /* * ISA Level encodings diff --git a/include/asm-mips/mach-bcm47xx/bcm47xx.h b/include/asm-mips/mach-bcm47xx/bcm47xx.h new file mode 100644 index 000000000000..a2fb5e8dd6c6 --- /dev/null +++ b/include/asm-mips/mach-bcm47xx/bcm47xx.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2007 Aurelien Jarno + * + * 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. + */ + +#ifndef __ASM_BCM47XX_H +#define __ASM_BCM47XX_H + +/* SSB bus */ +extern struct ssb_bus ssb_bcm47xx; + +extern void bcm47xx_time_init(void); + +#endif /* __ASM_BCM47XX_H */ From 4e45171c4e31578157189ca22cfb7b2bcc5f69f2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 28 Aug 2007 09:03:01 +0000 Subject: [PATCH 2214/2804] [MIPS] cleanup struct irqaction initializers Signed-off-by: Thomas Gleixner CC: Ralf Baechle Signed-off-by: Ralf Baechle --- arch/mips/cobalt/irq.c | 4 +++- arch/mips/jmr3927/rbhma3100/irq.c | 8 ++++++-- arch/mips/kernel/i8259.c | 4 +++- arch/mips/sgi-ip32/ip32-irq.c | 16 ++++++++++++---- .../toshiba_rbtx4927/toshiba_rbtx4927_irq.c | 10 ++++++---- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c index 950ad1e8be44..48763cd10eaa 100644 --- a/arch/mips/cobalt/irq.c +++ b/arch/mips/cobalt/irq.c @@ -92,7 +92,9 @@ asmlinkage void plat_irq_dispatch(void) } static struct irqaction irq_via = { - no_action, 0, { { 0, } }, "cascade", NULL, NULL + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade" }; void __init arch_init_irq(void) diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c index d9efe692e551..3a47e8ce1196 100644 --- a/arch/mips/jmr3927/rbhma3100/irq.c +++ b/arch/mips/jmr3927/rbhma3100/irq.c @@ -104,7 +104,9 @@ static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id) } static struct irqaction ioc_action = { - jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL, + .handler = jmr3927_ioc_interrupt, + .mask = CPU_MASK_NONE, + .name = "IOC", }; static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id) @@ -116,7 +118,9 @@ static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } static struct irqaction pcierr_action = { - jmr3927_pcierr_interrupt, 0, CPU_MASK_NONE, "PCI error", NULL, NULL, + .handler = jmr3927_pcierr_interrupt, + .mask = CPU_MASK_NONE, + .name = "PCI error", }; static void __init jmr3927_irq_init(void); diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 4f4359bfd180..60021647cac1 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -303,7 +303,9 @@ void init_8259A(int auto_eoi) * IRQ2 is cascade interrupt to second interrupt controller */ static struct irqaction irq2 = { - no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", }; static struct resource pic1_io_resource = { diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index fb9da9acf53f..5bad1b744d0f 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -117,10 +117,18 @@ static void inline flush_mace_bus(void) extern irqreturn_t crime_memerr_intr(int irq, void *dev_id); extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); -struct irqaction memerr_irq = { crime_memerr_intr, IRQF_DISABLED, - CPU_MASK_NONE, "CRIME memory error", NULL, NULL }; -struct irqaction cpuerr_irq = { crime_cpuerr_intr, IRQF_DISABLED, - CPU_MASK_NONE, "CRIME CPU error", NULL, NULL }; +struct irqaction memerr_irq = { + .handler = crime_memerr_intr, + .flags = IRQF_DISABLED, + .mask = CPU_MASK_NONE, + .name = "CRIME memory error", +}; +struct irqaction cpuerr_irq = { + .handler = crime_cpuerr_intr, + .flags = IRQF_DISABLED, + .mask = CPU_MASK_NONE, + .name = "CRIME CPU error", +}; /* * For interrupts wired from a single device to the CPU. Only the clock diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index 9607ad5e734a..551235648811 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -243,10 +243,12 @@ int toshiba_rbtx4927_irq_nested(int sw_irq) return (sw_irq); } -//#define TOSHIBA_RBTX4927_PIC_ACTION(s) { no_action, 0, CPU_MASK_NONE, s, NULL, NULL } -#define TOSHIBA_RBTX4927_PIC_ACTION(s) { no_action, IRQF_SHARED, CPU_MASK_NONE, s, NULL, NULL } -static struct irqaction toshiba_rbtx4927_irq_ioc_action = -TOSHIBA_RBTX4927_PIC_ACTION(TOSHIBA_RBTX4927_IOC_NAME); +static struct irqaction toshiba_rbtx4927_irq_ioc_action = { + .handler = no_action, + .flags = IRQF_SHARED, + .mask = CPU_MASK_NONE, + .name = TOSHIBA_RBTX4927_IOC_NAME +}; /**********************************************************************************/ From a02eb8da02741f43efb6f06adf534f9f2b913d80 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 28 Aug 2007 00:28:09 +0900 Subject: [PATCH 2215/2804] [MIPS] tx4927: Cleanup unused macros and non-standard IO accessors. This patch removes many unused constants, replaces non-standard IO accessors with standard ones, and kills terrible tx4927_mips.h file. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/tx4927/common/tx4927_dbgio.c | 1 - arch/mips/tx4927/common/tx4927_prom.c | 12 +- arch/mips/tx4927/common/tx4927_setup.c | 11 +- .../toshiba_rbtx4927/toshiba_rbtx4927_irq.c | 21 +- .../toshiba_rbtx4927/toshiba_rbtx4927_setup.c | 32 +- include/asm-mips/tx4927/toshiba_rbtx4927.h | 8 +- include/asm-mips/tx4927/tx4927.h | 439 -- include/asm-mips/tx4927/tx4927_mips.h | 4177 ----------------- 8 files changed, 38 insertions(+), 4663 deletions(-) delete mode 100644 include/asm-mips/tx4927/tx4927_mips.h diff --git a/arch/mips/tx4927/common/tx4927_dbgio.c b/arch/mips/tx4927/common/tx4927_dbgio.c index 09bdf2baa835..d8423e001b2d 100644 --- a/arch/mips/tx4927/common/tx4927_dbgio.c +++ b/arch/mips/tx4927/common/tx4927_dbgio.c @@ -31,7 +31,6 @@ #include #include -#include u8 getDebugChar(void) { diff --git a/arch/mips/tx4927/common/tx4927_prom.c b/arch/mips/tx4927/common/tx4927_prom.c index 7d4cbf512d8a..6eed53d8f386 100644 --- a/arch/mips/tx4927/common/tx4927_prom.c +++ b/arch/mips/tx4927/common/tx4927_prom.c @@ -38,7 +38,7 @@ #include #include -static unsigned int __init tx4927_process_sdccr(u64 * addr) +static unsigned int __init tx4927_process_sdccr(unsigned long addr) { u64 val; unsigned int sdccr_ce; @@ -52,7 +52,7 @@ static unsigned int __init tx4927_process_sdccr(u64 * addr) unsigned int mw = 0; unsigned int msize = 0; - val = (*((vu64 *) (addr))); + val = __raw_readq((void __iomem *)addr); /* MVMCP -- need #defs for these bits masks */ sdccr_ce = ((val & (1 << 10)) >> 10); @@ -136,10 +136,10 @@ unsigned int __init tx4927_get_mem_size(void) unsigned int total; /* MVMCP -- need #defs for these registers */ - c0 = tx4927_process_sdccr((u64 *) 0xff1f8000); - c1 = tx4927_process_sdccr((u64 *) 0xff1f8008); - c2 = tx4927_process_sdccr((u64 *) 0xff1f8010); - c3 = tx4927_process_sdccr((u64 *) 0xff1f8018); + c0 = tx4927_process_sdccr(0xff1f8000); + c1 = tx4927_process_sdccr(0xff1f8008); + c2 = tx4927_process_sdccr(0xff1f8010); + c3 = tx4927_process_sdccr(0xff1f8018); total = c0 + c1 + c2 + c3; return (total); diff --git a/arch/mips/tx4927/common/tx4927_setup.c b/arch/mips/tx4927/common/tx4927_setup.c index c8e49feb345b..b18ed58f88a9 100644 --- a/arch/mips/tx4927/common/tx4927_setup.c +++ b/arch/mips/tx4927/common/tx4927_setup.c @@ -124,10 +124,10 @@ dump_cp0(char *key) return; } -void print_pic(char *key, u32 reg, char *name) +void print_pic(char *key, unsigned long reg, char *name) { - printk("%s pic:0x%08x:%s=0x%08x\n", key, reg, name, - TX4927_RD(reg)); + printk(KERN_INFO "%s pic:0x%08lx:%s=0x%08x\n", key, reg, name, + __raw_readl((void __iomem *)reg)); return; } @@ -166,9 +166,10 @@ void dump_pic(char *key) } -void print_addr(char *hdr, char *key, u32 addr) +void print_addr(char *hdr, char *key, unsigned long addr) { - printk("%s %s:0x%08x=0x%08x\n", hdr, key, addr, TX4927_RD(addr)); + printk(KERN_INFO "%s %s:0x%08lx=0x%08x\n", hdr, key, addr, + __raw_readl((void __iomem *)addr)); return; } diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index 551235648811..305eb12f84cc 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -204,8 +204,8 @@ static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { .mask_ack = toshiba_rbtx4927_irq_ioc_disable, .unmask = toshiba_rbtx4927_irq_ioc_enable, }; -#define TOSHIBA_RBTX4927_IOC_INTR_ENAB 0xbc002000 -#define TOSHIBA_RBTX4927_IOC_INTR_STAT 0xbc002006 +#define TOSHIBA_RBTX4927_IOC_INTR_ENAB (void __iomem *)0xbc002000UL +#define TOSHIBA_RBTX4927_IOC_INTR_STAT (void __iomem *)0xbc002006UL u32 bit2num(u32 num) @@ -224,7 +224,7 @@ int toshiba_rbtx4927_irq_nested(int sw_irq) { u32 level3; - level3 = reg_rd08(TOSHIBA_RBTX4927_IOC_INTR_STAT) & 0x1f; + level3 = readb(TOSHIBA_RBTX4927_IOC_INTR_STAT) & 0x1f; if (level3) { sw_irq = TOSHIBA_RBTX4927_IRQ_IOC_BEG + bit2num(level3); if (sw_irq != TOSHIBA_RBTX4927_IRQ_NEST_ISA_ON_IOC) { @@ -288,9 +288,9 @@ static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq) panic("\n"); } - v = TX4927_RD08(TOSHIBA_RBTX4927_IOC_INTR_ENAB); + v = readb(TOSHIBA_RBTX4927_IOC_INTR_ENAB); v |= (1 << (irq - TOSHIBA_RBTX4927_IRQ_IOC_BEG)); - TOSHIBA_RBTX4927_WR08(TOSHIBA_RBTX4927_IOC_INTR_ENAB, v); + writeb(v, TOSHIBA_RBTX4927_IOC_INTR_ENAB); } @@ -308,9 +308,10 @@ static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq) panic("\n"); } - v = TX4927_RD08(TOSHIBA_RBTX4927_IOC_INTR_ENAB); + v = readb(TOSHIBA_RBTX4927_IOC_INTR_ENAB); v &= ~(1 << (irq - TOSHIBA_RBTX4927_IRQ_IOC_BEG)); - TOSHIBA_RBTX4927_WR08(TOSHIBA_RBTX4927_IOC_INTR_ENAB, v); + writeb(v, TOSHIBA_RBTX4927_IOC_INTR_ENAB); + mmiowb(); } @@ -387,12 +388,12 @@ void toshiba_rbtx4927_irq_dump_pics(char *s) level1_m = level0_m; level1_s = level0_s & 0x87; - level2 = TX4927_RD(0xff1ff6a0); + level2 = __raw_readl((void __iomem *)0xff1ff6a0UL); level2_p = (((level2 & 0x10000)) ? 0 : 1); level2_s = (((level2 & 0x1f) == 0x1f) ? 0 : (level2 & 0x1f)); - level3_m = reg_rd08(TOSHIBA_RBTX4927_IOC_INTR_ENAB) & 0x1f; - level3_s = reg_rd08(TOSHIBA_RBTX4927_IOC_INTR_STAT) & 0x1f; + level3_m = readb(TOSHIBA_RBTX4927_IOC_INTR_ENAB) & 0x1f; + level3_s = readb(TOSHIBA_RBTX4927_IOC_INTR_STAT) & 0x1f; level4_m = inb(0x21); outb(0x0A, 0x20); diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index 3e84237abe63..4f302062b2d6 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c @@ -679,25 +679,30 @@ void __init tx4927_pci_setup(void) #endif /* CONFIG_PCI */ +static void __noreturn wait_forever(void) +{ + while (1) + if (cpu_wait) + (*cpu_wait)(); +} + void toshiba_rbtx4927_restart(char *command) { printk(KERN_NOTICE "System Rebooting...\n"); /* enable the s/w reset register */ - reg_wr08(RBTX4927_SW_RESET_ENABLE, RBTX4927_SW_RESET_ENABLE_SET); + writeb(RBTX4927_SW_RESET_ENABLE_SET, RBTX4927_SW_RESET_ENABLE); /* wait for enable to be seen */ - while ((reg_rd08(RBTX4927_SW_RESET_ENABLE) & + while ((readb(RBTX4927_SW_RESET_ENABLE) & RBTX4927_SW_RESET_ENABLE_SET) == 0x00); /* do a s/w reset */ - reg_wr08(RBTX4927_SW_RESET_DO, RBTX4927_SW_RESET_DO_SET); + writeb(RBTX4927_SW_RESET_DO_SET, RBTX4927_SW_RESET_DO); /* do something passive while waiting for reset */ local_irq_disable(); - while (1) - asm_wait(); - + wait_forever(); /* no return */ } @@ -706,9 +711,7 @@ void toshiba_rbtx4927_halt(void) { printk(KERN_NOTICE "System Halted\n"); local_irq_disable(); - while (1) { - asm_wait(); - } + wait_forever(); /* no return */ } @@ -720,7 +723,7 @@ void toshiba_rbtx4927_power_off(void) void __init toshiba_rbtx4927_setup(void) { - vu32 cp0_config; + u32 cp0_config; char *argptr; printk("CPU is %s\n", toshiba_name); @@ -747,15 +750,6 @@ void __init toshiba_rbtx4927_setup(void) } #endif - /* setup serial stuff */ - TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_SETUP, - ":Setting up tx4927 sio.\n"); - TX4927_WR(0xff1ff314, 0x00000000); /* h/w flow control off */ - TX4927_WR(0xff1ff414, 0x00000000); /* h/w flow control off */ - - TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_SETUP, - "+\n"); - set_io_port_base(KSEG1 + TBTX4927_ISA_IO_OFFSET); TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_SETUP, ":mips_io_port_base=0x%08lx\n", diff --git a/include/asm-mips/tx4927/toshiba_rbtx4927.h b/include/asm-mips/tx4927/toshiba_rbtx4927.h index a60649569c2c..b188a659ce02 100644 --- a/include/asm-mips/tx4927/toshiba_rbtx4927.h +++ b/include/asm-mips/tx4927/toshiba_rbtx4927.h @@ -28,24 +28,20 @@ #define __ASM_TX4927_TOSHIBA_RBTX4927_H #include -#include #ifdef CONFIG_PCI #include #endif -#define TOSHIBA_RBTX4927_WR08(a,b) do { TX4927_WR08(a,b); wbflush(); } while ( 0 ) - - #ifdef CONFIG_PCI #define TBTX4927_ISA_IO_OFFSET TX4927_PCIIO #else #define TBTX4927_ISA_IO_OFFSET 0 #endif -#define RBTX4927_SW_RESET_DO 0xbc00f000 +#define RBTX4927_SW_RESET_DO (void __iomem *)0xbc00f000UL #define RBTX4927_SW_RESET_DO_SET 0x01 -#define RBTX4927_SW_RESET_ENABLE 0xbc00f002 +#define RBTX4927_SW_RESET_ENABLE (void __iomem *)0xbc00f002UL #define RBTX4927_SW_RESET_ENABLE_SET 0x01 diff --git a/include/asm-mips/tx4927/tx4927.h b/include/asm-mips/tx4927/tx4927.h index 4bd4368e188c..193e80a17c12 100644 --- a/include/asm-mips/tx4927/tx4927.h +++ b/include/asm-mips/tx4927/tx4927.h @@ -27,447 +27,8 @@ #ifndef __ASM_TX4927_TX4927_H #define __ASM_TX4927_TX4927_H -#include #include -/* - This register naming came from the integrated CPU/controller name TX4927 - followed by the device name from table 4.2.2 on page 4-3 and then followed - by the register name from table 4.2.3 on pages 4-4 to 4-8. The manaul - used was "TMPR4927BT Preliminary Rev 0.1 20.Jul.2001". - */ - -#define TX4927_SIO_0_BASE - -/* TX4927 controller */ -#define TX4927_BASE 0xfff1f0000 -#define TX4927_BASE 0xfff1f0000 -#define TX4927_LIMIT 0xfff1fffff - - -/* TX4927 SDRAM controller (64-bit registers) */ -#define TX4927_SDRAMC_BASE 0x8000 -#define TX4927_SDRAMC_SDCCR0 0x8000 -#define TX4927_SDRAMC_SDCCR1 0x8008 -#define TX4927_SDRAMC_SDCCR2 0x8010 -#define TX4927_SDRAMC_SDCCR3 0x8018 -#define TX4927_SDRAMC_SDCTR 0x8040 -#define TX4927_SDRAMC_SDCMD 0x8058 -#define TX4927_SDRAMC_LIMIT 0x8fff - - -/* TX4927 external bus controller (64-bit registers) */ -#define TX4927_EBUSC_BASE 0x9000 -#define TX4927_EBUSC_EBCCR0 0x9000 -#define TX4927_EBUSC_EBCCR1 0x9008 -#define TX4927_EBUSC_EBCCR2 0x9010 -#define TX4927_EBUSC_EBCCR3 0x9018 -#define TX4927_EBUSC_EBCCR4 0x9020 -#define TX4927_EBUSC_EBCCR5 0x9028 -#define TX4927_EBUSC_EBCCR6 0x9030 -#define TX4927_EBUSC_EBCCR7 0x9008 -#define TX4927_EBUSC_LIMIT 0x9fff - - -/* TX4927 SDRRAM Error Check Correction (64-bit registers) */ -#define TX4927_ECC_BASE 0xa000 -#define TX4927_ECC_ECCCR 0xa000 -#define TX4927_ECC_ECCSR 0xa008 -#define TX4927_ECC_LIMIT 0xafff - - -/* TX4927 DMA Controller (64-bit registers) */ -#define TX4927_DMAC_BASE 0xb000 -#define TX4927_DMAC_TBD 0xb000 -#define TX4927_DMAC_LIMIT 0xbfff - - -/* TX4927 PCI Controller (32-bit registers) */ -#define TX4927_PCIC_BASE 0xd000 -#define TX4927_PCIC_TBD 0xb000 -#define TX4927_PCIC_LIMIT 0xdfff - - -/* TX4927 Configuration registers (64-bit registers) */ -#define TX4927_CONFIG_BASE 0xe000 -#define TX4927_CONFIG_CCFG 0xe000 -#define TX4927_CONFIG_CCFG_RESERVED_42_63 BM_63_42 -#define TX4927_CONFIG_CCFG_WDRST BM_41_41 -#define TX4927_CONFIG_CCFG_WDREXEN BM_40_40 -#define TX4927_CONFIG_CCFG_BCFG BM_39_32 -#define TX4927_CONFIG_CCFG_RESERVED_27_31 BM_31_27 -#define TX4927_CONFIG_CCFG_GTOT BM_26_25 -#define TX4927_CONFIG_CCFG_GTOT_4096 BM_26_25 -#define TX4927_CONFIG_CCFG_GTOT_2048 BM_26_26 -#define TX4927_CONFIG_CCFG_GTOT_1024 BM_25_25 -#define TX4927_CONFIG_CCFG_GTOT_0512 (~BM_26_25) -#define TX4927_CONFIG_CCFG_TINTDIS BM_24_24 -#define TX4927_CONFIG_CCFG_PCI66 BM_23_23 -#define TX4927_CONFIG_CCFG_PCIMODE BM_22_22 -#define TX4927_CONFIG_CCFG_RESERVED_20_21 BM_21_20 -#define TX4927_CONFIG_CCFG_DIVMODE BM_19_17 -#define TX4927_CONFIG_CCFG_DIVMODE_2_0 BM_19_19 -#define TX4927_CONFIG_CCFG_DIVMODE_3_0 (BM_19_19|BM_17_17) -#define TX4927_CONFIG_CCFG_DIVMODE_4_0 BM_19_18 -#define TX4927_CONFIG_CCFG_DIVMODE_2_5 BM_19_17 -#define TX4927_CONFIG_CCFG_DIVMODE_8_0 (~BM_19_17) -#define TX4927_CONFIG_CCFG_DIVMODE_12_0 BM_17_17 -#define TX4927_CONFIG_CCFG_DIVMODE_16_0 BM_18_18 -#define TX4927_CONFIG_CCFG_DIVMODE_10_0 BM_18_17 -#define TX4927_CONFIG_CCFG_BEOW BM_16_16 -#define TX4927_CONFIG_CCFG_WR BM_15_15 -#define TX4927_CONFIG_CCFG_TOE BM_14_14 -#define TX4927_CONFIG_CCFG_PCIARB BM_13_13 -#define TX4927_CONFIG_CCFG_PCIDIVMODE BM_12_11 -#define TX4927_CONFIG_CCFG_RESERVED_08_10 BM_10_08 -#define TX4927_CONFIG_CCFG_SYSSP BM_07_06 -#define TX4927_CONFIG_CCFG_RESERVED_03_05 BM_05_03 -#define TX4927_CONFIG_CCFG_ENDIAN BM_02_02 -#define TX4927_CONFIG_CCFG_ARMODE BM_01_01 -#define TX4927_CONFIG_CCFG_ACEHOLD BM_00_00 -#define TX4927_CONFIG_REVID 0xe008 -#define TX4927_CONFIG_REVID_RESERVED_32_63 BM_32_63 -#define TX4927_CONFIG_REVID_PCODE BM_16_31 -#define TX4927_CONFIG_REVID_MJERREV BM_12_15 -#define TX4927_CONFIG_REVID_MINEREV BM_08_11 -#define TX4927_CONFIG_REVID_MJREV BM_04_07 -#define TX4927_CONFIG_REVID_MINREV BM_00_03 -#define TX4927_CONFIG_PCFG 0xe010 -#define TX4927_CONFIG_PCFG_RESERVED_57_63 BM_57_63 -#define TX4927_CONFIG_PCFG_DRVDATA BM_56_56 -#define TX4927_CONFIG_PCFG_DRVCB BM_55_55 -#define TX4927_CONFIG_PCFG_DRVDQM BM_54_54 -#define TX4927_CONFIG_PCFG_DRVADDR BM_53_53 -#define TX4927_CONFIG_PCFG_DRVCKE BM_52_52 -#define TX4927_CONFIG_PCFG_DRVRAS BM_51_51 -#define TX4927_CONFIG_PCFG_DRVCAS BM_50_50 -#define TX4927_CONFIG_PCFG_DRVWE BM_49_49 -#define TX4927_CONFIG_PCFG_DRVCS3 BM_48_48 -#define TX4927_CONFIG_PCFG_DRVCS2 BM_47_47 -#define TX4927_CONFIG_PCFG_DRVCS1 BM_46_4k -#define TX4927_CONFIG_PCFG_DRVCS0 BM_45_45 -#define TX4927_CONFIG_PCFG_DRVCK3 BM_44_44 -#define TX4927_CONFIG_PCFG_DRVCK2 BM_43_43 -#define TX4927_CONFIG_PCFG_DRVCK1 BM_42_42 -#define TX4927_CONFIG_PCFG_DRVCK0 BM_41_41 -#define TX4927_CONFIG_PCFG_DRVCKIN BM_40_40 -#define TX4927_CONFIG_PCFG_RESERVED_33_39 BM_33_39 -#define TX4927_CONFIG_PCFG_BYPASS_PLL BM_32_32 -#define TX4927_CONFIG_PCFG_RESERVED_30_31 BM_30_31 -#define TX4927_CONFIG_PCFG_SDCLKDLY BM_28_29 -#define TX4927_CONFIG_PCFG_SDCLKDLY_DELAY_1 (~BM_28_29) -#define TX4927_CONFIG_PCFG_SDCLKDLY_DELAY_2 BM_28_28 -#define TX4927_CONFIG_PCFG_SDCLKDLY_DELAY_3 BM_29_29 -#define TX4927_CONFIG_PCFG_SDCLKDLY_DELAY_4 BM_28_29 -#define TX4927_CONFIG_PCFG_SYSCLKEN BM_27_27 -#define TX4927_CONFIG_PCFG_SDCLKEN3 BM_26_26 -#define TX4927_CONFIG_PCFG_SDCLKEN2 BM_25_25 -#define TX4927_CONFIG_PCFG_SDCLKEN1 BM_24_24 -#define TX4927_CONFIG_PCFG_SDCLKEN0 BM_23_23 -#define TX4927_CONFIG_PCFG_SDCLKINEN BM_22_22 -#define TX4927_CONFIG_PCFG_PCICLKEN5 BM_21_21 -#define TX4927_CONFIG_PCFG_PCICLKEN4 BM_20_20 -#define TX4927_CONFIG_PCFG_PCICLKEN3 BM_19_19 -#define TX4927_CONFIG_PCFG_PCICLKEN2 BM_18_18 -#define TX4927_CONFIG_PCFG_PCICLKEN1 BM_17_17 -#define TX4927_CONFIG_PCFG_PCICLKEN0 BM_16_16 -#define TX4927_CONFIG_PCFG_RESERVED_10_15 BM_10_15 -#define TX4927_CONFIG_PCFG_SEL2 BM_09_09 -#define TX4927_CONFIG_PCFG_SEL1 BM_08_08 -#define TX4927_CONFIG_PCFG_DMASEL3 BM_06_07 -#define TX4927_CONFIG_PCFG_DMASEL3_DMAREQ3 (~BM_06_07) -#define TX4927_CONFIG_PCFG_DMASEL3_SIO0 BM_06_06 -#define TX4927_CONFIG_PCFG_DMASEL3_ACLC3 BM_07_07 -#define TX4927_CONFIG_PCFG_DMASEL3_ACLC1 BM_06_07 -#define TX4927_CONFIG_PCFG_DMASEL2 BM_06_07 -#define TX4927_CONFIG_PCFG_DMASEL2_SEL2_0_DMAREQ2 (~BM_06_07) -#define TX4927_CONFIG_PCFG_DMASEL2_SEL2_0_SIO0 BM_06_06 -#define TX4927_CONFIG_PCFG_DMASEL2_SEL2_0_RESERVED_10 BM_07_07 -#define TX4927_CONFIG_PCFG_DMASEL2_SEL2_0_RESERVED_11 BM_06_07 -#define TX4927_CONFIG_PCFG_DMASEL2_SEL2_1_ACLC1 (~BM_06_07) -#define TX4927_CONFIG_PCFG_DMASEL2_SEL2_1_SIO0 BM_06_06 -#define TX4927_CONFIG_PCFG_DMASEL2_SEL2_1_ACLC2 BM_07_07 -#define TX4927_CONFIG_PCFG_DMASEL2_SEL2_1_ACLC0 BM_06_07 -#define TX4927_CONFIG_PCFG_DMASEL1 BM_02_03 -#define TX4927_CONFIG_PCFG_DMASEL1_DMAREQ1 (~BM_02_03) -#define TX4927_CONFIG_PCFG_DMASEL1_SIO1 BM_02_02 -#define TX4927_CONFIG_PCFG_DMASEL1_ACLC1 BM_03_03 -#define TX4927_CONFIG_PCFG_DMASEL1_ACLC3 BM_02_03 -#define TX4927_CONFIG_PCFG_DMASEL0 BM_00_01 -#define TX4927_CONFIG_PCFG_DMASEL0_DMAREQ0 (~BM_00_01) -#define TX4927_CONFIG_PCFG_DMASEL0_SIO1 BM_00_00 -#define TX4927_CONFIG_PCFG_DMASEL0_ACLC0 BM_01_01 -#define TX4927_CONFIG_PCFG_DMASEL0_ACLC2 BM_00_01 -#define TX4927_CONFIG_TOEA 0xe018 -#define TX4927_CONFIG_TOEA_RESERVED_36_63 BM_36_63 -#define TX4927_CONFIG_TOEA_TOEA BM_00_35 -#define TX4927_CONFIG_CLKCTR 0xe020 -#define TX4927_CONFIG_CLKCTR_RESERVED_26_63 BM_26_63 -#define TX4927_CONFIG_CLKCTR_ACLCKD BM_25_25 -#define TX4927_CONFIG_CLKCTR_PIOCKD BM_24_24 -#define TX4927_CONFIG_CLKCTR_DMACKD BM_23_23 -#define TX4927_CONFIG_CLKCTR_PCICKD BM_22_22 -#define TX4927_CONFIG_CLKCTR_SET_21 BM_21_21 -#define TX4927_CONFIG_CLKCTR_TM0CKD BM_20_20 -#define TX4927_CONFIG_CLKCTR_TM1CKD BM_19_19 -#define TX4927_CONFIG_CLKCTR_TM2CKD BM_18_18 -#define TX4927_CONFIG_CLKCTR_SIO0CKD BM_17_17 -#define TX4927_CONFIG_CLKCTR_SIO1CKD BM_16_16 -#define TX4927_CONFIG_CLKCTR_RESERVED_10_15 BM_10_15 -#define TX4927_CONFIG_CLKCTR_ACLRST BM_09_09 -#define TX4927_CONFIG_CLKCTR_PIORST BM_08_08 -#define TX4927_CONFIG_CLKCTR_DMARST BM_07_07 -#define TX4927_CONFIG_CLKCTR_PCIRST BM_06_06 -#define TX4927_CONFIG_CLKCTR_RESERVED_05_05 BM_05_05 -#define TX4927_CONFIG_CLKCTR_TM0RST BM_04_04 -#define TX4927_CONFIG_CLKCTR_TM1RST BM_03_03 -#define TX4927_CONFIG_CLKCTR_TM2RST BM_02_02 -#define TX4927_CONFIG_CLKCTR_SIO0RST BM_01_01 -#define TX4927_CONFIG_CLKCTR_SIO1RST BM_00_00 -#define TX4927_CONFIG_GARBC 0xe030 -#define TX4927_CONFIG_GARBC_RESERVED_10_63 BM_10_63 -#define TX4927_CONFIG_GARBC_SET_09 BM_09_09 -#define TX4927_CONFIG_GARBC_ARBMD BM_08_08 -#define TX4927_CONFIG_GARBC_RESERVED_06_07 BM_06_07 -#define TX4927_CONFIG_GARBC_PRIORITY_H1 BM_04_05 -#define TX4927_CONFIG_GARBC_PRIORITY_H1_PCI (~BM_04_05) -#define TX4927_CONFIG_GARBC_PRIORITY_H1_PDMAC BM_04_04 -#define TX4927_CONFIG_GARBC_PRIORITY_H1_DMAC BM_05_05 -#define TX4927_CONFIG_GARBC_PRIORITY_H1_BAD_VALUE BM_04_05 -#define TX4927_CONFIG_GARBC_PRIORITY_H2 BM_02_03 -#define TX4927_CONFIG_GARBC_PRIORITY_H2_PCI (~BM_02_03) -#define TX4927_CONFIG_GARBC_PRIORITY_H2_PDMAC BM_02_02 -#define TX4927_CONFIG_GARBC_PRIORITY_H2_DMAC BM_03_03 -#define TX4927_CONFIG_GARBC_PRIORITY_H2_BAD_VALUE BM_02_03 -#define TX4927_CONFIG_GARBC_PRIORITY_H3 BM_00_01 -#define TX4927_CONFIG_GARBC_PRIORITY_H3_PCI (~BM_00_01) -#define TX4927_CONFIG_GARBC_PRIORITY_H3_PDMAC BM_00_00 -#define TX4927_CONFIG_GARBC_PRIORITY_H3_DMAC BM_01_01 -#define TX4927_CONFIG_GARBC_PRIORITY_H3_BAD_VALUE BM_00_01 -#define TX4927_CONFIG_RAMP 0xe048 -#define TX4927_CONFIG_RAMP_RESERVED_20_63 BM_20_63 -#define TX4927_CONFIG_RAMP_RAMP BM_00_19 -#define TX4927_CONFIG_LIMIT 0xefff - - -/* TX4927 Timer 0 (32-bit registers) */ -#define TX4927_TMR0_BASE 0xf000 -#define TX4927_TMR0_TMTCR0 0xf000 -#define TX4927_TMR0_TMTISR0 0xf004 -#define TX4927_TMR0_TMCPRA0 0xf008 -#define TX4927_TMR0_TMCPRB0 0xf00c -#define TX4927_TMR0_TMITMR0 0xf010 -#define TX4927_TMR0_TMCCDR0 0xf020 -#define TX4927_TMR0_TMPGMR0 0xf030 -#define TX4927_TMR0_TMTRR0 0xf0f0 -#define TX4927_TMR0_LIMIT 0xf0ff - - -/* TX4927 Timer 1 (32-bit registers) */ -#define TX4927_TMR1_BASE 0xf100 -#define TX4927_TMR1_TMTCR1 0xf100 -#define TX4927_TMR1_TMTISR1 0xf104 -#define TX4927_TMR1_TMCPRA1 0xf108 -#define TX4927_TMR1_TMCPRB1 0xf10c -#define TX4927_TMR1_TMITMR1 0xf110 -#define TX4927_TMR1_TMCCDR1 0xf120 -#define TX4927_TMR1_TMPGMR1 0xf130 -#define TX4927_TMR1_TMTRR1 0xf1f0 -#define TX4927_TMR1_LIMIT 0xf1ff - - -/* TX4927 Timer 2 (32-bit registers) */ -#define TX4927_TMR2_BASE 0xf200 -#define TX4927_TMR2_TMTCR2 0xf200 -#define TX4927_TMR2_TMTISR2 0xf204 -#define TX4927_TMR2_TMCPRA2 0xf208 -#define TX4927_TMR2_TMITMR2 0xf210 -#define TX4927_TMR2_TMCCDR2 0xf220 -#define TX4927_TMR2_TMWTMR2 0xf240 -#define TX4927_TMR2_TMTRR2 0xf2f0 -#define TX4927_TMR2_LIMIT 0xf2ff - - -/* TX4927 serial port 0 (32-bit registers) */ -#define TX4927_SIO0_BASE 0xf300 -#define TX4927_SIO0_SILCR0 0xf300 -#define TX4927_SIO0_SILCR0_RESERVED_16_31 BM_16_31 -#define TX4927_SIO0_SILCR0_RWUB BM_15_15 -#define TX4927_SIO0_SILCR0_TWUB BM_14_14 -#define TX4927_SIO0_SILCR0_UODE BM_13_13 -#define TX4927_SIO0_SILCR0_RESERVED_07_12 BM_07_12 -#define TX4927_SIO0_SILCR0_SCS BM_05_06 -#define TX4927_SIO0_SILCR0_SCS_IMBUSCLK_IC (~BM_05_06) -#define TX4927_SIO0_SILCR0_SCS_IMBUSCLK_BRG BM_05_05 -#define TX4927_SIO0_SILCR0_SCS_SCLK_EC BM_06_06 -#define TX4927_SIO0_SILCR0_SCS_SCLK_BRG BM_05_06 -#define TX4927_SIO0_SILCR0_UEPS BM_04_04 -#define TX4927_SIO0_SILCR0_UPEN BM_03_03 -#define TX4927_SIO0_SILCR0_USBL BM_02_02 -#define TX4927_SIO0_SILCR0_UMODE BM_00_01 -#define TX4927_SIO0_SILCR0_UMODE_DATA_8_BIT BM_00_01 -#define TX4927_SIO0_SILCR0_UMODE_DATA_7_BIT (~BM_00_01) -#define TX4927_SIO0_SILCR0_UMODE_DATA_8_BIT_MC BM_01_01 -#define TX4927_SIO0_SILCR0_UMODE_DATA_7_BIT_MC BM_00_01 -#define TX4927_SIO0_SIDICR0 0xf304 -#define TX4927_SIO0_SIDICR0_RESERVED_16_31 BM_16_31 -#define TX4927_SIO0_SIDICR0_TDE BM_15_15 -#define TX4927_SIO0_SIDICR0_RDE BM_14_14 -#define TX4927_SIO0_SIDICR0_TIE BM_13_13 -#define TX4927_SIO0_SIDICR0_RIE BM_12_12 -#define TX4927_SIO0_SIDICR0_SPIE BM_11_11 -#define TX4927_SIO0_SIDICR0_CTSAC BM_09_10 -#define TX4927_SIO0_SIDICR0_CTSAC_NONE (~BM_09_10) -#define TX4927_SIO0_SIDICR0_CTSAC_RISE BM_09_09 -#define TX4927_SIO0_SIDICR0_CTSAC_FALL BM_10_10 -#define TX4927_SIO0_SIDICR0_CTSAC_BOTH BM_09_10 -#define TX4927_SIO0_SIDICR0_RESERVED_06_08 BM_06_08 -#define TX4927_SIO0_SIDICR0_STIE BM_00_05 -#define TX4927_SIO0_SIDICR0_STIE_NONE (~BM_00_05) -#define TX4927_SIO0_SIDICR0_STIE_OERS BM_05_05 -#define TX4927_SIO0_SIDICR0_STIE_CTSAC BM_04_04 -#define TX4927_SIO0_SIDICR0_STIE_RBRKD BM_03_03 -#define TX4927_SIO0_SIDICR0_STIE_TRDY BM_02_02 -#define TX4927_SIO0_SIDICR0_STIE_TXALS BM_01_01 -#define TX4927_SIO0_SIDICR0_STIE_UBRKD BM_00_00 -#define TX4927_SIO0_SIDISR0 0xf308 -#define TX4927_SIO0_SIDISR0_RESERVED_16_31 BM_16_31 -#define TX4927_SIO0_SIDISR0_UBRK BM_15_15 -#define TX4927_SIO0_SIDISR0_UVALID BM_14_14 -#define TX4927_SIO0_SIDISR0_UFER BM_13_13 -#define TX4927_SIO0_SIDISR0_UPER BM_12_12 -#define TX4927_SIO0_SIDISR0_UOER BM_11_11 -#define TX4927_SIO0_SIDISR0_ERI BM_10_10 -#define TX4927_SIO0_SIDISR0_TOUT BM_09_09 -#define TX4927_SIO0_SIDISR0_TDIS BM_08_08 -#define TX4927_SIO0_SIDISR0_RDIS BM_07_07 -#define TX4927_SIO0_SIDISR0_STIS BM_06_06 -#define TX4927_SIO0_SIDISR0_RESERVED_05_05 BM_05_05 -#define TX4927_SIO0_SIDISR0_RFDN BM_00_04 -#define TX4927_SIO0_SISCISR0 0xf30c -#define TX4927_SIO0_SISCISR0_RESERVED_06_31 BM_06_31 -#define TX4927_SIO0_SISCISR0_OERS BM_05_05 -#define TX4927_SIO0_SISCISR0_CTSS BM_04_04 -#define TX4927_SIO0_SISCISR0_RBRKD BM_03_03 -#define TX4927_SIO0_SISCISR0_TRDY BM_02_02 -#define TX4927_SIO0_SISCISR0_TXALS BM_01_01 -#define TX4927_SIO0_SISCISR0_UBRKD BM_00_00 -#define TX4927_SIO0_SIFCR0 0xf310 -#define TX4927_SIO0_SIFCR0_RESERVED_16_31 BM_16_31 -#define TX4927_SIO0_SIFCR0_SWRST BM_16_31 -#define TX4927_SIO0_SIFCR0_RESERVED_09_14 BM_09_14 -#define TX4927_SIO0_SIFCR0_RDIL BM_16_31 -#define TX4927_SIO0_SIFCR0_RDIL_BYTES_1 (~BM_07_08) -#define TX4927_SIO0_SIFCR0_RDIL_BYTES_4 BM_07_07 -#define TX4927_SIO0_SIFCR0_RDIL_BYTES_8 BM_08_08 -#define TX4927_SIO0_SIFCR0_RDIL_BYTES_12 BM_07_08 -#define TX4927_SIO0_SIFCR0_RESERVED_05_06 BM_05_06 -#define TX4927_SIO0_SIFCR0_TDIL BM_03_04 -#define TX4927_SIO0_SIFCR0_TDIL_BYTES_1 (~BM_03_04) -#define TX4927_SIO0_SIFCR0_TDIL_BYTES_4 BM_03_03 -#define TX4927_SIO0_SIFCR0_TDIL_BYTES_8 BM_04_04 -#define TX4927_SIO0_SIFCR0_TDIL_BYTES_0 BM_03_04 -#define TX4927_SIO0_SIFCR0_TFRST BM_02_02 -#define TX4927_SIO0_SIFCR0_RFRST BM_01_01 -#define TX4927_SIO0_SIFCR0_FRSTE BM_00_00 -#define TX4927_SIO0_SIFLCR0 0xf314 -#define TX4927_SIO0_SIFLCR0_RESERVED_13_31 BM_13_31 -#define TX4927_SIO0_SIFLCR0_RCS BM_12_12 -#define TX4927_SIO0_SIFLCR0_TES BM_11_11 -#define TX4927_SIO0_SIFLCR0_RESERVED_10_10 BM_10_10 -#define TX4927_SIO0_SIFLCR0_RTSSC BM_09_09 -#define TX4927_SIO0_SIFLCR0_RSDE BM_08_08 -#define TX4927_SIO0_SIFLCR0_TSDE BM_07_07 -#define TX4927_SIO0_SIFLCR0_RESERVED_05_06 BM_05_06 -#define TX4927_SIO0_SIFLCR0_RTSTL BM_01_04 -#define TX4927_SIO0_SIFLCR0_TBRK BM_00_00 -#define TX4927_SIO0_SIBGR0 0xf318 -#define TX4927_SIO0_SIBGR0_RESERVED_10_31 BM_10_31 -#define TX4927_SIO0_SIBGR0_BCLK BM_08_09 -#define TX4927_SIO0_SIBGR0_BCLK_T0 (~BM_08_09) -#define TX4927_SIO0_SIBGR0_BCLK_T2 BM_08_08 -#define TX4927_SIO0_SIBGR0_BCLK_T4 BM_09_09 -#define TX4927_SIO0_SIBGR0_BCLK_T6 BM_08_09 -#define TX4927_SIO0_SIBGR0_BRD BM_00_07 -#define TX4927_SIO0_SITFIF00 0xf31c -#define TX4927_SIO0_SITFIF00_RESERVED_08_31 BM_08_31 -#define TX4927_SIO0_SITFIF00_TXD BM_00_07 -#define TX4927_SIO0_SIRFIFO0 0xf320 -#define TX4927_SIO0_SIRFIFO0_RESERVED_08_31 BM_08_31 -#define TX4927_SIO0_SIRFIFO0_RXD BM_00_07 -#define TX4927_SIO0_SIRFIFO0 0xf320 -#define TX4927_SIO0_LIMIT 0xf3ff - - -/* TX4927 serial port 1 (32-bit registers) */ -#define TX4927_SIO1_BASE 0xf400 -#define TX4927_SIO1_SILCR1 0xf400 -#define TX4927_SIO1_SIDICR1 0xf404 -#define TX4927_SIO1_SIDISR1 0xf408 -#define TX4927_SIO1_SISCISR1 0xf40c -#define TX4927_SIO1_SIFCR1 0xf410 -#define TX4927_SIO1_SIFLCR1 0xf414 -#define TX4927_SIO1_SIBGR1 0xf418 -#define TX4927_SIO1_SITFIF01 0xf41c -#define TX4927_SIO1_SIRFIFO1 0xf420 -#define TX4927_SIO1_LIMIT 0xf4ff - - -/* TX4927 parallel port (32-bit registers) */ -#define TX4927_PIO_BASE 0xf500 -#define TX4927_PIO_PIOD0 0xf500 -#define TX4927_PIO_PIODI 0xf504 -#define TX4927_PIO_PIODIR 0xf508 -#define TX4927_PIO_PIOOD 0xf50c -#define TX4927_PIO_LIMIT 0xf50f - - -/* TX4927 AC-link controller (32-bit registers) */ -#define TX4927_ACLC_BASE 0xf700 -#define TX4927_ACLC_ACCTLEN 0xf700 -#define TX4927_ACLC_ACCTLDIS 0xf704 -#define TX4927_ACLC_ACREGACC 0xf708 -#define TX4927_ACLC_ACINTSTS 0xf710 -#define TX4927_ACLC_ACINTMSTS 0xf714 -#define TX4927_ACLC_ACINTEN 0xf718 -#define TX4927_ACLC_ACINTDIS 0xf71c -#define TX4927_ACLC_ACSEMAPH 0xf720 -#define TX4927_ACLC_ACGPIDAT 0xf740 -#define TX4927_ACLC_ACGPODAT 0xf744 -#define TX4927_ACLC_ACSLTEN 0xf748 -#define TX4927_ACLC_ACSLTDIS 0xf74c -#define TX4927_ACLC_ACFIFOSTS 0xf750 -#define TX4927_ACLC_ACDMASTS 0xf780 -#define TX4927_ACLC_ACDMASEL 0xf784 -#define TX4927_ACLC_ACAUDODAT 0xf7a0 -#define TX4927_ACLC_ACSURRDAT 0xf7a4 -#define TX4927_ACLC_ACCENTDAT 0xf7a8 -#define TX4927_ACLC_ACLFEDAT 0xf7ac -#define TX4927_ACLC_ACAUDIDAT 0xf7b0 -#define TX4927_ACLC_ACMODODAT 0xf7b8 -#define TX4927_ACLC_ACMODIDAT 0xf7bc -#define TX4927_ACLC_ACREVID 0xf7fc -#define TX4927_ACLC_LIMIT 0xf7ff - - -#define TX4927_REG(x) ((TX4927_BASE)+(x)) - -#define TX4927_RD08( reg ) (*(vu08*)(reg)) -#define TX4927_WR08( reg, val ) ((*(vu08*)(reg))=(val)) - -#define TX4927_RD16( reg ) (*(vu16*)(reg)) -#define TX4927_WR16( reg, val ) ((*(vu16*)(reg))=(val)) - -#define TX4927_RD32( reg ) (*(vu32*)(reg)) -#define TX4927_WR32( reg, val ) ((*(vu32*)(reg))=(val)) - -#define TX4927_RD64( reg ) (*(vu64*)(reg)) -#define TX4927_WR64( reg, val ) ((*(vu64*)(reg))=(val)) - -#define TX4927_RD( reg ) TX4927_RD32( reg ) -#define TX4927_WR( reg, val ) TX4927_WR32( reg, val ) - - #define TX4927_IRQ_CP0_BEG MIPS_CPU_IRQ_BASE #define TX4927_IRQ_CP0_END (MIPS_CPU_IRQ_BASE + 8 - 1) diff --git a/include/asm-mips/tx4927/tx4927_mips.h b/include/asm-mips/tx4927/tx4927_mips.h deleted file mode 100644 index 242ab93bf2e2..000000000000 --- a/include/asm-mips/tx4927/tx4927_mips.h +++ /dev/null @@ -1,4177 +0,0 @@ -/* - * Author: MontaVista Software, Inc. - * source@mvista.com - * - * Copyright 2001-2002 MontaVista Software 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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * 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 __ASM_TX4927_TX4927_MIPS_H -#define __ASM_TX4927_TX4927_MIPS_H - -#ifndef __ASSEMBLY__ - -static inline void asm_wait(void) -{ - __asm__(".set\tmips3\n\t" - "wait\n\t" - ".set\tmips0"); -} - -#define reg_rd08(r) ((u8 )(*((vu8 *)(r)))) -#define reg_rd16(r) ((u16)(*((vu16*)(r)))) -#define reg_rd32(r) ((u32)(*((vu32*)(r)))) -#define reg_rd64(r) ((u64)(*((vu64*)(r)))) - -#define reg_wr08(r,v) ((*((vu8 *)(r)))=((u8 )(v))) -#define reg_wr16(r,v) ((*((vu16*)(r)))=((u16)(v))) -#define reg_wr32(r,v) ((*((vu32*)(r)))=((u32)(v))) -#define reg_wr64(r,v) ((*((vu64*)(r)))=((u64)(v))) - -typedef volatile __signed char vs8; -typedef volatile unsigned char vu8; - -typedef volatile __signed short vs16; -typedef volatile unsigned short vu16; - -typedef volatile __signed int vs32; -typedef volatile unsigned int vu32; - -typedef s8 s08; -typedef vs8 vs08; - -typedef u8 u08; -typedef vu8 vu08; - - -#if (_MIPS_SZLONG == 64) - -typedef volatile __signed__ long vs64; -typedef volatile unsigned long vu64; - -#else - -typedef volatile __signed__ long long vs64; -typedef volatile unsigned long long vu64; - -#endif - - -#define BM_00_00 0x0000000000000001 -#define BM_01_00 0x0000000000000003 -#define BM_00_01 BM_01_00 -#define BM_02_00 0x0000000000000007 -#define BM_00_02 BM_02_00 -#define BM_03_00 0x000000000000000f -#define BM_00_03 BM_03_00 -#define BM_04_00 0x000000000000001f -#define BM_00_04 BM_04_00 -#define BM_05_00 0x000000000000003f -#define BM_00_05 BM_05_00 -#define BM_06_00 0x000000000000007f -#define BM_00_06 BM_06_00 -#define BM_07_00 0x00000000000000ff -#define BM_00_07 BM_07_00 -#define BM_08_00 0x00000000000001ff -#define BM_00_08 BM_08_00 -#define BM_09_00 0x00000000000003ff -#define BM_00_09 BM_09_00 -#define BM_10_00 0x00000000000007ff -#define BM_00_10 BM_10_00 -#define BM_11_00 0x0000000000000fff -#define BM_00_11 BM_11_00 -#define BM_12_00 0x0000000000001fff -#define BM_00_12 BM_12_00 -#define BM_13_00 0x0000000000003fff -#define BM_00_13 BM_13_00 -#define BM_14_00 0x0000000000007fff -#define BM_00_14 BM_14_00 -#define BM_15_00 0x000000000000ffff -#define BM_00_15 BM_15_00 -#define BM_16_00 0x000000000001ffff -#define BM_00_16 BM_16_00 -#define BM_17_00 0x000000000003ffff -#define BM_00_17 BM_17_00 -#define BM_18_00 0x000000000007ffff -#define BM_00_18 BM_18_00 -#define BM_19_00 0x00000000000fffff -#define BM_00_19 BM_19_00 -#define BM_20_00 0x00000000001fffff -#define BM_00_20 BM_20_00 -#define BM_21_00 0x00000000003fffff -#define BM_00_21 BM_21_00 -#define BM_22_00 0x00000000007fffff -#define BM_00_22 BM_22_00 -#define BM_23_00 0x0000000000ffffff -#define BM_00_23 BM_23_00 -#define BM_24_00 0x0000000001ffffff -#define BM_00_24 BM_24_00 -#define BM_25_00 0x0000000003ffffff -#define BM_00_25 BM_25_00 -#define BM_26_00 0x0000000007ffffff -#define BM_00_26 BM_26_00 -#define BM_27_00 0x000000000fffffff -#define BM_00_27 BM_27_00 -#define BM_28_00 0x000000001fffffff -#define BM_00_28 BM_28_00 -#define BM_29_00 0x000000003fffffff -#define BM_00_29 BM_29_00 -#define BM_30_00 0x000000007fffffff -#define BM_00_30 BM_30_00 -#define BM_31_00 0x00000000ffffffff -#define BM_00_31 BM_31_00 -#define BM_32_00 0x00000001ffffffff -#define BM_00_32 BM_32_00 -#define BM_33_00 0x00000003ffffffff -#define BM_00_33 BM_33_00 -#define BM_34_00 0x00000007ffffffff -#define BM_00_34 BM_34_00 -#define BM_35_00 0x0000000fffffffff -#define BM_00_35 BM_35_00 -#define BM_36_00 0x0000001fffffffff -#define BM_00_36 BM_36_00 -#define BM_37_00 0x0000003fffffffff -#define BM_00_37 BM_37_00 -#define BM_38_00 0x0000007fffffffff -#define BM_00_38 BM_38_00 -#define BM_39_00 0x000000ffffffffff -#define BM_00_39 BM_39_00 -#define BM_40_00 0x000001ffffffffff -#define BM_00_40 BM_40_00 -#define BM_41_00 0x000003ffffffffff -#define BM_00_41 BM_41_00 -#define BM_42_00 0x000007ffffffffff -#define BM_00_42 BM_42_00 -#define BM_43_00 0x00000fffffffffff -#define BM_00_43 BM_43_00 -#define BM_44_00 0x00001fffffffffff -#define BM_00_44 BM_44_00 -#define BM_45_00 0x00003fffffffffff -#define BM_00_45 BM_45_00 -#define BM_46_00 0x00007fffffffffff -#define BM_00_46 BM_46_00 -#define BM_47_00 0x0000ffffffffffff -#define BM_00_47 BM_47_00 -#define BM_48_00 0x0001ffffffffffff -#define BM_00_48 BM_48_00 -#define BM_49_00 0x0003ffffffffffff -#define BM_00_49 BM_49_00 -#define BM_50_00 0x0007ffffffffffff -#define BM_00_50 BM_50_00 -#define BM_51_00 0x000fffffffffffff -#define BM_00_51 BM_51_00 -#define BM_52_00 0x001fffffffffffff -#define BM_00_52 BM_52_00 -#define BM_53_00 0x003fffffffffffff -#define BM_00_53 BM_53_00 -#define BM_54_00 0x007fffffffffffff -#define BM_00_54 BM_54_00 -#define BM_55_00 0x00ffffffffffffff -#define BM_00_55 BM_55_00 -#define BM_56_00 0x01ffffffffffffff -#define BM_00_56 BM_56_00 -#define BM_57_00 0x03ffffffffffffff -#define BM_00_57 BM_57_00 -#define BM_58_00 0x07ffffffffffffff -#define BM_00_58 BM_58_00 -#define BM_59_00 0x0fffffffffffffff -#define BM_00_59 BM_59_00 -#define BM_60_00 0x1fffffffffffffff -#define BM_00_60 BM_60_00 -#define BM_61_00 0x3fffffffffffffff -#define BM_00_61 BM_61_00 -#define BM_62_00 0x7fffffffffffffff -#define BM_00_62 BM_62_00 -#define BM_63_00 0xffffffffffffffff -#define BM_00_63 BM_63_00 -#define BM_01_01 0x0000000000000002 -#define BM_02_01 0x0000000000000006 -#define BM_01_02 BM_02_01 -#define BM_03_01 0x000000000000000e -#define BM_01_03 BM_03_01 -#define BM_04_01 0x000000000000001e -#define BM_01_04 BM_04_01 -#define BM_05_01 0x000000000000003e -#define BM_01_05 BM_05_01 -#define BM_06_01 0x000000000000007e -#define BM_01_06 BM_06_01 -#define BM_07_01 0x00000000000000fe -#define BM_01_07 BM_07_01 -#define BM_08_01 0x00000000000001fe -#define BM_01_08 BM_08_01 -#define BM_09_01 0x00000000000003fe -#define BM_01_09 BM_09_01 -#define BM_10_01 0x00000000000007fe -#define BM_01_10 BM_10_01 -#define BM_11_01 0x0000000000000ffe -#define BM_01_11 BM_11_01 -#define BM_12_01 0x0000000000001ffe -#define BM_01_12 BM_12_01 -#define BM_13_01 0x0000000000003ffe -#define BM_01_13 BM_13_01 -#define BM_14_01 0x0000000000007ffe -#define BM_01_14 BM_14_01 -#define BM_15_01 0x000000000000fffe -#define BM_01_15 BM_15_01 -#define BM_16_01 0x000000000001fffe -#define BM_01_16 BM_16_01 -#define BM_17_01 0x000000000003fffe -#define BM_01_17 BM_17_01 -#define BM_18_01 0x000000000007fffe -#define BM_01_18 BM_18_01 -#define BM_19_01 0x00000000000ffffe -#define BM_01_19 BM_19_01 -#define BM_20_01 0x00000000001ffffe -#define BM_01_20 BM_20_01 -#define BM_21_01 0x00000000003ffffe -#define BM_01_21 BM_21_01 -#define BM_22_01 0x00000000007ffffe -#define BM_01_22 BM_22_01 -#define BM_23_01 0x0000000000fffffe -#define BM_01_23 BM_23_01 -#define BM_24_01 0x0000000001fffffe -#define BM_01_24 BM_24_01 -#define BM_25_01 0x0000000003fffffe -#define BM_01_25 BM_25_01 -#define BM_26_01 0x0000000007fffffe -#define BM_01_26 BM_26_01 -#define BM_27_01 0x000000000ffffffe -#define BM_01_27 BM_27_01 -#define BM_28_01 0x000000001ffffffe -#define BM_01_28 BM_28_01 -#define BM_29_01 0x000000003ffffffe -#define BM_01_29 BM_29_01 -#define BM_30_01 0x000000007ffffffe -#define BM_01_30 BM_30_01 -#define BM_31_01 0x00000000fffffffe -#define BM_01_31 BM_31_01 -#define BM_32_01 0x00000001fffffffe -#define BM_01_32 BM_32_01 -#define BM_33_01 0x00000003fffffffe -#define BM_01_33 BM_33_01 -#define BM_34_01 0x00000007fffffffe -#define BM_01_34 BM_34_01 -#define BM_35_01 0x0000000ffffffffe -#define BM_01_35 BM_35_01 -#define BM_36_01 0x0000001ffffffffe -#define BM_01_36 BM_36_01 -#define BM_37_01 0x0000003ffffffffe -#define BM_01_37 BM_37_01 -#define BM_38_01 0x0000007ffffffffe -#define BM_01_38 BM_38_01 -#define BM_39_01 0x000000fffffffffe -#define BM_01_39 BM_39_01 -#define BM_40_01 0x000001fffffffffe -#define BM_01_40 BM_40_01 -#define BM_41_01 0x000003fffffffffe -#define BM_01_41 BM_41_01 -#define BM_42_01 0x000007fffffffffe -#define BM_01_42 BM_42_01 -#define BM_43_01 0x00000ffffffffffe -#define BM_01_43 BM_43_01 -#define BM_44_01 0x00001ffffffffffe -#define BM_01_44 BM_44_01 -#define BM_45_01 0x00003ffffffffffe -#define BM_01_45 BM_45_01 -#define BM_46_01 0x00007ffffffffffe -#define BM_01_46 BM_46_01 -#define BM_47_01 0x0000fffffffffffe -#define BM_01_47 BM_47_01 -#define BM_48_01 0x0001fffffffffffe -#define BM_01_48 BM_48_01 -#define BM_49_01 0x0003fffffffffffe -#define BM_01_49 BM_49_01 -#define BM_50_01 0x0007fffffffffffe -#define BM_01_50 BM_50_01 -#define BM_51_01 0x000ffffffffffffe -#define BM_01_51 BM_51_01 -#define BM_52_01 0x001ffffffffffffe -#define BM_01_52 BM_52_01 -#define BM_53_01 0x003ffffffffffffe -#define BM_01_53 BM_53_01 -#define BM_54_01 0x007ffffffffffffe -#define BM_01_54 BM_54_01 -#define BM_55_01 0x00fffffffffffffe -#define BM_01_55 BM_55_01 -#define BM_56_01 0x01fffffffffffffe -#define BM_01_56 BM_56_01 -#define BM_57_01 0x03fffffffffffffe -#define BM_01_57 BM_57_01 -#define BM_58_01 0x07fffffffffffffe -#define BM_01_58 BM_58_01 -#define BM_59_01 0x0ffffffffffffffe -#define BM_01_59 BM_59_01 -#define BM_60_01 0x1ffffffffffffffe -#define BM_01_60 BM_60_01 -#define BM_61_01 0x3ffffffffffffffe -#define BM_01_61 BM_61_01 -#define BM_62_01 0x7ffffffffffffffe -#define BM_01_62 BM_62_01 -#define BM_63_01 0xfffffffffffffffe -#define BM_01_63 BM_63_01 -#define BM_02_02 0x0000000000000004 -#define BM_03_02 0x000000000000000c -#define BM_02_03 BM_03_02 -#define BM_04_02 0x000000000000001c -#define BM_02_04 BM_04_02 -#define BM_05_02 0x000000000000003c -#define BM_02_05 BM_05_02 -#define BM_06_02 0x000000000000007c -#define BM_02_06 BM_06_02 -#define BM_07_02 0x00000000000000fc -#define BM_02_07 BM_07_02 -#define BM_08_02 0x00000000000001fc -#define BM_02_08 BM_08_02 -#define BM_09_02 0x00000000000003fc -#define BM_02_09 BM_09_02 -#define BM_10_02 0x00000000000007fc -#define BM_02_10 BM_10_02 -#define BM_11_02 0x0000000000000ffc -#define BM_02_11 BM_11_02 -#define BM_12_02 0x0000000000001ffc -#define BM_02_12 BM_12_02 -#define BM_13_02 0x0000000000003ffc -#define BM_02_13 BM_13_02 -#define BM_14_02 0x0000000000007ffc -#define BM_02_14 BM_14_02 -#define BM_15_02 0x000000000000fffc -#define BM_02_15 BM_15_02 -#define BM_16_02 0x000000000001fffc -#define BM_02_16 BM_16_02 -#define BM_17_02 0x000000000003fffc -#define BM_02_17 BM_17_02 -#define BM_18_02 0x000000000007fffc -#define BM_02_18 BM_18_02 -#define BM_19_02 0x00000000000ffffc -#define BM_02_19 BM_19_02 -#define BM_20_02 0x00000000001ffffc -#define BM_02_20 BM_20_02 -#define BM_21_02 0x00000000003ffffc -#define BM_02_21 BM_21_02 -#define BM_22_02 0x00000000007ffffc -#define BM_02_22 BM_22_02 -#define BM_23_02 0x0000000000fffffc -#define BM_02_23 BM_23_02 -#define BM_24_02 0x0000000001fffffc -#define BM_02_24 BM_24_02 -#define BM_25_02 0x0000000003fffffc -#define BM_02_25 BM_25_02 -#define BM_26_02 0x0000000007fffffc -#define BM_02_26 BM_26_02 -#define BM_27_02 0x000000000ffffffc -#define BM_02_27 BM_27_02 -#define BM_28_02 0x000000001ffffffc -#define BM_02_28 BM_28_02 -#define BM_29_02 0x000000003ffffffc -#define BM_02_29 BM_29_02 -#define BM_30_02 0x000000007ffffffc -#define BM_02_30 BM_30_02 -#define BM_31_02 0x00000000fffffffc -#define BM_02_31 BM_31_02 -#define BM_32_02 0x00000001fffffffc -#define BM_02_32 BM_32_02 -#define BM_33_02 0x00000003fffffffc -#define BM_02_33 BM_33_02 -#define BM_34_02 0x00000007fffffffc -#define BM_02_34 BM_34_02 -#define BM_35_02 0x0000000ffffffffc -#define BM_02_35 BM_35_02 -#define BM_36_02 0x0000001ffffffffc -#define BM_02_36 BM_36_02 -#define BM_37_02 0x0000003ffffffffc -#define BM_02_37 BM_37_02 -#define BM_38_02 0x0000007ffffffffc -#define BM_02_38 BM_38_02 -#define BM_39_02 0x000000fffffffffc -#define BM_02_39 BM_39_02 -#define BM_40_02 0x000001fffffffffc -#define BM_02_40 BM_40_02 -#define BM_41_02 0x000003fffffffffc -#define BM_02_41 BM_41_02 -#define BM_42_02 0x000007fffffffffc -#define BM_02_42 BM_42_02 -#define BM_43_02 0x00000ffffffffffc -#define BM_02_43 BM_43_02 -#define BM_44_02 0x00001ffffffffffc -#define BM_02_44 BM_44_02 -#define BM_45_02 0x00003ffffffffffc -#define BM_02_45 BM_45_02 -#define BM_46_02 0x00007ffffffffffc -#define BM_02_46 BM_46_02 -#define BM_47_02 0x0000fffffffffffc -#define BM_02_47 BM_47_02 -#define BM_48_02 0x0001fffffffffffc -#define BM_02_48 BM_48_02 -#define BM_49_02 0x0003fffffffffffc -#define BM_02_49 BM_49_02 -#define BM_50_02 0x0007fffffffffffc -#define BM_02_50 BM_50_02 -#define BM_51_02 0x000ffffffffffffc -#define BM_02_51 BM_51_02 -#define BM_52_02 0x001ffffffffffffc -#define BM_02_52 BM_52_02 -#define BM_53_02 0x003ffffffffffffc -#define BM_02_53 BM_53_02 -#define BM_54_02 0x007ffffffffffffc -#define BM_02_54 BM_54_02 -#define BM_55_02 0x00fffffffffffffc -#define BM_02_55 BM_55_02 -#define BM_56_02 0x01fffffffffffffc -#define BM_02_56 BM_56_02 -#define BM_57_02 0x03fffffffffffffc -#define BM_02_57 BM_57_02 -#define BM_58_02 0x07fffffffffffffc -#define BM_02_58 BM_58_02 -#define BM_59_02 0x0ffffffffffffffc -#define BM_02_59 BM_59_02 -#define BM_60_02 0x1ffffffffffffffc -#define BM_02_60 BM_60_02 -#define BM_61_02 0x3ffffffffffffffc -#define BM_02_61 BM_61_02 -#define BM_62_02 0x7ffffffffffffffc -#define BM_02_62 BM_62_02 -#define BM_63_02 0xfffffffffffffffc -#define BM_02_63 BM_63_02 -#define BM_03_03 0x0000000000000008 -#define BM_04_03 0x0000000000000018 -#define BM_03_04 BM_04_03 -#define BM_05_03 0x0000000000000038 -#define BM_03_05 BM_05_03 -#define BM_06_03 0x0000000000000078 -#define BM_03_06 BM_06_03 -#define BM_07_03 0x00000000000000f8 -#define BM_03_07 BM_07_03 -#define BM_08_03 0x00000000000001f8 -#define BM_03_08 BM_08_03 -#define BM_09_03 0x00000000000003f8 -#define BM_03_09 BM_09_03 -#define BM_10_03 0x00000000000007f8 -#define BM_03_10 BM_10_03 -#define BM_11_03 0x0000000000000ff8 -#define BM_03_11 BM_11_03 -#define BM_12_03 0x0000000000001ff8 -#define BM_03_12 BM_12_03 -#define BM_13_03 0x0000000000003ff8 -#define BM_03_13 BM_13_03 -#define BM_14_03 0x0000000000007ff8 -#define BM_03_14 BM_14_03 -#define BM_15_03 0x000000000000fff8 -#define BM_03_15 BM_15_03 -#define BM_16_03 0x000000000001fff8 -#define BM_03_16 BM_16_03 -#define BM_17_03 0x000000000003fff8 -#define BM_03_17 BM_17_03 -#define BM_18_03 0x000000000007fff8 -#define BM_03_18 BM_18_03 -#define BM_19_03 0x00000000000ffff8 -#define BM_03_19 BM_19_03 -#define BM_20_03 0x00000000001ffff8 -#define BM_03_20 BM_20_03 -#define BM_21_03 0x00000000003ffff8 -#define BM_03_21 BM_21_03 -#define BM_22_03 0x00000000007ffff8 -#define BM_03_22 BM_22_03 -#define BM_23_03 0x0000000000fffff8 -#define BM_03_23 BM_23_03 -#define BM_24_03 0x0000000001fffff8 -#define BM_03_24 BM_24_03 -#define BM_25_03 0x0000000003fffff8 -#define BM_03_25 BM_25_03 -#define BM_26_03 0x0000000007fffff8 -#define BM_03_26 BM_26_03 -#define BM_27_03 0x000000000ffffff8 -#define BM_03_27 BM_27_03 -#define BM_28_03 0x000000001ffffff8 -#define BM_03_28 BM_28_03 -#define BM_29_03 0x000000003ffffff8 -#define BM_03_29 BM_29_03 -#define BM_30_03 0x000000007ffffff8 -#define BM_03_30 BM_30_03 -#define BM_31_03 0x00000000fffffff8 -#define BM_03_31 BM_31_03 -#define BM_32_03 0x00000001fffffff8 -#define BM_03_32 BM_32_03 -#define BM_33_03 0x00000003fffffff8 -#define BM_03_33 BM_33_03 -#define BM_34_03 0x00000007fffffff8 -#define BM_03_34 BM_34_03 -#define BM_35_03 0x0000000ffffffff8 -#define BM_03_35 BM_35_03 -#define BM_36_03 0x0000001ffffffff8 -#define BM_03_36 BM_36_03 -#define BM_37_03 0x0000003ffffffff8 -#define BM_03_37 BM_37_03 -#define BM_38_03 0x0000007ffffffff8 -#define BM_03_38 BM_38_03 -#define BM_39_03 0x000000fffffffff8 -#define BM_03_39 BM_39_03 -#define BM_40_03 0x000001fffffffff8 -#define BM_03_40 BM_40_03 -#define BM_41_03 0x000003fffffffff8 -#define BM_03_41 BM_41_03 -#define BM_42_03 0x000007fffffffff8 -#define BM_03_42 BM_42_03 -#define BM_43_03 0x00000ffffffffff8 -#define BM_03_43 BM_43_03 -#define BM_44_03 0x00001ffffffffff8 -#define BM_03_44 BM_44_03 -#define BM_45_03 0x00003ffffffffff8 -#define BM_03_45 BM_45_03 -#define BM_46_03 0x00007ffffffffff8 -#define BM_03_46 BM_46_03 -#define BM_47_03 0x0000fffffffffff8 -#define BM_03_47 BM_47_03 -#define BM_48_03 0x0001fffffffffff8 -#define BM_03_48 BM_48_03 -#define BM_49_03 0x0003fffffffffff8 -#define BM_03_49 BM_49_03 -#define BM_50_03 0x0007fffffffffff8 -#define BM_03_50 BM_50_03 -#define BM_51_03 0x000ffffffffffff8 -#define BM_03_51 BM_51_03 -#define BM_52_03 0x001ffffffffffff8 -#define BM_03_52 BM_52_03 -#define BM_53_03 0x003ffffffffffff8 -#define BM_03_53 BM_53_03 -#define BM_54_03 0x007ffffffffffff8 -#define BM_03_54 BM_54_03 -#define BM_55_03 0x00fffffffffffff8 -#define BM_03_55 BM_55_03 -#define BM_56_03 0x01fffffffffffff8 -#define BM_03_56 BM_56_03 -#define BM_57_03 0x03fffffffffffff8 -#define BM_03_57 BM_57_03 -#define BM_58_03 0x07fffffffffffff8 -#define BM_03_58 BM_58_03 -#define BM_59_03 0x0ffffffffffffff8 -#define BM_03_59 BM_59_03 -#define BM_60_03 0x1ffffffffffffff8 -#define BM_03_60 BM_60_03 -#define BM_61_03 0x3ffffffffffffff8 -#define BM_03_61 BM_61_03 -#define BM_62_03 0x7ffffffffffffff8 -#define BM_03_62 BM_62_03 -#define BM_63_03 0xfffffffffffffff8 -#define BM_03_63 BM_63_03 -#define BM_04_04 0x0000000000000010 -#define BM_05_04 0x0000000000000030 -#define BM_04_05 BM_05_04 -#define BM_06_04 0x0000000000000070 -#define BM_04_06 BM_06_04 -#define BM_07_04 0x00000000000000f0 -#define BM_04_07 BM_07_04 -#define BM_08_04 0x00000000000001f0 -#define BM_04_08 BM_08_04 -#define BM_09_04 0x00000000000003f0 -#define BM_04_09 BM_09_04 -#define BM_10_04 0x00000000000007f0 -#define BM_04_10 BM_10_04 -#define BM_11_04 0x0000000000000ff0 -#define BM_04_11 BM_11_04 -#define BM_12_04 0x0000000000001ff0 -#define BM_04_12 BM_12_04 -#define BM_13_04 0x0000000000003ff0 -#define BM_04_13 BM_13_04 -#define BM_14_04 0x0000000000007ff0 -#define BM_04_14 BM_14_04 -#define BM_15_04 0x000000000000fff0 -#define BM_04_15 BM_15_04 -#define BM_16_04 0x000000000001fff0 -#define BM_04_16 BM_16_04 -#define BM_17_04 0x000000000003fff0 -#define BM_04_17 BM_17_04 -#define BM_18_04 0x000000000007fff0 -#define BM_04_18 BM_18_04 -#define BM_19_04 0x00000000000ffff0 -#define BM_04_19 BM_19_04 -#define BM_20_04 0x00000000001ffff0 -#define BM_04_20 BM_20_04 -#define BM_21_04 0x00000000003ffff0 -#define BM_04_21 BM_21_04 -#define BM_22_04 0x00000000007ffff0 -#define BM_04_22 BM_22_04 -#define BM_23_04 0x0000000000fffff0 -#define BM_04_23 BM_23_04 -#define BM_24_04 0x0000000001fffff0 -#define BM_04_24 BM_24_04 -#define BM_25_04 0x0000000003fffff0 -#define BM_04_25 BM_25_04 -#define BM_26_04 0x0000000007fffff0 -#define BM_04_26 BM_26_04 -#define BM_27_04 0x000000000ffffff0 -#define BM_04_27 BM_27_04 -#define BM_28_04 0x000000001ffffff0 -#define BM_04_28 BM_28_04 -#define BM_29_04 0x000000003ffffff0 -#define BM_04_29 BM_29_04 -#define BM_30_04 0x000000007ffffff0 -#define BM_04_30 BM_30_04 -#define BM_31_04 0x00000000fffffff0 -#define BM_04_31 BM_31_04 -#define BM_32_04 0x00000001fffffff0 -#define BM_04_32 BM_32_04 -#define BM_33_04 0x00000003fffffff0 -#define BM_04_33 BM_33_04 -#define BM_34_04 0x00000007fffffff0 -#define BM_04_34 BM_34_04 -#define BM_35_04 0x0000000ffffffff0 -#define BM_04_35 BM_35_04 -#define BM_36_04 0x0000001ffffffff0 -#define BM_04_36 BM_36_04 -#define BM_37_04 0x0000003ffffffff0 -#define BM_04_37 BM_37_04 -#define BM_38_04 0x0000007ffffffff0 -#define BM_04_38 BM_38_04 -#define BM_39_04 0x000000fffffffff0 -#define BM_04_39 BM_39_04 -#define BM_40_04 0x000001fffffffff0 -#define BM_04_40 BM_40_04 -#define BM_41_04 0x000003fffffffff0 -#define BM_04_41 BM_41_04 -#define BM_42_04 0x000007fffffffff0 -#define BM_04_42 BM_42_04 -#define BM_43_04 0x00000ffffffffff0 -#define BM_04_43 BM_43_04 -#define BM_44_04 0x00001ffffffffff0 -#define BM_04_44 BM_44_04 -#define BM_45_04 0x00003ffffffffff0 -#define BM_04_45 BM_45_04 -#define BM_46_04 0x00007ffffffffff0 -#define BM_04_46 BM_46_04 -#define BM_47_04 0x0000fffffffffff0 -#define BM_04_47 BM_47_04 -#define BM_48_04 0x0001fffffffffff0 -#define BM_04_48 BM_48_04 -#define BM_49_04 0x0003fffffffffff0 -#define BM_04_49 BM_49_04 -#define BM_50_04 0x0007fffffffffff0 -#define BM_04_50 BM_50_04 -#define BM_51_04 0x000ffffffffffff0 -#define BM_04_51 BM_51_04 -#define BM_52_04 0x001ffffffffffff0 -#define BM_04_52 BM_52_04 -#define BM_53_04 0x003ffffffffffff0 -#define BM_04_53 BM_53_04 -#define BM_54_04 0x007ffffffffffff0 -#define BM_04_54 BM_54_04 -#define BM_55_04 0x00fffffffffffff0 -#define BM_04_55 BM_55_04 -#define BM_56_04 0x01fffffffffffff0 -#define BM_04_56 BM_56_04 -#define BM_57_04 0x03fffffffffffff0 -#define BM_04_57 BM_57_04 -#define BM_58_04 0x07fffffffffffff0 -#define BM_04_58 BM_58_04 -#define BM_59_04 0x0ffffffffffffff0 -#define BM_04_59 BM_59_04 -#define BM_60_04 0x1ffffffffffffff0 -#define BM_04_60 BM_60_04 -#define BM_61_04 0x3ffffffffffffff0 -#define BM_04_61 BM_61_04 -#define BM_62_04 0x7ffffffffffffff0 -#define BM_04_62 BM_62_04 -#define BM_63_04 0xfffffffffffffff0 -#define BM_04_63 BM_63_04 -#define BM_05_05 0x0000000000000020 -#define BM_06_05 0x0000000000000060 -#define BM_05_06 BM_06_05 -#define BM_07_05 0x00000000000000e0 -#define BM_05_07 BM_07_05 -#define BM_08_05 0x00000000000001e0 -#define BM_05_08 BM_08_05 -#define BM_09_05 0x00000000000003e0 -#define BM_05_09 BM_09_05 -#define BM_10_05 0x00000000000007e0 -#define BM_05_10 BM_10_05 -#define BM_11_05 0x0000000000000fe0 -#define BM_05_11 BM_11_05 -#define BM_12_05 0x0000000000001fe0 -#define BM_05_12 BM_12_05 -#define BM_13_05 0x0000000000003fe0 -#define BM_05_13 BM_13_05 -#define BM_14_05 0x0000000000007fe0 -#define BM_05_14 BM_14_05 -#define BM_15_05 0x000000000000ffe0 -#define BM_05_15 BM_15_05 -#define BM_16_05 0x000000000001ffe0 -#define BM_05_16 BM_16_05 -#define BM_17_05 0x000000000003ffe0 -#define BM_05_17 BM_17_05 -#define BM_18_05 0x000000000007ffe0 -#define BM_05_18 BM_18_05 -#define BM_19_05 0x00000000000fffe0 -#define BM_05_19 BM_19_05 -#define BM_20_05 0x00000000001fffe0 -#define BM_05_20 BM_20_05 -#define BM_21_05 0x00000000003fffe0 -#define BM_05_21 BM_21_05 -#define BM_22_05 0x00000000007fffe0 -#define BM_05_22 BM_22_05 -#define BM_23_05 0x0000000000ffffe0 -#define BM_05_23 BM_23_05 -#define BM_24_05 0x0000000001ffffe0 -#define BM_05_24 BM_24_05 -#define BM_25_05 0x0000000003ffffe0 -#define BM_05_25 BM_25_05 -#define BM_26_05 0x0000000007ffffe0 -#define BM_05_26 BM_26_05 -#define BM_27_05 0x000000000fffffe0 -#define BM_05_27 BM_27_05 -#define BM_28_05 0x000000001fffffe0 -#define BM_05_28 BM_28_05 -#define BM_29_05 0x000000003fffffe0 -#define BM_05_29 BM_29_05 -#define BM_30_05 0x000000007fffffe0 -#define BM_05_30 BM_30_05 -#define BM_31_05 0x00000000ffffffe0 -#define BM_05_31 BM_31_05 -#define BM_32_05 0x00000001ffffffe0 -#define BM_05_32 BM_32_05 -#define BM_33_05 0x00000003ffffffe0 -#define BM_05_33 BM_33_05 -#define BM_34_05 0x00000007ffffffe0 -#define BM_05_34 BM_34_05 -#define BM_35_05 0x0000000fffffffe0 -#define BM_05_35 BM_35_05 -#define BM_36_05 0x0000001fffffffe0 -#define BM_05_36 BM_36_05 -#define BM_37_05 0x0000003fffffffe0 -#define BM_05_37 BM_37_05 -#define BM_38_05 0x0000007fffffffe0 -#define BM_05_38 BM_38_05 -#define BM_39_05 0x000000ffffffffe0 -#define BM_05_39 BM_39_05 -#define BM_40_05 0x000001ffffffffe0 -#define BM_05_40 BM_40_05 -#define BM_41_05 0x000003ffffffffe0 -#define BM_05_41 BM_41_05 -#define BM_42_05 0x000007ffffffffe0 -#define BM_05_42 BM_42_05 -#define BM_43_05 0x00000fffffffffe0 -#define BM_05_43 BM_43_05 -#define BM_44_05 0x00001fffffffffe0 -#define BM_05_44 BM_44_05 -#define BM_45_05 0x00003fffffffffe0 -#define BM_05_45 BM_45_05 -#define BM_46_05 0x00007fffffffffe0 -#define BM_05_46 BM_46_05 -#define BM_47_05 0x0000ffffffffffe0 -#define BM_05_47 BM_47_05 -#define BM_48_05 0x0001ffffffffffe0 -#define BM_05_48 BM_48_05 -#define BM_49_05 0x0003ffffffffffe0 -#define BM_05_49 BM_49_05 -#define BM_50_05 0x0007ffffffffffe0 -#define BM_05_50 BM_50_05 -#define BM_51_05 0x000fffffffffffe0 -#define BM_05_51 BM_51_05 -#define BM_52_05 0x001fffffffffffe0 -#define BM_05_52 BM_52_05 -#define BM_53_05 0x003fffffffffffe0 -#define BM_05_53 BM_53_05 -#define BM_54_05 0x007fffffffffffe0 -#define BM_05_54 BM_54_05 -#define BM_55_05 0x00ffffffffffffe0 -#define BM_05_55 BM_55_05 -#define BM_56_05 0x01ffffffffffffe0 -#define BM_05_56 BM_56_05 -#define BM_57_05 0x03ffffffffffffe0 -#define BM_05_57 BM_57_05 -#define BM_58_05 0x07ffffffffffffe0 -#define BM_05_58 BM_58_05 -#define BM_59_05 0x0fffffffffffffe0 -#define BM_05_59 BM_59_05 -#define BM_60_05 0x1fffffffffffffe0 -#define BM_05_60 BM_60_05 -#define BM_61_05 0x3fffffffffffffe0 -#define BM_05_61 BM_61_05 -#define BM_62_05 0x7fffffffffffffe0 -#define BM_05_62 BM_62_05 -#define BM_63_05 0xffffffffffffffe0 -#define BM_05_63 BM_63_05 -#define BM_06_06 0x0000000000000040 -#define BM_07_06 0x00000000000000c0 -#define BM_06_07 BM_07_06 -#define BM_08_06 0x00000000000001c0 -#define BM_06_08 BM_08_06 -#define BM_09_06 0x00000000000003c0 -#define BM_06_09 BM_09_06 -#define BM_10_06 0x00000000000007c0 -#define BM_06_10 BM_10_06 -#define BM_11_06 0x0000000000000fc0 -#define BM_06_11 BM_11_06 -#define BM_12_06 0x0000000000001fc0 -#define BM_06_12 BM_12_06 -#define BM_13_06 0x0000000000003fc0 -#define BM_06_13 BM_13_06 -#define BM_14_06 0x0000000000007fc0 -#define BM_06_14 BM_14_06 -#define BM_15_06 0x000000000000ffc0 -#define BM_06_15 BM_15_06 -#define BM_16_06 0x000000000001ffc0 -#define BM_06_16 BM_16_06 -#define BM_17_06 0x000000000003ffc0 -#define BM_06_17 BM_17_06 -#define BM_18_06 0x000000000007ffc0 -#define BM_06_18 BM_18_06 -#define BM_19_06 0x00000000000fffc0 -#define BM_06_19 BM_19_06 -#define BM_20_06 0x00000000001fffc0 -#define BM_06_20 BM_20_06 -#define BM_21_06 0x00000000003fffc0 -#define BM_06_21 BM_21_06 -#define BM_22_06 0x00000000007fffc0 -#define BM_06_22 BM_22_06 -#define BM_23_06 0x0000000000ffffc0 -#define BM_06_23 BM_23_06 -#define BM_24_06 0x0000000001ffffc0 -#define BM_06_24 BM_24_06 -#define BM_25_06 0x0000000003ffffc0 -#define BM_06_25 BM_25_06 -#define BM_26_06 0x0000000007ffffc0 -#define BM_06_26 BM_26_06 -#define BM_27_06 0x000000000fffffc0 -#define BM_06_27 BM_27_06 -#define BM_28_06 0x000000001fffffc0 -#define BM_06_28 BM_28_06 -#define BM_29_06 0x000000003fffffc0 -#define BM_06_29 BM_29_06 -#define BM_30_06 0x000000007fffffc0 -#define BM_06_30 BM_30_06 -#define BM_31_06 0x00000000ffffffc0 -#define BM_06_31 BM_31_06 -#define BM_32_06 0x00000001ffffffc0 -#define BM_06_32 BM_32_06 -#define BM_33_06 0x00000003ffffffc0 -#define BM_06_33 BM_33_06 -#define BM_34_06 0x00000007ffffffc0 -#define BM_06_34 BM_34_06 -#define BM_35_06 0x0000000fffffffc0 -#define BM_06_35 BM_35_06 -#define BM_36_06 0x0000001fffffffc0 -#define BM_06_36 BM_36_06 -#define BM_37_06 0x0000003fffffffc0 -#define BM_06_37 BM_37_06 -#define BM_38_06 0x0000007fffffffc0 -#define BM_06_38 BM_38_06 -#define BM_39_06 0x000000ffffffffc0 -#define BM_06_39 BM_39_06 -#define BM_40_06 0x000001ffffffffc0 -#define BM_06_40 BM_40_06 -#define BM_41_06 0x000003ffffffffc0 -#define BM_06_41 BM_41_06 -#define BM_42_06 0x000007ffffffffc0 -#define BM_06_42 BM_42_06 -#define BM_43_06 0x00000fffffffffc0 -#define BM_06_43 BM_43_06 -#define BM_44_06 0x00001fffffffffc0 -#define BM_06_44 BM_44_06 -#define BM_45_06 0x00003fffffffffc0 -#define BM_06_45 BM_45_06 -#define BM_46_06 0x00007fffffffffc0 -#define BM_06_46 BM_46_06 -#define BM_47_06 0x0000ffffffffffc0 -#define BM_06_47 BM_47_06 -#define BM_48_06 0x0001ffffffffffc0 -#define BM_06_48 BM_48_06 -#define BM_49_06 0x0003ffffffffffc0 -#define BM_06_49 BM_49_06 -#define BM_50_06 0x0007ffffffffffc0 -#define BM_06_50 BM_50_06 -#define BM_51_06 0x000fffffffffffc0 -#define BM_06_51 BM_51_06 -#define BM_52_06 0x001fffffffffffc0 -#define BM_06_52 BM_52_06 -#define BM_53_06 0x003fffffffffffc0 -#define BM_06_53 BM_53_06 -#define BM_54_06 0x007fffffffffffc0 -#define BM_06_54 BM_54_06 -#define BM_55_06 0x00ffffffffffffc0 -#define BM_06_55 BM_55_06 -#define BM_56_06 0x01ffffffffffffc0 -#define BM_06_56 BM_56_06 -#define BM_57_06 0x03ffffffffffffc0 -#define BM_06_57 BM_57_06 -#define BM_58_06 0x07ffffffffffffc0 -#define BM_06_58 BM_58_06 -#define BM_59_06 0x0fffffffffffffc0 -#define BM_06_59 BM_59_06 -#define BM_60_06 0x1fffffffffffffc0 -#define BM_06_60 BM_60_06 -#define BM_61_06 0x3fffffffffffffc0 -#define BM_06_61 BM_61_06 -#define BM_62_06 0x7fffffffffffffc0 -#define BM_06_62 BM_62_06 -#define BM_63_06 0xffffffffffffffc0 -#define BM_06_63 BM_63_06 -#define BM_07_07 0x0000000000000080 -#define BM_08_07 0x0000000000000180 -#define BM_07_08 BM_08_07 -#define BM_09_07 0x0000000000000380 -#define BM_07_09 BM_09_07 -#define BM_10_07 0x0000000000000780 -#define BM_07_10 BM_10_07 -#define BM_11_07 0x0000000000000f80 -#define BM_07_11 BM_11_07 -#define BM_12_07 0x0000000000001f80 -#define BM_07_12 BM_12_07 -#define BM_13_07 0x0000000000003f80 -#define BM_07_13 BM_13_07 -#define BM_14_07 0x0000000000007f80 -#define BM_07_14 BM_14_07 -#define BM_15_07 0x000000000000ff80 -#define BM_07_15 BM_15_07 -#define BM_16_07 0x000000000001ff80 -#define BM_07_16 BM_16_07 -#define BM_17_07 0x000000000003ff80 -#define BM_07_17 BM_17_07 -#define BM_18_07 0x000000000007ff80 -#define BM_07_18 BM_18_07 -#define BM_19_07 0x00000000000fff80 -#define BM_07_19 BM_19_07 -#define BM_20_07 0x00000000001fff80 -#define BM_07_20 BM_20_07 -#define BM_21_07 0x00000000003fff80 -#define BM_07_21 BM_21_07 -#define BM_22_07 0x00000000007fff80 -#define BM_07_22 BM_22_07 -#define BM_23_07 0x0000000000ffff80 -#define BM_07_23 BM_23_07 -#define BM_24_07 0x0000000001ffff80 -#define BM_07_24 BM_24_07 -#define BM_25_07 0x0000000003ffff80 -#define BM_07_25 BM_25_07 -#define BM_26_07 0x0000000007ffff80 -#define BM_07_26 BM_26_07 -#define BM_27_07 0x000000000fffff80 -#define BM_07_27 BM_27_07 -#define BM_28_07 0x000000001fffff80 -#define BM_07_28 BM_28_07 -#define BM_29_07 0x000000003fffff80 -#define BM_07_29 BM_29_07 -#define BM_30_07 0x000000007fffff80 -#define BM_07_30 BM_30_07 -#define BM_31_07 0x00000000ffffff80 -#define BM_07_31 BM_31_07 -#define BM_32_07 0x00000001ffffff80 -#define BM_07_32 BM_32_07 -#define BM_33_07 0x00000003ffffff80 -#define BM_07_33 BM_33_07 -#define BM_34_07 0x00000007ffffff80 -#define BM_07_34 BM_34_07 -#define BM_35_07 0x0000000fffffff80 -#define BM_07_35 BM_35_07 -#define BM_36_07 0x0000001fffffff80 -#define BM_07_36 BM_36_07 -#define BM_37_07 0x0000003fffffff80 -#define BM_07_37 BM_37_07 -#define BM_38_07 0x0000007fffffff80 -#define BM_07_38 BM_38_07 -#define BM_39_07 0x000000ffffffff80 -#define BM_07_39 BM_39_07 -#define BM_40_07 0x000001ffffffff80 -#define BM_07_40 BM_40_07 -#define BM_41_07 0x000003ffffffff80 -#define BM_07_41 BM_41_07 -#define BM_42_07 0x000007ffffffff80 -#define BM_07_42 BM_42_07 -#define BM_43_07 0x00000fffffffff80 -#define BM_07_43 BM_43_07 -#define BM_44_07 0x00001fffffffff80 -#define BM_07_44 BM_44_07 -#define BM_45_07 0x00003fffffffff80 -#define BM_07_45 BM_45_07 -#define BM_46_07 0x00007fffffffff80 -#define BM_07_46 BM_46_07 -#define BM_47_07 0x0000ffffffffff80 -#define BM_07_47 BM_47_07 -#define BM_48_07 0x0001ffffffffff80 -#define BM_07_48 BM_48_07 -#define BM_49_07 0x0003ffffffffff80 -#define BM_07_49 BM_49_07 -#define BM_50_07 0x0007ffffffffff80 -#define BM_07_50 BM_50_07 -#define BM_51_07 0x000fffffffffff80 -#define BM_07_51 BM_51_07 -#define BM_52_07 0x001fffffffffff80 -#define BM_07_52 BM_52_07 -#define BM_53_07 0x003fffffffffff80 -#define BM_07_53 BM_53_07 -#define BM_54_07 0x007fffffffffff80 -#define BM_07_54 BM_54_07 -#define BM_55_07 0x00ffffffffffff80 -#define BM_07_55 BM_55_07 -#define BM_56_07 0x01ffffffffffff80 -#define BM_07_56 BM_56_07 -#define BM_57_07 0x03ffffffffffff80 -#define BM_07_57 BM_57_07 -#define BM_58_07 0x07ffffffffffff80 -#define BM_07_58 BM_58_07 -#define BM_59_07 0x0fffffffffffff80 -#define BM_07_59 BM_59_07 -#define BM_60_07 0x1fffffffffffff80 -#define BM_07_60 BM_60_07 -#define BM_61_07 0x3fffffffffffff80 -#define BM_07_61 BM_61_07 -#define BM_62_07 0x7fffffffffffff80 -#define BM_07_62 BM_62_07 -#define BM_63_07 0xffffffffffffff80 -#define BM_07_63 BM_63_07 -#define BM_08_08 0x0000000000000100 -#define BM_09_08 0x0000000000000300 -#define BM_08_09 BM_09_08 -#define BM_10_08 0x0000000000000700 -#define BM_08_10 BM_10_08 -#define BM_11_08 0x0000000000000f00 -#define BM_08_11 BM_11_08 -#define BM_12_08 0x0000000000001f00 -#define BM_08_12 BM_12_08 -#define BM_13_08 0x0000000000003f00 -#define BM_08_13 BM_13_08 -#define BM_14_08 0x0000000000007f00 -#define BM_08_14 BM_14_08 -#define BM_15_08 0x000000000000ff00 -#define BM_08_15 BM_15_08 -#define BM_16_08 0x000000000001ff00 -#define BM_08_16 BM_16_08 -#define BM_17_08 0x000000000003ff00 -#define BM_08_17 BM_17_08 -#define BM_18_08 0x000000000007ff00 -#define BM_08_18 BM_18_08 -#define BM_19_08 0x00000000000fff00 -#define BM_08_19 BM_19_08 -#define BM_20_08 0x00000000001fff00 -#define BM_08_20 BM_20_08 -#define BM_21_08 0x00000000003fff00 -#define BM_08_21 BM_21_08 -#define BM_22_08 0x00000000007fff00 -#define BM_08_22 BM_22_08 -#define BM_23_08 0x0000000000ffff00 -#define BM_08_23 BM_23_08 -#define BM_24_08 0x0000000001ffff00 -#define BM_08_24 BM_24_08 -#define BM_25_08 0x0000000003ffff00 -#define BM_08_25 BM_25_08 -#define BM_26_08 0x0000000007ffff00 -#define BM_08_26 BM_26_08 -#define BM_27_08 0x000000000fffff00 -#define BM_08_27 BM_27_08 -#define BM_28_08 0x000000001fffff00 -#define BM_08_28 BM_28_08 -#define BM_29_08 0x000000003fffff00 -#define BM_08_29 BM_29_08 -#define BM_30_08 0x000000007fffff00 -#define BM_08_30 BM_30_08 -#define BM_31_08 0x00000000ffffff00 -#define BM_08_31 BM_31_08 -#define BM_32_08 0x00000001ffffff00 -#define BM_08_32 BM_32_08 -#define BM_33_08 0x00000003ffffff00 -#define BM_08_33 BM_33_08 -#define BM_34_08 0x00000007ffffff00 -#define BM_08_34 BM_34_08 -#define BM_35_08 0x0000000fffffff00 -#define BM_08_35 BM_35_08 -#define BM_36_08 0x0000001fffffff00 -#define BM_08_36 BM_36_08 -#define BM_37_08 0x0000003fffffff00 -#define BM_08_37 BM_37_08 -#define BM_38_08 0x0000007fffffff00 -#define BM_08_38 BM_38_08 -#define BM_39_08 0x000000ffffffff00 -#define BM_08_39 BM_39_08 -#define BM_40_08 0x000001ffffffff00 -#define BM_08_40 BM_40_08 -#define BM_41_08 0x000003ffffffff00 -#define BM_08_41 BM_41_08 -#define BM_42_08 0x000007ffffffff00 -#define BM_08_42 BM_42_08 -#define BM_43_08 0x00000fffffffff00 -#define BM_08_43 BM_43_08 -#define BM_44_08 0x00001fffffffff00 -#define BM_08_44 BM_44_08 -#define BM_45_08 0x00003fffffffff00 -#define BM_08_45 BM_45_08 -#define BM_46_08 0x00007fffffffff00 -#define BM_08_46 BM_46_08 -#define BM_47_08 0x0000ffffffffff00 -#define BM_08_47 BM_47_08 -#define BM_48_08 0x0001ffffffffff00 -#define BM_08_48 BM_48_08 -#define BM_49_08 0x0003ffffffffff00 -#define BM_08_49 BM_49_08 -#define BM_50_08 0x0007ffffffffff00 -#define BM_08_50 BM_50_08 -#define BM_51_08 0x000fffffffffff00 -#define BM_08_51 BM_51_08 -#define BM_52_08 0x001fffffffffff00 -#define BM_08_52 BM_52_08 -#define BM_53_08 0x003fffffffffff00 -#define BM_08_53 BM_53_08 -#define BM_54_08 0x007fffffffffff00 -#define BM_08_54 BM_54_08 -#define BM_55_08 0x00ffffffffffff00 -#define BM_08_55 BM_55_08 -#define BM_56_08 0x01ffffffffffff00 -#define BM_08_56 BM_56_08 -#define BM_57_08 0x03ffffffffffff00 -#define BM_08_57 BM_57_08 -#define BM_58_08 0x07ffffffffffff00 -#define BM_08_58 BM_58_08 -#define BM_59_08 0x0fffffffffffff00 -#define BM_08_59 BM_59_08 -#define BM_60_08 0x1fffffffffffff00 -#define BM_08_60 BM_60_08 -#define BM_61_08 0x3fffffffffffff00 -#define BM_08_61 BM_61_08 -#define BM_62_08 0x7fffffffffffff00 -#define BM_08_62 BM_62_08 -#define BM_63_08 0xffffffffffffff00 -#define BM_08_63 BM_63_08 -#define BM_09_09 0x0000000000000200 -#define BM_10_09 0x0000000000000600 -#define BM_09_10 BM_10_09 -#define BM_11_09 0x0000000000000e00 -#define BM_09_11 BM_11_09 -#define BM_12_09 0x0000000000001e00 -#define BM_09_12 BM_12_09 -#define BM_13_09 0x0000000000003e00 -#define BM_09_13 BM_13_09 -#define BM_14_09 0x0000000000007e00 -#define BM_09_14 BM_14_09 -#define BM_15_09 0x000000000000fe00 -#define BM_09_15 BM_15_09 -#define BM_16_09 0x000000000001fe00 -#define BM_09_16 BM_16_09 -#define BM_17_09 0x000000000003fe00 -#define BM_09_17 BM_17_09 -#define BM_18_09 0x000000000007fe00 -#define BM_09_18 BM_18_09 -#define BM_19_09 0x00000000000ffe00 -#define BM_09_19 BM_19_09 -#define BM_20_09 0x00000000001ffe00 -#define BM_09_20 BM_20_09 -#define BM_21_09 0x00000000003ffe00 -#define BM_09_21 BM_21_09 -#define BM_22_09 0x00000000007ffe00 -#define BM_09_22 BM_22_09 -#define BM_23_09 0x0000000000fffe00 -#define BM_09_23 BM_23_09 -#define BM_24_09 0x0000000001fffe00 -#define BM_09_24 BM_24_09 -#define BM_25_09 0x0000000003fffe00 -#define BM_09_25 BM_25_09 -#define BM_26_09 0x0000000007fffe00 -#define BM_09_26 BM_26_09 -#define BM_27_09 0x000000000ffffe00 -#define BM_09_27 BM_27_09 -#define BM_28_09 0x000000001ffffe00 -#define BM_09_28 BM_28_09 -#define BM_29_09 0x000000003ffffe00 -#define BM_09_29 BM_29_09 -#define BM_30_09 0x000000007ffffe00 -#define BM_09_30 BM_30_09 -#define BM_31_09 0x00000000fffffe00 -#define BM_09_31 BM_31_09 -#define BM_32_09 0x00000001fffffe00 -#define BM_09_32 BM_32_09 -#define BM_33_09 0x00000003fffffe00 -#define BM_09_33 BM_33_09 -#define BM_34_09 0x00000007fffffe00 -#define BM_09_34 BM_34_09 -#define BM_35_09 0x0000000ffffffe00 -#define BM_09_35 BM_35_09 -#define BM_36_09 0x0000001ffffffe00 -#define BM_09_36 BM_36_09 -#define BM_37_09 0x0000003ffffffe00 -#define BM_09_37 BM_37_09 -#define BM_38_09 0x0000007ffffffe00 -#define BM_09_38 BM_38_09 -#define BM_39_09 0x000000fffffffe00 -#define BM_09_39 BM_39_09 -#define BM_40_09 0x000001fffffffe00 -#define BM_09_40 BM_40_09 -#define BM_41_09 0x000003fffffffe00 -#define BM_09_41 BM_41_09 -#define BM_42_09 0x000007fffffffe00 -#define BM_09_42 BM_42_09 -#define BM_43_09 0x00000ffffffffe00 -#define BM_09_43 BM_43_09 -#define BM_44_09 0x00001ffffffffe00 -#define BM_09_44 BM_44_09 -#define BM_45_09 0x00003ffffffffe00 -#define BM_09_45 BM_45_09 -#define BM_46_09 0x00007ffffffffe00 -#define BM_09_46 BM_46_09 -#define BM_47_09 0x0000fffffffffe00 -#define BM_09_47 BM_47_09 -#define BM_48_09 0x0001fffffffffe00 -#define BM_09_48 BM_48_09 -#define BM_49_09 0x0003fffffffffe00 -#define BM_09_49 BM_49_09 -#define BM_50_09 0x0007fffffffffe00 -#define BM_09_50 BM_50_09 -#define BM_51_09 0x000ffffffffffe00 -#define BM_09_51 BM_51_09 -#define BM_52_09 0x001ffffffffffe00 -#define BM_09_52 BM_52_09 -#define BM_53_09 0x003ffffffffffe00 -#define BM_09_53 BM_53_09 -#define BM_54_09 0x007ffffffffffe00 -#define BM_09_54 BM_54_09 -#define BM_55_09 0x00fffffffffffe00 -#define BM_09_55 BM_55_09 -#define BM_56_09 0x01fffffffffffe00 -#define BM_09_56 BM_56_09 -#define BM_57_09 0x03fffffffffffe00 -#define BM_09_57 BM_57_09 -#define BM_58_09 0x07fffffffffffe00 -#define BM_09_58 BM_58_09 -#define BM_59_09 0x0ffffffffffffe00 -#define BM_09_59 BM_59_09 -#define BM_60_09 0x1ffffffffffffe00 -#define BM_09_60 BM_60_09 -#define BM_61_09 0x3ffffffffffffe00 -#define BM_09_61 BM_61_09 -#define BM_62_09 0x7ffffffffffffe00 -#define BM_09_62 BM_62_09 -#define BM_63_09 0xfffffffffffffe00 -#define BM_09_63 BM_63_09 -#define BM_10_10 0x0000000000000400 -#define BM_11_10 0x0000000000000c00 -#define BM_10_11 BM_11_10 -#define BM_12_10 0x0000000000001c00 -#define BM_10_12 BM_12_10 -#define BM_13_10 0x0000000000003c00 -#define BM_10_13 BM_13_10 -#define BM_14_10 0x0000000000007c00 -#define BM_10_14 BM_14_10 -#define BM_15_10 0x000000000000fc00 -#define BM_10_15 BM_15_10 -#define BM_16_10 0x000000000001fc00 -#define BM_10_16 BM_16_10 -#define BM_17_10 0x000000000003fc00 -#define BM_10_17 BM_17_10 -#define BM_18_10 0x000000000007fc00 -#define BM_10_18 BM_18_10 -#define BM_19_10 0x00000000000ffc00 -#define BM_10_19 BM_19_10 -#define BM_20_10 0x00000000001ffc00 -#define BM_10_20 BM_20_10 -#define BM_21_10 0x00000000003ffc00 -#define BM_10_21 BM_21_10 -#define BM_22_10 0x00000000007ffc00 -#define BM_10_22 BM_22_10 -#define BM_23_10 0x0000000000fffc00 -#define BM_10_23 BM_23_10 -#define BM_24_10 0x0000000001fffc00 -#define BM_10_24 BM_24_10 -#define BM_25_10 0x0000000003fffc00 -#define BM_10_25 BM_25_10 -#define BM_26_10 0x0000000007fffc00 -#define BM_10_26 BM_26_10 -#define BM_27_10 0x000000000ffffc00 -#define BM_10_27 BM_27_10 -#define BM_28_10 0x000000001ffffc00 -#define BM_10_28 BM_28_10 -#define BM_29_10 0x000000003ffffc00 -#define BM_10_29 BM_29_10 -#define BM_30_10 0x000000007ffffc00 -#define BM_10_30 BM_30_10 -#define BM_31_10 0x00000000fffffc00 -#define BM_10_31 BM_31_10 -#define BM_32_10 0x00000001fffffc00 -#define BM_10_32 BM_32_10 -#define BM_33_10 0x00000003fffffc00 -#define BM_10_33 BM_33_10 -#define BM_34_10 0x00000007fffffc00 -#define BM_10_34 BM_34_10 -#define BM_35_10 0x0000000ffffffc00 -#define BM_10_35 BM_35_10 -#define BM_36_10 0x0000001ffffffc00 -#define BM_10_36 BM_36_10 -#define BM_37_10 0x0000003ffffffc00 -#define BM_10_37 BM_37_10 -#define BM_38_10 0x0000007ffffffc00 -#define BM_10_38 BM_38_10 -#define BM_39_10 0x000000fffffffc00 -#define BM_10_39 BM_39_10 -#define BM_40_10 0x000001fffffffc00 -#define BM_10_40 BM_40_10 -#define BM_41_10 0x000003fffffffc00 -#define BM_10_41 BM_41_10 -#define BM_42_10 0x000007fffffffc00 -#define BM_10_42 BM_42_10 -#define BM_43_10 0x00000ffffffffc00 -#define BM_10_43 BM_43_10 -#define BM_44_10 0x00001ffffffffc00 -#define BM_10_44 BM_44_10 -#define BM_45_10 0x00003ffffffffc00 -#define BM_10_45 BM_45_10 -#define BM_46_10 0x00007ffffffffc00 -#define BM_10_46 BM_46_10 -#define BM_47_10 0x0000fffffffffc00 -#define BM_10_47 BM_47_10 -#define BM_48_10 0x0001fffffffffc00 -#define BM_10_48 BM_48_10 -#define BM_49_10 0x0003fffffffffc00 -#define BM_10_49 BM_49_10 -#define BM_50_10 0x0007fffffffffc00 -#define BM_10_50 BM_50_10 -#define BM_51_10 0x000ffffffffffc00 -#define BM_10_51 BM_51_10 -#define BM_52_10 0x001ffffffffffc00 -#define BM_10_52 BM_52_10 -#define BM_53_10 0x003ffffffffffc00 -#define BM_10_53 BM_53_10 -#define BM_54_10 0x007ffffffffffc00 -#define BM_10_54 BM_54_10 -#define BM_55_10 0x00fffffffffffc00 -#define BM_10_55 BM_55_10 -#define BM_56_10 0x01fffffffffffc00 -#define BM_10_56 BM_56_10 -#define BM_57_10 0x03fffffffffffc00 -#define BM_10_57 BM_57_10 -#define BM_58_10 0x07fffffffffffc00 -#define BM_10_58 BM_58_10 -#define BM_59_10 0x0ffffffffffffc00 -#define BM_10_59 BM_59_10 -#define BM_60_10 0x1ffffffffffffc00 -#define BM_10_60 BM_60_10 -#define BM_61_10 0x3ffffffffffffc00 -#define BM_10_61 BM_61_10 -#define BM_62_10 0x7ffffffffffffc00 -#define BM_10_62 BM_62_10 -#define BM_63_10 0xfffffffffffffc00 -#define BM_10_63 BM_63_10 -#define BM_11_11 0x0000000000000800 -#define BM_12_11 0x0000000000001800 -#define BM_11_12 BM_12_11 -#define BM_13_11 0x0000000000003800 -#define BM_11_13 BM_13_11 -#define BM_14_11 0x0000000000007800 -#define BM_11_14 BM_14_11 -#define BM_15_11 0x000000000000f800 -#define BM_11_15 BM_15_11 -#define BM_16_11 0x000000000001f800 -#define BM_11_16 BM_16_11 -#define BM_17_11 0x000000000003f800 -#define BM_11_17 BM_17_11 -#define BM_18_11 0x000000000007f800 -#define BM_11_18 BM_18_11 -#define BM_19_11 0x00000000000ff800 -#define BM_11_19 BM_19_11 -#define BM_20_11 0x00000000001ff800 -#define BM_11_20 BM_20_11 -#define BM_21_11 0x00000000003ff800 -#define BM_11_21 BM_21_11 -#define BM_22_11 0x00000000007ff800 -#define BM_11_22 BM_22_11 -#define BM_23_11 0x0000000000fff800 -#define BM_11_23 BM_23_11 -#define BM_24_11 0x0000000001fff800 -#define BM_11_24 BM_24_11 -#define BM_25_11 0x0000000003fff800 -#define BM_11_25 BM_25_11 -#define BM_26_11 0x0000000007fff800 -#define BM_11_26 BM_26_11 -#define BM_27_11 0x000000000ffff800 -#define BM_11_27 BM_27_11 -#define BM_28_11 0x000000001ffff800 -#define BM_11_28 BM_28_11 -#define BM_29_11 0x000000003ffff800 -#define BM_11_29 BM_29_11 -#define BM_30_11 0x000000007ffff800 -#define BM_11_30 BM_30_11 -#define BM_31_11 0x00000000fffff800 -#define BM_11_31 BM_31_11 -#define BM_32_11 0x00000001fffff800 -#define BM_11_32 BM_32_11 -#define BM_33_11 0x00000003fffff800 -#define BM_11_33 BM_33_11 -#define BM_34_11 0x00000007fffff800 -#define BM_11_34 BM_34_11 -#define BM_35_11 0x0000000ffffff800 -#define BM_11_35 BM_35_11 -#define BM_36_11 0x0000001ffffff800 -#define BM_11_36 BM_36_11 -#define BM_37_11 0x0000003ffffff800 -#define BM_11_37 BM_37_11 -#define BM_38_11 0x0000007ffffff800 -#define BM_11_38 BM_38_11 -#define BM_39_11 0x000000fffffff800 -#define BM_11_39 BM_39_11 -#define BM_40_11 0x000001fffffff800 -#define BM_11_40 BM_40_11 -#define BM_41_11 0x000003fffffff800 -#define BM_11_41 BM_41_11 -#define BM_42_11 0x000007fffffff800 -#define BM_11_42 BM_42_11 -#define BM_43_11 0x00000ffffffff800 -#define BM_11_43 BM_43_11 -#define BM_44_11 0x00001ffffffff800 -#define BM_11_44 BM_44_11 -#define BM_45_11 0x00003ffffffff800 -#define BM_11_45 BM_45_11 -#define BM_46_11 0x00007ffffffff800 -#define BM_11_46 BM_46_11 -#define BM_47_11 0x0000fffffffff800 -#define BM_11_47 BM_47_11 -#define BM_48_11 0x0001fffffffff800 -#define BM_11_48 BM_48_11 -#define BM_49_11 0x0003fffffffff800 -#define BM_11_49 BM_49_11 -#define BM_50_11 0x0007fffffffff800 -#define BM_11_50 BM_50_11 -#define BM_51_11 0x000ffffffffff800 -#define BM_11_51 BM_51_11 -#define BM_52_11 0x001ffffffffff800 -#define BM_11_52 BM_52_11 -#define BM_53_11 0x003ffffffffff800 -#define BM_11_53 BM_53_11 -#define BM_54_11 0x007ffffffffff800 -#define BM_11_54 BM_54_11 -#define BM_55_11 0x00fffffffffff800 -#define BM_11_55 BM_55_11 -#define BM_56_11 0x01fffffffffff800 -#define BM_11_56 BM_56_11 -#define BM_57_11 0x03fffffffffff800 -#define BM_11_57 BM_57_11 -#define BM_58_11 0x07fffffffffff800 -#define BM_11_58 BM_58_11 -#define BM_59_11 0x0ffffffffffff800 -#define BM_11_59 BM_59_11 -#define BM_60_11 0x1ffffffffffff800 -#define BM_11_60 BM_60_11 -#define BM_61_11 0x3ffffffffffff800 -#define BM_11_61 BM_61_11 -#define BM_62_11 0x7ffffffffffff800 -#define BM_11_62 BM_62_11 -#define BM_63_11 0xfffffffffffff800 -#define BM_11_63 BM_63_11 -#define BM_12_12 0x0000000000001000 -#define BM_13_12 0x0000000000003000 -#define BM_12_13 BM_13_12 -#define BM_14_12 0x0000000000007000 -#define BM_12_14 BM_14_12 -#define BM_15_12 0x000000000000f000 -#define BM_12_15 BM_15_12 -#define BM_16_12 0x000000000001f000 -#define BM_12_16 BM_16_12 -#define BM_17_12 0x000000000003f000 -#define BM_12_17 BM_17_12 -#define BM_18_12 0x000000000007f000 -#define BM_12_18 BM_18_12 -#define BM_19_12 0x00000000000ff000 -#define BM_12_19 BM_19_12 -#define BM_20_12 0x00000000001ff000 -#define BM_12_20 BM_20_12 -#define BM_21_12 0x00000000003ff000 -#define BM_12_21 BM_21_12 -#define BM_22_12 0x00000000007ff000 -#define BM_12_22 BM_22_12 -#define BM_23_12 0x0000000000fff000 -#define BM_12_23 BM_23_12 -#define BM_24_12 0x0000000001fff000 -#define BM_12_24 BM_24_12 -#define BM_25_12 0x0000000003fff000 -#define BM_12_25 BM_25_12 -#define BM_26_12 0x0000000007fff000 -#define BM_12_26 BM_26_12 -#define BM_27_12 0x000000000ffff000 -#define BM_12_27 BM_27_12 -#define BM_28_12 0x000000001ffff000 -#define BM_12_28 BM_28_12 -#define BM_29_12 0x000000003ffff000 -#define BM_12_29 BM_29_12 -#define BM_30_12 0x000000007ffff000 -#define BM_12_30 BM_30_12 -#define BM_31_12 0x00000000fffff000 -#define BM_12_31 BM_31_12 -#define BM_32_12 0x00000001fffff000 -#define BM_12_32 BM_32_12 -#define BM_33_12 0x00000003fffff000 -#define BM_12_33 BM_33_12 -#define BM_34_12 0x00000007fffff000 -#define BM_12_34 BM_34_12 -#define BM_35_12 0x0000000ffffff000 -#define BM_12_35 BM_35_12 -#define BM_36_12 0x0000001ffffff000 -#define BM_12_36 BM_36_12 -#define BM_37_12 0x0000003ffffff000 -#define BM_12_37 BM_37_12 -#define BM_38_12 0x0000007ffffff000 -#define BM_12_38 BM_38_12 -#define BM_39_12 0x000000fffffff000 -#define BM_12_39 BM_39_12 -#define BM_40_12 0x000001fffffff000 -#define BM_12_40 BM_40_12 -#define BM_41_12 0x000003fffffff000 -#define BM_12_41 BM_41_12 -#define BM_42_12 0x000007fffffff000 -#define BM_12_42 BM_42_12 -#define BM_43_12 0x00000ffffffff000 -#define BM_12_43 BM_43_12 -#define BM_44_12 0x00001ffffffff000 -#define BM_12_44 BM_44_12 -#define BM_45_12 0x00003ffffffff000 -#define BM_12_45 BM_45_12 -#define BM_46_12 0x00007ffffffff000 -#define BM_12_46 BM_46_12 -#define BM_47_12 0x0000fffffffff000 -#define BM_12_47 BM_47_12 -#define BM_48_12 0x0001fffffffff000 -#define BM_12_48 BM_48_12 -#define BM_49_12 0x0003fffffffff000 -#define BM_12_49 BM_49_12 -#define BM_50_12 0x0007fffffffff000 -#define BM_12_50 BM_50_12 -#define BM_51_12 0x000ffffffffff000 -#define BM_12_51 BM_51_12 -#define BM_52_12 0x001ffffffffff000 -#define BM_12_52 BM_52_12 -#define BM_53_12 0x003ffffffffff000 -#define BM_12_53 BM_53_12 -#define BM_54_12 0x007ffffffffff000 -#define BM_12_54 BM_54_12 -#define BM_55_12 0x00fffffffffff000 -#define BM_12_55 BM_55_12 -#define BM_56_12 0x01fffffffffff000 -#define BM_12_56 BM_56_12 -#define BM_57_12 0x03fffffffffff000 -#define BM_12_57 BM_57_12 -#define BM_58_12 0x07fffffffffff000 -#define BM_12_58 BM_58_12 -#define BM_59_12 0x0ffffffffffff000 -#define BM_12_59 BM_59_12 -#define BM_60_12 0x1ffffffffffff000 -#define BM_12_60 BM_60_12 -#define BM_61_12 0x3ffffffffffff000 -#define BM_12_61 BM_61_12 -#define BM_62_12 0x7ffffffffffff000 -#define BM_12_62 BM_62_12 -#define BM_63_12 0xfffffffffffff000 -#define BM_12_63 BM_63_12 -#define BM_13_13 0x0000000000002000 -#define BM_14_13 0x0000000000006000 -#define BM_13_14 BM_14_13 -#define BM_15_13 0x000000000000e000 -#define BM_13_15 BM_15_13 -#define BM_16_13 0x000000000001e000 -#define BM_13_16 BM_16_13 -#define BM_17_13 0x000000000003e000 -#define BM_13_17 BM_17_13 -#define BM_18_13 0x000000000007e000 -#define BM_13_18 BM_18_13 -#define BM_19_13 0x00000000000fe000 -#define BM_13_19 BM_19_13 -#define BM_20_13 0x00000000001fe000 -#define BM_13_20 BM_20_13 -#define BM_21_13 0x00000000003fe000 -#define BM_13_21 BM_21_13 -#define BM_22_13 0x00000000007fe000 -#define BM_13_22 BM_22_13 -#define BM_23_13 0x0000000000ffe000 -#define BM_13_23 BM_23_13 -#define BM_24_13 0x0000000001ffe000 -#define BM_13_24 BM_24_13 -#define BM_25_13 0x0000000003ffe000 -#define BM_13_25 BM_25_13 -#define BM_26_13 0x0000000007ffe000 -#define BM_13_26 BM_26_13 -#define BM_27_13 0x000000000fffe000 -#define BM_13_27 BM_27_13 -#define BM_28_13 0x000000001fffe000 -#define BM_13_28 BM_28_13 -#define BM_29_13 0x000000003fffe000 -#define BM_13_29 BM_29_13 -#define BM_30_13 0x000000007fffe000 -#define BM_13_30 BM_30_13 -#define BM_31_13 0x00000000ffffe000 -#define BM_13_31 BM_31_13 -#define BM_32_13 0x00000001ffffe000 -#define BM_13_32 BM_32_13 -#define BM_33_13 0x00000003ffffe000 -#define BM_13_33 BM_33_13 -#define BM_34_13 0x00000007ffffe000 -#define BM_13_34 BM_34_13 -#define BM_35_13 0x0000000fffffe000 -#define BM_13_35 BM_35_13 -#define BM_36_13 0x0000001fffffe000 -#define BM_13_36 BM_36_13 -#define BM_37_13 0x0000003fffffe000 -#define BM_13_37 BM_37_13 -#define BM_38_13 0x0000007fffffe000 -#define BM_13_38 BM_38_13 -#define BM_39_13 0x000000ffffffe000 -#define BM_13_39 BM_39_13 -#define BM_40_13 0x000001ffffffe000 -#define BM_13_40 BM_40_13 -#define BM_41_13 0x000003ffffffe000 -#define BM_13_41 BM_41_13 -#define BM_42_13 0x000007ffffffe000 -#define BM_13_42 BM_42_13 -#define BM_43_13 0x00000fffffffe000 -#define BM_13_43 BM_43_13 -#define BM_44_13 0x00001fffffffe000 -#define BM_13_44 BM_44_13 -#define BM_45_13 0x00003fffffffe000 -#define BM_13_45 BM_45_13 -#define BM_46_13 0x00007fffffffe000 -#define BM_13_46 BM_46_13 -#define BM_47_13 0x0000ffffffffe000 -#define BM_13_47 BM_47_13 -#define BM_48_13 0x0001ffffffffe000 -#define BM_13_48 BM_48_13 -#define BM_49_13 0x0003ffffffffe000 -#define BM_13_49 BM_49_13 -#define BM_50_13 0x0007ffffffffe000 -#define BM_13_50 BM_50_13 -#define BM_51_13 0x000fffffffffe000 -#define BM_13_51 BM_51_13 -#define BM_52_13 0x001fffffffffe000 -#define BM_13_52 BM_52_13 -#define BM_53_13 0x003fffffffffe000 -#define BM_13_53 BM_53_13 -#define BM_54_13 0x007fffffffffe000 -#define BM_13_54 BM_54_13 -#define BM_55_13 0x00ffffffffffe000 -#define BM_13_55 BM_55_13 -#define BM_56_13 0x01ffffffffffe000 -#define BM_13_56 BM_56_13 -#define BM_57_13 0x03ffffffffffe000 -#define BM_13_57 BM_57_13 -#define BM_58_13 0x07ffffffffffe000 -#define BM_13_58 BM_58_13 -#define BM_59_13 0x0fffffffffffe000 -#define BM_13_59 BM_59_13 -#define BM_60_13 0x1fffffffffffe000 -#define BM_13_60 BM_60_13 -#define BM_61_13 0x3fffffffffffe000 -#define BM_13_61 BM_61_13 -#define BM_62_13 0x7fffffffffffe000 -#define BM_13_62 BM_62_13 -#define BM_63_13 0xffffffffffffe000 -#define BM_13_63 BM_63_13 -#define BM_14_14 0x0000000000004000 -#define BM_15_14 0x000000000000c000 -#define BM_14_15 BM_15_14 -#define BM_16_14 0x000000000001c000 -#define BM_14_16 BM_16_14 -#define BM_17_14 0x000000000003c000 -#define BM_14_17 BM_17_14 -#define BM_18_14 0x000000000007c000 -#define BM_14_18 BM_18_14 -#define BM_19_14 0x00000000000fc000 -#define BM_14_19 BM_19_14 -#define BM_20_14 0x00000000001fc000 -#define BM_14_20 BM_20_14 -#define BM_21_14 0x00000000003fc000 -#define BM_14_21 BM_21_14 -#define BM_22_14 0x00000000007fc000 -#define BM_14_22 BM_22_14 -#define BM_23_14 0x0000000000ffc000 -#define BM_14_23 BM_23_14 -#define BM_24_14 0x0000000001ffc000 -#define BM_14_24 BM_24_14 -#define BM_25_14 0x0000000003ffc000 -#define BM_14_25 BM_25_14 -#define BM_26_14 0x0000000007ffc000 -#define BM_14_26 BM_26_14 -#define BM_27_14 0x000000000fffc000 -#define BM_14_27 BM_27_14 -#define BM_28_14 0x000000001fffc000 -#define BM_14_28 BM_28_14 -#define BM_29_14 0x000000003fffc000 -#define BM_14_29 BM_29_14 -#define BM_30_14 0x000000007fffc000 -#define BM_14_30 BM_30_14 -#define BM_31_14 0x00000000ffffc000 -#define BM_14_31 BM_31_14 -#define BM_32_14 0x00000001ffffc000 -#define BM_14_32 BM_32_14 -#define BM_33_14 0x00000003ffffc000 -#define BM_14_33 BM_33_14 -#define BM_34_14 0x00000007ffffc000 -#define BM_14_34 BM_34_14 -#define BM_35_14 0x0000000fffffc000 -#define BM_14_35 BM_35_14 -#define BM_36_14 0x0000001fffffc000 -#define BM_14_36 BM_36_14 -#define BM_37_14 0x0000003fffffc000 -#define BM_14_37 BM_37_14 -#define BM_38_14 0x0000007fffffc000 -#define BM_14_38 BM_38_14 -#define BM_39_14 0x000000ffffffc000 -#define BM_14_39 BM_39_14 -#define BM_40_14 0x000001ffffffc000 -#define BM_14_40 BM_40_14 -#define BM_41_14 0x000003ffffffc000 -#define BM_14_41 BM_41_14 -#define BM_42_14 0x000007ffffffc000 -#define BM_14_42 BM_42_14 -#define BM_43_14 0x00000fffffffc000 -#define BM_14_43 BM_43_14 -#define BM_44_14 0x00001fffffffc000 -#define BM_14_44 BM_44_14 -#define BM_45_14 0x00003fffffffc000 -#define BM_14_45 BM_45_14 -#define BM_46_14 0x00007fffffffc000 -#define BM_14_46 BM_46_14 -#define BM_47_14 0x0000ffffffffc000 -#define BM_14_47 BM_47_14 -#define BM_48_14 0x0001ffffffffc000 -#define BM_14_48 BM_48_14 -#define BM_49_14 0x0003ffffffffc000 -#define BM_14_49 BM_49_14 -#define BM_50_14 0x0007ffffffffc000 -#define BM_14_50 BM_50_14 -#define BM_51_14 0x000fffffffffc000 -#define BM_14_51 BM_51_14 -#define BM_52_14 0x001fffffffffc000 -#define BM_14_52 BM_52_14 -#define BM_53_14 0x003fffffffffc000 -#define BM_14_53 BM_53_14 -#define BM_54_14 0x007fffffffffc000 -#define BM_14_54 BM_54_14 -#define BM_55_14 0x00ffffffffffc000 -#define BM_14_55 BM_55_14 -#define BM_56_14 0x01ffffffffffc000 -#define BM_14_56 BM_56_14 -#define BM_57_14 0x03ffffffffffc000 -#define BM_14_57 BM_57_14 -#define BM_58_14 0x07ffffffffffc000 -#define BM_14_58 BM_58_14 -#define BM_59_14 0x0fffffffffffc000 -#define BM_14_59 BM_59_14 -#define BM_60_14 0x1fffffffffffc000 -#define BM_14_60 BM_60_14 -#define BM_61_14 0x3fffffffffffc000 -#define BM_14_61 BM_61_14 -#define BM_62_14 0x7fffffffffffc000 -#define BM_14_62 BM_62_14 -#define BM_63_14 0xffffffffffffc000 -#define BM_14_63 BM_63_14 -#define BM_15_15 0x0000000000008000 -#define BM_16_15 0x0000000000018000 -#define BM_15_16 BM_16_15 -#define BM_17_15 0x0000000000038000 -#define BM_15_17 BM_17_15 -#define BM_18_15 0x0000000000078000 -#define BM_15_18 BM_18_15 -#define BM_19_15 0x00000000000f8000 -#define BM_15_19 BM_19_15 -#define BM_20_15 0x00000000001f8000 -#define BM_15_20 BM_20_15 -#define BM_21_15 0x00000000003f8000 -#define BM_15_21 BM_21_15 -#define BM_22_15 0x00000000007f8000 -#define BM_15_22 BM_22_15 -#define BM_23_15 0x0000000000ff8000 -#define BM_15_23 BM_23_15 -#define BM_24_15 0x0000000001ff8000 -#define BM_15_24 BM_24_15 -#define BM_25_15 0x0000000003ff8000 -#define BM_15_25 BM_25_15 -#define BM_26_15 0x0000000007ff8000 -#define BM_15_26 BM_26_15 -#define BM_27_15 0x000000000fff8000 -#define BM_15_27 BM_27_15 -#define BM_28_15 0x000000001fff8000 -#define BM_15_28 BM_28_15 -#define BM_29_15 0x000000003fff8000 -#define BM_15_29 BM_29_15 -#define BM_30_15 0x000000007fff8000 -#define BM_15_30 BM_30_15 -#define BM_31_15 0x00000000ffff8000 -#define BM_15_31 BM_31_15 -#define BM_32_15 0x00000001ffff8000 -#define BM_15_32 BM_32_15 -#define BM_33_15 0x00000003ffff8000 -#define BM_15_33 BM_33_15 -#define BM_34_15 0x00000007ffff8000 -#define BM_15_34 BM_34_15 -#define BM_35_15 0x0000000fffff8000 -#define BM_15_35 BM_35_15 -#define BM_36_15 0x0000001fffff8000 -#define BM_15_36 BM_36_15 -#define BM_37_15 0x0000003fffff8000 -#define BM_15_37 BM_37_15 -#define BM_38_15 0x0000007fffff8000 -#define BM_15_38 BM_38_15 -#define BM_39_15 0x000000ffffff8000 -#define BM_15_39 BM_39_15 -#define BM_40_15 0x000001ffffff8000 -#define BM_15_40 BM_40_15 -#define BM_41_15 0x000003ffffff8000 -#define BM_15_41 BM_41_15 -#define BM_42_15 0x000007ffffff8000 -#define BM_15_42 BM_42_15 -#define BM_43_15 0x00000fffffff8000 -#define BM_15_43 BM_43_15 -#define BM_44_15 0x00001fffffff8000 -#define BM_15_44 BM_44_15 -#define BM_45_15 0x00003fffffff8000 -#define BM_15_45 BM_45_15 -#define BM_46_15 0x00007fffffff8000 -#define BM_15_46 BM_46_15 -#define BM_47_15 0x0000ffffffff8000 -#define BM_15_47 BM_47_15 -#define BM_48_15 0x0001ffffffff8000 -#define BM_15_48 BM_48_15 -#define BM_49_15 0x0003ffffffff8000 -#define BM_15_49 BM_49_15 -#define BM_50_15 0x0007ffffffff8000 -#define BM_15_50 BM_50_15 -#define BM_51_15 0x000fffffffff8000 -#define BM_15_51 BM_51_15 -#define BM_52_15 0x001fffffffff8000 -#define BM_15_52 BM_52_15 -#define BM_53_15 0x003fffffffff8000 -#define BM_15_53 BM_53_15 -#define BM_54_15 0x007fffffffff8000 -#define BM_15_54 BM_54_15 -#define BM_55_15 0x00ffffffffff8000 -#define BM_15_55 BM_55_15 -#define BM_56_15 0x01ffffffffff8000 -#define BM_15_56 BM_56_15 -#define BM_57_15 0x03ffffffffff8000 -#define BM_15_57 BM_57_15 -#define BM_58_15 0x07ffffffffff8000 -#define BM_15_58 BM_58_15 -#define BM_59_15 0x0fffffffffff8000 -#define BM_15_59 BM_59_15 -#define BM_60_15 0x1fffffffffff8000 -#define BM_15_60 BM_60_15 -#define BM_61_15 0x3fffffffffff8000 -#define BM_15_61 BM_61_15 -#define BM_62_15 0x7fffffffffff8000 -#define BM_15_62 BM_62_15 -#define BM_63_15 0xffffffffffff8000 -#define BM_15_63 BM_63_15 -#define BM_16_16 0x0000000000010000 -#define BM_17_16 0x0000000000030000 -#define BM_16_17 BM_17_16 -#define BM_18_16 0x0000000000070000 -#define BM_16_18 BM_18_16 -#define BM_19_16 0x00000000000f0000 -#define BM_16_19 BM_19_16 -#define BM_20_16 0x00000000001f0000 -#define BM_16_20 BM_20_16 -#define BM_21_16 0x00000000003f0000 -#define BM_16_21 BM_21_16 -#define BM_22_16 0x00000000007f0000 -#define BM_16_22 BM_22_16 -#define BM_23_16 0x0000000000ff0000 -#define BM_16_23 BM_23_16 -#define BM_24_16 0x0000000001ff0000 -#define BM_16_24 BM_24_16 -#define BM_25_16 0x0000000003ff0000 -#define BM_16_25 BM_25_16 -#define BM_26_16 0x0000000007ff0000 -#define BM_16_26 BM_26_16 -#define BM_27_16 0x000000000fff0000 -#define BM_16_27 BM_27_16 -#define BM_28_16 0x000000001fff0000 -#define BM_16_28 BM_28_16 -#define BM_29_16 0x000000003fff0000 -#define BM_16_29 BM_29_16 -#define BM_30_16 0x000000007fff0000 -#define BM_16_30 BM_30_16 -#define BM_31_16 0x00000000ffff0000 -#define BM_16_31 BM_31_16 -#define BM_32_16 0x00000001ffff0000 -#define BM_16_32 BM_32_16 -#define BM_33_16 0x00000003ffff0000 -#define BM_16_33 BM_33_16 -#define BM_34_16 0x00000007ffff0000 -#define BM_16_34 BM_34_16 -#define BM_35_16 0x0000000fffff0000 -#define BM_16_35 BM_35_16 -#define BM_36_16 0x0000001fffff0000 -#define BM_16_36 BM_36_16 -#define BM_37_16 0x0000003fffff0000 -#define BM_16_37 BM_37_16 -#define BM_38_16 0x0000007fffff0000 -#define BM_16_38 BM_38_16 -#define BM_39_16 0x000000ffffff0000 -#define BM_16_39 BM_39_16 -#define BM_40_16 0x000001ffffff0000 -#define BM_16_40 BM_40_16 -#define BM_41_16 0x000003ffffff0000 -#define BM_16_41 BM_41_16 -#define BM_42_16 0x000007ffffff0000 -#define BM_16_42 BM_42_16 -#define BM_43_16 0x00000fffffff0000 -#define BM_16_43 BM_43_16 -#define BM_44_16 0x00001fffffff0000 -#define BM_16_44 BM_44_16 -#define BM_45_16 0x00003fffffff0000 -#define BM_16_45 BM_45_16 -#define BM_46_16 0x00007fffffff0000 -#define BM_16_46 BM_46_16 -#define BM_47_16 0x0000ffffffff0000 -#define BM_16_47 BM_47_16 -#define BM_48_16 0x0001ffffffff0000 -#define BM_16_48 BM_48_16 -#define BM_49_16 0x0003ffffffff0000 -#define BM_16_49 BM_49_16 -#define BM_50_16 0x0007ffffffff0000 -#define BM_16_50 BM_50_16 -#define BM_51_16 0x000fffffffff0000 -#define BM_16_51 BM_51_16 -#define BM_52_16 0x001fffffffff0000 -#define BM_16_52 BM_52_16 -#define BM_53_16 0x003fffffffff0000 -#define BM_16_53 BM_53_16 -#define BM_54_16 0x007fffffffff0000 -#define BM_16_54 BM_54_16 -#define BM_55_16 0x00ffffffffff0000 -#define BM_16_55 BM_55_16 -#define BM_56_16 0x01ffffffffff0000 -#define BM_16_56 BM_56_16 -#define BM_57_16 0x03ffffffffff0000 -#define BM_16_57 BM_57_16 -#define BM_58_16 0x07ffffffffff0000 -#define BM_16_58 BM_58_16 -#define BM_59_16 0x0fffffffffff0000 -#define BM_16_59 BM_59_16 -#define BM_60_16 0x1fffffffffff0000 -#define BM_16_60 BM_60_16 -#define BM_61_16 0x3fffffffffff0000 -#define BM_16_61 BM_61_16 -#define BM_62_16 0x7fffffffffff0000 -#define BM_16_62 BM_62_16 -#define BM_63_16 0xffffffffffff0000 -#define BM_16_63 BM_63_16 -#define BM_17_17 0x0000000000020000 -#define BM_18_17 0x0000000000060000 -#define BM_17_18 BM_18_17 -#define BM_19_17 0x00000000000e0000 -#define BM_17_19 BM_19_17 -#define BM_20_17 0x00000000001e0000 -#define BM_17_20 BM_20_17 -#define BM_21_17 0x00000000003e0000 -#define BM_17_21 BM_21_17 -#define BM_22_17 0x00000000007e0000 -#define BM_17_22 BM_22_17 -#define BM_23_17 0x0000000000fe0000 -#define BM_17_23 BM_23_17 -#define BM_24_17 0x0000000001fe0000 -#define BM_17_24 BM_24_17 -#define BM_25_17 0x0000000003fe0000 -#define BM_17_25 BM_25_17 -#define BM_26_17 0x0000000007fe0000 -#define BM_17_26 BM_26_17 -#define BM_27_17 0x000000000ffe0000 -#define BM_17_27 BM_27_17 -#define BM_28_17 0x000000001ffe0000 -#define BM_17_28 BM_28_17 -#define BM_29_17 0x000000003ffe0000 -#define BM_17_29 BM_29_17 -#define BM_30_17 0x000000007ffe0000 -#define BM_17_30 BM_30_17 -#define BM_31_17 0x00000000fffe0000 -#define BM_17_31 BM_31_17 -#define BM_32_17 0x00000001fffe0000 -#define BM_17_32 BM_32_17 -#define BM_33_17 0x00000003fffe0000 -#define BM_17_33 BM_33_17 -#define BM_34_17 0x00000007fffe0000 -#define BM_17_34 BM_34_17 -#define BM_35_17 0x0000000ffffe0000 -#define BM_17_35 BM_35_17 -#define BM_36_17 0x0000001ffffe0000 -#define BM_17_36 BM_36_17 -#define BM_37_17 0x0000003ffffe0000 -#define BM_17_37 BM_37_17 -#define BM_38_17 0x0000007ffffe0000 -#define BM_17_38 BM_38_17 -#define BM_39_17 0x000000fffffe0000 -#define BM_17_39 BM_39_17 -#define BM_40_17 0x000001fffffe0000 -#define BM_17_40 BM_40_17 -#define BM_41_17 0x000003fffffe0000 -#define BM_17_41 BM_41_17 -#define BM_42_17 0x000007fffffe0000 -#define BM_17_42 BM_42_17 -#define BM_43_17 0x00000ffffffe0000 -#define BM_17_43 BM_43_17 -#define BM_44_17 0x00001ffffffe0000 -#define BM_17_44 BM_44_17 -#define BM_45_17 0x00003ffffffe0000 -#define BM_17_45 BM_45_17 -#define BM_46_17 0x00007ffffffe0000 -#define BM_17_46 BM_46_17 -#define BM_47_17 0x0000fffffffe0000 -#define BM_17_47 BM_47_17 -#define BM_48_17 0x0001fffffffe0000 -#define BM_17_48 BM_48_17 -#define BM_49_17 0x0003fffffffe0000 -#define BM_17_49 BM_49_17 -#define BM_50_17 0x0007fffffffe0000 -#define BM_17_50 BM_50_17 -#define BM_51_17 0x000ffffffffe0000 -#define BM_17_51 BM_51_17 -#define BM_52_17 0x001ffffffffe0000 -#define BM_17_52 BM_52_17 -#define BM_53_17 0x003ffffffffe0000 -#define BM_17_53 BM_53_17 -#define BM_54_17 0x007ffffffffe0000 -#define BM_17_54 BM_54_17 -#define BM_55_17 0x00fffffffffe0000 -#define BM_17_55 BM_55_17 -#define BM_56_17 0x01fffffffffe0000 -#define BM_17_56 BM_56_17 -#define BM_57_17 0x03fffffffffe0000 -#define BM_17_57 BM_57_17 -#define BM_58_17 0x07fffffffffe0000 -#define BM_17_58 BM_58_17 -#define BM_59_17 0x0ffffffffffe0000 -#define BM_17_59 BM_59_17 -#define BM_60_17 0x1ffffffffffe0000 -#define BM_17_60 BM_60_17 -#define BM_61_17 0x3ffffffffffe0000 -#define BM_17_61 BM_61_17 -#define BM_62_17 0x7ffffffffffe0000 -#define BM_17_62 BM_62_17 -#define BM_63_17 0xfffffffffffe0000 -#define BM_17_63 BM_63_17 -#define BM_18_18 0x0000000000040000 -#define BM_19_18 0x00000000000c0000 -#define BM_18_19 BM_19_18 -#define BM_20_18 0x00000000001c0000 -#define BM_18_20 BM_20_18 -#define BM_21_18 0x00000000003c0000 -#define BM_18_21 BM_21_18 -#define BM_22_18 0x00000000007c0000 -#define BM_18_22 BM_22_18 -#define BM_23_18 0x0000000000fc0000 -#define BM_18_23 BM_23_18 -#define BM_24_18 0x0000000001fc0000 -#define BM_18_24 BM_24_18 -#define BM_25_18 0x0000000003fc0000 -#define BM_18_25 BM_25_18 -#define BM_26_18 0x0000000007fc0000 -#define BM_18_26 BM_26_18 -#define BM_27_18 0x000000000ffc0000 -#define BM_18_27 BM_27_18 -#define BM_28_18 0x000000001ffc0000 -#define BM_18_28 BM_28_18 -#define BM_29_18 0x000000003ffc0000 -#define BM_18_29 BM_29_18 -#define BM_30_18 0x000000007ffc0000 -#define BM_18_30 BM_30_18 -#define BM_31_18 0x00000000fffc0000 -#define BM_18_31 BM_31_18 -#define BM_32_18 0x00000001fffc0000 -#define BM_18_32 BM_32_18 -#define BM_33_18 0x00000003fffc0000 -#define BM_18_33 BM_33_18 -#define BM_34_18 0x00000007fffc0000 -#define BM_18_34 BM_34_18 -#define BM_35_18 0x0000000ffffc0000 -#define BM_18_35 BM_35_18 -#define BM_36_18 0x0000001ffffc0000 -#define BM_18_36 BM_36_18 -#define BM_37_18 0x0000003ffffc0000 -#define BM_18_37 BM_37_18 -#define BM_38_18 0x0000007ffffc0000 -#define BM_18_38 BM_38_18 -#define BM_39_18 0x000000fffffc0000 -#define BM_18_39 BM_39_18 -#define BM_40_18 0x000001fffffc0000 -#define BM_18_40 BM_40_18 -#define BM_41_18 0x000003fffffc0000 -#define BM_18_41 BM_41_18 -#define BM_42_18 0x000007fffffc0000 -#define BM_18_42 BM_42_18 -#define BM_43_18 0x00000ffffffc0000 -#define BM_18_43 BM_43_18 -#define BM_44_18 0x00001ffffffc0000 -#define BM_18_44 BM_44_18 -#define BM_45_18 0x00003ffffffc0000 -#define BM_18_45 BM_45_18 -#define BM_46_18 0x00007ffffffc0000 -#define BM_18_46 BM_46_18 -#define BM_47_18 0x0000fffffffc0000 -#define BM_18_47 BM_47_18 -#define BM_48_18 0x0001fffffffc0000 -#define BM_18_48 BM_48_18 -#define BM_49_18 0x0003fffffffc0000 -#define BM_18_49 BM_49_18 -#define BM_50_18 0x0007fffffffc0000 -#define BM_18_50 BM_50_18 -#define BM_51_18 0x000ffffffffc0000 -#define BM_18_51 BM_51_18 -#define BM_52_18 0x001ffffffffc0000 -#define BM_18_52 BM_52_18 -#define BM_53_18 0x003ffffffffc0000 -#define BM_18_53 BM_53_18 -#define BM_54_18 0x007ffffffffc0000 -#define BM_18_54 BM_54_18 -#define BM_55_18 0x00fffffffffc0000 -#define BM_18_55 BM_55_18 -#define BM_56_18 0x01fffffffffc0000 -#define BM_18_56 BM_56_18 -#define BM_57_18 0x03fffffffffc0000 -#define BM_18_57 BM_57_18 -#define BM_58_18 0x07fffffffffc0000 -#define BM_18_58 BM_58_18 -#define BM_59_18 0x0ffffffffffc0000 -#define BM_18_59 BM_59_18 -#define BM_60_18 0x1ffffffffffc0000 -#define BM_18_60 BM_60_18 -#define BM_61_18 0x3ffffffffffc0000 -#define BM_18_61 BM_61_18 -#define BM_62_18 0x7ffffffffffc0000 -#define BM_18_62 BM_62_18 -#define BM_63_18 0xfffffffffffc0000 -#define BM_18_63 BM_63_18 -#define BM_19_19 0x0000000000080000 -#define BM_20_19 0x0000000000180000 -#define BM_19_20 BM_20_19 -#define BM_21_19 0x0000000000380000 -#define BM_19_21 BM_21_19 -#define BM_22_19 0x0000000000780000 -#define BM_19_22 BM_22_19 -#define BM_23_19 0x0000000000f80000 -#define BM_19_23 BM_23_19 -#define BM_24_19 0x0000000001f80000 -#define BM_19_24 BM_24_19 -#define BM_25_19 0x0000000003f80000 -#define BM_19_25 BM_25_19 -#define BM_26_19 0x0000000007f80000 -#define BM_19_26 BM_26_19 -#define BM_27_19 0x000000000ff80000 -#define BM_19_27 BM_27_19 -#define BM_28_19 0x000000001ff80000 -#define BM_19_28 BM_28_19 -#define BM_29_19 0x000000003ff80000 -#define BM_19_29 BM_29_19 -#define BM_30_19 0x000000007ff80000 -#define BM_19_30 BM_30_19 -#define BM_31_19 0x00000000fff80000 -#define BM_19_31 BM_31_19 -#define BM_32_19 0x00000001fff80000 -#define BM_19_32 BM_32_19 -#define BM_33_19 0x00000003fff80000 -#define BM_19_33 BM_33_19 -#define BM_34_19 0x00000007fff80000 -#define BM_19_34 BM_34_19 -#define BM_35_19 0x0000000ffff80000 -#define BM_19_35 BM_35_19 -#define BM_36_19 0x0000001ffff80000 -#define BM_19_36 BM_36_19 -#define BM_37_19 0x0000003ffff80000 -#define BM_19_37 BM_37_19 -#define BM_38_19 0x0000007ffff80000 -#define BM_19_38 BM_38_19 -#define BM_39_19 0x000000fffff80000 -#define BM_19_39 BM_39_19 -#define BM_40_19 0x000001fffff80000 -#define BM_19_40 BM_40_19 -#define BM_41_19 0x000003fffff80000 -#define BM_19_41 BM_41_19 -#define BM_42_19 0x000007fffff80000 -#define BM_19_42 BM_42_19 -#define BM_43_19 0x00000ffffff80000 -#define BM_19_43 BM_43_19 -#define BM_44_19 0x00001ffffff80000 -#define BM_19_44 BM_44_19 -#define BM_45_19 0x00003ffffff80000 -#define BM_19_45 BM_45_19 -#define BM_46_19 0x00007ffffff80000 -#define BM_19_46 BM_46_19 -#define BM_47_19 0x0000fffffff80000 -#define BM_19_47 BM_47_19 -#define BM_48_19 0x0001fffffff80000 -#define BM_19_48 BM_48_19 -#define BM_49_19 0x0003fffffff80000 -#define BM_19_49 BM_49_19 -#define BM_50_19 0x0007fffffff80000 -#define BM_19_50 BM_50_19 -#define BM_51_19 0x000ffffffff80000 -#define BM_19_51 BM_51_19 -#define BM_52_19 0x001ffffffff80000 -#define BM_19_52 BM_52_19 -#define BM_53_19 0x003ffffffff80000 -#define BM_19_53 BM_53_19 -#define BM_54_19 0x007ffffffff80000 -#define BM_19_54 BM_54_19 -#define BM_55_19 0x00fffffffff80000 -#define BM_19_55 BM_55_19 -#define BM_56_19 0x01fffffffff80000 -#define BM_19_56 BM_56_19 -#define BM_57_19 0x03fffffffff80000 -#define BM_19_57 BM_57_19 -#define BM_58_19 0x07fffffffff80000 -#define BM_19_58 BM_58_19 -#define BM_59_19 0x0ffffffffff80000 -#define BM_19_59 BM_59_19 -#define BM_60_19 0x1ffffffffff80000 -#define BM_19_60 BM_60_19 -#define BM_61_19 0x3ffffffffff80000 -#define BM_19_61 BM_61_19 -#define BM_62_19 0x7ffffffffff80000 -#define BM_19_62 BM_62_19 -#define BM_63_19 0xfffffffffff80000 -#define BM_19_63 BM_63_19 -#define BM_20_20 0x0000000000100000 -#define BM_21_20 0x0000000000300000 -#define BM_20_21 BM_21_20 -#define BM_22_20 0x0000000000700000 -#define BM_20_22 BM_22_20 -#define BM_23_20 0x0000000000f00000 -#define BM_20_23 BM_23_20 -#define BM_24_20 0x0000000001f00000 -#define BM_20_24 BM_24_20 -#define BM_25_20 0x0000000003f00000 -#define BM_20_25 BM_25_20 -#define BM_26_20 0x0000000007f00000 -#define BM_20_26 BM_26_20 -#define BM_27_20 0x000000000ff00000 -#define BM_20_27 BM_27_20 -#define BM_28_20 0x000000001ff00000 -#define BM_20_28 BM_28_20 -#define BM_29_20 0x000000003ff00000 -#define BM_20_29 BM_29_20 -#define BM_30_20 0x000000007ff00000 -#define BM_20_30 BM_30_20 -#define BM_31_20 0x00000000fff00000 -#define BM_20_31 BM_31_20 -#define BM_32_20 0x00000001fff00000 -#define BM_20_32 BM_32_20 -#define BM_33_20 0x00000003fff00000 -#define BM_20_33 BM_33_20 -#define BM_34_20 0x00000007fff00000 -#define BM_20_34 BM_34_20 -#define BM_35_20 0x0000000ffff00000 -#define BM_20_35 BM_35_20 -#define BM_36_20 0x0000001ffff00000 -#define BM_20_36 BM_36_20 -#define BM_37_20 0x0000003ffff00000 -#define BM_20_37 BM_37_20 -#define BM_38_20 0x0000007ffff00000 -#define BM_20_38 BM_38_20 -#define BM_39_20 0x000000fffff00000 -#define BM_20_39 BM_39_20 -#define BM_40_20 0x000001fffff00000 -#define BM_20_40 BM_40_20 -#define BM_41_20 0x000003fffff00000 -#define BM_20_41 BM_41_20 -#define BM_42_20 0x000007fffff00000 -#define BM_20_42 BM_42_20 -#define BM_43_20 0x00000ffffff00000 -#define BM_20_43 BM_43_20 -#define BM_44_20 0x00001ffffff00000 -#define BM_20_44 BM_44_20 -#define BM_45_20 0x00003ffffff00000 -#define BM_20_45 BM_45_20 -#define BM_46_20 0x00007ffffff00000 -#define BM_20_46 BM_46_20 -#define BM_47_20 0x0000fffffff00000 -#define BM_20_47 BM_47_20 -#define BM_48_20 0x0001fffffff00000 -#define BM_20_48 BM_48_20 -#define BM_49_20 0x0003fffffff00000 -#define BM_20_49 BM_49_20 -#define BM_50_20 0x0007fffffff00000 -#define BM_20_50 BM_50_20 -#define BM_51_20 0x000ffffffff00000 -#define BM_20_51 BM_51_20 -#define BM_52_20 0x001ffffffff00000 -#define BM_20_52 BM_52_20 -#define BM_53_20 0x003ffffffff00000 -#define BM_20_53 BM_53_20 -#define BM_54_20 0x007ffffffff00000 -#define BM_20_54 BM_54_20 -#define BM_55_20 0x00fffffffff00000 -#define BM_20_55 BM_55_20 -#define BM_56_20 0x01fffffffff00000 -#define BM_20_56 BM_56_20 -#define BM_57_20 0x03fffffffff00000 -#define BM_20_57 BM_57_20 -#define BM_58_20 0x07fffffffff00000 -#define BM_20_58 BM_58_20 -#define BM_59_20 0x0ffffffffff00000 -#define BM_20_59 BM_59_20 -#define BM_60_20 0x1ffffffffff00000 -#define BM_20_60 BM_60_20 -#define BM_61_20 0x3ffffffffff00000 -#define BM_20_61 BM_61_20 -#define BM_62_20 0x7ffffffffff00000 -#define BM_20_62 BM_62_20 -#define BM_63_20 0xfffffffffff00000 -#define BM_20_63 BM_63_20 -#define BM_21_21 0x0000000000200000 -#define BM_22_21 0x0000000000600000 -#define BM_21_22 BM_22_21 -#define BM_23_21 0x0000000000e00000 -#define BM_21_23 BM_23_21 -#define BM_24_21 0x0000000001e00000 -#define BM_21_24 BM_24_21 -#define BM_25_21 0x0000000003e00000 -#define BM_21_25 BM_25_21 -#define BM_26_21 0x0000000007e00000 -#define BM_21_26 BM_26_21 -#define BM_27_21 0x000000000fe00000 -#define BM_21_27 BM_27_21 -#define BM_28_21 0x000000001fe00000 -#define BM_21_28 BM_28_21 -#define BM_29_21 0x000000003fe00000 -#define BM_21_29 BM_29_21 -#define BM_30_21 0x000000007fe00000 -#define BM_21_30 BM_30_21 -#define BM_31_21 0x00000000ffe00000 -#define BM_21_31 BM_31_21 -#define BM_32_21 0x00000001ffe00000 -#define BM_21_32 BM_32_21 -#define BM_33_21 0x00000003ffe00000 -#define BM_21_33 BM_33_21 -#define BM_34_21 0x00000007ffe00000 -#define BM_21_34 BM_34_21 -#define BM_35_21 0x0000000fffe00000 -#define BM_21_35 BM_35_21 -#define BM_36_21 0x0000001fffe00000 -#define BM_21_36 BM_36_21 -#define BM_37_21 0x0000003fffe00000 -#define BM_21_37 BM_37_21 -#define BM_38_21 0x0000007fffe00000 -#define BM_21_38 BM_38_21 -#define BM_39_21 0x000000ffffe00000 -#define BM_21_39 BM_39_21 -#define BM_40_21 0x000001ffffe00000 -#define BM_21_40 BM_40_21 -#define BM_41_21 0x000003ffffe00000 -#define BM_21_41 BM_41_21 -#define BM_42_21 0x000007ffffe00000 -#define BM_21_42 BM_42_21 -#define BM_43_21 0x00000fffffe00000 -#define BM_21_43 BM_43_21 -#define BM_44_21 0x00001fffffe00000 -#define BM_21_44 BM_44_21 -#define BM_45_21 0x00003fffffe00000 -#define BM_21_45 BM_45_21 -#define BM_46_21 0x00007fffffe00000 -#define BM_21_46 BM_46_21 -#define BM_47_21 0x0000ffffffe00000 -#define BM_21_47 BM_47_21 -#define BM_48_21 0x0001ffffffe00000 -#define BM_21_48 BM_48_21 -#define BM_49_21 0x0003ffffffe00000 -#define BM_21_49 BM_49_21 -#define BM_50_21 0x0007ffffffe00000 -#define BM_21_50 BM_50_21 -#define BM_51_21 0x000fffffffe00000 -#define BM_21_51 BM_51_21 -#define BM_52_21 0x001fffffffe00000 -#define BM_21_52 BM_52_21 -#define BM_53_21 0x003fffffffe00000 -#define BM_21_53 BM_53_21 -#define BM_54_21 0x007fffffffe00000 -#define BM_21_54 BM_54_21 -#define BM_55_21 0x00ffffffffe00000 -#define BM_21_55 BM_55_21 -#define BM_56_21 0x01ffffffffe00000 -#define BM_21_56 BM_56_21 -#define BM_57_21 0x03ffffffffe00000 -#define BM_21_57 BM_57_21 -#define BM_58_21 0x07ffffffffe00000 -#define BM_21_58 BM_58_21 -#define BM_59_21 0x0fffffffffe00000 -#define BM_21_59 BM_59_21 -#define BM_60_21 0x1fffffffffe00000 -#define BM_21_60 BM_60_21 -#define BM_61_21 0x3fffffffffe00000 -#define BM_21_61 BM_61_21 -#define BM_62_21 0x7fffffffffe00000 -#define BM_21_62 BM_62_21 -#define BM_63_21 0xffffffffffe00000 -#define BM_21_63 BM_63_21 -#define BM_22_22 0x0000000000400000 -#define BM_23_22 0x0000000000c00000 -#define BM_22_23 BM_23_22 -#define BM_24_22 0x0000000001c00000 -#define BM_22_24 BM_24_22 -#define BM_25_22 0x0000000003c00000 -#define BM_22_25 BM_25_22 -#define BM_26_22 0x0000000007c00000 -#define BM_22_26 BM_26_22 -#define BM_27_22 0x000000000fc00000 -#define BM_22_27 BM_27_22 -#define BM_28_22 0x000000001fc00000 -#define BM_22_28 BM_28_22 -#define BM_29_22 0x000000003fc00000 -#define BM_22_29 BM_29_22 -#define BM_30_22 0x000000007fc00000 -#define BM_22_30 BM_30_22 -#define BM_31_22 0x00000000ffc00000 -#define BM_22_31 BM_31_22 -#define BM_32_22 0x00000001ffc00000 -#define BM_22_32 BM_32_22 -#define BM_33_22 0x00000003ffc00000 -#define BM_22_33 BM_33_22 -#define BM_34_22 0x00000007ffc00000 -#define BM_22_34 BM_34_22 -#define BM_35_22 0x0000000fffc00000 -#define BM_22_35 BM_35_22 -#define BM_36_22 0x0000001fffc00000 -#define BM_22_36 BM_36_22 -#define BM_37_22 0x0000003fffc00000 -#define BM_22_37 BM_37_22 -#define BM_38_22 0x0000007fffc00000 -#define BM_22_38 BM_38_22 -#define BM_39_22 0x000000ffffc00000 -#define BM_22_39 BM_39_22 -#define BM_40_22 0x000001ffffc00000 -#define BM_22_40 BM_40_22 -#define BM_41_22 0x000003ffffc00000 -#define BM_22_41 BM_41_22 -#define BM_42_22 0x000007ffffc00000 -#define BM_22_42 BM_42_22 -#define BM_43_22 0x00000fffffc00000 -#define BM_22_43 BM_43_22 -#define BM_44_22 0x00001fffffc00000 -#define BM_22_44 BM_44_22 -#define BM_45_22 0x00003fffffc00000 -#define BM_22_45 BM_45_22 -#define BM_46_22 0x00007fffffc00000 -#define BM_22_46 BM_46_22 -#define BM_47_22 0x0000ffffffc00000 -#define BM_22_47 BM_47_22 -#define BM_48_22 0x0001ffffffc00000 -#define BM_22_48 BM_48_22 -#define BM_49_22 0x0003ffffffc00000 -#define BM_22_49 BM_49_22 -#define BM_50_22 0x0007ffffffc00000 -#define BM_22_50 BM_50_22 -#define BM_51_22 0x000fffffffc00000 -#define BM_22_51 BM_51_22 -#define BM_52_22 0x001fffffffc00000 -#define BM_22_52 BM_52_22 -#define BM_53_22 0x003fffffffc00000 -#define BM_22_53 BM_53_22 -#define BM_54_22 0x007fffffffc00000 -#define BM_22_54 BM_54_22 -#define BM_55_22 0x00ffffffffc00000 -#define BM_22_55 BM_55_22 -#define BM_56_22 0x01ffffffffc00000 -#define BM_22_56 BM_56_22 -#define BM_57_22 0x03ffffffffc00000 -#define BM_22_57 BM_57_22 -#define BM_58_22 0x07ffffffffc00000 -#define BM_22_58 BM_58_22 -#define BM_59_22 0x0fffffffffc00000 -#define BM_22_59 BM_59_22 -#define BM_60_22 0x1fffffffffc00000 -#define BM_22_60 BM_60_22 -#define BM_61_22 0x3fffffffffc00000 -#define BM_22_61 BM_61_22 -#define BM_62_22 0x7fffffffffc00000 -#define BM_22_62 BM_62_22 -#define BM_63_22 0xffffffffffc00000 -#define BM_22_63 BM_63_22 -#define BM_23_23 0x0000000000800000 -#define BM_24_23 0x0000000001800000 -#define BM_23_24 BM_24_23 -#define BM_25_23 0x0000000003800000 -#define BM_23_25 BM_25_23 -#define BM_26_23 0x0000000007800000 -#define BM_23_26 BM_26_23 -#define BM_27_23 0x000000000f800000 -#define BM_23_27 BM_27_23 -#define BM_28_23 0x000000001f800000 -#define BM_23_28 BM_28_23 -#define BM_29_23 0x000000003f800000 -#define BM_23_29 BM_29_23 -#define BM_30_23 0x000000007f800000 -#define BM_23_30 BM_30_23 -#define BM_31_23 0x00000000ff800000 -#define BM_23_31 BM_31_23 -#define BM_32_23 0x00000001ff800000 -#define BM_23_32 BM_32_23 -#define BM_33_23 0x00000003ff800000 -#define BM_23_33 BM_33_23 -#define BM_34_23 0x00000007ff800000 -#define BM_23_34 BM_34_23 -#define BM_35_23 0x0000000fff800000 -#define BM_23_35 BM_35_23 -#define BM_36_23 0x0000001fff800000 -#define BM_23_36 BM_36_23 -#define BM_37_23 0x0000003fff800000 -#define BM_23_37 BM_37_23 -#define BM_38_23 0x0000007fff800000 -#define BM_23_38 BM_38_23 -#define BM_39_23 0x000000ffff800000 -#define BM_23_39 BM_39_23 -#define BM_40_23 0x000001ffff800000 -#define BM_23_40 BM_40_23 -#define BM_41_23 0x000003ffff800000 -#define BM_23_41 BM_41_23 -#define BM_42_23 0x000007ffff800000 -#define BM_23_42 BM_42_23 -#define BM_43_23 0x00000fffff800000 -#define BM_23_43 BM_43_23 -#define BM_44_23 0x00001fffff800000 -#define BM_23_44 BM_44_23 -#define BM_45_23 0x00003fffff800000 -#define BM_23_45 BM_45_23 -#define BM_46_23 0x00007fffff800000 -#define BM_23_46 BM_46_23 -#define BM_47_23 0x0000ffffff800000 -#define BM_23_47 BM_47_23 -#define BM_48_23 0x0001ffffff800000 -#define BM_23_48 BM_48_23 -#define BM_49_23 0x0003ffffff800000 -#define BM_23_49 BM_49_23 -#define BM_50_23 0x0007ffffff800000 -#define BM_23_50 BM_50_23 -#define BM_51_23 0x000fffffff800000 -#define BM_23_51 BM_51_23 -#define BM_52_23 0x001fffffff800000 -#define BM_23_52 BM_52_23 -#define BM_53_23 0x003fffffff800000 -#define BM_23_53 BM_53_23 -#define BM_54_23 0x007fffffff800000 -#define BM_23_54 BM_54_23 -#define BM_55_23 0x00ffffffff800000 -#define BM_23_55 BM_55_23 -#define BM_56_23 0x01ffffffff800000 -#define BM_23_56 BM_56_23 -#define BM_57_23 0x03ffffffff800000 -#define BM_23_57 BM_57_23 -#define BM_58_23 0x07ffffffff800000 -#define BM_23_58 BM_58_23 -#define BM_59_23 0x0fffffffff800000 -#define BM_23_59 BM_59_23 -#define BM_60_23 0x1fffffffff800000 -#define BM_23_60 BM_60_23 -#define BM_61_23 0x3fffffffff800000 -#define BM_23_61 BM_61_23 -#define BM_62_23 0x7fffffffff800000 -#define BM_23_62 BM_62_23 -#define BM_63_23 0xffffffffff800000 -#define BM_23_63 BM_63_23 -#define BM_24_24 0x0000000001000000 -#define BM_25_24 0x0000000003000000 -#define BM_24_25 BM_25_24 -#define BM_26_24 0x0000000007000000 -#define BM_24_26 BM_26_24 -#define BM_27_24 0x000000000f000000 -#define BM_24_27 BM_27_24 -#define BM_28_24 0x000000001f000000 -#define BM_24_28 BM_28_24 -#define BM_29_24 0x000000003f000000 -#define BM_24_29 BM_29_24 -#define BM_30_24 0x000000007f000000 -#define BM_24_30 BM_30_24 -#define BM_31_24 0x00000000ff000000 -#define BM_24_31 BM_31_24 -#define BM_32_24 0x00000001ff000000 -#define BM_24_32 BM_32_24 -#define BM_33_24 0x00000003ff000000 -#define BM_24_33 BM_33_24 -#define BM_34_24 0x00000007ff000000 -#define BM_24_34 BM_34_24 -#define BM_35_24 0x0000000fff000000 -#define BM_24_35 BM_35_24 -#define BM_36_24 0x0000001fff000000 -#define BM_24_36 BM_36_24 -#define BM_37_24 0x0000003fff000000 -#define BM_24_37 BM_37_24 -#define BM_38_24 0x0000007fff000000 -#define BM_24_38 BM_38_24 -#define BM_39_24 0x000000ffff000000 -#define BM_24_39 BM_39_24 -#define BM_40_24 0x000001ffff000000 -#define BM_24_40 BM_40_24 -#define BM_41_24 0x000003ffff000000 -#define BM_24_41 BM_41_24 -#define BM_42_24 0x000007ffff000000 -#define BM_24_42 BM_42_24 -#define BM_43_24 0x00000fffff000000 -#define BM_24_43 BM_43_24 -#define BM_44_24 0x00001fffff000000 -#define BM_24_44 BM_44_24 -#define BM_45_24 0x00003fffff000000 -#define BM_24_45 BM_45_24 -#define BM_46_24 0x00007fffff000000 -#define BM_24_46 BM_46_24 -#define BM_47_24 0x0000ffffff000000 -#define BM_24_47 BM_47_24 -#define BM_48_24 0x0001ffffff000000 -#define BM_24_48 BM_48_24 -#define BM_49_24 0x0003ffffff000000 -#define BM_24_49 BM_49_24 -#define BM_50_24 0x0007ffffff000000 -#define BM_24_50 BM_50_24 -#define BM_51_24 0x000fffffff000000 -#define BM_24_51 BM_51_24 -#define BM_52_24 0x001fffffff000000 -#define BM_24_52 BM_52_24 -#define BM_53_24 0x003fffffff000000 -#define BM_24_53 BM_53_24 -#define BM_54_24 0x007fffffff000000 -#define BM_24_54 BM_54_24 -#define BM_55_24 0x00ffffffff000000 -#define BM_24_55 BM_55_24 -#define BM_56_24 0x01ffffffff000000 -#define BM_24_56 BM_56_24 -#define BM_57_24 0x03ffffffff000000 -#define BM_24_57 BM_57_24 -#define BM_58_24 0x07ffffffff000000 -#define BM_24_58 BM_58_24 -#define BM_59_24 0x0fffffffff000000 -#define BM_24_59 BM_59_24 -#define BM_60_24 0x1fffffffff000000 -#define BM_24_60 BM_60_24 -#define BM_61_24 0x3fffffffff000000 -#define BM_24_61 BM_61_24 -#define BM_62_24 0x7fffffffff000000 -#define BM_24_62 BM_62_24 -#define BM_63_24 0xffffffffff000000 -#define BM_24_63 BM_63_24 -#define BM_25_25 0x0000000002000000 -#define BM_26_25 0x0000000006000000 -#define BM_25_26 BM_26_25 -#define BM_27_25 0x000000000e000000 -#define BM_25_27 BM_27_25 -#define BM_28_25 0x000000001e000000 -#define BM_25_28 BM_28_25 -#define BM_29_25 0x000000003e000000 -#define BM_25_29 BM_29_25 -#define BM_30_25 0x000000007e000000 -#define BM_25_30 BM_30_25 -#define BM_31_25 0x00000000fe000000 -#define BM_25_31 BM_31_25 -#define BM_32_25 0x00000001fe000000 -#define BM_25_32 BM_32_25 -#define BM_33_25 0x00000003fe000000 -#define BM_25_33 BM_33_25 -#define BM_34_25 0x00000007fe000000 -#define BM_25_34 BM_34_25 -#define BM_35_25 0x0000000ffe000000 -#define BM_25_35 BM_35_25 -#define BM_36_25 0x0000001ffe000000 -#define BM_25_36 BM_36_25 -#define BM_37_25 0x0000003ffe000000 -#define BM_25_37 BM_37_25 -#define BM_38_25 0x0000007ffe000000 -#define BM_25_38 BM_38_25 -#define BM_39_25 0x000000fffe000000 -#define BM_25_39 BM_39_25 -#define BM_40_25 0x000001fffe000000 -#define BM_25_40 BM_40_25 -#define BM_41_25 0x000003fffe000000 -#define BM_25_41 BM_41_25 -#define BM_42_25 0x000007fffe000000 -#define BM_25_42 BM_42_25 -#define BM_43_25 0x00000ffffe000000 -#define BM_25_43 BM_43_25 -#define BM_44_25 0x00001ffffe000000 -#define BM_25_44 BM_44_25 -#define BM_45_25 0x00003ffffe000000 -#define BM_25_45 BM_45_25 -#define BM_46_25 0x00007ffffe000000 -#define BM_25_46 BM_46_25 -#define BM_47_25 0x0000fffffe000000 -#define BM_25_47 BM_47_25 -#define BM_48_25 0x0001fffffe000000 -#define BM_25_48 BM_48_25 -#define BM_49_25 0x0003fffffe000000 -#define BM_25_49 BM_49_25 -#define BM_50_25 0x0007fffffe000000 -#define BM_25_50 BM_50_25 -#define BM_51_25 0x000ffffffe000000 -#define BM_25_51 BM_51_25 -#define BM_52_25 0x001ffffffe000000 -#define BM_25_52 BM_52_25 -#define BM_53_25 0x003ffffffe000000 -#define BM_25_53 BM_53_25 -#define BM_54_25 0x007ffffffe000000 -#define BM_25_54 BM_54_25 -#define BM_55_25 0x00fffffffe000000 -#define BM_25_55 BM_55_25 -#define BM_56_25 0x01fffffffe000000 -#define BM_25_56 BM_56_25 -#define BM_57_25 0x03fffffffe000000 -#define BM_25_57 BM_57_25 -#define BM_58_25 0x07fffffffe000000 -#define BM_25_58 BM_58_25 -#define BM_59_25 0x0ffffffffe000000 -#define BM_25_59 BM_59_25 -#define BM_60_25 0x1ffffffffe000000 -#define BM_25_60 BM_60_25 -#define BM_61_25 0x3ffffffffe000000 -#define BM_25_61 BM_61_25 -#define BM_62_25 0x7ffffffffe000000 -#define BM_25_62 BM_62_25 -#define BM_63_25 0xfffffffffe000000 -#define BM_25_63 BM_63_25 -#define BM_26_26 0x0000000004000000 -#define BM_27_26 0x000000000c000000 -#define BM_26_27 BM_27_26 -#define BM_28_26 0x000000001c000000 -#define BM_26_28 BM_28_26 -#define BM_29_26 0x000000003c000000 -#define BM_26_29 BM_29_26 -#define BM_30_26 0x000000007c000000 -#define BM_26_30 BM_30_26 -#define BM_31_26 0x00000000fc000000 -#define BM_26_31 BM_31_26 -#define BM_32_26 0x00000001fc000000 -#define BM_26_32 BM_32_26 -#define BM_33_26 0x00000003fc000000 -#define BM_26_33 BM_33_26 -#define BM_34_26 0x00000007fc000000 -#define BM_26_34 BM_34_26 -#define BM_35_26 0x0000000ffc000000 -#define BM_26_35 BM_35_26 -#define BM_36_26 0x0000001ffc000000 -#define BM_26_36 BM_36_26 -#define BM_37_26 0x0000003ffc000000 -#define BM_26_37 BM_37_26 -#define BM_38_26 0x0000007ffc000000 -#define BM_26_38 BM_38_26 -#define BM_39_26 0x000000fffc000000 -#define BM_26_39 BM_39_26 -#define BM_40_26 0x000001fffc000000 -#define BM_26_40 BM_40_26 -#define BM_41_26 0x000003fffc000000 -#define BM_26_41 BM_41_26 -#define BM_42_26 0x000007fffc000000 -#define BM_26_42 BM_42_26 -#define BM_43_26 0x00000ffffc000000 -#define BM_26_43 BM_43_26 -#define BM_44_26 0x00001ffffc000000 -#define BM_26_44 BM_44_26 -#define BM_45_26 0x00003ffffc000000 -#define BM_26_45 BM_45_26 -#define BM_46_26 0x00007ffffc000000 -#define BM_26_46 BM_46_26 -#define BM_47_26 0x0000fffffc000000 -#define BM_26_47 BM_47_26 -#define BM_48_26 0x0001fffffc000000 -#define BM_26_48 BM_48_26 -#define BM_49_26 0x0003fffffc000000 -#define BM_26_49 BM_49_26 -#define BM_50_26 0x0007fffffc000000 -#define BM_26_50 BM_50_26 -#define BM_51_26 0x000ffffffc000000 -#define BM_26_51 BM_51_26 -#define BM_52_26 0x001ffffffc000000 -#define BM_26_52 BM_52_26 -#define BM_53_26 0x003ffffffc000000 -#define BM_26_53 BM_53_26 -#define BM_54_26 0x007ffffffc000000 -#define BM_26_54 BM_54_26 -#define BM_55_26 0x00fffffffc000000 -#define BM_26_55 BM_55_26 -#define BM_56_26 0x01fffffffc000000 -#define BM_26_56 BM_56_26 -#define BM_57_26 0x03fffffffc000000 -#define BM_26_57 BM_57_26 -#define BM_58_26 0x07fffffffc000000 -#define BM_26_58 BM_58_26 -#define BM_59_26 0x0ffffffffc000000 -#define BM_26_59 BM_59_26 -#define BM_60_26 0x1ffffffffc000000 -#define BM_26_60 BM_60_26 -#define BM_61_26 0x3ffffffffc000000 -#define BM_26_61 BM_61_26 -#define BM_62_26 0x7ffffffffc000000 -#define BM_26_62 BM_62_26 -#define BM_63_26 0xfffffffffc000000 -#define BM_26_63 BM_63_26 -#define BM_27_27 0x0000000008000000 -#define BM_28_27 0x0000000018000000 -#define BM_27_28 BM_28_27 -#define BM_29_27 0x0000000038000000 -#define BM_27_29 BM_29_27 -#define BM_30_27 0x0000000078000000 -#define BM_27_30 BM_30_27 -#define BM_31_27 0x00000000f8000000 -#define BM_27_31 BM_31_27 -#define BM_32_27 0x00000001f8000000 -#define BM_27_32 BM_32_27 -#define BM_33_27 0x00000003f8000000 -#define BM_27_33 BM_33_27 -#define BM_34_27 0x00000007f8000000 -#define BM_27_34 BM_34_27 -#define BM_35_27 0x0000000ff8000000 -#define BM_27_35 BM_35_27 -#define BM_36_27 0x0000001ff8000000 -#define BM_27_36 BM_36_27 -#define BM_37_27 0x0000003ff8000000 -#define BM_27_37 BM_37_27 -#define BM_38_27 0x0000007ff8000000 -#define BM_27_38 BM_38_27 -#define BM_39_27 0x000000fff8000000 -#define BM_27_39 BM_39_27 -#define BM_40_27 0x000001fff8000000 -#define BM_27_40 BM_40_27 -#define BM_41_27 0x000003fff8000000 -#define BM_27_41 BM_41_27 -#define BM_42_27 0x000007fff8000000 -#define BM_27_42 BM_42_27 -#define BM_43_27 0x00000ffff8000000 -#define BM_27_43 BM_43_27 -#define BM_44_27 0x00001ffff8000000 -#define BM_27_44 BM_44_27 -#define BM_45_27 0x00003ffff8000000 -#define BM_27_45 BM_45_27 -#define BM_46_27 0x00007ffff8000000 -#define BM_27_46 BM_46_27 -#define BM_47_27 0x0000fffff8000000 -#define BM_27_47 BM_47_27 -#define BM_48_27 0x0001fffff8000000 -#define BM_27_48 BM_48_27 -#define BM_49_27 0x0003fffff8000000 -#define BM_27_49 BM_49_27 -#define BM_50_27 0x0007fffff8000000 -#define BM_27_50 BM_50_27 -#define BM_51_27 0x000ffffff8000000 -#define BM_27_51 BM_51_27 -#define BM_52_27 0x001ffffff8000000 -#define BM_27_52 BM_52_27 -#define BM_53_27 0x003ffffff8000000 -#define BM_27_53 BM_53_27 -#define BM_54_27 0x007ffffff8000000 -#define BM_27_54 BM_54_27 -#define BM_55_27 0x00fffffff8000000 -#define BM_27_55 BM_55_27 -#define BM_56_27 0x01fffffff8000000 -#define BM_27_56 BM_56_27 -#define BM_57_27 0x03fffffff8000000 -#define BM_27_57 BM_57_27 -#define BM_58_27 0x07fffffff8000000 -#define BM_27_58 BM_58_27 -#define BM_59_27 0x0ffffffff8000000 -#define BM_27_59 BM_59_27 -#define BM_60_27 0x1ffffffff8000000 -#define BM_27_60 BM_60_27 -#define BM_61_27 0x3ffffffff8000000 -#define BM_27_61 BM_61_27 -#define BM_62_27 0x7ffffffff8000000 -#define BM_27_62 BM_62_27 -#define BM_63_27 0xfffffffff8000000 -#define BM_27_63 BM_63_27 -#define BM_28_28 0x0000000010000000 -#define BM_29_28 0x0000000030000000 -#define BM_28_29 BM_29_28 -#define BM_30_28 0x0000000070000000 -#define BM_28_30 BM_30_28 -#define BM_31_28 0x00000000f0000000 -#define BM_28_31 BM_31_28 -#define BM_32_28 0x00000001f0000000 -#define BM_28_32 BM_32_28 -#define BM_33_28 0x00000003f0000000 -#define BM_28_33 BM_33_28 -#define BM_34_28 0x00000007f0000000 -#define BM_28_34 BM_34_28 -#define BM_35_28 0x0000000ff0000000 -#define BM_28_35 BM_35_28 -#define BM_36_28 0x0000001ff0000000 -#define BM_28_36 BM_36_28 -#define BM_37_28 0x0000003ff0000000 -#define BM_28_37 BM_37_28 -#define BM_38_28 0x0000007ff0000000 -#define BM_28_38 BM_38_28 -#define BM_39_28 0x000000fff0000000 -#define BM_28_39 BM_39_28 -#define BM_40_28 0x000001fff0000000 -#define BM_28_40 BM_40_28 -#define BM_41_28 0x000003fff0000000 -#define BM_28_41 BM_41_28 -#define BM_42_28 0x000007fff0000000 -#define BM_28_42 BM_42_28 -#define BM_43_28 0x00000ffff0000000 -#define BM_28_43 BM_43_28 -#define BM_44_28 0x00001ffff0000000 -#define BM_28_44 BM_44_28 -#define BM_45_28 0x00003ffff0000000 -#define BM_28_45 BM_45_28 -#define BM_46_28 0x00007ffff0000000 -#define BM_28_46 BM_46_28 -#define BM_47_28 0x0000fffff0000000 -#define BM_28_47 BM_47_28 -#define BM_48_28 0x0001fffff0000000 -#define BM_28_48 BM_48_28 -#define BM_49_28 0x0003fffff0000000 -#define BM_28_49 BM_49_28 -#define BM_50_28 0x0007fffff0000000 -#define BM_28_50 BM_50_28 -#define BM_51_28 0x000ffffff0000000 -#define BM_28_51 BM_51_28 -#define BM_52_28 0x001ffffff0000000 -#define BM_28_52 BM_52_28 -#define BM_53_28 0x003ffffff0000000 -#define BM_28_53 BM_53_28 -#define BM_54_28 0x007ffffff0000000 -#define BM_28_54 BM_54_28 -#define BM_55_28 0x00fffffff0000000 -#define BM_28_55 BM_55_28 -#define BM_56_28 0x01fffffff0000000 -#define BM_28_56 BM_56_28 -#define BM_57_28 0x03fffffff0000000 -#define BM_28_57 BM_57_28 -#define BM_58_28 0x07fffffff0000000 -#define BM_28_58 BM_58_28 -#define BM_59_28 0x0ffffffff0000000 -#define BM_28_59 BM_59_28 -#define BM_60_28 0x1ffffffff0000000 -#define BM_28_60 BM_60_28 -#define BM_61_28 0x3ffffffff0000000 -#define BM_28_61 BM_61_28 -#define BM_62_28 0x7ffffffff0000000 -#define BM_28_62 BM_62_28 -#define BM_63_28 0xfffffffff0000000 -#define BM_28_63 BM_63_28 -#define BM_29_29 0x0000000020000000 -#define BM_30_29 0x0000000060000000 -#define BM_29_30 BM_30_29 -#define BM_31_29 0x00000000e0000000 -#define BM_29_31 BM_31_29 -#define BM_32_29 0x00000001e0000000 -#define BM_29_32 BM_32_29 -#define BM_33_29 0x00000003e0000000 -#define BM_29_33 BM_33_29 -#define BM_34_29 0x00000007e0000000 -#define BM_29_34 BM_34_29 -#define BM_35_29 0x0000000fe0000000 -#define BM_29_35 BM_35_29 -#define BM_36_29 0x0000001fe0000000 -#define BM_29_36 BM_36_29 -#define BM_37_29 0x0000003fe0000000 -#define BM_29_37 BM_37_29 -#define BM_38_29 0x0000007fe0000000 -#define BM_29_38 BM_38_29 -#define BM_39_29 0x000000ffe0000000 -#define BM_29_39 BM_39_29 -#define BM_40_29 0x000001ffe0000000 -#define BM_29_40 BM_40_29 -#define BM_41_29 0x000003ffe0000000 -#define BM_29_41 BM_41_29 -#define BM_42_29 0x000007ffe0000000 -#define BM_29_42 BM_42_29 -#define BM_43_29 0x00000fffe0000000 -#define BM_29_43 BM_43_29 -#define BM_44_29 0x00001fffe0000000 -#define BM_29_44 BM_44_29 -#define BM_45_29 0x00003fffe0000000 -#define BM_29_45 BM_45_29 -#define BM_46_29 0x00007fffe0000000 -#define BM_29_46 BM_46_29 -#define BM_47_29 0x0000ffffe0000000 -#define BM_29_47 BM_47_29 -#define BM_48_29 0x0001ffffe0000000 -#define BM_29_48 BM_48_29 -#define BM_49_29 0x0003ffffe0000000 -#define BM_29_49 BM_49_29 -#define BM_50_29 0x0007ffffe0000000 -#define BM_29_50 BM_50_29 -#define BM_51_29 0x000fffffe0000000 -#define BM_29_51 BM_51_29 -#define BM_52_29 0x001fffffe0000000 -#define BM_29_52 BM_52_29 -#define BM_53_29 0x003fffffe0000000 -#define BM_29_53 BM_53_29 -#define BM_54_29 0x007fffffe0000000 -#define BM_29_54 BM_54_29 -#define BM_55_29 0x00ffffffe0000000 -#define BM_29_55 BM_55_29 -#define BM_56_29 0x01ffffffe0000000 -#define BM_29_56 BM_56_29 -#define BM_57_29 0x03ffffffe0000000 -#define BM_29_57 BM_57_29 -#define BM_58_29 0x07ffffffe0000000 -#define BM_29_58 BM_58_29 -#define BM_59_29 0x0fffffffe0000000 -#define BM_29_59 BM_59_29 -#define BM_60_29 0x1fffffffe0000000 -#define BM_29_60 BM_60_29 -#define BM_61_29 0x3fffffffe0000000 -#define BM_29_61 BM_61_29 -#define BM_62_29 0x7fffffffe0000000 -#define BM_29_62 BM_62_29 -#define BM_63_29 0xffffffffe0000000 -#define BM_29_63 BM_63_29 -#define BM_30_30 0x0000000040000000 -#define BM_31_30 0x00000000c0000000 -#define BM_30_31 BM_31_30 -#define BM_32_30 0x00000001c0000000 -#define BM_30_32 BM_32_30 -#define BM_33_30 0x00000003c0000000 -#define BM_30_33 BM_33_30 -#define BM_34_30 0x00000007c0000000 -#define BM_30_34 BM_34_30 -#define BM_35_30 0x0000000fc0000000 -#define BM_30_35 BM_35_30 -#define BM_36_30 0x0000001fc0000000 -#define BM_30_36 BM_36_30 -#define BM_37_30 0x0000003fc0000000 -#define BM_30_37 BM_37_30 -#define BM_38_30 0x0000007fc0000000 -#define BM_30_38 BM_38_30 -#define BM_39_30 0x000000ffc0000000 -#define BM_30_39 BM_39_30 -#define BM_40_30 0x000001ffc0000000 -#define BM_30_40 BM_40_30 -#define BM_41_30 0x000003ffc0000000 -#define BM_30_41 BM_41_30 -#define BM_42_30 0x000007ffc0000000 -#define BM_30_42 BM_42_30 -#define BM_43_30 0x00000fffc0000000 -#define BM_30_43 BM_43_30 -#define BM_44_30 0x00001fffc0000000 -#define BM_30_44 BM_44_30 -#define BM_45_30 0x00003fffc0000000 -#define BM_30_45 BM_45_30 -#define BM_46_30 0x00007fffc0000000 -#define BM_30_46 BM_46_30 -#define BM_47_30 0x0000ffffc0000000 -#define BM_30_47 BM_47_30 -#define BM_48_30 0x0001ffffc0000000 -#define BM_30_48 BM_48_30 -#define BM_49_30 0x0003ffffc0000000 -#define BM_30_49 BM_49_30 -#define BM_50_30 0x0007ffffc0000000 -#define BM_30_50 BM_50_30 -#define BM_51_30 0x000fffffc0000000 -#define BM_30_51 BM_51_30 -#define BM_52_30 0x001fffffc0000000 -#define BM_30_52 BM_52_30 -#define BM_53_30 0x003fffffc0000000 -#define BM_30_53 BM_53_30 -#define BM_54_30 0x007fffffc0000000 -#define BM_30_54 BM_54_30 -#define BM_55_30 0x00ffffffc0000000 -#define BM_30_55 BM_55_30 -#define BM_56_30 0x01ffffffc0000000 -#define BM_30_56 BM_56_30 -#define BM_57_30 0x03ffffffc0000000 -#define BM_30_57 BM_57_30 -#define BM_58_30 0x07ffffffc0000000 -#define BM_30_58 BM_58_30 -#define BM_59_30 0x0fffffffc0000000 -#define BM_30_59 BM_59_30 -#define BM_60_30 0x1fffffffc0000000 -#define BM_30_60 BM_60_30 -#define BM_61_30 0x3fffffffc0000000 -#define BM_30_61 BM_61_30 -#define BM_62_30 0x7fffffffc0000000 -#define BM_30_62 BM_62_30 -#define BM_63_30 0xffffffffc0000000 -#define BM_30_63 BM_63_30 -#define BM_31_31 0x0000000080000000 -#define BM_32_31 0x0000000180000000 -#define BM_31_32 BM_32_31 -#define BM_33_31 0x0000000380000000 -#define BM_31_33 BM_33_31 -#define BM_34_31 0x0000000780000000 -#define BM_31_34 BM_34_31 -#define BM_35_31 0x0000000f80000000 -#define BM_31_35 BM_35_31 -#define BM_36_31 0x0000001f80000000 -#define BM_31_36 BM_36_31 -#define BM_37_31 0x0000003f80000000 -#define BM_31_37 BM_37_31 -#define BM_38_31 0x0000007f80000000 -#define BM_31_38 BM_38_31 -#define BM_39_31 0x000000ff80000000 -#define BM_31_39 BM_39_31 -#define BM_40_31 0x000001ff80000000 -#define BM_31_40 BM_40_31 -#define BM_41_31 0x000003ff80000000 -#define BM_31_41 BM_41_31 -#define BM_42_31 0x000007ff80000000 -#define BM_31_42 BM_42_31 -#define BM_43_31 0x00000fff80000000 -#define BM_31_43 BM_43_31 -#define BM_44_31 0x00001fff80000000 -#define BM_31_44 BM_44_31 -#define BM_45_31 0x00003fff80000000 -#define BM_31_45 BM_45_31 -#define BM_46_31 0x00007fff80000000 -#define BM_31_46 BM_46_31 -#define BM_47_31 0x0000ffff80000000 -#define BM_31_47 BM_47_31 -#define BM_48_31 0x0001ffff80000000 -#define BM_31_48 BM_48_31 -#define BM_49_31 0x0003ffff80000000 -#define BM_31_49 BM_49_31 -#define BM_50_31 0x0007ffff80000000 -#define BM_31_50 BM_50_31 -#define BM_51_31 0x000fffff80000000 -#define BM_31_51 BM_51_31 -#define BM_52_31 0x001fffff80000000 -#define BM_31_52 BM_52_31 -#define BM_53_31 0x003fffff80000000 -#define BM_31_53 BM_53_31 -#define BM_54_31 0x007fffff80000000 -#define BM_31_54 BM_54_31 -#define BM_55_31 0x00ffffff80000000 -#define BM_31_55 BM_55_31 -#define BM_56_31 0x01ffffff80000000 -#define BM_31_56 BM_56_31 -#define BM_57_31 0x03ffffff80000000 -#define BM_31_57 BM_57_31 -#define BM_58_31 0x07ffffff80000000 -#define BM_31_58 BM_58_31 -#define BM_59_31 0x0fffffff80000000 -#define BM_31_59 BM_59_31 -#define BM_60_31 0x1fffffff80000000 -#define BM_31_60 BM_60_31 -#define BM_61_31 0x3fffffff80000000 -#define BM_31_61 BM_61_31 -#define BM_62_31 0x7fffffff80000000 -#define BM_31_62 BM_62_31 -#define BM_63_31 0xffffffff80000000 -#define BM_31_63 BM_63_31 -#define BM_32_32 0x0000000100000000 -#define BM_33_32 0x0000000300000000 -#define BM_32_33 BM_33_32 -#define BM_34_32 0x0000000700000000 -#define BM_32_34 BM_34_32 -#define BM_35_32 0x0000000f00000000 -#define BM_32_35 BM_35_32 -#define BM_36_32 0x0000001f00000000 -#define BM_32_36 BM_36_32 -#define BM_37_32 0x0000003f00000000 -#define BM_32_37 BM_37_32 -#define BM_38_32 0x0000007f00000000 -#define BM_32_38 BM_38_32 -#define BM_39_32 0x000000ff00000000 -#define BM_32_39 BM_39_32 -#define BM_40_32 0x000001ff00000000 -#define BM_32_40 BM_40_32 -#define BM_41_32 0x000003ff00000000 -#define BM_32_41 BM_41_32 -#define BM_42_32 0x000007ff00000000 -#define BM_32_42 BM_42_32 -#define BM_43_32 0x00000fff00000000 -#define BM_32_43 BM_43_32 -#define BM_44_32 0x00001fff00000000 -#define BM_32_44 BM_44_32 -#define BM_45_32 0x00003fff00000000 -#define BM_32_45 BM_45_32 -#define BM_46_32 0x00007fff00000000 -#define BM_32_46 BM_46_32 -#define BM_47_32 0x0000ffff00000000 -#define BM_32_47 BM_47_32 -#define BM_48_32 0x0001ffff00000000 -#define BM_32_48 BM_48_32 -#define BM_49_32 0x0003ffff00000000 -#define BM_32_49 BM_49_32 -#define BM_50_32 0x0007ffff00000000 -#define BM_32_50 BM_50_32 -#define BM_51_32 0x000fffff00000000 -#define BM_32_51 BM_51_32 -#define BM_52_32 0x001fffff00000000 -#define BM_32_52 BM_52_32 -#define BM_53_32 0x003fffff00000000 -#define BM_32_53 BM_53_32 -#define BM_54_32 0x007fffff00000000 -#define BM_32_54 BM_54_32 -#define BM_55_32 0x00ffffff00000000 -#define BM_32_55 BM_55_32 -#define BM_56_32 0x01ffffff00000000 -#define BM_32_56 BM_56_32 -#define BM_57_32 0x03ffffff00000000 -#define BM_32_57 BM_57_32 -#define BM_58_32 0x07ffffff00000000 -#define BM_32_58 BM_58_32 -#define BM_59_32 0x0fffffff00000000 -#define BM_32_59 BM_59_32 -#define BM_60_32 0x1fffffff00000000 -#define BM_32_60 BM_60_32 -#define BM_61_32 0x3fffffff00000000 -#define BM_32_61 BM_61_32 -#define BM_62_32 0x7fffffff00000000 -#define BM_32_62 BM_62_32 -#define BM_63_32 0xffffffff00000000 -#define BM_32_63 BM_63_32 -#define BM_33_33 0x0000000200000000 -#define BM_34_33 0x0000000600000000 -#define BM_33_34 BM_34_33 -#define BM_35_33 0x0000000e00000000 -#define BM_33_35 BM_35_33 -#define BM_36_33 0x0000001e00000000 -#define BM_33_36 BM_36_33 -#define BM_37_33 0x0000003e00000000 -#define BM_33_37 BM_37_33 -#define BM_38_33 0x0000007e00000000 -#define BM_33_38 BM_38_33 -#define BM_39_33 0x000000fe00000000 -#define BM_33_39 BM_39_33 -#define BM_40_33 0x000001fe00000000 -#define BM_33_40 BM_40_33 -#define BM_41_33 0x000003fe00000000 -#define BM_33_41 BM_41_33 -#define BM_42_33 0x000007fe00000000 -#define BM_33_42 BM_42_33 -#define BM_43_33 0x00000ffe00000000 -#define BM_33_43 BM_43_33 -#define BM_44_33 0x00001ffe00000000 -#define BM_33_44 BM_44_33 -#define BM_45_33 0x00003ffe00000000 -#define BM_33_45 BM_45_33 -#define BM_46_33 0x00007ffe00000000 -#define BM_33_46 BM_46_33 -#define BM_47_33 0x0000fffe00000000 -#define BM_33_47 BM_47_33 -#define BM_48_33 0x0001fffe00000000 -#define BM_33_48 BM_48_33 -#define BM_49_33 0x0003fffe00000000 -#define BM_33_49 BM_49_33 -#define BM_50_33 0x0007fffe00000000 -#define BM_33_50 BM_50_33 -#define BM_51_33 0x000ffffe00000000 -#define BM_33_51 BM_51_33 -#define BM_52_33 0x001ffffe00000000 -#define BM_33_52 BM_52_33 -#define BM_53_33 0x003ffffe00000000 -#define BM_33_53 BM_53_33 -#define BM_54_33 0x007ffffe00000000 -#define BM_33_54 BM_54_33 -#define BM_55_33 0x00fffffe00000000 -#define BM_33_55 BM_55_33 -#define BM_56_33 0x01fffffe00000000 -#define BM_33_56 BM_56_33 -#define BM_57_33 0x03fffffe00000000 -#define BM_33_57 BM_57_33 -#define BM_58_33 0x07fffffe00000000 -#define BM_33_58 BM_58_33 -#define BM_59_33 0x0ffffffe00000000 -#define BM_33_59 BM_59_33 -#define BM_60_33 0x1ffffffe00000000 -#define BM_33_60 BM_60_33 -#define BM_61_33 0x3ffffffe00000000 -#define BM_33_61 BM_61_33 -#define BM_62_33 0x7ffffffe00000000 -#define BM_33_62 BM_62_33 -#define BM_63_33 0xfffffffe00000000 -#define BM_33_63 BM_63_33 -#define BM_34_34 0x0000000400000000 -#define BM_35_34 0x0000000c00000000 -#define BM_34_35 BM_35_34 -#define BM_36_34 0x0000001c00000000 -#define BM_34_36 BM_36_34 -#define BM_37_34 0x0000003c00000000 -#define BM_34_37 BM_37_34 -#define BM_38_34 0x0000007c00000000 -#define BM_34_38 BM_38_34 -#define BM_39_34 0x000000fc00000000 -#define BM_34_39 BM_39_34 -#define BM_40_34 0x000001fc00000000 -#define BM_34_40 BM_40_34 -#define BM_41_34 0x000003fc00000000 -#define BM_34_41 BM_41_34 -#define BM_42_34 0x000007fc00000000 -#define BM_34_42 BM_42_34 -#define BM_43_34 0x00000ffc00000000 -#define BM_34_43 BM_43_34 -#define BM_44_34 0x00001ffc00000000 -#define BM_34_44 BM_44_34 -#define BM_45_34 0x00003ffc00000000 -#define BM_34_45 BM_45_34 -#define BM_46_34 0x00007ffc00000000 -#define BM_34_46 BM_46_34 -#define BM_47_34 0x0000fffc00000000 -#define BM_34_47 BM_47_34 -#define BM_48_34 0x0001fffc00000000 -#define BM_34_48 BM_48_34 -#define BM_49_34 0x0003fffc00000000 -#define BM_34_49 BM_49_34 -#define BM_50_34 0x0007fffc00000000 -#define BM_34_50 BM_50_34 -#define BM_51_34 0x000ffffc00000000 -#define BM_34_51 BM_51_34 -#define BM_52_34 0x001ffffc00000000 -#define BM_34_52 BM_52_34 -#define BM_53_34 0x003ffffc00000000 -#define BM_34_53 BM_53_34 -#define BM_54_34 0x007ffffc00000000 -#define BM_34_54 BM_54_34 -#define BM_55_34 0x00fffffc00000000 -#define BM_34_55 BM_55_34 -#define BM_56_34 0x01fffffc00000000 -#define BM_34_56 BM_56_34 -#define BM_57_34 0x03fffffc00000000 -#define BM_34_57 BM_57_34 -#define BM_58_34 0x07fffffc00000000 -#define BM_34_58 BM_58_34 -#define BM_59_34 0x0ffffffc00000000 -#define BM_34_59 BM_59_34 -#define BM_60_34 0x1ffffffc00000000 -#define BM_34_60 BM_60_34 -#define BM_61_34 0x3ffffffc00000000 -#define BM_34_61 BM_61_34 -#define BM_62_34 0x7ffffffc00000000 -#define BM_34_62 BM_62_34 -#define BM_63_34 0xfffffffc00000000 -#define BM_34_63 BM_63_34 -#define BM_35_35 0x0000000800000000 -#define BM_36_35 0x0000001800000000 -#define BM_35_36 BM_36_35 -#define BM_37_35 0x0000003800000000 -#define BM_35_37 BM_37_35 -#define BM_38_35 0x0000007800000000 -#define BM_35_38 BM_38_35 -#define BM_39_35 0x000000f800000000 -#define BM_35_39 BM_39_35 -#define BM_40_35 0x000001f800000000 -#define BM_35_40 BM_40_35 -#define BM_41_35 0x000003f800000000 -#define BM_35_41 BM_41_35 -#define BM_42_35 0x000007f800000000 -#define BM_35_42 BM_42_35 -#define BM_43_35 0x00000ff800000000 -#define BM_35_43 BM_43_35 -#define BM_44_35 0x00001ff800000000 -#define BM_35_44 BM_44_35 -#define BM_45_35 0x00003ff800000000 -#define BM_35_45 BM_45_35 -#define BM_46_35 0x00007ff800000000 -#define BM_35_46 BM_46_35 -#define BM_47_35 0x0000fff800000000 -#define BM_35_47 BM_47_35 -#define BM_48_35 0x0001fff800000000 -#define BM_35_48 BM_48_35 -#define BM_49_35 0x0003fff800000000 -#define BM_35_49 BM_49_35 -#define BM_50_35 0x0007fff800000000 -#define BM_35_50 BM_50_35 -#define BM_51_35 0x000ffff800000000 -#define BM_35_51 BM_51_35 -#define BM_52_35 0x001ffff800000000 -#define BM_35_52 BM_52_35 -#define BM_53_35 0x003ffff800000000 -#define BM_35_53 BM_53_35 -#define BM_54_35 0x007ffff800000000 -#define BM_35_54 BM_54_35 -#define BM_55_35 0x00fffff800000000 -#define BM_35_55 BM_55_35 -#define BM_56_35 0x01fffff800000000 -#define BM_35_56 BM_56_35 -#define BM_57_35 0x03fffff800000000 -#define BM_35_57 BM_57_35 -#define BM_58_35 0x07fffff800000000 -#define BM_35_58 BM_58_35 -#define BM_59_35 0x0ffffff800000000 -#define BM_35_59 BM_59_35 -#define BM_60_35 0x1ffffff800000000 -#define BM_35_60 BM_60_35 -#define BM_61_35 0x3ffffff800000000 -#define BM_35_61 BM_61_35 -#define BM_62_35 0x7ffffff800000000 -#define BM_35_62 BM_62_35 -#define BM_63_35 0xfffffff800000000 -#define BM_35_63 BM_63_35 -#define BM_36_36 0x0000001000000000 -#define BM_37_36 0x0000003000000000 -#define BM_36_37 BM_37_36 -#define BM_38_36 0x0000007000000000 -#define BM_36_38 BM_38_36 -#define BM_39_36 0x000000f000000000 -#define BM_36_39 BM_39_36 -#define BM_40_36 0x000001f000000000 -#define BM_36_40 BM_40_36 -#define BM_41_36 0x000003f000000000 -#define BM_36_41 BM_41_36 -#define BM_42_36 0x000007f000000000 -#define BM_36_42 BM_42_36 -#define BM_43_36 0x00000ff000000000 -#define BM_36_43 BM_43_36 -#define BM_44_36 0x00001ff000000000 -#define BM_36_44 BM_44_36 -#define BM_45_36 0x00003ff000000000 -#define BM_36_45 BM_45_36 -#define BM_46_36 0x00007ff000000000 -#define BM_36_46 BM_46_36 -#define BM_47_36 0x0000fff000000000 -#define BM_36_47 BM_47_36 -#define BM_48_36 0x0001fff000000000 -#define BM_36_48 BM_48_36 -#define BM_49_36 0x0003fff000000000 -#define BM_36_49 BM_49_36 -#define BM_50_36 0x0007fff000000000 -#define BM_36_50 BM_50_36 -#define BM_51_36 0x000ffff000000000 -#define BM_36_51 BM_51_36 -#define BM_52_36 0x001ffff000000000 -#define BM_36_52 BM_52_36 -#define BM_53_36 0x003ffff000000000 -#define BM_36_53 BM_53_36 -#define BM_54_36 0x007ffff000000000 -#define BM_36_54 BM_54_36 -#define BM_55_36 0x00fffff000000000 -#define BM_36_55 BM_55_36 -#define BM_56_36 0x01fffff000000000 -#define BM_36_56 BM_56_36 -#define BM_57_36 0x03fffff000000000 -#define BM_36_57 BM_57_36 -#define BM_58_36 0x07fffff000000000 -#define BM_36_58 BM_58_36 -#define BM_59_36 0x0ffffff000000000 -#define BM_36_59 BM_59_36 -#define BM_60_36 0x1ffffff000000000 -#define BM_36_60 BM_60_36 -#define BM_61_36 0x3ffffff000000000 -#define BM_36_61 BM_61_36 -#define BM_62_36 0x7ffffff000000000 -#define BM_36_62 BM_62_36 -#define BM_63_36 0xfffffff000000000 -#define BM_36_63 BM_63_36 -#define BM_37_37 0x0000002000000000 -#define BM_38_37 0x0000006000000000 -#define BM_37_38 BM_38_37 -#define BM_39_37 0x000000e000000000 -#define BM_37_39 BM_39_37 -#define BM_40_37 0x000001e000000000 -#define BM_37_40 BM_40_37 -#define BM_41_37 0x000003e000000000 -#define BM_37_41 BM_41_37 -#define BM_42_37 0x000007e000000000 -#define BM_37_42 BM_42_37 -#define BM_43_37 0x00000fe000000000 -#define BM_37_43 BM_43_37 -#define BM_44_37 0x00001fe000000000 -#define BM_37_44 BM_44_37 -#define BM_45_37 0x00003fe000000000 -#define BM_37_45 BM_45_37 -#define BM_46_37 0x00007fe000000000 -#define BM_37_46 BM_46_37 -#define BM_47_37 0x0000ffe000000000 -#define BM_37_47 BM_47_37 -#define BM_48_37 0x0001ffe000000000 -#define BM_37_48 BM_48_37 -#define BM_49_37 0x0003ffe000000000 -#define BM_37_49 BM_49_37 -#define BM_50_37 0x0007ffe000000000 -#define BM_37_50 BM_50_37 -#define BM_51_37 0x000fffe000000000 -#define BM_37_51 BM_51_37 -#define BM_52_37 0x001fffe000000000 -#define BM_37_52 BM_52_37 -#define BM_53_37 0x003fffe000000000 -#define BM_37_53 BM_53_37 -#define BM_54_37 0x007fffe000000000 -#define BM_37_54 BM_54_37 -#define BM_55_37 0x00ffffe000000000 -#define BM_37_55 BM_55_37 -#define BM_56_37 0x01ffffe000000000 -#define BM_37_56 BM_56_37 -#define BM_57_37 0x03ffffe000000000 -#define BM_37_57 BM_57_37 -#define BM_58_37 0x07ffffe000000000 -#define BM_37_58 BM_58_37 -#define BM_59_37 0x0fffffe000000000 -#define BM_37_59 BM_59_37 -#define BM_60_37 0x1fffffe000000000 -#define BM_37_60 BM_60_37 -#define BM_61_37 0x3fffffe000000000 -#define BM_37_61 BM_61_37 -#define BM_62_37 0x7fffffe000000000 -#define BM_37_62 BM_62_37 -#define BM_63_37 0xffffffe000000000 -#define BM_37_63 BM_63_37 -#define BM_38_38 0x0000004000000000 -#define BM_39_38 0x000000c000000000 -#define BM_38_39 BM_39_38 -#define BM_40_38 0x000001c000000000 -#define BM_38_40 BM_40_38 -#define BM_41_38 0x000003c000000000 -#define BM_38_41 BM_41_38 -#define BM_42_38 0x000007c000000000 -#define BM_38_42 BM_42_38 -#define BM_43_38 0x00000fc000000000 -#define BM_38_43 BM_43_38 -#define BM_44_38 0x00001fc000000000 -#define BM_38_44 BM_44_38 -#define BM_45_38 0x00003fc000000000 -#define BM_38_45 BM_45_38 -#define BM_46_38 0x00007fc000000000 -#define BM_38_46 BM_46_38 -#define BM_47_38 0x0000ffc000000000 -#define BM_38_47 BM_47_38 -#define BM_48_38 0x0001ffc000000000 -#define BM_38_48 BM_48_38 -#define BM_49_38 0x0003ffc000000000 -#define BM_38_49 BM_49_38 -#define BM_50_38 0x0007ffc000000000 -#define BM_38_50 BM_50_38 -#define BM_51_38 0x000fffc000000000 -#define BM_38_51 BM_51_38 -#define BM_52_38 0x001fffc000000000 -#define BM_38_52 BM_52_38 -#define BM_53_38 0x003fffc000000000 -#define BM_38_53 BM_53_38 -#define BM_54_38 0x007fffc000000000 -#define BM_38_54 BM_54_38 -#define BM_55_38 0x00ffffc000000000 -#define BM_38_55 BM_55_38 -#define BM_56_38 0x01ffffc000000000 -#define BM_38_56 BM_56_38 -#define BM_57_38 0x03ffffc000000000 -#define BM_38_57 BM_57_38 -#define BM_58_38 0x07ffffc000000000 -#define BM_38_58 BM_58_38 -#define BM_59_38 0x0fffffc000000000 -#define BM_38_59 BM_59_38 -#define BM_60_38 0x1fffffc000000000 -#define BM_38_60 BM_60_38 -#define BM_61_38 0x3fffffc000000000 -#define BM_38_61 BM_61_38 -#define BM_62_38 0x7fffffc000000000 -#define BM_38_62 BM_62_38 -#define BM_63_38 0xffffffc000000000 -#define BM_38_63 BM_63_38 -#define BM_39_39 0x0000008000000000 -#define BM_40_39 0x0000018000000000 -#define BM_39_40 BM_40_39 -#define BM_41_39 0x0000038000000000 -#define BM_39_41 BM_41_39 -#define BM_42_39 0x0000078000000000 -#define BM_39_42 BM_42_39 -#define BM_43_39 0x00000f8000000000 -#define BM_39_43 BM_43_39 -#define BM_44_39 0x00001f8000000000 -#define BM_39_44 BM_44_39 -#define BM_45_39 0x00003f8000000000 -#define BM_39_45 BM_45_39 -#define BM_46_39 0x00007f8000000000 -#define BM_39_46 BM_46_39 -#define BM_47_39 0x0000ff8000000000 -#define BM_39_47 BM_47_39 -#define BM_48_39 0x0001ff8000000000 -#define BM_39_48 BM_48_39 -#define BM_49_39 0x0003ff8000000000 -#define BM_39_49 BM_49_39 -#define BM_50_39 0x0007ff8000000000 -#define BM_39_50 BM_50_39 -#define BM_51_39 0x000fff8000000000 -#define BM_39_51 BM_51_39 -#define BM_52_39 0x001fff8000000000 -#define BM_39_52 BM_52_39 -#define BM_53_39 0x003fff8000000000 -#define BM_39_53 BM_53_39 -#define BM_54_39 0x007fff8000000000 -#define BM_39_54 BM_54_39 -#define BM_55_39 0x00ffff8000000000 -#define BM_39_55 BM_55_39 -#define BM_56_39 0x01ffff8000000000 -#define BM_39_56 BM_56_39 -#define BM_57_39 0x03ffff8000000000 -#define BM_39_57 BM_57_39 -#define BM_58_39 0x07ffff8000000000 -#define BM_39_58 BM_58_39 -#define BM_59_39 0x0fffff8000000000 -#define BM_39_59 BM_59_39 -#define BM_60_39 0x1fffff8000000000 -#define BM_39_60 BM_60_39 -#define BM_61_39 0x3fffff8000000000 -#define BM_39_61 BM_61_39 -#define BM_62_39 0x7fffff8000000000 -#define BM_39_62 BM_62_39 -#define BM_63_39 0xffffff8000000000 -#define BM_39_63 BM_63_39 -#define BM_40_40 0x0000010000000000 -#define BM_41_40 0x0000030000000000 -#define BM_40_41 BM_41_40 -#define BM_42_40 0x0000070000000000 -#define BM_40_42 BM_42_40 -#define BM_43_40 0x00000f0000000000 -#define BM_40_43 BM_43_40 -#define BM_44_40 0x00001f0000000000 -#define BM_40_44 BM_44_40 -#define BM_45_40 0x00003f0000000000 -#define BM_40_45 BM_45_40 -#define BM_46_40 0x00007f0000000000 -#define BM_40_46 BM_46_40 -#define BM_47_40 0x0000ff0000000000 -#define BM_40_47 BM_47_40 -#define BM_48_40 0x0001ff0000000000 -#define BM_40_48 BM_48_40 -#define BM_49_40 0x0003ff0000000000 -#define BM_40_49 BM_49_40 -#define BM_50_40 0x0007ff0000000000 -#define BM_40_50 BM_50_40 -#define BM_51_40 0x000fff0000000000 -#define BM_40_51 BM_51_40 -#define BM_52_40 0x001fff0000000000 -#define BM_40_52 BM_52_40 -#define BM_53_40 0x003fff0000000000 -#define BM_40_53 BM_53_40 -#define BM_54_40 0x007fff0000000000 -#define BM_40_54 BM_54_40 -#define BM_55_40 0x00ffff0000000000 -#define BM_40_55 BM_55_40 -#define BM_56_40 0x01ffff0000000000 -#define BM_40_56 BM_56_40 -#define BM_57_40 0x03ffff0000000000 -#define BM_40_57 BM_57_40 -#define BM_58_40 0x07ffff0000000000 -#define BM_40_58 BM_58_40 -#define BM_59_40 0x0fffff0000000000 -#define BM_40_59 BM_59_40 -#define BM_60_40 0x1fffff0000000000 -#define BM_40_60 BM_60_40 -#define BM_61_40 0x3fffff0000000000 -#define BM_40_61 BM_61_40 -#define BM_62_40 0x7fffff0000000000 -#define BM_40_62 BM_62_40 -#define BM_63_40 0xffffff0000000000 -#define BM_40_63 BM_63_40 -#define BM_41_41 0x0000020000000000 -#define BM_42_41 0x0000060000000000 -#define BM_41_42 BM_42_41 -#define BM_43_41 0x00000e0000000000 -#define BM_41_43 BM_43_41 -#define BM_44_41 0x00001e0000000000 -#define BM_41_44 BM_44_41 -#define BM_45_41 0x00003e0000000000 -#define BM_41_45 BM_45_41 -#define BM_46_41 0x00007e0000000000 -#define BM_41_46 BM_46_41 -#define BM_47_41 0x0000fe0000000000 -#define BM_41_47 BM_47_41 -#define BM_48_41 0x0001fe0000000000 -#define BM_41_48 BM_48_41 -#define BM_49_41 0x0003fe0000000000 -#define BM_41_49 BM_49_41 -#define BM_50_41 0x0007fe0000000000 -#define BM_41_50 BM_50_41 -#define BM_51_41 0x000ffe0000000000 -#define BM_41_51 BM_51_41 -#define BM_52_41 0x001ffe0000000000 -#define BM_41_52 BM_52_41 -#define BM_53_41 0x003ffe0000000000 -#define BM_41_53 BM_53_41 -#define BM_54_41 0x007ffe0000000000 -#define BM_41_54 BM_54_41 -#define BM_55_41 0x00fffe0000000000 -#define BM_41_55 BM_55_41 -#define BM_56_41 0x01fffe0000000000 -#define BM_41_56 BM_56_41 -#define BM_57_41 0x03fffe0000000000 -#define BM_41_57 BM_57_41 -#define BM_58_41 0x07fffe0000000000 -#define BM_41_58 BM_58_41 -#define BM_59_41 0x0ffffe0000000000 -#define BM_41_59 BM_59_41 -#define BM_60_41 0x1ffffe0000000000 -#define BM_41_60 BM_60_41 -#define BM_61_41 0x3ffffe0000000000 -#define BM_41_61 BM_61_41 -#define BM_62_41 0x7ffffe0000000000 -#define BM_41_62 BM_62_41 -#define BM_63_41 0xfffffe0000000000 -#define BM_41_63 BM_63_41 -#define BM_42_42 0x0000040000000000 -#define BM_43_42 0x00000c0000000000 -#define BM_42_43 BM_43_42 -#define BM_44_42 0x00001c0000000000 -#define BM_42_44 BM_44_42 -#define BM_45_42 0x00003c0000000000 -#define BM_42_45 BM_45_42 -#define BM_46_42 0x00007c0000000000 -#define BM_42_46 BM_46_42 -#define BM_47_42 0x0000fc0000000000 -#define BM_42_47 BM_47_42 -#define BM_48_42 0x0001fc0000000000 -#define BM_42_48 BM_48_42 -#define BM_49_42 0x0003fc0000000000 -#define BM_42_49 BM_49_42 -#define BM_50_42 0x0007fc0000000000 -#define BM_42_50 BM_50_42 -#define BM_51_42 0x000ffc0000000000 -#define BM_42_51 BM_51_42 -#define BM_52_42 0x001ffc0000000000 -#define BM_42_52 BM_52_42 -#define BM_53_42 0x003ffc0000000000 -#define BM_42_53 BM_53_42 -#define BM_54_42 0x007ffc0000000000 -#define BM_42_54 BM_54_42 -#define BM_55_42 0x00fffc0000000000 -#define BM_42_55 BM_55_42 -#define BM_56_42 0x01fffc0000000000 -#define BM_42_56 BM_56_42 -#define BM_57_42 0x03fffc0000000000 -#define BM_42_57 BM_57_42 -#define BM_58_42 0x07fffc0000000000 -#define BM_42_58 BM_58_42 -#define BM_59_42 0x0ffffc0000000000 -#define BM_42_59 BM_59_42 -#define BM_60_42 0x1ffffc0000000000 -#define BM_42_60 BM_60_42 -#define BM_61_42 0x3ffffc0000000000 -#define BM_42_61 BM_61_42 -#define BM_62_42 0x7ffffc0000000000 -#define BM_42_62 BM_62_42 -#define BM_63_42 0xfffffc0000000000 -#define BM_42_63 BM_63_42 -#define BM_43_43 0x0000080000000000 -#define BM_44_43 0x0000180000000000 -#define BM_43_44 BM_44_43 -#define BM_45_43 0x0000380000000000 -#define BM_43_45 BM_45_43 -#define BM_46_43 0x0000780000000000 -#define BM_43_46 BM_46_43 -#define BM_47_43 0x0000f80000000000 -#define BM_43_47 BM_47_43 -#define BM_48_43 0x0001f80000000000 -#define BM_43_48 BM_48_43 -#define BM_49_43 0x0003f80000000000 -#define BM_43_49 BM_49_43 -#define BM_50_43 0x0007f80000000000 -#define BM_43_50 BM_50_43 -#define BM_51_43 0x000ff80000000000 -#define BM_43_51 BM_51_43 -#define BM_52_43 0x001ff80000000000 -#define BM_43_52 BM_52_43 -#define BM_53_43 0x003ff80000000000 -#define BM_43_53 BM_53_43 -#define BM_54_43 0x007ff80000000000 -#define BM_43_54 BM_54_43 -#define BM_55_43 0x00fff80000000000 -#define BM_43_55 BM_55_43 -#define BM_56_43 0x01fff80000000000 -#define BM_43_56 BM_56_43 -#define BM_57_43 0x03fff80000000000 -#define BM_43_57 BM_57_43 -#define BM_58_43 0x07fff80000000000 -#define BM_43_58 BM_58_43 -#define BM_59_43 0x0ffff80000000000 -#define BM_43_59 BM_59_43 -#define BM_60_43 0x1ffff80000000000 -#define BM_43_60 BM_60_43 -#define BM_61_43 0x3ffff80000000000 -#define BM_43_61 BM_61_43 -#define BM_62_43 0x7ffff80000000000 -#define BM_43_62 BM_62_43 -#define BM_63_43 0xfffff80000000000 -#define BM_43_63 BM_63_43 -#define BM_44_44 0x0000100000000000 -#define BM_45_44 0x0000300000000000 -#define BM_44_45 BM_45_44 -#define BM_46_44 0x0000700000000000 -#define BM_44_46 BM_46_44 -#define BM_47_44 0x0000f00000000000 -#define BM_44_47 BM_47_44 -#define BM_48_44 0x0001f00000000000 -#define BM_44_48 BM_48_44 -#define BM_49_44 0x0003f00000000000 -#define BM_44_49 BM_49_44 -#define BM_50_44 0x0007f00000000000 -#define BM_44_50 BM_50_44 -#define BM_51_44 0x000ff00000000000 -#define BM_44_51 BM_51_44 -#define BM_52_44 0x001ff00000000000 -#define BM_44_52 BM_52_44 -#define BM_53_44 0x003ff00000000000 -#define BM_44_53 BM_53_44 -#define BM_54_44 0x007ff00000000000 -#define BM_44_54 BM_54_44 -#define BM_55_44 0x00fff00000000000 -#define BM_44_55 BM_55_44 -#define BM_56_44 0x01fff00000000000 -#define BM_44_56 BM_56_44 -#define BM_57_44 0x03fff00000000000 -#define BM_44_57 BM_57_44 -#define BM_58_44 0x07fff00000000000 -#define BM_44_58 BM_58_44 -#define BM_59_44 0x0ffff00000000000 -#define BM_44_59 BM_59_44 -#define BM_60_44 0x1ffff00000000000 -#define BM_44_60 BM_60_44 -#define BM_61_44 0x3ffff00000000000 -#define BM_44_61 BM_61_44 -#define BM_62_44 0x7ffff00000000000 -#define BM_44_62 BM_62_44 -#define BM_63_44 0xfffff00000000000 -#define BM_44_63 BM_63_44 -#define BM_45_45 0x0000200000000000 -#define BM_46_45 0x0000600000000000 -#define BM_45_46 BM_46_45 -#define BM_47_45 0x0000e00000000000 -#define BM_45_47 BM_47_45 -#define BM_48_45 0x0001e00000000000 -#define BM_45_48 BM_48_45 -#define BM_49_45 0x0003e00000000000 -#define BM_45_49 BM_49_45 -#define BM_50_45 0x0007e00000000000 -#define BM_45_50 BM_50_45 -#define BM_51_45 0x000fe00000000000 -#define BM_45_51 BM_51_45 -#define BM_52_45 0x001fe00000000000 -#define BM_45_52 BM_52_45 -#define BM_53_45 0x003fe00000000000 -#define BM_45_53 BM_53_45 -#define BM_54_45 0x007fe00000000000 -#define BM_45_54 BM_54_45 -#define BM_55_45 0x00ffe00000000000 -#define BM_45_55 BM_55_45 -#define BM_56_45 0x01ffe00000000000 -#define BM_45_56 BM_56_45 -#define BM_57_45 0x03ffe00000000000 -#define BM_45_57 BM_57_45 -#define BM_58_45 0x07ffe00000000000 -#define BM_45_58 BM_58_45 -#define BM_59_45 0x0fffe00000000000 -#define BM_45_59 BM_59_45 -#define BM_60_45 0x1fffe00000000000 -#define BM_45_60 BM_60_45 -#define BM_61_45 0x3fffe00000000000 -#define BM_45_61 BM_61_45 -#define BM_62_45 0x7fffe00000000000 -#define BM_45_62 BM_62_45 -#define BM_63_45 0xffffe00000000000 -#define BM_45_63 BM_63_45 -#define BM_46_46 0x0000400000000000 -#define BM_47_46 0x0000c00000000000 -#define BM_46_47 BM_47_46 -#define BM_48_46 0x0001c00000000000 -#define BM_46_48 BM_48_46 -#define BM_49_46 0x0003c00000000000 -#define BM_46_49 BM_49_46 -#define BM_50_46 0x0007c00000000000 -#define BM_46_50 BM_50_46 -#define BM_51_46 0x000fc00000000000 -#define BM_46_51 BM_51_46 -#define BM_52_46 0x001fc00000000000 -#define BM_46_52 BM_52_46 -#define BM_53_46 0x003fc00000000000 -#define BM_46_53 BM_53_46 -#define BM_54_46 0x007fc00000000000 -#define BM_46_54 BM_54_46 -#define BM_55_46 0x00ffc00000000000 -#define BM_46_55 BM_55_46 -#define BM_56_46 0x01ffc00000000000 -#define BM_46_56 BM_56_46 -#define BM_57_46 0x03ffc00000000000 -#define BM_46_57 BM_57_46 -#define BM_58_46 0x07ffc00000000000 -#define BM_46_58 BM_58_46 -#define BM_59_46 0x0fffc00000000000 -#define BM_46_59 BM_59_46 -#define BM_60_46 0x1fffc00000000000 -#define BM_46_60 BM_60_46 -#define BM_61_46 0x3fffc00000000000 -#define BM_46_61 BM_61_46 -#define BM_62_46 0x7fffc00000000000 -#define BM_46_62 BM_62_46 -#define BM_63_46 0xffffc00000000000 -#define BM_46_63 BM_63_46 -#define BM_47_47 0x0000800000000000 -#define BM_48_47 0x0001800000000000 -#define BM_47_48 BM_48_47 -#define BM_49_47 0x0003800000000000 -#define BM_47_49 BM_49_47 -#define BM_50_47 0x0007800000000000 -#define BM_47_50 BM_50_47 -#define BM_51_47 0x000f800000000000 -#define BM_47_51 BM_51_47 -#define BM_52_47 0x001f800000000000 -#define BM_47_52 BM_52_47 -#define BM_53_47 0x003f800000000000 -#define BM_47_53 BM_53_47 -#define BM_54_47 0x007f800000000000 -#define BM_47_54 BM_54_47 -#define BM_55_47 0x00ff800000000000 -#define BM_47_55 BM_55_47 -#define BM_56_47 0x01ff800000000000 -#define BM_47_56 BM_56_47 -#define BM_57_47 0x03ff800000000000 -#define BM_47_57 BM_57_47 -#define BM_58_47 0x07ff800000000000 -#define BM_47_58 BM_58_47 -#define BM_59_47 0x0fff800000000000 -#define BM_47_59 BM_59_47 -#define BM_60_47 0x1fff800000000000 -#define BM_47_60 BM_60_47 -#define BM_61_47 0x3fff800000000000 -#define BM_47_61 BM_61_47 -#define BM_62_47 0x7fff800000000000 -#define BM_47_62 BM_62_47 -#define BM_63_47 0xffff800000000000 -#define BM_47_63 BM_63_47 -#define BM_48_48 0x0001000000000000 -#define BM_49_48 0x0003000000000000 -#define BM_48_49 BM_49_48 -#define BM_50_48 0x0007000000000000 -#define BM_48_50 BM_50_48 -#define BM_51_48 0x000f000000000000 -#define BM_48_51 BM_51_48 -#define BM_52_48 0x001f000000000000 -#define BM_48_52 BM_52_48 -#define BM_53_48 0x003f000000000000 -#define BM_48_53 BM_53_48 -#define BM_54_48 0x007f000000000000 -#define BM_48_54 BM_54_48 -#define BM_55_48 0x00ff000000000000 -#define BM_48_55 BM_55_48 -#define BM_56_48 0x01ff000000000000 -#define BM_48_56 BM_56_48 -#define BM_57_48 0x03ff000000000000 -#define BM_48_57 BM_57_48 -#define BM_58_48 0x07ff000000000000 -#define BM_48_58 BM_58_48 -#define BM_59_48 0x0fff000000000000 -#define BM_48_59 BM_59_48 -#define BM_60_48 0x1fff000000000000 -#define BM_48_60 BM_60_48 -#define BM_61_48 0x3fff000000000000 -#define BM_48_61 BM_61_48 -#define BM_62_48 0x7fff000000000000 -#define BM_48_62 BM_62_48 -#define BM_63_48 0xffff000000000000 -#define BM_48_63 BM_63_48 -#define BM_49_49 0x0002000000000000 -#define BM_50_49 0x0006000000000000 -#define BM_49_50 BM_50_49 -#define BM_51_49 0x000e000000000000 -#define BM_49_51 BM_51_49 -#define BM_52_49 0x001e000000000000 -#define BM_49_52 BM_52_49 -#define BM_53_49 0x003e000000000000 -#define BM_49_53 BM_53_49 -#define BM_54_49 0x007e000000000000 -#define BM_49_54 BM_54_49 -#define BM_55_49 0x00fe000000000000 -#define BM_49_55 BM_55_49 -#define BM_56_49 0x01fe000000000000 -#define BM_49_56 BM_56_49 -#define BM_57_49 0x03fe000000000000 -#define BM_49_57 BM_57_49 -#define BM_58_49 0x07fe000000000000 -#define BM_49_58 BM_58_49 -#define BM_59_49 0x0ffe000000000000 -#define BM_49_59 BM_59_49 -#define BM_60_49 0x1ffe000000000000 -#define BM_49_60 BM_60_49 -#define BM_61_49 0x3ffe000000000000 -#define BM_49_61 BM_61_49 -#define BM_62_49 0x7ffe000000000000 -#define BM_49_62 BM_62_49 -#define BM_63_49 0xfffe000000000000 -#define BM_49_63 BM_63_49 -#define BM_50_50 0x0004000000000000 -#define BM_51_50 0x000c000000000000 -#define BM_50_51 BM_51_50 -#define BM_52_50 0x001c000000000000 -#define BM_50_52 BM_52_50 -#define BM_53_50 0x003c000000000000 -#define BM_50_53 BM_53_50 -#define BM_54_50 0x007c000000000000 -#define BM_50_54 BM_54_50 -#define BM_55_50 0x00fc000000000000 -#define BM_50_55 BM_55_50 -#define BM_56_50 0x01fc000000000000 -#define BM_50_56 BM_56_50 -#define BM_57_50 0x03fc000000000000 -#define BM_50_57 BM_57_50 -#define BM_58_50 0x07fc000000000000 -#define BM_50_58 BM_58_50 -#define BM_59_50 0x0ffc000000000000 -#define BM_50_59 BM_59_50 -#define BM_60_50 0x1ffc000000000000 -#define BM_50_60 BM_60_50 -#define BM_61_50 0x3ffc000000000000 -#define BM_50_61 BM_61_50 -#define BM_62_50 0x7ffc000000000000 -#define BM_50_62 BM_62_50 -#define BM_63_50 0xfffc000000000000 -#define BM_50_63 BM_63_50 -#define BM_51_51 0x0008000000000000 -#define BM_52_51 0x0018000000000000 -#define BM_51_52 BM_52_51 -#define BM_53_51 0x0038000000000000 -#define BM_51_53 BM_53_51 -#define BM_54_51 0x0078000000000000 -#define BM_51_54 BM_54_51 -#define BM_55_51 0x00f8000000000000 -#define BM_51_55 BM_55_51 -#define BM_56_51 0x01f8000000000000 -#define BM_51_56 BM_56_51 -#define BM_57_51 0x03f8000000000000 -#define BM_51_57 BM_57_51 -#define BM_58_51 0x07f8000000000000 -#define BM_51_58 BM_58_51 -#define BM_59_51 0x0ff8000000000000 -#define BM_51_59 BM_59_51 -#define BM_60_51 0x1ff8000000000000 -#define BM_51_60 BM_60_51 -#define BM_61_51 0x3ff8000000000000 -#define BM_51_61 BM_61_51 -#define BM_62_51 0x7ff8000000000000 -#define BM_51_62 BM_62_51 -#define BM_63_51 0xfff8000000000000 -#define BM_51_63 BM_63_51 -#define BM_52_52 0x0010000000000000 -#define BM_53_52 0x0030000000000000 -#define BM_52_53 BM_53_52 -#define BM_54_52 0x0070000000000000 -#define BM_52_54 BM_54_52 -#define BM_55_52 0x00f0000000000000 -#define BM_52_55 BM_55_52 -#define BM_56_52 0x01f0000000000000 -#define BM_52_56 BM_56_52 -#define BM_57_52 0x03f0000000000000 -#define BM_52_57 BM_57_52 -#define BM_58_52 0x07f0000000000000 -#define BM_52_58 BM_58_52 -#define BM_59_52 0x0ff0000000000000 -#define BM_52_59 BM_59_52 -#define BM_60_52 0x1ff0000000000000 -#define BM_52_60 BM_60_52 -#define BM_61_52 0x3ff0000000000000 -#define BM_52_61 BM_61_52 -#define BM_62_52 0x7ff0000000000000 -#define BM_52_62 BM_62_52 -#define BM_63_52 0xfff0000000000000 -#define BM_52_63 BM_63_52 -#define BM_53_53 0x0020000000000000 -#define BM_54_53 0x0060000000000000 -#define BM_53_54 BM_54_53 -#define BM_55_53 0x00e0000000000000 -#define BM_53_55 BM_55_53 -#define BM_56_53 0x01e0000000000000 -#define BM_53_56 BM_56_53 -#define BM_57_53 0x03e0000000000000 -#define BM_53_57 BM_57_53 -#define BM_58_53 0x07e0000000000000 -#define BM_53_58 BM_58_53 -#define BM_59_53 0x0fe0000000000000 -#define BM_53_59 BM_59_53 -#define BM_60_53 0x1fe0000000000000 -#define BM_53_60 BM_60_53 -#define BM_61_53 0x3fe0000000000000 -#define BM_53_61 BM_61_53 -#define BM_62_53 0x7fe0000000000000 -#define BM_53_62 BM_62_53 -#define BM_63_53 0xffe0000000000000 -#define BM_53_63 BM_63_53 -#define BM_54_54 0x0040000000000000 -#define BM_55_54 0x00c0000000000000 -#define BM_54_55 BM_55_54 -#define BM_56_54 0x01c0000000000000 -#define BM_54_56 BM_56_54 -#define BM_57_54 0x03c0000000000000 -#define BM_54_57 BM_57_54 -#define BM_58_54 0x07c0000000000000 -#define BM_54_58 BM_58_54 -#define BM_59_54 0x0fc0000000000000 -#define BM_54_59 BM_59_54 -#define BM_60_54 0x1fc0000000000000 -#define BM_54_60 BM_60_54 -#define BM_61_54 0x3fc0000000000000 -#define BM_54_61 BM_61_54 -#define BM_62_54 0x7fc0000000000000 -#define BM_54_62 BM_62_54 -#define BM_63_54 0xffc0000000000000 -#define BM_54_63 BM_63_54 -#define BM_55_55 0x0080000000000000 -#define BM_56_55 0x0180000000000000 -#define BM_55_56 BM_56_55 -#define BM_57_55 0x0380000000000000 -#define BM_55_57 BM_57_55 -#define BM_58_55 0x0780000000000000 -#define BM_55_58 BM_58_55 -#define BM_59_55 0x0f80000000000000 -#define BM_55_59 BM_59_55 -#define BM_60_55 0x1f80000000000000 -#define BM_55_60 BM_60_55 -#define BM_61_55 0x3f80000000000000 -#define BM_55_61 BM_61_55 -#define BM_62_55 0x7f80000000000000 -#define BM_55_62 BM_62_55 -#define BM_63_55 0xff80000000000000 -#define BM_55_63 BM_63_55 -#define BM_56_56 0x0100000000000000 -#define BM_57_56 0x0300000000000000 -#define BM_56_57 BM_57_56 -#define BM_58_56 0x0700000000000000 -#define BM_56_58 BM_58_56 -#define BM_59_56 0x0f00000000000000 -#define BM_56_59 BM_59_56 -#define BM_60_56 0x1f00000000000000 -#define BM_56_60 BM_60_56 -#define BM_61_56 0x3f00000000000000 -#define BM_56_61 BM_61_56 -#define BM_62_56 0x7f00000000000000 -#define BM_56_62 BM_62_56 -#define BM_63_56 0xff00000000000000 -#define BM_56_63 BM_63_56 -#define BM_57_57 0x0200000000000000 -#define BM_58_57 0x0600000000000000 -#define BM_57_58 BM_58_57 -#define BM_59_57 0x0e00000000000000 -#define BM_57_59 BM_59_57 -#define BM_60_57 0x1e00000000000000 -#define BM_57_60 BM_60_57 -#define BM_61_57 0x3e00000000000000 -#define BM_57_61 BM_61_57 -#define BM_62_57 0x7e00000000000000 -#define BM_57_62 BM_62_57 -#define BM_63_57 0xfe00000000000000 -#define BM_57_63 BM_63_57 -#define BM_58_58 0x0400000000000000 -#define BM_59_58 0x0c00000000000000 -#define BM_58_59 BM_59_58 -#define BM_60_58 0x1c00000000000000 -#define BM_58_60 BM_60_58 -#define BM_61_58 0x3c00000000000000 -#define BM_58_61 BM_61_58 -#define BM_62_58 0x7c00000000000000 -#define BM_58_62 BM_62_58 -#define BM_63_58 0xfc00000000000000 -#define BM_58_63 BM_63_58 -#define BM_59_59 0x0800000000000000 -#define BM_60_59 0x1800000000000000 -#define BM_59_60 BM_60_59 -#define BM_61_59 0x3800000000000000 -#define BM_59_61 BM_61_59 -#define BM_62_59 0x7800000000000000 -#define BM_59_62 BM_62_59 -#define BM_63_59 0xf800000000000000 -#define BM_59_63 BM_63_59 -#define BM_60_60 0x1000000000000000 -#define BM_61_60 0x3000000000000000 -#define BM_60_61 BM_61_60 -#define BM_62_60 0x7000000000000000 -#define BM_60_62 BM_62_60 -#define BM_63_60 0xf000000000000000 -#define BM_60_63 BM_63_60 -#define BM_61_61 0x2000000000000000 -#define BM_62_61 0x6000000000000000 -#define BM_61_62 BM_62_61 -#define BM_63_61 0xe000000000000000 -#define BM_61_63 BM_63_61 -#define BM_62_62 0x4000000000000000 -#define BM_63_62 0xc000000000000000 -#define BM_62_63 BM_63_62 -#define BM_63_63 0x8000000000000000 - -#endif - -#endif /* __ASM_TX4927_TX4927_MIPS_H */ From abb4ae4630633573862934173e5f506771c5d6b1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:03 +0100 Subject: [PATCH 2216/2804] [MIPS] PCI: Always enable CONFIG_PCI_DOMAINS The cost is just too low. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 +--- include/asm-mips/pci.h | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 6648f9b914e7..ebc7b4b45c84 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -381,7 +381,6 @@ config SGI_IP27 select SYS_HAS_EARLY_PRINTK select HW_HAS_PCI select NR_CPUS_DEFAULT_64 - select PCI_DOMAINS select SYS_HAS_CPU_R10000 select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN @@ -513,7 +512,6 @@ config SIBYTE_BIGSUR select BOOT_ELF32 select DMA_COHERENT select NR_CPUS_DEFAULT_4 - select PCI_DOMAINS select SIBYTE_BCM1x80 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -1808,6 +1806,7 @@ config HW_HAS_PCI config PCI bool "Support for PCI controller" depends on HW_HAS_PCI + select PCI_DOMAINS help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside @@ -1821,7 +1820,6 @@ config PCI config PCI_DOMAINS bool - depends on PCI source "drivers/pci/Kconfig" diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h index 4fcc185cb2d1..301ff2f28012 100644 --- a/include/asm-mips/pci.h +++ b/include/asm-mips/pci.h @@ -150,8 +150,6 @@ pcibios_select_root(struct pci_dev *pdev, struct resource *res) return root; } -#ifdef CONFIG_PCI_DOMAINS - #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index static inline int pci_proc_domain(struct pci_bus *bus) @@ -160,8 +158,6 @@ static inline int pci_proc_domain(struct pci_bus *bus) return hose->need_domain_info; } -#endif /* CONFIG_PCI_DOMAINS */ - #endif /* __KERNEL__ */ /* implement the pci_ DMA API in terms of the generic device dma_ one */ From 7ca16d269a1a4b96d98968b48f137977bcab1522 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:03 +0100 Subject: [PATCH 2217/2804] [MIPS] floppy: Rewrite fd_cacheflush() to use dma_cache_sync(). Signed-off-by: Ralf Baechle --- include/asm-mips/floppy.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/asm-mips/floppy.h b/include/asm-mips/floppy.h index aa1ef8b352cc..dcadd8562523 100644 --- a/include/asm-mips/floppy.h +++ b/include/asm-mips/floppy.h @@ -10,9 +10,11 @@ #ifndef _ASM_FLOPPY_H #define _ASM_FLOPPY_H +#include + static inline void fd_cacheflush(char * addr, long size) { - dma_cache_wback_inv((unsigned long)addr,size); + dma_cache_sync(NULL, addr, size, DMA_BIDIRECTIONAL); } #define MAX_BUFFER_SECTORS 24 From bcb0fd94633afde9c1f4f8aca43141ba2c78f04b Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Wed, 5 Sep 2007 17:44:50 +0100 Subject: [PATCH 2218/2804] [MIPS] Define known MIPS ISA overrides for Sibyte and Excite boards. Signed-Off-By: Thiemo Seufer Signed-off-by: Ralf Baechle --- include/asm-mips/mach-excite/cpu-feature-overrides.h | 5 +++++ include/asm-mips/mach-sibyte/cpu-feature-overrides.h | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/asm-mips/mach-excite/cpu-feature-overrides.h b/include/asm-mips/mach-excite/cpu-feature-overrides.h index 07f4322c235d..107104c3cd12 100644 --- a/include/asm-mips/mach-excite/cpu-feature-overrides.h +++ b/include/asm-mips/mach-excite/cpu-feature-overrides.h @@ -34,6 +34,11 @@ #define cpu_has_nofpuex 0 #define cpu_has_64bits 1 +#define cpu_has_mips32r1 0 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r1 0 +#define cpu_has_mips64r2 0 + #define cpu_has_inclusive_pcaches 0 #define cpu_dcache_line_size() 32 diff --git a/include/asm-mips/mach-sibyte/cpu-feature-overrides.h b/include/asm-mips/mach-sibyte/cpu-feature-overrides.h index 63d5bf649af1..1c1f92415b9a 100644 --- a/include/asm-mips/mach-sibyte/cpu-feature-overrides.h +++ b/include/asm-mips/mach-sibyte/cpu-feature-overrides.h @@ -9,7 +9,7 @@ #define __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H /* - * Sibyte are MIPS64 processors weired to a specific configuration + * Sibyte are MIPS64 processors wired to a specific configuration */ #define cpu_has_watch 1 #define cpu_has_mips16 0 @@ -33,6 +33,11 @@ #define cpu_has_nofpuex 0 #define cpu_has_64bits 1 +#define cpu_has_mips32r1 1 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r1 1 +#define cpu_has_mips64r2 0 + #define cpu_has_inclusive_pcaches 0 #define cpu_dcache_line_size() 32 From b47bd961e298aff8144a98bff38cf4de4a2834b9 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Sun, 9 Sep 2007 02:50:42 +0900 Subject: [PATCH 2219/2804] [MIPS] Kill redundant EXTRA_AFLAGS Kill redundant EXTRA_AFLAGS added after the commit d2af363cfb94f1bacb3e60327bc44a97881a38c2. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/lemote/lm2e/Makefile | 1 - arch/mips/sibyte/common/Makefile | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/mips/lemote/lm2e/Makefile b/arch/mips/lemote/lm2e/Makefile index dcaf6f4c3a37..d34671d1b899 100644 --- a/arch/mips/lemote/lm2e/Makefile +++ b/arch/mips/lemote/lm2e/Makefile @@ -4,5 +4,4 @@ obj-y += setup.o prom.o reset.o irq.o pci.o bonito-irq.o dbg_io.o mem.o -EXTRA_AFLAGS := $(CFLAGS) EXTRA_CFLAGS += -Werror diff --git a/arch/mips/sibyte/common/Makefile b/arch/mips/sibyte/common/Makefile index f8ae30066a05..48a91b9e5870 100644 --- a/arch/mips/sibyte/common/Makefile +++ b/arch/mips/sibyte/common/Makefile @@ -2,5 +2,4 @@ obj-y := obj-$(CONFIG_SIBYTE_TBPROF) += sb_tbprof.o -EXTRA_AFLAGS := $(CFLAGS) EXTRA_CFLAGS += -Werror From ec70f65e3b5309e7ac8b5508ff5657050c92b913 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:03 +0100 Subject: [PATCH 2220/2804] [MIPS] Kill useless volatile keyword Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 6379003f9d8d..3d033e1cd4f0 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1075,8 +1075,8 @@ void *set_except_vector(int n, void *addr) exception_handlers[n] = handler; if (n == 0 && cpu_has_divec) { - *(volatile u32 *)(ebase + 0x200) = 0x08000000 | - (0x03ffffff & (handler >> 2)); + *(u32 *)(ebase + 0x200) = 0x08000000 | + (0x03ffffff & (handler >> 2)); flush_icache_range(ebase + 0x200, ebase + 0x204); } return (void *)old_handler; From d80c1c0b2207ba326b2c06249dfebddf8ac863bd Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 13 Sep 2007 11:04:04 +0900 Subject: [PATCH 2221/2804] [MIPS] i8295 cleanups. o Move i8259 function declarations to include/asm-mips/i8259.h o Make i8259.c functions static where possible. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/kernel/i8259.c | 14 ++++++++------ include/asm-mips/hw_irq.h | 7 ------- include/asm-mips/i8259.h | 5 ++--- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 60021647cac1..b6e5bb41b06b 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -30,8 +30,10 @@ static int i8259A_auto_eoi = -1; DEFINE_SPINLOCK(i8259A_lock); -/* some platforms call this... */ -void mask_and_ack_8259A(unsigned int); +static void disable_8259A_irq(unsigned int irq); +static void enable_8259A_irq(unsigned int irq); +static void mask_and_ack_8259A(unsigned int irq); +static void init_8259A(int auto_eoi); static struct irq_chip i8259A_chip = { .name = "XT-PIC", @@ -56,7 +58,7 @@ static unsigned int cached_irq_mask = 0xffff; #define cached_master_mask (cached_irq_mask) #define cached_slave_mask (cached_irq_mask >> 8) -void disable_8259A_irq(unsigned int irq) +static void disable_8259A_irq(unsigned int irq) { unsigned int mask; unsigned long flags; @@ -72,7 +74,7 @@ void disable_8259A_irq(unsigned int irq) spin_unlock_irqrestore(&i8259A_lock, flags); } -void enable_8259A_irq(unsigned int irq) +static void enable_8259A_irq(unsigned int irq) { unsigned int mask; unsigned long flags; @@ -142,7 +144,7 @@ static inline int i8259A_irq_real(unsigned int irq) * first, _then_ send the EOI, and the order of EOI * to the two 8259s is important! */ -void mask_and_ack_8259A(unsigned int irq) +static void mask_and_ack_8259A(unsigned int irq) { unsigned int irqmask; unsigned long flags; @@ -256,7 +258,7 @@ static int __init i8259A_init_sysfs(void) device_initcall(i8259A_init_sysfs); -void init_8259A(int auto_eoi) +static void init_8259A(int auto_eoi) { unsigned long flags; diff --git a/include/asm-mips/hw_irq.h b/include/asm-mips/hw_irq.h index 458d9fdc76bf..aca05a43a97b 100644 --- a/include/asm-mips/hw_irq.h +++ b/include/asm-mips/hw_irq.h @@ -8,15 +8,8 @@ #ifndef __ASM_HW_IRQ_H #define __ASM_HW_IRQ_H -#include #include -extern void disable_8259A_irq(unsigned int irq); -extern void enable_8259A_irq(unsigned int irq); -extern int i8259A_irq_pending(unsigned int irq); -extern void make_8259A_irq(unsigned int irq); -extern void init_8259A(int aeoi); - extern atomic_t irq_err_count; /* diff --git a/include/asm-mips/i8259.h b/include/asm-mips/i8259.h index e88a01607fea..8572a2d90484 100644 --- a/include/asm-mips/i8259.h +++ b/include/asm-mips/i8259.h @@ -37,9 +37,8 @@ extern spinlock_t i8259A_lock; -extern void init_8259A(int auto_eoi); -extern void enable_8259A_irq(unsigned int irq); -extern void disable_8259A_irq(unsigned int irq); +extern int i8259A_irq_pending(unsigned int irq); +extern void make_8259A_irq(unsigned int irq); extern void init_i8259_irqs(void); From 718f05f6ddc171a90fb7a277be6f6f65b4ca82be Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Wed, 12 Sep 2007 23:19:45 +0900 Subject: [PATCH 2222/2804] [MIPS] GT64120: Remove unused definitions Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- include/asm-mips/mach-mips/mach-gt64120.h | 9 --------- include/asm-mips/mach-wrppmc/mach-gt64120.h | 1 - 2 files changed, 10 deletions(-) diff --git a/include/asm-mips/mach-mips/mach-gt64120.h b/include/asm-mips/mach-mips/mach-gt64120.h index 511f7cf3a6be..0f863148f3b6 100644 --- a/include/asm-mips/mach-mips/mach-gt64120.h +++ b/include/asm-mips/mach-mips/mach-gt64120.h @@ -16,13 +16,4 @@ extern unsigned long _pcictrl_gt64120; */ #define GT64120_BASE _pcictrl_gt64120 -/* - * PCI Bus allocation - */ -#define GT_PCI_MEM_BASE 0x12000000UL -#define GT_PCI_MEM_SIZE 0x02000000UL -#define GT_PCI_IO_BASE 0x10000000UL -#define GT_PCI_IO_SIZE 0x02000000UL -#define GT_ISA_IO_BASE PCI_IO_BASE - #endif /* _ASM_MACH_MIPS_MACH_GT64120_DEP_H */ diff --git a/include/asm-mips/mach-wrppmc/mach-gt64120.h b/include/asm-mips/mach-wrppmc/mach-gt64120.h index ba9205a04582..00d8bf6164a9 100644 --- a/include/asm-mips/mach-wrppmc/mach-gt64120.h +++ b/include/asm-mips/mach-wrppmc/mach-gt64120.h @@ -43,7 +43,6 @@ #define GT_PCI_MEM_SIZE 0x02000000UL #define GT_PCI_IO_BASE 0x11000000UL #define GT_PCI_IO_SIZE 0x02000000UL -#define GT_ISA_IO_BASE PCI_IO_BASE /* * PCI interrupts will come in on either the INTA or INTD interrups lines, From d5ab1a6910fe850fa092888f210cf6c43136a7ab Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 13 Sep 2007 23:51:26 +0900 Subject: [PATCH 2223/2804] [MIPS] Add GT641xx IRQ routines. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 + arch/mips/cobalt/irq.c | 118 ++++++----------------- arch/mips/cobalt/rtc.c | 5 +- arch/mips/cobalt/serial.c | 7 +- arch/mips/cobalt/setup.c | 9 +- arch/mips/kernel/Makefile | 1 + arch/mips/kernel/irq-gt641xx.c | 131 ++++++++++++++++++++++++++ arch/mips/pci/fixup-cobalt.c | 23 ++--- include/asm-mips/irq_gt641xx.h | 60 ++++++++++++ include/asm-mips/mach-cobalt/cobalt.h | 26 ----- include/asm-mips/mach-cobalt/irq.h | 58 ++++++++++++ 11 files changed, 307 insertions(+), 135 deletions(-) create mode 100644 arch/mips/kernel/irq-gt641xx.c create mode 100644 include/asm-mips/irq_gt641xx.h create mode 100644 include/asm-mips/mach-cobalt/irq.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ebc7b4b45c84..90b409d06153 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -64,6 +64,7 @@ config MIPS_COBALT select HW_HAS_PCI select I8259 select IRQ_CPU + select IRQ_GT641XX select PCI_GT64XXX_PCI0 select SYS_HAS_CPU_NEVADA select SYS_HAS_EARLY_PRINTK @@ -806,6 +807,9 @@ config IRQ_MSP_CIC config IRQ_TXX9 bool +config IRQ_GT641XX + bool + config MIPS_BOARDS_GEN bool diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c index 48763cd10eaa..ac4fb912649d 100644 --- a/arch/mips/cobalt/irq.c +++ b/arch/mips/cobalt/irq.c @@ -15,104 +15,48 @@ #include #include +#include #include -#include - -/* - * We have two types of interrupts that we handle, ones that come in through - * the CPU interrupt lines, and ones that come in on the via chip. The CPU - * mappings are: - * - * 16 - Software interrupt 0 (unused) IE_SW0 - * 17 - Software interrupt 1 (unused) IE_SW1 - * 18 - Galileo chip (timer) IE_IRQ0 - * 19 - Tulip 0 + NCR SCSI IE_IRQ1 - * 20 - Tulip 1 IE_IRQ2 - * 21 - 16550 UART IE_IRQ3 - * 22 - VIA southbridge PIC IE_IRQ4 - * 23 - unused IE_IRQ5 - * - * The VIA chip is a master/slave 8259 setup and has the following interrupts: - * - * 8 - RTC - * 9 - PCI - * 14 - IDE0 - * 15 - IDE1 - */ - -static inline void galileo_irq(void) -{ - unsigned int mask, pending, devfn; - - mask = GT_READ(GT_INTRMASK_OFS); - pending = GT_READ(GT_INTRCAUSE_OFS) & mask; - - if (pending & GT_INTR_T0EXP_MSK) { - GT_WRITE(GT_INTRCAUSE_OFS, ~GT_INTR_T0EXP_MSK); - do_IRQ(COBALT_GALILEO_IRQ); - } else if (pending & GT_INTR_RETRYCTR0_MSK) { - devfn = GT_READ(GT_PCI0_CFGADDR_OFS) >> 8; - GT_WRITE(GT_INTRCAUSE_OFS, ~GT_INTR_RETRYCTR0_MSK); - printk(KERN_WARNING - "Galileo: PCI retry count exceeded (%02x.%u)\n", - PCI_SLOT(devfn), PCI_FUNC(devfn)); - } else { - GT_WRITE(GT_INTRMASK_OFS, mask & ~pending); - printk(KERN_WARNING - "Galileo: masking unexpected interrupt %08x\n", pending); - } -} - -static inline void via_pic_irq(void) -{ - int irq; - - irq = i8259_irq(); - if (irq >= 0) - do_IRQ(irq); -} +#include asmlinkage void plat_irq_dispatch(void) { - unsigned pending = read_c0_status() & read_c0_cause(); + unsigned pending = read_c0_status() & read_c0_cause() & ST0_IM; + int irq; - if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */ - galileo_irq(); - else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */ - via_pic_irq(); - else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */ - do_IRQ(COBALT_CPU_IRQ + 3); - else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */ - do_IRQ(COBALT_CPU_IRQ + 4); - else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */ - do_IRQ(COBALT_CPU_IRQ + 5); - else if (pending & CAUSEF_IP7) /* IRQ 23 */ - do_IRQ(COBALT_CPU_IRQ + 7); + if (pending & CAUSEF_IP2) + gt641xx_irq_dispatch(); + else if (pending & CAUSEF_IP6) { + irq = i8259_irq(); + if (irq < 0) + spurious_interrupt(); + else + do_IRQ(irq); + } else if (pending & CAUSEF_IP3) + do_IRQ(MIPS_CPU_IRQ_BASE + 3); + else if (pending & CAUSEF_IP4) + do_IRQ(MIPS_CPU_IRQ_BASE + 4); + else if (pending & CAUSEF_IP5) + do_IRQ(MIPS_CPU_IRQ_BASE + 5); + else if (pending & CAUSEF_IP7) + do_IRQ(MIPS_CPU_IRQ_BASE + 7); + else + spurious_interrupt(); } -static struct irqaction irq_via = { - .handler = no_action, - .mask = CPU_MASK_NONE, - .name = "cascade" +static struct irqaction cascade = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", }; void __init arch_init_irq(void) { - /* - * Mask all Galileo interrupts. The Galileo - * handler is set in cobalt_timer_setup() - */ - GT_WRITE(GT_INTRMASK_OFS, 0); + mips_cpu_irq_init(); + gt641xx_irq_init(); + init_i8259_irqs(); - init_i8259_irqs(); /* 0 ... 15 */ - mips_cpu_irq_init(); /* 16 ... 23 */ - - /* - * Mask all cpu interrupts - * (except IE4, we already masked those at VIA level) - */ - change_c0_status(ST0_IM, IE_IRQ4); - - setup_irq(COBALT_VIA_IRQ, &irq_via); + setup_irq(GT641XX_CASCADE_IRQ, &cascade); + setup_irq(I8259_CASCADE_IRQ, &cascade); } diff --git a/arch/mips/cobalt/rtc.c b/arch/mips/cobalt/rtc.c index 284daefc5c55..e70794b8bcba 100644 --- a/arch/mips/cobalt/rtc.c +++ b/arch/mips/cobalt/rtc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include static struct resource cobalt_rtc_resource[] __initdata = { @@ -29,8 +30,8 @@ static struct resource cobalt_rtc_resource[] __initdata = { .flags = IORESOURCE_IO, }, { - .start = 8, - .end = 8, + .start = RTC_IRQ, + .end = RTC_IRQ, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/mips/cobalt/serial.c b/arch/mips/cobalt/serial.c index 08e739704cc9..53b8d0d6da90 100644 --- a/arch/mips/cobalt/serial.c +++ b/arch/mips/cobalt/serial.c @@ -24,6 +24,7 @@ #include #include +#include static struct resource cobalt_uart_resource[] __initdata = { { @@ -32,15 +33,15 @@ static struct resource cobalt_uart_resource[] __initdata = { .flags = IORESOURCE_MEM, }, { - .start = COBALT_SERIAL_IRQ, - .end = COBALT_SERIAL_IRQ, + .start = SERIAL_IRQ, + .end = SERIAL_IRQ, .flags = IORESOURCE_IRQ, }, }; static struct plat_serial8250_port cobalt_serial8250_port[] = { { - .irq = COBALT_SERIAL_IRQ, + .irq = SERIAL_IRQ, .uartclk = 18432000, .iotype = UPIO_MEM, .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index 7abe45e78425..fc9cbb251edc 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -20,6 +20,7 @@ #include #include +#include extern void cobalt_machine_restart(char *command); extern void cobalt_machine_halt(void); @@ -45,14 +46,10 @@ void __init plat_timer_setup(struct irqaction *irq) /* Load timer value for HZ (TCLK is 50MHz) */ GT_WRITE(GT_TC0_OFS, 50*1000*1000 / HZ); - /* Enable timer */ + /* Enable timer0 */ GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); - /* Register interrupt */ - setup_irq(COBALT_GALILEO_IRQ, irq); - - /* Enable interrupt */ - GT_WRITE(GT_INTRMASK_OFS, GT_INTR_T0EXP_MSK | GT_READ(GT_INTRMASK_OFS)); + setup_irq(GT641XX_TIMER0_IRQ, irq); } /* diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 2fd96d95a39c..7851b4b447d0 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o +obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o obj-$(CONFIG_32BIT) += scall32-o32.o obj-$(CONFIG_64BIT) += scall64-64.o diff --git a/arch/mips/kernel/irq-gt641xx.c b/arch/mips/kernel/irq-gt641xx.c new file mode 100644 index 000000000000..1b81b131f43c --- /dev/null +++ b/arch/mips/kernel/irq-gt641xx.c @@ -0,0 +1,131 @@ +/* + * GT641xx IRQ routines. + * + * Copyright (C) 2007 Yoichi Yuasa + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include + +#include + +#define GT641XX_IRQ_TO_BIT(irq) (1U << (irq - GT641XX_IRQ_BASE)) + +static DEFINE_SPINLOCK(gt641xx_irq_lock); + +static void ack_gt641xx_irq(unsigned int irq) +{ + unsigned long flags; + u32 cause; + + spin_lock_irqsave(>641xx_irq_lock, flags); + cause = GT_READ(GT_INTRCAUSE_OFS); + cause &= ~GT641XX_IRQ_TO_BIT(irq); + GT_WRITE(GT_INTRCAUSE_OFS, cause); + spin_unlock_irqrestore(>641xx_irq_lock, flags); +} + +static void mask_gt641xx_irq(unsigned int irq) +{ + unsigned long flags; + u32 mask; + + spin_lock_irqsave(>641xx_irq_lock, flags); + mask = GT_READ(GT_INTRMASK_OFS); + mask &= ~GT641XX_IRQ_TO_BIT(irq); + GT_WRITE(GT_INTRMASK_OFS, mask); + spin_unlock_irqrestore(>641xx_irq_lock, flags); +} + +static void mask_ack_gt641xx_irq(unsigned int irq) +{ + unsigned long flags; + u32 cause, mask; + + spin_lock_irqsave(>641xx_irq_lock, flags); + mask = GT_READ(GT_INTRMASK_OFS); + mask &= ~GT641XX_IRQ_TO_BIT(irq); + GT_WRITE(GT_INTRMASK_OFS, mask); + + cause = GT_READ(GT_INTRCAUSE_OFS); + cause &= ~GT641XX_IRQ_TO_BIT(irq); + GT_WRITE(GT_INTRCAUSE_OFS, cause); + spin_unlock_irqrestore(>641xx_irq_lock, flags); +} + +static void unmask_gt641xx_irq(unsigned int irq) +{ + unsigned long flags; + u32 mask; + + spin_lock_irqsave(>641xx_irq_lock, flags); + mask = GT_READ(GT_INTRMASK_OFS); + mask |= GT641XX_IRQ_TO_BIT(irq); + GT_WRITE(GT_INTRMASK_OFS, mask); + spin_unlock_irqrestore(>641xx_irq_lock, flags); +} + +static struct irq_chip gt641xx_irq_chip = { + .name = "GT641xx", + .ack = ack_gt641xx_irq, + .mask = mask_gt641xx_irq, + .mask_ack = mask_ack_gt641xx_irq, + .unmask = unmask_gt641xx_irq, +}; + +void gt641xx_irq_dispatch(void) +{ + u32 cause, mask; + int i; + + cause = GT_READ(GT_INTRCAUSE_OFS); + mask = GT_READ(GT_INTRMASK_OFS); + cause &= mask; + + /* + * bit0 : logical or of all the interrupt bits. + * bit30: logical or of bits[29:26,20:1]. + * bit31: logical or of bits[25:1]. + */ + for (i = 1; i < 30; i++) { + if (cause & (1U << i)) { + do_IRQ(GT641XX_IRQ_BASE + i); + return; + } + } + + atomic_inc(&irq_err_count); +} + +void __init gt641xx_irq_init(void) +{ + int i; + + GT_WRITE(GT_INTRMASK_OFS, 0); + GT_WRITE(GT_INTRCAUSE_OFS, 0); + + /* + * bit0 : logical or of all the interrupt bits. + * bit30: logical or of bits[29:26,20:1]. + * bit31: logical or of bits[25:1]. + */ + for (i = 1; i < 30; i++) + set_irq_chip_and_handler(GT641XX_IRQ_BASE + i, + >641xx_irq_chip, handle_level_irq); +} diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c index 76b4f0ffb1e5..4eb5410f842a 100644 --- a/arch/mips/pci/fixup-cobalt.c +++ b/arch/mips/pci/fixup-cobalt.c @@ -18,6 +18,7 @@ #include #include +#include static void qube_raq_galileo_early_fixup(struct pci_dev *dev) { @@ -132,29 +133,29 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, static char irq_tab_qube1[] __initdata = { [COBALT_PCICONF_CPU] = 0, - [COBALT_PCICONF_ETH0] = COBALT_QUBE1_ETH0_IRQ, - [COBALT_PCICONF_RAQSCSI] = COBALT_SCSI_IRQ, + [COBALT_PCICONF_ETH0] = QUBE1_ETH0_IRQ, + [COBALT_PCICONF_RAQSCSI] = SCSI_IRQ, [COBALT_PCICONF_VIA] = 0, - [COBALT_PCICONF_PCISLOT] = COBALT_QUBE_SLOT_IRQ, + [COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ, [COBALT_PCICONF_ETH1] = 0 }; static char irq_tab_cobalt[] __initdata = { [COBALT_PCICONF_CPU] = 0, - [COBALT_PCICONF_ETH0] = COBALT_ETH0_IRQ, - [COBALT_PCICONF_RAQSCSI] = COBALT_SCSI_IRQ, + [COBALT_PCICONF_ETH0] = ETH0_IRQ, + [COBALT_PCICONF_RAQSCSI] = SCSI_IRQ, [COBALT_PCICONF_VIA] = 0, - [COBALT_PCICONF_PCISLOT] = COBALT_QUBE_SLOT_IRQ, - [COBALT_PCICONF_ETH1] = COBALT_ETH1_IRQ + [COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ, + [COBALT_PCICONF_ETH1] = ETH1_IRQ }; static char irq_tab_raq2[] __initdata = { [COBALT_PCICONF_CPU] = 0, - [COBALT_PCICONF_ETH0] = COBALT_ETH0_IRQ, - [COBALT_PCICONF_RAQSCSI] = COBALT_RAQ_SCSI_IRQ, + [COBALT_PCICONF_ETH0] = ETH0_IRQ, + [COBALT_PCICONF_RAQSCSI] = RAQ2_SCSI_IRQ, [COBALT_PCICONF_VIA] = 0, - [COBALT_PCICONF_PCISLOT] = COBALT_QUBE_SLOT_IRQ, - [COBALT_PCICONF_ETH1] = COBALT_ETH1_IRQ + [COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ, + [COBALT_PCICONF_ETH1] = ETH1_IRQ }; int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) diff --git a/include/asm-mips/irq_gt641xx.h b/include/asm-mips/irq_gt641xx.h new file mode 100644 index 000000000000..f9a7c3ac2e66 --- /dev/null +++ b/include/asm-mips/irq_gt641xx.h @@ -0,0 +1,60 @@ +/* + * Galileo/Marvell GT641xx IRQ definitions. + * + * Copyright (C) 2007 Yoichi Yuasa + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef _ASM_IRQ_GT641XX_H +#define _ASM_IRQ_GT641XX_H + +#ifndef GT641XX_IRQ_BASE +#define GT641XX_IRQ_BASE 8 +#endif + +#define GT641XX_MEMORY_OUT_OF_RANGE_IRQ (GT641XX_IRQ_BASE + 1) +#define GT641XX_DMA_OUT_OF_RANGE_IRQ (GT641XX_IRQ_BASE + 2) +#define GT641XX_CPU_ACCESS_OUT_OF_RANGE_IRQ (GT641XX_IRQ_BASE + 3) +#define GT641XX_DMA0_IRQ (GT641XX_IRQ_BASE + 4) +#define GT641XX_DMA1_IRQ (GT641XX_IRQ_BASE + 5) +#define GT641XX_DMA2_IRQ (GT641XX_IRQ_BASE + 6) +#define GT641XX_DMA3_IRQ (GT641XX_IRQ_BASE + 7) +#define GT641XX_TIMER0_IRQ (GT641XX_IRQ_BASE + 8) +#define GT641XX_TIMER1_IRQ (GT641XX_IRQ_BASE + 9) +#define GT641XX_TIMER2_IRQ (GT641XX_IRQ_BASE + 10) +#define GT641XX_TIMER3_IRQ (GT641XX_IRQ_BASE + 11) +#define GT641XX_PCI_0_MASTER_READ_ERROR_IRQ (GT641XX_IRQ_BASE + 12) +#define GT641XX_PCI_0_SLAVE_WRITE_ERROR_IRQ (GT641XX_IRQ_BASE + 13) +#define GT641XX_PCI_0_MASTER_WRITE_ERROR_IRQ (GT641XX_IRQ_BASE + 14) +#define GT641XX_PCI_0_SLAVE_READ_ERROR_IRQ (GT641XX_IRQ_BASE + 15) +#define GT641XX_PCI_0_ADDRESS_ERROR_IRQ (GT641XX_IRQ_BASE + 16) +#define GT641XX_MEMORY_ERROR_IRQ (GT641XX_IRQ_BASE + 17) +#define GT641XX_PCI_0_MASTER_ABORT_IRQ (GT641XX_IRQ_BASE + 18) +#define GT641XX_PCI_0_TARGET_ABORT_IRQ (GT641XX_IRQ_BASE + 19) +#define GT641XX_PCI_0_RETRY_TIMEOUT_IRQ (GT641XX_IRQ_BASE + 20) +#define GT641XX_CPU_INT0_IRQ (GT641XX_IRQ_BASE + 21) +#define GT641XX_CPU_INT1_IRQ (GT641XX_IRQ_BASE + 22) +#define GT641XX_CPU_INT2_IRQ (GT641XX_IRQ_BASE + 23) +#define GT641XX_CPU_INT3_IRQ (GT641XX_IRQ_BASE + 24) +#define GT641XX_CPU_INT4_IRQ (GT641XX_IRQ_BASE + 25) +#define GT641XX_PCI_INT0_IRQ (GT641XX_IRQ_BASE + 26) +#define GT641XX_PCI_INT1_IRQ (GT641XX_IRQ_BASE + 27) +#define GT641XX_PCI_INT2_IRQ (GT641XX_IRQ_BASE + 28) +#define GT641XX_PCI_INT3_IRQ (GT641XX_IRQ_BASE + 29) + +extern void gt641xx_irq_dispatch(void); +extern void gt641xx_irq_init(void); + +#endif /* _ASM_IRQ_GT641XX_H */ diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h index 9c9d2b998ca4..408eeccbe512 100644 --- a/include/asm-mips/mach-cobalt/cobalt.h +++ b/include/asm-mips/mach-cobalt/cobalt.h @@ -12,32 +12,6 @@ #ifndef __ASM_COBALT_H #define __ASM_COBALT_H -#include - -/* - * i8259 legacy interrupts used on Cobalt: - * - * 8 - RTC - * 9 - PCI - * 14 - IDE0 - * 15 - IDE1 - */ -#define COBALT_QUBE_SLOT_IRQ 9 - -/* - * CPU IRQs are 16 ... 23 - */ -#define COBALT_CPU_IRQ MIPS_CPU_IRQ_BASE - -#define COBALT_GALILEO_IRQ (COBALT_CPU_IRQ + 2) -#define COBALT_RAQ_SCSI_IRQ (COBALT_CPU_IRQ + 3) -#define COBALT_ETH0_IRQ (COBALT_CPU_IRQ + 3) -#define COBALT_QUBE1_ETH0_IRQ (COBALT_CPU_IRQ + 4) -#define COBALT_ETH1_IRQ (COBALT_CPU_IRQ + 4) -#define COBALT_SERIAL_IRQ (COBALT_CPU_IRQ + 5) -#define COBALT_SCSI_IRQ (COBALT_CPU_IRQ + 5) -#define COBALT_VIA_IRQ (COBALT_CPU_IRQ + 6) /* Chained to VIA ISA bridge */ - /* * PCI configuration space manifest constants. These are wired into * the board layout according to the PCI spec to enable the software diff --git a/include/asm-mips/mach-cobalt/irq.h b/include/asm-mips/mach-cobalt/irq.h new file mode 100644 index 000000000000..179d0e850b59 --- /dev/null +++ b/include/asm-mips/mach-cobalt/irq.h @@ -0,0 +1,58 @@ +/* + * Cobalt IRQ definitions. + * + * 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. + * + * Copyright (C) 1997 Cobalt Microserver + * Copyright (C) 1997, 2003 Ralf Baechle + * Copyright (C) 2001-2003 Liam Davies (ldavies@agile.tv) + * Copyright (C) 2007 Yoichi Yuasa + */ +#ifndef _ASM_COBALT_IRQ_H +#define _ASM_COBALT_IRQ_H + +/* + * i8259 interrupts used on Cobalt: + * + * 8 - RTC + * 9 - PCI slot + * 14 - IDE0 + * 15 - IDE1(no connector on board) + */ +#define I8259A_IRQ_BASE 0 + +#define PCISLOT_IRQ (I8259A_IRQ_BASE + 9) + +/* + * CPU interrupts used on Cobalt: + * + * 0 - Software interrupt 0 (unused) + * 1 - Software interrupt 0 (unused) + * 2 - cascade GT64111 + * 3 - ethernet or SCSI host controller + * 4 - ethernet + * 5 - 16550 UART + * 6 - cascade i8259 + * 7 - CP0 counter (unused) + */ +#define MIPS_CPU_IRQ_BASE 16 + +#define GT641XX_CASCADE_IRQ (MIPS_CPU_IRQ_BASE + 2) +#define RAQ2_SCSI_IRQ (MIPS_CPU_IRQ_BASE + 3) +#define ETH0_IRQ (MIPS_CPU_IRQ_BASE + 3) +#define QUBE1_ETH0_IRQ (MIPS_CPU_IRQ_BASE + 4) +#define ETH1_IRQ (MIPS_CPU_IRQ_BASE + 4) +#define SERIAL_IRQ (MIPS_CPU_IRQ_BASE + 5) +#define SCSI_IRQ (MIPS_CPU_IRQ_BASE + 5) +#define I8259_CASCADE_IRQ (MIPS_CPU_IRQ_BASE + 6) + + +#define GT641XX_IRQ_BASE 24 + +#include + +#define NR_IRQS (GT641XX_PCI_INT3_IRQ + 1) + +#endif /* _ASM_COBALT_IRQ_H */ From 0f5c90644240cc17d5940fa3594cc51ad1ae7ba7 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 15 Sep 2007 23:35:53 +0200 Subject: [PATCH 2224/2804] [MIPS] Introduce a consistent style for vmlinux.lds. This style will be consitent with all other arch's - soon. In addition: - Moved a few labels inside brackets for the sections they specify to prevent that linker alignmnet made them point before the section start Signed-off-by: Sam Ravnborg Signed-off-by: Ralf Baechle --- arch/mips/kernel/vmlinux.lds.S | 303 +++++++++++++++++++-------------- 1 file changed, 171 insertions(+), 132 deletions(-) diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 087ab997487d..84f9a4cc6f2f 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -6,163 +6,202 @@ OUTPUT_ARCH(mips) ENTRY(kernel_entry) jiffies = JIFFIES; + SECTIONS { #ifdef CONFIG_BOOT_ELF64 - /* Read-only sections, merged into text segment: */ - /* . = 0xc000000000000000; */ + /* Read-only sections, merged into text segment: */ + /* . = 0xc000000000000000; */ - /* This is the value for an Origin kernel, taken from an IRIX kernel. */ - /* . = 0xc00000000001c000; */ + /* This is the value for an Origin kernel, taken from an IRIX kernel. */ + /* . = 0xc00000000001c000; */ - /* Set the vaddr for the text segment to a value - >= 0xa800 0000 0001 9000 if no symmon is going to configured - >= 0xa800 0000 0030 0000 otherwise */ + /* Set the vaddr for the text segment to a value + * >= 0xa800 0000 0001 9000 if no symmon is going to configured + * >= 0xa800 0000 0030 0000 otherwise + */ - /* . = 0xa800000000300000; */ - /* . = 0xa800000000300000; */ - . = 0xffffffff80300000; + /* . = 0xa800000000300000; */ + /* . = 0xa800000000300000; */ + . = 0xffffffff80300000; #endif - . = LOADADDR; - /* read-only */ - _text = .; /* Text and read-only data */ - .text : { - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - *(.fixup) - *(.gnu.warning) - } =0 + . = LOADADDR; + /* read-only */ + _text = .; /* Text and read-only data */ + .text : { + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + *(.fixup) + *(.gnu.warning) + } =0 + _etext = .; /* End of text section */ - _etext = .; /* End of text section */ + /* Exception table */ + . = ALIGN(16); + __ex_table : { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; + /* Exception table for data bus errors */ + __dbe_table : { + __start___dbe_table = .; + *(__dbe_table) + __stop___dbe_table = .; + } + RODATA - __start___dbe_table = .; /* Exception table for data bus errors */ - __dbe_table : { *(__dbe_table) } - __stop___dbe_table = .; + /* writeable */ + .data : { /* Data */ + . = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */ + /* + * This ALIGN is needed as a workaround for a bug a gcc bug upto 4.1 which + * limits the maximum alignment to at most 32kB and results in the following + * warning: + * + * CC arch/mips/kernel/init_task.o + * arch/mips/kernel/init_task.c:30: warning: alignment of โ€˜init_thread_unionโ€™ + * is greater than maximum object file alignment. Using 32768 + */ + . = ALIGN(_PAGE_SIZE); + *(.data.init_task) - NOTES + DATA_DATA + CONSTRUCTORS + } + _gp = . + 0x8000; + .lit8 : { + *(.lit8) + } + .lit4 : { + *(.lit4) + } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { + *(.sdata) + } - RODATA + . = ALIGN(_PAGE_SIZE); + .data_nosave : { + __nosave_begin = .; + *(.data.nosave) + } + . = ALIGN(_PAGE_SIZE); + __nosave_end = .; - /* writeable */ - .data : { /* Data */ - . = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */ - /* - * This ALIGN is needed as a workaround for a bug a gcc bug upto 4.1 which - * limits the maximum alignment to at most 32kB and results in the following - * warning: - * - * CC arch/mips/kernel/init_task.o - * arch/mips/kernel/init_task.c:30: warning: alignment of โ€˜init_thread_unionโ€™ - * is greater than maximum object file alignment. Using 32768 - */ - . = ALIGN(_PAGE_SIZE); - *(.data.init_task) + . = ALIGN(32); + .data.cacheline_aligned : { + *(.data.cacheline_aligned) + } + _edata = .; /* End of data section */ - DATA_DATA + /* will be freed after init */ + . = ALIGN(_PAGE_SIZE); /* Init code and data */ + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + .init.data : { + *(.init.data) + } + . = ALIGN(16); + .init.setup : { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } - CONSTRUCTORS - } - _gp = . + 0x8000; - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } + .initcall.init : { + __initcall_start = .; + INITCALLS + __initcall_end = .; + } - . = ALIGN(_PAGE_SIZE); - __nosave_begin = .; - .data_nosave : { *(.data.nosave) } - . = ALIGN(_PAGE_SIZE); - __nosave_end = .; + .con_initcall.init : { + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + } + SECURITY_INIT - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - _edata = .; /* End of data section */ - - /* will be freed after init */ - . = ALIGN(_PAGE_SIZE); /* Init code and data */ - __init_begin = .; - .init.text : { - _sinittext = .; - *(.init.text) - _einittext = .; - } - .init.data : { *(.init.data) } - . = ALIGN(16); - __setup_start = .; - .init.setup : { *(.init.setup) } - __setup_end = .; - - __initcall_start = .; - .initcall.init : { - INITCALLS - } - __initcall_end = .; - - __con_initcall_start = .; - .con_initcall.init : { *(.con_initcall.init) } - __con_initcall_end = .; - SECURITY_INIT - /* .exit.text is discarded at runtime, not link time, to deal with - references from .rodata */ - .exit.text : { *(.exit.text) } - .exit.data : { *(.exit.data) } + /* .exit.text is discarded at runtime, not link time, to deal with + * references from .rodata + */ + .exit.text : { + *(.exit.text) + } + .exit.data : { + *(.exit.data) + } #if defined(CONFIG_BLK_DEV_INITRD) - . = ALIGN(_PAGE_SIZE); - __initramfs_start = .; - .init.ramfs : { *(.init.ramfs) } - __initramfs_end = .; + . = ALIGN(_PAGE_SIZE); + .init.ramfs : { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } #endif - PERCPU(_PAGE_SIZE) - . = ALIGN(_PAGE_SIZE); - __init_end = .; - /* freed after init ends here */ + PERCPU(_PAGE_SIZE) + . = ALIGN(_PAGE_SIZE); + __init_end = .; + /* freed after init ends here */ - __bss_start = .; /* BSS */ - .sbss : { - *(.sbss) - *(.scommon) - } - .bss : { - *(.bss) - *(COMMON) - } - __bss_stop = .; + __bss_start = .; /* BSS */ + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + __bss_stop = .; - _end = . ; + _end = . ; - /* Sections to be discarded */ - /DISCARD/ : { - *(.exitcall.exit) + /* Sections to be discarded */ + /DISCARD/ : { + *(.exitcall.exit) - /* ABI crap starts here */ - *(.MIPS.options) - *(.options) - *(.pdr) - *(.reginfo) - } + /* ABI crap starts here */ + *(.MIPS.options) + *(.options) + *(.pdr) + *(.reginfo) + } - /* These mark the ABI of the kernel for debuggers. */ - .mdebug.abi32 : { KEEP(*(.mdebug.abi32)) } - .mdebug.abi64 : { KEEP(*(.mdebug.abi64)) } + /* These mark the ABI of the kernel for debuggers. */ + .mdebug.abi32 : { + KEEP(*(.mdebug.abi32)) + } + .mdebug.abi64 : { + KEEP(*(.mdebug.abi64)) + } - /* This is the MIPS specific mdebug section. */ - .mdebug : { *(.mdebug) } + /* This is the MIPS specific mdebug section. */ + .mdebug : { + *(.mdebug) + } - STABS_DEBUG + STABS_DEBUG + DWARF_DEBUG - DWARF_DEBUG - - /* These must appear regardless of . */ - .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } - .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } - .note : { *(.note) } + /* These must appear regardless of . */ + .gptab.sdata : { + *(.gptab.data) + *(.gptab.sdata) + } + .gptab.sbss : { + *(.gptab.bss) + *(.gptab.sbss) + } + .note : { + *(.note) + } } From e5d77754c5e1a54f9eb61c03085d7932a0b6b738 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 18 Sep 2007 18:49:08 +0100 Subject: [PATCH 2225/2804] [MIPS] R3000 setup for kernel_thread() Match the R4000 semantics for the initial state of interrupt/kernel status register flags for the R3000 in kernel_thread(). Signed-off-by: Maciej W. Rozycki Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index e6ce943099a0..aadd2cd5778c 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -231,8 +231,8 @@ long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) regs.cp0_epc = (unsigned long) kernel_thread_helper; regs.cp0_status = read_c0_status(); #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) - regs.cp0_status &= ~(ST0_KUP | ST0_IEC); - regs.cp0_status |= ST0_IEP; + regs.cp0_status = (regs.cp0_status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) | + ((regs.cp0_status & (ST0_KUC | ST0_IEC)) << 2); #else regs.cp0_status |= ST0_EXL; #endif From 7c4b4773b9b6c440837e5a479204d7bd1b804a43 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:05 +0100 Subject: [PATCH 2226/2804] [MIPS] Sibyte: cleanup static inline forward declarations. In fact there are no foward declarations at all needed when moving things into the right order. Signed-off-by: Ralf Baechle --- arch/mips/sibyte/bcm1480/setup.c | 80 ++++++++++++++++---------------- arch/mips/sibyte/sb1250/setup.c | 74 ++++++++++++++--------------- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/arch/mips/sibyte/bcm1480/setup.c b/arch/mips/sibyte/bcm1480/setup.c index 7e1aa348b8e0..05ed92c92b69 100644 --- a/arch/mips/sibyte/bcm1480/setup.c +++ b/arch/mips/sibyte/bcm1480/setup.c @@ -43,16 +43,49 @@ static unsigned int part_type; static char *soc_str; static char *pass_str; -static inline int setup_bcm1x80_bcm1x55(void); +static int __init setup_bcm1x80_bcm1x55(void) +{ + int ret = 0; + + switch (soc_pass) { + case K_SYS_REVISION_BCM1480_S0: + periph_rev = 1; + pass_str = "S0 (pass1)"; + break; + case K_SYS_REVISION_BCM1480_A1: + periph_rev = 1; + pass_str = "A1 (pass1)"; + break; + case K_SYS_REVISION_BCM1480_A2: + periph_rev = 1; + pass_str = "A2 (pass1)"; + break; + case K_SYS_REVISION_BCM1480_A3: + periph_rev = 1; + pass_str = "A3 (pass1)"; + break; + case K_SYS_REVISION_BCM1480_B0: + periph_rev = 1; + pass_str = "B0 (pass2)"; + break; + default: + printk("Unknown %s rev %x\n", soc_str, soc_pass); + periph_rev = 1; + pass_str = "Unknown Revision"; + break; + } + + return ret; +} /* Setup code likely to be common to all SiByte platforms */ -static inline int sys_rev_decode(void) +static int __init sys_rev_decode(void) { int ret = 0; switch (soc_type) { - case K_SYS_SOC_TYPE_BCM1x80: + case K_SYS_SOC_TYPE_BCM1x80: if (part_type == K_SYS_PART_BCM1480) soc_str = "BCM1480"; else if (part_type == K_SYS_PART_BCM1280) @@ -62,7 +95,7 @@ static inline int sys_rev_decode(void) ret = setup_bcm1x80_bcm1x55(); break; - case K_SYS_SOC_TYPE_BCM1x55: + case K_SYS_SOC_TYPE_BCM1x55: if (part_type == K_SYS_PART_BCM1455) soc_str = "BCM1455"; else if (part_type == K_SYS_PART_BCM1255) @@ -72,49 +105,16 @@ static inline int sys_rev_decode(void) ret = setup_bcm1x80_bcm1x55(); break; - default: + default: printk("Unknown part type %x\n", part_type); ret = 1; break; } + return ret; } -static inline int setup_bcm1x80_bcm1x55(void) -{ - int ret = 0; - - switch (soc_pass) { - case K_SYS_REVISION_BCM1480_S0: - periph_rev = 1; - pass_str = "S0 (pass1)"; - break; - case K_SYS_REVISION_BCM1480_A1: - periph_rev = 1; - pass_str = "A1 (pass1)"; - break; - case K_SYS_REVISION_BCM1480_A2: - periph_rev = 1; - pass_str = "A2 (pass1)"; - break; - case K_SYS_REVISION_BCM1480_A3: - periph_rev = 1; - pass_str = "A3 (pass1)"; - break; - case K_SYS_REVISION_BCM1480_B0: - periph_rev = 1; - pass_str = "B0 (pass2)"; - break; - default: - printk("Unknown %s rev %x\n", soc_str, soc_pass); - periph_rev = 1; - pass_str = "Unknown Revision"; - break; - } - return ret; -} - -void bcm1480_setup(void) +void __init bcm1480_setup(void) { uint64_t sys_rev; int plldiv; diff --git a/arch/mips/sibyte/sb1250/setup.c b/arch/mips/sibyte/sb1250/setup.c index 2d5c6d8b41f2..0444da1e23c2 100644 --- a/arch/mips/sibyte/sb1250/setup.c +++ b/arch/mips/sibyte/sb1250/setup.c @@ -40,43 +40,6 @@ static char *soc_str; static char *pass_str; static unsigned int war_pass; /* XXXKW don't overload PASS defines? */ -static inline int setup_bcm1250(void); -static inline int setup_bcm112x(void); - -/* Setup code likely to be common to all SiByte platforms */ - -static int __init sys_rev_decode(void) -{ - int ret = 0; - - war_pass = soc_pass; - switch (soc_type) { - case K_SYS_SOC_TYPE_BCM1250: - case K_SYS_SOC_TYPE_BCM1250_ALT: - case K_SYS_SOC_TYPE_BCM1250_ALT2: - soc_str = "BCM1250"; - ret = setup_bcm1250(); - break; - case K_SYS_SOC_TYPE_BCM1120: - soc_str = "BCM1120"; - ret = setup_bcm112x(); - break; - case K_SYS_SOC_TYPE_BCM1125: - soc_str = "BCM1125"; - ret = setup_bcm112x(); - break; - case K_SYS_SOC_TYPE_BCM1125H: - soc_str = "BCM1125H"; - ret = setup_bcm112x(); - break; - default: - printk("Unknown SOC type %x\n", soc_type); - ret = 1; - break; - } - return ret; -} - static int __init setup_bcm1250(void) { int ret = 0; @@ -120,6 +83,7 @@ static int __init setup_bcm1250(void) } break; } + return ret; } @@ -158,6 +122,42 @@ static int __init setup_bcm112x(void) printk("Unknown %s rev %x\n", soc_str, soc_pass); ret = 1; } + + return ret; +} + +/* Setup code likely to be common to all SiByte platforms */ + +static int __init sys_rev_decode(void) +{ + int ret = 0; + + war_pass = soc_pass; + switch (soc_type) { + case K_SYS_SOC_TYPE_BCM1250: + case K_SYS_SOC_TYPE_BCM1250_ALT: + case K_SYS_SOC_TYPE_BCM1250_ALT2: + soc_str = "BCM1250"; + ret = setup_bcm1250(); + break; + case K_SYS_SOC_TYPE_BCM1120: + soc_str = "BCM1120"; + ret = setup_bcm112x(); + break; + case K_SYS_SOC_TYPE_BCM1125: + soc_str = "BCM1125"; + ret = setup_bcm112x(); + break; + case K_SYS_SOC_TYPE_BCM1125H: + soc_str = "BCM1125H"; + ret = setup_bcm112x(); + break; + default: + printk("Unknown SOC type %x\n", soc_type); + ret = 1; + break; + } + return ret; } From 424b28ba4d25fc41abdb7e6fa90e132f0d9558fb Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:05 +0100 Subject: [PATCH 2227/2804] [MIPS] Alchemy: remove useless prototypes. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/irq.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index ea6e99fbe2f7..db2ba0dbfd5a 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -65,19 +65,8 @@ #define EXT_INTC1_REQ1 5 /* IP 5 */ #define MIPS_TIMER_IP 7 /* IP 7 */ -extern void set_debug_traps(void); -extern irq_cpustat_t irq_stat [NR_CPUS]; extern void mips_timer_interrupt(void); -static void setup_local_irq(unsigned int irq, int type, int int_req); -static void end_irq(unsigned int irq_nr); -static inline void mask_and_ack_level_irq(unsigned int irq_nr); -static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr); -static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr); -static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr); -inline void local_enable_irq(unsigned int irq_nr); -inline void local_disable_irq(unsigned int irq_nr); - void (*board_init_irq)(void); static DEFINE_SPINLOCK(irq_lock); From 641e97f318870921d048154af6807e46e43c307a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:05 +0100 Subject: [PATCH 2228/2804] [MIPS] Sibyte: Replace SB1 cachecode with standard R4000 class cache code. It may not be perfect yet but the SB1 code is badly borken and has horrible performance issues. Downside: This seriously breaks support for pass 1 parts of the BCM1250 where indexed cacheops don't work quite reliable but I seem to be the last one on the planet with a pass 1 part anyway. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 8 - arch/mips/kernel/traps.c | 6 + arch/mips/mm/Makefile | 2 +- arch/mips/mm/c-r4k.c | 22 +- arch/mips/mm/c-sb1.c | 535 ------------------ arch/mips/mm/cache.c | 9 +- arch/mips/mm/pg-sb1.c | 8 + include/asm-mips/cpu-features.h | 3 - include/asm-mips/cpu.h | 35 +- include/asm-mips/linkage.h | 2 + .../mach-cobalt/cpu-feature-overrides.h | 1 - 11 files changed, 54 insertions(+), 577 deletions(-) delete mode 100644 arch/mips/mm/c-sb1.c diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 97c03865c06a..dde2adf1481c 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -746,14 +746,6 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) { decode_configs(c); - /* - * For historical reasons the SB1 comes with it's own variant of - * cache code which eventually will be folded into c-r4k.c. Until - * then we pretend it's got it's own cache architecture. - */ - c->options &= ~MIPS_CPU_4K_CACHE; - c->options |= MIPS_CPU_SB1_CACHE; - switch (c->processor_id & 0xff00) { case PRID_IMP_SB1: c->cputype = CPU_SB1; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 3d033e1cd4f0..d96f8218a91e 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1435,6 +1435,9 @@ void __init set_handler (unsigned long offset, void *addr, unsigned long size) flush_icache_range(ebase + offset, ebase + offset + size); } +static char panic_null_cerr[] __initdata = + "Trying to set NULL cache error exception handler"; + /* Install uncached CPU exception handler */ void __init set_uncached_handler (unsigned long offset, void *addr, unsigned long size) { @@ -1445,6 +1448,9 @@ void __init set_uncached_handler (unsigned long offset, void *addr, unsigned lon unsigned long uncached_ebase = TO_UNCAC(ebase); #endif + if (!addr) + panic(panic_null_cerr); + memcpy((void *)(uncached_ebase + offset), addr, size); } diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 43e4810dcaa8..32fd5db95774 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_CPU_R5432) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o obj-$(CONFIG_CPU_R8000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r8k.o obj-$(CONFIG_CPU_RM7000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o obj-$(CONFIG_CPU_RM9000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o -obj-$(CONFIG_CPU_SB1) += c-sb1.o cerr-sb1.o cex-sb1.o pg-sb1.o \ +obj-$(CONFIG_CPU_SB1) += c-r4k.o cerr-sb1.o cex-sb1.o pg-sb1.o \ tlb-r4k.o obj-$(CONFIG_CPU_TX39XX) += c-tx39.o pg-r4k.o tlb-r3k.o obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index bad571971bf6..738b89803a44 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -9,6 +9,7 @@ */ #include #include +#include #include #include #include @@ -948,12 +949,16 @@ static void __init probe_pcache(void) switch (c->cputype) { case CPU_20KC: case CPU_25KF: + case CPU_SB1: + case CPU_SB1A: c->dcache.flags |= MIPS_CACHE_PINDEX; + break; + case CPU_R10000: case CPU_R12000: case CPU_R14000: - case CPU_SB1: break; + case CPU_24K: case CPU_34K: case CPU_74K: @@ -1235,11 +1240,20 @@ void __init r4k_cache_init(void) { extern void build_clear_page(void); extern void build_copy_page(void); - extern char except_vec2_generic; + extern char __weak except_vec2_generic; + extern char __weak except_vec2_sb1; struct cpuinfo_mips *c = ¤t_cpu_data; - /* Default cache error handler for R4000 and R5000 family */ - set_uncached_handler (0x100, &except_vec2_generic, 0x80); + switch (c->cputype) { + case CPU_SB1: + case CPU_SB1A: + set_uncached_handler(0x100, &except_vec2_sb1, 0x80); + break; + + default: + set_uncached_handler(0x100, &except_vec2_generic, 0x80); + break; + } probe_pcache(); setup_scache(); diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c deleted file mode 100644 index 85ce2842d0da..000000000000 --- a/arch/mips/mm/c-sb1.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation - * Copyright (C) 2004 Maciej W. Rozycki - * - * 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. - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -extern void sb1_dma_init(void); - -/* These are probed at ld_mmu time */ -static unsigned long icache_size; -static unsigned long dcache_size; - -static unsigned short icache_line_size; -static unsigned short dcache_line_size; - -static unsigned int icache_index_mask; -static unsigned int dcache_index_mask; - -static unsigned short icache_assoc; -static unsigned short dcache_assoc; - -static unsigned short icache_sets; -static unsigned short dcache_sets; - -static unsigned int icache_range_cutoff; -static unsigned int dcache_range_cutoff; - -static inline void sb1_on_each_cpu(void (*func) (void *info), void *info, - int retry, int wait) -{ - preempt_disable(); - smp_call_function(func, info, retry, wait); - func(info); - preempt_enable(); -} - -/* - * The dcache is fully coherent to the system, with one - * big caveat: the instruction stream. In other words, - * if we miss in the icache, and have dirty data in the - * L1 dcache, then we'll go out to memory (or the L2) and - * get the not-as-recent data. - * - * So the only time we have to flush the dcache is when - * we're flushing the icache. Since the L2 is fully - * coherent to everything, including I/O, we never have - * to flush it - */ - -#define cache_set_op(op, addr) \ - __asm__ __volatile__( \ - " .set noreorder \n" \ - " .set mips64\n\t \n" \ - " cache %0, (0<<13)(%1) \n" \ - " cache %0, (1<<13)(%1) \n" \ - " cache %0, (2<<13)(%1) \n" \ - " cache %0, (3<<13)(%1) \n" \ - " .set mips0 \n" \ - " .set reorder" \ - : \ - : "i" (op), "r" (addr)) - -#define sync() \ - __asm__ __volatile( \ - " .set mips64\n\t \n" \ - " sync \n" \ - " .set mips0") - -#define mispredict() \ - __asm__ __volatile__( \ - " bnezl $0, 1f \n" /* Force mispredict */ \ - "1: \n"); - -/* - * Writeback and invalidate the entire dcache - */ -static inline void __sb1_writeback_inv_dcache_all(void) -{ - unsigned long addr = 0; - - while (addr < dcache_line_size * dcache_sets) { - cache_set_op(Index_Writeback_Inv_D, addr); - addr += dcache_line_size; - } -} - -/* - * Writeback and invalidate a range of the dcache. The addresses are - * virtual, and since we're using index ops and bit 12 is part of both - * the virtual frame and physical index, we have to clear both sets - * (bit 12 set and cleared). - */ -static inline void __sb1_writeback_inv_dcache_range(unsigned long start, - unsigned long end) -{ - unsigned long index; - - start &= ~(dcache_line_size - 1); - end = (end + dcache_line_size - 1) & ~(dcache_line_size - 1); - - while (start != end) { - index = start & dcache_index_mask; - cache_set_op(Index_Writeback_Inv_D, index); - cache_set_op(Index_Writeback_Inv_D, index ^ (1<<12)); - start += dcache_line_size; - } - sync(); -} - -/* - * Writeback and invalidate a range of the dcache. With physical - * addresseses, we don't have to worry about possible bit 12 aliasing. - * XXXKW is it worth turning on KX and using hit ops with xkphys? - */ -static inline void __sb1_writeback_inv_dcache_phys_range(unsigned long start, - unsigned long end) -{ - start &= ~(dcache_line_size - 1); - end = (end + dcache_line_size - 1) & ~(dcache_line_size - 1); - - while (start != end) { - cache_set_op(Index_Writeback_Inv_D, start & dcache_index_mask); - start += dcache_line_size; - } - sync(); -} - - -/* - * Invalidate the entire icache - */ -static inline void __sb1_flush_icache_all(void) -{ - unsigned long addr = 0; - - while (addr < icache_line_size * icache_sets) { - cache_set_op(Index_Invalidate_I, addr); - addr += icache_line_size; - } -} - -/* - * Invalidate a range of the icache. The addresses are virtual, and - * the cache is virtually indexed and tagged. However, we don't - * necessarily have the right ASID context, so use index ops instead - * of hit ops. - */ -static inline void __sb1_flush_icache_range(unsigned long start, - unsigned long end) -{ - start &= ~(icache_line_size - 1); - end = (end + icache_line_size - 1) & ~(icache_line_size - 1); - - while (start != end) { - cache_set_op(Index_Invalidate_I, start & icache_index_mask); - start += icache_line_size; - } - mispredict(); - sync(); -} - -/* - * Flush the icache for a given physical page. Need to writeback the - * dcache first, then invalidate the icache. If the page isn't - * executable, nothing is required. - */ -static void local_sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn) -{ - int cpu = smp_processor_id(); - -#ifndef CONFIG_SMP - if (!(vma->vm_flags & VM_EXEC)) - return; -#endif - - __sb1_writeback_inv_dcache_range(addr, addr + PAGE_SIZE); - - /* - * Bumping the ASID is probably cheaper than the flush ... - */ - if (vma->vm_mm == current->active_mm) { - if (cpu_context(cpu, vma->vm_mm) != 0) - drop_mmu_context(vma->vm_mm, cpu); - } else - __sb1_flush_icache_range(addr, addr + PAGE_SIZE); -} - -#ifdef CONFIG_SMP -struct flush_cache_page_args { - struct vm_area_struct *vma; - unsigned long addr; - unsigned long pfn; -}; - -static void sb1_flush_cache_page_ipi(void *info) -{ - struct flush_cache_page_args *args = info; - - local_sb1_flush_cache_page(args->vma, args->addr, args->pfn); -} - -/* Dirty dcache could be on another CPU, so do the IPIs */ -static void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn) -{ - struct flush_cache_page_args args; - - if (!(vma->vm_flags & VM_EXEC)) - return; - - addr &= PAGE_MASK; - args.vma = vma; - args.addr = addr; - args.pfn = pfn; - sb1_on_each_cpu(sb1_flush_cache_page_ipi, (void *) &args, 1, 1); -} -#else -void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn) - __attribute__((alias("local_sb1_flush_cache_page"))); -#endif - -#ifdef CONFIG_SMP -static void sb1_flush_cache_data_page_ipi(void *info) -{ - unsigned long start = (unsigned long)info; - - __sb1_writeback_inv_dcache_range(start, start + PAGE_SIZE); -} - -static void sb1_flush_cache_data_page(unsigned long addr) -{ - if (in_atomic()) - __sb1_writeback_inv_dcache_range(addr, addr + PAGE_SIZE); - else - on_each_cpu(sb1_flush_cache_data_page_ipi, (void *) addr, 1, 1); -} -#else - -static void local_sb1_flush_cache_data_page(unsigned long addr) -{ - __sb1_writeback_inv_dcache_range(addr, addr + PAGE_SIZE); -} - -void sb1_flush_cache_data_page(unsigned long) - __attribute__((alias("local_sb1_flush_cache_data_page"))); -#endif - -/* - * Invalidate all caches on this CPU - */ -static void __used local_sb1___flush_cache_all(void) -{ - __sb1_writeback_inv_dcache_all(); - __sb1_flush_icache_all(); -} - -#ifdef CONFIG_SMP -void sb1___flush_cache_all_ipi(void *ignored) - __attribute__((alias("local_sb1___flush_cache_all"))); - -static void sb1___flush_cache_all(void) -{ - sb1_on_each_cpu(sb1___flush_cache_all_ipi, 0, 1, 1); -} -#else -void sb1___flush_cache_all(void) - __attribute__((alias("local_sb1___flush_cache_all"))); -#endif - -/* - * When flushing a range in the icache, we have to first writeback - * the dcache for the same range, so new ifetches will see any - * data that was dirty in the dcache. - * - * The start/end arguments are Kseg addresses (possibly mapped Kseg). - */ - -static void local_sb1_flush_icache_range(unsigned long start, - unsigned long end) -{ - /* Just wb-inv the whole dcache if the range is big enough */ - if ((end - start) > dcache_range_cutoff) - __sb1_writeback_inv_dcache_all(); - else - __sb1_writeback_inv_dcache_range(start, end); - - /* Just flush the whole icache if the range is big enough */ - if ((end - start) > icache_range_cutoff) - __sb1_flush_icache_all(); - else - __sb1_flush_icache_range(start, end); -} - -#ifdef CONFIG_SMP -struct flush_icache_range_args { - unsigned long start; - unsigned long end; -}; - -static void sb1_flush_icache_range_ipi(void *info) -{ - struct flush_icache_range_args *args = info; - - local_sb1_flush_icache_range(args->start, args->end); -} - -void sb1_flush_icache_range(unsigned long start, unsigned long end) -{ - struct flush_icache_range_args args; - - args.start = start; - args.end = end; - sb1_on_each_cpu(sb1_flush_icache_range_ipi, &args, 1, 1); -} -#else -void sb1_flush_icache_range(unsigned long start, unsigned long end) - __attribute__((alias("local_sb1_flush_icache_range"))); -#endif - -/* - * A signal trampoline must fit into a single cacheline. - */ -static void local_sb1_flush_cache_sigtramp(unsigned long addr) -{ - cache_set_op(Index_Writeback_Inv_D, addr & dcache_index_mask); - cache_set_op(Index_Writeback_Inv_D, (addr ^ (1<<12)) & dcache_index_mask); - cache_set_op(Index_Invalidate_I, addr & icache_index_mask); - mispredict(); -} - -#ifdef CONFIG_SMP -static void sb1_flush_cache_sigtramp_ipi(void *info) -{ - unsigned long iaddr = (unsigned long) info; - local_sb1_flush_cache_sigtramp(iaddr); -} - -static void sb1_flush_cache_sigtramp(unsigned long addr) -{ - sb1_on_each_cpu(sb1_flush_cache_sigtramp_ipi, (void *) addr, 1, 1); -} -#else -void sb1_flush_cache_sigtramp(unsigned long addr) - __attribute__((alias("local_sb1_flush_cache_sigtramp"))); -#endif - - -/* - * Anything that just flushes dcache state can be ignored, as we're always - * coherent in dcache space. This is just a dummy function that all the - * nop'ed routines point to - */ -static void sb1_nop(void) -{ -} - -/* - * Cache set values (from the mips64 spec) - * 0 - 64 - * 1 - 128 - * 2 - 256 - * 3 - 512 - * 4 - 1024 - * 5 - 2048 - * 6 - 4096 - * 7 - Reserved - */ - -static unsigned int decode_cache_sets(unsigned int config_field) -{ - if (config_field == 7) { - /* JDCXXX - Find a graceful way to abort. */ - return 0; - } - return (1<<(config_field + 6)); -} - -/* - * Cache line size values (from the mips64 spec) - * 0 - No cache present. - * 1 - 4 bytes - * 2 - 8 bytes - * 3 - 16 bytes - * 4 - 32 bytes - * 5 - 64 bytes - * 6 - 128 bytes - * 7 - Reserved - */ - -static unsigned int decode_cache_line_size(unsigned int config_field) -{ - if (config_field == 0) { - return 0; - } else if (config_field == 7) { - /* JDCXXX - Find a graceful way to abort. */ - return 0; - } - return (1<<(config_field + 1)); -} - -/* - * Relevant bits of the config1 register format (from the MIPS32/MIPS64 specs) - * - * 24:22 Icache sets per way - * 21:19 Icache line size - * 18:16 Icache Associativity - * 15:13 Dcache sets per way - * 12:10 Dcache line size - * 9:7 Dcache Associativity - */ - -static char *way_string[] = { - "direct mapped", "2-way", "3-way", "4-way", - "5-way", "6-way", "7-way", "8-way", -}; - -static __init void probe_cache_sizes(void) -{ - u32 config1; - - config1 = read_c0_config1(); - icache_line_size = decode_cache_line_size((config1 >> 19) & 0x7); - dcache_line_size = decode_cache_line_size((config1 >> 10) & 0x7); - icache_sets = decode_cache_sets((config1 >> 22) & 0x7); - dcache_sets = decode_cache_sets((config1 >> 13) & 0x7); - icache_assoc = ((config1 >> 16) & 0x7) + 1; - dcache_assoc = ((config1 >> 7) & 0x7) + 1; - icache_size = icache_line_size * icache_sets * icache_assoc; - dcache_size = dcache_line_size * dcache_sets * dcache_assoc; - /* Need to remove non-index bits for index ops */ - icache_index_mask = (icache_sets - 1) * icache_line_size; - dcache_index_mask = (dcache_sets - 1) * dcache_line_size; - /* - * These are for choosing range (index ops) versus all. - * icache flushes all ways for each set, so drop icache_assoc. - * dcache flushes all ways and each setting of bit 12 for each - * index, so drop dcache_assoc and halve the dcache_sets. - */ - icache_range_cutoff = icache_sets * icache_line_size; - dcache_range_cutoff = (dcache_sets / 2) * icache_line_size; - - printk("Primary instruction cache %ldkB, %s, linesize %d bytes.\n", - icache_size >> 10, way_string[icache_assoc - 1], - icache_line_size); - printk("Primary data cache %ldkB, %s, linesize %d bytes.\n", - dcache_size >> 10, way_string[dcache_assoc - 1], - dcache_line_size); -} - -/* - * This is called from cache.c. We have to set up all the - * memory management function pointers, as well as initialize - * the caches and tlbs - */ -void __init sb1_cache_init(void) -{ - extern char except_vec2_sb1; - - /* Special cache error handler for SB1 */ - set_uncached_handler (0x100, &except_vec2_sb1, 0x80); - - probe_cache_sizes(); - -#ifdef CONFIG_SIBYTE_DMA_PAGEOPS - sb1_dma_init(); -#endif - - /* - * None of these are needed for the SB1 - the Dcache is - * physically indexed and tagged, so no virtual aliasing can - * occur - */ - flush_cache_range = (void *) sb1_nop; - flush_cache_mm = (void (*)(struct mm_struct *))sb1_nop; - flush_cache_all = sb1_nop; - - /* These routines are for Icache coherence with the Dcache */ - flush_icache_range = sb1_flush_icache_range; - flush_icache_all = __sb1_flush_icache_all; /* local only */ - - /* This implies an Icache flush too, so can't be nop'ed */ - flush_cache_page = sb1_flush_cache_page; - - flush_cache_sigtramp = sb1_flush_cache_sigtramp; - local_flush_data_cache_page = (void *) sb1_nop; - flush_data_cache_page = sb1_flush_cache_data_page; - - /* Full flush */ - __flush_cache_all = sb1___flush_cache_all; - - change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT); - - /* - * This is the only way to force the update of K0 to complete - * before subsequent instruction fetch. - */ - __asm__ __volatile__( - ".set push \n" - " .set noat \n" - " .set noreorder \n" - " .set mips3 \n" - " " STR(PTR_LA) " $1, 1f \n" - " " STR(MTC0) " $1, $14 \n" - " eret \n" - "1: .set pop" - : - : - : "memory"); - - local_sb1___flush_cache_all(); -} diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 81f925a9a731..43dde874f414 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -3,13 +3,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994 - 2003, 07 by Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 1994 - 2003, 06, 07 by Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2007 MIPS Technologies, Inc. */ #include #include #include #include +#include #include #include #include @@ -157,12 +158,6 @@ void __init cpu_cache_init(void) tx39_cache_init(); return; } - if (cpu_has_sb1_cache) { - extern void __weak sb1_cache_init(void); - - sb1_cache_init(); - return; - } panic(cache_panic); } diff --git a/arch/mips/mm/pg-sb1.c b/arch/mips/mm/pg-sb1.c index adb37d0a30ea..82f42ace73c8 100644 --- a/arch/mips/mm/pg-sb1.c +++ b/arch/mips/mm/pg-sb1.c @@ -292,3 +292,11 @@ void copy_page(void *to, void *from) EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(copy_page); + +void __init build_clear_page(void) +{ +} + +void __init build_copy_page(void) +{ +} diff --git a/include/asm-mips/cpu-features.h b/include/asm-mips/cpu-features.h index d95a83e3e1d7..81f19aebc0db 100644 --- a/include/asm-mips/cpu-features.h +++ b/include/asm-mips/cpu-features.h @@ -35,9 +35,6 @@ #ifndef cpu_has_tx39_cache #define cpu_has_tx39_cache (cpu_data[0].options & MIPS_CPU_TX39_CACHE) #endif -#ifndef cpu_has_sb1_cache -#define cpu_has_sb1_cache (cpu_data[0].options & MIPS_CPU_SB1_CACHE) -#endif #ifndef cpu_has_fpu #define cpu_has_fpu (current_cpu_data.options & MIPS_CPU_FPU) #define raw_cpu_has_fpu (raw_current_cpu_data.options & MIPS_CPU_FPU) diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h index d67f43b09964..107ccbeee294 100644 --- a/include/asm-mips/cpu.h +++ b/include/asm-mips/cpu.h @@ -255,24 +255,23 @@ #define MIPS_CPU_3K_CACHE 0x00000004 /* R3000-style caches */ #define MIPS_CPU_4K_CACHE 0x00000008 /* R4000-style caches */ #define MIPS_CPU_TX39_CACHE 0x00000010 /* TX3900-style caches */ -#define MIPS_CPU_SB1_CACHE 0x00000020 /* SB1-style caches */ -#define MIPS_CPU_FPU 0x00000040 /* CPU has FPU */ -#define MIPS_CPU_32FPR 0x00000080 /* 32 dbl. prec. FP registers */ -#define MIPS_CPU_COUNTER 0x00000100 /* Cycle count/compare */ -#define MIPS_CPU_WATCH 0x00000200 /* watchpoint registers */ -#define MIPS_CPU_DIVEC 0x00000400 /* dedicated interrupt vector */ -#define MIPS_CPU_VCE 0x00000800 /* virt. coherence conflict possible */ -#define MIPS_CPU_CACHE_CDEX_P 0x00001000 /* Create_Dirty_Exclusive CACHE op */ -#define MIPS_CPU_CACHE_CDEX_S 0x00002000 /* ... same for seconary cache ... */ -#define MIPS_CPU_MCHECK 0x00004000 /* Machine check exception */ -#define MIPS_CPU_EJTAG 0x00008000 /* EJTAG exception */ -#define MIPS_CPU_NOFPUEX 0x00010000 /* no FPU exception */ -#define MIPS_CPU_LLSC 0x00020000 /* CPU has ll/sc instructions */ -#define MIPS_CPU_INCLUSIVE_CACHES 0x00040000 /* P-cache subset enforced */ -#define MIPS_CPU_PREFETCH 0x00080000 /* CPU has usable prefetch */ -#define MIPS_CPU_VINT 0x00100000 /* CPU supports MIPSR2 vectored interrupts */ -#define MIPS_CPU_VEIC 0x00200000 /* CPU supports MIPSR2 external interrupt controller mode */ -#define MIPS_CPU_ULRI 0x00400000 /* CPU has ULRI feature */ +#define MIPS_CPU_FPU 0x00000020 /* CPU has FPU */ +#define MIPS_CPU_32FPR 0x00000040 /* 32 dbl. prec. FP registers */ +#define MIPS_CPU_COUNTER 0x00000080 /* Cycle count/compare */ +#define MIPS_CPU_WATCH 0x00000100 /* watchpoint registers */ +#define MIPS_CPU_DIVEC 0x00000200 /* dedicated interrupt vector */ +#define MIPS_CPU_VCE 0x00000400 /* virt. coherence conflict possible */ +#define MIPS_CPU_CACHE_CDEX_P 0x00000800 /* Create_Dirty_Exclusive CACHE op */ +#define MIPS_CPU_CACHE_CDEX_S 0x00001000 /* ... same for seconary cache ... */ +#define MIPS_CPU_MCHECK 0x00002000 /* Machine check exception */ +#define MIPS_CPU_EJTAG 0x00004000 /* EJTAG exception */ +#define MIPS_CPU_NOFPUEX 0x00008000 /* no FPU exception */ +#define MIPS_CPU_LLSC 0x00010000 /* CPU has ll/sc instructions */ +#define MIPS_CPU_INCLUSIVE_CACHES 0x00020000 /* P-cache subset enforced */ +#define MIPS_CPU_PREFETCH 0x00040000 /* CPU has usable prefetch */ +#define MIPS_CPU_VINT 0x00080000 /* CPU supports MIPSR2 vectored interrupts */ +#define MIPS_CPU_VEIC 0x00100000 /* CPU supports MIPSR2 external interrupt controller mode */ +#define MIPS_CPU_ULRI 0x00200000 /* CPU has ULRI feature */ /* * CPU ASE encodings diff --git a/include/asm-mips/linkage.h b/include/asm-mips/linkage.h index b6185d3cfe68..e9a940d1b0c6 100644 --- a/include/asm-mips/linkage.h +++ b/include/asm-mips/linkage.h @@ -5,4 +5,6 @@ #include #endif +#define __weak __attribute__((weak)) + #endif diff --git a/include/asm-mips/mach-cobalt/cpu-feature-overrides.h b/include/asm-mips/mach-cobalt/cpu-feature-overrides.h index d38f069d9e95..b3314cf53194 100644 --- a/include/asm-mips/mach-cobalt/cpu-feature-overrides.h +++ b/include/asm-mips/mach-cobalt/cpu-feature-overrides.h @@ -14,7 +14,6 @@ #define cpu_has_3k_cache 0 #define cpu_has_4k_cache 1 #define cpu_has_tx39_cache 0 -#define cpu_has_sb1_cache 0 #define cpu_has_fpu 1 #define cpu_has_32fpr 1 #define cpu_has_counter 1 From cc6e8e0812cf95aea397c457ff48de2ac069614f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:05 +0100 Subject: [PATCH 2229/2804] [MIPS] Remove IP27 specific structures from struct cpuinfo_mips Signed-off-by: Ralf Baechle --- arch/mips/sgi-ip27/ip27-init.c | 3 +++ arch/mips/sgi-ip27/ip27-smp.c | 2 +- include/asm-mips/cpu-info.h | 18 ------------------ include/asm-mips/mach-ip27/topology.h | 20 +++++++++++++++++++- include/asm-mips/sn/arch.h | 4 ++-- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c index 74158d349630..af08c41d6aa8 100644 --- a/arch/mips/sgi-ip27/ip27-init.c +++ b/arch/mips/sgi-ip27/ip27-init.c @@ -47,6 +47,9 @@ cnodeid_t cpuid_to_compact_node[MAXCPUS]; EXPORT_SYMBOL(nasid_to_compact_node); +struct cpuinfo_ip27 sn_cpu_info[NR_CPUS]; +EXPORT_SYMBOL_GPL(sn_cpu_info); + extern void pcibr_setup(cnodeid_t); extern void xtalk_probe_node(cnodeid_t nid); diff --git a/arch/mips/sgi-ip27/ip27-smp.c b/arch/mips/sgi-ip27/ip27-smp.c index fbb27728a76a..493777e39a01 100644 --- a/arch/mips/sgi-ip27/ip27-smp.c +++ b/arch/mips/sgi-ip27/ip27-smp.c @@ -33,7 +33,7 @@ static void alloc_cpupda(cpuid_t cpu, int cpunum) nasid_t nasid = COMPACT_TO_NASID_NODEID(node); cputonasid(cpunum) = nasid; - cpu_data[cpunum].p_nodeid = node; + sn_cpu_info[cpunum].p_nodeid = node; cputoslice(cpunum) = get_cpu_slice(cpu); } diff --git a/include/asm-mips/cpu-info.h b/include/asm-mips/cpu-info.h index 22fe8453fcc7..04689590eeed 100644 --- a/include/asm-mips/cpu-info.h +++ b/include/asm-mips/cpu-info.h @@ -14,10 +14,6 @@ #include -#ifdef CONFIG_SGI_IP27 -#include -#endif - /* * Descriptor for a cache */ @@ -43,20 +39,6 @@ struct cache_desc { struct cpuinfo_mips { unsigned long udelay_val; unsigned long asid_cache; -#if defined(CONFIG_SGI_IP27) -// cpuid_t p_cpuid; /* PROM assigned cpuid */ - cnodeid_t p_nodeid; /* my node ID in compact-id-space */ - nasid_t p_nasid; /* my node ID in numa-as-id-space */ - unsigned char p_slice; /* Physical position on node board */ -#endif -#if 0 - unsigned long loops_per_sec; - unsigned long ipi_count; - unsigned long irq_attempt[NR_IRQS]; - unsigned long smp_local_irq_count; - unsigned long prof_multiplier; - unsigned long prof_counter; -#endif /* * Capability and feature descriptor structure for MIPS CPU diff --git a/include/asm-mips/mach-ip27/topology.h b/include/asm-mips/mach-ip27/topology.h index 61d9be3f3175..372291f53fb9 100644 --- a/include/asm-mips/mach-ip27/topology.h +++ b/include/asm-mips/mach-ip27/topology.h @@ -2,9 +2,27 @@ #define _ASM_MACH_TOPOLOGY_H 1 #include +#include #include -#define cpu_to_node(cpu) (cpu_data[(cpu)].p_nodeid) +struct cpuinfo_ip27 { +// cpuid_t p_cpuid; /* PROM assigned cpuid */ + cnodeid_t p_nodeid; /* my node ID in compact-id-space */ + nasid_t p_nasid; /* my node ID in numa-as-id-space */ + unsigned char p_slice; /* Physical position on node board */ +#if 0 + unsigned long loops_per_sec; + unsigned long ipi_count; + unsigned long irq_attempt[NR_IRQS]; + unsigned long smp_local_irq_count; + unsigned long prof_multiplier; + unsigned long prof_counter; +#endif +}; + +extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS]; + +#define cpu_to_node(cpu) (sn_cpu_info[(cpu)].p_nodeid) #define parent_node(node) (node) #define node_to_cpumask(node) (hub_data(node)->h_cpus) #define node_to_first_cpu(node) (first_cpu(node_to_cpumask(node))) diff --git a/include/asm-mips/sn/arch.h b/include/asm-mips/sn/arch.h index da523de628be..bd75945e10ff 100644 --- a/include/asm-mips/sn/arch.h +++ b/include/asm-mips/sn/arch.h @@ -19,8 +19,8 @@ typedef u64 hubreg_t; -#define cputonasid(cpu) (cpu_data[(cpu)].p_nasid) -#define cputoslice(cpu) (cpu_data[(cpu)].p_slice) +#define cputonasid(cpu) (sn_cpu_info[(cpu)].p_nasid) +#define cputoslice(cpu) (sn_cpu_info[(cpu)].p_slice) #define makespnum(_nasid, _slice) \ (((_nasid) << CPUS_PER_NODE_SHFT) | (_slice)) From df78b5c8faa72b3c04f82faab126de93af178348 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 5 Sep 2007 08:58:26 +0200 Subject: [PATCH 2230/2804] [MIPS] Move CFE code into arch/mips/fw/cfe Move the platform independent part of the CFE code to arch/mips/fw/cfe from arch/mips/sibyte/cfe. Signed-off-by: Aurelien Jarno Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 3 +++ arch/mips/Makefile | 1 + arch/mips/fw/cfe/Makefile | 5 +++++ arch/mips/{sibyte => fw}/cfe/cfe_api.c | 2 +- arch/mips/{sibyte => fw}/cfe/cfe_api_int.h | 0 arch/mips/sibyte/Kconfig | 1 + arch/mips/sibyte/cfe/Makefile | 2 +- arch/mips/sibyte/cfe/console.c | 4 ++-- arch/mips/sibyte/cfe/setup.c | 4 ++-- arch/mips/sibyte/cfe/smp.c | 4 ++-- {arch/mips/sibyte => include/asm-mips/fw}/cfe/cfe_api.h | 0 {arch/mips/sibyte => include/asm-mips/fw}/cfe/cfe_error.h | 0 12 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 arch/mips/fw/cfe/Makefile rename arch/mips/{sibyte => fw}/cfe/cfe_api.c (99%) rename arch/mips/{sibyte => fw}/cfe/cfe_api_int.h (100%) rename {arch/mips/sibyte => include/asm-mips/fw}/cfe/cfe_api.h (100%) rename {arch/mips/sibyte => include/asm-mips/fw}/cfe/cfe_error.h (100%) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 90b409d06153..4863494bac9f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -688,6 +688,9 @@ config ARCH_MAY_HAVE_PC_FDC config BOOT_RAW bool +config CFE + bool + config DMA_COHERENT bool diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 7b936edd2c16..a097ae61eb6b 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -149,6 +149,7 @@ endif # Firmware support # libs-$(CONFIG_ARC) += arch/mips/arc/ +libs-$(CONFIG_CFE) += arch/mips/fw/cfe/ libs-$(CONFIG_SIBYTE_CFE) += arch/mips/sibyte/cfe/ # diff --git a/arch/mips/fw/cfe/Makefile b/arch/mips/fw/cfe/Makefile new file mode 100644 index 000000000000..8f20044c0adf --- /dev/null +++ b/arch/mips/fw/cfe/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Broadcom Common Firmware Environment support +# + +lib-y += cfe_api.o diff --git a/arch/mips/sibyte/cfe/cfe_api.c b/arch/mips/fw/cfe/cfe_api.c similarity index 99% rename from arch/mips/sibyte/cfe/cfe_api.c rename to arch/mips/fw/cfe/cfe_api.c index c0213605e18a..a9f69e4e40ac 100644 --- a/arch/mips/sibyte/cfe/cfe_api.c +++ b/arch/mips/fw/cfe/cfe_api.c @@ -30,7 +30,7 @@ * ********************************************************************* */ -#include "cfe_api.h" +#include #include "cfe_api_int.h" /* Cast from a native pointer to a cfe_xptr_t and back. */ diff --git a/arch/mips/sibyte/cfe/cfe_api_int.h b/arch/mips/fw/cfe/cfe_api_int.h similarity index 100% rename from arch/mips/sibyte/cfe/cfe_api_int.h rename to arch/mips/fw/cfe/cfe_api_int.h diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index fdd7bd98fb44..841b301c99f0 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -124,6 +124,7 @@ config SB1_CERR_STALL config SIBYTE_CFE bool "Booting from CFE" depends on SIBYTE_SB1xxx_SOC + select CFE select SYS_HAS_EARLY_PRINTK help Make use of the CFE API for enumerating available memory, diff --git a/arch/mips/sibyte/cfe/Makefile b/arch/mips/sibyte/cfe/Makefile index 059d84a1d8a8..a1214937b705 100644 --- a/arch/mips/sibyte/cfe/Makefile +++ b/arch/mips/sibyte/cfe/Makefile @@ -1,3 +1,3 @@ -lib-y = cfe_api.o setup.o +lib-y = setup.o lib-$(CONFIG_SMP) += smp.o lib-$(CONFIG_SIBYTE_CFE_CONSOLE) += console.o diff --git a/arch/mips/sibyte/cfe/console.c b/arch/mips/sibyte/cfe/console.c index 4cec9d798d2f..7a4ecfcde48d 100644 --- a/arch/mips/sibyte/cfe/console.c +++ b/arch/mips/sibyte/cfe/console.c @@ -4,8 +4,8 @@ #include -#include "cfe_api.h" -#include "cfe_error.h" +#include +#include extern int cfe_cons_handle; diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c index 51898dd1304a..d842b98efb67 100644 --- a/arch/mips/sibyte/cfe/setup.c +++ b/arch/mips/sibyte/cfe/setup.c @@ -29,8 +29,8 @@ #include #include -#include "cfe_api.h" -#include "cfe_error.h" +#include +#include /* Max ram addressable in 32-bit segments */ #ifdef CONFIG_64BIT diff --git a/arch/mips/sibyte/cfe/smp.c b/arch/mips/sibyte/cfe/smp.c index 5de4cff9d14a..534a62912f21 100644 --- a/arch/mips/sibyte/cfe/smp.c +++ b/arch/mips/sibyte/cfe/smp.c @@ -21,8 +21,8 @@ #include #include -#include "cfe_api.h" -#include "cfe_error.h" +#include +#include /* * Use CFE to find out how many CPUs are available, setting up diff --git a/arch/mips/sibyte/cfe/cfe_api.h b/include/asm-mips/fw/cfe/cfe_api.h similarity index 100% rename from arch/mips/sibyte/cfe/cfe_api.h rename to include/asm-mips/fw/cfe/cfe_api.h diff --git a/arch/mips/sibyte/cfe/cfe_error.h b/include/asm-mips/fw/cfe/cfe_error.h similarity index 100% rename from arch/mips/sibyte/cfe/cfe_error.h rename to include/asm-mips/fw/cfe/cfe_error.h From 2f56cfdd812a17623483d3dfa3370a2e6282b245 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 5 Sep 2007 08:59:34 +0200 Subject: [PATCH 2231/2804] [MIPS] Move ARC code into arch/mips/fw/arc Move the ARC code to arch/mips/fw/arc from arch/mips/arc. Signed-off-by: Aurelien Jarno Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 2 +- arch/mips/{ => fw}/arc/Makefile | 0 arch/mips/{ => fw}/arc/arc_con.c | 0 arch/mips/{ => fw}/arc/cmdline.c | 0 arch/mips/{ => fw}/arc/env.c | 2 +- arch/mips/{ => fw}/arc/file.c | 2 +- arch/mips/{ => fw}/arc/identify.c | 0 arch/mips/{ => fw}/arc/init.c | 0 arch/mips/{ => fw}/arc/memory.c | 0 arch/mips/{ => fw}/arc/misc.c | 2 +- arch/mips/{ => fw}/arc/promlib.c | 0 arch/mips/{ => fw}/arc/salone.c | 0 arch/mips/{ => fw}/arc/time.c | 2 +- arch/mips/{ => fw}/arc/tree.c | 2 +- arch/mips/sni/setup.c | 2 +- include/asm-mips/{ => fw}/arc/hinv.h | 2 +- include/asm-mips/{ => fw}/arc/types.h | 0 include/asm-mips/sgiarcs.h | 2 +- include/asm-mips/sn/klconfig.h | 4 ++-- 19 files changed, 11 insertions(+), 11 deletions(-) rename arch/mips/{ => fw}/arc/Makefile (100%) rename arch/mips/{ => fw}/arc/arc_con.c (100%) rename arch/mips/{ => fw}/arc/cmdline.c (100%) rename arch/mips/{ => fw}/arc/env.c (95%) rename arch/mips/{ => fw}/arc/file.c (98%) rename arch/mips/{ => fw}/arc/identify.c (100%) rename arch/mips/{ => fw}/arc/init.c (100%) rename arch/mips/{ => fw}/arc/memory.c (100%) rename arch/mips/{ => fw}/arc/misc.c (97%) rename arch/mips/{ => fw}/arc/promlib.c (100%) rename arch/mips/{ => fw}/arc/salone.c (100%) rename arch/mips/{ => fw}/arc/time.c (94%) rename arch/mips/{ => fw}/arc/tree.c (99%) rename include/asm-mips/{ => fw}/arc/hinv.h (99%) rename include/asm-mips/{ => fw}/arc/types.h (100%) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index a097ae61eb6b..b0fac2d436b7 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -148,7 +148,7 @@ endif # # Firmware support # -libs-$(CONFIG_ARC) += arch/mips/arc/ +libs-$(CONFIG_ARC) += arch/mips/fw/arc/ libs-$(CONFIG_CFE) += arch/mips/fw/cfe/ libs-$(CONFIG_SIBYTE_CFE) += arch/mips/sibyte/cfe/ diff --git a/arch/mips/arc/Makefile b/arch/mips/fw/arc/Makefile similarity index 100% rename from arch/mips/arc/Makefile rename to arch/mips/fw/arc/Makefile diff --git a/arch/mips/arc/arc_con.c b/arch/mips/fw/arc/arc_con.c similarity index 100% rename from arch/mips/arc/arc_con.c rename to arch/mips/fw/arc/arc_con.c diff --git a/arch/mips/arc/cmdline.c b/arch/mips/fw/arc/cmdline.c similarity index 100% rename from arch/mips/arc/cmdline.c rename to arch/mips/fw/arc/cmdline.c diff --git a/arch/mips/arc/env.c b/arch/mips/fw/arc/env.c similarity index 95% rename from arch/mips/arc/env.c rename to arch/mips/fw/arc/env.c index e521a6e010aa..6f5dd42b96e2 100644 --- a/arch/mips/arc/env.c +++ b/arch/mips/fw/arc/env.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include PCHAR __init diff --git a/arch/mips/arc/file.c b/arch/mips/fw/arc/file.c similarity index 98% rename from arch/mips/arc/file.c rename to arch/mips/fw/arc/file.c index cb0127cf5bc1..30335341b447 100644 --- a/arch/mips/arc/file.c +++ b/arch/mips/fw/arc/file.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include LONG diff --git a/arch/mips/arc/identify.c b/arch/mips/fw/arc/identify.c similarity index 100% rename from arch/mips/arc/identify.c rename to arch/mips/fw/arc/identify.c diff --git a/arch/mips/arc/init.c b/arch/mips/fw/arc/init.c similarity index 100% rename from arch/mips/arc/init.c rename to arch/mips/fw/arc/init.c diff --git a/arch/mips/arc/memory.c b/arch/mips/fw/arc/memory.c similarity index 100% rename from arch/mips/arc/memory.c rename to arch/mips/fw/arc/memory.c diff --git a/arch/mips/arc/misc.c b/arch/mips/fw/arc/misc.c similarity index 97% rename from arch/mips/arc/misc.c rename to arch/mips/fw/arc/misc.c index b2e10b9e9452..e527c5fd5a32 100644 --- a/arch/mips/arc/misc.c +++ b/arch/mips/fw/arc/misc.c @@ -14,7 +14,7 @@ #include -#include +#include #include #include #include diff --git a/arch/mips/arc/promlib.c b/arch/mips/fw/arc/promlib.c similarity index 100% rename from arch/mips/arc/promlib.c rename to arch/mips/fw/arc/promlib.c diff --git a/arch/mips/arc/salone.c b/arch/mips/fw/arc/salone.c similarity index 100% rename from arch/mips/arc/salone.c rename to arch/mips/fw/arc/salone.c diff --git a/arch/mips/arc/time.c b/arch/mips/fw/arc/time.c similarity index 94% rename from arch/mips/arc/time.c rename to arch/mips/fw/arc/time.c index 299ff2c5c0b5..42138c837d48 100644 --- a/arch/mips/arc/time.c +++ b/arch/mips/fw/arc/time.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include struct linux_tinfo * __init diff --git a/arch/mips/arc/tree.c b/arch/mips/fw/arc/tree.c similarity index 99% rename from arch/mips/arc/tree.c rename to arch/mips/fw/arc/tree.c index abd1786ea09b..d68e5a59c1f6 100644 --- a/arch/mips/arc/tree.c +++ b/arch/mips/fw/arc/tree.c @@ -10,7 +10,7 @@ * Copyright (C) 1999 Silicon Graphics, Inc. */ #include -#include +#include #include #undef DEBUG_PROM_TREE diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 6edbb3051c82..883e35ea4e82 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -15,7 +15,7 @@ #include #ifdef CONFIG_ARC -#include +#include #include #endif diff --git a/include/asm-mips/arc/hinv.h b/include/asm-mips/fw/arc/hinv.h similarity index 99% rename from include/asm-mips/arc/hinv.h rename to include/asm-mips/fw/arc/hinv.h index 1862912ab148..e6ff4add04e2 100644 --- a/include/asm-mips/arc/hinv.h +++ b/include/asm-mips/fw/arc/hinv.h @@ -5,7 +5,7 @@ #define _ASM_ARC_HINV_H #include -#include +#include /* configuration query defines */ typedef enum configclass { diff --git a/include/asm-mips/arc/types.h b/include/asm-mips/fw/arc/types.h similarity index 100% rename from include/asm-mips/arc/types.h rename to include/asm-mips/fw/arc/types.h diff --git a/include/asm-mips/sgiarcs.h b/include/asm-mips/sgiarcs.h index 439bce7daa3a..6d1eda60e01f 100644 --- a/include/asm-mips/sgiarcs.h +++ b/include/asm-mips/sgiarcs.h @@ -13,7 +13,7 @@ #define _ASM_SGIARCS_H #include -#include +#include /* Various ARCS error codes. */ #define PROM_ESUCCESS 0x00 diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h index 82aeb9e322db..852213d03b72 100644 --- a/include/asm-mips/sn/klconfig.h +++ b/include/asm-mips/sn/klconfig.h @@ -51,8 +51,8 @@ #if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP35) #include -#include -#include +#include +#include #if defined(CONFIG_SGI_IP35) // The hack file has to be before vector and after sn0_fru.... #include From 25e5fb97419f73d39b37e9f73f9492c394de07b2 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 25 Sep 2007 15:41:24 +0200 Subject: [PATCH 2232/2804] [MIPS] Add CFE support to BCM47XX Add CFE support to the BCM47XX code. That includes querying CFE environment variables as well as using CFE to print messages before the serial port is initialized (early printk). Signed-off-by: Aurelien Jarno Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 2 + arch/mips/bcm47xx/prom.c | 113 +++++++++++++++++++++++++++++++++++++- arch/mips/bcm47xx/setup.c | 51 ++++++++++++++++- 3 files changed, 161 insertions(+), 5 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 4863494bac9f..371434dd744c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -55,6 +55,8 @@ config BCM47XX select SSB select SSB_DRIVER_MIPS select GENERIC_GPIO + select SYS_HAS_EARLY_PRINTK + select CFE help Support for BCM47XX based boards diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c index 41ac9dd88bde..079e33d52783 100644 --- a/arch/mips/bcm47xx/prom.c +++ b/arch/mips/bcm47xx/prom.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2004 Florian Schirmer + * Copyright (C) 2007 Aurelien Jarno * * 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 @@ -23,18 +24,117 @@ */ #include +#include +#include +#include #include +#include +#include + +static int cfe_cons_handle; const char *get_system_type(void) { return "Broadcom BCM47XX"; } -void __init prom_init(void) +void prom_putchar(char c) +{ + while (cfe_write(cfe_cons_handle, &c, 1) == 0) + ; +} + +static __init void prom_init_cfe(void) +{ + uint32_t cfe_ept; + uint32_t cfe_handle; + uint32_t cfe_eptseal; + int argc = fw_arg0; + char **envp = (char **) fw_arg2; + int *prom_vec = (int *) fw_arg3; + + /* + * Check if a loader was used; if NOT, the 4 arguments are + * what CFE gives us (handle, 0, EPT and EPTSEAL) + */ + if (argc < 0) { + cfe_handle = (uint32_t)argc; + cfe_ept = (uint32_t)envp; + cfe_eptseal = (uint32_t)prom_vec; + } else { + if ((int)prom_vec < 0) { + /* + * Old loader; all it gives us is the handle, + * so use the "known" entrypoint and assume + * the seal. + */ + cfe_handle = (uint32_t)prom_vec; + cfe_ept = 0xBFC00500; + cfe_eptseal = CFE_EPTSEAL; + } else { + /* + * Newer loaders bundle the handle/ept/eptseal + * Note: prom_vec is in the loader's useg + * which is still alive in the TLB. + */ + cfe_handle = prom_vec[0]; + cfe_ept = prom_vec[2]; + cfe_eptseal = prom_vec[3]; + } + } + + if (cfe_eptseal != CFE_EPTSEAL) { + /* too early for panic to do any good */ + printk(KERN_ERR "CFE's entrypoint seal doesn't match."); + while (1) ; + } + + cfe_init(cfe_handle, cfe_ept); +} + +static __init void prom_init_console(void) +{ + /* Initialize CFE console */ + cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); +} + +static __init void prom_init_cmdline(void) +{ + char buf[CL_SIZE]; + + /* Get the kernel command line from CFE */ + if (cfe_getenv("LINUX_CMDLINE", buf, CL_SIZE) >= 0) { + buf[CL_SIZE-1] = 0; + strcpy(arcs_cmdline, buf); + } + + /* Force a console handover by adding a console= argument if needed, + * as CFE is not available anymore later in the boot process. */ + if ((strstr(arcs_cmdline, "console=")) == NULL) { + /* Try to read the default serial port used by CFE */ + if ((cfe_getenv("BOOT_CONSOLE", buf, CL_SIZE) < 0) + || (strncmp("uart", buf, 4))) + /* Default to uart0 */ + strcpy(buf, "uart0"); + + /* Compute the new command line */ + snprintf(arcs_cmdline, CL_SIZE, "%s console=ttyS%c,115200", + arcs_cmdline, buf[4]); + } +} + +static __init void prom_init_mem(void) { unsigned long mem; - /* Figure out memory size by finding aliases */ + /* Figure out memory size by finding aliases. + * + * We should theoretically use the mapping from CFE using cfe_enummem(). + * However as the BCM47XX is mostly used on low-memory systems, we + * want to reuse the memory used by CFE (around 4MB). That means cfe_* + * functions stop to work at some point during the boot, we should only + * call them at the beginning of the boot. + */ for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { if (*(unsigned long *)((unsigned long)(prom_init) + mem) == *(unsigned long *)(prom_init)) @@ -44,6 +144,15 @@ void __init prom_init(void) add_memory_region(0, mem, BOOT_MEM_RAM); } +void __init prom_init(void) +{ + prom_init_cfe(); + prom_init_console(); + prom_init_cmdline(); + prom_init_mem(); +} + void __init prom_free_prom_memory(void) { } + diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index dfc580aae958..f48aa5aa9bf0 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -27,9 +27,11 @@ #include #include +#include #include #include #include +#include struct ssb_bus ssb_bcm47xx; EXPORT_SYMBOL(ssb_bcm47xx); @@ -53,12 +55,55 @@ static void bcm47xx_machine_halt(void) cpu_relax(); } +static void str2eaddr(char *str, char *dest) +{ + int i = 0; + + if (str == NULL) { + memset(dest, 0, 6); + return; + } + + for (;;) { + dest[i++] = (char) simple_strtoul(str, NULL, 16); + str += 2; + if (!*str++ || i == 6) + break; + } +} + static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) { - /* TODO: fill ssb_init_invariants using boardtype/boardrev - * CFE environment variables. - */ + char buf[100]; + + /* Fill boardinfo structure */ + memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); + + if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0) + iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); + if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0) + iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); + if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0) + iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); + + /* Fill sprom structure */ + memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); + iv->sprom.revision = 3; + + if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) + str2eaddr(buf, iv->sprom.r1.et0mac); + if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) + str2eaddr(buf, iv->sprom.r1.et1mac); + if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) + iv->sprom.r1.et0phyaddr = simple_strtoul(buf, NULL, 10); + if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) + iv->sprom.r1.et1phyaddr = simple_strtoul(buf, NULL, 10); + if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) + iv->sprom.r1.et0mdcport = simple_strtoul(buf, NULL, 10); + if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) + iv->sprom.r1.et1mdcport = simple_strtoul(buf, NULL, 10); + return 0; } From 34cc662f8aae0ce1db5c64d55a39a5081f9e3cd8 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 25 Sep 2007 15:42:09 +0200 Subject: [PATCH 2233/2804] [MIPS] Add gpio support to the BCM47XX platform Add GPIO support to the BCM47XX platform. It will be used by a GPIO LED driver. Signed-off-by: Aurelien Jarno Signed-off-by: Ralf Baechle --- arch/mips/bcm47xx/Makefile | 2 +- arch/mips/bcm47xx/gpio.c | 79 ++++++++++++++++++++++++++++ include/asm-mips/mach-bcm47xx/gpio.h | 59 +++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 arch/mips/bcm47xx/gpio.c create mode 100644 include/asm-mips/mach-bcm47xx/gpio.h diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile index dc035f90d363..0afe09703e3f 100644 --- a/arch/mips/bcm47xx/Makefile +++ b/arch/mips/bcm47xx/Makefile @@ -3,4 +3,4 @@ # under Linux. # -obj-y := irq.o prom.o serial.o setup.o time.o +obj-y := gpio.o irq.o prom.o serial.o setup.o time.o diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c new file mode 100644 index 000000000000..f5a53acf995a --- /dev/null +++ b/arch/mips/bcm47xx/gpio.c @@ -0,0 +1,79 @@ +/* + * 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. + * + * Copyright (C) 2007 Aurelien Jarno + */ + +#include +#include +#include +#include +#include + +int bcm47xx_gpio_to_irq(unsigned gpio) +{ + if (ssb_bcm47xx.chipco.dev) + return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2; + else if (ssb_bcm47xx.extif.dev) + return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2; + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(bcm47xx_gpio_to_irq); + +int bcm47xx_gpio_get_value(unsigned gpio) +{ + if (ssb_bcm47xx.chipco.dev) + return ssb_chipco_gpio_in(&ssb_bcm47xx.chipco, 1 << gpio); + else if (ssb_bcm47xx.extif.dev) + return ssb_extif_gpio_in(&ssb_bcm47xx.extif, 1 << gpio); + else + return 0; +} +EXPORT_SYMBOL_GPL(bcm47xx_gpio_get_value); + +void bcm47xx_gpio_set_value(unsigned gpio, int value) +{ + if (ssb_bcm47xx.chipco.dev) + ssb_chipco_gpio_out(&ssb_bcm47xx.chipco, + 1 << gpio, + value ? 1 << gpio : 0); + else if (ssb_bcm47xx.extif.dev) + ssb_extif_gpio_out(&ssb_bcm47xx.extif, + 1 << gpio, + value ? 1 << gpio : 0); +} +EXPORT_SYMBOL_GPL(bcm47xx_gpio_set_value); + +int bcm47xx_gpio_direction_input(unsigned gpio) +{ + if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES)) + ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco, + 1 << gpio, 0); + else if (ssb_bcm47xx.extif.dev && (gpio < BCM47XX_EXTIF_GPIO_LINES)) + ssb_extif_gpio_outen(&ssb_bcm47xx.extif, + 1 << gpio, 0); + else + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_input); + +int bcm47xx_gpio_direction_output(unsigned gpio, int value) +{ + bcm47xx_gpio_set_value(gpio, value); + + if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES)) + ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco, + 1 << gpio, 1 << gpio); + else if (ssb_bcm47xx.extif.dev && (gpio < BCM47XX_EXTIF_GPIO_LINES)) + ssb_extif_gpio_outen(&ssb_bcm47xx.extif, + 1 << gpio, 1 << gpio); + else + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_output); + diff --git a/include/asm-mips/mach-bcm47xx/gpio.h b/include/asm-mips/mach-bcm47xx/gpio.h new file mode 100644 index 000000000000..cfc8f4d618ce --- /dev/null +++ b/include/asm-mips/mach-bcm47xx/gpio.h @@ -0,0 +1,59 @@ +/* + * 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. + * + * Copyright (C) 2007 Aurelien Jarno + */ + +#ifndef __BCM47XX_GPIO_H +#define __BCM47XX_GPIO_H + +#define BCM47XX_EXTIF_GPIO_LINES 5 +#define BCM47XX_CHIPCO_GPIO_LINES 16 + +extern int bcm47xx_gpio_to_irq(unsigned gpio); +extern int bcm47xx_gpio_get_value(unsigned gpio); +extern void bcm47xx_gpio_set_value(unsigned gpio, int value); +extern int bcm47xx_gpio_direction_input(unsigned gpio); +extern int bcm47xx_gpio_direction_output(unsigned gpio, int value); + +static inline int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +static inline void gpio_free(unsigned gpio) +{ +} + +static inline int gpio_to_irq(unsigned gpio) +{ + return bcm47xx_gpio_to_irq(gpio); +} + +static inline int gpio_get_value(unsigned gpio) +{ + return bcm47xx_gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + bcm47xx_gpio_set_value(gpio, value); +} + +static inline int gpio_direction_input(unsigned gpio) +{ + return bcm47xx_gpio_direction_input(gpio); +} + +static inline int gpio_direction_output(unsigned gpio, int value) +{ + return bcm47xx_gpio_direction_output(gpio, value); +} + + +/* cansleep wrappers */ +#include + +#endif /* __BCM47XX_GPIO_H */ From 21c854dcbd7698bf723676a552968040e2813490 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 25 Sep 2007 15:43:07 +0200 Subject: [PATCH 2234/2804] [MIPS] GPIO LED driver for the WGT634U machine Add LED support to the WGT634U machine. It uses the new gpio-led driver and a platform driver for the pin definitions. Signed-off-by: Aurelien Jarno Signed-off-by: Ralf Baechle --- arch/mips/bcm47xx/Makefile | 2 +- arch/mips/bcm47xx/wgt634u.c | 64 +++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 arch/mips/bcm47xx/wgt634u.c diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile index 0afe09703e3f..35294b12d638 100644 --- a/arch/mips/bcm47xx/Makefile +++ b/arch/mips/bcm47xx/Makefile @@ -3,4 +3,4 @@ # under Linux. # -obj-y := gpio.o irq.o prom.o serial.o setup.o time.o +obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c new file mode 100644 index 000000000000..5a017eaee712 --- /dev/null +++ b/arch/mips/bcm47xx/wgt634u.c @@ -0,0 +1,64 @@ +/* + * 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. + * + * Copyright (C) 2007 Aurelien Jarno + */ + +#include +#include +#include +#include +#include + +/* GPIO definitions for the WGT634U */ +#define WGT634U_GPIO_LED 3 +#define WGT634U_GPIO_RESET 2 +#define WGT634U_GPIO_TP1 7 +#define WGT634U_GPIO_TP2 6 +#define WGT634U_GPIO_TP3 5 +#define WGT634U_GPIO_TP4 4 +#define WGT634U_GPIO_TP5 1 + +static struct gpio_led wgt634u_leds[] = { + { + .name = "power", + .gpio = WGT634U_GPIO_LED, + .active_low = 1, + .default_trigger = "heartbeat", + }, +}; + +static struct gpio_led_platform_data wgt634u_led_data = { + .num_leds = ARRAY_SIZE(wgt634u_leds), + .leds = wgt634u_leds, +}; + +static struct platform_device wgt634u_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &wgt634u_led_data, + } +}; + +static int __init wgt634u_init(void) +{ + /* There is no easy way to detect that we are running on a WGT634U + * machine. Use the MAC address as an heuristic. Netgear Inc. has + * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx. + */ + + u8 *et0mac = ssb_bcm47xx.sprom.r1.et0mac; + + if (et0mac[0] == 0x00 && + ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) || + (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) + return platform_device_register(&wgt634u_gpio_leds); + else + return -ENODEV; +} + +module_init(wgt634u_init); + From baf22c1e7aedf264e264b15d2595e5e76564bd4e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:07 +0100 Subject: [PATCH 2235/2804] [MIPS] Split up war.h It was getting a little big, ugly and a primary source for merge conflicts. Also the old method was a bit too forgiving in that the workaround did default to off, so now there is an explicit #error forcing platform maintainers to think if they should enable a workaround for a particular platform. Signed-off-by: Ralf Baechle --- include/asm-mips/mach-au1x00/war.h | 25 ++++++ include/asm-mips/mach-bcm47xx/war.h | 25 ++++++ include/asm-mips/mach-cobalt/war.h | 25 ++++++ include/asm-mips/mach-dec/war.h | 25 ++++++ include/asm-mips/mach-emma2rh/war.h | 25 ++++++ include/asm-mips/mach-excite/war.h | 25 ++++++ include/asm-mips/mach-ip22/war.h | 29 ++++++ include/asm-mips/mach-ip27/war.h | 25 ++++++ include/asm-mips/mach-ip32/war.h | 25 ++++++ include/asm-mips/mach-jazz/war.h | 25 ++++++ include/asm-mips/mach-jmr3927/war.h | 25 ++++++ include/asm-mips/mach-lasat/war.h | 25 ++++++ include/asm-mips/mach-lemote/war.h | 25 ++++++ include/asm-mips/mach-mips/war.h | 25 ++++++ include/asm-mips/mach-mipssim/war.h | 25 ++++++ include/asm-mips/mach-pnx8550/war.h | 25 ++++++ include/asm-mips/mach-qemu/war.h | 25 ++++++ include/asm-mips/mach-rm/war.h | 29 ++++++ include/asm-mips/mach-sibyte/war.h | 37 ++++++++ include/asm-mips/mach-tx49xx/war.h | 25 ++++++ include/asm-mips/mach-vr41xx/war.h | 25 ++++++ include/asm-mips/mach-wrppmc/war.h | 25 ++++++ include/asm-mips/mach-yosemite/war.h | 25 ++++++ include/asm-mips/war.h | 127 +++++++-------------------- 24 files changed, 625 insertions(+), 97 deletions(-) create mode 100644 include/asm-mips/mach-au1x00/war.h create mode 100644 include/asm-mips/mach-bcm47xx/war.h create mode 100644 include/asm-mips/mach-cobalt/war.h create mode 100644 include/asm-mips/mach-dec/war.h create mode 100644 include/asm-mips/mach-emma2rh/war.h create mode 100644 include/asm-mips/mach-excite/war.h create mode 100644 include/asm-mips/mach-ip22/war.h create mode 100644 include/asm-mips/mach-ip27/war.h create mode 100644 include/asm-mips/mach-ip32/war.h create mode 100644 include/asm-mips/mach-jazz/war.h create mode 100644 include/asm-mips/mach-jmr3927/war.h create mode 100644 include/asm-mips/mach-lasat/war.h create mode 100644 include/asm-mips/mach-lemote/war.h create mode 100644 include/asm-mips/mach-mips/war.h create mode 100644 include/asm-mips/mach-mipssim/war.h create mode 100644 include/asm-mips/mach-pnx8550/war.h create mode 100644 include/asm-mips/mach-qemu/war.h create mode 100644 include/asm-mips/mach-rm/war.h create mode 100644 include/asm-mips/mach-sibyte/war.h create mode 100644 include/asm-mips/mach-tx49xx/war.h create mode 100644 include/asm-mips/mach-vr41xx/war.h create mode 100644 include/asm-mips/mach-wrppmc/war.h create mode 100644 include/asm-mips/mach-yosemite/war.h diff --git a/include/asm-mips/mach-au1x00/war.h b/include/asm-mips/mach-au1x00/war.h new file mode 100644 index 000000000000..dd57d03d68ba --- /dev/null +++ b/include/asm-mips/mach-au1x00/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_AU1X00_WAR_H +#define __ASM_MIPS_MACH_AU1X00_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_AU1X00_WAR_H */ diff --git a/include/asm-mips/mach-bcm47xx/war.h b/include/asm-mips/mach-bcm47xx/war.h new file mode 100644 index 000000000000..4a2b7986b582 --- /dev/null +++ b/include/asm-mips/mach-bcm47xx/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_BCM947XX_WAR_H +#define __ASM_MIPS_MACH_BCM947XX_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_BCM947XX_WAR_H */ diff --git a/include/asm-mips/mach-cobalt/war.h b/include/asm-mips/mach-cobalt/war.h new file mode 100644 index 000000000000..97884fd18ac0 --- /dev/null +++ b/include/asm-mips/mach-cobalt/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_COBALT_WAR_H +#define __ASM_MIPS_MACH_COBALT_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_COBALT_WAR_H */ diff --git a/include/asm-mips/mach-dec/war.h b/include/asm-mips/mach-dec/war.h new file mode 100644 index 000000000000..ca5e2ef909ad --- /dev/null +++ b/include/asm-mips/mach-dec/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_DEC_WAR_H +#define __ASM_MIPS_MACH_DEC_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_DEC_WAR_H */ diff --git a/include/asm-mips/mach-emma2rh/war.h b/include/asm-mips/mach-emma2rh/war.h new file mode 100644 index 000000000000..b660a4c30e6a --- /dev/null +++ b/include/asm-mips/mach-emma2rh/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_EMMA2RH_WAR_H +#define __ASM_MIPS_MACH_EMMA2RH_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_EMMA2RH_WAR_H */ diff --git a/include/asm-mips/mach-excite/war.h b/include/asm-mips/mach-excite/war.h new file mode 100644 index 000000000000..1f82180c1598 --- /dev/null +++ b/include/asm-mips/mach-excite/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_EXCITE_WAR_H +#define __ASM_MIPS_MACH_EXCITE_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 1 +#define ICACHE_REFILLS_WORKAROUND_WAR 1 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_EXCITE_WAR_H */ diff --git a/include/asm-mips/mach-ip22/war.h b/include/asm-mips/mach-ip22/war.h new file mode 100644 index 000000000000..a44fa9656a82 --- /dev/null +++ b/include/asm-mips/mach-ip22/war.h @@ -0,0 +1,29 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_IP22_WAR_H +#define __ASM_MIPS_MACH_IP22_WAR_H + +/* + * R4600 CPU modules for the Indy come with both V1.7 and V2.0 processors. + */ + +#define R4600_V1_INDEX_ICACHEOP_WAR 1 +#define R4600_V1_HIT_CACHEOP_WAR 1 +#define R4600_V2_HIT_CACHEOP_WAR 1 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_IP22_WAR_H */ diff --git a/include/asm-mips/mach-ip27/war.h b/include/asm-mips/mach-ip27/war.h new file mode 100644 index 000000000000..e2ddcc9b1fff --- /dev/null +++ b/include/asm-mips/mach-ip27/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_IP27_WAR_H +#define __ASM_MIPS_MACH_IP27_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 1 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_IP27_WAR_H */ diff --git a/include/asm-mips/mach-ip32/war.h b/include/asm-mips/mach-ip32/war.h new file mode 100644 index 000000000000..d194056dcd7a --- /dev/null +++ b/include/asm-mips/mach-ip32/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_IP32_WAR_H +#define __ASM_MIPS_MACH_IP32_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 1 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_IP32_WAR_H */ diff --git a/include/asm-mips/mach-jazz/war.h b/include/asm-mips/mach-jazz/war.h new file mode 100644 index 000000000000..6158ee861bfd --- /dev/null +++ b/include/asm-mips/mach-jazz/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_JAZZ_WAR_H +#define __ASM_MIPS_MACH_JAZZ_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_JAZZ_WAR_H */ diff --git a/include/asm-mips/mach-jmr3927/war.h b/include/asm-mips/mach-jmr3927/war.h new file mode 100644 index 000000000000..1ff55fb3fbcb --- /dev/null +++ b/include/asm-mips/mach-jmr3927/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_JMR3927_WAR_H +#define __ASM_MIPS_MACH_JMR3927_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_JMR3927_WAR_H */ diff --git a/include/asm-mips/mach-lasat/war.h b/include/asm-mips/mach-lasat/war.h new file mode 100644 index 000000000000..bb1e0325c9be --- /dev/null +++ b/include/asm-mips/mach-lasat/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_LASAT_WAR_H +#define __ASM_MIPS_MACH_LASAT_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_LASAT_WAR_H */ diff --git a/include/asm-mips/mach-lemote/war.h b/include/asm-mips/mach-lemote/war.h new file mode 100644 index 000000000000..05f89e0f2a11 --- /dev/null +++ b/include/asm-mips/mach-lemote/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_LEMOTE_WAR_H +#define __ASM_MIPS_MACH_LEMOTE_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_LEMOTE_WAR_H */ diff --git a/include/asm-mips/mach-mips/war.h b/include/asm-mips/mach-mips/war.h new file mode 100644 index 000000000000..7c6931d5f45f --- /dev/null +++ b/include/asm-mips/mach-mips/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_MIPS_WAR_H +#define __ASM_MIPS_MACH_MIPS_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 1 +#define MIPS_CACHE_SYNC_WAR 1 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 1 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_MIPS_WAR_H */ diff --git a/include/asm-mips/mach-mipssim/war.h b/include/asm-mips/mach-mipssim/war.h new file mode 100644 index 000000000000..c8a74a3515e0 --- /dev/null +++ b/include/asm-mips/mach-mipssim/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_MIPSSIM_WAR_H +#define __ASM_MIPS_MACH_MIPSSIM_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_MIPSSIM_WAR_H */ diff --git a/include/asm-mips/mach-pnx8550/war.h b/include/asm-mips/mach-pnx8550/war.h new file mode 100644 index 000000000000..d0458dd082f9 --- /dev/null +++ b/include/asm-mips/mach-pnx8550/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_PNX8550_WAR_H +#define __ASM_MIPS_MACH_PNX8550_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_PNX8550_WAR_H */ diff --git a/include/asm-mips/mach-qemu/war.h b/include/asm-mips/mach-qemu/war.h new file mode 100644 index 000000000000..0eaf0c548a47 --- /dev/null +++ b/include/asm-mips/mach-qemu/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_QEMU_WAR_H +#define __ASM_MIPS_MACH_QEMU_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_QEMU_WAR_H */ diff --git a/include/asm-mips/mach-rm/war.h b/include/asm-mips/mach-rm/war.h new file mode 100644 index 000000000000..948d3129a114 --- /dev/null +++ b/include/asm-mips/mach-rm/war.h @@ -0,0 +1,29 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_RM_WAR_H +#define __ASM_MIPS_MACH_RM_WAR_H + +/* + * The RM200C seems to have been shipped only with V2.0 R4600s + */ + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 1 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_RM_WAR_H */ diff --git a/include/asm-mips/mach-sibyte/war.h b/include/asm-mips/mach-sibyte/war.h new file mode 100644 index 000000000000..7950ef4f032c --- /dev/null +++ b/include/asm-mips/mach-sibyte/war.h @@ -0,0 +1,37 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_SIBYTE_WAR_H +#define __ASM_MIPS_MACH_SIBYTE_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 + +#if defined(CONFIG_SB1_PASS_1_WORKAROUNDS) || \ + defined(CONFIG_SB1_PASS_2_WORKAROUNDS) + +#define BCM1250_M3_WAR 1 +#define SIBYTE_1956_WAR 1 + +#else + +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 + +#endif + +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_SIBYTE_WAR_H */ diff --git a/include/asm-mips/mach-tx49xx/war.h b/include/asm-mips/mach-tx49xx/war.h new file mode 100644 index 000000000000..39b5d1177c57 --- /dev/null +++ b/include/asm-mips/mach-tx49xx/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_TX49XX_WAR_H +#define __ASM_MIPS_MACH_TX49XX_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 1 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_TX49XX_WAR_H */ diff --git a/include/asm-mips/mach-vr41xx/war.h b/include/asm-mips/mach-vr41xx/war.h new file mode 100644 index 000000000000..56a38926412a --- /dev/null +++ b/include/asm-mips/mach-vr41xx/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_VR41XX_WAR_H +#define __ASM_MIPS_MACH_VR41XX_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_VR41XX_WAR_H */ diff --git a/include/asm-mips/mach-wrppmc/war.h b/include/asm-mips/mach-wrppmc/war.h new file mode 100644 index 000000000000..ac48629bb1ce --- /dev/null +++ b/include/asm-mips/mach-wrppmc/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_WRPPMC_WAR_H +#define __ASM_MIPS_MACH_WRPPMC_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 1 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_WRPPMC_WAR_H */ diff --git a/include/asm-mips/mach-yosemite/war.h b/include/asm-mips/mach-yosemite/war.h new file mode 100644 index 000000000000..e5c6d53efc86 --- /dev/null +++ b/include/asm-mips/mach-yosemite/war.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_YOSEMITE_WAR_H +#define __ASM_MIPS_MACH_YOSEMITE_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 1 +#define ICACHE_REFILLS_WORKAROUND_WAR 1 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_YOSEMITE_WAR_H */ diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h index c0715d0a6b28..d2808edfd4e9 100644 --- a/include/asm-mips/war.h +++ b/include/asm-mips/war.h @@ -3,20 +3,22 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2002, 2004 by Ralf Baechle + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle */ #ifndef _ASM_WAR_H #define _ASM_WAR_H +#include /* * Another R4600 erratum. Due to the lack of errata information the exact * technical details aren't known. I've experimentally found that disabling * interrupts during indexed I-cache flushes seems to be sufficient to deal * with the issue. - * - * #define R4600_V1_INDEX_ICACHEOP_WAR 1 */ +#ifndef R4600_V1_INDEX_ICACHEOP_WAR +#error Check setting of R4600_V1_INDEX_ICACHEOP_WAR for your platform +#endif /* * Pleasures of the R4600 V1.x. Cite from the IDT R4600 V1.7 errata: @@ -43,9 +45,10 @@ * nop * nop * cache Hit_Writeback_Invalidate_D - * - * #define R4600_V1_HIT_CACHEOP_WAR 1 */ +#ifndef R4600_V1_HIT_CACHEOP_WAR +#error Check setting of R4600_V1_HIT_CACHEOP_WAR for your platform +#endif /* @@ -58,32 +61,11 @@ * by a load instruction to an uncached address to empty the response buffer." * (Revision 2.0 device errata from IDT available on http://www.idt.com/ * in .pdf format.) - * - * #define R4600_V2_HIT_CACHEOP_WAR 1 */ - -/* - * R4600 CPU modules for the Indy come with both V1.7 and V2.0 processors. - */ -#ifdef CONFIG_SGI_IP22 - -#define R4600_V1_INDEX_ICACHEOP_WAR 1 -#define R4600_V1_HIT_CACHEOP_WAR 1 -#define R4600_V2_HIT_CACHEOP_WAR 1 - +#ifndef R4600_V2_HIT_CACHEOP_WAR +#error Check setting of R4600_V2_HIT_CACHEOP_WAR for your platform #endif -/* - * But the RM200C seems to have been shipped only with V2.0 R4600s - */ -#ifdef CONFIG_SNI_RM - -#define R4600_V2_HIT_CACHEOP_WAR 1 - -#endif - -#ifdef CONFIG_CPU_R5432 - /* * When an interrupt happens on a CP0 register read instruction, CPU may * lock up or read corrupted values of CP0 registers after it enters @@ -93,13 +75,10 @@ * first thing in the exception handler, which breaks one of the * pre-conditions for this problem. */ -#define R5432_CP0_INTERRUPT_WAR 1 - +#ifndef R5432_CP0_INTERRUPT_WAR +#error Check setting of R5432_CP0_INTERRUPT_WAR for your platform #endif -#if defined(CONFIG_SB1_PASS_1_WORKAROUNDS) || \ - defined(CONFIG_SB1_PASS_2_WORKAROUNDS) - /* * Workaround for the Sibyte M3 errata the text of which can be found at * @@ -110,13 +89,15 @@ * will just return and take the exception again if the information was * found to be inconsistent. */ -#define BCM1250_M3_WAR 1 +#ifndef BCM1250_M3_WAR +#error Check setting of BCM1250_M3_WAR for your platform +#endif /* * This is a DUART workaround related to glitches around register accesses */ -#define SIBYTE_1956_WAR 1 - +#ifndef SIBYTE_1956_WAR +#error Check setting of SIBYTE_1956_WAR for your platform #endif /* @@ -131,9 +112,8 @@ * Affects: * MIPS 4K RTL revision <3.0, PRID revision <4 */ -#if defined(CONFIG_MIPS_MALTA) || defined(CONFIG_MIPS_ATLAS) || \ - defined(CONFIG_MIPS_SEAD) -#define MIPS4K_ICACHE_REFILL_WAR 1 +#ifndef MIPS4K_ICACHE_REFILL_WAR +#error Check setting of MIPS4K_ICACHE_REFILL_WAR for your platform #endif /* @@ -151,9 +131,8 @@ * MIPS 5Kc,5Kf RTL revision <2.3, PRID revision <8 * MIPS 20Kc RTL revision <4.0, PRID revision Date: Mon, 24 Sep 2007 16:13:34 +0100 Subject: [PATCH 2236/2804] [MIPS] dec/time.c: Remove no longer needed inclusion of . Signed-off-by: Maciej W. Rozycki Signed-off-by: Ralf Baechle --- arch/mips/dec/time.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 8b7e0c17ac35..e2973a432b92 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include From 112b20a1e849aec8077bbf11fc3de338b62f363a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:07 +0100 Subject: [PATCH 2237/2804] [MIPS] ARC: Convert mach_table[] to ISO C initializers. Signed-off-by: Ralf Baechle --- arch/mips/fw/arc/identify.c | 88 ++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/arch/mips/fw/arc/identify.c b/arch/mips/fw/arc/identify.c index 4b907369b0f9..5d28dbe06f40 100644 --- a/arch/mips/fw/arc/identify.c +++ b/arch/mips/fw/arc/identify.c @@ -28,46 +28,54 @@ struct smatch { }; static struct smatch mach_table[] = { - { "SGI-IP22", - "SGI Indy", - MACH_GROUP_SGI, - MACH_SGI_IP22, - PROM_FLAG_ARCS - }, { "SGI-IP27", - "SGI Origin", - MACH_GROUP_SGI, - MACH_SGI_IP27, - PROM_FLAG_ARCS - }, { "SGI-IP28", - "SGI IP28", - MACH_GROUP_SGI, - MACH_SGI_IP28, - PROM_FLAG_ARCS - }, { "SGI-IP30", - "SGI Octane", - MACH_GROUP_SGI, - MACH_SGI_IP30, - PROM_FLAG_ARCS - }, { "SGI-IP32", - "SGI O2", - MACH_GROUP_SGI, - MACH_SGI_IP32, - PROM_FLAG_ARCS - }, { "Microsoft-Jazz", - "Jazz MIPS_Magnum_4000", - MACH_GROUP_JAZZ, - MACH_MIPS_MAGNUM_4000, - 0 - }, { "PICA-61", - "Jazz Acer_PICA_61", - MACH_GROUP_JAZZ, - MACH_ACER_PICA_61, - 0 - }, { "RM200PCI", - "SNI RM200_PCI", - MACH_GROUP_SNI_RM, - MACH_SNI_RM200_PCI, - PROM_FLAG_DONT_FREE_TEMP + { + .arcname = "SGI-IP22", + .liname = "SGI Indy", + .group = MACH_GROUP_SGI, + .type = MACH_SGI_IP22, + .flags = PROM_FLAG_ARCS, + }, { + .arcname = "SGI-IP27", + .liname = "SGI Origin", + .group = MACH_GROUP_SGI, + .type = MACH_SGI_IP27, + .flags = PROM_FLAG_ARCS, + }, { + .arcname = "SGI-IP28", + .liname = "SGI IP28", + .group = MACH_GROUP_SGI, + .type = MACH_SGI_IP28, + .flags = PROM_FLAG_ARCS, + }, { + .arcname = "SGI-IP30", + .liname = "SGI Octane", + .group = MACH_GROUP_SGI, + .type = MACH_SGI_IP30, + .flags = PROM_FLAG_ARCS, + }, { + .arcname = "SGI-IP32", + .liname = "SGI O2", + .group = MACH_GROUP_SGI, + .type = MACH_SGI_IP32, + .flags = PROM_FLAG_ARCS, + }, { + .arcname = "Microsoft-Jazz", + .liname = "Jazz MIPS_Magnum_4000", + .group = MACH_GROUP_JAZZ, + .type = MACH_MIPS_MAGNUM_4000, + .flags = 0, + }, { + .arcname = "PICA-61", + .liname = "Jazz Acer_PICA_61", + .group = MACH_GROUP_JAZZ, + .type = MACH_ACER_PICA_61, + .flags = 0, + }, { + .arcname = "RM200PCI", + .liname = "SNI RM200_PCI", + .group = MACH_GROUP_SNI_RM, + .type = MACH_SNI_RM200_PCI, + .flags = PROM_FLAG_DONT_FREE_TEMP, } }; From 05dc8c02bf40090e9ed23932b1980ead48eb8870 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:08 +0100 Subject: [PATCH 2238/2804] [MIPS] ARC: Get rid of mips_machgroup This has not been any serious user of this ill conceived thing since the original invention in like '95. Signed-off-by: Ralf Baechle --- arch/mips/au1000/db1x00/init.c | 2 -- arch/mips/au1000/mtx-1/init.c | 1 - arch/mips/au1000/pb1000/init.c | 1 - arch/mips/au1000/pb1100/init.c | 1 - arch/mips/au1000/pb1200/init.c | 1 - arch/mips/au1000/pb1500/init.c | 1 - arch/mips/au1000/pb1550/init.c | 1 - arch/mips/au1000/xxs1500/init.c | 1 - arch/mips/basler/excite/excite_prom.c | 1 - arch/mips/cobalt/setup.c | 2 -- arch/mips/dec/prom/identify.c | 3 -- arch/mips/emma2rh/common/prom.c | 2 -- arch/mips/fw/arc/identify.c | 10 ------- arch/mips/gt64120/wrppmc/setup.c | 1 - arch/mips/jmr3927/rbhma3100/init.c | 1 - arch/mips/kernel/setup.c | 2 -- arch/mips/lasat/prom.c | 2 -- arch/mips/lemote/lm2e/prom.c | 1 - arch/mips/philips/pnx8550/jbs/init.c | 1 - arch/mips/philips/pnx8550/stb810/prom_init.c | 1 - arch/mips/pmc-sierra/msp71xx/msp_setup.c | 15 +--------- arch/mips/pmc-sierra/yosemite/prom.c | 1 - arch/mips/sibyte/cfe/setup.c | 1 - arch/mips/sibyte/sb1250/prom.c | 1 - .../toshiba_rbtx4927/toshiba_rbtx4927_prom.c | 2 -- arch/mips/tx4938/toshiba_rbtx4938/prom.c | 1 - arch/mips/vr41xx/nec-cmbvr4133/setup.c | 1 - include/asm-mips/bootinfo.h | 30 ++----------------- 28 files changed, 4 insertions(+), 84 deletions(-) diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c index 0a3f025eb023..e6bdd07cc093 100644 --- a/arch/mips/au1000/db1x00/init.c +++ b/arch/mips/au1000/db1x00/init.c @@ -59,8 +59,6 @@ void __init prom_init(void) prom_argv = (char **) fw_arg1; prom_envp = (char **) fw_arg2; - mips_machgroup = MACH_GROUP_ALCHEMY; - /* Set the platform # */ #if defined (CONFIG_MIPS_DB1550) mips_machtype = MACH_DB1550; diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/au1000/mtx-1/init.c index 88f2b6d97281..2aa7b2ed6a8c 100644 --- a/arch/mips/au1000/mtx-1/init.c +++ b/arch/mips/au1000/mtx-1/init.c @@ -56,7 +56,6 @@ void __init prom_init(void) prom_argv = (char **) fw_arg1; prom_envp = (char **) fw_arg2; - mips_machgroup = MACH_GROUP_ALCHEMY; mips_machtype = MACH_MTX1; /* set the platform # */ prom_init_cmdline(); diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/au1000/pb1000/init.c index e9fa1bab81f3..4535f7208e18 100644 --- a/arch/mips/au1000/pb1000/init.c +++ b/arch/mips/au1000/pb1000/init.c @@ -54,7 +54,6 @@ void __init prom_init(void) prom_argv = (char **) fw_arg1; prom_envp = (char **) fw_arg2; - mips_machgroup = MACH_GROUP_ALCHEMY; mips_machtype = MACH_PB1000; prom_init_cmdline(); diff --git a/arch/mips/au1000/pb1100/init.c b/arch/mips/au1000/pb1100/init.c index 6131b56f41b5..7ba6852de7cd 100644 --- a/arch/mips/au1000/pb1100/init.c +++ b/arch/mips/au1000/pb1100/init.c @@ -55,7 +55,6 @@ void __init prom_init(void) prom_argv = (char **) fw_arg1; prom_envp = (char **) fw_arg3; - mips_machgroup = MACH_GROUP_ALCHEMY; mips_machtype = MACH_PB1100; prom_init_cmdline(); diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/au1000/pb1200/init.c index 27f09e374e15..5a70029d5388 100644 --- a/arch/mips/au1000/pb1200/init.c +++ b/arch/mips/au1000/pb1200/init.c @@ -55,7 +55,6 @@ void __init prom_init(void) prom_argv = (char **) fw_arg1; prom_envp = (char **) fw_arg2; - mips_machgroup = MACH_GROUP_ALCHEMY; mips_machtype = MACH_PB1200; prom_init_cmdline(); diff --git a/arch/mips/au1000/pb1500/init.c b/arch/mips/au1000/pb1500/init.c index 733d2e469db2..e58a9d6c5021 100644 --- a/arch/mips/au1000/pb1500/init.c +++ b/arch/mips/au1000/pb1500/init.c @@ -55,7 +55,6 @@ void __init prom_init(void) prom_argv = (char **) fw_arg1; prom_envp = (char **) fw_arg2; - mips_machgroup = MACH_GROUP_ALCHEMY; mips_machtype = MACH_PB1500; prom_init_cmdline(); diff --git a/arch/mips/au1000/pb1550/init.c b/arch/mips/au1000/pb1550/init.c index 41daa3371be3..fad53bf5aad1 100644 --- a/arch/mips/au1000/pb1550/init.c +++ b/arch/mips/au1000/pb1550/init.c @@ -55,7 +55,6 @@ void __init prom_init(void) prom_argv = (char **) fw_arg1; prom_envp = (char **) fw_arg2; - mips_machgroup = MACH_GROUP_ALCHEMY; mips_machtype = MACH_PB1550; prom_init_cmdline(); diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/au1000/xxs1500/init.c index f1c76533b6fc..9f839c36f69e 100644 --- a/arch/mips/au1000/xxs1500/init.c +++ b/arch/mips/au1000/xxs1500/init.c @@ -54,7 +54,6 @@ void __init prom_init(void) prom_argv = (char **) fw_arg1; prom_envp = (char **) fw_arg2; - mips_machgroup = MACH_GROUP_ALCHEMY; mips_machtype = MACH_XXS1500; /* set the platform # */ prom_init_cmdline(); diff --git a/arch/mips/basler/excite/excite_prom.c b/arch/mips/basler/excite/excite_prom.c index 6ecd512b999d..2d752c2f6e59 100644 --- a/arch/mips/basler/excite/excite_prom.c +++ b/arch/mips/basler/excite/excite_prom.c @@ -136,7 +136,6 @@ void __init prom_init(void) # error 64 bit support not implemented #endif /* CONFIG_64BIT */ - mips_machgroup = MACH_GROUP_TITAN; mips_machtype = MACH_TITAN_EXCITE; } diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index fc9cbb251edc..5d2e8790b28b 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -114,8 +114,6 @@ void __init prom_init(void) unsigned long memsz; char **argv; - mips_machgroup = MACH_GROUP_COBALT; - memsz = fw_arg0 & 0x7fff0000; narg = fw_arg0 & 0x0000ffff; diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c index cd85924e2572..95e26f4bb38f 100644 --- a/arch/mips/dec/prom/identify.c +++ b/arch/mips/dec/prom/identify.c @@ -133,9 +133,6 @@ void __init prom_identify_arch(u32 magic) dec_firmrev = (dec_sysid & 0xff00) >> 8; dec_etc = dec_sysid & 0xff; - /* We're obviously one of the DEC machines */ - mips_machgroup = MACH_GROUP_DEC; - /* * FIXME: This may not be an exhaustive list of DECStations/Servers! * Put all model-specific initialisation calls here. diff --git a/arch/mips/emma2rh/common/prom.c b/arch/mips/emma2rh/common/prom.c index 7433bd8e5562..0f791eb6bb66 100644 --- a/arch/mips/emma2rh/common/prom.c +++ b/arch/mips/emma2rh/common/prom.c @@ -62,8 +62,6 @@ void __init prom_init(void) strcat(arcs_cmdline, " "); } - mips_machgroup = MACH_GROUP_NEC_EMMA2RH; - #if defined(CONFIG_MARKEINS) mips_machtype = MACH_NEC_MARKEINS; add_memory_region(0, EMMA2RH_RAM_SIZE, BOOT_MEM_RAM); diff --git a/arch/mips/fw/arc/identify.c b/arch/mips/fw/arc/identify.c index 5d28dbe06f40..28dfd2e2989a 100644 --- a/arch/mips/fw/arc/identify.c +++ b/arch/mips/fw/arc/identify.c @@ -22,7 +22,6 @@ struct smatch { char *arcname; char *liname; - int group; int type; int flags; }; @@ -31,49 +30,41 @@ static struct smatch mach_table[] = { { .arcname = "SGI-IP22", .liname = "SGI Indy", - .group = MACH_GROUP_SGI, .type = MACH_SGI_IP22, .flags = PROM_FLAG_ARCS, }, { .arcname = "SGI-IP27", .liname = "SGI Origin", - .group = MACH_GROUP_SGI, .type = MACH_SGI_IP27, .flags = PROM_FLAG_ARCS, }, { .arcname = "SGI-IP28", .liname = "SGI IP28", - .group = MACH_GROUP_SGI, .type = MACH_SGI_IP28, .flags = PROM_FLAG_ARCS, }, { .arcname = "SGI-IP30", .liname = "SGI Octane", - .group = MACH_GROUP_SGI, .type = MACH_SGI_IP30, .flags = PROM_FLAG_ARCS, }, { .arcname = "SGI-IP32", .liname = "SGI O2", - .group = MACH_GROUP_SGI, .type = MACH_SGI_IP32, .flags = PROM_FLAG_ARCS, }, { .arcname = "Microsoft-Jazz", .liname = "Jazz MIPS_Magnum_4000", - .group = MACH_GROUP_JAZZ, .type = MACH_MIPS_MAGNUM_4000, .flags = 0, }, { .arcname = "PICA-61", .liname = "Jazz Acer_PICA_61", - .group = MACH_GROUP_JAZZ, .type = MACH_ACER_PICA_61, .flags = 0, }, { .arcname = "RM200PCI", .liname = "SNI RM200_PCI", - .group = MACH_GROUP_SNI_RM, .type = MACH_SNI_RM200_PCI, .flags = PROM_FLAG_DONT_FREE_TEMP, } @@ -125,7 +116,6 @@ void __init prom_identify_arch(void) mach = string_to_mach(iname); system_type = mach->liname; - mips_machgroup = mach->group; mips_machtype = mach->type; prom_flags = mach->flags; } diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c index ed58c13b6032..238b5087fbb3 100644 --- a/arch/mips/gt64120/wrppmc/setup.c +++ b/arch/mips/gt64120/wrppmc/setup.c @@ -159,7 +159,6 @@ const char *get_system_type(void) */ void __init prom_init(void) { - mips_machgroup = MACH_GROUP_WINDRIVER; mips_machtype = MACH_WRPPMC; add_memory_region(WRPPMC_SDRAM_SCS0_BASE, WRPPMC_SDRAM_SCS0_SIZE, BOOT_MEM_RAM); diff --git a/arch/mips/jmr3927/rbhma3100/init.c b/arch/mips/jmr3927/rbhma3100/init.c index 9169fab1773a..b643f75ec9a5 100644 --- a/arch/mips/jmr3927/rbhma3100/init.c +++ b/arch/mips/jmr3927/rbhma3100/init.c @@ -51,7 +51,6 @@ void __init prom_init(void) if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0) puts("Warning: TX3927 TLB off\n"); #endif - mips_machgroup = MACH_GROUP_TOSHIBA; #ifdef CONFIG_TOSHIBA_JMR3927 mips_machtype = MACH_TOSHIBA_JMR3927; diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 316685fca059..a06a27d6cfcd 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -51,10 +51,8 @@ EXPORT_SYMBOL(PCI_DMA_BUS_IS_PHYS); * These are initialized so they are in the .data section */ unsigned long mips_machtype __read_mostly = MACH_UNKNOWN; -unsigned long mips_machgroup __read_mostly = MACH_GROUP_UNKNOWN; EXPORT_SYMBOL(mips_machtype); -EXPORT_SYMBOL(mips_machgroup); struct boot_mem_map boot_mem_map; diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c index 4b80fffcf262..209edcc26f07 100644 --- a/arch/mips/lasat/prom.c +++ b/arch/mips/lasat/prom.c @@ -100,8 +100,6 @@ void __init prom_init(void) lasat_init_board_info(); /* Read info from EEPROM */ - mips_machgroup = MACH_GROUP_LASAT; - /* Get the command line */ if (argc > 0) { strncpy(arcs_cmdline, argv[0], CL_SIZE-1); diff --git a/arch/mips/lemote/lm2e/prom.c b/arch/mips/lemote/lm2e/prom.c index 3efb1cf111f2..824336812198 100644 --- a/arch/mips/lemote/lm2e/prom.c +++ b/arch/mips/lemote/lm2e/prom.c @@ -57,7 +57,6 @@ void __init prom_init(void) arg = (int *)fw_arg1; env = (int *)fw_arg2; - mips_machgroup = MACH_GROUP_LEMOTE; mips_machtype = MACH_LEMOTE_FULONG; prom_init_cmdline(); diff --git a/arch/mips/philips/pnx8550/jbs/init.c b/arch/mips/philips/pnx8550/jbs/init.c index 85f449174bc3..cfd90fa3d799 100644 --- a/arch/mips/philips/pnx8550/jbs/init.c +++ b/arch/mips/philips/pnx8550/jbs/init.c @@ -48,7 +48,6 @@ void __init prom_init(void) unsigned long memsize; - mips_machgroup = MACH_GROUP_PHILIPS; mips_machtype = MACH_PHILIPS_JBS; //memsize = 0x02800000; /* Trimedia uses memory above */ diff --git a/arch/mips/philips/pnx8550/stb810/prom_init.c b/arch/mips/philips/pnx8550/stb810/prom_init.c index ea5b4e0fb47d..fdb33ed089b9 100644 --- a/arch/mips/philips/pnx8550/stb810/prom_init.c +++ b/arch/mips/philips/pnx8550/stb810/prom_init.c @@ -41,7 +41,6 @@ void __init prom_init(void) prom_init_cmdline(); - mips_machgroup = MACH_GROUP_PHILIPS; mips_machtype = MACH_PHILIPS_STB810; memsize = 0x08000000; /* Trimedia uses memory above */ diff --git a/arch/mips/pmc-sierra/msp71xx/msp_setup.c b/arch/mips/pmc-sierra/msp71xx/msp_setup.c index 8f69b789be90..e4cc54824475 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_setup.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_setup.c @@ -176,16 +176,13 @@ void __init prom_init(void) case FAMILY_FPGA: if (FPGA_IS_MSP4200(revision)) { /* Old-style revision ID */ - mips_machgroup = MACH_GROUP_MSP; mips_machtype = MACH_MSP4200_FPGA; } else { - mips_machgroup = MACH_GROUP_MSP; mips_machtype = MACH_MSP_OTHER; } break; case FAMILY_MSP4200: - mips_machgroup = MACH_GROUP_MSP; #if defined(CONFIG_PMC_MSP4200_EVAL) mips_machtype = MACH_MSP4200_EVAL; #elif defined(CONFIG_PMC_MSP4200_GW) @@ -196,12 +193,10 @@ void __init prom_init(void) break; case FAMILY_MSP4200_FPGA: - mips_machgroup = MACH_GROUP_MSP; mips_machtype = MACH_MSP4200_FPGA; break; case FAMILY_MSP7100: - mips_machgroup = MACH_GROUP_MSP; #if defined(CONFIG_PMC_MSP7120_EVAL) mips_machtype = MACH_MSP7120_EVAL; #elif defined(CONFIG_PMC_MSP7120_GW) @@ -212,22 +207,14 @@ void __init prom_init(void) break; case FAMILY_MSP7100_FPGA: - mips_machgroup = MACH_GROUP_MSP; mips_machtype = MACH_MSP7120_FPGA; break; default: /* we don't recognize the machine */ - mips_machgroup = MACH_GROUP_UNKNOWN; mips_machtype = MACH_UNKNOWN; - break; - } - - /* make sure we have the right initialization routine - sanity */ - if (mips_machgroup != MACH_GROUP_MSP) { - ppfinit("Unknown machine group in a " - "MSP initialization routine\n"); panic("***Bogosity factor five***, exiting\n"); + break; } prom_init_cmdline(); diff --git a/arch/mips/pmc-sierra/yosemite/prom.c b/arch/mips/pmc-sierra/yosemite/prom.c index 0cd78f0f5f2d..9b9936de6589 100644 --- a/arch/mips/pmc-sierra/yosemite/prom.c +++ b/arch/mips/pmc-sierra/yosemite/prom.c @@ -126,7 +126,6 @@ void __init prom_init(void) env++; } - mips_machgroup = MACH_GROUP_TITAN; mips_machtype = MACH_TITAN_YOSEMITE; prom_grab_secondary(); diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c index d842b98efb67..147b7fb02e64 100644 --- a/arch/mips/sibyte/cfe/setup.c +++ b/arch/mips/sibyte/cfe/setup.c @@ -339,7 +339,6 @@ void __init prom_init(void) /* Not sure this is needed, but it's the safe way. */ arcs_cmdline[CL_SIZE-1] = 0; - mips_machgroup = MACH_GROUP_SIBYTE; prom_meminit(); } diff --git a/arch/mips/sibyte/sb1250/prom.c b/arch/mips/sibyte/sb1250/prom.c index 257c4e674353..f07ad3baccab 100644 --- a/arch/mips/sibyte/sb1250/prom.c +++ b/arch/mips/sibyte/sb1250/prom.c @@ -83,7 +83,6 @@ void __init prom_init(void) strcpy(arcs_cmdline, "root=/dev/ram0 "); - mips_machgroup = MACH_GROUP_SIBYTE; prom_meminit(); } diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c index 9a3a5babd1fb..f3f86857beae 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c @@ -66,8 +66,6 @@ void __init prom_init(void) prom_init_cmdline(); - mips_machgroup = MACH_GROUP_TOSHIBA; - if ((read_c0_prid() & 0xff) == PRID_REV_TX4927) { mips_machtype = MACH_TOSHIBA_RBTX4927; toshiba_name = "TX4927"; diff --git a/arch/mips/tx4938/toshiba_rbtx4938/prom.c b/arch/mips/tx4938/toshiba_rbtx4938/prom.c index 7dc6a0aae21c..69f21c1b7942 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/prom.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/prom.c @@ -47,7 +47,6 @@ void __init prom_init(void) #ifndef CONFIG_TX4938_NAND_BOOT prom_init_cmdline(); #endif - mips_machgroup = MACH_GROUP_TOSHIBA; mips_machtype = MACH_TOSHIBA_RBTX4938; msize = tx4938_get_mem_size(); diff --git a/arch/mips/vr41xx/nec-cmbvr4133/setup.c b/arch/mips/vr41xx/nec-cmbvr4133/setup.c index b20b93b2b95e..58e47686b499 100644 --- a/arch/mips/vr41xx/nec-cmbvr4133/setup.c +++ b/arch/mips/vr41xx/nec-cmbvr4133/setup.c @@ -64,7 +64,6 @@ static void __init nec_cmbvr4133_setup(void) #endif set_io_port_base(KSEG1ADDR(0x16000000)); - mips_machgroup = MACH_GROUP_NEC_VR41XX; mips_machtype = MACH_NEC_CMBVR4133; #ifdef CONFIG_PCI diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index efa8158f61eb..b2dd9b33de8f 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -15,21 +15,19 @@ #include /* - * The MACH_GROUP_ IDs are the equivalent to PCI vendor IDs; the remaining - * MACH_ values equivalent to product IDs. As such the numbers do not - * necessarily reflect technical relations or similarities between systems. + * The MACH_ IDs are sort of equivalent to PCI product IDs. As such the + * numbers do not necessarily reflect technical relations or similarities + * between systems. */ /* * Valid machtype values for group unknown */ -#define MACH_GROUP_UNKNOWN 0 /* whatever... */ #define MACH_UNKNOWN 0 /* whatever... */ /* * Valid machtype values for group JAZZ */ -#define MACH_GROUP_JAZZ 1 /* Jazz */ #define MACH_ACER_PICA_61 0 /* Acer PICA-61 (PICA1) */ #define MACH_MIPS_MAGNUM_4000 1 /* Mips Magnum 4000 "RC4030" */ #define MACH_OLIVETTI_M700 2 /* Olivetti M700-10 (-15 ??) */ @@ -37,7 +35,6 @@ /* * Valid machtype for group DEC */ -#define MACH_GROUP_DEC 2 /* Digital Equipment */ #define MACH_DSUNKNOWN 0 #define MACH_DS23100 1 /* DECstation 2100 or 3100 */ #define MACH_DS5100 2 /* DECsystem 5100 */ @@ -53,26 +50,22 @@ /* * Valid machtype for group ARC */ -#define MACH_GROUP_ARC 3 /* Deskstation */ #define MACH_DESKSTATION_RPC44 0 /* Deskstation rPC44 */ #define MACH_DESKSTATION_TYNE 1 /* Deskstation Tyne */ /* * Valid machtype for group SNI_RM */ -#define MACH_GROUP_SNI_RM 4 /* Siemens Nixdorf RM series */ #define MACH_SNI_RM200_PCI 0 /* RM200/RM300/RM400 PCI series */ /* * Valid machtype for group ACN */ -#define MACH_GROUP_ACN 5 #define MACH_ACN_MIPS_BOARD 0 /* ACN MIPS single board */ /* * Valid machtype for group SGI */ -#define MACH_GROUP_SGI 6 /* Silicon Graphics */ #define MACH_SGI_IP22 0 /* Indy, Indigo2, Challenge S */ #define MACH_SGI_IP27 1 /* Origin 200, Origin 2000, Onyx 2 */ #define MACH_SGI_IP28 2 /* Indigo2 Impact */ @@ -82,26 +75,22 @@ /* * Valid machtype for group COBALT */ -#define MACH_GROUP_COBALT 7 /* Cobalt servers */ #define MACH_COBALT_27 0 /* Proto "27" hardware */ /* * Valid machtype for group BAGET */ -#define MACH_GROUP_BAGET 9 /* Baget */ #define MACH_BAGET201 0 /* BT23-201 */ #define MACH_BAGET202 1 /* BT23-202 */ /* * Cosine boards. */ -#define MACH_GROUP_COSINE 10 /* CoSine Orion */ #define MACH_COSINE_ORION 0 /* * Valid machtype for group MOMENCO */ -#define MACH_GROUP_MOMENCO 12 /* Momentum Boards */ #define MACH_MOMENCO_OCELOT 0 #define MACH_MOMENCO_OCELOT_G 1 /* no more supported (may 2007) */ #define MACH_MOMENCO_OCELOT_C 2 /* no more supported (jun 2007) */ @@ -111,7 +100,6 @@ /* * Valid machtype for group PHILIPS */ -#define MACH_GROUP_PHILIPS 14 #define MACH_PHILIPS_NINO 0 /* Nino */ #define MACH_PHILIPS_VELO 1 /* Velo */ #define MACH_PHILIPS_JBS 2 /* JBS */ @@ -120,13 +108,11 @@ /* * Valid machtype for group SIBYTE */ -#define MACH_GROUP_SIBYTE 16 /* Sibyte / Broadcom */ #define MACH_SWARM 0 /* * Valid machtypes for group Toshiba */ -#define MACH_GROUP_TOSHIBA 17 /* Toshiba Reference Systems TSBREF */ #define MACH_PALLAS 0 #define MACH_TOPAS 1 #define MACH_JMR 2 @@ -138,7 +124,6 @@ /* * Valid machtype for group Alchemy */ -#define MACH_GROUP_ALCHEMY 18 /* AMD Alchemy */ #define MACH_PB1000 0 /* Au1000-based eval board */ #define MACH_PB1100 1 /* Au1100-based eval board */ #define MACH_PB1500 2 /* Au1500-based eval board */ @@ -160,7 +145,6 @@ * FIXME: MACH_GROUPs should be by _MANUFACTURER_ of * the device, not by * technical properties, so no new additions to this group. */ -#define MACH_GROUP_NEC_VR41XX 19 #define MACH_NEC_OSPREY 0 /* Osprey eval board */ #define MACH_NEC_EAGLE 1 /* NEC Eagle/Hawk board */ #define MACH_ZAO_CAPCELLA 2 /* ZAO Networks Capcella */ @@ -171,39 +155,33 @@ #define MACH_TANBAC_TB0229 7 /* TANBAC TB0229 (VR4131DIMM) */ #define MACH_NEC_CMBVR4133 8 /* CMB VR4133 Board */ -#define MACH_GROUP_HP_LJ 20 /* Hewlett Packard LaserJet */ #define MACH_HP_LASERJET 1 /* * Valid machtype for group LASAT */ -#define MACH_GROUP_LASAT 21 #define MACH_LASAT_100 0 /* Masquerade II/SP100/SP50/SP25 */ #define MACH_LASAT_200 1 /* Masquerade PRO/SP200 */ /* * Valid machtype for group TITAN */ -#define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */ #define MACH_TITAN_EXCITE 2 /* Basler eXcite */ /* * Valid machtype for group NEC EMMA2RH */ -#define MACH_GROUP_NEC_EMMA2RH 25 /* NEC EMMA2RH (was 23) */ #define MACH_NEC_MARKEINS 0 /* NEC EMMA2RH Mark-eins */ /* * Valid machtype for group LEMOTE */ -#define MACH_GROUP_LEMOTE 27 #define MACH_LEMOTE_FULONG 0 /* * Valid machtype for group PMC-MSP */ -#define MACH_GROUP_MSP 26 /* PMC-Sierra MSP boards/CPUs */ #define MACH_MSP4200_EVAL 0 /* PMC-Sierra MSP4200 Evaluation */ #define MACH_MSP4200_GW 1 /* PMC-Sierra MSP4200 Gateway demo */ #define MACH_MSP4200_FPGA 2 /* PMC-Sierra MSP4200 Emulation */ @@ -212,7 +190,6 @@ #define MACH_MSP7120_FPGA 5 /* PMC-Sierra MSP7120 Emulation */ #define MACH_MSP_OTHER 255 /* PMC-Sierra unknown board type */ -#define MACH_GROUP_WINDRIVER 28 /* Windriver boards */ #define MACH_WRPPMC 1 /* @@ -226,7 +203,6 @@ const char *get_system_type(void); extern unsigned long mips_machtype; -extern unsigned long mips_machgroup; #define BOOT_MEM_MAP_MAX 32 #define BOOT_MEM_RAM 1 From 4680576edecb640f64936bd9b92add0a56027b61 Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Thu, 27 Sep 2007 01:35:43 +0300 Subject: [PATCH 2239/2804] [MIPS] Replace deprecated SA_* IRQ flags with modern IRQF_ variants. Signed-off-by: Ahmed S. Darwish Signed-off-by: Ralf Baechle --- arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c index 6fa85728158b..ab96a2d7f4c4 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c @@ -163,7 +163,7 @@ static int msp_hwbutton_register(struct hwbutton_interrupt *hirq) CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq); *CIC_EXT_CFG_REG = cic_ext; - return request_irq(hirq->irq, hwbutton_handler, SA_INTERRUPT, + return request_irq(hirq->irq, hwbutton_handler, IRQF_DISABLED, hirq->name, (void *)hirq); } From f5ff0a280201c9cbfb6e9eb4bafdb465c2269ed3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 13 Aug 2007 15:26:12 +0100 Subject: [PATCH 2240/2804] [MIPS] Use generic NTP code for all MIPS platforms Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 ++++ arch/mips/kernel/time.c | 24 ++++-------------------- arch/mips/sgi-ip27/ip27-timer.c | 18 ------------------ 3 files changed, 8 insertions(+), 38 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 371434dd744c..c024113ce280 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -670,6 +670,10 @@ config GENERIC_TIME bool default y +config GENERIC_CMOS_UPDATE + bool + default y + config SCHED_NO_NO_OMIT_FRAME_POINTER bool default y diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 9a5596bf8571..628a8ba6da57 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -67,6 +67,10 @@ unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time; int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time; int (*rtc_mips_set_mmss)(unsigned long); +int update_persistent_clock(struct timespec now) +{ + return rtc_mips_set_mmss(now.tv_sec); +} /* how many counter cycles in a jiffy */ static unsigned long cycles_per_jiffy __read_mostly; @@ -125,9 +129,6 @@ static void __init c0_hpt_timer_init(void) int (*mips_timer_state)(void); void (*mips_timer_ack)(void); -/* last time when xtime and rtc are sync'ed up */ -static long last_rtc_update; - /* * local_timer_interrupt() does profiling and process accounting * on a per-CPU basis. @@ -159,23 +160,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) */ do_timer(1); - /* - * If we have an externally synchronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. rtc_mips_set_time() has to be - * called as close as possible to 500 ms before the new second starts. - */ - if (ntp_synced() && - xtime.tv_sec > last_rtc_update + 660 && - (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && - (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { - if (rtc_mips_set_mmss(xtime.tv_sec) == 0) { - last_rtc_update = xtime.tv_sec; - } else { - /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec - 600; - } - } - write_sequnlock(&xtime_lock); /* diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 8c3c78c63ccd..31346162e9fa 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -40,7 +40,6 @@ #define TICK_SIZE (tick_nsec / 1000) static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */ -static long last_rtc_update; /* Last time the rtc clock got updated */ #if 0 static int set_rtc_mmss(unsigned long nowtime) @@ -113,23 +112,6 @@ again: update_process_times(user_mode(get_irq_regs())); - /* - * If we have an externally synchronized Linux clock, then update - * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to when a second starts. - */ - if (ntp_synced() && - xtime.tv_sec > last_rtc_update + 660 && - (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && - (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { - if (rtc_mips_set_time(xtime.tv_sec) == 0) { - last_rtc_update = xtime.tv_sec; - } else { - last_rtc_update = xtime.tv_sec - 600; - /* do it again in 60 s */ - } - } - write_sequnlock(&xtime_lock); irq_exit(); } From 4b550488f894c899aa54dc935c8fee47bca2b7df Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:08 +0100 Subject: [PATCH 2241/2804] [MIPS] Deforest the function pointer jungle in the time code. Hard to follow who is pointing what to where and why so it's simply getting in the way of the time code renovation. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/setup.c | 2 - arch/mips/au1000/common/time.c | 4 -- arch/mips/basler/excite/excite_setup.c | 5 +- arch/mips/bcm47xx/setup.c | 1 - arch/mips/bcm47xx/time.c | 3 +- arch/mips/dec/setup.c | 4 -- arch/mips/dec/time.c | 12 ++--- arch/mips/emma2rh/markeins/setup.c | 4 +- arch/mips/gt64120/wrppmc/setup.c | 4 -- arch/mips/gt64120/wrppmc/time.c | 2 +- arch/mips/jmr3927/rbhma3100/setup.c | 4 +- arch/mips/kernel/time.c | 47 ++++++------------- arch/mips/lasat/ds1603.c | 6 +-- arch/mips/lasat/ds1603.h | 2 - arch/mips/lasat/setup.c | 6 +-- arch/mips/lasat/sysctl.c | 10 ++-- arch/mips/lemote/lm2e/setup.c | 7 +-- arch/mips/mips-boards/atlas/atlas_setup.c | 5 -- arch/mips/mips-boards/generic/time.c | 4 +- arch/mips/mips-boards/malta/malta_setup.c | 4 -- arch/mips/mips-boards/sead/sead_setup.c | 3 -- arch/mips/mipssim/sim_setup.c | 2 - arch/mips/mipssim/sim_time.c | 2 +- arch/mips/philips/pnx8550/common/setup.c | 3 -- arch/mips/philips/pnx8550/common/time.c | 7 +-- arch/mips/pmc-sierra/msp71xx/msp_setup.c | 3 -- arch/mips/pmc-sierra/msp71xx/msp_time.c | 3 +- arch/mips/pmc-sierra/yosemite/setup.c | 18 ++------ arch/mips/sgi-ip22/ip22-setup.c | 2 - arch/mips/sgi-ip22/ip22-time.c | 15 ++---- arch/mips/sgi-ip27/ip27-init.c | 3 -- arch/mips/sgi-ip27/ip27-timer.c | 6 +-- arch/mips/sgi-ip32/ip32-setup.c | 12 ++--- arch/mips/sibyte/swarm/setup.c | 56 +++++++++++++++++------ arch/mips/sni/pcimt.c | 1 - arch/mips/sni/pcit.c | 1 - arch/mips/sni/rm200.c | 1 - arch/mips/sni/time.c | 8 +++- arch/mips/tx4927/common/tx4927_setup.c | 9 +--- arch/mips/tx4938/common/setup.c | 9 ---- arch/mips/tx4938/toshiba_rbtx4938/setup.c | 3 +- arch/mips/vr41xx/common/init.c | 8 +--- include/asm-mips/mach-bcm47xx/bcm47xx.h | 2 - include/asm-mips/time.h | 12 ++--- 44 files changed, 115 insertions(+), 210 deletions(-) diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c index a95b37773196..b212c0726125 100644 --- a/arch/mips/au1000/common/setup.c +++ b/arch/mips/au1000/common/setup.c @@ -50,7 +50,6 @@ extern void au1000_halt(void); extern void au1000_power_off(void); extern void au1x_time_init(void); extern void au1x_timer_setup(struct irqaction *irq); -extern void au1xxx_time_init(void); extern void set_cpuspec(void); void __init plat_mem_setup(void) @@ -112,7 +111,6 @@ void __init plat_mem_setup(void) _machine_restart = au1000_restart; _machine_halt = au1000_halt; pm_power_off = au1000_power_off; - board_time_init = au1xxx_time_init; /* IO/MEM resources. */ set_io_port_base(0); diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 8fc29982d700..fb1fd50f19a6 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -329,7 +329,3 @@ void __init plat_timer_setup(struct irqaction *irq) #endif } - -void __init au1xxx_time_init(void) -{ -} diff --git a/arch/mips/basler/excite/excite_setup.c b/arch/mips/basler/excite/excite_setup.c index 56003188f17c..68be19d1802e 100644 --- a/arch/mips/basler/excite/excite_setup.c +++ b/arch/mips/basler/excite/excite_setup.c @@ -68,7 +68,7 @@ DEFINE_SPINLOCK(titan_lock); int titan_irqflags; -static void excite_timer_init(void) +void __init plat_time_init(void) { const u32 modebit5 = ocd_readl(0x00e4); unsigned int @@ -261,9 +261,6 @@ void __init plat_mem_setup(void) /* Announce RAM to system */ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); - /* Set up timer initialization hooks */ - board_time_init = excite_timer_init; - /* Set up the peripheral address map */ *(boot_ocd_base + (LKB9 / sizeof (u32))) = 0; *(boot_ocd_base + (LKB10 / sizeof (u32))) = 0; diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index f48aa5aa9bf0..1b6b0fa5028f 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -119,6 +119,5 @@ void __init plat_mem_setup(void) _machine_restart = bcm47xx_machine_restart; _machine_halt = bcm47xx_machine_halt; pm_power_off = bcm47xx_machine_halt; - board_time_init = bcm47xx_time_init; } diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c index b27d07f29059..0ab4676c8bd3 100644 --- a/arch/mips/bcm47xx/time.c +++ b/arch/mips/bcm47xx/time.c @@ -28,8 +28,7 @@ #include #include -void __init -bcm47xx_time_init(void) +void __init plat_time_init(void) { unsigned long hz; diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index 3e634f2f5443..bd5431e1f408 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -145,13 +145,9 @@ static void __init dec_be_init(void) } } - -extern void dec_time_init(void); - void __init plat_mem_setup(void) { board_be_init = dec_be_init; - board_time_init = dec_time_init; wbflush_setup(); diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index e2973a432b92..820e5331205f 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c @@ -35,7 +35,7 @@ #include #include -static unsigned long dec_rtc_get_time(void) +unsigned long read_persistent_clock(void) { unsigned int year, mon, day, hour, min, sec, real_year; unsigned long flags; @@ -74,13 +74,13 @@ static unsigned long dec_rtc_get_time(void) } /* - * In order to set the CMOS clock precisely, dec_rtc_set_mmss has to + * In order to set the CMOS clock precisely, rtc_mips_set_mmss has to * be called 500 ms after the second nowtime has started, because when * nowtime is written into the registers of the CMOS clock, it will * jump to the next second precisely 500 ms later. Check the Dallas * DS1287 data sheet for details. */ -static int dec_rtc_set_mmss(unsigned long nowtime) +int rtc_mips_set_mmss(unsigned long nowtime) { int retval = 0; int real_seconds, real_minutes, cmos_minutes; @@ -139,7 +139,6 @@ static int dec_rtc_set_mmss(unsigned long nowtime) return retval; } - static int dec_timer_state(void) { return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0; @@ -160,11 +159,8 @@ static cycle_t dec_ioasic_hpt_read(void) } -void __init dec_time_init(void) +void __init plat_time_init(void) { - rtc_mips_get_time = dec_rtc_get_time; - rtc_mips_set_mmss = dec_rtc_set_mmss; - mips_timer_state = dec_timer_state; mips_timer_ack = dec_timer_ack; diff --git a/arch/mips/emma2rh/markeins/setup.c b/arch/mips/emma2rh/markeins/setup.c index 2f060e1ed36c..5e1da53b04a7 100644 --- a/arch/mips/emma2rh/markeins/setup.c +++ b/arch/mips/emma2rh/markeins/setup.c @@ -88,7 +88,7 @@ static unsigned int __init detect_bus_frequency(unsigned long rtc_base) return clock[reg]; } -static void __init emma2rh_time_init(void) +void __init plat_time_init(void) { u32 reg; if (bus_frequency == 0) @@ -124,8 +124,6 @@ void __init plat_mem_setup(void) set_io_port_base(KSEG1ADDR(EMMA2RH_PCI_IO_BASE)); - board_time_init = emma2rh_time_init; - _machine_restart = markeins_machine_restart; _machine_halt = markeins_machine_halt; pm_power_off = markeins_machine_power_off; diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c index 238b5087fbb3..f2ccf101e6d9 100644 --- a/arch/mips/gt64120/wrppmc/setup.c +++ b/arch/mips/gt64120/wrppmc/setup.c @@ -126,7 +126,6 @@ static void wrppmc_setup_serial(void) void __init plat_mem_setup(void) { - extern void wrppmc_time_init(void); extern void wrppmc_machine_restart(char *command); extern void wrppmc_machine_halt(void); extern void wrppmc_machine_power_off(void); @@ -135,9 +134,6 @@ void __init plat_mem_setup(void) _machine_halt = wrppmc_machine_halt; pm_power_off = wrppmc_machine_power_off; - /* Use MIPS Count/Compare Timer */ - board_time_init = wrppmc_time_init; - /* This makes the operations of 'in/out[bwl]' to the * physical address ( < KSEG0) can work via KSEG1 */ diff --git a/arch/mips/gt64120/wrppmc/time.c b/arch/mips/gt64120/wrppmc/time.c index 5b440859bcee..faf164e7e0df 100644 --- a/arch/mips/gt64120/wrppmc/time.c +++ b/arch/mips/gt64120/wrppmc/time.c @@ -38,7 +38,7 @@ void __init plat_timer_setup(struct irqaction *irq) * NOTE: We disable all GT64120 timers, and use MIPS processor internal * timer as the source of kernel clock tick. */ -void __init wrppmc_time_init(void) +void __init plat_time_init(void) { /* Disable GT64120 timers */ GT_WRITE(GT_TC_CONTROL_OFS, 0x00); diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index fde56e86c2ab..7f14f70a1b88 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c @@ -109,7 +109,7 @@ static void jmr3927_timer_ack(void) jmr3927_tmrptr->tisr = 0; /* ack interrupt */ } -static void __init jmr3927_time_init(void) +void __init plat_time_init(void) { clocksource_mips.read = jmr3927_hpt_read; mips_timer_ack = jmr3927_timer_ack; @@ -141,8 +141,6 @@ void __init plat_mem_setup(void) set_io_port_base(JMR3927_PORT_BASE + JMR3927_PCIIO); - board_time_init = jmr3927_time_init; - _machine_restart = jmr3927_machine_restart; _machine_halt = jmr3927_machine_halt; pm_power_off = jmr3927_machine_power_off; diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 628a8ba6da57..9bbbd9b327fc 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -49,23 +49,18 @@ * forward reference */ DEFINE_SPINLOCK(rtc_lock); +EXPORT_SYMBOL(rtc_lock); -/* - * By default we provide the null RTC ops - */ -static unsigned long null_rtc_get_time(void) -{ - return mktime(2000, 1, 1, 0, 0, 0); -} - -static int null_rtc_set_time(unsigned long sec) +int __weak rtc_mips_set_time(unsigned long sec) { return 0; } +EXPORT_SYMBOL(rtc_mips_set_time); -unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time; -int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time; -int (*rtc_mips_set_mmss)(unsigned long); +int __weak rtc_mips_set_mmss(unsigned long nowtime) +{ + return rtc_mips_set_time(nowtime); +} int update_persistent_clock(struct timespec now) { @@ -247,21 +242,18 @@ asmlinkage void ll_local_timer_interrupt(int irq) /* * time_init() - it does the following things. * - * 1) board_time_init() - + * 1) plat_time_init() - * a) (optional) set up RTC routines, * b) (optional) calibrate and set the mips_hpt_frequency * (only needed if you intended to use cpu counter as timer interrupt * source) - * 2) setup xtime based on rtc_mips_get_time(). - * 3) calculate a couple of cached variables for later usage - * 4) plat_timer_setup() - + * 2) calculate a couple of cached variables for later usage + * 3) plat_timer_setup() - * a) (optional) over-write any choices made above by time_init(). * b) machine specific code should setup the timer irqaction. * c) enable the timer interrupt */ -void (*board_time_init)(void); - unsigned int mips_hpt_frequency; static struct irqaction timer_irqaction = { @@ -341,19 +333,13 @@ static void __init init_mips_clocksource(void) clocksource_register(&clocksource_mips); } +void __init __weak plat_time_init(void) +{ +} + void __init time_init(void) { - if (board_time_init) - board_time_init(); - - if (!rtc_mips_set_mmss) - rtc_mips_set_mmss = rtc_mips_set_time; - - xtime.tv_sec = rtc_mips_get_time(); - xtime.tv_nsec = 0; - - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); + plat_time_init(); /* Choose appropriate high precision timer routines. */ if (!cpu_has_counter && !clocksource_mips.read) @@ -459,7 +445,4 @@ void to_tm(unsigned long tim, struct rtc_time *tm) tm->tm_wday = (gday + 4) % 7; /* 1970/1/1 was Thursday */ } -EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL(to_tm); -EXPORT_SYMBOL(rtc_mips_set_time); -EXPORT_SYMBOL(rtc_mips_get_time); diff --git a/arch/mips/lasat/ds1603.c b/arch/mips/lasat/ds1603.c index 0b315f51d62c..52cb1436a12a 100644 --- a/arch/mips/lasat/ds1603.c +++ b/arch/mips/lasat/ds1603.c @@ -135,8 +135,7 @@ static void rtc_end_op(void) lasat_ndelay(1000); } -/* interface */ -unsigned long ds1603_read(void) +unsigned long read_persistent_clock(void) { unsigned long word; unsigned long flags; @@ -147,10 +146,11 @@ unsigned long ds1603_read(void) word = rtc_read_word(); rtc_end_op(); spin_unlock_irqrestore(&rtc_lock, flags); + return word; } -int ds1603_set(unsigned long time) +int rtc_mips_set_mmss(unsigned long time) { unsigned long flags; diff --git a/arch/mips/lasat/ds1603.h b/arch/mips/lasat/ds1603.h index c2e5c76a379d..2da3704044fd 100644 --- a/arch/mips/lasat/ds1603.h +++ b/arch/mips/lasat/ds1603.h @@ -20,8 +20,6 @@ struct ds_defs { extern struct ds_defs *ds1603; -unsigned long ds1603_read(void); -int ds1603_set(unsigned long); void ds1603_set_trimmer(unsigned int); void ds1603_enable(void); void ds1603_disable(void); diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c index 187e37821d93..54827d0174bf 100644 --- a/arch/mips/lasat/setup.c +++ b/arch/mips/lasat/setup.c @@ -117,7 +117,7 @@ static struct notifier_block lasat_panic_block[] = } }; -static void lasat_time_init(void) +void plat_time_init(void) { mips_hpt_frequency = lasat_board_info.li_cpu_hz / 2; } @@ -142,12 +142,8 @@ void __init plat_mem_setup(void) lasat_reboot_setup(); - board_time_init = lasat_time_init; - #ifdef CONFIG_DS1603 ds1603 = &ds_defs[mips_machtype]; - rtc_mips_get_time = ds1603_read; - rtc_mips_set_time = ds1603_set; #endif #ifdef DYNAMIC_SERIAL_INIT diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c index 4575a829766d..389336c4ecc5 100644 --- a/arch/mips/lasat/sysctl.c +++ b/arch/mips/lasat/sysctl.c @@ -32,6 +32,8 @@ #include #include +#include + #include "sysctl.h" #include "ds1603.h" @@ -106,7 +108,7 @@ int proc_dolasatrtc(ctl_table *table, int write, struct file *filp, mutex_lock(&lasat_info_mutex); if (!write) { - rtctmp = ds1603_read(); + rtctmp = read_persistent_clock(); /* check for time < 0 and set to 0 */ if (rtctmp < 0) rtctmp = 0; @@ -116,7 +118,7 @@ int proc_dolasatrtc(ctl_table *table, int write, struct file *filp, mutex_unlock(&lasat_info_mutex); return r; } - ds1603_set(rtctmp); + rtc_mips_set_mmss(rtctmp); mutex_unlock(&lasat_info_mutex); return 0; @@ -152,7 +154,7 @@ int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen, int r; mutex_lock(&lasat_info_mutex); - rtctmp = ds1603_read(); + rtctmp = read_persistent_clock(); if (rtctmp < 0) rtctmp = 0; r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); @@ -161,7 +163,7 @@ int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen, return r; } if (newval && newlen) - ds1603_set(rtctmp); + rtc_mips_set_mmss(rtctmp); mutex_unlock(&lasat_info_mutex); return 1; diff --git a/arch/mips/lemote/lm2e/setup.c b/arch/mips/lemote/lm2e/setup.c index f34350a4f271..09314a20f9fb 100644 --- a/arch/mips/lemote/lm2e/setup.c +++ b/arch/mips/lemote/lm2e/setup.c @@ -58,13 +58,13 @@ void __init plat_timer_setup(struct irqaction *irq) setup_irq(MIPS_CPU_IRQ_BASE + 7, irq); } -static void __init loongson2e_time_init(void) +void __init plat_time_init(void) { /* setup mips r4k timer */ mips_hpt_frequency = cpu_clock_freq / 2; } -static unsigned long __init mips_rtc_get_time(void) +unsigned long read_persistent_clock(void) { return mc146818_get_cmos_time(); } @@ -89,9 +89,6 @@ void __init plat_mem_setup(void) mips_reboot_setup(); - board_time_init = loongson2e_time_init; - rtc_mips_get_time = mips_rtc_get_time; - __wbflush = wbflush_loongson2e; add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c index c68358a476dd..86bfc0548164 100644 --- a/arch/mips/mips-boards/atlas/atlas_setup.c +++ b/arch/mips/mips-boards/atlas/atlas_setup.c @@ -35,8 +35,6 @@ #include extern void mips_reboot_setup(void); -extern void mips_time_init(void); -extern unsigned long mips_rtc_get_time(void); #ifdef CONFIG_KGDB extern void kgdb_config(void); @@ -63,9 +61,6 @@ void __init plat_mem_setup(void) kgdb_config(); #endif mips_reboot_setup(); - - board_time_init = mips_time_init; - rtc_mips_get_time = mips_rtc_get_time; } static void __init serial_init(void) diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index d7bff9ca5356..075f9d46f40e 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -224,12 +224,12 @@ static unsigned int __init estimate_cpu_frequency(void) return count; } -unsigned long __init mips_rtc_get_time(void) +unsigned long read_persistent_clock(void) { return mc146818_get_cmos_time(); } -void __init mips_time_init(void) +void __init plat_time_init(void) { unsigned int est_freq; diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index 8f1b78dfd89f..a5a5a43a1984 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c @@ -36,7 +36,6 @@ #endif extern void mips_reboot_setup(void); -extern void mips_time_init(void); extern unsigned long mips_rtc_get_time(void); #ifdef CONFIG_KGDB @@ -185,7 +184,4 @@ void __init plat_mem_setup(void) #endif #endif mips_reboot_setup(); - - board_time_init = mips_time_init; - rtc_mips_get_time = mips_rtc_get_time; } diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c index 5f70eaf01fab..fad58972f3ac 100644 --- a/arch/mips/mips-boards/sead/sead_setup.c +++ b/arch/mips/mips-boards/sead/sead_setup.c @@ -35,7 +35,6 @@ #include extern void mips_reboot_setup(void); -extern void mips_time_init(void); static void __init serial_init(void); @@ -52,8 +51,6 @@ void __init plat_mem_setup(void) serial_init (); - board_time_init = mips_time_init; - mips_reboot_setup(); } diff --git a/arch/mips/mipssim/sim_setup.c b/arch/mips/mipssim/sim_setup.c index d012719c4d24..452c129d02c1 100644 --- a/arch/mips/mipssim/sim_setup.c +++ b/arch/mips/mipssim/sim_setup.c @@ -36,7 +36,6 @@ #include -extern void sim_time_init(void); static void __init serial_init(void); unsigned int _isbonito = 0; @@ -54,7 +53,6 @@ void __init plat_mem_setup(void) serial_init(); - board_time_init = sim_time_init; pr_info("Linux started...\n"); #ifdef CONFIG_MIPS_MT_SMP diff --git a/arch/mips/mipssim/sim_time.c b/arch/mips/mipssim/sim_time.c index a0f5a5dca1b2..9a355e77952f 100644 --- a/arch/mips/mipssim/sim_time.c +++ b/arch/mips/mipssim/sim_time.c @@ -146,7 +146,7 @@ static unsigned int __init estimate_cpu_frequency(void) return count; } -void __init sim_time_init(void) +void __init plat_time_init(void) { unsigned int est_freq, flags; diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/philips/pnx8550/common/setup.c index 5bd737477685..2ce298f4d19a 100644 --- a/arch/mips/philips/pnx8550/common/setup.c +++ b/arch/mips/philips/pnx8550/common/setup.c @@ -47,7 +47,6 @@ extern void pnx8550_machine_halt(void); extern void pnx8550_machine_power_off(void); extern struct resource ioport_resource; extern struct resource iomem_resource; -extern void pnx8550_time_init(void); extern void rs_kgdb_hook(int tty_no); extern char *prom_getcmdline(void); @@ -104,8 +103,6 @@ void __init plat_mem_setup(void) _machine_halt = pnx8550_machine_halt; pm_power_off = pnx8550_machine_power_off; - board_time_init = pnx8550_time_init; - /* Clear the Global 2 Register, PCI Inta Output Enable Registers Bit 1:Enable DAC Powerdown -> 0:DACs are enabled and are working normally diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/philips/pnx8550/common/time.c index 68def3880a1c..e818fd0f1584 100644 --- a/arch/mips/philips/pnx8550/common/time.c +++ b/arch/mips/philips/pnx8550/common/time.c @@ -1,6 +1,7 @@ /* * Copyright 2001, 2002, 2003 MontaVista Software Inc. * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) * * Common time service routines for MIPS machines. See * Documents/MIPS/README.txt. @@ -46,16 +47,16 @@ static void timer_ack(void) } /* - * pnx8550_time_init() - it does the following things: + * plat_time_init() - it does the following things: * - * 1) board_time_init() - + * 1) plat_time_init() - * a) (optional) set up RTC routines, * b) (optional) calibrate and set the mips_hpt_frequency * (only needed if you intended to use cpu counter as timer interrupt * source) */ -void pnx8550_time_init(void) +__init void plat_time_init(void) { unsigned int n; unsigned int m; diff --git a/arch/mips/pmc-sierra/msp71xx/msp_setup.c b/arch/mips/pmc-sierra/msp71xx/msp_setup.c index e4cc54824475..c93675615f5d 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_setup.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_setup.c @@ -25,7 +25,6 @@ #define MSP_BOARD_RESET_GPIO 9 #endif -extern void msp_timer_init(void); extern void msp_serial_setup(void); extern void pmctwiled_setup(void); @@ -149,8 +148,6 @@ void __init plat_mem_setup(void) _machine_restart = msp_restart; _machine_halt = msp_halt; pm_power_off = msp_power_off; - - board_time_init = msp_timer_init; } void __init prom_init(void) diff --git a/arch/mips/pmc-sierra/msp71xx/msp_time.c b/arch/mips/pmc-sierra/msp71xx/msp_time.c index 2a2beac5a4f8..f221d4763625 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_time.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_time.c @@ -36,7 +36,7 @@ #include #include -void __init msp_timer_init(void) +void __init plat_time_init(void) { char *endp, *s; unsigned long cpu_rate = 0; @@ -81,7 +81,6 @@ void __init msp_timer_init(void) mips_hpt_frequency = cpu_rate/2; } - void __init plat_timer_setup(struct irqaction *irq) { #ifdef CONFIG_IRQ_MSP_CIC diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 58862c8d1d00..56bf69595da8 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c @@ -70,7 +70,7 @@ void __init bus_error_init(void) } -unsigned long m48t37y_get_time(void) +unsigned long read_persistent_clock(void) { unsigned int year, month, day, hour, min, sec; unsigned long flags; @@ -95,7 +95,7 @@ unsigned long m48t37y_get_time(void) return mktime(year, month, day, hour, min, sec); } -int m48t37y_set_time(unsigned long sec) +int rtc_mips_set_time(unsigned long tim) { struct rtc_time tm; unsigned long flags; @@ -138,7 +138,7 @@ void __init plat_timer_setup(struct irqaction *irq) setup_irq(7, irq); } -void yosemite_time_init(void) +void __init plat_time_init(void) { mips_hpt_frequency = cpu_clock_freq / 2; mips_hpt_frequency = 33000000 * 3 * 5; @@ -198,17 +198,6 @@ static void __init py_rtc_setup(void) m48t37_base = ioremap(YOSEMITE_RTC_BASE, YOSEMITE_RTC_SIZE); if (!m48t37_base) printk(KERN_ERR "Mapping the RTC failed\n"); - - rtc_mips_get_time = m48t37y_get_time; - rtc_mips_set_time = m48t37y_set_time; - - write_seqlock(&xtime_lock); - xtime.tv_sec = m48t37y_get_time(); - xtime.tv_nsec = 0; - - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); - write_sequnlock(&xtime_lock); } /* Not only time init but that's what the hook it's called through is named */ @@ -221,7 +210,6 @@ static void __init py_late_time_init(void) void __init plat_mem_setup(void) { - board_time_init = yosemite_time_init; late_time_init = py_late_time_init; /* Add memory regions */ diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c index e7ce7982db72..174f09e42f6b 100644 --- a/arch/mips/sgi-ip22/ip22-setup.c +++ b/arch/mips/sgi-ip22/ip22-setup.c @@ -51,7 +51,6 @@ void ip22_do_break(void) EXPORT_SYMBOL(ip22_do_break); extern void ip22_be_init(void) __init; -extern void ip22_time_init(void) __init; void __init plat_mem_setup(void) { @@ -59,7 +58,6 @@ void __init plat_mem_setup(void) char *cserial; board_be_init = ip22_be_init; - ip22_time_init(); /* Init the INDY HPC I/O controller. Need to call this before * fucking with the memory controller because it needs to know the diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index de3d01823ad5..0387c385b4b2 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -32,7 +32,7 @@ * note that mktime uses month from 1 to 12 while to_tm * uses 0 to 11. */ -static unsigned long indy_rtc_get_time(void) +unsigned long read_persistent_clock(void) { unsigned int yrs, mon, day, hrs, min, sec; unsigned int save_control; @@ -60,7 +60,7 @@ static unsigned long indy_rtc_get_time(void) return mktime(yrs + 1900, mon, day, hrs, min, sec); } -static int indy_rtc_set_time(unsigned long tim) +int rtc_mips_set_time(unsigned long tim) { struct rtc_time tm; unsigned int save_control; @@ -128,7 +128,7 @@ static unsigned long dosample(void) /* * Here we need to calibrate the cycle counter to at least be close. */ -static __init void indy_time_init(void) +__init void plat_time_init(void) { unsigned long r4k_ticks[3]; unsigned long r4k_tick; @@ -207,12 +207,3 @@ void __init plat_timer_setup(struct irqaction *irq) /* setup irqaction */ setup_irq(SGI_TIMER_IRQ, irq); } - -void __init ip22_time_init(void) -{ - /* setup hookup functions */ - rtc_mips_get_time = indy_rtc_get_time; - rtc_mips_set_time = indy_rtc_set_time; - - board_time_init = indy_time_init; -} diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c index af08c41d6aa8..681b593071cb 100644 --- a/arch/mips/sgi-ip27/ip27-init.c +++ b/arch/mips/sgi-ip27/ip27-init.c @@ -194,7 +194,6 @@ static inline void ioc3_eth_init(void) ioc3->eier = 0; } -extern void ip27_time_init(void); extern void ip27_reboot_setup(void); void __init plat_mem_setup(void) @@ -241,6 +240,4 @@ void __init plat_mem_setup(void) per_cpu_init(); set_io_port_base(IO_BASE); - - board_time_init = ip27_time_init; } diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 31346162e9fa..9c1700e85be0 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -123,7 +123,7 @@ again: #include #include -static __init unsigned long get_m48t35_time(void) +unsigned long read_persistent_clock(void) { unsigned int year, month, date, hour, min, sec; struct m48t35_rtc *rtc; @@ -205,12 +205,10 @@ static cycle_t ip27_hpt_read(void) return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); } -void __init ip27_time_init(void) +void __init plat_time_init(void) { clocksource_mips.read = ip27_hpt_read; mips_hpt_frequency = CYCLES_PER_SEC; - xtime.tv_sec = get_m48t35_time(); - xtime.tv_nsec = 0; } void __init cpu_time_init(void) diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c index bbba066cb405..4125a5ba119e 100644 --- a/arch/mips/sgi-ip32/ip32-setup.c +++ b/arch/mips/sgi-ip32/ip32-setup.c @@ -62,10 +62,15 @@ static inline void str2eaddr(unsigned char *ea, unsigned char *str) } #endif +unsigned long read_persistent_clock(void) +{ + return mc146818_get_cmos_time(); +} + /* An arbitrary time; this can be decreased if reliability looks good */ #define WAIT_MS 10 -void __init ip32_time_init(void) +void __init plat_time_init(void) { printk(KERN_INFO "Calibrating system timer... "); write_c0_count(0); @@ -85,11 +90,6 @@ void __init plat_mem_setup(void) { board_be_init = ip32_be_init; - rtc_mips_get_time = mc146818_get_cmos_time; - rtc_mips_set_mmss = mc146818_set_rtc_mmss; - - board_time_init = ip32_time_init; - #ifdef CONFIG_SGI_O2MACE_ETH { char *mac = ArcGetEnvironmentVariable("eaddr"); diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index 83572d8f3e14..8b3ef0e4cd55 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c @@ -69,7 +69,7 @@ const char *get_system_type(void) return "SiByte " SIBYTE_BOARD_NAME; } -void __init swarm_time_init(void) +void __init plat_time_init(void) { #if defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) /* Setup HPT */ @@ -104,6 +104,44 @@ int swarm_be_handler(struct pt_regs *regs, int is_fixup) return (is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL); } +enum swarm_rtc_type { + RTC_NONE, + RTC_XICOR, + RTC_M4LT81 +}; + +enum swarm_rtc_type swarm_rtc_type; + +unsigned long read_persistent_clock(void) +{ + switch (swarm_rtc_type) { + case RTC_XICOR: + return xicor_get_time(); + + case RTC_M4LT81: + return m41t81_get_time(); + + case RTC_NONE: + default: + return mktime(2000, 1, 1, 0, 0, 0); + } +} + +int rtc_mips_set_time(unsigned long sec) +{ + switch (swarm_rtc_type) { + case RTC_XICOR: + return xicor_set_time(sec); + + case RTC_M4LT81: + return m41t81_set_time(sec); + + case RTC_NONE: + default: + return -1; + } +} + void __init plat_mem_setup(void) { #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) @@ -116,20 +154,12 @@ void __init plat_mem_setup(void) panic_timeout = 5; /* For debug. */ - board_time_init = swarm_time_init; board_be_handler = swarm_be_handler; - if (xicor_probe()) { - printk("swarm setup: Xicor 1241 RTC detected.\n"); - rtc_mips_get_time = xicor_get_time; - rtc_mips_set_time = xicor_set_time; - } - - if (m41t81_probe()) { - printk("swarm setup: M41T81 RTC detected.\n"); - rtc_mips_get_time = m41t81_get_time; - rtc_mips_set_time = m41t81_set_time; - } + if (xicor_probe()) + swarm_rtc_type = RTC_XICOR; + if (m41t81_probe()) + swarm_rtc_type = RTC_M4LT81; printk("This kernel optimized for " #ifdef CONFIG_SIMULATION diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c index 44b1ae62aa4a..25cf646329ae 100644 --- a/arch/mips/sni/pcimt.c +++ b/arch/mips/sni/pcimt.c @@ -313,7 +313,6 @@ void __init sni_pcimt_init(void) { sni_pcimt_detect(); sni_pcimt_sc_init(); - board_time_init = sni_cpu_time_init; ioport_resource.end = sni_io_resource.end; #ifdef CONFIG_PCI PCIBIOS_MIN_IO = 0x9000; diff --git a/arch/mips/sni/pcit.c b/arch/mips/sni/pcit.c index 2480c478dcbd..3361bdd240e6 100644 --- a/arch/mips/sni/pcit.c +++ b/arch/mips/sni/pcit.c @@ -263,7 +263,6 @@ void __init sni_pcit_cplus_irq_init(void) void __init sni_pcit_init(void) { - board_time_init = sni_cpu_time_init; ioport_resource.end = sni_io_resource.end; #ifdef CONFIG_PCI PCIBIOS_MIN_IO = 0x9000; diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c index 28a11d8605ce..94f115c6b2e0 100644 --- a/arch/mips/sni/rm200.c +++ b/arch/mips/sni/rm200.c @@ -194,5 +194,4 @@ void __init sni_rm200_init(void) { set_io_port_base(SNI_PORT_BASE + 0x02000000); ioport_resource.end += 0x02000000; - board_time_init = sni_cpu_time_init; } diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index 20028fc7757e..92452d677d8f 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c @@ -4,6 +4,7 @@ #include #include +#include #define SNI_CLOCK_TICK_RATE 3686400 #define SNI_COUNTER2_DIV 64 @@ -71,7 +72,7 @@ static __init unsigned long dosample(void) /* * Here we need to calibrate the cycle counter to at least be close. */ -__init void sni_cpu_time_init(void) +void __init plat_time_init(void) { unsigned long r4k_ticks[3]; unsigned long r4k_tick; @@ -146,3 +147,8 @@ void __init plat_timer_setup(struct irqaction *irq) break; } } + +unsigned long read_persistent_clock(void) +{ + return -1; +} diff --git a/arch/mips/tx4927/common/tx4927_setup.c b/arch/mips/tx4927/common/tx4927_setup.c index b18ed58f88a9..8ce0989671d8 100644 --- a/arch/mips/tx4927/common/tx4927_setup.c +++ b/arch/mips/tx4927/common/tx4927_setup.c @@ -49,14 +49,11 @@ #undef DEBUG -void __init tx4927_time_init(void); void dump_cp0(char *key); void __init plat_mem_setup(void) { - board_time_init = tx4927_time_init; - #ifdef CONFIG_TOSHIBA_RBTX4927 { extern void toshiba_rbtx4927_setup(void); @@ -65,20 +62,16 @@ void __init plat_mem_setup(void) #endif } -void __init tx4927_time_init(void) +void __init plat_time_init(void) { - #ifdef CONFIG_TOSHIBA_RBTX4927 { extern void toshiba_rbtx4927_time_init(void); toshiba_rbtx4927_time_init(); } #endif - - return; } - void __init plat_timer_setup(struct irqaction *irq) { setup_irq(TX4927_IRQ_CPU_TIMER, irq); diff --git a/arch/mips/tx4938/common/setup.c b/arch/mips/tx4938/common/setup.c index 142abf453e40..ab4082267553 100644 --- a/arch/mips/tx4938/common/setup.c +++ b/arch/mips/tx4938/common/setup.c @@ -34,25 +34,16 @@ #include extern void toshiba_rbtx4938_setup(void); -extern void rbtx4938_time_init(void); void __init tx4938_setup(void); -void __init tx4938_time_init(void); void dump_cp0(char *key); void __init plat_mem_setup(void) { - board_time_init = tx4938_time_init; toshiba_rbtx4938_setup(); } -void __init -tx4938_time_init(void) -{ - rbtx4938_time_init(); -} - void __init plat_timer_setup(struct irqaction *irq) { setup_irq(TX4938_IRQ_CPU_TIMER, irq); diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c index f236b1ff8923..304b406fcb9d 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c @@ -39,7 +39,6 @@ #include #include -extern void rbtx4938_time_init(void) __init; extern char * __init prom_getcmdline(void); static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr); @@ -856,7 +855,7 @@ void tx4938_report_pcic_status(void) /* We use onchip r4k counter or TMR timer as our system wide timer * interrupt running at 100HZ. */ -void __init rbtx4938_time_init(void) +void __init plat_time_init(void) { mips_hpt_frequency = txx9_cpu_clock / 2; } diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c index 4f97e0ba9e24..407cec203b29 100644 --- a/arch/mips/vr41xx/common/init.c +++ b/arch/mips/vr41xx/common/init.c @@ -36,7 +36,7 @@ static void __init iomem_resource_init(void) iomem_resource.end = IO_MEM_RESOURCE_END; } -static void __init setup_timer_frequency(void) +void __init plat_time_init(void) { unsigned long tclock; @@ -53,16 +53,10 @@ void __init plat_timer_setup(struct irqaction *irq) setup_irq(TIMER_IRQ, irq); } -static void __init timer_init(void) -{ - board_time_init = setup_timer_frequency; -} - void __init plat_mem_setup(void) { vr41xx_calculate_clock_frequency(); - timer_init(); iomem_resource_init(); } diff --git a/include/asm-mips/mach-bcm47xx/bcm47xx.h b/include/asm-mips/mach-bcm47xx/bcm47xx.h index a2fb5e8dd6c6..d008f47a28bd 100644 --- a/include/asm-mips/mach-bcm47xx/bcm47xx.h +++ b/include/asm-mips/mach-bcm47xx/bcm47xx.h @@ -22,6 +22,4 @@ /* SSB bus */ extern struct ssb_bus ssb_bcm47xx; -extern void bcm47xx_time_init(void); - #endif /* __ASM_BCM47XX_H */ diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index a632cef830a2..74ab33157d69 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -26,15 +26,13 @@ extern spinlock_t rtc_lock; /* - * RTC ops. By default, they point to no-RTC functions. - * rtc_mips_get_time - mktime(year, mon, day, hour, min, sec) in seconds. + * RTC ops. By default, they point to weak no-op RTC functions. * rtc_mips_set_time - reverse the above translation and set time to RTC. * rtc_mips_set_mmss - similar to rtc_set_time, but only min and sec need * to be set. Used by RTC sync-up. */ -extern unsigned long (*rtc_mips_get_time)(void); -extern int (*rtc_mips_set_time)(unsigned long); -extern int (*rtc_mips_set_mmss)(unsigned long); +extern int rtc_mips_set_time(unsigned long); +extern int rtc_mips_set_mmss(unsigned long); /* * Timer interrupt functions. @@ -75,11 +73,9 @@ extern asmlinkage void ll_local_timer_interrupt(int irq); /* * board specific routines required by time_init(). - * board_time_init is defaulted to NULL and can remain so. - * plat_timer_setup must be setup properly in machine setup routine. */ struct irqaction; -extern void (*board_time_init)(void); +extern void plat_time_init(void); extern void plat_timer_setup(struct irqaction *irq); /* From 90b02340dcc6ce00bf22c48f4865915f5989e5e4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:09 +0100 Subject: [PATCH 2242/2804] [MIPS] Switch from to_tm to rtc_time_to_tm This replaces the MIPS-specific to_tm function with the generic rtc_time_to_tm function. The big difference between the two functions is that rtc_time_to_tm uses epoch 70 while to_tm uses 1970, so the result of rtc_time_to_tm needs to be fixed up. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/kernel/time.c | 49 -------------------------- arch/mips/pmc-sierra/yosemite/setup.c | 8 +++-- arch/mips/sgi-ip22/ip22-time.c | 6 ++-- arch/mips/sibyte/swarm/rtc_m41t81.c | 3 +- arch/mips/sibyte/swarm/rtc_xicor1241.c | 3 +- include/asm-mips/time.h | 7 ---- 7 files changed, 14 insertions(+), 63 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index c024113ce280..0cd0f835b13d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -3,6 +3,7 @@ config MIPS default y # Horrible source of confusion. Die, die, die ... select EMBEDDED + select RTC_LIB mainmenu "Linux/MIPS Kernel Configuration" diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 9bbbd9b327fc..c48ebd4b495e 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -397,52 +397,3 @@ void __init time_init(void) init_mips_clocksource(); } - -#define FEBRUARY 2 -#define STARTOFTIME 1970 -#define SECDAY 86400L -#define SECYR (SECDAY * 365) -#define leapyear(y) ((!((y) % 4) && ((y) % 100)) || !((y) % 400)) -#define days_in_year(y) (leapyear(y) ? 366 : 365) -#define days_in_month(m) (month_days[(m) - 1]) - -static int month_days[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -void to_tm(unsigned long tim, struct rtc_time *tm) -{ - long hms, day, gday; - int i; - - gday = day = tim / SECDAY; - hms = tim % SECDAY; - - /* Hours, minutes, seconds are easy */ - tm->tm_hour = hms / 3600; - tm->tm_min = (hms % 3600) / 60; - tm->tm_sec = (hms % 3600) % 60; - - /* Number of years in days */ - for (i = STARTOFTIME; day >= days_in_year(i); i++) - day -= days_in_year(i); - tm->tm_year = i; - - /* Number of months in days left */ - if (leapyear(tm->tm_year)) - days_in_month(FEBRUARY) = 29; - for (i = 1; day >= days_in_month(i); i++) - day -= days_in_month(i); - days_in_month(FEBRUARY) = 28; - tm->tm_mon = i - 1; /* tm_mon starts from 0 to 11 */ - - /* Days are what is left over (+1) from all that. */ - tm->tm_mday = day + 1; - - /* - * Determine the day of week - */ - tm->tm_wday = (gday + 4) % 7; /* 1970/1/1 was Thursday */ -} - -EXPORT_SYMBOL(to_tm); diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 56bf69595da8..015fcc363dc0 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c @@ -100,8 +100,12 @@ int rtc_mips_set_time(unsigned long tim) struct rtc_time tm; unsigned long flags; - /* convert to a more useful format -- note months count from 0 */ - to_tm(sec, &tm); + /* + * Convert to a more useful format -- note months count from 0 + * and years from 1900 + */ + rtc_time_to_tm(tim, &tm); + tm.tm_year += 1900; tm.tm_mon += 1; spin_lock_irqsave(&rtc_lock, flags); diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index 0387c385b4b2..c49418067f93 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -29,7 +29,7 @@ #include /* - * note that mktime uses month from 1 to 12 while to_tm + * Note that mktime uses month from 1 to 12 while rtc_time_to_tm * uses 0 to 11. */ unsigned long read_persistent_clock(void) @@ -66,10 +66,10 @@ int rtc_mips_set_time(unsigned long tim) unsigned int save_control; unsigned long flags; - to_tm(tim, &tm); + rtc_time_to_tm(tim, &tm); tm.tm_mon += 1; /* tm_mon starts at zero */ - tm.tm_year -= 1940; + tm.tm_year -= 40; if (tm.tm_year >= 100) tm.tm_year -= 100; diff --git a/arch/mips/sibyte/swarm/rtc_m41t81.c b/arch/mips/sibyte/swarm/rtc_m41t81.c index c13914bdda59..26fbff4c15b1 100644 --- a/arch/mips/sibyte/swarm/rtc_m41t81.c +++ b/arch/mips/sibyte/swarm/rtc_m41t81.c @@ -146,7 +146,8 @@ int m41t81_set_time(unsigned long t) struct rtc_time tm; unsigned long flags; - to_tm(t, &tm); + /* Note we don't care about the century */ + rtc_time_to_tm(t, &tm); /* * Note the write order matters as it ensures the correctness. diff --git a/arch/mips/sibyte/swarm/rtc_xicor1241.c b/arch/mips/sibyte/swarm/rtc_xicor1241.c index f4a178836415..ff3e5dabb348 100644 --- a/arch/mips/sibyte/swarm/rtc_xicor1241.c +++ b/arch/mips/sibyte/swarm/rtc_xicor1241.c @@ -115,7 +115,8 @@ int xicor_set_time(unsigned long t) int tmp; unsigned long flags; - to_tm(t, &tm); + rtc_time_to_tm(t, &tm); + tm.tm_year += 1900; spin_lock_irqsave(&rtc_lock, flags); /* unlock writes to the CCR */ diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 74ab33157d69..963507d33f69 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -48,13 +48,6 @@ extern void (*mips_timer_ack)(void); */ extern struct clocksource clocksource_mips; -/* - * to_tm() converts system time back to (year, mon, day, hour, min, sec). - * It is intended to help implement rtc_set_time() functions. - * Copied from PPC implementation. - */ -extern void to_tm(unsigned long tim, struct rtc_time *tm); - /* * high-level timer interrupt routines. */ From 91a2fcc88634663e9e13dcdfad0e4a860e64aeee Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:09 +0100 Subject: [PATCH 2243/2804] [MIPS] Consolidate all variants of MIPS cp0 timer interrupt handlers. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/irq.c | 4 +- arch/mips/au1000/common/time.c | 40 ---------- arch/mips/kernel/smtc.c | 2 +- arch/mips/kernel/time.c | 91 ++++++++++++++++------ arch/mips/mips-boards/generic/time.c | 112 ++------------------------- arch/mips/mipssim/sim_time.c | 72 ----------------- arch/mips/sgi-ip22/ip22-int.c | 5 +- arch/mips/sgi-ip22/ip22-time.c | 10 --- arch/mips/sibyte/bcm1480/time.c | 13 +--- arch/mips/sibyte/sb1250/time.c | 13 +--- include/asm-mips/time.h | 16 ++-- 11 files changed, 87 insertions(+), 291 deletions(-) diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index db2ba0dbfd5a..47949d6f2c10 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -65,8 +65,6 @@ #define EXT_INTC1_REQ1 5 /* IP 5 */ #define MIPS_TIMER_IP 7 /* IP 7 */ -extern void mips_timer_interrupt(void); - void (*board_init_irq)(void); static DEFINE_SPINLOCK(irq_lock); @@ -635,7 +633,7 @@ asmlinkage void plat_irq_dispatch(void) unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; if (pending & CAUSEF_IP7) - mips_timer_interrupt(); + ll_timer_interrupt(63); else if (pending & CAUSEF_IP2) intc0_req0_irqdispatch(); else if (pending & CAUSEF_IP3) diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index fb1fd50f19a6..726c340460b6 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -64,48 +64,8 @@ static unsigned long last_pc0, last_match20; static DEFINE_SPINLOCK(time_lock); -static inline void ack_r4ktimer(unsigned long newval) -{ - write_c0_compare(newval); -} - -/* - * There are a lot of conceptually broken versions of the MIPS timer interrupt - * handler floating around. This one is rather different, but the algorithm - * is provably more robust. - */ unsigned long wtimer; -void mips_timer_interrupt(void) -{ - int irq = 63; - - irq_enter(); - kstat_this_cpu.irqs[irq]++; - - if (r4k_offset == 0) - goto null; - - do { - kstat_this_cpu.irqs[irq]++; - do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - r4k_cur += r4k_offset; - ack_r4ktimer(r4k_cur); - - } while (((unsigned long)read_c0_count() - - r4k_cur) < 0x7fffffff); - - irq_exit(); - return; - -null: - ack_r4ktimer(0); - irq_exit(); -} - #ifdef CONFIG_PM irqreturn_t counter0_irq(int irq, void *dev_id) { diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 137183bba54f..a7afbf2c9710 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -867,7 +867,7 @@ void ipi_decode(struct smtc_ipi *pipi) #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG clock_hang_reported[dest_copy] = 0; #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ - local_timer_interrupt(0, NULL); + local_timer_interrupt(0); irq_exit(); break; case LINUX_SMP_IPI: diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index c48ebd4b495e..d23e6825e988 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -144,7 +144,7 @@ void local_timer_interrupt(int irq, void *dev_id) * High-level timer interrupt service routines. This function * is set as irqaction->handler and is invoked through do_IRQ. */ -irqreturn_t timer_interrupt(int irq, void *dev_id) +static irqreturn_t timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); @@ -174,9 +174,10 @@ int null_perf_irq(void) return 0; } +EXPORT_SYMBOL(null_perf_irq); + int (*perf_irq)(void) = null_perf_irq; -EXPORT_SYMBOL(null_perf_irq); EXPORT_SYMBOL(perf_irq); /* @@ -208,35 +209,79 @@ static inline int handle_perf_irq (int r2) !r2; } -asmlinkage void ll_timer_interrupt(int irq) +void ll_timer_interrupt(int irq, void *dev_id) { + int cpu = smp_processor_id(); + +#ifdef CONFIG_MIPS_MT_SMTC + /* + * In an SMTC system, one Count/Compare set exists per VPE. + * Which TC within a VPE gets the interrupt is essentially + * random - we only know that it shouldn't be one with + * IXMT set. Whichever TC gets the interrupt needs to + * send special interprocessor interrupts to the other + * TCs to make sure that they schedule, etc. + * + * That code is specific to the SMTC kernel, not to + * the a particular platform, so it's invoked from + * the general MIPS timer_interrupt routine. + */ + + /* + * We could be here due to timer interrupt, + * perf counter overflow, or both. + */ + (void) handle_perf_irq(1); + + if (read_c0_cause() & (1 << 30)) { + /* + * There are things we only want to do once per tick + * in an "MP" system. One TC of each VPE will take + * the actual timer interrupt. The others will get + * timer broadcast IPIs. We use whoever it is that takes + * the tick on VPE 0 to run the full timer_interrupt(). + */ + if (cpu_data[cpu].vpe_id == 0) { + timer_interrupt(irq, NULL); + } else { + write_c0_compare(read_c0_count() + + (mips_hpt_frequency/HZ)); + local_timer_interrupt(irq, dev_id); + } + smtc_timer_broadcast(cpu_data[cpu].vpe_id); + } +#else /* CONFIG_MIPS_MT_SMTC */ int r2 = cpu_has_mips_r2; - irq_enter(); - kstat_this_cpu.irqs[irq]++; - if (handle_perf_irq(r2)) - goto out; + return; if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) - goto out; + return; - timer_interrupt(irq, NULL); + if (cpu == 0) { + /* + * CPU 0 handles the global timer interrupt job and process + * accounting resets count/compare registers to trigger next + * timer int. + */ + timer_interrupt(irq, NULL); + } else { + /* Everyone else needs to reset the timer int here as + ll_local_timer_interrupt doesn't */ + /* + * FIXME: need to cope with counter underflow. + * More support needs to be added to kernel/time for + * counter/timer interrupts on multiple CPU's + */ + write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); -out: - irq_exit(); -} - -asmlinkage void ll_local_timer_interrupt(int irq) -{ - irq_enter(); - if (smp_processor_id() != 0) - kstat_this_cpu.irqs[irq]++; - - /* we keep interrupt disabled all the time */ - local_timer_interrupt(irq, NULL); - - irq_exit(); + /* + * Other CPUs should do profiling and process accounting + */ + local_timer_interrupt(irq, dev_id); + } +#endif /* CONFIG_MIPS_MT_SMTC */ } /* diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 075f9d46f40e..345de881013c 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -67,108 +67,6 @@ static void mips_perf_dispatch(void) do_IRQ(cp0_perfcount_irq); } -/* - * Redeclare until I get around mopping the timer code insanity on MIPS. - */ -extern int null_perf_irq(void); - -extern int (*perf_irq)(void); - -/* - * Possibly handle a performance counter interrupt. - * Return true if the timer interrupt should not be checked - */ -static inline int handle_perf_irq (int r2) -{ - /* - * The performance counter overflow interrupt may be shared with the - * timer interrupt (cp0_perfcount_irq < 0). If it is and a - * performance counter has overflowed (perf_irq() == IRQ_HANDLED) - * and we can't reliably determine if a counter interrupt has also - * happened (!r2) then don't check for a timer interrupt. - */ - return (cp0_perfcount_irq < 0) && - perf_irq() == IRQ_HANDLED && - !r2; -} - -irqreturn_t mips_timer_interrupt(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - -#ifdef CONFIG_MIPS_MT_SMTC - /* - * In an SMTC system, one Count/Compare set exists per VPE. - * Which TC within a VPE gets the interrupt is essentially - * random - we only know that it shouldn't be one with - * IXMT set. Whichever TC gets the interrupt needs to - * send special interprocessor interrupts to the other - * TCs to make sure that they schedule, etc. - * - * That code is specific to the SMTC kernel, not to - * the a particular platform, so it's invoked from - * the general MIPS timer_interrupt routine. - */ - - /* - * We could be here due to timer interrupt, - * perf counter overflow, or both. - */ - (void) handle_perf_irq(1); - - if (read_c0_cause() & (1 << 30)) { - /* - * There are things we only want to do once per tick - * in an "MP" system. One TC of each VPE will take - * the actual timer interrupt. The others will get - * timer broadcast IPIs. We use whoever it is that takes - * the tick on VPE 0 to run the full timer_interrupt(). - */ - if (cpu_data[cpu].vpe_id == 0) { - timer_interrupt(irq, NULL); - } else { - write_c0_compare(read_c0_count() + - (mips_hpt_frequency/HZ)); - local_timer_interrupt(irq, dev_id); - } - smtc_timer_broadcast(); - } -#else /* CONFIG_MIPS_MT_SMTC */ - int r2 = cpu_has_mips_r2; - - if (handle_perf_irq(r2)) - goto out; - - if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) - goto out; - - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job and process - * accounting resets count/compare registers to trigger next - * timer int. - */ - timer_interrupt(irq, NULL); - } else { - /* Everyone else needs to reset the timer int here as - ll_local_timer_interrupt doesn't */ - /* - * FIXME: need to cope with counter underflow. - * More support needs to be added to kernel/time for - * counter/timer interrupts on multiple CPU's - */ - write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); - - /* - * Other CPUs should do profiling and process accounting - */ - local_timer_interrupt(irq, dev_id); - } -out: -#endif /* CONFIG_MIPS_MT_SMTC */ - return IRQ_HANDLED; -} - /* * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect */ @@ -246,7 +144,7 @@ void __init plat_time_init(void) mips_scroll_message(); } -irqreturn_t mips_perf_interrupt(int irq, void *dev_id) +static irqreturn_t mips_perf_interrupt(int irq, void *dev_id) { return perf_irq(); } @@ -257,8 +155,10 @@ static struct irqaction perf_irqaction = { .name = "performance", }; -void __init plat_perf_setup(struct irqaction *irq) +void __init plat_perf_setup(void) { + struct irqaction *irq = &perf_irqaction; + cp0_perfcount_irq = -1; #ifdef MSC01E_INT_BASE @@ -297,8 +197,6 @@ void __init plat_timer_setup(struct irqaction *irq) mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; } - /* we are using the cpu counter for timer interrupts */ - irq->handler = mips_timer_interrupt; /* we use our own handler */ #ifdef CONFIG_MIPS_MT_SMTC setup_irq_smtc(mips_cpu_timer_irq, irq, 0x100 << cp0_compare_irq); #else @@ -308,5 +206,5 @@ void __init plat_timer_setup(struct irqaction *irq) set_irq_handler(mips_cpu_timer_irq, handle_percpu_irq); #endif - plat_perf_setup(&perf_irqaction); + plat_perf_setup(); } diff --git a/arch/mips/mipssim/sim_time.c b/arch/mips/mipssim/sim_time.c index 9a355e77952f..3625f7d49035 100644 --- a/arch/mips/mipssim/sim_time.c +++ b/arch/mips/mipssim/sim_time.c @@ -23,77 +23,6 @@ unsigned long cpu_khz; -irqreturn_t sim_timer_interrupt(int irq, void *dev_id) -{ -#ifdef CONFIG_SMP - int cpu = smp_processor_id(); - - /* - * CPU 0 handles the global timer interrupt job - * resets count/compare registers to trigger next timer int. - */ -#ifndef CONFIG_MIPS_MT_SMTC - if (cpu == 0) { - timer_interrupt(irq, dev_id); - } else { - /* Everyone else needs to reset the timer int here as - ll_local_timer_interrupt doesn't */ - /* - * FIXME: need to cope with counter underflow. - * More support needs to be added to kernel/time for - * counter/timer interrupts on multiple CPU's - */ - write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ)); - } -#else /* SMTC */ - /* - * In SMTC system, one Count/Compare set exists per VPE. - * Which TC within a VPE gets the interrupt is essentially - * random - we only know that it shouldn't be one with - * IXMT set. Whichever TC gets the interrupt needs to - * send special interprocessor interrupts to the other - * TCs to make sure that they schedule, etc. - * - * That code is specific to the SMTC kernel, not to - * the simulation platform, so it's invoked from - * the general MIPS timer_interrupt routine. - * - * We have a problem in that the interrupt vector code - * had to turn off the timer IM bit to avoid redundant - * entries, but we may never get to mips_cpu_irq_end - * to turn it back on again if the scheduler gets - * involved. So we clear the pending timer here, - * and re-enable the mask... - */ - - int vpflags = dvpe(); - write_c0_compare (read_c0_count() - 1); - clear_c0_cause(0x100 << cp0_compare_irq); - set_c0_status(0x100 << cp0_compare_irq); - irq_enable_hazard(); - evpe(vpflags); - - if (cpu_data[cpu].vpe_id == 0) - timer_interrupt(irq, dev_id); - else - write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ)); - smtc_timer_broadcast(cpu_data[cpu].vpe_id); - -#endif /* CONFIG_MIPS_MT_SMTC */ - - /* - * every CPU should do profiling and process accounting - */ - local_timer_interrupt (irq, dev_id); - - return IRQ_HANDLED; -#else - return timer_interrupt (irq, dev_id); -#endif -} - - - /* * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect */ @@ -185,7 +114,6 @@ void __init plat_timer_setup(struct irqaction *irq) } /* we are using the cpu counter for timer interrupts */ - irq->handler = sim_timer_interrupt; setup_irq(mips_cpu_timer_irq, irq); #ifdef CONFIG_SMP diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index 18348321795d..338c0d706988 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -20,10 +20,10 @@ #include #include #include - #include #include #include +#include /* #define DEBUG_SGINT */ @@ -204,7 +204,6 @@ static struct irqaction map1_cascade = { #define SGI_INTERRUPTS SGINT_LOCAL3 #endif -extern void indy_r4k_timer_interrupt(void); extern void indy_8254timer_irq(void); /* @@ -243,7 +242,7 @@ asmlinkage void plat_irq_dispatch(void) * First we check for r4k counter/timer IRQ. */ if (pending & CAUSEF_IP7) - indy_r4k_timer_interrupt(); + ll_timer_interrupt(SGI_TIMER_IRQ, NULL); else if (pending & CAUSEF_IP2) indy_local0_irqdispatch(); else if (pending & CAUSEF_IP3) diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index c49418067f93..a1df1f9e26fa 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -189,16 +189,6 @@ void indy_8254timer_irq(void) irq_exit(); } -void indy_r4k_timer_interrupt(void) -{ - int irq = SGI_TIMER_IRQ; - - irq_enter(); - kstat_this_cpu.irqs[irq]++; - timer_interrupt(irq, NULL); - irq_exit(); -} - void __init plat_timer_setup(struct irqaction *irq) { /* over-write the handler, we use our own way */ diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index 6f3f71bf4244..8519091d848b 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -103,18 +103,7 @@ void bcm1480_timer_interrupt(void) __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job - */ - ll_timer_interrupt(irq); - } - else { - /* - * other CPUs should just do profiling and process accounting - */ - ll_local_timer_interrupt(irq); - } + ll_timer_interrupt(irq); } static cycle_t bcm1480_hpt_read(void) diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 2efffe15ff23..5bb83cd4c113 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -125,18 +125,7 @@ void sb1250_timer_interrupt(void) ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job - */ - ll_timer_interrupt(irq); - } - else { - /* - * other CPUs should just do profiling and process accounting - */ - ll_local_timer_interrupt(irq); - } + ll_timer_interrupt(irq); } /* diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 963507d33f69..3516b32c9efb 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -49,20 +49,14 @@ extern void (*mips_timer_ack)(void); extern struct clocksource clocksource_mips; /* - * high-level timer interrupt routines. + * The low-level timer interrupt routine. */ -extern irqreturn_t timer_interrupt(int irq, void *dev_id); - -/* - * the corresponding low-level timer interrupt routine. - */ -extern asmlinkage void ll_timer_interrupt(int irq); +extern void ll_timer_interrupt(int irq, void *dev_id); /* * profiling and process accouting is done separately in local_timer_interrupt */ extern void local_timer_interrupt(int irq, void *dev_id); -extern asmlinkage void ll_local_timer_interrupt(int irq); /* * board specific routines required by time_init(). @@ -78,4 +72,10 @@ extern void plat_timer_setup(struct irqaction *irq); */ extern unsigned int mips_hpt_frequency; +/* + * The performance counter IRQ on MIPS is a close relative to the timer IRQ + * so it lives here. + */ +extern int (*perf_irq)(void); + #endif /* _ASM_TIME_H */ From 7bcf7717b6a047c272410d0cd00213185fe6b99d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:09 +0100 Subject: [PATCH 2244/2804] [MIPS] Implement clockevents for R4000-style cp0 count/compare interrupt Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 7 + arch/mips/au1000/common/irq.c | 2 +- arch/mips/configs/bigsur_defconfig | 1 - arch/mips/configs/sb1250-swarm_defconfig | 1 - arch/mips/kernel/process.c | 3 + arch/mips/kernel/smp.c | 2 + arch/mips/kernel/smtc.c | 2 +- arch/mips/kernel/time.c | 256 +++++++++++------------ arch/mips/mips-boards/generic/time.c | 26 +-- arch/mips/qemu/q-irq.c | 4 +- arch/mips/qemu/q-setup.c | 1 - arch/mips/sgi-ip22/ip22-int.c | 2 +- arch/mips/sgi-ip32/ip32-irq.c | 2 +- arch/mips/sibyte/Kconfig | 12 +- arch/mips/sibyte/bcm1480/irq.c | 13 +- arch/mips/sibyte/sb1250/irq.c | 50 +++-- arch/mips/sibyte/sb1250/time.c | 12 -- include/asm-mips/mach-ip27/irq.h | 2 + include/asm-mips/qemu.h | 2 +- include/asm-mips/time.h | 10 +- 20 files changed, 210 insertions(+), 200 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 0cd0f835b13d..ecce3aab1981 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -335,6 +335,7 @@ config QEMU select GENERIC_ISA_DMA select HAVE_STD_PC_SERIAL_PORT select I8259 + select IRQ_CPU select ISA select PCSPEAKER select SWAP_IO_SPACE @@ -667,6 +668,10 @@ config GENERIC_CALIBRATE_DELAY bool default y +config GENERIC_CLOCKEVENTS + bool + default y + config GENERIC_TIME bool default y @@ -901,6 +906,8 @@ config BOOT_ELF64 menu "CPU selection" +source "kernel/time/Kconfig" + choice prompt "CPU type" default CPU_R4X00 diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index 47949d6f2c10..a6640b998c6e 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -633,7 +633,7 @@ asmlinkage void plat_irq_dispatch(void) unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; if (pending & CAUSEF_IP7) - ll_timer_interrupt(63); + do_IRQ(63); else if (pending & CAUSEF_IP2) intc0_req0_irqdispatch(); else if (pending & CAUSEF_IP3) diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 700a3a2d688e..30f3e9a2466f 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -69,7 +69,6 @@ CONFIG_SIBYTE_SB1xxx_SOC=y CONFIG_SIBYTE_CFE=y # CONFIG_SIBYTE_CFE_CONSOLE is not set # CONFIG_SIBYTE_BUS_WATCHER is not set -# CONFIG_SIBYTE_SB1250_PROF is not set # CONFIG_SIBYTE_TBPROF is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index 93f9e8331ad7..3d1b6281d887 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig @@ -70,7 +70,6 @@ CONFIG_SIBYTE_HAS_LDT=y CONFIG_SIBYTE_CFE=y # CONFIG_SIBYTE_CFE_CONSOLE is not set # CONFIG_SIBYTE_BUS_WATCHER is not set -# CONFIG_SIBYTE_SB1250_PROF is not set # CONFIG_SIBYTE_TBPROF is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index aadd2cd5778c..f99bb4085430 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ void __noreturn cpu_idle(void) { /* endless idle loop with no priority at all */ while (1) { + tick_nohz_stop_sched_tick(); while (!need_resched()) { #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG extern void smtc_idle_loop_hook(void); @@ -61,6 +63,7 @@ void __noreturn cpu_idle(void) if (cpu_wait) (*cpu_wait)(); } + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 73b0dab02668..500a7ec2880f 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef CONFIG_MIPS_MT_SMTC #include @@ -70,6 +71,7 @@ asmlinkage __cpuinit void start_secondary(void) cpu_probe(); cpu_report(); per_cpu_trap_init(); + mips_clockevent_init(); prom_init_secondary(); /* diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index a7afbf2c9710..137183bba54f 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -867,7 +867,7 @@ void ipi_decode(struct smtc_ipi *pipi) #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG clock_hang_reported[dest_copy] = 0; #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ - local_timer_interrupt(0); + local_timer_interrupt(0, NULL); irq_exit(); break; case LINUX_SMP_IPI: diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index d23e6825e988..35988847c98a 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -11,6 +11,7 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ +#include #include #include #include @@ -34,6 +35,8 @@ #include #include +#include + /* * The integer part of the number of usecs per jiffy is taken from tick, * but the fractional part is not recorded, so we calculate it using the @@ -70,10 +73,6 @@ int update_persistent_clock(struct timespec now) /* how many counter cycles in a jiffy */ static unsigned long cycles_per_jiffy __read_mostly; -/* expirelo is the count value for next CPU timer interrupt */ -static unsigned int expirelo; - - /* * Null timer ack for systems not needing one (e.g. i8254). */ @@ -92,18 +91,7 @@ static cycle_t null_hpt_read(void) */ static void c0_timer_ack(void) { - unsigned int count; - - /* Ack this timer interrupt and set the next one. */ - expirelo += cycles_per_jiffy; - write_c0_compare(expirelo); - - /* Check to see if we have missed any timer interrupts. */ - while (((count = read_c0_count()) - expirelo) < 0x7fffffff) { - /* missed_timer_count++; */ - expirelo = count + cycles_per_jiffy; - write_c0_compare(expirelo); - } + write_c0_compare(read_c0_compare()); } /* @@ -114,13 +102,6 @@ static cycle_t c0_hpt_read(void) return read_c0_count(); } -/* For use both as a high precision timer and an interrupt source. */ -static void __init c0_hpt_timer_init(void) -{ - expirelo = read_c0_count() + cycles_per_jiffy; - write_c0_compare(expirelo); -} - int (*mips_timer_state)(void); void (*mips_timer_ack)(void); @@ -140,35 +121,6 @@ void local_timer_interrupt(int irq, void *dev_id) update_process_times(user_mode(get_irq_regs())); } -/* - * High-level timer interrupt service routines. This function - * is set as irqaction->handler and is invoked through do_IRQ. - */ -static irqreturn_t timer_interrupt(int irq, void *dev_id) -{ - write_seqlock(&xtime_lock); - - mips_timer_ack(); - - /* - * call the generic timer interrupt handling - */ - do_timer(1); - - write_sequnlock(&xtime_lock); - - /* - * In UP mode, we call local_timer_interrupt() to do profiling - * and process accouting. - * - * In SMP mode, local_timer_interrupt() is invoked by appropriate - * low-level local timer interrupt handler. - */ - local_timer_interrupt(irq, dev_id); - - return IRQ_HANDLED; -} - int null_perf_irq(void) { return 0; @@ -209,81 +161,6 @@ static inline int handle_perf_irq (int r2) !r2; } -void ll_timer_interrupt(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - -#ifdef CONFIG_MIPS_MT_SMTC - /* - * In an SMTC system, one Count/Compare set exists per VPE. - * Which TC within a VPE gets the interrupt is essentially - * random - we only know that it shouldn't be one with - * IXMT set. Whichever TC gets the interrupt needs to - * send special interprocessor interrupts to the other - * TCs to make sure that they schedule, etc. - * - * That code is specific to the SMTC kernel, not to - * the a particular platform, so it's invoked from - * the general MIPS timer_interrupt routine. - */ - - /* - * We could be here due to timer interrupt, - * perf counter overflow, or both. - */ - (void) handle_perf_irq(1); - - if (read_c0_cause() & (1 << 30)) { - /* - * There are things we only want to do once per tick - * in an "MP" system. One TC of each VPE will take - * the actual timer interrupt. The others will get - * timer broadcast IPIs. We use whoever it is that takes - * the tick on VPE 0 to run the full timer_interrupt(). - */ - if (cpu_data[cpu].vpe_id == 0) { - timer_interrupt(irq, NULL); - } else { - write_c0_compare(read_c0_count() + - (mips_hpt_frequency/HZ)); - local_timer_interrupt(irq, dev_id); - } - smtc_timer_broadcast(cpu_data[cpu].vpe_id); - } -#else /* CONFIG_MIPS_MT_SMTC */ - int r2 = cpu_has_mips_r2; - - if (handle_perf_irq(r2)) - return; - - if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) - return; - - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job and process - * accounting resets count/compare registers to trigger next - * timer int. - */ - timer_interrupt(irq, NULL); - } else { - /* Everyone else needs to reset the timer int here as - ll_local_timer_interrupt doesn't */ - /* - * FIXME: need to cope with counter underflow. - * More support needs to be added to kernel/time for - * counter/timer interrupts on multiple CPU's - */ - write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); - - /* - * Other CPUs should do profiling and process accounting - */ - local_timer_interrupt(irq, dev_id); - } -#endif /* CONFIG_MIPS_MT_SMTC */ -} - /* * time_init() - it does the following things. * @@ -301,12 +178,6 @@ void ll_timer_interrupt(int irq, void *dev_id) unsigned int mips_hpt_frequency; -static struct irqaction timer_irqaction = { - .handler = timer_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU, - .name = "timer", -}; - static unsigned int __init calibrate_hpt(void) { cycle_t frequency, hpt_start, hpt_end, hpt_count, hz; @@ -355,6 +226,65 @@ struct clocksource clocksource_mips = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; +static int mips_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + unsigned int cnt; + + cnt = read_c0_count(); + cnt += delta; + write_c0_compare(cnt); + + return ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; +} + +static void mips_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + /* Nothing to do ... */ +} + +struct clock_event_device mips_clockevent; + +static struct clock_event_device *global_cd[NR_CPUS]; +static int cp0_timer_irq_installed; + +static irqreturn_t timer_interrupt(int irq, void *dev_id) +{ + const int r2 = cpu_has_mips_r2; + struct clock_event_device *cd; + int cpu = smp_processor_id(); + + /* + * Suckage alert: + * Before R2 of the architecture there was no way to see if a + * performance counter interrupt was pending, so we have to run + * the performance counter interrupt handler anyway. + */ + if (handle_perf_irq(r2)) + goto out; + + /* + * The same applies to performance counter interrupts. But with the + * above we now know that the reason we got here must be a timer + * interrupt. Being the paranoiacs we are we check anyway. + */ + if (!r2 || (read_c0_cause() & (1 << 30))) { + c0_timer_ack(); + cd = global_cd[cpu]; + cd->event_handler(cd); + } + +out: + return IRQ_HANDLED; +} + +static struct irqaction timer_irqaction = { + .handler = timer_interrupt, + .flags = IRQF_DISABLED | IRQF_PERCPU, + .name = "timer", +}; + static void __init init_mips_clocksource(void) { u64 temp; @@ -382,6 +312,56 @@ void __init __weak plat_time_init(void) { } +void __init __weak plat_timer_setup(struct irqaction *irq) +{ +} + +void __cpuinit mips_clockevent_init(void) +{ + uint64_t mips_freq = mips_hpt_frequency; + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd; + unsigned int irq = MIPS_CPU_IRQ_BASE + 7; + + if (!cpu_has_counter) + return; + + if (cpu == 0) + cd = &mips_clockevent; + else + cd = kzalloc(sizeof(*cd), GFP_ATOMIC); + if (!cd) + return; /* We're probably roadkill ... */ + + cd->name = "MIPS"; + cd->features = CLOCK_EVT_FEAT_ONESHOT; + + /* Calculate the min / max delta */ + cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); + cd->shift = 32; + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x30, cd); + + cd->rating = 300; + cd->irq = irq; + cd->cpumask = cpumask_of_cpu(cpu); + cd->set_next_event = mips_next_event; + cd->set_mode = mips_set_mode; + + global_cd[cpu] = cd; + clockevents_register_device(cd); + + if (!cp0_timer_irq_installed) { +#ifdef CONFIG_MIPS_MT_SMTC +#define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq) + setup_irq_smtc(irq, &timer_irqaction, CPUCTR_IMASKBIT); +#else + setup_irq(irq, &timer_irqaction); +#endif /* CONFIG_MIPS_MT_SMTC */ + cp0_timer_irq_installed = 1; + } +} + void __init time_init(void) { plat_time_init(); @@ -407,11 +387,6 @@ void __init time_init(void) /* Calculate cache parameters. */ cycles_per_jiffy = (mips_hpt_frequency + HZ / 2) / HZ; - /* - * This sets up the high precision - * timer for the first interrupt. - */ - c0_hpt_timer_init(); } } if (!mips_hpt_frequency) @@ -421,6 +396,10 @@ void __init time_init(void) printk("Using %u.%03u MHz high precision timer.\n", ((mips_hpt_frequency + 500) / 1000) / 1000, ((mips_hpt_frequency + 500) / 1000) % 1000); + +#ifdef CONFIG_IRQ_CPU + setup_irq(MIPS_CPU_IRQ_BASE + 7, &timer_irqaction); +#endif } if (!mips_timer_ack) @@ -441,4 +420,5 @@ void __init time_init(void) plat_timer_setup(&timer_irqaction); init_mips_clocksource(); + mips_clockevent_init(); } diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 345de881013c..2c8db3e0f4b7 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -144,20 +144,20 @@ void __init plat_time_init(void) mips_scroll_message(); } -static irqreturn_t mips_perf_interrupt(int irq, void *dev_id) -{ - return perf_irq(); -} +//static irqreturn_t mips_perf_interrupt(int irq, void *dev_id) +//{ +// return perf_irq(); +//} -static struct irqaction perf_irqaction = { - .handler = mips_perf_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU, - .name = "performance", -}; +//static struct irqaction perf_irqaction = { +// .handler = mips_perf_interrupt, +// .flags = IRQF_DISABLED | IRQF_PERCPU, +// .name = "performance", +//}; void __init plat_perf_setup(void) { - struct irqaction *irq = &perf_irqaction; +// struct irqaction *irq = &perf_irqaction; cp0_perfcount_irq = -1; @@ -170,12 +170,6 @@ void __init plat_perf_setup(void) if (cp0_perfcount_irq >= 0) { if (cpu_has_vint) set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); -#ifdef CONFIG_MIPS_MT_SMTC - setup_irq_smtc(cp0_perfcount_irq, irq, - 0x100 << cp0_perfcount_irq); -#else - setup_irq(cp0_perfcount_irq, irq); -#endif /* CONFIG_MIPS_MT_SMTC */ #ifdef CONFIG_SMP set_irq_handler(cp0_perfcount_irq, handle_percpu_irq); #endif diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c index 89891e984b3b..4681757460a1 100644 --- a/arch/mips/qemu/q-irq.c +++ b/arch/mips/qemu/q-irq.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -12,7 +13,7 @@ asmlinkage void plat_irq_dispatch(void) unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & 0x8000) { - ll_timer_interrupt(Q_COUNT_COMPARE_IRQ); + do_IRQ(Q_COUNT_COMPARE_IRQ); return; } if (pending & 0x0400) { @@ -29,6 +30,7 @@ void __init arch_init_irq(void) { mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */ + mips_cpu_irq_init(); init_i8259_irqs(); set_c0_status(0x8400); } diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c index 841394336f00..89a207650ce9 100644 --- a/arch/mips/qemu/q-setup.c +++ b/arch/mips/qemu/q-setup.c @@ -17,7 +17,6 @@ void __init plat_timer_setup(struct irqaction *irq) outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40); /* LSB */ outb(LATCH >> 8 , 0x40); /* MSB */ - setup_irq(0, irq); } void __init plat_mem_setup(void) diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index 338c0d706988..f199da7e49cf 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -242,7 +242,7 @@ asmlinkage void plat_irq_dispatch(void) * First we check for r4k counter/timer IRQ. */ if (pending & CAUSEF_IP7) - ll_timer_interrupt(SGI_TIMER_IRQ, NULL); + do_IRQ(SGI_TIMER_IRQ); else if (pending & CAUSEF_IP2) indy_local0_irqdispatch(); else if (pending & CAUSEF_IP3) diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index 5bad1b744d0f..002095b364a3 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -457,7 +457,7 @@ static void ip32_irq4(void) static void ip32_irq5(void) { - ll_timer_interrupt(IP32_R4K_TIMER_IRQ); + do_IRQ(IP32_R4K_TIMER_IRQ); } asmlinkage void plat_irq_dispatch(void) diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index 841b301c99f0..e8fb880272bd 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -1,6 +1,7 @@ config SIBYTE_SB1250 bool select HW_HAS_PCI + select IRQ_CPU select SIBYTE_ENABLE_LDT_IF_PCI select SIBYTE_HAS_ZBUS_PROFILING select SIBYTE_SB1xxx_SOC @@ -8,6 +9,7 @@ config SIBYTE_SB1250 config SIBYTE_BCM1120 bool + select IRQ_CPU select SIBYTE_BCM112X select SIBYTE_HAS_ZBUS_PROFILING select SIBYTE_SB1xxx_SOC @@ -15,6 +17,7 @@ config SIBYTE_BCM1120 config SIBYTE_BCM1125 bool select HW_HAS_PCI + select IRQ_CPU select SIBYTE_BCM112X select SIBYTE_HAS_ZBUS_PROFILING select SIBYTE_SB1xxx_SOC @@ -22,6 +25,7 @@ config SIBYTE_BCM1125 config SIBYTE_BCM1125H bool select HW_HAS_PCI + select IRQ_CPU select SIBYTE_BCM112X select SIBYTE_ENABLE_LDT_IF_PCI select SIBYTE_HAS_ZBUS_PROFILING @@ -29,12 +33,14 @@ config SIBYTE_BCM1125H config SIBYTE_BCM112X bool + select IRQ_CPU select SIBYTE_SB1xxx_SOC select SIBYTE_HAS_ZBUS_PROFILING config SIBYTE_BCM1x80 bool select HW_HAS_PCI + select IRQ_CPU select SIBYTE_HAS_ZBUS_PROFILING select SIBYTE_SB1xxx_SOC select SYS_SUPPORTS_SMP @@ -42,6 +48,7 @@ config SIBYTE_BCM1x80 config SIBYTE_BCM1x55 bool select HW_HAS_PCI + select IRQ_CPU select SIBYTE_SB1xxx_SOC select SIBYTE_HAS_ZBUS_PROFILING select SYS_SUPPORTS_SMP @@ -49,6 +56,7 @@ config SIBYTE_BCM1x55 config SIBYTE_SB1xxx_SOC bool select DMA_COHERENT + select IRQ_CPU select SIBYTE_CFE select SWAP_IO_SPACE select SYS_SUPPORTS_32BIT_KERNEL @@ -166,10 +174,6 @@ config SIBYTE_BW_TRACE buffer activity. Raw buffer data is dumped to console, and must be processed off-line. -config SIBYTE_SB1250_PROF - bool "Support for SB1/SOC profiling - SB1/SCD perf counters" - depends on SIBYTE_SB1xxx_SOC - config SIBYTE_TBPROF tristate "Support for ZBbus profiling" depends on SIBYTE_HAS_ZBUS_PROFILING diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index e729b5f30264..cf979dbb282d 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c @@ -450,7 +450,6 @@ static void bcm1480_kgdb_interrupt(void) #endif /* CONFIG_KGDB */ -extern void bcm1480_timer_interrupt(void); extern void bcm1480_mailbox_interrupt(void); asmlinkage void plat_irq_dispatch(void) @@ -470,8 +469,16 @@ asmlinkage void plat_irq_dispatch(void) else #endif - if (pending & CAUSEF_IP4) - bcm1480_timer_interrupt(); + if (pending & CAUSEF_IP4) { + int cpu = smp_processor_id(); + int irq = K_BCM1480_INT_TIMER_0 + cpu; + + /* Reset the timer */ + __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, + IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); + + do_IRQ(irq); + } #ifdef CONFIG_SMP else if (pending & CAUSEF_IP3) diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index ad593a6c20be..6a4cc84194a9 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -399,18 +400,45 @@ static void sb1250_kgdb_interrupt(void) #endif /* CONFIG_KGDB */ -extern void sb1250_timer_interrupt(void); +static inline void sb1250_timer_interrupt(void) +{ + int cpu = smp_processor_id(); + int irq = K_INT_TIMER_0 + cpu; + + irq_enter(); + kstat_this_cpu.irqs[irq]++; + + write_seqlock(&xtime_lock); + + /* ACK interrupt */ + ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); + + /* + * call the generic timer interrupt handling + */ + do_timer(1); + + write_sequnlock(&xtime_lock); + + /* + * In UP mode, we call local_timer_interrupt() to do profiling + * and process accouting. + * + * In SMP mode, local_timer_interrupt() is invoked by appropriate + * low-level local timer interrupt handler. + */ + local_timer_interrupt(irq); + + irq_exit(); +} + extern void sb1250_mailbox_interrupt(void); asmlinkage void plat_irq_dispatch(void) { unsigned int pending; -#ifdef CONFIG_SIBYTE_SB1250_PROF - /* Set compare to count to silence count/compare timer interrupts */ - write_c0_compare(read_c0_count()); -#endif - /* * What a pain. We have to be really careful saving the upper 32 bits * of any * register across function calls if we don't want them @@ -423,13 +451,9 @@ asmlinkage void plat_irq_dispatch(void) pending = read_c0_cause() & read_c0_status() & ST0_IM; -#ifdef CONFIG_SIBYTE_SB1250_PROF - if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */ - sbprof_cpu_intr(); - else -#endif - - if (pending & CAUSEF_IP4) + if (pending & CAUSEF_IP7) /* CPU performance counter interrupt */ + do_IRQ(MIPS_CPU_IRQ_BASE + 7); + else if (pending & CAUSEF_IP4) sb1250_timer_interrupt(); #ifdef CONFIG_SMP diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 5bb83cd4c113..eb177075e9c0 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -116,18 +116,6 @@ void sb1250_time_init(void) */ } -void sb1250_timer_interrupt(void) -{ - int cpu = smp_processor_id(); - int irq = K_INT_TIMER_0 + cpu; - - /* ACK interrupt */ - ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - - ll_timer_interrupt(irq); -} - /* * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over * again. diff --git a/include/asm-mips/mach-ip27/irq.h b/include/asm-mips/mach-ip27/irq.h index 25f0c3f39adf..cf4384bfa846 100644 --- a/include/asm-mips/mach-ip27/irq.h +++ b/include/asm-mips/mach-ip27/irq.h @@ -17,4 +17,6 @@ */ #define NR_IRQS 256 +#include_next + #endif /* __ASM_MACH_IP27_IRQ_H */ diff --git a/include/asm-mips/qemu.h b/include/asm-mips/qemu.h index 531caf44560c..487ced4a40de 100644 --- a/include/asm-mips/qemu.h +++ b/include/asm-mips/qemu.h @@ -12,7 +12,7 @@ * Interrupt numbers */ #define Q_PIC_IRQ_BASE 0 -#define Q_COUNT_COMPARE_IRQ 16 +#define Q_COUNT_COMPARE_IRQ 23 /* * Qemu clock rate. Unlike on real MIPS this has no relation to the diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 3516b32c9efb..35555bd5c52d 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -48,11 +48,6 @@ extern void (*mips_timer_ack)(void); */ extern struct clocksource clocksource_mips; -/* - * The low-level timer interrupt routine. - */ -extern void ll_timer_interrupt(int irq, void *dev_id); - /* * profiling and process accouting is done separately in local_timer_interrupt */ @@ -78,4 +73,9 @@ extern unsigned int mips_hpt_frequency; */ extern int (*perf_irq)(void); +/* + * Initialize the calling CPU's compare interrupt as clockevent device + */ +extern void mips_clockevent_init(void); + #endif /* _ASM_TIME_H */ From ea5804015c0ce67741eb4b156a071fb4f415345f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:09 +0100 Subject: [PATCH 2245/2804] [MIPS] Dyntick support for SMTC: The kernel currently only supports broadcasting of the timer interrupt from a single timer, not multicasting into two multicast groups of processors. So the implemented mechanism for SMTC works by broadcasting the cp0 compare interrupt on VPE 0 and ignoring it on any additional VPEs. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 + arch/mips/kernel/smtc.c | 67 ++++++++-------- arch/mips/kernel/time.c | 111 +++++++++++++++++++++++---- arch/mips/mips-boards/generic/time.c | 1 - 4 files changed, 134 insertions(+), 49 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ecce3aab1981..d8c905840af5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1368,6 +1368,7 @@ config MIPS_MT_SMTC depends on CPU_MIPS32_R2 #depends on CPU_MIPS64_R2 # once there is hardware ... depends on SYS_SUPPORTS_MULTITHREADING + select GENERIC_CLOCKEVENTS_BROADCAST select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select CPU_MIPSR2_SRS @@ -1537,6 +1538,9 @@ config CPU_HAS_SYNC depends on !CPU_R3000 default y +config GENERIC_CLOCKEVENTS_BROADCAST + bool + # # Use the generic interrupt handling code in kernel/irq/: # diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 137183bba54f..4d1ac9692dcd 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -1,5 +1,6 @@ /* Copyright (C) 2004 Mips Technologies, Inc */ +#include #include #include #include @@ -62,7 +63,7 @@ asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; * Clock interrupt "latch" buffers, per "CPU" */ -unsigned int ipi_timer_latch[NR_CPUS]; +static atomic_t ipi_timer_latch[NR_CPUS]; /* * Number of InterProcessor Interupt (IPI) message buffers to allocate @@ -296,8 +297,10 @@ int __init mipsmt_build_cpu_map(int start_cpu_slot) __cpu_number_map[i] = i; __cpu_logical_map[i] = i; } +#ifdef CONFIG_MIPS_MT_FPAFF /* Initialize map of CPUs with FPUs */ cpus_clear(mt_fpu_cpumask); +#endif /* One of those TC's is the one booting, and not a secondary... */ printk("%i available secondary CPU TC(s)\n", i - 1); @@ -359,7 +362,7 @@ void mipsmt_prepare_cpus(void) IPIQ[i].head = IPIQ[i].tail = NULL; spin_lock_init(&IPIQ[i].lock); IPIQ[i].depth = 0; - ipi_timer_latch[i] = 0; + atomic_set(&ipi_timer_latch[i], 0); } /* cpu_data index starts at zero */ @@ -482,10 +485,12 @@ void mipsmt_prepare_cpus(void) /* Set up coprocessor affinity CPU mask(s) */ +#ifdef CONFIG_MIPS_MT_FPAFF for (tc = 0; tc < ntc; tc++) { if (cpu_data[tc].options & MIPS_CPU_FPU) cpu_set(tc, mt_fpu_cpumask); } +#endif /* set up ipi interrupts... */ @@ -702,7 +707,7 @@ static void smtc_ipi_qdump(void) * be done with the atomic.h primitives). And since this is * MIPS MT, we can assume that we have LL/SC. */ -static __inline__ int atomic_postincrement(unsigned int *pv) +static inline int atomic_postincrement(atomic_t *v) { unsigned long result; @@ -714,8 +719,8 @@ static __inline__ int atomic_postincrement(unsigned int *pv) " sc %1, %2 \n" " beqz %1, 1b \n" __WEAK_LLSC_MB - : "=&r" (result), "=&r" (temp), "=m" (*pv) - : "m" (*pv) + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "m" (v->counter) : "memory"); return result; @@ -743,6 +748,8 @@ void smtc_send_ipi(int cpu, int type, unsigned int action) pipi->arg = (void *)action; pipi->dest = cpu; if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) { + if (type == SMTC_CLOCK_TICK) + atomic_inc(&ipi_timer_latch[cpu]); /* If not on same VPE, enqueue and send cross-VPE interupt */ smtc_ipi_nq(&IPIQ[cpu], pipi); LOCK_CORE_PRA(); @@ -784,6 +791,8 @@ void smtc_send_ipi(int cpu, int type, unsigned int action) } smtc_ipi_nq(&IPIQ[cpu], pipi); } else { + if (type == SMTC_CLOCK_TICK) + atomic_inc(&ipi_timer_latch[cpu]); post_direct_ipi(cpu, pipi); write_tc_c0_tchalt(0); UNLOCK_CORE_PRA(); @@ -801,6 +810,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) unsigned long tcrestart; extern u32 kernelsp[NR_CPUS]; extern void __smtc_ipi_vector(void); +//printk("%s: on %d for %d\n", __func__, smp_processor_id(), cpu); /* Extract Status, EPC from halted TC */ tcstatus = read_tc_c0_tcstatus(); @@ -851,25 +861,31 @@ static void ipi_call_interrupt(void) smp_call_function_interrupt(); } +DECLARE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); + void ipi_decode(struct smtc_ipi *pipi) { + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd; void *arg_copy = pipi->arg; int type_copy = pipi->type; - int dest_copy = pipi->dest; + int ticks; smtc_ipi_nq(&freeIPIq, pipi); switch (type_copy) { case SMTC_CLOCK_TICK: irq_enter(); - kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + cp0_compare_irq]++; - /* Invoke Clock "Interrupt" */ - ipi_timer_latch[dest_copy] = 0; -#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG - clock_hang_reported[dest_copy] = 0; -#endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ - local_timer_interrupt(0, NULL); + kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + 1]++; + cd = &per_cpu(smtc_dummy_clockevent_device, cpu); + ticks = atomic_read(&ipi_timer_latch[cpu]); + atomic_sub(ticks, &ipi_timer_latch[cpu]); + while (ticks) { + cd->event_handler(cd); + ticks--; + } irq_exit(); break; + case LINUX_SMP_IPI: switch ((int)arg_copy) { case SMP_RESCHEDULE_YOURSELF: @@ -920,25 +936,6 @@ void deferred_smtc_ipi(void) } } -/* - * Send clock tick to all TCs except the one executing the funtion - */ - -void smtc_timer_broadcast(void) -{ - int cpu; - int myTC = cpu_data[smp_processor_id()].tc_id; - int myVPE = cpu_data[smp_processor_id()].vpe_id; - - smtc_cpu_stats[smp_processor_id()].timerints++; - - for_each_online_cpu(cpu) { - if (cpu_data[cpu].vpe_id == myVPE && - cpu_data[cpu].tc_id != myTC) - smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); - } -} - /* * Cross-VPE interrupts in the SMTC prototype use "software interrupts" * set via cross-VPE MTTR manipulation of the Cause register. It would be @@ -1180,11 +1177,11 @@ void smtc_idle_loop_hook(void) for (tc = 0; tc < NR_CPUS; tc++) { /* Don't check ourself - we'll dequeue IPIs just below */ if ((tc != smp_processor_id()) && - ipi_timer_latch[tc] > timerq_limit) { + atomic_read(&ipi_timer_latch[tc]) > timerq_limit) { if (clock_hang_reported[tc] == 0) { pdb_msg += sprintf(pdb_msg, "TC %d looks hung with timer latch at %d\n", - tc, ipi_timer_latch[tc]); + tc, atomic_read(&ipi_timer_latch[tc])); clock_hang_reported[tc]++; } } @@ -1225,7 +1222,7 @@ void smtc_soft_dump(void) smtc_ipi_qdump(); printk("Timer IPI Backlogs:\n"); for (i=0; i < NR_CPUS; i++) { - printk("%d: %d\n", i, ipi_timer_latch[i]); + printk("%d: %d\n", i, atomic_read(&ipi_timer_latch[i])); } printk("%d Recoveries of \"stolen\" FPU\n", atomic_read(&smtc_fpu_recoveries)); diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 35988847c98a..369a5f9ad268 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include @@ -230,12 +232,24 @@ static int mips_next_event(unsigned long delta, struct clock_event_device *evt) { unsigned int cnt; + int res; +#ifdef CONFIG_MIPS_MT_SMTC + { + unsigned long flags, vpflags; + local_irq_save(flags); + vpflags = dvpe(); +#endif cnt = read_c0_count(); cnt += delta; write_c0_compare(cnt); - - return ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; + res = ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; +#ifdef CONFIG_MIPS_MT_SMTC + evpe(vpflags); + local_irq_restore(flags); + } +#endif + return res; } static void mips_set_mode(enum clock_event_mode mode, @@ -244,9 +258,7 @@ static void mips_set_mode(enum clock_event_mode mode, /* Nothing to do ... */ } -struct clock_event_device mips_clockevent; - -static struct clock_event_device *global_cd[NR_CPUS]; +static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); static int cp0_timer_irq_installed; static irqreturn_t timer_interrupt(int irq, void *dev_id) @@ -271,7 +283,12 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) */ if (!r2 || (read_c0_cause() & (1 << 30))) { c0_timer_ack(); - cd = global_cd[cpu]; +#ifdef CONFIG_MIPS_MT_SMTC + if (cpu_data[cpu].vpe_id) + goto out; + cpu = 0; +#endif + cd = &per_cpu(mips_clockevent_device, cpu); cd->event_handler(cd); } @@ -281,7 +298,11 @@ out: static struct irqaction timer_irqaction = { .handler = timer_interrupt, +#ifdef CONFIG_MIPS_MT_SMTC + .flags = IRQF_DISABLED, +#else .flags = IRQF_DISABLED | IRQF_PERCPU, +#endif .name = "timer", }; @@ -316,6 +337,60 @@ void __init __weak plat_timer_setup(struct irqaction *irq) { } +#ifdef CONFIG_MIPS_MT_SMTC +DEFINE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); + +static void smtc_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ +} + +int dummycnt[NR_CPUS]; + +static void mips_broadcast(cpumask_t mask) +{ + unsigned int cpu; + + for_each_cpu_mask(cpu, mask) + smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); +} + +static void setup_smtc_dummy_clockevent_device(void) +{ + //uint64_t mips_freq = mips_hpt_^frequency; + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd; + + cd = &per_cpu(smtc_dummy_clockevent_device, cpu); + + cd->name = "SMTC"; + cd->features = CLOCK_EVT_FEAT_DUMMY; + + /* Calculate the min / max delta */ + cd->mult = 0; //div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); + cd->shift = 0; //32; + cd->max_delta_ns = 0; //clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = 0; //clockevent_delta2ns(0x30, cd); + + cd->rating = 200; + cd->irq = 17; //-1; +// if (cpu) +// cd->cpumask = CPU_MASK_ALL; // cpumask_of_cpu(cpu); +// else + cd->cpumask = cpumask_of_cpu(cpu); + + cd->set_mode = smtc_set_mode; + + cd->broadcast = mips_broadcast; + + clockevents_register_device(cd); +} +#endif + +static void mips_event_handler(struct clock_event_device *dev) +{ +} + void __cpuinit mips_clockevent_init(void) { uint64_t mips_freq = mips_hpt_frequency; @@ -326,12 +401,18 @@ void __cpuinit mips_clockevent_init(void) if (!cpu_has_counter) return; - if (cpu == 0) - cd = &mips_clockevent; - else - cd = kzalloc(sizeof(*cd), GFP_ATOMIC); - if (!cd) - return; /* We're probably roadkill ... */ +#ifdef CONFIG_MIPS_MT_SMTC + setup_smtc_dummy_clockevent_device(); + + /* + * On SMTC we only register VPE0's compare interrupt as clockevent + * device. + */ + if (cpu) + return; +#endif + + cd = &per_cpu(mips_clockevent_device, cpu); cd->name = "MIPS"; cd->features = CLOCK_EVT_FEAT_ONESHOT; @@ -344,11 +425,15 @@ void __cpuinit mips_clockevent_init(void) cd->rating = 300; cd->irq = irq; +#ifdef CONFIG_MIPS_MT_SMTC + cd->cpumask = CPU_MASK_ALL; +#else cd->cpumask = cpumask_of_cpu(cpu); +#endif cd->set_next_event = mips_next_event; cd->set_mode = mips_set_mode; + cd->event_handler = mips_event_handler; - global_cd[cpu] = cd; clockevents_register_device(cd); if (!cp0_timer_irq_installed) { diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 2c8db3e0f4b7..cf55ecd96bf4 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -55,7 +55,6 @@ unsigned long cpu_khz; static int mips_cpu_timer_irq; extern int cp0_perfcount_irq; -extern void smtc_timer_broadcast(void); static void mips_timer_dispatch(void) { From 584d98be3b90f00b410288e59eeba871fbf81b86 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:09 +0100 Subject: [PATCH 2246/2804] [MIPS] Jazz clockevent driver Signed-off-by: Ralf Baechle --- arch/mips/jazz/irq.c | 48 ++++++++++++++++++++++++++++++++++++++++++ arch/mips/jazz/setup.c | 7 ------ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index 56235412cbb7..835b056cea36 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -6,6 +6,7 @@ * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994 - 2001, 2003 Ralf Baechle */ +#include #include #include #include @@ -105,3 +106,50 @@ asmlinkage void plat_irq_dispatch(void) panic("Unimplemented loc_no_irq handler"); } } + +static void r4030_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + /* Nothing to do ... */ +} + +struct clock_event_device r4030_clockevent = { + .name = "r4030", + .features = CLOCK_EVT_FEAT_PERIODIC, + .rating = 100, + .irq = JAZZ_TIMER_IRQ, + .cpumask = CPU_MASK_CPU0, + .set_mode = r4030_set_mode, +}; + +static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) +{ + r4030_clockevent.event_handler(&r4030_clockevent); + + return IRQ_HANDLED; +} + +static struct irqaction r4030_timer_irqaction = { + .handler = r4030_timer_interrupt, + .flags = IRQF_DISABLED, + .mask = CPU_MASK_CPU0, + .name = "timer", +}; + +void __init plat_timer_setup(struct irqaction *ignored) +{ + struct irqaction *irq = &r4030_timer_irqaction; + + BUG_ON(HZ != 100); + + /* + * Set clock to 100Hz. + * + * The R4030 timer receives an input clock of 1kHz which is divieded by + * a programmable 4-bit divider. This makes it fairly inflexible. + */ + r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); + setup_irq(JAZZ_TIMER_IRQ, irq); + + clockevents_register_device(&r4030_clockevent); +} diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 5c6271ab927f..fa890df36589 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -39,13 +39,6 @@ extern asmlinkage void jazz_handle_int(void); extern void jazz_machine_restart(char *command); -void __init plat_timer_setup(struct irqaction *irq) -{ - /* set the clock to 100 Hz */ - r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); - setup_irq(JAZZ_TIMER_IRQ, irq); -} - static struct resource jazz_io_resources[] = { { .start = 0x00, From 87b2335d6ef97e19ca19dbbb523673680a029e3f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:10 +0100 Subject: [PATCH 2247/2804] [MIPS] IP27: Add clocksource drivers Signed-off-by: Ralf Baechle --- arch/mips/sgi-ip27/ip27-timer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 9c1700e85be0..b7b3479b6bce 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -200,15 +200,23 @@ void __init plat_timer_setup(struct irqaction *irq) setup_irq(irqno, &rt_irqaction); } -static cycle_t ip27_hpt_read(void) +static cycle_t hub_rt_read(void) { return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); } +struct clocksource ht_rt_clocksource = { + .name = "HUB", + .rating = 200, + .read = hub_rt_read, + .mask = CLOCKSOURCE_MASK(52), + .shift = 32, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + void __init plat_time_init(void) { - clocksource_mips.read = ip27_hpt_read; - mips_hpt_frequency = CYCLES_PER_SEC; + clocksource_register(&ht_rt_clocksource); } void __init cpu_time_init(void) From d865bea4dace1d42995a6cf552bc4863842623f4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:10 +0100 Subject: [PATCH 2248/2804] [MIPS] i8253 PIT clocksource and clockevent drivers Derived from the i386 variant with a few x86 complexities chopped off. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 9 ++ arch/mips/cobalt/setup.c | 6 + arch/mips/jazz/setup.c | 6 + arch/mips/kernel/Makefile | 1 + arch/mips/kernel/i8253.c | 213 +++++++++++++++++++++++++++ arch/mips/mips-boards/generic/time.c | 4 + arch/mips/qemu/q-setup.c | 9 +- arch/mips/sgi-ip22/ip22-time.c | 4 + arch/mips/sni/time.c | 3 + include/asm-mips/i8253.h | 30 ++++ 10 files changed, 280 insertions(+), 5 deletions(-) create mode 100644 arch/mips/kernel/i8253.c create mode 100644 include/asm-mips/i8253.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index d8c905840af5..f943736541cb 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -65,6 +65,7 @@ config MIPS_COBALT bool "Cobalt Server" select DMA_NONCOHERENT select HW_HAS_PCI + select I8253 select I8259 select IRQ_CPU select IRQ_GT641XX @@ -112,6 +113,7 @@ config MACH_JAZZ select ARCH_MAY_HAVE_PC_FDC select GENERIC_ISA_DMA select IRQ_CPU + select I8253 select I8259 select ISA select PCSPEAKER @@ -201,6 +203,7 @@ config MIPS_MALTA select GENERIC_ISA_DMA select IRQ_CPU select HW_HAS_PCI + select I8253 select I8259 select MIPS_BOARDS_GEN select MIPS_BONITO64 @@ -334,6 +337,7 @@ config QEMU select DMA_COHERENT select GENERIC_ISA_DMA select HAVE_STD_PC_SERIAL_PORT + select I8253 select I8259 select IRQ_CPU select ISA @@ -362,6 +366,7 @@ config SGI_IP22 select BOOT_ELF32 select DMA_NONCOHERENT select HW_HAS_EISA + select I8253 select IP22_CPU_SCACHE select IRQ_CPU select GENERIC_ISA_DMA_SUPPORT_BROKEN @@ -534,6 +539,7 @@ config SNI_RM select HW_HAS_EISA select HW_HAS_PCI select IRQ_CPU + select I8253 select I8259 select ISA select PCSPEAKER @@ -1893,6 +1899,9 @@ config MMU bool default y +config I8253 + bool + config PCSPEAKER bool diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index 5d2e8790b28b..345e4ae998df 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -84,6 +85,11 @@ static struct resource cobalt_reserved_resources[] = { }, }; +void __init plat_time_init(void) +{ + setup_pit_timer(); +} + void __init plat_mem_setup(void) { int i; diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index fa890df36589..2a7ec08b6bad 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -63,6 +64,11 @@ static struct resource jazz_io_resources[] = { } }; +void __init plat_time_init(void) +{ + setup_pit_timer(); +} + void __init plat_mem_setup(void) { int i; diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 7851b4b447d0..a2689f93c160 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_64BIT) += cpu-bugs64.o +obj-$(CONFIG_I8253) += i8253.o obj-$(CONFIG_PCSPEAKER) += pcspeaker.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c new file mode 100644 index 000000000000..5d9830df3595 --- /dev/null +++ b/arch/mips/kernel/i8253.c @@ -0,0 +1,213 @@ +/* + * i8253.c 8253/PIT functions + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static DEFINE_SPINLOCK(i8253_lock); + +/* + * Initialize the PIT timer. + * + * This is also called after resume to bring the PIT into operation again. + */ +static void init_pit_timer(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long flags; + + spin_lock_irqsave(&i8253_lock, flags); + + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(0x34, PIT_MODE); + outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ + outb(LATCH >> 8 , PIT_CH0); /* MSB */ + break; + + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + if (evt->mode == CLOCK_EVT_MODE_PERIODIC || + evt->mode == CLOCK_EVT_MODE_ONESHOT) { + outb_p(0x30, PIT_MODE); + outb_p(0, PIT_CH0); + outb_p(0, PIT_CH0); + } + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* One shot setup */ + outb_p(0x38, PIT_MODE); + break; + + case CLOCK_EVT_MODE_RESUME: + /* Nothing to do here */ + break; + } + spin_unlock_irqrestore(&i8253_lock, flags); +} + +/* + * Program the next event in oneshot mode + * + * Delta is given in PIT ticks + */ +static int pit_next_event(unsigned long delta, struct clock_event_device *evt) +{ + unsigned long flags; + + spin_lock_irqsave(&i8253_lock, flags); + outb_p(delta & 0xff , PIT_CH0); /* LSB */ + outb(delta >> 8 , PIT_CH0); /* MSB */ + spin_unlock_irqrestore(&i8253_lock, flags); + + return 0; +} + +/* + * On UP the PIT can serve all of the possible timer functions. On SMP systems + * it can be solely used for the global tick. + * + * The profiling and update capabilites are switched off once the local apic is + * registered. This mechanism replaces the previous #ifdef LOCAL_APIC - + * !using_apic_timer decisions in do_timer_interrupt_hook() + */ +struct clock_event_device pit_clockevent = { + .name = "pit", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = init_pit_timer, + .set_next_event = pit_next_event, + .shift = 32, + .irq = 0, +}; + +irqreturn_t timer_interrupt(int irq, void *dev_id) +{ + pit_clockevent.event_handler(&pit_clockevent); + + return IRQ_HANDLED; +} + +static struct irqaction irq0 = { + .handler = timer_interrupt, + .flags = IRQF_DISABLED | IRQF_NOBALANCING, + .mask = CPU_MASK_NONE, + .name = "timer" +}; + +/* + * Initialize the conversion factor and the min/max deltas of the clock event + * structure and register the clock event source with the framework. + */ +void __init setup_pit_timer(void) +{ + /* + * Start pit with the boot cpu mask and make it global after the + * IO_APIC has been initialized. + */ + pit_clockevent.cpumask = cpumask_of_cpu(0); + pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32); + pit_clockevent.max_delta_ns = + clockevent_delta2ns(0x7FFF, &pit_clockevent); + pit_clockevent.min_delta_ns = + clockevent_delta2ns(0xF, &pit_clockevent); + clockevents_register_device(&pit_clockevent); + + irq0.mask = cpumask_of_cpu(0); + setup_irq(0, &irq0); +} + +/* + * Since the PIT overflows every tick, its not very useful + * to just read by itself. So use jiffies to emulate a free + * running counter: + */ +static cycle_t pit_read(void) +{ + unsigned long flags; + int count; + u32 jifs; + static int old_count; + static u32 old_jifs; + + spin_lock_irqsave(&i8253_lock, flags); + /* + * Although our caller may have the read side of xtime_lock, + * this is now a seqlock, and we are cheating in this routine + * by having side effects on state that we cannot undo if + * there is a collision on the seqlock and our caller has to + * retry. (Namely, old_jifs and old_count.) So we must treat + * jiffies as volatile despite the lock. We read jiffies + * before latching the timer count to guarantee that although + * the jiffies value might be older than the count (that is, + * the counter may underflow between the last point where + * jiffies was incremented and the point where we latch the + * count), it cannot be newer. + */ + jifs = jiffies; + outb_p(0x00, PIT_MODE); /* latch the count ASAP */ + count = inb_p(PIT_CH0); /* read the latched count */ + count |= inb_p(PIT_CH0) << 8; + + /* VIA686a test code... reset the latch if count > max + 1 */ + if (count > LATCH) { + outb_p(0x34, PIT_MODE); + outb_p(LATCH & 0xff, PIT_CH0); + outb(LATCH >> 8, PIT_CH0); + count = LATCH - 1; + } + + /* + * It's possible for count to appear to go the wrong way for a + * couple of reasons: + * + * 1. The timer counter underflows, but we haven't handled the + * resulting interrupt and incremented jiffies yet. + * 2. Hardware problem with the timer, not giving us continuous time, + * the counter does small "jumps" upwards on some Pentium systems, + * (see c't 95/10 page 335 for Neptun bug.) + * + * Previous attempts to handle these cases intelligently were + * buggy, so we just do the simple thing now. + */ + if (count > old_count && jifs == old_jifs) { + count = old_count; + } + old_count = count; + old_jifs = jifs; + + spin_unlock_irqrestore(&i8253_lock, flags); + + count = (LATCH - 1) - count; + + return (cycle_t)(jifs * LATCH) + count; +} + +static struct clocksource clocksource_pit = { + .name = "pit", + .rating = 110, + .read = pit_read, + .mask = CLOCKSOURCE_MASK(32), + .mult = 0, + .shift = 20, +}; + +static int __init init_pit_clocksource(void) +{ + if (num_possible_cpus() > 1) /* PIT does not scale! */ + return 0; + + clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); + return clocksource_register(&clocksource_pit); +} +arch_initcall(init_pit_clocksource); diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index cf55ecd96bf4..4fab3b2e8736 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -141,6 +142,9 @@ void __init plat_time_init(void) cpu_khz = est_freq / 1000; mips_scroll_message(); +#ifdef CONFIG_I8253 /* Only Malta has a PIT */ + setup_pit_timer(); +#endif } //static irqreturn_t mips_perf_interrupt(int irq, void *dev_id) diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c index 89a207650ce9..23d34c1917c0 100644 --- a/arch/mips/qemu/q-setup.c +++ b/arch/mips/qemu/q-setup.c @@ -1,4 +1,6 @@ #include + +#include #include #include @@ -11,12 +13,9 @@ const char *get_system_type(void) return "Qemu"; } -void __init plat_timer_setup(struct irqaction *irq) +void __init plat_time_init(void) { - /* set the clock to 100 Hz */ - outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - outb_p(LATCH & 0xff , 0x40); /* LSB */ - outb(LATCH >> 8 , 0x40); /* MSB */ + setup_pit_timer(); } void __init plat_mem_setup(void) diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index a1df1f9e26fa..9b9bffd2e8fb 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -172,6 +173,9 @@ __init void plat_time_init(void) (int) (r4k_tick % (500000 / HZ))); mips_hpt_frequency = r4k_tick * HZ; + + if (ip22_is_fullhouse()) + setup_pit_timer(); } /* Generic SGI handler for (spurious) 8254 interrupts */ diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index 92452d677d8f..153f065434ea 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -116,6 +117,8 @@ void __init plat_time_init(void) (int) (r4k_tick % (500000 / HZ))); mips_hpt_frequency = r4k_tick * HZ; + + setup_pit_timer(); } /* diff --git a/include/asm-mips/i8253.h b/include/asm-mips/i8253.h new file mode 100644 index 000000000000..8f689d7df6b1 --- /dev/null +++ b/include/asm-mips/i8253.h @@ -0,0 +1,30 @@ +/* + * Machine specific IO port address definition for generic. + * Written by Osamu Tomita + */ +#ifndef _MACH_IO_PORTS_H +#define _MACH_IO_PORTS_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 +#define PIT_CH2 0x42 + +/* i8259A PIC registers */ +#define PIC_MASTER_CMD 0x20 +#define PIC_MASTER_IMR 0x21 +#define PIC_MASTER_ISR PIC_MASTER_CMD +#define PIC_MASTER_POLL PIC_MASTER_ISR +#define PIC_MASTER_OCW3 PIC_MASTER_ISR +#define PIC_SLAVE_CMD 0xa0 +#define PIC_SLAVE_IMR 0xa1 + +/* i8259A PIC related value */ +#define PIC_CASCADE_IR 2 +#define MASTER_ICW4_DEFAULT 0x01 +#define SLAVE_ICW4_DEFAULT 0x01 +#define PIC_ICW4_AEOI 2 + +extern void setup_pit_timer(void); + +#endif /* !_MACH_IO_PORTS_H */ From 9b9ea2202f3396790f635c62f7498ad75f08f62c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:10 +0100 Subject: [PATCH 2249/2804] [MIPS] Clockevent driver for BCM1250 Signed-off-by: Ralf Baechle --- arch/mips/sibyte/sb1250/time.c | 183 +++++++++++++++++++++++++++++---- 1 file changed, 161 insertions(+), 22 deletions(-) diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index eb177075e9c0..38199ad8fc54 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -25,6 +25,7 @@ * code to do general bookkeeping (e.g. update jiffies, run * bottom halves, etc.) */ +#include #include #include #include @@ -71,16 +72,158 @@ void __init sb1250_hpt_setup(void) } } - -void sb1250_time_init(void) +/* + * The general purpose timer ticks at 1 Mhz independent if + * the rest of the system + */ +static void sibyte_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) { - int cpu = smp_processor_id(); - int irq = K_INT_TIMER_0+cpu; + unsigned int cpu = smp_processor_id(); + void __iomem *timer_cfg, *timer_init; + + timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + __raw_writeq(0, timer_cfg); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + timer_cfg); + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* Stop the timer until we actually program a shot */ + case CLOCK_EVT_MODE_SHUTDOWN: + __raw_writeq(0, timer_cfg); + break; + + case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ + ; + } +} + +static int +sibyte_next_event(unsigned long delta, struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *timer_cfg, *timer_init; + + timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + __raw_writeq(0, timer_cfg); + __raw_writeq(delta, timer_init); + __raw_writeq(M_SCD_TIMER_ENABLE, timer_cfg); + + return 0; +} + +struct clock_event_device sibyte_hpt_clockevent = { + .name = "sb1250-counter", + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_mode = sibyte_set_mode, + .set_next_event = sibyte_next_event, + .shift = 32, + .irq = 0, +}; + +static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) +{ + struct clock_event_device *cd = &sibyte_hpt_clockevent; + + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static struct irqaction sibyte_irqaction = { + .handler = sibyte_counter_handler, + .flags = IRQF_DISABLED | IRQF_PERCPU, + .name = "timer", +}; + +/* + * The general purpose timer ticks at 1 Mhz independent if + * the rest of the system + */ +static void sibyte_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *timer_cfg, *timer_init; + + timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + __raw_writeq(0, timer_cfg); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + timer_cfg); + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* Stop the timer until we actually program a shot */ + case CLOCK_EVT_MODE_SHUTDOWN: + __raw_writeq(0, timer_cfg); + break; + + case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ + ; + } +} + +static int +sibyte_next_event(unsigned long delta, struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *timer_cfg, *timer_init; + + timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + __raw_writeq(0, timer_cfg); + __raw_writeq(delta, timer_init); + __raw_writeq(M_SCD_TIMER_ENABLE, timer_cfg); + + return 0; +} + +struct clock_event_device sibyte_hpt_clockevent = { + .name = "sb1250-counter", + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_mode = sibyte_set_mode, + .set_next_event = sibyte_next_event, + .shift = 32, + .irq = 0, +}; + +static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) +{ + struct clock_event_device *cd = &sibyte_hpt_clockevent; + + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static struct irqaction sibyte_irqaction = { + .handler = sibyte_counter_handler, + .flags = IRQF_DISABLED | IRQF_PERCPU, + .name = "timer", +}; + +static void __init sb1250_clockevent_init(void) +{ + struct clock_event_device *cd = &sibyte_hpt_clockevent; + unsigned int cpu = smp_processor_id(); + int irq = K_INT_TIMER_0 + cpu; /* Only have 4 general purpose timers, and we use last one as hpt */ - if (cpu > 2) { - BUG(); - } + BUG_ON(cpu > 2); sb1250_mask_irq(cpu, irq); @@ -88,24 +231,11 @@ void sb1250_time_init(void) __raw_writeq(IMR_IP4_VAL, IOADDR(A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) + (irq << 3))); - - /* the general purpose timer ticks at 1 Mhz independent if the rest of the system */ - /* Disable the timer and set up the count */ - __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); -#ifdef CONFIG_SIMULATION - __raw_writeq((50000 / HZ) - 1, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT))); -#else - __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT))); -#endif - - /* Set the timer running */ - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); + cd->cpumask = cpumask_of_cpu(0); sb1250_unmask_irq(cpu, irq); sb1250_steal_irq(irq); + /* * This interrupt is "special" in that it doesn't use the request_irq * way to hook the irq line. The timer interrupt is initialized early @@ -114,6 +244,15 @@ void sb1250_time_init(void) * called directly from irq_handler.S when IP[4] is set during an * interrupt */ + setup_irq(irq, &sibyte_irqaction); + + clockevents_register_device(cd); +} + +void __init plat_time_init(void) +{ + sb1250_clocksource_init(); + sb1250_clockevent_init(); } /* From e9f874b6f761f7f8394157d28641491c9babc1d3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:10 +0100 Subject: [PATCH 2250/2804] [MIPS] Clockevent driver for BCM1480 Signed-off-by: Ralf Baechle --- arch/mips/sibyte/bcm1480/time.c | 107 ++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 26 deletions(-) diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index 8519091d848b..40d7126cd5bf 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -25,6 +25,7 @@ * code to do general bookkeeping (e.g. update jiffies, run * bottom halves, etc.) */ +#include #include #include #include @@ -55,15 +56,12 @@ extern int bcm1480_steal_irq(int irq); -void bcm1480_time_init(void) +void __init plat_time_init(void) { - int cpu = smp_processor_id(); - int irq = K_BCM1480_INT_TIMER_0+cpu; + unsigned int cpu = smp_processor_id(); + unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; - /* Only have 4 general purpose timers */ - if (cpu > 3) { - BUG(); - } + BUG_ON(cpu > 3); /* Only have 4 general purpose timers */ bcm1480_mask_irq(cpu, irq); @@ -71,27 +69,83 @@ void bcm1480_time_init(void) __raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (irq<<3))); - /* the general purpose timer ticks at 1 Mhz independent of the rest of the system */ - /* Disable the timer and set up the count */ - __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - __raw_writeq( - BCM1480_HPT_VALUE/HZ - , IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT))); - - /* Set the timer running */ - __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - bcm1480_unmask_irq(cpu, irq); bcm1480_steal_irq(irq); - /* - * This interrupt is "special" in that it doesn't use the request_irq - * way to hook the irq line. The timer interrupt is initialized early - * enough to make this a major pain, and it's also firing enough to - * warrant a bit of special case code. bcm1480_timer_interrupt is - * called directly from irq_handler.S when IP[4] is set during an - * interrupt - */ +} + +/* + * The general purpose timer ticks at 1 Mhz independent if + * the rest of the system + */ +static void sibyte_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *timer_cfg, *timer_init; + + timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + __raw_writeq(0, timer_cfg); + __raw_writeq(BCM1480_HPT_VALUE / HZ - 1, timer_init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + timer_cfg); + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* Stop the timer until we actually program a shot */ + case CLOCK_EVT_MODE_SHUTDOWN: + __raw_writeq(0, timer_cfg); + break; + + case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ + ; + } +} + +struct clock_event_device sibyte_hpt_clockevent = { + .name = "bcm1480-counter", + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_mode = sibyte_set_mode, + .shift = 32, + .irq = 0, +}; + +static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) +{ + struct clock_event_device *cd = &sibyte_hpt_clockevent; + unsigned int cpu = smp_processor_id(); + + /* Reset the timer */ + __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, + IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static struct irqaction sibyte_counter_irqaction = { + .handler = sibyte_counter_handler, + .flags = IRQF_DISABLED | IRQF_PERCPU, + .name = "timer", +}; + +/* + * This interrupt is "special" in that it doesn't use the request_irq + * way to hook the irq line. The timer interrupt is initialized early + * enough to make this a major pain, and it's also firing enough to + * warrant a bit of special case code. bcm1480_timer_interrupt is + * called directly from irq_handler.S when IP[4] is set during an + * interrupt + */ +static void __init sb1480_clockevent_init(void) +{ + unsigned int cpu = smp_processor_id(); + unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; + + setup_irq(irq, &sibyte_counter_irqaction); } void bcm1480_timer_interrupt(void) @@ -118,4 +172,5 @@ void __init bcm1480_hpt_setup(void) { clocksource_mips.read = bcm1480_hpt_read; mips_hpt_frequency = BCM1480_HPT_VALUE; + sb1480_clockevent_init(); } From e58d95abb7b3232333ab35a09f7f5b0cd6a19cdb Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 27 Sep 2007 16:26:40 +0200 Subject: [PATCH 2251/2804] [MIPS] Don't abort the build process if '-msym32' isn't supported -msym32 and previously the strategy to tell the compiler to generate 64-bit code but the assembler to put it into 32-bit ELF was initially a hack to get around the lack of proper 64-bit binutils support and later turned into a neat optimization with significant code size savings. But it's really just an optimization so there is nothing wrong with just dropping the option (and whatever else goes along with it, I forgot all the nasty details) on the floor if due to a vintage compiler it can't be suported. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index b0fac2d436b7..ebd5d02a7d78 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -602,7 +602,9 @@ ifdef CONFIG_64BIT endif ifeq ($(KBUILD_SYM32), y) - cflags-y += -msym32 -DKBUILD_64BIT_SYM32 + ifeq ($(call cc-option-yn,-msym32), y) + cflags-y += -msym32 -DKBUILD_64BIT_SYM32 + endif endif endif From db813fe5a77d03b29e872da47463d2efbddc3fc2 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 27 Sep 2007 18:26:43 +0100 Subject: [PATCH 2252/2804] [MIPS] Avoid indexed cacheops. On MP configurations it's highly dubious what this code will actually affect since blasting away cachelines may or may not do the right thing wrt. cache coherency. Signed-off-by: Ralf Baechle --- arch/mips/mm/c-r4k.c | 74 +++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 46 deletions(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 738b89803a44..cf48371e5690 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -8,6 +8,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include +#include #include #include #include @@ -318,23 +319,6 @@ static void __init r4k_blast_scache_setup(void) r4k_blast_scache = blast_scache128; } -/* - * This is former mm's flush_cache_all() which really should be - * flush_cache_vunmap these days ... - */ -static inline void local_r4k_flush_cache_all(void * args) -{ - r4k_blast_dcache(); -} - -static void r4k_flush_cache_all(void) -{ - if (!cpu_has_dc_aliases) - return; - - r4k_on_each_cpu(local_r4k_flush_cache_all, NULL, 1, 1); -} - static inline void local_r4k___flush_cache_all(void * args) { #if defined(CONFIG_CPU_LOONGSON2) @@ -423,13 +407,14 @@ static inline void local_r4k_flush_cache_page(void *args) struct flush_cache_page_args *fcp_args = args; struct vm_area_struct *vma = fcp_args->vma; unsigned long addr = fcp_args->addr; - unsigned long paddr = fcp_args->pfn << PAGE_SHIFT; + struct page *page = pfn_to_page(fcp_args->pfn); int exec = vma->vm_flags & VM_EXEC; struct mm_struct *mm = vma->vm_mm; pgd_t *pgdp; pud_t *pudp; pmd_t *pmdp; pte_t *ptep; + void *vaddr; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -451,43 +436,40 @@ static inline void local_r4k_flush_cache_page(void *args) if (!(pte_val(*ptep) & _PAGE_PRESENT)) return; - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { - if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { - r4k_blast_dcache_page(addr); - if (exec && !cpu_icache_snoops_remote_store) - r4k_blast_scache_page(addr); - } - if (exec) - r4k_blast_icache_page(addr); - - return; + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) + vaddr = NULL; + else { + /* + * Use kmap_coherent or kmap_atomic to do flushes for + * another ASID than the current one. + */ + if (cpu_has_dc_aliases) + vaddr = kmap_coherent(page, addr); + else + vaddr = kmap_atomic(page, KM_USER0); + addr = (unsigned long)vaddr; } - /* - * Do indexed flush, too much work to get the (possible) TLB refills - * to work correctly. - */ if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { - r4k_blast_dcache_page_indexed(cpu_has_pindexed_dcache ? - paddr : addr); - if (exec && !cpu_icache_snoops_remote_store) { - r4k_blast_scache_page_indexed(paddr); - } + r4k_blast_dcache_page(addr); + if (exec && !cpu_icache_snoops_remote_store) + r4k_blast_scache_page(addr); } if (exec) { - if (cpu_has_vtag_icache && mm == current->active_mm) { + if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { int cpu = smp_processor_id(); if (cpu_context(cpu, mm) != 0) drop_mmu_context(mm, cpu); } else - r4k_blast_icache_page_indexed(addr); + r4k_blast_icache_page(addr); + } + + if (vaddr) { + if (cpu_has_dc_aliases) + kunmap_coherent(); + else + kunmap_atomic(vaddr, KM_USER0); } } @@ -1279,7 +1261,7 @@ void __init r4k_cache_init(void) PAGE_SIZE - 1); else shm_align_mask = PAGE_SIZE-1; - flush_cache_all = r4k_flush_cache_all; + flush_cache_all = cache_noop; __flush_cache_all = r4k___flush_cache_all; flush_cache_mm = r4k_flush_cache_mm; flush_cache_page = r4k_flush_cache_page; From f4fae8267c152d6c319a7bfaf92ed1c2c9a2c4e8 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:12 +0100 Subject: [PATCH 2253/2804] [MIPS] Optimize __alloc_zeroed_user_highpage implementation. Signed-off-by: Ralf Baechle --- include/asm-mips/page.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index c90fe560a0d9..e3301e54d559 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -142,7 +142,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; /* * __pa()/__va() should be used only during mem init. */ -#ifdef KBUILD_64BIT_SYM32 +#ifdef CONFIG_64BIT #define __pa(x) \ ({ \ unsigned long __x = (unsigned long)(x); \ From e86169fffedc2f461be6f70817ae5ab201c12fd5 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Mon, 1 Oct 2007 19:45:05 +0900 Subject: [PATCH 2254/2804] [MIPS] Cobalt: Add Cobalt Raq LED platform register and power off trigger Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/cobalt/Makefile | 2 +- arch/mips/cobalt/led.c | 56 +++++++++++++++++++++++++++++++++++++++ arch/mips/cobalt/reset.c | 22 +++++++++------ 3 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 arch/mips/cobalt/led.c diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile index a043f93f7d08..6b83f4ddc8fc 100644 --- a/arch/mips/cobalt/Makefile +++ b/arch/mips/cobalt/Makefile @@ -2,7 +2,7 @@ # Makefile for the Cobalt micro systems family specific parts of the kernel # -obj-y := buttons.o irq.o reset.o rtc.o serial.o setup.o +obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_EARLY_PRINTK) += console.o diff --git a/arch/mips/cobalt/led.c b/arch/mips/cobalt/led.c new file mode 100644 index 000000000000..8150af3abb8e --- /dev/null +++ b/arch/mips/cobalt/led.c @@ -0,0 +1,56 @@ +/* + * Registration of Cobalt LED platform device. + * + * Copyright (C) 2007 Yoichi Yuasa + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include + +static struct resource cobalt_led_resource __initdata = { + .start = 0x1c000000, + .end = 0x1c000000, + .flags = IORESOURCE_MEM, +}; + +static __init int cobalt_led_add(void) +{ + struct platform_device *pdev; + int retval; + + pdev = platform_device_alloc("cobalt-raq-leds", -1); + + if (!pdev) + return -ENOMEM; + + retval = platform_device_add_resources(pdev, &cobalt_led_resource, 1); + if (retval) + goto err_free_device; + + retval = platform_device_add(pdev); + if (retval) + goto err_free_device; + + return 0; + +err_free_device: + platform_device_put(pdev); + + return retval; +} +device_initcall(cobalt_led_add); diff --git a/arch/mips/cobalt/reset.c b/arch/mips/cobalt/reset.c index 43cca21fdbc0..f503a0d04b3b 100644 --- a/arch/mips/cobalt/reset.c +++ b/arch/mips/cobalt/reset.c @@ -8,31 +8,37 @@ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) */ +#include #include - -#include -#include +#include #include +DEFINE_LED_TRIGGER(power_off_led_trigger); + +static int __init ledtrig_power_off_init(void) +{ + led_trigger_register_simple("power-off", &power_off_led_trigger); + return 0; +} +device_initcall(ledtrig_power_off_init); + void cobalt_machine_halt(void) { int state, last, diff; unsigned long mark; /* - * turn off bar on Qube, flash power off LED on RaQ (0.5Hz) + * turn on power off LED on RaQ * * restart if ENTER and SELECT are pressed */ last = COBALT_KEY_PORT; + led_trigger_event(power_off_led_trigger, LED_FULL); + for (state = 0;;) { - - state ^= COBALT_LED_POWER_OFF; - COBALT_LED_PORT = state; - diff = COBALT_KEY_PORT ^ last; last ^= diff; From 9a203755ca392587953be2b5cf235800dcb27d8e Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Mon, 1 Oct 2007 19:46:50 +0900 Subject: [PATCH 2255/2804] [MIPS] Cobalt: Add Qube series front LED support to platform register Add Cobalt Qube series front LED support to platform register. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/cobalt/led.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/mips/cobalt/led.c b/arch/mips/cobalt/led.c index 8150af3abb8e..1c6ebd468b07 100644 --- a/arch/mips/cobalt/led.c +++ b/arch/mips/cobalt/led.c @@ -22,6 +22,8 @@ #include #include +#include + static struct resource cobalt_led_resource __initdata = { .start = 0x1c000000, .end = 0x1c000000, @@ -33,7 +35,11 @@ static __init int cobalt_led_add(void) struct platform_device *pdev; int retval; - pdev = platform_device_alloc("cobalt-raq-leds", -1); + if (cobalt_board_id == COBALT_BRD_ID_QUBE1 || + cobalt_board_id == COBALT_BRD_ID_QUBE2) + pdev = platform_device_alloc("cobalt-qube-leds", -1); + else + pdev = platform_device_alloc("cobalt-raq-leds", -1); if (!pdev) return -ENOMEM; From 414461f9e0e30551a75b015aa2864efbf393de2f Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Mon, 1 Oct 2007 19:48:31 +0900 Subject: [PATCH 2256/2804] [MIPS] Cobalt: Add LED support to cobalt_defconfig Add LED support to cobalt_defconfig. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/configs/cobalt_defconfig | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index ebcb7ad8814b..36c13039e237 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.23-rc2 -# Tue Aug 7 22:12:54 2007 +# Linux kernel version: 2.6.23-rc5 +# Thu Sep 6 13:14:29 2007 # CONFIG_MIPS=y @@ -55,12 +55,14 @@ CONFIG_DMA_NONCOHERENT=y CONFIG_DMA_NEED_PCI_MAP_STATE=y CONFIG_EARLY_PRINTK=y CONFIG_SYS_HAS_EARLY_PRINTK=y +# CONFIG_HOTPLUG_CPU is not set CONFIG_I8259=y # CONFIG_NO_IOPORT is not set # CONFIG_CPU_BIG_ENDIAN is not set CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y CONFIG_IRQ_CPU=y +CONFIG_IRQ_GT641XX=y CONFIG_PCI_GT64XXX_PCI0=y CONFIG_MIPS_L1_CACHE_SHIFT=5 @@ -235,6 +237,7 @@ CONFIG_TRAD_SIGNALS=y # Power management options # # CONFIG_PM is not set +CONFIG_SUSPEND_UP_POSSIBLE=y # # Networking @@ -844,7 +847,21 @@ CONFIG_USB_MON=y # # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set -# CONFIG_NEW_LEDS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +CONFIG_LEDS_COBALT_QUBE=y +CONFIG_LEDS_COBALT_RAQ=y + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set # CONFIG_INFINIBAND is not set CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y From b1df86d6e148e3be6d1e43e604b19fbb6815b8ba Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 1 Oct 2007 13:52:38 +0200 Subject: [PATCH 2257/2804] [MIPS] MTX1: Add defconfig file Signed-off-by: Florian Fainelli Signed-off-by: Ralf Baechle --- arch/mips/configs/mtx1_defconfig | 3115 ++++++++++++++++++++++++++++++ 1 file changed, 3115 insertions(+) create mode 100644 arch/mips/configs/mtx1_defconfig diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig new file mode 100644 index 000000000000..0280ef389d8d --- /dev/null +++ b/arch/mips/configs/mtx1_defconfig @@ -0,0 +1,3115 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc8 +# Sun Sep 30 12:56:10 2007 +# +CONFIG_MIPS=y + +# +# Machine selection +# +CONFIG_MACH_ALCHEMY=y +# CONFIG_BASLER_EXCITE is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_LEMOTE_FULONG is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MARKEINS is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_QEMU is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_PTSWARM is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SNI_RM is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_TOSHIBA_RBTX4938 is not set +# CONFIG_WR_PPMC is not set +CONFIG_MIPS_MTX1=y +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1200 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_DB1550 is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1200 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_MIPS_PB1550 is not set +# CONFIG_MIPS_XXS1500 is not set +CONFIG_SOC_AU1500=y +CONFIG_SOC_AU1X00=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_NO_IOPORT is not set +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +# CONFIG_CPU_LOONGSON2 is not set +CONFIG_CPU_MIPS32_R1=y +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y + +# +# Kernel type +# +CONFIG_32BIT=y +# CONFIG_64BIT is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_MIPS_MT_DISABLED=y +# CONFIG_MIPS_MT_SMP is not set +# CONFIG_MIPS_MT_SMTC is not set +CONFIG_64BIT_PHYS_ADDR=y +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=250 +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set +# CONFIG_KEXEC is not set +CONFIG_SECCOMP=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +CONFIG_AUDIT=y +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_SYSFS_DEPRECATED=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_MMU=y + +# +# PCCARD (PCMCIA/CardBus) support +# +CONFIG_PCCARD=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=m +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_PD6729=m +CONFIG_I82092=m +# CONFIG_PCMCIA_AU1X00 is not set +CONFIG_PCCARD_NONSTATIC=m +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_TRAD_SIGNALS=y + +# +# Power management options +# +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_UP_POSSIBLE=y +CONFIG_SUSPEND=y +# CONFIG_APM_EMULATION is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETLABEL is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +# CONFIG_NF_CONNTRACK_ENABLED is not set +# CONFIG_NF_CONNTRACK is not set +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +# CONFIG_IP6_NF_MATCH_MH is not set +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_FIFO=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +# CONFIG_NET_SCH_RR is not set +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +CONFIG_NET_CLS_POLICE=y +# CONFIG_NET_CLS_IND is not set + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +# CONFIG_AX25_DAMA_SLAVE is not set +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_EPP=m +CONFIG_YAM=m +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +CONFIG_DONGLE=y +CONFIG_ESI_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_TEKRAM_DONGLE=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_LITELINK_DONGLE=m +CONFIG_MA600_DONGLE=m +CONFIG_GIRBIL_DONGLE=m +CONFIG_MCP2120_DONGLE=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_ACT200L_DONGLE=m +# CONFIG_KINGSUN_DONGLE is not set + +# +# Old SIR device drivers +# +# CONFIG_IRPORT_SIR is not set + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +CONFIG_USB_IRDA=m +CONFIG_SIGMATEL_FIR=m +CONFIG_TOSHIBA_FIR=m +CONFIG_VLSI_FIR=m +CONFIG_MCS_FIR=m +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIVHCI=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +# CONFIG_RXKAD is not set +CONFIG_FIB_RULES=y + +# +# Wireless +# +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT=y +# CONFIG_MAC80211 is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_SOFTMAC=m +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_ALCHEMY is not set +# CONFIG_MTD_MTX1 is not set +CONFIG_MTD_PCI=m +CONFIG_MTD_PLATRAM=m + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCECC=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +# CONFIG_MTD_NAND_CAFE is not set +CONFIG_MTD_NAND_NANDSIM=m +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_OTP is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_SUPERIO=y +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_AX88796=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_BLK_DEV=y +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +CONFIG_PARIDE_EPATC8=y +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SX8=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +CONFIG_SGI_IOC4=m +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_DELKIN is not set +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +CONFIG_IDEPCI_PCIBUS_ORDER=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=m +CONFIG_BLK_DEV_OPTI621=m +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +# CONFIG_WDC_ALI15X3 is not set +CONFIG_BLK_DEV_AMD74XX=m +CONFIG_BLK_DEV_CMD64X=m +CONFIG_BLK_DEV_TRIFLEX=m +CONFIG_BLK_DEV_CY82C693=m +# CONFIG_BLK_DEV_CS5520 is not set +CONFIG_BLK_DEV_CS5530=m +CONFIG_BLK_DEV_HPT34X=m +# CONFIG_HPT34X_AUTODMA is not set +CONFIG_BLK_DEV_HPT366=m +# CONFIG_BLK_DEV_JMICRON is not set +CONFIG_BLK_DEV_SC1200=m +CONFIG_BLK_DEV_PIIX=m +# CONFIG_BLK_DEV_IT8213 is not set +CONFIG_BLK_DEV_IT821X=m +CONFIG_BLK_DEV_NS87415=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_PDC202XX_BURST=y +CONFIG_BLK_DEV_PDC202XX_NEW=m +CONFIG_BLK_DEV_SVWKS=m +CONFIG_BLK_DEV_SIIMAGE=m +# CONFIG_BLK_DEV_SLC90E66 is not set +CONFIG_BLK_DEV_TRM290=m +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_ATA is not set +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_ARCMSR=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_DEBUG=m +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_SVW=m +CONFIG_ATA_PIIX=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SX4=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +CONFIG_PATA_CS5520=m +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_ATA_GENERIC=m +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +CONFIG_PATA_JMICRON=m +CONFIG_PATA_TRIFLEX=m +# CONFIG_PATA_MARVELL is not set +CONFIG_PATA_MPIIX=m +# CONFIG_PATA_OLDPIIX is not set +CONFIG_PATA_NETCELL=m +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +# CONFIG_PATA_PLATFORM is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_RAID5_RESHAPE is not set +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_EMC=m +# CONFIG_DM_MULTIPATH_RDAC is not set +# CONFIG_DM_DELAY is not set + +# +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +# CONFIG_FUSION_LOGGING is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# Controllers +# +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocols +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_I2O=m +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_IFB is not set +CONFIG_DUMMY=m +CONFIG_BONDING=m +# CONFIG_MACVLAN is not set +CONFIG_EQUALIZER=m +CONFIG_TUN=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_PHYLIB=m + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_LXT_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_SMSC_PHY=m +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +CONFIG_FIXED_PHY=m +# CONFIG_FIXED_MII_10_FDX is not set +# CONFIG_FIXED_MII_100_FDX is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +# CONFIG_AX88796 is not set +# CONFIG_MIPS_AU1X00_ENET is not set +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_PCMCIA_XIRCOM=m +# CONFIG_PCMCIA_XIRTULIP is not set +CONFIG_HP100=m +CONFIG_NET_PCI=y +CONFIG_PCNET32=m +# CONFIG_PCNET32_NAPI is not set +CONFIG_AMD8111_ETH=m +# CONFIG_AMD8111E_NAPI is not set +CONFIG_ADAPTEC_STARFIRE=m +# CONFIG_ADAPTEC_STARFIRE_NAPI is not set +CONFIG_B44=m +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +# CONFIG_TC35815 is not set +CONFIG_DGRS=m +CONFIG_EEPRO100=m +CONFIG_E100=m +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NE2K_PCI=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_SIS900=m +CONFIG_EPIC100=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_VIA_RHINE_NAPI is not set +# CONFIG_SC92031 is not set +CONFIG_NET_POCKET=y +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_NETDEV_1000=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m +CONFIG_E1000=m +# CONFIG_E1000_NAPI is not set +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_NS83820=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_R8169=m +# CONFIG_R8169_NAPI is not set +CONFIG_R8169_VLAN=y +CONFIG_SIS190=m +CONFIG_SKGE=m +CONFIG_SKY2=m +CONFIG_SK98LIN=m +CONFIG_VIA_VELOCITY=m +CONFIG_TIGON3=m +CONFIG_BNX2=m +CONFIG_QLA3XXX=m +# CONFIG_ATL1 is not set +CONFIG_NETDEV_10000=y +CONFIG_CHELSIO_T1=m +# CONFIG_CHELSIO_T1_1G is not set +CONFIG_CHELSIO_T1_NAPI=y +# CONFIG_CHELSIO_T3 is not set +CONFIG_IXGB=m +# CONFIG_IXGB_NAPI is not set +CONFIG_S2IO=m +# CONFIG_S2IO_NAPI is not set +CONFIG_MYRI10GE=m +# CONFIG_NETXEN_NIC is not set +# CONFIG_MLX4_CORE is not set +CONFIG_TR=y +CONFIG_IBMOL=m +CONFIG_IBMLS=m +CONFIG_3C359=m +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +CONFIG_ABYSS=m + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET_MII=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_DM9601 is not set +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=m +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_WAN=y +CONFIG_LANMEDIA=m +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300=m +CONFIG_PC300_MLPPP=y + +# +# Cyclades-PC300 MLPPP support is disabled. +# + +# +# Refer to the file README.mlppp, provided by PC300 package. +# +# CONFIG_PC300TOO is not set +CONFIG_FARSYNC=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +CONFIG_LAPBETHER=m +CONFIG_X25_ASY=m +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_FORE200E_MAYBE=m +CONFIG_ATM_FORE200E_PCA=y +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E=m +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_FDDI=y +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_SKFP=m +CONFIG_HIPPI=y +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_PPPOATM=m +# CONFIG_PPPOL2TP is not set +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLHC=m +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_NET_FC=y +CONFIG_SHAPER=m +CONFIG_NETCONSOLE=m +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_ISDN=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_IPPP_FILTER=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y + +# +# ISDN feature submodules +# +# CONFIG_ISDN_DRV_LOOP is not set +CONFIG_ISDN_DIVERSION=m + +# +# ISDN4Linux hardware drivers +# + +# +# Passive cards +# +CONFIG_ISDN_DRV_HISAX=m + +# +# D-channel protocol features +# +CONFIG_HISAX_EURO=y +CONFIG_DE_AOC=y +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_KEYPAD is not set +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_MAX_CARDS=8 + +# +# HiSax supported cards +# +CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NICCY=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_ENTERNOW_PCI=y +# CONFIG_HISAX_DEBUG is not set + +# +# HiSax PCMCIA card service modules +# +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_TELES_CS=m + +# +# HiSax sub driver modules +# +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_HDLC=y + +# +# Active cards +# +# CONFIG_HYSDN is not set +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_BASE=m +CONFIG_GIGASET_M105=m +# CONFIG_GIGASET_M101 is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_CAPI_TRACE=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIDRV=m + +# +# CAPI hardware drivers +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_TSDEV=m +CONFIG_INPUT_TSDEV_SCREEN_X=240 +CONFIG_INPUT_TSDEV_SCREEN_Y=320 +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_SERIAL=m +# CONFIG_MOUSE_APPLETOUCH is not set +CONFIG_MOUSE_VSXXXAA=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +# CONFIG_JOYSTICK_XPAD is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=m +# CONFIG_TOUCHSCREEN_FUJITSU is not set +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +# CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PCSPKR=m +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +CONFIG_INPUT_UINPUT=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +CONFIG_ROCKETPORT=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_DIGIEPCA=m +# CONFIG_MOXA_INTELLIO is not set +CONFIG_MOXA_SMARTIO=m +# CONFIG_MOXA_SMARTIO_NEW is not set +# CONFIG_ISI is not set +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_N_HDLC=m +# CONFIG_RISCOM8 is not set +CONFIG_SPECIALIX=m +# CONFIG_SPECIALIX_RTSCTS is not set +CONFIG_SX=m +# CONFIG_RIO is not set +CONFIG_STALDRV=y +# CONFIG_STALLION is not set +# CONFIG_ISTALLION is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=m +CONFIG_SERIAL_8250_PCI=m +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y +# CONFIG_SERIAL_8250_AU1X00 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=m +CONFIG_SERIAL_JSM=m +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +CONFIG_PPDEV=m +CONFIG_TIPAR=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +# CONFIG_WDT_MTX1 is not set + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_HW_RANDOM=y +CONFIG_RTC=y +CONFIG_R3964=m +CONFIG_APPLICOM=m +CONFIG_DRM=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_MGA=m +CONFIG_DRM_VIA=m +CONFIG_DRM_SAVAGE=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_TCG_TPM=m +CONFIG_TCG_ATMEL=m +CONFIG_DEVPORT=y +CONFIG_I2C=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_I810=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PROSAVAGE=m +CONFIG_I2C_SAVAGE4=m +# CONFIG_I2C_SIMTEC is not set +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +# CONFIG_I2C_TAOS_EVM is not set +CONFIG_I2C_STUB=m +# CONFIG_I2C_TINY_USB is not set +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +# CONFIG_DS1682 is not set +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_LM70_LLP is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +CONFIG_W1=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +CONFIG_SENSORS_ABITUGURU=m +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7418 is not set +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +# CONFIG_SENSORS_ADM1029 is not set +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +# CONFIG_SENSORS_LM93 is not set +CONFIG_SENSORS_MAX1619=m +# CONFIG_SENSORS_MAX6650 is not set +CONFIG_SENSORS_PC87360=m +# CONFIG_SENSORS_PC87427 is not set +CONFIG_SENSORS_SIS5595=m +# CONFIG_SENSORS_DME1737 is not set +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +# CONFIG_SENSORS_THMC50 is not set +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +# CONFIG_SENSORS_W83793 is not set +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_TUNER_3036=m +# CONFIG_TUNER_TEA5761 is not set +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_OSS=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_29XXX=y +CONFIG_VIDEO_PVRUSB2_24XXX=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_EM28XX=m +# CONFIG_VIDEO_USBVISION is not set +CONFIG_VIDEO_USBVIDEO=m +CONFIG_USB_VICAM=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_ET61X251=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_USB_W9968CF=m +# CONFIG_USB_OV511 is not set +CONFIG_USB_SE401=m +CONFIG_USB_SN9C102=m +CONFIG_USB_STV680=m +CONFIG_USB_ZC0301=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +# CONFIG_USB_ZR364XX is not set +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_MAESTRO=m +CONFIG_USB_DSBR=m +CONFIG_DVB_CORE=m +CONFIG_DVB_CORE_ATTACH=y +CONFIG_DVB_CAPTURE_DRIVERS=y + +# +# Supported SAA7146 based PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m + +# +# Supported USB Adapters +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_M920X is not set +# CONFIG_DVB_USB_GL861 is not set +# CONFIG_DVB_USB_AU6610 is not set +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +# CONFIG_DVB_USB_TTUSB2 is not set +CONFIG_DVB_USB_DTT200U=m +# CONFIG_DVB_USB_OPERA1 is not set +# CONFIG_DVB_USB_AF9005 is not set +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_CINERGYT2=m +CONFIG_DVB_CINERGYT2_TUNING=y +CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT=32 +CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE=512 +CONFIG_DVB_CINERGYT2_QUERY_INTERVAL=250 +CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE=y +CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL=100 + +# +# Supported FlexCopII (B2C2) Adapters +# +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m + +# +# Supported Pluto2 Adapters +# +CONFIG_DVB_PLUTO2=m + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_STV0299=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_TDA10086=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m + +# +# Tuners/PLL support +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TDA827X=m +# CONFIG_DVB_TUNER_QT1010 is not set +CONFIG_DVB_TUNER_MT2060=m + +# +# Miscellaneous devices +# +CONFIG_DVB_LNBP21=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_TUA6100=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_BUF=m +CONFIG_VIDEO_BUF_DVB=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_DAB=y +CONFIG_USB_DABUSB=m + +# +# Graphics support +# +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +CONFIG_VGASTATE=m +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_DDC=m +CONFIG_FB_CFB_FILLRECT=m +CONFIG_FB_CFB_COPYAREA=m +CONFIG_FB_CFB_IMAGEBLIT=m +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_CYBER2000=m +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_S1D13XXX=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_BACKLIGHT=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_I2C=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_BACKLIGHT=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_BACKLIGHT=y +# CONFIG_FB_S3 is not set +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_VOODOO1=m +# CONFIG_FB_VT8623 is not set +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_RTCTIMER=m +CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_DUMMY=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +# CONFIG_SND_PORTMAN2X4 is not set + +# +# PCI devices +# +CONFIG_SND_AD1889=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +# CONFIG_SND_BT87X_OVERCLOCK is not set +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_KORG1212_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_FIRMWARE_IN_KERNEL=y +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y +# CONFIG_SND_AC97_POWER_SAVE is not set + +# +# ALSA MIPS devices +# +# CONFIG_SND_AU1X00 is not set + +# +# USB devices +# +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_CAIAQ is not set + +# +# PCMCIA devices +# +CONFIG_SND_VXPOCKET=m +CONFIG_SND_PDAUDIOCF=m + +# +# System on Chip audio support +# +# CONFIG_SND_SOC is not set + +# +# SoC Audio support for SuperH +# + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_TRIDENT=m +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_AC97_BUS=m +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT_POWERBOOK=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_PERSIST is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_SPLIT_ISO=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_CS=m +# CONFIG_USB_R8A66597_HCD is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_MON=y + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_AIRPRIME=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +# CONFIG_USB_SERIAL_OTI6858 is not set +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +# CONFIG_USB_SERIAL_DEBUG is not set +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +# CONFIG_USB_BERRY_CHARGE is not set +CONFIG_USB_LED=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +# CONFIG_USB_IOWARRIOR is not set +CONFIG_USB_TEST=m + +# +# USB DSL modem support +# +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +CONFIG_USB_GADGET_NET2280=y +CONFIG_USB_NET2280=m +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +CONFIG_USB_MIDI_GADGET=m +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_SDHCI=m +CONFIG_MMC_TIFM_SD=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m + +# +# LED drivers +# + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGERS is not set +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +# CONFIG_MLX4_INFINIBAND is not set +CONFIG_INFINIBAND_IPOIB=m +# CONFIG_INFINIBAND_IPOIB_CM is not set +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_ISER=m +CONFIG_RTC_LIB=m +CONFIG_RTC_CLASS=m + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_TEST=m + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1672=m +# CONFIG_RTC_DRV_MAX6900 is not set +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +# CONFIG_RTC_DRV_M41T80 is not set + +# +# SPI RTC drivers +# +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1553=m +# CONFIG_RTC_DRV_STK17TA8 is not set +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_M48T86=m +# CONFIG_RTC_DRV_M48T59 is not set +CONFIG_RTC_DRV_V3020=m + +# +# on-CPU RTC drivers +# + +# +# DMA Engine support +# +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=m +# CONFIG_AUXDISPLAY is not set + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_STATISTICS=y +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=y +CONFIG_VXFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +# CONFIG_SUNRPC_BIND34 is not set +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +# CONFIG_CODA_FS_OLD_API is not set +CONFIG_AFS_FS=m +# CONFIG_AFS_DEBUG is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Distributed Lock Manager +# +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=m + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_CROSSCOMPILE is not set +CONFIG_CMDLINE="" +CONFIG_SYS_SUPPORTS_KGDB=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_CAPABILITIES=m +CONFIG_SECURITY_ROOTPLUG=m +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_FCRYPT is not set +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_CAMELLIA is not set +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_HW=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=m +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CHECK_SIGNATURE=y From b4126e86301cfc6863cbc74bc4500a88b7c582df Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 2 Oct 2007 22:54:41 +0900 Subject: [PATCH 2258/2804] [MIPS] Cobalt: Move PCI definitions to arch/mips/pci/fixup-cobalt.c. These PCI definitions are only used in arch/mips/pci/fixup-cobalt.c. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/pci/fixup-cobalt.c | 17 +++++++++++++++++ include/asm-mips/mach-cobalt/cobalt.h | 26 ++------------------------ 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c index 4eb5410f842a..f7df1142912b 100644 --- a/arch/mips/pci/fixup-cobalt.c +++ b/arch/mips/pci/fixup-cobalt.c @@ -20,6 +20,23 @@ #include #include +/* + * PCI slot numbers + */ +#define COBALT_PCICONF_CPU 0x06 +#define COBALT_PCICONF_ETH0 0x07 +#define COBALT_PCICONF_RAQSCSI 0x08 +#define COBALT_PCICONF_VIA 0x09 +#define COBALT_PCICONF_PCISLOT 0x0A +#define COBALT_PCICONF_ETH1 0x0C + +/* + * The Cobalt board ID information. The boards have an ID number wired + * into the VIA that is available in the high nibble of register 94. + */ +#define VIA_COBALT_BRD_ID_REG 0x94 +#define VIA_COBALT_BRD_REG_to_ID(reg) ((unsigned char)(reg) >> 4) + static void qube_raq_galileo_early_fixup(struct pci_dev *dev) { if (dev->devfn == PCI_DEVFN(0, 0) && diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h index 408eeccbe512..f27fcef3e3ff 100644 --- a/include/asm-mips/mach-cobalt/cobalt.h +++ b/include/asm-mips/mach-cobalt/cobalt.h @@ -13,37 +13,15 @@ #define __ASM_COBALT_H /* - * PCI configuration space manifest constants. These are wired into - * the board layout according to the PCI spec to enable the software - * to probe the hardware configuration space in a well defined manner. - * - * The PCI_DEVSHFT() macro transforms these values into numbers - * suitable for passing as the dev parameter to the various - * pcibios_read/write_config routines. + * The Cobalt board ID information. */ -#define COBALT_PCICONF_CPU 0x06 -#define COBALT_PCICONF_ETH0 0x07 -#define COBALT_PCICONF_RAQSCSI 0x08 -#define COBALT_PCICONF_VIA 0x09 -#define COBALT_PCICONF_PCISLOT 0x0A -#define COBALT_PCICONF_ETH1 0x0C +extern int cobalt_board_id; - -/* - * The Cobalt board id information. The boards have an ID number wired - * into the VIA that is available in the high nibble of register 94. - * This register is available in the VIA configuration space through the - * interface routines qube_pcibios_read/write_config. See cobalt/pci.c - */ -#define VIA_COBALT_BRD_ID_REG 0x94 -#define VIA_COBALT_BRD_REG_to_ID(reg) ((unsigned char) (reg) >> 4) #define COBALT_BRD_ID_QUBE1 0x3 #define COBALT_BRD_ID_RAQ1 0x4 #define COBALT_BRD_ID_QUBE2 0x5 #define COBALT_BRD_ID_RAQ2 0x6 -extern int cobalt_board_id; - #define COBALT_LED_PORT (*(volatile unsigned char *) CKSEG1ADDR(0x1c000000)) # define COBALT_LED_BAR_LEFT (1 << 0) /* Qube */ # define COBALT_LED_BAR_RIGHT (1 << 1) /* Qube */ From 5a860424a1bcf21655d993a7c09b36662e34d2a9 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 2 Oct 2007 23:13:17 +0900 Subject: [PATCH 2259/2804] [MIPS] Cobalt: Move UART base definition to arch/mips/cobalt/console.c They're only used in arch/mips/cobalt/console.c. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/cobalt/console.c | 9 ++++----- include/asm-mips/mach-cobalt/cobalt.h | 2 -- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/mips/cobalt/console.c b/arch/mips/cobalt/console.c index 0485d51f7216..db330e811025 100644 --- a/arch/mips/cobalt/console.c +++ b/arch/mips/cobalt/console.c @@ -1,16 +1,15 @@ /* * (C) P. Horton 2006 */ +#include #include -#include - -#include +#define UART_BASE ((void __iomem *)CKSEG1ADDR(0x1c800000)) void prom_putchar(char c) { - while(!(COBALT_UART[UART_LSR] & UART_LSR_THRE)) + while (!(readb(UART_BASE + UART_LSR) & UART_LSR_THRE)) ; - COBALT_UART[UART_TX] = c; + writeb(c, UART_BASE + UART_TX); } diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h index f27fcef3e3ff..4cb5844d42df 100644 --- a/include/asm-mips/mach-cobalt/cobalt.h +++ b/include/asm-mips/mach-cobalt/cobalt.h @@ -39,6 +39,4 @@ extern int cobalt_board_id; # define COBALT_KEY_SELECT (1 << 7) # define COBALT_KEY_MASK 0xfe -#define COBALT_UART ((volatile unsigned char *) CKSEG1ADDR(0x1c800000)) - #endif /* __ASM_COBALT_H */ From 3282bd3cb0c7653e604c0d3666331281ae8f74c4 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 2 Oct 2007 23:17:38 +0900 Subject: [PATCH 2260/2804] [MIPS] Cobalt: Move reset port definition to arch/mips/cobalt/reset.c It's only used in arch/mips/cobalt/reset.c. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/cobalt/reset.c | 8 ++++++-- include/asm-mips/mach-cobalt/cobalt.h | 7 ------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/mips/cobalt/reset.c b/arch/mips/cobalt/reset.c index f503a0d04b3b..81628b3ae621 100644 --- a/arch/mips/cobalt/reset.c +++ b/arch/mips/cobalt/reset.c @@ -9,11 +9,15 @@ * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) */ #include +#include #include #include #include +#define RESET_PORT ((void __iomem *)CKSEG1ADDR(0x1c000000)) +#define RESET 0x0f + DEFINE_LED_TRIGGER(power_off_led_trigger); static int __init ledtrig_power_off_init(void) @@ -43,7 +47,7 @@ void cobalt_machine_halt(void) last ^= diff; if((diff & (COBALT_KEY_ENTER | COBALT_KEY_SELECT)) && !(~last & (COBALT_KEY_ENTER | COBALT_KEY_SELECT))) - COBALT_LED_PORT = COBALT_LED_RESET; + writeb(RESET, RESET_PORT); for (mark = jiffies; jiffies - mark < HZ;) ; @@ -52,7 +56,7 @@ void cobalt_machine_halt(void) void cobalt_machine_restart(char *command) { - COBALT_LED_PORT = COBALT_LED_RESET; + writeb(RESET, RESET_PORT); /* we should never get here */ cobalt_machine_halt(); diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h index 4cb5844d42df..a79e7caf3a86 100644 --- a/include/asm-mips/mach-cobalt/cobalt.h +++ b/include/asm-mips/mach-cobalt/cobalt.h @@ -22,13 +22,6 @@ extern int cobalt_board_id; #define COBALT_BRD_ID_QUBE2 0x5 #define COBALT_BRD_ID_RAQ2 0x6 -#define COBALT_LED_PORT (*(volatile unsigned char *) CKSEG1ADDR(0x1c000000)) -# define COBALT_LED_BAR_LEFT (1 << 0) /* Qube */ -# define COBALT_LED_BAR_RIGHT (1 << 1) /* Qube */ -# define COBALT_LED_WEB (1 << 2) /* RaQ */ -# define COBALT_LED_POWER_OFF (1 << 3) /* RaQ */ -# define COBALT_LED_RESET 0x0f - #define COBALT_KEY_PORT ((~*(volatile unsigned int *) CKSEG1ADDR(0x1d000000) >> 24) & COBALT_KEY_MASK) # define COBALT_KEY_CLEAR (1 << 1) # define COBALT_KEY_LEFT (1 << 2) From f13558c2a4a7339192ff7148ee903340affdb790 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 2 Oct 2007 23:21:36 +0900 Subject: [PATCH 2261/2804] [MIPS] Cobalt: Remove cobalt_machine_power_off() It's same as cobalt_machine_halt(). Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/cobalt/reset.c | 9 --------- arch/mips/cobalt/setup.c | 3 +-- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/arch/mips/cobalt/reset.c b/arch/mips/cobalt/reset.c index 81628b3ae621..71eb4ccc4bc1 100644 --- a/arch/mips/cobalt/reset.c +++ b/arch/mips/cobalt/reset.c @@ -61,12 +61,3 @@ void cobalt_machine_restart(char *command) /* we should never get here */ cobalt_machine_halt(); } - -/* - * This triggers the luser mode device driver for the power switch ;-) - */ -void cobalt_machine_power_off(void) -{ - printk("You can switch the machine off now.\n"); - cobalt_machine_halt(); -} diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index 345e4ae998df..d11bb1bc7b6b 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -25,7 +25,6 @@ extern void cobalt_machine_restart(char *command); extern void cobalt_machine_halt(void); -extern void cobalt_machine_power_off(void); const char *get_system_type(void) { @@ -96,7 +95,7 @@ void __init plat_mem_setup(void) _machine_restart = cobalt_machine_restart; _machine_halt = cobalt_machine_halt; - pm_power_off = cobalt_machine_power_off; + pm_power_off = cobalt_machine_halt; set_io_port_base(CKSEG1ADDR(GT_DEF_PCI0_IO_BASE)); From 1ac74d528dcfe3dcaa6072289d71fa96569f5e39 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 2 Oct 2007 14:54:15 +0100 Subject: [PATCH 2262/2804] [MIPS] pg-r4k.c: Dump the generated code Dump the generated code for clear/copy page calls like it is done for TLB fault handlers. Useful for debugging. Signed-off-by: Maciej W. Rozycki Signed-off-by: Ralf Baechle --- arch/mips/mm/pg-r4k.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c index e47e9e9486bf..c0294541d295 100644 --- a/arch/mips/mm/pg-r4k.c +++ b/arch/mips/mm/pg-r4k.c @@ -347,6 +347,7 @@ void __init build_clear_page(void) { unsigned int loop_start; unsigned long off; + int i; epc = (unsigned int *) &clear_page_array; instruction_pending = 0; @@ -434,12 +435,22 @@ dest = label(); build_jr_ra(); BUG_ON(epc > clear_page_array + ARRAY_SIZE(clear_page_array)); + + pr_info("Synthesized clear page handler (%u instructions).\n", + (unsigned int)(epc - clear_page_array)); + + pr_debug("\t.set push\n"); + pr_debug("\t.set noreorder\n"); + for (i = 0; i < (epc - clear_page_array); i++) + pr_debug("\t.word 0x%08x\n", clear_page_array[i]); + pr_debug("\t.set pop\n"); } void __init build_copy_page(void) { unsigned int loop_start; unsigned long off; + int i; epc = (unsigned int *) ©_page_array; store_offset = load_offset = 0; @@ -515,4 +526,13 @@ dest = label(); build_jr_ra(); BUG_ON(epc > copy_page_array + ARRAY_SIZE(copy_page_array)); + + pr_info("Synthesized copy page handler (%u instructions).\n", + (unsigned int)(epc - copy_page_array)); + + pr_debug("\t.set push\n"); + pr_debug("\t.set noreorder\n"); + for (i = 0; i < (epc - copy_page_array); i++) + pr_debug("\t.word 0x%08x\n", copy_page_array[i]); + pr_debug("\t.set pop\n"); } From aeffdbbaff133b0c3989e20af5baa091d3d0b409 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:14 +0100 Subject: [PATCH 2263/2804] [MIPS] tlbex: Size optimize code by declaring a few functions inline. Signed-off-by: Ralf Baechle --- arch/mips/mm/tlbex.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index b2c6b9e47564..73250741a0f9 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -35,24 +35,24 @@ #include #include -static __init int __maybe_unused r45k_bvahwbug(void) +static inline int r45k_bvahwbug(void) { /* XXX: We should probe for the presence of this bug, but we don't. */ return 0; } -static __init int __maybe_unused r4k_250MHZhwbug(void) +static inline int r4k_250MHZhwbug(void) { /* XXX: We should probe for the presence of this bug, but we don't. */ return 0; } -static __init int __maybe_unused bcm1250_m3_war(void) +static inline int __maybe_unused bcm1250_m3_war(void) { return BCM1250_M3_WAR; } -static __init int __maybe_unused r10000_llsc_war(void) +static inline int __maybe_unused r10000_llsc_war(void) { return R10000_LLSC_WAR; } From 10cc3529072d5415fb040018a8a99aa7a60190b6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:15 +0100 Subject: [PATCH 2264/2804] [MIPS] Allow hardwiring of the CPU type to a single type for optimization. This saves a few k on systems which only ever ship with a single CPU type. Signed-off-by: Ralf Baechle --- arch/mips/dec/ecc-berr.c | 2 +- arch/mips/dec/kn02xa-berr.c | 2 +- arch/mips/dec/prom/init.c | 8 +-- arch/mips/kernel/traps.c | 6 +-- arch/mips/mm/c-r4k.c | 12 ++--- arch/mips/mm/c-tx39.c | 6 +-- arch/mips/mm/dma-default.c | 4 +- arch/mips/mm/pg-r4k.c | 2 +- arch/mips/mm/tlbex.c | 10 ++-- arch/mips/oprofile/common.c | 2 +- arch/mips/oprofile/op_model_mipsxx.c | 4 +- arch/mips/pci/pci-vr41xx.c | 2 +- arch/mips/vr41xx/common/bcu.c | 8 +-- arch/mips/vr41xx/common/cmu.c | 16 +++--- arch/mips/vr41xx/common/giu.c | 2 +- arch/mips/vr41xx/common/icu.c | 76 ++++++++++++++-------------- arch/mips/vr41xx/common/pmu.c | 4 +- arch/mips/vr41xx/common/rtc.c | 2 +- arch/mips/vr41xx/common/siu.c | 2 +- include/asm-mips/cpu-features.h | 5 +- 20 files changed, 89 insertions(+), 86 deletions(-) diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c index 6d55e8aab668..6a17c9b508ea 100644 --- a/arch/mips/dec/ecc-berr.c +++ b/arch/mips/dec/ecc-berr.c @@ -263,7 +263,7 @@ static inline void dec_kn03_be_init(void) */ *mcr = (*mcr & ~(KN03_MCR_DIAGCHK | KN03_MCR_DIAGGEN)) | KN03_MCR_CORRECT; - if (current_cpu_data.cputype == CPU_R4400SC) + if (current_cpu_type() == CPU_R4400SC) *mbcs |= KN4K_MB_CSR_EE; fast_iob(); } diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c index 7a053aadcd3a..5f04545c3606 100644 --- a/arch/mips/dec/kn02xa-berr.c +++ b/arch/mips/dec/kn02xa-berr.c @@ -132,7 +132,7 @@ void __init dec_kn02xa_be_init(void) volatile u32 *mbcs = (void *)CKSEG1ADDR(KN4K_SLOT_BASE + KN4K_MB_CSR); /* For KN04 we need to make sure EE (?) is enabled in the MB. */ - if (current_cpu_data.cputype == CPU_R4000SC) + if (current_cpu_type() == CPU_R4000SC) *mbcs |= KN4K_MB_CSR_EE; fast_iob(); diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c index 808c182fd3fa..93f1239af524 100644 --- a/arch/mips/dec/prom/init.c +++ b/arch/mips/dec/prom/init.c @@ -108,8 +108,8 @@ void __init prom_init(void) /* Were we compiled with the right CPU option? */ #if defined(CONFIG_CPU_R3000) - if ((current_cpu_data.cputype == CPU_R4000SC) || - (current_cpu_data.cputype == CPU_R4400SC)) { + if ((current_cpu_type() == CPU_R4000SC) || + (current_cpu_type() == CPU_R4400SC)) { static char r4k_msg[] __initdata = "Please recompile with \"CONFIG_CPU_R4x00 = y\".\n"; printk(cpu_msg); @@ -119,8 +119,8 @@ void __init prom_init(void) #endif #if defined(CONFIG_CPU_R4X00) - if ((current_cpu_data.cputype == CPU_R3000) || - (current_cpu_data.cputype == CPU_R3000A)) { + if ((current_cpu_type() == CPU_R3000) || + (current_cpu_type() == CPU_R3000A)) { static char r3k_msg[] __initdata = "Please recompile with \"CONFIG_CPU_R3000 = y\".\n"; printk(cpu_msg); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index d96f8218a91e..ac762d8d802d 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -954,7 +954,7 @@ asmlinkage void do_reserved(struct pt_regs *regs) */ static inline void parity_protection_init(void) { - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_24K: case CPU_34K: case CPU_5KC: @@ -1549,8 +1549,8 @@ void __init trap_init(void) set_except_vector(12, handle_ov); set_except_vector(13, handle_tr); - if (current_cpu_data.cputype == CPU_R6000 || - current_cpu_data.cputype == CPU_R6000A) { + if (current_cpu_type() == CPU_R6000 || + current_cpu_type() == CPU_R6000A) { /* * The R6000 is the only R-series CPU that features a machine * check exception (similar to the R4000 cache error) and diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index cf48371e5690..8b7b7c57baca 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -328,7 +328,7 @@ static inline void local_r4k___flush_cache_all(void * args) r4k_blast_dcache(); r4k_blast_icache(); - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_R4000SC: case CPU_R4000MC: case CPU_R4400SC: @@ -377,10 +377,10 @@ static inline void local_r4k_flush_cache_mm(void * args) * R4000SC and R4400SC indexed S-cache ops also invalidate primary * caches, so we can bail out early. */ - if (current_cpu_data.cputype == CPU_R4000SC || - current_cpu_data.cputype == CPU_R4000MC || - current_cpu_data.cputype == CPU_R4400SC || - current_cpu_data.cputype == CPU_R4400MC) { + if (current_cpu_type() == CPU_R4000SC || + current_cpu_type() == CPU_R4000MC || + current_cpu_type() == CPU_R4400SC || + current_cpu_type() == CPU_R4400MC) { r4k_blast_scache(); return; } @@ -1197,7 +1197,7 @@ static void __init coherency_setup(void) * this bit and; some wire it to zero, others like Toshiba had the * silly idea of putting something else there ... */ - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_R4000PC: case CPU_R4000SC: case CPU_R4000MC: diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index 560a6de96556..9ea121e8cdce 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c @@ -69,7 +69,7 @@ static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size) /* TX39H2,TX39H3 */ static inline void tx39_blast_dcache_page(unsigned long addr) { - if (current_cpu_data.cputype != CPU_TX3912) + if (current_cpu_type() != CPU_TX3912) blast_dcache16_page(addr); } @@ -307,7 +307,7 @@ static __init void tx39_probe_cache(void) TX39_CONF_DCS_SHIFT)); current_cpu_data.icache.linesz = 16; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_TX3912: current_cpu_data.icache.ways = 1; current_cpu_data.dcache.ways = 1; @@ -341,7 +341,7 @@ void __init tx39_cache_init(void) tx39_probe_cache(); - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_TX3912: /* TX39/H core (writethru direct-map cache) */ flush_cache_all = tx39h_flush_icache_all; diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index f60b3dc0fc62..98b5e5bac02e 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -35,8 +35,8 @@ static inline unsigned long dma_addr_to_virt(dma_addr_t dma_addr) static inline int cpu_is_noncoherent_r10000(struct device *dev) { return !plat_device_is_coherent(dev) && - (current_cpu_data.cputype == CPU_R10000 || - current_cpu_data.cputype == CPU_R12000); + (current_cpu_type() == CPU_R10000 || + current_cpu_type() == CPU_R12000); } void *dma_alloc_noncoherent(struct device *dev, size_t size, diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c index c0294541d295..4f770ac885ce 100644 --- a/arch/mips/mm/pg-r4k.c +++ b/arch/mips/mm/pg-r4k.c @@ -354,7 +354,7 @@ void __init build_clear_page(void) store_offset = 0; if (cpu_has_prefetch) { - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_TX49XX: /* TX49 supports only Pref_Load */ pref_offset_clear = 0; diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 73250741a0f9..c3da4fefbcb4 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -827,7 +827,7 @@ static __initdata u32 final_handler[64]; */ static __init void __maybe_unused build_tlb_probe_entry(u32 **p) { - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { /* Found by experiment: R4600 v2.0 needs this, too. */ case CPU_R4600: case CPU_R5000: @@ -860,7 +860,7 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l, case tlb_indexed: tlbw = i_tlbwi; break; } - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_R4000PC: case CPU_R4000SC: case CPU_R4000MC: @@ -1158,7 +1158,7 @@ static __init void build_adjust_context(u32 **p, unsigned int ctx) unsigned int shift = 4 - (PTE_T_LOG2 + 1) + PAGE_SHIFT - 12; unsigned int mask = (PTRS_PER_PTE / 2 - 1) << (PTE_T_LOG2 + 1); - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR41XX: case CPU_VR4111: case CPU_VR4121: @@ -1188,7 +1188,7 @@ static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr) * in a different cacheline or a load instruction, probably any * memory reference, is between them. */ - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_NEVADA: i_LW(p, ptr, 0, ptr); GET_CONTEXT(p, tmp); /* get context reg */ @@ -1872,7 +1872,7 @@ void __init build_tlb_refill_handler(void) */ static int run_once = 0; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_R2000: case CPU_R3000: case CPU_R3000A: diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index 4e0a90b3916b..aa52aa146cea 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -74,7 +74,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) struct op_mips_model *lmodel = NULL; int res; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_5KC: case CPU_20KC: case CPU_24K: diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 1ea5c9c1010b..6383000422ab 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -222,7 +222,7 @@ static inline int n_counters(void) { int counters; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_R10000: counters = 2; break; @@ -274,7 +274,7 @@ static int __init mipsxx_init(void) #endif op_model_mipsxx_ops.num_counters = counters; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_20KC: op_model_mipsxx_ops.cpu_type = "mips/20K"; break; diff --git a/arch/mips/pci/pci-vr41xx.c b/arch/mips/pci/pci-vr41xx.c index 9885fa403603..240df9e33813 100644 --- a/arch/mips/pci/pci-vr41xx.c +++ b/arch/mips/pci/pci-vr41xx.c @@ -228,7 +228,7 @@ static int __init vr41xx_pciu_init(void) else pciu_write(PCIEXACCREG, 0); - if (current_cpu_data.cputype == CPU_VR4122) + if (current_cpu_type() == CPU_VR4122) pciu_write(PCITRDYVREG, TRDYV(setup->wait_time_limit_from_irdy_to_trdy)); pciu_write(LATTIMEREG, MLTIM(setup->master_latency_timer)); diff --git a/arch/mips/vr41xx/common/bcu.c b/arch/mips/vr41xx/common/bcu.c index ff272b2e8395..d77c330a0d59 100644 --- a/arch/mips/vr41xx/common/bcu.c +++ b/arch/mips/vr41xx/common/bcu.c @@ -70,7 +70,7 @@ EXPORT_SYMBOL_GPL(vr41xx_get_tclock_frequency); static inline uint16_t read_clkspeed(void) { - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: case CPU_VR4121: return readw(CLKSPEEDREG_TYPE1); case CPU_VR4122: @@ -88,7 +88,7 @@ static inline unsigned long calculate_pclock(uint16_t clkspeed) { unsigned long pclock = 0; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: case CPU_VR4121: pclock = 18432000 * 64; @@ -138,7 +138,7 @@ static inline unsigned long calculate_vtclock(uint16_t clkspeed, unsigned long p { unsigned long vtclock = 0; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: /* The NEC VR4111 doesn't have the VTClock. */ break; @@ -180,7 +180,7 @@ static inline unsigned long calculate_tclock(uint16_t clkspeed, unsigned long pc { unsigned long tclock = 0; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: if (!(clkspeed & DIV2B)) tclock = pclock / 2; diff --git a/arch/mips/vr41xx/common/cmu.c b/arch/mips/vr41xx/common/cmu.c index 657c5133c933..ad0e8e3409d9 100644 --- a/arch/mips/vr41xx/common/cmu.c +++ b/arch/mips/vr41xx/common/cmu.c @@ -95,8 +95,8 @@ void vr41xx_supply_clock(vr41xx_clock_t clock) cmuclkmsk |= MSKFIR | MSKFFIR; break; case DSIU_CLOCK: - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) cmuclkmsk |= MSKDSIU; else cmuclkmsk |= MSKSIU | MSKDSIU; @@ -146,8 +146,8 @@ void vr41xx_mask_clock(vr41xx_clock_t clock) cmuclkmsk &= ~MSKPIU; break; case SIU_CLOCK: - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) { + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) { cmuclkmsk &= ~(MSKSIU | MSKSSIU); } else { if (cmuclkmsk & MSKDSIU) @@ -166,8 +166,8 @@ void vr41xx_mask_clock(vr41xx_clock_t clock) cmuclkmsk &= ~(MSKFIR | MSKFFIR); break; case DSIU_CLOCK: - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) { + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) { cmuclkmsk &= ~MSKDSIU; } else { if (cmuclkmsk & MSKSSIU) @@ -216,7 +216,7 @@ static int __init vr41xx_cmu_init(void) { unsigned long start, size; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: case CPU_VR4121: start = CMU_TYPE1_BASE; @@ -246,7 +246,7 @@ static int __init vr41xx_cmu_init(void) } cmuclkmsk = cmu_read(CMUCLKMSK); - if (current_cpu_data.cputype == CPU_VR4133) + if (current_cpu_type() == CPU_VR4133) cmuclkmsk2 = cmu_read(CMUCLKMSK2); spin_lock_init(&cmu_lock); diff --git a/arch/mips/vr41xx/common/giu.c b/arch/mips/vr41xx/common/giu.c index d21f6f2d22a3..2b272f1496fe 100644 --- a/arch/mips/vr41xx/common/giu.c +++ b/arch/mips/vr41xx/common/giu.c @@ -81,7 +81,7 @@ static int __init vr41xx_giu_add(void) if (!pdev) return -ENOMEM; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: case CPU_VR4121: pdev->id = GPIO_50PINS_PULLUPDOWN; diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index adabc6bad440..1899601e5862 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c @@ -157,8 +157,8 @@ void vr41xx_enable_piuint(uint16_t mask) struct irq_desc *desc = irq_desc + PIU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) { + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) { spin_lock_irqsave(&desc->lock, flags); icu1_set(MPIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); @@ -172,8 +172,8 @@ void vr41xx_disable_piuint(uint16_t mask) struct irq_desc *desc = irq_desc + PIU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) { + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) { spin_lock_irqsave(&desc->lock, flags); icu1_clear(MPIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); @@ -187,8 +187,8 @@ void vr41xx_enable_aiuint(uint16_t mask) struct irq_desc *desc = irq_desc + AIU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) { + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) { spin_lock_irqsave(&desc->lock, flags); icu1_set(MAIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); @@ -202,8 +202,8 @@ void vr41xx_disable_aiuint(uint16_t mask) struct irq_desc *desc = irq_desc + AIU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) { + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) { spin_lock_irqsave(&desc->lock, flags); icu1_clear(MAIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); @@ -217,8 +217,8 @@ void vr41xx_enable_kiuint(uint16_t mask) struct irq_desc *desc = irq_desc + KIU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) { + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) { spin_lock_irqsave(&desc->lock, flags); icu1_set(MKIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); @@ -232,8 +232,8 @@ void vr41xx_disable_kiuint(uint16_t mask) struct irq_desc *desc = irq_desc + KIU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4111 || - current_cpu_data.cputype == CPU_VR4121) { + if (current_cpu_type() == CPU_VR4111 || + current_cpu_type() == CPU_VR4121) { spin_lock_irqsave(&desc->lock, flags); icu1_clear(MKIUINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); @@ -319,9 +319,9 @@ void vr41xx_enable_pciint(void) struct irq_desc *desc = irq_desc + PCI_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4122 || - current_cpu_data.cputype == CPU_VR4131 || - current_cpu_data.cputype == CPU_VR4133) { + if (current_cpu_type() == CPU_VR4122 || + current_cpu_type() == CPU_VR4131 || + current_cpu_type() == CPU_VR4133) { spin_lock_irqsave(&desc->lock, flags); icu2_write(MPCIINTREG, PCIINT0); spin_unlock_irqrestore(&desc->lock, flags); @@ -335,9 +335,9 @@ void vr41xx_disable_pciint(void) struct irq_desc *desc = irq_desc + PCI_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4122 || - current_cpu_data.cputype == CPU_VR4131 || - current_cpu_data.cputype == CPU_VR4133) { + if (current_cpu_type() == CPU_VR4122 || + current_cpu_type() == CPU_VR4131 || + current_cpu_type() == CPU_VR4133) { spin_lock_irqsave(&desc->lock, flags); icu2_write(MPCIINTREG, 0); spin_unlock_irqrestore(&desc->lock, flags); @@ -351,9 +351,9 @@ void vr41xx_enable_scuint(void) struct irq_desc *desc = irq_desc + SCU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4122 || - current_cpu_data.cputype == CPU_VR4131 || - current_cpu_data.cputype == CPU_VR4133) { + if (current_cpu_type() == CPU_VR4122 || + current_cpu_type() == CPU_VR4131 || + current_cpu_type() == CPU_VR4133) { spin_lock_irqsave(&desc->lock, flags); icu2_write(MSCUINTREG, SCUINT0); spin_unlock_irqrestore(&desc->lock, flags); @@ -367,9 +367,9 @@ void vr41xx_disable_scuint(void) struct irq_desc *desc = irq_desc + SCU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4122 || - current_cpu_data.cputype == CPU_VR4131 || - current_cpu_data.cputype == CPU_VR4133) { + if (current_cpu_type() == CPU_VR4122 || + current_cpu_type() == CPU_VR4131 || + current_cpu_type() == CPU_VR4133) { spin_lock_irqsave(&desc->lock, flags); icu2_write(MSCUINTREG, 0); spin_unlock_irqrestore(&desc->lock, flags); @@ -383,9 +383,9 @@ void vr41xx_enable_csiint(uint16_t mask) struct irq_desc *desc = irq_desc + CSI_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4122 || - current_cpu_data.cputype == CPU_VR4131 || - current_cpu_data.cputype == CPU_VR4133) { + if (current_cpu_type() == CPU_VR4122 || + current_cpu_type() == CPU_VR4131 || + current_cpu_type() == CPU_VR4133) { spin_lock_irqsave(&desc->lock, flags); icu2_set(MCSIINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); @@ -399,9 +399,9 @@ void vr41xx_disable_csiint(uint16_t mask) struct irq_desc *desc = irq_desc + CSI_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4122 || - current_cpu_data.cputype == CPU_VR4131 || - current_cpu_data.cputype == CPU_VR4133) { + if (current_cpu_type() == CPU_VR4122 || + current_cpu_type() == CPU_VR4131 || + current_cpu_type() == CPU_VR4133) { spin_lock_irqsave(&desc->lock, flags); icu2_clear(MCSIINTREG, mask); spin_unlock_irqrestore(&desc->lock, flags); @@ -415,9 +415,9 @@ void vr41xx_enable_bcuint(void) struct irq_desc *desc = irq_desc + BCU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4122 || - current_cpu_data.cputype == CPU_VR4131 || - current_cpu_data.cputype == CPU_VR4133) { + if (current_cpu_type() == CPU_VR4122 || + current_cpu_type() == CPU_VR4131 || + current_cpu_type() == CPU_VR4133) { spin_lock_irqsave(&desc->lock, flags); icu2_write(MBCUINTREG, BCUINTR); spin_unlock_irqrestore(&desc->lock, flags); @@ -431,9 +431,9 @@ void vr41xx_disable_bcuint(void) struct irq_desc *desc = irq_desc + BCU_IRQ; unsigned long flags; - if (current_cpu_data.cputype == CPU_VR4122 || - current_cpu_data.cputype == CPU_VR4131 || - current_cpu_data.cputype == CPU_VR4133) { + if (current_cpu_type() == CPU_VR4122 || + current_cpu_type() == CPU_VR4131 || + current_cpu_type() == CPU_VR4133) { spin_lock_irqsave(&desc->lock, flags); icu2_write(MBCUINTREG, 0); spin_unlock_irqrestore(&desc->lock, flags); @@ -608,7 +608,7 @@ int vr41xx_set_intassign(unsigned int irq, unsigned char intassign) { int retval = -EINVAL; - if (current_cpu_data.cputype != CPU_VR4133) + if (current_cpu_type() != CPU_VR4133) return -EINVAL; if (intassign > INTASSIGN_MAX) @@ -665,7 +665,7 @@ static int __init vr41xx_icu_init(void) unsigned long icu1_start, icu2_start; int i; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: case CPU_VR4121: icu1_start = ICU1_TYPE1_BASE; diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c index ad5b6db53396..028aaf75eb21 100644 --- a/arch/mips/vr41xx/common/pmu.c +++ b/arch/mips/vr41xx/common/pmu.c @@ -62,7 +62,7 @@ static inline void software_reset(void) { uint16_t pmucnt2; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4122: case CPU_VR4131: case CPU_VR4133: @@ -98,7 +98,7 @@ static int __init vr41xx_pmu_init(void) { unsigned long start, size; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: case CPU_VR4121: start = PMU_TYPE1_BASE; diff --git a/arch/mips/vr41xx/common/rtc.c b/arch/mips/vr41xx/common/rtc.c index cce605b3d688..9f26c14edcac 100644 --- a/arch/mips/vr41xx/common/rtc.c +++ b/arch/mips/vr41xx/common/rtc.c @@ -82,7 +82,7 @@ static int __init vr41xx_rtc_add(void) if (!pdev) return -ENOMEM; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: case CPU_VR4121: res = rtc_type1_resource; diff --git a/arch/mips/vr41xx/common/siu.c b/arch/mips/vr41xx/common/siu.c index a1e774142163..b735f45b25f0 100644 --- a/arch/mips/vr41xx/common/siu.c +++ b/arch/mips/vr41xx/common/siu.c @@ -83,7 +83,7 @@ static int __init vr41xx_siu_add(void) if (!pdev) return -ENOMEM; - switch (current_cpu_data.cputype) { + switch (current_cpu_type()) { case CPU_VR4111: case CPU_VR4121: pdev->dev.platform_data = siu_type1_ports; diff --git a/include/asm-mips/cpu-features.h b/include/asm-mips/cpu-features.h index 81f19aebc0db..f6bd308f047f 100644 --- a/include/asm-mips/cpu-features.h +++ b/include/asm-mips/cpu-features.h @@ -9,11 +9,14 @@ #ifndef __ASM_CPU_FEATURES_H #define __ASM_CPU_FEATURES_H - #include #include #include +#ifndef current_cpu_type +#define current_cpu_type() current_cpu_data.cputype +#endif + /* * SMP assumption: Options of CPU 0 are a superset of all processors. * This is true for all known MIPS systems. From 49a89efbbbcc178a39555c43bd59a7593c429664 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:15 +0100 Subject: [PATCH 2265/2804] [MIPS] Fix "no space between function name and open parenthesis" warnings. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/dbdma.c | 2 +- arch/mips/au1000/common/reset.c | 2 +- arch/mips/au1000/common/time.c | 2 +- arch/mips/au1000/db1x00/board_setup.c | 2 +- arch/mips/au1000/db1x00/init.c | 6 +- arch/mips/au1000/mtx-1/board_setup.c | 2 +- arch/mips/au1000/pb1000/board_setup.c | 2 +- arch/mips/au1000/pb1100/board_setup.c | 2 +- arch/mips/au1000/pb1200/board_setup.c | 8 +- arch/mips/au1000/pb1500/board_setup.c | 2 +- arch/mips/au1000/pb1550/board_setup.c | 2 +- arch/mips/au1000/xxs1500/board_setup.c | 2 +- arch/mips/basler/excite/excite_setup.c | 12 +- arch/mips/boot/addinitrd.c | 52 +- arch/mips/fw/arc/memory.c | 6 +- arch/mips/jazz/reset.c | 4 +- arch/mips/jazz/setup.c | 6 +- arch/mips/kernel/cpu-bugs64.c | 2 +- arch/mips/kernel/gdb-stub.c | 4 +- arch/mips/kernel/i8259.c | 2 +- arch/mips/kernel/irixelf.c | 32 +- arch/mips/kernel/irixinv.c | 42 +- arch/mips/kernel/irixioctl.c | 2 +- arch/mips/kernel/irq-msc01.c | 4 +- arch/mips/kernel/kspd.c | 10 +- arch/mips/kernel/linux32.c | 14 +- arch/mips/kernel/mips-mt.c | 2 +- arch/mips/kernel/process.c | 4 +- arch/mips/kernel/ptrace.c | 50 +- arch/mips/kernel/ptrace32.c | 16 +- arch/mips/kernel/signal32.c | 44 +- arch/mips/kernel/signal_n32.c | 4 +- arch/mips/kernel/smp-mt.c | 2 +- arch/mips/kernel/smtc.c | 4 +- arch/mips/kernel/syscall.c | 58 +- arch/mips/kernel/sysirix.c | 20 +- arch/mips/kernel/time.c | 2 +- arch/mips/kernel/traps.c | 26 +- arch/mips/kernel/unaligned.c | 2 +- arch/mips/lib/ucmpdi2.c | 2 +- arch/mips/math-emu/cp1emu.c | 8 +- arch/mips/mips-boards/atlas/atlas_int.c | 22 +- arch/mips/mips-boards/atlas/atlas_setup.c | 2 +- arch/mips/mips-boards/generic/init.c | 12 +- arch/mips/mips-boards/generic/memory.c | 4 +- arch/mips/mips-boards/generic/pci.c | 2 +- arch/mips/mips-boards/generic/time.c | 6 +- arch/mips/mips-boards/malta/malta_int.c | 34 +- arch/mips/mips-boards/malta/malta_setup.c | 10 +- arch/mips/mips-boards/sead/sead_int.c | 2 +- arch/mips/mips-boards/sead/sead_setup.c | 2 +- arch/mips/mipssim/sim_int.c | 2 +- arch/mips/mipssim/sim_mem.c | 4 +- arch/mips/mipssim/sim_time.c | 2 +- arch/mips/mm/c-r3k.c | 12 +- arch/mips/mm/sc-mips.c | 2 +- arch/mips/mm/tlb-r4k.c | 2 +- arch/mips/oprofile/op_model_mipsxx.c | 2 +- arch/mips/oprofile/op_model_rm9000.c | 2 +- arch/mips/pci/fixup-atlas.c | 6 +- arch/mips/pci/ops-au1000.c | 2 +- arch/mips/pci/ops-sni.c | 22 +- arch/mips/philips/pnx8550/common/proc.c | 4 +- arch/mips/pmc-sierra/msp71xx/msp_usb.c | 8 +- arch/mips/qemu/q-firmware.c | 2 +- arch/mips/sgi-ip22/ip22-eisa.c | 2 +- arch/mips/sgi-ip22/ip22-int.c | 2 +- arch/mips/sgi-ip32/crime.c | 6 +- arch/mips/sgi-ip32/ip32-irq.c | 26 +- arch/mips/sgi-ip32/ip32-memory.c | 4 +- arch/mips/sibyte/common/sb_tbprof.c | 4 +- arch/mips/sni/a20r.c | 6 +- arch/mips/sni/pcimt.c | 4 +- arch/mips/sni/pcit.c | 26 +- arch/mips/sni/rm200.c | 10 +- arch/mips/sni/setup.c | 6 +- arch/mips/sni/sniprom.c | 6 +- arch/mips/sni/time.c | 16 +- include/asm-mips/asmmacro.h | 12 +- include/asm-mips/bitops.h | 12 +- include/asm-mips/byteorder.h | 4 +- include/asm-mips/elf.h | 2 +- include/asm-mips/fixmap.h | 4 +- include/asm-mips/futex.h | 2 +- include/asm-mips/inventory.h | 4 +- include/asm-mips/irqflags.h | 10 +- include/asm-mips/mach-au1x00/au1000.h | 618 +++++++++--------- include/asm-mips/mach-au1x00/au1xxx_ide.h | 2 +- include/asm-mips/mach-ip32/kmalloc.h | 2 +- include/asm-mips/mach-pb1x00/pb1000.h | 54 +- include/asm-mips/mach-pb1x00/pb1100.h | 60 +- .../asm-mips/mach-pnx8550/kernel-entry-init.h | 24 +- include/asm-mips/parport.h | 6 +- include/asm-mips/prctl.h | 2 +- include/asm-mips/semaphore.h | 6 +- include/asm-mips/sim.h | 4 +- include/asm-mips/sn/addrs.h | 44 +- include/asm-mips/sn/io.h | 2 +- include/asm-mips/sn/kldir.h | 2 +- include/asm-mips/sn/sn0/addrs.h | 8 +- include/asm-mips/sni.h | 18 +- include/asm-mips/system.h | 6 +- include/asm-mips/timex.h | 2 +- include/asm-mips/uaccess.h | 18 +- 104 files changed, 842 insertions(+), 842 deletions(-) diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c index 626de44bd888..d15b047d480d 100644 --- a/arch/mips/au1000/common/dbdma.c +++ b/arch/mips/au1000/common/dbdma.c @@ -184,7 +184,7 @@ static dbdev_tab_t dbdev_tab[] = { static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS]; static dbdev_tab_t * -find_dbdev_id (u32 id) +find_dbdev_id(u32 id) { int i; dbdev_tab_t *p; diff --git a/arch/mips/au1000/common/reset.c b/arch/mips/au1000/common/reset.c index de5447e83849..b8638d293cf9 100644 --- a/arch/mips/au1000/common/reset.c +++ b/arch/mips/au1000/common/reset.c @@ -42,7 +42,7 @@ extern void (*flush_cache_all)(void); void au1000_restart(char *command) { /* Set all integrated peripherals to disabled states */ - extern void board_reset (void); + extern void board_reset(void); u32 prid = read_c0_prid(); printk(KERN_NOTICE "\n** Resetting Integrated Peripherals\n"); diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 726c340460b6..2556399708ba 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -200,7 +200,7 @@ unsigned long cal_r4koff(void) while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); - au_writel (0, SYS_TOYWRITE); + au_writel(0, SYS_TOYWRITE); while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/au1000/db1x00/board_setup.c index 8b08edb977be..99eafeada518 100644 --- a/arch/mips/au1000/db1x00/board_setup.c +++ b/arch/mips/au1000/db1x00/board_setup.c @@ -46,7 +46,7 @@ static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR; -void board_reset (void) +void board_reset(void) { /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ bcsr->swreset = 0x0000; diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c index e6bdd07cc093..4d7bcfc8cf73 100644 --- a/arch/mips/au1000/db1x00/init.c +++ b/arch/mips/au1000/db1x00/init.c @@ -60,11 +60,11 @@ void __init prom_init(void) prom_envp = (char **) fw_arg2; /* Set the platform # */ -#if defined (CONFIG_MIPS_DB1550) +#if defined(CONFIG_MIPS_DB1550) mips_machtype = MACH_DB1550; -#elif defined (CONFIG_MIPS_DB1500) +#elif defined(CONFIG_MIPS_DB1500) mips_machtype = MACH_DB1500; -#elif defined (CONFIG_MIPS_DB1100) +#elif defined(CONFIG_MIPS_DB1100) mips_machtype = MACH_DB1100; #else mips_machtype = MACH_DB1000; diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c index 2c460c116570..abfc4bcddf7a 100644 --- a/arch/mips/au1000/mtx-1/board_setup.c +++ b/arch/mips/au1000/mtx-1/board_setup.c @@ -46,7 +46,7 @@ extern int (*board_pci_idsel)(unsigned int devsel, int assert); int mtx1_pci_idsel(unsigned int devsel, int assert); -void board_reset (void) +void board_reset(void) { /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ au_writel(0x00000000, 0xAE00001C); diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c index 0aed89114bfc..5198c4f98b43 100644 --- a/arch/mips/au1000/pb1000/board_setup.c +++ b/arch/mips/au1000/pb1000/board_setup.c @@ -39,7 +39,7 @@ #include #include -void board_reset (void) +void board_reset(void) { } diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c index 259ca05860c3..42874a6b31d1 100644 --- a/arch/mips/au1000/pb1100/board_setup.c +++ b/arch/mips/au1000/pb1100/board_setup.c @@ -39,7 +39,7 @@ #include #include -void board_reset (void) +void board_reset(void) { /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ au_writel(0x00000000, 0xAE00001C); diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/au1000/pb1200/board_setup.c index eea2092bde8d..2122515f79d7 100644 --- a/arch/mips/au1000/pb1200/board_setup.c +++ b/arch/mips/au1000/pb1200/board_setup.c @@ -57,7 +57,7 @@ extern void _board_init_irq(void); extern void (*board_init_irq)(void); -void board_reset (void) +void board_reset(void) { bcsr->resets = 0; bcsr->system = 0; @@ -148,7 +148,7 @@ void __init board_setup(void) } int -board_au1200fb_panel (void) +board_au1200fb_panel(void) { BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; int p; @@ -160,7 +160,7 @@ board_au1200fb_panel (void) } int -board_au1200fb_panel_init (void) +board_au1200fb_panel_init(void) { /* Apply power */ BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; @@ -170,7 +170,7 @@ board_au1200fb_panel_init (void) } int -board_au1200fb_panel_shutdown (void) +board_au1200fb_panel_shutdown(void) { /* Remove power */ BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/au1000/pb1500/board_setup.c index a2d850db8902..5446836869d6 100644 --- a/arch/mips/au1000/pb1500/board_setup.c +++ b/arch/mips/au1000/pb1500/board_setup.c @@ -39,7 +39,7 @@ #include #include -void board_reset (void) +void board_reset(void) { /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ au_writel(0x00000000, 0xAE00001C); diff --git a/arch/mips/au1000/pb1550/board_setup.c b/arch/mips/au1000/pb1550/board_setup.c index 05fd27dc24e6..e3cfb0d73180 100644 --- a/arch/mips/au1000/pb1550/board_setup.c +++ b/arch/mips/au1000/pb1550/board_setup.c @@ -44,7 +44,7 @@ #include #include -void board_reset (void) +void board_reset(void) { /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ au_writew(au_readw(0xAF00001C) & ~(1<<15), 0xAF00001C); diff --git a/arch/mips/au1000/xxs1500/board_setup.c b/arch/mips/au1000/xxs1500/board_setup.c index ae3d6b19e94d..a9237f41933d 100644 --- a/arch/mips/au1000/xxs1500/board_setup.c +++ b/arch/mips/au1000/xxs1500/board_setup.c @@ -39,7 +39,7 @@ #include #include -void board_reset (void) +void board_reset(void) { /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ au_writel(0x00000000, 0xAE00001C); diff --git a/arch/mips/basler/excite/excite_setup.c b/arch/mips/basler/excite/excite_setup.c index 68be19d1802e..404ca9284b30 100644 --- a/arch/mips/basler/excite/excite_setup.c +++ b/arch/mips/basler/excite/excite_setup.c @@ -216,7 +216,7 @@ static int __init excite_platform_init(void) titan_writel(0x80021dff, GXCFG); /* XDMA reset */ titan_writel(0x00000000, CPXCISRA); titan_writel(0x00000000, CPXCISRB); /* clear pending interrupts */ -#if defined (CONFIG_HIGHMEM) +#if defined(CONFIG_HIGHMEM) # error change for HIGHMEM support! #else titan_writel(0x00000000, GXDMADRPFX); /* buffer address prefix */ @@ -262,12 +262,12 @@ void __init plat_mem_setup(void) add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); /* Set up the peripheral address map */ - *(boot_ocd_base + (LKB9 / sizeof (u32))) = 0; - *(boot_ocd_base + (LKB10 / sizeof (u32))) = 0; - *(boot_ocd_base + (LKB11 / sizeof (u32))) = 0; - *(boot_ocd_base + (LKB12 / sizeof (u32))) = 0; + *(boot_ocd_base + (LKB9 / sizeof(u32))) = 0; + *(boot_ocd_base + (LKB10 / sizeof(u32))) = 0; + *(boot_ocd_base + (LKB11 / sizeof(u32))) = 0; + *(boot_ocd_base + (LKB12 / sizeof(u32))) = 0; wmb(); - *(boot_ocd_base + (LKB0 / sizeof (u32))) = EXCITE_PHYS_OCD >> 4; + *(boot_ocd_base + (LKB0 / sizeof(u32))) = EXCITE_PHYS_OCD >> 4; wmb(); ocd_writel((EXCITE_PHYS_TITAN >> 4) | 0x1UL, LKB5); diff --git a/arch/mips/boot/addinitrd.c b/arch/mips/boot/addinitrd.c index 8b3033304770..193e4be52e79 100644 --- a/arch/mips/boot/addinitrd.c +++ b/arch/mips/boot/addinitrd.c @@ -32,13 +32,13 @@ #define SWAB(a) (swab ? swab32(a) : (a)) -void die (char *s) +void die(char *s) { - perror (s); - exit (1); + perror(s); + exit(1); } -int main (int argc, char *argv[]) +int main(int argc, char *argv[]) { int fd_vmlinux,fd_initrd,fd_outfile; FILHDR efile; @@ -52,18 +52,18 @@ int main (int argc, char *argv[]) int swab = 0; if (argc != 4) { - printf ("Usage: %s \n",argv[0]); - exit (1); + printf("Usage: %s \n",argv[0]); + exit(1); } if ((fd_vmlinux = open (argv[1],O_RDONLY)) < 0) - die ("open vmlinux"); + die("open vmlinux"); if (read (fd_vmlinux, &efile, sizeof efile) != sizeof efile) - die ("read file header"); + die("read file header"); if (read (fd_vmlinux, &eaout, sizeof eaout) != sizeof eaout) - die ("read aout header"); + die("read aout header"); if (read (fd_vmlinux, esecs, sizeof esecs) != sizeof esecs) - die ("read section headers"); + die("read section headers"); /* * check whether the file is good for us */ @@ -82,13 +82,13 @@ int main (int argc, char *argv[]) /* make sure we have an empty data segment for the initrd */ if (eaout.dsize || esecs[1].s_size) { - fprintf (stderr, "Data segment not empty. Giving up!\n"); - exit (1); + fprintf(stderr, "Data segment not empty. Giving up!\n"); + exit(1); } if ((fd_initrd = open (argv[2], O_RDONLY)) < 0) - die ("open initrd"); + die("open initrd"); if (fstat (fd_initrd, &st) < 0) - die ("fstat initrd"); + die("fstat initrd"); loadaddr = ((SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size) + MIPS_PAGE_SIZE-1) & ~MIPS_PAGE_MASK) - 8; if (loadaddr < (SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size))) @@ -99,33 +99,33 @@ int main (int argc, char *argv[]) eaout.data_start = esecs[1].s_vaddr = esecs[1].s_paddr = SWAB(loadaddr); if ((fd_outfile = open (argv[3], O_RDWR|O_CREAT|O_TRUNC,0666)) < 0) - die ("open outfile"); + die("open outfile"); if (write (fd_outfile, &efile, sizeof efile) != sizeof efile) - die ("write file header"); + die("write file header"); if (write (fd_outfile, &eaout, sizeof eaout) != sizeof eaout) - die ("write aout header"); + die("write aout header"); if (write (fd_outfile, esecs, sizeof esecs) != sizeof esecs) - die ("write section headers"); + die("write section headers"); /* skip padding */ if(lseek(fd_vmlinux, SWAB(esecs[0].s_scnptr), SEEK_SET) == (off_t)-1) - die ("lseek vmlinux"); + die("lseek vmlinux"); if(lseek(fd_outfile, SWAB(esecs[0].s_scnptr), SEEK_SET) == (off_t)-1) - die ("lseek outfile"); + die("lseek outfile"); /* copy text segment */ cnt = SWAB(eaout.tsize); while (cnt) { if ((i = read (fd_vmlinux, buf, sizeof buf)) <= 0) - die ("read vmlinux"); + die("read vmlinux"); if (write (fd_outfile, buf, i) != i) - die ("write vmlinux"); + die("write vmlinux"); cnt -= i; } if (write (fd_outfile, initrd_header, sizeof initrd_header) != sizeof initrd_header) - die ("write initrd header"); + die("write initrd header"); while ((i = read (fd_initrd, buf, sizeof buf)) > 0) if (write (fd_outfile, buf, i) != i) - die ("write initrd"); - close (fd_vmlinux); - close (fd_initrd); + die("write initrd"); + close(fd_vmlinux); + close(fd_initrd); return 0; } diff --git a/arch/mips/fw/arc/memory.c b/arch/mips/fw/arc/memory.c index 83d15791ef6a..8b8eea2b6cf6 100644 --- a/arch/mips/fw/arc/memory.c +++ b/arch/mips/fw/arc/memory.c @@ -63,7 +63,7 @@ static char *arc_mtypes[8] = { : arc_mtypes[a.arc] #endif -static inline int memtype_classify_arcs (union linux_memtypes type) +static inline int memtype_classify_arcs(union linux_memtypes type) { switch (type.arcs) { case arcs_fcontig: @@ -83,7 +83,7 @@ static inline int memtype_classify_arcs (union linux_memtypes type) while(1); /* Nuke warning. */ } -static inline int memtype_classify_arc (union linux_memtypes type) +static inline int memtype_classify_arc(union linux_memtypes type) { switch (type.arc) { case arc_free: @@ -103,7 +103,7 @@ static inline int memtype_classify_arc (union linux_memtypes type) while(1); /* Nuke warning. */ } -static int __init prom_memtype_classify (union linux_memtypes type) +static int __init prom_memtype_classify(union linux_memtypes type) { if (prom_flags & PROM_FLAG_ARCS) /* SGI is ``different'' ... */ return memtype_classify_arcs(type); diff --git a/arch/mips/jazz/reset.c b/arch/mips/jazz/reset.c index d8ade85060b3..dd889fe86bd1 100644 --- a/arch/mips/jazz/reset.c +++ b/arch/mips/jazz/reset.c @@ -49,8 +49,8 @@ void jazz_machine_restart(char *command) { while(1) { kb_wait(); - jazz_write_command (0xd1); + jazz_write_command(0xd1); kb_wait(); - jazz_write_output (0x00); + jazz_write_output(0x00); } } diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 2a7ec08b6bad..cfc7dce78dab 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -74,11 +74,11 @@ void __init plat_mem_setup(void) int i; /* Map 0xe0000000 -> 0x0:800005C0, 0xe0010000 -> 0x1:30000580 */ - add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K); + add_wired_entry(0x02000017, 0x03c00017, 0xe0000000, PM_64K); /* Map 0xe2000000 -> 0x0:900005C0, 0xe3010000 -> 0x0:910005C0 */ - add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M); + add_wired_entry(0x02400017, 0x02440017, 0xe2000000, PM_16M); /* Map 0xe4000000 -> 0x0:600005C0, 0xe4100000 -> 400005C0 */ - add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M); + add_wired_entry(0x01800017, 0x01000017, 0xe4000000, PM_4M); set_io_port_base(JAZZ_PORT_BASE); #ifdef CONFIG_EISA diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c index 6648fde20b96..af78456d4138 100644 --- a/arch/mips/kernel/cpu-bugs64.c +++ b/arch/mips/kernel/cpu-bugs64.c @@ -29,7 +29,7 @@ static inline void align_mod(const int align, const int mod) ".endr\n\t" ".set pop" : - : GCC_IMM_ASM (align), GCC_IMM_ASM (mod)); + : GCC_IMM_ASM(align), GCC_IMM_ASM(mod)); } static inline void mult_sh_align_mod(long *v1, long *v2, long *w, diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index cb5623aad552..989d06c3827b 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -733,7 +733,7 @@ static int kgdb_smp_call_kgdb_wait(void) * returns 1 if you should skip the instruction at the trap address, 0 * otherwise. */ -void handle_exception (struct gdb_regs *regs) +void handle_exception(struct gdb_regs *regs) { int trap; /* Trap type */ int sigval; @@ -917,7 +917,7 @@ void handle_exception (struct gdb_regs *regs) && hexToInt(&ptr, &length)) { if (mem2hex((char *)addr, output_buffer, length, 1)) break; - strcpy (output_buffer, "E03"); + strcpy(output_buffer, "E03"); } else strcpy(output_buffer,"E01"); break; diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index b6e5bb41b06b..a860b21e63e9 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -329,7 +329,7 @@ static struct resource pic2_io_resource = { * driver compatibility reasons interrupts 0 - 15 to be the i8259 * interrupts even if the hardware uses a different interrupt numbering. */ -void __init init_i8259_irqs (void) +void __init init_i8259_irqs(void) { int i; diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 403d96f99e77..e3b4b547a822 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -203,8 +203,8 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc, * Put the ELF interpreter info on the stack */ #define NEW_AUX_ENT(nr, id, val) \ - __put_user ((id), sp+(nr*2)); \ - __put_user ((val), sp+(nr*2+1)); \ + __put_user((id), sp+(nr*2)); \ + __put_user((val), sp+(nr*2+1)); \ sp -= 2; NEW_AUX_ENT(0, AT_NULL, 0); @@ -212,17 +212,17 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc, if (exec) { sp -= 11*2; - NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff); - NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr)); - NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum); - NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE); - NEW_AUX_ENT (4, AT_BASE, interp_load_addr); - NEW_AUX_ENT (5, AT_FLAGS, 0); - NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry); - NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid); - NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid); - NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid); - NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid); + NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff); + NEW_AUX_ENT(1, AT_PHENT, sizeof(struct elf_phdr)); + NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum); + NEW_AUX_ENT(3, AT_PAGESZ, ELF_EXEC_PAGESIZE); + NEW_AUX_ENT(4, AT_BASE, interp_load_addr); + NEW_AUX_ENT(5, AT_FLAGS, 0); + NEW_AUX_ENT(6, AT_ENTRY, (elf_addr_t) exec->e_entry); + NEW_AUX_ENT(7, AT_UID, (elf_addr_t) current->uid); + NEW_AUX_ENT(8, AT_EUID, (elf_addr_t) current->euid); + NEW_AUX_ENT(9, AT_GID, (elf_addr_t) current->gid); + NEW_AUX_ENT(10, AT_EGID, (elf_addr_t) current->egid); } #undef NEW_AUX_ENT @@ -581,7 +581,7 @@ static void irix_map_prda_page(void) struct prda *pp; down_write(¤t->mm->mmap_sem); - v = do_brk (PRDA_ADDRESS, PAGE_SIZE); + v = do_brk(PRDA_ADDRESS, PAGE_SIZE); up_write(¤t->mm->mmap_sem); if (v < 0) @@ -815,7 +815,7 @@ out_free_interp: kfree(elf_interpreter); out_free_file: out_free_ph: - kfree (elf_phdata); + kfree(elf_phdata); goto out; } @@ -1232,7 +1232,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) strlcpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); /* Try to dump the FPU. */ - prstatus.pr_fpvalid = dump_fpu (regs, &fpu); + prstatus.pr_fpvalid = dump_fpu(regs, &fpu); if (!prstatus.pr_fpvalid) { numnote--; } else { diff --git a/arch/mips/kernel/irixinv.c b/arch/mips/kernel/irixinv.c index de8584f62311..cf2dcd3d6a93 100644 --- a/arch/mips/kernel/irixinv.c +++ b/arch/mips/kernel/irixinv.c @@ -14,7 +14,7 @@ int inventory_items = 0; static inventory_t inventory [MAX_INVENTORY]; -void add_to_inventory (int class, int type, int controller, int unit, int state) +void add_to_inventory(int class, int type, int controller, int unit, int state) { inventory_t *ni = &inventory [inventory_items]; @@ -30,7 +30,7 @@ void add_to_inventory (int class, int type, int controller, int unit, int state) inventory_items++; } -int dump_inventory_to_user (void __user *userbuf, int size) +int dump_inventory_to_user(void __user *userbuf, int size) { inventory_t *inv = &inventory [0]; inventory_t __user *user = userbuf; @@ -45,7 +45,7 @@ int dump_inventory_to_user (void __user *userbuf, int size) return -EFAULT; user++; } - return inventory_items * sizeof (inventory_t); + return inventory_items * sizeof(inventory_t); } int __init init_inventory(void) @@ -55,24 +55,24 @@ int __init init_inventory(void) * most likely this will not let just anyone run the X server * until we put the right values all over the place */ - add_to_inventory (10, 3, 0, 0, 16400); - add_to_inventory (1, 1, 150, -1, 12); - add_to_inventory (1, 3, 0, 0, 8976); - add_to_inventory (1, 2, 0, 0, 8976); - add_to_inventory (4, 8, 0, 0, 2); - add_to_inventory (5, 5, 0, 0, 1); - add_to_inventory (3, 3, 0, 0, 32768); - add_to_inventory (3, 4, 0, 0, 32768); - add_to_inventory (3, 8, 0, 0, 524288); - add_to_inventory (3, 9, 0, 0, 64); - add_to_inventory (3, 1, 0, 0, 67108864); - add_to_inventory (12, 3, 0, 0, 16); - add_to_inventory (8, 7, 17, 0, 16777472); - add_to_inventory (8, 0, 0, 0, 1); - add_to_inventory (2, 1, 0, 13, 2); - add_to_inventory (2, 2, 0, 2, 0); - add_to_inventory (2, 2, 0, 1, 0); - add_to_inventory (7, 14, 0, 0, 6); + add_to_inventory(10, 3, 0, 0, 16400); + add_to_inventory(1, 1, 150, -1, 12); + add_to_inventory(1, 3, 0, 0, 8976); + add_to_inventory(1, 2, 0, 0, 8976); + add_to_inventory(4, 8, 0, 0, 2); + add_to_inventory(5, 5, 0, 0, 1); + add_to_inventory(3, 3, 0, 0, 32768); + add_to_inventory(3, 4, 0, 0, 32768); + add_to_inventory(3, 8, 0, 0, 524288); + add_to_inventory(3, 9, 0, 0, 64); + add_to_inventory(3, 1, 0, 0, 67108864); + add_to_inventory(12, 3, 0, 0, 16); + add_to_inventory(8, 7, 17, 0, 16777472); + add_to_inventory(8, 0, 0, 0, 1); + add_to_inventory(2, 1, 0, 13, 2); + add_to_inventory(2, 2, 0, 2, 0); + add_to_inventory(2, 2, 0, 1, 0); + add_to_inventory(7, 14, 0, 0, 6); return 0; } diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c index 30f9eb09db3f..2bde200d5ad0 100644 --- a/arch/mips/kernel/irixioctl.c +++ b/arch/mips/kernel/irixioctl.c @@ -238,7 +238,7 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) current->comm, current->pid, cmd); do_exit(255); #else - error = sys_ioctl (fd, cmd, arg); + error = sys_ioctl(fd, cmd, arg); #endif } diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index 1ecdd50bfc60..4edc7e451d91 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c @@ -99,7 +99,7 @@ void ll_msc_irq(void) } void -msc_bind_eic_interrupt (unsigned int irq, unsigned int set) +msc_bind_eic_interrupt(unsigned int irq, unsigned int set) { MSCIC_WRITE(MSC01_IC_RAMW, (irq<tv_sec) || - __put_user (t.tv_nsec, &interval->tv_nsec)) + __put_user(t.tv_nsec, &interval->tv_nsec)) return -EFAULT; return ret; } @@ -314,7 +314,7 @@ asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid, #ifdef CONFIG_SYSVIPC asmlinkage long -sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) +sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) { int version, err; @@ -373,7 +373,7 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) #else asmlinkage long -sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) +sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) { return -ENOSYS; } @@ -505,7 +505,7 @@ asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32) set_fs(KERNEL_DS); err = sys_ustat(dev, (struct ustat __user *)&tmp); - set_fs (old_fs); + set_fs(old_fs); if (err) goto out; diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index 56750b02ab40..3d6b1ec1f328 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -236,7 +236,7 @@ void mips_mt_set_cpuoptions(void) if (oconfig7 != nconfig7) { __asm__ __volatile("sync"); write_c0_config7(nconfig7); - ehb (); + ehb(); printk("Config7: 0x%08x\n", read_c0_config7()); } diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index f99bb4085430..11cb264f59ce 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -202,13 +202,13 @@ void elf_dump_regs(elf_greg_t *gp, struct pt_regs *regs) #endif } -int dump_task_regs (struct task_struct *tsk, elf_gregset_t *regs) +int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) { elf_dump_regs(*regs, task_pt_regs(tsk)); return 1; } -int dump_task_fpu (struct task_struct *t, elf_fpregset_t *fpr) +int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr) { memcpy(fpr, &t->thread.fpu, sizeof(current->thread.fpu)); diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index bbd57b20b43e..58aa6fec1146 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -54,7 +54,7 @@ void ptrace_disable(struct task_struct *child) * for 32-bit kernels and for 32-bit processes on a 64-bit kernel. * Registers are sign extended to fill the available space. */ -int ptrace_getregs (struct task_struct *child, __s64 __user *data) +int ptrace_getregs(struct task_struct *child, __s64 __user *data) { struct pt_regs *regs; int i; @@ -65,13 +65,13 @@ int ptrace_getregs (struct task_struct *child, __s64 __user *data) regs = task_pt_regs(child); for (i = 0; i < 32; i++) - __put_user (regs->regs[i], data + i); - __put_user (regs->lo, data + EF_LO - EF_R0); - __put_user (regs->hi, data + EF_HI - EF_R0); - __put_user (regs->cp0_epc, data + EF_CP0_EPC - EF_R0); - __put_user (regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0); - __put_user (regs->cp0_status, data + EF_CP0_STATUS - EF_R0); - __put_user (regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0); + __put_user(regs->regs[i], data + i); + __put_user(regs->lo, data + EF_LO - EF_R0); + __put_user(regs->hi, data + EF_HI - EF_R0); + __put_user(regs->cp0_epc, data + EF_CP0_EPC - EF_R0); + __put_user(regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0); + __put_user(regs->cp0_status, data + EF_CP0_STATUS - EF_R0); + __put_user(regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0); return 0; } @@ -81,7 +81,7 @@ int ptrace_getregs (struct task_struct *child, __s64 __user *data) * the 64-bit format. On a 32-bit kernel only the lower order half * (according to endianness) will be used. */ -int ptrace_setregs (struct task_struct *child, __s64 __user *data) +int ptrace_setregs(struct task_struct *child, __s64 __user *data) { struct pt_regs *regs; int i; @@ -92,17 +92,17 @@ int ptrace_setregs (struct task_struct *child, __s64 __user *data) regs = task_pt_regs(child); for (i = 0; i < 32; i++) - __get_user (regs->regs[i], data + i); - __get_user (regs->lo, data + EF_LO - EF_R0); - __get_user (regs->hi, data + EF_HI - EF_R0); - __get_user (regs->cp0_epc, data + EF_CP0_EPC - EF_R0); + __get_user(regs->regs[i], data + i); + __get_user(regs->lo, data + EF_LO - EF_R0); + __get_user(regs->hi, data + EF_HI - EF_R0); + __get_user(regs->cp0_epc, data + EF_CP0_EPC - EF_R0); /* badvaddr, status, and cause may not be written. */ return 0; } -int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) +int ptrace_getfpregs(struct task_struct *child, __u32 __user *data) { int i; unsigned int tmp; @@ -113,13 +113,13 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) if (tsk_used_math(child)) { fpureg_t *fregs = get_fpu_regs(child); for (i = 0; i < 32; i++) - __put_user (fregs[i], i + (__u64 __user *) data); + __put_user(fregs[i], i + (__u64 __user *) data); } else { for (i = 0; i < 32; i++) - __put_user ((__u64) -1, i + (__u64 __user *) data); + __put_user((__u64) -1, i + (__u64 __user *) data); } - __put_user (child->thread.fpu.fcr31, data + 64); + __put_user(child->thread.fpu.fcr31, data + 64); preempt_disable(); if (cpu_has_fpu) { @@ -142,12 +142,12 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) tmp = 0; } preempt_enable(); - __put_user (tmp, data + 65); + __put_user(tmp, data + 65); return 0; } -int ptrace_setfpregs (struct task_struct *child, __u32 __user *data) +int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) { fpureg_t *fregs; int i; @@ -158,9 +158,9 @@ int ptrace_setfpregs (struct task_struct *child, __u32 __user *data) fregs = get_fpu_regs(child); for (i = 0; i < 32; i++) - __get_user (fregs[i], i + (__u64 __user *) data); + __get_user(fregs[i], i + (__u64 __user *) data); - __get_user (child->thread.fpu.fcr31, data + 64); + __get_user(child->thread.fpu.fcr31, data + 64); /* FIR may not be written. */ @@ -390,19 +390,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } case PTRACE_GETREGS: - ret = ptrace_getregs (child, (__u64 __user *) data); + ret = ptrace_getregs(child, (__u64 __user *) data); break; case PTRACE_SETREGS: - ret = ptrace_setregs (child, (__u64 __user *) data); + ret = ptrace_setregs(child, (__u64 __user *) data); break; case PTRACE_GETFPREGS: - ret = ptrace_getfpregs (child, (__u32 __user *) data); + ret = ptrace_getfpregs(child, (__u32 __user *) data); break; case PTRACE_SETFPREGS: - ret = ptrace_setfpregs (child, (__u32 __user *) data); + ret = ptrace_setfpregs(child, (__u32 __user *) data); break; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index d9a39c169450..f2bffed94fa3 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -36,11 +36,11 @@ #include #include -int ptrace_getregs (struct task_struct *child, __s64 __user *data); -int ptrace_setregs (struct task_struct *child, __s64 __user *data); +int ptrace_getregs(struct task_struct *child, __s64 __user *data); +int ptrace_setregs(struct task_struct *child, __s64 __user *data); -int ptrace_getfpregs (struct task_struct *child, __u32 __user *data); -int ptrace_setfpregs (struct task_struct *child, __u32 __user *data); +int ptrace_getfpregs(struct task_struct *child, __u32 __user *data); +int ptrace_setfpregs(struct task_struct *child, __u32 __user *data); /* * Tracing a 32-bit process with a 64-bit strace and vice versa will not @@ -346,19 +346,19 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) } case PTRACE_GETREGS: - ret = ptrace_getregs (child, (__u64 __user *) (__u64) data); + ret = ptrace_getregs(child, (__u64 __user *) (__u64) data); break; case PTRACE_SETREGS: - ret = ptrace_setregs (child, (__u64 __user *) (__u64) data); + ret = ptrace_setregs(child, (__u64 __user *) (__u64) data); break; case PTRACE_GETFPREGS: - ret = ptrace_getfpregs (child, (__u32 __user *) (__u64) data); + ret = ptrace_getfpregs(child, (__u32 __user *) (__u64) data); break; case PTRACE_SETFPREGS: - ret = ptrace_setfpregs (child, (__u32 __user *) (__u64) data); + ret = ptrace_setfpregs(child, (__u32 __user *) (__u64) data); break; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 64b612a0a622..572c610db1b1 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -261,11 +261,11 @@ static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) default: __put_sigset_unknown_nsig(); case 2: - err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]); - err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); + err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]); + err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); case 1: - err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]); - err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); + err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]); + err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); } return err; @@ -283,12 +283,12 @@ static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) default: __get_sigset_unknown_nsig(); case 2: - err |= __get_user (sig[3], &ubuf->sig[3]); - err |= __get_user (sig[2], &ubuf->sig[2]); + err |= __get_user(sig[3], &ubuf->sig[3]); + err |= __get_user(sig[2], &ubuf->sig[2]); kbuf->sig[1] = sig[2] | (sig[3] << 32); case 1: - err |= __get_user (sig[1], &ubuf->sig[1]); - err |= __get_user (sig[0], &ubuf->sig[0]); + err |= __get_user(sig[1], &ubuf->sig[1]); + err |= __get_user(sig[0], &ubuf->sig[0]); kbuf->sig[0] = sig[0] | (sig[1] << 32); } @@ -412,10 +412,10 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) return -EFAULT; } - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL, uoss ? (stack_t __user *)&koss : NULL, usp); - set_fs (old_fs); + set_fs(old_fs); if (!ret && uoss) { if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) @@ -559,9 +559,9 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) /* It is more difficult to avoid calling this function than to call it and ignore errors. */ old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]); - set_fs (old_fs); + set_fs(old_fs); /* * Don't let your children do this ... @@ -746,11 +746,11 @@ asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, if (set && get_sigset(&new_set, set)) return -EFAULT; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL, oset ? (sigset_t __user *)&old_set : NULL, sigsetsize); - set_fs (old_fs); + set_fs(old_fs); if (!ret && oset && put_sigset(&old_set, oset)) return -EFAULT; @@ -765,9 +765,9 @@ asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset, sigset_t set; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize); - set_fs (old_fs); + set_fs(old_fs); if (!ret && put_sigset(&set, uset)) return -EFAULT; @@ -781,12 +781,12 @@ asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user * int ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&info, uinfo, 3*sizeof(int)) || - copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) + if (copy_from_user(&info, uinfo, 3*sizeof(int)) || + copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) return -EFAULT; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info); - set_fs (old_fs); + set_fs(old_fs); return ret; } @@ -801,10 +801,10 @@ sys32_waitid(int which, compat_pid_t pid, mm_segment_t old_fs = get_fs(); info.si_signo = 0; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, uru ? (struct rusage __user *) &ru : NULL); - set_fs (old_fs); + set_fs(old_fs); if (ret < 0 || info.si_signo == 0) return ret; diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index eb7e05926ebe..bb277e82d421 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -88,7 +88,7 @@ struct rt_sigframe_n32 { #endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ -extern void sigset_from_compat (sigset_t *set, compat_sigset_t *compat); +extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { @@ -105,7 +105,7 @@ asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) unewset = (compat_sigset_t __user *) regs.regs[4]; if (copy_from_user(&uset, unewset, sizeof(uset))) return -EFAULT; - sigset_from_compat (&newset, &uset); + sigset_from_compat(&newset, &uset); sigdelsetmask(&newset, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 05dcce416325..94e210cc6cb6 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -353,7 +353,7 @@ void core_send_ipi(int cpu, unsigned int action) unsigned long flags; int vpflags; - local_irq_save (flags); + local_irq_save(flags); vpflags = dvpe(); /* cant access the other CPU's registers whilst MVPE enabled */ diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 4d1ac9692dcd..770182887c5b 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -372,7 +372,7 @@ void mipsmt_prepare_cpus(void) cpu++; /* Report on boot-time options */ - mips_mt_set_cpuoptions (); + mips_mt_set_cpuoptions(); if (vpelimit > 0) printk("Limit of %d VPEs set\n", vpelimit); if (tclimit > 0) @@ -572,7 +572,7 @@ void smtc_init_secondary(void) if (((read_c0_tcbind() & TCBIND_CURTC) != 0) && ((read_c0_tcbind() & TCBIND_CURVPE) != cpu_data[smp_processor_id() - 1].vpe_id)){ - write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); + write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ); } local_irq_enable(); diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 7c800ec3ff55..ef2c6360d052 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -314,8 +314,8 @@ asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) * * This is really horribly ugly. */ -asmlinkage int sys_ipc (unsigned int call, int first, int second, - unsigned long third, void __user *ptr, long fifth) +asmlinkage int sys_ipc(unsigned int call, int first, int second, + unsigned long third, void __user *ptr, long fifth) { int version, ret; @@ -324,26 +324,26 @@ asmlinkage int sys_ipc (unsigned int call, int first, int second, switch (call) { case SEMOP: - return sys_semtimedop (first, (struct sembuf __user *)ptr, - second, NULL); + return sys_semtimedop(first, (struct sembuf __user *)ptr, + second, NULL); case SEMTIMEDOP: - return sys_semtimedop (first, (struct sembuf __user *)ptr, - second, - (const struct timespec __user *)fifth); + return sys_semtimedop(first, (struct sembuf __user *)ptr, + second, + (const struct timespec __user *)fifth); case SEMGET: - return sys_semget (first, second, third); + return sys_semget(first, second, third); case SEMCTL: { union semun fourth; if (!ptr) return -EINVAL; if (get_user(fourth.__pad, (void __user *__user *) ptr)) return -EFAULT; - return sys_semctl (first, second, third, fourth); + return sys_semctl(first, second, third, fourth); } case MSGSND: - return sys_msgsnd (first, (struct msgbuf __user *) ptr, - second, third); + return sys_msgsnd(first, (struct msgbuf __user *) ptr, + second, third); case MSGRCV: switch (version) { case 0: { @@ -353,45 +353,45 @@ asmlinkage int sys_ipc (unsigned int call, int first, int second, if (copy_from_user(&tmp, (struct ipc_kludge __user *) ptr, - sizeof (tmp))) + sizeof(tmp))) return -EFAULT; - return sys_msgrcv (first, tmp.msgp, second, - tmp.msgtyp, third); + return sys_msgrcv(first, tmp.msgp, second, + tmp.msgtyp, third); } default: - return sys_msgrcv (first, - (struct msgbuf __user *) ptr, - second, fifth, third); + return sys_msgrcv(first, + (struct msgbuf __user *) ptr, + second, fifth, third); } case MSGGET: - return sys_msgget ((key_t) first, second); + return sys_msgget((key_t) first, second); case MSGCTL: - return sys_msgctl (first, second, - (struct msqid_ds __user *) ptr); + return sys_msgctl(first, second, + (struct msqid_ds __user *) ptr); case SHMAT: switch (version) { default: { unsigned long raddr; - ret = do_shmat (first, (char __user *) ptr, second, - &raddr); + ret = do_shmat(first, (char __user *) ptr, second, + &raddr); if (ret) return ret; - return put_user (raddr, (unsigned long __user *) third); + return put_user(raddr, (unsigned long __user *) third); } case 1: /* iBCS2 emulator entry point */ if (!segment_eq(get_fs(), get_ds())) return -EINVAL; - return do_shmat (first, (char __user *) ptr, second, - (unsigned long *) third); + return do_shmat(first, (char __user *) ptr, second, + (unsigned long *) third); } case SHMDT: - return sys_shmdt ((char __user *)ptr); + return sys_shmdt((char __user *)ptr); case SHMGET: - return sys_shmget (first, second, third); + return sys_shmget(first, second, third); case SHMCTL: - return sys_shmctl (first, second, - (struct shmid_ds __user *) ptr); + return sys_shmctl(first, second, + (struct shmid_ds __user *) ptr); default: return -ENOSYS; } diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 93a148486f88..b50239574c95 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -486,10 +486,10 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) switch (arg1) { case SGI_INV_SIZEOF: - retval = sizeof (inventory_t); + retval = sizeof(inventory_t); break; case SGI_INV_READ: - retval = dump_inventory_to_user (buffer, count); + retval = dump_inventory_to_user(buffer, count); break; default: retval = -EINVAL; @@ -1042,9 +1042,9 @@ asmlinkage unsigned long irix_mmap32(unsigned long addr, size_t len, int prot, long max_size = offset + len; if (max_size > file->f_path.dentry->d_inode->i_size) { - old_pos = sys_lseek (fd, max_size - 1, 0); - sys_write (fd, (void __user *) "", 1); - sys_lseek (fd, old_pos, 0); + old_pos = sys_lseek(fd, max_size - 1, 0); + sys_write(fd, (void __user *) "", 1); + sys_lseek(fd, old_pos, 0); } } } @@ -1176,7 +1176,7 @@ static int irix_xstat32_xlate(struct kstat *stat, void __user *ubuf) ub.st_ctime1 = stat->atime.tv_nsec; ub.st_blksize = stat->blksize; ub.st_blocks = stat->blocks; - strcpy (ub.st_fstype, "efs"); + strcpy(ub.st_fstype, "efs"); return copy_to_user(ubuf, &ub, sizeof(ub)) ? -EFAULT : 0; } @@ -1208,7 +1208,7 @@ static int irix_xstat64_xlate(struct kstat *stat, void __user *ubuf) ks.st_nlink = (u32) stat->nlink; ks.st_uid = (s32) stat->uid; ks.st_gid = (s32) stat->gid; - ks.st_rdev = sysv_encode_dev (stat->rdev); + ks.st_rdev = sysv_encode_dev(stat->rdev); ks.st_pad2[0] = ks.st_pad2[1] = 0; ks.st_size = (long long) stat->size; ks.st_pad3 = 0; @@ -1527,9 +1527,9 @@ asmlinkage int irix_mmap64(struct pt_regs *regs) long max_size = off2 + len; if (max_size > file->f_path.dentry->d_inode->i_size) { - old_pos = sys_lseek (fd, max_size - 1, 0); - sys_write (fd, (void __user *) "", 1); - sys_lseek (fd, old_pos, 0); + old_pos = sys_lseek(fd, max_size - 1, 0); + sys_write(fd, (void __user *) "", 1); + sys_lseek(fd, old_pos, 0); } } } diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 369a5f9ad268..5892491b40eb 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -149,7 +149,7 @@ EXPORT_SYMBOL_GPL(cp0_perfcount_irq); * Possibly handle a performance counter interrupt. * Return true if the timer interrupt should not be checked */ -static inline int handle_perf_irq (int r2) +static inline int handle_perf_irq(int r2) { /* * The performance counter overflow interrupt may be shared with the diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ac762d8d802d..b3e408b54c24 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -627,7 +627,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) lose_fpu(1); /* Run the emulator */ - sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1); + sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1); /* * We can't allow the emulated instruction to leave any of @@ -1165,11 +1165,11 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) if (cpu_has_veic) { if (board_bind_eic_interrupt) - board_bind_eic_interrupt (n, srs); + board_bind_eic_interrupt(n, srs); } else if (cpu_has_vint) { /* SRSMap is only defined if shadow sets are implemented */ if (mips_srs_max() > 1) - change_c0_srsmap (0xf << n*4, srs << n*4); + change_c0_srsmap(0xf << n*4, srs << n*4); } if (srs == 0) { @@ -1198,10 +1198,10 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) * Sigh... panicing won't help as the console * is probably not configured :( */ - panic ("VECTORSPACING too small"); + panic("VECTORSPACING too small"); } - memcpy (b, &except_vec_vi, handler_len); + memcpy(b, &except_vec_vi, handler_len); #ifdef CONFIG_MIPS_MT_SMTC BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ @@ -1370,9 +1370,9 @@ void __init per_cpu_trap_init(void) #endif /* CONFIG_MIPS_MT_SMTC */ if (cpu_has_veic || cpu_has_vint) { - write_c0_ebase (ebase); + write_c0_ebase(ebase); /* Setting vector spacing enables EI/VI mode */ - change_c0_intctl (0x3e0, VECTORSPACING); + change_c0_intctl(0x3e0, VECTORSPACING); } if (cpu_has_divec) { if (cpu_has_mipsmt) { @@ -1390,8 +1390,8 @@ void __init per_cpu_trap_init(void) * o read IntCtl.IPPCI to determine the performance counter interrupt */ if (cpu_has_mips_r2) { - cp0_compare_irq = (read_c0_intctl () >> 29) & 7; - cp0_perfcount_irq = (read_c0_intctl () >> 26) & 7; + cp0_compare_irq = (read_c0_intctl() >> 29) & 7; + cp0_perfcount_irq = (read_c0_intctl() >> 26) & 7; if (cp0_perfcount_irq == cp0_compare_irq) cp0_perfcount_irq = -1; } else { @@ -1429,7 +1429,7 @@ void __init per_cpu_trap_init(void) } /* Install CPU exception handler */ -void __init set_handler (unsigned long offset, void *addr, unsigned long size) +void __init set_handler(unsigned long offset, void *addr, unsigned long size) { memcpy((void *)(ebase + offset), addr, size); flush_icache_range(ebase + offset, ebase + offset + size); @@ -1439,7 +1439,7 @@ static char panic_null_cerr[] __initdata = "Trying to set NULL cache error exception handler"; /* Install uncached CPU exception handler */ -void __init set_uncached_handler (unsigned long offset, void *addr, unsigned long size) +void __init set_uncached_handler(unsigned long offset, void *addr, unsigned long size) { #ifdef CONFIG_32BIT unsigned long uncached_ebase = KSEG1ADDR(ebase); @@ -1470,7 +1470,7 @@ void __init trap_init(void) unsigned long i; if (cpu_has_veic || cpu_has_vint) - ebase = (unsigned long) alloc_bootmem_low_pages (0x200 + VECTORSPACING*64); + ebase = (unsigned long) alloc_bootmem_low_pages(0x200 + VECTORSPACING*64); else ebase = CAC_BASE; @@ -1496,7 +1496,7 @@ void __init trap_init(void) * destination. */ if (cpu_has_ejtag && board_ejtag_handler_setup) - board_ejtag_handler_setup (); + board_ejtag_handler_setup(); /* * Only some CPUs have the watch exceptions. diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index d34b1fb3665d..c327b21bca81 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -481,7 +481,7 @@ fault: if (fixup_exception(regs)) return; - die_if_kernel ("Unhandled kernel unaligned access", regs); + die_if_kernel("Unhandled kernel unaligned access", regs); send_sig(SIGSEGV, current, 1); return; diff --git a/arch/mips/lib/ucmpdi2.c b/arch/mips/lib/ucmpdi2.c index e2ff6072b5a3..b33d8569bcb0 100644 --- a/arch/mips/lib/ucmpdi2.c +++ b/arch/mips/lib/ucmpdi2.c @@ -2,7 +2,7 @@ #include "libgcc.h" -word_type __ucmpdi2 (unsigned long long a, unsigned long long b) +word_type __ucmpdi2(unsigned long long a, unsigned long long b) { const DWunion au = {.ll = a}; const DWunion bu = {.ll = b}; diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 17419e11ecad..c44e9cc2b19c 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -549,16 +549,16 @@ static const unsigned char cmptab[8] = { */ #define DEF3OP(name, p, f1, f2, f3) \ -static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \ +static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \ ieee754##p t) \ { \ struct _ieee754_csr ieee754_csr_save; \ - s = f1 (s, t); \ + s = f1(s, t); \ ieee754_csr_save = ieee754_csr; \ - s = f2 (s, r); \ + s = f2(s, r); \ ieee754_csr_save.cx |= ieee754_csr.cx; \ ieee754_csr_save.sx |= ieee754_csr.sx; \ - s = f3 (s); \ + s = f3(s); \ ieee754_csr.cx |= ieee754_csr_save.cx; \ ieee754_csr.sx |= ieee754_csr_save.sx; \ return s; \ diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c index 3c692abc2553..6fb29c3ff62d 100644 --- a/arch/mips/mips-boards/atlas/atlas_int.c +++ b/arch/mips/mips-boards/atlas/atlas_int.c @@ -112,7 +112,7 @@ static inline void atlas_hw0_irqdispatch(void) static inline int clz(unsigned long x) { - __asm__ ( + __asm__( " .set push \n" " .set mips32 \n" " clz %0, %1 \n" @@ -194,7 +194,7 @@ asmlinkage void plat_irq_dispatch(void) spurious_interrupt(); } -static inline void init_atlas_irqs (int base) +static inline void init_atlas_irqs(int base) { int i; @@ -249,21 +249,21 @@ void __init arch_init_irq(void) case MIPS_REVISION_CORID_CORE_24K: case MIPS_REVISION_CORID_CORE_EMUL_MSC: if (cpu_has_veic) - init_msc_irqs (MSC01E_INT_BASE, MSC01E_INT_BASE, - msc_eicirqmap, msc_nr_eicirqs); + init_msc_irqs(MSC01E_INT_BASE, MSC01E_INT_BASE, + msc_eicirqmap, msc_nr_eicirqs); else - init_msc_irqs (MSC01E_INT_BASE, MSC01C_INT_BASE, - msc_irqmap, msc_nr_irqs); + init_msc_irqs(MSC01E_INT_BASE, MSC01C_INT_BASE, + msc_irqmap, msc_nr_irqs); } if (cpu_has_veic) { - set_vi_handler (MSC01E_INT_ATLAS, atlas_hw0_irqdispatch); - setup_irq (MSC01E_INT_BASE + MSC01E_INT_ATLAS, &atlasirq); + set_vi_handler(MSC01E_INT_ATLAS, atlas_hw0_irqdispatch); + setup_irq(MSC01E_INT_BASE + MSC01E_INT_ATLAS, &atlasirq); } else if (cpu_has_vint) { - set_vi_handler (MIPSCPU_INT_ATLAS, atlas_hw0_irqdispatch); + set_vi_handler(MIPSCPU_INT_ATLAS, atlas_hw0_irqdispatch); #ifdef CONFIG_MIPS_MT_SMTC - setup_irq_smtc (MIPS_CPU_IRQ_BASE + MIPSCPU_INT_ATLAS, - &atlasirq, (0x100 << MIPSCPU_INT_ATLAS)); + setup_irq_smtc(MIPS_CPU_IRQ_BASE + MIPSCPU_INT_ATLAS, + &atlasirq, (0x100 << MIPSCPU_INT_ATLAS)); #else /* Not SMTC */ setup_irq(MIPS_CPU_IRQ_BASE + MIPSCPU_INT_ATLAS, &atlasirq); #endif /* CONFIG_MIPS_MT_SMTC */ diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c index 86bfc0548164..e405d112a067 100644 --- a/arch/mips/mips-boards/atlas/atlas_setup.c +++ b/arch/mips/mips-boards/atlas/atlas_setup.c @@ -55,7 +55,7 @@ void __init plat_mem_setup(void) ioport_resource.end = 0x7fffffff; - serial_init (); + serial_init(); #ifdef CONFIG_KGDB kgdb_config(); diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c index e2c7147fedf7..30f1f54cb68b 100644 --- a/arch/mips/mips-boards/generic/init.c +++ b/arch/mips/mips-boards/generic/init.c @@ -166,15 +166,15 @@ static void __init console_config(void) bits = '8'; if (flow == '\0') flow = 'r'; - sprintf (console_string, " console=ttyS0,%d%c%c%c", baud, parity, bits, flow); - strcat (prom_getcmdline(), console_string); + sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, parity, bits, flow); + strcat(prom_getcmdline(), console_string); pr_info("Config serial console:%s\n", console_string); } } #endif #ifdef CONFIG_KGDB -void __init kgdb_config (void) +void __init kgdb_config(void) { extern int (*generic_putDebugChar)(char); extern char (*generic_getDebugChar)(void); @@ -218,7 +218,7 @@ void __init kgdb_config (void) { char *s; for (s = "Please connect GDB to this port\r\n"; *s; ) - generic_putDebugChar (*s++); + generic_putDebugChar(*s++); } /* Breakpoint is invoked after interrupts are initialised */ @@ -226,7 +226,7 @@ void __init kgdb_config (void) } #endif -void __init mips_nmi_setup (void) +void __init mips_nmi_setup(void) { void *base; extern char except_vec_nmi; @@ -238,7 +238,7 @@ void __init mips_nmi_setup (void) flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); } -void __init mips_ejtag_setup (void) +void __init mips_ejtag_setup(void) { void *base; extern char except_vec_ejtag_debug; diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c index ae39953da2c4..dc272c188233 100644 --- a/arch/mips/mips-boards/generic/memory.c +++ b/arch/mips/mips-boards/generic/memory.c @@ -125,7 +125,7 @@ struct prom_pmemblock * __init prom_getmdesc(void) return &mdesc[0]; } -static int __init prom_memtype_classify (unsigned int type) +static int __init prom_memtype_classify(unsigned int type) { switch (type) { case yamon_free: @@ -158,7 +158,7 @@ void __init prom_meminit(void) long type; unsigned long base, size; - type = prom_memtype_classify (p->type); + type = prom_memtype_classify(p->type); base = p->base; size = p->size; diff --git a/arch/mips/mips-boards/generic/pci.c b/arch/mips/mips-boards/generic/pci.c index c9852206890a..b9743190609a 100644 --- a/arch/mips/mips-boards/generic/pci.c +++ b/arch/mips/mips-boards/generic/pci.c @@ -239,5 +239,5 @@ void __init mips_pcibios_init(void) iomem_resource.end &= 0xfffffffffULL; /* 64 GB */ ioport_resource.end = controller->io_resource->end; - register_pci_controller (controller); + register_pci_controller(controller); } diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 4fab3b2e8736..1d00b778ff1e 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -134,7 +134,7 @@ void __init plat_time_init(void) /* Set Data mode - binary. */ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); - est_freq = estimate_cpu_frequency (); + est_freq = estimate_cpu_frequency(); printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, (est_freq%1000000)*100/1000000); @@ -166,7 +166,7 @@ void __init plat_perf_setup(void) #ifdef MSC01E_INT_BASE if (cpu_has_veic) { - set_vi_handler (MSC01E_INT_PERFCTR, mips_perf_dispatch); + set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; } else #endif @@ -183,7 +183,7 @@ void __init plat_timer_setup(struct irqaction *irq) { #ifdef MSC01E_INT_BASE if (cpu_has_veic) { - set_vi_handler (MSC01E_INT_CPUCTR, mips_timer_dispatch); + set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch); mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; } else diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index b73f21823c5e..8232392750a8 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c @@ -178,7 +178,7 @@ static void corehi_irqdispatch(void) static inline int clz(unsigned long x) { - __asm__ ( + __asm__( " .set push \n" " .set mips32 \n" " clz %0, %1 \n" @@ -303,32 +303,32 @@ void __init arch_init_irq(void) case MIPS_REVISION_SCON_SOCIT: case MIPS_REVISION_SCON_ROCIT: if (cpu_has_veic) - init_msc_irqs (MIPS_MSC01_IC_REG_BASE, MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs); + init_msc_irqs(MIPS_MSC01_IC_REG_BASE, MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs); else - init_msc_irqs (MIPS_MSC01_IC_REG_BASE, MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs); + init_msc_irqs(MIPS_MSC01_IC_REG_BASE, MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs); break; case MIPS_REVISION_SCON_SOCITSC: case MIPS_REVISION_SCON_SOCITSCP: if (cpu_has_veic) - init_msc_irqs (MIPS_SOCITSC_IC_REG_BASE, MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs); + init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE, MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs); else - init_msc_irqs (MIPS_SOCITSC_IC_REG_BASE, MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs); + init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE, MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs); } if (cpu_has_veic) { - set_vi_handler (MSC01E_INT_I8259A, malta_hw0_irqdispatch); - set_vi_handler (MSC01E_INT_COREHI, corehi_irqdispatch); - setup_irq (MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq); - setup_irq (MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction); + set_vi_handler(MSC01E_INT_I8259A, malta_hw0_irqdispatch); + set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch); + setup_irq(MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq); + setup_irq(MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction); } else if (cpu_has_vint) { - set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); - set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch); + set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); + set_vi_handler(MIPSCPU_INT_COREHI, corehi_irqdispatch); #ifdef CONFIG_MIPS_MT_SMTC - setup_irq_smtc (MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq, + setup_irq_smtc(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq, (0x100 << MIPSCPU_INT_I8259A)); - setup_irq_smtc (MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, + setup_irq_smtc(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI)); /* * Temporary hack to ensure that the subsidiary device @@ -343,12 +343,12 @@ void __init arch_init_irq(void) irq_hwmask[i] = (0x100 << MIPSCPU_INT_I8259A); } #else /* Not SMTC */ - setup_irq (MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); - setup_irq (MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); + setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); + setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); #endif /* CONFIG_MIPS_MT_SMTC */ } else { - setup_irq (MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); - setup_irq (MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); + setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); + setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); } } diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index a5a5a43a1984..e243d5efcb38 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c @@ -99,7 +99,7 @@ void __init plat_mem_setup(void) enable_dma(4); #ifdef CONFIG_KGDB - kgdb_config (); + kgdb_config(); #endif if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) { @@ -108,7 +108,7 @@ void __init plat_mem_setup(void) argptr = prom_getcmdline(); if (strstr(argptr, "debug")) { BONITO_BONGENCFG |= BONITO_BONGENCFG_DEBUGMODE; - printk ("Enabled Bonito debug mode\n"); + printk("Enabled Bonito debug mode\n"); } else BONITO_BONGENCFG &= ~BONITO_BONGENCFG_DEBUGMODE; @@ -159,14 +159,14 @@ void __init plat_mem_setup(void) if (pciclock != 33 && !strstr (argptr, "idebus=")) { printk("WARNING: PCI clock is %dMHz, setting idebus\n", pciclock); argptr += strlen(argptr); - sprintf (argptr, " idebus=%d", pciclock); + sprintf(argptr, " idebus=%d", pciclock); if (pciclock < 20 || pciclock > 66) - printk ("WARNING: IDE timing calculations will be incorrect\n"); + printk("WARNING: IDE timing calculations will be incorrect\n"); } } #endif #ifdef CONFIG_BLK_DEV_FD - fd_activate (); + fd_activate(); #endif #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c index 9ca0f82f1360..ec6dd194c14a 100644 --- a/arch/mips/mips-boards/sead/sead_int.c +++ b/arch/mips/mips-boards/sead/sead_int.c @@ -31,7 +31,7 @@ static inline int clz(unsigned long x) { - __asm__ ( + __asm__( " .set push \n" " .set mips32 \n" " clz %0, %1 \n" diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c index fad58972f3ac..1fb61b852304 100644 --- a/arch/mips/mips-boards/sead/sead_setup.c +++ b/arch/mips/mips-boards/sead/sead_setup.c @@ -49,7 +49,7 @@ void __init plat_mem_setup(void) { ioport_resource.end = 0x7fffffff; - serial_init (); + serial_init(); mips_reboot_setup(); } diff --git a/arch/mips/mipssim/sim_int.c b/arch/mips/mipssim/sim_int.c index 5cbc3509ab52..46067ad542dc 100644 --- a/arch/mips/mipssim/sim_int.c +++ b/arch/mips/mipssim/sim_int.c @@ -25,7 +25,7 @@ static inline int clz(unsigned long x) { - __asm__ ( + __asm__( " .set push \n" " .set mips32 \n" " clz %0, %1 \n" diff --git a/arch/mips/mipssim/sim_mem.c b/arch/mips/mipssim/sim_mem.c index 2312483eb838..953d836a7713 100644 --- a/arch/mips/mipssim/sim_mem.c +++ b/arch/mips/mipssim/sim_mem.c @@ -69,7 +69,7 @@ struct prom_pmemblock * __init prom_getmdesc(void) return &mdesc[0]; } -static int __init prom_memtype_classify (unsigned int type) +static int __init prom_memtype_classify(unsigned int type) { switch (type) { case simmem_free: @@ -90,7 +90,7 @@ void __init prom_meminit(void) long type; unsigned long base, size; - type = prom_memtype_classify (p->type); + type = prom_memtype_classify(p->type); base = p->base; size = p->size; diff --git a/arch/mips/mipssim/sim_time.c b/arch/mips/mipssim/sim_time.c index 3625f7d49035..e7fa0d1078a3 100644 --- a/arch/mips/mipssim/sim_time.c +++ b/arch/mips/mipssim/sim_time.c @@ -84,7 +84,7 @@ void __init plat_time_init(void) /* Set Data mode - binary. */ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); - est_freq = estimate_cpu_frequency (); + est_freq = estimate_cpu_frequency(); printk(KERN_INFO "CPU frequency %d.%02d MHz\n", est_freq / 1000000, (est_freq % 1000000) * 100 / 1000000); diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index 59868a1edf66..c55312f6fd3a 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -121,7 +121,7 @@ static void r3k_flush_icache_range(unsigned long start, unsigned long end) write_c0_status((ST0_ISC|ST0_SWC|flags)&~ST0_IEC); for (i = 0; i < size; i += 0x080) { - asm ( "sb\t$0, 0x000(%0)\n\t" + asm( "sb\t$0, 0x000(%0)\n\t" "sb\t$0, 0x004(%0)\n\t" "sb\t$0, 0x008(%0)\n\t" "sb\t$0, 0x00c(%0)\n\t" @@ -178,7 +178,7 @@ static void r3k_flush_dcache_range(unsigned long start, unsigned long end) write_c0_status((ST0_ISC|flags)&~ST0_IEC); for (i = 0; i < size; i += 0x080) { - asm ( "sb\t$0, 0x000(%0)\n\t" + asm( "sb\t$0, 0x000(%0)\n\t" "sb\t$0, 0x004(%0)\n\t" "sb\t$0, 0x008(%0)\n\t" "sb\t$0, 0x00c(%0)\n\t" @@ -217,8 +217,8 @@ static void r3k_flush_dcache_range(unsigned long start, unsigned long end) write_c0_status(flags); } -static inline unsigned long get_phys_page (unsigned long addr, - struct mm_struct *mm) +static inline unsigned long get_phys_page(unsigned long addr, + struct mm_struct *mm) { pgd_t *pgd; pud_t *pud; @@ -281,13 +281,13 @@ static void r3k_flush_cache_sigtramp(unsigned long addr) write_c0_status(flags&~ST0_IEC); /* Fill the TLB to avoid an exception with caches isolated. */ - asm ( "lw\t$0, 0x000(%0)\n\t" + asm( "lw\t$0, 0x000(%0)\n\t" "lw\t$0, 0x004(%0)\n\t" : : "r" (addr) ); write_c0_status((ST0_ISC|ST0_SWC|flags)&~ST0_IEC); - asm ( "sb\t$0, 0x000(%0)\n\t" + asm( "sb\t$0, 0x000(%0)\n\t" "sb\t$0, 0x004(%0)\n\t" : : "r" (addr) ); diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 42b50964c644..c13170bc675c 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -102,7 +102,7 @@ static inline int __init mips_sc_probe(void) int __init mips_sc_init(void) { - int found = mips_sc_probe (); + int found = mips_sc_probe(); if (found) { mips_sc_enable(); bcops = &mips_sc_ops; diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index dcd6913dc1ff..74ae0348cc92 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -491,7 +491,7 @@ void __init tlb_init(void) int wired = current_cpu_data.tlbsize - ntlb; write_c0_wired(wired); write_c0_index(wired-1); - printk ("Restricting TLB to %d entries\n", ntlb); + printk("Restricting TLB to %d entries\n", ntlb); } else printk("Ignoring invalid argument ntlb=%d\n", ntlb); } diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 6383000422ab..423bc2c473df 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -118,7 +118,7 @@ static void mipsxx_reg_setup(struct op_counter_config *ctr) /* Program all of the registers in preparation for enabling profiling. */ -static void mipsxx_cpu_setup (void *args) +static void mipsxx_cpu_setup(void *args) { unsigned int counters = op_model_mipsxx_ops.num_counters; diff --git a/arch/mips/oprofile/op_model_rm9000.c b/arch/mips/oprofile/op_model_rm9000.c index d29040a56aea..a45d3202894f 100644 --- a/arch/mips/oprofile/op_model_rm9000.c +++ b/arch/mips/oprofile/op_model_rm9000.c @@ -60,7 +60,7 @@ static void rm9000_reg_setup(struct op_counter_config *ctr) /* Program all of the registers in preparation for enabling profiling. */ -static void rm9000_cpu_setup (void *args) +static void rm9000_cpu_setup(void *args) { uint64_t perfcount; diff --git a/arch/mips/pci/fixup-atlas.c b/arch/mips/pci/fixup-atlas.c index 45224fd2c7ba..506e883a8c71 100644 --- a/arch/mips/pci/fixup-atlas.c +++ b/arch/mips/pci/fixup-atlas.c @@ -77,12 +77,12 @@ int pcibios_plat_dev_init(struct pci_dev *dev) * code, but it is better than nothing... */ -static void atlas_saa9730_base_fixup (struct pci_dev *pdev) +static void atlas_saa9730_base_fixup(struct pci_dev *pdev) { extern void *saa9730_base; if (pdev->bus == 0 && PCI_SLOT(pdev->devfn) == 19) - (void) pci_read_config_dword (pdev, 0x14, (u32 *)&saa9730_base); - printk ("saa9730_base = %x\n", saa9730_base); + (void) pci_read_config_dword(pdev, 0x14, (u32 *)&saa9730_base); + printk("saa9730_base = %x\n", saa9730_base); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, diff --git a/arch/mips/pci/ops-au1000.c b/arch/mips/pci/ops-au1000.c index 7932dfe5eb9b..6b29904acf45 100644 --- a/arch/mips/pci/ops-au1000.c +++ b/arch/mips/pci/ops-au1000.c @@ -112,7 +112,7 @@ static int config_access(unsigned char access_type, struct pci_bus *bus, first_cfg = 0; pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP); if (!pci_cfg_vm) - panic (KERN_ERR "PCI unable to get vm area\n"); + panic(KERN_ERR "PCI unable to get vm area\n"); pci_cfg_wired_entry = read_c0_wired(); add_wired_entry(0, 0, (unsigned long)pci_cfg_vm->addr, PM_4K); last_entryLo0 = last_entryLo1 = 0xffffffff; diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c index fa2d2c60f797..97ed25b92edf 100644 --- a/arch/mips/pci/ops-sni.c +++ b/arch/mips/pci/ops-sni.c @@ -70,13 +70,13 @@ static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg, switch (size) { case 1: - outb (val, PCIMT_CONFIG_DATA + (reg & 3)); + outb(val, PCIMT_CONFIG_DATA + (reg & 3)); break; case 2: - outw (val, PCIMT_CONFIG_DATA + (reg & 2)); + outw(val, PCIMT_CONFIG_DATA + (reg & 2)); break; case 4: - outl (val, PCIMT_CONFIG_DATA); + outl(val, PCIMT_CONFIG_DATA); break; } @@ -93,7 +93,7 @@ static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int r if ((devfn > 255) || (reg > 255) || (busno > 255)) return PCIBIOS_BAD_REGISTER_NUMBER; - outl ((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8); + outl((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8); return PCIBIOS_SUCCESSFUL; } @@ -108,12 +108,12 @@ static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg, * we don't do it, we will get a data bus error */ if (bus->number == 0) { - pcit_set_config_address (0, 0, 0x68); - outl (inl (0xcfc) | 0xc0000000, 0xcfc); + pcit_set_config_address(0, 0, 0x68); + outl(inl(0xcfc) | 0xc0000000, 0xcfc); if ((res = pcit_set_config_address(0, devfn, 0))) return res; - outl (0xffffffff, 0xcfc); - pcit_set_config_address (0, 0, 0x68); + outl(0xffffffff, 0xcfc); + pcit_set_config_address(0, 0, 0x68); if (inl(0xcfc) & 0x100000) return PCIBIOS_DEVICE_NOT_FOUND; } @@ -144,13 +144,13 @@ static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg, switch (size) { case 1: - outb (val, PCIMT_CONFIG_DATA + (reg & 3)); + outb(val, PCIMT_CONFIG_DATA + (reg & 3)); break; case 2: - outw (val, PCIMT_CONFIG_DATA + (reg & 2)); + outw(val, PCIMT_CONFIG_DATA + (reg & 2)); break; case 4: - outl (val, PCIMT_CONFIG_DATA); + outl(val, PCIMT_CONFIG_DATA); break; } diff --git a/arch/mips/philips/pnx8550/common/proc.c b/arch/mips/philips/pnx8550/common/proc.c index 92311e95b700..416f834784bc 100644 --- a/arch/mips/philips/pnx8550/common/proc.c +++ b/arch/mips/philips/pnx8550/common/proc.c @@ -27,7 +27,7 @@ #include -static int pnx8550_timers_read (char* page, char** start, off_t offset, int count, int* eof, void* data) +static int pnx8550_timers_read(char* page, char** start, off_t offset, int count, int* eof, void* data) { int len = 0; int configPR = read_c0_config7(); @@ -48,7 +48,7 @@ static int pnx8550_timers_read (char* page, char** start, off_t offset, int coun return len; } -static int pnx8550_registers_read (char* page, char** start, off_t offset, int count, int* eof, void* data) +static int pnx8550_registers_read(char* page, char** start, off_t offset, int count, int* eof, void* data) { int len = 0; diff --git a/arch/mips/pmc-sierra/msp71xx/msp_usb.c b/arch/mips/pmc-sierra/msp71xx/msp_usb.c index 21f9c70b6923..f7ca4f582331 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_usb.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_usb.c @@ -58,7 +58,7 @@ static struct platform_device msp_usbhost_device = { .dma_mask = &msp_usbhost_dma_mask, .coherent_dma_mask = DMA_32BIT_MASK, }, - .num_resources = ARRAY_SIZE (msp_usbhost_resources), + .num_resources = ARRAY_SIZE(msp_usbhost_resources), .resource = msp_usbhost_resources, }; #endif /* CONFIG_USB_EHCI_HCD */ @@ -86,7 +86,7 @@ static struct platform_device msp_usbdev_device = { .dma_mask = &msp_usbdev_dma_mask, .coherent_dma_mask = DMA_32BIT_MASK, }, - .num_resources = ARRAY_SIZE (msp_usbdev_resources), + .num_resources = ARRAY_SIZE(msp_usbdev_resources), .resource = msp_usbdev_resources, }; #endif /* CONFIG_USB_GADGET */ @@ -129,7 +129,7 @@ static int __init msp_usb_setup(void) ppfinit("platform add USB HOST done %s.\n", msp_devs[0]->name); - result = platform_add_devices(msp_devs, ARRAY_SIZE (msp_devs)); + result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs)); #endif /* CONFIG_USB_EHCI_HCD */ } #if defined(CONFIG_USB_GADGET) @@ -139,7 +139,7 @@ static int __init msp_usb_setup(void) ppfinit("platform add USB DEVICE done %s.\n", msp_devs[0]->name); - result = platform_add_devices(msp_devs, ARRAY_SIZE (msp_devs)); + result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs)); } #endif /* CONFIG_USB_GADGET */ #endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */ diff --git a/arch/mips/qemu/q-firmware.c b/arch/mips/qemu/q-firmware.c index fb2a8673a6bf..c2239b417587 100644 --- a/arch/mips/qemu/q-firmware.c +++ b/arch/mips/qemu/q-firmware.c @@ -10,7 +10,7 @@ void __init prom_init(void) cmdline = (int *) (CKSEG0 + (0x10 << 20) - 260); if (*cmdline == 0x12345678) { if (*(char *)(cmdline + 1)) - strcpy (arcs_cmdline, (char *)(cmdline + 1)); + strcpy(arcs_cmdline, (char *)(cmdline + 1)); add_memory_region(0x0<<20, cmdline[-1], BOOT_MEM_RAM); } else { add_memory_region(0x0<<20, 0x10<<20, BOOT_MEM_RAM); diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c index 6b6e97b90c6e..26854fb11e7c 100644 --- a/arch/mips/sgi-ip22/ip22-eisa.c +++ b/arch/mips/sgi-ip22/ip22-eisa.c @@ -55,7 +55,7 @@ static char __init *decode_eisa_sig(unsigned long addr) int i; for (i = 0; i < 4; i++) { - sig[i] = inb (addr + i); + sig[i] = inb(addr + i); if (!i && (sig[0] & 0x80)) return NULL; diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index f199da7e49cf..f6d9bf4b26e7 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -344,6 +344,6 @@ void __init arch_init_irq(void) #ifdef CONFIG_EISA if (ip22_is_fullhouse()) /* Only Indigo-2 has EISA stuff */ - ip22_eisa_init (); + ip22_eisa_init(); #endif } diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c index bff508704d03..563c614ad021 100644 --- a/arch/mips/sgi-ip32/crime.c +++ b/arch/mips/sgi-ip32/crime.c @@ -35,8 +35,8 @@ void __init crime_init(void) id = crime->id; rev = id & CRIME_ID_REV; id = (id & CRIME_ID_IDBITS) >> 4; - printk (KERN_INFO "CRIME id %1x rev %d at 0x%0*lx\n", - id, rev, field, (unsigned long) CRIME_BASE); + printk(KERN_INFO "CRIME id %1x rev %d at 0x%0*lx\n", + id, rev, field, (unsigned long) CRIME_BASE); } irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id) @@ -96,7 +96,7 @@ irqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id) unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK; addr <<= 2; - printk ("CRIME CPU error at 0x%09lx status 0x%08lx\n", addr, stat); + printk("CRIME CPU error at 0x%09lx status 0x%08lx\n", addr, stat); crime->cpu_error_stat = 0; return IRQ_HANDLED; diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index 002095b364a3..7f4b793c3df3 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -148,7 +148,7 @@ static void disable_cpu_irq(unsigned int irq) static void end_cpu_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - enable_cpu_irq (irq); + enable_cpu_irq(irq); } static struct irq_chip ip32_cpu_interrupt = { @@ -289,11 +289,11 @@ static struct irq_chip ip32_macepci_interrupt = { static unsigned long maceisa_mask; -static void enable_maceisa_irq (unsigned int irq) +static void enable_maceisa_irq(unsigned int irq) { unsigned int crime_int = 0; - DBG ("maceisa enable: %u\n", irq); + DBG("maceisa enable: %u\n", irq); switch (irq) { case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ: @@ -306,7 +306,7 @@ static void enable_maceisa_irq (unsigned int irq) crime_int = MACE_SUPERIO_INT; break; } - DBG ("crime_int %08x enabled\n", crime_int); + DBG("crime_int %08x enabled\n", crime_int); crime_mask |= crime_int; crime->imask = crime_mask; maceisa_mask |= 1 << (irq - 33); @@ -397,15 +397,15 @@ static struct irq_chip ip32_mace_interrupt = { static void ip32_unknown_interrupt(void) { - printk ("Unknown interrupt occurred!\n"); - printk ("cp0_status: %08x\n", read_c0_status()); - printk ("cp0_cause: %08x\n", read_c0_cause()); - printk ("CRIME intr mask: %016lx\n", crime->imask); - printk ("CRIME intr status: %016lx\n", crime->istat); - printk ("CRIME hardware intr register: %016lx\n", crime->hard_int); - printk ("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask); - printk ("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat); - printk ("MACE PCI control register: %08x\n", mace->pci.control); + printk("Unknown interrupt occurred!\n"); + printk("cp0_status: %08x\n", read_c0_status()); + printk("cp0_cause: %08x\n", read_c0_cause()); + printk("CRIME intr mask: %016lx\n", crime->imask); + printk("CRIME intr status: %016lx\n", crime->istat); + printk("CRIME hardware intr register: %016lx\n", crime->hard_int); + printk("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask); + printk("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat); + printk("MACE PCI control register: %08x\n", mace->pci.control); printk("Register dump:\n"); show_regs(get_irq_regs()); diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c index 849d392a0013..ca93ecf825ae 100644 --- a/arch/mips/sgi-ip32/ip32-memory.c +++ b/arch/mips/sgi-ip32/ip32-memory.c @@ -19,7 +19,7 @@ extern void crime_init(void); -void __init prom_meminit (void) +void __init prom_meminit(void) { u64 base, size; int bank; @@ -38,7 +38,7 @@ void __init prom_meminit (void) printk("CRIME MC: bank %u base 0x%016lx size %luMiB\n", bank, base, size >> 20); - add_memory_region (base, size, BOOT_MEM_RAM); + add_memory_region(base, size, BOOT_MEM_RAM); } } diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c index 4fcdaa8ba514..63b444eaf01e 100644 --- a/arch/mips/sibyte/common/sb_tbprof.c +++ b/arch/mips/sibyte/common/sb_tbprof.c @@ -276,8 +276,8 @@ static int sbprof_zbprof_start(struct file *filp) sbp.next_tb_sample = 0; filp->f_pos = 0; - err = request_irq (K_INT_TRACE_FREEZE, sbprof_tb_intr, 0, - DEVNAME " trace freeze", &sbp); + err = request_irq(K_INT_TRACE_FREEZE, sbprof_tb_intr, 0, + DEVNAME " trace freeze", &sbp); if (err) return -EBUSY; diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c index acc9ba76c1a9..b74607599971 100644 --- a/arch/mips/sni/a20r.c +++ b/arch/mips/sni/a20r.c @@ -127,7 +127,7 @@ static u32 a20r_ack_hwint(void) { u32 status = read_c0_status(); - write_c0_status (status | 0x00010000); + write_c0_status(status | 0x00010000); asm volatile( " .set push \n" " .set noat \n" @@ -195,7 +195,7 @@ static void a20r_hwint(void) u32 cause, status; int irq; - clear_c0_status (IE_IRQ0); + clear_c0_status(IE_IRQ0); status = a20r_ack_hwint(); cause = read_c0_cause(); @@ -213,7 +213,7 @@ void __init sni_a20r_irq_init(void) set_irq_chip(i, &a20r_irq_type); sni_hwint = a20r_hwint; change_c0_status(ST0_IM, IE_IRQ0); - setup_irq (SNI_A20R_IRQ_BASE + 3, &sni_isa_irq); + setup_irq(SNI_A20R_IRQ_BASE + 3, &sni_isa_irq); } void sni_a20r_init(void) diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c index 25cf646329ae..39bb15f1f2a6 100644 --- a/arch/mips/sni/pcimt.c +++ b/arch/mips/sni/pcimt.c @@ -284,9 +284,9 @@ static void sni_pcimt_hwint(void) u32 pending = read_c0_cause() & read_c0_status(); if (pending & C_IRQ5) - do_IRQ (MIPS_CPU_IRQ_BASE + 7); + do_IRQ(MIPS_CPU_IRQ_BASE + 7); else if (pending & C_IRQ4) - do_IRQ (MIPS_CPU_IRQ_BASE + 6); + do_IRQ(MIPS_CPU_IRQ_BASE + 6); else if (pending & C_IRQ3) pcimt_hwint3(); else if (pending & C_IRQ1) diff --git a/arch/mips/sni/pcit.c b/arch/mips/sni/pcit.c index 3361bdd240e6..416f397c768b 100644 --- a/arch/mips/sni/pcit.c +++ b/arch/mips/sni/pcit.c @@ -188,8 +188,8 @@ static void pcit_hwint1(void) irq = ffs((pending >> 16) & 0x7f); if (likely(irq > 0)) - do_IRQ (irq + SNI_PCIT_INT_START - 1); - set_c0_status (IE_IRQ1); + do_IRQ(irq + SNI_PCIT_INT_START - 1); + set_c0_status(IE_IRQ1); } static void pcit_hwint0(void) @@ -201,8 +201,8 @@ static void pcit_hwint0(void) irq = ffs((pending >> 16) & 0x3f); if (likely(irq > 0)) - do_IRQ (irq + SNI_PCIT_INT_START - 1); - set_c0_status (IE_IRQ0); + do_IRQ(irq + SNI_PCIT_INT_START - 1); + set_c0_status(IE_IRQ0); } static void sni_pcit_hwint(void) @@ -212,11 +212,11 @@ static void sni_pcit_hwint(void) if (pending & C_IRQ1) pcit_hwint1(); else if (pending & C_IRQ2) - do_IRQ (MIPS_CPU_IRQ_BASE + 4); + do_IRQ(MIPS_CPU_IRQ_BASE + 4); else if (pending & C_IRQ3) - do_IRQ (MIPS_CPU_IRQ_BASE + 5); + do_IRQ(MIPS_CPU_IRQ_BASE + 5); else if (pending & C_IRQ5) - do_IRQ (MIPS_CPU_IRQ_BASE + 7); + do_IRQ(MIPS_CPU_IRQ_BASE + 7); } static void sni_pcit_hwint_cplus(void) @@ -226,13 +226,13 @@ static void sni_pcit_hwint_cplus(void) if (pending & C_IRQ0) pcit_hwint0(); else if (pending & C_IRQ1) - do_IRQ (MIPS_CPU_IRQ_BASE + 3); + do_IRQ(MIPS_CPU_IRQ_BASE + 3); else if (pending & C_IRQ2) - do_IRQ (MIPS_CPU_IRQ_BASE + 4); + do_IRQ(MIPS_CPU_IRQ_BASE + 4); else if (pending & C_IRQ3) - do_IRQ (MIPS_CPU_IRQ_BASE + 5); + do_IRQ(MIPS_CPU_IRQ_BASE + 5); else if (pending & C_IRQ5) - do_IRQ (MIPS_CPU_IRQ_BASE + 7); + do_IRQ(MIPS_CPU_IRQ_BASE + 7); } void __init sni_pcit_irq_init(void) @@ -245,7 +245,7 @@ void __init sni_pcit_irq_init(void) *(volatile u32 *)SNI_PCIT_INT_REG = 0; sni_hwint = sni_pcit_hwint; change_c0_status(ST0_IM, IE_IRQ1); - setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq); + setup_irq(SNI_PCIT_INT_START + 6, &sni_isa_irq); } void __init sni_pcit_cplus_irq_init(void) @@ -258,7 +258,7 @@ void __init sni_pcit_cplus_irq_init(void) *(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000; sni_hwint = sni_pcit_hwint_cplus; change_c0_status(ST0_IM, IE_IRQ0); - setup_irq (MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq); + setup_irq(MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq); } void __init sni_pcit_init(void) diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c index 94f115c6b2e0..67b061eef6cd 100644 --- a/arch/mips/sni/rm200.c +++ b/arch/mips/sni/rm200.c @@ -162,16 +162,16 @@ static void sni_rm200_hwint(void) int irq; if (pending & C_IRQ5) - do_IRQ (MIPS_CPU_IRQ_BASE + 7); + do_IRQ(MIPS_CPU_IRQ_BASE + 7); else if (pending & C_IRQ0) { - clear_c0_status (IE_IRQ0); + clear_c0_status(IE_IRQ0); mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f; stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14; irq = ffs(stat & mask & 0x1f); if (likely(irq > 0)) - do_IRQ (irq + SNI_RM200_INT_START - 1); - set_c0_status (IE_IRQ0); + do_IRQ(irq + SNI_RM200_INT_START - 1); + set_c0_status(IE_IRQ0); } } @@ -187,7 +187,7 @@ void __init sni_rm200_irq_init(void) set_irq_chip(i, &rm200_irq_type); sni_hwint = sni_rm200_hwint; change_c0_status(ST0_IM, IE_IRQ0); - setup_irq (SNI_RM200_INT_START + 0, &sni_isa_irq); + setup_irq(SNI_RM200_INT_START + 0, &sni_isa_irq); } void __init sni_rm200_init(void) diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 883e35ea4e82..e8b26bdee24c 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -106,11 +106,11 @@ static void __devinit quirk_cirrus_ram_size(struct pci_dev *dev) * need to do it here, otherwise we get screen corruption * on older Cirrus chips */ - pci_read_config_word (dev, PCI_COMMAND, &cmd); + pci_read_config_word(dev, PCI_COMMAND, &cmd); if ((cmd & (PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) == (PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) { - vga_wseq (NULL, CL_SEQR6, 0x12); /* unlock all extension registers */ - vga_wseq (NULL, CL_SEQRF, 0x18); + vga_wseq(NULL, CL_SEQR6, 0x12); /* unlock all extension registers */ + vga_wseq(NULL, CL_SEQRF, 0x18); } } diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c index db544a6e23f3..11eddd43458d 100644 --- a/arch/mips/sni/sniprom.c +++ b/arch/mips/sni/sniprom.c @@ -45,7 +45,7 @@ void prom_putchar(char c) static char *(*__prom_getenv)(char *) = (char *(*)(char *))PROM_ENTRY(PROM_GETENV); static void (*__prom_get_memconf)(void *) = (void (*)(void *))PROM_ENTRY(PROM_GET_MEMCONF); -char *prom_getenv (char *s) +char *prom_getenv(char *s) { return __prom_getenv(s); } @@ -131,9 +131,9 @@ static void __init sni_console_setup(void) int port; static char options[8]; - cdev = prom_getenv ("console_dev"); + cdev = prom_getenv("console_dev"); if (strncmp (cdev, "tty", 3) == 0) { - ctype = prom_getenv ("console"); + ctype = prom_getenv("console"); switch (*ctype) { default: case 'l': diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index 153f065434ea..b80877349d38 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c @@ -44,23 +44,23 @@ static __init unsigned long dosample(void) volatile u8 msb, lsb; /* Start the counter. */ - outb_p (0x34, 0x43); + outb_p(0x34, 0x43); outb_p(SNI_8254_TCSAMP_COUNTER & 0xff, 0x40); - outb (SNI_8254_TCSAMP_COUNTER >> 8, 0x40); + outb(SNI_8254_TCSAMP_COUNTER >> 8, 0x40); /* Get initial counter invariant */ ct0 = read_c0_count(); /* Latch and spin until top byte of counter0 is zero */ do { - outb (0x00, 0x43); - lsb = inb (0x40); - msb = inb (0x40); + outb(0x00, 0x43); + lsb = inb(0x40); + msb = inb(0x40); ct1 = read_c0_count(); } while (msb); /* Stop the counter. */ - outb (0x38, 0x43); + outb(0x38, 0x43); /* * Return the difference, this is how far the r4k counter increments * for every 1/HZ seconds. We round off the nearest 1 MHz of master @@ -137,7 +137,7 @@ void __init plat_timer_setup(struct irqaction *irq) case SNI_BRD_10NEW: case SNI_BRD_TOWER_OASIC: case SNI_BRD_MINITOWER: - sni_a20r_timer_setup (irq); + sni_a20r_timer_setup(irq); break; case SNI_BRD_PCI_TOWER: @@ -146,7 +146,7 @@ void __init plat_timer_setup(struct irqaction *irq) case SNI_BRD_PCI_DESKTOP: case SNI_BRD_PCI_TOWER_CPLUS: case SNI_BRD_PCI_MTOWER_CPLUS: - sni_cpu_timer_setup (irq); + sni_cpu_timer_setup(irq); break; } } diff --git a/include/asm-mips/asmmacro.h b/include/asm-mips/asmmacro.h index c5f20df780e9..7a881755800f 100644 --- a/include/asm-mips/asmmacro.h +++ b/include/asm-mips/asmmacro.h @@ -56,27 +56,27 @@ * Temporary until all gas have MT ASE support */ .macro DMT reg=0 - .word (0x41600bc1 | (\reg << 16)) + .word 0x41600bc1 | (\reg << 16) .endm .macro EMT reg=0 - .word (0x41600be1 | (\reg << 16)) + .word 0x41600be1 | (\reg << 16) .endm .macro DVPE reg=0 - .word (0x41600001 | (\reg << 16)) + .word 0x41600001 | (\reg << 16) .endm .macro EVPE reg=0 - .word (0x41600021 | (\reg << 16)) + .word 0x41600021 | (\reg << 16) .endm .macro MFTR rt=0, rd=0, u=0, sel=0 - .word (0x41000000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel)) + .word 0x41000000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel) .endm .macro MTTR rt=0, rd=0, u=0, sel=0 - .word (0x41800000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel)) + .word 0x41800000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel) .endm #endif /* _ASM_ASMMACRO_H */ diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index 148bc79557f1..899357a72ac4 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h @@ -19,14 +19,14 @@ #include #include -#if (_MIPS_SZLONG == 32) +#if _MIPS_SZLONG == 32 #define SZLONG_LOG 5 #define SZLONG_MASK 31UL #define __LL "ll " #define __SC "sc " #define __INS "ins " #define __EXT "ext " -#elif (_MIPS_SZLONG == 64) +#elif _MIPS_SZLONG == 64 #define SZLONG_LOG 6 #define SZLONG_MASK 63UL #define __LL "lld " @@ -461,7 +461,7 @@ static inline int __ilog2(unsigned long x) int lz; if (sizeof(x) == 4) { - __asm__ ( + __asm__( " .set push \n" " .set mips32 \n" " clz %0, %1 \n" @@ -474,7 +474,7 @@ static inline int __ilog2(unsigned long x) BUG_ON(sizeof(x) != 8); - __asm__ ( + __asm__( " .set push \n" " .set mips64 \n" " dclz %0, %1 \n" @@ -508,7 +508,7 @@ static inline unsigned long __ffs(unsigned long word) */ static inline int fls(int word) { - __asm__ ("clz %0, %1" : "=r" (word) : "r" (word)); + __asm__("clz %0, %1" : "=r" (word) : "r" (word)); return 32 - word; } @@ -516,7 +516,7 @@ static inline int fls(int word) #if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPS64) static inline int fls64(__u64 word) { - __asm__ ("dclz %0, %1" : "=r" (word) : "r" (word)); + __asm__("dclz %0, %1" : "=r" (word) : "r" (word)); return 64 - word; } diff --git a/include/asm-mips/byteorder.h b/include/asm-mips/byteorder.h index eee83cbdf2b0..fe7dc2d59b69 100644 --- a/include/asm-mips/byteorder.h +++ b/include/asm-mips/byteorder.h @@ -65,9 +65,9 @@ static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x) #endif /* __GNUC__ */ -#if defined (__MIPSEB__) +#if defined(__MIPSEB__) # include -#elif defined (__MIPSEL__) +#elif defined(__MIPSEL__) # include #else # error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???" diff --git a/include/asm-mips/elf.h b/include/asm-mips/elf.h index e7d95d48177d..766f91ad5cd3 100644 --- a/include/asm-mips/elf.h +++ b/include/asm-mips/elf.h @@ -319,7 +319,7 @@ do { \ struct task_struct; extern void elf_dump_regs(elf_greg_t *, struct pt_regs *regs); -extern int dump_task_regs (struct task_struct *, elf_gregset_t *); +extern int dump_task_regs(struct task_struct *, elf_gregset_t *); extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); #define ELF_CORE_COPY_REGS(elf_regs, regs) \ diff --git a/include/asm-mips/fixmap.h b/include/asm-mips/fixmap.h index 02c8a13fc894..f27b96cfac2e 100644 --- a/include/asm-mips/fixmap.h +++ b/include/asm-mips/fixmap.h @@ -60,8 +60,8 @@ enum fixed_addresses { __end_of_fixed_addresses }; -extern void __set_fixmap (enum fixed_addresses idx, - unsigned long phys, pgprot_t flags); +extern void __set_fixmap(enum fixed_addresses idx, + unsigned long phys, pgprot_t flags); #define set_fixmap(idx, phys) \ __set_fixmap(idx, phys, PAGE_KERNEL) diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h index b623882bce19..3e7e30d4f418 100644 --- a/include/asm-mips/futex.h +++ b/include/asm-mips/futex.h @@ -75,7 +75,7 @@ } static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) +futex_atomic_op_inuser(int encoded_op, int __user *uaddr) { int op = (encoded_op >> 28) & 7; int cmp = (encoded_op >> 24) & 15; diff --git a/include/asm-mips/inventory.h b/include/asm-mips/inventory.h index 92d90f75a636..cc88aed23f0f 100644 --- a/include/asm-mips/inventory.h +++ b/include/asm-mips/inventory.h @@ -17,8 +17,8 @@ typedef struct inventory_s { extern int inventory_items; -extern void add_to_inventory (int class, int type, int controller, int unit, int state); -extern int dump_inventory_to_user (void __user *userbuf, int size); +extern void add_to_inventory(int class, int type, int controller, int unit, int state); +extern int dump_inventory_to_user(void __user *userbuf, int size); extern int __init init_inventory(void); #endif /* __ASM_INVENTORY_H */ diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h index e459fa05db83..881e8866501d 100644 --- a/include/asm-mips/irqflags.h +++ b/include/asm-mips/irqflags.h @@ -16,7 +16,7 @@ #include #include -__asm__ ( +__asm__( " .macro raw_local_irq_enable \n" " .set push \n" " .set reorder \n" @@ -65,7 +65,7 @@ static inline void raw_local_irq_enable(void) * * Workaround: mask EXL bit of the result or place a nop before mfc0. */ -__asm__ ( +__asm__( " .macro raw_local_irq_disable\n" " .set push \n" " .set noat \n" @@ -96,7 +96,7 @@ static inline void raw_local_irq_disable(void) : "memory"); } -__asm__ ( +__asm__( " .macro raw_local_save_flags flags \n" " .set push \n" " .set reorder \n" @@ -113,7 +113,7 @@ __asm__ __volatile__( \ "raw_local_save_flags %0" \ : "=r" (x)) -__asm__ ( +__asm__( " .macro raw_local_irq_save result \n" " .set push \n" " .set reorder \n" @@ -145,7 +145,7 @@ __asm__ __volatile__( \ : /* no inputs */ \ : "memory") -__asm__ ( +__asm__( " .macro raw_local_irq_restore flags \n" " .set push \n" " .set noreorder \n" diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h index 58fca8a5a9a6..10f613f23c33 100644 --- a/include/asm-mips/mach-au1x00/au1000.h +++ b/include/asm-mips/mach-au1x00/au1000.h @@ -951,25 +951,25 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; /* Programmable Counters 0 and 1 */ #define SYS_BASE 0xB1900000 #define SYS_COUNTER_CNTRL (SYS_BASE + 0x14) - #define SYS_CNTRL_E1S (1<<23) - #define SYS_CNTRL_T1S (1<<20) - #define SYS_CNTRL_M21 (1<<19) - #define SYS_CNTRL_M11 (1<<18) - #define SYS_CNTRL_M01 (1<<17) - #define SYS_CNTRL_C1S (1<<16) - #define SYS_CNTRL_BP (1<<14) - #define SYS_CNTRL_EN1 (1<<13) - #define SYS_CNTRL_BT1 (1<<12) - #define SYS_CNTRL_EN0 (1<<11) - #define SYS_CNTRL_BT0 (1<<10) - #define SYS_CNTRL_E0 (1<<8) - #define SYS_CNTRL_E0S (1<<7) - #define SYS_CNTRL_32S (1<<5) - #define SYS_CNTRL_T0S (1<<4) - #define SYS_CNTRL_M20 (1<<3) - #define SYS_CNTRL_M10 (1<<2) - #define SYS_CNTRL_M00 (1<<1) - #define SYS_CNTRL_C0S (1<<0) +# define SYS_CNTRL_E1S (1<<23) +# define SYS_CNTRL_T1S (1<<20) +# define SYS_CNTRL_M21 (1<<19) +# define SYS_CNTRL_M11 (1<<18) +# define SYS_CNTRL_M01 (1<<17) +# define SYS_CNTRL_C1S (1<<16) +# define SYS_CNTRL_BP (1<<14) +# define SYS_CNTRL_EN1 (1<<13) +# define SYS_CNTRL_BT1 (1<<12) +# define SYS_CNTRL_EN0 (1<<11) +# define SYS_CNTRL_BT0 (1<<10) +# define SYS_CNTRL_E0 (1<<8) +# define SYS_CNTRL_E0S (1<<7) +# define SYS_CNTRL_32S (1<<5) +# define SYS_CNTRL_T0S (1<<4) +# define SYS_CNTRL_M20 (1<<3) +# define SYS_CNTRL_M10 (1<<2) +# define SYS_CNTRL_M00 (1<<1) +# define SYS_CNTRL_C0S (1<<0) /* Programmable Counter 0 Registers */ #define SYS_TOYTRIM (SYS_BASE + 0) @@ -989,34 +989,34 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; /* I2S Controller */ #define I2S_DATA 0xB1000000 - #define I2S_DATA_MASK (0xffffff) +# define I2S_DATA_MASK (0xffffff) #define I2S_CONFIG 0xB1000004 - #define I2S_CONFIG_XU (1<<25) - #define I2S_CONFIG_XO (1<<24) - #define I2S_CONFIG_RU (1<<23) - #define I2S_CONFIG_RO (1<<22) - #define I2S_CONFIG_TR (1<<21) - #define I2S_CONFIG_TE (1<<20) - #define I2S_CONFIG_TF (1<<19) - #define I2S_CONFIG_RR (1<<18) - #define I2S_CONFIG_RE (1<<17) - #define I2S_CONFIG_RF (1<<16) - #define I2S_CONFIG_PD (1<<11) - #define I2S_CONFIG_LB (1<<10) - #define I2S_CONFIG_IC (1<<9) - #define I2S_CONFIG_FM_BIT 7 - #define I2S_CONFIG_FM_MASK (0x3 << I2S_CONFIG_FM_BIT) - #define I2S_CONFIG_FM_I2S (0x0 << I2S_CONFIG_FM_BIT) - #define I2S_CONFIG_FM_LJ (0x1 << I2S_CONFIG_FM_BIT) - #define I2S_CONFIG_FM_RJ (0x2 << I2S_CONFIG_FM_BIT) - #define I2S_CONFIG_TN (1<<6) - #define I2S_CONFIG_RN (1<<5) - #define I2S_CONFIG_SZ_BIT 0 - #define I2S_CONFIG_SZ_MASK (0x1F << I2S_CONFIG_SZ_BIT) +# define I2S_CONFIG_XU (1<<25) +# define I2S_CONFIG_XO (1<<24) +# define I2S_CONFIG_RU (1<<23) +# define I2S_CONFIG_RO (1<<22) +# define I2S_CONFIG_TR (1<<21) +# define I2S_CONFIG_TE (1<<20) +# define I2S_CONFIG_TF (1<<19) +# define I2S_CONFIG_RR (1<<18) +# define I2S_CONFIG_RE (1<<17) +# define I2S_CONFIG_RF (1<<16) +# define I2S_CONFIG_PD (1<<11) +# define I2S_CONFIG_LB (1<<10) +# define I2S_CONFIG_IC (1<<9) +# define I2S_CONFIG_FM_BIT 7 +# define I2S_CONFIG_FM_MASK (0x3 << I2S_CONFIG_FM_BIT) +# define I2S_CONFIG_FM_I2S (0x0 << I2S_CONFIG_FM_BIT) +# define I2S_CONFIG_FM_LJ (0x1 << I2S_CONFIG_FM_BIT) +# define I2S_CONFIG_FM_RJ (0x2 << I2S_CONFIG_FM_BIT) +# define I2S_CONFIG_TN (1<<6) +# define I2S_CONFIG_RN (1<<5) +# define I2S_CONFIG_SZ_BIT 0 +# define I2S_CONFIG_SZ_MASK (0x1F << I2S_CONFIG_SZ_BIT) #define I2S_CONTROL 0xB1000008 - #define I2S_CONTROL_D (1<<1) - #define I2S_CONTROL_CE (1<<0) +# define I2S_CONTROL_D (1<<1) +# define I2S_CONTROL_CE (1<<0) /* USB Host Controller */ #ifndef USB_OHCI_LEN @@ -1034,38 +1034,38 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; #define USBD_EP5RD 0xB0200014 #define USBD_INTEN 0xB0200018 #define USBD_INTSTAT 0xB020001C - #define USBDEV_INT_SOF (1<<12) - #define USBDEV_INT_HF_BIT 6 - #define USBDEV_INT_HF_MASK (0x3f << USBDEV_INT_HF_BIT) - #define USBDEV_INT_CMPLT_BIT 0 - #define USBDEV_INT_CMPLT_MASK (0x3f << USBDEV_INT_CMPLT_BIT) +# define USBDEV_INT_SOF (1<<12) +# define USBDEV_INT_HF_BIT 6 +# define USBDEV_INT_HF_MASK (0x3f << USBDEV_INT_HF_BIT) +# define USBDEV_INT_CMPLT_BIT 0 +# define USBDEV_INT_CMPLT_MASK (0x3f << USBDEV_INT_CMPLT_BIT) #define USBD_CONFIG 0xB0200020 #define USBD_EP0CS 0xB0200024 #define USBD_EP2CS 0xB0200028 #define USBD_EP3CS 0xB020002C #define USBD_EP4CS 0xB0200030 #define USBD_EP5CS 0xB0200034 - #define USBDEV_CS_SU (1<<14) - #define USBDEV_CS_NAK (1<<13) - #define USBDEV_CS_ACK (1<<12) - #define USBDEV_CS_BUSY (1<<11) - #define USBDEV_CS_TSIZE_BIT 1 - #define USBDEV_CS_TSIZE_MASK (0x3ff << USBDEV_CS_TSIZE_BIT) - #define USBDEV_CS_STALL (1<<0) +# define USBDEV_CS_SU (1<<14) +# define USBDEV_CS_NAK (1<<13) +# define USBDEV_CS_ACK (1<<12) +# define USBDEV_CS_BUSY (1<<11) +# define USBDEV_CS_TSIZE_BIT 1 +# define USBDEV_CS_TSIZE_MASK (0x3ff << USBDEV_CS_TSIZE_BIT) +# define USBDEV_CS_STALL (1<<0) #define USBD_EP0RDSTAT 0xB0200040 #define USBD_EP0WRSTAT 0xB0200044 #define USBD_EP2WRSTAT 0xB0200048 #define USBD_EP3WRSTAT 0xB020004C #define USBD_EP4RDSTAT 0xB0200050 #define USBD_EP5RDSTAT 0xB0200054 - #define USBDEV_FSTAT_FLUSH (1<<6) - #define USBDEV_FSTAT_UF (1<<5) - #define USBDEV_FSTAT_OF (1<<4) - #define USBDEV_FSTAT_FCNT_BIT 0 - #define USBDEV_FSTAT_FCNT_MASK (0x0f << USBDEV_FSTAT_FCNT_BIT) +# define USBDEV_FSTAT_FLUSH (1<<6) +# define USBDEV_FSTAT_UF (1<<5) +# define USBDEV_FSTAT_OF (1<<4) +# define USBDEV_FSTAT_FCNT_BIT 0 +# define USBDEV_FSTAT_FCNT_MASK (0x0f << USBDEV_FSTAT_FCNT_BIT) #define USBD_ENABLE 0xB0200058 - #define USBDEV_ENABLE (1<<1) - #define USBDEV_CE (1<<0) +# define USBDEV_ENABLE (1<<1) +# define USBDEV_CE (1<<0) #endif /* !CONFIG_SOC_AU1200 */ @@ -1073,55 +1073,55 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; /* 4 byte offsets from AU1000_ETH_BASE */ #define MAC_CONTROL 0x0 - #define MAC_RX_ENABLE (1<<2) - #define MAC_TX_ENABLE (1<<3) - #define MAC_DEF_CHECK (1<<5) - #define MAC_SET_BL(X) (((X)&0x3)<<6) - #define MAC_AUTO_PAD (1<<8) - #define MAC_DISABLE_RETRY (1<<10) - #define MAC_DISABLE_BCAST (1<<11) - #define MAC_LATE_COL (1<<12) - #define MAC_HASH_MODE (1<<13) - #define MAC_HASH_ONLY (1<<15) - #define MAC_PASS_ALL (1<<16) - #define MAC_INVERSE_FILTER (1<<17) - #define MAC_PROMISCUOUS (1<<18) - #define MAC_PASS_ALL_MULTI (1<<19) - #define MAC_FULL_DUPLEX (1<<20) - #define MAC_NORMAL_MODE 0 - #define MAC_INT_LOOPBACK (1<<21) - #define MAC_EXT_LOOPBACK (1<<22) - #define MAC_DISABLE_RX_OWN (1<<23) - #define MAC_BIG_ENDIAN (1<<30) - #define MAC_RX_ALL (1<<31) +# define MAC_RX_ENABLE (1<<2) +# define MAC_TX_ENABLE (1<<3) +# define MAC_DEF_CHECK (1<<5) +# define MAC_SET_BL(X) (((X)&0x3)<<6) +# define MAC_AUTO_PAD (1<<8) +# define MAC_DISABLE_RETRY (1<<10) +# define MAC_DISABLE_BCAST (1<<11) +# define MAC_LATE_COL (1<<12) +# define MAC_HASH_MODE (1<<13) +# define MAC_HASH_ONLY (1<<15) +# define MAC_PASS_ALL (1<<16) +# define MAC_INVERSE_FILTER (1<<17) +# define MAC_PROMISCUOUS (1<<18) +# define MAC_PASS_ALL_MULTI (1<<19) +# define MAC_FULL_DUPLEX (1<<20) +# define MAC_NORMAL_MODE 0 +# define MAC_INT_LOOPBACK (1<<21) +# define MAC_EXT_LOOPBACK (1<<22) +# define MAC_DISABLE_RX_OWN (1<<23) +# define MAC_BIG_ENDIAN (1<<30) +# define MAC_RX_ALL (1<<31) #define MAC_ADDRESS_HIGH 0x4 #define MAC_ADDRESS_LOW 0x8 #define MAC_MCAST_HIGH 0xC #define MAC_MCAST_LOW 0x10 #define MAC_MII_CNTRL 0x14 - #define MAC_MII_BUSY (1<<0) - #define MAC_MII_READ 0 - #define MAC_MII_WRITE (1<<1) - #define MAC_SET_MII_SELECT_REG(X) (((X)&0x1f)<<6) - #define MAC_SET_MII_SELECT_PHY(X) (((X)&0x1f)<<11) +# define MAC_MII_BUSY (1<<0) +# define MAC_MII_READ 0 +# define MAC_MII_WRITE (1<<1) +# define MAC_SET_MII_SELECT_REG(X) (((X)&0x1f)<<6) +# define MAC_SET_MII_SELECT_PHY(X) (((X)&0x1f)<<11) #define MAC_MII_DATA 0x18 #define MAC_FLOW_CNTRL 0x1C - #define MAC_FLOW_CNTRL_BUSY (1<<0) - #define MAC_FLOW_CNTRL_ENABLE (1<<1) - #define MAC_PASS_CONTROL (1<<2) - #define MAC_SET_PAUSE(X) (((X)&0xffff)<<16) +# define MAC_FLOW_CNTRL_BUSY (1<<0) +# define MAC_FLOW_CNTRL_ENABLE (1<<1) +# define MAC_PASS_CONTROL (1<<2) +# define MAC_SET_PAUSE(X) (((X)&0xffff)<<16) #define MAC_VLAN1_TAG 0x20 #define MAC_VLAN2_TAG 0x24 /* Ethernet Controller Enable */ - #define MAC_EN_CLOCK_ENABLE (1<<0) - #define MAC_EN_RESET0 (1<<1) - #define MAC_EN_TOSS (0<<2) - #define MAC_EN_CACHEABLE (1<<3) - #define MAC_EN_RESET1 (1<<4) - #define MAC_EN_RESET2 (1<<5) - #define MAC_DMA_RESET (1<<6) +# define MAC_EN_CLOCK_ENABLE (1<<0) +# define MAC_EN_RESET0 (1<<1) +# define MAC_EN_TOSS (0<<2) +# define MAC_EN_CACHEABLE (1<<3) +# define MAC_EN_RESET1 (1<<4) +# define MAC_EN_RESET2 (1<<5) +# define MAC_DMA_RESET (1<<6) /* Ethernet Controller DMA Channels */ @@ -1129,22 +1129,22 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; #define MAC1_TX_DMA_ADDR 0xB4004200 /* offsets from MAC_TX_RING_ADDR address */ #define MAC_TX_BUFF0_STATUS 0x0 - #define TX_FRAME_ABORTED (1<<0) - #define TX_JAB_TIMEOUT (1<<1) - #define TX_NO_CARRIER (1<<2) - #define TX_LOSS_CARRIER (1<<3) - #define TX_EXC_DEF (1<<4) - #define TX_LATE_COLL_ABORT (1<<5) - #define TX_EXC_COLL (1<<6) - #define TX_UNDERRUN (1<<7) - #define TX_DEFERRED (1<<8) - #define TX_LATE_COLL (1<<9) - #define TX_COLL_CNT_MASK (0xF<<10) - #define TX_PKT_RETRY (1<<31) +# define TX_FRAME_ABORTED (1<<0) +# define TX_JAB_TIMEOUT (1<<1) +# define TX_NO_CARRIER (1<<2) +# define TX_LOSS_CARRIER (1<<3) +# define TX_EXC_DEF (1<<4) +# define TX_LATE_COLL_ABORT (1<<5) +# define TX_EXC_COLL (1<<6) +# define TX_UNDERRUN (1<<7) +# define TX_DEFERRED (1<<8) +# define TX_LATE_COLL (1<<9) +# define TX_COLL_CNT_MASK (0xF<<10) +# define TX_PKT_RETRY (1<<31) #define MAC_TX_BUFF0_ADDR 0x4 - #define TX_DMA_ENABLE (1<<0) - #define TX_T_DONE (1<<1) - #define TX_GET_DMA_BUFFER(X) (((X)>>2)&0x3) +# define TX_DMA_ENABLE (1<<0) +# define TX_T_DONE (1<<1) +# define TX_GET_DMA_BUFFER(X) (((X)>>2)&0x3) #define MAC_TX_BUFF0_LEN 0x8 #define MAC_TX_BUFF1_STATUS 0x10 #define MAC_TX_BUFF1_ADDR 0x14 @@ -1160,34 +1160,34 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; #define MAC1_RX_DMA_ADDR 0xB4004300 /* offsets from MAC_RX_RING_ADDR */ #define MAC_RX_BUFF0_STATUS 0x0 - #define RX_FRAME_LEN_MASK 0x3fff - #define RX_WDOG_TIMER (1<<14) - #define RX_RUNT (1<<15) - #define RX_OVERLEN (1<<16) - #define RX_COLL (1<<17) - #define RX_ETHER (1<<18) - #define RX_MII_ERROR (1<<19) - #define RX_DRIBBLING (1<<20) - #define RX_CRC_ERROR (1<<21) - #define RX_VLAN1 (1<<22) - #define RX_VLAN2 (1<<23) - #define RX_LEN_ERROR (1<<24) - #define RX_CNTRL_FRAME (1<<25) - #define RX_U_CNTRL_FRAME (1<<26) - #define RX_MCAST_FRAME (1<<27) - #define RX_BCAST_FRAME (1<<28) - #define RX_FILTER_FAIL (1<<29) - #define RX_PACKET_FILTER (1<<30) - #define RX_MISSED_FRAME (1<<31) +# define RX_FRAME_LEN_MASK 0x3fff +# define RX_WDOG_TIMER (1<<14) +# define RX_RUNT (1<<15) +# define RX_OVERLEN (1<<16) +# define RX_COLL (1<<17) +# define RX_ETHER (1<<18) +# define RX_MII_ERROR (1<<19) +# define RX_DRIBBLING (1<<20) +# define RX_CRC_ERROR (1<<21) +# define RX_VLAN1 (1<<22) +# define RX_VLAN2 (1<<23) +# define RX_LEN_ERROR (1<<24) +# define RX_CNTRL_FRAME (1<<25) +# define RX_U_CNTRL_FRAME (1<<26) +# define RX_MCAST_FRAME (1<<27) +# define RX_BCAST_FRAME (1<<28) +# define RX_FILTER_FAIL (1<<29) +# define RX_PACKET_FILTER (1<<30) +# define RX_MISSED_FRAME (1<<31) - #define RX_ERROR (RX_WDOG_TIMER | RX_RUNT | RX_OVERLEN | \ +# define RX_ERROR (RX_WDOG_TIMER | RX_RUNT | RX_OVERLEN | \ RX_COLL | RX_MII_ERROR | RX_CRC_ERROR | \ RX_LEN_ERROR | RX_U_CNTRL_FRAME | RX_MISSED_FRAME) #define MAC_RX_BUFF0_ADDR 0x4 - #define RX_DMA_ENABLE (1<<0) - #define RX_T_DONE (1<<1) - #define RX_GET_DMA_BUFFER(X) (((X)>>2)&0x3) - #define RX_SET_BUFF_ADDR(X) ((X)&0xffffffc0) +# define RX_DMA_ENABLE (1<<0) +# define RX_T_DONE (1<<1) +# define RX_GET_DMA_BUFFER(X) (((X)>>2)&0x3) +# define RX_SET_BUFF_ADDR(X) ((X)&0xffffffc0) #define MAC_RX_BUFF1_STATUS 0x10 #define MAC_RX_BUFF1_ADDR 0x14 #define MAC_RX_BUFF2_STATUS 0x20 @@ -1298,44 +1298,44 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; /* SSIO */ #define SSI0_STATUS 0xB1600000 - #define SSI_STATUS_BF (1<<4) - #define SSI_STATUS_OF (1<<3) - #define SSI_STATUS_UF (1<<2) - #define SSI_STATUS_D (1<<1) - #define SSI_STATUS_B (1<<0) +# define SSI_STATUS_BF (1<<4) +# define SSI_STATUS_OF (1<<3) +# define SSI_STATUS_UF (1<<2) +# define SSI_STATUS_D (1<<1) +# define SSI_STATUS_B (1<<0) #define SSI0_INT 0xB1600004 - #define SSI_INT_OI (1<<3) - #define SSI_INT_UI (1<<2) - #define SSI_INT_DI (1<<1) +# define SSI_INT_OI (1<<3) +# define SSI_INT_UI (1<<2) +# define SSI_INT_DI (1<<1) #define SSI0_INT_ENABLE 0xB1600008 - #define SSI_INTE_OIE (1<<3) - #define SSI_INTE_UIE (1<<2) - #define SSI_INTE_DIE (1<<1) +# define SSI_INTE_OIE (1<<3) +# define SSI_INTE_UIE (1<<2) +# define SSI_INTE_DIE (1<<1) #define SSI0_CONFIG 0xB1600020 - #define SSI_CONFIG_AO (1<<24) - #define SSI_CONFIG_DO (1<<23) - #define SSI_CONFIG_ALEN_BIT 20 - #define SSI_CONFIG_ALEN_MASK (0x7<<20) - #define SSI_CONFIG_DLEN_BIT 16 - #define SSI_CONFIG_DLEN_MASK (0x7<<16) - #define SSI_CONFIG_DD (1<<11) - #define SSI_CONFIG_AD (1<<10) - #define SSI_CONFIG_BM_BIT 8 - #define SSI_CONFIG_BM_MASK (0x3<<8) - #define SSI_CONFIG_CE (1<<7) - #define SSI_CONFIG_DP (1<<6) - #define SSI_CONFIG_DL (1<<5) - #define SSI_CONFIG_EP (1<<4) +# define SSI_CONFIG_AO (1<<24) +# define SSI_CONFIG_DO (1<<23) +# define SSI_CONFIG_ALEN_BIT 20 +# define SSI_CONFIG_ALEN_MASK (0x7<<20) +# define SSI_CONFIG_DLEN_BIT 16 +# define SSI_CONFIG_DLEN_MASK (0x7<<16) +# define SSI_CONFIG_DD (1<<11) +# define SSI_CONFIG_AD (1<<10) +# define SSI_CONFIG_BM_BIT 8 +# define SSI_CONFIG_BM_MASK (0x3<<8) +# define SSI_CONFIG_CE (1<<7) +# define SSI_CONFIG_DP (1<<6) +# define SSI_CONFIG_DL (1<<5) +# define SSI_CONFIG_EP (1<<4) #define SSI0_ADATA 0xB1600024 - #define SSI_AD_D (1<<24) - #define SSI_AD_ADDR_BIT 16 - #define SSI_AD_ADDR_MASK (0xff<<16) - #define SSI_AD_DATA_BIT 0 - #define SSI_AD_DATA_MASK (0xfff<<0) +# define SSI_AD_D (1<<24) +# define SSI_AD_ADDR_BIT 16 +# define SSI_AD_ADDR_MASK (0xff<<16) +# define SSI_AD_DATA_BIT 0 +# define SSI_AD_DATA_MASK (0xfff<<0) #define SSI0_CLKDIV 0xB1600028 #define SSI0_CONTROL 0xB1600100 - #define SSI_CONTROL_CD (1<<1) - #define SSI_CONTROL_E (1<<0) +# define SSI_CONTROL_CD (1<<1) +# define SSI_CONTROL_E (1<<0) /* SSI1 */ #define SSI1_STATUS 0xB1680000 @@ -1401,75 +1401,75 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; #define IR_RING_ADDR_CMPR (IRDA_BASE+0x14) #define IR_INT_CLEAR (IRDA_BASE+0x18) #define IR_CONFIG_1 (IRDA_BASE+0x20) - #define IR_RX_INVERT_LED (1<<0) - #define IR_TX_INVERT_LED (1<<1) - #define IR_ST (1<<2) - #define IR_SF (1<<3) - #define IR_SIR (1<<4) - #define IR_MIR (1<<5) - #define IR_FIR (1<<6) - #define IR_16CRC (1<<7) - #define IR_TD (1<<8) - #define IR_RX_ALL (1<<9) - #define IR_DMA_ENABLE (1<<10) - #define IR_RX_ENABLE (1<<11) - #define IR_TX_ENABLE (1<<12) - #define IR_LOOPBACK (1<<14) - #define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \ +# define IR_RX_INVERT_LED (1<<0) +# define IR_TX_INVERT_LED (1<<1) +# define IR_ST (1<<2) +# define IR_SF (1<<3) +# define IR_SIR (1<<4) +# define IR_MIR (1<<5) +# define IR_FIR (1<<6) +# define IR_16CRC (1<<7) +# define IR_TD (1<<8) +# define IR_RX_ALL (1<<9) +# define IR_DMA_ENABLE (1<<10) +# define IR_RX_ENABLE (1<<11) +# define IR_TX_ENABLE (1<<12) +# define IR_LOOPBACK (1<<14) +# define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \ IR_RX_ALL | IR_RX_ENABLE | IR_SF | IR_16CRC) #define IR_SIR_FLAGS (IRDA_BASE+0x24) #define IR_ENABLE (IRDA_BASE+0x28) - #define IR_RX_STATUS (1<<9) - #define IR_TX_STATUS (1<<10) +# define IR_RX_STATUS (1<<9) +# define IR_TX_STATUS (1<<10) #define IR_READ_PHY_CONFIG (IRDA_BASE+0x2C) #define IR_WRITE_PHY_CONFIG (IRDA_BASE+0x30) #define IR_MAX_PKT_LEN (IRDA_BASE+0x34) #define IR_RX_BYTE_CNT (IRDA_BASE+0x38) #define IR_CONFIG_2 (IRDA_BASE+0x3C) - #define IR_MODE_INV (1<<0) - #define IR_ONE_PIN (1<<1) +# define IR_MODE_INV (1<<0) +# define IR_ONE_PIN (1<<1) #define IR_INTERFACE_CONFIG (IRDA_BASE+0x40) /* GPIO */ #define SYS_PINFUNC 0xB190002C - #define SYS_PF_USB (1<<15) /* 2nd USB device/host */ - #define SYS_PF_U3 (1<<14) /* GPIO23/U3TXD */ - #define SYS_PF_U2 (1<<13) /* GPIO22/U2TXD */ - #define SYS_PF_U1 (1<<12) /* GPIO21/U1TXD */ - #define SYS_PF_SRC (1<<11) /* GPIO6/SROMCKE */ - #define SYS_PF_CK5 (1<<10) /* GPIO3/CLK5 */ - #define SYS_PF_CK4 (1<<9) /* GPIO2/CLK4 */ - #define SYS_PF_IRF (1<<8) /* GPIO15/IRFIRSEL */ - #define SYS_PF_UR3 (1<<7) /* GPIO[14:9]/UART3 */ - #define SYS_PF_I2D (1<<6) /* GPIO8/I2SDI */ - #define SYS_PF_I2S (1<<5) /* I2S/GPIO[29:31] */ - #define SYS_PF_NI2 (1<<4) /* NI2/GPIO[24:28] */ - #define SYS_PF_U0 (1<<3) /* U0TXD/GPIO20 */ - #define SYS_PF_RD (1<<2) /* IRTXD/GPIO19 */ - #define SYS_PF_A97 (1<<1) /* AC97/SSL1 */ - #define SYS_PF_S0 (1<<0) /* SSI_0/GPIO[16:18] */ +# define SYS_PF_USB (1<<15) /* 2nd USB device/host */ +# define SYS_PF_U3 (1<<14) /* GPIO23/U3TXD */ +# define SYS_PF_U2 (1<<13) /* GPIO22/U2TXD */ +# define SYS_PF_U1 (1<<12) /* GPIO21/U1TXD */ +# define SYS_PF_SRC (1<<11) /* GPIO6/SROMCKE */ +# define SYS_PF_CK5 (1<<10) /* GPIO3/CLK5 */ +# define SYS_PF_CK4 (1<<9) /* GPIO2/CLK4 */ +# define SYS_PF_IRF (1<<8) /* GPIO15/IRFIRSEL */ +# define SYS_PF_UR3 (1<<7) /* GPIO[14:9]/UART3 */ +# define SYS_PF_I2D (1<<6) /* GPIO8/I2SDI */ +# define SYS_PF_I2S (1<<5) /* I2S/GPIO[29:31] */ +# define SYS_PF_NI2 (1<<4) /* NI2/GPIO[24:28] */ +# define SYS_PF_U0 (1<<3) /* U0TXD/GPIO20 */ +# define SYS_PF_RD (1<<2) /* IRTXD/GPIO19 */ +# define SYS_PF_A97 (1<<1) /* AC97/SSL1 */ +# define SYS_PF_S0 (1<<0) /* SSI_0/GPIO[16:18] */ /* Au1100 Only */ - #define SYS_PF_PC (1<<18) /* PCMCIA/GPIO[207:204] */ - #define SYS_PF_LCD (1<<17) /* extern lcd/GPIO[203:200] */ - #define SYS_PF_CS (1<<16) /* EXTCLK0/32khz to gpio2 */ - #define SYS_PF_EX0 (1<<9) /* gpio2/clock */ +# define SYS_PF_PC (1<<18) /* PCMCIA/GPIO[207:204] */ +# define SYS_PF_LCD (1<<17) /* extern lcd/GPIO[203:200] */ +# define SYS_PF_CS (1<<16) /* EXTCLK0/32khz to gpio2 */ +# define SYS_PF_EX0 (1<<9) /* gpio2/clock */ /* Au1550 Only. Redefines lots of pins */ - #define SYS_PF_PSC2_MASK (7 << 17) - #define SYS_PF_PSC2_AC97 (0) - #define SYS_PF_PSC2_SPI (0) - #define SYS_PF_PSC2_I2S (1 << 17) - #define SYS_PF_PSC2_SMBUS (3 << 17) - #define SYS_PF_PSC2_GPIO (7 << 17) - #define SYS_PF_PSC3_MASK (7 << 20) - #define SYS_PF_PSC3_AC97 (0) - #define SYS_PF_PSC3_SPI (0) - #define SYS_PF_PSC3_I2S (1 << 20) - #define SYS_PF_PSC3_SMBUS (3 << 20) - #define SYS_PF_PSC3_GPIO (7 << 20) - #define SYS_PF_PSC1_S1 (1 << 1) - #define SYS_PF_MUST_BE_SET ((1 << 5) | (1 << 2)) +# define SYS_PF_PSC2_MASK (7 << 17) +# define SYS_PF_PSC2_AC97 (0) +# define SYS_PF_PSC2_SPI (0) +# define SYS_PF_PSC2_I2S (1 << 17) +# define SYS_PF_PSC2_SMBUS (3 << 17) +# define SYS_PF_PSC2_GPIO (7 << 17) +# define SYS_PF_PSC3_MASK (7 << 20) +# define SYS_PF_PSC3_AC97 (0) +# define SYS_PF_PSC3_SPI (0) +# define SYS_PF_PSC3_I2S (1 << 20) +# define SYS_PF_PSC3_SMBUS (3 << 20) +# define SYS_PF_PSC3_GPIO (7 << 20) +# define SYS_PF_PSC1_S1 (1 << 1) +# define SYS_PF_MUST_BE_SET ((1 << 5) | (1 << 2)) /* Au1200 Only */ #ifdef CONFIG_SOC_AU1200 @@ -1530,104 +1530,104 @@ extern au1xxx_irq_map_t au1xxx_irq_map[]; /* Clock Controller */ #define SYS_FREQCTRL0 0xB1900020 - #define SYS_FC_FRDIV2_BIT 22 - #define SYS_FC_FRDIV2_MASK (0xff << SYS_FC_FRDIV2_BIT) - #define SYS_FC_FE2 (1<<21) - #define SYS_FC_FS2 (1<<20) - #define SYS_FC_FRDIV1_BIT 12 - #define SYS_FC_FRDIV1_MASK (0xff << SYS_FC_FRDIV1_BIT) - #define SYS_FC_FE1 (1<<11) - #define SYS_FC_FS1 (1<<10) - #define SYS_FC_FRDIV0_BIT 2 - #define SYS_FC_FRDIV0_MASK (0xff << SYS_FC_FRDIV0_BIT) - #define SYS_FC_FE0 (1<<1) - #define SYS_FC_FS0 (1<<0) +# define SYS_FC_FRDIV2_BIT 22 +# define SYS_FC_FRDIV2_MASK (0xff << SYS_FC_FRDIV2_BIT) +# define SYS_FC_FE2 (1<<21) +# define SYS_FC_FS2 (1<<20) +# define SYS_FC_FRDIV1_BIT 12 +# define SYS_FC_FRDIV1_MASK (0xff << SYS_FC_FRDIV1_BIT) +# define SYS_FC_FE1 (1<<11) +# define SYS_FC_FS1 (1<<10) +# define SYS_FC_FRDIV0_BIT 2 +# define SYS_FC_FRDIV0_MASK (0xff << SYS_FC_FRDIV0_BIT) +# define SYS_FC_FE0 (1<<1) +# define SYS_FC_FS0 (1<<0) #define SYS_FREQCTRL1 0xB1900024 - #define SYS_FC_FRDIV5_BIT 22 - #define SYS_FC_FRDIV5_MASK (0xff << SYS_FC_FRDIV5_BIT) - #define SYS_FC_FE5 (1<<21) - #define SYS_FC_FS5 (1<<20) - #define SYS_FC_FRDIV4_BIT 12 - #define SYS_FC_FRDIV4_MASK (0xff << SYS_FC_FRDIV4_BIT) - #define SYS_FC_FE4 (1<<11) - #define SYS_FC_FS4 (1<<10) - #define SYS_FC_FRDIV3_BIT 2 - #define SYS_FC_FRDIV3_MASK (0xff << SYS_FC_FRDIV3_BIT) - #define SYS_FC_FE3 (1<<1) - #define SYS_FC_FS3 (1<<0) +# define SYS_FC_FRDIV5_BIT 22 +# define SYS_FC_FRDIV5_MASK (0xff << SYS_FC_FRDIV5_BIT) +# define SYS_FC_FE5 (1<<21) +# define SYS_FC_FS5 (1<<20) +# define SYS_FC_FRDIV4_BIT 12 +# define SYS_FC_FRDIV4_MASK (0xff << SYS_FC_FRDIV4_BIT) +# define SYS_FC_FE4 (1<<11) +# define SYS_FC_FS4 (1<<10) +# define SYS_FC_FRDIV3_BIT 2 +# define SYS_FC_FRDIV3_MASK (0xff << SYS_FC_FRDIV3_BIT) +# define SYS_FC_FE3 (1<<1) +# define SYS_FC_FS3 (1<<0) #define SYS_CLKSRC 0xB1900028 - #define SYS_CS_ME1_BIT 27 - #define SYS_CS_ME1_MASK (0x7<count, val); init_waitqueue_head(&sem->wait); } -static inline void init_MUTEX (struct semaphore *sem) +static inline void init_MUTEX(struct semaphore *sem) { sema_init(sem, 1); } -static inline void init_MUTEX_LOCKED (struct semaphore *sem) +static inline void init_MUTEX_LOCKED(struct semaphore *sem) { sema_init(sem, 0); } diff --git a/include/asm-mips/sim.h b/include/asm-mips/sim.h index 67c4fe52bb42..0cd719fabb51 100644 --- a/include/asm-mips/sim.h +++ b/include/asm-mips/sim.h @@ -18,7 +18,7 @@ #ifdef CONFIG_32BIT #define save_static_function(symbol) \ -__asm__ ( \ +__asm__( \ ".text\n\t" \ ".globl\t" #symbol "\n\t" \ ".align\t2\n\t" \ @@ -46,7 +46,7 @@ __asm__ ( \ #ifdef CONFIG_64BIT #define save_static_function(symbol) \ -__asm__ ( \ +__asm__( \ ".text\n\t" \ ".globl\t" #symbol "\n\t" \ ".align\t2\n\t" \ diff --git a/include/asm-mips/sn/addrs.h b/include/asm-mips/sn/addrs.h index 8fa0af6b68d2..6aa086868249 100644 --- a/include/asm-mips/sn/addrs.h +++ b/include/asm-mips/sn/addrs.h @@ -50,7 +50,7 @@ #define TO_NODE_ADDRSPACE(_pa) (UINT64_CAST (_pa) & NODE_ADDRSPACE_MASK) #define CHANGE_ADDR_NASID(_pa, _nasid) \ - ((UINT64_CAST (_pa) & ~NASID_MASK) | \ + ((UINT64_CAST(_pa) & ~NASID_MASK) | \ (UINT64_CAST(_nasid) << NASID_SHFT)) @@ -75,7 +75,7 @@ #define RAW_NODE_SWIN_BASE(nasid, widget) \ - (NODE_IO_BASE(nasid) + (UINT64_CAST (widget) << SWIN_SIZE_BITS)) + (NODE_IO_BASE(nasid) + (UINT64_CAST(widget) << SWIN_SIZE_BITS)) #define WIDGETID_GET(addr) ((unsigned char)((addr >> SWIN_SIZE_BITS) & 0xff)) @@ -192,21 +192,21 @@ #define BDDIR_ENTRY_LO(_pa) ((HSPEC_BASE + \ NODE_ADDRSPACE_SIZE * 3 / 4 + \ 0x200) | \ - UINT64_CAST (_pa) & NASID_MASK | \ - UINT64_CAST (_pa) >> 2 & BDDIR_UPPER_MASK | \ - UINT64_CAST (_pa) >> 3 & 0x1f << 4) + UINT64_CAST(_pa) & NASID_MASK | \ + UINT64_CAST(_pa) >> 2 & BDDIR_UPPER_MASK | \ + UINT64_CAST(_pa) >> 3 & 0x1f << 4) #define BDDIR_ENTRY_HI(_pa) ((HSPEC_BASE + \ NODE_ADDRSPACE_SIZE * 3 / 4 + \ 0x208) | \ - UINT64_CAST (_pa) & NASID_MASK | \ - UINT64_CAST (_pa) >> 2 & BDDIR_UPPER_MASK | \ - UINT64_CAST (_pa) >> 3 & 0x1f << 4) + UINT64_CAST(_pa) & NASID_MASK | \ + UINT64_CAST(_pa) >> 2 & BDDIR_UPPER_MASK | \ + UINT64_CAST(_pa) >> 3 & 0x1f << 4) #define BDPRT_ENTRY(_pa, _rgn) ((HSPEC_BASE + \ NODE_ADDRSPACE_SIZE * 3 / 4) | \ - UINT64_CAST (_pa) & NASID_MASK | \ - UINT64_CAST (_pa) >> 2 & BDDIR_UPPER_MASK | \ + UINT64_CAST(_pa) & NASID_MASK | \ + UINT64_CAST(_pa) >> 2 & BDDIR_UPPER_MASK | \ (_rgn) << 3) #define BDPRT_ENTRY_ADDR(_pa,_rgn) (BDPRT_ENTRY((_pa),(_rgn))) #define BDPRT_ENTRY_S(_pa,_rgn,_val) (*(__psunsigned_t *)BDPRT_ENTRY((_pa),(_rgn))=(_val)) @@ -214,9 +214,9 @@ #define BDECC_ENTRY(_pa) ((HSPEC_BASE + \ NODE_ADDRSPACE_SIZE / 2) | \ - UINT64_CAST (_pa) & NASID_MASK | \ - UINT64_CAST (_pa) >> 2 & BDECC_UPPER_MASK | \ - UINT64_CAST (_pa) >> 3 & 3) + UINT64_CAST(_pa) & NASID_MASK | \ + UINT64_CAST(_pa) >> 2 & BDECC_UPPER_MASK | \ + UINT64_CAST(_pa) >> 3 & 3) /* * Macro to convert a back door directory or protection address into the @@ -225,16 +225,16 @@ #define BDADDR_IS_DIR(_ba) ((UINT64_CAST (_ba) & 0x200) != 0) #define BDADDR_IS_PRT(_ba) ((UINT64_CAST (_ba) & 0x200) == 0) -#define BDDIR_TO_MEM(_ba) (UINT64_CAST (_ba) & NASID_MASK | \ - (UINT64_CAST (_ba) & BDDIR_UPPER_MASK)<<2 | \ - (UINT64_CAST (_ba) & 0x1f << 4) << 3) +#define BDDIR_TO_MEM(_ba) (UINT64_CAST (_ba) & NASID_MASK | \ + (UINT64_CAST(_ba) & BDDIR_UPPER_MASK)<<2 | \ + (UINT64_CAST(_ba) & 0x1f << 4) << 3) -#define BDPRT_TO_MEM(_ba) (UINT64_CAST (_ba) & NASID_MASK | \ - (UINT64_CAST (_ba) & BDDIR_UPPER_MASK)<<2) +#define BDPRT_TO_MEM(_ba) (UINT64_CAST (_ba) & NASID_MASK | \ + (UINT64_CAST(_ba) & BDDIR_UPPER_MASK)<<2) -#define BDECC_TO_MEM(_ba) (UINT64_CAST (_ba) & NASID_MASK | \ - (UINT64_CAST (_ba) & BDECC_UPPER_MASK)<<2 | \ - (UINT64_CAST (_ba) & 3) << 3) +#define BDECC_TO_MEM(_ba) (UINT64_CAST (_ba) & NASID_MASK | \ + (UINT64_CAST(_ba) & BDECC_UPPER_MASK)<<2 | \ + (UINT64_CAST(_ba) & 3) << 3) #endif /* CONFIG_SGI_IP27 */ @@ -282,7 +282,7 @@ * the base of the register space. */ #define HUB_REG_PTR(_base, _off) \ - (HUBREG_CAST ((__psunsigned_t)(_base) + (__psunsigned_t)(_off))) + (HUBREG_CAST((__psunsigned_t)(_base) + (__psunsigned_t)(_off))) #define HUB_REG_PTR_L(_base, _off) \ HUB_L(HUB_REG_PTR((_base), (_off))) diff --git a/include/asm-mips/sn/io.h b/include/asm-mips/sn/io.h index ab2fa8cd2627..24c6775fbb0f 100644 --- a/include/asm-mips/sn/io.h +++ b/include/asm-mips/sn/io.h @@ -9,7 +9,7 @@ #ifndef _ASM_SN_IO_H #define _ASM_SN_IO_H -#if defined (CONFIG_SGI_IP27) +#if defined(CONFIG_SGI_IP27) #include #endif diff --git a/include/asm-mips/sn/kldir.h b/include/asm-mips/sn/kldir.h index 0573cbffc104..1327e12e9645 100644 --- a/include/asm-mips/sn/kldir.h +++ b/include/asm-mips/sn/kldir.h @@ -140,7 +140,7 @@ */ #define SYMMON_STACK_SIZE 0x8000 -#if defined (PROM) +#if defined(PROM) /* * These defines are prom version dependent. No code other than the IP27 diff --git a/include/asm-mips/sn/sn0/addrs.h b/include/asm-mips/sn/sn0/addrs.h index 9e8cc52910f6..b06190093bbc 100644 --- a/include/asm-mips/sn/sn0/addrs.h +++ b/include/asm-mips/sn/sn0/addrs.h @@ -91,7 +91,7 @@ : RAW_NODE_SWIN_BASE(nasid, widget)) #else /* __ASSEMBLY__ */ #define NODE_SWIN_BASE(nasid, widget) \ - (NODE_IO_BASE(nasid) + (UINT64_CAST (widget) << SWIN_SIZE_BITS)) + (NODE_IO_BASE(nasid) + (UINT64_CAST(widget) << SWIN_SIZE_BITS)) #endif /* __ASSEMBLY__ */ /* @@ -106,7 +106,7 @@ #define BWIN_WIDGET_MASK 0x7 #define NODE_BWIN_BASE0(nasid) (NODE_IO_BASE(nasid) + BWIN_SIZE) #define NODE_BWIN_BASE(nasid, bigwin) (NODE_BWIN_BASE0(nasid) + \ - (UINT64_CAST (bigwin) << BWIN_SIZE_BITS)) + (UINT64_CAST(bigwin) << BWIN_SIZE_BITS)) #define BWIN_WIDGETADDR(addr) ((addr) & BWIN_SIZEMASK) #define BWIN_WINDOWNUM(addr) (((addr) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK) @@ -259,7 +259,7 @@ * CACHE_ERR_SP_PTR could either contain an address to the stack, or * the stack could start at CACHE_ERR_SP_PTR */ -#if defined (HUB_ERR_STS_WAR) +#if defined(HUB_ERR_STS_WAR) #define CACHE_ERR_EFRAME 0x480 #else /* HUB_ERR_STS_WAR */ #define CACHE_ERR_EFRAME 0x400 @@ -275,7 +275,7 @@ #define _ARCSPROM -#if defined (HUB_ERR_STS_WAR) +#if defined(HUB_ERR_STS_WAR) #define ERR_STS_WAR_REGISTER IIO_IIBUSERR #define ERR_STS_WAR_ADDR LOCAL_HUB_ADDR(IIO_IIBUSERR) diff --git a/include/asm-mips/sni.h b/include/asm-mips/sni.h index ddaf36a1e389..4d43dbb7f8b8 100644 --- a/include/asm-mips/sni.h +++ b/include/asm-mips/sni.h @@ -194,17 +194,17 @@ extern unsigned int sni_brd_type; #define PCIMT_INT_ACKNOWLEDGE 0xba000000 /* board specific init functions */ -extern void sni_a20r_init (void); -extern void sni_pcit_init (void); -extern void sni_rm200_init (void); -extern void sni_pcimt_init (void); +extern void sni_a20r_init(void); +extern void sni_pcit_init(void); +extern void sni_rm200_init(void); +extern void sni_pcimt_init(void); /* board specific irq init functions */ -extern void sni_a20r_irq_init (void); -extern void sni_pcit_irq_init (void); -extern void sni_pcit_cplus_irq_init (void); -extern void sni_rm200_irq_init (void); -extern void sni_pcimt_irq_init (void); +extern void sni_a20r_irq_init(void); +extern void sni_pcit_irq_init(void); +extern void sni_pcit_cplus_irq_init(void); +extern void sni_rm200_irq_init(void); +extern void sni_pcimt_irq_init(void); /* timer inits */ extern void sni_cpu_time_init(void); diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 480b574e2483..862f161e88b6 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -195,11 +195,11 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) -extern void set_handler (unsigned long offset, void *addr, unsigned long len); -extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len); +extern void set_handler(unsigned long offset, void *addr, unsigned long len); +extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len); typedef void (*vi_handler_t)(void); -extern void *set_vi_handler (int n, vi_handler_t addr); +extern void *set_vi_handler(int n, vi_handler_t addr); extern void *set_except_vector(int n, void *addr); extern unsigned long ebase; diff --git a/include/asm-mips/timex.h b/include/asm-mips/timex.h index b80de8e0fbbd..87c68ae76ff8 100644 --- a/include/asm-mips/timex.h +++ b/include/asm-mips/timex.h @@ -48,7 +48,7 @@ typedef unsigned int cycles_t; -static inline cycles_t get_cycles (void) +static inline cycles_t get_cycles(void) { return read_c0_count(); } diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h index b25511787ee0..017dfb0d75c3 100644 --- a/include/asm-mips/uaccess.h +++ b/include/asm-mips/uaccess.h @@ -391,9 +391,9 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n); #define __invoke_copy_to_user(to,from,n) \ ({ \ - register void __user *__cu_to_r __asm__ ("$4"); \ - register const void *__cu_from_r __asm__ ("$5"); \ - register long __cu_len_r __asm__ ("$6"); \ + register void __user *__cu_to_r __asm__("$4"); \ + register const void *__cu_from_r __asm__("$5"); \ + register long __cu_len_r __asm__("$6"); \ \ __cu_to_r = (to); \ __cu_from_r = (from); \ @@ -495,9 +495,9 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); #define __invoke_copy_from_user(to,from,n) \ ({ \ - register void *__cu_to_r __asm__ ("$4"); \ - register const void __user *__cu_from_r __asm__ ("$5"); \ - register long __cu_len_r __asm__ ("$6"); \ + register void *__cu_to_r __asm__("$4"); \ + register const void __user *__cu_from_r __asm__("$5"); \ + register long __cu_len_r __asm__("$6"); \ \ __cu_to_r = (to); \ __cu_from_r = (from); \ @@ -518,9 +518,9 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); #define __invoke_copy_from_user_inatomic(to,from,n) \ ({ \ - register void *__cu_to_r __asm__ ("$4"); \ - register const void __user *__cu_from_r __asm__ ("$5"); \ - register long __cu_len_r __asm__ ("$6"); \ + register void *__cu_to_r __asm__("$4"); \ + register const void __user *__cu_from_r __asm__("$5"); \ + register long __cu_len_r __asm__("$6"); \ \ __cu_to_r = (to); \ __cu_from_r = (from); \ From 21a151d8ca3aa74ee79f9791a9d4dc370d3e0636 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:15 +0100 Subject: [PATCH 2266/2804] [MIPS] checkfiles: Fix "need space after that ','" errors. Signed-off-by: Ralf Baechle --- arch/mips/au1000/common/dbdma.c | 4 +- arch/mips/au1000/common/dbg_io.c | 2 +- arch/mips/au1000/common/power.c | 2 +- arch/mips/au1000/pb1200/irqmap.c | 2 +- arch/mips/boot/addinitrd.c | 10 +- arch/mips/boot/elf2ecoff.c | 2 +- arch/mips/kernel/binfmt_elfo32.c | 2 +- arch/mips/kernel/gdb-stub.c | 8 +- arch/mips/kernel/i8259.c | 14 +- arch/mips/kernel/irixelf.c | 8 +- arch/mips/kernel/irixsig.c | 8 +- arch/mips/kernel/irq.c | 4 +- arch/mips/kernel/kspd.c | 2 +- arch/mips/kernel/linux32.c | 10 +- arch/mips/kernel/signal.c | 4 +- arch/mips/kernel/smtc.c | 6 +- arch/mips/kernel/syscall.c | 2 +- arch/mips/kernel/sysirix.c | 2 +- arch/mips/kernel/vpe.c | 2 +- arch/mips/math-emu/cp1emu.c | 24 +- arch/mips/math-emu/dp_mul.c | 2 +- arch/mips/math-emu/ieee754.c | 12 +- arch/mips/math-emu/ieee754dp.h | 12 +- arch/mips/math-emu/ieee754int.h | 30 +- arch/mips/math-emu/ieee754sp.h | 12 +- arch/mips/mips-boards/atlas/atlas_gdb.c | 2 +- arch/mips/mips-boards/malta/malta_int.c | 2 +- arch/mips/mips-boards/malta/malta_setup.c | 2 +- arch/mips/mm/c-r4k.c | 8 +- arch/mips/mm/cerr-sb1.c | 24 +- arch/mips/mm/pg-sb1.c | 4 +- arch/mips/mm/pgtable.c | 8 +- arch/mips/mm/tlb-r8k.c | 2 +- arch/mips/mm/tlbex.c | 94 +-- arch/mips/pci/pci-bcm1480.c | 6 +- arch/mips/pci/pci-bcm1480ht.c | 4 +- arch/mips/pci/pci-sb1250.c | 4 +- arch/mips/philips/pnx8550/common/proc.c | 32 +- arch/mips/pmc-sierra/msp71xx/msp_serial.c | 8 +- arch/mips/pmc-sierra/yosemite/ht.c | 2 +- arch/mips/sgi-ip27/ip27-smp.c | 2 +- arch/mips/sibyte/bcm1480/irq.c | 8 +- arch/mips/sibyte/cfe/console.c | 2 +- arch/mips/sibyte/cfe/setup.c | 2 +- arch/mips/sibyte/sb1250/irq.c | 8 +- arch/mips/sibyte/sb1250/prom.c | 2 +- arch/mips/sibyte/swarm/dbg_io.c | 4 +- arch/mips/sni/reset.c | 2 +- arch/mips/sni/sniprom.c | 2 +- .../toshiba_rbtx4927/toshiba_rbtx4927_irq.c | 2 +- .../toshiba_rbtx4927/toshiba_rbtx4927_setup.c | 4 +- arch/mips/tx4938/toshiba_rbtx4938/setup.c | 4 +- arch/mips/vr41xx/nec-cmbvr4133/init.c | 6 +- arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c | 6 +- include/asm-mips/addrspace.h | 6 +- include/asm-mips/asm.h | 66 +- include/asm-mips/atomic.h | 28 +- include/asm-mips/cmpxchg.h | 4 +- include/asm-mips/delay.h | 2 +- include/asm-mips/floppy.h | 2 +- include/asm-mips/fw/cfe/cfe_api.h | 24 +- include/asm-mips/hazards.h | 2 +- include/asm-mips/io.h | 18 +- include/asm-mips/ioctl.h | 16 +- include/asm-mips/ioctls.h | 12 +- include/asm-mips/jmr3927/tx3927.h | 32 +- include/asm-mips/local.h | 20 +- include/asm-mips/mach-au1x00/au1xxx_dbdma.h | 14 +- include/asm-mips/mach-generic/mangle-port.h | 32 +- include/asm-mips/mach-ip27/mangle-port.h | 16 +- include/asm-mips/mach-ip32/mangle-port.h | 16 +- include/asm-mips/mach-jmr3927/mangle-port.h | 16 +- .../asm-mips/mach-pnx8550/kernel-entry-init.h | 2 +- include/asm-mips/mach-pnx8550/uart.h | 2 +- include/asm-mips/mc146818-time.h | 4 +- include/asm-mips/mips-boards/bonito64.h | 20 +- include/asm-mips/mips-boards/malta.h | 2 +- include/asm-mips/mipsmtregs.h | 60 +- include/asm-mips/mipsregs.h | 4 +- include/asm-mips/mmu_context.h | 4 +- include/asm-mips/paccess.h | 8 +- include/asm-mips/page.h | 2 +- include/asm-mips/pci/bridge.h | 2 +- include/asm-mips/pgalloc.h | 6 +- include/asm-mips/pgtable-32.h | 2 +- include/asm-mips/pgtable-64.h | 4 +- include/asm-mips/pgtable.h | 4 +- include/asm-mips/r4kcache.h | 6 +- include/asm-mips/semaphore.h | 2 +- include/asm-mips/sgiarcs.h | 34 +- include/asm-mips/sibyte/bcm1480_int.h | 22 +- include/asm-mips/sibyte/bcm1480_l2c.h | 102 +-- include/asm-mips/sibyte/bcm1480_mc.h | 644 +++++++++--------- include/asm-mips/sibyte/bcm1480_regs.h | 18 +- include/asm-mips/sibyte/bcm1480_scd.h | 102 +-- include/asm-mips/sibyte/board.h | 4 +- include/asm-mips/sibyte/sb1250_defs.h | 14 +- include/asm-mips/sibyte/sb1250_dma.h | 246 +++---- include/asm-mips/sibyte/sb1250_genbus.h | 322 ++++----- include/asm-mips/sibyte/sb1250_int.h | 22 +- include/asm-mips/sibyte/sb1250_l2c.h | 64 +- include/asm-mips/sibyte/sb1250_ldt.h | 194 +++--- include/asm-mips/sibyte/sb1250_mac.h | 284 ++++---- include/asm-mips/sibyte/sb1250_mc.h | 306 ++++----- include/asm-mips/sibyte/sb1250_regs.h | 32 +- include/asm-mips/sibyte/sb1250_scd.h | 306 ++++----- include/asm-mips/sibyte/sb1250_smbus.h | 62 +- include/asm-mips/sibyte/sb1250_syncser.h | 16 +- include/asm-mips/sibyte/sb1250_uart.h | 70 +- include/asm-mips/siginfo.h | 4 +- include/asm-mips/sn/addrs.h | 6 +- include/asm-mips/sn/klconfig.h | 2 +- include/asm-mips/stackframe.h | 8 +- include/asm-mips/system.h | 4 +- include/asm-mips/tlbflush.h | 4 +- include/asm-mips/tx4938/rbtx4938.h | 2 +- include/asm-mips/tx4938/tx4938.h | 44 +- include/asm-mips/tx4938/tx4938_mips.h | 8 +- include/asm-mips/uaccess.h | 40 +- include/asm-mips/vga.h | 4 +- include/asm-mips/xtalk/xtalk.h | 2 +- 121 files changed, 1951 insertions(+), 1943 deletions(-) diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c index d15b047d480d..461cf0139737 100644 --- a/arch/mips/au1000/common/dbdma.c +++ b/arch/mips/au1000/common/dbdma.c @@ -213,7 +213,7 @@ au1xxx_ddma_add_device(dbdev_tab_t *dev) if ( NULL != p ) { memcpy(p, dev, sizeof(dbdev_tab_t)); - p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id); + p->dev_id = DSCR_DEV2CUSTOM_ID(new_id, dev->dev_id); ret = p->dev_id; new_id++; #if 0 @@ -671,7 +671,7 @@ _au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags) * parts. If it is fixedin the future, these dma_cache_inv will just * be nothing more than empty macros. See io.h. * */ - dma_cache_inv((unsigned long)buf,nbytes); + dma_cache_inv((unsigned long)buf, nbytes); dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ au_sync(); dma_cache_wback_inv((unsigned long)dp, sizeof(dp)); diff --git a/arch/mips/au1000/common/dbg_io.c b/arch/mips/au1000/common/dbg_io.c index 0a50af7f34b8..79e0b0a51ace 100644 --- a/arch/mips/au1000/common/dbg_io.c +++ b/arch/mips/au1000/common/dbg_io.c @@ -53,7 +53,7 @@ typedef unsigned int uint32; /* memory-mapped read/write of the port */ #define UART16550_READ(y) (au_readl(DEBUG_BASE + y) & 0xff) -#define UART16550_WRITE(y,z) (au_writel(z&0xff, DEBUG_BASE + y)) +#define UART16550_WRITE(y, z) (au_writel(z&0xff, DEBUG_BASE + y)) extern unsigned long get_au1x00_uart_baud_base(void); extern unsigned long cal_r4koff(void); diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c index 3901e8e04755..6f57f72a7d57 100644 --- a/arch/mips/au1000/common/power.c +++ b/arch/mips/au1000/common/power.c @@ -211,7 +211,7 @@ int au_sleep(void) unsigned long wakeup, flags; extern void save_and_sleep(void); - spin_lock_irqsave(&pm_lock,flags); + spin_lock_irqsave(&pm_lock, flags); save_core_regs(); diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c index b73b2d18bf56..7c708db04a88 100644 --- a/arch/mips/au1000/pb1200/irqmap.c +++ b/arch/mips/au1000/pb1200/irqmap.c @@ -132,7 +132,7 @@ static void pb1200_shutdown_irq( unsigned int irq_nr ) pb1200_disable_irq(irq_nr); if (--pb1200_cascade_en == 0) { - free_irq(AU1000_GPIO_7,&pb1200_cascade_handler ); + free_irq(AU1000_GPIO_7, &pb1200_cascade_handler ); } return; } diff --git a/arch/mips/boot/addinitrd.c b/arch/mips/boot/addinitrd.c index 193e4be52e79..b5b3febc10cc 100644 --- a/arch/mips/boot/addinitrd.c +++ b/arch/mips/boot/addinitrd.c @@ -40,7 +40,7 @@ void die(char *s) int main(int argc, char *argv[]) { - int fd_vmlinux,fd_initrd,fd_outfile; + int fd_vmlinux, fd_initrd, fd_outfile; FILHDR efile; AOUTHDR eaout; SCNHDR esecs[3]; @@ -48,15 +48,15 @@ int main(int argc, char *argv[]) char buf[1024]; unsigned long loadaddr; unsigned long initrd_header[2]; - int i,cnt; + int i, cnt; int swab = 0; if (argc != 4) { - printf("Usage: %s \n",argv[0]); + printf("Usage: %s \n", argv[0]); exit(1); } - if ((fd_vmlinux = open (argv[1],O_RDONLY)) < 0) + if ((fd_vmlinux = open (argv[1], O_RDONLY)) < 0) die("open vmlinux"); if (read (fd_vmlinux, &efile, sizeof efile) != sizeof efile) die("read file header"); @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) eaout.dsize = esecs[1].s_size = initrd_header[1] = SWAB(st.st_size+8); eaout.data_start = esecs[1].s_vaddr = esecs[1].s_paddr = SWAB(loadaddr); - if ((fd_outfile = open (argv[3], O_RDWR|O_CREAT|O_TRUNC,0666)) < 0) + if ((fd_outfile = open (argv[3], O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) die("open outfile"); if (write (fd_outfile, &efile, sizeof efile) != sizeof efile) die("write file header"); diff --git a/arch/mips/boot/elf2ecoff.c b/arch/mips/boot/elf2ecoff.c index c3543d9eb266..c5a7f308c405 100644 --- a/arch/mips/boot/elf2ecoff.c +++ b/arch/mips/boot/elf2ecoff.c @@ -467,7 +467,7 @@ int main(int argc, char *argv[]) esecs[0].s_scnptr = N_TXTOFF(efh, eah); esecs[1].s_scnptr = N_DATOFF(efh, eah); #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10 -#define ECOFF_ROUND(s,a) (((s)+(a)-1)&~((a)-1)) +#define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1)) esecs[2].s_scnptr = esecs[1].s_scnptr + ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah)); if (addflag) { diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 993f7ec70f35..da41eac195ca 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -110,7 +110,7 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) } #undef ELF_CORE_COPY_REGS -#define ELF_CORE_COPY_REGS(_dest,_regs) elf32_core_copy_regs(_dest,_regs); +#define ELF_CORE_COPY_REGS(_dest, _regs) elf32_core_copy_regs(_dest, _regs); void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs) { diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index 989d06c3827b..c33f6f22d86a 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -902,7 +902,7 @@ void handle_exception(struct gdb_regs *regs) hex2mem(ptr, (char *)®s->frame_ptr, 2*sizeof(long), 0, 0); ptr += 2*(2*sizeof(long)); hex2mem(ptr, (char *)®s->cp0_index, 16*sizeof(long), 0, 0); - strcpy(output_buffer,"OK"); + strcpy(output_buffer, "OK"); } break; @@ -919,7 +919,7 @@ void handle_exception(struct gdb_regs *regs) break; strcpy(output_buffer, "E03"); } else - strcpy(output_buffer,"E01"); + strcpy(output_buffer, "E01"); break; /* @@ -996,7 +996,7 @@ void handle_exception(struct gdb_regs *regs) ptr = &input_buffer[1]; if (!hexToInt(&ptr, &baudrate)) { - strcpy(output_buffer,"B01"); + strcpy(output_buffer, "B01"); break; } @@ -1015,7 +1015,7 @@ void handle_exception(struct gdb_regs *regs) break; default: baudrate = 0; - strcpy(output_buffer,"B02"); + strcpy(output_buffer, "B02"); goto x1; } diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index a860b21e63e9..471013577108 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -127,14 +127,14 @@ static inline int i8259A_irq_real(unsigned int irq) int irqmask = 1 << irq; if (irq < 8) { - outb(0x0B,PIC_MASTER_CMD); /* ISR register */ + outb(0x0B, PIC_MASTER_CMD); /* ISR register */ value = inb(PIC_MASTER_CMD) & irqmask; - outb(0x0A,PIC_MASTER_CMD); /* back to the IRR register */ + outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */ return value; } - outb(0x0B,PIC_SLAVE_CMD); /* ISR register */ + outb(0x0B, PIC_SLAVE_CMD); /* ISR register */ value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); - outb(0x0A,PIC_SLAVE_CMD); /* back to the IRR register */ + outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */ return value; } @@ -175,12 +175,12 @@ handle_real_irq: if (irq & 8) { inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ outb(cached_slave_mask, PIC_SLAVE_IMR); - outb(0x60+(irq&7),PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ - outb(0x60+PIC_CASCADE_IR,PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ + outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ + outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ } else { inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ outb(cached_master_mask, PIC_MASTER_IMR); - outb(0x60+irq,PIC_MASTER_CMD); /* 'Specific EOI to master */ + outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ } smtc_im_ack_irq(irq); spin_unlock_irqrestore(&i8259A_lock, flags); diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index e3b4b547a822..8ef5cf4cc423 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -231,16 +231,16 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc, sp -= argc+1; argv = sp; - __put_user((elf_addr_t)argc,--sp); + __put_user((elf_addr_t)argc, --sp); current->mm->arg_start = (unsigned long) p; while (argc-->0) { - __put_user((unsigned long)p,argv++); + __put_user((unsigned long)p, argv++); p += strlen_user(p); } __put_user((unsigned long) NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { - __put_user((unsigned long)p,envp++); + __put_user((unsigned long)p, envp++); p += strlen_user(p); } __put_user((unsigned long) NULL, envp); @@ -831,7 +831,7 @@ static int load_irix_library(struct file *file) int retval; unsigned int bss; int error; - int i,j, k; + int i, j, k; error = kernel_read(file, 0, (char *) &elf_ex, sizeof(elf_ex)); if (error != sizeof(elf_ex)) diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 28b2a8f00911..85c2e389edd6 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -163,9 +163,9 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info, ret = setup_irix_frame(ka, regs, sig, oldset); spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); + sigaddset(¤t->blocked, sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); @@ -605,8 +605,8 @@ repeat: current->state = TASK_INTERRUPTIBLE; read_lock(&tasklist_lock); tsk = current; - list_for_each(_p,&tsk->children) { - p = list_entry(_p,struct task_struct,sibling); + list_for_each(_p, &tsk->children) { + p = list_entry(_p, struct task_struct, sibling); if ((type == IRIX_P_PID) && p->pid != pid) continue; if ((type == IRIX_P_PGID) && process_group(p) != pid) diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index a990aad2f049..d06e9c9af790 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -93,7 +93,7 @@ int show_interrupts(struct seq_file *p, void *v) if (i == 0) { seq_printf(p, " "); for_each_online_cpu(j) - seq_printf(p, "CPU%d ",j); + seq_printf(p, "CPU%d ", j); seq_putc(p, '\n'); } @@ -102,7 +102,7 @@ int show_interrupts(struct seq_file *p, void *v) action = irq_desc[i].action; if (!action) goto skip; - seq_printf(p, "%3d: ",i); + seq_printf(p, "%3d: ", i); #ifndef CONFIG_SMP seq_printf(p, "%10u ", kstat_irqs(i)); #else diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index 1ed176606548..d2c2e00e5864 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -239,7 +239,7 @@ void sp_work_handle_request(void) case MTSP_SYSCALL_GETTOD: memset(&tz, 0, sizeof(tz)); if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv, - (int)&tz, 0,0)) == 0) + (int)&tz, 0, 0)) == 0) ret.retval = tv.tv_sec; break; diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index a6de17081cad..d6e01215fb2b 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -58,10 +58,10 @@ #define AA(__x) ((unsigned long)((int)__x)) #ifdef __MIPSEB__ -#define merge_64(r1,r2) ((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL)) +#define merge_64(r1, r2) ((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL)) #endif #ifdef __MIPSEL__ -#define merge_64(r1,r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL)) +#define merge_64(r1, r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL)) #endif /* @@ -96,7 +96,7 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) #endif tmp.st_blocks = stat->blocks; tmp.st_blksize = stat->blksize; - return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; + return copy_to_user(statbuf, &tmp, sizeof(tmp)) ? -EFAULT : 0; } asmlinkage unsigned long @@ -510,11 +510,11 @@ asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32) if (err) goto out; - memset(&tmp32,0,sizeof(struct ustat32)); + memset(&tmp32, 0, sizeof(struct ustat32)); tmp32.f_tfree = tmp.f_tfree; tmp32.f_tinode = tmp.f_tinode; - err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0; + err = copy_to_user(ubuf32, &tmp32, sizeof(struct ustat32)) ? -EFAULT : 0; out: return err; diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 2a08ce41bf2b..a4e106c56ab5 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -613,9 +613,9 @@ static int handle_signal(unsigned long sig, siginfo_t *info, ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); + sigaddset(¤t->blocked, sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 770182887c5b..4d91e2f455c0 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -180,7 +180,7 @@ void __init sanitize_tlb_entries(void) static void smtc_configure_tlb(void) { - int i,tlbsiz,vpes; + int i, tlbsiz, vpes; unsigned long mvpconf0; unsigned long config1val; @@ -423,7 +423,7 @@ void mipsmt_prepare_cpus(void) * code. Leave it alone! */ if (tc != 0) { - smtc_tc_setup(vpe,tc, cpu); + smtc_tc_setup(vpe, tc, cpu); cpu++; } printk(" %d", tc); @@ -431,7 +431,7 @@ void mipsmt_prepare_cpus(void) } if (slop) { if (tc != 0) { - smtc_tc_setup(vpe,tc, cpu); + smtc_tc_setup(vpe, tc, cpu); cpu++; } printk(" %d", tc); diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index ef2c6360d052..17c4374d2209 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -245,7 +245,7 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) if (!name) return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) return -EFAULT; error = __copy_to_user(&name->sysname, &utsname()->sysname, diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index b50239574c95..ee7790d9debe 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -778,7 +778,7 @@ asmlinkage int irix_times(struct tms __user *tbuf) int err = 0; if (tbuf) { - if (!access_ok(VERIFY_WRITE,tbuf,sizeof *tbuf)) + if (!access_ok(VERIFY_WRITE, tbuf, sizeof *tbuf)) return -EFAULT; err = __put_user(current->utime, &tbuf->tms_utime); diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 3c09b9785f4c..45077c4b2e22 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -1044,7 +1044,7 @@ static int getcwd(char *buff, int size) old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_getcwd(buff,size); + ret = sys_getcwd(buff, size); set_fs(old_fs); diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index c44e9cc2b19c..b08fc65c13a6 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -178,24 +178,24 @@ static int isBranchInstr(mips_instruction * i) #define FR_BIT 0 #endif -#define SIFROMREG(si,x) ((si) = \ +#define SIFROMREG(si, x) ((si) = \ (xcp->cp0_status & FR_BIT) || !(x & 1) ? \ (int)ctx->fpr[x] : \ (int)(ctx->fpr[x & ~1] >> 32 )) -#define SITOREG(si,x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] = \ +#define SITOREG(si, x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] = \ (xcp->cp0_status & FR_BIT) || !(x & 1) ? \ ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \ ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32) -#define DIFROMREG(di,x) ((di) = \ +#define DIFROMREG(di, x) ((di) = \ ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)]) -#define DITOREG(di,x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] \ +#define DITOREG(di, x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] \ = (di)) -#define SPFROMREG(sp,x) SIFROMREG((sp).bits,x) -#define SPTOREG(sp,x) SITOREG((sp).bits,x) -#define DPFROMREG(dp,x) DIFROMREG((dp).bits,x) -#define DPTOREG(dp,x) DITOREG((dp).bits,x) +#define SPFROMREG(sp, x) SIFROMREG((sp).bits, x) +#define SPTOREG(sp, x) SITOREG((sp).bits, x) +#define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) +#define DPTOREG(dp, x) DITOREG((dp).bits, x) /* * Emulate the single floating point instruction pointed at by EPC. @@ -584,12 +584,12 @@ static ieee754sp fpemu_sp_rsqrt(ieee754sp s) return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); } -DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add,); -DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub,); +DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add, ); +DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub, ); DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg); DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg); -DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add,); -DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub,); +DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add, ); +DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index f2373902f524..48908a809c17 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -121,7 +121,7 @@ ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) */ /* 32 * 32 => 64 */ -#define DPXMULT(x,y) ((u64)(x) * (u64)y) +#define DPXMULT(x, y) ((u64)(x) * (u64)y) { unsigned lxm = xm; diff --git a/arch/mips/math-emu/ieee754.c b/arch/mips/math-emu/ieee754.c index a93c45dbdefd..946aee331788 100644 --- a/arch/mips/math-emu/ieee754.c +++ b/arch/mips/math-emu/ieee754.c @@ -47,13 +47,13 @@ #if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) -#define SPSTR(s,b,m) {m,b,s} -#define DPSTR(s,b,mh,ml) {ml,mh,b,s} +#define SPSTR(s, b, m) {m, b, s} +#define DPSTR(s, b, mh, ml) {ml, mh, b, s} #endif #ifdef __MIPSEB__ -#define SPSTR(s,b,m) {s,b,m} -#define DPSTR(s,b,mh,ml) {s,b,mh,ml} +#define SPSTR(s, b, m) {s, b, m} +#define DPSTR(s, b, mh, ml) {s, b, mh, ml} #endif const struct ieee754dp_konst __ieee754dp_spcvals[] = { @@ -65,7 +65,7 @@ const struct ieee754dp_konst __ieee754dp_spcvals[] = { DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */ DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */ DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */ - DPSTR(0,DP_EMAX+1+DP_EBIAS,0x7FFFF,0xFFFFFFFF), /* + indef quiet Nan */ + DPSTR(0, DP_EMAX+1+DP_EBIAS, 0x7FFFF, 0xFFFFFFFF), /* + indef quiet Nan */ DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */ DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */ DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */ @@ -85,7 +85,7 @@ const struct ieee754sp_konst __ieee754sp_spcvals[] = { SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ - SPSTR(0,SP_EMAX+1+SP_EBIAS,0x3FFFFF), /* + indef quiet Nan */ + SPSTR(0, SP_EMAX+1+SP_EBIAS, 0x3FFFFF), /* + indef quiet Nan */ SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index a37370dae232..8977eb585a37 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h @@ -43,8 +43,8 @@ /* convert denormal to normalized with extended exponent */ #define DPDNORMx(m,e) \ while( (m >> DP_MBITS) == 0) { m <<= 1; e--; } -#define DPDNORMX DPDNORMx(xm,xe) -#define DPDNORMY DPDNORMx(ym,ye) +#define DPDNORMX DPDNORMx(xm, xe) +#define DPDNORMY DPDNORMx(ym, ye) static __inline ieee754dp builddp(int s, int bx, u64 m) { @@ -71,13 +71,13 @@ extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp); extern ieee754dp ieee754dp_format(int, int, u64); -#define DPNORMRET2(s,e,m,name,a0,a1) \ +#define DPNORMRET2(s, e, m, name, a0, a1) \ { \ - ieee754dp V = ieee754dp_format(s,e,m); \ + ieee754dp V = ieee754dp_format(s, e, m); \ if(TSTX()) \ - return ieee754dp_xcpt(V,name,a0,a1); \ + return ieee754dp_xcpt(V, name, a0, a1); \ else \ return V; \ } -#define DPNORMRET1(s,e,m,name,a0) DPNORMRET2(s,e,m,name,a0,a0) +#define DPNORMRET1(s, e, m, name, a0) DPNORMRET2(s, e, m, name, a0, a0) diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index 4a5a81d6b893..1a846c5425cd 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -55,16 +55,16 @@ #define DPBEXP(dp) (dp.parts.bexp) #define DPMANT(dp) (dp.parts.mant) -#define CLPAIR(x,y) ((x)*6+(y)) +#define CLPAIR(x, y) ((x)*6+(y)) #define CLEARCX \ (ieee754_csr.cx = 0) #define SETCX(x) \ - (ieee754_csr.cx |= (x),ieee754_csr.sx |= (x)) + (ieee754_csr.cx |= (x), ieee754_csr.sx |= (x)) #define SETANDTESTCX(x) \ - (SETCX(x),ieee754_csr.mx & (x)) + (SETCX(x), ieee754_csr.mx & (x)) #define TSTX() \ (ieee754_csr.cx & ieee754_csr.mx) @@ -76,7 +76,7 @@ #define COMPYSP \ unsigned ym; int ye; int ys; int yc -#define EXPLODESP(v,vc,vs,ve,vm) \ +#define EXPLODESP(v, vc, vs, ve, vm) \ {\ vs = SPSIGN(v);\ ve = SPBEXP(v);\ @@ -100,8 +100,8 @@ vc = IEEE754_CLASS_NORM;\ }\ } -#define EXPLODEXSP EXPLODESP(x,xc,xs,xe,xm) -#define EXPLODEYSP EXPLODESP(y,yc,ys,ye,ym) +#define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) +#define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) #define COMPXDP \ @@ -110,7 +110,7 @@ u64 xm; int xe; int xs; int xc #define COMPYDP \ u64 ym; int ye; int ys; int yc -#define EXPLODEDP(v,vc,vs,ve,vm) \ +#define EXPLODEDP(v, vc, vs, ve, vm) \ {\ vm = DPMANT(v);\ vs = DPSIGN(v);\ @@ -134,10 +134,10 @@ u64 ym; int ye; int ys; int yc vc = IEEE754_CLASS_NORM;\ }\ } -#define EXPLODEXDP EXPLODEDP(x,xc,xs,xe,xm) -#define EXPLODEYDP EXPLODEDP(y,yc,ys,ye,ym) +#define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) +#define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) -#define FLUSHDP(v,vc,vs,ve,vm) \ +#define FLUSHDP(v, vc, vs, ve, vm) \ if(vc==IEEE754_CLASS_DNORM) {\ if(ieee754_csr.nod) {\ SETCX(IEEE754_INEXACT);\ @@ -148,7 +148,7 @@ u64 ym; int ye; int ys; int yc }\ } -#define FLUSHSP(v,vc,vs,ve,vm) \ +#define FLUSHSP(v, vc, vs, ve, vm) \ if(vc==IEEE754_CLASS_DNORM) {\ if(ieee754_csr.nod) {\ SETCX(IEEE754_INEXACT);\ @@ -159,7 +159,7 @@ u64 ym; int ye; int ys; int yc }\ } -#define FLUSHXDP FLUSHDP(x,xc,xs,xe,xm) -#define FLUSHYDP FLUSHDP(y,yc,ys,ye,ym) -#define FLUSHXSP FLUSHSP(x,xc,xs,xe,xm) -#define FLUSHYSP FLUSHSP(y,yc,ys,ye,ym) +#define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) +#define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) +#define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) +#define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index ae82f51297e5..9917c1e4d947 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -48,8 +48,8 @@ /* convert denormal to normalized with extended exponent */ #define SPDNORMx(m,e) \ while( (m >> SP_MBITS) == 0) { m <<= 1; e--; } -#define SPDNORMX SPDNORMx(xm,xe) -#define SPDNORMY SPDNORMx(ym,ye) +#define SPDNORMX SPDNORMx(xm, xe) +#define SPDNORMY SPDNORMx(ym, ye) static __inline ieee754sp buildsp(int s, int bx, unsigned m) { @@ -77,13 +77,13 @@ extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp); extern ieee754sp ieee754sp_format(int, int, unsigned); -#define SPNORMRET2(s,e,m,name,a0,a1) \ +#define SPNORMRET2(s, e, m, name, a0, a1) \ { \ - ieee754sp V = ieee754sp_format(s,e,m); \ + ieee754sp V = ieee754sp_format(s, e, m); \ if(TSTX()) \ - return ieee754sp_xcpt(V,name,a0,a1); \ + return ieee754sp_xcpt(V, name, a0, a1); \ else \ return V; \ } -#define SPNORMRET1(s,e,m,name,a0) SPNORMRET2(s,e,m,name,a0,a0) +#define SPNORMRET1(s, e, m, name, a0) SPNORMRET2(s, e, m, name, a0, a0) diff --git a/arch/mips/mips-boards/atlas/atlas_gdb.c b/arch/mips/mips-boards/atlas/atlas_gdb.c index fb65280f1780..00c98cff62dc 100644 --- a/arch/mips/mips-boards/atlas/atlas_gdb.c +++ b/arch/mips/mips-boards/atlas/atlas_gdb.c @@ -22,7 +22,7 @@ #include #define INB(a) inb((unsigned long)a) -#define OUTB(x,a) outb(x,(unsigned long)a) +#define OUTB(x, a) outb(x, (unsigned long)a) /* * This is the interface to the remote debugger stub diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index 8232392750a8..f010261b75d8 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c @@ -124,7 +124,7 @@ static void corehi_irqdispatch(void) { unsigned int intedge, intsteer, pcicmd, pcibadaddr; unsigned int pcimstat, intisr, inten, intpol; - unsigned int intrcause,datalo,datahi; + unsigned int intrcause, datalo, datahi; struct pt_regs *regs = get_irq_regs(); printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n"); diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index e243d5efcb38..9a2636e56243 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c @@ -176,7 +176,7 @@ void __init plat_mem_setup(void) 0, /* orig-video-page */ 0, /* orig-video-mode */ 80, /* orig-video-cols */ - 0,0,0, /* ega_ax, ega_bx, ega_cx */ + 0, 0, 0, /* ega_ax, ega_bx, ega_cx */ 25, /* orig-video-lines */ VIDEO_TYPE_VGAC, /* orig-video-isVGA */ 16 /* orig-video-points */ diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 8b7b7c57baca..971f6c047b8a 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -164,12 +164,12 @@ static inline void tx49_blast_icache32(void) /* I'm in even chunk. blast odd chunks */ for (ws = 0; ws < ws_end; ws += ws_inc) for (addr = start + 0x400; addr < end; addr += 0x400 * 2) - cache32_unroll32(addr|ws,Index_Invalidate_I); + cache32_unroll32(addr|ws, Index_Invalidate_I); CACHE32_UNROLL32_ALIGN; /* I'm in odd chunk. blast even chunks */ for (ws = 0; ws < ws_end; ws += ws_inc) for (addr = start; addr < end; addr += 0x400 * 2) - cache32_unroll32(addr|ws,Index_Invalidate_I); + cache32_unroll32(addr|ws, Index_Invalidate_I); } static inline void blast_icache32_r4600_v1_page_indexed(unsigned long page) @@ -195,12 +195,12 @@ static inline void tx49_blast_icache32_page_indexed(unsigned long page) /* I'm in even chunk. blast odd chunks */ for (ws = 0; ws < ws_end; ws += ws_inc) for (addr = start + 0x400; addr < end; addr += 0x400 * 2) - cache32_unroll32(addr|ws,Index_Invalidate_I); + cache32_unroll32(addr|ws, Index_Invalidate_I); CACHE32_UNROLL32_ALIGN; /* I'm in odd chunk. blast even chunks */ for (ws = 0; ws < ws_end; ws += ws_inc) for (addr = start; addr < end; addr += 0x400 * 2) - cache32_unroll32(addr|ws,Index_Invalidate_I); + cache32_unroll32(addr|ws, Index_Invalidate_I); } static void (* r4k_blast_icache_page)(unsigned long addr); diff --git a/arch/mips/mm/cerr-sb1.c b/arch/mips/mm/cerr-sb1.c index 4c72e650f9b6..e7f539e3284b 100644 --- a/arch/mips/mm/cerr-sb1.c +++ b/arch/mips/mm/cerr-sb1.c @@ -271,14 +271,22 @@ asmlinkage void sb1_cache_error(void) /* Parity lookup table. */ static const uint8_t parity[256] = { - 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, - 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, - 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, - 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, - 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, - 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, - 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, - 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0 + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; /* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */ diff --git a/arch/mips/mm/pg-sb1.c b/arch/mips/mm/pg-sb1.c index 82f42ace73c8..a3e98c243a89 100644 --- a/arch/mips/mm/pg-sb1.c +++ b/arch/mips/mm/pg-sb1.c @@ -188,9 +188,9 @@ static inline void copy_page_cpu(void *to, void *from) : "+r" (src), "+r" (dst) : "r" (end) #ifdef CONFIG_64BIT - : "$8","$9","$10","$11","memory"); + : "$8", "$9", "$10", "$11", "memory"); #else - : "$2","$3","$6","$7","$8","$9","$10","$11","memory"); + : "$2", "$3", "$6", "$7", "$8", "$9", "$10", "$11", "memory"); #endif } diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c index c93aa6cbcaca..57df1c38e303 100644 --- a/arch/mips/mm/pgtable.c +++ b/arch/mips/mm/pgtable.c @@ -29,9 +29,9 @@ void show_mem(void) shared += page_count(page) - 1; } printk("%d pages of RAM\n", total); - printk("%d pages of HIGHMEM\n",highmem); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); + printk("%d pages of HIGHMEM\n", highmem); + printk("%d reserved pages\n", reserved); + printk("%d pages shared\n", shared); + printk("%d pages swap cached\n", cached); #endif } diff --git a/arch/mips/mm/tlb-r8k.c b/arch/mips/mm/tlb-r8k.c index 266a47d65eed..bd8409d8ff62 100644 --- a/arch/mips/mm/tlb-r8k.c +++ b/arch/mips/mm/tlb-r8k.c @@ -56,7 +56,7 @@ void local_flush_tlb_mm(struct mm_struct *mm) int cpu = smp_processor_id(); if (cpu_context(cpu, mm) != 0) - drop_mmu_context(mm,cpu); + drop_mmu_context(mm, cpu); } void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index c3da4fefbcb4..a61246d3533d 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -141,53 +141,53 @@ struct insn { | (f) << FUNC_SH) static __initdata struct insn insn_table[] = { - { insn_addiu, M(addiu_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_addu, M(spec_op,0,0,0,0,addu_op), RS | RT | RD }, - { insn_and, M(spec_op,0,0,0,0,and_op), RS | RT | RD }, - { insn_andi, M(andi_op,0,0,0,0,0), RS | RT | UIMM }, - { insn_beq, M(beq_op,0,0,0,0,0), RS | RT | BIMM }, - { insn_beql, M(beql_op,0,0,0,0,0), RS | RT | BIMM }, - { insn_bgez, M(bcond_op,0,bgez_op,0,0,0), RS | BIMM }, - { insn_bgezl, M(bcond_op,0,bgezl_op,0,0,0), RS | BIMM }, - { insn_bltz, M(bcond_op,0,bltz_op,0,0,0), RS | BIMM }, - { insn_bltzl, M(bcond_op,0,bltzl_op,0,0,0), RS | BIMM }, - { insn_bne, M(bne_op,0,0,0,0,0), RS | RT | BIMM }, - { insn_daddiu, M(daddiu_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_daddu, M(spec_op,0,0,0,0,daddu_op), RS | RT | RD }, - { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD | SET}, - { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD | SET}, - { insn_dsll, M(spec_op,0,0,0,0,dsll_op), RT | RD | RE }, - { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE }, - { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE }, - { insn_dsrl, M(spec_op,0,0,0,0,dsrl_op), RT | RD | RE }, - { insn_dsrl32, M(spec_op,0,0,0,0,dsrl32_op), RT | RD | RE }, - { insn_dsubu, M(spec_op,0,0,0,0,dsubu_op), RS | RT | RD }, - { insn_eret, M(cop0_op,cop_op,0,0,0,eret_op), 0 }, - { insn_j, M(j_op,0,0,0,0,0), JIMM }, - { insn_jal, M(jal_op,0,0,0,0,0), JIMM }, - { insn_jr, M(spec_op,0,0,0,0,jr_op), RS }, - { insn_ld, M(ld_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_ll, M(ll_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_lld, M(lld_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_lui, M(lui_op,0,0,0,0,0), RT | SIMM }, - { insn_lw, M(lw_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD | SET}, - { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD | SET}, - { insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM }, - { insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 }, - { insn_sc, M(sc_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_scd, M(scd_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_sd, M(sd_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_sll, M(spec_op,0,0,0,0,sll_op), RT | RD | RE }, - { insn_sra, M(spec_op,0,0,0,0,sra_op), RT | RD | RE }, - { insn_srl, M(spec_op,0,0,0,0,srl_op), RT | RD | RE }, - { insn_subu, M(spec_op,0,0,0,0,subu_op), RS | RT | RD }, - { insn_sw, M(sw_op,0,0,0,0,0), RS | RT | SIMM }, - { insn_tlbp, M(cop0_op,cop_op,0,0,0,tlbp_op), 0 }, - { insn_tlbwi, M(cop0_op,cop_op,0,0,0,tlbwi_op), 0 }, - { insn_tlbwr, M(cop0_op,cop_op,0,0,0,tlbwr_op), 0 }, - { insn_xor, M(spec_op,0,0,0,0,xor_op), RS | RT | RD }, - { insn_xori, M(xori_op,0,0,0,0,0), RS | RT | UIMM }, + { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD }, + { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD }, + { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, + { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, + { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, + { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM }, + { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM }, + { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM }, + { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM }, + { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, + { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, + { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET}, + { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET}, + { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE }, + { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE }, + { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE }, + { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE }, + { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE }, + { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD }, + { insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 }, + { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, + { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM }, + { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS }, + { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM }, + { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET}, + { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET}, + { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, + { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 }, + { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE }, + { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE }, + { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE }, + { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD }, + { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 }, + { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 }, + { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 }, + { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, + { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, { insn_invalid, 0, 0 } }; diff --git a/arch/mips/pci/pci-bcm1480.c b/arch/mips/pci/pci-bcm1480.c index 2b4e30c7d105..5443ea3596f8 100644 --- a/arch/mips/pci/pci-bcm1480.c +++ b/arch/mips/pci/pci-bcm1480.c @@ -49,8 +49,8 @@ * Macros for calculating offsets into config space given a device * structure or dev/fun/reg */ -#define CFGOFFSET(bus,devfn,where) (((bus)<<16)+((devfn)<<8)+(where)) -#define CFGADDR(bus,devfn,where) CFGOFFSET((bus)->number,(devfn),where) +#define CFGOFFSET(bus, devfn, where) (((bus)<<16)+((devfn)<<8)+(where)) +#define CFGADDR(bus, devfn, where) CFGOFFSET((bus)->number, (devfn), where) static void *cfg_space; @@ -255,7 +255,7 @@ static int __init bcm1480_pcibios_init(void) register_pci_controller(&bcm1480_controller); #ifdef CONFIG_VGA_CONSOLE - take_over_console(&vga_con,0,MAX_NR_CONSOLES-1,1); + take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1); #endif return 0; } diff --git a/arch/mips/pci/pci-bcm1480ht.c b/arch/mips/pci/pci-bcm1480ht.c index ba2e34b09231..a63e3bd6b0ac 100644 --- a/arch/mips/pci/pci-bcm1480ht.c +++ b/arch/mips/pci/pci-bcm1480ht.c @@ -48,8 +48,8 @@ * Macros for calculating offsets into config space given a device * structure or dev/fun/reg */ -#define CFGOFFSET(bus,devfn,where) (((bus)<<16)+((devfn)<<8)+(where)) -#define CFGADDR(bus,devfn,where) CFGOFFSET((bus)->number,(devfn),where) +#define CFGOFFSET(bus, devfn, where) (((bus)<<16)+((devfn)<<8)+(where)) +#define CFGADDR(bus, devfn, where) CFGOFFSET((bus)->number, (devfn), where) static void *ht_cfg_space; diff --git a/arch/mips/pci/pci-sb1250.c b/arch/mips/pci/pci-sb1250.c index c1ac6493155e..42e4d2c800fa 100644 --- a/arch/mips/pci/pci-sb1250.c +++ b/arch/mips/pci/pci-sb1250.c @@ -49,8 +49,8 @@ * Macros for calculating offsets into config space given a device * structure or dev/fun/reg */ -#define CFGOFFSET(bus,devfn,where) (((bus)<<16) + ((devfn)<<8) + (where)) -#define CFGADDR(bus,devfn,where) CFGOFFSET((bus)->number,(devfn),where) +#define CFGOFFSET(bus, devfn, where) (((bus)<<16) + ((devfn)<<8) + (where)) +#define CFGADDR(bus, devfn, where) CFGOFFSET((bus)->number, (devfn), where) static void *cfg_space; diff --git a/arch/mips/philips/pnx8550/common/proc.c b/arch/mips/philips/pnx8550/common/proc.c index 416f834784bc..18b125e3b65d 100644 --- a/arch/mips/philips/pnx8550/common/proc.c +++ b/arch/mips/philips/pnx8550/common/proc.c @@ -33,14 +33,14 @@ static int pnx8550_timers_read(char* page, char** start, off_t offset, int count int configPR = read_c0_config7(); if (offset==0) { - len += sprintf(&page[len],"Timer: count, compare, tc, status\n"); - len += sprintf(&page[len]," 1: %11i, %8i, %1i, %s\n", + len += sprintf(&page[len], "Timer: count, compare, tc, status\n"); + len += sprintf(&page[len], " 1: %11i, %8i, %1i, %s\n", read_c0_count(), read_c0_compare(), (configPR>>6)&0x1, ((configPR>>3)&0x1)? "off":"on"); - len += sprintf(&page[len]," 2: %11i, %8i, %1i, %s\n", + len += sprintf(&page[len], " 2: %11i, %8i, %1i, %s\n", read_c0_count2(), read_c0_compare2(), (configPR>>7)&0x1, ((configPR>>4)&0x1)? "off":"on"); - len += sprintf(&page[len]," 3: %11i, %8i, %1i, %s\n", + len += sprintf(&page[len], " 3: %11i, %8i, %1i, %s\n", read_c0_count3(), read_c0_compare3(), (configPR>>8)&0x1, ((configPR>>5)&0x1)? "off":"on"); } @@ -53,18 +53,18 @@ static int pnx8550_registers_read(char* page, char** start, off_t offset, int co int len = 0; if (offset==0) { - len += sprintf(&page[len],"config1: %#10.8x\n",read_c0_config1()); - len += sprintf(&page[len],"config2: %#10.8x\n",read_c0_config2()); - len += sprintf(&page[len],"config3: %#10.8x\n",read_c0_config3()); - len += sprintf(&page[len],"configPR: %#10.8x\n",read_c0_config7()); - len += sprintf(&page[len],"status: %#10.8x\n",read_c0_status()); - len += sprintf(&page[len],"cause: %#10.8x\n",read_c0_cause()); - len += sprintf(&page[len],"count: %#10.8x\n",read_c0_count()); - len += sprintf(&page[len],"count_2: %#10.8x\n",read_c0_count2()); - len += sprintf(&page[len],"count_3: %#10.8x\n",read_c0_count3()); - len += sprintf(&page[len],"compare: %#10.8x\n",read_c0_compare()); - len += sprintf(&page[len],"compare_2: %#10.8x\n",read_c0_compare2()); - len += sprintf(&page[len],"compare_3: %#10.8x\n",read_c0_compare3()); + len += sprintf(&page[len], "config1: %#10.8x\n", read_c0_config1()); + len += sprintf(&page[len], "config2: %#10.8x\n", read_c0_config2()); + len += sprintf(&page[len], "config3: %#10.8x\n", read_c0_config3()); + len += sprintf(&page[len], "configPR: %#10.8x\n", read_c0_config7()); + len += sprintf(&page[len], "status: %#10.8x\n", read_c0_status()); + len += sprintf(&page[len], "cause: %#10.8x\n", read_c0_cause()); + len += sprintf(&page[len], "count: %#10.8x\n", read_c0_count()); + len += sprintf(&page[len], "count_2: %#10.8x\n", read_c0_count2()); + len += sprintf(&page[len], "count_3: %#10.8x\n", read_c0_count3()); + len += sprintf(&page[len], "compare: %#10.8x\n", read_c0_compare()); + len += sprintf(&page[len], "compare_2: %#10.8x\n", read_c0_compare2()); + len += sprintf(&page[len], "compare_3: %#10.8x\n", read_c0_compare3()); } return len; diff --git a/arch/mips/pmc-sierra/msp71xx/msp_serial.c b/arch/mips/pmc-sierra/msp71xx/msp_serial.c index e25bac537d77..15e7b8000b4c 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_serial.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_serial.c @@ -117,7 +117,7 @@ void __init msp_serial_setup(void) /* Initialize first serial port */ up.mapbase = MSP_UART0_BASE; - up.membase = ioremap_nocache(up.mapbase,MSP_UART_REG_LEN); + up.membase = ioremap_nocache(up.mapbase, MSP_UART_REG_LEN); up.irq = MSP_INT_UART0; up.uartclk = uartclk; up.regshift = 2; @@ -145,9 +145,9 @@ void __init msp_serial_setup(void) if( DEBUG_PORT_BASE == KSEG1ADDR(MSP_UART1_BASE) ) { if( mips_machtype == MACH_MSP4200_FPGA || mips_machtype == MACH_MSP7120_FPGA ) - initDebugPort(uartclk,19200); + initDebugPort(uartclk, 19200); else - initDebugPort(uartclk,57600); + initDebugPort(uartclk, 57600); } #endif break; @@ -157,7 +157,7 @@ void __init msp_serial_setup(void) } up.mapbase = MSP_UART1_BASE; - up.membase = ioremap_nocache(up.mapbase,MSP_UART_REG_LEN); + up.membase = ioremap_nocache(up.mapbase, MSP_UART_REG_LEN); up.irq = MSP_INT_UART1; up.line = 1; up.private_data = (void*)UART1_STATUS_REG; diff --git a/arch/mips/pmc-sierra/yosemite/ht.c b/arch/mips/pmc-sierra/yosemite/ht.c index 1f7c999eb7c6..6380662bbf3c 100644 --- a/arch/mips/pmc-sierra/yosemite/ht.c +++ b/arch/mips/pmc-sierra/yosemite/ht.c @@ -115,7 +115,7 @@ static int titan_ht_config_read_word(struct pci_dev *device, u32 longswap(unsigned long l) { - unsigned char b1,b2,b3,b4; + unsigned char b1, b2, b3, b4; b1 = l&255; b2 = (l>>8)&255; diff --git a/arch/mips/sgi-ip27/ip27-smp.c b/arch/mips/sgi-ip27/ip27-smp.c index 493777e39a01..a70656d42191 100644 --- a/arch/mips/sgi-ip27/ip27-smp.c +++ b/arch/mips/sgi-ip27/ip27-smp.c @@ -176,7 +176,7 @@ void __cpuinit prom_boot_secondary(int cpu, struct task_struct *idle) unsigned long gp = (unsigned long)task_thread_info(idle); unsigned long sp = __KSTK_TOS(idle); - LAUNCH_SLAVE(cputonasid(cpu),cputoslice(cpu), + LAUNCH_SLAVE(cputonasid(cpu), cputoslice(cpu), (launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap), 0, (void *) sp, (void *) gp); } diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index cf979dbb282d..7aa79bf63c4a 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c @@ -289,7 +289,7 @@ int bcm1480_steal_irq(int irq) if (irq >= BCM1480_NR_IRQS) return -EINVAL; - spin_lock_irqsave(&desc->lock,flags); + spin_lock_irqsave(&desc->lock, flags); /* Don't allow sharing at all for these */ if (desc->action != NULL) retval = -EBUSY; @@ -297,7 +297,7 @@ int bcm1480_steal_irq(int irq) desc->action = &bcm1480_dummy_action; desc->depth = 0; } - spin_unlock_irqrestore(&desc->lock,flags); + spin_unlock_irqrestore(&desc->lock, flags); return 0; } @@ -431,8 +431,8 @@ void __init arch_init_irq(void) #include -#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) -#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) +#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port, reg))) +#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) static void bcm1480_kgdb_interrupt(void) { diff --git a/arch/mips/sibyte/cfe/console.c b/arch/mips/sibyte/cfe/console.c index 7a4ecfcde48d..81e3d54376e9 100644 --- a/arch/mips/sibyte/cfe/console.c +++ b/arch/mips/sibyte/cfe/console.c @@ -14,7 +14,7 @@ static void cfe_console_write(struct console *cons, const char *str, { int i, last, written; - for (i=0,last=0; i= SB1250_NR_IRQS) return -EINVAL; - spin_lock_irqsave(&desc->lock,flags); + spin_lock_irqsave(&desc->lock, flags); /* Don't allow sharing at all for these */ if (desc->action != NULL) retval = -EBUSY; @@ -267,7 +267,7 @@ int sb1250_steal_irq(int irq) desc->action = &sb1250_dummy_action; desc->depth = 0; } - spin_unlock_irqrestore(&desc->lock,flags); + spin_unlock_irqrestore(&desc->lock, flags); return 0; } @@ -381,8 +381,8 @@ void __init arch_init_irq(void) #include -#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) -#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) +#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port, reg))) +#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) static void sb1250_kgdb_interrupt(void) { diff --git a/arch/mips/sibyte/sb1250/prom.c b/arch/mips/sibyte/sb1250/prom.c index f07ad3baccab..cf8f6b3de86c 100644 --- a/arch/mips/sibyte/sb1250/prom.c +++ b/arch/mips/sibyte/sb1250/prom.c @@ -66,7 +66,7 @@ static void prom_linux_exit(void) { #ifdef CONFIG_SMP if (smp_processor_id()) { - smp_call_function(prom_cpu0_exit,NULL,1,1); + smp_call_function(prom_cpu0_exit, NULL, 1, 1); } #endif while(1); diff --git a/arch/mips/sibyte/swarm/dbg_io.c b/arch/mips/sibyte/swarm/dbg_io.c index 75ce14c8eb69..b97ae3048482 100644 --- a/arch/mips/sibyte/swarm/dbg_io.c +++ b/arch/mips/sibyte/swarm/dbg_io.c @@ -37,8 +37,8 @@ static int duart_initialized = 0; /* 0: need to be init'ed by kgdb */ /* -------------------- END OF CONFIG --------------------- */ extern int kgdb_port; -#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) -#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) +#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port, reg))) +#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port, reg))) void putDebugChar(unsigned char c); unsigned char getDebugChar(void); diff --git a/arch/mips/sni/reset.c b/arch/mips/sni/reset.c index 38b6a97a31b5..79f8d70f48c9 100644 --- a/arch/mips/sni/reset.c +++ b/arch/mips/sni/reset.c @@ -35,7 +35,7 @@ void sni_machine_restart(char *command) kb_wait(); for (j = 0; j < 100000 ; j++) /* nothing */; - outb_p(0xfe,0x64); /* pulse reset low */ + outb_p(0xfe, 0x64); /* pulse reset low */ } } } diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c index 11eddd43458d..eff4b89d7b75 100644 --- a/arch/mips/sni/sniprom.c +++ b/arch/mips/sni/sniprom.c @@ -233,7 +233,7 @@ void __init prom_init(void) systype = "RM300-Exx"; break; } - pr_debug("Found SNI brdtype %02x name %s\n", sni_brd_type,systype); + pr_debug("Found SNI brdtype %02x name %s\n", sni_brd_type, systype); #ifdef DEBUG sni_idprom_dump(); diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index 305eb12f84cc..3f808b629242 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -176,7 +176,7 @@ static const u32 toshiba_rbtx4927_irq_debug_flag = printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \ } #else -#define TOSHIBA_RBTX4927_IRQ_DPRINTK(flag,str...) +#define TOSHIBA_RBTX4927_IRQ_DPRINTK(flag, str...) #endif diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index 4f302062b2d6..acaf613358c7 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c @@ -122,7 +122,7 @@ static const u32 toshiba_rbtx4927_setup_debug_flag = printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \ } #else -#define TOSHIBA_RBTX4927_SETUP_DPRINTK(flag,str...) +#define TOSHIBA_RBTX4927_SETUP_DPRINTK(flag, str...) #endif /* These functions are used for rebooting or halting the machine*/ @@ -497,7 +497,7 @@ void __init tx4927_pci_setup(void) "Internal"); called = 1; } - printk("%s PCIC --%s PCICLK:",toshiba_name, + printk("%s PCIC --%s PCICLK:", toshiba_name, (tx4927_ccfgptr->ccfg & TX4927_CCFG_PCI66) ? " PCI66" : ""); if (tx4927_ccfgptr->pcfg & TX4927_PCFG_PCICLKEN_ALL) { int pciclk = 0; diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c index 304b406fcb9d..ceecaf498957 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c @@ -457,9 +457,9 @@ extern struct pci_controller tx4938_pci_controller[]; static int __init tx4938_pcibios_init(void) { unsigned long mem_base[2]; - unsigned long mem_size[2] = {TX4938_PCIMEM_SIZE_0,TX4938_PCIMEM_SIZE_1}; /* MAX 128M,64K */ + unsigned long mem_size[2] = {TX4938_PCIMEM_SIZE_0, TX4938_PCIMEM_SIZE_1}; /* MAX 128M,64K */ unsigned long io_base[2]; - unsigned long io_size[2] = {TX4938_PCIIO_SIZE_0,TX4938_PCIIO_SIZE_1}; /* MAX 16M,64K */ + unsigned long io_size[2] = {TX4938_PCIIO_SIZE_0, TX4938_PCIIO_SIZE_1}; /* MAX 16M,64K */ /* TX4938 PCIC1: 64K MEM/IO is enough for ETH0,ETH1 */ int extarb = !(tx4938_ccfgptr->ccfg & TX4938_CCFG_PCIXARB); diff --git a/arch/mips/vr41xx/nec-cmbvr4133/init.c b/arch/mips/vr41xx/nec-cmbvr4133/init.c index ae1af6b21c45..7c5e18ee2231 100644 --- a/arch/mips/vr41xx/nec-cmbvr4133/init.c +++ b/arch/mips/vr41xx/nec-cmbvr4133/init.c @@ -36,7 +36,7 @@ void disable_pcnet(void) */ writel((2 << 16) | - (PCI_DEVFN(1,0) << 8) | + (PCI_DEVFN(1, 0) << 8) | (0 & 0xfc) | 1UL, PCICONFAREG); @@ -44,7 +44,7 @@ void disable_pcnet(void) data = readl(PCICONFDREG); writel((2 << 16) | - (PCI_DEVFN(1,0) << 8) | + (PCI_DEVFN(1, 0) << 8) | (4 & 0xfc) | 1UL, PCICONFAREG); @@ -52,7 +52,7 @@ void disable_pcnet(void) data = readl(PCICONFDREG); writel((2 << 16) | - (PCI_DEVFN(1,0) << 8) | + (PCI_DEVFN(1, 0) << 8) | (4 & 0xfc) | 1UL, PCICONFAREG); diff --git a/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c b/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c index f45caccedc07..1341f3287d04 100644 --- a/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c +++ b/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c @@ -38,7 +38,7 @@ outb_p((dev_no), DATA_PORT(port)); \ } while(0) -#define WRITE_CONFIG_DATA(port,index,data) \ +#define WRITE_CONFIG_DATA(port, index, data) \ do { \ outb_p((index), INDEX_PORT(port)); \ outb_p((data), DATA_PORT(port)); \ @@ -206,8 +206,8 @@ static inline u16 ali_config_readw(u8 reg, int devfn) int vr4133_rockhopper = 0; void __init ali_m5229_preinit(void) { - if (ali_config_readw(PCI_VENDOR_ID,16) == PCI_VENDOR_ID_AL && - ali_config_readw(PCI_DEVICE_ID,16) == PCI_DEVICE_ID_AL_M1533) { + if (ali_config_readw(PCI_VENDOR_ID, 16) == PCI_VENDOR_ID_AL && + ali_config_readw(PCI_DEVICE_ID, 16) == PCI_DEVICE_ID_AL_M1533) { printk(KERN_INFO "Found an NEC Rockhopper \n"); vr4133_rockhopper = 1; /* diff --git a/include/asm-mips/addrspace.h b/include/asm-mips/addrspace.h index 0b3ff9c48409..0bb7a93b7a5e 100644 --- a/include/asm-mips/addrspace.h +++ b/include/asm-mips/addrspace.h @@ -123,10 +123,10 @@ /* * 64-bit address conversions */ -#define PHYS_TO_XKSEG_UNCACHED(p) PHYS_TO_XKPHYS(K_CALG_UNCACHED,(p)) -#define PHYS_TO_XKSEG_CACHED(p) PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE,(p)) +#define PHYS_TO_XKSEG_UNCACHED(p) PHYS_TO_XKPHYS(K_CALG_UNCACHED, (p)) +#define PHYS_TO_XKSEG_CACHED(p) PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p)) #define XKPHYS_TO_PHYS(p) ((p) & TO_PHYS_MASK) -#define PHYS_TO_XKPHYS(cm,a) (_CONST64_(0x8000000000000000) | \ +#define PHYS_TO_XKPHYS(cm, a) (_CONST64_(0x8000000000000000) | \ ((cm)<<59) | (a)) /* diff --git a/include/asm-mips/asm.h b/include/asm-mips/asm.h index 838eb3144d81..12e17581b823 100644 --- a/include/asm-mips/asm.h +++ b/include/asm-mips/asm.h @@ -21,11 +21,11 @@ #ifndef CAT #ifdef __STDC__ -#define __CAT(str1,str2) str1##str2 +#define __CAT(str1, str2) str1##str2 #else -#define __CAT(str1,str2) str1/**/str2 +#define __CAT(str1, str2) str1/**/str2 #endif -#define CAT(str1,str2) __CAT(str1,str2) +#define CAT(str1, str2) __CAT(str1, str2) #endif /* @@ -51,9 +51,9 @@ #define LEAF(symbol) \ .globl symbol; \ .align 2; \ - .type symbol,@function; \ - .ent symbol,0; \ -symbol: .frame sp,0,ra + .type symbol, @function; \ + .ent symbol, 0; \ +symbol: .frame sp, 0, ra /* * NESTED - declare nested routine entry point @@ -61,8 +61,8 @@ symbol: .frame sp,0,ra #define NESTED(symbol, framesize, rpc) \ .globl symbol; \ .align 2; \ - .type symbol,@function; \ - .ent symbol,0; \ + .type symbol, @function; \ + .ent symbol, 0; \ symbol: .frame sp, framesize, rpc /* @@ -70,7 +70,7 @@ symbol: .frame sp, framesize, rpc */ #define END(function) \ .end function; \ - .size function,.-function + .size function, .-function /* * EXPORT - export definition of symbol @@ -84,7 +84,7 @@ symbol: */ #define FEXPORT(symbol) \ .globl symbol; \ - .type symbol,@function; \ + .type symbol, @function; \ symbol: /* @@ -97,7 +97,7 @@ symbol = value #define PANIC(msg) \ .set push; \ .set reorder; \ - PTR_LA a0,8f; \ + PTR_LA a0, 8f; \ jal panic; \ 9: b 9b; \ .set pop; \ @@ -110,7 +110,7 @@ symbol = value #define PRINT(string) \ .set push; \ .set reorder; \ - PTR_LA a0,8f; \ + PTR_LA a0, 8f; \ jal printk; \ .set pop; \ TEXT(string) @@ -146,19 +146,19 @@ symbol = value #define PREF(hint,addr) \ .set push; \ .set mips4; \ - pref hint,addr; \ + pref hint, addr; \ .set pop #define PREFX(hint,addr) \ .set push; \ .set mips4; \ - prefx hint,addr; \ + prefx hint, addr; \ .set pop #else /* !CONFIG_CPU_HAS_PREFETCH */ -#define PREF(hint,addr) -#define PREFX(hint,addr) +#define PREF(hint, addr) +#define PREFX(hint, addr) #endif /* !CONFIG_CPU_HAS_PREFETCH */ @@ -166,43 +166,43 @@ symbol = value * MIPS ISA IV/V movn/movz instructions and equivalents for older CPUs. */ #if (_MIPS_ISA == _MIPS_ISA_MIPS1) -#define MOVN(rd,rs,rt) \ +#define MOVN(rd, rs, rt) \ .set push; \ .set reorder; \ - beqz rt,9f; \ - move rd,rs; \ + beqz rt, 9f; \ + move rd, rs; \ .set pop; \ 9: -#define MOVZ(rd,rs,rt) \ +#define MOVZ(rd, rs, rt) \ .set push; \ .set reorder; \ - bnez rt,9f; \ - move rd,rs; \ + bnez rt, 9f; \ + move rd, rs; \ .set pop; \ 9: #endif /* _MIPS_ISA == _MIPS_ISA_MIPS1 */ #if (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) -#define MOVN(rd,rs,rt) \ +#define MOVN(rd, rs, rt) \ .set push; \ .set noreorder; \ - bnezl rt,9f; \ - move rd,rs; \ + bnezl rt, 9f; \ + move rd, rs; \ .set pop; \ 9: -#define MOVZ(rd,rs,rt) \ +#define MOVZ(rd, rs, rt) \ .set push; \ .set noreorder; \ - beqzl rt,9f; \ - move rd,rs; \ + beqzl rt, 9f; \ + move rd, rs; \ .set pop; \ 9: #endif /* (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) */ #if (_MIPS_ISA == _MIPS_ISA_MIPS4 ) || (_MIPS_ISA == _MIPS_ISA_MIPS5) || \ (_MIPS_ISA == _MIPS_ISA_MIPS32) || (_MIPS_ISA == _MIPS_ISA_MIPS64) -#define MOVN(rd,rs,rt) \ - movn rd,rs,rt -#define MOVZ(rd,rs,rt) \ - movz rd,rs,rt +#define MOVN(rd, rs, rt) \ + movn rd, rs, rt +#define MOVZ(rd, rs, rt) \ + movz rd, rs, rt #endif /* MIPS IV, MIPS V, MIPS32 or MIPS64 */ /* @@ -396,6 +396,6 @@ symbol = value #define MTC0 dmtc0 #endif -#define SSNOP sll zero,zero,1 +#define SSNOP sll zero, zero, 1 #endif /* __ASM_ASM_H */ diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h index 7d8003769a44..a798d6299a79 100644 --- a/include/asm-mips/atomic.h +++ b/include/asm-mips/atomic.h @@ -39,7 +39,7 @@ typedef struct { volatile int counter; } atomic_t; * * Atomically sets the value of @v to @i. */ -#define atomic_set(v,i) ((v)->counter = (i)) +#define atomic_set(v, i) ((v)->counter = (i)) /* * atomic_add - add integer to atomic variable @@ -335,8 +335,8 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) } #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) -#define atomic_dec_return(v) atomic_sub_return(1,(v)) -#define atomic_inc_return(v) atomic_add_return(1,(v)) +#define atomic_dec_return(v) atomic_sub_return(1, (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) /* * atomic_sub_and_test - subtract value from variable and test result @@ -347,7 +347,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) * true if the result is zero, or false for all * other cases. */ -#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) /* * atomic_inc_and_test - increment and test @@ -381,7 +381,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) * * Atomically increments @v by 1. */ -#define atomic_inc(v) atomic_add(1,(v)) +#define atomic_inc(v) atomic_add(1, (v)) /* * atomic_dec - decrement and test @@ -389,7 +389,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) * * Atomically decrements @v by 1. */ -#define atomic_dec(v) atomic_sub(1,(v)) +#define atomic_dec(v) atomic_sub(1, (v)) /* * atomic_add_negative - add and test if negative @@ -400,7 +400,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) * if the result is negative, or false when * result is greater than or equal to zero. */ -#define atomic_add_negative(i,v) (atomic_add_return(i, (v)) < 0) +#define atomic_add_negative(i, v) (atomic_add_return(i, (v)) < 0) #ifdef CONFIG_64BIT @@ -420,7 +420,7 @@ typedef struct { volatile long counter; } atomic64_t; * @v: pointer of type atomic64_t * @i: required value */ -#define atomic64_set(v,i) ((v)->counter = (i)) +#define atomic64_set(v, i) ((v)->counter = (i)) /* * atomic64_add - add integer to atomic variable @@ -718,8 +718,8 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) -#define atomic64_dec_return(v) atomic64_sub_return(1,(v)) -#define atomic64_inc_return(v) atomic64_add_return(1,(v)) +#define atomic64_dec_return(v) atomic64_sub_return(1, (v)) +#define atomic64_inc_return(v) atomic64_add_return(1, (v)) /* * atomic64_sub_and_test - subtract value from variable and test result @@ -730,7 +730,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) * true if the result is zero, or false for all * other cases. */ -#define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0) +#define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0) /* * atomic64_inc_and_test - increment and test @@ -764,7 +764,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) * * Atomically increments @v by 1. */ -#define atomic64_inc(v) atomic64_add(1,(v)) +#define atomic64_inc(v) atomic64_add(1, (v)) /* * atomic64_dec - decrement and test @@ -772,7 +772,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) * * Atomically decrements @v by 1. */ -#define atomic64_dec(v) atomic64_sub(1,(v)) +#define atomic64_dec(v) atomic64_sub(1, (v)) /* * atomic64_add_negative - add and test if negative @@ -783,7 +783,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) * if the result is negative, or false when * result is greater than or equal to zero. */ -#define atomic64_add_negative(i,v) (atomic64_add_return(i, (v)) < 0) +#define atomic64_add_negative(i, v) (atomic64_add_return(i, (v)) < 0) #endif /* CONFIG_64BIT */ diff --git a/include/asm-mips/cmpxchg.h b/include/asm-mips/cmpxchg.h index c5b4708e003b..a5ec0e5dc5b8 100644 --- a/include/asm-mips/cmpxchg.h +++ b/include/asm-mips/cmpxchg.h @@ -72,7 +72,7 @@ */ extern void __cmpxchg_called_with_bad_pointer(void); -#define __cmpxchg(ptr,old,new,barrier) \ +#define __cmpxchg(ptr, old, new, barrier) \ ({ \ __typeof__(ptr) __ptr = (ptr); \ __typeof__(*(ptr)) __old = (old); \ @@ -102,6 +102,6 @@ extern void __cmpxchg_called_with_bad_pointer(void); }) #define cmpxchg(ptr, old, new) __cmpxchg(ptr, old, new, smp_llsc_mb()) -#define cmpxchg_local(ptr, old, new) __cmpxchg(ptr, old, new,) +#define cmpxchg_local(ptr, old, new) __cmpxchg(ptr, old, new, ) #endif /* __ASM_CMPXCHG_H */ diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h index 223d156efb9f..fab32131e9b4 100644 --- a/include/asm-mips/delay.h +++ b/include/asm-mips/delay.h @@ -81,7 +81,7 @@ static inline void __udelay(unsigned long usecs, unsigned long lpj) #define __udelay_val cpu_data[raw_smp_processor_id()].udelay_val -#define udelay(usecs) __udelay((usecs),__udelay_val) +#define udelay(usecs) __udelay((usecs), __udelay_val) /* make sure "usecs *= ..." in udelay do not overflow. */ #if HZ >= 1000 diff --git a/include/asm-mips/floppy.h b/include/asm-mips/floppy.h index dcadd8562523..a62d0990c8ae 100644 --- a/include/asm-mips/floppy.h +++ b/include/asm-mips/floppy.h @@ -49,7 +49,7 @@ static inline void fd_cacheflush(char * addr, long size) * Actually this needs to be a bit more complicated since the so much different * hardware available with MIPS CPUs ... */ -#define CROSS_64KB(a,s) ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64) +#define CROSS_64KB(a, s) ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64) #define EXTRA_FLOPPY_PARAMS diff --git a/include/asm-mips/fw/cfe/cfe_api.h b/include/asm-mips/fw/cfe/cfe_api.h index d8230cc53b81..41cf050b6810 100644 --- a/include/asm-mips/fw/cfe/cfe_api.h +++ b/include/asm-mips/fw/cfe/cfe_api.h @@ -136,25 +136,25 @@ int64_t cfe_getticks(void); */ #ifdef CFE_API_IMPL_NAMESPACE #define cfe_close(a) __cfe_close(a) -#define cfe_cpu_start(a,b,c,d,e) __cfe_cpu_start(a,b,c,d,e) +#define cfe_cpu_start(a, b, c, d, e) __cfe_cpu_start(a, b, c, d, e) #define cfe_cpu_stop(a) __cfe_cpu_stop(a) -#define cfe_enumenv(a,b,d,e,f) __cfe_enumenv(a,b,d,e,f) -#define cfe_enummem(a,b,c,d,e) __cfe_enummem(a,b,c,d,e) -#define cfe_exit(a,b) __cfe_exit(a,b) +#define cfe_enumenv(a, b, d, e, f) __cfe_enumenv(a, b, d, e, f) +#define cfe_enummem(a, b, c, d, e) __cfe_enummem(a, b, c, d, e) +#define cfe_exit(a, b) __cfe_exit(a, b) #define cfe_flushcache(a) __cfe_cacheflush(a) #define cfe_getdevinfo(a) __cfe_getdevinfo(a) -#define cfe_getenv(a,b,c) __cfe_getenv(a,b,c) +#define cfe_getenv(a, b, c) __cfe_getenv(a, b, c) #define cfe_getfwinfo(a) __cfe_getfwinfo(a) #define cfe_getstdhandle(a) __cfe_getstdhandle(a) -#define cfe_init(a,b) __cfe_init(a,b) +#define cfe_init(a, b) __cfe_init(a, b) #define cfe_inpstat(a) __cfe_inpstat(a) -#define cfe_ioctl(a,b,c,d,e,f) __cfe_ioctl(a,b,c,d,e,f) +#define cfe_ioctl(a, b, c, d, e, f) __cfe_ioctl(a, b, c, d, e, f) #define cfe_open(a) __cfe_open(a) -#define cfe_read(a,b,c) __cfe_read(a,b,c) -#define cfe_readblk(a,b,c,d) __cfe_readblk(a,b,c,d) -#define cfe_setenv(a,b) __cfe_setenv(a,b) -#define cfe_write(a,b,c) __cfe_write(a,b,c) -#define cfe_writeblk(a,b,c,d) __cfe_writeblk(a,b,c,d) +#define cfe_read(a, b, c) __cfe_read(a, b, c) +#define cfe_readblk(a, b, c, d) __cfe_readblk(a, b, c, d) +#define cfe_setenv(a, b) __cfe_setenv(a, b) +#define cfe_write(a, b, c) __cfe_write(a, b, c) +#define cfe_writeblk(a, b, c, d __cfe_writeblk(a, b, c, d) #endif /* CFE_API_IMPL_NAMESPACE */ int cfe_close(int handle); diff --git a/include/asm-mips/hazards.h b/include/asm-mips/hazards.h index 6a5fa32f615b..7e843b5fee92 100644 --- a/include/asm-mips/hazards.h +++ b/include/asm-mips/hazards.h @@ -193,7 +193,7 @@ ASMMACRO(enable_fpu_hazard, .set mips64; .set noreorder; _ssnop; - bnezl $0,.+4; + bnezl $0, .+4; _ssnop; .set pop ) diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h index 7ba92890ea13..2cd8323c8586 100644 --- a/include/asm-mips/io.h +++ b/include/asm-mips/io.h @@ -40,11 +40,11 @@ * hardware. An example use would be for flash memory that's used for * execute in place. */ -# define __raw_ioswabb(a,x) (x) -# define __raw_ioswabw(a,x) (x) -# define __raw_ioswabl(a,x) (x) -# define __raw_ioswabq(a,x) (x) -# define ____raw_ioswabq(a,x) (x) +# define __raw_ioswabb(a, x) (x) +# define __raw_ioswabw(a, x) (x) +# define __raw_ioswabl(a, x) (x) +# define __raw_ioswabq(a, x) (x) +# define ____raw_ioswabq(a, x) (x) /* ioswab[bwlq], __mem_ioswab[bwlq] are defined in mangle-port.h */ @@ -561,9 +561,9 @@ extern void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); extern void (*_dma_cache_wback)(unsigned long start, unsigned long size); extern void (*_dma_cache_inv)(unsigned long start, unsigned long size); -#define dma_cache_wback_inv(start, size) _dma_cache_wback_inv(start,size) -#define dma_cache_wback(start, size) _dma_cache_wback(start,size) -#define dma_cache_inv(start, size) _dma_cache_inv(start,size) +#define dma_cache_wback_inv(start, size) _dma_cache_wback_inv(start, size) +#define dma_cache_wback(start, size) _dma_cache_wback(start, size) +#define dma_cache_inv(start, size) _dma_cache_inv(start, size) #else /* Sane hardware */ @@ -587,7 +587,7 @@ extern void (*_dma_cache_inv)(unsigned long start, unsigned long size); #define __CSR_32_ADJUST 0 #endif -#define csr_out32(v,a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v)) +#define csr_out32(v, a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v)) #define csr_in32(a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST)) /* diff --git a/include/asm-mips/ioctl.h b/include/asm-mips/ioctl.h index 2036fcb9f117..85067e248a83 100644 --- a/include/asm-mips/ioctl.h +++ b/include/asm-mips/ioctl.h @@ -54,7 +54,7 @@ #define _IOC_IN 0x80000000 #define _IOC_INOUT (IOC_IN|IOC_OUT) -#define _IOC(dir,type,nr,size) \ +#define _IOC(dir, type, nr, size) \ (((dir) << _IOC_DIRSHIFT) | \ ((type) << _IOC_TYPESHIFT) | \ ((nr) << _IOC_NRSHIFT) | \ @@ -68,13 +68,13 @@ extern unsigned int __invalid_size_argument_for_IOC; sizeof(t) : __invalid_size_argument_for_IOC) /* used to create numbers */ -#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) -#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) -#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) -#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IO(type, nr) _IOC(_IOC_NONE, (type), (nr), 0) +#define _IOR(type, nr, size) _IOC(_IOC_READ, (type), (nr), (_IOC_TYPECHECK(size))) +#define _IOW(type, nr, size) _IOC(_IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size))) +#define _IOWR(type, nr, size) _IOC(_IOC_READ|_IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size))) +#define _IOR_BAD(type, nr, size) _IOC(_IOC_READ, (type), (nr), sizeof(size)) +#define _IOW_BAD(type, nr, size) _IOC(_IOC_WRITE, (type), (nr), sizeof(size)) +#define _IOWR_BAD(type, nr, size) _IOC(_IOC_READ|_IOC_WRITE, (type), (nr), sizeof(size)) /* used to decode them.. */ diff --git a/include/asm-mips/ioctls.h b/include/asm-mips/ioctls.h index 5097cbf183a9..3f04a995ec54 100644 --- a/include/asm-mips/ioctls.h +++ b/include/asm-mips/ioctls.h @@ -77,12 +77,12 @@ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x7416 /* 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 TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#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 TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ /* I hope the range from 0x5480 on is free ... */ #define TIOCSCTTY 0x5480 /* become controlling tty */ diff --git a/include/asm-mips/jmr3927/tx3927.h b/include/asm-mips/jmr3927/tx3927.h index 4be2f25f70dd..211bcf47fffb 100644 --- a/include/asm-mips/jmr3927/tx3927.h +++ b/include/asm-mips/jmr3927/tx3927.h @@ -53,23 +53,23 @@ struct tx3927_dma_reg { #include #ifdef __BIG_ENDIAN -#define endian_def_s2(e1,e2) \ - volatile unsigned short e1,e2 -#define endian_def_sb2(e1,e2,e3) \ - volatile unsigned short e1;volatile unsigned char e2,e3 -#define endian_def_b2s(e1,e2,e3) \ - volatile unsigned char e1,e2;volatile unsigned short e3 -#define endian_def_b4(e1,e2,e3,e4) \ - volatile unsigned char e1,e2,e3,e4 +#define endian_def_s2(e1, e2) \ + volatile unsigned short e1, e2 +#define endian_def_sb2(e1, e2, e3) \ + volatile unsigned short e1;volatile unsigned char e2, e3 +#define endian_def_b2s(e1, e2, e3) \ + volatile unsigned char e1, e2;volatile unsigned short e3 +#define endian_def_b4(e1, e2, e3, e4) \ + volatile unsigned char e1, e2, e3, e4 #else -#define endian_def_s2(e1,e2) \ - volatile unsigned short e2,e1 -#define endian_def_sb2(e1,e2,e3) \ - volatile unsigned char e3,e2;volatile unsigned short e1 -#define endian_def_b2s(e1,e2,e3) \ - volatile unsigned short e3;volatile unsigned char e2,e1 -#define endian_def_b4(e1,e2,e3,e4) \ - volatile unsigned char e4,e3,e2,e1 +#define endian_def_s2(e1, e2) \ + volatile unsigned short e2, e1 +#define endian_def_sb2(e1, e2, e3) \ + volatile unsigned char e3, e2;volatile unsigned short e1 +#define endian_def_b2s(e1, e2, e3) \ + volatile unsigned short e3;volatile unsigned char e2, e1 +#define endian_def_b4(e1, e2, e3, e4) \ + volatile unsigned char e4, e3, e2, e1 #endif struct tx3927_pcic_reg { diff --git a/include/asm-mips/local.h b/include/asm-mips/local.h index f9a5ce5c9af1..f96fd59e0845 100644 --- a/include/asm-mips/local.h +++ b/include/asm-mips/local.h @@ -15,10 +15,10 @@ typedef struct #define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } #define local_read(l) atomic_long_read(&(l)->a) -#define local_set(l,i) atomic_long_set(&(l)->a, (i)) +#define local_set(l, i) atomic_long_set(&(l)->a, (i)) -#define local_add(i,l) atomic_long_add((i),(&(l)->a)) -#define local_sub(i,l) atomic_long_sub((i),(&(l)->a)) +#define local_add(i, l) atomic_long_add((i), (&(l)->a)) +#define local_sub(i, l) atomic_long_sub((i), (&(l)->a)) #define local_inc(l) atomic_long_inc(&(l)->a) #define local_dec(l) atomic_long_dec(&(l)->a) @@ -117,7 +117,7 @@ static __inline__ long local_sub_return(long i, local_t * l) #define local_cmpxchg(l, o, n) \ ((long)cmpxchg_local(&((l)->a.counter), (o), (n))) -#define local_xchg(l, n) (xchg_local(&((l)->a.counter),(n))) +#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n))) /** * local_add_unless - add unless the number is a given value @@ -138,8 +138,8 @@ static __inline__ long local_sub_return(long i, local_t * l) }) #define local_inc_not_zero(l) local_add_unless((l), 1, 0) -#define local_dec_return(l) local_sub_return(1,(l)) -#define local_inc_return(l) local_add_return(1,(l)) +#define local_dec_return(l) local_sub_return(1, (l)) +#define local_inc_return(l) local_add_return(1, (l)) /* * local_sub_and_test - subtract value from variable and test result @@ -150,7 +150,7 @@ static __inline__ long local_sub_return(long i, local_t * l) * true if the result is zero, or false for all * other cases. */ -#define local_sub_and_test(i,l) (local_sub_return((i), (l)) == 0) +#define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0) /* * local_inc_and_test - increment and test @@ -181,7 +181,7 @@ static __inline__ long local_sub_return(long i, local_t * l) * if the result is negative, or false when * result is greater than or equal to zero. */ -#define local_add_negative(i,l) (local_add_return(i, (l)) < 0) +#define local_add_negative(i, l) (local_add_return(i, (l)) < 0) /* Use these for per-cpu local_t variables: on some archs they are * much more efficient than these naive implementations. Note they take @@ -190,8 +190,8 @@ static __inline__ long local_sub_return(long i, local_t * l) #define __local_inc(l) ((l)->a.counter++) #define __local_dec(l) ((l)->a.counter++) -#define __local_add(i,l) ((l)->a.counter+=(i)) -#define __local_sub(i,l) ((l)->a.counter-=(i)) +#define __local_add(i, l) ((l)->a.counter+=(i)) +#define __local_sub(i, l) ((l)->a.counter-=(i)) /* Need to disable preemption for the cpu local counters otherwise we could still access a variable of a previous CPU in a non atomic way. */ diff --git a/include/asm-mips/mach-au1x00/au1xxx_dbdma.h b/include/asm-mips/mach-au1x00/au1xxx_dbdma.h index eeb0c3115b6a..93d507cea518 100644 --- a/include/asm-mips/mach-au1x00/au1xxx_dbdma.h +++ b/include/asm-mips/mach-au1x00/au1xxx_dbdma.h @@ -199,7 +199,7 @@ typedef volatile struct au1xxx_ddma_desc { #define DSCR_CMD0_ALWAYS 31 #define DSCR_NDEV_IDS 32 /* THis macro is used to find/create custom device types */ -#define DSCR_DEV2CUSTOM_ID(x,d) (((((x)&0xFFFF)<<8)|0x32000000)|((d)&0xFF)) +#define DSCR_DEV2CUSTOM_ID(x, d) (((((x)&0xFFFF)<<8)|0x32000000)|((d)&0xFF)) #define DSCR_CUSTOM2DEV_ID(x) ((x)&0xFF) @@ -373,14 +373,14 @@ void * au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp); Some compatibilty macros -- Needed to make changes to API without breaking existing drivers */ -#define au1xxx_dbdma_put_source(chanid,buf,nbytes)_au1xxx_dbdma_put_source(chanid, buf, nbytes, DDMA_FLAGS_IE) -#define au1xxx_dbdma_put_source_flags(chanid,buf,nbytes,flags) _au1xxx_dbdma_put_source(chanid, buf, nbytes, flags) -#define put_source_flags(chanid,buf,nbytes,flags) au1xxx_dbdma_put_source_flags(chanid,buf,nbytes,flags) +#define au1xxx_dbdma_put_source(chanid, buf, nbytes)_au1xxx_dbdma_put_source(chanid, buf, nbytes, DDMA_FLAGS_IE) +#define au1xxx_dbdma_put_source_flags(chanid, buf, nbytes, flags) _au1xxx_dbdma_put_source(chanid, buf, nbytes, flags) +#define put_source_flags(chanid, buf, nbytes, flags) au1xxx_dbdma_put_source_flags(chanid, buf, nbytes, flags) -#define au1xxx_dbdma_put_dest(chanid,buf,nbytes) _au1xxx_dbdma_put_dest(chanid, buf, nbytes, DDMA_FLAGS_IE) -#define au1xxx_dbdma_put_dest_flags(chanid,buf,nbytes,flags) _au1xxx_dbdma_put_dest(chanid, buf, nbytes, flags) -#define put_dest_flags(chanid,buf,nbytes,flags) au1xxx_dbdma_put_dest_flags(chanid,buf,nbytes,flags) +#define au1xxx_dbdma_put_dest(chanid, buf, nbytes) _au1xxx_dbdma_put_dest(chanid, buf, nbytes, DDMA_FLAGS_IE) +#define au1xxx_dbdma_put_dest_flags(chanid, buf, nbytes, flags) _au1xxx_dbdma_put_dest(chanid, buf, nbytes, flags) +#define put_dest_flags(chanid, buf, nbytes, flags) au1xxx_dbdma_put_dest_flags(chanid, buf, nbytes, flags) /* * Flags for the put_source/put_dest functions. diff --git a/include/asm-mips/mach-generic/mangle-port.h b/include/asm-mips/mach-generic/mangle-port.h index 6e1b0c075de7..f49dc990214b 100644 --- a/include/asm-mips/mach-generic/mangle-port.h +++ b/include/asm-mips/mach-generic/mangle-port.h @@ -27,25 +27,25 @@ */ #if defined(CONFIG_SWAP_IO_SPACE) -# define ioswabb(a,x) (x) -# define __mem_ioswabb(a,x) (x) -# define ioswabw(a,x) le16_to_cpu(x) -# define __mem_ioswabw(a,x) (x) -# define ioswabl(a,x) le32_to_cpu(x) -# define __mem_ioswabl(a,x) (x) -# define ioswabq(a,x) le64_to_cpu(x) -# define __mem_ioswabq(a,x) (x) +# define ioswabb(a, x) (x) +# define __mem_ioswabb(a, x) (x) +# define ioswabw(a, x) le16_to_cpu(x) +# define __mem_ioswabw(a, x) (x) +# define ioswabl(a, x) le32_to_cpu(x) +# define __mem_ioswabl(a, x) (x) +# define ioswabq(a, x) le64_to_cpu(x) +# define __mem_ioswabq(a, x) (x) #else -# define ioswabb(a,x) (x) -# define __mem_ioswabb(a,x) (x) -# define ioswabw(a,x) (x) -# define __mem_ioswabw(a,x) cpu_to_le16(x) -# define ioswabl(a,x) (x) -# define __mem_ioswabl(a,x) cpu_to_le32(x) -# define ioswabq(a,x) (x) -# define __mem_ioswabq(a,x) cpu_to_le32(x) +# define ioswabb(a, x) (x) +# define __mem_ioswabb(a, x) (x) +# define ioswabw(a, x) (x) +# define __mem_ioswabw(a, x) cpu_to_le16(x) +# define ioswabl(a, x) (x) +# define __mem_ioswabl(a, x) cpu_to_le32(x) +# define ioswabq(a, x) (x) +# define __mem_ioswabq(a, x) cpu_to_le32(x) #endif diff --git a/include/asm-mips/mach-ip27/mangle-port.h b/include/asm-mips/mach-ip27/mangle-port.h index d615312a451a..f6e4912ea062 100644 --- a/include/asm-mips/mach-ip27/mangle-port.h +++ b/include/asm-mips/mach-ip27/mangle-port.h @@ -13,13 +13,13 @@ #define __swizzle_addr_l(port) (port) #define __swizzle_addr_q(port) (port) -# define ioswabb(a,x) (x) -# define __mem_ioswabb(a,x) (x) -# define ioswabw(a,x) (x) -# define __mem_ioswabw(a,x) cpu_to_le16(x) -# define ioswabl(a,x) (x) -# define __mem_ioswabl(a,x) cpu_to_le32(x) -# define ioswabq(a,x) (x) -# define __mem_ioswabq(a,x) cpu_to_le32(x) +# define ioswabb(a, x) (x) +# define __mem_ioswabb(a, x) (x) +# define ioswabw(a, x) (x) +# define __mem_ioswabw(a, x) cpu_to_le16(x) +# define ioswabl(a, x) (x) +# define __mem_ioswabl(a, x) cpu_to_le32(x) +# define ioswabq(a, x) (x) +# define __mem_ioswabq(a, x) cpu_to_le32(x) #endif /* __ASM_MACH_IP27_MANGLE_PORT_H */ diff --git a/include/asm-mips/mach-ip32/mangle-port.h b/include/asm-mips/mach-ip32/mangle-port.h index 81320eb55324..f1d0f1756a9f 100644 --- a/include/asm-mips/mach-ip32/mangle-port.h +++ b/include/asm-mips/mach-ip32/mangle-port.h @@ -14,13 +14,13 @@ #define __swizzle_addr_l(port) (port) #define __swizzle_addr_q(port) (port) -# define ioswabb(a,x) (x) -# define __mem_ioswabb(a,x) (x) -# define ioswabw(a,x) (x) -# define __mem_ioswabw(a,x) cpu_to_le16(x) -# define ioswabl(a,x) (x) -# define __mem_ioswabl(a,x) cpu_to_le32(x) -# define ioswabq(a,x) (x) -# define __mem_ioswabq(a,x) cpu_to_le32(x) +# define ioswabb(a, x) (x) +# define __mem_ioswabb(a, x) (x) +# define ioswabw(a, x) (x) +# define __mem_ioswabw(a, x) cpu_to_le16(x) +# define ioswabl(a, x) (x) +# define __mem_ioswabl(a, x) cpu_to_le32(x) +# define ioswabq(a, x) (x) +# define __mem_ioswabq(a, x) cpu_to_le32(x) #endif /* __ASM_MACH_IP32_MANGLE_PORT_H */ diff --git a/include/asm-mips/mach-jmr3927/mangle-port.h b/include/asm-mips/mach-jmr3927/mangle-port.h index 501a202631b5..11bffcd1043b 100644 --- a/include/asm-mips/mach-jmr3927/mangle-port.h +++ b/include/asm-mips/mach-jmr3927/mangle-port.h @@ -6,13 +6,13 @@ extern unsigned long __swizzle_addr_b(unsigned long port); #define __swizzle_addr_l(port) (port) #define __swizzle_addr_q(port) (port) -#define ioswabb(a,x) (x) -#define __mem_ioswabb(a,x) (x) -#define ioswabw(a,x) le16_to_cpu(x) -#define __mem_ioswabw(a,x) (x) -#define ioswabl(a,x) le32_to_cpu(x) -#define __mem_ioswabl(a,x) (x) -#define ioswabq(a,x) le64_to_cpu(x) -#define __mem_ioswabq(a,x) (x) +#define ioswabb(a, x) (x) +#define __mem_ioswabb(a, x) (x) +#define ioswabw(a, x) le16_to_cpu(x) +#define __mem_ioswabw(a, x) (x) +#define ioswabl(a, x) le32_to_cpu(x) +#define __mem_ioswabl(a, x) (x) +#define ioswabq(a, x) le64_to_cpu(x) +#define __mem_ioswabq(a, x) (x) #endif /* __ASM_MACH_JMR3927_MANGLE_PORT_H */ diff --git a/include/asm-mips/mach-pnx8550/kernel-entry-init.h b/include/asm-mips/mach-pnx8550/kernel-entry-init.h index 982079f410b5..bdde00c9199b 100644 --- a/include/asm-mips/mach-pnx8550/kernel-entry-init.h +++ b/include/asm-mips/mach-pnx8550/kernel-entry-init.h @@ -44,7 +44,7 @@ cache_begin: li t0, (1<<28) mfc0 t0, CP0_CONFIG, 7 HAZARD_CP0 - and t0,~((1<<19) | (1<<20)) /* TLB/MAP cleared */ + and t0, ~((1<<19) | (1<<20)) /* TLB/MAP cleared */ mtc0 t0, CP0_CONFIG, 7 HAZARD_CP0 diff --git a/include/asm-mips/mach-pnx8550/uart.h b/include/asm-mips/mach-pnx8550/uart.h index 814a7a15ab49..ad7608d44874 100644 --- a/include/asm-mips/mach-pnx8550/uart.h +++ b/include/asm-mips/mach-pnx8550/uart.h @@ -15,7 +15,7 @@ /* early macros needed for prom/kgdb */ -#define ip3106_lcr(base,port) *(volatile u32 *)(base+(port*0x1000) + 0x000) +#define ip3106_lcr(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x000) #define ip3106_mcr(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x004) #define ip3106_baud(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x008) #define ip3106_cfg(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x00C) diff --git a/include/asm-mips/mc146818-time.h b/include/asm-mips/mc146818-time.h index 41ac8d363c67..cdc379a0a94e 100644 --- a/include/asm-mips/mc146818-time.h +++ b/include/asm-mips/mc146818-time.h @@ -63,8 +63,8 @@ static inline int mc146818_set_rtc_mmss(unsigned long nowtime) BIN_TO_BCD(real_seconds); BIN_TO_BCD(real_minutes); } - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); + CMOS_WRITE(real_seconds, RTC_SECONDS); + CMOS_WRITE(real_minutes, RTC_MINUTES); } else { printk(KERN_WARNING "set_rtc_mmss: can't update from %d to %d\n", diff --git a/include/asm-mips/mips-boards/bonito64.h b/include/asm-mips/mips-boards/bonito64.h index dc3fc32eedd8..a0f04bb99c99 100644 --- a/include/asm-mips/mips-boards/bonito64.h +++ b/include/asm-mips/mips-boards/bonito64.h @@ -387,7 +387,7 @@ extern unsigned long _pcictrl_bonito_pcicfg; #define BONITO_PCIMAP_PCIMAP_LO2 0x0003f000 #define BONITO_PCIMAP_PCIMAP_LO2_SHIFT 12 #define BONITO_PCIMAP_PCIMAP_2 0x00040000 -#define BONITO_PCIMAP_WIN(WIN,ADDR) ((((ADDR)>>26) & BONITO_PCIMAP_PCIMAP_LO0) << ((WIN)*6)) +#define BONITO_PCIMAP_WIN(WIN, ADDR) ((((ADDR)>>26) & BONITO_PCIMAP_PCIMAP_LO0) << ((WIN)*6)) #define BONITO_PCIMAP_WINSIZE (1<<26) #define BONITO_PCIMAP_WINOFFSET(ADDR) ((ADDR) & (BONITO_PCIMAP_WINSIZE - 1)) @@ -412,19 +412,19 @@ extern unsigned long _pcictrl_bonito_pcicfg; #define BONITO_PCIMEMBASECFG_ASHIFT 23 #define BONITO_PCIMEMBASECFG_AMASK 0x007fffff -#define BONITO_PCIMEMBASECFGSIZE(WIN,SIZE) (((~((SIZE)-1))>>(BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK_SHIFT)) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK) -#define BONITO_PCIMEMBASECFGBASE(WIN,BASE) (((BASE)>>(BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE##WIN##_TRANS_SHIFT)) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_TRANS) +#define BONITO_PCIMEMBASECFGSIZE(WIN, SIZE) (((~((SIZE)-1))>>(BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK_SHIFT)) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK) +#define BONITO_PCIMEMBASECFGBASE(WIN, BASE) (((BASE)>>(BONITO_PCIMEMBASECFG_ASHIFT-BONITO_PCIMEMBASECFG_MEMBASE##WIN##_TRANS_SHIFT)) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_TRANS) -#define BONITO_PCIMEMBASECFG_SIZE(WIN,CFG) (((((~(CFG)) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK)) << (BONITO_PCIMEMBASECFG_ASHIFT - BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK_SHIFT)) | BONITO_PCIMEMBASECFG_AMASK) +#define BONITO_PCIMEMBASECFG_SIZE(WIN, CFG) (((((~(CFG)) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK)) << (BONITO_PCIMEMBASECFG_ASHIFT - BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK_SHIFT)) | BONITO_PCIMEMBASECFG_AMASK) -#define BONITO_PCIMEMBASECFG_ADDRMASK(WIN,CFG) ((((CFG) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK) >> BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK_SHIFT) << BONITO_PCIMEMBASECFG_ASHIFT) -#define BONITO_PCIMEMBASECFG_ADDRMASK(WIN,CFG) ((((CFG) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK) >> BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK_SHIFT) << BONITO_PCIMEMBASECFG_ASHIFT) -#define BONITO_PCIMEMBASECFG_ADDRTRANS(WIN,CFG) ((((CFG) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_TRANS) >> BONITO_PCIMEMBASECFG_MEMBASE##WIN##_TRANS_SHIFT) << BONITO_PCIMEMBASECFG_ASHIFT) +#define BONITO_PCIMEMBASECFG_ADDRMASK(WIN, CFG) ((((CFG) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK) >> BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK_SHIFT) << BONITO_PCIMEMBASECFG_ASHIFT) +#define BONITO_PCIMEMBASECFG_ADDRMASK(WIN, CFG) ((((CFG) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK) >> BONITO_PCIMEMBASECFG_MEMBASE##WIN##_MASK_SHIFT) << BONITO_PCIMEMBASECFG_ASHIFT) +#define BONITO_PCIMEMBASECFG_ADDRTRANS(WIN, CFG) ((((CFG) & BONITO_PCIMEMBASECFG_MEMBASE##WIN##_TRANS) >> BONITO_PCIMEMBASECFG_MEMBASE##WIN##_TRANS_SHIFT) << BONITO_PCIMEMBASECFG_ASHIFT) -#define BONITO_PCITOPHYS(WIN,ADDR,CFG) ( \ - (((ADDR) & (~(BONITO_PCIMEMBASECFG_MASK))) & (~(BONITO_PCIMEMBASECFG_ADDRMASK(WIN,CFG)))) | \ - (BONITO_PCIMEMBASECFG_ADDRTRANS(WIN,CFG)) \ +#define BONITO_PCITOPHYS(WIN, ADDR, CFG) ( \ + (((ADDR) & (~(BONITO_PCIMEMBASECFG_MASK))) & (~(BONITO_PCIMEMBASECFG_ADDRMASK(WIN, CFG)))) | \ + (BONITO_PCIMEMBASECFG_ADDRTRANS(WIN, CFG)) \ ) /* PCICmd */ diff --git a/include/asm-mips/mips-boards/malta.h b/include/asm-mips/mips-boards/malta.h index eec91001bb65..93bf4e51b8a4 100644 --- a/include/asm-mips/mips-boards/malta.h +++ b/include/asm-mips/mips-boards/malta.h @@ -72,7 +72,7 @@ static inline unsigned long get_msc_port_base(unsigned long reg) #define SMSC_CONFIG_ACTIVATE_ENABLE 1 -#define SMSC_WRITE(x,a) outb(x,a) +#define SMSC_WRITE(x, a) outb(x, a) #define MALTA_JMPRS_REG 0x1f000210 diff --git a/include/asm-mips/mipsmtregs.h b/include/asm-mips/mipsmtregs.h index 294bca12cd3f..5a2f8a3a6a1f 100644 --- a/include/asm-mips/mipsmtregs.h +++ b/include/asm-mips/mipsmtregs.h @@ -41,27 +41,27 @@ * Macros for use in assembly language code */ -#define CP0_MVPCONTROL $0,1 -#define CP0_MVPCONF0 $0,2 -#define CP0_MVPCONF1 $0,3 -#define CP0_VPECONTROL $1,1 -#define CP0_VPECONF0 $1,2 -#define CP0_VPECONF1 $1,3 -#define CP0_YQMASK $1,4 -#define CP0_VPESCHEDULE $1,5 -#define CP0_VPESCHEFBK $1,6 -#define CP0_TCSTATUS $2,1 -#define CP0_TCBIND $2,2 -#define CP0_TCRESTART $2,3 -#define CP0_TCHALT $2,4 -#define CP0_TCCONTEXT $2,5 -#define CP0_TCSCHEDULE $2,6 -#define CP0_TCSCHEFBK $2,7 -#define CP0_SRSCONF0 $6,1 -#define CP0_SRSCONF1 $6,2 -#define CP0_SRSCONF2 $6,3 -#define CP0_SRSCONF3 $6,4 -#define CP0_SRSCONF4 $6,5 +#define CP0_MVPCONTROL $0, 1 +#define CP0_MVPCONF0 $0, 2 +#define CP0_MVPCONF1 $0, 3 +#define CP0_VPECONTROL $1, 1 +#define CP0_VPECONF0 $1, 2 +#define CP0_VPECONF1 $1, 3 +#define CP0_YQMASK $1, 4 +#define CP0_VPESCHEDULE $1, 5 +#define CP0_VPESCHEFBK $1, 6 +#define CP0_TCSTATUS $2, 1 +#define CP0_TCBIND $2, 2 +#define CP0_TCRESTART $2, 3 +#define CP0_TCHALT $2, 4 +#define CP0_TCCONTEXT $2, 5 +#define CP0_TCSCHEDULE $2, 6 +#define CP0_TCSCHEFBK $2, 7 +#define CP0_SRSCONF0 $6, 1 +#define CP0_SRSCONF1 $6, 2 +#define CP0_SRSCONF2 $6, 3 +#define CP0_SRSCONF3 $6, 4 +#define CP0_SRSCONF4 $6, 5 #endif @@ -291,7 +291,7 @@ static inline void ehb(void) __res; \ }) -#define mftr(rt,u,sel) \ +#define mftr(rt, u, sel) \ ({ \ unsigned long __res; \ \ @@ -315,7 +315,7 @@ do { \ : : "r" (v)); \ } while (0) -#define mttc0(rd,sel,v) \ +#define mttc0(rd, sel, v) \ ({ \ __asm__ __volatile__( \ " .set push \n" \ @@ -330,7 +330,7 @@ do { \ }) -#define mttr(rd,u,sel,v) \ +#define mttr(rd, u, sel, v) \ ({ \ __asm__ __volatile__( \ "mttr %0," #rd ", " #u ", " #sel \ @@ -362,7 +362,7 @@ do { \ #define write_vpe_c0_config1(val) mttc0(16, 1, val) #define read_vpe_c0_config7() mftc0(16, 7) #define write_vpe_c0_config7(val) mttc0(16, 7, val) -#define read_vpe_c0_ebase() mftc0(15,1) +#define read_vpe_c0_ebase() mftc0(15, 1) #define write_vpe_c0_ebase(val) mttc0(15, 1, val) #define write_vpe_c0_compare(val) mttc0(11, 0, val) #define read_vpe_c0_badvaddr() mftc0(8, 0) @@ -372,15 +372,15 @@ do { \ /* TC */ #define read_tc_c0_tcstatus() mftc0(2, 1) -#define write_tc_c0_tcstatus(val) mttc0(2,1,val) +#define write_tc_c0_tcstatus(val) mttc0(2, 1, val) #define read_tc_c0_tcbind() mftc0(2, 2) -#define write_tc_c0_tcbind(val) mttc0(2,2,val) +#define write_tc_c0_tcbind(val) mttc0(2, 2, val) #define read_tc_c0_tcrestart() mftc0(2, 3) -#define write_tc_c0_tcrestart(val) mttc0(2,3,val) +#define write_tc_c0_tcrestart(val) mttc0(2, 3, val) #define read_tc_c0_tchalt() mftc0(2, 4) -#define write_tc_c0_tchalt(val) mttc0(2,4,val) +#define write_tc_c0_tchalt(val) mttc0(2, 4, val) #define read_tc_c0_tccontext() mftc0(2, 5) -#define write_tc_c0_tccontext(val) mttc0(2,5,val) +#define write_tc_c0_tccontext(val) mttc0(2, 5, val) /* GPR */ #define read_tc_gpr_sp() mftgpr(29) diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h index 18f47f1e8cd5..aa17f658f73c 100644 --- a/include/asm-mips/mipsregs.h +++ b/include/asm-mips/mipsregs.h @@ -981,7 +981,7 @@ do { \ #define write_c0_errorepc(val) __write_ulong_c0_register($30, 0, val) /* MIPSR2 */ -#define read_c0_hwrena() __read_32bit_c0_register($7,0) +#define read_c0_hwrena() __read_32bit_c0_register($7, 0) #define write_c0_hwrena(val) __write_32bit_c0_register($7, 0, val) #define read_c0_intctl() __read_32bit_c0_register($12, 1) @@ -993,7 +993,7 @@ do { \ #define read_c0_srsmap() __read_32bit_c0_register($12, 3) #define write_c0_srsmap(val) __write_32bit_c0_register($12, 3, val) -#define read_c0_ebase() __read_32bit_c0_register($15,1) +#define read_c0_ebase() __read_32bit_c0_register($15, 1) #define write_c0_ebase(val) __write_32bit_c0_register($15, 1, val) /* diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h index 65024ffd7879..b3b7a689e7d3 100644 --- a/include/asm-mips/mmu_context.h +++ b/include/asm-mips/mmu_context.h @@ -107,7 +107,7 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) #else /* CONFIG_MIPS_MT_SMTC */ -#define get_new_mmu_context(mm,cpu) smtc_get_new_mmu_context((mm),(cpu)) +#define get_new_mmu_context(mm, cpu) smtc_get_new_mmu_context((mm), (cpu)) #endif /* CONFIG_MIPS_MT_SMTC */ @@ -191,7 +191,7 @@ static inline void destroy_context(struct mm_struct *mm) { } -#define deactivate_mm(tsk,mm) do { } while (0) +#define deactivate_mm(tsk, mm) do { } while (0) /* * After we have set current->mm to a new value, this activates diff --git a/include/asm-mips/paccess.h b/include/asm-mips/paccess.h index 8c08fa904b2c..c2394f8b0fe1 100644 --- a/include/asm-mips/paccess.h +++ b/include/asm-mips/paccess.h @@ -25,13 +25,13 @@ extern asmlinkage void handle_ibe(void); extern asmlinkage void handle_dbe(void); -#define put_dbe(x,ptr) __put_dbe((x),(ptr),sizeof(*(ptr))) -#define get_dbe(x,ptr) __get_dbe((x),(ptr),sizeof(*(ptr))) +#define put_dbe(x, ptr) __put_dbe((x), (ptr), sizeof(*(ptr))) +#define get_dbe(x, ptr) __get_dbe((x), (ptr), sizeof(*(ptr))) struct __large_pstruct { unsigned long buf[100]; }; #define __mp(x) (*(struct __large_pstruct *)(x)) -#define __get_dbe(x,ptr,size) \ +#define __get_dbe(x, ptr, size) \ ({ \ long __gu_err; \ __typeof__(*(ptr)) __gu_val; \ @@ -70,7 +70,7 @@ struct __large_pstruct { unsigned long buf[100]; }; extern void __get_dbe_unknown(void); -#define __put_dbe(x,ptr,size) \ +#define __put_dbe(x, ptr, size) \ ({ \ long __pu_err; \ __typeof__(*(ptr)) __pu_val; \ diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index e3301e54d559..d2ea983bec06 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -153,7 +153,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET) #endif #define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET)) -#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0)) +#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) diff --git a/include/asm-mips/pci/bridge.h b/include/asm-mips/pci/bridge.h index 0c45e7598f3f..b84feebf2cef 100644 --- a/include/asm-mips/pci/bridge.h +++ b/include/asm-mips/pci/bridge.h @@ -360,7 +360,7 @@ typedef struct bridge_err_cmdword_s { #define BRIDGE_TYPE0_CFG_FUNC_OFF 0x00000100 /* Type 0 Cfg Func Offset (1..7) */ #define BRIDGE_TYPE0_CFG_DEV(s) (BRIDGE_TYPE0_CFG_DEV0+\ (s)*BRIDGE_TYPE0_CFG_SLOT_OFF) -#define BRIDGE_TYPE0_CFG_DEVF(s,f) (BRIDGE_TYPE0_CFG_DEV0+\ +#define BRIDGE_TYPE0_CFG_DEVF(s, f) (BRIDGE_TYPE0_CFG_DEV0+\ (s)*BRIDGE_TYPE0_CFG_SLOT_OFF+\ (f)*BRIDGE_TYPE0_CFG_FUNC_OFF) diff --git a/include/asm-mips/pgalloc.h b/include/asm-mips/pgalloc.h index 9fb57c035213..81b72122207a 100644 --- a/include/asm-mips/pgalloc.h +++ b/include/asm-mips/pgalloc.h @@ -95,7 +95,7 @@ static inline void pte_free(struct page *pte) __free_pages(pte, PTE_ORDER); } -#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) +#define __pte_free_tlb(tlb, pte) tlb_remove_page((tlb), (pte)) #ifdef CONFIG_32BIT @@ -104,7 +104,7 @@ static inline void pte_free(struct page *pte) * inside the pgd, so has no extra memory associated with it. */ #define pmd_free(x) do { } while (0) -#define __pmd_free_tlb(tlb,x) do { } while (0) +#define __pmd_free_tlb(tlb, x) do { } while (0) #endif @@ -125,7 +125,7 @@ static inline void pmd_free(pmd_t *pmd) free_pages((unsigned long)pmd, PMD_ORDER); } -#define __pmd_free_tlb(tlb,x) pmd_free(x) +#define __pmd_free_tlb(tlb, x) pmd_free(x) #endif diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h index 59c865deb0c7..a0947092d0e0 100644 --- a/include/asm-mips/pgtable-32.h +++ b/include/asm-mips/pgtable-32.h @@ -140,7 +140,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) /* to find an entry in a page-table-directory */ -#define pgd_offset(mm,addr) ((mm)->pgd + pgd_index(addr)) +#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr)) /* Find an entry in the third-level page table.. */ #define __pte_offset(address) \ diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h index a8aed9c6a159..943515f0ef87 100644 --- a/include/asm-mips/pgtable-64.h +++ b/include/asm-mips/pgtable-64.h @@ -193,7 +193,7 @@ static inline void pud_clear(pud_t *pudp) #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) /* to find an entry in a page-table-directory */ -#define pgd_offset(mm,addr) ((mm)->pgd + pgd_index(addr)) +#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr)) static inline unsigned long pud_page_vaddr(pud_t pud) { @@ -237,7 +237,7 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __swp_type(x) (((x).val >> 32) & 0xff) #define __swp_offset(x) ((x).val >> 40) -#define __swp_entry(type,offset) ((swp_entry_t) { pte_val(mk_swap_pte((type),(offset))) }) +#define __swp_entry(type, offset) ((swp_entry_t) { pte_val(mk_swap_pte((type), (offset))) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h index d2ee28156743..17a7703a2969 100644 --- a/include/asm-mips/pgtable.h +++ b/include/asm-mips/pgtable.h @@ -103,7 +103,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte) } } } -#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) +#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { @@ -140,7 +140,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) } #endif } -#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) +#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { diff --git a/include/asm-mips/r4kcache.h b/include/asm-mips/r4kcache.h index 3c8e3c8d1a9a..2b8466ffd3ca 100644 --- a/include/asm-mips/r4kcache.h +++ b/include/asm-mips/r4kcache.h @@ -354,7 +354,7 @@ static inline void blast_##pfx##cache##lsize(void) \ \ for (ws = 0; ws < ws_end; ws += ws_inc) \ for (addr = start; addr < end; addr += lsize * 32) \ - cache##lsize##_unroll32(addr|ws,indexop); \ + cache##lsize##_unroll32(addr|ws, indexop); \ \ __##pfx##flush_epilogue \ } \ @@ -367,7 +367,7 @@ static inline void blast_##pfx##cache##lsize##_page(unsigned long page) \ __##pfx##flush_prologue \ \ do { \ - cache##lsize##_unroll32(start,hitop); \ + cache##lsize##_unroll32(start, hitop); \ start += lsize * 32; \ } while (start < end); \ \ @@ -388,7 +388,7 @@ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page) \ for (ws = 0; ws < ws_end; ws += ws_inc) \ for (addr = start; addr < end; addr += lsize * 32) \ - cache##lsize##_unroll32(addr|ws,indexop); \ + cache##lsize##_unroll32(addr|ws, indexop); \ \ __##pfx##flush_epilogue \ } diff --git a/include/asm-mips/semaphore.h b/include/asm-mips/semaphore.h index ea2413c58e78..080daa77f867 100644 --- a/include/asm-mips/semaphore.h +++ b/include/asm-mips/semaphore.h @@ -46,7 +46,7 @@ struct semaphore { } #define __DECLARE_SEMAPHORE_GENERIC(name, count) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) + struct semaphore name = __SEMAPHORE_INITIALIZER(name, count) #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1) #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name, 0) diff --git a/include/asm-mips/sgiarcs.h b/include/asm-mips/sgiarcs.h index 6d1eda60e01f..721327f88601 100644 --- a/include/asm-mips/sgiarcs.h +++ b/include/asm-mips/sgiarcs.h @@ -369,8 +369,8 @@ struct linux_smonblock { #if defined(CONFIG_64BIT) && defined(CONFIG_ARC32) #define __arc_clobbers \ - "$2","$3" /* ... */, "$8","$9","$10","$11", \ - "$12","$13","$14","$15","$16","$24","$25","$31" + "$2", "$3" /* ... */, "$8", "$9", "$10", "$11", \ + "$12", "$13", "$14", "$15", "$16", "$24", "$25", "$31" #define ARC_CALL0(dest) \ ({ long __res; \ @@ -382,11 +382,11 @@ struct linux_smonblock { "move\t%0, $2" \ : "=r" (__res), "=r" (__vec) \ : "1" (__vec) \ - : __arc_clobbers, "$4","$5","$6","$7"); \ + : __arc_clobbers, "$4", "$5", "$6", "$7"); \ (unsigned long) __res; \ }) -#define ARC_CALL1(dest,a1) \ +#define ARC_CALL1(dest, a1) \ ({ long __res; \ register signed int __a1 __asm__("$4") = (int) (long) (a1); \ long __vec = (long) romvec->dest; \ @@ -397,11 +397,11 @@ struct linux_smonblock { "move\t%0, $2" \ : "=r" (__res), "=r" (__vec) \ : "1" (__vec), "r" (__a1) \ - : __arc_clobbers, "$5","$6","$7"); \ + : __arc_clobbers, "$5", "$6", "$7"); \ (unsigned long) __res; \ }) -#define ARC_CALL2(dest,a1,a2) \ +#define ARC_CALL2(dest, a1, a2) \ ({ long __res; \ register signed int __a1 __asm__("$4") = (int) (long) (a1); \ register signed int __a2 __asm__("$5") = (int) (long) (a2); \ @@ -413,11 +413,11 @@ struct linux_smonblock { "move\t%0, $2" \ : "=r" (__res), "=r" (__vec) \ : "1" (__vec), "r" (__a1), "r" (__a2) \ - : __arc_clobbers, "$6","$7"); \ + : __arc_clobbers, "$6", "$7"); \ __res; \ }) -#define ARC_CALL3(dest,a1,a2,a3) \ +#define ARC_CALL3(dest, a1, a2, a3) \ ({ long __res; \ register signed int __a1 __asm__("$4") = (int) (long) (a1); \ register signed int __a2 __asm__("$5") = (int) (long) (a2); \ @@ -434,7 +434,7 @@ struct linux_smonblock { __res; \ }) -#define ARC_CALL4(dest,a1,a2,a3,a4) \ +#define ARC_CALL4(dest, a1, a2, a3, a4) \ ({ long __res; \ register signed int __a1 __asm__("$4") = (int) (long) (a1); \ register signed int __a2 __asm__("$5") = (int) (long) (a2); \ @@ -453,7 +453,7 @@ struct linux_smonblock { __res; \ }) -#define ARC_CALL5(dest,a1,a2,a3,a4,a5) \ +#define ARC_CALL5(dest, a1, a2, a3, a4, a5) \ ({ long __res; \ register signed int __a1 __asm__("$4") = (int) (long) (a1); \ register signed int __a2 __asm__("$5") = (int) (long) (a2); \ @@ -468,8 +468,8 @@ struct linux_smonblock { "daddu\t$29, 32\n\t" \ "move\t%0, $2" \ : "=r" (__res), "=r" (__vec) \ - : "1" (__vec), \ - "r" (__a1), "r" (__a2), "r" (__a3), "r" (__a4), \ + : "1" (__vec), \ + "r" (__a1), "r" (__a2), "r" (__a3), "r" (__a4), \ "r" (__a5) \ : __arc_clobbers); \ __res; \ @@ -488,7 +488,7 @@ struct linux_smonblock { __res; \ }) -#define ARC_CALL1(dest,a1) \ +#define ARC_CALL1(dest, a1) \ ({ long __res; \ long __a1 = (long) (a1); \ long (*__vec)(long) = (void *) romvec->dest; \ @@ -497,7 +497,7 @@ struct linux_smonblock { __res; \ }) -#define ARC_CALL2(dest,a1,a2) \ +#define ARC_CALL2(dest, a1, a2) \ ({ long __res; \ long __a1 = (long) (a1); \ long __a2 = (long) (a2); \ @@ -507,7 +507,7 @@ struct linux_smonblock { __res; \ }) -#define ARC_CALL3(dest,a1,a2,a3) \ +#define ARC_CALL3(dest, a1, a2, a3) \ ({ long __res; \ long __a1 = (long) (a1); \ long __a2 = (long) (a2); \ @@ -518,7 +518,7 @@ struct linux_smonblock { __res; \ }) -#define ARC_CALL4(dest,a1,a2,a3,a4) \ +#define ARC_CALL4(dest, a1, a2, a3, a4) \ ({ long __res; \ long __a1 = (long) (a1); \ long __a2 = (long) (a2); \ @@ -530,7 +530,7 @@ struct linux_smonblock { __res; \ }) -#define ARC_CALL5(dest,a1,a2,a3,a4,a5) \ +#define ARC_CALL5(dest, a1, a2, a3, a4, a5) \ ({ long __res; \ long __a1 = (long) (a1); \ long __a2 = (long) (a2); \ diff --git a/include/asm-mips/sibyte/bcm1480_int.h b/include/asm-mips/sibyte/bcm1480_int.h index c0d5206020fd..6109557c14e9 100644 --- a/include/asm-mips/sibyte/bcm1480_int.h +++ b/include/asm-mips/sibyte/bcm1480_int.h @@ -157,7 +157,7 @@ * Mask values for each interrupt */ -#define _BCM1480_INT_MASK(w,n) _SB_MAKEMASK(w,((n) & 0x3F)) +#define _BCM1480_INT_MASK(w, n) _SB_MAKEMASK(w, ((n) & 0x3F)) #define _BCM1480_INT_MASK1(n) _SB_MAKEMASK1(((n) & 0x3F)) #define _BCM1480_INT_OFFSET(n) (((n) & 0x40) << 6) @@ -196,7 +196,7 @@ #define M_BCM1480_INT_PMI_HIGH _BCM1480_INT_MASK1(K_BCM1480_INT_PMI_HIGH) #define M_BCM1480_INT_PMO_LOW _BCM1480_INT_MASK1(K_BCM1480_INT_PMO_LOW) #define M_BCM1480_INT_PMO_HIGH _BCM1480_INT_MASK1(K_BCM1480_INT_PMO_HIGH) -#define M_BCM1480_INT_MBOX_ALL _BCM1480_INT_MASK(8,K_BCM1480_INT_MBOX_0_0) +#define M_BCM1480_INT_MBOX_ALL _BCM1480_INT_MASK(8, K_BCM1480_INT_MBOX_0_0) #define M_BCM1480_INT_MBOX_0_0 _BCM1480_INT_MASK1(K_BCM1480_INT_MBOX_0_0) #define M_BCM1480_INT_MBOX_0_1 _BCM1480_INT_MASK1(K_BCM1480_INT_MBOX_0_1) #define M_BCM1480_INT_MBOX_0_2 _BCM1480_INT_MASK1(K_BCM1480_INT_MBOX_0_2) @@ -269,9 +269,9 @@ */ #define S_BCM1480_INT_HT_INTMSG 0 -#define M_BCM1480_INT_HT_INTMSG _SB_MAKEMASK(3,S_BCM1480_INT_HT_INTMSG) -#define V_BCM1480_INT_HT_INTMSG(x) _SB_MAKEVALUE(x,S_BCM1480_INT_HT_INTMSG) -#define G_BCM1480_INT_HT_INTMSG(x) _SB_GETVALUE(x,S_BCM1480_INT_HT_INTMSG,M_BCM1480_INT_HT_INTMSG) +#define M_BCM1480_INT_HT_INTMSG _SB_MAKEMASK(3, S_BCM1480_INT_HT_INTMSG) +#define V_BCM1480_INT_HT_INTMSG(x) _SB_MAKEVALUE(x, S_BCM1480_INT_HT_INTMSG) +#define G_BCM1480_INT_HT_INTMSG(x) _SB_GETVALUE(x, S_BCM1480_INT_HT_INTMSG, M_BCM1480_INT_HT_INTMSG) #define K_BCM1480_INT_HT_INTMSG_FIXED 0 #define K_BCM1480_INT_HT_INTMSG_ARBITRATED 1 @@ -291,14 +291,14 @@ #define V_BCM1480_INT_HT_LOGICALDEST M_BCM1480_INT_HT_DESTMODE #define S_BCM1480_INT_HT_INTDEST 5 -#define M_BCM1480_INT_HT_INTDEST _SB_MAKEMASK(8,S_BCM1480_INT_HT_INTDEST) -#define V_BCM1480_INT_HT_INTDEST(x) _SB_MAKEVALUE(x,S_BCM1480_INT_HT_INTDEST) -#define G_BCM1480_INT_HT_INTDEST(x) _SB_GETVALUE(x,S_BCM1480_INT_HT_INTDEST,M_BCM1480_INT_HT_INTDEST) +#define M_BCM1480_INT_HT_INTDEST _SB_MAKEMASK(8, S_BCM1480_INT_HT_INTDEST) +#define V_BCM1480_INT_HT_INTDEST(x) _SB_MAKEVALUE(x, S_BCM1480_INT_HT_INTDEST) +#define G_BCM1480_INT_HT_INTDEST(x) _SB_GETVALUE(x, S_BCM1480_INT_HT_INTDEST, M_BCM1480_INT_HT_INTDEST) #define S_BCM1480_INT_HT_VECTOR 13 -#define M_BCM1480_INT_HT_VECTOR _SB_MAKEMASK(8,S_BCM1480_INT_HT_VECTOR) -#define V_BCM1480_INT_HT_VECTOR(x) _SB_MAKEVALUE(x,S_BCM1480_INT_HT_VECTOR) -#define G_BCM1480_INT_HT_VECTOR(x) _SB_GETVALUE(x,S_BCM1480_INT_HT_VECTOR,M_BCM1480_INT_HT_VECTOR) +#define M_BCM1480_INT_HT_VECTOR _SB_MAKEMASK(8, S_BCM1480_INT_HT_VECTOR) +#define V_BCM1480_INT_HT_VECTOR(x) _SB_MAKEVALUE(x, S_BCM1480_INT_HT_VECTOR) +#define G_BCM1480_INT_HT_VECTOR(x) _SB_GETVALUE(x, S_BCM1480_INT_HT_VECTOR, M_BCM1480_INT_HT_VECTOR) /* * Vector prefix (Table 4-7) diff --git a/include/asm-mips/sibyte/bcm1480_l2c.h b/include/asm-mips/sibyte/bcm1480_l2c.h index 886b099565e6..fd75817f7ac4 100644 --- a/include/asm-mips/sibyte/bcm1480_l2c.h +++ b/include/asm-mips/sibyte/bcm1480_l2c.h @@ -40,22 +40,22 @@ */ #define S_BCM1480_L2C_MGMT_INDEX 5 -#define M_BCM1480_L2C_MGMT_INDEX _SB_MAKEMASK(12,S_BCM1480_L2C_MGMT_INDEX) -#define V_BCM1480_L2C_MGMT_INDEX(x) _SB_MAKEVALUE(x,S_BCM1480_L2C_MGMT_INDEX) -#define G_BCM1480_L2C_MGMT_INDEX(x) _SB_GETVALUE(x,S_BCM1480_L2C_MGMT_INDEX,M_BCM1480_L2C_MGMT_INDEX) +#define M_BCM1480_L2C_MGMT_INDEX _SB_MAKEMASK(12, S_BCM1480_L2C_MGMT_INDEX) +#define V_BCM1480_L2C_MGMT_INDEX(x) _SB_MAKEVALUE(x, S_BCM1480_L2C_MGMT_INDEX) +#define G_BCM1480_L2C_MGMT_INDEX(x) _SB_GETVALUE(x, S_BCM1480_L2C_MGMT_INDEX, M_BCM1480_L2C_MGMT_INDEX) #define S_BCM1480_L2C_MGMT_WAY 17 -#define M_BCM1480_L2C_MGMT_WAY _SB_MAKEMASK(3,S_BCM1480_L2C_MGMT_WAY) -#define V_BCM1480_L2C_MGMT_WAY(x) _SB_MAKEVALUE(x,S_BCM1480_L2C_MGMT_WAY) -#define G_BCM1480_L2C_MGMT_WAY(x) _SB_GETVALUE(x,S_BCM1480_L2C_MGMT_WAY,M_BCM1480_L2C_MGMT_WAY) +#define M_BCM1480_L2C_MGMT_WAY _SB_MAKEMASK(3, S_BCM1480_L2C_MGMT_WAY) +#define V_BCM1480_L2C_MGMT_WAY(x) _SB_MAKEVALUE(x, S_BCM1480_L2C_MGMT_WAY) +#define G_BCM1480_L2C_MGMT_WAY(x) _SB_GETVALUE(x, S_BCM1480_L2C_MGMT_WAY, M_BCM1480_L2C_MGMT_WAY) #define M_BCM1480_L2C_MGMT_DIRTY _SB_MAKEMASK1(20) #define M_BCM1480_L2C_MGMT_VALID _SB_MAKEMASK1(21) #define S_BCM1480_L2C_MGMT_ECC_DIAG 22 -#define M_BCM1480_L2C_MGMT_ECC_DIAG _SB_MAKEMASK(2,S_BCM1480_L2C_MGMT_ECC_DIAG) -#define V_BCM1480_L2C_MGMT_ECC_DIAG(x) _SB_MAKEVALUE(x,S_BCM1480_L2C_MGMT_ECC_DIAG) -#define G_BCM1480_L2C_MGMT_ECC_DIAG(x) _SB_GETVALUE(x,S_BCM1480_L2C_MGMT_ECC_DIAG,M_BCM1480_L2C_MGMT_ECC_DIAG) +#define M_BCM1480_L2C_MGMT_ECC_DIAG _SB_MAKEMASK(2, S_BCM1480_L2C_MGMT_ECC_DIAG) +#define V_BCM1480_L2C_MGMT_ECC_DIAG(x) _SB_MAKEVALUE(x, S_BCM1480_L2C_MGMT_ECC_DIAG) +#define G_BCM1480_L2C_MGMT_ECC_DIAG(x) _SB_GETVALUE(x, S_BCM1480_L2C_MGMT_ECC_DIAG, M_BCM1480_L2C_MGMT_ECC_DIAG) #define A_BCM1480_L2C_MGMT_TAG_BASE 0x00D0000000 @@ -68,36 +68,36 @@ */ #define S_BCM1480_L2C_TAG_MBZ 0 -#define M_BCM1480_L2C_TAG_MBZ _SB_MAKEMASK(5,S_BCM1480_L2C_TAG_MBZ) +#define M_BCM1480_L2C_TAG_MBZ _SB_MAKEMASK(5, S_BCM1480_L2C_TAG_MBZ) #define S_BCM1480_L2C_TAG_INDEX 5 -#define M_BCM1480_L2C_TAG_INDEX _SB_MAKEMASK(12,S_BCM1480_L2C_TAG_INDEX) -#define V_BCM1480_L2C_TAG_INDEX(x) _SB_MAKEVALUE(x,S_BCM1480_L2C_TAG_INDEX) -#define G_BCM1480_L2C_TAG_INDEX(x) _SB_GETVALUE(x,S_BCM1480_L2C_TAG_INDEX,M_BCM1480_L2C_TAG_INDEX) +#define M_BCM1480_L2C_TAG_INDEX _SB_MAKEMASK(12, S_BCM1480_L2C_TAG_INDEX) +#define V_BCM1480_L2C_TAG_INDEX(x) _SB_MAKEVALUE(x, S_BCM1480_L2C_TAG_INDEX) +#define G_BCM1480_L2C_TAG_INDEX(x) _SB_GETVALUE(x, S_BCM1480_L2C_TAG_INDEX, M_BCM1480_L2C_TAG_INDEX) /* Note that index bit 16 is also tag bit 40 */ #define S_BCM1480_L2C_TAG_TAG 17 -#define M_BCM1480_L2C_TAG_TAG _SB_MAKEMASK(23,S_BCM1480_L2C_TAG_TAG) -#define V_BCM1480_L2C_TAG_TAG(x) _SB_MAKEVALUE(x,S_BCM1480_L2C_TAG_TAG) -#define G_BCM1480_L2C_TAG_TAG(x) _SB_GETVALUE(x,S_BCM1480_L2C_TAG_TAG,M_BCM1480_L2C_TAG_TAG) +#define M_BCM1480_L2C_TAG_TAG _SB_MAKEMASK(23, S_BCM1480_L2C_TAG_TAG) +#define V_BCM1480_L2C_TAG_TAG(x) _SB_MAKEVALUE(x, S_BCM1480_L2C_TAG_TAG) +#define G_BCM1480_L2C_TAG_TAG(x) _SB_GETVALUE(x, S_BCM1480_L2C_TAG_TAG, M_BCM1480_L2C_TAG_TAG) #define S_BCM1480_L2C_TAG_ECC 40 -#define M_BCM1480_L2C_TAG_ECC _SB_MAKEMASK(6,S_BCM1480_L2C_TAG_ECC) -#define V_BCM1480_L2C_TAG_ECC(x) _SB_MAKEVALUE(x,S_BCM1480_L2C_TAG_ECC) -#define G_BCM1480_L2C_TAG_ECC(x) _SB_GETVALUE(x,S_BCM1480_L2C_TAG_ECC,M_BCM1480_L2C_TAG_ECC) +#define M_BCM1480_L2C_TAG_ECC _SB_MAKEMASK(6, S_BCM1480_L2C_TAG_ECC) +#define V_BCM1480_L2C_TAG_ECC(x) _SB_MAKEVALUE(x, S_BCM1480_L2C_TAG_ECC) +#define G_BCM1480_L2C_TAG_ECC(x) _SB_GETVALUE(x, S_BCM1480_L2C_TAG_ECC, M_BCM1480_L2C_TAG_ECC) #define S_BCM1480_L2C_TAG_WAY 46 -#define M_BCM1480_L2C_TAG_WAY _SB_MAKEMASK(3,S_BCM1480_L2C_TAG_WAY) -#define V_BCM1480_L2C_TAG_WAY(x) _SB_MAKEVALUE(x,S_BCM1480_L2C_TAG_WAY) -#define G_BCM1480_L2C_TAG_WAY(x) _SB_GETVALUE(x,S_BCM1480_L2C_TAG_WAY,M_BCM1480_L2C_TAG_WAY) +#define M_BCM1480_L2C_TAG_WAY _SB_MAKEMASK(3, S_BCM1480_L2C_TAG_WAY) +#define V_BCM1480_L2C_TAG_WAY(x) _SB_MAKEVALUE(x, S_BCM1480_L2C_TAG_WAY) +#define G_BCM1480_L2C_TAG_WAY(x) _SB_GETVALUE(x, S_BCM1480_L2C_TAG_WAY, M_BCM1480_L2C_TAG_WAY) #define M_BCM1480_L2C_TAG_DIRTY _SB_MAKEMASK1(49) #define M_BCM1480_L2C_TAG_VALID _SB_MAKEMASK1(50) #define S_BCM1480_L2C_DATA_ECC 51 -#define M_BCM1480_L2C_DATA_ECC _SB_MAKEMASK(10,S_BCM1480_L2C_DATA_ECC) -#define V_BCM1480_L2C_DATA_ECC(x) _SB_MAKEVALUE(x,S_BCM1480_L2C_DATA_ECC) -#define G_BCM1480_L2C_DATA_ECC(x) _SB_GETVALUE(x,S_BCM1480_L2C_DATA_ECC,M_BCM1480_L2C_DATA_ECC) +#define M_BCM1480_L2C_DATA_ECC _SB_MAKEMASK(10, S_BCM1480_L2C_DATA_ECC) +#define V_BCM1480_L2C_DATA_ECC(x) _SB_MAKEVALUE(x, S_BCM1480_L2C_DATA_ECC) +#define G_BCM1480_L2C_DATA_ECC(x) _SB_GETVALUE(x, S_BCM1480_L2C_DATA_ECC, M_BCM1480_L2C_DATA_ECC) /* @@ -105,24 +105,24 @@ */ #define S_BCM1480_L2C_MISC0_WAY_REMOTE 0 -#define M_BCM1480_L2C_MISC0_WAY_REMOTE _SB_MAKEMASK(8,S_BCM1480_L2C_MISC0_WAY_REMOTE) -#define G_BCM1480_L2C_MISC0_WAY_REMOTE(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC0_WAY_REMOTE,M_BCM1480_L2C_MISC0_WAY_REMOTE) +#define M_BCM1480_L2C_MISC0_WAY_REMOTE _SB_MAKEMASK(8, S_BCM1480_L2C_MISC0_WAY_REMOTE) +#define G_BCM1480_L2C_MISC0_WAY_REMOTE(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC0_WAY_REMOTE, M_BCM1480_L2C_MISC0_WAY_REMOTE) #define S_BCM1480_L2C_MISC0_WAY_LOCAL 8 -#define M_BCM1480_L2C_MISC0_WAY_LOCAL _SB_MAKEMASK(8,S_BCM1480_L2C_MISC0_WAY_LOCAL) -#define G_BCM1480_L2C_MISC0_WAY_LOCAL(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC0_WAY_LOCAL,M_BCM1480_L2C_MISC0_WAY_LOCAL) +#define M_BCM1480_L2C_MISC0_WAY_LOCAL _SB_MAKEMASK(8, S_BCM1480_L2C_MISC0_WAY_LOCAL) +#define G_BCM1480_L2C_MISC0_WAY_LOCAL(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC0_WAY_LOCAL, M_BCM1480_L2C_MISC0_WAY_LOCAL) #define S_BCM1480_L2C_MISC0_WAY_ENABLE 16 -#define M_BCM1480_L2C_MISC0_WAY_ENABLE _SB_MAKEMASK(8,S_BCM1480_L2C_MISC0_WAY_ENABLE) -#define G_BCM1480_L2C_MISC0_WAY_ENABLE(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC0_WAY_ENABLE,M_BCM1480_L2C_MISC0_WAY_ENABLE) +#define M_BCM1480_L2C_MISC0_WAY_ENABLE _SB_MAKEMASK(8, S_BCM1480_L2C_MISC0_WAY_ENABLE) +#define G_BCM1480_L2C_MISC0_WAY_ENABLE(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC0_WAY_ENABLE, M_BCM1480_L2C_MISC0_WAY_ENABLE) #define S_BCM1480_L2C_MISC0_CACHE_DISABLE 24 -#define M_BCM1480_L2C_MISC0_CACHE_DISABLE _SB_MAKEMASK(2,S_BCM1480_L2C_MISC0_CACHE_DISABLE) -#define G_BCM1480_L2C_MISC0_CACHE_DISABLE(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC0_CACHE_DISABLE,M_BCM1480_L2C_MISC0_CACHE_DISABLE) +#define M_BCM1480_L2C_MISC0_CACHE_DISABLE _SB_MAKEMASK(2, S_BCM1480_L2C_MISC0_CACHE_DISABLE) +#define G_BCM1480_L2C_MISC0_CACHE_DISABLE(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC0_CACHE_DISABLE, M_BCM1480_L2C_MISC0_CACHE_DISABLE) #define S_BCM1480_L2C_MISC0_CACHE_QUAD 26 -#define M_BCM1480_L2C_MISC0_CACHE_QUAD _SB_MAKEMASK(2,S_BCM1480_L2C_MISC0_CACHE_QUAD) -#define G_BCM1480_L2C_MISC0_CACHE_QUAD(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC0_CACHE_QUAD,M_BCM1480_L2C_MISC0_CACHE_QUAD) +#define M_BCM1480_L2C_MISC0_CACHE_QUAD _SB_MAKEMASK(2, S_BCM1480_L2C_MISC0_CACHE_QUAD) +#define G_BCM1480_L2C_MISC0_CACHE_QUAD(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC0_CACHE_QUAD, M_BCM1480_L2C_MISC0_CACHE_QUAD) #define S_BCM1480_L2C_MISC0_MC_PRIORITY 30 #define M_BCM1480_L2C_MISC0_MC_PRIORITY _SB_MAKEMASK1(S_BCM1480_L2C_MISC0_MC_PRIORITY) @@ -136,24 +136,24 @@ */ #define S_BCM1480_L2C_MISC1_WAY_AGENT_0 0 -#define M_BCM1480_L2C_MISC1_WAY_AGENT_0 _SB_MAKEMASK(8,S_BCM1480_L2C_MISC1_WAY_AGENT_0) -#define G_BCM1480_L2C_MISC1_WAY_AGENT_0(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC1_WAY_AGENT_0,M_BCM1480_L2C_MISC1_WAY_AGENT_0) +#define M_BCM1480_L2C_MISC1_WAY_AGENT_0 _SB_MAKEMASK(8, S_BCM1480_L2C_MISC1_WAY_AGENT_0) +#define G_BCM1480_L2C_MISC1_WAY_AGENT_0(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC1_WAY_AGENT_0, M_BCM1480_L2C_MISC1_WAY_AGENT_0) #define S_BCM1480_L2C_MISC1_WAY_AGENT_1 8 -#define M_BCM1480_L2C_MISC1_WAY_AGENT_1 _SB_MAKEMASK(8,S_BCM1480_L2C_MISC1_WAY_AGENT_1) -#define G_BCM1480_L2C_MISC1_WAY_AGENT_1(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC1_WAY_AGENT_1,M_BCM1480_L2C_MISC1_WAY_AGENT_1) +#define M_BCM1480_L2C_MISC1_WAY_AGENT_1 _SB_MAKEMASK(8, S_BCM1480_L2C_MISC1_WAY_AGENT_1) +#define G_BCM1480_L2C_MISC1_WAY_AGENT_1(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC1_WAY_AGENT_1, M_BCM1480_L2C_MISC1_WAY_AGENT_1) #define S_BCM1480_L2C_MISC1_WAY_AGENT_2 16 -#define M_BCM1480_L2C_MISC1_WAY_AGENT_2 _SB_MAKEMASK(8,S_BCM1480_L2C_MISC1_WAY_AGENT_2) -#define G_BCM1480_L2C_MISC1_WAY_AGENT_2(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC1_WAY_AGENT_2,M_BCM1480_L2C_MISC1_WAY_AGENT_2) +#define M_BCM1480_L2C_MISC1_WAY_AGENT_2 _SB_MAKEMASK(8, S_BCM1480_L2C_MISC1_WAY_AGENT_2) +#define G_BCM1480_L2C_MISC1_WAY_AGENT_2(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC1_WAY_AGENT_2, M_BCM1480_L2C_MISC1_WAY_AGENT_2) #define S_BCM1480_L2C_MISC1_WAY_AGENT_3 24 -#define M_BCM1480_L2C_MISC1_WAY_AGENT_3 _SB_MAKEMASK(8,S_BCM1480_L2C_MISC1_WAY_AGENT_3) -#define G_BCM1480_L2C_MISC1_WAY_AGENT_3(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC1_WAY_AGENT_3,M_BCM1480_L2C_MISC1_WAY_AGENT_3) +#define M_BCM1480_L2C_MISC1_WAY_AGENT_3 _SB_MAKEMASK(8, S_BCM1480_L2C_MISC1_WAY_AGENT_3) +#define G_BCM1480_L2C_MISC1_WAY_AGENT_3(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC1_WAY_AGENT_3, M_BCM1480_L2C_MISC1_WAY_AGENT_3) #define S_BCM1480_L2C_MISC1_WAY_AGENT_4 32 -#define M_BCM1480_L2C_MISC1_WAY_AGENT_4 _SB_MAKEMASK(8,S_BCM1480_L2C_MISC1_WAY_AGENT_4) -#define G_BCM1480_L2C_MISC1_WAY_AGENT_4(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC1_WAY_AGENT_4,M_BCM1480_L2C_MISC1_WAY_AGENT_4) +#define M_BCM1480_L2C_MISC1_WAY_AGENT_4 _SB_MAKEMASK(8, S_BCM1480_L2C_MISC1_WAY_AGENT_4) +#define G_BCM1480_L2C_MISC1_WAY_AGENT_4(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC1_WAY_AGENT_4, M_BCM1480_L2C_MISC1_WAY_AGENT_4) /* @@ -161,16 +161,16 @@ */ #define S_BCM1480_L2C_MISC2_WAY_AGENT_8 0 -#define M_BCM1480_L2C_MISC2_WAY_AGENT_8 _SB_MAKEMASK(8,S_BCM1480_L2C_MISC2_WAY_AGENT_8) -#define G_BCM1480_L2C_MISC2_WAY_AGENT_8(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC2_WAY_AGENT_8,M_BCM1480_L2C_MISC2_WAY_AGENT_8) +#define M_BCM1480_L2C_MISC2_WAY_AGENT_8 _SB_MAKEMASK(8, S_BCM1480_L2C_MISC2_WAY_AGENT_8) +#define G_BCM1480_L2C_MISC2_WAY_AGENT_8(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC2_WAY_AGENT_8, M_BCM1480_L2C_MISC2_WAY_AGENT_8) #define S_BCM1480_L2C_MISC2_WAY_AGENT_9 8 -#define M_BCM1480_L2C_MISC2_WAY_AGENT_9 _SB_MAKEMASK(8,S_BCM1480_L2C_MISC2_WAY_AGENT_9) -#define G_BCM1480_L2C_MISC2_WAY_AGENT_9(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC2_WAY_AGENT_9,M_BCM1480_L2C_MISC2_WAY_AGENT_9) +#define M_BCM1480_L2C_MISC2_WAY_AGENT_9 _SB_MAKEMASK(8, S_BCM1480_L2C_MISC2_WAY_AGENT_9) +#define G_BCM1480_L2C_MISC2_WAY_AGENT_9(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC2_WAY_AGENT_9, M_BCM1480_L2C_MISC2_WAY_AGENT_9) #define S_BCM1480_L2C_MISC2_WAY_AGENT_A 16 -#define M_BCM1480_L2C_MISC2_WAY_AGENT_A _SB_MAKEMASK(8,S_BCM1480_L2C_MISC2_WAY_AGENT_A) -#define G_BCM1480_L2C_MISC2_WAY_AGENT_A(x) _SB_GETVALUE(x,S_BCM1480_L2C_MISC2_WAY_AGENT_A,M_BCM1480_L2C_MISC2_WAY_AGENT_A) +#define M_BCM1480_L2C_MISC2_WAY_AGENT_A _SB_MAKEMASK(8, S_BCM1480_L2C_MISC2_WAY_AGENT_A) +#define G_BCM1480_L2C_MISC2_WAY_AGENT_A(x) _SB_GETVALUE(x, S_BCM1480_L2C_MISC2_WAY_AGENT_A, M_BCM1480_L2C_MISC2_WAY_AGENT_A) #endif /* _BCM1480_L2C_H */ diff --git a/include/asm-mips/sibyte/bcm1480_mc.h b/include/asm-mips/sibyte/bcm1480_mc.h index a6a437451da4..f26a41a82b59 100644 --- a/include/asm-mips/sibyte/bcm1480_mc.h +++ b/include/asm-mips/sibyte/bcm1480_mc.h @@ -40,27 +40,27 @@ */ #define S_BCM1480_MC_INTLV0 0 -#define M_BCM1480_MC_INTLV0 _SB_MAKEMASK(6,S_BCM1480_MC_INTLV0) -#define V_BCM1480_MC_INTLV0(x) _SB_MAKEVALUE(x,S_BCM1480_MC_INTLV0) -#define G_BCM1480_MC_INTLV0(x) _SB_GETVALUE(x,S_BCM1480_MC_INTLV0,M_BCM1480_MC_INTLV0) +#define M_BCM1480_MC_INTLV0 _SB_MAKEMASK(6, S_BCM1480_MC_INTLV0) +#define V_BCM1480_MC_INTLV0(x) _SB_MAKEVALUE(x, S_BCM1480_MC_INTLV0) +#define G_BCM1480_MC_INTLV0(x) _SB_GETVALUE(x, S_BCM1480_MC_INTLV0, M_BCM1480_MC_INTLV0) #define V_BCM1480_MC_INTLV0_DEFAULT V_BCM1480_MC_INTLV0(0) #define S_BCM1480_MC_INTLV1 8 -#define M_BCM1480_MC_INTLV1 _SB_MAKEMASK(6,S_BCM1480_MC_INTLV1) -#define V_BCM1480_MC_INTLV1(x) _SB_MAKEVALUE(x,S_BCM1480_MC_INTLV1) -#define G_BCM1480_MC_INTLV1(x) _SB_GETVALUE(x,S_BCM1480_MC_INTLV1,M_BCM1480_MC_INTLV1) +#define M_BCM1480_MC_INTLV1 _SB_MAKEMASK(6, S_BCM1480_MC_INTLV1) +#define V_BCM1480_MC_INTLV1(x) _SB_MAKEVALUE(x, S_BCM1480_MC_INTLV1) +#define G_BCM1480_MC_INTLV1(x) _SB_GETVALUE(x, S_BCM1480_MC_INTLV1, M_BCM1480_MC_INTLV1) #define V_BCM1480_MC_INTLV1_DEFAULT V_BCM1480_MC_INTLV1(0) #define S_BCM1480_MC_INTLV2 16 -#define M_BCM1480_MC_INTLV2 _SB_MAKEMASK(6,S_BCM1480_MC_INTLV2) -#define V_BCM1480_MC_INTLV2(x) _SB_MAKEVALUE(x,S_BCM1480_MC_INTLV2) -#define G_BCM1480_MC_INTLV2(x) _SB_GETVALUE(x,S_BCM1480_MC_INTLV2,M_BCM1480_MC_INTLV2) +#define M_BCM1480_MC_INTLV2 _SB_MAKEMASK(6, S_BCM1480_MC_INTLV2) +#define V_BCM1480_MC_INTLV2(x) _SB_MAKEVALUE(x, S_BCM1480_MC_INTLV2) +#define G_BCM1480_MC_INTLV2(x) _SB_GETVALUE(x, S_BCM1480_MC_INTLV2, M_BCM1480_MC_INTLV2) #define V_BCM1480_MC_INTLV2_DEFAULT V_BCM1480_MC_INTLV2(0) #define S_BCM1480_MC_CS_MODE 32 -#define M_BCM1480_MC_CS_MODE _SB_MAKEMASK(8,S_BCM1480_MC_CS_MODE) -#define V_BCM1480_MC_CS_MODE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS_MODE) -#define G_BCM1480_MC_CS_MODE(x) _SB_GETVALUE(x,S_BCM1480_MC_CS_MODE,M_BCM1480_MC_CS_MODE) +#define M_BCM1480_MC_CS_MODE _SB_MAKEMASK(8, S_BCM1480_MC_CS_MODE) +#define V_BCM1480_MC_CS_MODE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS_MODE) +#define G_BCM1480_MC_CS_MODE(x) _SB_GETVALUE(x, S_BCM1480_MC_CS_MODE, M_BCM1480_MC_CS_MODE) #define V_BCM1480_MC_CS_MODE_DEFAULT V_BCM1480_MC_CS_MODE(0) #define V_BCM1480_MC_CONFIG_DEFAULT (V_BCM1480_MC_INTLV0_DEFAULT | \ @@ -81,131 +81,131 @@ */ #define S_BCM1480_MC_CS0_START 0 -#define M_BCM1480_MC_CS0_START _SB_MAKEMASK(12,S_BCM1480_MC_CS0_START) -#define V_BCM1480_MC_CS0_START(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS0_START) -#define G_BCM1480_MC_CS0_START(x) _SB_GETVALUE(x,S_BCM1480_MC_CS0_START,M_BCM1480_MC_CS0_START) +#define M_BCM1480_MC_CS0_START _SB_MAKEMASK(12, S_BCM1480_MC_CS0_START) +#define V_BCM1480_MC_CS0_START(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS0_START) +#define G_BCM1480_MC_CS0_START(x) _SB_GETVALUE(x, S_BCM1480_MC_CS0_START, M_BCM1480_MC_CS0_START) #define S_BCM1480_MC_CS1_START 16 -#define M_BCM1480_MC_CS1_START _SB_MAKEMASK(12,S_BCM1480_MC_CS1_START) -#define V_BCM1480_MC_CS1_START(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS1_START) -#define G_BCM1480_MC_CS1_START(x) _SB_GETVALUE(x,S_BCM1480_MC_CS1_START,M_BCM1480_MC_CS1_START) +#define M_BCM1480_MC_CS1_START _SB_MAKEMASK(12, S_BCM1480_MC_CS1_START) +#define V_BCM1480_MC_CS1_START(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS1_START) +#define G_BCM1480_MC_CS1_START(x) _SB_GETVALUE(x, S_BCM1480_MC_CS1_START, M_BCM1480_MC_CS1_START) #define S_BCM1480_MC_CS2_START 32 -#define M_BCM1480_MC_CS2_START _SB_MAKEMASK(12,S_BCM1480_MC_CS2_START) -#define V_BCM1480_MC_CS2_START(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS2_START) -#define G_BCM1480_MC_CS2_START(x) _SB_GETVALUE(x,S_BCM1480_MC_CS2_START,M_BCM1480_MC_CS2_START) +#define M_BCM1480_MC_CS2_START _SB_MAKEMASK(12, S_BCM1480_MC_CS2_START) +#define V_BCM1480_MC_CS2_START(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS2_START) +#define G_BCM1480_MC_CS2_START(x) _SB_GETVALUE(x, S_BCM1480_MC_CS2_START, M_BCM1480_MC_CS2_START) #define S_BCM1480_MC_CS3_START 48 -#define M_BCM1480_MC_CS3_START _SB_MAKEMASK(12,S_BCM1480_MC_CS3_START) -#define V_BCM1480_MC_CS3_START(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS3_START) -#define G_BCM1480_MC_CS3_START(x) _SB_GETVALUE(x,S_BCM1480_MC_CS3_START,M_BCM1480_MC_CS3_START) +#define M_BCM1480_MC_CS3_START _SB_MAKEMASK(12, S_BCM1480_MC_CS3_START) +#define V_BCM1480_MC_CS3_START(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS3_START) +#define G_BCM1480_MC_CS3_START(x) _SB_GETVALUE(x, S_BCM1480_MC_CS3_START, M_BCM1480_MC_CS3_START) /* * Chip Select End Address Register (Table 83) */ #define S_BCM1480_MC_CS0_END 0 -#define M_BCM1480_MC_CS0_END _SB_MAKEMASK(12,S_BCM1480_MC_CS0_END) -#define V_BCM1480_MC_CS0_END(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS0_END) -#define G_BCM1480_MC_CS0_END(x) _SB_GETVALUE(x,S_BCM1480_MC_CS0_END,M_BCM1480_MC_CS0_END) +#define M_BCM1480_MC_CS0_END _SB_MAKEMASK(12, S_BCM1480_MC_CS0_END) +#define V_BCM1480_MC_CS0_END(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS0_END) +#define G_BCM1480_MC_CS0_END(x) _SB_GETVALUE(x, S_BCM1480_MC_CS0_END, M_BCM1480_MC_CS0_END) #define S_BCM1480_MC_CS1_END 16 -#define M_BCM1480_MC_CS1_END _SB_MAKEMASK(12,S_BCM1480_MC_CS1_END) -#define V_BCM1480_MC_CS1_END(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS1_END) -#define G_BCM1480_MC_CS1_END(x) _SB_GETVALUE(x,S_BCM1480_MC_CS1_END,M_BCM1480_MC_CS1_END) +#define M_BCM1480_MC_CS1_END _SB_MAKEMASK(12, S_BCM1480_MC_CS1_END) +#define V_BCM1480_MC_CS1_END(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS1_END) +#define G_BCM1480_MC_CS1_END(x) _SB_GETVALUE(x, S_BCM1480_MC_CS1_END, M_BCM1480_MC_CS1_END) #define S_BCM1480_MC_CS2_END 32 -#define M_BCM1480_MC_CS2_END _SB_MAKEMASK(12,S_BCM1480_MC_CS2_END) -#define V_BCM1480_MC_CS2_END(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS2_END) -#define G_BCM1480_MC_CS2_END(x) _SB_GETVALUE(x,S_BCM1480_MC_CS2_END,M_BCM1480_MC_CS2_END) +#define M_BCM1480_MC_CS2_END _SB_MAKEMASK(12, S_BCM1480_MC_CS2_END) +#define V_BCM1480_MC_CS2_END(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS2_END) +#define G_BCM1480_MC_CS2_END(x) _SB_GETVALUE(x, S_BCM1480_MC_CS2_END, M_BCM1480_MC_CS2_END) #define S_BCM1480_MC_CS3_END 48 -#define M_BCM1480_MC_CS3_END _SB_MAKEMASK(12,S_BCM1480_MC_CS3_END) -#define V_BCM1480_MC_CS3_END(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS3_END) -#define G_BCM1480_MC_CS3_END(x) _SB_GETVALUE(x,S_BCM1480_MC_CS3_END,M_BCM1480_MC_CS3_END) +#define M_BCM1480_MC_CS3_END _SB_MAKEMASK(12, S_BCM1480_MC_CS3_END) +#define V_BCM1480_MC_CS3_END(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS3_END) +#define G_BCM1480_MC_CS3_END(x) _SB_GETVALUE(x, S_BCM1480_MC_CS3_END, M_BCM1480_MC_CS3_END) /* * Row Address Bit Select Register 0 (Table 84) */ #define S_BCM1480_MC_ROW00 0 -#define M_BCM1480_MC_ROW00 _SB_MAKEMASK(6,S_BCM1480_MC_ROW00) -#define V_BCM1480_MC_ROW00(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW00) -#define G_BCM1480_MC_ROW00(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW00,M_BCM1480_MC_ROW00) +#define M_BCM1480_MC_ROW00 _SB_MAKEMASK(6, S_BCM1480_MC_ROW00) +#define V_BCM1480_MC_ROW00(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW00) +#define G_BCM1480_MC_ROW00(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW00, M_BCM1480_MC_ROW00) #define S_BCM1480_MC_ROW01 8 -#define M_BCM1480_MC_ROW01 _SB_MAKEMASK(6,S_BCM1480_MC_ROW01) -#define V_BCM1480_MC_ROW01(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW01) -#define G_BCM1480_MC_ROW01(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW01,M_BCM1480_MC_ROW01) +#define M_BCM1480_MC_ROW01 _SB_MAKEMASK(6, S_BCM1480_MC_ROW01) +#define V_BCM1480_MC_ROW01(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW01) +#define G_BCM1480_MC_ROW01(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW01, M_BCM1480_MC_ROW01) #define S_BCM1480_MC_ROW02 16 -#define M_BCM1480_MC_ROW02 _SB_MAKEMASK(6,S_BCM1480_MC_ROW02) -#define V_BCM1480_MC_ROW02(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW02) -#define G_BCM1480_MC_ROW02(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW02,M_BCM1480_MC_ROW02) +#define M_BCM1480_MC_ROW02 _SB_MAKEMASK(6, S_BCM1480_MC_ROW02) +#define V_BCM1480_MC_ROW02(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW02) +#define G_BCM1480_MC_ROW02(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW02, M_BCM1480_MC_ROW02) #define S_BCM1480_MC_ROW03 24 -#define M_BCM1480_MC_ROW03 _SB_MAKEMASK(6,S_BCM1480_MC_ROW03) -#define V_BCM1480_MC_ROW03(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW03) -#define G_BCM1480_MC_ROW03(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW03,M_BCM1480_MC_ROW03) +#define M_BCM1480_MC_ROW03 _SB_MAKEMASK(6, S_BCM1480_MC_ROW03) +#define V_BCM1480_MC_ROW03(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW03) +#define G_BCM1480_MC_ROW03(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW03, M_BCM1480_MC_ROW03) #define S_BCM1480_MC_ROW04 32 -#define M_BCM1480_MC_ROW04 _SB_MAKEMASK(6,S_BCM1480_MC_ROW04) -#define V_BCM1480_MC_ROW04(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW04) -#define G_BCM1480_MC_ROW04(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW04,M_BCM1480_MC_ROW04) +#define M_BCM1480_MC_ROW04 _SB_MAKEMASK(6, S_BCM1480_MC_ROW04) +#define V_BCM1480_MC_ROW04(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW04) +#define G_BCM1480_MC_ROW04(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW04, M_BCM1480_MC_ROW04) #define S_BCM1480_MC_ROW05 40 -#define M_BCM1480_MC_ROW05 _SB_MAKEMASK(6,S_BCM1480_MC_ROW05) -#define V_BCM1480_MC_ROW05(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW05) -#define G_BCM1480_MC_ROW05(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW05,M_BCM1480_MC_ROW05) +#define M_BCM1480_MC_ROW05 _SB_MAKEMASK(6, S_BCM1480_MC_ROW05) +#define V_BCM1480_MC_ROW05(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW05) +#define G_BCM1480_MC_ROW05(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW05, M_BCM1480_MC_ROW05) #define S_BCM1480_MC_ROW06 48 -#define M_BCM1480_MC_ROW06 _SB_MAKEMASK(6,S_BCM1480_MC_ROW06) -#define V_BCM1480_MC_ROW06(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW06) -#define G_BCM1480_MC_ROW06(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW06,M_BCM1480_MC_ROW06) +#define M_BCM1480_MC_ROW06 _SB_MAKEMASK(6, S_BCM1480_MC_ROW06) +#define V_BCM1480_MC_ROW06(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW06) +#define G_BCM1480_MC_ROW06(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW06, M_BCM1480_MC_ROW06) #define S_BCM1480_MC_ROW07 56 -#define M_BCM1480_MC_ROW07 _SB_MAKEMASK(6,S_BCM1480_MC_ROW07) -#define V_BCM1480_MC_ROW07(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW07) -#define G_BCM1480_MC_ROW07(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW07,M_BCM1480_MC_ROW07) +#define M_BCM1480_MC_ROW07 _SB_MAKEMASK(6, S_BCM1480_MC_ROW07) +#define V_BCM1480_MC_ROW07(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW07) +#define G_BCM1480_MC_ROW07(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW07, M_BCM1480_MC_ROW07) /* * Row Address Bit Select Register 1 (Table 85) */ #define S_BCM1480_MC_ROW08 0 -#define M_BCM1480_MC_ROW08 _SB_MAKEMASK(6,S_BCM1480_MC_ROW08) -#define V_BCM1480_MC_ROW08(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW08) -#define G_BCM1480_MC_ROW08(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW08,M_BCM1480_MC_ROW08) +#define M_BCM1480_MC_ROW08 _SB_MAKEMASK(6, S_BCM1480_MC_ROW08) +#define V_BCM1480_MC_ROW08(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW08) +#define G_BCM1480_MC_ROW08(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW08, M_BCM1480_MC_ROW08) #define S_BCM1480_MC_ROW09 8 -#define M_BCM1480_MC_ROW09 _SB_MAKEMASK(6,S_BCM1480_MC_ROW09) -#define V_BCM1480_MC_ROW09(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW09) -#define G_BCM1480_MC_ROW09(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW09,M_BCM1480_MC_ROW09) +#define M_BCM1480_MC_ROW09 _SB_MAKEMASK(6, S_BCM1480_MC_ROW09) +#define V_BCM1480_MC_ROW09(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW09) +#define G_BCM1480_MC_ROW09(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW09, M_BCM1480_MC_ROW09) #define S_BCM1480_MC_ROW10 16 -#define M_BCM1480_MC_ROW10 _SB_MAKEMASK(6,S_BCM1480_MC_ROW10) -#define V_BCM1480_MC_ROW10(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW10) -#define G_BCM1480_MC_ROW10(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW10,M_BCM1480_MC_ROW10) +#define M_BCM1480_MC_ROW10 _SB_MAKEMASK(6, S_BCM1480_MC_ROW10) +#define V_BCM1480_MC_ROW10(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW10) +#define G_BCM1480_MC_ROW10(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW10, M_BCM1480_MC_ROW10) #define S_BCM1480_MC_ROW11 24 -#define M_BCM1480_MC_ROW11 _SB_MAKEMASK(6,S_BCM1480_MC_ROW11) -#define V_BCM1480_MC_ROW11(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW11) -#define G_BCM1480_MC_ROW11(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW11,M_BCM1480_MC_ROW11) +#define M_BCM1480_MC_ROW11 _SB_MAKEMASK(6, S_BCM1480_MC_ROW11) +#define V_BCM1480_MC_ROW11(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW11) +#define G_BCM1480_MC_ROW11(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW11, M_BCM1480_MC_ROW11) #define S_BCM1480_MC_ROW12 32 -#define M_BCM1480_MC_ROW12 _SB_MAKEMASK(6,S_BCM1480_MC_ROW12) -#define V_BCM1480_MC_ROW12(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW12) -#define G_BCM1480_MC_ROW12(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW12,M_BCM1480_MC_ROW12) +#define M_BCM1480_MC_ROW12 _SB_MAKEMASK(6, S_BCM1480_MC_ROW12) +#define V_BCM1480_MC_ROW12(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW12) +#define G_BCM1480_MC_ROW12(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW12, M_BCM1480_MC_ROW12) #define S_BCM1480_MC_ROW13 40 -#define M_BCM1480_MC_ROW13 _SB_MAKEMASK(6,S_BCM1480_MC_ROW13) -#define V_BCM1480_MC_ROW13(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW13) -#define G_BCM1480_MC_ROW13(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW13,M_BCM1480_MC_ROW13) +#define M_BCM1480_MC_ROW13 _SB_MAKEMASK(6, S_BCM1480_MC_ROW13) +#define V_BCM1480_MC_ROW13(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW13) +#define G_BCM1480_MC_ROW13(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW13, M_BCM1480_MC_ROW13) #define S_BCM1480_MC_ROW14 48 -#define M_BCM1480_MC_ROW14 _SB_MAKEMASK(6,S_BCM1480_MC_ROW14) -#define V_BCM1480_MC_ROW14(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ROW14) -#define G_BCM1480_MC_ROW14(x) _SB_GETVALUE(x,S_BCM1480_MC_ROW14,M_BCM1480_MC_ROW14) +#define M_BCM1480_MC_ROW14 _SB_MAKEMASK(6, S_BCM1480_MC_ROW14) +#define V_BCM1480_MC_ROW14(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ROW14) +#define G_BCM1480_MC_ROW14(x) _SB_GETVALUE(x, S_BCM1480_MC_ROW14, M_BCM1480_MC_ROW14) #define K_BCM1480_MC_ROWX_BIT_SPACING 8 @@ -214,80 +214,80 @@ */ #define S_BCM1480_MC_COL00 0 -#define M_BCM1480_MC_COL00 _SB_MAKEMASK(6,S_BCM1480_MC_COL00) -#define V_BCM1480_MC_COL00(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL00) -#define G_BCM1480_MC_COL00(x) _SB_GETVALUE(x,S_BCM1480_MC_COL00,M_BCM1480_MC_COL00) +#define M_BCM1480_MC_COL00 _SB_MAKEMASK(6, S_BCM1480_MC_COL00) +#define V_BCM1480_MC_COL00(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL00) +#define G_BCM1480_MC_COL00(x) _SB_GETVALUE(x, S_BCM1480_MC_COL00, M_BCM1480_MC_COL00) #define S_BCM1480_MC_COL01 8 -#define M_BCM1480_MC_COL01 _SB_MAKEMASK(6,S_BCM1480_MC_COL01) -#define V_BCM1480_MC_COL01(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL01) -#define G_BCM1480_MC_COL01(x) _SB_GETVALUE(x,S_BCM1480_MC_COL01,M_BCM1480_MC_COL01) +#define M_BCM1480_MC_COL01 _SB_MAKEMASK(6, S_BCM1480_MC_COL01) +#define V_BCM1480_MC_COL01(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL01) +#define G_BCM1480_MC_COL01(x) _SB_GETVALUE(x, S_BCM1480_MC_COL01, M_BCM1480_MC_COL01) #define S_BCM1480_MC_COL02 16 -#define M_BCM1480_MC_COL02 _SB_MAKEMASK(6,S_BCM1480_MC_COL02) -#define V_BCM1480_MC_COL02(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL02) -#define G_BCM1480_MC_COL02(x) _SB_GETVALUE(x,S_BCM1480_MC_COL02,M_BCM1480_MC_COL02) +#define M_BCM1480_MC_COL02 _SB_MAKEMASK(6, S_BCM1480_MC_COL02) +#define V_BCM1480_MC_COL02(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL02) +#define G_BCM1480_MC_COL02(x) _SB_GETVALUE(x, S_BCM1480_MC_COL02, M_BCM1480_MC_COL02) #define S_BCM1480_MC_COL03 24 -#define M_BCM1480_MC_COL03 _SB_MAKEMASK(6,S_BCM1480_MC_COL03) -#define V_BCM1480_MC_COL03(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL03) -#define G_BCM1480_MC_COL03(x) _SB_GETVALUE(x,S_BCM1480_MC_COL03,M_BCM1480_MC_COL03) +#define M_BCM1480_MC_COL03 _SB_MAKEMASK(6, S_BCM1480_MC_COL03) +#define V_BCM1480_MC_COL03(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL03) +#define G_BCM1480_MC_COL03(x) _SB_GETVALUE(x, S_BCM1480_MC_COL03, M_BCM1480_MC_COL03) #define S_BCM1480_MC_COL04 32 -#define M_BCM1480_MC_COL04 _SB_MAKEMASK(6,S_BCM1480_MC_COL04) -#define V_BCM1480_MC_COL04(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL04) -#define G_BCM1480_MC_COL04(x) _SB_GETVALUE(x,S_BCM1480_MC_COL04,M_BCM1480_MC_COL04) +#define M_BCM1480_MC_COL04 _SB_MAKEMASK(6, S_BCM1480_MC_COL04) +#define V_BCM1480_MC_COL04(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL04) +#define G_BCM1480_MC_COL04(x) _SB_GETVALUE(x, S_BCM1480_MC_COL04, M_BCM1480_MC_COL04) #define S_BCM1480_MC_COL05 40 -#define M_BCM1480_MC_COL05 _SB_MAKEMASK(6,S_BCM1480_MC_COL05) -#define V_BCM1480_MC_COL05(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL05) -#define G_BCM1480_MC_COL05(x) _SB_GETVALUE(x,S_BCM1480_MC_COL05,M_BCM1480_MC_COL05) +#define M_BCM1480_MC_COL05 _SB_MAKEMASK(6, S_BCM1480_MC_COL05) +#define V_BCM1480_MC_COL05(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL05) +#define G_BCM1480_MC_COL05(x) _SB_GETVALUE(x, S_BCM1480_MC_COL05, M_BCM1480_MC_COL05) #define S_BCM1480_MC_COL06 48 -#define M_BCM1480_MC_COL06 _SB_MAKEMASK(6,S_BCM1480_MC_COL06) -#define V_BCM1480_MC_COL06(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL06) -#define G_BCM1480_MC_COL06(x) _SB_GETVALUE(x,S_BCM1480_MC_COL06,M_BCM1480_MC_COL06) +#define M_BCM1480_MC_COL06 _SB_MAKEMASK(6, S_BCM1480_MC_COL06) +#define V_BCM1480_MC_COL06(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL06) +#define G_BCM1480_MC_COL06(x) _SB_GETVALUE(x, S_BCM1480_MC_COL06, M_BCM1480_MC_COL06) #define S_BCM1480_MC_COL07 56 -#define M_BCM1480_MC_COL07 _SB_MAKEMASK(6,S_BCM1480_MC_COL07) -#define V_BCM1480_MC_COL07(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL07) -#define G_BCM1480_MC_COL07(x) _SB_GETVALUE(x,S_BCM1480_MC_COL07,M_BCM1480_MC_COL07) +#define M_BCM1480_MC_COL07 _SB_MAKEMASK(6, S_BCM1480_MC_COL07) +#define V_BCM1480_MC_COL07(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL07) +#define G_BCM1480_MC_COL07(x) _SB_GETVALUE(x, S_BCM1480_MC_COL07, M_BCM1480_MC_COL07) /* * Column Address Bit Select Register 1 (Table 87) */ #define S_BCM1480_MC_COL08 0 -#define M_BCM1480_MC_COL08 _SB_MAKEMASK(6,S_BCM1480_MC_COL08) -#define V_BCM1480_MC_COL08(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL08) -#define G_BCM1480_MC_COL08(x) _SB_GETVALUE(x,S_BCM1480_MC_COL08,M_BCM1480_MC_COL08) +#define M_BCM1480_MC_COL08 _SB_MAKEMASK(6, S_BCM1480_MC_COL08) +#define V_BCM1480_MC_COL08(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL08) +#define G_BCM1480_MC_COL08(x) _SB_GETVALUE(x, S_BCM1480_MC_COL08, M_BCM1480_MC_COL08) #define S_BCM1480_MC_COL09 8 -#define M_BCM1480_MC_COL09 _SB_MAKEMASK(6,S_BCM1480_MC_COL09) -#define V_BCM1480_MC_COL09(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL09) -#define G_BCM1480_MC_COL09(x) _SB_GETVALUE(x,S_BCM1480_MC_COL09,M_BCM1480_MC_COL09) +#define M_BCM1480_MC_COL09 _SB_MAKEMASK(6, S_BCM1480_MC_COL09) +#define V_BCM1480_MC_COL09(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL09) +#define G_BCM1480_MC_COL09(x) _SB_GETVALUE(x, S_BCM1480_MC_COL09, M_BCM1480_MC_COL09) #define S_BCM1480_MC_COL10 16 /* not a valid position, must be prog as 0 */ #define S_BCM1480_MC_COL11 24 -#define M_BCM1480_MC_COL11 _SB_MAKEMASK(6,S_BCM1480_MC_COL11) -#define V_BCM1480_MC_COL11(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL11) -#define G_BCM1480_MC_COL11(x) _SB_GETVALUE(x,S_BCM1480_MC_COL11,M_BCM1480_MC_COL11) +#define M_BCM1480_MC_COL11 _SB_MAKEMASK(6, S_BCM1480_MC_COL11) +#define V_BCM1480_MC_COL11(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL11) +#define G_BCM1480_MC_COL11(x) _SB_GETVALUE(x, S_BCM1480_MC_COL11, M_BCM1480_MC_COL11) #define S_BCM1480_MC_COL12 32 -#define M_BCM1480_MC_COL12 _SB_MAKEMASK(6,S_BCM1480_MC_COL12) -#define V_BCM1480_MC_COL12(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL12) -#define G_BCM1480_MC_COL12(x) _SB_GETVALUE(x,S_BCM1480_MC_COL12,M_BCM1480_MC_COL12) +#define M_BCM1480_MC_COL12 _SB_MAKEMASK(6, S_BCM1480_MC_COL12) +#define V_BCM1480_MC_COL12(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL12) +#define G_BCM1480_MC_COL12(x) _SB_GETVALUE(x, S_BCM1480_MC_COL12, M_BCM1480_MC_COL12) #define S_BCM1480_MC_COL13 40 -#define M_BCM1480_MC_COL13 _SB_MAKEMASK(6,S_BCM1480_MC_COL13) -#define V_BCM1480_MC_COL13(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL13) -#define G_BCM1480_MC_COL13(x) _SB_GETVALUE(x,S_BCM1480_MC_COL13,M_BCM1480_MC_COL13) +#define M_BCM1480_MC_COL13 _SB_MAKEMASK(6, S_BCM1480_MC_COL13) +#define V_BCM1480_MC_COL13(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL13) +#define G_BCM1480_MC_COL13(x) _SB_GETVALUE(x, S_BCM1480_MC_COL13, M_BCM1480_MC_COL13) #define S_BCM1480_MC_COL14 48 -#define M_BCM1480_MC_COL14 _SB_MAKEMASK(6,S_BCM1480_MC_COL14) -#define V_BCM1480_MC_COL14(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COL14) -#define G_BCM1480_MC_COL14(x) _SB_GETVALUE(x,S_BCM1480_MC_COL14,M_BCM1480_MC_COL14) +#define M_BCM1480_MC_COL14 _SB_MAKEMASK(6, S_BCM1480_MC_COL14) +#define V_BCM1480_MC_COL14(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COL14) +#define G_BCM1480_MC_COL14(x) _SB_GETVALUE(x, S_BCM1480_MC_COL14, M_BCM1480_MC_COL14) #define K_BCM1480_MC_COLX_BIT_SPACING 8 @@ -296,38 +296,38 @@ */ #define S_BCM1480_MC_CS01_BANK0 0 -#define M_BCM1480_MC_CS01_BANK0 _SB_MAKEMASK(6,S_BCM1480_MC_CS01_BANK0) -#define V_BCM1480_MC_CS01_BANK0(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS01_BANK0) -#define G_BCM1480_MC_CS01_BANK0(x) _SB_GETVALUE(x,S_BCM1480_MC_CS01_BANK0,M_BCM1480_MC_CS01_BANK0) +#define M_BCM1480_MC_CS01_BANK0 _SB_MAKEMASK(6, S_BCM1480_MC_CS01_BANK0) +#define V_BCM1480_MC_CS01_BANK0(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS01_BANK0) +#define G_BCM1480_MC_CS01_BANK0(x) _SB_GETVALUE(x, S_BCM1480_MC_CS01_BANK0, M_BCM1480_MC_CS01_BANK0) #define S_BCM1480_MC_CS01_BANK1 8 -#define M_BCM1480_MC_CS01_BANK1 _SB_MAKEMASK(6,S_BCM1480_MC_CS01_BANK1) -#define V_BCM1480_MC_CS01_BANK1(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS01_BANK1) -#define G_BCM1480_MC_CS01_BANK1(x) _SB_GETVALUE(x,S_BCM1480_MC_CS01_BANK1,M_BCM1480_MC_CS01_BANK1) +#define M_BCM1480_MC_CS01_BANK1 _SB_MAKEMASK(6, S_BCM1480_MC_CS01_BANK1) +#define V_BCM1480_MC_CS01_BANK1(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS01_BANK1) +#define G_BCM1480_MC_CS01_BANK1(x) _SB_GETVALUE(x, S_BCM1480_MC_CS01_BANK1, M_BCM1480_MC_CS01_BANK1) #define S_BCM1480_MC_CS01_BANK2 16 -#define M_BCM1480_MC_CS01_BANK2 _SB_MAKEMASK(6,S_BCM1480_MC_CS01_BANK2) -#define V_BCM1480_MC_CS01_BANK2(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS01_BANK2) -#define G_BCM1480_MC_CS01_BANK2(x) _SB_GETVALUE(x,S_BCM1480_MC_CS01_BANK2,M_BCM1480_MC_CS01_BANK2) +#define M_BCM1480_MC_CS01_BANK2 _SB_MAKEMASK(6, S_BCM1480_MC_CS01_BANK2) +#define V_BCM1480_MC_CS01_BANK2(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS01_BANK2) +#define G_BCM1480_MC_CS01_BANK2(x) _SB_GETVALUE(x, S_BCM1480_MC_CS01_BANK2, M_BCM1480_MC_CS01_BANK2) /* * CS2 and CS3 Bank Address Bit Select Register (Table 89) */ #define S_BCM1480_MC_CS23_BANK0 0 -#define M_BCM1480_MC_CS23_BANK0 _SB_MAKEMASK(6,S_BCM1480_MC_CS23_BANK0) -#define V_BCM1480_MC_CS23_BANK0(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS23_BANK0) -#define G_BCM1480_MC_CS23_BANK0(x) _SB_GETVALUE(x,S_BCM1480_MC_CS23_BANK0,M_BCM1480_MC_CS23_BANK0) +#define M_BCM1480_MC_CS23_BANK0 _SB_MAKEMASK(6, S_BCM1480_MC_CS23_BANK0) +#define V_BCM1480_MC_CS23_BANK0(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS23_BANK0) +#define G_BCM1480_MC_CS23_BANK0(x) _SB_GETVALUE(x, S_BCM1480_MC_CS23_BANK0, M_BCM1480_MC_CS23_BANK0) #define S_BCM1480_MC_CS23_BANK1 8 -#define M_BCM1480_MC_CS23_BANK1 _SB_MAKEMASK(6,S_BCM1480_MC_CS23_BANK1) -#define V_BCM1480_MC_CS23_BANK1(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS23_BANK1) -#define G_BCM1480_MC_CS23_BANK1(x) _SB_GETVALUE(x,S_BCM1480_MC_CS23_BANK1,M_BCM1480_MC_CS23_BANK1) +#define M_BCM1480_MC_CS23_BANK1 _SB_MAKEMASK(6, S_BCM1480_MC_CS23_BANK1) +#define V_BCM1480_MC_CS23_BANK1(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS23_BANK1) +#define G_BCM1480_MC_CS23_BANK1(x) _SB_GETVALUE(x, S_BCM1480_MC_CS23_BANK1, M_BCM1480_MC_CS23_BANK1) #define S_BCM1480_MC_CS23_BANK2 16 -#define M_BCM1480_MC_CS23_BANK2 _SB_MAKEMASK(6,S_BCM1480_MC_CS23_BANK2) -#define V_BCM1480_MC_CS23_BANK2(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS23_BANK2) -#define G_BCM1480_MC_CS23_BANK2(x) _SB_GETVALUE(x,S_BCM1480_MC_CS23_BANK2,M_BCM1480_MC_CS23_BANK2) +#define M_BCM1480_MC_CS23_BANK2 _SB_MAKEMASK(6, S_BCM1480_MC_CS23_BANK2) +#define V_BCM1480_MC_CS23_BANK2(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS23_BANK2) +#define G_BCM1480_MC_CS23_BANK2(x) _SB_GETVALUE(x, S_BCM1480_MC_CS23_BANK2, M_BCM1480_MC_CS23_BANK2) #define K_BCM1480_MC_CSXX_BANKX_BIT_SPACING 8 @@ -336,9 +336,9 @@ */ #define S_BCM1480_MC_COMMAND 0 -#define M_BCM1480_MC_COMMAND _SB_MAKEMASK(4,S_BCM1480_MC_COMMAND) -#define V_BCM1480_MC_COMMAND(x) _SB_MAKEVALUE(x,S_BCM1480_MC_COMMAND) -#define G_BCM1480_MC_COMMAND(x) _SB_GETVALUE(x,S_BCM1480_MC_COMMAND,M_BCM1480_MC_COMMAND) +#define M_BCM1480_MC_COMMAND _SB_MAKEMASK(4, S_BCM1480_MC_COMMAND) +#define V_BCM1480_MC_COMMAND(x) _SB_MAKEVALUE(x, S_BCM1480_MC_COMMAND) +#define G_BCM1480_MC_COMMAND(x) _SB_GETVALUE(x, S_BCM1480_MC_COMMAND, M_BCM1480_MC_COMMAND) #define K_BCM1480_MC_COMMAND_EMRS 0 #define K_BCM1480_MC_COMMAND_MRS 1 @@ -382,9 +382,9 @@ #define M_BCM1480_MC_CS6 _SB_MAKEMASK1(10) #define M_BCM1480_MC_CS7 _SB_MAKEMASK1(11) -#define M_BCM1480_MC_CS _SB_MAKEMASK(8,S_BCM1480_MC_CS0) -#define V_BCM1480_MC_CS(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CS0) -#define G_BCM1480_MC_CS(x) _SB_GETVALUE(x,S_BCM1480_MC_CS0,M_BCM1480_MC_CS0) +#define M_BCM1480_MC_CS _SB_MAKEMASK(8, S_BCM1480_MC_CS0) +#define V_BCM1480_MC_CS(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CS0) +#define G_BCM1480_MC_CS(x) _SB_GETVALUE(x, S_BCM1480_MC_CS0, M_BCM1480_MC_CS0) #define M_BCM1480_MC_CMD_ACTIVE _SB_MAKEMASK1(16) @@ -393,21 +393,21 @@ */ #define S_BCM1480_MC_EMODE 0 -#define M_BCM1480_MC_EMODE _SB_MAKEMASK(15,S_BCM1480_MC_EMODE) -#define V_BCM1480_MC_EMODE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_EMODE) -#define G_BCM1480_MC_EMODE(x) _SB_GETVALUE(x,S_BCM1480_MC_EMODE,M_BCM1480_MC_EMODE) +#define M_BCM1480_MC_EMODE _SB_MAKEMASK(15, S_BCM1480_MC_EMODE) +#define V_BCM1480_MC_EMODE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_EMODE) +#define G_BCM1480_MC_EMODE(x) _SB_GETVALUE(x, S_BCM1480_MC_EMODE, M_BCM1480_MC_EMODE) #define V_BCM1480_MC_EMODE_DEFAULT V_BCM1480_MC_EMODE(0) #define S_BCM1480_MC_MODE 16 -#define M_BCM1480_MC_MODE _SB_MAKEMASK(15,S_BCM1480_MC_MODE) -#define V_BCM1480_MC_MODE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_MODE) -#define G_BCM1480_MC_MODE(x) _SB_GETVALUE(x,S_BCM1480_MC_MODE,M_BCM1480_MC_MODE) +#define M_BCM1480_MC_MODE _SB_MAKEMASK(15, S_BCM1480_MC_MODE) +#define V_BCM1480_MC_MODE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_MODE) +#define G_BCM1480_MC_MODE(x) _SB_GETVALUE(x, S_BCM1480_MC_MODE, M_BCM1480_MC_MODE) #define V_BCM1480_MC_MODE_DEFAULT V_BCM1480_MC_MODE(0) #define S_BCM1480_MC_DRAM_TYPE 32 -#define M_BCM1480_MC_DRAM_TYPE _SB_MAKEMASK(4,S_BCM1480_MC_DRAM_TYPE) -#define V_BCM1480_MC_DRAM_TYPE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DRAM_TYPE) -#define G_BCM1480_MC_DRAM_TYPE(x) _SB_GETVALUE(x,S_BCM1480_MC_DRAM_TYPE,M_BCM1480_MC_DRAM_TYPE) +#define M_BCM1480_MC_DRAM_TYPE _SB_MAKEMASK(4, S_BCM1480_MC_DRAM_TYPE) +#define V_BCM1480_MC_DRAM_TYPE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DRAM_TYPE) +#define G_BCM1480_MC_DRAM_TYPE(x) _SB_GETVALUE(x, S_BCM1480_MC_DRAM_TYPE, M_BCM1480_MC_DRAM_TYPE) #define K_BCM1480_MC_DRAM_TYPE_JEDEC 0 #define K_BCM1480_MC_DRAM_TYPE_FCRAM 1 @@ -431,9 +431,9 @@ #define M_BCM1480_MC_ECC_DISABLE _SB_MAKEMASK1(39) #define S_BCM1480_MC_PG_POLICY 40 -#define M_BCM1480_MC_PG_POLICY _SB_MAKEMASK(2,S_BCM1480_MC_PG_POLICY) -#define V_BCM1480_MC_PG_POLICY(x) _SB_MAKEVALUE(x,S_BCM1480_MC_PG_POLICY) -#define G_BCM1480_MC_PG_POLICY(x) _SB_GETVALUE(x,S_BCM1480_MC_PG_POLICY,M_BCM1480_MC_PG_POLICY) +#define M_BCM1480_MC_PG_POLICY _SB_MAKEMASK(2, S_BCM1480_MC_PG_POLICY) +#define V_BCM1480_MC_PG_POLICY(x) _SB_MAKEVALUE(x, S_BCM1480_MC_PG_POLICY) +#define G_BCM1480_MC_PG_POLICY(x) _SB_GETVALUE(x, S_BCM1480_MC_PG_POLICY, M_BCM1480_MC_PG_POLICY) #define K_BCM1480_MC_PG_POLICY_CLOSED 0 #define K_BCM1480_MC_PG_POLICY_CAS_TIME_CHK 1 @@ -454,16 +454,16 @@ */ #define S_BCM1480_MC_CLK_RATIO 0 -#define M_BCM1480_MC_CLK_RATIO _SB_MAKEMASK(6,S_BCM1480_MC_CLK_RATIO) -#define V_BCM1480_MC_CLK_RATIO(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CLK_RATIO) -#define G_BCM1480_MC_CLK_RATIO(x) _SB_GETVALUE(x,S_BCM1480_MC_CLK_RATIO,M_BCM1480_MC_CLK_RATIO) +#define M_BCM1480_MC_CLK_RATIO _SB_MAKEMASK(6, S_BCM1480_MC_CLK_RATIO) +#define V_BCM1480_MC_CLK_RATIO(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CLK_RATIO) +#define G_BCM1480_MC_CLK_RATIO(x) _SB_GETVALUE(x, S_BCM1480_MC_CLK_RATIO, M_BCM1480_MC_CLK_RATIO) #define V_BCM1480_MC_CLK_RATIO_DEFAULT V_BCM1480_MC_CLK_RATIO(10) #define S_BCM1480_MC_REF_RATE 8 -#define M_BCM1480_MC_REF_RATE _SB_MAKEMASK(8,S_BCM1480_MC_REF_RATE) -#define V_BCM1480_MC_REF_RATE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_REF_RATE) -#define G_BCM1480_MC_REF_RATE(x) _SB_GETVALUE(x,S_BCM1480_MC_REF_RATE,M_BCM1480_MC_REF_RATE) +#define M_BCM1480_MC_REF_RATE _SB_MAKEMASK(8, S_BCM1480_MC_REF_RATE) +#define V_BCM1480_MC_REF_RATE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_REF_RATE) +#define G_BCM1480_MC_REF_RATE(x) _SB_GETVALUE(x, S_BCM1480_MC_REF_RATE, M_BCM1480_MC_REF_RATE) #define K_BCM1480_MC_REF_RATE_100MHz 0x31 #define K_BCM1480_MC_REF_RATE_200MHz 0x62 @@ -519,20 +519,20 @@ #define M_BCM1480_MC_CS_ODD_ODT_EN _SB_MAKEMASK1(32) #define S_BCM1480_MC_ODT0 0 -#define M_BCM1480_MC_ODT0 _SB_MAKEMASK(8,S_BCM1480_MC_ODT0) -#define V_BCM1480_MC_ODT0(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ODT0) +#define M_BCM1480_MC_ODT0 _SB_MAKEMASK(8, S_BCM1480_MC_ODT0) +#define V_BCM1480_MC_ODT0(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ODT0) #define S_BCM1480_MC_ODT2 8 -#define M_BCM1480_MC_ODT2 _SB_MAKEMASK(8,S_BCM1480_MC_ODT2) -#define V_BCM1480_MC_ODT2(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ODT2) +#define M_BCM1480_MC_ODT2 _SB_MAKEMASK(8, S_BCM1480_MC_ODT2) +#define V_BCM1480_MC_ODT2(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ODT2) #define S_BCM1480_MC_ODT4 16 -#define M_BCM1480_MC_ODT4 _SB_MAKEMASK(8,S_BCM1480_MC_ODT4) -#define V_BCM1480_MC_ODT4(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ODT4) +#define M_BCM1480_MC_ODT4 _SB_MAKEMASK(8, S_BCM1480_MC_ODT4) +#define V_BCM1480_MC_ODT4(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ODT4) #define S_BCM1480_MC_ODT6 24 -#define M_BCM1480_MC_ODT6 _SB_MAKEMASK(8,S_BCM1480_MC_ODT6) -#define V_BCM1480_MC_ODT6(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ODT6) +#define M_BCM1480_MC_ODT6 _SB_MAKEMASK(8, S_BCM1480_MC_ODT6) +#define V_BCM1480_MC_ODT6(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ODT6) #endif /* @@ -540,70 +540,70 @@ */ #define S_BCM1480_MC_ADDR_COARSE_ADJ 0 -#define M_BCM1480_MC_ADDR_COARSE_ADJ _SB_MAKEMASK(6,S_BCM1480_MC_ADDR_COARSE_ADJ) -#define V_BCM1480_MC_ADDR_COARSE_ADJ(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ADDR_COARSE_ADJ) -#define G_BCM1480_MC_ADDR_COARSE_ADJ(x) _SB_GETVALUE(x,S_BCM1480_MC_ADDR_COARSE_ADJ,M_BCM1480_MC_ADDR_COARSE_ADJ) +#define M_BCM1480_MC_ADDR_COARSE_ADJ _SB_MAKEMASK(6, S_BCM1480_MC_ADDR_COARSE_ADJ) +#define V_BCM1480_MC_ADDR_COARSE_ADJ(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ADDR_COARSE_ADJ) +#define G_BCM1480_MC_ADDR_COARSE_ADJ(x) _SB_GETVALUE(x, S_BCM1480_MC_ADDR_COARSE_ADJ, M_BCM1480_MC_ADDR_COARSE_ADJ) #define V_BCM1480_MC_ADDR_COARSE_ADJ_DEFAULT V_BCM1480_MC_ADDR_COARSE_ADJ(0x0) #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_ADDR_FREQ_RANGE 8 -#define M_BCM1480_MC_ADDR_FREQ_RANGE _SB_MAKEMASK(4,S_BCM1480_MC_ADDR_FREQ_RANGE) -#define V_BCM1480_MC_ADDR_FREQ_RANGE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ADDR_FREQ_RANGE) -#define G_BCM1480_MC_ADDR_FREQ_RANGE(x) _SB_GETVALUE(x,S_BCM1480_MC_ADDR_FREQ_RANGE,M_BCM1480_MC_ADDR_FREQ_RANGE) +#define M_BCM1480_MC_ADDR_FREQ_RANGE _SB_MAKEMASK(4, S_BCM1480_MC_ADDR_FREQ_RANGE) +#define V_BCM1480_MC_ADDR_FREQ_RANGE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ADDR_FREQ_RANGE) +#define G_BCM1480_MC_ADDR_FREQ_RANGE(x) _SB_GETVALUE(x, S_BCM1480_MC_ADDR_FREQ_RANGE, M_BCM1480_MC_ADDR_FREQ_RANGE) #define V_BCM1480_MC_ADDR_FREQ_RANGE_DEFAULT V_BCM1480_MC_ADDR_FREQ_RANGE(0x4) #endif #define S_BCM1480_MC_ADDR_FINE_ADJ 8 -#define M_BCM1480_MC_ADDR_FINE_ADJ _SB_MAKEMASK(4,S_BCM1480_MC_ADDR_FINE_ADJ) -#define V_BCM1480_MC_ADDR_FINE_ADJ(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ADDR_FINE_ADJ) -#define G_BCM1480_MC_ADDR_FINE_ADJ(x) _SB_GETVALUE(x,S_BCM1480_MC_ADDR_FINE_ADJ,M_BCM1480_MC_ADDR_FINE_ADJ) +#define M_BCM1480_MC_ADDR_FINE_ADJ _SB_MAKEMASK(4, S_BCM1480_MC_ADDR_FINE_ADJ) +#define V_BCM1480_MC_ADDR_FINE_ADJ(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ADDR_FINE_ADJ) +#define G_BCM1480_MC_ADDR_FINE_ADJ(x) _SB_GETVALUE(x, S_BCM1480_MC_ADDR_FINE_ADJ, M_BCM1480_MC_ADDR_FINE_ADJ) #define V_BCM1480_MC_ADDR_FINE_ADJ_DEFAULT V_BCM1480_MC_ADDR_FINE_ADJ(0x8) #define S_BCM1480_MC_DQI_COARSE_ADJ 16 -#define M_BCM1480_MC_DQI_COARSE_ADJ _SB_MAKEMASK(6,S_BCM1480_MC_DQI_COARSE_ADJ) -#define V_BCM1480_MC_DQI_COARSE_ADJ(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DQI_COARSE_ADJ) -#define G_BCM1480_MC_DQI_COARSE_ADJ(x) _SB_GETVALUE(x,S_BCM1480_MC_DQI_COARSE_ADJ,M_BCM1480_MC_DQI_COARSE_ADJ) +#define M_BCM1480_MC_DQI_COARSE_ADJ _SB_MAKEMASK(6, S_BCM1480_MC_DQI_COARSE_ADJ) +#define V_BCM1480_MC_DQI_COARSE_ADJ(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DQI_COARSE_ADJ) +#define G_BCM1480_MC_DQI_COARSE_ADJ(x) _SB_GETVALUE(x, S_BCM1480_MC_DQI_COARSE_ADJ, M_BCM1480_MC_DQI_COARSE_ADJ) #define V_BCM1480_MC_DQI_COARSE_ADJ_DEFAULT V_BCM1480_MC_DQI_COARSE_ADJ(0x0) #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_DQI_FREQ_RANGE 24 -#define M_BCM1480_MC_DQI_FREQ_RANGE _SB_MAKEMASK(4,S_BCM1480_MC_DQI_FREQ_RANGE) -#define V_BCM1480_MC_DQI_FREQ_RANGE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DQI_FREQ_RANGE) -#define G_BCM1480_MC_DQI_FREQ_RANGE(x) _SB_GETVALUE(x,S_BCM1480_MC_DQI_FREQ_RANGE,M_BCM1480_MC_DQI_FREQ_RANGE) +#define M_BCM1480_MC_DQI_FREQ_RANGE _SB_MAKEMASK(4, S_BCM1480_MC_DQI_FREQ_RANGE) +#define V_BCM1480_MC_DQI_FREQ_RANGE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DQI_FREQ_RANGE) +#define G_BCM1480_MC_DQI_FREQ_RANGE(x) _SB_GETVALUE(x, S_BCM1480_MC_DQI_FREQ_RANGE, M_BCM1480_MC_DQI_FREQ_RANGE) #define V_BCM1480_MC_DQI_FREQ_RANGE_DEFAULT V_BCM1480_MC_DQI_FREQ_RANGE(0x4) #endif #define S_BCM1480_MC_DQI_FINE_ADJ 24 -#define M_BCM1480_MC_DQI_FINE_ADJ _SB_MAKEMASK(4,S_BCM1480_MC_DQI_FINE_ADJ) -#define V_BCM1480_MC_DQI_FINE_ADJ(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DQI_FINE_ADJ) -#define G_BCM1480_MC_DQI_FINE_ADJ(x) _SB_GETVALUE(x,S_BCM1480_MC_DQI_FINE_ADJ,M_BCM1480_MC_DQI_FINE_ADJ) +#define M_BCM1480_MC_DQI_FINE_ADJ _SB_MAKEMASK(4, S_BCM1480_MC_DQI_FINE_ADJ) +#define V_BCM1480_MC_DQI_FINE_ADJ(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DQI_FINE_ADJ) +#define G_BCM1480_MC_DQI_FINE_ADJ(x) _SB_GETVALUE(x, S_BCM1480_MC_DQI_FINE_ADJ, M_BCM1480_MC_DQI_FINE_ADJ) #define V_BCM1480_MC_DQI_FINE_ADJ_DEFAULT V_BCM1480_MC_DQI_FINE_ADJ(0x8) #define S_BCM1480_MC_DQO_COARSE_ADJ 32 -#define M_BCM1480_MC_DQO_COARSE_ADJ _SB_MAKEMASK(6,S_BCM1480_MC_DQO_COARSE_ADJ) -#define V_BCM1480_MC_DQO_COARSE_ADJ(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DQO_COARSE_ADJ) -#define G_BCM1480_MC_DQO_COARSE_ADJ(x) _SB_GETVALUE(x,S_BCM1480_MC_DQO_COARSE_ADJ,M_BCM1480_MC_DQO_COARSE_ADJ) +#define M_BCM1480_MC_DQO_COARSE_ADJ _SB_MAKEMASK(6, S_BCM1480_MC_DQO_COARSE_ADJ) +#define V_BCM1480_MC_DQO_COARSE_ADJ(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DQO_COARSE_ADJ) +#define G_BCM1480_MC_DQO_COARSE_ADJ(x) _SB_GETVALUE(x, S_BCM1480_MC_DQO_COARSE_ADJ, M_BCM1480_MC_DQO_COARSE_ADJ) #define V_BCM1480_MC_DQO_COARSE_ADJ_DEFAULT V_BCM1480_MC_DQO_COARSE_ADJ(0x0) #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_DQO_FREQ_RANGE 40 -#define M_BCM1480_MC_DQO_FREQ_RANGE _SB_MAKEMASK(4,S_BCM1480_MC_DQO_FREQ_RANGE) -#define V_BCM1480_MC_DQO_FREQ_RANGE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DQO_FREQ_RANGE) -#define G_BCM1480_MC_DQO_FREQ_RANGE(x) _SB_GETVALUE(x,S_BCM1480_MC_DQO_FREQ_RANGE,M_BCM1480_MC_DQO_FREQ_RANGE) +#define M_BCM1480_MC_DQO_FREQ_RANGE _SB_MAKEMASK(4, S_BCM1480_MC_DQO_FREQ_RANGE) +#define V_BCM1480_MC_DQO_FREQ_RANGE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DQO_FREQ_RANGE) +#define G_BCM1480_MC_DQO_FREQ_RANGE(x) _SB_GETVALUE(x, S_BCM1480_MC_DQO_FREQ_RANGE, M_BCM1480_MC_DQO_FREQ_RANGE) #define V_BCM1480_MC_DQO_FREQ_RANGE_DEFAULT V_BCM1480_MC_DQO_FREQ_RANGE(0x4) #endif #define S_BCM1480_MC_DQO_FINE_ADJ 40 -#define M_BCM1480_MC_DQO_FINE_ADJ _SB_MAKEMASK(4,S_BCM1480_MC_DQO_FINE_ADJ) -#define V_BCM1480_MC_DQO_FINE_ADJ(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DQO_FINE_ADJ) -#define G_BCM1480_MC_DQO_FINE_ADJ(x) _SB_GETVALUE(x,S_BCM1480_MC_DQO_FINE_ADJ,M_BCM1480_MC_DQO_FINE_ADJ) +#define M_BCM1480_MC_DQO_FINE_ADJ _SB_MAKEMASK(4, S_BCM1480_MC_DQO_FINE_ADJ) +#define V_BCM1480_MC_DQO_FINE_ADJ(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DQO_FINE_ADJ) +#define G_BCM1480_MC_DQO_FINE_ADJ(x) _SB_GETVALUE(x, S_BCM1480_MC_DQO_FINE_ADJ, M_BCM1480_MC_DQO_FINE_ADJ) #define V_BCM1480_MC_DQO_FINE_ADJ_DEFAULT V_BCM1480_MC_DQO_FINE_ADJ(0x8) #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_DLL_PDSEL 44 -#define M_BCM1480_MC_DLL_PDSEL _SB_MAKEMASK(2,S_BCM1480_MC_DLL_PDSEL) -#define V_BCM1480_MC_DLL_PDSEL(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DLL_PDSEL) -#define G_BCM1480_MC_DLL_PDSEL(x) _SB_GETVALUE(x,S_BCM1480_MC_DLL_PDSEL,M_BCM1480_MC_DLL_PDSEL) +#define M_BCM1480_MC_DLL_PDSEL _SB_MAKEMASK(2, S_BCM1480_MC_DLL_PDSEL) +#define V_BCM1480_MC_DLL_PDSEL(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DLL_PDSEL) +#define G_BCM1480_MC_DLL_PDSEL(x) _SB_GETVALUE(x, S_BCM1480_MC_DLL_PDSEL, M_BCM1480_MC_DLL_PDSEL) #define V_BCM1480_MC_DLL_DEFAULT_PDSEL V_BCM1480_MC_DLL_PDSEL(0x0) #define M_BCM1480_MC_DLL_REGBYPASS _SB_MAKEMASK1(46) @@ -611,38 +611,38 @@ #endif #define S_BCM1480_MC_DLL_DEFAULT 48 -#define M_BCM1480_MC_DLL_DEFAULT _SB_MAKEMASK(6,S_BCM1480_MC_DLL_DEFAULT) -#define V_BCM1480_MC_DLL_DEFAULT(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DLL_DEFAULT) -#define G_BCM1480_MC_DLL_DEFAULT(x) _SB_GETVALUE(x,S_BCM1480_MC_DLL_DEFAULT,M_BCM1480_MC_DLL_DEFAULT) +#define M_BCM1480_MC_DLL_DEFAULT _SB_MAKEMASK(6, S_BCM1480_MC_DLL_DEFAULT) +#define V_BCM1480_MC_DLL_DEFAULT(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DLL_DEFAULT) +#define G_BCM1480_MC_DLL_DEFAULT(x) _SB_GETVALUE(x, S_BCM1480_MC_DLL_DEFAULT, M_BCM1480_MC_DLL_DEFAULT) #define V_BCM1480_MC_DLL_DEFAULT_DEFAULT V_BCM1480_MC_DLL_DEFAULT(0x10) #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_DLL_REGCTRL 54 -#define M_BCM1480_MC_DLL_REGCTRL _SB_MAKEMASK(2,S_BCM1480_MC_DLL_REGCTRL) -#define V_BCM1480_MC_DLL_REGCTRL(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DLL_REGCTRL) -#define G_BCM1480_MC_DLL_REGCTRL(x) _SB_GETVALUE(x,S_BCM1480_MC_DLL_REGCTRL,M_BCM1480_MC_DLL_REGCTRL) +#define M_BCM1480_MC_DLL_REGCTRL _SB_MAKEMASK(2, S_BCM1480_MC_DLL_REGCTRL) +#define V_BCM1480_MC_DLL_REGCTRL(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DLL_REGCTRL) +#define G_BCM1480_MC_DLL_REGCTRL(x) _SB_GETVALUE(x, S_BCM1480_MC_DLL_REGCTRL, M_BCM1480_MC_DLL_REGCTRL) #define V_BCM1480_MC_DLL_DEFAULT_REGCTRL V_BCM1480_MC_DLL_REGCTRL(0x0) #endif #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_DLL_FREQ_RANGE 56 -#define M_BCM1480_MC_DLL_FREQ_RANGE _SB_MAKEMASK(4,S_BCM1480_MC_DLL_FREQ_RANGE) -#define V_BCM1480_MC_DLL_FREQ_RANGE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DLL_FREQ_RANGE) -#define G_BCM1480_MC_DLL_FREQ_RANGE(x) _SB_GETVALUE(x,S_BCM1480_MC_DLL_FREQ_RANGE,M_BCM1480_MC_DLL_FREQ_RANGE) +#define M_BCM1480_MC_DLL_FREQ_RANGE _SB_MAKEMASK(4, S_BCM1480_MC_DLL_FREQ_RANGE) +#define V_BCM1480_MC_DLL_FREQ_RANGE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DLL_FREQ_RANGE) +#define G_BCM1480_MC_DLL_FREQ_RANGE(x) _SB_GETVALUE(x, S_BCM1480_MC_DLL_FREQ_RANGE, M_BCM1480_MC_DLL_FREQ_RANGE) #define V_BCM1480_MC_DLL_FREQ_RANGE_DEFAULT V_BCM1480_MC_DLL_FREQ_RANGE(0x4) #endif #define S_BCM1480_MC_DLL_STEP_SIZE 56 -#define M_BCM1480_MC_DLL_STEP_SIZE _SB_MAKEMASK(4,S_BCM1480_MC_DLL_STEP_SIZE) -#define V_BCM1480_MC_DLL_STEP_SIZE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DLL_STEP_SIZE) -#define G_BCM1480_MC_DLL_STEP_SIZE(x) _SB_GETVALUE(x,S_BCM1480_MC_DLL_STEP_SIZE,M_BCM1480_MC_DLL_STEP_SIZE) +#define M_BCM1480_MC_DLL_STEP_SIZE _SB_MAKEMASK(4, S_BCM1480_MC_DLL_STEP_SIZE) +#define V_BCM1480_MC_DLL_STEP_SIZE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DLL_STEP_SIZE) +#define G_BCM1480_MC_DLL_STEP_SIZE(x) _SB_GETVALUE(x, S_BCM1480_MC_DLL_STEP_SIZE, M_BCM1480_MC_DLL_STEP_SIZE) #define V_BCM1480_MC_DLL_STEP_SIZE_DEFAULT V_BCM1480_MC_DLL_STEP_SIZE(0x8) #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_DLL_BGCTRL 60 -#define M_BCM1480_MC_DLL_BGCTRL _SB_MAKEMASK(2,S_BCM1480_MC_DLL_BGCTRL) -#define V_BCM1480_MC_DLL_BGCTRL(x) _SB_MAKEVALUE(x,S_BCM1480_MC_DLL_BGCTRL) -#define G_BCM1480_MC_DLL_BGCTRL(x) _SB_GETVALUE(x,S_BCM1480_MC_DLL_BGCTRL,M_BCM1480_MC_DLL_BGCTRL) +#define M_BCM1480_MC_DLL_BGCTRL _SB_MAKEMASK(2, S_BCM1480_MC_DLL_BGCTRL) +#define V_BCM1480_MC_DLL_BGCTRL(x) _SB_MAKEVALUE(x, S_BCM1480_MC_DLL_BGCTRL) +#define G_BCM1480_MC_DLL_BGCTRL(x) _SB_GETVALUE(x, S_BCM1480_MC_DLL_BGCTRL, M_BCM1480_MC_DLL_BGCTRL) #define V_BCM1480_MC_DLL_DEFAULT_BGCTRL V_BCM1480_MC_DLL_BGCTRL(0x0) #endif @@ -653,37 +653,37 @@ */ #define S_BCM1480_MC_RTT_BYP_PULLDOWN 0 -#define M_BCM1480_MC_RTT_BYP_PULLDOWN _SB_MAKEMASK(3,S_BCM1480_MC_RTT_BYP_PULLDOWN) -#define V_BCM1480_MC_RTT_BYP_PULLDOWN(x) _SB_MAKEVALUE(x,S_BCM1480_MC_RTT_BYP_PULLDOWN) -#define G_BCM1480_MC_RTT_BYP_PULLDOWN(x) _SB_GETVALUE(x,S_BCM1480_MC_RTT_BYP_PULLDOWN,M_BCM1480_MC_RTT_BYP_PULLDOWN) +#define M_BCM1480_MC_RTT_BYP_PULLDOWN _SB_MAKEMASK(3, S_BCM1480_MC_RTT_BYP_PULLDOWN) +#define V_BCM1480_MC_RTT_BYP_PULLDOWN(x) _SB_MAKEVALUE(x, S_BCM1480_MC_RTT_BYP_PULLDOWN) +#define G_BCM1480_MC_RTT_BYP_PULLDOWN(x) _SB_GETVALUE(x, S_BCM1480_MC_RTT_BYP_PULLDOWN, M_BCM1480_MC_RTT_BYP_PULLDOWN) #define S_BCM1480_MC_RTT_BYP_PULLUP 6 -#define M_BCM1480_MC_RTT_BYP_PULLUP _SB_MAKEMASK(3,S_BCM1480_MC_RTT_BYP_PULLUP) -#define V_BCM1480_MC_RTT_BYP_PULLUP(x) _SB_MAKEVALUE(x,S_BCM1480_MC_RTT_BYP_PULLUP) -#define G_BCM1480_MC_RTT_BYP_PULLUP(x) _SB_GETVALUE(x,S_BCM1480_MC_RTT_BYP_PULLUP,M_BCM1480_MC_RTT_BYP_PULLUP) +#define M_BCM1480_MC_RTT_BYP_PULLUP _SB_MAKEMASK(3, S_BCM1480_MC_RTT_BYP_PULLUP) +#define V_BCM1480_MC_RTT_BYP_PULLUP(x) _SB_MAKEVALUE(x, S_BCM1480_MC_RTT_BYP_PULLUP) +#define G_BCM1480_MC_RTT_BYP_PULLUP(x) _SB_GETVALUE(x, S_BCM1480_MC_RTT_BYP_PULLUP, M_BCM1480_MC_RTT_BYP_PULLUP) #define M_BCM1480_MC_RTT_BYPASS _SB_MAKEMASK1(8) #define M_BCM1480_MC_RTT_COMP_MOV_AVG _SB_MAKEMASK1(9) #define S_BCM1480_MC_PVT_BYP_C1_PULLDOWN 10 -#define M_BCM1480_MC_PVT_BYP_C1_PULLDOWN _SB_MAKEMASK(4,S_BCM1480_MC_PVT_BYP_C1_PULLDOWN) -#define V_BCM1480_MC_PVT_BYP_C1_PULLDOWN(x) _SB_MAKEVALUE(x,S_BCM1480_MC_PVT_BYP_C1_PULLDOWN) -#define G_BCM1480_MC_PVT_BYP_C1_PULLDOWN(x) _SB_GETVALUE(x,S_BCM1480_MC_PVT_BYP_C1_PULLDOWN,M_BCM1480_MC_PVT_BYP_C1_PULLDOWN) +#define M_BCM1480_MC_PVT_BYP_C1_PULLDOWN _SB_MAKEMASK(4, S_BCM1480_MC_PVT_BYP_C1_PULLDOWN) +#define V_BCM1480_MC_PVT_BYP_C1_PULLDOWN(x) _SB_MAKEVALUE(x, S_BCM1480_MC_PVT_BYP_C1_PULLDOWN) +#define G_BCM1480_MC_PVT_BYP_C1_PULLDOWN(x) _SB_GETVALUE(x, S_BCM1480_MC_PVT_BYP_C1_PULLDOWN, M_BCM1480_MC_PVT_BYP_C1_PULLDOWN) #define S_BCM1480_MC_PVT_BYP_C1_PULLUP 15 -#define M_BCM1480_MC_PVT_BYP_C1_PULLUP _SB_MAKEMASK(4,S_BCM1480_MC_PVT_BYP_C1_PULLUP) -#define V_BCM1480_MC_PVT_BYP_C1_PULLUP(x) _SB_MAKEVALUE(x,S_BCM1480_MC_PVT_BYP_C1_PULLUP) -#define G_BCM1480_MC_PVT_BYP_C1_PULLUP(x) _SB_GETVALUE(x,S_BCM1480_MC_PVT_BYP_C1_PULLUP,M_BCM1480_MC_PVT_BYP_C1_PULLUP) +#define M_BCM1480_MC_PVT_BYP_C1_PULLUP _SB_MAKEMASK(4, S_BCM1480_MC_PVT_BYP_C1_PULLUP) +#define V_BCM1480_MC_PVT_BYP_C1_PULLUP(x) _SB_MAKEVALUE(x, S_BCM1480_MC_PVT_BYP_C1_PULLUP) +#define G_BCM1480_MC_PVT_BYP_C1_PULLUP(x) _SB_GETVALUE(x, S_BCM1480_MC_PVT_BYP_C1_PULLUP, M_BCM1480_MC_PVT_BYP_C1_PULLUP) #define S_BCM1480_MC_PVT_BYP_C2_PULLDOWN 20 -#define M_BCM1480_MC_PVT_BYP_C2_PULLDOWN _SB_MAKEMASK(4,S_BCM1480_MC_PVT_BYP_C2_PULLDOWN) -#define V_BCM1480_MC_PVT_BYP_C2_PULLDOWN(x) _SB_MAKEVALUE(x,S_BCM1480_MC_PVT_BYP_C2_PULLDOWN) -#define G_BCM1480_MC_PVT_BYP_C2_PULLDOWN(x) _SB_GETVALUE(x,S_BCM1480_MC_PVT_BYP_C2_PULLDOWN,M_BCM1480_MC_PVT_BYP_C2_PULLDOWN) +#define M_BCM1480_MC_PVT_BYP_C2_PULLDOWN _SB_MAKEMASK(4, S_BCM1480_MC_PVT_BYP_C2_PULLDOWN) +#define V_BCM1480_MC_PVT_BYP_C2_PULLDOWN(x) _SB_MAKEVALUE(x, S_BCM1480_MC_PVT_BYP_C2_PULLDOWN) +#define G_BCM1480_MC_PVT_BYP_C2_PULLDOWN(x) _SB_GETVALUE(x, S_BCM1480_MC_PVT_BYP_C2_PULLDOWN, M_BCM1480_MC_PVT_BYP_C2_PULLDOWN) #define S_BCM1480_MC_PVT_BYP_C2_PULLUP 25 -#define M_BCM1480_MC_PVT_BYP_C2_PULLUP _SB_MAKEMASK(4,S_BCM1480_MC_PVT_BYP_C2_PULLUP) -#define V_BCM1480_MC_PVT_BYP_C2_PULLUP(x) _SB_MAKEVALUE(x,S_BCM1480_MC_PVT_BYP_C2_PULLUP) -#define G_BCM1480_MC_PVT_BYP_C2_PULLUP(x) _SB_GETVALUE(x,S_BCM1480_MC_PVT_BYP_C2_PULLUP,M_BCM1480_MC_PVT_BYP_C2_PULLUP) +#define M_BCM1480_MC_PVT_BYP_C2_PULLUP _SB_MAKEMASK(4, S_BCM1480_MC_PVT_BYP_C2_PULLUP) +#define V_BCM1480_MC_PVT_BYP_C2_PULLUP(x) _SB_MAKEVALUE(x, S_BCM1480_MC_PVT_BYP_C2_PULLUP) +#define G_BCM1480_MC_PVT_BYP_C2_PULLUP(x) _SB_GETVALUE(x, S_BCM1480_MC_PVT_BYP_C2_PULLUP, M_BCM1480_MC_PVT_BYP_C2_PULLUP) #define M_BCM1480_MC_PVT_BYPASS _SB_MAKEMASK1(30) #define M_BCM1480_MC_PVT_COMP_MOV_AVG _SB_MAKEMASK1(31) @@ -703,111 +703,111 @@ */ #define S_BCM1480_MC_DATA_INVERT 0 -#define M_DATA_ECC_INVERT _SB_MAKEMASK(64,S_BCM1480_MC_ECC_INVERT) +#define M_DATA_ECC_INVERT _SB_MAKEMASK(64, S_BCM1480_MC_ECC_INVERT) /* * ECC Test ECC Register (Table 96) */ #define S_BCM1480_MC_ECC_INVERT 0 -#define M_BCM1480_MC_ECC_INVERT _SB_MAKEMASK(8,S_BCM1480_MC_ECC_INVERT) +#define M_BCM1480_MC_ECC_INVERT _SB_MAKEMASK(8, S_BCM1480_MC_ECC_INVERT) /* * SDRAM Timing Register (Table 97) */ #define S_BCM1480_MC_tRCD 0 -#define M_BCM1480_MC_tRCD _SB_MAKEMASK(4,S_BCM1480_MC_tRCD) -#define V_BCM1480_MC_tRCD(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tRCD) -#define G_BCM1480_MC_tRCD(x) _SB_GETVALUE(x,S_BCM1480_MC_tRCD,M_BCM1480_MC_tRCD) +#define M_BCM1480_MC_tRCD _SB_MAKEMASK(4, S_BCM1480_MC_tRCD) +#define V_BCM1480_MC_tRCD(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tRCD) +#define G_BCM1480_MC_tRCD(x) _SB_GETVALUE(x, S_BCM1480_MC_tRCD, M_BCM1480_MC_tRCD) #define K_BCM1480_MC_tRCD_DEFAULT 3 #define V_BCM1480_MC_tRCD_DEFAULT V_BCM1480_MC_tRCD(K_BCM1480_MC_tRCD_DEFAULT) #define S_BCM1480_MC_tCL 4 -#define M_BCM1480_MC_tCL _SB_MAKEMASK(4,S_BCM1480_MC_tCL) -#define V_BCM1480_MC_tCL(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tCL) -#define G_BCM1480_MC_tCL(x) _SB_GETVALUE(x,S_BCM1480_MC_tCL,M_BCM1480_MC_tCL) +#define M_BCM1480_MC_tCL _SB_MAKEMASK(4, S_BCM1480_MC_tCL) +#define V_BCM1480_MC_tCL(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tCL) +#define G_BCM1480_MC_tCL(x) _SB_GETVALUE(x, S_BCM1480_MC_tCL, M_BCM1480_MC_tCL) #define K_BCM1480_MC_tCL_DEFAULT 2 #define V_BCM1480_MC_tCL_DEFAULT V_BCM1480_MC_tCL(K_BCM1480_MC_tCL_DEFAULT) #define M_BCM1480_MC_tCrDh _SB_MAKEMASK1(8) #define S_BCM1480_MC_tWR 9 -#define M_BCM1480_MC_tWR _SB_MAKEMASK(3,S_BCM1480_MC_tWR) -#define V_BCM1480_MC_tWR(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tWR) -#define G_BCM1480_MC_tWR(x) _SB_GETVALUE(x,S_BCM1480_MC_tWR,M_BCM1480_MC_tWR) +#define M_BCM1480_MC_tWR _SB_MAKEMASK(3, S_BCM1480_MC_tWR) +#define V_BCM1480_MC_tWR(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tWR) +#define G_BCM1480_MC_tWR(x) _SB_GETVALUE(x, S_BCM1480_MC_tWR, M_BCM1480_MC_tWR) #define K_BCM1480_MC_tWR_DEFAULT 2 #define V_BCM1480_MC_tWR_DEFAULT V_BCM1480_MC_tWR(K_BCM1480_MC_tWR_DEFAULT) #define S_BCM1480_MC_tCwD 12 -#define M_BCM1480_MC_tCwD _SB_MAKEMASK(4,S_BCM1480_MC_tCwD) -#define V_BCM1480_MC_tCwD(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tCwD) -#define G_BCM1480_MC_tCwD(x) _SB_GETVALUE(x,S_BCM1480_MC_tCwD,M_BCM1480_MC_tCwD) +#define M_BCM1480_MC_tCwD _SB_MAKEMASK(4, S_BCM1480_MC_tCwD) +#define V_BCM1480_MC_tCwD(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tCwD) +#define G_BCM1480_MC_tCwD(x) _SB_GETVALUE(x, S_BCM1480_MC_tCwD, M_BCM1480_MC_tCwD) #define K_BCM1480_MC_tCwD_DEFAULT 1 #define V_BCM1480_MC_tCwD_DEFAULT V_BCM1480_MC_tCwD(K_BCM1480_MC_tCwD_DEFAULT) #define S_BCM1480_MC_tRP 16 -#define M_BCM1480_MC_tRP _SB_MAKEMASK(4,S_BCM1480_MC_tRP) -#define V_BCM1480_MC_tRP(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tRP) -#define G_BCM1480_MC_tRP(x) _SB_GETVALUE(x,S_BCM1480_MC_tRP,M_BCM1480_MC_tRP) +#define M_BCM1480_MC_tRP _SB_MAKEMASK(4, S_BCM1480_MC_tRP) +#define V_BCM1480_MC_tRP(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tRP) +#define G_BCM1480_MC_tRP(x) _SB_GETVALUE(x, S_BCM1480_MC_tRP, M_BCM1480_MC_tRP) #define K_BCM1480_MC_tRP_DEFAULT 4 #define V_BCM1480_MC_tRP_DEFAULT V_BCM1480_MC_tRP(K_BCM1480_MC_tRP_DEFAULT) #define S_BCM1480_MC_tRRD 20 -#define M_BCM1480_MC_tRRD _SB_MAKEMASK(4,S_BCM1480_MC_tRRD) -#define V_BCM1480_MC_tRRD(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tRRD) -#define G_BCM1480_MC_tRRD(x) _SB_GETVALUE(x,S_BCM1480_MC_tRRD,M_BCM1480_MC_tRRD) +#define M_BCM1480_MC_tRRD _SB_MAKEMASK(4, S_BCM1480_MC_tRRD) +#define V_BCM1480_MC_tRRD(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tRRD) +#define G_BCM1480_MC_tRRD(x) _SB_GETVALUE(x, S_BCM1480_MC_tRRD, M_BCM1480_MC_tRRD) #define K_BCM1480_MC_tRRD_DEFAULT 2 #define V_BCM1480_MC_tRRD_DEFAULT V_BCM1480_MC_tRRD(K_BCM1480_MC_tRRD_DEFAULT) #define S_BCM1480_MC_tRCw 24 -#define M_BCM1480_MC_tRCw _SB_MAKEMASK(5,S_BCM1480_MC_tRCw) -#define V_BCM1480_MC_tRCw(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tRCw) -#define G_BCM1480_MC_tRCw(x) _SB_GETVALUE(x,S_BCM1480_MC_tRCw,M_BCM1480_MC_tRCw) +#define M_BCM1480_MC_tRCw _SB_MAKEMASK(5, S_BCM1480_MC_tRCw) +#define V_BCM1480_MC_tRCw(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tRCw) +#define G_BCM1480_MC_tRCw(x) _SB_GETVALUE(x, S_BCM1480_MC_tRCw, M_BCM1480_MC_tRCw) #define K_BCM1480_MC_tRCw_DEFAULT 10 #define V_BCM1480_MC_tRCw_DEFAULT V_BCM1480_MC_tRCw(K_BCM1480_MC_tRCw_DEFAULT) #define S_BCM1480_MC_tRCr 32 -#define M_BCM1480_MC_tRCr _SB_MAKEMASK(5,S_BCM1480_MC_tRCr) -#define V_BCM1480_MC_tRCr(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tRCr) -#define G_BCM1480_MC_tRCr(x) _SB_GETVALUE(x,S_BCM1480_MC_tRCr,M_BCM1480_MC_tRCr) +#define M_BCM1480_MC_tRCr _SB_MAKEMASK(5, S_BCM1480_MC_tRCr) +#define V_BCM1480_MC_tRCr(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tRCr) +#define G_BCM1480_MC_tRCr(x) _SB_GETVALUE(x, S_BCM1480_MC_tRCr, M_BCM1480_MC_tRCr) #define K_BCM1480_MC_tRCr_DEFAULT 9 #define V_BCM1480_MC_tRCr_DEFAULT V_BCM1480_MC_tRCr(K_BCM1480_MC_tRCr_DEFAULT) #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_tFAW 40 -#define M_BCM1480_MC_tFAW _SB_MAKEMASK(6,S_BCM1480_MC_tFAW) -#define V_BCM1480_MC_tFAW(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tFAW) -#define G_BCM1480_MC_tFAW(x) _SB_GETVALUE(x,S_BCM1480_MC_tFAW,M_BCM1480_MC_tFAW) +#define M_BCM1480_MC_tFAW _SB_MAKEMASK(6, S_BCM1480_MC_tFAW) +#define V_BCM1480_MC_tFAW(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tFAW) +#define G_BCM1480_MC_tFAW(x) _SB_GETVALUE(x, S_BCM1480_MC_tFAW, M_BCM1480_MC_tFAW) #define K_BCM1480_MC_tFAW_DEFAULT 0 #define V_BCM1480_MC_tFAW_DEFAULT V_BCM1480_MC_tFAW(K_BCM1480_MC_tFAW_DEFAULT) #endif #define S_BCM1480_MC_tRFC 48 -#define M_BCM1480_MC_tRFC _SB_MAKEMASK(7,S_BCM1480_MC_tRFC) -#define V_BCM1480_MC_tRFC(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tRFC) -#define G_BCM1480_MC_tRFC(x) _SB_GETVALUE(x,S_BCM1480_MC_tRFC,M_BCM1480_MC_tRFC) +#define M_BCM1480_MC_tRFC _SB_MAKEMASK(7, S_BCM1480_MC_tRFC) +#define V_BCM1480_MC_tRFC(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tRFC) +#define G_BCM1480_MC_tRFC(x) _SB_GETVALUE(x, S_BCM1480_MC_tRFC, M_BCM1480_MC_tRFC) #define K_BCM1480_MC_tRFC_DEFAULT 12 #define V_BCM1480_MC_tRFC_DEFAULT V_BCM1480_MC_tRFC(K_BCM1480_MC_tRFC_DEFAULT) #define S_BCM1480_MC_tFIFO 56 -#define M_BCM1480_MC_tFIFO _SB_MAKEMASK(2,S_BCM1480_MC_tFIFO) -#define V_BCM1480_MC_tFIFO(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tFIFO) -#define G_BCM1480_MC_tFIFO(x) _SB_GETVALUE(x,S_BCM1480_MC_tFIFO,M_BCM1480_MC_tFIFO) +#define M_BCM1480_MC_tFIFO _SB_MAKEMASK(2, S_BCM1480_MC_tFIFO) +#define V_BCM1480_MC_tFIFO(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tFIFO) +#define G_BCM1480_MC_tFIFO(x) _SB_GETVALUE(x, S_BCM1480_MC_tFIFO, M_BCM1480_MC_tFIFO) #define K_BCM1480_MC_tFIFO_DEFAULT 0 #define V_BCM1480_MC_tFIFO_DEFAULT V_BCM1480_MC_tFIFO(K_BCM1480_MC_tFIFO_DEFAULT) #define S_BCM1480_MC_tW2R 58 -#define M_BCM1480_MC_tW2R _SB_MAKEMASK(2,S_BCM1480_MC_tW2R) -#define V_BCM1480_MC_tW2R(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tW2R) -#define G_BCM1480_MC_tW2R(x) _SB_GETVALUE(x,S_BCM1480_MC_tW2R,M_BCM1480_MC_tW2R) +#define M_BCM1480_MC_tW2R _SB_MAKEMASK(2, S_BCM1480_MC_tW2R) +#define V_BCM1480_MC_tW2R(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tW2R) +#define G_BCM1480_MC_tW2R(x) _SB_GETVALUE(x, S_BCM1480_MC_tW2R, M_BCM1480_MC_tW2R) #define K_BCM1480_MC_tW2R_DEFAULT 1 #define V_BCM1480_MC_tW2R_DEFAULT V_BCM1480_MC_tW2R(K_BCM1480_MC_tW2R_DEFAULT) #define S_BCM1480_MC_tR2W 60 -#define M_BCM1480_MC_tR2W _SB_MAKEMASK(2,S_BCM1480_MC_tR2W) -#define V_BCM1480_MC_tR2W(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tR2W) -#define G_BCM1480_MC_tR2W(x) _SB_GETVALUE(x,S_BCM1480_MC_tR2W,M_BCM1480_MC_tR2W) +#define M_BCM1480_MC_tR2W _SB_MAKEMASK(2, S_BCM1480_MC_tR2W) +#define V_BCM1480_MC_tR2W(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tR2W) +#define G_BCM1480_MC_tR2W(x) _SB_GETVALUE(x, S_BCM1480_MC_tR2W, M_BCM1480_MC_tR2W) #define K_BCM1480_MC_tR2W_DEFAULT 0 #define V_BCM1480_MC_tR2W_DEFAULT V_BCM1480_MC_tR2W(K_BCM1480_MC_tR2W_DEFAULT) @@ -835,30 +835,30 @@ #if SIBYTE_HDR_FEATURE(1480, PASS2) #define S_BCM1480_MC_tAL 0 -#define M_BCM1480_MC_tAL _SB_MAKEMASK(4,S_BCM1480_MC_tAL) -#define V_BCM1480_MC_tAL(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tAL) -#define G_BCM1480_MC_tAL(x) _SB_GETVALUE(x,S_BCM1480_MC_tAL,M_BCM1480_MC_tAL) +#define M_BCM1480_MC_tAL _SB_MAKEMASK(4, S_BCM1480_MC_tAL) +#define V_BCM1480_MC_tAL(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tAL) +#define G_BCM1480_MC_tAL(x) _SB_GETVALUE(x, S_BCM1480_MC_tAL, M_BCM1480_MC_tAL) #define K_BCM1480_MC_tAL_DEFAULT 0 #define V_BCM1480_MC_tAL_DEFAULT V_BCM1480_MC_tAL(K_BCM1480_MC_tAL_DEFAULT) #define S_BCM1480_MC_tRTP 4 -#define M_BCM1480_MC_tRTP _SB_MAKEMASK(3,S_BCM1480_MC_tRTP) -#define V_BCM1480_MC_tRTP(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tRTP) -#define G_BCM1480_MC_tRTP(x) _SB_GETVALUE(x,S_BCM1480_MC_tRTP,M_BCM1480_MC_tRTP) +#define M_BCM1480_MC_tRTP _SB_MAKEMASK(3, S_BCM1480_MC_tRTP) +#define V_BCM1480_MC_tRTP(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tRTP) +#define G_BCM1480_MC_tRTP(x) _SB_GETVALUE(x, S_BCM1480_MC_tRTP, M_BCM1480_MC_tRTP) #define K_BCM1480_MC_tRTP_DEFAULT 2 #define V_BCM1480_MC_tRTP_DEFAULT V_BCM1480_MC_tRTP(K_BCM1480_MC_tRTP_DEFAULT) #define S_BCM1480_MC_tW2W 8 -#define M_BCM1480_MC_tW2W _SB_MAKEMASK(2,S_BCM1480_MC_tW2W) -#define V_BCM1480_MC_tW2W(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tW2W) -#define G_BCM1480_MC_tW2W(x) _SB_GETVALUE(x,S_BCM1480_MC_tW2W,M_BCM1480_MC_tW2W) +#define M_BCM1480_MC_tW2W _SB_MAKEMASK(2, S_BCM1480_MC_tW2W) +#define V_BCM1480_MC_tW2W(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tW2W) +#define G_BCM1480_MC_tW2W(x) _SB_GETVALUE(x, S_BCM1480_MC_tW2W, M_BCM1480_MC_tW2W) #define K_BCM1480_MC_tW2W_DEFAULT 0 #define V_BCM1480_MC_tW2W_DEFAULT V_BCM1480_MC_tW2W(K_BCM1480_MC_tW2W_DEFAULT) #define S_BCM1480_MC_tRAP 12 -#define M_BCM1480_MC_tRAP _SB_MAKEMASK(4,S_BCM1480_MC_tRAP) -#define V_BCM1480_MC_tRAP(x) _SB_MAKEVALUE(x,S_BCM1480_MC_tRAP) -#define G_BCM1480_MC_tRAP(x) _SB_GETVALUE(x,S_BCM1480_MC_tRAP,M_BCM1480_MC_tRAP) +#define M_BCM1480_MC_tRAP _SB_MAKEMASK(4, S_BCM1480_MC_tRAP) +#define V_BCM1480_MC_tRAP(x) _SB_MAKEVALUE(x, S_BCM1480_MC_tRAP) +#define G_BCM1480_MC_tRAP(x) _SB_GETVALUE(x, S_BCM1480_MC_tRAP, M_BCM1480_MC_tRAP) #define K_BCM1480_MC_tRAP_DEFAULT 0 #define V_BCM1480_MC_tRAP_DEFAULT V_BCM1480_MC_tRAP(K_BCM1480_MC_tRAP_DEFAULT) @@ -875,30 +875,30 @@ */ #define S_BCM1480_MC_BLK_SET_MARK 8 -#define M_BCM1480_MC_BLK_SET_MARK _SB_MAKEMASK(4,S_BCM1480_MC_BLK_SET_MARK) -#define V_BCM1480_MC_BLK_SET_MARK(x) _SB_MAKEVALUE(x,S_BCM1480_MC_BLK_SET_MARK) -#define G_BCM1480_MC_BLK_SET_MARK(x) _SB_GETVALUE(x,S_BCM1480_MC_BLK_SET_MARK,M_BCM1480_MC_BLK_SET_MARK) +#define M_BCM1480_MC_BLK_SET_MARK _SB_MAKEMASK(4, S_BCM1480_MC_BLK_SET_MARK) +#define V_BCM1480_MC_BLK_SET_MARK(x) _SB_MAKEVALUE(x, S_BCM1480_MC_BLK_SET_MARK) +#define G_BCM1480_MC_BLK_SET_MARK(x) _SB_GETVALUE(x, S_BCM1480_MC_BLK_SET_MARK, M_BCM1480_MC_BLK_SET_MARK) #define S_BCM1480_MC_BLK_CLR_MARK 12 -#define M_BCM1480_MC_BLK_CLR_MARK _SB_MAKEMASK(4,S_BCM1480_MC_BLK_CLR_MARK) -#define V_BCM1480_MC_BLK_CLR_MARK(x) _SB_MAKEVALUE(x,S_BCM1480_MC_BLK_CLR_MARK) -#define G_BCM1480_MC_BLK_CLR_MARK(x) _SB_GETVALUE(x,S_BCM1480_MC_BLK_CLR_MARK,M_BCM1480_MC_BLK_CLR_MARK) +#define M_BCM1480_MC_BLK_CLR_MARK _SB_MAKEMASK(4, S_BCM1480_MC_BLK_CLR_MARK) +#define V_BCM1480_MC_BLK_CLR_MARK(x) _SB_MAKEVALUE(x, S_BCM1480_MC_BLK_CLR_MARK) +#define G_BCM1480_MC_BLK_CLR_MARK(x) _SB_GETVALUE(x, S_BCM1480_MC_BLK_CLR_MARK, M_BCM1480_MC_BLK_CLR_MARK) #define M_BCM1480_MC_PKT_PRIORITY _SB_MAKEMASK1(16) #define S_BCM1480_MC_MAX_AGE 20 -#define M_BCM1480_MC_MAX_AGE _SB_MAKEMASK(4,S_BCM1480_MC_MAX_AGE) -#define V_BCM1480_MC_MAX_AGE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_MAX_AGE) -#define G_BCM1480_MC_MAX_AGE(x) _SB_GETVALUE(x,S_BCM1480_MC_MAX_AGE,M_BCM1480_MC_MAX_AGE) +#define M_BCM1480_MC_MAX_AGE _SB_MAKEMASK(4, S_BCM1480_MC_MAX_AGE) +#define V_BCM1480_MC_MAX_AGE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_MAX_AGE) +#define G_BCM1480_MC_MAX_AGE(x) _SB_GETVALUE(x, S_BCM1480_MC_MAX_AGE, M_BCM1480_MC_MAX_AGE) #define M_BCM1480_MC_BERR_DISABLE _SB_MAKEMASK1(29) #define M_BCM1480_MC_FORCE_SEQ _SB_MAKEMASK1(30) #define M_BCM1480_MC_VGEN _SB_MAKEMASK1(32) #define S_BCM1480_MC_SLEW 33 -#define M_BCM1480_MC_SLEW _SB_MAKEMASK(2,S_BCM1480_MC_SLEW) -#define V_BCM1480_MC_SLEW(x) _SB_MAKEVALUE(x,S_BCM1480_MC_SLEW) -#define G_BCM1480_MC_SLEW(x) _SB_GETVALUE(x,S_BCM1480_MC_SLEW,M_BCM1480_MC_SLEW) +#define M_BCM1480_MC_SLEW _SB_MAKEMASK(2, S_BCM1480_MC_SLEW) +#define V_BCM1480_MC_SLEW(x) _SB_MAKEVALUE(x, S_BCM1480_MC_SLEW) +#define G_BCM1480_MC_SLEW(x) _SB_GETVALUE(x, S_BCM1480_MC_SLEW, M_BCM1480_MC_SLEW) #define M_BCM1480_MC_SSTL_VOLTAGE _SB_MAKEMASK1(35) @@ -907,19 +907,19 @@ */ #define S_BCM1480_MC_INTLV0 0 -#define M_BCM1480_MC_INTLV0 _SB_MAKEMASK(6,S_BCM1480_MC_INTLV0) -#define V_BCM1480_MC_INTLV0(x) _SB_MAKEVALUE(x,S_BCM1480_MC_INTLV0) -#define G_BCM1480_MC_INTLV0(x) _SB_GETVALUE(x,S_BCM1480_MC_INTLV0,M_BCM1480_MC_INTLV0) +#define M_BCM1480_MC_INTLV0 _SB_MAKEMASK(6, S_BCM1480_MC_INTLV0) +#define V_BCM1480_MC_INTLV0(x) _SB_MAKEVALUE(x, S_BCM1480_MC_INTLV0) +#define G_BCM1480_MC_INTLV0(x) _SB_GETVALUE(x, S_BCM1480_MC_INTLV0, M_BCM1480_MC_INTLV0) #define S_BCM1480_MC_INTLV1 8 -#define M_BCM1480_MC_INTLV1 _SB_MAKEMASK(6,S_BCM1480_MC_INTLV1) -#define V_BCM1480_MC_INTLV1(x) _SB_MAKEVALUE(x,S_BCM1480_MC_INTLV1) -#define G_BCM1480_MC_INTLV1(x) _SB_GETVALUE(x,S_BCM1480_MC_INTLV1,M_BCM1480_MC_INTLV1) +#define M_BCM1480_MC_INTLV1 _SB_MAKEMASK(6, S_BCM1480_MC_INTLV1) +#define V_BCM1480_MC_INTLV1(x) _SB_MAKEVALUE(x, S_BCM1480_MC_INTLV1) +#define G_BCM1480_MC_INTLV1(x) _SB_GETVALUE(x, S_BCM1480_MC_INTLV1, M_BCM1480_MC_INTLV1) #define S_BCM1480_MC_INTLV_MODE 16 -#define M_BCM1480_MC_INTLV_MODE _SB_MAKEMASK(3,S_BCM1480_MC_INTLV_MODE) -#define V_BCM1480_MC_INTLV_MODE(x) _SB_MAKEVALUE(x,S_BCM1480_MC_INTLV_MODE) -#define G_BCM1480_MC_INTLV_MODE(x) _SB_GETVALUE(x,S_BCM1480_MC_INTLV_MODE,M_BCM1480_MC_INTLV_MODE) +#define M_BCM1480_MC_INTLV_MODE _SB_MAKEMASK(3, S_BCM1480_MC_INTLV_MODE) +#define V_BCM1480_MC_INTLV_MODE(x) _SB_MAKEVALUE(x, S_BCM1480_MC_INTLV_MODE) +#define G_BCM1480_MC_INTLV_MODE(x) _SB_GETVALUE(x, S_BCM1480_MC_INTLV_MODE, M_BCM1480_MC_INTLV_MODE) #define K_BCM1480_MC_INTLV_MODE_NONE 0x0 #define K_BCM1480_MC_INTLV_MODE_01 0x1 @@ -938,9 +938,9 @@ */ #define S_BCM1480_MC_ECC_ERR_ADDR 0 -#define M_BCM1480_MC_ECC_ERR_ADDR _SB_MAKEMASK(37,S_BCM1480_MC_ECC_ERR_ADDR) -#define V_BCM1480_MC_ECC_ERR_ADDR(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ECC_ERR_ADDR) -#define G_BCM1480_MC_ECC_ERR_ADDR(x) _SB_GETVALUE(x,S_BCM1480_MC_ECC_ERR_ADDR,M_BCM1480_MC_ECC_ERR_ADDR) +#define M_BCM1480_MC_ECC_ERR_ADDR _SB_MAKEMASK(37, S_BCM1480_MC_ECC_ERR_ADDR) +#define V_BCM1480_MC_ECC_ERR_ADDR(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ECC_ERR_ADDR) +#define G_BCM1480_MC_ECC_ERR_ADDR(x) _SB_GETVALUE(x, S_BCM1480_MC_ECC_ERR_ADDR, M_BCM1480_MC_ECC_ERR_ADDR) #if SIBYTE_HDR_FEATURE(1480, PASS2) #define M_BCM1480_MC_ECC_ERR_RMW _SB_MAKEMASK1(60) @@ -955,27 +955,27 @@ */ #define S_BCM1480_MC_ECC_CORR_ADDR 0 -#define M_BCM1480_MC_ECC_CORR_ADDR _SB_MAKEMASK(37,S_BCM1480_MC_ECC_CORR_ADDR) -#define V_BCM1480_MC_ECC_CORR_ADDR(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ECC_CORR_ADDR) -#define G_BCM1480_MC_ECC_CORR_ADDR(x) _SB_GETVALUE(x,S_BCM1480_MC_ECC_CORR_ADDR,M_BCM1480_MC_ECC_CORR_ADDR) +#define M_BCM1480_MC_ECC_CORR_ADDR _SB_MAKEMASK(37, S_BCM1480_MC_ECC_CORR_ADDR) +#define V_BCM1480_MC_ECC_CORR_ADDR(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ECC_CORR_ADDR) +#define G_BCM1480_MC_ECC_CORR_ADDR(x) _SB_GETVALUE(x, S_BCM1480_MC_ECC_CORR_ADDR, M_BCM1480_MC_ECC_CORR_ADDR) /* * Global ECC Correction Register (Table 103) */ #define S_BCM1480_MC_ECC_CORRECT 0 -#define M_BCM1480_MC_ECC_CORRECT _SB_MAKEMASK(64,S_BCM1480_MC_ECC_CORRECT) -#define V_BCM1480_MC_ECC_CORRECT(x) _SB_MAKEVALUE(x,S_BCM1480_MC_ECC_CORRECT) -#define G_BCM1480_MC_ECC_CORRECT(x) _SB_GETVALUE(x,S_BCM1480_MC_ECC_CORRECT,M_BCM1480_MC_ECC_CORRECT) +#define M_BCM1480_MC_ECC_CORRECT _SB_MAKEMASK(64, S_BCM1480_MC_ECC_CORRECT) +#define V_BCM1480_MC_ECC_CORRECT(x) _SB_MAKEVALUE(x, S_BCM1480_MC_ECC_CORRECT) +#define G_BCM1480_MC_ECC_CORRECT(x) _SB_GETVALUE(x, S_BCM1480_MC_ECC_CORRECT, M_BCM1480_MC_ECC_CORRECT) /* * Global ECC Performance Counters Control Register (Table 104) */ #define S_BCM1480_MC_CHANNEL_SELECT 0 -#define M_BCM1480_MC_CHANNEL_SELECT _SB_MAKEMASK(4,S_BCM1480_MC_CHANNEL_SELECT) -#define V_BCM1480_MC_CHANNEL_SELECT(x) _SB_MAKEVALUE(x,S_BCM1480_MC_CHANNEL_SELECT) -#define G_BCM1480_MC_CHANNEL_SELECT(x) _SB_GETVALUE(x,S_BCM1480_MC_CHANNEL_SELECT,M_BCM1480_MC_CHANNEL_SELECT) +#define M_BCM1480_MC_CHANNEL_SELECT _SB_MAKEMASK(4, S_BCM1480_MC_CHANNEL_SELECT) +#define V_BCM1480_MC_CHANNEL_SELECT(x) _SB_MAKEVALUE(x, S_BCM1480_MC_CHANNEL_SELECT) +#define G_BCM1480_MC_CHANNEL_SELECT(x) _SB_GETVALUE(x, S_BCM1480_MC_CHANNEL_SELECT, M_BCM1480_MC_CHANNEL_SELECT) #define K_BCM1480_MC_CHANNEL_SELECT_0 0x1 #define K_BCM1480_MC_CHANNEL_SELECT_1 0x2 #define K_BCM1480_MC_CHANNEL_SELECT_2 0x4 diff --git a/include/asm-mips/sibyte/bcm1480_regs.h b/include/asm-mips/sibyte/bcm1480_regs.h index c34d36b6b8c2..b4077bb72611 100644 --- a/include/asm-mips/sibyte/bcm1480_regs.h +++ b/include/asm-mips/sibyte/bcm1480_regs.h @@ -87,7 +87,7 @@ #define BCM1480_MC_REGISTER_SPACING 0x1000 #define A_BCM1480_MC_BASE(ctlid) (A_BCM1480_MC_BASE_0+(ctlid)*BCM1480_MC_REGISTER_SPACING) -#define A_BCM1480_MC_REGISTER(ctlid,reg) (A_BCM1480_MC_BASE(ctlid)+(reg)) +#define A_BCM1480_MC_REGISTER(ctlid, reg) (A_BCM1480_MC_BASE(ctlid)+(reg)) #define R_BCM1480_MC_CONFIG 0x0000000100 #define R_BCM1480_MC_CS_START 0x0000000120 @@ -327,7 +327,7 @@ #define BCM1480_SCD_NUM_WDOGS 4 #define A_BCM1480_SCD_WDOG_BASE(w) (A_BCM1480_SCD_WDOG_0+((w)&2)*0x1000 + ((w)&1)*0x100) -#define A_BCM1480_SCD_WDOG_REGISTER(w,r) (A_BCM1480_SCD_WDOG_BASE(w) + (r)) +#define A_BCM1480_SCD_WDOG_REGISTER(w, r) (A_BCM1480_SCD_WDOG_BASE(w) + (r)) #define A_BCM1480_SCD_WDOG_INIT_2 0x0010022050 #define A_BCM1480_SCD_WDOG_CNT_2 0x0010022058 @@ -372,7 +372,7 @@ #define BCM1480_IMR_REGISTER_SPACING_SHIFT 13 #define A_BCM1480_IMR_MAPPER(cpu) (A_BCM1480_IMR_CPU0_BASE+(cpu)*BCM1480_IMR_REGISTER_SPACING) -#define A_BCM1480_IMR_REGISTER(cpu,reg) (A_BCM1480_IMR_MAPPER(cpu)+(reg)) +#define A_BCM1480_IMR_REGISTER(cpu, reg) (A_BCM1480_IMR_MAPPER(cpu)+(reg)) /* Most IMR registers are 128 bits, implemented as non-contiguous 64-bit registers high (_H) and low (_L) */ @@ -413,7 +413,7 @@ #define A_BCM1480_IMR_ALIAS_MAILBOX(cpu) (A_BCM1480_IMR_ALIAS_MAILBOX_CPU0_BASE + \ (cpu)*BCM1480_IMR_ALIAS_MAILBOX_SPACING) -#define A_BCM1480_IMR_ALIAS_MAILBOX_REGISTER(cpu,reg) (A_BCM1480_IMR_ALIAS_MAILBOX(cpu)+(reg)) +#define A_BCM1480_IMR_ALIAS_MAILBOX_REGISTER(cpu, reg) (A_BCM1480_IMR_ALIAS_MAILBOX(cpu)+(reg)) #define R_BCM1480_IMR_ALIAS_MAILBOX_0 0x0000 /* 0x0x0 */ #define R_BCM1480_IMR_ALIAS_MAILBOX_0_SET 0x0008 /* 0x0x8 */ @@ -427,7 +427,7 @@ #define R_BCM1480_IMR_MAILBOX_SET 0x08 #define R_BCM1480_IMR_MAILBOX_CLR 0x10 #define R_BCM1480_IMR_MAILBOX_NUM_SPACING 0x20 -#define A_BCM1480_MAILBOX_REGISTER(num,reg,cpu) \ +#define A_BCM1480_MAILBOX_REGISTER(num, reg, cpu) \ (A_BCM1480_IMR_CPU0_BASE + \ (num * R_BCM1480_IMR_MAILBOX_NUM_SPACING) + \ (cpu * BCM1480_IMR_REGISTER_SPACING) + \ @@ -550,7 +550,7 @@ #define BCM1480_HR_REGISTER_SPACING 0x80000 #define A_BCM1480_HR_BASE(idx) (A_BCM1480_HR_BASE_0 + ((idx)*BCM1480_HR_REGISTER_SPACING)) -#define A_BCM1480_HR_REGISTER(idx,reg) (A_BCM1480_HR_BASE(idx) + (reg)) +#define A_BCM1480_HR_REGISTER(idx, reg) (A_BCM1480_HR_BASE(idx) + (reg)) #define R_BCM1480_HR_CFG 0x0000000000 @@ -599,9 +599,9 @@ #define BCM1480_PM_NUM_CHANNELS 32 #define A_BCM1480_PMI_LCL_BASE(idx) (A_BCM1480_PMI_LCL_0 + ((idx)*BCM1480_PM_LCL_REGISTER_SPACING)) -#define A_BCM1480_PMI_LCL_REGISTER(idx,reg) (A_BCM1480_PMI_LCL_BASE(idx) + (reg)) +#define A_BCM1480_PMI_LCL_REGISTER(idx, reg) (A_BCM1480_PMI_LCL_BASE(idx) + (reg)) #define A_BCM1480_PMO_LCL_BASE(idx) (A_BCM1480_PMO_LCL_0 + ((idx)*BCM1480_PM_LCL_REGISTER_SPACING)) -#define A_BCM1480_PMO_LCL_REGISTER(idx,reg) (A_BCM1480_PMO_LCL_BASE(idx) + (reg)) +#define A_BCM1480_PMO_LCL_REGISTER(idx, reg) (A_BCM1480_PMO_LCL_BASE(idx) + (reg)) #define BCM1480_PM_INT_PACKING 8 #define BCM1480_PM_INT_FUNCTION_SPACING 0x40 @@ -721,7 +721,7 @@ #define BCM1480_HSP_REGISTER_SPACING 0x80000 #define A_BCM1480_HSP_BASE(idx) (A_BCM1480_HSP_BASE_0 + ((idx)*BCM1480_HSP_REGISTER_SPACING)) -#define A_BCM1480_HSP_REGISTER(idx,reg) (A_BCM1480_HSP_BASE(idx) + (reg)) +#define A_BCM1480_HSP_REGISTER(idx, reg) (A_BCM1480_HSP_BASE(idx) + (reg)) #define R_BCM1480_HSP_RX_SPI4_CFG_0 0x0000000000 #define R_BCM1480_HSP_RX_SPI4_CFG_1 0x0000000008 diff --git a/include/asm-mips/sibyte/bcm1480_scd.h b/include/asm-mips/sibyte/bcm1480_scd.h index 6111d6dcf117..25ef24cbb92a 100644 --- a/include/asm-mips/sibyte/bcm1480_scd.h +++ b/include/asm-mips/sibyte/bcm1480_scd.h @@ -99,22 +99,22 @@ #define M_BCM1480_SYS_IOB_DIV _SB_MAKEMASK1(5) #define S_BCM1480_SYS_PLL_DIV _SB_MAKE64(6) -#define M_BCM1480_SYS_PLL_DIV _SB_MAKEMASK(5,S_BCM1480_SYS_PLL_DIV) -#define V_BCM1480_SYS_PLL_DIV(x) _SB_MAKEVALUE(x,S_BCM1480_SYS_PLL_DIV) -#define G_BCM1480_SYS_PLL_DIV(x) _SB_GETVALUE(x,S_BCM1480_SYS_PLL_DIV,M_BCM1480_SYS_PLL_DIV) +#define M_BCM1480_SYS_PLL_DIV _SB_MAKEMASK(5, S_BCM1480_SYS_PLL_DIV) +#define V_BCM1480_SYS_PLL_DIV(x) _SB_MAKEVALUE(x, S_BCM1480_SYS_PLL_DIV) +#define G_BCM1480_SYS_PLL_DIV(x) _SB_GETVALUE(x, S_BCM1480_SYS_PLL_DIV, M_BCM1480_SYS_PLL_DIV) #define S_BCM1480_SYS_SW_DIV _SB_MAKE64(11) -#define M_BCM1480_SYS_SW_DIV _SB_MAKEMASK(5,S_BCM1480_SYS_SW_DIV) -#define V_BCM1480_SYS_SW_DIV(x) _SB_MAKEVALUE(x,S_BCM1480_SYS_SW_DIV) -#define G_BCM1480_SYS_SW_DIV(x) _SB_GETVALUE(x,S_BCM1480_SYS_SW_DIV,M_BCM1480_SYS_SW_DIV) +#define M_BCM1480_SYS_SW_DIV _SB_MAKEMASK(5, S_BCM1480_SYS_SW_DIV) +#define V_BCM1480_SYS_SW_DIV(x) _SB_MAKEVALUE(x, S_BCM1480_SYS_SW_DIV) +#define G_BCM1480_SYS_SW_DIV(x) _SB_GETVALUE(x, S_BCM1480_SYS_SW_DIV, M_BCM1480_SYS_SW_DIV) #define M_BCM1480_SYS_PCMCIA_ENABLE _SB_MAKEMASK1(16) #define M_BCM1480_SYS_DUART1_ENABLE _SB_MAKEMASK1(17) #define S_BCM1480_SYS_BOOT_MODE _SB_MAKE64(18) -#define M_BCM1480_SYS_BOOT_MODE _SB_MAKEMASK(2,S_BCM1480_SYS_BOOT_MODE) -#define V_BCM1480_SYS_BOOT_MODE(x) _SB_MAKEVALUE(x,S_BCM1480_SYS_BOOT_MODE) -#define G_BCM1480_SYS_BOOT_MODE(x) _SB_GETVALUE(x,S_BCM1480_SYS_BOOT_MODE,M_BCM1480_SYS_BOOT_MODE) +#define M_BCM1480_SYS_BOOT_MODE _SB_MAKEMASK(2, S_BCM1480_SYS_BOOT_MODE) +#define V_BCM1480_SYS_BOOT_MODE(x) _SB_MAKEVALUE(x, S_BCM1480_SYS_BOOT_MODE) +#define G_BCM1480_SYS_BOOT_MODE(x) _SB_GETVALUE(x, S_BCM1480_SYS_BOOT_MODE, M_BCM1480_SYS_BOOT_MODE) #define K_BCM1480_SYS_BOOT_MODE_ROM32 0 #define K_BCM1480_SYS_BOOT_MODE_ROM8 1 #define K_BCM1480_SYS_BOOT_MODE_SMBUS_SMALL 2 @@ -129,16 +129,16 @@ #define M_BCM1480_SYS_RESERVED25 _SB_MAKEMASK1(25) #define S_BCM1480_SYS_CONFIG 26 -#define M_BCM1480_SYS_CONFIG _SB_MAKEMASK(6,S_BCM1480_SYS_CONFIG) -#define V_BCM1480_SYS_CONFIG(x) _SB_MAKEVALUE(x,S_BCM1480_SYS_CONFIG) -#define G_BCM1480_SYS_CONFIG(x) _SB_GETVALUE(x,S_BCM1480_SYS_CONFIG,M_BCM1480_SYS_CONFIG) +#define M_BCM1480_SYS_CONFIG _SB_MAKEMASK(6, S_BCM1480_SYS_CONFIG) +#define V_BCM1480_SYS_CONFIG(x) _SB_MAKEVALUE(x, S_BCM1480_SYS_CONFIG) +#define G_BCM1480_SYS_CONFIG(x) _SB_GETVALUE(x, S_BCM1480_SYS_CONFIG, M_BCM1480_SYS_CONFIG) -#define M_BCM1480_SYS_RESERVED32 _SB_MAKEMASK(32,15) +#define M_BCM1480_SYS_RESERVED32 _SB_MAKEMASK(32, 15) #define S_BCM1480_SYS_NODEID 47 -#define M_BCM1480_SYS_NODEID _SB_MAKEMASK(4,S_BCM1480_SYS_NODEID) -#define V_BCM1480_SYS_NODEID(x) _SB_MAKEVALUE(x,S_BCM1480_SYS_NODEID) -#define G_BCM1480_SYS_NODEID(x) _SB_GETVALUE(x,S_BCM1480_SYS_NODEID,M_BCM1480_SYS_NODEID) +#define M_BCM1480_SYS_NODEID _SB_MAKEMASK(4, S_BCM1480_SYS_NODEID) +#define V_BCM1480_SYS_NODEID(x) _SB_MAKEVALUE(x, S_BCM1480_SYS_NODEID) +#define G_BCM1480_SYS_NODEID(x) _SB_GETVALUE(x, S_BCM1480_SYS_NODEID, M_BCM1480_SYS_NODEID) #define M_BCM1480_SYS_CCNUMA_EN _SB_MAKEMASK1(51) #define M_BCM1480_SYS_CPU_RESET_0 _SB_MAKEMASK1(52) @@ -196,9 +196,9 @@ #define M_BCM1480_SCD_WDOG_ENABLE _SB_MAKEMASK1(0) #define S_BCM1480_SCD_WDOG_RESET_TYPE 2 -#define M_BCM1480_SCD_WDOG_RESET_TYPE _SB_MAKEMASK(5,S_BCM1480_SCD_WDOG_RESET_TYPE) -#define V_BCM1480_SCD_WDOG_RESET_TYPE(x) _SB_MAKEVALUE(x,S_BCM1480_SCD_WDOG_RESET_TYPE) -#define G_BCM1480_SCD_WDOG_RESET_TYPE(x) _SB_GETVALUE(x,S_BCM1480_SCD_WDOG_RESET_TYPE,M_BCM1480_SCD_WDOG_RESET_TYPE) +#define M_BCM1480_SCD_WDOG_RESET_TYPE _SB_MAKEMASK(5, S_BCM1480_SCD_WDOG_RESET_TYPE) +#define V_BCM1480_SCD_WDOG_RESET_TYPE(x) _SB_MAKEVALUE(x, S_BCM1480_SCD_WDOG_RESET_TYPE) +#define G_BCM1480_SCD_WDOG_RESET_TYPE(x) _SB_GETVALUE(x, S_BCM1480_SCD_WDOG_RESET_TYPE, M_BCM1480_SCD_WDOG_RESET_TYPE) #define K_BCM1480_SCD_WDOG_RESET_FULL 0 /* actually, (x & 1) == 0 */ #define K_BCM1480_SCD_WDOG_RESET_SOFT 1 @@ -244,24 +244,24 @@ */ #define S_SPC_CFG_SRC4 32 -#define M_SPC_CFG_SRC4 _SB_MAKEMASK(8,S_SPC_CFG_SRC4) -#define V_SPC_CFG_SRC4(x) _SB_MAKEVALUE(x,S_SPC_CFG_SRC4) -#define G_SPC_CFG_SRC4(x) _SB_GETVALUE(x,S_SPC_CFG_SRC4,M_SPC_CFG_SRC4) +#define M_SPC_CFG_SRC4 _SB_MAKEMASK(8, S_SPC_CFG_SRC4) +#define V_SPC_CFG_SRC4(x) _SB_MAKEVALUE(x, S_SPC_CFG_SRC4) +#define G_SPC_CFG_SRC4(x) _SB_GETVALUE(x, S_SPC_CFG_SRC4, M_SPC_CFG_SRC4) #define S_SPC_CFG_SRC5 40 -#define M_SPC_CFG_SRC5 _SB_MAKEMASK(8,S_SPC_CFG_SRC5) -#define V_SPC_CFG_SRC5(x) _SB_MAKEVALUE(x,S_SPC_CFG_SRC5) -#define G_SPC_CFG_SRC5(x) _SB_GETVALUE(x,S_SPC_CFG_SRC5,M_SPC_CFG_SRC5) +#define M_SPC_CFG_SRC5 _SB_MAKEMASK(8, S_SPC_CFG_SRC5) +#define V_SPC_CFG_SRC5(x) _SB_MAKEVALUE(x, S_SPC_CFG_SRC5) +#define G_SPC_CFG_SRC5(x) _SB_GETVALUE(x, S_SPC_CFG_SRC5, M_SPC_CFG_SRC5) #define S_SPC_CFG_SRC6 48 -#define M_SPC_CFG_SRC6 _SB_MAKEMASK(8,S_SPC_CFG_SRC6) -#define V_SPC_CFG_SRC6(x) _SB_MAKEVALUE(x,S_SPC_CFG_SRC6) -#define G_SPC_CFG_SRC6(x) _SB_GETVALUE(x,S_SPC_CFG_SRC6,M_SPC_CFG_SRC6) +#define M_SPC_CFG_SRC6 _SB_MAKEMASK(8, S_SPC_CFG_SRC6) +#define V_SPC_CFG_SRC6(x) _SB_MAKEVALUE(x, S_SPC_CFG_SRC6) +#define G_SPC_CFG_SRC6(x) _SB_GETVALUE(x, S_SPC_CFG_SRC6, M_SPC_CFG_SRC6) #define S_SPC_CFG_SRC7 56 -#define M_SPC_CFG_SRC7 _SB_MAKEMASK(8,S_SPC_CFG_SRC7) -#define V_SPC_CFG_SRC7(x) _SB_MAKEVALUE(x,S_SPC_CFG_SRC7) -#define G_SPC_CFG_SRC7(x) _SB_GETVALUE(x,S_SPC_CFG_SRC7,M_SPC_CFG_SRC7) +#define M_SPC_CFG_SRC7 _SB_MAKEMASK(8, S_SPC_CFG_SRC7) +#define V_SPC_CFG_SRC7(x) _SB_MAKEVALUE(x, S_SPC_CFG_SRC7) +#define G_SPC_CFG_SRC7(x) _SB_GETVALUE(x, S_SPC_CFG_SRC7, M_SPC_CFG_SRC7) /* * System Performance Counter Control Register (Table 32) @@ -281,9 +281,9 @@ */ #define S_BCM1480_SPC_CNT_COUNT 0 -#define M_BCM1480_SPC_CNT_COUNT _SB_MAKEMASK(40,S_BCM1480_SPC_CNT_COUNT) -#define V_BCM1480_SPC_CNT_COUNT(x) _SB_MAKEVALUE(x,S_BCM1480_SPC_CNT_COUNT) -#define G_BCM1480_SPC_CNT_COUNT(x) _SB_GETVALUE(x,S_BCM1480_SPC_CNT_COUNT,M_BCM1480_SPC_CNT_COUNT) +#define M_BCM1480_SPC_CNT_COUNT _SB_MAKEMASK(40, S_BCM1480_SPC_CNT_COUNT) +#define V_BCM1480_SPC_CNT_COUNT(x) _SB_MAKEVALUE(x, S_BCM1480_SPC_CNT_COUNT) +#define G_BCM1480_SPC_CNT_COUNT(x) _SB_GETVALUE(x, S_BCM1480_SPC_CNT_COUNT, M_BCM1480_SPC_CNT_COUNT) #define M_BCM1480_SPC_CNT_OFLOW _SB_MAKEMASK1(40) @@ -322,13 +322,13 @@ * slightly different. */ -#define M_BCM1480_ATRAP_INDEX _SB_MAKEMASK(4,0) -#define M_BCM1480_ATRAP_ADDRESS _SB_MAKEMASK(40,0) +#define M_BCM1480_ATRAP_INDEX _SB_MAKEMASK(4, 0) +#define M_BCM1480_ATRAP_ADDRESS _SB_MAKEMASK(40, 0) #define S_BCM1480_ATRAP_CFG_CNT 0 -#define M_BCM1480_ATRAP_CFG_CNT _SB_MAKEMASK(3,S_BCM1480_ATRAP_CFG_CNT) -#define V_BCM1480_ATRAP_CFG_CNT(x) _SB_MAKEVALUE(x,S_BCM1480_ATRAP_CFG_CNT) -#define G_BCM1480_ATRAP_CFG_CNT(x) _SB_GETVALUE(x,S_BCM1480_ATRAP_CFG_CNT,M_BCM1480_ATRAP_CFG_CNT) +#define M_BCM1480_ATRAP_CFG_CNT _SB_MAKEMASK(3, S_BCM1480_ATRAP_CFG_CNT) +#define V_BCM1480_ATRAP_CFG_CNT(x) _SB_MAKEVALUE(x, S_BCM1480_ATRAP_CFG_CNT) +#define G_BCM1480_ATRAP_CFG_CNT(x) _SB_GETVALUE(x, S_BCM1480_ATRAP_CFG_CNT, M_BCM1480_ATRAP_CFG_CNT) #define M_BCM1480_ATRAP_CFG_WRITE _SB_MAKEMASK1(3) #define M_BCM1480_ATRAP_CFG_ALL _SB_MAKEMASK1(4) @@ -337,9 +337,9 @@ #define M_BCM1480_ATRAP_CFG_SRCINV _SB_MAKEMASK1(7) #define S_BCM1480_ATRAP_CFG_AGENTID 8 -#define M_BCM1480_ATRAP_CFG_AGENTID _SB_MAKEMASK(4,S_BCM1480_ATRAP_CFG_AGENTID) -#define V_BCM1480_ATRAP_CFG_AGENTID(x) _SB_MAKEVALUE(x,S_BCM1480_ATRAP_CFG_AGENTID) -#define G_BCM1480_ATRAP_CFG_AGENTID(x) _SB_GETVALUE(x,S_BCM1480_ATRAP_CFG_AGENTID,M_BCM1480_ATRAP_CFG_AGENTID) +#define M_BCM1480_ATRAP_CFG_AGENTID _SB_MAKEMASK(4, S_BCM1480_ATRAP_CFG_AGENTID) +#define V_BCM1480_ATRAP_CFG_AGENTID(x) _SB_MAKEVALUE(x, S_BCM1480_ATRAP_CFG_AGENTID) +#define G_BCM1480_ATRAP_CFG_AGENTID(x) _SB_GETVALUE(x, S_BCM1480_ATRAP_CFG_AGENTID, M_BCM1480_ATRAP_CFG_AGENTID) #define K_BCM1480_BUS_AGENT_CPU0 0 @@ -354,9 +354,9 @@ #define K_BCM1480_BUS_AGENT_PM 10 #define S_BCM1480_ATRAP_CFG_CATTR 12 -#define M_BCM1480_ATRAP_CFG_CATTR _SB_MAKEMASK(2,S_BCM1480_ATRAP_CFG_CATTR) -#define V_BCM1480_ATRAP_CFG_CATTR(x) _SB_MAKEVALUE(x,S_BCM1480_ATRAP_CFG_CATTR) -#define G_BCM1480_ATRAP_CFG_CATTR(x) _SB_GETVALUE(x,S_BCM1480_ATRAP_CFG_CATTR,M_BCM1480_ATRAP_CFG_CATTR) +#define M_BCM1480_ATRAP_CFG_CATTR _SB_MAKEMASK(2, S_BCM1480_ATRAP_CFG_CATTR) +#define V_BCM1480_ATRAP_CFG_CATTR(x) _SB_MAKEVALUE(x, S_BCM1480_ATRAP_CFG_CATTR) +#define G_BCM1480_ATRAP_CFG_CATTR(x) _SB_GETVALUE(x, S_BCM1480_ATRAP_CFG_CATTR, M_BCM1480_ATRAP_CFG_CATTR) #define K_BCM1480_ATRAP_CFG_CATTR_IGNORE 0 #define K_BCM1480_ATRAP_CFG_CATTR_UNC 1 @@ -382,9 +382,9 @@ #define M_BCM1480_SCD_TRSEQ_TID_MATCH_EN _SB_MAKEMASK1(25) #define S_BCM1480_SCD_TRSEQ_SWFUNC 26 -#define M_BCM1480_SCD_TRSEQ_SWFUNC _SB_MAKEMASK(2,S_BCM1480_SCD_TRSEQ_SWFUNC) -#define V_BCM1480_SCD_TRSEQ_SWFUNC(x) _SB_MAKEVALUE(x,S_BCM1480_SCD_TRSEQ_SWFUNC) -#define G_BCM1480_SCD_TRSEQ_SWFUNC(x) _SB_GETVALUE(x,S_BCM1480_SCD_TRSEQ_SWFUNC,M_BCM1480_SCD_TRSEQ_SWFUNC) +#define M_BCM1480_SCD_TRSEQ_SWFUNC _SB_MAKEMASK(2, S_BCM1480_SCD_TRSEQ_SWFUNC) +#define V_BCM1480_SCD_TRSEQ_SWFUNC(x) _SB_MAKEVALUE(x, S_BCM1480_SCD_TRSEQ_SWFUNC) +#define G_BCM1480_SCD_TRSEQ_SWFUNC(x) _SB_GETVALUE(x, S_BCM1480_SCD_TRSEQ_SWFUNC, M_BCM1480_SCD_TRSEQ_SWFUNC) /* * Trace Control Register (Table 49) @@ -395,9 +395,9 @@ */ #define S_BCM1480_SCD_TRACE_CFG_MODE 16 -#define M_BCM1480_SCD_TRACE_CFG_MODE _SB_MAKEMASK(2,S_BCM1480_SCD_TRACE_CFG_MODE) -#define V_BCM1480_SCD_TRACE_CFG_MODE(x) _SB_MAKEVALUE(x,S_BCM1480_SCD_TRACE_CFG_MODE) -#define G_BCM1480_SCD_TRACE_CFG_MODE(x) _SB_GETVALUE(x,S_BCM1480_SCD_TRACE_CFG_MODE,M_BCM1480_SCD_TRACE_CFG_MODE) +#define M_BCM1480_SCD_TRACE_CFG_MODE _SB_MAKEMASK(2, S_BCM1480_SCD_TRACE_CFG_MODE) +#define V_BCM1480_SCD_TRACE_CFG_MODE(x) _SB_MAKEVALUE(x, S_BCM1480_SCD_TRACE_CFG_MODE) +#define G_BCM1480_SCD_TRACE_CFG_MODE(x) _SB_GETVALUE(x, S_BCM1480_SCD_TRACE_CFG_MODE, M_BCM1480_SCD_TRACE_CFG_MODE) #define K_BCM1480_SCD_TRACE_CFG_MODE_BLOCKERS 0 #define K_BCM1480_SCD_TRACE_CFG_MODE_BYTEEN_INT 1 diff --git a/include/asm-mips/sibyte/board.h b/include/asm-mips/sibyte/board.h index 73bce901a378..da198a1c8c81 100644 --- a/include/asm-mips/sibyte/board.h +++ b/include/asm-mips/sibyte/board.h @@ -41,7 +41,7 @@ #ifdef __ASSEMBLY__ #ifdef LEDS_PHYS -#define setleds(t0,t1,c0,c1,c2,c3) \ +#define setleds(t0, t1, c0, c1, c2, c3) \ li t0, (LEDS_PHYS|0xa0000000); \ li t1, c0; \ sb t1, 0x18(t0); \ @@ -52,7 +52,7 @@ li t1, c3; \ sb t1, 0x00(t0) #else -#define setleds(t0,t1,c0,c1,c2,c3) +#define setleds(t0, t1, c0, c1, c2, c3) #endif /* LEDS_PHYS */ #else diff --git a/include/asm-mips/sibyte/sb1250_defs.h b/include/asm-mips/sibyte/sb1250_defs.h index a885491217c1..09365f9111fa 100644 --- a/include/asm-mips/sibyte/sb1250_defs.h +++ b/include/asm-mips/sibyte/sb1250_defs.h @@ -232,18 +232,18 @@ * Make a mask for 'v' bits at position 'n' */ -#define _SB_MAKEMASK(v,n) (_SB_MAKE64((_SB_MAKE64(1)<<(v))-1) << _SB_MAKE64(n)) -#define _SB_MAKEMASK_32(v,n) (_SB_MAKE32((_SB_MAKE32(1)<<(v))-1) << _SB_MAKE32(n)) +#define _SB_MAKEMASK(v, n) (_SB_MAKE64((_SB_MAKE64(1)<<(v))-1) << _SB_MAKE64(n)) +#define _SB_MAKEMASK_32(v, n) (_SB_MAKE32((_SB_MAKE32(1)<<(v))-1) << _SB_MAKE32(n)) /* * Make a value at 'v' at bit position 'n' */ -#define _SB_MAKEVALUE(v,n) (_SB_MAKE64(v) << _SB_MAKE64(n)) -#define _SB_MAKEVALUE_32(v,n) (_SB_MAKE32(v) << _SB_MAKE32(n)) +#define _SB_MAKEVALUE(v, n) (_SB_MAKE64(v) << _SB_MAKE64(n)) +#define _SB_MAKEVALUE_32(v, n) (_SB_MAKE32(v) << _SB_MAKE32(n)) -#define _SB_GETVALUE(v,n,m) ((_SB_MAKE64(v) & _SB_MAKE64(m)) >> _SB_MAKE64(n)) -#define _SB_GETVALUE_32(v,n,m) ((_SB_MAKE32(v) & _SB_MAKE32(m)) >> _SB_MAKE32(n)) +#define _SB_GETVALUE(v, n, m) ((_SB_MAKE64(v) & _SB_MAKE64(m)) >> _SB_MAKE64(n)) +#define _SB_GETVALUE_32(v, n, m) ((_SB_MAKE32(v) & _SB_MAKE32(m)) >> _SB_MAKE32(n)) /* * Macros to read/write on-chip registers @@ -252,7 +252,7 @@ #if defined(__mips64) && !defined(__ASSEMBLY__) -#define SBWRITECSR(csr,val) *((volatile uint64_t *) PHYS_TO_K1(csr)) = (val) +#define SBWRITECSR(csr, val) *((volatile uint64_t *) PHYS_TO_K1(csr)) = (val) #define SBREADCSR(csr) (*((volatile uint64_t *) PHYS_TO_K1(csr))) #endif /* __ASSEMBLY__ */ diff --git a/include/asm-mips/sibyte/sb1250_dma.h b/include/asm-mips/sibyte/sb1250_dma.h index e6145f524fbd..bad56171d747 100644 --- a/include/asm-mips/sibyte/sb1250_dma.h +++ b/include/asm-mips/sibyte/sb1250_dma.h @@ -57,9 +57,9 @@ #define M_DMA_RESERVED1 _SB_MAKEMASK1(2) #define S_DMA_DESC_TYPE _SB_MAKE64(1) -#define M_DMA_DESC_TYPE _SB_MAKEMASK(2,S_DMA_DESC_TYPE) -#define V_DMA_DESC_TYPE(x) _SB_MAKEVALUE(x,S_DMA_DESC_TYPE) -#define G_DMA_DESC_TYPE(x) _SB_GETVALUE(x,S_DMA_DESC_TYPE,M_DMA_DESC_TYPE) +#define M_DMA_DESC_TYPE _SB_MAKEMASK(2, S_DMA_DESC_TYPE) +#define V_DMA_DESC_TYPE(x) _SB_MAKEVALUE(x, S_DMA_DESC_TYPE) +#define G_DMA_DESC_TYPE(x) _SB_GETVALUE(x, S_DMA_DESC_TYPE, M_DMA_DESC_TYPE) #define K_DMA_DESC_TYPE_RING_AL 0 #define K_DMA_DESC_TYPE_CHAIN_AL 1 @@ -76,24 +76,24 @@ #define M_DMA_TDX_EN _SB_MAKEMASK1(7) #define S_DMA_INT_PKTCNT _SB_MAKE64(8) -#define M_DMA_INT_PKTCNT _SB_MAKEMASK(8,S_DMA_INT_PKTCNT) -#define V_DMA_INT_PKTCNT(x) _SB_MAKEVALUE(x,S_DMA_INT_PKTCNT) -#define G_DMA_INT_PKTCNT(x) _SB_GETVALUE(x,S_DMA_INT_PKTCNT,M_DMA_INT_PKTCNT) +#define M_DMA_INT_PKTCNT _SB_MAKEMASK(8, S_DMA_INT_PKTCNT) +#define V_DMA_INT_PKTCNT(x) _SB_MAKEVALUE(x, S_DMA_INT_PKTCNT) +#define G_DMA_INT_PKTCNT(x) _SB_GETVALUE(x, S_DMA_INT_PKTCNT, M_DMA_INT_PKTCNT) #define S_DMA_RINGSZ _SB_MAKE64(16) -#define M_DMA_RINGSZ _SB_MAKEMASK(16,S_DMA_RINGSZ) -#define V_DMA_RINGSZ(x) _SB_MAKEVALUE(x,S_DMA_RINGSZ) -#define G_DMA_RINGSZ(x) _SB_GETVALUE(x,S_DMA_RINGSZ,M_DMA_RINGSZ) +#define M_DMA_RINGSZ _SB_MAKEMASK(16, S_DMA_RINGSZ) +#define V_DMA_RINGSZ(x) _SB_MAKEVALUE(x, S_DMA_RINGSZ) +#define G_DMA_RINGSZ(x) _SB_GETVALUE(x, S_DMA_RINGSZ, M_DMA_RINGSZ) #define S_DMA_HIGH_WATERMARK _SB_MAKE64(32) -#define M_DMA_HIGH_WATERMARK _SB_MAKEMASK(16,S_DMA_HIGH_WATERMARK) -#define V_DMA_HIGH_WATERMARK(x) _SB_MAKEVALUE(x,S_DMA_HIGH_WATERMARK) -#define G_DMA_HIGH_WATERMARK(x) _SB_GETVALUE(x,S_DMA_HIGH_WATERMARK,M_DMA_HIGH_WATERMARK) +#define M_DMA_HIGH_WATERMARK _SB_MAKEMASK(16, S_DMA_HIGH_WATERMARK) +#define V_DMA_HIGH_WATERMARK(x) _SB_MAKEVALUE(x, S_DMA_HIGH_WATERMARK) +#define G_DMA_HIGH_WATERMARK(x) _SB_GETVALUE(x, S_DMA_HIGH_WATERMARK, M_DMA_HIGH_WATERMARK) #define S_DMA_LOW_WATERMARK _SB_MAKE64(48) -#define M_DMA_LOW_WATERMARK _SB_MAKEMASK(16,S_DMA_LOW_WATERMARK) -#define V_DMA_LOW_WATERMARK(x) _SB_MAKEVALUE(x,S_DMA_LOW_WATERMARK) -#define G_DMA_LOW_WATERMARK(x) _SB_GETVALUE(x,S_DMA_LOW_WATERMARK,M_DMA_LOW_WATERMARK) +#define M_DMA_LOW_WATERMARK _SB_MAKEMASK(16, S_DMA_LOW_WATERMARK) +#define V_DMA_LOW_WATERMARK(x) _SB_MAKEVALUE(x, S_DMA_LOW_WATERMARK) +#define G_DMA_LOW_WATERMARK(x) _SB_GETVALUE(x, S_DMA_LOW_WATERMARK, M_DMA_LOW_WATERMARK) /* * Ethernet and Serial DMA Configuration Register 1 (Table 7-5) @@ -116,37 +116,37 @@ #define M_DMA_TX_FC_PAUSE_EN _SB_MAKEMASK1(7) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ -#define M_DMA_MBZ1 _SB_MAKEMASK(6,15) +#define M_DMA_MBZ1 _SB_MAKEMASK(6, 15) #define S_DMA_HDR_SIZE _SB_MAKE64(21) -#define M_DMA_HDR_SIZE _SB_MAKEMASK(9,S_DMA_HDR_SIZE) -#define V_DMA_HDR_SIZE(x) _SB_MAKEVALUE(x,S_DMA_HDR_SIZE) -#define G_DMA_HDR_SIZE(x) _SB_GETVALUE(x,S_DMA_HDR_SIZE,M_DMA_HDR_SIZE) +#define M_DMA_HDR_SIZE _SB_MAKEMASK(9, S_DMA_HDR_SIZE) +#define V_DMA_HDR_SIZE(x) _SB_MAKEVALUE(x, S_DMA_HDR_SIZE) +#define G_DMA_HDR_SIZE(x) _SB_GETVALUE(x, S_DMA_HDR_SIZE, M_DMA_HDR_SIZE) -#define M_DMA_MBZ2 _SB_MAKEMASK(5,32) +#define M_DMA_MBZ2 _SB_MAKEMASK(5, 32) #define S_DMA_ASICXFR_SIZE _SB_MAKE64(37) -#define M_DMA_ASICXFR_SIZE _SB_MAKEMASK(9,S_DMA_ASICXFR_SIZE) -#define V_DMA_ASICXFR_SIZE(x) _SB_MAKEVALUE(x,S_DMA_ASICXFR_SIZE) -#define G_DMA_ASICXFR_SIZE(x) _SB_GETVALUE(x,S_DMA_ASICXFR_SIZE,M_DMA_ASICXFR_SIZE) +#define M_DMA_ASICXFR_SIZE _SB_MAKEMASK(9, S_DMA_ASICXFR_SIZE) +#define V_DMA_ASICXFR_SIZE(x) _SB_MAKEVALUE(x, S_DMA_ASICXFR_SIZE) +#define G_DMA_ASICXFR_SIZE(x) _SB_GETVALUE(x, S_DMA_ASICXFR_SIZE, M_DMA_ASICXFR_SIZE) #define S_DMA_INT_TIMEOUT _SB_MAKE64(48) -#define M_DMA_INT_TIMEOUT _SB_MAKEMASK(16,S_DMA_INT_TIMEOUT) -#define V_DMA_INT_TIMEOUT(x) _SB_MAKEVALUE(x,S_DMA_INT_TIMEOUT) -#define G_DMA_INT_TIMEOUT(x) _SB_GETVALUE(x,S_DMA_INT_TIMEOUT,M_DMA_INT_TIMEOUT) +#define M_DMA_INT_TIMEOUT _SB_MAKEMASK(16, S_DMA_INT_TIMEOUT) +#define V_DMA_INT_TIMEOUT(x) _SB_MAKEVALUE(x, S_DMA_INT_TIMEOUT) +#define G_DMA_INT_TIMEOUT(x) _SB_GETVALUE(x, S_DMA_INT_TIMEOUT, M_DMA_INT_TIMEOUT) /* * Ethernet and Serial DMA Descriptor base address (Table 7-6) */ -#define M_DMA_DSCRBASE_MBZ _SB_MAKEMASK(4,0) +#define M_DMA_DSCRBASE_MBZ _SB_MAKEMASK(4, 0) /* * ASIC Mode Base Address (Table 7-7) */ -#define M_DMA_ASIC_BASE_MBZ _SB_MAKEMASK(20,0) +#define M_DMA_ASIC_BASE_MBZ _SB_MAKEMASK(20, 0) /* * DMA Descriptor Count Registers (Table 7-8) @@ -160,9 +160,9 @@ */ #define S_DMA_CURDSCR_ADDR _SB_MAKE64(0) -#define M_DMA_CURDSCR_ADDR _SB_MAKEMASK(40,S_DMA_CURDSCR_ADDR) +#define M_DMA_CURDSCR_ADDR _SB_MAKEMASK(40, S_DMA_CURDSCR_ADDR) #define S_DMA_CURDSCR_COUNT _SB_MAKE64(40) -#define M_DMA_CURDSCR_COUNT _SB_MAKEMASK(16,S_DMA_CURDSCR_COUNT) +#define M_DMA_CURDSCR_COUNT _SB_MAKEMASK(16, S_DMA_CURDSCR_COUNT) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define M_DMA_TX_CH_PAUSE_ON _SB_MAKEMASK1(56) @@ -173,12 +173,12 @@ */ #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_DMA_OODLOST_RX _SB_MAKE64(0) -#define M_DMA_OODLOST_RX _SB_MAKEMASK(16,S_DMA_OODLOST_RX) -#define G_DMA_OODLOST_RX(x) _SB_GETVALUE(x,S_DMA_OODLOST_RX,M_DMA_OODLOST_RX) +#define M_DMA_OODLOST_RX _SB_MAKEMASK(16, S_DMA_OODLOST_RX) +#define G_DMA_OODLOST_RX(x) _SB_GETVALUE(x, S_DMA_OODLOST_RX, M_DMA_OODLOST_RX) #define S_DMA_EOP_COUNT_RX _SB_MAKE64(16) -#define M_DMA_EOP_COUNT_RX _SB_MAKEMASK(8,S_DMA_EOP_COUNT_RX) -#define G_DMA_EOP_COUNT_RX(x) _SB_GETVALUE(x,S_DMA_EOP_COUNT_RX,M_DMA_EOP_COUNT_RX) +#define M_DMA_EOP_COUNT_RX _SB_MAKEMASK(8, S_DMA_EOP_COUNT_RX) +#define G_DMA_EOP_COUNT_RX(x) _SB_GETVALUE(x, S_DMA_EOP_COUNT_RX, M_DMA_EOP_COUNT_RX) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ /* ********************************************************************* @@ -190,39 +190,39 @@ */ #define S_DMA_DSCRA_OFFSET _SB_MAKE64(0) -#define M_DMA_DSCRA_OFFSET _SB_MAKEMASK(5,S_DMA_DSCRA_OFFSET) -#define V_DMA_DSCRA_OFFSET(x) _SB_MAKEVALUE(x,S_DMA_DSCRA_OFFSET) -#define G_DMA_DSCRA_OFFSET(x) _SB_GETVALUE(x,S_DMA_DSCRA_OFFSET,M_DMA_DSCRA_OFFSET) +#define M_DMA_DSCRA_OFFSET _SB_MAKEMASK(5, S_DMA_DSCRA_OFFSET) +#define V_DMA_DSCRA_OFFSET(x) _SB_MAKEVALUE(x, S_DMA_DSCRA_OFFSET) +#define G_DMA_DSCRA_OFFSET(x) _SB_GETVALUE(x, S_DMA_DSCRA_OFFSET, M_DMA_DSCRA_OFFSET) /* Note: Don't shift the address over, just mask it with the mask below */ #define S_DMA_DSCRA_A_ADDR _SB_MAKE64(5) -#define M_DMA_DSCRA_A_ADDR _SB_MAKEMASK(35,S_DMA_DSCRA_A_ADDR) +#define M_DMA_DSCRA_A_ADDR _SB_MAKEMASK(35, S_DMA_DSCRA_A_ADDR) #define M_DMA_DSCRA_A_ADDR_OFFSET (M_DMA_DSCRA_OFFSET | M_DMA_DSCRA_A_ADDR) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_DMA_DSCRA_A_ADDR_UA _SB_MAKE64(0) -#define M_DMA_DSCRA_A_ADDR_UA _SB_MAKEMASK(40,S_DMA_DSCRA_A_ADDR_UA) +#define M_DMA_DSCRA_A_ADDR_UA _SB_MAKEMASK(40, S_DMA_DSCRA_A_ADDR_UA) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ #define S_DMA_DSCRA_A_SIZE _SB_MAKE64(40) -#define M_DMA_DSCRA_A_SIZE _SB_MAKEMASK(9,S_DMA_DSCRA_A_SIZE) -#define V_DMA_DSCRA_A_SIZE(x) _SB_MAKEVALUE(x,S_DMA_DSCRA_A_SIZE) -#define G_DMA_DSCRA_A_SIZE(x) _SB_GETVALUE(x,S_DMA_DSCRA_A_SIZE,M_DMA_DSCRA_A_SIZE) +#define M_DMA_DSCRA_A_SIZE _SB_MAKEMASK(9, S_DMA_DSCRA_A_SIZE) +#define V_DMA_DSCRA_A_SIZE(x) _SB_MAKEVALUE(x, S_DMA_DSCRA_A_SIZE) +#define G_DMA_DSCRA_A_SIZE(x) _SB_GETVALUE(x, S_DMA_DSCRA_A_SIZE, M_DMA_DSCRA_A_SIZE) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_DMA_DSCRA_DSCR_CNT _SB_MAKE64(40) -#define M_DMA_DSCRA_DSCR_CNT _SB_MAKEMASK(8,S_DMA_DSCRA_DSCR_CNT) -#define G_DMA_DSCRA_DSCR_CNT(x) _SB_GETVALUE(x,S_DMA_DSCRA_DSCR_CNT,M_DMA_DSCRA_DSCR_CNT) +#define M_DMA_DSCRA_DSCR_CNT _SB_MAKEMASK(8, S_DMA_DSCRA_DSCR_CNT) +#define G_DMA_DSCRA_DSCR_CNT(x) _SB_GETVALUE(x, S_DMA_DSCRA_DSCR_CNT, M_DMA_DSCRA_DSCR_CNT) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ #define M_DMA_DSCRA_INTERRUPT _SB_MAKEMASK1(49) #define M_DMA_DSCRA_OFFSETB _SB_MAKEMASK1(50) #define S_DMA_DSCRA_STATUS _SB_MAKE64(51) -#define M_DMA_DSCRA_STATUS _SB_MAKEMASK(13,S_DMA_DSCRA_STATUS) -#define V_DMA_DSCRA_STATUS(x) _SB_MAKEVALUE(x,S_DMA_DSCRA_STATUS) -#define G_DMA_DSCRA_STATUS(x) _SB_GETVALUE(x,S_DMA_DSCRA_STATUS,M_DMA_DSCRA_STATUS) +#define M_DMA_DSCRA_STATUS _SB_MAKEMASK(13, S_DMA_DSCRA_STATUS) +#define V_DMA_DSCRA_STATUS(x) _SB_MAKEVALUE(x, S_DMA_DSCRA_STATUS) +#define G_DMA_DSCRA_STATUS(x) _SB_GETVALUE(x, S_DMA_DSCRA_STATUS, M_DMA_DSCRA_STATUS) /* * Descriptor doubleword "B" (Table 7-13) @@ -230,49 +230,49 @@ #define S_DMA_DSCRB_OPTIONS _SB_MAKE64(0) -#define M_DMA_DSCRB_OPTIONS _SB_MAKEMASK(4,S_DMA_DSCRB_OPTIONS) -#define V_DMA_DSCRB_OPTIONS(x) _SB_MAKEVALUE(x,S_DMA_DSCRB_OPTIONS) -#define G_DMA_DSCRB_OPTIONS(x) _SB_GETVALUE(x,S_DMA_DSCRB_OPTIONS,M_DMA_DSCRB_OPTIONS) +#define M_DMA_DSCRB_OPTIONS _SB_MAKEMASK(4, S_DMA_DSCRB_OPTIONS) +#define V_DMA_DSCRB_OPTIONS(x) _SB_MAKEVALUE(x, S_DMA_DSCRB_OPTIONS) +#define G_DMA_DSCRB_OPTIONS(x) _SB_GETVALUE(x, S_DMA_DSCRB_OPTIONS, M_DMA_DSCRB_OPTIONS) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_DMA_DSCRB_A_SIZE _SB_MAKE64(8) -#define M_DMA_DSCRB_A_SIZE _SB_MAKEMASK(14,S_DMA_DSCRB_A_SIZE) -#define V_DMA_DSCRB_A_SIZE(x) _SB_MAKEVALUE(x,S_DMA_DSCRB_A_SIZE) -#define G_DMA_DSCRB_A_SIZE(x) _SB_GETVALUE(x,S_DMA_DSCRB_A_SIZE,M_DMA_DSCRB_A_SIZE) +#define M_DMA_DSCRB_A_SIZE _SB_MAKEMASK(14, S_DMA_DSCRB_A_SIZE) +#define V_DMA_DSCRB_A_SIZE(x) _SB_MAKEVALUE(x, S_DMA_DSCRB_A_SIZE) +#define G_DMA_DSCRB_A_SIZE(x) _SB_GETVALUE(x, S_DMA_DSCRB_A_SIZE, M_DMA_DSCRB_A_SIZE) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ #define R_DMA_DSCRB_ADDR _SB_MAKE64(0x10) /* Note: Don't shift the address over, just mask it with the mask below */ #define S_DMA_DSCRB_B_ADDR _SB_MAKE64(5) -#define M_DMA_DSCRB_B_ADDR _SB_MAKEMASK(35,S_DMA_DSCRB_B_ADDR) +#define M_DMA_DSCRB_B_ADDR _SB_MAKEMASK(35, S_DMA_DSCRB_B_ADDR) #define S_DMA_DSCRB_B_SIZE _SB_MAKE64(40) -#define M_DMA_DSCRB_B_SIZE _SB_MAKEMASK(9,S_DMA_DSCRB_B_SIZE) -#define V_DMA_DSCRB_B_SIZE(x) _SB_MAKEVALUE(x,S_DMA_DSCRB_B_SIZE) -#define G_DMA_DSCRB_B_SIZE(x) _SB_GETVALUE(x,S_DMA_DSCRB_B_SIZE,M_DMA_DSCRB_B_SIZE) +#define M_DMA_DSCRB_B_SIZE _SB_MAKEMASK(9, S_DMA_DSCRB_B_SIZE) +#define V_DMA_DSCRB_B_SIZE(x) _SB_MAKEVALUE(x, S_DMA_DSCRB_B_SIZE) +#define G_DMA_DSCRB_B_SIZE(x) _SB_GETVALUE(x, S_DMA_DSCRB_B_SIZE, M_DMA_DSCRB_B_SIZE) #define M_DMA_DSCRB_B_VALID _SB_MAKEMASK1(49) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_DMA_DSCRB_PKT_SIZE_MSB _SB_MAKE64(48) -#define M_DMA_DSCRB_PKT_SIZE_MSB _SB_MAKEMASK(2,S_DMA_DSCRB_PKT_SIZE_MSB) -#define V_DMA_DSCRB_PKT_SIZE_MSB(x) _SB_MAKEVALUE(x,S_DMA_DSCRB_PKT_SIZE_MSB) -#define G_DMA_DSCRB_PKT_SIZE_MSB(x) _SB_GETVALUE(x,S_DMA_DSCRB_PKT_SIZE_MSB,M_DMA_DSCRB_PKT_SIZE_MSB) +#define M_DMA_DSCRB_PKT_SIZE_MSB _SB_MAKEMASK(2, S_DMA_DSCRB_PKT_SIZE_MSB) +#define V_DMA_DSCRB_PKT_SIZE_MSB(x) _SB_MAKEVALUE(x, S_DMA_DSCRB_PKT_SIZE_MSB) +#define G_DMA_DSCRB_PKT_SIZE_MSB(x) _SB_GETVALUE(x, S_DMA_DSCRB_PKT_SIZE_MSB, M_DMA_DSCRB_PKT_SIZE_MSB) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ #define S_DMA_DSCRB_PKT_SIZE _SB_MAKE64(50) -#define M_DMA_DSCRB_PKT_SIZE _SB_MAKEMASK(14,S_DMA_DSCRB_PKT_SIZE) -#define V_DMA_DSCRB_PKT_SIZE(x) _SB_MAKEVALUE(x,S_DMA_DSCRB_PKT_SIZE) -#define G_DMA_DSCRB_PKT_SIZE(x) _SB_GETVALUE(x,S_DMA_DSCRB_PKT_SIZE,M_DMA_DSCRB_PKT_SIZE) +#define M_DMA_DSCRB_PKT_SIZE _SB_MAKEMASK(14, S_DMA_DSCRB_PKT_SIZE) +#define V_DMA_DSCRB_PKT_SIZE(x) _SB_MAKEVALUE(x, S_DMA_DSCRB_PKT_SIZE) +#define G_DMA_DSCRB_PKT_SIZE(x) _SB_GETVALUE(x, S_DMA_DSCRB_PKT_SIZE, M_DMA_DSCRB_PKT_SIZE) /* * from pass2 some bits in dscr_b are also used for rx status */ #define S_DMA_DSCRB_STATUS _SB_MAKE64(0) -#define M_DMA_DSCRB_STATUS _SB_MAKEMASK(1,S_DMA_DSCRB_STATUS) -#define V_DMA_DSCRB_STATUS(x) _SB_MAKEVALUE(x,S_DMA_DSCRB_STATUS) -#define G_DMA_DSCRB_STATUS(x) _SB_GETVALUE(x,S_DMA_DSCRB_STATUS,M_DMA_DSCRB_STATUS) +#define M_DMA_DSCRB_STATUS _SB_MAKEMASK(1, S_DMA_DSCRB_STATUS) +#define V_DMA_DSCRB_STATUS(x) _SB_MAKEVALUE(x, S_DMA_DSCRB_STATUS) +#define G_DMA_DSCRB_STATUS(x) _SB_GETVALUE(x, S_DMA_DSCRB_STATUS, M_DMA_DSCRB_STATUS) /* * Ethernet Descriptor Status Bits (Table 7-15) @@ -293,14 +293,14 @@ #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ #define S_DMA_ETHRX_RXCH 53 -#define M_DMA_ETHRX_RXCH _SB_MAKEMASK(2,S_DMA_ETHRX_RXCH) -#define V_DMA_ETHRX_RXCH(x) _SB_MAKEVALUE(x,S_DMA_ETHRX_RXCH) -#define G_DMA_ETHRX_RXCH(x) _SB_GETVALUE(x,S_DMA_ETHRX_RXCH,M_DMA_ETHRX_RXCH) +#define M_DMA_ETHRX_RXCH _SB_MAKEMASK(2, S_DMA_ETHRX_RXCH) +#define V_DMA_ETHRX_RXCH(x) _SB_MAKEVALUE(x, S_DMA_ETHRX_RXCH) +#define G_DMA_ETHRX_RXCH(x) _SB_GETVALUE(x, S_DMA_ETHRX_RXCH, M_DMA_ETHRX_RXCH) #define S_DMA_ETHRX_PKTTYPE 55 -#define M_DMA_ETHRX_PKTTYPE _SB_MAKEMASK(3,S_DMA_ETHRX_PKTTYPE) -#define V_DMA_ETHRX_PKTTYPE(x) _SB_MAKEVALUE(x,S_DMA_ETHRX_PKTTYPE) -#define G_DMA_ETHRX_PKTTYPE(x) _SB_GETVALUE(x,S_DMA_ETHRX_PKTTYPE,M_DMA_ETHRX_PKTTYPE) +#define M_DMA_ETHRX_PKTTYPE _SB_MAKEMASK(3, S_DMA_ETHRX_PKTTYPE) +#define V_DMA_ETHRX_PKTTYPE(x) _SB_MAKEVALUE(x, S_DMA_ETHRX_PKTTYPE) +#define G_DMA_ETHRX_PKTTYPE(x) _SB_GETVALUE(x, S_DMA_ETHRX_PKTTYPE, M_DMA_ETHRX_PKTTYPE) #define K_DMA_ETHRX_PKTTYPE_IPV4 0 #define K_DMA_ETHRX_PKTTYPE_ARPV4 1 @@ -385,21 +385,21 @@ * Register: DM_DSCR_BASE_3 */ -#define M_DM_DSCR_BASE_MBZ _SB_MAKEMASK(4,0) +#define M_DM_DSCR_BASE_MBZ _SB_MAKEMASK(4, 0) /* Note: Just mask the base address and then OR it in. */ #define S_DM_DSCR_BASE_ADDR _SB_MAKE64(4) -#define M_DM_DSCR_BASE_ADDR _SB_MAKEMASK(36,S_DM_DSCR_BASE_ADDR) +#define M_DM_DSCR_BASE_ADDR _SB_MAKEMASK(36, S_DM_DSCR_BASE_ADDR) #define S_DM_DSCR_BASE_RINGSZ _SB_MAKE64(40) -#define M_DM_DSCR_BASE_RINGSZ _SB_MAKEMASK(16,S_DM_DSCR_BASE_RINGSZ) -#define V_DM_DSCR_BASE_RINGSZ(x) _SB_MAKEVALUE(x,S_DM_DSCR_BASE_RINGSZ) -#define G_DM_DSCR_BASE_RINGSZ(x) _SB_GETVALUE(x,S_DM_DSCR_BASE_RINGSZ,M_DM_DSCR_BASE_RINGSZ) +#define M_DM_DSCR_BASE_RINGSZ _SB_MAKEMASK(16, S_DM_DSCR_BASE_RINGSZ) +#define V_DM_DSCR_BASE_RINGSZ(x) _SB_MAKEVALUE(x, S_DM_DSCR_BASE_RINGSZ) +#define G_DM_DSCR_BASE_RINGSZ(x) _SB_GETVALUE(x, S_DM_DSCR_BASE_RINGSZ, M_DM_DSCR_BASE_RINGSZ) #define S_DM_DSCR_BASE_PRIORITY _SB_MAKE64(56) -#define M_DM_DSCR_BASE_PRIORITY _SB_MAKEMASK(3,S_DM_DSCR_BASE_PRIORITY) -#define V_DM_DSCR_BASE_PRIORITY(x) _SB_MAKEVALUE(x,S_DM_DSCR_BASE_PRIORITY) -#define G_DM_DSCR_BASE_PRIORITY(x) _SB_GETVALUE(x,S_DM_DSCR_BASE_PRIORITY,M_DM_DSCR_BASE_PRIORITY) +#define M_DM_DSCR_BASE_PRIORITY _SB_MAKEMASK(3, S_DM_DSCR_BASE_PRIORITY) +#define V_DM_DSCR_BASE_PRIORITY(x) _SB_MAKEVALUE(x, S_DM_DSCR_BASE_PRIORITY) +#define G_DM_DSCR_BASE_PRIORITY(x) _SB_GETVALUE(x, S_DM_DSCR_BASE_PRIORITY, M_DM_DSCR_BASE_PRIORITY) #define K_DM_DSCR_BASE_PRIORITY_1 0 #define K_DM_DSCR_BASE_PRIORITY_2 1 @@ -429,12 +429,12 @@ */ #define S_DM_CUR_DSCR_DSCR_ADDR _SB_MAKE64(0) -#define M_DM_CUR_DSCR_DSCR_ADDR _SB_MAKEMASK(40,S_DM_CUR_DSCR_DSCR_ADDR) +#define M_DM_CUR_DSCR_DSCR_ADDR _SB_MAKEMASK(40, S_DM_CUR_DSCR_DSCR_ADDR) #define S_DM_CUR_DSCR_DSCR_COUNT _SB_MAKE64(48) -#define M_DM_CUR_DSCR_DSCR_COUNT _SB_MAKEMASK(16,S_DM_CUR_DSCR_DSCR_COUNT) -#define V_DM_CUR_DSCR_DSCR_COUNT(r) _SB_MAKEVALUE(r,S_DM_CUR_DSCR_DSCR_COUNT) -#define G_DM_CUR_DSCR_DSCR_COUNT(r) _SB_GETVALUE(r,S_DM_CUR_DSCR_DSCR_COUNT,\ +#define M_DM_CUR_DSCR_DSCR_COUNT _SB_MAKEMASK(16, S_DM_CUR_DSCR_DSCR_COUNT) +#define V_DM_CUR_DSCR_DSCR_COUNT(r) _SB_MAKEVALUE(r, S_DM_CUR_DSCR_DSCR_COUNT) +#define G_DM_CUR_DSCR_DSCR_COUNT(r) _SB_GETVALUE(r, S_DM_CUR_DSCR_DSCR_COUNT,\ M_DM_CUR_DSCR_DSCR_COUNT) @@ -447,15 +447,15 @@ * Register: DM_PARTIAL_3 */ #define S_DM_PARTIAL_CRC_PARTIAL _SB_MAKE64(0) -#define M_DM_PARTIAL_CRC_PARTIAL _SB_MAKEMASK(32,S_DM_PARTIAL_CRC_PARTIAL) -#define V_DM_PARTIAL_CRC_PARTIAL(r) _SB_MAKEVALUE(r,S_DM_PARTIAL_CRC_PARTIAL) -#define G_DM_PARTIAL_CRC_PARTIAL(r) _SB_GETVALUE(r,S_DM_PARTIAL_CRC_PARTIAL,\ +#define M_DM_PARTIAL_CRC_PARTIAL _SB_MAKEMASK(32, S_DM_PARTIAL_CRC_PARTIAL) +#define V_DM_PARTIAL_CRC_PARTIAL(r) _SB_MAKEVALUE(r, S_DM_PARTIAL_CRC_PARTIAL) +#define G_DM_PARTIAL_CRC_PARTIAL(r) _SB_GETVALUE(r, S_DM_PARTIAL_CRC_PARTIAL,\ M_DM_PARTIAL_CRC_PARTIAL) #define S_DM_PARTIAL_TCPCS_PARTIAL _SB_MAKE64(32) -#define M_DM_PARTIAL_TCPCS_PARTIAL _SB_MAKEMASK(16,S_DM_PARTIAL_TCPCS_PARTIAL) -#define V_DM_PARTIAL_TCPCS_PARTIAL(r) _SB_MAKEVALUE(r,S_DM_PARTIAL_TCPCS_PARTIAL) -#define G_DM_PARTIAL_TCPCS_PARTIAL(r) _SB_GETVALUE(r,S_DM_PARTIAL_TCPCS_PARTIAL,\ +#define M_DM_PARTIAL_TCPCS_PARTIAL _SB_MAKEMASK(16, S_DM_PARTIAL_TCPCS_PARTIAL) +#define V_DM_PARTIAL_TCPCS_PARTIAL(r) _SB_MAKEVALUE(r, S_DM_PARTIAL_TCPCS_PARTIAL) +#define G_DM_PARTIAL_TCPCS_PARTIAL(r) _SB_GETVALUE(r, S_DM_PARTIAL_TCPCS_PARTIAL,\ M_DM_PARTIAL_TCPCS_PARTIAL) #define M_DM_PARTIAL_ODD_BYTE _SB_MAKEMASK1(48) @@ -469,15 +469,15 @@ * Register: CRC_DEF_1 */ #define S_CRC_DEF_CRC_INIT _SB_MAKE64(0) -#define M_CRC_DEF_CRC_INIT _SB_MAKEMASK(32,S_CRC_DEF_CRC_INIT) -#define V_CRC_DEF_CRC_INIT(r) _SB_MAKEVALUE(r,S_CRC_DEF_CRC_INIT) -#define G_CRC_DEF_CRC_INIT(r) _SB_GETVALUE(r,S_CRC_DEF_CRC_INIT,\ +#define M_CRC_DEF_CRC_INIT _SB_MAKEMASK(32, S_CRC_DEF_CRC_INIT) +#define V_CRC_DEF_CRC_INIT(r) _SB_MAKEVALUE(r, S_CRC_DEF_CRC_INIT) +#define G_CRC_DEF_CRC_INIT(r) _SB_GETVALUE(r, S_CRC_DEF_CRC_INIT,\ M_CRC_DEF_CRC_INIT) #define S_CRC_DEF_CRC_POLY _SB_MAKE64(32) -#define M_CRC_DEF_CRC_POLY _SB_MAKEMASK(32,S_CRC_DEF_CRC_POLY) -#define V_CRC_DEF_CRC_POLY(r) _SB_MAKEVALUE(r,S_CRC_DEF_CRC_POLY) -#define G_CRC_DEF_CRC_POLY(r) _SB_GETVALUE(r,S_CRC_DEF_CRC_POLY,\ +#define M_CRC_DEF_CRC_POLY _SB_MAKEMASK(32, S_CRC_DEF_CRC_POLY) +#define V_CRC_DEF_CRC_POLY(r) _SB_MAKEVALUE(r, S_CRC_DEF_CRC_POLY) +#define G_CRC_DEF_CRC_POLY(r) _SB_GETVALUE(r, S_CRC_DEF_CRC_POLY,\ M_CRC_DEF_CRC_POLY) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ @@ -489,21 +489,21 @@ * Register: CTCP_DEF_1 */ #define S_CTCP_DEF_CRC_TXOR _SB_MAKE64(0) -#define M_CTCP_DEF_CRC_TXOR _SB_MAKEMASK(32,S_CTCP_DEF_CRC_TXOR) -#define V_CTCP_DEF_CRC_TXOR(r) _SB_MAKEVALUE(r,S_CTCP_DEF_CRC_TXOR) -#define G_CTCP_DEF_CRC_TXOR(r) _SB_GETVALUE(r,S_CTCP_DEF_CRC_TXOR,\ +#define M_CTCP_DEF_CRC_TXOR _SB_MAKEMASK(32, S_CTCP_DEF_CRC_TXOR) +#define V_CTCP_DEF_CRC_TXOR(r) _SB_MAKEVALUE(r, S_CTCP_DEF_CRC_TXOR) +#define G_CTCP_DEF_CRC_TXOR(r) _SB_GETVALUE(r, S_CTCP_DEF_CRC_TXOR,\ M_CTCP_DEF_CRC_TXOR) #define S_CTCP_DEF_TCPCS_INIT _SB_MAKE64(32) -#define M_CTCP_DEF_TCPCS_INIT _SB_MAKEMASK(16,S_CTCP_DEF_TCPCS_INIT) -#define V_CTCP_DEF_TCPCS_INIT(r) _SB_MAKEVALUE(r,S_CTCP_DEF_TCPCS_INIT) -#define G_CTCP_DEF_TCPCS_INIT(r) _SB_GETVALUE(r,S_CTCP_DEF_TCPCS_INIT,\ +#define M_CTCP_DEF_TCPCS_INIT _SB_MAKEMASK(16, S_CTCP_DEF_TCPCS_INIT) +#define V_CTCP_DEF_TCPCS_INIT(r) _SB_MAKEVALUE(r, S_CTCP_DEF_TCPCS_INIT) +#define G_CTCP_DEF_TCPCS_INIT(r) _SB_GETVALUE(r, S_CTCP_DEF_TCPCS_INIT,\ M_CTCP_DEF_TCPCS_INIT) #define S_CTCP_DEF_CRC_WIDTH _SB_MAKE64(48) -#define M_CTCP_DEF_CRC_WIDTH _SB_MAKEMASK(2,S_CTCP_DEF_CRC_WIDTH) -#define V_CTCP_DEF_CRC_WIDTH(r) _SB_MAKEVALUE(r,S_CTCP_DEF_CRC_WIDTH) -#define G_CTCP_DEF_CRC_WIDTH(r) _SB_GETVALUE(r,S_CTCP_DEF_CRC_WIDTH,\ +#define M_CTCP_DEF_CRC_WIDTH _SB_MAKEMASK(2, S_CTCP_DEF_CRC_WIDTH) +#define V_CTCP_DEF_CRC_WIDTH(r) _SB_MAKEVALUE(r, S_CTCP_DEF_CRC_WIDTH) +#define G_CTCP_DEF_CRC_WIDTH(r) _SB_GETVALUE(r, S_CTCP_DEF_CRC_WIDTH,\ M_CTCP_DEF_CRC_WIDTH) #define K_CTCP_DEF_CRC_WIDTH_4 0 @@ -519,7 +519,7 @@ */ #define S_DM_DSCRA_DST_ADDR _SB_MAKE64(0) -#define M_DM_DSCRA_DST_ADDR _SB_MAKEMASK(40,S_DM_DSCRA_DST_ADDR) +#define M_DM_DSCRA_DST_ADDR _SB_MAKEMASK(40, S_DM_DSCRA_DST_ADDR) #define M_DM_DSCRA_UN_DEST _SB_MAKEMASK1(40) #define M_DM_DSCRA_UN_SRC _SB_MAKEMASK1(41) @@ -529,30 +529,30 @@ #endif /* up to 1250 PASS1 */ #define S_DM_DSCRA_DIR_DEST _SB_MAKE64(44) -#define M_DM_DSCRA_DIR_DEST _SB_MAKEMASK(2,S_DM_DSCRA_DIR_DEST) -#define V_DM_DSCRA_DIR_DEST(x) _SB_MAKEVALUE(x,S_DM_DSCRA_DIR_DEST) -#define G_DM_DSCRA_DIR_DEST(x) _SB_GETVALUE(x,S_DM_DSCRA_DIR_DEST,M_DM_DSCRA_DIR_DEST) +#define M_DM_DSCRA_DIR_DEST _SB_MAKEMASK(2, S_DM_DSCRA_DIR_DEST) +#define V_DM_DSCRA_DIR_DEST(x) _SB_MAKEVALUE(x, S_DM_DSCRA_DIR_DEST) +#define G_DM_DSCRA_DIR_DEST(x) _SB_GETVALUE(x, S_DM_DSCRA_DIR_DEST, M_DM_DSCRA_DIR_DEST) #define K_DM_DSCRA_DIR_DEST_INCR 0 #define K_DM_DSCRA_DIR_DEST_DECR 1 #define K_DM_DSCRA_DIR_DEST_CONST 2 -#define V_DM_DSCRA_DIR_DEST_INCR _SB_MAKEVALUE(K_DM_DSCRA_DIR_DEST_INCR,S_DM_DSCRA_DIR_DEST) -#define V_DM_DSCRA_DIR_DEST_DECR _SB_MAKEVALUE(K_DM_DSCRA_DIR_DEST_DECR,S_DM_DSCRA_DIR_DEST) -#define V_DM_DSCRA_DIR_DEST_CONST _SB_MAKEVALUE(K_DM_DSCRA_DIR_DEST_CONST,S_DM_DSCRA_DIR_DEST) +#define V_DM_DSCRA_DIR_DEST_INCR _SB_MAKEVALUE(K_DM_DSCRA_DIR_DEST_INCR, S_DM_DSCRA_DIR_DEST) +#define V_DM_DSCRA_DIR_DEST_DECR _SB_MAKEVALUE(K_DM_DSCRA_DIR_DEST_DECR, S_DM_DSCRA_DIR_DEST) +#define V_DM_DSCRA_DIR_DEST_CONST _SB_MAKEVALUE(K_DM_DSCRA_DIR_DEST_CONST, S_DM_DSCRA_DIR_DEST) #define S_DM_DSCRA_DIR_SRC _SB_MAKE64(46) -#define M_DM_DSCRA_DIR_SRC _SB_MAKEMASK(2,S_DM_DSCRA_DIR_SRC) -#define V_DM_DSCRA_DIR_SRC(x) _SB_MAKEVALUE(x,S_DM_DSCRA_DIR_SRC) -#define G_DM_DSCRA_DIR_SRC(x) _SB_GETVALUE(x,S_DM_DSCRA_DIR_SRC,M_DM_DSCRA_DIR_SRC) +#define M_DM_DSCRA_DIR_SRC _SB_MAKEMASK(2, S_DM_DSCRA_DIR_SRC) +#define V_DM_DSCRA_DIR_SRC(x) _SB_MAKEVALUE(x, S_DM_DSCRA_DIR_SRC) +#define G_DM_DSCRA_DIR_SRC(x) _SB_GETVALUE(x, S_DM_DSCRA_DIR_SRC, M_DM_DSCRA_DIR_SRC) #define K_DM_DSCRA_DIR_SRC_INCR 0 #define K_DM_DSCRA_DIR_SRC_DECR 1 #define K_DM_DSCRA_DIR_SRC_CONST 2 -#define V_DM_DSCRA_DIR_SRC_INCR _SB_MAKEVALUE(K_DM_DSCRA_DIR_SRC_INCR,S_DM_DSCRA_DIR_SRC) -#define V_DM_DSCRA_DIR_SRC_DECR _SB_MAKEVALUE(K_DM_DSCRA_DIR_SRC_DECR,S_DM_DSCRA_DIR_SRC) -#define V_DM_DSCRA_DIR_SRC_CONST _SB_MAKEVALUE(K_DM_DSCRA_DIR_SRC_CONST,S_DM_DSCRA_DIR_SRC) +#define V_DM_DSCRA_DIR_SRC_INCR _SB_MAKEVALUE(K_DM_DSCRA_DIR_SRC_INCR, S_DM_DSCRA_DIR_SRC) +#define V_DM_DSCRA_DIR_SRC_DECR _SB_MAKEVALUE(K_DM_DSCRA_DIR_SRC_DECR, S_DM_DSCRA_DIR_SRC) +#define V_DM_DSCRA_DIR_SRC_CONST _SB_MAKEVALUE(K_DM_DSCRA_DIR_SRC_CONST, S_DM_DSCRA_DIR_SRC) #define M_DM_DSCRA_ZERO_MEM _SB_MAKEMASK1(48) @@ -576,19 +576,19 @@ #define M_DM_DSCRA_CRC_XBIT _SB_MAKEMASK1(61) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ -#define M_DM_DSCRA_RESERVED2 _SB_MAKEMASK(3,61) +#define M_DM_DSCRA_RESERVED2 _SB_MAKEMASK(3, 61) /* * Data Mover Descriptor Doubleword "B" (Table 7-25) */ #define S_DM_DSCRB_SRC_ADDR _SB_MAKE64(0) -#define M_DM_DSCRB_SRC_ADDR _SB_MAKEMASK(40,S_DM_DSCRB_SRC_ADDR) +#define M_DM_DSCRB_SRC_ADDR _SB_MAKEMASK(40, S_DM_DSCRB_SRC_ADDR) #define S_DM_DSCRB_SRC_LENGTH _SB_MAKE64(40) -#define M_DM_DSCRB_SRC_LENGTH _SB_MAKEMASK(20,S_DM_DSCRB_SRC_LENGTH) -#define V_DM_DSCRB_SRC_LENGTH(x) _SB_MAKEVALUE(x,S_DM_DSCRB_SRC_LENGTH) -#define G_DM_DSCRB_SRC_LENGTH(x) _SB_GETVALUE(x,S_DM_DSCRB_SRC_LENGTH,M_DM_DSCRB_SRC_LENGTH) +#define M_DM_DSCRB_SRC_LENGTH _SB_MAKEMASK(20, S_DM_DSCRB_SRC_LENGTH) +#define V_DM_DSCRB_SRC_LENGTH(x) _SB_MAKEVALUE(x, S_DM_DSCRB_SRC_LENGTH) +#define G_DM_DSCRB_SRC_LENGTH(x) _SB_GETVALUE(x, S_DM_DSCRB_SRC_LENGTH, M_DM_DSCRB_SRC_LENGTH) #endif diff --git a/include/asm-mips/sibyte/sb1250_genbus.h b/include/asm-mips/sibyte/sb1250_genbus.h index 1b5cbc5c6454..94e9c7c8e783 100644 --- a/include/asm-mips/sibyte/sb1250_genbus.h +++ b/include/asm-mips/sibyte/sb1250_genbus.h @@ -11,7 +11,7 @@ * ********************************************************************* * - * Copyright 2000,2001,2002,2003 + * Copyright 2000, 2001, 2002, 2003 * Broadcom Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or @@ -47,7 +47,7 @@ #define M_IO_ENA_RDY _SB_MAKEMASK1(S_IO_ENA_RDY) #define S_IO_WIDTH_SEL 2 -#define M_IO_WIDTH_SEL _SB_MAKEMASK(2,S_IO_WIDTH_SEL) +#define M_IO_WIDTH_SEL _SB_MAKEMASK(2, S_IO_WIDTH_SEL) #define K_IO_WIDTH_SEL_1 0 #define K_IO_WIDTH_SEL_2 1 #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) \ @@ -55,8 +55,8 @@ #define K_IO_WIDTH_SEL_1L 2 #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ #define K_IO_WIDTH_SEL_4 3 -#define V_IO_WIDTH_SEL(x) _SB_MAKEVALUE(x,S_IO_WIDTH_SEL) -#define G_IO_WIDTH_SEL(x) _SB_GETVALUE(x,S_IO_WIDTH_SEL,M_IO_WIDTH_SEL) +#define V_IO_WIDTH_SEL(x) _SB_MAKEVALUE(x, S_IO_WIDTH_SEL) +#define G_IO_WIDTH_SEL(x) _SB_GETVALUE(x, S_IO_WIDTH_SEL, M_IO_WIDTH_SEL) #define S_IO_PARITY_ENA 4 #define M_IO_PARITY_ENA _SB_MAKEMASK1(S_IO_PARITY_ENA) @@ -71,18 +71,18 @@ #define M_IO_NONMUX _SB_MAKEMASK1(S_IO_NONMUX) #define S_IO_TIMEOUT 8 -#define M_IO_TIMEOUT _SB_MAKEMASK(8,S_IO_TIMEOUT) -#define V_IO_TIMEOUT(x) _SB_MAKEVALUE(x,S_IO_TIMEOUT) -#define G_IO_TIMEOUT(x) _SB_GETVALUE(x,S_IO_TIMEOUT,M_IO_TIMEOUT) +#define M_IO_TIMEOUT _SB_MAKEMASK(8, S_IO_TIMEOUT) +#define V_IO_TIMEOUT(x) _SB_MAKEVALUE(x, S_IO_TIMEOUT) +#define G_IO_TIMEOUT(x) _SB_GETVALUE(x, S_IO_TIMEOUT, M_IO_TIMEOUT) /* * Generic Bus Region Size register (Table 11-5) */ #define S_IO_MULT_SIZE 0 -#define M_IO_MULT_SIZE _SB_MAKEMASK(12,S_IO_MULT_SIZE) -#define V_IO_MULT_SIZE(x) _SB_MAKEVALUE(x,S_IO_MULT_SIZE) -#define G_IO_MULT_SIZE(x) _SB_GETVALUE(x,S_IO_MULT_SIZE,M_IO_MULT_SIZE) +#define M_IO_MULT_SIZE _SB_MAKEMASK(12, S_IO_MULT_SIZE) +#define V_IO_MULT_SIZE(x) _SB_MAKEVALUE(x, S_IO_MULT_SIZE) +#define G_IO_MULT_SIZE(x) _SB_GETVALUE(x, S_IO_MULT_SIZE, M_IO_MULT_SIZE) #define S_IO_REGSIZE 16 /* # bits to shift size for this reg */ @@ -91,9 +91,9 @@ */ #define S_IO_START_ADDR 0 -#define M_IO_START_ADDR _SB_MAKEMASK(14,S_IO_START_ADDR) -#define V_IO_START_ADDR(x) _SB_MAKEVALUE(x,S_IO_START_ADDR) -#define G_IO_START_ADDR(x) _SB_GETVALUE(x,S_IO_START_ADDR,M_IO_START_ADDR) +#define M_IO_START_ADDR _SB_MAKEMASK(14, S_IO_START_ADDR) +#define V_IO_START_ADDR(x) _SB_MAKEVALUE(x, S_IO_START_ADDR) +#define G_IO_START_ADDR(x) _SB_GETVALUE(x, S_IO_START_ADDR, M_IO_START_ADDR) #define S_IO_ADDRBASE 16 /* # bits to shift addr for this reg */ @@ -105,9 +105,9 @@ */ #define S_IO_ALE_WIDTH 0 -#define M_IO_ALE_WIDTH _SB_MAKEMASK(3,S_IO_ALE_WIDTH) -#define V_IO_ALE_WIDTH(x) _SB_MAKEVALUE(x,S_IO_ALE_WIDTH) -#define G_IO_ALE_WIDTH(x) _SB_GETVALUE(x,S_IO_ALE_WIDTH,M_IO_ALE_WIDTH) +#define M_IO_ALE_WIDTH _SB_MAKEMASK(3, S_IO_ALE_WIDTH) +#define V_IO_ALE_WIDTH(x) _SB_MAKEVALUE(x, S_IO_ALE_WIDTH) +#define G_IO_ALE_WIDTH(x) _SB_GETVALUE(x, S_IO_ALE_WIDTH, M_IO_ALE_WIDTH) #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) \ || SIBYTE_HDR_FEATURE_CHIP(1480) @@ -115,27 +115,27 @@ #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ #define S_IO_ALE_TO_CS 4 -#define M_IO_ALE_TO_CS _SB_MAKEMASK(2,S_IO_ALE_TO_CS) -#define V_IO_ALE_TO_CS(x) _SB_MAKEVALUE(x,S_IO_ALE_TO_CS) -#define G_IO_ALE_TO_CS(x) _SB_GETVALUE(x,S_IO_ALE_TO_CS,M_IO_ALE_TO_CS) +#define M_IO_ALE_TO_CS _SB_MAKEMASK(2, S_IO_ALE_TO_CS) +#define V_IO_ALE_TO_CS(x) _SB_MAKEVALUE(x, S_IO_ALE_TO_CS) +#define G_IO_ALE_TO_CS(x) _SB_GETVALUE(x, S_IO_ALE_TO_CS, M_IO_ALE_TO_CS) #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) \ || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_IO_BURST_WIDTH _SB_MAKE64(6) -#define M_IO_BURST_WIDTH _SB_MAKEMASK(2,S_IO_BURST_WIDTH) -#define V_IO_BURST_WIDTH(x) _SB_MAKEVALUE(x,S_IO_BURST_WIDTH) -#define G_IO_BURST_WIDTH(x) _SB_GETVALUE(x,S_IO_BURST_WIDTH,M_IO_BURST_WIDTH) +#define M_IO_BURST_WIDTH _SB_MAKEMASK(2, S_IO_BURST_WIDTH) +#define V_IO_BURST_WIDTH(x) _SB_MAKEVALUE(x, S_IO_BURST_WIDTH) +#define G_IO_BURST_WIDTH(x) _SB_GETVALUE(x, S_IO_BURST_WIDTH, M_IO_BURST_WIDTH) #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ #define S_IO_CS_WIDTH 8 -#define M_IO_CS_WIDTH _SB_MAKEMASK(5,S_IO_CS_WIDTH) -#define V_IO_CS_WIDTH(x) _SB_MAKEVALUE(x,S_IO_CS_WIDTH) -#define G_IO_CS_WIDTH(x) _SB_GETVALUE(x,S_IO_CS_WIDTH,M_IO_CS_WIDTH) +#define M_IO_CS_WIDTH _SB_MAKEMASK(5, S_IO_CS_WIDTH) +#define V_IO_CS_WIDTH(x) _SB_MAKEVALUE(x, S_IO_CS_WIDTH) +#define G_IO_CS_WIDTH(x) _SB_GETVALUE(x, S_IO_CS_WIDTH, M_IO_CS_WIDTH) #define S_IO_RDY_SMPLE 13 -#define M_IO_RDY_SMPLE _SB_MAKEMASK(3,S_IO_RDY_SMPLE) -#define V_IO_RDY_SMPLE(x) _SB_MAKEVALUE(x,S_IO_RDY_SMPLE) -#define G_IO_RDY_SMPLE(x) _SB_GETVALUE(x,S_IO_RDY_SMPLE,M_IO_RDY_SMPLE) +#define M_IO_RDY_SMPLE _SB_MAKEMASK(3, S_IO_RDY_SMPLE) +#define V_IO_RDY_SMPLE(x) _SB_MAKEVALUE(x, S_IO_RDY_SMPLE) +#define G_IO_RDY_SMPLE(x) _SB_GETVALUE(x, S_IO_RDY_SMPLE, M_IO_RDY_SMPLE) /* @@ -143,9 +143,9 @@ */ #define S_IO_ALE_TO_WRITE 0 -#define M_IO_ALE_TO_WRITE _SB_MAKEMASK(3,S_IO_ALE_TO_WRITE) -#define V_IO_ALE_TO_WRITE(x) _SB_MAKEVALUE(x,S_IO_ALE_TO_WRITE) -#define G_IO_ALE_TO_WRITE(x) _SB_GETVALUE(x,S_IO_ALE_TO_WRITE,M_IO_ALE_TO_WRITE) +#define M_IO_ALE_TO_WRITE _SB_MAKEMASK(3, S_IO_ALE_TO_WRITE) +#define V_IO_ALE_TO_WRITE(x) _SB_MAKEVALUE(x, S_IO_ALE_TO_WRITE) +#define G_IO_ALE_TO_WRITE(x) _SB_GETVALUE(x, S_IO_ALE_TO_WRITE, M_IO_ALE_TO_WRITE) #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) \ || SIBYTE_HDR_FEATURE_CHIP(1480) @@ -153,30 +153,30 @@ #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ #define S_IO_WRITE_WIDTH 4 -#define M_IO_WRITE_WIDTH _SB_MAKEMASK(4,S_IO_WRITE_WIDTH) -#define V_IO_WRITE_WIDTH(x) _SB_MAKEVALUE(x,S_IO_WRITE_WIDTH) -#define G_IO_WRITE_WIDTH(x) _SB_GETVALUE(x,S_IO_WRITE_WIDTH,M_IO_WRITE_WIDTH) +#define M_IO_WRITE_WIDTH _SB_MAKEMASK(4, S_IO_WRITE_WIDTH) +#define V_IO_WRITE_WIDTH(x) _SB_MAKEVALUE(x, S_IO_WRITE_WIDTH) +#define G_IO_WRITE_WIDTH(x) _SB_GETVALUE(x, S_IO_WRITE_WIDTH, M_IO_WRITE_WIDTH) #define S_IO_IDLE_CYCLE 8 -#define M_IO_IDLE_CYCLE _SB_MAKEMASK(4,S_IO_IDLE_CYCLE) -#define V_IO_IDLE_CYCLE(x) _SB_MAKEVALUE(x,S_IO_IDLE_CYCLE) -#define G_IO_IDLE_CYCLE(x) _SB_GETVALUE(x,S_IO_IDLE_CYCLE,M_IO_IDLE_CYCLE) +#define M_IO_IDLE_CYCLE _SB_MAKEMASK(4, S_IO_IDLE_CYCLE) +#define V_IO_IDLE_CYCLE(x) _SB_MAKEVALUE(x, S_IO_IDLE_CYCLE) +#define G_IO_IDLE_CYCLE(x) _SB_GETVALUE(x, S_IO_IDLE_CYCLE, M_IO_IDLE_CYCLE) #define S_IO_OE_TO_CS 12 -#define M_IO_OE_TO_CS _SB_MAKEMASK(2,S_IO_OE_TO_CS) -#define V_IO_OE_TO_CS(x) _SB_MAKEVALUE(x,S_IO_OE_TO_CS) -#define G_IO_OE_TO_CS(x) _SB_GETVALUE(x,S_IO_OE_TO_CS,M_IO_OE_TO_CS) +#define M_IO_OE_TO_CS _SB_MAKEMASK(2, S_IO_OE_TO_CS) +#define V_IO_OE_TO_CS(x) _SB_MAKEVALUE(x, S_IO_OE_TO_CS) +#define G_IO_OE_TO_CS(x) _SB_GETVALUE(x, S_IO_OE_TO_CS, M_IO_OE_TO_CS) #define S_IO_CS_TO_OE 14 -#define M_IO_CS_TO_OE _SB_MAKEMASK(2,S_IO_CS_TO_OE) -#define V_IO_CS_TO_OE(x) _SB_MAKEVALUE(x,S_IO_CS_TO_OE) -#define G_IO_CS_TO_OE(x) _SB_GETVALUE(x,S_IO_CS_TO_OE,M_IO_CS_TO_OE) +#define M_IO_CS_TO_OE _SB_MAKEMASK(2, S_IO_CS_TO_OE) +#define V_IO_CS_TO_OE(x) _SB_MAKEVALUE(x, S_IO_CS_TO_OE) +#define G_IO_CS_TO_OE(x) _SB_GETVALUE(x, S_IO_CS_TO_OE, M_IO_CS_TO_OE) /* * Generic Bus Interrupt Status Register (Table 11-9) */ -#define M_IO_CS_ERR_INT _SB_MAKEMASK(0,8) +#define M_IO_CS_ERR_INT _SB_MAKEMASK(0, 8) #define M_IO_CS0_ERR_INT _SB_MAKEMASK1(0) #define M_IO_CS1_ERR_INT _SB_MAKEMASK1(1) #define M_IO_CS2_ERR_INT _SB_MAKEMASK1(2) @@ -200,116 +200,116 @@ */ #define S_IO_SLEW0 0 -#define M_IO_SLEW0 _SB_MAKEMASK(2,S_IO_SLEW0) -#define V_IO_SLEW0(x) _SB_MAKEVALUE(x,S_IO_SLEW0) -#define G_IO_SLEW0(x) _SB_GETVALUE(x,S_IO_SLEW0,M_IO_SLEW0) +#define M_IO_SLEW0 _SB_MAKEMASK(2, S_IO_SLEW0) +#define V_IO_SLEW0(x) _SB_MAKEVALUE(x, S_IO_SLEW0) +#define G_IO_SLEW0(x) _SB_GETVALUE(x, S_IO_SLEW0, M_IO_SLEW0) #define S_IO_DRV_A 2 -#define M_IO_DRV_A _SB_MAKEMASK(2,S_IO_DRV_A) -#define V_IO_DRV_A(x) _SB_MAKEVALUE(x,S_IO_DRV_A) -#define G_IO_DRV_A(x) _SB_GETVALUE(x,S_IO_DRV_A,M_IO_DRV_A) +#define M_IO_DRV_A _SB_MAKEMASK(2, S_IO_DRV_A) +#define V_IO_DRV_A(x) _SB_MAKEVALUE(x, S_IO_DRV_A) +#define G_IO_DRV_A(x) _SB_GETVALUE(x, S_IO_DRV_A, M_IO_DRV_A) #define S_IO_DRV_B 6 -#define M_IO_DRV_B _SB_MAKEMASK(2,S_IO_DRV_B) -#define V_IO_DRV_B(x) _SB_MAKEVALUE(x,S_IO_DRV_B) -#define G_IO_DRV_B(x) _SB_GETVALUE(x,S_IO_DRV_B,M_IO_DRV_B) +#define M_IO_DRV_B _SB_MAKEMASK(2, S_IO_DRV_B) +#define V_IO_DRV_B(x) _SB_MAKEVALUE(x, S_IO_DRV_B) +#define G_IO_DRV_B(x) _SB_GETVALUE(x, S_IO_DRV_B, M_IO_DRV_B) #define S_IO_DRV_C 10 -#define M_IO_DRV_C _SB_MAKEMASK(2,S_IO_DRV_C) -#define V_IO_DRV_C(x) _SB_MAKEVALUE(x,S_IO_DRV_C) -#define G_IO_DRV_C(x) _SB_GETVALUE(x,S_IO_DRV_C,M_IO_DRV_C) +#define M_IO_DRV_C _SB_MAKEMASK(2, S_IO_DRV_C) +#define V_IO_DRV_C(x) _SB_MAKEVALUE(x, S_IO_DRV_C) +#define G_IO_DRV_C(x) _SB_GETVALUE(x, S_IO_DRV_C, M_IO_DRV_C) #define S_IO_DRV_D 14 -#define M_IO_DRV_D _SB_MAKEMASK(2,S_IO_DRV_D) -#define V_IO_DRV_D(x) _SB_MAKEVALUE(x,S_IO_DRV_D) -#define G_IO_DRV_D(x) _SB_GETVALUE(x,S_IO_DRV_D,M_IO_DRV_D) +#define M_IO_DRV_D _SB_MAKEMASK(2, S_IO_DRV_D) +#define V_IO_DRV_D(x) _SB_MAKEVALUE(x, S_IO_DRV_D) +#define G_IO_DRV_D(x) _SB_GETVALUE(x, S_IO_DRV_D, M_IO_DRV_D) /* * Generic Bus Output Drive Control Register 1 (Table 14-19) */ #define S_IO_DRV_E 2 -#define M_IO_DRV_E _SB_MAKEMASK(2,S_IO_DRV_E) -#define V_IO_DRV_E(x) _SB_MAKEVALUE(x,S_IO_DRV_E) -#define G_IO_DRV_E(x) _SB_GETVALUE(x,S_IO_DRV_E,M_IO_DRV_E) +#define M_IO_DRV_E _SB_MAKEMASK(2, S_IO_DRV_E) +#define V_IO_DRV_E(x) _SB_MAKEVALUE(x, S_IO_DRV_E) +#define G_IO_DRV_E(x) _SB_GETVALUE(x, S_IO_DRV_E, M_IO_DRV_E) #define S_IO_DRV_F 6 -#define M_IO_DRV_F _SB_MAKEMASK(2,S_IO_DRV_F) -#define V_IO_DRV_F(x) _SB_MAKEVALUE(x,S_IO_DRV_F) -#define G_IO_DRV_F(x) _SB_GETVALUE(x,S_IO_DRV_F,M_IO_DRV_F) +#define M_IO_DRV_F _SB_MAKEMASK(2, S_IO_DRV_F) +#define V_IO_DRV_F(x) _SB_MAKEVALUE(x, S_IO_DRV_F) +#define G_IO_DRV_F(x) _SB_GETVALUE(x, S_IO_DRV_F, M_IO_DRV_F) #define S_IO_SLEW1 8 -#define M_IO_SLEW1 _SB_MAKEMASK(2,S_IO_SLEW1) -#define V_IO_SLEW1(x) _SB_MAKEVALUE(x,S_IO_SLEW1) -#define G_IO_SLEW1(x) _SB_GETVALUE(x,S_IO_SLEW1,M_IO_SLEW1) +#define M_IO_SLEW1 _SB_MAKEMASK(2, S_IO_SLEW1) +#define V_IO_SLEW1(x) _SB_MAKEVALUE(x, S_IO_SLEW1) +#define G_IO_SLEW1(x) _SB_GETVALUE(x, S_IO_SLEW1, M_IO_SLEW1) #define S_IO_DRV_G 10 -#define M_IO_DRV_G _SB_MAKEMASK(2,S_IO_DRV_G) -#define V_IO_DRV_G(x) _SB_MAKEVALUE(x,S_IO_DRV_G) -#define G_IO_DRV_G(x) _SB_GETVALUE(x,S_IO_DRV_G,M_IO_DRV_G) +#define M_IO_DRV_G _SB_MAKEMASK(2, S_IO_DRV_G) +#define V_IO_DRV_G(x) _SB_MAKEVALUE(x, S_IO_DRV_G) +#define G_IO_DRV_G(x) _SB_GETVALUE(x, S_IO_DRV_G, M_IO_DRV_G) #define S_IO_SLEW2 12 -#define M_IO_SLEW2 _SB_MAKEMASK(2,S_IO_SLEW2) -#define V_IO_SLEW2(x) _SB_MAKEVALUE(x,S_IO_SLEW2) -#define G_IO_SLEW2(x) _SB_GETVALUE(x,S_IO_SLEW2,M_IO_SLEW2) +#define M_IO_SLEW2 _SB_MAKEMASK(2, S_IO_SLEW2) +#define V_IO_SLEW2(x) _SB_MAKEVALUE(x, S_IO_SLEW2) +#define G_IO_SLEW2(x) _SB_GETVALUE(x, S_IO_SLEW2, M_IO_SLEW2) #define S_IO_DRV_H 14 -#define M_IO_DRV_H _SB_MAKEMASK(2,S_IO_DRV_H) -#define V_IO_DRV_H(x) _SB_MAKEVALUE(x,S_IO_DRV_H) -#define G_IO_DRV_H(x) _SB_GETVALUE(x,S_IO_DRV_H,M_IO_DRV_H) +#define M_IO_DRV_H _SB_MAKEMASK(2, S_IO_DRV_H) +#define V_IO_DRV_H(x) _SB_MAKEVALUE(x, S_IO_DRV_H) +#define G_IO_DRV_H(x) _SB_GETVALUE(x, S_IO_DRV_H, M_IO_DRV_H) /* * Generic Bus Output Drive Control Register 2 (Table 14-20) */ #define S_IO_DRV_J 2 -#define M_IO_DRV_J _SB_MAKEMASK(2,S_IO_DRV_J) -#define V_IO_DRV_J(x) _SB_MAKEVALUE(x,S_IO_DRV_J) -#define G_IO_DRV_J(x) _SB_GETVALUE(x,S_IO_DRV_J,M_IO_DRV_J) +#define M_IO_DRV_J _SB_MAKEMASK(2, S_IO_DRV_J) +#define V_IO_DRV_J(x) _SB_MAKEVALUE(x, S_IO_DRV_J) +#define G_IO_DRV_J(x) _SB_GETVALUE(x, S_IO_DRV_J, M_IO_DRV_J) #define S_IO_DRV_K 6 -#define M_IO_DRV_K _SB_MAKEMASK(2,S_IO_DRV_K) -#define V_IO_DRV_K(x) _SB_MAKEVALUE(x,S_IO_DRV_K) -#define G_IO_DRV_K(x) _SB_GETVALUE(x,S_IO_DRV_K,M_IO_DRV_K) +#define M_IO_DRV_K _SB_MAKEMASK(2, S_IO_DRV_K) +#define V_IO_DRV_K(x) _SB_MAKEVALUE(x, S_IO_DRV_K) +#define G_IO_DRV_K(x) _SB_GETVALUE(x, S_IO_DRV_K, M_IO_DRV_K) #define S_IO_DRV_L 10 -#define M_IO_DRV_L _SB_MAKEMASK(2,S_IO_DRV_L) -#define V_IO_DRV_L(x) _SB_MAKEVALUE(x,S_IO_DRV_L) -#define G_IO_DRV_L(x) _SB_GETVALUE(x,S_IO_DRV_L,M_IO_DRV_L) +#define M_IO_DRV_L _SB_MAKEMASK(2, S_IO_DRV_L) +#define V_IO_DRV_L(x) _SB_MAKEVALUE(x, S_IO_DRV_L) +#define G_IO_DRV_L(x) _SB_GETVALUE(x, S_IO_DRV_L, M_IO_DRV_L) #define S_IO_DRV_M 14 -#define M_IO_DRV_M _SB_MAKEMASK(2,S_IO_DRV_M) -#define V_IO_DRV_M(x) _SB_MAKEVALUE(x,S_IO_DRV_M) -#define G_IO_DRV_M(x) _SB_GETVALUE(x,S_IO_DRV_M,M_IO_DRV_M) +#define M_IO_DRV_M _SB_MAKEMASK(2, S_IO_DRV_M) +#define V_IO_DRV_M(x) _SB_MAKEVALUE(x, S_IO_DRV_M) +#define G_IO_DRV_M(x) _SB_GETVALUE(x, S_IO_DRV_M, M_IO_DRV_M) /* * Generic Bus Output Drive Control Register 3 (Table 14-21) */ #define S_IO_SLEW3 0 -#define M_IO_SLEW3 _SB_MAKEMASK(2,S_IO_SLEW3) -#define V_IO_SLEW3(x) _SB_MAKEVALUE(x,S_IO_SLEW3) -#define G_IO_SLEW3(x) _SB_GETVALUE(x,S_IO_SLEW3,M_IO_SLEW3) +#define M_IO_SLEW3 _SB_MAKEMASK(2, S_IO_SLEW3) +#define V_IO_SLEW3(x) _SB_MAKEVALUE(x, S_IO_SLEW3) +#define G_IO_SLEW3(x) _SB_GETVALUE(x, S_IO_SLEW3, M_IO_SLEW3) #define S_IO_DRV_N 2 -#define M_IO_DRV_N _SB_MAKEMASK(2,S_IO_DRV_N) -#define V_IO_DRV_N(x) _SB_MAKEVALUE(x,S_IO_DRV_N) -#define G_IO_DRV_N(x) _SB_GETVALUE(x,S_IO_DRV_N,M_IO_DRV_N) +#define M_IO_DRV_N _SB_MAKEMASK(2, S_IO_DRV_N) +#define V_IO_DRV_N(x) _SB_MAKEVALUE(x, S_IO_DRV_N) +#define G_IO_DRV_N(x) _SB_GETVALUE(x, S_IO_DRV_N, M_IO_DRV_N) #define S_IO_DRV_P 6 -#define M_IO_DRV_P _SB_MAKEMASK(2,S_IO_DRV_P) -#define V_IO_DRV_P(x) _SB_MAKEVALUE(x,S_IO_DRV_P) -#define G_IO_DRV_P(x) _SB_GETVALUE(x,S_IO_DRV_P,M_IO_DRV_P) +#define M_IO_DRV_P _SB_MAKEMASK(2, S_IO_DRV_P) +#define V_IO_DRV_P(x) _SB_MAKEVALUE(x, S_IO_DRV_P) +#define G_IO_DRV_P(x) _SB_GETVALUE(x, S_IO_DRV_P, M_IO_DRV_P) #define S_IO_DRV_Q 10 -#define M_IO_DRV_Q _SB_MAKEMASK(2,S_IO_DRV_Q) -#define V_IO_DRV_Q(x) _SB_MAKEVALUE(x,S_IO_DRV_Q) -#define G_IO_DRV_Q(x) _SB_GETVALUE(x,S_IO_DRV_Q,M_IO_DRV_Q) +#define M_IO_DRV_Q _SB_MAKEMASK(2, S_IO_DRV_Q) +#define V_IO_DRV_Q(x) _SB_MAKEVALUE(x, S_IO_DRV_Q) +#define G_IO_DRV_Q(x) _SB_GETVALUE(x, S_IO_DRV_Q, M_IO_DRV_Q) #define S_IO_DRV_R 14 -#define M_IO_DRV_R _SB_MAKEMASK(2,S_IO_DRV_R) -#define V_IO_DRV_R(x) _SB_MAKEVALUE(x,S_IO_DRV_R) -#define G_IO_DRV_R(x) _SB_GETVALUE(x,S_IO_DRV_R,M_IO_DRV_R) +#define M_IO_DRV_R _SB_MAKEMASK(2, S_IO_DRV_R) +#define V_IO_DRV_R(x) _SB_MAKEVALUE(x, S_IO_DRV_R) +#define G_IO_DRV_R(x) _SB_GETVALUE(x, S_IO_DRV_R, M_IO_DRV_R) /* @@ -329,9 +329,9 @@ #if SIBYTE_HDR_FEATURE_CHIP(1480) #define S_PCMCIA_MODE 16 -#define M_PCMCIA_MODE _SB_MAKEMASK(3,S_PCMCIA_MODE) -#define V_PCMCIA_MODE(x) _SB_MAKEVALUE(x,S_PCMCIA_MODE) -#define G_PCMCIA_MODE(x) _SB_GETVALUE(x,S_PCMCIA_MODE,M_PCMCIA_MODE) +#define M_PCMCIA_MODE _SB_MAKEMASK(3, S_PCMCIA_MODE) +#define V_PCMCIA_MODE(x) _SB_MAKEVALUE(x, S_PCMCIA_MODE) +#define G_PCMCIA_MODE(x) _SB_GETVALUE(x, S_PCMCIA_MODE, M_PCMCIA_MODE) #define K_PCMCIA_MODE_PCMA_NOB 0 /* standard PCMCIA "A", no "B" */ #define K_PCMCIA_MODE_IDEA_NOB 1 /* IDE "A", no "B" */ @@ -369,49 +369,49 @@ #define K_GPIO_INTR_SPLIT 3 #define S_GPIO_INTR_TYPEX(n) (((n)/2)*2) -#define M_GPIO_INTR_TYPEX(n) _SB_MAKEMASK(2,S_GPIO_INTR_TYPEX(n)) -#define V_GPIO_INTR_TYPEX(n,x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPEX(n)) -#define G_GPIO_INTR_TYPEX(n,x) _SB_GETVALUE(x,S_GPIO_INTR_TYPEX(n),M_GPIO_INTR_TYPEX(n)) +#define M_GPIO_INTR_TYPEX(n) _SB_MAKEMASK(2, S_GPIO_INTR_TYPEX(n)) +#define V_GPIO_INTR_TYPEX(n, x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPEX(n)) +#define G_GPIO_INTR_TYPEX(n, x) _SB_GETVALUE(x, S_GPIO_INTR_TYPEX(n), M_GPIO_INTR_TYPEX(n)) #define S_GPIO_INTR_TYPE0 0 -#define M_GPIO_INTR_TYPE0 _SB_MAKEMASK(2,S_GPIO_INTR_TYPE0) -#define V_GPIO_INTR_TYPE0(x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPE0) -#define G_GPIO_INTR_TYPE0(x) _SB_GETVALUE(x,S_GPIO_INTR_TYPE0,M_GPIO_INTR_TYPE0) +#define M_GPIO_INTR_TYPE0 _SB_MAKEMASK(2, S_GPIO_INTR_TYPE0) +#define V_GPIO_INTR_TYPE0(x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPE0) +#define G_GPIO_INTR_TYPE0(x) _SB_GETVALUE(x, S_GPIO_INTR_TYPE0, M_GPIO_INTR_TYPE0) #define S_GPIO_INTR_TYPE2 2 -#define M_GPIO_INTR_TYPE2 _SB_MAKEMASK(2,S_GPIO_INTR_TYPE2) -#define V_GPIO_INTR_TYPE2(x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPE2) -#define G_GPIO_INTR_TYPE2(x) _SB_GETVALUE(x,S_GPIO_INTR_TYPE2,M_GPIO_INTR_TYPE2) +#define M_GPIO_INTR_TYPE2 _SB_MAKEMASK(2, S_GPIO_INTR_TYPE2) +#define V_GPIO_INTR_TYPE2(x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPE2) +#define G_GPIO_INTR_TYPE2(x) _SB_GETVALUE(x, S_GPIO_INTR_TYPE2, M_GPIO_INTR_TYPE2) #define S_GPIO_INTR_TYPE4 4 -#define M_GPIO_INTR_TYPE4 _SB_MAKEMASK(2,S_GPIO_INTR_TYPE4) -#define V_GPIO_INTR_TYPE4(x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPE4) -#define G_GPIO_INTR_TYPE4(x) _SB_GETVALUE(x,S_GPIO_INTR_TYPE4,M_GPIO_INTR_TYPE4) +#define M_GPIO_INTR_TYPE4 _SB_MAKEMASK(2, S_GPIO_INTR_TYPE4) +#define V_GPIO_INTR_TYPE4(x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPE4) +#define G_GPIO_INTR_TYPE4(x) _SB_GETVALUE(x, S_GPIO_INTR_TYPE4, M_GPIO_INTR_TYPE4) #define S_GPIO_INTR_TYPE6 6 -#define M_GPIO_INTR_TYPE6 _SB_MAKEMASK(2,S_GPIO_INTR_TYPE6) -#define V_GPIO_INTR_TYPE6(x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPE6) -#define G_GPIO_INTR_TYPE6(x) _SB_GETVALUE(x,S_GPIO_INTR_TYPE6,M_GPIO_INTR_TYPE6) +#define M_GPIO_INTR_TYPE6 _SB_MAKEMASK(2, S_GPIO_INTR_TYPE6) +#define V_GPIO_INTR_TYPE6(x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPE6) +#define G_GPIO_INTR_TYPE6(x) _SB_GETVALUE(x, S_GPIO_INTR_TYPE6, M_GPIO_INTR_TYPE6) #define S_GPIO_INTR_TYPE8 8 -#define M_GPIO_INTR_TYPE8 _SB_MAKEMASK(2,S_GPIO_INTR_TYPE8) -#define V_GPIO_INTR_TYPE8(x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPE8) -#define G_GPIO_INTR_TYPE8(x) _SB_GETVALUE(x,S_GPIO_INTR_TYPE8,M_GPIO_INTR_TYPE8) +#define M_GPIO_INTR_TYPE8 _SB_MAKEMASK(2, S_GPIO_INTR_TYPE8) +#define V_GPIO_INTR_TYPE8(x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPE8) +#define G_GPIO_INTR_TYPE8(x) _SB_GETVALUE(x, S_GPIO_INTR_TYPE8, M_GPIO_INTR_TYPE8) #define S_GPIO_INTR_TYPE10 10 -#define M_GPIO_INTR_TYPE10 _SB_MAKEMASK(2,S_GPIO_INTR_TYPE10) -#define V_GPIO_INTR_TYPE10(x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPE10) -#define G_GPIO_INTR_TYPE10(x) _SB_GETVALUE(x,S_GPIO_INTR_TYPE10,M_GPIO_INTR_TYPE10) +#define M_GPIO_INTR_TYPE10 _SB_MAKEMASK(2, S_GPIO_INTR_TYPE10) +#define V_GPIO_INTR_TYPE10(x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPE10) +#define G_GPIO_INTR_TYPE10(x) _SB_GETVALUE(x, S_GPIO_INTR_TYPE10, M_GPIO_INTR_TYPE10) #define S_GPIO_INTR_TYPE12 12 -#define M_GPIO_INTR_TYPE12 _SB_MAKEMASK(2,S_GPIO_INTR_TYPE12) -#define V_GPIO_INTR_TYPE12(x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPE12) -#define G_GPIO_INTR_TYPE12(x) _SB_GETVALUE(x,S_GPIO_INTR_TYPE12,M_GPIO_INTR_TYPE12) +#define M_GPIO_INTR_TYPE12 _SB_MAKEMASK(2, S_GPIO_INTR_TYPE12) +#define V_GPIO_INTR_TYPE12(x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPE12) +#define G_GPIO_INTR_TYPE12(x) _SB_GETVALUE(x, S_GPIO_INTR_TYPE12, M_GPIO_INTR_TYPE12) #define S_GPIO_INTR_TYPE14 14 -#define M_GPIO_INTR_TYPE14 _SB_MAKEMASK(2,S_GPIO_INTR_TYPE14) -#define V_GPIO_INTR_TYPE14(x) _SB_MAKEVALUE(x,S_GPIO_INTR_TYPE14) -#define G_GPIO_INTR_TYPE14(x) _SB_GETVALUE(x,S_GPIO_INTR_TYPE14,M_GPIO_INTR_TYPE14) +#define M_GPIO_INTR_TYPE14 _SB_MAKEMASK(2, S_GPIO_INTR_TYPE14) +#define V_GPIO_INTR_TYPE14(x) _SB_MAKEVALUE(x, S_GPIO_INTR_TYPE14) +#define G_GPIO_INTR_TYPE14(x) _SB_GETVALUE(x, S_GPIO_INTR_TYPE14, M_GPIO_INTR_TYPE14) #if SIBYTE_HDR_FEATURE_CHIP(1480) @@ -425,49 +425,49 @@ #define K_GPIO_INTR_UNPRED2 3 #define S_GPIO_INTR_ATYPEX(n) (((n)/2)*2) -#define M_GPIO_INTR_ATYPEX(n) _SB_MAKEMASK(2,S_GPIO_INTR_ATYPEX(n)) -#define V_GPIO_INTR_ATYPEX(n,x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPEX(n)) -#define G_GPIO_INTR_ATYPEX(n,x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPEX(n),M_GPIO_INTR_ATYPEX(n)) +#define M_GPIO_INTR_ATYPEX(n) _SB_MAKEMASK(2, S_GPIO_INTR_ATYPEX(n)) +#define V_GPIO_INTR_ATYPEX(n, x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPEX(n)) +#define G_GPIO_INTR_ATYPEX(n, x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPEX(n), M_GPIO_INTR_ATYPEX(n)) #define S_GPIO_INTR_ATYPE0 0 -#define M_GPIO_INTR_ATYPE0 _SB_MAKEMASK(2,S_GPIO_INTR_ATYPE0) -#define V_GPIO_INTR_ATYPE0(x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPE0) -#define G_GPIO_INTR_ATYPE0(x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPE0,M_GPIO_INTR_ATYPE0) +#define M_GPIO_INTR_ATYPE0 _SB_MAKEMASK(2, S_GPIO_INTR_ATYPE0) +#define V_GPIO_INTR_ATYPE0(x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPE0) +#define G_GPIO_INTR_ATYPE0(x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPE0, M_GPIO_INTR_ATYPE0) #define S_GPIO_INTR_ATYPE2 2 -#define M_GPIO_INTR_ATYPE2 _SB_MAKEMASK(2,S_GPIO_INTR_ATYPE2) -#define V_GPIO_INTR_ATYPE2(x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPE2) -#define G_GPIO_INTR_ATYPE2(x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPE2,M_GPIO_INTR_ATYPE2) +#define M_GPIO_INTR_ATYPE2 _SB_MAKEMASK(2, S_GPIO_INTR_ATYPE2) +#define V_GPIO_INTR_ATYPE2(x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPE2) +#define G_GPIO_INTR_ATYPE2(x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPE2, M_GPIO_INTR_ATYPE2) #define S_GPIO_INTR_ATYPE4 4 -#define M_GPIO_INTR_ATYPE4 _SB_MAKEMASK(2,S_GPIO_INTR_ATYPE4) -#define V_GPIO_INTR_ATYPE4(x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPE4) -#define G_GPIO_INTR_ATYPE4(x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPE4,M_GPIO_INTR_ATYPE4) +#define M_GPIO_INTR_ATYPE4 _SB_MAKEMASK(2, S_GPIO_INTR_ATYPE4) +#define V_GPIO_INTR_ATYPE4(x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPE4) +#define G_GPIO_INTR_ATYPE4(x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPE4, M_GPIO_INTR_ATYPE4) #define S_GPIO_INTR_ATYPE6 6 -#define M_GPIO_INTR_ATYPE6 _SB_MAKEMASK(2,S_GPIO_INTR_ATYPE6) -#define V_GPIO_INTR_ATYPE6(x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPE6) -#define G_GPIO_INTR_ATYPE6(x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPE6,M_GPIO_INTR_ATYPE6) +#define M_GPIO_INTR_ATYPE6 _SB_MAKEMASK(2, S_GPIO_INTR_ATYPE6) +#define V_GPIO_INTR_ATYPE6(x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPE6) +#define G_GPIO_INTR_ATYPE6(x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPE6, M_GPIO_INTR_ATYPE6) #define S_GPIO_INTR_ATYPE8 8 -#define M_GPIO_INTR_ATYPE8 _SB_MAKEMASK(2,S_GPIO_INTR_ATYPE8) -#define V_GPIO_INTR_ATYPE8(x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPE8) -#define G_GPIO_INTR_ATYPE8(x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPE8,M_GPIO_INTR_ATYPE8) +#define M_GPIO_INTR_ATYPE8 _SB_MAKEMASK(2, S_GPIO_INTR_ATYPE8) +#define V_GPIO_INTR_ATYPE8(x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPE8) +#define G_GPIO_INTR_ATYPE8(x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPE8, M_GPIO_INTR_ATYPE8) #define S_GPIO_INTR_ATYPE10 10 -#define M_GPIO_INTR_ATYPE10 _SB_MAKEMASK(2,S_GPIO_INTR_ATYPE10) -#define V_GPIO_INTR_ATYPE10(x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPE10) -#define G_GPIO_INTR_ATYPE10(x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPE10,M_GPIO_INTR_ATYPE10) +#define M_GPIO_INTR_ATYPE10 _SB_MAKEMASK(2, S_GPIO_INTR_ATYPE10) +#define V_GPIO_INTR_ATYPE10(x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPE10) +#define G_GPIO_INTR_ATYPE10(x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPE10, M_GPIO_INTR_ATYPE10) #define S_GPIO_INTR_ATYPE12 12 -#define M_GPIO_INTR_ATYPE12 _SB_MAKEMASK(2,S_GPIO_INTR_ATYPE12) -#define V_GPIO_INTR_ATYPE12(x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPE12) -#define G_GPIO_INTR_ATYPE12(x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPE12,M_GPIO_INTR_ATYPE12) +#define M_GPIO_INTR_ATYPE12 _SB_MAKEMASK(2, S_GPIO_INTR_ATYPE12) +#define V_GPIO_INTR_ATYPE12(x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPE12) +#define G_GPIO_INTR_ATYPE12(x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPE12, M_GPIO_INTR_ATYPE12) #define S_GPIO_INTR_ATYPE14 14 -#define M_GPIO_INTR_ATYPE14 _SB_MAKEMASK(2,S_GPIO_INTR_ATYPE14) -#define V_GPIO_INTR_ATYPE14(x) _SB_MAKEVALUE(x,S_GPIO_INTR_ATYPE14) -#define G_GPIO_INTR_ATYPE14(x) _SB_GETVALUE(x,S_GPIO_INTR_ATYPE14,M_GPIO_INTR_ATYPE14) +#define M_GPIO_INTR_ATYPE14 _SB_MAKEMASK(2, S_GPIO_INTR_ATYPE14) +#define V_GPIO_INTR_ATYPE14(x) _SB_MAKEVALUE(x, S_GPIO_INTR_ATYPE14) +#define G_GPIO_INTR_ATYPE14(x) _SB_GETVALUE(x, S_GPIO_INTR_ATYPE14, M_GPIO_INTR_ATYPE14) #endif diff --git a/include/asm-mips/sibyte/sb1250_int.h b/include/asm-mips/sibyte/sb1250_int.h index 94e8299b0a2a..f2850b4bcfd4 100644 --- a/include/asm-mips/sibyte/sb1250_int.h +++ b/include/asm-mips/sibyte/sb1250_int.h @@ -10,7 +10,7 @@ * ********************************************************************* * - * Copyright 2000,2001,2002,2003 + * Copyright 2000, 2001, 2002, 2003 * Broadcom Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or @@ -150,7 +150,7 @@ #define M_INT_MBOX_1 _SB_MAKEMASK1(K_INT_MBOX_1) #define M_INT_MBOX_2 _SB_MAKEMASK1(K_INT_MBOX_2) #define M_INT_MBOX_3 _SB_MAKEMASK1(K_INT_MBOX_3) -#define M_INT_MBOX_ALL _SB_MAKEMASK(4,K_INT_MBOX_0) +#define M_INT_MBOX_ALL _SB_MAKEMASK(4, K_INT_MBOX_0) #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) #define M_INT_CYCLE_CP0_INT _SB_MAKEMASK1(K_INT_CYCLE_CP0_INT) #define M_INT_CYCLE_CP1_INT _SB_MAKEMASK1(K_INT_CYCLE_CP1_INT) @@ -208,9 +208,9 @@ */ #define S_INT_LDT_INTMSG 0 -#define M_INT_LDT_INTMSG _SB_MAKEMASK(3,S_INT_LDT_INTMSG) -#define V_INT_LDT_INTMSG(x) _SB_MAKEVALUE(x,S_INT_LDT_INTMSG) -#define G_INT_LDT_INTMSG(x) _SB_GETVALUE(x,S_INT_LDT_INTMSG,M_INT_LDT_INTMSG) +#define M_INT_LDT_INTMSG _SB_MAKEMASK(3, S_INT_LDT_INTMSG) +#define V_INT_LDT_INTMSG(x) _SB_MAKEVALUE(x, S_INT_LDT_INTMSG) +#define G_INT_LDT_INTMSG(x) _SB_GETVALUE(x, S_INT_LDT_INTMSG, M_INT_LDT_INTMSG) #define K_INT_LDT_INTMSG_FIXED 0 #define K_INT_LDT_INTMSG_ARBITRATED 1 @@ -228,14 +228,14 @@ #define M_INT_LDT_LOGICALDEST _SB_MAKEMASK1(4) #define S_INT_LDT_INTDEST 5 -#define M_INT_LDT_INTDEST _SB_MAKEMASK(10,S_INT_LDT_INTDEST) -#define V_INT_LDT_INTDEST(x) _SB_MAKEVALUE(x,S_INT_LDT_INTDEST) -#define G_INT_LDT_INTDEST(x) _SB_GETVALUE(x,S_INT_LDT_INTDEST,M_INT_LDT_INTDEST) +#define M_INT_LDT_INTDEST _SB_MAKEMASK(10, S_INT_LDT_INTDEST) +#define V_INT_LDT_INTDEST(x) _SB_MAKEVALUE(x, S_INT_LDT_INTDEST) +#define G_INT_LDT_INTDEST(x) _SB_GETVALUE(x, S_INT_LDT_INTDEST, M_INT_LDT_INTDEST) #define S_INT_LDT_VECTOR 13 -#define M_INT_LDT_VECTOR _SB_MAKEMASK(8,S_INT_LDT_VECTOR) -#define V_INT_LDT_VECTOR(x) _SB_MAKEVALUE(x,S_INT_LDT_VECTOR) -#define G_INT_LDT_VECTOR(x) _SB_GETVALUE(x,S_INT_LDT_VECTOR,M_INT_LDT_VECTOR) +#define M_INT_LDT_VECTOR _SB_MAKEMASK(8, S_INT_LDT_VECTOR) +#define V_INT_LDT_VECTOR(x) _SB_MAKEVALUE(x, S_INT_LDT_VECTOR) +#define G_INT_LDT_VECTOR(x) _SB_GETVALUE(x, S_INT_LDT_VECTOR, M_INT_LDT_VECTOR) /* * Vector format (Table 4-6) diff --git a/include/asm-mips/sibyte/sb1250_l2c.h b/include/asm-mips/sibyte/sb1250_l2c.h index 842f205094af..6554dcf05cfe 100644 --- a/include/asm-mips/sibyte/sb1250_l2c.h +++ b/include/asm-mips/sibyte/sb1250_l2c.h @@ -40,27 +40,27 @@ */ #define S_L2C_TAG_MBZ 0 -#define M_L2C_TAG_MBZ _SB_MAKEMASK(5,S_L2C_TAG_MBZ) +#define M_L2C_TAG_MBZ _SB_MAKEMASK(5, S_L2C_TAG_MBZ) #define S_L2C_TAG_INDEX 5 -#define M_L2C_TAG_INDEX _SB_MAKEMASK(12,S_L2C_TAG_INDEX) -#define V_L2C_TAG_INDEX(x) _SB_MAKEVALUE(x,S_L2C_TAG_INDEX) -#define G_L2C_TAG_INDEX(x) _SB_GETVALUE(x,S_L2C_TAG_INDEX,M_L2C_TAG_INDEX) +#define M_L2C_TAG_INDEX _SB_MAKEMASK(12, S_L2C_TAG_INDEX) +#define V_L2C_TAG_INDEX(x) _SB_MAKEVALUE(x, S_L2C_TAG_INDEX) +#define G_L2C_TAG_INDEX(x) _SB_GETVALUE(x, S_L2C_TAG_INDEX, M_L2C_TAG_INDEX) #define S_L2C_TAG_TAG 17 -#define M_L2C_TAG_TAG _SB_MAKEMASK(23,S_L2C_TAG_TAG) -#define V_L2C_TAG_TAG(x) _SB_MAKEVALUE(x,S_L2C_TAG_TAG) -#define G_L2C_TAG_TAG(x) _SB_GETVALUE(x,S_L2C_TAG_TAG,M_L2C_TAG_TAG) +#define M_L2C_TAG_TAG _SB_MAKEMASK(23, S_L2C_TAG_TAG) +#define V_L2C_TAG_TAG(x) _SB_MAKEVALUE(x, S_L2C_TAG_TAG) +#define G_L2C_TAG_TAG(x) _SB_GETVALUE(x, S_L2C_TAG_TAG, M_L2C_TAG_TAG) #define S_L2C_TAG_ECC 40 -#define M_L2C_TAG_ECC _SB_MAKEMASK(6,S_L2C_TAG_ECC) -#define V_L2C_TAG_ECC(x) _SB_MAKEVALUE(x,S_L2C_TAG_ECC) -#define G_L2C_TAG_ECC(x) _SB_GETVALUE(x,S_L2C_TAG_ECC,M_L2C_TAG_ECC) +#define M_L2C_TAG_ECC _SB_MAKEMASK(6, S_L2C_TAG_ECC) +#define V_L2C_TAG_ECC(x) _SB_MAKEVALUE(x, S_L2C_TAG_ECC) +#define G_L2C_TAG_ECC(x) _SB_GETVALUE(x, S_L2C_TAG_ECC, M_L2C_TAG_ECC) #define S_L2C_TAG_WAY 46 -#define M_L2C_TAG_WAY _SB_MAKEMASK(2,S_L2C_TAG_WAY) -#define V_L2C_TAG_WAY(x) _SB_MAKEVALUE(x,S_L2C_TAG_WAY) -#define G_L2C_TAG_WAY(x) _SB_GETVALUE(x,S_L2C_TAG_WAY,M_L2C_TAG_WAY) +#define M_L2C_TAG_WAY _SB_MAKEMASK(2, S_L2C_TAG_WAY) +#define V_L2C_TAG_WAY(x) _SB_MAKEVALUE(x, S_L2C_TAG_WAY) +#define G_L2C_TAG_WAY(x) _SB_GETVALUE(x, S_L2C_TAG_WAY, M_L2C_TAG_WAY) #define M_L2C_TAG_DIRTY _SB_MAKEMASK1(48) #define M_L2C_TAG_VALID _SB_MAKEMASK1(49) @@ -70,32 +70,32 @@ */ #define S_L2C_MGMT_INDEX 5 -#define M_L2C_MGMT_INDEX _SB_MAKEMASK(12,S_L2C_MGMT_INDEX) -#define V_L2C_MGMT_INDEX(x) _SB_MAKEVALUE(x,S_L2C_MGMT_INDEX) -#define G_L2C_MGMT_INDEX(x) _SB_GETVALUE(x,S_L2C_MGMT_INDEX,M_L2C_MGMT_INDEX) +#define M_L2C_MGMT_INDEX _SB_MAKEMASK(12, S_L2C_MGMT_INDEX) +#define V_L2C_MGMT_INDEX(x) _SB_MAKEVALUE(x, S_L2C_MGMT_INDEX) +#define G_L2C_MGMT_INDEX(x) _SB_GETVALUE(x, S_L2C_MGMT_INDEX, M_L2C_MGMT_INDEX) #define S_L2C_MGMT_QUADRANT 15 -#define M_L2C_MGMT_QUADRANT _SB_MAKEMASK(2,S_L2C_MGMT_QUADRANT) -#define V_L2C_MGMT_QUADRANT(x) _SB_MAKEVALUE(x,S_L2C_MGMT_QUADRANT) -#define G_L2C_MGMT_QUADRANT(x) _SB_GETVALUE(x,S_L2C_MGMT_QUADRANT,M_L2C_MGMT_QUADRANT) +#define M_L2C_MGMT_QUADRANT _SB_MAKEMASK(2, S_L2C_MGMT_QUADRANT) +#define V_L2C_MGMT_QUADRANT(x) _SB_MAKEVALUE(x, S_L2C_MGMT_QUADRANT) +#define G_L2C_MGMT_QUADRANT(x) _SB_GETVALUE(x, S_L2C_MGMT_QUADRANT, M_L2C_MGMT_QUADRANT) #define S_L2C_MGMT_HALF 16 -#define M_L2C_MGMT_HALF _SB_MAKEMASK(1,S_L2C_MGMT_HALF) +#define M_L2C_MGMT_HALF _SB_MAKEMASK(1, S_L2C_MGMT_HALF) #define S_L2C_MGMT_WAY 17 -#define M_L2C_MGMT_WAY _SB_MAKEMASK(2,S_L2C_MGMT_WAY) -#define V_L2C_MGMT_WAY(x) _SB_MAKEVALUE(x,S_L2C_MGMT_WAY) -#define G_L2C_MGMT_WAY(x) _SB_GETVALUE(x,S_L2C_MGMT_WAY,M_L2C_MGMT_WAY) +#define M_L2C_MGMT_WAY _SB_MAKEMASK(2, S_L2C_MGMT_WAY) +#define V_L2C_MGMT_WAY(x) _SB_MAKEVALUE(x, S_L2C_MGMT_WAY) +#define G_L2C_MGMT_WAY(x) _SB_GETVALUE(x, S_L2C_MGMT_WAY, M_L2C_MGMT_WAY) #define S_L2C_MGMT_ECC_DIAG 21 -#define M_L2C_MGMT_ECC_DIAG _SB_MAKEMASK(2,S_L2C_MGMT_ECC_DIAG) -#define V_L2C_MGMT_ECC_DIAG(x) _SB_MAKEVALUE(x,S_L2C_MGMT_ECC_DIAG) -#define G_L2C_MGMT_ECC_DIAG(x) _SB_GETVALUE(x,S_L2C_MGMT_ECC_DIAG,M_L2C_MGMT_ECC_DIAG) +#define M_L2C_MGMT_ECC_DIAG _SB_MAKEMASK(2, S_L2C_MGMT_ECC_DIAG) +#define V_L2C_MGMT_ECC_DIAG(x) _SB_MAKEVALUE(x, S_L2C_MGMT_ECC_DIAG) +#define G_L2C_MGMT_ECC_DIAG(x) _SB_GETVALUE(x, S_L2C_MGMT_ECC_DIAG, M_L2C_MGMT_ECC_DIAG) #define S_L2C_MGMT_TAG 23 -#define M_L2C_MGMT_TAG _SB_MAKEMASK(4,S_L2C_MGMT_TAG) -#define V_L2C_MGMT_TAG(x) _SB_MAKEVALUE(x,S_L2C_MGMT_TAG) -#define G_L2C_MGMT_TAG(x) _SB_GETVALUE(x,S_L2C_MGMT_TAG,M_L2C_MGMT_TAG) +#define M_L2C_MGMT_TAG _SB_MAKEMASK(4, S_L2C_MGMT_TAG) +#define V_L2C_MGMT_TAG(x) _SB_MAKEVALUE(x, S_L2C_MGMT_TAG) +#define G_L2C_MGMT_TAG(x) _SB_GETVALUE(x, S_L2C_MGMT_TAG, M_L2C_MGMT_TAG) #define M_L2C_MGMT_DIRTY _SB_MAKEMASK1(19) #define M_L2C_MGMT_VALID _SB_MAKEMASK1(20) @@ -111,9 +111,9 @@ * L2 Read Misc. register (A_L2_READ_MISC) */ #define S_L2C_MISC_NO_WAY 10 -#define M_L2C_MISC_NO_WAY _SB_MAKEMASK(4,S_L2C_MISC_NO_WAY) -#define V_L2C_MISC_NO_WAY(x) _SB_MAKEVALUE(x,S_L2C_MISC_NO_WAY) -#define G_L2C_MISC_NO_WAY(x) _SB_GETVALUE(x,S_L2C_MISC_NO_WAY,M_L2C_MISC_NO_WAY) +#define M_L2C_MISC_NO_WAY _SB_MAKEMASK(4, S_L2C_MISC_NO_WAY) +#define V_L2C_MISC_NO_WAY(x) _SB_MAKEVALUE(x, S_L2C_MISC_NO_WAY) +#define G_L2C_MISC_NO_WAY(x) _SB_GETVALUE(x, S_L2C_MISC_NO_WAY, M_L2C_MISC_NO_WAY) #define M_L2C_MISC_ECC_CLEANUP_DIS _SB_MAKEMASK1(9) #define M_L2C_MISC_MC_PRIO_LOW _SB_MAKEMASK1(8) diff --git a/include/asm-mips/sibyte/sb1250_ldt.h b/include/asm-mips/sibyte/sb1250_ldt.h index 7092535d1108..081e8b1c4ad0 100644 --- a/include/asm-mips/sibyte/sb1250_ldt.h +++ b/include/asm-mips/sibyte/sb1250_ldt.h @@ -10,7 +10,7 @@ * ********************************************************************* * - * Copyright 2000,2001,2002,2003 + * Copyright 2000, 2001, 2002, 2003 * Broadcom Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or @@ -81,14 +81,14 @@ */ #define S_LDT_DEVICEID_VENDOR 0 -#define M_LDT_DEVICEID_VENDOR _SB_MAKEMASK_32(16,S_LDT_DEVICEID_VENDOR) -#define V_LDT_DEVICEID_VENDOR(x) _SB_MAKEVALUE_32(x,S_LDT_DEVICEID_VENDOR) -#define G_LDT_DEVICEID_VENDOR(x) _SB_GETVALUE_32(x,S_LDT_DEVICEID_VENDOR,M_LDT_DEVICEID_VENDOR) +#define M_LDT_DEVICEID_VENDOR _SB_MAKEMASK_32(16, S_LDT_DEVICEID_VENDOR) +#define V_LDT_DEVICEID_VENDOR(x) _SB_MAKEVALUE_32(x, S_LDT_DEVICEID_VENDOR) +#define G_LDT_DEVICEID_VENDOR(x) _SB_GETVALUE_32(x, S_LDT_DEVICEID_VENDOR, M_LDT_DEVICEID_VENDOR) #define S_LDT_DEVICEID_DEVICEID 16 -#define M_LDT_DEVICEID_DEVICEID _SB_MAKEMASK_32(16,S_LDT_DEVICEID_DEVICEID) -#define V_LDT_DEVICEID_DEVICEID(x) _SB_MAKEVALUE_32(x,S_LDT_DEVICEID_DEVICEID) -#define G_LDT_DEVICEID_DEVICEID(x) _SB_GETVALUE_32(x,S_LDT_DEVICEID_DEVICEID,M_LDT_DEVICEID_DEVICEID) +#define M_LDT_DEVICEID_DEVICEID _SB_MAKEMASK_32(16, S_LDT_DEVICEID_DEVICEID) +#define V_LDT_DEVICEID_DEVICEID(x) _SB_MAKEVALUE_32(x, S_LDT_DEVICEID_DEVICEID) +#define G_LDT_DEVICEID_DEVICEID(x) _SB_GETVALUE_32(x, S_LDT_DEVICEID_DEVICEID, M_LDT_DEVICEID_DEVICEID) /* @@ -111,14 +111,14 @@ */ #define S_LDT_CLASSREV_REV 0 -#define M_LDT_CLASSREV_REV _SB_MAKEMASK_32(8,S_LDT_CLASSREV_REV) -#define V_LDT_CLASSREV_REV(x) _SB_MAKEVALUE_32(x,S_LDT_CLASSREV_REV) -#define G_LDT_CLASSREV_REV(x) _SB_GETVALUE_32(x,S_LDT_CLASSREV_REV,M_LDT_CLASSREV_REV) +#define M_LDT_CLASSREV_REV _SB_MAKEMASK_32(8, S_LDT_CLASSREV_REV) +#define V_LDT_CLASSREV_REV(x) _SB_MAKEVALUE_32(x, S_LDT_CLASSREV_REV) +#define G_LDT_CLASSREV_REV(x) _SB_GETVALUE_32(x, S_LDT_CLASSREV_REV, M_LDT_CLASSREV_REV) #define S_LDT_CLASSREV_CLASS 8 -#define M_LDT_CLASSREV_CLASS _SB_MAKEMASK_32(24,S_LDT_CLASSREV_CLASS) -#define V_LDT_CLASSREV_CLASS(x) _SB_MAKEVALUE_32(x,S_LDT_CLASSREV_CLASS) -#define G_LDT_CLASSREV_CLASS(x) _SB_GETVALUE_32(x,S_LDT_CLASSREV_CLASS,M_LDT_CLASSREV_CLASS) +#define M_LDT_CLASSREV_CLASS _SB_MAKEMASK_32(24, S_LDT_CLASSREV_CLASS) +#define V_LDT_CLASSREV_CLASS(x) _SB_MAKEVALUE_32(x, S_LDT_CLASSREV_CLASS) +#define G_LDT_CLASSREV_CLASS(x) _SB_GETVALUE_32(x, S_LDT_CLASSREV_CLASS, M_LDT_CLASSREV_CLASS) #define K_LDT_REV 0x01 #define K_LDT_CLASS 0x060000 @@ -128,26 +128,26 @@ */ #define S_LDT_DEVHDR_CLINESZ 0 -#define M_LDT_DEVHDR_CLINESZ _SB_MAKEMASK_32(8,S_LDT_DEVHDR_CLINESZ) -#define V_LDT_DEVHDR_CLINESZ(x) _SB_MAKEVALUE_32(x,S_LDT_DEVHDR_CLINESZ) -#define G_LDT_DEVHDR_CLINESZ(x) _SB_GETVALUE_32(x,S_LDT_DEVHDR_CLINESZ,M_LDT_DEVHDR_CLINESZ) +#define M_LDT_DEVHDR_CLINESZ _SB_MAKEMASK_32(8, S_LDT_DEVHDR_CLINESZ) +#define V_LDT_DEVHDR_CLINESZ(x) _SB_MAKEVALUE_32(x, S_LDT_DEVHDR_CLINESZ) +#define G_LDT_DEVHDR_CLINESZ(x) _SB_GETVALUE_32(x, S_LDT_DEVHDR_CLINESZ, M_LDT_DEVHDR_CLINESZ) #define S_LDT_DEVHDR_LATTMR 8 -#define M_LDT_DEVHDR_LATTMR _SB_MAKEMASK_32(8,S_LDT_DEVHDR_LATTMR) -#define V_LDT_DEVHDR_LATTMR(x) _SB_MAKEVALUE_32(x,S_LDT_DEVHDR_LATTMR) -#define G_LDT_DEVHDR_LATTMR(x) _SB_GETVALUE_32(x,S_LDT_DEVHDR_LATTMR,M_LDT_DEVHDR_LATTMR) +#define M_LDT_DEVHDR_LATTMR _SB_MAKEMASK_32(8, S_LDT_DEVHDR_LATTMR) +#define V_LDT_DEVHDR_LATTMR(x) _SB_MAKEVALUE_32(x, S_LDT_DEVHDR_LATTMR) +#define G_LDT_DEVHDR_LATTMR(x) _SB_GETVALUE_32(x, S_LDT_DEVHDR_LATTMR, M_LDT_DEVHDR_LATTMR) #define S_LDT_DEVHDR_HDRTYPE 16 -#define M_LDT_DEVHDR_HDRTYPE _SB_MAKEMASK_32(8,S_LDT_DEVHDR_HDRTYPE) -#define V_LDT_DEVHDR_HDRTYPE(x) _SB_MAKEVALUE_32(x,S_LDT_DEVHDR_HDRTYPE) -#define G_LDT_DEVHDR_HDRTYPE(x) _SB_GETVALUE_32(x,S_LDT_DEVHDR_HDRTYPE,M_LDT_DEVHDR_HDRTYPE) +#define M_LDT_DEVHDR_HDRTYPE _SB_MAKEMASK_32(8, S_LDT_DEVHDR_HDRTYPE) +#define V_LDT_DEVHDR_HDRTYPE(x) _SB_MAKEVALUE_32(x, S_LDT_DEVHDR_HDRTYPE) +#define G_LDT_DEVHDR_HDRTYPE(x) _SB_GETVALUE_32(x, S_LDT_DEVHDR_HDRTYPE, M_LDT_DEVHDR_HDRTYPE) #define K_LDT_DEVHDR_HDRTYPE_TYPE1 1 #define S_LDT_DEVHDR_BIST 24 -#define M_LDT_DEVHDR_BIST _SB_MAKEMASK_32(8,S_LDT_DEVHDR_BIST) -#define V_LDT_DEVHDR_BIST(x) _SB_MAKEVALUE_32(x,S_LDT_DEVHDR_BIST) -#define G_LDT_DEVHDR_BIST(x) _SB_GETVALUE_32(x,S_LDT_DEVHDR_BIST,M_LDT_DEVHDR_BIST) +#define M_LDT_DEVHDR_BIST _SB_MAKEMASK_32(8, S_LDT_DEVHDR_BIST) +#define V_LDT_DEVHDR_BIST(x) _SB_MAKEVALUE_32(x, S_LDT_DEVHDR_BIST) +#define G_LDT_DEVHDR_BIST(x) _SB_GETVALUE_32(x, S_LDT_DEVHDR_BIST, M_LDT_DEVHDR_BIST) @@ -170,9 +170,9 @@ #define M_LDT_STATUS_MSTRDPARERR _SB_MAKEMASK1_32(24) #define S_LDT_STATUS_DEVSELTIMING 25 -#define M_LDT_STATUS_DEVSELTIMING _SB_MAKEMASK_32(2,S_LDT_STATUS_DEVSELTIMING) -#define V_LDT_STATUS_DEVSELTIMING(x) _SB_MAKEVALUE_32(x,S_LDT_STATUS_DEVSELTIMING) -#define G_LDT_STATUS_DEVSELTIMING(x) _SB_GETVALUE_32(x,S_LDT_STATUS_DEVSELTIMING,M_LDT_STATUS_DEVSELTIMING) +#define M_LDT_STATUS_DEVSELTIMING _SB_MAKEMASK_32(2, S_LDT_STATUS_DEVSELTIMING) +#define V_LDT_STATUS_DEVSELTIMING(x) _SB_MAKEVALUE_32(x, S_LDT_STATUS_DEVSELTIMING) +#define G_LDT_STATUS_DEVSELTIMING(x) _SB_GETVALUE_32(x, S_LDT_STATUS_DEVSELTIMING, M_LDT_STATUS_DEVSELTIMING) #define M_LDT_STATUS_SIGDTGTABORT _SB_MAKEMASK1_32(27) #define M_LDT_STATUS_RCVDTGTABORT _SB_MAKEMASK1_32(28) @@ -208,9 +208,9 @@ #define M_LDT_CMD_DOUBLEENDED _SB_MAKEMASK1_32(17) #define S_LDT_CMD_CAPTYPE 29 -#define M_LDT_CMD_CAPTYPE _SB_MAKEMASK_32(3,S_LDT_CMD_CAPTYPE) -#define V_LDT_CMD_CAPTYPE(x) _SB_MAKEVALUE_32(x,S_LDT_CMD_CAPTYPE) -#define G_LDT_CMD_CAPTYPE(x) _SB_GETVALUE_32(x,S_LDT_CMD_CAPTYPE,M_LDT_CMD_CAPTYPE) +#define M_LDT_CMD_CAPTYPE _SB_MAKEMASK_32(3, S_LDT_CMD_CAPTYPE) +#define V_LDT_CMD_CAPTYPE(x) _SB_MAKEVALUE_32(x, S_LDT_CMD_CAPTYPE) +#define G_LDT_CMD_CAPTYPE(x) _SB_GETVALUE_32(x, S_LDT_CMD_CAPTYPE, M_LDT_CMD_CAPTYPE) /* * LDT link control register (Table 8-18), and (Table 8-19) @@ -225,35 +225,35 @@ #define M_LDT_LINKCTRL_XMITOFF _SB_MAKEMASK1_32(7) #define S_LDT_LINKCTRL_CRCERR 8 -#define M_LDT_LINKCTRL_CRCERR _SB_MAKEMASK_32(4,S_LDT_LINKCTRL_CRCERR) -#define V_LDT_LINKCTRL_CRCERR(x) _SB_MAKEVALUE_32(x,S_LDT_LINKCTRL_CRCERR) -#define G_LDT_LINKCTRL_CRCERR(x) _SB_GETVALUE_32(x,S_LDT_LINKCTRL_CRCERR,M_LDT_LINKCTRL_CRCERR) +#define M_LDT_LINKCTRL_CRCERR _SB_MAKEMASK_32(4, S_LDT_LINKCTRL_CRCERR) +#define V_LDT_LINKCTRL_CRCERR(x) _SB_MAKEVALUE_32(x, S_LDT_LINKCTRL_CRCERR) +#define G_LDT_LINKCTRL_CRCERR(x) _SB_GETVALUE_32(x, S_LDT_LINKCTRL_CRCERR, M_LDT_LINKCTRL_CRCERR) #define S_LDT_LINKCTRL_MAXIN 16 -#define M_LDT_LINKCTRL_MAXIN _SB_MAKEMASK_32(3,S_LDT_LINKCTRL_MAXIN) -#define V_LDT_LINKCTRL_MAXIN(x) _SB_MAKEVALUE_32(x,S_LDT_LINKCTRL_MAXIN) -#define G_LDT_LINKCTRL_MAXIN(x) _SB_GETVALUE_32(x,S_LDT_LINKCTRL_MAXIN,M_LDT_LINKCTRL_MAXIN) +#define M_LDT_LINKCTRL_MAXIN _SB_MAKEMASK_32(3, S_LDT_LINKCTRL_MAXIN) +#define V_LDT_LINKCTRL_MAXIN(x) _SB_MAKEVALUE_32(x, S_LDT_LINKCTRL_MAXIN) +#define G_LDT_LINKCTRL_MAXIN(x) _SB_GETVALUE_32(x, S_LDT_LINKCTRL_MAXIN, M_LDT_LINKCTRL_MAXIN) #define M_LDT_LINKCTRL_DWFCLN _SB_MAKEMASK1_32(19) #define S_LDT_LINKCTRL_MAXOUT 20 -#define M_LDT_LINKCTRL_MAXOUT _SB_MAKEMASK_32(3,S_LDT_LINKCTRL_MAXOUT) -#define V_LDT_LINKCTRL_MAXOUT(x) _SB_MAKEVALUE_32(x,S_LDT_LINKCTRL_MAXOUT) -#define G_LDT_LINKCTRL_MAXOUT(x) _SB_GETVALUE_32(x,S_LDT_LINKCTRL_MAXOUT,M_LDT_LINKCTRL_MAXOUT) +#define M_LDT_LINKCTRL_MAXOUT _SB_MAKEMASK_32(3, S_LDT_LINKCTRL_MAXOUT) +#define V_LDT_LINKCTRL_MAXOUT(x) _SB_MAKEVALUE_32(x, S_LDT_LINKCTRL_MAXOUT) +#define G_LDT_LINKCTRL_MAXOUT(x) _SB_GETVALUE_32(x, S_LDT_LINKCTRL_MAXOUT, M_LDT_LINKCTRL_MAXOUT) #define M_LDT_LINKCTRL_DWFCOUT _SB_MAKEMASK1_32(23) #define S_LDT_LINKCTRL_WIDTHIN 24 -#define M_LDT_LINKCTRL_WIDTHIN _SB_MAKEMASK_32(3,S_LDT_LINKCTRL_WIDTHIN) -#define V_LDT_LINKCTRL_WIDTHIN(x) _SB_MAKEVALUE_32(x,S_LDT_LINKCTRL_WIDTHIN) -#define G_LDT_LINKCTRL_WIDTHIN(x) _SB_GETVALUE_32(x,S_LDT_LINKCTRL_WIDTHIN,M_LDT_LINKCTRL_WIDTHIN) +#define M_LDT_LINKCTRL_WIDTHIN _SB_MAKEMASK_32(3, S_LDT_LINKCTRL_WIDTHIN) +#define V_LDT_LINKCTRL_WIDTHIN(x) _SB_MAKEVALUE_32(x, S_LDT_LINKCTRL_WIDTHIN) +#define G_LDT_LINKCTRL_WIDTHIN(x) _SB_GETVALUE_32(x, S_LDT_LINKCTRL_WIDTHIN, M_LDT_LINKCTRL_WIDTHIN) #define M_LDT_LINKCTRL_DWFCLIN_EN _SB_MAKEMASK1_32(27) #define S_LDT_LINKCTRL_WIDTHOUT 28 -#define M_LDT_LINKCTRL_WIDTHOUT _SB_MAKEMASK_32(3,S_LDT_LINKCTRL_WIDTHOUT) -#define V_LDT_LINKCTRL_WIDTHOUT(x) _SB_MAKEVALUE_32(x,S_LDT_LINKCTRL_WIDTHOUT) -#define G_LDT_LINKCTRL_WIDTHOUT(x) _SB_GETVALUE_32(x,S_LDT_LINKCTRL_WIDTHOUT,M_LDT_LINKCTRL_WIDTHOUT) +#define M_LDT_LINKCTRL_WIDTHOUT _SB_MAKEMASK_32(3, S_LDT_LINKCTRL_WIDTHOUT) +#define V_LDT_LINKCTRL_WIDTHOUT(x) _SB_MAKEVALUE_32(x, S_LDT_LINKCTRL_WIDTHOUT) +#define G_LDT_LINKCTRL_WIDTHOUT(x) _SB_GETVALUE_32(x, S_LDT_LINKCTRL_WIDTHOUT, M_LDT_LINKCTRL_WIDTHOUT) #define M_LDT_LINKCTRL_DWFCOUT_EN _SB_MAKEMASK1_32(31) @@ -262,9 +262,9 @@ */ #define S_LDT_LINKFREQ_FREQ 8 -#define M_LDT_LINKFREQ_FREQ _SB_MAKEMASK_32(4,S_LDT_LINKFREQ_FREQ) -#define V_LDT_LINKFREQ_FREQ(x) _SB_MAKEVALUE_32(x,S_LDT_LINKFREQ_FREQ) -#define G_LDT_LINKFREQ_FREQ(x) _SB_GETVALUE_32(x,S_LDT_LINKFREQ_FREQ,M_LDT_LINKFREQ_FREQ) +#define M_LDT_LINKFREQ_FREQ _SB_MAKEMASK_32(4, S_LDT_LINKFREQ_FREQ) +#define V_LDT_LINKFREQ_FREQ(x) _SB_MAKEVALUE_32(x, S_LDT_LINKFREQ_FREQ) +#define G_LDT_LINKFREQ_FREQ(x) _SB_GETVALUE_32(x, S_LDT_LINKFREQ_FREQ, M_LDT_LINKFREQ_FREQ) #define K_LDT_LINKFREQ_200MHZ 0 #define K_LDT_LINKFREQ_300MHZ 1 @@ -293,16 +293,16 @@ #define S_LDT_SRICMD_RXMARGIN 20 -#define M_LDT_SRICMD_RXMARGIN _SB_MAKEMASK_32(5,S_LDT_SRICMD_RXMARGIN) -#define V_LDT_SRICMD_RXMARGIN(x) _SB_MAKEVALUE_32(x,S_LDT_SRICMD_RXMARGIN) -#define G_LDT_SRICMD_RXMARGIN(x) _SB_GETVALUE_32(x,S_LDT_SRICMD_RXMARGIN,M_LDT_SRICMD_RXMARGIN) +#define M_LDT_SRICMD_RXMARGIN _SB_MAKEMASK_32(5, S_LDT_SRICMD_RXMARGIN) +#define V_LDT_SRICMD_RXMARGIN(x) _SB_MAKEVALUE_32(x, S_LDT_SRICMD_RXMARGIN) +#define G_LDT_SRICMD_RXMARGIN(x) _SB_GETVALUE_32(x, S_LDT_SRICMD_RXMARGIN, M_LDT_SRICMD_RXMARGIN) #define M_LDT_SRICMD_LDTPLLCOMPAT _SB_MAKEMASK1_32(25) #define S_LDT_SRICMD_TXINITIALOFFSET 28 -#define M_LDT_SRICMD_TXINITIALOFFSET _SB_MAKEMASK_32(3,S_LDT_SRICMD_TXINITIALOFFSET) -#define V_LDT_SRICMD_TXINITIALOFFSET(x) _SB_MAKEVALUE_32(x,S_LDT_SRICMD_TXINITIALOFFSET) -#define G_LDT_SRICMD_TXINITIALOFFSET(x) _SB_GETVALUE_32(x,S_LDT_SRICMD_TXINITIALOFFSET,M_LDT_SRICMD_TXINITIALOFFSET) +#define M_LDT_SRICMD_TXINITIALOFFSET _SB_MAKEMASK_32(3, S_LDT_SRICMD_TXINITIALOFFSET) +#define V_LDT_SRICMD_TXINITIALOFFSET(x) _SB_MAKEVALUE_32(x, S_LDT_SRICMD_TXINITIALOFFSET) +#define G_LDT_SRICMD_TXINITIALOFFSET(x) _SB_GETVALUE_32(x, S_LDT_SRICMD_TXINITIALOFFSET, M_LDT_SRICMD_TXINITIALOFFSET) #define M_LDT_SRICMD_LINKFREQDIRECT _SB_MAKEMASK1_32(31) @@ -340,73 +340,73 @@ */ #define S_LDT_SRICTRL_NEEDRESP 0 -#define M_LDT_SRICTRL_NEEDRESP _SB_MAKEMASK_32(2,S_LDT_SRICTRL_NEEDRESP) -#define V_LDT_SRICTRL_NEEDRESP(x) _SB_MAKEVALUE_32(x,S_LDT_SRICTRL_NEEDRESP) -#define G_LDT_SRICTRL_NEEDRESP(x) _SB_GETVALUE_32(x,S_LDT_SRICTRL_NEEDRESP,M_LDT_SRICTRL_NEEDRESP) +#define M_LDT_SRICTRL_NEEDRESP _SB_MAKEMASK_32(2, S_LDT_SRICTRL_NEEDRESP) +#define V_LDT_SRICTRL_NEEDRESP(x) _SB_MAKEVALUE_32(x, S_LDT_SRICTRL_NEEDRESP) +#define G_LDT_SRICTRL_NEEDRESP(x) _SB_GETVALUE_32(x, S_LDT_SRICTRL_NEEDRESP, M_LDT_SRICTRL_NEEDRESP) #define S_LDT_SRICTRL_NEEDNPREQ 2 -#define M_LDT_SRICTRL_NEEDNPREQ _SB_MAKEMASK_32(2,S_LDT_SRICTRL_NEEDNPREQ) -#define V_LDT_SRICTRL_NEEDNPREQ(x) _SB_MAKEVALUE_32(x,S_LDT_SRICTRL_NEEDNPREQ) -#define G_LDT_SRICTRL_NEEDNPREQ(x) _SB_GETVALUE_32(x,S_LDT_SRICTRL_NEEDNPREQ,M_LDT_SRICTRL_NEEDNPREQ) +#define M_LDT_SRICTRL_NEEDNPREQ _SB_MAKEMASK_32(2, S_LDT_SRICTRL_NEEDNPREQ) +#define V_LDT_SRICTRL_NEEDNPREQ(x) _SB_MAKEVALUE_32(x, S_LDT_SRICTRL_NEEDNPREQ) +#define G_LDT_SRICTRL_NEEDNPREQ(x) _SB_GETVALUE_32(x, S_LDT_SRICTRL_NEEDNPREQ, M_LDT_SRICTRL_NEEDNPREQ) #define S_LDT_SRICTRL_NEEDPREQ 4 -#define M_LDT_SRICTRL_NEEDPREQ _SB_MAKEMASK_32(2,S_LDT_SRICTRL_NEEDPREQ) -#define V_LDT_SRICTRL_NEEDPREQ(x) _SB_MAKEVALUE_32(x,S_LDT_SRICTRL_NEEDPREQ) -#define G_LDT_SRICTRL_NEEDPREQ(x) _SB_GETVALUE_32(x,S_LDT_SRICTRL_NEEDPREQ,M_LDT_SRICTRL_NEEDPREQ) +#define M_LDT_SRICTRL_NEEDPREQ _SB_MAKEMASK_32(2, S_LDT_SRICTRL_NEEDPREQ) +#define V_LDT_SRICTRL_NEEDPREQ(x) _SB_MAKEVALUE_32(x, S_LDT_SRICTRL_NEEDPREQ) +#define G_LDT_SRICTRL_NEEDPREQ(x) _SB_GETVALUE_32(x, S_LDT_SRICTRL_NEEDPREQ, M_LDT_SRICTRL_NEEDPREQ) #define S_LDT_SRICTRL_WANTRESP 8 -#define M_LDT_SRICTRL_WANTRESP _SB_MAKEMASK_32(2,S_LDT_SRICTRL_WANTRESP) -#define V_LDT_SRICTRL_WANTRESP(x) _SB_MAKEVALUE_32(x,S_LDT_SRICTRL_WANTRESP) -#define G_LDT_SRICTRL_WANTRESP(x) _SB_GETVALUE_32(x,S_LDT_SRICTRL_WANTRESP,M_LDT_SRICTRL_WANTRESP) +#define M_LDT_SRICTRL_WANTRESP _SB_MAKEMASK_32(2, S_LDT_SRICTRL_WANTRESP) +#define V_LDT_SRICTRL_WANTRESP(x) _SB_MAKEVALUE_32(x, S_LDT_SRICTRL_WANTRESP) +#define G_LDT_SRICTRL_WANTRESP(x) _SB_GETVALUE_32(x, S_LDT_SRICTRL_WANTRESP, M_LDT_SRICTRL_WANTRESP) #define S_LDT_SRICTRL_WANTNPREQ 10 -#define M_LDT_SRICTRL_WANTNPREQ _SB_MAKEMASK_32(2,S_LDT_SRICTRL_WANTNPREQ) -#define V_LDT_SRICTRL_WANTNPREQ(x) _SB_MAKEVALUE_32(x,S_LDT_SRICTRL_WANTNPREQ) -#define G_LDT_SRICTRL_WANTNPREQ(x) _SB_GETVALUE_32(x,S_LDT_SRICTRL_WANTNPREQ,M_LDT_SRICTRL_WANTNPREQ) +#define M_LDT_SRICTRL_WANTNPREQ _SB_MAKEMASK_32(2, S_LDT_SRICTRL_WANTNPREQ) +#define V_LDT_SRICTRL_WANTNPREQ(x) _SB_MAKEVALUE_32(x, S_LDT_SRICTRL_WANTNPREQ) +#define G_LDT_SRICTRL_WANTNPREQ(x) _SB_GETVALUE_32(x, S_LDT_SRICTRL_WANTNPREQ, M_LDT_SRICTRL_WANTNPREQ) #define S_LDT_SRICTRL_WANTPREQ 12 -#define M_LDT_SRICTRL_WANTPREQ _SB_MAKEMASK_32(2,S_LDT_SRICTRL_WANTPREQ) -#define V_LDT_SRICTRL_WANTPREQ(x) _SB_MAKEVALUE_32(x,S_LDT_SRICTRL_WANTPREQ) -#define G_LDT_SRICTRL_WANTPREQ(x) _SB_GETVALUE_32(x,S_LDT_SRICTRL_WANTPREQ,M_LDT_SRICTRL_WANTPREQ) +#define M_LDT_SRICTRL_WANTPREQ _SB_MAKEMASK_32(2, S_LDT_SRICTRL_WANTPREQ) +#define V_LDT_SRICTRL_WANTPREQ(x) _SB_MAKEVALUE_32(x, S_LDT_SRICTRL_WANTPREQ) +#define G_LDT_SRICTRL_WANTPREQ(x) _SB_GETVALUE_32(x, S_LDT_SRICTRL_WANTPREQ, M_LDT_SRICTRL_WANTPREQ) #define S_LDT_SRICTRL_BUFRELSPACE 16 -#define M_LDT_SRICTRL_BUFRELSPACE _SB_MAKEMASK_32(4,S_LDT_SRICTRL_BUFRELSPACE) -#define V_LDT_SRICTRL_BUFRELSPACE(x) _SB_MAKEVALUE_32(x,S_LDT_SRICTRL_BUFRELSPACE) -#define G_LDT_SRICTRL_BUFRELSPACE(x) _SB_GETVALUE_32(x,S_LDT_SRICTRL_BUFRELSPACE,M_LDT_SRICTRL_BUFRELSPACE) +#define M_LDT_SRICTRL_BUFRELSPACE _SB_MAKEMASK_32(4, S_LDT_SRICTRL_BUFRELSPACE) +#define V_LDT_SRICTRL_BUFRELSPACE(x) _SB_MAKEVALUE_32(x, S_LDT_SRICTRL_BUFRELSPACE) +#define G_LDT_SRICTRL_BUFRELSPACE(x) _SB_GETVALUE_32(x, S_LDT_SRICTRL_BUFRELSPACE, M_LDT_SRICTRL_BUFRELSPACE) /* * LDT SRI Transmit Buffer Count register (Table 8-26) */ #define S_LDT_TXBUFCNT_PCMD 0 -#define M_LDT_TXBUFCNT_PCMD _SB_MAKEMASK_32(4,S_LDT_TXBUFCNT_PCMD) -#define V_LDT_TXBUFCNT_PCMD(x) _SB_MAKEVALUE_32(x,S_LDT_TXBUFCNT_PCMD) -#define G_LDT_TXBUFCNT_PCMD(x) _SB_GETVALUE_32(x,S_LDT_TXBUFCNT_PCMD,M_LDT_TXBUFCNT_PCMD) +#define M_LDT_TXBUFCNT_PCMD _SB_MAKEMASK_32(4, S_LDT_TXBUFCNT_PCMD) +#define V_LDT_TXBUFCNT_PCMD(x) _SB_MAKEVALUE_32(x, S_LDT_TXBUFCNT_PCMD) +#define G_LDT_TXBUFCNT_PCMD(x) _SB_GETVALUE_32(x, S_LDT_TXBUFCNT_PCMD, M_LDT_TXBUFCNT_PCMD) #define S_LDT_TXBUFCNT_PDATA 4 -#define M_LDT_TXBUFCNT_PDATA _SB_MAKEMASK_32(4,S_LDT_TXBUFCNT_PDATA) -#define V_LDT_TXBUFCNT_PDATA(x) _SB_MAKEVALUE_32(x,S_LDT_TXBUFCNT_PDATA) -#define G_LDT_TXBUFCNT_PDATA(x) _SB_GETVALUE_32(x,S_LDT_TXBUFCNT_PDATA,M_LDT_TXBUFCNT_PDATA) +#define M_LDT_TXBUFCNT_PDATA _SB_MAKEMASK_32(4, S_LDT_TXBUFCNT_PDATA) +#define V_LDT_TXBUFCNT_PDATA(x) _SB_MAKEVALUE_32(x, S_LDT_TXBUFCNT_PDATA) +#define G_LDT_TXBUFCNT_PDATA(x) _SB_GETVALUE_32(x, S_LDT_TXBUFCNT_PDATA, M_LDT_TXBUFCNT_PDATA) #define S_LDT_TXBUFCNT_NPCMD 8 -#define M_LDT_TXBUFCNT_NPCMD _SB_MAKEMASK_32(4,S_LDT_TXBUFCNT_NPCMD) -#define V_LDT_TXBUFCNT_NPCMD(x) _SB_MAKEVALUE_32(x,S_LDT_TXBUFCNT_NPCMD) -#define G_LDT_TXBUFCNT_NPCMD(x) _SB_GETVALUE_32(x,S_LDT_TXBUFCNT_NPCMD,M_LDT_TXBUFCNT_NPCMD) +#define M_LDT_TXBUFCNT_NPCMD _SB_MAKEMASK_32(4, S_LDT_TXBUFCNT_NPCMD) +#define V_LDT_TXBUFCNT_NPCMD(x) _SB_MAKEVALUE_32(x, S_LDT_TXBUFCNT_NPCMD) +#define G_LDT_TXBUFCNT_NPCMD(x) _SB_GETVALUE_32(x, S_LDT_TXBUFCNT_NPCMD, M_LDT_TXBUFCNT_NPCMD) #define S_LDT_TXBUFCNT_NPDATA 12 -#define M_LDT_TXBUFCNT_NPDATA _SB_MAKEMASK_32(4,S_LDT_TXBUFCNT_NPDATA) -#define V_LDT_TXBUFCNT_NPDATA(x) _SB_MAKEVALUE_32(x,S_LDT_TXBUFCNT_NPDATA) -#define G_LDT_TXBUFCNT_NPDATA(x) _SB_GETVALUE_32(x,S_LDT_TXBUFCNT_NPDATA,M_LDT_TXBUFCNT_NPDATA) +#define M_LDT_TXBUFCNT_NPDATA _SB_MAKEMASK_32(4, S_LDT_TXBUFCNT_NPDATA) +#define V_LDT_TXBUFCNT_NPDATA(x) _SB_MAKEVALUE_32(x, S_LDT_TXBUFCNT_NPDATA) +#define G_LDT_TXBUFCNT_NPDATA(x) _SB_GETVALUE_32(x, S_LDT_TXBUFCNT_NPDATA, M_LDT_TXBUFCNT_NPDATA) #define S_LDT_TXBUFCNT_RCMD 16 -#define M_LDT_TXBUFCNT_RCMD _SB_MAKEMASK_32(4,S_LDT_TXBUFCNT_RCMD) -#define V_LDT_TXBUFCNT_RCMD(x) _SB_MAKEVALUE_32(x,S_LDT_TXBUFCNT_RCMD) -#define G_LDT_TXBUFCNT_RCMD(x) _SB_GETVALUE_32(x,S_LDT_TXBUFCNT_RCMD,M_LDT_TXBUFCNT_RCMD) +#define M_LDT_TXBUFCNT_RCMD _SB_MAKEMASK_32(4, S_LDT_TXBUFCNT_RCMD) +#define V_LDT_TXBUFCNT_RCMD(x) _SB_MAKEVALUE_32(x, S_LDT_TXBUFCNT_RCMD) +#define G_LDT_TXBUFCNT_RCMD(x) _SB_GETVALUE_32(x, S_LDT_TXBUFCNT_RCMD, M_LDT_TXBUFCNT_RCMD) #define S_LDT_TXBUFCNT_RDATA 20 -#define M_LDT_TXBUFCNT_RDATA _SB_MAKEMASK_32(4,S_LDT_TXBUFCNT_RDATA) -#define V_LDT_TXBUFCNT_RDATA(x) _SB_MAKEVALUE_32(x,S_LDT_TXBUFCNT_RDATA) -#define G_LDT_TXBUFCNT_RDATA(x) _SB_GETVALUE_32(x,S_LDT_TXBUFCNT_RDATA,M_LDT_TXBUFCNT_RDATA) +#define M_LDT_TXBUFCNT_RDATA _SB_MAKEMASK_32(4, S_LDT_TXBUFCNT_RDATA) +#define V_LDT_TXBUFCNT_RDATA(x) _SB_MAKEVALUE_32(x, S_LDT_TXBUFCNT_RDATA) +#define G_LDT_TXBUFCNT_RDATA(x) _SB_GETVALUE_32(x, S_LDT_TXBUFCNT_RDATA, M_LDT_TXBUFCNT_RDATA) #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) /* @@ -414,9 +414,9 @@ */ #define S_LDT_ADDSTATUS_TGTDONE 0 -#define M_LDT_ADDSTATUS_TGTDONE _SB_MAKEMASK_32(8,S_LDT_ADDSTATUS_TGTDONE) -#define V_LDT_ADDSTATUS_TGTDONE(x) _SB_MAKEVALUE_32(x,S_LDT_ADDSTATUS_TGTDONE) -#define G_LDT_ADDSTATUS_TGTDONE(x) _SB_GETVALUE_32(x,S_LDT_ADDSTATUS_TGTDONE,M_LDT_ADDSTATUS_TGTDONE) +#define M_LDT_ADDSTATUS_TGTDONE _SB_MAKEMASK_32(8, S_LDT_ADDSTATUS_TGTDONE) +#define V_LDT_ADDSTATUS_TGTDONE(x) _SB_MAKEVALUE_32(x, S_LDT_ADDSTATUS_TGTDONE) +#define G_LDT_ADDSTATUS_TGTDONE(x) _SB_GETVALUE_32(x, S_LDT_ADDSTATUS_TGTDONE, M_LDT_ADDSTATUS_TGTDONE) #endif /* 1250 PASS2 || 112x PASS1 */ #endif diff --git a/include/asm-mips/sibyte/sb1250_mac.h b/include/asm-mips/sibyte/sb1250_mac.h index 833c8b59d687..b6faf08ca81d 100644 --- a/include/asm-mips/sibyte/sb1250_mac.h +++ b/include/asm-mips/sibyte/sb1250_mac.h @@ -55,8 +55,8 @@ #define M_MAC_BURST_EN _SB_MAKEMASK1(5) #define S_MAC_TX_PAUSE _SB_MAKE64(6) -#define M_MAC_TX_PAUSE_CNT _SB_MAKEMASK(3,S_MAC_TX_PAUSE) -#define V_MAC_TX_PAUSE_CNT(x) _SB_MAKEVALUE(x,S_MAC_TX_PAUSE) +#define M_MAC_TX_PAUSE_CNT _SB_MAKEMASK(3, S_MAC_TX_PAUSE) +#define V_MAC_TX_PAUSE_CNT(x) _SB_MAKEVALUE(x, S_MAC_TX_PAUSE) #define K_MAC_TX_PAUSE_CNT_512 0 #define K_MAC_TX_PAUSE_CNT_1K 1 @@ -76,7 +76,7 @@ #define V_MAC_TX_PAUSE_CNT_32K V_MAC_TX_PAUSE_CNT(K_MAC_TX_PAUSE_CNT_32K) #define V_MAC_TX_PAUSE_CNT_64K V_MAC_TX_PAUSE_CNT(K_MAC_TX_PAUSE_CNT_64K) -#define M_MAC_RESERVED1 _SB_MAKEMASK(8,9) +#define M_MAC_RESERVED1 _SB_MAKEMASK(8, 9) #define M_MAC_AP_STAT_EN _SB_MAKEMASK1(17) @@ -91,15 +91,15 @@ #define M_MAC_DRP_OSZPKT_EN _SB_MAKEMASK1(24) #define M_MAC_DRP_LENERRPKT_EN _SB_MAKEMASK1(25) -#define M_MAC_RESERVED3 _SB_MAKEMASK(6,26) +#define M_MAC_RESERVED3 _SB_MAKEMASK(6, 26) #define M_MAC_BYPASS_SEL _SB_MAKEMASK1(32) #define M_MAC_HDX_EN _SB_MAKEMASK1(33) #define S_MAC_SPEED_SEL _SB_MAKE64(34) -#define M_MAC_SPEED_SEL _SB_MAKEMASK(2,S_MAC_SPEED_SEL) -#define V_MAC_SPEED_SEL(x) _SB_MAKEVALUE(x,S_MAC_SPEED_SEL) -#define G_MAC_SPEED_SEL(x) _SB_GETVALUE(x,S_MAC_SPEED_SEL,M_MAC_SPEED_SEL) +#define M_MAC_SPEED_SEL _SB_MAKEMASK(2, S_MAC_SPEED_SEL) +#define V_MAC_SPEED_SEL(x) _SB_MAKEVALUE(x, S_MAC_SPEED_SEL) +#define G_MAC_SPEED_SEL(x) _SB_GETVALUE(x, S_MAC_SPEED_SEL, M_MAC_SPEED_SEL) #define K_MAC_SPEED_SEL_10MBPS 0 #define K_MAC_SPEED_SEL_100MBPS 1 @@ -117,9 +117,9 @@ #define M_MAC_SS_EN _SB_MAKEMASK1(39) #define S_MAC_BYPASS_CFG _SB_MAKE64(40) -#define M_MAC_BYPASS_CFG _SB_MAKEMASK(2,S_MAC_BYPASS_CFG) -#define V_MAC_BYPASS_CFG(x) _SB_MAKEVALUE(x,S_MAC_BYPASS_CFG) -#define G_MAC_BYPASS_CFG(x) _SB_GETVALUE(x,S_MAC_BYPASS_CFG,M_MAC_BYPASS_CFG) +#define M_MAC_BYPASS_CFG _SB_MAKEMASK(2, S_MAC_BYPASS_CFG) +#define V_MAC_BYPASS_CFG(x) _SB_MAKEVALUE(x, S_MAC_BYPASS_CFG) +#define G_MAC_BYPASS_CFG(x) _SB_GETVALUE(x, S_MAC_BYPASS_CFG, M_MAC_BYPASS_CFG) #define K_MAC_BYPASS_GMII 0 #define K_MAC_BYPASS_ENCODED 1 @@ -138,9 +138,9 @@ #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ #define S_MAC_BYPASS_IFG _SB_MAKE64(46) -#define M_MAC_BYPASS_IFG _SB_MAKEMASK(8,S_MAC_BYPASS_IFG) -#define V_MAC_BYPASS_IFG(x) _SB_MAKEVALUE(x,S_MAC_BYPASS_IFG) -#define G_MAC_BYPASS_IFG(x) _SB_GETVALUE(x,S_MAC_BYPASS_IFG,M_MAC_BYPASS_IFG) +#define M_MAC_BYPASS_IFG _SB_MAKEMASK(8, S_MAC_BYPASS_IFG) +#define V_MAC_BYPASS_IFG(x) _SB_MAKEVALUE(x, S_MAC_BYPASS_IFG) +#define G_MAC_BYPASS_IFG(x) _SB_GETVALUE(x, S_MAC_BYPASS_IFG, M_MAC_BYPASS_IFG) #define K_MAC_FC_CMD_DISABLED 0 #define K_MAC_FC_CMD_ENABLED 1 @@ -153,14 +153,14 @@ #define M_MAC_FC_SEL _SB_MAKEMASK1(54) #define S_MAC_FC_CMD _SB_MAKE64(55) -#define M_MAC_FC_CMD _SB_MAKEMASK(2,S_MAC_FC_CMD) -#define V_MAC_FC_CMD(x) _SB_MAKEVALUE(x,S_MAC_FC_CMD) -#define G_MAC_FC_CMD(x) _SB_GETVALUE(x,S_MAC_FC_CMD,M_MAC_FC_CMD) +#define M_MAC_FC_CMD _SB_MAKEMASK(2, S_MAC_FC_CMD) +#define V_MAC_FC_CMD(x) _SB_MAKEVALUE(x, S_MAC_FC_CMD) +#define G_MAC_FC_CMD(x) _SB_GETVALUE(x, S_MAC_FC_CMD, M_MAC_FC_CMD) #define S_MAC_RX_CH_SEL _SB_MAKE64(57) -#define M_MAC_RX_CH_SEL _SB_MAKEMASK(7,S_MAC_RX_CH_SEL) -#define V_MAC_RX_CH_SEL(x) _SB_MAKEVALUE(x,S_MAC_RX_CH_SEL) -#define G_MAC_RX_CH_SEL(x) _SB_GETVALUE(x,S_MAC_RX_CH_SEL,M_MAC_RX_CH_SEL) +#define M_MAC_RX_CH_SEL _SB_MAKEMASK(7, S_MAC_RX_CH_SEL) +#define V_MAC_RX_CH_SEL(x) _SB_MAKEVALUE(x, S_MAC_RX_CH_SEL) +#define G_MAC_RX_CH_SEL(x) _SB_GETVALUE(x, S_MAC_RX_CH_SEL, M_MAC_RX_CH_SEL) /* @@ -202,14 +202,14 @@ */ #define S_MAC_TXD_WEIGHT0 _SB_MAKE64(0) -#define M_MAC_TXD_WEIGHT0 _SB_MAKEMASK(4,S_MAC_TXD_WEIGHT0) -#define V_MAC_TXD_WEIGHT0(x) _SB_MAKEVALUE(x,S_MAC_TXD_WEIGHT0) -#define G_MAC_TXD_WEIGHT0(x) _SB_GETVALUE(x,S_MAC_TXD_WEIGHT0,M_MAC_TXD_WEIGHT0) +#define M_MAC_TXD_WEIGHT0 _SB_MAKEMASK(4, S_MAC_TXD_WEIGHT0) +#define V_MAC_TXD_WEIGHT0(x) _SB_MAKEVALUE(x, S_MAC_TXD_WEIGHT0) +#define G_MAC_TXD_WEIGHT0(x) _SB_GETVALUE(x, S_MAC_TXD_WEIGHT0, M_MAC_TXD_WEIGHT0) #define S_MAC_TXD_WEIGHT1 _SB_MAKE64(4) -#define M_MAC_TXD_WEIGHT1 _SB_MAKEMASK(4,S_MAC_TXD_WEIGHT1) -#define V_MAC_TXD_WEIGHT1(x) _SB_MAKEVALUE(x,S_MAC_TXD_WEIGHT1) -#define G_MAC_TXD_WEIGHT1(x) _SB_GETVALUE(x,S_MAC_TXD_WEIGHT1,M_MAC_TXD_WEIGHT1) +#define M_MAC_TXD_WEIGHT1 _SB_MAKEMASK(4, S_MAC_TXD_WEIGHT1) +#define V_MAC_TXD_WEIGHT1(x) _SB_MAKEVALUE(x, S_MAC_TXD_WEIGHT1) +#define G_MAC_TXD_WEIGHT1(x) _SB_GETVALUE(x, S_MAC_TXD_WEIGHT1, M_MAC_TXD_WEIGHT1) /* * MAC Fifo Threshhold registers (Table 9-14) @@ -221,50 +221,50 @@ #define S_MAC_TX_WR_THRSH _SB_MAKE64(0) #if SIBYTE_HDR_FEATURE_UP_TO(1250, PASS1) /* XXX: Can't enable, as it has the same name as a pass2+ define below. */ -/* #define M_MAC_TX_WR_THRSH _SB_MAKEMASK(6,S_MAC_TX_WR_THRSH) */ +/* #define M_MAC_TX_WR_THRSH _SB_MAKEMASK(6, S_MAC_TX_WR_THRSH) */ #endif /* up to 1250 PASS1 */ #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) -#define M_MAC_TX_WR_THRSH _SB_MAKEMASK(7,S_MAC_TX_WR_THRSH) +#define M_MAC_TX_WR_THRSH _SB_MAKEMASK(7, S_MAC_TX_WR_THRSH) #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ -#define V_MAC_TX_WR_THRSH(x) _SB_MAKEVALUE(x,S_MAC_TX_WR_THRSH) -#define G_MAC_TX_WR_THRSH(x) _SB_GETVALUE(x,S_MAC_TX_WR_THRSH,M_MAC_TX_WR_THRSH) +#define V_MAC_TX_WR_THRSH(x) _SB_MAKEVALUE(x, S_MAC_TX_WR_THRSH) +#define G_MAC_TX_WR_THRSH(x) _SB_GETVALUE(x, S_MAC_TX_WR_THRSH, M_MAC_TX_WR_THRSH) #define S_MAC_TX_RD_THRSH _SB_MAKE64(8) #if SIBYTE_HDR_FEATURE_UP_TO(1250, PASS1) /* XXX: Can't enable, as it has the same name as a pass2+ define below. */ -/* #define M_MAC_TX_RD_THRSH _SB_MAKEMASK(6,S_MAC_TX_RD_THRSH) */ +/* #define M_MAC_TX_RD_THRSH _SB_MAKEMASK(6, S_MAC_TX_RD_THRSH) */ #endif /* up to 1250 PASS1 */ #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) -#define M_MAC_TX_RD_THRSH _SB_MAKEMASK(7,S_MAC_TX_RD_THRSH) +#define M_MAC_TX_RD_THRSH _SB_MAKEMASK(7, S_MAC_TX_RD_THRSH) #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ -#define V_MAC_TX_RD_THRSH(x) _SB_MAKEVALUE(x,S_MAC_TX_RD_THRSH) -#define G_MAC_TX_RD_THRSH(x) _SB_GETVALUE(x,S_MAC_TX_RD_THRSH,M_MAC_TX_RD_THRSH) +#define V_MAC_TX_RD_THRSH(x) _SB_MAKEVALUE(x, S_MAC_TX_RD_THRSH) +#define G_MAC_TX_RD_THRSH(x) _SB_GETVALUE(x, S_MAC_TX_RD_THRSH, M_MAC_TX_RD_THRSH) #define S_MAC_TX_RL_THRSH _SB_MAKE64(16) -#define M_MAC_TX_RL_THRSH _SB_MAKEMASK(4,S_MAC_TX_RL_THRSH) -#define V_MAC_TX_RL_THRSH(x) _SB_MAKEVALUE(x,S_MAC_TX_RL_THRSH) -#define G_MAC_TX_RL_THRSH(x) _SB_GETVALUE(x,S_MAC_TX_RL_THRSH,M_MAC_TX_RL_THRSH) +#define M_MAC_TX_RL_THRSH _SB_MAKEMASK(4, S_MAC_TX_RL_THRSH) +#define V_MAC_TX_RL_THRSH(x) _SB_MAKEVALUE(x, S_MAC_TX_RL_THRSH) +#define G_MAC_TX_RL_THRSH(x) _SB_GETVALUE(x, S_MAC_TX_RL_THRSH, M_MAC_TX_RL_THRSH) #define S_MAC_RX_PL_THRSH _SB_MAKE64(24) -#define M_MAC_RX_PL_THRSH _SB_MAKEMASK(6,S_MAC_RX_PL_THRSH) -#define V_MAC_RX_PL_THRSH(x) _SB_MAKEVALUE(x,S_MAC_RX_PL_THRSH) -#define G_MAC_RX_PL_THRSH(x) _SB_GETVALUE(x,S_MAC_RX_PL_THRSH,M_MAC_RX_PL_THRSH) +#define M_MAC_RX_PL_THRSH _SB_MAKEMASK(6, S_MAC_RX_PL_THRSH) +#define V_MAC_RX_PL_THRSH(x) _SB_MAKEVALUE(x, S_MAC_RX_PL_THRSH) +#define G_MAC_RX_PL_THRSH(x) _SB_GETVALUE(x, S_MAC_RX_PL_THRSH, M_MAC_RX_PL_THRSH) #define S_MAC_RX_RD_THRSH _SB_MAKE64(32) -#define M_MAC_RX_RD_THRSH _SB_MAKEMASK(6,S_MAC_RX_RD_THRSH) -#define V_MAC_RX_RD_THRSH(x) _SB_MAKEVALUE(x,S_MAC_RX_RD_THRSH) -#define G_MAC_RX_RD_THRSH(x) _SB_GETVALUE(x,S_MAC_RX_RD_THRSH,M_MAC_RX_RD_THRSH) +#define M_MAC_RX_RD_THRSH _SB_MAKEMASK(6, S_MAC_RX_RD_THRSH) +#define V_MAC_RX_RD_THRSH(x) _SB_MAKEVALUE(x, S_MAC_RX_RD_THRSH) +#define G_MAC_RX_RD_THRSH(x) _SB_GETVALUE(x, S_MAC_RX_RD_THRSH, M_MAC_RX_RD_THRSH) #define S_MAC_RX_RL_THRSH _SB_MAKE64(40) -#define M_MAC_RX_RL_THRSH _SB_MAKEMASK(6,S_MAC_RX_RL_THRSH) -#define V_MAC_RX_RL_THRSH(x) _SB_MAKEVALUE(x,S_MAC_RX_RL_THRSH) -#define G_MAC_RX_RL_THRSH(x) _SB_GETVALUE(x,S_MAC_RX_RL_THRSH,M_MAC_RX_RL_THRSH) +#define M_MAC_RX_RL_THRSH _SB_MAKEMASK(6, S_MAC_RX_RL_THRSH) +#define V_MAC_RX_RL_THRSH(x) _SB_MAKEVALUE(x, S_MAC_RX_RL_THRSH) +#define G_MAC_RX_RL_THRSH(x) _SB_GETVALUE(x, S_MAC_RX_RL_THRSH, M_MAC_RX_RL_THRSH) #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_MAC_ENC_FC_THRSH _SB_MAKE64(56) -#define M_MAC_ENC_FC_THRSH _SB_MAKEMASK(6,S_MAC_ENC_FC_THRSH) -#define V_MAC_ENC_FC_THRSH(x) _SB_MAKEVALUE(x,S_MAC_ENC_FC_THRSH) -#define G_MAC_ENC_FC_THRSH(x) _SB_GETVALUE(x,S_MAC_ENC_FC_THRSH,M_MAC_ENC_FC_THRSH) +#define M_MAC_ENC_FC_THRSH _SB_MAKEMASK(6, S_MAC_ENC_FC_THRSH) +#define V_MAC_ENC_FC_THRSH(x) _SB_MAKEVALUE(x, S_MAC_ENC_FC_THRSH) +#define G_MAC_ENC_FC_THRSH(x) _SB_GETVALUE(x, S_MAC_ENC_FC_THRSH, M_MAC_ENC_FC_THRSH) #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ /* @@ -276,51 +276,51 @@ /* XXXCGD: ??? Unused in pass2? */ #define S_MAC_IFG_RX _SB_MAKE64(0) -#define M_MAC_IFG_RX _SB_MAKEMASK(6,S_MAC_IFG_RX) -#define V_MAC_IFG_RX(x) _SB_MAKEVALUE(x,S_MAC_IFG_RX) -#define G_MAC_IFG_RX(x) _SB_GETVALUE(x,S_MAC_IFG_RX,M_MAC_IFG_RX) +#define M_MAC_IFG_RX _SB_MAKEMASK(6, S_MAC_IFG_RX) +#define V_MAC_IFG_RX(x) _SB_MAKEVALUE(x, S_MAC_IFG_RX) +#define G_MAC_IFG_RX(x) _SB_GETVALUE(x, S_MAC_IFG_RX, M_MAC_IFG_RX) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_MAC_PRE_LEN _SB_MAKE64(0) -#define M_MAC_PRE_LEN _SB_MAKEMASK(6,S_MAC_PRE_LEN) -#define V_MAC_PRE_LEN(x) _SB_MAKEVALUE(x,S_MAC_PRE_LEN) -#define G_MAC_PRE_LEN(x) _SB_GETVALUE(x,S_MAC_PRE_LEN,M_MAC_PRE_LEN) +#define M_MAC_PRE_LEN _SB_MAKEMASK(6, S_MAC_PRE_LEN) +#define V_MAC_PRE_LEN(x) _SB_MAKEVALUE(x, S_MAC_PRE_LEN) +#define G_MAC_PRE_LEN(x) _SB_GETVALUE(x, S_MAC_PRE_LEN, M_MAC_PRE_LEN) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ #define S_MAC_IFG_TX _SB_MAKE64(6) -#define M_MAC_IFG_TX _SB_MAKEMASK(6,S_MAC_IFG_TX) -#define V_MAC_IFG_TX(x) _SB_MAKEVALUE(x,S_MAC_IFG_TX) -#define G_MAC_IFG_TX(x) _SB_GETVALUE(x,S_MAC_IFG_TX,M_MAC_IFG_TX) +#define M_MAC_IFG_TX _SB_MAKEMASK(6, S_MAC_IFG_TX) +#define V_MAC_IFG_TX(x) _SB_MAKEVALUE(x, S_MAC_IFG_TX) +#define G_MAC_IFG_TX(x) _SB_GETVALUE(x, S_MAC_IFG_TX, M_MAC_IFG_TX) #define S_MAC_IFG_THRSH _SB_MAKE64(12) -#define M_MAC_IFG_THRSH _SB_MAKEMASK(6,S_MAC_IFG_THRSH) -#define V_MAC_IFG_THRSH(x) _SB_MAKEVALUE(x,S_MAC_IFG_THRSH) -#define G_MAC_IFG_THRSH(x) _SB_GETVALUE(x,S_MAC_IFG_THRSH,M_MAC_IFG_THRSH) +#define M_MAC_IFG_THRSH _SB_MAKEMASK(6, S_MAC_IFG_THRSH) +#define V_MAC_IFG_THRSH(x) _SB_MAKEVALUE(x, S_MAC_IFG_THRSH) +#define G_MAC_IFG_THRSH(x) _SB_GETVALUE(x, S_MAC_IFG_THRSH, M_MAC_IFG_THRSH) #define S_MAC_BACKOFF_SEL _SB_MAKE64(18) -#define M_MAC_BACKOFF_SEL _SB_MAKEMASK(4,S_MAC_BACKOFF_SEL) -#define V_MAC_BACKOFF_SEL(x) _SB_MAKEVALUE(x,S_MAC_BACKOFF_SEL) -#define G_MAC_BACKOFF_SEL(x) _SB_GETVALUE(x,S_MAC_BACKOFF_SEL,M_MAC_BACKOFF_SEL) +#define M_MAC_BACKOFF_SEL _SB_MAKEMASK(4, S_MAC_BACKOFF_SEL) +#define V_MAC_BACKOFF_SEL(x) _SB_MAKEVALUE(x, S_MAC_BACKOFF_SEL) +#define G_MAC_BACKOFF_SEL(x) _SB_GETVALUE(x, S_MAC_BACKOFF_SEL, M_MAC_BACKOFF_SEL) #define S_MAC_LFSR_SEED _SB_MAKE64(22) -#define M_MAC_LFSR_SEED _SB_MAKEMASK(8,S_MAC_LFSR_SEED) -#define V_MAC_LFSR_SEED(x) _SB_MAKEVALUE(x,S_MAC_LFSR_SEED) -#define G_MAC_LFSR_SEED(x) _SB_GETVALUE(x,S_MAC_LFSR_SEED,M_MAC_LFSR_SEED) +#define M_MAC_LFSR_SEED _SB_MAKEMASK(8, S_MAC_LFSR_SEED) +#define V_MAC_LFSR_SEED(x) _SB_MAKEVALUE(x, S_MAC_LFSR_SEED) +#define G_MAC_LFSR_SEED(x) _SB_GETVALUE(x, S_MAC_LFSR_SEED, M_MAC_LFSR_SEED) #define S_MAC_SLOT_SIZE _SB_MAKE64(30) -#define M_MAC_SLOT_SIZE _SB_MAKEMASK(10,S_MAC_SLOT_SIZE) -#define V_MAC_SLOT_SIZE(x) _SB_MAKEVALUE(x,S_MAC_SLOT_SIZE) -#define G_MAC_SLOT_SIZE(x) _SB_GETVALUE(x,S_MAC_SLOT_SIZE,M_MAC_SLOT_SIZE) +#define M_MAC_SLOT_SIZE _SB_MAKEMASK(10, S_MAC_SLOT_SIZE) +#define V_MAC_SLOT_SIZE(x) _SB_MAKEVALUE(x, S_MAC_SLOT_SIZE) +#define G_MAC_SLOT_SIZE(x) _SB_GETVALUE(x, S_MAC_SLOT_SIZE, M_MAC_SLOT_SIZE) #define S_MAC_MIN_FRAMESZ _SB_MAKE64(40) -#define M_MAC_MIN_FRAMESZ _SB_MAKEMASK(8,S_MAC_MIN_FRAMESZ) -#define V_MAC_MIN_FRAMESZ(x) _SB_MAKEVALUE(x,S_MAC_MIN_FRAMESZ) -#define G_MAC_MIN_FRAMESZ(x) _SB_GETVALUE(x,S_MAC_MIN_FRAMESZ,M_MAC_MIN_FRAMESZ) +#define M_MAC_MIN_FRAMESZ _SB_MAKEMASK(8, S_MAC_MIN_FRAMESZ) +#define V_MAC_MIN_FRAMESZ(x) _SB_MAKEVALUE(x, S_MAC_MIN_FRAMESZ) +#define G_MAC_MIN_FRAMESZ(x) _SB_GETVALUE(x, S_MAC_MIN_FRAMESZ, M_MAC_MIN_FRAMESZ) #define S_MAC_MAX_FRAMESZ _SB_MAKE64(48) -#define M_MAC_MAX_FRAMESZ _SB_MAKEMASK(16,S_MAC_MAX_FRAMESZ) -#define V_MAC_MAX_FRAMESZ(x) _SB_MAKEVALUE(x,S_MAC_MAX_FRAMESZ) -#define G_MAC_MAX_FRAMESZ(x) _SB_GETVALUE(x,S_MAC_MAX_FRAMESZ,M_MAC_MAX_FRAMESZ) +#define M_MAC_MAX_FRAMESZ _SB_MAKEMASK(16, S_MAC_MAX_FRAMESZ) +#define V_MAC_MAX_FRAMESZ(x) _SB_MAKEVALUE(x, S_MAC_MAX_FRAMESZ) +#define G_MAC_MAX_FRAMESZ(x) _SB_GETVALUE(x, S_MAC_MAX_FRAMESZ, M_MAC_MAX_FRAMESZ) /* * These constants are used to configure the fields within the Frame @@ -377,20 +377,20 @@ */ #define S_MAC_VLAN_TAG _SB_MAKE64(0) -#define M_MAC_VLAN_TAG _SB_MAKEMASK(32,S_MAC_VLAN_TAG) -#define V_MAC_VLAN_TAG(x) _SB_MAKEVALUE(x,S_MAC_VLAN_TAG) -#define G_MAC_VLAN_TAG(x) _SB_GETVALUE(x,S_MAC_VLAN_TAG,M_MAC_VLAN_TAG) +#define M_MAC_VLAN_TAG _SB_MAKEMASK(32, S_MAC_VLAN_TAG) +#define V_MAC_VLAN_TAG(x) _SB_MAKEVALUE(x, S_MAC_VLAN_TAG) +#define G_MAC_VLAN_TAG(x) _SB_GETVALUE(x, S_MAC_VLAN_TAG, M_MAC_VLAN_TAG) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) #define S_MAC_TX_PKT_OFFSET _SB_MAKE64(32) -#define M_MAC_TX_PKT_OFFSET _SB_MAKEMASK(8,S_MAC_TX_PKT_OFFSET) -#define V_MAC_TX_PKT_OFFSET(x) _SB_MAKEVALUE(x,S_MAC_TX_PKT_OFFSET) -#define G_MAC_TX_PKT_OFFSET(x) _SB_GETVALUE(x,S_MAC_TX_PKT_OFFSET,M_MAC_TX_PKT_OFFSET) +#define M_MAC_TX_PKT_OFFSET _SB_MAKEMASK(8, S_MAC_TX_PKT_OFFSET) +#define V_MAC_TX_PKT_OFFSET(x) _SB_MAKEVALUE(x, S_MAC_TX_PKT_OFFSET) +#define G_MAC_TX_PKT_OFFSET(x) _SB_GETVALUE(x, S_MAC_TX_PKT_OFFSET, M_MAC_TX_PKT_OFFSET) #define S_MAC_TX_CRC_OFFSET _SB_MAKE64(40) -#define M_MAC_TX_CRC_OFFSET _SB_MAKEMASK(8,S_MAC_TX_CRC_OFFSET) -#define V_MAC_TX_CRC_OFFSET(x) _SB_MAKEVALUE(x,S_MAC_TX_CRC_OFFSET) -#define G_MAC_TX_CRC_OFFSET(x) _SB_GETVALUE(x,S_MAC_TX_CRC_OFFSET,M_MAC_TX_CRC_OFFSET) +#define M_MAC_TX_CRC_OFFSET _SB_MAKEMASK(8, S_MAC_TX_CRC_OFFSET) +#define V_MAC_TX_CRC_OFFSET(x) _SB_MAKEVALUE(x, S_MAC_TX_CRC_OFFSET) +#define G_MAC_TX_CRC_OFFSET(x) _SB_GETVALUE(x, S_MAC_TX_CRC_OFFSET, M_MAC_TX_CRC_OFFSET) #define M_MAC_CH_BASE_FC_EN _SB_MAKEMASK1(48) #endif /* 1250 PASS3 || 112x PASS1 */ @@ -425,7 +425,7 @@ * is that you'll use one of the "S_" things above * and pass just the six bits to a DMA-channel-specific ISR */ -#define M_MAC_INT_CHANNEL _SB_MAKEMASK(8,0) +#define M_MAC_INT_CHANNEL _SB_MAKEMASK(8, 0) #define M_MAC_INT_EOP_COUNT _SB_MAKEMASK1(0) #define M_MAC_INT_EOP_TIMER _SB_MAKEMASK1(1) #define M_MAC_INT_EOP_SEEN _SB_MAKEMASK1(2) @@ -440,19 +440,19 @@ * In the following definitions we use ch (0/1) and txrx (TX=1, RX=0, see * also DMA_TX/DMA_RX in sb_regs.h). */ -#define S_MAC_STATUS_CH_OFFSET(ch,txrx) _SB_MAKE64(((ch) + 2 * (txrx)) * S_MAC_CHANWIDTH) +#define S_MAC_STATUS_CH_OFFSET(ch, txrx) _SB_MAKE64(((ch) + 2 * (txrx)) * S_MAC_CHANWIDTH) -#define M_MAC_STATUS_CHANNEL(ch,txrx) _SB_MAKEVALUE(_SB_MAKEMASK(8,0),S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_EOP_COUNT(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_EOP_COUNT,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_EOP_TIMER(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_EOP_TIMER,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_EOP_SEEN(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_EOP_SEEN,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_HWM(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_HWM,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_LWM(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_LWM,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_DSCR(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_DSCR,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_ERR(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_ERR,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_DZERO(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_DZERO,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_DROP(ch,txrx) _SB_MAKEVALUE(M_MAC_INT_DROP,S_MAC_STATUS_CH_OFFSET(ch,txrx)) -#define M_MAC_STATUS_OTHER_ERR _SB_MAKEVALUE(_SB_MAKEMASK(7,0),40) +#define M_MAC_STATUS_CHANNEL(ch, txrx) _SB_MAKEVALUE(_SB_MAKEMASK(8, 0), S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_EOP_COUNT(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_EOP_COUNT, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_EOP_TIMER(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_EOP_TIMER, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_EOP_SEEN(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_EOP_SEEN, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_HWM(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_HWM, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_LWM(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_LWM, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_DSCR(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_DSCR, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_ERR(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_ERR, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_DZERO(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_DZERO, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_DROP(ch, txrx) _SB_MAKEVALUE(M_MAC_INT_DROP, S_MAC_STATUS_CH_OFFSET(ch, txrx)) +#define M_MAC_STATUS_OTHER_ERR _SB_MAKEVALUE(_SB_MAKEMASK(7, 0), 40) #define M_MAC_RX_UNDRFL _SB_MAKEMASK1(40) @@ -467,9 +467,9 @@ #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ #define S_MAC_COUNTER_ADDR _SB_MAKE64(47) -#define M_MAC_COUNTER_ADDR _SB_MAKEMASK(5,S_MAC_COUNTER_ADDR) -#define V_MAC_COUNTER_ADDR(x) _SB_MAKEVALUE(x,S_MAC_COUNTER_ADDR) -#define G_MAC_COUNTER_ADDR(x) _SB_GETVALUE(x,S_MAC_COUNTER_ADDR,M_MAC_COUNTER_ADDR) +#define M_MAC_COUNTER_ADDR _SB_MAKEMASK(5, S_MAC_COUNTER_ADDR) +#define V_MAC_COUNTER_ADDR(x) _SB_MAKEVALUE(x, S_MAC_COUNTER_ADDR) +#define G_MAC_COUNTER_ADDR(x) _SB_GETVALUE(x, S_MAC_COUNTER_ADDR, M_MAC_COUNTER_ADDR) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define M_MAC_TX_PAUSE_ON _SB_MAKEMASK1(52) @@ -483,24 +483,24 @@ */ #define S_MAC_TX_WRPTR _SB_MAKE64(0) -#define M_MAC_TX_WRPTR _SB_MAKEMASK(6,S_MAC_TX_WRPTR) -#define V_MAC_TX_WRPTR(x) _SB_MAKEVALUE(x,S_MAC_TX_WRPTR) -#define G_MAC_TX_WRPTR(x) _SB_GETVALUE(x,S_MAC_TX_WRPTR,M_MAC_TX_WRPTR) +#define M_MAC_TX_WRPTR _SB_MAKEMASK(6, S_MAC_TX_WRPTR) +#define V_MAC_TX_WRPTR(x) _SB_MAKEVALUE(x, S_MAC_TX_WRPTR) +#define G_MAC_TX_WRPTR(x) _SB_GETVALUE(x, S_MAC_TX_WRPTR, M_MAC_TX_WRPTR) #define S_MAC_TX_RDPTR _SB_MAKE64(8) -#define M_MAC_TX_RDPTR _SB_MAKEMASK(6,S_MAC_TX_RDPTR) -#define V_MAC_TX_RDPTR(x) _SB_MAKEVALUE(x,S_MAC_TX_RDPTR) -#define G_MAC_TX_RDPTR(x) _SB_GETVALUE(x,S_MAC_TX_RDPTR,M_MAC_TX_RDPTR) +#define M_MAC_TX_RDPTR _SB_MAKEMASK(6, S_MAC_TX_RDPTR) +#define V_MAC_TX_RDPTR(x) _SB_MAKEVALUE(x, S_MAC_TX_RDPTR) +#define G_MAC_TX_RDPTR(x) _SB_GETVALUE(x, S_MAC_TX_RDPTR, M_MAC_TX_RDPTR) #define S_MAC_RX_WRPTR _SB_MAKE64(16) -#define M_MAC_RX_WRPTR _SB_MAKEMASK(6,S_MAC_RX_WRPTR) -#define V_MAC_RX_WRPTR(x) _SB_MAKEVALUE(x,S_MAC_RX_WRPTR) -#define G_MAC_RX_WRPTR(x) _SB_GETVALUE(x,S_MAC_RX_WRPTR,M_MAC_TX_WRPTR) +#define M_MAC_RX_WRPTR _SB_MAKEMASK(6, S_MAC_RX_WRPTR) +#define V_MAC_RX_WRPTR(x) _SB_MAKEVALUE(x, S_MAC_RX_WRPTR) +#define G_MAC_RX_WRPTR(x) _SB_GETVALUE(x, S_MAC_RX_WRPTR, M_MAC_TX_WRPTR) #define S_MAC_RX_RDPTR _SB_MAKE64(24) -#define M_MAC_RX_RDPTR _SB_MAKEMASK(6,S_MAC_RX_RDPTR) -#define V_MAC_RX_RDPTR(x) _SB_MAKEVALUE(x,S_MAC_RX_RDPTR) -#define G_MAC_RX_RDPTR(x) _SB_GETVALUE(x,S_MAC_RX_RDPTR,M_MAC_TX_RDPTR) +#define M_MAC_RX_RDPTR _SB_MAKEMASK(6, S_MAC_RX_RDPTR) +#define V_MAC_RX_RDPTR(x) _SB_MAKEVALUE(x, S_MAC_RX_RDPTR) +#define G_MAC_RX_RDPTR(x) _SB_GETVALUE(x, S_MAC_RX_RDPTR, M_MAC_TX_RDPTR) /* * MAC Fifo End Of Packet Count Registers (Table 9-20) [Debug register] @@ -510,14 +510,14 @@ */ #define S_MAC_TX_EOP_COUNTER _SB_MAKE64(0) -#define M_MAC_TX_EOP_COUNTER _SB_MAKEMASK(6,S_MAC_TX_EOP_COUNTER) -#define V_MAC_TX_EOP_COUNTER(x) _SB_MAKEVALUE(x,S_MAC_TX_EOP_COUNTER) -#define G_MAC_TX_EOP_COUNTER(x) _SB_GETVALUE(x,S_MAC_TX_EOP_COUNTER,M_MAC_TX_EOP_COUNTER) +#define M_MAC_TX_EOP_COUNTER _SB_MAKEMASK(6, S_MAC_TX_EOP_COUNTER) +#define V_MAC_TX_EOP_COUNTER(x) _SB_MAKEVALUE(x, S_MAC_TX_EOP_COUNTER) +#define G_MAC_TX_EOP_COUNTER(x) _SB_GETVALUE(x, S_MAC_TX_EOP_COUNTER, M_MAC_TX_EOP_COUNTER) #define S_MAC_RX_EOP_COUNTER _SB_MAKE64(8) -#define M_MAC_RX_EOP_COUNTER _SB_MAKEMASK(6,S_MAC_RX_EOP_COUNTER) -#define V_MAC_RX_EOP_COUNTER(x) _SB_MAKEVALUE(x,S_MAC_RX_EOP_COUNTER) -#define G_MAC_RX_EOP_COUNTER(x) _SB_GETVALUE(x,S_MAC_RX_EOP_COUNTER,M_MAC_RX_EOP_COUNTER) +#define M_MAC_RX_EOP_COUNTER _SB_MAKEMASK(6, S_MAC_RX_EOP_COUNTER) +#define V_MAC_RX_EOP_COUNTER(x) _SB_MAKEVALUE(x, S_MAC_RX_EOP_COUNTER) +#define G_MAC_RX_EOP_COUNTER(x) _SB_GETVALUE(x, S_MAC_RX_EOP_COUNTER, M_MAC_RX_EOP_COUNTER) /* * MAC Recieve Address Filter Exact Match Registers (Table 9-21) @@ -565,24 +565,24 @@ #define S_TYPECFG_TYPESIZE _SB_MAKE64(16) #define S_TYPECFG_TYPE0 _SB_MAKE64(0) -#define M_TYPECFG_TYPE0 _SB_MAKEMASK(16,S_TYPECFG_TYPE0) -#define V_TYPECFG_TYPE0(x) _SB_MAKEVALUE(x,S_TYPECFG_TYPE0) -#define G_TYPECFG_TYPE0(x) _SB_GETVALUE(x,S_TYPECFG_TYPE0,M_TYPECFG_TYPE0) +#define M_TYPECFG_TYPE0 _SB_MAKEMASK(16, S_TYPECFG_TYPE0) +#define V_TYPECFG_TYPE0(x) _SB_MAKEVALUE(x, S_TYPECFG_TYPE0) +#define G_TYPECFG_TYPE0(x) _SB_GETVALUE(x, S_TYPECFG_TYPE0, M_TYPECFG_TYPE0) #define S_TYPECFG_TYPE1 _SB_MAKE64(0) -#define M_TYPECFG_TYPE1 _SB_MAKEMASK(16,S_TYPECFG_TYPE1) -#define V_TYPECFG_TYPE1(x) _SB_MAKEVALUE(x,S_TYPECFG_TYPE1) -#define G_TYPECFG_TYPE1(x) _SB_GETVALUE(x,S_TYPECFG_TYPE1,M_TYPECFG_TYPE1) +#define M_TYPECFG_TYPE1 _SB_MAKEMASK(16, S_TYPECFG_TYPE1) +#define V_TYPECFG_TYPE1(x) _SB_MAKEVALUE(x, S_TYPECFG_TYPE1) +#define G_TYPECFG_TYPE1(x) _SB_GETVALUE(x, S_TYPECFG_TYPE1, M_TYPECFG_TYPE1) #define S_TYPECFG_TYPE2 _SB_MAKE64(0) -#define M_TYPECFG_TYPE2 _SB_MAKEMASK(16,S_TYPECFG_TYPE2) -#define V_TYPECFG_TYPE2(x) _SB_MAKEVALUE(x,S_TYPECFG_TYPE2) -#define G_TYPECFG_TYPE2(x) _SB_GETVALUE(x,S_TYPECFG_TYPE2,M_TYPECFG_TYPE2) +#define M_TYPECFG_TYPE2 _SB_MAKEMASK(16, S_TYPECFG_TYPE2) +#define V_TYPECFG_TYPE2(x) _SB_MAKEVALUE(x, S_TYPECFG_TYPE2) +#define G_TYPECFG_TYPE2(x) _SB_GETVALUE(x, S_TYPECFG_TYPE2, M_TYPECFG_TYPE2) #define S_TYPECFG_TYPE3 _SB_MAKE64(0) -#define M_TYPECFG_TYPE3 _SB_MAKEMASK(16,S_TYPECFG_TYPE3) -#define V_TYPECFG_TYPE3(x) _SB_MAKEVALUE(x,S_TYPECFG_TYPE3) -#define G_TYPECFG_TYPE3(x) _SB_GETVALUE(x,S_TYPECFG_TYPE3,M_TYPECFG_TYPE3) +#define M_TYPECFG_TYPE3 _SB_MAKEMASK(16, S_TYPECFG_TYPE3) +#define V_TYPECFG_TYPE3(x) _SB_MAKEVALUE(x, S_TYPECFG_TYPE3) +#define G_TYPECFG_TYPE3(x) _SB_GETVALUE(x, S_TYPECFG_TYPE3, M_TYPECFG_TYPE3) /* * MAC Receive Address Filter Control Registers (Table 9-24) @@ -603,28 +603,28 @@ #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ #define S_MAC_IPHDR_OFFSET _SB_MAKE64(8) -#define M_MAC_IPHDR_OFFSET _SB_MAKEMASK(8,S_MAC_IPHDR_OFFSET) -#define V_MAC_IPHDR_OFFSET(x) _SB_MAKEVALUE(x,S_MAC_IPHDR_OFFSET) -#define G_MAC_IPHDR_OFFSET(x) _SB_GETVALUE(x,S_MAC_IPHDR_OFFSET,M_MAC_IPHDR_OFFSET) +#define M_MAC_IPHDR_OFFSET _SB_MAKEMASK(8, S_MAC_IPHDR_OFFSET) +#define V_MAC_IPHDR_OFFSET(x) _SB_MAKEVALUE(x, S_MAC_IPHDR_OFFSET) +#define G_MAC_IPHDR_OFFSET(x) _SB_GETVALUE(x, S_MAC_IPHDR_OFFSET, M_MAC_IPHDR_OFFSET) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_MAC_RX_CRC_OFFSET _SB_MAKE64(16) -#define M_MAC_RX_CRC_OFFSET _SB_MAKEMASK(8,S_MAC_RX_CRC_OFFSET) -#define V_MAC_RX_CRC_OFFSET(x) _SB_MAKEVALUE(x,S_MAC_RX_CRC_OFFSET) -#define G_MAC_RX_CRC_OFFSET(x) _SB_GETVALUE(x,S_MAC_RX_CRC_OFFSET,M_MAC_RX_CRC_OFFSET) +#define M_MAC_RX_CRC_OFFSET _SB_MAKEMASK(8, S_MAC_RX_CRC_OFFSET) +#define V_MAC_RX_CRC_OFFSET(x) _SB_MAKEVALUE(x, S_MAC_RX_CRC_OFFSET) +#define G_MAC_RX_CRC_OFFSET(x) _SB_GETVALUE(x, S_MAC_RX_CRC_OFFSET, M_MAC_RX_CRC_OFFSET) #define S_MAC_RX_PKT_OFFSET _SB_MAKE64(24) -#define M_MAC_RX_PKT_OFFSET _SB_MAKEMASK(8,S_MAC_RX_PKT_OFFSET) -#define V_MAC_RX_PKT_OFFSET(x) _SB_MAKEVALUE(x,S_MAC_RX_PKT_OFFSET) -#define G_MAC_RX_PKT_OFFSET(x) _SB_GETVALUE(x,S_MAC_RX_PKT_OFFSET,M_MAC_RX_PKT_OFFSET) +#define M_MAC_RX_PKT_OFFSET _SB_MAKEMASK(8, S_MAC_RX_PKT_OFFSET) +#define V_MAC_RX_PKT_OFFSET(x) _SB_MAKEVALUE(x, S_MAC_RX_PKT_OFFSET) +#define G_MAC_RX_PKT_OFFSET(x) _SB_GETVALUE(x, S_MAC_RX_PKT_OFFSET, M_MAC_RX_PKT_OFFSET) #define M_MAC_FWDPAUSE_EN _SB_MAKEMASK1(32) #define M_MAC_VLAN_DET_EN _SB_MAKEMASK1(33) #define S_MAC_RX_CH_MSN_SEL _SB_MAKE64(34) -#define M_MAC_RX_CH_MSN_SEL _SB_MAKEMASK(8,S_MAC_RX_CH_MSN_SEL) -#define V_MAC_RX_CH_MSN_SEL(x) _SB_MAKEVALUE(x,S_MAC_RX_CH_MSN_SEL) -#define G_MAC_RX_CH_MSN_SEL(x) _SB_GETVALUE(x,S_MAC_RX_CH_MSN_SEL,M_MAC_RX_CH_MSN_SEL) +#define M_MAC_RX_CH_MSN_SEL _SB_MAKEMASK(8, S_MAC_RX_CH_MSN_SEL) +#define V_MAC_RX_CH_MSN_SEL(x) _SB_MAKEVALUE(x, S_MAC_RX_CH_MSN_SEL) +#define G_MAC_RX_CH_MSN_SEL(x) _SB_GETVALUE(x, S_MAC_RX_CH_MSN_SEL, M_MAC_RX_CH_MSN_SEL) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ /* diff --git a/include/asm-mips/sibyte/sb1250_mc.h b/include/asm-mips/sibyte/sb1250_mc.h index 4fe848ffbc31..1eb1b5a88736 100644 --- a/include/asm-mips/sibyte/sb1250_mc.h +++ b/include/asm-mips/sibyte/sb1250_mc.h @@ -10,7 +10,7 @@ * ********************************************************************* * - * Copyright 2000,2001,2002,2003 + * Copyright 2000, 2001, 2002, 2003 * Broadcom Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or @@ -40,73 +40,73 @@ */ #define S_MC_RESERVED0 0 -#define M_MC_RESERVED0 _SB_MAKEMASK(8,S_MC_RESERVED0) +#define M_MC_RESERVED0 _SB_MAKEMASK(8, S_MC_RESERVED0) #define S_MC_CHANNEL_SEL 8 -#define M_MC_CHANNEL_SEL _SB_MAKEMASK(8,S_MC_CHANNEL_SEL) -#define V_MC_CHANNEL_SEL(x) _SB_MAKEVALUE(x,S_MC_CHANNEL_SEL) -#define G_MC_CHANNEL_SEL(x) _SB_GETVALUE(x,S_MC_CHANNEL_SEL,M_MC_CHANNEL_SEL) +#define M_MC_CHANNEL_SEL _SB_MAKEMASK(8, S_MC_CHANNEL_SEL) +#define V_MC_CHANNEL_SEL(x) _SB_MAKEVALUE(x, S_MC_CHANNEL_SEL) +#define G_MC_CHANNEL_SEL(x) _SB_GETVALUE(x, S_MC_CHANNEL_SEL, M_MC_CHANNEL_SEL) #define S_MC_BANK0_MAP 16 -#define M_MC_BANK0_MAP _SB_MAKEMASK(4,S_MC_BANK0_MAP) -#define V_MC_BANK0_MAP(x) _SB_MAKEVALUE(x,S_MC_BANK0_MAP) -#define G_MC_BANK0_MAP(x) _SB_GETVALUE(x,S_MC_BANK0_MAP,M_MC_BANK0_MAP) +#define M_MC_BANK0_MAP _SB_MAKEMASK(4, S_MC_BANK0_MAP) +#define V_MC_BANK0_MAP(x) _SB_MAKEVALUE(x, S_MC_BANK0_MAP) +#define G_MC_BANK0_MAP(x) _SB_GETVALUE(x, S_MC_BANK0_MAP, M_MC_BANK0_MAP) #define K_MC_BANK0_MAP_DEFAULT 0x00 #define V_MC_BANK0_MAP_DEFAULT V_MC_BANK0_MAP(K_MC_BANK0_MAP_DEFAULT) #define S_MC_BANK1_MAP 20 -#define M_MC_BANK1_MAP _SB_MAKEMASK(4,S_MC_BANK1_MAP) -#define V_MC_BANK1_MAP(x) _SB_MAKEVALUE(x,S_MC_BANK1_MAP) -#define G_MC_BANK1_MAP(x) _SB_GETVALUE(x,S_MC_BANK1_MAP,M_MC_BANK1_MAP) +#define M_MC_BANK1_MAP _SB_MAKEMASK(4, S_MC_BANK1_MAP) +#define V_MC_BANK1_MAP(x) _SB_MAKEVALUE(x, S_MC_BANK1_MAP) +#define G_MC_BANK1_MAP(x) _SB_GETVALUE(x, S_MC_BANK1_MAP, M_MC_BANK1_MAP) #define K_MC_BANK1_MAP_DEFAULT 0x08 #define V_MC_BANK1_MAP_DEFAULT V_MC_BANK1_MAP(K_MC_BANK1_MAP_DEFAULT) #define S_MC_BANK2_MAP 24 -#define M_MC_BANK2_MAP _SB_MAKEMASK(4,S_MC_BANK2_MAP) -#define V_MC_BANK2_MAP(x) _SB_MAKEVALUE(x,S_MC_BANK2_MAP) -#define G_MC_BANK2_MAP(x) _SB_GETVALUE(x,S_MC_BANK2_MAP,M_MC_BANK2_MAP) +#define M_MC_BANK2_MAP _SB_MAKEMASK(4, S_MC_BANK2_MAP) +#define V_MC_BANK2_MAP(x) _SB_MAKEVALUE(x, S_MC_BANK2_MAP) +#define G_MC_BANK2_MAP(x) _SB_GETVALUE(x, S_MC_BANK2_MAP, M_MC_BANK2_MAP) #define K_MC_BANK2_MAP_DEFAULT 0x09 #define V_MC_BANK2_MAP_DEFAULT V_MC_BANK2_MAP(K_MC_BANK2_MAP_DEFAULT) #define S_MC_BANK3_MAP 28 -#define M_MC_BANK3_MAP _SB_MAKEMASK(4,S_MC_BANK3_MAP) -#define V_MC_BANK3_MAP(x) _SB_MAKEVALUE(x,S_MC_BANK3_MAP) -#define G_MC_BANK3_MAP(x) _SB_GETVALUE(x,S_MC_BANK3_MAP,M_MC_BANK3_MAP) +#define M_MC_BANK3_MAP _SB_MAKEMASK(4, S_MC_BANK3_MAP) +#define V_MC_BANK3_MAP(x) _SB_MAKEVALUE(x, S_MC_BANK3_MAP) +#define G_MC_BANK3_MAP(x) _SB_GETVALUE(x, S_MC_BANK3_MAP, M_MC_BANK3_MAP) #define K_MC_BANK3_MAP_DEFAULT 0x0C #define V_MC_BANK3_MAP_DEFAULT V_MC_BANK3_MAP(K_MC_BANK3_MAP_DEFAULT) -#define M_MC_RESERVED1 _SB_MAKEMASK(8,32) +#define M_MC_RESERVED1 _SB_MAKEMASK(8, 32) #define S_MC_QUEUE_SIZE 40 -#define M_MC_QUEUE_SIZE _SB_MAKEMASK(4,S_MC_QUEUE_SIZE) -#define V_MC_QUEUE_SIZE(x) _SB_MAKEVALUE(x,S_MC_QUEUE_SIZE) -#define G_MC_QUEUE_SIZE(x) _SB_GETVALUE(x,S_MC_QUEUE_SIZE,M_MC_QUEUE_SIZE) +#define M_MC_QUEUE_SIZE _SB_MAKEMASK(4, S_MC_QUEUE_SIZE) +#define V_MC_QUEUE_SIZE(x) _SB_MAKEVALUE(x, S_MC_QUEUE_SIZE) +#define G_MC_QUEUE_SIZE(x) _SB_GETVALUE(x, S_MC_QUEUE_SIZE, M_MC_QUEUE_SIZE) #define V_MC_QUEUE_SIZE_DEFAULT V_MC_QUEUE_SIZE(0x0A) #define S_MC_AGE_LIMIT 44 -#define M_MC_AGE_LIMIT _SB_MAKEMASK(4,S_MC_AGE_LIMIT) -#define V_MC_AGE_LIMIT(x) _SB_MAKEVALUE(x,S_MC_AGE_LIMIT) -#define G_MC_AGE_LIMIT(x) _SB_GETVALUE(x,S_MC_AGE_LIMIT,M_MC_AGE_LIMIT) +#define M_MC_AGE_LIMIT _SB_MAKEMASK(4, S_MC_AGE_LIMIT) +#define V_MC_AGE_LIMIT(x) _SB_MAKEVALUE(x, S_MC_AGE_LIMIT) +#define G_MC_AGE_LIMIT(x) _SB_GETVALUE(x, S_MC_AGE_LIMIT, M_MC_AGE_LIMIT) #define V_MC_AGE_LIMIT_DEFAULT V_MC_AGE_LIMIT(8) #define S_MC_WR_LIMIT 48 -#define M_MC_WR_LIMIT _SB_MAKEMASK(4,S_MC_WR_LIMIT) -#define V_MC_WR_LIMIT(x) _SB_MAKEVALUE(x,S_MC_WR_LIMIT) -#define G_MC_WR_LIMIT(x) _SB_GETVALUE(x,S_MC_WR_LIMIT,M_MC_WR_LIMIT) +#define M_MC_WR_LIMIT _SB_MAKEMASK(4, S_MC_WR_LIMIT) +#define V_MC_WR_LIMIT(x) _SB_MAKEVALUE(x, S_MC_WR_LIMIT) +#define G_MC_WR_LIMIT(x) _SB_GETVALUE(x, S_MC_WR_LIMIT, M_MC_WR_LIMIT) #define V_MC_WR_LIMIT_DEFAULT V_MC_WR_LIMIT(5) #define M_MC_IOB1HIGHPRIORITY _SB_MAKEMASK1(52) -#define M_MC_RESERVED2 _SB_MAKEMASK(3,53) +#define M_MC_RESERVED2 _SB_MAKEMASK(3, 53) #define S_MC_CS_MODE 56 -#define M_MC_CS_MODE _SB_MAKEMASK(4,S_MC_CS_MODE) -#define V_MC_CS_MODE(x) _SB_MAKEVALUE(x,S_MC_CS_MODE) -#define G_MC_CS_MODE(x) _SB_GETVALUE(x,S_MC_CS_MODE,M_MC_CS_MODE) +#define M_MC_CS_MODE _SB_MAKEMASK(4, S_MC_CS_MODE) +#define V_MC_CS_MODE(x) _SB_MAKEVALUE(x, S_MC_CS_MODE) +#define G_MC_CS_MODE(x) _SB_GETVALUE(x, S_MC_CS_MODE, M_MC_CS_MODE) #define K_MC_CS_MODE_MSB_CS 0 #define K_MC_CS_MODE_INTLV_CS 15 @@ -138,9 +138,9 @@ */ #define S_MC_CLK_RATIO 0 -#define M_MC_CLK_RATIO _SB_MAKEMASK(4,S_MC_CLK_RATIO) -#define V_MC_CLK_RATIO(x) _SB_MAKEVALUE(x,S_MC_CLK_RATIO) -#define G_MC_CLK_RATIO(x) _SB_GETVALUE(x,S_MC_CLK_RATIO,M_MC_CLK_RATIO) +#define M_MC_CLK_RATIO _SB_MAKEMASK(4, S_MC_CLK_RATIO) +#define V_MC_CLK_RATIO(x) _SB_MAKEVALUE(x, S_MC_CLK_RATIO) +#define G_MC_CLK_RATIO(x) _SB_GETVALUE(x, S_MC_CLK_RATIO, M_MC_CLK_RATIO) #define K_MC_CLK_RATIO_2X 4 #define K_MC_CLK_RATIO_25X 5 @@ -158,9 +158,9 @@ #define V_MC_CLK_RATIO_DEFAULT V_MC_CLK_RATIO_25X #define S_MC_REF_RATE 8 -#define M_MC_REF_RATE _SB_MAKEMASK(8,S_MC_REF_RATE) -#define V_MC_REF_RATE(x) _SB_MAKEVALUE(x,S_MC_REF_RATE) -#define G_MC_REF_RATE(x) _SB_GETVALUE(x,S_MC_REF_RATE,M_MC_REF_RATE) +#define M_MC_REF_RATE _SB_MAKEMASK(8, S_MC_REF_RATE) +#define V_MC_REF_RATE(x) _SB_MAKEVALUE(x, S_MC_REF_RATE) +#define G_MC_REF_RATE(x) _SB_GETVALUE(x, S_MC_REF_RATE, M_MC_REF_RATE) #define K_MC_REF_RATE_100MHz 0x62 #define K_MC_REF_RATE_133MHz 0x81 @@ -172,21 +172,21 @@ #define V_MC_REF_RATE_DEFAULT V_MC_REF_RATE_100MHz #define S_MC_CLOCK_DRIVE 16 -#define M_MC_CLOCK_DRIVE _SB_MAKEMASK(4,S_MC_CLOCK_DRIVE) -#define V_MC_CLOCK_DRIVE(x) _SB_MAKEVALUE(x,S_MC_CLOCK_DRIVE) -#define G_MC_CLOCK_DRIVE(x) _SB_GETVALUE(x,S_MC_CLOCK_DRIVE,M_MC_CLOCK_DRIVE) +#define M_MC_CLOCK_DRIVE _SB_MAKEMASK(4, S_MC_CLOCK_DRIVE) +#define V_MC_CLOCK_DRIVE(x) _SB_MAKEVALUE(x, S_MC_CLOCK_DRIVE) +#define G_MC_CLOCK_DRIVE(x) _SB_GETVALUE(x, S_MC_CLOCK_DRIVE, M_MC_CLOCK_DRIVE) #define V_MC_CLOCK_DRIVE_DEFAULT V_MC_CLOCK_DRIVE(0xF) #define S_MC_DATA_DRIVE 20 -#define M_MC_DATA_DRIVE _SB_MAKEMASK(4,S_MC_DATA_DRIVE) -#define V_MC_DATA_DRIVE(x) _SB_MAKEVALUE(x,S_MC_DATA_DRIVE) -#define G_MC_DATA_DRIVE(x) _SB_GETVALUE(x,S_MC_DATA_DRIVE,M_MC_DATA_DRIVE) +#define M_MC_DATA_DRIVE _SB_MAKEMASK(4, S_MC_DATA_DRIVE) +#define V_MC_DATA_DRIVE(x) _SB_MAKEVALUE(x, S_MC_DATA_DRIVE) +#define G_MC_DATA_DRIVE(x) _SB_GETVALUE(x, S_MC_DATA_DRIVE, M_MC_DATA_DRIVE) #define V_MC_DATA_DRIVE_DEFAULT V_MC_DATA_DRIVE(0x0) #define S_MC_ADDR_DRIVE 24 -#define M_MC_ADDR_DRIVE _SB_MAKEMASK(4,S_MC_ADDR_DRIVE) -#define V_MC_ADDR_DRIVE(x) _SB_MAKEVALUE(x,S_MC_ADDR_DRIVE) -#define G_MC_ADDR_DRIVE(x) _SB_GETVALUE(x,S_MC_ADDR_DRIVE,M_MC_ADDR_DRIVE) +#define M_MC_ADDR_DRIVE _SB_MAKEMASK(4, S_MC_ADDR_DRIVE) +#define V_MC_ADDR_DRIVE(x) _SB_MAKEVALUE(x, S_MC_ADDR_DRIVE) +#define G_MC_ADDR_DRIVE(x) _SB_GETVALUE(x, S_MC_ADDR_DRIVE, M_MC_ADDR_DRIVE) #define V_MC_ADDR_DRIVE_DEFAULT V_MC_ADDR_DRIVE(0x0) #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) @@ -196,27 +196,27 @@ #define M_MC_DLL_BYPASS _SB_MAKEMASK1(31) #define S_MC_DQI_SKEW 32 -#define M_MC_DQI_SKEW _SB_MAKEMASK(8,S_MC_DQI_SKEW) -#define V_MC_DQI_SKEW(x) _SB_MAKEVALUE(x,S_MC_DQI_SKEW) -#define G_MC_DQI_SKEW(x) _SB_GETVALUE(x,S_MC_DQI_SKEW,M_MC_DQI_SKEW) +#define M_MC_DQI_SKEW _SB_MAKEMASK(8, S_MC_DQI_SKEW) +#define V_MC_DQI_SKEW(x) _SB_MAKEVALUE(x, S_MC_DQI_SKEW) +#define G_MC_DQI_SKEW(x) _SB_GETVALUE(x, S_MC_DQI_SKEW, M_MC_DQI_SKEW) #define V_MC_DQI_SKEW_DEFAULT V_MC_DQI_SKEW(0) #define S_MC_DQO_SKEW 40 -#define M_MC_DQO_SKEW _SB_MAKEMASK(8,S_MC_DQO_SKEW) -#define V_MC_DQO_SKEW(x) _SB_MAKEVALUE(x,S_MC_DQO_SKEW) -#define G_MC_DQO_SKEW(x) _SB_GETVALUE(x,S_MC_DQO_SKEW,M_MC_DQO_SKEW) +#define M_MC_DQO_SKEW _SB_MAKEMASK(8, S_MC_DQO_SKEW) +#define V_MC_DQO_SKEW(x) _SB_MAKEVALUE(x, S_MC_DQO_SKEW) +#define G_MC_DQO_SKEW(x) _SB_GETVALUE(x, S_MC_DQO_SKEW, M_MC_DQO_SKEW) #define V_MC_DQO_SKEW_DEFAULT V_MC_DQO_SKEW(0) #define S_MC_ADDR_SKEW 48 -#define M_MC_ADDR_SKEW _SB_MAKEMASK(8,S_MC_ADDR_SKEW) -#define V_MC_ADDR_SKEW(x) _SB_MAKEVALUE(x,S_MC_ADDR_SKEW) -#define G_MC_ADDR_SKEW(x) _SB_GETVALUE(x,S_MC_ADDR_SKEW,M_MC_ADDR_SKEW) +#define M_MC_ADDR_SKEW _SB_MAKEMASK(8, S_MC_ADDR_SKEW) +#define V_MC_ADDR_SKEW(x) _SB_MAKEVALUE(x, S_MC_ADDR_SKEW) +#define G_MC_ADDR_SKEW(x) _SB_GETVALUE(x, S_MC_ADDR_SKEW, M_MC_ADDR_SKEW) #define V_MC_ADDR_SKEW_DEFAULT V_MC_ADDR_SKEW(0x0F) #define S_MC_DLL_DEFAULT 56 -#define M_MC_DLL_DEFAULT _SB_MAKEMASK(8,S_MC_DLL_DEFAULT) -#define V_MC_DLL_DEFAULT(x) _SB_MAKEVALUE(x,S_MC_DLL_DEFAULT) -#define G_MC_DLL_DEFAULT(x) _SB_GETVALUE(x,S_MC_DLL_DEFAULT,M_MC_DLL_DEFAULT) +#define M_MC_DLL_DEFAULT _SB_MAKEMASK(8, S_MC_DLL_DEFAULT) +#define V_MC_DLL_DEFAULT(x) _SB_MAKEVALUE(x, S_MC_DLL_DEFAULT) +#define G_MC_DLL_DEFAULT(x) _SB_GETVALUE(x, S_MC_DLL_DEFAULT, M_MC_DLL_DEFAULT) #define V_MC_DLL_DEFAULT_DEFAULT V_MC_DLL_DEFAULT(0x10) #define V_MC_CLKCONFIG_DEFAULT V_MC_DLL_DEFAULT_DEFAULT | \ @@ -235,9 +235,9 @@ */ #define S_MC_COMMAND 0 -#define M_MC_COMMAND _SB_MAKEMASK(4,S_MC_COMMAND) -#define V_MC_COMMAND(x) _SB_MAKEVALUE(x,S_MC_COMMAND) -#define G_MC_COMMAND(x) _SB_GETVALUE(x,S_MC_COMMAND,M_MC_COMMAND) +#define M_MC_COMMAND _SB_MAKEMASK(4, S_MC_COMMAND) +#define V_MC_COMMAND(x) _SB_MAKEVALUE(x, S_MC_COMMAND) +#define G_MC_COMMAND(x) _SB_GETVALUE(x, S_MC_COMMAND, M_MC_COMMAND) #define K_MC_COMMAND_EMRS 0 #define K_MC_COMMAND_MRS 1 @@ -267,21 +267,21 @@ */ #define S_MC_EMODE 0 -#define M_MC_EMODE _SB_MAKEMASK(15,S_MC_EMODE) -#define V_MC_EMODE(x) _SB_MAKEVALUE(x,S_MC_EMODE) -#define G_MC_EMODE(x) _SB_GETVALUE(x,S_MC_EMODE,M_MC_EMODE) +#define M_MC_EMODE _SB_MAKEMASK(15, S_MC_EMODE) +#define V_MC_EMODE(x) _SB_MAKEVALUE(x, S_MC_EMODE) +#define G_MC_EMODE(x) _SB_GETVALUE(x, S_MC_EMODE, M_MC_EMODE) #define V_MC_EMODE_DEFAULT V_MC_EMODE(0) #define S_MC_MODE 16 -#define M_MC_MODE _SB_MAKEMASK(15,S_MC_MODE) -#define V_MC_MODE(x) _SB_MAKEVALUE(x,S_MC_MODE) -#define G_MC_MODE(x) _SB_GETVALUE(x,S_MC_MODE,M_MC_MODE) +#define M_MC_MODE _SB_MAKEMASK(15, S_MC_MODE) +#define V_MC_MODE(x) _SB_MAKEVALUE(x, S_MC_MODE) +#define G_MC_MODE(x) _SB_GETVALUE(x, S_MC_MODE, M_MC_MODE) #define V_MC_MODE_DEFAULT V_MC_MODE(0x22) #define S_MC_DRAM_TYPE 32 -#define M_MC_DRAM_TYPE _SB_MAKEMASK(3,S_MC_DRAM_TYPE) -#define V_MC_DRAM_TYPE(x) _SB_MAKEVALUE(x,S_MC_DRAM_TYPE) -#define G_MC_DRAM_TYPE(x) _SB_GETVALUE(x,S_MC_DRAM_TYPE,M_MC_DRAM_TYPE) +#define M_MC_DRAM_TYPE _SB_MAKEMASK(3, S_MC_DRAM_TYPE) +#define V_MC_DRAM_TYPE(x) _SB_MAKEVALUE(x, S_MC_DRAM_TYPE) +#define G_MC_DRAM_TYPE(x) _SB_GETVALUE(x, S_MC_DRAM_TYPE, M_MC_DRAM_TYPE) #define K_MC_DRAM_TYPE_JEDEC 0 #define K_MC_DRAM_TYPE_FCRAM 1 @@ -309,16 +309,16 @@ #define M_MC_r2rIDLE_TWOCYCLES _SB_MAKEMASK1(62) #define S_MC_tFIFO 56 -#define M_MC_tFIFO _SB_MAKEMASK(4,S_MC_tFIFO) -#define V_MC_tFIFO(x) _SB_MAKEVALUE(x,S_MC_tFIFO) -#define G_MC_tFIFO(x) _SB_GETVALUE(x,S_MC_tFIFO,M_MC_tFIFO) +#define M_MC_tFIFO _SB_MAKEMASK(4, S_MC_tFIFO) +#define V_MC_tFIFO(x) _SB_MAKEVALUE(x, S_MC_tFIFO) +#define G_MC_tFIFO(x) _SB_GETVALUE(x, S_MC_tFIFO, M_MC_tFIFO) #define K_MC_tFIFO_DEFAULT 1 #define V_MC_tFIFO_DEFAULT V_MC_tFIFO(K_MC_tFIFO_DEFAULT) #define S_MC_tRFC 52 -#define M_MC_tRFC _SB_MAKEMASK(4,S_MC_tRFC) -#define V_MC_tRFC(x) _SB_MAKEVALUE(x,S_MC_tRFC) -#define G_MC_tRFC(x) _SB_GETVALUE(x,S_MC_tRFC,M_MC_tRFC) +#define M_MC_tRFC _SB_MAKEMASK(4, S_MC_tRFC) +#define V_MC_tRFC(x) _SB_MAKEVALUE(x, S_MC_tRFC) +#define G_MC_tRFC(x) _SB_GETVALUE(x, S_MC_tRFC, M_MC_tRFC) #define K_MC_tRFC_DEFAULT 12 #define V_MC_tRFC_DEFAULT V_MC_tRFC(K_MC_tRFC_DEFAULT) @@ -327,44 +327,44 @@ #endif #define S_MC_tCwCr 40 -#define M_MC_tCwCr _SB_MAKEMASK(4,S_MC_tCwCr) -#define V_MC_tCwCr(x) _SB_MAKEVALUE(x,S_MC_tCwCr) -#define G_MC_tCwCr(x) _SB_GETVALUE(x,S_MC_tCwCr,M_MC_tCwCr) +#define M_MC_tCwCr _SB_MAKEMASK(4, S_MC_tCwCr) +#define V_MC_tCwCr(x) _SB_MAKEVALUE(x, S_MC_tCwCr) +#define G_MC_tCwCr(x) _SB_GETVALUE(x, S_MC_tCwCr, M_MC_tCwCr) #define K_MC_tCwCr_DEFAULT 4 #define V_MC_tCwCr_DEFAULT V_MC_tCwCr(K_MC_tCwCr_DEFAULT) #define S_MC_tRCr 28 -#define M_MC_tRCr _SB_MAKEMASK(4,S_MC_tRCr) -#define V_MC_tRCr(x) _SB_MAKEVALUE(x,S_MC_tRCr) -#define G_MC_tRCr(x) _SB_GETVALUE(x,S_MC_tRCr,M_MC_tRCr) +#define M_MC_tRCr _SB_MAKEMASK(4, S_MC_tRCr) +#define V_MC_tRCr(x) _SB_MAKEVALUE(x, S_MC_tRCr) +#define G_MC_tRCr(x) _SB_GETVALUE(x, S_MC_tRCr, M_MC_tRCr) #define K_MC_tRCr_DEFAULT 9 #define V_MC_tRCr_DEFAULT V_MC_tRCr(K_MC_tRCr_DEFAULT) #define S_MC_tRCw 24 -#define M_MC_tRCw _SB_MAKEMASK(4,S_MC_tRCw) -#define V_MC_tRCw(x) _SB_MAKEVALUE(x,S_MC_tRCw) -#define G_MC_tRCw(x) _SB_GETVALUE(x,S_MC_tRCw,M_MC_tRCw) +#define M_MC_tRCw _SB_MAKEMASK(4, S_MC_tRCw) +#define V_MC_tRCw(x) _SB_MAKEVALUE(x, S_MC_tRCw) +#define G_MC_tRCw(x) _SB_GETVALUE(x, S_MC_tRCw, M_MC_tRCw) #define K_MC_tRCw_DEFAULT 10 #define V_MC_tRCw_DEFAULT V_MC_tRCw(K_MC_tRCw_DEFAULT) #define S_MC_tRRD 20 -#define M_MC_tRRD _SB_MAKEMASK(4,S_MC_tRRD) -#define V_MC_tRRD(x) _SB_MAKEVALUE(x,S_MC_tRRD) -#define G_MC_tRRD(x) _SB_GETVALUE(x,S_MC_tRRD,M_MC_tRRD) +#define M_MC_tRRD _SB_MAKEMASK(4, S_MC_tRRD) +#define V_MC_tRRD(x) _SB_MAKEVALUE(x, S_MC_tRRD) +#define G_MC_tRRD(x) _SB_GETVALUE(x, S_MC_tRRD, M_MC_tRRD) #define K_MC_tRRD_DEFAULT 2 #define V_MC_tRRD_DEFAULT V_MC_tRRD(K_MC_tRRD_DEFAULT) #define S_MC_tRP 16 -#define M_MC_tRP _SB_MAKEMASK(4,S_MC_tRP) -#define V_MC_tRP(x) _SB_MAKEVALUE(x,S_MC_tRP) -#define G_MC_tRP(x) _SB_GETVALUE(x,S_MC_tRP,M_MC_tRP) +#define M_MC_tRP _SB_MAKEMASK(4, S_MC_tRP) +#define V_MC_tRP(x) _SB_MAKEVALUE(x, S_MC_tRP) +#define G_MC_tRP(x) _SB_GETVALUE(x, S_MC_tRP, M_MC_tRP) #define K_MC_tRP_DEFAULT 4 #define V_MC_tRP_DEFAULT V_MC_tRP(K_MC_tRP_DEFAULT) #define S_MC_tCwD 8 -#define M_MC_tCwD _SB_MAKEMASK(4,S_MC_tCwD) -#define V_MC_tCwD(x) _SB_MAKEVALUE(x,S_MC_tCwD) -#define G_MC_tCwD(x) _SB_GETVALUE(x,S_MC_tCwD,M_MC_tCwD) +#define M_MC_tCwD _SB_MAKEMASK(4, S_MC_tCwD) +#define V_MC_tCwD(x) _SB_MAKEVALUE(x, S_MC_tCwD) +#define G_MC_tCwD(x) _SB_GETVALUE(x, S_MC_tCwD, M_MC_tCwD) #define K_MC_tCwD_DEFAULT 1 #define V_MC_tCwD_DEFAULT V_MC_tCwD(K_MC_tCwD_DEFAULT) @@ -372,16 +372,16 @@ #define M_MC_tCrDh M_tCrDh #define S_MC_tCrD 4 -#define M_MC_tCrD _SB_MAKEMASK(3,S_MC_tCrD) -#define V_MC_tCrD(x) _SB_MAKEVALUE(x,S_MC_tCrD) -#define G_MC_tCrD(x) _SB_GETVALUE(x,S_MC_tCrD,M_MC_tCrD) +#define M_MC_tCrD _SB_MAKEMASK(3, S_MC_tCrD) +#define V_MC_tCrD(x) _SB_MAKEVALUE(x, S_MC_tCrD) +#define G_MC_tCrD(x) _SB_GETVALUE(x, S_MC_tCrD, M_MC_tCrD) #define K_MC_tCrD_DEFAULT 2 #define V_MC_tCrD_DEFAULT V_MC_tCrD(K_MC_tCrD_DEFAULT) #define S_MC_tRCD 0 -#define M_MC_tRCD _SB_MAKEMASK(4,S_MC_tRCD) -#define V_MC_tRCD(x) _SB_MAKEVALUE(x,S_MC_tRCD) -#define G_MC_tRCD(x) _SB_GETVALUE(x,S_MC_tRCD,M_MC_tRCD) +#define M_MC_tRCD _SB_MAKEMASK(4, S_MC_tRCD) +#define V_MC_tRCD(x) _SB_MAKEVALUE(x, S_MC_tRCD) +#define G_MC_tRCD(x) _SB_GETVALUE(x, S_MC_tRCD, M_MC_tRCD) #define K_MC_tRCD_DEFAULT 3 #define V_MC_tRCD_DEFAULT V_MC_tRCD(K_MC_tRCD_DEFAULT) @@ -409,76 +409,76 @@ */ #define S_MC_CS0_START 0 -#define M_MC_CS0_START _SB_MAKEMASK(16,S_MC_CS0_START) -#define V_MC_CS0_START(x) _SB_MAKEVALUE(x,S_MC_CS0_START) -#define G_MC_CS0_START(x) _SB_GETVALUE(x,S_MC_CS0_START,M_MC_CS0_START) +#define M_MC_CS0_START _SB_MAKEMASK(16, S_MC_CS0_START) +#define V_MC_CS0_START(x) _SB_MAKEVALUE(x, S_MC_CS0_START) +#define G_MC_CS0_START(x) _SB_GETVALUE(x, S_MC_CS0_START, M_MC_CS0_START) #define S_MC_CS1_START 16 -#define M_MC_CS1_START _SB_MAKEMASK(16,S_MC_CS1_START) -#define V_MC_CS1_START(x) _SB_MAKEVALUE(x,S_MC_CS1_START) -#define G_MC_CS1_START(x) _SB_GETVALUE(x,S_MC_CS1_START,M_MC_CS1_START) +#define M_MC_CS1_START _SB_MAKEMASK(16, S_MC_CS1_START) +#define V_MC_CS1_START(x) _SB_MAKEVALUE(x, S_MC_CS1_START) +#define G_MC_CS1_START(x) _SB_GETVALUE(x, S_MC_CS1_START, M_MC_CS1_START) #define S_MC_CS2_START 32 -#define M_MC_CS2_START _SB_MAKEMASK(16,S_MC_CS2_START) -#define V_MC_CS2_START(x) _SB_MAKEVALUE(x,S_MC_CS2_START) -#define G_MC_CS2_START(x) _SB_GETVALUE(x,S_MC_CS2_START,M_MC_CS2_START) +#define M_MC_CS2_START _SB_MAKEMASK(16, S_MC_CS2_START) +#define V_MC_CS2_START(x) _SB_MAKEVALUE(x, S_MC_CS2_START) +#define G_MC_CS2_START(x) _SB_GETVALUE(x, S_MC_CS2_START, M_MC_CS2_START) #define S_MC_CS3_START 48 -#define M_MC_CS3_START _SB_MAKEMASK(16,S_MC_CS3_START) -#define V_MC_CS3_START(x) _SB_MAKEVALUE(x,S_MC_CS3_START) -#define G_MC_CS3_START(x) _SB_GETVALUE(x,S_MC_CS3_START,M_MC_CS3_START) +#define M_MC_CS3_START _SB_MAKEMASK(16, S_MC_CS3_START) +#define V_MC_CS3_START(x) _SB_MAKEVALUE(x, S_MC_CS3_START) +#define G_MC_CS3_START(x) _SB_GETVALUE(x, S_MC_CS3_START, M_MC_CS3_START) /* * Chip Select End Address Register (Table 6-18) */ #define S_MC_CS0_END 0 -#define M_MC_CS0_END _SB_MAKEMASK(16,S_MC_CS0_END) -#define V_MC_CS0_END(x) _SB_MAKEVALUE(x,S_MC_CS0_END) -#define G_MC_CS0_END(x) _SB_GETVALUE(x,S_MC_CS0_END,M_MC_CS0_END) +#define M_MC_CS0_END _SB_MAKEMASK(16, S_MC_CS0_END) +#define V_MC_CS0_END(x) _SB_MAKEVALUE(x, S_MC_CS0_END) +#define G_MC_CS0_END(x) _SB_GETVALUE(x, S_MC_CS0_END, M_MC_CS0_END) #define S_MC_CS1_END 16 -#define M_MC_CS1_END _SB_MAKEMASK(16,S_MC_CS1_END) -#define V_MC_CS1_END(x) _SB_MAKEVALUE(x,S_MC_CS1_END) -#define G_MC_CS1_END(x) _SB_GETVALUE(x,S_MC_CS1_END,M_MC_CS1_END) +#define M_MC_CS1_END _SB_MAKEMASK(16, S_MC_CS1_END) +#define V_MC_CS1_END(x) _SB_MAKEVALUE(x, S_MC_CS1_END) +#define G_MC_CS1_END(x) _SB_GETVALUE(x, S_MC_CS1_END, M_MC_CS1_END) #define S_MC_CS2_END 32 -#define M_MC_CS2_END _SB_MAKEMASK(16,S_MC_CS2_END) -#define V_MC_CS2_END(x) _SB_MAKEVALUE(x,S_MC_CS2_END) -#define G_MC_CS2_END(x) _SB_GETVALUE(x,S_MC_CS2_END,M_MC_CS2_END) +#define M_MC_CS2_END _SB_MAKEMASK(16, S_MC_CS2_END) +#define V_MC_CS2_END(x) _SB_MAKEVALUE(x, S_MC_CS2_END) +#define G_MC_CS2_END(x) _SB_GETVALUE(x, S_MC_CS2_END, M_MC_CS2_END) #define S_MC_CS3_END 48 -#define M_MC_CS3_END _SB_MAKEMASK(16,S_MC_CS3_END) -#define V_MC_CS3_END(x) _SB_MAKEVALUE(x,S_MC_CS3_END) -#define G_MC_CS3_END(x) _SB_GETVALUE(x,S_MC_CS3_END,M_MC_CS3_END) +#define M_MC_CS3_END _SB_MAKEMASK(16, S_MC_CS3_END) +#define V_MC_CS3_END(x) _SB_MAKEVALUE(x, S_MC_CS3_END) +#define G_MC_CS3_END(x) _SB_GETVALUE(x, S_MC_CS3_END, M_MC_CS3_END) /* * Chip Select Interleave Register (Table 6-19) */ #define S_MC_INTLV_RESERVED 0 -#define M_MC_INTLV_RESERVED _SB_MAKEMASK(5,S_MC_INTLV_RESERVED) +#define M_MC_INTLV_RESERVED _SB_MAKEMASK(5, S_MC_INTLV_RESERVED) #define S_MC_INTERLEAVE 7 -#define M_MC_INTERLEAVE _SB_MAKEMASK(18,S_MC_INTERLEAVE) -#define V_MC_INTERLEAVE(x) _SB_MAKEVALUE(x,S_MC_INTERLEAVE) +#define M_MC_INTERLEAVE _SB_MAKEMASK(18, S_MC_INTERLEAVE) +#define V_MC_INTERLEAVE(x) _SB_MAKEVALUE(x, S_MC_INTERLEAVE) #define S_MC_INTLV_MBZ 25 -#define M_MC_INTLV_MBZ _SB_MAKEMASK(39,S_MC_INTLV_MBZ) +#define M_MC_INTLV_MBZ _SB_MAKEMASK(39, S_MC_INTLV_MBZ) /* * Row Address Bits Register (Table 6-20) */ #define S_MC_RAS_RESERVED 0 -#define M_MC_RAS_RESERVED _SB_MAKEMASK(5,S_MC_RAS_RESERVED) +#define M_MC_RAS_RESERVED _SB_MAKEMASK(5, S_MC_RAS_RESERVED) #define S_MC_RAS_SELECT 12 -#define M_MC_RAS_SELECT _SB_MAKEMASK(25,S_MC_RAS_SELECT) -#define V_MC_RAS_SELECT(x) _SB_MAKEVALUE(x,S_MC_RAS_SELECT) +#define M_MC_RAS_SELECT _SB_MAKEMASK(25, S_MC_RAS_SELECT) +#define V_MC_RAS_SELECT(x) _SB_MAKEVALUE(x, S_MC_RAS_SELECT) #define S_MC_RAS_MBZ 37 -#define M_MC_RAS_MBZ _SB_MAKEMASK(27,S_MC_RAS_MBZ) +#define M_MC_RAS_MBZ _SB_MAKEMASK(27, S_MC_RAS_MBZ) /* @@ -486,14 +486,14 @@ */ #define S_MC_CAS_RESERVED 0 -#define M_MC_CAS_RESERVED _SB_MAKEMASK(5,S_MC_CAS_RESERVED) +#define M_MC_CAS_RESERVED _SB_MAKEMASK(5, S_MC_CAS_RESERVED) #define S_MC_CAS_SELECT 5 -#define M_MC_CAS_SELECT _SB_MAKEMASK(18,S_MC_CAS_SELECT) -#define V_MC_CAS_SELECT(x) _SB_MAKEVALUE(x,S_MC_CAS_SELECT) +#define M_MC_CAS_SELECT _SB_MAKEMASK(18, S_MC_CAS_SELECT) +#define V_MC_CAS_SELECT(x) _SB_MAKEVALUE(x, S_MC_CAS_SELECT) #define S_MC_CAS_MBZ 23 -#define M_MC_CAS_MBZ _SB_MAKEMASK(41,S_MC_CAS_MBZ) +#define M_MC_CAS_MBZ _SB_MAKEMASK(41, S_MC_CAS_MBZ) /* @@ -501,14 +501,14 @@ */ #define S_MC_BA_RESERVED 0 -#define M_MC_BA_RESERVED _SB_MAKEMASK(5,S_MC_BA_RESERVED) +#define M_MC_BA_RESERVED _SB_MAKEMASK(5, S_MC_BA_RESERVED) #define S_MC_BA_SELECT 5 -#define M_MC_BA_SELECT _SB_MAKEMASK(20,S_MC_BA_SELECT) -#define V_MC_BA_SELECT(x) _SB_MAKEVALUE(x,S_MC_BA_SELECT) +#define M_MC_BA_SELECT _SB_MAKEMASK(20, S_MC_BA_SELECT) +#define V_MC_BA_SELECT(x) _SB_MAKEVALUE(x, S_MC_BA_SELECT) #define S_MC_BA_MBZ 25 -#define M_MC_BA_MBZ _SB_MAKEMASK(39,S_MC_BA_MBZ) +#define M_MC_BA_MBZ _SB_MAKEMASK(39, S_MC_BA_MBZ) /* * Chip Select Attribute Register (Table 6-23) @@ -520,31 +520,31 @@ #define K_MC_CS_ATTR_OPEN 3 #define S_MC_CS0_PAGE 0 -#define M_MC_CS0_PAGE _SB_MAKEMASK(2,S_MC_CS0_PAGE) -#define V_MC_CS0_PAGE(x) _SB_MAKEVALUE(x,S_MC_CS0_PAGE) -#define G_MC_CS0_PAGE(x) _SB_GETVALUE(x,S_MC_CS0_PAGE,M_MC_CS0_PAGE) +#define M_MC_CS0_PAGE _SB_MAKEMASK(2, S_MC_CS0_PAGE) +#define V_MC_CS0_PAGE(x) _SB_MAKEVALUE(x, S_MC_CS0_PAGE) +#define G_MC_CS0_PAGE(x) _SB_GETVALUE(x, S_MC_CS0_PAGE, M_MC_CS0_PAGE) #define S_MC_CS1_PAGE 16 -#define M_MC_CS1_PAGE _SB_MAKEMASK(2,S_MC_CS1_PAGE) -#define V_MC_CS1_PAGE(x) _SB_MAKEVALUE(x,S_MC_CS1_PAGE) -#define G_MC_CS1_PAGE(x) _SB_GETVALUE(x,S_MC_CS1_PAGE,M_MC_CS1_PAGE) +#define M_MC_CS1_PAGE _SB_MAKEMASK(2, S_MC_CS1_PAGE) +#define V_MC_CS1_PAGE(x) _SB_MAKEVALUE(x, S_MC_CS1_PAGE) +#define G_MC_CS1_PAGE(x) _SB_GETVALUE(x, S_MC_CS1_PAGE, M_MC_CS1_PAGE) #define S_MC_CS2_PAGE 32 -#define M_MC_CS2_PAGE _SB_MAKEMASK(2,S_MC_CS2_PAGE) -#define V_MC_CS2_PAGE(x) _SB_MAKEVALUE(x,S_MC_CS2_PAGE) -#define G_MC_CS2_PAGE(x) _SB_GETVALUE(x,S_MC_CS2_PAGE,M_MC_CS2_PAGE) +#define M_MC_CS2_PAGE _SB_MAKEMASK(2, S_MC_CS2_PAGE) +#define V_MC_CS2_PAGE(x) _SB_MAKEVALUE(x, S_MC_CS2_PAGE) +#define G_MC_CS2_PAGE(x) _SB_GETVALUE(x, S_MC_CS2_PAGE, M_MC_CS2_PAGE) #define S_MC_CS3_PAGE 48 -#define M_MC_CS3_PAGE _SB_MAKEMASK(2,S_MC_CS3_PAGE) -#define V_MC_CS3_PAGE(x) _SB_MAKEVALUE(x,S_MC_CS3_PAGE) -#define G_MC_CS3_PAGE(x) _SB_GETVALUE(x,S_MC_CS3_PAGE,M_MC_CS3_PAGE) +#define M_MC_CS3_PAGE _SB_MAKEMASK(2, S_MC_CS3_PAGE) +#define V_MC_CS3_PAGE(x) _SB_MAKEVALUE(x, S_MC_CS3_PAGE) +#define G_MC_CS3_PAGE(x) _SB_GETVALUE(x, S_MC_CS3_PAGE, M_MC_CS3_PAGE) /* * ECC Test ECC Register (Table 6-25) */ #define S_MC_ECC_INVERT 0 -#define M_MC_ECC_INVERT _SB_MAKEMASK(8,S_MC_ECC_INVERT) +#define M_MC_ECC_INVERT _SB_MAKEMASK(8, S_MC_ECC_INVERT) #endif diff --git a/include/asm-mips/sibyte/sb1250_regs.h b/include/asm-mips/sibyte/sb1250_regs.h index 220b7e94f1bf..8f53ec817a5e 100644 --- a/include/asm-mips/sibyte/sb1250_regs.h +++ b/include/asm-mips/sibyte/sb1250_regs.h @@ -66,7 +66,7 @@ #define MC_REGISTER_SPACING 0x1000 #define A_MC_BASE(ctlid) ((ctlid)*MC_REGISTER_SPACING+A_MC_BASE_0) -#define A_MC_REGISTER(ctlid,reg) (A_MC_BASE(ctlid)+(reg)) +#define A_MC_REGISTER(ctlid, reg) (A_MC_BASE(ctlid)+(reg)) #define R_MC_CONFIG 0x0000000100 #define R_MC_DRAMCMD 0x0000000120 @@ -173,23 +173,23 @@ #define R_MAC_DMA_CHANNELS 0x800 /* Relative to A_MAC_CHANNEL_BASE */ -#define A_MAC_DMA_CHANNEL_BASE(macnum,txrx,chan) \ +#define A_MAC_DMA_CHANNEL_BASE(macnum, txrx, chan) \ ((A_MAC_CHANNEL_BASE(macnum)) + \ R_MAC_DMA_CHANNELS + \ (MAC_DMA_TXRX_SPACING*(txrx)) + \ (MAC_DMA_CHANNEL_SPACING*(chan))) -#define R_MAC_DMA_CHANNEL_BASE(txrx,chan) \ +#define R_MAC_DMA_CHANNEL_BASE(txrx, chan) \ (R_MAC_DMA_CHANNELS + \ (MAC_DMA_TXRX_SPACING*(txrx)) + \ (MAC_DMA_CHANNEL_SPACING*(chan))) -#define A_MAC_DMA_REGISTER(macnum,txrx,chan,reg) \ - (A_MAC_DMA_CHANNEL_BASE(macnum,txrx,chan) + \ +#define A_MAC_DMA_REGISTER(macnum, txrx, chan, reg) \ + (A_MAC_DMA_CHANNEL_BASE(macnum, txrx, chan) + \ (reg)) -#define R_MAC_DMA_REGISTER(txrx,chan,reg) \ - (R_MAC_DMA_CHANNEL_BASE(txrx,chan) + \ +#define R_MAC_DMA_REGISTER(txrx, chan, reg) \ + (R_MAC_DMA_CHANNEL_BASE(txrx, chan) + \ (reg)) /* @@ -415,8 +415,8 @@ R_SER_DMA_CHANNELS + \ (SER_DMA_TXRX_SPACING*(txrx))) -#define A_SER_DMA_REGISTER(sernum,txrx,reg) \ - (A_SER_DMA_CHANNEL_BASE(sernum,txrx) + \ +#define A_SER_DMA_REGISTER(sernum, txrx, reg) \ + (A_SER_DMA_CHANNEL_BASE(sernum, txrx) + \ (reg)) @@ -499,7 +499,7 @@ #define IO_EXT_REGISTER_SPACING 8 #define A_IO_EXT_CS_BASE(cs) (A_IO_EXT_CFG_BASE+IO_EXT_REGISTER_SPACING*(cs)) -#define R_IO_EXT_REG(reg,cs) ((cs)*IO_EXT_REGISTER_SPACING + (reg)) +#define R_IO_EXT_REG(reg, cs) ((cs)*IO_EXT_REGISTER_SPACING + (reg)) #define R_IO_EXT_CFG 0x0000 #define R_IO_EXT_MULT_SIZE 0x0100 @@ -587,7 +587,7 @@ #define A_SMB_1 0x0010060008 #define SMB_REGISTER_SPACING 0x8 #define A_SMB_BASE(idx) (A_SMB_0+(idx)*SMB_REGISTER_SPACING) -#define A_SMB_REGISTER(idx,reg) (A_SMB_BASE(idx)+(reg)) +#define A_SMB_REGISTER(idx, reg) (A_SMB_BASE(idx)+(reg)) #define R_SMB_XTRA 0x0000000000 #define R_SMB_FREQ 0x0000000010 @@ -611,7 +611,7 @@ #define SCD_WDOG_SPACING 0x100 #define SCD_NUM_WDOGS 2 #define A_SCD_WDOG_BASE(w) (A_SCD_WDOG_0+SCD_WDOG_SPACING*(w)) -#define A_SCD_WDOG_REGISTER(w,r) (A_SCD_WDOG_BASE(w) + (r)) +#define A_SCD_WDOG_REGISTER(w, r) (A_SCD_WDOG_BASE(w) + (r)) #define R_SCD_WDOG_INIT 0x0000000000 #define R_SCD_WDOG_CNT 0x0000000008 @@ -635,7 +635,7 @@ #define A_SCD_TIMER_3 0x0010020178 #define SCD_NUM_TIMERS 4 #define A_SCD_TIMER_BASE(w) (A_SCD_TIMER_0+0x08*((w)&1)+0x100*(((w)&2)>>1)) -#define A_SCD_TIMER_REGISTER(w,r) (A_SCD_TIMER_BASE(w) + (r)) +#define A_SCD_TIMER_REGISTER(w, r) (A_SCD_TIMER_BASE(w) + (r)) #define R_SCD_TIMER_INIT 0x0000000000 #define R_SCD_TIMER_CNT 0x0000000010 @@ -714,7 +714,7 @@ #define IMR_REGISTER_SPACING_SHIFT 13 #define A_IMR_MAPPER(cpu) (A_IMR_CPU0_BASE+(cpu)*IMR_REGISTER_SPACING) -#define A_IMR_REGISTER(cpu,reg) (A_IMR_MAPPER(cpu)+(reg)) +#define A_IMR_REGISTER(cpu, reg) (A_IMR_MAPPER(cpu)+(reg)) #define R_IMR_INTERRUPT_DIAG 0x0010 #define R_IMR_INTERRUPT_LDT 0x0018 @@ -821,7 +821,7 @@ #define DM_REGISTER_SPACING 0x20 #define DM_NUM_CHANNELS 4 #define A_DM_BASE(idx) (A_DM_0 + ((idx) * DM_REGISTER_SPACING)) -#define A_DM_REGISTER(idx,reg) (A_DM_BASE(idx) + (reg)) +#define A_DM_REGISTER(idx, reg) (A_DM_BASE(idx) + (reg)) #define R_DM_DSCR_BASE 0x0000000000 #define R_DM_DSCR_COUNT 0x0000000008 @@ -843,7 +843,7 @@ #define DM_CRC_REGISTER_SPACING 0x10 #define DM_CRC_NUM_CHANNELS 2 #define A_DM_CRC_BASE(idx) (A_DM_CRC_0 + ((idx) * DM_CRC_REGISTER_SPACING)) -#define A_DM_CRC_REGISTER(idx,reg) (A_DM_CRC_BASE(idx) + (reg)) +#define A_DM_CRC_REGISTER(idx, reg) (A_DM_CRC_BASE(idx) + (reg)) #define R_CRC_DEF_0 0x00 #define R_CTCP_DEF_0 0x08 diff --git a/include/asm-mips/sibyte/sb1250_scd.h b/include/asm-mips/sibyte/sb1250_scd.h index 9ea3da367ab6..e49c3e89b5ee 100644 --- a/include/asm-mips/sibyte/sb1250_scd.h +++ b/include/asm-mips/sibyte/sb1250_scd.h @@ -42,12 +42,12 @@ * System Revision Register (Table 4-1) */ -#define M_SYS_RESERVED _SB_MAKEMASK(8,0) +#define M_SYS_RESERVED _SB_MAKEMASK(8, 0) #define S_SYS_REVISION _SB_MAKE64(8) -#define M_SYS_REVISION _SB_MAKEMASK(8,S_SYS_REVISION) -#define V_SYS_REVISION(x) _SB_MAKEVALUE(x,S_SYS_REVISION) -#define G_SYS_REVISION(x) _SB_GETVALUE(x,S_SYS_REVISION,M_SYS_REVISION) +#define M_SYS_REVISION _SB_MAKEMASK(8, S_SYS_REVISION) +#define V_SYS_REVISION(x) _SB_MAKEVALUE(x, S_SYS_REVISION) +#define G_SYS_REVISION(x) _SB_GETVALUE(x, S_SYS_REVISION, M_SYS_REVISION) #define K_SYS_REVISION_BCM1250_PASS1 0x01 @@ -94,9 +94,9 @@ /*Cache size - 23:20 of revision register*/ #define S_SYS_L2C_SIZE _SB_MAKE64(20) -#define M_SYS_L2C_SIZE _SB_MAKEMASK(4,S_SYS_L2C_SIZE) -#define V_SYS_L2C_SIZE(x) _SB_MAKEVALUE(x,S_SYS_L2C_SIZE) -#define G_SYS_L2C_SIZE(x) _SB_GETVALUE(x,S_SYS_L2C_SIZE,M_SYS_L2C_SIZE) +#define M_SYS_L2C_SIZE _SB_MAKEMASK(4, S_SYS_L2C_SIZE) +#define V_SYS_L2C_SIZE(x) _SB_MAKEVALUE(x, S_SYS_L2C_SIZE) +#define G_SYS_L2C_SIZE(x) _SB_GETVALUE(x, S_SYS_L2C_SIZE, M_SYS_L2C_SIZE) #define K_SYS_L2C_SIZE_1MB 0 #define K_SYS_L2C_SIZE_512KB 5 @@ -110,16 +110,16 @@ /* Number of CPU cores, bits 27:24 of revision register*/ #define S_SYS_NUM_CPUS _SB_MAKE64(24) -#define M_SYS_NUM_CPUS _SB_MAKEMASK(4,S_SYS_NUM_CPUS) -#define V_SYS_NUM_CPUS(x) _SB_MAKEVALUE(x,S_SYS_NUM_CPUS) -#define G_SYS_NUM_CPUS(x) _SB_GETVALUE(x,S_SYS_NUM_CPUS,M_SYS_NUM_CPUS) +#define M_SYS_NUM_CPUS _SB_MAKEMASK(4, S_SYS_NUM_CPUS) +#define V_SYS_NUM_CPUS(x) _SB_MAKEVALUE(x, S_SYS_NUM_CPUS) +#define G_SYS_NUM_CPUS(x) _SB_GETVALUE(x, S_SYS_NUM_CPUS, M_SYS_NUM_CPUS) /* XXX: discourage people from using these constants. */ #define S_SYS_PART _SB_MAKE64(16) -#define M_SYS_PART _SB_MAKEMASK(16,S_SYS_PART) -#define V_SYS_PART(x) _SB_MAKEVALUE(x,S_SYS_PART) -#define G_SYS_PART(x) _SB_GETVALUE(x,S_SYS_PART,M_SYS_PART) +#define M_SYS_PART _SB_MAKEMASK(16, S_SYS_PART) +#define V_SYS_PART(x) _SB_MAKEVALUE(x, S_SYS_PART) +#define G_SYS_PART(x) _SB_GETVALUE(x, S_SYS_PART, M_SYS_PART) /* XXX: discourage people from using these constants. */ #define K_SYS_PART_SB1250 0x1250 @@ -131,9 +131,9 @@ /* The "peripheral set" (SOC type) is the low 4 bits of the "part" field. */ #define S_SYS_SOC_TYPE _SB_MAKE64(16) -#define M_SYS_SOC_TYPE _SB_MAKEMASK(4,S_SYS_SOC_TYPE) -#define V_SYS_SOC_TYPE(x) _SB_MAKEVALUE(x,S_SYS_SOC_TYPE) -#define G_SYS_SOC_TYPE(x) _SB_GETVALUE(x,S_SYS_SOC_TYPE,M_SYS_SOC_TYPE) +#define M_SYS_SOC_TYPE _SB_MAKEMASK(4, S_SYS_SOC_TYPE) +#define V_SYS_SOC_TYPE(x) _SB_MAKEVALUE(x, S_SYS_SOC_TYPE) +#define G_SYS_SOC_TYPE(x) _SB_GETVALUE(x, S_SYS_SOC_TYPE, M_SYS_SOC_TYPE) #define K_SYS_SOC_TYPE_BCM1250 0x0 #define K_SYS_SOC_TYPE_BCM1120 0x1 @@ -170,9 +170,9 @@ #endif #define S_SYS_WID _SB_MAKE64(32) -#define M_SYS_WID _SB_MAKEMASK(32,S_SYS_WID) -#define V_SYS_WID(x) _SB_MAKEVALUE(x,S_SYS_WID) -#define G_SYS_WID(x) _SB_GETVALUE(x,S_SYS_WID,M_SYS_WID) +#define M_SYS_WID _SB_MAKEMASK(32, S_SYS_WID) +#define V_SYS_WID(x) _SB_MAKEVALUE(x, S_SYS_WID) +#define G_SYS_WID(x) _SB_GETVALUE(x, S_SYS_WID, M_SYS_WID) /* * System Manufacturing Register @@ -182,36 +182,36 @@ #if SIBYTE_HDR_FEATURE_1250_112x /* Wafer ID: bits 31:0 */ #define S_SYS_WAFERID1_200 _SB_MAKE64(0) -#define M_SYS_WAFERID1_200 _SB_MAKEMASK(32,S_SYS_WAFERID1_200) -#define V_SYS_WAFERID1_200(x) _SB_MAKEVALUE(x,S_SYS_WAFERID1_200) -#define G_SYS_WAFERID1_200(x) _SB_GETVALUE(x,S_SYS_WAFERID1_200,M_SYS_WAFERID1_200) +#define M_SYS_WAFERID1_200 _SB_MAKEMASK(32, S_SYS_WAFERID1_200) +#define V_SYS_WAFERID1_200(x) _SB_MAKEVALUE(x, S_SYS_WAFERID1_200) +#define G_SYS_WAFERID1_200(x) _SB_GETVALUE(x, S_SYS_WAFERID1_200, M_SYS_WAFERID1_200) #define S_SYS_BIN _SB_MAKE64(32) -#define M_SYS_BIN _SB_MAKEMASK(4,S_SYS_BIN) -#define V_SYS_BIN(x) _SB_MAKEVALUE(x,S_SYS_BIN) -#define G_SYS_BIN(x) _SB_GETVALUE(x,S_SYS_BIN,M_SYS_BIN) +#define M_SYS_BIN _SB_MAKEMASK(4, S_SYS_BIN) +#define V_SYS_BIN(x) _SB_MAKEVALUE(x, S_SYS_BIN) +#define G_SYS_BIN(x) _SB_GETVALUE(x, S_SYS_BIN, M_SYS_BIN) /* Wafer ID: bits 39:36 */ #define S_SYS_WAFERID2_200 _SB_MAKE64(36) -#define M_SYS_WAFERID2_200 _SB_MAKEMASK(4,S_SYS_WAFERID2_200) -#define V_SYS_WAFERID2_200(x) _SB_MAKEVALUE(x,S_SYS_WAFERID2_200) -#define G_SYS_WAFERID2_200(x) _SB_GETVALUE(x,S_SYS_WAFERID2_200,M_SYS_WAFERID2_200) +#define M_SYS_WAFERID2_200 _SB_MAKEMASK(4, S_SYS_WAFERID2_200) +#define V_SYS_WAFERID2_200(x) _SB_MAKEVALUE(x, S_SYS_WAFERID2_200) +#define G_SYS_WAFERID2_200(x) _SB_GETVALUE(x, S_SYS_WAFERID2_200, M_SYS_WAFERID2_200) /* Wafer ID: bits 39:0 */ #define S_SYS_WAFERID_300 _SB_MAKE64(0) -#define M_SYS_WAFERID_300 _SB_MAKEMASK(40,S_SYS_WAFERID_300) -#define V_SYS_WAFERID_300(x) _SB_MAKEVALUE(x,S_SYS_WAFERID_300) -#define G_SYS_WAFERID_300(x) _SB_GETVALUE(x,S_SYS_WAFERID_300,M_SYS_WAFERID_300) +#define M_SYS_WAFERID_300 _SB_MAKEMASK(40, S_SYS_WAFERID_300) +#define V_SYS_WAFERID_300(x) _SB_MAKEVALUE(x, S_SYS_WAFERID_300) +#define G_SYS_WAFERID_300(x) _SB_GETVALUE(x, S_SYS_WAFERID_300, M_SYS_WAFERID_300) #define S_SYS_XPOS _SB_MAKE64(40) -#define M_SYS_XPOS _SB_MAKEMASK(6,S_SYS_XPOS) -#define V_SYS_XPOS(x) _SB_MAKEVALUE(x,S_SYS_XPOS) -#define G_SYS_XPOS(x) _SB_GETVALUE(x,S_SYS_XPOS,M_SYS_XPOS) +#define M_SYS_XPOS _SB_MAKEMASK(6, S_SYS_XPOS) +#define V_SYS_XPOS(x) _SB_MAKEVALUE(x, S_SYS_XPOS) +#define G_SYS_XPOS(x) _SB_GETVALUE(x, S_SYS_XPOS, M_SYS_XPOS) #define S_SYS_YPOS _SB_MAKE64(46) -#define M_SYS_YPOS _SB_MAKEMASK(6,S_SYS_YPOS) -#define V_SYS_YPOS(x) _SB_MAKEVALUE(x,S_SYS_YPOS) -#define G_SYS_YPOS(x) _SB_GETVALUE(x,S_SYS_YPOS,M_SYS_YPOS) +#define M_SYS_YPOS _SB_MAKEMASK(6, S_SYS_YPOS) +#define V_SYS_YPOS(x) _SB_MAKEVALUE(x, S_SYS_YPOS) +#define G_SYS_YPOS(x) _SB_GETVALUE(x, S_SYS_YPOS, M_SYS_YPOS) #endif @@ -227,9 +227,9 @@ #define M_SYS_IOB1_DIV _SB_MAKEMASK1(6) #define S_SYS_PLL_DIV _SB_MAKE64(7) -#define M_SYS_PLL_DIV _SB_MAKEMASK(5,S_SYS_PLL_DIV) -#define V_SYS_PLL_DIV(x) _SB_MAKEVALUE(x,S_SYS_PLL_DIV) -#define G_SYS_PLL_DIV(x) _SB_GETVALUE(x,S_SYS_PLL_DIV,M_SYS_PLL_DIV) +#define M_SYS_PLL_DIV _SB_MAKEMASK(5, S_SYS_PLL_DIV) +#define V_SYS_PLL_DIV(x) _SB_MAKEVALUE(x, S_SYS_PLL_DIV) +#define G_SYS_PLL_DIV(x) _SB_GETVALUE(x, S_SYS_PLL_DIV, M_SYS_PLL_DIV) #define M_SYS_SER0_ENABLE _SB_MAKEMASK1(12) #define M_SYS_SER0_RSTB_EN _SB_MAKEMASK1(13) @@ -238,9 +238,9 @@ #define M_SYS_PCMCIA_ENABLE _SB_MAKEMASK1(16) #define S_SYS_BOOT_MODE _SB_MAKE64(17) -#define M_SYS_BOOT_MODE _SB_MAKEMASK(2,S_SYS_BOOT_MODE) -#define V_SYS_BOOT_MODE(x) _SB_MAKEVALUE(x,S_SYS_BOOT_MODE) -#define G_SYS_BOOT_MODE(x) _SB_GETVALUE(x,S_SYS_BOOT_MODE,M_SYS_BOOT_MODE) +#define M_SYS_BOOT_MODE _SB_MAKEMASK(2, S_SYS_BOOT_MODE) +#define V_SYS_BOOT_MODE(x) _SB_MAKEVALUE(x, S_SYS_BOOT_MODE) +#define G_SYS_BOOT_MODE(x) _SB_GETVALUE(x, S_SYS_BOOT_MODE, M_SYS_BOOT_MODE) #define K_SYS_BOOT_MODE_ROM32 0 #define K_SYS_BOOT_MODE_ROM8 1 #define K_SYS_BOOT_MODE_SMBUS_SMALL 2 @@ -255,9 +255,9 @@ #define M_SYS_GEN_PARITY_EN _SB_MAKEMASK1(25) #define S_SYS_CONFIG 26 -#define M_SYS_CONFIG _SB_MAKEMASK(6,S_SYS_CONFIG) -#define V_SYS_CONFIG(x) _SB_MAKEVALUE(x,S_SYS_CONFIG) -#define G_SYS_CONFIG(x) _SB_GETVALUE(x,S_SYS_CONFIG,M_SYS_CONFIG) +#define M_SYS_CONFIG _SB_MAKEMASK(6, S_SYS_CONFIG) +#define V_SYS_CONFIG(x) _SB_MAKEVALUE(x, S_SYS_CONFIG) +#define G_SYS_CONFIG(x) _SB_GETVALUE(x, S_SYS_CONFIG, M_SYS_CONFIG) /* The following bits are writeable by JTAG only. */ @@ -265,20 +265,20 @@ #define M_SYS_CLKSTEP _SB_MAKEMASK1(33) #define S_SYS_CLKCOUNT 34 -#define M_SYS_CLKCOUNT _SB_MAKEMASK(8,S_SYS_CLKCOUNT) -#define V_SYS_CLKCOUNT(x) _SB_MAKEVALUE(x,S_SYS_CLKCOUNT) -#define G_SYS_CLKCOUNT(x) _SB_GETVALUE(x,S_SYS_CLKCOUNT,M_SYS_CLKCOUNT) +#define M_SYS_CLKCOUNT _SB_MAKEMASK(8, S_SYS_CLKCOUNT) +#define V_SYS_CLKCOUNT(x) _SB_MAKEVALUE(x, S_SYS_CLKCOUNT) +#define G_SYS_CLKCOUNT(x) _SB_GETVALUE(x, S_SYS_CLKCOUNT, M_SYS_CLKCOUNT) #define M_SYS_PLL_BYPASS _SB_MAKEMASK1(42) #define S_SYS_PLL_IREF 43 -#define M_SYS_PLL_IREF _SB_MAKEMASK(2,S_SYS_PLL_IREF) +#define M_SYS_PLL_IREF _SB_MAKEMASK(2, S_SYS_PLL_IREF) #define S_SYS_PLL_VCO 45 -#define M_SYS_PLL_VCO _SB_MAKEMASK(2,S_SYS_PLL_VCO) +#define M_SYS_PLL_VCO _SB_MAKEMASK(2, S_SYS_PLL_VCO) #define S_SYS_PLL_VREG 47 -#define M_SYS_PLL_VREG _SB_MAKEMASK(2,S_SYS_PLL_VREG) +#define M_SYS_PLL_VREG _SB_MAKEMASK(2, S_SYS_PLL_VREG) #define M_SYS_MEM_RESET _SB_MAKEMASK1(49) #define M_SYS_L2C_RESET _SB_MAKEMASK1(50) @@ -314,13 +314,13 @@ */ #define S_MBOX_INT_3 0 -#define M_MBOX_INT_3 _SB_MAKEMASK(16,S_MBOX_INT_3) +#define M_MBOX_INT_3 _SB_MAKEMASK(16, S_MBOX_INT_3) #define S_MBOX_INT_2 16 -#define M_MBOX_INT_2 _SB_MAKEMASK(16,S_MBOX_INT_2) +#define M_MBOX_INT_2 _SB_MAKEMASK(16, S_MBOX_INT_2) #define S_MBOX_INT_1 32 -#define M_MBOX_INT_1 _SB_MAKEMASK(16,S_MBOX_INT_1) +#define M_MBOX_INT_1 _SB_MAKEMASK(16, S_MBOX_INT_1) #define S_MBOX_INT_0 48 -#define M_MBOX_INT_0 _SB_MAKEMASK(16,S_MBOX_INT_0) +#define M_MBOX_INT_0 _SB_MAKEMASK(16, S_MBOX_INT_0) /* * Watchdog Registers (Table 4-8) (Table 4-9) (Table 4-10) @@ -330,18 +330,18 @@ #define V_SCD_WDOG_FREQ 1000000 #define S_SCD_WDOG_INIT 0 -#define M_SCD_WDOG_INIT _SB_MAKEMASK(23,S_SCD_WDOG_INIT) +#define M_SCD_WDOG_INIT _SB_MAKEMASK(23, S_SCD_WDOG_INIT) #define S_SCD_WDOG_CNT 0 -#define M_SCD_WDOG_CNT _SB_MAKEMASK(23,S_SCD_WDOG_CNT) +#define M_SCD_WDOG_CNT _SB_MAKEMASK(23, S_SCD_WDOG_CNT) #define S_SCD_WDOG_ENABLE 0 #define M_SCD_WDOG_ENABLE _SB_MAKEMASK1(S_SCD_WDOG_ENABLE) #define S_SCD_WDOG_RESET_TYPE 2 -#define M_SCD_WDOG_RESET_TYPE _SB_MAKEMASK(3,S_SCD_WDOG_RESET_TYPE) -#define V_SCD_WDOG_RESET_TYPE(x) _SB_MAKEVALUE(x,S_SCD_WDOG_RESET_TYPE) -#define G_SCD_WDOG_RESET_TYPE(x) _SB_GETVALUE(x,S_SCD_WDOG_RESET_TYPE,M_SCD_WDOG_RESET_TYPE) +#define M_SCD_WDOG_RESET_TYPE _SB_MAKEMASK(3, S_SCD_WDOG_RESET_TYPE) +#define V_SCD_WDOG_RESET_TYPE(x) _SB_MAKEVALUE(x, S_SCD_WDOG_RESET_TYPE) +#define G_SCD_WDOG_RESET_TYPE(x) _SB_GETVALUE(x, S_SCD_WDOG_RESET_TYPE, M_SCD_WDOG_RESET_TYPE) #define K_SCD_WDOG_RESET_FULL 0 /* actually, (x & 1) == 0 */ #define K_SCD_WDOG_RESET_SOFT 1 @@ -363,15 +363,15 @@ #define V_SCD_TIMER_FREQ 1000000 #define S_SCD_TIMER_INIT 0 -#define M_SCD_TIMER_INIT _SB_MAKEMASK(23,S_SCD_TIMER_INIT) -#define V_SCD_TIMER_INIT(x) _SB_MAKEVALUE(x,S_SCD_TIMER_INIT) -#define G_SCD_TIMER_INIT(x) _SB_GETVALUE(x,S_SCD_TIMER_INIT,M_SCD_TIMER_INIT) +#define M_SCD_TIMER_INIT _SB_MAKEMASK(23, S_SCD_TIMER_INIT) +#define V_SCD_TIMER_INIT(x) _SB_MAKEVALUE(x, S_SCD_TIMER_INIT) +#define G_SCD_TIMER_INIT(x) _SB_GETVALUE(x, S_SCD_TIMER_INIT, M_SCD_TIMER_INIT) #define V_SCD_TIMER_WIDTH 23 #define S_SCD_TIMER_CNT 0 -#define M_SCD_TIMER_CNT _SB_MAKEMASK(V_SCD_TIMER_WIDTH,S_SCD_TIMER_CNT) -#define V_SCD_TIMER_CNT(x) _SB_MAKEVALUE(x,S_SCD_TIMER_CNT) -#define G_SCD_TIMER_CNT(x) _SB_GETVALUE(x,S_SCD_TIMER_CNT,M_SCD_TIMER_CNT) +#define M_SCD_TIMER_CNT _SB_MAKEMASK(V_SCD_TIMER_WIDTH, S_SCD_TIMER_CNT) +#define V_SCD_TIMER_CNT(x) _SB_MAKEVALUE(x, S_SCD_TIMER_CNT) +#define G_SCD_TIMER_CNT(x) _SB_GETVALUE(x, S_SCD_TIMER_CNT, M_SCD_TIMER_CNT) #define M_SCD_TIMER_ENABLE _SB_MAKEMASK1(0) #define M_SCD_TIMER_MODE _SB_MAKEMASK1(1) @@ -382,24 +382,24 @@ */ #define S_SPC_CFG_SRC0 0 -#define M_SPC_CFG_SRC0 _SB_MAKEMASK(8,S_SPC_CFG_SRC0) -#define V_SPC_CFG_SRC0(x) _SB_MAKEVALUE(x,S_SPC_CFG_SRC0) -#define G_SPC_CFG_SRC0(x) _SB_GETVALUE(x,S_SPC_CFG_SRC0,M_SPC_CFG_SRC0) +#define M_SPC_CFG_SRC0 _SB_MAKEMASK(8, S_SPC_CFG_SRC0) +#define V_SPC_CFG_SRC0(x) _SB_MAKEVALUE(x, S_SPC_CFG_SRC0) +#define G_SPC_CFG_SRC0(x) _SB_GETVALUE(x, S_SPC_CFG_SRC0, M_SPC_CFG_SRC0) #define S_SPC_CFG_SRC1 8 -#define M_SPC_CFG_SRC1 _SB_MAKEMASK(8,S_SPC_CFG_SRC1) -#define V_SPC_CFG_SRC1(x) _SB_MAKEVALUE(x,S_SPC_CFG_SRC1) -#define G_SPC_CFG_SRC1(x) _SB_GETVALUE(x,S_SPC_CFG_SRC1,M_SPC_CFG_SRC1) +#define M_SPC_CFG_SRC1 _SB_MAKEMASK(8, S_SPC_CFG_SRC1) +#define V_SPC_CFG_SRC1(x) _SB_MAKEVALUE(x, S_SPC_CFG_SRC1) +#define G_SPC_CFG_SRC1(x) _SB_GETVALUE(x, S_SPC_CFG_SRC1, M_SPC_CFG_SRC1) #define S_SPC_CFG_SRC2 16 -#define M_SPC_CFG_SRC2 _SB_MAKEMASK(8,S_SPC_CFG_SRC2) -#define V_SPC_CFG_SRC2(x) _SB_MAKEVALUE(x,S_SPC_CFG_SRC2) -#define G_SPC_CFG_SRC2(x) _SB_GETVALUE(x,S_SPC_CFG_SRC2,M_SPC_CFG_SRC2) +#define M_SPC_CFG_SRC2 _SB_MAKEMASK(8, S_SPC_CFG_SRC2) +#define V_SPC_CFG_SRC2(x) _SB_MAKEVALUE(x, S_SPC_CFG_SRC2) +#define G_SPC_CFG_SRC2(x) _SB_GETVALUE(x, S_SPC_CFG_SRC2, M_SPC_CFG_SRC2) #define S_SPC_CFG_SRC3 24 -#define M_SPC_CFG_SRC3 _SB_MAKEMASK(8,S_SPC_CFG_SRC3) -#define V_SPC_CFG_SRC3(x) _SB_MAKEVALUE(x,S_SPC_CFG_SRC3) -#define G_SPC_CFG_SRC3(x) _SB_GETVALUE(x,S_SPC_CFG_SRC3,M_SPC_CFG_SRC3) +#define M_SPC_CFG_SRC3 _SB_MAKEMASK(8, S_SPC_CFG_SRC3) +#define V_SPC_CFG_SRC3(x) _SB_MAKEVALUE(x, S_SPC_CFG_SRC3) +#define G_SPC_CFG_SRC3(x) _SB_GETVALUE(x, S_SPC_CFG_SRC3, M_SPC_CFG_SRC3) #if SIBYTE_HDR_FEATURE_1250_112x #define M_SPC_CFG_CLEAR _SB_MAKEMASK1(32) @@ -412,57 +412,57 @@ */ #define S_SCD_BERR_TID 8 -#define M_SCD_BERR_TID _SB_MAKEMASK(10,S_SCD_BERR_TID) -#define V_SCD_BERR_TID(x) _SB_MAKEVALUE(x,S_SCD_BERR_TID) -#define G_SCD_BERR_TID(x) _SB_GETVALUE(x,S_SCD_BERR_TID,M_SCD_BERR_TID) +#define M_SCD_BERR_TID _SB_MAKEMASK(10, S_SCD_BERR_TID) +#define V_SCD_BERR_TID(x) _SB_MAKEVALUE(x, S_SCD_BERR_TID) +#define G_SCD_BERR_TID(x) _SB_GETVALUE(x, S_SCD_BERR_TID, M_SCD_BERR_TID) #define S_SCD_BERR_RID 18 -#define M_SCD_BERR_RID _SB_MAKEMASK(4,S_SCD_BERR_RID) -#define V_SCD_BERR_RID(x) _SB_MAKEVALUE(x,S_SCD_BERR_RID) -#define G_SCD_BERR_RID(x) _SB_GETVALUE(x,S_SCD_BERR_RID,M_SCD_BERR_RID) +#define M_SCD_BERR_RID _SB_MAKEMASK(4, S_SCD_BERR_RID) +#define V_SCD_BERR_RID(x) _SB_MAKEVALUE(x, S_SCD_BERR_RID) +#define G_SCD_BERR_RID(x) _SB_GETVALUE(x, S_SCD_BERR_RID, M_SCD_BERR_RID) #define S_SCD_BERR_DCODE 22 -#define M_SCD_BERR_DCODE _SB_MAKEMASK(3,S_SCD_BERR_DCODE) -#define V_SCD_BERR_DCODE(x) _SB_MAKEVALUE(x,S_SCD_BERR_DCODE) -#define G_SCD_BERR_DCODE(x) _SB_GETVALUE(x,S_SCD_BERR_DCODE,M_SCD_BERR_DCODE) +#define M_SCD_BERR_DCODE _SB_MAKEMASK(3, S_SCD_BERR_DCODE) +#define V_SCD_BERR_DCODE(x) _SB_MAKEVALUE(x, S_SCD_BERR_DCODE) +#define G_SCD_BERR_DCODE(x) _SB_GETVALUE(x, S_SCD_BERR_DCODE, M_SCD_BERR_DCODE) #define M_SCD_BERR_MULTERRS _SB_MAKEMASK1(30) #define S_SCD_L2ECC_CORR_D 0 -#define M_SCD_L2ECC_CORR_D _SB_MAKEMASK(8,S_SCD_L2ECC_CORR_D) -#define V_SCD_L2ECC_CORR_D(x) _SB_MAKEVALUE(x,S_SCD_L2ECC_CORR_D) -#define G_SCD_L2ECC_CORR_D(x) _SB_GETVALUE(x,S_SCD_L2ECC_CORR_D,M_SCD_L2ECC_CORR_D) +#define M_SCD_L2ECC_CORR_D _SB_MAKEMASK(8, S_SCD_L2ECC_CORR_D) +#define V_SCD_L2ECC_CORR_D(x) _SB_MAKEVALUE(x, S_SCD_L2ECC_CORR_D) +#define G_SCD_L2ECC_CORR_D(x) _SB_GETVALUE(x, S_SCD_L2ECC_CORR_D, M_SCD_L2ECC_CORR_D) #define S_SCD_L2ECC_BAD_D 8 -#define M_SCD_L2ECC_BAD_D _SB_MAKEMASK(8,S_SCD_L2ECC_BAD_D) -#define V_SCD_L2ECC_BAD_D(x) _SB_MAKEVALUE(x,S_SCD_L2ECC_BAD_D) -#define G_SCD_L2ECC_BAD_D(x) _SB_GETVALUE(x,S_SCD_L2ECC_BAD_D,M_SCD_L2ECC_BAD_D) +#define M_SCD_L2ECC_BAD_D _SB_MAKEMASK(8, S_SCD_L2ECC_BAD_D) +#define V_SCD_L2ECC_BAD_D(x) _SB_MAKEVALUE(x, S_SCD_L2ECC_BAD_D) +#define G_SCD_L2ECC_BAD_D(x) _SB_GETVALUE(x, S_SCD_L2ECC_BAD_D, M_SCD_L2ECC_BAD_D) #define S_SCD_L2ECC_CORR_T 16 -#define M_SCD_L2ECC_CORR_T _SB_MAKEMASK(8,S_SCD_L2ECC_CORR_T) -#define V_SCD_L2ECC_CORR_T(x) _SB_MAKEVALUE(x,S_SCD_L2ECC_CORR_T) -#define G_SCD_L2ECC_CORR_T(x) _SB_GETVALUE(x,S_SCD_L2ECC_CORR_T,M_SCD_L2ECC_CORR_T) +#define M_SCD_L2ECC_CORR_T _SB_MAKEMASK(8, S_SCD_L2ECC_CORR_T) +#define V_SCD_L2ECC_CORR_T(x) _SB_MAKEVALUE(x, S_SCD_L2ECC_CORR_T) +#define G_SCD_L2ECC_CORR_T(x) _SB_GETVALUE(x, S_SCD_L2ECC_CORR_T, M_SCD_L2ECC_CORR_T) #define S_SCD_L2ECC_BAD_T 24 -#define M_SCD_L2ECC_BAD_T _SB_MAKEMASK(8,S_SCD_L2ECC_BAD_T) -#define V_SCD_L2ECC_BAD_T(x) _SB_MAKEVALUE(x,S_SCD_L2ECC_BAD_T) -#define G_SCD_L2ECC_BAD_T(x) _SB_GETVALUE(x,S_SCD_L2ECC_BAD_T,M_SCD_L2ECC_BAD_T) +#define M_SCD_L2ECC_BAD_T _SB_MAKEMASK(8, S_SCD_L2ECC_BAD_T) +#define V_SCD_L2ECC_BAD_T(x) _SB_MAKEVALUE(x, S_SCD_L2ECC_BAD_T) +#define G_SCD_L2ECC_BAD_T(x) _SB_GETVALUE(x, S_SCD_L2ECC_BAD_T, M_SCD_L2ECC_BAD_T) #define S_SCD_MEM_ECC_CORR 0 -#define M_SCD_MEM_ECC_CORR _SB_MAKEMASK(8,S_SCD_MEM_ECC_CORR) -#define V_SCD_MEM_ECC_CORR(x) _SB_MAKEVALUE(x,S_SCD_MEM_ECC_CORR) -#define G_SCD_MEM_ECC_CORR(x) _SB_GETVALUE(x,S_SCD_MEM_ECC_CORR,M_SCD_MEM_ECC_CORR) +#define M_SCD_MEM_ECC_CORR _SB_MAKEMASK(8, S_SCD_MEM_ECC_CORR) +#define V_SCD_MEM_ECC_CORR(x) _SB_MAKEVALUE(x, S_SCD_MEM_ECC_CORR) +#define G_SCD_MEM_ECC_CORR(x) _SB_GETVALUE(x, S_SCD_MEM_ECC_CORR, M_SCD_MEM_ECC_CORR) #define S_SCD_MEM_ECC_BAD 8 -#define M_SCD_MEM_ECC_BAD _SB_MAKEMASK(8,S_SCD_MEM_ECC_BAD) -#define V_SCD_MEM_ECC_BAD(x) _SB_MAKEVALUE(x,S_SCD_MEM_ECC_BAD) -#define G_SCD_MEM_ECC_BAD(x) _SB_GETVALUE(x,S_SCD_MEM_ECC_BAD,M_SCD_MEM_ECC_BAD) +#define M_SCD_MEM_ECC_BAD _SB_MAKEMASK(8, S_SCD_MEM_ECC_BAD) +#define V_SCD_MEM_ECC_BAD(x) _SB_MAKEVALUE(x, S_SCD_MEM_ECC_BAD) +#define G_SCD_MEM_ECC_BAD(x) _SB_GETVALUE(x, S_SCD_MEM_ECC_BAD, M_SCD_MEM_ECC_BAD) #define S_SCD_MEM_BUSERR 16 -#define M_SCD_MEM_BUSERR _SB_MAKEMASK(8,S_SCD_MEM_BUSERR) -#define V_SCD_MEM_BUSERR(x) _SB_MAKEVALUE(x,S_SCD_MEM_BUSERR) -#define G_SCD_MEM_BUSERR(x) _SB_GETVALUE(x,S_SCD_MEM_BUSERR,M_SCD_MEM_BUSERR) +#define M_SCD_MEM_BUSERR _SB_MAKEMASK(8, S_SCD_MEM_BUSERR) +#define V_SCD_MEM_BUSERR(x) _SB_MAKEVALUE(x, S_SCD_MEM_BUSERR) +#define G_SCD_MEM_BUSERR(x) _SB_GETVALUE(x, S_SCD_MEM_BUSERR, M_SCD_MEM_BUSERR) /* @@ -470,13 +470,13 @@ */ #if SIBYTE_HDR_FEATURE_1250_112x -#define M_ATRAP_INDEX _SB_MAKEMASK(4,0) -#define M_ATRAP_ADDRESS _SB_MAKEMASK(40,0) +#define M_ATRAP_INDEX _SB_MAKEMASK(4, 0) +#define M_ATRAP_ADDRESS _SB_MAKEMASK(40, 0) #define S_ATRAP_CFG_CNT 0 -#define M_ATRAP_CFG_CNT _SB_MAKEMASK(3,S_ATRAP_CFG_CNT) -#define V_ATRAP_CFG_CNT(x) _SB_MAKEVALUE(x,S_ATRAP_CFG_CNT) -#define G_ATRAP_CFG_CNT(x) _SB_GETVALUE(x,S_ATRAP_CFG_CNT,M_ATRAP_CFG_CNT) +#define M_ATRAP_CFG_CNT _SB_MAKEMASK(3, S_ATRAP_CFG_CNT) +#define V_ATRAP_CFG_CNT(x) _SB_MAKEVALUE(x, S_ATRAP_CFG_CNT) +#define G_ATRAP_CFG_CNT(x) _SB_GETVALUE(x, S_ATRAP_CFG_CNT, M_ATRAP_CFG_CNT) #define M_ATRAP_CFG_WRITE _SB_MAKEMASK1(3) #define M_ATRAP_CFG_ALL _SB_MAKEMASK1(4) @@ -485,9 +485,9 @@ #define M_ATRAP_CFG_SRCINV _SB_MAKEMASK1(7) #define S_ATRAP_CFG_AGENTID 8 -#define M_ATRAP_CFG_AGENTID _SB_MAKEMASK(4,S_ATRAP_CFG_AGENTID) -#define V_ATRAP_CFG_AGENTID(x) _SB_MAKEVALUE(x,S_ATRAP_CFG_AGENTID) -#define G_ATRAP_CFG_AGENTID(x) _SB_GETVALUE(x,S_ATRAP_CFG_AGENTID,M_ATRAP_CFG_AGENTID) +#define M_ATRAP_CFG_AGENTID _SB_MAKEMASK(4, S_ATRAP_CFG_AGENTID) +#define V_ATRAP_CFG_AGENTID(x) _SB_MAKEVALUE(x, S_ATRAP_CFG_AGENTID) +#define G_ATRAP_CFG_AGENTID(x) _SB_GETVALUE(x, S_ATRAP_CFG_AGENTID, M_ATRAP_CFG_AGENTID) #define K_BUS_AGENT_CPU0 0 #define K_BUS_AGENT_CPU1 1 @@ -498,9 +498,9 @@ #define K_BUS_AGENT_MC 7 #define S_ATRAP_CFG_CATTR 12 -#define M_ATRAP_CFG_CATTR _SB_MAKEMASK(3,S_ATRAP_CFG_CATTR) -#define V_ATRAP_CFG_CATTR(x) _SB_MAKEVALUE(x,S_ATRAP_CFG_CATTR) -#define G_ATRAP_CFG_CATTR(x) _SB_GETVALUE(x,S_ATRAP_CFG_CATTR,M_ATRAP_CFG_CATTR) +#define M_ATRAP_CFG_CATTR _SB_MAKEMASK(3, S_ATRAP_CFG_CATTR) +#define V_ATRAP_CFG_CATTR(x) _SB_MAKEVALUE(x, S_ATRAP_CFG_CATTR) +#define G_ATRAP_CFG_CATTR(x) _SB_GETVALUE(x, S_ATRAP_CFG_CATTR, M_ATRAP_CFG_CATTR) #define K_ATRAP_CFG_CATTR_IGNORE 0 #define K_ATRAP_CFG_CATTR_UNC 1 @@ -541,18 +541,18 @@ #endif /* 1480 */ #endif /* 1250/112x */ -#define M_SCD_TRACE_CFG_CUR_ADDR _SB_MAKEMASK(8,S_SCD_TRACE_CFG_CUR_ADDR) -#define V_SCD_TRACE_CFG_CUR_ADDR(x) _SB_MAKEVALUE(x,S_SCD_TRACE_CFG_CUR_ADDR) -#define G_SCD_TRACE_CFG_CUR_ADDR(x) _SB_GETVALUE(x,S_SCD_TRACE_CFG_CUR_ADDR,M_SCD_TRACE_CFG_CUR_ADDR) +#define M_SCD_TRACE_CFG_CUR_ADDR _SB_MAKEMASK(8, S_SCD_TRACE_CFG_CUR_ADDR) +#define V_SCD_TRACE_CFG_CUR_ADDR(x) _SB_MAKEVALUE(x, S_SCD_TRACE_CFG_CUR_ADDR) +#define G_SCD_TRACE_CFG_CUR_ADDR(x) _SB_GETVALUE(x, S_SCD_TRACE_CFG_CUR_ADDR, M_SCD_TRACE_CFG_CUR_ADDR) /* * Trace Event registers */ #define S_SCD_TREVT_ADDR_MATCH 0 -#define M_SCD_TREVT_ADDR_MATCH _SB_MAKEMASK(4,S_SCD_TREVT_ADDR_MATCH) -#define V_SCD_TREVT_ADDR_MATCH(x) _SB_MAKEVALUE(x,S_SCD_TREVT_ADDR_MATCH) -#define G_SCD_TREVT_ADDR_MATCH(x) _SB_GETVALUE(x,S_SCD_TREVT_ADDR_MATCH,M_SCD_TREVT_ADDR_MATCH) +#define M_SCD_TREVT_ADDR_MATCH _SB_MAKEMASK(4, S_SCD_TREVT_ADDR_MATCH) +#define V_SCD_TREVT_ADDR_MATCH(x) _SB_MAKEVALUE(x, S_SCD_TREVT_ADDR_MATCH) +#define G_SCD_TREVT_ADDR_MATCH(x) _SB_GETVALUE(x, S_SCD_TREVT_ADDR_MATCH, M_SCD_TREVT_ADDR_MATCH) #define M_SCD_TREVT_REQID_MATCH _SB_MAKEMASK1(4) #define M_SCD_TREVT_DATAID_MATCH _SB_MAKEMASK1(5) @@ -563,48 +563,48 @@ #define M_SCD_TREVT_READ _SB_MAKEMASK1(11) #define S_SCD_TREVT_REQID 12 -#define M_SCD_TREVT_REQID _SB_MAKEMASK(4,S_SCD_TREVT_REQID) -#define V_SCD_TREVT_REQID(x) _SB_MAKEVALUE(x,S_SCD_TREVT_REQID) -#define G_SCD_TREVT_REQID(x) _SB_GETVALUE(x,S_SCD_TREVT_REQID,M_SCD_TREVT_REQID) +#define M_SCD_TREVT_REQID _SB_MAKEMASK(4, S_SCD_TREVT_REQID) +#define V_SCD_TREVT_REQID(x) _SB_MAKEVALUE(x, S_SCD_TREVT_REQID) +#define G_SCD_TREVT_REQID(x) _SB_GETVALUE(x, S_SCD_TREVT_REQID, M_SCD_TREVT_REQID) #define S_SCD_TREVT_RESPID 16 -#define M_SCD_TREVT_RESPID _SB_MAKEMASK(4,S_SCD_TREVT_RESPID) -#define V_SCD_TREVT_RESPID(x) _SB_MAKEVALUE(x,S_SCD_TREVT_RESPID) -#define G_SCD_TREVT_RESPID(x) _SB_GETVALUE(x,S_SCD_TREVT_RESPID,M_SCD_TREVT_RESPID) +#define M_SCD_TREVT_RESPID _SB_MAKEMASK(4, S_SCD_TREVT_RESPID) +#define V_SCD_TREVT_RESPID(x) _SB_MAKEVALUE(x, S_SCD_TREVT_RESPID) +#define G_SCD_TREVT_RESPID(x) _SB_GETVALUE(x, S_SCD_TREVT_RESPID, M_SCD_TREVT_RESPID) #define S_SCD_TREVT_DATAID 20 -#define M_SCD_TREVT_DATAID _SB_MAKEMASK(4,S_SCD_TREVT_DATAID) -#define V_SCD_TREVT_DATAID(x) _SB_MAKEVALUE(x,S_SCD_TREVT_DATAID) -#define G_SCD_TREVT_DATAID(x) _SB_GETVALUE(x,S_SCD_TREVT_DATAID,M_SCD_TREVT_DATID) +#define M_SCD_TREVT_DATAID _SB_MAKEMASK(4, S_SCD_TREVT_DATAID) +#define V_SCD_TREVT_DATAID(x) _SB_MAKEVALUE(x, S_SCD_TREVT_DATAID) +#define G_SCD_TREVT_DATAID(x) _SB_GETVALUE(x, S_SCD_TREVT_DATAID, M_SCD_TREVT_DATID) #define S_SCD_TREVT_COUNT 24 -#define M_SCD_TREVT_COUNT _SB_MAKEMASK(8,S_SCD_TREVT_COUNT) -#define V_SCD_TREVT_COUNT(x) _SB_MAKEVALUE(x,S_SCD_TREVT_COUNT) -#define G_SCD_TREVT_COUNT(x) _SB_GETVALUE(x,S_SCD_TREVT_COUNT,M_SCD_TREVT_COUNT) +#define M_SCD_TREVT_COUNT _SB_MAKEMASK(8, S_SCD_TREVT_COUNT) +#define V_SCD_TREVT_COUNT(x) _SB_MAKEVALUE(x, S_SCD_TREVT_COUNT) +#define G_SCD_TREVT_COUNT(x) _SB_GETVALUE(x, S_SCD_TREVT_COUNT, M_SCD_TREVT_COUNT) /* * Trace Sequence registers */ #define S_SCD_TRSEQ_EVENT4 0 -#define M_SCD_TRSEQ_EVENT4 _SB_MAKEMASK(4,S_SCD_TRSEQ_EVENT4) -#define V_SCD_TRSEQ_EVENT4(x) _SB_MAKEVALUE(x,S_SCD_TRSEQ_EVENT4) -#define G_SCD_TRSEQ_EVENT4(x) _SB_GETVALUE(x,S_SCD_TRSEQ_EVENT4,M_SCD_TRSEQ_EVENT4) +#define M_SCD_TRSEQ_EVENT4 _SB_MAKEMASK(4, S_SCD_TRSEQ_EVENT4) +#define V_SCD_TRSEQ_EVENT4(x) _SB_MAKEVALUE(x, S_SCD_TRSEQ_EVENT4) +#define G_SCD_TRSEQ_EVENT4(x) _SB_GETVALUE(x, S_SCD_TRSEQ_EVENT4, M_SCD_TRSEQ_EVENT4) #define S_SCD_TRSEQ_EVENT3 4 -#define M_SCD_TRSEQ_EVENT3 _SB_MAKEMASK(4,S_SCD_TRSEQ_EVENT3) -#define V_SCD_TRSEQ_EVENT3(x) _SB_MAKEVALUE(x,S_SCD_TRSEQ_EVENT3) -#define G_SCD_TRSEQ_EVENT3(x) _SB_GETVALUE(x,S_SCD_TRSEQ_EVENT3,M_SCD_TRSEQ_EVENT3) +#define M_SCD_TRSEQ_EVENT3 _SB_MAKEMASK(4, S_SCD_TRSEQ_EVENT3) +#define V_SCD_TRSEQ_EVENT3(x) _SB_MAKEVALUE(x, S_SCD_TRSEQ_EVENT3) +#define G_SCD_TRSEQ_EVENT3(x) _SB_GETVALUE(x, S_SCD_TRSEQ_EVENT3, M_SCD_TRSEQ_EVENT3) #define S_SCD_TRSEQ_EVENT2 8 -#define M_SCD_TRSEQ_EVENT2 _SB_MAKEMASK(4,S_SCD_TRSEQ_EVENT2) -#define V_SCD_TRSEQ_EVENT2(x) _SB_MAKEVALUE(x,S_SCD_TRSEQ_EVENT2) -#define G_SCD_TRSEQ_EVENT2(x) _SB_GETVALUE(x,S_SCD_TRSEQ_EVENT2,M_SCD_TRSEQ_EVENT2) +#define M_SCD_TRSEQ_EVENT2 _SB_MAKEMASK(4, S_SCD_TRSEQ_EVENT2) +#define V_SCD_TRSEQ_EVENT2(x) _SB_MAKEVALUE(x, S_SCD_TRSEQ_EVENT2) +#define G_SCD_TRSEQ_EVENT2(x) _SB_GETVALUE(x, S_SCD_TRSEQ_EVENT2, M_SCD_TRSEQ_EVENT2) #define S_SCD_TRSEQ_EVENT1 12 -#define M_SCD_TRSEQ_EVENT1 _SB_MAKEMASK(4,S_SCD_TRSEQ_EVENT1) -#define V_SCD_TRSEQ_EVENT1(x) _SB_MAKEVALUE(x,S_SCD_TRSEQ_EVENT1) -#define G_SCD_TRSEQ_EVENT1(x) _SB_GETVALUE(x,S_SCD_TRSEQ_EVENT1,M_SCD_TRSEQ_EVENT1) +#define M_SCD_TRSEQ_EVENT1 _SB_MAKEMASK(4, S_SCD_TRSEQ_EVENT1) +#define V_SCD_TRSEQ_EVENT1(x) _SB_MAKEVALUE(x, S_SCD_TRSEQ_EVENT1) +#define G_SCD_TRSEQ_EVENT1(x) _SB_GETVALUE(x, S_SCD_TRSEQ_EVENT1, M_SCD_TRSEQ_EVENT1) #define K_SCD_TRSEQ_E0 0 #define K_SCD_TRSEQ_E1 1 @@ -629,9 +629,9 @@ V_SCD_TRSEQ_EVENT4(K_SCD_TRSEQ_IGNORED)) #define S_SCD_TRSEQ_FUNCTION 16 -#define M_SCD_TRSEQ_FUNCTION _SB_MAKEMASK(4,S_SCD_TRSEQ_FUNCTION) -#define V_SCD_TRSEQ_FUNCTION(x) _SB_MAKEVALUE(x,S_SCD_TRSEQ_FUNCTION) -#define G_SCD_TRSEQ_FUNCTION(x) _SB_GETVALUE(x,S_SCD_TRSEQ_FUNCTION,M_SCD_TRSEQ_FUNCTION) +#define M_SCD_TRSEQ_FUNCTION _SB_MAKEMASK(4, S_SCD_TRSEQ_FUNCTION) +#define V_SCD_TRSEQ_FUNCTION(x) _SB_MAKEVALUE(x, S_SCD_TRSEQ_FUNCTION) +#define G_SCD_TRSEQ_FUNCTION(x) _SB_GETVALUE(x, S_SCD_TRSEQ_FUNCTION, M_SCD_TRSEQ_FUNCTION) #define K_SCD_TRSEQ_FUNC_NOP 0 #define K_SCD_TRSEQ_FUNC_START 1 diff --git a/include/asm-mips/sibyte/sb1250_smbus.h b/include/asm-mips/sibyte/sb1250_smbus.h index 279a912213cd..04769923cf1e 100644 --- a/include/asm-mips/sibyte/sb1250_smbus.h +++ b/include/asm-mips/sibyte/sb1250_smbus.h @@ -41,16 +41,16 @@ */ #define S_SMB_FREQ_DIV 0 -#define M_SMB_FREQ_DIV _SB_MAKEMASK(13,S_SMB_FREQ_DIV) -#define V_SMB_FREQ_DIV(x) _SB_MAKEVALUE(x,S_SMB_FREQ_DIV) +#define M_SMB_FREQ_DIV _SB_MAKEMASK(13, S_SMB_FREQ_DIV) +#define V_SMB_FREQ_DIV(x) _SB_MAKEVALUE(x, S_SMB_FREQ_DIV) #define K_SMB_FREQ_400KHZ 0x1F #define K_SMB_FREQ_100KHZ 0x7D #define K_SMB_FREQ_10KHZ 1250 #define S_SMB_CMD 0 -#define M_SMB_CMD _SB_MAKEMASK(8,S_SMB_CMD) -#define V_SMB_CMD(x) _SB_MAKEVALUE(x,S_SMB_CMD) +#define M_SMB_CMD _SB_MAKEMASK(8, S_SMB_CMD) +#define V_SMB_CMD(x) _SB_MAKEVALUE(x, S_SMB_CMD) /* * SMBus control register (Table 14-4) @@ -61,7 +61,7 @@ #define S_SMB_DATA_OUT 4 #define M_SMB_DATA_OUT _SB_MAKEMASK1(S_SMB_DATA_OUT) -#define V_SMB_DATA_OUT(x) _SB_MAKEVALUE(x,S_SMB_DATA_OUT) +#define V_SMB_DATA_OUT(x) _SB_MAKEVALUE(x, S_SMB_DATA_OUT) #define M_SMB_DATA_DIR _SB_MAKEMASK1(5) #define M_SMB_DATA_DIR_OUTPUT M_SMB_DATA_DIR @@ -79,35 +79,35 @@ #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_SMB_SCL_IN 5 #define M_SMB_SCL_IN _SB_MAKEMASK1(S_SMB_SCL_IN) -#define V_SMB_SCL_IN(x) _SB_MAKEVALUE(x,S_SMB_SCL_IN) -#define G_SMB_SCL_IN(x) _SB_GETVALUE(x,S_SMB_SCL_IN,M_SMB_SCL_IN) +#define V_SMB_SCL_IN(x) _SB_MAKEVALUE(x, S_SMB_SCL_IN) +#define G_SMB_SCL_IN(x) _SB_GETVALUE(x, S_SMB_SCL_IN, M_SMB_SCL_IN) #endif /* 1250 PASS3 || 112x PASS1 || 1480 */ #define S_SMB_REF 6 #define M_SMB_REF _SB_MAKEMASK1(S_SMB_REF) -#define V_SMB_REF(x) _SB_MAKEVALUE(x,S_SMB_REF) -#define G_SMB_REF(x) _SB_GETVALUE(x,S_SMB_REF,M_SMB_REF) +#define V_SMB_REF(x) _SB_MAKEVALUE(x, S_SMB_REF) +#define G_SMB_REF(x) _SB_GETVALUE(x, S_SMB_REF, M_SMB_REF) #define S_SMB_DATA_IN 7 #define M_SMB_DATA_IN _SB_MAKEMASK1(S_SMB_DATA_IN) -#define V_SMB_DATA_IN(x) _SB_MAKEVALUE(x,S_SMB_DATA_IN) -#define G_SMB_DATA_IN(x) _SB_GETVALUE(x,S_SMB_DATA_IN,M_SMB_DATA_IN) +#define V_SMB_DATA_IN(x) _SB_MAKEVALUE(x, S_SMB_DATA_IN) +#define G_SMB_DATA_IN(x) _SB_GETVALUE(x, S_SMB_DATA_IN, M_SMB_DATA_IN) /* * SMBus Start/Command registers (Table 14-9) */ #define S_SMB_ADDR 0 -#define M_SMB_ADDR _SB_MAKEMASK(7,S_SMB_ADDR) -#define V_SMB_ADDR(x) _SB_MAKEVALUE(x,S_SMB_ADDR) -#define G_SMB_ADDR(x) _SB_GETVALUE(x,S_SMB_ADDR,M_SMB_ADDR) +#define M_SMB_ADDR _SB_MAKEMASK(7, S_SMB_ADDR) +#define V_SMB_ADDR(x) _SB_MAKEVALUE(x, S_SMB_ADDR) +#define G_SMB_ADDR(x) _SB_GETVALUE(x, S_SMB_ADDR, M_SMB_ADDR) #define M_SMB_QDATA _SB_MAKEMASK1(7) #define S_SMB_TT 8 -#define M_SMB_TT _SB_MAKEMASK(3,S_SMB_TT) -#define V_SMB_TT(x) _SB_MAKEVALUE(x,S_SMB_TT) -#define G_SMB_TT(x) _SB_GETVALUE(x,S_SMB_TT,M_SMB_TT) +#define M_SMB_TT _SB_MAKEMASK(3, S_SMB_TT) +#define V_SMB_TT(x) _SB_MAKEVALUE(x, S_SMB_TT) +#define G_SMB_TT(x) _SB_GETVALUE(x, S_SMB_TT, M_SMB_TT) #define K_SMB_TT_WR1BYTE 0 #define K_SMB_TT_WR2BYTE 1 @@ -134,12 +134,12 @@ */ #define S_SMB_LB 0 -#define M_SMB_LB _SB_MAKEMASK(8,S_SMB_LB) -#define V_SMB_LB(x) _SB_MAKEVALUE(x,S_SMB_LB) +#define M_SMB_LB _SB_MAKEMASK(8, S_SMB_LB) +#define V_SMB_LB(x) _SB_MAKEVALUE(x, S_SMB_LB) #define S_SMB_MB 8 -#define M_SMB_MB _SB_MAKEMASK(8,S_SMB_MB) -#define V_SMB_MB(x) _SB_MAKEVALUE(x,S_SMB_MB) +#define M_SMB_MB _SB_MAKEMASK(8, S_SMB_MB) +#define V_SMB_MB(x) _SB_MAKEVALUE(x, S_SMB_MB) /* @@ -147,22 +147,22 @@ */ #define S_SPEC_PEC 0 -#define M_SPEC_PEC _SB_MAKEMASK(8,S_SPEC_PEC) -#define V_SPEC_MB(x) _SB_MAKEVALUE(x,S_SPEC_PEC) +#define M_SPEC_PEC _SB_MAKEMASK(8, S_SPEC_PEC) +#define V_SPEC_MB(x) _SB_MAKEVALUE(x, S_SPEC_PEC) #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480) #define S_SMB_CMDH 8 -#define M_SMB_CMDH _SB_MAKEMASK(8,S_SMB_CMDH) -#define V_SMB_CMDH(x) _SB_MAKEVALUE(x,S_SMB_CMDH) +#define M_SMB_CMDH _SB_MAKEMASK(8, S_SMB_CMDH) +#define V_SMB_CMDH(x) _SB_MAKEVALUE(x, S_SMB_CMDH) #define M_SMB_EXTEND _SB_MAKEMASK1(14) #define S_SMB_DFMT 8 -#define M_SMB_DFMT _SB_MAKEMASK(3,S_SMB_DFMT) -#define V_SMB_DFMT(x) _SB_MAKEVALUE(x,S_SMB_DFMT) -#define G_SMB_DFMT(x) _SB_GETVALUE(x,S_SMB_DFMT,M_SMB_DFMT) +#define M_SMB_DFMT _SB_MAKEMASK(3, S_SMB_DFMT) +#define V_SMB_DFMT(x) _SB_MAKEVALUE(x, S_SMB_DFMT) +#define G_SMB_DFMT(x) _SB_GETVALUE(x, S_SMB_DFMT, M_SMB_DFMT) #define K_SMB_DFMT_1BYTE 0 #define K_SMB_DFMT_2BYTE 1 @@ -183,9 +183,9 @@ #define V_SMB_DFMT_RESERVED V_SMB_DFMT(K_SMB_DFMT_RESERVED) #define S_SMB_AFMT 11 -#define M_SMB_AFMT _SB_MAKEMASK(2,S_SMB_AFMT) -#define V_SMB_AFMT(x) _SB_MAKEVALUE(x,S_SMB_AFMT) -#define G_SMB_AFMT(x) _SB_GETVALUE(x,S_SMB_AFMT,M_SMB_AFMT) +#define M_SMB_AFMT _SB_MAKEMASK(2, S_SMB_AFMT) +#define V_SMB_AFMT(x) _SB_MAKEVALUE(x, S_SMB_AFMT) +#define G_SMB_AFMT(x) _SB_GETVALUE(x, S_SMB_AFMT, M_SMB_AFMT) #define K_SMB_AFMT_NONE 0 #define K_SMB_AFMT_ADDR 1 diff --git a/include/asm-mips/sibyte/sb1250_syncser.h b/include/asm-mips/sibyte/sb1250_syncser.h index dd154ac505d8..d4b8558e0bf1 100644 --- a/include/asm-mips/sibyte/sb1250_syncser.h +++ b/include/asm-mips/sibyte/sb1250_syncser.h @@ -43,8 +43,8 @@ #define M_SYNCSER_MSB_FIRST _SB_MAKEMASK1(1) #define S_SYNCSER_FLAG_NUM 2 -#define M_SYNCSER_FLAG_NUM _SB_MAKEMASK(4,S_SYNCSER_FLAG_NUM) -#define V_SYNCSER_FLAG_NUM _SB_MAKEVALUE(x,S_SYNCSER_FLAG_NUM) +#define M_SYNCSER_FLAG_NUM _SB_MAKEMASK(4, S_SYNCSER_FLAG_NUM) +#define V_SYNCSER_FLAG_NUM _SB_MAKEVALUE(x, S_SYNCSER_FLAG_NUM) #define M_SYNCSER_FLAG_EN _SB_MAKEMASK1(6) #define M_SYNCSER_HDLC_EN _SB_MAKEMASK1(7) @@ -59,8 +59,8 @@ #define M_SYNCSER_RXCLK_EXT _SB_MAKEMASK1(1) #define S_SYNCSER_RXSYNC_DLY 2 -#define M_SYNCSER_RXSYNC_DLY _SB_MAKEMASK(2,S_SYNCSER_RXSYNC_DLY) -#define V_SYNCSER_RXSYNC_DLY(x) _SB_MAKEVALUE(x,S_SYNCSER_RXSYNC_DLY) +#define M_SYNCSER_RXSYNC_DLY _SB_MAKEMASK(2, S_SYNCSER_RXSYNC_DLY) +#define V_SYNCSER_RXSYNC_DLY(x) _SB_MAKEVALUE(x, S_SYNCSER_RXSYNC_DLY) #define M_SYNCSER_RXSYNC_LOW _SB_MAKEMASK1(4) #define M_SYNCSER_RXSTRB_LOW _SB_MAKEMASK1(5) @@ -72,8 +72,8 @@ #define M_SYNCSER_TXCLK_EXT _SB_MAKEMASK1(9) #define S_SYNCSER_TXSYNC_DLY 10 -#define M_SYNCSER_TXSYNC_DLY _SB_MAKEMASK(2,S_SYNCSER_TXSYNC_DLY) -#define V_SYNCSER_TXSYNC_DLY(x) _SB_MAKEVALUE(x,S_SYNCSER_TXSYNC_DLY) +#define M_SYNCSER_TXSYNC_DLY _SB_MAKEMASK(2, S_SYNCSER_TXSYNC_DLY) +#define V_SYNCSER_TXSYNC_DLY(x) _SB_MAKEVALUE(x, S_SYNCSER_TXSYNC_DLY) #define M_SYNCSER_TXSYNC_LOW _SB_MAKEMASK1(12) #define M_SYNCSER_TXSTRB_LOW _SB_MAKEMASK1(13) @@ -137,8 +137,8 @@ #define M_SYNCSER_SEQ_BYTE _SB_MAKEMASK1(1) #define S_SYNCSER_SEQ_COUNT 2 -#define M_SYNCSER_SEQ_COUNT _SB_MAKEMASK(4,S_SYNCSER_SEQ_COUNT) -#define V_SYNCSER_SEQ_COUNT(x) _SB_MAKEVALUE(x,S_SYNCSER_SEQ_COUNT) +#define M_SYNCSER_SEQ_COUNT _SB_MAKEMASK(4, S_SYNCSER_SEQ_COUNT) +#define V_SYNCSER_SEQ_COUNT(x) _SB_MAKEVALUE(x, S_SYNCSER_SEQ_COUNT) #define M_SYNCSER_SEQ_ENABLE _SB_MAKEMASK1(6) #define M_SYNCSER_SEQ_STROBE _SB_MAKEMASK1(7) diff --git a/include/asm-mips/sibyte/sb1250_uart.h b/include/asm-mips/sibyte/sb1250_uart.h index cf74fedcbef1..d835bf280140 100644 --- a/include/asm-mips/sibyte/sb1250_uart.h +++ b/include/asm-mips/sibyte/sb1250_uart.h @@ -46,8 +46,8 @@ */ #define S_DUART_BITS_PER_CHAR 0 -#define M_DUART_BITS_PER_CHAR _SB_MAKEMASK(2,S_DUART_BITS_PER_CHAR) -#define V_DUART_BITS_PER_CHAR(x) _SB_MAKEVALUE(x,S_DUART_BITS_PER_CHAR) +#define M_DUART_BITS_PER_CHAR _SB_MAKEMASK(2, S_DUART_BITS_PER_CHAR) +#define V_DUART_BITS_PER_CHAR(x) _SB_MAKEVALUE(x, S_DUART_BITS_PER_CHAR) #define K_DUART_BITS_PER_CHAR_RSV0 0 #define K_DUART_BITS_PER_CHAR_RSV1 1 @@ -64,8 +64,8 @@ #define M_DUART_PARITY_TYPE_ODD _SB_MAKEMASK1(2) #define S_DUART_PARITY_MODE 3 -#define M_DUART_PARITY_MODE _SB_MAKEMASK(2,S_DUART_PARITY_MODE) -#define V_DUART_PARITY_MODE(x) _SB_MAKEVALUE(x,S_DUART_PARITY_MODE) +#define M_DUART_PARITY_MODE _SB_MAKEMASK(2, S_DUART_PARITY_MODE) +#define V_DUART_PARITY_MODE(x) _SB_MAKEVALUE(x, S_DUART_PARITY_MODE) #define K_DUART_PARITY_MODE_ADD 0 #define K_DUART_PARITY_MODE_ADD_FIXED 1 @@ -89,7 +89,7 @@ * Register: DUART_MODE_REG_2_B */ -#define M_DUART_MODE_RESERVED1 _SB_MAKEMASK(3,0) /* ignored */ +#define M_DUART_MODE_RESERVED1 _SB_MAKEMASK(3, 0) /* ignored */ #define M_DUART_STOP_BIT_LEN_2 _SB_MAKEMASK1(3) #define M_DUART_STOP_BIT_LEN_1 0 @@ -100,8 +100,8 @@ #define M_DUART_MODE_RESERVED2 _SB_MAKEMASK1(5) /* must be zero */ #define S_DUART_CHAN_MODE 6 -#define M_DUART_CHAN_MODE _SB_MAKEMASK(2,S_DUART_CHAN_MODE) -#define V_DUART_CHAN_MODE(x) _SB_MAKEVALUE(x,S_DUART_CHAN_MODE) +#define M_DUART_CHAN_MODE _SB_MAKEMASK(2, S_DUART_CHAN_MODE) +#define V_DUART_CHAN_MODE(x) _SB_MAKEVALUE(x, S_DUART_CHAN_MODE) #define K_DUART_CHAN_MODE_NORMAL 0 #define K_DUART_CHAN_MODE_LCL_LOOP 2 @@ -123,8 +123,8 @@ #define M_DUART_TX_DIS _SB_MAKEMASK1(3) #define S_DUART_MISC_CMD 4 -#define M_DUART_MISC_CMD _SB_MAKEMASK(3,S_DUART_MISC_CMD) -#define V_DUART_MISC_CMD(x) _SB_MAKEVALUE(x,S_DUART_MISC_CMD) +#define M_DUART_MISC_CMD _SB_MAKEMASK(3, S_DUART_MISC_CMD) +#define V_DUART_MISC_CMD(x) _SB_MAKEVALUE(x, S_DUART_MISC_CMD) #define K_DUART_MISC_CMD_NOACTION0 0 #define K_DUART_MISC_CMD_NOACTION1 1 @@ -168,7 +168,7 @@ * Register: DUART_CLK_SEL_B */ -#define M_DUART_CLK_COUNTER _SB_MAKEMASK(12,0) +#define M_DUART_CLK_COUNTER _SB_MAKEMASK(12, 0) #define V_DUART_BAUD_RATE(x) (100000000/((x)*20)-1) /* @@ -179,8 +179,8 @@ * Register: DUART_TX_HOLD_B */ -#define M_DUART_RX_DATA _SB_MAKEMASK(8,0) -#define M_DUART_TX_DATA _SB_MAKEMASK(8,0) +#define M_DUART_RX_DATA _SB_MAKEMASK(8, 0) +#define M_DUART_TX_DATA _SB_MAKEMASK(8, 0) /* * DUART Input Port Register (Table 10-10) @@ -202,10 +202,10 @@ */ #define S_DUART_IN_PIN_VAL 0 -#define M_DUART_IN_PIN_VAL _SB_MAKEMASK(4,S_DUART_IN_PIN_VAL) +#define M_DUART_IN_PIN_VAL _SB_MAKEMASK(4, S_DUART_IN_PIN_VAL) #define S_DUART_IN_PIN_CHNG 4 -#define M_DUART_IN_PIN_CHNG _SB_MAKEMASK(4,S_DUART_IN_PIN_CHNG) +#define M_DUART_IN_PIN_CHNG _SB_MAKEMASK(4, S_DUART_IN_PIN_CHNG) /* @@ -217,7 +217,7 @@ #define M_DUART_OPC2_SEL _SB_MAKEMASK1(1) #define M_DUART_OPCR_RESERVED1 _SB_MAKEMASK1(2) /* must be zero */ #define M_DUART_OPC3_SEL _SB_MAKEMASK1(3) -#define M_DUART_OPCR_RESERVED2 _SB_MAKEMASK(4,4) /* must be zero */ +#define M_DUART_OPCR_RESERVED2 _SB_MAKEMASK(4, 4) /* must be zero */ /* * DUART Aux Control Register (Table 10-15) @@ -228,7 +228,7 @@ #define M_DUART_IP1_CHNG_ENA _SB_MAKEMASK1(1) #define M_DUART_IP2_CHNG_ENA _SB_MAKEMASK1(2) #define M_DUART_IP3_CHNG_ENA _SB_MAKEMASK1(3) -#define M_DUART_ACR_RESERVED _SB_MAKEMASK(4,4) +#define M_DUART_ACR_RESERVED _SB_MAKEMASK(4, 4) #define M_DUART_CTS_CHNG_ENA _SB_MAKEMASK1(0) #define M_DUART_CIN_CHNG_ENA _SB_MAKEMASK1(2) @@ -242,18 +242,18 @@ #define S_DUART_ISR_RX_A 1 #define M_DUART_ISR_RX_A _SB_MAKEMASK1(S_DUART_ISR_RX_A) -#define V_DUART_ISR_RX_A(x) _SB_MAKEVALUE(x,S_DUART_ISR_RX_A) -#define G_DUART_ISR_RX_A(x) _SB_GETVALUE(x,S_DUART_ISR_RX_A,M_DUART_ISR_RX_A) +#define V_DUART_ISR_RX_A(x) _SB_MAKEVALUE(x, S_DUART_ISR_RX_A) +#define G_DUART_ISR_RX_A(x) _SB_GETVALUE(x, S_DUART_ISR_RX_A, M_DUART_ISR_RX_A) #define M_DUART_ISR_BRK_A _SB_MAKEMASK1(2) #define M_DUART_ISR_IN_A _SB_MAKEMASK1(3) -#define M_DUART_ISR_ALL_A _SB_MAKEMASK(4,0) +#define M_DUART_ISR_ALL_A _SB_MAKEMASK(4, 0) #define M_DUART_ISR_TX_B _SB_MAKEMASK1(4) #define M_DUART_ISR_RX_B _SB_MAKEMASK1(5) #define M_DUART_ISR_BRK_B _SB_MAKEMASK1(6) #define M_DUART_ISR_IN_B _SB_MAKEMASK1(7) -#define M_DUART_ISR_ALL_B _SB_MAKEMASK(4,4) +#define M_DUART_ISR_ALL_B _SB_MAKEMASK(4, 4) /* * DUART Channel A Interrupt Status Register (Table 10-17) @@ -266,8 +266,8 @@ #define M_DUART_ISR_RX _SB_MAKEMASK1(1) #define M_DUART_ISR_BRK _SB_MAKEMASK1(2) #define M_DUART_ISR_IN _SB_MAKEMASK1(3) -#define M_DUART_ISR_ALL _SB_MAKEMASK(4,0) -#define M_DUART_ISR_RESERVED _SB_MAKEMASK(4,4) +#define M_DUART_ISR_ALL _SB_MAKEMASK(4, 0) +#define M_DUART_ISR_RESERVED _SB_MAKEMASK(4, 4) /* * DUART Interrupt Mask Register (Table 10-19) @@ -278,13 +278,13 @@ #define M_DUART_IMR_RX_A _SB_MAKEMASK1(1) #define M_DUART_IMR_BRK_A _SB_MAKEMASK1(2) #define M_DUART_IMR_IN_A _SB_MAKEMASK1(3) -#define M_DUART_IMR_ALL_A _SB_MAKEMASK(4,0) +#define M_DUART_IMR_ALL_A _SB_MAKEMASK(4, 0) #define M_DUART_IMR_TX_B _SB_MAKEMASK1(4) #define M_DUART_IMR_RX_B _SB_MAKEMASK1(5) #define M_DUART_IMR_BRK_B _SB_MAKEMASK1(6) #define M_DUART_IMR_IN_B _SB_MAKEMASK1(7) -#define M_DUART_IMR_ALL_B _SB_MAKEMASK(4,4) +#define M_DUART_IMR_ALL_B _SB_MAKEMASK(4, 4) /* * DUART Channel A Interrupt Mask Register (Table 10-20) @@ -297,8 +297,8 @@ #define M_DUART_IMR_RX _SB_MAKEMASK1(1) #define M_DUART_IMR_BRK _SB_MAKEMASK1(2) #define M_DUART_IMR_IN _SB_MAKEMASK1(3) -#define M_DUART_IMR_ALL _SB_MAKEMASK(4,0) -#define M_DUART_IMR_RESERVED _SB_MAKEMASK(4,4) +#define M_DUART_IMR_ALL _SB_MAKEMASK(4, 0) +#define M_DUART_IMR_RESERVED _SB_MAKEMASK(4, 4) /* @@ -310,7 +310,7 @@ #define M_DUART_SET_OPR1 _SB_MAKEMASK1(1) #define M_DUART_SET_OPR2 _SB_MAKEMASK1(2) #define M_DUART_SET_OPR3 _SB_MAKEMASK1(3) -#define M_DUART_OPSR_RESERVED _SB_MAKEMASK(4,4) +#define M_DUART_OPSR_RESERVED _SB_MAKEMASK(4, 4) /* * DUART Output Port Clear Register (Table 10-23) @@ -321,7 +321,7 @@ #define M_DUART_CLR_OPR1 _SB_MAKEMASK1(1) #define M_DUART_CLR_OPR2 _SB_MAKEMASK1(2) #define M_DUART_CLR_OPR3 _SB_MAKEMASK1(3) -#define M_DUART_OPCR_RESERVED _SB_MAKEMASK(4,4) +#define M_DUART_OPCR_RESERVED _SB_MAKEMASK(4, 4) /* * DUART Output Port RTS Register (Table 10-24) @@ -332,7 +332,7 @@ #define M_DUART_OUT_PIN_SET1 _SB_MAKEMASK1(1) #define M_DUART_OUT_PIN_CLR0 _SB_MAKEMASK1(2) #define M_DUART_OUT_PIN_CLR1 _SB_MAKEMASK1(3) -#define M_DUART_OPRR_RESERVED _SB_MAKEMASK(4,4) +#define M_DUART_OPRR_RESERVED _SB_MAKEMASK(4, 4) #define M_DUART_OUT_PIN_SET(chan) \ (chan == 0 ? M_DUART_OUT_PIN_SET0 : M_DUART_OUT_PIN_SET1) @@ -345,14 +345,14 @@ */ #define S_DUART_SIG_FULL _SB_MAKE64(0) -#define M_DUART_SIG_FULL _SB_MAKEMASK(4,S_DUART_SIG_FULL) -#define V_DUART_SIG_FULL(x) _SB_MAKEVALUE(x,S_DUART_SIG_FULL) -#define G_DUART_SIG_FULL(x) _SB_GETVALUE(x,S_DUART_SIG_FULL,M_DUART_SIG_FULL) +#define M_DUART_SIG_FULL _SB_MAKEMASK(4, S_DUART_SIG_FULL) +#define V_DUART_SIG_FULL(x) _SB_MAKEVALUE(x, S_DUART_SIG_FULL) +#define G_DUART_SIG_FULL(x) _SB_GETVALUE(x, S_DUART_SIG_FULL, M_DUART_SIG_FULL) #define S_DUART_INT_TIME _SB_MAKE64(4) -#define M_DUART_INT_TIME _SB_MAKEMASK(4,S_DUART_INT_TIME) -#define V_DUART_INT_TIME(x) _SB_MAKEVALUE(x,S_DUART_INT_TIME) -#define G_DUART_INT_TIME(x) _SB_GETVALUE(x,S_DUART_INT_TIME,M_DUART_INT_TIME) +#define M_DUART_INT_TIME _SB_MAKEMASK(4, S_DUART_INT_TIME) +#define V_DUART_INT_TIME(x) _SB_MAKEVALUE(x, S_DUART_INT_TIME) +#define G_DUART_INT_TIME(x) _SB_GETVALUE(x, S_DUART_INT_TIME, M_DUART_INT_TIME) #endif /* 1250 PASS2 || 112x PASS1 || 1480 */ diff --git a/include/asm-mips/siginfo.h b/include/asm-mips/siginfo.h index 2e32949bd674..96e28f18dad1 100644 --- a/include/asm-mips/siginfo.h +++ b/include/asm-mips/siginfo.h @@ -106,8 +106,8 @@ typedef struct siginfo { #undef SI_TIMER #undef SI_MESGQ #define SI_ASYNCIO -2 /* sent by AIO completion */ -#define SI_TIMER __SI_CODE(__SI_TIMER,-3) /* sent by timer expiration */ -#define SI_MESGQ __SI_CODE(__SI_MESGQ,-4) /* sent by real time mesq state change */ +#define SI_TIMER __SI_CODE(__SI_TIMER, -3) /* sent by timer expiration */ +#define SI_MESGQ __SI_CODE(__SI_MESGQ, -4) /* sent by real time mesq state change */ #ifdef __KERNEL__ diff --git a/include/asm-mips/sn/addrs.h b/include/asm-mips/sn/addrs.h index 6aa086868249..fec9bdd34913 100644 --- a/include/asm-mips/sn/addrs.h +++ b/include/asm-mips/sn/addrs.h @@ -208,9 +208,9 @@ UINT64_CAST(_pa) & NASID_MASK | \ UINT64_CAST(_pa) >> 2 & BDDIR_UPPER_MASK | \ (_rgn) << 3) -#define BDPRT_ENTRY_ADDR(_pa,_rgn) (BDPRT_ENTRY((_pa),(_rgn))) -#define BDPRT_ENTRY_S(_pa,_rgn,_val) (*(__psunsigned_t *)BDPRT_ENTRY((_pa),(_rgn))=(_val)) -#define BDPRT_ENTRY_L(_pa,_rgn) (*(__psunsigned_t *)BDPRT_ENTRY((_pa),(_rgn))) +#define BDPRT_ENTRY_ADDR(_pa, _rgn) (BDPRT_ENTRY((_pa), (_rgn))) +#define BDPRT_ENTRY_S(_pa, _rgn, _val) (*(__psunsigned_t *)BDPRT_ENTRY((_pa), (_rgn))=(_val)) +#define BDPRT_ENTRY_L(_pa, _rgn) (*(__psunsigned_t *)BDPRT_ENTRY((_pa), (_rgn))) #define BDECC_ENTRY(_pa) ((HSPEC_BASE + \ NODE_ADDRSPACE_SIZE / 2) | \ diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h index 852213d03b72..96cfd2ab1bcd 100644 --- a/include/asm-mips/sn/klconfig.h +++ b/include/asm-mips/sn/klconfig.h @@ -405,7 +405,7 @@ typedef struct kl_config_hdr { #define KLTYPE(_x) ((_x) & KLTYPE_MASK) #define IS_MIO_PRESENT(l) ((l->brd_type == KLTYPE_BASEIO) && \ (l->brd_flags & SECOND_NIC_PRESENT)) -#define IS_MIO_IOC3(l,n) (IS_MIO_PRESENT(l) && (n > 2)) +#define IS_MIO_IOC3(l, n) (IS_MIO_PRESENT(l) && (n > 2)) /* * board structures diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h index 59334f598b78..fb41a8d76392 100644 --- a/include/asm-mips/stackframe.h +++ b/include/asm-mips/stackframe.h @@ -393,11 +393,11 @@ * and disable interrupts only for the * current TC, using the TCStatus register. */ - mfc0 t0,CP0_TCSTATUS + mfc0 t0, CP0_TCSTATUS /* Fortunately CU 0 is in the same place in both registers */ /* Set TCU0, TMX, TKSU (for later inversion) and IXMT */ li t1, ST0_CU0 | 0x08001c00 - or t0,t1 + or t0, t1 /* Clear TKSU, leave IXMT */ xori t0, 0x00001800 mtc0 t0, CP0_TCSTATUS @@ -429,11 +429,11 @@ * current TC, using the TCStatus register. */ _ehb - mfc0 t0,CP0_TCSTATUS + mfc0 t0, CP0_TCSTATUS /* Fortunately CU 0 is in the same place in both registers */ /* Set TCU0, TKSU (for later inversion) and IXMT */ li t1, ST0_CU0 | 0x08001c00 - or t0,t1 + or t0, t1 /* Clear TKSU *and* IXMT */ xori t0, 0x00001c00 mtc0 t0, CP0_TCSTATUS diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 862f161e88b6..90e4b403f531 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -62,7 +62,7 @@ do { \ #define __mips_mt_fpaff_switch_to(prev) do { (void) (prev); } while (0) #endif -#define switch_to(prev,next,last) \ +#define switch_to(prev, next, last) \ do { \ __mips_mt_fpaff_switch_to(prev); \ if (cpu_has_dsp) \ @@ -193,7 +193,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz return x; } -#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) extern void set_handler(unsigned long offset, void *addr, unsigned long len); extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len); diff --git a/include/asm-mips/tlbflush.h b/include/asm-mips/tlbflush.h index 276be77c3e85..730e841fb08a 100644 --- a/include/asm-mips/tlbflush.h +++ b/include/asm-mips/tlbflush.h @@ -37,10 +37,10 @@ extern void flush_tlb_one(unsigned long vaddr); #define flush_tlb_all() local_flush_tlb_all() #define flush_tlb_mm(mm) local_flush_tlb_mm(mm) -#define flush_tlb_range(vma,vmaddr,end) local_flush_tlb_range(vma, vmaddr, end) +#define flush_tlb_range(vma, vmaddr, end) local_flush_tlb_range(vma, vmaddr, end) #define flush_tlb_kernel_range(vmaddr,end) \ local_flush_tlb_kernel_range(vmaddr, end) -#define flush_tlb_page(vma,page) local_flush_tlb_page(vma, page) +#define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page) #define flush_tlb_one(vaddr) local_flush_tlb_one(vaddr) #endif /* CONFIG_SMP */ diff --git a/include/asm-mips/tx4938/rbtx4938.h b/include/asm-mips/tx4938/rbtx4938.h index b14acb575be2..b180488dcdc4 100644 --- a/include/asm-mips/tx4938/rbtx4938.h +++ b/include/asm-mips/tx4938/rbtx4938.h @@ -153,7 +153,7 @@ #define RBTX4938_IRQ_IRC_WTOERR (RBTX4938_IRQ_IRC + TX4938_IR_WTOERR) #define RBTX4938_IRQ_IRC_INT(n) (RBTX4938_IRQ_IRC + TX4938_IR_INT(n)) #define RBTX4938_IRQ_IRC_SIO(n) (RBTX4938_IRQ_IRC + TX4938_IR_SIO(n)) -#define RBTX4938_IRQ_IRC_DMA(ch,n) (RBTX4938_IRQ_IRC + TX4938_IR_DMA(ch,n)) +#define RBTX4938_IRQ_IRC_DMA(ch, n) (RBTX4938_IRQ_IRC + TX4938_IR_DMA(ch, n)) #define RBTX4938_IRQ_IRC_PIO (RBTX4938_IRQ_IRC + TX4938_IR_PIO) #define RBTX4938_IRQ_IRC_PDMAC (RBTX4938_IRQ_IRC + TX4938_IR_PDMAC) #define RBTX4938_IRQ_IRC_PCIC (RBTX4938_IRQ_IRC + TX4938_IR_PCIC) diff --git a/include/asm-mips/tx4938/tx4938.h b/include/asm-mips/tx4938/tx4938.h index afdb19813ca1..650b010761f9 100644 --- a/include/asm-mips/tx4938/tx4938.h +++ b/include/asm-mips/tx4938/tx4938.h @@ -16,7 +16,7 @@ #include #define tx4938_read_nfmc(addr) (*(volatile unsigned int *)(addr)) -#define tx4938_write_nfmc(b,addr) (*(volatile unsigned int *)(addr)) = (b) +#define tx4938_write_nfmc(b, addr) (*(volatile unsigned int *)(addr)) = (b) #define TX4938_NR_IRQ_LOCAL TX4938_IRQ_PIC_BEG @@ -84,27 +84,27 @@ #include #ifdef __BIG_ENDIAN -#define endian_def_l2(e1,e2) \ - volatile unsigned long e1,e2 -#define endian_def_s2(e1,e2) \ - volatile unsigned short e1,e2 -#define endian_def_sb2(e1,e2,e3) \ - volatile unsigned short e1;volatile unsigned char e2,e3 -#define endian_def_b2s(e1,e2,e3) \ - volatile unsigned char e1,e2;volatile unsigned short e3 -#define endian_def_b4(e1,e2,e3,e4) \ - volatile unsigned char e1,e2,e3,e4 +#define endian_def_l2(e1, e2) \ + volatile unsigned long e1, e2 +#define endian_def_s2(e1, e2) \ + volatile unsigned short e1, e2 +#define endian_def_sb2(e1, e2, e3) \ + volatile unsigned short e1;volatile unsigned char e2, e3 +#define endian_def_b2s(e1, e2, e3) \ + volatile unsigned char e1, e2;volatile unsigned short e3 +#define endian_def_b4(e1, e2, e3, e4) \ + volatile unsigned char e1, e2, e3, e4 #else -#define endian_def_l2(e1,e2) \ - volatile unsigned long e2,e1 -#define endian_def_s2(e1,e2) \ - volatile unsigned short e2,e1 -#define endian_def_sb2(e1,e2,e3) \ - volatile unsigned char e3,e2;volatile unsigned short e1 -#define endian_def_b2s(e1,e2,e3) \ - volatile unsigned short e3;volatile unsigned char e2,e1 -#define endian_def_b4(e1,e2,e3,e4) \ - volatile unsigned char e4,e3,e2,e1 +#define endian_def_l2(e1, e2) \ + volatile unsigned long e2, e1 +#define endian_def_s2(e1, e2) \ + volatile unsigned short e2, e1 +#define endian_def_sb2(e1, e2, e3) \ + volatile unsigned char e3, e2;volatile unsigned short e1 +#define endian_def_b2s(e1, e2, e3) \ + volatile unsigned short e3;volatile unsigned char e2, e1 +#define endian_def_b4(e1, e2, e3, e4) \ + volatile unsigned char e4, e3, e2, e1 #endif @@ -354,7 +354,7 @@ struct tx4938_ccfg_reg { #define TX4938_NUM_IR_SIO 2 #define TX4938_IR_SIO(n) (8 + (n)) #define TX4938_NUM_IR_DMA 4 -#define TX4938_IR_DMA(ch,n) ((ch ? 27 : 10) + (n)) /* 10-13,27-30 */ +#define TX4938_IR_DMA(ch, n) ((ch ? 27 : 10) + (n)) /* 10-13, 27-30 */ #define TX4938_IR_PIO 14 #define TX4938_IR_PDMAC 15 #define TX4938_IR_PCIC 16 diff --git a/include/asm-mips/tx4938/tx4938_mips.h b/include/asm-mips/tx4938/tx4938_mips.h index 5f8498fef005..f346ff58b947 100644 --- a/include/asm-mips/tx4938/tx4938_mips.h +++ b/include/asm-mips/tx4938/tx4938_mips.h @@ -19,10 +19,10 @@ #define reg_rd32(r) ((u32)(*((vu32*)(r)))) #define reg_rd64(r) ((u64)(*((vu64*)(r)))) -#define reg_wr08(r,v) ((*((vu8 *)(r)))=((u8 )(v))) -#define reg_wr16(r,v) ((*((vu16*)(r)))=((u16)(v))) -#define reg_wr32(r,v) ((*((vu32*)(r)))=((u32)(v))) -#define reg_wr64(r,v) ((*((vu64*)(r)))=((u64)(v))) +#define reg_wr08(r, v) ((*((vu8 *)(r)))=((u8 )(v))) +#define reg_wr16(r, v) ((*((vu16*)(r)))=((u16)(v))) +#define reg_wr32(r, v) ((*((vu32*)(r)))=((u32)(v))) +#define reg_wr64(r, v) ((*((vu64*)(r)))=((u64)(v))) typedef volatile __signed char vs8; typedef volatile unsigned char vu8; diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h index 017dfb0d75c3..c30c718994c9 100644 --- a/include/asm-mips/uaccess.h +++ b/include/asm-mips/uaccess.h @@ -63,7 +63,7 @@ #define get_fs() (current_thread_info()->addr_limit) #define set_fs(x) (current_thread_info()->addr_limit = (x)) -#define segment_eq(a,b) ((a).seg == (b).seg) +#define segment_eq(a, b) ((a).seg == (b).seg) /* @@ -108,7 +108,7 @@ (((signed long)((mask) & ((addr) | ((addr) + (size)) | __ua_size(size)))) == 0) #define access_ok(type, addr, size) \ - likely(__access_ok((unsigned long)(addr), (size),__access_mask)) + likely(__access_ok((unsigned long)(addr), (size), __access_mask)) /* * put_user: - Write a simple value into user space. @@ -127,7 +127,7 @@ * Returns zero on success, or -EFAULT on error. */ #define put_user(x,ptr) \ - __put_user_check((x),(ptr),sizeof(*(ptr))) + __put_user_check((x), (ptr), sizeof(*(ptr))) /* * get_user: - Get a simple variable from user space. @@ -147,7 +147,7 @@ * On error, the variable @x is set to zero. */ #define get_user(x,ptr) \ - __get_user_check((x),(ptr),sizeof(*(ptr))) + __get_user_check((x), (ptr), sizeof(*(ptr))) /* * __put_user: - Write a simple value into user space, with less checking. @@ -169,7 +169,7 @@ * Returns zero on success, or -EFAULT on error. */ #define __put_user(x,ptr) \ - __put_user_nocheck((x),(ptr),sizeof(*(ptr))) + __put_user_nocheck((x), (ptr), sizeof(*(ptr))) /* * __get_user: - Get a simple variable from user space, with less checking. @@ -192,7 +192,7 @@ * On error, the variable @x is set to zero. */ #define __get_user(x,ptr) \ - __get_user_nocheck((x),(ptr),sizeof(*(ptr))) + __get_user_nocheck((x), (ptr), sizeof(*(ptr))) struct __large_struct { unsigned long buf[100]; }; #define __m(x) (*(struct __large_struct __user *)(x)) @@ -221,7 +221,7 @@ do { \ } \ } while (0) -#define __get_user_nocheck(x,ptr,size) \ +#define __get_user_nocheck(x, ptr, size) \ ({ \ long __gu_err; \ \ @@ -229,7 +229,7 @@ do { \ __gu_err; \ }) -#define __get_user_check(x,ptr,size) \ +#define __get_user_check(x, ptr, size) \ ({ \ long __gu_err = -EFAULT; \ const __typeof__(*(ptr)) __user * __gu_ptr = (ptr); \ @@ -300,7 +300,7 @@ do { \ #define __PUT_USER_DW(ptr) __put_user_asm("sd", ptr) #endif -#define __put_user_nocheck(x,ptr,size) \ +#define __put_user_nocheck(x, ptr, size) \ ({ \ __typeof__(*(ptr)) __pu_val; \ long __pu_err = 0; \ @@ -316,7 +316,7 @@ do { \ __pu_err; \ }) -#define __put_user_check(x,ptr,size) \ +#define __put_user_check(x, ptr, size) \ ({ \ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ __typeof__(*(ptr)) __pu_val = (x); \ @@ -389,7 +389,7 @@ extern void __put_user_unknown(void); extern size_t __copy_user(void *__to, const void *__from, size_t __n); -#define __invoke_copy_to_user(to,from,n) \ +#define __invoke_copy_to_user(to, from, n) \ ({ \ register void __user *__cu_to_r __asm__("$4"); \ register const void *__cu_from_r __asm__("$5"); \ @@ -421,7 +421,7 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n); * Returns number of bytes that could not be copied. * On success, this will be zero. */ -#define __copy_to_user(to,from,n) \ +#define __copy_to_user(to, from, n) \ ({ \ void __user *__cu_to; \ const void *__cu_from; \ @@ -437,7 +437,7 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n); extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); -#define __copy_to_user_inatomic(to,from,n) \ +#define __copy_to_user_inatomic(to, from, n) \ ({ \ void __user *__cu_to; \ const void *__cu_from; \ @@ -450,7 +450,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); __cu_len; \ }) -#define __copy_from_user_inatomic(to,from,n) \ +#define __copy_from_user_inatomic(to, from, n) \ ({ \ void *__cu_to; \ const void __user *__cu_from; \ @@ -477,7 +477,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); * Returns number of bytes that could not be copied. * On success, this will be zero. */ -#define copy_to_user(to,from,n) \ +#define copy_to_user(to, from, n) \ ({ \ void __user *__cu_to; \ const void *__cu_from; \ @@ -493,7 +493,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); __cu_len; \ }) -#define __invoke_copy_from_user(to,from,n) \ +#define __invoke_copy_from_user(to, from, n) \ ({ \ register void *__cu_to_r __asm__("$4"); \ register const void __user *__cu_from_r __asm__("$5"); \ @@ -516,7 +516,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); __cu_len_r; \ }) -#define __invoke_copy_from_user_inatomic(to,from,n) \ +#define __invoke_copy_from_user_inatomic(to, from, n) \ ({ \ register void *__cu_to_r __asm__("$4"); \ register const void __user *__cu_from_r __asm__("$5"); \ @@ -556,7 +556,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); * If some data could not be copied, this function will pad the copied * data to the requested size using zero bytes. */ -#define __copy_from_user(to,from,n) \ +#define __copy_from_user(to, from, n) \ ({ \ void *__cu_to; \ const void __user *__cu_from; \ @@ -587,7 +587,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); * If some data could not be copied, this function will pad the copied * data to the requested size using zero bytes. */ -#define copy_from_user(to,from,n) \ +#define copy_from_user(to, from, n) \ ({ \ void *__cu_to; \ const void __user *__cu_from; \ @@ -605,7 +605,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); #define __copy_in_user(to, from, n) __copy_from_user(to, from, n) -#define copy_in_user(to,from,n) \ +#define copy_in_user(to, from, n) \ ({ \ void __user *__cu_to; \ const void __user *__cu_from; \ diff --git a/include/asm-mips/vga.h b/include/asm-mips/vga.h index c1dd0b10bc27..f4cff7e4fa8a 100644 --- a/include/asm-mips/vga.h +++ b/include/asm-mips/vga.h @@ -13,10 +13,10 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x,s) (0xb0000000L + (unsigned long)(x)) +#define VGA_MAP_MEM(x, s) (0xb0000000L + (unsigned long)(x)) #define vga_readb(x) (*(x)) -#define vga_writeb(x,y) (*(y) = (x)) +#define vga_writeb(x, y) (*(y) = (x)) #define VT_BUF_HAVE_RW /* diff --git a/include/asm-mips/xtalk/xtalk.h b/include/asm-mips/xtalk/xtalk.h index 4a60f27c8817..79bac882a739 100644 --- a/include/asm-mips/xtalk/xtalk.h +++ b/include/asm-mips/xtalk/xtalk.h @@ -45,7 +45,7 @@ typedef struct xtalk_piomap_s *xtalk_piomap_t; #define XIO_PACKED(x) (((x)&XIO_PORT_BITS) != 0) #define XIO_ADDR(x) ((x)&XIO_ADDR_BITS) #define XIO_PORT(x) ((xwidgetnum_t)(((x)&XIO_PORT_BITS) >> XIO_PORT_SHIFT)) -#define XIO_PACK(p,o) ((((uint64_t)(p))< Date: Wed, 14 Feb 2007 21:16:14 +0000 Subject: [PATCH 2267/2804] [MIPS] Optimize get_unaligned / put_unaligned implementations. Signed-off-by: Ralf Baechle --- include/asm-mips/unaligned.h | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/include/asm-mips/unaligned.h b/include/asm-mips/unaligned.h index a0042563838a..3249049e93aa 100644 --- a/include/asm-mips/unaligned.h +++ b/include/asm-mips/unaligned.h @@ -3,12 +3,27 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1999, 2000, 2001, 2003 by Ralf Baechle - * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. + * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) */ -#ifndef _ASM_UNALIGNED_H -#define _ASM_UNALIGNED_H +#ifndef __ASM_GENERIC_UNALIGNED_H +#define __ASM_GENERIC_UNALIGNED_H -#include +#include -#endif /* _ASM_UNALIGNED_H */ +#define get_unaligned(ptr) \ +({ \ + struct __packed { \ + typeof(*(ptr)) __v; \ + } *__p = (void *) (ptr); \ + __p->__v; \ +}) + +#define put_unaligned(val, ptr) \ +do { \ + struct __packed { \ + typeof(*(ptr)) __v; \ + } *__p = (void *) (ptr); \ + __p->__v = (val); \ +} while(0) + +#endif /* __ASM_GENERIC_UNALIGNED_H */ From 36cfbaad815908f54872a7b471e9a7a09b4084a4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:16 +0100 Subject: [PATCH 2268/2804] [MIPS] Convert list of CPU types from #define to enum. Signed-off-by: Ralf Baechle --- include/asm-mips/cpu.h | 119 +++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 70 deletions(-) diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h index 107ccbeee294..54fc18a4e5a8 100644 --- a/include/asm-mips/cpu.h +++ b/include/asm-mips/cpu.h @@ -157,76 +157,55 @@ #define FPIR_IMP_NONE 0x0000 -#define CPU_UNKNOWN 0 -#define CPU_R2000 1 -#define CPU_R3000 2 -#define CPU_R3000A 3 -#define CPU_R3041 4 -#define CPU_R3051 5 -#define CPU_R3052 6 -#define CPU_R3081 7 -#define CPU_R3081E 8 -#define CPU_R4000PC 9 -#define CPU_R4000SC 10 -#define CPU_R4000MC 11 -#define CPU_R4200 12 -#define CPU_R4400PC 13 -#define CPU_R4400SC 14 -#define CPU_R4400MC 15 -#define CPU_R4600 16 -#define CPU_R6000 17 -#define CPU_R6000A 18 -#define CPU_R8000 19 -#define CPU_R10000 20 -#define CPU_R12000 21 -#define CPU_R4300 22 -#define CPU_R4650 23 -#define CPU_R4700 24 -#define CPU_R5000 25 -#define CPU_R5000A 26 -#define CPU_R4640 27 -#define CPU_NEVADA 28 -#define CPU_RM7000 29 -#define CPU_R5432 30 -#define CPU_4KC 31 -#define CPU_5KC 32 -#define CPU_R4310 33 -#define CPU_SB1 34 -#define CPU_TX3912 35 -#define CPU_TX3922 36 -#define CPU_TX3927 37 -#define CPU_AU1000 38 -#define CPU_4KEC 39 -#define CPU_4KSC 40 -#define CPU_VR41XX 41 -#define CPU_R5500 42 -#define CPU_TX49XX 43 -#define CPU_AU1500 44 -#define CPU_20KC 45 -#define CPU_VR4111 46 -#define CPU_VR4121 47 -#define CPU_VR4122 48 -#define CPU_VR4131 49 -#define CPU_VR4181 50 -#define CPU_VR4181A 51 -#define CPU_AU1100 52 -#define CPU_SR71000 53 -#define CPU_RM9000 54 -#define CPU_25KF 55 -#define CPU_VR4133 56 -#define CPU_AU1550 57 -#define CPU_24K 58 -#define CPU_AU1200 59 -#define CPU_34K 60 -#define CPU_PR4450 61 -#define CPU_SB1A 62 -#define CPU_74K 63 -#define CPU_R14000 64 -#define CPU_LOONGSON1 65 -#define CPU_LOONGSON2 66 -#define CPU_BCM3302 67 -#define CPU_BCM4710 68 -#define CPU_LAST 68 +enum cpu_type_enum { + CPU_UNKNOWN, + + /* + * R2000 class processors + */ + CPU_R2000, CPU_R3000, CPU_R3000A, CPU_R3041, CPU_R3051, CPU_R3052, + CPU_R3081, CPU_R3081E, + + /* + * R6000 class processors + */ + CPU_R6000, CPU_R6000A, + + /* + * R4000 class processors + */ + CPU_R4000PC, CPU_R4000SC, CPU_R4000MC, CPU_R4200, CPU_R4300, CPU_R4310, + CPU_R4400PC, CPU_R4400SC, CPU_R4400MC, CPU_R4600, CPU_R4640, CPU_R4650, + CPU_R4700, CPU_R5000, CPU_R5000A, CPU_R5500, CPU_NEVADA, CPU_R5432, + CPU_R10000, CPU_R12000, CPU_R14000, CPU_VR41XX, CPU_VR4111, CPU_VR4121, + CPU_VR4122, CPU_VR4131, CPU_VR4133, CPU_VR4181, CPU_VR4181A, CPU_RM7000, + CPU_SR71000, CPU_RM9000, CPU_TX49XX, + + /* + * R8000 class processors + */ + CPU_R8000, + + /* + * TX3900 class processors + */ + CPU_TX3912, CPU_TX3922, CPU_TX3927, + + /* + * MIPS32 class processors + */ + CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_74K, CPU_AU1000, + CPU_AU1100, CPU_AU1200, CPU_AU1500, CPU_AU1550, CPU_PR4450, + CPU_BCM3302, CPU_BCM4710, + + /* + * MIPS64 class processors + */ + CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2, + + CPU_LAST +}; + /* * ISA Level encodings From 9966db25defba4e1dce263246db25237bc24479f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 11 Oct 2007 23:46:17 +0100 Subject: [PATCH 2269/2804] [MIPS] Make facility to convert CPU types to strings generally available. So far /proc/cpuinfo has been the only user but human readable processor name are more useful than that for proc. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 93 +++++++++++++++++++++++++++++++++++- arch/mips/kernel/proc.c | 75 +---------------------------- arch/mips/kernel/traps.c | 3 +- include/asm-mips/cpu-info.h | 3 ++ 4 files changed, 97 insertions(+), 77 deletions(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index dde2adf1481c..234c7f5005fb 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -802,9 +802,95 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c) } } +const char *__cpu_name[NR_CPUS]; + +/* + * Name a CPU + */ +static __init const char *cpu_to_name(struct cpuinfo_mips *c) +{ + const char *name = NULL; + + switch (c->cputype) { + case CPU_UNKNOWN: name = "unknown"; break; + case CPU_R2000: name = "R2000"; break; + case CPU_R3000: name = "R3000"; break; + case CPU_R3000A: name = "R3000A"; break; + case CPU_R3041: name = "R3041"; break; + case CPU_R3051: name = "R3051"; break; + case CPU_R3052: name = "R3052"; break; + case CPU_R3081: name = "R3081"; break; + case CPU_R3081E: name = "R3081E"; break; + case CPU_R4000PC: name = "R4000PC"; break; + case CPU_R4000SC: name = "R4000SC"; break; + case CPU_R4000MC: name = "R4000MC"; break; + case CPU_R4200: name = "R4200"; break; + case CPU_R4400PC: name = "R4400PC"; break; + case CPU_R4400SC: name = "R4400SC"; break; + case CPU_R4400MC: name = "R4400MC"; break; + case CPU_R4600: name = "R4600"; break; + case CPU_R6000: name = "R6000"; break; + case CPU_R6000A: name = "R6000A"; break; + case CPU_R8000: name = "R8000"; break; + case CPU_R10000: name = "R10000"; break; + case CPU_R12000: name = "R12000"; break; + case CPU_R14000: name = "R14000"; break; + case CPU_R4300: name = "R4300"; break; + case CPU_R4650: name = "R4650"; break; + case CPU_R4700: name = "R4700"; break; + case CPU_R5000: name = "R5000"; break; + case CPU_R5000A: name = "R5000A"; break; + case CPU_R4640: name = "R4640"; break; + case CPU_NEVADA: name = "Nevada"; break; + case CPU_RM7000: name = "RM7000"; break; + case CPU_RM9000: name = "RM9000"; break; + case CPU_R5432: name = "R5432"; break; + case CPU_4KC: name = "MIPS 4Kc"; break; + case CPU_5KC: name = "MIPS 5Kc"; break; + case CPU_R4310: name = "R4310"; break; + case CPU_SB1: name = "SiByte SB1"; break; + case CPU_SB1A: name = "SiByte SB1A"; break; + case CPU_TX3912: name = "TX3912"; break; + case CPU_TX3922: name = "TX3922"; break; + case CPU_TX3927: name = "TX3927"; break; + case CPU_AU1000: name = "Au1000"; break; + case CPU_AU1500: name = "Au1500"; break; + case CPU_AU1100: name = "Au1100"; break; + case CPU_AU1550: name = "Au1550"; break; + case CPU_AU1200: name = "Au1200"; break; + case CPU_4KEC: name = "MIPS 4KEc"; break; + case CPU_4KSC: name = "MIPS 4KSc"; break; + case CPU_VR41XX: name = "NEC Vr41xx"; break; + case CPU_R5500: name = "R5500"; break; + case CPU_TX49XX: name = "TX49xx"; break; + case CPU_20KC: name = "MIPS 20Kc"; break; + case CPU_24K: name = "MIPS 24K"; break; + case CPU_25KF: name = "MIPS 25Kf"; break; + case CPU_34K: name = "MIPS 34K"; break; + case CPU_74K: name = "MIPS 74K"; break; + case CPU_VR4111: name = "NEC VR4111"; break; + case CPU_VR4121: name = "NEC VR4121"; break; + case CPU_VR4122: name = "NEC VR4122"; break; + case CPU_VR4131: name = "NEC VR4131"; break; + case CPU_VR4133: name = "NEC VR4133"; break; + case CPU_VR4181: name = "NEC VR4181"; break; + case CPU_VR4181A: name = "NEC VR4181A"; break; + case CPU_SR71000: name = "Sandcraft SR71000"; break; + case CPU_BCM3302: name = "Broadcom BCM3302"; break; + case CPU_BCM4710: name = "Broadcom BCM4710"; break; + case CPU_PR4450: name = "Philips PR4450"; break; + case CPU_LOONGSON2: name = "ICT Loongson-2"; break; + default: + BUG(); + } + + return name; +} + __init void cpu_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int cpu = smp_processor_id(); c->processor_id = PRID_IMP_UNKNOWN; c->fpu_id = FPIR_IMP_NONE; @@ -847,13 +933,16 @@ __init void cpu_probe(void) c->ases |= MIPS_ASE_MIPS3D; } } + + __cpu_name[cpu] = cpu_to_name(c); } __init void cpu_report(void) { struct cpuinfo_mips *c = ¤t_cpu_data; - printk("CPU revision is: %08x\n", c->processor_id); + printk(KERN_INFO "CPU revision is: %08x (%s)\n", + c->processor_id, cpu_name_string()); if (c->options & MIPS_CPU_FPU) - printk("FPU revision is: %08x\n", c->fpu_id); + printk(KERN_INFO "FPU revision is: %08x\n", c->fpu_id); } diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index accd5201d0e1..efd2d1314123 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -17,78 +17,6 @@ unsigned int vced_count, vcei_count; -static const char *cpu_name[] = { - [CPU_UNKNOWN] = "unknown", - [CPU_R2000] = "R2000", - [CPU_R3000] = "R3000", - [CPU_R3000A] = "R3000A", - [CPU_R3041] = "R3041", - [CPU_R3051] = "R3051", - [CPU_R3052] = "R3052", - [CPU_R3081] = "R3081", - [CPU_R3081E] = "R3081E", - [CPU_R4000PC] = "R4000PC", - [CPU_R4000SC] = "R4000SC", - [CPU_R4000MC] = "R4000MC", - [CPU_R4200] = "R4200", - [CPU_R4400PC] = "R4400PC", - [CPU_R4400SC] = "R4400SC", - [CPU_R4400MC] = "R4400MC", - [CPU_R4600] = "R4600", - [CPU_R6000] = "R6000", - [CPU_R6000A] = "R6000A", - [CPU_R8000] = "R8000", - [CPU_R10000] = "R10000", - [CPU_R12000] = "R12000", - [CPU_R14000] = "R14000", - [CPU_R4300] = "R4300", - [CPU_R4650] = "R4650", - [CPU_R4700] = "R4700", - [CPU_R5000] = "R5000", - [CPU_R5000A] = "R5000A", - [CPU_R4640] = "R4640", - [CPU_NEVADA] = "Nevada", - [CPU_RM7000] = "RM7000", - [CPU_RM9000] = "RM9000", - [CPU_R5432] = "R5432", - [CPU_4KC] = "MIPS 4Kc", - [CPU_5KC] = "MIPS 5Kc", - [CPU_R4310] = "R4310", - [CPU_SB1] = "SiByte SB1", - [CPU_SB1A] = "SiByte SB1A", - [CPU_TX3912] = "TX3912", - [CPU_TX3922] = "TX3922", - [CPU_TX3927] = "TX3927", - [CPU_AU1000] = "Au1000", - [CPU_AU1500] = "Au1500", - [CPU_AU1100] = "Au1100", - [CPU_AU1550] = "Au1550", - [CPU_AU1200] = "Au1200", - [CPU_4KEC] = "MIPS 4KEc", - [CPU_4KSC] = "MIPS 4KSc", - [CPU_VR41XX] = "NEC Vr41xx", - [CPU_R5500] = "R5500", - [CPU_TX49XX] = "TX49xx", - [CPU_20KC] = "MIPS 20Kc", - [CPU_24K] = "MIPS 24K", - [CPU_25KF] = "MIPS 25Kf", - [CPU_34K] = "MIPS 34K", - [CPU_74K] = "MIPS 74K", - [CPU_VR4111] = "NEC VR4111", - [CPU_VR4121] = "NEC VR4121", - [CPU_VR4122] = "NEC VR4122", - [CPU_VR4131] = "NEC VR4131", - [CPU_VR4133] = "NEC VR4133", - [CPU_VR4181] = "NEC VR4181", - [CPU_VR4181A] = "NEC VR4181A", - [CPU_SR71000] = "Sandcraft SR71000", - [CPU_BCM3302] = "Broadcom BCM3302", - [CPU_BCM4710] = "Broadcom BCM4710", - [CPU_PR4450] = "Philips PR4450", - [CPU_LOONGSON2] = "ICT Loongson-2", -}; - - static int show_cpuinfo(struct seq_file *m, void *v) { unsigned long n = (unsigned long) v - 1; @@ -110,8 +38,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t\t: %ld\n", n); sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); - seq_printf(m, fmt, cpu_name[cpu_data[n].cputype <= CPU_LAST ? - cpu_data[n].cputype : CPU_UNKNOWN], + seq_printf(m, fmt, __cpu_name[smp_processor_id()], (version >> 4) & 0x0f, version & 0x0f, (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b3e408b54c24..632bce1bf420 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -295,7 +295,8 @@ void show_regs(struct pt_regs *regs) if (1 <= cause && cause <= 5) printk("BadVA : %0*lx\n", field, regs->cp0_badvaddr); - printk("PrId : %08x\n", read_c0_prid()); + printk("PrId : %08x (%s)\n", read_c0_prid(), + cpu_name_string()); } void show_registers(struct pt_regs *regs) diff --git a/include/asm-mips/cpu-info.h b/include/asm-mips/cpu-info.h index 04689590eeed..94f1c8172360 100644 --- a/include/asm-mips/cpu-info.h +++ b/include/asm-mips/cpu-info.h @@ -74,4 +74,7 @@ extern struct cpuinfo_mips cpu_data[]; extern void cpu_probe(void); extern void cpu_report(void); +extern const char *__cpu_name[]; +#define cpu_name_string() __cpu_name[smp_processor_id()] + #endif /* __ASM_CPU_INFO_H */ From bd6aeeffcc0be716e4d2d1f27fb132741e345cc0 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 Oct 2007 01:24:16 +0100 Subject: [PATCH 2270/2804] [MIPS] SMP: Implement smp_call_function_mask(). Signed-off-by: Ralf Baechle --- arch/mips/kernel/gdb-stub.c | 10 ++++---- arch/mips/kernel/smp.c | 51 ++++++++++++------------------------- include/asm-mips/smp.h | 9 +++++++ 3 files changed, 30 insertions(+), 40 deletions(-) diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index c33f6f22d86a..bd128fab4b36 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -676,15 +676,18 @@ static void kgdb_wait(void *arg) static int kgdb_smp_call_kgdb_wait(void) { #ifdef CONFIG_SMP + cpumask_t mask = cpu_online_map; struct call_data_struct data; - int i, cpus = num_online_cpus() - 1; int cpu = smp_processor_id(); + int cpus; /* * Can die spectacularly if this CPU isn't yet marked online */ BUG_ON(!cpu_online(cpu)); + cpu_clear(cpu, mask); + cpus = cpus_weight(mask); if (!cpus) return 0; @@ -711,10 +714,7 @@ static int kgdb_smp_call_kgdb_wait(void) call_data = &data; mb(); - /* Send a message to all other CPUs and wait for them to respond */ - for (i = 0; i < NR_CPUS; i++) - if (cpu_online(i) && i != cpu) - core_send_ipi(i, SMP_CALL_FUNCTION); + core_send_ipi_mask(mask, SMP_CALL_FUNCTION); /* Wait for response */ /* FIXME: lock-up detection, backtrace on lock-up */ diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 500a7ec2880f..481ba5355dcb 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -97,6 +97,8 @@ struct call_data_struct *call_data; /* * Run a function on all other CPUs. + * + * cpuset_t of all processors to run the function on. * The function to run. This must be fast and non-blocking. * An arbitrary pointer to pass to the function. * If true, keep retrying until ready. @@ -121,18 +123,20 @@ struct call_data_struct *call_data; * Spin waiting for call_lock * Deadlock Deadlock */ -int smp_call_function (void (*func) (void *info), void *info, int retry, - int wait) +int smp_call_function_mask(cpumask_t mask, void (*func) (void *info), + void *info, int retry, int wait) { struct call_data_struct data; - int i, cpus = num_online_cpus() - 1; int cpu = smp_processor_id(); + int cpus; /* * Can die spectacularly if this CPU isn't yet marked online */ BUG_ON(!cpu_online(cpu)); + cpu_clear(cpu, mask); + cpus = cpus_weight(mask); if (!cpus) return 0; @@ -151,9 +155,7 @@ int smp_call_function (void (*func) (void *info), void *info, int retry, smp_mb(); /* Send a message to all other CPUs and wait for them to respond */ - for_each_online_cpu(i) - if (i != cpu) - core_send_ipi(i, SMP_CALL_FUNCTION); + core_send_ipi_mask(mask, SMP_CALL_FUNCTION); /* Wait for response */ /* FIXME: lock-up detection, backtrace on lock-up */ @@ -169,6 +171,11 @@ int smp_call_function (void (*func) (void *info), void *info, int retry, return 0; } +int smp_call_function(void (*func) (void *info), void *info, int retry, + int wait) +{ + return smp_call_function_mask(cpu_online_map, func, info, retry, wait); +} void smp_call_function_interrupt(void) { @@ -199,8 +206,7 @@ void smp_call_function_interrupt(void) int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int retry, int wait) { - struct call_data_struct data; - int me; + int ret, me; /* * Can die spectacularly if this CPU isn't yet marked online @@ -219,33 +225,8 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, return 0; } - /* Can deadlock when called with interrupts disabled */ - WARN_ON(irqs_disabled()); - - data.func = func; - data.info = info; - atomic_set(&data.started, 0); - data.wait = wait; - if (wait) - atomic_set(&data.finished, 0); - - spin_lock(&smp_call_lock); - call_data = &data; - smp_mb(); - - /* Send a message to the other CPU */ - core_send_ipi(cpu, SMP_CALL_FUNCTION); - - /* Wait for response */ - /* FIXME: lock-up detection, backtrace on lock-up */ - while (atomic_read(&data.started) != 1) - barrier(); - - if (wait) - while (atomic_read(&data.finished) != 1) - barrier(); - call_data = NULL; - spin_unlock(&smp_call_lock); + ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, retry, + wait); put_cpu(); return 0; diff --git a/include/asm-mips/smp.h b/include/asm-mips/smp.h index 13aef6af422c..dc770025a9b0 100644 --- a/include/asm-mips/smp.h +++ b/include/asm-mips/smp.h @@ -60,6 +60,15 @@ extern cpumask_t phys_cpu_present_map; */ extern void core_send_ipi(int cpu, unsigned int action); +static inline void core_send_ipi_mask(cpumask_t mask, unsigned int action) +{ + unsigned int i; + + for_each_cpu_mask(i, mask) + core_send_ipi(i, action); +} + + /* * Firmware CPU startup hook */ From b5eb551145395382ddf302548991a5fbaabc5341 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 Oct 2007 19:16:57 +0100 Subject: [PATCH 2271/2804] [MIPS] Kill num_online_cpus() loops. Signed-off-by: Ralf Baechle --- arch/mips/kernel/gdb-stub.c | 4 ++-- arch/mips/kernel/smp.c | 33 +++++++++++++++++++++------------ arch/mips/kernel/smtc.c | 4 ++-- include/asm-mips/mmu_context.h | 4 ++-- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index bd128fab4b36..3191afa29ad8 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -769,7 +769,7 @@ void handle_exception(struct gdb_regs *regs) /* * acquire the CPU spinlocks */ - for (i = num_online_cpus()-1; i >= 0; i--) + for_each_online_cpu(i) if (__raw_spin_trylock(&kgdb_cpulock[i]) == 0) panic("kgdb: couldn't get cpulock %d\n", i); @@ -1044,7 +1044,7 @@ finish_kgdb: exit_kgdb_exception: /* release locks so other CPUs can go */ - for (i = num_online_cpus()-1; i >= 0; i--) + for_each_online_cpu(i) __raw_spin_unlock(&kgdb_cpulock[i]); spin_unlock(&kgdb_lock); diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 481ba5355dcb..5ca3809a1b45 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -375,10 +375,13 @@ void flush_tlb_mm(struct mm_struct *mm) if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { smp_on_other_tlbs(flush_tlb_mm_ipi, (void *)mm); } else { - int i; - for (i = 0; i < num_online_cpus(); i++) - if (smp_processor_id() != i) - cpu_context(i, mm) = 0; + cpumask_t mask = cpu_online_map; + unsigned int cpu; + + cpu_clear(smp_processor_id(), mask); + for_each_online_cpu(cpu) + if (cpu_context(cpu, mm)) + cpu_context(cpu, mm) = 0; } local_flush_tlb_mm(mm); @@ -411,10 +414,13 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l fd.addr2 = end; smp_on_other_tlbs(flush_tlb_range_ipi, (void *)&fd); } else { - int i; - for (i = 0; i < num_online_cpus(); i++) - if (smp_processor_id() != i) - cpu_context(i, mm) = 0; + cpumask_t mask = cpu_online_map; + unsigned int cpu; + + cpu_clear(smp_processor_id(), mask); + for_each_online_cpu(cpu) + if (cpu_context(cpu, mm)) + cpu_context(cpu, mm) = 0; } local_flush_tlb_range(vma, start, end); preempt_enable(); @@ -453,10 +459,13 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) fd.addr1 = page; smp_on_other_tlbs(flush_tlb_page_ipi, (void *)&fd); } else { - int i; - for (i = 0; i < num_online_cpus(); i++) - if (smp_processor_id() != i) - cpu_context(i, vma->vm_mm) = 0; + cpumask_t mask = cpu_online_map; + unsigned int cpu; + + cpu_clear(smp_processor_id(), mask); + for_each_online_cpu(cpu) + if (cpu_context(cpu, vma->vm_mm)) + cpu_context(cpu, vma->vm_mm) = 0; } local_flush_tlb_page(vma, page); preempt_enable(); diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 4d91e2f455c0..a8c1a698d588 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -1264,7 +1264,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) if (cpu_has_vtag_icache) flush_icache_all(); /* Traverse all online CPUs (hack requires contigous range) */ - for (i = 0; i < num_online_cpus(); i++) { + for_each_online_cpu(i) { /* * We don't need to worry about our own CPU, nor those of * CPUs who don't share our TLB. @@ -1293,7 +1293,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) /* * SMTC shares the TLB within VPEs and possibly across all VPEs. */ - for (i = 0; i < num_online_cpus(); i++) { + for_each_online_cpu(i) { if ((smtc_status & SMTC_TLB_SHARED) || (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id)) cpu_context(i, mm) = asid_cache(i) = asid; diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h index b3b7a689e7d3..0c4f245eaeb2 100644 --- a/include/asm-mips/mmu_context.h +++ b/include/asm-mips/mmu_context.h @@ -120,7 +120,7 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) { int i; - for (i = 0; i < num_online_cpus(); i++) + for_each_online_cpu(i) cpu_context(i, mm) = 0; return 0; @@ -284,7 +284,7 @@ drop_mmu_context(struct mm_struct *mm, unsigned cpu) int i; /* SMTC shares the TLB (and ASIDs) across VPEs */ - for (i = 0; i < num_online_cpus(); i++) { + for_each_online_cpu(i) { if((smtc_status & SMTC_TLB_SHARED) || (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id)) cpu_context(i, mm) = 0; From c50cade95b075e1116fc4fae6a9c63829720efb9 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 4 Oct 2007 16:57:08 +0100 Subject: [PATCH 2272/2804] [MIPS] SMP: Kill useless casts. Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 5ca3809a1b45..54464fd36198 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -373,7 +373,7 @@ void flush_tlb_mm(struct mm_struct *mm) preempt_disable(); if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { - smp_on_other_tlbs(flush_tlb_mm_ipi, (void *)mm); + smp_on_other_tlbs(flush_tlb_mm_ipi, mm); } else { cpumask_t mask = cpu_online_map; unsigned int cpu; @@ -396,7 +396,7 @@ struct flush_tlb_data { static void flush_tlb_range_ipi(void *info) { - struct flush_tlb_data *fd = (struct flush_tlb_data *)info; + struct flush_tlb_data *fd = info; local_flush_tlb_range(fd->vma, fd->addr1, fd->addr2); } @@ -412,7 +412,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l fd.vma = vma; fd.addr1 = start; fd.addr2 = end; - smp_on_other_tlbs(flush_tlb_range_ipi, (void *)&fd); + smp_on_other_tlbs(flush_tlb_range_ipi, &fd); } else { cpumask_t mask = cpu_online_map; unsigned int cpu; @@ -428,7 +428,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l static void flush_tlb_kernel_range_ipi(void *info) { - struct flush_tlb_data *fd = (struct flush_tlb_data *)info; + struct flush_tlb_data *fd = info; local_flush_tlb_kernel_range(fd->addr1, fd->addr2); } @@ -439,12 +439,12 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end) fd.addr1 = start; fd.addr2 = end; - on_each_cpu(flush_tlb_kernel_range_ipi, (void *)&fd, 1, 1); + on_each_cpu(flush_tlb_kernel_range_ipi, &fd, 1, 1); } static void flush_tlb_page_ipi(void *info) { - struct flush_tlb_data *fd = (struct flush_tlb_data *)info; + struct flush_tlb_data *fd = info; local_flush_tlb_page(fd->vma, fd->addr1); } @@ -457,7 +457,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) fd.vma = vma; fd.addr1 = page; - smp_on_other_tlbs(flush_tlb_page_ipi, (void *)&fd); + smp_on_other_tlbs(flush_tlb_page_ipi, &fd); } else { cpumask_t mask = cpu_online_map; unsigned int cpu; From 89a8a5a6c965d3dd2571a263ef59e7b23a036d5e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 4 Oct 2007 18:18:52 +0100 Subject: [PATCH 2273/2804] [MIPS] SMP: Use ISO C struct initializer for local structs. Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 54464fd36198..432f2e376aea 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -407,11 +407,12 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l preempt_disable(); if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) { - struct flush_tlb_data fd; + struct flush_tlb_data fd = { + .vma = vma, + .addr1 = start, + .addr2 = end, + }; - fd.vma = vma; - fd.addr1 = start; - fd.addr2 = end; smp_on_other_tlbs(flush_tlb_range_ipi, &fd); } else { cpumask_t mask = cpu_online_map; @@ -435,10 +436,11 @@ static void flush_tlb_kernel_range_ipi(void *info) void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - struct flush_tlb_data fd; + struct flush_tlb_data fd = { + .addr1 = start, + .addr2 = end, + }; - fd.addr1 = start; - fd.addr2 = end; on_each_cpu(flush_tlb_kernel_range_ipi, &fd, 1, 1); } @@ -453,10 +455,11 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { preempt_disable(); if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) { - struct flush_tlb_data fd; + struct flush_tlb_data fd = { + .vma = vma, + .addr1 = page, + }; - fd.vma = vma; - fd.addr1 = page; smp_on_other_tlbs(flush_tlb_page_ipi, &fd); } else { cpumask_t mask = cpu_online_map; From dec8b1ca990055f3a8954ac3bc98fdb785af52e4 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Mon, 8 Oct 2007 16:11:51 +0200 Subject: [PATCH 2274/2804] [MIPS] Add BUG_ON assertion for attempt to run kernel on the wrong CPU type. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 234c7f5005fb..c8c47a2d1972 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -922,6 +922,14 @@ __init void cpu_probe(void) default: c->cputype = CPU_UNKNOWN; } + + /* + * Platform code can force the cpu type to optimize code + * generation. In that case be sure the cpu type is correctly + * manually setup otherwise it could trigger some nasty bugs. + */ + BUG_ON(current_cpu_type() != c->cputype); + if (c->options & MIPS_CPU_FPU) { c->fpu_id = cpu_get_fpu_id(); From 4b92fe2309c762d9ba9201a16f20d6d167e641b3 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Wed, 10 Oct 2007 00:28:26 +0900 Subject: [PATCH 2275/2804] [MIPS] cleanup WRPPMC include files Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/gt64120/wrppmc/irq.c | 23 +++++------------------ arch/mips/gt64120/wrppmc/pci.c | 3 ++- arch/mips/gt64120/wrppmc/reset.c | 10 +++------- arch/mips/gt64120/wrppmc/time.c | 11 ++--------- 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c index 06177bf5b1d6..c6e706274db4 100644 --- a/arch/mips/gt64120/wrppmc/irq.c +++ b/arch/mips/gt64120/wrppmc/irq.c @@ -9,26 +9,13 @@ * 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 + #include +#include +#include asmlinkage void plat_irq_dispatch(void) { diff --git a/arch/mips/gt64120/wrppmc/pci.c b/arch/mips/gt64120/wrppmc/pci.c index 0d5289bc1804..d06192faeb7c 100644 --- a/arch/mips/gt64120/wrppmc/pci.c +++ b/arch/mips/gt64120/wrppmc/pci.c @@ -8,9 +8,10 @@ * for more details. */ #include +#include #include #include -#include + #include extern struct pci_ops gt64xxx_pci0_ops; diff --git a/arch/mips/gt64120/wrppmc/reset.c b/arch/mips/gt64120/wrppmc/reset.c index b97039c6d3db..c355cff38f6c 100644 --- a/arch/mips/gt64120/wrppmc/reset.c +++ b/arch/mips/gt64120/wrppmc/reset.c @@ -5,14 +5,10 @@ * * Copyright (C) 1997 Ralf Baechle */ -#include -#include -#include -#include -#include -#include -#include +#include + #include +#include void wrppmc_machine_restart(char *command) { diff --git a/arch/mips/gt64120/wrppmc/time.c b/arch/mips/gt64120/wrppmc/time.c index faf164e7e0df..b207e7f1417a 100644 --- a/arch/mips/gt64120/wrppmc/time.c +++ b/arch/mips/gt64120/wrppmc/time.c @@ -11,18 +11,11 @@ * Copyright (C) 2006, Wind River System Inc. */ #include -#include -#include -#include /* for HZ */ -#include -#include #include +#include -#include -#include -#include -#include #include +#include #define WRPPMC_CPU_CLK_FREQ 40000000 /* 40MHZ */ From bdf5d42c6e4d7aa56251b8899f60f55a88c0aaa7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 10 Oct 2007 13:33:03 +0100 Subject: [PATCH 2276/2804] [MIPS] VPE: reimplement ELF loader. Loading ELF binaries based on the section table is totally wrong. This still leaves the other fat bug of referencing symbols in an executable unfixed, so people better don't run strip on their binaries ... As added bonus the new loader is also 23 lines shorter. Signed-off-by: Ralf Baechle --- arch/mips/kernel/vpe.c | 45 +++++++++++------------------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 45077c4b2e22..61b729fa0548 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -936,8 +936,18 @@ static int vpe_elfload(struct vpe * v) } } else { - for (i = 0; i < hdr->e_shnum; i++) { + struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff); + for (i = 0; i < hdr->e_phnum; i++) { + if (phdr->p_type != PT_LOAD) + continue; + + memcpy((void *)phdr->p_vaddr, (char *)hdr + phdr->p_offset, phdr->p_filesz); + memset((void *)phdr->p_vaddr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + phdr++; + } + + for (i = 0; i < hdr->e_shnum; i++) { /* Internal symbols and strings. */ if (sechdrs[i].sh_type == SHT_SYMTAB) { symindex = i; @@ -948,39 +958,6 @@ static int vpe_elfload(struct vpe * v) magic symbols */ sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; } - - /* filter sections we dont want in the final image */ - if (!(sechdrs[i].sh_flags & SHF_ALLOC) || - (sechdrs[i].sh_type == SHT_MIPS_REGINFO)) { - printk( KERN_DEBUG " ignoring section, " - "name %s type %x address 0x%x \n", - secstrings + sechdrs[i].sh_name, - sechdrs[i].sh_type, sechdrs[i].sh_addr); - continue; - } - - if (sechdrs[i].sh_addr < (unsigned int)v->load_addr) { - printk( KERN_WARNING "VPE loader: " - "fully linked image has invalid section, " - "name %s type %x address 0x%x, before load " - "address of 0x%x\n", - secstrings + sechdrs[i].sh_name, - sechdrs[i].sh_type, sechdrs[i].sh_addr, - (unsigned int)v->load_addr); - return -ENOEXEC; - } - - printk(KERN_DEBUG " copying section sh_name %s, sh_addr 0x%x " - "size 0x%x0 from x%p\n", - secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr, - sechdrs[i].sh_size, hdr + sechdrs[i].sh_offset); - - if (sechdrs[i].sh_type != SHT_NOBITS) - memcpy((void *)sechdrs[i].sh_addr, - (char *)hdr + sechdrs[i].sh_offset, - sechdrs[i].sh_size); - else - memset((void *)sechdrs[i].sh_addr, 0, sechdrs[i].sh_size); } } From 572afc248c33c902760f6f24a72c180f0e4f1719 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 21 Sep 2007 13:05:44 +0100 Subject: [PATCH 2277/2804] [MIPS] R1: Fix hazard barriers to make kernels work on R2 also. Tested with Malta; inflates malta_defconfig by 3932 bytes. Ideally there should be additional configuration to allow getting rid of this overhead but that would be too much complexity at this stage of the release cycle. Signed-off-by: Ralf Baechle --- include/asm-mips/hazards.h | 54 +++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/include/asm-mips/hazards.h b/include/asm-mips/hazards.h index 7e843b5fee92..2de638f84c86 100644 --- a/include/asm-mips/hazards.h +++ b/include/asm-mips/hazards.h @@ -10,11 +10,12 @@ #ifndef _ASM_HAZARDS_H #define _ASM_HAZARDS_H - #ifdef __ASSEMBLY__ #define ASMMACRO(name, code...) .macro name; code; .endm #else +#include + #define ASMMACRO(name, code...) \ __asm__(".macro " #name "; " #code "; .endm"); \ \ @@ -86,6 +87,57 @@ do { \ : "=r" (tmp)); \ } while (0) +#elif defined(CONFIG_CPU_MIPSR1) + +/* + * These are slightly complicated by the fact that we guarantee R1 kernels to + * run fine on R2 processors. + */ +ASMMACRO(mtc0_tlbw_hazard, + _ssnop; _ssnop; _ehb + ) +ASMMACRO(tlbw_use_hazard, + _ssnop; _ssnop; _ssnop; _ehb + ) +ASMMACRO(tlb_probe_hazard, + _ssnop; _ssnop; _ssnop; _ehb + ) +ASMMACRO(irq_enable_hazard, + _ssnop; _ssnop; _ssnop; _ehb + ) +ASMMACRO(irq_disable_hazard, + _ssnop; _ssnop; _ssnop; _ehb + ) +ASMMACRO(back_to_back_c0_hazard, + _ssnop; _ssnop; _ssnop; _ehb + ) +/* + * gcc has a tradition of misscompiling the previous construct using the + * address of a label as argument to inline assembler. Gas otoh has the + * annoying difference between la and dla which are only usable for 32-bit + * rsp. 64-bit code, so can't be used without conditional compilation. + * The alterantive is switching the assembler to 64-bit code which happens + * to work right even for 32-bit code ... + */ +#define __instruction_hazard() \ +do { \ + unsigned long tmp; \ + \ + __asm__ __volatile__( \ + " .set mips64r2 \n" \ + " dla %0, 1f \n" \ + " jr.hb %0 \n" \ + " .set mips0 \n" \ + "1: \n" \ + : "=r" (tmp)); \ +} while (0) + +#define instruction_hazard() \ +do { \ + if (cpu_has_mips_r2) \ + __instruction_hazard(); \ +} while (0) + #elif defined(CONFIG_CPU_R10000) /* From 2c4d13570d8e512cca65d159502622e1666ad4bd Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 11 Oct 2007 22:54:13 +0900 Subject: [PATCH 2278/2804] [MIPS] WRPPMC serial support move to platform device Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- arch/mips/gt64120/wrppmc/Makefile | 2 +- arch/mips/gt64120/wrppmc/serial.c | 80 +++++++++++++++++++++++++++++++ arch/mips/gt64120/wrppmc/setup.c | 34 ------------- 3 files changed, 81 insertions(+), 35 deletions(-) create mode 100644 arch/mips/gt64120/wrppmc/serial.c diff --git a/arch/mips/gt64120/wrppmc/Makefile b/arch/mips/gt64120/wrppmc/Makefile index bef15c90ae15..b49d282bee8a 100644 --- a/arch/mips/gt64120/wrppmc/Makefile +++ b/arch/mips/gt64120/wrppmc/Makefile @@ -9,6 +9,6 @@ # Makefile for the Wind River MIPS 4KC PPMC Eval Board # -obj-y += irq.o reset.o setup.o time.o pci.o +obj-y += irq.o pci.o reset.o serial.o setup.o time.o EXTRA_CFLAGS += -Werror diff --git a/arch/mips/gt64120/wrppmc/serial.c b/arch/mips/gt64120/wrppmc/serial.c new file mode 100644 index 000000000000..5ec1c2ffd3a5 --- /dev/null +++ b/arch/mips/gt64120/wrppmc/serial.c @@ -0,0 +1,80 @@ +/* + * Registration of WRPPMC UART platform device. + * + * Copyright (C) 2007 Yoichi Yuasa + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include + +#include + +static struct resource wrppmc_uart_resource[] __initdata = { + { + .start = WRPPMC_UART16550_BASE, + .end = WRPPMC_UART16550_BASE + 7, + .flags = IORESOURCE_MEM, + }, + { + .start = WRPPMC_UART16550_IRQ, + .end = WRPPMC_UART16550_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct plat_serial8250_port wrppmc_serial8250_port[] = { + { + .irq = WRPPMC_UART16550_IRQ, + .uartclk = WRPPMC_UART16550_CLOCK, + .iotype = UPIO_MEM, + .flags = UPF_IOREMAP | UPF_SKIP_TEST, + .mapbase = WRPPMC_UART16550_BASE, + }, + {}, +}; + +static __init int wrppmc_uart_add(void) +{ + struct platform_device *pdev; + int retval; + + pdev = platform_device_alloc("serial8250", -1); + if (!pdev) + return -ENOMEM; + + pdev->id = PLAT8250_DEV_PLATFORM; + pdev->dev.platform_data = wrppmc_serial8250_port; + + retval = platform_device_add_resources(pdev, wrppmc_uart_resource, + ARRAY_SIZE(wrppmc_uart_resource)); + if (retval) + goto err_free_device; + + retval = platform_device_add(pdev); + if (retval) + goto err_free_device; + + return 0; + +err_free_device: + platform_device_put(pdev); + + return retval; +} +device_initcall(wrppmc_uart_add); diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c index f2ccf101e6d9..51f6b7862460 100644 --- a/arch/mips/gt64120/wrppmc/setup.c +++ b/arch/mips/gt64120/wrppmc/setup.c @@ -11,10 +11,6 @@ #include #include #include -#include -#include -#include -#include #include #include @@ -98,32 +94,6 @@ void __init prom_free_prom_memory(void) { } -#ifdef CONFIG_SERIAL_8250 -static void wrppmc_setup_serial(void) -{ - struct uart_port up; - - memset(&up, 0x00, sizeof(struct uart_port)); - - /* - * A note about mapbase/membase - * -) mapbase is the physical address of the IO port. - * -) membase is an 'ioremapped' cookie. - */ - up.line = 0; - up.type = PORT_16550; - up.iotype = UPIO_MEM; - up.mapbase = WRPPMC_UART16550_BASE; - up.membase = ioremap(up.mapbase, 8); - up.irq = WRPPMC_UART16550_IRQ; - up.uartclk = WRPPMC_UART16550_CLOCK; - up.flags = UPF_SKIP_TEST/* | UPF_BOOT_AUTOCONF */; - up.regshift = 0; - - early_serial_setup(&up); -} -#endif - void __init plat_mem_setup(void) { extern void wrppmc_machine_restart(char *command); @@ -138,10 +108,6 @@ void __init plat_mem_setup(void) * physical address ( < KSEG0) can work via KSEG1 */ set_io_port_base(KSEG1); - -#ifdef CONFIG_SERIAL_8250 - wrppmc_setup_serial(); -#endif } const char *get_system_type(void) From aaf76a3245c02faba51c96b9a340c14d6bb0dcc0 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Tue, 9 Oct 2007 22:34:26 +0200 Subject: [PATCH 2279/2804] [MIPS] tlbex.c: Cleanup __init usage. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/mm/tlbex.c | 96 ++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index a61246d3533d..01b0961acfb6 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -66,7 +66,7 @@ static inline int __maybe_unused r10000_llsc_war(void) * why; it's not an issue caused by the core RTL. * */ -static __init int __attribute__((unused)) m4kc_tlbp_war(void) +static int __init m4kc_tlbp_war(void) { return (current_cpu_data.processor_id & 0xffff00) == (PRID_COMP_MIPS | PRID_IMP_4KC); @@ -140,7 +140,7 @@ struct insn { | (e) << RE_SH \ | (f) << FUNC_SH) -static __initdata struct insn insn_table[] = { +static struct insn insn_table[] __initdata = { { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD }, { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD }, @@ -193,7 +193,7 @@ static __initdata struct insn insn_table[] = { #undef M -static __init u32 build_rs(u32 arg) +static u32 __init build_rs(u32 arg) { if (arg & ~RS_MASK) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -201,7 +201,7 @@ static __init u32 build_rs(u32 arg) return (arg & RS_MASK) << RS_SH; } -static __init u32 build_rt(u32 arg) +static u32 __init build_rt(u32 arg) { if (arg & ~RT_MASK) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -209,7 +209,7 @@ static __init u32 build_rt(u32 arg) return (arg & RT_MASK) << RT_SH; } -static __init u32 build_rd(u32 arg) +static u32 __init build_rd(u32 arg) { if (arg & ~RD_MASK) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -217,7 +217,7 @@ static __init u32 build_rd(u32 arg) return (arg & RD_MASK) << RD_SH; } -static __init u32 build_re(u32 arg) +static u32 __init build_re(u32 arg) { if (arg & ~RE_MASK) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -225,7 +225,7 @@ static __init u32 build_re(u32 arg) return (arg & RE_MASK) << RE_SH; } -static __init u32 build_simm(s32 arg) +static u32 __init build_simm(s32 arg) { if (arg > 0x7fff || arg < -0x8000) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -233,7 +233,7 @@ static __init u32 build_simm(s32 arg) return arg & 0xffff; } -static __init u32 build_uimm(u32 arg) +static u32 __init build_uimm(u32 arg) { if (arg & ~IMM_MASK) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -241,7 +241,7 @@ static __init u32 build_uimm(u32 arg) return arg & IMM_MASK; } -static __init u32 build_bimm(s32 arg) +static u32 __init build_bimm(s32 arg) { if (arg > 0x1ffff || arg < -0x20000) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -252,7 +252,7 @@ static __init u32 build_bimm(s32 arg) return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff); } -static __init u32 build_jimm(u32 arg) +static u32 __init build_jimm(u32 arg) { if (arg & ~((JIMM_MASK) << 2)) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -260,7 +260,7 @@ static __init u32 build_jimm(u32 arg) return (arg >> 2) & JIMM_MASK; } -static __init u32 build_func(u32 arg) +static u32 __init build_func(u32 arg) { if (arg & ~FUNC_MASK) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -268,7 +268,7 @@ static __init u32 build_func(u32 arg) return arg & FUNC_MASK; } -static __init u32 build_set(u32 arg) +static u32 __init build_set(u32 arg) { if (arg & ~SET_MASK) printk(KERN_WARNING "TLB synthesizer field overflow\n"); @@ -315,69 +315,69 @@ static void __init build_insn(u32 **buf, enum opcode opc, ...) } #define I_u1u2u3(op) \ - static inline void __init i##op(u32 **buf, unsigned int a, \ + static inline void i##op(u32 **buf, unsigned int a, \ unsigned int b, unsigned int c) \ { \ build_insn(buf, insn##op, a, b, c); \ } #define I_u2u1u3(op) \ - static inline void __init i##op(u32 **buf, unsigned int a, \ + static inline void i##op(u32 **buf, unsigned int a, \ unsigned int b, unsigned int c) \ { \ build_insn(buf, insn##op, b, a, c); \ } #define I_u3u1u2(op) \ - static inline void __init i##op(u32 **buf, unsigned int a, \ + static inline void i##op(u32 **buf, unsigned int a, \ unsigned int b, unsigned int c) \ { \ build_insn(buf, insn##op, b, c, a); \ } #define I_u1u2s3(op) \ - static inline void __init i##op(u32 **buf, unsigned int a, \ + static inline void i##op(u32 **buf, unsigned int a, \ unsigned int b, signed int c) \ { \ build_insn(buf, insn##op, a, b, c); \ } #define I_u2s3u1(op) \ - static inline void __init i##op(u32 **buf, unsigned int a, \ + static inline void i##op(u32 **buf, unsigned int a, \ signed int b, unsigned int c) \ { \ build_insn(buf, insn##op, c, a, b); \ } #define I_u2u1s3(op) \ - static inline void __init i##op(u32 **buf, unsigned int a, \ + static inline void i##op(u32 **buf, unsigned int a, \ unsigned int b, signed int c) \ { \ build_insn(buf, insn##op, b, a, c); \ } #define I_u1u2(op) \ - static inline void __init i##op(u32 **buf, unsigned int a, \ + static inline void i##op(u32 **buf, unsigned int a, \ unsigned int b) \ { \ build_insn(buf, insn##op, a, b); \ } #define I_u1s2(op) \ - static inline void __init i##op(u32 **buf, unsigned int a, \ + static inline void i##op(u32 **buf, unsigned int a, \ signed int b) \ { \ build_insn(buf, insn##op, a, b); \ } #define I_u1(op) \ - static inline void __init i##op(u32 **buf, unsigned int a) \ + static inline void i##op(u32 **buf, unsigned int a) \ { \ build_insn(buf, insn##op, a); \ } #define I_0(op) \ - static inline void __init i##op(u32 **buf) \ + static inline void i##op(u32 **buf) \ { \ build_insn(buf, insn##op); \ } @@ -457,7 +457,7 @@ struct label { enum label_id lab; }; -static __init void build_label(struct label **lab, u32 *addr, +static void __init build_label(struct label **lab, u32 *addr, enum label_id l) { (*lab)->addr = addr; @@ -526,34 +526,34 @@ L_LA(_r3000_write_probe_fail) #define i_ehb(buf) i_sll(buf, 0, 0, 3) #ifdef CONFIG_64BIT -static __init int __maybe_unused in_compat_space_p(long addr) +static int __init __maybe_unused in_compat_space_p(long addr) { /* Is this address in 32bit compat space? */ return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L); } -static __init int __maybe_unused rel_highest(long val) +static int __init __maybe_unused rel_highest(long val) { return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000; } -static __init int __maybe_unused rel_higher(long val) +static int __init __maybe_unused rel_higher(long val) { return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000; } #endif -static __init int rel_hi(long val) +static int __init rel_hi(long val) { return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000; } -static __init int rel_lo(long val) +static int __init rel_lo(long val) { return ((val & 0xffff) ^ 0x8000) - 0x8000; } -static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr) +static void __init i_LA_mostly(u32 **buf, unsigned int rs, long addr) { #ifdef CONFIG_64BIT if (!in_compat_space_p(addr)) { @@ -571,7 +571,7 @@ static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr) i_lui(buf, rs, rel_hi(addr)); } -static __init void __maybe_unused i_LA(u32 **buf, unsigned int rs, +static void __init __maybe_unused i_LA(u32 **buf, unsigned int rs, long addr) { i_LA_mostly(buf, rs, addr); @@ -589,7 +589,7 @@ struct reloc { enum label_id lab; }; -static __init void r_mips_pc16(struct reloc **rel, u32 *addr, +static void __init r_mips_pc16(struct reloc **rel, u32 *addr, enum label_id l) { (*rel)->addr = addr; @@ -614,7 +614,7 @@ static inline void __resolve_relocs(struct reloc *rel, struct label *lab) } } -static __init void resolve_relocs(struct reloc *rel, struct label *lab) +static void __init resolve_relocs(struct reloc *rel, struct label *lab) { struct label *l; @@ -624,7 +624,7 @@ static __init void resolve_relocs(struct reloc *rel, struct label *lab) __resolve_relocs(rel, l); } -static __init void move_relocs(struct reloc *rel, u32 *first, u32 *end, +static void __init move_relocs(struct reloc *rel, u32 *first, u32 *end, long off) { for (; rel->lab != label_invalid; rel++) @@ -632,7 +632,7 @@ static __init void move_relocs(struct reloc *rel, u32 *first, u32 *end, rel->addr += off; } -static __init void move_labels(struct label *lab, u32 *first, u32 *end, +static void __init move_labels(struct label *lab, u32 *first, u32 *end, long off) { for (; lab->lab != label_invalid; lab++) @@ -640,7 +640,7 @@ static __init void move_labels(struct label *lab, u32 *first, u32 *end, lab->addr += off; } -static __init void copy_handler(struct reloc *rel, struct label *lab, +static void __init copy_handler(struct reloc *rel, struct label *lab, u32 *first, u32 *end, u32 *target) { long off = (long)(target - first); @@ -651,7 +651,7 @@ static __init void copy_handler(struct reloc *rel, struct label *lab, move_labels(lab, first, end, off); } -static __init int __maybe_unused insn_has_bdelay(struct reloc *rel, +static int __init __maybe_unused insn_has_bdelay(struct reloc *rel, u32 *addr) { for (; rel->lab != label_invalid; rel++) { @@ -743,11 +743,11 @@ il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l) * We deliberately chose a buffer size of 128, so we won't scribble * over anything important on overflow before we panic. */ -static __initdata u32 tlb_handler[128]; +static u32 tlb_handler[128] __initdata; /* simply assume worst case size for labels and relocs */ -static __initdata struct label labels[128]; -static __initdata struct reloc relocs[128]; +static struct label labels[128] __initdata; +static struct reloc relocs[128] __initdata; /* * The R3000 TLB handler is simple. @@ -801,7 +801,7 @@ static void __init build_r3000_tlb_refill_handler(void) * other one.To keep things simple, we first assume linear space, * then we relocate it to the final handler layout as needed. */ -static __initdata u32 final_handler[64]; +static u32 final_handler[64] __initdata; /* * Hazards @@ -825,7 +825,7 @@ static __initdata u32 final_handler[64]; * * As if we MIPS hackers wouldn't know how to nop pipelines happy ... */ -static __init void __maybe_unused build_tlb_probe_entry(u32 **p) +static void __init __maybe_unused build_tlb_probe_entry(u32 **p) { switch (current_cpu_type()) { /* Found by experiment: R4600 v2.0 needs this, too. */ @@ -849,7 +849,7 @@ static __init void __maybe_unused build_tlb_probe_entry(u32 **p) */ enum tlb_write_entry { tlb_random, tlb_indexed }; -static __init void build_tlb_write_entry(u32 **p, struct label **l, +static void __init build_tlb_write_entry(u32 **p, struct label **l, struct reloc **r, enum tlb_write_entry wmode) { @@ -993,7 +993,7 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l, * TMP and PTR are scratch. * TMP will be clobbered, PTR will hold the pmd entry. */ -static __init void +static void __init build_get_pmde64(u32 **p, struct label **l, struct reloc **r, unsigned int tmp, unsigned int ptr) { @@ -1054,7 +1054,7 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r, * BVADDR is the faulting address, PTR is scratch. * PTR will hold the pgd for vmalloc. */ -static __init void +static void __init build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r, unsigned int bvaddr, unsigned int ptr) { @@ -1118,7 +1118,7 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r, * TMP and PTR are scratch. * TMP will be clobbered, PTR will hold the pgd entry. */ -static __init void __maybe_unused +static void __init __maybe_unused build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr) { long pgdc = (long)pgd_current; @@ -1153,7 +1153,7 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr) #endif /* !CONFIG_64BIT */ -static __init void build_adjust_context(u32 **p, unsigned int ctx) +static void __init build_adjust_context(u32 **p, unsigned int ctx) { unsigned int shift = 4 - (PTE_T_LOG2 + 1) + PAGE_SHIFT - 12; unsigned int mask = (PTRS_PER_PTE / 2 - 1) << (PTE_T_LOG2 + 1); @@ -1179,7 +1179,7 @@ static __init void build_adjust_context(u32 **p, unsigned int ctx) i_andi(p, ctx, ctx, mask); } -static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr) +static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr) { /* * Bug workaround for the Nevada. It seems as if under certain @@ -1204,7 +1204,7 @@ static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr) i_ADDU(p, ptr, ptr, tmp); /* add in offset */ } -static __init void build_update_entries(u32 **p, unsigned int tmp, +static void __init build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep) { /* From 16e906812f885cf16d95577dba260db6375ba571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 11 Oct 2007 17:32:31 -0700 Subject: [PATCH 2280/2804] [TCP]: Add bytes_acked (ABC) clearing to FRTO too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I was reading tcp_enter_loss while looking for Cedric's bug and noticed bytes_acked adjustment is missing from FRTO side. Since bytes_acked will only be used in tcp_cong_avoid, I think it's safe to assume RTO would be spurious. During FRTO cwnd will be not controlled by tcp_cong_avoid and if FRTO calls for conventional recovery, cwnd is adjusted and the result of wrong assumption is cleared from bytes_acked. If RTO was in fact spurious, we did normal ABC already and can continue without any additional adjustments. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 101054cb13e9..e40857e073b3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1687,6 +1687,7 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) tp->snd_cwnd_cnt = 0; tp->snd_cwnd_stamp = tcp_time_stamp; tp->frto_counter = 0; + tp->bytes_acked = 0; tp->reordering = min_t(unsigned int, tp->reordering, sysctl_tcp_reordering); @@ -2824,6 +2825,7 @@ static void tcp_conservative_spur_to_response(struct tcp_sock *tp) { tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh); tp->snd_cwnd_cnt = 0; + tp->bytes_acked = 0; TCP_ECN_queue_cwr(tp); tcp_moderate_cwnd(tp); } From 3eec0047d9bdd68fddef6539e77fee99ba2531f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 11 Oct 2007 17:33:11 -0700 Subject: [PATCH 2281/2804] [TCP]: Fix mark_head_lost to ignore R-bit when trying to mark L MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This condition (plain R) can arise at least in recovery that is triggered after tcp_undo_loss. There isn't any reason why they should not be marked as lost, not marking makes in_flight estimator to return too large values. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e40857e073b3..c827285b488e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1987,7 +1987,7 @@ static void tcp_mark_head_lost(struct sock *sk, cnt += tcp_skb_pcount(skb); if (cnt > packets || after(TCP_SKB_CB(skb)->end_seq, high_seq)) break; - if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { + if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_SACKED_ACKED|TCPCB_LOST))) { TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; tp->lost_out += tcp_skb_pcount(skb); tcp_verify_retransmit_hint(tp, skb); From f6fb128d272eb7b0f1a8be78153a724545e28be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 11 Oct 2007 17:33:55 -0700 Subject: [PATCH 2282/2804] [TCP]: Kill almost unused variable pcount from sacktag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's on the way for future cutting of that function. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c827285b488e..50047045df62 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1314,7 +1314,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ flag |= FLAG_DATA_LOST; tcp_for_write_queue_from(skb, sk) { - int in_sack, pcount; + int in_sack; u8 sacked; if (skb == tcp_send_head(sk)) @@ -1336,9 +1336,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && !before(end_seq, TCP_SKB_CB(skb)->end_seq); - pcount = tcp_skb_pcount(skb); - - if (pcount > 1 && !in_sack && + if (tcp_skb_pcount(skb) > 1 && !in_sack && after(TCP_SKB_CB(skb)->end_seq, start_seq)) { unsigned int pkt_len; @@ -1353,10 +1351,9 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ TCP_SKB_CB(skb)->seq); if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size)) break; - pcount = tcp_skb_pcount(skb); } - fack_count += pcount; + fack_count += tcp_skb_pcount(skb); sacked = TCP_SKB_CB(skb)->sacked; From d193594299064d386a2705928cd61ab2ca3d7cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 11 Oct 2007 17:34:25 -0700 Subject: [PATCH 2283/2804] [TCP]: Extract tcp_match_queue_to_sack from sacktag code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is necessary for upcoming DSACK bugfix. Reduces sacktag length which is not very sad thing at all... :-) Notice that there's a need to handle out-of-mem at caller's place. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 54 ++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 50047045df62..bd18c252dee4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1181,6 +1181,38 @@ static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, return dup_sack; } +/* Check if skb is fully within the SACK block. In presence of GSO skbs, + * the incoming SACK may not exactly match but we can find smaller MSS + * aligned portion of it that matches. Therefore we might need to fragment + * which may fail and creates some hassle (caller must handle error case + * returns). + */ +int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb, + u32 start_seq, u32 end_seq) +{ + int in_sack, err; + unsigned int pkt_len; + + in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && + !before(end_seq, TCP_SKB_CB(skb)->end_seq); + + if (tcp_skb_pcount(skb) > 1 && !in_sack && + after(TCP_SKB_CB(skb)->end_seq, start_seq)) { + + in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq); + + if (!in_sack) + pkt_len = start_seq - TCP_SKB_CB(skb)->seq; + else + pkt_len = end_seq - TCP_SKB_CB(skb)->seq; + err = tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size); + if (err < 0) + return err; + } + + return in_sack; +} + static int tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una) { @@ -1333,25 +1365,9 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (!before(TCP_SKB_CB(skb)->seq, end_seq)) break; - in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && - !before(end_seq, TCP_SKB_CB(skb)->end_seq); - - if (tcp_skb_pcount(skb) > 1 && !in_sack && - after(TCP_SKB_CB(skb)->end_seq, start_seq)) { - unsigned int pkt_len; - - in_sack = !after(start_seq, - TCP_SKB_CB(skb)->seq); - - if (!in_sack) - pkt_len = (start_seq - - TCP_SKB_CB(skb)->seq); - else - pkt_len = (end_seq - - TCP_SKB_CB(skb)->seq); - if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size)) - break; - } + in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq); + if (in_sack < 0) + break; fack_count += tcp_skb_pcount(skb); From 4cd829995b86e0359796780d43d2f210cb5cf021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 11 Oct 2007 17:34:57 -0700 Subject: [PATCH 2284/2804] [TCP]: No need to re-count fackets_out/sacked_out at RTO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both sacked_out and fackets_out are directly known from how parameter. Since fackets_out is accurate, there's no need for recounting (sacked_out was previously unnecessarily counted in the loop anyway). Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bd18c252dee4..a06603912137 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1711,18 +1711,23 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag) tcp_clear_retrans_hints_partial(tp); } -void tcp_clear_retrans(struct tcp_sock *tp) +static void tcp_clear_retrans_partial(struct tcp_sock *tp) { tp->retrans_out = 0; - - tp->fackets_out = 0; - tp->sacked_out = 0; tp->lost_out = 0; tp->undo_marker = 0; tp->undo_retrans = 0; } +void tcp_clear_retrans(struct tcp_sock *tp) +{ + tcp_clear_retrans_partial(tp); + + tp->fackets_out = 0; + tp->sacked_out = 0; +} + /* Enter Loss state. If "how" is not zero, forget all SACK information * and reset tags completely, otherwise preserve SACKs. If receiver * dropped its ofo queue, we will know this due to reneging detection. @@ -1732,7 +1737,6 @@ void tcp_enter_loss(struct sock *sk, int how) const struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; - int cnt = 0; /* Reduce ssthresh if it has not yet been made inside this window. */ if (icsk->icsk_ca_state <= TCP_CA_Disorder || tp->snd_una == tp->high_seq || @@ -1746,7 +1750,10 @@ void tcp_enter_loss(struct sock *sk, int how) tp->snd_cwnd_stamp = tcp_time_stamp; tp->bytes_acked = 0; - tcp_clear_retrans(tp); + tcp_clear_retrans_partial(tp); + + if (tcp_is_reno(tp)) + tcp_reset_reno_sack(tp); if (!how) { /* Push undo marker, if it was plain RTO and nothing @@ -1754,13 +1761,15 @@ void tcp_enter_loss(struct sock *sk, int how) tp->undo_marker = tp->snd_una; tcp_clear_retrans_hints_partial(tp); } else { + tp->sacked_out = 0; + tp->fackets_out = 0; tcp_clear_all_retrans_hints(tp); } tcp_for_write_queue(skb, sk) { if (skb == tcp_send_head(sk)) break; - cnt += tcp_skb_pcount(skb); + if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS) tp->undo_marker = 0; TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; @@ -1768,9 +1777,6 @@ void tcp_enter_loss(struct sock *sk, int how) TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; tp->lost_out += tcp_skb_pcount(skb); - } else { - tp->sacked_out += tcp_skb_pcount(skb); - tp->fackets_out = cnt; } } tcp_verify_left_out(tp); From f785a8e28b9d103c7473655743b6ac1bc3cd3a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 11 Oct 2007 17:35:41 -0700 Subject: [PATCH 2285/2804] [TCP]: Fix lost_retrans loop vs fastpath problems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detection implemented with lost_retrans must work also when fastpath is taken, yet most of the queue is skipped including (very likely) those retransmitted skb's we're interested in. This problem appeared when the hints got added, which removed a need to always walk over the whole write queue head. Therefore decicion for the lost_retrans worker loop entry must be separated from the sacktag processing more than it was necessary before. It turns out to be problematic to optimize the worker loop very heavily because ack_seqs of skb may have a number of discontinuity points. Maybe similar approach as currently is implemented could be attempted but that's becoming more and more complex because the trend is towards less skb walking in sacktag marker. Trying a simple work until all rexmitted skbs heve been processed approach. Maybe after(highest_sack_end_seq, tp->high_seq) checking is not sufficiently accurate and causes entry too often in no-work-to-do cases. Since that's not known, I've separated solution to that from this patch. Noticed because of report against a related problem from TAKANO Ryousei . He also provided a patch to that part of the problem. This patch includes solution to it (though this patch has to use somewhat different placement). TAKANO's description and patch is available here: http://marc.info/?l=linux-netdev&m=119149311913288&w=2 ...In short, TAKANO's problem is that end_seq the loop is using not necessarily the largest SACK block's end_seq because the current ACK may still have higher SACK blocks which are later by the loop. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a06603912137..d5e0fcc22a3b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1109,27 +1109,34 @@ static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack, /* Check for lost retransmit. This superb idea is borrowed from "ratehalving". * Event "C". Later note: FACK people cheated me again 8), we have to account * for reordering! Ugly, but should help. + * + * Search retransmitted skbs from write_queue that were sent when snd_nxt was + * less than what is now known to be received by the other end (derived from + * SACK blocks by the caller). */ -static int tcp_mark_lost_retrans(struct sock *sk, u32 lost_retrans) +static int tcp_mark_lost_retrans(struct sock *sk, u32 received_upto) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; int flag = 0; + int cnt = 0; tcp_for_write_queue(skb, sk) { u32 ack_seq = TCP_SKB_CB(skb)->ack_seq; if (skb == tcp_send_head(sk)) break; - if (after(TCP_SKB_CB(skb)->seq, lost_retrans)) + if (cnt == tp->retrans_out) break; if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) continue; - if ((TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) && - after(lost_retrans, ack_seq) && + if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)) + continue; + + if (after(received_upto, ack_seq) && (tcp_is_fack(tp) || - !before(lost_retrans, + !before(received_upto, ack_seq + tp->reordering * tp->mss_cache))) { TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; tp->retrans_out -= tcp_skb_pcount(skb); @@ -1143,6 +1150,8 @@ static int tcp_mark_lost_retrans(struct sock *sk, u32 lost_retrans) flag |= FLAG_DATA_SACKED; NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); } + } else { + cnt += tcp_skb_pcount(skb); } } return flag; @@ -1225,7 +1234,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; int reord = tp->packets_out; int prior_fackets; - u32 lost_retrans = 0; + u32 highest_sack_end_seq = 0; int flag = 0; int found_dup_sack = 0; int cached_fack_count; @@ -1396,11 +1405,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ continue; } - if ((sacked&TCPCB_SACKED_RETRANS) && - after(end_seq, TCP_SKB_CB(skb)->ack_seq) && - (!lost_retrans || after(end_seq, lost_retrans))) - lost_retrans = end_seq; - if (!in_sack) continue; @@ -1454,9 +1458,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (fack_count > tp->fackets_out) tp->fackets_out = fack_count; - if (after(TCP_SKB_CB(skb)->seq, - tp->highest_sack)) + if (after(TCP_SKB_CB(skb)->seq, tp->highest_sack)) { tp->highest_sack = TCP_SKB_CB(skb)->seq; + highest_sack_end_seq = TCP_SKB_CB(skb)->end_seq; + } } else { if (dup_sack && (sacked&TCPCB_RETRANS)) reord = min(fack_count, reord); @@ -1476,8 +1481,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ } } - if (lost_retrans && icsk->icsk_ca_state == TCP_CA_Recovery) - flag |= tcp_mark_lost_retrans(sk, lost_retrans); + if (tp->retrans_out && highest_sack_end_seq && + after(highest_sack_end_seq, tp->high_seq) && + icsk->icsk_ca_state == TCP_CA_Recovery) + flag |= tcp_mark_lost_retrans(sk, highest_sack_end_seq); tcp_verify_left_out(tp); From b08d6cb22c777c8c91c16d8e3b8aafc93c98cbd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 11 Oct 2007 17:36:13 -0700 Subject: [PATCH 2286/2804] [TCP]: Limit processing lost_retrans loop to work-to-do cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This addition of lost_retrans_low to tcp_sock might be unnecessary, it's not clear how often lost_retrans worker is executed when there wasn't work to do. Signed-off-by: Ilpo Jรคrvinen Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 ++ net/ipv4/tcp_input.c | 14 +++++++++++--- net/ipv4/tcp_output.c | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 9ff456e8d6c7..c5b94c1a5ee2 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -348,6 +348,8 @@ struct tcp_sock { int lost_cnt_hint; int retransmit_cnt_hint; + u32 lost_retrans_low; /* Sent seq after any rxmit (lowest) */ + u16 advmss; /* Advertised MSS */ u16 prior_ssthresh; /* ssthresh saved at recovery start */ u32 lost_out; /* Lost packets */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d5e0fcc22a3b..0a42e9340346 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1112,7 +1112,8 @@ static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack, * * Search retransmitted skbs from write_queue that were sent when snd_nxt was * less than what is now known to be received by the other end (derived from - * SACK blocks by the caller). + * SACK blocks by the caller). Also calculate the lowest snd_nxt among the + * remaining retransmitted skbs to avoid some costly processing per ACKs. */ static int tcp_mark_lost_retrans(struct sock *sk, u32 received_upto) { @@ -1120,6 +1121,7 @@ static int tcp_mark_lost_retrans(struct sock *sk, u32 received_upto) struct sk_buff *skb; int flag = 0; int cnt = 0; + u32 new_low_seq = 0; tcp_for_write_queue(skb, sk) { u32 ack_seq = TCP_SKB_CB(skb)->ack_seq; @@ -1151,9 +1153,15 @@ static int tcp_mark_lost_retrans(struct sock *sk, u32 received_upto) NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); } } else { + if (!new_low_seq || before(ack_seq, new_low_seq)) + new_low_seq = ack_seq; cnt += tcp_skb_pcount(skb); } } + + if (tp->retrans_out) + tp->lost_retrans_low = new_low_seq; + return flag; } @@ -1481,8 +1489,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ } } - if (tp->retrans_out && highest_sack_end_seq && - after(highest_sack_end_seq, tp->high_seq) && + if (tp->retrans_out && + after(highest_sack_end_seq, tp->lost_retrans_low) && icsk->icsk_ca_state == TCP_CA_Recovery) flag |= tcp_mark_lost_retrans(sk, highest_sack_end_seq); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 53296753b0bd..324b4207254a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1914,6 +1914,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) printk(KERN_DEBUG "retrans_out leaked.\n"); } #endif + if (!tp->retrans_out) + tp->lost_retrans_low = tp->snd_nxt; TCP_SKB_CB(skb)->sacked |= TCPCB_RETRANS; tp->retrans_out += tcp_skb_pcount(skb); From 6f535763165331bb91277d7519b507fed22034e5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 11 Oct 2007 18:08:29 -0700 Subject: [PATCH 2287/2804] [NET]: Fix NAPI completion handling in some drivers. In order for the list handling in net_rx_action() to be correct, drivers must follow certain rules as stated by this comment in net_rx_action(): /* Drivers must not modify the NAPI state if they * consume the entire weight. In such cases this code * still "owns" the NAPI instance and therefore can * move the instance around on the list at-will. */ A few drivers do not do this because they mix the budget checks with reading hardware state, resulting in crashes like the one reported by takano@axe-inc.co.jp. BNX2 and TG3 are taken care of here, SKY2 fix is from Stephen Hemminger. Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 52 ++++++++++++++++++++++++++----------------- drivers/net/sky2.c | 17 ++++++++++---- drivers/net/tg3.c | 55 +++++++++++++++++++++++++++++++--------------- 3 files changed, 82 insertions(+), 42 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index bbfbdafb4ae5..d68accea380b 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2633,15 +2633,11 @@ bnx2_has_work(struct bnx2 *bp) return 0; } -static int -bnx2_poll(struct napi_struct *napi, int budget) +static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) { - struct bnx2 *bp = container_of(napi, struct bnx2, napi); - struct net_device *dev = bp->dev; struct status_block *sblk = bp->status_blk; u32 status_attn_bits = sblk->status_attn_bits; u32 status_attn_bits_ack = sblk->status_attn_bits_ack; - int work_done = 0; if ((status_attn_bits & STATUS_ATTN_EVENTS) != (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { @@ -2660,27 +2656,43 @@ bnx2_poll(struct napi_struct *napi, int budget) bnx2_tx_int(bp); if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) - work_done = bnx2_rx_int(bp, budget); + work_done += bnx2_rx_int(bp, budget - work_done); - bp->last_status_idx = bp->status_blk->status_idx; - rmb(); + return work_done; +} + +static int bnx2_poll(struct napi_struct *napi, int budget) +{ + struct bnx2 *bp = container_of(napi, struct bnx2, napi); + int work_done = 0; + + while (1) { + work_done = bnx2_poll_work(bp, work_done, budget); + + if (unlikely(work_done >= budget)) + break; + + if (likely(!bnx2_has_work(bp))) { + bp->last_status_idx = bp->status_blk->status_idx; + rmb(); + + netif_rx_complete(bp->dev, napi); + if (likely(bp->flags & USING_MSI_FLAG)) { + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + bp->last_status_idx); + return 0; + } + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + BNX2_PCICFG_INT_ACK_CMD_MASK_INT | + bp->last_status_idx); - if (!bnx2_has_work(bp)) { - netif_rx_complete(dev, napi); - if (likely(bp->flags & USING_MSI_FLAG)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); - return 0; + break; } - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - BNX2_PCICFG_INT_ACK_CMD_MASK_INT | - bp->last_status_idx); - - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - bp->last_status_idx); } return work_done; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index fe0e7560d236..4e569fa0f96c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2606,7 +2606,7 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) { struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi); u32 status = sky2_read32(hw, B0_Y2_SP_EISR); - int work_done; + int work_done = 0; if (unlikely(status & Y2_IS_ERROR)) sky2_err_intr(hw, status); @@ -2617,10 +2617,16 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) if (status & Y2_IS_IRQ_PHY2) sky2_phy_intr(hw, 1); - work_done = sky2_status_intr(hw, work_limit); + for(;;) { + work_done += sky2_status_intr(hw, work_limit); + + if (work_done >= work_limit) + break; + + /* More work? */ + if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX)) + continue; - /* More work? */ - if (hw->st_idx == sky2_read16(hw, STAT_PUT_IDX)) { /* Bug/Errata workaround? * Need to kick the TX irq moderation timer. */ @@ -2631,7 +2637,10 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) napi_complete(napi); sky2_read32(hw, B0_Y2_SP_LISR); + break; + } + return work_done; } diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d2b30fb0b318..a402b5c01896 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3555,12 +3555,9 @@ next_pkt_nopost: return received; } -static int tg3_poll(struct napi_struct *napi, int budget) +static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) { - struct tg3 *tp = container_of(napi, struct tg3, napi); - struct net_device *netdev = tp->dev; struct tg3_hw_status *sblk = tp->hw_status; - int work_done = 0; /* handle link change and other phy events */ if (!(tp->tg3_flags & @@ -3578,11 +3575,8 @@ static int tg3_poll(struct napi_struct *napi, int budget) /* run TX completion thread */ if (sblk->idx[0].tx_consumer != tp->tx_cons) { tg3_tx(tp); - if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) { - netif_rx_complete(netdev, napi); - schedule_work(&tp->reset_task); + if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) return 0; - } } /* run RX thread, within the bounds set by NAPI. @@ -3590,21 +3584,46 @@ static int tg3_poll(struct napi_struct *napi, 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 += tg3_rx(tp, budget - work_done); - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { - tp->last_tag = sblk->status_tag; - rmb(); - } else - sblk->status &= ~SD_STATUS_UPDATED; + return work_done; +} - /* if no more work, tell net stack and NIC we're done */ - if (!tg3_has_work(tp)) { - netif_rx_complete(netdev, napi); - tg3_restart_ints(tp); +static int tg3_poll(struct napi_struct *napi, int budget) +{ + struct tg3 *tp = container_of(napi, struct tg3, napi); + int work_done = 0; + + while (1) { + work_done = tg3_poll_work(tp, work_done, budget); + + if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) + goto tx_recovery; + + if (unlikely(work_done >= budget)) + break; + + if (likely(!tg3_has_work(tp))) { + struct tg3_hw_status *sblk = tp->hw_status; + + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + tp->last_tag = sblk->status_tag; + rmb(); + } else + sblk->status &= ~SD_STATUS_UPDATED; + + netif_rx_complete(tp->dev, napi); + tg3_restart_ints(tp); + break; + } } return work_done; + +tx_recovery: + netif_rx_complete(tp->dev, napi); + schedule_work(&tp->reset_task); + return 0; } static void tg3_irq_quiesce(struct tg3 *tp) From 266918303226cceac7eca38ced30f15f277bd89c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 18:31:13 -0700 Subject: [PATCH 2288/2804] [SKY2]: status polling loop (post merge) Handle the corner case where budget is exhausted correctly. And save unnecessary read of index register. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4e569fa0f96c..0a3203465415 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2245,15 +2245,13 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) } /* Process status response ring */ -static int sky2_status_intr(struct sky2_hw *hw, int to_do) +static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) { int work_done = 0; unsigned rx[2] = { 0, 0 }; - u16 hwidx = sky2_read16(hw, STAT_PUT_IDX); rmb(); - - while (hw->st_idx != hwidx) { + do { struct sky2_port *sky2; struct sky2_status_le *le = hw->st_le + hw->st_idx; unsigned port = le->css & CSS_LINK_BIT; @@ -2364,7 +2362,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) printk(KERN_WARNING PFX "unknown status opcode 0x%x\n", le->opcode); } - } + } while (hw->st_idx != idx); /* Fully processed status ring so clear irq */ sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); @@ -2607,6 +2605,7 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi); u32 status = sky2_read32(hw, B0_Y2_SP_EISR); int work_done = 0; + u16 idx; if (unlikely(status & Y2_IS_ERROR)) sky2_err_intr(hw, status); @@ -2617,30 +2616,24 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) if (status & Y2_IS_IRQ_PHY2) sky2_phy_intr(hw, 1); - for(;;) { - work_done += sky2_status_intr(hw, work_limit); + while ((idx = sky2_read16(hw, STAT_PUT_IDX)) != hw->st_idx) { + work_done += sky2_status_intr(hw, work_limit - work_done, idx); if (work_done >= work_limit) - break; - - /* More work? */ - if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX)) - continue; - - /* Bug/Errata workaround? - * Need to kick the TX irq moderation timer. - */ - if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); - } - - napi_complete(napi); - sky2_read32(hw, B0_Y2_SP_LISR); - break; - + goto done; } + /* Bug/Errata workaround? + * Need to kick the TX irq moderation timer. + */ + if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); + } + napi_complete(napi); + sky2_read32(hw, B0_Y2_SP_LISR); +done: + return work_done; } From d94bad827d9a0df939a0e7ed081a2780b9f72c4b Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Mon, 8 Oct 2007 22:51:24 +1000 Subject: [PATCH 2289/2804] [POWERPC] PCI: Add 64-bit physical address support to setup_indirect_pci Add 64-bit physical address support to setup_indirect_pci(). Signed-off-by: Valentine Barshak Acked-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/indirect_pci.c | 6 ++++-- include/asm-powerpc/pci-bridge.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index b5d068204aa3..cfbd2aae93e8 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -149,9 +149,11 @@ static struct pci_ops indirect_pci_ops = }; void __init -setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data, u32 flags) +setup_indirect_pci(struct pci_controller* hose, + resource_size_t cfg_addr, + resource_size_t cfg_data, u32 flags) { - unsigned long base = cfg_addr & PAGE_MASK; + resource_size_t base = cfg_addr & PAGE_MASK; void __iomem *mbase; mbase = ioremap(base, PAGE_SIZE); diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index e909769b6410..dc318458b5fe 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -98,7 +98,8 @@ extern int early_find_capability(struct pci_controller *hose, int bus, int dev_fn, int cap); extern void setup_indirect_pci(struct pci_controller* hose, - u32 cfg_addr, u32 cfg_data, u32 flags); + resource_size_t cfg_addr, + resource_size_t cfg_data, u32 flags); extern void setup_grackle(struct pci_controller *hose); extern void __init update_bridge_resource(struct pci_dev *dev, struct resource *res); From 01ba1e9d26fcd29f3ad4f3a5bcf40c0fbc40ee81 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:46 +1000 Subject: [PATCH 2290/2804] [POWERPC] XilinxFB: Use pdata to pass around framebuffer parameters The call to xilinxfb_assign is getting unwieldy when adding features to the Xilinx framebuffer driver. Change xilinxfb_assign() to accept a pointer to a xilinxfb_platform_data structure to prepare for adding additition configuration options. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 43 +++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index dec602c23075..b3b57f4a35a2 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -83,6 +83,12 @@ #define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */ +/* + * Default xilinxfb configuration + */ +static struct xilinxfb_platform_data xilinx_fb_default_pdata = { +}; + /* * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures */ @@ -207,7 +213,7 @@ static struct fb_ops xilinxfb_ops = */ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, - int width_mm, int height_mm, int rotate) + struct xilinxfb_platform_data *pdata) { struct xilinxfb_drvdata *drvdata; int rc; @@ -253,7 +259,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Turn on the display */ drvdata->reg_ctrl_default = REG_CTRL_ENABLE; - if (rotate) + if (pdata->rotate_screen) drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); @@ -267,8 +273,8 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, drvdata->info.flags = FBINFO_DEFAULT; drvdata->info.var = xilinx_fb_var; - xilinx_fb_var.height = height_mm; - xilinx_fb_var.width = width_mm; + xilinx_fb_var.height = pdata->screen_height_mm; + xilinx_fb_var.width = pdata->screen_width_mm; /* Allocate a colour map */ rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); @@ -349,9 +355,6 @@ xilinxfb_platform_probe(struct platform_device *pdev) { struct xilinxfb_platform_data *pdata; struct resource *res; - int width_mm = 0; - int height_mm = 0; - int rotate = 0; /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -361,15 +364,12 @@ xilinxfb_platform_probe(struct platform_device *pdev) } /* If a pdata structure is provided, then extract the parameters */ - pdata = pdev->dev.platform_data; - if (pdata) { - height_mm = pdata->screen_height_mm; - width_mm = pdata->screen_width_mm; - rotate = pdata->rotate_screen ? 1 : 0; - } + if (pdev->dev.platform_data) + pdata = pdev->dev.platform_data; + else + pdata = &xilinx_fb_default_pdata; - return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, - rotate); + return xilinxfb_assign(&pdev->dev, res->start, pdata); } static int @@ -398,9 +398,12 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) { struct resource res; const u32 *prop; - int width = 0, height = 0, rotate = 0; + struct xilinxfb_platform_data pdata; int size, rc; + /* Copy with the default pdata (not a ptr reference!) */ + pdata = xilinx_fb_default_pdata; + dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); rc = of_address_to_resource(op->node, 0, &res); @@ -411,14 +414,14 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) prop = of_get_property(op->node, "display-number", &size); if ((prop) && (size >= sizeof(u32)*2)) { - width = prop[0]; - height = prop[1]; + pdata.screen_width_mm = prop[0]; + pdata.screen_height_mm = prop[1]; } if (of_find_property(op->node, "rotate-display", NULL)) - rotate = 1; + pdata.rotate_screen = 1; - return xilinxfb_assign(&op->dev, res.start, width, height, rotate); + return xilinxfb_assign(&op->dev, res.start, &pdata); } static int __devexit xilinxfb_of_remove(struct of_device *op) From b4d6a7268fc754eefb196cabc0ccfa2e97022af2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:51 +1000 Subject: [PATCH 2291/2804] [POWERPC] XilinxFB: Add support for custom screen resolution Some custom implementations of the xilinx fb can use resolutions other than 640x480. This patch allows the resolution to be specified in the device tree or the xilinx_platform_data structure. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 71 +++++++++++++++++++++++++--------------- include/linux/xilinxfb.h | 6 ++-- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index b3b57f4a35a2..c6174125f52b 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -70,12 +70,6 @@ */ #define BYTES_PER_PIXEL 4 #define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8) -#define XRES 640 -#define YRES 480 -#define XRES_VIRTUAL 1024 -#define YRES_VIRTUAL YRES -#define LINE_LENGTH (XRES_VIRTUAL * BYTES_PER_PIXEL) -#define FB_SIZE (YRES_VIRTUAL * LINE_LENGTH) #define RED_SHIFT 16 #define GREEN_SHIFT 8 @@ -87,6 +81,10 @@ * Default xilinxfb configuration */ static struct xilinxfb_platform_data xilinx_fb_default_pdata = { + .xres = 640, + .yres = 480, + .xvirt = 1024, + .yvirt = 480; }; /* @@ -96,17 +94,10 @@ static struct fb_fix_screeninfo xilinx_fb_fix = { .id = "Xilinx", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, - .smem_len = FB_SIZE, - .line_length = LINE_LENGTH, .accel = FB_ACCEL_NONE }; static struct fb_var_screeninfo xilinx_fb_var = { - .xres = XRES, - .yres = YRES, - .xres_virtual = XRES_VIRTUAL, - .yres_virtual = YRES_VIRTUAL, - .bits_per_pixel = BITS_PER_PIXEL, .red = { RED_SHIFT, 8, 0 }, @@ -217,6 +208,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, { struct xilinxfb_drvdata *drvdata; int rc; + int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; /* Allocate the driver data region */ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); @@ -243,7 +235,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Allocate the framebuffer memory */ - drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), + drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); @@ -252,7 +244,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Clear (turn to black) the framebuffer */ - memset_io((void __iomem *)drvdata->fb_virt, 0, FB_SIZE); + memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); @@ -269,12 +261,18 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, drvdata->info.fbops = &xilinxfb_ops; drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; + drvdata->info.fix.smem_len = fbsize; + drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL; + drvdata->info.pseudo_palette = drvdata->pseudo_palette; drvdata->info.flags = FBINFO_DEFAULT; drvdata->info.var = xilinx_fb_var; - - xilinx_fb_var.height = pdata->screen_height_mm; - xilinx_fb_var.width = pdata->screen_width_mm; + drvdata->info.var.height = pdata->screen_height_mm; + drvdata->info.var.width = pdata->screen_width_mm; + drvdata->info.var.xres = pdata->xres; + drvdata->info.var.yres = pdata->yres; + drvdata->info.var.xres_virtual = pdata->xvirt; + drvdata->info.var.yres_virtual = pdata->yvirt; /* Allocate a colour map */ rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); @@ -294,14 +292,15 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Put a banner in the log (for DEBUG) */ dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", - (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); + (void*)drvdata->fb_phys, drvdata->fb_virt, fbsize); + return 0; /* success */ err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); err_cmap: - dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, + dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -331,8 +330,8 @@ static int xilinxfb_release(struct device *dev) fb_dealloc_cmap(&drvdata->info.cmap); - dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, - drvdata->fb_phys); + dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), + drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -364,10 +363,18 @@ xilinxfb_platform_probe(struct platform_device *pdev) } /* If a pdata structure is provided, then extract the parameters */ - if (pdev->dev.platform_data) + pdata = &xilinx_fb_default_pdata; + if (pdev->dev.platform_data) { pdata = pdev->dev.platform_data; - else - pdata = &xilinx_fb_default_pdata; + if (!pdata->xres) + pdata->xres = xilinx_fb_default_pdata.xres; + if (!pdata->yres) + pdata->yres = xilinx_fb_default_pdata.yres; + if (!pdata->xvirt) + pdata->xvirt = xilinx_fb_default_pdata.xvirt; + if (!pdata->yvirt) + pdata->yvirt = xilinx_fb_default_pdata.yvirt; + } return xilinxfb_assign(&pdev->dev, res->start, pdata); } @@ -412,12 +419,24 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) return rc; } - prop = of_get_property(op->node, "display-number", &size); + prop = of_get_property(op->node, "phys-size", &size); if ((prop) && (size >= sizeof(u32)*2)) { pdata.screen_width_mm = prop[0]; pdata.screen_height_mm = prop[1]; } + prop = of_get_property(op->node, "resolution", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + pdata.xres = prop[0]; + pdata.yres = prop[1]; + } + + prop = of_get_property(op->node, "virtual-resolution", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + pdata.xvirt = prop[0]; + pdata.yvirt = prop[1]; + } + if (of_find_property(op->node, "rotate-display", NULL)) pdata.rotate_screen = 1; diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h index 9ad984d22c38..199a1eedf223 100644 --- a/include/linux/xilinxfb.h +++ b/include/linux/xilinxfb.h @@ -15,9 +15,11 @@ /* ML300/403 reference design framebuffer driver platform data struct */ struct xilinxfb_platform_data { - u32 rotate_screen; - u32 screen_height_mm; + u32 rotate_screen; /* Flag to rotate display 180 degrees */ + u32 screen_height_mm; /* Physical dimentions of screen in mm */ u32 screen_width_mm; + u32 xres, yres; /* resolution of screen in pixels */ + u32 xvirt, yvirt; /* resolution of memory buffer */ }; #endif /* __XILINXFB_H__ */ From 287e5d6fcccfa38b953cebe307e1ddfd32363355 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:56 +1000 Subject: [PATCH 2292/2804] [POWERPC] XilinxFB: Allow fixed framebuffer base address Allow a fixed framebuffer address to be assigned to the framebuffer device instead of allocating the framebuffer from the consistent memory pool. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 22 ++++++++++++++++------ include/linux/xilinxfb.h | 5 +++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index c6174125f52b..6ef99b2d13ca 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -117,6 +117,7 @@ struct xilinxfb_drvdata { void *fb_virt; /* virt. address of the frame buffer */ dma_addr_t fb_phys; /* phys. address of the frame buffer */ + int fb_alloced; /* Flag, was the fb memory alloced? */ u32 reg_ctrl_default; @@ -235,8 +236,15 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Allocate the framebuffer memory */ - drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), - &drvdata->fb_phys, GFP_KERNEL); + if (pdata->fb_phys) { + drvdata->fb_phys = pdata->fb_phys; + drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize); + } else { + drvdata->fb_alloced = 1; + drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), + &drvdata->fb_phys, GFP_KERNEL); + } + if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); rc = -ENOMEM; @@ -300,8 +308,9 @@ err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); err_cmap: - dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, - drvdata->fb_phys); + if (drvdata->fb_alloced) + dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, + drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -330,8 +339,9 @@ static int xilinxfb_release(struct device *dev) fb_dealloc_cmap(&drvdata->info.cmap); - dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), - drvdata->fb_virt, drvdata->fb_phys); + if (drvdata->fb_alloced) + dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), + drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h index 199a1eedf223..f2463f559fb9 100644 --- a/include/linux/xilinxfb.h +++ b/include/linux/xilinxfb.h @@ -20,6 +20,11 @@ struct xilinxfb_platform_data { u32 screen_width_mm; u32 xres, yres; /* resolution of screen in pixels */ u32 xvirt, yvirt; /* resolution of memory buffer */ + + /* Physical address of framebuffer memory; If non-zero, driver + * will use provided memory address instead of allocating one from + * the consistent pool. */ + u32 fb_phys; }; #endif /* __XILINXFB_H__ */ From 1189be6508d45183013ddb82b18f4934193de274 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 11 Oct 2007 20:37:10 +1000 Subject: [PATCH 2293/2804] [POWERPC] Use 1TB segments This makes the kernel use 1TB segments for all kernel mappings and for user addresses of 1TB and above, on machines which support them (currently POWER5+, POWER6 and PA6T). We detect that the machine supports 1TB segments by looking at the ibm,processor-segment-sizes property in the device tree. We don't currently use 1TB segments for user addresses < 1T, since that would effectively prevent 32-bit processes from using huge pages unless we also had a way to revert to using 256MB segments. That would be possible but would involve extra complications (such as keeping track of which segment size was used when HPTEs were inserted) and is not addressed here. Parts of this patch were originally written by Ben Herrenschmidt. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/entry_64.S | 14 ++- arch/powerpc/kernel/head_64.S | 2 +- arch/powerpc/kernel/process.c | 9 +- arch/powerpc/mm/hash_low_64.S | 73 +++++++++-- arch/powerpc/mm/hash_native_64.c | 92 +++++++------- arch/powerpc/mm/hash_utils_64.c | 114 ++++++++++++----- arch/powerpc/mm/hugetlbpage.c | 13 +- arch/powerpc/mm/pgtable_64.c | 4 +- arch/powerpc/mm/slb.c | 67 ++++++---- arch/powerpc/mm/slb_low.S | 37 +++++- arch/powerpc/mm/stab.c | 6 +- arch/powerpc/mm/tlb_64.c | 20 +-- arch/powerpc/platforms/cell/spu_base.c | 6 +- arch/powerpc/platforms/cell/spufs/switch.c | 2 +- arch/powerpc/platforms/celleb/htab.c | 34 ++--- arch/powerpc/platforms/iseries/htab.c | 13 +- arch/powerpc/platforms/ps3/htab.c | 14 ++- arch/powerpc/platforms/pseries/lpar.c | 85 +++++++------ include/asm-powerpc/cputable.h | 3 +- include/asm-powerpc/machdep.h | 8 +- include/asm-powerpc/mmu-hash64.h | 140 ++++++++++++++------- include/asm-powerpc/page_64.h | 8 +- include/asm-powerpc/tlbflush.h | 3 +- 23 files changed, 511 insertions(+), 256 deletions(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index fbbd3f6f0064..0ec134034899 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -372,9 +372,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) std r6,PACACURRENT(r13) /* Set new 'current' */ ld r8,KSP(r4) /* new stack pointer */ +BEGIN_FTR_SECTION + b 2f +END_FTR_SECTION_IFCLR(CPU_FTR_SLB) BEGIN_FTR_SECTION clrrdi r6,r8,28 /* get its ESID */ clrrdi r9,r1,28 /* get current sp ESID */ +END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) +BEGIN_FTR_SECTION + clrrdi r6,r8,40 /* get its 1T ESID */ + clrrdi r9,r1,40 /* get current sp 1T ESID */ +END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) clrldi. r0,r6,2 /* is new ESID c00000000? */ cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ cror eq,4*cr1+eq,eq @@ -384,6 +392,11 @@ BEGIN_FTR_SECTION ld r7,KSP_VSID(r4) /* Get new stack's VSID */ oris r0,r6,(SLB_ESID_V)@h ori r0,r0,(SLB_NUM_BOLTED-1)@l +BEGIN_FTR_SECTION + li r9,MMU_SEGSIZE_1T /* insert B field */ + oris r6,r6,(MMU_SEGSIZE_1T << SLBIE_SSIZE_SHIFT)@h + rldimi r7,r9,SLB_VSID_SSIZE_SHIFT,0 +END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) /* Update the last bolted SLB. No write barriers are needed * here, provided we only update the current CPU's SLB shadow @@ -401,7 +414,6 @@ BEGIN_FTR_SECTION isync 2: -END_FTR_SECTION_IFSET(CPU_FTR_SLB) clrrdi r7,r8,THREAD_SHIFT /* base of new stack */ /* Note: this uses SWITCH_FRAME_SIZE rather than INT_FRAME_SIZE because we don't need to leave the 288-byte ABI gap at the diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 22ac245bd59a..97c5857faf00 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -935,7 +935,7 @@ _GLOBAL(do_stab_bolted) /* Calculate VSID */ /* This is a kernel address, so protovsid = ESID */ - ASM_VSID_SCRAMBLE(r11, r9) + ASM_VSID_SCRAMBLE(r11, r9, 256M) rldic r9,r11,12,16 /* r9 = vsid << 12 */ /* Search the primary group for a free entry */ diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 15998b57767c..7949c203cb89 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -564,10 +564,15 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, #ifdef CONFIG_PPC64 if (cpu_has_feature(CPU_FTR_SLB)) { - unsigned long sp_vsid = get_kernel_vsid(sp); + unsigned long sp_vsid; unsigned long llp = mmu_psize_defs[mmu_linear_psize].sllp; - sp_vsid <<= SLB_VSID_SHIFT; + if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) + sp_vsid = get_kernel_vsid(sp, MMU_SEGSIZE_1T) + << SLB_VSID_SHIFT_1T; + else + sp_vsid = get_kernel_vsid(sp, MMU_SEGSIZE_256M) + << SLB_VSID_SHIFT; sp_vsid |= SLB_VSID_KERNEL | llp; p->thread.ksp_vsid = sp_vsid; } diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 35eabfb50723..ad253b959030 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -54,7 +54,7 @@ /* * _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, - * pte_t *ptep, unsigned long trap, int local) + * pte_t *ptep, unsigned long trap, int local, int ssize) * * Adds a 4K page to the hash table in a segment of 4K pages only */ @@ -66,6 +66,7 @@ _GLOBAL(__hash_page_4K) /* Save all params that we need after a function call */ std r6,STK_PARM(r6)(r1) std r8,STK_PARM(r8)(r1) + std r9,STK_PARM(r9)(r1) /* Add _PAGE_PRESENT to access */ ori r4,r4,_PAGE_PRESENT @@ -117,6 +118,10 @@ _GLOBAL(__hash_page_4K) * r4 (access) is re-useable, we use it for the new HPTE flags */ +BEGIN_FTR_SECTION + cmpdi r9,0 /* check segment size */ + bne 3f +END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 rldicl r3,r3,0,36 @@ -126,9 +131,20 @@ _GLOBAL(__hash_page_4K) rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ rldicl r0,r3,64-12,48 /* (ea >> 12) & 0xffff */ xor r28,r5,r0 + b 4f + +3: /* Calc VA and hash in r29 and r28 for 1T segment */ + sldi r29,r5,40 /* vsid << 40 */ + clrldi r3,r3,24 /* ea & 0xffffffffff */ + rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ + clrldi r5,r5,40 /* vsid & 0xffffff */ + rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */ + xor r28,r28,r5 + or r29,r3,r29 /* VA */ + xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ - andi. r3,r30,0x1fe /* Get basic set of flags */ +4: andi. r3,r30,0x1fe /* Get basic set of flags */ xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */ rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */ rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */ @@ -183,6 +199,7 @@ htab_insert_pte: mr r4,r29 /* Retreive va */ li r7,0 /* !bolted, !secondary */ li r8,MMU_PAGE_4K /* page size */ + ld r9,STK_PARM(r9)(r1) /* segment size */ _GLOBAL(htab_call_hpte_insert1) bl . /* Patched by htab_finish_init() */ cmpdi 0,r3,0 @@ -205,6 +222,7 @@ _GLOBAL(htab_call_hpte_insert1) mr r4,r29 /* Retreive va */ li r7,HPTE_V_SECONDARY /* !bolted, secondary */ li r8,MMU_PAGE_4K /* page size */ + ld r9,STK_PARM(r9)(r1) /* segment size */ _GLOBAL(htab_call_hpte_insert2) bl . /* Patched by htab_finish_init() */ cmpdi 0,r3,0 @@ -273,7 +291,8 @@ htab_modify_pte: /* Call ppc_md.hpte_updatepp */ mr r5,r29 /* va */ li r6,MMU_PAGE_4K /* page size */ - ld r7,STK_PARM(r8)(r1) /* get "local" param */ + ld r7,STK_PARM(r9)(r1) /* segment size */ + ld r8,STK_PARM(r8)(r1) /* get "local" param */ _GLOBAL(htab_call_hpte_updatepp) bl . /* Patched by htab_finish_init() */ @@ -325,6 +344,7 @@ _GLOBAL(__hash_page_4K) /* Save all params that we need after a function call */ std r6,STK_PARM(r6)(r1) std r8,STK_PARM(r8)(r1) + std r9,STK_PARM(r9)(r1) /* Add _PAGE_PRESENT to access */ ori r4,r4,_PAGE_PRESENT @@ -383,18 +403,33 @@ _GLOBAL(__hash_page_4K) /* Load the hidx index */ rldicl r25,r3,64-12,60 +BEGIN_FTR_SECTION + cmpdi r9,0 /* check segment size */ + bne 3f +END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */ rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */ - or r29,r3,r29 /* r29 = va + or r29,r3,r29 /* r29 = va */ /* Calculate hash value for primary slot and store it in r28 */ rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ rldicl r0,r3,64-12,48 /* (ea >> 12) & 0xffff */ xor r28,r5,r0 + b 4f + +3: /* Calc VA and hash in r29 and r28 for 1T segment */ + sldi r29,r5,40 /* vsid << 40 */ + clrldi r3,r3,24 /* ea & 0xffffffffff */ + rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ + clrldi r5,r5,40 /* vsid & 0xffffff */ + rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */ + xor r28,r28,r5 + or r29,r3,r29 /* VA */ + xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ - andi. r3,r30,0x1fe /* Get basic set of flags */ +4: andi. r3,r30,0x1fe /* Get basic set of flags */ xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */ rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */ rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */ @@ -462,6 +497,7 @@ htab_special_pfn: mr r4,r29 /* Retreive va */ li r7,0 /* !bolted, !secondary */ li r8,MMU_PAGE_4K /* page size */ + ld r9,STK_PARM(r9)(r1) /* segment size */ _GLOBAL(htab_call_hpte_insert1) bl . /* patched by htab_finish_init() */ cmpdi 0,r3,0 @@ -488,6 +524,7 @@ _GLOBAL(htab_call_hpte_insert1) mr r4,r29 /* Retreive va */ li r7,HPTE_V_SECONDARY /* !bolted, secondary */ li r8,MMU_PAGE_4K /* page size */ + ld r9,STK_PARM(r9)(r1) /* segment size */ _GLOBAL(htab_call_hpte_insert2) bl . /* patched by htab_finish_init() */ cmpdi 0,r3,0 @@ -586,7 +623,8 @@ htab_modify_pte: /* Call ppc_md.hpte_updatepp */ mr r5,r29 /* va */ li r6,MMU_PAGE_4K /* page size */ - ld r7,STK_PARM(r8)(r1) /* get "local" param */ + ld r7,STK_PARM(r9)(r1) /* segment size */ + ld r8,STK_PARM(r8)(r1) /* get "local" param */ _GLOBAL(htab_call_hpte_updatepp) bl . /* patched by htab_finish_init() */ @@ -634,6 +672,7 @@ _GLOBAL(__hash_page_64K) /* Save all params that we need after a function call */ std r6,STK_PARM(r6)(r1) std r8,STK_PARM(r8)(r1) + std r9,STK_PARM(r9)(r1) /* Add _PAGE_PRESENT to access */ ori r4,r4,_PAGE_PRESENT @@ -690,6 +729,10 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) * r4 (access) is re-useable, we use it for the new HPTE flags */ +BEGIN_FTR_SECTION + cmpdi r9,0 /* check segment size */ + bne 3f +END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 rldicl r3,r3,0,36 @@ -699,9 +742,20 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ rldicl r0,r3,64-16,52 /* (ea >> 16) & 0xfff */ xor r28,r5,r0 + b 4f + +3: /* Calc VA and hash in r29 and r28 for 1T segment */ + sldi r29,r5,40 /* vsid << 40 */ + clrldi r3,r3,24 /* ea & 0xffffffffff */ + rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ + clrldi r5,r5,40 /* vsid & 0xffffff */ + rldicl r0,r3,64-16,40 /* (ea >> 16) & 0xffffff */ + xor r28,r28,r5 + or r29,r3,r29 /* VA */ + xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ - andi. r3,r30,0x1fe /* Get basic set of flags */ +4: andi. r3,r30,0x1fe /* Get basic set of flags */ xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */ rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */ rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */ @@ -756,6 +810,7 @@ ht64_insert_pte: mr r4,r29 /* Retreive va */ li r7,0 /* !bolted, !secondary */ li r8,MMU_PAGE_64K + ld r9,STK_PARM(r9)(r1) /* segment size */ _GLOBAL(ht64_call_hpte_insert1) bl . /* patched by htab_finish_init() */ cmpdi 0,r3,0 @@ -778,6 +833,7 @@ _GLOBAL(ht64_call_hpte_insert1) mr r4,r29 /* Retreive va */ li r7,HPTE_V_SECONDARY /* !bolted, secondary */ li r8,MMU_PAGE_64K + ld r9,STK_PARM(r9)(r1) /* segment size */ _GLOBAL(ht64_call_hpte_insert2) bl . /* patched by htab_finish_init() */ cmpdi 0,r3,0 @@ -846,7 +902,8 @@ ht64_modify_pte: /* Call ppc_md.hpte_updatepp */ mr r5,r29 /* va */ li r6,MMU_PAGE_64K - ld r7,STK_PARM(r8)(r1) /* get "local" param */ + ld r7,STK_PARM(r9)(r1) /* segment size */ + ld r8,STK_PARM(r8)(r1) /* get "local" param */ _GLOBAL(ht64_call_hpte_updatepp) bl . /* patched by htab_finish_init() */ diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 6ba9b47e55af..34e5c0b219b9 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -38,7 +38,7 @@ static DEFINE_SPINLOCK(native_tlbie_lock); -static inline void __tlbie(unsigned long va, unsigned int psize) +static inline void __tlbie(unsigned long va, int psize, int ssize) { unsigned int penc; @@ -48,18 +48,20 @@ static inline void __tlbie(unsigned long va, unsigned int psize) switch (psize) { case MMU_PAGE_4K: va &= ~0xffful; + va |= ssize << 8; asm volatile("tlbie %0,0" : : "r" (va) : "memory"); break; default: penc = mmu_psize_defs[psize].penc; va &= ~((1ul << mmu_psize_defs[psize].shift) - 1); va |= penc << 12; + va |= ssize << 8; asm volatile("tlbie %0,1" : : "r" (va) : "memory"); break; } } -static inline void __tlbiel(unsigned long va, unsigned int psize) +static inline void __tlbiel(unsigned long va, int psize, int ssize) { unsigned int penc; @@ -69,6 +71,7 @@ static inline void __tlbiel(unsigned long va, unsigned int psize) switch (psize) { case MMU_PAGE_4K: va &= ~0xffful; + va |= ssize << 8; asm volatile(".long 0x7c000224 | (%0 << 11) | (0 << 21)" : : "r"(va) : "memory"); break; @@ -76,6 +79,7 @@ static inline void __tlbiel(unsigned long va, unsigned int psize) penc = mmu_psize_defs[psize].penc; va &= ~((1ul << mmu_psize_defs[psize].shift) - 1); va |= penc << 12; + va |= ssize << 8; asm volatile(".long 0x7c000224 | (%0 << 11) | (1 << 21)" : : "r"(va) : "memory"); break; @@ -83,7 +87,7 @@ static inline void __tlbiel(unsigned long va, unsigned int psize) } -static inline void tlbie(unsigned long va, int psize, int local) +static inline void tlbie(unsigned long va, int psize, int ssize, int local) { unsigned int use_local = local && cpu_has_feature(CPU_FTR_TLBIEL); int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); @@ -94,10 +98,10 @@ static inline void tlbie(unsigned long va, int psize, int local) spin_lock(&native_tlbie_lock); asm volatile("ptesync": : :"memory"); if (use_local) { - __tlbiel(va, psize); + __tlbiel(va, psize, ssize); asm volatile("ptesync": : :"memory"); } else { - __tlbie(va, psize); + __tlbie(va, psize, ssize); asm volatile("eieio; tlbsync; ptesync": : :"memory"); } if (lock_tlbie && !use_local) @@ -126,7 +130,7 @@ static inline void native_unlock_hpte(struct hash_pte *hptep) static long native_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long pa, unsigned long rflags, - unsigned long vflags, int psize) + unsigned long vflags, int psize, int ssize) { struct hash_pte *hptep = htab_address + hpte_group; unsigned long hpte_v, hpte_r; @@ -153,7 +157,7 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va, if (i == HPTES_PER_GROUP) return -1; - hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) { @@ -215,13 +219,14 @@ static long native_hpte_remove(unsigned long hpte_group) } static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int psize, int local) + unsigned long va, int psize, int ssize, + int local) { struct hash_pte *hptep = htab_address + slot; unsigned long hpte_v, want_v; int ret = 0; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, ssize); DBG_LOW(" update(va=%016lx, avpnv=%016lx, hash=%016lx, newpp=%x)", va, want_v & HPTE_V_AVPN, slot, newpp); @@ -243,39 +248,32 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, native_unlock_hpte(hptep); /* Ensure it is out of the tlb too. */ - tlbie(va, psize, local); + tlbie(va, psize, ssize, local); return ret; } -static long native_hpte_find(unsigned long va, int psize) +static long native_hpte_find(unsigned long va, int psize, int ssize) { struct hash_pte *hptep; unsigned long hash; - unsigned long i, j; + unsigned long i; long slot; unsigned long want_v, hpte_v; - hash = hpt_hash(va, mmu_psize_defs[psize].shift); - want_v = hpte_encode_v(va, psize); + hash = hpt_hash(va, mmu_psize_defs[psize].shift, ssize); + want_v = hpte_encode_v(va, psize, ssize); - for (j = 0; j < 2; j++) { - slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; - for (i = 0; i < HPTES_PER_GROUP; i++) { - hptep = htab_address + slot; - hpte_v = hptep->v; + /* Bolted mappings are only ever in the primary group */ + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; + for (i = 0; i < HPTES_PER_GROUP; i++) { + hptep = htab_address + slot; + hpte_v = hptep->v; - if (HPTE_V_COMPARE(hpte_v, want_v) - && (hpte_v & HPTE_V_VALID) - && ( !!(hpte_v & HPTE_V_SECONDARY) == j)) { - /* HPTE matches */ - if (j) - slot = -slot; - return slot; - } - ++slot; - } - hash = ~hash; + if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) + /* HPTE matches */ + return slot; + ++slot; } return -1; @@ -289,16 +287,16 @@ static long native_hpte_find(unsigned long va, int psize) * No need to lock here because we should be the only user. */ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { unsigned long vsid, va; long slot; struct hash_pte *hptep; - vsid = get_kernel_vsid(ea); - va = (vsid << 28) | (ea & 0x0fffffff); + vsid = get_kernel_vsid(ea, ssize); + va = hpt_va(ea, vsid, ssize); - slot = native_hpte_find(va, psize); + slot = native_hpte_find(va, psize, ssize); if (slot == -1) panic("could not find page to bolt\n"); hptep = htab_address + slot; @@ -308,11 +306,11 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, (newpp & (HPTE_R_PP | HPTE_R_N)); /* Ensure it is out of the tlb too. */ - tlbie(va, psize, 0); + tlbie(va, psize, ssize, 0); } static void native_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { struct hash_pte *hptep = htab_address + slot; unsigned long hpte_v; @@ -323,7 +321,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, DBG_LOW(" invalidate(va=%016lx, hash: %x)\n", va, slot); - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, ssize); native_lock_hpte(hptep); hpte_v = hptep->v; @@ -335,7 +333,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, hptep->v = 0; /* Invalidate the TLB */ - tlbie(va, psize, local); + tlbie(va, psize, ssize, local); local_irq_restore(flags); } @@ -345,7 +343,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, #define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT) static void hpte_decode(struct hash_pte *hpte, unsigned long slot, - int *psize, unsigned long *va) + int *psize, int *ssize, unsigned long *va) { unsigned long hpte_r = hpte->r; unsigned long hpte_v = hpte->v; @@ -401,6 +399,7 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot, *va = avpn; *psize = size; + *ssize = hpte_v >> HPTE_V_SSIZE_SHIFT; } /* @@ -417,7 +416,7 @@ static void native_hpte_clear(void) struct hash_pte *hptep = htab_address; unsigned long hpte_v, va; unsigned long pteg_count; - int psize; + int psize, ssize; pteg_count = htab_hash_mask + 1; @@ -443,9 +442,9 @@ static void native_hpte_clear(void) * already hold the native_tlbie_lock. */ if (hpte_v & HPTE_V_VALID) { - hpte_decode(hptep, slot, &psize, &va); + hpte_decode(hptep, slot, &psize, &ssize, &va); hptep->v = 0; - __tlbie(va, psize); + __tlbie(va, psize, ssize); } } @@ -468,6 +467,7 @@ static void native_flush_hash_range(unsigned long number, int local) real_pte_t pte; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); unsigned long psize = batch->psize; + int ssize = batch->ssize; int i; local_irq_save(flags); @@ -477,14 +477,14 @@ static void native_flush_hash_range(unsigned long number, int local) pte = batch->pte[i]; pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - hash = hpt_hash(va, shift); + hash = hpt_hash(va, shift, ssize); hidx = __rpte_to_hidx(pte, index); if (hidx & _PTEIDX_SECONDARY) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += hidx & _PTEIDX_GROUP_IX; hptep = htab_address + slot; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, ssize); native_lock_hpte(hptep); hpte_v = hptep->v; if (!HPTE_V_COMPARE(hpte_v, want_v) || @@ -504,7 +504,7 @@ static void native_flush_hash_range(unsigned long number, int local) pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - __tlbiel(va, psize); + __tlbiel(va, psize, ssize); } pte_iterate_hashed_end(); } asm volatile("ptesync":::"memory"); @@ -521,7 +521,7 @@ static void native_flush_hash_range(unsigned long number, int local) pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - __tlbie(va, psize); + __tlbie(va, psize, ssize); } pte_iterate_hashed_end(); } asm volatile("eieio; tlbsync; ptesync":::"memory"); diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index d525f2eba313..611ad084b7e7 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -93,6 +93,8 @@ int mmu_linear_psize = MMU_PAGE_4K; int mmu_virtual_psize = MMU_PAGE_4K; int mmu_vmalloc_psize = MMU_PAGE_4K; int mmu_io_psize = MMU_PAGE_4K; +int mmu_kernel_ssize = MMU_SEGSIZE_256M; +int mmu_highuser_ssize = MMU_SEGSIZE_256M; #ifdef CONFIG_HUGETLB_PAGE int mmu_huge_psize = MMU_PAGE_16M; unsigned int HPAGE_SHIFT; @@ -145,7 +147,8 @@ struct mmu_psize_def mmu_psize_defaults_gp[] = { int htab_bolt_mapping(unsigned long vstart, unsigned long vend, - unsigned long pstart, unsigned long mode, int psize) + unsigned long pstart, unsigned long mode, + int psize, int ssize) { unsigned long vaddr, paddr; unsigned int step, shift; @@ -158,8 +161,8 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, for (vaddr = vstart, paddr = pstart; vaddr < vend; vaddr += step, paddr += step) { unsigned long hash, hpteg; - unsigned long vsid = get_kernel_vsid(vaddr); - unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); + unsigned long vsid = get_kernel_vsid(vaddr, ssize); + unsigned long va = hpt_va(vaddr, vsid, ssize); tmp_mode = mode; @@ -167,14 +170,14 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, if (!in_kernel_text(vaddr)) tmp_mode = mode | HPTE_R_N; - hash = hpt_hash(va, shift); + hash = hpt_hash(va, shift, ssize); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); DBG("htab_bolt_mapping: calling %p\n", ppc_md.hpte_insert); BUG_ON(!ppc_md.hpte_insert); ret = ppc_md.hpte_insert(hpteg, va, paddr, - tmp_mode, HPTE_V_BOLTED, psize); + tmp_mode, HPTE_V_BOLTED, psize, ssize); if (ret < 0) break; @@ -186,6 +189,37 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, return ret < 0 ? ret : 0; } +static int __init htab_dt_scan_seg_sizes(unsigned long node, + const char *uname, int depth, + void *data) +{ + char *type = of_get_flat_dt_prop(node, "device_type", NULL); + u32 *prop; + unsigned long size = 0; + + /* We are scanning "cpu" nodes only */ + if (type == NULL || strcmp(type, "cpu") != 0) + return 0; + + prop = (u32 *)of_get_flat_dt_prop(node, "ibm,processor-segment-sizes", + &size); + if (prop == NULL) + return 0; + for (; size >= 4; size -= 4, ++prop) { + if (prop[0] == 40) { + DBG("1T segment support detected\n"); + cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT; + } + return 1; + } + return 0; +} + +static void __init htab_init_seg_sizes(void) +{ + of_scan_flat_dt(htab_dt_scan_seg_sizes, NULL); +} + static int __init htab_dt_scan_page_sizes(unsigned long node, const char *uname, int depth, void *data) @@ -265,7 +299,6 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, return 0; } - static void __init htab_init_page_sizes(void) { int rc; @@ -398,7 +431,7 @@ void create_section_mapping(unsigned long start, unsigned long end) { BUG_ON(htab_bolt_mapping(start, end, __pa(start), _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX, - mmu_linear_psize)); + mmu_linear_psize, mmu_kernel_ssize)); } #endif /* CONFIG_MEMORY_HOTPLUG */ @@ -449,9 +482,18 @@ void __init htab_initialize(void) DBG(" -> htab_initialize()\n"); + /* Initialize segment sizes */ + htab_init_seg_sizes(); + /* Initialize page sizes */ htab_init_page_sizes(); + if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { + mmu_kernel_ssize = MMU_SEGSIZE_1T; + mmu_highuser_ssize = MMU_SEGSIZE_1T; + printk(KERN_INFO "Using 1TB segments\n"); + } + /* * Calculate the required size of the htab. We want the number of * PTEGs to equal one half the number of real pages. @@ -523,18 +565,20 @@ void __init htab_initialize(void) if (base != dart_tablebase) BUG_ON(htab_bolt_mapping(base, dart_tablebase, __pa(base), mode_rw, - mmu_linear_psize)); + mmu_linear_psize, + mmu_kernel_ssize)); if ((base + size) > dart_table_end) BUG_ON(htab_bolt_mapping(dart_tablebase+16*MB, base + size, __pa(dart_table_end), mode_rw, - mmu_linear_psize)); + mmu_linear_psize, + mmu_kernel_ssize)); continue; } #endif /* CONFIG_U3_DART */ BUG_ON(htab_bolt_mapping(base, base + size, __pa(base), - mode_rw, mmu_linear_psize)); + mode_rw, mmu_linear_psize, mmu_kernel_ssize)); } /* @@ -553,7 +597,7 @@ void __init htab_initialize(void) BUG_ON(htab_bolt_mapping(tce_alloc_start, tce_alloc_end, __pa(tce_alloc_start), mode_rw, - mmu_linear_psize)); + mmu_linear_psize, mmu_kernel_ssize)); } htab_finish_init(); @@ -621,7 +665,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) pte_t *ptep; cpumask_t tmp; int rc, user_region = 0, local = 0; - int psize; + int psize, ssize; DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", ea, access, trap); @@ -640,20 +684,22 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) DBG_LOW(" user region with no mm !\n"); return 1; } - vsid = get_vsid(mm->context.id, ea); #ifdef CONFIG_PPC_MM_SLICES psize = get_slice_psize(mm, ea); #else psize = mm->context.user_psize; #endif + ssize = user_segment_size(ea); + vsid = get_vsid(mm->context.id, ea, ssize); break; case VMALLOC_REGION_ID: mm = &init_mm; - vsid = get_kernel_vsid(ea); + vsid = get_kernel_vsid(ea, mmu_kernel_ssize); if (ea < VMALLOC_END) psize = mmu_vmalloc_psize; else psize = mmu_io_psize; + ssize = mmu_kernel_ssize; break; default: /* Not a valid range @@ -758,10 +804,10 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) #ifdef CONFIG_PPC_HAS_HASH_64K if (psize == MMU_PAGE_64K) - rc = __hash_page_64K(ea, access, vsid, ptep, trap, local); + rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); else #endif /* CONFIG_PPC_HAS_HASH_64K */ - rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); + rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize); #ifndef CONFIG_PPC_64K_PAGES DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep)); @@ -783,6 +829,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, cpumask_t mask; unsigned long flags; int local = 0; + int ssize; BUG_ON(REGION_ID(ea) != USER_REGION_ID); @@ -815,7 +862,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, #endif /* CONFIG_PPC_64K_PAGES */ /* Get VSID */ - vsid = get_vsid(mm->context.id, ea); + ssize = user_segment_size(ea); + vsid = get_vsid(mm->context.id, ea, ssize); /* Hash doesn't like irqs */ local_irq_save(flags); @@ -828,28 +876,29 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, /* Hash it in */ #ifdef CONFIG_PPC_HAS_HASH_64K if (mm->context.user_psize == MMU_PAGE_64K) - __hash_page_64K(ea, access, vsid, ptep, trap, local); + __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); else #endif /* CONFIG_PPC_HAS_HASH_64K */ - __hash_page_4K(ea, access, vsid, ptep, trap, local); + __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize); local_irq_restore(flags); } -void flush_hash_page(unsigned long va, real_pte_t pte, int psize, int local) +void flush_hash_page(unsigned long va, real_pte_t pte, int psize, int ssize, + int local) { unsigned long hash, index, shift, hidx, slot; DBG_LOW("flush_hash_page(va=%016x)\n", va); pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - hash = hpt_hash(va, shift); + hash = hpt_hash(va, shift, ssize); hidx = __rpte_to_hidx(pte, index); if (hidx & _PTEIDX_SECONDARY) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += hidx & _PTEIDX_GROUP_IX; DBG_LOW(" sub %d: hash=%x, hidx=%x\n", index, slot, hidx); - ppc_md.hpte_invalidate(slot, va, psize, local); + ppc_md.hpte_invalidate(slot, va, psize, ssize, local); } pte_iterate_hashed_end(); } @@ -864,7 +913,7 @@ void flush_hash_range(unsigned long number, int local) for (i = 0; i < number; i++) flush_hash_page(batch->vaddr[i], batch->pte[i], - batch->psize, local); + batch->psize, batch->ssize, local); } } @@ -890,17 +939,19 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address) #ifdef CONFIG_DEBUG_PAGEALLOC static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) { - unsigned long hash, hpteg, vsid = get_kernel_vsid(vaddr); - unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); + unsigned long hash, hpteg; + unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); + unsigned long va = hpt_va(vaddr, vsid, mmu_kernel_ssize); unsigned long mode = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX | HPTE_R_N; int ret; - hash = hpt_hash(va, PAGE_SHIFT); + hash = hpt_hash(va, PAGE_SHIFT, mmu_kernel_ssize); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr), - mode, HPTE_V_BOLTED, mmu_linear_psize); + mode, HPTE_V_BOLTED, + mmu_linear_psize, mmu_kernel_ssize); BUG_ON (ret < 0); spin_lock(&linear_map_hash_lock); BUG_ON(linear_map_hash_slots[lmi] & 0x80); @@ -910,10 +961,11 @@ static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) { - unsigned long hash, hidx, slot, vsid = get_kernel_vsid(vaddr); - unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); + unsigned long hash, hidx, slot; + unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); + unsigned long va = hpt_va(vaddr, vsid, mmu_kernel_ssize); - hash = hpt_hash(va, PAGE_SHIFT); + hash = hpt_hash(va, PAGE_SHIFT, mmu_kernel_ssize); spin_lock(&linear_map_hash_lock); BUG_ON(!(linear_map_hash_slots[lmi] & 0x80)); hidx = linear_map_hash_slots[lmi] & 0x7f; @@ -923,7 +975,7 @@ static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += hidx & _PTEIDX_GROUP_IX; - ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, 0); + ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, mmu_kernel_ssize, 0); } void kernel_map_pages(struct page *page, int numpages, int enable) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index ba5f12a60467..08f0d9ff7712 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -403,11 +403,12 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access, unsigned long va, rflags, pa; long slot; int err = 1; + int ssize = user_segment_size(ea); ptep = huge_pte_offset(mm, ea); /* Search the Linux page table for a match with va */ - va = (vsid << 28) | (ea & 0x0fffffff); + va = hpt_va(ea, vsid, ssize); /* * If no pte found or not present, send the problem up to @@ -458,19 +459,19 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access, /* There MIGHT be an HPTE for this pte */ unsigned long hash, slot; - hash = hpt_hash(va, HPAGE_SHIFT); + hash = hpt_hash(va, HPAGE_SHIFT, ssize); if (old_pte & _PAGE_F_SECOND) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += (old_pte & _PAGE_F_GIX) >> 12; if (ppc_md.hpte_updatepp(slot, rflags, va, mmu_huge_psize, - local) == -1) + ssize, local) == -1) old_pte &= ~_PAGE_HPTEFLAGS; } if (likely(!(old_pte & _PAGE_HASHPTE))) { - unsigned long hash = hpt_hash(va, HPAGE_SHIFT); + unsigned long hash = hpt_hash(va, HPAGE_SHIFT, ssize); unsigned long hpte_group; pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT; @@ -489,7 +490,7 @@ repeat: /* Insert into the hash table, primary slot */ slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, 0, - mmu_huge_psize); + mmu_huge_psize, ssize); /* Primary is full, try the secondary */ if (unlikely(slot == -1)) { @@ -497,7 +498,7 @@ repeat: HPTES_PER_GROUP) & ~0x7UL; slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, HPTE_V_SECONDARY, - mmu_huge_psize); + mmu_huge_psize, ssize); if (slot == -1) { if (mftb() & 0x1) hpte_group = ((hash & htab_hash_mask) * diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 60fd52cd270f..3ef0ad2f9ca0 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -87,8 +87,8 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags) * entry in the hardware page table. * */ - if (htab_bolt_mapping(ea, (unsigned long)ea + PAGE_SIZE, - pa, flags, mmu_io_psize)) { + if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags, + mmu_io_psize, mmu_kernel_ssize)) { printk(KERN_ERR "Failed to do bolted mapping IO " "memory at %016lx !\n", pa); return -ENOMEM; diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 4bee1cfa9dea..6c164cec9d2c 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -43,17 +43,26 @@ static void slb_allocate(unsigned long ea) slb_allocate_realmode(ea); } -static inline unsigned long mk_esid_data(unsigned long ea, unsigned long slot) +static inline unsigned long mk_esid_data(unsigned long ea, int ssize, + unsigned long slot) { - return (ea & ESID_MASK) | SLB_ESID_V | slot; + unsigned long mask; + + mask = (ssize == MMU_SEGSIZE_256M)? ESID_MASK: ESID_MASK_1T; + return (ea & mask) | SLB_ESID_V | slot; } -static inline unsigned long mk_vsid_data(unsigned long ea, unsigned long flags) +#define slb_vsid_shift(ssize) \ + ((ssize) == MMU_SEGSIZE_256M? SLB_VSID_SHIFT: SLB_VSID_SHIFT_1T) + +static inline unsigned long mk_vsid_data(unsigned long ea, int ssize, + unsigned long flags) { - return (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | flags; + return (get_kernel_vsid(ea, ssize) << slb_vsid_shift(ssize)) | flags | + ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); } -static inline void slb_shadow_update(unsigned long ea, +static inline void slb_shadow_update(unsigned long ea, int ssize, unsigned long flags, unsigned long entry) { @@ -63,8 +72,8 @@ static inline void slb_shadow_update(unsigned long ea, * we only update the current CPU's SLB shadow buffer. */ get_slb_shadow()->save_area[entry].esid = 0; - get_slb_shadow()->save_area[entry].vsid = mk_vsid_data(ea, flags); - get_slb_shadow()->save_area[entry].esid = mk_esid_data(ea, entry); + get_slb_shadow()->save_area[entry].vsid = mk_vsid_data(ea, ssize, flags); + get_slb_shadow()->save_area[entry].esid = mk_esid_data(ea, ssize, entry); } static inline void slb_shadow_clear(unsigned long entry) @@ -72,7 +81,8 @@ static inline void slb_shadow_clear(unsigned long entry) get_slb_shadow()->save_area[entry].esid = 0; } -static inline void create_shadowed_slbe(unsigned long ea, unsigned long flags, +static inline void create_shadowed_slbe(unsigned long ea, int ssize, + unsigned long flags, unsigned long entry) { /* @@ -80,11 +90,11 @@ static inline void create_shadowed_slbe(unsigned long ea, unsigned long flags, * we don't get a stale entry here if we get preempted by PHYP * between these two statements. */ - slb_shadow_update(ea, flags, entry); + slb_shadow_update(ea, ssize, flags, entry); asm volatile("slbmte %0,%1" : - : "r" (mk_vsid_data(ea, flags)), - "r" (mk_esid_data(ea, entry)) + : "r" (mk_vsid_data(ea, ssize, flags)), + "r" (mk_esid_data(ea, ssize, entry)) : "memory" ); } @@ -93,7 +103,7 @@ 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; + unsigned long ksp_esid_data, ksp_vsid_data; WARN_ON(!irqs_disabled()); @@ -102,13 +112,15 @@ void slb_flush_and_rebolt(void) lflags = SLB_VSID_KERNEL | linear_llp; vflags = SLB_VSID_KERNEL | vmalloc_llp; - ksp_esid_data = mk_esid_data(get_paca()->kstack, 2); - if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET) { + ksp_esid_data = mk_esid_data(get_paca()->kstack, mmu_kernel_ssize, 2); + if ((ksp_esid_data & ~0xfffffffUL) <= PAGE_OFFSET) { ksp_esid_data &= ~SLB_ESID_V; + ksp_vsid_data = 0; slb_shadow_clear(2); } else { /* Update stack entry; others don't change */ - slb_shadow_update(get_paca()->kstack, lflags, 2); + slb_shadow_update(get_paca()->kstack, mmu_kernel_ssize, lflags, 2); + ksp_vsid_data = get_slb_shadow()->save_area[2].vsid; } /* We need to do this all in asm, so we're sure we don't touch @@ -120,9 +132,9 @@ void slb_flush_and_rebolt(void) /* Slot 2 - kernel stack */ "slbmte %2,%3\n" "isync" - :: "r"(mk_vsid_data(VMALLOC_START, vflags)), - "r"(mk_esid_data(VMALLOC_START, 1)), - "r"(mk_vsid_data(ksp_esid_data, lflags)), + :: "r"(mk_vsid_data(VMALLOC_START, mmu_kernel_ssize, vflags)), + "r"(mk_esid_data(VMALLOC_START, mmu_kernel_ssize, 1)), + "r"(ksp_vsid_data), "r"(ksp_esid_data) : "memory"); } @@ -132,7 +144,7 @@ void slb_vmalloc_update(void) unsigned long vflags; vflags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_vmalloc_psize].sllp; - slb_shadow_update(VMALLOC_START, vflags, 1); + slb_shadow_update(VMALLOC_START, mmu_kernel_ssize, vflags, 1); slb_flush_and_rebolt(); } @@ -140,7 +152,7 @@ void slb_vmalloc_update(void) void switch_slb(struct task_struct *tsk, struct mm_struct *mm) { unsigned long offset = get_paca()->slb_cache_ptr; - unsigned long esid_data = 0; + unsigned long slbie_data = 0; unsigned long pc = KSTK_EIP(tsk); unsigned long stack = KSTK_ESP(tsk); unsigned long unmapped_base; @@ -149,9 +161,12 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) int i; asm volatile("isync" : : : "memory"); for (i = 0; i < offset; i++) { - esid_data = ((unsigned long)get_paca()->slb_cache[i] - << SID_SHIFT) | SLBIE_C; - asm volatile("slbie %0" : : "r" (esid_data)); + slbie_data = (unsigned long)get_paca()->slb_cache[i] + << SID_SHIFT; /* EA */ + slbie_data |= user_segment_size(slbie_data) + << SLBIE_SSIZE_SHIFT; + slbie_data |= SLBIE_C; /* C set for user addresses */ + asm volatile("slbie %0" : : "r" (slbie_data)); } asm volatile("isync" : : : "memory"); } else { @@ -160,7 +175,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) /* Workaround POWER5 < DD2.1 issue */ if (offset == 1 || offset > SLB_CACHE_ENTRIES) - asm volatile("slbie %0" : : "r" (esid_data)); + asm volatile("slbie %0" : : "r" (slbie_data)); get_paca()->slb_cache_ptr = 0; get_paca()->context = mm->context; @@ -243,9 +258,9 @@ void slb_initialize(void) asm volatile("isync":::"memory"); asm volatile("slbmte %0,%0"::"r" (0) : "memory"); asm volatile("isync; slbia; isync":::"memory"); - create_shadowed_slbe(PAGE_OFFSET, lflags, 0); + create_shadowed_slbe(PAGE_OFFSET, mmu_kernel_ssize, lflags, 0); - create_shadowed_slbe(VMALLOC_START, vflags, 1); + create_shadowed_slbe(VMALLOC_START, mmu_kernel_ssize, vflags, 1); /* We don't bolt the stack for the time being - we're in boot, * so the stack is in the bolted segment. By the time it goes diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index cd1a93d4948c..1328a81a84aa 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -57,7 +57,10 @@ _GLOBAL(slb_allocate_realmode) */ _GLOBAL(slb_miss_kernel_load_linear) li r11,0 +BEGIN_FTR_SECTION b slb_finish_load +END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) + b slb_finish_load_1T 1: /* vmalloc/ioremap mapping encoding bits, the "li" instructions below * will be patched by the kernel at boot @@ -68,13 +71,16 @@ BEGIN_FTR_SECTION cmpldi r11,(VMALLOC_SIZE >> 28) - 1 bgt 5f lhz r11,PACAVMALLOCSLLP(r13) - b slb_finish_load + b 6f 5: END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) _GLOBAL(slb_miss_kernel_load_io) li r11,0 +6: +BEGIN_FTR_SECTION b slb_finish_load - +END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) + b slb_finish_load_1T 0: /* user address: proto-VSID = context << 15 | ESID. First check * if the address is within the boundaries of the user region @@ -122,7 +128,13 @@ _GLOBAL(slb_miss_kernel_load_io) #endif /* CONFIG_PPC_MM_SLICES */ ld r9,PACACONTEXTID(r13) +BEGIN_FTR_SECTION + cmpldi r10,0x1000 +END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) rldimi r10,r9,USER_ESID_BITS,0 +BEGIN_FTR_SECTION + bge slb_finish_load_1T +END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) b slb_finish_load 8: /* invalid EA */ @@ -188,7 +200,7 @@ _GLOBAL(slb_allocate_user) * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET */ slb_finish_load: - ASM_VSID_SCRAMBLE(r10,r9) + ASM_VSID_SCRAMBLE(r10,r9,256M) rldimi r11,r10,SLB_VSID_SHIFT,16 /* combine VSID and flags */ /* r3 = EA, r11 = VSID data */ @@ -213,7 +225,7 @@ BEGIN_FW_FTR_SECTION END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif /* CONFIG_PPC_ISERIES */ - ld r10,PACASTABRR(r13) +7: ld r10,PACASTABRR(r13) addi r10,r10,1 /* use a cpu feature mask if we ever change our slb size */ cmpldi r10,SLB_NUM_ENTRIES @@ -259,3 +271,20 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) crclr 4*cr0+eq /* set result to "success" */ blr +/* + * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. + * We assume legacy iSeries will never have 1T segments. + * + * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9 + */ +slb_finish_load_1T: + srdi r10,r10,40-28 /* get 1T ESID */ + ASM_VSID_SCRAMBLE(r10,r9,1T) + rldimi r11,r10,SLB_VSID_SHIFT_1T,16 /* combine VSID and flags */ + li r10,MMU_SEGSIZE_1T + rldimi r11,r10,SLB_VSID_SSIZE_SHIFT,0 /* insert segment size */ + + /* r3 = EA, r11 = VSID data */ + clrrdi r3,r3,SID_SHIFT_1T /* clear out non-ESID bits */ + b 7b + diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 28492bbdee8e..9e85bda76216 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -122,12 +122,12 @@ static int __ste_allocate(unsigned long ea, struct mm_struct *mm) /* Kernel or user address? */ if (is_kernel_addr(ea)) { - vsid = get_kernel_vsid(ea); + vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); } else { if ((ea >= TASK_SIZE_USER64) || (! mm)) return 1; - vsid = get_vsid(mm->context.id, ea); + vsid = get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M); } stab_entry = make_ste(get_paca()->stab_addr, GET_ESID(ea), vsid); @@ -261,7 +261,7 @@ void __init stabs_alloc(void) */ void stab_initialize(unsigned long stab) { - unsigned long vsid = get_kernel_vsid(PAGE_OFFSET); + unsigned long vsid = get_kernel_vsid(PAGE_OFFSET, MMU_SEGSIZE_256M); unsigned long stabreal; asm volatile("isync; slbia; isync":::"memory"); diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c index cbd34fc813ee..eafbca52bff9 100644 --- a/arch/powerpc/mm/tlb_64.c +++ b/arch/powerpc/mm/tlb_64.c @@ -132,6 +132,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); unsigned long vsid, vaddr; unsigned int psize; + int ssize; real_pte_t rpte; int i; @@ -161,11 +162,14 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, /* Build full vaddr */ if (!is_kernel_addr(addr)) { - vsid = get_vsid(mm->context.id, addr); + ssize = user_segment_size(addr); + vsid = get_vsid(mm->context.id, addr, ssize); WARN_ON(vsid == 0); - } else - vsid = get_kernel_vsid(addr); - vaddr = (vsid << 28 ) | (addr & 0x0fffffff); + } else { + vsid = get_kernel_vsid(addr, mmu_kernel_ssize); + ssize = mmu_kernel_ssize; + } + vaddr = hpt_va(addr, vsid, ssize); rpte = __real_pte(__pte(pte), ptep); /* @@ -175,7 +179,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, * and decide to use local invalidates instead... */ if (!batch->active) { - flush_hash_page(vaddr, rpte, psize, 0); + flush_hash_page(vaddr, rpte, psize, ssize, 0); return; } @@ -189,13 +193,15 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, * We also need to ensure only one page size is present in a given * batch */ - if (i != 0 && (mm != batch->mm || batch->psize != psize)) { + if (i != 0 && (mm != batch->mm || batch->psize != psize || + batch->ssize != ssize)) { __flush_tlb_pending(batch); i = 0; } if (i == 0) { batch->mm = mm; batch->psize = psize; + batch->ssize = ssize; } batch->pte[i] = rpte; batch->vaddr[i] = vaddr; @@ -222,7 +228,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch) local = 1; if (i == 1) flush_hash_page(batch->vaddr[0], batch->pte[0], - batch->psize, local); + batch->psize, batch->ssize, local); else flush_hash_range(i, local); batch->index = 0; diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index b5a21177bb32..c83c3e3f5178 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -168,7 +168,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) #else psize = mm->context.user_psize; #endif - vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | + vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_USER; break; case VMALLOC_REGION_ID: @@ -176,12 +176,12 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) psize = mmu_vmalloc_psize; else psize = mmu_io_psize; - vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | + vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL; break; case KERNEL_REGION_ID: psize = mmu_linear_psize; - vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | + vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL; break; default: diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index de7e5ee451d2..3d64c81cc6e2 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -699,7 +699,7 @@ static inline void get_kernel_slb(u64 ea, u64 slb[2]) llp = mmu_psize_defs[mmu_linear_psize].sllp; else llp = mmu_psize_defs[mmu_virtual_psize].sllp; - slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | + slb[0] = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL | llp; slb[1] = (ea & ESID_MASK) | SLB_ESID_V; } diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/celleb/htab.c index 5e75c77ea8f3..fbf27c74ebda 100644 --- a/arch/powerpc/platforms/celleb/htab.c +++ b/arch/powerpc/platforms/celleb/htab.c @@ -90,7 +90,7 @@ static inline unsigned int beat_read_mask(unsigned hpte_group) static long beat_lpar_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long pa, unsigned long rflags, unsigned long vflags, - int psize) + int psize, int ssize) { unsigned long lpar_rc; unsigned long slot; @@ -105,7 +105,8 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, "rflags=%lx, vflags=%lx, psize=%d)\n", hpte_group, va, pa, rflags, vflags, psize); - hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) @@ -184,12 +185,12 @@ static void beat_lpar_hptab_clear(void) static long beat_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long lpar_rc; unsigned long dummy0, dummy1, want_v; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); DBG_LOW(" update: " "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", @@ -225,8 +226,8 @@ static long beat_lpar_hpte_find(unsigned long va, int psize) long slot; unsigned long want_v, hpte_v; - hash = hpt_hash(va, mmu_psize_defs[psize].shift); - want_v = hpte_encode_v(va, psize); + hash = hpt_hash(va, mmu_psize_defs[psize].shift, MMU_SEGSIZE_256M); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); for (j = 0; j < 2; j++) { slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; @@ -251,11 +252,11 @@ static long beat_lpar_hpte_find(unsigned long va, int psize) static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1; - vsid = get_kernel_vsid(ea); + vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); va = (vsid << 28) | (ea & 0x0fffffff); spin_lock(&beat_htab_lock); @@ -270,7 +271,7 @@ static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, } static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long want_v; unsigned long lpar_rc; @@ -279,7 +280,7 @@ static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", slot, va, psize, local); - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); spin_lock_irqsave(&beat_htab_lock, flags); dummy1 = beat_lpar_hpte_getword0(slot); @@ -310,7 +311,7 @@ void __init hpte_init_beat(void) static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, unsigned long va, unsigned long pa, unsigned long rflags, unsigned long vflags, - int psize) + int psize, int ssize) { unsigned long lpar_rc; unsigned long slot; @@ -325,7 +326,8 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, "rflags=%lx, vflags=%lx, psize=%d)\n", hpte_group, va, pa, rflags, vflags, psize); - hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) @@ -363,13 +365,13 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, static long beat_lpar_hpte_updatepp_v3(unsigned long slot, unsigned long newpp, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long lpar_rc; unsigned long want_v; unsigned long pss; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc; DBG_LOW(" update: " @@ -391,7 +393,7 @@ static long beat_lpar_hpte_updatepp_v3(unsigned long slot, } static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long want_v; unsigned long lpar_rc; @@ -399,7 +401,7 @@ static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long va, DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", slot, va, psize, local); - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc; lpar_rc = beat_invalidate_htab_entry3(0, slot, want_v, pss); diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c index b4e2c7a038e1..15a7097e5dd7 100644 --- a/arch/powerpc/platforms/iseries/htab.c +++ b/arch/powerpc/platforms/iseries/htab.c @@ -86,7 +86,8 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, } - lhpte.v = hpte_encode_v(va, MMU_PAGE_4K) | vflags | HPTE_V_VALID; + lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags; /* Now fill in the actual HPTE */ @@ -142,7 +143,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group) * bits 61..63 : PP2,PP1,PP0 */ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int psize, int local) + unsigned long va, int psize, int ssize, int local) { struct hash_pte hpte; unsigned long want_v; @@ -150,7 +151,7 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, iSeries_hlock(slot); HvCallHpt_get(&hpte, slot); - want_v = hpte_encode_v(va, MMU_PAGE_4K); + want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M); if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) { /* @@ -205,14 +206,14 @@ static long iSeries_hpte_find(unsigned long vpn) * No need to lock here because we should be the only user. */ static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { unsigned long vsid,va,vpn; long slot; BUG_ON(psize != MMU_PAGE_4K); - vsid = get_kernel_vsid(ea); + vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); va = (vsid << 28) | (ea & 0x0fffffff); vpn = va >> HW_PAGE_SHIFT; slot = iSeries_hpte_find(vpn); @@ -222,7 +223,7 @@ static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, } static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long hpte_v; unsigned long avpn = va >> 23; diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 5d2e176a1b18..7382f195c4f8 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -60,7 +60,8 @@ static void _debug_dump_hpte(unsigned long pa, unsigned long va, } static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, - unsigned long pa, unsigned long rflags, unsigned long vflags, int psize) + unsigned long pa, unsigned long rflags, unsigned long vflags, + int psize, int ssize) { unsigned long slot; struct hash_pte lhpte; @@ -72,7 +73,8 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, vflags &= ~HPTE_V_SECONDARY; /* this bit is ignored */ - lhpte.v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + lhpte.v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; lhpte.r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags; p_pteg = hpte_group / HPTES_PER_GROUP; @@ -167,14 +169,14 @@ static long ps3_hpte_remove(unsigned long hpte_group) } static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int psize, int local) + unsigned long va, int psize, int ssize, int local) { unsigned long flags; unsigned long result; unsigned long pteg, bit; unsigned long hpte_v, want_v; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); spin_lock_irqsave(&ps3_bolttab_lock, flags); @@ -205,13 +207,13 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, } static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { panic("ps3_hpte_updateboltedpp() not implemented"); } static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long flags; unsigned long result; diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index ea327ca345c6..9a455d46379d 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -284,7 +284,7 @@ void vpa_init(int cpu) static long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long pa, unsigned long rflags, unsigned long vflags, - int psize) + int psize, int ssize) { unsigned long lpar_rc; unsigned long flags; @@ -296,7 +296,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, "rflags=%lx, vflags=%lx, psize=%d)\n", hpte_group, va, pa, rflags, vflags, psize); - hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) @@ -391,6 +391,22 @@ static void pSeries_lpar_hptab_clear(void) } } +/* + * This computes the AVPN and B fields of the first dword of a HPTE, + * for use when we want to match an existing PTE. The bottom 7 bits + * of the returned value are zero. + */ +static inline unsigned long hpte_encode_avpn(unsigned long va, int psize, + int ssize) +{ + unsigned long v; + + v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm); + v <<= HPTE_V_AVPN_SHIFT; + v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT; + return v; +} + /* * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and * the low 3 bits of flags happen to line up. So no transform is needed. @@ -400,18 +416,18 @@ static void pSeries_lpar_hptab_clear(void) static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long lpar_rc; unsigned long flags = (newpp & 7) | H_AVPN; unsigned long want_v; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_avpn(va, psize, ssize); DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ", - want_v & HPTE_V_AVPN, slot, flags, psize); + want_v, slot, flags, psize); - lpar_rc = plpar_pte_protect(flags, slot, want_v & HPTE_V_AVPN); + lpar_rc = plpar_pte_protect(flags, slot, want_v); if (lpar_rc == H_NOT_FOUND) { DBG_LOW("not found !\n"); @@ -444,32 +460,25 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) return dword0; } -static long pSeries_lpar_hpte_find(unsigned long va, int psize) +static long pSeries_lpar_hpte_find(unsigned long va, int psize, int ssize) { unsigned long hash; - unsigned long i, j; + unsigned long i; long slot; unsigned long want_v, hpte_v; - hash = hpt_hash(va, mmu_psize_defs[psize].shift); - want_v = hpte_encode_v(va, psize); + hash = hpt_hash(va, mmu_psize_defs[psize].shift, ssize); + want_v = hpte_encode_avpn(va, psize, ssize); - for (j = 0; j < 2; j++) { - slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; - for (i = 0; i < HPTES_PER_GROUP; i++) { - hpte_v = pSeries_lpar_hpte_getword0(slot); + /* Bolted entries are always in the primary group */ + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; + for (i = 0; i < HPTES_PER_GROUP; i++) { + hpte_v = pSeries_lpar_hpte_getword0(slot); - if (HPTE_V_COMPARE(hpte_v, want_v) - && (hpte_v & HPTE_V_VALID) - && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { - /* HPTE matches */ - if (j) - slot = -slot; - return slot; - } - ++slot; - } - hash = ~hash; + if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) + /* HPTE matches */ + return slot; + ++slot; } return -1; @@ -477,14 +486,14 @@ static long pSeries_lpar_hpte_find(unsigned long va, int psize) static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { unsigned long lpar_rc, slot, vsid, va, flags; - vsid = get_kernel_vsid(ea); - va = (vsid << 28) | (ea & 0x0fffffff); + vsid = get_kernel_vsid(ea, ssize); + va = hpt_va(ea, vsid, ssize); - slot = pSeries_lpar_hpte_find(va, psize); + slot = pSeries_lpar_hpte_find(va, psize, ssize); BUG_ON(slot == -1); flags = newpp & 7; @@ -494,7 +503,7 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, } static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long want_v; unsigned long lpar_rc; @@ -503,9 +512,8 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d", slot, va, psize, local); - want_v = hpte_encode_v(va, psize); - lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v & HPTE_V_AVPN, - &dummy1, &dummy2); + want_v = hpte_encode_avpn(va, psize, ssize); + lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v, &dummy1, &dummy2); if (lpar_rc == H_NOT_FOUND) return; @@ -533,18 +541,19 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) unsigned long va; unsigned long hash, index, shift, hidx, slot; real_pte_t pte; - int psize; + int psize, ssize; if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); psize = batch->psize; + ssize = batch->ssize; pix = 0; for (i = 0; i < number; i++) { va = batch->vaddr[i]; pte = batch->pte[i]; pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - hash = hpt_hash(va, shift); + hash = hpt_hash(va, shift, ssize); hidx = __rpte_to_hidx(pte, index); if (hidx & _PTEIDX_SECONDARY) hash = ~hash; @@ -552,11 +561,11 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) slot += hidx & _PTEIDX_GROUP_IX; if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { pSeries_lpar_hpte_invalidate(slot, va, psize, - local); + ssize, local); } else { param[pix] = HBR_REQUEST | HBR_AVPN | slot; - param[pix+1] = hpte_encode_v(va, psize) & - HPTE_V_AVPN; + param[pix+1] = hpte_encode_avpn(va, psize, + ssize); pix += 2; if (pix == 8) { rc = plpar_hcall9(H_BULK_REMOVE, param, diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index d913f460e710..ae093ef68363 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -164,6 +164,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, #define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000) #define CPU_FTR_SPURR LONG_ASM_CONST(0x0001000000000000) #define CPU_FTR_DSCR LONG_ASM_CONST(0x0002000000000000) +#define CPU_FTR_1T_SEGMENT LONG_ASM_CONST(0x0004000000000000) #ifndef __ASSEMBLY__ @@ -374,7 +375,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \ - CPU_FTRS_CELL | CPU_FTRS_PA6T) + CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_1T_SEGMENT) #else enum { CPU_FTRS_POSSIBLE = diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index cc7c17f16a9a..6968f4300dca 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -51,22 +51,22 @@ struct machdep_calls { #ifdef CONFIG_PPC64 void (*hpte_invalidate)(unsigned long slot, unsigned long va, - int psize, + int psize, int ssize, int local); long (*hpte_updatepp)(unsigned long slot, unsigned long newpp, unsigned long va, - int pize, + int psize, int ssize, int local); void (*hpte_updateboltedpp)(unsigned long newpp, unsigned long ea, - int psize); + int psize, int ssize); long (*hpte_insert)(unsigned long hpte_group, unsigned long va, unsigned long prpn, unsigned long rflags, unsigned long vflags, - int psize); + int psize, int ssize); long (*hpte_remove)(unsigned long hpte_group); void (*flush_hash_range)(unsigned long number, int local); diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h index b22b0d20e157..82328dec2b52 100644 --- a/include/asm-powerpc/mmu-hash64.h +++ b/include/asm-powerpc/mmu-hash64.h @@ -47,6 +47,8 @@ extern char initial_stab[]; /* Bits in the SLB VSID word */ #define SLB_VSID_SHIFT 12 +#define SLB_VSID_SHIFT_1T 24 +#define SLB_VSID_SSIZE_SHIFT 62 #define SLB_VSID_B ASM_CONST(0xc000000000000000) #define SLB_VSID_B_256M ASM_CONST(0x0000000000000000) #define SLB_VSID_B_1T ASM_CONST(0x4000000000000000) @@ -66,6 +68,7 @@ extern char initial_stab[]; #define SLB_VSID_USER (SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C) #define SLBIE_C (0x08000000) +#define SLBIE_SSIZE_SHIFT 25 /* * Hash table @@ -77,7 +80,7 @@ extern char initial_stab[]; #define HPTE_V_AVPN_SHIFT 7 #define HPTE_V_AVPN ASM_CONST(0x3fffffffffffff80) #define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT) -#define HPTE_V_COMPARE(x,y) (!(((x) ^ (y)) & HPTE_V_AVPN)) +#define HPTE_V_COMPARE(x,y) (!(((x) ^ (y)) & 0xffffffffffffff80)) #define HPTE_V_BOLTED ASM_CONST(0x0000000000000010) #define HPTE_V_LOCK ASM_CONST(0x0000000000000008) #define HPTE_V_LARGE ASM_CONST(0x0000000000000004) @@ -164,16 +167,19 @@ struct mmu_psize_def #define MMU_SEGSIZE_256M 0 #define MMU_SEGSIZE_1T 1 + #ifndef __ASSEMBLY__ /* - * The current system page sizes + * The current system page and segment sizes */ extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; extern int mmu_linear_psize; extern int mmu_virtual_psize; extern int mmu_vmalloc_psize; extern int mmu_io_psize; +extern int mmu_kernel_ssize; +extern int mmu_highuser_ssize; /* * If the processor supports 64k normal pages but not 64k cache @@ -195,13 +201,15 @@ extern int mmu_huge_psize; * This function sets the AVPN and L fields of the HPTE appropriately * for the page size */ -static inline unsigned long hpte_encode_v(unsigned long va, int psize) +static inline unsigned long hpte_encode_v(unsigned long va, int psize, + int ssize) { - unsigned long v = + unsigned long v; v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm); v <<= HPTE_V_AVPN_SHIFT; if (psize != MMU_PAGE_4K) v |= HPTE_V_LARGE; + v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT; return v; } @@ -226,20 +234,40 @@ static inline unsigned long hpte_encode_r(unsigned long pa, int psize) } /* - * This hashes a virtual address for a 256Mb segment only for now + * Build a VA given VSID, EA and segment size + */ +static inline unsigned long hpt_va(unsigned long ea, unsigned long vsid, + int ssize) +{ + if (ssize == MMU_SEGSIZE_256M) + return (vsid << 28) | (ea & 0xfffffffUL); + return (vsid << 40) | (ea & 0xffffffffffUL); +} + +/* + * This hashes a virtual address */ -static inline unsigned long hpt_hash(unsigned long va, unsigned int shift) +static inline unsigned long hpt_hash(unsigned long va, unsigned int shift, + int ssize) { - return ((va >> 28) & 0x7fffffffffUL) ^ ((va & 0x0fffffffUL) >> shift); + unsigned long hash, vsid; + + if (ssize == MMU_SEGSIZE_256M) { + hash = (va >> 28) ^ ((va & 0x0fffffffUL) >> shift); + } else { + vsid = va >> 40; + hash = vsid ^ (vsid << 25) ^ ((va & 0xffffffffffUL) >> shift); + } + return hash & 0x7fffffffffUL; } extern int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, pte_t *ptep, unsigned long trap, - unsigned int local); + unsigned int local, int ssize); extern int __hash_page_64K(unsigned long ea, unsigned long access, unsigned long vsid, pte_t *ptep, unsigned long trap, - unsigned int local); + unsigned int local, int ssize); struct mm_struct; extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); extern int hash_huge_page(struct mm_struct *mm, unsigned long access, @@ -248,7 +276,7 @@ extern int hash_huge_page(struct mm_struct *mm, unsigned long access, extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend, unsigned long pstart, unsigned long mode, - int psize); + int psize, int ssize); extern void htab_initialize(void); extern void htab_initialize_secondary(void); @@ -317,12 +345,17 @@ extern void slb_vmalloc_update(void); * which are used by the iSeries firmware. */ -#define VSID_MULTIPLIER ASM_CONST(200730139) /* 28-bit prime */ -#define VSID_BITS 36 -#define VSID_MODULUS ((1UL<= \ @@ -355,7 +388,7 @@ extern void slb_vmalloc_update(void); * doesn't, the answer is the low 36 bits of r3+1. So in all \ * cases the answer is the low 36 bits of (r3 + ((r3+1) >> 36))*/\ addi rx,rt,1; \ - srdi rx,rx,VSID_BITS; /* extract 2^36 bit */ \ + srdi rx,rx,VSID_BITS_##size; /* extract 2^VSID_BITS bit */ \ add rt,rt,rx @@ -377,37 +410,60 @@ typedef struct { } mm_context_t; -static inline unsigned long vsid_scramble(unsigned long protovsid) -{ #if 0 - /* The code below is equivalent to this function for arguments - * < 2^VSID_BITS, which is all this should ever be called - * with. However gcc is not clever enough to compute the - * modulus (2^n-1) without a second multiply. */ - return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS); -#else /* 1 */ - unsigned long x; +/* + * The code below is equivalent to this function for arguments + * < 2^VSID_BITS, which is all this should ever be called + * with. However gcc is not clever enough to compute the + * modulus (2^n-1) without a second multiply. + */ +#define vsid_scrample(protovsid, size) \ + ((((protovsid) * VSID_MULTIPLIER_##size) % VSID_MODULUS_##size)) - x = protovsid * VSID_MULTIPLIER; - x = (x >> VSID_BITS) + (x & VSID_MODULUS); - return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS; +#else /* 1 */ +#define vsid_scramble(protovsid, size) \ + ({ \ + unsigned long x; \ + x = (protovsid) * VSID_MULTIPLIER_##size; \ + x = (x >> VSID_BITS_##size) + (x & VSID_MODULUS_##size); \ + (x + ((x+1) >> VSID_BITS_##size)) & VSID_MODULUS_##size; \ + }) #endif /* 1 */ -} /* This is only valid for addresses >= KERNELBASE */ -static inline unsigned long get_kernel_vsid(unsigned long ea) +static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize) { - return vsid_scramble(ea >> SID_SHIFT); + if (ssize == MMU_SEGSIZE_256M) + return vsid_scramble(ea >> SID_SHIFT, 256M); + return vsid_scramble(ea >> SID_SHIFT_1T, 1T); } -/* This is only valid for user addresses (which are below 2^41) */ -static inline unsigned long get_vsid(unsigned long context, unsigned long ea) +/* Returns the segment size indicator for a user address */ +static inline int user_segment_size(unsigned long addr) { - return vsid_scramble((context << USER_ESID_BITS) - | (ea >> SID_SHIFT)); + /* Use 1T segments if possible for addresses >= 1T */ + if (addr >= (1UL << SID_SHIFT_1T)) + return mmu_highuser_ssize; + return MMU_SEGSIZE_256M; } -#define VSID_SCRAMBLE(pvsid) (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS) +/* This is only valid for user addresses (which are below 2^44) */ +static inline unsigned long get_vsid(unsigned long context, unsigned long ea, + int ssize) +{ + if (ssize == MMU_SEGSIZE_256M) + return vsid_scramble((context << USER_ESID_BITS) + | (ea >> SID_SHIFT), 256M); + return vsid_scramble((context << USER_ESID_BITS_1T) + | (ea >> SID_SHIFT_1T), 1T); +} + +/* + * This is only used on legacy iSeries in lparmap.c, + * hence the 256MB segment assumption. + */ +#define VSID_SCRAMBLE(pvsid) (((pvsid) * VSID_MULTIPLIER_256M) % \ + VSID_MODULUS_256M) #define KERNEL_VSID(ea) VSID_SCRAMBLE(GET_ESID(ea)) /* Physical address used by some IO functions */ diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h index 56a2df0f6836..4ee82c61e4d7 100644 --- a/include/asm-powerpc/page_64.h +++ b/include/asm-powerpc/page_64.h @@ -26,12 +26,18 @@ */ #define PAGE_FACTOR (PAGE_SHIFT - HW_PAGE_SHIFT) -/* Segment size */ +/* Segment size; normal 256M segments */ #define SID_SHIFT 28 #define SID_MASK ASM_CONST(0xfffffffff) #define ESID_MASK 0xfffffffff0000000UL #define GET_ESID(x) (((x) >> SID_SHIFT) & SID_MASK) +/* 1T segments */ +#define SID_SHIFT_1T 40 +#define SID_MASK_1T 0xffffffUL +#define ESID_MASK_1T 0xffffff0000000000UL +#define GET_ESID_1T(x) (((x) >> SID_SHIFT_1T) & SID_MASK_1T) + #ifndef __ASSEMBLY__ #include diff --git a/include/asm-powerpc/tlbflush.h b/include/asm-powerpc/tlbflush.h index 99a0439baa50..a022f806bb21 100644 --- a/include/asm-powerpc/tlbflush.h +++ b/include/asm-powerpc/tlbflush.h @@ -97,6 +97,7 @@ struct ppc64_tlb_batch { real_pte_t pte[PPC64_TLB_BATCH_NR]; unsigned long vaddr[PPC64_TLB_BATCH_NR]; unsigned int psize; + int ssize; }; DECLARE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch); @@ -127,7 +128,7 @@ static inline void arch_leave_lazy_mmu_mode(void) extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize, - int local); + int ssize, int local); extern void flush_hash_range(unsigned long number, int local); From b63db45ca44a805ef21eb10a3750e88419156423 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Fri, 12 Oct 2007 05:09:25 +1000 Subject: [PATCH 2294/2804] [POWERPC] Add legacy serial support for OPB with flattened device tree Currently find_legacy_serial_ports() can find no serial ports on the OPB with flattened device tree. Thus no legacy boot console can be initialized. Just the early udbg console works, which is initialized with udbg_init_44x_as1 on the UART's physical address specified in kernel config. This happens because we look for ns16750 serial devices only and expect opb node to have a device type property. This patch makes it look for ns16550-compatible devices and use of_device_is_compatible() for opb in case device type is not specified. Signed-off-by: Valentine Barshak Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/legacy_serial.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 90fa11c72e1c..4ed58875ee17 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -340,9 +340,10 @@ void __init find_legacy_serial_ports(void) } /* First fill our array with opb bus ports */ - for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16750")) != NULL;) { + for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) { struct device_node *opb = of_get_parent(np); - if (opb && !strcmp(opb->type, "opb")) { + if (opb && (!strcmp(opb->type, "opb") || + of_device_is_compatible(opb, "ibm,opb"))) { index = add_legacy_soc_port(np, np); if (index >= 0 && np == stdout) legacy_serial_console = index; From d0c3d534a4388a465101b634a95f2ec586415254 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 12 Oct 2007 10:20:07 +1000 Subject: [PATCH 2295/2804] [POWERPC] Implement logging of unhandled signals Implement show_unhandled_signals sysctl + support to print when a process is killed due to unhandled signals just as i386 and x86_64 does. Default to having it off, unlike x86 that defaults on. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/signal.c | 6 ++++++ arch/powerpc/kernel/signal_32.c | 38 +++++++++++++++++++++++++++++++++ arch/powerpc/kernel/signal_64.c | 15 +++++++++++++ arch/powerpc/kernel/traps.c | 12 ++++++++++- kernel/sysctl.c | 2 +- 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index c434d6c4e4e6..a65a44fbe523 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -16,6 +16,12 @@ #include "signal.h" +/* Log an error when sending an unhandled signal to a process. Controlled + * through debug.exception-trace sysctl. + */ + +int show_unhandled_signals = 0; + /* * Allocate space for the signal frame */ diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 590057e9e987..6126bca8b70a 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -705,11 +705,13 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, { struct rt_sigframe __user *rt_sf; struct mcontext __user *frame; + void __user *addr; unsigned long newsp = 0; /* Set up Signal Frame */ /* Put a Real Time Context onto stack */ rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf)); + addr = rt_sf; if (unlikely(rt_sf == NULL)) goto badframe; @@ -728,6 +730,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; + addr = frame; if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { if (save_user_regs(regs, frame, 0)) goto badframe; @@ -742,6 +745,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, /* create a stack frame for the caller of the handler */ newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16); + addr = (void __user *)regs->gpr[1]; if (put_user(regs->gpr[1], (u32 __user *)newsp)) goto badframe; @@ -762,6 +766,12 @@ badframe: printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif + if (show_unhandled_signals && printk_ratelimit()) + printk(KERN_INFO "%s[%d]: bad frame in handle_rt_signal32: " + "%p nip %08lx lr %08lx\n", + current->comm, current->pid, + addr, regs->nip, regs->link); + force_sigsegv(sig, current); return 0; } @@ -886,6 +896,12 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, return 0; bad: + if (show_unhandled_signals && printk_ratelimit()) + printk(KERN_INFO "%s[%d]: bad frame in sys_rt_sigreturn: " + "%p nip %08lx lr %08lx\n", + current->comm, current->pid, + rt_sf, regs->nip, regs->link); + force_sig(SIGSEGV, current); return 0; } @@ -967,6 +983,13 @@ int sys_debug_setcontext(struct ucontext __user *ctx, * We kill the task with a SIGSEGV in this situation. */ if (do_setcontext(ctx, regs, 1)) { + if (show_unhandled_signals && printk_ratelimit()) + printk(KERN_INFO "%s[%d]: bad frame in " + "sys_debug_setcontext: %p nip %08lx " + "lr %08lx\n", + current->comm, current->pid, + ctx, regs->nip, regs->link); + force_sig(SIGSEGV, current); goto out; } @@ -1048,6 +1071,12 @@ badframe: printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif + if (show_unhandled_signals && printk_ratelimit()) + printk(KERN_INFO "%s[%d]: bad frame in handle_signal32: " + "%p nip %08lx lr %08lx\n", + current->comm, current->pid, + frame, regs->nip, regs->link); + force_sigsegv(sig, current); return 0; } @@ -1061,12 +1090,14 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, struct sigcontext __user *sc; struct sigcontext sigctx; struct mcontext __user *sr; + void __user *addr; sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); + addr = sc; if (copy_from_user(&sigctx, sc, sizeof(sigctx))) goto badframe; @@ -1083,6 +1114,7 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, restore_sigmask(&set); sr = (struct mcontext __user *)from_user_ptr(sigctx.regs); + addr = sr; if (!access_ok(VERIFY_READ, sr, sizeof(*sr)) || restore_user_regs(regs, sr, 1)) goto badframe; @@ -1091,6 +1123,12 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, return 0; badframe: + if (show_unhandled_signals && printk_ratelimit()) + printk(KERN_INFO "%s[%d]: bad frame in sys_sigreturn: " + "%p nip %08lx lr %08lx\n", + current->comm, current->pid, + addr, regs->nip, regs->link); + force_sig(SIGSEGV, current); return 0; } diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index de895e6d8c62..faeb8f207ea4 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -64,6 +64,11 @@ struct rt_sigframe { char abigap[288]; } __attribute__ ((aligned (16))); +static const char fmt32[] = KERN_INFO \ + "%s[%d]: bad frame in %s: %08lx nip %08lx lr %08lx\n"; +static const char fmt64[] = KERN_INFO \ + "%s[%d]: bad frame in %s: %016lx nip %016lx lr %016lx\n"; + /* * Set up the sigcontext for the signal frame. */ @@ -315,6 +320,11 @@ badframe: printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n", regs, uc, &uc->uc_mcontext); #endif + if (show_unhandled_signals && printk_ratelimit()) + printk(regs->msr & MSR_SF ? fmt64 : fmt32, + current->comm, current->pid, "rt_sigreturn", + (long)uc, regs->nip, regs->link); + force_sig(SIGSEGV, current); return 0; } @@ -398,6 +408,11 @@ badframe: printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif + if (show_unhandled_signals && printk_ratelimit()) + printk(regs->msr & MSR_SF ? fmt64 : fmt32, + current->comm, current->pid, "setup_rt_frame", + (long)frame, regs->nip, regs->link); + force_sigsegv(signr, current); return 0; } diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 2f1857c9819f..bf9e39c6e296 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -172,11 +172,21 @@ int die(const char *str, struct pt_regs *regs, long err) void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { siginfo_t info; + const char fmt32[] = KERN_INFO "%s[%d]: unhandled signal %d " \ + "at %08lx nip %08lx lr %08lx code %x\n"; + const char fmt64[] = KERN_INFO "%s[%d]: unhandled signal %d " \ + "at %016lx nip %016lx lr %016lx code %x\n"; if (!user_mode(regs)) { if (die("Exception in kernel mode", regs, signr)) return; - } + } else if (show_unhandled_signals && + unhandled_signal(current, signr) && + printk_ratelimit()) { + printk(regs->msr & MSR_SF ? fmt64 : fmt32, + current->comm, current->pid, signr, + addr, regs->nip, regs->link, code); + } memset(&info, 0, sizeof(info)); info.si_signo = signr; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 53a456ebf6d5..c7314f952647 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1221,7 +1221,7 @@ static ctl_table fs_table[] = { }; static ctl_table debug_table[] = { -#ifdef CONFIG_X86 +#if defined(CONFIG_X86) || defined(CONFIG_PPC) { .ctl_name = CTL_UNNUMBERED, .procname = "exception-trace", From 9b4b8feb962f4b3e74768b7205f1f8f6cce87238 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 12 Oct 2007 12:36:20 +1000 Subject: [PATCH 2296/2804] [POWERPC] Add memchr() to the bootwrapper This adds a memchr() implementation to the bootwrapper, which will be needed when libfdt is merged in. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/string.S | 13 +++++++++++++ arch/powerpc/boot/string.h | 1 + 2 files changed, 14 insertions(+) diff --git a/arch/powerpc/boot/string.S b/arch/powerpc/boot/string.S index 2627558bcb71..643e4cb2f11d 100644 --- a/arch/powerpc/boot/string.S +++ b/arch/powerpc/boot/string.S @@ -219,6 +219,19 @@ backwards_memcpy: mtctr r7 b 1b + .globl memchr +memchr: + cmpwi 0,r5,0 + blelr + mtctr r5 + addi r3,r3,-1 +1: lbzu r0,1(r3) + cmpw r0,r4 + beqlr + bdnz 1b + li r3,0 + blr + .globl memcmp memcmp: cmpwi 0,r5,0 diff --git a/arch/powerpc/boot/string.h b/arch/powerpc/boot/string.h index 4650030d1040..50091cc0eed9 100644 --- a/arch/powerpc/boot/string.h +++ b/arch/powerpc/boot/string.h @@ -14,6 +14,7 @@ extern size_t strnlen(const char *s, size_t count); extern void *memset(void *s, int c, size_t n); extern void *memmove(void *dest, const void *src, unsigned long n); extern void *memcpy(void *dest, const void *src, unsigned long n); +extern void *memchr(const void *s, int c, size_t n); extern int memcmp(const void *s1, const void *s2, size_t n); #endif /* _PPC_BOOT_STRING_H_ */ From e30408b2a99cb7b8bf529c7dc2328a19d71894cf Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 12 Oct 2007 00:01:21 -0400 Subject: [PATCH 2297/2804] JFS: fix bio-related build breakage Signed-off-by: Jeff Garzik Signed-off-by: Linus Torvalds --- fs/jfs/jfs_logmgr.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 57c3b8ac36bf..ccfd02944053 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2162,7 +2162,7 @@ static void lbmStartIO(struct lbuf * bp) /* check if journaling to disk has been disabled */ if (log->no_integrity) { bio->bi_size = 0; - lbmIODone(bio, 0, 0); + lbmIODone(bio, 0); } else { submit_bio(WRITE_SYNC, bio); INCREMENT(lmStat.submitted); @@ -2234,8 +2234,6 @@ static void lbmIODone(struct bio *bio, int error) /* wakeup I/O initiator */ LCACHE_WAKEUP(&bp->l_ioevent); - - return 0; } /* @@ -2260,7 +2258,6 @@ static void lbmIODone(struct bio *bio, int error) if (bp->l_flag & lbmDIRECT) { LCACHE_WAKEUP(&bp->l_ioevent); LCACHE_UNLOCK(flags); - return 0; } tail = log->wqueue; @@ -2339,8 +2336,6 @@ static void lbmIODone(struct bio *bio, int error) LCACHE_UNLOCK(flags); /* unlock+enable */ } - - return 0; } int jfsIOWait(void *arg) From 6c08772e49622e90d39903e7ff0be1a0f463ac86 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 12 Oct 2007 00:16:23 -0400 Subject: [PATCH 2298/2804] [libata] sata_mv: more S/G fixes * corruption fix: we only want the lower 16 bits of length (0 == 64kb) * ditto: the upper layer sets max-phys-segments to LIBATA_MAX_PRD, so we must reset it to own hw-specific length. * delete unused mv_fill_sg() return value Signed-off-by: Jeff Garzik --- drivers/ata/sata_mv.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index cb7dec97fee6..d9832e234e44 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -69,10 +69,11 @@ #include #include #include +#include #include #define DRV_NAME "sata_mv" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.01" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -420,6 +421,7 @@ static void mv_error_handler(struct ata_port *ap); static void mv_post_int_cmd(struct ata_queued_cmd *qc); static void mv_eh_freeze(struct ata_port *ap); static void mv_eh_thaw(struct ata_port *ap); +static int mv_slave_config(struct scsi_device *sdev); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, @@ -457,7 +459,7 @@ static struct scsi_host_template mv5_sht = { .use_clustering = 1, .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, + .slave_configure = mv_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, }; @@ -475,7 +477,7 @@ static struct scsi_host_template mv6_sht = { .use_clustering = 1, .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, + .slave_configure = mv_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, }; @@ -763,6 +765,17 @@ static void mv_irq_clear(struct ata_port *ap) { } +static int mv_slave_config(struct scsi_device *sdev) +{ + int rc = ata_scsi_slave_config(sdev); + if (rc) + return rc; + + blk_queue_max_phys_segments(sdev->request_queue, MV_MAX_SG_CT / 2); + + return 0; /* scsi layer doesn't check return value, sigh */ +} + static void mv_set_edma_ptrs(void __iomem *port_mmio, struct mv_host_priv *hpriv, struct mv_port_priv *pp) @@ -1130,10 +1143,9 @@ static void mv_port_stop(struct ata_port *ap) * LOCKING: * Inherited from caller. */ -static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) +static void mv_fill_sg(struct ata_queued_cmd *qc) { struct mv_port_priv *pp = qc->ap->private_data; - unsigned int n_sg = 0; struct scatterlist *sg; struct mv_sg *mv_sg; @@ -1151,7 +1163,7 @@ static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) mv_sg->addr = cpu_to_le32(addr & 0xffffffff); mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); - mv_sg->flags_size = cpu_to_le32(len); + mv_sg->flags_size = cpu_to_le32(len & 0xffff); sg_len -= len; addr += len; @@ -1160,12 +1172,9 @@ static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); mv_sg++; - n_sg++; } } - - return n_sg; } static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last) From 295b54c4902c52cd00d7c837d50a86e39e26caec Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:47:22 -0700 Subject: [PATCH 2299/2804] [SKY2]: ethtool register reserved area blackout Make sure and not dump reserved areas of device space. Touching some of these causes machine check exceptions on boards like D-Link DGE-550SX. Coding note, used a complex switch statement rather than bitmap because it is easier to relate the block values to the documentation rather than looking at a encoded bitmask. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 62 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 0a3203465415..4832f6403721 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3569,20 +3569,64 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, { const struct sky2_port *sky2 = netdev_priv(dev); const void __iomem *io = sky2->hw->regs; + unsigned int b; regs->version = 1; - memset(p, 0, regs->len); - memcpy_fromio(p, io, B3_RAM_ADDR); + for (b = 0; b < 128; b++) { + /* This complicated switch statement is to make sure and + * only access regions that are unreserved. + * Some blocks are only valid on dual port cards. + * and block 3 has some special diagnostic registers that + * are poison. + */ + switch (b) { + case 3: + /* skip diagnostic ram region */ + memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10); + break; - /* skip diagnostic ram region */ - memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1); - - /* copy GMAC registers */ - memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000); - if (sky2->hw->ports > 1) - memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000); + /* dual port cards only */ + case 5: /* Tx Arbiter 2 */ + case 9: /* RX2 */ + case 14 ... 15: /* TX2 */ + case 17: case 19: /* Ram Buffer 2 */ + case 22 ... 23: /* Tx Ram Buffer 2 */ + case 25: /* Rx MAC Fifo 1 */ + case 27: /* Tx MAC Fifo 2 */ + case 31: /* GPHY 2 */ + case 40 ... 47: /* Pattern Ram 2 */ + case 52: case 54: /* TCP Segmentation 2 */ + case 112 ... 116: /* GMAC 2 */ + if (sky2->hw->ports == 1) + goto reserved; + /* fall through */ + case 0: /* Control */ + case 2: /* Mac address */ + case 4: /* Tx Arbiter 1 */ + case 7: /* PCI express reg */ + case 8: /* RX1 */ + case 12 ... 13: /* TX1 */ + case 16: case 18:/* Rx Ram Buffer 1 */ + case 20 ... 21: /* Tx Ram Buffer 1 */ + case 24: /* Rx MAC Fifo 1 */ + case 26: /* Tx MAC Fifo 1 */ + case 28 ... 29: /* Descriptor and status unit */ + case 30: /* GPHY 1*/ + case 32 ... 39: /* Pattern Ram 1 */ + case 48: case 50: /* TCP Segmentation 1 */ + case 56 ... 60: /* PCI space */ + case 80 ... 84: /* GMAC 1 */ + memcpy_fromio(p, io, 128); + break; + default: +reserved: + memset(p, 0, 128); + } + p += 128; + io += 128; + } } /* In order to do Jumbo packets on these chips, need to turn off the From ff35164e72648e0bf0b10ec4410c195e8607e88b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:47:44 -0700 Subject: [PATCH 2300/2804] [SKY2]: fix power settings on Yukon XL Make sure PCI register for PHY power gets set correctly. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4832f6403721..c9ee8a2c24b5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -606,20 +606,19 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) { struct pci_dev *pdev = hw->pdev; u32 reg1; - static const u32 phy_power[] - = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; - - /* looks like this XL is back asswards .. */ - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) - onoff = !onoff; + static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; + static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); + /* Turn on/off phy power saving */ if (onoff) - /* Turn off phy power saving */ reg1 &= ~phy_power[port]; else reg1 |= phy_power[port]; + if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + reg1 |= coma_mode[port]; + pci_write_config_dword(pdev, PCI_DEV_REG1, reg1); pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); From df3fe1f318b226453b8dc48622c2b6eb78d75dbb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:48:04 -0700 Subject: [PATCH 2301/2804] [SKY2]: fiber advertise bits initialization (trivial) Put initialization in sequential order (same as other constants). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c9ee8a2c24b5..55cda58bf59f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -296,10 +296,10 @@ static const u16 copper_fc_adv[] = { /* flow control to advertise bits when using 1000BaseX */ static const u16 fiber_fc_adv[] = { - [FC_BOTH] = PHY_M_P_BOTH_MD_X, + [FC_NONE] = PHY_M_P_NO_PAUSE_X, [FC_TX] = PHY_M_P_ASYM_MD_X, [FC_RX] = PHY_M_P_SYM_MD_X, - [FC_NONE] = PHY_M_P_NO_PAUSE_X, + [FC_BOTH] = PHY_M_P_BOTH_MD_X, }; /* flow control to GMA disable bits */ From 7138a0f591b0aac3b9117e68db46903606a97b0c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:48:22 -0700 Subject: [PATCH 2302/2804] [SKY2]: use netdevice stats struct Use builtin statistics structure from net device. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 33 +++++++++++++-------------------- drivers/net/sky2.h | 2 -- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 55cda58bf59f..93655efae50b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1635,8 +1635,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) printk(KERN_DEBUG "%s: tx done %u\n", dev->name, idx); - sky2->net_stats.tx_packets++; - sky2->net_stats.tx_bytes += re->skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += re->skb->len; dev_kfree_skb_any(re->skb); sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE); @@ -2204,16 +2204,16 @@ resubmit: len_error: /* Truncation of overlength packets causes PHY length to not match MAC length */ - ++sky2->net_stats.rx_length_errors; + ++dev->stats.rx_length_errors; if (netif_msg_rx_err(sky2) && net_ratelimit()) pr_info(PFX "%s: rx length error: status %#x length %d\n", dev->name, status, length); goto resubmit; error: - ++sky2->net_stats.rx_errors; + ++dev->stats.rx_errors; if (status & GMR_FS_RX_FF_OV) { - sky2->net_stats.rx_over_errors++; + dev->stats.rx_over_errors++; goto resubmit; } @@ -2222,11 +2222,11 @@ error: dev->name, status, length); if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE)) - sky2->net_stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & GMR_FS_FRAGMENT) - sky2->net_stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & GMR_FS_CRC_ERR) - sky2->net_stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; goto resubmit; } @@ -2271,7 +2271,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) ++rx[port]; skb = sky2_receive(dev, length, status); if (unlikely(!skb)) { - sky2->net_stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -2286,8 +2286,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) } skb->protocol = eth_type_trans(skb, dev); - sky2->net_stats.rx_packets++; - sky2->net_stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; dev->last_rx = jiffies; #ifdef SKY2_VLAN_TAG_USED @@ -2478,12 +2478,12 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) gma_read16(hw, port, GM_TX_IRQ_SRC); if (status & GM_IS_RX_FF_OR) { - ++sky2->net_stats.rx_fifo_errors; + ++dev->stats.rx_fifo_errors; sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO); } if (status & GM_IS_TX_FF_UR) { - ++sky2->net_stats.tx_fifo_errors; + ++dev->stats.tx_fifo_errors; sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU); } } @@ -3222,12 +3222,6 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data) } } -static struct net_device_stats *sky2_get_stats(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - return &sky2->net_stats; -} - static int sky2_set_mac_address(struct net_device *dev, void *p) { struct sky2_port *sky2 = netdev_priv(dev); @@ -3977,7 +3971,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, dev->stop = sky2_down; dev->do_ioctl = sky2_ioctl; dev->hard_start_xmit = sky2_xmit_frame; - dev->get_stats = sky2_get_stats; dev->set_multicast_list = sky2_set_multicast; dev->set_mac_address = sky2_set_mac_address; dev->change_mtu = sky2_change_mtu; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index f4a3c2f403e5..49ee264064ab 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2031,8 +2031,6 @@ struct sky2_port { #ifdef CONFIG_SKY2_DEBUG struct dentry *debugfs; #endif - struct net_device_stats net_stats; - }; struct sky2_hw { From a7b850eaa1110b1fcdc09fdfe89e792828e9b7aa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:48:40 -0700 Subject: [PATCH 2303/2804] [SKY2]: version 1.19 Update version to keep track of new changes. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 93655efae50b..68f728f0b600 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -52,7 +52,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.18" +#define DRV_VERSION "1.19" #define PFX DRV_NAME " " /* From 9ce768ead83216d394175c0a0d72bc527648c7d0 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 11 Oct 2007 19:49:11 -0700 Subject: [PATCH 2304/2804] [TG3]: Fix APE induced regression This patch fixes a bug caused by the recent APE support added for 5761 devices. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a402b5c01896..e795c33b982d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6985,9 +6985,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) break; }; - /* Write our heartbeat update interval to APE. */ - tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, - APE_HOST_HEARTBEAT_INT_DISABLE); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + /* Write our heartbeat update interval to APE. */ + tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, + APE_HOST_HEARTBEAT_INT_DISABLE); tg3_write_sig_post_reset(tp, RESET_KIND_INIT); From d4faaecbcc6d9ea4f7c05f6de6af98e2336a4afb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 11 Oct 2007 22:15:08 -0700 Subject: [PATCH 2305/2804] [ZLIB]: Fix external builds of zlib_inflate code. Move zlib_inflate_blob() out into it's own source file, infutil.c, so that things like the powerpc zImage builder in arch/powerpc/boot/Makefile don't end up trying to compile it. Signed-off-by: David S. Miller --- lib/zlib_inflate/Makefile | 2 +- lib/zlib_inflate/inflate.c | 47 ------------------------------------ lib/zlib_inflate/infutil.c | 49 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 48 deletions(-) create mode 100644 lib/zlib_inflate/infutil.c diff --git a/lib/zlib_inflate/Makefile b/lib/zlib_inflate/Makefile index bf065482fa67..49f8ce5774d2 100644 --- a/lib/zlib_inflate/Makefile +++ b/lib/zlib_inflate/Makefile @@ -15,5 +15,5 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate.o -zlib_inflate-objs := inffast.o inflate.o \ +zlib_inflate-objs := inffast.o inflate.o infutil.o \ inftrees.o inflate_syms.o diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c index 0ad1ebf00947..f5ce87b0800e 100644 --- a/lib/zlib_inflate/inflate.c +++ b/lib/zlib_inflate/inflate.c @@ -916,50 +916,3 @@ int zlib_inflateIncomp(z_stream *z) return Z_OK; } - -#include -#include -#include - -/* Utility function: initialize zlib, unpack binary blob, clean up zlib, - * return len or negative error code. */ -int zlib_inflate_blob(void *gunzip_buf, unsigned sz, const void *buf, unsigned len) -{ - const u8 *zbuf = buf; - struct z_stream_s *strm; - int rc; - - rc = -ENOMEM; - strm = kmalloc(sizeof(*strm), GFP_KERNEL); - if (strm == NULL) - goto gunzip_nomem1; - strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (strm->workspace == NULL) - goto gunzip_nomem2; - - /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) - * expected to be stripped from input */ - - strm->next_in = zbuf; - strm->avail_in = len; - strm->next_out = gunzip_buf; - strm->avail_out = sz; - - rc = zlib_inflateInit2(strm, -MAX_WBITS); - if (rc == Z_OK) { - rc = zlib_inflate(strm, Z_FINISH); - /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ - if (rc == Z_STREAM_END) - rc = sz - strm->avail_out; - else - rc = -EINVAL; - zlib_inflateEnd(strm); - } else - rc = -EINVAL; - - kfree(strm->workspace); -gunzip_nomem2: - kfree(strm); -gunzip_nomem1: - return rc; /* returns Z_OK (0) if successful */ -} diff --git a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c new file mode 100644 index 000000000000..4824c2cc7a09 --- /dev/null +++ b/lib/zlib_inflate/infutil.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +/* Utility function: initialize zlib, unpack binary blob, clean up zlib, + * return len or negative error code. + */ +int zlib_inflate_blob(void *gunzip_buf, unsigned int sz, + const void *buf, unsigned int len) +{ + const u8 *zbuf = buf; + struct z_stream_s *strm; + int rc; + + rc = -ENOMEM; + strm = kmalloc(sizeof(*strm), GFP_KERNEL); + if (strm == NULL) + goto gunzip_nomem1; + strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (strm->workspace == NULL) + goto gunzip_nomem2; + + /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) + * expected to be stripped from input + */ + strm->next_in = zbuf; + strm->avail_in = len; + strm->next_out = gunzip_buf; + strm->avail_out = sz; + + rc = zlib_inflateInit2(strm, -MAX_WBITS); + if (rc == Z_OK) { + rc = zlib_inflate(strm, Z_FINISH); + /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ + if (rc == Z_STREAM_END) + rc = sz - strm->avail_out; + else + rc = -EINVAL; + zlib_inflateEnd(strm); + } else + rc = -EINVAL; + + kfree(strm->workspace); +gunzip_nomem2: + kfree(strm); +gunzip_nomem1: + return rc; /* returns Z_OK (0) if successful */ +} From d81fec0f97cce4aea36a89340af247523c1263a0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Oct 2007 07:00:19 +0100 Subject: [PATCH 2306/2804] missed bio_endio() in axonram Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/powerpc/sysdev/axonram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 4d3ba63bba79..5eaf3e3f4b8b 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -117,7 +117,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) transfered = 0; bio_for_each_segment(vec, bio, idx) { if (unlikely(phys_mem + vec->bv_len > phys_end)) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); rc = -ERANGE; break; } @@ -131,7 +131,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) phys_mem += vec->bv_len; transfered += vec->bv_len; } - bio_endio(bio, transfered, 0); + bio_endio(bio, 0); return rc; } From 782e3b3b3804c38d5130c7f21d7ec7bf6709023f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Oct 2007 07:17:47 +0100 Subject: [PATCH 2307/2804] Fix up more bio fallout Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/gfs2/super.c | 1 - fs/jfs/jfs_metapage.c | 3 --- fs/ocfs2/cluster/heartbeat.c | 3 +-- fs/xfs/linux-2.6/xfs_aops.c | 3 +-- fs/xfs/linux-2.6/xfs_buf.c | 3 +-- 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 2473e2a86d1b..a2da76b5ae4c 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -169,7 +169,6 @@ static void end_bio_io_page(struct bio *bio, int error) else printk(KERN_WARNING "gfs2: error %d reading superblock\n", error); unlock_page(page); - return 0; } static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 1332adc0b9fa..941369c1ac8d 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -291,8 +291,6 @@ static void metapage_read_end_io(struct bio *bio, int err) dec_io(page, last_read_complete); bio_put(bio); - - return 0; } static void remove_from_logsync(struct metapage *mp) @@ -349,7 +347,6 @@ static void metapage_write_end_io(struct bio *bio, int err) } dec_io(page, last_write_complete); bio_put(bio); - return 0; } static int metapage_writepage(struct page *page, struct writeback_control *wbc) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index da2c2b442b49..f14b541fab95 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -216,7 +216,7 @@ static void o2hb_wait_on_io(struct o2hb_region *reg, wait_for_completion(&wc->wc_io_complete); } -static int o2hb_bio_end_io(struct bio *bio, +static void o2hb_bio_end_io(struct bio *bio, int error) { struct o2hb_bio_wait_ctxt *wc = bio->bi_private; @@ -228,7 +228,6 @@ static int o2hb_bio_end_io(struct bio *bio, o2hb_bio_wait_dec(wc, 1); bio_put(bio); - return 0; } /* Setup a Bio to cover I/O against num_slots slots starting at diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 3f13519436af..6f4c29e9c3d9 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -323,7 +323,7 @@ xfs_iomap_valid( /* * BIO completion handler for buffered IO. */ -STATIC int +STATIC void xfs_end_bio( struct bio *bio, int error) @@ -339,7 +339,6 @@ xfs_end_bio( bio_put(bio); xfs_finish_ioend(ioend, 0); - return 0; } STATIC void diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 6a75f4d984a1..39f44ee572e8 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1103,7 +1103,7 @@ _xfs_buf_ioend( } } -STATIC int +STATIC void xfs_buf_bio_end_io( struct bio *bio, int error) @@ -1139,7 +1139,6 @@ xfs_buf_bio_end_io( _xfs_buf_ioend(bp, 1); bio_put(bio); - return 0; } STATIC void From 4fd7ab5949edfdf99be0ceef206c9d0b7f186318 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 12 Oct 2007 01:39:50 -0700 Subject: [PATCH 2308/2804] [TG3]: Refine napi poll loop. Need to read and store sblk->status_tag before checking for more work. The status tag is later written back to the hardware when enabling interrupts to acknowledge how much work has been processed. If the order is reversed, we can end up acknowledging work we haven't processed. When we detect tx error, it is more correct to return the rx work_done so far instead of 0. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e795c33b982d..30b1cca8144c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3576,7 +3576,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) if (sblk->idx[0].tx_consumer != tp->tx_cons) { tg3_tx(tp); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) - return 0; + return work_done; } /* run RX thread, within the bounds set by NAPI. @@ -3593,6 +3593,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) { struct tg3 *tp = container_of(napi, struct tg3, napi); int work_done = 0; + struct tg3_hw_status *sblk = tp->hw_status; while (1) { work_done = tg3_poll_work(tp, work_done, budget); @@ -3603,15 +3604,17 @@ static int tg3_poll(struct napi_struct *napi, int budget) if (unlikely(work_done >= budget)) break; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + /* tp->last_tag is used in tg3_restart_ints() below + * 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; + rmb(); + } else + sblk->status &= ~SD_STATUS_UPDATED; + if (likely(!tg3_has_work(tp))) { - struct tg3_hw_status *sblk = tp->hw_status; - - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { - tp->last_tag = sblk->status_tag; - rmb(); - } else - sblk->status &= ~SD_STATUS_UPDATED; - netif_rx_complete(tp->dev, napi); tg3_restart_ints(tp); break; @@ -3621,9 +3624,10 @@ static int tg3_poll(struct napi_struct *napi, int budget) return work_done; tx_recovery: + /* work_done is guaranteed to be less than budget. */ netif_rx_complete(tp->dev, napi); schedule_work(&tp->reset_task); - return 0; + return work_done; } static void tg3_irq_quiesce(struct tg3 *tp) From 6dee6421581d3484e9a01d403dbf158161942db6 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 12 Oct 2007 01:40:38 -0700 Subject: [PATCH 2309/2804] [BNX2]: Refine napi poll loop. Need to read and store sblk->status_idx before checking for more work. The status idx is later written back to the hardware when enabling interrupts to acknowledge how much work has been processed. If the order is reversed, we can end up acknowledging work we haven't processed. When completing bnx2_poll(), we should always break out of the while loop and return work_done instead of returning 0. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d68accea380b..78ed633ceb82 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2652,10 +2652,10 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) REG_RD(bp, BNX2_HC_COMMAND); } - if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) + if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) bnx2_tx_int(bp); - if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) + if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) work_done += bnx2_rx_int(bp, budget - work_done); return work_done; @@ -2665,6 +2665,7 @@ static int bnx2_poll(struct napi_struct *napi, int budget) { struct bnx2 *bp = container_of(napi, struct bnx2, napi); int work_done = 0; + struct status_block *sblk = bp->status_blk; while (1) { work_done = bnx2_poll_work(bp, work_done, budget); @@ -2672,16 +2673,19 @@ static int bnx2_poll(struct napi_struct *napi, int budget) if (unlikely(work_done >= budget)) break; + /* bp->last_status_idx is used below to tell the hw how + * much work has been processed, so we must read it before + * checking for more work. + */ + bp->last_status_idx = sblk->status_idx; + rmb(); if (likely(!bnx2_has_work(bp))) { - bp->last_status_idx = bp->status_blk->status_idx; - rmb(); - netif_rx_complete(bp->dev, napi); if (likely(bp->flags & USING_MSI_FLAG)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); - return 0; + break; } REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | From 2da96acde0318f121ed3f5993ae9324c856ecfd4 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 12 Oct 2007 12:40:38 +0200 Subject: [PATCH 2310/2804] [BLOCK] Move sector_div() from blkdev.h to kernel.h We need it even if CONFIG_BLOCK is disabled, so move it outside of the block layer include system. Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 14 -------------- include/linux/kernel.h | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 95be0ac57e76..5ed888b04b29 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -20,20 +20,6 @@ #include -#ifdef CONFIG_LBD -# include -# define sector_div(a, b) do_div(a, b) -#else -# define sector_div(n, b)( \ -{ \ - int _res; \ - _res = (n) % (b); \ - (n) /= (b); \ - _res; \ -} \ -) -#endif - struct scsi_ioctl_command; struct request_queue; diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 47160fe378c9..d9725a28a265 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -42,6 +42,20 @@ extern const char linux_proc_banner[]; #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#ifdef CONFIG_LBD +# include +# define sector_div(a, b) do_div(a, b) +#else +# define sector_div(n, b)( \ +{ \ + int _res; \ + _res = (n) % (b); \ + (n) /= (b); \ + _res; \ +} \ +) +#endif + /** * upper_32_bits - return bits 32-63 of a number * @n: the number we're accessing From 43d28d98bed372649060ef783719b426a91972ed Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 12 Oct 2007 12:50:07 +0200 Subject: [PATCH 2311/2804] [BLOCK] Better fix for do_blk_trace_setup() for !CONFIG_BLOCK We don't have the request queue definition, so just make it a macro instead. Signed-off-by: Jens Axboe --- include/linux/blktrace_api.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index 2e105a12fe29..7e11d23ac36a 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -290,12 +290,7 @@ static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio, #define blk_add_trace_generic(q, rq, rw, what) do { } while (0) #define blk_add_trace_pdu_int(q, what, bio, pdu) do { } while (0) #define blk_add_trace_remap(q, bio, dev, f, t) do {} while (0) -static inline int do_blk_trace_setup(struct request_queue *q, - struct block_device *bdev, - struct blk_user_trace_setup *buts) -{ - return 0; -} +#define do_blk_trace_setup(q, bdev, buts) (-ENOTTY) #endif /* CONFIG_BLK_DEV_IO_TRACE */ #endif /* __KERNEL__ */ #endif From 99874d50481c093adfe74e796436024d88b6a48c Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 12 Oct 2007 12:50:41 +0200 Subject: [PATCH 2312/2804] [BLOCK] Only include the compat ioctl code if CONFIG_BLOCK is set Add an extra CONFIG_BLOCK_COMPAT that we can use in the Makefile Signed-off-by: Jens Axboe --- block/Kconfig | 4 ++++ block/Makefile | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/block/Kconfig b/block/Kconfig index 2484e0e9d89c..e10895647f72 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -62,6 +62,10 @@ config BLK_DEV_BSG protocols (e.g. Task Management Functions and SMP in Serial Attached SCSI). +config BLOCK_COMPAT + bool + default y + endif # BLOCK source block/Kconfig.iosched diff --git a/block/Makefile b/block/Makefile index 3cfe7cebaa6a..826108190f00 100644 --- a/block/Makefile +++ b/block/Makefile @@ -11,4 +11,4 @@ obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o -obj-$(CONFIG_COMPAT) += compat_ioctl.o +obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o From b018fc09498f73da0014b44acbd59ea4a94300b4 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 12 Oct 2007 12:54:13 +0200 Subject: [PATCH 2313/2804] [BLOCK] s390 xpram typo bio_end_io() should be bio_endio() Signed-off-by: Jens Axboe --- drivers/s390/block/xpram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 0fbacc8b1063..f231bc21b1ca 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -230,7 +230,7 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } } set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_end_io(bio, 0); + bio_endio(bio, 0); return 0; fail: bio_io_error(bio); From 60cc5147ae07b3b0f7592a611fa20169f7dd02cc Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 2 Aug 2007 18:51:14 -0400 Subject: [PATCH 2314/2804] [ISDN] hysdn: convert to PCI hotplug API Signed-off-by: Jeff Garzik --- drivers/isdn/hysdn/hysdn_init.c | 274 +++++++++++++++----------------- 1 file changed, 130 insertions(+), 144 deletions(-) diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 9e01748a176e..b7cc5c2f08c6 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -20,10 +20,15 @@ #include "hysdn_defs.h" static struct pci_device_id hysdn_pci_tbl[] = { - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO}, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); @@ -34,128 +39,7 @@ MODULE_LICENSE("GPL"); static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; static int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ - -/**********************************************/ -/* table assigning PCI-sub ids to board types */ -/* the last entry contains all 0 */ -/**********************************************/ -static struct { - unsigned short subid; /* PCI sub id */ - unsigned char cardtyp; /* card type assigned */ -} pci_subid_map[] = { - - { - PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2 - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO - }, - { - 0, 0 - } /* terminating entry */ -}; - - -/*********************************************************************/ -/* search_cards searches for available cards in the pci config data. */ -/* If a card is found, the card structure is allocated and the cards */ -/* ressources are reserved. cardmax is incremented. */ -/*********************************************************************/ -static void -search_cards(void) -{ - struct pci_dev *akt_pcidev = NULL; - hysdn_card *card, *card_last; - int i; - - card_root = NULL; - card_last = NULL; - while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, - akt_pcidev)) != NULL) { - if (pci_enable_device(akt_pcidev)) - continue; - - if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { - printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); - return; - } - card->myid = cardmax; /* set own id */ - card->bus = akt_pcidev->bus->number; - card->devfn = akt_pcidev->devfn; /* slot + function */ - card->subsysid = akt_pcidev->subsystem_device; - card->irq = akt_pcidev->irq; - card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); - card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); - card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); - card->brdtype = BD_NONE; /* unknown */ - card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ - card->faxchans = 0; /* default no fax channels */ - card->bchans = 2; /* and 2 b-channels */ - for (i = 0; pci_subid_map[i].subid; i++) - if (pci_subid_map[i].subid == card->subsysid) { - card->brdtype = pci_subid_map[i].cardtyp; - break; - } - if (card->brdtype != BD_NONE) { - if (ergo_inithardware(card)) { - printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); - kfree(card); - continue; - } - } else { - printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); - kfree(card); /* release mem */ - continue; - } - cardmax++; - card->next = NULL; /*end of chain */ - if (card_last) - card_last->next = card; /* pointer to next card */ - else - card_root = card; - card_last = card; /* new chain end */ - } /* device found */ -} /* search_cards */ - -/************************************************************************************/ -/* free_resources frees the acquired PCI resources and returns the allocated memory */ -/************************************************************************************/ -static void -free_resources(void) -{ - hysdn_card *card; - - while (card_root) { - card = card_root; - if (card->releasehardware) - card->releasehardware(card); /* free all hardware resources */ - card_root = card_root->next; /* remove card from chain */ - kfree(card); /* return mem */ - - } /* while card_root */ -} /* free_resources */ - -/**************************************************************************/ -/* stop_cards disables (hardware resets) all cards and disables interrupt */ -/**************************************************************************/ -static void -stop_cards(void) -{ - hysdn_card *card; - - card = card_root; /* first in chain */ - while (card) { - if (card->stopcard) - card->stopcard(card); - card = card->next; /* remove card from chain */ - } /* while card */ -} /* stop_cards */ +static hysdn_card *card_last = NULL; /* pointer to first card */ /****************************************************************************/ @@ -191,31 +75,138 @@ hysdn_getrev(const char *revision) /* and the module is added to the list in /proc/modules, otherwise an error */ /* is assumed and the module will not be kept in memory. */ /****************************************************************************/ + +static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev, + const struct pci_device_id *ent) +{ + hysdn_card *card; + int rc; + + rc = pci_enable_device(akt_pcidev); + if (rc) + return rc; + + if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { + printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); + rc = -ENOMEM; + goto err_out; + } + card->myid = cardmax; /* set own id */ + card->bus = akt_pcidev->bus->number; + card->devfn = akt_pcidev->devfn; /* slot + function */ + card->subsysid = akt_pcidev->subsystem_device; + card->irq = akt_pcidev->irq; + card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); + card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); + card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); + card->brdtype = BD_NONE; /* unknown */ + card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ + card->faxchans = 0; /* default no fax channels */ + card->bchans = 2; /* and 2 b-channels */ + card->brdtype = ent->driver_data; + + if (ergo_inithardware(card)) { + printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); + rc = -EBUSY; + goto err_out_card; + } + + cardmax++; + card->next = NULL; /*end of chain */ + if (card_last) + card_last->next = card; /* pointer to next card */ + else + card_root = card; + card_last = card; /* new chain end */ + + pci_set_drvdata(akt_pcidev, card); + return 0; + +err_out_card: + kfree(card); +err_out: + pci_disable_device(akt_pcidev); + return rc; +} + +static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev) +{ + hysdn_card *card = pci_get_drvdata(akt_pcidev); + + pci_set_drvdata(akt_pcidev, NULL); + + if (card->stopcard) + card->stopcard(card); + +#ifdef CONFIG_HYSDN_CAPI + hycapi_capi_release(card); +#endif + + if (card->releasehardware) + card->releasehardware(card); /* free all hardware resources */ + + if (card == card_root) { + card_root = card_root->next; + if (!card_root) + card_last = NULL; + } else { + hysdn_card *tmp = card_root; + while (tmp) { + if (tmp->next == card) + tmp->next = card->next; + card_last = tmp; + tmp = tmp->next; + } + } + + kfree(card); + pci_disable_device(akt_pcidev); +} + +static struct pci_driver hysdn_pci_driver = { + .name = "hysdn", + .id_table = hysdn_pci_tbl, + .probe = hysdn_pci_init_one, + .remove = __devexit_p(hysdn_pci_remove_one), +}; + +static int hysdn_have_procfs; + static int __init hysdn_init(void) { char tmp[50]; + int rc; strcpy(tmp, hysdn_init_revision); printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); strcpy(tmp, hysdn_net_revision); printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); - search_cards(); + + rc = pci_register_driver(&hysdn_pci_driver); + if (rc) + return rc; + printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); - if (hysdn_procconf_init()) { - free_resources(); /* proc file_sys not created */ - return (-1); - } + if (!hysdn_procconf_init()) + hysdn_have_procfs = 1; + #ifdef CONFIG_HYSDN_CAPI if(cardmax > 0) { if(hycapi_init()) { printk(KERN_ERR "HYCAPI: init failed\n"); - return(-1); + + if (hysdn_have_procfs) + hysdn_procconf_release(); + + pci_unregister_driver(&hysdn_pci_driver); + return -ESPIPE; } } #endif /* CONFIG_HYSDN_CAPI */ - return (0); /* no error */ + + return 0; /* no error */ } /* init_module */ @@ -230,20 +221,15 @@ hysdn_init(void) static void __exit hysdn_exit(void) { + if (hysdn_have_procfs) + hysdn_procconf_release(); + + pci_unregister_driver(&hysdn_pci_driver); + #ifdef CONFIG_HYSDN_CAPI - hysdn_card *card; -#endif /* CONFIG_HYSDN_CAPI */ - stop_cards(); -#ifdef CONFIG_HYSDN_CAPI - card = card_root; /* first in chain */ - while (card) { - hycapi_capi_release(card); - card = card->next; /* remove card from chain */ - } /* while card */ hycapi_cleanup(); #endif /* CONFIG_HYSDN_CAPI */ - hysdn_procconf_release(); - free_resources(); + printk(KERN_NOTICE "HYSDN: module unloaded\n"); } /* cleanup_module */ From bfc7c89f068bbbc2c48588385529d15c6feef802 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 2 Aug 2007 16:56:22 -0400 Subject: [PATCH 2315/2804] [ISDN] Remove CONFIG_PCI ifdefs from 100% PCI source code Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/bkm_a8.c | 8 -------- drivers/isdn/hisax/telespci.c | 8 ++------ drivers/isdn/hisax/w6692.c | 7 +------ 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 6339bb443f62..99ef3b43fcd7 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -20,8 +20,6 @@ #include #include "bkm_ax.h" -#ifdef CONFIG_PCI - #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; @@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0; static u_char pci_device_fn __devinitdata = 0; static u_char pci_irq __devinitdata = 0; -#endif /* CONFIG_PCI */ - int __devinit setup_sct_quadro(struct IsdnCard *card) { -#ifdef CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; u_int found = 0; @@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card) sct_quadro_subtypes[cs->subtyp], readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); return (1); -#else - printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); -#endif /* CONFIG_PCI */ } diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index d09f6d033f15..4393003ae162 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -295,11 +295,12 @@ setup_telespci(struct IsdnCard *card) #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif + strcpy(tmp, telespci_revision); printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) return (0); -#ifdef CONFIG_PCI + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) return(0); @@ -317,11 +318,6 @@ setup_telespci(struct IsdnCard *card) printk(KERN_WARNING "TelesPCI: No PCI card found\n"); return(0); } -#else - printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n"); - printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ /* Initialize Zoran PCI controller */ writel(0x00000000, cs->hw.teles0.membase + 0x28); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 3aeceaf9769e..39129b94f8be 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card) printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) return (0); -#ifdef CONFIG_PCI + while (id_list[id_idx].vendor_id) { dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, @@ -1061,11 +1061,6 @@ setup_w6692(struct IsdnCard *card) cs->hw.w6692.iobase + 255); return (0); } -#else - printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "HiSax: W6692 unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ printk(KERN_INFO "HiSax: %s config irq:%d I/O:%x\n", From 2fbde4c0923f53bca9975a46059b5c481a3551ba Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:23:49 -0400 Subject: [PATCH 2316/2804] [ISDN] HiSax avm_pci: split setup into three smaller functions Preparation for new ISA/PNP/PCI APIs. Just code movement, and the glue to call the new functions. Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/avm_pci.c | 224 +++++++++++++++++++++-------------- 1 file changed, 136 insertions(+), 88 deletions(-) diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index b04a178e5021..f8b79783c8b3 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -20,7 +20,6 @@ #include #include -extern const char *CardType[]; static const char *avm_pci_rev = "$Revision: 1.29.2.4 $"; #define AVM_FRITZ_PCI 1 @@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -#ifdef CONFIG_PCI -static struct pci_dev *dev_avm __devinitdata = NULL; -#endif -#ifdef __ISAPNP__ -static struct pnp_card *pnp_avm_c __devinitdata = NULL; -#endif - -int __devinit -setup_avm_pcipnp(struct IsdnCard *card) +static int __devinit avm_setup_rest(struct IsdnCardState *cs) { u_int val, ver; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, avm_pci_rev); - printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_FRITZPCI) - return (0); - if (card->para[1]) { - /* old manual method */ - cs->hw.avm.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_avm_d = NULL; - if ((pnp_avm_c = pnp_find_card( - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { - if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { - int err; - - pnp_disable_dev(pnp_avm_d); - err = pnp_activate_dev(pnp_avm_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - cs->hw.avm.cfg_reg = - pnp_port_start(pnp_avm_d, 0); - cs->irq = pnp_irq(pnp_avm_d, 0); - if (!cs->irq) { - printk(KERN_ERR "FritzPnP:No IRQ\n"); - return(0); - } - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPnP:No IO address\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } - } - } else { - printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); - } -#endif -#ifdef CONFIG_PCI - if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, - PCI_DEVICE_ID_AVM_A1, dev_avm))) { - if (pci_enable_device(dev_avm)) - return(0); - cs->irq = dev_avm->irq; - if (!cs->irq) { - printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PCI; - } else { - printk(KERN_WARNING "FritzPCI: No PCI card found\n"); - return(0); - } - cs->irq_flags |= IRQF_SHARED; -#else - printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); - return (0); -#endif /* CONFIG_PCI */ -ready: cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; if (!request_region(cs->hw.avm.cfg_reg, 32, (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], + "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n", cs->hw.avm.cfg_reg, cs->hw.avm.cfg_reg + 31); return (0); @@ -860,3 +774,137 @@ ready: ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); return (1); } + +#ifndef __ISAPNP__ + +static int __devinit avm_pnp_setup(struct IsdnCardState *cs) +{ + return(1); /* no-op: success */ +} + +#else + +static struct pnp_card *pnp_avm_c __devinitdata = NULL; + +static int __devinit avm_pnp_setup(struct IsdnCardState *cs) +{ + struct pnp_dev *pnp_avm_d = NULL; + + if (!isapnp_present()) + return(1); /* no-op: success */ + + if ((pnp_avm_c = pnp_find_card( + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { + if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { + int err; + + pnp_disable_dev(pnp_avm_d); + err = pnp_activate_dev(pnp_avm_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + cs->hw.avm.cfg_reg = + pnp_port_start(pnp_avm_d, 0); + cs->irq = pnp_irq(pnp_avm_d, 0); + if (!cs->irq) { + printk(KERN_ERR "FritzPnP:No IRQ\n"); + return(0); + } + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPnP:No IO address\n"); + return(0); + } + cs->subtyp = AVM_FRITZ_PNP; + + return (2); /* goto 'ready' label */ + } + } + + return (1); +} + +#endif /* __ISAPNP__ */ + +#ifndef CONFIG_PCI + +static int __devinit avm_pci_setup(struct IsdnCardState *cs) +{ + return(1); /* no-op: success */ +} + +#else + +static struct pci_dev *dev_avm __devinitdata = NULL; + +static int __devinit avm_pci_setup(struct IsdnCardState *cs) +{ + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_A1, dev_avm))) { + + if (pci_enable_device(dev_avm)) + return(0); + + cs->irq = dev_avm->irq; + if (!cs->irq) { + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); + return(0); + } + + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); + return(0); + } + + cs->subtyp = AVM_FRITZ_PCI; + } else { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); + } + + cs->irq_flags |= IRQF_SHARED; + + return (1); +} + +#endif /* CONFIG_PCI */ + +int __devinit +setup_avm_pcipnp(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + int rc; + + strcpy(tmp, avm_pci_rev); + printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); + + if (cs->typ != ISDN_CTYPE_FRITZPCI) + return (0); + + if (card->para[1]) { + /* old manual method */ + cs->hw.avm.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + cs->subtyp = AVM_FRITZ_PNP; + goto ready; + } + + rc = avm_pnp_setup(cs); + if (rc < 1) + return (0); + if (rc == 2) + goto ready; + + rc = avm_pci_setup(cs); + if (rc < 1) + return (0); + +ready: + return avm_setup_rest(cs); +} From 1e5d82e18b7204545737a5ef96bc34180a8df844 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:27:22 -0400 Subject: [PATCH 2317/2804] [ISDN] HiSax elsa: split huge setup function into four smaller functions Prep for hotplug API conversion. Just code movement (+glue). Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/elsa.c | 498 +++++++++++++++++++++----------------- 1 file changed, 280 insertions(+), 218 deletions(-) diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index fab3e4ea0595..0c1351b23840 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -30,8 +30,6 @@ #include #include -extern const char *CardType[]; - static const char *Elsa_revision = "$Revision: 2.32.2.4 $"; static const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", @@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs) return (CARD_portlist[i]); } -static struct pci_dev *dev_qs1000 __devinitdata = NULL; -static struct pci_dev *dev_qs3000 __devinitdata = NULL; +static int __devinit +setup_elsa_isa(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + cs->hw.elsa.base = card->para[0]; + printk(KERN_INFO "Elsa: Microlink IO probing\n"); + if (cs->hw.elsa.base) { + if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, + cs->typ))) { + printk(KERN_WARNING + "Elsa: no Elsa Microlink at %#lx\n", + cs->hw.elsa.base); + return (0); + } + } else + cs->hw.elsa.base = probe_elsa(cs); + + if (!cs->hw.elsa.base) { + printk(KERN_WARNING + "No Elsa Microlink found\n"); + return (0); + } + + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + val = bytein(cs->hw.elsa.cfg); + if (cs->subtyp == ELSA_PC) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; + } else if (cs->subtyp == ELSA_PCC8) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; + } else { + const u_char CARD_IrqTab[8] = + {15, 10, 15, 3, 11, 5, 11, 9}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; + } + val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; + if (val < 3) + val |= 8; + val += 'A' - 3; + if (val == 'B' || val == 'C') + val ^= 1; + if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) + val = 'C'; + printk(KERN_INFO + "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + val, cs->irq); + val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; + if (val) { + printk(KERN_WARNING + "Elsa: Microlink S0 bus power bad\n"); + cs->hw.elsa.status |= ELSA_BAD_PWR; + } + + return (1); +} #ifdef __ISAPNP__ static struct isapnp_device_id elsa_ids[] __devinitdata = { @@ -848,233 +913,194 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = { static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; -#endif +#endif /* __ISAPNP__ */ -int __devinit -setup_elsa(struct IsdnCard *card) +static int __devinit +setup_elsa_isapnp(struct IsdnCard *card) { - int bytecnt; - u_char val; struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, Elsa_revision); - printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); - cs->hw.elsa.ctrl_reg = 0; - cs->hw.elsa.status = 0; - cs->hw.elsa.MFlag = 0; - cs->subtyp = 0; - if (cs->typ == ISDN_CTYPE_ELSA) { - cs->hw.elsa.base = card->para[0]; - printk(KERN_INFO "Elsa: Microlink IO probing\n"); - if (cs->hw.elsa.base) { - if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, - cs->typ))) { - printk(KERN_WARNING - "Elsa: no Elsa Microlink at %#lx\n", - cs->hw.elsa.base); - return (0); - } - } else - cs->hw.elsa.base = probe_elsa(cs); - if (cs->hw.elsa.base) { - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - val = bytein(cs->hw.elsa.cfg); - if (cs->subtyp == ELSA_PC) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; - } else if (cs->subtyp == ELSA_PCC8) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; - } else { - const u_char CARD_IrqTab[8] = - {15, 10, 15, 3, 11, 5, 11, 9}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; - } - val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; - if (val < 3) - val |= 8; - val += 'A' - 3; - if (val == 'B' || val == 'C') - val ^= 1; - if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) - val = 'C'; - printk(KERN_INFO - "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - val, cs->irq); - val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; - if (val) { - printk(KERN_WARNING - "Elsa: Microlink S0 bus power bad\n"); - cs->hw.elsa.status |= ELSA_BAD_PWR; - } - } else { - printk(KERN_WARNING - "No Elsa Microlink found\n"); - return (0); - } - } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { #ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; + if (!card->para[1] && isapnp_present()) { + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - if (ipid->function == ISAPNP_FUNCTION(0x133)) - cs->subtyp = ELSA_QS1000; - else - cs->subtyp = ELSA_QS3000; - break; - } else { - printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); return(0); } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + if (ipid->function == ISAPNP_FUNCTION(0x133)) + cs->subtyp = ELSA_QS1000; + else + cs->subtyp = ELSA_QS3000; + break; + } else { + printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); + return(0); } - ipid++; - pnp_c=NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); - return(0); } + ipid++; + pnp_c=NULL; + } + if (!ipid->card_vendor) { + printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); + return(0); } -#endif - if (card->para[1] && card->para[0]) { - cs->hw.elsa.base = card->para[1]; - cs->irq = card->para[0]; - if (!cs->subtyp) - cs->subtyp = ELSA_QS1000; - } else { - printk(KERN_ERR "Elsa PnP: no parameter\n"); - } - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) { + } +#endif /* __ISAPNP__ */ + + if (card->para[1] && card->para[0]) { cs->hw.elsa.base = card->para[1]; cs->irq = card->para[0]; - val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); - if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ - cs->subtyp = ELSA_PCMCIA_IPAC; - cs->hw.elsa.ale = cs->hw.elsa.base + 0; - cs->hw.elsa.isac = cs->hw.elsa.base + 2; - cs->hw.elsa.hscx = cs->hw.elsa.base + 2; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = ELSA_PCMCIA; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - } - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->hw.elsa.ctrl = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { -#ifdef CONFIG_PCI - cs->subtyp = 0; - if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { - if (pci_enable_device(dev_qs1000)) - return(0); - cs->subtyp = ELSA_QS1000PCI; - cs->irq = dev_qs1000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { - if (pci_enable_device(dev_qs3000)) - return(0); - cs->subtyp = ELSA_QS3000PCI; - cs->irq = dev_qs3000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); - } else { - printk(KERN_WARNING "Elsa: No PCI card found\n"); - return(0); - } - if (!cs->irq) { - printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); - return(0); - } + if (!cs->subtyp) + cs->subtyp = ELSA_QS1000; + } else { + printk(KERN_ERR "Elsa PnP: no parameter\n"); + } + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); - if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { - printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); - return(0); - } - if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { - printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); - printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); - printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); - } - cs->hw.elsa.ale = cs->hw.elsa.base; - cs->hw.elsa.isac = cs->hw.elsa.base +1; - cs->hw.elsa.hscx = cs->hw.elsa.base +1; + return (1); +} + +static void __devinit +setup_elsa_pcmcia(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + cs->hw.elsa.base = card->para[1]; + cs->irq = card->para[0]; + val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); + if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ + cs->subtyp = ELSA_PCMCIA_IPAC; + cs->hw.elsa.ale = cs->hw.elsa.base + 0; + cs->hw.elsa.isac = cs->hw.elsa.base + 2; + cs->hw.elsa.hscx = cs->hw.elsa.base + 2; test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx/0x%x IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->hw.elsa.cfg, - cs->irq); + } else { + cs->subtyp = ELSA_PCMCIA; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + } + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->hw.elsa.ctrl = 0; + cs->irq_flags |= IRQF_SHARED; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); +} + +#ifdef CONFIG_PCI +static struct pci_dev *dev_qs1000 __devinitdata = NULL; +static struct pci_dev *dev_qs3000 __devinitdata = NULL; + +static int __devinit +setup_elsa_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + + cs->subtyp = 0; + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { + if (pci_enable_device(dev_qs1000)) + return(0); + cs->subtyp = ELSA_QS1000PCI; + cs->irq = dev_qs1000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { + if (pci_enable_device(dev_qs3000)) + return(0); + cs->subtyp = ELSA_QS3000PCI; + cs->irq = dev_qs3000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); + } else { + printk(KERN_WARNING "Elsa: No PCI card found\n"); + return(0); + } + if (!cs->irq) { + printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + return(0); + } + + if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { + printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); + return(0); + } + if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { + printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); + printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); + printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); + } + cs->hw.elsa.ale = cs->hw.elsa.base; + cs->hw.elsa.isac = cs->hw.elsa.base +1; + cs->hw.elsa.hscx = cs->hw.elsa.base +1; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->irq_flags |= IRQF_SHARED; + printk(KERN_INFO + "Elsa: %s defined at %#lx/0x%x IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->hw.elsa.cfg, + cs->irq); + + return (1); +} + #else - printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n"); - return (0); + +static void __devinit +setup_elsa_pci(struct IsdnCard *card) +{ + return (1); +} #endif /* CONFIG_PCI */ - } else - return (0); + +static int __devinit +setup_elsa_common(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + int bytecnt; switch (cs->subtyp) { case ELSA_PC: @@ -1104,8 +1130,7 @@ setup_elsa(struct IsdnCard *card) here, it would fail. */ if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { printk(KERN_WARNING - "HiSax: %s config port %#lx-%#lx already in use\n", - CardType[card->typ], + "HiSax: ELSA config port %#lx-%#lx already in use\n", cs->hw.elsa.base, cs->hw.elsa.base + bytecnt); return (0); @@ -1113,8 +1138,7 @@ setup_elsa(struct IsdnCard *card) if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { printk(KERN_WARNING - "HiSax: %s pci port %x-%x already in use\n", - CardType[card->typ], + "HiSax: ELSA pci port %x-%x already in use\n", cs->hw.elsa.cfg, cs->hw.elsa.cfg + 0x80); release_region(cs->hw.elsa.base, bytecnt); @@ -1186,3 +1210,41 @@ setup_elsa(struct IsdnCard *card) } return (1); } + +int __devinit +setup_elsa(struct IsdnCard *card) +{ + int rc; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, Elsa_revision); + printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); + cs->hw.elsa.ctrl_reg = 0; + cs->hw.elsa.status = 0; + cs->hw.elsa.MFlag = 0; + cs->subtyp = 0; + + if (cs->typ == ISDN_CTYPE_ELSA) { + rc = setup_elsa_isa(card); + if (!rc) + return (0); + + } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { + rc = setup_elsa_isapnp(card); + if (!rc) + return (0); + + } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) + setup_elsa_pcmcia(card); + + else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { + rc = setup_elsa_pci(card); + if (!rc) + return (0); + + } else + return (0); + + return setup_elsa_common(card); +} From 7da0d9801bd52a1d5e58eae85a3b9508b4a11ffb Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:37:40 -0400 Subject: [PATCH 2318/2804] [ISDN] HiSax sedlbauer: move ISAPNP and PCI code into functions of their own Prep for hotplug API conversion. Just code movement (+glue). Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/sedlbauer.c | 272 +++++++++++++++++++-------------- 1 file changed, 155 insertions(+), 117 deletions(-) diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index ad06f3cc60fb..03dfc32166a0 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -518,8 +518,6 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_sedl __devinitdata = NULL; - #ifdef __ISAPNP__ static struct isapnp_device_id sedl_ids[] __devinitdata = { { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), @@ -533,15 +531,158 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = { static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; -#endif + +static int __devinit +setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) +{ + struct IsdnCardState *cs = card->cs; + struct pnp_dev *pnp_d; + + if (!isapnp_present()) + return -1; + + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.sedl.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0x2)) { + cs->subtyp = SEDL_SPEED_FAX; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + *bytecnt = 16; + } else { + cs->subtyp = SEDL_SPEED_CARD_WIN; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } + + return (1); + } else { + printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); + return(0); + } + } + ipid++; + pnp_c = NULL; + } + + printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); + return -1; +} +#else + +static int __devinit +setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) +{ + return -1; +} +#endif /* __ISAPNP__ */ + +#ifdef CONFIG_PCI +static struct pci_dev *dev_sedl __devinitdata = NULL; + +static int __devinit +setup_sedlbauer_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u16 sub_vendor_id, sub_id; + + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { + if (pci_enable_device(dev_sedl)) + return(0); + cs->irq = dev_sedl->irq; + if (!cs->irq) { + printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); + } else { + printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); + return(0); + } + cs->irq_flags |= IRQF_SHARED; + cs->hw.sedl.bus = SEDL_BUS_PCI; + sub_vendor_id = dev_sedl->subsystem_vendor; + sub_id = dev_sedl->subsystem_device; + printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", + sub_vendor_id, sub_id); + printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", + cs->hw.sedl.cfg_reg); + if (sub_id != PCI_SUB_ID_SEDLBAUER) { + printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); + return(0); + } + if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; + } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PCI; + } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = HST_SAPHIR3; + } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); + } + + cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; + cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; + byteout(cs->hw.sedl.cfg_reg, 0xff); + byteout(cs->hw.sedl.cfg_reg, 0x00); + byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); + byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */ + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); + mdelay(2); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + mdelay(10); + + return (1); +} + +#else + +static int __devinit +setup_sedlbauer_pci(struct IsdnCard *card) +{ + return (1); +} + +#endif /* CONFIG_PCI */ int __devinit setup_sedlbauer(struct IsdnCard *card) { - int bytecnt, ver, val; + int bytecnt = 8, ver, val, rc; struct IsdnCardState *cs = card->cs; char tmp[64]; - u16 sub_vendor_id, sub_id; strcpy(tmp, Sedlbauer_revision); printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); @@ -569,124 +710,21 @@ setup_sedlbauer(struct IsdnCard *card) bytecnt = 16; } } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; + rc = setup_sedlbauer_isapnp(card, &bytecnt); + if (!rc) + return (0); + if (rc > 0) + goto ready; - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); + /* Probe for Sedlbauer speed pci */ + rc = setup_sedlbauer_pci(card); + if (!rc) + return (0); - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0x2)) { - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - bytecnt = 16; - } else { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } - goto ready; - } else { - printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); - return(0); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); - } - } -#endif -/* Probe for Sedlbauer speed pci */ -#ifdef CONFIG_PCI - if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { - if (pci_enable_device(dev_sedl)) - return(0); - cs->irq = dev_sedl->irq; - if (!cs->irq) { - printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); - } else { - printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); - return(0); - } - cs->irq_flags |= IRQF_SHARED; - cs->hw.sedl.bus = SEDL_BUS_PCI; - sub_vendor_id = dev_sedl->subsystem_vendor; - sub_id = dev_sedl->subsystem_device; - printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", - sub_vendor_id, sub_id); - printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", - cs->hw.sedl.cfg_reg); - if (sub_id != PCI_SUB_ID_SEDLBAUER) { - printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); - return(0); - } - if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PYRAMID; - } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PCI; - } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = HST_SAPHIR3; - } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = SEDL_SPEED_PCI; - } else { - printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", - sub_vendor_id); - return(0); - } bytecnt = 256; - cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; - cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; - byteout(cs->hw.sedl.cfg_reg, 0xff); - byteout(cs->hw.sedl.cfg_reg, 0x00); - byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); - byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */ - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); - mdelay(2); - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); - mdelay(10); -#else - printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); - return (0); -#endif /* CONFIG_PCI */ } -#ifdef __ISAPNP__ ready: -#endif /* In case of the sedlbauer pcmcia card, this region is in use, * reserved for us by the card manager. So we do not check it From 4b5a9b3d8e857249f2670f4419ce764be02e11db Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:47:00 -0400 Subject: [PATCH 2319/2804] [ISDN] HiSax diva: split setup into three smaller functions Just code movement, and the glue to call the new functions. Preparation for hotplug APIs. Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/diva.c | 513 ++++++++++++++++++++++---------------- 1 file changed, 294 insertions(+), 219 deletions(-) diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 6eebeb441bfd..826745078746 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -25,8 +25,6 @@ #include #include -extern const char *CardType[]; - static const char *Diva_revision = "$Revision: 1.33.2.6 $"; #define byteout(addr,val) outb(val,addr) @@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_diva __devinitdata = NULL; -static struct pci_dev *dev_diva_u __devinitdata = NULL; -static struct pci_dev *dev_diva201 __devinitdata = NULL; -static struct pci_dev *dev_diva202 __devinitdata = NULL; - -#ifdef __ISAPNP__ -static struct isapnp_device_id diva_ids[] __devinitdata = { - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { 0, } -}; - -static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; -static struct pnp_card *pnp_c __devinitdata = NULL; -#endif - - -int __devinit -setup_diva(struct IsdnCard *card) +static int __devinit setup_diva_common(struct IsdnCardState *cs) { - int bytecnt = 8; + int bytecnt; u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, Diva_revision); - printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_DIEHLDIVA) - return(0); - cs->hw.diva.status = 0; - if (card->para[1]) { - cs->hw.diva.ctrl_reg = 0; - cs->hw.diva.cfg_reg = card->para[1]; - val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, - cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - if ((val == 1) || (val==2)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; - } - cs->irq = card->para[0]; - } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - cs->hw.diva.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0xA1)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = - card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = - card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_HSCX_ADR; - } - goto ready; - } else { - printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); - return(0); - } - } - ipid++; - pnp_c=NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Diva PnP: no ISAPnP card found\n"); - } - } -#endif -#ifdef CONFIG_PCI - cs->subtyp = 0; - if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { - if (pci_enable_device(dev_diva)) - return(0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { - if (pci_enable_device(dev_diva_u)) - return(0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva_u->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { - if (pci_enable_device(dev_diva201)) - return(0); - cs->subtyp = DIVA_IPAC_PCI; - cs->irq = dev_diva201->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); - } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { - if (pci_enable_device(dev_diva202)) - return(0); - cs->subtyp = DIVA_IPACX_PCI; - cs->irq = dev_diva202->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); - } else { - printk(KERN_WARNING "Diva: No PCI card found\n"); - return(0); - } - - if (!cs->irq) { - printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); - iounmap_diva(cs); - return(0); - } - - if (!cs->hw.diva.cfg_reg) { - printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); - iounmap_diva(cs); - return(0); - } - cs->irq_flags |= IRQF_SHARED; -#else - printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Diva: unable to config DIVA PCI\n"); - return (0); -#endif /* CONFIG_PCI */ - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI) ) { - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = 0; - cs->hw.diva.hscx = 0; - cs->hw.diva.isac_adr = 0; - cs->hw.diva.hscx_adr = 0; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - bytecnt = 0; - } else { - cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; - cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; - bytecnt = 32; - } - } - -#ifdef __ISAPNP__ -ready: -#endif + if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) + bytecnt = 8; + else + bytecnt = 32; printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", @@ -1145,7 +933,7 @@ ready: if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) { printk(KERN_WARNING "HiSax: %s config port %lx-%lx already in use\n", - CardType[card->typ], + "diva", cs->hw.diva.cfg_reg, cs->hw.diva.cfg_reg + bytecnt); iounmap_diva(cs); @@ -1206,3 +994,290 @@ ready: } return (1); } + +#ifdef CONFIG_ISA + +static int __devinit setup_diva_isa(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + if (!card->para[1]) + return (-1); /* card not found; continue search */ + + cs->hw.diva.ctrl_reg = 0; + cs->hw.diva.cfg_reg = card->para[1]; + val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, + cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + if ((val == 1) || (val==2)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + } + cs->irq = card->para[0]; + + return (1); /* card found */ +} + +#else /* if !CONFIG_ISA */ + +static int __devinit setup_diva_isa(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* CONFIG_ISA */ + +#ifdef __ISAPNP__ +static struct isapnp_device_id diva_ids[] __devinitdata = { + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + (unsigned long) "Diva picola" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), + (unsigned long) "Diva picola" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + (unsigned long) "Diva 2.0" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), + (unsigned long) "Diva 2.0" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + (unsigned long) "Diva 2.01" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), + (unsigned long) "Diva 2.01" }, + { 0, } +}; + +static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; +static struct pnp_card *pnp_c __devinitdata = NULL; + +static int __devinit setup_diva_isapnp(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + struct pnp_dev *pnp_d; + + if (!isapnp_present()) + return (-1); /* card not found; continue search */ + + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.diva.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0xA1)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = + card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = + card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_HSCX_ADR; + } + return (1); /* card found */ + } else { + printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); + return(0); + } + } + ipid++; + pnp_c=NULL; + } + + return (-1); /* card not found; continue search */ +} + +#else /* if !ISAPNP */ + +static int __devinit setup_diva_isapnp(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* ISAPNP */ + +#ifdef CONFIG_PCI +static struct pci_dev *dev_diva __devinitdata = NULL; +static struct pci_dev *dev_diva_u __devinitdata = NULL; +static struct pci_dev *dev_diva201 __devinitdata = NULL; +static struct pci_dev *dev_diva202 __devinitdata = NULL; + +static int __devinit setup_diva_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + + cs->subtyp = 0; + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { + if (pci_enable_device(dev_diva)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { + if (pci_enable_device(dev_diva_u)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva_u->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { + if (pci_enable_device(dev_diva201)) + return(0); + cs->subtyp = DIVA_IPAC_PCI; + cs->irq = dev_diva201->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); + } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { + if (pci_enable_device(dev_diva202)) + return(0); + cs->subtyp = DIVA_IPACX_PCI; + cs->irq = dev_diva202->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); + } else { + return (-1); /* card not found; continue search */ + } + + if (!cs->irq) { + printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); + iounmap_diva(cs); + return(0); + } + + if (!cs->hw.diva.cfg_reg) { + printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); + iounmap_diva(cs); + return(0); + } + cs->irq_flags |= IRQF_SHARED; + + if ((cs->subtyp == DIVA_IPAC_PCI) || + (cs->subtyp == DIVA_IPACX_PCI) ) { + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = 0; + cs->hw.diva.hscx = 0; + cs->hw.diva.isac_adr = 0; + cs->hw.diva.hscx_adr = 0; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; + cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; + cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; + cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; + } + + return (1); /* card found */ +} + +#else /* if !CONFIG_PCI */ + +static int __devinit setup_diva_pci(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* CONFIG_PCI */ + +int __devinit +setup_diva(struct IsdnCard *card) +{ + int rc, have_card = 0; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, Diva_revision); + printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_DIEHLDIVA) + return(0); + cs->hw.diva.status = 0; + + rc = setup_diva_isa(card); + if (!rc) + return rc; + if (rc > 0) { + have_card = 1; + goto ready; + } + + rc = setup_diva_isapnp(card); + if (!rc) + return rc; + if (rc > 0) { + have_card = 1; + goto ready; + } + + rc = setup_diva_pci(card); + if (!rc) + return rc; + if (rc > 0) + have_card = 1; + +ready: + if (!have_card) { + printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n"); + return(0); + } + + return setup_diva_common(card->cs); +} From 7c9f4e3aaae020fc674f52393cbac1bdb648bf90 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:13 +0200 Subject: [PATCH 2320/2804] [S390] cio: rename css to channel_subsystems Rename css[] to channel_subsystems[] to avoid name clashes. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/chp.c | 14 +++---- drivers/s390/cio/css.c | 69 ++++++++++++++++++++--------------- drivers/s390/cio/css.h | 2 +- drivers/s390/cio/device_fsm.c | 3 +- 4 files changed, 49 insertions(+), 39 deletions(-) diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 920dd71e6434..8ce4ff95cc9c 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue; /* Return channel_path struct for given chpid. */ static inline struct channel_path *chpid_to_chp(struct chp_id chpid) { - return css[chpid.cssid]->chps[chpid.id]; + return channel_subsystems[chpid.cssid]->chps[chpid.id]; } /* Set vary state for given chpid. */ @@ -395,7 +395,7 @@ int chp_new(struct chp_id chpid) /* fill in status, etc. */ chp->chpid = chpid; chp->state = 1; - chp->dev.parent = &css[chpid.cssid]->device; + chp->dev.parent = &channel_subsystems[chpid.cssid]->device; chp->dev.release = chp_release; snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid, chpid.id); @@ -430,18 +430,18 @@ int chp_new(struct chp_id chpid) device_unregister(&chp->dev); goto out_free; } - mutex_lock(&css[chpid.cssid]->mutex); - if (css[chpid.cssid]->cm_enabled) { + mutex_lock(&channel_subsystems[chpid.cssid]->mutex); + if (channel_subsystems[chpid.cssid]->cm_enabled) { ret = chp_add_cmg_attr(chp); if (ret) { sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); device_unregister(&chp->dev); - mutex_unlock(&css[chpid.cssid]->mutex); + mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); goto out_free; } } - css[chpid.cssid]->chps[chpid.id] = chp; - mutex_unlock(&css[chpid.cssid]->mutex); + channel_subsystems[chpid.cssid]->chps[chpid.id] = chp; + mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); return ret; out_free: kfree(chp); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 5635e656c1a3..08f6e7b6c999 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -27,7 +27,7 @@ int css_init_done = 0; static int need_reprobe = 0; static int max_ssid = 0; -struct channel_subsystem *css[__MAX_CSSID + 1]; +struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; int css_characteristics_avail = 0; @@ -177,7 +177,7 @@ static int css_register_subchannel(struct subchannel *sch) int ret; /* Initialize the subchannel structure */ - sch->dev.parent = &css[0]->device; + sch->dev.parent = &channel_subsystems[0]->device; sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; sch->dev.groups = subch_attr_groups; @@ -606,27 +606,29 @@ static int __init setup_css(int nr) { u32 tod_high; int ret; + struct channel_subsystem *css; - memset(css[nr], 0, sizeof(struct channel_subsystem)); - css[nr]->pseudo_subchannel = - kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL); - if (!css[nr]->pseudo_subchannel) + css = channel_subsystems[nr]; + memset(css, 0, sizeof(struct channel_subsystem)); + css->pseudo_subchannel = + kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL); + if (!css->pseudo_subchannel) return -ENOMEM; - css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device; - css[nr]->pseudo_subchannel->dev.release = css_subchannel_release; - sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct"); - ret = cio_create_sch_lock(css[nr]->pseudo_subchannel); + css->pseudo_subchannel->dev.parent = &css->device; + css->pseudo_subchannel->dev.release = css_subchannel_release; + sprintf(css->pseudo_subchannel->dev.bus_id, "defunct"); + ret = cio_create_sch_lock(css->pseudo_subchannel); if (ret) { - kfree(css[nr]->pseudo_subchannel); + kfree(css->pseudo_subchannel); return ret; } - mutex_init(&css[nr]->mutex); - css[nr]->valid = 1; - css[nr]->cssid = nr; - sprintf(css[nr]->device.bus_id, "css%x", nr); - css[nr]->device.release = channel_subsystem_release; + mutex_init(&css->mutex); + css->valid = 1; + css->cssid = nr; + sprintf(css->device.bus_id, "css%x", nr); + css->device.release = channel_subsystem_release; tod_high = (u32) (get_clock() >> 32); - css_generate_pgid(css[nr], tod_high); + css_generate_pgid(css, tod_high); return 0; } @@ -670,25 +672,28 @@ init_channel_subsystem (void) } /* Setup css structure. */ for (i = 0; i <= __MAX_CSSID; i++) { - css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); - if (!css[i]) { + struct channel_subsystem *css; + + css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); + if (!css) { ret = -ENOMEM; goto out_unregister; } + channel_subsystems[i] = css; ret = setup_css(i); if (ret) goto out_free; - ret = device_register(&css[i]->device); + ret = device_register(&css->device); if (ret) goto out_free_all; if (css_characteristics_avail && css_chsc_characteristics.secm) { - ret = device_create_file(&css[i]->device, + ret = device_create_file(&css->device, &dev_attr_cm_enable); if (ret) goto out_device; } - ret = device_register(&css[i]->pseudo_subchannel->dev); + ret = device_register(&css->pseudo_subchannel->dev); if (ret) goto out_file; } @@ -699,22 +704,26 @@ init_channel_subsystem (void) for_each_subchannel(__init_channel_subsystem, NULL); return 0; out_file: - device_remove_file(&css[i]->device, &dev_attr_cm_enable); + device_remove_file(&channel_subsystems[i]->device, + &dev_attr_cm_enable); out_device: - device_unregister(&css[i]->device); + device_unregister(&channel_subsystems[i]->device); out_free_all: - kfree(css[i]->pseudo_subchannel->lock); - kfree(css[i]->pseudo_subchannel); + kfree(channel_subsystems[i]->pseudo_subchannel->lock); + kfree(channel_subsystems[i]->pseudo_subchannel); out_free: - kfree(css[i]); + kfree(channel_subsystems[i]); out_unregister: while (i > 0) { + struct channel_subsystem *css; + i--; - device_unregister(&css[i]->pseudo_subchannel->dev); + css = channel_subsystems[i]; + device_unregister(&css->pseudo_subchannel->dev); if (css_characteristics_avail && css_chsc_characteristics.secm) - device_remove_file(&css[i]->device, + device_remove_file(&css->device, &dev_attr_cm_enable); - device_unregister(&css[i]->device); + device_unregister(&css->device); } out_bus: bus_unregister(&css_bus_type); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 5d65e83ca66e..f290c5c0f27b 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -167,7 +167,7 @@ struct channel_subsystem { #define to_css(dev) container_of(dev, struct channel_subsystem, device) extern struct bus_type css_bus_type; -extern struct channel_subsystem *css[]; +extern struct channel_subsystem *channel_subsystems[]; /* Some helper functions for disconnected state. */ int device_is_disconnected(struct subchannel *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8633dc537695..f772ef0a4f22 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -446,7 +446,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev) if (cdev->private->pgid[last].inf.ps.state1 == SNID_STATE1_RESET) /* No previous pgid found */ - memcpy(&cdev->private->pgid[0], &css[0]->global_pgid, + memcpy(&cdev->private->pgid[0], + &channel_subsystems[0]->global_pgid, sizeof(struct pgid)); else /* Use existing pgid */ From fbf9772b8e7917f85f35913b30788c74ea34cad5 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:14 +0200 Subject: [PATCH 2321/2804] [S390] cio: remove subchannel_add_files() subchannel_add_files() no longer exists, remove from header. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/css.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index f290c5c0f27b..81215ef32435 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -191,6 +191,5 @@ int sch_is_pseudo_sch(struct subchannel *); extern struct workqueue_struct *slow_path_wq; -int subchannel_add_files (struct device *); extern struct attribute_group *subch_attr_groups[]; #endif From fc5019c5c7067bcea1e49fe9cd5190285f0c8927 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:15 +0200 Subject: [PATCH 2322/2804] [S390] cio: Fix some coding style issues in cmf. Fix some formatting and correct a comment. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/cmf.c | 141 ++++++++++++++++++++++------------------- include/asm-s390/cmb.h | 8 +-- 2 files changed, 81 insertions(+), 68 deletions(-) diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 34a796913b06..ff1e442d4b09 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -45,7 +45,8 @@ #include "ioasm.h" #include "chsc.h" -/* parameter to enable cmf during boot, possible uses are: +/* + * parameter to enable cmf during boot, possible uses are: * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be * used on any subchannel * "s390cmf=" -- enable cmf and allocate enough memory to measure @@ -84,6 +85,7 @@ enum cmb_format { CMF_EXTENDED, CMF_AUTODETECT = -1, }; + /** * format - actual format for all measurement blocks * @@ -111,13 +113,13 @@ module_param(format, bool, 0444); * @align: align an allocated block so that the hardware can use it */ struct cmb_operations { - int (*alloc) (struct ccw_device*); - void(*free) (struct ccw_device*); - int (*set) (struct ccw_device*, u32); - u64 (*read) (struct ccw_device*, int); - int (*readall)(struct ccw_device*, struct cmbdata *); - void (*reset) (struct ccw_device*); - void * (*align) (void *); + int (*alloc) (struct ccw_device *); + void (*free) (struct ccw_device *); + int (*set) (struct ccw_device *, u32); + u64 (*read) (struct ccw_device *, int); + int (*readall)(struct ccw_device *, struct cmbdata *); + void (*reset) (struct ccw_device *); + void *(*align) (void *); struct attribute_group *attr_group; }; @@ -130,9 +132,11 @@ struct cmb_data { unsigned long long last_update; /* when last_block was updated */ }; -/* our user interface is designed in terms of nanoseconds, +/* + * Our user interface is designed in terms of nanoseconds, * while the hardware measures total times in its own - * unit.*/ + * unit. + */ static inline u64 time_to_nsec(u32 value) { return ((u64)value) * 128000ull; @@ -159,12 +163,13 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count) return ret; } -/* activate or deactivate the channel monitor. When area is NULL, +/* + * Activate or deactivate the channel monitor. When area is NULL, * the monitor is deactivated. The channel monitor needs to * be active in order to measure subchannels, which also need - * to be enabled. */ -static inline void -cmf_activate(void *area, unsigned int onoff) + * to be enabled. + */ +static inline void cmf_activate(void *area, unsigned int onoff) { register void * __gpr2 asm("2"); register long __gpr1 asm("1"); @@ -175,8 +180,8 @@ cmf_activate(void *area, unsigned int onoff) asm("schm" : : "d" (__gpr2), "d" (__gpr1) ); } -static int -set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) +static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, + unsigned long address) { int ret; int retry; @@ -484,15 +489,14 @@ static struct cmb_area cmb_area = { /* ****** old style CMB handling ********/ -/** int maxchannels - * +/* * Basic channel measurement blocks are allocated in one contiguous * block of memory, which can not be moved as long as any channel * is active. Therefore, a maximum number of subchannels needs to * be defined somewhere. This is a module parameter, defaulting to * a resonable value of 1024, or 32 kb of memory. * Current kernels don't allow kmalloc with more than 128kb, so the - * maximum is 4096 + * maximum is 4096. */ module_param_named(maxchannels, cmb_area.num_channels, uint, 0444); @@ -516,8 +520,9 @@ struct cmb { u32 reserved[2]; }; -/* insert a single device into the cmb_area list - * called with cmb_area.lock held from alloc_cmb +/* + * Insert a single device into the cmb_area list. + * Called with cmb_area.lock held from alloc_cmb. */ static int alloc_cmb_single(struct ccw_device *cdev, struct cmb_data *cmb_data) @@ -532,9 +537,11 @@ static int alloc_cmb_single(struct ccw_device *cdev, goto out; } - /* find first unused cmb in cmb_area.mem. - * this is a little tricky: cmb_area.list - * remains sorted by ->cmb->hw_data pointers */ + /* + * Find first unused cmb in cmb_area.mem. + * This is a little tricky: cmb_area.list + * remains sorted by ->cmb->hw_data pointers. + */ cmb = cmb_area.mem; list_for_each_entry(node, &cmb_area.list, cmb_list) { struct cmb_data *data; @@ -558,8 +565,7 @@ out: return ret; } -static int -alloc_cmb (struct ccw_device *cdev) +static int alloc_cmb(struct ccw_device *cdev) { int ret; struct cmb *mem; @@ -670,7 +676,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme) return set_schib_wait(cdev, mme, 0, offset); } -static u64 read_cmb (struct ccw_device *cdev, int index) +static u64 read_cmb(struct ccw_device *cdev, int index) { struct cmb *cmb; u32 val; @@ -720,7 +726,7 @@ out: return ret; } -static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data) +static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data) { struct cmb *cmb; struct cmb_data *cmb_data; @@ -816,10 +822,12 @@ struct cmbe { u32 reserved[7]; }; -/* kmalloc only guarantees 8 byte alignment, but we need cmbe +/* + * kmalloc only guarantees 8 byte alignment, but we need cmbe * pointers to be naturally aligned. Make sure to allocate - * enough space for two cmbes */ -static inline struct cmbe* cmbe_align(struct cmbe *c) + * enough space for two cmbes. + */ +static inline struct cmbe *cmbe_align(struct cmbe *c) { unsigned long addr; addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) & @@ -827,7 +835,7 @@ static inline struct cmbe* cmbe_align(struct cmbe *c) return (struct cmbe*)addr; } -static int alloc_cmbe (struct ccw_device *cdev) +static int alloc_cmbe(struct ccw_device *cdev) { struct cmbe *cmbe; struct cmb_data *cmb_data; @@ -873,7 +881,7 @@ out_free: return ret; } -static void free_cmbe (struct ccw_device *cdev) +static void free_cmbe(struct ccw_device *cdev) { struct cmb_data *cmb_data; @@ -912,7 +920,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme) } -static u64 read_cmbe (struct ccw_device *cdev, int index) +static u64 read_cmbe(struct ccw_device *cdev, int index) { struct cmbe *cmb; struct cmb_data *cmb_data; @@ -970,7 +978,7 @@ out: return ret; } -static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data) +static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data) { struct cmbe *cmb; struct cmb_data *cmb_data; @@ -1049,15 +1057,15 @@ static struct cmb_operations cmbops_extended = { }; -static ssize_t -cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) +static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) { return sprintf(buf, "%lld\n", (unsigned long long) cmf_read(to_ccwdev(dev), idx)); } -static ssize_t -cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_show_avg_sample_interval(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ccw_device *cdev; long interval; @@ -1079,8 +1087,9 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%ld\n", interval); } -static ssize_t -cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_show_avg_utilization(struct device *dev, + struct device_attribute *attr, + char *buf) { struct cmbdata data; u64 utilization; @@ -1112,14 +1121,16 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char } #define cmf_attr(name) \ -static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ -{ return cmb_show_attr((dev), buf, cmb_ ## name); } \ -static DEVICE_ATTR(name, 0444, show_ ## name, NULL); +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ return cmb_show_attr((dev), buf, cmb_##name); } \ +static DEVICE_ATTR(name, 0444, show_##name, NULL); #define cmf_attr_avg(name) \ -static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ -{ return cmb_show_attr((dev), buf, cmb_ ## name); } \ -static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL); +static ssize_t show_avg_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ return cmb_show_attr((dev), buf, cmb_##name); } \ +static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL); cmf_attr(ssch_rsch_count); cmf_attr(sample_count); @@ -1131,7 +1142,8 @@ cmf_attr_avg(device_active_only_time); cmf_attr_avg(device_busy_time); cmf_attr_avg(initial_command_response_time); -static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL); +static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, + NULL); static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL); static struct attribute *cmf_attributes[] = { @@ -1172,12 +1184,16 @@ static struct attribute_group cmf_attr_group_ext = { .attrs = cmf_attributes_ext, }; -static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0); } -static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c) +static ssize_t cmb_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t c) { struct ccw_device *cdev; int ret; @@ -1203,8 +1219,7 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); /* enable_cmf/disable_cmf: module interface for cmf (de)activation */ -int -enable_cmf(struct ccw_device *cdev) +int enable_cmf(struct ccw_device *cdev) { int ret; @@ -1225,8 +1240,7 @@ enable_cmf(struct ccw_device *cdev) return ret; } -int -disable_cmf(struct ccw_device *cdev) +int disable_cmf(struct ccw_device *cdev) { int ret; @@ -1238,14 +1252,12 @@ disable_cmf(struct ccw_device *cdev) return ret; } -u64 -cmf_read(struct ccw_device *cdev, int index) +u64 cmf_read(struct ccw_device *cdev, int index) { return cmbops->read(cdev, index); } -int -cmf_readall(struct ccw_device *cdev, struct cmbdata *data) +int cmf_readall(struct ccw_device *cdev, struct cmbdata *data) { return cmbops->readall(cdev, data); } @@ -1257,15 +1269,16 @@ int cmf_reenable(struct ccw_device *cdev) return cmbops->set(cdev, 2); } -static int __init -init_cmf(void) +static int __init init_cmf(void) { char *format_string; char *detect_string = "parameter"; - /* We cannot really autoprobe this. If the user did not give a parameter, - see if we are running on z990 or up, otherwise fall back to basic mode. */ - + /* + * If the user did not give a parameter, see if we are running on a + * machine supporting extended measurement blocks, otherwise fall back + * to basic mode. + */ if (format == CMF_AUTODETECT) { if (!css_characteristics_avail || !css_general_characteristics.ext_mb) { @@ -1284,7 +1297,7 @@ init_cmf(void) cmbops = &cmbops_basic; break; case CMF_EXTENDED: - format_string = "extended"; + format_string = "extended"; cmbops = &cmbops_extended; break; default: diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h index 021e7c3223ec..2e84eebaf8f4 100644 --- a/include/asm-s390/cmb.h +++ b/include/asm-s390/cmb.h @@ -41,11 +41,11 @@ struct cmbdata { }; /* enable channel measurement */ -#define BIODASDCMFENABLE _IO(DASD_IOCTL_LETTER,32) +#define BIODASDCMFENABLE _IO(DASD_IOCTL_LETTER, 32) /* enable channel measurement */ -#define BIODASDCMFDISABLE _IO(DASD_IOCTL_LETTER,33) +#define BIODASDCMFDISABLE _IO(DASD_IOCTL_LETTER, 33) /* read channel measurement data */ -#define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER,33,struct cmbdata) +#define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER, 33, struct cmbdata) #ifdef __KERNEL__ struct ccw_device; @@ -87,7 +87,7 @@ extern u64 cmf_read(struct ccw_device *cdev, int index); * Context: * any **/ -extern int cmf_readall(struct ccw_device *cdev, struct cmbdata*data); +extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data); #endif /* __KERNEL__ */ #endif /* S390_CMB_H */ From c02087162af5d8880ff2d688999d71e1bfa16f2f Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:16 +0200 Subject: [PATCH 2323/2804] [S390] cio: Kerneldoc comments for cmf. - Fix existing kerneldoc-style comments. - Move descriptions of functions from cmb.h to cmf.c. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/cmf.c | 87 +++++++++++++++++++++++++++++++++++------- include/asm-s390/cmb.h | 65 ++++++++----------------------- 2 files changed, 89 insertions(+), 63 deletions(-) diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index ff1e442d4b09..6ef0ab895477 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -74,19 +74,20 @@ enum cmb_index { * enum cmb_format - types of supported measurement block formats * * @CMF_BASIC: traditional channel measurement blocks supported - * by all machines that we run on + * by all machines that we run on * @CMF_EXTENDED: improved format that was introduced with the z990 - * machine - * @CMF_AUTODETECT: default: use extended format when running on a z990 - * or later machine, otherwise fall back to basic format - **/ + * machine + * @CMF_AUTODETECT: default: use extended format when running on a machine + * supporting extended format, otherwise fall back to + * basic format + */ enum cmb_format { CMF_BASIC, CMF_EXTENDED, CMF_AUTODETECT = -1, }; -/** +/* * format - actual format for all measurement blocks * * The format module parameter can be set to a value of 0 (zero) @@ -107,6 +108,7 @@ module_param(format, bool, 0444); * either with the help of a special pool or with kmalloc * @free: free memory allocated with @alloc * @set: enable or disable measurement + * @read: read a measurement entry at an index * @readall: read a measurement block in a common format * @reset: clear the data in the associated measurement block and * reset its time stamp @@ -120,7 +122,7 @@ struct cmb_operations { int (*readall)(struct ccw_device *, struct cmbdata *); void (*reset) (struct ccw_device *); void *(*align) (void *); - +/* private: */ struct attribute_group *attr_group; }; static struct cmb_operations *cmbops; @@ -471,6 +473,7 @@ static void cmf_generic_reset(struct ccw_device *cdev) * * @mem: pointer to CMBs (only in basic measurement mode) * @list: contains a linked list of all subchannels + * @num_channels: number of channels to be measured * @lock: protect concurrent access to @mem and @list */ struct cmb_area { @@ -503,10 +506,20 @@ module_param_named(maxchannels, cmb_area.num_channels, uint, 0444); /** * struct cmb - basic channel measurement block + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @reserved: unused in basic measurement mode * - * cmb as used by the hardware the fields are described in z/Architecture - * Principles of Operation, chapter 17. - * The area to be a contiguous array and may not be reallocated or freed. + * The measurement block as used by the hardware. The fields are described + * further in z/Architecture Principles of Operation, chapter 17. + * + * The cmb area made up from these blocks must be a contiguous array and may + * not be reallocated or freed. * Only one cmb area can be present in the system. */ struct cmb { @@ -804,9 +817,20 @@ static struct cmb_operations cmbops_basic = { /** * struct cmbe - extended channel measurement block + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @device_busy_time: time of device busy + * @initial_command_response_time: initial command response time + * @reserved: unused * - * cmb as used by the hardware, may be in any 64 bit physical location, - * the fields are described in z/Architecture Principles of Operation, + * The measurement block as used by the hardware. May be in any 64 bit physical + * location. + * The fields are described further in z/Architecture Principles of Operation, * third edition, chapter 17. */ struct cmbe { @@ -1218,7 +1242,15 @@ static ssize_t cmb_enable_store(struct device *dev, DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); -/* enable_cmf/disable_cmf: module interface for cmf (de)activation */ +/** + * enable_cmf() - switch on the channel measurement for a specific device + * @cdev: The ccw device to be enabled + * + * Returns %0 for success or a negative error value. + * + * Context: + * non-atomic + */ int enable_cmf(struct ccw_device *cdev) { int ret; @@ -1240,6 +1272,15 @@ int enable_cmf(struct ccw_device *cdev) return ret; } +/** + * disable_cmf() - switch off the channel measurement for a specific device + * @cdev: The ccw device to be disabled + * + * Returns %0 for success or a negative error value. + * + * Context: + * non-atomic + */ int disable_cmf(struct ccw_device *cdev) { int ret; @@ -1252,11 +1293,31 @@ int disable_cmf(struct ccw_device *cdev) return ret; } +/** + * cmf_read() - read one value from the current channel measurement block + * @cdev: the channel to be read + * @index: the index of the value to be read + * + * Returns the value read or %0 if the value cannot be read. + * + * Context: + * any + */ u64 cmf_read(struct ccw_device *cdev, int index) { return cmbops->read(cdev, index); } +/** + * cmf_readall() - read the current channel measurement block + * @cdev: the channel to be read + * @data: a pointer to a data block that will be filled + * + * Returns %0 on success, a negative error value otherwise. + * + * Context: + * any + */ int cmf_readall(struct ccw_device *cdev, struct cmbdata *data) { return cmbops->readall(cdev, data); diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h index 2e84eebaf8f4..50196857d27a 100644 --- a/include/asm-s390/cmb.h +++ b/include/asm-s390/cmb.h @@ -1,29 +1,29 @@ #ifndef S390_CMB_H #define S390_CMB_H /** - * struct cmbdata -- channel measurement block data for user space + * struct cmbdata - channel measurement block data for user space + * @size: size of the stored data + * @elapsed_time: time since last sampling + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @device_busy_time: time of device busy (ext. format) + * @initial_command_response_time: initial command response time (ext. format) * - * @size: size of the stored data - * @ssch_rsch_count: XXX - * @sample_count: - * @device_connect_time: - * @function_pending_time: - * @device_disconnect_time: - * @control_unit_queuing_time: - * @device_active_only_time: - * @device_busy_time: - * @initial_command_response_time: - * - * all values are stored as 64 bit for simplicity, especially + * All values are stored as 64 bit for simplicity, especially * in 32 bit emulation mode. All time values are normalized to * nanoseconds. * Currently, two formats are known, which differ by the size of * this structure, i.e. the last two members are only set when * the extended channel measurement facility (first shipped in * z990 machines) is activated. - * Potentially, more fields could be added, which results in a + * Potentially, more fields could be added, which would result in a * new ioctl number. - **/ + */ struct cmbdata { __u64 size; __u64 elapsed_time; @@ -49,44 +49,9 @@ struct cmbdata { #ifdef __KERNEL__ struct ccw_device; -/** - * enable_cmf() - switch on the channel measurement for a specific device - * @cdev: The ccw device to be enabled - * returns 0 for success or a negative error value. - * - * Context: - * non-atomic - **/ extern int enable_cmf(struct ccw_device *cdev); - -/** - * disable_cmf() - switch off the channel measurement for a specific device - * @cdev: The ccw device to be disabled - * returns 0 for success or a negative error value. - * - * Context: - * non-atomic - **/ extern int disable_cmf(struct ccw_device *cdev); - -/** - * cmf_read() - read one value from the current channel measurement block - * @cmf: the channel to be read - * @index: the name of the value that is read - * - * Context: - * any - **/ - extern u64 cmf_read(struct ccw_device *cdev, int index); -/** - * cmf_readall() - read one value from the current channel measurement block - * @cmf: the channel to be read - * @data: a pointer to a data block that will be filled - * - * Context: - * any - **/ extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data); #endif /* __KERNEL__ */ From b2ffd8e9a76ec90bd4a509f3d092e35978c568a3 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:17 +0200 Subject: [PATCH 2324/2804] [S390] cio: Add docbook comments. Comment a bunch of function in docbook style and convert existing comments on structures to docbook. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/ccwgroup.c | 67 ++++++-- drivers/s390/cio/device.c | 64 ++++++-- drivers/s390/cio/device_ops.c | 241 ++++++++++++++++++++++++---- include/asm-s390/ccwdev.h | 75 ++++----- include/asm-s390/ccwgroup.h | 32 +++- include/asm-s390/cio.h | 288 +++++++++++++++++++++++----------- 6 files changed, 575 insertions(+), 192 deletions(-) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b0a18f5176aa..9c3b9ea1e66f 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -152,16 +152,24 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) return 0; } -/* - * try to add a new ccwgroup device for one driver - * argc and argv[] are a list of bus_id's of devices - * belonging to the driver. +/** + * ccwgroup_create() - create and register a ccw group device + * @root: parent device for the new device + * @creator_id: identifier of creating driver + * @cdrv: ccw driver of slave devices + * @argc: number of slave devices + * @argv: bus ids of slave devices + * + * Create and register a new ccw group device as a child of @root. Slave + * devices are obtained from the list of bus ids given in @argv[] and must all + * belong to @cdrv. + * Returns: + * %0 on success and an error code on failure. + * Context: + * non-atomic */ -int -ccwgroup_create(struct device *root, - unsigned int creator_id, - struct ccw_driver *cdrv, - int argc, char *argv[]) +int ccwgroup_create(struct device *root, unsigned int creator_id, + struct ccw_driver *cdrv, int argc, char *argv[]) { struct ccwgroup_device *gdev; int i; @@ -390,8 +398,13 @@ static struct bus_type ccwgroup_bus_type = { .remove = ccwgroup_remove, }; -int -ccwgroup_driver_register (struct ccwgroup_driver *cdriver) +/** + * ccwgroup_driver_register() - register a ccw group driver + * @cdriver: driver to be registered + * + * This function is mainly a wrapper around driver_register(). + */ +int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) { /* register our new driver with the core */ cdriver->driver.bus = &ccwgroup_bus_type; @@ -406,8 +419,13 @@ __ccwgroup_match_all(struct device *dev, void *data) return 1; } -void -ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) +/** + * ccwgroup_driver_unregister() - deregister a ccw group driver + * @cdriver: driver to be deregistered + * + * This function is mainly a wrapper around driver_unregister(). + */ +void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) { struct device *dev; @@ -427,8 +445,16 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) driver_unregister(&cdriver->driver); } -int -ccwgroup_probe_ccwdev(struct ccw_device *cdev) +/** + * ccwgroup_probe_ccwdev() - probe function for slave devices + * @cdev: ccw device to be probed + * + * This is a dummy probe function for ccw devices that are slave devices in + * a ccw group device. + * Returns: + * always %0 + */ +int ccwgroup_probe_ccwdev(struct ccw_device *cdev) { return 0; } @@ -452,8 +478,15 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) return NULL; } -void -ccwgroup_remove_ccwdev(struct ccw_device *cdev) +/** + * ccwgroup_remove_ccwdev() - remove function for slave devices + * @cdev: ccw device to be removed + * + * This is a remove function for ccw devices that are slave devices in a ccw + * group device. It sets the ccw device offline and also deregisters the + * embedding ccw group device. + */ +void ccwgroup_remove_ccwdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e44d92eac8e9..3943a4fde22a 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -357,8 +357,18 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) cdev->private->dev_id.devno); } -int -ccw_device_set_offline(struct ccw_device *cdev) +/** + * ccw_device_set_offline() - disable a ccw device for I/O + * @cdev: target ccw device + * + * This function calls the driver's set_offline() function for @cdev, if + * given, and then disables @cdev. + * Returns: + * %0 on success and a negative error value on failure. + * Context: + * enabled, ccw device lock not held + */ +int ccw_device_set_offline(struct ccw_device *cdev) { int ret; @@ -396,8 +406,19 @@ ccw_device_set_offline(struct ccw_device *cdev) return ret; } -int -ccw_device_set_online(struct ccw_device *cdev) +/** + * ccw_device_set_online() - enable a ccw device for I/O + * @cdev: target ccw device + * + * This function first enables @cdev and then calls the driver's set_online() + * function for @cdev, if given. If set_online() returns an error, @cdev is + * disabled again. + * Returns: + * %0 on success and a negative error value on failure. + * Context: + * enabled, ccw device lock not held + */ +int ccw_device_set_online(struct ccw_device *cdev) { int ret; @@ -1326,8 +1347,19 @@ __ccwdev_check_busid(struct device *dev, void *id) } -struct ccw_device * -get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) +/** + * get_ccwdev_by_busid() - obtain device from a bus id + * @cdrv: driver the device is owned by + * @bus_id: bus id of the device to be searched + * + * This function searches all devices owned by @cdrv for a device with a bus + * id matching @bus_id. + * Returns: + * If a match is found, its reference count of the found device is increased + * and it is returned; else %NULL is returned. + */ +struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, + const char *bus_id) { struct device *dev; struct device_driver *drv; @@ -1409,8 +1441,15 @@ struct bus_type ccw_bus_type = { .remove = ccw_device_remove, }; -int -ccw_driver_register (struct ccw_driver *cdriver) +/** + * ccw_driver_register() - register a ccw driver + * @cdriver: driver to be registered + * + * This function is mainly a wrapper around driver_register(). + * Returns: + * %0 on success and a negative error value on failure. + */ +int ccw_driver_register(struct ccw_driver *cdriver) { struct device_driver *drv = &cdriver->driver; @@ -1420,8 +1459,13 @@ ccw_driver_register (struct ccw_driver *cdriver) return driver_register(drv); } -void -ccw_driver_unregister (struct ccw_driver *cdriver) +/** + * ccw_driver_unregister() - deregister a ccw driver + * @cdriver: driver to be deregistered + * + * This function is mainly a wrapper around driver_unregister(). + */ +void ccw_driver_unregister(struct ccw_driver *cdriver) { driver_unregister(&cdriver->driver); } diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 14eba854b155..7fd2dadc3297 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -25,6 +25,16 @@ #include "device.h" #include "chp.h" +/** + * ccw_device_set_options_mask() - set some options and unset the rest + * @cdev: device for which the options are to be set + * @flags: options to be set + * + * All flags specified in @flags are set, all flags not specified in @flags + * are cleared. + * Returns: + * %0 on success, -%EINVAL on an invalid flag combination. + */ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) { /* @@ -40,6 +50,15 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) return 0; } +/** + * ccw_device_set_options() - set some options + * @cdev: device for which the options are to be set + * @flags: options to be set + * + * All flags specified in @flags are set, the remainder is left untouched. + * Returns: + * %0 on success, -%EINVAL if an invalid flag combination would ensue. + */ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) { /* @@ -59,6 +78,13 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) return 0; } +/** + * ccw_device_clear_options() - clear some options + * @cdev: device for which the options are to be cleared + * @flags: options to be cleared + * + * All flags specified in @flags are cleared, the remainder is left untouched. + */ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) { cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0; @@ -67,8 +93,22 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0; } -int -ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) +/** + * ccw_device_clear() - terminate I/O request processing + * @cdev: target ccw device + * @intparm: interruption parameter; value is only used if no I/O is + * outstanding, otherwise the intparm associated with the I/O request + * is returned + * + * ccw_device_clear() calls csch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) { struct subchannel *sch; int ret; @@ -89,10 +129,33 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) return ret; } -int -ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags) +/** + * ccw_device_start_key() - start a s390 channel program with key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags) { struct subchannel *sch; int ret; @@ -135,11 +198,38 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, return ret; } - -int -ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags, int expires) +/** + * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags, int expires) { int ret; @@ -152,18 +242,67 @@ ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, return ret; } -int -ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, unsigned long flags) +/** + * ccw_device_start() - start a s390 channel program + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, unsigned long flags) { return ccw_device_start_key(cdev, cpa, intparm, lpm, PAGE_DEFAULT_KEY, flags); } -int -ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, unsigned long flags, - int expires) +/** + * ccw_device_start_timeout() - start a s390 channel program with timeout + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, + unsigned long flags, int expires) { return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, PAGE_DEFAULT_KEY, flags, @@ -171,8 +310,23 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, } -int -ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) +/** + * ccw_device_halt() - halt I/O request processing + * @cdev: target ccw device + * @intparm: interruption parameter; value is only used if no I/O is + * outstanding, otherwise the intparm associated with the I/O request + * is returned + * + * ccw_device_halt() calls hsch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state, + * -%EBUSY on device busy or interrupt pending. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) { struct subchannel *sch; int ret; @@ -193,8 +347,20 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) return ret; } -int -ccw_device_resume(struct ccw_device *cdev) +/** + * ccw_device_resume() - resume channel program execution + * @cdev: target ccw device + * + * ccw_device_resume() calls rsch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state, + * -%EBUSY on device busy or interrupt pending. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_resume(struct ccw_device *cdev) { struct subchannel *sch; @@ -260,11 +426,21 @@ ccw_device_call_handler(struct ccw_device *cdev) return 1; } -/* - * Search for CIW command in extended sense data. +/** + * ccw_device_get_ciw() - Search for CIW command in extended sense data. + * @cdev: ccw device to inspect + * @ct: command type to look for + * + * During SenseID, command information words (CIWs) describing special + * commands available to the device may have been stored in the extended + * sense data. This function searches for CIWs of a specified command + * type in the extended sense data. + * Returns: + * %NULL if no extended sense data has been stored or if no CIW of the + * specified command type could be found, + * else a pointer to the CIW of the specified command type. */ -struct ciw * -ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) +struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) { int ciw_cnt; @@ -276,8 +452,14 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) return NULL; } -__u8 -ccw_device_get_path_mask(struct ccw_device *cdev) +/** + * ccw_device_get_path_mask() - get currently available paths + * @cdev: ccw device to be queried + * Returns: + * %0 if no subchannel for the device is available, + * else the mask of currently available paths for the ccw device's subchannel. + */ +__u8 ccw_device_get_path_mask(struct ccw_device *cdev) { struct subchannel *sch; @@ -357,8 +539,7 @@ out_unlock: return ret; } -void * -ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) +void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) { struct subchannel *sch; struct chp_id chpid; diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h index 1aeda27d5a8b..8e961aa4b394 100644 --- a/include/asm-s390/ccwdev.h +++ b/include/asm-s390/ccwdev.h @@ -67,36 +67,53 @@ ccw_device_id_match(const struct ccw_device_id *array, return NULL; } -/* The struct ccw device is our replacement for the globally accessible - * ioinfo array. ioinfo will mutate into a subchannel device later. +/** + * struct ccw_device - channel attached device + * @ccwlock: pointer to device lock + * @id: id of this device + * @drv: ccw driver for this device + * @dev: embedded device structure + * @online: online status of device + * @handler: interrupt handler * - * Reference: Documentation/s390/driver-model.txt */ + * @handler is a member of the device rather than the driver since a driver + * can have different interrupt handlers for different ccw devices + * (multi-subchannel drivers). + */ struct ccw_device { spinlock_t *ccwlock; +/* private: */ struct ccw_device_private *private; /* cio private information */ - struct ccw_device_id id; /* id of this device, driver_info is - set by ccw_find_driver */ - struct ccw_driver *drv; /* */ - struct device dev; /* */ +/* public: */ + struct ccw_device_id id; + struct ccw_driver *drv; + struct device dev; int online; - /* This is sick, but a driver can have different interrupt handlers - for different ccw_devices (multi-subchannel drivers)... */ void (*handler) (struct ccw_device *, unsigned long, struct irb *); }; -/* Each ccw driver registers with the ccw root bus */ +/** + * struct ccw driver - device driver for channel attached devices + * @owner: owning module + * @ids: ids supported by this driver + * @probe: function called on probe + * @remove: function called on remove + * @set_online: called when setting device online + * @set_offline: called when setting device offline + * @notify: notify driver of device state changes + * @driver: embedded device driver structure + * @name: device driver name + */ struct ccw_driver { - struct module *owner; /* for automatic MOD_INC_USE_COUNT */ - struct ccw_device_id *ids; /* probe driver with these devs */ - int (*probe) (struct ccw_device *); /* ask driver to probe dev */ + struct module *owner; + struct ccw_device_id *ids; + int (*probe) (struct ccw_device *); void (*remove) (struct ccw_device *); - /* device is no longer available */ int (*set_online) (struct ccw_device *); int (*set_offline) (struct ccw_device *); int (*notify) (struct ccw_device *, int); - struct device_driver driver; /* higher level structure, don't init - this from your driver */ + struct device_driver driver; char *name; }; @@ -124,36 +141,10 @@ extern void ccw_device_clear_options(struct ccw_device *, unsigned long); /* Allow forced onlining of boxed devices. */ #define CCWDEV_ALLOW_FORCE 0x0008 -/* - * ccw_device_start() - * - * Start a S/390 channel program. When the interrupt arrives, the - * IRQ handler is called, either immediately, delayed (dev-end missing, - * or sense required) or never (no IRQ handler registered). - * Depending on the action taken, ccw_device_start() returns: - * 0 - Success - * -EBUSY - Device busy, or status pending - * -ENODEV - Device not operational - * -EINVAL - Device invalid for operation - */ extern int ccw_device_start(struct ccw_device *, struct ccw1 *, unsigned long, __u8, unsigned long); -/* - * ccw_device_start_timeout() - * - * This function notifies the device driver if the channel program has not - * completed during the specified time. If a timeout occurs, the channel - * program is terminated via xsch(), hsch() or csch(). - */ extern int ccw_device_start_timeout(struct ccw_device *, struct ccw1 *, unsigned long, __u8, unsigned long, int); -/* - * ccw_device_start_key() - * ccw_device_start_key_timeout() - * - * Same as ccw_device_start() and ccw_device_start_timeout(), except a - * storage key != default key can be provided for the I/O. - */ extern int ccw_device_start_key(struct ccw_device *, struct ccw1 *, unsigned long, __u8, __u8, unsigned long); extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *, diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h index 925b3ddfa141..7109c7cab87e 100644 --- a/include/asm-s390/ccwgroup.h +++ b/include/asm-s390/ccwgroup.h @@ -4,19 +4,41 @@ struct ccw_device; struct ccw_driver; +/** + * struct ccwgroup_device - ccw group device + * @creator_id: unique number of the driver + * @state: online/offline state + * @count: number of attached slave devices + * @dev: embedded device structure + * @cdev: variable number of slave devices, allocated as needed + */ struct ccwgroup_device { - unsigned long creator_id; /* unique number of the driver */ + unsigned long creator_id; enum { CCWGROUP_OFFLINE, CCWGROUP_ONLINE, } state; +/* private: */ atomic_t onoff; struct mutex reg_mutex; - unsigned int count; /* number of attached slave devices */ - struct device dev; /* master device */ - struct ccw_device *cdev[0]; /* variable number, allocate as needed */ +/* public: */ + unsigned int count; + struct device dev; + struct ccw_device *cdev[0]; }; +/** + * struct ccwgroup_driver - driver for ccw group devices + * @owner: driver owner + * @name: driver name + * @max_slaves: maximum number of slave devices + * @driver_id: unique id + * @probe: function called on probe + * @remove: function called on remove + * @set_online: function called when device is set online + * @set_offline: function called when device is set offline + * @driver: embedded driver structure + */ struct ccwgroup_driver { struct module *owner; char *name; @@ -28,7 +50,7 @@ struct ccwgroup_driver { int (*set_online) (struct ccwgroup_device *); int (*set_offline) (struct ccwgroup_device *); - struct device_driver driver; /* this driver */ + struct device_driver driver; }; extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index 1982fb344164..2f08c16e44ad 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h @@ -15,30 +15,50 @@ #define LPM_ANYPATH 0xff #define __MAX_CSSID 0 -/* - * subchannel status word +/** + * struct scsw - 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: adress-limit checking control + * @ssi: supress-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 scsw { - __u32 key : 4; /* subchannel key */ - __u32 sctl : 1; /* suspend control */ - __u32 eswf : 1; /* ESW format */ - __u32 cc : 2; /* deferred condition code */ - __u32 fmt : 1; /* format */ - __u32 pfch : 1; /* prefetch */ - __u32 isic : 1; /* initial-status interruption control */ - __u32 alcc : 1; /* address-limit checking control */ - __u32 ssi : 1; /* supress-suspended interruption */ - __u32 zcc : 1; /* zero condition code */ - __u32 ectl : 1; /* extended control */ - __u32 pno : 1; /* path not operational */ - __u32 res : 1; /* reserved */ - __u32 fctl : 3; /* function control */ - __u32 actl : 7; /* activity control */ - __u32 stctl : 5; /* status control */ - __u32 cpa; /* channel program address */ - __u32 dstat : 8; /* device status */ - __u32 cstat : 8; /* subchannel status */ - __u32 count : 16; /* residual count */ + __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)); #define SCSW_FCTL_CLEAR_FUNC 0x1 @@ -110,11 +130,22 @@ struct scsw { #define SNS2_ENV_DATA_PRESENT 0x10 #define SNS2_INPRECISE_END 0x04 +/** + * struct ccw1 - channel command word + * @cmd_code: command code + * @flags: flags, like IDA adressing, etc. + * @count: byte count + * @cda: data address + * + * The ccw is the basic structure to build channel programs that perform + * operations with the device or the control unit. Only Format-1 channel + * command words are supported. + */ struct ccw1 { - __u8 cmd_code; /* command code */ - __u8 flags; /* flags, like IDA addressing, etc. */ - __u16 count; /* byte count */ - __u32 cda; /* data address */ + __u8 cmd_code; + __u8 flags; + __u16 count; + __u32 cda; } __attribute__ ((packed,aligned(8))); #define CCW_FLAG_DC 0x80 @@ -140,102 +171,162 @@ struct ccw1 { #define SENSE_MAX_COUNT 0x20 +/** + * struct erw - extended report word + * @res0: reserved + * @auth: authorization check + * @pvrf: path-verification-required flag + * @cpt: channel-path timeout + * @fsavf: failing storage address validity flag + * @cons: concurrent sense + * @scavf: secondary ccw address validity flag + * @fsaf: failing storage address format + * @scnt: sense count, if @cons == %1 + * @res16: reserved + */ struct erw { - __u32 res0 : 3; /* reserved */ - __u32 auth : 1; /* Authorization check */ - __u32 pvrf : 1; /* path-verification-required flag */ - __u32 cpt : 1; /* channel-path timeout */ - __u32 fsavf : 1; /* Failing storage address validity flag */ - __u32 cons : 1; /* concurrent-sense */ - __u32 scavf : 1; /* Secondary ccw address validity flag */ - __u32 fsaf : 1; /* Failing storage address format */ - __u32 scnt : 6; /* sense count if cons == 1 */ - __u32 res16 : 16; /* reserved */ + __u32 res0 : 3; + __u32 auth : 1; + __u32 pvrf : 1; + __u32 cpt : 1; + __u32 fsavf : 1; + __u32 cons : 1; + __u32 scavf : 1; + __u32 fsaf : 1; + __u32 scnt : 6; + __u32 res16 : 16; } __attribute__ ((packed)); -/* - * subchannel logout area +/** + * struct sublog - subchannel logout area + * @res0: reserved + * @esf: extended status flags + * @lpum: last path used mask + * @arep: ancillary report + * @fvf: field-validity flags + * @sacc: storage access code + * @termc: termination code + * @devsc: device-status check + * @serr: secondary error + * @ioerr: i/o-error alert + * @seqc: sequence code */ struct sublog { - __u32 res0 : 1; /* reserved */ - __u32 esf : 7; /* extended status flags */ - __u32 lpum : 8; /* last path used mask */ - __u32 arep : 1; /* ancillary report */ - __u32 fvf : 5; /* field-validity flags */ - __u32 sacc : 2; /* storage access code */ - __u32 termc : 2; /* termination code */ - __u32 devsc : 1; /* device-status check */ - __u32 serr : 1; /* secondary error */ - __u32 ioerr : 1; /* i/o-error alert */ - __u32 seqc : 3; /* sequence code */ + __u32 res0 : 1; + __u32 esf : 7; + __u32 lpum : 8; + __u32 arep : 1; + __u32 fvf : 5; + __u32 sacc : 2; + __u32 termc : 2; + __u32 devsc : 1; + __u32 serr : 1; + __u32 ioerr : 1; + __u32 seqc : 3; } __attribute__ ((packed)); -/* - * Format 0 Extended Status Word (ESW) +/** + * struct esw0 - Format 0 Extended Status Word (ESW) + * @sublog: subchannel logout + * @erw: extended report word + * @faddr: failing storage address + * @saddr: secondary ccw address */ struct esw0 { - struct sublog sublog; /* subchannel logout */ - struct erw erw; /* extended report word */ - __u32 faddr[2]; /* failing storage address */ - __u32 saddr; /* secondary ccw address */ + struct sublog sublog; + struct erw erw; + __u32 faddr[2]; + __u32 saddr; } __attribute__ ((packed)); -/* - * Format 1 Extended Status Word (ESW) +/** + * struct esw1 - Format 1 Extended Status Word (ESW) + * @zero0: reserved zeros + * @lpum: last path used mask + * @zero16: reserved zeros + * @erw: extended report word + * @zeros: three fullwords of zeros */ struct esw1 { - __u8 zero0; /* reserved zeros */ - __u8 lpum; /* last path used mask */ - __u16 zero16; /* reserved zeros */ - struct erw erw; /* extended report word */ - __u32 zeros[3]; /* 2 fullwords of zeros */ + __u8 zero0; + __u8 lpum; + __u16 zero16; + struct erw erw; + __u32 zeros[3]; } __attribute__ ((packed)); -/* - * Format 2 Extended Status Word (ESW) +/** + * struct esw2 - Format 2 Extended Status Word (ESW) + * @zero0: reserved zeros + * @lpum: last path used mask + * @dcti: device-connect-time interval + * @erw: extended report word + * @zeros: three fullwords of zeros */ struct esw2 { - __u8 zero0; /* reserved zeros */ - __u8 lpum; /* last path used mask */ - __u16 dcti; /* device-connect-time interval */ - struct erw erw; /* extended report word */ - __u32 zeros[3]; /* 2 fullwords of zeros */ + __u8 zero0; + __u8 lpum; + __u16 dcti; + struct erw erw; + __u32 zeros[3]; } __attribute__ ((packed)); -/* - * Format 3 Extended Status Word (ESW) +/** + * struct esw3 - Format 3 Extended Status Word (ESW) + * @zero0: reserved zeros + * @lpum: last path used mask + * @res: reserved + * @erw: extended report word + * @zeros: three fullwords of zeros */ struct esw3 { - __u8 zero0; /* reserved zeros */ - __u8 lpum; /* last path used mask */ - __u16 res; /* reserved */ - struct erw erw; /* extended report word */ - __u32 zeros[3]; /* 2 fullwords of zeros */ + __u8 zero0; + __u8 lpum; + __u16 res; + struct erw erw; + __u32 zeros[3]; } __attribute__ ((packed)); -/* - * interruption response block +/** + * struct irb - interruption response block + * @scsw: subchannel status word + * @esw: extened status word, 4 formats + * @ecw: extended control word + * + * The irb that is handed to the device driver when an interrupt occurs. For + * solicited interrupts, the common I/O layer already performs checks whether + * a field is valid; a field not being valid is always passed as %0. + * If a unit check occured, @ecw may contain sense data; this is retrieved + * by the common I/O layer itself if the device doesn't support concurrent + * sense (so that the device driver never needs to perform basic sene itself). + * For unsolicited interrupts, the irb is passed as-is (expect for sense data, + * if applicable). */ struct irb { - struct scsw scsw; /* subchannel status word */ - union { /* extended status word, 4 formats */ + struct scsw scsw; + union { struct esw0 esw0; struct esw1 esw1; struct esw2 esw2; struct esw3 esw3; } esw; - __u8 ecw[32]; /* extended control word */ + __u8 ecw[32]; } __attribute__ ((packed,aligned(4))); -/* - * command information word (CIW) layout +/** + * struct ciw - command information word (CIW) layout + * @et: entry type + * @reserved: reserved bits + * @ct: command type + * @cmd: command code + * @count: command count */ struct ciw { - __u32 et : 2; /* entry type */ - __u32 reserved : 2; /* reserved */ - __u32 ct : 4; /* command type */ - __u32 cmd : 8; /* command */ - __u32 count : 16; /* coun */ + __u32 et : 2; + __u32 reserved : 2; + __u32 ct : 4; + __u32 cmd : 8; + __u32 count : 16; } __attribute__ ((packed)); #define CIW_TYPE_RCD 0x0 /* read configuration data */ @@ -258,11 +349,32 @@ struct ciw { /* Sick revalidation of device. */ #define CIO_REVALIDATE 0x0008 +/** + * struct ccw_dev_id - unique identifier for ccw devices + * @ssid: subchannel set id + * @devno: device number + * + * This structure is not directly based on any hardware structure. The + * hardware identifies a device by its device number and its subchannel, + * which is in turn identified by its id. In order to get a unique identifier + * for ccw devices across subchannel sets, @struct ccw_dev_id has been + * introduced. + */ struct ccw_dev_id { u8 ssid; u16 devno; }; +/** + * ccw_device_id_is_equal() - compare two ccw_dev_ids + * @dev_id1: a ccw_dev_id + * @dev_id2: another ccw_dev_id + * Returns: + * %1 if the two structures are equal field-by-field, + * %0 if not. + * Context: + * any + */ static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1, struct ccw_dev_id *dev_id2) { From 3a2fbff228f773e3628bc26a688d40b2214af025 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:18 +0200 Subject: [PATCH 2325/2804] [S390] cio: Add s390-drivers book. s390-drivers is generated using the docbook comments. It should eventually supersede Documentation/s390/cds.txt. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- Documentation/DocBook/Makefile | 2 +- Documentation/DocBook/s390-drivers.tmpl | 149 ++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 Documentation/DocBook/s390-drivers.tmpl diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 08687e45e19d..1a7f53068ec2 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -11,7 +11,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ procfs-guide.xml writing_usb_driver.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ - genericirq.xml + genericirq.xml s390-drivers.xml ### # The build process is as follows (targets): diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl new file mode 100644 index 000000000000..254e769282a4 --- /dev/null +++ b/Documentation/DocBook/s390-drivers.tmpl @@ -0,0 +1,149 @@ + + + + + + Writing s390 channel device drivers + + + + Cornelia + Huck + +
+ cornelia.huck@de.ibm.com +
+
+
+
+ + + 2007 + IBM Corp. + + + + + This documentation 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 + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + This document describes the interfaces available for device drivers that + drive s390 based channel attached devices. This includes interfaces for + interaction with the hardware and interfaces for interacting with the + common driver core. Those interfaces are provided by the s390 common I/O + layer. + + + The document assumes a familarity with the technical terms associated + with the s390 channel I/O architecture. For a description of this + architecture, please refer to the "z/Architecture: Principles of + Operation", IBM publication no. SA22-7832. + + + While most I/O devices on a s390 system are typically driven through the + channel I/O mechanism described here, there are various other methods + (like the diag interface). These are out of the scope of this document. + + + Some additional information can also be found in the kernel source + under Documentation/s390/driver-model.txt. + + + + The ccw bus + + The ccw bus typically contains the majority of devices available to + a s390 system. Named after the channel command word (ccw), the basic + command structure used to address its devices, the ccw bus contains + so-called channel attached devices. They are addressed via subchannels, + visible on the css bus. A device driver, however, will never interact + with the subchannel directly, but only via the device on the ccw bus, + the ccw device. + + + I/O functions for channel-attached devices + + Some hardware structures have been translated into C structures for use + by the common I/O layer and device drivers. For more information on + the hardware structures represented here, please consult the Principles + of Operation. + +!Iinclude/asm-s390/cio.h + + + ccw devices + + Devices that want to initiate channel I/O need to attach to the ccw bus. + Interaction with the driver core is done via the common I/O layer, which + provides the abstractions of ccw devices and ccw device drivers. + + + The functions that initiate or terminate channel I/O all act upon a + ccw device structure. Device drivers must not bypass those functions + or strange side effects may happen. + +!Iinclude/asm-s390/ccwdev.h +!Edrivers/s390/cio/device.c +!Edrivers/s390/cio/device_ops.c + + + The channel-measurement facility + + The channel-measurement facility provides a means to collect + measurement data which is made available by the channel subsystem + for each channel attached device. + +!Iinclude/asm-s390/cmb.h +!Edrivers/s390/cio/cmf.c + + + + + The ccwgroup bus + + The ccwgroup bus only contains artificial devices, created by the user. + Many networking devices (e.g. qeth) are in fact composed of several + ccw devices (like read, write and data channel for qeth). The + ccwgroup bus provides a mechanism to create a meta-device which + contains those ccw devices as slave devices and can be associated + with the netdevice. + + + ccw group devices +!Iinclude/asm-s390/ccwgroup.h +!Edrivers/s390/cio/ccwgroup.c + + + +
From a0ea22c3d912de6044f83b07dcc26ee006106139 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:19 +0200 Subject: [PATCH 2326/2804] [S390] cio: Minor style fixes. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 8ce4ff95cc9c..3d49919a4517 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch) opm = 0; chp_id_init(&chpid); - for (i=0; i < 8; i++) { + for (i = 0; i < 8; i++) { opm <<= 1; chpid.id = sch->schib.pmcw.chpid[i]; if (chp_get_status(chpid) != 0) @@ -118,7 +118,7 @@ static int s390_vary_chpid(struct chp_id chpid, int on) sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid, chpid.id); - CIO_TRACE_EVENT( 2, dbf_text); + CIO_TRACE_EVENT(2, dbf_text); status = chp_get_status(chpid); if (!on && !status) { @@ -353,7 +353,7 @@ static ssize_t chp_shared_show(struct device *dev, static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); -static struct attribute * chp_attrs[] = { +static struct attribute *chp_attrs[] = { &dev_attr_status.attr, &dev_attr_configure.attr, &dev_attr_type.attr, From a55360df406cca797ac07d722688dd7ec29bf46e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:20 +0200 Subject: [PATCH 2327/2804] [S390] cio: Disable channel path measurements on shutdown/reboot. Make sure channel path measurements are disabled via a reboot notifier since we cannot rely on userspace to disable it again after enabling it. This is 1. clean and 2. makes sure that channel path measurements do not stay enabled after a reboot not involving a subsystem reset (which would lead to the channel subsystem scribbling onto random memory). Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 08f6e7b6c999..5d83dd471461 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "css.h" #include "cio.h" @@ -632,6 +633,29 @@ static int __init setup_css(int nr) return 0; } +static int css_reboot_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + int ret, i; + + ret = NOTIFY_DONE; + for (i = 0; i <= __MAX_CSSID; i++) { + struct channel_subsystem *css; + + css = channel_subsystems[i]; + if (css->cm_enabled) + if (chsc_secm(css, 0)) + ret = NOTIFY_BAD; + } + + return ret; +} + +static struct notifier_block css_reboot_notifier = { + .notifier_call = css_reboot_event, +}; + /* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the @@ -697,12 +721,17 @@ init_channel_subsystem (void) if (ret) goto out_file; } + ret = register_reboot_notifier(&css_reboot_notifier); + if (ret) + goto out_pseudo; css_init_done = 1; ctl_set_bit(6, 28); for_each_subchannel(__init_channel_subsystem, NULL); return 0; +out_pseudo: + device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev); out_file: device_remove_file(&channel_subsystems[i]->device, &dev_attr_cm_enable); From 958974fb596ad037fb571cf2899f783764a83e1a Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:21 +0200 Subject: [PATCH 2328/2804] [S390] cio: Introduce ccw_bus_type.shutdown. Introduce a shutdown method for the ccw bus that calls the driver specific shutdown method in struct ccw_driver. Switch zfcp to the new ccw_driver shutdown method. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 10 ++++++++++ drivers/s390/scsi/zfcp_ccw.c | 10 ++++------ include/asm-s390/ccwdev.h | 2 ++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 3943a4fde22a..7fb271c60c27 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1433,12 +1433,22 @@ ccw_device_remove (struct device *dev) return 0; } +static void ccw_device_shutdown(struct device *dev) +{ + struct ccw_device *cdev; + + cdev = to_ccwdev(dev); + if (cdev->drv && cdev->drv->shutdown) + cdev->drv->shutdown(cdev); +} + struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, .uevent = ccw_uevent, .probe = ccw_device_probe, .remove = ccw_device_remove, + .shutdown = ccw_device_shutdown, }; /** diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 1c8f71a59855..c0d1c0eb3209 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *); static int zfcp_ccw_set_online(struct ccw_device *); static int zfcp_ccw_set_offline(struct ccw_device *); static int zfcp_ccw_notify(struct ccw_device *, int); -static void zfcp_ccw_shutdown(struct device *); +static void zfcp_ccw_shutdown(struct ccw_device *); static struct ccw_device_id zfcp_ccw_device_id[] = { {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, @@ -51,9 +51,7 @@ static struct ccw_driver zfcp_ccw_driver = { .set_online = zfcp_ccw_set_online, .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, - .driver = { - .shutdown = zfcp_ccw_shutdown, - }, + .shutdown = zfcp_ccw_shutdown, }; MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); @@ -277,12 +275,12 @@ zfcp_ccw_register(void) * Makes sure that QDIO queues are down when the system gets stopped. */ static void -zfcp_ccw_shutdown(struct device *dev) +zfcp_ccw_shutdown(struct ccw_device *cdev) { struct zfcp_adapter *adapter; down(&zfcp_data.config_sema); - adapter = dev_get_drvdata(dev); + adapter = dev_get_drvdata(&cdev->dev); zfcp_erp_adapter_shutdown(adapter, 0); zfcp_erp_wait(adapter); up(&zfcp_data.config_sema); diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h index 8e961aa4b394..066aa70518ce 100644 --- a/include/asm-s390/ccwdev.h +++ b/include/asm-s390/ccwdev.h @@ -102,6 +102,7 @@ struct ccw_device { * @set_online: called when setting device online * @set_offline: called when setting device offline * @notify: notify driver of device state changes + * @shutdown: called at device shutdown * @driver: embedded device driver structure * @name: device driver name */ @@ -113,6 +114,7 @@ struct ccw_driver { int (*set_online) (struct ccw_device *); int (*set_offline) (struct ccw_device *); int (*notify) (struct ccw_device *, int); + void (*shutdown) (struct ccw_device *); struct device_driver driver; char *name; }; From 1842f2b1847155805f9cc8c834ef4272198b272b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:22 +0200 Subject: [PATCH 2329/2804] [S390] cio: Disable channel measurements (cmf) on shutdown/reboot. Disable channel measurements for all ccw devices via the ccw bus's shutdown method. Clear residual cmf related information that may be in the schib when setting up a new subchannel. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 5 +++++ drivers/s390/cio/device.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index f2708d65be5a..46905345159e 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -619,6 +619,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) sch->schib.pmcw.ena = 0; if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; /* multipath mode */ + /* clean up possible residual cmf stuff */ + sch->schib.pmcw.mme = 0; + sch->schib.pmcw.mbfc = 0; + sch->schib.pmcw.mbi = 0; + sch->schib.mba = 0; return 0; out: if (!cio_is_console(schid)) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 7fb271c60c27..eea9b1de0af7 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -21,6 +21,7 @@ #include #include #include /* HZ */ +#include #include "cio.h" #include "cio_debug.h" @@ -1440,6 +1441,7 @@ static void ccw_device_shutdown(struct device *dev) cdev = to_ccwdev(dev); if (cdev->drv && cdev->drv->shutdown) cdev->drv->shutdown(cdev); + disable_cmf(cdev); } struct bus_type ccw_bus_type = { From e103178658f07131fee4e643596982b604cc63a9 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:23 +0200 Subject: [PATCH 2330/2804] [S390] cio: Fix device attributes for early devices. Don't forget to set dev->groups for early ccw devices like the console device so the default attributes are created. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index eea9b1de0af7..c96380db0136 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1123,6 +1123,7 @@ io_subchannel_probe (struct subchannel *sch) * device, e.g. the console. */ cdev = sch->dev.driver_data; + cdev->dev.groups = ccwdev_attr_groups; device_initialize(&cdev->dev); ccw_device_register(cdev); /* From 6920c12a407e073168d6cae164fa820d666af5c6 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:24 +0200 Subject: [PATCH 2331/2804] [S390] Add Documentation/s390/00-INDEX. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- Documentation/s390/00-INDEX | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/s390/00-INDEX diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX new file mode 100644 index 000000000000..93ed47119bac --- /dev/null +++ b/Documentation/s390/00-INDEX @@ -0,0 +1,26 @@ +00-INDEX + - this file. +3270.ChangeLog + - ChangeLog for the UTS Global 3270-support patch (outdated). +3270.txt + - how to use the IBM 3270 display system support. +cds.txt + - s390 common device support (common I/O layer). +CommonIO + - common I/O layer command line parameters and /proc entries +config3270.sh + - example configuration for 3270 devices. +DASD + - information on the DASD disk device driver. +Debugging390.txt + - hints for debugging on s390 systems. +driver-model.txt + - information on s390 devices and the driver model. +monreader.txt + - information on accessing the z/VM monitor stream from Linux. +s390dbf.txt + - information on using the s390 debug feature. +TAPE + - information on the driver for channel-attached tapes. +zfcpdump + - information on the s390 SCSI dump tool. From 3952c8d43aa23862181ad23ecdf72895b4be3143 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:25 +0200 Subject: [PATCH 2332/2804] [S390] cio: Documentation update. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- Documentation/s390/00-INDEX | 2 +- Documentation/s390/CommonIO | 51 +++++++++++++++++++++---------------- Documentation/s390/cds.txt | 8 +++--- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX index 93ed47119bac..3a2b96302ecc 100644 --- a/Documentation/s390/00-INDEX +++ b/Documentation/s390/00-INDEX @@ -7,7 +7,7 @@ cds.txt - s390 common device support (common I/O layer). CommonIO - - common I/O layer command line parameters and /proc entries + - common I/O layer command line parameters, procfs and debugfs entries config3270.sh - example configuration for 3270 devices. DASD diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO index 22f82f21bc60..86320aa3fb0b 100644 --- a/Documentation/s390/CommonIO +++ b/Documentation/s390/CommonIO @@ -1,5 +1,5 @@ -S/390 common I/O-Layer - command line parameters and /proc entries -================================================================== +S/390 common I/O-Layer - command line parameters, procfs and debugfs entries +============================================================================ Command line parameters ----------------------- @@ -7,9 +7,9 @@ Command line parameters * cio_msg = yes | no Determines whether information on found devices and sensed device - characteristics should be shown during startup, i. e. messages of the types - "Detected device 0.0.4711 on subchannel 0.0.0042" and "SenseID: Device - 0.0.4711 reports: ...". + characteristics should be shown during startup or when new devices are + found, i. e. messages of the types "Detected device 0.0.4711 on subchannel + 0.0.0042" and "SenseID: Device 0.0.4711 reports: ...". Default is off. @@ -26,8 +26,10 @@ Command line parameters An ignored device can be un-ignored later; see the "/proc entries"-section for details. - The devices must be given either as bus ids (0.0.abcd) or as hexadecimal - device numbers (0xabcd or abcd, for 2.4 backward compatibility). + The devices must be given either as bus ids (0.x.abcd) or as hexadecimal + device numbers (0xabcd or abcd, for 2.4 backward compatibility). If you + give a device number 0xabcd, it will be interpreted as 0.0.abcd. + You can use the 'all' keyword to ignore all devices. The '!' operator will cause the I/O-layer to _not_ ignore a device. The command line is parsed from left to right. @@ -81,31 +83,36 @@ Command line parameters will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored devices. - The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward - compatibility, by the device number in hexadecimal (0xabcd or abcd). + The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward + compatibility, by the device number in hexadecimal (0xabcd or abcd). Device + numbers given as 0xabcd will be interpreted as 0.0.abcd. + +* For some of the information present in the /proc filesystem in 2.4 (namely, + /proc/subchannels and /proc/chpids), see driver-model.txt. + Information formerly in /proc/irq_count is now in /proc/interrupts. -* /proc/s390dbf/cio_*/ (S/390 debug feature) +debugfs entries +--------------- + +* /sys/kernel/debug/s390dbf/cio_*/ (S/390 debug feature) Some views generated by the debug feature to hold various debug outputs. - - /proc/s390dbf/cio_crw/sprintf + - /sys/kernel/debug/s390dbf/cio_crw/sprintf Messages from the processing of pending channel report words (machine check - handling), which will also show when CONFIG_DEBUG_CRW is defined. + handling). - - /proc/s390dbf/cio_msg/sprintf - Various debug messages from the common I/O-layer; generally, messages which - will also show when CONFIG_DEBUG_IO is defined. + - /sys/kernel/debug/s390dbf/cio_msg/sprintf + Various debug messages from the common I/O-layer, including messages + printed when cio_msg=yes. - - /proc/s390dbf/cio_trace/hex_ascii + - /sys/kernel/debug/s390dbf/cio_trace/hex_ascii Logs the calling of functions in the common I/O-layer and, if applicable, which subchannel they were called for, as well as dumps of some data structures (like irb in an error case). The level of logging can be changed to be more or less verbose by piping to - /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on - the S/390 debug feature (Documentation/s390/s390dbf.txt) for details. - -* For some of the information present in the /proc filesystem in 2.4 (namely, - /proc/subchannels and /proc/chpids), see driver-model.txt. - Information formerly in /proc/irq_count is now in /proc/interrupts. + /sys/kernel/debug/s390dbf/cio_*/level a number between 0 and 6; see the + documentation on the S/390 debug feature (Documentation/s390/s390dbf.txt) + for details. diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt index 58919d6a593a..3081927cc2d6 100644 --- a/Documentation/s390/cds.txt +++ b/Documentation/s390/cds.txt @@ -286,10 +286,10 @@ first: timeout value -EIO: the common I/O layer terminated the request due to an error state -If the concurrent sense flag in the extended status word in the irb is set, the -field irb->scsw.count describes the number of device specific sense bytes -available in the extended control word irb->scsw.ecw[0]. No device sensing by -the device driver itself is required. +If the concurrent sense flag in the extended status word (esw) in the irb is +set, the field erw.scnt in the esw describes the number of device specific +sense bytes available in the extended control word irb->scsw.ecw[]. No device +sensing by the device driver itself is required. The device interrupt handler can use the following definitions to investigate the primary unit check source coded in sense byte 0 : From 3f4cf6e72f9f6a0b046b32881acc4f829f3aaa46 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:26 +0200 Subject: [PATCH 2333/2804] [S390] cio: Avoid machine check vs. not operational races. There was the possibilty that an action like ccw_device_set_offline() triggered by a device gone machine check might trigger a not oper event. Unfortunately, this could lead to the situation that we tried to unregister a subchannel twice: Once from the slow path evaluation, and once via the not oper event. Fix this by always using the same mechanism (css_schedule_eval()) for triggering the unregister. This makes sure that unregistration will only be done once. As an added bonus, it also simplyfies the code. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 3 +- drivers/s390/cio/device.h | 1 - drivers/s390/cio/device_fsm.c | 144 +++++----------------------------- 3 files changed, 21 insertions(+), 127 deletions(-) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index c96380db0136..39f02b48e4c7 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -969,8 +969,7 @@ out: wake_up(&ccw_device_init_wq); } -void -ccw_device_call_sch_unregister(struct work_struct *work) +static void ccw_device_call_sch_unregister(struct work_struct *work) { struct ccw_device_private *priv; struct ccw_device *cdev; diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index b66338b76579..0d4089600439 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -80,7 +80,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); void ccw_device_do_unreg_rereg(struct work_struct *); -void ccw_device_call_sch_unregister(struct work_struct *); void ccw_device_move_to_orphanage(struct work_struct *); int ccw_device_is_orphan(struct ccw_device *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index f772ef0a4f22..8867443b8060 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -544,51 +544,6 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event) } -static void -ccw_device_nopath_notify(struct work_struct *work) -{ - struct ccw_device_private *priv; - struct ccw_device *cdev; - struct subchannel *sch; - int ret; - unsigned long flags; - - priv = container_of(work, struct ccw_device_private, kick_work); - cdev = priv->cdev; - spin_lock_irqsave(cdev->ccwlock, flags); - sch = to_subchannel(cdev->dev.parent); - /* Extra sanity. */ - if (sch->lpm) - goto out_unlock; - if (sch->driver && sch->driver->notify) { - spin_unlock_irqrestore(cdev->ccwlock, flags); - ret = sch->driver->notify(&sch->dev, CIO_NO_PATH); - spin_lock_irqsave(cdev->ccwlock, flags); - } else - ret = 0; - if (!ret) { - if (get_device(&sch->dev)) { - /* Driver doesn't want to keep device. */ - cio_disable_subchannel(sch); - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, - &cdev->private->kick_work); - } else - put_device(&sch->dev); - } - } else { - cio_disable_subchannel(sch); - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - wake_up(&cdev->private->wait_q); - } -out_unlock: - spin_unlock_irqrestore(cdev->ccwlock, flags); -} - void ccw_device_verify_done(struct ccw_device *cdev, int err) { @@ -632,12 +587,9 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) default: /* Reset oper notify indication after verify error. */ cdev->private->flags.donotify = 0; - if (cdev->online) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else + if (cdev->online) + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + else ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -691,11 +643,7 @@ ccw_device_disband_done(struct ccw_device *cdev, int err) break; default: cdev->private->flags.donotify = 0; - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -766,59 +714,16 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event) } /* - * Handle not operational event while offline. + * Handle not operational event in non-special state. */ -static void -ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event) +static void ccw_device_generic_notoper(struct ccw_device *cdev, + enum dev_event dev_event) { struct subchannel *sch; cdev->private->state = DEV_STATE_NOT_OPER; sch = to_subchannel(cdev->dev.parent); - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - wake_up(&cdev->private->wait_q); -} - -/* - * Handle not operational event while online. - */ -static void -ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) -{ - struct subchannel *sch; - int ret; - - sch = to_subchannel(cdev->dev.parent); - if (sch->driver->notify) { - spin_unlock_irq(cdev->ccwlock); - ret = sch->driver->notify(&sch->dev, - sch->lpm ? CIO_GONE : CIO_NO_PATH); - spin_lock_irq(cdev->ccwlock); - } else - ret = 0; - if (ret) { - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - wake_up(&cdev->private->wait_q); - return; - } - cdev->private->state = DEV_STATE_NOT_OPER; - cio_disable_subchannel(sch); - if (sch->schib.scsw.actl != 0) { - // FIXME: not-oper indication to device driver ? - ccw_device_call_handler(cdev); - } - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - wake_up(&cdev->private->wait_q); + css_schedule_eval(sch->schid); } /* @@ -916,18 +821,9 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) cdev->private->state = DEV_STATE_TIMEOUT_KILL; return; } - if (ret == -ENODEV) { - struct subchannel *sch; - - sch = to_subchannel(cdev->dev.parent); - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else - dev_fsm_event(cdev, DEV_EVENT_NOTOPER); - } else if (cdev->handler) + if (ret == -ENODEV) + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + else if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-ETIMEDOUT)); } @@ -1234,7 +1130,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_SENSE_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, @@ -1246,50 +1142,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_OFFLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, + [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_STATE_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_delay_verify, }, [DEV_STATE_ONLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_irq, [DEV_EVENT_TIMEOUT] = ccw_device_online_timeout, [DEV_EVENT_VERIFY] = ccw_device_online_verify, }, [DEV_STATE_W4SENSE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_w4sense, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_online_verify, }, [DEV_STATE_DISBAND_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_disband_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_BOXED] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_stlck_done, [DEV_EVENT_TIMEOUT] = ccw_device_stlck_done, [DEV_EVENT_VERIFY] = ccw_device_nop, }, /* states to wait for i/o completion before doing something */ [DEV_STATE_CLEAR_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_clear_verify, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_TIMEOUT_KILL] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq, [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME From 731475c92ed587ac0e112c49b47b12de8d0ab609 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:27 +0200 Subject: [PATCH 2334/2804] [S390] zcrypt: make init/exit functions static. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_mono.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c index 2a9349ad68b7..44253fdd4136 100644 --- a/drivers/s390/crypto/zcrypt_mono.c +++ b/drivers/s390/crypto/zcrypt_mono.c @@ -45,7 +45,7 @@ /** * The module initialization code. */ -int __init zcrypt_init(void) +static int __init zcrypt_init(void) { int rc; @@ -86,7 +86,7 @@ out: /** * The module termination code. */ -void __exit zcrypt_exit(void) +static void __exit zcrypt_exit(void) { zcrypt_cex2a_exit(); zcrypt_pcixcc_exit(); From 16db63fda0c63de7a7feb59c6ca59ce7e2670ffb Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Fri, 12 Oct 2007 16:11:28 +0200 Subject: [PATCH 2335/2804] [S390] zcrypt: remove duplicated struct CPRBX definition Signed-off-by: Ralph Wuerthner --- drivers/s390/crypto/zcrypt_pcixcc.c | 2 +- drivers/s390/crypto/zcrypt_pcixcc.h | 45 ----------------------------- include/asm-s390/zcrypt.h | 4 +-- 3 files changed, 3 insertions(+), 48 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 64948788d301..c28369260c2f 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, }; struct { struct type6_hdr hdr; - struct ica_CPRBX cprbx; + struct CPRBX cprbx; } __attribute__((packed)) *msg = ap_msg->message; int rcblen = CEIL4(xcRB->request_control_blk_length); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index a78ff307fd19..8cb7d7a6973b 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h @@ -28,51 +28,6 @@ #ifndef _ZCRYPT_PCIXCC_H_ #define _ZCRYPT_PCIXCC_H_ -/** - * CPRBX - * Note that all shorts and ints are big-endian. - * All pointer fields are 16 bytes long, and mean nothing. - * - * A request CPRB is followed by a request_parameter_block. - * - * The request (or reply) parameter block is organized thus: - * function code - * VUD block - * key block - */ -struct CPRBX { - unsigned short cprb_len; /* CPRB length 220 */ - unsigned char cprb_ver_id; /* CPRB version id. 0x02 */ - unsigned char pad_000[3]; /* Alignment pad bytes */ - unsigned char func_id[2]; /* function id 0x5432 */ - unsigned char cprb_flags[4]; /* Flags */ - unsigned int req_parml; /* request parameter buffer len */ - unsigned int req_datal; /* request data buffer */ - unsigned int rpl_msgbl; /* reply message block length */ - unsigned int rpld_parml; /* replied parameter block len */ - unsigned int rpl_datal; /* reply data block len */ - unsigned int rpld_datal; /* replied data block len */ - unsigned int req_extbl; /* request extension block len */ - unsigned char pad_001[4]; /* reserved */ - unsigned int rpld_extbl; /* replied extension block len */ - unsigned char req_parmb[16]; /* request parm block 'address' */ - unsigned char req_datab[16]; /* request data block 'address' */ - unsigned char rpl_parmb[16]; /* reply parm block 'address' */ - unsigned char rpl_datab[16]; /* reply data block 'address' */ - unsigned char req_extb[16]; /* request extension block 'addr'*/ - unsigned char rpl_extb[16]; /* reply extension block 'addres'*/ - unsigned short ccp_rtcode; /* server return code */ - unsigned short ccp_rscode; /* server reason code */ - unsigned int mac_data_len; /* Mac Data Length */ - unsigned char logon_id[8]; /* Logon Identifier */ - unsigned char mac_value[8]; /* Mac Value */ - unsigned char mac_content_flgs;/* Mac content flag byte */ - unsigned char pad_002; /* Alignment */ - unsigned short domain; /* Domain */ - unsigned char pad_003[12]; /* Domain masks */ - unsigned char pad_004[36]; /* reserved */ -} __attribute__((packed)); - int zcrypt_pcixcc_init(void); void zcrypt_pcixcc_exit(void); diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h index b90e55888a55..a5dada617751 100644 --- a/include/asm-s390/zcrypt.h +++ b/include/asm-s390/zcrypt.h @@ -91,7 +91,7 @@ struct ica_rsa_modexpo_crt { * VUD block * key block */ -struct ica_CPRBX { +struct CPRBX { unsigned short cprb_len; /* CPRB length 220 */ unsigned char cprb_ver_id; /* CPRB version id. 0x02 */ unsigned char pad_000[3]; /* Alignment pad bytes */ @@ -130,7 +130,7 @@ struct ica_CPRBX { unsigned char cntrl_domain[4];/* Control domain */ unsigned char S390enf_mask[4];/* S/390 enforcement mask */ unsigned char pad_004[36]; /* reserved */ -}; +} __attribute__((packed)); /** * xcRB From 39aa7cf612cc4e7f688c18f04c35afb51c57472e Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Fri, 12 Oct 2007 16:11:29 +0200 Subject: [PATCH 2336/2804] [S390] zcrypt: fix ap_reset_domain() Resetting of a all queues within a domain requires that a domain must be selected first. Signed-off-by: Ralph Wuerthner Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 90bd22014513..d334b0f7a1ec 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1231,8 +1231,9 @@ static void ap_reset_domain(void) { int i; - for (i = 0; i < AP_DEVICES; i++) - ap_reset_queue(AP_MKQID(i, ap_domain_index)); + if (ap_domain_index != -1) + for (i = 0; i < AP_DEVICES; i++) + ap_reset_queue(AP_MKQID(i, ap_domain_index)); } static void ap_reset_all(void) From 2af48080e100d66db8f086af70a70713a953a83d Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Fri, 12 Oct 2007 16:11:30 +0200 Subject: [PATCH 2337/2804] [S390] zcrypt: fix PCIXCC/CEX2C error recovery Symptom: zcrypt fails by setting all PCIXCC/CEX2C cards offline for a certain type of invalid keys. Problem: zcrypt does not handle rc=12/rs=769 request responses correctly Solution: modify convert_type86_ica() to handle these error codes correctly Signed-off-by: Ralph Wuerthner Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_pcixcc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index c28369260c2f..70b9ddc8cf9d 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -432,14 +432,17 @@ static int convert_type86_ica(struct zcrypt_device *zdev, } if (service_rc == 8 && service_rs == 770) { PDEBUG("Invalid key length on PCIXCC/CEX2C\n"); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; - return -EAGAIN; + return -EINVAL; } if (service_rc == 8 && service_rs == 783) { PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n"); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; return -EAGAIN; } + if (service_rc == 12 && service_rs == 769) { + PDEBUG("Invalid key on PCIXCC/CEX2C\n"); + return -EINVAL; + } PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n", service_rc, service_rs); zdev->online = 0; From 11b8bf0107e688434b9e0570fd05e7c715534f3b Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 12 Oct 2007 16:11:31 +0200 Subject: [PATCH 2338/2804] [S390] appldata_base: Misc cpuinit annotations and bugfix appldata_offline_cpu() is only called from __cpuinit-marked hotplug notifier callback and from the __exit-marked module_exit function, therefore candidate for __cpuexit. BTW the __exit module_exit function appldata_exit() of this driver fails to unregister_hotcpu_notifier() the notifier_block that was registered by appldata_init() during module startup. This will lead to oops if hotplug notification comes after module has been unloaded. Let's fix this by unregistering the notifier appropriately (before appldata_offline_cpu()'ing the CPUs). Signed-off-by: Satyam Sharma Cc: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Martin Schwidefsky --- arch/s390/appldata/appldata_base.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 62391fb1f61f..a355d8133261 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -547,8 +547,7 @@ static void __cpuinit appldata_online_cpu(int cpu) spin_unlock(&appldata_timer_lock); } -static void -appldata_offline_cpu(int cpu) +static void __cpuexit appldata_offline_cpu(int cpu) { del_virt_timer(&per_cpu(appldata_timer, cpu)); if (atomic_dec_and_test(&appldata_expire_count)) { @@ -560,9 +559,9 @@ appldata_offline_cpu(int cpu) spin_unlock(&appldata_timer_lock); } -static int __cpuinit -appldata_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +static int __cpuinit appldata_cpu_notify(struct notifier_block *self, + unsigned long action, + void *hcpu) { switch (action) { case CPU_ONLINE: @@ -646,6 +645,8 @@ static void __exit appldata_exit(void) } spin_unlock(&appldata_ops_lock); + unregister_hotcpu_notifier(&appldata_nb); + for_each_online_cpu(i) appldata_offline_cpu(i); From 076fc808ab804c6cfb40fd0caa0b74dd50e0d5de Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 12 Oct 2007 16:11:32 +0200 Subject: [PATCH 2339/2804] [S390] appldata_base: Remove module_exit function and modular stuff arch/s390/Kconfig tells us that CONFIG_APPLDATA_BASE is bool and hence can never be built modular. Given this, defining appldata_exit() function is pointless (and wasteful, actually). Remove all that. Previous patch annotated appldata_offline_cpu() as __cpuexit, but now with the __exit function appldata_exit() gone, the only callsite that references it is __cpuinit, so this function can also be __cpuinit, thereby saving space when HOTPLUG_CPU=n. Signed-off-by: Satyam Sharma Cc: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Martin Schwidefsky --- arch/s390/appldata/appldata_base.c | 54 ++---------------------------- 1 file changed, 2 insertions(+), 52 deletions(-) diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index a355d8133261..ac61cf43a7d9 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -547,7 +547,7 @@ static void __cpuinit appldata_online_cpu(int cpu) spin_unlock(&appldata_timer_lock); } -static void __cpuexit appldata_offline_cpu(int cpu) +static void __cpuinit appldata_offline_cpu(int cpu) { del_virt_timer(&per_cpu(appldata_timer, cpu)); if (atomic_dec_and_test(&appldata_expire_count)) { @@ -607,65 +607,15 @@ static int __init appldata_init(void) register_hotcpu_notifier(&appldata_nb); appldata_sysctl_header = register_sysctl_table(appldata_dir_table); -#ifdef MODULE - appldata_dir_table[0].de->owner = THIS_MODULE; - appldata_table[0].de->owner = THIS_MODULE; - appldata_table[1].de->owner = THIS_MODULE; -#endif P_DEBUG("Base interface initialized.\n"); return 0; } -/* - * appldata_exit() - * - * stop timer, unregister /proc entries - */ -static void __exit appldata_exit(void) -{ - struct list_head *lh; - struct appldata_ops *ops; - int rc, i; +__initcall(appldata_init); - P_DEBUG("Unloading module ...\n"); - /* - * ops list should be empty, but just in case something went wrong... - */ - spin_lock(&appldata_ops_lock); - list_for_each(lh, &appldata_ops_list) { - ops = list_entry(lh, struct appldata_ops, list); - rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, - (unsigned long) ops->data, ops->size, - ops->mod_lvl); - if (rc != 0) { - P_ERROR("STOP DIAG 0xDC for %s failed, " - "return code: %d\n", ops->name, rc); - } - } - spin_unlock(&appldata_ops_lock); - - unregister_hotcpu_notifier(&appldata_nb); - - for_each_online_cpu(i) - appldata_offline_cpu(i); - - appldata_timer_active = 0; - - unregister_sysctl_table(appldata_sysctl_header); - - destroy_workqueue(appldata_wq); - P_DEBUG("... module unloaded!\n"); -} /**************************** init / exit ******************************/ - -module_init(appldata_init); -module_exit(appldata_exit); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Gerald Schaefer"); -MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure"); - EXPORT_SYMBOL_GPL(appldata_register_ops); EXPORT_SYMBOL_GPL(appldata_unregister_ops); EXPORT_SYMBOL_GPL(appldata_diag); From 74ccbdc226cac44bb56cd479917195dc5132d7aa Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 12 Oct 2007 16:11:33 +0200 Subject: [PATCH 2340/2804] [S390] disassembler: fix output for insns with 6 operands. The termination condition of the loop that prints the operands of an instruction doesn't stop after the maximum of 6 operands. It continues with the operands of the next instruction format instead which create really long lines. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/dis.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 50d2235df732..5f315affc81e 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -1162,6 +1162,7 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr) unsigned int value; char separator; char *ptr; + int i; ptr = buffer; insn = find_insn(code); @@ -1169,7 +1170,8 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr) ptr += sprintf(ptr, "%.5s\t", insn->name); /* Extract the operands. */ separator = 0; - for (ops = formats[insn->format] + 1; *ops != 0; ops++) { + for (ops = formats[insn->format] + 1, i = 0; + *ops != 0 && i < 6; ops++, i++) { operand = operands + *ops; value = extract_operand(code, operand); if ((operand->flags & OPERAND_INDEX) && value == 0) From f5360106422302e8eed4d07ea8daf81ec19ca345 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 12 Oct 2007 16:11:34 +0200 Subject: [PATCH 2341/2804] [S390] disassembler: Remove redundant variable assignment There is no need to assign "0" to "hops" twice. Remove one assigment. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/dis.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 5f315affc81e..c14a336f6300 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -1243,7 +1243,6 @@ void show_code(struct pt_regs *regs) } /* Find a starting point for the disassembly. */ while (start < 32) { - hops = 0; for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) { if (!find_insn(code + start + i)) break; From 364c85584e030f7cfc25e9d27ca893dee6f4bf8e Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:35 +0200 Subject: [PATCH 2342/2804] [S390] Get rid of a bunch of sparse warnings again. Also removes a bunch of ^L in drivers/s390/cio/cmf.c Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/audit.c | 7 +------ arch/s390/kernel/audit.h | 15 +++++++++++++++ arch/s390/kernel/compat_audit.c | 1 + drivers/s390/char/con3270.c | 3 +-- drivers/s390/char/sclp.c | 5 ++--- drivers/s390/char/tty3270.c | 9 ++++++--- drivers/s390/char/tty3270.h | 16 ++++++++++++++++ drivers/s390/cio/chp.c | 8 ++++++-- drivers/s390/cio/cmf.c | 4 +--- drivers/s390/scsi/zfcp_dbf.c | 10 +++++----- drivers/s390/scsi/zfcp_erp.c | 18 ++++++++---------- 11 files changed, 62 insertions(+), 34 deletions(-) create mode 100644 arch/s390/kernel/audit.h create mode 100644 drivers/s390/char/tty3270.h diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c index d1c76fe10f29..f4932c22ebe4 100644 --- a/arch/s390/kernel/audit.c +++ b/arch/s390/kernel/audit.c @@ -2,6 +2,7 @@ #include #include #include +#include "audit.h" static unsigned dir_class[] = { #include @@ -40,7 +41,6 @@ int audit_classify_arch(int arch) int audit_classify_syscall(int abi, unsigned syscall) { #ifdef CONFIG_COMPAT - extern int s390_classify_syscall(unsigned); if (abi == AUDIT_ARCH_S390) return s390_classify_syscall(syscall); #endif @@ -61,11 +61,6 @@ int audit_classify_syscall(int abi, unsigned syscall) static int __init audit_classes_init(void) { #ifdef CONFIG_COMPAT - extern __u32 s390_dir_class[]; - extern __u32 s390_write_class[]; - extern __u32 s390_read_class[]; - extern __u32 s390_chattr_class[]; - extern __u32 s390_signal_class[]; audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class); audit_register_class(AUDIT_CLASS_READ_32, s390_read_class); audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class); diff --git a/arch/s390/kernel/audit.h b/arch/s390/kernel/audit.h new file mode 100644 index 000000000000..12b56f4b5a73 --- /dev/null +++ b/arch/s390/kernel/audit.h @@ -0,0 +1,15 @@ +#ifndef __ARCH_S390_KERNEL_AUDIT_H +#define __ARCH_S390_KERNEL_AUDIT_H + +#include + +#ifdef CONFIG_COMPAT +extern int s390_classify_syscall(unsigned); +extern __u32 s390_dir_class[]; +extern __u32 s390_write_class[]; +extern __u32 s390_read_class[]; +extern __u32 s390_chattr_class[]; +extern __u32 s390_signal_class[]; +#endif /* CONFIG_COMPAT */ + +#endif /* __ARCH_S390_KERNEL_AUDIT_H */ diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c index 0569f5126e49..d6487bf879e5 100644 --- a/arch/s390/kernel/compat_audit.c +++ b/arch/s390/kernel/compat_audit.c @@ -1,5 +1,6 @@ #undef __s390x__ #include +#include "audit.h" unsigned s390_dir_class[] = { #include diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index fd3479119eb4..0b040557db02 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -22,6 +22,7 @@ #include #include "raw3270.h" +#include "tty3270.h" #include "ctrlchar.h" #define CON3270_OUTPUT_BUFFER_SIZE 1024 @@ -507,8 +508,6 @@ con3270_write(struct console *co, const char *str, unsigned int count) spin_unlock_irqrestore(&cp->view.lock,flags); } -extern struct tty_driver *tty3270_driver; - static struct tty_driver * con3270_device(struct console *c, int *index) { diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index fa62e6944057..25629b92dec3 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -93,6 +93,7 @@ static volatile enum sclp_mask_state_t { #define SCLP_RETRY_INTERVAL 30 static void sclp_process_queue(void); +static void __sclp_make_read_req(void); static int sclp_init_mask(int calculate); static int sclp_init(void); @@ -115,7 +116,6 @@ sclp_service_call(sclp_cmdw_t command, void *sccb) return 0; } -static inline void __sclp_make_read_req(void); static void __sclp_queue_read_req(void) @@ -318,8 +318,7 @@ sclp_read_cb(struct sclp_req *req, void *data) } /* Prepare read event data request. Called while sclp_lock is locked. */ -static inline void -__sclp_make_read_req(void) +static void __sclp_make_read_req(void) { struct sccb_header *sccb; diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index bc33068b9ce2..70b1980a08b6 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -25,8 +25,8 @@ #include #include - #include "raw3270.h" +#include "tty3270.h" #include "keyboard.h" #define TTY3270_CHAR_BUF_SIZE 256 @@ -1338,8 +1338,11 @@ tty3270_getpar(struct tty3270 *tp, int ix) static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy) { - tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx)); - cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy)); + int max_cx = max(0, cx); + int max_cy = max(0, cy); + + tp->cx = min_t(int, tp->view.cols - 1, max_cx); + cy = min_t(int, tp->view.rows - 3, max_cy); if (cy != tp->cy) { tty3270_convert_line(tp, tp->cy); tp->cy = cy; diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h new file mode 100644 index 000000000000..799da57f0390 --- /dev/null +++ b/drivers/s390/char/tty3270.h @@ -0,0 +1,16 @@ +/* + * drivers/s390/char/tty3270.h + * + * Copyright IBM Corp. 2007 + * + */ + +#ifndef __DRIVERS_S390_CHAR_TTY3270_H +#define __DRIVERS_S390_CHAR_TTY3270_H + +#include +#include + +extern struct tty_driver *tty3270_driver; + +#endif /* __DRIVERS_S390_CHAR_TTY3270_H */ diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 3d49919a4517..42c1f4659adb 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -140,9 +140,11 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct channel_path *chp; + struct device *device; unsigned int size; - chp = to_channelpath(container_of(kobj, struct device, kobj)); + device = container_of(kobj, struct device, kobj); + chp = to_channelpath(device); if (!chp->cmg_chars) return 0; @@ -193,9 +195,11 @@ static ssize_t chp_measurement_read(struct kobject *kobj, { struct channel_path *chp; struct channel_subsystem *css; + struct device *device; unsigned int size; - chp = to_channelpath(container_of(kobj, struct device, kobj)); + device = container_of(kobj, struct device, kobj); + chp = to_channelpath(device); css = to_css(chp->dev.parent); size = sizeof(struct cmg_entry); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 6ef0ab895477..b960f66843e4 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -489,7 +489,6 @@ static struct cmb_area cmb_area = { .num_channels = 1024, }; - /* ****** old style CMB handling ********/ /* @@ -812,7 +811,7 @@ static struct cmb_operations cmbops_basic = { .align = align_cmb, .attr_group = &cmf_attr_group, }; - + /* ******** extended cmb handling ********/ /** @@ -1079,7 +1078,6 @@ static struct cmb_operations cmbops_extended = { .align = align_cmbe, .attr_group = &cmf_attr_group_ext, }; - static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) { diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 5f3212440f68..ffa3bf756943 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -19,8 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include +#include #include "zfcp_ext.h" static u32 dbfsize = 4; @@ -35,17 +35,17 @@ static int zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck) { unsigned long long sec; - struct timespec xtime; + struct timespec dbftime; int len = 0; stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); sec = stck >> 12; do_div(sec, 1000000); - xtime.tv_sec = sec; + dbftime.tv_sec = sec; stck -= (sec * 1000000) << 12; - xtime.tv_nsec = ((stck * 1000) >> 12); + dbftime.tv_nsec = ((stck * 1000) >> 12); len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n", - label, xtime.tv_sec, xtime.tv_nsec); + label, dbftime.tv_sec, dbftime.tv_nsec); return len; } diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d8cd75ce2d9a..16b4418ab257 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int); static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *, int); -static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); +static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *, int); @@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, static void zfcp_erp_action_ready(struct zfcp_erp_action *); static int zfcp_erp_action_exists(struct zfcp_erp_action *); -static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *); -static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *); +static void zfcp_erp_action_to_ready(struct zfcp_erp_action *); +static void zfcp_erp_action_to_running(struct zfcp_erp_action *); static void zfcp_erp_memwait_handler(unsigned long); @@ -952,7 +952,7 @@ zfcp_erp_memwait_handler(unsigned long data) * action gets an appropriate flag and will be processed * accordingly */ -void zfcp_erp_timeout_handler(unsigned long data) +static void zfcp_erp_timeout_handler(unsigned long data) { struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; struct zfcp_adapter *adapter = erp_action->adapter; @@ -1491,7 +1491,7 @@ zfcp_erp_strategy_statechange(int action, return retval; } -static inline int +static int zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) { return @@ -2001,7 +2001,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) * returns: 0 - successful setup * !0 - failed setup */ -int +static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) { int retval; @@ -3248,8 +3248,7 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) zfcp_erp_action_dismiss(&unit->erp_action); } -static inline void -zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; @@ -3258,8 +3257,7 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) list_move(&erp_action->list, &erp_action->adapter->erp_running_head); } -static inline void -zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; From ca08de05ed83b7c2029c742ef3310a284b7790ee Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 12 Oct 2007 16:11:36 +0200 Subject: [PATCH 2343/2804] [S390] remove packed attribute from ext_int_info_t. ext_int_info_t is no longer used in entry(64).S Instead do_extint is a C function that handles the hash search. As the structure is handled in C code, we can also remove the packed attribute to avoid alignment issues. (Currently there is no alignment problem in ext_int_info_t, even if packet) Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- include/asm-s390/s390_ext.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/asm-s390/s390_ext.h b/include/asm-s390/s390_ext.h index 1e72362cad78..2afc060266a2 100644 --- a/include/asm-s390/s390_ext.h +++ b/include/asm-s390/s390_ext.h @@ -5,7 +5,7 @@ * include/asm-s390/s390_ext.h * * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 1999,2007 * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com) */ @@ -14,15 +14,11 @@ typedef void (*ext_int_handler_t)(__u16 code); -/* - * Warning: if you change ext_int_info_t you have to change the - * external interrupt handler in entry.S too. - */ typedef struct ext_int_info_t { struct ext_int_info_t *next; ext_int_handler_t handler; __u16 code; -} __attribute__ ((packed)) ext_int_info_t; +} ext_int_info_t; extern ext_int_info_t *ext_int_hash[]; From 5a291321d6b7ab40923b9a42b36746f7b5ca0055 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:37 +0200 Subject: [PATCH 2344/2804] [S390] Get rid of ARCH_KMALLOC_MINALIGN. slab cache debugging code has been changed so that we always get a minimum alignment of the alignment of a 64-integer. Since this is 8 on s390/s390x there is no need of ARCH_KMALLOC_MINALIGN anymore. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- include/asm-s390/cache.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/asm-s390/cache.h b/include/asm-s390/cache.h index cdf431b061bb..9b866816863c 100644 --- a/include/asm-s390/cache.h +++ b/include/asm-s390/cache.h @@ -14,8 +14,6 @@ #define L1_CACHE_BYTES 256 #define L1_CACHE_SHIFT 8 -#define ARCH_KMALLOC_MINALIGN 8 - #define __read_mostly __attribute__((__section__(".data.read_mostly"))) #endif From b18a2db416088ad54a4bfb59c0b932be383aee83 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:38 +0200 Subject: [PATCH 2345/2804] [S390] qdio: dont cast function pointers and use them to call functions. According to C99 6.3.2.3 it's undefined what happens if a converted pointer is used to call a function whose type is not compatible with the pointed-to type. That's what the qdio code is doing, so fix it. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index d8d479876ec7..151636cc8f24 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1024,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q) } static void -qdio_outbound_processing(struct qdio_q *q) +qdio_outbound_processing(unsigned long q) { - __qdio_outbound_processing(q); + __qdio_outbound_processing((struct qdio_q *) q); } /************************* INBOUND ROUTINES *******************************/ @@ -1449,9 +1449,10 @@ out: } static void -tiqdio_inbound_processing(struct qdio_q *q) +tiqdio_inbound_processing(unsigned long q) { - __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount)); + __tiqdio_inbound_processing((struct qdio_q *) q, + atomic_read(&spare_indicator_usecount)); } static void @@ -1494,9 +1495,9 @@ again: } static void -qdio_inbound_processing(struct qdio_q *q) +qdio_inbound_processing(unsigned long q) { - __qdio_inbound_processing(q); + __qdio_inbound_processing((struct qdio_q *) q); } /************************* MAIN ROUTINES *******************************/ @@ -1760,12 +1761,15 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->handler=input_handler; q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind; - q->tasklet.data=(unsigned long)q; /* q->is_thinint_q isn't valid at this time, but - * irq_ptr->is_thinint_irq is */ - q->tasklet.func=(void(*)(unsigned long)) - ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing: - &qdio_inbound_processing); + * irq_ptr->is_thinint_irq is + */ + if (irq_ptr->is_thinint_irq) + tasklet_init(&q->tasklet, tiqdio_inbound_processing, + (unsigned long) q); + else + tasklet_init(&q->tasklet, qdio_inbound_processing, + (unsigned long) q); /* actually this is not used for inbound queues. yet. */ atomic_set(&q->busy_siga_counter,0); @@ -1836,13 +1840,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->last_move_ftc=0; q->handler=output_handler; - q->tasklet.data=(unsigned long)q; - q->tasklet.func=(void(*)(unsigned long)) - &qdio_outbound_processing; - q->timer.function=(void(*)(unsigned long)) - &qdio_outbound_processing; - q->timer.data = (long)q; - init_timer(&q->timer); + tasklet_init(&q->tasklet, qdio_outbound_processing, + (unsigned long) q); + setup_timer(&q->timer, qdio_outbound_processing, + (unsigned long) q); atomic_set(&q->busy_siga_counter,0); q->timing.busy_start=0; From e108cebb21316714de43767e242316c784471740 Mon Sep 17 00:00:00 2001 From: vignesh babu Date: Fri, 12 Oct 2007 16:11:39 +0200 Subject: [PATCH 2346/2804] [S390] is_power_of_2 in drivers/s390/block/dasd_int.h Replacing n & (n - 1) for power of 2 check by is_power_of_2(n) Signed-off-by: vignesh babu Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/block/dasd_int.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index aeda52682446..d427daeef511 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -456,7 +457,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem) static inline int dasd_check_blocksize(int bsize) { - if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0) + if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize)) return -EMEDIUMTYPE; return 0; } From c622498e5c82217cda7f661eebbabdaad0814659 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 12 Oct 2007 16:11:40 +0200 Subject: [PATCH 2347/2804] [S390] qdio: change QDIO performance_stats error message priority Signed-off-by: Ursula Braun Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/qdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 151636cc8f24..40a3208c7cf3 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -3727,7 +3727,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count #endif /* CONFIG_64BIT */ } } else { - QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n"); + QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n"); return -EINVAL; } return count; From 210d3a90ce665509e4852977d7a3352654e5e990 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:41 +0200 Subject: [PATCH 2348/2804] [S390] Force link error if xchg/cmpxchg gets called with unsupported size. Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- include/asm-s390/system.h | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index 64a3cd05cae1..d866d3385556 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -130,6 +130,8 @@ extern void pfault_fini(void); __ret; \ }) +extern void __xchg_called_with_bad_pointer(void); + static inline unsigned long __xchg(unsigned long x, void * ptr, int size) { unsigned long addr, old; @@ -150,8 +152,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) : "=&d" (old), "=m" (*(int *) addr) : "d" (x << shift), "d" (~(255 << shift)), "a" (addr), "m" (*(int *) addr) : "memory", "cc", "0"); - x = old >> shift; - break; + return old >> shift; case 2: addr = (unsigned long) ptr; shift = (2 ^ (addr & 2)) << 3; @@ -166,8 +167,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) : "=&d" (old), "=m" (*(int *) addr) : "d" (x << shift), "d" (~(65535 << shift)), "a" (addr), "m" (*(int *) addr) : "memory", "cc", "0"); - x = old >> shift; - break; + return old >> shift; case 4: asm volatile( " l %0,0(%3)\n" @@ -176,8 +176,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) : "=&d" (old), "=m" (*(int *) ptr) : "d" (x), "a" (ptr), "m" (*(int *) ptr) : "memory", "cc"); - x = old; - break; + return old; #ifdef __s390x__ case 8: asm volatile( @@ -187,11 +186,11 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) : "=&d" (old), "=m" (*(long *) ptr) : "d" (x), "a" (ptr), "m" (*(long *) ptr) : "memory", "cc"); - x = old; - break; + return old; #endif /* __s390x__ */ - } - return x; + } + __xchg_called_with_bad_pointer(); + return x; } /* @@ -206,6 +205,8 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ (unsigned long)(n),sizeof(*(ptr)))) +extern void __cmpxchg_called_with_bad_pointer(void); + static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) { @@ -270,7 +271,8 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) return prev; #endif /* __s390x__ */ } - return old; + __cmpxchg_called_with_bad_pointer(); + return old; } /* From 6517156cd0225d666f53ecaf49b5b4784b0df8b6 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 12 Oct 2007 16:11:42 +0200 Subject: [PATCH 2349/2804] [S390] Use IPL CLEAR for reipl under z/VM If we use the CLEAR ipl option, reipl is faster, since then VM can release the memory, which has been paged out. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/ipl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 8b8f136d9cc7..66b51901c87d 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -735,10 +735,10 @@ void do_reipl(void) case REIPL_METHOD_CCW_VM: reipl_get_ascii_loadparm(loadparm); if (strlen(loadparm) == 0) - sprintf(buf, "IPL %X", + sprintf(buf, "IPL %X CLEAR", reipl_block_ccw->ipl_info.ccw.devno); else - sprintf(buf, "IPL %X LOADPARM '%s'", + sprintf(buf, "IPL %X CLEAR LOADPARM '%s'", reipl_block_ccw->ipl_info.ccw.devno, loadparm); __cpcmd(buf, NULL, 0, NULL); break; From cebe0fe70fbf033a1a6b7c5c8b79eb13060a4ab7 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Fri, 12 Oct 2007 16:11:43 +0200 Subject: [PATCH 2350/2804] [S390] Remove obsolete recommendation for 8M ramdisk size. Signed-off-by: Robert P. J. Day Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/block/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4245b7f80a49..ca4d7f0d09b7 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -361,8 +361,7 @@ config BLK_DEV_RAM_SIZE default "4096" help The default value is 4096 kilobytes. Only change this if you know - what are you doing. If you are using IBM S/390, then set this to - 8192. + what are you doing. config BLK_DEV_RAM_BLOCKSIZE int "Default RAM disk block size (bytes)" From 53a0868cb4d77dcba8e95e1033361ffdb6e510e2 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 12 Oct 2007 16:11:44 +0200 Subject: [PATCH 2351/2804] [S390] zcore: fix inline assembly in memcpy_real() memcpy_real uses the mvcle instruction. This instruction alters all used registers (source, destination and 2 x count). Therefore we have to flag those registers as input/output registers (+d). In addition to that, we have to specify, that we read from memory designated by "src" and write to memory designated by "dest". Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/char/zcore.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3712ede16723..7073daf77981 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -141,15 +141,16 @@ static int memcpy_real(void *dest, unsigned long src, size_t count) if (count == 0) return 0; - flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */ + flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */ asm volatile ( "0: mvcle %1,%2,0x0\n" "1: jo 0b\n" " lhi %0,0x0\n" "2:\n" EX_TABLE(1b,2b) - : "+d" (rc) - : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2) + : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), + "+d" (_len2), "=m" (*((long*)dest)) + : "m" (*((long*)src)) : "cc", "memory"); __raw_local_irq_ssm(flags); From e39394b84156bc0822785e379977fe75a5662aad Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:45 +0200 Subject: [PATCH 2352/2804] [S390] Make vmalloc area start at address > 4GB. Prevent that modules get loaded at addresses below 4GB to prevent exchanging system call table entries. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- include/asm-s390/pgtable.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 3208dc6c412c..39bb5192dc31 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -107,11 +107,18 @@ extern char empty_zero_page[PAGE_SIZE]; * any out-of-bounds memory accesses will hopefully be caught. * The vmalloc() routines leaves a hole of 4kB between each vmalloced * area for the same reason. ;) + * vmalloc area starts at 4GB to prevent syscall table entry exchanging + * from modules. */ extern unsigned long vmalloc_end; -#define VMALLOC_OFFSET (8*1024*1024) -#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \ - & ~(VMALLOC_OFFSET-1)) + +#ifdef CONFIG_64BIT +#define VMALLOC_ADDR (max(0x100000000UL, (unsigned long) high_memory)) +#else +#define VMALLOC_ADDR ((unsigned long) high_memory) +#endif +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START ((VMALLOC_ADDR + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #define VMALLOC_END vmalloc_end /* From a004fb0c33539ae90f25573505be6a116a76e639 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:46 +0200 Subject: [PATCH 2353/2804] [S390] cpcmd: fix inline assembly usage. After assigning values to specific registers memset was called. This may clobber the contents of the used registers. To solve this extract the two used inline assemblies into small functions that don't call any functions. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/cpcmd.c | 100 +++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 6c89f30c8e31..d8c1131e0815 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -2,7 +2,7 @@ * arch/s390/kernel/cpcmd.c * * S390 version - * Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 1999,2007 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Christian Borntraeger (cborntra@de.ibm.com), */ @@ -21,6 +21,49 @@ static DEFINE_SPINLOCK(cpcmd_lock); static char cpcmd_buf[241]; +static int diag8_noresponse(int cmdlen) +{ + register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf; + register unsigned long reg3 asm ("3") = cmdlen; + + asm volatile( +#ifndef CONFIG_64BIT + " diag %1,%0,0x8\n" +#else /* CONFIG_64BIT */ + " sam31\n" + " diag %1,%0,0x8\n" + " sam64\n" +#endif /* CONFIG_64BIT */ + : "+d" (reg3) : "d" (reg2) : "cc"); + return reg3; +} + +static int diag8_response(int cmdlen, char *response, int *rlen) +{ + register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf; + register unsigned long reg3 asm ("3") = (addr_t) response; + register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L; + register unsigned long reg5 asm ("5") = *rlen; + + asm volatile( +#ifndef CONFIG_64BIT + " diag %2,%0,0x8\n" + " brc 8,1f\n" + " ar %1,%4\n" +#else /* CONFIG_64BIT */ + " sam31\n" + " diag %2,%0,0x8\n" + " sam64\n" + " brc 8,1f\n" + " agr %1,%4\n" +#endif /* CONFIG_64BIT */ + "1:\n" + : "+d" (reg4), "+d" (reg5) + : "d" (reg2), "d" (reg3), "d" (*rlen) : "cc"); + *rlen = reg5; + return reg4; +} + /* * __cpcmd has some restrictions over cpcmd * - the response buffer must reside below 2GB (if any) @@ -28,59 +71,27 @@ static char cpcmd_buf[241]; */ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) { - unsigned cmdlen; - int return_code, return_len; + int cmdlen; + int rc; + int response_len; cmdlen = strlen(cmd); BUG_ON(cmdlen > 240); memcpy(cpcmd_buf, cmd, cmdlen); ASCEBC(cpcmd_buf, cmdlen); - if (response != NULL && rlen > 0) { - register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf; - register unsigned long reg3 asm ("3") = (addr_t) response; - register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L; - register unsigned long reg5 asm ("5") = rlen; - + if (response) { memset(response, 0, rlen); - asm volatile( -#ifndef CONFIG_64BIT - " diag %2,%0,0x8\n" - " brc 8,1f\n" - " ar %1,%4\n" -#else /* CONFIG_64BIT */ - " sam31\n" - " diag %2,%0,0x8\n" - " sam64\n" - " brc 8,1f\n" - " agr %1,%4\n" -#endif /* CONFIG_64BIT */ - "1:\n" - : "+d" (reg4), "+d" (reg5) - : "d" (reg2), "d" (reg3), "d" (rlen) : "cc"); - return_code = (int) reg4; - return_len = (int) reg5; - EBCASC(response, rlen); + response_len = rlen; + rc = diag8_response(cmdlen, response, &rlen); + EBCASC(response, response_len); } else { - register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf; - register unsigned long reg3 asm ("3") = cmdlen; - return_len = 0; - asm volatile( -#ifndef CONFIG_64BIT - " diag %1,%0,0x8\n" -#else /* CONFIG_64BIT */ - " sam31\n" - " diag %1,%0,0x8\n" - " sam64\n" -#endif /* CONFIG_64BIT */ - : "+d" (reg3) : "d" (reg2) : "cc"); - return_code = (int) reg3; + rc = diag8_noresponse(cmdlen); } - if (response_code != NULL) - *response_code = return_code; - return return_len; + if (response_code) + *response_code = rc; + return rlen; } - EXPORT_SYMBOL(__cpcmd); int cpcmd(const char *cmd, char *response, int rlen, int *response_code) @@ -109,5 +120,4 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) } return len; } - EXPORT_SYMBOL(cpcmd); From 1b9fd76e30368489b561db5794b3831bcc28c8bc Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 12 Oct 2007 16:11:47 +0200 Subject: [PATCH 2354/2804] [S390] tape: Fix medium state handling Currently there are situations, where the tape medium state (loaded, unloaded, unknown) is not set correctly. The reason is that the medium association field is used to determine the medium state. This not always leads to correct results. To fix that we use another field of the medium sense data instead. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_3590.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 9f244c591eeb..da25f8e24152 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -708,16 +708,22 @@ static void tape_3590_med_state_set(struct tape_device *device, c_info = &TAPE_3590_CRYPT_INFO(device); - if (sense->masst == MSENSE_UNASSOCIATED) { + DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst); + switch (sense->macst) { + case 0x04: + case 0x05: + case 0x06: tape_med_state_set(device, MS_UNLOADED); TAPE_3590_CRYPT_INFO(device).medium_status = 0; return; - } - if (sense->masst != MSENSE_ASSOCIATED_MOUNT) { - PRINT_ERR("Unknown medium state: %x\n", sense->masst); + case 0x08: + case 0x09: + tape_med_state_set(device, MS_LOADED); + break; + default: + tape_med_state_set(device, MS_UNKNOWN); return; } - tape_med_state_set(device, MS_LOADED); c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; if (sense->flags & MSENSE_CRYPT_MASK) { PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); @@ -835,15 +841,17 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb) /* Probably result of halt ssch */ return TAPE_IO_PENDING; else if (irb->scsw.dstat == 0x85) - /* Device Ready -> check medium state */ - tape_3590_schedule_work(device, TO_MSEN); - else if (irb->scsw.dstat & DEV_STAT_ATTENTION) + /* Device Ready */ + DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id); + else if (irb->scsw.dstat & DEV_STAT_ATTENTION) { tape_3590_schedule_work(device, TO_READ_ATTMSG); - else { + } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); tape_dump_sense(device, NULL, irb); } + /* check medium state */ + tape_3590_schedule_work(device, TO_MSEN); return TAPE_IO_SUCCESS; } From 2b12f996c992334f65f6d9e0a3e731ec049fdad3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:48 +0200 Subject: [PATCH 2355/2804] [S390] vmwatchdog: fix broken inline assembly. Constraint for err is wrong since it is preinitialized and the code relies on it in case of an exception. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmwatchdog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 680b9b58b80e..6f40facb1c4d 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout, "0: la %0,0\n" "1:\n" EX_TABLE(0b,1b) - : "=d" (err) : "d"(__func), "d"(__timeout), - "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc"); + : "+d" (err) : "d"(__func), "d"(__timeout), + "d"(__cmdp), "d"(__cmdl) : "1", "cc"); return err; } From e16af09d76ac3322e26f5b3ff49979691f350c12 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Fri, 12 Oct 2007 16:11:49 +0200 Subject: [PATCH 2356/2804] [S390] s390: beautify vmlinux.lds Introduce a consistent style in vmlinux.lds. This style is gradually being introduced for all archs. A few lables were moved inside the section definition so they are assigned the correct value of gcc decide to align the content to another address than the one . has. In the past this has fixed several bugs but for s390 it will not impact due to all the alignmnet already introduced. Stabs definitions are consolidated in asm-generic/vmlinux.lds.h This patch also introduce support for DWARF - without knowing if this makes sense for s390. Signed-off-by: Sam Ravnborg Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/vmlinux.lds.S | 207 ++++++++++++++++++--------------- 1 file changed, 114 insertions(+), 93 deletions(-) diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index b4622a3889b0..f6b16aec32e7 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -18,121 +18,142 @@ jiffies = jiffies_64; SECTIONS { - . = 0x00000000; - _text = .; /* Text and read-only data */ - .text : { - *(.text.head) + . = 0x00000000; + .text : { + _text = .; /* Text and read-only data */ + *(.text.head) TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) - *(.gnu.warning) + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + *(.fixup) + *(.gnu.warning) } = 0x0700 - _etext = .; /* End of text section */ + _etext = .; /* End of text section */ - RODATA + RODATA #ifdef CONFIG_SHARED_KERNEL - . = ALIGN(1048576); /* VM shared segments are 1MB aligned */ + . = ALIGN(1048576); /* VM shared segments are 1MB aligned */ #endif - . = ALIGN(4096); - _eshared = .; /* End of shareable data */ + . = ALIGN(4096); + _eshared = .; /* End of shareable data */ - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - NOTES - - BUG_TABLE - - .data : { /* Data */ - DATA_DATA - CONSTRUCTORS + . = ALIGN(16); /* Exception table */ + __ex_table : { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; } - . = ALIGN(4096); - __nosave_begin = .; - .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); - __nosave_end = .; + NOTES + BUG_TABLE - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } + .data : { /* Data */ + DATA_DATA + CONSTRUCTORS + } - . = ALIGN(256); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } + . = ALIGN(4096); + .data_nosave : { + __nosave_begin = .; + *(.data.nosave) + } + . = ALIGN(4096); + __nosave_end = .; - . = ALIGN(256); - .data.read_mostly : { *(.data.read_mostly) } - _edata = .; /* End of data section */ + . = ALIGN(4096); + .data.page_aligned : { + *(.data.idt) + } - . = ALIGN(8192); /* init_task */ - .data.init_task : { *(.data.init_task) } + . = ALIGN(256); + .data.cacheline_aligned : { + *(.data.cacheline_aligned) + } - /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ - __init_begin = .; - .init.text : { - _sinittext = .; - *(.init.text) - _einittext = .; - } - /* - * .exit.text is discarded at runtime, not link time, - * to deal with references from __bug_table - */ - .exit.text : { *(.exit.text) } + . = ALIGN(256); + .data.read_mostly : { + *(.data.read_mostly) + } + _edata = .; /* End of data section */ - .init.data : { *(.init.data) } - . = ALIGN(256); - __setup_start = .; - .init.setup : { *(.init.setup) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { - INITCALLS - } - __initcall_end = .; - __con_initcall_start = .; - .con_initcall.init : { *(.con_initcall.init) } - __con_initcall_end = .; - SECURITY_INIT + . = ALIGN(8192); /* init_task */ + .data.init_task : { + *(.data.init_task) + } + + /* will be freed after init */ + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + /* + * .exit.text is discarded at runtime, not link time, + * to deal with references from __bug_table + */ + .exit.text : { + *(.exit.text) + } + + .init.data : { + *(.init.data) + } + . = ALIGN(256); + .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(256); - __initramfs_start = .; - .init.ramfs : { *(.init.initramfs) } - . = ALIGN(2); - __initramfs_end = .; + . = ALIGN(256); + .init.ramfs : { + __initramfs_start = .; + *(.init.ramfs) + . = ALIGN(2); + __initramfs_end = .; + } #endif - PERCPU(4096) - . = ALIGN(4096); - __init_end = .; - /* freed after init ends here */ - __bss_start = .; /* BSS */ - .bss : { *(.bss) } - . = ALIGN(2); - __bss_stop = .; + PERCPU(4096) + . = ALIGN(4096); + __init_end = .; /* freed after init ends here */ - _end = . ; - - /* Sections to be discarded */ - /DISCARD/ : { - *(.exit.data) *(.exitcall.exit) + /* BSS */ + .bss : { + __bss_start = .; + *(.bss) + . = ALIGN(2); + __bss_stop = .; } - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.data) + *(.exitcall.exit) + } + + /* Debugging sections. */ + STABS_DEBUG + DWARF_DEBUG } From 52480ee5206a3fe3a61b5529ce063202c60b8b27 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Fri, 12 Oct 2007 16:11:50 +0200 Subject: [PATCH 2357/2804] [S390] s390: use PAGE_SIZE in vmlinux.lds Replace the hardcoded 4096 value with the PAGE_SIZE macro. Converted a few decimal numbers to readable hex numbers. Use of PAGE_SIZE required a small change to page.h to allow PAGE_SIZE to be used from assembler/linker scripts. Signed-off-by: Sam Ravnborg Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/vmlinux.lds.S | 27 ++++++++++++++------------- include/asm-s390/page.h | 3 ++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index f6b16aec32e7..849120e3e28a 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -2,6 +2,7 @@ * Written by Martin Schwidefsky (schwidefsky@de.ibm.com) */ +#include #include #ifndef CONFIG_64BIT @@ -35,10 +36,10 @@ SECTIONS RODATA #ifdef CONFIG_SHARED_KERNEL - . = ALIGN(1048576); /* VM shared segments are 1MB aligned */ + . = ALIGN(0x100000); /* VM shared segments are 1MB aligned */ #endif - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); _eshared = .; /* End of shareable data */ . = ALIGN(16); /* Exception table */ @@ -56,37 +57,37 @@ SECTIONS CONSTRUCTORS } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); .data_nosave : { __nosave_begin = .; *(.data.nosave) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); __nosave_end = .; - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); .data.page_aligned : { *(.data.idt) } - . = ALIGN(256); + . = ALIGN(0x100); .data.cacheline_aligned : { *(.data.cacheline_aligned) } - . = ALIGN(256); + . = ALIGN(0x100); .data.read_mostly : { *(.data.read_mostly) } _edata = .; /* End of data section */ - . = ALIGN(8192); /* init_task */ + . = ALIGN(2 * PAGE_SIZE); /* init_task */ .data.init_task : { *(.data.init_task) } /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ + . = ALIGN(PAGE_SIZE); /* Init code and data */ __init_begin = .; .init.text : { _sinittext = .; @@ -104,7 +105,7 @@ SECTIONS .init.data : { *(.init.data) } - . = ALIGN(256); + . = ALIGN(0x100); .init.setup : { __setup_start = .; *(.init.setup) @@ -124,7 +125,7 @@ SECTIONS SECURITY_INIT #ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(256); + . = ALIGN(0x100); .init.ramfs : { __initramfs_start = .; *(.init.ramfs) @@ -133,8 +134,8 @@ SECTIONS } #endif - PERCPU(4096) - . = ALIGN(4096); + PERCPU(PAGE_SIZE) + . = ALIGN(PAGE_SIZE); __init_end = .; /* freed after init ends here */ /* BSS */ diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index f326451ed6ec..ceec3826a67c 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -9,11 +9,12 @@ #ifndef _S390_PAGE_H #define _S390_PAGE_H +#include #include /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 -#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) #define PAGE_DEFAULT_ACC 0 #define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4) From c41fbc69654dd74339f76ea88054fe41e3c1b7a8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:51 +0200 Subject: [PATCH 2358/2804] [S390] pfault: Fix alignment of parameter list. Make sure parameter list of the pfault token function is eight byte aligned. Otherwise we can get specification exceptions. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 54055194e9af..4c1ac341ec80 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -468,7 +468,7 @@ typedef struct { __u64 refselmk; __u64 refcmpmk; __u64 reserved; -} __attribute__ ((packed)) pfault_refbk_t; +} __attribute__ ((packed, aligned(8))) pfault_refbk_t; int pfault_init(void) { From a2e53801971edbdaac4411760d893b8b65646987 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:52 +0200 Subject: [PATCH 2359/2804] [S390] 3215: Handle special console device. The early console device is special as it already has all needed data set and raw3215[0] allocated from con3215_init(). Therefore, it needs special treatment in the probe function so it can be matched with the 3215 driver which is already owning it. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/char/con3215.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 6000bdee4082..0e1f35c9ed9d 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -667,6 +667,9 @@ raw3215_probe (struct ccw_device *cdev) struct raw3215_info *raw; int line; + /* Console is special. */ + if (raw3215[0] && (cdev->dev.driver_data == raw3215[0])) + return 0; raw = kmalloc(sizeof(struct raw3215_info) + RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); if (raw == NULL) From 1462222b76a09a24b240563a51d5f9fbea8bd3e1 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 12 Oct 2007 16:11:53 +0200 Subject: [PATCH 2360/2804] [S390] xpram: fix bio_end{_,}io typo Signed-off-by: Martin Schwidefsky --- drivers/s390/block/xpram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 0fbacc8b1063..f231bc21b1ca 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -230,7 +230,7 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } } set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_end_io(bio, 0); + bio_endio(bio, 0); return 0; fail: bio_io_error(bio); From bfab36e81611e60573b84eb4e4b4c8d8545b2320 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Fri, 12 Oct 2007 09:37:15 +0100 Subject: [PATCH 2361/2804] NTFS: Fix a mount time deadlock. Big thanks go to Mathias Kolehmainen for reporting the bug, providing debug output and testing the patches I sent him to get it working. The fix was to stop calling ntfs_attr_set() at mount time as that causes balance_dirty_pages_ratelimited() to be called which on systems with little memory actually tries to go and balance the dirty pages which tries to take the s_umount semaphore but because we are still in fill_super() across which the VFS holds s_umount for writing this results in a deadlock. We now do the dirty work by hand by submitting individual buffers. This has the annoying "feature" that mounting can take a few seconds if the journal is large as we have clear it all. One day someone should improve on this by deferring the journal clearing to a helper kernel thread so it can be done in the background but I don't have time for this at the moment and the current solution works fine so I am leaving it like this for now. Signed-off-by: Anton Altaparmakov Signed-off-by: Linus Torvalds --- Documentation/filesystems/ntfs.txt | 4 +- fs/ntfs/ChangeLog | 12 +++ fs/ntfs/Makefile | 2 +- fs/ntfs/aops.c | 22 ++--- fs/ntfs/attrib.c | 8 +- fs/ntfs/file.c | 36 ++++---- fs/ntfs/inode.c | 3 - fs/ntfs/logfile.c | 143 ++++++++++++++++++++++++++--- fs/ntfs/runlist.c | 4 +- 9 files changed, 181 insertions(+), 53 deletions(-) diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt index 8ee10ec88293..e79ee2db183a 100644 --- a/Documentation/filesystems/ntfs.txt +++ b/Documentation/filesystems/ntfs.txt @@ -407,7 +407,7 @@ raiddev /dev/md0 device /dev/hda5 raid-disk 0 device /dev/hdb1 - raid-disl 1 + raid-disk 1 For linear raid, just change the raid-level above to "raid-level linear", for mirrors, change it to "raid-level 1", and for stripe sets with parity, change @@ -457,6 +457,8 @@ ChangeLog Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.1.29: + - Fix a deadlock when mounting read-write. 2.1.28: - Fix a deadlock. 2.1.27: diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index af4ef808fa94..345798ebd366 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -17,6 +17,18 @@ ToDo/Notes: happen is unclear however so it is worth waiting until someone hits the problem. +2.1.29 - Fix a deadlock at mount time. + + - During mount the VFS holds s_umount lock on the superblock. So when + we try to empty the journal $LogFile contents by calling + ntfs_attr_set() when the machine does not have much memory and the + journal is large ntfs_attr_set() results in the VM trying to balance + dirty pages which in turn tries to that the s_umount lock and thus we + get a deadlock. The solution is to not use ntfs_attr_set() and + instead do the zeroing by hand at the block level rather than page + cache level. + - Fix sparse warnings. + 2.1.28 - Fix a deadlock. - Fix deadlock in fs/ntfs/inode.c::ntfs_put_inode(). Thanks to Sergey diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index 825508385565..58b6be992544 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile @@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.28\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.29\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 6e5c2534f4bc..cfdc7900d271 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -2,7 +2,7 @@ * aops.c - NTFS kernel address space operations and page cache handling. * Part of the Linux-NTFS project. * - * Copyright (c) 2001-2006 Anton Altaparmakov + * Copyright (c) 2001-2007 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -396,7 +396,7 @@ static int ntfs_readpage(struct file *file, struct page *page) loff_t i_size; struct inode *vi; ntfs_inode *ni, *base_ni; - u8 *kaddr; + u8 *addr; ntfs_attr_search_ctx *ctx; MFT_RECORD *mrec; unsigned long flags; @@ -491,15 +491,15 @@ retry_readpage: /* Race with shrinking truncate. */ attr_len = i_size; } - kaddr = kmap_atomic(page, KM_USER0); + addr = kmap_atomic(page, KM_USER0); /* Copy the data to the page. */ - memcpy(kaddr, (u8*)ctx->attr + + memcpy(addr, (u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset), attr_len); /* Zero the remainder of the page. */ - memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); + memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(addr, KM_USER0); put_unm_err_out: ntfs_attr_put_search_ctx(ctx); unm_err_out: @@ -1344,7 +1344,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) loff_t i_size; struct inode *vi = page->mapping->host; ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi); - char *kaddr; + char *addr; ntfs_attr_search_ctx *ctx = NULL; MFT_RECORD *m = NULL; u32 attr_len; @@ -1484,14 +1484,14 @@ retry_writepage: /* Shrinking cannot fail. */ BUG_ON(err); } - kaddr = kmap_atomic(page, KM_USER0); + addr = kmap_atomic(page, KM_USER0); /* Copy the data from the page to the mft record. */ memcpy((u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset), - kaddr, attr_len); + addr, attr_len); /* Zero out of bounds area in the page cache page. */ - memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); - kunmap_atomic(kaddr, KM_USER0); + memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); + kunmap_atomic(addr, KM_USER0); flush_dcache_page(page); flush_dcache_mft_record_page(ctx->ntfs_ino); /* We are done with the page. */ diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 1c08fefe487a..92dabdcf2b80 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1,7 +1,7 @@ /** * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2006 Anton Altaparmakov + * Copyright (c) 2001-2007 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -2500,7 +2500,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) struct page *page; u8 *kaddr; pgoff_t idx, end; - unsigned int start_ofs, end_ofs, size; + unsigned start_ofs, end_ofs, size; ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.", (long long)ofs, (long long)cnt, val); @@ -2548,6 +2548,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) kunmap_atomic(kaddr, KM_USER0); set_page_dirty(page); page_cache_release(page); + balance_dirty_pages_ratelimited(mapping); + cond_resched(); if (idx == end) goto done; idx++; @@ -2604,6 +2606,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) kunmap_atomic(kaddr, KM_USER0); set_page_dirty(page); page_cache_release(page); + balance_dirty_pages_ratelimited(mapping); + cond_resched(); } done: ntfs_debug("Done."); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index ffcc504a1667..c814204d4ea0 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -1,7 +1,7 @@ /* * file.c - NTFS kernel file operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2006 Anton Altaparmakov + * Copyright (c) 2001-2007 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -362,7 +361,7 @@ static inline void ntfs_fault_in_pages_readable(const char __user *uaddr, volatile char c; /* Set @end to the first byte outside the last page we care about. */ - end = (const char __user*)PAGE_ALIGN((ptrdiff_t __user)uaddr + bytes); + end = (const char __user*)PAGE_ALIGN((unsigned long)uaddr + bytes); while (!__get_user(c, uaddr) && (uaddr += PAGE_SIZE, uaddr < end)) ; @@ -532,7 +531,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, blocksize_bits = vol->sb->s_blocksize_bits; u = 0; do { - struct page *page = pages[u]; + page = pages[u]; + BUG_ON(!page); /* * create_empty_buffers() will create uptodate/dirty buffers if * the page is uptodate/dirty. @@ -1291,7 +1291,7 @@ static inline size_t ntfs_copy_from_user(struct page **pages, size_t bytes) { struct page **last_page = pages + nr_pages; - char *kaddr; + char *addr; size_t total = 0; unsigned len; int left; @@ -1300,13 +1300,13 @@ static inline size_t ntfs_copy_from_user(struct page **pages, len = PAGE_CACHE_SIZE - ofs; if (len > bytes) len = bytes; - kaddr = kmap_atomic(*pages, KM_USER0); - left = __copy_from_user_inatomic(kaddr + ofs, buf, len); - kunmap_atomic(kaddr, KM_USER0); + addr = kmap_atomic(*pages, KM_USER0); + left = __copy_from_user_inatomic(addr + ofs, buf, len); + kunmap_atomic(addr, KM_USER0); if (unlikely(left)) { /* Do it the slow way. */ - kaddr = kmap(*pages); - left = __copy_from_user(kaddr + ofs, buf, len); + addr = kmap(*pages); + left = __copy_from_user(addr + ofs, buf, len); kunmap(*pages); if (unlikely(left)) goto err_out; @@ -1408,26 +1408,26 @@ static inline size_t ntfs_copy_from_user_iovec(struct page **pages, size_t *iov_ofs, size_t bytes) { struct page **last_page = pages + nr_pages; - char *kaddr; + char *addr; size_t copied, len, total = 0; do { len = PAGE_CACHE_SIZE - ofs; if (len > bytes) len = bytes; - kaddr = kmap_atomic(*pages, KM_USER0); - copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs, + addr = kmap_atomic(*pages, KM_USER0); + copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs, *iov, *iov_ofs, len); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(addr, KM_USER0); if (unlikely(copied != len)) { /* Do it the slow way. */ - kaddr = kmap(*pages); - copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs, + addr = kmap(*pages); + copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs, *iov, *iov_ofs, len); /* * Zero the rest of the target like __copy_from_user(). */ - memset(kaddr + ofs + copied, 0, len - copied); + memset(addr + ofs + copied, 0, len - copied); kunmap(*pages); if (unlikely(copied != len)) goto err_out; @@ -1735,8 +1735,6 @@ static int ntfs_commit_pages_after_write(struct page **pages, read_unlock_irqrestore(&ni->size_lock, flags); BUG_ON(initialized_size != i_size); if (end > initialized_size) { - unsigned long flags; - write_lock_irqsave(&ni->size_lock, flags); ni->initialized_size = end; i_size_write(vi, end); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index b532a730cec2..e9da092e2772 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -34,7 +34,6 @@ #include "dir.h" #include "debug.h" #include "inode.h" -#include "attrib.h" #include "lcnalloc.h" #include "malloc.h" #include "mft.h" @@ -2500,8 +2499,6 @@ retry_truncate: /* Resize the attribute record to best fit the new attribute size. */ if (new_size < vol->mft_record_size && !ntfs_resident_attr_value_resize(m, a, new_size)) { - unsigned long flags; - /* The resize succeeded! */ flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index acfed325f4ec..d7932e95b1fd 100644 --- a/fs/ntfs/logfile.c +++ b/fs/ntfs/logfile.c @@ -1,7 +1,7 @@ /* * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project. * - * Copyright (c) 2002-2005 Anton Altaparmakov + * Copyright (c) 2002-2007 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -724,24 +724,139 @@ bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp) */ bool ntfs_empty_logfile(struct inode *log_vi) { - ntfs_volume *vol = NTFS_SB(log_vi->i_sb); + VCN vcn, end_vcn; + ntfs_inode *log_ni = NTFS_I(log_vi); + ntfs_volume *vol = log_ni->vol; + struct super_block *sb = vol->sb; + runlist_element *rl; + unsigned long flags; + unsigned block_size, block_size_bits; + int err; + bool should_wait = true; ntfs_debug("Entering."); - if (!NVolLogFileEmpty(vol)) { - int err; - - err = ntfs_attr_set(NTFS_I(log_vi), 0, i_size_read(log_vi), - 0xff); - if (unlikely(err)) { - ntfs_error(vol->sb, "Failed to fill $LogFile with " - "0xff bytes (error code %i).", err); - return false; - } - /* Set the flag so we do not have to do it again on remount. */ - NVolSetLogFileEmpty(vol); + if (NVolLogFileEmpty(vol)) { + ntfs_debug("Done."); + return true; } + /* + * We cannot use ntfs_attr_set() because we may be still in the middle + * of a mount operation. Thus we do the emptying by hand by first + * zapping the page cache pages for the $LogFile/$DATA attribute and + * then emptying each of the buffers in each of the clusters specified + * by the runlist by hand. + */ + block_size = sb->s_blocksize; + block_size_bits = sb->s_blocksize_bits; + vcn = 0; + read_lock_irqsave(&log_ni->size_lock, flags); + end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >> + vol->cluster_size_bits; + read_unlock_irqrestore(&log_ni->size_lock, flags); + truncate_inode_pages(log_vi->i_mapping, 0); + down_write(&log_ni->runlist.lock); + rl = log_ni->runlist.rl; + if (unlikely(!rl || vcn < rl->vcn || !rl->length)) { +map_vcn: + err = ntfs_map_runlist_nolock(log_ni, vcn, NULL); + if (err) { + ntfs_error(sb, "Failed to map runlist fragment (error " + "%d).", -err); + goto err; + } + rl = log_ni->runlist.rl; + BUG_ON(!rl || vcn < rl->vcn || !rl->length); + } + /* Seek to the runlist element containing @vcn. */ + while (rl->length && vcn >= rl[1].vcn) + rl++; + do { + LCN lcn; + sector_t block, end_block; + s64 len; + + /* + * If this run is not mapped map it now and start again as the + * runlist will have been updated. + */ + lcn = rl->lcn; + if (unlikely(lcn == LCN_RL_NOT_MAPPED)) { + vcn = rl->vcn; + goto map_vcn; + } + /* If this run is not valid abort with an error. */ + if (unlikely(!rl->length || lcn < LCN_HOLE)) + goto rl_err; + /* Skip holes. */ + if (lcn == LCN_HOLE) + continue; + block = lcn << vol->cluster_size_bits >> block_size_bits; + len = rl->length; + if (rl[1].vcn > end_vcn) + len = end_vcn - rl->vcn; + end_block = (lcn + len) << vol->cluster_size_bits >> + block_size_bits; + /* Iterate over the blocks in the run and empty them. */ + do { + struct buffer_head *bh; + + /* Obtain the buffer, possibly not uptodate. */ + bh = sb_getblk(sb, block); + BUG_ON(!bh); + /* Setup buffer i/o submission. */ + lock_buffer(bh); + bh->b_end_io = end_buffer_write_sync; + get_bh(bh); + /* Set the entire contents of the buffer to 0xff. */ + memset(bh->b_data, -1, block_size); + if (!buffer_uptodate(bh)) + set_buffer_uptodate(bh); + if (buffer_dirty(bh)) + clear_buffer_dirty(bh); + /* + * Submit the buffer and wait for i/o to complete but + * only for the first buffer so we do not miss really + * serious i/o errors. Once the first buffer has + * completed ignore errors afterwards as we can assume + * that if one buffer worked all of them will work. + */ + submit_bh(WRITE, bh); + if (should_wait) { + should_wait = false; + wait_on_buffer(bh); + if (unlikely(!buffer_uptodate(bh))) + goto io_err; + } + brelse(bh); + } while (++block < end_block); + } while ((++rl)->vcn < end_vcn); + up_write(&log_ni->runlist.lock); + /* + * Zap the pages again just in case any got instantiated whilst we were + * emptying the blocks by hand. FIXME: We may not have completed + * writing to all the buffer heads yet so this may happen too early. + * We really should use a kernel thread to do the emptying + * asynchronously and then we can also set the volume dirty and output + * an error message if emptying should fail. + */ + truncate_inode_pages(log_vi->i_mapping, 0); + /* Set the flag so we do not have to do it again on remount. */ + NVolSetLogFileEmpty(vol); ntfs_debug("Done."); return true; +io_err: + ntfs_error(sb, "Failed to write buffer. Unmount and run chkdsk."); + goto dirty_err; +rl_err: + ntfs_error(sb, "Runlist is corrupt. Unmount and run chkdsk."); +dirty_err: + NVolSetErrors(vol); + err = -EIO; +err: + up_write(&log_ni->runlist.lock); + ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).", + -err); + return false; } #endif /* NTFS_RW */ diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index 9afd72c7ad0d..56a9a6d25a2a 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c @@ -1,7 +1,7 @@ /** * runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2007 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -1714,7 +1714,7 @@ extend_hole: sizeof(*rl)); /* Adjust the beginning of the tail if necessary. */ if (end > rl->vcn) { - s64 delta = end - rl->vcn; + delta = end - rl->vcn; rl->vcn = end; rl->length -= delta; /* Only adjust the lcn if it is real. */ From c77534f6fb6d58e27d923b6825ea3b0ef485ab26 Mon Sep 17 00:00:00 2001 From: Tao Mao Date: Tue, 28 Aug 2007 17:22:33 -0700 Subject: [PATCH 2362/2804] ocfs2: remove mostly unused field from insert structure ocfs2_insert_type->ins_free_records was only used in one place, and was set incorrectly in most places. We can free up some memory and lose some code by removing this. * Small warning fixup contributed by Andrew Mortom Signed-off-by: Tao Mao Signed-off-by: Mark Fasheh --- fs/ocfs2/alloc.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 778a850b4634..33d5cab5e690 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -354,7 +354,6 @@ struct ocfs2_insert_type { enum ocfs2_append_type ins_appending; enum ocfs2_contig_type ins_contig; int ins_contig_index; - int ins_free_records; int ins_tree_depth; }; @@ -3593,6 +3592,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, struct buffer_head *di_bh, struct buffer_head **last_eb_bh, struct ocfs2_extent_rec *insert_rec, + int *free_records, struct ocfs2_insert_type *insert) { int ret; @@ -3633,7 +3633,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, * XXX: This test is simplistic, we can search for empty * extent records too. */ - insert->ins_free_records = le16_to_cpu(el->l_count) - + *free_records = le16_to_cpu(el->l_count) - le16_to_cpu(el->l_next_free_rec); if (!insert->ins_tree_depth) { @@ -3730,6 +3730,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, struct ocfs2_alloc_context *meta_ac) { int status; + int uninitialized_var(free_records); struct buffer_head *last_eb_bh = NULL; struct ocfs2_insert_type insert = {0, }; struct ocfs2_extent_rec rec; @@ -3752,7 +3753,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, rec.e_flags = flags; status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec, - &insert); + &free_records, &insert); if (status < 0) { mlog_errno(status); goto bail; @@ -3762,9 +3763,9 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, "Insert.contig_index: %d, Insert.free_records: %d, " "Insert.tree_depth: %d\n", insert.ins_appending, insert.ins_contig, insert.ins_contig_index, - insert.ins_free_records, insert.ins_tree_depth); + free_records, insert.ins_tree_depth); - if (insert.ins_contig == CONTIG_NONE && insert.ins_free_records == 0) { + if (insert.ins_contig == CONTIG_NONE && free_records == 0) { status = ocfs2_grow_tree(inode, handle, fe_bh, &insert.ins_tree_depth, &last_eb_bh, meta_ac); @@ -3847,26 +3848,17 @@ leftright: if (le16_to_cpu(rightmost_el->l_next_free_rec) == le16_to_cpu(rightmost_el->l_count)) { - int old_depth = depth; - ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh, meta_ac); if (ret) { mlog_errno(ret); goto out; } - - if (old_depth != depth) { - eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; - rightmost_el = &eb->h_list; - } } memset(&insert, 0, sizeof(struct ocfs2_insert_type)); insert.ins_appending = APPEND_NONE; insert.ins_contig = CONTIG_NONE; - insert.ins_free_records = le16_to_cpu(rightmost_el->l_count) - - le16_to_cpu(rightmost_el->l_next_free_rec); insert.ins_tree_depth = depth; insert_range = le32_to_cpu(split_rec.e_cpos) + @@ -4180,27 +4172,18 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh, if (le16_to_cpu(rightmost_el->l_next_free_rec) == le16_to_cpu(rightmost_el->l_count)) { - int old_depth = depth; - ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh, meta_ac); if (ret) { mlog_errno(ret); goto out; } - - if (old_depth != depth) { - eb = (struct ocfs2_extent_block *)last_eb_bh->b_data; - rightmost_el = &eb->h_list; - } } memset(&insert, 0, sizeof(struct ocfs2_insert_type)); insert.ins_appending = APPEND_NONE; insert.ins_contig = CONTIG_NONE; insert.ins_split = SPLIT_RIGHT; - insert.ins_free_records = le16_to_cpu(rightmost_el->l_count) - - le16_to_cpu(rightmost_el->l_next_free_rec); insert.ins_tree_depth = depth; ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert); From 518d7269f3c9129ae51d5f804edff998ab945a40 Mon Sep 17 00:00:00 2001 From: Tao Mao Date: Tue, 28 Aug 2007 17:25:35 -0700 Subject: [PATCH 2363/2804] ocfs2: remove unused variable delete_tail_recs in ocfs2_try_to_merge_extent() was only ever set, remove it. Signed-off-by: Tao Mao Signed-off-by: Mark Fasheh --- fs/ocfs2/alloc.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 33d5cab5e690..c078b3b1f01e 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -2807,36 +2807,28 @@ static int ocfs2_try_to_merge_extent(struct inode *inode, struct ocfs2_merge_ctxt *ctxt) { - int ret = 0, delete_tail_recs = 0; + int ret = 0; struct ocfs2_extent_list *el = path_leaf_el(left_path); struct ocfs2_extent_rec *rec = &el->l_recs[split_index]; BUG_ON(ctxt->c_contig_type == CONTIG_NONE); - if (ctxt->c_split_covers_rec) { - delete_tail_recs++; - - if (ctxt->c_contig_type == CONTIG_LEFTRIGHT || - ctxt->c_has_empty_extent) - delete_tail_recs++; - - if (ctxt->c_has_empty_extent) { - /* - * The merge code will need to create an empty - * extent to take the place of the newly - * emptied slot. Remove any pre-existing empty - * extents - having more than one in a leaf is - * illegal. - */ - ret = ocfs2_rotate_tree_left(inode, handle, left_path, - dealloc); - if (ret) { - mlog_errno(ret); - goto out; - } - split_index--; - rec = &el->l_recs[split_index]; + if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) { + /* + * The merge code will need to create an empty + * extent to take the place of the newly + * emptied slot. Remove any pre-existing empty + * extents - having more than one in a leaf is + * illegal. + */ + ret = ocfs2_rotate_tree_left(inode, handle, left_path, + dealloc); + if (ret) { + mlog_errno(ret); + goto out; } + split_index--; + rec = &el->l_recs[split_index]; } if (ctxt->c_contig_type == CONTIG_LEFTRIGHT) { From 015452b15ff6c2d9fa1f82f28d61e7a66e2df86a Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Wed, 12 Sep 2007 10:21:22 -0700 Subject: [PATCH 2364/2804] ocfs2: Remove unused structure field c_used_tail_recs in struct ocfs2_merge_ctxt is only ever set, so we can remove it. Signed-off-by: Mark Fasheh --- fs/ocfs2/alloc.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index c078b3b1f01e..c91706f949ff 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -361,7 +361,6 @@ struct ocfs2_merge_ctxt { enum ocfs2_contig_type c_contig_type; int c_has_empty_extent; int c_split_covers_rec; - int c_used_tail_recs; }; /* @@ -3999,11 +3998,6 @@ static int __ocfs2_mark_extent_written(struct inode *inode, } else rightmost_el = path_root_el(path); - ctxt.c_used_tail_recs = le16_to_cpu(rightmost_el->l_next_free_rec); - if (ctxt.c_used_tail_recs > 0 && - ocfs2_is_empty_extent(&rightmost_el->l_recs[0])) - ctxt.c_used_tail_recs--; - if (rec->e_cpos == split_rec->e_cpos && rec->e_leaf_clusters == split_rec->e_leaf_clusters) ctxt.c_split_covers_rec = 1; @@ -4012,10 +4006,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode, ctxt.c_has_empty_extent = ocfs2_is_empty_extent(&el->l_recs[0]); - mlog(0, "index: %d, contig: %u, used_tail_recs: %u, " - "has_empty: %u, split_covers: %u\n", split_index, - ctxt.c_contig_type, ctxt.c_used_tail_recs, - ctxt.c_has_empty_extent, ctxt.c_split_covers_rec); + mlog(0, "index: %d, contig: %u, has_empty: %u, split_covers: %u\n", + split_index, ctxt.c_contig_type, ctxt.c_has_empty_extent, + ctxt.c_split_covers_rec); if (ctxt.c_contig_type == CONTIG_NONE) { if (ctxt.c_split_covers_rec) From 19b613d41051296be628581e7e21b847e9eaba80 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 4 Oct 2007 14:47:09 -0700 Subject: [PATCH 2365/2804] ocfs2: Clear slot map when umounting a local volume This is technically harmless (recovery will clean it out later), but leaves a bogus entry in the slot_map which really shouldn't be there. Signed-off-by: Mark Fasheh --- fs/ocfs2/super.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index c034b5129c1e..19436d1ff57f 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1209,13 +1209,14 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) tmp = ocfs2_request_umount_vote(osb); if (tmp < 0) mlog_errno(tmp); - - if (osb->slot_num != OCFS2_INVALID_SLOT) - ocfs2_put_slot(osb); - - ocfs2_super_unlock(osb, 1); } + if (osb->slot_num != OCFS2_INVALID_SLOT) + ocfs2_put_slot(osb); + + if (osb->dlm) + ocfs2_super_unlock(osb, 1); + ocfs2_release_system_inodes(osb); if (osb->dlm) { From d550071c03f129a60dfad60d23dab73f894129a9 Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Thu, 6 Sep 2007 13:34:16 -0700 Subject: [PATCH 2366/2804] ocfs2: Implement show_options() Implement sops->show_options() so as to allow /proc/mounts to show the mount options. Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh --- fs/ocfs2/super.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 19436d1ff57f..e5ac0714dab2 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -91,6 +92,7 @@ struct mount_options static int ocfs2_parse_options(struct super_block *sb, char *options, struct mount_options *mopt, int is_remount); +static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt); static void ocfs2_put_super(struct super_block *sb); static int ocfs2_mount_volume(struct super_block *sb); static int ocfs2_remount(struct super_block *sb, int *flags, char *data); @@ -133,6 +135,7 @@ static const struct super_operations ocfs2_sops = { .write_super = ocfs2_write_super, .put_super = ocfs2_put_super, .remount_fs = ocfs2_remount, + .show_options = ocfs2_show_options, }; enum { @@ -830,6 +833,41 @@ bail: return status; } +static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) +{ + struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb); + unsigned long opts = osb->s_mount_opt; + + if (opts & OCFS2_MOUNT_HB_LOCAL) + seq_printf(s, ",_netdev,heartbeat=local"); + else + seq_printf(s, ",heartbeat=none"); + + if (opts & OCFS2_MOUNT_NOINTR) + seq_printf(s, ",nointr"); + + if (opts & OCFS2_MOUNT_DATA_WRITEBACK) + seq_printf(s, ",data=writeback"); + else + seq_printf(s, ",data=ordered"); + + if (opts & OCFS2_MOUNT_BARRIER) + seq_printf(s, ",barrier=1"); + + if (opts & OCFS2_MOUNT_ERRORS_PANIC) + seq_printf(s, ",errors=panic"); + else + seq_printf(s, ",errors=remount-ro"); + + if (osb->preferred_slot != OCFS2_INVALID_SLOT) + seq_printf(s, ",preferred_slot=%d", osb->preferred_slot); + + if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM) + seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum); + + return 0; +} + static int __init ocfs2_init(void) { int status; From bddb8eb37f1460fc19e1af16010c9ad4ca3717a6 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Thu, 27 Sep 2007 02:10:04 +0800 Subject: [PATCH 2367/2804] [PATCH] fs/ocfs2/: removed unneeded initial value and function's return value Signed-off-by: Denis Cheng Signed-off-by: Mark Fasheh --- fs/ocfs2/super.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index e5ac0714dab2..0e2a1b45bf92 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -107,7 +107,7 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait); static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb); static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb); -static int ocfs2_release_system_inodes(struct ocfs2_super *osb); +static void ocfs2_release_system_inodes(struct ocfs2_super *osb); static int ocfs2_fill_local_node_info(struct ocfs2_super *osb); static int ocfs2_check_volume(struct ocfs2_super *osb); static int ocfs2_verify_volume(struct ocfs2_dinode *di, @@ -180,7 +180,7 @@ static void ocfs2_write_super(struct super_block *sb) static int ocfs2_sync_fs(struct super_block *sb, int wait) { - int status = 0; + int status; tid_t target; struct ocfs2_super *osb = OCFS2_SB(sb); @@ -278,9 +278,9 @@ bail: return status; } -static int ocfs2_release_system_inodes(struct ocfs2_super *osb) +static void ocfs2_release_system_inodes(struct ocfs2_super *osb) { - int status = 0, i; + int i; struct inode *inode; mlog_entry_void(); @@ -305,8 +305,7 @@ static int ocfs2_release_system_inodes(struct ocfs2_super *osb) osb->root_inode = NULL; } - mlog_exit(status); - return status; + mlog_exit(0); } /* We're allocating fs objects, use GFP_NOFS */ @@ -456,7 +455,7 @@ static int ocfs2_sb_probe(struct super_block *sb, struct buffer_head **bh, int *sector_size) { - int status = 0, tmpstat; + int status, tmpstat; struct ocfs1_vol_disk_hdr *hdr; struct ocfs2_dinode *di; int blksize; @@ -1314,7 +1313,7 @@ static int ocfs2_initialize_super(struct super_block *sb, struct buffer_head *bh, int sector_size) { - int status = 0; + int status; int i, cbits, bbits; struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; struct inode *inode = NULL; @@ -1635,7 +1634,7 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di, static int ocfs2_check_volume(struct ocfs2_super *osb) { - int status = 0; + int status; int dirty; int local; struct ocfs2_dinode *local_alloc = NULL; /* only used if we From 92e91ce2a30b2af53ebf077512801dc01e75cca5 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 20 Sep 2007 11:19:20 -0700 Subject: [PATCH 2368/2804] ocfs2: Sync ocfs2_fs.h with ocfs2-tools ocfs2-tools added some on-disk fields and flags which are used by tunefs.ocfs2. Signed-off-by: Mark Fasheh --- fs/ocfs2/ocfs2_fs.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index 82f8a75b207e..bf10a5453833 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -110,6 +110,17 @@ /* Support for sparse allocation in b-trees */ #define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC 0x0010 +/* + * Tunefs sets this incompat flag before starting an operation which + * would require cleanup on abort. This is done to protect users from + * inadvertently mounting the fs after an aborted run without + * fsck-ing. + * + * s_tunefs_flags on the super block describes precisely which + * operations were in progress. + */ +#define OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG 0x0020 + /* * backup superblock flag is used to indicate that this volume * has backup superblocks. @@ -129,6 +140,11 @@ /* the max backup superblock nums */ #define OCFS2_MAX_BACKUP_SUPERBLOCKS 6 +/* + * Flags on ocfs2_super_block.s_tunefs_flags + */ +#define OCFS2_TUNEFS_INPROG_REMOVE_SLOT 0x0001 /* Removing slots */ + /* * Flags on ocfs2_dinode.i_flags */ @@ -447,8 +463,8 @@ struct ocfs2_super_block { __le32 s_clustersize_bits; /* Clustersize for this fs */ /*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts before tunefs required */ - __le16 s_reserved1; - __le32 s_reserved2; + __le16 s_tunefs_flag; + __le32 s_reserved1; __le64 s_first_cluster_group; /* Block offset of 1st cluster * group header */ /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ From 65ed39d6ca78f07d2958814e08440e4264b6b488 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 28 Aug 2007 17:13:23 -0700 Subject: [PATCH 2369/2804] ocfs2: move nonsparse hole-filling into ocfs2_write_begin() By doing this, we can remove any higher level logic which has to have knowledge of btree functionality - any callers of ocfs2_write_begin() can now expect it to do anything necessary to prepare the inode for new data. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/aops.c | 40 ++++++++- fs/ocfs2/file.c | 219 +++++++++++++++++------------------------------- fs/ocfs2/file.h | 2 + 3 files changed, 116 insertions(+), 145 deletions(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index f37f25c931f5..fae07672eb18 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -301,12 +301,8 @@ int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page, { int ret; - down_read(&OCFS2_I(inode)->ip_alloc_sem); - ret = block_prepare_write(page, from, to, ocfs2_get_block); - up_read(&OCFS2_I(inode)->ip_alloc_sem); - return ret; } @@ -1360,6 +1356,36 @@ out: return ret; } +/* + * This function only does anything for file systems which can't + * handle sparse files. + * + * What we want to do here is fill in any hole between the current end + * of allocation and the end of our write. That way the rest of the + * write path can treat it as an non-allocating write, which has no + * special case code for sparse/nonsparse files. + */ +static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos, + unsigned len, + struct ocfs2_write_ctxt *wc) +{ + int ret; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + loff_t newsize = pos + len; + + if (ocfs2_sparse_alloc(osb)) + return 0; + + if (newsize <= i_size_read(inode)) + return 0; + + ret = ocfs2_extend_no_holes(inode, newsize, newsize - len); + if (ret) + mlog_errno(ret); + + return ret; +} + int ocfs2_write_begin_nolock(struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata, @@ -1381,6 +1407,12 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, return ret; } + ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc); + if (ret) { + mlog_errno(ret); + goto out; + } + ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc, &extents_to_split); if (ret) { diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index f3bc3658e7a5..781ba6c4ef85 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -779,25 +779,6 @@ leave: return status; } -static int ocfs2_extend_allocation(struct inode *inode, u32 logical_start, - u32 clusters_to_add, int mark_unwritten) -{ - int ret; - - /* - * The alloc sem blocks peope in read/write from reading our - * allocation until we're done changing it. We depend on - * i_mutex to block other extend/truncate calls while we're - * here. - */ - down_write(&OCFS2_I(inode)->ip_alloc_sem); - ret = __ocfs2_extend_allocation(inode, logical_start, clusters_to_add, - mark_unwritten); - up_write(&OCFS2_I(inode)->ip_alloc_sem); - - return ret; -} - /* Some parts of this taken from generic_cont_expand, which turned out * to be too fragile to do exactly what we need without us having to * worry about recursive locking in ->prepare_write() and @@ -889,25 +870,47 @@ out: return ret; } -/* - * A tail_to_skip value > 0 indicates that we're being called from - * ocfs2_file_aio_write(). This has the following implications: - * - * - we don't want to update i_size - * - di_bh will be NULL, which is fine because it's only used in the - * case where we want to update i_size. - * - ocfs2_zero_extend() will then only be filling the hole created - * between i_size and the start of the write. - */ +int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, u64 zero_to) +{ + int ret; + u32 clusters_to_add; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + + clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size); + if (clusters_to_add < oi->ip_clusters) + clusters_to_add = 0; + else + clusters_to_add -= oi->ip_clusters; + + if (clusters_to_add) { + ret = __ocfs2_extend_allocation(inode, oi->ip_clusters, + clusters_to_add, 0); + if (ret) { + mlog_errno(ret); + goto out; + } + } + + /* + * Call this even if we don't add any clusters to the tree. We + * still need to zero the area between the old i_size and the + * new i_size. + */ + ret = ocfs2_zero_extend(inode, zero_to); + if (ret < 0) + mlog_errno(ret); + +out: + return ret; +} + static int ocfs2_extend_file(struct inode *inode, struct buffer_head *di_bh, - u64 new_i_size, - size_t tail_to_skip) + u64 new_i_size) { int ret = 0; - u32 clusters_to_add = 0; - BUG_ON(!tail_to_skip && !di_bh); + BUG_ON(!di_bh); /* setattr sometimes calls us like this. */ if (new_i_size == 0) @@ -917,13 +920,8 @@ static int ocfs2_extend_file(struct inode *inode, goto out; BUG_ON(new_i_size < i_size_read(inode)); - if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { - BUG_ON(tail_to_skip != 0); + if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) goto out_update_size; - } - - clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) - - OCFS2_I(inode)->ip_clusters; /* * protect the pages that ocfs2_zero_extend is going to be @@ -938,35 +936,25 @@ static int ocfs2_extend_file(struct inode *inode, goto out; } - if (clusters_to_add) { - ret = ocfs2_extend_allocation(inode, - OCFS2_I(inode)->ip_clusters, - clusters_to_add, 0); - if (ret < 0) { - mlog_errno(ret); - goto out_unlock; - } - } - /* - * Call this even if we don't add any clusters to the tree. We - * still need to zero the area between the old i_size and the - * new i_size. + * The alloc sem blocks people in read/write from reading our + * allocation until we're done changing it. We depend on + * i_mutex to block other extend/truncate calls while we're + * here. */ - ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip); + down_write(&OCFS2_I(inode)->ip_alloc_sem); + ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size); + up_write(&OCFS2_I(inode)->ip_alloc_sem); + if (ret < 0) { mlog_errno(ret); goto out_unlock; } out_update_size: - if (!tail_to_skip) { - /* We're being called from ocfs2_setattr() which wants - * us to update i_size */ - ret = ocfs2_simple_size_update(inode, di_bh, new_i_size); - if (ret < 0) - mlog_errno(ret); - } + ret = ocfs2_simple_size_update(inode, di_bh, new_i_size); + if (ret < 0) + mlog_errno(ret); out_unlock: if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) @@ -1035,7 +1023,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) if (i_size_read(inode) > attr->ia_size) status = ocfs2_truncate_file(inode, bh, attr->ia_size); else - status = ocfs2_extend_file(inode, bh, attr->ia_size, 0); + status = ocfs2_extend_file(inode, bh, attr->ia_size); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -1713,15 +1701,13 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, int appending, int *direct_io) { - int ret = 0, meta_level = appending; + int ret = 0, meta_level = 0; struct inode *inode = dentry->d_inode; - u32 clusters; - loff_t newsize, saved_pos; + loff_t saved_pos, end; /* - * We sample i_size under a read level meta lock to see if our write - * is extending the file, if it is we back off and get a write level - * meta lock. + * We start with a read level meta lock and only jump to an ex + * if we need to make modifications here. */ for(;;) { ret = ocfs2_meta_lock(inode, NULL, meta_level); @@ -1763,87 +1749,38 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, saved_pos = *ppos; } - if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { - loff_t end = saved_pos + count; + end = saved_pos + count; - /* - * Skip the O_DIRECT checks if we don't need - * them. - */ - if (!direct_io || !(*direct_io)) - break; + /* + * Skip the O_DIRECT checks if we don't need + * them. + */ + if (!direct_io || !(*direct_io)) + break; - /* - * Allowing concurrent direct writes means - * i_size changes wouldn't be synchronized, so - * one node could wind up truncating another - * nodes writes. - */ - if (end > i_size_read(inode)) { - *direct_io = 0; - break; - } - - /* - * We don't fill holes during direct io, so - * check for them here. If any are found, the - * caller will have to retake some cluster - * locks and initiate the io as buffered. - */ - ret = ocfs2_check_range_for_holes(inode, saved_pos, - count); - if (ret == 1) { - *direct_io = 0; - ret = 0; - } else if (ret < 0) - mlog_errno(ret); + /* + * Allowing concurrent direct writes means + * i_size changes wouldn't be synchronized, so + * one node could wind up truncating another + * nodes writes. + */ + if (end > i_size_read(inode)) { + *direct_io = 0; break; } /* - * The rest of this loop is concerned with legacy file - * systems which don't support sparse files. + * We don't fill holes during direct io, so + * check for them here. If any are found, the + * caller will have to retake some cluster + * locks and initiate the io as buffered. */ - - newsize = count + saved_pos; - - mlog(0, "pos=%lld newsize=%lld cursize=%lld\n", - (long long) saved_pos, (long long) newsize, - (long long) i_size_read(inode)); - - /* No need for a higher level metadata lock if we're - * never going past i_size. */ - if (newsize <= i_size_read(inode)) - break; - - if (meta_level == 0) { - ocfs2_meta_unlock(inode, meta_level); - meta_level = 1; - continue; - } - - spin_lock(&OCFS2_I(inode)->ip_lock); - clusters = ocfs2_clusters_for_bytes(inode->i_sb, newsize) - - OCFS2_I(inode)->ip_clusters; - spin_unlock(&OCFS2_I(inode)->ip_lock); - - mlog(0, "Writing at EOF, may need more allocation: " - "i_size = %lld, newsize = %lld, need %u clusters\n", - (long long) i_size_read(inode), (long long) newsize, - clusters); - - /* We only want to continue the rest of this loop if - * our extend will actually require more - * allocation. */ - if (!clusters) - break; - - ret = ocfs2_extend_file(inode, NULL, newsize, count); - if (ret < 0) { - if (ret != -ENOSPC) - mlog_errno(ret); - goto out_unlock; - } + ret = ocfs2_check_range_for_holes(inode, saved_pos, count); + if (ret == 1) { + *direct_io = 0; + ret = 0; + } else if (ret < 0) + mlog_errno(ret); break; } diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 36fe27f268ee..066f14add3a8 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h @@ -47,6 +47,8 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb, struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret); +int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, + u64 zero_to); int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di, u32 clusters_to_add, u32 extents_to_split, struct ocfs2_alloc_context **data_ac, From 1d410a6e337a0d2d5543ad1d9bccb670a7a05312 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 7 Sep 2007 14:20:45 -0700 Subject: [PATCH 2370/2804] ocfs2: Small refactor of truncate zeroing code We'll want to reuse most of this when pushing inline data back out to an extent. Keeping this part as a seperate patch helps to keep the upcoming changes for write support uncluttered. The core portion of ocfs2_zero_cluster_pages() responsible for making sure a page is mapped and properly dirtied is abstracted out into it's own function, ocfs2_map_and_dirty_page(). Actual functionality doesn't change, though zeroing becomes optional. We also turn part of ocfs2_free_write_ctxt() into a common function for unlocking and freeing a page array. This operation is very common (and uniform) for Ocfs2 cluster sizes greater than page size, so it makes sense to keep the code in one place. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/alloc.c | 151 ++++++++++++++++++++++------------------------- fs/ocfs2/aops.c | 20 ++++--- fs/ocfs2/aops.h | 2 + 3 files changed, 86 insertions(+), 87 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index c91706f949ff..c81bfdfb9929 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -5633,12 +5633,50 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh) return ocfs2_journal_dirty_data(handle, bh); } +static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle, + unsigned int from, unsigned int to, + struct page *page, int zero, u64 *phys) +{ + int ret, partial = 0; + + ret = ocfs2_map_page_blocks(page, phys, inode, from, to, 0); + if (ret) + mlog_errno(ret); + + if (zero) + zero_user_page(page, from, to - from, KM_USER0); + + /* + * Need to set the buffers we zero'd into uptodate + * here if they aren't - ocfs2_map_page_blocks() + * might've skipped some + */ + if (ocfs2_should_order_data(inode)) { + ret = walk_page_buffers(handle, + page_buffers(page), + from, to, &partial, + ocfs2_ordered_zero_func); + if (ret < 0) + mlog_errno(ret); + } else { + ret = walk_page_buffers(handle, page_buffers(page), + from, to, &partial, + ocfs2_writeback_zero_func); + if (ret < 0) + mlog_errno(ret); + } + + if (!partial) + SetPageUptodate(page); + + flush_dcache_page(page); +} + static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start, loff_t end, struct page **pages, int numpages, u64 phys, handle_t *handle) { - int i, ret, partial = 0; - void *kaddr; + int i; struct page *page; unsigned int from, to = PAGE_CACHE_SIZE; struct super_block *sb = inode->i_sb; @@ -5659,87 +5697,31 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start, BUG_ON(from > PAGE_CACHE_SIZE); BUG_ON(to > PAGE_CACHE_SIZE); - ret = ocfs2_map_page_blocks(page, &phys, inode, from, to, 0); - if (ret) - mlog_errno(ret); - - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + from, 0, to - from); - kunmap_atomic(kaddr, KM_USER0); - - /* - * Need to set the buffers we zero'd into uptodate - * here if they aren't - ocfs2_map_page_blocks() - * might've skipped some - */ - if (ocfs2_should_order_data(inode)) { - ret = walk_page_buffers(handle, - page_buffers(page), - from, to, &partial, - ocfs2_ordered_zero_func); - if (ret < 0) - mlog_errno(ret); - } else { - ret = walk_page_buffers(handle, page_buffers(page), - from, to, &partial, - ocfs2_writeback_zero_func); - if (ret < 0) - mlog_errno(ret); - } - - if (!partial) - SetPageUptodate(page); - - flush_dcache_page(page); + ocfs2_map_and_dirty_page(inode, handle, from, to, page, 1, + &phys); start = (page->index + 1) << PAGE_CACHE_SHIFT; } out: - if (pages) { - for (i = 0; i < numpages; i++) { - page = pages[i]; - unlock_page(page); - mark_page_accessed(page); - page_cache_release(page); - } - } + if (pages) + ocfs2_unlock_and_free_pages(pages, numpages); } static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end, - struct page **pages, int *num, u64 *phys) + struct page **pages, int *num) { - int i, numpages = 0, ret = 0; - unsigned int ext_flags; + int numpages, ret = 0; struct super_block *sb = inode->i_sb; struct address_space *mapping = inode->i_mapping; unsigned long index; loff_t last_page_bytes; - BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb))); BUG_ON(start > end); - if (start == end) - goto out; - BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits != (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits); - ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits, - phys, NULL, &ext_flags); - if (ret) { - mlog_errno(ret); - goto out; - } - - /* Tail is a hole. */ - if (*phys == 0) - goto out; - - /* Tail is marked as unwritten, we can count on write to zero - * in that case. */ - if (ext_flags & OCFS2_EXT_UNWRITTEN) - goto out; - + numpages = 0; last_page_bytes = PAGE_ALIGN(end); index = start >> PAGE_CACHE_SHIFT; do { @@ -5756,14 +5738,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end, out: if (ret != 0) { - if (pages) { - for (i = 0; i < numpages; i++) { - if (pages[i]) { - unlock_page(pages[i]); - page_cache_release(pages[i]); - } - } - } + if (pages) + ocfs2_unlock_and_free_pages(pages, numpages); numpages = 0; } @@ -5784,18 +5760,20 @@ out: int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, u64 range_start, u64 range_end) { - int ret, numpages; + int ret = 0, numpages; struct page **pages = NULL; u64 phys; + unsigned int ext_flags; + struct super_block *sb = inode->i_sb; /* * File systems which don't support sparse files zero on every * extend. */ - if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) + if (!ocfs2_sparse_alloc(OCFS2_SB(sb))) return 0; - pages = kcalloc(ocfs2_pages_per_cluster(inode->i_sb), + pages = kcalloc(ocfs2_pages_per_cluster(sb), sizeof(struct page *), GFP_NOFS); if (pages == NULL) { ret = -ENOMEM; @@ -5803,16 +5781,31 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, goto out; } - ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages, - &numpages, &phys); + if (range_start == range_end) + goto out; + + ret = ocfs2_extent_map_get_blocks(inode, + range_start >> sb->s_blocksize_bits, + &phys, NULL, &ext_flags); if (ret) { mlog_errno(ret); goto out; } - if (numpages == 0) + /* + * Tail is a hole, or is marked unwritten. In either case, we + * can count on read and write to return/push zero's. + */ + if (phys == 0 || ext_flags & OCFS2_EXT_UNWRITTEN) goto out; + ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages, + &numpages); + if (ret) { + mlog_errno(ret); + goto out; + } + ocfs2_zero_cluster_pages(inode, range_start, range_end, pages, numpages, phys, handle); diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index fae07672eb18..8416e383197c 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -830,18 +830,22 @@ struct ocfs2_write_ctxt { struct ocfs2_cached_dealloc_ctxt w_dealloc; }; -static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) +void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages) { int i; - for(i = 0; i < wc->w_num_pages; i++) { - if (wc->w_pages[i] == NULL) - continue; - - unlock_page(wc->w_pages[i]); - mark_page_accessed(wc->w_pages[i]); - page_cache_release(wc->w_pages[i]); + for(i = 0; i < num_pages; i++) { + if (pages[i]) { + unlock_page(pages[i]); + mark_page_accessed(pages[i]); + page_cache_release(pages[i]); + } } +} + +static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) +{ + ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages); brelse(wc->w_di_bh); kfree(wc); diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index 389579bd64e3..b4fa37d40db4 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h @@ -34,6 +34,8 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno, struct inode *inode, unsigned int from, unsigned int to, int new); +void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages); + int walk_page_buffers( handle_t *handle, struct buffer_head *head, unsigned from, From 316f4b9f98a353ac1be93199694fd97272378815 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 7 Sep 2007 18:21:26 -0700 Subject: [PATCH 2371/2804] ocfs2: Move directory manipulation code into dir.c The code for adding, removing, deleting directory entries was splattered all over namei.c. I'd rather have this all centralized, so that it's easier to make changes for inline dir data, and eventually indexed directories. None of the code in any of the functions was changed. I only removed the static keyword from some prototypes so that they could be exported. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 430 +++++++++++++++++++++++++++++++++++++++++++- fs/ocfs2/dir.h | 44 ++++- fs/ocfs2/journal.c | 2 +- fs/ocfs2/namei.c | 433 --------------------------------------------- fs/ocfs2/namei.h | 19 -- 5 files changed, 461 insertions(+), 467 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 0d5fdde959c8..8e0ae022b2e9 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -55,10 +55,16 @@ #include "journal.h" #include "namei.h" #include "suballoc.h" +#include "super.h" #include "uptodate.h" #include "buffer_head_io.h" +#define NAMEI_RA_CHUNKS 2 +#define NAMEI_RA_BLOCKS 4 +#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + static unsigned char ocfs2_filetype_table[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; @@ -67,6 +73,347 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, struct inode *dir, struct buffer_head *parent_fe_bh, struct buffer_head **new_de_bh); +static int ocfs2_do_extend_dir(struct super_block *sb, + handle_t *handle, + struct inode *dir, + struct buffer_head *parent_fe_bh, + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, + struct buffer_head **new_bh); + +int ocfs2_check_dir_entry(struct inode * dir, + struct ocfs2_dir_entry * de, + struct buffer_head * bh, + unsigned long offset) +{ + const char *error_msg = NULL; + const int rlen = le16_to_cpu(de->rec_len); + + if (rlen < OCFS2_DIR_REC_LEN(1)) + error_msg = "rec_len is smaller than minimal"; + else if (rlen % 4 != 0) + error_msg = "rec_len % 4 != 0"; + else if (rlen < OCFS2_DIR_REC_LEN(de->name_len)) + error_msg = "rec_len is too small for name_len"; + else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) + error_msg = "directory entry across blocks"; + + if (error_msg != NULL) + mlog(ML_ERROR, "bad entry in directory #%llu: %s - " + "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n", + (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg, + offset, (unsigned long long)le64_to_cpu(de->inode), rlen, + de->name_len); + return error_msg == NULL ? 1 : 0; +} + +static inline int ocfs2_match(int len, + const char * const name, + struct ocfs2_dir_entry *de) +{ + if (len != de->name_len) + return 0; + if (!de->inode) + return 0; + return !memcmp(name, de->name, len); +} + +/* + * Returns 0 if not found, -1 on failure, and 1 on success + */ +static int inline ocfs2_search_dirblock(struct buffer_head *bh, + struct inode *dir, + const char *name, int namelen, + unsigned long offset, + struct ocfs2_dir_entry **res_dir) +{ + struct ocfs2_dir_entry *de; + char *dlimit, *de_buf; + int de_len; + int ret = 0; + + mlog_entry_void(); + + de_buf = bh->b_data; + dlimit = de_buf + dir->i_sb->s_blocksize; + + while (de_buf < dlimit) { + /* this code is executed quadratically often */ + /* do minimal checking `by hand' */ + + de = (struct ocfs2_dir_entry *) de_buf; + + if (de_buf + namelen <= dlimit && + ocfs2_match(namelen, name, de)) { + /* found a match - just to be sure, do a full check */ + if (!ocfs2_check_dir_entry(dir, de, bh, offset)) { + ret = -1; + goto bail; + } + *res_dir = de; + ret = 1; + goto bail; + } + + /* prevent looping on a bad block */ + de_len = le16_to_cpu(de->rec_len); + if (de_len <= 0) { + ret = -1; + goto bail; + } + + de_buf += de_len; + offset += de_len; + } + +bail: + mlog_exit(ret); + return ret; +} + +struct buffer_head *ocfs2_find_entry(const char *name, int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir) +{ + struct super_block *sb; + struct buffer_head *bh_use[NAMEI_RA_SIZE]; + struct buffer_head *bh, *ret = NULL; + unsigned long start, block, b; + int ra_max = 0; /* Number of bh's in the readahead + buffer, bh_use[] */ + int ra_ptr = 0; /* Current index into readahead + buffer */ + int num = 0; + int nblocks, i, err; + + mlog_entry_void(); + + *res_dir = NULL; + sb = dir->i_sb; + + nblocks = i_size_read(dir) >> sb->s_blocksize_bits; + start = OCFS2_I(dir)->ip_dir_start_lookup; + if (start >= nblocks) + start = 0; + block = start; + +restart: + do { + /* + * We deal with the read-ahead logic here. + */ + if (ra_ptr >= ra_max) { + /* Refill the readahead buffer */ + ra_ptr = 0; + b = block; + for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { + /* + * Terminate if we reach the end of the + * directory and must wrap, or if our + * search has finished at this block. + */ + if (b >= nblocks || (num && block == start)) { + bh_use[ra_max] = NULL; + break; + } + num++; + + bh = ocfs2_bread(dir, b++, &err, 1); + bh_use[ra_max] = bh; + } + } + if ((bh = bh_use[ra_ptr++]) == NULL) + goto next; + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + /* read error, skip block & hope for the best */ + ocfs2_error(dir->i_sb, "reading directory %llu, " + "offset %lu\n", + (unsigned long long)OCFS2_I(dir)->ip_blkno, + block); + brelse(bh); + goto next; + } + i = ocfs2_search_dirblock(bh, dir, name, namelen, + block << sb->s_blocksize_bits, + res_dir); + if (i == 1) { + OCFS2_I(dir)->ip_dir_start_lookup = block; + ret = bh; + goto cleanup_and_exit; + } else { + brelse(bh); + if (i < 0) + goto cleanup_and_exit; + } + next: + if (++block >= nblocks) + block = 0; + } while (block != start); + + /* + * If the directory has grown while we were searching, then + * search the last part of the directory before giving up. + */ + block = nblocks; + nblocks = i_size_read(dir) >> sb->s_blocksize_bits; + if (block < nblocks) { + start = 0; + goto restart; + } + +cleanup_and_exit: + /* Clean up the read-ahead blocks */ + for (; ra_ptr < ra_max; ra_ptr++) + brelse(bh_use[ra_ptr]); + + mlog_exit_ptr(ret); + return ret; +} + +/* + * ocfs2_delete_entry deletes a directory entry by merging it with the + * previous entry + */ +int ocfs2_delete_entry(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh) +{ + struct ocfs2_dir_entry *de, *pde; + int i, status = -ENOENT; + + mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh); + + i = 0; + pde = NULL; + de = (struct ocfs2_dir_entry *) bh->b_data; + while (i < bh->b_size) { + if (!ocfs2_check_dir_entry(dir, de, bh, i)) { + status = -EIO; + mlog_errno(status); + goto bail; + } + if (de == de_del) { + status = ocfs2_journal_access(handle, dir, bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + status = -EIO; + mlog_errno(status); + goto bail; + } + if (pde) + pde->rec_len = + cpu_to_le16(le16_to_cpu(pde->rec_len) + + le16_to_cpu(de->rec_len)); + else + de->inode = 0; + dir->i_version++; + status = ocfs2_journal_dirty(handle, bh); + goto bail; + } + i += le16_to_cpu(de->rec_len); + pde = de; + de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len)); + } +bail: + mlog_exit(status); + return status; +} + +/* we don't always have a dentry for what we want to add, so people + * like orphan dir can call this instead. + * + * If you pass me insert_bh, I'll skip the search of the other dir + * blocks and put the record in there. + */ +int __ocfs2_add_entry(handle_t *handle, + struct inode *dir, + const char *name, int namelen, + struct inode *inode, u64 blkno, + struct buffer_head *parent_fe_bh, + struct buffer_head *insert_bh) +{ + unsigned long offset; + unsigned short rec_len; + struct ocfs2_dir_entry *de, *de1; + struct super_block *sb; + int retval, status; + + mlog_entry_void(); + + sb = dir->i_sb; + + if (!namelen) + return -EINVAL; + + rec_len = OCFS2_DIR_REC_LEN(namelen); + offset = 0; + de = (struct ocfs2_dir_entry *) insert_bh->b_data; + while (1) { + BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data); + /* These checks should've already been passed by the + * prepare function, but I guess we can leave them + * here anyway. */ + if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) { + retval = -ENOENT; + goto bail; + } + if (ocfs2_match(namelen, name, de)) { + retval = -EEXIST; + goto bail; + } + if (((le64_to_cpu(de->inode) == 0) && + (le16_to_cpu(de->rec_len) >= rec_len)) || + (le16_to_cpu(de->rec_len) >= + (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) { + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); + if (retval < 0) { + mlog_errno(retval); + goto bail; + } + + status = ocfs2_journal_access(handle, dir, insert_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + /* By now the buffer is marked for journaling */ + offset += le16_to_cpu(de->rec_len); + if (le64_to_cpu(de->inode)) { + de1 = (struct ocfs2_dir_entry *)((char *) de + + OCFS2_DIR_REC_LEN(de->name_len)); + de1->rec_len = + cpu_to_le16(le16_to_cpu(de->rec_len) - + OCFS2_DIR_REC_LEN(de->name_len)); + de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); + de = de1; + } + de->file_type = OCFS2_FT_UNKNOWN; + if (blkno) { + de->inode = cpu_to_le64(blkno); + ocfs2_set_de_type(de, inode->i_mode); + } else + de->inode = 0; + de->name_len = namelen; + memcpy(de->name, name, namelen); + + dir->i_version++; + status = ocfs2_journal_dirty(handle, insert_bh); + retval = 0; + goto bail; + } + offset += le16_to_cpu(de->rec_len); + de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); + } + + /* when you think about it, the assert above should prevent us + * from ever getting here. */ + retval = -ENOSPC; +bail: + + mlog_exit(retval); + return retval; +} + /* * ocfs2_readdir() * @@ -347,14 +694,83 @@ int ocfs2_empty_dir(struct inode *inode) return 1; } +int ocfs2_fill_new_dir(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *fe_bh, + struct ocfs2_alloc_context *data_ac) +{ + int status; + struct buffer_head *new_bh = NULL; + struct ocfs2_dir_entry *de = NULL; + + mlog_entry_void(); + + status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh, + data_ac, NULL, &new_bh); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + ocfs2_set_new_buffer_uptodate(inode, new_bh); + + status = ocfs2_journal_access(handle, inode, new_bh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (status < 0) { + mlog_errno(status); + goto bail; + } + memset(new_bh->b_data, 0, osb->sb->s_blocksize); + + de = (struct ocfs2_dir_entry *) new_bh->b_data; + de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); + de->name_len = 1; + de->rec_len = + cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); + strcpy(de->name, "."); + ocfs2_set_de_type(de, S_IFDIR); + de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len)); + de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno); + de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - + OCFS2_DIR_REC_LEN(1)); + de->name_len = 2; + strcpy(de->name, ".."); + ocfs2_set_de_type(de, S_IFDIR); + + status = ocfs2_journal_dirty(handle, new_bh); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + i_size_write(inode, inode->i_sb->s_blocksize); + inode->i_nlink = 2; + inode->i_blocks = ocfs2_inode_sector_count(inode); + status = ocfs2_mark_inode_dirty(handle, inode, fe_bh); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + status = 0; +bail: + if (new_bh) + brelse(new_bh); + + mlog_exit(status); + return status; +} + /* returns a bh of the 1st new block in the allocation. */ -int ocfs2_do_extend_dir(struct super_block *sb, - handle_t *handle, - struct inode *dir, - struct buffer_head *parent_fe_bh, - struct ocfs2_alloc_context *data_ac, - struct ocfs2_alloc_context *meta_ac, - struct buffer_head **new_bh) +static int ocfs2_do_extend_dir(struct super_block *sb, + handle_t *handle, + struct inode *dir, + struct buffer_head *parent_fe_bh, + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, + struct buffer_head **new_bh) { int status; int extend; diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index 3f67e146864a..7bf9c0a01cdf 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h @@ -26,6 +26,31 @@ #ifndef OCFS2_DIR_H #define OCFS2_DIR_H +struct buffer_head *ocfs2_find_entry(const char *name, + int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir); +int ocfs2_delete_entry(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh); +int __ocfs2_add_entry(handle_t *handle, + struct inode *dir, + const char *name, int namelen, + struct inode *inode, u64 blkno, + struct buffer_head *parent_fe_bh, + struct buffer_head *insert_bh); +static inline int ocfs2_add_entry(handle_t *handle, + struct dentry *dentry, + struct inode *inode, u64 blkno, + struct buffer_head *parent_fe_bh, + struct buffer_head *insert_bh) +{ + return __ocfs2_add_entry(handle, dentry->d_parent->d_inode, + dentry->d_name.name, dentry->d_name.len, + inode, blkno, parent_fe_bh, insert_bh); +} + int ocfs2_check_dir_for_entry(struct inode *dir, const char *name, int namelen); @@ -44,11 +69,16 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, int namelen, struct buffer_head **ret_de_bh); struct ocfs2_alloc_context; -int ocfs2_do_extend_dir(struct super_block *sb, - handle_t *handle, - struct inode *dir, - struct buffer_head *parent_fe_bh, - struct ocfs2_alloc_context *data_ac, - struct ocfs2_alloc_context *meta_ac, - struct buffer_head **new_bh); +int ocfs2_fill_new_dir(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *fe_bh, + struct ocfs2_alloc_context *data_ac); + +int ocfs2_check_dir_entry(struct inode *dir, + struct ocfs2_dir_entry *de, + struct buffer_head *bh, + unsigned long offset); + #endif /* OCFS2_DIR_H */ diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index dbfb20bb27ea..8bbfc80e5c5c 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -35,13 +35,13 @@ #include "ocfs2.h" #include "alloc.h" +#include "dir.h" #include "dlmglue.h" #include "extent_map.h" #include "heartbeat.h" #include "inode.h" #include "journal.h" #include "localalloc.h" -#include "namei.h" #include "slot_map.h" #include "super.h" #include "vote.h" diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 701e6d04ed5d..aae6c0bf6696 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -64,29 +64,6 @@ #include "buffer_head_io.h" -#define NAMEI_RA_CHUNKS 2 -#define NAMEI_RA_BLOCKS 4 -#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) -#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) - -static int inline ocfs2_search_dirblock(struct buffer_head *bh, - struct inode *dir, - const char *name, int namelen, - unsigned long offset, - struct ocfs2_dir_entry **res_dir); - -static int ocfs2_delete_entry(handle_t *handle, - struct inode *dir, - struct ocfs2_dir_entry *de_del, - struct buffer_head *bh); - -static int __ocfs2_add_entry(handle_t *handle, - struct inode *dir, - const char *name, int namelen, - struct inode *inode, u64 blkno, - struct buffer_head *parent_fe_bh, - struct buffer_head *insert_bh); - static int ocfs2_mknod_locked(struct ocfs2_super *osb, struct inode *dir, struct dentry *dentry, int mode, @@ -97,13 +74,6 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, struct inode **ret_inode, struct ocfs2_alloc_context *inode_ac); -static int ocfs2_fill_new_dir(struct ocfs2_super *osb, - handle_t *handle, - struct inode *parent, - struct inode *inode, - struct buffer_head *fe_bh, - struct ocfs2_alloc_context *data_ac); - static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, struct inode **ret_orphan_dir, struct inode *inode, @@ -123,17 +93,6 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb, struct inode *inode, const char *symname); -static inline int ocfs2_add_entry(handle_t *handle, - struct dentry *dentry, - struct inode *inode, u64 blkno, - struct buffer_head *parent_fe_bh, - struct buffer_head *insert_bh) -{ - return __ocfs2_add_entry(handle, dentry->d_parent->d_inode, - dentry->d_name.name, dentry->d_name.len, - inode, blkno, parent_fe_bh, insert_bh); -} - /* An orphan dir name is an 8 byte value, printed as a hex string */ #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64))) @@ -232,75 +191,6 @@ bail: return ret; } -static int ocfs2_fill_new_dir(struct ocfs2_super *osb, - handle_t *handle, - struct inode *parent, - struct inode *inode, - struct buffer_head *fe_bh, - struct ocfs2_alloc_context *data_ac) -{ - int status; - struct buffer_head *new_bh = NULL; - struct ocfs2_dir_entry *de = NULL; - - mlog_entry_void(); - - status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh, - data_ac, NULL, &new_bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } - - ocfs2_set_new_buffer_uptodate(inode, new_bh); - - status = ocfs2_journal_access(handle, inode, new_bh, - OCFS2_JOURNAL_ACCESS_CREATE); - if (status < 0) { - mlog_errno(status); - goto bail; - } - memset(new_bh->b_data, 0, osb->sb->s_blocksize); - - de = (struct ocfs2_dir_entry *) new_bh->b_data; - de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); - de->name_len = 1; - de->rec_len = - cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); - strcpy(de->name, "."); - ocfs2_set_de_type(de, S_IFDIR); - de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len)); - de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno); - de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - - OCFS2_DIR_REC_LEN(1)); - de->name_len = 2; - strcpy(de->name, ".."); - ocfs2_set_de_type(de, S_IFDIR); - - status = ocfs2_journal_dirty(handle, new_bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } - - i_size_write(inode, inode->i_sb->s_blocksize); - inode->i_nlink = 2; - inode->i_blocks = ocfs2_inode_sector_count(inode); - status = ocfs2_mark_inode_dirty(handle, inode, fe_bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } - - status = 0; -bail: - if (new_bh) - brelse(new_bh); - - mlog_exit(status); - return status; -} - static int ocfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, @@ -1767,329 +1657,6 @@ bail: return status; } -int ocfs2_check_dir_entry(struct inode * dir, - struct ocfs2_dir_entry * de, - struct buffer_head * bh, - unsigned long offset) -{ - const char *error_msg = NULL; - const int rlen = le16_to_cpu(de->rec_len); - - if (rlen < OCFS2_DIR_REC_LEN(1)) - error_msg = "rec_len is smaller than minimal"; - else if (rlen % 4 != 0) - error_msg = "rec_len % 4 != 0"; - else if (rlen < OCFS2_DIR_REC_LEN(de->name_len)) - error_msg = "rec_len is too small for name_len"; - else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) - error_msg = "directory entry across blocks"; - - if (error_msg != NULL) - mlog(ML_ERROR, "bad entry in directory #%llu: %s - " - "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n", - (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg, - offset, (unsigned long long)le64_to_cpu(de->inode), rlen, - de->name_len); - return error_msg == NULL ? 1 : 0; -} - -/* we don't always have a dentry for what we want to add, so people - * like orphan dir can call this instead. - * - * If you pass me insert_bh, I'll skip the search of the other dir - * blocks and put the record in there. - */ -static int __ocfs2_add_entry(handle_t *handle, - struct inode *dir, - const char *name, int namelen, - struct inode *inode, u64 blkno, - struct buffer_head *parent_fe_bh, - struct buffer_head *insert_bh) -{ - unsigned long offset; - unsigned short rec_len; - struct ocfs2_dir_entry *de, *de1; - struct super_block *sb; - int retval, status; - - mlog_entry_void(); - - sb = dir->i_sb; - - if (!namelen) - return -EINVAL; - - rec_len = OCFS2_DIR_REC_LEN(namelen); - offset = 0; - de = (struct ocfs2_dir_entry *) insert_bh->b_data; - while (1) { - BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data); - /* These checks should've already been passed by the - * prepare function, but I guess we can leave them - * here anyway. */ - if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) { - retval = -ENOENT; - goto bail; - } - if (ocfs2_match(namelen, name, de)) { - retval = -EEXIST; - goto bail; - } - if (((le64_to_cpu(de->inode) == 0) && - (le16_to_cpu(de->rec_len) >= rec_len)) || - (le16_to_cpu(de->rec_len) >= - (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) { - dir->i_mtime = dir->i_ctime = CURRENT_TIME; - retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); - if (retval < 0) { - mlog_errno(retval); - goto bail; - } - - status = ocfs2_journal_access(handle, dir, insert_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - /* By now the buffer is marked for journaling */ - offset += le16_to_cpu(de->rec_len); - if (le64_to_cpu(de->inode)) { - de1 = (struct ocfs2_dir_entry *)((char *) de + - OCFS2_DIR_REC_LEN(de->name_len)); - de1->rec_len = - cpu_to_le16(le16_to_cpu(de->rec_len) - - OCFS2_DIR_REC_LEN(de->name_len)); - de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); - de = de1; - } - de->file_type = OCFS2_FT_UNKNOWN; - if (blkno) { - de->inode = cpu_to_le64(blkno); - ocfs2_set_de_type(de, inode->i_mode); - } else - de->inode = 0; - de->name_len = namelen; - memcpy(de->name, name, namelen); - - dir->i_version++; - status = ocfs2_journal_dirty(handle, insert_bh); - retval = 0; - goto bail; - } - offset += le16_to_cpu(de->rec_len); - de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); - } - - /* when you think about it, the assert above should prevent us - * from ever getting here. */ - retval = -ENOSPC; -bail: - - mlog_exit(retval); - return retval; -} - - -/* - * ocfs2_delete_entry deletes a directory entry by merging it with the - * previous entry - */ -static int ocfs2_delete_entry(handle_t *handle, - struct inode *dir, - struct ocfs2_dir_entry *de_del, - struct buffer_head *bh) -{ - struct ocfs2_dir_entry *de, *pde; - int i, status = -ENOENT; - - mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh); - - i = 0; - pde = NULL; - de = (struct ocfs2_dir_entry *) bh->b_data; - while (i < bh->b_size) { - if (!ocfs2_check_dir_entry(dir, de, bh, i)) { - status = -EIO; - mlog_errno(status); - goto bail; - } - if (de == de_del) { - status = ocfs2_journal_access(handle, dir, bh, - OCFS2_JOURNAL_ACCESS_WRITE); - if (status < 0) { - status = -EIO; - mlog_errno(status); - goto bail; - } - if (pde) - pde->rec_len = - cpu_to_le16(le16_to_cpu(pde->rec_len) + - le16_to_cpu(de->rec_len)); - else - de->inode = 0; - dir->i_version++; - status = ocfs2_journal_dirty(handle, bh); - goto bail; - } - i += le16_to_cpu(de->rec_len); - pde = de; - de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len)); - } -bail: - mlog_exit(status); - return status; -} - -/* - * Returns 0 if not found, -1 on failure, and 1 on success - */ -static int inline ocfs2_search_dirblock(struct buffer_head *bh, - struct inode *dir, - const char *name, int namelen, - unsigned long offset, - struct ocfs2_dir_entry **res_dir) -{ - struct ocfs2_dir_entry *de; - char *dlimit, *de_buf; - int de_len; - int ret = 0; - - mlog_entry_void(); - - de_buf = bh->b_data; - dlimit = de_buf + dir->i_sb->s_blocksize; - - while (de_buf < dlimit) { - /* this code is executed quadratically often */ - /* do minimal checking `by hand' */ - - de = (struct ocfs2_dir_entry *) de_buf; - - if (de_buf + namelen <= dlimit && - ocfs2_match(namelen, name, de)) { - /* found a match - just to be sure, do a full check */ - if (!ocfs2_check_dir_entry(dir, de, bh, offset)) { - ret = -1; - goto bail; - } - *res_dir = de; - ret = 1; - goto bail; - } - - /* prevent looping on a bad block */ - de_len = le16_to_cpu(de->rec_len); - if (de_len <= 0) { - ret = -1; - goto bail; - } - - de_buf += de_len; - offset += de_len; - } - -bail: - mlog_exit(ret); - return ret; -} - -struct buffer_head *ocfs2_find_entry(const char *name, int namelen, - struct inode *dir, - struct ocfs2_dir_entry **res_dir) -{ - struct super_block *sb; - struct buffer_head *bh_use[NAMEI_RA_SIZE]; - struct buffer_head *bh, *ret = NULL; - unsigned long start, block, b; - int ra_max = 0; /* Number of bh's in the readahead - buffer, bh_use[] */ - int ra_ptr = 0; /* Current index into readahead - buffer */ - int num = 0; - int nblocks, i, err; - - mlog_entry_void(); - - *res_dir = NULL; - sb = dir->i_sb; - - nblocks = i_size_read(dir) >> sb->s_blocksize_bits; - start = OCFS2_I(dir)->ip_dir_start_lookup; - if (start >= nblocks) - start = 0; - block = start; - -restart: - do { - /* - * We deal with the read-ahead logic here. - */ - if (ra_ptr >= ra_max) { - /* Refill the readahead buffer */ - ra_ptr = 0; - b = block; - for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { - /* - * Terminate if we reach the end of the - * directory and must wrap, or if our - * search has finished at this block. - */ - if (b >= nblocks || (num && block == start)) { - bh_use[ra_max] = NULL; - break; - } - num++; - - bh = ocfs2_bread(dir, b++, &err, 1); - bh_use[ra_max] = bh; - } - } - if ((bh = bh_use[ra_ptr++]) == NULL) - goto next; - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - /* read error, skip block & hope for the best */ - ocfs2_error(dir->i_sb, "reading directory %llu, " - "offset %lu\n", - (unsigned long long)OCFS2_I(dir)->ip_blkno, - block); - brelse(bh); - goto next; - } - i = ocfs2_search_dirblock(bh, dir, name, namelen, - block << sb->s_blocksize_bits, - res_dir); - if (i == 1) { - OCFS2_I(dir)->ip_dir_start_lookup = block; - ret = bh; - goto cleanup_and_exit; - } else { - brelse(bh); - if (i < 0) - goto cleanup_and_exit; - } - next: - if (++block >= nblocks) - block = 0; - } while (block != start); - - /* - * If the directory has grown while we were searching, then - * search the last part of the directory before giving up. - */ - block = nblocks; - nblocks = i_size_read(dir) >> sb->s_blocksize_bits; - if (block < nblocks) { - start = 0; - goto restart; - } - -cleanup_and_exit: - /* Clean up the read-ahead blocks */ - for (; ra_ptr < ra_max; ra_ptr++) - brelse(bh_use[ra_ptr]); - - mlog_exit_ptr(ret); - return ret; -} - static int ocfs2_blkno_stringify(u64 blkno, char *name) { int status, namelen; diff --git a/fs/ocfs2/namei.h b/fs/ocfs2/namei.h index 0975c7b7212b..688aef64c879 100644 --- a/fs/ocfs2/namei.h +++ b/fs/ocfs2/namei.h @@ -30,29 +30,10 @@ extern const struct inode_operations ocfs2_dir_iops; struct dentry *ocfs2_get_parent(struct dentry *child); -int ocfs2_check_dir_entry (struct inode *dir, - struct ocfs2_dir_entry *de, - struct buffer_head *bh, - unsigned long offset); -struct buffer_head *ocfs2_find_entry(const char *name, - int namelen, - struct inode *dir, - struct ocfs2_dir_entry **res_dir); int ocfs2_orphan_del(struct ocfs2_super *osb, handle_t *handle, struct inode *orphan_dir_inode, struct inode *inode, struct buffer_head *orphan_dir_bh); -static inline int ocfs2_match(int len, - const char * const name, - struct ocfs2_dir_entry *de) -{ - if (len != de->name_len) - return 0; - if (!de->inode) - return 0; - return !memcmp(name, de->name, len); -} - #endif /* OCFS2_NAMEI_H */ From b8bc5f4fde376c9eee524a9a2b7e85560e604e85 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Mon, 10 Sep 2007 17:17:52 -0700 Subject: [PATCH 2372/2804] ocfs2: Abstract out core dir listing functionality Put this in it's own function so that the functionality can be overridden. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 103 +++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 8e0ae022b2e9..d1f92fd2ed96 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -414,11 +414,8 @@ bail: return retval; } -/* - * ocfs2_readdir() - * - */ -int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) +static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, + loff_t *f_pos, void *priv, filldir_t filldir) { int error = 0; unsigned long offset, blk, last_ra_blk = 0; @@ -426,45 +423,23 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) struct buffer_head * bh, * tmp; struct ocfs2_dir_entry * de; int err; - struct inode *inode = filp->f_path.dentry->d_inode; struct super_block * sb = inode->i_sb; unsigned int ra_sectors = 16; - int lock_level = 0; - - mlog_entry("dirino=%llu\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno); stored = 0; bh = NULL; - error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level); - if (lock_level && error >= 0) { - /* We release EX lock which used to update atime - * and get PR lock again to reduce contention - * on commonly accessed directories. */ - ocfs2_meta_unlock(inode, 1); - lock_level = 0; - error = ocfs2_meta_lock(inode, NULL, 0); - } - if (error < 0) { - if (error != -ENOENT) - mlog_errno(error); - /* we haven't got any yet, so propagate the error. */ - stored = error; - goto bail_nolock; - } + offset = (*f_pos) & (sb->s_blocksize - 1); - offset = filp->f_pos & (sb->s_blocksize - 1); - - while (!error && !stored && filp->f_pos < i_size_read(inode)) { - blk = (filp->f_pos) >> sb->s_blocksize_bits; + while (!error && !stored && *f_pos < i_size_read(inode)) { + blk = (*f_pos) >> sb->s_blocksize_bits; bh = ocfs2_bread(inode, blk, &err, 0); if (!bh) { mlog(ML_ERROR, "directory #%llu contains a hole at offset %lld\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, - filp->f_pos); - filp->f_pos += sb->s_blocksize - offset; + *f_pos); + *f_pos += sb->s_blocksize - offset; continue; } @@ -490,7 +465,7 @@ revalidate: * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the block * to make sure. */ - if (filp->f_version != inode->i_version) { + if (*f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { de = (struct ocfs2_dir_entry *) (bh->b_data + i); /* It's too expensive to do a full @@ -505,21 +480,20 @@ revalidate: i += le16_to_cpu(de->rec_len); } offset = i; - filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) + *f_pos = ((*f_pos) & ~(sb->s_blocksize - 1)) | offset; - filp->f_version = inode->i_version; + *f_version = inode->i_version; } - while (!error && filp->f_pos < i_size_read(inode) + while (!error && *f_pos < i_size_read(inode) && offset < sb->s_blocksize) { de = (struct ocfs2_dir_entry *) (bh->b_data + offset); if (!ocfs2_check_dir_entry(inode, de, bh, offset)) { /* On error, skip the f_pos to the next block. */ - filp->f_pos = (filp->f_pos | - (sb->s_blocksize - 1)) + 1; + *f_pos = ((*f_pos) | (sb->s_blocksize - 1)) + 1; brelse(bh); - goto bail; + goto out; } offset += le16_to_cpu(de->rec_len); if (le64_to_cpu(de->inode)) { @@ -530,36 +504,71 @@ revalidate: * not the directory has been modified * during the copy operation. */ - unsigned long version = filp->f_version; + unsigned long version = *f_version; unsigned char d_type = DT_UNKNOWN; if (de->file_type < OCFS2_FT_MAX) d_type = ocfs2_filetype_table[de->file_type]; - error = filldir(dirent, de->name, + error = filldir(priv, de->name, de->name_len, - filp->f_pos, + *f_pos, ino_from_blkno(sb, le64_to_cpu(de->inode)), d_type); if (error) break; - if (version != filp->f_version) + if (version != *f_version) goto revalidate; stored ++; } - filp->f_pos += le16_to_cpu(de->rec_len); + *f_pos += le16_to_cpu(de->rec_len); } offset = 0; brelse(bh); } stored = 0; -bail: +out: + return stored; +} + +/* + * ocfs2_readdir() + * + */ +int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) +{ + int error = 0; + struct inode *inode = filp->f_path.dentry->d_inode; + int lock_level = 0; + + mlog_entry("dirino=%llu\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno); + + error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level); + if (lock_level && error >= 0) { + /* We release EX lock which used to update atime + * and get PR lock again to reduce contention + * on commonly accessed directories. */ + ocfs2_meta_unlock(inode, 1); + lock_level = 0; + error = ocfs2_meta_lock(inode, NULL, 0); + } + if (error < 0) { + if (error != -ENOENT) + mlog_errno(error); + /* we haven't got any yet, so propagate the error. */ + goto bail_nolock; + } + + error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos, + dirent, filldir); + ocfs2_meta_unlock(inode, lock_level); bail_nolock: - mlog_exit(stored); + mlog_exit(error); - return stored; + return error; } /* From 7e8536797d4508ddc790cc3af6a281db1582d485 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Mon, 10 Sep 2007 17:30:26 -0700 Subject: [PATCH 2373/2804] ocfs2: Pass raw u64 to filldir filldir_t can take this, so don't turn de->inode into a 32 bit value. Right now this doesn't make a difference since no ocfs2 inodes overflow that, but it could be a nasty surprise later on if some kernel code is calling ocfs2_dir_foreach_blk() and expecting real inode numbers back... Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index d1f92fd2ed96..dbfa6f66291a 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -512,7 +512,7 @@ revalidate: error = filldir(priv, de->name, de->name_len, *f_pos, - ino_from_blkno(sb, le64_to_cpu(de->inode)), + le64_to_cpu(de->inode), d_type); if (error) break; From 5eae5b96fc86e6c85f5f90e90fe9e6966f1fec63 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Mon, 10 Sep 2007 17:50:51 -0700 Subject: [PATCH 2374/2804] ocfs2: Remove open coded readdir() ocfs2_queue_orphans() has an open coded readdir loop which can easily just use a directory accessor function. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 28 +++++++++-- fs/ocfs2/dir.h | 7 +-- fs/ocfs2/journal.c | 118 +++++++++++++++++---------------------------- 3 files changed, 70 insertions(+), 83 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index dbfa6f66291a..a75c340fc689 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -81,10 +81,10 @@ static int ocfs2_do_extend_dir(struct super_block *sb, struct ocfs2_alloc_context *meta_ac, struct buffer_head **new_bh); -int ocfs2_check_dir_entry(struct inode * dir, - struct ocfs2_dir_entry * de, - struct buffer_head * bh, - unsigned long offset) +static int ocfs2_check_dir_entry(struct inode * dir, + struct ocfs2_dir_entry * de, + struct buffer_head * bh, + unsigned long offset) { const char *error_msg = NULL; const int rlen = le16_to_cpu(de->rec_len); @@ -531,6 +531,26 @@ out: return stored; } +/* + * This is intended to be called from inside other kernel functions, + * so we fake some arguments. + */ +int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, + filldir_t filldir) +{ + int ret = 0; + unsigned long version = inode->i_version; + + while (*f_pos < i_size_read(inode)) { + ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv, + filldir); + if (ret) + break; + } + + return 0; +} + /* * ocfs2_readdir() * diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index 7bf9c0a01cdf..075d0e9fd459 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h @@ -62,6 +62,8 @@ int ocfs2_find_files_on_disk(const char *name, struct buffer_head **dirent_bh, struct ocfs2_dir_entry **dirent); int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir); +int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, + filldir_t filldir); int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, struct inode *dir, struct buffer_head *parent_fe_bh, @@ -76,9 +78,4 @@ int ocfs2_fill_new_dir(struct ocfs2_super *osb, struct buffer_head *fe_bh, struct ocfs2_alloc_context *data_ac); -int ocfs2_check_dir_entry(struct inode *dir, - struct ocfs2_dir_entry *de, - struct buffer_head *bh, - unsigned long offset); - #endif /* OCFS2_DIR_H */ diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 8bbfc80e5c5c..f9d01e25298d 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -1213,17 +1213,49 @@ bail: return status; } +struct ocfs2_orphan_filldir_priv { + struct inode *head; + struct ocfs2_super *osb; +}; + +static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len, + loff_t pos, u64 ino, unsigned type) +{ + struct ocfs2_orphan_filldir_priv *p = priv; + struct inode *iter; + + if (name_len == 1 && !strncmp(".", name, 1)) + return 0; + if (name_len == 2 && !strncmp("..", name, 2)) + return 0; + + /* Skip bad inodes so that recovery can continue */ + iter = ocfs2_iget(p->osb, ino, + OCFS2_FI_FLAG_ORPHAN_RECOVERY); + if (IS_ERR(iter)) + return 0; + + mlog(0, "queue orphan %llu\n", + (unsigned long long)OCFS2_I(iter)->ip_blkno); + /* No locking is required for the next_orphan queue as there + * is only ever a single process doing orphan recovery. */ + OCFS2_I(iter)->ip_next_orphan = p->head; + p->head = iter; + + return 0; +} + static int ocfs2_queue_orphans(struct ocfs2_super *osb, int slot, struct inode **head) { int status; struct inode *orphan_dir_inode = NULL; - struct inode *iter; - unsigned long offset, blk, local; - struct buffer_head *bh = NULL; - struct ocfs2_dir_entry *de; - struct super_block *sb = osb->sb; + struct ocfs2_orphan_filldir_priv priv; + loff_t pos = 0; + + priv.osb = osb; + priv.head = *head; orphan_dir_inode = ocfs2_get_system_file_inode(osb, ORPHAN_DIR_SYSTEM_INODE, @@ -1241,77 +1273,15 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb, goto out; } - offset = 0; - iter = NULL; - while(offset < i_size_read(orphan_dir_inode)) { - blk = offset >> sb->s_blocksize_bits; - - bh = ocfs2_bread(orphan_dir_inode, blk, &status, 0); - if (!bh) - status = -EINVAL; - if (status < 0) { - if (bh) - brelse(bh); - mlog_errno(status); - goto out_unlock; - } - - local = 0; - while(offset < i_size_read(orphan_dir_inode) - && local < sb->s_blocksize) { - de = (struct ocfs2_dir_entry *) (bh->b_data + local); - - if (!ocfs2_check_dir_entry(orphan_dir_inode, - de, bh, local)) { - status = -EINVAL; - mlog_errno(status); - brelse(bh); - goto out_unlock; - } - - local += le16_to_cpu(de->rec_len); - offset += le16_to_cpu(de->rec_len); - - /* I guess we silently fail on no inode? */ - if (!le64_to_cpu(de->inode)) - continue; - if (de->file_type > OCFS2_FT_MAX) { - mlog(ML_ERROR, - "block %llu contains invalid de: " - "inode = %llu, rec_len = %u, " - "name_len = %u, file_type = %u, " - "name='%.*s'\n", - (unsigned long long)bh->b_blocknr, - (unsigned long long)le64_to_cpu(de->inode), - le16_to_cpu(de->rec_len), - de->name_len, - de->file_type, - de->name_len, - de->name); - continue; - } - if (de->name_len == 1 && !strncmp(".", de->name, 1)) - continue; - if (de->name_len == 2 && !strncmp("..", de->name, 2)) - continue; - - iter = ocfs2_iget(osb, le64_to_cpu(de->inode), - OCFS2_FI_FLAG_ORPHAN_RECOVERY); - if (IS_ERR(iter)) - continue; - - mlog(0, "queue orphan %llu\n", - (unsigned long long)OCFS2_I(iter)->ip_blkno); - /* No locking is required for the next_orphan - * queue as there is only ever a single - * process doing orphan recovery. */ - OCFS2_I(iter)->ip_next_orphan = *head; - *head = iter; - } - brelse(bh); + status = ocfs2_dir_foreach(orphan_dir_inode, &pos, &priv, + ocfs2_orphan_filldir); + if (status) { + mlog_errno(status); + goto out; } -out_unlock: + *head = priv.head; + ocfs2_meta_unlock(orphan_dir_inode, 0); out: mutex_unlock(&orphan_dir_inode->i_mutex); From 0bfbbf62a8b5a129ba2c689283bfece80a601aba Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Wed, 12 Sep 2007 11:19:00 -0700 Subject: [PATCH 2375/2804] ocfs2: Implement ocfs2_empty_dir() as a caller of ocfs2_dir_foreach() We can preserve the behavior of ocfs2_empty_dir(), while getting rid of the open coded directory walk by just providing a smart filldir callback. This also automatically gets to use the dir readahead code, though in this case any advantage is minor at best. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 96 +++++++++++++++++++++++--------------------------- fs/ocfs2/dir.h | 2 +- 2 files changed, 46 insertions(+), 52 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index a75c340fc689..4bb54406354b 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -660,67 +660,61 @@ bail: return ret; } +struct ocfs2_empty_dir_priv { + unsigned seen_dot; + unsigned seen_dot_dot; + unsigned seen_other; +}; +static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, + loff_t pos, u64 ino, unsigned type) +{ + struct ocfs2_empty_dir_priv *p = priv; + + /* + * Check the positions of "." and ".." records to be sure + * they're in the correct place. + */ + if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) { + p->seen_dot = 1; + return 0; + } + + if (name_len == 2 && !strncmp("..", name, 2) && + pos == OCFS2_DIR_REC_LEN(1)) { + p->seen_dot_dot = 1; + return 0; + } + + p->seen_other = 1; + return 1; +} /* * routine to check that the specified directory is empty (for rmdir) + * + * Returns 1 if dir is empty, zero otherwise. */ int ocfs2_empty_dir(struct inode *inode) { - unsigned long offset; - struct buffer_head * bh; - struct ocfs2_dir_entry * de, * de1; - struct super_block * sb; - int err; + int ret; + loff_t start = 0; + struct ocfs2_empty_dir_priv priv; - sb = inode->i_sb; - if ((i_size_read(inode) < - (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) || - !(bh = ocfs2_bread(inode, 0, &err, 0))) { - mlog(ML_ERROR, "bad directory (dir #%llu) - no data block\n", + memset(&priv, 0, sizeof(priv)); + + ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir); + if (ret) + mlog_errno(ret); + + if (!priv.seen_dot || !priv.seen_dot_dot) { + mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); + /* + * XXX: Is it really safe to allow an unlink to continue? + */ return 1; } - de = (struct ocfs2_dir_entry *) bh->b_data; - de1 = (struct ocfs2_dir_entry *) - ((char *)de + le16_to_cpu(de->rec_len)); - if ((le64_to_cpu(de->inode) != OCFS2_I(inode)->ip_blkno) || - !le64_to_cpu(de1->inode) || - strcmp(".", de->name) || - strcmp("..", de1->name)) { - mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno); - brelse(bh); - return 1; - } - offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); - de = (struct ocfs2_dir_entry *)((char *)de1 + le16_to_cpu(de1->rec_len)); - while (offset < i_size_read(inode) ) { - if (!bh || (void *)de >= (void *)(bh->b_data + sb->s_blocksize)) { - brelse(bh); - bh = ocfs2_bread(inode, - offset >> sb->s_blocksize_bits, &err, 0); - if (!bh) { - mlog(ML_ERROR, "dir %llu has a hole at %lu\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno, offset); - offset += sb->s_blocksize; - continue; - } - de = (struct ocfs2_dir_entry *) bh->b_data; - } - if (!ocfs2_check_dir_entry(inode, de, bh, offset)) { - brelse(bh); - return 1; - } - if (le64_to_cpu(de->inode)) { - brelse(bh); - return 0; - } - offset += le16_to_cpu(de->rec_len); - de = (struct ocfs2_dir_entry *) - ((char *)de + le16_to_cpu(de->rec_len)); - } - brelse(bh); - return 1; + return !priv.seen_other; } int ocfs2_fill_new_dir(struct ocfs2_super *osb, diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index 075d0e9fd459..3e65f91b034d 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h @@ -54,7 +54,7 @@ static inline int ocfs2_add_entry(handle_t *handle, int ocfs2_check_dir_for_entry(struct inode *dir, const char *name, int namelen); -int ocfs2_empty_dir(struct inode *inode); /* FIXME: to namei.c */ +int ocfs2_empty_dir(struct inode *inode); int ocfs2_find_files_on_disk(const char *name, int namelen, u64 *blkno, From be94d11704ef79030fd2e6a0c41b4a7f65f9e860 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 11 Sep 2007 15:22:06 -0700 Subject: [PATCH 2376/2804] ocfs2: Provide convenience function for ino lookup A couple paths which needed to just match a parent dir + name pair to an inode number were a bit messy because they had to deal with ocfs2_find_files_on_disk() which returns a larger number of values. Provide a convenience function, ocfs2_lookup_ino_from_name() which internalizes all the extra accounting. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 17 +++++++++++++++++ fs/ocfs2/dir.h | 2 ++ fs/ocfs2/export.c | 8 +------- fs/ocfs2/namei.c | 9 ++------- fs/ocfs2/sysfile.c | 10 +++------- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 4bb54406354b..4791683a119c 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -628,6 +628,23 @@ leave: return status; } +/* + * Convenience function for callers which just want the block number + * mapped to a name and don't require the full dirent info, etc. + */ +int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name, + int namelen, u64 *blkno) +{ + int ret; + struct buffer_head *bh = NULL; + struct ocfs2_dir_entry *dirent = NULL; + + ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &bh, &dirent); + brelse(bh); + + return ret; +} + /* Check for a name within a directory. * * Return 0 if the name does not exist diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index 3e65f91b034d..d03eaaa5cfd4 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h @@ -61,6 +61,8 @@ int ocfs2_find_files_on_disk(const char *name, struct inode *inode, struct buffer_head **dirent_bh, struct ocfs2_dir_entry **dirent); +int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name, + int namelen, u64 *blkno); int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir); int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, filldir_t filldir); diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index bc48177bd183..c3bbc198f9ce 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c @@ -88,8 +88,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) struct dentry *parent; struct inode *inode; struct inode *dir = child->d_inode; - struct buffer_head *dirent_bh = NULL; - struct ocfs2_dir_entry *dirent; mlog_entry("(0x%p, '%.*s')\n", child, child->d_name.len, child->d_name.name); @@ -105,8 +103,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) goto bail; } - status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh, - &dirent); + status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno); if (status < 0) { parent = ERR_PTR(-ENOENT); goto bail_unlock; @@ -131,9 +128,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) bail_unlock: ocfs2_meta_unlock(dir, 0); - if (dirent_bh) - brelse(dirent_bh); - bail: mlog_exit_ptr(parent); diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index aae6c0bf6696..98aeebc2c9fa 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -101,10 +101,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, { int status; u64 blkno; - struct buffer_head *dirent_bh = NULL; struct inode *inode = NULL; struct dentry *ret; - struct ocfs2_dir_entry *dirent; struct ocfs2_inode_info *oi; mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry, @@ -126,9 +124,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, goto bail; } - status = ocfs2_find_files_on_disk(dentry->d_name.name, - dentry->d_name.len, &blkno, - dir, &dirent_bh, &dirent); + status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name, + dentry->d_name.len, &blkno); if (status < 0) goto bail_add; @@ -183,8 +180,6 @@ bail_unlock: ocfs2_meta_unlock(dir, 0); bail: - if (dirent_bh) - brelse(dirent_bh); mlog_exit_ptr(ret); diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c index 5df6e35d09b1..fd2e846e3e6f 100644 --- a/fs/ocfs2/sysfile.c +++ b/fs/ocfs2/sysfile.c @@ -100,17 +100,14 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, char namebuf[40]; struct inode *inode = NULL; u64 blkno; - struct buffer_head *dirent_bh = NULL; - struct ocfs2_dir_entry *de = NULL; int status = 0; ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, slot); - status = ocfs2_find_files_on_disk(namebuf, strlen(namebuf), - &blkno, osb->sys_root_inode, - &dirent_bh, &de); + status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf, + strlen(namebuf), &blkno); if (status < 0) { goto bail; } @@ -122,8 +119,7 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, goto bail; } bail: - if (dirent_bh) - brelse(dirent_bh); + return inode; } From 38760e243249f03b4c6d78ca624dd846a2681b67 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Tue, 11 Sep 2007 17:21:56 -0700 Subject: [PATCH 2377/2804] ocfs2: Rename cleanups ocfs2_rename() does direct manipulation of the dirent it's gotten back from a directory search. Wrap this manipulation inside of a function so that we can transparently change directory update behavior in the future. As an added bonus, this gets rid of an ugly macro. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 22 +++++++++++++++++++ fs/ocfs2/dir.h | 3 +++ fs/ocfs2/namei.c | 55 ++++++++++++++++++++---------------------------- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 4791683a119c..31db7e3881b1 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -271,6 +271,28 @@ cleanup_and_exit: return ret; } +int ocfs2_update_entry(struct inode *dir, handle_t *handle, + struct buffer_head *de_bh, struct ocfs2_dir_entry *de, + struct inode *new_entry_inode) +{ + int ret; + + ret = ocfs2_journal_access(handle, dir, de_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out; + } + + de->inode = cpu_to_le64(OCFS2_I(new_entry_inode)->ip_blkno); + ocfs2_set_de_type(de, new_entry_inode->i_mode); + + ocfs2_journal_dirty(handle, de_bh); + +out: + return ret; +} + /* * ocfs2_delete_entry deletes a directory entry by merging it with the * previous entry diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index d03eaaa5cfd4..ce48b9080d87 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h @@ -50,6 +50,9 @@ static inline int ocfs2_add_entry(handle_t *handle, dentry->d_name.name, dentry->d_name.len, inode, blkno, parent_fe_bh, insert_bh); } +int ocfs2_update_entry(struct inode *dir, handle_t *handle, + struct buffer_head *de_bh, struct ocfs2_dir_entry *de, + struct inode *new_entry_inode); int ocfs2_check_dir_for_entry(struct inode *dir, const char *name, diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 98aeebc2c9fa..d2f03355d127 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -933,11 +933,6 @@ static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2) ocfs2_meta_unlock(inode2, 1); } -#define PARENT_INO(buffer) \ - ((struct ocfs2_dir_entry *) \ - ((char *)buffer + \ - le16_to_cpu(((struct ocfs2_dir_entry *)buffer)->rec_len)))->inode - static int ocfs2_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, @@ -959,8 +954,8 @@ static int ocfs2_rename(struct inode *old_dir, handle_t *handle = NULL; struct buffer_head *old_dir_bh = NULL; struct buffer_head *new_dir_bh = NULL; - struct ocfs2_dir_entry *old_de = NULL, *new_de = NULL; // dirent for old_dentry - // and new_dentry + struct ocfs2_dir_entry *old_inode_dot_dot_de = NULL, *old_de = NULL, + *new_de = NULL; struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir, // this is the 1st dirent bh @@ -1044,19 +1039,26 @@ static int ocfs2_rename(struct inode *old_dir, } if (S_ISDIR(old_inode->i_mode)) { - status = -EIO; - old_inode_de_bh = ocfs2_bread(old_inode, 0, &status, 0); - if (!old_inode_de_bh) - goto bail; + u64 old_inode_parent; - status = -EIO; - if (le64_to_cpu(PARENT_INO(old_inode_de_bh->b_data)) != - OCFS2_I(old_dir)->ip_blkno) + status = ocfs2_find_files_on_disk("..", 2, &old_inode_parent, + old_inode, &old_inode_de_bh, + &old_inode_dot_dot_de); + if (status) { + status = -EIO; goto bail; - status = -EMLINK; - if (!new_inode && new_dir!=old_dir && - new_dir->i_nlink >= OCFS2_LINK_MAX) + } + + if (old_inode_parent != OCFS2_I(old_dir)->ip_blkno) { + status = -EIO; goto bail; + } + + if (!new_inode && new_dir != old_dir && + new_dir->i_nlink >= OCFS2_LINK_MAX) { + status = -EMLINK; + goto bail; + } } status = -ENOENT; @@ -1206,20 +1208,13 @@ static int ocfs2_rename(struct inode *old_dir, } /* change the dirent to point to the correct inode */ - status = ocfs2_journal_access(handle, new_dir, new_de_bh, - OCFS2_JOURNAL_ACCESS_WRITE); + status = ocfs2_update_entry(new_dir, handle, new_de_bh, + new_de, old_inode); if (status < 0) { mlog_errno(status); goto bail; } - new_de->inode = cpu_to_le64(OCFS2_I(old_inode)->ip_blkno); - new_de->file_type = old_de->file_type; new_dir->i_version++; - status = ocfs2_journal_dirty(handle, new_de_bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } if (S_ISDIR(new_inode->i_mode)) newfe->i_links_count = 0; @@ -1268,12 +1263,8 @@ static int ocfs2_rename(struct inode *old_dir, } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; if (old_inode_de_bh) { - status = ocfs2_journal_access(handle, old_inode, - old_inode_de_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - PARENT_INO(old_inode_de_bh->b_data) = - cpu_to_le64(OCFS2_I(new_dir)->ip_blkno); - status = ocfs2_journal_dirty(handle, old_inode_de_bh); + status = ocfs2_update_entry(old_inode, handle, old_inode_de_bh, + old_inode_dot_dot_de, new_dir); old_dir->i_nlink--; if (new_inode) { new_inode->i_nlink--; From 8553cf4f360d6fc4913a0bdd3b22dd7b5bb9a3be Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 13 Sep 2007 16:29:01 -0700 Subject: [PATCH 2378/2804] ocfs2: Cleanup dirent size check The check to see if a new dirent would fit in an old one is pretty ugly, and it's done at least twice. Clean things up by putting this in it's own easier-to-read function. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 31db7e3881b1..f2e2ffbf6c95 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -343,6 +343,31 @@ bail: return status; } +/* + * Check whether 'de' has enough room to hold an entry of + * 'new_rec_len' bytes. + */ +static inline int ocfs2_dirent_would_fit(struct ocfs2_dir_entry *de, + unsigned int new_rec_len) +{ + unsigned int de_really_used; + + /* Check whether this is an empty record with enough space */ + if (le64_to_cpu(de->inode) == 0 && + le16_to_cpu(de->rec_len) >= new_rec_len) + return 1; + + /* + * Record might have free space at the end which we can + * use. + */ + de_really_used = OCFS2_DIR_REC_LEN(de->name_len); + if (le16_to_cpu(de->rec_len) >= (de_really_used + new_rec_len)) + return 1; + + return 0; +} + /* we don't always have a dentry for what we want to add, so people * like orphan dir can call this instead. * @@ -385,10 +410,8 @@ int __ocfs2_add_entry(handle_t *handle, retval = -EEXIST; goto bail; } - if (((le64_to_cpu(de->inode) == 0) && - (le16_to_cpu(de->rec_len) >= rec_len)) || - (le16_to_cpu(de->rec_len) >= - (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) { + + if (ocfs2_dirent_would_fit(de, rec_len)) { dir->i_mtime = dir->i_ctime = CURRENT_TIME; retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); if (retval < 0) { @@ -1078,10 +1101,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, status = -EEXIST; goto bail; } - if (((le64_to_cpu(de->inode) == 0) && - (le16_to_cpu(de->rec_len) >= rec_len)) || - (le16_to_cpu(de->rec_len) >= - (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) { + if (ocfs2_dirent_would_fit(de, rec_len)) { /* Ok, we found a spot. Return this bh and let * the caller actually fill it in. */ *ret_de_bh = bh; From 15b1e36bdb487d67ef924a37b0967453143be53a Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 7 Sep 2007 13:58:15 -0700 Subject: [PATCH 2379/2804] ocfs2: Structure updates for inline data Add the disk, network and memory structures needed to support data in inode. Struct ocfs2_inline_data is defined and embedded in ocfs2_dinode for storing inline data. A new inode field, i_dyn_features, is added to facilitate tracking of dynamic inode state. Since it will be used often, we want to mirror it on ocfs2_inode_info, and transfer it via the meta data lvb. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dlmglue.c | 2 ++ fs/ocfs2/dlmglue.h | 4 ++-- fs/ocfs2/inode.c | 3 +++ fs/ocfs2/inode.h | 1 + fs/ocfs2/ocfs2.h | 7 +++++++ fs/ocfs2/ocfs2_fs.h | 44 ++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 57 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index f71250ed166f..41c76ff2fcfb 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -1482,6 +1482,7 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode) lvb->lvb_imtime_packed = cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime)); lvb->lvb_iattr = cpu_to_be32(oi->ip_attr); + lvb->lvb_idynfeatures = cpu_to_be16(oi->ip_dyn_features); lvb->lvb_igeneration = cpu_to_be32(inode->i_generation); out: @@ -1515,6 +1516,7 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode) i_size_write(inode, be64_to_cpu(lvb->lvb_isize)); oi->ip_attr = be32_to_cpu(lvb->lvb_iattr); + oi->ip_dyn_features = be16_to_cpu(lvb->lvb_idynfeatures); ocfs2_set_inode_flags(inode); /* fast-symlinks are a special case */ diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index 492bad32a8c0..87a785e41205 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h @@ -29,12 +29,12 @@ #include "dcache.h" -#define OCFS2_LVB_VERSION 4 +#define OCFS2_LVB_VERSION 5 struct ocfs2_meta_lvb { __u8 lvb_version; __u8 lvb_reserved0; - __be16 lvb_reserved1; + __be16 lvb_idynfeatures; __be32 lvb_iclusters; __be32 lvb_iuid; __be32 lvb_igid; diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index c53a6763bbbe..c8923bab422a 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -241,6 +241,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr); + OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features); inode->i_version = 1; inode->i_generation = le32_to_cpu(fe->i_generation); @@ -1220,6 +1221,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle, fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters); ocfs2_get_inode_flags(OCFS2_I(inode)); fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr); + fe->i_dyn_features = cpu_to_le16(OCFS2_I(inode)->ip_dyn_features); spin_unlock(&OCFS2_I(inode)->ip_lock); fe->i_size = cpu_to_le64(i_size_read(inode)); @@ -1257,6 +1259,7 @@ void ocfs2_refresh_inode(struct inode *inode, OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr); + OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features); ocfs2_set_inode_flags(inode); i_size_write(inode, le64_to_cpu(fe->i_size)); inode->i_nlink = le16_to_cpu(fe->i_links_count); diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index a41d0817121b..70e881c55536 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h @@ -51,6 +51,7 @@ struct ocfs2_inode_info u32 ip_flags; /* see below */ u32 ip_attr; /* inode attributes */ + u16 ip_dyn_features; /* protected by recovery_lock. */ struct inode *ip_next_orphan; diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 58307853fb4a..60a23e1906b0 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -319,6 +319,13 @@ static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super *osb) return 0; } +static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb) +{ + if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INLINE_DATA) + return 1; + return 0; +} + /* set / clear functions because cluster events can make these happen * in parallel so we want the transitions to be atomic. this also * means that any future flags osb_flags must be protected by spinlock diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index bf10a5453833..6ef876759a73 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -87,7 +87,8 @@ #define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB #define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \ - | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) + | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \ + | OCFS2_FEATURE_INCOMPAT_INLINE_DATA) #define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN /* @@ -121,6 +122,9 @@ */ #define OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG 0x0020 +/* Support for data packed into inode blocks */ +#define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040 + /* * backup superblock flag is used to indicate that this volume * has backup superblocks. @@ -162,6 +166,17 @@ #define OCFS2_CHAIN_FL (0x00000400) /* Chain allocator */ #define OCFS2_DEALLOC_FL (0x00000800) /* Truncate log */ +/* + * Flags on ocfs2_dinode.i_dyn_features + * + * These can change much more often than i_flags. When adding flags, + * keep in mind that i_dyn_features is only 16 bits wide. + */ +#define OCFS2_INLINE_DATA_FL (0x0001) /* Data stored in inode block */ +#define OCFS2_HAS_XATTR_FL (0x0002) +#define OCFS2_INLINE_XATTR_FL (0x0004) +#define OCFS2_INDEXED_DIR_FL (0x0008) + /* Inode attributes, keep in sync with EXT2 */ #define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */ #define OCFS2_UNRM_FL (0x00000002) /* Undelete */ @@ -486,6 +501,19 @@ struct ocfs2_local_alloc /*10*/ __u8 la_bitmap[0]; }; +/* + * Data-in-inode header. This is only used if i_dyn_features has + * OCFS2_INLINE_DATA_FL set. + */ +struct ocfs2_inline_data +{ +/*00*/ __le16 id_count; /* Number of bytes that can be used + * for data, starting at id_data */ + __le16 id_reserved0; + __le32 id_reserved1; + __u8 id_data[0]; /* Start of user data */ +}; + /* * On disk inode for OCFS2 */ @@ -518,7 +546,7 @@ struct ocfs2_dinode { __le32 i_attr; __le16 i_orphaned_slot; /* Only valid when OCFS2_ORPHANED_FL was set in i_flags */ - __le16 i_reserved1; + __le16 i_dyn_features; /*70*/ __le64 i_reserved2[8]; /*B8*/ union { __le64 i_pad1; /* Generic way to refer to this @@ -544,6 +572,7 @@ struct ocfs2_dinode { struct ocfs2_chain_list i_chain; struct ocfs2_extent_list i_list; struct ocfs2_truncate_log i_dealloc; + struct ocfs2_inline_data i_data; __u8 i_symlink[0]; } id2; /* Actual on-disk size is one block */ @@ -593,6 +622,12 @@ static inline int ocfs2_fast_symlink_chars(struct super_block *sb) offsetof(struct ocfs2_dinode, id2.i_symlink); } +static inline int ocfs2_max_inline_data(struct super_block *sb) +{ + return sb->s_blocksize - + offsetof(struct ocfs2_dinode, id2.i_data.id_data); +} + static inline int ocfs2_extent_recs_per_inode(struct super_block *sb) { int size; @@ -672,6 +707,11 @@ static inline int ocfs2_fast_symlink_chars(int blocksize) return blocksize - offsetof(struct ocfs2_dinode, id2.i_symlink); } +static inline int ocfs2_max_inline_data(int blocksize) +{ + return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data); +} + static inline int ocfs2_extent_recs_per_inode(int blocksize) { int size; From 6798d35a31c413bbb3f83bbaa844bd2598168ccc Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 7 Sep 2007 14:05:51 -0700 Subject: [PATCH 2380/2804] ocfs2: Read support for inline data This hooks up ocfs2_readpage() to populate a page with data from an inode block. Direct IO reads from inline data are modified to fall back to buffered I/O. Appropriate checks are also placed in the extent map code to avoid reading an extent list when inline data might be stored. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/aops.c | 80 ++++++++++++++++++++++++++++++++++++++++--- fs/ocfs2/extent_map.c | 6 ++++ 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 8416e383197c..fef0186a91cd 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -206,9 +206,70 @@ bail: return err; } +static int ocfs2_read_inline_data(struct inode *inode, struct page *page, + struct buffer_head *di_bh) +{ + void *kaddr; + unsigned int size; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + + if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) { + ocfs2_error(inode->i_sb, "Inode %llu lost inline data flag", + (unsigned long long)OCFS2_I(inode)->ip_blkno); + return -EROFS; + } + + size = i_size_read(inode); + + if (size > PAGE_CACHE_SIZE || + size > ocfs2_max_inline_data(inode->i_sb)) { + ocfs2_error(inode->i_sb, + "Inode %llu has with inline data has bad size: %u", + (unsigned long long)OCFS2_I(inode)->ip_blkno, size); + return -EROFS; + } + + kaddr = kmap_atomic(page, KM_USER0); + if (size) + memcpy(kaddr, di->id2.i_data.id_data, size); + /* Clear the remaining part of the page */ + memset(kaddr + size, 0, PAGE_CACHE_SIZE - size); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + + SetPageUptodate(page); + + return 0; +} + +static int ocfs2_readpage_inline(struct inode *inode, struct page *page) +{ + int ret; + struct buffer_head *di_bh = NULL; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + + BUG_ON(!PageLocked(page)); + BUG_ON(!OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); + + ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh, + OCFS2_BH_CACHED, inode); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_read_inline_data(inode, page, di_bh); +out: + unlock_page(page); + + brelse(di_bh); + return ret; +} + static int ocfs2_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; + struct ocfs2_inode_info *oi = OCFS2_I(inode); loff_t start = (loff_t)page->index << PAGE_CACHE_SHIFT; int ret, unlock = 1; @@ -222,7 +283,7 @@ static int ocfs2_readpage(struct file *file, struct page *page) goto out; } - if (down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem) == 0) { + if (down_read_trylock(&oi->ip_alloc_sem) == 0) { ret = AOP_TRUNCATED_PAGE; goto out_meta_unlock; } @@ -252,7 +313,10 @@ static int ocfs2_readpage(struct file *file, struct page *page) goto out_alloc; } - ret = block_read_full_page(page, ocfs2_get_block); + if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) + ret = ocfs2_readpage_inline(inode, page); + else + ret = block_read_full_page(page, ocfs2_get_block); unlock = 0; ocfs2_data_unlock(inode, 0); @@ -397,7 +461,9 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) down_read(&OCFS2_I(inode)->ip_alloc_sem); } - err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, NULL); + if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)) + err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, + NULL); if (!INODE_JOURNAL(inode)) { up_read(&OCFS2_I(inode)->ip_alloc_sem); @@ -411,7 +477,6 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) goto bail; } - bail: status = err ? 0 : p_blkno; @@ -566,6 +631,13 @@ static ssize_t ocfs2_direct_IO(int rw, mlog_entry_void(); + /* + * Fallback to buffered I/O if we see an inode without + * extents. + */ + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return 0; + if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { /* * We get PR data locks even for O_DIRECT. This diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index 03c1d365c78b..c58668a326fe 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c @@ -387,6 +387,12 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, struct ocfs2_extent_rec *rec; u32 coff; + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = -ERANGE; + mlog_errno(ret); + goto out; + } + ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster, num_clusters, extent_flags); if (ret == 0) From 1afc32b952335f665327a1a9001ba1b44bb76fd9 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 7 Sep 2007 14:46:51 -0700 Subject: [PATCH 2381/2804] ocfs2: Write support for inline data This fixes up write, truncate, mmap, and RESVSP/UNRESVP to understand inline inode data. For the most part, the changes to the core write code can be relied on to do the heavy lifting. Any code calling ocfs2_write_begin (including shared writeable mmap) can count on it doing the right thing with respect to growing inline data to an extent tree. Size reducing truncates, including UNRESVP can simply zero that portion of the inode block being removed. Size increasing truncatesm, including RESVP have to be a little bit smarter and grow the inode to an extent tree if necessary. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/alloc.c | 245 +++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/alloc.h | 6 ++ fs/ocfs2/aops.c | 173 +++++++++++++++++++++++++++++++- fs/ocfs2/aops.h | 4 + fs/ocfs2/file.c | 99 ++++++++++++++++-- fs/ocfs2/inode.c | 4 + fs/ocfs2/journal.h | 3 + 7 files changed, 526 insertions(+), 8 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index c81bfdfb9929..72cefe25382b 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -3726,6 +3726,8 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, struct ocfs2_insert_type insert = {0, }; struct ocfs2_extent_rec rec; + BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); + mlog(0, "add %u clusters at position %u to inode %llu\n", new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno); @@ -5826,6 +5828,174 @@ out: return ret; } +static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di) +{ + unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits; + + memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2)); +} + +void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di) +{ + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_inline_data *idata = &di->id2.i_data; + + spin_lock(&oi->ip_lock); + oi->ip_dyn_features |= OCFS2_INLINE_DATA_FL; + di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); + spin_unlock(&oi->ip_lock); + + /* + * We clear the entire i_data structure here so that all + * fields can be properly initialized. + */ + ocfs2_zero_dinode_id2(inode, di); + + idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb)); +} + +int ocfs2_convert_inline_data_to_extents(struct inode *inode, + struct buffer_head *di_bh) +{ + int ret, i, has_data, num_pages = 0; + handle_t *handle; + u64 uninitialized_var(block); + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_extent_list *el = &di->id2.i_list; + struct ocfs2_alloc_context *data_ac = NULL; + struct page **pages = NULL; + loff_t end = osb->s_clustersize; + + has_data = i_size_read(inode) ? 1 : 0; + + if (has_data) { + pages = kcalloc(ocfs2_pages_per_cluster(osb->sb), + sizeof(struct page *), GFP_NOFS); + if (pages == NULL) { + ret = -ENOMEM; + mlog_errno(ret); + goto out; + } + + ret = ocfs2_reserve_clusters(osb, 1, &data_ac); + if (ret) { + mlog_errno(ret); + goto out; + } + } + + handle = ocfs2_start_trans(osb, OCFS2_INLINE_TO_EXTENTS_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out_unlock; + } + + ret = ocfs2_journal_access(handle, inode, di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + if (has_data) { + u32 bit_off, num; + unsigned int page_end; + u64 phys; + + ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, + &num); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * Save two copies, one for insert, and one that can + * be changed by ocfs2_map_and_dirty_page() below. + */ + block = phys = ocfs2_clusters_to_blocks(inode->i_sb, bit_off); + + /* + * Non sparse file systems zero on extend, so no need + * to do that now. + */ + if (!ocfs2_sparse_alloc(osb) && + PAGE_CACHE_SIZE < osb->s_clustersize) + end = PAGE_CACHE_SIZE; + + ret = ocfs2_grab_eof_pages(inode, 0, end, pages, &num_pages); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * This should populate the 1st page for us and mark + * it up to date. + */ + ret = ocfs2_read_inline_data(inode, pages[0], di_bh); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + page_end = PAGE_CACHE_SIZE; + if (PAGE_CACHE_SIZE > osb->s_clustersize) + page_end = osb->s_clustersize; + + for (i = 0; i < num_pages; i++) + ocfs2_map_and_dirty_page(inode, handle, 0, page_end, + pages[i], i > 0, &phys); + } + + spin_lock(&oi->ip_lock); + oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL; + di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); + spin_unlock(&oi->ip_lock); + + ocfs2_zero_dinode_id2(inode, di); + + el->l_tree_depth = 0; + el->l_next_free_rec = 0; + el->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb)); + + ocfs2_journal_dirty(handle, di_bh); + + if (has_data) { + /* + * An error at this point should be extremely rare. If + * this proves to be false, we could always re-build + * the in-inode data from our pages. + */ + ret = ocfs2_insert_extent(osb, handle, inode, di_bh, + 0, block, 1, 0, NULL); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + inode->i_blocks = ocfs2_inode_sector_count(inode); + } + +out_commit: + ocfs2_commit_trans(osb, handle); + +out_unlock: + if (data_ac) + ocfs2_free_alloc_context(data_ac); + +out: + if (pages) { + ocfs2_unlock_and_free_pages(pages, num_pages); + kfree(pages); + } + + return ret; +} + /* * It is expected, that by the time you call this function, * inode->i_size and fe->i_size have been adjusted. @@ -6051,6 +6221,81 @@ bail: return status; } +/* + * 'start' is inclusive, 'end' is not. + */ +int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh, + unsigned int start, unsigned int end, int trunc) +{ + int ret; + unsigned int numbytes; + handle_t *handle; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_inline_data *idata = &di->id2.i_data; + + if (end > i_size_read(inode)) + end = i_size_read(inode); + + BUG_ON(start >= end); + + if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) || + !(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) || + !ocfs2_supports_inline_data(osb)) { + ocfs2_error(inode->i_sb, + "Inline data flags for inode %llu don't agree! " + "Disk: 0x%x, Memory: 0x%x, Superblock: 0x%x\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno, + le16_to_cpu(di->i_dyn_features), + OCFS2_I(inode)->ip_dyn_features, + osb->s_feature_incompat); + ret = -EROFS; + goto out; + } + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } + + ret = ocfs2_journal_access(handle, inode, di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + numbytes = end - start; + memset(idata->id_data + start, 0, numbytes); + + /* + * No need to worry about the data page here - it's been + * truncated already and inline data doesn't need it for + * pushing zero's to disk, so we'll let readpage pick it up + * later. + */ + if (trunc) { + i_size_write(inode, start); + di->i_size = cpu_to_le64(start); + } + + inode->i_blocks = ocfs2_inode_sector_count(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + + di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec); + di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); + + ocfs2_journal_dirty(handle, di_bh); + +out_commit: + ocfs2_commit_trans(osb, handle); + +out: + return ret; +} + static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc) { /* diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index 990df48ae8d3..826e0a6cf5c7 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h @@ -62,6 +62,10 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe) return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2; } +void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di); +int ocfs2_convert_inline_data_to_extents(struct inode *inode, + struct buffer_head *di_bh); + int ocfs2_truncate_log_init(struct ocfs2_super *osb); void ocfs2_truncate_log_shutdown(struct ocfs2_super *osb); void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb, @@ -115,6 +119,8 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_truncate_context *tc); +int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh, + unsigned int start, unsigned int end, int trunc); int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el, u32 cpos, struct buffer_head **leaf_bh); diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index fef0186a91cd..34d10452c56d 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -206,8 +206,8 @@ bail: return err; } -static int ocfs2_read_inline_data(struct inode *inode, struct page *page, - struct buffer_head *di_bh) +int ocfs2_read_inline_data(struct inode *inode, struct page *page, + struct buffer_head *di_bh) { void *kaddr; unsigned int size; @@ -1432,6 +1432,130 @@ out: return ret; } +static int ocfs2_write_begin_inline(struct address_space *mapping, + struct inode *inode, + struct ocfs2_write_ctxt *wc) +{ + int ret; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct page *page; + handle_t *handle; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)wc->w_di_bh->b_data; + + page = find_or_create_page(mapping, 0, GFP_NOFS); + if (!page) { + ret = -ENOMEM; + mlog_errno(ret); + goto out; + } + /* + * If we don't set w_num_pages then this page won't get unlocked + * and freed on cleanup of the write context. + */ + wc->w_pages[0] = wc->w_target_page = page; + wc->w_num_pages = 1; + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } + + ret = ocfs2_journal_access(handle, inode, wc->w_di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + ocfs2_commit_trans(osb, handle); + + mlog_errno(ret); + goto out; + } + + if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)) + ocfs2_set_inode_data_inline(inode, di); + + if (!PageUptodate(page)) { + ret = ocfs2_read_inline_data(inode, page, wc->w_di_bh); + if (ret) { + ocfs2_commit_trans(osb, handle); + + goto out; + } + } + + wc->w_handle = handle; +out: + return ret; +} + +int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size) +{ + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + + if (new_size < le16_to_cpu(di->id2.i_data.id_count)) + return 1; + return 0; +} + +static int ocfs2_try_to_write_inline_data(struct address_space *mapping, + struct inode *inode, loff_t pos, + unsigned len, struct page *mmap_page, + struct ocfs2_write_ctxt *wc) +{ + int ret, written = 0; + loff_t end = pos + len; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + + mlog(0, "Inode %llu, write of %u bytes at off %llu. features: 0x%x\n", + (unsigned long long)oi->ip_blkno, len, (unsigned long long)pos, + oi->ip_dyn_features); + + /* + * Handle inodes which already have inline data 1st. + */ + if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + if (mmap_page == NULL && + ocfs2_size_fits_inline_data(wc->w_di_bh, end)) + goto do_inline_write; + + /* + * The write won't fit - we have to give this inode an + * inline extent list now. + */ + ret = ocfs2_convert_inline_data_to_extents(inode, wc->w_di_bh); + if (ret) + mlog_errno(ret); + goto out; + } + + /* + * Check whether the inode can accept inline data. + */ + if (oi->ip_clusters != 0 || i_size_read(inode) != 0) + return 0; + + /* + * Check whether the write can fit. + */ + if (mmap_page || end > ocfs2_max_inline_data(inode->i_sb)) + return 0; + +do_inline_write: + ret = ocfs2_write_begin_inline(mapping, inode, wc); + if (ret) { + mlog_errno(ret); + goto out; + } + + /* + * This signals to the caller that the data can be written + * inline. + */ + written = 1; +out: + return written ? written : ret; +} + /* * This function only does anything for file systems which can't * handle sparse files. @@ -1483,6 +1607,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, return ret; } + if (ocfs2_supports_inline_data(osb)) { + ret = ocfs2_try_to_write_inline_data(mapping, inode, pos, len, + mmap_page, wc); + if (ret == 1) { + ret = 0; + goto success; + } + if (ret < 0) { + mlog_errno(ret); + goto out; + } + } + ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc); if (ret) { mlog_errno(ret); @@ -1570,6 +1707,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, if (meta_ac) ocfs2_free_alloc_context(meta_ac); +success: *pagep = wc->w_target_page; *fsdata = wc; return 0; @@ -1637,6 +1775,31 @@ out_fail: return ret; } +static void ocfs2_write_end_inline(struct inode *inode, loff_t pos, + unsigned len, unsigned *copied, + struct ocfs2_dinode *di, + struct ocfs2_write_ctxt *wc) +{ + void *kaddr; + + if (unlikely(*copied < len)) { + if (!PageUptodate(wc->w_target_page)) { + *copied = 0; + return; + } + } + + kaddr = kmap_atomic(wc->w_target_page, KM_USER0); + memcpy(di->id2.i_data.id_data + pos, kaddr + pos, *copied); + kunmap_atomic(kaddr, KM_USER0); + + mlog(0, "Data written to inode at offset %llu. " + "id_count = %u, copied = %u, i_dyn_features = 0x%x\n", + (unsigned long long)pos, *copied, + le16_to_cpu(di->id2.i_data.id_count), + le16_to_cpu(di->i_dyn_features)); +} + int ocfs2_write_end_nolock(struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) @@ -1650,6 +1813,11 @@ int ocfs2_write_end_nolock(struct address_space *mapping, handle_t *handle = wc->w_handle; struct page *tmppage; + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ocfs2_write_end_inline(inode, pos, len, &copied, di, wc); + goto out_write_size; + } + if (unlikely(copied < len)) { if (!PageUptodate(wc->w_target_page)) copied = 0; @@ -1687,6 +1855,7 @@ int ocfs2_write_end_nolock(struct address_space *mapping, block_commit_write(tmppage, from, to); } +out_write_size: pos += copied; if (pos > inode->i_size) { i_size_write(inode, pos); diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index b4fa37d40db4..113560877dbb 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h @@ -61,6 +61,10 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, struct page **pagep, void **fsdata, struct buffer_head *di_bh, struct page *mmap_page); +int ocfs2_read_inline_data(struct inode *inode, struct page *page, + struct buffer_head *di_bh); +int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size); + /* all ocfs2_dio_end_io()'s fault */ #define ocfs2_iocb_is_rw_locked(iocb) \ test_bit(0, (unsigned long *)&iocb->private) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 781ba6c4ef85..a62b14eb4065 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -397,6 +397,15 @@ static int ocfs2_truncate_file(struct inode *inode, unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1); truncate_inode_pages(inode->i_mapping, new_i_size); + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + status = ocfs2_truncate_inline(inode, di_bh, new_i_size, + i_size_read(inode), 0); + if (status) + mlog_errno(status); + + goto bail_unlock_data; + } + /* alright, we're going to need to do a full blown alloc size * change. Orphan the inode so that recovery can complete the * truncate if necessary. This does the task of marking @@ -908,7 +917,8 @@ static int ocfs2_extend_file(struct inode *inode, struct buffer_head *di_bh, u64 new_i_size) { - int ret = 0; + int ret = 0, data_locked = 0; + struct ocfs2_inode_info *oi = OCFS2_I(inode); BUG_ON(!di_bh); @@ -920,7 +930,17 @@ static int ocfs2_extend_file(struct inode *inode, goto out; BUG_ON(new_i_size < i_size_read(inode)); - if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) + /* + * Fall through for converting inline data, even if the fs + * supports sparse files. + * + * The check for inline data here is legal - nobody can add + * the feature since we have i_mutex. We must check it again + * after acquiring ip_alloc_sem though, as paths like mmap + * might have raced us to converting the inode to extents. + */ + if (!(oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) + && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) goto out_update_size; /* @@ -935,6 +955,7 @@ static int ocfs2_extend_file(struct inode *inode, mlog_errno(ret); goto out; } + data_locked = 1; /* * The alloc sem blocks people in read/write from reading our @@ -942,9 +963,31 @@ static int ocfs2_extend_file(struct inode *inode, * i_mutex to block other extend/truncate calls while we're * here. */ - down_write(&OCFS2_I(inode)->ip_alloc_sem); - ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size); - up_write(&OCFS2_I(inode)->ip_alloc_sem); + down_write(&oi->ip_alloc_sem); + + if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + /* + * We can optimize small extends by keeping the inodes + * inline data. + */ + if (ocfs2_size_fits_inline_data(di_bh, new_i_size)) { + up_write(&oi->ip_alloc_sem); + goto out_update_size; + } + + ret = ocfs2_convert_inline_data_to_extents(inode, di_bh); + if (ret) { + up_write(&oi->ip_alloc_sem); + + mlog_errno(ret); + goto out_unlock; + } + } + + if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) + ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size); + + up_write(&oi->ip_alloc_sem); if (ret < 0) { mlog_errno(ret); @@ -957,7 +1000,7 @@ out_update_size: mlog_errno(ret); out_unlock: - if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) + if (data_locked) ocfs2_data_unlock(inode, 1); out: @@ -1231,6 +1274,31 @@ static int ocfs2_allocate_unwritten_extents(struct inode *inode, { int ret; u32 cpos, phys_cpos, clusters, alloc_size; + u64 end = start + len; + struct buffer_head *di_bh = NULL; + + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), + OCFS2_I(inode)->ip_blkno, &di_bh, + OCFS2_BH_CACHED, inode); + if (ret) { + mlog_errno(ret); + goto out; + } + + /* + * Nothing to do if the requested reservation range + * fits within the inode. + */ + if (ocfs2_size_fits_inline_data(di_bh, end)) + goto out; + + ret = ocfs2_convert_inline_data_to_extents(inode, di_bh); + if (ret) { + mlog_errno(ret); + goto out; + } + } /* * We consider both start and len to be inclusive. @@ -1276,6 +1344,8 @@ next: ret = 0; out: + + brelse(di_bh); return ret; } @@ -1457,6 +1527,14 @@ static int ocfs2_remove_inode_range(struct inode *inode, if (byte_len == 0) return 0; + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = ocfs2_truncate_inline(inode, di_bh, byte_start, + byte_start + byte_len, 1); + if (ret) + mlog_errno(ret); + return ret; + } + trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start); trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits; if (trunc_len >= trunc_start) @@ -1758,6 +1836,15 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, if (!direct_io || !(*direct_io)) break; + /* + * There's no sane way to do direct writes to an inode + * with inline data. + */ + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + *direct_io = 0; + break; + } + /* * Allowing concurrent direct writes means * i_size changes wouldn't be synchronized, so diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index c8923bab422a..1d5e0cb0fda1 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -514,6 +514,10 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb, fe = (struct ocfs2_dinode *) fe_bh->b_data; + /* + * This check will also skip truncate of inodes with inline + * data and fast symlinks. + */ if (fe->i_clusters) { handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index ce60aab013aa..4b32e0961568 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -282,6 +282,9 @@ int ocfs2_journal_dirty_data(handle_t *handle, * prev. group desc. if we relink. */ #define OCFS2_SUBALLOC_ALLOC (3) +#define OCFS2_INLINE_TO_EXTENTS_CREDITS (OCFS2_SUBALLOC_ALLOC \ + + OCFS2_INODE_UPDATE_CREDITS) + /* dinode + group descriptor update. We don't relink on free yet. */ #define OCFS2_SUBALLOC_FREE (2) From 23193e513d1cd69411469f028d56fd175d4a6b07 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Wed, 12 Sep 2007 13:01:18 -0700 Subject: [PATCH 2382/2804] ocfs2: Read support for directories with inline data This splits out extent based directory read support and implements inline-data versions of those functions. All knowledge of inline-data versus extent based directories is internalized. For lookups the code uses ocfs2_find_entry_id(), full dir iterations make use of ocfs2_dir_foreach_blk_id(). Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/dir.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 168 insertions(+), 8 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index f2e2ffbf6c95..8deed89330c7 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -81,6 +81,10 @@ static int ocfs2_do_extend_dir(struct super_block *sb, struct ocfs2_alloc_context *meta_ac, struct buffer_head **new_bh); +/* + * bh passed here can be an inode block or a dir data block, depending + * on the inode inline data flag. + */ static int ocfs2_check_dir_entry(struct inode * dir, struct ocfs2_dir_entry * de, struct buffer_head * bh, @@ -125,6 +129,8 @@ static int inline ocfs2_search_dirblock(struct buffer_head *bh, struct inode *dir, const char *name, int namelen, unsigned long offset, + char *first_de, + unsigned int bytes, struct ocfs2_dir_entry **res_dir) { struct ocfs2_dir_entry *de; @@ -134,8 +140,8 @@ static int inline ocfs2_search_dirblock(struct buffer_head *bh, mlog_entry_void(); - de_buf = bh->b_data; - dlimit = de_buf + dir->i_sb->s_blocksize; + de_buf = first_de; + dlimit = de_buf + bytes; while (de_buf < dlimit) { /* this code is executed quadratically often */ @@ -171,9 +177,39 @@ bail: return ret; } -struct buffer_head *ocfs2_find_entry(const char *name, int namelen, - struct inode *dir, - struct ocfs2_dir_entry **res_dir) +static struct buffer_head *ocfs2_find_entry_id(const char *name, + int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir) +{ + int ret, found; + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + + ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno, + &di_bh, OCFS2_BH_CACHED, dir); + if (ret) { + mlog_errno(ret); + goto out; + } + + di = (struct ocfs2_dinode *)di_bh->b_data; + data = &di->id2.i_data; + + found = ocfs2_search_dirblock(di_bh, dir, name, namelen, 0, + data->id_data, i_size_read(dir), res_dir); + if (found == 1) + return di_bh; + + brelse(di_bh); +out: + return NULL; +} + +struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir) { struct super_block *sb; struct buffer_head *bh_use[NAMEI_RA_SIZE]; @@ -188,7 +224,6 @@ struct buffer_head *ocfs2_find_entry(const char *name, int namelen, mlog_entry_void(); - *res_dir = NULL; sb = dir->i_sb; nblocks = i_size_read(dir) >> sb->s_blocksize_bits; @@ -236,6 +271,7 @@ restart: } i = ocfs2_search_dirblock(bh, dir, name, namelen, block << sb->s_blocksize_bits, + bh->b_data, sb->s_blocksize, res_dir); if (i == 1) { OCFS2_I(dir)->ip_dir_start_lookup = block; @@ -271,6 +307,30 @@ cleanup_and_exit: return ret; } +/* + * Try to find an entry of the provided name within 'dir'. + * + * If nothing was found, NULL is returned. Otherwise, a buffer_head + * and pointer to the dir entry are passed back. + * + * Caller can NOT assume anything about the contents of the + * buffer_head - it is passed back only so that it can be passed into + * any one of the manipulation functions (add entry, delete entry, + * etc). As an example, bh in the extent directory case is a data + * block, in the inline-data case it actually points to an inode. + */ +struct buffer_head *ocfs2_find_entry(const char *name, int namelen, + struct inode *dir, + struct ocfs2_dir_entry **res_dir) +{ + *res_dir = NULL; + + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return ocfs2_find_entry_id(name, namelen, dir, res_dir); + + return ocfs2_find_entry_el(name, namelen, dir, res_dir); +} + int ocfs2_update_entry(struct inode *dir, handle_t *handle, struct buffer_head *de_bh, struct ocfs2_dir_entry *de, struct inode *new_entry_inode) @@ -459,8 +519,98 @@ bail: return retval; } -static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, - loff_t *f_pos, void *priv, filldir_t filldir) +static int ocfs2_dir_foreach_blk_id(struct inode *inode, + unsigned long *f_version, + loff_t *f_pos, void *priv, + filldir_t filldir) +{ + int ret, i, filldir_ret; + unsigned long offset = *f_pos; + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + struct ocfs2_dir_entry *de; + + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, + &di_bh, OCFS2_BH_CACHED, inode); + if (ret) { + mlog(ML_ERROR, "Unable to read inode block for dir %llu\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno); + goto out; + } + + di = (struct ocfs2_dinode *)di_bh->b_data; + data = &di->id2.i_data; + + while (*f_pos < i_size_read(inode)) { +revalidate: + /* If the dir block has changed since the last call to + * readdir(2), then we might be pointing to an invalid + * dirent right now. Scan from the start of the block + * to make sure. */ + if (*f_version != inode->i_version) { + for (i = 0; i < i_size_read(inode) && i < offset; ) { + de = (struct ocfs2_dir_entry *) + (data->id_data + i); + /* It's too expensive to do a full + * dirent test each time round this + * loop, but we do have to test at + * least that it is non-zero. A + * failure will be detected in the + * dirent test below. */ + if (le16_to_cpu(de->rec_len) < + OCFS2_DIR_REC_LEN(1)) + break; + i += le16_to_cpu(de->rec_len); + } + *f_pos = offset = i; + *f_version = inode->i_version; + } + + de = (struct ocfs2_dir_entry *) (data->id_data + *f_pos); + if (!ocfs2_check_dir_entry(inode, de, di_bh, *f_pos)) { + /* On error, skip the f_pos to the end. */ + *f_pos = i_size_read(inode); + goto out; + } + offset += le16_to_cpu(de->rec_len); + if (le64_to_cpu(de->inode)) { + /* We might block in the next section + * if the data destination is + * currently swapped out. So, use a + * version stamp to detect whether or + * not the directory has been modified + * during the copy operation. + */ + unsigned long version = *f_version; + unsigned char d_type = DT_UNKNOWN; + + if (de->file_type < OCFS2_FT_MAX) + d_type = ocfs2_filetype_table[de->file_type]; + + filldir_ret = filldir(priv, de->name, + de->name_len, + *f_pos, + le64_to_cpu(de->inode), + d_type); + if (filldir_ret) + break; + if (version != *f_version) + goto revalidate; + } + *f_pos += le16_to_cpu(de->rec_len); + } + +out: + brelse(di_bh); + + return 0; +} + +static int ocfs2_dir_foreach_blk_el(struct inode *inode, + unsigned long *f_version, + loff_t *f_pos, void *priv, + filldir_t filldir) { int error = 0; unsigned long offset, blk, last_ra_blk = 0; @@ -576,6 +726,16 @@ out: return stored; } +static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, + loff_t *f_pos, void *priv, filldir_t filldir) +{ + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv, + filldir); + + return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir); +} + /* * This is intended to be called from inside other kernel functions, * so we fake some arguments. From 5b6a3a2b4a5f071d170f8122038dd647a84810a8 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 13 Sep 2007 16:33:54 -0700 Subject: [PATCH 2383/2804] ocfs2: Write support for directories with inline data Create all new directories with OCFS2_INLINE_DATA_FL and the inline data bytes formatted as an empty directory. Inode size field reflects the actual amount of inline data available, which makes searching for dirent space very similar to the regular directory search. Inline-data directories are automatically pushed out to extents on any insert request which is too large for the available space. Signed-off-by: Mark Fasheh Reviewed-by: Joel Becker --- fs/ocfs2/alloc.c | 16 +- fs/ocfs2/alloc.h | 1 + fs/ocfs2/dir.c | 620 +++++++++++++++++++++++++++++++++++++++++------ fs/ocfs2/namei.c | 57 +++-- 4 files changed, 595 insertions(+), 99 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 72cefe25382b..4ba7f0bdc248 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -5835,6 +5835,15 @@ static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di) memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2)); } +void ocfs2_dinode_new_extent_list(struct inode *inode, + struct ocfs2_dinode *di) +{ + ocfs2_zero_dinode_id2(inode, di); + di->id2.i_list.l_tree_depth = 0; + di->id2.i_list.l_next_free_rec = 0; + di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb)); +} + void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di) { struct ocfs2_inode_info *oi = OCFS2_I(inode); @@ -5863,7 +5872,6 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode, struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; - struct ocfs2_extent_list *el = &di->id2.i_list; struct ocfs2_alloc_context *data_ac = NULL; struct page **pages = NULL; loff_t end = osb->s_clustersize; @@ -5956,11 +5964,7 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode, di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); spin_unlock(&oi->ip_lock); - ocfs2_zero_dinode_id2(inode, di); - - el->l_tree_depth = 0; - el->l_next_free_rec = 0; - el->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb)); + ocfs2_dinode_new_extent_list(inode, di); ocfs2_journal_dirty(handle, di_bh); diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index 826e0a6cf5c7..42ff94bd8011 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h @@ -62,6 +62,7 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe) return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2; } +void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di); void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di); int ocfs2_convert_inline_data_to_extents(struct inode *inode, struct buffer_head *di_bh); diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 8deed89330c7..e15351338417 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -72,6 +72,7 @@ static unsigned char ocfs2_filetype_table[] = { static int ocfs2_extend_dir(struct ocfs2_super *osb, struct inode *dir, struct buffer_head *parent_fe_bh, + unsigned int blocks_wanted, struct buffer_head **new_de_bh); static int ocfs2_do_extend_dir(struct super_block *sb, handle_t *handle, @@ -331,12 +332,20 @@ struct buffer_head *ocfs2_find_entry(const char *name, int namelen, return ocfs2_find_entry_el(name, namelen, dir, res_dir); } +/* + * Update inode number and type of a previously found directory entry. + */ int ocfs2_update_entry(struct inode *dir, handle_t *handle, struct buffer_head *de_bh, struct ocfs2_dir_entry *de, struct inode *new_entry_inode) { int ret; + /* + * The same code works fine for both inline-data and extent + * based directories, so no need to split this up. + */ + ret = ocfs2_journal_access(handle, dir, de_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { @@ -353,14 +362,10 @@ out: return ret; } -/* - * ocfs2_delete_entry deletes a directory entry by merging it with the - * previous entry - */ -int ocfs2_delete_entry(handle_t *handle, - struct inode *dir, - struct ocfs2_dir_entry *de_del, - struct buffer_head *bh) +static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh, char *first_de, + unsigned int bytes) { struct ocfs2_dir_entry *de, *pde; int i, status = -ENOENT; @@ -369,8 +374,8 @@ int ocfs2_delete_entry(handle_t *handle, i = 0; pde = NULL; - de = (struct ocfs2_dir_entry *) bh->b_data; - while (i < bh->b_size) { + de = (struct ocfs2_dir_entry *) first_de; + while (i < bytes) { if (!ocfs2_check_dir_entry(dir, de, bh, i)) { status = -EIO; mlog_errno(status); @@ -403,6 +408,58 @@ bail: return status; } +static inline int ocfs2_delete_entry_id(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh) +{ + int ret; + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + + ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno, + &di_bh, OCFS2_BH_CACHED, dir); + if (ret) { + mlog_errno(ret); + goto out; + } + + di = (struct ocfs2_dinode *)di_bh->b_data; + data = &di->id2.i_data; + + ret = __ocfs2_delete_entry(handle, dir, de_del, bh, data->id_data, + i_size_read(dir)); + + brelse(di_bh); +out: + return ret; +} + +static inline int ocfs2_delete_entry_el(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh) +{ + return __ocfs2_delete_entry(handle, dir, de_del, bh, bh->b_data, + bh->b_size); +} + +/* + * ocfs2_delete_entry deletes a directory entry by merging it with the + * previous entry + */ +int ocfs2_delete_entry(handle_t *handle, + struct inode *dir, + struct ocfs2_dir_entry *de_del, + struct buffer_head *bh) +{ + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return ocfs2_delete_entry_id(handle, dir, de_del, bh); + + return ocfs2_delete_entry_el(handle, dir, de_del, bh); +} + /* * Check whether 'de' has enough room to hold an entry of * 'new_rec_len' bytes. @@ -444,21 +501,30 @@ int __ocfs2_add_entry(handle_t *handle, unsigned long offset; unsigned short rec_len; struct ocfs2_dir_entry *de, *de1; - struct super_block *sb; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)parent_fe_bh->b_data; + struct super_block *sb = dir->i_sb; int retval, status; + unsigned int size = sb->s_blocksize; + char *data_start = insert_bh->b_data; mlog_entry_void(); - sb = dir->i_sb; - if (!namelen) return -EINVAL; + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + data_start = di->id2.i_data.id_data; + size = i_size_read(dir); + + BUG_ON(insert_bh != parent_fe_bh); + } + rec_len = OCFS2_DIR_REC_LEN(namelen); offset = 0; - de = (struct ocfs2_dir_entry *) insert_bh->b_data; + de = (struct ocfs2_dir_entry *) data_start; while (1) { - BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data); + BUG_ON((char *)de >= (size + data_start)); + /* These checks should've already been passed by the * prepare function, but I guess we can leave them * here anyway. */ @@ -939,16 +1005,78 @@ int ocfs2_empty_dir(struct inode *inode) return !priv.seen_other; } -int ocfs2_fill_new_dir(struct ocfs2_super *osb, - handle_t *handle, - struct inode *parent, - struct inode *inode, - struct buffer_head *fe_bh, - struct ocfs2_alloc_context *data_ac) +static void ocfs2_fill_initial_dirents(struct inode *inode, + struct inode *parent, + char *start, unsigned int size) +{ + struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start; + + de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); + de->name_len = 1; + de->rec_len = + cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); + strcpy(de->name, "."); + ocfs2_set_de_type(de, S_IFDIR); + + de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len)); + de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno); + de->rec_len = cpu_to_le16(size - OCFS2_DIR_REC_LEN(1)); + de->name_len = 2; + strcpy(de->name, ".."); + ocfs2_set_de_type(de, S_IFDIR); +} + +/* + * This works together with code in ocfs2_mknod_locked() which sets + * the inline-data flag and initializes the inline-data section. + */ +static int ocfs2_fill_new_dir_id(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *di_bh) +{ + int ret; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_inline_data *data = &di->id2.i_data; + unsigned int size = le16_to_cpu(data->id_count); + + ret = ocfs2_journal_access(handle, inode, di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out; + } + + ocfs2_fill_initial_dirents(inode, parent, data->id_data, size); + + ocfs2_journal_dirty(handle, di_bh); + if (ret) { + mlog_errno(ret); + goto out; + } + + i_size_write(inode, size); + inode->i_nlink = 2; + inode->i_blocks = ocfs2_inode_sector_count(inode); + + ret = ocfs2_mark_inode_dirty(handle, inode, di_bh); + if (ret < 0) + mlog_errno(ret); + +out: + return ret; +} + +static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *fe_bh, + struct ocfs2_alloc_context *data_ac) { int status; struct buffer_head *new_bh = NULL; - struct ocfs2_dir_entry *de = NULL; mlog_entry_void(); @@ -969,20 +1097,8 @@ int ocfs2_fill_new_dir(struct ocfs2_super *osb, } memset(new_bh->b_data, 0, osb->sb->s_blocksize); - de = (struct ocfs2_dir_entry *) new_bh->b_data; - de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); - de->name_len = 1; - de->rec_len = - cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); - strcpy(de->name, "."); - ocfs2_set_de_type(de, S_IFDIR); - de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len)); - de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno); - de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - - OCFS2_DIR_REC_LEN(1)); - de->name_len = 2; - strcpy(de->name, ".."); - ocfs2_set_de_type(de, S_IFDIR); + ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data, + osb->sb->s_blocksize); status = ocfs2_journal_dirty(handle, new_bh); if (status < 0) { @@ -1008,6 +1124,230 @@ bail: return status; } +int ocfs2_fill_new_dir(struct ocfs2_super *osb, + handle_t *handle, + struct inode *parent, + struct inode *inode, + struct buffer_head *fe_bh, + struct ocfs2_alloc_context *data_ac) +{ + BUG_ON(!ocfs2_supports_inline_data(osb) && data_ac == NULL); + + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + return ocfs2_fill_new_dir_id(osb, handle, parent, inode, fe_bh); + + return ocfs2_fill_new_dir_el(osb, handle, parent, inode, fe_bh, + data_ac); +} + +static void ocfs2_expand_last_dirent(char *start, unsigned int old_size, + unsigned int new_size) +{ + struct ocfs2_dir_entry *de; + struct ocfs2_dir_entry *prev_de; + char *de_buf, *limit; + unsigned int bytes = new_size - old_size; + + limit = start + old_size; + de_buf = start; + de = (struct ocfs2_dir_entry *)de_buf; + do { + prev_de = de; + de_buf += le16_to_cpu(de->rec_len); + de = (struct ocfs2_dir_entry *)de_buf; + } while (de_buf < limit); + + le16_add_cpu(&prev_de->rec_len, bytes); +} + +/* + * We allocate enough clusters to fulfill "blocks_wanted", but set + * i_size to exactly one block. Ocfs2_extend_dir() will handle the + * rest automatically for us. + * + * *first_block_bh is a pointer to the 1st data block allocated to the + * directory. + */ +static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, + unsigned int blocks_wanted, + struct buffer_head **first_block_bh) +{ + int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS; + u32 alloc, bit_off, len; + struct super_block *sb = dir->i_sb; + u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits; + struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); + struct ocfs2_inode_info *oi = OCFS2_I(dir); + struct ocfs2_alloc_context *data_ac; + struct buffer_head *dirdata_bh = NULL; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + handle_t *handle; + + alloc = ocfs2_clusters_for_bytes(sb, bytes); + + /* + * We should never need more than 2 clusters for this - + * maximum dirent size is far less than one block. In fact, + * the only time we'd need more than one cluster is if + * blocksize == clustersize and the dirent won't fit in the + * extra space that the expansion to a single block gives. As + * of today, that only happens on 4k/4k file systems. + */ + BUG_ON(alloc > 2); + + ret = ocfs2_reserve_clusters(osb, alloc, &data_ac); + if (ret) { + mlog_errno(ret); + goto out; + } + + down_write(&oi->ip_alloc_sem); + + /* + * Prepare for worst case allocation scenario of two seperate + * extents. + */ + if (alloc == 2) + credits += OCFS2_SUBALLOC_ALLOC; + + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out_sem; + } + + /* + * Try to claim as many clusters as the bitmap can give though + * if we only get one now, that's enough to continue. The rest + * will be claimed after the conversion to extents. + */ + ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * Operations are carefully ordered so that we set up the new + * data block first. The conversion from inline data to + * extents follows. + */ + blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); + dirdata_bh = sb_getblk(sb, blkno); + if (!dirdata_bh) { + ret = -EIO; + mlog_errno(ret); + goto out_commit; + } + + ocfs2_set_new_buffer_uptodate(dir, dirdata_bh); + + ret = ocfs2_journal_access(handle, dir, dirdata_bh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir)); + memset(dirdata_bh->b_data + i_size_read(dir), 0, + sb->s_blocksize - i_size_read(dir)); + ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir), + sb->s_blocksize); + + ret = ocfs2_journal_dirty(handle, dirdata_bh); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * Set extent, i_size, etc on the directory. After this, the + * inode should contain the same exact dirents as before and + * be fully accessible from system calls. + * + * We let the later dirent insert modify c/mtime - to the user + * the data hasn't changed. + */ + ret = ocfs2_journal_access(handle, dir, di_bh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + spin_lock(&oi->ip_lock); + oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL; + di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); + spin_unlock(&oi->ip_lock); + + ocfs2_dinode_new_extent_list(dir, di); + + i_size_write(dir, sb->s_blocksize); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + + di->i_size = cpu_to_le64(sb->s_blocksize); + di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec); + di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec); + dir->i_blocks = ocfs2_inode_sector_count(dir); + + /* + * This should never fail as our extent list is empty and all + * related blocks have been journaled already. + */ + ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0, + NULL); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_journal_dirty(handle, di_bh); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * We asked for two clusters, but only got one in the 1st + * pass. Claim the 2nd cluster as a separate extent. + */ + if (alloc > len) { + ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, + &len); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); + + ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno, + len, 0, NULL); + if (ret) { + mlog_errno(ret); + goto out; + } + } + + *first_block_bh = dirdata_bh; + dirdata_bh = NULL; + +out_commit: + ocfs2_commit_trans(osb, handle); + +out_sem: + up_write(&oi->ip_alloc_sem); + +out: + if (data_ac) + ocfs2_free_alloc_context(data_ac); + + brelse(dirdata_bh); + + return ret; +} + /* returns a bh of the 1st new block in the allocation. */ static int ocfs2_do_extend_dir(struct super_block *sb, handle_t *handle, @@ -1057,10 +1397,18 @@ bail: return status; } -/* assumes you already have a cluster lock on the directory. */ +/* + * Assumes you already have a cluster lock on the directory. + * + * 'blocks_wanted' is only used if we have an inline directory which + * is to be turned into an extent based one. The size of the dirent to + * insert might be larger than the space gained by growing to just one + * block, so we may have to grow the inode by two blocks in that case. + */ static int ocfs2_extend_dir(struct ocfs2_super *osb, struct inode *dir, struct buffer_head *parent_fe_bh, + unsigned int blocks_wanted, struct buffer_head **new_de_bh) { int status = 0; @@ -1076,6 +1424,38 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, mlog_entry_void(); + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + status = ocfs2_expand_inline_dir(dir, parent_fe_bh, + blocks_wanted, &new_bh); + if (status) { + mlog_errno(status); + goto bail; + } + + if (blocks_wanted == 1) { + /* + * If the new dirent will fit inside the space + * created by pushing out to one block, then + * we can complete the operation + * here. Otherwise we have to expand i_size + * and format the 2nd block below. + */ + BUG_ON(new_bh == NULL); + goto bail_bh; + } + + /* + * Get rid of 'new_bh' - we want to format the 2nd + * data block and return that instead. + */ + brelse(new_bh); + new_bh = NULL; + + dir_i_size = i_size_read(dir); + credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; + goto do_extend; + } + dir_i_size = i_size_read(dir); mlog(0, "extending dir %llu (i_size = %lld)\n", (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size); @@ -1113,6 +1493,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; } +do_extend: down_write(&OCFS2_I(dir)->ip_alloc_sem); drop_alloc_sem = 1; @@ -1158,6 +1539,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, goto bail; } +bail_bh: *new_de_bh = new_bh; get_bh(*new_de_bh); bail: @@ -1178,42 +1560,72 @@ bail: return status; } -/* - * Search the dir for a good spot, extending it if necessary. The - * block containing an appropriate record is returned in ret_de_bh. - */ -int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, - struct inode *dir, - struct buffer_head *parent_fe_bh, - const char *name, - int namelen, - struct buffer_head **ret_de_bh) +static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh, + const char *name, int namelen, + struct buffer_head **ret_de_bh, + unsigned int *blocks_wanted) +{ + int ret; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_dir_entry *de, *last_de = NULL; + char *de_buf, *limit; + unsigned long offset = 0; + unsigned int rec_len, new_rec_len; + + de_buf = di->id2.i_data.id_data; + limit = de_buf + i_size_read(dir); + rec_len = OCFS2_DIR_REC_LEN(namelen); + + while (de_buf < limit) { + de = (struct ocfs2_dir_entry *)de_buf; + + if (!ocfs2_check_dir_entry(dir, de, di_bh, offset)) { + ret = -ENOENT; + goto out; + } + if (ocfs2_match(namelen, name, de)) { + ret = -EEXIST; + goto out; + } + if (ocfs2_dirent_would_fit(de, rec_len)) { + /* Ok, we found a spot. Return this bh and let + * the caller actually fill it in. */ + *ret_de_bh = di_bh; + get_bh(*ret_de_bh); + ret = 0; + goto out; + } + + last_de = de; + de_buf += le16_to_cpu(de->rec_len); + offset += le16_to_cpu(de->rec_len); + } + + /* + * We're going to require expansion of the directory - figure + * out how many blocks we'll need so that a place for the + * dirent can be found. + */ + *blocks_wanted = 1; + new_rec_len = le16_to_cpu(last_de->rec_len) + (dir->i_sb->s_blocksize - i_size_read(dir)); + if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len))) + *blocks_wanted = 2; + + ret = -ENOSPC; +out: + return ret; +} + +static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, + int namelen, struct buffer_head **ret_de_bh) { unsigned long offset; - struct buffer_head * bh = NULL; + struct buffer_head *bh = NULL; unsigned short rec_len; - struct ocfs2_dinode *fe; struct ocfs2_dir_entry *de; - struct super_block *sb; + struct super_block *sb = dir->i_sb; int status; - mlog_entry_void(); - - mlog(0, "getting ready to insert namelen %d into dir %llu\n", - namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno); - - BUG_ON(!S_ISDIR(dir->i_mode)); - fe = (struct ocfs2_dinode *) parent_fe_bh->b_data; - BUG_ON(le64_to_cpu(fe->i_size) != i_size_read(dir)); - - sb = dir->i_sb; - - if (!namelen) { - status = -EINVAL; - mlog_errno(status); - goto bail; - } - bh = ocfs2_bread(dir, 0, &status, 0); if (!bh) { mlog_errno(status); @@ -1229,17 +1641,11 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, bh = NULL; if (i_size_read(dir) <= offset) { - status = ocfs2_extend_dir(osb, - dir, - parent_fe_bh, - &bh); - if (status < 0) { - mlog_errno(status); - goto bail; - } - BUG_ON(!bh); - *ret_de_bh = bh; - get_bh(*ret_de_bh); + /* + * Caller will have to expand this + * directory. + */ + status = -ENOSPC; goto bail; } bh = ocfs2_bread(dir, @@ -1281,3 +1687,61 @@ bail: mlog_exit(status); return status; } + +int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, + struct inode *dir, + struct buffer_head *parent_fe_bh, + const char *name, + int namelen, + struct buffer_head **ret_de_bh) +{ + int ret; + unsigned int blocks_wanted = 1; + struct buffer_head *bh = NULL; + + mlog(0, "getting ready to insert namelen %d into dir %llu\n", + namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno); + + *ret_de_bh = NULL; + + if (!namelen) { + ret = -EINVAL; + mlog_errno(ret); + goto out; + } + + if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = ocfs2_find_dir_space_id(dir, parent_fe_bh, name, + namelen, &bh, &blocks_wanted); + } else + ret = ocfs2_find_dir_space_el(dir, name, namelen, &bh); + + if (ret && ret != -ENOSPC) { + mlog_errno(ret); + goto out; + } + + if (ret == -ENOSPC) { + /* + * We have to expand the directory to add this name. + */ + BUG_ON(bh); + + ret = ocfs2_extend_dir(osb, dir, parent_fe_bh, blocks_wanted, + &bh); + if (ret) { + if (ret != -ENOSPC) + mlog_errno(ret); + goto out; + } + + BUG_ON(!bh); + } + + *ret_de_bh = bh; + bh = NULL; +out: + if (bh) + brelse(bh); + return ret; +} diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index d2f03355d127..729259016c18 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -250,9 +250,8 @@ static int ocfs2_mknod(struct inode *dir, goto leave; } - /* are we making a directory? If so, reserve a cluster for his - * 1st extent. */ - if (S_ISDIR(mode)) { + /* Reserve a cluster if creating an extent based directory. */ + if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) { status = ocfs2_reserve_clusters(osb, 1, &data_ac); if (status < 0) { if (status != -ENOSPC) @@ -449,10 +448,21 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, cpu_to_le32(CURRENT_TIME.tv_nsec); fe->i_dtime = 0; - fel = &fe->id2.i_list; - fel->l_tree_depth = 0; - fel->l_next_free_rec = 0; - fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb)); + /* + * If supported, directories start with inline data. + */ + if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) { + u16 feat = le16_to_cpu(fe->i_dyn_features); + + fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL); + + fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb)); + } else { + fel = &fe->id2.i_list; + fel->l_tree_depth = 0; + fel->l_next_free_rec = 0; + fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb)); + } status = ocfs2_journal_dirty(handle, *new_fe_bh); if (status < 0) { @@ -950,7 +960,7 @@ static int ocfs2_rename(struct inode *old_dir, struct buffer_head *old_inode_bh = NULL; struct buffer_head *insert_entry_bh = NULL; struct ocfs2_super *osb = NULL; - u64 newfe_blkno; + u64 newfe_blkno, old_de_ino; handle_t *handle = NULL; struct buffer_head *old_dir_bh = NULL; struct buffer_head *new_dir_bh = NULL; @@ -1061,12 +1071,13 @@ static int ocfs2_rename(struct inode *old_dir, } } - status = -ENOENT; - old_de_bh = ocfs2_find_entry(old_dentry->d_name.name, - old_dentry->d_name.len, - old_dir, &old_de); - if (!old_de_bh) + status = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name, + old_dentry->d_name.len, + &old_de_ino); + if (status) { + status = -ENOENT; goto bail; + } /* * Check for inode number is _not_ due to possible IO errors. @@ -1074,8 +1085,10 @@ static int ocfs2_rename(struct inode *old_dir, * and merrily kill the link to whatever was created under the * same name. Goodbye sticky bit ;-< */ - if (le64_to_cpu(old_de->inode) != OCFS2_I(old_inode)->ip_blkno) + if (old_de_ino != OCFS2_I(old_inode)->ip_blkno) { + status = -ENOENT; goto bail; + } /* check if the target already exists (in which case we need * to delete it */ @@ -1250,7 +1263,21 @@ static int ocfs2_rename(struct inode *old_dir, } else mlog_errno(status); - /* now that the name has been added to new_dir, remove the old name */ + /* + * Now that the name has been added to new_dir, remove the old name. + * + * We don't keep any directory entry context around until now + * because the insert might have changed the type of directory + * we're dealing with. + */ + old_de_bh = ocfs2_find_entry(old_dentry->d_name.name, + old_dentry->d_name.len, + old_dir, &old_de); + if (!old_de_bh) { + status = -EIO; + goto bail; + } + status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh); if (status < 0) { mlog_errno(status); From e7b34019606ab1dd06196635e931b0c302799228 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Mon, 24 Sep 2007 14:25:27 -0700 Subject: [PATCH 2384/2804] ocfs2: Optionally return filldir errors Modify ocfs2_dir_foreach_blk() to optionally return any error from the filldir callback. This way ocfs2_dirforeach() can terminate early, as opposed to always passing through the entire directory. This fixes a bug introduced during a previous code refactor where ocfs2_empty_dir() would loop infinitely. Signed-off-by: Mark Fasheh --- fs/ocfs2/dir.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index e15351338417..7453b70c1a19 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -588,7 +588,7 @@ bail: static int ocfs2_dir_foreach_blk_id(struct inode *inode, unsigned long *f_version, loff_t *f_pos, void *priv, - filldir_t filldir) + filldir_t filldir, int *filldir_err) { int ret, i, filldir_ret; unsigned long offset = *f_pos; @@ -659,8 +659,11 @@ revalidate: *f_pos, le64_to_cpu(de->inode), d_type); - if (filldir_ret) + if (filldir_ret) { + if (filldir_err) + *filldir_err = filldir_ret; break; + } if (version != *f_version) goto revalidate; } @@ -676,7 +679,7 @@ out: static int ocfs2_dir_foreach_blk_el(struct inode *inode, unsigned long *f_version, loff_t *f_pos, void *priv, - filldir_t filldir) + filldir_t filldir, int *filldir_err) { int error = 0; unsigned long offset, blk, last_ra_blk = 0; @@ -775,8 +778,11 @@ revalidate: *f_pos, le64_to_cpu(de->inode), d_type); - if (error) + if (error) { + if (filldir_err) + *filldir_err = error; break; + } if (version != *f_version) goto revalidate; stored ++; @@ -793,13 +799,15 @@ out: } static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, - loff_t *f_pos, void *priv, filldir_t filldir) + loff_t *f_pos, void *priv, filldir_t filldir, + int *filldir_err) { if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv, - filldir); + filldir, filldir_err); - return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir); + return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir, + filldir_err); } /* @@ -809,16 +817,19 @@ static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, filldir_t filldir) { - int ret = 0; + int ret = 0, filldir_err = 0; unsigned long version = inode->i_version; while (*f_pos < i_size_read(inode)) { ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv, - filldir); - if (ret) + filldir, &filldir_err); + if (ret || filldir_err) break; } + if (ret > 0) + ret = -EIO; + return 0; } @@ -852,7 +863,7 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) } error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos, - dirent, filldir); + dirent, filldir, NULL); ocfs2_meta_unlock(inode, lock_level); From 640fdb504941fa2b9f6f274716fc9f97f2bf6bff Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 3 Aug 2007 11:10:07 -0400 Subject: [PATCH 2385/2804] [libata] pdc_adma: convert to new exception handling (EH) framework Signed-off-by: Jeff Garzik --- drivers/ata/pdc_adma.c | 84 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 5c79271401af..c95c1bf7df37 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -92,6 +92,8 @@ enum { /* CPB bits */ cDONE = (1 << 0), + cATERR = (1 << 3), + cVLD = (1 << 0), cDAT = (1 << 2), cIEN = (1 << 3), @@ -131,14 +133,15 @@ static int adma_ata_init_one (struct pci_dev *pdev, static int adma_port_start(struct ata_port *ap); static void adma_host_stop(struct ata_host *host); static void adma_port_stop(struct ata_port *ap); -static void adma_phy_reset(struct ata_port *ap); static void adma_qc_prep(struct ata_queued_cmd *qc); static unsigned int adma_qc_issue(struct ata_queued_cmd *qc); static int adma_check_atapi_dma(struct ata_queued_cmd *qc); static void adma_bmdma_stop(struct ata_queued_cmd *qc); static u8 adma_bmdma_status(struct ata_port *ap); static void adma_irq_clear(struct ata_port *ap); -static void adma_eng_timeout(struct ata_port *ap); +static void adma_freeze(struct ata_port *ap); +static void adma_thaw(struct ata_port *ap); +static void adma_error_handler(struct ata_port *ap); static struct scsi_host_template adma_ata_sht = { .module = THIS_MODULE, @@ -165,12 +168,13 @@ static const struct ata_port_operations adma_ata_ops = { .exec_command = ata_exec_command, .check_status = ata_check_status, .dev_select = ata_std_dev_select, - .phy_reset = adma_phy_reset, .check_atapi_dma = adma_check_atapi_dma, .data_xfer = ata_data_xfer, .qc_prep = adma_qc_prep, .qc_issue = adma_qc_issue, - .eng_timeout = adma_eng_timeout, + .freeze = adma_freeze, + .thaw = adma_thaw, + .error_handler = adma_error_handler, .irq_clear = adma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -184,7 +188,7 @@ static const struct ata_port_operations adma_ata_ops = { static struct ata_port_info adma_port_info[] = { /* board_1841_idx */ { - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ @@ -273,24 +277,41 @@ static inline void adma_enter_reg_mode(struct ata_port *ap) readb(chan + ADMA_STATUS); /* flush */ } -static void adma_phy_reset(struct ata_port *ap) +static void adma_freeze(struct ata_port *ap) { - struct adma_port_priv *pp = ap->private_data; + void __iomem *chan = ADMA_PORT_REGS(ap); - pp->state = adma_state_idle; - adma_reinit_engine(ap); - ata_port_probe(ap); - ata_bus_reset(ap); + /* mask/clear ATA interrupts */ + writeb(ATA_NIEN, ap->ioaddr.ctl_addr); + ata_check_status(ap); + + /* reset ADMA to idle state */ + writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); + udelay(2); + writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL); + udelay(2); } -static void adma_eng_timeout(struct ata_port *ap) +static void adma_thaw(struct ata_port *ap) +{ + adma_reinit_engine(ap); +} + +static int adma_prereset(struct ata_port *ap, unsigned long deadline) { struct adma_port_priv *pp = ap->private_data; if (pp->state != adma_state_idle) /* healthy paranoia */ pp->state = adma_state_mmio; adma_reinit_engine(ap); - ata_eng_timeout(ap); + + return ata_std_prereset(ap, deadline); +} + +static void adma_error_handler(struct ata_port *ap) +{ + ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL, + ata_std_postreset); } static int adma_fill_sg(struct ata_queued_cmd *qc) @@ -466,12 +487,31 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) continue; qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { - if ((status & (aPERR | aPSD | aUIRQ))) + if (status & aPERR) + qc->err_mask |= AC_ERR_HOST_BUS; + else if ((status & (aPSD | aUIRQ))) qc->err_mask |= AC_ERR_OTHER; + + if (pp->pkt[0] & cATERR) + qc->err_mask |= AC_ERR_DEV; else if (pp->pkt[0] != cDONE) qc->err_mask |= AC_ERR_OTHER; - ata_qc_complete(qc); + if (!qc->err_mask) + ata_qc_complete(qc); + else { + struct ata_eh_info *ehi = &ap->eh_info; + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, + "ADMA-status 0x%02X", status); + ata_ehi_push_desc(ehi, + "pkt[0] 0x%02X", pp->pkt[0]); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } } } return handled; @@ -502,7 +542,19 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) /* complete taskfile transaction */ pp->state = adma_state_idle; qc->err_mask |= ac_err_mask(status); - ata_qc_complete(qc); + if (!qc->err_mask) + ata_qc_complete(qc); + else { + struct ata_eh_info *ehi = &ap->eh_info; + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, + "status 0x%02X", status); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } handled = 1; } } From 9af5c9c97dc9d599281778864c72b385f0c63341 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:22 +0900 Subject: [PATCH 2386/2804] libata-link: introduce ata_link Introduce ata_link. It abstracts PHY and sits between ata_port and ata_device. This new level of abstraction is necessary to support SATA Port Multiplier, which basically adds a bunch of links (PHYs) to a ATA host port. Fields related to command execution, spd_limit and EH are per-link and thus moved to ata_link. This patch only defines the host link. Multiple link handling will be added later. Also, a lot of ap->link derefences are added but many of them will be removed as each part is converted to deal directly with ata_link instead of ata_port. This patch introduces no behavior change. Signed-off-by: Tejun Heo Cc: James Bottomley Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 18 ++-- drivers/ata/ata_generic.c | 2 +- drivers/ata/libata-acpi.c | 21 ++--- drivers/ata/libata-core.c | 157 ++++++++++++++++++---------------- drivers/ata/libata-eh.c | 100 +++++++++++----------- drivers/ata/libata-scsi.c | 41 ++++----- drivers/ata/libata-sff.c | 4 +- drivers/ata/pata_it821x.c | 4 +- drivers/ata/pata_ixp4xx_cf.c | 4 +- drivers/ata/pata_legacy.c | 4 +- drivers/ata/pata_optidma.c | 4 +- drivers/ata/pata_pcmcia.c | 4 +- drivers/ata/pata_pdc2027x.c | 2 +- drivers/ata/pata_platform.c | 2 +- drivers/ata/pata_qdi.c | 2 +- drivers/ata/pata_rz1000.c | 2 +- drivers/ata/pata_scc.c | 2 +- drivers/ata/pata_sis.c | 2 +- drivers/ata/pata_winbond.c | 2 +- drivers/ata/pdc_adma.c | 9 +- drivers/ata/sata_inic162x.c | 7 +- drivers/ata/sata_mv.c | 14 +-- drivers/ata/sata_nv.c | 26 +++--- drivers/ata/sata_promise.c | 6 +- drivers/ata/sata_qstor.c | 4 +- drivers/ata/sata_sil.c | 14 +-- drivers/ata/sata_sil24.c | 14 +-- drivers/ata/sata_sx4.c | 4 +- drivers/ata/sata_via.c | 2 +- drivers/ata/sata_vsc.c | 2 +- drivers/scsi/ipr.c | 6 +- drivers/scsi/libsas/sas_ata.c | 10 +-- include/linux/libata.h | 40 +++++---- 33 files changed, 280 insertions(+), 255 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c16820325d7b..c72fa468a697 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1064,7 +1064,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, ata_port_printk(ap, KERN_WARNING, "failed to reset engine (errno=%d)", rc); - ata_tf_init(ap->device, &tf); + ata_tf_init(ap->link.device, &tf); /* issue the first D2H Register FIS */ msecs = 0; @@ -1132,7 +1132,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ - ata_tf_init(ap->device, &tf); + ata_tf_init(ap->link.device, &tf); tf.command = 0x80; ata_tf_to_fis(&tf, 0, 0, d2h_fis); @@ -1159,7 +1159,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); - rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context), + rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->link.eh_context), deadline); /* vt8251 needs SError cleared for the port to operate */ @@ -1278,7 +1278,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { struct ahci_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned int err_mask = 0, action = 0; struct ata_queued_cmd *qc; u32 serror; @@ -1332,7 +1332,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) ehi->serror |= serror; ehi->action |= action; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) qc->err_mask |= err_mask; else @@ -1347,7 +1347,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) static void ahci_port_intr(struct ata_port *ap) { void __iomem *port_mmio = ap->ioaddr.cmd_addr; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; struct ahci_port_priv *pp = ap->private_data; u32 status, qc_active; int rc, known_irq = 0; @@ -1360,7 +1360,7 @@ static void ahci_port_intr(struct ata_port *ap) return; } - if (ap->sactive) + if (ap->link.sactive) qc_active = readl(port_mmio + PORT_SCR_ACT); else qc_active = readl(port_mmio + PORT_CMD_ISSUE); @@ -1380,7 +1380,7 @@ static void ahci_port_intr(struct ata_port *ap) /* if !NCQ, ignore. No modern ATA device has broken HSM * implementation for non-NCQ commands. */ - if (!ap->sactive) + if (!ap->link.sactive) return; if (status & PORT_IRQ_D2H_REG_FIS) { @@ -1433,7 +1433,7 @@ static void ahci_port_intr(struct ata_port *ap) if (!known_irq) ata_port_printk(ap, KERN_INFO, "spurious interrupt " "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n", - status, ap->active_tag, ap->sactive); + status, ap->link.active_tag, ap->link.sactive); } static void ahci_irq_clear(struct ata_port *ap) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 945466954724..b5e390ff5bd8 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -53,7 +53,7 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index c059f78ad944..0023ac4ff496 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -44,7 +44,8 @@ static void ata_acpi_associate_sata_port(struct ata_port *ap) { acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); - ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr); + ap->link.device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); } static void ata_acpi_associate_ide_port(struct ata_port *ap) @@ -60,7 +61,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) max_devices++; for (i = 0; i < max_devices; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); } @@ -182,10 +183,10 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) /* Buffers for id may need byteswapping ? */ in_params[1].type = ACPI_TYPE_BUFFER; in_params[1].buffer.length = 512; - in_params[1].buffer.pointer = (u8 *)ap->device[0].id; + in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id; in_params[2].type = ACPI_TYPE_BUFFER; in_params[2].buffer.length = 512; - in_params[2].buffer.pointer = (u8 *)ap->device[1].id; + in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id; input.count = 3; input.pointer = in_params; @@ -226,7 +227,7 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, void **ptr_to_free) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; acpi_status status; struct acpi_buffer output; union acpi_object *out_obj; @@ -320,7 +321,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, static int taskfile_load_raw(struct ata_device *dev, const struct ata_acpi_gtf *gtf) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf, rtf; unsigned int err_mask; @@ -424,7 +425,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev) */ static int ata_acpi_push_id(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; int err; acpi_status status; struct acpi_object_list input; @@ -519,7 +520,7 @@ void ata_acpi_on_resume(struct ata_port *ap) /* schedule _GTF */ for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING; + ap->link.device[i].flags |= ATA_DFLAG_ACPI_PENDING; } /** @@ -538,8 +539,8 @@ void ata_acpi_on_resume(struct ata_port *ap) */ int ata_acpi_on_devcfg(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &ap->link.eh_context; int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; int rc; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 772be09b4689..dd2de485124a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -235,7 +235,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev) if (dev->flags & ATA_DFLAG_PIO) { tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; - } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) { + } else if (lba48 && (dev->link->ap->flags & ATA_FLAG_PIO_LBA48)) { /* Unable to use DMA due to host limitation */ tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; @@ -604,7 +604,7 @@ static const char *sata_spd_string(unsigned int spd) void ata_dev_disable(struct ata_device *dev) { if (ata_dev_enabled(dev)) { - if (ata_msg_drv(dev->ap)) + if (ata_msg_drv(dev->link->ap)) ata_dev_printk(dev, KERN_WARNING, "disabled\n"); ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); @@ -735,7 +735,7 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) /* see if device passed diags: if master then continue and warn later */ if (err == 0 && device == 0) /* diagnostic fail : do nothing _YET_ */ - ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC; + ap->link.device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC; else if (err == 1) /* do nothing */ ; else if ((device == 0) && (err == 0x81)) @@ -1150,7 +1150,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, ap->ops->dev_select(ap, device); if (wait) { - if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI) + if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI) msleep(150); ata_wait_idle(ap); } @@ -1346,7 +1346,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, int dma_dir, struct scatterlist *sg, unsigned int n_elem) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; u8 command = tf->command; struct ata_queued_cmd *qc; unsigned int tag, preempted_tag; @@ -1386,11 +1387,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, qc->dev = dev; ata_qc_reinit(qc); - preempted_tag = ap->active_tag; - preempted_sactive = ap->sactive; + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; preempted_qc_active = ap->qc_active; - ap->active_tag = ATA_TAG_POISON; - ap->sactive = 0; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; ap->qc_active = 0; /* prepare & issue qc */ @@ -1467,8 +1468,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, err_mask = qc->err_mask; ata_qc_free(qc); - ap->active_tag = preempted_tag; - ap->sactive = preempted_sactive; + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; ap->qc_active = preempted_qc_active; /* XXX - Some LLDDs (sata_mv) disable port on command failure. @@ -1566,7 +1567,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) { /* Controller doesn't support IORDY. Probably a pointless check as the caller should know this */ - if (adev->ap->flags & ATA_FLAG_NO_IORDY) + if (adev->link->ap->flags & ATA_FLAG_NO_IORDY) return 0; /* PIO3 and higher it is mandatory */ if (adev->pio_mode > XFER_PIO_2) @@ -1622,7 +1623,7 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; unsigned int class = *p_class; struct ata_taskfile tf; unsigned int err_mask = 0; @@ -1774,13 +1775,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, static inline u8 ata_dev_knobble(struct ata_device *dev) { - return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); + struct ata_port *ap = dev->link->ap; + return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } static void ata_dev_config_ncq(struct ata_device *dev, char *desc, size_t desc_sz) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; int hdepth = 0, ddepth = ata_id_queue_depth(dev->id); if (!ata_id_has_ncq(dev->id)) { @@ -1817,8 +1819,8 @@ static void ata_dev_config_ncq(struct ata_device *dev, */ int ata_dev_configure(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &dev->link->eh_context; int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned int xfer_mask; @@ -2116,7 +2118,7 @@ int ata_bus_probe(struct ata_port *ap) ap->ops->phy_reset(ap); for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!(ap->flags & ATA_FLAG_DISABLED) && dev->class != ATA_DEV_UNKNOWN) @@ -2133,14 +2135,14 @@ int ata_bus_probe(struct ata_port *ap) state is undefined. Record the mode */ for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].pio_mode = XFER_PIO_0; + ap->link.device[i].pio_mode = XFER_PIO_0; /* read IDENTIFY page and configure devices. We have to do the identify specific sequence bass-ackwards so that PDIAG- is released by the slave device */ for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (tries[i]) dev->class = classes[i]; @@ -2162,13 +2164,13 @@ int ata_bus_probe(struct ata_port *ap) this in the normal order so that the user doesn't get confused */ for(i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev)) continue; - ap->eh_context.i.flags |= ATA_EHI_PRINTINFO; + ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO; rc = ata_dev_configure(dev); - ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO; + ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO; if (rc) goto fail; } @@ -2179,7 +2181,7 @@ int ata_bus_probe(struct ata_port *ap) goto fail; for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->device[i])) + if (ata_dev_enabled(&ap->link.device[i])) return 0; /* no device present, disable port */ @@ -2344,8 +2346,8 @@ void sata_phy_reset(struct ata_port *ap) struct ata_device *ata_dev_pair(struct ata_device *adev) { - struct ata_port *ap = adev->ap; - struct ata_device *pair = &ap->device[1 - adev->devno]; + struct ata_link *link = adev->link; + struct ata_device *pair = &link->device[1 - adev->devno]; if (!ata_dev_enabled(pair)) return NULL; return pair; @@ -2366,8 +2368,8 @@ struct ata_device *ata_dev_pair(struct ata_device *adev) void ata_port_disable(struct ata_port *ap) { - ap->device[0].class = ATA_DEV_NONE; - ap->device[1].class = ATA_DEV_NONE; + ap->link.device[0].class = ATA_DEV_NONE; + ap->link.device[1].class = ATA_DEV_NONE; ap->flags |= ATA_FLAG_DISABLED; } @@ -2400,9 +2402,9 @@ int sata_down_spd_limit(struct ata_port *ap) if (rc == 0) spd = (sstatus >> 4) & 0xf; else - spd = ap->sata_spd; + spd = ap->link.sata_spd; - mask = ap->sata_spd_limit; + mask = ap->link.sata_spd_limit; if (mask <= 1) return -EINVAL; @@ -2422,7 +2424,7 @@ int sata_down_spd_limit(struct ata_port *ap) if (!mask) return -EINVAL; - ap->sata_spd_limit = mask; + ap->link.sata_spd_limit = mask; ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n", sata_spd_string(fls(mask))); @@ -2434,10 +2436,10 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) { u32 spd, limit; - if (ap->sata_spd_limit == UINT_MAX) + if (ap->link.sata_spd_limit == UINT_MAX) limit = 0; else - limit = fls(ap->sata_spd_limit); + limit = fls(ap->link.sata_spd_limit); spd = (*scontrol >> 4) & 0xf; *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4); @@ -2450,7 +2452,7 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) * @ap: Port in question * * Test whether the spd limit in SControl matches - * @ap->sata_spd_limit. This function is used to determine + * @ap->link.sata_spd_limit. This function is used to determine * whether hardreset is necessary to apply SATA spd * configuration. * @@ -2749,7 +2751,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) static int ata_dev_set_mode(struct ata_device *dev) { - struct ata_eh_context *ehc = &dev->ap->eh_context; + struct ata_eh_context *ehc = &dev->link->eh_context; unsigned int err_mask; int rc; @@ -2809,7 +2811,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) for (i = 0; i < ATA_MAX_DEVICES; i++) { unsigned int pio_mask, dma_mask; - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev)) continue; @@ -2830,7 +2832,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /* step 2: always set host PIO timings */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev)) continue; @@ -2848,7 +2850,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /* step 3: set host DMA timings */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev) || !dev->dma_mode) continue; @@ -2861,7 +2863,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /* step 4: update devices' xfer mode */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; /* don't update suspended devices' xfer mode */ if (!ata_dev_enabled(dev)) @@ -3142,6 +3144,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, void ata_bus_reset(struct ata_port *ap) { + struct ata_device *device = ap->link.device; struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; u8 err; @@ -3177,19 +3180,19 @@ void ata_bus_reset(struct ata_port *ap) /* * determine by signature whether we have ATA or ATAPI devices */ - ap->device[0].class = ata_dev_try_classify(ap, 0, &err); + device[0].class = ata_dev_try_classify(ap, 0, &err); if ((slave_possible) && (err != 0x81)) - ap->device[1].class = ata_dev_try_classify(ap, 1, &err); + device[1].class = ata_dev_try_classify(ap, 1, &err); /* is double-select really necessary? */ - if (ap->device[1].class != ATA_DEV_NONE) + if (device[1].class != ATA_DEV_NONE) ap->ops->dev_select(ap, 1); - if (ap->device[0].class != ATA_DEV_NONE) + if (device[0].class != ATA_DEV_NONE) ap->ops->dev_select(ap, 0); /* if no devices were detected, disable this port */ - if ((ap->device[0].class == ATA_DEV_NONE) && - (ap->device[1].class == ATA_DEV_NONE)) + if ((device[0].class == ATA_DEV_NONE) && + (device[1].class == ATA_DEV_NONE)) goto err_out; if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { @@ -3331,7 +3334,7 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params, */ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; @@ -3503,7 +3506,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, int sata_std_hardreset(struct ata_port *ap, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + const unsigned long *timing = sata_ehc_deb_timing(&ap->link.eh_context); int rc; DPRINTK("ENTER\n"); @@ -3652,7 +3655,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) { unsigned int class = dev->class; - u16 *id = (void *)dev->ap->sector_buf; + u16 *id = (void *)dev->link->ap->sector_buf; int rc; /* read ID data */ @@ -3837,7 +3840,7 @@ static int ata_dma_blacklisted(const struct ata_device *dev) * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) * if the LLDD handles only interrupts in the HSM_ST_LAST state. */ - if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && + if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) && (dev->flags & ATA_DFLAG_CDB_INTR)) return 1; return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0; @@ -3857,7 +3860,8 @@ static int ata_dma_blacklisted(const struct ata_device *dev) */ static void ata_dev_xfermask(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; struct ata_host *host = ap->host; unsigned long xfer_mask; @@ -4482,7 +4486,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) void ata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; /* Transfer multiple of 2 bytes */ @@ -5188,7 +5192,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_queued_cmd *qc; qc = ata_qc_new(ap); @@ -5231,6 +5235,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) void __ata_qc_complete(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); @@ -5240,9 +5245,9 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) /* command should be marked inactive atomically with qc completion */ if (qc->tf.protocol == ATA_PROT_NCQ) - ap->sactive &= ~(1 << qc->tag); + link->sactive &= ~(1 << qc->tag); else - ap->active_tag = ATA_TAG_POISON; + link->active_tag = ATA_TAG_POISON; /* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler @@ -5411,19 +5416,20 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc) void ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; /* Make sure only one non-NCQ command is outstanding. The * check is skipped for old EH because it reuses active qc to * request ATAPI sense. */ - WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag)); + WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag)); if (qc->tf.protocol == ATA_PROT_NCQ) { - WARN_ON(ap->sactive & (1 << qc->tag)); - ap->sactive |= 1 << qc->tag; + WARN_ON(link->sactive & (1 << qc->tag)); + link->sactive |= 1 << qc->tag; } else { - WARN_ON(ap->sactive); - ap->active_tag = qc->tag; + WARN_ON(link->sactive); + link->active_tag = qc->tag; } qc->flags |= ATA_QCFLAG_ACTIVE; @@ -5606,7 +5612,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) inline unsigned int ata_host_intr (struct ata_port *ap, struct ata_queued_cmd *qc) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; u8 status, host_stat = 0; VPRINTK("ata%u: protocol %d task_state %d\n", @@ -5721,7 +5727,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && (qc->flags & ATA_QCFLAG_ACTIVE)) handled |= ata_host_intr(ap, qc); @@ -5921,8 +5927,8 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, } ap->pflags |= ATA_PFLAG_PM_PENDING; - ap->eh_info.action |= action; - ap->eh_info.flags |= ehi_flags; + ap->link.eh_info.action |= action; + ap->link.eh_info.flags |= ehi_flags; ata_port_schedule_eh(ap); @@ -6026,12 +6032,13 @@ int ata_port_start(struct ata_port *ap) */ void ata_dev_init(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; unsigned long flags; /* SATA spd limit is bound to the first device */ - ap->sata_spd_limit = ap->hw_sata_spd_limit; - ap->sata_spd = 0; + link->sata_spd_limit = link->hw_sata_spd_limit; + link->sata_spd = 0; /* High bits of dev->flags are used to record warm plug * requests which occur asynchronously. Synchronize using @@ -6080,8 +6087,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->host = host; ap->dev = host->dev; - ap->hw_sata_spd_limit = UINT_MAX; - ap->active_tag = ATA_TAG_POISON; + ap->link.hw_sata_spd_limit = UINT_MAX; + ap->link.active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; #if defined(ATA_VERBOSE_DEBUG) @@ -6104,9 +6111,11 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->cbl = ATA_CBL_NONE; + ap->link.ap = ap; + for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; - dev->ap = ap; + struct ata_device *dev = &ap->link.device[i]; + dev->link = &ap->link; dev->devno = i; ata_dev_init(dev); } @@ -6402,9 +6411,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { int spd = (scontrol >> 4) & 0xf; if (spd) - ap->hw_sata_spd_limit &= (1 << spd) - 1; + ap->link.hw_sata_spd_limit &= (1 << spd) - 1; } - ap->sata_spd_limit = ap->hw_sata_spd_limit; + ap->link.sata_spd_limit = ap->link.hw_sata_spd_limit; /* report the secondary IRQ for second channel legacy */ irq_line = host->irq; @@ -6436,7 +6445,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* probe */ if (ap->ops->error_handler) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned long flags; ata_port_probe(ap); @@ -6560,7 +6569,7 @@ void ata_port_detach(struct ata_port *ap) spin_lock_irqsave(ap->lock, flags); for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->device[i]); + ata_dev_disable(&ap->link.device[i]); spin_unlock_irqrestore(ap->lock, flags); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index ac6ceed4bb60..e2681f56ed44 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -195,7 +195,7 @@ static int ata_ering_map(struct ata_ering *ering, static unsigned int ata_eh_dev_action(struct ata_device *dev) { - struct ata_eh_context *ehc = &dev->ap->eh_context; + struct ata_eh_context *ehc = &dev->link->eh_context; return ehc->i.action | ehc->i.dev_action[dev->devno]; } @@ -261,7 +261,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) ret = EH_HANDLED; spin_lock_irqsave(ap->lock, flags); - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) { WARN_ON(qc->scsicmd != cmd); qc->flags |= ATA_QCFLAG_EH_SCHEDULED; @@ -371,9 +371,9 @@ void ata_scsi_error(struct Scsi_Host *host) /* fetch & clear EH info */ spin_lock_irqsave(ap->lock, flags); - memset(&ap->eh_context, 0, sizeof(ap->eh_context)); - ap->eh_context.i = ap->eh_info; - memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + memset(&ap->link.eh_context, 0, sizeof(ap->link.eh_context)); + ap->link.eh_context.i = ap->link.eh_info; + memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info)); ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; ap->pflags &= ~ATA_PFLAG_EH_PENDING; @@ -409,7 +409,7 @@ void ata_scsi_error(struct Scsi_Host *host) } /* this run is complete, make sure EH info is clear */ - memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info)); /* Clear host_eh_scheduled while holding ap->lock such * that if exception occurs after this point but @@ -420,7 +420,7 @@ void ata_scsi_error(struct Scsi_Host *host) spin_unlock_irqrestore(ap->lock, flags); } else { - WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); + WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); ap->ops->eng_timeout(ap); } @@ -575,7 +575,7 @@ void ata_eng_timeout(struct ata_port *ap) { DPRINTK("ENTER\n"); - ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag)); + ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag)); DPRINTK("EXIT\n"); } @@ -922,7 +922,7 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) */ static void ata_eh_detach_dev(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; unsigned long flags; ata_dev_disable(dev); @@ -937,8 +937,8 @@ static void ata_eh_detach_dev(struct ata_device *dev) } /* clear per-dev EH actions */ - ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK); - ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(dev, &dev->link->eh_info, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(dev, &dev->link->eh_context.i, ATA_EH_PERDEV_MASK); spin_unlock_irqrestore(ap->lock, flags); } @@ -950,8 +950,8 @@ static void ata_eh_detach_dev(struct ata_device *dev) * @action: action about to be performed * * Called just before performing EH actions to clear related bits - * in @ap->eh_info such that eh actions are not unnecessarily - * repeated. + * in @ap->link.eh_info such that eh actions are not + * unnecessarily repeated. * * LOCKING: * None. @@ -960,8 +960,8 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, unsigned int action) { unsigned long flags; - struct ata_eh_info *ehi = &ap->eh_info; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_info *ehi = &ap->link.eh_info; + struct ata_eh_context *ehc = &ap->link.eh_context; spin_lock_irqsave(ap->lock, flags); @@ -993,7 +993,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, * @action: action just completed * * Called right after performing EH actions to clear related bits - * in @ap->eh_context. + * in @ap->link.eh_context. * * LOCKING: * None. @@ -1001,13 +1001,15 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, unsigned int action) { + struct ata_eh_context *ehc = &ap->link.eh_context; + /* if reset is complete, clear all reset actions & reset modifier */ if (action & ATA_EH_RESET_MASK) { action |= ATA_EH_RESET_MASK; - ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(dev, &ap->eh_context.i, action); + ata_eh_clear_action(dev, &ehc->i, action); } /** @@ -1101,7 +1103,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev, static int ata_eh_read_log_10h(struct ata_device *dev, int *tag, struct ata_taskfile *tf) { - u8 *buf = dev->ap->sector_buf; + u8 *buf = dev->link->ap->sector_buf; unsigned int err_mask; u8 csum; int i; @@ -1155,7 +1157,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) { struct ata_device *dev = qc->dev; unsigned char *sense_buf = qc->scsicmd->sense_buffer; - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf; u8 cdb[ATAPI_CDB_LEN]; @@ -1206,7 +1208,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) */ static void ata_eh_analyze_serror(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; u32 serror = ehc->i.serror; unsigned int err_mask = 0, action = 0; @@ -1248,8 +1250,8 @@ static void ata_eh_analyze_serror(struct ata_port *ap) */ static void ata_eh_analyze_ncq_error(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; - struct ata_device *dev = ap->device; + struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_device *dev = ap->link.device; struct ata_queued_cmd *qc; struct ata_taskfile tf; int tag, rc; @@ -1259,7 +1261,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) return; /* is it NCQ device error? */ - if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV)) + if (!ap->link.sactive || !(ehc->i.err_mask & AC_ERR_DEV)) return; /* has LLDD analyzed already? */ @@ -1281,7 +1283,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) return; } - if (!(ap->sactive & (1 << tag))) { + if (!(ap->link.sactive & (1 << tag))) { ata_port_printk(ap, KERN_ERR, "log page 10h reported " "inactive tag %d\n", tag); return; @@ -1497,7 +1499,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, /* speed down? */ if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ - if (sata_down_spd_limit(dev->ap) == 0) { + if (sata_down_spd_limit(dev->link->ap) == 0) { action |= ATA_EH_HARDRESET; goto done; } @@ -1528,7 +1530,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, * SATA. Consider it only for PATA. */ if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) && - (dev->ap->cbl != ATA_CBL_SATA) && + (dev->link->ap->cbl != ATA_CBL_SATA) && (dev->xfer_shift != ATA_SHIFT_PIO)) { if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) { dev->spdn_cnt = 0; @@ -1557,7 +1559,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, */ static void ata_eh_autopsy(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; unsigned int all_err_mask = 0; int tag, is_io = 0; u32 serror; @@ -1656,7 +1658,7 @@ static void ata_eh_autopsy(struct ata_port *ap) */ static void ata_eh_report(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; const char *frozen, *desc; int tag, nr_failed = 0; @@ -1685,15 +1687,15 @@ static void ata_eh_report(struct ata_port *ap) if (ehc->i.dev) { ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->sactive, ehc->i.serror, - ehc->i.action, frozen); + ehc->i.err_mask, ap->link.sactive, + ehc->i.serror, ehc->i.action, frozen); if (desc) ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->sactive, ehc->i.serror, - ehc->i.action, frozen); + ehc->i.err_mask, ap->link.sactive, + ehc->i.serror, ehc->i.action, frozen); if (desc) ata_port_printk(ap, KERN_ERR, "%s\n", desc); } @@ -1775,7 +1777,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); int try = 0; @@ -1804,7 +1806,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, if (rc == -ENOENT) { ata_port_printk(ap, KERN_DEBUG, "port disabled. ignoring.\n"); - ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; + ehc->i.action &= ~ATA_EH_RESET_MASK; for (i = 0; i < ATA_MAX_DEVICES; i++) classes[i] = ATA_DEV_NONE; @@ -1907,11 +1909,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify, * controller state is undefined. Record the mode. */ for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].pio_mode = XFER_PIO_0; + ap->link.device[i].pio_mode = XFER_PIO_0; /* record current link speed */ if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0) - ap->sata_spd = (sstatus >> 4) & 0xf; + ap->link.sata_spd = (sstatus >> 4) & 0xf; if (postreset) postreset(ap, classes); @@ -1929,7 +1931,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, static int ata_eh_revalidate_and_attach(struct ata_port *ap, struct ata_device **r_failed_dev) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; struct ata_device *dev; unsigned int new_mask = 0; unsigned long flags; @@ -1944,7 +1946,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { unsigned int action, readid_flags = 0; - dev = &ap->device[i]; + dev = &ap->link.device[i]; action = ata_eh_dev_action(dev); if (ehc->i.flags & ATA_EHI_DID_RESET) @@ -2004,7 +2006,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, * device detection messages backwards. */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!(new_mask & (1 << i))) continue; @@ -2036,7 +2038,7 @@ static int ata_port_nr_enabled(struct ata_port *ap) int i, cnt = 0; for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->device[i])) + if (ata_dev_enabled(&ap->link.device[i])) cnt++; return cnt; } @@ -2046,14 +2048,14 @@ static int ata_port_nr_vacant(struct ata_port *ap) int i, cnt = 0; for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ap->device[i].class == ATA_DEV_UNKNOWN) + if (ap->link.device[i].class == ATA_DEV_UNKNOWN) cnt++; return cnt; } static int ata_eh_skip_recovery(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; int i; /* thaw frozen port, resume link and recover failed devices */ @@ -2063,7 +2065,7 @@ static int ata_eh_skip_recovery(struct ata_port *ap) /* skip if class codes for all vacant slots are ATA_DEV_NONE */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (dev->class == ATA_DEV_UNKNOWN && ehc->classes[dev->devno] != ATA_DEV_NONE) @@ -2075,8 +2077,8 @@ static int ata_eh_skip_recovery(struct ata_port *ap) static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &dev->link->eh_context; ehc->tries[dev->devno]--; @@ -2149,7 +2151,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; struct ata_device *dev; int i, rc; @@ -2157,7 +2159,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* prep for recovery */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; @@ -2240,7 +2242,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, out: if (rc) { for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->device[i]); + ata_dev_disable(&ap->link.device[i]); } DPRINTK("EXIT, rc=%d\n", rc); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e83647651b31..ec0e2638200e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1368,14 +1368,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) case ATA_CMD_SET_FEATURES: if ((qc->tf.feature == SETFEATURES_WC_ON) || (qc->tf.feature == SETFEATURES_WC_OFF)) { - ap->eh_info.action |= ATA_EH_REVALIDATE; + ap->link.eh_info.action |= ATA_EH_REVALIDATE; ata_port_schedule_eh(ap); } break; case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ case ATA_CMD_SET_MULTI: /* multi_count changed */ - ap->eh_info.action |= ATA_EH_REVALIDATE; + ap->link.eh_info.action |= ATA_EH_REVALIDATE; ata_port_schedule_eh(ap); break; } @@ -1439,14 +1439,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) */ static int ata_scmd_need_defer(struct ata_device *dev, int is_io) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; int is_ncq = is_io && ata_ncq_enabled(dev); if (is_ncq) { - if (!ata_tag_valid(ap->active_tag)) + if (!ata_tag_valid(link->active_tag)) return 0; } else { - if (!ata_tag_valid(ap->active_tag) && !ap->sactive) + if (!ata_tag_valid(link->active_tag) && !link->sactive) return 0; } return 1; @@ -2426,7 +2426,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) static struct ata_device * ata_find_dev(struct ata_port *ap, int id) { if (likely(id < ATA_MAX_DEVICES)) - return &ap->device[id]; + return &ap->link.device[id]; return NULL; } @@ -2458,7 +2458,7 @@ static int ata_scsi_dev_enabled(struct ata_device *dev) if (unlikely(!ata_dev_enabled(dev))) return 0; - if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) { + if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) { if (unlikely(dev->class == ATA_DEV_ATAPI)) { ata_dev_printk(dev, KERN_WARNING, "WARNING: ATAPI is %s, device ignored.\n", @@ -2961,7 +2961,7 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) for (i = 0; i < ATA_MAX_DEVICES; i++) { struct scsi_device *sdev; - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev) || dev->sdev) continue; @@ -2978,7 +2978,7 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) * whether all devices are attached. */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (ata_dev_enabled(dev) && !dev->sdev) break; } @@ -3049,7 +3049,7 @@ int ata_scsi_offline_dev(struct ata_device *dev) */ static void ata_scsi_remove_dev(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct scsi_device *sdev; unsigned long flags; @@ -3123,7 +3123,7 @@ void ata_scsi_hotplug(struct work_struct *work) /* unplug detached devices */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; unsigned long flags; if (!(dev->flags & ATA_DFLAG_DETACHED)) @@ -3162,6 +3162,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, unsigned int id, unsigned int lun) { struct ata_port *ap = ata_shost_to_port(shost); + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned long flags; int rc = 0; @@ -3175,15 +3176,15 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, spin_lock_irqsave(ap->lock, flags); if (id == SCAN_WILD_CARD) { - ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1; - ap->eh_info.action |= ATA_EH_SOFTRESET; + ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; + ehi->action |= ATA_EH_SOFTRESET; } else { struct ata_device *dev = ata_find_dev(ap, id); if (dev) { - ap->eh_info.probe_mask |= 1 << dev->devno; - ap->eh_info.action |= ATA_EH_SOFTRESET; - ap->eh_info.flags |= ATA_EHI_RESUME_LINK; + ehi->probe_mask |= 1 << dev->devno; + ehi->action |= ATA_EH_SOFTRESET; + ehi->flags |= ATA_EHI_RESUME_LINK; } else rc = -EINVAL; } @@ -3220,7 +3221,7 @@ void ata_scsi_dev_rescan(struct work_struct *work) spin_lock_irqsave(ap->lock, flags); for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; struct scsi_device *sdev = dev->sdev; if (!ata_dev_enabled(dev) || !sdev) @@ -3359,7 +3360,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_destroy); int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap) { ata_scsi_sdev_config(sdev); - ata_scsi_dev_config(sdev, ap->device); + ata_scsi_dev_config(sdev, ap->link.device); return 0; } EXPORT_SYMBOL_GPL(ata_sas_slave_configure); @@ -3382,8 +3383,8 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), ata_scsi_dump_cdb(ap, cmd); - if (likely(ata_scsi_dev_enabled(ap->device))) - rc = __ata_scsi_queuecmd(cmd, done, ap->device); + if (likely(ata_scsi_dev_enabled(ap->link.device))) + rc = __ata_scsi_queuecmd(cmd, done, ap->link.device); else { cmd->result = (DID_BAD_TARGET << 16); done(cmd); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 8023167bbbeb..2100cd61ed69 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -445,7 +445,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, unsigned long flags; int thaw = 0; - qc = __ata_qc_from_tag(ap, ap->active_tag); + qc = __ata_qc_from_tag(ap, ap->link.active_tag); if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) qc = NULL; @@ -909,7 +909,7 @@ unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer /* Filter out DMA modes if the device has been configured by the BIOS as PIO only */ - if (adev->ap->ioaddr.bmdma_addr == 0) + if (adev->link->ap->ioaddr.bmdma_addr == 0) xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); return xfer_mask; } diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 5d8b91e70ecd..ece1a28f0a4a 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -391,7 +391,7 @@ static void it821x_passthru_dev_select(struct ata_port *ap, { struct it821x_dev *itdev = ap->private_data; if (itdev && device != itdev->last_device) { - struct ata_device *adev = &ap->device[device]; + struct ata_device *adev = &ap->link.device[device]; it821x_program(ap, adev, itdev->pio[adev->devno]); itdev->last_device = device; } @@ -464,7 +464,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 5dea3584c6c2..3e2b8ce5fa37 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -31,7 +31,7 @@ static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; @@ -49,7 +49,7 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int i; unsigned int words = buflen >> 1; u16 *buf16 = (u16 *) buf; - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; void __iomem *mmio = ap->ioaddr.data_addr; struct ixp4xx_pata_data *data = ap->host->dev->platform_data; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index edffc25d2d3f..4bcc0ae8d108 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -112,7 +112,7 @@ static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; @@ -256,7 +256,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; unsigned long flags; diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index f89bdfde16d0..f8234d7fd825 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -340,8 +340,8 @@ static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed) pci_read_config_byte(pdev, 0x43, &r); r &= (0x0F << nybble); - r |= (optidma_make_bits43(&ap->device[0]) + - (optidma_make_bits43(&ap->device[0]) << 2)) << nybble; + r |= (optidma_make_bits43(&ap->link.device[0]) + + (optidma_make_bits43(&ap->link.device[0]) << 2)) << nybble; pci_write_config_byte(pdev, 0x43, r); } return rc; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 0f2b027624d6..890f649ddcce 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -67,8 +67,8 @@ struct ata_pcmcia_info { static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) { - struct ata_device *master = &ap->device[0]; - struct ata_device *slave = &ap->device[1]; + struct ata_device *master = &ap->link.device[0]; + struct ata_device *slave = &ap->link.device[1]; if (!ata_dev_enabled(master) || !ata_dev_enabled(slave)) return ata_do_set_mode(ap, r_failed_dev); diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index bb64a986e8f5..fa780509a1dc 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -486,7 +486,7 @@ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) return i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 5086d03f2d7c..e89656bffa84 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -35,7 +35,7 @@ static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unuse int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { /* We don't really care */ diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 1998c19e8743..ec2206e820ac 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -126,7 +126,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; if (ata_id_has_dword_io(adev->id)) { diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 7632fcb070ca..57363c0ce068 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -39,7 +39,7 @@ static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 2d048ef25a5a..aab068fbb7bc 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -785,7 +785,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) static void scc_data_xfer (struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; unsigned int i; u16 *buf16 = (u16 *) buf; diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index cce2834b2b60..9d6f81d52e18 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -84,7 +84,7 @@ static int sis_short_ata40(struct pci_dev *dev) static int sis_old_port_base(struct ata_device *adev) { - return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno); + return 0x40 + (4 * adev->link->ap->port_no) + (2 * adev->devno); } /** diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 83abfeca4057..c37570330073 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -94,7 +94,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; if (ata_id_has_dword_io(adev->id)) { diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index c95c1bf7df37..064a3b505609 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -485,7 +485,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) pp = ap->private_data; if (!pp || pp->state != adma_state_pkt) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { if (status & aPERR) qc->err_mask |= AC_ERR_HOST_BUS; @@ -500,7 +500,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) if (!qc->err_mask) ata_qc_complete(qc); else { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "ADMA-status 0x%02X", status); @@ -529,7 +529,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) struct adma_port_priv *pp = ap->private_data; if (!pp || pp->state != adma_state_mmio) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ @@ -545,7 +545,8 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) if (!qc->err_mask) ata_qc_complete(qc); else { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = + &ap->link.eh_info; ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "status 0x%02X", status); diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index fdbed8ecdfc2..3c0ef7a2f2fe 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -285,7 +285,7 @@ static void inic_irq_clear(struct ata_port *ap) static void inic_host_intr(struct ata_port *ap) { void __iomem *port_base = inic_port_base(ap); - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; u8 irq_stat; /* fetch and clear irq */ @@ -293,7 +293,8 @@ static void inic_host_intr(struct ata_port *ap) writeb(irq_stat, port_base + PORT_IRQ_STAT); if (likely(!(irq_stat & PIRQ_ERR))) { - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = + ata_qc_from_tag(ap, ap->link.active_tag); if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { ata_chk_status(ap); /* clear ATA interrupt */ @@ -421,7 +422,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, { void __iomem *port_base = inic_port_base(ap); void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; - const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + const unsigned long *timing = sata_ehc_deb_timing(&ap->link.eh_context); u16 val; int rc; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index d9832e234e44..246e7c5fdce8 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1415,7 +1415,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) struct mv_host_priv *hpriv = ap->host->private_data; unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN); unsigned int action = 0, err_mask = 0; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); @@ -1508,7 +1508,7 @@ static void mv_intr_pio(struct ata_port *ap) return; /* get active ATA command */ - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (unlikely(!qc)) /* no active tag */ return; if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */ @@ -1543,7 +1543,7 @@ static void mv_intr_edma(struct ata_port *ap) /* 50xx: get active ATA command */ if (IS_GEN_I(hpriv)) - tag = ap->active_tag; + tag = ap->link.active_tag; /* Gen II/IIE: get active ATA command via tag, to enable * support for queueing. this works transparently for @@ -1646,7 +1646,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) if (unlikely(have_err_bits)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (qc->tf.flags & ATA_TFLAG_POLLING)) continue; @@ -1688,14 +1688,14 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) for (i = 0; i < host->n_ports; i++) { ap = host->ports[i]; if (!ata_port_offline(ap)) { - ehi = &ap->eh_info; + ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); if (!printed++) ata_ehi_push_desc(ehi, "PCI err cause 0x%08x", err_cause); err_mask = AC_ERR_HOST_BUS; ehi->action = ATA_EH_HARDRESET; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) qc->err_mask |= err_mask; else @@ -2269,7 +2269,7 @@ comreset_retry: static int mv_prereset(struct ata_port *ap, unsigned long deadline) { struct mv_port_priv *pp = ap->private_data; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; int rc; rc = mv_stop_dma(ap); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 40dc73139858..df4d50dcffbc 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -594,7 +594,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev) /* Not a proper libata device, ignore */ return rc; - if (ap->device[sdev->id].class == ATA_DEV_ATAPI) { + if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) { /* * NVIDIA reports that ADMA mode does not support ATAPI commands. * Therefore ATAPI commands are sent through the legacy interface. @@ -711,7 +711,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) flags & (NV_CPB_RESP_ATA_ERR | NV_CPB_RESP_CMD_ERR | NV_CPB_RESP_CPB_ERR)))) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; int freeze = 0; ata_ehi_clear_desc(ehi); @@ -747,7 +747,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) DPRINTK("Completing qc from tag %d\n",cpb_num); ata_qc_complete(qc); } else { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; /* Notifier bits set without a command may indicate the drive is misbehaving. Raise host state machine violation on this condition. */ @@ -764,7 +764,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) static int nv_host_intr(struct ata_port *ap, u8 irq_stat) { - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); /* freeze if hotplugged */ if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { @@ -817,7 +817,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804) >> (NV_INT_PORT_SHIFT * i); - if(ata_tag_valid(ap->active_tag)) + if(ata_tag_valid(ap->link.active_tag)) /** NV_INT_DEV indication seems unreliable at times at least in ADMA mode. Force it on always when a command is active, to prevent losing interrupts. */ @@ -852,7 +852,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) NV_ADMA_STAT_HOTUNPLUG | NV_ADMA_STAT_TIMEOUT | NV_ADMA_STAT_SERROR))) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status ); @@ -879,10 +879,10 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) u32 check_commands; int pos, error = 0; - if(ata_tag_valid(ap->active_tag)) - check_commands = 1 << ap->active_tag; + if(ata_tag_valid(ap->link.active_tag)) + check_commands = 1 << ap->link.active_tag; else - check_commands = ap->sactive; + check_commands = ap->link.sactive; /** Check CPBs for completed commands */ while ((pos = ffs(check_commands)) && !error) { @@ -1333,7 +1333,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); else @@ -1485,7 +1485,7 @@ static void nv_adma_error_handler(struct ata_port *ap) int i; u16 tmp; - if(ata_tag_valid(ap->active_tag) || ap->sactive) { + if(ata_tag_valid(ap->link.active_tag) || ap->link.sactive) { u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL); @@ -1501,8 +1501,8 @@ static void nv_adma_error_handler(struct ata_port *ap) for( i=0;icpb[i]; - if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) || - ap->sactive & (1 << i) ) + if( (ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) || + ap->link.sactive & (1 << i) ) ata_port_printk(ap, KERN_ERR, "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", i, cpb->ctl_flags, cpb->resp_flags); diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 25698cf0dce0..620d0675d18a 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -626,7 +626,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, u32 port_status, u32 err_mask) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned int ac_err_mask = 0; ata_ehi_clear_desc(ehi); @@ -773,7 +773,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance) tmp = hotplug_status & (0x11 << ata_no); if (tmp && ap && !(ap->flags & ATA_FLAG_DISABLED)) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp); @@ -788,7 +788,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc_host_intr(ap, qc); } diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 5e1dfdda698f..ef1ad69c26ed 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -404,7 +404,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host) struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_pkt) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { switch (sHST) { case 0: /* successful CPB */ @@ -437,7 +437,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_mmio) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 8c72e714b456..2ddbe4cc71e4 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -312,7 +312,7 @@ static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) return rc; for (i = 0; i < 2; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev)) dev_mode[i] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) @@ -374,8 +374,8 @@ static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static void sil_host_intr(struct ata_port *ap, u32 bmdma2) { - struct ata_eh_info *ehi = &ap->eh_info; - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_eh_info *ehi = &ap->link.eh_info; + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); u8 status; if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) { @@ -394,8 +394,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) * repeat probing needlessly. */ if (!(ap->pflags & ATA_PFLAG_FROZEN)) { - ata_ehi_hotplugged(&ap->eh_info); - ap->eh_info.serror |= serror; + ata_ehi_hotplugged(&ap->link.eh_info); + ap->link.eh_info.serror |= serror; } goto freeze; @@ -562,8 +562,8 @@ static void sil_thaw(struct ata_port *ap) */ static void sil_dev_config(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; + struct ata_port *ap = dev->link->ap; + int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; unsigned char model_num[ATA_ID_PROD_LEN + 1]; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 233e88693395..2d8334e7921d 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -456,7 +456,7 @@ static int sil24_tag(int tag) static void sil24_dev_config(struct ata_device *dev) { - void __iomem *port = dev->ap->ioaddr.cmd_addr; + void __iomem *port = dev->link->ap->ioaddr.cmd_addr; if (dev->cdb_len == 16) writel(PORT_CS_CDB16, port + PORT_CTRL_STAT); @@ -609,7 +609,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, if (time_after(deadline, jiffies)) timeout_msec = jiffies_to_msecs(deadline - jiffies); - ata_tf_init(ap->device, &tf); /* doesn't really matter */ + ata_tf_init(ap->link.device, &tf); /* doesn't really matter */ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST, timeout_msec); if (rc == -EBUSY) { @@ -804,7 +804,7 @@ static void sil24_error_intr(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; int freeze = 0; u32 irq_stat; @@ -856,7 +856,7 @@ static void sil24_error_intr(struct ata_port *ap) } /* record error info */ - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) { sil24_read_tf(ap, qc->tag, &pp->tf); qc->err_mask |= err_mask; @@ -910,7 +910,7 @@ static inline void sil24_host_intr(struct ata_port *ap) if (rc > 0) return; if (rc < 0) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ehi->err_mask |= AC_ERR_HSM; ehi->action |= ATA_EH_SOFTRESET; ata_port_freeze(ap); @@ -921,7 +921,7 @@ static inline void sil24_host_intr(struct ata_port *ap) if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit()) ata_port_printk(ap, KERN_INFO, "spurious interrupt " "(slot_stat 0x%x active_tag %d sactive 0x%x)\n", - slot_stat, ap->active_tag, ap->sactive); + slot_stat, ap->link.active_tag, ap->link.sactive); } static irqreturn_t sil24_interrupt(int irq, void *dev_instance) @@ -963,7 +963,7 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) static void sil24_error_handler(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; if (sil24_init_port(ap)) { ata_eh_freeze_port(ap); diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 97aefdd87be4..12691f091933 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -854,7 +854,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc20621_host_intr(ap, qc, (i > 4), mmio_base); @@ -881,7 +881,7 @@ static void pdc_eng_timeout(struct ata_port *ap) spin_lock_irqsave(&host->lock, flags); - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); switch (qc->tf.protocol) { case ATA_PROT_DMA: diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 57fd30de8f0d..78a6833af713 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -296,7 +296,7 @@ static void svia_noop_freeze(struct ata_port *ap) */ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; unsigned long timeout = jiffies + (HZ * 5); u32 sstatus, scontrol; int online; diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 1920915dfa2c..9586b8b51cea 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -240,7 +240,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap) return; } - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING))) handled = ata_host_intr(ap, qc); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index f142eafb6fc7..affd77aafb23 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4988,14 +4988,14 @@ static void ipr_ata_phy_reset(struct ata_port *ap) switch(res->cfgte.proto) { case IPR_PROTO_SATA: case IPR_PROTO_SAS_STP: - ap->device[0].class = ATA_DEV_ATA; + ap->link.device[0].class = ATA_DEV_ATA; break; case IPR_PROTO_SATA_ATAPI: case IPR_PROTO_SAS_STP_ATAPI: - ap->device[0].class = ATA_DEV_ATAPI; + ap->link.device[0].class = ATA_DEV_ATAPI; break; default: - ap->device[0].class = ATA_DEV_UNKNOWN; + ap->link.device[0].class = ATA_DEV_UNKNOWN; ap->ops->port_disable(ap); break; }; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 5e573efcf0a7..1d6503d85f02 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -249,17 +249,17 @@ static void sas_ata_phy_reset(struct ata_port *ap) switch (dev->sata_dev.command_set) { case ATA_COMMAND_SET: SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__); - ap->device[0].class = ATA_DEV_ATA; + ap->link.device[0].class = ATA_DEV_ATA; break; case ATAPI_COMMAND_SET: SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__); - ap->device[0].class = ATA_DEV_ATAPI; + ap->link.device[0].class = ATA_DEV_ATAPI; break; default: SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", __FUNCTION__, dev->sata_dev.command_set); - ap->device[0].class = ATA_DEV_UNKNOWN; + ap->link.device[0].class = ATA_DEV_UNKNOWN; break; } @@ -317,7 +317,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in, dev->sata_dev.serror = val; break; case SCR_ACTIVE: - dev->sata_dev.ap->sactive = val; + dev->sata_dev.ap->link.sactive = val; break; default: return -EINVAL; @@ -342,7 +342,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, *val = dev->sata_dev.serror; return 0; case SCR_ACTIVE: - *val = dev->sata_dev.ap->sactive; + *val = dev->sata_dev.ap->link.sactive; return 0; default: return -EINVAL; diff --git a/include/linux/libata.h b/include/linux/libata.h index a67bb9075e9b..ca4493125fa0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -436,7 +436,7 @@ struct ata_ering { }; struct ata_device { - struct ata_port *ap; + struct ata_link *link; unsigned int devno; /* 0 or 1 */ unsigned long flags; /* ATA_DFLAG_xxx */ unsigned int horkage; /* List of broken features */ @@ -510,6 +510,24 @@ struct ata_acpi_gtm { u32 flags; } __packed; +struct ata_link { + struct ata_port *ap; + + unsigned int active_tag; /* active tag on this link */ + u32 sactive; /* active NCQ commands */ + + unsigned int hw_sata_spd_limit; + unsigned int sata_spd_limit; + unsigned int sata_spd; /* current SATA PHY speed */ + + /* record runtime error info, protected by host_set lock */ + struct ata_eh_info eh_info; + /* EH context */ + struct ata_eh_context eh_context; + + struct ata_device device[ATA_MAX_DEVICES]; +}; + struct ata_port { struct Scsi_Host *scsi_host; /* our co-allocated scsi host */ const struct ata_port_operations *ops; @@ -533,23 +551,12 @@ struct ata_port { unsigned int mwdma_mask; unsigned int udma_mask; unsigned int cbl; /* cable type; ATA_CBL_xxx */ - unsigned int hw_sata_spd_limit; - unsigned int sata_spd_limit; /* SATA PHY speed limit */ - unsigned int sata_spd; /* current SATA PHY speed */ - - /* record runtime error info, protected by host lock */ - struct ata_eh_info eh_info; - /* EH context owned by EH */ - struct ata_eh_context eh_context; - - struct ata_device device[ATA_MAX_DEVICES]; struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; unsigned long qc_allocated; unsigned int qc_active; - unsigned int active_tag; - u32 sactive; + struct ata_link link; /* host default link */ struct ata_port_stats stats; struct ata_host *host; @@ -912,8 +919,11 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, #define ata_port_printk(ap, lv, fmt, args...) \ printk(lv"ata%u: "fmt, (ap)->print_id , ##args) +#define ata_link_printk(link, lv, fmt, args...) \ + printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args) + #define ata_dev_printk(dev, lv, fmt, args...) \ - printk(lv"ata%u.%02u: "fmt, (dev)->ap->print_id, (dev)->devno , ##args) + printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, (dev)->devno , ##args) /* * ata_eh_info helpers @@ -1149,7 +1159,7 @@ static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf) { memset(tf, 0, sizeof(*tf)); - tf->ctl = dev->ap->ctl; + tf->ctl = dev->link->ap->ctl; if (dev->devno == 0) tf->device = ATA_DEVICE_OBS; else From f58229f8060055b08b34008ea08f31de1e2f003c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2387/2804] libata-link: implement and use link/device iterators Multiple links and different number of devices per link should be considered to iterate over links and devices. This patch implements and uses link and device iterators - ata_port_for_each_link() and ata_link_for_each_dev() - and ata_link_max_devices(). This change makes a lot of functions iterate over only possible devices instead of from dev 0 to dev ATA_MAX_DEVICES. All such changes have been examined and nothing should be broken. While at it, add a separating comment before device helpers to distinguish them better from link helpers and others. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 7 +-- drivers/ata/libata-acpi.c | 6 +- drivers/ata/libata-core.c | 58 +++++++---------- drivers/ata/libata-eh.c | 117 ++++++++++++++++++----------------- drivers/ata/libata-scsi.c | 26 +++----- drivers/ata/pata_it821x.c | 5 +- drivers/ata/pata_ixp4xx_cf.c | 5 +- drivers/ata/pata_legacy.c | 5 +- drivers/ata/pata_pdc2027x.c | 13 ++-- drivers/ata/pata_platform.c | 6 +- drivers/ata/pata_rz1000.c | 5 +- drivers/ata/sata_sil.c | 12 ++-- include/linux/libata.h | 17 ++++- 13 files changed, 134 insertions(+), 148 deletions(-) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index b5e390ff5bd8..44328a16075c 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -46,21 +46,20 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) { int dma_enabled = 0; - int i; + struct ata_device *dev; /* Bits 5 and 6 indicate if DMA is active on master/slave */ if (ap->ioaddr.bmdma_addr) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; dev->dma_mode = XFER_MW_DMA_0; /* We do need the right mode information for DMA or PIO and this comes from the current configuration flags */ - if (dma_enabled & (1 << (5 + i))) { + if (dma_enabled & (1 << (5 + dev->devno))) { ata_id_to_dma_mode(dev, XFER_MW_DMA_0); dev->flags &= ~ATA_DFLAG_PIO; } else { diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 0023ac4ff496..43af2e06d446 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -509,7 +509,7 @@ int ata_acpi_on_suspend(struct ata_port *ap) */ void ata_acpi_on_resume(struct ata_port *ap) { - int i; + struct ata_device *dev; if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) { BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); @@ -519,8 +519,8 @@ void ata_acpi_on_resume(struct ata_port *ap) } /* schedule _GTF */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->link.device[i].flags |= ATA_DFLAG_ACPI_PENDING; + ata_link_for_each_dev(dev, &ap->link) + dev->flags |= ATA_DFLAG_ACPI_PENDING; } /** diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dd2de485124a..f30c4771b3af 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2105,21 +2105,19 @@ int ata_bus_probe(struct ata_port *ap) { unsigned int classes[ATA_MAX_DEVICES]; int tries[ATA_MAX_DEVICES]; - int i, rc; + int rc; struct ata_device *dev; ata_port_probe(ap); - for (i = 0; i < ATA_MAX_DEVICES; i++) - tries[i] = ATA_PROBE_MAX_TRIES; + ata_link_for_each_dev(dev, &ap->link) + tries[dev->devno] = ATA_PROBE_MAX_TRIES; retry: /* reset and determine device classes */ ap->ops->phy_reset(ap); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, &ap->link) { if (!(ap->flags & ATA_FLAG_DISABLED) && dev->class != ATA_DEV_UNKNOWN) classes[dev->devno] = dev->class; @@ -2134,18 +2132,16 @@ int ata_bus_probe(struct ata_port *ap) /* after the reset the device state is PIO 0 and the controller state is undefined. Record the mode */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->link.device[i].pio_mode = XFER_PIO_0; + ata_link_for_each_dev(dev, &ap->link) + dev->pio_mode = XFER_PIO_0; /* read IDENTIFY page and configure devices. We have to do the identify specific sequence bass-ackwards so that PDIAG- is released by the slave device */ - for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { - dev = &ap->link.device[i]; - - if (tries[i]) - dev->class = classes[i]; + ata_link_for_each_dev(dev, &ap->link) { + if (tries[dev->devno]) + dev->class = classes[dev->devno]; if (!ata_dev_enabled(dev)) continue; @@ -2163,8 +2159,7 @@ int ata_bus_probe(struct ata_port *ap) /* After the identify sequence we can now set up the devices. We do this in the normal order so that the user doesn't get confused */ - for(i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (!ata_dev_enabled(dev)) continue; @@ -2180,8 +2175,8 @@ int ata_bus_probe(struct ata_port *ap) if (rc) goto fail; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->link.device[i])) + ata_link_for_each_dev(dev, &ap->link) + if (ata_dev_enabled(dev)) return 0; /* no device present, disable port */ @@ -2803,16 +2798,14 @@ static int ata_dev_set_mode(struct ata_device *dev) int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) { + struct ata_link *link = &ap->link; struct ata_device *dev; - int i, rc = 0, used_dma = 0, found = 0; - + int rc = 0, used_dma = 0, found = 0; /* step 1: calculate xfer_mask */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { + ata_link_for_each_dev(dev, link) { unsigned int pio_mask, dma_mask; - dev = &ap->link.device[i]; - if (!ata_dev_enabled(dev)) continue; @@ -2831,8 +2824,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) goto out; /* step 2: always set host PIO timings */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev)) continue; @@ -2849,9 +2841,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) } /* step 3: set host DMA timings */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev) || !dev->dma_mode) continue; @@ -2862,9 +2852,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) } /* step 4: update devices' xfer mode */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, link) { /* don't update suspended devices' xfer mode */ if (!ata_dev_enabled(dev)) continue; @@ -6113,6 +6101,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->link.ap = ap; + /* can't use iterator, ap isn't initialized yet */ for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->link.device[i]; dev->link = &ap->link; @@ -6453,7 +6442,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* kick EH for boot probing */ spin_lock_irqsave(ap->lock, flags); - ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1; + ehi->probe_mask = + (1 << ata_link_max_devices(&ap->link)) - 1; ehi->action |= ATA_EH_SOFTRESET; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; @@ -6551,7 +6541,7 @@ int ata_host_activate(struct ata_host *host, int irq, void ata_port_detach(struct ata_port *ap) { unsigned long flags; - int i; + struct ata_device *dev; if (!ap->ops->error_handler) goto skip_eh; @@ -6568,8 +6558,8 @@ void ata_port_detach(struct ata_port *ap) */ spin_lock_irqsave(ap->lock, flags); - for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->link.device[i]); + ata_link_for_each_dev(dev, &ap->link) + ata_dev_disable(dev); spin_unlock_irqrestore(ap->lock, flags); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e2681f56ed44..8c37ec0bbf6c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -200,23 +200,24 @@ static unsigned int ata_eh_dev_action(struct ata_device *dev) return ehc->i.action | ehc->i.dev_action[dev->devno]; } -static void ata_eh_clear_action(struct ata_device *dev, +static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, struct ata_eh_info *ehi, unsigned int action) { - int i; + struct ata_device *tdev; if (!dev) { ehi->action &= ~action; - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehi->dev_action[i] &= ~action; + ata_link_for_each_dev(tdev, link) + ehi->dev_action[tdev->devno] &= ~action; } else { /* doesn't make sense for port-wide EH actions */ WARN_ON(!(action & ATA_EH_PERDEV_MASK)); /* break ehi->action into ehi->dev_action */ if (ehi->action & action) { - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehi->dev_action[i] |= ehi->action & action; + ata_link_for_each_dev(tdev, link) + ehi->dev_action[tdev->devno] |= + ehi->action & action; ehi->action &= ~action; } @@ -922,7 +923,8 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) */ static void ata_eh_detach_dev(struct ata_device *dev) { - struct ata_port *ap = dev->link->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; unsigned long flags; ata_dev_disable(dev); @@ -937,8 +939,8 @@ static void ata_eh_detach_dev(struct ata_device *dev) } /* clear per-dev EH actions */ - ata_eh_clear_action(dev, &dev->link->eh_info, ATA_EH_PERDEV_MASK); - ata_eh_clear_action(dev, &dev->link->eh_context.i, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK); spin_unlock_irqrestore(ap->lock, flags); } @@ -978,7 +980,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(dev, ehi, action); + ata_eh_clear_action(&ap->link, dev, ehi, action); if (!(ehc->i.flags & ATA_EHI_QUIET)) ap->pflags |= ATA_PFLAG_RECOVERED; @@ -1009,7 +1011,7 @@ static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(dev, &ehc->i, action); + ata_eh_clear_action(&ap->link, dev, &ehc->i, action); } /** @@ -1736,10 +1738,11 @@ static void ata_eh_report(struct ata_port *ap) static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { - int i, rc; + struct ata_device *dev; + int rc; - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_UNKNOWN; + ata_link_for_each_dev(dev, &ap->link) + classes[dev->devno] = ATA_DEV_UNKNOWN; rc = reset(ap, classes, deadline); if (rc) @@ -1749,14 +1752,16 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, * is complete and convert all ATA_DEV_UNKNOWN to * ATA_DEV_NONE. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (classes[i] != ATA_DEV_UNKNOWN) + ata_link_for_each_dev(dev, &ap->link) + if (classes[dev->devno] != ATA_DEV_UNKNOWN) break; - if (i < ATA_MAX_DEVICES) - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (classes[i] == ATA_DEV_UNKNOWN) - classes[i] = ATA_DEV_NONE; + if (dev) { + ata_link_for_each_dev(dev, &ap->link) { + if (classes[dev->devno] == ATA_DEV_UNKNOWN) + classes[dev->devno] = ATA_DEV_NONE; + } + } return 0; } @@ -1781,10 +1786,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify, unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); int try = 0; + struct ata_device *dev; unsigned long deadline; unsigned int action; ata_reset_fn_t reset; - int i, rc; + int rc; /* about to reset */ ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); @@ -1808,8 +1814,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, "port disabled. ignoring.\n"); ehc->i.action &= ~ATA_EH_RESET_MASK; - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_NONE; + ata_link_for_each_dev(dev, &ap->link) + classes[dev->devno] = ATA_DEV_NONE; rc = 0; } else @@ -1826,8 +1832,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset = softreset; else { /* prereset told us not to reset, bang classes and return */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_NONE; + ata_link_for_each_dev(dev, &ap->link) + classes[dev->devno] = ATA_DEV_NONE; rc = 0; goto out; } @@ -1908,8 +1914,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, /* After the reset, the device state is PIO 0 and the * controller state is undefined. Record the mode. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->link.device[i].pio_mode = XFER_PIO_0; + ata_link_for_each_dev(dev, &ap->link) + dev->pio_mode = XFER_PIO_0; /* record current link speed */ if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0) @@ -1935,7 +1941,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, struct ata_device *dev; unsigned int new_mask = 0; unsigned long flags; - int i, rc = 0; + int rc = 0; DPRINTK("ENTER\n"); @@ -1943,11 +1949,9 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, * be done backwards such that PDIAG- is released by the slave * device before the master device is identified. */ - for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { - unsigned int action, readid_flags = 0; - - dev = &ap->link.device[i]; - action = ata_eh_dev_action(dev); + ata_link_for_each_dev_reverse(dev, &ap->link) { + unsigned int action = ata_eh_dev_action(dev); + unsigned int readid_flags = 0; if (ehc->i.flags & ATA_EHI_DID_RESET) readid_flags |= ATA_READID_POSTRESET; @@ -1981,7 +1985,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, dev->id); switch (rc) { case 0: - new_mask |= 1 << i; + new_mask |= 1 << dev->devno; break; case -ENOENT: /* IDENTIFY was issued to non-existent @@ -2005,10 +2009,8 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, /* Configure new devices forward such that user doesn't see * device detection messages backwards. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - - if (!(new_mask & (1 << i))) + ata_link_for_each_dev(dev, &ap->link) { + if (!(new_mask & (1 << dev->devno))) continue; ehc->i.flags |= ATA_EHI_PRINTINFO; @@ -2035,20 +2037,22 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, static int ata_port_nr_enabled(struct ata_port *ap) { - int i, cnt = 0; + struct ata_device *dev; + int cnt = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->link.device[i])) + ata_link_for_each_dev(dev, &ap->link) + if (ata_dev_enabled(dev)) cnt++; return cnt; } static int ata_port_nr_vacant(struct ata_port *ap) { - int i, cnt = 0; + struct ata_device *dev; + int cnt = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ap->link.device[i].class == ATA_DEV_UNKNOWN) + ata_link_for_each_dev(dev, &ap->link) + if (dev->class == ATA_DEV_UNKNOWN) cnt++; return cnt; } @@ -2056,7 +2060,7 @@ static int ata_port_nr_vacant(struct ata_port *ap) static int ata_eh_skip_recovery(struct ata_port *ap) { struct ata_eh_context *ehc = &ap->link.eh_context; - int i; + struct ata_device *dev; /* thaw frozen port, resume link and recover failed devices */ if ((ap->pflags & ATA_PFLAG_FROZEN) || @@ -2064,9 +2068,7 @@ static int ata_eh_skip_recovery(struct ata_port *ap) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, &ap->link) { if (dev->class == ATA_DEV_UNKNOWN && ehc->classes[dev->devno] != ATA_DEV_NONE) return 0; @@ -2153,19 +2155,18 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, { struct ata_eh_context *ehc = &ap->link.eh_context; struct ata_device *dev; - int i, rc; + int rc; DPRINTK("ENTER\n"); /* prep for recovery */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, &ap->link) { ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; /* collect port action mask recorded in dev actions */ - ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK; - ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK; + ehc->i.action |= + ehc->i.dev_action[dev->devno] & ~ATA_EH_PERDEV_MASK; + ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; /* process hotplug request */ if (dev->flags & ATA_DFLAG_DETACH) @@ -2192,8 +2193,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (ata_eh_skip_recovery(ap)) ehc->i.action = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehc->classes[i] = ATA_DEV_UNKNOWN; + ata_link_for_each_dev(dev, &ap->link) + ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; /* reset */ if (ehc->i.action & ATA_EH_RESET_MASK) { @@ -2241,8 +2242,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, out: if (rc) { - for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->link.device[i]); + ata_link_for_each_dev(dev, &ap->link); + ata_dev_disable(dev); } DPRINTK("EXIT, rc=%d\n", rc); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index ec0e2638200e..3d6d5f737994 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2425,7 +2425,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) static struct ata_device * ata_find_dev(struct ata_port *ap, int id) { - if (likely(id < ATA_MAX_DEVICES)) + if (likely(id < ata_link_max_devices(&ap->link))) return &ap->link.device[id]; return NULL; } @@ -2952,21 +2952,18 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) int tries = 5; struct ata_device *last_failed_dev = NULL; struct ata_device *dev; - unsigned int i; if (ap->flags & ATA_FLAG_DISABLED) return; repeat: - for (i = 0; i < ATA_MAX_DEVICES; i++) { + ata_link_for_each_dev(dev, &ap->link) { struct scsi_device *sdev; - dev = &ap->link.device[i]; - if (!ata_dev_enabled(dev) || dev->sdev) continue; - sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL); + sdev = __scsi_add_device(ap->scsi_host, 0, dev->devno, 0, NULL); if (!IS_ERR(sdev)) { dev->sdev = sdev; scsi_device_put(sdev); @@ -2977,12 +2974,11 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) * failure occurred, scan would have failed silently. Check * whether all devices are attached. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev) && !dev->sdev) break; } - if (i == ATA_MAX_DEVICES) + if (!dev) return; /* we're missing some SCSI devices */ @@ -3112,7 +3108,7 @@ void ata_scsi_hotplug(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, hotplug_task.work); - int i; + struct ata_device *dev; if (ap->pflags & ATA_PFLAG_UNLOADING) { DPRINTK("ENTER/EXIT - unloading\n"); @@ -3122,8 +3118,7 @@ void ata_scsi_hotplug(struct work_struct *work) DPRINTK("ENTER\n"); /* unplug detached devices */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { unsigned long flags; if (!(dev->flags & ATA_DFLAG_DETACHED)) @@ -3176,7 +3171,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, spin_lock_irqsave(ap->lock, flags); if (id == SCAN_WILD_CARD) { - ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; + ehi->probe_mask |= (1 << ata_link_max_devices(&ap->link)) - 1; ehi->action |= ATA_EH_SOFTRESET; } else { struct ata_device *dev = ata_find_dev(ap, id); @@ -3215,13 +3210,12 @@ void ata_scsi_dev_rescan(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, scsi_rescan_task); + struct ata_device *dev; unsigned long flags; - unsigned int i; spin_lock_irqsave(ap->lock, flags); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { struct scsi_device *sdev = dev->sdev; if (!ata_dev_enabled(dev) || !sdev) diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index ece1a28f0a4a..088eb1d23761 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -461,10 +461,9 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 3e2b8ce5fa37..7db315a9baad 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -28,10 +28,9 @@ static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 4bcc0ae8d108..9d92843b033d 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -109,10 +109,9 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index fa780509a1dc..83c90cabc7ff 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -479,15 +479,14 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) */ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) { - int i; + struct ata_device *dev; + int rc; - i = ata_do_set_mode(ap, r_failed); - if (i < 0) - return i; - - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + rc = ata_do_set_mode(ap, r_failed); + if (rc < 0) + return rc; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { pdc2027x_set_piomode(ap, dev); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index e89656bffa84..ee1605bfc29f 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -32,11 +32,9 @@ static int pio_mask = 1; */ static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused) { - int i; - - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + struct ata_device *dev; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = dev->xfer_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 57363c0ce068..300b3d5de81e 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -36,10 +36,9 @@ static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 2ddbe4cc71e4..4c9295a49a49 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -303,22 +303,20 @@ static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) struct ata_device *dev; void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; - u32 tmp, dev_mode[2]; - unsigned int i; + u32 tmp, dev_mode[2] = { }; int rc; rc = ata_do_set_mode(ap, r_failed); if (rc) return rc; - for (i = 0; i < 2; i++) { - dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (!ata_dev_enabled(dev)) - dev_mode[i] = 0; /* PIO0/1/2 */ + dev_mode[dev->devno] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) - dev_mode[i] = 1; /* PIO3/4 */ + dev_mode[dev->devno] = 1; /* PIO3/4 */ else - dev_mode[i] = 3; /* UDMA */ + dev_mode[dev->devno] = 3; /* UDMA */ /* value 2 indicates MDMA */ } diff --git a/include/linux/libata.h b/include/linux/libata.h index ca4493125fa0..62fa8cf677a1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1030,15 +1030,26 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev) } /* - * port helpers + * link helpers */ -static inline int ata_port_max_devices(const struct ata_port *ap) +static inline int ata_link_max_devices(const struct ata_link *link) { - if (ap->flags & ATA_FLAG_SLAVE_POSS) + if (link->ap->flags & ATA_FLAG_SLAVE_POSS) return 2; return 1; } +#define ata_port_for_each_link(lk, ap) \ + for ((lk) = &(ap)->link; (lk); (lk) = NULL) + +#define ata_link_for_each_dev(dev, link) \ + for ((dev) = (link)->device; \ + (dev) < (link)->device + ata_link_max_devices(link) || ((dev) = NULL); \ + (dev)++) + +#define ata_link_for_each_dev_reverse(dev, link) \ + for ((dev) = (link)->device + ata_link_max_devices(link) - 1; \ + (dev) >= (link)->device || ((dev) = NULL); (dev)--) static inline u8 ata_chk_status(struct ata_port *ap) { From 936fd7328657884d5a69a55666c74a55aa83ca27 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2388/2804] libata-link: linkify PHY-related functions Make the following PHY-related functions to deal with ata_link instead of ata_port. * sata_print_link_status() * sata_down_spd_limit() * ata_set_sata_spd_limit() and friends * sata_link_debounce/resume() * sata_scr_valid/read/write/write_flush() * ata_link_on/offline() This patch introduces no behavior change. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 +- drivers/ata/libata-core.c | 227 +++++++++++++++++++----------------- drivers/ata/libata-eh.c | 31 ++--- drivers/ata/libata-sff.c | 2 +- drivers/ata/libata.h | 4 +- drivers/ata/pata_scc.c | 2 +- drivers/ata/sata_inic162x.c | 4 +- drivers/ata/sata_mv.c | 26 ++--- drivers/ata/sata_promise.c | 4 +- drivers/ata/sata_sil24.c | 10 +- include/linux/libata.h | 24 ++-- 11 files changed, 177 insertions(+), 161 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c72fa468a697..6e5f69a3a0c2 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1052,7 +1052,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; return 0; @@ -1140,7 +1140,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, ahci_start_engine(ap); - if (rc == 0 && ata_port_online(ap)) + if (rc == 0 && ata_link_online(&ap->link)) *class = ahci_dev_classify(ap); if (*class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f30c4771b3af..6f99dee6b6d2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2201,7 +2201,7 @@ int ata_bus_probe(struct ata_port *ap) /* This is the last chance, better to slow * down than lose it. */ - sata_down_spd_limit(ap); + sata_down_spd_limit(&ap->link); ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); } } @@ -2230,28 +2230,28 @@ void ata_port_probe(struct ata_port *ap) /** * sata_print_link_status - Print SATA link status - * @ap: SATA port to printk link status about + * @link: SATA link to printk link status about * * This function prints link speed and status of a SATA link. * * LOCKING: * None. */ -void sata_print_link_status(struct ata_port *ap) +void sata_print_link_status(struct ata_link *link) { u32 sstatus, scontrol, tmp; - if (sata_scr_read(ap, SCR_STATUS, &sstatus)) + if (sata_scr_read(link, SCR_STATUS, &sstatus)) return; - sata_scr_read(ap, SCR_CONTROL, &scontrol); + sata_scr_read(link, SCR_CONTROL, &scontrol); - if (ata_port_online(ap)) { + if (ata_link_online(link)) { tmp = (sstatus >> 4) & 0xf; - ata_port_printk(ap, KERN_INFO, + ata_link_printk(link, KERN_INFO, "SATA link up %s (SStatus %X SControl %X)\n", sata_spd_string(tmp), sstatus, scontrol); } else { - ata_port_printk(ap, KERN_INFO, + ata_link_printk(link, KERN_INFO, "SATA link down (SStatus %X SControl %X)\n", sstatus, scontrol); } @@ -2271,32 +2271,33 @@ void sata_print_link_status(struct ata_port *ap) */ void __sata_phy_reset(struct ata_port *ap) { - u32 sstatus; + struct ata_link *link = &ap->link; unsigned long timeout = jiffies + (HZ * 5); + u32 sstatus; if (ap->flags & ATA_FLAG_SATA_RESET) { /* issue phy wake/reset */ - sata_scr_write_flush(ap, SCR_CONTROL, 0x301); + sata_scr_write_flush(link, SCR_CONTROL, 0x301); /* Couldn't find anything in SATA I/II specs, but * AHCI-1.1 10.4.2 says at least 1 ms. */ mdelay(1); } /* phy wake/clear reset */ - sata_scr_write_flush(ap, SCR_CONTROL, 0x300); + sata_scr_write_flush(link, SCR_CONTROL, 0x300); /* wait for phy to become ready, if necessary */ do { msleep(200); - sata_scr_read(ap, SCR_STATUS, &sstatus); + sata_scr_read(link, SCR_STATUS, &sstatus); if ((sstatus & 0xf) != 1) break; } while (time_before(jiffies, timeout)); /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(link); /* TODO: phy layer with polling, timeouts, etc. */ - if (!ata_port_offline(ap)) + if (!ata_link_offline(link)) ata_port_probe(ap); else ata_port_disable(ap); @@ -2370,9 +2371,9 @@ void ata_port_disable(struct ata_port *ap) /** * sata_down_spd_limit - adjust SATA spd limit downward - * @ap: Port to adjust SATA spd limit for + * @link: Link to adjust SATA spd limit for * - * Adjust SATA spd limit of @ap downward. Note that this + * Adjust SATA spd limit of @link downward. Note that this * function only adjusts the limit. The change must be applied * using sata_set_spd(). * @@ -2382,24 +2383,24 @@ void ata_port_disable(struct ata_port *ap) * RETURNS: * 0 on success, negative errno on failure */ -int sata_down_spd_limit(struct ata_port *ap) +int sata_down_spd_limit(struct ata_link *link) { u32 sstatus, spd, mask; int rc, highbit; - if (!sata_scr_valid(ap)) + if (!sata_scr_valid(link)) return -EOPNOTSUPP; /* If SCR can be read, use it to determine the current SPD. - * If not, use cached value in ap->sata_spd. + * If not, use cached value in link->sata_spd. */ - rc = sata_scr_read(ap, SCR_STATUS, &sstatus); + rc = sata_scr_read(link, SCR_STATUS, &sstatus); if (rc == 0) spd = (sstatus >> 4) & 0xf; else - spd = ap->link.sata_spd; + spd = link->sata_spd; - mask = ap->link.sata_spd_limit; + mask = link->sata_spd_limit; if (mask <= 1) return -EINVAL; @@ -2419,22 +2420,22 @@ int sata_down_spd_limit(struct ata_port *ap) if (!mask) return -EINVAL; - ap->link.sata_spd_limit = mask; + link->sata_spd_limit = mask; - ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n", + ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n", sata_spd_string(fls(mask))); return 0; } -static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) +static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol) { u32 spd, limit; - if (ap->link.sata_spd_limit == UINT_MAX) + if (link->sata_spd_limit == UINT_MAX) limit = 0; else - limit = fls(ap->link.sata_spd_limit); + limit = fls(link->sata_spd_limit); spd = (*scontrol >> 4) & 0xf; *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4); @@ -2444,10 +2445,10 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) /** * sata_set_spd_needed - is SATA spd configuration needed - * @ap: Port in question + * @link: Link in question * * Test whether the spd limit in SControl matches - * @ap->link.sata_spd_limit. This function is used to determine + * @link->sata_spd_limit. This function is used to determine * whether hardreset is necessary to apply SATA spd * configuration. * @@ -2457,21 +2458,21 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) * RETURNS: * 1 if SATA spd configuration is needed, 0 otherwise. */ -int sata_set_spd_needed(struct ata_port *ap) +int sata_set_spd_needed(struct ata_link *link) { u32 scontrol; - if (sata_scr_read(ap, SCR_CONTROL, &scontrol)) + if (sata_scr_read(link, SCR_CONTROL, &scontrol)) return 0; - return __sata_set_spd_needed(ap, &scontrol); + return __sata_set_spd_needed(link, &scontrol); } /** * sata_set_spd - set SATA spd according to spd limit - * @ap: Port to set SATA spd for + * @link: Link to set SATA spd for * - * Set SATA spd of @ap according to sata_spd_limit. + * Set SATA spd of @link according to sata_spd_limit. * * LOCKING: * Inherited from caller. @@ -2480,18 +2481,18 @@ int sata_set_spd_needed(struct ata_port *ap) * 0 if spd doesn't need to be changed, 1 if spd has been * changed. Negative errno if SCR registers are inaccessible. */ -int sata_set_spd(struct ata_port *ap) +int sata_set_spd(struct ata_link *link) { u32 scontrol; int rc; - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) return rc; - if (!__sata_set_spd_needed(ap, &scontrol)) + if (!__sata_set_spd_needed(link, &scontrol)) return 0; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) return rc; return 1; @@ -2997,7 +2998,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline) if (!(status & ATA_BUSY)) return 0; - if (!ata_port_online(ap) && status == 0xff) + if (!ata_link_online(&ap->link) && status == 0xff) return -ENODEV; if (time_after(now, deadline)) return -EBUSY; @@ -3199,12 +3200,12 @@ err_out: } /** - * sata_phy_debounce - debounce SATA phy status - * @ap: ATA port to debounce SATA phy status for + * sata_link_debounce - debounce SATA phy status + * @link: ATA link to debounce SATA phy status for * @params: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * Make sure SStatus of @ap reaches stable state, determined by +* Make sure SStatus of @link reaches stable state, determined by * holding the same value where DET is not 1 for @duration polled * every @interval, before @timeout. Timeout constraints the * beginning of the stable state. Because DET gets stuck at 1 on @@ -3220,8 +3221,8 @@ err_out: * RETURNS: * 0 on success, -errno on failure. */ -int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, - unsigned long deadline) +int sata_link_debounce(struct ata_link *link, const unsigned long *params, + unsigned long deadline) { unsigned long interval_msec = params[0]; unsigned long duration = msecs_to_jiffies(params[1]); @@ -3233,7 +3234,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, if (time_before(t, deadline)) deadline = t; - if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) + if ((rc = sata_scr_read(link, SCR_STATUS, &cur))) return rc; cur &= 0xf; @@ -3242,7 +3243,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, while (1) { msleep(interval_msec); - if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) + if ((rc = sata_scr_read(link, SCR_STATUS, &cur))) return rc; cur &= 0xf; @@ -3268,12 +3269,12 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, } /** - * sata_phy_resume - resume SATA phy - * @ap: ATA port to resume SATA phy for + * sata_link_resume - resume SATA link + * @link: ATA link to resume SATA * @params: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * Resume SATA phy of @ap and debounce it. + * Resume SATA phy @link and debounce it. * * LOCKING: * Kernel thread context (may sleep) @@ -3281,18 +3282,18 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, * RETURNS: * 0 on success, -errno on failure. */ -int sata_phy_resume(struct ata_port *ap, const unsigned long *params, - unsigned long deadline) +int sata_link_resume(struct ata_link *link, const unsigned long *params, + unsigned long deadline) { u32 scontrol; int rc; - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) return rc; scontrol = (scontrol & 0x0f0) | 0x300; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) return rc; /* Some PHYs react badly if SStatus is pounded immediately @@ -3300,7 +3301,7 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params, */ msleep(200); - return sata_phy_debounce(ap, params, deadline); + return sata_link_debounce(link, params, deadline); } /** @@ -3322,7 +3323,8 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params, */ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; @@ -3335,9 +3337,9 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) if (ehc->i.action & ATA_EH_HARDRESET) return 0; - /* if SATA, resume phy */ + /* if SATA, resume link */ if (ap->flags & ATA_FLAG_SATA) { - rc = sata_phy_resume(ap, timing, deadline); + rc = sata_link_resume(link, timing, deadline); /* whine about phy resume failure but proceed */ if (rc && rc != -EOPNOTSUPP) ata_port_printk(ap, KERN_WARNING, "failed to resume " @@ -3347,7 +3349,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) /* Wait for !BSY if the controller can wait for the first D2H * Reg FIS and we don't know that no device is attached. */ - if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) { + if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { ata_port_printk(ap, KERN_WARNING, "device not ready " @@ -3376,6 +3378,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) int ata_std_softreset(struct ata_port *ap, unsigned int *classes, unsigned long deadline) { + struct ata_link *link = &ap->link; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0; int rc; @@ -3383,7 +3386,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(link)) { classes[0] = ATA_DEV_NONE; goto out; } @@ -3401,7 +3404,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, DPRINTK("about to softreset, devmask=%x\n", devmask); rc = ata_bus_softreset(ap, devmask, deadline); /* if link is occupied, -ENODEV too is an error */ - if (rc && (rc != -ENODEV || sata_scr_valid(ap))) { + if (rc && (rc != -ENODEV || sata_scr_valid(link))) { ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc); return rc; } @@ -3433,35 +3436,36 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, unsigned long deadline) { + struct ata_link *link = &ap->link; u32 scontrol; int rc; DPRINTK("ENTER\n"); - if (sata_set_spd_needed(ap)) { + if (sata_set_spd_needed(link)) { /* SATA spec says nothing about how to reconfigure * spd. To be on the safe side, turn off phy during * reconfiguration. This works for at least ICH7 AHCI * and Sil3124. */ - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) goto out; scontrol = (scontrol & 0x0f0) | 0x304; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) goto out; - sata_set_spd(ap); + sata_set_spd(link); } /* issue phy wake/reset */ - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) goto out; scontrol = (scontrol & 0x0f0) | 0x301; - if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol))) goto out; /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 @@ -3469,8 +3473,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, */ msleep(1); - /* bring phy back */ - rc = sata_phy_resume(ap, timing, deadline); + /* bring link back */ + rc = sata_link_resume(link, timing, deadline); out: DPRINTK("EXIT, rc=%d\n", rc); return rc; @@ -3494,7 +3498,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, int sata_std_hardreset(struct ata_port *ap, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&ap->link.eh_context); + struct ata_link *link = &ap->link; + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); int rc; DPRINTK("ENTER\n"); @@ -3508,7 +3513,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, } /* TODO: phy layer with polling, timeouts, etc. */ - if (ata_port_offline(ap)) { + if (ata_link_offline(link)) { *class = ATA_DEV_NONE; DPRINTK("EXIT, link offline\n"); return 0; @@ -3547,16 +3552,17 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, */ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) { + struct ata_link *link = &ap->link; u32 serror; DPRINTK("ENTER\n"); /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(link); /* clear SError */ - if (sata_scr_read(ap, SCR_ERROR, &serror) == 0) - sata_scr_write(ap, SCR_ERROR, serror); + if (sata_scr_read(link, SCR_ERROR, &serror) == 0) + sata_scr_write(link, SCR_ERROR, serror); /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) @@ -5729,9 +5735,9 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) /** * sata_scr_valid - test whether SCRs are accessible - * @ap: ATA port to test SCR accessibility for + * @link: ATA link to test SCR accessibility for * - * Test whether SCRs are accessible for @ap. + * Test whether SCRs are accessible for @link. * * LOCKING: * None. @@ -5739,18 +5745,20 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) * RETURNS: * 1 if SCRs are accessible, 0 otherwise. */ -int sata_scr_valid(struct ata_port *ap) +int sata_scr_valid(struct ata_link *link) { + struct ata_port *ap = link->ap; + return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read; } /** * sata_scr_read - read SCR register of the specified port - * @ap: ATA port to read SCR for + * @link: ATA link to read SCR for * @reg: SCR to read * @val: Place to store read value * - * Read SCR register @reg of @ap into *@val. This function is + * Read SCR register @reg of @link into *@val. This function is * guaranteed to succeed if the cable type of the port is SATA * and the port implements ->scr_read. * @@ -5760,20 +5768,22 @@ int sata_scr_valid(struct ata_port *ap) * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_read(struct ata_port *ap, int reg, u32 *val) +int sata_scr_read(struct ata_link *link, int reg, u32 *val) { - if (sata_scr_valid(ap)) + struct ata_port *ap = link->ap; + + if (sata_scr_valid(link)) return ap->ops->scr_read(ap, reg, val); return -EOPNOTSUPP; } /** * sata_scr_write - write SCR register of the specified port - * @ap: ATA port to write SCR for + * @link: ATA link to write SCR for * @reg: SCR to write * @val: value to write * - * Write @val to SCR register @reg of @ap. This function is + * Write @val to SCR register @reg of @link. This function is * guaranteed to succeed if the cable type of the port is SATA * and the port implements ->scr_read. * @@ -5783,16 +5793,18 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val) * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_write(struct ata_port *ap, int reg, u32 val) +int sata_scr_write(struct ata_link *link, int reg, u32 val) { - if (sata_scr_valid(ap)) + struct ata_port *ap = link->ap; + + if (sata_scr_valid(link)) return ap->ops->scr_write(ap, reg, val); return -EOPNOTSUPP; } /** * sata_scr_write_flush - write SCR register of the specified port and flush - * @ap: ATA port to write SCR for + * @link: ATA link to write SCR for * @reg: SCR to write * @val: value to write * @@ -5805,11 +5817,12 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val) * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) +int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) { + struct ata_port *ap = link->ap; int rc; - if (sata_scr_valid(ap)) { + if (sata_scr_valid(link)) { rc = ap->ops->scr_write(ap, reg, val); if (rc == 0) rc = ap->ops->scr_read(ap, reg, &val); @@ -5819,12 +5832,12 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) } /** - * ata_port_online - test whether the given port is online - * @ap: ATA port to test + * ata_link_online - test whether the given link is online + * @link: ATA link to test * - * Test whether @ap is online. Note that this function returns 0 - * if online status of @ap cannot be obtained, so - * ata_port_online(ap) != !ata_port_offline(ap). + * Test whether @link is online. Note that this function returns + * 0 if online status of @link cannot be obtained, so + * ata_link_online(link) != !ata_link_offline(link). * * LOCKING: * None. @@ -5832,22 +5845,23 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) * RETURNS: * 1 if the port online status is available and online. */ -int ata_port_online(struct ata_port *ap) +int ata_link_online(struct ata_link *link) { u32 sstatus; - if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3) + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && + (sstatus & 0xf) == 0x3) return 1; return 0; } /** - * ata_port_offline - test whether the given port is offline - * @ap: ATA port to test + * ata_link_offline - test whether the given link is offline + * @link: ATA link to test * - * Test whether @ap is offline. Note that this function returns - * 0 if offline status of @ap cannot be obtained, so - * ata_port_online(ap) != !ata_port_offline(ap). + * Test whether @link is offline. Note that this function + * returns 0 if offline status of @link cannot be obtained, so + * ata_link_online(link) != !ata_link_offline(link). * * LOCKING: * None. @@ -5855,11 +5869,12 @@ int ata_port_online(struct ata_port *ap) * RETURNS: * 1 if the port offline status is available and offline. */ -int ata_port_offline(struct ata_port *ap) +int ata_link_offline(struct ata_link *link) { u32 sstatus; - if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3) + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && + (sstatus & 0xf) != 0x3) return 1; return 0; } @@ -6397,7 +6412,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ap->cbl = ATA_CBL_SATA; /* init sata_spd_limit to the current value */ - if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { + if (sata_scr_read(&ap->link, SCR_CONTROL, &scontrol) == 0) { int spd = (scontrol >> 4) & 0xf; if (spd) ap->link.hw_sata_spd_limit &= (1 << spd) - 1; @@ -6924,8 +6939,8 @@ EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(ata_dev_disable); EXPORT_SYMBOL_GPL(sata_set_spd); -EXPORT_SYMBOL_GPL(sata_phy_debounce); -EXPORT_SYMBOL_GPL(sata_phy_resume); +EXPORT_SYMBOL_GPL(sata_link_debounce); +EXPORT_SYMBOL_GPL(sata_link_resume); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); @@ -6952,8 +6967,8 @@ EXPORT_SYMBOL_GPL(sata_scr_valid); EXPORT_SYMBOL_GPL(sata_scr_read); EXPORT_SYMBOL_GPL(sata_scr_write); EXPORT_SYMBOL_GPL(sata_scr_write_flush); -EXPORT_SYMBOL_GPL(ata_port_online); -EXPORT_SYMBOL_GPL(ata_port_offline); +EXPORT_SYMBOL_GPL(ata_link_online); +EXPORT_SYMBOL_GPL(ata_link_offline); #ifdef CONFIG_PM EXPORT_SYMBOL_GPL(ata_host_suspend); EXPORT_SYMBOL_GPL(ata_host_resume); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8c37ec0bbf6c..48ca68b3979b 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1501,7 +1501,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, /* speed down? */ if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ - if (sata_down_spd_limit(dev->link->ap) == 0) { + if (sata_down_spd_limit(dev->link) == 0) { action |= ATA_EH_HARDRESET; goto done; } @@ -1561,7 +1561,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, */ static void ata_eh_autopsy(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; unsigned int all_err_mask = 0; int tag, is_io = 0; u32 serror; @@ -1573,7 +1574,7 @@ static void ata_eh_autopsy(struct ata_port *ap) return; /* obtain and analyze SError */ - rc = sata_scr_read(ap, SCR_ERROR, &serror); + rc = sata_scr_read(link, SCR_ERROR, &serror); if (rc == 0) { ehc->i.serror |= serror; ata_eh_analyze_serror(ap); @@ -1782,7 +1783,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); int try = 0; @@ -1800,7 +1802,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, */ action = ehc->i.action; ehc->i.action &= ~ATA_EH_RESET_MASK; - if (softreset && (!hardreset || (!sata_set_spd_needed(ap) && + if (softreset && (!hardreset || (!sata_set_spd_needed(link) && !(action & ATA_EH_HARDRESET)))) ehc->i.action |= ATA_EH_SOFTRESET; else @@ -1814,7 +1816,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, "port disabled. ignoring.\n"); ehc->i.action &= ~ATA_EH_RESET_MASK; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; rc = 0; @@ -1832,7 +1834,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset = softreset; else { /* prereset told us not to reset, bang classes and return */ - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; rc = 0; goto out; @@ -1902,7 +1904,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, if (rc == -EPIPE || try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1) - sata_down_spd_limit(ap); + sata_down_spd_limit(link); if (hardreset) reset = hardreset; goto retry; @@ -1914,12 +1916,12 @@ static int ata_eh_reset(struct ata_port *ap, int classify, /* After the reset, the device state is PIO 0 and the * controller state is undefined. Record the mode. */ - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) dev->pio_mode = XFER_PIO_0; /* record current link speed */ - if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0) - ap->link.sata_spd = (sstatus >> 4) & 0xf; + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) + link->sata_spd = (sstatus >> 4) & 0xf; if (postreset) postreset(ap, classes); @@ -1957,7 +1959,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, readid_flags |= ATA_READID_POSTRESET; if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { rc = -EIO; goto err; } @@ -2079,7 +2081,6 @@ static int ata_eh_skip_recovery(struct ata_port *ap) static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) { - struct ata_port *ap = dev->link->ap; struct ata_eh_context *ehc = &dev->link->eh_context; ehc->tries[dev->devno]--; @@ -2096,7 +2097,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) /* This is the last chance, better to slow * down than lose it. */ - sata_down_spd_limit(ap); + sata_down_spd_limit(dev->link); ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); } } @@ -2106,7 +2107,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) ata_dev_disable(dev); /* detach if offline */ - if (ata_port_offline(ap)) + if (ata_link_offline(dev->link)) ata_eh_detach_dev(dev); /* probe if requested */ diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 2100cd61ed69..dd528dbd9ccf 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -500,7 +500,7 @@ void ata_bmdma_error_handler(struct ata_port *ap) ata_reset_fn_t hardreset; hardreset = NULL; - if (sata_scr_valid(ap)) + if (sata_scr_valid(&ap->link)) hardreset = sata_std_hardreset; ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 564cd234c805..700843a9f30a 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -78,8 +78,8 @@ extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags); extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags); extern int ata_dev_configure(struct ata_device *dev); -extern int sata_down_spd_limit(struct ata_port *ap); -extern int sata_set_spd_needed(struct ata_port *ap); +extern int sata_down_spd_limit(struct ata_link *link); +extern int sata_set_spd_needed(struct ata_link *link); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); extern void ata_sg_clean(struct ata_queued_cmd *qc); diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index aab068fbb7bc..63fe99a10cd1 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -612,7 +612,7 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { classes[0] = ATA_DEV_NONE; goto out; } diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 3c0ef7a2f2fe..f2b1bea934bc 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -435,7 +435,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, msleep(1); writew(val & ~IDMA_CTL_RST_ATA, idma_ctl); - rc = sata_phy_resume(ap, timing, deadline); + rc = sata_link_resume(&ap->link, timing, deadline); if (rc) { ata_port_printk(ap, KERN_WARNING, "failed to resume " "link after reset (errno=%d)\n", rc); @@ -443,7 +443,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, } *class = ATA_DEV_NONE; - if (ata_port_online(ap)) { + if (ata_link_online(&ap->link)) { struct ata_taskfile tf; /* wait a while before checking status */ diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 246e7c5fdce8..8e63c60adaff 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1423,8 +1423,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) /* just a guess: do we need to do this? should we * expand this, and do it in all cases? */ - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(&ap->link, SCR_ERROR, &serr); + sata_scr_write_flush(&ap->link, SCR_ERROR, serr); } edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -1468,8 +1468,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) } if (edma_err_cause & EDMA_ERR_SERR) { - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(&ap->link, SCR_ERROR, &serr); + sata_scr_write_flush(&ap->link, SCR_ERROR, serr); err_mask = AC_ERR_ATA_BUS; action |= ATA_EH_HARDRESET; } @@ -1687,7 +1687,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) for (i = 0; i < host->n_ports; i++) { ap = host->ports[i]; - if (!ata_port_offline(ap)) { + if (!ata_link_offline(&ap->link)) { ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); if (!printed++) @@ -2198,14 +2198,14 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class, /* Issue COMRESET via SControl */ comreset_retry: - sata_scr_write_flush(ap, SCR_CONTROL, 0x301); + sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301); msleep(1); - sata_scr_write_flush(ap, SCR_CONTROL, 0x300); + sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300); msleep(20); do { - sata_scr_read(ap, SCR_STATUS, &sstatus); + sata_scr_read(&ap->link, SCR_STATUS, &sstatus); if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0)) break; @@ -2230,7 +2230,7 @@ comreset_retry: } #endif - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { *class = ATA_DEV_NONE; return; } @@ -2285,7 +2285,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) if (ehc->i.action & ATA_EH_HARDRESET) return 0; - if (ata_port_online(ap)) + if (ata_link_online(&ap->link)) rc = ata_wait_ready(ap, deadline); else rc = -ENODEV; @@ -2313,11 +2313,11 @@ static void mv_postreset(struct ata_port *ap, unsigned int *classes) u32 serr; /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(&ap->link); /* clear SError */ - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(&ap->link, SCR_ERROR, &serr); + sata_scr_write_flush(&ap->link, SCR_ERROR, serr); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 620d0675d18a..c7238ce83541 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -475,7 +475,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc) buf32[2] = 0; /* no next-packet */ /* select drive */ - if (sata_scr_valid(ap)) { + if (sata_scr_valid(&ap->link)) { dev_sel = PDC_DEVICE_SATA; } else { dev_sel = ATA_DEVICE_OBS; @@ -643,7 +643,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR)) ac_err_mask |= AC_ERR_HOST_BUS; - if (sata_scr_valid(ap)) { + if (sata_scr_valid(&ap->link)) { u32 serror; pdc_sata_scr_read(ap, SCR_ERROR, &serror); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 2d8334e7921d..0cd40d5215fe 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -593,7 +593,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; goto out; @@ -650,10 +650,10 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, u32 tmp; /* sil24 does the right thing(tm) without any protection */ - sata_set_spd(ap); + sata_set_spd(&ap->link); tout_msec = 100; - if (ata_port_online(ap)) + if (ata_link_online(&ap->link)) tout_msec = 5000; writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); @@ -663,14 +663,14 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, /* SStatus oscillates between zero and valid status after * DEV_RST, debounce it. */ - rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline); + rc = sata_link_debounce(&ap->link, sata_deb_timing_long, deadline); if (rc) { reason = "PHY debouncing failed"; goto err; } if (tmp & PORT_CS_DEV_RST) { - if (ata_port_offline(ap)) + if (ata_link_offline(&ap->link)) return 0; reason = "link not ready"; goto err; diff --git a/include/linux/libata.h b/include/linux/libata.h index 62fa8cf677a1..e7882ba63e78 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -696,16 +696,16 @@ static inline int ata_port_is_dummy(struct ata_port *ap) return ap->ops == &ata_dummy_port_ops; } -extern void sata_print_link_status(struct ata_port *ap); +extern void sata_print_link_status(struct ata_link *link); extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap); extern void ata_bus_reset(struct ata_port *ap); -extern int sata_set_spd(struct ata_port *ap); -extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param, - unsigned long deadline); -extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param, - unsigned long deadline); +extern int sata_set_spd(struct ata_link *link); +extern int sata_link_debounce(struct ata_link *link, + const unsigned long *params, unsigned long deadline); +extern int sata_link_resume(struct ata_link *link, const unsigned long *params, + unsigned long deadline); extern int ata_std_prereset(struct ata_port *ap, unsigned long deadline); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes, unsigned long deadline); @@ -753,12 +753,12 @@ extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *); extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), struct ata_port *ap); extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); -extern int sata_scr_valid(struct ata_port *ap); -extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val); -extern int sata_scr_write(struct ata_port *ap, int reg, u32 val); -extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val); -extern int ata_port_online(struct ata_port *ap); -extern int ata_port_offline(struct ata_port *ap); +extern int sata_scr_valid(struct ata_link *link); +extern int sata_scr_read(struct ata_link *link, int reg, u32 *val); +extern int sata_scr_write(struct ata_link *link, int reg, u32 val); +extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val); +extern int ata_link_online(struct ata_link *link); +extern int ata_link_offline(struct ata_link *link); #ifdef CONFIG_PM extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern void ata_host_resume(struct ata_host *host); From 955e57dfde4ff75e4d7329ac7a3d645b16015309 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2389/2804] libata-link: linkify EH action helpers Make ata_eh_about_to_do() and ata_eh_done() deal with ata_link instead of ata_port. This patch introduces no behavior change. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 48ca68b3979b..fc4b6413b192 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -947,23 +947,24 @@ static void ata_eh_detach_dev(struct ata_device *dev) /** * ata_eh_about_to_do - about to perform eh_action - * @ap: target ATA port + * @link: target ATA link * @dev: target ATA dev for per-dev action (can be NULL) * @action: action about to be performed * * Called just before performing EH actions to clear related bits - * in @ap->link.eh_info such that eh actions are not - * unnecessarily repeated. + * in @link->eh_info such that eh actions are not unnecessarily + * repeated. * * LOCKING: * None. */ -static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, +static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, unsigned int action) { + struct ata_port *ap = link->ap; + struct ata_eh_info *ehi = &link->eh_info; + struct ata_eh_context *ehc = &link->eh_context; unsigned long flags; - struct ata_eh_info *ehi = &ap->link.eh_info; - struct ata_eh_context *ehc = &ap->link.eh_context; spin_lock_irqsave(ap->lock, flags); @@ -980,7 +981,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(&ap->link, dev, ehi, action); + ata_eh_clear_action(link, dev, ehi, action); if (!(ehc->i.flags & ATA_EHI_QUIET)) ap->pflags |= ATA_PFLAG_RECOVERED; @@ -990,20 +991,20 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, /** * ata_eh_done - EH action complete - * @ap: target ATA port +* @ap: target ATA port * @dev: target ATA dev for per-dev action (can be NULL) * @action: action just completed * * Called right after performing EH actions to clear related bits - * in @ap->link.eh_context. + * in @link->eh_context. * * LOCKING: * None. */ -static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, +static void ata_eh_done(struct ata_link *link, struct ata_device *dev, unsigned int action) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_eh_context *ehc = &link->eh_context; /* if reset is complete, clear all reset actions & reset modifier */ if (action & ATA_EH_RESET_MASK) { @@ -1011,7 +1012,7 @@ static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(&ap->link, dev, &ehc->i, action); + ata_eh_clear_action(link, dev, &ehc->i, action); } /** @@ -1795,7 +1796,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, int rc; /* about to reset */ - ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); /* Determine which reset to use and record in ehc->i.action. * prereset() may examine and modify it. @@ -1877,7 +1878,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, goto out; } - ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); + ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); rc = ata_do_reset(ap, reset, classes, deadline); if (rc == 0 && classify && @@ -1927,7 +1928,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, postreset(ap, classes); /* reset successful, schedule revalidation */ - ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); ehc->i.action |= ATA_EH_REVALIDATE; } out: @@ -1964,12 +1965,12 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, goto err; } - ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); + ata_eh_about_to_do(&ap->link, dev, ATA_EH_REVALIDATE); rc = ata_dev_revalidate(dev, readid_flags); if (rc) goto err; - ata_eh_done(ap, dev, ATA_EH_REVALIDATE); + ata_eh_done(&ap->link, dev, ATA_EH_REVALIDATE); /* Configuration may have changed, reconfigure * transfer mode. From cc0680a580b5be81a1ca321b58f8e9b80b5c1052 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2390/2804] libata-link: linkify reset Make reset methods and related functions deal with ata_link instead of ata_port. * ata_do_reset() * ata_eh_reset() * all prereset/reset/postreset methods and related functions This patch introduces no behavior change. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 34 +++++++++++++------------ drivers/ata/ata_piix.c | 7 +++--- drivers/ata/libata-core.c | 49 ++++++++++++++++++------------------- drivers/ata/libata-eh.c | 35 +++++++++++++------------- drivers/ata/pata_amd.c | 16 ++++++------ drivers/ata/pata_artop.c | 12 +++++---- drivers/ata/pata_atiixp.c | 5 ++-- drivers/ata/pata_efar.c | 7 +++--- drivers/ata/pata_hpt37x.c | 12 +++++---- drivers/ata/pata_hpt3x2n.c | 7 +++--- drivers/ata/pata_it8213.c | 7 +++--- drivers/ata/pata_jmicron.c | 8 +++--- drivers/ata/pata_marvell.c | 7 +++--- drivers/ata/pata_mpiix.c | 5 ++-- drivers/ata/pata_ns87410.c | 7 +++--- drivers/ata/pata_oldpiix.c | 7 +++--- drivers/ata/pata_opti.c | 7 +++--- drivers/ata/pata_optidma.c | 7 +++--- drivers/ata/pata_pdc2027x.c | 8 +++--- drivers/ata/pata_sil680.c | 7 +++--- drivers/ata/pata_sis.c | 7 +++--- drivers/ata/pata_sl82c105.c | 7 +++--- drivers/ata/pata_triflex.c | 7 +++--- drivers/ata/pata_via.c | 5 ++-- drivers/ata/sata_inic162x.c | 13 +++++----- drivers/ata/sata_mv.c | 19 ++++++++------ drivers/ata/sata_nv.c | 4 +-- drivers/ata/sata_sil24.c | 26 +++++++++++--------- drivers/ata/sata_via.c | 5 ++-- drivers/scsi/ipr.c | 8 +++--- include/linux/libata.h | 19 +++++++------- 31 files changed, 203 insertions(+), 171 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6e5f69a3a0c2..e38ae12d0148 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1042,9 +1042,10 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, return 0; } -static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, +static int ahci_do_softreset(struct ata_link *link, unsigned int *class, int pmp, unsigned long deadline) { + struct ata_port *ap = link->ap; const char *reason = NULL; unsigned long now, msecs; struct ata_taskfile tf; @@ -1052,7 +1053,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_link_offline(&ap->link)) { + if (ata_link_offline(link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; return 0; @@ -1061,10 +1062,10 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, /* prepare for SRST (AHCI-1.1 10.4.1) */ rc = ahci_kick_engine(ap, 1); if (rc) - ata_port_printk(ap, KERN_WARNING, + ata_link_printk(link, KERN_WARNING, "failed to reset engine (errno=%d)", rc); - ata_tf_init(ap->link.device, &tf); + ata_tf_init(link->device, &tf); /* issue the first D2H Register FIS */ msecs = 0; @@ -1109,19 +1110,20 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, return 0; fail: - ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); return rc; } -static int ahci_softreset(struct ata_port *ap, unsigned int *class, +static int ahci_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return ahci_do_softreset(ap, class, 0, deadline); + return ahci_do_softreset(link, class, 0, deadline); } -static int ahci_hardreset(struct ata_port *ap, unsigned int *class, +static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; @@ -1132,15 +1134,15 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ - ata_tf_init(ap->link.device, &tf); + ata_tf_init(link->device, &tf); tf.command = 0x80; ata_tf_to_fis(&tf, 0, 0, d2h_fis); - rc = sata_std_hardreset(ap, class, deadline); + rc = sata_std_hardreset(link, class, deadline); ahci_start_engine(ap); - if (rc == 0 && ata_link_online(&ap->link)) + if (rc == 0 && ata_link_online(link)) *class = ahci_dev_classify(ap); if (*class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; @@ -1149,9 +1151,10 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, return rc; } -static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, +static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; u32 serror; int rc; @@ -1159,7 +1162,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); - rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->link.eh_context), + rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline); /* vt8251 needs SError cleared for the port to operate */ @@ -1176,12 +1179,13 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, return rc ?: -EAGAIN; } -static void ahci_postreset(struct ata_port *ap, unsigned int *class) +static void ahci_postreset(struct ata_link *link, unsigned int *class) { + struct ata_port *ap = link->ap; void __iomem *port_mmio = ahci_port_base(ap); u32 new_tmp, tmp; - ata_std_postreset(ap, class); + ata_std_postreset(link, class); /* Make sure port's ATAPI bit is set appropriately */ new_tmp = tmp = readl(port_mmio + PORT_CMD); diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 92c2d5082bef..03fe493026eb 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -657,19 +657,20 @@ static int ich_pata_cable_detect(struct ata_port *ap) /** * piix_pata_prereset - prereset for PATA host controller - * @ap: Target port + * @link: Target link * @deadline: deadline jiffies for the operation * * LOCKING: * None (inherited from caller). */ -static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline) +static int piix_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); if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void piix_pata_error_handler(struct ata_port *ap) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 6f99dee6b6d2..73f66f4e1eeb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3306,10 +3306,10 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, /** * ata_std_prereset - prepare for reset - * @ap: ATA port to be reset + * @link: ATA link to be reset * @deadline: deadline jiffies for the operation * - * @ap is about to be reset. Initialize it. Failure from + * @link is about to be reset. Initialize it. Failure from * prereset makes libata abort whole reset sequence and give up * that port, so prereset should be best-effort. It does its * best to prepare for reset sequence but if things go wrong, it @@ -3321,9 +3321,9 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_prereset(struct ata_port *ap, unsigned long deadline) +int ata_std_prereset(struct ata_link *link, unsigned long deadline) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; @@ -3342,7 +3342,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) rc = sata_link_resume(link, timing, deadline); /* whine about phy resume failure but proceed */ if (rc && rc != -EOPNOTSUPP) - ata_port_printk(ap, KERN_WARNING, "failed to resume " + ata_link_printk(link, KERN_WARNING, "failed to resume " "link for reset (errno=%d)\n", rc); } @@ -3352,7 +3352,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { - ata_port_printk(ap, KERN_WARNING, "device not ready " + ata_link_printk(link, KERN_WARNING, "device not ready " "(errno=%d), forcing hardreset\n", rc); ehc->i.action |= ATA_EH_HARDRESET; } @@ -3363,7 +3363,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) /** * ata_std_softreset - reset host port via ATA SRST - * @ap: port to reset + * @link: ATA link to reset * @classes: resulting classes of attached devices * @deadline: deadline jiffies for the operation * @@ -3375,10 +3375,10 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_softreset(struct ata_port *ap, unsigned int *classes, +int ata_std_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0; int rc; @@ -3405,7 +3405,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, rc = ata_bus_softreset(ap, devmask, deadline); /* if link is occupied, -ENODEV too is an error */ if (rc && (rc != -ENODEV || sata_scr_valid(link))) { - ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc); + ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); return rc; } @@ -3420,12 +3420,12 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, } /** - * sata_port_hardreset - reset port via SATA phy reset - * @ap: port to reset + * sata_link_hardreset - reset link via SATA phy reset + * @link: link to reset * @timing: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * SATA phy-reset host port using DET bits of SControl register. + * SATA phy-reset @link using DET bits of SControl register. * * LOCKING: * Kernel thread context (may sleep) @@ -3433,10 +3433,9 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, * RETURNS: * 0 on success, -errno otherwise. */ -int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, +int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, unsigned long deadline) { - struct ata_link *link = &ap->link; u32 scontrol; int rc; @@ -3482,7 +3481,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, /** * sata_std_hardreset - reset host port via SATA phy reset - * @ap: port to reset + * @link: link to reset * @class: resulting class of attached device * @deadline: deadline jiffies for the operation * @@ -3495,19 +3494,19 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, unsigned int *class, +int sata_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); int rc; DPRINTK("ENTER\n"); /* do hardreset */ - rc = sata_port_hardreset(ap, timing, deadline); + rc = sata_link_hardreset(link, timing, deadline); if (rc) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); return rc; } @@ -3525,7 +3524,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); return rc; } @@ -3540,7 +3539,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, /** * ata_std_postreset - standard postreset callback - * @ap: the target ata_port + * @link: the target ata_link * @classes: classes of attached devices * * This function is invoked after a successful reset. Note that @@ -3550,9 +3549,9 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, * LOCKING: * Kernel thread context (may sleep) */ -void ata_std_postreset(struct ata_port *ap, unsigned int *classes) +void ata_std_postreset(struct ata_link *link, unsigned int *classes) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; u32 serror; DPRINTK("ENTER\n"); @@ -6946,7 +6945,7 @@ EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); -EXPORT_SYMBOL_GPL(sata_port_hardreset); +EXPORT_SYMBOL_GPL(sata_link_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index fc4b6413b192..0a9ce34a0e64 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1737,16 +1737,16 @@ static void ata_eh_report(struct ata_port *ap) } } -static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, +static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { struct ata_device *dev; int rc; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_UNKNOWN; - rc = reset(ap, classes, deadline); + rc = reset(link, classes, deadline); if (rc) return rc; @@ -1754,12 +1754,12 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, * is complete and convert all ATA_DEV_UNKNOWN to * ATA_DEV_NONE. */ - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) if (classes[dev->devno] != ATA_DEV_UNKNOWN) break; if (dev) { - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (classes[dev->devno] == ATA_DEV_UNKNOWN) classes[dev->devno] = ATA_DEV_NONE; } @@ -1780,11 +1780,10 @@ static int ata_eh_followup_srst_needed(int rc, int classify, return 0; } -static int ata_eh_reset(struct ata_port *ap, int classify, +static int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_link *link = &ap->link; struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); @@ -1810,10 +1809,10 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ehc->i.action |= ATA_EH_HARDRESET; if (prereset) { - rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT); + rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT); if (rc) { if (rc == -ENOENT) { - ata_port_printk(ap, KERN_DEBUG, + ata_link_printk(link, KERN_DEBUG, "port disabled. ignoring.\n"); ehc->i.action &= ~ATA_EH_RESET_MASK; @@ -1822,7 +1821,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, rc = 0; } else - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "prereset failed (errno=%d)\n", rc); goto out; } @@ -1854,7 +1853,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, /* shut up during boot probing */ if (verbose) - ata_port_printk(ap, KERN_INFO, "%s resetting port\n", + ata_link_printk(link, KERN_INFO, "%s resetting link\n", reset == softreset ? "soft" : "hard"); /* mark that this EH session started with reset */ @@ -1863,7 +1862,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, else ehc->i.flags |= ATA_EHI_DID_SOFTRESET; - rc = ata_do_reset(ap, reset, classes, deadline); + rc = ata_do_reset(link, reset, classes, deadline); if (reset == hardreset && ata_eh_followup_srst_needed(rc, classify, classes)) { @@ -1871,7 +1870,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset = softreset; if (!reset) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "follow-up softreset required " "but no softreset avaliable\n"); rc = -EINVAL; @@ -1879,11 +1878,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify, } ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); - rc = ata_do_reset(ap, reset, classes, deadline); + rc = ata_do_reset(link, reset, classes, deadline); if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "classification failed\n"); rc = -EINVAL; goto out; @@ -1896,7 +1895,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, if (time_before(now, deadline)) { unsigned long delta = deadline - jiffies; - ata_port_printk(ap, KERN_WARNING, "reset failed " + ata_link_printk(link, KERN_WARNING, "reset failed " "(errno=%d), retrying in %u secs\n", rc, (jiffies_to_msecs(delta) + 999) / 1000); @@ -1925,7 +1924,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, link->sata_spd = (sstatus >> 4) & 0xf; if (postreset) - postreset(ap, classes); + postreset(link, classes); /* reset successful, schedule revalidation */ ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); @@ -2202,7 +2201,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (ehc->i.action & ATA_EH_RESET_MASK) { ata_eh_freeze_port(ap); - rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset, + rc = ata_eh_reset(&ap->link, ata_port_nr_vacant(ap), prereset, softreset, hardreset, postreset); if (rc) { ata_port_printk(ap, KERN_ERR, diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 04048fcf6305..d0cebe16a8ee 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -119,27 +119,28 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse } /** - * amd_probe_init - perform reset handling - * @ap: ATA port + * amd_pre_reset - perform reset handling + * @link: ATA link * @deadline: deadline jiffies for the operation * * Reset sequence checking enable bits to see which ports are * active. */ -static int amd_pre_reset(struct ata_port *ap, unsigned long deadline) +static int amd_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits amd_enable_bits[] = { { 0x40, 1, 0x02, 0x02 }, { 0x40, 1, 0x01, 0x01 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void amd_error_handler(struct ata_port *ap) @@ -221,25 +222,26 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) /** * nv_probe_init - cable detection - * @ap: ATA port + * @lin: ATA link * * Perform cable detection. The BIOS stores this in PCI config * space for us. */ -static int nv_pre_reset(struct ata_port *ap, unsigned long deadline) +static int nv_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits nv_enable_bits[] = { { 0x50, 1, 0x02, 0x02 }, { 0x50, 1, 0x01, 0x01 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void nv_error_handler(struct ata_port *ap) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index b5352ebecef9..361f2fca7e54 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -40,8 +40,9 @@ static int clock = 0; -static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline) +static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); const struct pci_bits artop_enable_bits[] = { { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ @@ -51,7 +52,7 @@ static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -71,27 +72,28 @@ static void artop6210_error_handler(struct ata_port *ap) /** * artop6260_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * The ARTOP hardware reports the cable detect bits in register 0x49. * Nothing complicated needed here. */ -static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline) +static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits artop_enable_bits[] = { { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Odd numbered device ids are the units with enable bits (the -R cards) */ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 86f85a2cab7e..656f4d0a5728 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -33,8 +33,9 @@ enum { ATIIXP_IDE_UDMA_MODE = 0x56 }; -static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline) +static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; static const struct pci_bits atiixp_enable_bits[] = { { 0x48, 1, 0x01, 0x00 }, { 0x48, 1, 0x08, 0x00 } @@ -44,7 +45,7 @@ static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void atiixp_error_handler(struct ata_port *ap) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index c8ba59c56114..9f6fae6e38bf 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -26,25 +26,26 @@ /** * efar_pre_reset - Enable bits - * @ap: Port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Perform cable detection for the EFAR ATA interface. This is * different to the PIIX arrangement */ -static int efar_pre_reset(struct ata_port *ap, unsigned long deadline) +static int efar_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits efar_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index c5ddd937dbf2..1a4d0ad68d18 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -304,15 +304,16 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) /** * hpt37x_pre_reset - reset the hpt37x bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the initial reset handling for the 370/372 and 374 func 0 */ -static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline) { u8 scr2, ata66; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits hpt37x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -337,7 +338,7 @@ static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -352,7 +353,7 @@ static void hpt37x_error_handler(struct ata_port *ap) ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } -static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits hpt37x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -360,6 +361,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) }; u16 mcr3, mcr6; u8 ata66; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) @@ -387,7 +389,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index f8f234bfc8ce..739a89180eb9 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -141,21 +141,22 @@ static int hpt3x2n_cable_detect(struct ata_port *ap) /** * hpt3x2n_pre_reset - reset the hpt3x2n bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the initial reset handling for the 3x2n series controllers. * Reset the hardware and state machine, */ -static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Reset the state machine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index b8af55e89156..1daf1e19bdfc 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -23,23 +23,24 @@ /** * it8213_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * Filter out ports by the enable bits before doing the normal reset * and probe. */ -static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline) +static int it8213_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits it8213_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 4d67f238eee2..1619b86b74af 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -29,7 +29,7 @@ typedef enum { /** * jmicron_pre_reset - check for 40/80 pin - * @ap: Port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Perform the PATA port setup we need. @@ -39,9 +39,9 @@ typedef enum { * and setup here. We assume that has been done by init_one and the * BIOS. */ - -static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline) +static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 control; u32 control5; @@ -103,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline) ap->cbl = ATA_CBL_SATA; break; } - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index b45506f1ef73..b4dd18f3fa5d 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -24,14 +24,15 @@ /** * marvell_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * Perform the PATA port setup we need. */ -static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline) +static int marvell_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 devices; void __iomem *barp; @@ -54,7 +55,7 @@ static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline) (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static int marvell_cable_detect(struct ata_port *ap) diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 4ea42838297e..36c964b9e7da 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -46,15 +46,16 @@ enum { SECONDARY = (1 << 14) }; -static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline) +static int mpiix_pre_reset(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 mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 }; if (!pci_test_config_bits(pdev, &mpiix_enable_bits)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 2f5d714ebfc4..65a217727718 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -32,14 +32,15 @@ /** * ns87410_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Check enabled ports */ -static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline) +static int ns87410_pre_reset(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 ns87410_enable_bits[] = { { 0x43, 1, 0x08, 0x08 }, @@ -49,7 +50,7 @@ static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 091a70a0ef1c..5b2c86fe9fc2 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -29,14 +29,15 @@ /** * oldpiix_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline) +static int oldpiix_pre_reset(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 oldpiix_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ @@ -46,7 +47,7 @@ static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 458bf67f766f..5770c7755a62 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -46,14 +46,15 @@ enum { /** * opti_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int opti_pre_reset(struct ata_port *ap, unsigned long deadline) +static int opti_pre_reset(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 opti_enable_bits[] = { { 0x45, 1, 0x80, 0x00 }, @@ -63,7 +64,7 @@ static int opti_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index f8234d7fd825..39fcba800077 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -47,14 +47,15 @@ static int pci_clock; /* 0 = 33 1 = 25 */ /** * optidma_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline) +static int optidma_pre_reset(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 optidma_enable_bits = { 0x40, 1, 0x08, 0x00 @@ -63,7 +64,7 @@ static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline) if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 83c90cabc7ff..ba39efbe5405 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -300,7 +300,7 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap) /** * pdc2027x_prereset - prereset for PATA host controller - * @ap: Target port + * @link: Target link * @deadline: deadline jiffies for the operation * * Probeinit including cable detection. @@ -309,12 +309,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap) * None (inherited from caller). */ -static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline) +static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline) { /* Check whether port enabled */ - if (!pdc2027x_port_enabled(ap)) + if (!pdc2027x_port_enabled(link->ap)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 40395804a66f..45515a22d856 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -95,15 +95,16 @@ static int sil680_cable_detect(struct ata_port *ap) { /** * sil680_bus_reset - reset the SIL680 bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the SIL680 housekeeping when doing an ATA bus reset */ -static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes, +static int sil680_bus_reset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); unsigned long addr = sil680_selreg(ap, 0); u8 reset; @@ -112,7 +113,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes, pci_write_config_byte(pdev, addr, reset | 0x03); udelay(25); pci_write_config_byte(pdev, addr, reset); - return ata_std_softreset(ap, classes, deadline); + return ata_std_softreset(link, classes, deadline); } static void sil680_error_handler(struct ata_port *ap) diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 9d6f81d52e18..b72227676f00 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -133,19 +133,20 @@ static int sis_66_cable_detect(struct ata_port *ap) /** * sis_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int sis_pre_reset(struct ata_port *ap, unsigned long deadline) +static int sis_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits sis_enable_bits[] = { { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) @@ -154,7 +155,7 @@ static int sis_pre_reset(struct ata_port *ap, unsigned long deadline) /* Clear the FIFO settings. We can't enable the FIFO until we know we are poking at a disk */ pci_write_config_byte(pdev, 0x4B, 0); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index c0f43bb25956..375c3705dc43 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -43,23 +43,24 @@ enum { /** * sl82c105_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline) +static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits sl82c105_enable_bits[] = { { 0x40, 1, 0x01, 0x01 }, { 0x40, 1, 0x10, 0x10 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index af21f443db6e..bc4b6f6be963 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -47,25 +47,26 @@ /** * triflex_prereset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int triflex_prereset(struct ata_port *ap, unsigned long deadline) +static int triflex_prereset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits triflex_enable_bits[] = { { 0x80, 1, 0x01, 0x01 }, { 0x80, 1, 0x02, 0x02 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index f143db4559e0..b612808a319e 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -187,8 +187,9 @@ static int via_cable_detect(struct ata_port *ap) { return ATA_CBL_PATA40; } -static int via_pre_reset(struct ata_port *ap, unsigned long deadline) +static int via_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; const struct via_isa_bridge *config = ap->host->private_data; if (!(config->flags & VIA_NO_ENABLES)) { @@ -201,7 +202,7 @@ static int via_pre_reset(struct ata_port *ap, unsigned long deadline) return -ENOENT; } - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index f2b1bea934bc..95caba0f910e 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -417,12 +417,13 @@ static void inic_thaw(struct ata_port *ap) * SRST and SControl hardreset don't give valid signature on this * controller. Only controller specific hardreset mechanism works. */ -static int inic_hardreset(struct ata_port *ap, unsigned int *class, +static int inic_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; void __iomem *port_base = inic_port_base(ap); void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; - const unsigned long *timing = sata_ehc_deb_timing(&ap->link.eh_context); + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); u16 val; int rc; @@ -435,15 +436,15 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, msleep(1); writew(val & ~IDMA_CTL_RST_ATA, idma_ctl); - rc = sata_link_resume(&ap->link, timing, deadline); + rc = sata_link_resume(link, timing, deadline); if (rc) { - ata_port_printk(ap, KERN_WARNING, "failed to resume " + ata_link_printk(link, KERN_WARNING, "failed to resume " "link after reset (errno=%d)\n", rc); return rc; } *class = ATA_DEV_NONE; - if (ata_link_online(&ap->link)) { + if (ata_link_online(link)) { struct ata_taskfile tf; /* wait a while before checking status */ @@ -452,7 +453,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { - ata_port_printk(ap, KERN_WARNING, "device not ready " + ata_link_printk(link, KERN_WARNING, "device not ready " "after hardreset (errno=%d)\n", rc); return rc; } diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 8e63c60adaff..56784ce10544 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2266,10 +2266,11 @@ comreset_retry: VPRINTK("EXIT\n"); } -static int mv_prereset(struct ata_port *ap, unsigned long deadline) +static int mv_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct mv_port_priv *pp = ap->private_data; - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_eh_context *ehc = &link->eh_context; int rc; rc = mv_stop_dma(ap); @@ -2285,7 +2286,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) if (ehc->i.action & ATA_EH_HARDRESET) return 0; - if (ata_link_online(&ap->link)) + if (ata_link_online(link)) rc = ata_wait_ready(ap, deadline); else rc = -ENODEV; @@ -2293,9 +2294,10 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) return rc; } -static int mv_hardreset(struct ata_port *ap, unsigned int *class, +static int mv_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; struct mv_host_priv *hpriv = ap->host->private_data; void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; @@ -2308,16 +2310,17 @@ static int mv_hardreset(struct ata_port *ap, unsigned int *class, return 0; } -static void mv_postreset(struct ata_port *ap, unsigned int *classes) +static void mv_postreset(struct ata_link *link, unsigned int *classes) { + struct ata_port *ap = link->ap; u32 serr; /* print link status */ - sata_print_link_status(&ap->link); + sata_print_link_status(link); /* clear SError */ - sata_scr_read(&ap->link, SCR_ERROR, &serr); - sata_scr_write_flush(&ap->link, SCR_ERROR, serr); + sata_scr_read(link, SCR_ERROR, &serr); + sata_scr_write_flush(link, SCR_ERROR, serr); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index df4d50dcffbc..67ba0f75f1e9 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1459,7 +1459,7 @@ static void nv_ck804_thaw(struct ata_port *ap) writeb(mask, mmio_base + NV_INT_ENABLE_CK804); } -static int nv_hardreset(struct ata_port *ap, unsigned int *class, +static int nv_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { unsigned int dummy; @@ -1468,7 +1468,7 @@ static int nv_hardreset(struct ata_port *ap, unsigned int *class, * some controllers. Don't classify on hardreset. For more * info, see http://bugme.osdl.org/show_bug.cgi?id=3352 */ - return sata_std_hardreset(ap, &dummy, deadline); + return sata_std_hardreset(link, &dummy, deadline); } static void nv_error_handler(struct ata_port *ap) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 0cd40d5215fe..869e414d7ed3 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -583,9 +583,10 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp, return rc; } -static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, +static int sil24_do_softreset(struct ata_link *link, unsigned int *class, int pmp, unsigned long deadline) { + struct ata_port *ap = link->ap; unsigned long timeout_msec = 0; struct ata_taskfile tf; const char *reason; @@ -593,7 +594,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_link_offline(&ap->link)) { + if (ata_link_offline(link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; goto out; @@ -609,7 +610,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, if (time_after(deadline, jiffies)) timeout_msec = jiffies_to_msecs(deadline - jiffies); - ata_tf_init(ap->link.device, &tf); /* doesn't really matter */ + ata_tf_init(link->device, &tf); /* doesn't really matter */ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST, timeout_msec); if (rc == -EBUSY) { @@ -631,29 +632,30 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, return 0; err: - ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); return -EIO; } -static int sil24_softreset(struct ata_port *ap, unsigned int *class, +static int sil24_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return sil24_do_softreset(ap, class, 0, deadline); + return sil24_do_softreset(link, class, 0, deadline); } -static int sil24_hardreset(struct ata_port *ap, unsigned int *class, +static int sil24_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; void __iomem *port = ap->ioaddr.cmd_addr; const char *reason; int tout_msec, rc; u32 tmp; /* sil24 does the right thing(tm) without any protection */ - sata_set_spd(&ap->link); + sata_set_spd(link); tout_msec = 100; - if (ata_link_online(&ap->link)) + if (ata_link_online(link)) tout_msec = 5000; writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); @@ -663,14 +665,14 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, /* SStatus oscillates between zero and valid status after * DEV_RST, debounce it. */ - rc = sata_link_debounce(&ap->link, sata_deb_timing_long, deadline); + rc = sata_link_debounce(link, sata_deb_timing_long, deadline); if (rc) { reason = "PHY debouncing failed"; goto err; } if (tmp & PORT_CS_DEV_RST) { - if (ata_link_offline(&ap->link)) + if (ata_link_offline(link)) return 0; reason = "link not ready"; goto err; @@ -685,7 +687,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, return -EAGAIN; err: - ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason); return -EIO; } diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 78a6833af713..690280660b81 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -276,7 +276,7 @@ static void svia_noop_freeze(struct ata_port *ap) /** * vt6420_prereset - prereset for vt6420 - * @ap: target ATA port + * @link: target ATA link * @deadline: deadline jiffies for the operation * * SCR registers on vt6420 are pieces of shit and may hang the @@ -294,8 +294,9 @@ static void svia_noop_freeze(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise. */ -static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) +static int vt6420_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &ap->link.eh_context; unsigned long timeout = jiffies + (HZ * 5); u32 sstatus, scontrol; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index affd77aafb23..9350fbf39f77 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3829,18 +3829,18 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, /** * ipr_sata_reset - Reset the SATA port - * @ap: SATA port to reset + * @link: SATA link to reset * @classes: class of the attached device * - * This function issues a SATA phy reset to the affected ATA port. + * This function issues a SATA phy reset to the affected ATA link. * * Return value: * 0 on success / non-zero on failure **/ -static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes, +static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { - struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_sata_port *sata_port = link->ap->private_data; struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; struct ipr_resource_entry *res; unsigned long lock_flags = 0; diff --git a/include/linux/libata.h b/include/linux/libata.h index e7882ba63e78..25444dafae50 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -333,14 +333,15 @@ enum ata_completion_errors { struct scsi_device; struct ata_port_operations; struct ata_port; +struct ata_link; struct ata_queued_cmd; /* typedefs */ typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); -typedef int (*ata_prereset_fn_t)(struct ata_port *ap, unsigned long deadline); -typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes, +typedef int (*ata_prereset_fn_t)(struct ata_link *link, unsigned long deadline); +typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes, unsigned long deadline); -typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes); +typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes); struct ata_ioports { void __iomem *cmd_addr; @@ -706,14 +707,14 @@ extern int sata_link_debounce(struct ata_link *link, const unsigned long *params, unsigned long deadline); extern int sata_link_resume(struct ata_link *link, const unsigned long *params, unsigned long deadline); -extern int ata_std_prereset(struct ata_port *ap, unsigned long deadline); -extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes, +extern int ata_std_prereset(struct ata_link *link, unsigned long deadline); +extern int ata_std_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline); -extern int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, - unsigned long deadline); -extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class, +extern int sata_link_hardreset(struct ata_link *link, + const unsigned long *timing, unsigned long deadline); +extern int sata_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); +extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); extern void ata_port_disable(struct ata_port *); extern void ata_std_ports(struct ata_ioports *ioaddr); #ifdef CONFIG_PCI From 0260731f0187840e272bfa10d3ba0f3e417976f5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2391/2804] libata-link: linkify config/EH related functions Make the following functions deal with ata_link instead of ata_port. * ata_set_mode() * ata_eh_autopsy() and related functions * ata_eh_report() and related functions * suspend/resume related functions * ata_eh_recover() and related functions Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 7 +- drivers/ata/libata-core.c | 18 +++--- drivers/ata/libata-eh.c | 121 ++++++++++++++++++----------------- drivers/ata/libata.h | 2 +- drivers/ata/pata_it821x.c | 6 +- drivers/ata/pata_ixp4xx_cf.c | 4 +- drivers/ata/pata_legacy.c | 6 +- drivers/ata/pata_optidma.c | 11 ++-- drivers/ata/pata_pcmcia.c | 12 ++-- drivers/ata/pata_pdc2027x.c | 11 ++-- drivers/ata/pata_platform.c | 4 +- drivers/ata/pata_rz1000.c | 6 +- drivers/ata/pdc_adma.c | 5 +- drivers/ata/sata_sil.c | 16 ++--- include/linux/libata.h | 4 +- 15 files changed, 122 insertions(+), 111 deletions(-) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 44328a16075c..e390ad47c8ef 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -34,7 +34,7 @@ /** * generic_set_mode - mode setting - * @ap: interface to set up + * @link: link to set up * @unused: returned device on error * * Use a non standard set_mode function. We don't want to be tuned. @@ -43,8 +43,9 @@ * and respect them. */ -static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) +static int generic_set_mode(struct ata_link *link, struct ata_device **unused) { + struct ata_port *ap = link->ap; int dma_enabled = 0; struct ata_device *dev; @@ -52,7 +53,7 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) if (ap->ioaddr.bmdma_addr) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 73f66f4e1eeb..944f54457c8f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2171,7 +2171,7 @@ int ata_bus_probe(struct ata_port *ap) } /* configure transfer mode */ - rc = ata_set_mode(ap, &dev); + rc = ata_set_mode(&ap->link, &dev); if (rc) goto fail; @@ -2782,7 +2782,7 @@ static int ata_dev_set_mode(struct ata_device *dev) /** * ata_do_set_mode - Program timings and issue SET FEATURES - XFER - * @ap: port on which timings will be programmed + * @link: link on which timings will be programmed * @r_failed_dev: out paramter for failed device * * Standard implementation of the function used to tune and set @@ -2797,9 +2797,9 @@ static int ata_dev_set_mode(struct ata_device *dev) * 0 on success, negative errno otherwise */ -int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; struct ata_device *dev; int rc = 0, used_dma = 0, found = 0; @@ -2877,7 +2877,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /** * ata_set_mode - Program timings and issue SET FEATURES - XFER - * @ap: port on which timings will be programmed + * @link: link on which timings will be programmed * @r_failed_dev: out paramter for failed device * * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If @@ -2890,12 +2890,14 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) * RETURNS: * 0 on success, negative errno otherwise */ -int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { + struct ata_port *ap = link->ap; + /* has private set_mode? */ if (ap->ops->set_mode) - return ap->ops->set_mode(ap, r_failed_dev); - return ata_do_set_mode(ap, r_failed_dev); + return ap->ops->set_mode(link, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); } /** diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0a9ce34a0e64..733aa761f3ee 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1201,7 +1201,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) /** * ata_eh_analyze_serror - analyze SError for a failed port - * @ap: ATA port to analyze SError for + * @link: ATA link to analyze SError for * * Analyze SError if available and further determine cause of * failure. @@ -1209,9 +1209,9 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) * LOCKING: * None. */ -static void ata_eh_analyze_serror(struct ata_port *ap) +static void ata_eh_analyze_serror(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_eh_context *ehc = &link->eh_context; u32 serror = ehc->i.serror; unsigned int err_mask = 0, action = 0; @@ -1241,7 +1241,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap) /** * ata_eh_analyze_ncq_error - analyze NCQ error - * @ap: ATA port to analyze NCQ error for + * @link: ATA link to analyze NCQ error for * * Read log page 10h, determine the offending qc and acquire * error status TF. For NCQ device errors, all LLDDs have to do @@ -1251,10 +1251,11 @@ static void ata_eh_analyze_serror(struct ata_port *ap) * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_analyze_ncq_error(struct ata_port *ap) +static void ata_eh_analyze_ncq_error(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->link.eh_context; - struct ata_device *dev = ap->link.device; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev = link->device; struct ata_queued_cmd *qc; struct ata_taskfile tf; int tag, rc; @@ -1264,7 +1265,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) return; /* is it NCQ device error? */ - if (!ap->link.sactive || !(ehc->i.err_mask & AC_ERR_DEV)) + if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV)) return; /* has LLDD analyzed already? */ @@ -1281,13 +1282,13 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) /* okay, this error is ours */ rc = ata_eh_read_log_10h(dev, &tag, &tf); if (rc) { - ata_port_printk(ap, KERN_ERR, "failed to read log page 10h " + ata_link_printk(link, KERN_ERR, "failed to read log page 10h " "(errno=%d)\n", rc); return; } - if (!(ap->link.sactive & (1 << tag))) { - ata_port_printk(ap, KERN_ERR, "log page 10h reported " + if (!(link->sactive & (1 << tag))) { + ata_link_printk(link, KERN_ERR, "log page 10h reported " "inactive tag %d\n", tag); return; } @@ -1551,18 +1552,18 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, /** * ata_eh_autopsy - analyze error and determine recovery action - * @ap: ATA port to perform autopsy on + * @link: ATA link to perform autopsy on * - * Analyze why @ap failed and determine which recovery action is - * needed. This function also sets more detailed AC_ERR_* values - * and fills sense data for ATAPI CHECK SENSE. + * Analyze why @link failed and determine which recovery actions + * are needed. This function also sets more detailed AC_ERR_* + * values and fills sense data for ATAPI CHECK SENSE. * * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_autopsy(struct ata_port *ap) +static void ata_eh_autopsy(struct ata_link *link) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; unsigned int all_err_mask = 0; int tag, is_io = 0; @@ -1578,7 +1579,7 @@ static void ata_eh_autopsy(struct ata_port *ap) rc = sata_scr_read(link, SCR_ERROR, &serror); if (rc == 0) { ehc->i.serror |= serror; - ata_eh_analyze_serror(ap); + ata_eh_analyze_serror(link); } else if (rc != -EOPNOTSUPP) { /* SError read failed, force hardreset and probing */ ata_ehi_schedule_probe(&ehc->i); @@ -1587,7 +1588,7 @@ static void ata_eh_autopsy(struct ata_port *ap) } /* analyze NCQ failure */ - ata_eh_analyze_ncq_error(ap); + ata_eh_analyze_ncq_error(link); /* any real error trumps AC_ERR_OTHER */ if (ehc->i.err_mask & ~AC_ERR_OTHER) @@ -1598,7 +1599,7 @@ static void ata_eh_autopsy(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link) continue; /* inherit upper level err_mask */ @@ -1653,16 +1654,17 @@ static void ata_eh_autopsy(struct ata_port *ap) /** * ata_eh_report - report error handling to user - * @ap: ATA port EH is going on + * @link: ATA link EH is going on * * Report EH to user. * * LOCKING: * None. */ -static void ata_eh_report(struct ata_port *ap) +static void ata_eh_report(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; const char *frozen, *desc; int tag, nr_failed = 0; @@ -1673,7 +1675,7 @@ static void ata_eh_report(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link) continue; if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask) continue; @@ -1691,17 +1693,17 @@ static void ata_eh_report(struct ata_port *ap) if (ehc->i.dev) { ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->link.sactive, + ehc->i.err_mask, link->sactive, ehc->i.serror, ehc->i.action, frozen); if (desc) ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { - ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x " + ata_link_printk(link, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->link.sactive, + ehc->i.err_mask, link->sactive, ehc->i.serror, ehc->i.action, frozen); if (desc) - ata_port_printk(ap, KERN_ERR, "%s\n", desc); + ata_link_printk(link, KERN_ERR, "%s\n", desc); } for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { @@ -1714,7 +1716,8 @@ static void ata_eh_report(struct ata_port *ap) struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; - if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) + if (!(qc->flags & ATA_QCFLAG_FAILED) || + qc->dev->link != link || !qc->err_mask) continue; ata_dev_printk(qc->dev, KERN_ERR, @@ -1936,10 +1939,11 @@ static int ata_eh_reset(struct ata_link *link, int classify, return rc; } -static int ata_eh_revalidate_and_attach(struct ata_port *ap, +static int ata_eh_revalidate_and_attach(struct ata_link *link, struct ata_device **r_failed_dev) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; unsigned int new_mask = 0; unsigned long flags; @@ -1951,7 +1955,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, * be done backwards such that PDIAG- is released by the slave * device before the master device is identified. */ - ata_link_for_each_dev_reverse(dev, &ap->link) { + ata_link_for_each_dev_reverse(dev, link) { unsigned int action = ata_eh_dev_action(dev); unsigned int readid_flags = 0; @@ -1959,17 +1963,17 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, readid_flags |= ATA_READID_POSTRESET; if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { - if (ata_link_offline(&ap->link)) { + if (ata_link_offline(link)) { rc = -EIO; goto err; } - ata_eh_about_to_do(&ap->link, dev, ATA_EH_REVALIDATE); + ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE); rc = ata_dev_revalidate(dev, readid_flags); if (rc) goto err; - ata_eh_done(&ap->link, dev, ATA_EH_REVALIDATE); + ata_eh_done(link, dev, ATA_EH_REVALIDATE); /* Configuration may have changed, reconfigure * transfer mode. @@ -2011,7 +2015,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, /* Configure new devices forward such that user doesn't see * device detection messages backwards. */ - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (!(new_mask & (1 << dev->devno))) continue; @@ -2037,40 +2041,40 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, return rc; } -static int ata_port_nr_enabled(struct ata_port *ap) +static int ata_link_nr_enabled(struct ata_link *link) { struct ata_device *dev; int cnt = 0; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) if (ata_dev_enabled(dev)) cnt++; return cnt; } -static int ata_port_nr_vacant(struct ata_port *ap) +static int ata_link_nr_vacant(struct ata_link *link) { struct ata_device *dev; int cnt = 0; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) if (dev->class == ATA_DEV_UNKNOWN) cnt++; return cnt; } -static int ata_eh_skip_recovery(struct ata_port *ap) +static int ata_eh_skip_recovery(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; /* thaw frozen port, resume link and recover failed devices */ - if ((ap->pflags & ATA_PFLAG_FROZEN) || - (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap)) + if ((link->ap->pflags & ATA_PFLAG_FROZEN) || + (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link)) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (dev->class == ATA_DEV_UNKNOWN && ehc->classes[dev->devno] != ATA_DEV_NONE) return 0; @@ -2154,14 +2158,15 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; int rc; DPRINTK("ENTER\n"); /* prep for recovery */ - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; /* collect port action mask recorded in dev actions */ @@ -2191,20 +2196,20 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, goto out; /* skip EH if possible. */ - if (ata_eh_skip_recovery(ap)) + if (ata_eh_skip_recovery(link)) ehc->i.action = 0; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; /* reset */ if (ehc->i.action & ATA_EH_RESET_MASK) { ata_eh_freeze_port(ap); - rc = ata_eh_reset(&ap->link, ata_port_nr_vacant(ap), prereset, + rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset, softreset, hardreset, postreset); if (rc) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "reset failed, giving up\n"); goto out; } @@ -2213,13 +2218,13 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } /* revalidate existing devices and attach new ones */ - rc = ata_eh_revalidate_and_attach(ap, &dev); + rc = ata_eh_revalidate_and_attach(link, &dev); if (rc) goto dev_fail; /* configure transfer mode if necessary */ if (ehc->i.flags & ATA_EHI_SETMODE) { - rc = ata_set_mode(ap, &dev); + rc = ata_set_mode(link, &dev); if (rc) goto dev_fail; ehc->i.flags &= ~ATA_EHI_SETMODE; @@ -2230,8 +2235,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, dev_fail: ata_eh_handle_dev_fail(dev, rc); - if (ata_port_nr_enabled(ap)) { - ata_port_printk(ap, KERN_WARNING, "failed to recover some " + if (ata_link_nr_enabled(link)) { + ata_link_printk(link, KERN_WARNING, "failed to recover some " "devices, retrying in 5 secs\n"); ssleep(5); } else { @@ -2243,7 +2248,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, out: if (rc) { - ata_link_for_each_dev(dev, &ap->link); + ata_link_for_each_dev(dev, link); ata_dev_disable(dev); } @@ -2310,8 +2315,8 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - ata_eh_autopsy(ap); - ata_eh_report(ap); + ata_eh_autopsy(&ap->link); + ata_eh_report(&ap->link); ata_eh_recover(ap, prereset, softreset, hardreset, postreset); ata_eh_finish(ap); } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 700843a9f30a..6d85edefa7c6 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -81,7 +81,7 @@ extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_link *link); extern int sata_set_spd_needed(struct ata_link *link); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); -extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); +extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 088eb1d23761..f32d9b7ab496 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -450,7 +450,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) /** * it821x_smart_set_mode - mode setting - * @ap: interface to set up + * @link: interface to set up * @unused: device that failed (error only) * * Use a non standard set_mode function. We don't want to be tuned. @@ -459,11 +459,11 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) * and respect them. */ -static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused) +static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 7db315a9baad..6bf1709508ab 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -26,11 +26,11 @@ #define DRV_NAME "pata_ixp4xx_cf" #define DRV_VERSION "0.2" -static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) +static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 9d92843b033d..cfb2bc86a1d1 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -96,7 +96,7 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ /** * legacy_set_mode - mode setting - * @ap: IDE interface + * @link: IDE link * @unused: Device that failed when error is returned * * Use a non standard set_mode function. We don't want to be tuned. @@ -107,11 +107,11 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ * expand on this as per hdparm in the base kernel. */ -static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) +static int legacy_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 39fcba800077..09ef725afd90 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -324,25 +324,26 @@ static u8 optidma_make_bits43(struct ata_device *adev) /** * optidma_set_mode - mode setup - * @ap: port to set up + * @link: link to set up * * Use the standard setup to tune the chipset and then finalise the * configuration by writing the nibble of extra bits of data into * the chip. */ -static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed) +static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed) { + struct ata_port *ap = link->ap; u8 r; int nybble = 4 * ap->port_no; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - int rc = ata_do_set_mode(ap, r_failed); + int rc = ata_do_set_mode(link, r_failed); if (rc == 0) { pci_read_config_byte(pdev, 0x43, &r); r &= (0x0F << nybble); - r |= (optidma_make_bits43(&ap->link.device[0]) + - (optidma_make_bits43(&ap->link.device[0]) << 2)) << nybble; + r |= (optidma_make_bits43(&link->device[0]) + + (optidma_make_bits43(&link->device[0]) << 2)) << nybble; pci_write_config_byte(pdev, 0x43, r); } return rc; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 890f649ddcce..9bfe12ac851a 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -56,7 +56,7 @@ struct ata_pcmcia_info { /** * pcmcia_set_mode - PCMCIA specific mode setup - * @ap: Port + * @link: link * @r_failed_dev: Return pointer for failed device * * Perform the tuning and setup of the devices and timings, which @@ -65,13 +65,13 @@ struct ata_pcmcia_info { * decode, which alas is embarrassingly common in the PC world */ -static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { - struct ata_device *master = &ap->link.device[0]; - struct ata_device *slave = &ap->link.device[1]; + struct ata_device *master = &link->device[0]; + struct ata_device *slave = &link->device[1]; if (!ata_dev_enabled(master) || !ata_dev_enabled(slave)) - return ata_do_set_mode(ap, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV, ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0) @@ -84,7 +84,7 @@ static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev ata_dev_disable(slave); } } - return ata_do_set_mode(ap, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); } static struct scsi_host_template pcmcia_sht = { diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index ba39efbe5405..db069d7515bc 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -69,7 +69,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask); static int pdc2027x_cable_detect(struct ata_port *ap); -static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed); +static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed); /* * ATA Timing Tables based on 133MHz controller clock. @@ -470,23 +470,24 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) /** * pdc2027x_set_mode - Set the timing registers back to correct values. - * @ap: Port to configure + * @link: link to configure * @r_failed: Returned device for failure * * The pdc2027x hardware will look at "SET FEATURES" and change the timing registers * automatically. The values set by the hardware might be incorrect, under 133Mhz PLL. * This function overwrites the possibly incorrect values set by the hardware to be correct. */ -static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) +static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed) { + struct ata_port *ap = link->ap; struct ata_device *dev; int rc; - rc = ata_do_set_mode(ap, r_failed); + rc = ata_do_set_mode(link, r_failed); if (rc < 0) return rc; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { pdc2027x_set_piomode(ap, dev); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index ee1605bfc29f..37e5158391da 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -30,11 +30,11 @@ static int pio_mask = 1; * Provide our own set_mode() as we don't want to change anything that has * already been configured.. */ -static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused) +static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = dev->xfer_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 300b3d5de81e..de3698cf3b8c 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -26,7 +26,7 @@ /** * rz1000_set_mode - mode setting function - * @ap: ATA interface + * @link: ATA link * @unused: returned device on set_mode failure * * Use a non standard set_mode function. We don't want to be tuned. We @@ -34,11 +34,11 @@ * whacked out. */ -static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) +static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 064a3b505609..304c19b9b0f2 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -297,15 +297,16 @@ static void adma_thaw(struct ata_port *ap) adma_reinit_engine(ap); } -static int adma_prereset(struct ata_port *ap, unsigned long deadline) +static int adma_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct adma_port_priv *pp = ap->private_data; if (pp->state != adma_state_idle) /* healthy paranoia */ pp->state = adma_state_mmio; adma_reinit_engine(ap); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void adma_error_handler(struct ata_port *ap) diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 4c9295a49a49..5cd3eb83e4ad 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -117,7 +117,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev); static void sil_dev_config(struct ata_device *dev); static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); -static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed); +static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed); static void sil_freeze(struct ata_port *ap); static void sil_thaw(struct ata_port *ap); @@ -290,27 +290,27 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev) /** * sil_set_mode - wrap set_mode functions - * @ap: port to set up + * @link: link to set up * @r_failed: returned device when we fail * * Wrap the libata method for device setup as after the setup we need * to inspect the results and do some configuration work */ -static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) +static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed) { - struct ata_host *host = ap->host; - struct ata_device *dev; - void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; + struct ata_port *ap = link->ap; + void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; + struct ata_device *dev; u32 tmp, dev_mode[2] = { }; int rc; - rc = ata_do_set_mode(ap, r_failed); + rc = ata_do_set_mode(link, r_failed); if (rc) return rc; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev)) dev_mode[dev->devno] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) diff --git a/include/linux/libata.h b/include/linux/libata.h index 25444dafae50..0f86d9be78ab 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -607,7 +607,7 @@ struct ata_port_operations { void (*dev_select)(struct ata_port *ap, unsigned int device); void (*phy_reset) (struct ata_port *ap); /* obsolete */ - int (*set_mode) (struct ata_port *ap, struct ata_device **r_failed_dev); + int (*set_mode) (struct ata_link *link, struct ata_device **r_failed_dev); int (*cable_detect) (struct ata_port *ap); @@ -838,7 +838,7 @@ extern void ata_scsi_slave_destroy(struct scsi_device *sdev); extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth); extern struct ata_device *ata_dev_pair(struct ata_device *adev); -extern int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); +extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern u8 ata_irq_on(struct ata_port *ap); extern u8 ata_dummy_irq_on(struct ata_port *ap); extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq); From 0c88758b5a6325428aaadab619886242db20ceae Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2392/2804] libata-link: make two port flags HRST_TO_RESUME and SKIP_D2H_BSY link flags HRST_TO_RESUME and SKIP_D2H_BSY are link attributes. Move them to ata_link->flags. This will allow host and PMP links to have different attributes. ata_port_info->link_flags is added and used by LLDs to specify these flags during initialization. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 16 ++++++++++------ drivers/ata/libata-core.c | 5 +++-- drivers/ata/sata_nv.c | 14 +++++++------- drivers/ata/sata_sil.c | 7 ++++++- drivers/ata/sata_sil24.c | 7 +++++-- include/linux/libata.h | 11 ++++++++--- 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e38ae12d0148..483733783cf8 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -178,8 +178,8 @@ enum { AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY | ATA_FLAG_ACPI_SATA, + AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, }; struct ahci_cmd_hdr { @@ -333,6 +333,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { .flags = AHCI_FLAG_COMMON, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -340,14 +341,15 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_pi */ { .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, /* board_ahci_vt8251 */ { - .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME | - AHCI_FLAG_NO_NCQ, + .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, + .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_vt8251_ops, @@ -355,6 +357,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_ign_iferr */ { .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -364,6 +367,7 @@ static const struct ata_port_info ahci_port_info[] = { .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_SERR_INTERNAL | AHCI_FLAG_32BIT_ONLY, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -373,9 +377,9 @@ static const struct ata_port_info ahci_port_info[] = { .sht = &ahci_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI | - AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | - AHCI_FLAG_MV_PATA, + AHCI_FLAG_HONOR_PI | AHCI_FLAG_NO_NCQ | + AHCI_FLAG_NO_MSI | AHCI_FLAG_MV_PATA, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 944f54457c8f..2be30c7a2226 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3332,7 +3332,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) /* handle link resume */ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && - (ap->flags & ATA_FLAG_HRST_TO_RESUME)) + (link->flags & ATA_LFLAG_HRST_TO_RESUME)) ehc->i.action |= ATA_EH_HARDRESET; /* if we're about to do hardreset, nothing more to do */ @@ -3351,7 +3351,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) /* Wait for !BSY if the controller can wait for the first D2H * Reg FIS and we don't know that no device is attached. */ - if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { + if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { ata_link_printk(link, KERN_WARNING, "device not ready " @@ -6269,6 +6269,7 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, ap->mwdma_mask = pi->mwdma_mask; ap->udma_mask = pi->udma_mask; ap->flags |= pi->flags; + ap->link.flags |= pi->link_flags; ap->ops = pi->port_ops; if (!host->ops && (pi->port_ops != &ata_dummy_port_ops)) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 67ba0f75f1e9..884d9f05e6c6 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -455,8 +455,8 @@ static const struct ata_port_info nv_port_info[] = { /* generic */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -466,8 +466,8 @@ static const struct ata_port_info nv_port_info[] = { /* nforce2/3 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -477,8 +477,8 @@ static const struct ata_port_info nv_port_info[] = { /* ck804 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -489,8 +489,8 @@ static const struct ata_port_info nv_port_info[] = { { .sht = &nv_adma_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME | ATA_FLAG_MMIO | ATA_FLAG_NCQ, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 5cd3eb83e4ad..802d679dc994 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -59,7 +59,8 @@ enum { SIL_FLAG_MOD15WRITE = (1 << 30), SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME, + ATA_FLAG_MMIO, + SIL_DFL_LINK_FLAGS = ATA_LFLAG_HRST_TO_RESUME, /* * Controller IDs @@ -216,6 +217,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3112 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -225,6 +227,7 @@ static const struct ata_port_info sil_port_info[] = { { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE | SIL_FLAG_NO_SATA_IRQ, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -233,6 +236,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3512 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -241,6 +245,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3114 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 869e414d7ed3..e2cccc7f4358 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -237,8 +237,8 @@ enum { /* host flags */ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY | - ATA_FLAG_ACPI_SATA, + ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA, + SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ IRQ_STAT_4PORTS = 0xf, @@ -424,6 +424,7 @@ static const struct ata_port_info sil24_port_info[] = { { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) | SIL24_FLAG_PCIX_IRQ_WOC, + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -432,6 +433,7 @@ static const struct ata_port_info sil24_port_info[] = { /* sil_3132 */ { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -440,6 +442,7 @@ static const struct ata_port_info sil24_port_info[] = { /* sil_3131/sil_3531 */ { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 0f86d9be78ab..74ced08d5989 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -156,6 +156,11 @@ enum { ATA_DEV_ATAPI_UNSUP = 4, /* ATAPI device (unsupported) */ ATA_DEV_NONE = 5, /* no device */ + /* struct ata_link flags */ + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H + * Register FIS clearing BSY */ + /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ /* (doesn't imply presence) */ @@ -170,9 +175,6 @@ enum { ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD * doesn't handle PIO interrupts */ ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ - ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */ - ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H - * Register FIS clearing BSY */ ATA_FLAG_DEBUGMSG = (1 << 13), ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ @@ -517,6 +519,8 @@ struct ata_link { unsigned int active_tag; /* active tag on this link */ u32 sactive; /* active NCQ commands */ + unsigned int flags; /* ATA_LFLAG_xxx */ + unsigned int hw_sata_spd_limit; unsigned int sata_spd_limit; unsigned int sata_spd; /* current SATA PHY speed */ @@ -654,6 +658,7 @@ struct ata_port_operations { struct ata_port_info { struct scsi_host_template *sht; unsigned long flags; + unsigned long link_flags; unsigned long pio_mask; unsigned long mwdma_mask; unsigned long udma_mask; From 4fb37a25b976e8d1b34461330b3f2c6d9b94c133 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2393/2804] libata-link: separate out link initialization functions Separate out link initialization into ata_link_init() and ata_link_init_sata_spd(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 84 +++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2be30c7a2226..3da642bd2ee2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6060,6 +6060,68 @@ void ata_dev_init(struct ata_device *dev) dev->udma_mask = UINT_MAX; } +/** + * ata_link_init - Initialize an ata_link structure + * @ap: ATA port link is attached to + * @link: Link structure to initialize + * + * Initialize @link. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +static void ata_link_init(struct ata_port *ap, struct ata_link *link) +{ + int i; + + /* clear everything except for devices */ + memset(link, 0, offsetof(struct ata_link, device[0])); + + link->ap = ap; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = UINT_MAX; + + /* can't use iterator, ap isn't initialized yet */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &link->device[i]; + + dev->link = link; + dev->devno = dev - link->device; + ata_dev_init(dev); + } +} + +/** + * sata_link_init_spd - Initialize link->sata_spd_limit + * @link: Link to configure sata_spd_limit for + * + * Initialize @link->[hw_]sata_spd_limit to the currently + * configured value. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_link_init_spd(struct ata_link *link) +{ + u32 scontrol, spd; + int rc; + + rc = sata_scr_read(link, SCR_CONTROL, &scontrol); + if (rc) + return rc; + + spd = (scontrol >> 4) & 0xf; + if (spd) + link->hw_sata_spd_limit &= (1 << spd) - 1; + + link->sata_spd_limit = link->hw_sata_spd_limit; + + return 0; +} + /** * ata_port_alloc - allocate and initialize basic ATA port resources * @host: ATA host this allocated port belongs to @@ -6075,7 +6137,6 @@ void ata_dev_init(struct ata_device *dev) struct ata_port *ata_port_alloc(struct ata_host *host) { struct ata_port *ap; - unsigned int i; DPRINTK("ENTER\n"); @@ -6090,9 +6151,6 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->ctl = ATA_DEVCTL_OBS; ap->host = host; ap->dev = host->dev; - - ap->link.hw_sata_spd_limit = UINT_MAX; - ap->link.active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; #if defined(ATA_VERBOSE_DEBUG) @@ -6115,15 +6173,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->cbl = ATA_CBL_NONE; - ap->link.ap = ap; - - /* can't use iterator, ap isn't initialized yet */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; - dev->link = &ap->link; - dev->devno = i; - ata_dev_init(dev); - } + ata_link_init(ap, &ap->link); #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; @@ -6406,7 +6456,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; int irq_line; - u32 scontrol; unsigned long xfer_mask; /* set SATA cable type if still unset */ @@ -6414,12 +6463,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ap->cbl = ATA_CBL_SATA; /* init sata_spd_limit to the current value */ - if (sata_scr_read(&ap->link, SCR_CONTROL, &scontrol) == 0) { - int spd = (scontrol >> 4) & 0xf; - if (spd) - ap->link.hw_sata_spd_limit &= (1 << spd) - 1; - } - ap->link.sata_spd_limit = ap->link.hw_sata_spd_limit; + sata_link_init_spd(&ap->link); /* report the secondary IRQ for second channel legacy */ irq_line = host->irq; From dbd826168d6267a26cf20cd233f6730f8d8047d6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2394/2804] libata-link: implement ata_link_abort() Implement ata_link_abort(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + drivers/ata/libata-eh.c | 50 ++++++++++++++++++++++++++++----------- include/linux/libata.h | 1 + 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3da642bd2ee2..dcae590cc9b4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7050,6 +7050,7 @@ EXPORT_SYMBOL_GPL(ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); +EXPORT_SYMBOL_GPL(ata_link_abort); EXPORT_SYMBOL_GPL(ata_port_abort); EXPORT_SYMBOL_GPL(ata_port_freeze); EXPORT_SYMBOL_GPL(ata_eh_freeze_port); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 733aa761f3ee..eb4c0593b406 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -719,19 +719,7 @@ void ata_port_schedule_eh(struct ata_port *ap) DPRINTK("port EH scheduled\n"); } -/** - * ata_port_abort - abort all qc's on the port - * @ap: ATA port to abort qc's for - * - * Abort all active qc's of @ap and schedule EH. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * Number of aborted qc's. - */ -int ata_port_abort(struct ata_port *ap) +static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) { int tag, nr_aborted = 0; @@ -743,7 +731,7 @@ int ata_port_abort(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); - if (qc) { + if (qc && (!link || qc->dev->link == link)) { qc->flags |= ATA_QCFLAG_FAILED; ata_qc_complete(qc); nr_aborted++; @@ -756,6 +744,40 @@ int ata_port_abort(struct ata_port *ap) return nr_aborted; } +/** + * ata_link_abort - abort all qc's on the link + * @link: ATA link to abort qc's for + * + * Abort all active qc's active on @link and schedule EH. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Number of aborted qc's. + */ +int ata_link_abort(struct ata_link *link) +{ + return ata_do_link_abort(link->ap, link); +} + +/** + * ata_port_abort - abort all qc's on the port + * @ap: ATA port to abort qc's for + * + * Abort all active qc's of @ap and schedule EH. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Number of aborted qc's. + */ +int ata_port_abort(struct ata_port *ap) +{ + return ata_do_link_abort(ap, NULL); +} + /** * __ata_port_freeze - freeze port * @ap: ATA port to freeze diff --git a/include/linux/libata.h b/include/linux/libata.h index 74ced08d5989..bfa155789993 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -906,6 +906,7 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); extern void ata_eng_timeout(struct ata_port *ap); extern void ata_port_schedule_eh(struct ata_port *ap); +extern int ata_link_abort(struct ata_link *link); extern int ata_port_abort(struct ata_port *ap); extern int ata_port_freeze(struct ata_port *ap); From 8989805d6d176aa32c0e9a68a536aa4c8ef5231c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2395/2804] libata-link: add PMP links Add link->pmp, ap->nr_pmp_links, ap->pmp_link[], and implement/update link helpers. printk helpers are updated such that port and link are identifed as 'ataP:' if no PMP is attached, while device is identified as 'ataP.DD:'. If PMP is attached, they become 'ataP:', 'ataP.LL:' and 'ataP.LL' - ie. link and device are identified their PMP number. If PPM is attached (ap->nr_pmp_links != 0), ata_for_each_link() iterates over PMP links, while __ata_for_each_link() iterates over the host link + PMP links. If PMP is not attached (ap->nr_pmp_links == 0), both iterate over only the host link. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 +++-- include/linux/libata.h | 53 ++++++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dcae590cc9b4..af9c0ab600dc 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6064,13 +6064,14 @@ void ata_dev_init(struct ata_device *dev) * ata_link_init - Initialize an ata_link structure * @ap: ATA port link is attached to * @link: Link structure to initialize + * @pmp: Port multiplier port number * * Initialize @link. * * LOCKING: * Kernel thread context (may sleep) */ -static void ata_link_init(struct ata_port *ap, struct ata_link *link) +static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) { int i; @@ -6078,6 +6079,7 @@ static void ata_link_init(struct ata_port *ap, struct ata_link *link) memset(link, 0, offsetof(struct ata_link, device[0])); link->ap = ap; + link->pmp = pmp; link->active_tag = ATA_TAG_POISON; link->hw_sata_spd_limit = UINT_MAX; @@ -6173,7 +6175,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->cbl = ATA_CBL_NONE; - ata_link_init(ap, &ap->link); + ata_link_init(ap, &ap->link, 0); #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; diff --git a/include/linux/libata.h b/include/linux/libata.h index bfa155789993..7a1793bd2371 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -515,6 +515,7 @@ struct ata_acpi_gtm { struct ata_link { struct ata_port *ap; + int pmp; /* port multiplier port # */ unsigned int active_tag; /* active tag on this link */ u32 sactive; /* active NCQ commands */ @@ -563,6 +564,9 @@ struct ata_port { struct ata_link link; /* host default link */ + int nr_pmp_links; /* nr of available PMP links */ + struct ata_link *pmp_link; /* array of PMP links */ + struct ata_port_stats stats; struct ata_host *host; struct device *dev; @@ -926,11 +930,17 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, #define ata_port_printk(ap, lv, fmt, args...) \ printk(lv"ata%u: "fmt, (ap)->print_id , ##args) -#define ata_link_printk(link, lv, fmt, args...) \ - printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args) +#define ata_link_printk(link, lv, fmt, args...) do { \ + if ((link)->ap->nr_pmp_links) \ + printk(lv"ata%u.%02u: "fmt, (link)->ap->print_id, \ + (link)->pmp , ##args); \ + else \ + printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args); \ + } while(0) #define ata_dev_printk(dev, lv, fmt, args...) \ - printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, (dev)->devno , ##args) + printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, \ + (dev)->link->pmp + (dev)->devno , ##args) /* * ata_eh_info helpers @@ -1039,15 +1049,46 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev) /* * link helpers */ +static inline int ata_is_host_link(const struct ata_link *link) +{ + return link == &link->ap->link; +} + static inline int ata_link_max_devices(const struct ata_link *link) { - if (link->ap->flags & ATA_FLAG_SLAVE_POSS) + if (ata_is_host_link(link) && link->ap->flags & ATA_FLAG_SLAVE_POSS) return 2; return 1; } -#define ata_port_for_each_link(lk, ap) \ - for ((lk) = &(ap)->link; (lk); (lk) = NULL) +static inline struct ata_link *ata_port_first_link(struct ata_port *ap) +{ + if (ap->nr_pmp_links) + return ap->pmp_link; + return &ap->link; +} + +static inline struct ata_link *ata_port_next_link(struct ata_link *link) +{ + struct ata_port *ap = link->ap; + + if (link == &ap->link) { + if (!ap->nr_pmp_links) + return NULL; + return ap->pmp_link; + } + + if (++link - ap->pmp_link < ap->nr_pmp_links) + return link; + return NULL; +} + +#define __ata_port_for_each_link(lk, ap) \ + for ((lk) = &(ap)->link; (lk); (lk) = ata_port_next_link(lk)) + +#define ata_port_for_each_link(link, ap) \ + for ((link) = ata_port_first_link(ap); (link); \ + (link) = ata_port_next_link(link)) #define ata_link_for_each_dev(dev, link) \ for ((dev) = (link)->device; \ From cf1b86c8ab41fe2b2a2eb59c9a2ea9a7e463653a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: [PATCH 2396/2804] libata-link: update ata_scsi_error() to handle PMP links Update ata_scsi_error() to handle PMP links. As error conditions can occur on both host and PMP links, __ata_port_for_each_link() is used. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index eb4c0593b406..45eb932c3935 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -363,6 +363,8 @@ void ata_scsi_error(struct Scsi_Host *host) repeat: /* invoke error handler */ if (ap->ops->error_handler) { + struct ata_link *link; + /* kill fast drain timer */ del_timer_sync(&ap->fastdrain_timer); @@ -372,9 +374,11 @@ void ata_scsi_error(struct Scsi_Host *host) /* fetch & clear EH info */ spin_lock_irqsave(ap->lock, flags); - memset(&ap->link.eh_context, 0, sizeof(ap->link.eh_context)); - ap->link.eh_context.i = ap->link.eh_info; - memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info)); + __ata_port_for_each_link(link, ap) { + memset(&link->eh_context, 0, sizeof(link->eh_context)); + link->eh_context.i = link->eh_info; + memset(&link->eh_info, 0, sizeof(link->eh_info)); + } ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; ap->pflags &= ~ATA_PFLAG_EH_PENDING; @@ -410,7 +414,8 @@ void ata_scsi_error(struct Scsi_Host *host) } /* this run is complete, make sure EH info is clear */ - memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info)); + __ata_port_for_each_link(link, ap) + memset(&link->eh_info, 0, sizeof(link->eh_info)); /* Clear host_eh_scheduled while holding ap->lock such * that if exception occurs after this point but From 9b1e2658faf3f3095a96558c333b333c0e29dbc0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:24 +0900 Subject: [PATCH 2397/2804] libata-link: update EH to deal with PMP links Update ata_eh_autopsy(), ata_eh_report(), ata_eh_revalidate_and_attach() and ata_eh_recover() to deal with PMP links. ata_eh_autopsy() and ata_eh_report() updates are straightforward. They just repeat the same operation over all configured links. The only change to ata_eh_revalidate_and_attach() is avoiding calling ->cable_select() on non-host ports. ata_eh_recover() update is more complex as it first processes all resets and then performs the rest. This is necessary as thawing with some links in unknown state can be dangerous. ehi->action is cleared on successful recovery of a link to avoid repeating recovery due to failures in other links. ata_eh_recover() iterates over only PMP links if PMP is attached, and, on failure, the failing link is returned in @failed_link instead of disabling devices directly. These are to integrate ata_eh_recover() into PMP EH later. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 228 ++++++++++++++++++++++++++++------------ 1 file changed, 158 insertions(+), 70 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 45eb932c3935..2ddc2ed9c29d 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1578,8 +1578,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, } /** - * ata_eh_autopsy - analyze error and determine recovery action - * @link: ATA link to perform autopsy on + * ata_eh_link_autopsy - analyze error and determine recovery action + * @link: host link to perform autopsy on * * Analyze why @link failed and determine which recovery actions * are needed. This function also sets more detailed AC_ERR_* @@ -1588,7 +1588,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_autopsy(struct ata_link *link) +static void ata_eh_link_autopsy(struct ata_link *link) { struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; @@ -1680,7 +1680,25 @@ static void ata_eh_autopsy(struct ata_link *link) } /** - * ata_eh_report - report error handling to user + * ata_eh_autopsy - analyze error and determine recovery action + * @ap: host port to perform autopsy on + * + * Analyze all links of @ap and determine why they failed and + * which recovery actions are needed. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void ata_eh_autopsy(struct ata_port *ap) +{ + struct ata_link *link; + + __ata_port_for_each_link(link, ap) + ata_eh_link_autopsy(link); +} + +/** + * ata_eh_link_report - report error handling to user * @link: ATA link EH is going on * * Report EH to user. @@ -1688,7 +1706,7 @@ static void ata_eh_autopsy(struct ata_link *link) * LOCKING: * None. */ -static void ata_eh_report(struct ata_link *link) +static void ata_eh_link_report(struct ata_link *link) { struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; @@ -1767,6 +1785,23 @@ static void ata_eh_report(struct ata_link *link) } } +/** + * ata_eh_report - report error handling to user + * @ap: ATA port to report EH about + * + * Report EH to user. + * + * LOCKING: + * None. + */ +static void ata_eh_report(struct ata_port *ap) +{ + struct ata_link *link; + + __ata_port_for_each_link(link, ap) + ata_eh_link_report(link); +} + static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { @@ -2036,7 +2071,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, } /* PDIAG- should have been released, ask cable type if post-reset */ - if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect) + if (ata_is_host_link(link) && ap->ops->cable_detect && + (ehc->i.flags & ATA_EHI_DID_RESET)) ap->cbl = ap->ops->cable_detect(ap); /* Configure new devices forward such that user doesn't see @@ -2110,7 +2146,7 @@ static int ata_eh_skip_recovery(struct ata_link *link) return 1; } -static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) +static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) { struct ata_eh_context *ehc = &dev->link->eh_context; @@ -2151,12 +2187,16 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) ehc->did_probe_mask |= (1 << dev->devno); ehc->i.action |= ATA_EH_SOFTRESET; } + + return 1; } else { /* soft didn't work? be haaaaard */ if (ehc->i.flags & ATA_EHI_DID_RESET) ehc->i.action |= ATA_EH_HARDRESET; else ehc->i.action |= ATA_EH_SOFTRESET; + + return 0; } } @@ -2167,12 +2207,13 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) * @postreset: postreset method (can be NULL) + * @r_failed_link: out parameter for failed link * * This is the alpha and omega, eum and yang, heart and soul of * libata exception handling. On entry, actions required to - * recover the port and hotplug requests are recorded in - * eh_context. This function executes all the operations with - * appropriate retrials and fallbacks to resurrect failed + * recover each link and hotplug requests are recorded in the + * link's eh_context. This function executes all the operations + * with appropriate retrials and fallbacks to resurrect failed * devices, detach goners and greet newcomers. * * LOCKING: @@ -2183,101 +2224,138 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) */ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset) + ata_postreset_fn_t postreset, + struct ata_link **r_failed_link) { - struct ata_link *link = &ap->link; - struct ata_eh_context *ehc = &link->eh_context; + struct ata_link *link; struct ata_device *dev; - int rc; + int nr_failed_devs, nr_disabled_devs; + int reset, rc; DPRINTK("ENTER\n"); /* prep for recovery */ - ata_link_for_each_dev(dev, link) { - ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - /* collect port action mask recorded in dev actions */ - ehc->i.action |= - ehc->i.dev_action[dev->devno] & ~ATA_EH_PERDEV_MASK; - ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; + ata_link_for_each_dev(dev, link) { + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; - /* process hotplug request */ - if (dev->flags & ATA_DFLAG_DETACH) - ata_eh_detach_dev(dev); + /* collect port action mask recorded in dev actions */ + ehc->i.action |= ehc->i.dev_action[dev->devno] & + ~ATA_EH_PERDEV_MASK; + ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; - if (!ata_dev_enabled(dev) && - ((ehc->i.probe_mask & (1 << dev->devno)) && - !(ehc->did_probe_mask & (1 << dev->devno)))) { - ata_eh_detach_dev(dev); - ata_dev_init(dev); - ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |= ATA_EH_SOFTRESET; + /* process hotplug request */ + if (dev->flags & ATA_DFLAG_DETACH) + ata_eh_detach_dev(dev); + + if (!ata_dev_enabled(dev) && + ((ehc->i.probe_mask & (1 << dev->devno)) && + !(ehc->did_probe_mask & (1 << dev->devno)))) { + ata_eh_detach_dev(dev); + ata_dev_init(dev); + ehc->did_probe_mask |= (1 << dev->devno); + ehc->i.action |= ATA_EH_SOFTRESET; + } } } retry: rc = 0; + nr_failed_devs = 0; + nr_disabled_devs = 0; + reset = 0; /* if UNLOADING, finish immediately */ if (ap->pflags & ATA_PFLAG_UNLOADING) goto out; - /* skip EH if possible. */ - if (ata_eh_skip_recovery(link)) - ehc->i.action = 0; + /* prep for EH */ + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - ata_link_for_each_dev(dev, link) - ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; + /* skip EH if possible. */ + if (ata_eh_skip_recovery(link)) + ehc->i.action = 0; + + /* do we need to reset? */ + if (ehc->i.action & ATA_EH_RESET_MASK) + reset = 1; + + ata_link_for_each_dev(dev, link) + ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; + } /* reset */ - if (ehc->i.action & ATA_EH_RESET_MASK) { + if (reset) { ata_eh_freeze_port(ap); - rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset, - softreset, hardreset, postreset); - if (rc) { - ata_link_printk(link, KERN_ERR, - "reset failed, giving up\n"); - goto out; + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; + + if (!(ehc->i.action & ATA_EH_RESET_MASK)) + continue; + + rc = ata_eh_reset(link, ata_link_nr_vacant(link), + prereset, softreset, hardreset, + postreset); + if (rc) { + ata_link_printk(link, KERN_ERR, + "reset failed, giving up\n"); + goto out; + } } ata_eh_thaw_port(ap); } - /* revalidate existing devices and attach new ones */ - rc = ata_eh_revalidate_and_attach(link, &dev); - if (rc) - goto dev_fail; + /* the rest */ + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - /* configure transfer mode if necessary */ - if (ehc->i.flags & ATA_EHI_SETMODE) { - rc = ata_set_mode(link, &dev); + /* revalidate existing devices and attach new ones */ + rc = ata_eh_revalidate_and_attach(link, &dev); if (rc) goto dev_fail; - ehc->i.flags &= ~ATA_EHI_SETMODE; + + /* configure transfer mode if necessary */ + if (ehc->i.flags & ATA_EHI_SETMODE) { + rc = ata_set_mode(link, &dev); + if (rc) + goto dev_fail; + ehc->i.flags &= ~ATA_EHI_SETMODE; + } + + /* this link is okay now */ + ehc->i.flags = 0; + continue; + + dev_fail: + nr_failed_devs++; + if (ata_eh_handle_dev_fail(dev, rc)) + nr_disabled_devs++; + + if (ap->pflags & ATA_PFLAG_FROZEN) + break; } - goto out; + if (nr_failed_devs) { + if (nr_failed_devs != nr_disabled_devs) { + ata_port_printk(ap, KERN_WARNING, "failed to recover " + "some devices, retrying in 5 secs\n"); + ssleep(5); + } else { + /* no device left to recover, repeat fast */ + msleep(500); + } - dev_fail: - ata_eh_handle_dev_fail(dev, rc); - - if (ata_link_nr_enabled(link)) { - ata_link_printk(link, KERN_WARNING, "failed to recover some " - "devices, retrying in 5 secs\n"); - ssleep(5); - } else { - /* no device left, repeat fast */ - msleep(500); + goto retry; } - goto retry; - out: - if (rc) { - ata_link_for_each_dev(dev, link); - ata_dev_disable(dev); - } + if (rc && r_failed_link) + *r_failed_link = link; DPRINTK("EXIT, rc=%d\n", rc); return rc; @@ -2342,9 +2420,19 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - ata_eh_autopsy(&ap->link); - ata_eh_report(&ap->link); - ata_eh_recover(ap, prereset, softreset, hardreset, postreset); + struct ata_device *dev; + int rc; + + ata_eh_autopsy(ap); + ata_eh_report(ap); + + rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset, + NULL); + if (rc) { + ata_link_for_each_dev(dev, &ap->link) + ata_dev_disable(dev); + } + ata_eh_finish(ap); } From 41bda9c98035dd3589b02cbc1de02f71d2faf9c8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:24 +0900 Subject: [PATCH 2398/2804] libata-link: update hotplug to handle PMP links Update hotplug to handle PMP links. When PMP is attached, the PMP number corresponds to C of SCSI H:C:I:L. While at it, change argument to ata_find_dev() to @devno from @id to avoid confusion with SCSI device ID. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 7 +- drivers/ata/libata-scsi.c | 161 ++++++++++++++++++++++++++------------ 2 files changed, 115 insertions(+), 53 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index af9c0ab600dc..14f299278f1b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6604,6 +6604,7 @@ int ata_host_activate(struct ata_host *host, int irq, void ata_port_detach(struct ata_port *ap) { unsigned long flags; + struct ata_link *link; struct ata_device *dev; if (!ap->ops->error_handler) @@ -6621,8 +6622,10 @@ void ata_port_detach(struct ata_port *ap) */ spin_lock_irqsave(ap->lock, flags); - ata_link_for_each_dev(dev, &ap->link) - ata_dev_disable(dev); + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) + ata_dev_disable(dev); + } spin_unlock_irqrestore(ap->lock, flags); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 3d6d5f737994..58051ee40f1a 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2423,21 +2423,36 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) return 0; } -static struct ata_device * ata_find_dev(struct ata_port *ap, int id) +static struct ata_device * ata_find_dev(struct ata_port *ap, int devno) { - if (likely(id < ata_link_max_devices(&ap->link))) - return &ap->link.device[id]; + if (ap->nr_pmp_links == 0) { + if (likely(devno < ata_link_max_devices(&ap->link))) + return &ap->link.device[devno]; + } else { + if (likely(devno < ap->nr_pmp_links)) + return &ap->pmp_link[devno].device[0]; + } + return NULL; } static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { - /* skip commands not addressed to targets we simulate */ - if (unlikely(scsidev->channel || scsidev->lun)) - return NULL; + int devno; - return ata_find_dev(ap, scsidev->id); + /* skip commands not addressed to targets we simulate */ + if (ap->nr_pmp_links == 0) { + if (unlikely(scsidev->channel || scsidev->lun)) + return NULL; + devno = scsidev->id; + } else { + if (unlikely(scsidev->id || scsidev->lun)) + return NULL; + devno = scsidev->channel; + } + + return ata_find_dev(ap, devno); } /** @@ -2951,22 +2966,32 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) { int tries = 5; struct ata_device *last_failed_dev = NULL; + struct ata_link *link; struct ata_device *dev; if (ap->flags & ATA_FLAG_DISABLED) return; repeat: - ata_link_for_each_dev(dev, &ap->link) { - struct scsi_device *sdev; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + struct scsi_device *sdev; + int channel = 0, id = 0; - if (!ata_dev_enabled(dev) || dev->sdev) - continue; + if (!ata_dev_enabled(dev) || dev->sdev) + continue; - sdev = __scsi_add_device(ap->scsi_host, 0, dev->devno, 0, NULL); - if (!IS_ERR(sdev)) { - dev->sdev = sdev; - scsi_device_put(sdev); + if (ata_is_host_link(link)) + id = dev->devno; + else + channel = link->pmp; + + sdev = __scsi_add_device(ap->scsi_host, channel, id, 0, + NULL); + if (!IS_ERR(sdev)) { + dev->sdev = sdev; + scsi_device_put(sdev); + } } } @@ -2974,11 +2999,14 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) * failure occurred, scan would have failed silently. Check * whether all devices are attached. */ - ata_link_for_each_dev(dev, &ap->link) { - if (ata_dev_enabled(dev) && !dev->sdev) - break; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + if (ata_dev_enabled(dev) && !dev->sdev) + goto exit_loop; + } } - if (!dev) + exit_loop: + if (!link) return; /* we're missing some SCSI devices */ @@ -3092,6 +3120,25 @@ static void ata_scsi_remove_dev(struct ata_device *dev) } } +static void ata_scsi_handle_link_detach(struct ata_link *link) +{ + struct ata_port *ap = link->ap; + struct ata_device *dev; + + ata_link_for_each_dev(dev, link) { + unsigned long flags; + + if (!(dev->flags & ATA_DFLAG_DETACHED)) + continue; + + spin_lock_irqsave(ap->lock, flags); + dev->flags &= ~ATA_DFLAG_DETACHED; + spin_unlock_irqrestore(ap->lock, flags); + + ata_scsi_remove_dev(dev); + } +} + /** * ata_scsi_hotplug - SCSI part of hotplug * @work: Pointer to ATA port to perform SCSI hotplug on @@ -3108,7 +3155,7 @@ void ata_scsi_hotplug(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, hotplug_task.work); - struct ata_device *dev; + int i; if (ap->pflags & ATA_PFLAG_UNLOADING) { DPRINTK("ENTER/EXIT - unloading\n"); @@ -3117,19 +3164,14 @@ void ata_scsi_hotplug(struct work_struct *work) DPRINTK("ENTER\n"); - /* unplug detached devices */ - ata_link_for_each_dev(dev, &ap->link) { - unsigned long flags; - - if (!(dev->flags & ATA_DFLAG_DETACHED)) - continue; - - spin_lock_irqsave(ap->lock, flags); - dev->flags &= ~ATA_DFLAG_DETACHED; - spin_unlock_irqrestore(ap->lock, flags); - - ata_scsi_remove_dev(dev); - } + /* Unplug detached devices. We cannot use link iterator here + * because PMP links have to be scanned even if PMP is + * currently not attached. Iterate manually. + */ + ata_scsi_handle_link_detach(&ap->link); + if (ap->pmp_link) + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) + ata_scsi_handle_link_detach(&ap->pmp_link[i]); /* scan for new ones */ ata_scsi_scan_host(ap, 0); @@ -3157,26 +3199,40 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, unsigned int id, unsigned int lun) { struct ata_port *ap = ata_shost_to_port(shost); - struct ata_eh_info *ehi = &ap->link.eh_info; unsigned long flags; - int rc = 0; + int devno, rc = 0; if (!ap->ops->error_handler) return -EOPNOTSUPP; - if ((channel != SCAN_WILD_CARD && channel != 0) || - (lun != SCAN_WILD_CARD && lun != 0)) + if (lun != SCAN_WILD_CARD && lun) return -EINVAL; + if (ap->nr_pmp_links == 0) { + if (channel != SCAN_WILD_CARD && channel) + return -EINVAL; + devno = id; + } else { + if (id != SCAN_WILD_CARD && id) + return -EINVAL; + devno = channel; + } + spin_lock_irqsave(ap->lock, flags); - if (id == SCAN_WILD_CARD) { - ehi->probe_mask |= (1 << ata_link_max_devices(&ap->link)) - 1; - ehi->action |= ATA_EH_SOFTRESET; + if (devno == SCAN_WILD_CARD) { + struct ata_link *link; + + ata_port_for_each_link(link, ap) { + struct ata_eh_info *ehi = &link->eh_info; + ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1; + ehi->action |= ATA_EH_SOFTRESET; + } } else { - struct ata_device *dev = ata_find_dev(ap, id); + struct ata_device *dev = ata_find_dev(ap, devno); if (dev) { + struct ata_eh_info *ehi = &dev->link->eh_info; ehi->probe_mask |= 1 << dev->devno; ehi->action |= ATA_EH_SOFTRESET; ehi->flags |= ATA_EHI_RESUME_LINK; @@ -3210,23 +3266,26 @@ void ata_scsi_dev_rescan(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, scsi_rescan_task); + struct ata_link *link; struct ata_device *dev; unsigned long flags; spin_lock_irqsave(ap->lock, flags); - ata_link_for_each_dev(dev, &ap->link) { - struct scsi_device *sdev = dev->sdev; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + struct scsi_device *sdev = dev->sdev; - if (!ata_dev_enabled(dev) || !sdev) - continue; - if (scsi_device_get(sdev)) - continue; + if (!ata_dev_enabled(dev) || !sdev) + continue; + if (scsi_device_get(sdev)) + continue; - spin_unlock_irqrestore(ap->lock, flags); - scsi_rescan_device(&(sdev->sdev_gendev)); - scsi_device_put(sdev); - spin_lock_irqsave(ap->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); + scsi_rescan_device(&(sdev->sdev_gendev)); + scsi_device_put(sdev); + spin_lock_irqsave(ap->lock, flags); + } } spin_unlock_irqrestore(ap->lock, flags); From e3667ebf857ba744b5211c90d46f6a17dd9a2479 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:24 +0900 Subject: [PATCH 2399/2804] libata-link: update Power Management to handle PMP links Update Power Management to consider PMP links. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 14f299278f1b..8a79b976f08a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5912,6 +5912,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; + struct ata_link *link; /* Previous resume operation might still be in * progress. Wait for PM_PENDING to clear. @@ -5931,8 +5932,10 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, } ap->pflags |= ATA_PFLAG_PM_PENDING; - ap->link.eh_info.action |= action; - ap->link.eh_info.flags |= ehi_flags; + __ata_port_for_each_link(link, ap) { + link->eh_info.action |= action; + link->eh_info.flags |= ehi_flags; + } ata_port_schedule_eh(ap); From 0bc2a79a2002e3cc1b514c100b6c576983da6a90 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 31 Jul 2007 14:01:48 +0100 Subject: [PATCH 2400/2804] libata: Correct IORDY handling Debugging a report of a problem with an ancient solid state disk showed up some problems in the IORDY handling 1. We check the wrong bit to see if the device has IORDY 2. Even then some ancient creaking piles of crap don't support SETXFER at all. The cases it fixes are obscure and the risk of side effects is slight but possible. This also moves us slightly closer to supporting original MFM/RLL disks with libata. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 +++++- include/linux/ata.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8a79b976f08a..02425e401a6d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2759,7 +2759,11 @@ static int ata_dev_set_mode(struct ata_device *dev) /* Old CFA may refuse this command, which is just fine */ if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id)) err_mask &= ~AC_ERR_DEV; - + /* Some very old devices and some bad newer ones fail any kind of + SET_XFERMODE request but support PIO0-2 timings and no IORDY */ + if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) && + dev->pio_mode <= XFER_PIO_2) + err_mask &= ~AC_ERR_DEV; if (err_mask) { ata_dev_printk(dev, KERN_ERR, "failed to set xfermode " "(err_mask=0x%x)\n", err_mask); diff --git a/include/linux/ata.h b/include/linux/ata.h index c043c1ccf1c5..40c7af05fdb9 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -358,7 +358,7 @@ struct ata_taskfile { #define ata_id_removeable(id) ((id)[0] & (1 << 7)) #define ata_id_has_dword_io(id) ((id)[50] & (1 << 0)) #define ata_id_iordy_disable(id) ((id)[49] & (1 << 10)) -#define ata_id_has_iordy(id) ((id)[49] & (1 << 9)) +#define ata_id_has_iordy(id) ((id)[49] & (1 << 11)) #define ata_id_u32(id,n) \ (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)])) #define ata_id_u64(id,n) \ From 4cc980b34b2a25f600576dcd11de388bc44e1ebd Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 15 Aug 2007 03:19:45 -0400 Subject: [PATCH 2401/2804] libata: move ata_altstatus() to pio data xfer functions Move ata_altstatus() out from ata_hsm_move() to the pio data xfer functions like ata_pio_sectors() and atapi_pio_bytes() where it makes more sense. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 02425e401a6d..fc0679370638 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4614,6 +4614,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) ata_pio_sector(qc); } else ata_pio_sector(qc); + + ata_altstatus(qc->ap); /* flush */ } /** @@ -4788,6 +4790,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); __atapi_pio_bytes(qc, bytes); + ata_altstatus(ap); /* flush */ return; @@ -4959,7 +4962,6 @@ fsm_start: */ ap->hsm_task_state = HSM_ST; ata_pio_sectors(qc); - ata_altstatus(ap); /* flush */ } else /* send CDB */ atapi_send_cdb(ap, qc); @@ -5040,7 +5042,6 @@ fsm_start: if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { ata_pio_sectors(qc); - ata_altstatus(ap); status = ata_wait_idle(ap); } @@ -5060,13 +5061,11 @@ fsm_start: if (ap->hsm_task_state == HSM_ST_LAST && (!(qc->tf.flags & ATA_TFLAG_WRITE))) { /* all data read */ - ata_altstatus(ap); status = ata_wait_idle(ap); goto fsm_start; } } - ata_altstatus(ap); /* flush */ poll_next = 1; break; From baf4fdfaaf5cb9f4fb1c341c8cef60a64e580582 Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Wed, 8 Aug 2007 01:08:45 +0900 Subject: [PATCH 2402/2804] libata: add support for ATA_16 on ATAPI Add support for issuing ATA_16 passthru commands to ATAPI devices managed by libata. It requires the previous CDB length fix patch. A boot/module parameter, "atapi_passthru16=0" can be used to globally disable this feature, if ever desired. tj: restructured __ata_scsi_queuecmd() according to Jeff's suggestion. Signed-off-by: Mark Lord Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 +++ drivers/ata/libata-scsi.c | 52 +++++++++++++++++++++++++++------------ drivers/ata/libata.h | 1 + 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fc0679370638..75ccf46972d8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -86,6 +86,10 @@ int atapi_dmadir = 0; module_param(atapi_dmadir, int, 0444); MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)"); +int atapi_passthru16 = 1; +module_param(atapi_passthru16, int, 0444); +MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)"); + int libata_fua = 0; module_param_named(fua, libata_fua, int, 0444); MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 58051ee40f1a..7d66c986a54c 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2761,28 +2761,48 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *), struct ata_device *dev) { + u8 scsi_op = scmd->cmnd[0]; + ata_xlat_func_t xlat_func; int rc = 0; - if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) { - DPRINTK("bad CDB len=%u, max=%u\n", - scmd->cmd_len, dev->cdb_len); - scmd->result = DID_ERROR << 16; - done(scmd); - return 0; + if (dev->class == ATA_DEV_ATA) { + if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) + goto bad_cdb_len; + + xlat_func = ata_get_xlat_func(dev, scsi_op); + } else { + if (unlikely(!scmd->cmd_len)) + goto bad_cdb_len; + + xlat_func = NULL; + if (likely((scsi_op != ATA_16) || !atapi_passthru16)) { + /* relay SCSI command to ATAPI device */ + if (unlikely(scmd->cmd_len > dev->cdb_len)) + goto bad_cdb_len; + + xlat_func = atapi_xlat; + } else { + /* ATA_16 passthru, treat as an ATA command */ + if (unlikely(scmd->cmd_len > 16)) + goto bad_cdb_len; + + xlat_func = ata_get_xlat_func(dev, scsi_op); + } } - if (dev->class == ATA_DEV_ATA) { - ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, - scmd->cmnd[0]); - - if (xlat_func) - rc = ata_scsi_translate(dev, scmd, done, xlat_func); - else - ata_scsi_simulate(dev, scmd, done); - } else - rc = ata_scsi_translate(dev, scmd, done, atapi_xlat); + if (xlat_func) + rc = ata_scsi_translate(dev, scmd, done, xlat_func); + else + ata_scsi_simulate(dev, scmd, done); return rc; + + bad_cdb_len: + DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n", + scmd->cmd_len, scsi_op, dev->cdb_len); + scmd->result = DID_ERROR << 16; + done(scmd); + return 0; } /** diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 6d85edefa7c6..11f64a43b38a 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -56,6 +56,7 @@ extern unsigned int ata_print_id; extern struct workqueue_struct *ata_aux_wq; extern int atapi_enabled; extern int atapi_dmadir; +extern int atapi_passthru16; extern int libata_fua; extern int libata_noacpi; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); From 50a99018787aa1aed812e09ad5b27647475656a0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 8 Aug 2007 14:27:00 +0100 Subject: [PATCH 2403/2804] libata-core: Document some limits/assumptions about ID_ATA Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 75ccf46972d8..d2141a04fff1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1618,6 +1618,9 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) * devices. This function also issues ATA_CMD_INIT_DEV_PARAMS * for pre-ATA4 drives. * + * FIXME: ATA_CMD_ID_ATA is optional for early drives and right + * now we abort if we hit that case. + * * LOCKING: * Kernel thread context (may sleep) * @@ -1745,10 +1748,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, /* * The exact sequence expected by certain pre-ATA4 drives is: * SRST RESET - * IDENTIFY - * INITIALIZE DEVICE PARAMETERS + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) * anything else.. * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. */ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { err_mask = ata_dev_init_params(dev, id[3], id[6]); From 4f34337b1f6f7c1e0f2e3c938eb9eadd340593fe Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 8 Aug 2007 14:30:31 +0100 Subject: [PATCH 2404/2804] libata: Note that our cache flush code needs fixing up Remembered this while doing auditing and code review versus the specs Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d2141a04fff1..c0f3c78a2be0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5906,6 +5906,10 @@ int ata_flush_cache(struct ata_device *dev) else cmd = ATA_CMD_FLUSH; + /* This is wrong. On a failed flush we get back the LBA of the lost + sector and we should (assuming it wasn't aborted as unknown) issue + a further flush command to continue the writeback until it + does not error */ err_mask = ata_do_simple_cmd(dev, cmd); if (err_mask) { ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n"); From 05d1efffdc9bf84311bb1a3c2e3db55b544ca119 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 10 Aug 2007 13:59:49 -0700 Subject: [PATCH 2405/2804] pata_cmd64x: Set up MWDMA modes properly Set the MWDMA timing by updating the correct registers. Split the PIO path as this is mostly shared code. Wants testing. Signed-off-by: Alan Cox Tested-by: Mikael Pettersson Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/pata_cmd64x.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index e34b632487d7..922902a1b4ae 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -31,7 +31,7 @@ #include #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.4" +#define DRV_VERSION "0.2.5" /* * CMD64x specific registers definition. @@ -88,14 +88,15 @@ static int cmd648_cable_detect(struct ata_port *ap) } /** - * cmd64x_set_piomode - set initial PIO mode data + * cmd64x_set_piomode - set PIO and MWDMA timing * @ap: ATA interface * @adev: ATA device + * @mode: mode * - * Called to do the PIO mode setup. + * Called to do the PIO and MWDMA mode setup. */ -static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) +static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 mode) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct ata_timing t; @@ -117,8 +118,9 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) int arttim = arttim_port[ap->port_no][adev->devno]; int drwtim = drwtim_port[ap->port_no][adev->devno]; - - if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) { + /* ata_timing_compute is smart and will produce timings for MWDMA + that don't violate the drives PIO capabilities. */ + if (ata_timing_compute(adev, mode, &t, T, 0) < 0) { printk(KERN_ERR DRV_NAME ": mode computation failed.\n"); return; } @@ -167,6 +169,20 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) pci_write_config_byte(pdev, drwtim, (t.active << 4) | t.recover); } +/** + * cmd64x_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + * + * Used when configuring the devices ot set the PIO timings. All the + * actual work is done by the PIO/MWDMA setting helper + */ + +static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + cmd64x_set_timing(ap, adev, adev->pio_mode); +} + /** * cmd64x_set_dmamode - set initial DMA mode data * @ap: ATA interface @@ -180,9 +196,6 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) static const u8 udma_data[] = { 0x30, 0x20, 0x10, 0x20, 0x10, 0x00 }; - static const u8 mwdma_data[] = { - 0x30, 0x20, 0x10 - }; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 regU, regD; @@ -208,8 +221,10 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) regU |= 1 << adev->devno; /* UDMA on */ if (adev->dma_mode > 2) /* 15nS timing */ regU |= 4 << adev->devno; - } else - regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift; + } else { + regU &= ~ (1 << adev->devno); /* UDMA off */ + cmd64x_set_timing(ap, adev, adev->dma_mode); + } regD |= 0x20 << adev->devno; From 9f45cbd3f0fc597530aaf85cad7fe52cd63f1fd8 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 15 Aug 2007 03:57:11 -0400 Subject: [PATCH 2406/2804] [libata] check for SATA async notify support Check to see if an ATAPI device supports Asynchronous Notification. If so, enable it, if the host controller supports AN. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 53 +++++++++++++++++++++++++++++++++++++++ include/linux/ata.h | 9 +++++++ include/linux/libata.h | 2 ++ 3 files changed, 64 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c0f3c78a2be0..9f87f7ddd485 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -70,6 +70,7 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); +static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable); static void ata_dev_xfermask(struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev); @@ -1987,6 +1988,22 @@ int ata_dev_configure(struct ata_device *dev) } dev->cdb_len = (unsigned int) rc; + /* + * check to see if this ATAPI device supports + * Asynchronous Notification + */ + if ((ap->flags & ATA_FLAG_AN) && ata_id_has_AN(id)) { + int err; + /* issue SET feature command to turn this on */ + err = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE); + if (err) + ata_dev_printk(dev, KERN_ERR, + "unable to set AN, err %x\n", + err); + else + dev->flags |= ATA_DFLAG_AN; + } + if (ata_id_cdb_intr(dev->id)) { dev->flags |= ATA_DFLAG_CDB_INTR; cdb_intr_string = ", CDB intr"; @@ -3974,6 +3991,42 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) return err_mask; } +/** + * ata_dev_set_AN - Issue SET FEATURES - SATA FEATURES + * @dev: Device to which command will be sent + * @enable: Whether to enable or disable the feature + * + * Issue SET FEATURES - SATA FEATURES command to device @dev + * on port @ap with sector count set to indicate Asynchronous + * Notification feature + * + * LOCKING: + * PCI/etc. bus probe sem. + * + * RETURNS: + * 0 on success, AC_ERR_* mask otherwise. + */ +static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable) +{ + struct ata_taskfile tf; + unsigned int err_mask; + + /* set up set-features taskfile */ + DPRINTK("set features - SATA features\n"); + + ata_tf_init(dev, &tf); + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = SATA_AN; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + + DPRINTK("EXIT, err_mask=%x\n", err_mask); + return err_mask; +} + /** * ata_dev_init_params - Issue INIT DEV PARAMS command * @dev: Device to which command will be sent diff --git a/include/linux/ata.h b/include/linux/ata.h index 40c7af05fdb9..fba8e1459832 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -230,6 +230,12 @@ enum { SETFEATURES_SPINUP = 0x07, /* Spin-up drive */ + SETFEATURES_SATA_ENABLE = 0x10, /* Enable use of SATA feature */ + SETFEATURES_SATA_DISABLE = 0x90, /* Disable use of SATA feature */ + + /* SETFEATURE Sector counts for SATA features */ + SATA_AN = 0x05, /* Asynchronous Notification */ + /* ATAPI stuff */ ATAPI_PKT_DMA = (1 << 0), ATAPI_DMADIR = (1 << 2), /* ATAPI data dir: @@ -357,6 +363,9 @@ struct ata_taskfile { #define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1) #define ata_id_removeable(id) ((id)[0] & (1 << 7)) #define ata_id_has_dword_io(id) ((id)[50] & (1 << 0)) +#define ata_id_has_AN(id) \ + ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ + ((id)[78] & (1 << 5)) ) #define ata_id_iordy_disable(id) ((id)[49] & (1 << 10)) #define ata_id_has_iordy(id) ((id)[49] & (1 << 11)) #define ata_id_u32(id,n) \ diff --git a/include/linux/libata.h b/include/linux/libata.h index 7a1793bd2371..6dd5b437210d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -139,6 +139,7 @@ enum { ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ + ATA_DFLAG_AN = (1 << 7), /* device supports AN */ ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ @@ -179,6 +180,7 @@ enum { 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 */ + ATA_FLAG_AN = (1 << 18), /* controller supports AN */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be From 2f2949680ad89d606db838340b17c30216c0bb0f Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 15 Aug 2007 04:11:25 -0400 Subject: [PATCH 2407/2804] [libata] ahci: send event when AN received When we get an SDB FIS with the 'N' bit set, we should send an event to user space to indicate that there has been a media change. This will be done via the scsi device. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 24 ++++++++++++++++++++++++ drivers/ata/libata-scsi.c | 18 ++++++++++++++++++ include/linux/libata.h | 1 + 3 files changed, 43 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 483733783cf8..d52b73ab795a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1368,6 +1368,30 @@ static void ahci_port_intr(struct ata_port *ap) return; } + if (status & PORT_IRQ_SDB_FIS) { + /* + * if this is an ATAPI device with AN turned on, + * then we should interrogate the device to + * determine the cause of the interrupt + * + * for AN - this we should check the SDB FIS + * and find the I and N bits set + */ + const __le32 *f = pp->rx_fis + RX_FIS_SDB; + u32 f0 = le32_to_cpu(f[0]); + + /* check the 'N' bit in word 0 of the FIS */ + if (f0 & (1 << 15)) { + int port_addr = ((f0 & 0x00000f00) >> 8); + struct ata_device *adev; + if (port_addr < ATA_MAX_DEVICES) { + adev = &ap->link.device[port_addr]; + if (adev->flags & ATA_DFLAG_AN) + ata_scsi_media_change_notify(adev); + } + } + } + if (ap->link.sactive) qc_active = readl(port_mmio + PORT_SCR_ACT); else diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7d66c986a54c..f0f586b56c20 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3159,6 +3159,24 @@ static void ata_scsi_handle_link_detach(struct ata_link *link) } } +/** + * ata_scsi_media_change_notify - send media change event + * @atadev: Pointer to the disk device with media change event + * + * Tell the block layer to send a media change notification + * event. + * + * LOCKING: + * interrupt context, may not sleep. + */ +void ata_scsi_media_change_notify(struct ata_device *atadev) +{ +#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED + scsi_device_event_notify(atadev->sdev, SDEV_MEDIA_CHANGE); +#endif +} +EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify); + /** * ata_scsi_hotplug - SCSI part of hotplug * @work: Pointer to ATA port to perform SCSI hotplug on diff --git a/include/linux/libata.h b/include/linux/libata.h index 6dd5b437210d..d98e8b50e20c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -755,6 +755,7 @@ extern void ata_host_init(struct ata_host *, struct device *, extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); +extern void ata_scsi_media_change_notify(struct ata_device *atadev); extern void ata_sas_port_destroy(struct ata_port *); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, struct ata_port_info *, struct Scsi_Host *); From a738492501eaf6e266acc53a064552b3fcc706b2 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 9 Aug 2007 14:23:41 -0700 Subject: [PATCH 2408/2804] ahci: Store interrupt value Use a stored value for which interrupts to enable. Changing this allows us to selectively turn off certain interrupts later and have them stay off. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index d52b73ab795a..baf7d0562190 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -175,6 +175,7 @@ enum { AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */ + AHCI_FLAG_NO_HOTPLUG = (1 << 31), /* ignore PxSERR.DIAG.N */ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | @@ -215,6 +216,7 @@ struct ahci_port_priv { unsigned int ncq_saw_d2h:1; unsigned int ncq_saw_dmas:1; unsigned int ncq_saw_sdb:1; + u32 intr_mask; /* interrupts to enable */ }; static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); @@ -1552,6 +1554,7 @@ static void ahci_thaw(struct ata_port *ap) void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; + struct ahci_port_priv *pp = ap->private_data; /* clear IRQ */ tmp = readl(port_mmio + PORT_IRQ_STAT); @@ -1559,7 +1562,7 @@ static void ahci_thaw(struct ata_port *ap) writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); /* turn IRQ back on */ - writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_error_handler(struct ata_port *ap) @@ -1713,6 +1716,12 @@ static int ahci_port_start(struct ata_port *ap) pp->cmd_tbl = mem; pp->cmd_tbl_dma = mem_dma; + /* + * Save off initial list of interrupts to be enabled. + * This could be changed later + */ + pp->intr_mask = DEF_PORT_IRQ; + ap->private_data = pp; /* engage engines, captain */ From 2eb829e934abb10db36ddaacd82603c3cdd98b6d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 10 Aug 2007 13:59:51 -0700 Subject: [PATCH 2409/2804] ata_piix: disallow UDMA 133 on ICH5 & ICH7 There is another outstanding issue with ata_piix.c. Intel has never officially supported anything faster than PATA 100MB/s. But, the ata_piix.c driver "define" the ICH5 & ICH7 as UDMA6 (aka 133MB/s) capable. [ Well, no one has probably noticed it before, because there is bug in do_pata_set_dmamode... Just look at libata_atapiix_enable_real_udma133.patch and you'll see what wrong with it. ] Here are Intel's datasheets for the affected chipsets: ICH5 Datasheet: http://www.intel.com/design/chipsets/datashts/252516.htm (See note on page 183: "... the ICH5 supports reads at the maximum rate of 100MB/s.") ICH7 Datasheet: http://www.intel.com/design/chipsets/datashts/307013.htm (See first note on page 190: "... the ICH7 supports reads at the maximum rate of 100MB/s.") They are two different ways to deal with it: - Either - 1. replace all ich_pata_133 with ich_pata_100. (libata_atapiix_disable_udma6.diff - diff from 2.6.22 ) - Or - 2. keep all ich_pata_133 and fix the bug in "do_pata_set_dmamode". (libata_atapiix_enable_real_udma133.patch - diff from 2.6.22) If there are any concerns about the safety of the patch patch: http://lkml.org/lkml/2007/7/6/292 (It was already tested by an Intel employee, but I guess a bit more user input is necessary here... ) This patch implements 1. Cc: Alan Cox Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Christian Lamparter Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 03fe493026eb..4b66b9e9638f 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -123,7 +123,7 @@ enum { ich_pata_33 = 1, /* ICH up to UDMA 33 only */ ich_pata_66 = 2, /* ICH up to 66 Mhz */ ich_pata_100 = 3, /* ICH up to UDMA 100 */ - ich_pata_133 = 4, /* ICH up to UDMA 133 */ + /* ICH up to UDMA 133 is not supported */ ich5_sata = 5, ich6_sata = 6, ich6_sata_ahci = 7, @@ -199,7 +199,7 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* Intel ICH5 */ - { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, + { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* C-ICH (i810E2) */ { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ESB (855GME/875P + 6300ESB) UDMA 100 */ @@ -207,7 +207,7 @@ static const struct pci_device_id piix_pci_tbl[] = { /* ICH6 (and 6) (i915) UDMA 100 */ { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ICH7/7-R (i945, i975) UDMA 100*/ - { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, + { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ICH8 Mobile PATA Controller */ { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, @@ -505,7 +505,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &ich_pata_ops, }, - /* ich_pata_133: 4 ICH with full UDMA6 */ + /* ich_pata_133: 4 - Not supported - */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, From b8773531cc54c1ed10c8ec301353ee6b53b601a5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 10 Aug 2007 13:59:33 -0700 Subject: [PATCH 2410/2804] libata-add-irq_flags-to-struct-pata_platform_info-fix Remove unneeded, undesirable cast of void*. Cc: Jeff Garzik Cc: Sonic Zhang Cc: Tejun Heo Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/pata_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 37e5158391da..9dc628931e99 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -207,7 +207,7 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; - pp_info = (struct pata_platform_info *)(pdev->dev.platform_data); + pp_info = pdev->dev.platform_data; pata_platform_setup_port(&ap->ioaddr, pp_info); /* activate */ From 1552945669b4fb23bff8d3b30221bfe3ade63515 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 30 Jul 2007 14:23:03 +0900 Subject: [PATCH 2411/2804] libata: use ata_port_printk() in ata_wait_idle() ata_wait_idle() identified controller by printing out the address of the Status register. This is bogus because 1. it's iomapped address 2. some controllers don't have Status register and don't initialize the field. Use ata_port_printk() instead. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index d98e8b50e20c..86cc0491b35e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1182,9 +1182,11 @@ static inline u8 ata_wait_idle(struct ata_port *ap) { u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); +#ifdef ATA_DEBUG if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) - DPRINTK("ATA: abnormal status 0x%X on port 0x%p\n", - status, ap->ioaddr.status_addr); + ata_port_printk(ap, KERN_DEBUG, "abnormal Status 0x%X\n", + status); +#endif return status; } From cb94c1cf5a6beffbd8935eb91227df0dd1987644 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 30 Jul 2007 14:24:15 +0900 Subject: [PATCH 2412/2804] libata: add printf format attribute to ehi desc functions Tell the compiler that [__]ata_ehi_push_desc() functions take printf style format string and arguments. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index 86cc0491b35e..b89d191ceb2b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -948,8 +948,10 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, /* * ata_eh_info helpers */ -extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...); -extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...); +extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); +extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); extern void ata_ehi_clear_desc(struct ata_eh_info *ehi); static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi) From 6d32d30f55020d766388df7515f771f68c973033 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 15 Aug 2007 05:38:46 -0400 Subject: [PATCH 2413/2804] [libata] Remove ->irq_ack() hook, and ata_dummy_irq_on() * ->irq_ack() is redundant to what the irq handler already performs... chk-status + irq-clear. Furthermore, it is only called in one place, when screaming-irq-debugging is enabled, so we don't want to bother with a hook just for that. * ata_dummy_irq_on() is only ever used in drivers that have no callpath reaching ->irq_on(). Remove .irq_on hook from those drivers, and the now-unused ata_dummy_irq_on() Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 ---- drivers/ata/ata_generic.c | 1 - drivers/ata/ata_piix.c | 3 --- drivers/ata/libata-core.c | 6 ++--- drivers/ata/libata-sff.c | 40 --------------------------------- drivers/ata/pata_ali.c | 4 ---- drivers/ata/pata_amd.c | 6 ----- drivers/ata/pata_artop.c | 2 -- drivers/ata/pata_atiixp.c | 1 - drivers/ata/pata_cmd640.c | 1 - drivers/ata/pata_cmd64x.c | 3 --- drivers/ata/pata_cs5520.c | 1 - drivers/ata/pata_cs5530.c | 1 - drivers/ata/pata_cs5535.c | 1 - drivers/ata/pata_cypress.c | 1 - drivers/ata/pata_efar.c | 1 - drivers/ata/pata_hpt366.c | 1 - drivers/ata/pata_hpt37x.c | 4 ---- drivers/ata/pata_hpt3x2n.c | 1 - drivers/ata/pata_hpt3x3.c | 1 - drivers/ata/pata_icside.c | 18 --------------- drivers/ata/pata_isapnp.c | 1 - drivers/ata/pata_it8213.c | 1 - drivers/ata/pata_it821x.c | 2 -- drivers/ata/pata_ixp4xx_cf.c | 1 - drivers/ata/pata_jmicron.c | 1 - drivers/ata/pata_legacy.c | 7 ------ drivers/ata/pata_marvell.c | 1 - drivers/ata/pata_mpc52xx.c | 1 - drivers/ata/pata_mpiix.c | 1 - drivers/ata/pata_netcell.c | 1 - drivers/ata/pata_ns87410.c | 1 - drivers/ata/pata_oldpiix.c | 1 - drivers/ata/pata_opti.c | 1 - drivers/ata/pata_optidma.c | 2 -- drivers/ata/pata_pcmcia.c | 1 - drivers/ata/pata_pdc2027x.c | 2 -- drivers/ata/pata_pdc202xx_old.c | 2 -- drivers/ata/pata_platform.c | 1 - drivers/ata/pata_qdi.c | 2 -- drivers/ata/pata_radisys.c | 1 - drivers/ata/pata_rz1000.c | 1 - drivers/ata/pata_sc1200.c | 1 - drivers/ata/pata_scc.c | 33 --------------------------- drivers/ata/pata_serverworks.c | 2 -- drivers/ata/pata_sil680.c | 1 - drivers/ata/pata_sis.c | 6 ----- drivers/ata/pata_sl82c105.c | 1 - drivers/ata/pata_triflex.c | 1 - drivers/ata/pata_via.c | 2 -- drivers/ata/pata_winbond.c | 1 - drivers/ata/pdc_adma.c | 1 - drivers/ata/sata_inic162x.c | 1 - drivers/ata/sata_mv.c | 3 --- drivers/ata/sata_nv.c | 4 ---- drivers/ata/sata_promise.c | 3 --- drivers/ata/sata_qstor.c | 1 - drivers/ata/sata_sil.c | 1 - drivers/ata/sata_sil24.c | 2 -- drivers/ata/sata_sis.c | 1 - drivers/ata/sata_svw.c | 1 - drivers/ata/sata_sx4.c | 1 - drivers/ata/sata_uli.c | 1 - drivers/ata/sata_via.c | 3 --- drivers/ata/sata_vsc.c | 1 - include/linux/libata.h | 4 ---- 66 files changed, 2 insertions(+), 207 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index baf7d0562190..c888c966a020 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -276,8 +276,6 @@ static const struct ata_port_operations ahci_ops = { .qc_issue = ahci_qc_issue, .irq_clear = ahci_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -310,8 +308,6 @@ static const struct ata_port_operations ahci_vt8251_ops = { .qc_issue = ahci_qc_issue, .irq_clear = ahci_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index e390ad47c8ef..6ec1bbc4fcc4 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -121,7 +121,6 @@ static struct ata_port_operations generic_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 4b66b9e9638f..68bc0ae671c5 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -318,7 +318,6 @@ static const struct ata_port_operations piix_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -352,7 +351,6 @@ static const struct ata_port_operations ich_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -382,7 +380,6 @@ static const struct ata_port_operations piix_sata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9f87f7ddd485..4f8b8d210cf4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5747,7 +5747,8 @@ idle_irq: #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { - ap->ops->irq_ack(ap, 0); /* debug trap */ + ata_chk_status(ap); + ap->ops->irq_clear(ap); ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } @@ -7137,9 +7138,6 @@ EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); EXPORT_SYMBOL_GPL(ata_do_eh); EXPORT_SYMBOL_GPL(ata_irq_on); -EXPORT_SYMBOL_GPL(ata_dummy_irq_on); -EXPORT_SYMBOL_GPL(ata_irq_ack); -EXPORT_SYMBOL_GPL(ata_dummy_irq_ack); EXPORT_SYMBOL_GPL(ata_dev_try_classify); EXPORT_SYMBOL_GPL(ata_cable_40wire); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index dd528dbd9ccf..ccef99a0337c 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -64,46 +64,6 @@ u8 ata_irq_on(struct ata_port *ap) return tmp; } -u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; } - -/** - * ata_irq_ack - Acknowledge a device interrupt. - * @ap: Port on which interrupts are enabled. - * - * Wait up to 10 ms for legacy IDE device to become idle (BUSY - * or BUSY+DRQ clear). Obtain dma status and port status from - * device. Clear the interrupt. Return port status. - * - * LOCKING: - */ - -u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) -{ - unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; - u8 host_stat = 0, post_stat = 0, status; - - status = ata_busy_wait(ap, bits, 1000); - if (status & bits) - if (ata_msg_err(ap)) - printk(KERN_ERR "abnormal status 0x%X\n", status); - - if (ap->ioaddr.bmdma_addr) { - /* get controller status; clear intr, err bits */ - host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - - post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - } - if (ata_msg_intr(ap)) - printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", - __FUNCTION__, - host_stat, post_stat, status); - return status; -} - -u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; } - /** * ata_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 32a10c99c06f..9436c4963929 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -327,7 +327,6 @@ static struct ata_port_operations ali_early_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -369,7 +368,6 @@ static struct ata_port_operations ali_20_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -408,7 +406,6 @@ static struct ata_port_operations ali_c2_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -446,7 +443,6 @@ static struct ata_port_operations ali_c5_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index d0cebe16a8ee..46f829c838b3 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -358,7 +358,6 @@ static struct ata_port_operations amd33_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -393,7 +392,6 @@ static struct ata_port_operations amd66_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -428,7 +426,6 @@ static struct ata_port_operations amd100_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -463,7 +460,6 @@ static struct ata_port_operations amd133_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -498,7 +494,6 @@ static struct ata_port_operations nv100_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -533,7 +528,6 @@ static struct ata_port_operations nv133_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 361f2fca7e54..8c864353596e 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -361,7 +361,6 @@ static const struct ata_port_operations artop6210_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -394,7 +393,6 @@ static const struct ata_port_operations artop6260_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 656f4d0a5728..f2bfdeb44023 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -262,7 +262,6 @@ static struct ata_port_operations atiixp_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 0feb5ae8c486..a292ed97246d 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -213,7 +213,6 @@ static struct ata_port_operations cmd640_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = cmd640_port_start, }; diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 922902a1b4ae..d308c4644647 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -313,7 +313,6 @@ static struct ata_port_operations cmd64x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -348,7 +347,6 @@ static struct ata_port_operations cmd646r1_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -383,7 +381,6 @@ static struct ata_port_operations cmd648_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index e2459088cdcd..300dcff949e2 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -184,7 +184,6 @@ static struct ata_port_operations cs5520_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index eaaea848b649..2b770072f392 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -209,7 +209,6 @@ static struct ata_port_operations cs5530_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 360b6f32e17e..94b1a9caf3cb 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -206,7 +206,6 @@ static struct ata_port_operations cs5535_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 6cbc8778bf4f..8c439a9bb5dd 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -158,7 +158,6 @@ static struct ata_port_operations cy82c693_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 9f6fae6e38bf..4d646ffb257b 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -279,7 +279,6 @@ static const struct ata_port_operations efar_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 6f7d34ad19ef..508d1cab52d1 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -342,7 +342,6 @@ static struct ata_port_operations hpt366_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 1a4d0ad68d18..896e6e31c67f 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -673,7 +673,6 @@ static struct ata_port_operations hpt370_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -712,7 +711,6 @@ static struct ata_port_operations hpt370a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -752,7 +750,6 @@ static struct ata_port_operations hpt372_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -792,7 +789,6 @@ static struct ata_port_operations hpt374_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 739a89180eb9..2b7f099ac785 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -391,7 +391,6 @@ static struct ata_port_operations hpt3x2n_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index be0f05efac6d..a2f81f40d7ac 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -153,7 +153,6 @@ static struct ata_port_operations hpt3x3_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 64a711776c45..ffcccfc0b9d4 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -357,23 +357,6 @@ static void pata_icside_error_handler(struct ata_port *ap) pata_icside_postreset); } -static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq) -{ - unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; - u8 status; - - status = ata_busy_wait(ap, bits, 1000); - if (status & bits) - if (ata_msg_err(ap)) - printk(KERN_ERR "abnormal status 0x%X\n", status); - - if (ata_msg_intr(ap)) - printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n", - __FUNCTION__, status); - - return status; -} - static struct ata_port_operations pata_icside_port_ops = { .port_disable = ata_port_disable, @@ -403,7 +386,6 @@ static struct ata_port_operations pata_icside_port_ops = { .irq_clear = ata_dummy_noret, .irq_on = ata_irq_on, - .irq_ack = pata_icside_irq_ack, .port_start = pata_icside_port_start, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 9e553c54203a..b8d6d5c43537 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -58,7 +58,6 @@ static struct ata_port_operations isapnp_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 1daf1e19bdfc..8aae9d7171c1 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -289,7 +289,6 @@ static const struct ata_port_operations it8213_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index f32d9b7ab496..0179b29c5156 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -650,7 +650,6 @@ static struct ata_port_operations it821x_smart_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = it821x_port_start, }; @@ -687,7 +686,6 @@ static struct ata_port_operations it821x_passthru_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_handler = ata_interrupt, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = it821x_port_start, }; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 6bf1709508ab..ce1f9b17ad32 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -127,7 +127,6 @@ static struct ata_port_operations ixp4xx_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_dummy_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 1619b86b74af..26f84063859d 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -168,7 +168,6 @@ static const struct ata_port_operations jmicron_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index cfb2bc86a1d1..6529d34f0370 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -171,7 +171,6 @@ static struct ata_port_operations simple_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -200,7 +199,6 @@ static struct ata_port_operations legacy_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -316,7 +314,6 @@ static struct ata_port_operations pdc20230_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -372,7 +369,6 @@ static struct ata_port_operations ht6560a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -439,7 +435,6 @@ static struct ata_port_operations ht6560b_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -561,7 +556,6 @@ static struct ata_port_operations opti82c611a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -695,7 +689,6 @@ static struct ata_port_operations opti82c46x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index b4dd18f3fa5d..021d9d9218bd 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -139,7 +139,6 @@ static const struct ata_port_operations marvell_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 099f4cdc4cd9..6e3fac2fedc4 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -299,7 +299,6 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 36c964b9e7da..8a82fcd4fa31 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -190,7 +190,6 @@ static struct ata_port_operations mpiix_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 40eb574828bf..2d64c58482fa 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -68,7 +68,6 @@ static const struct ata_port_operations netcell_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 65a217727718..00a763c67f99 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -185,7 +185,6 @@ static struct ata_port_operations ns87410_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 5b2c86fe9fc2..851dae960018 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -266,7 +266,6 @@ static const struct ata_port_operations oldpiix_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 5770c7755a62..0ab300cda9b7 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -210,7 +210,6 @@ static struct ata_port_operations opti_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 09ef725afd90..51c49283fb39 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -398,7 +398,6 @@ static struct ata_port_operations optidma_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -434,7 +433,6 @@ static struct ata_port_operations optiplus_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 9bfe12ac851a..f2167729c3df 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -127,7 +127,6 @@ static struct ata_port_operations pcmcia_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index db069d7515bc..7c6df320c833 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -173,7 +173,6 @@ static struct ata_port_operations pdc2027x_pata100_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -208,7 +207,6 @@ static struct ata_port_operations pdc2027x_pata133_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 92447bed5e77..b03b33872457 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -275,7 +275,6 @@ static struct ata_port_operations pdc2024x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -310,7 +309,6 @@ static struct ata_port_operations pdc2026x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 9dc628931e99..a616616706da 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -89,7 +89,6 @@ static struct ata_port_operations pata_platform_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_dummy_ret0, }; diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index ec2206e820ac..ade5a4421663 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -192,7 +192,6 @@ static struct ata_port_operations qdi6500_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -220,7 +219,6 @@ static struct ata_port_operations qdi6580_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 7d1aabed422d..66b9a341931b 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -231,7 +231,6 @@ static const struct ata_port_operations radisys_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index de3698cf3b8c..98784647c7e8 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -99,7 +99,6 @@ static struct ata_port_operations rz1000_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 5edf67b1f3bf..61edff4a5c6e 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -227,7 +227,6 @@ static struct ata_port_operations sc1200_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 63fe99a10cd1..95f04b81352f 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -838,38 +838,6 @@ static u8 scc_irq_on (struct ata_port *ap) return tmp; } -/** - * scc_irq_ack - Acknowledge a device interrupt. - * @ap: Port on which interrupts are enabled. - * - * Note: Original code is ata_irq_ack(). - */ - -static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq) -{ - unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; - u8 host_stat, post_stat, status; - - status = ata_busy_wait(ap, bits, 1000); - if (status & bits) - if (ata_msg_err(ap)) - printk(KERN_ERR "abnormal status 0x%X\n", status); - - /* get controller status; clear intr, err bits */ - host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS); - out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS, - host_stat | ATA_DMA_INTR | ATA_DMA_ERR); - - post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS); - - if (ata_msg_intr(ap)) - printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", - __FUNCTION__, - host_stat, post_stat, status); - - return status; -} - /** * scc_bmdma_freeze - Freeze BMDMA controller port * @ap: port to freeze @@ -1047,7 +1015,6 @@ static const struct ata_port_operations scc_pata_ops = { .irq_clear = scc_bmdma_irq_clear, .irq_on = scc_irq_on, - .irq_ack = scc_irq_ack, .port_start = scc_port_start, .port_stop = scc_port_stop, diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 0faf99c8f13e..c87cd67f4152 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -348,7 +348,6 @@ static struct ata_port_operations serverworks_osb4_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -384,7 +383,6 @@ static struct ata_port_operations serverworks_csb_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 45515a22d856..c5abf6616543 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -267,7 +267,6 @@ static struct ata_port_operations sil680_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index b72227676f00..72850667d371 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -559,7 +559,6 @@ static const struct ata_port_operations sis_133_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -593,7 +592,6 @@ static const struct ata_port_operations sis_133_for_sata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -627,7 +625,6 @@ static const struct ata_port_operations sis_133_early_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -661,7 +658,6 @@ static const struct ata_port_operations sis_100_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -695,7 +691,6 @@ static const struct ata_port_operations sis_66_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -729,7 +724,6 @@ static const struct ata_port_operations sis_old_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 375c3705dc43..1c50c191e4bc 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -254,7 +254,6 @@ static struct ata_port_operations sl82c105_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index bc4b6f6be963..2a55eed45ad8 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -227,7 +227,6 @@ static struct ata_port_operations triflex_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index b612808a319e..4ddcae8b8c96 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -375,7 +375,6 @@ static struct ata_port_operations via_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -411,7 +410,6 @@ static struct ata_port_operations via_port_ops_noirq = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index c37570330073..c1647da55543 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -160,7 +160,6 @@ static struct ata_port_operations winbond_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 304c19b9b0f2..7dd7361289c4 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -177,7 +177,6 @@ static const struct ata_port_operations adma_ata_ops = { .error_handler = adma_error_handler, .irq_clear = adma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = adma_port_start, .port_stop = adma_port_stop, .host_stop = adma_host_stop, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 95caba0f910e..d6a3e286c79d 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -569,7 +569,6 @@ static struct ata_port_operations inic_port_ops = { .irq_clear = inic_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .qc_prep = ata_qc_prep, .qc_issue = inic_qc_issue, diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 56784ce10544..393fc655f8c1 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -499,7 +499,6 @@ static const struct ata_port_operations mv5_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, @@ -530,7 +529,6 @@ static const struct ata_port_operations mv6_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, @@ -561,7 +559,6 @@ static const struct ata_port_operations mv_iie_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 884d9f05e6c6..88ecca6343ea 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -359,7 +359,6 @@ static const struct ata_port_operations nv_generic_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, @@ -385,7 +384,6 @@ static const struct ata_port_operations nv_nf2_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, @@ -411,7 +409,6 @@ static const struct ata_port_operations nv_ck804_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, @@ -439,7 +436,6 @@ static const struct ata_port_operations nv_adma_ops = { .data_xfer = ata_data_xfer, .irq_clear = nv_adma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = nv_adma_port_start, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index c7238ce83541..37d737b442b5 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -185,7 +185,6 @@ static const struct ata_port_operations pdc_sata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, @@ -212,7 +211,6 @@ static const struct ata_port_operations pdc_old_sata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, @@ -238,7 +236,6 @@ static const struct ata_port_operations pdc_pata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = pdc_common_port_start, }; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index ef1ad69c26ed..5a60ab72ecb6 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -159,7 +159,6 @@ static const struct ata_port_operations qs_ata_ops = { .eng_timeout = qs_eng_timeout, .irq_clear = qs_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = qs_scr_read, .scr_write = qs_scr_write, .port_start = qs_port_start, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 802d679dc994..1930e7cf1438 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -207,7 +207,6 @@ static const struct ata_port_operations sil_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = sil_scr_read, .scr_write = sil_scr_write, .port_start = ata_port_start, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e2cccc7f4358..961b3f201a38 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -398,8 +398,6 @@ static const struct ata_port_operations sil24_ops = { .qc_issue = sil24_qc_issue, .irq_clear = sil24_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 41c1d6e8f1fe..691017eddbb1 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -123,7 +123,6 @@ static const struct ata_port_operations sis_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = sis_scr_read, .scr_write = sis_scr_write, .port_start = ata_port_start, diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index d9678e7bc3a9..006a720da406 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -349,7 +349,6 @@ static const struct ata_port_operations k2_sata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = k2_sata_scr_read, .scr_write = k2_sata_scr_write, .port_start = ata_port_start, diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 12691f091933..d5cbd16629ad 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -267,7 +267,6 @@ static const struct ata_port_operations pdc_20621_ops = { .eng_timeout = pdc_eng_timeout, .irq_clear = pdc20621_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = pdc_port_start, }; diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index e6b8b45279af..d4514e2149bc 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -117,7 +117,6 @@ static const struct ata_port_operations uli_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = uli_scr_read, .scr_write = uli_scr_write, diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 690280660b81..4b25c3ef986f 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -146,7 +146,6 @@ static const struct ata_port_operations vt6420_sata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -180,7 +179,6 @@ static const struct ata_port_operations vt6421_pata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -211,7 +209,6 @@ static const struct ata_port_operations vt6421_sata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = svia_scr_read, .scr_write = svia_scr_write, diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 9586b8b51cea..55fb2e0b369a 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -336,7 +336,6 @@ static const struct ata_port_operations vsc_sata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = vsc_sata_scr_read, .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, diff --git a/include/linux/libata.h b/include/linux/libata.h index b89d191ceb2b..9295cd541ffc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -644,7 +644,6 @@ struct ata_port_operations { irq_handler_t irq_handler; void (*irq_clear) (struct ata_port *); u8 (*irq_on) (struct ata_port *); - u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq); int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val); int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val); @@ -852,9 +851,6 @@ extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, extern struct ata_device *ata_dev_pair(struct ata_device *adev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern u8 ata_irq_on(struct ata_port *ap); -extern u8 ata_dummy_irq_on(struct ata_port *ap); -extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq); -extern u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq); extern int ata_cable_40wire(struct ata_port *ap); extern int ata_cable_80wire(struct ata_port *ap); From e1ddb4b6a2c9b2c72991eb8640ef2f50691ac502 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 16 Aug 2007 02:33:36 -0400 Subject: [PATCH 2414/2804] [libata] add ACPI cable detect API Combined from two Alan Cox patches: 1) libata: ACPI checks for 80wire cable We can use the ACPI mode information with several drivers as a hint to cable type. If the ACPI mode set by the BIOS is faster than UDMA33 then we know the BIOS thinks there are 80wire cables. If it doesn't set such a mode or it has no ACPI method then we get no further information and can rely on existing approaches Introduce the function headers needed. Null it out for non ACPI boxes Signed-off-by: Alan Cox 2) libata: ACPI checks for 80wire cable Provide actual methods for checking if the ACPI support thinks the cable is 80wire, or doesn't know Signed-off-by: Alan Cox Combined into a single changeset and Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 6 ++++++ 2 files changed, 44 insertions(+) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 43af2e06d446..dc9842ec6f06 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -296,6 +296,44 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, return rc; } +/** + * ata_acpi_cbl_80wire - Check for 80 wire cable + * @ap: Port to check + * + * Return 1 if the ACPI mode data for this port indicates the BIOS selected + * an 80wire mode. + */ + +int ata_acpi_cbl_80wire(struct ata_port *ap) +{ + struct ata_acpi_gtm gtm; + int valid = 0; + + /* No _GTM data, no information */ + if (ata_acpi_gtm(ap, >m) < 0) + return 0; + + /* Split timing, DMA enabled */ + if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55) + valid |= 1; + if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55) + valid |= 2; + /* Shared timing, DMA enabled */ + if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55) + valid |= 1; + if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55) + valid |= 2; + + /* Drive check */ + if ((valid & 1) && ata_dev_enabled(&ap->link.device[0])) + return 1; + if ((valid & 2) && ata_dev_enabled(&ap->link.device[1])) + return 1; + return 0; +} + +EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); + /** * taskfile_load_raw - send taskfile registers to host controller * @dev: target ATA device diff --git a/include/linux/libata.h b/include/linux/libata.h index 9295cd541ffc..382898ef6545 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -885,6 +885,12 @@ enum { ATA_TIMING_CYCLE | ATA_TIMING_UDMA, }; +/* libata-acpi.c */ +#ifdef CONFIG_ATA_ACPI +extern int ata_acpi_cbl_80wire(struct ata_port *ap); +#else +static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } +#endif #ifdef CONFIG_PCI struct pci_bits { From e708eb9bc0515f36d77477877e74b6b9056b5879 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 26 Jul 2007 18:37:28 +0100 Subject: [PATCH 2415/2804] libata pata_amd: ACPI checks for 80wire cable We can make use of this on the pata_amd driver as many Nvidia devices don't have reliable cable detect. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_amd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 46f829c838b3..c95922f8cc5e 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -270,6 +270,9 @@ static int nv_cable_detect(struct ata_port *ap) pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma); if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400) cbl = ATA_CBL_PATA80; + /* And a triple check across suspend/resume with ACPI around */ + if (ata_acpi_cbl_80wire(ap)) + cbl = ATA_CBL_PATA80; return cbl; } From 7d73a363dea186a864f6295bbe842da8044d42cd Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 26 Jul 2007 18:38:06 +0100 Subject: [PATCH 2416/2804] libata pata_via: ACPI checks for 80wire cable Testing this on the VIA boards fixes several problems with otherwise undetectable SATA bridge chips Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_via.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 4ddcae8b8c96..f11b87e18aae 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -184,6 +184,9 @@ static int via_cable_detect(struct ata_port *ap) { two drives */ if (ata66 & (0x10100000 >> (16 * ap->port_no))) return ATA_CBL_PATA80; + /* Check with ACPI so we can spot BIOS reported SATA bridges */ + if (ata_acpi_cbl_80wire(ap)) + return ATA_CBL_PATA80; return ATA_CBL_PATA40; } From ac8869d56d95a8c74403e6f7a47d74fcfcc1b988 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 16 Aug 2007 03:17:03 -0400 Subject: [PATCH 2417/2804] [libata] Remove ->port_disable() hook It was always set to ata_port_disable(). Removed the hook, and replaced the very few ap->ops->port_disable() callsites with direct calls to ata_port_disable(). Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 ---- drivers/ata/ata_generic.c | 1 - drivers/ata/ata_piix.c | 4 ---- drivers/ata/libata-core.c | 4 +--- drivers/ata/pata_ali.c | 5 ----- drivers/ata/pata_amd.c | 6 ------ drivers/ata/pata_artop.c | 2 -- drivers/ata/pata_atiixp.c | 1 - drivers/ata/pata_cmd640.c | 1 - drivers/ata/pata_cmd64x.c | 3 --- drivers/ata/pata_cs5520.c | 1 - drivers/ata/pata_cs5530.c | 1 - drivers/ata/pata_cs5535.c | 1 - drivers/ata/pata_cypress.c | 1 - drivers/ata/pata_efar.c | 1 - drivers/ata/pata_hpt366.c | 1 - drivers/ata/pata_hpt37x.c | 4 ---- drivers/ata/pata_hpt3x2n.c | 1 - drivers/ata/pata_hpt3x3.c | 1 - drivers/ata/pata_icside.c | 2 -- drivers/ata/pata_isapnp.c | 1 - drivers/ata/pata_it8213.c | 1 - drivers/ata/pata_it821x.c | 2 -- drivers/ata/pata_ixp4xx_cf.c | 1 - drivers/ata/pata_jmicron.c | 2 -- drivers/ata/pata_legacy.c | 7 ------- drivers/ata/pata_marvell.c | 2 -- drivers/ata/pata_mpc52xx.c | 1 - drivers/ata/pata_mpiix.c | 1 - drivers/ata/pata_netcell.c | 2 -- drivers/ata/pata_ns87410.c | 1 - drivers/ata/pata_oldpiix.c | 1 - drivers/ata/pata_opti.c | 1 - drivers/ata/pata_optidma.c | 2 -- drivers/ata/pata_pcmcia.c | 1 - drivers/ata/pata_pdc2027x.c | 2 -- drivers/ata/pata_pdc202xx_old.c | 2 -- drivers/ata/pata_platform.c | 1 - drivers/ata/pata_qdi.c | 2 -- drivers/ata/pata_radisys.c | 1 - drivers/ata/pata_rz1000.c | 1 - drivers/ata/pata_sc1200.c | 1 - drivers/ata/pata_scc.c | 1 - drivers/ata/pata_serverworks.c | 2 -- drivers/ata/pata_sil680.c | 1 - drivers/ata/pata_sis.c | 6 ------ drivers/ata/pata_sl82c105.c | 1 - drivers/ata/pata_triflex.c | 1 - drivers/ata/pata_via.c | 2 -- drivers/ata/pata_winbond.c | 1 - drivers/ata/pdc_adma.c | 1 - drivers/ata/sata_inic162x.c | 1 - drivers/ata/sata_mv.c | 6 ------ drivers/ata/sata_nv.c | 4 ---- drivers/ata/sata_promise.c | 3 --- drivers/ata/sata_qstor.c | 1 - drivers/ata/sata_sil.c | 1 - drivers/ata/sata_sil24.c | 2 -- drivers/ata/sata_sis.c | 1 - drivers/ata/sata_svw.c | 1 - drivers/ata/sata_sx4.c | 1 - drivers/ata/sata_uli.c | 2 -- drivers/ata/sata_via.c | 6 ------ drivers/ata/sata_vsc.c | 1 - drivers/scsi/ipr.c | 5 ++--- drivers/scsi/libsas/sas_ata.c | 1 - include/linux/libata.h | 2 -- 67 files changed, 3 insertions(+), 132 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c888c966a020..0d80189d03f3 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -264,8 +264,6 @@ static struct scsi_host_template ahci_sht = { }; static const struct ata_port_operations ahci_ops = { - .port_disable = ata_port_disable, - .check_status = ahci_check_status, .check_altstatus = ahci_check_status, .dev_select = ata_noop_dev_select, @@ -296,8 +294,6 @@ static const struct ata_port_operations ahci_ops = { }; static const struct ata_port_operations ahci_vt8251_ops = { - .port_disable = ata_port_disable, - .check_status = ahci_check_status, .check_altstatus = ahci_check_status, .dev_select = ata_noop_dev_select, diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 6ec1bbc4fcc4..afe71a6e0dab 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -95,7 +95,6 @@ static struct scsi_host_template generic_sht = { static struct ata_port_operations generic_port_ops = { .set_mode = generic_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 68bc0ae671c5..45e3b60f26d0 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -290,7 +290,6 @@ static struct scsi_host_template piix_sht = { }; static const struct ata_port_operations piix_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -323,7 +322,6 @@ static const struct ata_port_operations piix_pata_ops = { }; static const struct ata_port_operations ich_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = ich_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -356,8 +354,6 @@ static const struct ata_port_operations ich_pata_ops = { }; static const struct ata_port_operations piix_sata_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 4f8b8d210cf4..43c329544c00 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2208,7 +2208,6 @@ int ata_bus_probe(struct ata_port *ap) /* no device present, disable port */ ata_port_disable(ap); - ap->ops->port_disable(ap); return -ENODEV; fail: @@ -3227,7 +3226,7 @@ void ata_bus_reset(struct ata_port *ap) err_out: ata_port_printk(ap, KERN_ERR, "disabling port\n"); - ap->ops->port_disable(ap); + ata_port_disable(ap); DPRINTK("EXIT\n"); } @@ -6986,7 +6985,6 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc) } const struct ata_port_operations ata_dummy_port_ops = { - .port_disable = ata_port_disable, .check_status = ata_dummy_check_status, .check_altstatus = ata_dummy_check_status, .dev_select = ata_noop_dev_select, diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 9436c4963929..7fc11ef0fd26 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -305,7 +305,6 @@ static struct scsi_host_template ali_sht = { */ static struct ata_port_operations ali_early_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -336,8 +335,6 @@ static struct ata_port_operations ali_early_port_ops = { * detect */ static struct ata_port_operations ali_20_port_ops = { - .port_disable = ata_port_disable, - .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ali_20_filter, @@ -376,7 +373,6 @@ static struct ata_port_operations ali_20_port_ops = { * Port operations for DMA capable ALi with cable detect */ static struct ata_port_operations ali_c2_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -414,7 +410,6 @@ static struct ata_port_operations ali_c2_port_ops = { * Port operations for DMA capable ALi with cable detect and LBA48 */ static struct ata_port_operations ali_c5_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index c95922f8cc5e..b1db7ff8edd1 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -332,7 +332,6 @@ static struct scsi_host_template amd_sht = { }; static struct ata_port_operations amd33_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd33_set_piomode, .set_dmamode = amd33_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -366,7 +365,6 @@ static struct ata_port_operations amd33_port_ops = { }; static struct ata_port_operations amd66_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd66_set_piomode, .set_dmamode = amd66_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -400,7 +398,6 @@ static struct ata_port_operations amd66_port_ops = { }; static struct ata_port_operations amd100_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd100_set_piomode, .set_dmamode = amd100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -434,7 +431,6 @@ static struct ata_port_operations amd100_port_ops = { }; static struct ata_port_operations amd133_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd133_set_piomode, .set_dmamode = amd133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -468,7 +464,6 @@ static struct ata_port_operations amd133_port_ops = { }; static struct ata_port_operations nv100_port_ops = { - .port_disable = ata_port_disable, .set_piomode = nv100_set_piomode, .set_dmamode = nv100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -502,7 +497,6 @@ static struct ata_port_operations nv100_port_ops = { }; static struct ata_port_operations nv133_port_ops = { - .port_disable = ata_port_disable, .set_piomode = nv133_set_piomode, .set_dmamode = nv133_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 8c864353596e..1827843cda46 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -332,7 +332,6 @@ static struct scsi_host_template artop_sht = { }; static const struct ata_port_operations artop6210_ops = { - .port_disable = ata_port_disable, .set_piomode = artop6210_set_piomode, .set_dmamode = artop6210_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -366,7 +365,6 @@ static const struct ata_port_operations artop6210_ops = { }; static const struct ata_port_operations artop6260_ops = { - .port_disable = ata_port_disable, .set_piomode = artop6260_set_piomode, .set_dmamode = artop6260_set_dmamode, diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index f2bfdeb44023..0077ee783d1e 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -233,7 +233,6 @@ static struct scsi_host_template atiixp_sht = { }; static struct ata_port_operations atiixp_port_ops = { - .port_disable = ata_port_disable, .set_piomode = atiixp_set_piomode, .set_dmamode = atiixp_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index a292ed97246d..f09d4fa275ce 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -184,7 +184,6 @@ static struct scsi_host_template cmd640_sht = { }; static struct ata_port_operations cmd640_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd640_set_piomode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index d308c4644647..9e412c26b2a3 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -284,7 +284,6 @@ static struct scsi_host_template cmd64x_sht = { }; static struct ata_port_operations cmd64x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -318,7 +317,6 @@ static struct ata_port_operations cmd64x_port_ops = { }; static struct ata_port_operations cmd646r1_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -352,7 +350,6 @@ static struct ata_port_operations cmd646r1_port_ops = { }; static struct ata_port_operations cmd648_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 300dcff949e2..fe37e3e80f27 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -158,7 +158,6 @@ static struct scsi_host_template cs5520_sht = { }; static struct ata_port_operations cs5520_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5520_set_piomode, .set_dmamode = cs5520_set_dmamode, diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 2b770072f392..adeb3acf84cf 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -179,7 +179,6 @@ static struct scsi_host_template cs5530_sht = { }; static struct ata_port_operations cs5530_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5530_set_piomode, .set_dmamode = cs5530_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 94b1a9caf3cb..2c73807da626 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -176,7 +176,6 @@ static struct scsi_host_template cs5535_sht = { }; static struct ata_port_operations cs5535_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5535_set_piomode, .set_dmamode = cs5535_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 8c439a9bb5dd..cae44250d814 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = { }; static struct ata_port_operations cy82c693_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cy82c693_set_piomode, .set_dmamode = cy82c693_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 4d646ffb257b..cc418e34e63b 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -251,7 +251,6 @@ static struct scsi_host_template efar_sht = { }; static const struct ata_port_operations efar_ops = { - .port_disable = ata_port_disable, .set_piomode = efar_set_piomode, .set_dmamode = efar_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 508d1cab52d1..16cc143460e4 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -312,7 +312,6 @@ static struct scsi_host_template hpt36x_sht = { */ static struct ata_port_operations hpt366_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt366_set_piomode, .set_dmamode = hpt366_set_dmamode, .mode_filter = hpt366_filter, diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 896e6e31c67f..65c0cb21f6a0 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -644,7 +644,6 @@ static struct scsi_host_template hpt37x_sht = { */ static struct ata_port_operations hpt370_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt370_set_piomode, .set_dmamode = hpt370_set_dmamode, .mode_filter = hpt370_filter, @@ -682,7 +681,6 @@ static struct ata_port_operations hpt370_port_ops = { */ static struct ata_port_operations hpt370a_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt370_set_piomode, .set_dmamode = hpt370_set_dmamode, .mode_filter = hpt370a_filter, @@ -721,7 +719,6 @@ static struct ata_port_operations hpt370a_port_ops = { */ static struct ata_port_operations hpt372_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt372_set_piomode, .set_dmamode = hpt372_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -760,7 +757,6 @@ static struct ata_port_operations hpt372_port_ops = { */ static struct ata_port_operations hpt374_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt372_set_piomode, .set_dmamode = hpt372_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 2b7f099ac785..5559da7f9db3 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -361,7 +361,6 @@ static struct scsi_host_template hpt3x2n_sht = { */ static struct ata_port_operations hpt3x2n_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt3x2n_set_piomode, .set_dmamode = hpt3x2n_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index a2f81f40d7ac..752394b72652 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -120,7 +120,6 @@ static struct scsi_host_template hpt3x3_sht = { }; static struct ata_port_operations hpt3x3_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt3x3_set_piomode, #if defined(CONFIG_PATA_HPT3X3_DMA) .set_dmamode = hpt3x3_set_dmamode, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index ffcccfc0b9d4..4a69328a4c43 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -358,8 +358,6 @@ static void pata_icside_error_handler(struct ata_port *ap) } static struct ata_port_operations pata_icside_port_ops = { - .port_disable = ata_port_disable, - .set_dmamode = pata_icside_set_dmamode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index b8d6d5c43537..1def8c05f345 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -38,7 +38,6 @@ static struct scsi_host_template isapnp_sht = { }; static struct ata_port_operations isapnp_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 8aae9d7171c1..cc989ef30420 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -261,7 +261,6 @@ static struct scsi_host_template it8213_sht = { }; static const struct ata_port_operations it8213_ops = { - .port_disable = ata_port_disable, .set_piomode = it8213_set_piomode, .set_dmamode = it8213_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 0179b29c5156..4188898a66a0 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -620,7 +620,6 @@ static struct scsi_host_template it821x_sht = { static struct ata_port_operations it821x_smart_port_ops = { .set_mode = it821x_smart_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .mode_filter = ata_pci_default_filter, @@ -655,7 +654,6 @@ static struct ata_port_operations it821x_smart_port_ops = { }; static struct ata_port_operations it821x_passthru_port_ops = { - .port_disable = ata_port_disable, .set_piomode = it821x_passthru_set_piomode, .set_dmamode = it821x_passthru_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index ce1f9b17ad32..7b0d2fc57484 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -107,7 +107,6 @@ static struct ata_port_operations ixp4xx_port_ops = { .set_mode = ixp4xx_set_mode, .mode_filter = ata_pci_default_filter, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 26f84063859d..6d5a81869df6 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -141,8 +141,6 @@ static struct scsi_host_template jmicron_sht = { }; static const struct ata_port_operations jmicron_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 6529d34f0370..6cae26f4d272 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -150,7 +150,6 @@ static struct scsi_host_template legacy_sht = { */ static struct ata_port_operations simple_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -178,7 +177,6 @@ static struct ata_port_operations simple_port_ops = { static struct ata_port_operations legacy_port_ops = { .set_mode = legacy_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -293,7 +291,6 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig static struct ata_port_operations pdc20230_port_ops = { .set_piomode = pdc20230_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -348,7 +345,6 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) static struct ata_port_operations ht6560a_port_ops = { .set_piomode = ht6560a_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -414,7 +410,6 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) static struct ata_port_operations ht6560b_port_ops = { .set_piomode = ht6560b_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -535,7 +530,6 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev static struct ata_port_operations opti82c611a_port_ops = { .set_piomode = opti82c611a_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -668,7 +662,6 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc) static struct ata_port_operations opti82c46x_port_ops = { .set_piomode = opti82c46x_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 021d9d9218bd..99d0844c8cb8 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -111,8 +111,6 @@ static struct scsi_host_template marvell_sht = { }; static const struct ata_port_operations marvell_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 6e3fac2fedc4..a56694b2833e 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -283,7 +283,6 @@ static struct scsi_host_template mpc52xx_ata_sht = { }; static struct ata_port_operations mpc52xx_ata_port_ops = { - .port_disable = ata_port_disable, .set_piomode = mpc52xx_ata_set_piomode, .dev_select = mpc52xx_ata_dev_select, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 8a82fcd4fa31..b50910938e6f 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -169,7 +169,6 @@ static struct scsi_host_template mpiix_sht = { }; static struct ata_port_operations mpiix_port_ops = { - .port_disable = ata_port_disable, .set_piomode = mpiix_set_piomode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 2d64c58482fa..b2c3d0767547 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -40,8 +40,6 @@ static struct scsi_host_template netcell_sht = { }; static const struct ata_port_operations netcell_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 00a763c67f99..4b0ddf6ba3ba 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -162,7 +162,6 @@ static struct scsi_host_template ns87410_sht = { }; static struct ata_port_operations ns87410_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ns87410_set_piomode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 851dae960018..ada719ad45a4 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -238,7 +238,6 @@ static struct scsi_host_template oldpiix_sht = { }; static const struct ata_port_operations oldpiix_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = oldpiix_set_piomode, .set_dmamode = oldpiix_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 0ab300cda9b7..2a4bfbfbe75a 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -183,7 +183,6 @@ static struct scsi_host_template opti_sht = { }; static struct ata_port_operations opti_port_ops = { - .port_disable = ata_port_disable, .set_piomode = opti_set_piomode, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 51c49283fb39..848ae16f2390 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -368,7 +368,6 @@ static struct scsi_host_template optidma_sht = { }; static struct ata_port_operations optidma_port_ops = { - .port_disable = ata_port_disable, .set_piomode = optidma_set_pio_mode, .set_dmamode = optidma_set_dma_mode, @@ -403,7 +402,6 @@ static struct ata_port_operations optidma_port_ops = { }; static struct ata_port_operations optiplus_port_ops = { - .port_disable = ata_port_disable, .set_piomode = optiplus_set_pio_mode, .set_dmamode = optiplus_set_dma_mode, diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index f2167729c3df..5baf531f652e 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -107,7 +107,6 @@ static struct scsi_host_template pcmcia_sht = { static struct ata_port_operations pcmcia_port_ops = { .set_mode = pcmcia_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 7c6df320c833..5fba36f04ca9 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -147,7 +147,6 @@ static struct scsi_host_template pdc2027x_sht = { }; static struct ata_port_operations pdc2027x_pata100_ops = { - .port_disable = ata_port_disable, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, @@ -178,7 +177,6 @@ static struct ata_port_operations pdc2027x_pata100_ops = { }; static struct ata_port_operations pdc2027x_pata133_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc2027x_set_piomode, .set_dmamode = pdc2027x_set_dmamode, .set_mode = pdc2027x_set_mode, diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index b03b33872457..9b7077d51489 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -247,7 +247,6 @@ static struct scsi_host_template pdc202xx_sht = { }; static struct ata_port_operations pdc2024x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc202xx_set_piomode, .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -280,7 +279,6 @@ static struct ata_port_operations pdc2024x_port_ops = { }; static struct ata_port_operations pdc2026x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc202xx_set_piomode, .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index a616616706da..b04ce5f98410 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -69,7 +69,6 @@ static struct scsi_host_template pata_platform_sht = { static struct ata_port_operations pata_platform_port_ops = { .set_mode = pata_platform_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index ade5a4421663..da9ccd23ffc8 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -170,7 +170,6 @@ static struct scsi_host_template qdi_sht = { }; static struct ata_port_operations qdi6500_port_ops = { - .port_disable = ata_port_disable, .set_piomode = qdi6500_set_piomode, .tf_load = ata_tf_load, @@ -197,7 +196,6 @@ static struct ata_port_operations qdi6500_port_ops = { }; static struct ata_port_operations qdi6580_port_ops = { - .port_disable = ata_port_disable, .set_piomode = qdi6580_set_piomode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 66b9a341931b..ece2190971c3 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -203,7 +203,6 @@ static struct scsi_host_template radisys_sht = { }; static const struct ata_port_operations radisys_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = radisys_set_piomode, .set_dmamode = radisys_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 98784647c7e8..5f1a4e180dc4 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -73,7 +73,6 @@ static struct scsi_host_template rz1000_sht = { static struct ata_port_operations rz1000_port_ops = { .set_mode = rz1000_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 61edff4a5c6e..6c13754c75af 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -197,7 +197,6 @@ static struct scsi_host_template sc1200_sht = { }; static struct ata_port_operations sc1200_port_ops = { - .port_disable = ata_port_disable, .set_piomode = sc1200_set_piomode, .set_dmamode = sc1200_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 95f04b81352f..e138343b5d4e 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -988,7 +988,6 @@ static struct scsi_host_template scc_sht = { }; static const struct ata_port_operations scc_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = scc_set_piomode, .set_dmamode = scc_set_dmamode, .mode_filter = scc_mode_filter, diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index c87cd67f4152..7c08f25c9544 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -318,7 +318,6 @@ static struct scsi_host_template serverworks_sht = { }; static struct ata_port_operations serverworks_osb4_port_ops = { - .port_disable = ata_port_disable, .set_piomode = serverworks_set_piomode, .set_dmamode = serverworks_set_dmamode, .mode_filter = serverworks_osb4_filter, @@ -353,7 +352,6 @@ static struct ata_port_operations serverworks_osb4_port_ops = { }; static struct ata_port_operations serverworks_csb_port_ops = { - .port_disable = ata_port_disable, .set_piomode = serverworks_set_piomode, .set_dmamode = serverworks_set_dmamode, .mode_filter = serverworks_csb_filter, diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index c5abf6616543..71f206d7b5c1 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -238,7 +238,6 @@ static struct scsi_host_template sil680_sht = { }; static struct ata_port_operations sil680_port_ops = { - .port_disable = ata_port_disable, .set_piomode = sil680_set_piomode, .set_dmamode = sil680_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 72850667d371..4ccf09dac8c5 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -531,7 +531,6 @@ static struct scsi_host_template sis_sht = { }; static const struct ata_port_operations sis_133_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_133_set_piomode, .set_dmamode = sis_133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -564,7 +563,6 @@ static const struct ata_port_operations sis_133_ops = { }; static const struct ata_port_operations sis_133_for_sata_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_133_set_piomode, .set_dmamode = sis_133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -597,7 +595,6 @@ static const struct ata_port_operations sis_133_for_sata_ops = { }; static const struct ata_port_operations sis_133_early_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_100_set_piomode, .set_dmamode = sis_133_early_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -630,7 +627,6 @@ static const struct ata_port_operations sis_133_early_ops = { }; static const struct ata_port_operations sis_100_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_100_set_piomode, .set_dmamode = sis_100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -663,7 +659,6 @@ static const struct ata_port_operations sis_100_ops = { }; static const struct ata_port_operations sis_66_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_old_set_piomode, .set_dmamode = sis_66_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -696,7 +691,6 @@ static const struct ata_port_operations sis_66_ops = { }; static const struct ata_port_operations sis_old_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_old_set_piomode, .set_dmamode = sis_old_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 1c50c191e4bc..5bd78437e94b 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -225,7 +225,6 @@ static struct scsi_host_template sl82c105_sht = { }; static struct ata_port_operations sl82c105_port_ops = { - .port_disable = ata_port_disable, .set_piomode = sl82c105_set_piomode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 2a55eed45ad8..dc20b179e3b6 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -198,7 +198,6 @@ static struct scsi_host_template triflex_sht = { }; static struct ata_port_operations triflex_port_ops = { - .port_disable = ata_port_disable, .set_piomode = triflex_set_piomode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index f11b87e18aae..e1f20e73a61e 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -348,7 +348,6 @@ static struct scsi_host_template via_sht = { }; static struct ata_port_operations via_port_ops = { - .port_disable = ata_port_disable, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -383,7 +382,6 @@ static struct ata_port_operations via_port_ops = { }; static struct ata_port_operations via_port_ops_noirq = { - .port_disable = ata_port_disable, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index c1647da55543..d7555f775d5d 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -138,7 +138,6 @@ static struct scsi_host_template winbond_sht = { }; static struct ata_port_operations winbond_port_ops = { - .port_disable = ata_port_disable, .set_piomode = winbond_set_piomode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 7dd7361289c4..42fd15aaba0b 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -162,7 +162,6 @@ static struct scsi_host_template adma_ata_sht = { }; static const struct ata_port_operations adma_ata_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index d6a3e286c79d..f0ea0e166c11 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -552,7 +552,6 @@ static int inic_port_start(struct ata_port *ap) } static struct ata_port_operations inic_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 393fc655f8c1..68c3f22890d2 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -483,8 +483,6 @@ static struct scsi_host_template mv6_sht = { }; static const struct ata_port_operations mv5_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -513,8 +511,6 @@ static const struct ata_port_operations mv5_ops = { }; static const struct ata_port_operations mv6_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -543,8 +539,6 @@ static const struct ata_port_operations mv6_ops = { }; static const struct ata_port_operations mv_iie_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 88ecca6343ea..b860f99fc288 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -340,7 +340,6 @@ static struct scsi_host_template nv_adma_sht = { }; static const struct ata_port_operations nv_generic_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -365,7 +364,6 @@ static const struct ata_port_operations nv_generic_ops = { }; static const struct ata_port_operations nv_nf2_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -390,7 +388,6 @@ static const struct ata_port_operations nv_nf2_ops = { }; static const struct ata_port_operations nv_ck804_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -416,7 +413,6 @@ static const struct ata_port_operations nv_ck804_ops = { }; static const struct ata_port_operations nv_adma_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = nv_adma_tf_read, .check_atapi_dma = nv_adma_check_atapi_dma, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 37d737b442b5..983bff5c4def 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -167,7 +167,6 @@ static struct scsi_host_template pdc_ata_sht = { }; static const struct ata_port_operations pdc_sata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -193,7 +192,6 @@ static const struct ata_port_operations pdc_sata_ops = { /* First-generation chips need a more restrictive ->check_atapi_dma op */ static const struct ata_port_operations pdc_old_sata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -218,7 +216,6 @@ static const struct ata_port_operations pdc_old_sata_ops = { }; static const struct ata_port_operations pdc_pata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 5a60ab72ecb6..10bf52ca1e19 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -145,7 +145,6 @@ static struct scsi_host_template qs_ata_sht = { }; static const struct ata_port_operations qs_ata_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 1930e7cf1438..df0ac77fcdd4 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -186,7 +186,6 @@ static struct scsi_host_template sil_sht = { }; static const struct ata_port_operations sil_ops = { - .port_disable = ata_port_disable, .dev_config = sil_dev_config, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 961b3f201a38..e0cd31aa8002 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -384,8 +384,6 @@ static struct scsi_host_template sil24_sht = { }; static const struct ata_port_operations sil24_ops = { - .port_disable = ata_port_disable, - .dev_config = sil24_dev_config, .check_status = sil24_check_status, diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 691017eddbb1..8d98a9fb0a42 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -104,7 +104,6 @@ static struct scsi_host_template sis_sht = { }; static const struct ata_port_operations sis_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 006a720da406..822cabfec951 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -329,7 +329,6 @@ static struct scsi_host_template k2_sata_sht = { static const struct ata_port_operations k2_sata_ops = { - .port_disable = ata_port_disable, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index d5cbd16629ad..b425061dbe8c 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -254,7 +254,6 @@ static struct scsi_host_template pdc_sata_sht = { }; static const struct ata_port_operations pdc_20621_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index d4514e2149bc..6c53a790805f 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -94,8 +94,6 @@ static struct scsi_host_template uli_sht = { }; static const struct ata_port_operations uli_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 4b25c3ef986f..25162ec99384 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -122,8 +122,6 @@ static struct scsi_host_template svia_sht = { }; static const struct ata_port_operations vt6420_sata_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -151,8 +149,6 @@ static const struct ata_port_operations vt6420_sata_ops = { }; static const struct ata_port_operations vt6421_pata_ops = { - .port_disable = ata_port_disable, - .set_piomode = vt6421_set_pio_mode, .set_dmamode = vt6421_set_dma_mode, @@ -184,8 +180,6 @@ static const struct ata_port_operations vt6421_pata_ops = { }; static const struct ata_port_operations vt6421_sata_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 55fb2e0b369a..b1777c3f6d5c 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -317,7 +317,6 @@ static struct scsi_host_template vsc_sata_sht = { static const struct ata_port_operations vsc_sata_ops = { - .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, .exec_command = ata_exec_command, diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 9350fbf39f77..b41dfb539021 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4981,7 +4981,7 @@ static void ipr_ata_phy_reset(struct ata_port *ap) rc = ipr_device_reset(ioa_cfg, res); if (rc) { - ap->ops->port_disable(ap); + ata_port_disable(ap); goto out_unlock; } @@ -4996,7 +4996,7 @@ static void ipr_ata_phy_reset(struct ata_port *ap) break; default: ap->link.device[0].class = ATA_DEV_UNKNOWN; - ap->ops->port_disable(ap); + ata_port_disable(ap); break; }; @@ -5262,7 +5262,6 @@ static u8 ipr_ata_check_altstatus(struct ata_port *ap) } static struct ata_port_operations ipr_sata_ops = { - .port_disable = ata_port_disable, .check_status = ipr_ata_check_status, .check_altstatus = ipr_ata_check_altstatus, .dev_select = ata_noop_dev_select, diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 1d6503d85f02..0829b55c64d2 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -350,7 +350,6 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, } static struct ata_port_operations sas_sata_ops = { - .port_disable = ata_port_disable, .check_status = sas_ata_check_status, .check_altstatus = sas_ata_check_status, .dev_select = ata_noop_dev_select, diff --git a/include/linux/libata.h b/include/linux/libata.h index 382898ef6545..e7d163edb4c0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -600,8 +600,6 @@ struct ata_port { }; struct ata_port_operations { - void (*port_disable) (struct ata_port *); - void (*dev_config) (struct ata_device *); void (*set_piomode) (struct ata_port *, struct ata_device *); From 81ad1837b590775336f68eafcae8dab13a975b3a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 22:55:41 +0100 Subject: [PATCH 2418/2804] libata: Switch most of the remaining SFF drivers to ata_sff_port_start This avoids allocating DMA buffers if not needed but at the moment is mostly just a neatness item. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 2 +- drivers/ata/pata_ali.c | 8 ++++---- drivers/ata/pata_amd.c | 12 ++++++------ drivers/ata/pata_artop.c | 4 ++-- drivers/ata/pata_atiixp.c | 2 +- drivers/ata/pata_cmd640.c | 2 +- drivers/ata/pata_cs5520.c | 2 +- drivers/ata/pata_cs5530.c | 2 +- drivers/ata/pata_cs5535.c | 2 +- drivers/ata/pata_cypress.c | 2 +- drivers/ata/pata_efar.c | 2 +- drivers/ata/pata_hpt366.c | 2 +- drivers/ata/pata_hpt37x.c | 8 ++++---- drivers/ata/pata_hpt3x2n.c | 2 +- drivers/ata/pata_hpt3x3.c | 2 +- drivers/ata/pata_isapnp.c | 2 +- drivers/ata/pata_it8213.c | 2 +- drivers/ata/pata_it821x.c | 2 +- drivers/ata/pata_marvell.c | 2 +- drivers/ata/pata_mpiix.c | 2 +- drivers/ata/pata_netcell.c | 2 +- drivers/ata/pata_ns87410.c | 2 +- drivers/ata/pata_oldpiix.c | 2 +- drivers/ata/pata_opti.c | 2 +- drivers/ata/pata_optidma.c | 4 ++-- drivers/ata/pata_pdc2027x.c | 4 ++-- drivers/ata/pata_pdc202xx_old.c | 4 ++-- drivers/ata/pata_qdi.c | 4 ++-- drivers/ata/pata_radisys.c | 2 +- drivers/ata/pata_rz1000.c | 2 +- drivers/ata/pata_sc1200.c | 2 +- drivers/ata/pata_serverworks.c | 4 ++-- drivers/ata/pata_sil680.c | 2 +- drivers/ata/pata_sis.c | 12 ++++++------ drivers/ata/pata_sl82c105.c | 2 +- drivers/ata/pata_triflex.c | 2 +- drivers/ata/pata_via.c | 4 ++-- drivers/ata/pata_winbond.c | 2 +- 38 files changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index afe71a6e0dab..90329982bef7 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -121,7 +121,7 @@ static struct ata_port_operations generic_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int all_generic_ide; /* Set to claim all devices */ diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 7fc11ef0fd26..364534e7aff4 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -327,7 +327,7 @@ static struct ata_port_operations ali_early_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -366,7 +366,7 @@ static struct ata_port_operations ali_20_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -403,7 +403,7 @@ static struct ata_port_operations ali_c2_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -439,7 +439,7 @@ static struct ata_port_operations ali_c5_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index b1db7ff8edd1..c5779ad4abca 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -361,7 +361,7 @@ static struct ata_port_operations amd33_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd66_port_ops = { @@ -394,7 +394,7 @@ static struct ata_port_operations amd66_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd100_port_ops = { @@ -427,7 +427,7 @@ static struct ata_port_operations amd100_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd133_port_ops = { @@ -460,7 +460,7 @@ static struct ata_port_operations amd133_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations nv100_port_ops = { @@ -493,7 +493,7 @@ static struct ata_port_operations nv100_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations nv133_port_ops = { @@ -526,7 +526,7 @@ static struct ata_port_operations nv133_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 1827843cda46..d4218310327b 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -361,7 +361,7 @@ static const struct ata_port_operations artop6210_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations artop6260_ops = { @@ -392,7 +392,7 @@ static const struct ata_port_operations artop6260_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 0077ee783d1e..95ed3071a0a0 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -262,7 +262,7 @@ static struct ata_port_operations atiixp_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index f09d4fa275ce..43d198f90968 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -153,7 +153,7 @@ static int cmd640_port_start(struct ata_port *ap) struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct cmd640_reg *timing; - int ret = ata_port_start(ap); + int ret = ata_sff_port_start(ap); if (ret < 0) return ret; diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index fe37e3e80f27..1ae6b6bd8564 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -184,7 +184,7 @@ static struct ata_port_operations cs5520_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index adeb3acf84cf..57e827e4109e 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -209,7 +209,7 @@ static struct ata_port_operations cs5530_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct dmi_system_id palmax_dmi_table[] = { diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 2c73807da626..3578593a882b 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -206,7 +206,7 @@ static struct ata_port_operations cs5535_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index cae44250d814..fc5f9c4e5d87 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -158,7 +158,7 @@ static struct ata_port_operations cy82c693_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index cc418e34e63b..043dcd35106c 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -279,7 +279,7 @@ static const struct ata_port_operations efar_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 16cc143460e4..0713872cf65c 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -342,7 +342,7 @@ static struct ata_port_operations hpt366_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 65c0cb21f6a0..e61cb1fd57b2 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -673,7 +673,7 @@ static struct ata_port_operations hpt370_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -710,7 +710,7 @@ static struct ata_port_operations hpt370a_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -748,7 +748,7 @@ static struct ata_port_operations hpt372_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -786,7 +786,7 @@ static struct ata_port_operations hpt374_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 5559da7f9db3..9f1c084f846f 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -391,7 +391,7 @@ static struct ata_port_operations hpt3x2n_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 752394b72652..188d2176ec33 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -153,7 +153,7 @@ static struct ata_port_operations hpt3x3_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 1def8c05f345..8ac1e8beabaf 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -58,7 +58,7 @@ static struct ata_port_operations isapnp_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index cc989ef30420..1eda821e5e39 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -289,7 +289,7 @@ static const struct ata_port_operations it8213_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 4188898a66a0..988ef736b936 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -563,7 +563,7 @@ static int it821x_port_start(struct ata_port *ap) struct it821x_dev *itdev; u8 conf; - int ret = ata_port_start(ap); + int ret = ata_sff_port_start(ap); if (ret < 0) return ret; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 99d0844c8cb8..9afc8a32b226 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -139,7 +139,7 @@ static const struct ata_port_operations marvell_ops = { .irq_on = ata_irq_on, /* Generic PATA PCI ATA helpers */ - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index b50910938e6f..cb78b7bfe143 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -190,7 +190,7 @@ static struct ata_port_operations mpiix_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index b2c3d0767547..25c922abd554 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -68,7 +68,7 @@ static const struct ata_port_operations netcell_ops = { .irq_on = ata_irq_on, /* Generic PATA PCI ATA helpers */ - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 4b0ddf6ba3ba..6e8e55745b7b 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -185,7 +185,7 @@ static struct ata_port_operations ns87410_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index ada719ad45a4..3cd5eb2b6c91 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -266,7 +266,7 @@ static const struct ata_port_operations oldpiix_pata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 2a4bfbfbe75a..8f79447b6151 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -210,7 +210,7 @@ static struct ata_port_operations opti_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 848ae16f2390..6b07b5b48532 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -398,7 +398,7 @@ static struct ata_port_operations optidma_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations optiplus_port_ops = { @@ -432,7 +432,7 @@ static struct ata_port_operations optiplus_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 5fba36f04ca9..40b070ea85a1 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -173,7 +173,7 @@ static struct ata_port_operations pdc2027x_pata100_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations pdc2027x_pata133_ops = { @@ -206,7 +206,7 @@ static struct ata_port_operations pdc2027x_pata133_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_info pdc2027x_port_info[] = { diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 9b7077d51489..fd4350029bc4 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -275,7 +275,7 @@ static struct ata_port_operations pdc2024x_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations pdc2026x_port_ops = { @@ -308,7 +308,7 @@ static struct ata_port_operations pdc2026x_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index da9ccd23ffc8..032fa67acc8b 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -192,7 +192,7 @@ static struct ata_port_operations qdi6500_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations qdi6580_port_ops = { @@ -218,7 +218,7 @@ static struct ata_port_operations qdi6580_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index ece2190971c3..d5b76497f4a2 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -231,7 +231,7 @@ static const struct ata_port_operations radisys_pata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 5f1a4e180dc4..ba8a31c55edb 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -99,7 +99,7 @@ static struct ata_port_operations rz1000_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int rz1000_fifo_disable(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 6c13754c75af..21ebc485ca4b 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -227,7 +227,7 @@ static struct ata_port_operations sc1200_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 7c08f25c9544..df68806df4be 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -348,7 +348,7 @@ static struct ata_port_operations serverworks_osb4_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations serverworks_csb_port_ops = { @@ -382,7 +382,7 @@ static struct ata_port_operations serverworks_csb_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int serverworks_fixup_osb4(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 71f206d7b5c1..2eb75cd74a96 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -267,7 +267,7 @@ static struct ata_port_operations sil680_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 4ccf09dac8c5..3b5be77e861c 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -559,7 +559,7 @@ static const struct ata_port_operations sis_133_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_133_for_sata_ops = { @@ -591,7 +591,7 @@ static const struct ata_port_operations sis_133_for_sata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_133_early_ops = { @@ -623,7 +623,7 @@ static const struct ata_port_operations sis_133_early_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_100_ops = { @@ -655,7 +655,7 @@ static const struct ata_port_operations sis_100_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_66_ops = { @@ -687,7 +687,7 @@ static const struct ata_port_operations sis_66_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_old_ops = { @@ -719,7 +719,7 @@ static const struct ata_port_operations sis_old_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_info sis_info = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 5bd78437e94b..1388cef52c07 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -254,7 +254,7 @@ static struct ata_port_operations sl82c105_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index dc20b179e3b6..403eafcffe12 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -227,7 +227,7 @@ static struct ata_port_operations triflex_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index e1f20e73a61e..5d41b6612d7f 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -378,7 +378,7 @@ static struct ata_port_operations via_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations via_port_ops_noirq = { @@ -412,7 +412,7 @@ static struct ata_port_operations via_port_ops_noirq = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index d7555f775d5d..553658bacce0 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -160,7 +160,7 @@ static struct ata_port_operations winbond_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** From 4743d0854faa5624148ac6cf3fe9692e977eefa1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:12:50 +0100 Subject: [PATCH 2419/2804] libata-portmap: Remove unused definitions With the PCI layer properly handling legacy IDE and the kernel now using it these can go Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- include/asm-generic/libata-portmap.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/asm-generic/libata-portmap.h b/include/asm-generic/libata-portmap.h index 62fb3618293d..cf14f2ff40b6 100644 --- a/include/asm-generic/libata-portmap.h +++ b/include/asm-generic/libata-portmap.h @@ -1,12 +1,7 @@ #ifndef __ASM_GENERIC_LIBATA_PORTMAP_H #define __ASM_GENERIC_LIBATA_PORTMAP_H -#define ATA_PRIMARY_CMD 0x1F0 -#define ATA_PRIMARY_CTL 0x3F6 #define ATA_PRIMARY_IRQ(dev) 14 - -#define ATA_SECONDARY_CMD 0x170 -#define ATA_SECONDARY_CTL 0x376 #define ATA_SECONDARY_IRQ(dev) 15 #endif From 614fe29bd91f99cc1c1fbf3274fa918691044f47 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:22:45 +0100 Subject: [PATCH 2420/2804] libata: Spot bridge chips If we have a PATA cable with a SATA drive on it then we've found a bridge and we can flip the cable type. This fixes some cable detect problems with SATA bridges on chipsets and misdetected cable types. In theory cable detection and mode limiting is needed if you put a SATA/PATA bridge on a 40 wire cable, but I see no way to deal with that other than to point out its not a good idea anyway. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 43c329544c00..b81265d1e469 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2183,6 +2183,17 @@ int ata_bus_probe(struct ata_port *ap) if (ap->ops->cable_detect) ap->cbl = ap->ops->cable_detect(ap); + /* We may have SATA bridge glue hiding here irrespective of the + reported cable types and sensed types */ + ata_link_for_each_dev(dev, &ap->link) { + if (!ata_dev_enabled(dev)) + continue; + /* SATA drives indicate we have a bridge. We don't know which + end of the link the bridge is which is a problem */ + if (ata_id_is_sata(dev->id)) + ap->cbl = ATA_CBL_SATA; + } + /* After the identify sequence we can now set up the devices. We do this in the normal order so that the user doesn't get confused */ From c7293870a93a99e9ce0f4d98f3a271539c7c6ad6 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:31:43 +0100 Subject: [PATCH 2421/2804] libata: Strict checking for identify reporting The ATA specifications require checks on certain flags before assuming the validity of other data. Go through the methods and correct those needing extra checks. Also note limits on ata_id_major_version with respect to ATA-1 and ATA-2. Correct the 32bit PIO check. Wants to sit in -mm for a bit in case of a screwup on my part that I didn't hit on the test drives and also in case someone, somewhere has a drive that gets it wrong. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- include/linux/ata.h | 96 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/include/linux/ata.h b/include/linux/ata.h index fba8e1459832..a749f006387f 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -347,22 +347,12 @@ struct ata_taskfile { }; #define ata_id_is_ata(id) (((id)[0] & (1 << 15)) == 0) -#define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6)) -#define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5)) -#define ata_id_hpa_enabled(id) ((id)[85] & (1 << 10)) -#define ata_id_has_fua(id) ((id)[84] & (1 << 6)) -#define ata_id_has_flush(id) ((id)[83] & (1 << 12)) -#define ata_id_has_flush_ext(id) ((id)[83] & (1 << 13)) -#define ata_id_has_lba48(id) ((id)[83] & (1 << 10)) -#define ata_id_has_hpa(id) ((id)[82] & (1 << 10)) -#define ata_id_has_wcache(id) ((id)[82] & (1 << 5)) -#define ata_id_has_pm(id) ((id)[82] & (1 << 3)) #define ata_id_has_lba(id) ((id)[49] & (1 << 9)) #define ata_id_has_dma(id) ((id)[49] & (1 << 8)) #define ata_id_has_ncq(id) ((id)[76] & (1 << 8)) #define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1) #define ata_id_removeable(id) ((id)[0] & (1 << 7)) -#define ata_id_has_dword_io(id) ((id)[50] & (1 << 0)) +#define ata_id_has_dword_io(id) ((id)[48] & (1 << 0)) #define ata_id_has_AN(id) \ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ ((id)[78] & (1 << 5)) ) @@ -378,6 +368,90 @@ struct ata_taskfile { #define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20) +static inline int ata_id_has_fua(const u16 *id) +{ + if ((id[84] & 0xC000) != 0x4000) + return 0; + return id[84] & (1 << 6); +} + +static inline int ata_id_has_flush(const u16 *id) +{ + if ((id[83] & 0xC000) != 0x4000) + return 0; + return id[83] & (1 << 12); +} + +static inline int ata_id_has_flush_ext(const u16 *id) +{ + if ((id[83] & 0xC000) != 0x4000) + return 0; + return id[83] & (1 << 13); +} + +static inline int ata_id_has_lba48(const u16 *id) +{ + if ((id[83] & 0xC000) != 0x4000) + return 0; + return id[83] & (1 << 10); +} + +static inline int ata_id_hpa_enabled(const u16 *id) +{ + /* Yes children, word 83 valid bits cover word 82 data */ + if ((id[83] & 0xC000) != 0x4000) + return 0; + /* And 87 covers 85-87 */ + if ((id[87] & 0xC000) != 0x4000) + return 0; + /* Check command sets enabled as well as supported */ + if ((id[85] & ( 1 << 10)) == 0) + return 0; + return id[82] & (1 << 10); +} + +static inline int ata_id_has_wcache(const u16 *id) +{ + /* Yes children, word 83 valid bits cover word 82 data */ + if ((id[83] & 0xC000) != 0x4000) + return 0; + return id[82] & (1 << 5); +} + +static inline int ata_id_has_pm(const u16 *id) +{ + if ((id[83] & 0xC000) != 0x4000) + return 0; + return id[82] & (1 << 3); +} + +static inline int ata_id_rahead_enabled(const u16 *id) +{ + if ((id[87] & 0xC000) != 0x4000) + return 0; + return id[85] & (1 << 6); +} + +static inline int ata_id_wcache_enabled(const u16 *id) +{ + if ((id[87] & 0xC000) != 0x4000) + return 0; + return id[85] & (1 << 5); +} + +/** + * ata_id_major_version - get ATA level of drive + * @id: Identify data + * + * Caveats: + * ATA-1 considers identify optional + * ATA-2 introduces mandatory identify + * ATA-3 introduces word 80 and accurate reporting + * + * The practical impact of this is that ata_id_major_version cannot + * reliably report on drives below ATA3. + */ + static inline unsigned int ata_id_major_version(const u16 *id) { unsigned int mver; From e923090ddd9fef1d4e06dc6c5295e29baced19f3 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Mon, 20 Aug 2007 16:56:29 +0800 Subject: [PATCH 2422/2804] libata: pata_pdc2027x PLL detection minor cleanup Minor cleanup to remove the unneeded rmb()s per Jeff's advice. Also removed the pll_clock < 0 check since pll_clock now guaranteed to be >= 0 after Mikael's patch. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc2027x.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 40b070ea85a1..2141a99e4da1 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -561,12 +561,10 @@ static long pdc_read_counter(struct ata_host *host) retry: bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; - rmb(); /* Read the counter values again for verification */ bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; - rmb(); counter = (bccrh << 15) | bccrl; @@ -741,9 +739,6 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx) */ pll_clock = pdc_detect_pll_input_clock(host); - if (pll_clock < 0) /* counter overflow? Try again. */ - pll_clock = pdc_detect_pll_input_clock(host); - dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000); /* Adjust PLL control register */ From cbcdd87593a1d85c5c4b259945a3a09eee12814d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 18 Aug 2007 13:14:55 +0900 Subject: [PATCH 2423/2804] libata: implement and use ata_port_desc() to report port configuration Currently, port configuration reporting has the following problems. * iomapped address is reported instead of raw address * report contains irrelevant fields or lacks necessary fields for non-SFF controllers. * host->irq/irq2 are there just for reporting and hacky. This patch implements and uses ata_port_desc() and ata_port_pbar_desc(). ata_port_desc() is almost identical to ata_ehi_push_desc() except that it takes @ap instead of @ehi, has no locking requirement, can only be used during host initialization and " " is used as separator instead of ", ". ata_port_pbar_desc() is a helper to ease reporting of a PCI BAR or an offsetted address into it. LLD pushes whatever description it wants using the above two functions. The accumulated description is printed on host registration after "[S/P]ATA max MAX_XFERMODE ". SFF init helpers and ata_host_activate() automatically add descriptions for addresses and irq respectively, so only LLDs which isn't standard SFF need to add custom descriptions. In many cases, such controllers need to report different things anyway. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 +++ drivers/ata/libata-core.c | 27 ++++++--------- drivers/ata/libata-eh.c | 67 ++++++++++++++++++++++++++++++++++++ drivers/ata/libata-sff.c | 23 ++++++++++--- drivers/ata/pata_cs5520.c | 23 ++++++++----- drivers/ata/pata_hpt3x3.c | 6 +++- drivers/ata/pata_icside.c | 19 ++++++++-- drivers/ata/pata_isapnp.c | 4 +++ drivers/ata/pata_ixp4xx_cf.c | 13 +++++-- drivers/ata/pata_legacy.c | 2 ++ drivers/ata/pata_mpc52xx.c | 7 ++-- drivers/ata/pata_mpiix.c | 16 +++++---- drivers/ata/pata_pcmcia.c | 2 ++ drivers/ata/pata_pdc2027x.c | 17 ++++++--- drivers/ata/pata_platform.c | 4 +++ drivers/ata/pata_qdi.c | 5 ++- drivers/ata/pata_scc.c | 3 ++ drivers/ata/pata_winbond.c | 7 ++-- drivers/ata/pdc_adma.c | 13 +++++-- drivers/ata/sata_inic162x.c | 14 ++++++-- drivers/ata/sata_mv.c | 8 ++++- drivers/ata/sata_promise.c | 11 ++++-- drivers/ata/sata_qstor.c | 11 ++++-- drivers/ata/sata_sil.c | 6 +++- drivers/ata/sata_sil24.c | 7 ++-- drivers/ata/sata_svw.c | 12 +++++-- drivers/ata/sata_sx4.c | 19 ++++++---- drivers/ata/sata_uli.c | 13 +++++++ drivers/ata/sata_via.c | 3 ++ drivers/ata/sata_vsc.c | 12 +++++-- include/linux/libata.h | 12 +++++-- 31 files changed, 309 insertions(+), 81 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 0d80189d03f3..518c51830357 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1887,6 +1887,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_port *ap = host->ports[i]; void __iomem *port_mmio = ahci_port_base(ap); + ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); + ata_port_pbar_desc(ap, AHCI_PCI_BAR, + 0x100 + ap->port_no * 0x80, "port"); + /* standard SATA port setup */ if (hpriv->port_map & (1 << i)) ap->ioaddr.cmd_addr = port_mmio; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b81265d1e469..84d81b26e384 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6541,7 +6541,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* set cable, sata_spd_limit and report */ for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - int irq_line; unsigned long xfer_mask; /* set SATA cable type if still unset */ @@ -6551,24 +6550,16 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* init sata_spd_limit to the current value */ sata_link_init_spd(&ap->link); - /* report the secondary IRQ for second channel legacy */ - irq_line = host->irq; - if (i == 1 && host->irq2) - irq_line = host->irq2; - + /* print per-port info to dmesg */ xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, ap->udma_mask); - /* print per-port info to dmesg */ if (!ata_port_is_dummy(ap)) - ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " - "ctl 0x%p bmdma 0x%p irq %d\n", + ata_port_printk(ap, KERN_INFO, + "%cATA max %s %s\n", (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', ata_mode_string(xfer_mask), - ap->ioaddr.cmd_addr, - ap->ioaddr.ctl_addr, - ap->ioaddr.bmdma_addr, - irq_line); + ap->link.eh_info.desc); else ata_port_printk(ap, KERN_INFO, "DUMMY\n"); } @@ -6652,7 +6643,7 @@ int ata_host_activate(struct ata_host *host, int irq, irq_handler_t irq_handler, unsigned long irq_flags, struct scsi_host_template *sht) { - int rc; + int i, rc; rc = ata_host_start(host); if (rc) @@ -6663,8 +6654,8 @@ int ata_host_activate(struct ata_host *host, int irq, if (rc) return rc; - /* Used to print device info at probe */ - host->irq = irq; + for (i = 0; i < host->n_ports; i++) + ata_port_desc(host->ports[i], "irq %d", irq); rc = ata_host_register(host, sht); /* if failed, just free the IRQ and leave ports alone */ @@ -7136,6 +7127,10 @@ EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); +EXPORT_SYMBOL_GPL(ata_port_desc); +#ifdef CONFIG_PCI +EXPORT_SYMBOL_GPL(ata_port_pbar_desc); +#endif /* CONFIG_PCI */ EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_link_abort); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2ddc2ed9c29d..8219e2d71045 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -151,6 +151,73 @@ void ata_ehi_clear_desc(struct ata_eh_info *ehi) ehi->desc_len = 0; } +/** + * ata_port_desc - append port description + * @ap: target ATA port + * @fmt: printf format string + * + * Format string according to @fmt and append it to port + * description. If port description is not empty, " " is added + * in-between. This function is to be used while initializing + * ata_host. The description is printed on host registration. + * + * LOCKING: + * None. + */ +void ata_port_desc(struct ata_port *ap, const char *fmt, ...) +{ + va_list args; + + WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING)); + + if (ap->link.eh_info.desc_len) + __ata_ehi_push_desc(&ap->link.eh_info, " "); + + va_start(args, fmt); + __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args); + va_end(args); +} + +#ifdef CONFIG_PCI + +/** + * ata_port_pbar_desc - append PCI BAR description + * @ap: target ATA port + * @bar: target PCI BAR + * @offset: offset into PCI BAR + * @name: name of the area + * + * If @offset is negative, this function formats a string which + * contains the name, address, size and type of the BAR and + * appends it to the port description. If @offset is zero or + * positive, only name and offsetted address is appended. + * + * LOCKING: + * None. + */ +void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, + const char *name) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + char *type = ""; + unsigned long long start, len; + + if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) + type = "m"; + else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) + type = "i"; + + start = (unsigned long long)pci_resource_start(pdev, bar); + len = (unsigned long long)pci_resource_len(pdev, bar); + + if (offset < 0) + ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start); + else + ata_port_desc(ap, "%s 0x%llx", name, start + offset); +} + +#endif /* CONFIG_PCI */ + static void ata_ering_record(struct ata_ering *ering, int is_io, unsigned int err_mask) { diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index ccef99a0337c..026439e05afe 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -567,6 +567,9 @@ int ata_pci_init_bmdma(struct ata_host *host) if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) && (ioread8(bmdma + 2) & 0x80)) host->flags |= ATA_HOST_SIMPLEX; + + ata_port_desc(ap, "bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 4) + 8 * i); } return 0; @@ -634,6 +637,10 @@ int ata_pci_init_sff_host(struct ata_host *host) ((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS); ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pci_resource_start(pdev, base), + (unsigned long long)pci_resource_start(pdev, base + 1)); + mask |= 1 << i; } @@ -804,24 +811,30 @@ int ata_pci_init_one(struct pci_dev *pdev, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; - host->irq = pdev->irq; + + ata_port_desc(host->ports[0], "irq %d", pdev->irq); + ata_port_desc(host->ports[1], "irq %d", pdev->irq); } else { if (!ata_port_is_dummy(host->ports[0])) { - host->irq = ATA_PRIMARY_IRQ(pdev); - rc = devm_request_irq(dev, host->irq, + rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), pi->port_ops->irq_handler, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; + + ata_port_desc(host->ports[0], "irq %d", + ATA_PRIMARY_IRQ(pdev)); } if (!ata_port_is_dummy(host->ports[1])) { - host->irq2 = ATA_SECONDARY_IRQ(pdev); - rc = devm_request_irq(dev, host->irq2, + rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), pi->port_ops->irq_handler, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; + + ata_port_desc(host->ports[1], "irq %d", + ATA_SECONDARY_IRQ(pdev)); } } diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 1ae6b6bd8564..ff1eb84c7d22 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -189,6 +189,8 @@ static struct ata_port_operations cs5520_port_ops = { static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { + static const unsigned int cmd_port[] = { 0x1F0, 0x170 }; + static const unsigned int ctl_port[] = { 0x3F6, 0x376 }; struct ata_port_info pi = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, @@ -242,10 +244,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi } /* Map IO ports and initialize host accordingly */ - iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8); - iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1); - iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8); - iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1); + iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8); + iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1); + iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8); + iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1); iomap[4] = pcim_iomap(pdev, 2, 0); if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4]) @@ -258,6 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ioaddr->bmdma_addr = iomap[4]; ata_std_ports(ioaddr); + ata_port_desc(host->ports[0], + "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]); + ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma"); + ioaddr = &host->ports[1]->ioaddr; ioaddr->cmd_addr = iomap[2]; ioaddr->ctl_addr = iomap[3]; @@ -265,6 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ioaddr->bmdma_addr = iomap[4] + 8; ata_std_ports(ioaddr); + ata_port_desc(host->ports[1], + "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]); + ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma"); + /* activate the host */ pci_set_master(pdev); rc = ata_host_start(host); @@ -283,10 +293,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi if (rc) return rc; - if (i == 0) - host->irq = irq[0]; - else - host->irq2 = irq[1]; + ata_port_desc(ap, "irq %d", irq[i]); } return ata_host_register(host, &cs5520_sht); diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 188d2176ec33..cb8bdb6887de 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -237,7 +237,8 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) base = host->iomap[4]; /* Bus mastering base */ for (i = 0; i < host->n_ports; i++) { - struct ata_ioports *ioaddr = &host->ports[i]->ioaddr; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *ioaddr = &ap->ioaddr; ioaddr->cmd_addr = base + offset_cmd[i]; ioaddr->altstatus_addr = @@ -245,6 +246,9 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ioaddr->scr_addr = NULL; ata_std_ports(ioaddr); ioaddr->bmdma_addr = base + 8 * i; + + ata_port_pbar_desc(ap, 4, -1, "ioport"); + ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd"); } pci_set_master(pdev); return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 4a69328a4c43..be30923566c5 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -70,6 +70,8 @@ struct pata_icside_info { unsigned int mwdma_mask; unsigned int nr_ports; const struct portinfo *port[2]; + unsigned long raw_base; + unsigned long raw_ioc_base; }; #define ICS_TYPE_A3IN 0 @@ -392,9 +394,10 @@ static struct ata_port_operations pata_icside_port_ops = { }; static void __devinit -pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base, +pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base, const struct portinfo *info) { + struct ata_ioports *ioaddr = &ap->ioaddr; void __iomem *cmd = base + info->dataoffset; ioaddr->cmd_addr = cmd; @@ -411,6 +414,13 @@ pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base, ioaddr->ctl_addr = base + info->ctrloffset; ioaddr->altstatus_addr = ioaddr->ctl_addr; + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", + info->raw_base + info->dataoffset, + info->raw_base + info->ctrloffset); + + if (info->raw_ioc_base) + ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base); } static int __devinit pata_icside_register_v5(struct pata_icside_info *info) @@ -431,6 +441,8 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info) info->nr_ports = 1; info->port[0] = &pata_icside_portinfo_v5; + info->raw_base = ecard_resource_start(ec, ECARD_RES_MEMC); + return 0; } @@ -471,6 +483,9 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info) info->port[0] = &pata_icside_portinfo_v6_1; info->port[1] = &pata_icside_portinfo_v6_2; + info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI); + info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST); + return icside_dma_init(info); } @@ -507,7 +522,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info) ap->flags |= ATA_FLAG_SLAVE_POSS; ap->ops = &pata_icside_port_ops; - pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]); + pata_icside_setup_ioaddr(ap, info->base, info->port[i]); } return ata_host_activate(host, ec->irq, ata_interrupt, 0, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 8ac1e8beabaf..88ab0e1d353f 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -110,6 +110,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pnp_port_start(idev, 0), + (unsigned long long)pnp_port_start(idev, 1)); + /* activate */ return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0, &isapnp_sht); diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 7b0d2fc57484..fcd532afbf2e 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -131,8 +131,12 @@ static struct ata_port_operations ixp4xx_port_ops = { }; static void ixp4xx_setup_port(struct ata_ioports *ioaddr, - struct ixp4xx_pata_data *data) + struct ixp4xx_pata_data *data, + unsigned long raw_cs0, unsigned long raw_cs1) { + unsigned long raw_cmd = raw_cs0; + unsigned long raw_ctl = raw_cs1 + 0x06; + ioaddr->cmd_addr = data->cs0; ioaddr->altstatus_addr = data->cs1 + 0x06; ioaddr->ctl_addr = data->cs1 + 0x06; @@ -158,7 +162,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr, *(unsigned long *)&ioaddr->device_addr ^= 0x03; *(unsigned long *)&ioaddr->status_addr ^= 0x03; *(unsigned long *)&ioaddr->command_addr ^= 0x03; + + raw_cmd ^= 0x03; + raw_ctl ^= 0x03; #endif + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl); } static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) @@ -203,7 +212,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) ap->pio_mask = 0x1f; /* PIO4 */ ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI; - ixp4xx_setup_port(&ap->ioaddr, data); + ixp4xx_setup_port(ap, data, cs0->start, cs1->start); dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 6cae26f4d272..7bed8d806381 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -799,6 +799,8 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl ata_std_ports(&ap->ioaddr); ap->private_data = ld; + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl); + ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht); if (ret) goto fail; diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index a56694b2833e..412140f02853 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -302,7 +302,8 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { }; static int __devinit -mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) +mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, + unsigned long raw_ata_regs) { struct ata_host *host; struct ata_port *ap; @@ -336,6 +337,8 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) aio->status_addr = &priv->ata_regs->tf_command; aio->command_addr = &priv->ata_regs->tf_command; + ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs); + /* activate host */ return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0, &mpc52xx_ata_sht); @@ -432,7 +435,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) } /* Register ourselves to libata */ - rv = mpc52xx_ata_init_one(&op->dev, priv); + rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start); if (rv) { printk(KERN_ERR DRV_NAME ": " "Error while registering to ATA layer\n"); diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index cb78b7bfe143..d5483087a3fa 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -201,7 +201,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; u16 idetim; - int irq; + int cmd, ctl, irq; if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); @@ -209,6 +209,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) host = ata_host_alloc(&dev->dev, 1); if (!host) return -ENOMEM; + ap = host->ports[0]; /* MPIIX has many functions which can be turned on or off according to other devices present. Make sure IDE is enabled before we try @@ -220,25 +221,28 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* See if it's primary or secondary channel... */ if (!(idetim & SECONDARY)) { + cmd = 0x1F0; + ctl = 0x3F6; irq = 14; - cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8); - ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1); } else { + cmd = 0x170; + ctl = 0x376; irq = 15; - cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8); - ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1); } + cmd_addr = devm_ioport_map(&dev->dev, cmd, 8); + ctl_addr = devm_ioport_map(&dev->dev, ctl, 1); if (!cmd_addr || !ctl_addr) return -ENOMEM; + ata_port_desc(ap, "cmd 0x%x ctl 0x%x", cmd, ctl); + /* We do our own plumbing to avoid leaking special cases for whacko ancient hardware into the core code. There are two issues to worry about. #1 The chip is a bridge so if in legacy mode and without BARs set fools the setup. #2 If you pci_disable_device the MPIIX your box goes castors up */ - ap = host->ports[0]; ap->ops = &mpiix_port_ops; ap->pio_mask = 0x1F; ap->flags |= ATA_FLAG_SLAVE_POSS; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 5baf531f652e..782ff4ada9d1 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -302,6 +302,8 @@ next_entry: ap->ioaddr.ctl_addr = ctl_addr; ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base); + /* activate */ ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt, IRQF_SHARED, &pcmcia_sht); diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 2141a99e4da1..f87c800be7f3 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -782,12 +782,14 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; + static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 }; + static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 }; unsigned int board_idx = (unsigned int) ent->driver_data; const struct ata_port_info *ppi[] = { &pdc2027x_port_info[board_idx], NULL }; struct ata_host *host; void __iomem *mmio_base; - int rc; + int i, rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -817,10 +819,15 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de mmio_base = host->iomap[PDC_MMIO_BAR]; - pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0); - host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000; - pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0); - host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008; + for (i = 0; i < 2; i++) { + struct ata_port *ap = host->ports[i]; + + pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]); + ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i]; + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd"); + } //pci_enable_intx(pdev); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index b04ce5f98410..fc72a965643d 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -208,6 +208,10 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) pp_info = pdev->dev.platform_data; pata_platform_setup_port(&ap->ioaddr, pp_info); + ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport", + (unsigned long long)io_res->start, + (unsigned long long)ctl_res->start); + /* activate */ return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, pp_info ? pp_info->irq_flags diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 032fa67acc8b..7d4c696c4cb6 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -234,6 +234,7 @@ static struct ata_port_operations qdi6580_port_ops = { static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast) { + unsigned long ctl = io + 0x206; struct platform_device *pdev; struct ata_host *host; struct ata_port *ap; @@ -250,7 +251,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i ret = -ENOMEM; io_addr = devm_ioport_map(&pdev->dev, io, 8); - ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1); + ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1); if (!io_addr || !ctl_addr) goto fail; @@ -275,6 +276,8 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i ap->ioaddr.ctl_addr = ctl_addr; ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl); + /* * Hook in a private data structure per channel */ diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index e138343b5d4e..2153def3f345 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -1159,6 +1159,9 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) return rc; host->iomap = pcim_iomap_table(pdev); + ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl"); + ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid"); + rc = scc_host_init(host); if (rc) return rc; diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 553658bacce0..549cbbe9fd07 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -197,6 +197,7 @@ static __init int winbond_init_one(unsigned long port) for (i = 0; i < 2 ; i ++) { unsigned long cmd_port = 0x1F0 - (0x80 * i); + unsigned long ctl_port = cmd_port + 0x206; struct ata_host *host; struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; @@ -212,14 +213,16 @@ static __init int winbond_init_one(unsigned long port) host = ata_host_alloc(&pdev->dev, 1); if (!host) goto err_unregister; + ap = host->ports[0]; rc = -ENOMEM; cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8); - ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1); + ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1); if (!cmd_addr || !ctl_addr) goto err_unregister; - ap = host->ports[0]; + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port); + ap->ops = &winbond_port_ops; ap->pio_mask = 0x1F; ap->flags |= ATA_FLAG_SLAVE_POSS; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 42fd15aaba0b..8d1b03d5bcb1 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -704,9 +704,16 @@ static int adma_ata_init_one(struct pci_dev *pdev, if (rc) return rc; - for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_ata_setup_port(&host->ports[port_no]->ioaddr, - ADMA_ATA_REGS(mmio_base, port_no)); + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) { + struct ata_port *ap = host->ports[port_no]; + void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no); + unsigned int offset = port_base - mmio_base; + + adma_ata_setup_port(&ap->ioaddr, port_base); + + ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port"); + } /* initialize adapter */ adma_host_init(host, board_idx); diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index f0ea0e166c11..08595f34b3e8 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -693,16 +693,24 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->iomap = iomap = pcim_iomap_table(pdev); for (i = 0; i < NR_PORTS; i++) { - struct ata_ioports *port = &host->ports[i]->ioaddr; - void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *port = &ap->ioaddr; + unsigned int offset = i * PORT_SIZE; port->cmd_addr = iomap[2 * i]; port->altstatus_addr = port->ctl_addr = (void __iomem *) ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); - port->scr_addr = port_base + PORT_SCR; + port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR; ata_std_ports(port); + + ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, MMIO_BAR, offset, "port"); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pci_resource_start(pdev, 2 * i), + (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) | + ATA_PCI_CTL_OFS); } hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 68c3f22890d2..08077efa9afd 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2584,8 +2584,14 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) } for (port = 0; port < host->n_ports; port++) { + struct ata_port *ap = host->ports[port]; void __iomem *port_mmio = mv_port_base(mmio, port); - mv_port_init(&host->ports[port]->ioaddr, port_mmio); + unsigned int offset = port_mmio - mmio; + + mv_port_init(&ap->ioaddr, port_mmio); + + ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port"); } for (hc = 0; hc < n_hc; hc++) { diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 983bff5c4def..903213153b5d 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -1003,10 +1003,15 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags); for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4); - pdc_ata_setup_port(host->ports[i], - base + 0x200 + ata_no * 0x80, - base + 0x400 + ata_no * 0x100); + unsigned int port_offset = 0x200 + ata_no * 0x80; + unsigned int scr_offset = 0x400 + ata_no * 0x100; + + pdc_ata_setup_port(ap, base + port_offset, base + scr_offset); + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port"); } /* initialize adapter */ diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 10bf52ca1e19..c4c4cd29eebb 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -635,9 +635,14 @@ static int qs_ata_init_one(struct pci_dev *pdev, return rc; for (port_no = 0; port_no < host->n_ports; ++port_no) { - void __iomem *chan = - host->iomap[QS_MMIO_BAR] + (port_no * 0x4000); - qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan); + struct ata_port *ap = host->ports[port_no]; + unsigned int offset = port_no * 0x4000; + void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset; + + qs_ata_setup_port(&ap->ioaddr, chan); + + ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port"); } /* initialize adapter */ diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index df0ac77fcdd4..ea3a0ab7e027 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -687,7 +687,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) mmio_base = host->iomap[SIL_MMIO_BAR]; for (i = 0; i < host->n_ports; i++) { - struct ata_ioports *ioaddr = &host->ports[i]->ioaddr; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *ioaddr = &ap->ioaddr; ioaddr->cmd_addr = mmio_base + sil_port[i].tf; ioaddr->altstatus_addr = @@ -695,6 +696,9 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma; ioaddr->scr_addr = mmio_base + sil_port[i].scr; ata_std_ports(ioaddr); + + ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf"); } /* initialize and activate */ diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e0cd31aa8002..3dcb223117be 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -1119,12 +1119,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->iomap = iomap; for (i = 0; i < host->n_ports; i++) { - void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE; + struct ata_port *ap = host->ports[i]; + size_t offset = ap->port_no * PORT_REGS_SIZE; + void __iomem *port = iomap[SIL24_PORT_BAR] + offset; host->ports[i]->ioaddr.cmd_addr = port; host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL; - ata_std_ports(&host->ports[i]->ioaddr); + ata_port_pbar_desc(ap, SIL24_HOST_BAR, -1, "host"); + ata_port_pbar_desc(ap, SIL24_PORT_BAR, offset, "port"); } /* configure and activate the device */ diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 822cabfec951..12d613c48c19 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -443,9 +443,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e /* different controllers have different number of ports - currently 4 or 8 */ /* All ports are on the same function. Multi-function device is no * longer available. This should not be seen in any system. */ - for (i = 0; i < host->n_ports; i++) - k2_sata_setup_port(&host->ports[i]->ioaddr, - mmio_base + i * K2_SATA_PORT_OFFSET); + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + unsigned int offset = i * K2_SATA_PORT_OFFSET; + + k2_sata_setup_port(&ap->ioaddr, mmio_base + offset); + + ata_port_pbar_desc(ap, 5, -1, "mmio"); + ata_port_pbar_desc(ap, 5, offset, "port"); + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index b425061dbe8c..9f9f7b30654a 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -1381,9 +1381,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * const struct ata_port_info *ppi[] = { &pdc_port_info[ent->driver_data], NULL }; struct ata_host *host; - void __iomem *base; struct pdc_host_priv *hpriv; - int rc; + int i, rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -1409,11 +1408,17 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * return rc; host->iomap = pcim_iomap_table(pdev); - base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; - pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200); - pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280); - pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300); - pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380); + for (i = 0; i < 4; i++) { + struct ata_port *ap = host->ports[i]; + void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; + unsigned int offset = 0x200 + i * 0x80; + + pdc_sata_setup_port(&ap->ioaddr, base + offset); + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port"); + } /* configure and activate */ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 6c53a790805f..d394da085ae4 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -239,6 +239,12 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; ata_std_ports(ioaddr); + ata_port_desc(host->ports[2], + "cmd 0x%llx ctl 0x%llx bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 0) + 8, + ((unsigned long long)pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4, + (unsigned long long)pci_resource_start(pdev, 4) + 16); + ioaddr = &host->ports[3]->ioaddr; ioaddr->cmd_addr = iomap[2] + 8; ioaddr->altstatus_addr = @@ -247,6 +253,13 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ioaddr->bmdma_addr = iomap[4] + 24; hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; ata_std_ports(ioaddr); + + ata_port_desc(host->ports[2], + "cmd 0x%llx ctl 0x%llx bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 2) + 9, + ((unsigned long long)pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4, + (unsigned long long)pci_resource_start(pdev, 4) + 24); + break; case uli_5289: diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 25162ec99384..f0757023ce9d 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -399,6 +399,9 @@ static void vt6421_init_addrs(struct ata_port *ap) ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no); ata_std_ports(ioaddr); + + ata_port_pbar_desc(ap, ap->port_no, -1, "port"); + ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma"); } static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index b1777c3f6d5c..0d9be1684873 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -406,9 +406,15 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d mmio_base = host->iomap[VSC_MMIO_BAR]; - for (i = 0; i < host->n_ports; i++) - vsc_sata_setup_port(&host->ports[i]->ioaddr, - mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET); + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET; + + vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset); + + ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port"); + } /* * Use 32 bit DMA mask, because 64 bit address support is poor. diff --git a/include/linux/libata.h b/include/linux/libata.h index e7d163edb4c0..d3defae689ca 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -368,8 +368,6 @@ struct ata_ioports { struct ata_host { spinlock_t lock; struct device *dev; - unsigned long irq; - unsigned long irq2; void __iomem * const *iomap; unsigned int n_ports; void *private_data; @@ -968,6 +966,16 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) ehi->err_mask |= AC_ERR_ATA_BUS; } +/* + * port description helpers + */ +extern void ata_port_desc(struct ata_port *ap, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); +#ifdef CONFIG_PCI +extern void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, + const char *name); +#endif + /* * qc helpers */ From a1e10f7e68a544c80081fee4fa550dc28389f44a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 18 Aug 2007 13:28:49 +0900 Subject: [PATCH 2424/2804] libata: move EH repeat reporting into ata_eh_report() EH is sometimes repeated without any error or action. For example, this happens when probing IDENTIFY fails because of a phantom device. In these cases, all the repeated EH does is making sure there is no unhandled error or pending action and return. This repeation is necessary to avoid losing any event which occurred while EH was in progress. Unfortunately, this dry run causes annonying "EH pending after completion" message. This patch moves the repeat reporting into ata_eh_report() such that it's more compact and skipped on dry runs. Signed-off-by: Tejun Heo Cc: Mikael Pettersson Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 30 ++++++++++++++++++------------ include/linux/libata.h | 5 +++-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8219e2d71045..daa2f74f73c8 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -358,7 +358,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); - int i, repeat_cnt = ATA_EH_MAX_REPEAT; + int i; unsigned long flags; DPRINTK("ENTER\n"); @@ -424,6 +424,9 @@ void ata_scsi_error(struct Scsi_Host *host) __ata_port_freeze(ap); spin_unlock_irqrestore(ap->lock, flags); + + /* initialize eh_tries */ + ap->eh_tries = ATA_EH_MAX_TRIES; } else spin_unlock_wait(ap->lock); @@ -468,15 +471,12 @@ void ata_scsi_error(struct Scsi_Host *host) spin_lock_irqsave(ap->lock, flags); if (ap->pflags & ATA_PFLAG_EH_PENDING) { - if (--repeat_cnt) { - ata_port_printk(ap, KERN_INFO, - "EH pending after completion, " - "repeating EH (cnt=%d)\n", repeat_cnt); + if (--ap->eh_tries) { spin_unlock_irqrestore(ap->lock, flags); goto repeat; } ata_port_printk(ap, KERN_ERR, "EH pending after %d " - "tries, giving up\n", ATA_EH_MAX_REPEAT); + "tries, giving up\n", ATA_EH_MAX_TRIES); ap->pflags &= ~ATA_PFLAG_EH_PENDING; } @@ -1778,6 +1778,7 @@ static void ata_eh_link_report(struct ata_link *link) struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; const char *frozen, *desc; + char tries_buf[6]; int tag, nr_failed = 0; desc = NULL; @@ -1802,18 +1803,23 @@ static void ata_eh_link_report(struct ata_link *link) if (ap->pflags & ATA_PFLAG_FROZEN) frozen = " frozen"; + memset(tries_buf, 0, sizeof(tries_buf)); + if (ap->eh_tries < ATA_EH_MAX_TRIES) + snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d", + ap->eh_tries); + if (ehc->i.dev) { ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " - "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, link->sactive, - ehc->i.serror, ehc->i.action, frozen); + "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", + ehc->i.err_mask, link->sactive, ehc->i.serror, + ehc->i.action, frozen, tries_buf); if (desc) ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { ata_link_printk(link, KERN_ERR, "exception Emask 0x%x " - "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, link->sactive, - ehc->i.serror, ehc->i.action, frozen); + "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", + ehc->i.err_mask, link->sactive, ehc->i.serror, + ehc->i.action, frozen, tries_buf); if (desc) ata_link_printk(link, KERN_ERR, "%s\n", desc); } diff --git a/include/linux/libata.h b/include/linux/libata.h index d3defae689ca..74e034ea9016 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -293,8 +293,8 @@ enum { ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, - /* max repeat if error condition is still set after ->error_handler */ - ATA_EH_MAX_REPEAT = 5, + /* max tries if error condition is still set after ->error_handler */ + ATA_EH_MAX_TRIES = 5, /* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES = 3, @@ -581,6 +581,7 @@ struct ata_port { u32 msg_enable; struct list_head eh_done_q; wait_queue_head_t eh_wait_q; + int eh_tries; pm_message_t pm_mesg; int *pm_result; From d830d1731fa5906aad20c228ac8b73005b13d468 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 21 Aug 2007 13:12:31 +0800 Subject: [PATCH 2425/2804] libata driver for bf548 on chip ATAPI controller. Fix all issues pointed out in Jeff's email. Acked-by: Alan Cox Signed-off-by: Sonic Zhang Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 16 + drivers/ata/Makefile | 1 + drivers/ata/pata_bf54x.c | 1627 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1644 insertions(+) create mode 100644 drivers/ata/pata_bf54x.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index d8046a113c37..a427945f0bb1 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -596,4 +596,20 @@ config PATA_SCC If unsure, say N. +config PATA_BF54X + tristate "Blackfin 54x ATAPI support" + depends on BF542 || BF548 || BF549 + help + This option enables support for the built-in ATAPI controller on + Blackfin 54x family chips. + + If unsure, say N. + +config PATA_BF54X_DMA + bool "DMA mode" + depends on PATA_BF54X + default y + help + Enable DMA mode for Blackfin ATAPI controller. + endif # ATA diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 8149c68ac2c7..c2ecba5f0b47 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o obj-$(CONFIG_PATA_SCC) += pata_scc.o +obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o # Should be last but one libata driver diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c new file mode 100644 index 000000000000..747549e4563a --- /dev/null +++ b/drivers/ata/pata_bf54x.c @@ -0,0 +1,1627 @@ +/* + * File: drivers/ata/pata_bf54x.c + * Author: Sonic Zhang + * + * Created: + * Description: PATA Driver for blackfin 54x + * + * Modified: + * Copyright 2007 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 + +#define DRV_NAME "pata-bf54x" +#define DRV_VERSION "0.9" + +#define ATA_REG_CTRL 0x0E +#define ATA_REG_ALTSTATUS ATA_REG_CTRL + +/* These are the offset of the controller's registers */ +#define ATAPI_OFFSET_CONTROL 0x00 +#define ATAPI_OFFSET_STATUS 0x04 +#define ATAPI_OFFSET_DEV_ADDR 0x08 +#define ATAPI_OFFSET_DEV_TXBUF 0x0c +#define ATAPI_OFFSET_DEV_RXBUF 0x10 +#define ATAPI_OFFSET_INT_MASK 0x14 +#define ATAPI_OFFSET_INT_STATUS 0x18 +#define ATAPI_OFFSET_XFER_LEN 0x1c +#define ATAPI_OFFSET_LINE_STATUS 0x20 +#define ATAPI_OFFSET_SM_STATE 0x24 +#define ATAPI_OFFSET_TERMINATE 0x28 +#define ATAPI_OFFSET_PIO_TFRCNT 0x2c +#define ATAPI_OFFSET_DMA_TFRCNT 0x30 +#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34 +#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38 +#define ATAPI_OFFSET_REG_TIM_0 0x40 +#define ATAPI_OFFSET_PIO_TIM_0 0x44 +#define ATAPI_OFFSET_PIO_TIM_1 0x48 +#define ATAPI_OFFSET_MULTI_TIM_0 0x50 +#define ATAPI_OFFSET_MULTI_TIM_1 0x54 +#define ATAPI_OFFSET_MULTI_TIM_2 0x58 +#define ATAPI_OFFSET_ULTRA_TIM_0 0x60 +#define ATAPI_OFFSET_ULTRA_TIM_1 0x64 +#define ATAPI_OFFSET_ULTRA_TIM_2 0x68 +#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c + + +#define ATAPI_GET_CONTROL(base)\ + bfin_read16(base + ATAPI_OFFSET_CONTROL) +#define ATAPI_SET_CONTROL(base, val)\ + bfin_write16(base + ATAPI_OFFSET_CONTROL, val) +#define ATAPI_GET_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_STATUS) +#define ATAPI_GET_DEV_ADDR(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_ADDR) +#define ATAPI_SET_DEV_ADDR(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val) +#define ATAPI_GET_DEV_TXBUF(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF) +#define ATAPI_SET_DEV_TXBUF(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val) +#define ATAPI_GET_DEV_RXBUF(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF) +#define ATAPI_SET_DEV_RXBUF(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val) +#define ATAPI_GET_INT_MASK(base)\ + bfin_read16(base + ATAPI_OFFSET_INT_MASK) +#define ATAPI_SET_INT_MASK(base, val)\ + bfin_write16(base + ATAPI_OFFSET_INT_MASK, val) +#define ATAPI_GET_INT_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_INT_STATUS) +#define ATAPI_SET_INT_STATUS(base, val)\ + bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val) +#define ATAPI_GET_XFER_LEN(base)\ + bfin_read16(base + ATAPI_OFFSET_XFER_LEN) +#define ATAPI_SET_XFER_LEN(base, val)\ + bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val) +#define ATAPI_GET_LINE_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_LINE_STATUS) +#define ATAPI_GET_SM_STATE(base)\ + bfin_read16(base + ATAPI_OFFSET_SM_STATE) +#define ATAPI_GET_TERMINATE(base)\ + bfin_read16(base + ATAPI_OFFSET_TERMINATE) +#define ATAPI_SET_TERMINATE(base, val)\ + bfin_write16(base + ATAPI_OFFSET_TERMINATE, val) +#define ATAPI_GET_PIO_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT) +#define ATAPI_GET_DMA_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT) +#define ATAPI_GET_UMAIN_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT) +#define ATAPI_GET_UDMAOUT_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT) +#define ATAPI_GET_REG_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_REG_TIM_0) +#define ATAPI_SET_REG_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val) +#define ATAPI_GET_PIO_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0) +#define ATAPI_SET_PIO_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val) +#define ATAPI_GET_PIO_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1) +#define ATAPI_SET_PIO_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val) +#define ATAPI_GET_MULTI_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0) +#define ATAPI_SET_MULTI_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val) +#define ATAPI_GET_MULTI_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1) +#define ATAPI_SET_MULTI_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val) +#define ATAPI_GET_MULTI_TIM_2(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2) +#define ATAPI_SET_MULTI_TIM_2(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val) +#define ATAPI_GET_ULTRA_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0) +#define ATAPI_SET_ULTRA_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val) +#define ATAPI_GET_ULTRA_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1) +#define ATAPI_SET_ULTRA_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val) +#define ATAPI_GET_ULTRA_TIM_2(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2) +#define ATAPI_SET_ULTRA_TIM_2(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val) +#define ATAPI_GET_ULTRA_TIM_3(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3) +#define ATAPI_SET_ULTRA_TIM_3(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val) + +/** + * PIO Mode - Frequency compatibility + */ +/* mode: 0 1 2 3 4 */ +static const u32 pio_fsclk[] = +{ 33333333, 33333333, 33333333, 33333333, 33333333 }; + +/** + * MDMA Mode - Frequency compatibility + */ +/* mode: 0 1 2 */ +static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 }; + +/** + * UDMA Mode - Frequency compatibility + * + * UDMA5 - 100 MB/s - SCLK = 133 MHz + * UDMA4 - 66 MB/s - SCLK >= 80 MHz + * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz + * UDMA2 - 33 MB/s - SCLK >= 40 MHz + */ +/* mode: 0 1 2 3 4 5 */ +static const u32 udma_fsclk[] = +{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 }; + +/** + * Register transfer timing table + */ +/* mode: 0 1 2 3 4 */ +/* Cycle Time */ +static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 }; +/* DIOR/DIOW to end cycle */ +static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 }; + +/** + * PIO timing table + */ +/* mode: 0 1 2 3 4 */ +/* Cycle Time */ +static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 }; +/* Address valid to DIOR/DIORW */ +static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 }; +/* DIOR/DIOW to end cycle */ +static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 }; +/* DIOW data hold */ +static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 }; + +/* ****************************************************************** + * Multiword DMA timing table + * ****************************************************************** + */ +/* mode: 0 1 2 */ +/* Cycle Time */ +static const u32 mdma_t0min[] = { 480, 150, 120 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 mdma_tdmin[] = { 215, 80, 70 }; +/* DMACK to read data released */ +static const u32 mdma_thmin[] = { 20, 15, 10 }; +/* DIOR/DIOW to DMACK hold */ +static const u32 mdma_tjmin[] = { 20, 5, 5 }; +/* DIOR negated pulse width */ +static const u32 mdma_tkrmin[] = { 50, 50, 25 }; +/* DIOR negated pulse width */ +static const u32 mdma_tkwmin[] = { 215, 50, 25 }; +/* CS[1:0] valid to DIOR/DIOW */ +static const u32 mdma_tmmin[] = { 50, 30, 25 }; +/* DMACK to read data released */ +static const u32 mdma_tzmax[] = { 20, 25, 25 }; + +/** + * Ultra DMA timing table + */ +/* mode: 0 1 2 3 4 5 */ +static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 }; +static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 }; +static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 }; +static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 }; +static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 }; + + +static const u32 udma_tmlimin = 20; +static const u32 udma_tzahmin = 20; +static const u32 udma_tenvmin = 20; +static const u32 udma_tackmin = 20; +static const u32 udma_tssmin = 50; + +/** + * + * Function: num_clocks_min + * + * Description: + * calculate number of SCLK cycles to meet minimum timing + */ +static unsigned short num_clocks_min(unsigned long tmin, + unsigned long fsclk) +{ + unsigned long tmp ; + unsigned short result; + + tmp = tmin * (fsclk/1000/1000) / 1000; + result = (unsigned short)tmp; + if ((tmp*1000*1000) < (tmin*(fsclk/1000))) { + result++; + } + + return result; +} + +/** + * bfin_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set PIO mode for device. + * + * LOCKING: + * None (inherited from caller). + */ + +static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + int mode = adev->pio_mode - XFER_PIO_0; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int fsclk = get_sclk(); + unsigned short teoc_reg, t2_reg, teoc_pio; + unsigned short t4_reg, t2_pio, t1_reg; + unsigned short n0, n6, t6min = 5; + + /* the most restrictive timing value is t6 and tc, the DIOW - data hold + * If one SCLK pulse is longer than this minimum value then register + * transfers cannot be supported at this frequency. + */ + n6 = num_clocks_min(t6min, fsclk); + if (mode >= 0 && mode <= 4 && n6 >= 1) { + pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk); + /* calculate the timing values for register transfers. */ + while (mode > 0 && pio_fsclk[mode] > fsclk) + mode--; + + /* DIOR/DIOW to end cycle time */ + t2_reg = num_clocks_min(reg_t2min[mode], fsclk); + /* DIOR/DIOW asserted pulse width */ + teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk); + /* Cycle Time */ + n0 = num_clocks_min(reg_t0min[mode], fsclk); + + /* increase t2 until we meed the minimum cycle length */ + if (t2_reg + teoc_reg < n0) + t2_reg = n0 - teoc_reg; + + /* calculate the timing values for pio transfers. */ + + /* DIOR/DIOW to end cycle time */ + t2_pio = num_clocks_min(pio_t2min[mode], fsclk); + /* DIOR/DIOW asserted pulse width */ + teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk); + /* Cycle Time */ + n0 = num_clocks_min(pio_t0min[mode], fsclk); + + /* increase t2 until we meed the minimum cycle length */ + if (t2_pio + teoc_pio < n0) + t2_pio = n0 - teoc_pio; + + /* Address valid to DIOR/DIORW */ + t1_reg = num_clocks_min(pio_t1min[mode], fsclk); + + /* DIOW data hold */ + t4_reg = num_clocks_min(pio_t4min[mode], fsclk); + + ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg)); + ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg)); + ATAPI_SET_PIO_TIM_1(base, teoc_pio); + if (mode > 2) { + ATAPI_SET_CONTROL(base, + ATAPI_GET_CONTROL(base) | IORDY_EN); + } else { + ATAPI_SET_CONTROL(base, + ATAPI_GET_CONTROL(base) & ~IORDY_EN); + } + + /* Disable host ATAPI PIO interrupts */ + ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) + & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK)); + SSYNC(); + } +} + +/** + * bfin_set_dmamode - Initialize host controller PATA DMA timings + * @ap: Port whose timings we are configuring + * @adev: um + * @udma: udma mode, 0 - 6 + * + * Set UDMA mode for device. + * + * LOCKING: + * None (inherited from caller). + */ + +static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + int mode; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned long fsclk = get_sclk(); + unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah; + unsigned short tm, td, tkr, tkw, teoc, th; + unsigned short n0, nf, tfmin = 5; + unsigned short nmin, tcyc; + + mode = adev->dma_mode - XFER_UDMA_0; + if (mode >= 0 && mode <= 5) { + pr_debug("set udmamode: mode=%d\n", mode); + /* the most restrictive timing value is t6 and tc, + * the DIOW - data hold. If one SCLK pulse is longer + * than this minimum value then register + * transfers cannot be supported at this frequency. + */ + while (mode > 0 && udma_fsclk[mode] > fsclk) + mode--; + + nmin = num_clocks_min(udma_tmin[mode], fsclk); + if (nmin >= 1) { + /* calculate the timing values for Ultra DMA. */ + tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk); + tcyc = num_clocks_min(udma_tcycmin[mode], fsclk); + tcyc_tdvs = 2; + + /* increase tcyc - tdvs (tcyc_tdvs) until we meed + * the minimum cycle length + */ + if (tdvs + tcyc_tdvs < tcyc) + tcyc_tdvs = tcyc - tdvs; + + /* Mow assign the values required for the timing + * registers + */ + if (tcyc_tdvs < 2) + tcyc_tdvs = 2; + + if (tdvs < 2) + tdvs = 2; + + tack = num_clocks_min(udma_tackmin, fsclk); + tss = num_clocks_min(udma_tssmin, fsclk); + tmli = num_clocks_min(udma_tmlimin, fsclk); + tzah = num_clocks_min(udma_tzahmin, fsclk); + trp = num_clocks_min(udma_trpmin[mode], fsclk); + tenv = num_clocks_min(udma_tenvmin, fsclk); + if (tenv <= udma_tenvmax[mode]) { + ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack)); + ATAPI_SET_ULTRA_TIM_1(base, + (tcyc_tdvs<<8 | tdvs)); + ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss)); + ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah)); + + /* Enable host ATAPI Untra DMA interrupts */ + ATAPI_SET_INT_MASK(base, + ATAPI_GET_INT_MASK(base) + | UDMAIN_DONE_MASK + | UDMAOUT_DONE_MASK + | UDMAIN_TERM_MASK + | UDMAOUT_TERM_MASK); + } + } + } + + mode = adev->dma_mode - XFER_MW_DMA_0; + if (mode >= 0 && mode <= 2) { + pr_debug("set mdmamode: mode=%d\n", mode); + /* the most restrictive timing value is tf, the DMACK to + * read data released. If one SCLK pulse is longer than + * this maximum value then the MDMA mode + * cannot be supported at this frequency. + */ + while (mode > 0 && mdma_fsclk[mode] > fsclk) + mode--; + + nf = num_clocks_min(tfmin, fsclk); + if (nf >= 1) { + /* calculate the timing values for Multi-word DMA. */ + + /* DIOR/DIOW asserted pulse width */ + td = num_clocks_min(mdma_tdmin[mode], fsclk); + + /* DIOR negated pulse width */ + tkw = num_clocks_min(mdma_tkwmin[mode], fsclk); + + /* Cycle Time */ + n0 = num_clocks_min(mdma_t0min[mode], fsclk); + + /* increase tk until we meed the minimum cycle length */ + if (tkw + td < n0) + tkw = n0 - td; + + /* DIOR negated pulse width - read */ + tkr = num_clocks_min(mdma_tkrmin[mode], fsclk); + /* CS{1:0] valid to DIOR/DIOW */ + tm = num_clocks_min(mdma_tmmin[mode], fsclk); + /* DIOR/DIOW to DMACK hold */ + teoc = num_clocks_min(mdma_tjmin[mode], fsclk); + /* DIOW Data hold */ + th = num_clocks_min(mdma_thmin[mode], fsclk); + + ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td)); + ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw)); + ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th)); + + /* Enable host ATAPI Multi DMA interrupts */ + ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) + | MULTI_DONE_MASK | MULTI_TERM_MASK); + SSYNC(); + } + } + return; +} + +/** + * + * Function: wait_complete + * + * Description: Waits the interrupt from device + * + */ +static inline void wait_complete(void __iomem *base, unsigned short mask) +{ + unsigned short status; + unsigned int i = 0; + +#define PATA_BF54X_WAIT_TIMEOUT 10000 + + for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) { + status = ATAPI_GET_INT_STATUS(base) & mask; + if (status) + break; + } + + ATAPI_SET_INT_STATUS(base, mask); +} + +/** + * + * Function: write_atapi_register + * + * Description: Writes to ATA Device Resgister + * + */ + +static void write_atapi_register(void __iomem *base, + unsigned long ata_reg, unsigned short value) +{ + /* Program the ATA_DEV_TXBUF register with write data (to be + * written into the device). + */ + ATAPI_SET_DEV_TXBUF(base, value); + + /* Program the ATA_DEV_ADDR register with address of the + * device register (0x01 to 0x0F). + */ + ATAPI_SET_DEV_ADDR(base, ata_reg); + + /* Program the ATA_CTRL register with dir set to write (1) + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (We need to wait on and clear rhe ATA_DEV_INT interrupt status) + */ + wait_complete(base, PIO_DONE_INT); +} + +/** + * + * Function: read_atapi_register + * + *Description: Reads from ATA Device Resgister + * + */ + +static unsigned short read_atapi_register(void __iomem *base, + unsigned long ata_reg) +{ + /* Program the ATA_DEV_ADDR register with address of the + * device register (0x01 to 0x0F). + */ + ATAPI_SET_DEV_ADDR(base, ata_reg); + + /* Program the ATA_CTRL register with dir set to read (0) and + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (PIO_DONE interrupt is set and it doesn't seem to matter + * that we don't clear it) + */ + wait_complete(base, PIO_DONE_INT); + + /* Read the ATA_DEV_RXBUF register with write data (to be + * written into the device). + */ + return ATAPI_GET_DEV_RXBUF(base); +} + +/** + * + * Function: write_atapi_register_data + * + * Description: Writes to ATA Device Resgister + * + */ + +static void write_atapi_data(void __iomem *base, + int len, unsigned short *buf) +{ + int i; + + /* Set transfer length to 1 */ + ATAPI_SET_XFER_LEN(base, 1); + + /* Program the ATA_DEV_ADDR register with address of the + * ATA_REG_DATA + */ + ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA); + + /* Program the ATA_CTRL register with dir set to write (1) + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + for (i = 0; i < len; i++) { + /* Program the ATA_DEV_TXBUF register with write data (to be + * written into the device). + */ + ATAPI_SET_DEV_TXBUF(base, buf[i]); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (We need to wait on and clear rhe ATA_DEV_INT + * interrupt status) + */ + wait_complete(base, PIO_DONE_INT); + } +} + +/** + * + * Function: read_atapi_register_data + * + * Description: Reads from ATA Device Resgister + * + */ + +static void read_atapi_data(void __iomem *base, + int len, unsigned short *buf) +{ + int i; + + /* Set transfer length to 1 */ + ATAPI_SET_XFER_LEN(base, 1); + + /* Program the ATA_DEV_ADDR register with address of the + * ATA_REG_DATA + */ + ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA); + + /* Program the ATA_CTRL register with dir set to read (0) and + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + for (i = 0; i < len; i++) { + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (PIO_DONE interrupt is set and it doesn't seem to matter + * that we don't clear it) + */ + wait_complete(base, PIO_DONE_INT); + + /* Read the ATA_DEV_RXBUF register with write data (to be + * written into the device). + */ + buf[i] = ATAPI_GET_DEV_RXBUF(base); + } +} + +/** + * bfin_tf_load - send taskfile registers to host controller + * @ap: Port to which output is sent + * @tf: ATA taskfile register set + * + * Note: Original code is ata_tf_load(). + */ + +static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + write_atapi_register(base, ATA_REG_CTRL, tf->ctl); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr) { + if (tf->flags & ATA_TFLAG_LBA48) { + write_atapi_register(base, ATA_REG_FEATURE, + tf->hob_feature); + write_atapi_register(base, ATA_REG_NSECT, + tf->hob_nsect); + write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal); + write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam); + write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah); + pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X " + "0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } + + write_atapi_register(base, ATA_REG_FEATURE, tf->feature); + write_atapi_register(base, ATA_REG_NSECT, tf->nsect); + write_atapi_register(base, ATA_REG_LBAL, tf->lbal); + write_atapi_register(base, ATA_REG_LBAM, tf->lbam); + write_atapi_register(base, ATA_REG_LBAH, tf->lbah); + pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + write_atapi_register(base, ATA_REG_DEVICE, tf->device); + pr_debug("device 0x%X\n", tf->device); + } + + ata_wait_idle(ap); +} + +/** + * bfin_check_status - Read device status reg & clear interrupt + * @ap: port where the device is + * + * Note: Original code is ata_check_status(). + */ + +static u8 bfin_check_status(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + return read_atapi_register(base, ATA_REG_STATUS); +} + +/** + * bfin_tf_read - input device's ATA taskfile shadow registers + * @ap: Port from which input is read + * @tf: ATA taskfile register set for storing input + * + * Note: Original code is ata_tf_read(). + */ + +static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + tf->command = bfin_check_status(ap); + tf->feature = read_atapi_register(base, ATA_REG_ERR); + tf->nsect = read_atapi_register(base, ATA_REG_NSECT); + tf->lbal = read_atapi_register(base, ATA_REG_LBAL); + tf->lbam = read_atapi_register(base, ATA_REG_LBAM); + tf->lbah = read_atapi_register(base, ATA_REG_LBAH); + tf->device = read_atapi_register(base, ATA_REG_DEVICE); + + if (tf->flags & ATA_TFLAG_LBA48) { + write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB); + tf->hob_feature = read_atapi_register(base, ATA_REG_ERR); + tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT); + tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL); + tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM); + tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH); + } +} + +/** + * bfin_exec_command - issue ATA command to host controller + * @ap: port to which command is being issued + * @tf: ATA taskfile register set + * + * Note: Original code is ata_exec_command(). + */ + +static void bfin_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command); + + write_atapi_register(base, ATA_REG_CMD, tf->command); + ata_pause(ap); +} + +/** + * bfin_check_altstatus - Read device alternate status reg + * @ap: port where the device is + */ + +static u8 bfin_check_altstatus(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + return read_atapi_register(base, ATA_REG_ALTSTATUS); +} + +/** + * bfin_std_dev_select - Select device 0/1 on ATA bus + * @ap: ATA channel to manipulate + * @device: ATA device (numbered from zero) to select + * + * Note: Original code is ata_std_dev_select(). + */ + +static void bfin_std_dev_select(struct ata_port *ap, unsigned int device) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 tmp; + + if (device == 0) + tmp = ATA_DEVICE_OBS; + else + tmp = ATA_DEVICE_OBS | ATA_DEV1; + + write_atapi_register(base, ATA_REG_DEVICE, tmp); + ata_pause(ap); +} + +/** + * bfin_bmdma_setup - Set up IDE DMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_setup(). + */ + +static void bfin_bmdma_setup(struct ata_queued_cmd *qc) +{ + unsigned short config = WDSIZE_16; + struct scatterlist *sg; + + pr_debug("in atapi dma setup\n"); + /* Program the ATA_CTRL register with dir */ + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* fill the ATAPI DMA controller */ + set_dma_config(CH_ATAPI_TX, config); + set_dma_x_modify(CH_ATAPI_TX, 2); + ata_for_each_sg(sg, qc) { + set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg)); + set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1); + } + } else { + config |= WNR; + /* fill the ATAPI DMA controller */ + set_dma_config(CH_ATAPI_RX, config); + set_dma_x_modify(CH_ATAPI_RX, 2); + ata_for_each_sg(sg, qc) { + set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg)); + set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1); + } + } +} + +/** + * bfin_bmdma_start - Start an IDE DMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_start(). + */ + +static void bfin_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + struct scatterlist *sg; + + pr_debug("in atapi dma start\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return; + + /* start ATAPI DMA controller*/ + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* + * On blackfin arch, uncacheable memory is not + * allocated with flag GFP_DMA. DMA buffer from + * common kenel code should be flushed if WB + * data cache is enabled. Otherwise, this loop + * is an empty loop and optimized out. + */ + ata_for_each_sg(sg, qc) { + flush_dcache_range(sg_dma_address(sg), + sg_dma_address(sg) + sg_dma_len(sg)); + } + enable_dma(CH_ATAPI_TX); + pr_debug("enable udma write\n"); + + /* Send ATA DMA write command */ + bfin_exec_command(ap, &qc->tf); + + /* set ATA DMA write direction */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) + | XFER_DIR)); + } else { + enable_dma(CH_ATAPI_RX); + pr_debug("enable udma read\n"); + + /* Send ATA DMA read command */ + bfin_exec_command(ap, &qc->tf); + + /* set ATA DMA read direction */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) + & ~XFER_DIR)); + } + + /* Reset all transfer count */ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST); + + /* Set transfer length to buffer len */ + ata_for_each_sg(sg, qc) { + ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1)); + } + + /* Enable ATA DMA operation*/ + if (ap->udma_mask) + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) + | ULTRA_START); + else + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) + | MULTI_START); +} + +/** + * bfin_bmdma_stop - Stop IDE DMA transfer + * @qc: Command we are ending DMA for + */ + +static void bfin_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg; + + pr_debug("in atapi dma stop\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return; + + /* stop ATAPI DMA controller*/ + if (qc->tf.flags & ATA_TFLAG_WRITE) + disable_dma(CH_ATAPI_TX); + else { + disable_dma(CH_ATAPI_RX); + if (ap->hsm_task_state & HSM_ST_LAST) { + /* + * On blackfin arch, uncacheable memory is not + * allocated with flag GFP_DMA. DMA buffer from + * common kenel code should be invalidated if + * data cache is enabled. Otherwise, this loop + * is an empty loop and optimized out. + */ + ata_for_each_sg(sg, qc) { + invalidate_dcache_range( + sg_dma_address(sg), + sg_dma_address(sg) + + sg_dma_len(sg)); + } + } + } +} + +/** + * bfin_devchk - PATA device presence detection + * @ap: ATA channel to examine + * @device: Device to examine (starting at zero) + * + * Note: Original code is ata_devchk(). + */ + +static unsigned int bfin_devchk(struct ata_port *ap, + unsigned int device) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 nsect, lbal; + + bfin_std_dev_select(ap, device); + + write_atapi_register(base, ATA_REG_NSECT, 0x55); + write_atapi_register(base, ATA_REG_LBAL, 0xaa); + + write_atapi_register(base, ATA_REG_NSECT, 0xaa); + write_atapi_register(base, ATA_REG_LBAL, 0x55); + + write_atapi_register(base, ATA_REG_NSECT, 0x55); + write_atapi_register(base, ATA_REG_LBAL, 0xaa); + + nsect = read_atapi_register(base, ATA_REG_NSECT); + lbal = read_atapi_register(base, ATA_REG_LBAL); + + if ((nsect == 0x55) && (lbal == 0xaa)) + return 1; /* we found a device */ + + return 0; /* nothing found */ +} + +/** + * bfin_bus_post_reset - PATA device post reset + * + * Note: Original code is ata_bus_post_reset(). + */ + +static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int dev0 = devmask & (1 << 0); + unsigned int dev1 = devmask & (1 << 1); + unsigned long timeout; + + /* if device 0 was found in ata_devchk, wait for its + * BSY bit to clear + */ + if (dev0) + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + /* if device 1 was found in ata_devchk, wait for + * register access, then wait for BSY to clear + */ + timeout = jiffies + ATA_TMOUT_BOOT; + while (dev1) { + u8 nsect, lbal; + + bfin_std_dev_select(ap, 1); + nsect = read_atapi_register(base, ATA_REG_NSECT); + lbal = read_atapi_register(base, ATA_REG_LBAL); + if ((nsect == 1) && (lbal == 1)) + break; + if (time_after(jiffies, timeout)) { + dev1 = 0; + break; + } + msleep(50); /* give drive a breather */ + } + if (dev1) + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + /* is all this really necessary? */ + bfin_std_dev_select(ap, 0); + if (dev1) + bfin_std_dev_select(ap, 1); + if (dev0) + bfin_std_dev_select(ap, 0); +} + +/** + * bfin_bus_softreset - PATA device software reset + * + * Note: Original code is ata_bus_softreset(). + */ + +static unsigned int bfin_bus_softreset(struct ata_port *ap, + unsigned int devmask) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* software reset. causes dev0 to be selected */ + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + udelay(20); + write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST); + udelay(20); + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + + /* spec mandates ">= 2ms" before checking status. + * We wait 150ms, because that was the magic delay used for + * ATAPI devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + * + * Old drivers/ide uses the 2mS rule and then waits for ready + */ + msleep(150); + + /* Before we perform post reset processing we want to see if + * the bus shows 0xFF because the odd clown forgets the D7 + * pulldown resistor. + */ + if (bfin_check_status(ap) == 0xFF) + return 0; + + bfin_bus_post_reset(ap, devmask); + + return 0; +} + +/** + * bfin_std_softreset - reset host port via ATA SRST + * @ap: port to reset + * @classes: resulting classes of attached devices + * + * Note: Original code is ata_std_softreset(). + */ + +static int bfin_std_softreset(struct ata_port *ap, unsigned int *classes, + unsigned long deadline) +{ + unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; + unsigned int devmask = 0, err_mask; + u8 err; + + if (ata_port_offline(ap)) { + classes[0] = ATA_DEV_NONE; + goto out; + } + + /* determine if device 0/1 are present */ + if (bfin_devchk(ap, 0)) + devmask |= (1 << 0); + if (slave_possible && bfin_devchk(ap, 1)) + devmask |= (1 << 1); + + /* select device 0 again */ + bfin_std_dev_select(ap, 0); + + /* issue bus reset */ + err_mask = bfin_bus_softreset(ap, devmask); + if (err_mask) { + ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", + err_mask); + return -EIO; + } + + /* determine by signature whether we have ATA or ATAPI devices */ + classes[0] = ata_dev_try_classify(ap, 0, &err); + if (slave_possible && err != 0x81) + classes[1] = ata_dev_try_classify(ap, 1, &err); + + out: + return 0; +} + +/** + * bfin_bmdma_status - Read IDE DMA status + * @ap: Port associated with this ATA transaction. + */ + +static unsigned char bfin_bmdma_status(struct ata_port *ap) +{ + unsigned char host_stat = 0; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned short int_status = ATAPI_GET_INT_STATUS(base); + + if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) { + host_stat = ATA_DMA_ACTIVE; + } + if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) { + host_stat = ATA_DMA_INTR; + } + if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) { + host_stat = ATA_DMA_ERR; + } + + return host_stat; +} + +/** + * bfin_data_xfer - Transfer data by PIO + * @adev: device for this I/O + * @buf: data buffer + * @buflen: buffer length + * @write_data: read/write + * + * Note: Original code is ata_data_xfer(). + */ + +static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) +{ + struct ata_port *ap = adev->ap; + unsigned int words = buflen >> 1; + unsigned short *buf16 = (u16 *) buf; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* Transfer multiple of 2 bytes */ + if (write_data) { + write_atapi_data(base, words, buf16); + } else { + read_atapi_data(base, words, buf16); + } + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + unsigned short align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (write_data) { + memcpy(align_buf, trailing_buf, 1); + write_atapi_data(base, 1, align_buf); + } else { + read_atapi_data(base, 1, align_buf); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +/** + * bfin_irq_clear - Clear ATAPI interrupt. + * @ap: Port associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_irq_clear(). + */ + +static void bfin_irq_clear(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + pr_debug("in atapi irq clear\n"); + ATAPI_SET_INT_STATUS(base, 0x1FF); +} + +/** + * bfin_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Note: Original code is ata_irq_on(). + */ + +static unsigned char bfin_irq_on(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 tmp; + + pr_debug("in atapi irq on\n"); + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + tmp = ata_wait_idle(ap); + + bfin_irq_clear(ap); + + return tmp; +} + +/** + * bfin_irq_ack - Acknowledge a device interrupt. + * @ap: Port on which interrupts are enabled. + * + * Note: Original code is ata_irq_ack(). + */ + +static unsigned char bfin_irq_ack(struct ata_port *ap, unsigned int chk_drq) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; + unsigned char status; + + pr_debug("in atapi irq ack\n"); + status = ata_busy_wait(ap, bits, 1000); + if (status & bits) + if (ata_msg_err(ap)) + dev_err(ap->dev, "abnormal status 0x%X\n", status); + + /* get controller status; clear intr, err bits */ + ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT + | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT + | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT); + + return bfin_bmdma_status(ap); +} + +/** + * bfin_bmdma_freeze - Freeze DMA controller port + * @ap: port to freeze + * + * Note: Original code is ata_bmdma_freeze(). + */ + +static void bfin_bmdma_freeze(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + pr_debug("in atapi dma freeze\n"); + ap->ctl |= ATA_NIEN; + ap->last_ctl = ap->ctl; + + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + + /* Under certain circumstances, some controllers raise IRQ on + * ATA_NIEN manipulation. Also, many controllers fail to mask + * previously pending IRQ on ATA_NIEN assertion. Clear it. + */ + ata_chk_status(ap); + + bfin_irq_clear(ap); +} + +/** + * bfin_bmdma_thaw - Thaw DMA controller port + * @ap: port to thaw + * + * Note: Original code is ata_bmdma_thaw(). + */ + +void bfin_bmdma_thaw(struct ata_port *ap) +{ + bfin_check_status(ap); + bfin_irq_clear(ap); + bfin_irq_on(ap); +} + +/** + * bfin_std_postreset - standard postreset callback + * @ap: the target ata_port + * @classes: classes of attached devices + * + * Note: Original code is ata_std_postreset(). + */ + +static void bfin_std_postreset(struct ata_port *ap, unsigned int *classes) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* re-enable interrupts */ + bfin_irq_on(ap); + + /* is double-select really necessary? */ + if (classes[0] != ATA_DEV_NONE) + bfin_std_dev_select(ap, 1); + if (classes[1] != ATA_DEV_NONE) + bfin_std_dev_select(ap, 0); + + /* bail out if no device is present */ + if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { + return; + } + + /* set up device control */ + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); +} + +/** + * bfin_error_handler - Stock error handler for DMA controller + * @ap: port to handle error for + */ + +static void bfin_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL, + bfin_std_postreset); +} + +static void bfin_port_stop(struct ata_port *ap) +{ + pr_debug("in atapi port stop\n"); + if (ap->udma_mask != 0 || ap->mwdma_mask != 0) { + free_dma(CH_ATAPI_RX); + free_dma(CH_ATAPI_TX); + } +} + +static int bfin_port_start(struct ata_port *ap) +{ + pr_debug("in atapi port start\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return 0; + + if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) { + if (request_dma(CH_ATAPI_TX, + "BFIN ATAPI TX DMA") >= 0) + return 0; + + free_dma(CH_ATAPI_RX); + } + + ap->udma_mask = 0; + ap->mwdma_mask = 0; + dev_err(ap->dev, "Unable to request ATAPI DMA!" + " Continue in PIO mode.\n"); + + return 0; +} + +static struct scsi_host_template bfin_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = SG_NONE, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, +#endif +}; + +static const struct ata_port_operations bfin_pata_ops = { + .port_disable = ata_port_disable, + .set_piomode = bfin_set_piomode, + .set_dmamode = bfin_set_dmamode, + + .tf_load = bfin_tf_load, + .tf_read = bfin_tf_read, + .exec_command = bfin_exec_command, + .check_status = bfin_check_status, + .check_altstatus = bfin_check_altstatus, + .dev_select = bfin_std_dev_select, + + .bmdma_setup = bfin_bmdma_setup, + .bmdma_start = bfin_bmdma_start, + .bmdma_stop = bfin_bmdma_stop, + .bmdma_status = bfin_bmdma_status, + .data_xfer = bfin_data_xfer, + + .qc_prep = ata_noop_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = bfin_bmdma_freeze, + .thaw = bfin_bmdma_thaw, + .error_handler = bfin_error_handler, + .post_internal_cmd = bfin_bmdma_stop, + + .irq_handler = ata_interrupt, + .irq_clear = bfin_irq_clear, + .irq_on = bfin_irq_on, + .irq_ack = bfin_irq_ack, + + .port_start = bfin_port_start, + .port_stop = bfin_port_stop, +}; + +static struct ata_port_info bfin_port_info[] = { + { + .sht = &bfin_sht, + .flags = ATA_FLAG_SLAVE_POSS + | ATA_FLAG_MMIO + | ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0, +#ifdef CONFIG_PATA_BF54X_DMA + .udma_mask = ATA_UDMA5, +#else + .udma_mask = 0, +#endif + .port_ops = &bfin_pata_ops, + }, +}; + +/** + * bfin_reset_controller - initialize BF54x ATAPI controller. + */ + +static int bfin_reset_controller(struct ata_host *host) +{ + void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr; + int count; + unsigned short status; + + /* Disable all ATAPI interrupts */ + ATAPI_SET_INT_MASK(base, 0); + SSYNC(); + + /* Assert the RESET signal 25us*/ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST); + udelay(30); + + /* Negate the RESET signal for 2ms*/ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST); + msleep(2); + + /* Wait on Busy flag to clear */ + count = 10000000; + do { + status = read_atapi_register(base, ATA_REG_STATUS); + } while (count-- && (status & ATA_BUSY)); + + /* Enable only ATAPI Device interrupt */ + ATAPI_SET_INT_MASK(base, 1); + SSYNC(); + + return (!count); +} + +/** + * atapi_io_port - define atapi peripheral port pins. + */ +static unsigned short atapi_io_port[] = { + P_ATAPI_RESET, + P_ATAPI_DIOR, + P_ATAPI_DIOW, + P_ATAPI_CS0, + P_ATAPI_CS1, + P_ATAPI_DMACK, + P_ATAPI_DMARQ, + P_ATAPI_INTRQ, + P_ATAPI_IORDY, + 0 +}; + +/** + * bfin_atapi_probe - attach a bfin atapi interface + * @pdev: platform device + * + * Register a bfin atapi interface. + * + * + * Platform devices are expected to contain 2 resources per port: + * + * - I/O Base (IORESOURCE_IO) + * - IRQ (IORESOURCE_IRQ) + * + */ +static int __devinit bfin_atapi_probe(struct platform_device *pdev) +{ + int board_idx = 0; + struct resource *res; + struct ata_host *host; + const struct ata_port_info *ppi[] = + { &bfin_port_info[board_idx], NULL }; + + /* + * Simple resource validation .. + */ + if (unlikely(pdev->num_resources != 2)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + /* + * Get the register base first + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -EINVAL; + + /* + * Now that that's out of the way, wire up the port.. + */ + host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1); + if (!host) + return -ENOMEM; + + host->ports[0]->ioaddr.ctl_addr = (void *)res->start; + + if (peripheral_request_list(atapi_io_port, "atapi-io-port")) { + dev_err(&pdev->dev, "Requesting Peripherals faild\n"); + return -EFAULT; + } + + if (bfin_reset_controller(host)) { + peripheral_free_list(atapi_io_port); + dev_err(&pdev->dev, "Fail to reset ATAPI device\n"); + return -EFAULT; + } + + if (ata_host_activate(host, platform_get_irq(pdev, 0), + ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { + peripheral_free_list(atapi_io_port); + dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); + return -ENODEV; + } + + return 0; +} + +/** + * bfin_atapi_remove - unplug a bfin atapi interface + * @pdev: platform device + * + * A bfin atapi device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit bfin_atapi_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_detach(host); + + peripheral_free_list(atapi_io_port); + + return 0; +} + +#ifdef CONFIG_PM +int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +int bfin_atapi_resume(struct platform_device *pdev) +{ + return 0; +} +#endif + +static struct platform_driver bfin_atapi_driver = { + .probe = bfin_atapi_probe, + .remove = __devexit_p(bfin_atapi_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .suspend = bfin_atapi_suspend, + .resume = bfin_atapi_resume, +#endif + }, +}; + +static int __init bfin_atapi_init(void) +{ + pr_info("register bfin atapi driver\n"); + return platform_driver_register(&bfin_atapi_driver); +} + +static void __exit bfin_atapi_exit(void) +{ + platform_driver_unregister(&bfin_atapi_driver); +} + +module_init(bfin_atapi_init); +module_exit(bfin_atapi_exit); + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); From 7c9ef8e418374aec0a62e64d9b40d457634fd039 Mon Sep 17 00:00:00 2001 From: Kristoffer Nyborg Gregertsen Date: Wed, 8 Aug 2007 16:57:08 +0200 Subject: [PATCH 2426/2804] AVR32 PATA driver Updated and simplified driver. Use only register transfer timing for both data and register transfers. This gives poorer performance in PIO1 and 2, but should not be a problem in PIO3 and 4, correct me if I'm wrong :) The driver works very we'll but I still wonder about the interrupts. I have an interrupt line, that works nicely when POLLING flag is not set. The problem is the number of interrupts that eat away my CPU cycles. When using the POLLING flag there seem to be some interrupts that dosen't get cleared. Furthermore the device dosen't drive INTRQ high, it stays at 2.5 volts and generates a lot of interrupts due to ripple / noise. What to do? Signed-off-by: Kristoffer Nyborg Gregertsen Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 + drivers/ata/Makefile | 1 + drivers/ata/pata_at32.c | 441 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 451 insertions(+) create mode 100644 drivers/ata/pata_at32.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index a427945f0bb1..2cd0e7476718 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -199,6 +199,15 @@ config PATA_ARTOP If unsure, say N. +config PATA_AT32 + tristate "Atmel AVR32 PATA support (Experimental)" + depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL + help + This option enables support for the IDE devices on the + Atmel AT32AP platform. + + If unsure, say N. + config PATA_ATIIXP tristate "ATI PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index c2ecba5f0b47..4eb7fb44be3f 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o obj-$(CONFIG_PATA_ALI) += pata_ali.o obj-$(CONFIG_PATA_AMD) += pata_amd.o obj-$(CONFIG_PATA_ARTOP) += pata_artop.o +obj-$(CONFIG_PATA_AT32) += pata_at32.o obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c new file mode 100644 index 000000000000..bb250a48e27c --- /dev/null +++ b/drivers/ata/pata_at32.c @@ -0,0 +1,441 @@ +/* + * AVR32 SMC/CFC PATA Driver + * + * Copyright (C) 2007 Atmel Norway + * + * 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. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata_at32" +#define DRV_VERSION "0.0.2" + +/* + * CompactFlash controller memory layout relative to the base address: + * + * Attribute memory: 0000 0000 -> 003f ffff + * Common memory: 0040 0000 -> 007f ffff + * I/O memory: 0080 0000 -> 00bf ffff + * True IDE Mode: 00c0 0000 -> 00df ffff + * Alt IDE Mode: 00e0 0000 -> 00ff ffff + * + * Only True IDE and Alt True IDE mode are needed for this driver. + * + * True IDE mode => CS0 = 0, CS1 = 1 (cmd, error, stat, etc) + * Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat) + */ +#define CF_IDE_OFFSET 0x00c00000 +#define CF_ALT_IDE_OFFSET 0x00e00000 +#define CF_RES_SIZE 2048 + +/* + * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA + * adaptor with a logic analyzer or similar. + */ +#undef DEBUG_BUS + +/* + * ATA PIO modes + * + * Name | Mb/s | Min cycle time | Mask + * --------+-------+----------------+-------- + * Mode 0 | 3.3 | 600 ns | 0x01 + * Mode 1 | 5.2 | 383 ns | 0x03 + * Mode 2 | 8.3 | 240 ns | 0x07 + * Mode 3 | 11.1 | 180 ns | 0x0f + * Mode 4 | 16.7 | 120 ns | 0x1f + */ +#define PIO_MASK (0x1f) + +/* + * Struct containing private information about device. + */ +struct at32_ide_info { + unsigned int irq; + struct resource res_ide; + struct resource res_alt; + void __iomem *ide_addr; + void __iomem *alt_addr; + unsigned int cs; + struct smc_config smc; +}; + +/* + * Setup SMC for the given ATA timing. + */ +static int pata_at32_setup_timing(struct device *dev, + struct at32_ide_info *info, + const struct ata_timing *timing) +{ + /* These two values are found through testing */ + const int min_recover = 25; + const int ncs_hold = 15; + + struct smc_config *smc = &info->smc; + + int active; + int recover; + + /* Total cycle time */ + smc->read_cycle = timing->cyc8b; + + /* DIOR <= CFIOR timings */ + smc->nrd_setup = timing->setup; + smc->nrd_pulse = timing->act8b; + + /* Compute recover, extend total cycle if needed */ + active = smc->nrd_setup + smc->nrd_pulse; + recover = smc->read_cycle - active; + + if (recover < min_recover) { + smc->read_cycle = active + min_recover; + recover = min_recover; + } + + /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ + smc->ncs_read_setup = 0; + smc->ncs_read_pulse = active + ncs_hold; + + /* Write timings same as read timings */ + smc->write_cycle = smc->read_cycle; + smc->nwe_setup = smc->nrd_setup; + smc->nwe_pulse = smc->nrd_pulse; + smc->ncs_write_setup = smc->ncs_read_setup; + smc->ncs_write_pulse = smc->ncs_read_pulse; + + /* Do some debugging output */ + dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n", + smc->read_cycle, smc->nrd_setup, smc->nrd_pulse, + recover, smc->ncs_read_setup, smc->ncs_read_pulse, + smc->read_cycle - smc->ncs_read_pulse); + + /* Finally, configure the SMC */ + return smc_set_configuration(info->cs, smc); +} + +/* + * Procedures for libATA. + */ +static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing timing; + struct at32_ide_info *info = ap->host->private_data; + + int ret; + + /* Compute ATA timing */ + ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0); + if (ret) { + dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret); + return; + } + + /* Setup SMC to ATA timing */ + ret = pata_at32_setup_timing(ap->dev, info, &timing); + if (ret) { + dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret); + return; + } +} + +static void pata_at32_irq_clear(struct ata_port *ap) +{ + /* No DMA controller yet */ +} + +static struct scsi_host_template at32_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations at32_port_ops = { + .port_disable = ata_port_disable, + .set_piomode = pata_at32_set_piomode, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_data_xfer, + + .irq_clear = pata_at32_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + + .port_start = ata_sff_port_start, +}; + +static int __init pata_at32_init_one(struct device *dev, + struct at32_ide_info *info) +{ + struct ata_host *host; + struct ata_port *ap; + + host = ata_host_alloc(dev, 1); + if (!host) + return -ENOMEM; + + ap = host->ports[0]; + + /* Setup ATA bindings */ + ap->ops = &at32_port_ops; + ap->pio_mask = PIO_MASK; + ap->flags = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS + | ATA_FLAG_PIO_POLLING; + + /* + * Since all 8-bit taskfile transfers has to go on the lower + * byte of the data bus and there is a bug in the SMC that + * makes it impossible to alter the bus width during runtime, + * we need to hardwire the address signals as follows: + * + * A_IDE(2:0) <= A_EBI(3:1) + * + * This makes all addresses on the EBI even, thus all data + * will be on the lower byte of the data bus. All addresses + * used by libATA need to be altered according to this. + */ + ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1); + ap->ioaddr.ctl_addr = info->alt_addr + (0x06 << 1); + + ap->ioaddr.data_addr = info->ide_addr + (ATA_REG_DATA << 1); + ap->ioaddr.error_addr = info->ide_addr + (ATA_REG_ERR << 1); + ap->ioaddr.feature_addr = info->ide_addr + (ATA_REG_FEATURE << 1); + ap->ioaddr.nsect_addr = info->ide_addr + (ATA_REG_NSECT << 1); + ap->ioaddr.lbal_addr = info->ide_addr + (ATA_REG_LBAL << 1); + ap->ioaddr.lbam_addr = info->ide_addr + (ATA_REG_LBAM << 1); + ap->ioaddr.lbah_addr = info->ide_addr + (ATA_REG_LBAH << 1); + ap->ioaddr.device_addr = info->ide_addr + (ATA_REG_DEVICE << 1); + ap->ioaddr.status_addr = info->ide_addr + (ATA_REG_STATUS << 1); + ap->ioaddr.command_addr = info->ide_addr + (ATA_REG_CMD << 1); + + /* Set info as private data of ATA host */ + host->private_data = info; + + /* Register ATA device and return */ + return ata_host_activate(host, info->irq, ata_interrupt, + IRQF_SHARED | IRQF_TRIGGER_RISING, + &at32_sht); +} + +/* + * This function may come in handy for people analyzing their own + * EBI -> PATA adaptors. + */ +#ifdef DEBUG_BUS + +static void __init pata_at32_debug_bus(struct device *dev, + struct at32_ide_info *info) +{ + const int d1 = 0xff; + const int d2 = 0x00; + + int i; + + /* Write 8-bit values (registers) */ + iowrite8(d1, info->alt_addr + (0x06 << 1)); + iowrite8(d2, info->alt_addr + (0x06 << 1)); + + for (i = 0; i < 8; i++) { + iowrite8(d1, info->ide_addr + (i << 1)); + iowrite8(d2, info->ide_addr + (i << 1)); + } + + /* Write 16 bit values (data) */ + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); + + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); +} + +#endif + +static int __init pata_at32_probe(struct platform_device *pdev) +{ + const struct ata_timing initial_timing = + {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; + + struct device *dev = &pdev->dev; + struct at32_ide_info *info; + struct ide_platform_data *board = pdev->dev.platform_data; + struct resource *res; + + int irq; + int ret; + + if (!board) + return -ENXIO; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + /* Retrive IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + /* Setup struct containing private infomation */ + info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct at32_ide_info)); + + info->irq = irq; + info->cs = board->cs; + + /* Request memory resources */ + info->res_ide.start = res->start + CF_IDE_OFFSET; + info->res_ide.end = info->res_ide.start + CF_RES_SIZE - 1; + info->res_ide.name = "ide"; + info->res_ide.flags = IORESOURCE_MEM; + + ret = request_resource(res, &info->res_ide); + if (ret) + goto err_req_res_ide; + + info->res_alt.start = res->start + CF_ALT_IDE_OFFSET; + info->res_alt.end = info->res_alt.start + CF_RES_SIZE - 1; + info->res_alt.name = "alt"; + info->res_alt.flags = IORESOURCE_MEM; + + ret = request_resource(res, &info->res_alt); + if (ret) + goto err_req_res_alt; + + /* Setup non-timing elements of SMC */ + info->smc.bus_width = 2; /* 16 bit data bus */ + info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */ + info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */ + info->smc.nwait_mode = 3; /* NWAIT is in READY mode */ + info->smc.byte_write = 0; /* Byte select access type */ + info->smc.tdf_mode = 0; /* TDF optimization disabled */ + info->smc.tdf_cycles = 0; /* No TDF wait cycles */ + + /* Setup ATA timing */ + ret = pata_at32_setup_timing(dev, info, &initial_timing); + if (ret) + goto err_setup_timing; + + /* Setup ATA addresses */ + ret = -ENOMEM; + info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16); + info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16); + if (!info->ide_addr || !info->alt_addr) + goto err_ioremap; + +#ifdef DEBUG_BUS + pata_at32_debug_bus(dev, info); +#endif + + /* Register ATA device */ + ret = pata_at32_init_one(dev, info); + if (ret) + goto err_ata_device; + + return 0; + + err_ata_device: + err_ioremap: + err_setup_timing: + release_resource(&info->res_alt); + err_req_res_alt: + release_resource(&info->res_ide); + err_req_res_ide: + kfree(info); + + return ret; +} + +static int __exit pata_at32_remove(struct platform_device *pdev) +{ + struct ata_host *host = platform_get_drvdata(pdev); + struct at32_ide_info *info; + + if (!host) + return 0; + + info = host->private_data; + ata_host_detach(host); + + if (!info) + return 0; + + release_resource(&info->res_ide); + release_resource(&info->res_alt); + + kfree(info); + + return 0; +} + +static struct platform_driver pata_at32_driver = { + .remove = __exit_p(pata_at32_remove), + .driver = { + .name = "at32_ide", + .owner = THIS_MODULE, + }, +}; + +static int __init pata_at32_init(void) +{ + return platform_driver_probe(&pata_at32_driver, pata_at32_probe); +} + +static void __exit pata_at32_exit(void) +{ + platform_driver_unregister(&pata_at32_driver); +} + +module_init(pata_at32_init); +module_exit(pata_at32_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver"); +MODULE_AUTHOR("Kristoffer Nyborg Gregertsen "); +MODULE_VERSION(DRV_VERSION); From ec300d99ef8699a6f383889b8f8c0d0ebadc2a74 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 1 Sep 2007 07:17:36 -0400 Subject: [PATCH 2427/2804] [libata] ata_piix: Use more-robust form of array initialization Use a form of array init that is less fragile, less sensitive to trivial typos and ordering mismatches. Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 45e3b60f26d0..7adb2aa009aa 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -123,7 +123,6 @@ enum { ich_pata_33 = 1, /* ICH up to UDMA 33 only */ ich_pata_66 = 2, /* ICH up to 66 Mhz */ ich_pata_100 = 3, /* ICH up to UDMA 100 */ - /* ICH up to UDMA 133 is not supported */ ich5_sata = 5, ich6_sata = 6, ich6_sata_ahci = 7, @@ -459,7 +458,7 @@ static const struct piix_map_db *piix_map_db_table[] = { }; static struct ata_port_info piix_port_info[] = { - /* piix_pata_33: 0: PIIX4 at 33MHz */ + [piix_pata_33] = /* PIIX4 at 33MHz */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -469,7 +468,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_pata_ops, }, - /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/ + [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -478,7 +477,8 @@ static struct ata_port_info piix_port_info[] = { .udma_mask = ATA_UDMA2, /* UDMA33 */ .port_ops = &ich_pata_ops, }, - /* ich_pata_66: 2 ICH controllers up to 66MHz */ + + [ich_pata_66] = /* ICH controllers up to 66MHz */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -488,7 +488,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &ich_pata_ops, }, - /* ich_pata_100: 3 */ + [ich_pata_100] = { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, @@ -498,17 +498,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &ich_pata_ops, }, - /* ich_pata_133: 4 - Not supported - */ - { - .sht = &piix_sht, - .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x1f, /* pio 0-4 */ - .mwdma_mask = 0x06, /* Check: maybe 0x07 */ - .udma_mask = ATA_UDMA6, /* UDMA133 */ - .port_ops = &ich_pata_ops, - }, - - /* ich5_sata: 5 */ + [ich5_sata] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS, @@ -518,7 +508,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6_sata: 6 */ + [ich6_sata] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, @@ -528,7 +518,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6_sata_ahci: 7 */ + [ich6_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -539,7 +529,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6m_sata_ahci: 8 */ + [ich6m_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -550,7 +540,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich8_sata_ahci: 9 */ + [ich8_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -561,7 +551,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* piix_pata_mwdma: 10: PIIX3 MWDMA only */ + [piix_pata_mwdma] = /* PIIX3 MWDMA only */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -570,7 +560,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_pata_ops, }, - /* tolapai_sata_ahci: 11: */ + [tolapai_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | From 539cc7c70c12fbdad4ee11f901cd7a0d7f52b186 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 20 Sep 2007 16:31:47 -0400 Subject: [PATCH 2428/2804] [libata] blacklist Maxtor*BANC* using new wildcard blacklist matching Support the use of '*' in model_num and model_rev entries in ata_device_blacklist[]. Based largely on David Milburn's "libata-core: support wildcard matching in ata_blacklist_entry" patch. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 84d81b26e384..2b222700d9bb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3814,16 +3814,11 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* http://thread.gmane.org/gmane.linux.ide/14907 */ { "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ }, /* NCQ is broken */ - { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ }, - { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ }, - { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ }, - { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, }, - { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ }, + { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ }, { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI", - ATA_HORKAGE_NONCQ }, - /* NCQ hard hangs device under heavier load, needs hard power cycle */ - { "Maxtor 6B250S0", "BANC1B70", ATA_HORKAGE_NONCQ }, + ATA_HORKAGE_NONCQ }, + /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ { "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, }, @@ -3849,6 +3844,23 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { } }; +int strn_pattern_cmp(const char *patt, const char *name, int wildchar) +{ + const char *p; + int len; + + /* + * check for trailing wildcard: *\0 + */ + p = strchr(patt, wildchar); + if (p && ((*(p + 1)) == 0)) + len = p - patt; + else + len = strlen(name); + + return strncmp(patt, name, len); +} + static unsigned long ata_dev_blacklisted(const struct ata_device *dev) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; @@ -3859,10 +3871,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev) ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); while (ad->model_num) { - if (!strcmp(ad->model_num, model_num)) { + if (!strn_pattern_cmp(ad->model_num, model_num, '*')) { if (ad->model_rev == NULL) return ad->horkage; - if (!strcmp(ad->model_rev, model_rev)) + if (!strn_pattern_cmp(ad->model_rev, model_rev, '*')) return ad->horkage; } ad++; From c645fd34256e8ef4986d3e8acd569890cc421e5d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 20 Sep 2007 14:58:48 +0100 Subject: [PATCH 2429/2804] libata: Update experimental tags to reflect reality better Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 2cd0e7476718..3a737bdce2ec 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -192,8 +192,8 @@ config PATA_AMD If unsure, say N. config PATA_ARTOP - tristate "ARTOP 6210/6260 PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "ARTOP 6210/6260 PATA support" + depends on PCI help This option enables support for ARTOP PATA controllers. @@ -209,8 +209,8 @@ config PATA_AT32 If unsure, say N. config PATA_ATIIXP - tristate "ATI PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "ATI PATA support" + depends on PCI help This option enables support for the ATI ATA interfaces found on the many ATI chipsets. @@ -228,8 +228,8 @@ config PATA_CMD640_PCI If unsure, say N. config PATA_CMD64X - tristate "CMD64x PATA support (Very Experimental)" - depends on PCI&& EXPERIMENTAL + tristate "CMD64x PATA support" + depends on PCI help This option enables support for the CMD64x series chips except for the CMD640. @@ -291,8 +291,8 @@ config ATA_GENERIC If unsure, say N. config PATA_HPT366 - tristate "HPT 366/368 PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "HPT 366/368 PATA support" + depends on PCI help This option enables support for the HPT 366 and 368 PATA controllers via the new ATA layer. From d2a84f47899d1efc24fa610696f7b793692279c7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 20 Sep 2007 15:07:12 +0100 Subject: [PATCH 2430/2804] pdc2027x: Switch properly to ioread/iowrite Some iomap functions were still using readl/writel and friends which happens to work on most platforms but is not correct. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc2027x.c | 56 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index f87c800be7f3..3d3f1558cdee 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -273,7 +273,7 @@ static int pdc2027x_cable_detect(struct ata_port *ap) u32 cgcr; /* check cable detect results */ - cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL)); + cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL)); if (cgcr & (1 << 26)) goto cbl40; @@ -291,7 +291,7 @@ cbl40: */ static inline int pdc2027x_port_enabled(struct ata_port *ap) { - return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02; + return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02; } /** @@ -383,16 +383,16 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev) /* Set the PIO timing registers using value table for 133MHz */ PDPRINTK("Set pio regs... \n"); - ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0)); + ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); ctcr0 &= 0xffff0000; ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 | (pdc2027x_pio_timing_tbl[pio].value1 << 8); - writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); + iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); ctcr1 &= 0x00ffffff; ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24); - writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); PDPRINTK("Set pio regs done\n"); @@ -426,18 +426,18 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) * If tHOLD is '1', the hardware will add half clock for data hold time. * This code segment seems to be no effect. tHOLD will be overwritten below. */ - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); - writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); } PDPRINTK("Set udma regs... \n"); - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); ctcr1 &= 0xff000000; ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 | (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) | (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16); - writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); PDPRINTK("Set udma regs done\n"); @@ -449,13 +449,13 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) unsigned int mdma_mode = dma_mode & 0x07; PDPRINTK("Set mdma regs... \n"); - ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0)); + ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); ctcr0 &= 0x0000ffff; ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) | (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24); - writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); + iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); PDPRINTK("Set mdma regs done\n"); PDPRINTK("Set to mdma mode[%u] \n", mdma_mode); @@ -492,9 +492,9 @@ static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed * Enable prefetch if the device support PIO only. */ if (dev->xfer_shift == ATA_SHIFT_PIO) { - u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1)); + u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1)); ctcr1 |= (1 << 25); - writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1)); PDPRINTK("Turn on prefetch\n"); } else { @@ -559,12 +559,12 @@ static long pdc_read_counter(struct ata_host *host) u32 bccrl, bccrh, bccrlv, bccrhv; retry: - bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; - bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; + bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff; + bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; /* Read the counter values again for verification */ - bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; - bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; + bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff; + bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; counter = (bccrh << 15) | bccrl; @@ -613,7 +613,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b /* Show the current clock value of PLL control register * (maybe already configured by the firmware) */ - pll_ctl = readw(mmio_base + PDC_PLL_CTL); + pll_ctl = ioread16(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -653,8 +653,8 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl); - writew(pll_ctl, mmio_base + PDC_PLL_CTL); - readw(mmio_base + PDC_PLL_CTL); /* flush */ + iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL); + ioread16(mmio_base + PDC_PLL_CTL); /* flush */ /* Wait the PLL circuit to be stable */ mdelay(30); @@ -664,7 +664,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b * Show the current clock value of PLL control register * (maybe configured by the firmware) */ - pll_ctl = readw(mmio_base + PDC_PLL_CTL); + pll_ctl = ioread16(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -687,10 +687,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) long pll_clock, usec_elapsed; /* Start the test mode */ - scr = readl(mmio_base + PDC_SYS_CTL); + scr = ioread32(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); - readl(mmio_base + PDC_SYS_CTL); /* flush */ + iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); + ioread32(mmio_base + PDC_SYS_CTL); /* flush */ /* Read current counter value */ start_count = pdc_read_counter(host); @@ -704,10 +704,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) do_gettimeofday(&end_time); /* Stop the test mode */ - scr = readl(mmio_base + PDC_SYS_CTL); + scr = ioread32(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); - readl(mmio_base + PDC_SYS_CTL); /* flush */ + iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); + ioread32(mmio_base + PDC_SYS_CTL); /* flush */ /* calculate the input clock in Hz */ usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 + From e10b8c3f5f23188e065b1845ba732570eca007fe Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Tue, 18 Sep 2007 17:46:12 +0200 Subject: [PATCH 2431/2804] libata-scsi: Remove !use_sg code paths This is a minimal patch needed to remove use of !use_sg but it is not a complete clean up of the !use_sg paths. Libata-core still has the qc->flags & ATA_QCFLAG_SG and !qc->n_elem code paths. Perhaps an ata maintainer would have a go at it. - TODO: further cleanup of qc->flags & ATA_QCFLAG_SG and !qc->n_elem code paths in libata-core - TODO: Use scsi_dma_{map,unmap} where applicable. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f0f586b56c20..598ef1018e19 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -450,13 +450,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, qc->scsicmd = cmd; qc->scsidone = done; - if (cmd->use_sg) { - qc->__sg = (struct scatterlist *) cmd->request_buffer; - qc->n_elem = cmd->use_sg; - } else if (cmd->request_bufflen) { - qc->__sg = &qc->sgent; - qc->n_elem = 1; - } + qc->__sg = (struct scatterlist *) cmd->request_buffer; + qc->n_elem = cmd->use_sg; } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); done(cmd); @@ -1504,11 +1499,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, goto err_did; } - if (cmd->use_sg) - ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); - else - ata_sg_init_one(qc, cmd->request_buffer, - cmd->request_bufflen); + ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); qc->dma_dir = cmd->sc_data_direction; } @@ -1562,15 +1553,14 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) u8 *buf; unsigned int buflen; - if (cmd->use_sg) { - struct scatterlist *sg; + struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer; - sg = (struct scatterlist *) cmd->request_buffer; + if (sg) { buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; buflen = sg->length; } else { - buf = cmd->request_buffer; - buflen = cmd->request_bufflen; + buf = NULL; + buflen = 0; } *buf_out = buf; @@ -1590,12 +1580,9 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) { - if (cmd->use_sg) { - struct scatterlist *sg; - - sg = (struct scatterlist *) cmd->request_buffer; + struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer; + if (sg) kunmap_atomic(buf - sg->offset, KM_IRQ0); - } } /** From 7120165cf31e989baf7836218ca0a13643074735 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Tue, 18 Sep 2007 17:48:50 +0200 Subject: [PATCH 2432/2804] libata-scsi: convert to use the data buffer accessors simple search-and-replace of direct scsi_cmnd access to use the data buffer accessors. Signed-off-by: Boaz Harrosh Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 598ef1018e19..7ad046b7c356 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -450,8 +450,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, qc->scsicmd = cmd; qc->scsidone = done; - qc->__sg = (struct scatterlist *) cmd->request_buffer; - qc->n_elem = cmd->use_sg; + qc->__sg = scsi_sglist(cmd); + qc->n_elem = scsi_sg_count(cmd); } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); done(cmd); @@ -1493,13 +1493,13 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, /* data is present; dma-map it */ if (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_TO_DEVICE) { - if (unlikely(cmd->request_bufflen < 1)) { + if (unlikely(scsi_bufflen(cmd) < 1)) { ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len r/w req\n"); goto err_did; } - ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); + ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd)); qc->dma_dir = cmd->sc_data_direction; } @@ -1553,7 +1553,7 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) u8 *buf; unsigned int buflen; - struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer; + struct scatterlist *sg = scsi_sglist(cmd); if (sg) { buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; @@ -1580,7 +1580,7 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) { - struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer; + struct scatterlist *sg = scsi_sglist(cmd); if (sg) kunmap_atomic(buf - sg->offset, KM_IRQ0); } @@ -2383,7 +2383,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) } qc->tf.command = ATA_CMD_PACKET; - qc->nbytes = scmd->request_bufflen; + qc->nbytes = scsi_bufflen(scmd); /* check whether ATAPI DMA is safe */ if (!using_pio && ata_check_atapi_dma(qc)) @@ -2633,7 +2633,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) case ATA_CMD_WRITE_LONG_ONCE: if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) goto invalid_fld; - qc->sect_size = scmd->request_bufflen; + qc->sect_size = scsi_bufflen(scmd); } /* @@ -2663,7 +2663,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * TODO: find out if we need to do more here to * cover scatter/gather case. */ - qc->nbytes = scmd->request_bufflen; + qc->nbytes = scsi_bufflen(scmd); /* request result TF */ qc->flags |= ATA_QCFLAG_RESULT_TF; From e2d352af6d8f1734394bc1bcf0afe345cc3ef235 Mon Sep 17 00:00:00 2001 From: Jason Gaston Date: Fri, 7 Sep 2007 17:21:03 -0700 Subject: [PATCH 2433/2804] ata_piix: replace spaces with tabs This patch removes some incorrect formatting spaces and replaces them with tabs. Signed-off-by: Jason Gaston Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 7adb2aa009aa..8dc15a6cea72 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -437,15 +437,15 @@ static const struct piix_map_db ich8_map_db = { }; static const struct piix_map_db tolapai_map_db = { - .mask = 0x3, - .port_enable = 0x3, - .map = { - /* PM PS SM SS MAP */ - { P0, NA, P1, NA }, /* 00b */ - { RV, RV, RV, RV }, /* 01b */ - { RV, RV, RV, RV }, /* 10b */ - { RV, RV, RV, RV }, - }, + .mask = 0x3, + .port_enable = 0x3, + .map = { + /* PM PS SM SS MAP */ + { P0, NA, P1, NA }, /* 00b */ + { RV, RV, RV, RV }, /* 01b */ + { RV, RV, RV, RV }, /* 10b */ + { RV, RV, RV, RV }, + }, }; static const struct piix_map_db *piix_map_db_table[] = { From 2557164e0b18e78a7772632a2a90832f56181fc5 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 11 Sep 2007 11:41:59 -0700 Subject: [PATCH 2434/2804] ata: increase allowed config flags In anticipation of more features, increase number of config flags allowed, and move the init flags. Signed-off-by: Kristen Carlson Accardi Cc: Hugh Dickens Signed-off-by: Jeff Garzik --- include/linux/libata.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index 74e034ea9016..49da62d0c83b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -140,11 +140,11 @@ enum { ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ ATA_DFLAG_AN = (1 << 7), /* device supports AN */ - ATA_DFLAG_CFG_MASK = (1 << 8) - 1, + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, - ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ - ATA_DFLAG_NCQ_OFF = (1 << 9), /* device limited to non-NCQ mode */ - ATA_DFLAG_SPUNDOWN = (1 << 10), /* XXX: for spindown_compat */ + 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_INIT_MASK = (1 << 16) - 1, ATA_DFLAG_DETACH = (1 << 16), From db6f8759d05d2082f09a45b5674edc0fb5e92b1b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Sep 2007 12:31:58 +0900 Subject: [PATCH 2435/2804] libata: move ata_id_n_sectors() upward Move ata_id_n_sectors() upward right below ata_id_c_string(). This is to accomodate later changes. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2b222700d9bb..b33aea3638dc 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -821,6 +821,21 @@ void ata_id_c_string(const u16 *id, unsigned char *s, *p = '\0'; } +static u64 ata_id_n_sectors(const u16 *id) +{ + if (ata_id_has_lba(id)) { + if (ata_id_has_lba48(id)) + return ata_id_u64(id, 100); + else + return ata_id_u32(id, 60); + } else { + if (ata_id_current_chs_valid(id)) + return ata_id_u32(id, 57); + else + return id[1] * id[3] * id[6]; + } +} + static u64 ata_tf_to_lba48(struct ata_taskfile *tf) { u64 sectors = 0; @@ -1021,21 +1036,6 @@ static u64 ata_hpa_resize(struct ata_device *dev) return sectors; } -static u64 ata_id_n_sectors(const u16 *id) -{ - if (ata_id_has_lba(id)) { - if (ata_id_has_lba48(id)) - return ata_id_u64(id, 100); - else - return ata_id_u32(id, 60); - } else { - if (ata_id_current_chs_valid(id)) - return ata_id_u32(id, 57); - else - return id[1] * id[3] * id[6]; - } -} - /** * ata_id_to_dma_mode - Identify DMA mode from id block * @dev: device to identify From c728a9149f519cbb9f610962873f4e22ed4a6efd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Sep 2007 12:32:30 +0900 Subject: [PATCH 2436/2804] libata: clean up read/set native_max address functions Merge ata_read_native_max_addres_ext() into ata_read_native_max_address() and combine ata_set_native_max_address_ext() and ata_set_native_max_address() into ata_set_max_sectors(). * reduce duplicate code * return 0 or -errno depending on error conditions * report if command fails * use ATA_LBA instead of 0x40 This is in preparation of ata_hpa_resize() update. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 182 +++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 101 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b33aea3638dc..c7614bdc0cb9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -863,129 +863,113 @@ static u64 ata_tf_to_lba(struct ata_taskfile *tf) } /** - * ata_read_native_max_address_ext - LBA48 native max query - * @dev: Device to query + * ata_read_native_max_address - Read native max address + * @dev: target device + * @max_sectors: out parameter for the result native max address * - * Perform an LBA48 size query upon the device in question. Return the - * actual LBA48 size or zero if the command fails. + * Perform an LBA48 or LBA28 native size query upon the device in + * question. + * + * RETURNS: + * 0 on success, -EACCES if command is aborted by the drive. + * -EIO on other errors. */ - -static u64 ata_read_native_max_address_ext(struct ata_device *dev) +static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) { - unsigned int err; + unsigned int err_mask; struct ata_taskfile tf; + int lba48 = ata_id_has_lba48(dev->id); ata_tf_init(dev, &tf); - tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba48(&tf); -} - -/** - * ata_read_native_max_address - LBA28 native max query - * @dev: Device to query - * - * Performa an LBA28 size query upon the device in question. Return the - * actual LBA28 size or zero if the command fails. - */ - -static u64 ata_read_native_max_address(struct ata_device *dev) -{ - unsigned int err; - struct ata_taskfile tf; - - ata_tf_init(dev, &tf); - - tf.command = ATA_CMD_READ_NATIVE_MAX; + /* always clear all address registers */ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + + if (lba48) { + tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; + tf.flags |= ATA_TFLAG_LBA48; + } else + tf.command = ATA_CMD_READ_NATIVE_MAX; + tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; + tf.device |= ATA_LBA; - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + if (err_mask) { + ata_dev_printk(dev, KERN_WARNING, "failed to read native " + "max address (err_mask=0x%x)\n", err_mask); + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + return -EACCES; + return -EIO; + } - return ata_tf_to_lba(&tf); + if (lba48) + *max_sectors = ata_tf_to_lba48(&tf); + else + *max_sectors = ata_tf_to_lba(&tf); + + return 0; } /** - * ata_set_native_max_address_ext - LBA48 native max set - * @dev: Device to query + * ata_set_max_sectors - Set max sectors + * @dev: target device * @new_sectors: new max sectors value to set for the device + * @res_sectors: result max sectors * - * Perform an LBA48 size set max upon the device in question. Return the - * actual LBA48 size or zero if the command fails. + * Set max sectors of @dev to @new_sectors. + * + * RETURNS: + * 0 on success, -EACCES if command is aborted or denied (due to + * previous non-volatile SET_MAX) by the drive. -EIO on other + * errors. */ - -static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors) +static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, + u64 *res_sectors) { - unsigned int err; + unsigned int err_mask; struct ata_taskfile tf; + int lba48 = ata_id_has_lba48(dev->id); new_sectors--; ata_tf_init(dev, &tf); - tf.command = ATA_CMD_SET_MAX_EXT; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - tf.lbal = (new_sectors >> 0) & 0xff; - tf.lbam = (new_sectors >> 8) & 0xff; - tf.lbah = (new_sectors >> 16) & 0xff; - - tf.hob_lbal = (new_sectors >> 24) & 0xff; - tf.hob_lbam = (new_sectors >> 32) & 0xff; - tf.hob_lbah = (new_sectors >> 40) & 0xff; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba48(&tf); -} - -/** - * ata_set_native_max_address - LBA28 native max set - * @dev: Device to query - * @new_sectors: new max sectors value to set for the device - * - * Perform an LBA28 size set max upon the device in question. Return the - * actual LBA28 size or zero if the command fails. - */ - -static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors) -{ - unsigned int err; - struct ata_taskfile tf; - - new_sectors--; - - ata_tf_init(dev, &tf); - - tf.command = ATA_CMD_SET_MAX; tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + + if (lba48) { + tf.command = ATA_CMD_SET_MAX_EXT; + tf.flags |= ATA_TFLAG_LBA48; + + tf.hob_lbal = (new_sectors >> 24) & 0xff; + tf.hob_lbam = (new_sectors >> 32) & 0xff; + tf.hob_lbah = (new_sectors >> 40) & 0xff; + } else + tf.command = ATA_CMD_SET_MAX; + tf.protocol |= ATA_PROT_NODATA; + tf.device |= ATA_LBA; tf.lbal = (new_sectors >> 0) & 0xff; tf.lbam = (new_sectors >> 8) & 0xff; tf.lbah = (new_sectors >> 16) & 0xff; - tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40; - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + if (err_mask) { + ata_dev_printk(dev, KERN_WARNING, "failed to set " + "max address (err_mask=0x%x)\n", err_mask); + if (err_mask == AC_ERR_DEV && + (tf.feature & (ATA_ABORTED | ATA_IDNF))) + return -EACCES; + return -EIO; + } - return ata_tf_to_lba(&tf); + if (lba48) + *res_sectors = ata_tf_to_lba48(&tf); + else + *res_sectors = ata_tf_to_lba(&tf); + + return 0; } /** @@ -1001,11 +985,11 @@ static u64 ata_hpa_resize(struct ata_device *dev) { u64 sectors = dev->n_sectors; u64 hpa_sectors; + int rc; - if (ata_id_has_lba48(dev->id)) - hpa_sectors = ata_read_native_max_address_ext(dev); - else - hpa_sectors = ata_read_native_max_address(dev); + rc = ata_read_native_max_address(dev, &hpa_sectors); + if (rc) + return 0; if (hpa_sectors > sectors) { ata_dev_printk(dev, KERN_INFO, @@ -1015,13 +999,9 @@ static u64 ata_hpa_resize(struct ata_device *dev) (long long)sectors, (long long)hpa_sectors); if (ata_ignore_hpa) { - if (ata_id_has_lba48(dev->id)) - hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors); - else - hpa_sectors = ata_set_native_max_address(dev, - hpa_sectors); + rc = ata_set_max_sectors(dev, hpa_sectors, &hpa_sectors); - if (hpa_sectors) { + if (rc == 0) { ata_dev_printk(dev, KERN_INFO, "native size " "increased to %lld sectors\n", (long long)hpa_sectors); From 05027adccc09401a7e31d5ef51040dc75ab03c22 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Sep 2007 12:32:57 +0900 Subject: [PATCH 2437/2804] libata: remiplement ata_hpa_resize() This patch reimplement ata_hpa_resize() such that... * All HPA related decisions are made inside ata_hpa_resize() proper. ata_hpa_resize() returns 0 if configuration can proceed, -errno if device needs to be reset and reconfigured. * All errors are handled properly. If HPA unlocking isn't requested, HPA handling is disabled automatically to avoid unnecessary device detection failure. * Messages are trimmed. HPA detection message is printed only during initial configuration. HPA unlocked message is printed only during initial configuration or unlocking results in different size. * Instead of using sectors returned in TF of SET_MAX, re-read IDENTIFY data as that's the value the device is going to use. * It's called early during ata_dev_configure() as IDENTIFY data might change after resizing. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 122 ++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 38 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c7614bdc0cb9..b01b5a897dcf 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -915,7 +915,6 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) * ata_set_max_sectors - Set max sectors * @dev: target device * @new_sectors: new max sectors value to set for the device - * @res_sectors: result max sectors * * Set max sectors of @dev to @new_sectors. * @@ -924,8 +923,7 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) * previous non-volatile SET_MAX) by the drive. -EIO on other * errors. */ -static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, - u64 *res_sectors) +static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) { unsigned int err_mask; struct ata_taskfile tf; @@ -964,11 +962,6 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, return -EIO; } - if (lba48) - *res_sectors = ata_tf_to_lba48(&tf); - else - *res_sectors = ata_tf_to_lba(&tf); - return 0; } @@ -979,41 +972,93 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, * Read the size of an LBA28 or LBA48 disk with HPA features and resize * it if required to the full size of the media. The caller must check * the drive has the HPA feature set enabled. + * + * RETURNS: + * 0 on success, -errno on failure. */ - -static u64 ata_hpa_resize(struct ata_device *dev) +static int ata_hpa_resize(struct ata_device *dev) { - u64 sectors = dev->n_sectors; - u64 hpa_sectors; + struct ata_eh_context *ehc = &dev->link->eh_context; + int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; + u64 sectors = ata_id_n_sectors(dev->id); + u64 native_sectors; int rc; - rc = ata_read_native_max_address(dev, &hpa_sectors); - if (rc) + /* do we need to do it? */ + if (dev->class != ATA_DEV_ATA || + !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) || + (dev->horkage & ATA_HORKAGE_BROKEN_HPA)) return 0; - if (hpa_sectors > sectors) { - ata_dev_printk(dev, KERN_INFO, - "Host Protected Area detected:\n" - "\tcurrent size: %lld sectors\n" - "\tnative size: %lld sectors\n", - (long long)sectors, (long long)hpa_sectors); + /* read native max address */ + rc = ata_read_native_max_address(dev, &native_sectors); + if (rc) { + /* If HPA isn't going to be unlocked, skip HPA + * resizing from the next try. + */ + if (!ata_ignore_hpa) { + ata_dev_printk(dev, KERN_WARNING, "HPA support seems " + "broken, will skip HPA handling\n"); + dev->horkage |= ATA_HORKAGE_BROKEN_HPA; - if (ata_ignore_hpa) { - rc = ata_set_max_sectors(dev, hpa_sectors, &hpa_sectors); - - if (rc == 0) { - ata_dev_printk(dev, KERN_INFO, "native size " - "increased to %lld sectors\n", - (long long)hpa_sectors); - return hpa_sectors; - } + /* we can continue if device aborted the command */ + if (rc == -EACCES) + rc = 0; } - } else if (hpa_sectors < sectors) - ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) " - "is smaller than sectors (%lld)\n", __FUNCTION__, - (long long)hpa_sectors, (long long)sectors); - return sectors; + return rc; + } + + /* nothing to do? */ + if (native_sectors <= sectors || !ata_ignore_hpa) { + if (!print_info || native_sectors == sectors) + return 0; + + if (native_sectors > sectors) + ata_dev_printk(dev, KERN_INFO, + "HPA detected: current %llu, native %llu\n", + (unsigned long long)sectors, + (unsigned long long)native_sectors); + else if (native_sectors < sectors) + ata_dev_printk(dev, KERN_WARNING, + "native sectors (%llu) is smaller than " + "sectors (%llu)\n", + (unsigned long long)native_sectors, + (unsigned long long)sectors); + return 0; + } + + /* let's unlock HPA */ + rc = ata_set_max_sectors(dev, native_sectors); + if (rc == -EACCES) { + /* if device aborted the command, skip HPA resizing */ + ata_dev_printk(dev, KERN_WARNING, "device aborted resize " + "(%llu -> %llu), skipping HPA handling\n", + (unsigned long long)sectors, + (unsigned long long)native_sectors); + dev->horkage |= ATA_HORKAGE_BROKEN_HPA; + return 0; + } else if (rc) + return rc; + + /* re-read IDENTIFY data */ + rc = ata_dev_reread_id(dev, 0); + if (rc) { + ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY " + "data after HPA resizing\n"); + return rc; + } + + if (print_info) { + u64 new_sectors = ata_id_n_sectors(dev->id); + ata_dev_printk(dev, KERN_INFO, + "HPA unlocked: %llu -> %llu, native %llu\n", + (unsigned long long)sectors, + (unsigned long long)new_sectors, + (unsigned long long)native_sectors); + } + + return 0; } /** @@ -1837,6 +1882,11 @@ int ata_dev_configure(struct ata_device *dev) if (rc) return rc; + /* massage HPA, do it early as it might change IDENTIFY data */ + rc = ata_hpa_resize(dev); + if (rc) + return rc; + /* print device capabilities */ if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, @@ -1904,10 +1954,6 @@ int ata_dev_configure(struct ata_device *dev) dev->flags |= ATA_DFLAG_FLUSH_EXT; } - if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) && - ata_id_hpa_enabled(dev->id)) - dev->n_sectors = ata_hpa_resize(dev); - /* config NCQ */ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); From 7a234aff3d83728fd83cf19df32d3df52566d2ac Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Sep 2007 12:44:57 +0900 Subject: [PATCH 2438/2804] ahci: reimplement port_map handling Reimplement port_map handling such that 1. Non-zero PORTS_IMPL value is always examined and used if consistent with cap.n_ports. 2. When PI and cat.n_ports are inconsistent, honor cap.n_ports and force port_map to be ((1 << cap.n_ports) - 1). 3. There were two separate places dealing with port_map. Unify them to one. As all newer ahci chips seem to get PI correct and older ones usually have zero PI. Controllers with holes in PI are very unlikely to screw up PI, so #2 makes more sense than following inconsistent PI. Without this change, not setting ATA_FLAG_HONOR_PI when it's needed results in weird detection failure. This changed logic should be able to handle all known cases correctly automatically. Verified on ICH6 (reports 0 PI), ICH8 (with holes in port_map), ICH9, JMB360 and JMB363. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 89 ++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 518c51830357..57cc3e73a7e2 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -77,11 +77,10 @@ enum { RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, - board_ahci_pi = 1, - board_ahci_vt8251 = 2, - board_ahci_ign_iferr = 3, - board_ahci_sb600 = 4, - board_ahci_mv = 5, + board_ahci_vt8251 = 1, + board_ahci_ign_iferr = 2, + board_ahci_sb600 = 3, + board_ahci_mv = 4, /* global controller registers */ HOST_CAP = 0x00, /* host capabilities */ @@ -170,7 +169,6 @@ enum { /* ap->flags bits */ AHCI_FLAG_NO_NCQ = (1 << 24), AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ - AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ @@ -332,14 +330,6 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, - /* board_ahci_pi */ - { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, - .link_flags = AHCI_LFLAG_COMMON, - .pio_mask = 0x1f, /* pio0-4 */ - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_ops, - }, /* board_ahci_vt8251 */ { .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, @@ -371,8 +361,8 @@ static const struct ata_port_info ahci_port_info[] = { .sht = &ahci_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - AHCI_FLAG_HONOR_PI | AHCI_FLAG_NO_NCQ | - AHCI_FLAG_NO_MSI | AHCI_FLAG_MV_PATA, + AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | + AHCI_FLAG_MV_PATA, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -392,23 +382,23 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ - { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -562,16 +552,6 @@ static void ahci_save_initial_config(struct pci_dev *pdev, cap &= ~HOST_CAP_NCQ; } - /* fixup zero port_map */ - if (!port_map) { - port_map = (1 << ahci_nr_ports(cap)) - 1; - dev_printk(KERN_WARNING, &pdev->dev, - "PORTS_IMPL is zero, forcing 0x%x\n", port_map); - - /* write the fixed up value to the PI register */ - hpriv->saved_port_map = port_map; - } - /* * Temporary Marvell 6145 hack: PATA port presence * is asserted through the standard AHCI port @@ -587,7 +567,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, } /* cross check port_map and cap.n_ports */ - if (pi->flags & AHCI_FLAG_HONOR_PI) { + if (port_map) { u32 tmp_port_map = port_map; int n_ports = ahci_nr_ports(cap); @@ -598,17 +578,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev, } } - /* Whine if inconsistent. No need to update cap. - * port_map is used to determine number of ports. + /* If n_ports and port_map are inconsistent, whine and + * clear port_map and let it be generated from n_ports. */ - if (n_ports || tmp_port_map) + if (n_ports || tmp_port_map) { dev_printk(KERN_WARNING, &pdev->dev, "nr_ports (%u) and implemented port map " - "(0x%x) don't match\n", + "(0x%x) don't match, using nr_ports\n", ahci_nr_ports(cap), port_map); - } else { - /* fabricate port_map from cap.nr_ports */ + port_map = 0; + } + } + + /* fabricate port_map from cap.nr_ports */ + if (!port_map) { port_map = (1 << ahci_nr_ports(cap)) - 1; + dev_printk(KERN_WARNING, &pdev->dev, + "forcing PORTS_IMPL to 0x%x\n", port_map); + + /* write the fixed up value to the PI register */ + hpriv->saved_port_map = port_map; } /* record values to use during operation */ From 3f19859ee95a38c066a0420eb8a30c76ecd67a42 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Sep 2007 23:23:57 +0900 Subject: [PATCH 2439/2804] libata: update ata_dev_try_classify() arguments Make ata_dev_try_classify() take a pointer to ata_device instead of ata_port/port_number combination for consistency and add @present argument. @present indicates whether the device seems present during reset. It's the result of TF access during softreset and link onlineness during hardreset. @present will be used to improve diagnostic failure handling. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 30 ++++++++++++++++-------------- drivers/ata/pata_scc.c | 6 ++++-- drivers/ata/sata_mv.c | 2 +- include/linux/libata.h | 3 ++- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b01b5a897dcf..ea8c07b04f29 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -701,8 +701,8 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) /** * ata_dev_try_classify - Parse returned ATA device signature - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) + * @dev: ATA device to classify (starting at zero) + * @present: device seems present * @r_err: Value of error register on completion * * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, @@ -720,15 +720,15 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) * RETURNS: * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */ - -unsigned int -ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) +unsigned int ata_dev_try_classify(struct ata_device *dev, int present, + u8 *r_err) { + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf; unsigned int class; u8 err; - ap->ops->dev_select(ap, device); + ap->ops->dev_select(ap, dev->devno); memset(&tf, 0, sizeof(tf)); @@ -738,12 +738,12 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) *r_err = err; /* see if device passed diags: if master then continue and warn later */ - if (err == 0 && device == 0) + if (err == 0 && dev->devno == 0) /* diagnostic fail : do nothing _YET_ */ - ap->link.device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC; + dev->horkage |= ATA_HORKAGE_DIAGNOSTIC; else if (err == 1) /* do nothing */ ; - else if ((device == 0) && (err == 0x81)) + else if ((dev->devno == 0) && (err == 0x81)) /* do nothing */ ; else return ATA_DEV_NONE; @@ -3238,9 +3238,9 @@ void ata_bus_reset(struct ata_port *ap) /* * determine by signature whether we have ATA or ATAPI devices */ - device[0].class = ata_dev_try_classify(ap, 0, &err); + device[0].class = ata_dev_try_classify(&device[0], dev0, &err); if ((slave_possible) && (err != 0x81)) - device[1].class = ata_dev_try_classify(ap, 1, &err); + device[1].class = ata_dev_try_classify(&device[1], dev1, &err); /* is double-select really necessary? */ if (device[1].class != ATA_DEV_NONE) @@ -3479,9 +3479,11 @@ int ata_std_softreset(struct ata_link *link, unsigned int *classes, } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(ap, 0, &err); + classes[0] = ata_dev_try_classify(&link->device[0], + devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(ap, 1, &err); + classes[1] = ata_dev_try_classify(&link->device[1], + devmask & (1 << 1), &err); out: DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); @@ -3600,7 +3602,7 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, ap->ops->dev_select(ap, 0); /* probably unnecessary */ - *class = ata_dev_try_classify(ap, 0, NULL); + *class = ata_dev_try_classify(link->device, 1, NULL); DPRINTK("EXIT, class=%u\n", *class); return 0; diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 2153def3f345..941b72bec836 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -636,9 +636,11 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes, } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(ap, 0, &err); + classes[0] = ata_dev_try_classify(&ap->link.device[0], + devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(ap, 1, &err); + classes[1] = ata_dev_try_classify(&ap->link.device[1], + devmask & (1 << 1), &err); out: DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 08077efa9afd..4df8311968e9 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2248,7 +2248,7 @@ comreset_retry: */ /* finally, read device signature from TF registers */ - *class = ata_dev_try_classify(ap, 0, NULL); + *class = ata_dev_try_classify(ap->link.device, 1, NULL); writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); diff --git a/include/linux/libata.h b/include/linux/libata.h index 49da62d0c83b..3ab2196c651a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -781,7 +781,8 @@ extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn, extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, unsigned long interval_msec, unsigned long timeout_msec); -extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *); +extern unsigned int ata_dev_try_classify(struct ata_device *dev, int present, + u8 *r_err); /* * Default driver ops implementations From d7fbee050753e153622b5d41bc8bd1cb19cda9b9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Sep 2007 23:24:48 +0900 Subject: [PATCH 2440/2804] libata: assume ATA_DEV_ATA on diagnostic failure Certain device which reports diagnostic failure also reports invalid device signature. Assume ATA_DEV_ATA on diagnostic failure if reset indicates device presence. This is fix for bugzilla bug 8784. http://bugzilla.kernel.org/show_bug.cgi?id=8784 Signed-off-by: Tejun Heo Acked-by: Alan Cox Cc: Edward Amsden Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ea8c07b04f29..2116f2794580 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -751,10 +751,20 @@ unsigned int ata_dev_try_classify(struct ata_device *dev, int present, /* determine if device is ATA or ATAPI */ class = ata_dev_classify(&tf); - if (class == ATA_DEV_UNKNOWN) - return ATA_DEV_NONE; - if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) - return ATA_DEV_NONE; + if (class == ATA_DEV_UNKNOWN) { + /* If the device failed diagnostic, it's likely to + * have reported incorrect device signature too. + * Assume ATA device if the device seems present but + * device signature is invalid with diagnostic + * failure. + */ + if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC)) + class = ATA_DEV_ATA; + else + class = ATA_DEV_NONE; + } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) + class = ATA_DEV_NONE; + return class; } From d4155e6f13e931048036976d9fb47b5db53ee7a3 Mon Sep 17 00:00:00 2001 From: Jason Gaston Date: Thu, 20 Sep 2007 17:35:00 -0400 Subject: [PATCH 2441/2804] ahci: RAID mode SATA patch for Intel Tolapai Signed-off-by: Jason Gaston Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 57cc3e73a7e2..b721569faaf8 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -399,6 +399,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ + { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, From ad355b4628a19ba2af30409e13083edda221a5c9 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 20:38:03 -0400 Subject: [PATCH 2442/2804] [libata] SCSI: support INQUIRY page 89h (ATA info page) Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 72 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7ad046b7c356..b39966299e7b 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1803,6 +1803,61 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, return 0; } +/** + * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info + * @args: device IDENTIFY data / SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * @buflen: Response buffer length. + * + * Yields SAT-specified ATA VPD page. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ + +unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, + unsigned int buflen) +{ + u8 pbuf[60]; + struct ata_taskfile tf; + unsigned int i; + + if (!buflen) + return 0; + + memset(&pbuf, 0, sizeof(pbuf)); + memset(&tf, 0, sizeof(tf)); + + pbuf[1] = 0x89; /* our page code */ + pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ + pbuf[3] = (0x238 & 0xff); + + memcpy(&pbuf[8], "ATA ", 8); + ata_id_string(args->id, &pbuf[16], ATA_ID_PROD, 16); + ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4); + + /* we don't store the ATA device signature, so we fake it */ + + tf.command = ATA_DRDY; /* really, this is Status reg */ + tf.lbal = 0x1; + tf.nsect = 0x1; + + ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */ + pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ + + pbuf[56] = ATA_CMD_ID_ATA; + + i = min(buflen, 60U); + memcpy(rbuf, &pbuf[0], i); + buflen -= i; + + if (!buflen) + return 0; + + memcpy(&rbuf[60], &args->id[0], min(buflen, 512U)); + return 0; +} + /** * ata_scsiop_noop - Command handler that simply returns success. * @args: device IDENTIFY data / SCSI command of interest. @@ -2880,14 +2935,23 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_scsi_invalid_field(cmd, done); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); - else if (scsicmd[2] == 0x00) + else switch (scsicmd[2]) { + case 0x00: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00); - else if (scsicmd[2] == 0x80) + break; + case 0x80: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80); - else if (scsicmd[2] == 0x83) + break; + case 0x83: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); - else + break; + case 0x89: + ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89); + break; + default: ata_scsi_invalid_field(cmd, done); + break; + } break; case MODE_SENSE: From 453941455218a81eedcea5dbafa38b8815920a8c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 06:23:42 -0400 Subject: [PATCH 2443/2804] [libata] Slightly improved no-op REQUEST SENSE, SEND DIAGNOSTIC A few pedantic apps care about missing or lame "mandatory" SCSI commands, so REQUEST SENSE -- as we autosense, R.S. just returns zeroes SEND DIAGNOSTIC -- our default (no-op) self-test succeeds, all other requests for testing fail. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b39966299e7b..79550908adcc 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2912,6 +2912,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, { struct ata_scsi_args args; const u8 *scsicmd = cmd->cmnd; + u8 tmp8; args.dev = dev; args.id = dev->id; @@ -2926,7 +2927,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, case SEEK_10: case TEST_UNIT_READY: case FORMAT_UNIT: /* FIXME: correct? */ - case SEND_DIAGNOSTIC: /* FIXME: correct? */ ata_scsi_rbuf_fill(&args, ata_scsiop_noop); break; @@ -2979,8 +2979,19 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandatory commands we haven't implemented yet */ case REQUEST_SENSE: + ata_scsi_set_sense(cmd, 0, 0, 0); + cmd->result = (DRIVER_SENSE << 24); + done(cmd); + break; + + case SEND_DIAGNOSTIC: + tmp8 = scsicmd[1] & ~(1 << 3); + if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) + ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + else + ata_scsi_invalid_field(cmd, done); + break; /* all other commands */ default: From 00bd02027fc4a5cf92a3e538896b3642b40515df Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 07:26:08 -0400 Subject: [PATCH 2444/2804] [libata] SCSI: improve FORMAT UNIT; minor code cleanups * SAT specifies that FORMAT UNIT should be translated into a series of READ and WRITE commands that zero the ATA device. That is far too cumbersome to bother with. Since we don't actually format the device, the old behavior of always returning success was inaccurate. Change FORMAT UNIT from returning success immediately (old behavior) to always returning an error (new behavior). * Add some comments around SYNCHRONIZE CACHE * Shuffle scsi command code around a bit, so that things are close to alphabetic order. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 79550908adcc..553488015e49 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2920,14 +2920,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, args.done = done; switch(scsicmd[0]) { - /* no-op's, complete with success */ - case SYNCHRONIZE_CACHE: - case REZERO_UNIT: - case SEEK_6: - case SEEK_10: - case TEST_UNIT_READY: - case FORMAT_UNIT: /* FIXME: correct? */ - ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + /* TODO: worth improving? */ + case FORMAT_UNIT: + ata_scsi_invalid_field(cmd, done); break; case INQUIRY: @@ -2985,6 +2980,20 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, done(cmd); break; + /* if we reach this, then writeback caching is disabled, + * turning this into a no-op. + */ + case SYNCHRONIZE_CACHE: + /* fall through */ + + /* no-op's, complete with success */ + case REZERO_UNIT: + case SEEK_6: + case SEEK_10: + case TEST_UNIT_READY: + ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + break; + case SEND_DIAGNOSTIC: tmp8 = scsicmd[1] & ~(1 << 3); if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) From 24f756866676b40446e361c1f87738707161da93 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 07:54:49 -0400 Subject: [PATCH 2445/2804] [libata] SCSI: clean up R/W recovery mode page Clear ARRE, we don't do auto-reallocation on reads, just on writes. Also, hardcode the size of the array using RW_RECOVERY_MPAGE_LEN, following the style of the surrounding code. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 553488015e49..d482b589a18a 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -71,11 +71,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, #define ALL_SUB_MPAGES 0xff -static const u8 def_rw_recovery_mpage[] = { +static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = { RW_RECOVERY_MPAGE, RW_RECOVERY_MPAGE_LEN - 2, - (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */ - (1 << 6), /* ARRE (auto read reallocation) */ + (1 << 7), /* AWRE */ 0, /* read retry count */ 0, 0, 0, 0, 0, /* write retry count */ From c78968bb0f7714ceba1cdfa23714454fc98cefdf Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 21:03:28 -0400 Subject: [PATCH 2446/2804] [libata] SCSI: simulator version, not device version, belongs in VPD Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 2 -- drivers/ata/libata-scsi.c | 5 +++-- drivers/ata/libata.h | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2116f2794580..8d425064ce2c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -59,8 +59,6 @@ #include "libata.h" -#define DRV_VERSION "2.21" /* must be exactly four chars */ - /* debounce timing parameters in msecs { interval, duration, timeout } */ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d482b589a18a..468d791a303c 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1831,8 +1831,9 @@ unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ pbuf[3] = (0x238 & 0xff); - memcpy(&pbuf[8], "ATA ", 8); - ata_id_string(args->id, &pbuf[16], ATA_ID_PROD, 16); + memcpy(&pbuf[8], "linux ", 8); + memcpy(&pbuf[16], "libata ", 16); + memcpy(&pbuf[32], DRV_VERSION, 4); ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4); /* we don't store the ATA device signature, so we fake it */ diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 11f64a43b38a..e45f6d5542d5 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -29,6 +29,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" +#define DRV_VERSION "2.21" /* must be exactly four chars */ struct ata_scsi_args { struct ata_device *dev; From 854c73a2f1c3bcc4aa88c25e208dc597e8efb795 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:11 +0900 Subject: [PATCH 2447/2804] libata: misc updates for AN Update AN support in preparation of PMP support. * s/ata_id_has_AN/ata_id_has_atapi_AN/ * add AN enabled reporting during configuration * add err_mask to AN configuration failure reporting * update LOCKING comment for ata_scsi_media_change_notify() * check whether ATA dev is attached to SCSI dev ata_scsi_media_change_notify() * set ATA_FLAG_AN in ahci and sata_sil24 Signed-off-by: Tejun Heo Cc: Kriten Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 2 +- drivers/ata/libata-core.c | 24 ++++++++++++++---------- drivers/ata/libata-scsi.c | 7 ++++--- drivers/ata/sata_sil24.c | 13 +++++++++++-- include/linux/ata.h | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b721569faaf8..0a6b694f0d3a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -177,7 +177,7 @@ enum { AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_ACPI_SATA, + ATA_FLAG_ACPI_SATA | ATA_FLAG_AN, AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, }; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8d425064ce2c..1daea1caf3e5 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2010,7 +2010,8 @@ int ata_dev_configure(struct ata_device *dev) /* ATAPI-specific feature tests */ else if (dev->class == ATA_DEV_ATAPI) { - char *cdb_intr_string = ""; + const char *cdb_intr_string = ""; + const char *atapi_an_string = ""; rc = atapi_cdb_len(id); if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { @@ -2026,16 +2027,19 @@ int ata_dev_configure(struct ata_device *dev) * check to see if this ATAPI device supports * Asynchronous Notification */ - if ((ap->flags & ATA_FLAG_AN) && ata_id_has_AN(id)) { - int err; + if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id)) { + unsigned int err_mask; + /* issue SET feature command to turn this on */ - err = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE); - if (err) + err_mask = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE); + if (err_mask) ata_dev_printk(dev, KERN_ERR, - "unable to set AN, err %x\n", - err); - else + "failed to enable ATAPI AN " + "(err_mask=0x%x)\n", err_mask); + else { dev->flags |= ATA_DFLAG_AN; + atapi_an_string = ", ATAPI AN"; + } } if (ata_id_cdb_intr(dev->id)) { @@ -2046,10 +2050,10 @@ int ata_dev_configure(struct ata_device *dev) /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, - "ATAPI: %s, %s, max %s%s\n", + "ATAPI: %s, %s, max %s%s%s\n", modelbuf, fwrevbuf, ata_mode_string(xfer_mask), - cdb_intr_string); + cdb_intr_string, atapi_an_string); } /* determine max_sectors */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 468d791a303c..dc274001ddd9 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3238,12 +3238,13 @@ static void ata_scsi_handle_link_detach(struct ata_link *link) * event. * * LOCKING: - * interrupt context, may not sleep. + * spin_lock_irqsave(host lock) */ -void ata_scsi_media_change_notify(struct ata_device *atadev) +void ata_scsi_media_change_notify(struct ata_device *dev) { #ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED - scsi_device_event_notify(atadev->sdev, SDEV_MEDIA_CHANGE); + if (dev->sdev) + scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE); #endif } EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 3dcb223117be..d9c010ab2280 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -168,7 +168,7 @@ enum { DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG | - PORT_IRQ_UNK_FIS, + PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY, /* bits[27:16] are unmasked (raw) */ PORT_IRQ_RAW_SHIFT = 16, @@ -237,7 +237,8 @@ enum { /* host flags */ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA, + ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA | + ATA_FLAG_AN, SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ @@ -818,6 +819,14 @@ static void sil24_error_intr(struct ata_port *ap) ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); + if (irq_stat & PORT_IRQ_SDB_NOTIFY) { + struct ata_device *dev = ap->link.device; + + ata_ehi_push_desc(ehi, "SDB notify"); + if (dev->flags & ATA_DFLAG_AN) + ata_scsi_media_change_notify(dev); + } + if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) { ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, "%s", diff --git a/include/linux/ata.h b/include/linux/ata.h index a749f006387f..21f00a0646d8 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -353,7 +353,7 @@ struct ata_taskfile { #define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1) #define ata_id_removeable(id) ((id)[0] & (1 << 7)) #define ata_id_has_dword_io(id) ((id)[48] & (1 << 0)) -#define ata_id_has_AN(id) \ +#define ata_id_has_atapi_AN(id) \ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ ((id)[78] & (1 << 5)) ) #define ata_id_iordy_disable(id) ((id)[49] & (1 << 10)) From e0a7175263db4a226558883a51a88a5d2bc5d9fe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: [PATCH 2448/2804] libata-pmp-prep: add PMP related constants, fields, ops and update helpers Add PMP related constants, fields and ops. Also, update ata_class_enabled/disabled() such that PMP classes are considered. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index 3ab2196c651a..c3820f105ffa 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -155,7 +155,11 @@ enum { ATA_DEV_ATA_UNSUP = 2, /* ATA device (unsupported) */ ATA_DEV_ATAPI = 3, /* ATAPI device */ ATA_DEV_ATAPI_UNSUP = 4, /* ATAPI device (unsupported) */ - ATA_DEV_NONE = 5, /* no device */ + ATA_DEV_PMP = 5, /* SATA port multiplier */ + ATA_DEV_PMP_UNSUP = 6, /* SATA port multiplier (unsupported) */ + ATA_DEV_SEMB = 7, /* SEMB */ + ATA_DEV_SEMB_UNSUP = 8, /* SEMB (unsupported) */ + ATA_DEV_NONE = 9, /* no device */ /* struct ata_link flags */ ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ @@ -181,6 +185,7 @@ enum { ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ ATA_FLAG_AN = (1 << 18), /* controller supports AN */ + ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be @@ -299,6 +304,10 @@ enum { /* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES = 3, ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, /* Horkage types. May be set by libata or controller on drives (some horkage may be drive/controller pair dependant */ @@ -450,7 +459,12 @@ struct ata_device { /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ u64 n_sectors; /* size of device, if ATA */ unsigned int class; /* ATA_DEV_xxx */ - u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + + union { + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ + }; + u8 pio_mode; u8 dma_mode; u8 xfer_mode; @@ -628,6 +642,12 @@ struct ata_port_operations { void (*qc_prep) (struct ata_queued_cmd *qc); unsigned int (*qc_issue) (struct ata_queued_cmd *qc); + /* port multiplier */ + void (*pmp_attach) (struct ata_port *ap); + void (*pmp_detach) (struct ata_port *ap); + int (*pmp_read) (struct ata_device *dev, int pmp, int reg, u32 *r_val); + int (*pmp_write) (struct ata_device *dev, int pmp, int reg, u32 val); + /* Error handlers. ->error_handler overrides ->eng_timeout and * indicates that new-style EH is in place. */ @@ -1033,12 +1053,14 @@ static inline unsigned int ata_tag_internal(unsigned int tag) */ static inline unsigned int ata_class_enabled(unsigned int class) { - return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI; + return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI || + class == ATA_DEV_PMP || class == ATA_DEV_SEMB; } static inline unsigned int ata_class_disabled(unsigned int class) { - return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP; + return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP || + class == ATA_DEV_PMP_UNSUP || class == ATA_DEV_SEMB_UNSUP; } static inline unsigned int ata_class_absent(unsigned int class) From 422c9daa8b5bea09f3393b11a106afd68850b39b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: [PATCH 2449/2804] libata-pmp-prep: add @new_class to ata_dev_revalidate() Consider newly found class code while revalidating. PMP resetting always results in valid class code and issuing PMP commands to ATA/ATAPI device isn't very attractive. Add @new_class to ata_dev_revalidate() and check class code for revalidation. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 15 +++++++++++++-- drivers/ata/libata-eh.c | 3 ++- drivers/ata/libata.h | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1daea1caf3e5..c046c5e1e5db 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2846,7 +2846,7 @@ static int ata_dev_set_mode(struct ata_device *dev) } ehc->i.flags |= ATA_EHI_POST_SETMODE; - rc = ata_dev_revalidate(dev, 0); + rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0); ehc->i.flags &= ~ATA_EHI_POST_SETMODE; if (rc) return rc; @@ -3750,6 +3750,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) /** * ata_dev_revalidate - Revalidate ATA device * @dev: device to revalidate + * @new_class: new class code * @readid_flags: read ID flags * * Re-read IDENTIFY page, make sure @dev is still attached to the @@ -3761,7 +3762,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) * RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) +int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, + unsigned int readid_flags) { u64 n_sectors = dev->n_sectors; int rc; @@ -3769,6 +3771,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) if (!ata_dev_enabled(dev)) return -ENODEV; + /* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */ + if (ata_class_enabled(new_class) && + new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) { + ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n", + dev->class, new_class); + rc = -ENODEV; + goto fail; + } + /* re-read ID */ rc = ata_dev_reread_id(dev, readid_flags); if (rc) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index daa2f74f73c8..eb087bbc4771 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2104,7 +2104,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, } ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE); - rc = ata_dev_revalidate(dev, readid_flags); + rc = ata_dev_revalidate(dev, ehc->classes[dev->devno], + readid_flags); if (rc) goto err; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index e45f6d5542d5..d4d369908c0f 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -78,7 +78,8 @@ extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id); extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags); -extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags); +extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, + unsigned int readid_flags); extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_link *link); extern int sata_set_spd_needed(struct ata_link *link); From fb7fd61454c8681cd2621051a710b78a00369203 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: [PATCH 2450/2804] libata-pmp-prep: make a number of functions global to libata Make a number of functions from libata-core.c and libata-eh.c global to libata (drivers/ata/libata.h). These will be used by PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++-- drivers/ata/libata-eh.c | 31 +++++++++++++++---------------- drivers/ata/libata.h | 17 +++++++++++++++++ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c046c5e1e5db..9467c2f60192 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6218,7 +6218,7 @@ void ata_dev_init(struct ata_device *dev) * LOCKING: * Kernel thread context (may sleep) */ -static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) +void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) { int i; @@ -6253,7 +6253,7 @@ static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) * RETURNS: * 0 on success, -errno on failure. */ -static int sata_link_init_spd(struct ata_link *link) +int sata_link_init_spd(struct ata_link *link) { u32 scontrol, spd; int rc; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index eb087bbc4771..1d3b0dccfb0a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -74,7 +74,6 @@ static const unsigned long ata_eh_reset_timeouts[] = { }; static void __ata_port_freeze(struct ata_port *ap); -static void ata_eh_finish(struct ata_port *ap); #ifdef CONFIG_PM static void ata_eh_handle_port_suspend(struct ata_port *ap); static void ata_eh_handle_port_resume(struct ata_port *ap); @@ -1015,7 +1014,7 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) * LOCKING: * None. */ -static void ata_eh_detach_dev(struct ata_device *dev) +void ata_eh_detach_dev(struct ata_device *dev) { struct ata_link *link = dev->link; struct ata_port *ap = link->ap; @@ -1052,8 +1051,8 @@ static void ata_eh_detach_dev(struct ata_device *dev) * LOCKING: * None. */ -static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, - unsigned int action) +void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, + unsigned int action) { struct ata_port *ap = link->ap; struct ata_eh_info *ehi = &link->eh_info; @@ -1095,8 +1094,8 @@ static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, * LOCKING: * None. */ -static void ata_eh_done(struct ata_link *link, struct ata_device *dev, - unsigned int action) +void ata_eh_done(struct ata_link *link, struct ata_device *dev, + unsigned int action) { struct ata_eh_context *ehc = &link->eh_context; @@ -1756,7 +1755,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_autopsy(struct ata_port *ap) +void ata_eh_autopsy(struct ata_port *ap) { struct ata_link *link; @@ -1867,7 +1866,7 @@ static void ata_eh_link_report(struct ata_link *link) * LOCKING: * None. */ -static void ata_eh_report(struct ata_port *ap) +void ata_eh_report(struct ata_port *ap) { struct ata_link *link; @@ -1918,9 +1917,9 @@ static int ata_eh_followup_srst_needed(int rc, int classify, return 0; } -static int ata_eh_reset(struct ata_link *link, int classify, - ata_prereset_fn_t prereset, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +int ata_eh_reset(struct ata_link *link, int classify, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; @@ -2296,10 +2295,10 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) * RETURNS: * 0 on success, -errno on failure. */ -static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, - ata_reset_fn_t softreset, ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset, - struct ata_link **r_failed_link) +int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset, + struct ata_link **r_failed_link) { struct ata_link *link; struct ata_device *dev; @@ -2445,7 +2444,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, * LOCKING: * None. */ -static void ata_eh_finish(struct ata_port *ap) +void ata_eh_finish(struct ata_port *ap) { int tag; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index d4d369908c0f..0f3e355fdfd7 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -95,6 +95,8 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device, extern void swap_buf_le16(u16 *buf, unsigned int buf_words); extern int ata_flush_cache(struct ata_device *dev); extern void ata_dev_init(struct ata_device *dev); +extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp); +extern int sata_link_init_spd(struct ata_link *link); extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern struct ata_port *ata_port_alloc(struct ata_host *host); @@ -156,6 +158,21 @@ extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_eh_fastdrain_timerfn(unsigned long arg); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); +extern void ata_eh_detach_dev(struct ata_device *dev); +extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, + unsigned int action); +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); +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, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); +extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset, + struct ata_link **r_failed_disk); +extern void ata_eh_finish(struct ata_port *ap); /* libata-sff.c */ extern u8 ata_irq_on(struct ata_port *ap); From 31cc23b34913bc173680bdc87af79e551bf8cc0d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: [PATCH 2451/2804] libata-pmp-prep: implement ops->qc_defer() Controllers which support PMP have various restrictions on which combinations of commands are allowed to what number of devices concurrently. This patch implements ops->qc_defer() which determines whether a qc can be issued at the moment or should be deferred. If the function returns ATA_DEFER_LINK, the qc will be deferred until a qc completes on the link. If ATA_DEFER_PORT, until a qc completes on any link. The defer conditions are advisory and in general ATA_DEFER_LINK can be considered as lower priority deferring than ATA_DEFER_PORT. ops->qc_defer() replaces fixed ata_scmd_need_defer(). For standard NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented. ahci and sata_sil24 are converted to use ata_std_qc_defer(). ops->qc_defer() is heavier than the original mechanism because full qc is prepped before determining to defer it, but various information is needed to determine defer conditinos and fully translating a qc is the only way to supply such information in generic manner. IMHO, this shouldn't cause any noticeable performance issues as * for most cases deferring occurs rarely (except for NCQ-aware cmd-switching PMP) * translation itself isn't that expensive * once deferred the command won't be repeated until another command completes which usually is a very long time cpu-wise. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 2 ++ drivers/ata/libata-core.c | 31 ++++++++++++++++++++ drivers/ata/libata-scsi.c | 62 ++++++++++++++++----------------------- drivers/ata/sata_nv.c | 1 + drivers/ata/sata_sil24.c | 1 + include/linux/libata.h | 6 ++++ 6 files changed, 67 insertions(+), 36 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 0a6b694f0d3a..cf3404467ceb 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -268,6 +268,7 @@ static const struct ata_port_operations ahci_ops = { .tf_read = ahci_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, @@ -298,6 +299,7 @@ static const struct ata_port_operations ahci_vt8251_ops = { .tf_read = ahci_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9467c2f60192..b666f51da7ed 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4345,6 +4345,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc) return 0; } +/** + * ata_std_qc_defer - Check whether a qc needs to be deferred + * @qc: ATA command in question + * + * Non-NCQ commands cannot run with any other command, NCQ or + * not. As upper layer only knows the queue depth, we are + * responsible for maintaining exclusion. This function checks + * whether a new command @qc can be issued. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * ATA_DEFER_* if deferring is needed, 0 otherwise. + */ +int ata_std_qc_defer(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + + if (qc->tf.protocol == ATA_PROT_NCQ) { + if (!ata_tag_valid(link->active_tag)) + return 0; + } else { + if (!ata_tag_valid(link->active_tag) && !link->sactive) + return 0; + } + + return ATA_DEFER_LINK; +} + /** * ata_qc_prep - Prepare taskfile for submission * @qc: Metadata associated with taskfile to be prepared @@ -7111,6 +7141,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_do_set_mode); EXPORT_SYMBOL_GPL(ata_data_xfer); EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); +EXPORT_SYMBOL_GPL(ata_std_qc_defer); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index dc274001ddd9..8ca2caeed017 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -749,6 +749,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) { sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; + + /* Schedule policy is determined by ->qc_defer() callback and + * it needs to see every deferred qc. Set dev_blocked to 1 to + * prevent SCSI midlayer from automatically deferring + * requests. + */ + sdev->max_device_blocked = 1; } static void ata_scsi_dev_config(struct scsi_device *sdev, @@ -1415,37 +1422,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) ata_qc_free(qc); } -/** - * ata_scmd_need_defer - Check whether we need to defer scmd - * @dev: ATA device to which the command is addressed - * @is_io: Is the command IO (and thus possibly NCQ)? - * - * NCQ and non-NCQ commands cannot run together. As upper layer - * only knows the queue depth, we are responsible for maintaining - * exclusion. This function checks whether a new command can be - * issued to @dev. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * 1 if deferring is needed, 0 otherwise. - */ -static int ata_scmd_need_defer(struct ata_device *dev, int is_io) -{ - struct ata_link *link = dev->link; - int is_ncq = is_io && ata_ncq_enabled(dev); - - if (is_ncq) { - if (!ata_tag_valid(link->active_tag)) - return 0; - } else { - if (!ata_tag_valid(link->active_tag) && !link->sactive) - return 0; - } - return 1; -} - /** * ata_scsi_translate - Translate then issue SCSI command to ATA device * @dev: ATA device to which the command is addressed @@ -1477,14 +1453,12 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), ata_xlat_func_t xlat_func) { + struct ata_port *ap = dev->link->ap; struct ata_queued_cmd *qc; - int is_io = xlat_func == ata_scsi_rw_xlat; + int rc; VPRINTK("ENTER\n"); - if (unlikely(ata_scmd_need_defer(dev, is_io))) - goto defer; - qc = ata_scsi_qc_new(dev, cmd, done); if (!qc) goto err_mem; @@ -1508,6 +1482,11 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, if (xlat_func(qc)) goto early_finish; + if (ap->ops->qc_defer) { + if ((rc = ap->ops->qc_defer(qc))) + goto defer; + } + /* select device, send command to hardware */ ata_qc_issue(qc); @@ -1529,8 +1508,12 @@ err_mem: return 0; defer: + ata_qc_free(qc); DPRINTK("EXIT - defer\n"); - return SCSI_MLQUEUE_DEVICE_BUSY; + if (rc == ATA_DEFER_LINK) + return SCSI_MLQUEUE_DEVICE_BUSY; + else + return SCSI_MLQUEUE_HOST_BUSY; } /** @@ -3034,6 +3017,13 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) shost->max_channel = 1; shost->max_cmd_len = 16; + /* Schedule policy is determined by ->qc_defer() + * callback and it needs to see every deferred qc. + * Set host_blocked to 1 to prevent SCSI midlayer from + * automatically deferring requests. + */ + shost->max_host_blocked = 1; + rc = scsi_add_host(ap->scsi_host, ap->host->dev); if (rc) goto err_add; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index b860f99fc288..40557fe2ffdf 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -423,6 +423,7 @@ static const struct ata_port_operations nv_adma_ops = { .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, + .qc_defer = ata_std_qc_defer, .qc_prep = nv_adma_qc_prep, .qc_issue = nv_adma_qc_issue, .freeze = nv_adma_freeze, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index d9c010ab2280..9acfce43bde4 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -393,6 +393,7 @@ static const struct ata_port_operations sil24_ops = { .tf_read = sil24_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, diff --git a/include/linux/libata.h b/include/linux/libata.h index c3820f105ffa..b0d4ca0d27b4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -272,6 +272,10 @@ enum { /* ering size */ ATA_ERING_SIZE = 32, + /* return values for ->qc_defer */ + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + /* desc_len for ata_eh_info and context */ ATA_EH_DESC_LEN = 80, @@ -639,6 +643,7 @@ struct ata_port_operations { void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int); + int (*qc_defer) (struct ata_queued_cmd *qc); void (*qc_prep) (struct ata_queued_cmd *qc); unsigned int (*qc_issue) (struct ata_queued_cmd *qc); @@ -824,6 +829,7 @@ extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data); extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data); +extern int ata_std_qc_defer(struct ata_queued_cmd *qc); extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc); extern void ata_qc_prep(struct ata_queued_cmd *qc); extern void ata_noop_qc_prep(struct ata_queued_cmd *qc); From da917d69d0ea63f5390716cba6e77f490ce96df9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: [PATCH 2452/2804] libata-pmp-prep: implement qc_defer helpers Implement ap->nr_active_links (the number of links with active qcs), ap->excl_link (pointer to link which can be used by ->qc_defer and is cleared when a qc with ATA_QCFLAG_CLEAR_EXCL completes), and ata_link_active(). These can be used by ->qc_defer() to implement proper command exclusion. This set of helpers seem enough for both sil24 (ATAPI exclusion needed) and cmd-switching PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 22 ++++++++++++++++++++-- drivers/ata/libata-eh.c | 5 +++++ include/linux/libata.h | 8 ++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b666f51da7ed..376dbd80cc93 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1390,6 +1390,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_queued_cmd *qc; unsigned int tag, preempted_tag; u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; DECLARE_COMPLETION_ONSTACK(wait); unsigned long flags; unsigned int err_mask; @@ -1428,9 +1429,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, preempted_tag = link->active_tag; preempted_sactive = link->sactive; preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; link->active_tag = ATA_TAG_POISON; link->sactive = 0; ap->qc_active = 0; + ap->nr_active_links = 0; /* prepare & issue qc */ qc->tf = *tf; @@ -1509,6 +1512,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, link->active_tag = preempted_tag; link->sactive = preempted_sactive; ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; /* XXX - Some LLDDs (sata_mv) disable port on command failure. * Until those drivers are fixed, we detect the condition @@ -5408,10 +5412,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) ata_sg_clean(qc); /* command should be marked inactive atomically with qc completion */ - if (qc->tf.protocol == ATA_PROT_NCQ) + if (qc->tf.protocol == ATA_PROT_NCQ) { link->sactive &= ~(1 << qc->tag); - else + if (!link->sactive) + ap->nr_active_links--; + } else { link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + } + + /* clear exclusive status */ + if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL && + ap->excl_link == link)) + ap->excl_link = NULL; /* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler @@ -5590,9 +5603,14 @@ void ata_qc_issue(struct ata_queued_cmd *qc) if (qc->tf.protocol == ATA_PROT_NCQ) { WARN_ON(link->sactive & (1 << qc->tag)); + + if (!link->sactive) + ap->nr_active_links++; link->sactive |= 1 << qc->tag; } else { WARN_ON(link->sactive); + + ap->nr_active_links++; link->active_tag = qc->tag; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 1d3b0dccfb0a..5244723952c2 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -451,6 +451,7 @@ void ata_scsi_error(struct Scsi_Host *host) ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; ap->pflags &= ~ATA_PFLAG_EH_PENDING; + ap->excl_link = NULL; /* don't maintain exclusion over EH */ spin_unlock_irqrestore(ap->lock, flags); @@ -2474,6 +2475,10 @@ void ata_eh_finish(struct ata_port *ap) } } } + + /* make sure nr_active_links is zero after EH */ + WARN_ON(ap->nr_active_links); + ap->nr_active_links = 0; } /** diff --git a/include/linux/libata.h b/include/linux/libata.h index b0d4ca0d27b4..f9f81fd93293 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -216,6 +216,7 @@ enum { ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ @@ -579,11 +580,13 @@ struct ata_port { struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; unsigned long qc_allocated; unsigned int qc_active; + int nr_active_links; /* #links with active qcs */ struct ata_link link; /* host default link */ int nr_pmp_links; /* nr of available PMP links */ struct ata_link *pmp_link; /* array of PMP links */ + struct ata_link *excl_link; /* for PMP qc exclusion */ struct ata_port_stats stats; struct ata_host *host; @@ -1104,6 +1107,11 @@ static inline int ata_link_max_devices(const struct ata_link *link) return 1; } +static inline int ata_link_active(struct ata_link *link) +{ + return ata_tag_valid(link->active_tag) || link->sactive; +} + static inline struct ata_link *ata_port_first_link(struct ata_port *ap) { if (ap->nr_pmp_links) From ae791c05694d7391ee9261a0450a50f7e95aedfd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: [PATCH 2453/2804] libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB Some links on some PMPs locks up on SRST and/or report incorrect device signature. Implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB to handle these quirky links. NO_SRST makes EH avoid SRST. ASSUME_ATA and SEMB forces class code to ATA and SEMB_UNSUP respectively. Note that SEMB isn't currently supported yet so the _UNSUP variant is used. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 42 +++++++++++++++++++++++++++++++---------- include/linux/libata.h | 4 ++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5244723952c2..7be04bd30bfe 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1906,14 +1906,18 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, return 0; } -static int ata_eh_followup_srst_needed(int rc, int classify, +static int ata_eh_followup_srst_needed(struct ata_link *link, + int rc, int classify, const unsigned int *classes) { + if (link->flags & ATA_LFLAG_NO_SRST) + return 0; if (rc == -EAGAIN) return 1; if (rc != 0) return 0; - if (classify && classes[0] == ATA_DEV_UNKNOWN) + if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) && + classes[0] == ATA_DEV_UNKNOWN) return 1; return 0; } @@ -1940,7 +1944,8 @@ int ata_eh_reset(struct ata_link *link, int classify, */ action = ehc->i.action; ehc->i.action &= ~ATA_EH_RESET_MASK; - if (softreset && (!hardreset || (!sata_set_spd_needed(link) && + if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) && + !sata_set_spd_needed(link) && !(action & ATA_EH_HARDRESET)))) ehc->i.action |= ATA_EH_SOFTRESET; else @@ -2003,7 +2008,7 @@ int ata_eh_reset(struct ata_link *link, int classify, rc = ata_do_reset(link, reset, classes, deadline); if (reset == hardreset && - ata_eh_followup_srst_needed(rc, classify, classes)) { + ata_eh_followup_srst_needed(link, rc, classify, classes)) { /* okay, let's do follow-up softreset */ reset = softreset; @@ -2018,8 +2023,8 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); rc = ata_do_reset(link, reset, classes, deadline); - if (rc == 0 && classify && - classes[0] == ATA_DEV_UNKNOWN) { + if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN && + !(link->flags & ATA_LFLAG_ASSUME_CLASS)) { ata_link_printk(link, KERN_ERR, "classification failed\n"); rc = -EINVAL; @@ -2027,6 +2032,10 @@ int ata_eh_reset(struct ata_link *link, int classify, } } + /* if we skipped follow-up srst, clear rc */ + if (rc == -EAGAIN) + rc = 0; + if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { unsigned long now = jiffies; @@ -2051,12 +2060,25 @@ int ata_eh_reset(struct ata_link *link, int classify, if (rc == 0) { u32 sstatus; - /* After the reset, the device state is PIO 0 and the - * controller state is undefined. Record the mode. - */ - ata_link_for_each_dev(dev, link) + ata_link_for_each_dev(dev, link) { + /* After the reset, the device state is PIO 0 + * and the controller state is undefined. + * Record the mode. + */ dev->pio_mode = XFER_PIO_0; + if (ata_link_offline(link)) + continue; + + /* apply class override and convert UNKNOWN to NONE */ + if (link->flags & ATA_LFLAG_ASSUME_ATA) + classes[dev->devno] = ATA_DEV_ATA; + else if (link->flags & ATA_LFLAG_ASSUME_SEMB) + classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */ + else if (classes[dev->devno] == ATA_DEV_UNKNOWN) + classes[dev->devno] = ATA_DEV_NONE; + } + /* record current link speed */ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) link->sata_spd = (sstatus >> 4) & 0xf; diff --git a/include/linux/libata.h b/include/linux/libata.h index f9f81fd93293..6266fffb0eb3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -165,6 +165,10 @@ enum { ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H * Register FIS clearing BSY */ + ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */ + ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ + ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ From fd995f7039f1955ccc6b43e1e2d168060b31e4b2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: [PATCH 2454/2804] libata-pmp-prep: implement ATA_LFLAG_NO_RETRY Some PMP links are connected to internal pseudo devices which may come and go depending on situation. There's no reason to try hard to recover them. ATA_LFLAG_NO_RETRY tells EH to not retry if the device attached to the link fails. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 5 ++++- include/linux/libata.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7be04bd30bfe..8f8ed4dfb171 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2335,7 +2335,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, struct ata_eh_context *ehc = &link->eh_context; ata_link_for_each_dev(dev, link) { - ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + if (link->flags & ATA_LFLAG_NO_RETRY) + ehc->tries[dev->devno] = 1; + else + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; /* collect port action mask recorded in dev actions */ ehc->i.action |= ehc->i.dev_action[dev->devno] & diff --git a/include/linux/libata.h b/include/linux/libata.h index 6266fffb0eb3..adeee7397cdb 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -169,6 +169,7 @@ enum { ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ From f9df58cb27dfd605eced643bb3aa599fe4feeee8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:13 +0900 Subject: [PATCH 2455/2804] libata-pmp-prep: implement ATA_LFLAG_DISABLED Implement ATA_LFLAG_DISABLED. The flag indicates the link is disabled due to EH recovery failure. While a link is disabled, no EH action is taken on the link and suspend/resume become noop too. This will be used by PMP links to manage failed links. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 30 +++++++++++++++++++++++++++++- include/linux/libata.h | 3 +++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8f8ed4dfb171..fbbf79163900 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1308,6 +1308,7 @@ static void ata_eh_analyze_serror(struct ata_link *link) struct ata_eh_context *ehc = &link->eh_context; u32 serror = ehc->i.serror; unsigned int err_mask = 0, action = 0; + u32 hotplug_mask; if (serror & SERR_PERSISTENT) { err_mask |= AC_ERR_ATA_BUS; @@ -1326,7 +1327,20 @@ static void ata_eh_analyze_serror(struct ata_link *link) err_mask |= AC_ERR_SYSTEM; action |= ATA_EH_HARDRESET; } - if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) + + /* Determine whether a hotplug event has occurred. Both + * SError.N/X are considered hotplug events for enabled or + * host links. For disabled PMP links, only N bit is + * considered as X bit is left at 1 for link plugging. + */ + hotplug_mask = 0; + + if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) + hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; + else + hotplug_mask = SERR_PHYRDY_CHG; + + if (serror & hotplug_mask) ata_ehi_hotplugged(&ehc->i); ehc->i.err_mask |= err_mask; @@ -2227,6 +2241,10 @@ static int ata_eh_skip_recovery(struct ata_link *link) struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; + /* skip disabled links */ + if (link->flags & ATA_LFLAG_DISABLED) + return 1; + /* thaw frozen port, resume link and recover failed devices */ if ((link->ap->pflags & ATA_PFLAG_FROZEN) || (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link)) @@ -2327,6 +2345,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, struct ata_device *dev; int nr_failed_devs, nr_disabled_devs; int reset, rc; + unsigned long flags; DPRINTK("ENTER\n"); @@ -2334,6 +2353,15 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_port_for_each_link(link, ap) { struct ata_eh_context *ehc = &link->eh_context; + /* re-enable link? */ + if (ehc->i.action & ATA_EH_ENABLE_LINK) { + ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK); + spin_lock_irqsave(ap->lock, flags); + link->flags &= ~ATA_LFLAG_DISABLED; + spin_unlock_irqrestore(ap->lock, flags); + ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK); + } + ata_link_for_each_dev(dev, link) { if (link->flags & ATA_LFLAG_NO_RETRY) ehc->tries[dev->devno] = 1; diff --git a/include/linux/libata.h b/include/linux/libata.h index adeee7397cdb..2bd1d26c9c8d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -170,6 +170,7 @@ enum { ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ + ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ @@ -289,6 +290,7 @@ enum { ATA_EH_REVALIDATE = (1 << 0), ATA_EH_SOFTRESET = (1 << 1), ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, @@ -999,6 +1001,7 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) { ata_ehi_schedule_probe(ehi); ehi->flags |= ATA_EHI_HOTPLUGGED; + ehi->action |= ATA_EH_ENABLE_LINK; ehi->err_mask |= AC_ERR_ATA_BUS; } From 668108d73bbb1ae85f01db38d6be822fd28ece1f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:13 +0900 Subject: [PATCH 2456/2804] libata-pmp-prep: implement EH fast-fail path If PMP itself becomes inaccessible while trying to link a downstream link, spending time to recover the downstream link doesn't make any sense. Make EH skip retry and fail fast if -ERESTART is received. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index fbbf79163900..3c31e10caf21 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2050,7 +2050,7 @@ int ata_eh_reset(struct ata_link *link, int classify, if (rc == -EAGAIN) rc = 0; - if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { + if (rc && rc != -ERESTART && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { unsigned long now = jiffies; if (time_before(now, deadline)) { From e31e8531d668c9c4dc7883054788f89805188003 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:13 +0900 Subject: [PATCH 2457/2804] libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM Some pseudo devices fail PM commands unnecessarily aborting system suspend. Implement ATA_HORKAGE_SKIP_PM which makes libata skip PM commands for these devices. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 7 +++++++ include/linux/libata.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8ca2caeed017..451f79c6fbac 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -944,6 +944,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) goto invalid_fld; /* LOEJ bit set not supported */ if (((cdb[4] >> 4) & 0xf) != 0) goto invalid_fld; /* power conditions not supported */ + + if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) { + /* the device lacks PM support, finish without doing anything */ + scmd->result = SAM_STAT_GOOD; + return 1; + } + if (cdb[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 2bd1d26c9c8d..56b218771114 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -329,6 +329,7 @@ enum { ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */ ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ + ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ }; enum hsm_task_states { From 7d77b247088fb360aa74bfdd9e19bce1e1987668 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:13 +0900 Subject: [PATCH 2458/2804] libata-pmp-prep: implement sata_async_notification() AN serves multiple purposes. For ATAPI, it's used for media change notification. For PMP, for downstream PHY status change notification. Implement sata_async_notification() which demultiplexes AN. To avoid unnecessary port events, ATAPI AN is not enabled if PMP is attached but SNTF is not available. Signed-off-by: Tejun Heo Cc: Kriten Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 24 ++++--------- drivers/ata/libata-core.c | 13 ++++--- drivers/ata/libata-eh.c | 73 +++++++++++++++++++++++++++++++++++++++ drivers/ata/libata-scsi.c | 1 - drivers/ata/libata.h | 1 + drivers/ata/sata_sil24.c | 5 +-- include/linux/libata.h | 4 +-- 7 files changed, 93 insertions(+), 28 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index cf3404467ceb..9f3c591c7214 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1356,27 +1356,17 @@ static void ahci_port_intr(struct ata_port *ap) } if (status & PORT_IRQ_SDB_FIS) { - /* - * if this is an ATAPI device with AN turned on, - * then we should interrogate the device to - * determine the cause of the interrupt - * - * for AN - this we should check the SDB FIS - * and find the I and N bits set + /* If the 'N' bit in word 0 of the FIS is set, we just + * received asynchronous notification. Tell libata + * about it. Note that as the SDB FIS itself is + * accessible, SNotification can be emulated by the + * driver but don't bother for the time being. */ const __le32 *f = pp->rx_fis + RX_FIS_SDB; u32 f0 = le32_to_cpu(f[0]); - /* check the 'N' bit in word 0 of the FIS */ - if (f0 & (1 << 15)) { - int port_addr = ((f0 & 0x00000f00) >> 8); - struct ata_device *adev; - if (port_addr < ATA_MAX_DEVICES) { - adev = &ap->link.device[port_addr]; - if (adev->flags & ATA_DFLAG_AN) - ata_scsi_media_change_notify(adev); - } - } + if (f0 & (1 << 15)) + sata_async_notification(ap); } if (ap->link.sactive) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 376dbd80cc93..8b08e7bdd24d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2016,6 +2016,7 @@ int ata_dev_configure(struct ata_device *dev) else if (dev->class == ATA_DEV_ATAPI) { const char *cdb_intr_string = ""; const char *atapi_an_string = ""; + u32 sntf; rc = atapi_cdb_len(id); if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { @@ -2027,11 +2028,14 @@ int ata_dev_configure(struct ata_device *dev) } dev->cdb_len = (unsigned int) rc; - /* - * check to see if this ATAPI device supports - * Asynchronous Notification + /* Enable ATAPI AN if both the host and device have + * the support. If PMP is attached, SNTF is required + * to enable ATAPI AN to discern between PHY status + * changed notifications and ATAPI ANs. */ - if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id)) { + if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) && + (!ap->nr_pmp_links || + sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) { unsigned int err_mask; /* issue SET feature command to turn this on */ @@ -7248,6 +7252,7 @@ EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_link_abort); EXPORT_SYMBOL_GPL(ata_port_abort); EXPORT_SYMBOL_GPL(ata_port_freeze); +EXPORT_SYMBOL_GPL(sata_async_notification); EXPORT_SYMBOL_GPL(ata_eh_freeze_port); EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 3c31e10caf21..60186f8ac3a1 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -904,6 +904,79 @@ int ata_port_freeze(struct ata_port *ap) return nr_aborted; } +/** + * sata_async_notification - SATA async notification handler + * @ap: ATA port where async notification is received + * + * Handler to be called when async notification via SDB FIS is + * received. This function schedules EH if necessary. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * 1 if EH is scheduled, 0 otherwise. + */ +int sata_async_notification(struct ata_port *ap) +{ + u32 sntf; + int rc; + + if (!(ap->flags & ATA_FLAG_AN)) + return 0; + + rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); + if (rc == 0) + sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); + + if (!ap->nr_pmp_links || rc) { + /* PMP is not attached or SNTF is not available */ + if (!ap->nr_pmp_links) { + /* PMP is not attached. Check whether ATAPI + * AN is configured. If so, notify media + * change. + */ + struct ata_device *dev = ap->link.device; + + if ((dev->class == ATA_DEV_ATAPI) && + (dev->flags & ATA_DFLAG_AN)) + ata_scsi_media_change_notify(dev); + return 0; + } else { + /* PMP is attached but SNTF is not available. + * ATAPI async media change notification is + * not used. The PMP must be reporting PHY + * status change, schedule EH. + */ + ata_port_schedule_eh(ap); + return 1; + } + } else { + /* PMP is attached and SNTF is available */ + struct ata_link *link; + + /* check and notify ATAPI AN */ + ata_port_for_each_link(link, ap) { + if (!(sntf & (1 << link->pmp))) + continue; + + if ((link->device->class == ATA_DEV_ATAPI) && + (link->device->flags & ATA_DFLAG_AN)) + ata_scsi_media_change_notify(link->device); + } + + /* If PMP is reporting that PHY status of some + * downstream ports has changed, schedule EH. + */ + if (sntf & (1 << SATA_PMP_CTRL_PORT)) { + ata_port_schedule_eh(ap); + return 1; + } + + return 0; + } +} + /** * ata_eh_freeze_port - EH helper to freeze port * @ap: ATA port to freeze diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 451f79c6fbac..df2e05738f3b 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3244,7 +3244,6 @@ void ata_scsi_media_change_notify(struct ata_device *dev) scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE); #endif } -EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify); /** * ata_scsi_hotplug - SCSI part of hotplug diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0f3e355fdfd7..ebe22982e80c 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -119,6 +119,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht); extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); +extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 9acfce43bde4..b4f81eb8bbbe 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -821,11 +821,8 @@ static void sil24_error_intr(struct ata_port *ap) ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); if (irq_stat & PORT_IRQ_SDB_NOTIFY) { - struct ata_device *dev = ap->link.device; - ata_ehi_push_desc(ehi, "SDB notify"); - if (dev->flags & ATA_DFLAG_AN) - ata_scsi_media_change_notify(dev); + sata_async_notification(ap); } if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 56b218771114..cd9c2a28136a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -139,7 +139,7 @@ enum { ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ - ATA_DFLAG_AN = (1 << 7), /* device supports AN */ + ATA_DFLAG_AN = (1 << 7), /* AN configured */ ATA_DFLAG_CFG_MASK = (1 << 12) - 1, ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ @@ -787,7 +787,6 @@ extern void ata_host_init(struct ata_host *, struct device *, extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -extern void ata_scsi_media_change_notify(struct ata_device *atadev); extern void ata_sas_port_destroy(struct ata_port *); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, struct ata_port_info *, struct Scsi_Host *); @@ -953,6 +952,7 @@ extern void ata_port_schedule_eh(struct ata_port *ap); extern int ata_link_abort(struct ata_link *link); extern int ata_port_abort(struct ata_port *ap); extern int ata_port_freeze(struct ata_port *ap); +extern int sata_async_notification(struct ata_port *ap); extern void ata_eh_freeze_port(struct ata_port *ap); extern void ata_eh_thaw_port(struct ata_port *ap); From 1e582ba4ef6264dd8cb73250ebff767d0624d684 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Sep 2007 20:07:14 +0900 Subject: [PATCH 2459/2804] libata: fix ata_set_max_sectors() In ata_set_max_sectors(), the highest nibble in LBA28 mode was missing. This made drives sized between 8G and 128G with HPA turned on to be resized to under 8G. Fix it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8b08e7bdd24d..fd4563daacd1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -950,9 +950,12 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) tf.hob_lbal = (new_sectors >> 24) & 0xff; tf.hob_lbam = (new_sectors >> 32) & 0xff; tf.hob_lbah = (new_sectors >> 40) & 0xff; - } else + } else { tf.command = ATA_CMD_SET_MAX; + tf.device |= (new_sectors >> 24) & 0xf; + } + tf.protocol |= ATA_PROT_NODATA; tf.device |= ATA_LBA; From b6d6c74628767e1bd33c735b3b2ee7b132b4198e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Sep 2007 17:55:44 +0900 Subject: [PATCH 2460/2804] sata_via: kill SATA_PATA_SHARING register handling The SATA_PATA_SHARING register doesn't have anything to do with the SATA part of the controller. It indicates whether an extern SATA PHY is attached to the PATA part of the controller and if so how it is wired. As the PATA part is driven by pata_via, sata_via has no reason to care about that. Also, pata_via should work fine under all configurations. This patch removes unnecessary attach failures. It seems recent via chipsets are defaulting to different values or are actually connected to SATA PHY triggering this more often. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_via.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index f0757023ce9d..1dc9b4f2b2dc 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -57,7 +57,6 @@ enum { SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ SATA_INT_GATE = 0x41, /* SATA interrupt gating */ SATA_NATIVE_MODE = 0x42, /* Native mode enable */ - SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */ PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */ PATA_PIO_TIMING = 0xAB, /* PATA timing register */ @@ -68,7 +67,6 @@ enum { NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ - SATA_2DEV = (1 << 5), /* SATA is master/slave */ }; static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); @@ -508,7 +506,6 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_host *host; int board_id = (int) ent->driver_data; const int *bar_sizes; - u8 tmp8; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -517,19 +514,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - if (board_id == vt6420) { - pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); - if (tmp8 & SATA_2DEV) { - dev_printk(KERN_ERR, &pdev->dev, - "SATA master/slave not supported (0x%x)\n", - (int) tmp8); - return -EIO; - } - + if (board_id == vt6420) bar_sizes = &svia_bar_sizes[0]; - } else { + else bar_sizes = &vt6421_bar_sizes[0]; - } for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) if ((pci_resource_start(pdev, i) == 0) || From b90fe23bd51c6b1c298159591c833bdd24f55002 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Sat, 22 Sep 2007 08:20:09 +0530 Subject: [PATCH 2461/2804] libata: Fix build failure on ppc64 drivers/ata/pata_scc.c Little fixlets, that the build started erroring / warning about: drivers/ata/pata_scc.c: In function 'scc_bmdma_status': drivers/ata/pata_scc.c:734: error: structure has no member named 'active_tag' drivers/ata/pata_scc.c: In function 'scc_pata_prereset': drivers/ata/pata_scc.c:866: warning: passing arg 1 of 'ata_std_prereset' from incompatible pointer type drivers/ata/pata_scc.c: In function 'scc_error_handler': drivers/ata/pata_scc.c:908: warning: passing arg 2 of 'ata_bmdma_drive_eh' from incompatible pointer type drivers/ata/pata_scc.c:908: warning: passing arg 3 of 'ata_bmdma_drive_eh' from incompatible pointer type drivers/ata/pata_scc.c:908: warning: passing arg 5 of 'ata_bmdma_drive_eh' from incompatible pointer type make[2]: *** [drivers/ata/pata_scc.o] Error 1 Signed-off-by: Satyam Sharma Cc: Alan Cox Cc: Mel Gorman Signed-off-by: Jeff Garzik --- drivers/ata/pata_scc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 941b72bec836..55576138faea 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -603,16 +603,17 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, * Note: Original code is ata_std_softreset(). */ -static int scc_std_softreset (struct ata_port *ap, unsigned int *classes, - unsigned long deadline) +static int scc_std_softreset(struct ata_link *link, unsigned int *classes, + unsigned long deadline) { + struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0, err_mask; u8 err; DPRINTK("ENTER\n"); - if (ata_link_offline(&ap->link)) { + if (ata_link_offline(link)) { classes[0] = ATA_DEV_NONE; goto out; } @@ -703,7 +704,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc) printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME); out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT); /* TBD: SW reset */ - scc_std_softreset(ap, &classes, deadline); + scc_std_softreset(&ap->link, &classes, deadline); continue; } @@ -742,7 +743,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) void __iomem *mmio = ap->ioaddr.bmdma_addr; u8 host_stat = in_be32(mmio + SCC_DMA_STATUS); u32 int_status = in_be32(mmio + SCC_DMA_INTST); - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); static int retry = 0; /* return if IOS_SS is cleared */ @@ -871,10 +872,10 @@ static void scc_bmdma_freeze (struct ata_port *ap) * @deadline: deadline jiffies for the operation */ -static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline) +static int scc_pata_prereset(struct ata_link *link, unsigned long deadline) { - ap->cbl = ATA_CBL_PATA80; - return ata_std_prereset(ap, deadline); + link->ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(link, deadline); } /** @@ -885,8 +886,10 @@ static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline) * Note: Original code is ata_std_postreset(). */ -static void scc_std_postreset (struct ata_port *ap, unsigned int *classes) +static void scc_std_postreset(struct ata_link *link, unsigned int *classes) { + struct ata_port *ap = link->ap; + DPRINTK("ENTER\n"); /* is double-select really necessary? */ From 3cc3eb1148e4b2dfabf7a1dcf36fd8be1331ca95 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 26 Sep 2007 00:02:41 -0400 Subject: [PATCH 2462/2804] [libata] AHCI: enable AHCI mode, before using AHCI reset AHCI spec says host-reset bit may only be set when the ahci-enable bit is also set. Noticed by Peer Chen Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 9f3c591c7214..b615390b6b8a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -827,8 +827,14 @@ static int ahci_reset_controller(struct ata_host *host) void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; u32 tmp; - /* global controller reset */ + /* we must be in AHCI mode, before using anything + * AHCI-specific, such as HOST_RESET. + */ tmp = readl(mmio + HOST_CTL); + if (!(tmp & HOST_AHCI_EN)) + writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL); + + /* global controller reset */ if ((tmp & HOST_RESET) == 0) { writel(tmp | HOST_RESET, mmio + HOST_CTL); readl(mmio + HOST_CTL); /* flush */ From 21d2c925d3da6aabf9a0b34e95787202379f682a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 23:02:52 +0100 Subject: [PATCH 2463/2804] pata_atiixp: Audit notes on locking Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_atiixp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 95ed3071a0a0..9623f5295530 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -173,6 +173,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev) * * When DMA begins we need to ensure that the UDMA control * register for the channel is correctly set. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void atiixp_bmdma_start(struct ata_queued_cmd *qc) @@ -199,6 +202,9 @@ static void atiixp_bmdma_start(struct ata_queued_cmd *qc) * * DMA has completed. Clear the UDMA flag as the next operations will * be PIO ones not UDMA data transfer. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void atiixp_bmdma_stop(struct ata_queued_cmd *qc) From 06b74dd28fa607249c5e41e5f1f6dd1885fe0a0d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 15:23:17 +0100 Subject: [PATCH 2464/2804] pata_pdc202xx_old MWDMA fixes, and notes I've been doing an audit of this driver to try and find out why we have problems with some Clevo boxes that use it. Didn't get anywhere other than to discover all the bug reporters I have use vmware, which may or may not be chance. In the process however I did find out our MWDMA2 performance was a bit low and code review showed the MWDMA0/2 timings are reversed due to a thinko in the table ordering Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc202xx_old.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index fd4350029bc4..65d951618c60 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -9,7 +9,7 @@ * First cut with LBA48/ATAPI * * TODO: - * Channel interlock/reset on both required + * Channel interlock/reset on both required ? */ #include @@ -22,7 +22,7 @@ #include #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.3" static int pdc2026x_cable_detect(struct ata_port *ap) { @@ -106,9 +106,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) { 0x20, 0x01 } }; static u8 mdma_timing[3][2] = { - { 0x60, 0x03 }, - { 0x60, 0x04 }, { 0xe0, 0x0f }, + { 0x60, 0x04 }, + { 0x60, 0x03 }, }; u8 r_bp, r_cp; @@ -139,6 +139,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) * * In UDMA3 or higher we have to clock switch for the duration of the * DMA transfer sequence. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) @@ -187,6 +190,9 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) * * After a DMA completes we need to put the clock back to 33MHz for * PIO timings. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) @@ -206,7 +212,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) iowrite32(0, atapi_reg); iowrite8(ioread8(clock) & ~sel66, clock); } - /* Check we keep host level locking here */ /* Flip back to 33Mhz for PIO */ if (adev->dma_mode >= XFER_UDMA_2) iowrite8(ioread8(clock) & ~sel66, clock); From 78e70c237ffbf219680fb967624e1423e5c1f25a Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 27 Sep 2007 11:50:13 -0400 Subject: [PATCH 2465/2804] libata: correct kernel parameter in documentation. 'noacpi' isn't a standalone parameter, give it its prefix. Signed-off-by: Dave Jones Signed-off-by: Jeff Garzik --- Documentation/kernel-parameters.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a57c1f216b21..4881080b3388 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -864,6 +864,10 @@ and is between 256 and 4096 characters. It is defined in the file lasi= [HW,SCSI] PARISC LASI driver for the 53c700 chip Format: addr:,irq: + libata.noacpi [LIBATA] Disables use of ACPI in libata suspend/resume + when set. + Format: + load_ramdisk= [RAM] List of ramdisks to load from floppy See Documentation/ramdisk.txt. @@ -1080,10 +1084,6 @@ and is between 256 and 4096 characters. It is defined in the file emulation library even if a 387 maths coprocessor is present. - noacpi [LIBATA] Disables use of ACPI in libata suspend/resume - when set. - Format: - noaliencache [MM, NUMA, SLAB] Disables the allocation of alien caches in the slab allocator. Saves per-node memory, but will impact performance. From 7f567620ed32bea40a2acc25900c79db4dff96aa Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Sep 2007 06:29:23 -0700 Subject: [PATCH 2466/2804] libata: update spurious NCQ completion blacklist * The firmware version of ST3160812AS is "3.ADJ" no "3.AD". * Add several entries from various sources. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fd4563daacd1..7f424c4b1bb6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3891,9 +3891,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, }, { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, }, { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, + { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, }, { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, + { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, }, { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, - { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, }, + { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, }, + { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, }, { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, /* devices which puke on READ_NATIVE_MAX */ From 0b0a43e04ea671adc3cac085ee567d63c9ab3507 Mon Sep 17 00:00:00 2001 From: David Milburn Date: Fri, 28 Sep 2007 14:29:06 -0500 Subject: [PATCH 2467/2804] libata-core: blacklist HITACHI HDS drives using wildcard blacklist matching Blacklist HITACHI HDS7250SASUN500G and HITACHI HDS7225SBSUN250G drives using wildcard matching. Signed-off-by David Milburn Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7f424c4b1bb6..d2880b013c88 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3878,8 +3878,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* NCQ is broken */ { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ }, { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, - { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI", - ATA_HORKAGE_NONCQ }, + { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ }, + { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ }, /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ From c4b5b7b6c4423ec4ced4177c87d2da04de324028 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 29 Sep 2007 02:35:10 -0400 Subject: [PATCH 2468/2804] pata_ns87415: Initial cut at 87415/87560 IDE support Signed-off-by: Alan Cox [plus SuperIO fixes by Kyle McMartin] [plus a cleanup from me] Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 + drivers/ata/Makefile | 1 + drivers/ata/pata_ns87415.c | 467 +++++++++++++++++++++++++++++++++++++ 3 files changed, 477 insertions(+) create mode 100644 drivers/ata/pata_ns87415.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 3a737bdce2ec..cf960bd1c00a 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -441,6 +441,15 @@ config PATA_NS87410 If unsure, say N. +config PATA_NS87415 + tristate "Nat Semi NS87415 PATA support (Experimental)" + depends on PCI && EXPERIMENTAL + help + This option enables support for the National Semiconductor + NS87415 PCI-IDE controller. + + If unsure, say N. + config PATA_OPTI tristate "OPTI621/6215 PATA support (Very Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 4eb7fb44be3f..56bf13cbd198 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_PATA_IT8213) += pata_it8213.o obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o +obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c new file mode 100644 index 000000000000..bb97ef583f9b --- /dev/null +++ b/drivers/ata/pata_ns87415.c @@ -0,0 +1,467 @@ +/* + * pata_ns87415.c - NS87415 (non PARISC) PATA + * + * (C) 2005 Red Hat + * + * This is a fairly generic MWDMA controller. It has some limitations + * as it requires timing reloads on PIO/DMA transitions but it is otherwise + * fairly well designed. + * + * This driver assumes the firmware has left the chip in a valid ST506 + * compliant state, either legacy IRQ 14/15 or native INTA shared. You + * may need to add platform code if your system fails to do this. + * + * The same cell appears in the 87560 controller used by some PARISC + * systems. This has its own special mountain of errata. + * + * TODO: + * Test PARISC SuperIO + * Get someone to test on SPARC + * Implement lazy pio/dma switching for better performance + * 8bit shared timing. + * See if we need to kill the FIFO for ATAPI + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_ns87415" +#define DRV_VERSION "0.0.1" + +/** + * ns87415_set_mode - Initialize host controller mode timings + * @ap: Port whose timings we are configuring + * @adev: Device whose timings we are configuring + * @mode: Mode to set + * + * Program the mode registers for this controller, channel and + * device. Because the chip is quite an old design we have to do this + * for PIO/DMA switches. + * + * LOCKING: + * None (inherited from caller). + */ + +static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode) +{ + struct pci_dev *dev = to_pci_dev(ap->host->dev); + int unit = 2 * ap->port_no + adev->devno; + int timing = 0x44 + 2 * unit; + unsigned long T = 1000000000 / 33333; /* PCI clocks */ + struct ata_timing t; + u16 clocking; + u8 iordy; + u8 status; + + /* Timing register format is 17 - low nybble read timing with + the high nybble being 16 - x for recovery time in PCI clocks */ + + ata_timing_compute(adev, adev->pio_mode, &t, T, 0); + + clocking = 17 - FIT(t.active, 2, 17); + clocking |= (16 - FIT(t.recover, 1, 16)) << 4; + /* Use the same timing for read and write bytes */ + clocking |= (clocking << 8); + pci_write_config_word(dev, timing, clocking); + + /* Set the IORDY enable versus DMA enable on or off properly */ + pci_read_config_byte(dev, 0x42, &iordy); + iordy &= ~(1 << (4 + unit)); + if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev)) + iordy |= (1 << (4 + unit)); + + /* Paranoia: We shouldn't ever get here with busy write buffers + but if so wait */ + + pci_read_config_byte(dev, 0x43, &status); + while (status & 0x03) { + udelay(1); + pci_read_config_byte(dev, 0x43, &status); + } + /* Flip the IORDY/DMA bits now we are sure the write buffers are + clear */ + pci_write_config_byte(dev, 0x42, iordy); + + /* TODO: Set byte 54 command timing to the best 8bit + mode shared by all four devices */ +} + +/** + * ns87415_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: Device to program + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + ns87415_set_mode(ap, adev, adev->pio_mode); +} + +/** + * ns87415_bmdma_setup - Set up DMA + * @qc: Command block + * + * Set up for bus masterng DMA. We have to do this ourselves + * rather than use the helper due to a chip erratum + */ + +static void ns87415_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + u8 dmactl; + + /* load PRD table addr. */ + mb(); /* make sure PRD table writes are visible to controller */ + iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + + /* specify data direction, triple-check start bit is clear */ + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + /* Due to an erratum we need to write these bits to the wrong + place - which does save us an I/O bizarrely */ + dmactl |= ATA_DMA_INTR | ATA_DMA_ERR; + if (!rw) + dmactl |= ATA_DMA_WR; + iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +/** + * ns87415_bmdma_start - Begin DMA transfer + * @qc: Command block + * + * Switch the timings for the chip and set up for a DMA transfer + * before the DMA burst begins. + * + * FIXME: We should do lazy switching on bmdma_start versus + * ata_pio_data_xfer for better performance. + */ + +static void ns87415_bmdma_start(struct ata_queued_cmd *qc) +{ + ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode); + ata_bmdma_start(qc); +} + +/** + * ns87415_bmdma_stop - End DMA transfer + * @qc: Command block + * + * End DMA mode and switch the controller back into PIO mode + */ + +static void ns87415_bmdma_stop(struct ata_queued_cmd *qc) +{ + ata_bmdma_stop(qc); + ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode); +} + +/** + * ns87415_bmdma_irq_clear - Clear interrupt + * @ap: Channel to clear + * + * Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the + * error bits) are reset by writing to register 00 or 08. + */ + +static void ns87415_bmdma_irq_clear(struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + if (!mmio) + return; + iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR), + mmio + ATA_DMA_CMD); +} + +/** + * ns87415_check_atapi_dma - ATAPI DMA filter + * @qc: Command block + * + * Disable ATAPI DMA (for now). We may be able to do DMA if we + * kill the prefetching. This isn't clear. + */ + +static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc) +{ + return -EOPNOTSUPP; +} + +#if defined(CONFIG_SUPERIO) + +/* SUPERIO 87560 is a PoS chip that NatSem denies exists. + * Unfortunately, it's built-in on all Astro-based PA-RISC workstations + * which use the integrated NS87514 cell for CD-ROM support. + * i.e we have to support for CD-ROM installs. + * See drivers/parisc/superio.c for more gory details. + * + * Workarounds taken from drivers/ide/pci/ns87415.c + */ + +#include + +/** + * ns87560_read_buggy - workaround buggy Super I/O chip + * @port: Port to read + * + * Work around chipset problems in the 87560 SuperIO chip + */ + +static u8 ns87560_read_buggy(void __iomem *port) +{ + u8 tmp; + int retries = SUPERIO_IDE_MAX_RETRIES; + do { + tmp = ioread8(port); + if (tmp != 0) + return tmp; + udelay(50); + } while(retries-- > 0); + return tmp; +} + +/** + * ns87560_check_status + * @ap: channel to check + * + * Return the status of the channel working around the + * 87560 flaws. + */ + +static u8 ns87560_check_status(struct ata_port *ap) +{ + return ns87560_read_buggy(ap->ioaddr.status_addr); +} + +/** + * ns87560_tf_read - input device's ATA taskfile shadow registers + * @ap: Port from which input is read + * @tf: ATA taskfile register set for storing input + * + * Reads ATA taskfile registers for currently-selected device + * into @tf. Work around the 87560 bugs. + * + * LOCKING: + * Inherited from caller. + */ +void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ns87560_check_status(ap); + tf->feature = ioread8(ioaddr->error_addr); + tf->nsect = ioread8(ioaddr->nsect_addr); + tf->lbal = ioread8(ioaddr->lbal_addr); + tf->lbam = ioread8(ioaddr->lbam_addr); + tf->lbah = ioread8(ioaddr->lbah_addr); + tf->device = ns87560_read_buggy(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ioread8(ioaddr->error_addr); + tf->hob_nsect = ioread8(ioaddr->nsect_addr); + tf->hob_lbal = ioread8(ioaddr->lbal_addr); + tf->hob_lbam = ioread8(ioaddr->lbam_addr); + tf->hob_lbah = ioread8(ioaddr->lbah_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } +} + +/** + * ns87560_bmdma_status + * @ap: channel to check + * + * Return the DMA status of the channel working around the + * 87560 flaws. + */ + +static u8 ns87560_bmdma_status(struct ata_port *ap) +{ + return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); +} + +static const struct ata_port_operations ns87560_pata_ops = { + .set_piomode = ns87415_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ns87560_tf_read, + .check_status = ns87560_check_status, + .check_atapi_dma = ns87415_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ns87415_bmdma_setup, + .bmdma_start = ns87415_bmdma_start, + .bmdma_stop = ns87415_bmdma_stop, + .bmdma_status = ns87560_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ns87415_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +#endif /* 87560 SuperIO Support */ + + +static const struct ata_port_operations ns87415_pata_ops = { + .set_piomode = ns87415_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .check_atapi_dma = ns87415_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ns87415_bmdma_setup, + .bmdma_start = ns87415_bmdma_start, + .bmdma_stop = ns87415_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ns87415_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +static struct scsi_host_template ns87415_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + + +/** + * ns87415_init_one - Register 87415 ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in ns87415_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 ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + static const struct ata_port_info info = { + .sht = &ns87415_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .port_ops = &ns87415_pata_ops, + }; + const struct ata_port_info *ppi[] = { &info, NULL }; +#if defined(CONFIG_SUPERIO) + static const struct ata_port_info info87560 = { + .sht = &ns87415_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .port_ops = &ns87560_pata_ops, + }; + + if (PCI_SLOT(pdev->devfn) == 0x0E) + ppi[0] = &info87560; +#endif + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + /* Select 512 byte sectors */ + pci_write_config_byte(pdev, 0x55, 0xEE); + /* Select PIO0 8bit clocking */ + pci_write_config_byte(pdev, 0x54, 0xB7); + return ata_pci_init_one(pdev, ppi); +} + +static const struct pci_device_id ns87415_pci_tbl[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), }, + + { } /* terminate list */ +}; + +static struct pci_driver ns87415_pci_driver = { + .name = DRV_NAME, + .id_table = ns87415_pci_tbl, + .probe = ns87415_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif +}; + +static int __init ns87415_init(void) +{ + return pci_register_driver(&ns87415_pci_driver); +} + +static void __exit ns87415_exit(void) +{ + pci_unregister_driver(&ns87415_pci_driver); +} + +module_init(ns87415_init); +module_exit(ns87415_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); +MODULE_VERSION(DRV_VERSION); From 54174db300ee1bac632d62e4ac37fe02e47d1f18 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 29 Sep 2007 04:01:43 -0400 Subject: [PATCH 2469/2804] [libata] ata_piix: add HP compaq laptop to short cable list Reported by Andreas Messer. Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 8dc15a6cea72..e783e678acf5 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -598,6 +598,7 @@ static const struct ich_laptop ich_laptop[] = { { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ + { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ /* end marker */ { 0, } From 93328e1145c1989d1a214d34ac4e968dea7f7ed7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 29 Sep 2007 04:06:48 -0400 Subject: [PATCH 2470/2804] [PATCH] libata: Fix HPA handling regression Restore the support for handling drives that report one sector too many (ie SCSI not ATA style). This worked before the HPA update but was removed in that process. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 7 ++++++- include/linux/libata.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d2880b013c88..eb9709864a21 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -915,7 +915,8 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) *max_sectors = ata_tf_to_lba48(&tf); else *max_sectors = ata_tf_to_lba(&tf); - + if (dev->horkage & ATA_HORKAGE_HPA_SIZE) + (*max_sectors)--; return 0; } @@ -3905,6 +3906,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA }, { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA }, + /* Devices which report 1 sector over size HPA */ + { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, + { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, + /* End Marker */ { } }; diff --git a/include/linux/libata.h b/include/linux/libata.h index cd9c2a28136a..f9ed198e4fcd 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -330,6 +330,7 @@ enum { ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */ ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ + ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ }; enum hsm_task_states { From 3495de733633d24ee97852080b737b436c110d6e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:53 +0900 Subject: [PATCH 2471/2804] libata-pmp: update ata_eh_reset() for PMP PMP always requires SRST to be enabled. Also, hardreset reports classification code from the first device when PMP is attached, not from the PMP. Update ata_eh_reset() such that followup softreset is performed if the controller is PMP capable and the host link is being reset. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 60186f8ac3a1..687419b66708 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2003,6 +2003,8 @@ static int ata_eh_followup_srst_needed(struct ata_link *link, return 1; if (rc != 0) return 0; + if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) + return 1; if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) && classes[0] == ATA_DEV_UNKNOWN) return 1; From 3af9a77af9e2b72366363864bfcd3d51465ff98a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: [PATCH 2472/2804] libata-pmp: implement Port Multiplier support Implement Port Multiplier support. To support PMP, a LLDD has to supply ops->pmp_read() and pmp_write(). If non-null, ->pmp_attach and ->pmp_detach are called on PMP attach and detach, respectively. ->pmp_read/write() can be called while the port is frozen, so they must be implemented by polling. This patch supplies several helpers to ease ->pmp_read/write() implementation. Also, irq_handler and error_handler must be PMP aware. Most of PMP aware EH can be done by calling ata_pmp_do_eh() with appropriate methods. PMP EH uses separate set of reset methods and this patch implements standard prereset, hardreset and postreset methods. This patch only implements PMP support. The next patch will integrate PMP into the reset of libata and thus enable PMP support. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/Makefile | 3 +- drivers/ata/libata-core.c | 11 + drivers/ata/libata-pmp.c | 1182 +++++++++++++++++++++++++++++++++++++ drivers/ata/libata.h | 5 + include/linux/libata.h | 19 + 5 files changed, 1219 insertions(+), 1 deletion(-) create mode 100644 drivers/ata/libata-pmp.c diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 56bf13cbd198..7e937519a930 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -71,5 +71,6 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o -libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o +libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o \ + libata-pmp.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index eb9709864a21..9e7f55b71044 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3865,6 +3865,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "IOMEGA ZIP 250 ATAPI", NULL, ATA_HORKAGE_NODMA }, /* temporary fix */ { "IOMEGA ZIP 250 ATAPI Floppy", NULL, ATA_HORKAGE_NODMA }, + /* Odd clown on sil3726/4726 PMPs */ + { "Config Disk", NULL, ATA_HORKAGE_NODMA | + ATA_HORKAGE_SKIP_PM }, /* Weird ATAPI devices */ { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 }, @@ -7251,6 +7254,14 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ +EXPORT_SYMBOL_GPL(sata_pmp_read_init_tf); +EXPORT_SYMBOL_GPL(sata_pmp_read_val); +EXPORT_SYMBOL_GPL(sata_pmp_write_init_tf); +EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); +EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); +EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); +EXPORT_SYMBOL_GPL(sata_pmp_do_eh); + EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c new file mode 100644 index 000000000000..671d171055a3 --- /dev/null +++ b/drivers/ata/libata-pmp.c @@ -0,0 +1,1182 @@ +/* + * libata-pmp.c - libata port multiplier support + * + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#include +#include +#include "libata.h" + +/** + * sata_pmp_read - read PMP register + * @link: link to read PMP register for + * @reg: register to read + * @r_val: resulting value + * + * Wrapper around ap->ops->pmp_read to make it easier to call and + * nomarlize error return value. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) +{ + struct ata_port *ap = link->ap; + struct ata_device *pmp_dev = ap->link.device; + int rc; + + might_sleep(); + + rc = ap->ops->pmp_read(pmp_dev, link->pmp, reg, r_val); + if (rc) + rc = -EIO; + return rc; +} + +/** + * sata_pmp_write - write PMP register + * @link: link to write PMP register for + * @reg: register to write + * @r_val: value to write + * + * Wrapper around ap->ops->pmp_write to make it easier to call + * and nomarlize error return value. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_write(struct ata_link *link, int reg, u32 val) +{ + struct ata_port *ap = link->ap; + struct ata_device *pmp_dev = ap->link.device; + int rc; + + might_sleep(); + + rc = ap->ops->pmp_write(pmp_dev, link->pmp, reg, val); + if (rc) + rc = -EIO; + return rc; +} + +/** + * sata_pmp_read_init_tf - initialize TF for PMP read + * @tf: taskfile to initialize + * @dev: PMP dev + * @pmp: port multiplier port number + * @reg: register to read + * + * Initialize @tf for PMP read command. + * + * LOCKING: + * None. + */ +void sata_pmp_read_init_tf(struct ata_taskfile *tf, + struct ata_device *dev, int pmp, int reg) +{ + ata_tf_init(dev, tf); + tf->command = ATA_CMD_PMP_READ; + tf->protocol = ATA_PROT_NODATA; + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->feature = reg; + tf->device = pmp; +} + +/** + * sata_pmp_read_val - extract PMP read result from TF + * @tf: target TF + * + * Determine PMP read result from @tf. + * + * LOCKING: + * None. + */ +u32 sata_pmp_read_val(const struct ata_taskfile *tf) +{ + return tf->nsect | tf->lbal << 8 | tf->lbam << 16 | tf->lbah << 24; +} + +/** + * sata_pmp_read_init_tf - initialize TF for PMP write + * @tf: taskfile to initialize + * @dev: PMP dev + * @pmp: port multiplier port number + * @reg: register to read + * @val: value to write + * + * Initialize @tf for PMP write command. + * + * LOCKING: + * None. + */ +void sata_pmp_write_init_tf(struct ata_taskfile *tf, + struct ata_device *dev, int pmp, int reg, u32 val) +{ + ata_tf_init(dev, tf); + tf->command = ATA_CMD_PMP_WRITE; + tf->protocol = ATA_PROT_NODATA; + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->feature = reg; + tf->device = pmp; + tf->nsect = val & 0xff; + tf->lbal = (val >> 8) & 0xff; + tf->lbam = (val >> 16) & 0xff; + tf->lbah = (val >> 24) & 0xff; +} + +/** + * sata_pmp_scr_read - read PSCR + * @link: ATA link to read PSCR for + * @reg: PSCR to read + * @r_val: resulting value + * + * Read PSCR @reg into @r_val for @link, to be called from + * ata_scr_read(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val) +{ + if (reg > SATA_PMP_PSCR_CONTROL) + return -EINVAL; + + return sata_pmp_read(link, reg, r_val); +} + +/** + * sata_pmp_scr_write - write PSCR + * @link: ATA link to write PSCR for + * @reg: PSCR to write + * @val: value to be written + * + * Write @val to PSCR @reg for @link, to be called from + * ata_scr_write() and ata_scr_write_flush(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) +{ + if (reg > SATA_PMP_PSCR_CONTROL) + return -EINVAL; + + return sata_pmp_write(link, reg, val); +} + +/** + * sata_pmp_std_prereset - prepare PMP link for reset + * @link: link to be reset + * @deadline: deadline jiffies for the operation + * + * @link is about to be reset. Initialize it. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline) +{ + struct ata_eh_context *ehc = &link->eh_context; + const unsigned long *timing = sata_ehc_deb_timing(ehc); + int rc; + + /* force HRST? */ + if (link->flags & ATA_LFLAG_NO_SRST) + ehc->i.action |= ATA_EH_HARDRESET; + + /* handle link resume */ + if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && + (link->flags & ATA_LFLAG_HRST_TO_RESUME)) + ehc->i.action |= ATA_EH_HARDRESET; + + /* if we're about to do hardreset, nothing more to do */ + if (ehc->i.action & ATA_EH_HARDRESET) + return 0; + + /* resume link */ + rc = sata_link_resume(link, timing, deadline); + if (rc) { + /* phy resume failed */ + ata_link_printk(link, KERN_WARNING, "failed to resume link " + "for reset (errno=%d)\n", rc); + return rc; + } + + /* clear SError bits including .X which blocks the port when set */ + rc = sata_scr_write(link, SCR_ERROR, 0xffffffff); + if (rc) { + ata_link_printk(link, KERN_ERR, + "failed to clear SError (errno=%d)\n", rc); + return rc; + } + + return 0; +} + +/** + * sata_pmp_std_hardreset - standard hardreset method for PMP link + * @link: link to be reset + * @class: resulting class of attached device + * @deadline: deadline jiffies for the operation + * + * Hardreset PMP port @link. Note that this function doesn't + * wait for BSY clearance. There simply isn't a generic way to + * wait the event. Instead, this function return -EAGAIN thus + * telling libata-EH to followup with softreset. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + u32 tmp; + int rc; + + DPRINTK("ENTER\n"); + + /* do hardreset */ + rc = sata_link_hardreset(link, timing, deadline); + if (rc) { + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + goto out; + } + + /* clear SError bits including .X which blocks the port when set */ + rc = sata_scr_write(link, SCR_ERROR, 0xffffffff); + if (rc) { + ata_link_printk(link, KERN_ERR, "failed to clear SError " + "during hardreset (errno=%d)\n", rc); + goto out; + } + + /* if device is present, follow up with srst to wait for !BSY */ + if (ata_link_online(link)) + rc = -EAGAIN; + out: + /* if SCR isn't accessible, we need to reset the PMP */ + if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp)) + rc = -ERESTART; + + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * ata_std_postreset - standard postreset method for PMP link + * @link: the target ata_link + * @classes: classes of attached devices + * + * This function is invoked after a successful reset. Note that + * the device might have been reset more than once using + * different reset methods before postreset is invoked. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class) +{ + u32 serror; + + DPRINTK("ENTER\n"); + + /* clear SError */ + if (sata_scr_read(link, SCR_ERROR, &serror) == 0) + sata_scr_write(link, SCR_ERROR, serror); + + /* print link status */ + sata_print_link_status(link); + + DPRINTK("EXIT\n"); +} + +/** + * sata_pmp_read_gscr - read GSCR block of SATA PMP + * @dev: PMP device + * @gscr: buffer to read GSCR block into + * + * Read selected PMP GSCRs from the PMP at @dev. This will serve + * as configuration and identification info for the PMP. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr) +{ + static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 }; + int i, rc; + + for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) { + int reg = gscr_to_read[i]; + + rc = sata_pmp_read(dev->link, reg, &gscr[reg]); + if (rc) { + ata_dev_printk(dev, KERN_ERR, "failed to read " + "PMP GSCR[%d] (errno=%d)\n", reg, rc); + return rc; + } + } + + return 0; +} + +static const char *sata_pmp_spec_rev_str(const u32 *gscr) +{ + u32 rev = gscr[SATA_PMP_GSCR_REV]; + + if (rev & (1 << 2)) + return "1.1"; + if (rev & (1 << 1)) + return "1.0"; + return ""; +} + +static int sata_pmp_configure(struct ata_device *dev, int print_info) +{ + struct ata_port *ap = dev->link->ap; + u32 *gscr = dev->gscr; + const char *reason; + int nr_ports, rc; + + nr_ports = sata_pmp_gscr_ports(gscr); + + if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) { + rc = -EINVAL; + reason = "invalid nr_ports"; + goto fail; + } + + if ((ap->flags & ATA_FLAG_AN) && + (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY)) + dev->flags |= ATA_DFLAG_AN; + + /* monitor SERR_PHYRDY_CHG on fan-out ports */ + rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN, SERR_PHYRDY_CHG); + if (rc) { + reason = "failed to write GSCR_ERROR_EN"; + goto fail; + } + + /* turn off notification till fan-out ports are reset and configured */ + if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) { + gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY; + + rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN, + gscr[SATA_PMP_GSCR_FEAT_EN]); + if (rc) { + reason = "failed to write GSCR_FEAT_EN"; + goto fail; + } + } + + if (print_info) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, " + "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n", + sata_pmp_spec_rev_str(gscr), + sata_pmp_gscr_vendor(gscr), + sata_pmp_gscr_devid(gscr), + sata_pmp_gscr_rev(gscr), + nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN], + gscr[SATA_PMP_GSCR_FEAT]); + + if (!(dev->flags & ATA_DFLAG_AN)) + ata_dev_printk(dev, KERN_INFO, + "Asynchronous notification not supported, " + "hotplug won't\n work on fan-out " + "ports. Use warm-plug instead.\n"); + } + + return 0; + + fail: + ata_dev_printk(dev, KERN_ERR, + "failed to configure Port Multiplier (%s)\n", reason); + return rc; +} + +static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) +{ + struct ata_link *pmp_link = ap->pmp_link; + int i; + + if (!pmp_link) { + pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS, + GFP_NOIO); + if (!pmp_link) + return -ENOMEM; + + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) + ata_link_init(ap, &pmp_link[i], i); + + ap->pmp_link = pmp_link; + } + + for (i = 0; i < nr_ports; i++) { + struct ata_link *link = &pmp_link[i]; + struct ata_eh_context *ehc = &link->eh_context; + + link->flags = 0; + ehc->i.probe_mask |= 1; + ehc->i.action |= ATA_EH_SOFTRESET; + ehc->i.flags |= ATA_EHI_RESUME_LINK; + } + + return 0; +} + +static void sata_pmp_quirks(struct ata_port *ap) +{ + u32 *gscr = ap->link.device->gscr; + u16 vendor = sata_pmp_gscr_vendor(gscr); + u16 devid = sata_pmp_gscr_devid(gscr); + struct ata_link *link; + + if (vendor == 0x1095 && devid == 0x3726) { + /* sil3726 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 5) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* port 5 is for SEMB device and it doesn't like SRST */ + if (link->pmp == 5) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_SEMB; + } + } else if (vendor == 0x1095 && devid == 0x4723) { + /* sil4723 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 2) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* the config device at port 2 locks up on SRST */ + if (link->pmp == 2) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; + } + } else if (vendor == 0x1095 && devid == 0x4726) { + /* sil4726 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 5) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* The config device, which can be either at + * port 0 or 5, locks up on SRST. + */ + if (link->pmp == 0 || link->pmp == 5) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; + + /* Port 6 is for SEMB device which doesn't + * like SRST either. + */ + if (link->pmp == 6) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_SEMB; + } + } else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 || + devid == 0x5734 || devid == 0x5744)) { + /* sil5723/5744 quirks */ + + /* sil5723/5744 has either two or three downstream + * ports depending on operation mode. The last port + * is empty if any actual IO device is available or + * occupied by a pseudo configuration device + * otherwise. Don't try hard to recover it. + */ + ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; + } else if (vendor == 0x11ab && devid == 0x4140) { + /* Marvell 88SM4140 quirks. Fan-out ports require PHY + * reset to work; other than that, it behaves very + * nicely. + */ + ata_port_for_each_link(link, ap) + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + } +} + +/** + * sata_pmp_attach - attach a SATA PMP device + * @dev: SATA PMP device to attach + * + * Configure and attach SATA PMP device @dev. This function is + * also responsible for allocating and initializing PMP links. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_attach(struct ata_device *dev) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + unsigned long flags; + struct ata_link *tlink; + int rc; + + /* is it hanging off the right place? */ + if (!(ap->flags & ATA_FLAG_PMP)) { + ata_dev_printk(dev, KERN_ERR, + "host does not support Port Multiplier\n"); + return -EINVAL; + } + + if (!ata_is_host_link(link)) { + ata_dev_printk(dev, KERN_ERR, + "Port Multipliers cannot be nested\n"); + return -EINVAL; + } + + if (dev->devno) { + ata_dev_printk(dev, KERN_ERR, + "Port Multiplier must be the first device\n"); + return -EINVAL; + } + + WARN_ON(link->pmp != 0); + link->pmp = SATA_PMP_CTRL_PORT; + + /* read GSCR block */ + rc = sata_pmp_read_gscr(dev, dev->gscr); + if (rc) + goto fail; + + /* config PMP */ + rc = sata_pmp_configure(dev, 1); + if (rc) + goto fail; + + rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr)); + if (rc) { + ata_dev_printk(dev, KERN_INFO, + "failed to initialize PMP links\n"); + goto fail; + } + + /* attach it */ + spin_lock_irqsave(ap->lock, flags); + WARN_ON(ap->nr_pmp_links); + ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr); + spin_unlock_irqrestore(ap->lock, flags); + + sata_pmp_quirks(ap); + + if (ap->ops->pmp_attach) + ap->ops->pmp_attach(ap); + + ata_port_for_each_link(tlink, ap) + sata_link_init_spd(tlink); + + return 0; + + fail: + link->pmp = 0; + return rc; +} + +/** + * sata_pmp_detach - detach a SATA PMP device + * @dev: SATA PMP device to detach + * + * Detach SATA PMP device @dev. This function is also + * responsible for deconfiguring PMP links. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void sata_pmp_detach(struct ata_device *dev) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + struct ata_link *tlink; + unsigned long flags; + + ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n"); + + WARN_ON(!ata_is_host_link(link) || dev->devno || + link->pmp != SATA_PMP_CTRL_PORT); + + if (ap->ops->pmp_detach) + ap->ops->pmp_detach(ap); + + ata_port_for_each_link(tlink, ap) + ata_eh_detach_dev(tlink->device); + + spin_lock_irqsave(ap->lock, flags); + ap->nr_pmp_links = 0; + link->pmp = 0; + spin_unlock_irqrestore(ap->lock, flags); +} + +/** + * sata_pmp_same_pmp - does new GSCR matches the configured PMP? + * @dev: PMP device to compare against + * @new_gscr: GSCR block of the new device + * + * Compare @new_gscr against @dev and determine whether @dev is + * the PMP described by @new_gscr. + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if @dev matches @new_gscr, 0 otherwise. + */ +static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr) +{ + const u32 *old_gscr = dev->gscr; + u16 old_vendor, new_vendor, old_devid, new_devid; + int old_nr_ports, new_nr_ports; + + old_vendor = sata_pmp_gscr_vendor(old_gscr); + new_vendor = sata_pmp_gscr_vendor(new_gscr); + old_devid = sata_pmp_gscr_devid(old_gscr); + new_devid = sata_pmp_gscr_devid(new_gscr); + old_nr_ports = sata_pmp_gscr_ports(old_gscr); + new_nr_ports = sata_pmp_gscr_ports(new_gscr); + + if (old_vendor != new_vendor) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "vendor mismatch '0x%x' != '0x%x'\n", + old_vendor, new_vendor); + return 0; + } + + if (old_devid != new_devid) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "device ID mismatch '0x%x' != '0x%x'\n", + old_devid, new_devid); + return 0; + } + + if (old_nr_ports != new_nr_ports) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "nr_ports mismatch '0x%x' != '0x%x'\n", + old_nr_ports, new_nr_ports); + return 0; + } + + return 1; +} + +/** + * sata_pmp_revalidate - revalidate SATA PMP + * @dev: PMP device to revalidate + * @new_class: new class code + * + * Re-read GSCR block and make sure @dev is still attached to the + * port and properly configured. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + u32 *gscr = (void *)ap->sector_buf; + int rc; + + DPRINTK("ENTER\n"); + + ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE); + + if (!ata_dev_enabled(dev)) { + rc = -ENODEV; + goto fail; + } + + /* wrong class? */ + if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) { + rc = -ENODEV; + goto fail; + } + + /* read GSCR */ + rc = sata_pmp_read_gscr(dev, gscr); + if (rc) + goto fail; + + /* is the pmp still there? */ + if (!sata_pmp_same_pmp(dev, gscr)) { + rc = -ENODEV; + goto fail; + } + + memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS); + + rc = sata_pmp_configure(dev, 0); + if (rc) + goto fail; + + ata_eh_done(link, NULL, ATA_EH_REVALIDATE); + + DPRINTK("EXIT, rc=0\n"); + return 0; + + fail: + ata_dev_printk(dev, KERN_ERR, + "PMP revalidation failed (errno=%d)\n", rc); + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * sata_pmp_revalidate_quick - revalidate SATA PMP quickly + * @dev: PMP device to revalidate + * + * Make sure the attached PMP is accessible. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int sata_pmp_revalidate_quick(struct ata_device *dev) +{ + u32 prod_id; + int rc; + + rc = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id); + if (rc) { + ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID\n"); + return rc; + } + + if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) { + ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n"); + /* something weird is going on, request full PMP recovery */ + return -EIO; + } + + return 0; +} + +/** + * sata_pmp_eh_recover_pmp - recover PMP + * @ap: ATA port PMP is attached to + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * + * Recover PMP attached to @ap. Recovery procedure is somewhat + * similar to that of ata_eh_recover() except that reset should + * always be performed in hard->soft sequence and recovery + * failure results in PMP detachment. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_eh_recover_pmp(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev = link->device; + int tries = ATA_EH_PMP_TRIES; + int detach = 0, rc = 0; + int reval_failed = 0; + + DPRINTK("ENTER\n"); + + if (dev->flags & ATA_DFLAG_DETACH) { + detach = 1; + goto fail; + } + + retry: + ehc->classes[0] = ATA_DEV_UNKNOWN; + + if (ehc->i.action & ATA_EH_RESET_MASK) { + struct ata_link *tlink; + + ata_eh_freeze_port(ap); + + /* reset */ + ehc->i.action = ATA_EH_HARDRESET; + rc = ata_eh_reset(link, 0, prereset, softreset, hardreset, + postreset); + if (rc) { + ata_link_printk(link, KERN_ERR, + "failed to reset PMP, giving up\n"); + goto fail; + } + + ata_eh_thaw_port(ap); + + /* PMP is reset, SErrors cannot be trusted, scan all */ + ata_port_for_each_link(tlink, ap) + ata_ehi_schedule_probe(&tlink->eh_context.i); + } + + /* If revalidation is requested, revalidate and reconfigure; + * otherwise, do quick revalidation. + */ + if (ehc->i.action & ATA_EH_REVALIDATE) + rc = sata_pmp_revalidate(dev, ehc->classes[0]); + else + rc = sata_pmp_revalidate_quick(dev); + + if (rc) { + tries--; + + if (rc == -ENODEV) { + ehc->i.probe_mask |= 1; + detach = 1; + /* give it just two more chances */ + tries = min(tries, 2); + } + + if (tries) { + int sleep = ehc->i.flags & ATA_EHI_DID_RESET; + + /* consecutive revalidation failures? speed down */ + if (reval_failed) + sata_down_spd_limit(link); + else + reval_failed = 1; + + ata_dev_printk(dev, KERN_WARNING, + "retrying hardreset%s\n", + sleep ? " in 5 secs" : ""); + if (sleep) + ssleep(5); + ehc->i.action |= ATA_EH_HARDRESET; + goto retry; + } else { + ata_dev_printk(dev, KERN_ERR, "failed to recover PMP " + "after %d tries, giving up\n", + ATA_EH_PMP_TRIES); + goto fail; + } + } + + /* okay, PMP resurrected */ + ehc->i.flags = 0; + + DPRINTK("EXIT, rc=0\n"); + return 0; + + fail: + sata_pmp_detach(dev); + if (detach) + ata_eh_detach_dev(dev); + else + ata_dev_disable(dev); + + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap) +{ + struct ata_link *link; + unsigned long flags; + int rc; + + spin_lock_irqsave(ap->lock, flags); + + ata_port_for_each_link(link, ap) { + if (!(link->flags & ATA_LFLAG_DISABLED)) + continue; + + spin_unlock_irqrestore(ap->lock, flags); + + /* Some PMPs require hardreset sequence to get + * SError.N working. + */ + if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) && + (link->eh_context.i.flags & ATA_EHI_RESUME_LINK)) + sata_link_hardreset(link, sata_deb_timing_normal, + jiffies + ATA_TMOUT_INTERNAL_QUICK); + + /* unconditionally clear SError.N */ + rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG); + if (rc) { + ata_link_printk(link, KERN_ERR, "failed to clear " + "SError.N (errno=%d)\n", rc); + return rc; + } + + spin_lock_irqsave(ap->lock, flags); + } + + spin_unlock_irqrestore(ap->lock, flags); + + return 0; +} + +static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries) +{ + struct ata_port *ap = link->ap; + unsigned long flags; + + if (link_tries[link->pmp] && --link_tries[link->pmp]) + return 1; + + /* disable this link */ + if (!(link->flags & ATA_LFLAG_DISABLED)) { + ata_link_printk(link, KERN_WARNING, + "failed to recover link after %d tries, disabling\n", + ATA_EH_PMP_LINK_TRIES); + + spin_lock_irqsave(ap->lock, flags); + link->flags |= ATA_LFLAG_DISABLED; + spin_unlock_irqrestore(ap->lock, flags); + } + + ata_dev_disable(link->device); + link->eh_context.i.action = 0; + + return 0; +} + +/** + * sata_pmp_eh_recover - recover PMP-enabled port + * @ap: ATA port to recover + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * @pmp_prereset: PMP prereset method (can be NULL) + * @pmp_softreset: PMP softreset method (can be NULL) + * @pmp_hardreset: PMP hardreset method (can be NULL) + * @pmp_postreset: PMP postreset method (can be NULL) + * + * Drive EH recovery operation for PMP enabled port @ap. This + * function recovers host and PMP ports with proper retrials and + * fallbacks. Actual recovery operations are performed using + * ata_eh_recover() and sata_pmp_eh_recover_pmp(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_eh_recover(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, + ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, + ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset) +{ + int pmp_tries, link_tries[SATA_PMP_MAX_PORTS]; + struct ata_link *pmp_link = &ap->link; + struct ata_device *pmp_dev = pmp_link->device; + struct ata_eh_context *pmp_ehc = &pmp_link->eh_context; + struct ata_link *link; + struct ata_device *dev; + u32 gscr_error, sntf; + int cnt, rc; + + pmp_tries = ATA_EH_PMP_TRIES; + ata_port_for_each_link(link, ap) + link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES; + + retry: + /* PMP attached? */ + if (!ap->nr_pmp_links) { + rc = ata_eh_recover(ap, prereset, softreset, hardreset, + postreset, NULL); + if (rc) { + ata_link_for_each_dev(dev, &ap->link) + ata_dev_disable(dev); + return rc; + } + + if (pmp_dev->class != ATA_DEV_PMP) + return 0; + + /* new PMP online */ + ata_port_for_each_link(link, ap) + link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES; + + /* fall through */ + } + + /* recover pmp */ + rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset, + postreset); + if (rc) + goto pmp_fail; + + /* handle disabled links */ + rc = sata_pmp_eh_handle_disabled_links(ap); + if (rc) + goto pmp_fail; + + /* recover links */ + rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset, + pmp_postreset, &link); + if (rc) + goto link_fail; + + /* Connection status might have changed while resetting other + * links, check SATA_PMP_GSCR_ERROR before returning. + */ + + /* clear SNotification */ + rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); + if (rc == 0) + sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); + + /* enable notification */ + if (pmp_dev->flags & ATA_DFLAG_AN) { + pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; + + rc = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN, + pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]); + if (rc) { + ata_dev_printk(pmp_dev, KERN_ERR, + "failed to write PMP_FEAT_EN\n"); + goto pmp_fail; + } + } + + /* check GSCR_ERROR */ + rc = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error); + if (rc) { + ata_dev_printk(pmp_dev, KERN_ERR, + "failed to read PMP_GSCR_ERROR\n"); + goto pmp_fail; + } + + cnt = 0; + ata_port_for_each_link(link, ap) { + if (!(gscr_error & (1 << link->pmp))) + continue; + + if (sata_pmp_handle_link_fail(link, link_tries)) { + ata_ehi_hotplugged(&link->eh_context.i); + cnt++; + } else { + ata_link_printk(link, KERN_WARNING, + "PHY status changed but maxed out on retries, " + "giving up\n"); + ata_link_printk(link, KERN_WARNING, + "Manully issue scan to resume this link\n"); + } + } + + if (cnt) { + ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some " + "ports, repeating recovery\n"); + goto retry; + } + + return 0; + + link_fail: + if (sata_pmp_handle_link_fail(link, link_tries)) { + pmp_ehc->i.action |= ATA_EH_HARDRESET; + goto retry; + } + + /* fall through */ + pmp_fail: + /* Control always ends up here after detaching PMP. Shut up + * and return if we're unloading. + */ + if (ap->pflags & ATA_PFLAG_UNLOADING) + return rc; + + if (!ap->nr_pmp_links) + goto retry; + + if (--pmp_tries) { + ata_port_printk(ap, KERN_WARNING, + "failed to recover PMP, retrying in 5 secs\n"); + pmp_ehc->i.action |= ATA_EH_HARDRESET; + ssleep(5); + goto retry; + } + + ata_port_printk(ap, KERN_ERR, + "failed to recover PMP after %d tries, giving up\n", + ATA_EH_PMP_TRIES); + sata_pmp_detach(pmp_dev); + ata_dev_disable(pmp_dev); + + return rc; +} + +/** + * sata_pmp_do_eh - do standard error handling for PMP-enabled host + * @ap: host port to handle error for + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * @pmp_prereset: PMP prereset method (can be NULL) + * @pmp_softreset: PMP softreset method (can be NULL) + * @pmp_hardreset: PMP hardreset method (can be NULL) + * @pmp_postreset: PMP postreset method (can be NULL) + * + * Perform standard error handling sequence for PMP-enabled host + * @ap. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void sata_pmp_do_eh(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, + ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, + ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset) +{ + ata_eh_autopsy(ap); + ata_eh_report(ap); + sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset, + pmp_prereset, pmp_softreset, pmp_hardreset, + pmp_postreset); + ata_eh_finish(ap); +} diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index ebe22982e80c..a9b9c9e1e105 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -153,6 +153,11 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); +/* libata-pmp.c */ +extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); +extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); +extern int sata_pmp_attach(struct ata_device *dev); + /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); diff --git a/include/linux/libata.h b/include/linux/libata.h index f9ed198e4fcd..3cfdb5f67621 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -944,6 +944,25 @@ extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bit extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); #endif /* CONFIG_PCI */ +/* + * PMP + */ +extern void sata_pmp_read_init_tf(struct ata_taskfile *tf, + struct ata_device *dev, int pmp, int reg); +extern u32 sata_pmp_read_val(const struct ata_taskfile *tf); +extern void sata_pmp_write_init_tf(struct ata_taskfile *tf, + struct ata_device *dev, + int pmp, int reg, u32 val); +extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline); +extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +extern void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class); +extern void sata_pmp_do_eh(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, + ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, + ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset); + /* * EH */ From 633273a3ed1cf37ced90475b0f95cf81deab04f1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: [PATCH 2473/2804] libata-pmp: hook PMP support and enable it Hook PMP support into libata and enable it. Connect SCR and probing functions, and update ata_dev_classify() to detect PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 111 +++++++++++++++++++++++++++----------- drivers/ata/libata-eh.c | 18 +++++-- drivers/ata/libata.h | 2 +- 3 files changed, 96 insertions(+), 35 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9e7f55b71044..d3e78d97529d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -670,29 +670,49 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) * None. * * RETURNS: - * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN - * the event of failure. + * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or + * %ATA_DEV_UNKNOWN the event of failure. */ - unsigned int ata_dev_classify(const struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, * So, we only check those. It's sufficient for uniqueness. + * + * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate + * signatures for ATA and ATAPI devices attached on SerialATA, + * 0x3c/0xc3 and 0x69/0x96 respectively. However, SerialATA + * spec has never mentioned about using different signatures + * for ATA/ATAPI devices. Then, Serial ATA II: Port + * Multiplier specification began to use 0x69/0x96 to identify + * port multpliers and 0x3c/0xc3 to identify SEMB device. + * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and + * 0x69/0x96 shortly and described them as reserved for + * SerialATA. + * + * We follow the current spec and consider that 0x69/0x96 + * identifies a port multiplier and 0x3c/0xc3 a SEMB device. */ - - if (((tf->lbam == 0) && (tf->lbah == 0)) || - ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) { + if ((tf->lbam == 0) && (tf->lbah == 0)) { DPRINTK("found ATA device by sig\n"); return ATA_DEV_ATA; } - if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) || - ((tf->lbam == 0x69) && (tf->lbah == 0x96))) { + if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) { DPRINTK("found ATAPI device by sig\n"); return ATA_DEV_ATAPI; } + if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) { + DPRINTK("found PMP device by sig\n"); + return ATA_DEV_PMP; + } + + if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) { + printk("ata: SEMB device ignored\n"); + return ATA_DEV_SEMB_UNSUP; /* not yet */ + } + DPRINTK("unknown device\n"); return ATA_DEV_UNKNOWN; } @@ -3426,6 +3446,12 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) (link->flags & ATA_LFLAG_HRST_TO_RESUME)) ehc->i.action |= ATA_EH_HARDRESET; + /* Some PMPs don't work with only SRST, force hardreset if PMP + * is supported. + */ + if (ap->flags & ATA_FLAG_PMP) + ehc->i.action |= ATA_EH_HARDRESET; + /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) return 0; @@ -3616,6 +3642,16 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, /* wait a while before checking status, see SRST for more info */ msleep(150); + /* If PMP is supported, we have to do follow-up SRST. Note + * that some PMPs don't send D2H Reg FIS after hardreset at + * all if the first port is empty. Wait for it just for a + * second and request follow-up SRST. + */ + if (ap->flags & ATA_FLAG_PMP) { + ata_wait_ready(ap, jiffies + HZ); + return -EAGAIN; + } + rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { @@ -5966,22 +6002,26 @@ int sata_scr_valid(struct ata_link *link) * @val: Place to store read value * * Read SCR register @reg of @link into *@val. This function is - * guaranteed to succeed if the cable type of the port is SATA - * and the port implements ->scr_read. + * guaranteed to succeed if @link is ap->link, the cable type of + * the port is SATA and the port implements ->scr_read. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ int sata_scr_read(struct ata_link *link, int reg, u32 *val) { - struct ata_port *ap = link->ap; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; - if (sata_scr_valid(link)) - return ap->ops->scr_read(ap, reg, val); - return -EOPNOTSUPP; + if (sata_scr_valid(link)) + return ap->ops->scr_read(ap, reg, val); + return -EOPNOTSUPP; + } + + return sata_pmp_scr_read(link, reg, val); } /** @@ -5991,22 +6031,26 @@ int sata_scr_read(struct ata_link *link, int reg, u32 *val) * @val: value to write * * Write @val to SCR register @reg of @link. This function is - * guaranteed to succeed if the cable type of the port is SATA - * and the port implements ->scr_read. + * guaranteed to succeed if @link is ap->link, the cable type of + * the port is SATA and the port implements ->scr_read. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ int sata_scr_write(struct ata_link *link, int reg, u32 val) { - struct ata_port *ap = link->ap; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; - if (sata_scr_valid(link)) - return ap->ops->scr_write(ap, reg, val); - return -EOPNOTSUPP; + if (sata_scr_valid(link)) + return ap->ops->scr_write(ap, reg, val); + return -EOPNOTSUPP; + } + + return sata_pmp_scr_write(link, reg, val); } /** @@ -6019,23 +6063,27 @@ int sata_scr_write(struct ata_link *link, int reg, u32 val) * function performs flush after writing to the register. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) { - struct ata_port *ap = link->ap; - int rc; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; + int rc; - if (sata_scr_valid(link)) { - rc = ap->ops->scr_write(ap, reg, val); - if (rc == 0) - rc = ap->ops->scr_read(ap, reg, &val); - return rc; + if (sata_scr_valid(link)) { + rc = ap->ops->scr_write(ap, reg, val); + if (rc == 0) + rc = ap->ops->scr_read(ap, reg, &val); + return rc; + } + return -EOPNOTSUPP; } - return -EOPNOTSUPP; + + return sata_pmp_scr_write(link, reg, val); } /** @@ -6424,6 +6472,7 @@ static void ata_host_release(struct device *gendev, void *res) if (ap->scsi_host) scsi_host_put(ap->scsi_host); + kfree(ap->pmp_link); kfree(ap); host->ports[i] = NULL; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 687419b66708..5f2c0f376f74 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2209,6 +2209,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, readid_flags |= ATA_READID_POSTRESET; if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { + WARN_ON(dev->class == ATA_DEV_PMP); + if (ata_link_offline(link)) { rc = -EIO; goto err; @@ -2234,8 +2236,11 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; - rc = ata_dev_read_id(dev, &dev->class, readid_flags, - dev->id); + if (dev->class == ATA_DEV_PMP) + rc = sata_pmp_attach(dev); + else + rc = ata_dev_read_id(dev, &dev->class, + readid_flags, dev->id); switch (rc) { case 0: new_mask |= 1 << dev->devno; @@ -2264,7 +2269,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, * device detection messages backwards. */ ata_link_for_each_dev(dev, link) { - if (!(new_mask & (1 << dev->devno))) + if (!(new_mask & (1 << dev->devno)) || + dev->class == ATA_DEV_PMP) continue; ehc->i.flags |= ATA_EHI_PRINTINFO; @@ -2521,6 +2527,12 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (rc) goto dev_fail; + /* if PMP got attached, return, pmp EH will take care of it */ + if (link->device->class == ATA_DEV_PMP) { + ehc->i.action = 0; + return 0; + } + /* configure transfer mode if necessary */ if (ehc->i.flags & ATA_EHI_SETMODE) { rc = ata_set_mode(link, &dev); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a9b9c9e1e105..a44172fd1f5c 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -29,7 +29,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" -#define DRV_VERSION "2.21" /* must be exactly four chars */ +#define DRV_VERSION "3.00" /* must be exactly four chars */ struct ata_scsi_args { struct ata_device *dev; From d0df8b5d0fb547a3351c2a4b1ded7f7cde5d713a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: [PATCH 2474/2804] libata-pmp: extend ACPI support to cover PMP Extend ata_acpi_associate_sata_port() such that it can handle PMP and call it when PMP is attached and detached. Build breakage when !CONFIG_ATA_ACPI was spotted and fixed by Petr Vandrovec. Signed-off-by: Tejun Heo Cc: Petr Vandrovec Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 36 ++++++++++++++++++++++++++++++++---- drivers/ata/libata-pmp.c | 4 ++++ drivers/ata/libata.h | 2 ++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index dc9842ec6f06..a276c06dda95 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -40,12 +40,40 @@ static int is_pci_dev(struct device *dev) return (dev->bus == &pci_bus_type); } -static void ata_acpi_associate_sata_port(struct ata_port *ap) +/** + * ata_acpi_associate_sata_port - associate SATA port with ACPI objects + * @ap: target SATA port + * + * Look up ACPI objects associated with @ap and initialize acpi_handle + * fields of @ap, the port and devices accordingly. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +void ata_acpi_associate_sata_port(struct ata_port *ap) { - acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); + WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA)); - ap->link.device->acpi_handle = - acpi_get_child(ap->host->acpi_handle, adr); + if (!ap->nr_pmp_links) { + acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); + + ap->link.device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); + } else { + struct ata_link *link; + + ap->link.device->acpi_handle = NULL; + + ata_port_for_each_link(link, ap) { + acpi_integer adr = SATA_ADR(ap->port_no, link->pmp); + + link->device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); + } + } } static void ata_acpi_associate_ide_port(struct ata_port *ap) diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 671d171055a3..eeffce636d0c 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -607,6 +607,8 @@ int sata_pmp_attach(struct ata_device *dev) ata_port_for_each_link(tlink, ap) sata_link_init_spd(tlink); + ata_acpi_associate_sata_port(ap); + return 0; fail: @@ -646,6 +648,8 @@ static void sata_pmp_detach(struct ata_device *dev) ap->nr_pmp_links = 0; link->pmp = 0; spin_unlock_irqrestore(ap->lock, flags); + + ata_acpi_associate_sata_port(ap); } /** diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a44172fd1f5c..f8bd955c5ba7 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -103,11 +103,13 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host); /* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI +extern void ata_acpi_associate_sata_port(struct ata_port *ap); extern void ata_acpi_associate(struct ata_host *host); extern int ata_acpi_on_suspend(struct ata_port *ap); extern void ata_acpi_on_resume(struct ata_port *ap); extern int ata_acpi_on_devcfg(struct ata_device *adev); #else +static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { } static inline void ata_acpi_associate(struct ata_host *host) { } static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } static inline void ata_acpi_on_resume(struct ata_port *ap) { } From 31f88384443b3e0d7e2c9d36a96647b7e82edad3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: [PATCH 2475/2804] libata-pmp: implement qc_defer for command switching PMP support Implement sata_pmp_qc_defer_cmd_switch() - standard qc_defer for command switching PMP support. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + drivers/ata/libata-pmp.c | 30 ++++++++++++++++++++++++++++++ include/linux/libata.h | 1 + 3 files changed, 32 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d3e78d97529d..5532a6564d05 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7303,6 +7303,7 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ +EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); EXPORT_SYMBOL_GPL(sata_pmp_read_init_tf); EXPORT_SYMBOL_GPL(sata_pmp_read_val); EXPORT_SYMBOL_GPL(sata_pmp_write_init_tf); diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index eeffce636d0c..f6c4b11336e9 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -69,6 +69,36 @@ static int sata_pmp_write(struct ata_link *link, int reg, u32 val) return rc; } +/** + * sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP + * @qc: ATA command in question + * + * A host which has command switching PMP support cannot issue + * commands to multiple links simultaneously. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * ATA_DEFER_* if deferring is needed, 0 otherwise. + */ +int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + struct ata_port *ap = link->ap; + + if (ap->excl_link == NULL || ap->excl_link == link) { + if (ap->nr_active_links == 0 || ata_link_active(link)) { + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + return ata_std_qc_defer(qc); + } + + ap->excl_link = link; + } + + return ATA_DEFER_PORT; +} + /** * sata_pmp_read_init_tf - initialize TF for PMP read * @tf: taskfile to initialize diff --git a/include/linux/libata.h b/include/linux/libata.h index 3cfdb5f67621..ca296a575c4a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -947,6 +947,7 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); /* * PMP */ +extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); extern void sata_pmp_read_init_tf(struct ata_taskfile *tf, struct ata_device *dev, int pmp, int reg); extern u32 sata_pmp_read_val(const struct ata_taskfile *tf); From 3454dc6922dc550c0d3ccf292c4e227403b10b6e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: [PATCH 2476/2804] sata_sil24: implement PMP support Implement PMP support. sil24 supports full FIS-switching. However, it has a PMP DMA CS errata which requires port-wide resetting if commands are outstanding to three or more devices when an error occurs on one of them. ATAPI commands often result in CHECK SENSE and it's crucial to not reset them before fetching sense data. Unfortunately, ATAPI CHECK SENSE causes a lot of problem if command is outstanding to any other device usually resulting in port-wide reset. So, sata_sil24 implements sil24_qc_defer() which guarantees ATAPI command is run by itself. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_sil24.c | 227 +++++++++++++++++++++++++++++++++++---- 1 file changed, 206 insertions(+), 21 deletions(-) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index b4f81eb8bbbe..03bfbb65c533 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -30,7 +30,7 @@ #include #define DRV_NAME "sata_sil24" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.1" /* * Port request block (PRB) 32 bytes @@ -238,7 +238,7 @@ enum { SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA | - ATA_FLAG_AN, + ATA_FLAG_AN | ATA_FLAG_PMP, SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ @@ -330,9 +330,14 @@ static u8 sil24_check_status(struct ata_port *ap); static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val); static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static int sil24_qc_defer(struct ata_queued_cmd *qc); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static void sil24_irq_clear(struct ata_port *ap); +static void sil24_pmp_attach(struct ata_port *ap); +static void sil24_pmp_detach(struct ata_port *ap); +static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val); +static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val); static void sil24_freeze(struct ata_port *ap); static void sil24_thaw(struct ata_port *ap); static void sil24_error_handler(struct ata_port *ap); @@ -341,6 +346,7 @@ static int sil24_port_start(struct ata_port *ap); static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); #ifdef CONFIG_PM static int sil24_pci_device_resume(struct pci_dev *pdev); +static int sil24_port_resume(struct ata_port *ap); #endif static const struct pci_device_id sil24_pci_tbl[] = { @@ -393,7 +399,7 @@ static const struct ata_port_operations sil24_ops = { .tf_read = sil24_tf_read, - .qc_defer = ata_std_qc_defer, + .qc_defer = sil24_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, @@ -402,12 +408,21 @@ static const struct ata_port_operations sil24_ops = { .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, + .pmp_attach = sil24_pmp_attach, + .pmp_detach = sil24_pmp_detach, + .pmp_read = sil24_pmp_read, + .pmp_write = sil24_pmp_write, + .freeze = sil24_freeze, .thaw = sil24_thaw, .error_handler = sil24_error_handler, .post_internal_cmd = sil24_post_internal_cmd, .port_start = sil24_port_start, + +#ifdef CONFIG_PM + .port_resume = sil24_port_resume, +#endif }; /* @@ -521,11 +536,40 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) *tf = pp->tf; } +static void sil24_config_pmp(struct ata_port *ap, int attached) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + + if (attached) + writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT); + else + writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR); +} + +static void sil24_clear_pmp(struct ata_port *ap) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + int i; + + writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); + + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) { + void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE; + + writel(0, pmp_base + PORT_PMP_STATUS); + writel(0, pmp_base + PORT_PMP_QACTIVE); + } +} + static int sil24_init_port(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; u32 tmp; + /* clear PMP error status */ + if (ap->nr_pmp_links) + sil24_clear_pmp(ap); + writel(PORT_CS_INIT, port + PORT_CTRL_STAT); ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_INIT, PORT_CS_INIT, 10, 100); @@ -640,7 +684,7 @@ static int sil24_do_softreset(struct ata_link *link, unsigned int *class, static int sil24_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return sil24_do_softreset(link, class, 0, deadline); + return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline); } static int sil24_hardreset(struct ata_link *link, unsigned int *class, @@ -708,6 +752,38 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, } } +static int sil24_qc_defer(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + struct ata_port *ap = link->ap; + u8 prot = qc->tf.protocol; + int is_atapi = (prot == ATA_PROT_ATAPI || + prot == ATA_PROT_ATAPI_NODATA || + prot == ATA_PROT_ATAPI_DMA); + + /* ATAPI commands completing with CHECK_SENSE cause various + * weird problems if other commands are active. PMP DMA CS + * errata doesn't cover all and HSM violation occurs even with + * only one other device active. Always run an ATAPI command + * by itself. + */ + if (unlikely(ap->excl_link)) { + if (link == ap->excl_link) { + if (ap->nr_active_links) + return ATA_DEFER_PORT; + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + } else + return ATA_DEFER_PORT; + } else if (unlikely(is_atapi)) { + ap->excl_link = link; + if (ap->nr_active_links) + return ATA_DEFER_PORT; + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + } + + return ata_std_qc_defer(qc); +} + static void sil24_qc_prep(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -751,7 +827,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) } prb->ctrl = cpu_to_le16(ctrl); - ata_tf_to_fis(&qc->tf, 0, 1, prb->fis); + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis); if (qc->flags & ATA_QCFLAG_DMAMAP) sil24_fill_sg(qc, sge); @@ -780,6 +856,65 @@ static void sil24_irq_clear(struct ata_port *ap) /* unused */ } +static void sil24_pmp_attach(struct ata_port *ap) +{ + sil24_config_pmp(ap, 1); + sil24_init_port(ap); +} + +static void sil24_pmp_detach(struct ata_port *ap) +{ + sil24_init_port(ap); + sil24_config_pmp(ap, 0); +} + +static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) +{ + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + int rc; + + sata_pmp_read_init_tf(&tf, dev, pmp, reg); + rc = sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, + SATA_PMP_SCR_TIMEOUT); + if (rc == 0) { + sil24_read_tf(ap, 0, &tf); + *r_val = sata_pmp_read_val(&tf); + } + return rc; +} + +static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val) +{ + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + + sata_pmp_write_init_tf(&tf, dev, pmp, reg, val); + return sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, + SATA_PMP_SCR_TIMEOUT); +} + +static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + return sil24_do_softreset(link, class, link->pmp, deadline); +} + +static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int rc; + + rc = sil24_init_port(link->ap); + if (rc) { + ata_link_printk(link, KERN_ERR, + "hardreset failed (port not ready)\n"); + return rc; + } + + return sata_pmp_std_hardreset(link, class, deadline); +} + static void sil24_freeze(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; @@ -807,8 +942,10 @@ static void sil24_error_intr(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->link.eh_info; - int freeze = 0; + struct ata_queued_cmd *qc = NULL; + struct ata_link *link; + struct ata_eh_info *ehi; + int abort = 0, freeze = 0; u32 irq_stat; /* on error, we need to clear IRQ explicitly */ @@ -816,6 +953,8 @@ static void sil24_error_intr(struct ata_port *ap) writel(irq_stat, port + PORT_IRQ_STAT); /* first, analyze and record host port events */ + link = &ap->link; + ehi = &link->eh_info; ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); @@ -844,8 +983,43 @@ static void sil24_error_intr(struct ata_port *ap) if (irq_stat & PORT_IRQ_ERROR) { struct sil24_cerr_info *ci = NULL; unsigned int err_mask = 0, action = 0; - struct ata_queued_cmd *qc; - u32 cerr; + u32 context, cerr; + int pmp; + + abort = 1; + + /* DMA Context Switch Failure in Port Multiplier Mode + * errata. If we have active commands to 3 or more + * devices, any error condition on active devices can + * corrupt DMA context switching. + */ + if (ap->nr_active_links >= 3) { + ehi->err_mask |= AC_ERR_OTHER; + ehi->action |= ATA_EH_HARDRESET; + ata_ehi_push_desc(ehi, "PMP DMA CS errata"); + freeze = 1; + } + + /* find out the offending link and qc */ + if (ap->nr_pmp_links) { + context = readl(port + PORT_CONTEXT); + pmp = (context >> 5) & 0xf; + + if (pmp < ap->nr_pmp_links) { + link = &ap->pmp_link[pmp]; + ehi = &link->eh_info; + qc = ata_qc_from_tag(ap, link->active_tag); + + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "irq_stat 0x%08x", + irq_stat); + } else { + err_mask |= AC_ERR_HSM; + action |= ATA_EH_HARDRESET; + freeze = 1; + } + } else + qc = ata_qc_from_tag(ap, link->active_tag); /* analyze CMD_ERR */ cerr = readl(port + PORT_CMD_ERR); @@ -864,7 +1038,6 @@ static void sil24_error_intr(struct ata_port *ap) } /* record error info */ - qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) { sil24_read_tf(ap, qc->tag, &pp->tf); qc->err_mask |= err_mask; @@ -872,13 +1045,21 @@ static void sil24_error_intr(struct ata_port *ap) ehi->err_mask |= err_mask; ehi->action |= action; + + /* if PMP, resume */ + if (ap->nr_pmp_links) + writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT); } /* freeze or abort */ if (freeze) ata_port_freeze(ap); - else - ata_port_abort(ap); + else if (abort) { + if (qc) + ata_link_abort(qc->dev->link); + else + ata_port_abort(ap); + } } static void sil24_finish_qc(struct ata_queued_cmd *qc) @@ -971,16 +1152,14 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) static void sil24_error_handler(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->link.eh_context; - - if (sil24_init_port(ap)) { + if (sil24_init_port(ap)) ata_eh_freeze_port(ap); - ehc->i.action |= ATA_EH_HARDRESET; - } /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset, - ata_std_postreset); + sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset, + ata_std_postreset, sata_pmp_std_prereset, + sil24_pmp_softreset, sil24_pmp_hardreset, + sata_pmp_std_postreset); } static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) @@ -988,8 +1167,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) - sil24_init_port(ap); + if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap)) + ata_eh_freeze_port(ap); } static int sil24_port_start(struct ata_port *ap) @@ -1190,6 +1369,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) return 0; } + +static int sil24_port_resume(struct ata_port *ap) +{ + sil24_config_pmp(ap, ap->nr_pmp_links); + return 0; +} #endif static int __init sil24_init(void) From 238180343eff95697ed71eea137cf61ba3cea6ad Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: [PATCH 2477/2804] sata_sil24: implement PORT_RST As DEV_RST (hardreset) sometimes fail to recover the controller (especially after PMP DMA CS errata). In such cases, perform PORT_RST prior to DEV_RST. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_sil24.c | 93 ++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 03bfbb65c533..15b9a80a1782 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -323,6 +323,7 @@ struct sil24_port_priv { union sil24_cmd_block *cmd_block; /* 32 cmd blocks */ dma_addr_t cmd_block_dma; /* DMA base addr for them */ struct ata_taskfile tf; /* Cached taskfile registers */ + int do_port_rst; }; static void sil24_dev_config(struct ata_device *dev); @@ -536,6 +537,31 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) *tf = pp->tf; } +static void sil24_config_port(struct ata_port *ap) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + + /* configure IRQ WoC */ + if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); + else + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* zero error counters. */ + writel(0x8000, port + PORT_DECODE_ERR_THRESH); + writel(0x8000, port + PORT_CRC_ERR_THRESH); + writel(0x8000, port + PORT_HSHK_ERR_THRESH); + writel(0x0000, port + PORT_DECODE_ERR_CNT); + writel(0x0000, port + PORT_CRC_ERR_CNT); + writel(0x0000, port + PORT_HSHK_ERR_CNT); + + /* always use 64bit activation */ + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); + + /* clear port multiplier enable and resume bits */ + writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); +} + static void sil24_config_pmp(struct ata_port *ap, int attached) { void __iomem *port = ap->ioaddr.cmd_addr; @@ -564,6 +590,7 @@ static void sil24_clear_pmp(struct ata_port *ap) static int sil24_init_port(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; u32 tmp; /* clear PMP error status */ @@ -576,8 +603,12 @@ static int sil24_init_port(struct ata_port *ap) tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0, 10, 100); - if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) + if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) { + pp->do_port_rst = 1; + ap->link.eh_context.i.action |= ATA_EH_HARDRESET; return -EIO; + } + return 0; } @@ -692,10 +723,34 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, { struct ata_port *ap = link->ap; void __iomem *port = ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; + int did_port_rst = 0; const char *reason; int tout_msec, rc; u32 tmp; + retry: + /* Sometimes, DEV_RST is not enough to recover the controller. + * This happens often after PM DMA CS errata. + */ + if (pp->do_port_rst) { + ata_port_printk(ap, KERN_WARNING, "controller in dubious " + "state, performing PORT_RST\n"); + + writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT); + msleep(10); + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0, + 10, 5000); + + /* restore port configuration */ + sil24_config_port(ap); + sil24_config_pmp(ap, ap->nr_pmp_links); + + pp->do_port_rst = 0; + did_port_rst = 1; + } + /* sil24 does the right thing(tm) without any protection */ sata_set_spd(link); @@ -732,6 +787,11 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, return -EAGAIN; err: + if (!did_port_rst) { + pp->do_port_rst = 1; + goto retry; + } + ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason); return -EIO; } @@ -997,6 +1057,7 @@ static void sil24_error_intr(struct ata_port *ap) ehi->err_mask |= AC_ERR_OTHER; ehi->action |= ATA_EH_HARDRESET; ata_ehi_push_desc(ehi, "PMP DMA CS errata"); + pp->do_port_rst = 1; freeze = 1; } @@ -1152,6 +1213,8 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) static void sil24_error_handler(struct ata_port *ap) { + struct sil24_port_priv *pp = ap->private_data; + if (sil24_init_port(ap)) ata_eh_freeze_port(ap); @@ -1160,6 +1223,8 @@ static void sil24_error_handler(struct ata_port *ap) ata_std_postreset, sata_pmp_std_prereset, sil24_pmp_softreset, sil24_pmp_hardreset, sata_pmp_std_postreset); + + pp->do_port_rst = 0; } static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) @@ -1206,7 +1271,6 @@ static int sil24_port_start(struct ata_port *ap) static void sil24_init_controller(struct ata_host *host) { void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; - void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; u32 tmp; int i; @@ -1218,7 +1282,8 @@ static void sil24_init_controller(struct ata_host *host) /* init ports */ for (i = 0; i < host->n_ports; i++) { - void __iomem *port = port_base + i * PORT_REGS_SIZE; + struct ata_port *ap = host->ports[i]; + void __iomem *port = ap->ioaddr.cmd_addr; /* Initial PHY setting */ writel(0x20c, port + PORT_PHY_CFG); @@ -1235,26 +1300,8 @@ static void sil24_init_controller(struct ata_host *host) "failed to clear port RST\n"); } - /* Configure IRQ WoC */ - if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC) - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); - else - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); - - /* Zero error counters. */ - writel(0x8000, port + PORT_DECODE_ERR_THRESH); - writel(0x8000, port + PORT_CRC_ERR_THRESH); - writel(0x8000, port + PORT_HSHK_ERR_THRESH); - writel(0x0000, port + PORT_DECODE_ERR_CNT); - writel(0x0000, port + PORT_CRC_ERR_CNT); - writel(0x0000, port + PORT_HSHK_ERR_CNT); - - /* Always use 64bit activation */ - writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); - - /* Clear port multiplier enable and resume bits */ - writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, - port + PORT_CTRL_CLR); + /* configure port */ + sil24_config_port(ap); } /* Turn on interrupts */ From 7d50b60b5e38f910ad69f0187af00f5d6a8970d4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: [PATCH 2478/2804] ahci: implement PMP support Implement AHCI PMP support. ahci only supports command based switching. Also, for some reason, NCQ over PMP doesn't work now. Other than that, everything works. Tested on ICH9R, JMB360/363 + SIMG3726, 4726 and 5744. Signed-off-by: Tejun Heo Cc: Forrest Zhao Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 228 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 178 insertions(+), 50 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b615390b6b8a..b697da483b70 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -46,7 +46,7 @@ #include #define DRV_NAME "ahci" -#define DRV_VERSION "2.3" +#define DRV_VERSION "3.0" enum { @@ -96,6 +96,7 @@ enum { /* HOST_CAP bits */ HOST_CAP_SSC = (1 << 14), /* Slumber capable */ + HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ HOST_CAP_CLO = (1 << 24), /* Command List Override support */ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ HOST_CAP_SNTF = (1 << 29), /* SNotification register */ @@ -143,7 +144,8 @@ enum { PORT_IRQ_IF_ERR | PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | - PORT_IRQ_UNK_FIS, + PORT_IRQ_UNK_FIS | + PORT_IRQ_BAD_PMP, PORT_IRQ_ERROR = PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | PORT_IRQ_HBUS_DATA_ERR, @@ -153,6 +155,7 @@ enum { /* PORT_CMD bits */ PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ + PORT_CMD_PMP = (1 << 17), /* PMP attached */ PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ @@ -204,6 +207,7 @@ struct ahci_host_priv { }; struct ahci_port_priv { + struct ata_link *active_link; struct ahci_cmd_hdr *cmd_slot; dma_addr_t cmd_slot_dma; void *cmd_tbl; @@ -229,6 +233,10 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); +static void ahci_pmp_attach(struct ata_port *ap); +static void ahci_pmp_detach(struct ata_port *ap); +static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val); +static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val); static void ahci_error_handler(struct ata_port *ap); static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); @@ -268,7 +276,7 @@ static const struct ata_port_operations ahci_ops = { .tf_read = ahci_tf_read, - .qc_defer = ata_std_qc_defer, + .qc_defer = sata_pmp_qc_defer_cmd_switch, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, @@ -283,6 +291,11 @@ static const struct ata_port_operations ahci_ops = { .error_handler = ahci_error_handler, .post_internal_cmd = ahci_post_internal_cmd, + .pmp_attach = ahci_pmp_attach, + .pmp_detach = ahci_pmp_detach, + .pmp_read = ahci_pmp_read, + .pmp_write = ahci_pmp_write, + #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, @@ -299,7 +312,7 @@ static const struct ata_port_operations ahci_vt8251_ops = { .tf_read = ahci_tf_read, - .qc_defer = ata_std_qc_defer, + .qc_defer = sata_pmp_qc_defer_cmd_switch, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, @@ -314,6 +327,11 @@ static const struct ata_port_operations ahci_vt8251_ops = { .error_handler = ahci_vt8251_error_handler, .post_internal_cmd = ahci_post_internal_cmd, + .pmp_attach = ahci_pmp_attach, + .pmp_detach = ahci_pmp_detach, + .pmp_read = ahci_pmp_read, + .pmp_write = ahci_pmp_write, + #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, @@ -1114,7 +1132,12 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, static int ahci_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return ahci_do_softreset(link, class, 0, deadline); + int pmp = 0; + + if (link->ap->flags & ATA_FLAG_PMP) + pmp = SATA_PMP_CTRL_PORT; + + return ahci_do_softreset(link, class, pmp, deadline); } static int ahci_hardreset(struct ata_link *link, unsigned int *class, @@ -1141,7 +1164,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, if (rc == 0 && ata_link_online(link)) *class = ahci_dev_classify(ap); - if (*class == ATA_DEV_UNKNOWN) + if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); @@ -1196,6 +1219,12 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class) } } +static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + return ahci_do_softreset(link, class, link->pmp, deadline); +} + static u8 ahci_check_status(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.cmd_addr; @@ -1254,7 +1283,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) */ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; - ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl); + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); if (is_atapi) { memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); @@ -1267,7 +1296,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) /* * Fill in command slot information. */ - opts = cmd_fis_len | n_elem << 16; + opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); if (qc->tf.flags & ATA_TFLAG_WRITE) opts |= AHCI_CMD_WRITE; if (is_atapi) @@ -1279,65 +1308,85 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { struct ahci_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->link.eh_info; - unsigned int err_mask = 0, action = 0; - struct ata_queued_cmd *qc; + struct ata_eh_info *host_ehi = &ap->link.eh_info; + struct ata_link *link = NULL; + struct ata_queued_cmd *active_qc; + struct ata_eh_info *active_ehi; u32 serror; - ata_ehi_clear_desc(ehi); + /* determine active link */ + ata_port_for_each_link(link, ap) + if (ata_link_active(link)) + break; + if (!link) + link = &ap->link; + + active_qc = ata_qc_from_tag(ap, link->active_tag); + active_ehi = &link->eh_info; + + /* record irq stat */ + ata_ehi_clear_desc(host_ehi); + ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); /* AHCI needs SError cleared; otherwise, it might lock up */ ahci_scr_read(ap, SCR_ERROR, &serror); ahci_scr_write(ap, SCR_ERROR, serror); - - /* analyze @irq_stat */ - ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); + host_ehi->serror |= serror; /* some controllers set IRQ_IF_ERR on device errors, ignore it */ if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR) irq_stat &= ~PORT_IRQ_IF_ERR; if (irq_stat & PORT_IRQ_TF_ERR) { - err_mask |= AC_ERR_DEV; + /* If qc is active, charge it; otherwise, the active + * link. There's no active qc on NCQ errors. It will + * be determined by EH by reading log page 10h. + */ + if (active_qc) + active_qc->err_mask |= AC_ERR_DEV; + else + active_ehi->err_mask |= AC_ERR_DEV; + if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL) - serror &= ~SERR_INTERNAL; - } - - if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { - err_mask |= AC_ERR_HOST_BUS; - action |= ATA_EH_SOFTRESET; - } - - if (irq_stat & PORT_IRQ_IF_ERR) { - err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, "interface fatal error"); - } - - if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { - ata_ehi_hotplugged(ehi); - ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ? - "connection status changed" : "PHY RDY changed"); + host_ehi->serror &= ~SERR_INTERNAL; } if (irq_stat & PORT_IRQ_UNK_FIS) { u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); - err_mask |= AC_ERR_HSM; - action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x", + active_ehi->err_mask |= AC_ERR_HSM; + active_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(active_ehi, + "unknown FIS %08x %08x %08x %08x" , unk[0], unk[1], unk[2], unk[3]); } - /* okay, let's hand over to EH */ - ehi->serror |= serror; - ehi->action |= action; + if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) { + active_ehi->err_mask |= AC_ERR_HSM; + active_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(active_ehi, "incorrect PMP"); + } - qc = ata_qc_from_tag(ap, ap->link.active_tag); - if (qc) - qc->err_mask |= err_mask; - else - ehi->err_mask |= err_mask; + if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { + host_ehi->err_mask |= AC_ERR_HOST_BUS; + host_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(host_ehi, "host bus error"); + } + + if (irq_stat & PORT_IRQ_IF_ERR) { + host_ehi->err_mask |= AC_ERR_ATA_BUS; + host_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(host_ehi, "interface fatal error"); + } + + if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { + ata_ehi_hotplugged(host_ehi); + ata_ehi_push_desc(host_ehi, "%s", + irq_stat & PORT_IRQ_CONNECT ? + "connection status changed" : "PHY RDY changed"); + } + + /* okay, let's hand over to EH */ if (irq_stat & PORT_IRQ_FREEZE) ata_port_freeze(ap); @@ -1375,7 +1424,8 @@ static void ahci_port_intr(struct ata_port *ap) sata_async_notification(ap); } - if (ap->link.sactive) + /* pp->active_link is valid iff any command is in flight */ + if (ap->qc_active && pp->active_link->sactive) qc_active = readl(port_mmio + PORT_SCR_ACT); else qc_active = readl(port_mmio + PORT_CMD_ISSUE); @@ -1513,6 +1563,13 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; + + /* Keep track of the currently active link. It will be used + * in completion path to determine whether NCQ phase is in + * progress. + */ + pp->active_link = qc->dev->link; if (qc->tf.protocol == ATA_PROT_NCQ) writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); @@ -1542,8 +1599,11 @@ static void ahci_thaw(struct ata_port *ap) writel(tmp, port_mmio + PORT_IRQ_STAT); writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); - /* turn IRQ back on */ - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + /* turn IRQ back on, ignore BAD_PMP if PMP isn't attached */ + tmp = pp->intr_mask; + if (!ap->nr_pmp_links) + tmp &= ~PORT_IRQ_BAD_PMP; + writel(tmp, port_mmio + PORT_IRQ_MASK); } static void ahci_error_handler(struct ata_port *ap) @@ -1555,8 +1615,10 @@ static void ahci_error_handler(struct ata_port *ap) } /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, - ahci_postreset); + sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset, + ahci_hardreset, ahci_postreset, + sata_pmp_std_prereset, ahci_pmp_softreset, + sata_pmp_std_hardreset, sata_pmp_std_postreset); } static void ahci_vt8251_error_handler(struct ata_port *ap) @@ -1581,11 +1643,74 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) ahci_kick_engine(ap, 1); } +static void ahci_pmp_attach(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + u32 cmd; + + cmd = readl(port_mmio + PORT_CMD); + cmd |= PORT_CMD_PMP; + writel(cmd, port_mmio + PORT_CMD); +} + +static void ahci_pmp_detach(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_host_priv *hpriv = ap->host->private_data; + unsigned long flags; + u32 cmd; + + cmd = readl(port_mmio + PORT_CMD); + cmd &= ~PORT_CMD_PMP; + writel(cmd, port_mmio + PORT_CMD); + + if (hpriv->cap & HOST_CAP_NCQ) { + spin_lock_irqsave(ap->lock, flags); + ap->flags |= ATA_FLAG_NCQ; + spin_unlock_irqrestore(ap->lock, flags); + } +} + +static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) +{ + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + int rc; + + ahci_kick_engine(ap, 0); + + sata_pmp_read_init_tf(&tf, dev, pmp, reg); + rc = ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, + SATA_PMP_SCR_TIMEOUT); + if (rc == 0) { + ahci_tf_read(ap, &tf); + *r_val = sata_pmp_read_val(&tf); + } + return rc; +} + +static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val) +{ + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + + ahci_kick_engine(ap, 0); + + sata_pmp_write_init_tf(&tf, dev, pmp, reg, val); + return ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, + SATA_PMP_SCR_TIMEOUT); +} + static int ahci_port_resume(struct ata_port *ap) { ahci_power_up(ap); ahci_start_port(ap); + if (ap->nr_pmp_links) + ahci_pmp_attach(ap); + else + ahci_pmp_detach(ap); + return 0; } @@ -1866,6 +1991,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (hpriv->cap & HOST_CAP_NCQ) pi.flags |= ATA_FLAG_NCQ; + if (hpriv->cap & HOST_CAP_PMP) + pi.flags |= ATA_FLAG_PMP; + host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map)); if (!host) return -ENOMEM; From 417a1a6d3d7abad4c5288135f640e6e38e7a65c5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:55 +0900 Subject: [PATCH 2479/2804] ahci: move host flags over to pi.private_data Private pi.flags area is full and we need more private flags. Move host private flags over to pi.private_data. During initialization, these flags are copied to hpriv->flags. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 63 +++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b697da483b70..35ede5c31b9f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -169,14 +169,16 @@ enum { PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ + /* hpriv->flags bits */ + AHCI_HFLAG_NO_NCQ = (1 << 0), + AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ + AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ + AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ + AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ + AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ + /* ap->flags bits */ - AHCI_FLAG_NO_NCQ = (1 << 24), - AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ - AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ - AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ - AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ - AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */ - AHCI_FLAG_NO_HOTPLUG = (1 << 31), /* ignore PxSERR.DIAG.N */ + AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | @@ -200,6 +202,7 @@ struct ahci_sg { }; struct ahci_host_priv { + unsigned int flags; /* AHCI_HFLAG_* */ u32 cap; /* cap to use */ u32 port_map; /* port map to use */ u32 saved_cap; /* saved initial cap */ @@ -341,6 +344,8 @@ static const struct ata_port_operations ahci_vt8251_ops = { .port_stop = ahci_port_stop, }; +#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) + static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { @@ -352,7 +357,8 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_vt8251 */ { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -360,7 +366,8 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_ign_iferr */ { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR, + AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), + .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -368,9 +375,9 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_sb600 */ { - .flags = AHCI_FLAG_COMMON | - AHCI_FLAG_IGN_SERR_INTERNAL | - AHCI_FLAG_32BIT_ONLY, + AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | + AHCI_HFLAG_32BIT_ONLY), + .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -378,11 +385,10 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_mv */ { - .sht = &ahci_sht, + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | + AHCI_HFLAG_MV_PATA), .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | - AHCI_FLAG_MV_PATA, + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -534,7 +540,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap) /** * ahci_save_initial_config - Save and fixup initial config values * @pdev: target PCI device - * @pi: associated ATA port info * @hpriv: host private area to store config values * * Some registers containing configuration info might be setup by @@ -548,7 +553,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap) * None. */ static void ahci_save_initial_config(struct pci_dev *pdev, - const struct ata_port_info *pi, struct ahci_host_priv *hpriv) { void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; @@ -562,13 +566,13 @@ static void ahci_save_initial_config(struct pci_dev *pdev, hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); /* some chips have errata preventing 64bit use */ - if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) { + if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do 64bit DMA, forcing 32bit\n"); cap &= ~HOST_CAP_64; } - if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) { + if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do NCQ, turning off CAP_NCQ\n"); cap &= ~HOST_CAP_NCQ; @@ -579,7 +583,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, * is asserted through the standard AHCI port * presence register, as bit 4 (counting from 0) */ - if (pi->flags & AHCI_FLAG_MV_PATA) { + if (hpriv->flags & AHCI_HFLAG_MV_PATA) { dev_printk(KERN_ERR, &pdev->dev, "MV_AHCI HACK: port_map %x -> %x\n", hpriv->port_map, @@ -919,13 +923,14 @@ static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, static void ahci_init_controller(struct ata_host *host) { + struct ahci_host_priv *hpriv = host->private_data; struct pci_dev *pdev = to_pci_dev(host->dev); void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; int i; void __iomem *port_mmio; u32 tmp; - if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) { + if (hpriv->flags & AHCI_HFLAG_MV_PATA) { port_mmio = __ahci_port_base(host, 4); writel(0, port_mmio + PORT_IRQ_MASK); @@ -1307,6 +1312,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; struct ata_eh_info *host_ehi = &ap->link.eh_info; struct ata_link *link = NULL; @@ -1334,7 +1340,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) host_ehi->serror |= serror; /* some controllers set IRQ_IF_ERR on device errors, ignore it */ - if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR) + if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) irq_stat &= ~PORT_IRQ_IF_ERR; if (irq_stat & PORT_IRQ_TF_ERR) { @@ -1347,7 +1353,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) else active_ehi->err_mask |= AC_ERR_DEV; - if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL) + if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) host_ehi->serror &= ~SERR_INTERNAL; } @@ -1977,15 +1983,16 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev)) - pci_intx(pdev, 1); - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; + hpriv->flags |= (unsigned long)pi.private_data; + + if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) + pci_intx(pdev, 1); /* save initial config */ - ahci_save_initial_config(pdev, &pi, hpriv); + ahci_save_initial_config(pdev, hpriv); /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) From 6949b9148d3656afc13a2ccc06d13c071ec71bdc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:55 +0900 Subject: [PATCH 2480/2804] ahci: implement AHCI_HFLAG_NO_PMP Of course some controllers lie about PMP support. Black list them. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 35ede5c31b9f..af7bf2679088 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -176,6 +176,7 @@ enum { AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ + AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ /* ap->flags bits */ AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */ @@ -357,7 +358,7 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_vt8251 */ { - AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, .pio_mask = 0x1f, /* pio0-4 */ @@ -376,7 +377,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_sb600 */ { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_32BIT_ONLY), + AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ @@ -578,6 +579,12 @@ static void ahci_save_initial_config(struct pci_dev *pdev, cap &= ~HOST_CAP_NCQ; } + if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { + dev_printk(KERN_INFO, &pdev->dev, + "controller can't do PMP, turning off CAP_PMP\n"); + cap &= ~HOST_CAP_PMP; + } + /* * Temporary Marvell 6145 hack: PATA port presence * is asserted through the standard AHCI port From 1333e19434da116bc832e1b8925359d1565fedc9 Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Tue, 2 Oct 2007 11:22:02 -0400 Subject: [PATCH 2481/2804] libata: add human-readable error value decoding This adds human-readable decoding of the ATA status and error registers (similar to what drivers/ide does) as well as the SATA Serror register to libata error handling output. This prevents the need to pore through standards documents to figure out the meaning of the bits in these registers when looking at error reports. Some bits that drivers/ide decoded are not decoded here, since the bits are either command-dependent or obsolete, and properly parsing them would add too much complexity. Signed-off-by: Robert Hancock [edited slightly to make output a bit more symmetric] Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 45 +++++++++++++++++++++++++++++++++++++++++ include/linux/ata.h | 9 +++++++++ 2 files changed, 54 insertions(+) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5f2c0f376f74..0bd3898793a7 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1911,6 +1911,27 @@ static void ata_eh_link_report(struct ata_link *link) ata_link_printk(link, KERN_ERR, "%s\n", desc); } + if (ehc->i.serror) + ata_port_printk(ap, KERN_ERR, + "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n", + ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "", + ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "", + ehc->i.serror & SERR_DATA ? "UnrecovData " : "", + ehc->i.serror & SERR_PERSISTENT ? "Persist " : "", + ehc->i.serror & SERR_PROTOCOL ? "Proto " : "", + ehc->i.serror & SERR_INTERNAL ? "HostInt " : "", + ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "", + ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "", + ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "", + ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "", + ehc->i.serror & SERR_DISPARITY ? "Dispar " : "", + ehc->i.serror & SERR_CRC ? "BadCRC " : "", + ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "", + ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "", + ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "", + ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "", + ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "" ); + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { static const char *dma_str[] = { [DMA_BIDIRECTIONAL] = "bidi", @@ -1942,6 +1963,30 @@ static void ata_eh_link_report(struct ata_link *link) res->hob_lbal, res->hob_lbam, res->hob_lbah, res->device, qc->err_mask, ata_err_string(qc->err_mask), qc->err_mask & AC_ERR_NCQ ? " " : ""); + + if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | + ATA_ERR) ) { + if (res->command & ATA_BUSY) + ata_dev_printk(qc->dev, KERN_ERR, + "status: { Busy }\n" ); + else + ata_dev_printk(qc->dev, KERN_ERR, + "status: { %s%s%s%s}\n", + res->command & ATA_DRDY ? "DRDY " : "", + res->command & ATA_DF ? "DF " : "", + res->command & ATA_DRQ ? "DRQ " : "", + res->command & ATA_ERR ? "ERR " : "" ); + } + + if (cmd->command != ATA_CMD_PACKET && + (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF | + ATA_ABORTED))) + ata_dev_printk(qc->dev, KERN_ERR, + "error: { %s%s%s%s}\n", + res->feature & ATA_ICRC ? "ICRC " : "", + res->feature & ATA_UNC ? "UNC " : "", + res->feature & ATA_IDNF ? "IDNF " : "", + res->feature & ATA_ABORTED ? "ABRT " : "" ); } } diff --git a/include/linux/ata.h b/include/linux/ata.h index 21f00a0646d8..a4f373f8b798 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -287,6 +287,15 @@ enum { SERR_PROTOCOL = (1 << 10), /* protocol violation */ SERR_INTERNAL = (1 << 11), /* host internal error */ SERR_PHYRDY_CHG = (1 << 16), /* PHY RDY changed */ + SERR_PHY_INT_ERR = (1 << 17), /* PHY internal error */ + SERR_COMM_WAKE = (1 << 18), /* Comm wake */ + SERR_10B_8B_ERR = (1 << 19), /* 10b to 8b decode error */ + SERR_DISPARITY = (1 << 20), /* Disparity */ + SERR_CRC = (1 << 21), /* CRC error */ + SERR_HANDSHAKE = (1 << 22), /* Handshake error */ + SERR_LINK_SEQ_ERR = (1 << 23), /* Link sequence error */ + SERR_TRANS_ST_ERROR = (1 << 24), /* Transport state trans. error */ + SERR_UNRECOG_FIS = (1 << 25), /* Unrecognized FIS */ SERR_DEV_XCHG = (1 << 26), /* device exchanged */ /* struct ata_taskfile flags */ From 7100819f5f9b99eb7c7dd5597f293388a405bf7b Mon Sep 17 00:00:00 2001 From: Peer Chen Date: Mon, 24 Sep 2007 10:16:25 +0800 Subject: [PATCH 2482/2804] ahci: Add MCP79 support to AHCI driver Signed-off-by: Peer Chen Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index af7bf2679088..24fb90f58cd1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -491,6 +491,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ + { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ /* SiS */ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ From b3a706014e56b1356e7b275fd25b833c63175bf0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 2 Oct 2007 12:38:26 -0400 Subject: [PATCH 2483/2804] libata: Add a drivers/ide style DMA disable This is useful when debugging, handling problem systems, or for distributions just to get the system installed so it can be sorted out later. This is a bit smarter than the old IDE one and lets you do libata.dma=0 Disable all PATA DMA like old IDE libata.dma=1 Disk DMA only libata.dma=2 ATAPI DMA only libata.dma=4 CF DMA only (or combinations thereof - 0,1,3 being the useful ones I suspect) (I've split CF as it seems to be a seperate case of pain and suffering different to the others and caused by assorted PIO wired adapters etc) Signed-off-by: Alan Cox [edited to work on SATA too, changing name from 'pata_dma' to 'dma'] Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 17 +++++++++++++++++ include/linux/libata.h | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5532a6564d05..1501d63db2cb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -97,6 +97,10 @@ static int ata_ignore_hpa = 0; module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)"); +static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA; +module_param_named(dma, libata_dma_mask, int, 0444); +MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)"); + static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); @@ -2917,14 +2921,27 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) /* step 1: calculate xfer_mask */ ata_link_for_each_dev(dev, link) { unsigned int pio_mask, dma_mask; + unsigned int mode_mask; if (!ata_dev_enabled(dev)) continue; + mode_mask = ATA_DMA_MASK_ATA; + if (dev->class == ATA_DEV_ATAPI) + mode_mask = ATA_DMA_MASK_ATAPI; + else if (ata_id_is_cfa(dev->id)) + mode_mask = ATA_DMA_MASK_CFA; + ata_dev_xfermask(dev); pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0); dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); + + if (libata_dma_mask & mode_mask) + dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); + else + dma_mask = 0; + dev->pio_mode = ata_xfer_mask2mode(pio_mask); dev->dma_mode = ata_xfer_mask2mode(dma_mask); diff --git a/include/linux/libata.h b/include/linux/libata.h index ca296a575c4a..84dfc23b9d31 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -331,6 +331,12 @@ enum { ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ + + /* DMA mask for user DMA control: User visible values; DO NOT + renumber */ + ATA_DMA_MASK_ATA = (1 << 0), /* DMA on ATA Disk */ + ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */ + ATA_DMA_MASK_CFA = (1 << 2), /* DMA on CF Card */ }; enum hsm_task_states { From 237d8440cb2b104a3b97fc971a9bce67960bb616 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 3 Oct 2007 01:24:16 +0100 Subject: [PATCH 2484/2804] libata: Integrate ACPI-based PATA/SATA hotplug - version 5 Modern laptops with hotswap bays still tend to utilise a PATA interface on a SATA bridge, generally with the host controller in some legacy emulation mode rather than AHCI. This means that the existing hotplug code in libata is unable to work. The ACPI specification states that these devices can send notifications when hotswapped, which avoids the need to obtain notification from the controller. This patch uses the existing libata-acpi code and simply registers a notification in order to trigger a rescan whenever the firmware signals an event. Signed-off-by: Matthew Garrett Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 60 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index a276c06dda95..5ebbf16f3af1 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "libata.h" #include @@ -95,6 +96,47 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) } } +static void ata_acpi_handle_hotplug (struct ata_port *ap, struct kobject *kobj, + u32 event) +{ + char event_string[12]; + char *envp[] = { event_string, NULL }; + struct ata_eh_info *ehi = &ap->link.eh_info; + + if (event == 0 || event == 1) { + unsigned long flags; + spin_lock_irqsave(ap->lock, flags); + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "ACPI event"); + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); + spin_unlock_irqrestore(ap->lock, flags); + } + + if (kobj) { + sprintf(event_string, "BAY_EVENT=%d", event); + kobject_uevent_env(kobj, KOBJ_CHANGE, envp); + } +} + +static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_device *dev = data; + struct kobject *kobj = NULL; + + if (dev->sdev) + kobj = &dev->sdev->sdev_gendev.kobj; + + ata_acpi_handle_hotplug (dev->link->ap, kobj, event); +} + +static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_port *ap = data; + + ata_acpi_handle_hotplug (ap, &ap->dev->kobj, event); +} + /** * ata_acpi_associate - associate ATA host with ACPI objects * @host: target ATA host @@ -110,7 +152,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) */ void ata_acpi_associate(struct ata_host *host) { - int i; + int i, j; if (!is_pci_dev(host->dev) || libata_noacpi) return; @@ -126,6 +168,22 @@ void ata_acpi_associate(struct ata_host *host) ata_acpi_associate_sata_port(ap); else ata_acpi_associate_ide_port(ap); + + if (ap->acpi_handle) + acpi_install_notify_handler (ap->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_ap_notify, + ap); + + for (j = 0; j < ata_link_max_devices(&ap->link); j++) { + struct ata_device *dev = &ap->link.device[j]; + + if (dev->acpi_handle) + acpi_install_notify_handler (dev->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_dev_notify, + dev); + } } } From 681c80b5d96076f447e8101ac4325c82d8dce508 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 3 Oct 2007 13:23:18 +0100 Subject: [PATCH 2485/2804] libata: correct handling of SRST reset sequences Correct handling of SRST reset sequences. After an SRST it is undefined whether the drive has gone back to PIO0. In order to talk safely we should talk slowly and carefully until we know. Thus when we do the reset if the controller has a pio setup method we call it to flip back to PIO 0 and a known state. After the reset completes the identify will then be done at the safe speed and the drive/controller will pick suitable faster modes and reconfigure the controller to these timings. As a side effect it means we force the controller to PIO 0 as we bring it up which fixes funnies on a few systems where the BIOS firmware leaves us in an interesting choice of modes, or embedded boxes with no firmware which come up in random states. For smart controllers there is nothing to do - they know about this internally. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1501d63db2cb..aecbdad960fb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3209,6 +3209,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; + struct ata_device *dev; + int i = 0; DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); @@ -3219,6 +3221,25 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, udelay(20); /* FIXME: flush */ iowrite8(ap->ctl, ioaddr->ctl_addr); + /* If we issued an SRST then an ATA drive (not ATAPI) + * may have changed configuration and be in PIO0 timing. If + * we did a hard reset (or are coming from power on) this is + * true for ATA or ATAPI. Until we've set a suitable controller + * mode we should not touch the bus as we may be talking too fast. + */ + + ata_link_for_each_dev(dev, &ap->link) + dev->pio_mode = XFER_PIO_0; + + /* If the controller has a pio mode setup function then use + it to set the chipset to rights. Don't touch the DMA setup + as that will be dealt with when revalidating */ + if (ap->ops->set_piomode) { + ata_link_for_each_dev(dev, &ap->link) + if (devmask & (1 << i++)) + ap->ops->set_piomode(ap, dev); + } + /* spec mandates ">= 2ms" before checking status. * We wait 150ms, because that was the magic delay used for * ATAPI devices in Hale Landis's ATADRVR, for the period of time From 2db78dd302d26d242d3e8e5c4c5024b6c3ea93c2 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 2 Oct 2007 13:53:04 -0700 Subject: [PATCH 2486/2804] libata_scsi: Fix ATAPI transfer lengths Some controller variants snoop the ATAPI length value for Packet transfers to do state machine and FIFO management. Thus we want to set it properly, even for cases where it is otherwise meaningless. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index df2e05738f3b..ea53e6a570b4 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2305,8 +2305,8 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) qc->tf.feature |= ATAPI_PKT_DMA; } else { qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; + qc->tf.lbam = SCSI_SENSE_BUFFERSIZE; + qc->tf.lbah = 0; } qc->nbytes = SCSI_SENSE_BUFFERSIZE; @@ -2415,6 +2415,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) struct ata_device *dev = qc->dev; int using_pio = (dev->flags & ATA_DFLAG_PIO); int nodata = (scmd->sc_data_direction == DMA_NONE); + unsigned int nbytes; memset(qc->cdb, 0, dev->cdb_len); memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len); @@ -2434,14 +2435,20 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) if (!using_pio && ata_check_atapi_dma(qc)) using_pio = 1; + /* Some controller variants snoop this value for Packet transfers + to do state machine and FIFO management. Thus we want to set it + properly, and for DMA where it is effectively meaningless */ + nbytes = min(qc->nbytes, (unsigned int)63 * 1024); + + qc->tf.lbam = (nbytes & 0xFF); + qc->tf.lbah = (nbytes >> 8); + if (using_pio || nodata) { /* no data, or PIO data xfer */ if (nodata) qc->tf.protocol = ATA_PROT_ATAPI_NODATA; else qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; } else { /* DMA data xfer */ qc->tf.protocol = ATA_PROT_ATAPI_DMA; @@ -2452,6 +2459,9 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) qc->tf.feature |= ATAPI_DMADIR; } + + /* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE + as ATAPI tape drives don't get this right otherwise */ return 0; } From 6ebe9d8667d3f449350cbc6686cd917ecf1f40dd Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 5 Oct 2007 16:28:36 -0400 Subject: [PATCH 2487/2804] [libata] Turn on ACPI by default Let's see what explodes. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index aecbdad960fb..64d2c99d15e1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -105,9 +105,9 @@ static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); -int libata_noacpi = 1; +int libata_noacpi = 0; module_param_named(noacpi, libata_noacpi, int, 0444); -MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set"); +MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set"); MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); From da6f0ec2d54acf545e784363aa5bad0dafc5ffa8 Mon Sep 17 00:00:00 2001 From: Paolo Ornati Date: Thu, 4 Oct 2007 11:06:56 +0900 Subject: [PATCH 2488/2804] libata: blacklist NCQ on Seagate Barracuda ST380817AS Seagate Barracuda ST380817AS has troubles with NCQ. For example, unpacking a tarball on an XFS filesystem gives this: ata1.00: exception Emask 0x0 SAct 0x1 SErr 0x0 action 0x2 frozen ata1.00: cmd 61/40:00:29:a3:98/00:00:00:00:00/40 tag 0 cdb 0x0 data 32768 out res 40/00:00:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout) More info here: http://lkml.org/lkml/2007/1/21/76 Blacklist it! Signed-off-by: Paolo Ornati Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 64d2c99d15e1..a169ed9849c1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3958,6 +3958,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ }, { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ }, + { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ }, /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ From 70edb185dbaa8a9ec0d6f3e50bb5698a4e85ded6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 4 Oct 2007 17:27:59 +0900 Subject: [PATCH 2489/2804] libata: add HDT722516DLA380 to NCQ blacklist HDT722516DLA380 does spurious completion of NCQ commands. Blacklist it. Signed-off-by: Tejun Heo Cc: Frans Pop Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a169ed9849c1..d71f0d05403c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3968,6 +3968,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Drives which do spurious command completion */ { "HTS541680J9SA00", "SB2IC7EP", ATA_HORKAGE_NONCQ, }, { "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, }, + { "HDT722516DLA380", "V43OA96A", ATA_HORKAGE_NONCQ, }, { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, }, { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, }, From badff03df7a005d13ea2ae8ddc2f5ec0cfc049e8 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 4 Oct 2007 21:28:18 +0100 Subject: [PATCH 2490/2804] libata-core: Expose gtm methods for driver use Talk to the dark side our driver has to, yes. Much misleading is the data. Store it in a structure we do so that it may be parsed. Signed-off-by: Alan Cox -- Whats small, old and shouts phrases out of order across mountains ? Yodla.. Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 8 ++++++-- include/linux/libata.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 5ebbf16f3af1..f862e07d92f2 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -200,7 +200,7 @@ void ata_acpi_associate(struct ata_host *host) * RETURNS: * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. */ -static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) +int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) { struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; union acpi_object *out_obj; @@ -244,6 +244,8 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) return rc; } +EXPORT_SYMBOL_GPL(ata_acpi_gtm); + /** * ata_acpi_stm - execute _STM * @ap: target ATA port @@ -257,7 +259,7 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) * RETURNS: * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure. */ -static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) +int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) { acpi_status status; struct acpi_object_list input; @@ -289,6 +291,8 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) return 0; } +EXPORT_SYMBOL_GPL(ata_acpi_stm); + /** * ata_dev_get_GTF - get the drive bootup default taskfile settings * @dev: target ATA device diff --git a/include/linux/libata.h b/include/linux/libata.h index 84dfc23b9d31..751aabc21a3e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -929,6 +929,8 @@ enum { /* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI extern int ata_acpi_cbl_80wire(struct ata_port *ap); +int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm); +int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *stm); #else static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } #endif From 025621f9a7c0efe1139d43d246136a0f3e8ea675 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 4 Oct 2007 21:32:58 +0100 Subject: [PATCH 2491/2804] pata_acpi: ACPI driver support On a cable there may be eighty wires or perhaps forty and we learn about its type In the world of ACPI So we call the GTM And we find the the timing rate And we look through it to see If eighty wire it must be Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines And the drivers last you see Picking up unknown pci ids and the code begins to work Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines [Full speed ahead, Mr Hacker, full speed ahead] Full speed over here sir! Checking Cable, checking cable Aye aye, 80 wire, Heaven heaven] If we use ACPI (ACPI) Every box (every box) has all we need (has all we need) Cable type (cable type) and mode timing (mode timing) In our ATA (in our ATA) subroutines (subroutines, ha ha) Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 + drivers/ata/Makefile | 2 + drivers/ata/pata_acpi.c | 395 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 406 insertions(+) create mode 100644 drivers/ata/pata_acpi.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index cf960bd1c00a..4672066167e3 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -173,6 +173,15 @@ config SATA_INIC162X help This option enables support for Initio 162x Serial ATA. +config PATA_ACPI + tristate "ACPI firmware driver for PATA" + depends on ATA_ACPI + help + This option enables an ACPI method driver which drives + motherboard PATA controller interfaces through the ACPI + firmware in the BIOS. This driver can sometimes handle + otherwise unsupported hardware. + config PATA_ALI tristate "ALi PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 7e937519a930..2a63645003eb 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -66,6 +66,8 @@ obj-$(CONFIG_PATA_SCC) += pata_scc.o obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o +# Should be last but two libata driver +obj-$(CONFIG_PATA_ACPI) += pata_acpi.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c new file mode 100644 index 000000000000..5d3920f6fd69 --- /dev/null +++ b/drivers/ata/pata_acpi.c @@ -0,0 +1,395 @@ +/* + * ACPI PATA driver + * + * (c) 2007 Red Hat + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata_acpi" +#define DRV_VERSION "0.2.3" + +struct pata_acpi { + struct ata_acpi_gtm gtm; + void *last; + unsigned long mask[2]; +}; + +/** + * pacpi_pre_reset - check for 40/80 pin + * @ap: Port + * @deadline: deadline jiffies for the operation + * + * Perform the PATA port setup we need. + */ + +static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct pata_acpi *acpi = ap->private_data; + if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0) + return -ENODEV; + + return ata_std_prereset(link, deadline); +} + +/** + * pacpi_cable_detect - cable type detection + * @ap: port to detect + * + * Perform device specific cable detection + */ + +static int pacpi_cable_detect(struct ata_port *ap) +{ + struct pata_acpi *acpi = ap->private_data; + + if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA)) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +/** + * pacpi_error_handler - Setup and error handler + * @ap: Port to handle + * + * LOCKING: + * None (inherited from caller). + */ + +static void pacpi_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, + NULL, ata_std_postreset); +} + +/* Welcome to ACPI, bring a bucket */ +static const unsigned int pio_cycle[7] = { + 600, 383, 240, 180, 120, 100, 80 +}; +static const unsigned int mwdma_cycle[5] = { + 480, 150, 120, 100, 80 +}; +static const unsigned int udma_cycle[7] = { + 120, 80, 60, 45, 30, 20, 15 +}; + +/** + * pacpi_discover_modes - filter non ACPI modes + * @adev: ATA device + * @mask: proposed modes + * + * Try the modes available and see which ones the ACPI method will + * set up sensibly. From this we get a mask of ACPI modes we can use + */ + +static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + int i; + u32 t; + unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO); + + struct ata_acpi_gtm probe; + + probe = acpi->gtm; + + /* We always use the 0 slot for crap hardware */ + if (!(probe.flags & 0x10)) + unit = 0; + + ata_acpi_gtm(ap, &probe); + + /* Start by scanning for PIO modes */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].pio; + if (t <= pio_cycle[i]) { + mask |= (2 << (ATA_SHIFT_PIO + i)) - 1; + break; + } + } + + /* See if we have MWDMA or UDMA data. We don't bother with MWDMA + if UDMA is availabe as this means the BIOS set UDMA and our + error changedown if it works is UDMA to PIO anyway */ + if (probe.flags & (1 << (2 * unit))) { + /* MWDMA */ + for (i = 0; i < 5; i++) { + t = probe.drive[unit].dma; + if (t <= mwdma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1; + break; + } + } + } else { + /* UDMA */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].dma; + if (t <= udma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1; + break; + } + } + } + if (mask & (0xF8 << ATA_SHIFT_UDMA)) + ap->cbl = ATA_CBL_PATA80; + return mask; +} + +/** + * pacpi_mode_filter - mode filter for ACPI + * @adev: device + * @mask: mask of valid modes + * + * Filter the valid mode list according to our own specific rules, in + * this case the list of discovered valid modes obtained by ACPI probing + */ + +static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask) +{ + struct pata_acpi *acpi = adev->link->ap->private_data; + return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]); +} + +/** + * pacpi_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + */ + +static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + + if(!(acpi->gtm.flags & 0x10)) + unit = 0; + + /* Now stuff the nS values into the structure */ + acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0]; + ata_acpi_stm(ap, &acpi->gtm); + /* See what mode we actually got */ + ata_acpi_gtm(ap, &acpi->gtm); +} + +/** + * pacpi_set_dmamode - set initial DMA mode data + * @ap: ATA interface + * @adev: ATA device + */ + +static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + + if(!(acpi->gtm.flags & 0x10)) + unit = 0; + + /* Now stuff the nS values into the structure */ + if (adev->dma_mode >= XFER_UDMA_0) { + acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0]; + acpi->gtm.flags |= (1 << (2 * unit)); + } else { + acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0]; + acpi->gtm.flags &= ~(1 << (2 * unit)); + } + ata_acpi_stm(ap, &acpi->gtm); + /* See what mode we actually got */ + ata_acpi_gtm(ap, &acpi->gtm); +} + +/** + * pacpi_qc_issue_prot - command issue + * @qc: command pending + * + * Called when the libata layer is about to issue a command. We wrap + * this interface so that we can load the correct ATA timings if + * neccessary. + */ + +static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *adev = qc->dev; + struct pata_acpi *acpi = ap->private_data; + + if (acpi->gtm.flags & 0x10) + return ata_qc_issue_prot(qc); + + if (adev != acpi->last) { + pacpi_set_piomode(ap, adev); + if (adev->dma_mode) + pacpi_set_dmamode(ap, adev); + acpi->last = adev; + } + return ata_qc_issue_prot(qc); +} + +/** + * pacpi_port_start - port setup + * @ap: ATA port being set up + * + * Use the port_start hook to maintain private control structures + */ + +static int pacpi_port_start(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct pata_acpi *acpi; + + int ret; + + if (ap->acpi_handle == NULL) + return -ENODEV; + + acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL); + if (ap->private_data == NULL) + return -ENOMEM; + acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]); + acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]); + ret = ata_sff_port_start(ap); + if (ret < 0) + return ret; + + return ret; +} + +static struct scsi_host_template pacpi_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + /* Use standard CHS mapping rules */ + .bios_param = ata_std_bios_param, +}; + +static const struct ata_port_operations pacpi_ops = { + .set_piomode = pacpi_set_piomode, + .set_dmamode = pacpi_set_dmamode, + .mode_filter = pacpi_mode_filter, + + /* Task file is PCI ATA format, use helpers */ + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = pacpi_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = pacpi_cable_detect, + + /* BMDMA handling is PCI ATA format, use helpers */ + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = pacpi_qc_issue_prot, + .data_xfer = ata_data_xfer, + + /* Timeout handling */ + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + /* Generic PATA PCI ATA helpers */ + .port_start = pacpi_port_start, +}; + + +/** + * pacpi_init_one - Register ACPI ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in pacpi_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) +{ + static const struct ata_port_info info = { + .sht = &pacpi_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + + .port_ops = &pacpi_ops, + }; + const struct ata_port_info *ppi[] = { &info, NULL }; + return ata_pci_init_one(pdev, ppi); +} + +static const struct pci_device_id pacpi_pci_tbl[] = { + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1}, + { } /* terminate list */ +}; + +static struct pci_driver pacpi_pci_driver = { + .name = DRV_NAME, + .id_table = pacpi_pci_tbl, + .probe = pacpi_init_one, + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +}; + +static int __init pacpi_init(void) +{ + return pci_register_driver(&pacpi_pci_driver); +} + +static void __exit pacpi_exit(void) +{ + pci_unregister_driver(&pacpi_pci_driver); +} + +module_init(pacpi_init); +module_exit(pacpi_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl); +MODULE_VERSION(DRV_VERSION); + From 954bb005c9d5368188ef03ff1d723ff3c0e8ae99 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 5 Oct 2007 08:54:39 +0900 Subject: [PATCH 2492/2804] libata: add ST9160821AS / 3.ALD to NCQ blacklist ST9160821AS / 3.ALD also does spurious NCQ completions. Disable NCQ. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d71f0d05403c..519ce586bd13 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3975,6 +3975,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, }, { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, + { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, }, { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, }, { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, }, { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, From a01f48b8e7f5ca1000d662fe205e6fe884e0d132 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 7 Oct 2007 07:04:50 +0900 Subject: [PATCH 2493/2804] pata_jmicron: match vendor and class code only PATA part of all current JMB controllers behave the same way and JMicron confirms that all future ones will stay compatible. Drop device matching and match only vendor and class. Signed-off-by: Tejun Heo Cc: Ethan Hsiao Cc: Justin Tsai Signed-off-by: Jeff Garzik --- drivers/ata/pata_jmicron.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 6d5a81869df6..225a7223a726 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -204,17 +204,8 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i } static const struct pci_device_id jmicron_pci_tbl[] = { - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 }, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 }, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 }, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 }, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 }, - + { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, { } /* terminate list */ }; From abf6e8ed07213bdd9734be2e42639b79310bd81c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 14:57:25 +0900 Subject: [PATCH 2494/2804] libata: clear ehi description after initial host report ehi description field is used to carry LLD specific controller description. Sometimes, it's used without clearing before and LLD description gets printed with exception information one more time. Clear after printing. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 519ce586bd13..db760e2dc30b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6773,13 +6773,14 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, ap->udma_mask); - if (!ata_port_is_dummy(ap)) + if (!ata_port_is_dummy(ap)) { ata_port_printk(ap, KERN_INFO, "%cATA max %s %s\n", (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', ata_mode_string(xfer_mask), ap->link.eh_info.desc); - else + ata_ehi_clear_desc(&ap->link.eh_info); + } else ata_port_printk(ap, KERN_INFO, "DUMMY\n"); } From 94ff3d54080975686a3c41e73b8926030ee0c31f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 14:57:56 +0900 Subject: [PATCH 2495/2804] libata: skip suppress reporting if ATA_EHI_QUIET ATA_EHI_NO_AUTOPSY and ATA_EHI_QUIET are used during initial probing to skip exception analysis and reporting. Usually, there's nothing to report but on some allowed but rare corner cases (e.g. phy status changed interrupt when IRQ is enabled on frozen port - this happens if IRQ pending status isn't cleared in the IRQ router or controller) exception messages get printed. Skip reporting if ATA_EHI_QUIET is set. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0bd3898793a7..866ac9d5530a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1868,6 +1868,9 @@ static void ata_eh_link_report(struct ata_link *link) char tries_buf[6]; int tag, nr_failed = 0; + if (ehc->i.flags & ATA_EHI_QUIET) + return; + desc = NULL; if (ehc->i.desc[0] != '\0') desc = ehc->i.desc; From 9073868376ed5fa1f247327ccb2e6f766d5b7eed Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 14:58:33 +0900 Subject: [PATCH 2496/2804] libata: wrap schedule_timeout_uninterruptible() in loop Tasks in uninterruptible sleep might be woken up by unrelated events and should check whether the condition it was waiting for has actually triggered. Wrap schedule_timeout_uninterruptible() in loop to achieve it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 866ac9d5530a..8aa61403303f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2183,7 +2183,8 @@ int ata_eh_reset(struct ata_link *link, int classify, "(errno=%d), retrying in %u secs\n", rc, (jiffies_to_msecs(delta) + 999) / 1000); - schedule_timeout_uninterruptible(delta); + while (delta) + delta = schedule_timeout_uninterruptible(delta); } if (rc == -EPIPE || From 75da6d2b8f518bec40546bc0b0696a2cebecf6cc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 14:59:50 +0900 Subject: [PATCH 2497/2804] ahci: kill leftover from enabling NCQ over PMP ahci had problems with NCQ over PMP and NCQ used to be disabled while PMP was attached. After fixing the problem, the temporary NCQ disabling code wasn't removed completely. Kill the remaining piece. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 24fb90f58cd1..694eabcb932f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1677,19 +1677,11 @@ static void ahci_pmp_attach(struct ata_port *ap) static void ahci_pmp_detach(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_host_priv *hpriv = ap->host->private_data; - unsigned long flags; u32 cmd; cmd = readl(port_mmio + PORT_CMD); cmd &= ~PORT_CMD_PMP; writel(cmd, port_mmio + PORT_CMD); - - if (hpriv->cap & HOST_CAP_NCQ) { - spin_lock_irqsave(ap->lock, flags); - ap->flags |= ATA_FLAG_NCQ; - spin_unlock_irqrestore(ap->lock, flags); - } } static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) From 1c954a4d9a9e351fa3509533fd8dd5f3821206cd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:01:37 +0900 Subject: [PATCH 2498/2804] ahci: clean up PORT_IRQ_BAD_PMP enabling Now that we have pp->intr_mask, move PORT_IRQ_BAD_PMP enabling to ahci_pmp_attach/detach() where it belongs. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 694eabcb932f..6633c7422fc4 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1620,11 +1620,8 @@ static void ahci_thaw(struct ata_port *ap) writel(tmp, port_mmio + PORT_IRQ_STAT); writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); - /* turn IRQ back on, ignore BAD_PMP if PMP isn't attached */ - tmp = pp->intr_mask; - if (!ap->nr_pmp_links) - tmp &= ~PORT_IRQ_BAD_PMP; - writel(tmp, port_mmio + PORT_IRQ_MASK); + /* turn IRQ back on */ + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_error_handler(struct ata_port *ap) @@ -1667,21 +1664,29 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) static void ahci_pmp_attach(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; u32 cmd; cmd = readl(port_mmio + PORT_CMD); cmd |= PORT_CMD_PMP; writel(cmd, port_mmio + PORT_CMD); + + pp->intr_mask |= PORT_IRQ_BAD_PMP; + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_pmp_detach(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; u32 cmd; cmd = readl(port_mmio + PORT_CMD); cmd &= ~PORT_CMD_PMP; writel(cmd, port_mmio + PORT_CMD); + + pp->intr_mask &= ~PORT_IRQ_BAD_PMP; + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) From 5f226c6bf78edab023ed1ea679531731d9df92a6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:02:23 +0900 Subject: [PATCH 2499/2804] ahci: fix notification handling Asynchronous notification on ICH9 didn't work because it didn't write AN FIS into the RX area - it only updates SNotification. Also, snooping SDB_FIS RX area is racy against further SDB FIS receptions. Let sata_async_notification() determine using SNTF if it's available and snoop RX area iff SNTF isn't available Signed-off-by: Tejun Heo Cc: Kristen Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6633c7422fc4..abfb72aae3de 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1420,6 +1420,7 @@ static void ahci_port_intr(struct ata_port *ap) void __iomem *port_mmio = ap->ioaddr.cmd_addr; struct ata_eh_info *ehi = &ap->link.eh_info; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; u32 status, qc_active; int rc, known_irq = 0; @@ -1432,17 +1433,28 @@ static void ahci_port_intr(struct ata_port *ap) } if (status & PORT_IRQ_SDB_FIS) { - /* If the 'N' bit in word 0 of the FIS is set, we just - * received asynchronous notification. Tell libata - * about it. Note that as the SDB FIS itself is - * accessible, SNotification can be emulated by the - * driver but don't bother for the time being. + /* If SNotification is available, leave notification + * handling to sata_async_notification(). If not, + * emulate it by snooping SDB FIS RX area. + * + * Snooping FIS RX area is probably cheaper than + * poking SNotification but some constrollers which + * implement SNotification, ICH9 for example, don't + * store AN SDB FIS into receive area. */ - const __le32 *f = pp->rx_fis + RX_FIS_SDB; - u32 f0 = le32_to_cpu(f[0]); - - if (f0 & (1 << 15)) + if (hpriv->cap & HOST_CAP_SNTF) sata_async_notification(ap); + else { + /* If the 'N' bit in word 0 of the FIS is set, + * we just received asynchronous notification. + * Tell libata about it. + */ + const __le32 *f = pp->rx_fis + RX_FIS_SDB; + u32 f0 = le32_to_cpu(f[0]); + + if (f0 & (1 << 15)) + sata_async_notification(ap); + } } /* pp->active_link is valid iff any command is in flight */ From 2b789108fc1dcba22050a7e6e29ae5ebaea427dd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:05:44 +0900 Subject: [PATCH 2500/2804] libata: add @timeout to ata_exec_internal[_sg]() Add @timeout argument to ata_exec_internal[_sg](). If 0, default timeout ata_probe_timeout is used. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 2 +- drivers/ata/libata-core.c | 32 ++++++++++++++++++++------------ drivers/ata/libata-eh.c | 4 ++-- drivers/ata/libata.h | 5 +++-- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index f862e07d92f2..3f7533589041 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -478,7 +478,7 @@ static int taskfile_load_raw(struct ata_device *dev, tf.lbal, tf.lbam, tf.lbah, tf.device); rtf = tf; - err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { ata_dev_printk(dev, KERN_ERR, "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed " diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index db760e2dc30b..59ebc5d5100a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -926,7 +926,7 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) tf.protocol |= ATA_PROT_NODATA; tf.device |= ATA_LBA; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { ata_dev_printk(dev, KERN_WARNING, "failed to read native " "max address (err_mask=0x%x)\n", err_mask); @@ -988,7 +988,7 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) tf.lbam = (new_sectors >> 8) & 0xff; tf.lbah = (new_sectors >> 16) & 0xff; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { ata_dev_printk(dev, KERN_WARNING, "failed to set " "max address (err_mask=0x%x)\n", err_mask); @@ -1394,6 +1394,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc) * @dma_dir: Data tranfer direction of the command * @sg: sg list for the data buffer of the command * @n_elem: Number of sg entries + * @timeout: Timeout in msecs (0 for default) * * Executes libata internal command with timeout. @tf contains * command on entry and result on return. Timeout and error @@ -1410,7 +1411,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc) unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, struct scatterlist *sg, - unsigned int n_elem) + unsigned int n_elem, unsigned long timeout) { struct ata_link *link = dev->link; struct ata_port *ap = link->ap; @@ -1486,7 +1487,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, spin_unlock_irqrestore(ap->lock, flags); - rc = wait_for_completion_timeout(&wait, ata_probe_timeout); + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout)); ata_port_flush_task(ap); @@ -1571,6 +1575,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, * @dma_dir: Data tranfer direction of the command * @buf: Data buffer of the command * @buflen: Length of data buffer + * @timeout: Timeout in msecs (0 for default) * * Wrapper around ata_exec_internal_sg() which takes simple * buffer instead of sg list. @@ -1583,7 +1588,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, */ unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, void *buf, unsigned int buflen) + int dma_dir, void *buf, unsigned int buflen, + unsigned long timeout) { struct scatterlist *psg = NULL, sg; unsigned int n_elem = 0; @@ -1595,7 +1601,8 @@ unsigned ata_exec_internal(struct ata_device *dev, n_elem++; } - return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem); + return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem, + timeout); } /** @@ -1622,7 +1629,7 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) tf.flags |= ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; - return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); } /** @@ -1737,7 +1744,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.flags |= ATA_TFLAG_POLLING; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - id, sizeof(id[0]) * ATA_ID_WORDS); + id, sizeof(id[0]) * ATA_ID_WORDS, 0); if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { DPRINTK("ata%u.%d: NODEV after polling detection\n", @@ -1796,7 +1803,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.feature = SETFEATURES_SPINUP; tf.protocol = ATA_PROT_NODATA; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, + DMA_NONE, NULL, 0, 0); if (err_mask && id[2] != 0x738c) { rc = -EIO; reason = "SPINUP failed"; @@ -4157,7 +4165,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) tf.protocol = ATA_PROT_NODATA; tf.nsect = dev->xfer_mode; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -4193,7 +4201,7 @@ static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable) tf.protocol = ATA_PROT_NODATA; tf.nsect = SATA_AN; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -4231,7 +4239,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, tf.nsect = sectors; tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); /* A clean abort indicates an original or just out of spec drive and we should continue as we issue the setup based on the drive reported working geometry */ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8aa61403303f..c0e9a42e6ae7 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1249,7 +1249,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev, tf.protocol = ATA_PROT_PIO; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - buf, sectors * ATA_SECT_SIZE); + buf, sectors * ATA_SECT_SIZE, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -1363,7 +1363,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) } return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, - sense_buf, SCSI_SENSE_BUFFERSIZE); + sense_buf, SCSI_SENSE_BUFFERSIZE, 0); } /** diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index f8bd955c5ba7..90df58a3edc9 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -69,11 +69,12 @@ extern void ata_dev_disable(struct ata_device *dev); extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, void *buf, unsigned int buflen); + int dma_dir, void *buf, unsigned int buflen, + unsigned long timeout); extern unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, struct scatterlist *sg, - unsigned int n_elem); + unsigned int n_elem, unsigned long timeout); extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id); From afaa5c373d2c49ee4865847031b82f1377f609d0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:06:10 +0900 Subject: [PATCH 2501/2804] libata: implement ATA_PFLAG_RESETTING Implement ATA_PFLAG_RESETTING. This flag is set while reset is in progress. It's set before prereset is called and cleared after reset fails or postreset is finished. This flag itself doesn't have any function. It will be used by LLDs to tell whether reset is in progress if it needs to behave differently during reset. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 11 +++++++++++ include/linux/libata.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index c0e9a42e6ae7..1f84e40fa6ae 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2063,6 +2063,7 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); @@ -2071,9 +2072,14 @@ int ata_eh_reset(struct ata_link *link, int classify, unsigned long deadline; unsigned int action; ata_reset_fn_t reset; + unsigned long flags; int rc; /* about to reset */ + spin_lock_irqsave(ap->lock, flags); + ap->pflags |= ATA_PFLAG_RESETTING; + spin_unlock_irqrestore(ap->lock, flags); + ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); /* Determine which reset to use and record in ehc->i.action. @@ -2231,6 +2237,11 @@ int ata_eh_reset(struct ata_link *link, int classify, out: /* clear hotplug flag */ ehc->i.flags &= ~ATA_EHI_HOTPLUGGED; + + spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~ATA_PFLAG_RESETTING; + spin_unlock_irqrestore(ap->lock, flags); + return rc; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 751aabc21a3e..529af9fbed53 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -210,6 +210,7 @@ enum { ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */ ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */ ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */ + ATA_PFLAG_RESETTING = (1 << 8), /* reset in progress */ ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */ ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */ From b06ce3e51e3df4394a584c234f11240b1c6f8d5b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:06:48 +0900 Subject: [PATCH 2502/2804] libata: use ata_exec_internal() for PMP register access PMP registers used to be accessed with dedicated accessors ->pmp_read and ->pmp_write. During reset, those callbacks are called with the port frozen so they should be able to run without depending on interrupt delivery. To achieve this, they were implemented polling. However, as resetting the host port makes the PMP to isolate fan-out ports until SError.X is cleared, resetting fan-out ports while port is frozen doesn't buy much additional safety. This patch updates libata PMP support such that PMP registers are accessed using regular ata_exec_internal() mechanism and kills ->pmp_read/write() callbacks. The following changes are made. * PMP access helpers - sata_pmp_read_init_tf(), sata_pmp_read_val(), sata_pmp_write_init_tf() are folded into sata_pmp_read/write() which are now standalone PMP register access functions. * sata_pmp_read/write() returns err_mask instead of rc. This is consistent with other functions which issue internal commands and allows more detailed error reporting. * ahci interrupt handler is modified to ignore BAD_PMP and spurious/illegal completion IRQs while reset is in progress. These conditions are expected during reset. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 48 +++------ drivers/ata/libata-core.c | 3 - drivers/ata/libata-eh.c | 17 +++- drivers/ata/libata-pmp.c | 201 +++++++++++++++++--------------------- drivers/ata/sata_sil24.c | 30 ------ include/linux/libata.h | 8 -- 6 files changed, 114 insertions(+), 193 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index abfb72aae3de..10bc3f64c453 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -239,8 +239,6 @@ static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); static void ahci_pmp_attach(struct ata_port *ap); static void ahci_pmp_detach(struct ata_port *ap); -static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val); -static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val); static void ahci_error_handler(struct ata_port *ap); static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); @@ -297,8 +295,6 @@ static const struct ata_port_operations ahci_ops = { .pmp_attach = ahci_pmp_attach, .pmp_detach = ahci_pmp_detach, - .pmp_read = ahci_pmp_read, - .pmp_write = ahci_pmp_write, #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, @@ -333,8 +329,6 @@ static const struct ata_port_operations ahci_vt8251_ops = { .pmp_attach = ahci_pmp_attach, .pmp_detach = ahci_pmp_detach, - .pmp_read = ahci_pmp_read, - .pmp_write = ahci_pmp_write, #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, @@ -1421,12 +1415,17 @@ static void ahci_port_intr(struct ata_port *ap) struct ata_eh_info *ehi = &ap->link.eh_info; struct ahci_port_priv *pp = ap->private_data; struct ahci_host_priv *hpriv = ap->host->private_data; + int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); u32 status, qc_active; int rc, known_irq = 0; status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); + /* ignore BAD_PMP while resetting */ + if (unlikely(resetting)) + status &= ~PORT_IRQ_BAD_PMP; + if (unlikely(status & PORT_IRQ_ERROR)) { ahci_error_intr(ap, status); return; @@ -1464,6 +1463,13 @@ static void ahci_port_intr(struct ata_port *ap) qc_active = readl(port_mmio + PORT_CMD_ISSUE); rc = ata_qc_complete_multiple(ap, qc_active, NULL); + + /* If resetting, spurious or invalid completions are expected, + * return unconditionally. + */ + if (resetting) + return; + if (rc > 0) return; if (rc < 0) { @@ -1701,36 +1707,6 @@ static void ahci_pmp_detach(struct ata_port *ap) writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } -static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - int rc; - - ahci_kick_engine(ap, 0); - - sata_pmp_read_init_tf(&tf, dev, pmp, reg); - rc = ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, - SATA_PMP_SCR_TIMEOUT); - if (rc == 0) { - ahci_tf_read(ap, &tf); - *r_val = sata_pmp_read_val(&tf); - } - return rc; -} - -static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - - ahci_kick_engine(ap, 0); - - sata_pmp_write_init_tf(&tf, dev, pmp, reg, val); - return ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, - SATA_PMP_SCR_TIMEOUT); -} - static int ahci_port_resume(struct ata_port *ap) { ahci_power_up(ap); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 59ebc5d5100a..ce8ccb434aff 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7354,9 +7354,6 @@ EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); -EXPORT_SYMBOL_GPL(sata_pmp_read_init_tf); -EXPORT_SYMBOL_GPL(sata_pmp_read_val); -EXPORT_SYMBOL_GPL(sata_pmp_write_init_tf); EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 1f84e40fa6ae..5a2b2af4d0c1 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2557,7 +2557,11 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* reset */ if (reset) { - ata_eh_freeze_port(ap); + /* if PMP is attached, this function only deals with + * downstream links, port should stay thawed. + */ + if (!ap->nr_pmp_links) + ata_eh_freeze_port(ap); ata_port_for_each_link(link, ap) { struct ata_eh_context *ehc = &link->eh_context; @@ -2575,7 +2579,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } } - ata_eh_thaw_port(ap); + if (!ap->nr_pmp_links) + ata_eh_thaw_port(ap); } /* the rest */ @@ -2610,8 +2615,14 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (ata_eh_handle_dev_fail(dev, rc)) nr_disabled_devs++; - if (ap->pflags & ATA_PFLAG_FROZEN) + if (ap->pflags & ATA_PFLAG_FROZEN) { + /* PMP reset requires working host port. + * Can't retry if it's frozen. + */ + if (ap->nr_pmp_links) + goto out; break; + } } if (nr_failed_devs) { diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index f6c4b11336e9..c0c4dbcde091 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -17,27 +17,35 @@ * @reg: register to read * @r_val: resulting value * - * Wrapper around ap->ops->pmp_read to make it easier to call and - * nomarlize error return value. + * Read PMP register. * * LOCKING: * Kernel thread context (may sleep). * * RETURNS: - * 0 on success, -errno on failure. + * 0 on success, AC_ERR_* mask on failure. */ -static int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) +static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) { struct ata_port *ap = link->ap; struct ata_device *pmp_dev = ap->link.device; - int rc; + struct ata_taskfile tf; + unsigned int err_mask; - might_sleep(); + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_READ; + tf.protocol = ATA_PROT_NODATA; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.feature = reg; + tf.device = link->pmp; - rc = ap->ops->pmp_read(pmp_dev, link->pmp, reg, r_val); - if (rc) - rc = -EIO; - return rc; + err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, + SATA_PMP_SCR_TIMEOUT); + if (err_mask) + return err_mask; + + *r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24; + return 0; } /** @@ -46,27 +54,33 @@ static int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) * @reg: register to write * @r_val: value to write * - * Wrapper around ap->ops->pmp_write to make it easier to call - * and nomarlize error return value. + * Write PMP register. * * LOCKING: * Kernel thread context (may sleep). * * RETURNS: - * 0 on success, -errno on failure. + * 0 on success, AC_ERR_* mask on failure. */ -static int sata_pmp_write(struct ata_link *link, int reg, u32 val) +static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val) { struct ata_port *ap = link->ap; struct ata_device *pmp_dev = ap->link.device; - int rc; + struct ata_taskfile tf; - might_sleep(); + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_WRITE; + tf.protocol = ATA_PROT_NODATA; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.feature = reg; + tf.device = link->pmp; + tf.nsect = val & 0xff; + tf.lbal = (val >> 8) & 0xff; + tf.lbam = (val >> 16) & 0xff; + tf.lbah = (val >> 24) & 0xff; - rc = ap->ops->pmp_write(pmp_dev, link->pmp, reg, val); - if (rc) - rc = -EIO; - return rc; + return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, + SATA_PMP_SCR_TIMEOUT); } /** @@ -99,71 +113,6 @@ int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc) return ATA_DEFER_PORT; } -/** - * sata_pmp_read_init_tf - initialize TF for PMP read - * @tf: taskfile to initialize - * @dev: PMP dev - * @pmp: port multiplier port number - * @reg: register to read - * - * Initialize @tf for PMP read command. - * - * LOCKING: - * None. - */ -void sata_pmp_read_init_tf(struct ata_taskfile *tf, - struct ata_device *dev, int pmp, int reg) -{ - ata_tf_init(dev, tf); - tf->command = ATA_CMD_PMP_READ; - tf->protocol = ATA_PROT_NODATA; - tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->feature = reg; - tf->device = pmp; -} - -/** - * sata_pmp_read_val - extract PMP read result from TF - * @tf: target TF - * - * Determine PMP read result from @tf. - * - * LOCKING: - * None. - */ -u32 sata_pmp_read_val(const struct ata_taskfile *tf) -{ - return tf->nsect | tf->lbal << 8 | tf->lbam << 16 | tf->lbah << 24; -} - -/** - * sata_pmp_read_init_tf - initialize TF for PMP write - * @tf: taskfile to initialize - * @dev: PMP dev - * @pmp: port multiplier port number - * @reg: register to read - * @val: value to write - * - * Initialize @tf for PMP write command. - * - * LOCKING: - * None. - */ -void sata_pmp_write_init_tf(struct ata_taskfile *tf, - struct ata_device *dev, int pmp, int reg, u32 val) -{ - ata_tf_init(dev, tf); - tf->command = ATA_CMD_PMP_WRITE; - tf->protocol = ATA_PROT_NODATA; - tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->feature = reg; - tf->device = pmp; - tf->nsect = val & 0xff; - tf->lbal = (val >> 8) & 0xff; - tf->lbam = (val >> 16) & 0xff; - tf->lbah = (val >> 24) & 0xff; -} - /** * sata_pmp_scr_read - read PSCR * @link: ATA link to read PSCR for @@ -181,10 +130,18 @@ void sata_pmp_write_init_tf(struct ata_taskfile *tf, */ int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val) { + unsigned int err_mask; + if (reg > SATA_PMP_PSCR_CONTROL) return -EINVAL; - return sata_pmp_read(link, reg, r_val); + err_mask = sata_pmp_read(link, reg, r_val); + if (err_mask) { + ata_link_printk(link, KERN_WARNING, "failed to read SCR %d " + "(Emask=0x%x)\n", reg, err_mask); + return -EIO; + } + return 0; } /** @@ -204,10 +161,18 @@ int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val) */ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) { + unsigned int err_mask; + if (reg > SATA_PMP_PSCR_CONTROL) return -EINVAL; - return sata_pmp_write(link, reg, val); + err_mask = sata_pmp_write(link, reg, val); + if (err_mask) { + ata_link_printk(link, KERN_WARNING, "failed to write SCR %d " + "(Emask=0x%x)\n", reg, err_mask); + return -EIO; + } + return 0; } /** @@ -361,16 +326,17 @@ void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class) static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr) { static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 }; - int i, rc; + int i; for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) { int reg = gscr_to_read[i]; + unsigned int err_mask; - rc = sata_pmp_read(dev->link, reg, &gscr[reg]); - if (rc) { - ata_dev_printk(dev, KERN_ERR, "failed to read " - "PMP GSCR[%d] (errno=%d)\n", reg, rc); - return rc; + err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to read PMP " + "GSCR[%d] (Emask=0x%x)\n", reg, err_mask); + return -EIO; } } @@ -392,6 +358,7 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) { struct ata_port *ap = dev->link->ap; u32 *gscr = dev->gscr; + unsigned int err_mask = 0; const char *reason; int nr_ports, rc; @@ -408,8 +375,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) dev->flags |= ATA_DFLAG_AN; /* monitor SERR_PHYRDY_CHG on fan-out ports */ - rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN, SERR_PHYRDY_CHG); - if (rc) { + err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN, + SERR_PHYRDY_CHG); + if (err_mask) { + rc = -EIO; reason = "failed to write GSCR_ERROR_EN"; goto fail; } @@ -418,9 +387,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) { gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY; - rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN, - gscr[SATA_PMP_GSCR_FEAT_EN]); - if (rc) { + err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN, + gscr[SATA_PMP_GSCR_FEAT_EN]); + if (err_mask) { + rc = -EIO; reason = "failed to write GSCR_FEAT_EN"; goto fail; } @@ -447,7 +417,8 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) fail: ata_dev_printk(dev, KERN_ERR, - "failed to configure Port Multiplier (%s)\n", reason); + "failed to configure Port Multiplier (%s, Emask=0x%x)\n", + reason, err_mask); return rc; } @@ -812,13 +783,14 @@ static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class) */ static int sata_pmp_revalidate_quick(struct ata_device *dev) { + unsigned int err_mask; u32 prod_id; - int rc; - rc = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id); - if (rc) { - ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID\n"); - return rc; + err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID " + "(Emask=0x%x)\n", err_mask); + return -EIO; } if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) { @@ -1049,6 +1021,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap, struct ata_eh_context *pmp_ehc = &pmp_link->eh_context; struct ata_link *link; struct ata_device *dev; + unsigned int err_mask; u32 gscr_error, sntf; int cnt, rc; @@ -1107,20 +1080,22 @@ static int sata_pmp_eh_recover(struct ata_port *ap, if (pmp_dev->flags & ATA_DFLAG_AN) { pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; - rc = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN, - pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]); - if (rc) { - ata_dev_printk(pmp_dev, KERN_ERR, - "failed to write PMP_FEAT_EN\n"); + err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN, + pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]); + if (err_mask) { + ata_dev_printk(pmp_dev, KERN_ERR, "failed to write " + "PMP_FEAT_EN (Emask=0x%x)\n", err_mask); + rc = -EIO; goto pmp_fail; } } /* check GSCR_ERROR */ - rc = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error); - if (rc) { - ata_dev_printk(pmp_dev, KERN_ERR, - "failed to read PMP_GSCR_ERROR\n"); + err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error); + if (err_mask) { + ata_dev_printk(pmp_dev, KERN_ERR, "failed to read " + "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask); + rc = -EIO; goto pmp_fail; } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 15b9a80a1782..b0619278454a 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -337,8 +337,6 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static void sil24_irq_clear(struct ata_port *ap); static void sil24_pmp_attach(struct ata_port *ap); static void sil24_pmp_detach(struct ata_port *ap); -static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val); -static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val); static void sil24_freeze(struct ata_port *ap); static void sil24_thaw(struct ata_port *ap); static void sil24_error_handler(struct ata_port *ap); @@ -411,8 +409,6 @@ static const struct ata_port_operations sil24_ops = { .pmp_attach = sil24_pmp_attach, .pmp_detach = sil24_pmp_detach, - .pmp_read = sil24_pmp_read, - .pmp_write = sil24_pmp_write, .freeze = sil24_freeze, .thaw = sil24_thaw, @@ -928,32 +924,6 @@ static void sil24_pmp_detach(struct ata_port *ap) sil24_config_pmp(ap, 0); } -static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - int rc; - - sata_pmp_read_init_tf(&tf, dev, pmp, reg); - rc = sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, - SATA_PMP_SCR_TIMEOUT); - if (rc == 0) { - sil24_read_tf(ap, 0, &tf); - *r_val = sata_pmp_read_val(&tf); - } - return rc; -} - -static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - - sata_pmp_write_init_tf(&tf, dev, pmp, reg, val); - return sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, - SATA_PMP_SCR_TIMEOUT); -} - static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 529af9fbed53..2439f1fa47a1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -669,8 +669,6 @@ struct ata_port_operations { /* port multiplier */ void (*pmp_attach) (struct ata_port *ap); void (*pmp_detach) (struct ata_port *ap); - int (*pmp_read) (struct ata_device *dev, int pmp, int reg, u32 *r_val); - int (*pmp_write) (struct ata_device *dev, int pmp, int reg, u32 val); /* Error handlers. ->error_handler overrides ->eng_timeout and * indicates that new-style EH is in place. @@ -957,12 +955,6 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); * PMP */ extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); -extern void sata_pmp_read_init_tf(struct ata_taskfile *tf, - struct ata_device *dev, int pmp, int reg); -extern u32 sata_pmp_read_val(const struct ata_taskfile *tf); -extern void sata_pmp_write_init_tf(struct ata_taskfile *tf, - struct ata_device *dev, - int pmp, int reg, u32 val); extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline); extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); From 2855568b1ee4f58ef2c0a13ddfceb4b0b216b7ed Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 11 Oct 2007 17:12:35 -0400 Subject: [PATCH 2503/2804] [libata] struct pci_dev related cleanups * remove pointless pci_dev_to_dev() wrapper. Just directly reference the embedded struct device like everyone else does. * pata_cs5520: delete cs5520_remove_one(), it was a duplicate of ata_pci_remove_one() * linux/libata.h: don't bother including linux/pci.h, we don't need it. Simply declare 'struct pci_dev' and assume interested parties will include the header, as they should be doing anyway. * linux/libata.h: consolidate all CONFIG_PCI declarations into a single location in the header. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 2 +- drivers/ata/libata-eh.c | 1 + drivers/ata/pata_cs5520.c | 20 +------------------- include/linux/libata.h | 33 ++++++++++++++------------------- 4 files changed, 17 insertions(+), 39 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ce8ccb434aff..b05384a8c326 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7007,7 +7007,7 @@ void ata_std_ports(struct ata_ioports *ioaddr) */ void ata_pci_remove_one(struct pci_dev *pdev) { - struct device *dev = pci_dev_to_dev(pdev); + struct device *dev = &pdev->dev; struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5a2b2af4d0c1..2eaa39fc65d0 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -33,6 +33,7 @@ */ #include +#include #include #include #include diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index ff1eb84c7d22..33f7f0843f4f 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -299,24 +299,6 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi return ata_host_register(host, &cs5520_sht); } -/** - * cs5520_remove_one - device unload - * @pdev: PCI device being removed - * - * Handle an unplug/unload event for a PCI device. Unload the - * PCI driver but do not use the default handler as we manage - * resources ourself and *MUST NOT* disable the device as it has - * other functions. - */ - -static void __devexit cs5520_remove_one(struct pci_dev *pdev) -{ - struct device *dev = pci_dev_to_dev(pdev); - struct ata_host *host = dev_get_drvdata(dev); - - ata_host_detach(host); -} - #ifdef CONFIG_PM /** * cs5520_reinit_one - device resume @@ -373,7 +355,7 @@ static struct pci_driver cs5520_pci_driver = { .name = DRV_NAME, .id_table = pata_cs5520, .probe = cs5520_init_one, - .remove = cs5520_remove_one, + .remove = ata_pci_remove_one, #ifdef CONFIG_PM .suspend = cs5520_pci_device_suspend, .resume = cs5520_reinit_one, diff --git a/include/linux/libata.h b/include/linux/libata.h index 2439f1fa47a1..229a9ff9f924 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -107,12 +106,6 @@ static inline u32 ata_msg_init(int dval, int default_msg_enable_bits) /* defines only for the constants which don't work well as enums */ #define ATA_TAG_POISON 0xfafbfcfdU -/* move to PCI layer? */ -static inline struct device *pci_dev_to_dev(struct pci_dev *pdev) -{ - return &pdev->dev; -} - enum { /* various global constants */ LIBATA_MAX_PRD = ATA_MAX_PRD / 2, @@ -766,18 +759,7 @@ extern int sata_std_hardreset(struct ata_link *link, unsigned int *class, extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); extern void ata_port_disable(struct ata_port *); extern void ata_std_ports(struct ata_ioports *ioaddr); -#ifdef CONFIG_PCI -extern int ata_pci_init_one (struct pci_dev *pdev, - const struct ata_port_info * const * ppi); -extern void ata_pci_remove_one (struct pci_dev *pdev); -#ifdef CONFIG_PM -extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); -extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev); -extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); -extern int ata_pci_device_resume(struct pci_dev *pdev); -#endif -extern int ata_pci_clear_simplex(struct pci_dev *pdev); -#endif /* CONFIG_PCI */ + extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports); extern struct ata_host *ata_host_alloc_pinfo(struct device *dev, const struct ata_port_info * const * ppi, int n_ports); @@ -935,6 +917,19 @@ static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } #endif #ifdef CONFIG_PCI +struct pci_dev; + +extern int ata_pci_init_one (struct pci_dev *pdev, + const struct ata_port_info * const * ppi); +extern void ata_pci_remove_one (struct pci_dev *pdev); +#ifdef CONFIG_PM +extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); +extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev); +extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); +extern int ata_pci_device_resume(struct pci_dev *pdev); +#endif +extern int ata_pci_clear_simplex(struct pci_dev *pdev); + struct pci_bits { unsigned int reg; /* PCI config register to read */ unsigned int width; /* 1 (8 bit), 2 (16 bit), 4 (32 bit) */ From 77f1fd6ecd04556cbac1ca72e7a284ae313ea538 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 12 Oct 2007 22:48:46 +0200 Subject: [PATCH 2504/2804] mmc: use correct unregister function for led trigger We register a simple trigger so make sure we use the corresponding unregister function. (Also means we get a dummy function when triggers aren't compiled in) Signed-off-by: Pierre Ossman --- drivers/mmc/core/host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 64fbc9759a30..c65d203a846d 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -143,7 +143,7 @@ void mmc_remove_host(struct mmc_host *host) device_del(&host->class_dev); - led_trigger_unregister(host->led); + led_trigger_unregister_simple(host->led); spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); From 7f8033b76c8eea89dec9f658f4a31bcd4fe84bbb Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:05 +0200 Subject: [PATCH 2505/2804] clockevents: Remove unused inline function Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- include/linux/clockchips.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index def5a659b8a5..f368a6fe8cc9 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -130,7 +130,6 @@ extern void clockevents_notify(unsigned long reason, void *arg); #else -static inline void clockevents_resume_events(void) { } #define clockevents_notify(reason, arg) do { } while (0) #endif From de68d9b173ee657115dd0e584c2365b7954253a5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:05 +0200 Subject: [PATCH 2506/2804] clockevents: Allow build w/o run-tine usage for migration purposes Migration aid to allow preparatory patches which introduce not yet used parts of clock events code. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- include/linux/clockchips.h | 8 ++++++-- kernel/time/Kconfig | 5 +++++ kernel/time/Makefile | 2 +- kernel/time/clockevents.c | 3 ++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index f368a6fe8cc9..d2ddea926895 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -8,7 +8,7 @@ #ifndef _LINUX_CLOCKCHIPS_H #define _LINUX_CLOCKCHIPS_H -#ifdef CONFIG_GENERIC_CLOCKEVENTS +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD #include #include @@ -126,9 +126,13 @@ extern int clockevents_register_notifier(struct notifier_block *nb); extern int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, ktime_t now); +#ifdef CONFIG_GENERIC_CLOCKEVENTS extern void clockevents_notify(unsigned long reason, void *arg); - #else +# define clockevents_notify(reason, arg) do { } while (0) +#endif + +#else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ #define clockevents_notify(reason, arg) do { } while (0) diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index f66351126544..8d53106a0a92 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig @@ -23,3 +23,8 @@ config HIGH_RES_TIMERS hardware is not capable then this option only increases the size of the kernel image. +config GENERIC_CLOCKEVENTS_BUILD + bool + default y + depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR + diff --git a/kernel/time/Makefile b/kernel/time/Makefile index 99b6034fc86b..905b0b50792d 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -1,6 +1,6 @@ obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o -obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o +obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 41dd3105ce7f..822beebe664a 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -194,6 +194,7 @@ void clockevents_exchange_device(struct clock_event_device *old, local_irq_restore(flags); } +#ifdef CONFIG_GENERIC_CLOCKEVENTS /** * clockevents_notify - notification about relevant events */ @@ -222,4 +223,4 @@ void clockevents_notify(unsigned long reason, void *arg) spin_unlock(&clockevents_lock); } EXPORT_SYMBOL_GPL(clockevents_notify); - +#endif From c8a1d398de70a7774359b4720c392891cdd485f9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2507/2804] clockevents: fix periodic broadcast for oneshot devices The next_event member of the clock event device is used to keep track of the next periodic event. For one shot only devices it is wrong to clear the variable, as the next event will be based on it. Pointed out by Ralf Baechle Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- kernel/time/tick-broadcast.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 0962e0577660..acf15b49e55b 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -176,8 +176,6 @@ static void tick_do_periodic_broadcast(void) */ static void tick_handle_periodic_broadcast(struct clock_event_device *dev) { - dev->next_event.tv64 = KTIME_MAX; - tick_do_periodic_broadcast(); /* From 3c9aea47425885ec8b1f7b0df88c2ebc6f747c9d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2508/2804] x86: Fix irq0 / local apic timer accounting The clock events merge introduced a change to the nmi watchdog code to handle the not longer increasing local apic timer count in the broadcast mode. This is fine for UP, but on SMP it pampers over a stuck CPU which is not handling the broadcast interrupt due to the unconditional sum up of local apic timer count and irq0 count. To cover all cases we need to keep track on which CPU irq0 is handled. In theory this is CPU#0 due to the explicit disabling of irq balancing for irq0, but there are systems which ignore this on the hardware level. The per cpu irq0 accounting allows us to remove the irq0 to CPU0 binding as well. Add a per cpu counter for irq0 and evaluate this instead of the global irq0 count in the nmi watchdog code. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/nmi_32.c | 3 ++- arch/x86/kernel/time_32.c | 3 +++ include/asm-x86/hardirq_32.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c index c7227e2180f8..95d3fc203cf7 100644 --- a/arch/x86/kernel/nmi_32.c +++ b/arch/x86/kernel/nmi_32.c @@ -353,7 +353,8 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) * Take the local apic timer and PIT/HPET into account. We don't * know which one is active, when we have highres/dyntick on */ - sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0]; + sum = per_cpu(irq_stat, cpu).apic_timer_irqs + + per_cpu(irq_stat, cpu).irq0_irqs; /* if the none of the timers isn't firing, this cpu isn't doing much */ if (!touched && last_irq_sums[cpu] == sum) { diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c index 19a6c678d02e..56dadfc2f41c 100644 --- a/arch/x86/kernel/time_32.c +++ b/arch/x86/kernel/time_32.c @@ -157,6 +157,9 @@ EXPORT_SYMBOL(profile_pc); */ irqreturn_t timer_interrupt(int irq, void *dev_id) { + /* Keep nmi watchdog up to date */ + per_cpu(irq_stat, smp_processor_id()).irq0_irqs++; + #ifdef CONFIG_X86_IO_APIC if (timer_ack) { /* diff --git a/include/asm-x86/hardirq_32.h b/include/asm-x86/hardirq_32.h index 0e358dc405f8..34649585bb59 100644 --- a/include/asm-x86/hardirq_32.h +++ b/include/asm-x86/hardirq_32.h @@ -9,6 +9,7 @@ typedef struct { unsigned long idle_timestamp; unsigned int __nmi_count; /* arch dependent */ unsigned int apic_timer_irqs; /* arch dependent */ + unsigned int irq0_irqs; } ____cacheline_aligned irq_cpustat_t; DECLARE_PER_CPU(irq_cpustat_t, irq_stat); From 5fa3a246ea2e1be2ffaa01343bc183c8c0bfa472 Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2509/2804] x86: block irq balancing for timer Disable irq balancing on IRQ0. Several SIS chipsets lock up when you try to change affinity of IRQ #0. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andi Kleen Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Arjan van de Ven --- arch/x86/kernel/time_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index 6d48a4e826d9..2db4d698a2d3 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -360,7 +360,7 @@ void stop_timer_interrupt(void) static struct irqaction irq0 = { .handler = timer_interrupt, - .flags = IRQF_DISABLED | IRQF_IRQPOLL, + .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, .mask = CPU_MASK_NONE, .name = "timer" }; From 83d7384f8d4aa216b49cf9cb286ea743054b119f Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2510/2804] x86: Geode Multi-Function General Purpose Timers support This adds support for Multi-Function General Purpose Timers. It detects the available timers during southbridge init, and provides an API for allocating and setting the timers. They're higher resolution than the standard PIT, so the MFGPTs come in handy for quite a few things. Note that we never clobber the timers that the BIOS might have opted to use; we just check for unused timers. Signed-off-by: Jordan Crouse Signed-off-by: Andres Salomon Cc: Andi Kleen Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- Documentation/kernel-parameters.txt | 3 + arch/x86/kernel/Makefile_32 | 2 +- arch/x86/kernel/geode_32.c | 4 + arch/x86/kernel/mfgpt_32.c | 197 ++++++++++++++++++++++++++++ include/asm-x86/geode.h | 50 +++++++ 5 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 arch/x86/kernel/mfgpt_32.c diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a57c1f216b21..2128de6d80ea 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1160,6 +1160,9 @@ and is between 256 and 4096 characters. It is defined in the file nomce [X86-32] Machine Check Exception + nomfgpt [X86-32] Disable Multi-Function General Purpose + Timer usage (for AMD Geode machines). + noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops noreplace-smp [X86-32,SMP] Don't replace SMP instructions diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 index c624193740fd..10356443998e 100644 --- a/arch/x86/kernel/Makefile_32 +++ b/arch/x86/kernel/Makefile_32 @@ -39,7 +39,7 @@ obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_HPET_TIMER) += hpet_32.o obj-$(CONFIG_K8_NB) += k8.o -obj-$(CONFIG_MGEODE_LX) += geode_32.o +obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o obj-$(CONFIG_PARAVIRT) += paravirt_32.o diff --git a/arch/x86/kernel/geode_32.c b/arch/x86/kernel/geode_32.c index 41e8aec4c61d..f12d8c5d9809 100644 --- a/arch/x86/kernel/geode_32.c +++ b/arch/x86/kernel/geode_32.c @@ -145,10 +145,14 @@ EXPORT_SYMBOL_GPL(geode_gpio_setup_event); static int __init geode_southbridge_init(void) { + int timers; + if (!is_geode()) return -ENODEV; init_lbars(); + timers = geode_mfgpt_detect(); + printk(KERN_INFO "geode: %d MFGPT timers available.\n", timers); return 0; } diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c new file mode 100644 index 000000000000..3a63a2dd8d27 --- /dev/null +++ b/arch/x86/kernel/mfgpt_32.c @@ -0,0 +1,197 @@ +/* + * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT) + * + * Copyright (C) 2006, Advanced Micro Devices, Inc. + * Copyright (C) 2007, Andres Salomon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book. + */ + +/* + * We are using the 32Khz input clock - its the only one that has the + * ranges we find desirable. The following table lists the suitable + * divisors and the associated hz, minimum interval + * and the maximum interval: + * + * Divisor Hz Min Delta (S) Max Delta (S) + * 1 32000 .0005 2.048 + * 2 16000 .001 4.096 + * 4 8000 .002 8.192 + * 8 4000 .004 16.384 + * 16 2000 .008 32.768 + * 32 1000 .016 65.536 + * 64 500 .032 131.072 + * 128 250 .064 262.144 + * 256 125 .128 524.288 + */ + +#include +#include +#include +#include + +#define F_AVAIL 0x01 + +static struct mfgpt_timer_t { + int flags; + struct module *owner; +} mfgpt_timers[MFGPT_MAX_TIMERS]; + +/* Selected from the table above */ + +#define MFGPT_DIVISOR 16 +#define MFGPT_SCALE 4 /* divisor = 2^(scale) */ +#define MFGPT_HZ (32000 / MFGPT_DIVISOR) +#define MFGPT_PERIODIC (MFGPT_HZ / HZ) + +/* Allow for disabling of MFGPTs */ +static int disable; +static int __init mfgpt_disable(char *s) +{ + disable = 1; + return 1; +} +__setup("nomfgpt", mfgpt_disable); + +/* + * Check whether any MFGPTs are available for the kernel to use. In most + * cases, firmware that uses AMD's VSA code will claim all timers during + * bootup; we certainly don't want to take them if they're already in use. + * In other cases (such as with VSAless OpenFirmware), the system firmware + * leaves timers available for us to use. + */ +int __init geode_mfgpt_detect(void) +{ + int count = 0, i; + u16 val; + + if (disable) { + printk(KERN_INFO "geode-mfgpt: Skipping MFGPT setup\n"); + return 0; + } + + for (i = 0; i < MFGPT_MAX_TIMERS; i++) { + val = geode_mfgpt_read(i, MFGPT_REG_SETUP); + if (!(val & MFGPT_SETUP_SETUP)) { + mfgpt_timers[i].flags = F_AVAIL; + count++; + } + } + + return count; +} + +int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) +{ + u32 msr, mask, value, dummy; + int shift = (cmp == MFGPT_CMP1) ? 0 : 8; + + if (timer < 0 || timer >= MFGPT_MAX_TIMERS) + return -EIO; + + /* + * The register maps for these are described in sections 6.17.1.x of + * the AMD Geode CS5536 Companion Device Data Book. + */ + switch (event) { + case MFGPT_EVENT_RESET: + /* + * XXX: According to the docs, we cannot reset timers above + * 6; that is, resets for 7 and 8 will be ignored. Is this + * a problem? -dilinger + */ + msr = MFGPT_NR_MSR; + mask = 1 << (timer + 24); + break; + + case MFGPT_EVENT_NMI: + msr = MFGPT_NR_MSR; + mask = 1 << (timer + shift); + break; + + case MFGPT_EVENT_IRQ: + msr = MFGPT_IRQ_MSR; + mask = 1 << (timer + shift); + break; + + default: + return -EIO; + } + + rdmsr(msr, value, dummy); + + if (enable) + value |= mask; + else + value &= ~mask; + + wrmsr(msr, value, dummy); + return 0; +} + +int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable) +{ + u32 val, dummy; + int offset; + + if (timer < 0 || timer >= MFGPT_MAX_TIMERS) + return -EIO; + + if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable)) + return -EIO; + + rdmsr(MSR_PIC_ZSEL_LOW, val, dummy); + + offset = (timer % 4) * 4; + + val &= ~((0xF << offset) | (0xF << (offset + 16))); + + if (enable) { + val |= (irq & 0x0F) << (offset); + val |= (irq & 0x0F) << (offset + 16); + } + + wrmsr(MSR_PIC_ZSEL_LOW, val, dummy); + return 0; +} + +static int mfgpt_get(int timer, struct module *owner) +{ + mfgpt_timers[timer].flags &= ~F_AVAIL; + mfgpt_timers[timer].owner = owner; + printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer); + return timer; +} + +int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner) +{ + int i; + + if (!geode_get_dev_base(GEODE_DEV_MFGPT)) + return -ENODEV; + if (timer >= MFGPT_MAX_TIMERS) + return -EIO; + + if (timer < 0) { + /* Try to find an available timer */ + for (i = 0; i < MFGPT_MAX_TIMERS; i++) { + if (mfgpt_timers[i].flags & F_AVAIL) + return mfgpt_get(i, owner); + + if (i == 5 && domain == MFGPT_DOMAIN_WORKING) + break; + } + } else { + /* If they requested a specific timer, try to honor that */ + if (mfgpt_timers[timer].flags & F_AVAIL) + return mfgpt_get(timer, owner); + } + + /* No timers available - too bad */ + return -1; +} + diff --git a/include/asm-x86/geode.h b/include/asm-x86/geode.h index 6da4bbbea3dc..d94898831bac 100644 --- a/include/asm-x86/geode.h +++ b/include/asm-x86/geode.h @@ -156,4 +156,54 @@ static inline int is_geode(void) return (is_geode_gx() || is_geode_lx()); } +/* MFGPTs */ + +#define MFGPT_MAX_TIMERS 8 +#define MFGPT_TIMER_ANY -1 + +#define MFGPT_DOMAIN_WORKING 1 +#define MFGPT_DOMAIN_STANDBY 2 +#define MFGPT_DOMAIN_ANY (MFGPT_DOMAIN_WORKING | MFGPT_DOMAIN_STANDBY) + +#define MFGPT_CMP1 0 +#define MFGPT_CMP2 1 + +#define MFGPT_EVENT_IRQ 0 +#define MFGPT_EVENT_NMI 1 +#define MFGPT_EVENT_RESET 3 + +#define MFGPT_REG_CMP1 0 +#define MFGPT_REG_CMP2 2 +#define MFGPT_REG_COUNTER 4 +#define MFGPT_REG_SETUP 6 + +#define MFGPT_SETUP_CNTEN (1 << 15) +#define MFGPT_SETUP_CMP2 (1 << 14) +#define MFGPT_SETUP_CMP1 (1 << 13) +#define MFGPT_SETUP_SETUP (1 << 12) +#define MFGPT_SETUP_STOPEN (1 << 11) +#define MFGPT_SETUP_EXTEN (1 << 10) +#define MFGPT_SETUP_REVEN (1 << 5) +#define MFGPT_SETUP_CLKSEL (1 << 4) + +static inline void geode_mfgpt_write(int timer, u16 reg, u16 value) +{ + u32 base = geode_get_dev_base(GEODE_DEV_MFGPT); + outw(value, base + reg + (timer * 8)); +} + +static inline u16 geode_mfgpt_read(int timer, u16 reg) +{ + u32 base = geode_get_dev_base(GEODE_DEV_MFGPT); + return inw(base + reg + (timer * 8)); +} + +extern int __init geode_mfgpt_detect(void); +extern int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable); +extern int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable); +extern int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner); + +#define geode_mfgpt_setup_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 1) +#define geode_mfgpt_release_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 0) + #endif From 8f36881b3c972ebc019195692849f22488f9c0a3 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2511/2804] x86: Geode MFGPT clock event device support Add support for an MFGPT clock event device; this allows us to use MFGPTs as the basis for high-resolution timers. Signed-off-by: Jordan Crouse Signed-off-by: Andres Salomon Cc: Andi Kleen Cc: Alan Cox Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- Documentation/kernel-parameters.txt | 4 + arch/i386/Kconfig | 10 ++ arch/x86/kernel/mfgpt_32.c | 165 ++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 2128de6d80ea..f27cdd7125f2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1009,6 +1009,10 @@ and is between 256 and 4096 characters. It is defined in the file meye.*= [HW] Set MotionEye Camera parameters See Documentation/video4linux/meye.txt. + mfgpt_irq= [IA-32] Specify the IRQ to use for the + Multi-Function General Purpose Timers on AMD Geode + platforms. + mga= [HW,DRM] mousedev.tap_time= diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 2d85e4b87307..6bbbc2755e44 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -1206,6 +1206,16 @@ config SCx200HR_TIMER processor goes idle (as is done by the scheduler). The other workaround is idle=poll boot option. +config GEODE_MFGPT_TIMER + bool "Geode Multi-Function General Purpose Timer (MFGPT) events" + depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS + default y + help + This driver provides a clock event source based on the MFGPT + timer(s) in the CS5535 and CS5536 companion chip for the geode. + MFGPTs have a better resolution and max interval than the + generic PIT, and are suitable for use as high-res timers. + config K8_NB def_bool y depends on AGP_AMD64 diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c index 3a63a2dd8d27..0ab680f2d9db 100644 --- a/arch/x86/kernel/mfgpt_32.c +++ b/arch/x86/kernel/mfgpt_32.c @@ -48,6 +48,12 @@ static struct mfgpt_timer_t { #define MFGPT_HZ (32000 / MFGPT_DIVISOR) #define MFGPT_PERIODIC (MFGPT_HZ / HZ) +#ifdef CONFIG_GEODE_MFGPT_TIMER +static int __init mfgpt_timer_setup(void); +#else +#define mfgpt_timer_setup() (0) +#endif + /* Allow for disabling of MFGPTs */ static int disable; static int __init mfgpt_disable(char *s) @@ -82,6 +88,9 @@ int __init geode_mfgpt_detect(void) } } + /* set up clock event device, if desired */ + i = mfgpt_timer_setup(); + return count; } @@ -195,3 +204,159 @@ int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner) return -1; } + +#ifdef CONFIG_GEODE_MFGPT_TIMER + +/* + * The MFPGT timers on the CS5536 provide us with suitable timers to use + * as clock event sources - not as good as a HPET or APIC, but certainly + * better then the PIT. This isn't a general purpose MFGPT driver, but + * a simplified one designed specifically to act as a clock event source. + * For full details about the MFGPT, please consult the CS5536 data sheet. + */ + +#include +#include + +static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN; +static u16 mfgpt_event_clock; + +static int irq = 7; +static int __init mfgpt_setup(char *str) +{ + get_option(&str, &irq); + return 1; +} +__setup("mfgpt_irq=", mfgpt_setup); + +static inline void mfgpt_disable_timer(u16 clock) +{ + u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP); + geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN); +} + +static int mfgpt_next_event(unsigned long, struct clock_event_device *); +static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *); + +static struct clock_event_device mfgpt_clockevent = { + .name = "mfgpt-timer", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = mfgpt_set_mode, + .set_next_event = mfgpt_next_event, + .rating = 250, + .cpumask = CPU_MASK_ALL, + .shift = 32 +}; + +static inline void mfgpt_start_timer(u16 clock, u16 delta) +{ + geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta); + geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); + + geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, + MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); +} + +static void mfgpt_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + mfgpt_disable_timer(mfgpt_event_clock); + + if (mode == CLOCK_EVT_MODE_PERIODIC) + mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC); + + mfgpt_tick_mode = mode; +} + +static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) +{ + mfgpt_start_timer(mfgpt_event_clock, delta); + return 0; +} + +/* Assume (foolishly?), that this interrupt was due to our tick */ + +static irqreturn_t mfgpt_tick(int irq, void *dev_id) +{ + if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN) + return IRQ_HANDLED; + + /* Turn off the clock */ + mfgpt_disable_timer(mfgpt_event_clock); + + /* Clear the counter */ + geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); + + /* Restart the clock in periodic mode */ + + if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) { + geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, + MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); + } + + mfgpt_clockevent.event_handler(&mfgpt_clockevent); + return IRQ_HANDLED; +} + +static struct irqaction mfgptirq = { + .handler = mfgpt_tick, + .flags = IRQF_DISABLED | IRQF_NOBALANCING, + .mask = CPU_MASK_NONE, + .name = "mfgpt-timer" +}; + +static int __init mfgpt_timer_setup(void) +{ + int timer, ret; + u16 val; + + timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING, + THIS_MODULE); + if (timer < 0) { + printk(KERN_ERR + "mfgpt-timer: Could not allocate a MFPGT timer\n"); + return -ENODEV; + } + + mfgpt_event_clock = timer; + /* Set the clock scale and enable the event mode for CMP2 */ + val = MFGPT_SCALE | (3 << 8); + + geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val); + + /* Set up the IRQ on the MFGPT side */ + if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) { + printk(KERN_ERR "mfgpt-timer: Could not set up IRQ %d\n", irq); + return -EIO; + } + + /* And register it with the kernel */ + ret = setup_irq(irq, &mfgptirq); + + if (ret) { + printk(KERN_ERR + "mfgpt-timer: Unable to set up the interrupt.\n"); + goto err; + } + + /* Set up the clock event */ + mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32); + mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF, + &mfgpt_clockevent); + mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE, + &mfgpt_clockevent); + + printk(KERN_INFO + "mfgpt-timer: registering the MFGT timer as a clock event.\n"); + clockevents_register_device(&mfgpt_clockevent); + + return 0; + +err: + geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq); + printk(KERN_ERR + "mfgpt-timer: Unable to set up the MFGPT clock source\n"); + return -EIO; +} + +#endif From 89b2bbd69b89b4c5efdc112a88d72419bdeb8dfc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2512/2804] x86_64: Select clocksource watchdog in Kconfig TSC must be verified by a continous and reliable clocksource to allow high resolution timers and or dynamic ticks. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86_64/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index b1b98e614f7c..520f33b83bfc 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -36,6 +36,10 @@ config GENERIC_CMOS_UPDATE bool default y +config CLOCKSOURCE_WATCHDOG + bool + default y + config ZONE_DMA32 bool default y From d371698efd45c3664fd1726780c360f02e1f9580 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2513/2804] x86_64: Consolidate tsc calibration Move the TSC calibration code to tsc.c. Reimplement it so the pm timer can be used as a reference as well. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/hpet_64.c | 49 --------------------- arch/x86/kernel/time_64.c | 33 +------------- arch/x86/kernel/tsc_64.c | 90 +++++++++++++++++++++++++++++++++++++++ include/asm-x86/tsc.h | 4 ++ 4 files changed, 96 insertions(+), 80 deletions(-) diff --git a/arch/x86/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c index e2d1b912e154..1ebce2ec7eaf 100644 --- a/arch/x86/kernel/hpet_64.c +++ b/arch/x86/kernel/hpet_64.c @@ -184,55 +184,6 @@ int hpet_reenable(void) return hpet_timer_stop_set_go(hpet_tick); } -/* - * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing - * it to the HPET timer of known frequency. - */ - -#define TICK_COUNT 100000000 -#define SMI_THRESHOLD 50000 -#define MAX_TRIES 5 - -/* - * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none - * occurs between the reads of the hpet & TSC. - */ -static void __init read_hpet_tsc(int *hpet, int *tsc) -{ - int tsc1, tsc2, hpet1, i; - - for (i = 0; i < MAX_TRIES; i++) { - tsc1 = get_cycles_sync(); - hpet1 = hpet_readl(HPET_COUNTER); - tsc2 = get_cycles_sync(); - if ((tsc2 - tsc1) < SMI_THRESHOLD) - break; - } - *hpet = hpet1; - *tsc = tsc2; -} - -unsigned int __init hpet_calibrate_tsc(void) -{ - int tsc_start, hpet_start; - int tsc_now, hpet_now; - unsigned long flags; - - local_irq_save(flags); - - read_hpet_tsc(&hpet_start, &tsc_start); - - do { - local_irq_disable(); - read_hpet_tsc(&hpet_now, &tsc_now); - local_irq_restore(flags); - } while ((tsc_now - tsc_start) < TICK_COUNT && - (hpet_now - hpet_start) < TICK_COUNT); - - return (tsc_now - tsc_start) * 1000000000L - / ((hpet_now - hpet_start) * hpet_period / 1000); -} - #ifdef CONFIG_HPET_EMULATE_RTC /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET * is enabled, we support RTC interrupt functionality in software. diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index 2db4d698a2d3..e97a3ee13551 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -292,35 +292,6 @@ static unsigned int __init tsc_calibrate_cpu_khz(void) return pmc_now * tsc_khz / (tsc_now - tsc_start); } -/* - * pit_calibrate_tsc() uses the speaker output (channel 2) of - * the PIT. This is better than using the timer interrupt output, - * because we can read the value of the speaker with just one inb(), - * where we need three i/o operations for the interrupt channel. - * We count how many ticks the TSC does in 50 ms. - */ - -static unsigned int __init pit_calibrate_tsc(void) -{ - unsigned long start, end; - unsigned long flags; - - spin_lock_irqsave(&i8253_lock, flags); - - outb((inb(0x61) & ~0x02) | 0x01, 0x61); - - outb(0xb0, 0x43); - outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42); - outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42); - start = get_cycles_sync(); - while ((inb(0x61) & 0x20) == 0); - end = get_cycles_sync(); - - spin_unlock_irqrestore(&i8253_lock, flags); - - return (end - start) / 50; -} - #define PIT_MODE 0x43 #define PIT_CH0 0x40 @@ -376,14 +347,14 @@ void __init time_init(void) if (hpet_use_timer) { /* set tick_nsec to use the proper rate for HPET */ tick_nsec = TICK_NSEC_HPET; - tsc_khz = hpet_calibrate_tsc(); timename = "HPET"; } else { pit_init(); - tsc_khz = pit_calibrate_tsc(); timename = "PIT"; } + tsc_calibrate(); + cpu_khz = tsc_khz; if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) && boot_cpu_data.x86_vendor == X86_VENDOR_AMD && diff --git a/arch/x86/kernel/tsc_64.c b/arch/x86/kernel/tsc_64.c index 2a59bde663f2..59baecd135ab 100644 --- a/arch/x86/kernel/tsc_64.c +++ b/arch/x86/kernel/tsc_64.c @@ -6,7 +6,9 @@ #include #include #include +#include +#include #include static int notsc __initdata = 0; @@ -118,6 +120,94 @@ core_initcall(cpufreq_tsc); #endif +#define MAX_RETRIES 5 +#define SMI_TRESHOLD 50000 + +/* + * Read TSC and the reference counters. Take care of SMI disturbance + */ +static unsigned long __init tsc_read_refs(unsigned long *pm, + unsigned long *hpet) +{ + unsigned long t1, t2; + int i; + + for (i = 0; i < MAX_RETRIES; i++) { + t1 = get_cycles_sync(); + if (hpet) + *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF; + else + *pm = acpi_pm_read_early(); + t2 = get_cycles_sync(); + if ((t2 - t1) < SMI_TRESHOLD) + return t2; + } + return ULONG_MAX; +} + +/** + * tsc_calibrate - calibrate the tsc on boot + */ +void __init tsc_calibrate(void) +{ + unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2; + int hpet = is_hpet_enabled(); + + local_irq_save(flags); + + tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); + + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + + outb(0xb0, 0x43); + outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); + outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); + tr1 = get_cycles_sync(); + while ((inb(0x61) & 0x20) == 0); + tr2 = get_cycles_sync(); + + tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); + + local_irq_restore(flags); + + /* + * Preset the result with the raw and inaccurate PIT + * calibration value + */ + tsc_khz = (tr2 - tr1) / 50; + + /* hpet or pmtimer available ? */ + if (!hpet && !pm1 && !pm2) { + printk(KERN_INFO "TSC calibrated against PIT\n"); + return; + } + + /* Check, whether the sampling was disturbed by an SMI */ + if (tsc1 == ULONG_MAX || tsc2 == ULONG_MAX) { + printk(KERN_WARNING "TSC calibration disturbed by SMI, " + "using PIT calibration result\n"); + return; + } + + tsc2 = (tsc2 - tsc1) * 1000000L; + + if (hpet) { + printk(KERN_INFO "TSC calibrated against HPET\n"); + if (hpet2 < hpet1) + hpet2 += 0x100000000; + hpet2 -= hpet1; + tsc1 = (hpet2 * hpet_readl(HPET_PERIOD)) / 1000000; + } else { + printk(KERN_INFO "TSC calibrated against PM_TIMER\n"); + if (pm2 < pm1) + pm2 += ACPI_PM_OVRRUN; + pm2 -= pm1; + tsc1 = (pm2 * 1000000000) / PMTMR_TICKS_PER_SEC; + } + + tsc_khz = tsc2 / tsc1; +} + /* * Make an educated guess if the TSC is trustworthy and synchronized * over all CPUs. diff --git a/include/asm-x86/tsc.h b/include/asm-x86/tsc.h index a4d806610b7f..2002f8d6d20a 100644 --- a/include/asm-x86/tsc.h +++ b/include/asm-x86/tsc.h @@ -72,4 +72,8 @@ int check_tsc_unstable(void); extern void check_tsc_sync_source(int cpu); extern void check_tsc_sync_target(void); +#ifdef CONFIG_X86_64 +extern void tsc_calibrate(void); +#endif + #endif From 06a24dec10bc4014fc0974670627efed68f5da27 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2514/2804] i386: prepare sharing the hpet code with x86_64 The hpet implementations of i386 and x8664 has been mostly the same before the clock events conversion of i386. The clock events conversion of i386 hpet is already done. So it makes sense to share the code for the x86_64 clock events conversion. Abstract out the mapping functions. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/hpet_32.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet_32.c index 533d4932bc79..748abf0286d2 100644 --- a/arch/x86/kernel/hpet_32.c +++ b/arch/x86/kernel/hpet_32.c @@ -8,10 +8,9 @@ #include #include +#include #include -extern struct clock_event_device *global_clock_event; - #define HPET_MASK CLOCKSOURCE_MASK(32) #define HPET_SHIFT 22 @@ -22,7 +21,7 @@ extern struct clock_event_device *global_clock_event; * HPET address is set in acpi/boot.c, when an ACPI entry exists */ unsigned long hpet_address; -static void __iomem * hpet_virt_address; +static void __iomem *hpet_virt_address; static inline unsigned long hpet_readl(unsigned long a) { @@ -34,6 +33,17 @@ static inline void hpet_writel(unsigned long d, unsigned long a) writel(d, hpet_virt_address + a); } +static inline void hpet_set_mapping(void) +{ + hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); +} + +static inline void hpet_clear_mapping(void) +{ + iounmap(hpet_virt_address); + hpet_virt_address = NULL; +} + /* * HPET command line enable / disable */ @@ -83,7 +93,7 @@ static void hpet_reserve_platform_timers(unsigned long id) memset(&hd, 0, sizeof (hd)); hd.hd_phys_address = hpet_address; - hd.hd_address = hpet_virt_address; + hd.hd_address = hpet; hd.hd_nirqs = nrtimers; hd.hd_flags = HPET_DATA_PLATFORM; hpet_reserve_timer(&hd, 0); @@ -238,7 +248,7 @@ int __init hpet_enable(void) if (!is_hpet_capable()) return 0; - hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); + hpet_set_mapping(); /* * Read the period and check for a sane value: @@ -334,13 +344,11 @@ int __init hpet_enable(void) return 0; out_nohpet: - iounmap(hpet_virt_address); - hpet_virt_address = NULL; + hpet_clear_mapping(); boot_hpet_disable = 1; return 0; } - #ifdef CONFIG_HPET_EMULATE_RTC /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET From 28769149c285e0a392d2e601ae0cc71ffc345f7d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2515/2804] i386: prepare sharing the hpet code with x86_64 Add the x8664 specific bits (mapping) to share the hpet code later. Move the reserve_platform_timer call to late init. This is necessary for x86_64, as hpet enable() is called before memory is setup. i386 calls it in late_time_init, but it does not hurt to do it later for both. Pull in the x8664 hpet disable command line option as well. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/hpet_32.c | 59 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet_32.c index 748abf0286d2..dbe0e1d44113 100644 --- a/arch/x86/kernel/hpet_32.c +++ b/arch/x86/kernel/hpet_32.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,6 +8,7 @@ #include #include +#include #include #include #include @@ -23,6 +25,10 @@ unsigned long hpet_address; static void __iomem *hpet_virt_address; +/* Temporary hack. Cleanup after x86_64 clock events conversion */ +#undef hpet_readl +#undef hpet_writel + static inline unsigned long hpet_readl(unsigned long a) { return readl(hpet_virt_address + a); @@ -33,6 +39,24 @@ static inline void hpet_writel(unsigned long d, unsigned long a) writel(d, hpet_virt_address + a); } +#ifdef CONFIG_X86_64 + +#include + +static inline void hpet_set_mapping(void) +{ + set_fixmap_nocache(FIX_HPET_BASE, hpet_address); + __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); + hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE); +} + +static inline void hpet_clear_mapping(void) +{ + hpet_virt_address = NULL; +} + +#else + static inline void hpet_set_mapping(void) { hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); @@ -43,6 +67,7 @@ static inline void hpet_clear_mapping(void) iounmap(hpet_virt_address); hpet_virt_address = NULL; } +#endif /* * HPET command line enable / disable @@ -59,6 +84,13 @@ static int __init hpet_setup(char* str) } __setup("hpet=", hpet_setup); +static int __init disable_hpet(char *str) +{ + boot_hpet_disable = 1; + return 1; +} +__setup("nohpet", disable_hpet); + static inline int is_hpet_capable(void) { return (!boot_hpet_disable && hpet_address); @@ -225,6 +257,13 @@ static cycle_t read_hpet(void) return (cycle_t)hpet_readl(HPET_COUNTER); } +#ifdef CONFIG_X86_64 +static cycle_t __vsyscall_fn vread_hpet(void) +{ + return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); +} +#endif + static struct clocksource clocksource_hpet = { .name = "hpet", .rating = 250, @@ -233,6 +272,9 @@ static struct clocksource clocksource_hpet = { .shift = HPET_SHIFT, .flags = CLOCK_SOURCE_IS_CONTINUOUS, .resume = hpet_start_counter, +#ifdef CONFIG_X86_64 + .vread = vread_hpet, +#endif }; /* @@ -331,7 +373,6 @@ int __init hpet_enable(void) if (id & HPET_ID_LEGSUP) { hpet_enable_int(); - hpet_reserve_platform_timers(id); /* * Start hpet with the boot cpu mask and make it * global after the IO_APIC has been initialized. @@ -349,6 +390,22 @@ out_nohpet: return 0; } +/* + * Needs to be late, as the reserve_timer code calls kalloc ! + * + * Not a problem on i386 as hpet_enable is called from late_time_init, + * but on x86_64 it is necessary ! + */ +static __init int hpet_late_init(void) +{ + if (!is_hpet_capable()) + return -ENODEV; + + hpet_reserve_platform_timers(hpet_readl(HPET_ID)); + return 0; +} +fs_initcall(hpet_late_init); + #ifdef CONFIG_HPET_EMULATE_RTC /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET From f5e0e93faf8421083853b2d7a217267f49e27cc3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2516/2804] i386: prepare sharing the PIT code PIT clock events work already and the PIT handling is the same for i386 and x86_64. x86_64 does not support PIT as a clock source, so disable the PIT clocksource for x86_64. Prepare i8253.h to be shared with x8664 Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/i8253_32.c | 4 +++- include/asm-x86/i8253_32.h | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/i8253_32.c b/arch/x86/kernel/i8253_32.c index 6d839f2f1b1a..ac15e4cbd9c1 100644 --- a/arch/x86/kernel/i8253_32.c +++ b/arch/x86/kernel/i8253_32.c @@ -13,7 +13,6 @@ #include #include #include -#include DEFINE_SPINLOCK(i8253_lock); EXPORT_SYMBOL(i8253_lock); @@ -120,6 +119,7 @@ void __init setup_pit_timer(void) global_clock_event = &pit_clockevent; } +#ifndef CONFIG_X86_64 /* * Since the PIT overflows every tick, its not very useful * to just read by itself. So use jiffies to emulate a free @@ -204,3 +204,5 @@ static int __init init_pit_clocksource(void) return clocksource_register(&clocksource_pit); } arch_initcall(init_pit_clocksource); + +#endif diff --git a/include/asm-x86/i8253_32.h b/include/asm-x86/i8253_32.h index 7577d058d86e..28cf67da59a3 100644 --- a/include/asm-x86/i8253_32.h +++ b/include/asm-x86/i8253_32.h @@ -1,8 +1,6 @@ #ifndef __ASM_I8253_H__ #define __ASM_I8253_H__ -#include - /* i8253A PIT registers */ #define PIT_MODE 0x43 #define PIT_CH0 0x40 @@ -10,8 +8,12 @@ extern spinlock_t i8253_lock; +#ifdef CONFIG_GENERIC_CLOCKEVENTS + extern struct clock_event_device *global_clock_event; extern void setup_pit_timer(void); +#endif + #endif /* __ASM_I8253_H__ */ From 0190dae54de62fbb9ced75d134015266987eb6b8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2517/2804] i386: prepare sharing the PIT code PIT clock events work already and the PIT handling is the same for i386 and x86_64. x86_64 does not support PIT as a clock source, so disable the PIT clocksource for x86_64. Use the i386 i8253.h include file for x86_64 as well to share the exports and the PIT constants. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/time_64.c | 4 ---- include/asm-x86/i8253.h | 26 ++++++++++++++++++++++---- include/asm-x86/i8253_32.h | 19 ------------------- include/asm-x86/i8253_64.h | 6 ------ 4 files changed, 22 insertions(+), 33 deletions(-) delete mode 100644 include/asm-x86/i8253_32.h delete mode 100644 include/asm-x86/i8253_64.h diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index e97a3ee13551..d899216e01ca 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -32,7 +32,6 @@ #include /* for PM timer frequency */ #include #endif -#include #include #include #include @@ -292,9 +291,6 @@ static unsigned int __init tsc_calibrate_cpu_khz(void) return pmc_now * tsc_khz / (tsc_now - tsc_start); } -#define PIT_MODE 0x43 -#define PIT_CH0 0x40 - static void __pit_init(int val, u8 mode) { unsigned long flags; diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h index b2a4f995a33f..7eff6fd27474 100644 --- a/include/asm-x86/i8253.h +++ b/include/asm-x86/i8253.h @@ -1,5 +1,23 @@ -#ifdef CONFIG_X86_32 -# include "i8253_32.h" -#else -# include "i8253_64.h" +#ifndef __ASM_I8253_H__ +#define __ASM_I8253_H__ + +#ifdef CONFIG_X86_64 +# include #endif + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 +#define PIT_CH2 0x42 + +extern spinlock_t i8253_lock; + +#ifdef CONFIG_GENERIC_CLOCKEVENTS + +extern struct clock_event_device *global_clock_event; + +extern void setup_pit_timer(void); + +#endif + +#endif /* __ASM_I8253_H__ */ diff --git a/include/asm-x86/i8253_32.h b/include/asm-x86/i8253_32.h deleted file mode 100644 index 28cf67da59a3..000000000000 --- a/include/asm-x86/i8253_32.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __ASM_I8253_H__ -#define __ASM_I8253_H__ - -/* i8253A PIT registers */ -#define PIT_MODE 0x43 -#define PIT_CH0 0x40 -#define PIT_CH2 0x42 - -extern spinlock_t i8253_lock; - -#ifdef CONFIG_GENERIC_CLOCKEVENTS - -extern struct clock_event_device *global_clock_event; - -extern void setup_pit_timer(void); - -#endif - -#endif /* __ASM_I8253_H__ */ diff --git a/include/asm-x86/i8253_64.h b/include/asm-x86/i8253_64.h deleted file mode 100644 index 015d8df07690..000000000000 --- a/include/asm-x86/i8253_64.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_I8253_H__ -#define __ASM_I8253_H__ - -extern spinlock_t i8253_lock; - -#endif /* __ASM_I8253_H__ */ From 7ffeeb1e03c4fc1c7e8434c5496018dd035f8924 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2518/2804] x86: remove never used apic_mapped [ tglx: arch/x86 adaptation ] Signed-off-by: Yinghai Lu Signed-off-by: Andi Kleen Cc: Christoph Lameter Cc: Len Brown Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic_64.c | 5 ++--- include/asm-x86/apic_64.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 925758dbca0c..48206bb8de1f 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -39,7 +39,6 @@ #include #include -int apic_mapped; int apic_verbosity; int apic_runs_main_timer; int apic_calibrate_pmtmr __initdata; @@ -706,8 +705,8 @@ void __init init_apic_mappings(void) apic_phys = mp_lapic_addr; set_fixmap_nocache(FIX_APIC_BASE, apic_phys); - apic_mapped = 1; - apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys); + apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n", + APIC_BASE, apic_phys); /* Put local APIC into the resource map. */ lapic_resource.start = apic_phys; diff --git a/include/asm-x86/apic_64.h b/include/asm-x86/apic_64.h index 85125ef3c414..81335e95365b 100644 --- a/include/asm-x86/apic_64.h +++ b/include/asm-x86/apic_64.h @@ -19,7 +19,6 @@ extern int apic_verbosity; extern int apic_runs_main_timer; extern int ioapic_force; -extern int apic_mapped; /* * Define the default level of output to be very little From 801740971af7c6256b7ad2472706d43ed008fd3d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2519/2804] x86_64: prepare apic code for clock events Change __setup_APIC_LVTT so it takes the arguments which are necessary for the later clock events switch. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/apic_64.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 48206bb8de1f..ce2f8015d5ce 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -759,14 +759,14 @@ void __init init_apic_mappings(void) #define APIC_DIVISOR 16 -static void __setup_APIC_LVTT(unsigned int clocks) +static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) { unsigned int lvtt_value, tmp_value; - int cpu = smp_processor_id(); - lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; - - if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) + lvtt_value = LOCAL_TIMER_VECTOR; + if (!oneshot) + lvtt_value |= APIC_LVT_TIMER_PERIODIC; + if (!irqen) lvtt_value |= APIC_LVT_MASKED; apic_write(APIC_LVTT, lvtt_value); @@ -779,12 +779,14 @@ static void __setup_APIC_LVTT(unsigned int clocks) & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) | APIC_TDR_DIV_16); - apic_write(APIC_TMICT, clocks/APIC_DIVISOR); + if (!oneshot) + apic_write(APIC_TMICT, clocks/APIC_DIVISOR); } static void setup_APIC_timer(unsigned int clocks) { unsigned long flags; + int irqen; local_irq_save(flags); @@ -805,7 +807,10 @@ static void setup_APIC_timer(unsigned int clocks) c2 |= inb_p(0x40) << 8; } while (c2 - c1 < 300); } - __setup_APIC_LVTT(clocks); + + irqen = ! cpu_isset(smp_processor_id(), + timer_interrupt_broadcast_ipi_mask); + __setup_APIC_LVTT(clocks, 0, irqen); /* Turn off PIT interrupt if we use APIC timer as main timer. Only works with the PM timer right now TBD fix it for HPET too. */ @@ -843,8 +848,10 @@ static int __init calibrate_APIC_clock(void) * Put whatever arbitrary (but long enough) timeout * value into the APIC clock, we just want to get the * counter running for calibration. + * + * No interrupt enable ! */ - __setup_APIC_LVTT(4000000000); + __setup_APIC_LVTT(4000000000, 0, 0); apic_start = apic_read(APIC_TMCCT); #ifdef CONFIG_X86_PM_TIMER From 500ff08b76878a45391fffc7a4c972883503050e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2520/2804] x86_64: remove pit synchronization The APIC timer setup code synchronizes the local APIC timer to the PIT/HPET. This is pointless as the PIT and the local APIC timer frequency are not correlated and the APIC timer calibration can never be accurate enough to avoid that the local APIC timer and the PIT/HPET drift apart. Simply remove it. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/apic_64.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index ce2f8015d5ce..a73b443a1236 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -790,24 +790,6 @@ static void setup_APIC_timer(unsigned int clocks) local_irq_save(flags); - /* wait for irq slice */ - if (hpet_address && hpet_use_timer) { - u32 trigger = hpet_readl(HPET_T0_CMP); - while (hpet_readl(HPET_T0_CMP) == trigger) - /* do nothing */ ; - } else { - int c1, c2; - outb_p(0x00, 0x43); - c2 = inb_p(0x40); - c2 |= inb_p(0x40) << 8; - do { - c1 = c2; - outb_p(0x00, 0x43); - c2 = inb_p(0x40); - c2 |= inb_p(0x40) << 8; - } while (c2 - c1 < 300); - } - irqen = ! cpu_isset(smp_processor_id(), timer_interrupt_broadcast_ipi_mask); __setup_APIC_LVTT(clocks, 0, irqen); From d03030e917047cf7f475e641cd2d6e83647392b0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2521/2804] x86_64: Move apic calibration code around Let the calibration code fill in calibration_result directly and move the variable on top of the file. Fixup a printk w/o log level while at it. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/apic_64.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index a73b443a1236..b08c08ed36a7 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -55,6 +55,8 @@ static struct resource lapic_resource = { .flags = IORESOURCE_MEM | IORESOURCE_BUSY, }; +static unsigned int calibration_result; + /* * cpu_mask that denotes the CPUs that needs timer interrupt coming in as * IPIs in place of local APIC timers @@ -821,7 +823,7 @@ static void setup_APIC_timer(unsigned int clocks) #define TICK_COUNT 100000000 -static int __init calibrate_APIC_clock(void) +static void __init calibrate_APIC_clock(void) { unsigned apic, apic_start; unsigned long tsc, tsc_start; @@ -855,17 +857,14 @@ static int __init calibrate_APIC_clock(void) result = (apic_start - apic) * 1000L * tsc_khz / (tsc - tsc_start); } - printk("result %d\n", result); - + printk(KERN_DEBUG "APIC timer calibration result %d\n", result); printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", result / 1000 / 1000, result / 1000 % 1000); - return result * APIC_DIVISOR / HZ; + calibration_result = result * APIC_DIVISOR / HZ; } -static unsigned int calibration_result; - void __init setup_boot_APIC_clock (void) { if (disable_apic_timer) { @@ -878,7 +877,7 @@ void __init setup_boot_APIC_clock (void) local_irq_disable(); - calibration_result = calibrate_APIC_clock(); + calibrate_APIC_clock(); /* * Now set up the timer for real. */ @@ -985,8 +984,6 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector, apic_write(reg, v); } -#undef APIC_DIVISOR - /* * Local timer interrupt handler. It does both profiling and * process statistics/rescheduling. From b58eb00df7f7f80b7f456bf8fb740fddf14408ba Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:06 +0200 Subject: [PATCH 2522/2804] x86_64: Remove APIC_DIVISOR APIC_DIVISOR is rather useless. It makes the calibration result more accurate in the first place, but we discard this later when we write the value to the APIC timer by dividing the calibration value by APIC_DIVISOR. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/apic_64.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index b08c08ed36a7..f746f9dc8ced 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -759,8 +759,6 @@ void __init init_apic_mappings(void) * P5 APIC double write bug. */ -#define APIC_DIVISOR 16 - static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) { unsigned int lvtt_value, tmp_value; @@ -782,7 +780,7 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) | APIC_TDR_DIV_16); if (!oneshot) - apic_write(APIC_TMICT, clocks/APIC_DIVISOR); + apic_write(APIC_TMICT, clocks); } static void setup_APIC_timer(unsigned int clocks) @@ -835,7 +833,7 @@ static void __init calibrate_APIC_clock(void) * * No interrupt enable ! */ - __setup_APIC_LVTT(4000000000, 0, 0); + __setup_APIC_LVTT(250000000, 0, 0); apic_start = apic_read(APIC_TMCCT); #ifdef CONFIG_X86_PM_TIMER @@ -862,7 +860,7 @@ static void __init calibrate_APIC_clock(void) printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", result / 1000 / 1000, result / 1000 % 1000); - calibration_result = result * APIC_DIVISOR / HZ; + calibration_result = result / HZ; } void __init setup_boot_APIC_clock (void) From abc63fcd3cc61876b2d6f5b0d08021bd1538385c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:07 +0200 Subject: [PATCH 2523/2804] x86_64: apic change setup_APIC_timer calling convention setup_APIC_timer takes the file global calibration result as an argument. Remove it. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/apic_64.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index f746f9dc8ced..f74b1c20e5c0 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -783,7 +783,7 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) apic_write(APIC_TMICT, clocks); } -static void setup_APIC_timer(unsigned int clocks) +static void setup_APIC_timer(void) { unsigned long flags; int irqen; @@ -792,7 +792,7 @@ static void setup_APIC_timer(unsigned int clocks) irqen = ! cpu_isset(smp_processor_id(), timer_interrupt_broadcast_ipi_mask); - __setup_APIC_LVTT(clocks, 0, irqen); + __setup_APIC_LVTT(calibration_result, 0, irqen); /* Turn off PIT interrupt if we use APIC timer as main timer. Only works with the PM timer right now TBD fix it for HPET too. */ @@ -879,7 +879,7 @@ void __init setup_boot_APIC_clock (void) /* * Now set up the timer for real. */ - setup_APIC_timer(calibration_result); + setup_APIC_timer(); local_irq_enable(); } @@ -887,7 +887,7 @@ void __init setup_boot_APIC_clock (void) void __cpuinit setup_secondary_APIC_clock(void) { local_irq_disable(); /* FIXME: Do we need this? --RR */ - setup_APIC_timer(calibration_result); + setup_APIC_timer(); local_irq_enable(); } From c4d58cbd158dc9b30c55c0e3881ae7c6b8843d5a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:07 +0200 Subject: [PATCH 2524/2804] x86_64: remove nested irq disables setup_APIC_timer disables interrupts anyway. So no need to do the same in setup_boot_APIC_clock and setup_secondary_APIC_clock. Disable interrupts explicit in the calibration code. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/apic_64.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index f74b1c20e5c0..40938ef99dc2 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -826,6 +826,9 @@ static void __init calibrate_APIC_clock(void) unsigned apic, apic_start; unsigned long tsc, tsc_start; int result; + + local_irq_disable(); + /* * Put whatever arbitrary (but long enough) timeout * value into the APIC clock, we just want to get the @@ -855,6 +858,9 @@ static void __init calibrate_APIC_clock(void) result = (apic_start - apic) * 1000L * tsc_khz / (tsc - tsc_start); } + + local_irq_enable(); + printk(KERN_DEBUG "APIC timer calibration result %d\n", result); printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", @@ -873,22 +879,16 @@ void __init setup_boot_APIC_clock (void) printk(KERN_INFO "Using local APIC timer interrupts.\n"); using_apic_timer = 1; - local_irq_disable(); - calibrate_APIC_clock(); /* * Now set up the timer for real. */ setup_APIC_timer(); - - local_irq_enable(); } void __cpuinit setup_secondary_APIC_clock(void) { - local_irq_disable(); /* FIXME: Do we need this? --RR */ setup_APIC_timer(); - local_irq_enable(); } void disable_APIC_timer(void) From 02290683343391a50f45599710295dafa2ddd018 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 12 Oct 2007 23:04:07 +0200 Subject: [PATCH 2525/2804] x86_64: prepare idle loop for dynamic ticks Add tick_nohz_{stop,restart}_sched_tick to idle loop in prepartion for turning on dynticks. These are just noops until NO_HZ is enabled. Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Arjan van de Ven --- arch/x86/kernel/process_64.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 98956555450b..6f9dbbe65eef 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -208,6 +209,8 @@ void cpu_idle (void) if (__get_cpu_var(cpu_idle_state)) __get_cpu_var(cpu_idle_state) = 0; + tick_nohz_stop_sched_tick(); + rmb(); idle = pm_idle; if (!idle) @@ -228,6 +231,7 @@ void cpu_idle (void) __exit_idle(); } + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); From ba7eda4c60e1d070b2f6586d42719ec1d5302d3b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:07 +0200 Subject: [PATCH 2526/2804] x86_64: Add (not yet used) clock event functions Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/apic_64.c | 79 +++++++++++++++++++++++++++++++++++++++ arch/x86_64/Kconfig | 6 +++ 2 files changed, 85 insertions(+) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 40938ef99dc2..2c2807abe1d4 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,77 @@ static struct resource lapic_resource = { static unsigned int calibration_result; +static int lapic_next_event(unsigned long delta, + struct clock_event_device *evt); +static void lapic_timer_setup(enum clock_event_mode mode, + struct clock_event_device *evt); + +static void lapic_timer_broadcast(cpumask_t mask); + +static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen); + +static struct clock_event_device lapic_clockevent = { + .name = "lapic", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT + | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, + .shift = 32, + .set_mode = lapic_timer_setup, + .set_next_event = lapic_next_event, + .broadcast = lapic_timer_broadcast, + .rating = 100, + .irq = -1, +}; +static DEFINE_PER_CPU(struct clock_event_device, lapic_events); + +static int lapic_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + apic_write(APIC_TMICT, delta); + return 0; +} + +static void lapic_timer_setup(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long flags; + unsigned int v; + + /* Lapic used as dummy for broadcast ? */ + if (evt->features & CLOCK_EVT_FEAT_DUMMY) + return; + + local_irq_save(flags); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + case CLOCK_EVT_MODE_ONESHOT: + __setup_APIC_LVTT(calibration_result, + mode != CLOCK_EVT_MODE_PERIODIC, 1); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + v = apic_read(APIC_LVTT); + v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); + apic_write(APIC_LVTT, v); + break; + case CLOCK_EVT_MODE_RESUME: + /* Nothing to do here */ + break; + } + + local_irq_restore(flags); +} + +/* + * Local APIC timer broadcast function + */ +static void lapic_timer_broadcast(cpumask_t mask) +{ +#ifdef CONFIG_SMP + send_IPI_mask(mask, LOCAL_TIMER_VECTOR); +#endif +} + /* * cpu_mask that denotes the CPUs that needs timer interrupt coming in as * IPIs in place of local APIC timers @@ -866,6 +938,13 @@ static void __init calibrate_APIC_clock(void) printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", result / 1000 / 1000, result / 1000 % 1000); + /* Calculate the scaled math multiplication factor */ + lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32); + lapic_clockevent.max_delta_ns = + clockevent_delta2ns(0x7FFFFF, &lapic_clockevent); + lapic_clockevent.min_delta_ns = + clockevent_delta2ns(0xF, &lapic_clockevent); + calibration_result = result / HZ; } diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 520f33b83bfc..a9534c21c306 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -40,6 +40,10 @@ config CLOCKSOURCE_WATCHDOG bool default y +config GENERIC_CLOCKEVENTS_MIGR + bool + default y + config ZONE_DMA32 bool default y @@ -134,6 +138,8 @@ source "init/Kconfig" menu "Processor type and features" +source "kernel/time/Kconfig" + choice prompt "Subarchitecture Type" default X86_PC From b8ce33590687888ebb900d09557b8807c4539022 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:07 +0200 Subject: [PATCH 2527/2804] x86_64: convert to clock events Finally switch to the clockevents code. Share code with i386 for hpet and PIT. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/Makefile_64 | 4 +- arch/x86/kernel/apic_64.c | 90 ++++++++++++++++------------- arch/x86/kernel/i8259_64.c | 46 --------------- arch/x86/kernel/smpboot_64.c | 4 -- arch/x86/kernel/time_64.c | 107 +++++------------------------------ arch/x86_64/Kconfig | 6 +- include/asm-x86/hpet.h | 92 ++++++++++++++++++++++++++++-- include/asm-x86/hpet_32.h | 90 ----------------------------- include/asm-x86/hpet_64.h | 18 ------ 9 files changed, 158 insertions(+), 299 deletions(-) delete mode 100644 include/asm-x86/hpet_32.h delete mode 100644 include/asm-x86/hpet_64.h diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64 index 3ab017a0a3b9..080154e31502 100644 --- a/arch/x86/kernel/Makefile_64 +++ b/arch/x86/kernel/Makefile_64 @@ -8,8 +8,8 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ - pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \ - perfctr-watchdog.o + pci-dma_64.o pci-nommu_64.o alternative.o hpet_32.o tsc_64.o bugs_64.o \ + perfctr-watchdog.o i8253_32.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 2c2807abe1d4..b0237caff712 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -857,25 +857,12 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) static void setup_APIC_timer(void) { - unsigned long flags; - int irqen; + struct clock_event_device *levt = &__get_cpu_var(lapic_events); - local_irq_save(flags); + memcpy(levt, &lapic_clockevent, sizeof(*levt)); + levt->cpumask = cpumask_of_cpu(smp_processor_id()); - irqen = ! cpu_isset(smp_processor_id(), - timer_interrupt_broadcast_ipi_mask); - __setup_APIC_LVTT(calibration_result, 0, irqen); - /* Turn off PIT interrupt if we use APIC timer as main timer. - Only works with the PM timer right now - TBD fix it for HPET too. */ - if ((pmtmr_ioport != 0) && - smp_processor_id() == boot_cpu_id && - apic_runs_main_timer == 1 && - !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) { - stop_timer_interrupt(); - apic_runs_main_timer++; - } - local_irq_restore(flags); + clockevents_register_device(levt); } /* @@ -950,18 +937,34 @@ static void __init calibrate_APIC_clock(void) void __init setup_boot_APIC_clock (void) { + /* + * The local apic timer can be disabled via the kernel commandline. + * Register the lapic timer as a dummy clock event source on SMP + * systems, so the broadcast mechanism is used. On UP systems simply + * ignore it. + */ if (disable_apic_timer) { printk(KERN_INFO "Disabling APIC timer\n"); + /* No broadcast on UP ! */ + if (num_possible_cpus() > 1) + setup_APIC_timer(); return; } printk(KERN_INFO "Using local APIC timer interrupts.\n"); - using_apic_timer = 1; - calibrate_APIC_clock(); + /* - * Now set up the timer for real. + * If nmi_watchdog is set to IO_APIC, we need the + * PIT/HPET going. Otherwise register lapic as a dummy + * device. */ + if (nmi_watchdog != NMI_IO_APIC) + lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; + else + printk(KERN_WARNING "APIC timer registered as dummy," + " due to nmi_watchdog=1!\n"); + setup_APIC_timer(); } @@ -1073,22 +1076,34 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector, void smp_local_timer_interrupt(void) { - profile_tick(CPU_PROFILING); -#ifdef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id) - main_timer_handler(); + int cpu = smp_processor_id(); + struct clock_event_device *evt = &per_cpu(lapic_events, cpu); + /* - * We take the 'long' return path, and there every subsystem - * grabs the appropriate locks (kernel lock/ irq lock). + * Normally we should not be here till LAPIC has been initialized but + * in some cases like kdump, its possible that there is a pending LAPIC + * timer interrupt from previous kernel's context and is delivered in + * new kernel the moment interrupts are enabled. * - * We might want to decouple profiling from the 'long path', - * and do the profiling totally in assembly. - * - * Currently this isn't too much of an issue (performance wise), - * we can take more than 100K local irqs per second on a 100 MHz P5. + * Interrupts are enabled early and LAPIC is setup much later, hence + * its possible that when we get here evt->event_handler is NULL. + * Check for event_handler being NULL and discard the interrupt as + * spurious. */ + if (!evt->event_handler) { + printk(KERN_WARNING + "Spurious LAPIC timer interrupt on cpu %d\n", cpu); + /* Switch it off */ + lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); + return; + } + + /* + * the NMI deadlock-detector uses this. + */ + add_pda(apic_timer_irqs, 1); + + evt->event_handler(evt); } /* @@ -1103,11 +1118,6 @@ void smp_apic_timer_interrupt(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - /* - * the NMI deadlock-detector uses this. - */ - add_pda(apic_timer_irqs, 1); - /* * NOTE! We'd better ACK the irq immediately, * because timer handling can be slow. @@ -1291,7 +1301,7 @@ static __init int setup_noapictimer(char *str) static __init int setup_apicmaintimer(char *str) { apic_runs_main_timer = 1; - nohpet = 1; + return 1; } __setup("apicmaintimer", setup_apicmaintimer); @@ -1307,7 +1317,7 @@ static __init int setup_apicpmtimer(char *s) { apic_calibrate_pmtmr = 1; notsc_setup(NULL); - return setup_apicmaintimer(NULL); + return 0; } __setup("apicpmtimer", setup_apicpmtimer); diff --git a/arch/x86/kernel/i8259_64.c b/arch/x86/kernel/i8259_64.c index 948cae646099..eb72976cc13c 100644 --- a/arch/x86/kernel/i8259_64.c +++ b/arch/x86/kernel/i8259_64.c @@ -444,46 +444,6 @@ void __init init_ISA_irqs (void) } } -static void setup_timer_hardware(void) -{ - outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - udelay(10); - outb_p(LATCH & 0xff , 0x40); /* LSB */ - udelay(10); - outb(LATCH >> 8 , 0x40); /* MSB */ -} - -static int timer_resume(struct sys_device *dev) -{ - setup_timer_hardware(); - return 0; -} - -void i8254_timer_resume(void) -{ - setup_timer_hardware(); -} - -static struct sysdev_class timer_sysclass = { - set_kset_name("timer_pit"), - .resume = timer_resume, -}; - -static struct sys_device device_timer = { - .id = 0, - .cls = &timer_sysclass, -}; - -static int __init init_timer_sysfs(void) -{ - int error = sysdev_class_register(&timer_sysclass); - if (!error) - error = sysdev_register(&device_timer); - return error; -} - -device_initcall(init_timer_sysfs); - void __init init_IRQ(void) { int i; @@ -533,12 +493,6 @@ void __init init_IRQ(void) set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); - /* - * Set the clock to HZ Hz, we already have a valid - * vector now: - */ - setup_timer_hardware(); - if (!acpi_ioapic) setup_irq(2, &irq2); } diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c index 32f50783edc8..57ccf7cb6b91 100644 --- a/arch/x86/kernel/smpboot_64.c +++ b/arch/x86/kernel/smpboot_64.c @@ -223,8 +223,6 @@ void __cpuinit smp_callin(void) local_irq_disable(); Dprintk("Stack at about %p\n",&cpuid); - disable_APIC_timer(); - /* * Save our processor parameters */ @@ -348,8 +346,6 @@ void __cpuinit start_secondary(void) enable_8259A_irq(0); } - enable_APIC_timer(); - /* * The sibling maps must be set before turing the online map on for * this cpu diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index d899216e01ca..7781df1d50e3 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -28,6 +28,8 @@ #include #include #include +#include + #ifdef CONFIG_ACPI #include /* for PM timer frequency */ #include @@ -46,12 +48,8 @@ #include #include -static char *timename = NULL; - DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL(rtc_lock); -DEFINE_SPINLOCK(i8253_lock); -EXPORT_SYMBOL(i8253_lock); volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; @@ -194,6 +192,13 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t timer_event_interrupt(int irq, void *dev_id) +{ + global_clock_event->event_handler(global_clock_event); + + return IRQ_HANDLED; +} + unsigned long read_persistent_clock(void) { unsigned int year, mon, day, hour, min, sec; @@ -291,42 +296,8 @@ static unsigned int __init tsc_calibrate_cpu_khz(void) return pmc_now * tsc_khz / (tsc_now - tsc_start); } -static void __pit_init(int val, u8 mode) -{ - unsigned long flags; - - spin_lock_irqsave(&i8253_lock, flags); - outb_p(mode, PIT_MODE); - outb_p(val & 0xff, PIT_CH0); /* LSB */ - outb_p(val >> 8, PIT_CH0); /* MSB */ - spin_unlock_irqrestore(&i8253_lock, flags); -} - -void __init pit_init(void) -{ - __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */ -} - -void pit_stop_interrupt(void) -{ - __pit_init(0, 0x30); /* mode 0 */ -} - -void stop_timer_interrupt(void) -{ - char *name; - if (hpet_address) { - name = "HPET"; - hpet_timer_stop_set_go(0); - } else { - name = "PIT"; - pit_stop_interrupt(); - } - printk(KERN_INFO "timer: %s interrupt stopped.\n", name); -} - static struct irqaction irq0 = { - .handler = timer_interrupt, + .handler = timer_event_interrupt, .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, .mask = CPU_MASK_NONE, .name = "timer" @@ -334,20 +305,10 @@ static struct irqaction irq0 = { void __init time_init(void) { - if (nohpet) - hpet_address = 0; + if (!hpet_enable()) + setup_pit_timer(); - if (hpet_arch_init()) - hpet_address = 0; - - if (hpet_use_timer) { - /* set tick_nsec to use the proper rate for HPET */ - tick_nsec = TICK_NSEC_HPET; - timename = "HPET"; - } else { - pit_init(); - timename = "PIT"; - } + setup_irq(0, &irq0); tsc_calibrate(); @@ -369,46 +330,4 @@ void __init time_init(void) printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); init_tsc_clocksource(); - - setup_irq(0, &irq0); } - -/* - * sysfs support for the timer. - */ - -static int timer_suspend(struct sys_device *dev, pm_message_t state) -{ - return 0; -} - -static int timer_resume(struct sys_device *dev) -{ - if (hpet_address) - hpet_reenable(); - else - i8254_timer_resume(); - return 0; -} - -static struct sysdev_class timer_sysclass = { - .resume = timer_resume, - .suspend = timer_suspend, - set_kset_name("timer"), -}; - -/* XXX this sysfs stuff should probably go elsewhere later -john */ -static struct sys_device device_timer = { - .id = 0, - .cls = &timer_sysclass, -}; - -static int time_init_device(void) -{ - int error = sysdev_class_register(&timer_sysclass); - if (!error) - error = sysdev_register(&device_timer); - return error; -} - -device_initcall(time_init_device); diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index a9534c21c306..eb80f5aca54e 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -40,7 +40,11 @@ config CLOCKSOURCE_WATCHDOG bool default y -config GENERIC_CLOCKEVENTS_MIGR +config GENERIC_CLOCKEVENTS + bool + default y + +config GENERIC_CLOCKEVENTS_BROADCAST bool default y diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h index 9eff48601254..e2976ed30b70 100644 --- a/include/asm-x86/hpet.h +++ b/include/asm-x86/hpet.h @@ -1,5 +1,89 @@ -#ifdef CONFIG_X86_32 -# include "hpet_32.h" +#ifndef ASM_X86_HPET_H +#define ASM_X86_HPET_H + +#ifdef CONFIG_HPET_TIMER + +/* + * Documentation on HPET can be found at: + * http://www.intel.com/ial/home/sp/pcmmspec.htm + * ftp://download.intel.com/ial/home/sp/mmts098.pdf + */ + +#define HPET_MMAP_SIZE 1024 + +#define HPET_ID 0x000 +#define HPET_PERIOD 0x004 +#define HPET_CFG 0x010 +#define HPET_STATUS 0x020 +#define HPET_COUNTER 0x0f0 +#define HPET_T0_CFG 0x100 +#define HPET_T0_CMP 0x108 +#define HPET_T0_ROUTE 0x110 +#define HPET_T1_CFG 0x120 +#define HPET_T1_CMP 0x128 +#define HPET_T1_ROUTE 0x130 +#define HPET_T2_CFG 0x140 +#define HPET_T2_CMP 0x148 +#define HPET_T2_ROUTE 0x150 + +#define HPET_ID_REV 0x000000ff +#define HPET_ID_NUMBER 0x00001f00 +#define HPET_ID_64BIT 0x00002000 +#define HPET_ID_LEGSUP 0x00008000 +#define HPET_ID_VENDOR 0xffff0000 +#define HPET_ID_NUMBER_SHIFT 8 +#define HPET_ID_VENDOR_SHIFT 16 + +#define HPET_ID_VENDOR_8086 0x8086 + +#define HPET_CFG_ENABLE 0x001 +#define HPET_CFG_LEGACY 0x002 +#define HPET_LEGACY_8254 2 +#define HPET_LEGACY_RTC 8 + +#define HPET_TN_LEVEL 0x0002 +#define HPET_TN_ENABLE 0x0004 +#define HPET_TN_PERIODIC 0x0008 +#define HPET_TN_PERIODIC_CAP 0x0010 +#define HPET_TN_64BIT_CAP 0x0020 +#define HPET_TN_SETVAL 0x0040 +#define HPET_TN_32BIT 0x0100 +#define HPET_TN_ROUTE 0x3e00 +#define HPET_TN_FSB 0x4000 +#define HPET_TN_FSB_CAP 0x8000 +#define HPET_TN_ROUTE_SHIFT 9 + +/* Max HPET Period is 10^8 femto sec as in HPET spec */ +#define HPET_MAX_PERIOD 100000000UL +/* + * Min HPET period is 10^5 femto sec just for safety. If it is less than this, + * then 32 bit HPET counter wrapsaround in less than 0.5 sec. + */ +#define HPET_MIN_PERIOD 100000UL + +/* hpet memory map physical address */ +extern unsigned long hpet_address; +extern int is_hpet_enabled(void); +extern int hpet_enable(void); + +#ifdef CONFIG_HPET_EMULATE_RTC + +#include + +extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask); +extern int hpet_set_rtc_irq_bit(unsigned long bit_mask); +extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, + unsigned char sec); +extern int hpet_set_periodic_freq(unsigned long freq); +extern int hpet_rtc_dropped_irq(void); +extern int hpet_rtc_timer_init(void); +extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); + +#endif /* CONFIG_HPET_EMULATE_RTC */ + #else -# include "hpet_64.h" -#endif + +static inline int hpet_enable(void) { return 0; } + +#endif /* CONFIG_HPET_TIMER */ +#endif /* ASM_X86_HPET_H */ diff --git a/include/asm-x86/hpet_32.h b/include/asm-x86/hpet_32.h deleted file mode 100644 index c82dc7ed96b3..000000000000 --- a/include/asm-x86/hpet_32.h +++ /dev/null @@ -1,90 +0,0 @@ - -#ifndef _I386_HPET_H -#define _I386_HPET_H - -#ifdef CONFIG_HPET_TIMER - -/* - * Documentation on HPET can be found at: - * http://www.intel.com/ial/home/sp/pcmmspec.htm - * ftp://download.intel.com/ial/home/sp/mmts098.pdf - */ - -#define HPET_MMAP_SIZE 1024 - -#define HPET_ID 0x000 -#define HPET_PERIOD 0x004 -#define HPET_CFG 0x010 -#define HPET_STATUS 0x020 -#define HPET_COUNTER 0x0f0 -#define HPET_T0_CFG 0x100 -#define HPET_T0_CMP 0x108 -#define HPET_T0_ROUTE 0x110 -#define HPET_T1_CFG 0x120 -#define HPET_T1_CMP 0x128 -#define HPET_T1_ROUTE 0x130 -#define HPET_T2_CFG 0x140 -#define HPET_T2_CMP 0x148 -#define HPET_T2_ROUTE 0x150 - -#define HPET_ID_REV 0x000000ff -#define HPET_ID_NUMBER 0x00001f00 -#define HPET_ID_64BIT 0x00002000 -#define HPET_ID_LEGSUP 0x00008000 -#define HPET_ID_VENDOR 0xffff0000 -#define HPET_ID_NUMBER_SHIFT 8 -#define HPET_ID_VENDOR_SHIFT 16 - -#define HPET_ID_VENDOR_8086 0x8086 - -#define HPET_CFG_ENABLE 0x001 -#define HPET_CFG_LEGACY 0x002 -#define HPET_LEGACY_8254 2 -#define HPET_LEGACY_RTC 8 - -#define HPET_TN_LEVEL 0x0002 -#define HPET_TN_ENABLE 0x0004 -#define HPET_TN_PERIODIC 0x0008 -#define HPET_TN_PERIODIC_CAP 0x0010 -#define HPET_TN_64BIT_CAP 0x0020 -#define HPET_TN_SETVAL 0x0040 -#define HPET_TN_32BIT 0x0100 -#define HPET_TN_ROUTE 0x3e00 -#define HPET_TN_FSB 0x4000 -#define HPET_TN_FSB_CAP 0x8000 -#define HPET_TN_ROUTE_SHIFT 9 - -/* Max HPET Period is 10^8 femto sec as in HPET spec */ -#define HPET_MAX_PERIOD 100000000UL -/* - * Min HPET period is 10^5 femto sec just for safety. If it is less than this, - * then 32 bit HPET counter wrapsaround in less than 0.5 sec. - */ -#define HPET_MIN_PERIOD 100000UL - -/* hpet memory map physical address */ -extern unsigned long hpet_address; -extern int is_hpet_enabled(void); -extern int hpet_enable(void); - -#ifdef CONFIG_HPET_EMULATE_RTC - -#include - -extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask); -extern int hpet_set_rtc_irq_bit(unsigned long bit_mask); -extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, - unsigned char sec); -extern int hpet_set_periodic_freq(unsigned long freq); -extern int hpet_rtc_dropped_irq(void); -extern int hpet_rtc_timer_init(void); -extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); - -#endif /* CONFIG_HPET_EMULATE_RTC */ - -#else - -static inline int hpet_enable(void) { return 0; } - -#endif /* CONFIG_HPET_TIMER */ -#endif /* _I386_HPET_H */ diff --git a/include/asm-x86/hpet_64.h b/include/asm-x86/hpet_64.h deleted file mode 100644 index fd4decac93a8..000000000000 --- a/include/asm-x86/hpet_64.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _ASM_X8664_HPET_H -#define _ASM_X8664_HPET_H 1 - -#include - -#define HPET_TICK_RATE (HZ * 100000UL) - -extern int hpet_rtc_timer_init(void); -extern int hpet_arch_init(void); -extern int hpet_timer_stop_set_go(unsigned long tick); -extern int hpet_reenable(void); -extern unsigned int hpet_calibrate_tsc(void); - -extern int hpet_use_timer; -extern unsigned long hpet_period; -extern unsigned long hpet_tick; - -#endif From 4e77ae3e105d28aa9410585715d83818f0abe871 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:07 +0200 Subject: [PATCH 2528/2804] x86: Fix irq0 / local apic timer accounting The clock events merge introduced a change to the nmi watchdog code to handle the not longer increasing local apic timer count in the broadcast mode. This is fine for UP, but on SMP it pampers over a stuck CPU which is not handling the broadcast interrupt due to the unconditional sum up of local apic timer count and irq0 count. To cover all cases we need to keep track on which CPU irq0 is handled. In theory this is CPU#0 due to the explicit disabling of irq balancing for irq0, but there are systems which ignore this on the hardware level. The per cpu irq0 accounting allows us to remove the irq0 to CPU0 binding as well. Add a per cpu counter for irq0 and evaluate this instead of the global irq0 count in the nmi watchdog code. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/nmi_64.c | 2 +- arch/x86/kernel/time_64.c | 2 ++ include/asm-x86/pda.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c index 0ec6d2ddb931..e60ac0da5283 100644 --- a/arch/x86/kernel/nmi_64.c +++ b/arch/x86/kernel/nmi_64.c @@ -329,7 +329,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) touched = 1; } - sum = read_pda(apic_timer_irqs); + sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs); if (__get_cpu_var(nmi_touch)) { __get_cpu_var(nmi_touch) = 0; touched = 1; diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index 7781df1d50e3..16f58886e8dc 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -194,6 +194,8 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) static irqreturn_t timer_event_interrupt(int irq, void *dev_id) { + add_pda(irq0_irqs, 1); + global_clock_event->event_handler(global_clock_event); return IRQ_HANDLED; diff --git a/include/asm-x86/pda.h b/include/asm-x86/pda.h index 5642634843c4..fb49f80eb94f 100644 --- a/include/asm-x86/pda.h +++ b/include/asm-x86/pda.h @@ -29,6 +29,7 @@ struct x8664_pda { short isidle; struct mm_struct *active_mm; unsigned apic_timer_irqs; + unsigned irq0_irqs; } ____cacheline_aligned_in_smp; extern struct x8664_pda *_cpu_pda[]; From fb79d22e1d4b06385796cc0db0084a2e07beccee Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:07 +0200 Subject: [PATCH 2529/2804] x86: disable apic timer for AMD C1E enabled CPUs AMDs C1E enabled CPUs stop the local apic timer, when both cores are idle. This is a hardware feature which breaks highres/dynticks. Add the same quirk as we have for 32 bit already. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/apic_64.c | 2 +- arch/x86/kernel/setup_64.c | 34 ++++++++++++++++++++++++++++++++++ include/asm-x86/apic_64.h | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index b0237caff712..118830cba1ae 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -44,7 +44,7 @@ int apic_verbosity; int apic_runs_main_timer; int apic_calibrate_pmtmr __initdata; -int disable_apic_timer __initdata; +int disable_apic_timer __cpuinitdata; /* Local APIC timer works in C2? */ int local_apic_timer_c2_ok; diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index af838f6b0b7f..32054bf5ba40 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c @@ -546,6 +546,37 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) #endif } +#define ENABLE_C1E_MASK 0x18000000 +#define CPUID_PROCESSOR_SIGNATURE 1 +#define CPUID_XFAM 0x0ff00000 +#define CPUID_XFAM_K8 0x00000000 +#define CPUID_XFAM_10H 0x00100000 +#define CPUID_XFAM_11H 0x00200000 +#define CPUID_XMOD 0x000f0000 +#define CPUID_XMOD_REV_F 0x00040000 + +/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */ +static __cpuinit int amd_apic_timer_broken(void) +{ + u32 lo, hi; + u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); + switch (eax & CPUID_XFAM) { + case CPUID_XFAM_K8: + if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F) + break; + case CPUID_XFAM_10H: + case CPUID_XFAM_11H: + rdmsr(MSR_K8_ENABLE_C1E, lo, hi); + if (lo & ENABLE_C1E_MASK) + return 1; + break; + default: + /* err on the side of caution */ + return 1; + } + return 0; +} + static void __cpuinit init_amd(struct cpuinfo_x86 *c) { unsigned level; @@ -617,6 +648,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) /* Family 10 doesn't support C states in MWAIT so don't use it */ if (c->x86 == 0x10 && !force_mwait) clear_bit(X86_FEATURE_MWAIT, &c->x86_capability); + + if (amd_apic_timer_broken()) + disable_apic_timer = 1; } static void __cpuinit detect_ht(struct cpuinfo_x86 *c) diff --git a/include/asm-x86/apic_64.h b/include/asm-x86/apic_64.h index 81335e95365b..f32f654d1f96 100644 --- a/include/asm-x86/apic_64.h +++ b/include/asm-x86/apic_64.h @@ -19,6 +19,7 @@ extern int apic_verbosity; extern int apic_runs_main_timer; extern int ioapic_force; +extern int disable_apic_timer; /* * Define the default level of output to be very little From 5d5a2989b72847e1f5763420ea31383ca63ebf53 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2530/2804] x86: kill 8253pit.h Useless header file with 32 bit and 64 bit variants. Move the single useful line to the place where it is used. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/i8259_32.c | 1 - drivers/input/misc/pcspkr.c | 2 +- include/asm-x86/8253pit.h | 5 ----- include/asm-x86/8253pit_32.h | 12 ------------ include/asm-x86/8253pit_64.h | 10 ---------- include/asm-x86/i8253.h | 4 ---- include/asm-x86/timex_32.h | 6 +++--- include/asm-x86/timex_64.h | 2 +- 8 files changed, 5 insertions(+), 37 deletions(-) delete mode 100644 include/asm-x86/8253pit.h delete mode 100644 include/asm-x86/8253pit_32.h delete mode 100644 include/asm-x86/8253pit_64.h diff --git a/arch/x86/kernel/i8259_32.c b/arch/x86/kernel/i8259_32.c index 0499cbe9871a..679bb33acbf1 100644 --- a/arch/x86/kernel/i8259_32.c +++ b/arch/x86/kernel/i8259_32.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 906bf5e8de89..4e2ca6f0ab18 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -17,7 +17,6 @@ #include #include #include -#include #include MODULE_AUTHOR("Vojtech Pavlik "); @@ -28,6 +27,7 @@ MODULE_LICENSE("GPL"); /* Use the global PIT lock ! */ #include #else +#include static DEFINE_SPINLOCK(i8253_lock); #endif diff --git a/include/asm-x86/8253pit.h b/include/asm-x86/8253pit.h deleted file mode 100644 index d3c2b38a6618..000000000000 --- a/include/asm-x86/8253pit.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef CONFIG_X86_32 -# include "8253pit_32.h" -#else -# include "8253pit_64.h" -#endif diff --git a/include/asm-x86/8253pit_32.h b/include/asm-x86/8253pit_32.h deleted file mode 100644 index 96c7c3592daf..000000000000 --- a/include/asm-x86/8253pit_32.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 8253/8254 Programmable Interval Timer - */ - -#ifndef _8253PIT_H -#define _8253PIT_H - -#include - -#define PIT_TICK_RATE CLOCK_TICK_RATE - -#endif diff --git a/include/asm-x86/8253pit_64.h b/include/asm-x86/8253pit_64.h deleted file mode 100644 index 285f78488ccb..000000000000 --- a/include/asm-x86/8253pit_64.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 8253/8254 Programmable Interval Timer - */ - -#ifndef _8253PIT_H -#define _8253PIT_H - -#define PIT_TICK_RATE 1193182UL - -#endif diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h index 7eff6fd27474..28cf67da59a3 100644 --- a/include/asm-x86/i8253.h +++ b/include/asm-x86/i8253.h @@ -1,10 +1,6 @@ #ifndef __ASM_I8253_H__ #define __ASM_I8253_H__ -#ifdef CONFIG_X86_64 -# include -#endif - /* i8253A PIT registers */ #define PIT_MODE 0x43 #define PIT_CH0 0x40 diff --git a/include/asm-x86/timex_32.h b/include/asm-x86/timex_32.h index 3666044409f0..fa8839465bdb 100644 --- a/include/asm-x86/timex_32.h +++ b/include/asm-x86/timex_32.h @@ -10,11 +10,11 @@ #include #ifdef CONFIG_X86_ELAN -# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */ +# define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */ #else -# define CLOCK_TICK_RATE 1193182 /* Underlying HZ */ +# define PIT_TICK_RATE 1193182 /* Underlying HZ */ #endif - +#define CLOCK_TICK_RATE PIT_TICK_RATE extern int read_current_timer(unsigned long *timer_value); #define ARCH_HAS_READ_CURRENT_TIMER 1 diff --git a/include/asm-x86/timex_64.h b/include/asm-x86/timex_64.h index 6ed21f44d308..901bf89ce643 100644 --- a/include/asm-x86/timex_64.h +++ b/include/asm-x86/timex_64.h @@ -6,7 +6,6 @@ #ifndef _ASMx8664_TIMEX_H #define _ASMx8664_TIMEX_H -#include #include #include #include @@ -14,6 +13,7 @@ #include #include +#define PIT_TICK_RATE 1193182UL #define CLOCK_TICK_RATE PIT_TICK_RATE /* Underlying HZ */ extern int read_current_timer(unsigned long *timer_value); From 2f0798a3b1c2155b8f30858e853557aef9da2e4e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2531/2804] x86: unify timex.h variants Combine the timex.h variants and move the TSC related code into tsc.h. Move the set_cyc2ns_scale() call into the tsc calibraction code, where it belongs. Signed-off-by: Thomas Gleixner Signed-off-by: Arjan van de Ven --- arch/x86/kernel/time_64.c | 1 - arch/x86/kernel/tsc_64.c | 3 ++- include/asm-x86/timex.h | 19 ++++++++++++++++--- include/asm-x86/timex_32.h | 22 ---------------------- include/asm-x86/timex_64.h | 31 ------------------------------- include/asm-x86/tsc.h | 11 ++++++----- 6 files changed, 24 insertions(+), 63 deletions(-) delete mode 100644 include/asm-x86/timex_32.h delete mode 100644 include/asm-x86/timex_64.h diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index 16f58886e8dc..aca081c37884 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -328,7 +328,6 @@ void __init time_init(void) else vgetcpu_mode = VGETCPU_LSL; - set_cyc2ns_scale(tsc_khz); printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); init_tsc_clocksource(); diff --git a/arch/x86/kernel/tsc_64.c b/arch/x86/kernel/tsc_64.c index 59baecd135ab..9f22e542c374 100644 --- a/arch/x86/kernel/tsc_64.c +++ b/arch/x86/kernel/tsc_64.c @@ -20,7 +20,7 @@ EXPORT_SYMBOL(tsc_khz); static unsigned int cyc2ns_scale __read_mostly; -void set_cyc2ns_scale(unsigned long khz) +static inline void set_cyc2ns_scale(unsigned long khz) { cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz; } @@ -206,6 +206,7 @@ void __init tsc_calibrate(void) } tsc_khz = tsc2 / tsc1; + set_cyc2ns_scale(tsc_khz); } /* diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h index d01c18cfccef..39a21ab030f0 100644 --- a/include/asm-x86/timex.h +++ b/include/asm-x86/timex.h @@ -1,5 +1,18 @@ -#ifdef CONFIG_X86_32 -# include "timex_32.h" +/* x86 architecture timex specifications */ +#ifndef _ASM_X86_TIMEX_H +#define _ASM_X86_TIMEX_H + +#include +#include + +#ifdef CONFIG_X86_ELAN +# define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */ #else -# include "timex_64.h" +# define PIT_TICK_RATE 1193182 /* Underlying HZ */ +#endif +#define CLOCK_TICK_RATE PIT_TICK_RATE + +extern int read_current_timer(unsigned long *timer_value); +#define ARCH_HAS_READ_CURRENT_TIMER 1 + #endif diff --git a/include/asm-x86/timex_32.h b/include/asm-x86/timex_32.h deleted file mode 100644 index fa8839465bdb..000000000000 --- a/include/asm-x86/timex_32.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * linux/include/asm-i386/timex.h - * - * i386 architecture timex specifications - */ -#ifndef _ASMi386_TIMEX_H -#define _ASMi386_TIMEX_H - -#include -#include - -#ifdef CONFIG_X86_ELAN -# define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */ -#else -# define PIT_TICK_RATE 1193182 /* Underlying HZ */ -#endif -#define CLOCK_TICK_RATE PIT_TICK_RATE - -extern int read_current_timer(unsigned long *timer_value); -#define ARCH_HAS_READ_CURRENT_TIMER 1 - -#endif diff --git a/include/asm-x86/timex_64.h b/include/asm-x86/timex_64.h deleted file mode 100644 index 901bf89ce643..000000000000 --- a/include/asm-x86/timex_64.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * linux/include/asm-x86_64/timex.h - * - * x86-64 architecture timex specifications - */ -#ifndef _ASMx8664_TIMEX_H -#define _ASMx8664_TIMEX_H - -#include -#include -#include -#include -#include -#include - -#define PIT_TICK_RATE 1193182UL -#define CLOCK_TICK_RATE PIT_TICK_RATE /* Underlying HZ */ - -extern int read_current_timer(unsigned long *timer_value); -#define ARCH_HAS_READ_CURRENT_TIMER 1 - -#define USEC_PER_TICK (USEC_PER_SEC / HZ) -#define NSEC_PER_TICK (NSEC_PER_SEC / HZ) -#define FSEC_PER_TICK (FSEC_PER_SEC / HZ) - -#define NS_SCALE 10 /* 2^10, carefully chosen */ -#define US_SCALE 32 /* 2^32, arbitralrily chosen */ - -extern void mark_tsc_unstable(char *msg); -extern void set_cyc2ns_scale(unsigned long khz); -#endif diff --git a/include/asm-x86/tsc.h b/include/asm-x86/tsc.h index 2002f8d6d20a..6baab30dc2c8 100644 --- a/include/asm-x86/tsc.h +++ b/include/asm-x86/tsc.h @@ -1,13 +1,14 @@ /* - * linux/include/asm-i386/tsc.h - * - * i386 TSC related functions + * x86 TSC related functions */ -#ifndef _ASM_i386_TSC_H -#define _ASM_i386_TSC_H +#ifndef _ASM_X86_TSC_H +#define _ASM_X86_TSC_H #include +#define NS_SCALE 10 /* 2^10, carefully chosen */ +#define US_SCALE 32 /* 2^32, arbitralrily chosen */ + /* * Standard way to access the cycle counter. */ From 9f75e9b74a45d7d3c343c8979f49d5e6b92bbce3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2532/2804] x86_64: remove now unused code Remove the unused code after the switch to clock events. Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/Makefile_32 | 4 +- arch/x86/kernel/Makefile_64 | 4 +- arch/x86/kernel/apic_64.c | 106 +----- arch/x86/kernel/{hpet_32.c => hpet.c} | 0 arch/x86/kernel/hpet_64.c | 444 ------------------------ arch/x86/kernel/{i8253_32.c => i8253.c} | 0 arch/x86/kernel/time_64.c | 42 --- include/asm-x86/apic_64.h | 6 - include/asm-x86/proto.h | 7 - 9 files changed, 5 insertions(+), 608 deletions(-) rename arch/x86/kernel/{hpet_32.c => hpet.c} (100%) delete mode 100644 arch/x86/kernel/hpet_64.c rename arch/x86/kernel/{i8253_32.c => i8253.c} (100%) diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 index 10356443998e..7ff02063b858 100644 --- a/arch/x86/kernel/Makefile_32 +++ b/arch/x86/kernel/Makefile_32 @@ -7,7 +7,7 @@ extra-y := head_32.o init_task_32.o vmlinux.lds obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ - quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o + quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ @@ -37,7 +37,7 @@ obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_HPET_TIMER) += hpet_32.o +obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64 index 080154e31502..43da66213a47 100644 --- a/arch/x86/kernel/Makefile_64 +++ b/arch/x86/kernel/Makefile_64 @@ -8,8 +8,8 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ - pci-dma_64.o pci-nommu_64.o alternative.o hpet_32.o tsc_64.o bugs_64.o \ - perfctr-watchdog.o i8253_32.o + pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \ + perfctr-watchdog.o i8253.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 118830cba1ae..1231365404c4 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -41,7 +41,6 @@ #include int apic_verbosity; -int apic_runs_main_timer; int apic_calibrate_pmtmr __initdata; int disable_apic_timer __cpuinitdata; @@ -129,15 +128,6 @@ static void lapic_timer_broadcast(cpumask_t mask) #endif } -/* - * cpu_mask that denotes the CPUs that needs timer interrupt coming in as - * IPIs in place of local APIC timers - */ -static cpumask_t timer_interrupt_broadcast_ipi_mask; - -/* Using APIC to generate smp_local_timer_interrupt? */ -int using_apic_timer __read_mostly = 0; - static void apic_pm_activate(void); void apic_wait_icr_idle(void) @@ -973,84 +963,6 @@ void __cpuinit setup_secondary_APIC_clock(void) setup_APIC_timer(); } -void disable_APIC_timer(void) -{ - if (using_apic_timer) { - unsigned long v; - - v = apic_read(APIC_LVTT); - /* - * When an illegal vector value (0-15) is written to an LVT - * entry and delivery mode is Fixed, the APIC may signal an - * illegal vector error, with out regard to whether the mask - * bit is set or whether an interrupt is actually seen on input. - * - * Boot sequence might call this function when the LVTT has - * '0' vector value. So make sure vector field is set to - * valid value. - */ - v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); - apic_write(APIC_LVTT, v); - } -} - -void enable_APIC_timer(void) -{ - int cpu = smp_processor_id(); - - if (using_apic_timer && - !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { - unsigned long v; - - v = apic_read(APIC_LVTT); - apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED); - } -} - -void switch_APIC_timer_to_ipi(void *cpumask) -{ - cpumask_t mask = *(cpumask_t *)cpumask; - int cpu = smp_processor_id(); - - if (cpu_isset(cpu, mask) && - !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { - disable_APIC_timer(); - cpu_set(cpu, timer_interrupt_broadcast_ipi_mask); - } -} -EXPORT_SYMBOL(switch_APIC_timer_to_ipi); - -void smp_send_timer_broadcast_ipi(void) -{ - int cpu = smp_processor_id(); - cpumask_t mask; - - cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask); - - if (cpu_isset(cpu, mask)) { - cpu_clear(cpu, mask); - add_pda(apic_timer_irqs, 1); - smp_local_timer_interrupt(); - } - - if (!cpus_empty(mask)) { - send_IPI_mask(mask, LOCAL_TIMER_VECTOR); - } -} - -void switch_ipi_to_APIC_timer(void *cpumask) -{ - cpumask_t mask = *(cpumask_t *)cpumask; - int cpu = smp_processor_id(); - - if (cpu_isset(cpu, mask) && - cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { - cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask); - enable_APIC_timer(); - } -} -EXPORT_SYMBOL(switch_ipi_to_APIC_timer); - int setup_profiling_timer(unsigned int multiplier) { return -EINVAL; @@ -1297,21 +1209,7 @@ static __init int setup_noapictimer(char *str) disable_apic_timer = 1; return 1; } - -static __init int setup_apicmaintimer(char *str) -{ - apic_runs_main_timer = 1; - - return 1; -} -__setup("apicmaintimer", setup_apicmaintimer); - -static __init int setup_noapicmaintimer(char *str) -{ - apic_runs_main_timer = -1; - return 1; -} -__setup("noapicmaintimer", setup_noapicmaintimer); +__setup("noapictimer", setup_noapictimer); static __init int setup_apicpmtimer(char *s) { @@ -1321,5 +1219,3 @@ static __init int setup_apicpmtimer(char *s) } __setup("apicpmtimer", setup_apicpmtimer); -__setup("noapictimer", setup_noapictimer); - diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet.c similarity index 100% rename from arch/x86/kernel/hpet_32.c rename to arch/x86/kernel/hpet.c diff --git a/arch/x86/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c deleted file mode 100644 index 1ebce2ec7eaf..000000000000 --- a/arch/x86/kernel/hpet_64.c +++ /dev/null @@ -1,444 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HPET_MASK 0xFFFFFFFF -#define HPET_SHIFT 22 - -/* FSEC = 10^-15 NSEC = 10^-9 */ -#define FSEC_PER_NSEC 1000000 - -int nohpet __initdata; - -unsigned long hpet_address; -unsigned long hpet_period; /* fsecs / HPET clock */ -unsigned long hpet_tick; /* HPET clocks / interrupt */ - -int hpet_use_timer; /* Use counter of hpet for time keeping, - * otherwise PIT - */ - -#ifdef CONFIG_HPET -static __init int late_hpet_init(void) -{ - struct hpet_data hd; - unsigned int ntimer; - - if (!hpet_address) - return 0; - - memset(&hd, 0, sizeof(hd)); - - ntimer = hpet_readl(HPET_ID); - ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT; - ntimer++; - - /* - * Register with driver. - * Timer0 and Timer1 is used by platform. - */ - hd.hd_phys_address = hpet_address; - hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE); - hd.hd_nirqs = ntimer; - hd.hd_flags = HPET_DATA_PLATFORM; - hpet_reserve_timer(&hd, 0); -#ifdef CONFIG_HPET_EMULATE_RTC - hpet_reserve_timer(&hd, 1); -#endif - hd.hd_irq[0] = HPET_LEGACY_8254; - hd.hd_irq[1] = HPET_LEGACY_RTC; - if (ntimer > 2) { - struct hpet *hpet; - struct hpet_timer *timer; - int i; - - hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE); - timer = &hpet->hpet_timers[2]; - for (i = 2; i < ntimer; timer++, i++) - hd.hd_irq[i] = (timer->hpet_config & - Tn_INT_ROUTE_CNF_MASK) >> - Tn_INT_ROUTE_CNF_SHIFT; - - } - - hpet_alloc(&hd); - return 0; -} -fs_initcall(late_hpet_init); -#endif - -int hpet_timer_stop_set_go(unsigned long tick) -{ - unsigned int cfg; - -/* - * Stop the timers and reset the main counter. - */ - - cfg = hpet_readl(HPET_CFG); - cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY); - hpet_writel(cfg, HPET_CFG); - hpet_writel(0, HPET_COUNTER); - hpet_writel(0, HPET_COUNTER + 4); - -/* - * Set up timer 0, as periodic with first interrupt to happen at hpet_tick, - * and period also hpet_tick. - */ - if (hpet_use_timer) { - hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | - HPET_TN_32BIT, HPET_T0_CFG); - hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */ - hpet_writel(hpet_tick, HPET_T0_CMP); /* period */ - cfg |= HPET_CFG_LEGACY; - } -/* - * Go! - */ - - cfg |= HPET_CFG_ENABLE; - hpet_writel(cfg, HPET_CFG); - - return 0; -} - -static cycle_t read_hpet(void) -{ - return (cycle_t)hpet_readl(HPET_COUNTER); -} - -static cycle_t __vsyscall_fn vread_hpet(void) -{ - return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); -} - -struct clocksource clocksource_hpet = { - .name = "hpet", - .rating = 250, - .read = read_hpet, - .mask = (cycle_t)HPET_MASK, - .mult = 0, /* set below */ - .shift = HPET_SHIFT, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .vread = vread_hpet, -}; - -int __init hpet_arch_init(void) -{ - unsigned int id; - u64 tmp; - - if (!hpet_address) - return -1; - set_fixmap_nocache(FIX_HPET_BASE, hpet_address); - __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); - -/* - * Read the period, compute tick and quotient. - */ - - id = hpet_readl(HPET_ID); - - if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER)) - return -1; - - hpet_period = hpet_readl(HPET_PERIOD); - if (hpet_period < 100000 || hpet_period > 100000000) - return -1; - - hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period; - - hpet_use_timer = (id & HPET_ID_LEGSUP); - - /* - * hpet period is in femto seconds per cycle - * so we need to convert this to ns/cyc units - * aproximated by mult/2^shift - * - * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift - * fsec/cyc * 1ns/1000000fsec * 2^shift = mult - * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult - * (fsec/cyc << shift)/1000000 = mult - * (hpet_period << shift)/FSEC_PER_NSEC = mult - */ - tmp = (u64)hpet_period << HPET_SHIFT; - do_div(tmp, FSEC_PER_NSEC); - clocksource_hpet.mult = (u32)tmp; - clocksource_register(&clocksource_hpet); - - return hpet_timer_stop_set_go(hpet_tick); -} - -int hpet_reenable(void) -{ - return hpet_timer_stop_set_go(hpet_tick); -} - -#ifdef CONFIG_HPET_EMULATE_RTC -/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET - * is enabled, we support RTC interrupt functionality in software. - * RTC has 3 kinds of interrupts: - * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock - * is updated - * 2) Alarm Interrupt - generate an interrupt at a specific time of day - * 3) Periodic Interrupt - generate periodic interrupt, with frequencies - * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) - * (1) and (2) above are implemented using polling at a frequency of - * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt - * overhead. (DEFAULT_RTC_INT_FREQ) - * For (3), we use interrupts at 64Hz or user specified periodic - * frequency, whichever is higher. - */ -#include - -#define DEFAULT_RTC_INT_FREQ 64 -#define RTC_NUM_INTS 1 - -static unsigned long UIE_on; -static unsigned long prev_update_sec; - -static unsigned long AIE_on; -static struct rtc_time alarm_time; - -static unsigned long PIE_on; -static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; -static unsigned long PIE_count; - -static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ -static unsigned int hpet_t1_cmp; /* cached comparator register */ - -int is_hpet_enabled(void) -{ - return hpet_address != 0; -} - -/* - * Timer 1 for RTC, we do not use periodic interrupt feature, - * even if HPET supports periodic interrupts on Timer 1. - * The reason being, to set up a periodic interrupt in HPET, we need to - * stop the main counter. And if we do that everytime someone diables/enables - * RTC, we will have adverse effect on main kernel timer running on Timer 0. - * So, for the time being, simulate the periodic interrupt in software. - * - * hpet_rtc_timer_init() is called for the first time and during subsequent - * interuppts reinit happens through hpet_rtc_timer_reinit(). - */ -int hpet_rtc_timer_init(void) -{ - unsigned int cfg, cnt; - unsigned long flags; - - if (!is_hpet_enabled()) - return 0; - /* - * Set the counter 1 and enable the interrupts. - */ - if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) - hpet_rtc_int_freq = PIE_freq; - else - hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; - - local_irq_save(flags); - - cnt = hpet_readl(HPET_COUNTER); - cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); - hpet_writel(cnt, HPET_T1_CMP); - hpet_t1_cmp = cnt; - - cfg = hpet_readl(HPET_T1_CFG); - cfg &= ~HPET_TN_PERIODIC; - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; - hpet_writel(cfg, HPET_T1_CFG); - - local_irq_restore(flags); - - return 1; -} - -static void hpet_rtc_timer_reinit(void) -{ - unsigned int cfg, cnt, ticks_per_int, lost_ints; - - if (unlikely(!(PIE_on | AIE_on | UIE_on))) { - cfg = hpet_readl(HPET_T1_CFG); - cfg &= ~HPET_TN_ENABLE; - hpet_writel(cfg, HPET_T1_CFG); - return; - } - - if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) - hpet_rtc_int_freq = PIE_freq; - else - hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; - - /* It is more accurate to use the comparator value than current count.*/ - ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq; - hpet_t1_cmp += ticks_per_int; - hpet_writel(hpet_t1_cmp, HPET_T1_CMP); - - /* - * If the interrupt handler was delayed too long, the write above tries - * to schedule the next interrupt in the past and the hardware would - * not interrupt until the counter had wrapped around. - * So we have to check that the comparator wasn't set to a past time. - */ - cnt = hpet_readl(HPET_COUNTER); - if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) { - lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1; - /* Make sure that, even with the time needed to execute - * this code, the next scheduled interrupt has been moved - * back to the future: */ - lost_ints++; - - hpet_t1_cmp += lost_ints * ticks_per_int; - hpet_writel(hpet_t1_cmp, HPET_T1_CMP); - - if (PIE_on) - PIE_count += lost_ints; - - if (printk_ratelimit()) - printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", - hpet_rtc_int_freq); - } -} - -/* - * The functions below are called from rtc driver. - * Return 0 if HPET is not being used. - * Otherwise do the necessary changes and return 1. - */ -int hpet_mask_rtc_irq_bit(unsigned long bit_mask) -{ - if (!is_hpet_enabled()) - return 0; - - if (bit_mask & RTC_UIE) - UIE_on = 0; - if (bit_mask & RTC_PIE) - PIE_on = 0; - if (bit_mask & RTC_AIE) - AIE_on = 0; - - return 1; -} - -int hpet_set_rtc_irq_bit(unsigned long bit_mask) -{ - int timer_init_reqd = 0; - - if (!is_hpet_enabled()) - return 0; - - if (!(PIE_on | AIE_on | UIE_on)) - timer_init_reqd = 1; - - if (bit_mask & RTC_UIE) { - UIE_on = 1; - } - if (bit_mask & RTC_PIE) { - PIE_on = 1; - PIE_count = 0; - } - if (bit_mask & RTC_AIE) { - AIE_on = 1; - } - - if (timer_init_reqd) - hpet_rtc_timer_init(); - - return 1; -} - -int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec) -{ - if (!is_hpet_enabled()) - return 0; - - alarm_time.tm_hour = hrs; - alarm_time.tm_min = min; - alarm_time.tm_sec = sec; - - return 1; -} - -int hpet_set_periodic_freq(unsigned long freq) -{ - if (!is_hpet_enabled()) - return 0; - - PIE_freq = freq; - PIE_count = 0; - - return 1; -} - -int hpet_rtc_dropped_irq(void) -{ - if (!is_hpet_enabled()) - return 0; - - return 1; -} - -irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) -{ - struct rtc_time curr_time; - unsigned long rtc_int_flag = 0; - int call_rtc_interrupt = 0; - - hpet_rtc_timer_reinit(); - - if (UIE_on | AIE_on) { - rtc_get_rtc_time(&curr_time); - } - if (UIE_on) { - if (curr_time.tm_sec != prev_update_sec) { - /* Set update int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag = RTC_UF; - prev_update_sec = curr_time.tm_sec; - } - } - if (PIE_on) { - PIE_count++; - if (PIE_count >= hpet_rtc_int_freq/PIE_freq) { - /* Set periodic int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag |= RTC_PF; - PIE_count = 0; - } - } - if (AIE_on) { - if ((curr_time.tm_sec == alarm_time.tm_sec) && - (curr_time.tm_min == alarm_time.tm_min) && - (curr_time.tm_hour == alarm_time.tm_hour)) { - /* Set alarm int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag |= RTC_AF; - } - } - if (call_rtc_interrupt) { - rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); - rtc_interrupt(rtc_int_flag, dev_id); - } - return IRQ_HANDLED; -} -#endif - -static int __init nohpet_setup(char *s) -{ - nohpet = 1; - return 1; -} - -__setup("nohpet", nohpet_setup); diff --git a/arch/x86/kernel/i8253_32.c b/arch/x86/kernel/i8253.c similarity index 100% rename from arch/x86/kernel/i8253_32.c rename to arch/x86/kernel/i8253.c diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index aca081c37884..e0134d6c88da 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c @@ -150,48 +150,6 @@ int update_persistent_clock(struct timespec now) return set_rtc_mmss(now.tv_sec); } -void main_timer_handler(void) -{ -/* - * Here we are in the timer irq handler. We have irqs locally disabled (so we - * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running - * on the other CPU, so we need a lock. We also need to lock the vsyscall - * variables, because both do_timer() and us change them -arca+vojtech - */ - - write_seqlock(&xtime_lock); - -/* - * Do the timer stuff. - */ - - do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - -/* - * In the SMP case we use the local APIC timer interrupt to do the profiling, - * except when we simulate SMP mode on a uniprocessor system, in that case we - * have to call the local interrupt handler. - */ - - if (!using_apic_timer) - smp_local_timer_interrupt(); - - write_sequnlock(&xtime_lock); -} - -static irqreturn_t timer_interrupt(int irq, void *dev_id) -{ - if (apic_runs_main_timer > 1) - return IRQ_HANDLED; - main_timer_handler(); - if (using_apic_timer) - smp_send_timer_broadcast_ipi(); - return IRQ_HANDLED; -} - static irqreturn_t timer_event_interrupt(int irq, void *dev_id) { add_pda(irq0_irqs, 1); diff --git a/include/asm-x86/apic_64.h b/include/asm-x86/apic_64.h index f32f654d1f96..3c8f21eef0be 100644 --- a/include/asm-x86/apic_64.h +++ b/include/asm-x86/apic_64.h @@ -79,8 +79,6 @@ extern void smp_local_timer_interrupt (void); extern void setup_boot_APIC_clock (void); extern void setup_secondary_APIC_clock (void); extern int APIC_init_uniprocessor (void); -extern void disable_APIC_timer(void); -extern void enable_APIC_timer(void); extern void setup_apic_routing(void); extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector, @@ -95,10 +93,6 @@ extern int apic_is_clustered_box(void); #define K8_APIC_EXT_INT_MSG_EXT 0x7 #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD 0 -void smp_send_timer_broadcast_ipi(void); -void switch_APIC_timer_to_ipi(void *cpumask); -void switch_ipi_to_APIC_timer(void *cpumask); - #define ARCH_APICTIMER_STOPS_ON_C3 1 extern unsigned boot_cpu_id; diff --git a/include/asm-x86/proto.h b/include/asm-x86/proto.h index 31f20ad65876..c44a3a93b5a4 100644 --- a/include/asm-x86/proto.h +++ b/include/asm-x86/proto.h @@ -51,9 +51,6 @@ extern void reserve_bootmem_generic(unsigned long phys, unsigned len); extern void load_gs_index(unsigned gs); -extern void stop_timer_interrupt(void); -extern void main_timer_handler(void); - extern unsigned long end_pfn_map; extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp); @@ -90,14 +87,10 @@ extern int timer_over_8254; extern int gsi_irq_sharing(int gsi); -extern void smp_local_timer_interrupt(void); - extern int force_mwait; long do_arch_prctl(struct task_struct *task, int code, unsigned long addr); -void i8254_timer_resume(void); - #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1)) #define round_down(x,y) ((x) & ~((y)-1)) From bc1d99c1de85e826765318738e00e6c4e9a0cd12 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2533/2804] x86_64: cleanup apic.c after clock events switch Make variables static. Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic_64.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 1231365404c4..395928de28ea 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -41,9 +41,8 @@ #include int apic_verbosity; -int apic_calibrate_pmtmr __initdata; - int disable_apic_timer __cpuinitdata; +static int apic_calibrate_pmtmr __initdata; /* Local APIC timer works in C2? */ int local_apic_timer_c2_ok; @@ -247,7 +246,10 @@ void disconnect_bsp_APIC(int virt_wire_setup) apic_write(APIC_SPIV, value); if (!virt_wire_setup) { - /* For LVT0 make it edge triggered, active high, external and enabled */ + /* + * For LVT0 make it edge triggered, active high, + * external and enabled + */ value = apic_read(APIC_LVT0); value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | @@ -483,10 +485,12 @@ void __cpuinit setup_local_APIC (void) value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; if (!smp_processor_id() && !value) { value = APIC_DM_EXTINT; - apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", + smp_processor_id()); } else { value = APIC_DM_EXTINT | APIC_LVT_MASKED; - apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id()); + apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", + smp_processor_id()); } apic_write(APIC_LVT0, value); @@ -793,12 +797,14 @@ void __init init_apic_mappings(void) if (smp_found_config) { ioapic_phys = mp_ioapics[i].mpc_apicaddr; } else { - ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); + ioapic_phys = (unsigned long) + alloc_bootmem_pages(PAGE_SIZE); ioapic_phys = __pa(ioapic_phys); } set_fixmap_nocache(idx, ioapic_phys); - apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n", - __fix_to_virt(idx), ioapic_phys); + apic_printk(APIC_VERBOSE, + "mapped IOAPIC to %016lx (%016lx)\n", + __fix_to_virt(idx), ioapic_phys); idx++; if (ioapic_res != NULL) { From 5b94664a3a2a4f3c516a4a2f454f3c811cb25959 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2534/2804] jiffies: remove unused macros The x86 hpet cleanups allow removal of some unused macros. Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- include/linux/jiffies.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index c080f61fb024..d7a5e034c3a2 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -36,8 +36,6 @@ /* LATCH is used in the interval timer and ftape setup. */ #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ -#define LATCH_HPET ((HPET_TICK_RATE + HZ/2) / HZ) - /* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can * improve accuracy by shifting LSH bits, hence calculating: * (NOM << LSH) / DEN @@ -53,13 +51,9 @@ /* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */ #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8)) -#define ACTHZ_HPET (SH_DIV (HPET_TICK_RATE, LATCH_HPET, 8)) - /* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */ #define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8)) -#define TICK_NSEC_HPET (SH_DIV(1000000UL * 1000, ACTHZ_HPET, 8)) - /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) From 43ca7ec96f01bd921e772112729005d4474fdbf4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2535/2804] ACPI: remove the now unused ifdef code The conversion of x86-64 to clock events makes the #ifdef CONFIG_GENERIC_CLOCKEVENTS n the timer broadcast functions useless. Remove it. Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- drivers/acpi/processor_idle.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 1e8287b4f40c..1f6fb38de017 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -276,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr, static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS unsigned long reason; reason = pr->power.timer_broadcast_on_state < INT_MAX ? CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; clockevents_notify(reason, &pr->id); -#else - cpumask_t mask = cpumask_of_cpu(pr->id); - - if (pr->power.timer_broadcast_on_state < INT_MAX) - on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); - else - on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); -#endif } /* Power(C) State timer broadcast control */ @@ -298,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, int broadcast) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS - int state = cx - pr->power.states; if (state >= pr->power.timer_broadcast_on_state) { @@ -309,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, CLOCK_EVT_NOTIFY_BROADCAST_EXIT; clockevents_notify(reason, &pr->id); } -#endif } #else From 39d0b7ba7b9c0a2c594073400cde1d0beffa0bea Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2536/2804] i386: Remove the useless #ifdef in i8253.h Signed-off-by: Thomas Gleixner Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- include/asm-x86/i8253.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h index 28cf67da59a3..747548ec5d1d 100644 --- a/include/asm-x86/i8253.h +++ b/include/asm-x86/i8253.h @@ -8,12 +8,8 @@ extern spinlock_t i8253_lock; -#ifdef CONFIG_GENERIC_CLOCKEVENTS - extern struct clock_event_device *global_clock_event; extern void setup_pit_timer(void); -#endif - #endif /* __ASM_I8253_H__ */ From 31c435d75e7d15a5f965c5eb0e33fe0e236f49a4 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2537/2804] i386/x8664: cleanup the shared hpet code Remove hpet_readl/writel from vsyscall.h, where it does not belong anyway. Use the hpet code itself. Signed-off-by: Chris Wright Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Arjan van de Ven --- arch/x86/kernel/hpet.c | 6 +----- include/asm-x86/hpet.h | 2 ++ include/asm-x86/vsyscall.h | 3 --- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index dbe0e1d44113..078dbc6d80ec 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -25,11 +25,7 @@ unsigned long hpet_address; static void __iomem *hpet_virt_address; -/* Temporary hack. Cleanup after x86_64 clock events conversion */ -#undef hpet_readl -#undef hpet_writel - -static inline unsigned long hpet_readl(unsigned long a) +unsigned long hpet_readl(unsigned long a) { return readl(hpet_virt_address + a); } diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h index e2976ed30b70..64446a9577dc 100644 --- a/include/asm-x86/hpet.h +++ b/include/asm-x86/hpet.h @@ -65,6 +65,7 @@ extern unsigned long hpet_address; extern int is_hpet_enabled(void); extern int hpet_enable(void); +extern unsigned long hpet_readl(unsigned long a); #ifdef CONFIG_HPET_EMULATE_RTC @@ -84,6 +85,7 @@ extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); #else static inline int hpet_enable(void) { return 0; } +static inline unsigned long hpet_readl(unsigned long a) { return 0; } #endif /* CONFIG_HPET_TIMER */ #endif /* ASM_X86_HPET_H */ diff --git a/include/asm-x86/vsyscall.h b/include/asm-x86/vsyscall.h index 3b8ceb4af2cf..f01c49f5d108 100644 --- a/include/asm-x86/vsyscall.h +++ b/include/asm-x86/vsyscall.h @@ -29,9 +29,6 @@ enum vsyscall_num { #define VGETCPU_RDTSCP 1 #define VGETCPU_LSL 2 -#define hpet_readl(a) readl((const void __iomem *)fix_to_virt(FIX_HPET_BASE) + a) -#define hpet_writel(d,a) writel(d, (void __iomem *)fix_to_virt(FIX_HPET_BASE) + a) - extern int __vgetcpu_mode; extern volatile unsigned long __jiffies; From 4a93232dab0a07074bcc5291a0f1f39919916f31 Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2538/2804] clock events: allow replacement of broadcast timer Change the broadcast timer, if a timer with higher rating becomes available. Signed-off-by: Venkatesh Pallipadi Cc: Andi Kleen Cc: john stultz Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- kernel/time/tick-broadcast.c | 13 ++++++------- kernel/time/tick-common.c | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index acf15b49e55b..298bc7c6f09f 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -64,8 +64,9 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc) */ int tick_check_broadcast_device(struct clock_event_device *dev) { - if (tick_broadcast_device.evtdev || - (dev->features & CLOCK_EVT_FEAT_C3STOP)) + if ((tick_broadcast_device.evtdev && + tick_broadcast_device.evtdev->rating >= dev->rating) || + (dev->features & CLOCK_EVT_FEAT_C3STOP)) return 0; clockevents_exchange_device(NULL, dev); @@ -513,11 +514,9 @@ static void tick_broadcast_clear_oneshot(int cpu) */ void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { - if (bc->mode != CLOCK_EVT_MODE_ONESHOT) { - bc->event_handler = tick_handle_oneshot_broadcast; - clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); - bc->next_event.tv64 = KTIME_MAX; - } + bc->event_handler = tick_handle_oneshot_broadcast; + clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); + bc->next_event.tv64 = KTIME_MAX; } /* diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 77a21abc8716..3f3ae3907830 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -200,7 +200,7 @@ static int tick_check_new_device(struct clock_event_device *newdev) cpu = smp_processor_id(); if (!cpu_isset(cpu, newdev->cpumask)) - goto out; + goto out_bc; td = &per_cpu(tick_cpu_device, cpu); curdev = td->evtdev; @@ -265,7 +265,7 @@ out_bc: */ if (tick_check_broadcast_device(newdev)) ret = NOTIFY_STOP; -out: + spin_unlock_irqrestore(&tick_device_lock, flags); return ret; From 610bf2f143b9c5cda768a2d428d66d3a16769930 Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2539/2804] x86: HPET restructure hpet code for hpet force enable Restructure and rename legacy replacement mode HPET timer support. Just the code structural changes and should be zero functionality change. Signed-off-by: Venkatesh Pallipadi Cc: Andi Kleen Cc: john stultz Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- arch/x86/kernel/hpet.c | 148 +++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 65 deletions(-) diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 078dbc6d80ec..ce3bcc4334d5 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -149,9 +149,9 @@ static void hpet_reserve_platform_timers(unsigned long id) { } */ static unsigned long hpet_period; -static void hpet_set_mode(enum clock_event_mode mode, +static void hpet_legacy_set_mode(enum clock_event_mode mode, struct clock_event_device *evt); -static int hpet_next_event(unsigned long delta, +static int hpet_legacy_next_event(unsigned long delta, struct clock_event_device *evt); /* @@ -160,8 +160,8 @@ static int hpet_next_event(unsigned long delta, static struct clock_event_device hpet_clockevent = { .name = "hpet", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = hpet_set_mode, - .set_next_event = hpet_next_event, + .set_mode = hpet_legacy_set_mode, + .set_next_event = hpet_legacy_next_event, .shift = 32, .irq = 0, }; @@ -178,7 +178,7 @@ static void hpet_start_counter(void) hpet_writel(cfg, HPET_CFG); } -static void hpet_enable_int(void) +static void hpet_enable_legacy_int(void) { unsigned long cfg = hpet_readl(HPET_CFG); @@ -187,7 +187,39 @@ static void hpet_enable_int(void) hpet_legacy_int_enabled = 1; } -static void hpet_set_mode(enum clock_event_mode mode, +static void hpet_legacy_clockevent_register(void) +{ + uint64_t hpet_freq; + + /* Start HPET legacy interrupts */ + hpet_enable_legacy_int(); + + /* + * The period is a femto seconds value. We need to calculate the + * scaled math multiplication factor for nanosecond to hpet tick + * conversion. + */ + hpet_freq = 1000000000000000ULL; + do_div(hpet_freq, hpet_period); + hpet_clockevent.mult = div_sc((unsigned long) hpet_freq, + NSEC_PER_SEC, 32); + /* Calculate the min / max delta */ + hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, + &hpet_clockevent); + hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, + &hpet_clockevent); + + /* + * Start hpet with the boot cpu mask and make it + * global after the IO_APIC has been initialized. + */ + hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); + clockevents_register_device(&hpet_clockevent); + global_clock_event = &hpet_clockevent; + printk(KERN_DEBUG "hpet clockevent registered\n"); +} + +static void hpet_legacy_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { unsigned long cfg, cmp, now; @@ -228,12 +260,12 @@ static void hpet_set_mode(enum clock_event_mode mode, break; case CLOCK_EVT_MODE_RESUME: - hpet_enable_int(); + hpet_enable_legacy_int(); break; } } -static int hpet_next_event(unsigned long delta, +static int hpet_legacy_next_event(unsigned long delta, struct clock_event_device *evt) { unsigned long cnt; @@ -273,58 +305,11 @@ static struct clocksource clocksource_hpet = { #endif }; -/* - * Try to setup the HPET timer - */ -int __init hpet_enable(void) +static int hpet_clocksource_register(void) { - unsigned long id; - uint64_t hpet_freq; u64 tmp, start, now; cycle_t t1; - if (!is_hpet_capable()) - return 0; - - hpet_set_mapping(); - - /* - * Read the period and check for a sane value: - */ - hpet_period = hpet_readl(HPET_PERIOD); - if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) - goto out_nohpet; - - /* - * The period is a femto seconds value. We need to calculate the - * scaled math multiplication factor for nanosecond to hpet tick - * conversion. - */ - hpet_freq = 1000000000000000ULL; - do_div(hpet_freq, hpet_period); - hpet_clockevent.mult = div_sc((unsigned long) hpet_freq, - NSEC_PER_SEC, 32); - /* Calculate the min / max delta */ - hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, - &hpet_clockevent); - hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, - &hpet_clockevent); - - /* - * Read the HPET ID register to retrieve the IRQ routing - * information and the number of channels - */ - id = hpet_readl(HPET_ID); - -#ifdef CONFIG_HPET_EMULATE_RTC - /* - * The legacy routing mode needs at least two channels, tick timer - * and the rtc emulation channel. - */ - if (!(id & HPET_ID_NUMBER)) - goto out_nohpet; -#endif - /* Start the counter */ hpet_start_counter(); @@ -346,7 +331,7 @@ int __init hpet_enable(void) if (t1 == read_hpet()) { printk(KERN_WARNING "HPET counter not counting. HPET disabled\n"); - goto out_nohpet; + return -ENODEV; } /* Initialize and register HPET clocksource @@ -367,15 +352,48 @@ int __init hpet_enable(void) clocksource_register(&clocksource_hpet); + return 0; +} + +/* + * Try to setup the HPET timer + */ +int __init hpet_enable(void) +{ + unsigned long id; + + if (!is_hpet_capable()) + return 0; + + hpet_set_mapping(); + + /* + * Read the period and check for a sane value: + */ + hpet_period = hpet_readl(HPET_PERIOD); + if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) + goto out_nohpet; + + /* + * Read the HPET ID register to retrieve the IRQ routing + * information and the number of channels + */ + id = hpet_readl(HPET_ID); + +#ifdef CONFIG_HPET_EMULATE_RTC + /* + * The legacy routing mode needs at least two channels, tick timer + * and the rtc emulation channel. + */ + if (!(id & HPET_ID_NUMBER)) + goto out_nohpet; +#endif + + if (hpet_clocksource_register()) + goto out_nohpet; + if (id & HPET_ID_LEGSUP) { - hpet_enable_int(); - /* - * Start hpet with the boot cpu mask and make it - * global after the IO_APIC has been initialized. - */ - hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); - clockevents_register_device(&hpet_clockevent); - global_clock_event = &hpet_clockevent; + hpet_legacy_clockevent_register(); return 1; } return 0; From d54bd57d6580250e6551261f3b15c45a9d90c77b Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2540/2804] x86: HPET force enable o ICH7 and later Force detect and/or enable HPET on ICH chipsets. This patch just handles the detection part and following patches use this information. Adds a function to repeat the force enabling during resume time. Using HPET this way, instead of PIT increases the time CPUs can reside in C-state when system is totally idle. On my test system with Core 2 Duo, average C-state residency goes up from ~20mS to ~80mS. [ Build fixed from Andrew Morton ] Signed-off-by: Venkatesh Pallipadi Cc: Andi Kleen Cc: john stultz Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- arch/x86/kernel/quirks.c | 102 +++++++++++++++++++++++++++++++++++++++ include/asm-x86/hpet.h | 1 + 2 files changed, 103 insertions(+) diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 6722469c2633..d3ac703867d6 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -4,6 +4,8 @@ #include #include +#include + #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) @@ -47,3 +49,103 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quir DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); #endif + +#if defined(CONFIG_HPET_TIMER) +unsigned long force_hpet_address; + +static void __iomem *rcba_base; + +void ich_force_hpet_resume(void) +{ + u32 val; + + if (!force_hpet_address) + return; + + if (rcba_base == NULL) + BUG(); + + /* read the Function Disable register, dword mode only */ + val = readl(rcba_base + 0x3404); + if (!(val & 0x80)) { + /* HPET disabled in HPTC. Trying to enable */ + writel(val | 0x80, rcba_base + 0x3404); + } + + val = readl(rcba_base + 0x3404); + if (!(val & 0x80)) + BUG(); + else + printk(KERN_DEBUG "Force enabled HPET at resume\n"); + + return; +} + +static void ich_force_enable_hpet(struct pci_dev *dev) +{ + u32 val; + u32 uninitialized_var(rcba); + int err = 0; + + if (hpet_address || force_hpet_address) + return; + + pci_read_config_dword(dev, 0xF0, &rcba); + rcba &= 0xFFFFC000; + if (rcba == 0) { + printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n"); + return; + } + + /* use bits 31:14, 16 kB aligned */ + rcba_base = ioremap_nocache(rcba, 0x4000); + if (rcba_base == NULL) { + printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n"); + return; + } + + /* read the Function Disable register, dword mode only */ + val = readl(rcba_base + 0x3404); + + if (val & 0x80) { + /* HPET is enabled in HPTC. Just not reported by BIOS */ + val = val & 0x3; + force_hpet_address = 0xFED00000 | (val << 12); + printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", + force_hpet_address); + iounmap(rcba_base); + return; + } + + /* HPET disabled in HPTC. Trying to enable */ + writel(val | 0x80, rcba_base + 0x3404); + + val = readl(rcba_base + 0x3404); + if (!(val & 0x80)) { + err = 1; + } else { + val = val & 0x3; + force_hpet_address = 0xFED00000 | (val << 12); + } + + if (err) { + force_hpet_address = 0; + iounmap(rcba_base); + printk(KERN_DEBUG "Failed to force enable HPET\n"); + } else { + printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", + force_hpet_address); + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, + ich_force_enable_hpet); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, + ich_force_enable_hpet); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, + ich_force_enable_hpet); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, + ich_force_enable_hpet); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, + ich_force_enable_hpet); +#endif diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h index 64446a9577dc..7c933242365f 100644 --- a/include/asm-x86/hpet.h +++ b/include/asm-x86/hpet.h @@ -66,6 +66,7 @@ extern unsigned long hpet_address; extern int is_hpet_enabled(void); extern int hpet_enable(void); extern unsigned long hpet_readl(unsigned long a); +extern void ich_force_hpet_resume(void); #ifdef CONFIG_HPET_EMULATE_RTC From 59c69f2a51b41e9886b85f61c04e8d0d2a35f37b Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: [PATCH 2541/2804] x86: HPET try to activate force detected hpet Enable HPET later during boot, after the force detect in PCI quirks. Also add a call to repeat the force enabling at resume time. Signed-off-by: Venkatesh Pallipadi Cc: Andi Kleen Cc: john stultz Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- arch/x86/kernel/hpet.c | 27 +++++++++++++++++++++++++-- include/asm-x86/hpet.h | 1 + 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index ce3bcc4334d5..a6c68915d2a9 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -164,6 +164,7 @@ static struct clock_event_device hpet_clockevent = { .set_next_event = hpet_legacy_next_event, .shift = 32, .irq = 0, + .rating = 50, }; static void hpet_start_counter(void) @@ -178,6 +179,17 @@ static void hpet_start_counter(void) hpet_writel(cfg, HPET_CFG); } +static void hpet_resume_device(void) +{ + ich_force_hpet_resume(); +} + +static void hpet_restart_counter(void) +{ + hpet_resume_device(); + hpet_start_counter(); +} + static void hpet_enable_legacy_int(void) { unsigned long cfg = hpet_readl(HPET_CFG); @@ -299,7 +311,7 @@ static struct clocksource clocksource_hpet = { .mask = HPET_MASK, .shift = HPET_SHIFT, .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .resume = hpet_start_counter, + .resume = hpet_restart_counter, #ifdef CONFIG_X86_64 .vread = vread_hpet, #endif @@ -412,10 +424,21 @@ out_nohpet: */ static __init int hpet_late_init(void) { - if (!is_hpet_capable()) + if (boot_hpet_disable) return -ENODEV; + if (!hpet_address) { + if (!force_hpet_address) + return -ENODEV; + + hpet_address = force_hpet_address; + hpet_enable(); + if (!hpet_virt_address) + return -ENODEV; + } + hpet_reserve_platform_timers(hpet_readl(HPET_ID)); + return 0; } fs_initcall(hpet_late_init); diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h index 7c933242365f..47de4b8cdda9 100644 --- a/include/asm-x86/hpet.h +++ b/include/asm-x86/hpet.h @@ -63,6 +63,7 @@ /* hpet memory map physical address */ extern unsigned long hpet_address; +extern unsigned long force_hpet_address; extern int is_hpet_enabled(void); extern int hpet_enable(void); extern unsigned long hpet_readl(unsigned long a); From bfe0c1cc6456bba1f4e3cc1fe29c0ea578ac763a Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Fri, 12 Oct 2007 23:04:24 +0200 Subject: [PATCH 2542/2804] x86: HPET force enable for ICH5 force_enable hpet for ICH5. [ Build fixes from Andrew Morton ] Signed-off-by: Venkatesh Pallipadi Cc: Andi Kleen Cc: john stultz Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- arch/x86/kernel/hpet.c | 2 +- arch/x86/kernel/quirks.c | 103 ++++++++++++++++++++++++++++++++++++++- include/asm-x86/hpet.h | 2 +- include/linux/pci_ids.h | 1 + 4 files changed, 105 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index a6c68915d2a9..f8367074da0d 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -181,7 +181,7 @@ static void hpet_start_counter(void) static void hpet_resume_device(void) { - ich_force_hpet_resume(); + force_hpet_resume(); } static void hpet_restart_counter(void) diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index d3ac703867d6..79133b1c2595 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -53,9 +53,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quir #if defined(CONFIG_HPET_TIMER) unsigned long force_hpet_address; +static enum { + NONE_FORCE_HPET_RESUME, + OLD_ICH_FORCE_HPET_RESUME, + ICH_FORCE_HPET_RESUME +} force_hpet_resume_type; + static void __iomem *rcba_base; -void ich_force_hpet_resume(void) +static void ich_force_hpet_resume(void) { u32 val; @@ -133,6 +139,7 @@ static void ich_force_enable_hpet(struct pci_dev *dev) iounmap(rcba_base); printk(KERN_DEBUG "Failed to force enable HPET\n"); } else { + force_hpet_resume_type = ICH_FORCE_HPET_RESUME; printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", force_hpet_address); } @@ -148,4 +155,98 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, ich_force_enable_hpet); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, ich_force_enable_hpet); + + +static struct pci_dev *cached_dev; + +static void old_ich_force_hpet_resume(void) +{ + u32 val; + u32 uninitialized_var(gen_cntl); + + if (!force_hpet_address || !cached_dev) + return; + + pci_read_config_dword(cached_dev, 0xD0, &gen_cntl); + gen_cntl &= (~(0x7 << 15)); + gen_cntl |= (0x4 << 15); + + pci_write_config_dword(cached_dev, 0xD0, gen_cntl); + pci_read_config_dword(cached_dev, 0xD0, &gen_cntl); + val = gen_cntl >> 15; + val &= 0x7; + if (val == 0x4) + printk(KERN_DEBUG "Force enabled HPET at resume\n"); + else + BUG(); +} + +static void old_ich_force_enable_hpet(struct pci_dev *dev) +{ + u32 val; + u32 uninitialized_var(gen_cntl); + + if (hpet_address || force_hpet_address) + return; + + pci_read_config_dword(dev, 0xD0, &gen_cntl); + /* + * Bit 17 is HPET enable bit. + * Bit 16:15 control the HPET base address. + */ + val = gen_cntl >> 15; + val &= 0x7; + if (val & 0x4) { + val &= 0x3; + force_hpet_address = 0xFED00000 | (val << 12); + printk(KERN_DEBUG "HPET at base address 0x%lx\n", + force_hpet_address); + cached_dev = dev; + return; + } + + /* + * HPET is disabled. Trying enabling at FED00000 and check + * whether it sticks + */ + gen_cntl &= (~(0x7 << 15)); + gen_cntl |= (0x4 << 15); + pci_write_config_dword(dev, 0xD0, gen_cntl); + + pci_read_config_dword(dev, 0xD0, &gen_cntl); + + val = gen_cntl >> 15; + val &= 0x7; + if (val & 0x4) { + /* HPET is enabled in HPTC. Just not reported by BIOS */ + val &= 0x3; + force_hpet_address = 0xFED00000 | (val << 12); + printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", + force_hpet_address); + force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME; + return; + } + + printk(KERN_DEBUG "Failed to force enable HPET\n"); +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, + old_ich_force_enable_hpet); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12, + old_ich_force_enable_hpet); + +void force_hpet_resume(void) +{ + switch (force_hpet_resume_type) { + case ICH_FORCE_HPET_RESUME: + return ich_force_hpet_resume(); + + case OLD_ICH_FORCE_HPET_RESUME: + return old_ich_force_hpet_resume(); + + default: + break; + } +} + #endif diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h index 47de4b8cdda9..d4ab6db050b6 100644 --- a/include/asm-x86/hpet.h +++ b/include/asm-x86/hpet.h @@ -67,7 +67,7 @@ extern unsigned long force_hpet_address; extern int is_hpet_enabled(void); extern int hpet_enable(void); extern unsigned long hpet_readl(unsigned long a); -extern void ich_force_hpet_resume(void); +extern void force_hpet_resume(void); #ifdef CONFIG_HPET_EMULATE_RTC diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3948708c42ca..584741bb73b3 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2242,6 +2242,7 @@ #define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5 #define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6 #define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db +#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc #define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd #define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1 #define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2 From 32a2da64c26d3c886c35f60299259a3497ff96bb Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Fri, 12 Oct 2007 23:04:24 +0200 Subject: [PATCH 2543/2804] x86: HPET force enable ICH5 suspend/resume fix A bugfix in ich5 hpet force detect which caused resumes to fail. Thanks to Udo A Steinberg for reporting the problem. Signed-off-by: Venkatesh Pallipadi Cc: Andi Kleen Cc: john stultz Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Thomas Gleixner --- arch/x86/kernel/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 79133b1c2595..44e36c59cbde 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -201,7 +201,6 @@ static void old_ich_force_enable_hpet(struct pci_dev *dev) force_hpet_address = 0xFED00000 | (val << 12); printk(KERN_DEBUG "HPET at base address 0x%lx\n", force_hpet_address); - cached_dev = dev; return; } @@ -223,6 +222,7 @@ static void old_ich_force_enable_hpet(struct pci_dev *dev) force_hpet_address = 0xFED00000 | (val << 12); printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", force_hpet_address); + cached_dev = dev; force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME; return; } From ed6fb174eea8869e88d8bc506a55f3ef76fcb7ed Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Fri, 12 Oct 2007 23:04:24 +0200 Subject: [PATCH 2544/2804] x86: HPET add another ICH7 PCI id Add another PCI ID for ICH7 force hpet. Signed-off-by: Venkatesh Pallipadi Cc: Andi Kleen Cc: john stultz Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Arjan van de Ven --- arch/x86/kernel/quirks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 44e36c59cbde..d769e204f942 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -149,6 +149,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, ich_force_enable_hpet); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, ich_force_enable_hpet); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, + ich_force_enable_hpet); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, ich_force_enable_hpet); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, From 43cc71eed1250755986da4c0f9898f9a635cb3bf Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 18 Aug 2007 04:40:39 +0200 Subject: [PATCH 2545/2804] platform: prefix MODALIAS with "platform:" Prefix platform modalias strings with "platform:", which modprobe config to blacklist alias resolving if userspace configures it. Send uevents for all platform devices. Add MODULE_ALIAS's to: pxa2xx_pcmcia, ds1742 and pcspkr to trigger module autoloading by userspace. $ modinfo pcspkr alias: platform:pcspkr license: GPL description: PC Speaker beeper driver ... $ modprobe -n -v platform:pcspkr insmod /lib/modules/2.6.23-rc3-g28e8351a-dirty/kernel/drivers/input/misc/pcspkr.ko Signed-off-by: Kay Sievers Cc: David Brownell Cc: Atsushi Nemoto Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 15 ++------------- drivers/input/misc/pcspkr.c | 1 + drivers/pcmcia/pxa2xx_mainstone.c | 2 +- drivers/pcmcia/pxa2xx_sharpsl.c | 2 +- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 869ff8c00146..9bfc434d1327 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -160,11 +160,6 @@ static void platform_device_release(struct device *dev) * * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. - * - * This device will be marked as not supporting hotpluggable drivers; no - * device add/remove uevents will be generated. In the unusual case that - * the device isn't being dynamically allocated as a legacy "probe the - * hardware" driver, infrastructure code should reverse this marking. */ struct platform_device *platform_device_alloc(const char *name, unsigned int id) { @@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id) pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; - - /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in - * legacy probe-the-hardware drivers, which don't properly split - * out device enumeration logic from drivers. - */ - pa->pdev.dev.uevent_suppress = 1; } return pa ? &pa->pdev : NULL; @@ -530,7 +519,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { struct platform_device *pdev = to_platform_device(dev); - int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name); + int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -546,7 +535,7 @@ static int platform_uevent(struct device *dev, char **envp, int num_envp, struct platform_device *pdev = to_platform_device(dev); envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name); + snprintf(buffer, buffer_size, "MODALIAS=platform:%s", pdev->name); return 0; } diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 906bf5e8de89..e1a44020ed2b 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -23,6 +23,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcspkr"); #ifdef CONFIG_X86 /* Use the global PIT lock ! */ diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 383107ba4bd3..f6722ba0dd1e 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -175,7 +175,6 @@ static int __init mst_pcmcia_init(void) if (!mst_pcmcia_device) return -ENOMEM; - mst_pcmcia_device->dev.uevent_suppress = 0; mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; ret = platform_device_add(mst_pcmcia_device); @@ -195,3 +194,4 @@ fs_initcall(mst_pcmcia_init); module_exit(mst_pcmcia_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index a2daa3f531b2..d5c33bd78d68 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void) if (!sharpsl_pcmcia_device) return -ENOMEM; - sharpsl_pcmcia_device->dev.uevent_suppress = 0; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev; @@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit); MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); From 3b6662f192fc521b9657f63e68d20ec99979dae6 Mon Sep 17 00:00:00 2001 From: Tsugikazu Shibata Date: Tue, 25 Sep 2007 01:54:26 +0900 Subject: [PATCH 2546/2804] HOWTO: update ja_JP/HOWTO with latest changes Here is another sync patch of Documentation/ja_JP/HOWTO Japanese developer sent me some cosmetic changes and also follow changes of HOWTO Cross reference URL (sosdg.org/qiyong/lxr) known_regression explanations on kernel dev. process Signed-off-by: Tsugikazu Shibata Cc: stable Signed-off-by: Greg Kroah-Hartman --- Documentation/ja_JP/HOWTO | 84 +++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO index 9f08dab1e75b..d9d832c010ef 100644 --- a/Documentation/ja_JP/HOWTO +++ b/Documentation/ja_JP/HOWTO @@ -1,4 +1,4 @@ -๏ปฟNOTE: +NOTE: This is a version of Documentation/HOWTO translated into Japanese. This document is maintained by Tsugikazu Shibata and the JF Project team . @@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a fork. So if you have any comments or updates for this file, please try to update the original English file first. -Last Updated: 2007/07/18 +Last Updated: 2007/09/23 ================================== ใ“ใ‚Œใฏใ€ -linux-2.6.22/Documentation/HOWTO +linux-2.6.23/Documentation/HOWTO ใฎๅ’Œ่จณใงใ™ใ€‚ ็ฟป่จณๅ›ฃไฝ“๏ผš JF ใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆ < http://www.linux.or.jp/JF/ > -็ฟป่จณๆ—ฅ๏ผš 2007/07/16 +็ฟป่จณๆ—ฅ๏ผš 2007/09/19 ็ฟป่จณ่€…๏ผš Tsugikazu Shibata ๆ กๆญฃ่€…๏ผš ๆพๅ€‰ใ•ใ‚“ ๅฐๆž— ้›…ๅ…ธใ•ใ‚“ (Masanori Kobayasi) @@ -27,6 +27,7 @@ linux-2.6.22/Documentation/HOWTO ้‡Žๅฃใ•ใ‚“ (Kenji Noguchi) ๆฒณๅ†…ใ•ใ‚“ (Takayoshi Kochi) ๅฒฉๆœฌใ•ใ‚“ (iwamoto) + ๅ†…็”ฐใ•ใ‚“ (Satoshi Uchida) ================================== Linux ใ‚ซใƒผใƒใƒซ้–‹็™บใฎใ‚„ใ‚Šๆ–น @@ -40,7 +41,7 @@ Linux ใ‚ซใƒผใƒใƒซ้–‹็™บใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใจๅ…ฑใซๆดปๅ‹•ใ™ใ‚‹ใ‚„ใ‚Šๆ–นใ‚’ๅญฆ ๆ‰‹ๅŠฉใ‘ใซใชใ‚Šใพใ™ใ€‚ ใ‚‚ใ—ใ€ใ“ใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใฎใฉใ“ใ‹ใŒๅคใใชใฃใฆใ„ใŸๅ ดๅˆใซใฏใ€ใ“ใฎใƒ‰ใ‚ญใƒฅใƒกใƒณ -ใƒˆใฎๆœ€ๅพŒใซใƒชใ‚นใƒˆใ—ใŸใƒกใƒณใƒ†ใƒŠใƒผใซใƒ‘ใƒƒใƒใ‚’้€ใฃใฆใใ ใ•ใ„ใ€‚ +ใƒˆใฎๆœ€ๅพŒใซใƒชใ‚นใƒˆใ—ใŸใƒกใƒณใƒ†ใƒŠใซใƒ‘ใƒƒใƒใ‚’้€ใฃใฆใใ ใ•ใ„ใ€‚ ใฏใ˜ใ‚ใซ --------- @@ -59,7 +60,7 @@ Linux ใ‚ซใƒผใƒใƒซ้–‹็™บใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใจๅ…ฑใซๆดปๅ‹•ใ™ใ‚‹ใ‚„ใ‚Šๆ–นใ‚’ๅญฆ ใƒใƒซ้–‹็™บ่€…ใซใฏๅฟ…่ฆใงใ™ใ€‚ใ‚ขใƒผใ‚ญใƒ†ใ‚ฏใƒใƒฃๅ‘ใ‘ใฎไฝŽใƒฌใƒ™ใƒซ้ƒจๅˆ†ใฎ้–‹็™บใ‚’ใ™ใ‚‹ใฎ ใงใชใ‘ใ‚Œใฐใ€(ใฉใ‚“ใชใ‚ขใƒผใ‚ญใƒ†ใ‚ฏใƒใƒฃใงใ‚‚)ใ‚ขใ‚ปใƒณใƒ–ใƒช(่จณๆณจ: ่จ€่ชž)ใฏๅฟ…่ฆใ‚ใ‚Š ใพใ›ใ‚“ใ€‚ไปฅไธ‹ใฎๆœฌใฏใ€C ่จ€่ชžใฎๅๅˆ†ใช็Ÿฅ่ญ˜ใ‚„ไฝ•ๅนดใ‚‚ใฎ็ตŒ้จ“ใซๅ–ใฃใฆไปฃใ‚ใ‚‹ใ‚‚ใฎ -ใงใฏใ‚ใ‚Šใพใ›ใ‚“ใŒใ€ๅฐ‘ใชใใจใ‚‚ใƒชใƒ•ใ‚กใƒฌใƒณใ‚นใจใ—ใฆใฏใ„ใ„ๆœฌใงใ™ใ€‚ +ใงใฏใ‚ใ‚Šใพใ›ใ‚“ใŒใ€ๅฐ‘ใชใใจใ‚‚ใƒชใƒ•ใ‚กใƒฌใƒณใ‚นใจใ—ใฆใฏ่‰ฏใ„ๆœฌใงใ™ใ€‚ - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall] -ใ€Žใƒ—ใƒญใ‚ฐใƒฉใƒŸใƒณใ‚ฐ่จ€่ชž๏ผฃ็ฌฌ2็‰ˆใ€(B.W. ใ‚ซใƒผใƒ‹ใƒใƒณ/D.M. ใƒชใƒƒใƒใƒผ่‘— ็Ÿณ็”ฐๆ™ดไน…่จณ) [ๅ…ฑ็ซ‹ๅ‡บ็‰ˆ] - "Practical C Programming" by Steve Oualline [O'Reilly] @@ -76,7 +77,7 @@ Linux ใ‚ซใƒผใƒใƒซ้–‹็™บใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใจๅ…ฑใซๆดปๅ‹•ใ™ใ‚‹ใ‚„ใ‚Šๆ–นใ‚’ๅญฆ ใจใใฉใใ€ใ‚ซใƒผใƒใƒซใŒใƒ„ใƒผใƒซใƒใ‚งใ‚คใƒณใ‚„ C ่จ€่ชžๆ‹กๅผตใซ็ฝฎใ„ใฆใ„ใ‚‹ๅ‰ๆใŒใฉใ† ใชใฃใฆใ„ใ‚‹ใฎใ‹ใ‚ใ‹ใ‚Šใซใใ„ใ“ใจใŒใ‚ใ‚Šใ€ใพใŸใ€ๆฎ‹ๅฟตใชใ“ใจใซๆฑบๅฎš็š„ใชใƒชใƒ•ใ‚ก ใƒฌใƒณใ‚นใฏๅญ˜ๅœจใ—ใพใ›ใ‚“ใ€‚ๆƒ…ๅ ฑใ‚’ๅพ—ใ‚‹ใซใฏใ€gcc ใฎ info ใƒšใƒผใ‚ธ( info gcc )ใ‚’ -ใฟใฆใใ ใ•ใ„ใ€‚ +่ฆ‹ใฆใใ ใ•ใ„ใ€‚ ใ‚ใชใŸใฏๆ—ขๅญ˜ใฎ้–‹็™บใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใจไธ€็ท’ใซไฝœๆฅญใ™ใ‚‹ๆ–นๆณ•ใ‚’ๅญฆใผใ†ใจใ—ใฆใ„ใ‚‹ใ“ ใจใซ็•™ๆ„ใ—ใฆใใ ใ•ใ„ใ€‚ใใฎใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใฏใ€ใ‚ณใƒผใƒ‡ใ‚ฃใƒณใ‚ฐใ€ใ‚นใ‚ฟใ‚คใƒซใ€ @@ -92,7 +93,7 @@ Linux ใ‚ซใƒผใƒใƒซ้–‹็™บใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใจๅ…ฑใซๆดปๅ‹•ใ™ใ‚‹ใ‚„ใ‚Šๆ–นใ‚’ๅญฆ Linux ใ‚ซใƒผใƒใƒซใฎใ‚ฝใƒผใ‚นใ‚ณใƒผใƒ‰ใฏ GPL ใƒฉใ‚คใ‚ปใƒณใ‚นใฎไธ‹ใงใƒชใƒชใƒผใ‚นใ•ใ‚Œใฆใ„ใพ ใ™ใ€‚ใƒฉใ‚คใ‚ปใƒณใ‚นใฎ่ฉณ็ดฐใซใคใ„ใฆใฏใ€ใ‚ฝใƒผใ‚นใƒ„ใƒชใƒผใฎใƒกใ‚คใƒณใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒชใซๅญ˜ๅœจ -ใ™ใ‚‹ใ€COPYING ใฎใƒ•ใ‚กใ‚คใƒซใ‚’ใฟใฆใใ ใ•ใ„ใ€‚ใ‚‚ใ—ใƒฉใ‚คใ‚ปใƒณใ‚นใซใคใ„ใฆใ•ใ‚‰ใซ่ณช +ใ™ใ‚‹ใ€COPYING ใฎใƒ•ใ‚กใ‚คใƒซใ‚’่ฆ‹ใฆใใ ใ•ใ„ใ€‚ใ‚‚ใ—ใƒฉใ‚คใ‚ปใƒณใ‚นใซใคใ„ใฆใ•ใ‚‰ใซ่ณช ๅ•ใŒใ‚ใ‚Œใฐใ€Linux Kernel ใƒกใƒผใƒชใƒณใ‚ฐใƒชใ‚นใƒˆใซ่ณชๅ•ใ™ใ‚‹ใฎใงใฏใชใใ€ใฉใ†ใž ๆณ•ๅพ‹ๅฎถใซ็›ธ่ซ‡ใ—ใฆใใ ใ•ใ„ใ€‚ใƒกใƒผใƒชใƒณใ‚ฐใƒชใ‚นใƒˆใฎไบบ้”ใฏๆณ•ๅพ‹ๅฎถใงใฏใชใใ€ๆณ•็š„ ๅ•้กŒใซใคใ„ใฆใฏๅฝผใ‚‰ใฎๅฃฐๆ˜Žใฏใ‚ใฆใซใ™ใ‚‹ในใใงใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ @@ -109,7 +110,8 @@ Linux ใ‚ซใƒผใƒใƒซใ‚ฝใƒผใ‚นใƒ„ใƒชใƒผใฏๅน…ๅบƒใ„็ฏ„ๅ›ฒใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚’ ๆ–ฐใ—ใ„ใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใƒ•ใ‚กใ‚คใƒซใ‚‚่ฟฝๅŠ ใ™ใ‚‹ใ“ใจใ‚’ๅ‹งใ‚ใพใ™ใ€‚ ใ‚ซใƒผใƒใƒซใฎๅค‰ๆ›ดใŒใ€ใ‚ซใƒผใƒใƒซใŒใƒฆใƒผใ‚ถ็ฉบ้–“ใซๅ…ฌ้–‹ใ—ใฆใ„ใ‚‹ใ‚คใƒณใ‚ฟใƒผใƒ•ใ‚งใ‚คใ‚นใฎ ๅค‰ๆ›ดใ‚’ๅผ•ใ่ตทใ“ใ™ๅ ดๅˆใ€ใใฎๅค‰ๆ›ดใ‚’่ชฌๆ˜Žใ™ใ‚‹ใƒžใƒ‹ใƒฅใ‚ขใƒซใƒšใƒผใ‚ธใฎใƒ‘ใƒƒใƒใ‚„ๆƒ…ๅ ฑ -ใ‚’ใƒžใƒ‹ใƒฅใ‚ขใƒซใƒšใƒผใ‚ธใฎใƒกใƒณใƒ†ใƒŠ mtk-manpages@gmx.net ใซ้€ใ‚‹ใ“ใจใ‚’ๅ‹งใ‚ใพใ™ใ€‚ +ใ‚’ใƒžใƒ‹ใƒฅใ‚ขใƒซใƒšใƒผใ‚ธใฎใƒกใƒณใƒ†ใƒŠ mtk-manpages@gmx.net ใซ้€ใ‚‹ใ“ใจใ‚’ๅ‹งใ‚ใพ +ใ™ใ€‚ ไปฅไธ‹ใฏใ‚ซใƒผใƒใƒซใ‚ฝใƒผใ‚นใƒ„ใƒชใƒผใซๅซใพใ‚Œใฆใ„ใ‚‹่ชญใ‚“ใงใŠใในใใƒ•ใ‚กใ‚คใƒซใฎไธ€่ฆงใง ใ™- @@ -117,7 +119,7 @@ Linux ใ‚ซใƒผใƒใƒซใ‚ฝใƒผใ‚นใƒ„ใƒชใƒผใฏๅน…ๅบƒใ„็ฏ„ๅ›ฒใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚’ README ใ“ใฎใƒ•ใ‚กใ‚คใƒซใฏ Linuxใ‚ซใƒผใƒใƒซใฎ็ฐกๅ˜ใช่ƒŒๆ™ฏใจใ‚ซใƒผใƒใƒซใ‚’่จญๅฎš(่จณๆณจ configure )ใ—ใ€็”Ÿๆˆ(่จณๆณจ build )ใ™ใ‚‹ใŸใ‚ใซๅฟ…่ฆใชใ“ใจใฏไฝ•ใ‹ใŒๆ›ธใ‹ใ‚Œ - ใฆใ„ใพใ™ใ€‚ใ‚ซใƒผใƒใƒซใซ้–ขใ—ใฆๅˆใ‚ใฆใฎไบบใฏใ“ใ“ใ‹ใ‚‰ใ‚นใ‚ฟใƒผใƒˆใ™ใ‚‹ใจใ‚ˆใ„ใง + ใฆใ„ใพใ™ใ€‚ใ‚ซใƒผใƒใƒซใซ้–ขใ—ใฆๅˆใ‚ใฆใฎไบบใฏใ“ใ“ใ‹ใ‚‰ใ‚นใ‚ฟใƒผใƒˆใ™ใ‚‹ใจ่‰ฏใ„ใง ใ—ใ‚‡ใ†ใ€‚ Documentation/Changes @@ -128,7 +130,7 @@ Linux ใ‚ซใƒผใƒใƒซใ‚ฝใƒผใ‚นใƒ„ใƒชใƒผใฏๅน…ๅบƒใ„็ฏ„ๅ›ฒใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚’ Documentation/CodingStyle ใ“ใ‚Œใฏ Linux ใ‚ซใƒผใƒใƒซใฎใ‚ณใƒผใƒ‡ใ‚ฃใƒณใ‚ฐใ‚นใ‚ฟใ‚คใƒซใจ่ƒŒๆ™ฏใซใ‚ใ‚‹็†็”ฑใ‚’่จ˜่ฟฐ ใ—ใฆใ„ใพใ™ใ€‚ๅ…จใฆใฎๆ–ฐใ—ใ„ใ‚ณใƒผใƒ‰ใฏใ“ใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใซใ‚ใ‚‹ใ‚ฌใ‚คใƒ‰ใƒฉใ‚คใƒณ - ใซๅพ“ใฃใฆใ„ใ‚‹ใ“ใจใ‚’ๆœŸๅพ…ใ•ใ‚Œใฆใ„ใพใ™ใ€‚ๅคง้ƒจๅˆ†ใฎใƒกใƒณใƒ†ใƒŠใƒผใฏใ“ใ‚Œใ‚‰ใฎใƒซใƒผ + ใซๅพ“ใฃใฆใ„ใ‚‹ใ“ใจใ‚’ๆœŸๅพ…ใ•ใ‚Œใฆใ„ใพใ™ใ€‚ๅคง้ƒจๅˆ†ใฎใƒกใƒณใƒ†ใƒŠใฏใ“ใ‚Œใ‚‰ใฎใƒซใƒผ ใƒซใซๅพ“ใฃใฆใ„ใ‚‹ใ‚‚ใฎใ ใ‘ใ‚’ๅ—ใ‘ไป˜ใ‘ใ€ๅคšใใฎไบบใฏๆญฃใ—ใ„ใ‚นใ‚ฟใ‚คใƒซใฎใ‚ณใƒผใƒ‰ ใ ใ‘ใ‚’ใƒฌใƒ“ใƒฅใƒผใ—ใพใ™ใ€‚ @@ -168,16 +170,16 @@ Linux ใ‚ซใƒผใƒใƒซใ‚ฝใƒผใ‚นใƒ„ใƒชใƒผใฏๅน…ๅบƒใ„็ฏ„ๅ›ฒใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚’ ๆ”ฏๆดใ—ใฆใใ ใ•ใ„ใ€‚ Documentation/ManagementStyle - ใ“ใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใฏ Linux ใ‚ซใƒผใƒใƒซใฎใƒกใƒณใƒ†ใƒŠใƒผ้”ใŒใฉใ†่กŒๅ‹•ใ™ใ‚‹ใ‹ใ€ + ใ“ใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใฏ Linux ใ‚ซใƒผใƒใƒซใฎใƒกใƒณใƒ†ใƒŠ้”ใŒใฉใ†่กŒๅ‹•ใ™ใ‚‹ใ‹ใ€ ๅฝผใ‚‰ใฎๆ‰‹ๆณ•ใฎ่ƒŒๆ™ฏใซใ‚ใ‚‹ๅ…ฑๆœ‰ใ•ใ‚Œใฆใ„ใ‚‹็ฒพ็ฅžใซใคใ„ใฆ่จ˜่ฟฐใ—ใฆใ„ใพใ™ใ€‚ใ“ ใ‚Œใฏใ‚ซใƒผใƒใƒซ้–‹็™บใฎๅˆๅฟƒ่€…ใชใ‚‰๏ผˆใ‚‚ใ—ใใฏใ€ๅ˜ใซ่ˆˆๅ‘ณใŒใ‚ใ‚‹ใ ใ‘ใฎไบบใงใ‚‚๏ผ‰ - ้‡่ฆใงใ™ใ€‚ใชใœใชใ‚‰ใ“ใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใฏใ€ใ‚ซใƒผใƒใƒซใƒกใƒณใƒ†ใƒŠใƒผ้”ใฎ็‹ฌ็‰นใช + ้‡่ฆใงใ™ใ€‚ใชใœใชใ‚‰ใ“ใฎใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใฏใ€ใ‚ซใƒผใƒใƒซใƒกใƒณใƒ†ใƒŠ้”ใฎ็‹ฌ็‰นใช ่กŒๅ‹•ใซใคใ„ใฆใฎๅคšใใฎ่ชค่งฃใ‚„ๆททไนฑใ‚’่งฃๆถˆใ™ใ‚‹ใ‹ใ‚‰ใงใ™ใ€‚ Documentation/stable_kernel_rules.txt ใ“ใฎใƒ•ใ‚กใ‚คใƒซใฏใฉใฎใ‚ˆใ†ใซ stable ใ‚ซใƒผใƒใƒซใฎใƒชใƒชใƒผใ‚นใŒ่กŒใ‚ใ‚Œใ‚‹ใ‹ใฎใƒซใƒผ ใƒซใŒ่จ˜่ฟฐใ•ใ‚Œใฆใ„ใพใ™ใ€‚ใใ—ใฆใ“ใ‚Œใ‚‰ใฎใƒชใƒชใƒผใ‚นใฎไธญใฎใฉใ“ใ‹ใงๅค‰ๆ›ดใ‚’ๅ– - ใ‚Šๅ…ฅใ‚Œใฆใ‚‚ใ‚‰ใ„ใŸใ„ๅ ดๅˆใซไฝ•ใ‚’ใ™ใ‚Œใฐใ„ใ„ใ‹ใŒ็คบใ•ใ‚Œใฆใ„ใพใ™ใ€‚ + ใ‚Šๅ…ฅใ‚Œใฆใ‚‚ใ‚‰ใ„ใŸใ„ๅ ดๅˆใซไฝ•ใ‚’ใ™ใ‚Œใฐ่‰ฏใ„ใ‹ใŒ็คบใ•ใ‚Œใฆใ„ใพใ™ใ€‚ Documentation/kernel-docs.txt ใ€€ใ€€ใ‚ซใƒผใƒใƒซ้–‹็™บใซไป˜้šใ™ใ‚‹ๅค–้ƒจใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใฎใƒชใ‚นใƒˆใงใ™ใ€‚ใ‚‚ใ—ใ‚ใชใŸใŒ @@ -218,9 +220,9 @@ web ใ‚ตใ‚คใƒˆใซใฏใ€ใ‚ณใƒผใƒ‰ใฎๆง‹ๆˆใ€ใ‚ตใƒ–ใ‚ทใ‚นใƒ†ใƒ ใ€็พๅœจๅญ˜ๅœจใ™ ใ“ใ“ใซใฏใ€ใพใŸใ€ใ‚ซใƒผใƒใƒซใฎใ‚ณใƒณใƒ‘ใ‚คใƒซใฎใ‚„ใ‚Šๆ–นใ‚„ใƒ‘ใƒƒใƒใฎๅฝ“ใฆๆ–นใชใฉใฎ้–“ๆŽฅ ็š„ใชๅŸบๆœฌๆƒ…ๅ ฑใ‚‚่จ˜่ฟฐใ•ใ‚Œใฆใ„ใพใ™ใ€‚ -ใ‚ใชใŸใŒใฉใ“ใ‹ใ‚‰ใ‚นใ‚ฟใƒผใƒˆใ—ใฆใ‚ˆใ„ใ‹ใ‚ใ‹ใ‚‰ใชใ„ใŒใ€Linux ใ‚ซใƒผใƒใƒซ้–‹็™บใ‚ณใƒŸใƒฅ +ใ‚ใชใŸใŒใฉใ“ใ‹ใ‚‰ใ‚นใ‚ฟใƒผใƒˆใ—ใฆ่‰ฏใ„ใ‹ใ‚ใ‹ใ‚‰ใชใ„ใŒใ€Linux ใ‚ซใƒผใƒใƒซ้–‹็™บใ‚ณใƒŸใƒฅ ใƒ‹ใƒ†ใ‚ฃใซๅ‚ๅŠ ใ—ใฆไฝ•ใ‹ใ™ใ‚‹ใ“ใจใ‚’ใ•ใŒใ—ใฆใ„ใ‚‹ๅ ดๅˆใซใฏใ€Linux kernel -Janitor's ใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆใซใ„ใ‘ใฐใ‚ˆใ„ใงใ—ใ‚‡ใ† - +Janitor's ใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆใซใ„ใ‘ใฐ่‰ฏใ„ใงใ—ใ‚‡ใ† - http://janitor.kernelnewbies.org/ ใ“ใ“ใฏใใฎใ‚ˆใ†ใชใ‚นใ‚ฟใƒผใƒˆใ‚’ใ™ใ‚‹ใฎใซใ†ใฃใฆใคใ‘ใฎๅ ดๆ‰€ใงใ™ใ€‚ใ“ใ“ใซใฏใ€ Linux ใ‚ซใƒผใƒใƒซใ‚ฝใƒผใ‚นใƒ„ใƒชใƒผใฎไธญใซๅซใพใ‚Œใ‚‹ใ€ใใ‚Œใ„ใซใ—ใ€ไฟฎๆญฃใ—ใชใ‘ใ‚Œใฐใช @@ -243,7 +245,7 @@ Linux ใ‚ซใƒผใƒใƒซใ‚ฝใƒผใ‚นใƒ„ใƒชใƒผใฎไธญใซๅซใพใ‚Œใ‚‹ใ€ใใ‚Œใ„ใซใ—ใ€ ่‡ชๅทฑๅ‚็…งๆ–นๅผใงใ€็ดขๅผ•ใŒใคใ„ใŸ web ๅฝขๅผใงใ€ใ‚ฝใƒผใ‚นใ‚ณใƒผใƒ‰ใ‚’ๅ‚็…งใ™ใ‚‹ใ“ใจใŒ ใงใใพใ™ใ€‚ใ“ใฎๆœ€ๆ–ฐใฎ็ด ๆ™ดใ—ใ„ใ‚ซใƒผใƒใƒซใ‚ณใƒผใƒ‰ใฎใƒชใƒใ‚ธใƒˆใƒชใฏไปฅไธ‹ใง่ฆ‹ใคใ‹ใ‚Š ใพใ™- - http://sosdg.org/~coywolf/lxr/ + http://sosdg.org/~qiyong/lxr/ ้–‹็™บใƒ—ใƒญใ‚ปใ‚น ----------------------- @@ -265,9 +267,9 @@ Linux ใ‚ซใƒผใƒใƒซใฎ้–‹็™บใƒ—ใƒญใ‚ปใ‚นใฏ็พๅœจๅนพใคใ‹ใฎ็•ฐใชใ‚‹ใƒกใ‚คใƒณ ไปฅไธ‹ใฎใจใŠใ‚Š- - ๆ–ฐใ—ใ„ใ‚ซใƒผใƒใƒซใŒใƒชใƒชใƒผใ‚นใ•ใ‚ŒใŸ็›ดๅพŒใซใ€2้€ฑ้–“ใฎ็‰นๅˆฅๆœŸ้–“ใŒ่จญใ‘ใ‚‰ใ‚Œใ€ - ใ“ใฎๆœŸ้–“ไธญใซใ€ใƒกใƒณใƒ†ใƒŠใƒผ้”ใฏ Linus ใซๅคงใใชๅทฎๅˆ†ใ‚’้€ใ‚‹ใ“ใจใŒใงใใพ - ใ™ใ€‚ใ“ใฎใ‚ˆใ†ใชๅทฎๅˆ†ใฏ้€šๅธธ -mm ใ‚ซใƒผใƒใƒซใซๆ•ฐ้€ฑ้–“ๅซใพใ‚ŒใฆใใŸใƒ‘ใƒƒใƒใง - ใ™ใ€‚ ๅคงใใชๅค‰ๆ›ดใฏ git(ใ‚ซใƒผใƒใƒซใฎใ‚ฝใƒผใ‚น็ฎก็†ใƒ„ใƒผใƒซใ€่ฉณ็ดฐใฏ + ใ“ใฎๆœŸ้–“ไธญใซใ€ใƒกใƒณใƒ†ใƒŠ้”ใฏ Linus ใซๅคงใใชๅทฎๅˆ†ใ‚’้€ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ + ใ“ใฎใ‚ˆใ†ใชๅทฎๅˆ†ใฏ้€šๅธธ -mm ใ‚ซใƒผใƒใƒซใซๆ•ฐ้€ฑ้–“ๅซใพใ‚ŒใฆใใŸใƒ‘ใƒƒใƒใงใ™ใ€‚ + ๅคงใใชๅค‰ๆ›ดใฏ git(ใ‚ซใƒผใƒใƒซใฎใ‚ฝใƒผใ‚น็ฎก็†ใƒ„ใƒผใƒซใ€่ฉณ็ดฐใฏ http://git.or.cz/ ๅ‚็…ง) ใ‚’ไฝฟใฃใฆ้€ใ‚‹ใฎใŒๅฅฝใพใ—ใ„ใ‚„ใ‚Šๆ–นใงใ™ใŒใ€ใƒ‘ใƒƒ ใƒใƒ•ใ‚กใ‚คใƒซใฎๅฝขๅผใฎใพใพ้€ใ‚‹ใฎใงใ‚‚ๅๅˆ†ใงใ™ใ€‚ @@ -285,6 +287,10 @@ Linux ใ‚ซใƒผใƒใƒซใฎ้–‹็™บใƒ—ใƒญใ‚ปใ‚นใฏ็พๅœจๅนพใคใ‹ใฎ็•ฐใชใ‚‹ใƒกใ‚คใƒณ ใซๅฎ‰ๅฎšใ—ใŸ็Šถๆ…‹ใซใ‚ใ‚‹ใจๅˆคๆ–ญใ—ใŸใจใใซใƒชใƒชใƒผใ‚นใ•ใ‚Œใพใ™ใ€‚็›ฎๆจ™ใฏๆฏŽ้€ฑๆ–ฐ ใ—ใ„ -rc ใ‚ซใƒผใƒใƒซใ‚’ใƒชใƒชใƒผใ‚นใ™ใ‚‹ใ“ใจใงใ™ใ€‚ + - ไปฅไธ‹ใฎ URL ใงๅ„ -rc ใƒชใƒชใƒผใ‚นใซๅญ˜ๅœจใ™ใ‚‹ๆ—ข็ŸฅใฎๅพŒๆˆปใ‚Šๅ•้กŒใฎใƒชใ‚นใƒˆ + ใŒ่ฟฝ่ทกใ•ใ‚Œใพใ™- + http://kernelnewbies.org/known_regressions + - ใ“ใฎใƒ—ใƒญใ‚ปใ‚นใฏใ‚ซใƒผใƒใƒซใŒ ใ€Œๆบ–ๅ‚™ใŒใงใใŸใ€ใจ่€ƒใˆใ‚‰ใ‚Œใ‚‹ใพใง็ถ™็ถšใ—ใพ ใ™ใ€‚ใ“ใฎใƒ—ใƒญใ‚ปใ‚นใฏใ ใ„ใŸใ„ 6้€ฑ้–“็ถ™็ถšใ—ใพใ™ใ€‚ @@ -331,8 +337,8 @@ Andrew ใฏๅ€‹ๅˆฅใฎใ‚ตใƒ–ใ‚ทใ‚นใƒ†ใƒ ใ‚ซใƒผใƒใƒซใƒ„ใƒชใƒผใจใƒ‘ใƒƒใƒใ‚’ๅ…จใฆ linux-kernel ใƒกใƒผใƒชใƒณใ‚ฐใƒชใ‚นใƒˆใงๅŽ้›†ใ•ใ‚ŒใŸๅคšๆ•ฐใฎใƒ‘ใƒƒใƒใจๅŒๆ™‚ใซไธ€ใคใซใพ ใจใ‚ใพใ™ใ€‚ ใ“ใฎใƒ„ใƒชใƒผใฏๆ–ฐๆฉŸ่ƒฝใจใƒ‘ใƒƒใƒใŒๆคœ่จผใ•ใ‚Œใ‚‹ๅ ดใจใชใ‚Šใพใ™ใ€‚ใ‚ใ‚‹ๆœŸ้–“ใฎ้–“ใƒ‘ใƒƒใƒ -ใŒ -mm ใซๅ…ฅใฃใฆไพกๅ€คใ‚’่จผๆ˜Žใ•ใ‚ŒใŸใ‚‰ใ€Andrew ใ‚„ใ‚ตใƒ–ใ‚ทใ‚นใƒ†ใƒ ใƒกใƒณใƒ†ใƒŠใŒใ€ใƒก -ใ‚คใƒณใƒฉใ‚คใƒณใธๅ…ฅใ‚Œใ‚‹ใ‚ˆใ†ใซ Linus ใซใƒ—ใƒƒใ‚ทใƒฅใ—ใพใ™ใ€‚ +ใŒ -mm ใซๅ…ฅใฃใฆไพกๅ€คใ‚’่จผๆ˜Žใ•ใ‚ŒใŸใ‚‰ใ€Andrew ใ‚„ใ‚ตใƒ–ใ‚ทใ‚นใƒ†ใƒ ใƒกใƒณใƒ†ใƒŠใŒใ€ +ใƒกใ‚คใƒณใƒฉใ‚คใƒณใธๅ…ฅใ‚Œใ‚‹ใ‚ˆใ†ใซ Linus ใซใƒ—ใƒƒใ‚ทใƒฅใ—ใพใ™ใ€‚ ใƒกใ‚คใƒณใ‚ซใƒผใƒใƒซใƒ„ใƒชใƒผใซๅซใ‚ใ‚‹ใŸใ‚ใซ Linus ใซ้€ใ‚‹ๅ‰ใซใ€ใ™ในใฆใฎๆ–ฐใ—ใ„ใƒ‘ใƒƒ ใƒใŒ -mm ใƒ„ใƒชใƒผใงใƒ†ใ‚นใƒˆใ•ใ‚Œใ‚‹ใ“ใจใŒๅผทใๆŽจๅฅจใ•ใ‚Œใพใ™ใ€‚ @@ -460,7 +466,7 @@ MAINTAINERS ใƒ•ใ‚กใ‚คใƒซใซใƒชใ‚นใƒˆใŒใ‚ใ‚Šใพใ™ใฎใงๅ‚็…งใ—ใฆใใ ใ• ใ›ใ‚“- ๅฝผใ‚‰ใฏใ‚ใชใŸใฎใƒ‘ใƒƒใƒใฎ่กŒๆฏŽใซใ‚ณใƒกใƒณใƒˆใ‚’ๅ…ฅใ‚ŒใŸใ„ใฎใงใ€ใใฎใŸใ‚ใซใฏใใ†ใ™ ใ‚‹ใ—ใ‹ใ‚ใ‚Šใพใ›ใ‚“ใ€‚ใ‚ใชใŸใฎใƒกใƒผใƒซใƒ—ใƒญใ‚ฐใƒฉใƒ ใŒ็ฉบ็™ฝใ‚„ใ‚ฟใƒ–ใ‚’ๅœง็ธฎใ—ใชใ„ใ‚ˆใ† -ใซ็ขบ่ชใ—ใŸๆ–นใŒใ„ใ„ใงใ™ใ€‚ๆœ€ๅˆใฎ่‰ฏใ„ใƒ†ใ‚นใƒˆใจใ—ใฆใฏใ€่‡ชๅˆ†ใซใƒกใƒผใƒซใ‚’้€ใฃใฆ +ใซ็ขบ่ชใ—ใŸๆ–นใŒ่‰ฏใ„ใงใ™ใ€‚ๆœ€ๅˆใฎ่‰ฏใ„ใƒ†ใ‚นใƒˆใจใ—ใฆใฏใ€่‡ชๅˆ†ใซใƒกใƒผใƒซใ‚’้€ใฃใฆ ใฟใฆใ€ใใฎใƒ‘ใƒƒใƒใ‚’่‡ชๅˆ†ใงๅฝ“ใฆใฆใฟใ‚‹ใ“ใจใงใ™ใ€‚ใ‚‚ใ—ใใ‚ŒใŒใ†ใพใ่กŒใ‹ใชใ„ใช ใ‚‰ใ€ใ‚ใชใŸใฎใƒกใƒผใƒซใƒ—ใƒญใ‚ฐใƒฉใƒ ใ‚’็›ดใ—ใฆใ‚‚ใ‚‰ใ†ใ‹ใ€ๆญฃใ—ใๅ‹•ใใ‚ˆใ†ใซๅค‰ใˆใ‚‹ใน ใใงใ™ใ€‚ @@ -507,14 +513,14 @@ MAINTAINERS ใƒ•ใ‚กใ‚คใƒซใซใƒชใ‚นใƒˆใŒใ‚ใ‚Šใพใ™ใฎใงๅ‚็…งใ—ใฆใใ ใ• ใจใ‚‚ๆ™ฎ้€šใฎใ“ใจใงใ™ใ€‚ใ“ใ‚Œใฏใ‚ใชใŸใฎใƒ‘ใƒƒใƒใŒๅ—ใ‘ๅ…ฅใ‚Œใ‚‰ใ‚Œใชใ„ใจใ„ใ†ใ“ใจใง ใฏ *ใ‚ใ‚Šใพใ›ใ‚“*ใ€ใใ—ใฆใ‚ใชใŸ่‡ช่บซใซๅๅฏพใ™ใ‚‹ใ“ใจใ‚’ๆ„ๅ‘ณใ™ใ‚‹ใฎใงใ‚‚ *ใ‚ใ‚Šใพ ใ›ใ‚“*ใ€‚ๅ˜ใซ่‡ชๅˆ†ใฎใƒ‘ใƒƒใƒใซๅฏพใ—ใฆๆŒ‡ๆ‘˜ใ•ใ‚ŒใŸๅ•้กŒใ‚’ๅ…จใฆไฟฎๆญฃใ—ใฆๅ†้€ใ™ใ‚Œใฐ -ใ„ใ„ใฎใงใ™ใ€‚ +่‰ฏใ„ใฎใงใ™ใ€‚ ใ‚ซใƒผใƒใƒซใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใจไผๆฅญ็ต„็น”ใฎใกใŒใ„ ----------------------------------------------------------------- ใ‚ซใƒผใƒใƒซใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใฏๅคง้ƒจๅˆ†ใฎไผ็ตฑ็š„ใชไผš็คพใฎ้–‹็™บ็’ฐๅขƒใจใฏ็•ฐใฃใŸใ‚„ใ‚Šๆ–นใง -ๅ‹•ใ„ใฆใ„ใพใ™ใ€‚ไปฅไธ‹ใฏๅ•้กŒใ‚’้ฟใ‘ใ‚‹ใŸใ‚ใซใงใใ‚‹ใจใ‚ˆใ„ใ“ใจใฎใฎใƒชใ‚นใƒˆใงใ™- +ๅ‹•ใ„ใฆใ„ใพใ™ใ€‚ไปฅไธ‹ใฏๅ•้กŒใ‚’้ฟใ‘ใ‚‹ใŸใ‚ใซใงใใ‚‹ใจ่‰ฏใ„ใ“ใจใฎใƒชใ‚นใƒˆใงใ™- ใ‚ใชใŸใฎๆๆกˆใ™ใ‚‹ๅค‰ๆ›ดใซใคใ„ใฆ่จ€ใ†ใจใใฎใ†ใพใ„่จ€ใ„ๆ–น๏ผš @@ -525,7 +531,7 @@ MAINTAINERS ใƒ•ใ‚กใ‚คใƒซใซใƒชใ‚นใƒˆใŒใ‚ใ‚Šใพใ™ใฎใงๅ‚็…งใ—ใฆใใ ใ• - "ไปฅไธ‹ใฏไธ€้€ฃใฎๅฐใ•ใชใƒ‘ใƒƒใƒ็พคใงใ™ใŒ..." - "ใ“ใ‚Œใฏๅ…ธๅž‹็š„ใชใƒžใ‚ทใƒณใงใฎๆ€ง่ƒฝใ‚’ๅ‘ไธŠใ•ใ›ใพใ™.." - ใ‚„ใ‚ใŸๆ–นใŒใ„ใ„ๆ‚ชใ„่จ€ใ„ๆ–น๏ผš + ใ‚„ใ‚ใŸๆ–นใŒ่‰ฏใ„ๆ‚ชใ„่จ€ใ„ๆ–น๏ผš - ใ“ใฎใ‚„ใ‚Šๆ–นใง AIX/ptx/Solaris ใงใฏใงใใŸใฎใงใ€ใงใใ‚‹ใฏใšใ  - ็งใฏใ“ใ‚Œใ‚’20ๅนดใ‚‚ใฎ้–“ใ‚„ใฃใฆใใŸใ€ใ ใ‹ใ‚‰ @@ -575,10 +581,10 @@ Linux ใ‚ซใƒผใƒใƒซใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใฏใ€ไธ€ๅบฆใซๅคง้‡ใฎใ‚ณใƒผใƒ‰ใฎๅกŠใ‚’ 1) ๅฐใ•ใ„ใƒ‘ใƒƒใƒใฏใ‚ใชใŸใฎใƒ‘ใƒƒใƒใŒ้ฉ็”จใ•ใ‚Œใ‚‹่ฆ‹่พผใฟใ‚’ๅคงใใใ—ใพใ™ใ€ใ‚ซใƒผ ใƒใƒซใฎไบบ้”ใฏใƒ‘ใƒƒใƒใŒๆญฃใ—ใ„ใ‹ใฉใ†ใ‹ใ‚’็ขบ่ชใ™ใ‚‹ๆ™‚้–“ใ‚„ๅŠดๅŠ›ใ‚’ใ‹ใ‘ใชใ„ใ‹ - ใ‚‰ใงใ™ใ€‚5่กŒใฎใƒ‘ใƒƒใƒใฏใƒกใƒณใƒ†ใƒŠใŒใŸใฃใŸ1็ง’่ฆ‹ใ‚‹ใ ใ‘ใง้ฉ็”จใงใใพใ™ใ€‚ใ— - ใ‹ใ—ใ€500่กŒใฎใƒ‘ใƒƒใƒใฏใ€ๆญฃใ—ใ„ใ“ใจใ‚’ใƒฌใƒ“ใƒฅใƒผใ™ใ‚‹ใฎใซๆ•ฐๆ™‚้–“ใ‹ใ‹ใ‚‹ใ‹ใ‚‚ - ใ—ใ‚Œใพใ›ใ‚“(ๆ™‚้–“ใฏใƒ‘ใƒƒใƒใฎใ‚ตใ‚คใ‚บใชใฉใซใ‚ˆใ‚ŠๆŒ‡ๆ•ฐ้–ขๆ•ฐใซๆฏ”ไพ‹ใ—ใฆใ‹ใ‹ใ‚Šใพ - ใ™) + ใ‚‰ใงใ™ใ€‚5่กŒใฎใƒ‘ใƒƒใƒใฏใƒกใƒณใƒ†ใƒŠใŒใŸใฃใŸ1็ง’่ฆ‹ใ‚‹ใ ใ‘ใง้ฉ็”จใงใใพใ™ใ€‚ + ใ—ใ‹ใ—ใ€500่กŒใฎใƒ‘ใƒƒใƒใฏใ€ๆญฃใ—ใ„ใ“ใจใ‚’ใƒฌใƒ“ใƒฅใƒผใ™ใ‚‹ใฎใซๆ•ฐๆ™‚้–“ใ‹ใ‹ใ‚‹ใ‹ + ใ‚‚ใ—ใ‚Œใพใ›ใ‚“(ๆ™‚้–“ใฏใƒ‘ใƒƒใƒใฎใ‚ตใ‚คใ‚บใชใฉใซใ‚ˆใ‚ŠๆŒ‡ๆ•ฐ้–ขๆ•ฐใซๆฏ”ไพ‹ใ—ใฆใ‹ใ‹ใ‚Š + ใพใ™) ๅฐใ•ใ„ใƒ‘ใƒƒใƒใฏไฝ•ใ‹ใ‚ใฃใŸใจใใซใƒ‡ใƒใƒƒใ‚ฐใ‚‚ใจใฆใ‚‚็ฐกๅ˜ใซใชใ‚Šใพใ™ใ€‚ใƒ‘ใƒƒ ใƒใ‚’1ๅ€‹1ๅ€‹ๅ–ใ‚Š้™คใใฎใฏใ€ใจใฆใ‚‚ๅคงใใชใƒ‘ใƒƒใƒใ‚’ๅฝ“ใฆใŸๅพŒใซ(ใ‹ใคใ€ไฝ•ใ‹ใŠ @@ -587,23 +593,23 @@ Linux ใ‚ซใƒผใƒใƒซใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใฏใ€ไธ€ๅบฆใซๅคง้‡ใฎใ‚ณใƒผใƒ‰ใฎๅกŠใ‚’ 2) ๅฐใ•ใ„ใƒ‘ใƒƒใƒใ‚’้€ใ‚‹ใ ใ‘ใงใชใใ€้€ใ‚‹ใพใˆใซใ€ๆ›ธใ็›ดใ—ใฆใ€ใ‚ทใƒณใƒ—ใƒซใซใ™ ใ‚‹(ใ‚‚ใ—ใใฏใ€ๅ˜ใซ้ †็•ชใ‚’ๅค‰ใˆใ‚‹ใ ใ‘ใงใ‚‚)ใ“ใจใ‚‚ใ€ใจใฆใ‚‚้‡่ฆใงใ™ใ€‚ -ไปฅไธ‹ใฏใ‚ซใƒผใƒใƒซ้–‹็™บ่€…ใฎ Al Viro ใฎใŸใจใˆ่ฉฑใ—ใงใ™๏ผš +ไปฅไธ‹ใฏใ‚ซใƒผใƒใƒซ้–‹็™บ่€…ใฎ Al Viro ใฎใŸใจใˆ่ฉฑใงใ™๏ผš "็”Ÿๅพ’ใฎๆ•ฐๅญฆใฎๅฎฟ้กŒใ‚’ๆŽก็‚นใ™ใ‚‹ๅ…ˆ็”Ÿใฎใ“ใจใ‚’่€ƒใˆใฆใฟใฆใใ ใ•ใ„ใ€ๅ…ˆ - ็”Ÿใฏ็”Ÿๅพ’ใŒ่งฃใซๅˆฐ้”ใ™ใ‚‹ใพใงใฎ่ฉฆ่กŒ้Œฏ่ชคใ‚’ใฟใŸใ„ใจใฏๆ€ใ‚ใชใ„ใงใ—ใ‚‡ - ใ†ใ€‚ๅ…ˆ็”Ÿใฏ็ฐกๆฝ”ใชๆœ€้ซ˜ใฎ่งฃใ‚’ใฟใŸใ„ใฎใงใ™ใ€‚่‰ฏใ„็”Ÿๅพ’ใฏใ“ใ‚Œใ‚’็Ÿฅใฃใฆ + ็”Ÿใฏ็”Ÿๅพ’ใŒ่งฃใซๅˆฐ้”ใ™ใ‚‹ใพใงใฎ่ฉฆ่กŒ้Œฏ่ชคใ‚’่ฆ‹ใŸใ„ใจใฏๆ€ใ‚ใชใ„ใงใ—ใ‚‡ + ใ†ใ€‚ๅ…ˆ็”Ÿใฏ็ฐกๆฝ”ใชๆœ€้ซ˜ใฎ่งฃใ‚’่ฆ‹ใŸใ„ใฎใงใ™ใ€‚่‰ฏใ„็”Ÿๅพ’ใฏใ“ใ‚Œใ‚’็Ÿฅใฃใฆ ใŠใ‚Šใ€ใใ—ใฆๆœ€็ต‚่งฃใฎๅ‰ใฎไธญ้–“ไฝœๆฅญใ‚’ๆๅ‡บใ™ใ‚‹ใ“ใจใฏๆฑบใ—ใฆใชใ„ใฎใง ใ™" - ใ‚ซใƒผใƒใƒซ้–‹็™บใงใ‚‚ใ“ใ‚ŒใฏๅŒใ˜ใงใ™ใ€‚ใƒกใƒณใƒ†ใƒŠใƒผ้”ใจใƒฌใƒ“ใƒฅใƒผใ‚ข้”ใฏใ€ - ๅ•้กŒใ‚’่งฃๆฑบใ™ใ‚‹่งฃใฎ่ƒŒๅพŒใซใชใ‚‹ๆ€่€ƒใƒ—ใƒญใ‚ปใ‚นใ‚’ใฟใŸใ„ใจใฏๆ€ใ„ใพใ›ใ‚“ใ€‚ - ๅฝผใ‚‰ใฏๅ˜็ด”ใงใ‚ใ–ใ‚„ใ‹ใช่งฃๆฑบๆ–นๆณ•ใ‚’ใฟใŸใ„ใฎใงใ™ใ€‚ + ใ‚ซใƒผใƒใƒซ้–‹็™บใงใ‚‚ใ“ใ‚ŒใฏๅŒใ˜ใงใ™ใ€‚ใƒกใƒณใƒ†ใƒŠ้”ใจใƒฌใƒ“ใƒฅใƒผใ‚ข้”ใฏใ€ + ๅ•้กŒใ‚’่งฃๆฑบใ™ใ‚‹่งฃใฎ่ƒŒๅพŒใซใชใ‚‹ๆ€่€ƒใƒ—ใƒญใ‚ปใ‚นใ‚’่ฆ‹ใŸใ„ใจใฏๆ€ใ„ใพใ›ใ‚“ใ€‚ + ๅฝผใ‚‰ใฏๅ˜็ด”ใงใ‚ใ–ใ‚„ใ‹ใช่งฃๆฑบๆ–นๆณ•ใ‚’่ฆ‹ใŸใ„ใฎใงใ™ใ€‚ ใ‚ใ–ใ‚„ใ‹ใช่งฃใ‚’่ชฌๆ˜Žใ™ใ‚‹ใฎใจใ€ใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใจๅ…ฑใซไป•ไบ‹ใ‚’ใ—ใ€ๆœช่งฃๆฑบใฎไป•ไบ‹ใ‚’ ่ญฐ่ซ–ใ™ใ‚‹ใ“ใจใฎใƒใƒฉใƒณใ‚นใ‚’ใ‚ญใƒผใƒ—ใ™ใ‚‹ใฎใฏ้›ฃใ—ใ„ใ‹ใ‚‚ใ—ใ‚Œใพใ›ใ‚“ใ€‚ ใงใ™ใ‹ใ‚‰ใ€้–‹็™บใƒ—ใƒญใ‚ปใ‚นใฎๆ—ฉๆœŸๆฎต้šŽใงๆ”นๅ–„ใฎใŸใ‚ใฎใƒ•ใ‚ฃใƒผใƒ‰ใƒใƒƒใ‚ฏใ‚’ใ‚‚ใ‚‰ใ†ใ‚ˆ -ใ†ใซใ™ใ‚‹ใฎใ‚‚ใ„ใ„ใงใ™ใŒใ€ๅค‰ๆ›ด็‚นใ‚’ๅฐใ•ใ„้ƒจๅˆ†ใซๅˆ†ๅ‰ฒใ—ใฆๅ…จไฝ“ใงใฏใพใ ๅฎŒๆˆใ— -ใฆใ„ใชใ„ไป•ไบ‹ใ‚’(้ƒจๅˆ†็š„ใซ)ๅ–ใ‚Š่พผใ‚“ใงใ‚‚ใ‚‰ใˆใ‚‹ใ‚ˆใ†ใซใ™ใ‚‹ใ“ใจใ‚‚ใ„ใ„ใ“ใจใงใ™ใ€‚ +ใ†ใซใ™ใ‚‹ใฎใ‚‚่‰ฏใ„ใงใ™ใŒใ€ๅค‰ๆ›ด็‚นใ‚’ๅฐใ•ใ„้ƒจๅˆ†ใซๅˆ†ๅ‰ฒใ—ใฆๅ…จไฝ“ใงใฏใพใ ๅฎŒๆˆใ— +ใฆใ„ใชใ„ไป•ไบ‹ใ‚’(้ƒจๅˆ†็š„ใซ)ๅ–ใ‚Š่พผใ‚“ใงใ‚‚ใ‚‰ใˆใ‚‹ใ‚ˆใ†ใซใ™ใ‚‹ใ“ใจใ‚‚่‰ฏใ„ใ“ใจใงใ™ใ€‚ ใพใŸใ€ใงใไธŠใŒใฃใฆใ„ใชใ„ใ‚‚ใฎใ‚„ใ€"ๅฐ†ๆฅ็›ดใ™" ใ‚ˆใ†ใชใƒ‘ใƒƒใƒใ‚’ใ€ๆœฌๆตใซๅซใ‚ ใฆใ‚‚ใ‚‰ใ†ใ‚ˆใ†ใซ้€ใฃใฆใ‚‚ใ€ใใ‚Œใฏๅ—ใ‘ไป˜ใ‘ใ‚‰ใ‚Œใชใ„ใ“ใจใ‚’็†่งฃใ—ใฆใใ ใ•ใ„ใ€‚ @@ -629,7 +635,7 @@ Linux ใ‚ซใƒผใƒใƒซใ‚ณใƒŸใƒฅใƒ‹ใƒ†ใ‚ฃใฏใ€ไธ€ๅบฆใซๅคง้‡ใฎใ‚ณใƒผใƒ‰ใฎๅกŠใ‚’ - ใƒ†ใ‚นใƒˆ็ตๆžœ ใ“ใ‚Œใซใคใ„ใฆๅ…จใฆใŒใฉใฎใ‚ˆใ†ใซใ‚ใ‚‹ในใใ‹ใซใคใ„ใฆใฎ่ฉณ็ดฐใฏใ€ไปฅไธ‹ใฎใƒ‰ใ‚ญใƒฅใƒก -ใƒณใƒˆใฎ ChangeLog ใ‚ปใ‚ฏใ‚ทใƒงใƒณใ‚’ใฟใฆใใ ใ•ใ„- +ใƒณใƒˆใฎ ChangeLog ใ‚ปใ‚ฏใ‚ทใƒงใƒณใ‚’่ฆ‹ใฆใใ ใ•ใ„- "The Perfect Patch" http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt From 8380770c842faef3001e44662953d64ad9a93663 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 30 Jul 2007 02:28:56 +0200 Subject: [PATCH 2547/2804] Driver core: make sysfs uevent-attributes static Attributes do not have an owner(module) anymore, so there is no need to carry the attributes in every single bus instance. Signed-off-by: Kay Sievers Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 21 +++++++++------------ include/linux/device.h | 2 -- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 61c67526a656..ff850d1b0d92 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -568,32 +568,29 @@ static void remove_bind_files(struct device_driver *drv) driver_remove_file(drv, &driver_attr_unbind); } +static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); +static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, + show_drivers_autoprobe, store_drivers_autoprobe); + static int add_probe_files(struct bus_type *bus) { int retval; - bus->drivers_probe_attr.attr.name = "drivers_probe"; - bus->drivers_probe_attr.attr.mode = S_IWUSR; - bus->drivers_probe_attr.store = store_drivers_probe; - retval = bus_create_file(bus, &bus->drivers_probe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_probe); if (retval) goto out; - bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; - bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; - bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; - bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; - retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); if (retval) - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_probe); out: return retval; } static void remove_probe_files(struct bus_type *bus) { - bus_remove_file(bus, &bus->drivers_autoprobe_attr); - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_autoprobe); + bus_remove_file(bus, &bus_attr_drivers_probe); } #else static inline int add_bind_files(struct device_driver *drv) { return 0; } diff --git a/include/linux/device.h b/include/linux/device.h index 3a38d1f70cb7..5d97ca6d8655 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -64,8 +64,6 @@ struct bus_type { struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; struct driver_attribute * drv_attrs; - struct bus_attribute drivers_autoprobe_attr; - struct bus_attribute drivers_probe_attr; int (*match)(struct device * dev, struct device_driver * drv); int (*uevent)(struct device *dev, char **envp, From 7eff2e7a8b65c25920207324e56611150eb1cd9a Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 14 Aug 2007 15:15:12 +0200 Subject: [PATCH 2548/2804] Driver core: change add_uevent_var to use a struct This changes the uevent buffer functions to use a struct instead of a long list of parameters. It does no longer require the caller to do the proper buffer termination and size accounting, which is currently wrong in some places. It fixes a known bug where parts of the uevent environment are overwritten because of wrong index calculations. Many thanks to Mathieu Desnoyers for finding bugs and improving the error handling. Signed-off-by: Kay Sievers Cc: Mathieu Desnoyers Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- arch/ia64/sn/kernel/tiocx.c | 3 +- arch/powerpc/kernel/of_device.c | 37 ++--- arch/powerpc/kernel/vio.c | 16 +-- arch/powerpc/platforms/ps3/system-bus.c | 9 +- block/genhd.c | 35 ++--- drivers/acpi/scan.c | 16 ++- drivers/amba/bus.c | 9 +- drivers/base/class.c | 42 ++---- drivers/base/core.c | 84 ++++------- drivers/base/firmware_class.c | 11 +- drivers/base/memory.c | 3 +- drivers/base/platform.c | 6 +- drivers/eisa/eisa-bus.c | 9 +- drivers/firewire/fw-device.c | 11 +- drivers/firmware/dmi-id.c | 15 +- drivers/i2c/i2c-core.c | 8 +- drivers/ide/ide.c | 15 +- drivers/ieee1394/nodemgr.c | 17 +-- drivers/infiniband/core/sysfs.c | 9 +- drivers/input/input.c | 66 +++------ drivers/input/serio/serio.c | 11 +- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 4 +- drivers/misc/tifm_core.c | 9 +- drivers/mmc/core/bus.c | 21 +-- drivers/pci/hotplug.c | 28 +--- drivers/pci/pci-driver.c | 3 +- drivers/pci/pci.h | 3 +- drivers/pcmcia/cs.c | 10 +- drivers/pcmcia/ds.c | 26 +--- drivers/power/power_supply.h | 3 +- drivers/power/power_supply_sysfs.c | 17 +-- drivers/s390/cio/ccwgroup.c | 3 +- drivers/s390/cio/device.c | 25 +--- drivers/s390/crypto/ap_bus.c | 14 +- drivers/scsi/scsi_sysfs.c | 9 +- drivers/spi/spi.c | 7 +- drivers/usb/core/driver.c | 29 +--- drivers/usb/core/message.c | 28 +--- drivers/w1/w1.c | 19 +-- include/asm-powerpc/of_device.h | 2 +- include/linux/device.h | 15 +- include/linux/kobject.h | 23 +-- lib/kobject_uevent.c | 149 +++++++++----------- net/atm/atm_sysfs.c | 7 +- net/core/net-sysfs.c | 14 +- net/wireless/sysfs.c | 3 +- sound/aoa/soundbus/core.c | 33 ++--- 47 files changed, 300 insertions(+), 636 deletions(-) diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index 5a289e4de838..a88eba3314d7 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -66,8 +66,7 @@ static int tiocx_match(struct device *dev, struct device_driver *drv) } -static int tiocx_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index 89b911e83c04..8f3db32fac8b 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c @@ -57,26 +57,21 @@ ssize_t of_device_get_modalias(struct of_device *ofdev, return tsize; } -int of_device_uevent(struct device *dev, - char **envp, int num_envp, char *buffer, int buffer_size) +int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct of_device *ofdev; const char *compat; - int i = 0, length = 0, seen = 0, cplen, sl; + int seen = 0, cplen, sl; if (!dev) return -ENODEV; ofdev = to_of_device(dev); - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_NAME=%s", ofdev->node->name)) + if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_TYPE=%s", ofdev->node->type)) + if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type)) return -ENOMEM; /* Since the compatible field can contain pretty much anything @@ -85,9 +80,7 @@ int of_device_uevent(struct device *dev, compat = of_get_property(ofdev->node, "compatible", &cplen); while (compat && *compat && cplen > 0) { - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_%d=%s", seen, compat)) + if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) return -ENOMEM; sl = strlen (compat) + 1; @@ -96,25 +89,17 @@ int of_device_uevent(struct device *dev, seen++; } - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_N=%d", seen)) + if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) return -ENOMEM; /* modalias is trickier, we add it in 2 steps */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=")) + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - - sl = of_device_get_modalias(ofdev, &buffer[length-1], - buffer_size-length); - if (sl >= (buffer_size-length)) + sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1], + sizeof(env->buf) - env->buflen); + if (sl >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - - length += sl; - - envp[i] = NULL; + env->buflen += sl; return 0; } diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index cb22a3557c4e..19a5656001c0 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -317,30 +317,20 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv) return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL); } -static int vio_hotplug(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env) { const struct vio_dev *vio_dev = to_vio_dev(dev); struct device_node *dn; const char *cp; - int length; - - if (!num_envp) - return -ENOMEM; dn = dev->archdata.of_node; if (!dn) return -ENODEV; - cp = of_get_property(dn, "compatible", &length); + cp = of_get_property(dn, "compatible", NULL); if (!cp) return -ENODEV; - envp[0] = buffer; - length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s", - vio_dev->type, cp); - if ((buffer_size - length) <= 0) - return -ENOMEM; - envp[1] = NULL; + add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp); return 0; } diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 4bb634a17e43..ea0b2c790412 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -437,18 +437,13 @@ static void ps3_system_bus_shutdown(struct device *_dev) dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); } -static int ps3_system_bus_uevent(struct device *_dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MODALIAS=ps3:%d", - dev->match_id)) + if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id)) return -ENOMEM; - - envp[i] = NULL; return 0; } diff --git a/block/genhd.c b/block/genhd.c index 3af1e7a378d4..e609996f2e76 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -540,61 +540,42 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj) return ((ktype == &ktype_block) || (ktype == &ktype_part)); } -static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int block_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct kobj_type *ktype = get_ktype(kobj); struct device *physdev; struct gendisk *disk; struct hd_struct *part; - int length = 0; - int i = 0; if (ktype == &ktype_block) { disk = container_of(kobj, struct gendisk, kobj); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", disk->first_minor); + add_uevent_var(env, "MINOR=%u", disk->first_minor); } else if (ktype == &ktype_part) { disk = container_of(kobj->parent, struct gendisk, kobj); part = container_of(kobj, struct hd_struct, kobj); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", + add_uevent_var(env, "MINOR=%u", disk->first_minor + part->partno); } else return 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MAJOR=%u", disk->major); + add_uevent_var(env, "MAJOR=%u", disk->major); /* add physical device, backing this device */ physdev = disk->driverfs_dev; if (physdev) { char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); if (physdev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", - physdev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name); if (physdev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", - physdev->driver->name); + add_uevent_var(env, physdev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64620d668742..5b4d462117cf 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } -static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct acpi_device *acpi_dev = to_acpi_device(dev); + int len; - strcpy(buffer, "MODALIAS="); - if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) { - envp[0] = buffer; - envp[1] = NULL; - } + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 268e301775fc..6b94fb7be5f2 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) +static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) { struct amba_device *pcdev = to_amba_device(dev); - int retval = 0, i = 0, len = 0; + int retval = 0; - retval = add_uevent_var(envp, nr_env, &i, - buf, bufsz, &len, - "AMBA_ID=%08x", pcdev->periphid); - envp[i] = NULL; + retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); return retval; } #else diff --git a/drivers/base/class.c b/drivers/base/class.c index 4d2222618b78..ecd6336bffea 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev) /* needed to allow these devices to have parent class devices */ static int class_device_create_uevent(struct class_device *class_dev, - char **envp, int num_envp, - char *buffer, int buffer_size) + struct kobj_uevent_env *env) { pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); return 0; @@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd) { } #endif -static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int class_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct class_device *class_dev = to_class_dev(kobj); struct device *dev = class_dev->dev; - int i = 0; - int length = 0; int retval = 0; pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); if (MAJOR(class_dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(class_dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(class_dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt)); } if (dev) { const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } if (dev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - if (class_dev->uevent) { /* have the class device specific function add its stuff */ - retval = class_dev->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->uevent(class_dev, env); if (retval) pr_debug("class_dev->uevent() returned %d\n", retval); } else if (class_dev->class->uevent) { /* have the class specific function add its stuff */ - retval = class_dev->class->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->class->uevent(class_dev, env); if (retval) pr_debug("class->uevent() returned %d\n", retval); } diff --git a/drivers/base/core.c b/drivers/base/core.c index ec86d6fc2360..d487c032dc4a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) return NULL; } -static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dev_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct device *dev = to_dev(kobj); - int i = 0; - int length = 0; int retval = 0; /* add the major/minor if present */ if (MAJOR(dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); } if (dev->type && dev->type->name) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVTYPE=%s", dev->type->name); + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DRIVER=%s", dev->driver->name); + add_uevent_var(env, "DRIVER=%s", dev->driver->name); #ifdef CONFIG_SYSFS_DEPRECATED if (dev->class) { @@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, path = kobject_get_path(&parent->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", parent->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); if (parent->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", parent->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + parent->driver->name); } } else if (dev->bus) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } #endif - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - + /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { - /* have the bus specific function add its stuff */ - retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->bus->uevent(dev, env); if (retval) pr_debug ("%s: bus uevent() returned %d\n", __FUNCTION__, retval); } + /* have the class specific function add its stuff */ if (dev->class && dev->class->dev_uevent) { - /* have the class specific function add its stuff */ - retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->class->dev_uevent(dev, env); if (retval) pr_debug("%s: class uevent() returned %d\n", __FUNCTION__, retval); } + /* have the device type specific fuction add its stuff */ if (dev->type && dev->type->uevent) { - /* have the device type specific fuction add its stuff */ - retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->type->uevent(dev, env); if (retval) pr_debug("%s: dev_type uevent() returned %d\n", __FUNCTION__, retval); @@ -253,9 +227,7 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, { struct kobject *top_kobj; struct kset *kset; - char *envp[32]; - char *data = NULL; - char *pos; + struct kobj_uevent_env *env = NULL; int i; size_t count = 0; int retval; @@ -278,26 +250,20 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, if (!kset->uevent_ops->filter(kset, &dev->kobj)) goto out; - data = (char *)get_zeroed_page(GFP_KERNEL); - if (!data) + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env) return -ENOMEM; /* let the kset specific function add its keys */ - pos = data; - memset(envp, 0, sizeof(envp)); - retval = kset->uevent_ops->uevent(kset, &dev->kobj, - envp, ARRAY_SIZE(envp), - pos, PAGE_SIZE); + retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); if (retval) goto out; /* copy keys to file */ - for (i = 0; envp[i]; i++) { - pos = &buf[count]; - count += sprintf(pos, "%s\n", envp[i]); - } + for (i = 0; i < env->envp_idx; i++) + count += sprintf(&buf[count], "%s\n", env->envp[i]); out: - free_page((unsigned long)data); + kfree(env); return count; } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b24efd4e3e3d..4a1b9bfc5471 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); static void fw_dev_release(struct device *dev); -static int firmware_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) { struct firmware_priv *fw_priv = dev_get_drvdata(dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "FIRMWARE=%s", fw_priv->fw_id)) + if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "TIMEOUT=%i", loading_timeout)) + if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) return -ENOMEM; - envp[i] = NULL; return 0; } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 74b96795d2f5..cb99daeae936 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) return MEMORY_CLASS_NAME; } -static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env) { int retval = 0; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9bfc434d1327..a2e3910196e0 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -529,13 +529,11 @@ static struct device_attribute platform_dev_attrs[] = { __ATTR_NULL, }; -static int platform_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) { struct platform_device *pdev = to_platform_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=platform:%s", pdev->name); + add_uevent_var(env, "MODALIAS=platform:%s", pdev->name); return 0; } diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index d944647c82c2..4d4a47393909 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv) return 0; } -static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct eisa_device *edev = to_eisa_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); return 0; } diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 2b6586341635..56681b3b297b 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) } static int -fw_unit_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) { struct fw_unit *unit = fw_unit(dev); char modalias[64]; - int length = 0; - int i = 0; get_modalias(unit, modalias, sizeof(modalias)); - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", modalias)) + if (add_uevent_var(env, "MODALIAS=%s", modalias)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 59c3b5aa89f4..2678098d4504 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -134,14 +134,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = { NULL }; -static int dmi_dev_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { - strcpy(buffer, "MODALIAS="); - get_modalias(buffer+9, buffer_size-9); - envp[0] = buffer; - envp[1] = NULL; + ssize_t len; + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = get_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d663e6960d93..910a62de190d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) #ifdef CONFIG_HOTPLUG /* uevent helps with hotplug: modprobe -q $(MODALIAS) */ -static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - int i = 0, length = 0; /* by definition, legacy drivers can't hotplug */ if (dev->driver || !client->driver_name) return 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=%s", client->driver_name)) + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) return -ENOMEM; - envp[i] = NULL; dev_dbg(dev, "uevent\n"); return 0; } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index e96212ce5729..a96a8b1b3539 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1663,20 +1663,13 @@ static struct device_attribute ide_dev_attrs[] = { __ATTR_NULL }; -static int ide_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ide_uevent(struct device *dev, struct kobj_uevent_env *env) { ide_drive_t *drive = to_ide_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MEDIA=%s", media_string(drive)); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "DRIVENAME=%s", drive->name); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=ide:m-%s", media_string(drive)); - envp[i] = NULL; + add_uevent_var(env, "MEDIA=%s", media_string(drive)); + add_uevent_var(env, "DRIVENAME=%s", drive->name); + add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive)); return 0; } diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 2ffd53461db6..1939fee616ec 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -153,8 +153,7 @@ struct host_info { }; static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env); static void nodemgr_resume_ne(struct node_entry *ne); static void nodemgr_remove_ne(struct node_entry *ne); static struct node_entry *find_entry_by_guid(u64 guid); @@ -1160,12 +1159,9 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent #ifdef CONFIG_HOTPLUG -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { struct unit_directory *ud; - int i = 0; - int length = 0; int retval = 0; /* ieee1394:venNmoNspNverN */ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; @@ -1180,9 +1176,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, #define PUT_ENVP(fmt,val) \ do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &length, \ - fmt, val); \ + retval = add_uevent_var(env, fmt, val); \ if (retval) \ return retval; \ } while (0) @@ -1201,15 +1195,12 @@ do { \ #undef PUT_ENVP - envp[i] = NULL; - return 0; } #else -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 70b77ae67422..3d4050681325 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev) kfree(dev); } -static int ib_device_uevent(struct class_device *cdev, char **envp, - int num_envp, char *buf, int size) +static int ib_device_uevent(struct class_device *cdev, + struct kobj_uevent_env *env) { struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buf, size, &len, - "NAME=%s", dev->name)) + if (add_uevent_var(env, "NAME=%s", dev->name)) return -ENOMEM; /* * It would be nice to pass the node GUID with the event... */ - envp[i] = NULL; return 0; } diff --git a/drivers/input/input.c b/drivers/input/input.c index 5fe755586623..5dc361c954e2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -859,87 +859,66 @@ static void input_dev_release(struct device *device) * Input uevent interface - loading event handlers based on * device bitfields. */ -static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_bm_var(struct kobj_uevent_env *env, const char *name, unsigned long *bitmap, int max) { - if (*cur_index >= num_envp - 1) + int len; + + if (add_uevent_var(env, "%s=", name)) return -ENOMEM; - envp[*cur_index] = buffer + *cur_len; - - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); - if (*cur_len >= buffer_size) + len = input_print_bitmap(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + bitmap, max, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - *cur_len += input_print_bitmap(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - bitmap, max, 0) + 1; - if (*cur_len > buffer_size) - return -ENOMEM; - - (*cur_index)++; + env->buflen += len; return 0; } -static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_modalias_var(struct kobj_uevent_env *env, struct input_dev *dev) { - if (*cur_index >= num_envp - 1) + int len; + + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - envp[*cur_index] = buffer + *cur_len; - - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), - "MODALIAS="); - if (*cur_len >= buffer_size) + len = input_print_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + dev, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - *cur_len += input_print_modalias(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - dev, 0) + 1; - if (*cur_len > buffer_size) - return -ENOMEM; - - (*cur_index)++; + env->buflen += len; return 0; } #define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ do { \ - int err = input_add_uevent_bm_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - name, bm, max); \ + int err = input_add_uevent_bm_var(env, name, bm, max); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \ do { \ - int err = input_add_uevent_modalias_var(envp, \ - num_envp, &i, \ - buffer, buffer_size, &len, \ - dev); \ + int err = input_add_uevent_modalias_var(env, dev); \ if (err) \ return err; \ } while (0) -static int input_dev_uevent(struct device *device, char **envp, - int num_envp, char *buffer, int buffer_size) +static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct input_dev *dev = to_input_dev(device); - int i = 0; - int len = 0; INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", dev->id.bustype, dev->id.vendor, @@ -971,7 +950,6 @@ static int input_dev_uevent(struct device *device, char **envp, INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev); - envp[i] = NULL; return 0; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 372ca4931194..b3bc15acd3f5 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -876,18 +876,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv) #define SERIO_ADD_UEVENT_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { struct serio *serio; - int i = 0; - int len = 0; if (!dev) return -ENODEV; @@ -900,7 +896,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra); SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); - envp[i] = NULL; return 0; } @@ -908,7 +903,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf #else -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7a78d6b34738..2ee3c3049e8f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -905,8 +905,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct device *cd,char **envp, - int numenvp,char *buf,int size) +static int pvr2_sysfs_hotplug(struct device *d, + struct kobj_uevent_env *env) { /* Even though we don't do anything here, we still need this function because sysfs will still try to call it. */ diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d195fb088f4a..8f77949f93dd 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv) return 0; } -static int tifm_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env) { struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - int i = 0; - int length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "TIFM_CARD_TYPE=%s", - tifm_media_type_name(sock->type, 1))) + if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1))) return -ENOMEM; return 0; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8d6f6014870f..b0c22cad9423 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -58,12 +58,11 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv) } static int -mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, - int buf_size) +mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct mmc_card *card = dev_to_mmc_card(dev); const char *type; - int i = 0, length = 0; + int retval = 0; switch (card->type) { case MMC_TYPE_MMC: @@ -80,20 +79,14 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, } if (type) { - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_TYPE=%s", type)) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_TYPE=%s", type); + if (retval) + return retval; } - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_NAME=%s", mmc_card_name(card))) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); - envp[i] = NULL; - - return 0; + return retval; } static int mmc_bus_probe(struct device *dev) diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 1c97e7dd130b..2b5352a7dffc 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -3,12 +3,9 @@ #include #include "pci.h" -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pci_dev *pdev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp, if (!pdev) return -ENODEV; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_CLASS=%04X", pdev->class)) + if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) + if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, + if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SLOT_NAME=%s", pci_name(pdev))) + if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), (u8)(pdev->class))) return -ENOMEM; - - envp[i] = NULL; - return 0; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 004bc2487270..f61be3abfdca 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -532,8 +532,7 @@ void pci_dev_put(struct pci_dev *dev) } #ifndef CONFIG_HOTPLUG -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4c36e80f6d26..b3a7d5b0f936 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,7 +1,6 @@ /* Functions internal to the PCI core code */ -extern int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_cleanup_rom(struct pci_dev *dev); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f8b13f0270d7..a0aca46ce877 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -907,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) EXPORT_SYMBOL(pcmcia_insert_card); -static int pcmcia_socket_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int pcmcia_socket_uevent(struct device *dev, + struct kobj_uevent_env *env) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); - int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "SOCKET_NO=%u", s->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", s->sock)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a99607142fc8..55baa1f0fcbb 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1064,11 +1064,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { #ifdef CONFIG_HOTPLUG -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pcmcia_device *p_dev; - int i, length = 0; + int i; u32 hash[4] = { 0, 0, 0, 0}; if (!dev) @@ -1083,23 +1082,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i])); } - i = 0; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "SOCKET_NO=%u", - p_dev->socket->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE_NO=%02X", - p_dev->device_no)) + if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" + if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" "pa%08Xpb%08Xpc%08Xpd%08X", p_dev->has_manf_id ? p_dev->manf_id : 0, p_dev->has_card_id ? p_dev->card_id : 0, @@ -1112,15 +1101,12 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[3])) return -ENOMEM; - envp[i] = NULL; - return 0; } #else -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h index a9880d468ee4..f38ba482be75 100644 --- a/drivers/power/power_supply.h +++ b/drivers/power/power_supply.h @@ -14,8 +14,7 @@ extern int power_supply_create_attrs(struct power_supply *psy); extern void power_supply_remove_attrs(struct power_supply *psy); -extern int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); #else diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index de3155b21285..249f61bae639 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp) return ret; } -int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) { struct power_supply *psy = dev_get_drvdata(dev); - int i = 0, length = 0, ret = 0, j; + int ret = 0, j; char *prop_buf; char *attrname; @@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_NAME=%s", psy->name); + ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name); if (ret) return ret; @@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; @@ -282,14 +278,11 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; } - envp[i] = NULL; out: free_page((unsigned long)prop_buf); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b0a18f5176aa..5d967c439822 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv) return 0; } static int -ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer, - int buffer_size) +ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env) { /* TODO */ return 0; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e44d92eac8e9..606bb53e9fae 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -78,49 +78,38 @@ static int snprint_alias(char *buf, size_t size, /* Set up environment variables for ccw device uevent. Return 0 on success, * non-zero otherwise. */ -static int ccw_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); - int i = 0; - int len = 0; int ret; char modalias_buf[30]; /* CU_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_TYPE=%04X", id->cu_type); + ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type); if (ret) return ret; /* CU_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_MODEL=%02X", id->cu_model); + ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model); if (ret) return ret; /* The next two can be zero, that's ok for us */ /* DEV_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_TYPE=%04X", id->dev_type); + ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type); if (ret) return ret; /* DEV_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_MODEL=%02X", id->dev_model); + ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model); if (ret) return ret; /* MODALIAS= */ snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "MODALIAS=%s", modalias_buf); - if (ret) - return ret; - envp[i] = NULL; - return 0; + ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf); + return ret; } struct bus_type ccw_bus_type; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 90bd22014513..e99713041591 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * uevent function for AP devices. It sets up a single environment * variable DEV_TYPE which contains the hardware device type. */ -static int ap_uevent (struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) { struct ap_device *ap_dev = to_ap_dev(dev); - int retval = 0, length = 0, i = 0; + int retval = 0; if (!ap_dev) return -ENODEV; /* Set up DEV_TYPE environment variable. */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEV_TYPE=%04X", ap_dev->device_type); + retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type); if (retval) return retval; /* Add MODALIAS= */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=ap:t%02X", ap_dev->device_type); + retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type); - envp[i] = NULL; return retval; } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 34cdce6738a6..ede9986d349a 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -277,16 +277,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; } -static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct scsi_device *sdev = to_scsi_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); return 0; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e84d21597943..bcb8dd5fb0b4 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0; } -static int spi_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) { const struct spi_device *spi = to_spi_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias); - envp[1] = NULL; + add_uevent_var(env, "MODALIAS=%s", spi->modalias); return 0; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 63b1243a9139..6273a5197e6a 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -576,12 +576,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int usb_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -610,51 +607,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, * all the device descriptors we don't tell them about. Or * act as usermode drivers. */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif /* per-device configurations are common */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; /* class-based driver binding models */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "BUSNUM=%03d", + if (add_uevent_var(env, "BUSNUM=%03d", usb_dev->bus->busnum)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVNUM=%03d", + if (add_uevent_var(env, "DEVNUM=%03d", usb_dev->devnum)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d8f7b089a8f0..95a49d8efe7a 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1339,14 +1339,11 @@ void usb_release_interface(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int usb_if_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; struct usb_interface *intf; struct usb_host_interface *alt; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -1359,39 +1356,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt = intf->cur_altsetting; #ifdef CONFIG_USB_DEVICEFS - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", + if (add_uevent_var(env, "INTERFACE=%d/%d/%d", alt->desc.bInterfaceClass, alt->desc.bInterfaceSubClass, alt->desc.bInterfaceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, + if (add_uevent_var(env, "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), @@ -1404,14 +1392,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt->desc.bInterfaceProtocol)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_if_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index a593f900eff4..070217322c9f 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -197,7 +197,7 @@ static struct w1_family w1_default_family = { .fops = &w1_default_fops, }; -static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env); static struct bus_type w1_bus_type = { .name = "w1", @@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master) } #ifdef CONFIG_HOTPLUG -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { struct w1_master *md = NULL; struct w1_slave *sl = NULL; char *event_owner, *name; - int err, cur_index=0, cur_len=0; + int err; if (dev->driver == &w1_master_driver) { md = container_of(dev, struct w1_master, dev); @@ -423,23 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, if (dev->driver != &w1_slave_driver || !sl) return 0; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_FID=%02X", sl->reg_num.family); + err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family); if (err) return err; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_SLAVE_ID=%024LX", - (unsigned long long)sl->reg_num.id); - envp[cur_index] = NULL; + err = add_uevent_var(env, "W1_SLAVE_ID=%024LX", + (unsigned long long)sl->reg_num.id); if (err) return err; return 0; }; #else -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { return 0; } diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h index ec2a8a2c737c..93262f2546ad 100644 --- a/include/asm-powerpc/of_device.h +++ b/include/asm-powerpc/of_device.h @@ -20,7 +20,7 @@ struct of_device extern ssize_t of_device_get_modalias(struct of_device *ofdev, char *str, ssize_t len); extern int of_device_uevent(struct device *dev, - char **envp, int num_envp, char *buffer, int buffer_size); + struct kobj_uevent_env *env); /* This is just here during the transition */ #include diff --git a/include/linux/device.h b/include/linux/device.h index 5d97ca6d8655..2e15822fe409 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -66,8 +66,7 @@ struct bus_type { struct driver_attribute * drv_attrs; int (*match)(struct device * dev, struct device_driver * drv); - int (*uevent)(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device * dev); int (*remove)(struct device * dev); void (*shutdown)(struct device * dev); @@ -187,10 +186,8 @@ struct class { struct class_device_attribute * class_dev_attrs; struct device_attribute * dev_attrs; - int (*uevent)(struct class_device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); - int (*dev_uevent)(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); + int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); void (*release)(struct class_device *dev); void (*class_release)(struct class *class); @@ -266,8 +263,7 @@ struct class_device { struct attribute_group ** groups; /* optional groups */ void (*release)(struct class_device *dev); - int (*uevent)(struct class_device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); char class_id[BUS_ID_SIZE]; /* unique to this class */ }; @@ -335,8 +331,7 @@ extern void class_device_destroy(struct class *cls, dev_t devt); struct device_type { const char *name; struct attribute_group **groups; - int (*uevent)(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); void (*release)(struct device *dev); int (*suspend)(struct device * dev, pm_message_t state); int (*resume)(struct device * dev); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 949706c33622..626bdd3c3dd9 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -29,6 +29,8 @@ #define KOBJ_NAME_LEN 20 #define UEVENT_HELPER_PATH_LEN 256 +#define UEVENT_NUM_ENVP 32 /* number of env pointers */ +#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ /* path to the userspace helper executed on an event */ extern char uevent_helper[]; @@ -111,11 +113,18 @@ struct kobj_type { struct attribute ** default_attrs; }; +struct kobj_uevent_env { + char *envp[UEVENT_NUM_ENVP]; + int envp_idx; + char buf[UEVENT_BUFFER_SIZE]; + int buflen; +}; + struct kset_uevent_ops { int (*filter)(struct kset *kset, struct kobject *kobj); const char *(*name)(struct kset *kset, struct kobject *kobj); - int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env); }; /* @@ -275,10 +284,8 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action); int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp[]); -int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) - __attribute__((format (printf, 7, 8))); +int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) + __attribute__((format (printf, 2, 3))); #else static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action) { return 0; } @@ -287,9 +294,7 @@ static inline int kobject_uevent_env(struct kobject *kobj, char *envp[]) { return 0; } -static inline int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) +static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { return 0; } #endif diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index e06a8dcec0f0..7d8aeb301635 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -22,8 +22,6 @@ #include #include -#define BUFFER_SIZE 2048 /* buffer for the variables */ -#define NUM_ENVP 32 /* number of env pointers */ /* the strings here must match the enum in include/linux/kobject.h */ const char *kobject_actions[] = { @@ -54,31 +52,21 @@ static struct sock *uevent_sock; * corresponding error when it fails. */ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, - char *envp_ext[]) + char *envp_ext[]) { - char **envp; - char *buffer; - char *scratch; - const char *action_string; + struct kobj_uevent_env *env; + const char *action_string = kobject_actions[action]; const char *devpath = NULL; const char *subsystem; struct kobject *top_kobj; struct kset *kset; struct kset_uevent_ops *uevent_ops; u64 seq; - char *seq_buff; int i = 0; int retval = 0; - int j; pr_debug("%s\n", __FUNCTION__); - action_string = kobject_actions[action]; - if (!action_string) { - pr_debug("kobject attempted to send uevent without action_string!\n"); - return -EINVAL; - } - /* search the kset we belong to */ top_kobj = kobj; while (!top_kobj->kset && top_kobj->parent) { @@ -92,7 +80,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, kset = top_kobj->kset; uevent_ops = kset->uevent_ops; - /* skip the event, if the filter returns zero. */ + /* skip the event, if the filter returns zero. */ if (uevent_ops && uevent_ops->filter) if (!uevent_ops->filter(kset, kobj)) { pr_debug("kobject filter function caused the event to drop!\n"); @@ -109,18 +97,11 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, return 0; } - /* environment index */ - envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); - if (!envp) + /* environment buffer */ + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env) return -ENOMEM; - /* environment values */ - buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); - if (!buffer) { - retval = -ENOMEM; - goto exit; - } - /* complete object path */ devpath = kobject_get_path(kobj, GFP_KERNEL); if (!devpath) { @@ -128,29 +109,29 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, goto exit; } - /* event environemnt for helper process only */ - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - /* default keys */ - scratch = buffer; - envp [i++] = scratch; - scratch += sprintf(scratch, "ACTION=%s", action_string) + 1; - envp [i++] = scratch; - scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1; - envp [i++] = scratch; - scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1; - for (j = 0; envp_ext && envp_ext[j]; j++) - envp[i++] = envp_ext[j]; - /* just reserve the space, overwrite it after kset call has returned */ - envp[i++] = seq_buff = scratch; - scratch += strlen("SEQNUM=18446744073709551616") + 1; + retval = add_uevent_var(env, "ACTION=%s", action_string); + if (retval) + goto exit; + retval = add_uevent_var(env, "DEVPATH=%s", devpath); + if (retval) + goto exit; + retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); + if (retval) + goto exit; + + /* keys passed in from the caller */ + if (envp_ext) { + for (i = 0; envp_ext[i]; i++) { + retval = add_uevent_var(env, envp_ext[i]); + if (retval) + goto exit; + } + } /* let the kset specific function add its stuff */ if (uevent_ops && uevent_ops->uevent) { - retval = uevent_ops->uevent(kset, kobj, - &envp[i], NUM_ENVP - i, scratch, - BUFFER_SIZE - (scratch - buffer)); + retval = uevent_ops->uevent(kset, kobj, env); if (retval) { pr_debug ("%s - uevent() returned %d\n", __FUNCTION__, retval); @@ -158,11 +139,13 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, } } - /* we will send an event, request a new sequence number */ + /* we will send an event, so request a new sequence number */ spin_lock(&sequence_lock); seq = ++uevent_seqnum; spin_unlock(&sequence_lock); - sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq); + retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq); + if (retval) + goto exit; #if defined(CONFIG_NET) /* send netlink message */ @@ -172,17 +155,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* allocate message with the maximum possible size */ len = strlen(action_string) + strlen(devpath) + 2; - skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL); + skb = alloc_skb(len + env->buflen, GFP_KERNEL); if (skb) { + char *scratch; + /* add header */ scratch = skb_put(skb, len); sprintf(scratch, "%s@%s", action_string, devpath); /* copy keys to our continuous event payload buffer */ - for (i = 2; envp[i]; i++) { - len = strlen(envp[i]) + 1; + for (i = 0; i < env->envp_idx; i++) { + len = strlen(env->envp[i]) + 1; scratch = skb_put(skb, len); - strcpy(scratch, envp[i]); + strcpy(scratch, env->envp[i]); } NETLINK_CB(skb).dst_group = 1; @@ -198,13 +183,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, argv [0] = uevent_helper; argv [1] = (char *)subsystem; argv [2] = NULL; - call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC); + retval = add_uevent_var(env, "HOME=/"); + if (retval) + goto exit; + retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); + if (retval) + goto exit; + + call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC); } exit: kfree(devpath); - kfree(buffer); - kfree(envp); + kfree(env); return retval; } @@ -227,52 +218,38 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action) EXPORT_SYMBOL_GPL(kobject_uevent); /** - * add_uevent_var - helper for creating event variables - * @envp: Pointer to table of environment variables, as passed into - * uevent() method. - * @num_envp: Number of environment variable slots available, as - * passed into uevent() method. - * @cur_index: Pointer to current index into @envp. It should be - * initialized to 0 before the first call to add_uevent_var(), - * and will be incremented on success. - * @buffer: Pointer to buffer for environment variables, as passed - * into uevent() method. - * @buffer_size: Length of @buffer, as passed into uevent() method. - * @cur_len: Pointer to current length of space used in @buffer. - * Should be initialized to 0 before the first call to - * add_uevent_var(), and will be incremented on success. - * @format: Format for creating environment variable (of the form - * "XXX=%x") for snprintf(). + * add_uevent_var - add key value string to the environment buffer + * @env: environment buffer structure + * @format: printf format for the key=value pair * * Returns 0 if environment variable was added successfully or -ENOMEM * if no space was available. */ -int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) +int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { va_list args; + int len; - /* - * We check against num_envp - 1 to make sure there is at - * least one slot left after we return, since kobject_uevent() - * needs to set the last slot to NULL. - */ - if (*cur_index >= num_envp - 1) + if (env->envp_idx >= ARRAY_SIZE(env->envp)) { + printk(KERN_ERR "add_uevent_var: too many keys\n"); + WARN_ON(1); return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + } va_start(args, format); - *cur_len += vsnprintf(envp[*cur_index], - max(buffer_size - *cur_len, 0), - format, args) + 1; + len = vsnprintf(&env->buf[env->buflen], + sizeof(env->buf) - env->buflen, + format, args); va_end(args); - if (*cur_len > buffer_size) + if (len >= (sizeof(env->buf) - env->buflen)) { + printk(KERN_ERR "add_uevent_var: buffer size too small\n"); + WARN_ON(1); return -ENOMEM; + } - (*cur_index)++; + env->envp[env->envp_idx++] = &env->buf[env->buflen]; + env->buflen += len + 1; return 0; } EXPORT_SYMBOL_GPL(add_uevent_var); diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index f094a0879c16..9ef07eda2c43 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c @@ -105,10 +105,9 @@ static struct class_device_attribute *atm_attrs[] = { NULL }; -static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size) +static int atm_uevent(struct class_device *cdev, struct kobj_uevent_env *env) { struct atm_dev *adev; - int i = 0, len = 0; if (!cdev) return -ENODEV; @@ -117,11 +116,9 @@ static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char if (!adev) return -ENODEV; - if (add_uevent_var(envp, num_envp, &i, buf, size, &len, - "NAME=%s%d", adev->type, adev->number)) + if (add_uevent_var(env, "NAME=%s%d", adev->type, adev->number)) return -ENOMEM; - envp[i] = NULL; return 0; } diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 909a03d6c0e9..6628e457ddc0 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -396,28 +396,22 @@ static struct attribute_group wireless_group = { #endif /* CONFIG_SYSFS */ #ifdef CONFIG_HOTPLUG -static int netdev_uevent(struct device *d, char **envp, - int num_envp, char *buf, int size) +static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) { struct net_device *dev = to_net_dev(d); - int retval, len = 0, i = 0; + int retval; /* pass interface to uevent. */ - retval = add_uevent_var(envp, num_envp, &i, - buf, size, &len, - "INTERFACE=%s", dev->name); + retval = add_uevent_var(env, "INTERFACE=%s", dev->name); if (retval) goto exit; /* pass ifindex to uevent. * ifindex is useful as it won't change (interface name may change) * and is what RtNetlink uses natively. */ - retval = add_uevent_var(envp, num_envp, &i, - buf, size, &len, - "IFINDEX=%d", dev->ifindex); + retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); exit: - envp[i] = NULL; return retval; } #endif diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 2d5d2255a27c..29f820e18251 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -53,8 +53,7 @@ static void wiphy_dev_release(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int wiphy_uevent(struct device *dev, char **envp, - int num_envp, char *buf, int size) +static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) { /* TODO, we probably need stuff here */ return 0; diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c index 64d163914335..f84f3e505788 100644 --- a/sound/aoa/soundbus/core.c +++ b/sound/aoa/soundbus/core.c @@ -56,13 +56,12 @@ static int soundbus_probe(struct device *dev) } -static int soundbus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct soundbus_dev * soundbus_dev; struct of_device * of; const char *compat; - int retval = 0, i = 0, length = 0; + int retval = 0; int cplen, seen = 0; if (!dev) @@ -75,15 +74,11 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, of = &soundbus_dev->ofdev; /* stuff we want to pass to /sbin/hotplug */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_NAME=%s", of->node->name); + retval = add_uevent_var(env, "OF_NAME=%s", of->node->name); if (retval) return retval; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_TYPE=%s", of->node->type); + retval = add_uevent_var(env, "OF_TYPE=%s", of->node->type); if (retval) return retval; @@ -93,27 +88,19 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, compat = of_get_property(of->node, "compatible", &cplen); while (compat && cplen > 0) { - int tmp = length; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_%d=%s", seen, compat); + int tmp = env->buflen; + retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); if (retval) return retval; - compat += length - tmp; - cplen -= length - tmp; + compat += env->buflen - tmp; + cplen -= env->buflen - tmp; seen += 1; } - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_N=%d", seen); + retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); if (retval) return retval; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", soundbus_dev->modalias); - - envp[i] = NULL; + retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias); return retval; } From 6a8d8abb6e4497ae4132a9b1f0a956ea501f1c46 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 15:38:28 +0200 Subject: [PATCH 2549/2804] Driver core: add CONFIG_UEVENT_HELPER_PATH The kernel creates a process for every event that is send, even when there is no binary it could execute. We are needlessly creating around 200-300 failing processes during early bootup, until we have the chance to disable it from userspace. This change allows us to disable /sbin/hotplug entirely, if you want to, by setting UEVENT_HELPER_PATH="" in the kernel config. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 8 ++++++++ lib/kobject_uevent.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 5d6312e33490..d7da109c24fd 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -1,5 +1,13 @@ menu "Generic Driver Options" +config UEVENT_HELPER_PATH + string "path to uevent helper" + depends on HOTPLUG + default "/sbin/hotplug" + help + Path to uevent helper program forked by the kernel for + every uevent. + config STANDALONE bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL default y diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7d8aeb301635..5ccda460262c 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -35,7 +35,7 @@ const char *kobject_actions[] = { #if defined(CONFIG_HOTPLUG) u64 uevent_seqnum; -char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug"; +char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; static DEFINE_SPINLOCK(sequence_lock); #if defined(CONFIG_NET) static struct sock *uevent_sock; From d6b05b84edf590ff872de6310ec20d60b5b37dd2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: [PATCH 2550/2804] Driver core: remove subsys_set_kset This macro is only used by the driver core and is held over from when we had subsystems. It is not needed anymore. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 3 ++- drivers/base/class.c | 2 +- include/linux/kobject.h | 13 ------------- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index ff850d1b0d92..625f7e694521 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -823,7 +823,8 @@ int bus_register(struct bus_type * bus) if (retval) goto out; - subsys_set_kset(bus, bus_subsys); + bus->subsys.kobj.kset = &bus_subsys; + retval = subsystem_register(&bus->subsys); if (retval) goto out; diff --git a/drivers/base/class.c b/drivers/base/class.c index ecd6336bffea..cf9cf666f472 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -149,7 +149,7 @@ int class_register(struct class * cls) if (error) return error; - subsys_set_kset(cls, class_subsys); + cls->subsys.kobj.kset = &class_subsys; error = subsystem_register(&cls->subsys); if (!error) { diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 626bdd3c3dd9..0713799fde29 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -241,19 +241,6 @@ extern struct kset hypervisor_subsys; #define kset_set_kset_s(obj,subsys) \ (obj)->kset.kobj.kset = &(subsys) -/** - * subsys_set_kset(obj,subsys) - set kset for subsystem - * @obj: ptr to some object type. - * @_subsys: a subsystem object (not a ptr). - * - * Can be used for any object type with an embedded ->subsys. - * Sets the kset of @obj's kobject to @subsys.kset. This makes - * the object a member of that kset. - */ - -#define subsys_set_kset(obj,_subsys) \ - (obj)->subsys.kobj.kset = &(_subsys) - extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); From 27f20e5e4e60a7f28010eeb34399fe0cc9a1a235 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: [PATCH 2551/2804] Driver core: remove kset_set_kset_s This macro is only used by the driver core and is held over from when we had subsystems. It is not needed anymore. Signed-off-by: Greg Kroah-Hartman --- drivers/base/sys.c | 2 +- include/linux/kobject.h | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 18febe26caa1..7ad893167823 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls) kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); cls->kset.kobj.parent = &system_subsys.kobj; - kset_set_kset_s(cls, system_subsys); + cls->kset.kobj.kset = &system_subsys; return kset_register(&cls->kset); } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 0713799fde29..ee61ef27e799 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -227,20 +227,6 @@ extern struct kset hypervisor_subsys; #define kobj_set_kset_s(obj,subsys) \ (obj)->kobj.kset = &(subsys) -/** - * kset_set_kset_s(obj,subsys) - set kset for embedded kset. - * @obj: ptr to some object type. - * @subsys: a subsystem object (not a ptr). - * - * Can be used for any object type with an embedded ->kset. - * Sets the kset of @obj's embedded kobject (via its embedded - * kset) to @subsys.kset. This makes @obj a member of that - * kset. - */ - -#define kset_set_kset_s(obj,subsys) \ - (obj)->kset.kobj.kset = &(subsys) - extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); From 6e9d930d167f8957a12a80515f3c417a98296378 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: [PATCH 2552/2804] Driver core: remove subsys_put() There are no more subsystems, it's a kset now so remove the function and the only two users, which are in the driver core. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 2 +- drivers/base/class.c | 2 +- include/linux/kobject.h | 5 ----- lib/kobject.c | 2 +- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 625f7e694521..2f775936544b 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -734,7 +734,7 @@ struct bus_type *get_bus(struct bus_type *bus) void put_bus(struct bus_type * bus) { - subsys_put(&bus->subsys); + kset_put(&bus->subsys); } diff --git a/drivers/base/class.c b/drivers/base/class.c index cf9cf666f472..50e34132576c 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -100,7 +100,7 @@ static struct class *class_get(struct class *cls) static void class_put(struct class * cls) { if (cls) - subsys_put(&cls->subsys); + kset_put(&cls->subsys); } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index ee61ef27e799..45effedff315 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -238,11 +238,6 @@ static inline struct kset *subsys_get(struct kset *s) return NULL; } -static inline void subsys_put(struct kset *s) -{ - kset_put(s); -} - struct subsys_attribute { struct attribute attr; ssize_t (*show)(struct kset *, char *); diff --git a/lib/kobject.c b/lib/kobject.c index 4b08e0ff95c8..0aa4e906916a 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -681,7 +681,7 @@ int subsys_create_file(struct kset *s, struct subsys_attribute *a) if (subsys_get(s)) { error = sysfs_create_file(&s->kobj, &a->attr); - subsys_put(s); + kset_put(s); } return error; } From 1ef4cfac01fb5e98900f5bdb2a722aac1daff11b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: [PATCH 2553/2804] Driver core: remove subsys_get() There are no more subsystems, it's a kset now so remove the function and the only two users, which are in the driver core. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 2 +- drivers/base/class.c | 2 +- include/linux/kobject.h | 7 ------- lib/kobject.c | 2 +- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2f775936544b..bc38085dbb10 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -728,7 +728,7 @@ EXPORT_SYMBOL_GPL(device_reprobe); struct bus_type *get_bus(struct bus_type *bus) { - return bus ? container_of(subsys_get(&bus->subsys), + return bus ? container_of(kset_get(&bus->subsys), struct bus_type, subsys) : NULL; } diff --git a/drivers/base/class.c b/drivers/base/class.c index 50e34132576c..3e9b04c30fb9 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -93,7 +93,7 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) static struct class *class_get(struct class *cls) { if (cls) - return container_of(subsys_get(&cls->subsys), struct class, subsys); + return container_of(kset_get(&cls->subsys), struct class, subsys); return NULL; } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 45effedff315..c0fb535d7acd 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -231,13 +231,6 @@ extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); -static inline struct kset *subsys_get(struct kset *s) -{ - if (s) - return kset_get(s); - return NULL; -} - struct subsys_attribute { struct attribute attr; ssize_t (*show)(struct kset *, char *); diff --git a/lib/kobject.c b/lib/kobject.c index 0aa4e906916a..1326041213dd 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -679,7 +679,7 @@ int subsys_create_file(struct kset *s, struct subsys_attribute *a) if (!s || !a) return -EINVAL; - if (subsys_get(s)) { + if (kset_get(s)) { error = sysfs_create_file(&s->kobj, &a->attr); kset_put(s); } From fc1ede5888ab8a9b3e7f8567b945beed35222885 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Sep 2007 02:53:13 -0700 Subject: [PATCH 2554/2804] Driver core: remove put_bus() put_bus() should not be globally visable as it is not used by anything other than drivers/base/bus.c. This patch removes the visability of it, and renames it to match all of the other *_put() functions in the kernel. Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 1 - drivers/base/bus.c | 29 ++++++++++++++--------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index 47eb02d9f1af..cebc7e754574 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -19,7 +19,6 @@ extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); extern struct bus_type *get_bus(struct bus_type * bus); -extern void put_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index bc38085dbb10..4f53b758ac2b 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -30,6 +30,11 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +static void bus_put(struct bus_type *bus) +{ + kset_put(&bus->subsys); +} + static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -124,7 +129,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) int error; if (get_bus(bus)) { error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } else error = -EINVAL; return error; @@ -134,7 +139,7 @@ void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { if (get_bus(bus)) { sysfs_remove_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } } @@ -186,7 +191,7 @@ static ssize_t driver_unbind(struct device_driver *drv, err = count; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); @@ -219,7 +224,7 @@ static ssize_t driver_bind(struct device_driver *drv, err = -ENODEV; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); @@ -459,7 +464,7 @@ out_subsys: out_id: device_remove_attrs(bus, dev); out_put: - put_bus(dev->bus); + bus_put(dev->bus); return error; } @@ -509,7 +514,7 @@ void bus_remove_device(struct device * dev) } pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); - put_bus(dev->bus); + bus_put(dev->bus); } } @@ -646,7 +651,7 @@ int bus_add_driver(struct device_driver *drv) out_unregister: kobject_unregister(&drv->kobj); out_put_bus: - put_bus(bus); + bus_put(bus); return error; } @@ -671,7 +676,7 @@ void bus_remove_driver(struct device_driver * drv) driver_detach(drv); module_remove_driver(drv); kobject_unregister(&drv->kobj); - put_bus(drv->bus); + bus_put(drv->bus); } @@ -732,12 +737,6 @@ struct bus_type *get_bus(struct bus_type *bus) struct bus_type, subsys) : NULL; } -void put_bus(struct bus_type * bus) -{ - kset_put(&bus->subsys); -} - - /** * find_bus - locate bus by name. * @name: name of bus. @@ -874,7 +873,7 @@ out: * @bus: bus. * * Unregister the child subsystems and the bus itself. - * Finally, we call put_bus() to release the refcount + * Finally, we call bus_put() to release the refcount */ void bus_unregister(struct bus_type * bus) { From 5901d0145c6b9e791bacd049eea11c9db9a3006e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Sep 2007 02:53:13 -0700 Subject: [PATCH 2555/2804] Driver core: remove get_bus() get_bus() should not be globally visable as it is not used by anything other than drivers/base/bus.c. This patch removes the visability of it, and renames it to match all of the other *_get() functions in the kernel. Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 1 - drivers/base/bus.c | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index cebc7e754574..10b2fb6c9ce6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -18,7 +18,6 @@ extern int attribute_container_init(void); extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); -extern struct bus_type *get_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 4f53b758ac2b..0a8d075f3e6c 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -30,6 +30,12 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +static struct bus_type *bus_get(struct bus_type *bus) +{ + return bus ? container_of(kset_get(&bus->subsys), + struct bus_type, subsys) : NULL; +} + static void bus_put(struct bus_type *bus) { kset_put(&bus->subsys); @@ -127,7 +133,7 @@ static struct sysfs_ops bus_sysfs_ops = { int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) { int error; - if (get_bus(bus)) { + if (bus_get(bus)) { error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); bus_put(bus); } else @@ -137,7 +143,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { - if (get_bus(bus)) { + if (bus_get(bus)) { sysfs_remove_file(&bus->subsys.kobj, &attr->attr); bus_put(bus); } @@ -177,7 +183,7 @@ static int driver_helper(struct device *dev, void *data) static ssize_t driver_unbind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -204,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); static ssize_t driver_bind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -435,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } */ int bus_add_device(struct device * dev) { - struct bus_type * bus = get_bus(dev->bus); + struct bus_type * bus = bus_get(dev->bus); int error = 0; if (bus) { @@ -611,7 +617,7 @@ static inline void remove_probe_files(struct bus_type *bus) {} */ int bus_add_driver(struct device_driver *drv) { - struct bus_type * bus = get_bus(drv->bus); + struct bus_type * bus = bus_get(drv->bus); int error = 0; if (!bus) @@ -731,12 +737,6 @@ int device_reprobe(struct device *dev) } EXPORT_SYMBOL_GPL(device_reprobe); -struct bus_type *get_bus(struct bus_type *bus) -{ - return bus ? container_of(kset_get(&bus->subsys), - struct bus_type, subsys) : NULL; -} - /** * find_bus - locate bus by name. * @name: name of bus. From 19c38de88a80913351fcacefdb461cc0b585fa87 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: [PATCH 2556/2804] kobjects: fix up improper use of the kobject name field A number of different drivers incorrect access the kobject name field directly. This is not correct as the name might not be in the array. Use the proper accessor function instead. --- block/elevator.c | 2 +- block/ll_rw_blk.c | 2 +- drivers/acpi/bus.c | 2 +- drivers/cpufreq/cpufreq.c | 2 +- drivers/md/md.c | 3 +-- drivers/net/ibmveth.c | 2 +- drivers/pci/setup-irq.c | 2 +- fs/partitions/check.c | 12 +++++++----- fs/sysfs/dir.c | 2 +- net/bridge/br_sysfs_br.c | 2 +- 10 files changed, 16 insertions(+), 15 deletions(-) diff --git a/block/elevator.c b/block/elevator.c index c6d153de9fd6..b9c518afe1f8 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -186,7 +186,7 @@ static elevator_t *elevator_alloc(struct request_queue *q, eq->ops = &e->ops; eq->elevator_type = e; kobject_init(&eq->kobj); - snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); + kobject_set_name(&eq->kobj, "%s", "iosched"); eq->kobj.ktype = &elv_ktype; mutex_init(&eq->sysfs_lock); diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index cd9d2c5d91ae..d875673e76cd 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1854,7 +1854,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) init_timer(&q->unplug_timer); - snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue"); + kobject_set_name(&q->kobj, "%s", "queue"); q->kobj.ktype = &queue_ktype; kobject_init(&q->kobj); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index feab124d8e05..cbfc81579c9a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -194,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - device->dev.kobj.name)); + kobject_name(&device->dev.kobj))); return -ENODEV; } /* diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2f6a73c01b71..2ce3de5e84af 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -828,7 +828,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* prepare interface data */ policy->kobj.parent = &sys_dev->kobj; policy->kobj.ktype = &ktype_cpufreq; - strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN); + kobject_set_name(&policy->kobj, "cpufreq"); ret = kobject_register(&policy->kobj); if (ret) { diff --git a/drivers/md/md.c b/drivers/md/md.c index e8f102ea9b03..acf1b81b47cb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3076,8 +3076,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) mddev->gendisk = disk; mutex_unlock(&disks_mutex); mddev->kobj.parent = &disk->kobj; - mddev->kobj.k_name = NULL; - snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md"); + kobject_set_name(&mddev->kobj, "%s", "md"); mddev->kobj.ktype = &md_ktype; if (kobject_register(&mddev->kobj)) printk(KERN_WARNING "md: cannot register %s/md - name in use\n", diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 4ac161e1ca12..7d7758f3ad8c 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1183,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ pool_count[i], pool_size[i], pool_active[i]); kobj->parent = &dev->dev.kobj; - sprintf(kobj->name, "pool%d", i); + kobject_set_name(kobj, "pool%d", i); kobj->ktype = &ktype_veth_pool; kobject_register(kobj); } diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 568f1877315c..05ca2ed9eb51 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev, dev->irq = irq; pr_debug("PCI: fixup irq: (%s) got %d\n", - dev->dev.kobj.name, dev->irq); + kobject_name(&dev->dev.kobj), dev->irq); /* Always tell the device, so the driver knows what is the real IRQ to use; the device does not use it. */ diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 783c57ec07d3..722e12e5acc7 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -381,10 +381,12 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, p->partno = part; p->policy = disk->policy; - if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) - snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); + if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1])) + kobject_set_name(&p->kobj, "%sp%d", + kobject_name(&disk->kobj), part); else - snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); + kobject_set_name(&p->kobj, "%s%d", + kobject_name(&disk->kobj),part); p->kobj.parent = &disk->kobj; p->kobj.ktype = &ktype_part; kobject_init(&p->kobj); @@ -477,9 +479,9 @@ void register_disk(struct gendisk *disk) struct hd_struct *p; int err; - strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); + kobject_set_name(&disk->kobj, "%s", disk->disk_name); /* ewww... some of these buggers have / in name... */ - s = strchr(disk->kobj.name, '/'); + s = strchr(disk->kobj.k_name, '/'); if (s) *s = '!'; if ((err = kobject_add(&disk->kobj))) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 83e76b3813c9..ea33b660ae8a 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1013,7 +1013,7 @@ again: goto again; } - new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name)); + new_dentry = lookup_one_len(kobject_name(kobj), new_parent, strlen(kobject_name(kobj))); if (IS_ERR(new_dentry)) { error = PTR_ERR(new_dentry); goto out_unlock; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index c65f54e0e27f..3312e8f2abe4 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -435,7 +435,7 @@ int br_sysfs_addbr(struct net_device *dev) err = kobject_register(&br->ifobj); if (err) { pr_info("%s: can't add kobject (directory) %s/%s\n", - __FUNCTION__, dev->name, br->ifobj.name); + __FUNCTION__, dev->name, kobject_name(&br->ifobj)); goto out3; } return 0; From 7e7654a92a5a75a350cc3458389bc76273498f6a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: [PATCH 2557/2804] cdev: remove unneeded setting of cdev names struct cdev does not need the kobject name to be set, as it is never used. This patch fixes up the few places it is set. Signed-off-by: Greg Kroah-Hartman Acked-by: Mauro Carvalho Chehab --- block/bsg.c | 5 +---- drivers/char/raw.c | 5 +---- drivers/media/dvb/dvb-core/dvbdev.c | 5 +---- drivers/usb/core/devio.c | 6 ++---- 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/block/bsg.c b/block/bsg.c index ed2646827234..b8ddfc66f210 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -1010,10 +1010,7 @@ unlock: } EXPORT_SYMBOL_GPL(bsg_register_queue); -static struct cdev bsg_cdev = { - .kobj = {.name = "bsg", }, - .owner = THIS_MODULE, -}; +static struct cdev bsg_cdev; static int __init bsg_init(void) { diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 1f0d7c60c944..bbfa0e241cba 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = { .owner = THIS_MODULE, }; -static struct cdev raw_cdev = { - .kobj = {.name = "raw", }, - .owner = THIS_MODULE, -}; +static struct cdev raw_cdev; static int __init raw_init(void) { diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 56231d8edc07..18738faecbbc 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -103,10 +103,7 @@ static struct file_operations dvb_device_fops = .open = dvb_device_open, }; -static struct cdev dvb_device_cdev = { - .kobj = {.name = "dvb", }, - .owner = THIS_MODULE, -}; +static struct cdev dvb_device_cdev; int dvb_generic_open(struct inode *inode, struct file *file) { diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 927a181120a9..fe98796d2ff1 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1576,6 +1576,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai } const struct file_operations usbdev_file_operations = { + .owner = THIS_MODULE, .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, @@ -1625,10 +1626,7 @@ static struct notifier_block usbdev_nb = { }; #endif -static struct cdev usb_device_cdev = { - .kobj = {.name = "usb_device", }, - .owner = THIS_MODULE, -}; +static struct cdev usb_device_cdev; int __init usb_devio_init(void) { From 34980ca8faebfcce31094eba6ffbb0113950361f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: [PATCH 2558/2804] Drivers: clean up direct setting of the name of a kset A kset should not have its name set directly, so dynamically set the name at runtime. This is needed to remove the static array in the kobject structure which will be changed in a future patch. Signed-off-by: Greg Kroah-Hartman --- drivers/edac/edac_mc_sysfs.c | 3 ++- drivers/pci/hotplug/rpadlpar_sysfs.c | 6 +++--- fs/dlm/lockspace.c | 2 +- fs/gfs2/locking/dlm/sysfs.c | 2 +- fs/gfs2/sys.c | 2 +- fs/ocfs2/cluster/masklog.c | 3 ++- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4a0576bd06fc..3706b2bc0987 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -743,7 +743,7 @@ static struct kobj_type ktype_mc_set_attribs = { * /sys/devices/system/edac/mc */ static struct kset mc_kset = { - .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs }, + .kobj = {.ktype = &ktype_mc_set_attribs }, .ktype = &ktype_mci, }; @@ -1010,6 +1010,7 @@ int edac_sysfs_setup_mc_kset(void) } /* Init the MC's kobject */ + kobject_set_name(&mc_kset.kobj, "mc"); mc_kset.kobj.parent = &edac_class->kset.kobj; /* register the mc_kset */ diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index df076064a3e0..a080fedf0332 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = { }; struct kset dlpar_io_kset = { - .kobj = {.name = DLPAR_KOBJ_NAME, - .ktype = &ktype_dlpar_io, + .kobj = {.ktype = &ktype_dlpar_io, .parent = &pci_hotplug_slots_subsys.kobj}, .ktype = &ktype_dlpar_io, }; int dlpar_sysfs_init(void) { + kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME); if (kset_register(&dlpar_io_kset)) { printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n", - dlpar_io_kset.kobj.name); + kobject_name(&dlpar_io_kset.kobj)); return -EINVAL; } diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 1dc72105ab12..f88f88fdedf1 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -167,7 +167,6 @@ static struct kobj_type dlm_ktype = { }; static struct kset dlm_kset = { - .kobj = {.name = "dlm",}, .ktype = &dlm_ktype, }; @@ -228,6 +227,7 @@ int dlm_lockspace_init(void) INIT_LIST_HEAD(&lslist); spin_lock_init(&lslist_lock); + kobject_set_name(&dlm_kset.kobj, "dlm"); kobj_set_kset_s(&dlm_kset, kernel_subsys); error = kset_register(&dlm_kset); if (error) diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index d9fe3ca40e18..ae9e6a25fe2b 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = { }; static struct kset gdlm_kset = { - .kobj = {.name = "lock_dlm",}, .ktype = &gdlm_ktype, }; @@ -224,6 +223,7 @@ int gdlm_sysfs_init(void) { int error; + kobject_set_name(&gdlm_kset.kobj, "lock_dlm"); kobj_set_kset_s(&gdlm_kset, kernel_subsys); error = kset_register(&gdlm_kset); if (error) diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index c26c21b53c19..640cb6a6fc4c 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -222,7 +222,6 @@ static struct kobj_type gfs2_ktype = { }; static struct kset gfs2_kset = { - .kobj = {.name = "gfs2"}, .ktype = &gfs2_ktype, }; @@ -553,6 +552,7 @@ int gfs2_sys_init(void) { gfs2_sys_margs = NULL; spin_lock_init(&gfs2_sys_margs_lock); + kobject_set_name(&gfs2_kset.kobj, "gfs2"); kobj_set_kset_s(&gfs2_kset, fs_subsys); return kset_register(&gfs2_kset); } diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index e9e042b93dbf..a4882c8df945 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c @@ -143,7 +143,7 @@ static struct kobj_type mlog_ktype = { }; static struct kset mlog_kset = { - .kobj = {.name = "logmask", .ktype = &mlog_ktype}, + .kobj = {.ktype = &mlog_ktype}, }; int mlog_sys_init(struct kset *o2cb_subsys) @@ -156,6 +156,7 @@ int mlog_sys_init(struct kset *o2cb_subsys) } mlog_attr_ptrs[i] = NULL; + kobject_set_name(&mlog_kset.kobj, "logmask"); kobj_set_kset_s(&mlog_kset, *o2cb_subsys); return kset_register(&mlog_kset); } From ce2c9cb0259acd2aed184499ebe41ab00da13b25 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: [PATCH 2559/2804] kobject: remove the static array for the name Due to historical reasons, struct kobject contained a static array for the name, and a dynamic pointer in case the name got bigger than the array. That's just dumb, as people didn't always know which variable to reference, even with the accessor for the kobject name. This patch removes the static array, potentially saving a lot of memory as the majority of kobjects do not have a very long name. Thanks to Kay for the idea to do this. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/kobject.h | 7 ++-- lib/kobject.c | 77 ++++++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/include/linux/kobject.h b/include/linux/kobject.h index c0fb535d7acd..8b45946e8506 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -63,7 +63,6 @@ extern const char *kobject_actions[]; struct kobject { const char * k_name; - char name[KOBJ_NAME_LEN]; struct kref kref; struct list_head entry; struct kobject * parent; @@ -188,18 +187,18 @@ extern struct kobject * kset_find_obj(struct kset *, const char *); * Use this when initializing an embedded kset with no other * fields to initialize. */ -#define set_kset_name(str) .kset = { .kobj = { .name = str } } +#define set_kset_name(str) .kset = { .kobj = { .k_name = str } } #define decl_subsys(_name,_type,_uevent_ops) \ struct kset _name##_subsys = { \ - .kobj = { .name = __stringify(_name) }, \ + .kobj = { .k_name = __stringify(_name) }, \ .ktype = _type, \ .uevent_ops =_uevent_ops, \ } #define decl_subsys_name(_varname,_name,_type,_uevent_ops) \ struct kset _varname##_subsys = { \ - .kobj = { .name = __stringify(_name) }, \ + .kobj = { .k_name = __stringify(_name) }, \ .ktype = _type, \ .uevent_ops =_uevent_ops, \ } diff --git a/lib/kobject.c b/lib/kobject.c index 1326041213dd..10ae2ebeaf96 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -170,7 +170,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) if (!(kobj = kobject_get(kobj))) return -ENOENT; if (!kobj->k_name) - kobj->k_name = kobj->name; + kobject_set_name(kobj, "NO_NAME"); if (!*kobj->k_name) { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); @@ -181,7 +181,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) pr_debug("kobject %s: registering. parent: %s, set: %s\n", kobject_name(kobj), parent ? kobject_name(parent) : "", - kobj->kset ? kobj->kset->kobj.name : "" ); + kobj->kset ? kobject_name(&kobj->kset->kobj) : "" ); if (kobj->kset) { spin_lock(&kobj->kset->list_lock); @@ -255,54 +255,50 @@ int kobject_register(struct kobject * kobj) int kobject_set_name(struct kobject * kobj, const char * fmt, ...) { int error = 0; - int limit = KOBJ_NAME_LEN; + int limit; int need; va_list args; - char * name; + char *name; - /* - * First, try the static array - */ - va_start(args,fmt); - need = vsnprintf(kobj->name,limit,fmt,args); + /* find out how big a buffer we need */ + name = kmalloc(1024, GFP_KERNEL); + if (!name) { + error = -ENOMEM; + goto done; + } + va_start(args, fmt); + need = vsnprintf(name, 1024, fmt, args); va_end(args); - if (need < limit) - name = kobj->name; - else { - /* - * Need more space? Allocate it and try again - */ - limit = need + 1; - name = kmalloc(limit,GFP_KERNEL); - if (!name) { - error = -ENOMEM; - goto Done; - } - va_start(args,fmt); - need = vsnprintf(name,limit,fmt,args); - va_end(args); + kfree(name); - /* Still? Give up. */ - if (need >= limit) { - kfree(name); - error = -EFAULT; - goto Done; - } + /* Allocate the new space and copy the string in */ + limit = need + 1; + name = kmalloc(limit, GFP_KERNEL); + if (!name) { + error = -ENOMEM; + goto done; + } + va_start(args, fmt); + need = vsnprintf(name, limit, fmt, args); + va_end(args); + + /* something wrong with the string we copied? */ + if (need >= limit) { + kfree(name); + error = -EFAULT; + goto done; } /* Free the old name, if necessary. */ - if (kobj->k_name && kobj->k_name != kobj->name) - kfree(kobj->k_name); + kfree(kobj->k_name); /* Now, set the new name */ kobj->k_name = name; - Done: +done: return error; } - EXPORT_SYMBOL(kobject_set_name); - /** * kobject_rename - change the name of an object * @kobj: object in question. @@ -477,13 +473,16 @@ void kobject_cleanup(struct kobject * kobj) struct kobj_type * t = get_ktype(kobj); struct kset * s = kobj->kset; struct kobject * parent = kobj->parent; + const char *name = kobj->k_name; pr_debug("kobject %s: cleaning up\n",kobject_name(kobj)); - if (kobj->k_name != kobj->name) - kfree(kobj->k_name); - kobj->k_name = NULL; - if (t && t->release) + if (t && t->release) { t->release(kobj); + /* If we have a release function, we can guess that this was + * not a statically allocated kobject, so we should be safe to + * free the name */ + kfree(name); + } if (s) kset_put(s); kobject_put(parent); From d716551e188787effb08bf87a846404cfd239a8b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 14 Sep 2007 13:25:19 +0200 Subject: [PATCH 2560/2804] Driver core: clean up removed functions from the documentation Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- Documentation/kobject.txt | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index 8ee49ee7c963..5e7aca261359 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -54,7 +54,6 @@ embedded in larger data structures and replace fields they duplicate. struct kobject { const char * k_name; - char name[KOBJ_NAME_LEN]; struct kref kref; struct list_head entry; struct kobject * parent; @@ -223,18 +222,15 @@ decl_subsys(devices, &ktype_device, &device_uevent_ops); is equivalent to doing: struct kset devices_subsys = { - .kobj = { - .name = "devices", - }, .ktype = &ktype_devices, .uevent_ops = &device_uevent_ops, }; - +kobject_set_name(&devices_subsys, name); The objects that are registered with a subsystem that use the subsystem's default list must have their kset ptr set properly. These objects may have embedded kobjects or ksets. The -following helpers make setting the kset easier: +following helper makes setting the kset easier: kobj_set_kset_s(obj,subsys) @@ -242,22 +238,9 @@ kobj_set_kset_s(obj,subsys) - Assumes that obj->kobj exists, and is a struct kobject. - Sets the kset of that kobject to the kset . - -kset_set_kset_s(obj,subsys) - -- Assumes that obj->kset exists, and is a struct kset. -- Sets the kset of the embedded kobject to the kset . - -subsys_set_kset(obj,subsys) - -- Assumes obj->subsys exists, and is a struct subsystem. -- Sets obj->subsys.kset.kobj.kset to the subsystem's embedded kset. - void subsystem_init(struct kset *s); int subsystem_register(struct kset *s); void subsystem_unregister(struct kset *s); -struct kset *subsys_get(struct kset *s); -void kset_put(struct kset *s); These are just wrappers around the respective kset_* functions. From 2ebefc50161a0a1cdebccd62be749e72abdbec37 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Thu, 2 Aug 2007 18:23:50 -0400 Subject: [PATCH 2561/2804] debugfs: helper for decimal challenged Allows debugfs helper functions to have a hex output, rather than just decimal Signed-off-by: Robin Getz Signed-off-by: Greg Kroah-Hartman --- fs/debugfs/file.c | 36 ++++++++++++++++++++++++++++++++++++ include/linux/debugfs.h | 27 +++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 2e124e0075c5..a9b99c0dc2e7 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -221,6 +221,42 @@ struct dentry *debugfs_create_u64(const char *name, mode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_u64); +DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n"); + +DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n"); + +DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"); + +/** + * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value + * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value + * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value + * + * These functions are exactly the same as the above functions, (but use a hex + * output for the decimal challenged) for details look at the above unsigned + * decimal functions. + */ +struct dentry *debugfs_create_x8(const char *name, mode_t mode, + struct dentry *parent, u8 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x8); +} +EXPORT_SYMBOL_GPL(debugfs_create_x8); + +struct dentry *debugfs_create_x16(const char *name, mode_t mode, + struct dentry *parent, u16 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x16); +} +EXPORT_SYMBOL_GPL(debugfs_create_x16); + +struct dentry *debugfs_create_x32(const char *name, mode_t mode, + struct dentry *parent, u32 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x32); +} +EXPORT_SYMBOL_GPL(debugfs_create_x32); + static ssize_t read_file_bool(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 104e51e20e14..f592d6de3b97 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -49,6 +49,12 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode, struct dentry *parent, u32 *value); struct dentry *debugfs_create_u64(const char *name, mode_t mode, struct dentry *parent, u64 *value); +struct dentry *debugfs_create_x8(const char *name, mode_t mode, + struct dentry *parent, u8 *value); +struct dentry *debugfs_create_x16(const char *name, mode_t mode, + struct dentry *parent, u16 *value); +struct dentry *debugfs_create_x32(const char *name, mode_t mode, + struct dentry *parent, u32 *value); struct dentry *debugfs_create_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value); @@ -122,6 +128,27 @@ static inline struct dentry *debugfs_create_u64(const char *name, mode_t mode, return ERR_PTR(-ENODEV); } +static inline struct dentry *debugfs_create_x8(const char *name, mode_t mode, + struct dentry *parent, + u8 *value) +{ + return ERR_PTR(-ENODEV); +} + +static inline struct dentry *debugfs_create_x16(const char *name, mode_t mode, + struct dentry *parent, + u16 *value) +{ + return ERR_PTR(-ENODEV); +} + +static inline struct dentry *debugfs_create_x32(const char *name, mode_t mode, + struct dentry *parent, + u32 *value) +{ + return ERR_PTR(-ENODEV); +} + static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value) From 52e8c209d6d2bae6766b9940a107c73e943583f1 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Thu, 26 Jul 2007 11:03:54 +0000 Subject: [PATCH 2562/2804] sysfs/file.c - use mutex instead of semaphore Use mutex instead of semaphore in sysfs/file.c : sys_buffer. Signed-off-by: Dave Young Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 3e1cc062a740..b21d11b46754 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include "sysfs.h" @@ -55,7 +55,7 @@ struct sysfs_buffer { loff_t pos; char * page; struct sysfs_ops * ops; - struct semaphore sem; + struct mutex mutex; int needs_read_fill; int event; }; @@ -128,7 +128,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct sysfs_buffer * buffer = file->private_data; ssize_t retval = 0; - down(&buffer->sem); + mutex_lock(&buffer->mutex); if (buffer->needs_read_fill) { retval = fill_read_buffer(file->f_path.dentry,buffer); if (retval) @@ -139,7 +139,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) retval = simple_read_from_buffer(buf, count, ppos, buffer->page, buffer->count); out: - up(&buffer->sem); + mutex_unlock(&buffer->mutex); return retval; } @@ -228,13 +228,13 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t struct sysfs_buffer * buffer = file->private_data; ssize_t len; - down(&buffer->sem); + mutex_lock(&buffer->mutex); len = fill_write_buffer(buffer, buf, count); if (len > 0) len = flush_write_buffer(file->f_path.dentry, buffer, len); if (len > 0) *ppos += len; - up(&buffer->sem); + mutex_unlock(&buffer->mutex); return len; } @@ -294,7 +294,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) if (!buffer) goto err_out; - init_MUTEX(&buffer->sem); + mutex_init(&buffer->mutex); buffer->needs_read_fill = 1; buffer->ops = ops; file->private_data = buffer; From 869512ab5ab93e5e82ad7d4aaf4ed098d23bfc3f Mon Sep 17 00:00:00 2001 From: Dave Young Date: Thu, 26 Jul 2007 14:53:53 +0000 Subject: [PATCH 2563/2804] sysfs: cleanup semaphore.h Cleanup semaphore.h Signed-off-by: Dave Young Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/bin.c | 2 +- fs/sysfs/dir.c | 2 +- fs/sysfs/group.c | 1 - fs/sysfs/inode.c | 1 - fs/sysfs/mount.c | 1 - fs/sysfs/symlink.c | 2 +- 6 files changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 5afe2a26f5d8..a819a7e8d74d 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -14,9 +14,9 @@ #include #include #include +#include #include -#include #include "sysfs.h" diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index ea33b660ae8a..86d75e08de60 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "sysfs.h" DEFINE_MUTEX(sysfs_mutex); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index f318b73c790c..e6b904d71633 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 10d1b52899f1..aecb6e771e2a 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "sysfs.h" extern struct super_block * sysfs_sb; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index fbc7b65fe262..69a73ae307fe 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "sysfs.h" diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 4ce687f0b5d0..90484533801e 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "sysfs.h" From 90bc61359de0148f8627073d68a22edc7ed9893d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 31 Jul 2007 19:15:08 +0900 Subject: [PATCH 2564/2804] sysfs: Remove first pass at shadow directory support While shadow directories appear to be a good idea, the current scheme of controlling their creation and destruction outside of sysfs appears to be a locking and maintenance nightmare in the face of sysfs directories dynamically coming and going. Which can now occur for directories containing network devices when CONFIG_SYSFS_DEPRECATED is not set. This patch removes everything from the initial shadow directory support that allowed the shadow directory creation to be controlled at a higher level. So except for a few bits of sysfs_rename_dir everything from commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 is now gone. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 167 ++++++---------------------------------- fs/sysfs/group.c | 1 - fs/sysfs/inode.c | 10 --- fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 6 -- include/linux/kobject.h | 5 -- include/linux/sysfs.h | 27 +------ lib/kobject.c | 44 ++--------- 8 files changed, 33 insertions(+), 229 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 86d75e08de60..837073dbadf4 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -569,9 +569,6 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd) spin_unlock(&dcache_lock); spin_unlock(&sysfs_assoc_lock); - /* dentries for shadowed inodes are pinned, unpin */ - if (dentry && sysfs_is_shadowed_inode(dentry->d_inode)) - dput(dentry); dput(dentry); /* adjust nlink and update timestamp */ @@ -723,19 +720,15 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, /** * sysfs_create_dir - create a directory for an object. * @kobj: object we're creating directory for. - * @shadow_parent: parent object. */ -int sysfs_create_dir(struct kobject *kobj, - struct sysfs_dirent *shadow_parent_sd) +int sysfs_create_dir(struct kobject * kobj) { struct sysfs_dirent *parent_sd, *sd; int error = 0; BUG_ON(!kobj); - if (shadow_parent_sd) - parent_sd = shadow_parent_sd; - else if (kobj->parent) + if (kobj->parent) parent_sd = kobj->parent->sd; else if (sysfs_mount && sysfs_mount->mnt_sb) parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; @@ -890,45 +883,44 @@ void sysfs_remove_dir(struct kobject * kobj) __sysfs_remove_dir(sd); } -int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, - const char *new_name) +int sysfs_rename_dir(struct kobject * kobj, const char *new_name) { - struct sysfs_dirent *sd = kobj->sd; - struct dentry *new_parent = NULL; + struct sysfs_dirent *sd; + struct dentry *parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; + struct sysfs_dirent *parent_sd; const char *dup_name = NULL; int error; + if (!kobj->parent) + return -EINVAL; + /* get dentries */ + sd = kobj->sd; old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); goto out_dput; } - new_parent = sysfs_get_dentry(new_parent_sd); - if (IS_ERR(new_parent)) { - error = PTR_ERR(new_parent); + parent_sd = kobj->parent->sd; + parent = sysfs_get_dentry(parent_sd); + if (IS_ERR(parent)) { + error = PTR_ERR(parent); goto out_dput; } - /* lock new_parent and get dentry for new name */ - mutex_lock(&new_parent->d_inode->i_mutex); + /* lock parent and get dentry for new name */ + mutex_lock(&parent->d_inode->i_mutex); - new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); + new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); if (IS_ERR(new_dentry)) { error = PTR_ERR(new_dentry); goto out_unlock; } - /* By allowing two different directories with the same - * d_parent we allow this routine to move between different - * shadows of the same directory - */ error = -EINVAL; - if (old_dentry->d_parent->d_inode != new_parent->d_inode || - new_dentry->d_parent->d_inode != new_parent->d_inode || - old_dentry == new_dentry) + if (old_dentry == new_dentry) goto out_unlock; error = -EEXIST; @@ -955,9 +947,9 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, d_move(sd->s_dentry, new_dentry); sysfs_unlink_sibling(sd); - sysfs_get(new_parent_sd); + sysfs_get(parent_sd); sysfs_put(sd->s_parent); - sd->s_parent = new_parent_sd; + sd->s_parent = parent_sd; sysfs_link_sibling(sd); mutex_unlock(&sysfs_mutex); @@ -968,10 +960,10 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, out_drop: d_drop(new_dentry); out_unlock: - mutex_unlock(&new_parent->d_inode->i_mutex); + mutex_unlock(&parent->d_inode->i_mutex); out_dput: kfree(dup_name); - dput(new_parent); + dput(parent); dput(old_dentry); dput(new_dentry); return error; @@ -1192,121 +1184,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) return offset; } - -/** - * sysfs_make_shadowed_dir - Setup so a directory can be shadowed - * @kobj: object we're creating shadow of. - */ - -int sysfs_make_shadowed_dir(struct kobject *kobj, - void * (*follow_link)(struct dentry *, struct nameidata *)) -{ - struct dentry *dentry; - struct inode *inode; - struct inode_operations *i_op; - - /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */ - dentry = sysfs_get_dentry(kobj->sd); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - inode = dentry->d_inode; - if (inode->i_op != &sysfs_dir_inode_operations) { - dput(dentry); - return -EINVAL; - } - - i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); - if (!i_op) - return -ENOMEM; - - memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op)); - i_op->follow_link = follow_link; - - /* Locking of inode->i_op? - * Since setting i_op is a single word write and they - * are atomic we should be ok here. - */ - inode->i_op = i_op; - return 0; -} - -/** - * sysfs_create_shadow_dir - create a shadow directory for an object. - * @kobj: object we're creating directory for. - * - * sysfs_make_shadowed_dir must already have been called on this - * directory. - */ - -struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) -{ - struct sysfs_dirent *parent_sd = kobj->sd->s_parent; - struct dentry *dir, *parent, *shadow; - struct inode *inode; - struct sysfs_dirent *sd; - struct sysfs_addrm_cxt acxt; - - dir = sysfs_get_dentry(kobj->sd); - if (IS_ERR(dir)) { - sd = (void *)dir; - goto out; - } - parent = dir->d_parent; - - inode = dir->d_inode; - sd = ERR_PTR(-EINVAL); - if (!sysfs_is_shadowed_inode(inode)) - goto out_dput; - - shadow = d_alloc(parent, &dir->d_name); - if (!shadow) - goto nomem; - - sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR); - if (!sd) - goto nomem; - sd->s_elem.dir.kobj = kobj; - - sysfs_addrm_start(&acxt, parent_sd); - - /* add but don't link into children list */ - sysfs_add_one(&acxt, sd); - - /* attach and instantiate dentry */ - sysfs_attach_dentry(sd, shadow); - d_instantiate(shadow, igrab(inode)); - inc_nlink(inode); /* tj: synchronization? */ - - sysfs_addrm_finish(&acxt); - - dget(shadow); /* Extra count - pin the dentry in core */ - - goto out_dput; - - nomem: - dput(shadow); - sd = ERR_PTR(-ENOMEM); - out_dput: - dput(dir); - out: - return sd; -} - -/** - * sysfs_remove_shadow_dir - remove an object's directory. - * @shadow_sd: sysfs_dirent of shadow directory - * - * The only thing special about this is that we remove any files in - * the directory before we remove the directory, and we've inlined - * what used to be sysfs_rmdir() below, instead of calling separately. - */ - -void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd) -{ - __sysfs_remove_dir(shadow_sd); -} - const struct file_operations sysfs_dir_operations = { .open = sysfs_dir_open, .release = sysfs_dir_close, diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index e6b904d71633..d1972374655a 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index aecb6e771e2a..45128b79bc68 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -33,16 +33,6 @@ static const struct inode_operations sysfs_inode_operations ={ .setattr = sysfs_setattr, }; -void sysfs_delete_inode(struct inode *inode) -{ - /* Free the shadowed directory inode operations */ - if (sysfs_is_shadowed_inode(inode)) { - kfree(inode->i_op); - inode->i_op = NULL; - } - return generic_delete_inode(inode); -} - int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) { struct inode * inode = dentry->d_inode; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 69a73ae307fe..119f39da1ae1 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -20,7 +20,7 @@ struct kmem_cache *sysfs_dir_cachep; static const struct super_operations sysfs_ops = { .statfs = simple_statfs, - .drop_inode = sysfs_delete_inode, + .drop_inode = generic_delete_inode, }; struct sysfs_dirent sysfs_root = { diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6b8c8d76d308..b55e510ea239 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -70,7 +70,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); -extern void sysfs_delete_inode(struct inode *inode); extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); @@ -121,8 +120,3 @@ static inline void sysfs_put(struct sysfs_dirent * sd) if (sd && atomic_dec_and_test(&sd->s_count)) release_sysfs_dirent(sd); } - -static inline int sysfs_is_shadowed_inode(struct inode *inode) -{ - return S_ISDIR(inode->i_mode) && inode->i_op->follow_link; -} diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 8b45946e8506..56f5eaf10ea9 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -84,14 +84,9 @@ extern void kobject_init(struct kobject *); extern void kobject_cleanup(struct kobject *); extern int __must_check kobject_add(struct kobject *); -extern int __must_check kobject_shadow_add(struct kobject *kobj, - struct sysfs_dirent *shadow_parent); extern void kobject_del(struct kobject *); extern int __must_check kobject_rename(struct kobject *, const char *new_name); -extern int __must_check kobject_shadow_rename(struct kobject *kobj, - struct sysfs_dirent *new_parent, - const char *new_name); extern int __must_check kobject_move(struct kobject *, struct kobject *); extern int __must_check kobject_register(struct kobject *); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index be8228e50a27..c16e4c511621 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -17,9 +17,6 @@ struct kobject; struct module; -struct nameidata; -struct dentry; -struct sysfs_dirent; /* FIXME * The *owner field is no longer used, but leave around @@ -94,14 +91,13 @@ extern int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), void *data, struct module *owner); extern int __must_check -sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd); +sysfs_create_dir(struct kobject *); extern void sysfs_remove_dir(struct kobject *); extern int __must_check -sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, - const char *new_name); +sysfs_rename_dir(struct kobject *kobj, const char *new_name); extern int __must_check sysfs_move_dir(struct kobject *, struct kobject *); @@ -138,12 +134,6 @@ void sysfs_remove_file_from_group(struct kobject *kobj, void sysfs_notify(struct kobject * k, char *dir, char *attr); - -extern int sysfs_make_shadowed_dir(struct kobject *kobj, - void * (*follow_link)(struct dentry *, struct nameidata *)); -extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj); -extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd); - extern int __must_check sysfs_init(void); #else /* CONFIG_SYSFS */ @@ -154,8 +144,7 @@ static inline int sysfs_schedule_callback(struct kobject *kobj, return -ENOSYS; } -static inline int sysfs_create_dir(struct kobject *kobj, - struct sysfs_dirent *shadow_parent_sd) +static inline int sysfs_create_dir(struct kobject * kobj) { return 0; } @@ -165,9 +154,7 @@ static inline void sysfs_remove_dir(struct kobject * k) ; } -static inline int sysfs_rename_dir(struct kobject *kobj, - struct sysfs_dirent *new_parent_sd, - const char *new_name) +static inline int sysfs_rename_dir(struct kobject * kobj, const char *new_name) { return 0; } @@ -242,12 +229,6 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr) { } -static inline int sysfs_make_shadowed_dir(struct kobject *kobj, - void * (*follow_link)(struct dentry *, struct nameidata *)) -{ - return 0; -} - static inline int __must_check sysfs_init(void) { return 0; diff --git a/lib/kobject.c b/lib/kobject.c index 10ae2ebeaf96..e8181d3cec34 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj) return error; } -static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent) +static int create_dir(struct kobject * kobj) { int error = 0; if (kobject_name(kobj)) { - error = sysfs_create_dir(kobj, shadow_parent); + error = sysfs_create_dir(kobj); if (!error) { if ((error = populate_dir(kobj))) sysfs_remove_dir(kobj); @@ -157,12 +157,11 @@ static void unlink(struct kobject * kobj) } /** - * kobject_shadow_add - add an object to the hierarchy. + * kobject_add - add an object to the hierarchy. * @kobj: object. - * @shadow_parent: sysfs directory to add to. */ -int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) +int kobject_add(struct kobject * kobj) { int error = 0; struct kobject * parent; @@ -194,7 +193,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) kobj->parent = parent; } - error = create_dir(kobj, shadow_parent); + error = create_dir(kobj); if (error) { /* unlink does the kobject_put() for us */ unlink(kobj); @@ -215,16 +214,6 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) return error; } -/** - * kobject_add - add an object to the hierarchy. - * @kobj: object. - */ -int kobject_add(struct kobject * kobj) -{ - return kobject_shadow_add(kobj, NULL); -} - - /** * kobject_register - initialize and add an object. * @kobj: object in question. @@ -334,7 +323,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name) /* Note : if we want to send the new name alone, not the full path, * we could probably use kobject_name(kobj); */ - error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name); + error = sysfs_rename_dir(kobj, new_name); /* This function is mostly/only used for network interface. * Some hotplug package track interfaces by their name and @@ -350,27 +339,6 @@ out: return error; } -/** - * kobject_rename - change the name of an object - * @kobj: object in question. - * @new_parent: object's new parent - * @new_name: object's new name - */ - -int kobject_shadow_rename(struct kobject *kobj, - struct sysfs_dirent *new_parent, const char *new_name) -{ - int error = 0; - - kobj = kobject_get(kobj); - if (!kobj) - return -EINVAL; - error = sysfs_rename_dir(kobj, new_parent, new_name); - kobject_put(kobj); - - return error; -} - /** * kobject_move - move object to another parent * @kobj: object in question. From a7a0475497f9018e2e28cd421ee467d2ad68643e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:02 +0900 Subject: [PATCH 2565/2804] sysfs: cosmetic changes in sysfs_lookup() * remove space between * and symbol name in variable declaration. * kill unnecessary new line. * kill 'found' and test 'sd' instead. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 837073dbadf4..5da8da806660 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -756,24 +756,19 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret = NULL; - struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; - struct sysfs_dirent * sd; + struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; + struct sysfs_dirent *sd; struct bin_attribute *bin_attr; struct inode *inode; - int found = 0; mutex_lock(&sysfs_mutex); - for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { - if (sysfs_type(sd) && - !strcmp(sd->s_name, dentry->d_name.name)) { - found = 1; + for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) + if (sysfs_type(sd) && !strcmp(sd->s_name, dentry->d_name.name)) break; - } - } /* no such entry */ - if (!found) + if (!sd) goto out_unlock; /* attach dentry and inode */ From ff869de7bf5e76adffebd3a176c1c73bca7eddb7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:02 +0900 Subject: [PATCH 2566/2804] sysfs: simplify sysfs_rename_dir() With the shadow directories gone, sysfs_rename_dir() can be simplified. * parent doesn't need to be grabbed separately. Just access old_dentry->d_parent. * parent sd can never change. Remove code to move under the new parent. * Massage comments a bit. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5da8da806660..9504d4cb63eb 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -883,14 +883,10 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) struct sysfs_dirent *sd; struct dentry *parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; - struct sysfs_dirent *parent_sd; const char *dup_name = NULL; int error; - if (!kobj->parent) - return -EINVAL; - - /* get dentries */ + /* get the original dentry */ sd = kobj->sd; old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { @@ -898,12 +894,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) goto out_dput; } - parent_sd = kobj->parent->sd; - parent = sysfs_get_dentry(parent_sd); - if (IS_ERR(parent)) { - error = PTR_ERR(parent); - goto out_dput; - } + parent = old_dentry->d_parent; /* lock parent and get dentry for new name */ mutex_lock(&parent->d_inode->i_mutex); @@ -933,22 +924,14 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) goto out_drop; mutex_lock(&sysfs_mutex); - dup_name = sd->s_name; sd->s_name = new_name; + mutex_unlock(&sysfs_mutex); - /* move under the new parent */ + /* rename */ d_add(new_dentry, NULL); d_move(sd->s_dentry, new_dentry); - sysfs_unlink_sibling(sd); - sysfs_get(parent_sd); - sysfs_put(sd->s_parent); - sd->s_parent = parent_sd; - sysfs_link_sibling(sd); - - mutex_unlock(&sysfs_mutex); - error = 0; goto out_unlock; @@ -958,7 +941,6 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) mutex_unlock(&parent->d_inode->i_mutex); out_dput: kfree(dup_name); - dput(parent); dput(old_dentry); dput(new_dentry); return error; From 41fc1c27452e041a18e5141b8203ee0ea72bc483 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:03 +0900 Subject: [PATCH 2567/2804] sysfs: make sysfs_add/remove_one() call link/unlink_sibling() implictly When adding or removing a sysfs_dirent, the user used to be required to call link/unlink separately. It was for two reasons - code looked like that before sysfs_addrm_cxt conversion and to avoid looping through parent_sd->children list twice during removal. Performance optimization during removal just isn't worth it. Make sysfs_add/remove_one() call sysfs_link/unlink_sibing() implicitly. This makes code simpler albeit slightly less efficient. This change doesn't introduce any noticeable behavior change. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 21 ++++++++++----------- fs/sysfs/file.c | 4 +--- fs/sysfs/inode.c | 17 ++++------------- fs/sysfs/symlink.c | 4 +--- fs/sysfs/sysfs.h | 2 -- 5 files changed, 16 insertions(+), 32 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9504d4cb63eb..354675ad0965 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -30,7 +30,7 @@ static DEFINE_IDA(sysfs_ino_ida); * Locking: * mutex_lock(sysfs_mutex) */ -void sysfs_link_sibling(struct sysfs_dirent *sd) +static void sysfs_link_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd = sd->s_parent; @@ -49,7 +49,7 @@ void sysfs_link_sibling(struct sysfs_dirent *sd) * Locking: * mutex_lock(sysfs_mutex) */ -void sysfs_unlink_sibling(struct sysfs_dirent *sd) +static void sysfs_unlink_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent **pos; @@ -500,6 +500,8 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) inc_nlink(acxt->parent_inode); acxt->cnt++; + + sysfs_link_sibling(sd); } /** @@ -521,7 +523,9 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) */ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { - BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED)); + BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); + + sysfs_unlink_sibling(sd); sd->s_flags |= SYSFS_FLAG_REMOVED; sd->s_sibling = acxt->removed; @@ -697,10 +701,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, /* link in */ sysfs_addrm_start(&acxt, parent_sd); - if (!sysfs_find_dirent(parent_sd, name)) { + if (!sysfs_find_dirent(parent_sd, name)) sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } if (!sysfs_addrm_finish(&acxt)) { sysfs_put(sd); @@ -821,7 +823,6 @@ static void remove_dir(struct sysfs_dirent *sd) struct sysfs_addrm_cxt acxt; sysfs_addrm_start(&acxt, sd->s_parent); - sysfs_unlink_sibling(sd); sysfs_remove_one(&acxt, sd); sysfs_addrm_finish(&acxt); } @@ -846,11 +847,9 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) while (*pos) { struct sysfs_dirent *sd = *pos; - if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) { - *pos = sd->s_sibling; - sd->s_sibling = NULL; + if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) sysfs_remove_one(&acxt, sd); - } else + else pos = &(*pos)->s_sibling; } sysfs_addrm_finish(&acxt); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b21d11b46754..ea0e494d7d58 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -405,10 +405,8 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, sysfs_addrm_start(&acxt, dir_sd); - if (!sysfs_find_dirent(dir_sd, attr->name)) { + if (!sysfs_find_dirent(dir_sd, attr->name)) sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } if (!sysfs_addrm_finish(&acxt)) { sysfs_put(sd); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 45128b79bc68..efb4062fe099 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -189,25 +189,16 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) { struct sysfs_addrm_cxt acxt; - struct sysfs_dirent **pos, *sd; + struct sysfs_dirent *sd; if (!dir_sd) return -ENOENT; sysfs_addrm_start(&acxt, dir_sd); - for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { - sd = *pos; - - if (!sysfs_type(sd)) - continue; - if (!strcmp(sd->s_name, name)) { - *pos = sd->s_sibling; - sd->s_sibling = NULL; - sysfs_remove_one(&acxt, sd); - break; - } - } + sd = sysfs_find_dirent(dir_sd, name); + if (sd) + sysfs_remove_one(&acxt, sd); if (sysfs_addrm_finish(&acxt)) return 0; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 90484533801e..c129f307936a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -92,10 +92,8 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char sysfs_addrm_start(&acxt, parent_sd); - if (!sysfs_find_dirent(parent_sd, name)) { + if (!sysfs_find_dirent(parent_sd, name)) sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } if (!sysfs_addrm_finish(&acxt)) { error = -EEXIST; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index b55e510ea239..32b8b64e5cf1 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -56,8 +56,6 @@ extern struct sysfs_dirent sysfs_root; extern struct kmem_cache *sysfs_dir_cachep; extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); -extern void sysfs_link_sibling(struct sysfs_dirent *sd); -extern void sysfs_unlink_sibling(struct sysfs_dirent *sd); extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); extern void sysfs_put_active(struct sysfs_dirent *sd); extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); From 23dc279950a056c33a14d09cf759f5173d41abd9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:03 +0900 Subject: [PATCH 2568/2804] sysfs: make sysfs_add_one() automatically check for duplicate entry Make sysfs_add_one() check for duplicate entry and return -EEXIST if such entry exists. This simplifies node addition code a bit. This patch doesn't introduce any noticeable behavior change. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 26 +++++++++++++++++--------- fs/sysfs/file.c | 12 +++++------- fs/sysfs/symlink.c | 9 +++------ fs/sysfs/sysfs.h | 2 +- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 354675ad0965..620603296c6c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -491,9 +491,16 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, * * LOCKING: * Determined by sysfs_addrm_start(). + * + * RETURNS: + * 0 on success, -EEXIST if entry with the given name already + * exists. */ -void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) +int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { + if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) + return -EEXIST; + sd->s_parent = sysfs_get(acxt->parent_sd); if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) @@ -502,6 +509,8 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) acxt->cnt++; sysfs_link_sibling(sd); + + return 0; } /** @@ -691,6 +700,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; + int rc; /* allocate */ sd = sysfs_new_dirent(name, mode, SYSFS_DIR); @@ -700,17 +710,15 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, /* link in */ sysfs_addrm_start(&acxt, parent_sd); + rc = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(parent_sd, name)) - sysfs_add_one(&acxt, sd); - - if (!sysfs_addrm_finish(&acxt)) { + if (rc == 0) + *p_sd = sd; + else sysfs_put(sd); - return -EEXIST; - } - *p_sd = sd; - return 0; + return rc; } int sysfs_create_subdir(struct kobject *kobj, const char *name, diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index ea0e494d7d58..33bb3406dc49 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -397,6 +397,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; + int rc; sd = sysfs_new_dirent(attr->name, mode, type); if (!sd) @@ -404,16 +405,13 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, sd->s_elem.attr.attr = (void *)attr; sysfs_addrm_start(&acxt, dir_sd); + rc = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(dir_sd, attr->name)) - sysfs_add_one(&acxt, sd); - - if (!sysfs_addrm_finish(&acxt)) { + if (rc) sysfs_put(sd); - return -EEXIST; - } - return 0; + return rc; } diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index c129f307936a..a6b13f12b0e7 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -91,14 +91,11 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char target_sd = NULL; /* reference is now owned by the symlink */ sysfs_addrm_start(&acxt, parent_sd); + error = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(parent_sd, name)) - sysfs_add_one(&acxt, sd); - - if (!sysfs_addrm_finish(&acxt)) { - error = -EEXIST; + if (error) goto out_put; - } return 0; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 32b8b64e5cf1..bb3f0c999b15 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -62,7 +62,7 @@ extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); extern void sysfs_put_active_two(struct sysfs_dirent *sd); extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *parent_sd); -extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt, +extern int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); From 990e53f880be9ff93072b4cce590ec2826cee0b6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:03 +0900 Subject: [PATCH 2569/2804] sysfs: make sysfs_addrm_finish() return void With the previous sysfs_add_one() update, there is only one user of the return value of sysfs_addrm_finish() and the user can switch to testing @sd easily. Make sysfs_addrm_finish() return void for cleaner semantics as suggested by Satyam Sharma. This patch doesn't introduce any noticeable behavior change. Signed-off-by: Tejun Heo Cc: Satyam Sharma Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 7 +------ fs/sysfs/inode.c | 7 +++++-- fs/sysfs/sysfs.h | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 620603296c6c..a0da2b05a754 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -609,11 +609,8 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd) * * LOCKING: * All mutexes acquired by sysfs_addrm_start() are released. - * - * RETURNS: - * Number of added/removed sysfs_dirents since sysfs_addrm_start(). */ -int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) +void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) { /* release resources acquired by sysfs_addrm_start() */ mutex_unlock(&sysfs_mutex); @@ -639,8 +636,6 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) sysfs_deactivate(sd); sysfs_put(sd); } - - return acxt->cnt; } /** diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index efb4062fe099..e22db6cd4df7 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -200,7 +200,10 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) if (sd) sysfs_remove_one(&acxt, sd); - if (sysfs_addrm_finish(&acxt)) + sysfs_addrm_finish(&acxt); + + if (sd) return 0; - return -ENOENT; + else + return -ENOENT; } diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index bb3f0c999b15..043675471031 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -66,7 +66,7 @@ extern int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); -extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); +extern void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); From 6374475661172d508a9b93a2740a3fdc9d899756 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 13 Aug 2007 11:24:33 +0200 Subject: [PATCH 2570/2804] dmi-id: Use dynamic sysfs attributes We can use sysfs attributes with an extra parameter for dmi id attributes. This makes it possible to use the same callback function for all attributes, reducing the binary size significantly (-18% on x86_64.) Signed-off-by: Jean Delvare Acked-by: Lennart Poettering Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/dmi-id.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 2678098d4504..a7bd87d52897 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -13,21 +13,35 @@ #include #include +struct dmi_device_attribute{ + struct device_attribute dev_attr; + int field; +}; +#define to_dmi_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct dmi_device_attribute, dev_attr) + #define DEFINE_DMI_ATTR(_name, _mode, _show) \ static struct device_attribute sys_dmi_##_name##_attr = \ __ATTR(_name, _mode, _show, NULL); -#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ -static ssize_t sys_dmi_##_name##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *page) \ -{ \ - ssize_t len; \ - len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \ - page[len-1] = '\n'; \ - return len; \ -} \ -DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show); +static ssize_t sys_dmi_field_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + int field = to_dmi_dev_attr(attr)->field; + ssize_t len; + len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field)); + page[len-1] = '\n'; + return len; +} + +#define DMI_ATTR(_name, _mode, _show, _field) \ + { .dev_attr = __ATTR(_name, _mode, _show, NULL), \ + .field = _field } + +#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ +static struct dmi_device_attribute sys_dmi_##_name##_attr = \ + DMI_ATTR(_name, _mode, sys_dmi_field_show, _field); DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR); DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION); @@ -160,7 +174,7 @@ static struct device *dmi_dev; #define ADD_DMI_ATTR(_name, _field) \ if (dmi_get_system_info(_field)) \ - sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr; + sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr; extern int dmi_available; From 34b51f39e23bc9e529830ddf6108381d4bab95a6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 13 Aug 2007 11:26:26 +0200 Subject: [PATCH 2571/2804] dmi-id: Possible cleanup The DEFINE_DMI_ATTR macro has a single user left so we can expand it for slightly shorter/simpler code. Signed-off-by: Jean Delvare Acked-by: Lennart Poettering Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/dmi-id.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index a7bd87d52897..b6e1eb77d148 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -20,10 +20,6 @@ struct dmi_device_attribute{ #define to_dmi_dev_attr(_dev_attr) \ container_of(_dev_attr, struct dmi_device_attribute, dev_attr) -#define DEFINE_DMI_ATTR(_name, _mode, _show) \ -static struct device_attribute sys_dmi_##_name##_attr = \ - __ATTR(_name, _mode, _show, NULL); - static ssize_t sys_dmi_field_show(struct device *dev, struct device_attribute *attr, char *page) @@ -135,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev, return r+1; } -DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show); +static struct device_attribute sys_dmi_modalias_attr = + __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL); static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2]; From 60043428a561a5d431ad479b7ecb79805ed04efc Mon Sep 17 00:00:00 2001 From: "tonyj@suse.de" Date: Tue, 7 Aug 2007 22:28:47 -0700 Subject: [PATCH 2572/2804] Convert from class_device to device for drivers/video Convert from class_device to device for drivers/video. Signed-off-by: Tony Jones Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/video.c | 4 ++-- drivers/video/output.c | 29 ++++++++++++++++------------- include/linux/video_output.h | 4 ++-- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index d05891f16282..b8a2095cb5ee 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -316,7 +316,7 @@ static int acpi_video_output_get(struct output_device *od) { unsigned long state; struct acpi_video_device *vd = - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); acpi_video_device_get_state(vd, &state); return (int)state; } @@ -325,7 +325,7 @@ static int acpi_video_output_set(struct output_device *od) { unsigned long state = od->request_state; struct acpi_video_device *vd= - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); return acpi_video_device_set_state(vd, state); } diff --git a/drivers/video/output.c b/drivers/video/output.c index 1473f2c892d2..f2df5519c9c4 100644 --- a/drivers/video/output.c +++ b/drivers/video/output.c @@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luming Yu "); -static ssize_t video_output_show_state(struct class_device *dev,char *buf) +static ssize_t video_output_show_state(struct device *dev, + struct device_attribute *attr, char *buf) { ssize_t ret_size = 0; struct output_device *od = to_output_device(dev); @@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf) return ret_size; } -static ssize_t video_output_store_state(struct class_device *dev, - const char *buf,size_t count) +static ssize_t video_output_store_state(struct device *dev, + struct device_attribute *attr, + const char *buf,size_t count) { char *endp; struct output_device *od = to_output_device(dev); @@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev, return count; } -static void video_output_class_release(struct class_device *dev) +static void video_output_release(struct device *dev) { struct output_device *od = to_output_device(dev); kfree(od); } -static struct class_device_attribute video_output_attributes[] = { +static struct device_attribute video_output_attributes[] = { __ATTR(state, 0644, video_output_show_state, video_output_store_state), __ATTR_NULL, }; + static struct class video_output_class = { .name = "video_output", - .release = video_output_class_release, - .class_dev_attrs = video_output_attributes, + .dev_release = video_output_release, + .dev_attrs = video_output_attributes, }; struct output_device *video_output_register(const char *name, @@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name, goto error_return; } new_dev->props = op; - new_dev->class_dev.class = &video_output_class; - new_dev->class_dev.dev = dev; - strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN); - class_set_devdata(&new_dev->class_dev,devdata); - ret_code = class_device_register(&new_dev->class_dev); + new_dev->dev.class = &video_output_class; + new_dev->dev.parent = dev; + strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE); + dev_set_drvdata(&new_dev->dev, devdata); + ret_code = device_register(&new_dev->dev); if (ret_code) { kfree(new_dev); goto error_return; @@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev) { if (!dev) return; - class_device_unregister(&dev->class_dev); + device_unregister(&dev->dev); } EXPORT_SYMBOL(video_output_unregister); diff --git a/include/linux/video_output.h b/include/linux/video_output.h index e63e0c03ee0d..2fb46bc9340d 100644 --- a/include/linux/video_output.h +++ b/include/linux/video_output.h @@ -31,9 +31,9 @@ struct output_properties { struct output_device { int request_state; struct output_properties *props; - struct class_device class_dev; + struct device dev; }; -#define to_output_device(obj) container_of(obj, struct output_device, class_dev) +#define to_output_device(obj) container_of(obj, struct output_device, dev) struct output_device *video_output_register(const char *name, struct device *dev, void *devdata, From 07c015e7654821f2dda00dcf152c65b2afd46ac3 Mon Sep 17 00:00:00 2001 From: "tonyj@suse.de" Date: Tue, 7 Aug 2007 22:28:44 -0700 Subject: [PATCH 2573/2804] Convert from class_device to device in drivers/char Convert from class_device to device in drivers/char. Signed-off-by: Tony Jones Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/char/dsp56k.c | 4 ++-- drivers/char/ip2/ip2main.c | 12 ++++++------ drivers/char/ipmi/ipmi_devintf.c | 6 +++--- drivers/char/istallion.c | 8 +++----- drivers/char/lp.c | 5 ++--- drivers/char/pcmcia/cm4000_cs.c | 5 ++--- drivers/char/pcmcia/cm4040_cs.c | 5 ++--- drivers/char/snsc.c | 3 +-- drivers/char/stallion.c | 7 +++---- drivers/char/tipar.c | 6 +++--- drivers/char/viotape.c | 10 +++++----- 11 files changed, 32 insertions(+), 39 deletions(-) diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 9b8278e1f4f8..acbfe1c49b4d 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void) err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k"); printk(banner); goto out; @@ -527,7 +527,7 @@ module_init(dsp56k_init_driver); static void __exit dsp56k_cleanup_driver(void) { - class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 8d74b8745e60..bd94d5f9e62b 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -411,8 +411,8 @@ cleanup_module(void) iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { @@ -718,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_device_create(ip2_class, NULL, + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i), - NULL, "ipl%d", i); - class_device_create(ip2_class, NULL, + "ipl%d", i); + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - NULL, "stat%d", i); + "stat%d", i); for ( box = 0; box < ABS_MAX_BOXES; ++box ) { diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index c2aa44ee6eb6..0246a2b8ce48 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device) entry->dev = dev; mutex_lock(®_list_mutex); - class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num); + device_create(ipmi_class, device, dev, "ipmi%d", if_num); list_add(&entry->link, ®_list); mutex_unlock(®_list_mutex); } @@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num) break; } } - class_device_destroy(ipmi_class, dev); + device_destroy(ipmi_class, dev); mutex_unlock(®_list_mutex); } @@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void) mutex_lock(®_list_mutex); list_for_each_entry_safe(entry, entry2, ®_list, link) { list_del(&entry->link); - class_device_destroy(ipmi_class, entry->dev); + device_destroy(ipmi_class, entry->dev); kfree(entry); } mutex_unlock(®_list_mutex); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 3c66f402f9d7..1f27be1ec3d4 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void) istallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) - class_device_create(istallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), - NULL, "staliomem%d", i); + device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_deinit: @@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void) unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); for (j = 0; j < 4; j++) - class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, - j)); + device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j)); class_destroy(istallion_class); pci_unregister_driver(&stli_pcidriver); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 62051f8b0910..c59e2a0996cc 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev, - "lp%d", nr); + device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); @@ -971,7 +970,7 @@ static void lp_cleanup_module (void) if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); - class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); + device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } class_destroy(lp_class); } diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 4177f6db83e9..cc5d77797def 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1863,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, - "cmm%d", i); + device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i); return 0; } @@ -1888,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmm_class, MKDEV(major, devno)); + device_destroy(cmm_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index b24a3e7bbb9f..a0b9c8728d56 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmx_class, NULL, MKDEV(major, i), NULL, - "cmx%d", i); + device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i); return 0; } @@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmx_class, MKDEV(major, devno)); + device_destroy(cmx_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 52753e723eaa..b9c1dba6bd01 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -441,8 +441,7 @@ scdrv_init(void) continue; } - class_device_create(snsc_class, NULL, dev, NULL, - "%s", devname); + device_create(snsc_class, NULL, dev, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, 0 /*ignored */ , diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 4a80b2f864e0..45758d5b56ef 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void) if (IS_ERR(stallion_class)) printk("STALLION: failed to create class\n"); for (i = 0; i < 4; i++) - class_device_create(stallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), NULL, - "staliomem%d", i); + device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_unrtty: @@ -4816,7 +4815,7 @@ static void __exit stallion_module_exit(void) } for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); class_destroy(stallion_class); diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 35b40b996534..cef55c40654f 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port) goto out; } - class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), port->dev, "par%d", nr); + device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR, + TIPAR_MINOR + nr), "par%d", nr); /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == @@ -534,7 +534,7 @@ tipar_cleanup_module(void) if (table[i].dev == NULL) continue; parport_unregister_device(table[i].dev); - class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); + device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); } class_destroy(tipar_class); diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index f1d60f0cef8f..db7a731e2362 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -871,10 +871,10 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), "iseries!vt%d", i); - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), - NULL, "iseries!nvt%d", i); + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), + "iseries!nvt%d", i); printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " "resource %10.10s type %4.4s, model %3.3s\n", i, viotape_unitinfo[i].rsrcname, @@ -886,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev) { int i = vdev->unit_address; - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } From 5c5daf657cb5f963a38413f2852279d7a3843144 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 12 Aug 2007 20:43:55 +0200 Subject: [PATCH 2574/2804] Driver core: exclude kobject_uevent.c for !CONFIG_HOTPLUG Move uevent specific logic from the core into kobject_uevent.c, which does no longer require to link the unused string array if hotplug is not compiled in. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 18 +++---------- include/linux/kobject.h | 10 +++++--- lib/Makefile | 3 ++- lib/kobject_uevent.c | 57 +++++++++++++++++++++++++++++++---------- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index d487c032dc4a..65de221e3bfa 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -234,13 +234,11 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, /* search the kset, the device belongs to */ top_kobj = &dev->kobj; - if (!top_kobj->kset && top_kobj->parent) { - do { - top_kobj = top_kobj->parent; - } while (!top_kobj->kset && top_kobj->parent); - } + while (!top_kobj->kset && top_kobj->parent) + top_kobj = top_kobj->parent; if (!top_kobj->kset) goto out; + kset = top_kobj->kset; if (!kset->uevent_ops || !kset->uevent_ops->uevent) goto out; @@ -270,17 +268,9 @@ out: static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - size_t len = count; enum kobject_action action; - if (len && buf[len-1] == '\n') - len--; - - for (action = 0; action < KOBJ_MAX; action++) { - if (strncmp(kobject_actions[action], buf, len) != 0) - continue; - if (kobject_actions[action][len] != '\0') - continue; + if (kobject_action_type(buf, count, &action) == 0) { kobject_uevent(&dev->kobj, action); goto out; } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 56f5eaf10ea9..0777b3f57ae6 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -58,9 +58,6 @@ enum kobject_action { KOBJ_MAX }; -/* The list of strings defining the valid kobject actions as specified above */ -extern const char *kobject_actions[]; - struct kobject { const char * k_name; struct kref kref; @@ -241,6 +238,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) __attribute__((format (printf, 2, 3))); + +int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type); #else static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action) { return 0; } @@ -251,6 +251,10 @@ static inline int kobject_uevent_env(struct kobject *kobj, static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { return 0; } + +static inline int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type) +{ return -EINVAL; } #endif #endif /* __KERNEL__ */ diff --git a/lib/Makefile b/lib/Makefile index 4f3f3e256501..6c4ea33bb2cb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -10,7 +10,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o -lib-y += kobject.o kref.o kobject_uevent.o klist.o +lib-y += kobject.o kref.o klist.o obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o @@ -20,6 +20,7 @@ CFLAGS_kobject.o += -DDEBUG CFLAGS_kobject_uevent.o += -DDEBUG endif +lib-$(CONFIG_HOTPLUG) += kobject_uevent.o obj-$(CONFIG_GENERIC_IOMAP) += iomap.o obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 5ccda460262c..a8efb48dca54 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -23,17 +23,6 @@ #include -/* the strings here must match the enum in include/linux/kobject.h */ -const char *kobject_actions[] = { - "add", - "remove", - "change", - "move", - "online", - "offline", -}; - -#if defined(CONFIG_HOTPLUG) u64 uevent_seqnum; char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; static DEFINE_SPINLOCK(sequence_lock); @@ -41,6 +30,50 @@ static DEFINE_SPINLOCK(sequence_lock); static struct sock *uevent_sock; #endif +/* the strings here must match the enum in include/linux/kobject.h */ +static const char *kobject_actions[] = { + [KOBJ_ADD] = "add", + [KOBJ_REMOVE] = "remove", + [KOBJ_CHANGE] = "change", + [KOBJ_MOVE] = "move", + [KOBJ_ONLINE] = "online", + [KOBJ_OFFLINE] = "offline", +}; + +/** + * kobject_action_type - translate action string to numeric type + * + * @buf: buffer containing the action string, newline is ignored + * @len: length of buffer + * @type: pointer to the location to store the action type + * + * Returns 0 if the action string was recognized. + */ +int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type) +{ + enum kobject_action action; + int ret = -EINVAL; + + if (count && buf[count-1] == '\n') + count--; + + if (!count) + goto out; + + for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) { + if (strncmp(kobject_actions[action], buf, count) != 0) + continue; + if (kobject_actions[action][count] != '\0') + continue; + *type = action; + ret = 0; + break; + } +out: + return ret; +} + /** * kobject_uevent_env - send an uevent with environmental data * @@ -270,5 +303,3 @@ static int __init kobject_uevent_init(void) postcore_initcall(kobject_uevent_init); #endif - -#endif /* CONFIG_HOTPLUG */ From 7ac1cf4a87f446c130f7d8a4fe7e519f532a11de Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 12 Aug 2007 20:43:55 +0200 Subject: [PATCH 2575/2804] Driver core: add uevent file for bus and driver This has been in the SuSE kernels for some time now. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 0a8d075f3e6c..6768a01e210b 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -610,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; } static inline void remove_probe_files(struct bus_type *bus) {} #endif +static ssize_t driver_uevent_store(struct device_driver *drv, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&drv->kobj, action); + return count; +} +static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); + /** * bus_add_driver - Add a driver to the bus. * @drv: driver. @@ -640,6 +651,11 @@ int bus_add_driver(struct device_driver *drv) klist_add_tail(&drv->knode_bus, &bus->klist_drivers); module_add_driver(drv->owner, drv); + error = driver_create_file(drv, &driver_attr_uevent); + if (error) { + printk(KERN_ERR "%s: uevent attr (%s) failed\n", + __FUNCTION__, drv->name); + } error = driver_add_attrs(bus, drv); if (error) { /* How the hell do we get out of this pickle? Give up */ @@ -677,6 +693,7 @@ void bus_remove_driver(struct device_driver * drv) remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); + driver_remove_file(drv, &driver_attr_uevent); klist_remove(&drv->knode_bus); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); @@ -804,6 +821,17 @@ static void klist_devices_put(struct klist_node *n) put_device(dev); } +static ssize_t bus_uevent_store(struct bus_type *bus, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&bus->subsys.kobj, action); + return count; +} +static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); + /** * bus_register - register a bus with the system. * @bus: bus. @@ -828,6 +856,10 @@ int bus_register(struct bus_type * bus) if (retval) goto out; + retval = bus_create_file(bus, &bus_attr_uevent); + if (retval) + goto bus_uevent_fail; + kobject_set_name(&bus->devices.kobj, "devices"); bus->devices.kobj.parent = &bus->subsys.kobj; retval = kset_register(&bus->devices); @@ -863,6 +895,8 @@ bus_probe_files_fail: bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: + bus_remove_file(bus, &bus_attr_uevent); +bus_uevent_fail: subsystem_unregister(&bus->subsys); out: return retval; @@ -882,6 +916,7 @@ void bus_unregister(struct bus_type * bus) remove_probe_files(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); + bus_remove_file(bus, &bus_attr_uevent); subsystem_unregister(&bus->subsys); } From ccd490a3c3d9c5960c738c2720fb2dc6830bc334 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 12 Aug 2007 20:43:55 +0200 Subject: [PATCH 2576/2804] Driver core: kerneldoc - kobject_uevent_env is not "usually KOBJ_MOVE" Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- lib/kobject_uevent.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index a8efb48dca54..2e4eae5b0824 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -77,7 +77,7 @@ out: /** * kobject_uevent_env - send an uevent with environmental data * - * @action: action that is happening (usually KOBJ_MOVE) + * @action: action that is happening * @kobj: struct kobject that the action is happening to * @envp_ext: pointer to environmental data * @@ -102,9 +102,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* search the kset we belong to */ top_kobj = kobj; - while (!top_kobj->kset && top_kobj->parent) { + while (!top_kobj->kset && top_kobj->parent) top_kobj = top_kobj->parent; - } + if (!top_kobj->kset) { pr_debug("kobject attempted to send uevent without kset!\n"); return -EINVAL; @@ -237,7 +237,7 @@ EXPORT_SYMBOL_GPL(kobject_uevent_env); /** * kobject_uevent - notify userspace by ending an uevent * - * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE) + * @action: action that is happening * @kobj: struct kobject that the action is happening to * * Returns 0 if kobject_uevent() is completed with success or the From 109f0e93b6b728f03c1eb4af02bc25d71b646c59 Mon Sep 17 00:00:00 2001 From: Markus Rechberger Date: Mon, 13 Aug 2007 19:20:43 +0200 Subject: [PATCH 2577/2804] Fix Firmware class name collision following patch fixes the i2c name collision with i2c-dev. http://mcentral.de/wiki/index.php/Bugtracker#i2c_core_problem This issue has been experienced with em28xx and saa7133 based devices. I discussed that problem with Jean Delvare a while ago and he proposed to add a prefix to the class name. Signed-off-by: Markus Rechberger Acked-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4a1b9bfc5471..0295855a3eef 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -292,8 +292,7 @@ firmware_class_timeout(u_long data) static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) { - /* XXX warning we should watch out for name collisions */ - strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); + snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id); } static int fw_register_device(struct device **dev_p, const char *fw_name, From b4d1eb2ccecb76bce4c2125c5a3e77753fcfaeb0 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 10 Aug 2007 13:51:09 -0700 Subject: [PATCH 2578/2804] drivers/base/power/: make 2 functions static suspend_device() and resume_device() can now become static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/power.h | 6 ------ drivers/base/power/resume.c | 2 +- drivers/base/power/suspend.c | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 8ba0830cbc03..49e64dbcce96 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -55,12 +55,6 @@ extern void dpm_sysfs_remove(struct device *); extern void dpm_resume(void); extern void dpm_power_up(void); -extern int resume_device(struct device *); - -/* - * suspend.c - */ -extern int suspend_device(struct device *, pm_message_t); #else /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 00fd84ae6e66..67948bac9938 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -20,7 +20,7 @@ * */ -int resume_device(struct device * dev) +static int resume_device(struct device * dev) { int error = 0; diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 26df9b231737..204517afb15e 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -54,7 +54,7 @@ suspend_device_dbg(struct device *dev, pm_message_t state, char *info) * @state: Power state device is entering. */ -int suspend_device(struct device * dev, pm_message_t state) +static int suspend_device(struct device * dev, pm_message_t state) { int error = 0; From a93720eeb4b3bedc1fe15e4b6ca364e6be577d20 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 10 Aug 2007 13:51:07 -0700 Subject: [PATCH 2579/2804] sysfs: Fix typos in fs/sysfs/file.c Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 33bb3406dc49..16f39c30b091 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -335,7 +335,7 @@ static int sysfs_release(struct inode * inode, struct file * filp) * again will not get new data, or reset the state of 'poll'. * Reminder: this only works for attributes which actively support * it, and it is not possible to test an attribute from userspace - * to see if it supports poll (Nether 'poll' or 'select' return + * to see if it supports poll (Neither 'poll' nor 'select' return * an appropriate error code). When in doubt, set a suitable timeout value. */ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) From 44b760a825fae65629fb04b1deeab68c6bef5c50 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Aug 2007 16:51:14 +0900 Subject: [PATCH 2580/2804] sysdev: remove global sysdev drivers list No one uses sysdev_drivers. Because no one calls sysdev_driver_register with NULL class. And it is difficult to imagine that someone want to implement a global sysdev driver which is called with all sys_device on any kind of sysdev_class. So this patch removes global sysdev_drivers list and update comments for this change. Signed-off-by: Akinobu Mita Cc: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/sys.c | 71 +++++++++------------------------------------- 1 file changed, 14 insertions(+), 57 deletions(-) diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 7ad893167823..ac7ff6d0c6e5 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls) EXPORT_SYMBOL_GPL(sysdev_class_register); EXPORT_SYMBOL_GPL(sysdev_class_unregister); - -static LIST_HEAD(sysdev_drivers); static DEFINE_MUTEX(sysdev_drivers_lock); /** * sysdev_driver_register - Register auxillary driver - * @cls: Device class driver belongs to. + * @cls: Device class driver belongs to. * @drv: Driver. * - * If @cls is valid, then @drv is inserted into @cls->drivers to be + * @drv is inserted into @cls->drivers to be * called on each operation on devices of that class. The refcount * of @cls is incremented. - * Otherwise, @drv is inserted into sysdev_drivers, and called for - * each device. */ -int sysdev_driver_register(struct sysdev_class * cls, - struct sysdev_driver * drv) +int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) { + int err = 0; + mutex_lock(&sysdev_drivers_lock); if (cls && kset_get(&cls->kset)) { list_add_tail(&drv->entry, &cls->drivers); @@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls, list_for_each_entry(dev, &cls->kset.list, kobj.entry) drv->add(dev); } - } else - list_add_tail(&drv->entry, &sysdev_drivers); + } else { + err = -EINVAL; + printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__); + WARN_ON(1); + } mutex_unlock(&sysdev_drivers_lock); - return 0; + return err; } @@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev) * code that should have called us. */ - /* Notify global drivers */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->add) - drv->add(sysdev); - } - /* Notify class auxillary drivers */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->add) @@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev) struct sysdev_driver * drv; mutex_lock(&sysdev_drivers_lock); - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->remove) - drv->remove(sysdev); - } - list_for_each_entry(drv, &sysdev->cls->drivers, entry) { if (drv->remove) drv->remove(sysdev); @@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev) * * Loop over each class of system devices, and the devices in each * of those classes. For each device, we call the shutdown method for - * each driver registered for the device - the globals, the auxillaries, + * each driver registered for the device - the auxillaries, * and the class driver. * * Note: The list is iterated in reverse order, so that we shut down @@ -320,13 +309,7 @@ void sysdev_shutdown(void) struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->shutdown) - drv->shutdown(sysdev); - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); @@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev) if (drv->resume) drv->resume(dev); } - - /* Call global drivers. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->resume) - drv->resume(dev); - } } /** @@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state) list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->suspend) { - ret = drv->suspend(sysdev, state); - if (ret) - goto gbl_driver; - } - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->suspend) { ret = drv->suspend(sysdev, state); @@ -436,18 +404,7 @@ aux_driver: if (err_drv->resume) err_drv->resume(sysdev); } - drv = NULL; -gbl_driver: - if (drv) - printk(KERN_ERR "sysdev driver suspend failed for %s\n", - kobject_name(&sysdev->kobj)); - list_for_each_entry(err_drv, &sysdev_drivers, entry) { - if (err_drv == drv) - break; - if (err_drv->resume) - err_drv->resume(sysdev); - } /* resume other sysdevs in current class */ list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { if (err_dev == sysdev) From 1359555eb77d240b7c1d7ee75bb07e89e89770e4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 9 Sep 2007 12:54:16 +0200 Subject: [PATCH 2581/2804] Driver core: Make platform_device.id an int While platform_device.id is a u32, platform_device_add() handles "-1" as a special id value. This has potential for confusion and bugs. Making it an int instead should prevent problems from happening in the future. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 7 ++++--- include/linux/platform_device.h | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a2e3910196e0..fb5609241482 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -161,7 +161,7 @@ static void platform_device_release(struct device *dev) * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. */ -struct platform_device *platform_device_alloc(const char *name, unsigned int id) +struct platform_device *platform_device_alloc(const char *name, int id) { struct platform_object *pa; @@ -245,7 +245,8 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) - snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id); + snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, + pdev->id); else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); @@ -359,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); * the Linux driver model. In particular, when such drivers are built * as modules, they can't be "hotplugged". */ -struct platform_device *platform_device_register_simple(char *name, unsigned int id, +struct platform_device *platform_device_register_simple(char *name, int id, struct resource *res, unsigned int num) { struct platform_device *pdev; diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 8bbd459eafdc..e80804316cdb 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -15,7 +15,7 @@ struct platform_device { const char * name; - u32 id; + int id; struct device dev; u32 num_resources; struct resource * resource; @@ -35,9 +35,10 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u extern int platform_get_irq_byname(struct platform_device *, char *); extern int platform_add_devices(struct platform_device **, int); -extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int); +extern struct platform_device *platform_device_register_simple(char *, int id, + struct resource *, unsigned int); -extern struct platform_device *platform_device_alloc(const char *name, unsigned int id); +extern struct platform_device *platform_device_alloc(const char *name, int id); extern int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num); extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size); extern int platform_device_add(struct platform_device *pdev); From 253280267a7f1ced0c434fb24b7bef92d7d22628 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Aug 2007 21:36:29 +0900 Subject: [PATCH 2582/2804] sysfs: fix i_mutex locking in sysfs_get_dentry() lookup_one_len_kern() should be called with the parent's i_mutex locked. Fix it. Spotted by Eric W. Biederman. Signed-off-by: Tejun Heo Cc: Eric W. Biederman Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index a0da2b05a754..54ca4bc02dcf 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -130,8 +130,10 @@ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) /* look it up */ parent_dentry = dentry; + mutex_lock(&parent_dentry->d_inode->i_mutex); dentry = lookup_one_len_kern(cur->s_name, parent_dentry, strlen(cur->s_name)); + mutex_unlock(&parent_dentry->d_inode->i_mutex); dput(parent_dentry); if (IS_ERR(dentry)) { From 372e88bd1922228e0a55228f6dc8e311d1696fa0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:29 +0900 Subject: [PATCH 2583/2804] sysfs: Move all of inode initialization into sysfs_init_inode Signed-off-by: "Eric W. Biederman" Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 37 ------------------------------------- fs/sysfs/inode.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- fs/sysfs/mount.c | 5 ----- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 54ca4bc02dcf..5a70a93fc2f7 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -748,24 +748,12 @@ int sysfs_create_dir(struct kobject * kobj) return error; } -static int sysfs_count_nlink(struct sysfs_dirent *sd) -{ - struct sysfs_dirent *child; - int nr = 0; - - for (child = sd->s_children; child; child = child->s_sibling) - if (sysfs_type(child) == SYSFS_DIR) - nr++; - return nr + 2; -} - static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret = NULL; struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; struct sysfs_dirent *sd; - struct bin_attribute *bin_attr; struct inode *inode; mutex_lock(&sysfs_mutex); @@ -785,31 +773,6 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, goto out_unlock; } - if (inode->i_state & I_NEW) { - /* initialize inode according to type */ - switch (sysfs_type(sd)) { - case SYSFS_DIR: - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - inode->i_nlink = sysfs_count_nlink(sd); - break; - case SYSFS_KOBJ_ATTR: - inode->i_size = PAGE_SIZE; - inode->i_fop = &sysfs_file_operations; - break; - case SYSFS_KOBJ_BIN_ATTR: - bin_attr = sd->s_elem.bin_attr.bin_attr; - inode->i_size = bin_attr->size; - inode->i_fop = &bin_fops; - break; - case SYSFS_KOBJ_LINK: - inode->i_op = &sysfs_symlink_inode_operations; - break; - default: - BUG(); - } - } - sysfs_instantiate(dentry, inode); sysfs_attach_dentry(sd, dentry); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e22db6cd4df7..200e1bf6f932 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -122,8 +122,22 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) */ static struct lock_class_key sysfs_inode_imutex_key; +static int sysfs_count_nlink(struct sysfs_dirent *sd) +{ + struct sysfs_dirent *child; + int nr = 0; + + for (child = sd->s_children; child; child = child->s_sibling) + if (sysfs_type(child) == SYSFS_DIR) + nr++; + + return nr + 2; +} + static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) { + struct bin_attribute *bin_attr; + inode->i_blocks = 0; inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; @@ -139,6 +153,37 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) set_inode_attr(inode, sd->s_iattr); } else set_default_inode_attr(inode, sd->s_mode); + + + /* initialize inode according to type */ + switch (sysfs_type(sd)) { + case SYSFS_ROOT: + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; + inc_nlink(inode); /* directory, account for "." */ + break; + case SYSFS_DIR: + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; + inode->i_nlink = sysfs_count_nlink(sd); + break; + case SYSFS_KOBJ_ATTR: + inode->i_size = PAGE_SIZE; + inode->i_fop = &sysfs_file_operations; + break; + case SYSFS_KOBJ_BIN_ATTR: + bin_attr = sd->s_elem.bin_attr.bin_attr; + inode->i_size = bin_attr->size; + inode->i_fop = &bin_fops; + break; + case SYSFS_KOBJ_LINK: + inode->i_op = &sysfs_symlink_inode_operations; + break; + default: + BUG(); + } + + unlock_new_inode(inode); } /** @@ -180,9 +225,6 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) { BUG_ON(!dentry || dentry->d_inode); - if (inode->i_state & I_NEW) - unlock_new_inode(inode); - d_instantiate(dentry, inode); } diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 119f39da1ae1..92f407fb1263 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -49,11 +49,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; } - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - inc_nlink(inode); /* directory, account for "." */ - unlock_new_inode(inode); - /* instantiate and link root dentry */ root = d_alloc_root(inode); if (!root) { From 119dd52be33dfe6285f586ab7354897fdefc7e23 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:29 +0900 Subject: [PATCH 2584/2804] sysfs: Remove sysfs_instantiate Now that sysfs_get_inode is dropping the inode lock we no longer have a need from sysfs_instantiate. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 2 +- fs/sysfs/inode.c | 17 ----------------- fs/sysfs/sysfs.h | 1 - 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5a70a93fc2f7..739dda176b43 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -773,7 +773,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, goto out_unlock; } - sysfs_instantiate(dentry, inode); + d_instantiate(dentry, inode); sysfs_attach_dentry(sd, dentry); out_unlock: diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 200e1bf6f932..0d706a86d2c7 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -211,23 +211,6 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd) return inode; } -/** - * sysfs_instantiate - instantiate dentry - * @dentry: dentry to be instantiated - * @inode: inode associated with @sd - * - * Unlock @inode if locked and instantiate @dentry with @inode. - * - * LOCKING: - * None. - */ -void sysfs_instantiate(struct dentry *dentry, struct inode *inode) -{ - BUG_ON(!dentry || dentry->d_inode); - - d_instantiate(dentry, inode); -} - int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) { struct sysfs_addrm_cxt acxt; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 043675471031..8a0aea1ab86d 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -69,7 +69,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, extern void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); -extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); extern void release_sysfs_dirent(struct sysfs_dirent * sd); extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, From 0333cd8a3f4249fde2c50929a6eac35245fc685b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:29 +0900 Subject: [PATCH 2585/2804] sysfs: Use kill_anon_super Since sysfs no longer stores fs directory information in the dcache on a permanent basis kill_litter_super it is inappropriate and actively wrong. It will decrement the count on all dentries left in the dcache before trying to free them. At the moment this is not biting us only because we never unmount sysfs. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 92f407fb1263..ac7625631fcf 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -71,7 +71,7 @@ static int sysfs_get_sb(struct file_system_type *fs_type, static struct file_system_type sysfs_fs_type = { .name = "sysfs", .get_sb = sysfs_get_sb, - .kill_sb = kill_litter_super, + .kill_sb = kill_anon_super, }; int __init sysfs_init(void) From 7d0c7d676cc066413e1583b5af9fba8011972d41 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: [PATCH 2586/2804] sysfs: Make sysfs_mount static This patch modifies the users of sysfs_mount to use sysfs_root instead (which is what they are looking for). It then makes sysfs_mount static to keep people from using it by accident. The net result is slightly faster and cleaner code. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 4 +--- fs/sysfs/mount.c | 2 +- fs/sysfs/symlink.c | 7 +++---- fs/sysfs/sysfs.h | 1 - 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 739dda176b43..7f4abe176701 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -737,10 +737,8 @@ int sysfs_create_dir(struct kobject * kobj) if (kobj->parent) parent_sd = kobj->parent->sd; - else if (sysfs_mount && sysfs_mount->mnt_sb) - parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; else - return -EFAULT; + parent_sd = &sysfs_root; error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); if (!error) diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index ac7625631fcf..8989cbb51a39 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -14,7 +14,7 @@ /* Random magic number */ #define SYSFS_MAGIC 0x62656572 -struct vfsmount *sysfs_mount; +static struct vfsmount *sysfs_mount; struct super_block * sysfs_sb = NULL; struct kmem_cache *sysfs_dir_cachep; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index a6b13f12b0e7..8ad38bccc0e4 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -60,10 +60,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char BUG_ON(!name); - if (!kobj) { - if (sysfs_mount && sysfs_mount->mnt_sb) - parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; - } else + if (!kobj) + parent_sd = &sysfs_root; + else parent_sd = kobj->sd; error = -EFAULT; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 8a0aea1ab86d..77253aabc4af 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -51,7 +51,6 @@ struct sysfs_addrm_cxt { int cnt; }; -extern struct vfsmount * sysfs_mount; extern struct sysfs_dirent sysfs_root; extern struct kmem_cache *sysfs_dir_cachep; From 94777e09180b6249d455baa2dbe34cf630e0c033 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: [PATCH 2587/2804] sysfs: In sysfs_lookup don't open code sysfs_find_dirent This is a small cleanup patch that makes the code just a little bit cleaner. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 7f4abe176701..b72b42ed80d1 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -756,9 +756,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, mutex_lock(&sysfs_mutex); - for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) - if (sysfs_type(sd) && !strcmp(sd->s_name, dentry->d_name.name)) - break; + sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); /* no such entry */ if (!sd) From 3efa65b92d832873ece62b42a4268c2515943977 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: [PATCH 2588/2804] sysfs: Simplify readdir. At some point someone wrote sysfs_readdir to insert a cursor into the list of sysfs_dirents to ensure that sysfs_readdir would restart properly. That works but it is complex code and tends to be expensive. The same effect can be achieved by keeping the sysfs_dirents in inode order and using the inode number as the f_pos. Then when we restart we just have to find the first dirent whose inode number is equal or greater then the last sysfs_dirent we attempted to return. Removing the sysfs directory cursor also allows the remove of all of the mysterious checks for sysfs_type(sd) != 0. Which were nonbovious checks to see if a cursor was in a directory list. tj: offset marker for EOF is changed from UINT_MAX to INT_MAX to avoid overflow in case offset is 32bit. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 183 +++++++++++++------------------------------------ 1 file changed, 48 insertions(+), 135 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index b72b42ed80d1..953e8432b0ae 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -33,10 +33,20 @@ static DEFINE_IDA(sysfs_ino_ida); static void sysfs_link_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd = sd->s_parent; + struct sysfs_dirent **pos; BUG_ON(sd->s_sibling); - sd->s_sibling = parent_sd->s_children; - parent_sd->s_children = sd; + + /* Store directory entries in order by ino. This allows + * readdir to properly restart without having to add a + * cursor into the s_children list. + */ + for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) { + if (sd->s_ino < (*pos)->s_ino) + break; + } + sd->s_sibling = *pos; + *pos = sd; } /** @@ -659,7 +669,7 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, struct sysfs_dirent *sd; for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) - if (sysfs_type(sd) && !strcmp(sd->s_name, name)) + if (!strcmp(sd->s_name, name)) return sd; return NULL; } @@ -811,7 +821,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) while (*pos) { struct sysfs_dirent *sd = *pos; - if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) + if (sysfs_type(sd) != SYSFS_DIR) sysfs_remove_one(&acxt, sd); else pos = &(*pos)->s_sibling; @@ -976,37 +986,6 @@ again: return error; } -static int sysfs_dir_open(struct inode *inode, struct file *file) -{ - struct dentry * dentry = file->f_path.dentry; - struct sysfs_dirent * parent_sd = dentry->d_fsdata; - struct sysfs_dirent * sd; - - sd = sysfs_new_dirent("_DIR_", 0, 0); - if (sd) { - mutex_lock(&sysfs_mutex); - sd->s_parent = sysfs_get(parent_sd); - sysfs_link_sibling(sd); - mutex_unlock(&sysfs_mutex); - } - - file->private_data = sd; - return sd ? 0 : -ENOMEM; -} - -static int sysfs_dir_close(struct inode *inode, struct file *file) -{ - struct sysfs_dirent * cursor = file->private_data; - - mutex_lock(&sysfs_mutex); - sysfs_unlink_sibling(cursor); - mutex_unlock(&sysfs_mutex); - - release_sysfs_dirent(cursor); - - return 0; -} - /* Relationship between s_mode and the DT_xxx types */ static inline unsigned char dt_type(struct sysfs_dirent *sd) { @@ -1017,117 +996,51 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dentry *dentry = filp->f_path.dentry; struct sysfs_dirent * parent_sd = dentry->d_fsdata; - struct sysfs_dirent *cursor = filp->private_data; - struct sysfs_dirent **pos; + struct sysfs_dirent *pos; ino_t ino; - int i = filp->f_pos; - switch (i) { - case 0: + if (filp->f_pos == 0) { + ino = parent_sd->s_ino; + if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) + filp->f_pos++; + } + if (filp->f_pos == 1) { + if (parent_sd->s_parent) + ino = parent_sd->s_parent->s_ino; + else ino = parent_sd->s_ino; - if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) - break; + if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; - i++; - /* fallthrough */ - case 1: - if (parent_sd->s_parent) - ino = parent_sd->s_parent->s_ino; - else - ino = parent_sd->s_ino; - if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) + } + if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { + mutex_lock(&sysfs_mutex); + + /* Skip the dentries we have already reported */ + pos = parent_sd->s_children; + while (pos && (filp->f_pos > pos->s_ino)) + pos = pos->s_sibling; + + for ( ; pos; pos = pos->s_sibling) { + const char * name; + int len; + + name = pos->s_name; + len = strlen(name); + filp->f_pos = ino = pos->s_ino; + + if (filldir(dirent, name, len, filp->f_pos, ino, + dt_type(pos)) < 0) break; - filp->f_pos++; - i++; - /* fallthrough */ - default: - mutex_lock(&sysfs_mutex); - - pos = &parent_sd->s_children; - while (*pos != cursor) - pos = &(*pos)->s_sibling; - - /* unlink cursor */ - *pos = cursor->s_sibling; - - if (filp->f_pos == 2) - pos = &parent_sd->s_children; - - for ( ; *pos; pos = &(*pos)->s_sibling) { - struct sysfs_dirent *next = *pos; - const char * name; - int len; - - if (!sysfs_type(next)) - continue; - - name = next->s_name; - len = strlen(name); - ino = next->s_ino; - - if (filldir(dirent, name, len, filp->f_pos, ino, - dt_type(next)) < 0) - break; - - filp->f_pos++; - } - - /* put cursor back in */ - cursor->s_sibling = *pos; - *pos = cursor; - - mutex_unlock(&sysfs_mutex); + } + if (!pos) + filp->f_pos = INT_MAX; + mutex_unlock(&sysfs_mutex); } return 0; } -static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) -{ - struct dentry * dentry = file->f_path.dentry; - - switch (origin) { - case 1: - offset += file->f_pos; - case 0: - if (offset >= 0) - break; - default: - return -EINVAL; - } - if (offset != file->f_pos) { - mutex_lock(&sysfs_mutex); - - file->f_pos = offset; - if (file->f_pos >= 2) { - struct sysfs_dirent *sd = dentry->d_fsdata; - struct sysfs_dirent *cursor = file->private_data; - struct sysfs_dirent **pos; - loff_t n = file->f_pos - 2; - - sysfs_unlink_sibling(cursor); - - pos = &sd->s_children; - while (n && *pos) { - struct sysfs_dirent *next = *pos; - if (sysfs_type(next)) - n--; - pos = &(*pos)->s_sibling; - } - - cursor->s_sibling = *pos; - *pos = cursor; - } - - mutex_unlock(&sysfs_mutex); - } - - return offset; -} const struct file_operations sysfs_dir_operations = { - .open = sysfs_dir_open, - .release = sysfs_dir_close, - .llseek = sysfs_dir_lseek, .read = generic_read_dir, .readdir = sysfs_readdir, }; From 89bec09705d2033b8b765f3c3ac5093f80bd5bc4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: [PATCH 2589/2804] sysfs: Rewrite sysfs_drop_dentry. Currently we find the dentry to drop by looking at sd->s_dentry. We can just as easily accomplish the same task by looking up the sysfs inode and finding all of the dentries from there, with the added bonus that we don't need to play with the sysfs_assoc_lock. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 53 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 953e8432b0ae..1af963e66e3c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -565,50 +565,49 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) * Drop dentry for @sd. @sd must have been unlinked from its * parent on entry to this function such that it can't be looked * up anymore. - * - * @sd->s_dentry which is protected with sysfs_assoc_lock points - * to the currently associated dentry but we're not holding a - * reference to it and racing with dput(). Grab dcache_lock and - * verify dentry before dropping it. If @sd->s_dentry is NULL or - * dput() beats us, no need to bother. */ static void sysfs_drop_dentry(struct sysfs_dirent *sd) { - struct dentry *dentry = NULL; struct inode *inode; + struct dentry *dentry; - /* We're not holding a reference to ->s_dentry dentry but the - * field will stay valid as long as sysfs_assoc_lock is held. + inode = ilookup(sysfs_sb, sd->s_ino); + if (!inode) + return; + + /* Drop any existing dentries associated with sd. + * + * For the dentry to be properly freed we need to grab a + * reference to the dentry under the dcache lock, unhash it, + * and then put it. The playing with the dentry count allows + * dput to immediately free the dentry if it is not in use. */ - spin_lock(&sysfs_assoc_lock); +repeat: spin_lock(&dcache_lock); - - /* drop dentry if it's there and dput() didn't kill it yet */ - if (sd->s_dentry && sd->s_dentry->d_inode) { - dentry = dget_locked(sd->s_dentry); + list_for_each_entry(dentry, &inode->i_dentry, d_alias) { + if (d_unhashed(dentry)) + continue; + dget_locked(dentry); spin_lock(&dentry->d_lock); __d_drop(dentry); spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + dput(dentry); + goto repeat; } - spin_unlock(&dcache_lock); - spin_unlock(&sysfs_assoc_lock); - - dput(dentry); /* adjust nlink and update timestamp */ - inode = ilookup(sysfs_sb, sd->s_ino); - if (inode) { - mutex_lock(&inode->i_mutex); + mutex_lock(&inode->i_mutex); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME; + drop_nlink(inode); + if (sysfs_type(sd) == SYSFS_DIR) drop_nlink(inode); - if (sysfs_type(sd) == SYSFS_DIR) - drop_nlink(inode); - mutex_unlock(&inode->i_mutex); - iput(inode); - } + mutex_unlock(&inode->i_mutex); + + iput(inode); } /** From 932ea2e374dd1ca26676297a5eccd1cdab86f7cd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: [PATCH 2590/2804] sysfs: Introduce sysfs_rename_mutex Looking carefully at the rename code we have a subtle dependency that the structure of sysfs not change while we are performing a rename. If the parent directory of the object we are renaming changes while the rename is being performed nasty things could happen when we go to release our locks. So introduce a sysfs_rename_mutex to prevent this highly unlikely theoretical issue. In addition hold sysfs_rename_mutex over all calls to sysfs_get_dentry. Allowing sysfs_get_dentry to be simplified in the future. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 8 +++++++- fs/sysfs/file.c | 4 ++++ fs/sysfs/sysfs.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 1af963e66e3c..9fe83d23dc2c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -15,6 +15,7 @@ #include "sysfs.h" DEFINE_MUTEX(sysfs_mutex); +DEFINE_MUTEX(sysfs_rename_mutex); spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; @@ -82,7 +83,7 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) * down from there looking up dentry for each step. * * LOCKING: - * Kernel thread context (may sleep) + * mutex_lock(sysfs_rename_mutex) * * RETURNS: * Pointer to found dentry on success, ERR_PTR() value on error. @@ -858,6 +859,8 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) const char *dup_name = NULL; int error; + mutex_lock(&sysfs_rename_mutex); + /* get the original dentry */ sd = kobj->sd; old_dentry = sysfs_get_dentry(sd); @@ -915,6 +918,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) kfree(dup_name); dput(old_dentry); dput(new_dentry); + mutex_unlock(&sysfs_rename_mutex); return error; } @@ -926,6 +930,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) struct dentry *old_dentry = NULL, *new_dentry = NULL; int error; + mutex_lock(&sysfs_rename_mutex); BUG_ON(!sd->s_parent); new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; @@ -982,6 +987,7 @@ again: dput(new_parent); dput(old_dentry); dput(new_dentry); + mutex_unlock(&sysfs_rename_mutex); return error; } diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 16f39c30b091..ff93c92164b3 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -470,7 +470,9 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) if (!victim_sd) goto out; + mutex_lock(&sysfs_rename_mutex); victim = sysfs_get_dentry(victim_sd); + mutex_unlock(&sysfs_rename_mutex); if (IS_ERR(victim)) { rc = PTR_ERR(victim); victim = NULL; @@ -509,7 +511,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) if (!victim_sd) goto out; + mutex_lock(&sysfs_rename_mutex); victim = sysfs_get_dentry(victim_sd); + mutex_unlock(&sysfs_rename_mutex); if (IS_ERR(victim)) { rc = PTR_ERR(victim); victim = NULL; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 77253aabc4af..179e6a26ece1 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -90,6 +90,7 @@ extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); extern spinlock_t sysfs_assoc_lock; extern struct mutex sysfs_mutex; +extern struct mutex sysfs_rename_mutex; extern struct super_block * sysfs_sb; extern const struct file_operations sysfs_dir_operations; extern const struct file_operations sysfs_file_operations; From e0712bbfd9cb617fc3a822781c2466fb6b7ede50 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: [PATCH 2591/2804] sysfs: simply sysfs_get_dentry Now that we know the sysfs tree structure cannot change under us and sysfs shadow support is dropped, sysfs_get_dentry() can be simplified greatly. It can just look up from the root and there's no need to retry on failure. Signed-off-by: Tejun Heo Cc: Eric W. Biederman Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 91 +++++++++----------------------------------------- 1 file changed, 16 insertions(+), 75 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9fe83d23dc2c..1c3dc5d01ccd 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -78,9 +78,8 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) * @sd: sysfs_dirent of interest * * Get dentry for @sd. Dentry is looked up if currently not - * present. This function climbs sysfs_dirent tree till it - * reaches a sysfs_dirent with valid dentry attached and descends - * down from there looking up dentry for each step. + * present. This function descends from the root looking up + * dentry for each step. * * LOCKING: * mutex_lock(sysfs_rename_mutex) @@ -90,86 +89,28 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) */ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) { - struct sysfs_dirent *cur; - struct dentry *parent_dentry, *dentry; - int i, depth; + struct dentry *dentry = dget(sysfs_sb->s_root); - /* Find the first parent which has valid s_dentry and get the - * dentry. - */ - mutex_lock(&sysfs_mutex); - restart0: - spin_lock(&sysfs_assoc_lock); - restart1: - spin_lock(&dcache_lock); + while (dentry->d_fsdata != sd) { + struct sysfs_dirent *cur; + struct dentry *parent; - dentry = NULL; - depth = 0; - cur = sd; - while (!cur->s_dentry || !cur->s_dentry->d_inode) { - if (cur->s_flags & SYSFS_FLAG_REMOVED) { - dentry = ERR_PTR(-ENOENT); - depth = 0; - break; - } - cur = cur->s_parent; - depth++; - } - if (!IS_ERR(dentry)) - dentry = dget_locked(cur->s_dentry); - - spin_unlock(&dcache_lock); - spin_unlock(&sysfs_assoc_lock); - - /* from the found dentry, look up depth times */ - while (depth--) { - /* find and get depth'th ancestor */ - for (cur = sd, i = 0; cur && i < depth; i++) + /* find the first ancestor which hasn't been looked up */ + cur = sd; + while (cur->s_parent != dentry->d_fsdata) cur = cur->s_parent; - /* This can happen if tree structure was modified due - * to move/rename. Restart. - */ - if (i != depth) { - dput(dentry); - goto restart0; - } - - sysfs_get(cur); - - mutex_unlock(&sysfs_mutex); - /* look it up */ - parent_dentry = dentry; - mutex_lock(&parent_dentry->d_inode->i_mutex); - dentry = lookup_one_len_kern(cur->s_name, parent_dentry, + parent = dentry; + mutex_lock(&parent->d_inode->i_mutex); + dentry = lookup_one_len_kern(cur->s_name, parent, strlen(cur->s_name)); - mutex_unlock(&parent_dentry->d_inode->i_mutex); - dput(parent_dentry); + mutex_unlock(&parent->d_inode->i_mutex); + dput(parent); - if (IS_ERR(dentry)) { - sysfs_put(cur); - return dentry; - } - - mutex_lock(&sysfs_mutex); - spin_lock(&sysfs_assoc_lock); - - /* This, again, can happen if tree structure has - * changed and we looked up the wrong thing. Restart. - */ - if (cur->s_dentry != dentry) { - dput(dentry); - sysfs_put(cur); - goto restart1; - } - - spin_unlock(&sysfs_assoc_lock); - - sysfs_put(cur); + if (IS_ERR(dentry)) + break; } - - mutex_unlock(&sysfs_mutex); return dentry; } From 5a26b79c426f8e55ebf7204cb138eb6b1645d4d3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: [PATCH 2592/2804] sysfs: Remove s_dentry The only uses of s_dentry left are the code that maintains s_dentry and trivial users that don't actually need it. So this patch removes the s_dentry maintenance code and restructures the trivial uses to use something else. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 32 ++++---------------------------- fs/sysfs/mount.c | 1 - fs/sysfs/sysfs.h | 1 - 3 files changed, 4 insertions(+), 30 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 1c3dc5d01ccd..36b6c796d4d5 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -289,22 +289,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) { struct sysfs_dirent * sd = dentry->d_fsdata; - if (sd) { - /* sd->s_dentry is protected with sysfs_assoc_lock. - * This allows sysfs_drop_dentry() to dereference it. - */ - spin_lock(&sysfs_assoc_lock); - - /* The dentry might have been deleted or another - * lookup could have happened updating sd->s_dentry to - * point the new dentry. Ignore if it isn't pointing - * to this dentry. - */ - if (sd->s_dentry == dentry) - sd->s_dentry = NULL; - spin_unlock(&sysfs_assoc_lock); - sysfs_put(sd); - } + sysfs_put(sd); iput(inode); } @@ -352,9 +337,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) * @sd: target sysfs_dirent * @dentry: dentry to associate * - * Associate @sd with @dentry. This is protected by - * sysfs_assoc_lock to avoid race with sysfs_d_iput(). - * * LOCKING: * mutex_lock(sysfs_mutex) */ @@ -362,12 +344,6 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) { dentry->d_op = &sysfs_dentry_ops; dentry->d_fsdata = sysfs_get(sd); - - /* protect sd->s_dentry against sysfs_d_iput */ - spin_lock(&sysfs_assoc_lock); - sd->s_dentry = dentry; - spin_unlock(&sysfs_assoc_lock); - d_rehash(dentry); } @@ -846,7 +822,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) /* rename */ d_add(new_dentry, NULL); - d_move(sd->s_dentry, new_dentry); + d_move(old_dentry, new_dentry); error = 0; goto out_unlock; @@ -881,7 +857,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) error = PTR_ERR(old_dentry); goto out_dput; } - old_parent = sd->s_parent->s_dentry; + old_parent = old_dentry->d_parent; new_parent = sysfs_get_dentry(new_parent_sd); if (IS_ERR(new_parent)) { @@ -907,7 +883,7 @@ again: } else error = 0; d_add(new_dentry, NULL); - d_move(sd->s_dentry, new_dentry); + d_move(old_dentry, new_dentry); dput(new_dentry); /* Remove from old parent's list and insert into new parent's list. */ diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8989cbb51a39..28bf359981fc 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -56,7 +56,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) iput(inode); return -ENOMEM; } - sysfs_root.s_dentry = root; root->d_fsdata = &sysfs_root; sb->s_root = root; return 0; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 179e6a26ece1..791b3ed91a9b 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -37,7 +37,6 @@ struct sysfs_dirent { unsigned int s_flags; umode_t s_mode; ino_t s_ino; - struct dentry * s_dentry; struct iattr * s_iattr; atomic_t s_event; }; From 9918f9a4817cb6241c727b434d5f8ec5564198de Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:31 +0900 Subject: [PATCH 2593/2804] sysfs: Rewrite rename in terms of sysfs dirents This patch rewrites sysfs_rename_dir to perform it's checks as much as possible on the underlying sysfs_dirents instead of the contents of the dcache. It turns out that this version is a little simpler, and a little more like the rest of the sysfs directory modification code. tj: fixed double locking of sysfs_mutex Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 36b6c796d4d5..463c5e3ccf1f 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -770,7 +770,7 @@ void sysfs_remove_dir(struct kobject * kobj) int sysfs_rename_dir(struct kobject * kobj, const char *new_name) { - struct sysfs_dirent *sd; + struct sysfs_dirent *sd = kobj->sd; struct dentry *parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; const char *dup_name = NULL; @@ -778,63 +778,57 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) mutex_lock(&sysfs_rename_mutex); + error = 0; + if (strcmp(sd->s_name, new_name) == 0) + goto out; /* nothing to rename */ + /* get the original dentry */ - sd = kobj->sd; old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); - goto out_dput; + goto out; } parent = old_dentry->d_parent; /* lock parent and get dentry for new name */ mutex_lock(&parent->d_inode->i_mutex); - - new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); - if (IS_ERR(new_dentry)) { - error = PTR_ERR(new_dentry); - goto out_unlock; - } - - error = -EINVAL; - if (old_dentry == new_dentry) - goto out_unlock; + mutex_lock(&sysfs_mutex); error = -EEXIST; - if (new_dentry->d_inode) + if (sysfs_find_dirent(sd->s_parent, new_name)) + goto out_unlock; + + error = -ENOMEM; + new_dentry = d_alloc_name(parent, new_name); + if (!new_dentry) goto out_unlock; /* rename kobject and sysfs_dirent */ error = -ENOMEM; new_name = dup_name = kstrdup(new_name, GFP_KERNEL); if (!new_name) - goto out_drop; + goto out_unlock; error = kobject_set_name(kobj, "%s", new_name); if (error) - goto out_drop; + goto out_unlock; - mutex_lock(&sysfs_mutex); dup_name = sd->s_name; sd->s_name = new_name; - mutex_unlock(&sysfs_mutex); /* rename */ d_add(new_dentry, NULL); d_move(old_dentry, new_dentry); error = 0; - goto out_unlock; - - out_drop: - d_drop(new_dentry); out_unlock: + mutex_unlock(&sysfs_mutex); mutex_unlock(&parent->d_inode->i_mutex); - out_dput: kfree(dup_name); dput(old_dentry); dput(new_dentry); + out: mutex_unlock(&sysfs_rename_mutex); return error; } From 45aaae9c51d768d5a8fd53fb372b1eb714f37691 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:31 +0900 Subject: [PATCH 2594/2804] sysfs: Rewrite sysfs_move_dir in terms of sysfs dirents This patch rewrites sysfs_move_dir to perform it's checks as much as possible on the underlying sysfs_dirents instead of the contents of the dcache, making sysfs_move_dir more like the rest of the sysfs directory modification code. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 463c5e3ccf1f..da4bb66a610c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -845,56 +845,58 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) BUG_ON(!sd->s_parent); new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; + error = 0; + if (sd->s_parent == new_parent_sd) + goto out; /* nothing to move */ + /* get dentries */ old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); - goto out_dput; + goto out; } old_parent = old_dentry->d_parent; new_parent = sysfs_get_dentry(new_parent_sd); if (IS_ERR(new_parent)) { error = PTR_ERR(new_parent); - goto out_dput; + goto out; } - if (old_parent->d_inode == new_parent->d_inode) { - error = 0; - goto out_dput; /* nothing to move */ - } again: mutex_lock(&old_parent->d_inode->i_mutex); if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { mutex_unlock(&old_parent->d_inode->i_mutex); goto again; } + mutex_lock(&sysfs_mutex); - new_dentry = lookup_one_len(kobject_name(kobj), new_parent, strlen(kobject_name(kobj))); - if (IS_ERR(new_dentry)) { - error = PTR_ERR(new_dentry); + error = -EEXIST; + if (sysfs_find_dirent(new_parent_sd, sd->s_name)) goto out_unlock; - } else - error = 0; + + error = -ENOMEM; + new_dentry = d_alloc_name(new_parent, sd->s_name); + if (!new_dentry) + goto out_unlock; + + error = 0; d_add(new_dentry, NULL); d_move(old_dentry, new_dentry); dput(new_dentry); /* Remove from old parent's list and insert into new parent's list. */ - mutex_lock(&sysfs_mutex); - sysfs_unlink_sibling(sd); sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); sd->s_parent = new_parent_sd; sysfs_link_sibling(sd); - mutex_unlock(&sysfs_mutex); - out_unlock: + mutex_unlock(&sysfs_mutex); mutex_unlock(&new_parent->d_inode->i_mutex); mutex_unlock(&old_parent->d_inode->i_mutex); - out_dput: + out: dput(new_parent); dput(old_dentry); dput(new_dentry); From dc8c85871c9728c5fddca6854a191fd41eb9438c Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 12:25:38 +0200 Subject: [PATCH 2595/2804] PTY: add kernel parameter to overwrite legacy pty count Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 4 ++++ drivers/char/pty.c | 9 +++++++-- include/linux/tty.h | 1 - 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a57c1f216b21..bdddd3cd46dd 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1430,6 +1430,10 @@ and is between 256 and 4096 characters. It is defined in the file pt. [PARIDE] See Documentation/paride.txt. + pty.legacy_count= + [KNL] Number of legacy pty's. Overwrites compiled-in + default number. + quiet [KNL] Disable most log messages r128= [HW,DRM] diff --git a/drivers/char/pty.c b/drivers/char/pty.c index de14aea34e11..73de77105fea 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } +static int legacy_count = CONFIG_LEGACY_PTY_COUNT; +module_param(legacy_count, int, 0); + static void __init legacy_pty_init(void) { + if (legacy_count <= 0) + return; - pty_driver = alloc_tty_driver(NR_PTYS); + pty_driver = alloc_tty_driver(legacy_count); if (!pty_driver) panic("Couldn't allocate pty driver"); - pty_slave_driver = alloc_tty_driver(NR_PTYS); + pty_slave_driver = alloc_tty_driver(legacy_count); if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); diff --git a/include/linux/tty.h b/include/linux/tty.h index 6570719eafdf..60478f6e5dc6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -21,7 +21,6 @@ * (Note: the *_driver.minor_start values 1, 64, 128, 192 are * hardcoded at present.) */ -#define NR_PTYS CONFIG_LEGACY_PTY_COUNT /* Number of legacy ptys */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ #define NR_LDISCS 17 From 5c3e8964ce87477a12e3e9edc3742156a3929a74 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Sep 2007 02:53:13 -0700 Subject: [PATCH 2596/2804] sysfs: spit a warning to users when they try to create a duplicate sysfs file We want to let people know when we create a duplicate sysfs file, as they need to fix up their code. Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index da4bb66a610c..5d95aa8e23c6 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -428,8 +428,12 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, */ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { - if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) + if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) { + printk(KERN_WARNING "sysfs: duplicate filename '%s' " + "can not be created\n", sd->s_name); + WARN_ON(1); return -EEXIST; + } sd->s_parent = sysfs_get(acxt->parent_sd); From 181b2e4be1603ce3ccace8322047a548f29f4b20 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:09 +0900 Subject: [PATCH 2597/2804] sysfs: fix comments of sysfs_add/remove_one() sysfs_add/remove_one() now link and unlink the target dirent into and from the children list. Update comments accordingly. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5d95aa8e23c6..fc615eed67dc 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -410,10 +410,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, * @sd: sysfs_dirent to be added * * Get @acxt->parent_sd and set sd->s_parent to it and increment - * nlink of parent inode if @sd is a directory. @sd is NOT - * linked into the children list of the parent. The caller - * should invoke sysfs_link_sibling() after this function - * completes if @sd needs to be on the children list. + * nlink of parent inode if @sd is a directory and link into the + * children list of the parent. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be @@ -453,9 +451,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) * @sd: sysfs_dirent to be added * * Mark @sd removed and drop nlink of parent inode if @sd is a - * directory. @sd is NOT unlinked from the children list of the - * parent. The caller is repsonsible for removing @sd from the - * children list before calling this function. + * directory. @sd is unlinked from the children list. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be From f88123eaf953f13a0c597dde54745d28f81236de Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: [PATCH 2598/2804] sysfs: fix sysfs_chmod_file() such that it updates sd->s_mode too sysfs_chmod_file() looked and updated only inode of the target file. Dentry and inode are reclaimable and the update mode data will go away when the inode is reclaimed. This patch makes sysfs_chmod_file() update sd->s_mode too such that the change is permanent. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index ff93c92164b3..9fdf8dae0dcd 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -521,10 +521,19 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) } inode = victim->d_inode; + mutex_lock(&inode->i_mutex); + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; rc = notify_change(victim, &newattrs); + + if (rc == 0) { + mutex_lock(&sysfs_mutex); + victim_sd->s_mode = newattrs.ia_mode; + mutex_unlock(&sysfs_mutex); + } + mutex_unlock(&inode->i_mutex); out: dput(victim); From 59f69015684b3de7b9472be9a81b1a978f93a496 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: [PATCH 2599/2804] sysfs: clean up header files sysfs is about to go through major overhaul making this a pretty good opportunity to clean up (out-of-tree changes and pending patches will need regeneration anyway). Clean up headers. * Kill space between * and symbolname. * Move SYSFS_* type constants and flags into fs/sysfs/sysfs.h. They're internal to sysfs. * Reformat function prototypes and add argument symbol names. * Make dummy function definition order match that of function prototypes. * Add some comments. * Reorganize fs/sysfs/sysfs.h according to which file the declared variable or feature lives in. This patch does not introduce any behavior change. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/sysfs.h | 146 ++++++++++++++++++++++++++---------------- include/linux/sysfs.h | 143 +++++++++++++++++++---------------------- 2 files changed, 156 insertions(+), 133 deletions(-) diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 791b3ed91a9b..63adbecc9ba4 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,20 +1,24 @@ +/* type-specific structures for sysfs_dirent->s_* union members */ struct sysfs_elem_dir { - struct kobject * kobj; + struct kobject *kobj; }; struct sysfs_elem_symlink { - struct sysfs_dirent * target_sd; + struct sysfs_dirent *target_sd; }; struct sysfs_elem_attr { - struct attribute * attr; + struct attribute *attr; }; struct sysfs_elem_bin_attr { - struct bin_attribute * bin_attr; + struct bin_attribute *bin_attr; }; /* + * sysfs_dirent - the building block of sysfs hierarchy. Each and + * every sysfs node is represented by single sysfs_dirent. + * * As long as s_count reference is held, the sysfs_dirent itself is * accessible. Dereferencing s_elem or any other outer entity * requires s_active reference. @@ -22,10 +26,10 @@ struct sysfs_elem_bin_attr { struct sysfs_dirent { atomic_t s_count; atomic_t s_active; - struct sysfs_dirent * s_parent; - struct sysfs_dirent * s_sibling; - struct sysfs_dirent * s_children; - const char * s_name; + struct sysfs_dirent *s_parent; + struct sysfs_dirent *s_sibling; + struct sysfs_dirent *s_children; + const char *s_name; union { struct sysfs_elem_dir dir; @@ -37,12 +41,31 @@ struct sysfs_dirent { unsigned int s_flags; umode_t s_mode; ino_t s_ino; - struct iattr * s_iattr; + struct iattr *s_iattr; atomic_t s_event; }; -#define SD_DEACTIVATED_BIAS INT_MIN +#define SD_DEACTIVATED_BIAS INT_MIN +#define SYSFS_TYPE_MASK 0x00ff +#define SYSFS_ROOT 0x0001 +#define SYSFS_DIR 0x0002 +#define SYSFS_KOBJ_ATTR 0x0004 +#define SYSFS_KOBJ_BIN_ATTR 0x0008 +#define SYSFS_KOBJ_LINK 0x0020 +#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) + +#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +#define SYSFS_FLAG_REMOVED 0x0200 + +static inline unsigned int sysfs_type(struct sysfs_dirent *sd) +{ + return sd->s_flags & SYSFS_TYPE_MASK; +} + +/* + * Context structure to be used while adding/removing nodes. + */ struct sysfs_addrm_cxt { struct sysfs_dirent *parent_sd; struct inode *parent_inode; @@ -50,59 +73,47 @@ struct sysfs_addrm_cxt { int cnt; }; +/* + * mount.c + */ extern struct sysfs_dirent sysfs_root; +extern struct super_block *sysfs_sb; extern struct kmem_cache *sysfs_dir_cachep; -extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); -extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); -extern void sysfs_put_active(struct sysfs_dirent *sd); -extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); -extern void sysfs_put_active_two(struct sysfs_dirent *sd); -extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *parent_sd); -extern int sysfs_add_one(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd); -extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd); -extern void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); - -extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); - -extern void release_sysfs_dirent(struct sysfs_dirent * sd); -extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, - const unsigned char *name); -extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, - const unsigned char *name); -extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, - int type); - -extern int sysfs_add_file(struct sysfs_dirent *dir_sd, - const struct attribute *attr, int type); -extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); -extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name); - -extern int sysfs_create_subdir(struct kobject *kobj, const char *name, - struct sysfs_dirent **p_sd); -extern void sysfs_remove_subdir(struct sysfs_dirent *sd); - -extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); - -extern spinlock_t sysfs_assoc_lock; +/* + * dir.c + */ extern struct mutex sysfs_mutex; extern struct mutex sysfs_rename_mutex; -extern struct super_block * sysfs_sb; +extern spinlock_t sysfs_assoc_lock; + extern const struct file_operations sysfs_dir_operations; -extern const struct file_operations sysfs_file_operations; -extern const struct file_operations bin_fops; extern const struct inode_operations sysfs_dir_inode_operations; -extern const struct inode_operations sysfs_symlink_inode_operations; -static inline unsigned int sysfs_type(struct sysfs_dirent *sd) -{ - return sd->s_flags & SYSFS_TYPE_MASK; -} +struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); +struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); +void sysfs_put_active(struct sysfs_dirent *sd); +struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); +void sysfs_put_active_two(struct sysfs_dirent *sd); +void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, + struct sysfs_dirent *parent_sd); +int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); +void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); +void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); -static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) +struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, + const unsigned char *name); +struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, + const unsigned char *name); +struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); + +void release_sysfs_dirent(struct sysfs_dirent *sd); + +int sysfs_create_subdir(struct kobject *kobj, const char *name, + struct sysfs_dirent **p_sd); +void sysfs_remove_subdir(struct sysfs_dirent *sd); + +static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) { if (sd) { WARN_ON(!atomic_read(&sd->s_count)); @@ -111,8 +122,33 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) return sd; } -static inline void sysfs_put(struct sysfs_dirent * sd) +static inline void sysfs_put(struct sysfs_dirent *sd) { if (sd && atomic_dec_and_test(&sd->s_count)) release_sysfs_dirent(sd); } + +/* + * inode.c + */ +struct inode *sysfs_get_inode(struct sysfs_dirent *sd); +int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); +int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); + +/* + * file.c + */ +extern const struct file_operations sysfs_file_operations; + +int sysfs_add_file(struct sysfs_dirent *dir_sd, + const struct attribute *attr, int type); + +/* + * bin.c + */ +extern const struct file_operations bin_fops; + +/* + * symlink.c + */ +extern const struct inode_operations sysfs_symlink_inode_operations; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index c16e4c511621..b393bb449624 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -23,14 +23,14 @@ struct module; * until the tree gets cleaned up fully. */ struct attribute { - const char * name; - struct module * owner; + const char *name; + struct module *owner; mode_t mode; }; struct attribute_group { - const char * name; - struct attribute ** attrs; + const char *name; + struct attribute **attrs; }; @@ -74,65 +74,43 @@ struct sysfs_ops { ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); }; -#define SYSFS_TYPE_MASK 0x00ff -#define SYSFS_ROOT 0x0001 -#define SYSFS_DIR 0x0002 -#define SYSFS_KOBJ_ATTR 0x0004 -#define SYSFS_KOBJ_BIN_ATTR 0x0008 -#define SYSFS_KOBJ_LINK 0x0020 -#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) - -#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK -#define SYSFS_FLAG_REMOVED 0x0100 - #ifdef CONFIG_SYSFS -extern int sysfs_schedule_callback(struct kobject *kobj, - void (*func)(void *), void *data, struct module *owner); +int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), + void *data, struct module *owner); -extern int __must_check -sysfs_create_dir(struct kobject *); +int __must_check sysfs_create_dir(struct kobject *kobj); +void sysfs_remove_dir(struct kobject *kobj); +int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name); +int __must_check sysfs_move_dir(struct kobject *kobj, + struct kobject *new_parent_kobj); -extern void -sysfs_remove_dir(struct kobject *); - -extern int __must_check -sysfs_rename_dir(struct kobject *kobj, const char *new_name); - -extern int __must_check -sysfs_move_dir(struct kobject *, struct kobject *); - -extern int __must_check -sysfs_create_file(struct kobject *, const struct attribute *); - -extern int __must_check -sysfs_update_file(struct kobject *, const struct attribute *); - -extern int __must_check -sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode); - -extern void -sysfs_remove_file(struct kobject *, const struct attribute *); - -extern int __must_check -sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name); - -extern void -sysfs_remove_link(struct kobject *, const char * name); +int __must_check sysfs_create_file(struct kobject *kobj, + const struct attribute *attr); +int __must_check sysfs_update_file(struct kobject *kobj, + const struct attribute *attr); +int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, + mode_t mode); +void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr); int __must_check sysfs_create_bin_file(struct kobject *kobj, - struct bin_attribute *attr); + struct bin_attribute *attr); void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr); -int __must_check sysfs_create_group(struct kobject *, - const struct attribute_group *); -void sysfs_remove_group(struct kobject *, const struct attribute_group *); -int sysfs_add_file_to_group(struct kobject *kobj, - const struct attribute *attr, const char *group); -void sysfs_remove_file_from_group(struct kobject *kobj, - const struct attribute *attr, const char *group); +int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target, + const char *name); +void sysfs_remove_link(struct kobject *kobj, const char *name); -void sysfs_notify(struct kobject * k, char *dir, char *attr); +int __must_check sysfs_create_group(struct kobject *kobj, + const struct attribute_group *grp); +void sysfs_remove_group(struct kobject *kobj, + const struct attribute_group *grp); +int sysfs_add_file_to_group(struct kobject *kobj, + const struct attribute *attr, const char *group); +void sysfs_remove_file_from_group(struct kobject *kobj, + const struct attribute *attr, const char *group); + +void sysfs_notify(struct kobject *kobj, char *dir, char *attr); extern int __must_check sysfs_init(void); @@ -144,72 +122,81 @@ static inline int sysfs_schedule_callback(struct kobject *kobj, return -ENOSYS; } -static inline int sysfs_create_dir(struct kobject * kobj) +static inline int sysfs_create_dir(struct kobject *kobj) { return 0; } -static inline void sysfs_remove_dir(struct kobject * k) +static inline void sysfs_remove_dir(struct kobject *kobj) { ; } -static inline int sysfs_rename_dir(struct kobject * kobj, const char *new_name) +static inline int sysfs_rename_dir(struct kobject *kobj, const char *new_name) { return 0; } -static inline int sysfs_move_dir(struct kobject * k, struct kobject * new_parent) +static inline int sysfs_move_dir(struct kobject *kobj, + struct kobject *new_parent_kobj) { return 0; } -static inline int sysfs_create_file(struct kobject * k, const struct attribute * a) +static inline int sysfs_create_file(struct kobject *kobj, + const struct attribute *attr) { return 0; } -static inline int sysfs_update_file(struct kobject * k, const struct attribute * a) +static inline int sysfs_update_file(struct kobject *kobj, + const struct attribute *attr) { return 0; } -static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) +static inline int sysfs_chmod_file(struct kobject *kobj, + struct attribute *attr, mode_t mode) { return 0; } -static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a) +static inline void sysfs_remove_file(struct kobject *kobj, + const struct attribute *attr) { ; } -static inline int sysfs_create_link(struct kobject * k, struct kobject * t, const char * n) +static inline int sysfs_create_bin_file(struct kobject *kobj, + struct bin_attribute *attr) { return 0; } -static inline void sysfs_remove_link(struct kobject * k, const char * name) +static inline int sysfs_remove_bin_file(struct kobject *kobj, + struct bin_attribute *attr) +{ + return 0; +} + +static inline int sysfs_create_link(struct kobject *kobj, + struct kobject *target, const char *name) +{ + return 0; +} + +static inline void sysfs_remove_link(struct kobject *kobj, const char *name) { ; } - -static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a) +static inline int sysfs_create_group(struct kobject *kobj, + const struct attribute_group *grp) { return 0; } -static inline int sysfs_remove_bin_file(struct kobject * k, struct bin_attribute * a) -{ - return 0; -} - -static inline int sysfs_create_group(struct kobject * k, const struct attribute_group *g) -{ - return 0; -} - -static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g) +static inline void sysfs_remove_group(struct kobject *kobj, + const struct attribute_group *grp) { ; } @@ -225,7 +212,7 @@ static inline void sysfs_remove_file_from_group(struct kobject *kobj, { } -static inline void sysfs_notify(struct kobject * k, char *dir, char *attr) +static inline void sysfs_notify(struct kobject *kobj, char *dir, char *attr) { } From 5a7ad7f044941316dc98eda2a087a12a7a50649d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: [PATCH 2600/2804] sysfs: kill sysfs_update_file() sysfs_update_file() depends on inode->i_mtime but sysfs iondes are now reclaimable making the reported modification time unreliable. There's only one user (pci hotplug) of this notification mechanism and it reportedly isn't utilized from userland. Kill sysfs_update_file(). Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pci_hotplug_core.c | 60 -------------------------- fs/sysfs/file.c | 40 ----------------- include/linux/sysfs.h | 7 --- 3 files changed, 107 deletions(-) diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index bd433ef6bfc6..f0eba534f805 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -694,66 +694,6 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, if ((slot == NULL) || (info == NULL)) return -ENODEV; - /* - * check all fields in the info structure, and update timestamps - * for the files referring to the fields that have now changed. - */ - if ((has_power_file(slot) == 0) && - (slot->info->power_status != info->power_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_power.attr); - if (retval) - return retval; - } - - if ((has_attention_file(slot) == 0) && - (slot->info->attention_status != info->attention_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_attention.attr); - if (retval) - return retval; - } - - if ((has_latch_file(slot) == 0) && - (slot->info->latch_status != info->latch_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_latch.attr); - if (retval) - return retval; - } - - if ((has_adapter_file(slot) == 0) && - (slot->info->adapter_status != info->adapter_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_presence.attr); - if (retval) - return retval; - } - - if ((has_address_file(slot) == 0) && - (slot->info->address != info->address)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_address.attr); - if (retval) - return retval; - } - - if ((has_max_bus_speed_file(slot) == 0) && - (slot->info->max_bus_speed != info->max_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_max_bus_speed.attr); - if (retval) - return retval; - } - - if ((has_cur_bus_speed_file(slot) == 0) && - (slot->info->cur_bus_speed != info->cur_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_cur_bus_speed.attr); - if (retval) - return retval; - } - memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); return 0; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 9fdf8dae0dcd..61a8c19df7c3 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -3,7 +3,6 @@ */ #include -#include #include #include #include @@ -453,44 +452,6 @@ int sysfs_add_file_to_group(struct kobject *kobj, } EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); - -/** - * sysfs_update_file - update the modified timestamp on an object attribute. - * @kobj: object we're acting for. - * @attr: attribute descriptor. - */ -int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) -{ - struct sysfs_dirent *victim_sd = NULL; - struct dentry *victim = NULL; - int rc; - - rc = -ENOENT; - victim_sd = sysfs_get_dirent(kobj->sd, attr->name); - if (!victim_sd) - goto out; - - mutex_lock(&sysfs_rename_mutex); - victim = sysfs_get_dentry(victim_sd); - mutex_unlock(&sysfs_rename_mutex); - if (IS_ERR(victim)) { - rc = PTR_ERR(victim); - victim = NULL; - goto out; - } - - mutex_lock(&victim->d_inode->i_mutex); - victim->d_inode->i_mtime = CURRENT_TIME; - fsnotify_modify(victim); - mutex_unlock(&victim->d_inode->i_mutex); - rc = 0; - out: - dput(victim); - sysfs_put(victim_sd); - return rc; -} - - /** * sysfs_chmod_file - update the modified mode value on an object attribute. * @kobj: object we're acting for. @@ -641,4 +602,3 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback); EXPORT_SYMBOL_GPL(sysfs_create_file); EXPORT_SYMBOL_GPL(sysfs_remove_file); -EXPORT_SYMBOL_GPL(sysfs_update_file); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index b393bb449624..db5dd2403d08 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -87,8 +87,6 @@ int __must_check sysfs_move_dir(struct kobject *kobj, int __must_check sysfs_create_file(struct kobject *kobj, const struct attribute *attr); -int __must_check sysfs_update_file(struct kobject *kobj, - const struct attribute *attr); int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode); void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr); @@ -149,11 +147,6 @@ static inline int sysfs_create_file(struct kobject *kobj, return 0; } -static inline int sysfs_update_file(struct kobject *kobj, - const struct attribute *attr) -{ - return 0; -} static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) { From b13dc89c5a5bd5e34aadb44c0fb7e870959dcd06 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: [PATCH 2601/2804] sysfs: reposition sysfs_dirent->s_mode. Move s_mode downward such that it's side-by-side with s_iattr which is used for the same thing. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/sysfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 63adbecc9ba4..6cf61c882baa 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -39,8 +39,8 @@ struct sysfs_dirent { } s_elem; unsigned int s_flags; - umode_t s_mode; ino_t s_ino; + umode_t s_mode; struct iattr *s_iattr; atomic_t s_event; }; From b05f0548dabd20433f8c201a0307103721d6a18b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: [PATCH 2602/2804] sysfs: kill unnecessary sysfs_get() in open paths There's no reason to get an extra reference to sysfs_dirent for an open file. Open file has a reference to the dentry which in turn has a reference to sysfs_dirent. This is fairly obvious as otherwise open itself won't be able to access the sysfs_dirent. Kill the extra sysfs_get() and matching sysfs_put(). Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/bin.c | 4 +--- fs/sysfs/file.c | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index a819a7e8d74d..e93fe5e2fa41 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -193,9 +193,8 @@ static int open(struct inode * inode, struct file * file) mutex_init(&bb->mutex); file->private_data = bb; - /* open succeeded, put active reference and pin attr_sd */ + /* open succeeded, put active reference */ sysfs_put_active(attr_sd); - sysfs_get(attr_sd); return 0; err_out: @@ -211,7 +210,6 @@ static int release(struct inode * inode, struct file * file) if (bb->mmapped) sysfs_put_active_two(attr_sd); - sysfs_put(attr_sd); kfree(bb->buffer); kfree(bb); return 0; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 61a8c19df7c3..73333dc68545 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -298,9 +298,8 @@ static int sysfs_open_file(struct inode *inode, struct file *file) buffer->ops = ops; file->private_data = buffer; - /* open succeeded, put active references and pin attr_sd */ + /* open succeeded, put active references */ sysfs_put_active_two(attr_sd); - sysfs_get(attr_sd); return 0; err_out: @@ -310,11 +309,8 @@ static int sysfs_open_file(struct inode *inode, struct file *file) static int sysfs_release(struct inode * inode, struct file * filp) { - struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; struct sysfs_buffer *buffer = filp->private_data; - sysfs_put(attr_sd); - if (buffer) { if (buffer->page) free_page((unsigned long)buffer->page); From 50ab1a72863b1ad4b117862bc52610f8d4535609 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: [PATCH 2603/2804] sysfs: kill unnecessary NULL pointer check in sysfs_release() In sysfs_release(), sysfs_buffer pointed to by filp->private_data is guaranteed to exist. Kill the unnecessary NULL check. This also makes the code more consistent with the counterpart in fs/sysfs/bin.c. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 73333dc68545..8f1ebd88b9ce 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -311,11 +311,10 @@ static int sysfs_release(struct inode * inode, struct file * filp) { struct sysfs_buffer *buffer = filp->private_data; - if (buffer) { - if (buffer->page) - free_page((unsigned long)buffer->page); - kfree(buffer); - } + if (buffer->page) + free_page((unsigned long)buffer->page); + kfree(buffer); + return 0; } From 078ce6409ca54d5fc6eb7d2147cd6efc3eb09078 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: [PATCH 2604/2804] sysfs: make bin attr open get active reference of parent too All bin attr operations require active references of itself and its parent. There's no reason to allow open when its parent has been deactivated and allowing it is inconsistent with regular sysfs file. Use sysfs_get_active_two() in bin attribute open function. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/bin.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index e93fe5e2fa41..9c8f8824e660 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -171,8 +171,8 @@ static int open(struct inode * inode, struct file * file) struct bin_buffer *bb = NULL; int error; - /* need attr_sd for attr */ - if (!sysfs_get_active(attr_sd)) + /* binary file operations requires both @sd and its parent */ + if (!sysfs_get_active_two(attr_sd)) return -ENODEV; error = -EACCES; @@ -193,12 +193,12 @@ static int open(struct inode * inode, struct file * file) mutex_init(&bb->mutex); file->private_data = bb; - /* open succeeded, put active reference */ - sysfs_put_active(attr_sd); + /* open succeeded, put active references */ + sysfs_put_active_two(attr_sd); return 0; err_out: - sysfs_put_active(attr_sd); + sysfs_put_active_two(attr_sd); kfree(bb); return error; } From b1fc3d6144d56360d1373b01c7881826f558b6cd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:11 +0900 Subject: [PATCH 2605/2804] sysfs: make s_elem an anonymous union Make s_elem an anonymous union. Prefixing with s_elem makes things needlessly longer without any advantage. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/bin.c | 14 +++++++------- fs/sysfs/dir.c | 4 ++-- fs/sysfs/file.c | 14 +++++++------- fs/sysfs/inode.c | 2 +- fs/sysfs/symlink.c | 4 ++-- fs/sysfs/sysfs.h | 10 +++++----- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 9c8f8824e660..247ea19721c3 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -30,8 +30,8 @@ static int fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; /* need attr_sd for attr, its parent for kobj */ @@ -87,8 +87,8 @@ static int flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; /* need attr_sd for attr, its parent for kobj */ @@ -140,8 +140,8 @@ static int mmap(struct file *file, struct vm_area_struct *vma) { struct bin_buffer *bb = file->private_data; struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; mutex_lock(&bb->mutex); @@ -167,7 +167,7 @@ static int mmap(struct file *file, struct vm_area_struct *vma) static int open(struct inode * inode, struct file * file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; struct bin_buffer *bb = NULL; int error; diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index fc615eed67dc..6ee76a82eb38 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -273,7 +273,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) parent_sd = sd->s_parent; if (sysfs_type(sd) == SYSFS_KOBJ_LINK) - sysfs_put(sd->s_elem.symlink.target_sd); + sysfs_put(sd->s_symlink.target_sd); if (sysfs_type(sd) & SYSFS_COPY_NAME) kfree(sd->s_name); kfree(sd->s_iattr); @@ -630,7 +630,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, sd = sysfs_new_dirent(name, mode, SYSFS_DIR); if (!sd) return -ENOMEM; - sd->s_elem.dir.kobj = kobj; + sd->s_dir.kobj = kobj; /* link in */ sysfs_addrm_start(&acxt, parent_sd); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 8f1ebd88b9ce..3c91a57a1ed2 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -73,7 +73,7 @@ struct sysfs_buffer { static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_ops * ops = buffer->ops; int ret = 0; ssize_t count; @@ -88,7 +88,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer return -ENODEV; buffer->event = atomic_read(&attr_sd->s_event); - count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page); + count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); sysfs_put_active_two(attr_sd); @@ -188,7 +188,7 @@ static int flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_ops * ops = buffer->ops; int rc; @@ -196,7 +196,7 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t if (!sysfs_get_active_two(attr_sd)) return -ENODEV; - rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); + rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); sysfs_put_active_two(attr_sd); @@ -240,7 +240,7 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t static int sysfs_open_file(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_buffer * buffer; struct sysfs_ops * ops = NULL; int error; @@ -336,7 +336,7 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) { struct sysfs_buffer * buffer = filp->private_data; struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; /* need parent for the kobj, grab both */ if (!sysfs_get_active_two(attr_sd)) @@ -396,7 +396,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, sd = sysfs_new_dirent(attr->name, mode, type); if (!sd) return -ENOMEM; - sd->s_elem.attr.attr = (void *)attr; + sd->s_attr.attr = (void *)attr; sysfs_addrm_start(&acxt, dir_sd); rc = sysfs_add_one(&acxt, sd); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 0d706a86d2c7..b6ac4e6d6e79 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -172,7 +172,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) inode->i_fop = &sysfs_file_operations; break; case SYSFS_KOBJ_BIN_ATTR: - bin_attr = sd->s_elem.bin_attr.bin_attr; + bin_attr = sd->s_bin_attr.bin_attr; inode->i_size = bin_attr->size; inode->i_fop = &bin_fops; break; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 8ad38bccc0e4..ffa82e9802ad 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -86,7 +86,7 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char if (!sd) goto out_put; - sd->s_elem.symlink.target_sd = target_sd; + sd->s_symlink.target_sd = target_sd; target_sd = NULL; /* reference is now owned by the symlink */ sysfs_addrm_start(&acxt, parent_sd); @@ -142,7 +142,7 @@ static int sysfs_getlink(struct dentry *dentry, char * path) { struct sysfs_dirent *sd = dentry->d_fsdata; struct sysfs_dirent *parent_sd = sd->s_parent; - struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd; + struct sysfs_dirent *target_sd = sd->s_symlink.target_sd; int error; mutex_lock(&sysfs_mutex); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6cf61c882baa..2a68bfa46e43 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -32,11 +32,11 @@ struct sysfs_dirent { const char *s_name; union { - struct sysfs_elem_dir dir; - struct sysfs_elem_symlink symlink; - struct sysfs_elem_attr attr; - struct sysfs_elem_bin_attr bin_attr; - } s_elem; + struct sysfs_elem_dir s_dir; + struct sysfs_elem_symlink s_symlink; + struct sysfs_elem_attr s_attr; + struct sysfs_elem_bin_attr s_bin_attr; + }; unsigned int s_flags; ino_t s_ino; From d6b4fd2faeb9ddf55ce09cf90b88981e579ee010 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:11 +0900 Subject: [PATCH 2606/2804] sysfs: open code sysfs_attach_dentry() sysfs_attach_dentry() now has only one caller and isn't doing much other than obfuscating the code. Open code and kill it. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 6ee76a82eb38..48a3ed4f4537 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -332,21 +332,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) return NULL; } -/** - * sysfs_attach_dentry - associate sysfs_dirent with dentry - * @sd: target sysfs_dirent - * @dentry: dentry to associate - * - * LOCKING: - * mutex_lock(sysfs_mutex) - */ -static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) -{ - dentry->d_op = &sysfs_dentry_ops; - dentry->d_fsdata = sysfs_get(sd); - d_rehash(dentry); -} - static int sysfs_ilookup_test(struct inode *inode, void *arg) { struct sysfs_dirent *sd = arg; @@ -696,8 +681,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, goto out_unlock; } + /* instantiate and hash dentry */ + dentry->d_op = &sysfs_dentry_ops; + dentry->d_fsdata = sysfs_get(sd); d_instantiate(dentry, inode); - sysfs_attach_dentry(sd, dentry); + d_rehash(dentry); out_unlock: mutex_unlock(&sysfs_mutex); From dc2f75f0e0cac645c22c85bcf429683b3fa0d2d9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:12 +0900 Subject: [PATCH 2607/2804] sysfs: make sysfs_root a regular directory dirent sysfs_root is different from a regular directory dirent in that it's of type SYSFS_ROOT and doesn't have a name. These differences aren't used by anybody and only adds to complexity. Make sysfs_root a regular directory dirent. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/inode.c | 5 ----- fs/sysfs/mount.c | 3 ++- fs/sysfs/sysfs.h | 9 ++++----- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index b6ac4e6d6e79..c40fb9fdd04c 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -157,11 +157,6 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) /* initialize inode according to type */ switch (sysfs_type(sd)) { - case SYSFS_ROOT: - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - inc_nlink(inode); /* directory, account for "." */ - break; case SYSFS_DIR: inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 28bf359981fc..465902c18d31 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -24,8 +24,9 @@ static const struct super_operations sysfs_ops = { }; struct sysfs_dirent sysfs_root = { + .s_name = "", .s_count = ATOMIC_INIT(1), - .s_flags = SYSFS_ROOT, + .s_flags = SYSFS_DIR, .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, .s_ino = 1, }; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 2a68bfa46e43..60405a6e4c22 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -48,11 +48,10 @@ struct sysfs_dirent { #define SD_DEACTIVATED_BIAS INT_MIN #define SYSFS_TYPE_MASK 0x00ff -#define SYSFS_ROOT 0x0001 -#define SYSFS_DIR 0x0002 -#define SYSFS_KOBJ_ATTR 0x0004 -#define SYSFS_KOBJ_BIN_ATTR 0x0008 -#define SYSFS_KOBJ_LINK 0x0020 +#define SYSFS_DIR 0x0001 +#define SYSFS_KOBJ_ATTR 0x0002 +#define SYSFS_KOBJ_BIN_ATTR 0x0004 +#define SYSFS_KOBJ_LINK 0x0008 #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK From bc747f37a0f089b9366f7385ff870e12911f2383 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:12 +0900 Subject: [PATCH 2608/2804] sysfs: move sysfs_dirent->s_children into sysfs_dirent->s_dir Children list head is only meaninful for directory nodes. Move it into s_dir. This doesn't save any space currently but it will with further changes. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 17 +++++++++-------- fs/sysfs/inode.c | 2 +- fs/sysfs/sysfs.h | 3 ++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 48a3ed4f4537..4ad9422566a8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -26,7 +26,7 @@ static DEFINE_IDA(sysfs_ino_ida); * @sd: sysfs_dirent of interest * * Link @sd into its sibling list which starts from - * sd->s_parent->s_children. + * sd->s_parent->s_dir.children. * * Locking: * mutex_lock(sysfs_mutex) @@ -40,9 +40,9 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd) /* Store directory entries in order by ino. This allows * readdir to properly restart without having to add a - * cursor into the s_children list. + * cursor into the s_dir.children list. */ - for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) { + for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { if (sd->s_ino < (*pos)->s_ino) break; } @@ -55,7 +55,7 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd) * @sd: sysfs_dirent of interest * * Unlink @sd from its sibling list which starts from - * sd->s_parent->s_children. + * sd->s_parent->s_dir.children. * * Locking: * mutex_lock(sysfs_mutex) @@ -64,7 +64,8 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent **pos; - for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) { + for (pos = &sd->s_parent->s_dir.children; *pos; + pos = &(*pos)->s_sibling) { if (*pos == sd) { *pos = sd->s_sibling; sd->s_sibling = NULL; @@ -570,7 +571,7 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, { struct sysfs_dirent *sd; - for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) + for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) if (!strcmp(sd->s_name, name)) return sd; return NULL; @@ -722,7 +723,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); sysfs_addrm_start(&acxt, dir_sd); - pos = &dir_sd->s_children; + pos = &dir_sd->s_dir.children; while (*pos) { struct sysfs_dirent *sd = *pos; @@ -922,7 +923,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) mutex_lock(&sysfs_mutex); /* Skip the dentries we have already reported */ - pos = parent_sd->s_children; + pos = parent_sd->s_dir.children; while (pos && (filp->f_pos > pos->s_ino)) pos = pos->s_sibling; diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index c40fb9fdd04c..2210cf0005fe 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -127,7 +127,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) struct sysfs_dirent *child; int nr = 0; - for (child = sd->s_children; child; child = child->s_sibling) + for (child = sd->s_dir.children; child; child = child->s_sibling) if (sysfs_type(child) == SYSFS_DIR) nr++; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 60405a6e4c22..42b0327d1624 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,6 +1,8 @@ /* type-specific structures for sysfs_dirent->s_* union members */ struct sysfs_elem_dir { struct kobject *kobj; + /* children list starts here and goes through sd->s_sibling */ + struct sysfs_dirent *children; }; struct sysfs_elem_symlink { @@ -28,7 +30,6 @@ struct sysfs_dirent { atomic_t s_active; struct sysfs_dirent *s_parent; struct sysfs_dirent *s_sibling; - struct sysfs_dirent *s_children; const char *s_name; union { From 85a4ffad3de77177591f7c2c18c26c3c8dd28bff Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:12 +0900 Subject: [PATCH 2609/2804] sysfs: implement sysfs_open_dirent Implement sysfs_open_dirent which represents an open file (attribute) sysfs_dirent. A file sysfs_dirent with one or more open files have one sysfs_dirent and all sysfs_buffers (one for each open instance) are linked to it. sysfs_open_dirent doesn't actually do anything yet but will be used to off-load things which are specific for open file sysfs_dirent from it. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++- fs/sysfs/sysfs.h | 3 ++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 3c91a57a1ed2..b13ba94cf8ac 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -49,6 +49,22 @@ static struct sysfs_ops subsys_sysfs_ops = { .store = subsys_attr_store, }; +/* + * There's one sysfs_buffer for each open file and one + * sysfs_open_dirent for each sysfs_dirent with one or more open + * files. + * + * filp->private_data points to sysfs_buffer and + * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open + * is protected by sysfs_open_dirent_lock. + */ +static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; + +struct sysfs_open_dirent { + atomic_t refcnt; + struct list_head buffers; /* goes through sysfs_buffer.list */ +}; + struct sysfs_buffer { size_t count; loff_t pos; @@ -57,6 +73,7 @@ struct sysfs_buffer { struct mutex mutex; int needs_read_fill; int event; + struct list_head list; }; /** @@ -237,6 +254,86 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t return len; } +/** + * sysfs_get_open_dirent - get or create sysfs_open_dirent + * @sd: target sysfs_dirent + * @buffer: sysfs_buffer for this instance of open + * + * If @sd->s_attr.open exists, increment its reference count; + * otherwise, create one. @buffer is chained to the buffers + * list. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sysfs_get_open_dirent(struct sysfs_dirent *sd, + struct sysfs_buffer *buffer) +{ + struct sysfs_open_dirent *od, *new_od = NULL; + + retry: + spin_lock(&sysfs_open_dirent_lock); + + if (!sd->s_attr.open && new_od) { + sd->s_attr.open = new_od; + new_od = NULL; + } + + od = sd->s_attr.open; + if (od) { + atomic_inc(&od->refcnt); + list_add_tail(&buffer->list, &od->buffers); + } + + spin_unlock(&sysfs_open_dirent_lock); + + if (od) { + kfree(new_od); + return 0; + } + + /* not there, initialize a new one and retry */ + new_od = kmalloc(sizeof(*new_od), GFP_KERNEL); + if (!new_od) + return -ENOMEM; + + atomic_set(&new_od->refcnt, 0); + INIT_LIST_HEAD(&new_od->buffers); + goto retry; +} + +/** + * sysfs_put_open_dirent - put sysfs_open_dirent + * @sd: target sysfs_dirent + * @buffer: associated sysfs_buffer + * + * Put @sd->s_attr.open and unlink @buffer from the buffers list. + * If reference count reaches zero, disassociate and free it. + * + * LOCKING: + * None. + */ +static void sysfs_put_open_dirent(struct sysfs_dirent *sd, + struct sysfs_buffer *buffer) +{ + struct sysfs_open_dirent *od = sd->s_attr.open; + + spin_lock(&sysfs_open_dirent_lock); + + list_del(&buffer->list); + if (atomic_dec_and_test(&od->refcnt)) + sd->s_attr.open = NULL; + else + od = NULL; + + spin_unlock(&sysfs_open_dirent_lock); + + kfree(od); +} + static int sysfs_open_file(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; @@ -298,19 +395,29 @@ static int sysfs_open_file(struct inode *inode, struct file *file) buffer->ops = ops; file->private_data = buffer; + /* make sure we have open dirent struct */ + error = sysfs_get_open_dirent(attr_sd, buffer); + if (error) + goto err_free; + /* open succeeded, put active references */ sysfs_put_active_two(attr_sd); return 0; + err_free: + kfree(buffer); err_out: sysfs_put_active_two(attr_sd); return error; } -static int sysfs_release(struct inode * inode, struct file * filp) +static int sysfs_release(struct inode *inode, struct file *filp) { + struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; struct sysfs_buffer *buffer = filp->private_data; + sysfs_put_open_dirent(sd, buffer); + if (buffer->page) free_page((unsigned long)buffer->page); kfree(buffer); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 42b0327d1624..3adce7d5e4f7 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,3 +1,5 @@ +struct sysfs_open_dirent; + /* type-specific structures for sysfs_dirent->s_* union members */ struct sysfs_elem_dir { struct kobject *kobj; @@ -11,6 +13,7 @@ struct sysfs_elem_symlink { struct sysfs_elem_attr { struct attribute *attr; + struct sysfs_open_dirent *open; }; struct sysfs_elem_bin_attr { From a4e8b912541d5372ae049a3b7c1979968e52c40b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:12 +0900 Subject: [PATCH 2610/2804] sysfs: move sysfs file poll implementation to sysfs_open_dirent Sysfs file poll implementation is scattered over sysfs and kobject. Event numbering is done in sysfs_dirent but wait itself is done on kobject. This not only unecessarily bloats both kobject and sysfs_dirent but is also buggy - if a sysfs_dirent is removed while there still are pollers, the associaton betwen the kobject and sysfs_dirent breaks and kobject may be freed with the pollers still sleeping on it. This patch moves whole poll implementation into sysfs_open_dirent. Each time a sysfs_open_dirent is created, event number restarts from 1 and pollers sleep on sysfs_open_dirent. As event sequence number is meaningless without any open file and pollers should have open file and thus sysfs_open_dirent, this ephemeral event counting works and is a saner implementation. This patch fixes the dnagling sleepers bug and reduces the sizes of kobject and sysfs_dirent by one pointer. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 1 - fs/sysfs/file.c | 25 +++++++++++++++++++------ fs/sysfs/sysfs.h | 1 - include/linux/kobject.h | 1 - lib/kobject.c | 1 - 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 4ad9422566a8..e301a1207b60 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -318,7 +318,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) atomic_set(&sd->s_count, 1); atomic_set(&sd->s_active, 0); - atomic_set(&sd->s_event, 1); sd->s_name = name; sd->s_mode = mode; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b13ba94cf8ac..c05f9618b2dc 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -62,6 +62,8 @@ static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; struct sysfs_open_dirent { atomic_t refcnt; + atomic_t event; + wait_queue_head_t poll; struct list_head buffers; /* goes through sysfs_buffer.list */ }; @@ -104,7 +106,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer if (!sysfs_get_active_two(attr_sd)) return -ENODEV; - buffer->event = atomic_read(&attr_sd->s_event); + buffer->event = atomic_read(&attr_sd->s_attr.open->event); count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); sysfs_put_active_two(attr_sd); @@ -301,6 +303,8 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, return -ENOMEM; atomic_set(&new_od->refcnt, 0); + atomic_set(&new_od->event, 1); + init_waitqueue_head(&new_od->poll); INIT_LIST_HEAD(&new_od->buffers); goto retry; } @@ -443,17 +447,17 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) { struct sysfs_buffer * buffer = filp->private_data; struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; + struct sysfs_open_dirent *od = attr_sd->s_attr.open; /* need parent for the kobj, grab both */ if (!sysfs_get_active_two(attr_sd)) goto trigger; - poll_wait(filp, &kobj->poll, wait); + poll_wait(filp, &od->poll, wait); sysfs_put_active_two(attr_sd); - if (buffer->event != atomic_read(&attr_sd->s_event)) + if (buffer->event != atomic_read(&od->event)) goto trigger; return 0; @@ -474,8 +478,17 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr) if (sd && attr) sd = sysfs_find_dirent(sd, attr); if (sd) { - atomic_inc(&sd->s_event); - wake_up_interruptible(&k->poll); + struct sysfs_open_dirent *od; + + spin_lock(&sysfs_open_dirent_lock); + + od = sd->s_attr.open; + if (od) { + atomic_inc(&od->event); + wake_up_interruptible(&od->poll); + } + + spin_unlock(&sysfs_open_dirent_lock); } mutex_unlock(&sysfs_mutex); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3adce7d5e4f7..269c845c590f 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -46,7 +46,6 @@ struct sysfs_dirent { ino_t s_ino; umode_t s_mode; struct iattr *s_iattr; - atomic_t s_event; }; #define SD_DEACTIVATED_BIAS INT_MIN diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 0777b3f57ae6..a8a84fcccbc0 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -66,7 +66,6 @@ struct kobject { struct kset * kset; struct kobj_type * ktype; struct sysfs_dirent * sd; - wait_queue_head_t poll; }; extern int kobject_set_name(struct kobject *, const char *, ...) diff --git a/lib/kobject.c b/lib/kobject.c index e8181d3cec34..fc6db6b4bfc5 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -131,7 +131,6 @@ void kobject_init(struct kobject * kobj) return; kref_init(&kobj->kref); INIT_LIST_HEAD(&kobj->entry); - init_waitqueue_head(&kobj->poll); kobj->kset = kset_get(kobj->kset); } From e4bc16621d82ee1fd3685dcbf889a7c49891847b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 26 Sep 2007 11:12:00 -0700 Subject: [PATCH 2611/2804] driver core: remove subsystem_init() There is only one user of it, and it is only a wrapper for kset_init(). Signed-off-by: Greg Kroah-Hartman --- Documentation/kobject.txt | 1 - drivers/base/class.c | 2 +- include/linux/kobject.h | 1 - lib/kobject.c | 5 ----- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index 5e7aca261359..ca86a885ad8f 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -238,7 +238,6 @@ kobj_set_kset_s(obj,subsys) - Assumes that obj->kobj exists, and is a struct kobject. - Sets the kset of that kobject to the kset . -void subsystem_init(struct kset *s); int subsystem_register(struct kset *s); void subsystem_unregister(struct kset *s); diff --git a/drivers/base/class.c b/drivers/base/class.c index 3e9b04c30fb9..5b9cf06eab8f 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -861,7 +861,7 @@ int __init classes_init(void) /* ick, this is ugly, the things we go through to keep from showing up * in sysfs... */ - subsystem_init(&class_obj_subsys); + kset_init(&class_obj_subsys); if (!class_obj_subsys.kobj.parent) class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; return 0; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index a8a84fcccbc0..05cc5b2ddfff 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -217,7 +217,6 @@ extern struct kset hypervisor_subsys; #define kobj_set_kset_s(obj,subsys) \ (obj)->kobj.kset = &(subsys) -extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); diff --git a/lib/kobject.c b/lib/kobject.c index fc6db6b4bfc5..b7e0646f7977 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -617,11 +617,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name) return ret; } -void subsystem_init(struct kset *s) -{ - kset_init(s); -} - int subsystem_register(struct kset *s) { return kset_register(s); From adc56808f32e15fa0c0fcd5ecb4b30989076ef2b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: [PATCH 2612/2804] Driver core: rename ktype_class This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/base/class.c b/drivers/base/class.c index 5b9cf06eab8f..a863bb091e11 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = { .store = class_attr_store, }; -static struct kobj_type ktype_class = { +static struct kobj_type class_ktype = { .sysfs_ops = &class_sysfs_ops, .release = class_release, }; /* Hotplug events for classes go to the class_obj subsys */ -static decl_subsys(class, &ktype_class, NULL); +static decl_subsys(class, &class_ktype, NULL); int class_create_file(struct class * cls, const struct class_attribute * attr) @@ -323,7 +323,7 @@ static void class_dev_release(struct kobject * kobj) } } -static struct kobj_type ktype_class_device = { +static struct kobj_type class_device_ktype = { .sysfs_ops = &class_dev_sysfs_ops, .release = class_dev_release, }; @@ -332,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_class_device) { + if (ktype == &class_device_ktype) { struct class_device *class_dev = to_class_dev(kobj); if (class_dev->class) return 1; @@ -452,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = { .uevent = class_uevent, }; -static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops); +static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); static int class_device_add_attrs(struct class_device * cd) From 8f4afc410b8d2be49f34835b6bbe788f50471b02 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: [PATCH 2613/2804] Driver core: rename ktype_device This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 65de221e3bfa..c1343414d285 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj) } } -static struct kobj_type ktype_device = { +static struct kobj_type device_ktype = { .release = device_release, .sysfs_ops = &dev_sysfs_ops, }; @@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_device) { + if (ktype == &device_ktype) { struct device *dev = to_dev(kobj); if (dev->uevent_suppress) return 0; @@ -405,7 +405,7 @@ static struct device_attribute devt_attr = * devices_subsys - structure to be registered with kobject core. */ -decl_subsys(devices, &ktype_device, &device_uevent_ops); +decl_subsys(devices, &device_ktype, &device_uevent_ops); /** From a1148fb03f3c5d0bb5e6641234c2251a15741361 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: [PATCH 2614/2804] Driver core: rename ktype_driver This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 6768a01e210b..9a19b071c573 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -89,7 +89,7 @@ static void driver_release(struct kobject * kobj) */ } -static struct kobj_type ktype_driver = { +static struct kobj_type driver_ktype = { .sysfs_ops = &driver_sysfs_ops, .release = driver_release, }; @@ -868,7 +868,7 @@ int bus_register(struct bus_type * bus) kobject_set_name(&bus->drivers.kobj, "drivers"); bus->drivers.kobj.parent = &bus->subsys.kobj; - bus->drivers.ktype = &ktype_driver; + bus->drivers.ktype = &driver_ktype; retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; From e89a4116ef345cf10c21f722dd1d8bfa9b7c7d58 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: [PATCH 2615/2804] Driver core: rename ktype_edd and ktype_efivar This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/edd.c | 4 ++-- drivers/firmware/efivars.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 0fb730ee1da8..6942e065e609 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj) kfree(dev); } -static struct kobj_type ktype_edd = { +static struct kobj_type edd_ktype = { .release = edd_release, .sysfs_ops = &edd_attr_ops, .default_attrs = def_attrs, }; -static decl_subsys(edd,&ktype_edd,NULL); +static decl_subsys(edd, &edd_ktype, NULL); /** diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index bfd2d67df689..858a7b95933b 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = { NULL, }; -static struct kobj_type ktype_efivar = { +static struct kobj_type efivar_ktype = { .release = efivar_release, .sysfs_ops = &efivar_attr_ops, .default_attrs = def_attrs, @@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = { NULL, /* maybe more in the future? */ }; -static decl_subsys(vars, &ktype_efivar, NULL); +static decl_subsys(vars, &efivar_ktype, NULL); static decl_subsys(efi, NULL, NULL); /* From 6adf7554b9c70eac83251e00aa4a55f7dc830cec Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Sep 2007 14:48:53 -0700 Subject: [PATCH 2616/2804] kset: add some kerneldoc to help describe what these strange things are Signed-off-by: Greg Kroah-Hartman --- include/linux/kobject.h | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 05cc5b2ddfff..973aa7b39e02 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -117,29 +117,30 @@ struct kset_uevent_ops { struct kobj_uevent_env *env); }; -/* - * struct kset - a set of kobjects of a specific type, belonging - * to a specific subsystem. +/** + * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. * - * All kobjects of a kset should be embedded in an identical - * type. This type may have a descriptor, which the kset points - * to. This allows there to exist sets of objects of the same - * type in different subsystems. + * A kset defines a group of kobjects. They can be individually + * different "types" but overall these kobjects all want to be grouped + * together and operated on in the same manner. ksets are used to + * define the attribute callbacks and other common events that happen to + * a kobject. * - * A subsystem does not have to be a list of only one type - * of object; multiple ksets can belong to one subsystem. All - * ksets of a subsystem share the subsystem's lock. - * - * Each kset can support specific event variables; it can - * supress the event generation or add subsystem specific - * variables carried with the event. + * @ktype: the struct kobj_type for this specific kset + * @list: the list of all kobjects for this kset + * @list_lock: a lock for iterating over the kobjects + * @kobj: the embedded kobject for this kset (recursion, isn't it fun...) + * @uevent_ops: the set of uevent operations for this kset. These are + * called whenever a kobject has something happen to it so that the kset + * can add new environment variables, or filter out the uevents if so + * desired. */ struct kset { - struct kobj_type * ktype; + struct kobj_type *ktype; struct list_head list; spinlock_t list_lock; struct kobject kobj; - struct kset_uevent_ops * uevent_ops; + struct kset_uevent_ops *uevent_ops; }; From f0e7e1bd77d450ebfa12153b90f93ad46616ab4a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Sep 2007 14:48:53 -0700 Subject: [PATCH 2617/2804] kobject: update the copyrights I've been hacking on these files for a while now, might as well make it official... Signed-off-by: Greg Kroah-Hartman --- include/linux/kobject.h | 6 ++++-- lib/kobject.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 973aa7b39e02..4a0d27f475d7 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -1,8 +1,10 @@ /* * kobject.h - generic kernel object infrastructure. * - * Copyright (c) 2002-2003 Patrick Mochel - * Copyright (c) 2002-2003 Open Source Development Labs + * Copyright (c) 2002-2003 Patrick Mochel + * Copyright (c) 2002-2003 Open Source Development Labs + * Copyright (c) 2006-2007 Greg Kroah-Hartman + * Copyright (c) 2006-2007 Novell Inc. * * This file is released under the GPLv2. * diff --git a/lib/kobject.c b/lib/kobject.c index b7e0646f7977..03d40360ff1b 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -2,6 +2,8 @@ * kobject.c - library routines for handling generic kernel objects * * Copyright (c) 2002-2003 Patrick Mochel + * Copyright (c) 2006-2007 Greg Kroah-Hartman + * Copyright (c) 2006-2007 Novell Inc. * * This file is released under the GPLv2. * From 6d66f5cd26e4c482e986130b7572f2735a0f7e8b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 17:31:38 +0900 Subject: [PATCH 2618/2804] sysfs: add copyrights Sysfs has gone through considerable amount of reimplementation. Add copyrights. Any objections? :-) Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/bin.c | 8 +++++++- fs/sysfs/dir.c | 10 +++++++++- fs/sysfs/file.c | 10 +++++++++- fs/sysfs/inode.c | 8 ++++++-- fs/sysfs/mount.c | 10 +++++++++- fs/sysfs/symlink.c | 10 +++++++++- fs/sysfs/sysfs.h | 10 ++++++++++ include/linux/sysfs.h | 2 ++ 8 files changed, 61 insertions(+), 7 deletions(-) diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 247ea19721c3..006fc64227dd 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -1,9 +1,15 @@ /* - * bin.c - binary file operations for sysfs. + * fs/sysfs/bin.c - sysfs binary file implementation * * Copyright (c) 2003 Patrick Mochel * Copyright (c) 2003 Matthew Wilcox * Copyright (c) 2004 Silicon Graphics, Inc. + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #undef DEBUG diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index e301a1207b60..9161db4d6b5c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1,5 +1,13 @@ /* - * dir.c - Operations for sysfs directories. + * fs/sysfs/dir.c - sysfs core and dir operation implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #undef DEBUG diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index c05f9618b2dc..d3be1e7fb48b 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -1,5 +1,13 @@ /* - * file.c - operations for regular (text) files. + * fs/sysfs/file.c - sysfs regular (text) file implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #include diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 2210cf0005fe..9236635111f4 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -1,7 +1,11 @@ /* - * inode.c - basic inode and dentry operations. + * fs/sysfs/inode.c - basic sysfs inode and dentry operations * - * sysfs is Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. * * Please see Documentation/filesystems/sysfs.txt for more information. */ diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 465902c18d31..c76c540be3c8 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -1,5 +1,13 @@ /* - * mount.c - operations for initializing and mounting sysfs. + * fs/sysfs/symlink.c - operations for initializing and mounting sysfs + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #define DEBUG diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index ffa82e9802ad..3eac20c63c41 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -1,5 +1,13 @@ /* - * symlink.c - operations for sysfs symlinks. + * fs/sysfs/symlink.c - sysfs symlink implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #include diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 269c845c590f..f0326f281d1c 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,3 +1,13 @@ +/* + * fs/sysfs/sysfs.h - sysfs internal header file + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + */ + struct sysfs_open_dirent; /* type-specific structures for sysfs_dirent->s_* union members */ diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index db5dd2403d08..149ab62329e2 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -3,6 +3,8 @@ * * Copyright (c) 2001,2002 Patrick Mochel * Copyright (c) 2004 Silicon Graphics, Inc. + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo * * Please see Documentation/filesystems/sysfs.txt for more information. */ From cd59abfcc441b2abb4cf2cd62c1eb0f02a60e8dd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 21 Sep 2007 15:36:56 -0400 Subject: [PATCH 2619/2804] PM: merge device power-management source files This patch (as993) merges the suspend.c and resume.c files in drivers/base/power into main.c, making some public symbols private. Signed-off-by: Alan Stern Acked-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/Makefile | 2 +- drivers/base/power/main.c | 344 ++++++++++++++++++++++++++++++++++- drivers/base/power/power.h | 32 +--- drivers/base/power/resume.c | 149 --------------- drivers/base/power/suspend.c | 210 --------------------- 5 files changed, 343 insertions(+), 394 deletions(-) delete mode 100644 drivers/base/power/resume.c delete mode 100644 drivers/base/power/suspend.c diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 9caeaea753a3..a803733c839e 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,5 +1,5 @@ obj-y := shutdown.o -obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o +obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o obj-$(CONFIG_PM_TRACE) += trace.o ifeq ($(CONFIG_DEBUG_DRIVER),y) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index eb9f38d0aa58..0ab4ab21f564 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -20,19 +20,24 @@ */ #include +#include #include +#include +#include +#include "../base.h" #include "power.h" LIST_HEAD(dpm_active); -LIST_HEAD(dpm_off); -LIST_HEAD(dpm_off_irq); +static LIST_HEAD(dpm_off); +static LIST_HEAD(dpm_off_irq); -DEFINE_MUTEX(dpm_mtx); -DEFINE_MUTEX(dpm_list_mtx); +static DEFINE_MUTEX(dpm_mtx); +static DEFINE_MUTEX(dpm_list_mtx); int (*platform_enable_wakeup)(struct device *dev, int is_on); + int device_pm_add(struct device *dev) { int error; @@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev) } +/*------------------------- Resume routines -------------------------*/ + +/** + * resume_device - Restore state for one device. + * @dev: Device. + * + */ + +static int resume_device(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + down(&dev->sem); + + if (dev->bus && dev->bus->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->bus->resume(dev); + } + + if (!error && dev->type && dev->type->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->type->resume(dev); + } + + if (!error && dev->class && dev->class->resume) { + dev_dbg(dev,"class resume\n"); + error = dev->class->resume(dev); + } + + up(&dev->sem); + + TRACE_RESUME(error); + return error; +} + + +static int resume_device_early(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + if (dev->bus && dev->bus->resume_early) { + dev_dbg(dev,"EARLY resume\n"); + error = dev->bus->resume_early(dev); + } + TRACE_RESUME(error); + return error; +} + +/* + * Resume the devices that have either not gone through + * the late suspend, or that did go through it but also + * went through the early resume + */ +static void dpm_resume(void) +{ + mutex_lock(&dpm_list_mtx); + while(!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.next; + struct device * dev = to_device(entry); + + get_device(dev); + list_move_tail(entry, &dpm_active); + + mutex_unlock(&dpm_list_mtx); + resume_device(dev); + mutex_lock(&dpm_list_mtx); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); +} + + +/** + * device_resume - Restore state of each device in system. + * + * Walk the dpm_off list, remove each entry, resume the device, + * then add it to the dpm_active list. + */ + +void device_resume(void) +{ + might_sleep(); + mutex_lock(&dpm_mtx); + dpm_resume(); + mutex_unlock(&dpm_mtx); +} + +EXPORT_SYMBOL_GPL(device_resume); + + +/** + * dpm_power_up - Power on some devices. + * + * Walk the dpm_off_irq list and power each device up. This + * is used for devices that required they be powered down with + * interrupts disabled. As devices are powered on, they are moved + * to the dpm_active list. + * + * Interrupts must be disabled when calling this. + */ + +static void dpm_power_up(void) +{ + while(!list_empty(&dpm_off_irq)) { + struct list_head * entry = dpm_off_irq.next; + struct device * dev = to_device(entry); + + list_move_tail(entry, &dpm_off); + resume_device_early(dev); + } +} + + +/** + * device_power_up - Turn on all devices that need special attention. + * + * Power on system devices then devices that required we shut them down + * with interrupts disabled. + * Called with interrupts disabled. + */ + +void device_power_up(void) +{ + sysdev_resume(); + dpm_power_up(); +} + +EXPORT_SYMBOL_GPL(device_power_up); + + +/*------------------------- Suspend routines -------------------------*/ + +/* + * The entries in the dpm_active list are in a depth first order, simply + * because children are guaranteed to be discovered after parents, and + * are inserted at the back of the list on discovery. + * + * All list on the suspend path are done in reverse order, so we operate + * on the leaves of the device tree (or forests, depending on how you want + * to look at it ;) first. As nodes are removed from the back of the list, + * they are inserted into the front of their destintation lists. + * + * Things are the reverse on the resume path - iterations are done in + * forward order, and nodes are inserted at the back of their destination + * lists. This way, the ancestors will be accessed before their descendents. + */ + +static inline char *suspend_verb(u32 event) +{ + switch (event) { + case PM_EVENT_SUSPEND: return "suspend"; + case PM_EVENT_FREEZE: return "freeze"; + case PM_EVENT_PRETHAW: return "prethaw"; + default: return "(unknown suspend event)"; + } +} + + +static void +suspend_device_dbg(struct device *dev, pm_message_t state, char *info) +{ + dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), + ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? + ", may wakeup" : ""); +} + +/** + * suspend_device - Save state of one device. + * @dev: Device. + * @state: Power state device is entering. + */ + +static int suspend_device(struct device * dev, pm_message_t state) +{ + int error = 0; + + down(&dev->sem); + if (dev->power.power_state.event) { + dev_dbg(dev, "PM: suspend %d-->%d\n", + dev->power.power_state.event, state.event); + } + + if (dev->class && dev->class->suspend) { + suspend_device_dbg(dev, state, "class "); + error = dev->class->suspend(dev, state); + suspend_report_result(dev->class->suspend, error); + } + + if (!error && dev->type && dev->type->suspend) { + suspend_device_dbg(dev, state, "type "); + error = dev->type->suspend(dev, state); + suspend_report_result(dev->type->suspend, error); + } + + if (!error && dev->bus && dev->bus->suspend) { + suspend_device_dbg(dev, state, ""); + error = dev->bus->suspend(dev, state); + suspend_report_result(dev->bus->suspend, error); + } + up(&dev->sem); + return error; +} + + +/* + * This is called with interrupts off, only a single CPU + * running. We can't acquire a mutex or semaphore (and we don't + * need the protection) + */ +static int suspend_device_late(struct device *dev, pm_message_t state) +{ + int error = 0; + + if (dev->bus && dev->bus->suspend_late) { + suspend_device_dbg(dev, state, "LATE "); + error = dev->bus->suspend_late(dev, state); + suspend_report_result(dev->bus->suspend_late, error); + } + return error; +} + +/** + * device_suspend - Save state and stop all devices in system. + * @state: Power state to put each device in. + * + * Walk the dpm_active list, call ->suspend() for each device, and move + * it to the dpm_off list. + * + * (For historical reasons, if it returns -EAGAIN, that used to mean + * that the device would be called again with interrupts disabled. + * These days, we use the "suspend_late()" callback for that, so we + * print a warning and consider it an error). + * + * If we get a different error, try and back out. + * + * If we hit a failure with any of the devices, call device_resume() + * above to bring the suspended devices back to life. + * + */ + +int device_suspend(pm_message_t state) +{ + int error = 0; + + might_sleep(); + mutex_lock(&dpm_mtx); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_active) && error == 0) { + struct list_head * entry = dpm_active.prev; + struct device * dev = to_device(entry); + + get_device(dev); + mutex_unlock(&dpm_list_mtx); + + error = suspend_device(dev, state); + + mutex_lock(&dpm_list_mtx); + + /* Check if the device got removed */ + if (!list_empty(&dev->power.entry)) { + /* Move it to the dpm_off list */ + if (!error) + list_move(&dev->power.entry, &dpm_off); + } + if (error) + printk(KERN_ERR "Could not suspend device %s: " + "error %d%s\n", + kobject_name(&dev->kobj), error, + error == -EAGAIN ? " (please convert to suspend_late)" : ""); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); + if (error) + dpm_resume(); + + mutex_unlock(&dpm_mtx); + return error; +} + +EXPORT_SYMBOL_GPL(device_suspend); + +/** + * device_power_down - Shut down special devices. + * @state: Power state to enter. + * + * Walk the dpm_off_irq list, calling ->power_down() for each device that + * couldn't power down the device with interrupts enabled. When we're + * done, power down system devices. + */ + +int device_power_down(pm_message_t state) +{ + int error = 0; + struct device * dev; + + while (!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.prev; + + dev = to_device(entry); + error = suspend_device_late(dev, state); + if (error) + goto Error; + list_move(&dev->power.entry, &dpm_off_irq); + } + + error = sysdev_suspend(state); + Done: + return error; + Error: + printk(KERN_ERR "Could not power down device %s: " + "error %d\n", kobject_name(&dev->kobj), error); + dpm_power_up(); + goto Done; +} + +EXPORT_SYMBOL_GPL(device_power_down); + +void __suspend_report_result(const char *function, void *fn, int ret) +{ + if (ret) { + printk(KERN_ERR "%s(): ", function); + print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); + printk("%d\n", ret); + } +} +EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 49e64dbcce96..5c4efd493fa5 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -11,32 +11,11 @@ extern void device_shutdown(void); * main.c */ -/* - * Used to synchronize global power management operations. - */ -extern struct mutex dpm_mtx; - -/* - * Used to serialize changes to the dpm_* lists. - */ -extern struct mutex dpm_list_mtx; - -/* - * The PM lists. - */ -extern struct list_head dpm_active; -extern struct list_head dpm_off; -extern struct list_head dpm_off_irq; - - -static inline struct dev_pm_info * to_pm_info(struct list_head * entry) -{ - return container_of(entry, struct dev_pm_info, entry); -} +extern struct list_head dpm_active; /* The active device list */ static inline struct device * to_device(struct list_head * entry) { - return container_of(to_pm_info(entry), struct device, power); + return container_of(entry, struct device, power.entry); } extern int device_pm_add(struct device *); @@ -49,13 +28,6 @@ extern void device_pm_remove(struct device *); extern int dpm_sysfs_add(struct device *); extern void dpm_sysfs_remove(struct device *); -/* - * resume.c - */ - -extern void dpm_resume(void); -extern void dpm_power_up(void); - #else /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c deleted file mode 100644 index 67948bac9938..000000000000 --- a/drivers/base/power/resume.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * resume.c - Functions for waking devices up. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include "../base.h" -#include "power.h" - - -/** - * resume_device - Restore state for one device. - * @dev: Device. - * - */ - -static int resume_device(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - - down(&dev->sem); - - if (dev->bus && dev->bus->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->bus->resume(dev); - } - - if (!error && dev->type && dev->type->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->type->resume(dev); - } - - if (!error && dev->class && dev->class->resume) { - dev_dbg(dev,"class resume\n"); - error = dev->class->resume(dev); - } - - up(&dev->sem); - - TRACE_RESUME(error); - return error; -} - - -static int resume_device_early(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - if (dev->bus && dev->bus->resume_early) { - dev_dbg(dev,"EARLY resume\n"); - error = dev->bus->resume_early(dev); - } - TRACE_RESUME(error); - return error; -} - -/* - * Resume the devices that have either not gone through - * the late suspend, or that did go through it but also - * went through the early resume - */ -void dpm_resume(void) -{ - mutex_lock(&dpm_list_mtx); - while(!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.next; - struct device * dev = to_device(entry); - - get_device(dev); - list_move_tail(entry, &dpm_active); - - mutex_unlock(&dpm_list_mtx); - resume_device(dev); - mutex_lock(&dpm_list_mtx); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); -} - - -/** - * device_resume - Restore state of each device in system. - * - * Walk the dpm_off list, remove each entry, resume the device, - * then add it to the dpm_active list. - */ - -void device_resume(void) -{ - might_sleep(); - mutex_lock(&dpm_mtx); - dpm_resume(); - mutex_unlock(&dpm_mtx); -} - -EXPORT_SYMBOL_GPL(device_resume); - - -/** - * dpm_power_up - Power on some devices. - * - * Walk the dpm_off_irq list and power each device up. This - * is used for devices that required they be powered down with - * interrupts disabled. As devices are powered on, they are moved - * to the dpm_active list. - * - * Interrupts must be disabled when calling this. - */ - -void dpm_power_up(void) -{ - while(!list_empty(&dpm_off_irq)) { - struct list_head * entry = dpm_off_irq.next; - struct device * dev = to_device(entry); - - list_move_tail(entry, &dpm_off); - resume_device_early(dev); - } -} - - -/** - * device_power_up - Turn on all devices that need special attention. - * - * Power on system devices then devices that required we shut them down - * with interrupts disabled. - * Called with interrupts disabled. - */ - -void device_power_up(void) -{ - sysdev_resume(); - dpm_power_up(); -} - -EXPORT_SYMBOL_GPL(device_power_up); - - diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c deleted file mode 100644 index 204517afb15e..000000000000 --- a/drivers/base/power/suspend.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * suspend.c - Functions for putting devices to sleep. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include -#include "../base.h" -#include "power.h" - -/* - * The entries in the dpm_active list are in a depth first order, simply - * because children are guaranteed to be discovered after parents, and - * are inserted at the back of the list on discovery. - * - * All list on the suspend path are done in reverse order, so we operate - * on the leaves of the device tree (or forests, depending on how you want - * to look at it ;) first. As nodes are removed from the back of the list, - * they are inserted into the front of their destintation lists. - * - * Things are the reverse on the resume path - iterations are done in - * forward order, and nodes are inserted at the back of their destination - * lists. This way, the ancestors will be accessed before their descendents. - */ - -static inline char *suspend_verb(u32 event) -{ - switch (event) { - case PM_EVENT_SUSPEND: return "suspend"; - case PM_EVENT_FREEZE: return "freeze"; - case PM_EVENT_PRETHAW: return "prethaw"; - default: return "(unknown suspend event)"; - } -} - - -static void -suspend_device_dbg(struct device *dev, pm_message_t state, char *info) -{ - dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), - ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? - ", may wakeup" : ""); -} - -/** - * suspend_device - Save state of one device. - * @dev: Device. - * @state: Power state device is entering. - */ - -static int suspend_device(struct device * dev, pm_message_t state) -{ - int error = 0; - - down(&dev->sem); - if (dev->power.power_state.event) { - dev_dbg(dev, "PM: suspend %d-->%d\n", - dev->power.power_state.event, state.event); - } - - if (dev->class && dev->class->suspend) { - suspend_device_dbg(dev, state, "class "); - error = dev->class->suspend(dev, state); - suspend_report_result(dev->class->suspend, error); - } - - if (!error && dev->type && dev->type->suspend) { - suspend_device_dbg(dev, state, "type "); - error = dev->type->suspend(dev, state); - suspend_report_result(dev->type->suspend, error); - } - - if (!error && dev->bus && dev->bus->suspend) { - suspend_device_dbg(dev, state, ""); - error = dev->bus->suspend(dev, state); - suspend_report_result(dev->bus->suspend, error); - } - up(&dev->sem); - return error; -} - - -/* - * This is called with interrupts off, only a single CPU - * running. We can't acquire a mutex or semaphore (and we don't - * need the protection) - */ -static int suspend_device_late(struct device *dev, pm_message_t state) -{ - int error = 0; - - if (dev->bus && dev->bus->suspend_late) { - suspend_device_dbg(dev, state, "LATE "); - error = dev->bus->suspend_late(dev, state); - suspend_report_result(dev->bus->suspend_late, error); - } - return error; -} - -/** - * device_suspend - Save state and stop all devices in system. - * @state: Power state to put each device in. - * - * Walk the dpm_active list, call ->suspend() for each device, and move - * it to the dpm_off list. - * - * (For historical reasons, if it returns -EAGAIN, that used to mean - * that the device would be called again with interrupts disabled. - * These days, we use the "suspend_late()" callback for that, so we - * print a warning and consider it an error). - * - * If we get a different error, try and back out. - * - * If we hit a failure with any of the devices, call device_resume() - * above to bring the suspended devices back to life. - * - */ - -int device_suspend(pm_message_t state) -{ - int error = 0; - - might_sleep(); - mutex_lock(&dpm_mtx); - mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_active) && error == 0) { - struct list_head * entry = dpm_active.prev; - struct device * dev = to_device(entry); - - get_device(dev); - mutex_unlock(&dpm_list_mtx); - - error = suspend_device(dev, state); - - mutex_lock(&dpm_list_mtx); - - /* Check if the device got removed */ - if (!list_empty(&dev->power.entry)) { - /* Move it to the dpm_off list */ - if (!error) - list_move(&dev->power.entry, &dpm_off); - } - if (error) - printk(KERN_ERR "Could not suspend device %s: " - "error %d%s\n", - kobject_name(&dev->kobj), error, - error == -EAGAIN ? " (please convert to suspend_late)" : ""); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); - if (error) - dpm_resume(); - - mutex_unlock(&dpm_mtx); - return error; -} - -EXPORT_SYMBOL_GPL(device_suspend); - -/** - * device_power_down - Shut down special devices. - * @state: Power state to enter. - * - * Walk the dpm_off_irq list, calling ->power_down() for each device that - * couldn't power down the device with interrupts enabled. When we're - * done, power down system devices. - */ - -int device_power_down(pm_message_t state) -{ - int error = 0; - struct device * dev; - - while (!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.prev; - - dev = to_device(entry); - error = suspend_device_late(dev, state); - if (error) - goto Error; - list_move(&dev->power.entry, &dpm_off_irq); - } - - error = sysdev_suspend(state); - Done: - return error; - Error: - printk(KERN_ERR "Could not power down device %s: " - "error %d\n", kobject_name(&dev->kobj), error); - dpm_power_up(); - goto Done; -} - -EXPORT_SYMBOL_GPL(device_power_down); - -void __suspend_report_result(const char *function, void *fn, int ret) -{ - if (ret) { - printk(KERN_ERR "%s(): ", function); - print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); - printk("%d\n", ret); - } -} -EXPORT_SYMBOL_GPL(__suspend_report_result); From 011db815231f40d4d53531b5d41b82c8dc7c44bf Mon Sep 17 00:00:00 2001 From: Micah Gruber Date: Wed, 5 Sep 2007 13:49:58 +0800 Subject: [PATCH 2620/2804] USB: Remove unneeded pointer intf from speedtch_upload_firmware() This trivial patch removes the unneeded pointer intf returned from usb_ifnum_to_if(), which is never used. The check for NULL can be simply done by if (!usb_ifnum_to_if(usb_dev, 2)). Signed-off-by: Micah Gruber Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index eb0615abff68..8b132c4a503b 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, { unsigned char *buffer; struct usbatm_data *usbatm = instance->usbatm; - struct usb_interface *intf; struct usb_device *usb_dev = usbatm->usb_dev; int actual_length; int ret = 0; @@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, goto out; } - if (!(intf = usb_ifnum_to_if(usb_dev, 2))) { + if (!usb_ifnum_to_if(usb_dev, 2)) { ret = -ENODEV; usb_dbg(usbatm, "%s: interface not found!\n", __func__); goto out_free; From ca337db6f92a32347172a20b96f6f51b7bb63b7c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 21 Jul 2007 17:02:59 +0200 Subject: [PATCH 2621/2804] USB: Clean up duplicate includes in drivers/usb/ This patch cleans up duplicate includes in drivers/usb/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index b88eb3c62c02..598ad098aeeb 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include From 7f477358e2384c54b190cc3b6ce28277050a041b Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 23 Jul 2007 01:58:15 -0700 Subject: [PATCH 2622/2804] usblp: Implement the ENOSPC convention This patch implements a mode when a printer returns ENOSPC when it runs out of paper. The default remains the same as before. An application which wishes to use this function has to enable it explicitly with an ioctl LPABORT. This is done on a request by our (Fedora) CUPS guy, Tim Waugh. The API is similar enough to the lp0's one that CUPS works with both (but see below), but it's has some differences. Most importantly, the abort mode is persistent in case of lp0: once tunelp was run your cat fill blow up until you reboot or run tunelp again. For usblp, I made it so the abort mode is only in effect as long as device is open. This way you can mix and match CUPS and cat(1) freely and nothing bad happens even if you run out of paper. It is also safer in the face of any unexpected crashes. It has to be noted that mixing LPABORT and O_NONBLOCK is not advised. It probably does not do what you want: instead of returning -ENOSPC it will always return -EAGAIN (because it would otherwise block while waiting for the paper). Applications which use O_NONBLOCK should continue to use LPGETSTATUS like before. Finally, CUPS actually requires patching to take full advantage of this. It has several components; those which invoke LPABORT work, but some of them need the ioctl added. This is completely compatible, you can mix old CUPS and new kernels or vice versa. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 65 +++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 5192cd9356de..30d5a1315cc8 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -69,7 +69,6 @@ #define USBLP_DEVICE_ID_SIZE 1024 /* ioctls: */ -#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ #define IOCNR_GET_DEVICE_ID 1 #define IOCNR_GET_PROTOCOLS 2 #define IOCNR_SET_PROTOCOL 3 @@ -159,10 +158,12 @@ struct usblp { int wstatus; /* bytes written or error */ int rstatus; /* bytes ready or error */ unsigned int quirks; /* quirks flags */ + unsigned int flags; /* mode flags */ unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ unsigned char sleeping; /* interface is suspended */ + unsigned char no_paper; /* Paper Out happened */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -325,6 +326,7 @@ static void usblp_bulk_write(struct urb *urb) usblp->wstatus = status; else usblp->wstatus = urb->actual_length; + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock(&usblp->lock); @@ -411,18 +413,10 @@ static int usblp_open(struct inode *inode, struct file *file) goto out; /* - * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? - * This is #if 0-ed because we *don't* want to fail an open - * just because the printer is off-line. + * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons: + * - We do not want persistent state which close(2) does not clear + * - It is not used anyway, according to CUPS people */ -#if 0 - if ((retval = usblp_check_status(usblp, 0))) { - retval = retval > 1 ? -EIO : -ENOSPC; - goto out; - } -#else - retval = 0; -#endif retval = usb_autopm_get_interface(intf); if (retval < 0) @@ -463,6 +457,8 @@ static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; + usblp->flags &= ~LP_ABORT; + mutex_lock (&usblp_mutex); usblp->used = 0; if (usblp->present) { @@ -486,7 +482,7 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); + | ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } @@ -675,6 +671,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; + case LPABORT: + if (arg) + usblp->flags |= LP_ABORT; + else + usblp->flags &= ~LP_ABORT; + break; + default: retval = -ENOTTY; } @@ -730,6 +733,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { usblp->wstatus = 0; spin_lock_irq(&usblp->lock); + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock_irq(&usblp->lock); @@ -747,12 +751,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t /* Presume that it's going to complete well. */ writecount += transfer_length; } + if (rv == -ENOSPC) { + spin_lock_irq(&usblp->lock); + usblp->no_paper = 1; /* Mark for poll(2) */ + spin_unlock_irq(&usblp->lock); + writecount += transfer_length; + } /* Leave URB dangling, to be cleaned on close. */ goto collect_error; } if (usblp->wstatus < 0) { - usblp_check_status(usblp, 0); rv = -EIO; goto collect_error; } @@ -838,32 +847,36 @@ done: * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use * select(2) or poll(2) to wait for the buffer to drain before closing. * Alternatively, set blocking mode with fcntl and issue a zero-size write. - * - * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot - * to check the return code for timeout expiration, so it had no effect. - * Apparently, it was intended to check for error conditons, such as out - * of paper. It is going to return when we settle things with CUPS. XXX */ static int usblp_wwait(struct usblp *usblp, int nonblock) { DECLARE_WAITQUEUE(waita, current); int rc; + int err = 0; add_wait_queue(&usblp->wwait, &waita); for (;;) { + set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } - set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_wtest(usblp, nonblock)) < 0) { - mutex_unlock(&usblp->mut); - break; - } + rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); - if (rc == 0) + if (rc <= 0) break; - schedule(); + + if (usblp->flags & LP_ABORT) { + if (schedule_timeout(msecs_to_jiffies(5000)) == 0) { + err = usblp_check_status(usblp, err); + if (err == 1) { /* Paper out */ + rc = -ENOSPC; + break; + } + } + } else { + schedule(); + } } set_current_state(TASK_RUNNING); remove_wait_queue(&usblp->wwait, &waita); From e8fa0ce65c58dbb60be279c4e33534650dcacc31 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 23 Jul 2007 02:17:49 -0700 Subject: [PATCH 2623/2804] usblp: Make use of URB_FREE_BUFFER Employ the new API URB_FREE_BUFFER that we've got. There was talk of a combined constructor for this case, but apparently it's not happening, so just set the flag explicitly for now. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 30d5a1315cc8..9696668e5752 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -331,9 +331,6 @@ static void usblp_bulk_write(struct urb *urb) wake_up(&usblp->wwait); spin_unlock(&usblp->lock); - /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */ - kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */ usb_free_urb(urb); } @@ -719,6 +716,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t usb_sndbulkpipe(usblp->dev, usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), writebuf, transfer_length, usblp_bulk_write, usblp); + writeurb->transfer_flags |= URB_FREE_BUFFER; usb_anchor_urb(writeurb, &usblp->urbs); if (copy_from_user(writebuf, From 89a0fd18a96eb1f8732714b575073f8a8d69c009 Mon Sep 17 00:00:00 2001 From: Mike Nuss Date: Wed, 1 Aug 2007 13:24:30 -0700 Subject: [PATCH 2624/2804] USB: OHCI handles more ZFMicro quirks The ZF Micro OHCI controller exhibits unexpected behavior that seems to be related to high load. Under certain conditions, the controller will complete a TD, remove it from the endpoint's queue, and fail to add it to the donelist. This causes the endpoint to appear to stop responding. Worse, if the device is removed while in that state, OHCI will hang while waiting for the orphaned TD to complete. The situation is not recoverable without rebooting. This fix enhances the scope of the existing OHCI_QUIRK_ZFMICRO flag: 1. A watchdog routine periodically scans the OHCI structures to check for orphaned TDs. In these cases the TD is taken back from the controller and completed normally. 2. If a device is removed while the endpoint is hung but before the watchdog catches the situation, any outstanding TDs are taken back from the controller in the 'sanitize' phase. The ohci-hcd driver used to print "INTR_SF lossage" in this situation; this changes it to the universally accurate "ED unlink timeout". Other instances of this message presumably have different root causes. Both this Compaq quirk and a NEC quirk are now properly compiled out for non-PCI builds of this driver. Signed-off-by: Mike Nuss Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 166 ++++++++++++++++++++++++++++++------ drivers/usb/host/ohci-mem.c | 1 - drivers/usb/host/ohci-pci.c | 22 ++++- drivers/usb/host/ohci-q.c | 113 ++++++++++++++---------- drivers/usb/host/ohci.h | 26 ++++++ 5 files changed, 253 insertions(+), 75 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6edf4097d2d2..d673cb9c36b1 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose); static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); static int ohci_restart (struct ohci_hcd *ohci); -static void ohci_quirk_nec_worker (struct work_struct *work); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -314,6 +313,8 @@ rescan: if (!HC_IS_RUNNING (hcd->state)) { sanitize: ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; finish_unlinks (ohci, 0); } @@ -321,7 +322,12 @@ sanitize: case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SF too... */ if (limit-- == 0) { - ohci_warn (ohci, "IRQ INTR_SF lossage\n"); + ohci_warn(ohci, "ED unlink timeout\n"); + if (quirk_zfmicro(ohci)) { + ohci_warn(ohci, "Attempting ZF TD recovery\n"); + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + } goto sanitize; } spin_unlock_irqrestore (&ohci->lock, flags); @@ -379,6 +385,93 @@ ohci_shutdown (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); } +static int check_ed(struct ohci_hcd *ohci, struct ed *ed) +{ + return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 + && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) + == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) + && !list_empty(&ed->td_list); +} + +/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes + * an interrupt TD but neglects to add it to the donelist. On systems with + * this chipset, we need to periodically check the state of the queues to look + * for such "lost" TDs. + */ +static void unlink_watchdog_func(unsigned long _ohci) +{ + long flags; + unsigned max; + unsigned seen_count = 0; + unsigned i; + struct ed **seen = NULL; + struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; + + spin_lock_irqsave(&ohci->lock, flags); + max = ohci->eds_scheduled; + if (!max) + goto done; + + if (ohci->ed_to_check) + goto out; + + seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); + if (!seen) + goto out; + + for (i = 0; i < NUM_INTS; i++) { + struct ed *ed = ohci->periodic[i]; + + while (ed) { + unsigned temp; + + /* scan this branch of the periodic schedule tree */ + for (temp = 0; temp < seen_count; temp++) { + if (seen[temp] == ed) { + /* we've checked it and what's after */ + ed = NULL; + break; + } + } + if (!ed) + break; + seen[seen_count++] = ed; + if (!check_ed(ohci, ed)) { + ed = ed->ed_next; + continue; + } + + /* HC's TD list is empty, but HCD sees at least one + * TD that's not been sent through the donelist. + */ + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + + /* The HC may wait until the next frame to report the + * TD as done through the donelist and INTR_WDH. (We + * just *assume* it's not a multi-TD interrupt URB; + * those could defer the IRQ more than one frame, using + * DI...) Check again after the next INTR_SF. + */ + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrstatus); + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrenable); + + /* flush those writes */ + (void) ohci_readl(ohci, &ohci->regs->control); + + goto out; + } + } +out: + kfree(seen); + if (ohci->eds_scheduled) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); +done: + spin_unlock_irqrestore(&ohci->lock, flags); +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -616,6 +709,15 @@ retry: mdelay ((temp >> 23) & 0x1fe); hcd->state = HC_STATE_RUNNING; + if (quirk_zfmicro(ohci)) { + /* Create timer to watch for bad queue state on ZF Micro */ + setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, + (unsigned long) ohci); + + ohci->eds_scheduled = 0; + ohci->ed_to_check = NULL; + } + ohci_dump (ohci, 1); return 0; @@ -629,10 +731,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_regs __iomem *regs = ohci->regs; - int ints; + int ints; /* we can eliminate a (slow) ohci_readl() - if _only_ WDH caused this irq */ + * if _only_ WDH caused this irq + */ if ((ohci->hcca->done_head != 0) && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) & 0x01)) { @@ -651,7 +754,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) if (ints & OHCI_INTR_UE) { // e.g. due to PCI Master/Target Abort - if (ohci->flags & OHCI_QUIRK_NEC) { + if (quirk_nec(ohci)) { /* Workaround for a silicon bug in some NEC chips used * in Apple's PowerBooks. Adapted from Darwin code. */ @@ -713,6 +816,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } + if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { + spin_lock(&ohci->lock); + if (ohci->ed_to_check) { + struct ed *ed = ohci->ed_to_check; + + if (check_ed(ohci, ed)) { + /* HC thinks the TD list is empty; HCD knows + * at least one TD is outstanding + */ + if (--ohci->zf_delay == 0) { + struct td *td = list_entry( + ed->td_list.next, + struct td, td_list); + ohci_warn(ohci, + "Reclaiming orphan TD %p\n", + td); + takeback_td(ohci, td); + ohci->ed_to_check = NULL; + } + } else + ohci->ed_to_check = NULL; + } + spin_unlock(&ohci->lock); + } + /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled @@ -721,7 +849,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) spin_lock (&ohci->lock); if (ohci->ed_rm_list) finish_unlinks (ohci, ohci_frame_no(ohci)); - if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list + if ((ints & OHCI_INTR_SF) != 0 + && !ohci->ed_rm_list + && !ohci->ed_to_check && HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); @@ -751,6 +881,9 @@ static void ohci_stop (struct usb_hcd *hcd) free_irq(hcd->irq, hcd); hcd->irq = -1; + if (quirk_zfmicro(ohci)) + del_timer(&ohci->unlink_watchdog); + remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { @@ -828,27 +961,6 @@ static int ohci_restart (struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -/* NEC workaround */ -static void ohci_quirk_nec_worker(struct work_struct *work) -{ - struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); - int status; - - status = ohci_init(ohci); - if (status != 0) { - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_init, %d\n", status); - return; - } - - status = ohci_restart(ohci); - if (status != 0) - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_restart, %d\n", status); -} - -/*-------------------------------------------------------------------------*/ - #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_AUTHOR (DRIVER_AUTHOR); diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 450c7b460c5a..2f20d3dc895b 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); - INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a5e2eb85d073..d0360f65ebd9 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); + ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n"); return 0; } @@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd) /* Check for NEC chip and apply quirk for allegedly lost interrupts. */ + +static void ohci_quirk_nec_worker(struct work_struct *work) +{ + struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); + int status; + + status = ohci_init(ohci); + if (status != 0) { + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_init", status); + return; + } + + status = ohci_restart(ohci); + if (status != 0) + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_restart", status); +} + static int ohci_quirk_nec(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_NEC; + INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker); ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n"); return 0; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 830a3fe8615e..547d39be3eb9 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -179,6 +179,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ed->ed_prev = NULL; ed->ed_next = NULL; ed->hwNextED = 0; + if (quirk_zfmicro(ohci) + && (ed->type == PIPE_INTERRUPT) + && !(ohci->eds_scheduled++)) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); wmb (); /* we care about rm_list when setting CLE/BLE in case the HC was at @@ -940,8 +944,12 @@ skip_ed: TD_MASK; /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) - goto skip_ed; + if (td->td_dma != head) { + if (ed == ohci->ed_to_check) + ohci->ed_to_check = NULL; + else + goto skip_ed; + } } } @@ -998,6 +1006,8 @@ rescan_this: /* ED's now officially unlinked, hc doesn't see */ ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); ed->hwNextED = 0; wmb (); @@ -1021,7 +1031,7 @@ rescan_this: if (ohci->ed_controltail) { command |= OHCI_CLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_CLE)) { control |= OHCI_CTRL_CLE; @@ -1031,7 +1041,7 @@ rescan_this: } if (ohci->ed_bulktail) { command |= OHCI_BLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_BLE)) { control |= OHCI_CTRL_BLE; @@ -1043,13 +1053,13 @@ rescan_this: /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ if (control) { ohci->hc_control |= control; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } if (command) { - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, command, &ohci->regs->cmdstatus); } @@ -1060,12 +1070,60 @@ rescan_this: /*-------------------------------------------------------------------------*/ +/* + * Used to take back a TD from the host controller. This would normally be + * called from within dl_done_list, however it may be called directly if the + * HC no longer sees the TD and it has not appeared on the donelist (after + * two frames). This bug has been observed on ZF Micro systems. + */ +static void takeback_td(struct ohci_hcd *ohci, struct td *td) +{ + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + + /* update URB's length and status from TD */ + td_done(ohci, urb, td); + urb_priv->td_cnt++; + + /* If all this urb's TDs are done, call complete() */ + if (urb_priv->td_cnt == urb_priv->length) + finish_urb(ohci, urb); + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty(&ed->td_list)) { + if (ed->state == ED_OPER) + start_ed_unlink(ohci, ed); + + /* ... reenabling halted EDs only after fault cleanup */ + } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE)) + == cpu_to_hc32(ohci, ED_SKIP)) { + td = list_entry(ed->td_list.next, struct td, td_list); + if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) { + ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP); + /* ... hc may need waking-up */ + switch (ed->type) { + case PIPE_CONTROL: + ohci_writel(ohci, OHCI_CLF, + &ohci->regs->cmdstatus); + break; + case PIPE_BULK: + ohci_writel(ohci, OHCI_BLF, + &ohci->regs->cmdstatus); + break; + } + } + } +} + /* * Process normal completions (error or success) and clean the schedules. * * This is the main path for handing urbs back to drivers. The only other - * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of - * scanning the (re-reversed) donelist as this does. + * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, + * instead of scanning the (re-reversed) donelist as this does. There's + * an abnormal path too, handling a quirk in some Compaq silicon: URBs + * with TDs that appear to be orphaned are directly reclaimed. */ static void dl_done_list (struct ohci_hcd *ohci) @@ -1074,44 +1132,7 @@ dl_done_list (struct ohci_hcd *ohci) while (td) { struct td *td_next = td->next_dl_td; - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - - /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb); - - /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty (&ed->td_list)) { - if (ed->state == ED_OPER) - start_ed_unlink (ohci, ed); - - /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32 (ohci, - ED_SKIP | ED_DEQUEUE)) - == cpu_to_hc32 (ohci, ED_SKIP)) { - td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); - /* ... hc may need waking-up */ - switch (ed->type) { - case PIPE_CONTROL: - ohci_writel (ohci, OHCI_CLF, - &ohci->regs->cmdstatus); - break; - case PIPE_BULK: - ohci_writel (ohci, OHCI_BLF, - &ohci->regs->cmdstatus); - break; - } - } - } - + takeback_td(ohci, td); td = td_next; } } diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 4ada43cf1387..dd4d5b4dcb6c 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -401,8 +401,34 @@ struct ohci_hcd { // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ + + /* Needed for ZF Micro quirk */ + struct timer_list unlink_watchdog; + unsigned eds_scheduled; + struct ed *ed_to_check; + unsigned zf_delay; }; +#ifdef CONFIG_PCI +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_NEC; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_ZFMICRO; +} +#else +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return 0; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return 0; +} +#endif + /* convert between an hcd pointer and the corresponding ohci_hcd */ static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd) { From 9f705bde6e77c24a3ba737ac45abc0f8e619e92e Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 1 Aug 2007 18:16:55 -0400 Subject: [PATCH 2625/2804] USB: Remove dead references to "SAFE_SERIAL" CONFIG variables. Remove the references to CONFIG_USBD_SAFE_SERIAL_{VENDOR,PRODUCT}, which aren't defined in any Kconfig file. Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/safe_serial.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 51669b7622bb..4e6dcc199be9 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE("GPL"); -#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) -#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" -#endif - -#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) static __u16 vendor; // no default static __u16 product; // no default module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); -#endif module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); @@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = { {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp -#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR) - {MY_USB_DEVICE - (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS, - LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, -#endif // extra null entry for module // vendor/produc parameters {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, From efc9052e01fd316b7bd6b108feff7689c927ebe9 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 1 Aug 2007 16:04:53 -0700 Subject: [PATCH 2626/2804] USB: usb_gadget.h whitespace fixes This just fixes some whitespace bugs in , mostly extraneous spaces where a single tab suffices. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- include/linux/usb_gadget.h | 62 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 4f59b2aa8a9e..ec9732e7fea2 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -22,10 +22,10 @@ struct usb_ep; /** * struct usb_request - describes one i/o request * @buf: Buffer used for data. Always provide this; some controllers - * only use PIO, or don't use DMA for some endpoints. + * only use PIO, or don't use DMA for some endpoints. * @dma: DMA address corresponding to 'buf'. If you don't set this - * field, and the usb controller needs one, it is responsible - * for mapping and unmapping the buffer. + * field, and the usb controller needs one, it is responsible + * for mapping and unmapping the buffer. * @length: Length of that data * @no_interrupt: If true, hints that no completion irq is needed. * Helpful sometimes with deep request queues that are handled @@ -45,16 +45,16 @@ struct usb_ep; * @context: For use by the completion callback * @list: For use by the gadget driver. * @status: Reports completion code, zero or a negative errno. - * Normally, faults block the transfer queue from advancing until - * the completion callback returns. - * Code "-ESHUTDOWN" indicates completion caused by device disconnect, - * or when the driver disabled the endpoint. + * Normally, faults block the transfer queue from advancing until + * the completion callback returns. + * Code "-ESHUTDOWN" indicates completion caused by device disconnect, + * or when the driver disabled the endpoint. * @actual: Reports bytes transferred to/from the buffer. For reads (OUT - * transfers) this may be less than the requested length. If the - * short_not_ok flag is set, short reads are treated as errors - * even when status otherwise indicates successful completion. - * Note that for writes (IN transfers) some data bytes may still - * reside in a device-side FIFO when the request is reported as + * transfers) this may be less than the requested length. If the + * short_not_ok flag is set, short reads are treated as errors + * even when status otherwise indicates successful completion. + * Note that for writes (IN transfers) some data bytes may still + * reside in a device-side FIFO when the request is reported as * complete. * * These are allocated/freed through the endpoint they're used with. The @@ -128,7 +128,7 @@ struct usb_ep_ops { * value can sometimes be reduced (hardware allowing), according to * the endpoint descriptor used to configure the endpoint. * @driver_data:for use by the gadget driver. all other fields are - * read-only to gadget drivers. + * read-only to gadget drivers. * * the bus controller driver lists all the general purpose endpoints in * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, @@ -148,10 +148,10 @@ struct usb_ep { /** * usb_ep_enable - configure endpoint, making it usable * @ep:the endpoint being configured. may not be the endpoint named "ep0". - * drivers discover endpoints through the ep_list of a usb_gadget. + * drivers discover endpoints through the ep_list of a usb_gadget. * @desc:descriptor for desired behavior. caller guarantees this pointer - * remains valid until the endpoint is disabled; the data byte order - * is little-endian (usb-standard). + * remains valid until the endpoint is disabled; the data byte order + * is little-endian (usb-standard). * * when configurations are set, or when interface settings change, the driver * will enable or disable the relevant endpoints. while it is enabled, an @@ -232,7 +232,7 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) * @ep:the endpoint associated with the request * @req:the request being submitted * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't - * pre-allocate all necessary memory with the request. + * pre-allocate all necessary memory with the request. * * This tells the device controller to perform the specified request through * that endpoint (reading or writing a buffer). When the request completes, @@ -415,7 +415,7 @@ struct usb_gadget_ops { * struct usb_gadget - represents a usb slave device * @ops: Function pointers used to access hardware-specific operations. * @ep0: Endpoint zero, used when reading or writing responses to - * driver setup() requests + * driver setup() requests * @ep_list: List of other endpoints supported by the device. * @speed: Speed of current connection to USB host. * @is_dualspeed: True if the controller supports both high and full speed @@ -432,7 +432,7 @@ struct usb_gadget_ops { * @b_hnp_enable: OTG device feature flag, indicating that the A-Host * enabled HNP support. * @name: Identifies the controller hardware type. Used in diagnostics - * and sometimes configuration. + * and sometimes configuration. * @dev: Driver model state for this abstract device. * * Gadgets have a mostly-portable "gadget driver" implementing device @@ -655,23 +655,23 @@ usb_gadget_disconnect (struct usb_gadget *gadget) * @function: String describing the gadget's function * @speed: Highest speed the driver handles. * @bind: Invoked when the driver is bound to a gadget, usually - * after registering the driver. - * At that point, ep0 is fully initialized, and ep_list holds - * the currently-available endpoints. - * Called in a context that permits sleeping. + * after registering the driver. + * At that point, ep0 is fully initialized, and ep_list holds + * the currently-available endpoints. + * Called in a context that permits sleeping. * @setup: Invoked for ep0 control requests that aren't handled by - * the hardware level driver. Most calls must be handled by - * the gadget driver, including descriptor and configuration - * management. The 16 bit members of the setup data are in - * USB byte order. Called in_interrupt; this may not sleep. Driver + * the hardware level driver. Most calls must be handled by + * the gadget driver, including descriptor and configuration + * management. The 16 bit members of the setup data are in + * USB byte order. Called in_interrupt; this may not sleep. Driver * queues a response to ep0, or returns negative to stall. * @disconnect: Invoked after all transfers have been stopped, - * when the host is disconnected. May be called in_interrupt; this - * may not sleep. Some devices can't detect disconnect, so this might + * when the host is disconnected. May be called in_interrupt; this + * may not sleep. Some devices can't detect disconnect, so this might * not be called except as part of controller shutdown. * @unbind: Invoked when the driver is unbound from a gadget, - * usually from rmmod (after a disconnect is reported). - * Called in a context that permits sleeping. + * usually from rmmod (after a disconnect is reported). + * Called in a context that permits sleeping. * @suspend: Invoked on USB suspend. May be called in_interrupt. * @resume: Invoked on USB resume. May be called in_interrupt. * @driver: Driver model state for this driver. From a96173af521a173f45d3a27fa24265081f12e978 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 31 Jul 2007 00:28:22 +0200 Subject: [PATCH 2627/2804] USB: Storage: usbat_check_status(): fix check-after-use The Coverity checker spotted that we have already oops'ed if "us" was NULL. Since "us" can't be NULL in the only caller this patch removes the NULL check. Signed-off-by: Adrian Bunk Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/shuttle_usbat.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 5e27297c0175..17ca4d73577b 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us) unsigned char *reply = us->iobuf; int rc; - if (!us) - return USB_STOR_TRANSPORT_ERROR; - rc = usbat_get_status(us, reply); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; From 5b653c79c04c6b152b8dc7d18f8c8a7f77f4b235 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:04:37 -0400 Subject: [PATCH 2628/2804] USB: add urb->ep This patch (as943) prepares the way for eliminating urb->pipe by introducing an endpoint pointer into struct urb. For now urb->ep is set by usb_submit_urb() from the pipe value; eventually drivers will set it themselves and we will remove urb->pipe completely. The patch also adds new inline routines to retrieve an endpoint descriptor's number and transfer type, essentially as replacements for usb_pipeendpoint and usb_pipetype. usb_submit_urb(), usb_hcd_submit_urb(), and usb_hcd_unlink_urb() are converted to use the new field and new routines. Other parts of usbcore will be converted in later patches. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 13 +++------ drivers/usb/core/urb.c | 65 +++++++++++++++++++++++------------------- include/linux/usb.h | 26 +++++++++++++++++ 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 42ef1d5f6c8a..fb82c500caf4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -962,14 +962,14 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) spin_lock_irqsave(&hcd_urb_list_lock, flags); ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) [usb_pipeendpoint(urb->pipe)]; - if (unlikely (!ep)) + if (unlikely(ep != urb->ep)) status = -ENOENT; else if (unlikely (urb->reject)) status = -EPERM; else switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: - list_add_tail (&urb->urb_list, &ep->urb_list); + list_add_tail (&urb->urb_list, &urb->ep->urb_list); status = 0; break; default: @@ -1022,7 +1022,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) : DMA_TO_DEVICE); } - status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); + status = hcd->driver->urb_enqueue (hcd, urb->ep, urb, mem_flags); done: if (unlikely (status)) { urb_unlink(hcd, urb); @@ -1071,7 +1071,6 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ int usb_hcd_unlink_urb (struct urb *urb, int status) { - struct usb_host_endpoint *ep; struct usb_hcd *hcd = NULL; struct device *sys = NULL; unsigned long flags; @@ -1082,10 +1081,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) return -EINVAL; if (!urb->dev || !urb->dev->bus) return -ENODEV; - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (!ep) - return -ENODEV; /* * we contend for urb->status with the hcd core, @@ -1109,7 +1104,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) } /* insist the urb is still queued */ - list_for_each(tmp, &ep->urb_list) { + list_for_each(tmp, &urb->ep->urb_list) { if (tmp == &urb->urb_list) break; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index be630228461c..ff53acb4fab2 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -277,9 +277,10 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - int pipe, temp, max; - struct usb_device *dev; - int is_out; + int xfertype, max; + struct usb_device *dev; + struct usb_host_endpoint *ep; + int is_out; if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; @@ -291,30 +292,34 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) || dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; + /* For now, get the endpoint from the pipe. Eventually drivers + * will be required to set urb->ep directly and we will eliminate + * urb->pipe. + */ + ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) + return -ENOENT; + + urb->ep = ep; urb->status = -EINPROGRESS; urb->actual_length = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests */ - pipe = urb->pipe; - temp = usb_pipetype(pipe); - is_out = usb_pipeout(pipe); + xfertype = usb_endpoint_type(&ep->desc); + is_out = usb_pipeout(urb->pipe); - if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) + if (xfertype != USB_ENDPOINT_XFER_CONTROL && + dev->state < USB_STATE_CONFIGURED) return -ENODEV; - /* FIXME there should be a sharable lock protecting us against - * config/altsetting changes and disconnects, kicking in here. - * (here == before maxpacket, and eventually endpoint type, - * checks get made.) - */ - - max = usb_maxpacket(dev, pipe, is_out); + max = le16_to_cpu(ep->desc.wMaxPacketSize); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_pipeendpoint(pipe), is_out ? "out" : "in", + usb_endpoint_num(&ep->desc), is_out ? "out" : "in", __FUNCTION__, max); return -EMSGSIZE; } @@ -323,7 +328,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * but drivers only control those sizes for ISO. * while we're checking, initialize return status. */ - if (temp == PIPE_ISOCHRONOUS) { + if (xfertype == USB_ENDPOINT_XFER_ISOC) { int n, len; /* "high bandwidth" mode, 1-3 packets/uframe? */ @@ -359,19 +364,19 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_NO_INTERRUPT); - switch (temp) { - case PIPE_BULK: + switch (xfertype) { + case USB_ENDPOINT_XFER_BULK: if (is_out) allowed |= URB_ZERO_PACKET; /* FALLTHROUGH */ - case PIPE_CONTROL: + case USB_ENDPOINT_XFER_CONTROL: allowed |= URB_NO_FSBR; /* only affects UHCI */ /* FALLTHROUGH */ default: /* all non-iso endpoints */ if (!is_out) allowed |= URB_SHORT_NOT_OK; break; - case PIPE_ISOCHRONOUS: + case USB_ENDPOINT_XFER_ISOC: allowed |= URB_ISO_ASAP; break; } @@ -393,9 +398,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * supports different values... this uses EHCI/UHCI defaults (and * EHCI can use smaller non-default values). */ - switch (temp) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: + switch (xfertype) { + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_INT: /* too small? */ if (urb->interval <= 0) return -EINVAL; @@ -405,29 +410,29 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) // NOTE usb handles 2^15 if (urb->interval > (1024 * 8)) urb->interval = 1024 * 8; - temp = 1024 * 8; + max = 1024 * 8; break; case USB_SPEED_FULL: /* units are frames/msec */ case USB_SPEED_LOW: - if (temp == PIPE_INTERRUPT) { + if (xfertype == USB_ENDPOINT_XFER_INT) { if (urb->interval > 255) return -EINVAL; // NOTE ohci only handles up to 32 - temp = 128; + max = 128; } else { if (urb->interval > 1024) urb->interval = 1024; // NOTE usb and ohci handle up to 2^15 - temp = 1024; + max = 1024; } break; default: return -EINVAL; } /* power of two? */ - while (temp > urb->interval) - temp >>= 1; - urb->interval = temp; + while (max > urb->interval) + max >>= 1; + urb->interval = max; } return usb_hcd_submit_urb(urb, mem_flags); diff --git a/include/linux/usb.h b/include/linux/usb.h index 4f33a58fa9d1..105e3e9362d0 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -554,6 +554,29 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, /*-------------------------------------------------------------------------*/ +/** + * usb_endpoint_num - get the endpoint's number + * @epd: endpoint to be checked + * + * Returns @epd's number: 0 to 15. + */ +static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd) +{ + return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; +} + +/** + * usb_endpoint_type - get the endpoint's transfer type + * @epd: endpoint to be checked + * + * Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according + * to @epd's transfer type. + */ +static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd) +{ + return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; +} + /** * usb_endpoint_dir_in - check if the endpoint has IN direction * @epd: endpoint to be checked @@ -1037,6 +1060,8 @@ typedef void (*usb_complete_t)(struct urb *); * @urb_list: For use by current owner of the URB. * @anchor_list: membership in the list of an anchor * @anchor: to anchor URBs to a common mooring + * @ep: Points to the endpoint's data structure. Will eventually + * replace @pipe. * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" @@ -1212,6 +1237,7 @@ struct urb struct list_head anchor_list; /* the URB may be anchored by the driver */ struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ + struct usb_host_endpoint *ep; /* (internal) pointer to endpoint struct */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ From bdd016ba64d909329cb4bacacc8443901c00e112 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:05:22 -0400 Subject: [PATCH 2629/2804] USB: add ep->enable This patch (as944) adds an explicit "enabled" field to the usb_host_endpoint structure and uses it in place of the current mechanism. This is merely a time-space tradeoff; it makes checking whether URBs may be submitted to an endpoint simpler. The existing mechanism is efficient when converting urb->pipe to an endpoint pointer, but it's not so efficient when urb->ep is used instead. As a side effect, the procedure for enabling an endpoint is now a little more complicated. The ad-hoc inline code in usb.c and hub.c for enabling ep0 is now replaced with calls to usb_enable_endpoint, which is no longer static. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 5 +---- drivers/usb/core/hub.c | 2 +- drivers/usb/core/message.c | 20 ++++++++++---------- drivers/usb/core/usb.c | 2 +- drivers/usb/core/usb.h | 2 ++ include/linux/usb.h | 2 ++ 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fb82c500caf4..cc5b1d3c3680 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -943,7 +943,6 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - struct usb_host_endpoint *ep; unsigned long flags; if (!hcd) @@ -960,9 +959,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) // FIXME: verify that quiescing hc works right (RH cleans up) spin_lock_irqsave(&hcd_urb_list_lock, flags); - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (unlikely(ep != urb->ep)) + if (unlikely(!urb->ep->enabled)) status = -ENOENT; else if (unlikely (urb->reject)) status = -EPERM; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f7b337feb3ea..c8a01f66df70 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1999,7 +1999,7 @@ static void ep0_reinit(struct usb_device *udev) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - udev->ep_in[0] = udev->ep_out[0] = &udev->ep0; + usb_enable_endpoint(udev, &udev->ep0); } #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d8f7b089a8f0..0d618647758e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1013,8 +1013,10 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ep = dev->ep_in[epnum]; dev->ep_in[epnum] = NULL; } - if (ep && dev->bus) + if (ep) { + ep->enabled = 0; usb_hcd_endpoint_disable(dev, ep); + } } /** @@ -1096,23 +1098,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers. * For control endpoints, both the input and output sides are handled. */ -static void -usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) +void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) { - unsigned int epaddr = ep->desc.bEndpointAddress; - unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - int is_control; + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + int is_control = usb_endpoint_xfer_control(&ep->desc); - is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_CONTROL); - if (usb_endpoint_out(epaddr) || is_control) { + if (is_out || is_control) { usb_settoggle(dev, epnum, 1, 0); dev->ep_out[epnum] = ep; } - if (!usb_endpoint_out(epaddr) || is_control) { + if (!is_out || is_control) { usb_settoggle(dev, epnum, 0, 0); dev->ep_in[epnum] = ep; } + ep->enabled = 1; } /* diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0fee5c66fd64..d3c68d8eafb2 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -260,7 +260,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ - dev->ep_in[0] = dev->ep_out[0] = &dev->ep0; + usb_enable_endpoint(dev, &dev->ep0); /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index ad5fa0338f49..cde6e52b84fe 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -8,6 +8,8 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint * struct usb_device *udev); extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); +extern void usb_enable_endpoint(struct usb_device *dev, + struct usb_host_endpoint *ep); extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); diff --git a/include/linux/usb.h b/include/linux/usb.h index 105e3e9362d0..818a1b4f737a 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -52,6 +52,7 @@ struct ep_device; * @ep_dev: ep_device for sysfs info * @extra: descriptors following this endpoint in the configuration * @extralen: how many bytes of "extra" are valid + * @enabled: URBs may be submitted to this endpoint * * USB requests are always queued to a given endpoint, identified by a * descriptor within an active interface in a given USB configuration. @@ -64,6 +65,7 @@ struct usb_host_endpoint { unsigned char *extra; /* Extra descriptors */ int extralen; + int enabled; }; /* host-side wrapper for one interface setting's parsed descriptors */ From fea3409112a93581db18da4c4332c8bf8d68af6b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:06:16 -0400 Subject: [PATCH 2630/2804] USB: add direction bit to urb->transfer_flags This patch (as945) adds a bit to urb->transfer_flags for recording the direction of the URB. The bit is set/cleared automatically in usb_submit_urb() so drivers don't have to worry about it (although as a result, it isn't valid until the URB has been submitted). Inline routines are added for easily checking an URB's direction. They replace calls to usb_pipein in the DMA-mapping parts of hcd.c. For non-control endpoints, the direction is determined directly from the endpoint descriptor. However control endpoints are bi-directional; for them the direction is determined from the bRequestType byte and the wLength value in the setup packet. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 4 ++-- drivers/usb/core/urb.c | 18 ++++++++++++++++-- include/linux/usb.h | 30 ++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index cc5b1d3c3680..bcbaedc897d5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -928,7 +928,7 @@ static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) dma_unmap_single (hcd->self.controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } @@ -1014,7 +1014,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index ff53acb4fab2..1a64a6a850f3 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -309,7 +309,21 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * and don't need to duplicate tests */ xfertype = usb_endpoint_type(&ep->desc); - is_out = usb_pipeout(urb->pipe); + if (xfertype == USB_ENDPOINT_XFER_CONTROL) { + struct usb_ctrlrequest *setup = + (struct usb_ctrlrequest *) urb->setup_packet; + + if (!setup) + return -ENOEXEC; + is_out = !(setup->bRequestType & USB_DIR_IN) || + !setup->wLength; + } else { + is_out = usb_endpoint_dir_out(&ep->desc); + } + + /* Cache the direction for later use */ + urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) | + (is_out ? URB_DIR_OUT : URB_DIR_IN); if (xfertype != USB_ENDPOINT_XFER_CONTROL && dev->state < USB_STATE_CONFIGURED) @@ -363,7 +377,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | - URB_NO_INTERRUPT); + URB_NO_INTERRUPT | URB_DIR_MASK); switch (xfertype) { case USB_ENDPOINT_XFER_BULK: if (is_out) diff --git a/include/linux/usb.h b/include/linux/usb.h index 818a1b4f737a..9d08f5a5ba76 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1021,6 +1021,8 @@ extern int usb_disabled(void); /* * urb->transfer_flags: + * + * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb(). */ #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ #define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame @@ -1033,6 +1035,10 @@ extern int usb_disabled(void); * needed */ #define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */ +#define URB_DIR_IN 0x0200 /* Transfer from device to host */ +#define URB_DIR_OUT 0 +#define URB_DIR_MASK URB_DIR_IN + struct usb_iso_packet_descriptor { unsigned int offset; unsigned int length; /* expected length */ @@ -1380,6 +1386,30 @@ extern void usb_unanchor_urb(struct urb *urb); extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned int timeout); +/** + * usb_urb_dir_in - check if an URB describes an IN transfer + * @urb: URB to be checked + * + * Returns 1 if @urb describes an IN transfer (device-to-host), + * otherwise 0. + */ +static inline int usb_urb_dir_in(struct urb *urb) +{ + return (urb->transfer_flags & URB_DIR_MASK) != URB_DIR_OUT; +} + +/** + * usb_urb_dir_out - check if an URB describes an OUT transfer + * @urb: URB to be checked + * + * Returns 1 if @urb describes an OUT transfer (host-to-device), + * otherwise 0. + */ +static inline int usb_urb_dir_out(struct urb *urb) +{ + return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT; +} + void *usb_buffer_alloc (struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); void usb_buffer_free (struct usb_device *dev, size_t size, From 5e60a16139c2a48b9876b0ff910671eee5fb32ec Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:07:21 -0400 Subject: [PATCH 2631/2804] USB: avoid using urb->pipe in usbcore This patch (as946) eliminates many of the uses of urb->pipe in usbcore. Unfortunately there will have to be a significant API change, affecting all USB drivers, before we can remove it entirely. This patch contents itself with changing only the interface to usb_buffer_map_sg() and friends: The pipe argument is replaced with a direction flag. That can be done easily because those routines get used in only one place. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 40 +++++++++++++++++++++++--------------- drivers/usb/core/message.c | 14 +++++++------ drivers/usb/core/usb.c | 19 +++++++++--------- include/linux/usb.h | 6 +++--- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index bcbaedc897d5..739c5e0aa3b8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -635,9 +635,9 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeint (urb->pipe)) + if (usb_endpoint_xfer_int(&urb->ep->desc)) return rh_queue_status (hcd, urb); - if (usb_pipecontrol (urb->pipe)) + if (usb_endpoint_xfer_control(&urb->ep->desc)) return rh_call_control (hcd, urb); return -EINVAL; } @@ -651,7 +651,7 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; - if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ @@ -918,7 +918,7 @@ static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) spin_unlock_irqrestore(&hcd_urb_list_lock, flags); if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_pipecontrol (urb->pipe) + if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, sizeof (struct usb_ctrlrequest), @@ -1001,7 +1001,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * unless it uses pio or talks to another transport. */ if (hcd->self.uses_dma) { - if (usb_pipecontrol (urb->pipe) + if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( hcd->self.controller, @@ -1201,11 +1201,13 @@ rescan: spin_lock(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { int tmp; + int is_in; /* the urb may already have been unlinked */ if (urb->status != -EINPROGRESS) continue; usb_get_urb (urb); + is_in = usb_urb_dir_in(urb); spin_unlock(&hcd_urb_list_lock); spin_lock (&urb->lock); @@ -1216,19 +1218,25 @@ rescan: /* kick hcd unless it's already returning this */ if (tmp == -EINPROGRESS) { - tmp = urb->pipe; unlink1 (hcd, urb); dev_dbg (hcd->self.controller, - "shutdown urb %p pipe %08x ep%d%s%s\n", - urb, tmp, usb_pipeendpoint (tmp), - (tmp & USB_DIR_IN) ? "in" : "out", - ({ char *s; \ - switch (usb_pipetype (tmp)) { \ - case PIPE_CONTROL: s = ""; break; \ - case PIPE_BULK: s = "-bulk"; break; \ - case PIPE_INTERRUPT: s = "-intr"; break; \ - default: s = "-iso"; break; \ - }; s;})); + "shutdown urb %p ep%d%s%s\n", + urb, usb_endpoint_num(&ep->desc), + is_in ? "in" : "out", + ({ char *s; + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + s = ""; break; + case USB_ENDPOINT_XFER_BULK: + s = "-bulk"; break; + case USB_ENDPOINT_XFER_INT: + s = "-intr"; break; + default: + s = "-iso"; break; + }; + s; + })); } usb_put_urb (urb); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 0d618647758e..a26a7292b61a 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) dev_dbg(&urb->dev->dev, "%s timed out on ep%d%s len=%d/%d\n", current->comm, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", urb->actual_length, urb->transfer_buffer_length); } else @@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io) io->urbs = NULL; } if (io->dev->dev.dma_mask != NULL) - usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); + usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe), + io->sg, io->nents); io->dev = NULL; } @@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb) dev_err (io->dev->bus->controller, "dev %s ep%d%s scatterlist error %d/%d\n", io->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", status, io->status); // BUG (); } @@ -379,7 +380,8 @@ int usb_sg_init ( */ dma = (dev->dev.dma_mask != NULL); if (dma) - io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); + io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe), + sg, nents); else io->entries = nents; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index d3c68d8eafb2..67e2e582e463 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -748,7 +748,7 @@ void usb_buffer_unmap(struct urb *urb) /** * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to map * @nents: the number of entries in the scatterlist * @@ -771,14 +771,13 @@ void usb_buffer_unmap(struct urb *urb) * * Reverse the effect of this call with usb_buffer_unmap_sg(). */ -int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, +int usb_buffer_map_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int nents) { struct usb_bus *bus; struct device *controller; if (!dev - || usb_pipecontrol(pipe) || !(bus = dev->bus) || !(controller = bus->controller) || !controller->dma_mask) @@ -786,7 +785,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, // FIXME generic api broken like pci, can't report errors return dma_map_sg(controller, sg, nents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -799,14 +798,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, /** * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to synchronize * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Use this when you are re-using a scatterlist's data buffers for * another USB request. */ -void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -819,20 +818,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, return; dma_sync_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } #endif /** * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to unmap * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Reverses the effect of usb_buffer_map_sg(). */ -void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -845,7 +844,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, return; dma_unmap_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* format to disable USB on kernel command line is: nousb */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 9d08f5a5ba76..019ae963a9fe 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1422,13 +1422,13 @@ void usb_buffer_unmap (struct urb *urb); #endif struct scatterlist; -int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, +int usb_buffer_map_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int nents); #if 0 -void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents); #endif -void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents); /*-------------------------------------------------------------------* From 4326ed0be93574dac5b5e475713015159108bd88 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:08:43 -0400 Subject: [PATCH 2632/2804] USB: address-0 handling during device initialization This patch (as947) changes the device initialization and enumeration code in hub.c; now udev->devnum will be set to 0 while the device is being accessed at address 0. Until now this wasn't needed because the address value was passed as part of urb->pipe; without that field the device address must be stored elsewhere. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 21 +++++++++++++-------- drivers/usb/core/urb.c | 4 +--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c8a01f66df70..34be27a6cbb4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1481,6 +1481,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, case 0: /* TRSTRCY = 10 ms; plus some extra */ msleep(10 + 40); + udev->devnum = 0; /* Device now at address 0 */ /* FALL THROUGH */ case -ENOTCONN: case -ENODEV: @@ -2005,20 +2006,21 @@ static void ep0_reinit(struct usb_device *udev) #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) #define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN) -static int hub_set_address(struct usb_device *udev) +static int hub_set_address(struct usb_device *udev, int devnum) { int retval; - if (udev->devnum == 0) + if (devnum <= 1) return -EINVAL; if (udev->state == USB_STATE_ADDRESS) return 0; if (udev->state != USB_STATE_DEFAULT) return -EINVAL; retval = usb_control_msg(udev, usb_sndaddr0pipe(), - USB_REQ_SET_ADDRESS, 0, udev->devnum, 0, + USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval == 0) { + udev->devnum = devnum; /* Device now using proper address */ usb_set_device_state(udev, USB_STATE_ADDRESS); ep0_reinit(udev); } @@ -2045,6 +2047,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; char *speed, *type; + int devnum = udev->devnum; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -2074,7 +2077,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } oldspeed = udev->speed; - + /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. * For Wireless USB devices, ep0 max packet is always 512 (tho @@ -2115,7 +2118,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, dev_info (&udev->dev, "%s %s speed %sUSB device using %s and address %d\n", (udev->config) ? "reset" : "new", speed, type, - udev->bus->controller->driver->name, udev->devnum); + udev->bus->controller->driver->name, devnum); /* Set up TT records, if needed */ if (hdev->tt) { @@ -2202,7 +2205,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, } for (j = 0; j < SET_ADDRESS_TRIES; ++j) { - retval = hub_set_address(udev); + retval = hub_set_address(udev, devnum); if (retval >= 0) break; msleep(200); @@ -2210,7 +2213,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval < 0) { dev_err(&udev->dev, "device not accepting address %d, error %d\n", - udev->devnum, retval); + devnum, retval); goto fail; } @@ -2263,8 +2266,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, retval = 0; fail: - if (retval) + if (retval) { hub_port_disable(hub, port1, 0); + udev->devnum = devnum; /* for disconnect processing */ + } mutex_unlock(&usb_address0_mutex); return retval; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 1a64a6a850f3..1acca8696bcd 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -284,9 +284,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; - if (!(dev = urb->dev) || - (dev->state < USB_STATE_DEFAULT) || - (!dev->bus) || (dev->devnum <= 0)) + if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) return -ENODEV; if (dev->bus->controller->power.power_state.event != PM_EVENT_ON || dev->state == USB_STATE_SUSPENDED) From 93cf9b909efb773f74b5d87659d41f957ccbce7e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:09:28 -0400 Subject: [PATCH 2633/2804] USB: avoid urb->pipe in usbfs This patch (as948) removes most of the references to urb->pipe from the usbfs routines in devio.c. The one tricky aspect is in snoop_urb(), which can be called before the URB is submitted and which uses usb_urb_dir_in(). For this to work properly, the URB's direction flag must be set manually in proc_do_submiturb(). The patch also fixes a minor bug; the wValue, wIndex, and wLength fields were snooped in proc_do_submiturb() without conversion from le16 to CPU-byte-ordering. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 69 ++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 927a181120a9..b9f1edd6af53 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -289,10 +289,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb) if (!usbfs_snoop) return; - if (urb->pipe & USB_DIR_IN) - dev_info(&urb->dev->dev, "direction=IN\n"); - else - dev_info(&urb->dev->dev, "direction=OUT\n"); + dev_info(&urb->dev->dev, "direction=%s\n", + usb_urb_dir_in(urb) ? "IN" : "OUT"); dev_info(&urb->dev->dev, "userurb=%p\n", userurb); dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", urb->transfer_buffer_length); @@ -910,6 +908,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; + int is_in; if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| URB_NO_FSBR|URB_ZERO_PACKET)) @@ -924,16 +923,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if ((ret = checkintf(ps, ifnum))) return ret; } - if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) - ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - else - ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { + is_in = 1; + ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } else { + is_in = 0; + ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } if (!ep) return -ENOENT; switch(uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_CONTROL) + if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) @@ -952,23 +953,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return ret; } - uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { + if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { + is_in = 1; + uurb->endpoint |= USB_DIR_IN; + } else { + is_in = 0; + uurb->endpoint &= ~USB_DIR_IN; + } + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) { kfree(dr); return -EFAULT; } snoop(&ps->dev->dev, "control urb: bRequest=%02x " "bRrequestType=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", - dr->bRequest, dr->bRequestType, dr->wValue, - dr->wIndex, dr->wLength); + dr->bRequest, dr->bRequestType, + __le16_to_cpup(&dr->wValue), + __le16_to_cpup(&dr->wIndex), + __le16_to_cpup(&dr->wLength)); break; case USBDEVFS_URB_TYPE_BULK: - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(&ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_ISOC: return -EINVAL; @@ -977,7 +987,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, uurb->number_of_packets = 0; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "bulk urb\n"); break; @@ -986,8 +997,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, /* arbitrary limit */ if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) return -EINVAL; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_ISOC) + if (!usb_endpoint_xfer_isoc(&ep->desc)) return -EINVAL; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) @@ -1014,12 +1024,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_INTERRUPT: uurb->number_of_packets = 0; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_int(&ep->desc)) return -EINVAL; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "interrupt urb\n"); break; @@ -1039,8 +1049,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -ENOMEM; } as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags; + as->urb->pipe = (uurb->type << 30) | + __create_pipe(ps->dev, uurb->endpoint & 0xf) | + (uurb->endpoint & USB_DIR_IN); + as->urb->transfer_flags = uurb->flags | + (is_in ? URB_DIR_IN : URB_DIR_OUT); as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char*)dr; as->urb->start_frame = uurb->start_frame; @@ -1070,13 +1083,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->uid = current->uid; as->euid = current->euid; security_task_getsecid(current, &as->secid); - if (!(uurb->endpoint & USB_DIR_IN)) { - if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { + if (!is_in) { + if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, + as->urb->transfer_buffer_length)) { free_async(as); return -EFAULT; } } - snoop(&as->urb->dev->dev, "submit urb\n"); snoop_urb(as->urb, as->userurb); async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { @@ -1126,7 +1139,7 @@ static int processcompl(struct async *as, void __user * __user *arg) if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) @@ -1240,7 +1253,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) From 18ea5d00d05fa6300606f0711748016c95fb26dc Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:10:36 -0400 Subject: [PATCH 2634/2804] USB: avoid urb->pipe in usbmon This patch (as949) changes the usbmon driver to use the new urb->ep field rather than urb->pipe. Signed-off-by: Alan Stern Cc: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 44 ++++++++++++++++++++++------- drivers/usb/mon/mon_main.c | 4 +-- drivers/usb/mon/mon_text.c | 58 +++++++++++++++++++++----------------- 3 files changed, 68 insertions(+), 38 deletions(-) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index c03dfd7a9d36..0b0d77c669da 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -354,7 +354,7 @@ static inline char mon_bin_get_setup(unsigned char *setupb, const struct urb *urb, char ev_type) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') return '-'; if (urb->dev->bus->uses_dma && @@ -410,7 +410,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, if (length >= rp->b_size/5) length = rp->b_size/5; - if (usb_pipein(urb->pipe)) { + if (usb_urb_dir_in(urb)) { if (ev_type == 'S') { length = 0; data_tag = '<'; @@ -440,10 +440,22 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + switch (usb_endpoint_type(&urb->ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + ep->xfer_type = PIPE_CONTROL; + break; + case USB_ENDPOINT_XFER_BULK: + ep->xfer_type = PIPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + ep->xfer_type = PIPE_INTERRUPT; + break; + default: + ep->xfer_type = PIPE_ISOCHRONOUS; + break; + } + ep->epnum = urb->ep->desc.bEndpointAddress; + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; @@ -500,10 +512,22 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + switch (usb_endpoint_type(&urb->ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + ep->xfer_type = PIPE_CONTROL; + break; + case USB_ENDPOINT_XFER_BULK: + ep->xfer_type = PIPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + ep->xfer_type = PIPE_INTERRUPT; + break; + default: + ep->xfer_type = PIPE_ISOCHRONOUS; + break; + } + ep->epnum = urb->ep->desc.bEndpointAddress; + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->status = error; diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index ce61d8b0fd86..e58f761d060f 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -154,8 +154,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) * This should not happen. * At this point we do not even know the bus number... */ - printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n", - urb->pipe); + printk(KERN_ERR TAG ": Null mon bus in URB, address %p\n", + urb); return; } diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 8f27a9e1c36b..9d0070ceef52 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -50,10 +50,12 @@ struct mon_iso_desc { struct mon_event_text { struct list_head e_link; int type; /* submit, complete, etc. */ - unsigned int pipe; /* Pipe */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; + int xfertype; int busnum; + int devnum; + int epnum; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -61,6 +63,7 @@ struct mon_event_text { int error_count; char setup_flag; char data_flag; + char is_in; int numdesc; /* Full number */ struct mon_iso_desc isodesc[ISODESC_MAX]; unsigned char setup[SETUP_MAX]; @@ -121,7 +124,7 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, struct urb *urb, char ev_type, struct mon_bus *mbus) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; if (urb->dev->bus->uses_dma && @@ -138,14 +141,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type, struct mon_bus *mbus) { - int pipe = urb->pipe; - if (len <= 0) return 'L'; if (len >= DATA_MAX) len = DATA_MAX; - if (usb_pipein(pipe)) { + if (ep->is_in) { if (ev_type != 'C') return '<'; } else { @@ -203,24 +204,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, } ep->type = ev_type; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = urb->dev->bus->busnum; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = stamp; ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ ep->status = urb->status; - if (usb_pipeint(urb->pipe)) { + if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; - } else if (usb_pipeisoc(urb->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { ep->interval = urb->interval; ep->start_frame = urb->start_frame; ep->error_count = urb->error_count; } ep->numdesc = urb->number_of_packets; - if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) { + if (ep->xfertype == USB_ENDPOINT_XFER_ISOC && + urb->number_of_packets > 0) { if ((ndesc = urb->number_of_packets) > ISODESC_MAX) ndesc = ISODESC_MAX; fp = urb->iso_frame_desc; @@ -268,9 +273,12 @@ static void mon_text_error(void *data, struct urb *urb, int error) } ep->type = 'E'; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = 0; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = 0; ep->length = 0; ep->status = error; @@ -413,10 +421,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf, mon_text_read_head_u(rp, &ptr, ep); if (ep->type == 'E') { mon_text_read_statset(rp, &ptr, ep); - } else if (usb_pipeisoc(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { mon_text_read_isostat(rp, &ptr, ep); mon_text_read_isodesc(rp, &ptr, ep); - } else if (usb_pipeint(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { mon_text_read_intstat(rp, &ptr, ep); } else { mon_text_read_statset(rp, &ptr, ep); @@ -468,18 +476,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, - usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->devnum, ep->epnum); } static void mon_text_read_head_u(struct mon_reader_text *rp, @@ -487,18 +494,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%d:%03u:%u", ep->id, ep->tstamp, ep->type, - utype, udir, - ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->busnum, ep->devnum, ep->epnum); } static void mon_text_read_statset(struct mon_reader_text *rp, From d617bc83ff48ebf0df253605529d8b3bef15773a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:04:52 -0400 Subject: [PATCH 2635/2804] USB: cleanup for previous patches This patch (as951) cleans up a few loose ends from earlier patches. Redundant checks for non-NULL urb->dev are removed, as are checks of urb->dev->bus (which can never be NULL). Conversely, a check for non-NULL urb->ep is added to the unlink paths. A homegrown round-down-to-power-of-2 loop is simplified by using the ilog2 routine. The comparison in usb_urb_dir_in() is made more transparent. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 5 ----- drivers/usb/core/urb.c | 13 +++++++------ include/linux/usb.h | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 739c5e0aa3b8..47a055a2acf5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1074,11 +1074,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) struct list_head *tmp; int retval; - if (!urb) - return -EINVAL; - if (!urb->dev || !urb->dev->bus) - return -ENODEV; - /* * we contend for urb->status with the hcd core, * which changes it while returning the urb. diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 1acca8696bcd..19f5f66c2733 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "hcd.h" @@ -441,10 +442,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) default: return -EINVAL; } - /* power of two? */ - while (max > urb->interval) - max >>= 1; - urb->interval = max; + /* Round down to a power of 2, no more than max */ + urb->interval = min(max, 1 << ilog2(urb->interval)); } return usb_hcd_submit_urb(urb, mem_flags); @@ -513,8 +512,10 @@ int usb_unlink_urb(struct urb *urb) { if (!urb) return -EINVAL; - if (!(urb->dev && urb->dev->bus)) + if (!urb->dev) return -ENODEV; + if (!urb->ep) + return -EIDRM; return usb_hcd_unlink_urb(urb, -ECONNRESET); } @@ -541,7 +542,7 @@ int usb_unlink_urb(struct urb *urb) void usb_kill_urb(struct urb *urb) { might_sleep(); - if (!(urb && urb->dev && urb->dev->bus)) + if (!(urb && urb->dev && urb->ep)) return; spin_lock_irq(&urb->lock); ++urb->reject; diff --git a/include/linux/usb.h b/include/linux/usb.h index 019ae963a9fe..a51f34e80572 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1395,7 +1395,7 @@ extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, */ static inline int usb_urb_dir_in(struct urb *urb) { - return (urb->transfer_flags & URB_DIR_MASK) != URB_DIR_OUT; + return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN; } /** From 9439eb94b5c374d5b02699f8897fc43aa3603701 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:05:45 -0400 Subject: [PATCH 2636/2804] USB: update spinlock usage for root-hub URBs This patch (as952) adjusts the spinlock usage in the root-hub emulation part of usbcore, to make it match more closely the pattern used by regular host controller drivers. To wit: The private lock (usb_hcd_root_hub_lock) is held throughout the important parts, and it is dropped temporarily without re-enabling interrupts around the call to usb_hcd_giveback_urb(). A nice side effect is that the code now avoids calling local_irq_save(), thereby becoming more RT-friendly. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 52 +++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 47a055a2acf5..f8e7deb03ee9 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -356,10 +356,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; - unsigned long flags; int status = 0; int n; + might_sleep(); + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); @@ -523,13 +524,21 @@ error: } /* any errors get returned through the urb completion */ - local_irq_save (flags); - spin_lock (&urb->lock); + spin_lock_irq(&hcd_root_hub_lock); + spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - spin_unlock (&urb->lock); - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); + spin_unlock(&urb->lock); + + /* This peculiar use of spinlocks echoes what real HC drivers do. + * Avoiding calls to local_irq_disable/enable makes the code + * RT-friendly. + */ + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); + + spin_unlock_irq(&hcd_root_hub_lock); return 0; } @@ -559,8 +568,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) if (length > 0) { /* try to complete the status urb */ - local_irq_save (flags); - spin_lock(&hcd_root_hub_lock); + spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { spin_lock(&urb->lock); @@ -574,16 +582,16 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) } else /* urb has been unlinked */ length = 0; spin_unlock(&urb->lock); + + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); } else length = 0; - spin_unlock(&hcd_root_hub_lock); - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb); - else + if (length <= 0) hcd->poll_pending = 1; - local_irq_restore (flags); + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } /* The USB 2.0 spec says 256 ms. This is close enough and won't @@ -651,25 +659,23 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; + spin_lock_irqsave(&hcd_root_hub_lock, flags); if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ if (!hcd->uses_new_polling) del_timer (&hcd->rh_timer); - local_irq_save (flags); - spin_lock (&hcd_root_hub_lock); if (urb == hcd->status_urb) { hcd->status_urb = NULL; urb->hcpriv = NULL; - } else - urb = NULL; /* wasn't fully queued */ - spin_unlock (&hcd_root_hub_lock); - if (urb) - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); - } + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); + } + } + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); return 0; } From 9a9bf406df3ce238089d14f4cb41157ca56d8ad3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:06:54 -0400 Subject: [PATCH 2637/2804] USB: separate out endpoint queue management and DMA mapping routines This patch (as953) separates out three key portions from usb_hcd_submit_urb(), usb_hcd_unlink_urb(), and usb_hcd_giveback_urb() and puts them in separate functions of their own. In the next patch, these functions will be called directly by host controller drivers while holding their private spinlocks, which will remove the possibility of some unpleasant races. The code responsible for mapping and unmapping DMA buffers is also placed into a couple of separate subroutines, for the sake of cleanliness and consistency. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 340 +++++++++++++++++++++-------------------- 1 file changed, 178 insertions(+), 162 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index f8e7deb03ee9..eb2121788264 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -914,99 +914,117 @@ EXPORT_SYMBOL (usb_calc_bus_time); /*-------------------------------------------------------------------------*/ -static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) +static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&hcd_urb_list_lock, flags); + + /* Check that the URB isn't being killed */ + if (unlikely(urb->reject)) { + rc = -EPERM; + goto done; + } + + if (unlikely(!urb->ep->enabled)) { + rc = -ENOENT; + goto done; + } + + /* + * Check the host controller's state and add the URB to the + * endpoint's queue. + */ + switch (hcd->state) { + case HC_STATE_RUNNING: + case HC_STATE_RESUMING: + list_add_tail(&urb->urb_list, &urb->ep->urb_list); + break; + default: + rc = -ESHUTDOWN; + goto done; + } + done: + spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + return rc; +} + +static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status) +{ + unsigned long flags; + struct list_head *tmp; + int rc = 0; + + /* + * we contend for urb->status with the hcd core, + * which changes it while returning the urb. + * + * Caller guaranteed that the urb pointer hasn't been freed, and + * that it was submitted. But as a rule it can't know whether or + * not it's already been unlinked ... so we respect the reversed + * lock sequence needed for the usb_hcd_giveback_urb() code paths + * (urb lock, then hcd_urb_list_lock) in case some other CPU is now + * unlinking it. + */ + spin_lock_irqsave(&urb->lock, flags); + spin_lock(&hcd_urb_list_lock); + + /* insist the urb is still queued */ + list_for_each(tmp, &urb->ep->urb_list) { + if (tmp == &urb->urb_list) + break; + } + if (tmp != &urb->urb_list) { + rc = -EIDRM; + goto done; + } + + /* Any status except -EINPROGRESS means something already started to + * unlink this URB from the hardware. So there's no more work to do. + */ + if (urb->status != -EINPROGRESS) { + rc = -EBUSY; + goto done; + } + urb->status = status; + + /* IRQ setup can easily be broken so that USB controllers + * never get completion IRQs ... maybe even the ones we need to + * finish unlinking the initial failed usb_set_address() + * or device descriptor fetch. + */ + if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && + !is_root_hub(urb->dev)) { + dev_warn(hcd->self.controller, "Unlink after no-IRQ? " + "Controller is probably using the wrong IRQ.\n"); + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + } + + done: + spin_unlock(&hcd_urb_list_lock); + spin_unlock_irqrestore (&urb->lock, flags); + return rc; +} + +static void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; /* clear all state linking urb to this dev (and hcd) */ spin_lock_irqsave(&hcd_urb_list_lock, flags); - list_del_init (&urb->urb_list); + list_del_init(&urb->urb_list); spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) - dma_unmap_single (hcd->self.controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) - dma_unmap_single (hcd->self.controller, - urb->transfer_dma, - urb->transfer_buffer_length, - usb_urb_dir_in(urb) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); - } } -/* may be called in any context with a valid urb->dev usecount - * caller surrenders "ownership" of urb - * expects usb_submit_urb() to have sanity checked and conditioned all - * inputs in the urb - */ -int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) +static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { - int status; - struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - unsigned long flags; - - if (!hcd) - return -ENODEV; - - usbmon_urb_submit(&hcd->self, urb); - - /* - * Atomically queue the urb, first to our records, then to the HCD. - * Access to urb->status is controlled by urb->lock ... changes on - * i/o completion (normal or fault) or unlinking. - */ - - // FIXME: verify that quiescing hc works right (RH cleans up) - - spin_lock_irqsave(&hcd_urb_list_lock, flags); - if (unlikely(!urb->ep->enabled)) - status = -ENOENT; - else if (unlikely (urb->reject)) - status = -EPERM; - else switch (hcd->state) { - case HC_STATE_RUNNING: - case HC_STATE_RESUMING: - list_add_tail (&urb->urb_list, &urb->ep->urb_list); - status = 0; - break; - default: - status = -ESHUTDOWN; - break; - } - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - if (status) { - INIT_LIST_HEAD (&urb->urb_list); - usbmon_urb_submit_error(&hcd->self, urb, status); - return status; - } - - /* increment urb's reference count as part of giving it to the HCD - * (which now controls it). HCD guarantees that it either returns - * an error or calls giveback(), but not both. - */ - urb = usb_get_urb (urb); - atomic_inc (&urb->use_count); - - if (is_root_hub(urb->dev)) { - /* NOTE: requirement on hub callers (usbfs and the hub - * driver, for now) that URBs' urb->transfer_buffer be - * valid and usb_buffer_{sync,unmap}() not be needed, since - * they could clobber root hub response data. - */ - status = rh_urb_enqueue (hcd, urb); - goto done; - } - - /* lower level hcd code should use *_dma exclusively, + /* Map the URB's buffers for DMA access. + * Lower level HCD code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.uses_dma) { + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( @@ -1024,16 +1042,73 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +} - status = hcd->driver->urb_enqueue (hcd, urb->ep, urb, mem_flags); -done: - if (unlikely (status)) { - urb_unlink(hcd, urb); - atomic_dec (&urb->use_count); - if (urb->reject) - wake_up (&usb_kill_urb_queue); +static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + dma_unmap_single(hcd->self.controller, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + dma_unmap_single(hcd->self.controller, + urb->transfer_dma, + urb->transfer_buffer_length, + usb_urb_dir_in(urb) + ? DMA_FROM_DEVICE + : DMA_TO_DEVICE); + } +} + +/*-------------------------------------------------------------------------*/ + +/* may be called in any context with a valid urb->dev usecount + * caller surrenders "ownership" of urb + * expects usb_submit_urb() to have sanity checked and conditioned all + * inputs in the urb + */ +int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) +{ + int status; + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + + /* increment urb's reference count as part of giving it to the HCD + * (which will control it). HCD guarantees that it either returns + * an error or calls giveback(), but not both. + */ + usb_get_urb(urb); + atomic_inc(&urb->use_count); + usbmon_urb_submit(&hcd->self, urb); + + /* NOTE requirements on root-hub callers (usbfs and the hub + * driver, for now): URBs' urb->transfer_buffer must be + * valid and usb_buffer_{sync,unmap}() not be needed, since + * they could clobber root hub response data. Also, control + * URBs must be submitted in process context with interrupts + * enabled. + */ + status = usb_hcd_link_urb_to_ep(hcd, urb); + if (!status) { + map_urb_for_dma(hcd, urb); + if (is_root_hub(urb->dev)) + status = rh_urb_enqueue(hcd, urb); + else + status = hcd->driver->urb_enqueue(hcd, urb->ep, urb, + mem_flags); + } + + if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); - usb_put_urb (urb); + unmap_urb_for_dma(hcd, urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); + INIT_LIST_HEAD(&urb->urb_list); + atomic_dec(&urb->use_count); + if (urb->reject) + wake_up(&usb_kill_urb_queue); + usb_put_urb(urb); } return status; } @@ -1074,78 +1149,20 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ int usb_hcd_unlink_urb (struct urb *urb, int status) { - struct usb_hcd *hcd = NULL; - struct device *sys = NULL; - unsigned long flags; - struct list_head *tmp; - int retval; + struct usb_hcd *hcd; + int retval; - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_urb_list_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave (&urb->lock, flags); - spin_lock(&hcd_urb_list_lock); - - sys = &urb->dev->dev; hcd = bus_to_hcd(urb->dev->bus); - if (hcd == NULL) { - retval = -ENODEV; - goto done; - } - /* insist the urb is still queued */ - list_for_each(tmp, &urb->ep->urb_list) { - if (tmp == &urb->urb_list) - break; - } - if (tmp != &urb->urb_list) { - retval = -EIDRM; - goto done; - } + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (!retval) + retval = unlink1(hcd, urb); - /* Any status except -EINPROGRESS means something already started to - * unlink this URB from the hardware. So there's no more work to do. - */ - if (urb->status != -EINPROGRESS) { - retval = -EBUSY; - goto done; - } - - /* IRQ setup can easily be broken so that USB controllers - * never get completion IRQs ... maybe even the ones we need to - * finish unlinking the initial failed usb_set_address() - * or device descriptor fetch. - */ - if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && - !is_root_hub(urb->dev)) { - dev_warn (hcd->self.controller, "Unlink after no-IRQ? " - "Controller is probably using the wrong IRQ.\n"); - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - } - - urb->status = status; - - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - - retval = unlink1 (hcd, urb); if (retval == 0) retval = -EINPROGRESS; - return retval; - -done: - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - if (retval != -EIDRM && sys && sys->driver) - dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); + else if (retval != -EIDRM) + dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", + urb, retval); return retval; } @@ -1165,7 +1182,8 @@ done: */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - urb_unlink(hcd, urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); + unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); @@ -1194,12 +1212,12 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_hcd *hcd; struct urb *urb; + might_sleep(); hcd = bus_to_hcd(udev->bus); - local_irq_disable (); /* ep is already gone from udev->ep_{in,out}[]; no more submits */ rescan: - spin_lock(&hcd_urb_list_lock); + spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { int tmp; int is_in; @@ -1244,13 +1262,11 @@ rescan: /* list contents may have changed */ goto rescan; } - spin_unlock(&hcd_urb_list_lock); - local_irq_enable (); + spin_unlock_irq(&hcd_urb_list_lock); /* synchronize with the hardware, so old configuration state * clears out immediately (and will be freed). */ - might_sleep (); if (hcd->driver->endpoint_disable) hcd->driver->endpoint_disable (hcd, ep); From a1d534bb23e5c5c28fb6f6fb48588362df0907e8 Mon Sep 17 00:00:00 2001 From: Nico Erfurth Date: Thu, 2 Aug 2007 22:25:20 +0200 Subject: [PATCH 2638/2804] USB: Add drivers/usb/misc/iowarrior.c to the Makefile This patch adds the new iowarrior module to the Makefile in drivers/usb. Currently the module isn't build unless another driver from usb/misc is selected. Signed-off-by: Nico Erfurth Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index ac49b15fa768..cce216517ca1 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ obj-$(CONFIG_USB_FTDI_ELAN) += misc/ obj-$(CONFIG_USB_IDMOUSE) += misc/ +obj-$(CONFIG_USB_IOWARRIOR) += misc/ obj-$(CONFIG_USB_LCD) += misc/ obj-$(CONFIG_USB_LD) += misc/ obj-$(CONFIG_USB_LED) += misc/ From a4e3ef5597e26dad006544d38b9ab6ff42382b76 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 1 Aug 2007 23:58:22 -0700 Subject: [PATCH 2639/2804] USB: gadget: gadget_is_{dualspeed,otg} predicates and cleanup This adds two small inlines to the gadget stack, which will often evaluate to compile-time constants. That can help shrink object code and remove #ifdeffery. - gadget_is_dualspeed(), currently always a compile-time constant (depending on which controller is selected). - gadget_is_otg(), usually a compile time "false", but this is a runtime test if the platform enables OTG (since it's reasonable to populate boards with different USB sockets). It also updates two peripheral controller drivers to use these: - fsl_usb2_udc, mostly OTG-related bugfixes: non-OTG devices must follow the rules about drawing VBUS power, and OTG ones need to reject invalid SET_FEATURE requests. - omap_udc, just scrubbing a bit of #ifdeffery. And also gadgetfs, which lost some #ifdefs and moved to a more standard handling of DEBUG and VERBOSE_DEBUG. The main benefits come from patches which will follow. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/fsl_usb2_udc.c | 9 +++---- drivers/usb/gadget/inode.c | 44 ++++++++++++++----------------- drivers/usb/gadget/omap_udc.c | 10 +++---- include/linux/usb_gadget.h | 33 +++++++++++++++++++++++ 4 files changed, 59 insertions(+), 37 deletions(-) diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index d57bcfbc08a5..89c768e2aed7 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) */ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) { -#ifdef CONFIG_USB_OTG struct fsl_udc *udc; udc = container_of(gadget, struct fsl_udc, gadget); - if (udc->transceiver) return otg_set_power(udc->transceiver, mA); -#endif return -ENOTSUPP; } @@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc, | USB_TYPE_STANDARD)) { /* Note: The driver has not include OTG support yet. * This will be set when OTG support is added */ - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) break; else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) udc->gadget.b_hnp_enable = 1; @@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc, else if (setup->bRequest == USB_DEVICE_A_ALT_HNP_SUPPORT) udc->gadget.a_alt_hnp_support = 1; + else + break; rc = 0; } else break; @@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc_controller->driver || !driver->unbind) return -EINVAL; -#ifdef CONFIG_USB_OTG if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); -#endif /* stop DR, disable intr */ dr_controller_stop(udc_controller); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 173004f60fea..129eda5358f7 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,8 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ -// #define VERBOSE /* extra debug messages (success too) */ +/* #define VERBOSE_DEBUG */ #include #include @@ -253,7 +252,7 @@ static const char *CHIP; do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DBG #else #define VDEBUG(dev,fmt,args...) \ @@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* assume that was SET_CONFIGURATION */ if (dev->current_config) { unsigned power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (dev->gadget->speed == USB_SPEED_HIGH) + + if (gadget_is_dualspeed(dev->gadget) + && (dev->gadget->speed + == USB_SPEED_HIGH)) power = dev->hs_config->bMaxPower; else -#endif power = dev->config->bMaxPower; usb_gadget_vbus_draw(dev->gadget, 2 * power); } @@ -1355,24 +1355,21 @@ static int config_buf (struct dev_data *dev, u8 type, unsigned index) { int len; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs; -#endif + int hs = 0; /* only one configuration */ if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs = (dev->gadget->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(dev->gadget)) { + hs = (dev->gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) { dev->req->buf = dev->hs_config; len = le16_to_cpu(dev->hs_config->wTotalLength); - } else -#endif - { + } else { dev->req->buf = dev->config; len = le16_to_cpu(dev->config->wTotalLength); } @@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) { + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH + && dev->hs_config == NULL) { spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } -#endif /* CONFIG_USB_GADGET_DUALSPEED */ dev->state = STATE_DEV_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; @@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) // user mode expected to disable endpoints } else { u8 config, power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) { + + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; power = dev->hs_config->bMaxPower; - } else -#endif - { + } else { config = dev->config->bConfigurationValue; power = dev->config->bMaxPower; } diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 9b0f0925dddf..bf2788dfb32b 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc) udc->gadget.dev.parent->power.power_state = PMSG_ON; udc->gadget.dev.power.power_state = PMSG_ON; UDC_SYSCON1_REG |= UDC_PULLUP_EN; -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG |= OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; } static void pullup_disable(struct omap_udc *udc) { -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG &= ~OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; } @@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc) { u16 devstat; - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) return; if (OTG_CTRL_REG & OTG_ID) diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index ec9732e7fea2..5ea611e48ec1 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -479,6 +479,39 @@ static inline void *get_gadget_data (struct usb_gadget *gadget) list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) +/** + * gadget_is_dualspeed - return true iff the hardware handles high speed + * @gadget: controller that might support both high and full speeds + */ +static inline int gadget_is_dualspeed(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* runtime test would check "g->is_dualspeed" ... that might be + * useful to work around hardware bugs, but is mostly pointless + */ + return 1; +#else + return 0; +#endif +} + +/** + * gadget_is_otg - return true iff the hardware is OTG-ready + * @gadget: controller that might have a Mini-AB connector + * + * This is a runtime test, since kernels with a USB-OTG stack sometimes + * run on boards which only have a Mini-B (or Mini-A) connector. + */ +static inline int gadget_is_otg(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_OTG + return g->is_otg; +#else + return 0; +#endif +} + + /** * usb_gadget_frame_number - returns the current frame number * @gadget: controller that reports the frame number From 0cf4f2de0a0f4100795f38ef894d4910678c74f8 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:00:38 -0700 Subject: [PATCH 2640/2804] USB: gadget: ethernet gadget cleanups, shrinkage Clean up the ethernet gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the VERBOSE_DEBUG convention - Minor whitespace fixes. - Fix a warning from "sparse". Surprisingly, this saved about 2K of code (16%) on a fullspeed-only ARMv4 platform. I'm bit puzzled by that (it's so much!), but approve of the result. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 141 ++++++++++++++----------------------- 1 file changed, 54 insertions(+), 87 deletions(-) diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f70055473a00..ff244f42723f 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -19,41 +19,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* #define VERBOSE_DEBUG */ -// #define DEBUG 1 -// #define VERBOSE - -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include - -#include -#include -#include -#include -#include -#include +#include +#include #include #include #include -#include -#include -#include -#include - #include "gadget_chips.h" /*-------------------------------------------------------------------------*/ @@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); #define qlen(gadget) \ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) -/* also defer IRQs on highspeed TX */ -#define TX_DELAY qmult - static inline int BITRATE(struct usb_gadget *g) { return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS; } #else /* full speed (low speed doesn't do bulk) */ + +#define qmult 1 + #define DEVSPEED USB_SPEED_FULL #define qlen(gadget) DEFAULT_QLEN @@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g) do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DEBUG #else #define VDEBUG(dev,fmt,args...) \ @@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = { }; #endif -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else - -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) (((void)(g)), (fs)) - -static inline void __init hs_subset_descriptors(void) +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) { + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; } -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -989,22 +962,19 @@ static struct usb_gadget_strings stringtab = { * complications: class descriptors, and an altsetting. */ static int -config_buf (enum usb_device_speed speed, - u8 *buf, u8 type, - unsigned index, int is_otg) +config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg) { int len; const struct usb_config_descriptor *config; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (speed == USB_SPEED_HIGH); + int hs = 0; - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(g)) { + hs = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } #define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) -#else -#define which_fn(t) (fs_ ## t ## _function) -#endif if (index >= device_desc.bNumConfigurations) return -EINVAL; @@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) if (number) eth_reset_config (dev); usb_gadget_vbus_draw(dev->gadget, - dev->gadget->is_otg ? 8 : 100); + gadget_is_otg(dev->gadget) ? 8 : 100); } else { char *speed; unsigned power; @@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf(gadget, req->buf, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (value >= 0) value = min (wLength, (u16) value); break; @@ -1585,12 +1553,12 @@ done_set_intf: && rndis_control_intf.bInterfaceNumber == wIndex) { u8 *buf; + u32 n; /* return the result */ - buf = rndis_get_next_response (dev->rndis_config, - &value); + buf = rndis_get_next_response(dev->rndis_config, &n); if (buf) { - memcpy (req->buf, buf, value); + memcpy(req->buf, buf, n); req->complete = rndis_response_complete; rndis_free_response(dev->rndis_config, buf); } @@ -2026,12 +1994,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) req->length = length; -#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) - ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) - : 0; -#endif + if (gadget_is_dualspeed(dev->gadget)) + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) + : 0; retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); switch (retval) { @@ -2188,8 +2155,7 @@ static int eth_stop (struct net_device *net) } if (rndis_active(dev)) { - rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } @@ -2443,26 +2409,28 @@ autoconf_fail: if (rndis) device_desc.bNumConfigurations = 2; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (rndis) - dev_qualifier.bNumConfigurations = 2; - else if (!cdc) - dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; + if (gadget_is_dualspeed(gadget)) { + if (rndis) + dev_qualifier.bNumConfigurations = 2; + else if (!cdc) + dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; - /* assumes ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (status_ep) - hs_status_desc.bEndpointAddress = - fs_status_desc.bEndpointAddress; + if (status_ep) + hs_status_desc.bEndpointAddress = + fs_status_desc.bEndpointAddress; #endif -#endif /* DUALSPEED */ + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; eth_config.bMaxPower = 4; @@ -2598,12 +2566,11 @@ fail0: if (rndis_set_param_dev (dev->rndis_config, dev->net, &dev->stats, &dev->cdc_filter)) goto fail0; - if (rndis_set_param_vendor (dev->rndis_config, vendorID, - manufacturer)) + if (rndis_set_param_vendor(dev->rndis_config, vendorID, + manufacturer)) goto fail0; - if (rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, - 0)) + if (rndis_set_param_medium(dev->rndis_config, + NDIS_MEDIUM_802_3, 0)) goto fail0; INFO (dev, "RNDIS ready\n"); } From 8c07021635a10c9a4969cbff0f2325a94c860f77 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:01:27 -0700 Subject: [PATCH 2641/2804] USB: gadget: gmidi cleanups Clean up the midi gadget, using newer APIs and conventions: - Remove many now-needless #includes - Use the DEBUG (from Kconfig+Makefile) and VERBOSE_DEBUG conventions. - Whitespace fixes There should be no effect on object code size. Signed-off-by: David Brownell Cc: Ben Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/gmidi.c | 80 +++++++++++++++----------------------- 1 file changed, 32 insertions(+), 48 deletions(-) diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 1c5aa49d7432..d2475755a206 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -18,17 +18,11 @@ * http://www.usb.org/developers/devclass_docs/midi10.pdf */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include #include -#include -#include -#include #include #include -#include #include #include @@ -139,30 +133,16 @@ struct gmidi_device { static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req); -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) static unsigned buflen = 256; @@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget, return len; } -static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length) +static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) { struct usb_request *req; @@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = { * Receives a chunk of MIDI data. */ static void gmidi_read_data(struct usb_ep *ep, int cable, - uint8_t* data, int length) + uint8_t *data, int length) { struct gmidi_device *dev = ep->driver_data; /* cable is ignored, because for now we only have one. */ @@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags) { int err = 0; struct usb_request *req; - struct usb_ep* ep; + struct usb_ep *ep; unsigned i; err = usb_ep_enable(dev->in_ep, &bulk_in_desc); @@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100(gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO(dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } gmidi_reset_config(dev); @@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget) static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget) { struct gmidi_device *dev = get_gadget_data(gadget); - struct snd_card* card; + struct snd_card *card; DBG(dev, "unbind\n"); @@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device) return 0; } -static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, +static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3) { unsigned length = req->length; + u8 *buf = (u8 *)req->buf + length; - uint8_t* buf = (uint8_t*)req->buf + length; buf[0] = p0; buf[1] = p1; buf[2] = p2; @@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, /* * Converts MIDI commands to USB MIDI packets. */ -static void gmidi_transmit_byte(struct usb_request* req, - struct gmidi_in_port* port, uint8_t b) +static void gmidi_transmit_byte(struct usb_request *req, + struct gmidi_in_port *port, uint8_t b) { uint8_t p0 = port->cable; @@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req, } } -static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) +static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req) { - struct usb_ep* ep = dev->in_ep; - struct gmidi_in_port* port = &dev->in_port; + struct usb_ep *ep = dev->in_ep; + struct gmidi_in_port *port = &dev->in_port; if (!ep) { return; @@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) static void gmidi_in_tasklet(unsigned long data) { - struct gmidi_device* dev = (struct gmidi_device*)data; + struct gmidi_device *dev = (struct gmidi_device *)data; gmidi_transmit(dev, NULL); } static int gmidi_in_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_open\n"); dev->in_substream = substream; @@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream) static int gmidi_in_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_in_close\n"); return 0; } static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_trigger %d\n", up); dev->in_port.active = up; @@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) static int gmidi_out_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_open\n"); dev->out_substream = substream; @@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream) static int gmidi_out_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_out_close\n"); return 0; } static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_trigger %d\n", up); if (up) { From 51a0e85cd9b47e2e6332b40ea486cc1659d8a3ec Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:02:47 -0700 Subject: [PATCH 2642/2804] USB: gadget: serial gadget cleanups Clean up the serial gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the DEBUG and VERBOSE_DEBUG conventions; turned up a bug in the original debug messaging - Various whitespace fixes. This gave only a minor object code shrinkage, but the source looks much cleaner in various places. Signed-off-by: David Brownell Cc: Al Borchers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/serial.c | 166 ++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 93 deletions(-) diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ce4d2e09633d..afdf71f76f7e 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -17,30 +17,11 @@ * */ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include #include #include -#include - -#include -#include -#include -#include -#include -#include #include #include @@ -89,30 +70,29 @@ #define GS_DEFAULT_PARITY USB_CDC_NO_PARITY #define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS -/* select highspeed/fullspeed, hiding highspeed if not configured */ -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs)) -#else -#define GS_SPEED_SELECT(is_hs,hs,fs) (fs) -#endif /* CONFIG_USB_GADGET_DUALSPEED */ +/* maxpacket and other transfer characteristics vary by speed. */ +static inline struct usb_endpoint_descriptor * +choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + /* debug settings */ -#ifdef GS_DEBUG +#ifdef DEBUG static int debug = 1; +#else +#define debug 0 +#endif #define gs_debug(format, arg...) \ do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) #define gs_debug_level(level, format, arg...) \ do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0) -#else - -#define gs_debug(format, arg...) \ - do { } while(0) -#define gs_debug_level(level, format, arg...) \ - do { } while(0) - -#endif /* GS_DEBUG */ /* Thanks to NetChip Technologies for donating this product ID. * @@ -147,10 +127,10 @@ struct gs_req_entry { /* the port structure holds info for each port, one for each minor number */ struct gs_port { - struct gs_dev *port_dev; /* pointer to device struct */ + struct gs_dev *port_dev; /* pointer to device struct */ struct tty_struct *port_tty; /* pointer to tty struct */ spinlock_t port_lock; - int port_num; + int port_num; int port_open_count; int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ @@ -188,7 +168,7 @@ static void __exit gs_module_exit(void); /* tty driver */ static int gs_open(struct tty_struct *tty, struct file *file); static void gs_close(struct tty_struct *tty, struct file *file); -static int gs_write(struct tty_struct *tty, +static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count); static void gs_put_char(struct tty_struct *tty, unsigned char ch); static void gs_flush_chars(struct tty_struct *tty); @@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req); static void gs_disconnect(struct usb_gadget *gadget); static int gs_set_config(struct gs_dev *dev, unsigned config); static void gs_reset_config(struct gs_dev *dev); -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, @@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = { }; static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = { - .bLength = sizeof(gs_call_mgmt_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - .bmCapabilities = 0, - .bDataInterface = 1, /* index of data interface */ + .bLength = sizeof(gs_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + .bDataInterface = 1, /* index of data interface */ }; static struct usb_cdc_acm_descriptor gs_acm_descriptor = { - .bLength = sizeof(gs_acm_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = 0, + .bLength = sizeof(gs_acm_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = 0, }; static const struct usb_cdc_union_desc gs_union_desc = { @@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = { .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */ }; - + static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED static struct usb_endpoint_descriptor gs_highspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = { NULL, }; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - /* Module */ MODULE_DESCRIPTION(GS_LONG_NAME); MODULE_AUTHOR("Al Borchers"); MODULE_LICENSE("GPL"); -#ifdef GS_DEBUG +#ifdef DEBUG module_param(debug, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); #endif @@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) return; } - gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2)); + gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", + port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); @@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev) len = gs_send_packet(dev, req->buf, ep->maxpacket); if (len > 0) { -gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2)); + gs_debug_level(3, "gs_send: len=%d, 0x%2.2x " + "0x%2.2x 0x%2.2x ...\n", len, + *((unsigned char *)req->buf), + *((unsigned char *)req->buf+1), + *((unsigned char *)req->buf+2)); list_del(&req_entry->re_entry); req->length = len; spin_unlock_irqrestore(&dev->dev_lock, flags); @@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) switch(req->status) { case 0: - /* normal completion */ + /* normal completion */ gs_recv_packet(dev, req->buf, req->actual); requeue: req->length = ep->maxpacket; @@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget) ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - gs_qualifier_desc.bDeviceClass = use_acm - ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; - /* assume ep0 uses the same packet size for both speeds */ - gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; - /* assume endpoints are dual-speed */ - gs_highspeed_notify_desc.bEndpointAddress = - gs_fullspeed_notify_desc.bEndpointAddress; - gs_highspeed_in_desc.bEndpointAddress = - gs_fullspeed_in_desc.bEndpointAddress; - gs_highspeed_out_desc.bEndpointAddress = - gs_fullspeed_out_desc.bEndpointAddress; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ + if (gadget_is_dualspeed(gadget)) { + gs_qualifier_desc.bDeviceClass = use_acm + ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = + gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_notify_desc.bEndpointAddress = + gs_fullspeed_notify_desc.bEndpointAddress; + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; + } usb_gadget_set_selfpowered(gadget); - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { gs_otg_descriptor.bmAttributes |= USB_OTG_HNP, gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1570,9 +1553,8 @@ static int gs_setup_standard(struct usb_gadget *gadget, memcpy(req->buf, &gs_device_desc, ret); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; ret = min(wLength, (u16)sizeof(struct usb_qualifier_descriptor)); @@ -1580,14 +1562,13 @@ static int gs_setup_standard(struct usb_gadget *gadget, break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* fall through */ -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - ret = gs_build_config_buf(req->buf, gadget->speed, + ret = gs_build_config_buf(req->buf, gadget, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (ret >= 0) ret = min(wLength, (u16)ret); break; @@ -1827,8 +1808,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if (EP_NOTIFY_NAME && strcmp(ep->name, EP_NOTIFY_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_notify_desc, &gs_fullspeed_notify_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1844,9 +1824,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_IN_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, - &gs_highspeed_in_desc, + ep_desc = choose_ep_desc(gadget, + &gs_highspeed_in_desc, &gs_fullspeed_in_desc); ret = usb_ep_enable(ep,ep_desc); if (ret == 0) { @@ -1861,8 +1840,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_OUT_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_out_desc, &gs_fullspeed_out_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1981,11 +1959,11 @@ static void gs_reset_config(struct gs_dev *dev) * Builds the config descriptors in the given buffer and returns the * length, or a negative error number. */ -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg) { int len; - int high_speed; + int high_speed = 0; const struct usb_config_descriptor *config_desc; const struct usb_descriptor_header **function; @@ -1993,20 +1971,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, return -EINVAL; /* other speed switches high and full speed */ - high_speed = (speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - high_speed = !high_speed; + if (gadget_is_dualspeed(g)) { + high_speed = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + high_speed = !high_speed; + } if (use_acm) { config_desc = &gs_acm_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_acm_highspeed_function, - gs_acm_fullspeed_function); + function = high_speed + ? gs_acm_highspeed_function + : gs_acm_fullspeed_function; } else { config_desc = &gs_bulk_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_bulk_highspeed_function, - gs_bulk_fullspeed_function); + function = high_speed + ? gs_bulk_highspeed_function + : gs_bulk_fullspeed_function; } /* for now, don't advertise srp-only devices */ From 2e806f67cc570d25395469a0ded0df8ffbd4d82f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:03:39 -0700 Subject: [PATCH 2643/2804] USB: gadget: file storage gadget cleanups Clean up the file storage gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the DEBUG (from Kconfig+Makefile) and VERBOSE_DEBUG conventions. - Remove some "sparse" warnings (it still dislikes the __user annotations) This gave only a minor object code shrinkage. Signed-off-by: David Brownell Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 120 ++++++++++++------------------ 1 file changed, 46 insertions(+), 74 deletions(-) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 965ad7bec7b7..0019116ee411 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -217,17 +217,11 @@ */ -#undef DEBUG -#undef VERBOSE +/* #define VERBOSE_DEBUG */ #undef DUMP_MSGS -#include -#include - -#include #include -#include #include #include #include @@ -235,18 +229,10 @@ #include #include #include -#include -#include #include #include #include -#include -#include -#include -#include #include -#include -#include #include #include #include @@ -289,57 +275,51 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#define xprintk(f,level,fmt,args...) \ - dev_printk(level , &(f)->gadget->dev , fmt , ## args) #define yprintk(l,level,fmt,args...) \ dev_printk(level , &(l)->dev , fmt , ## args) #ifdef DEBUG -#define DBG(fsg,fmt,args...) \ - xprintk(fsg , KERN_DEBUG , fmt , ## args) #define LDBG(lun,fmt,args...) \ yprintk(lun , KERN_DEBUG , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else -#define DBG(fsg,fmt,args...) \ - do { } while (0) #define LDBG(lun,fmt,args...) \ do { } while (0) #define MDBG(fmt,args...) \ do { } while (0) -#undef VERBOSE +#undef VERBOSE_DEBUG #undef DUMP_MSGS #endif /* DEBUG */ -#ifdef VERBOSE -#define VDBG DBG +#ifdef VERBOSE_DEBUG #define VLDBG LDBG #else -#define VDBG(fsg,fmt,args...) \ - do { } while (0) #define VLDBG(lun,fmt,args...) \ do { } while (0) -#endif /* VERBOSE */ +#endif /* VERBOSE_DEBUG */ -#define ERROR(fsg,fmt,args...) \ - xprintk(fsg , KERN_ERR , fmt , ## args) #define LERROR(lun,fmt,args...) \ yprintk(lun , KERN_ERR , fmt , ## args) - -#define WARN(fsg,fmt,args...) \ - xprintk(fsg , KERN_WARNING , fmt , ## args) #define LWARN(lun,fmt,args...) \ yprintk(lun , KERN_WARNING , fmt , ## args) - -#define INFO(fsg,fmt,args...) \ - xprintk(fsg , KERN_INFO , fmt , ## args) #define LINFO(lun,fmt,args...) \ yprintk(lun , KERN_INFO , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) + /*-------------------------------------------------------------------------*/ @@ -350,8 +330,8 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[MAX_LUNS]; int ro[MAX_LUNS]; - int num_filenames; - int num_ros; + unsigned int num_filenames; + unsigned int num_ros; unsigned int nluns; int removable; @@ -950,8 +930,6 @@ static const struct usb_descriptor_header *fs_function[] = { #define FS_FUNCTION_PRE_EP_ENTRIES 2 -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -1014,14 +992,14 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) - -#else - -/* If there's no high speed support, always use the full-speed descriptor. */ -#define ep_desc(g,fs,hs) fs - -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} /* The CBI specification limits the serial string to 12 uppercase hexadecimal @@ -1053,26 +1031,22 @@ static struct usb_gadget_strings stringtab = { static int populate_config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { -#ifdef CONFIG_USB_GADGET_DUALSPEED enum usb_device_speed speed = gadget->speed; -#endif int len; const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - if (speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) function = hs_function; else -#endif function = fs_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); @@ -1394,10 +1368,9 @@ static int standard_setup_req(struct fsg_dev *fsg, value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); @@ -1405,15 +1378,12 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; goto get_config; -#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -#ifdef CONFIG_USB_GADGET_DUALSPEED - get_config: -#endif +get_config: value = populate_config_buf(fsg->gadget, req->buf, w_value >> 8, @@ -3859,7 +3829,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) /* Find out how many LUNs there should be */ i = mod_data.nluns; if (i == 0) - i = max(mod_data.num_filenames, 1); + i = max(mod_data.num_filenames, 1u); if (i > MAX_LUNS) { ERROR(fsg, "invalid number of LUNs: %d\n", i); rc = -EINVAL; @@ -3944,22 +3914,24 @@ static int __init fsg_bind(struct usb_gadget *gadget) intf_desc.bInterfaceProtocol = mod_data.transport_type; fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; + if (gadget_is_dualspeed(gadget)) { + hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - /* Assume ep0 uses the same maxpacket value for both speeds */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - /* Assume that all endpoint addresses are the same for both speeds */ - hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; - hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; - hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; -#endif - - if (gadget->is_otg) { - otg_desc.bmAttributes |= USB_OTG_HNP; + /* Assume endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = + fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = + fs_bulk_out_desc.bEndpointAddress; + hs_intr_in_desc.bEndpointAddress = + fs_intr_in_desc.bEndpointAddress; } + if (gadget_is_otg(gadget)) + otg_desc.bmAttributes |= USB_OTG_HNP; + rc = -ENOMEM; /* Allocate the request and buffer for endpoint 0 */ From ca2bdf4bcc91818f03e009b87c348609c2578d1d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 12:20:05 -0700 Subject: [PATCH 2644/2804] USB: gadget: gadget zero cleanups Clean up gadget zero, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the VERBOSE_DEBUG convention - Some whitespace fixes. - A few comment updates - Plus a few other small cleanups: don't pass gfp_t around when it's always going to be GFP_ATOMIC, and do static init of serial number. Also go to straight GPL; there's no real point in dual licensing this stuff any more. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/zero.c | 237 +++++++++++++++----------------------- 1 file changed, 96 insertions(+), 141 deletions(-) diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index fcfe869acb94..ff540879ce3a 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1,38 +1,22 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003-2004 David Brownell + * Copyright (C) 2003-2007 David Brownell * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. 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. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * 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. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that 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 SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 */ @@ -57,30 +41,18 @@ * Many drivers will only have one configuration, letting them be much * simpler if they also don't support high speed operation (like this * driver does). + * + * Why is *this* driver using two configurations, rather than setting up + * two interfaces with different functions? To help verify that multiple + * configuration infrastucture is working correctly; also, so that it can + * work with low capability USB controllers without four bulk endpoints. */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include - -#include -#include -#include -#include -#include #include #include @@ -90,7 +62,7 @@ /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "St Patrick's Day 2004" +#define DRIVER_VERSION "Lughnasadh, 2007" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -131,30 +103,16 @@ struct zero_dev { struct timer_list resume; }; -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) /*-------------------------------------------------------------------------*/ @@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = { }; /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} -#else +static char manufacturer[50]; -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) fs +/* default serial number takes at least two packets */ +static char serial[] = "0123456789.0123456789.0123456789"; -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ - -static char manufacturer [50]; -static char serial [40]; /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget, int is_source_sink; int len; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (gadget->speed == USB_SPEED_HIGH); -#endif + int hs = 0; /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; is_source_sink = loopdefault ? (index == 1) : (index == 0); -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(gadget)) { + hs = (gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) function = is_source_sink ? hs_source_sink_function : hs_loopback_function; else -#endif function = is_source_sink ? fs_source_sink_function : fs_loopback_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf (is_source_sink @@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) /*-------------------------------------------------------------------------*/ +/* + * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals, + * this just sinks bulk packets OUT to the peripheral and sources them IN + * to the host, optionally with specific data patterns. + * + * In terms of control messaging, this supports all the standard requests + * plus two that support control-OUT tests. + * + * Note that because this doesn't queue more than one request at a time, + * some other function must be used to test queueing logic. The network + * link (g_ether) is probably the best option for that. + */ + /* optionally require specific source/sink data patterns */ static int @@ -534,12 +505,7 @@ check_read_data ( return 0; } -static void -reinit_write_data ( - struct zero_dev *dev, - struct usb_ep *ep, - struct usb_request *req -) +static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) { unsigned i; u8 *buf = req->buf; @@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { check_read_data (dev, ep, req); memset (req->buf, 0x55, req->length); } else - reinit_write_data (dev, ep, req); + reinit_write_data(ep, req); break; /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, @@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } } -static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) +static struct usb_request *source_sink_start_ep(struct usb_ep *ep) { struct usb_request *req; int status; @@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) req->complete = source_sink_complete; if (strcmp (ep->name, EP_IN_NAME) == 0) - reinit_write_data (ep->driver_data, ep, req); + reinit_write_data(ep, req); else memset (req->buf, 0x55, req->length); - status = usb_ep_queue (ep, req, gfp_flags); + status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status) { struct zero_dev *dev = ep->driver_data; @@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) return req; } -static int -set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_source_sink_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->in_ep = ep; continue; } @@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->out_ep = ep; continue; } @@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { /* loop this OUT packet back IN to the host */ req->zero = (req->actual < req->length); @@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) * rely on the hardware driver to clean up on disconnect or * endpoint disable. */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ free_ep_req (ep, req); @@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } } -static int -set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_loopback_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev) * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */ -static int -zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) +static int zero_set_config(struct zero_dev *dev, unsigned number) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO (dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } zero_reset_config (dev); switch (number) { case CONFIG_SOURCE_SINK: - result = set_source_sink_config (dev, gfp_flags); + result = set_source_sink_config(dev); break; case CONFIG_LOOPBACK: - result = set_loopback_config (dev, gfp_flags); + result = set_loopback_config(dev); break; default: result = -EINVAL; @@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + default: speed = "?"; break; } dev->config = number; @@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (w_length, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (w_length, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget, req->buf, w_value >> 8, @@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) else VDBG (dev, "HNP inactive\n"); spin_lock (&dev->lock); - value = zero_set_config (dev, w_value, GFP_ATOMIC); + value = zero_set_config(dev, w_value); spin_unlock (&dev->lock); break; case USB_REQ_GET_CONFIGURATION: @@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * use this "reset the config" shortcut. */ zero_reset_config (dev); - zero_set_config (dev, config, GFP_ATOMIC); + zero_set_config(dev, config); value = 0; } spin_unlock (&dev->lock); @@ -1163,7 +1121,7 @@ autoconf_fail: } EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim */ - + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!ep) goto autoconf_fail; @@ -1207,16 +1165,18 @@ autoconf_fail: device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* assume ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + if (gadget_is_dualspeed(gadget)) { + /* assume ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; -#endif + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = { .suspend = zero_suspend, .resume = zero_resume, - .driver = { + .driver = { .name = (char *) shortname, .owner = THIS_MODULE, }, }; -MODULE_AUTHOR ("David Brownell"); -MODULE_LICENSE ("Dual BSD/GPL"); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); static int __init init (void) { - /* a real value would likely come through some id prom - * or module option. this one takes at least two packets. - */ - strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial); - return usb_gadget_register_driver (&zero_driver); } module_init (init); From da04b7a42711c1d1d8d9fbc2565cdd83efcfee40 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:33:57 -0700 Subject: [PATCH 2645/2804] usb: introduce usb_device authorization bits This just modifies 'struct usb_device' to contain the 'authorized' bit. It also adds a 'wusb' bit. This is needed because nonauthorized (and thus non-authenticated) wusb devices will fail certain kind of simple requests (such as string descriptors). By knowing the device is WUSB, we just avoid them. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/linux/usb.h b/include/linux/usb.h index a51f34e80572..92d63c6b6fc6 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -346,6 +346,11 @@ struct usb_tt; * * Usbcore drivers should not set usbdev->state directly. Instead use * usb_set_device_state(). + * + * @authorized: (user space) policy determines if we authorize this + * device to be used or not. By default, wired USB + * devices are authorized. WUSB devices are not, until we + * authorize them from user space. FIXME -- complete doc */ struct usb_device { int devnum; /* Address on USB bus */ @@ -380,6 +385,8 @@ struct usb_device { unsigned discon_suspended:1; /* Disconnected while suspended */ unsigned have_langid:1; /* whether string_langid is valid */ + unsigned authorized:1; /* Policy has determined we can use it */ + unsigned wusb:1; /* Device is Wireless USB */ int string_langid; /* language ID for strings */ /* static strings from the device */ From 5234ce1b02ae2574098ebe9839dcf241076a9367 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:33:58 -0700 Subject: [PATCH 2646/2804] usb: add the concept of default authorization to USB hosts This introduces /sys/bus/devices/usb*/authorized_default; it dictates what is going to be the default authorization state for devices connected to the host. User space can set that using the sysfs file. We hook to the root hub instead of to the device controller as it is quite easy to get to it in sysfs from the device structure (device 5-4.3 is usb5) vs. backtracking to the controller device. By default it is set to be 'authorized' (!0) for normal, wired USB devices and 'unauthorized' (0) for Wireless USB devices. As suggested by Adrian Bunk, make authorized_default static Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 73 +++++++++++++++++++++++++++++++++++++++++- drivers/usb/core/hcd.h | 7 ++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index eb2121788264..875e2476c1f5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -679,6 +679,66 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) return 0; } + + +/* + * Show & store the current value of authorized_default + */ +static ssize_t usb_host_authorized_default_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); +} + +static ssize_t usb_host_authorized_default_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + unsigned val; + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + result = sscanf(buf, "%u\n", &val); + if (result == 1) { + usb_hcd->authorized_default = val? 1 : 0; + result = size; + } + else + result = -EINVAL; + return result; +} + +static DEVICE_ATTR(authorized_default, 0644, + usb_host_authorized_default_show, + usb_host_authorized_default_store); + + +/* Group all the USB bus attributes */ +static struct attribute *usb_bus_attrs[] = { + &dev_attr_authorized_default.attr, + NULL, +}; + +static struct attribute_group usb_bus_attr_group = { + .name = NULL, /* we want them in the same directory */ + .attrs = usb_bus_attrs, +}; + + + /*-------------------------------------------------------------------------*/ static struct class *usb_host_class; @@ -1542,7 +1602,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; - return hcd; } EXPORT_SYMBOL (usb_create_hcd); @@ -1587,6 +1646,7 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); + hcd->authorized_default = hcd->wireless? 0 : 1; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* HC is in reset state, but accessible. Now do the one-time init, @@ -1663,10 +1723,20 @@ int usb_add_hcd(struct usb_hcd *hcd, if ((retval = register_root_hub(hcd)) != 0) goto err_register_root_hub; + retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); + if (retval < 0) { + printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n", + retval); + goto error_create_attr_group; + } if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; +error_create_attr_group: + mutex_lock(&usb_bus_list_lock); + usb_disconnect(&hcd->self.root_hub); + mutex_unlock(&usb_bus_list_lock); err_register_root_hub: hcd->driver->stop(hcd); err_hcd_driver_start: @@ -1708,6 +1778,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) cancel_work_sync(&hcd->wakeup_work); #endif + sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group); mutex_lock(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); mutex_unlock(&usb_bus_list_lock); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index b5ebb73c2332..8683142e70e1 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -51,6 +51,12 @@ * * Since "struct usb_bus" is so thin, you can't share much code in it. * This framework is a layer over that, and should be more sharable. + * + * @authorized_default: Specifies if new devices are authorized to + * connect by default or they require explicit + * user space authorization; this bit is settable + * through /sys/class/usb_host/X/authorized_default. + * For the rest is RO, so we don't lock to r/w it. */ /*-------------------------------------------------------------------------*/ @@ -90,6 +96,7 @@ struct usb_hcd { unsigned poll_rh:1; /* poll for rh status? */ unsigned poll_pending:1; /* status has changed? */ unsigned wireless:1; /* Wireless USB HCD */ + unsigned authorized_default:1; int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ From eb579f5811ddbc052c8d6b3bba38dd4e5148cf7b Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:33:59 -0700 Subject: [PATCH 2647/2804] usb: cleanup usb_register_bus() and hook up sysfs group This path cleans the exit paths of usb_register_bus() [to use a goto schema], maximum line length (keeping it under ~75). Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 875e2476c1f5..a5a46a55376b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -792,27 +792,23 @@ static void usb_bus_init (struct usb_bus *bus) */ static int usb_register_bus(struct usb_bus *bus) { + int result = -E2BIG; int busnum; mutex_lock(&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); - if (busnum < USB_MAXBUS) { - set_bit (busnum, busmap.busmap); - bus->busnum = busnum; - } else { + if (busnum >= USB_MAXBUS) { printk (KERN_ERR "%s: too many buses\n", usbcore_name); - mutex_unlock(&usb_bus_list_lock); - return -E2BIG; + goto error_find_busnum; } - + set_bit (busnum, busmap.busmap); + bus->busnum = busnum; bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), - bus->controller, "usb_host%d", busnum); - if (IS_ERR(bus->class_dev)) { - clear_bit(busnum, busmap.busmap); - mutex_unlock(&usb_bus_list_lock); - return PTR_ERR(bus->class_dev); - } - + bus->controller, "usb_host%d", + busnum); + result = PTR_ERR(bus->class_dev); + if (IS_ERR(bus->class_dev)) + goto error_create_class_dev; class_set_devdata(bus->class_dev, bus); /* Add it to the local list of buses */ @@ -821,8 +817,15 @@ static int usb_register_bus(struct usb_bus *bus) usb_notify_add_bus(bus); - dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); + dev_info (bus->controller, "new USB bus registered, assigned bus " + "number %d\n", bus->busnum); return 0; + +error_create_class_dev: + clear_bit(busnum, busmap.busmap); +error_find_busnum: + mutex_unlock(&usb_bus_list_lock); + return result; } /** From d7d07255d3f5607802b0af29e11448d18e9ed558 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:00 -0700 Subject: [PATCH 2648/2804] usb: initialize authorization and wusb bits in USB devices Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 67e2e582e463..e5ff161776fa 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void) #endif /* CONFIG_PM */ + +/* Returns 1 if @usb_bus is WUSB, 0 otherwise */ +static unsigned usb_bus_is_wusb(struct usb_bus *bus) +{ + struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self); + return hcd->wireless; +} + + /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub @@ -239,6 +248,8 @@ struct usb_device * usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) { struct usb_device *dev; + struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); + unsigned root_hub = 0; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) @@ -275,6 +286,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.parent = bus->controller; sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); + root_hub = 1; } else { /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') @@ -301,6 +313,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; #endif + if (root_hub) /* Root hub always ok [and always wired] */ + dev->authorized = 1; + else { + dev->authorized = usb_hcd->authorized_default; + dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; + } return dev; } From 16bbab2966309ae82cda3d378964c56096d4858c Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:01 -0700 Subject: [PATCH 2649/2804] usb: usb_set_configuration() obeys authorization Will refuse to configure a non-authorized device. Update: simplified if statement--thanks to Ragner Magalhaes for the heads up. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index a26a7292b61a..025ac0bd3534 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1483,6 +1483,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, * channels are available independently; and choosing between open * standard device protocols (like CDC) or proprietary ones. * + * Note that a non-authorized device (dev->authorized == 0) will only + * be put in unconfigured mode. + * * Note that USB has an additional level of device configurability, * associated with interfaces. That configurability is accessed using * usb_set_interface(). @@ -1504,7 +1507,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_interface **new_interfaces = NULL; int n, nintf; - if (configuration == -1) + if (dev->authorized == 0 || configuration == -1) configuration = 0; else { for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { From 1145065cd0434b0fd5cd7c0efe0f1438fb154ed0 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:02 -0700 Subject: [PATCH 2650/2804] usb: usb_get_configuration() obeys authorization If called and the device is not authorized to be used, then we don't allow reading the configurations. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index cb69aa1e02e8..1a8edcee7f30 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev) } -// hub-only!! ... and only in reset path, or usb_new_device() -// (used by real hubs and virtual root hubs) +/* + * Get the USB config descriptors, cache and parse'em + * + * hub-only!! ... and only in reset path, or usb_new_device() + * (used by real hubs and virtual root hubs) + * + * NOTE: if this is a WUSB device and is not authorized, we skip the + * whole thing. A non-authorized USB device has no + * configurations. + */ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = -ENOMEM; + int result = 0; unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; struct usb_config_descriptor *desc; + cfgno = 0; + if (dev->authorized == 0) /* Not really an error */ + goto out_not_authorized; + result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev) goto err2; desc = (struct usb_config_descriptor *)buffer; - for (cfgno = 0; cfgno < ncfg; cfgno++) { + result = 0; + for (; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, USB_DT_CONFIG_SIZE); if (result < 0) { dev_err(ddev, "unable to read config index %d " - "descriptor/%s\n", cfgno, "start"); + "descriptor/%s: %d\n", cfgno, "start", result); dev_err(ddev, "chopping to %d config(s)\n", cfgno); dev->descriptor.bNumConfigurations = cfgno; break; @@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev) err: kfree(buffer); +out_not_authorized: dev->descriptor.bNumConfigurations = cfgno; err2: if (result == -ENOMEM) From 72230abb21349cda54d6cce0d6fd325c023b958e Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:03 -0700 Subject: [PATCH 2651/2804] usb: usb_probe_interface() obeys authorization If called and the device is not authorized to be used, it won't configure the interface and print a message saying so. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 63b1243a9139..8da4801bb922 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev) intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); + if (udev->authorized == 0) { + dev_err(&intf->dev, "Device is not authorized for usage\n"); + return -ENODEV; + } + id = usb_match_id(intf, driver->id_table); if (!id) id = usb_match_dynamic_id(intf, driver); From f8a374648b58e5cfa14447eca866aed14a4fbfa8 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:04 -0700 Subject: [PATCH 2652/2804] usb: usb_generic_probe() obeys authorization If called and the device is not authorized to be used, then we won't choose a configuration (as they are not a concept that exists for an unauthorized device). However, the device is added to the system. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b2fc2b115256..20b095050a16 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev) /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ - c = choose_configuration(udev); - if (c >= 0) { - err = usb_set_configuration(udev, c); - if (err) { - dev_err(&udev->dev, "can't set config #%d, error %d\n", + if (udev->authorized == 0) + dev_err(&udev->dev, "Device is not authorized for usage\n"); + else { + c = choose_configuration(udev); + if (c >= 0) { + err = usb_set_configuration(udev, c); + if (err) { + dev_err(&udev->dev, "can't set config #%d, error %d\n", c, err); - /* This need not be fatal. The user can try to - * set other configurations. */ + /* This need not be fatal. The user can try to + * set other configurations. */ + } } } - /* USB device state == configured ... usable */ usb_notify_add_device(udev); From d9d16e8a92e385c9f57d2081b7aa737770a0a829 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:05 -0700 Subject: [PATCH 2653/2804] usb: split usb_new_device for clarity and refactoring This patch takes hub.c:usb_new_device() and splits it in three parts: - The actual actions of adding a new device (quirk detection, announcement and autoresume tracking) - Actual discovery and probing of the configuration and interfaces (split into __usb_configure_device()) - Configuration of the On-the-go parameters (split into __usb_configure_device_otg()). The fundamental reasons for doing this split are clarity (smaller functions are easier to maintain) and to allow part of the code to be reused when authorizing devices to connect. When a device is authorized connection, we need to run through the hoops we didn't run when it was connected but not authorized, which is basically parsing the configurations and probing them. usb_configure_device() will do that for us. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 136 ++++++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 48 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 34be27a6cbb4..65d9ea1e6d71 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1220,54 +1220,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) #endif /** - * usb_new_device - perform initial device setup (usbcore-internal) + * usb_configure_device_otg - FIXME (usbcore-internal) * @udev: newly addressed device (in ADDRESS state) * - * This is called with devices which have been enumerated, but not yet - * configured. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * It will return if the device is configured properly or not. Zero if - * the interface was registered with the driver core; else a negative - * errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. + * Do configuration for On-The-Go devices */ -int usb_new_device(struct usb_device *udev) +static int usb_configure_device_otg(struct usb_device *udev) { - int err; - - /* Determine quirks */ - usb_detect_quirks(udev); - - err = usb_get_configuration(udev); - if (err < 0) { - dev_err(&udev->dev, "can't read configurations, error %d\n", - err); - goto fail; - } - - /* read the standard strings and cache them if present */ - udev->product = usb_cache_string(udev, udev->descriptor.iProduct); - udev->manufacturer = usb_cache_string(udev, - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - - /* Tell the world! */ - dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " - "SerialNumber=%d\n", - udev->descriptor.iManufacturer, - udev->descriptor.iProduct, - udev->descriptor.iSerialNumber); - show_string(udev, "Product", udev->product); - show_string(udev, "Manufacturer", udev->manufacturer); - show_string(udev, "SerialNumber", udev->serial); + int err = 0; #ifdef CONFIG_USB_OTG /* @@ -1329,8 +1289,82 @@ int usb_new_device(struct usb_device *udev) err = -ENOTSUPP; goto fail; } +fail: #endif + return err; +} + +/** + * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is only called by usb_new_device() and usb_authorize_device() + * and FIXME -- all comments that apply to them apply here wrt to + * environment. + * + * If the device is WUSB and not authorized, we don't attempt to read + * the string descriptors, as they will be errored out by the device + * until it has been authorized. + */ +static int usb_configure_device(struct usb_device *udev) +{ + int err; + + if (udev->config == NULL) { + err = usb_get_configuration(udev); + if (err < 0) { + dev_err(&udev->dev, "can't read configurations, error %d\n", + err); + goto fail; + } + } + if (udev->wusb == 1 && udev->authorized == 0) { + udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + } + else { + /* read the standard strings and cache them if present */ + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); + } + err = usb_configure_device_otg(udev); +fail: + return err; +} + + +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller must have locked either + * the parent hub (if udev is a normal device) or else the + * usb_bus_list_lock (if udev is a root hub). The parent's pointer to + * udev has already been installed, but udev is not yet visible through + * sysfs or other filesystem code. + * + * It will return if the device is configured properly or not. Zero if + * the interface was registered with the driver core; else a negative + * errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) +{ + int err; + + usb_detect_quirks(udev); /* Determine quirks */ + err = usb_configure_device(udev); /* detect & probe dev/intfs */ + if (err < 0) + goto fail; /* export the usbdev device-node for libusb */ udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); @@ -1346,17 +1380,23 @@ int usb_new_device(struct usb_device *udev) err = device_add(&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); - if (udev->parent) - usb_autosuspend_device(udev->parent); goto fail; } -exit: + /* Tell the world! */ + dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " + "SerialNumber=%d\n", + udev->descriptor.iManufacturer, + udev->descriptor.iProduct, + udev->descriptor.iSerialNumber); + show_string(udev, "Product", udev->product); + show_string(udev, "Manufacturer", udev->manufacturer); + show_string(udev, "SerialNumber", udev->serial); return err; fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); - goto exit; + return err; } static int hub_port_status(struct usb_hub *hub, int port1, From 93993a0a3e528357ae4b9b0eb82fd4b428ebbf64 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:06 -0700 Subject: [PATCH 2654/2804] usb: introduce usb_authorize/deauthorize() These USB API functions will do the full authorization/deauthorization to be used for a device. When authorized we effectively allow a configuration to be set. Reverse that when deauthorized. Effectively this means that we have to clean all the configuration descriptors on deauthorize and reload them when we authorized. We could do without throwing them out for wired devices, but for wireless, we can read them only after authenticating, and thus, when authorizing an authenticated device we would need to read them. So to simplify, always release them on deauthorize(), re-read them on authorize(). Also fix leak reported by Ragner Magalhaes; in usb_deauthorize_device(), bNumConfigurations was being set to zero before the for loop, and thus the different raw descriptors where never being freed. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 2 +- drivers/usb/core/hub.c | 81 ++++++++++++++++++++++++++++++++++++++ drivers/usb/core/usb.h | 3 ++ 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 20b095050a16..7b9e1ec718d2 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -static int choose_configuration(struct usb_device *udev) +int choose_configuration(struct usb_device *udev) { int i; int num_configs; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 65d9ea1e6d71..f725d9e62b5b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1399,6 +1399,87 @@ fail: return err; } + +/** + * Similar to usb_disconnect() + * + * We share a lock (that we have) with device_del(), so we need to + * defer its call. + */ +int usb_deauthorize_device(struct usb_device *usb_dev) +{ + unsigned cnt; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 0) + goto out_unauthorized; + usb_dev->authorized = 0; + usb_set_configuration(usb_dev, -1); + usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + kfree(usb_dev->config); + usb_dev->config = NULL; + for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++) + kfree(usb_dev->rawdescriptors[cnt]); + usb_dev->descriptor.bNumConfigurations = 0; + kfree(usb_dev->rawdescriptors); +out_unauthorized: + usb_unlock_device(usb_dev); + return 0; +} + + +int usb_authorize_device(struct usb_device *usb_dev) +{ + int result = 0, c; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 1) + goto out_authorized; + kfree(usb_dev->product); + usb_dev->product = NULL; + kfree(usb_dev->manufacturer); + usb_dev->manufacturer = NULL; + kfree(usb_dev->serial); + usb_dev->serial = NULL; + result = usb_autoresume_device(usb_dev); + if (result < 0) { + dev_err(&usb_dev->dev, + "can't autoresume for authorization: %d\n", result); + goto error_autoresume; + } + result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); + if (result < 0) { + dev_err(&usb_dev->dev, "can't re-read device descriptor for " + "authorization: %d\n", result); + goto error_device_descriptor; + } + usb_dev->authorized = 1; + result = usb_configure_device(usb_dev); + if (result < 0) + goto error_configure; + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ + c = choose_configuration(usb_dev); + if (c >= 0) { + result = usb_set_configuration(usb_dev, c); + if (result) { + dev_err(&usb_dev->dev, + "can't set config #%d, error %d\n", c, result); + /* This need not be fatal. The user can try to + * set other configurations. */ + } + } + dev_info(&usb_dev->dev, "authorized to connect\n"); +error_configure: +error_device_descriptor: +error_autoresume: +out_authorized: + usb_unlock_device(usb_dev); // complements locktree + return result; +} + + static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index cde6e52b84fe..e22ec7f8eb15 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -15,12 +15,15 @@ extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device (struct usb_device *dev, int skip_ep0); +extern int usb_deauthorize_device (struct usb_device *); +extern int usb_authorize_device (struct usb_device *); extern void usb_detect_quirks(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); +extern int choose_configuration(struct usb_device *udev); extern void usb_kick_khubd(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, From e03f2e8a530e0ed46af43093e23a70b7c7215263 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:07 -0700 Subject: [PATCH 2655/2804] usb: hook up device authorization to sysfs Makes it possible to control the authorization of USB devices through sysfs's /sys/usb/devices/*/authorize. Update: per Adrian Bunk's suggestion, make dev_attr_authorized_default static Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 2ab222be8fd1..e02590297d31 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -413,6 +413,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n") usb_descriptor_attr(bNumConfigurations, "%d\n") usb_descriptor_attr(bMaxPacketSize0, "%d\n") + + +/* show if the device is authorized (1) or not (0) */ +static ssize_t usb_dev_authorized_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *usb_dev = to_usb_device(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized); +} + + +/* + * Authorize a device to be used in the system + * + * Writing a 0 deauthorizes the device, writing a 1 authorizes it. + */ +static ssize_t usb_dev_authorized_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + struct usb_device *usb_dev = to_usb_device(dev); + unsigned val; + result = sscanf(buf, "%u\n", &val); + if (result != 1) + result = -EINVAL; + else if (val == 0) + result = usb_deauthorize_device(usb_dev); + else + result = usb_authorize_device(usb_dev); + return result < 0? result : size; +} + +static DEVICE_ATTR(authorized, 0644, + usb_dev_authorized_show, usb_dev_authorized_store); + + static struct attribute *dev_attrs[] = { /* current configuration's attributes */ &dev_attr_configuration.attr, @@ -435,6 +473,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_version.attr, &dev_attr_maxchild.attr, &dev_attr_quirks.attr, + &dev_attr_authorized.attr, NULL, }; static struct attribute_group dev_attr_grp = { From 732bb9ee8195053a7dc00b9eec7be48891ad8668 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:08 -0700 Subject: [PATCH 2656/2804] usb: document device authorization Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/authorization.txt | 92 +++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Documentation/usb/authorization.txt diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt new file mode 100644 index 000000000000..2af400609498 --- /dev/null +++ b/Documentation/usb/authorization.txt @@ -0,0 +1,92 @@ + +Authorizing (or not) your USB devices to connect to the system + +(C) 2007 Inaky Perez-Gonzalez Intel Corporation + +This feature allows you to control if a USB device can be used (or +not) in a system. This feature will allow you to implement a lock-down +of USB devices, fully controlled by user space. + +As of now, when a USB device is connected it is configured and +it's interfaces inmediately made available to the users. With this +modification, only if root authorizes the device to be configured will +then it be possible to use it. + +Usage: + +Authorize a device to connect: + +$ echo 1 > /sys/usb/devices/DEVICE/authorized + +Deauthorize a device: + +$ echo 0 > /sys/usb/devices/DEVICE/authorized + +Set new devices connected to hostX to be deauthorized by default (ie: +lock down): + +$ echo 0 > /sys/bus/devices/usbX/authorized_default + +Remove the lock down: + +$ echo 1 > /sys/bus/devices/usbX/authorized_default + +By default, Wired USB devices are authorized by default to +connect. Wireless USB hosts deauthorize by default all new connected +devices (this is so because we need to do an authentication phase +before authorizing). + + +Example system lockdown (lame) +----------------------- + +Imagine you want to implement a lockdown so only devices of type XYZ +can be connected (for example, it is a kiosk machine with a visible +USB port): + +boot up +rc.local -> + + for host in /sys/bus/devices/usb* + do + echo 0 > $host/authorized_default + done + +Hookup an script to udev, for new USB devices + + if device_is_my_type $DEV + then + echo 1 > $device_path/authorized + done + + +Now, device_is_my_type() is where the juice for a lockdown is. Just +checking if the class, type and protocol match something is the worse +security verification you can make (or the best, for someone willing +to break it). If you need something secure, use crypto and Certificate +Authentication or stuff like that. Something simple for an storage key +could be: + +function device_is_my_type() +{ + echo 1 > authorized # temporarily authorize it + # FIXME: make sure none can mount it + mount DEVICENODE /mntpoint + sum=$(md5sum /mntpoint/.signature) + if [ $sum = $(cat /etc/lockdown/keysum) ] + then + echo "We are good, connected" + umount /mntpoint + # Other stuff so others can use it + else + echo 0 > authorized + fi +} + + +Of course, this is lame, you'd want to do a real certificate +verification stuff with PKI, so you don't depend on a shared secret, +etc, but you get the idea. Anybody with access to a device gadget kit +can fake descriptors and device info. Don't trust that. You are +welcome. + From b5ea060f1e19c6a3f409d3472c723da4517547b8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Aug 2007 22:44:27 -0600 Subject: [PATCH 2657/2804] USB: rename choose_configuration As it is global, give it a usb specific name in the global namespace. Cc: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 4 ++-- drivers/usb/core/hub.c | 2 +- drivers/usb/core/usb.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 7b9e1ec718d2..9148b69785c5 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -int choose_configuration(struct usb_device *udev) +int usb_choose_configuration(struct usb_device *udev) { int i; int num_configs; @@ -164,7 +164,7 @@ static int generic_probe(struct usb_device *udev) if (udev->authorized == 0) dev_err(&udev->dev, "Device is not authorized for usage\n"); else { - c = choose_configuration(udev); + c = usb_choose_configuration(udev); if (c >= 0) { err = usb_set_configuration(udev, c); if (err) { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f725d9e62b5b..4c495c4d5053 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1460,7 +1460,7 @@ int usb_authorize_device(struct usb_device *usb_dev) /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ - c = choose_configuration(usb_dev); + c = usb_choose_configuration(usb_dev); if (c >= 0) { result = usb_set_configuration(usb_dev, c); if (result) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index e22ec7f8eb15..c52626c51f70 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -23,7 +23,7 @@ extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); -extern int choose_configuration(struct usb_device *udev); +extern int usb_choose_configuration(struct usb_device *udev); extern void usb_kick_khubd(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, From b0e396e3097ce4914c643bc3f0c2fe0098f551eb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Aug 2007 22:44:27 -0600 Subject: [PATCH 2658/2804] USB: make usb_release_interface static No one else calls it, this makes sparse happy. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 025ac0bd3534..c905b35d4f85 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1330,7 +1330,7 @@ int usb_reset_configuration(struct usb_device *dev) return 0; } -void usb_release_interface(struct device *dev) +static void usb_release_interface(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); struct usb_interface_cache *intfc = From e9df41c5c5899259541dc928872cad4d07b82076 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 11:48:02 -0400 Subject: [PATCH 2659/2804] USB: make HCDs responsible for managing endpoint queues This patch (as954) implements a suggestion of David Brownell's. Now the host controller drivers are responsible for linking and unlinking URBs to/from their endpoint queues. This eliminates the possiblity of strange situations where usbcore thinks an URB is linked but the HCD thinks it isn't. It also means HCDs no longer have to check for URBs being dequeued before they were fully enqueued. In addition to the core changes, this requires changing every host controller driver and the root-hub URB handler. For the most part the required changes are fairly small; drivers have to call usb_hcd_link_urb_to_ep() in their urb_enqueue method, usb_hcd_check_unlink_urb() in their urb_dequeue method, and usb_hcd_unlink_urb_from_ep() before giving URBs back. A few HCDs make matters more complicated by the way they split up the flow of control. In addition some method interfaces get changed. The endpoint argument for urb_enqueue is now redundant so it is removed. The unlink status is required by usb_hcd_check_unlink_urb(), so it has been added to urb_dequeue. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Tony Olech CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 255 ++++++++++++++++---------------- drivers/usb/core/hcd.h | 14 +- drivers/usb/gadget/dummy_hcd.c | 22 ++- drivers/usb/host/ehci-hcd.c | 14 +- drivers/usb/host/ehci-q.c | 14 +- drivers/usb/host/ehci-sched.c | 43 ++++-- drivers/usb/host/isp116x-hcd.c | 31 ++-- drivers/usb/host/ohci-hcd.c | 32 ++-- drivers/usb/host/ohci-q.c | 1 + drivers/usb/host/r8a66597-hcd.c | 37 +++-- drivers/usb/host/sl811-hcd.c | 26 +++- drivers/usb/host/u132-hcd.c | 170 ++++++++++++++------- drivers/usb/host/uhci-q.c | 32 ++-- 13 files changed, 420 insertions(+), 271 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a5a46a55376b..a853f63b9254 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -356,11 +356,17 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; - int status = 0; + int status; int n; might_sleep(); + spin_lock_irq(&hcd_root_hub_lock); + status = usb_hcd_link_urb_to_ep(hcd, urb); + spin_unlock_irq(&hcd_root_hub_lock); + if (status) + return status; + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); @@ -525,10 +531,9 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - spin_unlock(&urb->lock); + usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. * Avoiding calls to local_irq_disable/enable makes the code @@ -571,26 +576,21 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) { - hcd->poll_pending = 0; - hcd->status_urb = NULL; - urb->status = 0; - urb->hcpriv = NULL; - urb->actual_length = length; - memcpy(urb->transfer_buffer, buffer, length); - } else /* urb has been unlinked */ - length = 0; - spin_unlock(&urb->lock); + hcd->poll_pending = 0; + hcd->status_urb = NULL; + urb->status = 0; + urb->hcpriv = NULL; + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); + usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&hcd_root_hub_lock); - } else + } else { length = 0; - - if (length <= 0) hcd->poll_pending = 1; + } spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } @@ -619,24 +619,26 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) int len = 1 + (urb->dev->maxchild / 8); spin_lock_irqsave (&hcd_root_hub_lock, flags); - if (urb->status != -EINPROGRESS) /* already unlinked */ - retval = urb->status; - else if (hcd->status_urb || urb->transfer_buffer_length < len) { + if (hcd->status_urb || urb->transfer_buffer_length < len) { dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); retval = -EINVAL; - } else { - hcd->status_urb = urb; - urb->hcpriv = hcd; /* indicate it's queued */ - - if (!hcd->uses_new_polling) - mod_timer (&hcd->rh_timer, - (jiffies/(HZ/4) + 1) * (HZ/4)); - - /* If a status change has already occurred, report it ASAP */ - else if (hcd->poll_pending) - mod_timer (&hcd->rh_timer, jiffies); - retval = 0; + goto done; } + + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) + goto done; + + hcd->status_urb = urb; + urb->hcpriv = hcd; /* indicate it's queued */ + if (!hcd->uses_new_polling) + mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); + + /* If a status change has already occurred, report it ASAP */ + else if (hcd->poll_pending) + mod_timer(&hcd->rh_timer, jiffies); + retval = 0; + done: spin_unlock_irqrestore (&hcd_root_hub_lock, flags); return retval; } @@ -655,11 +657,16 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) /* Unlinks of root-hub control URBs are legal, but they don't do anything * since these URBs always execute synchronously. */ -static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { unsigned long flags; + int rc; spin_lock_irqsave(&hcd_root_hub_lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ @@ -669,14 +676,16 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) if (urb == hcd->status_urb) { hcd->status_urb = NULL; urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&hcd_root_hub_lock); } } + done: spin_unlock_irqrestore(&hcd_root_hub_lock, flags); - return 0; + return rc; } @@ -977,12 +986,26 @@ EXPORT_SYMBOL (usb_calc_bus_time); /*-------------------------------------------------------------------------*/ -static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) +/** + * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being submitted + * + * Host controller drivers should call this routine in their enqueue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for URB + * submission, as well as for endpoint shutdown and for usb_kill_urb. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the enqueue() method must fail). If no error occurs but enqueue() fails + * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing + * the private spinlock and returning. + */ +int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; int rc = 0; - spin_lock_irqsave(&hcd_urb_list_lock, flags); + spin_lock(&hcd_urb_list_lock); /* Check that the URB isn't being killed */ if (unlikely(urb->reject)) { @@ -1009,48 +1032,48 @@ static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) goto done; } done: - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + spin_unlock(&hcd_urb_list_lock); return rc; } +EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep); -static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, +/** + * usb_hcd_check_unlink_urb - check whether an URB may be unlinked + * @hcd: host controller to which @urb was submitted + * @urb: URB being checked for unlinkability + * @status: error code to store in @urb if the unlink succeeds + * + * Host controller drivers should call this routine in their dequeue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for making + * sure than an unlink is valid. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the dequeue() method must fail). The possible error codes are: + * + * -EIDRM: @urb was not submitted or has already completed. + * The completion function may not have been called yet. + * + * -EBUSY: @urb has already been unlinked. + */ +int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, int status) { - unsigned long flags; struct list_head *tmp; - int rc = 0; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_urb_list_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave(&urb->lock, flags); - spin_lock(&hcd_urb_list_lock); /* insist the urb is still queued */ list_for_each(tmp, &urb->ep->urb_list) { if (tmp == &urb->urb_list) break; } - if (tmp != &urb->urb_list) { - rc = -EIDRM; - goto done; - } + if (tmp != &urb->urb_list) + return -EIDRM; /* Any status except -EINPROGRESS means something already started to * unlink this URB from the hardware. So there's no more work to do. */ - if (urb->status != -EINPROGRESS) { - rc = -EBUSY; - goto done; - } + if (urb->status != -EINPROGRESS) + return -EBUSY; urb->status = status; /* IRQ setup can easily be broken so that USB controllers @@ -1065,21 +1088,28 @@ static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } - done: - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - return rc; + return 0; } +EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); -static void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) +/** + * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being unlinked + * + * Host controller drivers should call this routine before calling + * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and + * interrupts must be disabled. The actions carried out here are required + * for URB completion. + */ +void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; - /* clear all state linking urb to this dev (and hcd) */ - spin_lock_irqsave(&hcd_urb_list_lock, flags); + spin_lock(&hcd_urb_list_lock); list_del_init(&urb->urb_list); - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + spin_unlock(&hcd_urb_list_lock); } +EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { @@ -1153,20 +1183,15 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * URBs must be submitted in process context with interrupts * enabled. */ - status = usb_hcd_link_urb_to_ep(hcd, urb); - if (!status) { - map_urb_for_dma(hcd, urb); - if (is_root_hub(urb->dev)) - status = rh_urb_enqueue(hcd, urb); - else - status = hcd->driver->urb_enqueue(hcd, urb->ep, urb, - mem_flags); - } + map_urb_for_dma(hcd, urb); + if (is_root_hub(urb->dev)) + status = rh_urb_enqueue(hcd, urb); + else + status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); unmap_urb_for_dma(hcd, urb); - usb_hcd_unlink_urb_from_ep(hcd, urb); INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); if (urb->reject) @@ -1183,24 +1208,19 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * soon as practical. we've already set up the urb's return status, * but we can't know if the callback completed already. */ -static int -unlink1 (struct usb_hcd *hcd, struct urb *urb) +static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) { int value; if (is_root_hub(urb->dev)) - value = usb_rh_urb_dequeue (hcd, urb); + value = usb_rh_urb_dequeue(hcd, urb, status); else { /* The only reason an HCD might fail this call is if * it has not yet fully queued the urb to begin with. * Such failures should be harmless. */ - value = hcd->driver->urb_dequeue (hcd, urb); + value = hcd->driver->urb_dequeue(hcd, urb, status); } - - if (value != 0) - dev_dbg (hcd->self.controller, "dequeue %p --> %d\n", - urb, value); return value; } @@ -1216,14 +1236,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) int retval; hcd = bus_to_hcd(urb->dev->bus); - - retval = usb_hcd_check_unlink_urb(hcd, urb, status); - if (!retval) - retval = unlink1(hcd, urb); + retval = unlink1(hcd, urb, status); if (retval == 0) retval = -EINPROGRESS; - else if (retval != -EIDRM) + else if (retval != -EIDRM && retval != -EBUSY) dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", urb, retval); return retval; @@ -1245,7 +1262,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - usb_hcd_unlink_urb_from_ep(hcd, urb); unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); @@ -1282,7 +1298,6 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, rescan: spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { - int tmp; int is_in; /* the urb may already have been unlinked */ @@ -1292,34 +1307,26 @@ rescan: is_in = usb_urb_dir_in(urb); spin_unlock(&hcd_urb_list_lock); - spin_lock (&urb->lock); - tmp = urb->status; - if (tmp == -EINPROGRESS) - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); + /* kick hcd */ + unlink1(hcd, urb, -ESHUTDOWN); + dev_dbg (hcd->self.controller, + "shutdown urb %p ep%d%s%s\n", + urb, usb_endpoint_num(&ep->desc), + is_in ? "in" : "out", + ({ char *s; - /* kick hcd unless it's already returning this */ - if (tmp == -EINPROGRESS) { - unlink1 (hcd, urb); - dev_dbg (hcd->self.controller, - "shutdown urb %p ep%d%s%s\n", - urb, usb_endpoint_num(&ep->desc), - is_in ? "in" : "out", - ({ char *s; - - switch (usb_endpoint_type(&ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - s = ""; break; - case USB_ENDPOINT_XFER_BULK: - s = "-bulk"; break; - case USB_ENDPOINT_XFER_INT: - s = "-intr"; break; - default: - s = "-iso"; break; - }; - s; - })); - } + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + s = ""; break; + case USB_ENDPOINT_XFER_BULK: + s = "-bulk"; break; + case USB_ENDPOINT_XFER_INT: + s = "-intr"; break; + default: + s = "-iso"; break; + }; + s; + })); usb_put_urb (urb); /* list contents may have changed */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8683142e70e1..745be2566f62 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -189,11 +189,10 @@ struct hc_driver { int (*get_frame_number) (struct usb_hcd *hcd); /* manage i/o requests, device state */ - int (*urb_enqueue) (struct usb_hcd *hcd, - struct usb_host_endpoint *ep, - struct urb *urb, - gfp_t mem_flags); - int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + int (*urb_enqueue)(struct usb_hcd *hcd, + struct urb *urb, gfp_t mem_flags); + int (*urb_dequeue)(struct usb_hcd *hcd, + struct urb *urb, int status); /* hw synch, freeing endpoint resources that urb_dequeue can't */ void (*endpoint_disable)(struct usb_hcd *hcd, @@ -211,6 +210,11 @@ struct hc_driver { /* Needed only if port-change IRQs are level-triggered */ }; +extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); +extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status); +extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); + extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index d008d1360a7a..c441d10c087e 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = { static int dummy_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; unsigned long flags; + int rc; if (!urb->transfer_buffer && urb->transfer_buffer_length) return -EINVAL; @@ -980,6 +980,11 @@ static int dummy_urb_enqueue ( dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + rc = usb_hcd_link_urb_to_ep(hcd, urb); + if (rc) { + kfree(urbp); + goto done; + } if (!dum->udev) { dum->udev = urb->dev; @@ -997,22 +1002,28 @@ static int dummy_urb_enqueue ( mod_timer (&dum->timer, jiffies + 1); spin_unlock_irqrestore (&dum->lock, flags); - return 0; + done: + return rc; } -static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct dummy *dum; unsigned long flags; + int rc; /* giveback happens automatically in timer callback, * so make sure the callback happens */ dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); - if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) + + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (!rc && dum->rh_state != DUMMY_RH_RUNNING && + !list_empty(&dum->urbp_list)) mod_timer (&dum->timer, jiffies); + spin_unlock_irqrestore (&dum->lock, flags); - return 0; + return rc; } static void maybe_set_status (struct urb *urb, int status) @@ -1511,6 +1522,7 @@ return_urb: if (ep) ep->already_seen = ep->setup_stage = 0; + usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); spin_lock (&dum->lock); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 35cdba10411b..db00492588b6 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -719,7 +719,6 @@ dead: */ static int ehci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -734,12 +733,12 @@ static int ehci_urb_enqueue ( default: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return submit_async (ehci, ep, urb, &qtd_list, mem_flags); + return submit_async(ehci, urb, &qtd_list, mem_flags); case PIPE_INTERRUPT: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return intr_submit (ehci, ep, urb, &qtd_list, mem_flags); + return intr_submit(ehci, urb, &qtd_list, mem_flags); case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) @@ -777,13 +776,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) * completions normally happen asynchronously */ -static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_qh *qh; unsigned long flags; + int rc; spin_lock_irqsave (&ehci->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: @@ -838,7 +842,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) } done: spin_unlock_irqrestore (&ehci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 140bfa423e07..1da2de4d34ed 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -262,6 +262,7 @@ __acquires(ehci->lock) #endif /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); spin_lock (&ehci->lock); @@ -913,7 +914,6 @@ static struct ehci_qh *qh_append_tds ( static int submit_async ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -922,10 +922,10 @@ submit_async ( int epnum; unsigned long flags; struct ehci_qh *qh = NULL; - int rc = 0; + int rc; qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -933,7 +933,7 @@ submit_async ( __FUNCTION__, urb->dev->devpath, urb, epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", urb->transfer_buffer_length, - qtd, ep->hcpriv); + qtd, urb->ep->hcpriv); #endif spin_lock_irqsave (&ehci->lock, flags); @@ -942,9 +942,13 @@ submit_async ( rc = -ESHUTDOWN; goto done; } + rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(rc)) + goto done; - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); if (unlikely(qh == NULL)) { + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); rc = -ENOMEM; goto done; } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e682f2342ef8..8b267b3fd2bb 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -797,7 +797,6 @@ done: static int intr_submit ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -805,23 +804,26 @@ static int intr_submit ( unsigned epnum; unsigned long flags; struct ehci_qh *qh; - int status = 0; + int status; struct list_head empty; /* get endpoint and transfer/schedule data */ - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - goto done; + goto done_not_linked; } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; /* get qh and force any scheduling errors */ INIT_LIST_HEAD (&empty); - qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv); if (qh == NULL) { status = -ENOMEM; goto done; @@ -832,13 +834,16 @@ static int intr_submit ( } /* then queue the urb's tds to the qh */ - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); BUG_ON (qh == NULL); /* ... update usbfs periodic stats */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; done: + if (unlikely(status)) + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); if (status) qtd_list_free (ehci, urb, qtd_list); @@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (likely (status == 0)) itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (status == 0) sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5c851a36de72..d5027dc75a57 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -290,6 +290,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock) urb_dbg(urb, "Finish"); + usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); spin_unlock(&isp116x->lock); usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); spin_lock(&isp116x->lock); @@ -673,7 +674,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) /*-----------------------------------------------------------------*/ static int isp116x_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, gfp_t mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); @@ -682,6 +683,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, int is_out = !usb_pipein(pipe); int type = usb_pipetype(pipe); int epnum = usb_pipeendpoint(pipe); + struct usb_host_endpoint *hep = urb->ep; struct isp116x_ep *ep = NULL; unsigned long flags; int i; @@ -705,7 +707,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, if (!HC_IS_RUNNING(hcd->state)) { kfree(ep); ret = -ENODEV; - goto fail; + goto fail_not_linked; + } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) @@ -818,6 +825,9 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, start_atl_transfers(isp116x); fail: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); + fail_not_linked: spin_unlock_irqrestore(&isp116x->lock, flags); return ret; } @@ -825,20 +835,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, /* Dequeue URBs. */ -static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_host_endpoint *hep; struct isp116x_ep *ep, *ep_act; unsigned long flags; + int rc; spin_lock_irqsave(&isp116x->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + hep = urb->hcpriv; - /* URB already unlinked (or never linked)? */ - if (!hep) { - spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; - } ep = hep->hcpriv; WARN_ON(hep != ep->hep); @@ -856,9 +867,9 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) if (urb) finish_request(isp116x, ep, urb); - + done: spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; + return rc; } static void isp116x_endpoint_disable(struct usb_hcd *hcd, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index d673cb9c36b1..6b06ab69938f 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -117,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); */ static int ohci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -134,7 +133,7 @@ static int ohci_urb_enqueue ( #endif /* every endpoint has a ed, locate and maybe (re)initialize it */ - if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) + if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) return -ENOMEM; /* for the private part of the URB we need the number of TDs (size) */ @@ -199,22 +198,17 @@ static int ohci_urb_enqueue ( retval = -ENODEV; goto fail; } - - /* in case of unlink-during-submit */ - spin_lock (&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock (&urb->lock); - urb->hcpriv = urb_priv; - finish_urb (ohci, urb); - retval = 0; + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) goto fail; - } /* schedule the ed if needed */ if (ed->state == ED_IDLE) { retval = ed_schedule (ohci, ed); - if (retval < 0) - goto fail0; + if (retval < 0) { + usb_hcd_unlink_urb_from_ep(hcd, urb); + goto fail; + } if (ed->type == PIPE_ISOCHRONOUS) { u16 frame = ohci_frame_no(ohci); @@ -238,8 +232,6 @@ static int ohci_urb_enqueue ( urb->hcpriv = urb_priv; td_submit_urb (ohci, urb); -fail0: - spin_unlock (&urb->lock); fail: if (retval) urb_free_priv (ohci, urb_priv); @@ -253,17 +245,21 @@ fail: * asynchronously, and we might be dealing with an urb that's * partially transferred, or an ED with other urbs being unlinked. */ -static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; + int rc; #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "UNLINK", 1); #endif spin_lock_irqsave (&ohci->lock, flags); - if (HC_IS_RUNNING(hcd->state)) { + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) { + ; /* Do nothing */ + } else if (HC_IS_RUNNING(hcd->state)) { urb_priv_t *urb_priv; /* Unless an IRQ completed the unlink while it was being @@ -284,7 +280,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) finish_urb (ohci, urb); } spin_unlock_irqrestore (&ohci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 547d39be3eb9..889c0720743b 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -74,6 +74,7 @@ __acquires(ohci->lock) #endif /* urb->complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); spin_lock (&ohci->lock); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 40a1de4c256e..94bb229df3bc 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -784,6 +784,9 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) if (urb) { urb->status = -ENODEV; urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), + urb); + spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb); spin_lock(&r8a66597->lock); @@ -1131,6 +1134,8 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, urb->start_frame = r8a66597_get_frame(hcd); urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); + spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&r8a66597->lock); @@ -1722,21 +1727,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597, } static int r8a66597_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { + struct usb_host_endpoint *hep = urb->ep; struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td = NULL; - int ret = 0, request = 0; + int ret, request = 0; unsigned long flags; spin_lock_irqsave(&r8a66597->lock, flags); if (!get_urb_to_r8a66597_dev(r8a66597, urb)) { ret = -ENODEV; - goto error; + goto error_not_linked; } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto error_not_linked; + if (!hep->hcpriv) { hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), GFP_ATOMIC); @@ -1761,15 +1770,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, if (list_empty(&r8a66597->pipe_queue[td->pipenum])) request = 1; list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]); - - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - ret = -EPIPE; - goto error; - } urb->hcpriv = td; - spin_unlock(&urb->lock); if (request) { ret = start_transfer(r8a66597, td); @@ -1781,17 +1782,26 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, set_td_timer(r8a66597, td); error: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +error_not_linked: spin_unlock_irqrestore(&r8a66597->lock, flags); return ret; } -static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td; unsigned long flags; + int rc; spin_lock_irqsave(&r8a66597->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + if (urb->hcpriv) { td = urb->hcpriv; pipe_stop(r8a66597, td->pipe); @@ -1799,8 +1809,9 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) disable_irq_empty(r8a66597, td->pipenum); done(r8a66597, td, td->pipenum, urb); } + done: spin_unlock_irqrestore(&r8a66597->lock, flags); - return 0; + return rc; } static void r8a66597_endpoint_disable(struct usb_hcd *hcd, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 4cfa3ff2c993..3d3a63d002c5 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -441,6 +441,7 @@ static void finish_request( urb->hcpriv = NULL; spin_unlock(&urb->lock); + usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); spin_unlock(&sl811->lock); usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); spin_lock(&sl811->lock); @@ -807,7 +808,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load) static int sl811h_urb_enqueue( struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags ) { @@ -820,7 +820,8 @@ static int sl811h_urb_enqueue( struct sl811h_ep *ep = NULL; unsigned long flags; int i; - int retval = 0; + int retval; + struct usb_host_endpoint *hep = urb->ep; #ifdef DISABLE_ISO if (type == PIPE_ISOCHRONOUS) @@ -838,7 +839,12 @@ static int sl811h_urb_enqueue( || !HC_IS_RUNNING(hcd->state)) { retval = -ENODEV; kfree(ep); - goto fail; + goto fail_not_linked; + } + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) { @@ -965,23 +971,27 @@ static int sl811h_urb_enqueue( start_transfer(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); fail: + if (retval) + usb_hcd_unlink_urb_from_ep(hcd, urb); +fail_not_linked: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } -static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_host_endpoint *hep; unsigned long flags; struct sl811h_ep *ep; - int retval = 0; + int retval; spin_lock_irqsave(&sl811->lock, flags); - hep = urb->hcpriv; - if (!hep) + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (retval) goto fail; + hep = urb->hcpriv; ep = hep->hcpriv; if (ep) { /* finish right away if this urb can't be active ... @@ -1029,8 +1039,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) VDBG("dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); } else -fail: retval = -EINVAL; + fail: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 598ad098aeeb..c87660b5edc3 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -521,6 +521,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, urb->status = status; urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -561,6 +562,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, urb->status = status; urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -1876,20 +1878,32 @@ static int u132_hcd_reset(struct usb_hcd *hcd) } static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, gfp_t mem_flags) { struct u132_ring *ring; unsigned long irqs; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -1905,7 +1919,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -1924,7 +1938,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132, u132_udev_get_kref(u132, udev); } urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->delayed = 1; endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); endp->udev_number = address; @@ -1939,8 +1952,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132, return 0; } -static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, +static int queue_int_on_old_endpoint(struct u132 *u132, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -1964,21 +1977,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, gfp_t mem_flags) { int ring_number; struct u132_ring *ring; unsigned long irqs; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); endp->dequeueing = 0; endp->edset_flush = 0; @@ -1986,7 +2011,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -2015,7 +2040,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } ring->length += 1; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->udev_number = address; endp->usb_addr = usb_addr; endp->usb_endp = usb_endp; @@ -2029,7 +2053,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -2051,19 +2075,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_control(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, gfp_t mem_flags) { struct u132_ring *ring; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + unsigned long irqs; + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -2079,11 +2116,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; u132_endp_init_kref(u132, endp); u132_endp_get_kref(u132, endp); if (usb_addr == 0) { - unsigned long irqs; u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; endp->udev_number = address; @@ -2097,7 +2133,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, udev->endp_number_in[usb_endp] = endp_number; udev->endp_number_out[usb_endp] = endp_number; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->queue_size = 1; endp->queue_last = 0; endp->queue_next = 0; @@ -2106,7 +2141,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, u132_endp_queue_work(u132, endp, 0); return 0; } else { /*(usb_addr > 0) */ - unsigned long irqs; u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; endp->udev_number = address; @@ -2120,7 +2154,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, udev->endp_number_in[usb_endp] = endp_number; udev->endp_number_out[usb_endp] = endp_number; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->queue_size = 1; endp->queue_last = 0; endp->queue_next = 0; @@ -2132,7 +2165,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132, } static int queue_control_on_old_endpoint(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp) { @@ -2232,8 +2265,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132, } } -static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, - struct urb *urb, gfp_t mem_flags) +static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) { struct u132 *u132 = hcd_to_u132(hcd); if (irqs_disabled()) { @@ -2258,16 +2291,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; urb->actual_length = 0; if (endp) { unsigned long irqs; int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_int_on_old_endpoint(u132, udev, - hep, urb, usb_dev, endp, usb_addr, - usb_endp, address); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_int_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2282,8 +2323,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else { /*(endp == NULL) */ return create_endpoint_and_queue_int(u132, udev, - hep, urb, usb_dev, usb_addr, usb_endp, - address, mem_flags); + urb, usb_dev, usb_addr, + usb_endp, address, mem_flags); } } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { dev_err(&u132->platform_dev->dev, "the hardware does no" @@ -2292,16 +2333,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; urb->actual_length = 0; if (endp) { unsigned long irqs; int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_bulk_on_old_endpoint(u132, udev, - hep, urb, usb_dev, endp, usb_addr, - usb_endp, address); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_bulk_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2314,10 +2363,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_bulk(u132, - udev, hep, urb, usb_dev, usb_addr, + udev, urb, usb_dev, usb_addr, usb_endp, address, mem_flags); } else { - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; u16 urb_size = 8; u8 *b = urb->setup_packet; int i = 0; @@ -2340,9 +2389,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_control_on_old_endpoint(u132, - hep, urb, usb_dev, endp, usb_addr, - usb_endp); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_control_on_old_endpoint( + u132, urb, usb_dev, + endp, usb_addr, + usb_endp); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2355,7 +2411,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_control(u132, - hep, urb, usb_dev, usb_addr, usb_endp, + urb, usb_dev, usb_addr, usb_endp, mem_flags); } } @@ -2390,10 +2446,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132, } static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb) + struct urb *urb, int status) { unsigned long irqs; + int rc; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + return rc; + } if (endp->queue_size == 0) { dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, @@ -2438,6 +2501,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } if (urb_slot) { struct usb_hcd *hcd = u132_to_hcd(u132); + + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_size -= 1; if (list_empty(&endp->urb_more)) { spin_unlock_irqrestore(&endp->queue_lock.slock, @@ -2467,7 +2532,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return -EINVAL; } else { - int retval = dequeue_from_overflow_chain(u132, endp, + int retval; + + usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); + retval = dequeue_from_overflow_chain(u132, endp, urb); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return retval; @@ -2475,7 +2543,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } } -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { @@ -2490,11 +2558,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) if (usb_pipein(urb->pipe)) { u8 endp_number = udev->endp_number_in[usb_endp]; struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb); + return u132_endp_urb_dequeue(u132, endp, urb, status); } else { u8 endp_number = udev->endp_number_out[usb_endp]; struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb); + return u132_endp_urb_dequeue(u132, endp, urb, status); } } } diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 3bb908ca38e9..bff200cb3d2e 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1376,7 +1376,6 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) } static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { int ret; @@ -1387,19 +1386,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, spin_lock_irqsave(&uhci->lock, flags); - ret = urb->status; - if (ret != -EINPROGRESS) /* URB already unlinked! */ - goto done; + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto done_not_linked; ret = -ENOMEM; urbp = uhci_alloc_urb_priv(uhci, urb); if (!urbp) goto done; - if (hep->hcpriv) - qh = (struct uhci_qh *) hep->hcpriv; + if (urb->ep->hcpriv) + qh = urb->ep->hcpriv; else { - qh = uhci_alloc_qh(uhci, urb->dev, hep); + qh = uhci_alloc_qh(uhci, urb->dev, urb->ep); if (!qh) goto err_no_qh; } @@ -1440,27 +1439,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, err_submit_failed: if (qh->state == QH_STATE_IDLE) uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */ - err_no_qh: uhci_free_urb_priv(uhci, urbp); - done: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +done_not_linked: spin_unlock_irqrestore(&uhci->lock, flags); return ret; } -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb_priv *urbp; struct uhci_qh *qh; + int rc; spin_lock_irqsave(&uhci->lock, flags); - urbp = urb->hcpriv; - if (!urbp) /* URB was never linked! */ + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) goto done; - qh = urbp->qh; + + qh = ((struct urb_priv *) urb->hcpriv)->qh; /* Remove Isochronous TDs from the frame list ASAP */ if (qh->type == USB_ENDPOINT_XFER_ISOC) { @@ -1477,7 +1478,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) done: spin_unlock_irqrestore(&uhci->lock, flags); - return 0; + return rc; } /* @@ -1529,6 +1530,7 @@ __acquires(uhci->lock) } uhci_free_urb_priv(uhci, urbp); + usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); spin_unlock(&uhci->lock); usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); From d74d4a69dc1cc7ddc0eabb9c9f1e45005e2984eb Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 11:59:18 -0400 Subject: [PATCH 2660/2804] USB: don't touch sysfs stuff when altsetting is unchanged This patch (as955) prevents the interface-related sysfs files and endpoint pseudo-devices from being deleted and recreated when a call to usb_set_interface() specifies the current altsetting. Since the altsetting doesn't get changed, there's no need to do anything. Furthermore, avoiding changes to the endpoint devices will be necessary in the future. This code is called from usb_reset_device(), which gets invoked for reset-resume processing, but upcoming changes to the PM and driver cores will make it impossible to register devices while a suspend/resume transition is in progress. Since we don't need to re-register those endpoint devices anyhow, it's best to skip the whole thing. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c905b35d4f85..d638375e22e7 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1173,6 +1173,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_host_interface *alt; int ret; int manual = 0; + int changed; if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -1212,7 +1213,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ - if (device_is_registered(&iface->dev)) + changed = (iface->cur_altsetting != alt); + if (changed && device_is_registered(&iface->dev)) usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); @@ -1249,7 +1251,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * (Likewise, EP0 never "halts" on well designed devices.) */ usb_enable_interface(dev, iface); - if (device_is_registered(&iface->dev)) + if (changed && device_is_registered(&iface->dev)) usb_create_sysfs_intf_files(iface); return 0; From 79a7d9ee1a2e8b8dc44dd217f07496911850ec0e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 17:10:11 -0400 Subject: [PATCH 2661/2804] USB: cleanups for g_file_storage This patch (as957) makes some minor cleanups to the g_file_storage driver: Update the copyright date and version string; Uniformize the logging macros for the gadget and the LUNs; Remove "inline" markers -- nowadays we rely on the compiler to decide which routines are best inlined; Use the print_hex_dump() library routines; Remove some unnecessary assignments within conditionals and fix some close-brace indenting levels; Fix some column-80 violations. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 129 ++++++++++++++---------------- 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 0019116ee411..9998cd7af418 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1,7 +1,7 @@ /* * file_storage.c -- File-backed USB Storage Gadget, for USB development * - * Copyright (C) 2003-2005 Alan Stern + * Copyright (C) 2003-2007 Alan Stern * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -218,7 +218,7 @@ /* #define VERBOSE_DEBUG */ -#undef DUMP_MSGS +/* #define DUMP_MSGS */ #include @@ -249,7 +249,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "28 November 2005" +#define DRIVER_VERSION "7 August 2007" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -275,12 +275,9 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#define yprintk(l,level,fmt,args...) \ - dev_printk(level , &(l)->dev , fmt , ## args) - #ifdef DEBUG #define LDBG(lun,fmt,args...) \ - yprintk(lun , KERN_DEBUG , fmt , ## args) + dev_dbg(&(lun)->dev , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else @@ -300,11 +297,11 @@ MODULE_LICENSE("Dual BSD/GPL"); #endif /* VERBOSE_DEBUG */ #define LERROR(lun,fmt,args...) \ - yprintk(lun , KERN_ERR , fmt , ## args) + dev_err(&(lun)->dev , fmt , ## args) #define LWARN(lun,fmt,args...) \ - yprintk(lun , KERN_WARNING , fmt , ## args) + dev_warn(&(lun)->dev , fmt , ## args) #define LINFO(lun,fmt,args...) \ - yprintk(lun , KERN_INFO , fmt , ## args) + dev_info(&(lun)->dev , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) @@ -558,7 +555,7 @@ struct lun { #define backing_file_is_open(curlun) ((curlun)->filp != NULL) -static inline struct lun *dev_to_lun(struct device *dev) +static struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); } @@ -691,13 +688,13 @@ struct fsg_dev { typedef void (*fsg_routine_t)(struct fsg_dev *); -static int inline exception_in_progress(struct fsg_dev *fsg) +static int exception_in_progress(struct fsg_dev *fsg) { return (fsg->state > FSG_STATE_IDLE); } /* Make bulk-out requests be divisible by the maxpacket size */ -static void inline set_bulk_out_req_length(struct fsg_dev *fsg, +static void set_bulk_out_req_length(struct fsg_dev *fsg, struct fsg_buffhd *bh, unsigned int length) { unsigned int rem; @@ -723,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg); static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) { - unsigned int start, num, i; - char line[52], *p; - - if (length >= 512) - return; - DBG(fsg, "%s, length %u:\n", label, length); - - start = 0; - while (length > 0) { - num = min(length, 16u); - p = line; - for (i = 0; i < num; ++i) { - if (i == 8) - *p++ = ' '; - sprintf(p, " %02x", buf[i]); - p += 3; - } - *p = 0; - printk(KERN_DEBUG "%6x: %s\n", start, line); - buf += num; - start += num; - length -= num; + if (length < 512) { + DBG(fsg, "%s, length %u:\n", label, length); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, + 16, 1, buf, length, 0); } } -static void inline dump_cdb(struct fsg_dev *fsg) +static void dump_cdb(struct fsg_dev *fsg) {} #else -static void inline dump_msg(struct fsg_dev *fsg, const char *label, +static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) {} -static void inline dump_cdb(struct fsg_dev *fsg) -{ - int i; - char cmdbuf[3*MAX_COMMAND_SIZE + 1]; +#ifdef VERBOSE_DEBUG - for (i = 0; i < fsg->cmnd_size; ++i) - sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]); - VDBG(fsg, "SCSI CDB: %s\n", cmdbuf); +static void dump_cdb(struct fsg_dev *fsg) +{ + print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, + 16, 1, fsg->cmnd, fsg->cmnd_size, 0); } +#else + +static void dump_cdb(struct fsg_dev *fsg) +{} + +#endif /* VERBOSE_DEBUG */ #endif /* DUMP_MSGS */ @@ -789,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Routines for unaligned data access */ -static u16 inline get_be16(u8 *buf) +static u16 get_be16(u8 *buf) { return ((u16) buf[0] << 8) | ((u16) buf[1]); } -static u32 inline get_be32(u8 *buf) +static u32 get_be32(u8 *buf) { return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | ((u32) buf[2] << 8) | ((u32) buf[3]); } -static void inline put_be16(u8 *buf, u16 val) +static void put_be16(u8 *buf, u16 val) { buf[0] = val >> 8; buf[1] = val; } -static void inline put_be32(u8 *buf, u32 val) +static void put_be32(u8 *buf, u32 val) { buf[0] = val >> 24; buf[1] = val >> 16; @@ -992,7 +975,7 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -static inline struct usb_endpoint_descriptor * +static struct usb_endpoint_descriptor * ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, struct usb_endpoint_descriptor *hs) { @@ -1616,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -1855,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg) } /* Wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2339,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg) /* Wait for the next buffer to be free */ while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2399,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg) } /* Otherwise wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } return 0; @@ -2521,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2741,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available for data or status */ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } fsg->phase_error = 0; fsg->short_packet_received = 0; @@ -3015,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); @@ -3031,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the CBW to arrive */ while (bh->state != BUF_STATE_FULL) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } smp_rmb(); rc = received_cbw(fsg, bh); bh->state = BUF_STATE_EMPTY; @@ -3042,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next command to arrive */ while (fsg->cbbuf_cmnd_size == 0) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Is the previous status interrupt request still busy? * The host is allowed to skip reading the status, @@ -3565,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * return sprintf(buf, "%d\n", curlun->ro); } -static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_file(struct device *dev, struct device_attribute *attr, + char *buf) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3574,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt, - buf, PAGE_SIZE - 1); + p = d_path(curlun->filp->f_path.dentry, + curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { @@ -3593,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char } -static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3617,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const return rc; } -static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); From ed86d97068c7d53561d3e9b59db6c6b11f6091c7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:24 -0400 Subject: [PATCH 2662/2804] USB: SisUSB2VGA: Whitespace Cleanups This patches clean some trailing whitespaces in sisusb2vga driver. Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 26 +++++++++++----------- drivers/usb/misc/sisusbvga/sisusb.h | 6 ++--- drivers/usb/misc/sisusbvga/sisusb_init.c | 2 +- drivers/usb/misc/sisusbvga/sisusb_init.h | 4 ++-- drivers/usb/misc/sisusbvga/sisusb_struct.h | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index b64ca91d9b02..376f86cab4b0 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, packet.address = 0x00000194; packet.data = addr; ret = sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); packet.header = 0x001f; packet.address = 0x00000190; packet.data = (length & ~3); ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); if (sisusb->flagb0 != 0x16) { packet.header = 0x001f; packet.address = 0x00000180; @@ -1019,7 +1019,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, } if (ret) - break; + break; } @@ -1305,7 +1305,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, } if (ret) - break; + break; } return ret; @@ -1533,9 +1533,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length) #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a) #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o) #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) static int sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype) @@ -2008,7 +2008,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines) SETIREG(SISSR, 0x26, 0x00); } - SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ + SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ return ret; } @@ -2942,7 +2942,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, unsigned long arg) { - int retval, port, length; + int retval, port, length; u32 address; /* All our commands require the device @@ -3065,12 +3065,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, static int sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { struct sisusb_usb_data *sisusb; struct sisusb_info x; struct sisusb_command y; - int retval = 0; + int retval = 0; u32 __user *argp = (u32 __user *)arg; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) @@ -3095,7 +3095,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case SISUSB_GET_CONFIG: - x.sisusb_id = SISUSB_ID; + x.sisusb_id = SISUSB_ID; x.sisusb_version = SISUSB_VERSION; x.sisusb_revision = SISUSB_REVISION; x.sisusb_patchlevel = SISUSB_PATCHLEVEL; @@ -3164,7 +3164,7 @@ static const struct file_operations usb_sisusb_fops = { .release = sisusb_release, .read = sisusb_read, .write = sisusb_write, - .llseek = sisusb_lseek, + .llseek = sisusb_lseek, #ifdef SISUSB_NEW_CONFIG_COMPAT .compat_ioctl = sisusb_compat_ioctl, #endif diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 8e1120a64806..555fed0ba0ef 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -30,7 +30,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -53,7 +53,7 @@ /* Version Information */ #define SISUSB_VERSION 0 -#define SISUSB_REVISION 0 +#define SISUSB_REVISION 0 #define SISUSB_PATCHLEVEL 8 /* Include console and mode switching code? */ @@ -93,7 +93,7 @@ */ #ifdef __BIG_ENDIAN -#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ +#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ do { \ p->header = cpu_to_le16(p->header); \ p->address = cpu_to_le32(p->address); \ diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 9b30f8962814..d51de0ff9e46 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index 864bc0e96591..d47301eaca7a 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -46,7 +46,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -82,7 +82,7 @@ /* Infoflag */ #define SupportTV 0x0008 #define SupportTV1024 0x0800 -#define SupportCHTV 0x0800 +#define SupportCHTV 0x0800 #define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 #define SupportYPbPr750p 0x1000 diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index f325ecb29a61..9def598192c2 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -44,7 +44,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ From 9dedd36778f9d9bd043df27c8fc62088ce93813f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:26 -0400 Subject: [PATCH 2663/2804] USB: SisUSB2VGA: Remove if 0'ed code Unused code should be removed. We don't need to increase the size of the file with dead code inside if 0 statements. Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 57 --------------- drivers/usb/misc/sisusbvga/sisusb.h | 4 +- drivers/usb/misc/sisusbvga/sisusb_con.c | 47 ------------- drivers/usb/misc/sisusbvga/sisusb_init.c | 90 ------------------------ 4 files changed, 1 insertion(+), 197 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 376f86cab4b0..558b94fd209d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1261,47 +1261,6 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, addr += 4; length -= 4; } -#if 0 /* That does not work, as EP 2 is an OUT EP! */ - default: - CLEARPACKET(&packet); - packet.header = 0x001f; - packet.address = 0x000001a0; - packet.data = 0x00000006; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b0; - packet.data = (length & ~3) | 0x40000000; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b4; - packet.data = addr; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001a4; - packet.data = 0x00000001; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - if (userbuffer) { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - NULL, userbuffer, - bytes_read, 0); - if (!ret) userbuffer += (*bytes_read); - } else { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - kernbuffer, NULL, - bytes_read, 0); - if (!ret) kernbuffer += (*bytes_read); - } - addr += (*bytes_read); - length -= (*bytes_read); -#endif } if (ret) @@ -1401,22 +1360,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); } -#if 0 - -int -sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data) -{ - return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -int -sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data) -{ - return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -#endif /* 0 */ - int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, u32 dest, int length, size_t *bytes_written) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 555fed0ba0ef..dc0473921e3d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -46,9 +46,7 @@ /* For older kernels, support for text consoles is by default * off. To ensable text console support, change the following: */ -#if 0 -#define CONFIG_USB_SISUSBVGA_CON -#endif +/* #define CONFIG_USB_SISUSBVGA_CON */ /* Version Information */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 8d0edc867f33..20938cd09ed4 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -373,14 +373,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) return; /* sisusb->lock is down */ - - /* Don't need to put the character into buffer ourselves, - * because the vt does this BEFORE calling us. - */ -#if 0 - sisusbcon_writew(ch, SISUSB_VADDR(x, y)); -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; @@ -490,10 +482,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, struct sisusb_usb_data *sisusb; ssize_t written; int cols, length; -#if 0 - u16 *src, *dest; - int i; -#endif if (width <= 0 || height <= 0) return; @@ -505,41 +493,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, cols = sisusb->sisusb_num_columns; - /* Don't need to move data outselves, because - * vt does this BEFORE calling us. - * This is only used by vt's insert/deletechar. - */ -#if 0 - if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) { - - sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy), - height * width * 2); - - } else if (dy < sy || (dy == sy && dx < sx)) { - - src = SISUSB_VADDR(sx, sy); - dest = SISUSB_VADDR(dx, dy); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src += cols; - dest += cols; - } - - } else { - - src = SISUSB_VADDR(sx, sy + height - 1); - dest = SISUSB_VADDR(dx, dy + height - 1); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src -= cols; - dest -= cols; - } - - } -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index d51de0ff9e46..5d8358295e71 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -69,96 +69,6 @@ SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; } -/*********************************************/ -/* HELPER: Get ModeID */ -/*********************************************/ - -#if 0 -unsigned short -SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) -{ - unsigned short ModeIndex = 0; - - switch (HDisplay) - { - case 320: - if (VDisplay == 200) - ModeIndex = ModeIndex_320x200[Depth]; - else if (VDisplay == 240) - ModeIndex = ModeIndex_320x240[Depth]; - break; - case 400: - if (VDisplay == 300) - ModeIndex = ModeIndex_400x300[Depth]; - break; - case 512: - if (VDisplay == 384) - ModeIndex = ModeIndex_512x384[Depth]; - break; - case 640: - if (VDisplay == 480) - ModeIndex = ModeIndex_640x480[Depth]; - else if (VDisplay == 400) - ModeIndex = ModeIndex_640x400[Depth]; - break; - case 720: - if (VDisplay == 480) - ModeIndex = ModeIndex_720x480[Depth]; - else if (VDisplay == 576) - ModeIndex = ModeIndex_720x576[Depth]; - break; - case 768: - if (VDisplay == 576) - ModeIndex = ModeIndex_768x576[Depth]; - break; - case 800: - if (VDisplay == 600) - ModeIndex = ModeIndex_800x600[Depth]; - else if (VDisplay == 480) - ModeIndex = ModeIndex_800x480[Depth]; - break; - case 848: - if (VDisplay == 480) - ModeIndex = ModeIndex_848x480[Depth]; - break; - case 856: - if (VDisplay == 480) - ModeIndex = ModeIndex_856x480[Depth]; - break; - case 960: - if (VDisplay == 540) - ModeIndex = ModeIndex_960x540[Depth]; - else if (VDisplay == 600) - ModeIndex = ModeIndex_960x600[Depth]; - break; - case 1024: - if (VDisplay == 576) - ModeIndex = ModeIndex_1024x576[Depth]; - else if (VDisplay == 768) - ModeIndex = ModeIndex_1024x768[Depth]; - break; - case 1152: - if (VDisplay == 864) - ModeIndex = ModeIndex_1152x864[Depth]; - break; - case 1280: - switch (VDisplay) { - case 720: - ModeIndex = ModeIndex_1280x720[Depth]; - break; - case 768: - ModeIndex = ModeIndex_1280x768[Depth]; - break; - case 1024: - ModeIndex = ModeIndex_1280x1024[Depth]; - break; - } - } - - return ModeIndex; -} -#endif /* 0 */ - /*********************************************/ /* HELPER: SetReg, GetReg */ /*********************************************/ From 2acbd647315017c07537287857ea2db36c70eacf Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:27 -0400 Subject: [PATCH 2664/2804] USB: SisUSB2VGA: Mis-spelled word Trivial fix Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index dc0473921e3d..7183e762fead 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -44,7 +44,7 @@ #include /* For older kernels, support for text consoles is by default - * off. To ensable text console support, change the following: + * off. To enable text console support, change the following: */ /* #define CONFIG_USB_SISUSBVGA_CON */ From 1c1772a2609a16b3b590f8390a337dbe25859118 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:29 -0400 Subject: [PATCH 2665/2804] USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.h | 118 ++++++++++++++-------------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 7183e762fead..d2d7872cd022 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -8,27 +8,27 @@ * * Otherwise, the following license terms apply: * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) 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. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1) Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2) 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. + * 3) The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Author: Thomas Winischhofer * @@ -72,7 +72,7 @@ #define SISUSB_IBUF_SIZE 0x01000 #define SISUSB_OBUF_SIZE 0x10000 /* fixed */ -#define NUMOBUFS 8 /* max number of output buffers/output URBs */ +#define NUMOBUFS 8 /* max number of output buffers/output URBs */ /* About endianness: * @@ -103,7 +103,7 @@ struct sisusb_usb_data; -struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ +struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ struct sisusb_usb_data *sisusb; int urbindex; int *actual_length; @@ -114,16 +114,16 @@ struct sisusb_usb_data { struct usb_interface *interface; struct kref kref; wait_queue_head_t wait_q; /* for syncind and timeouts */ - struct mutex lock; /* general race avoidance */ - unsigned int ifnum; /* interface number of the USB device */ - int minor; /* minor (for logging clarity) */ - int isopen; /* !=0 if open */ - int present; /* !=0 if device is present on the bus */ - int ready; /* !=0 if device is ready for userland */ + struct mutex lock; /* general race avoidance */ + unsigned int ifnum; /* interface number of the USB device */ + int minor; /* minor (for logging clarity) */ + int isopen; /* !=0 if open */ + int present; /* !=0 if device is present on the bus */ + int ready; /* !=0 if device is ready for userland */ #ifdef SISUSB_OLD_CONFIG_COMPAT int ioctl32registered; #endif - int numobufs; /* number of obufs = number of out urbs */ + int numobufs; /* number of obufs = number of out urbs */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ int obufsize, ibufsize; dma_addr_t transfer_dma_out[NUMOBUFS]; @@ -134,13 +134,13 @@ struct sisusb_usb_data { unsigned char completein; struct sisusb_urb_context urbout_context[NUMOBUFS]; unsigned long flagb0; - unsigned long vrambase; /* framebuffer base */ - unsigned int vramsize; /* framebuffer size (bytes) */ + unsigned long vrambase; /* framebuffer base */ + unsigned int vramsize; /* framebuffer size (bytes) */ unsigned long mmiobase; unsigned int mmiosize; unsigned long ioportbase; - unsigned char devinit; /* device initialized? */ - unsigned char gfxinit; /* graphics core initialized? */ + unsigned char devinit; /* device initialized? */ + unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; #ifdef INCL_SISUSB_CON @@ -150,7 +150,7 @@ struct sisusb_usb_data { int haveconsole, con_first, con_last; int havethisconsole[MAX_NR_CONSOLES]; int textmodedestroyed; - unsigned int sisusb_num_columns; /* real number, not vt's idea */ + unsigned int sisusb_num_columns; /* real number, not vt's idea */ int cur_start_addr, con_rolled_over; int sisusb_cursor_loc, bad_cursor_pos; int sisusb_cursor_size_from; @@ -195,7 +195,7 @@ struct sisusb_packet { unsigned short header; u32 address; u32 data; -} __attribute__((__packed__)); +} __attribute__ ((__packed__)); #define CLEARPACKET(packet) memset(packet, 0, 10) @@ -263,36 +263,36 @@ struct sisusb_packet { /* Structure argument for SISUSB_GET_INFO ioctl */ struct sisusb_info { - __u32 sisusb_id; /* for identifying sisusb */ -#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ - __u8 sisusb_version; - __u8 sisusb_revision; - __u8 sisusb_patchlevel; - __u8 sisusb_gfxinit; /* graphics core initialized? */ + __u32 sisusb_id; /* for identifying sisusb */ +#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ + __u8 sisusb_version; + __u8 sisusb_revision; + __u8 sisusb_patchlevel; + __u8 sisusb_gfxinit; /* graphics core initialized? */ - __u32 sisusb_vrambase; - __u32 sisusb_mmiobase; - __u32 sisusb_iobase; - __u32 sisusb_pcibase; + __u32 sisusb_vrambase; + __u32 sisusb_mmiobase; + __u32 sisusb_iobase; + __u32 sisusb_pcibase; - __u32 sisusb_vramsize; /* framebuffer size in bytes */ + __u32 sisusb_vramsize; /* framebuffer size in bytes */ - __u32 sisusb_minor; + __u32 sisusb_minor; - __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ + __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ - __u32 sisusb_conactive; /* != 0 if console driver active */ + __u32 sisusb_conactive; /* != 0 if console driver active */ - __u8 sisusb_reserved[28]; /* for future use */ + __u8 sisusb_reserved[28]; /* for future use */ }; struct sisusb_command { - __u8 operation; /* see below */ - __u8 data0; /* operation dependent */ - __u8 data1; /* operation dependent */ - __u8 data2; /* operation dependent */ - __u32 data3; /* operation dependent */ - __u32 data4; /* for future use */ + __u8 operation; /* see below */ + __u8 data0; /* operation dependent */ + __u8 data1; /* operation dependent */ + __u8 data2; /* operation dependent */ + __u32 data3; /* operation dependent */ + __u32 data4; /* for future use */ }; #define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ @@ -304,7 +304,7 @@ struct sisusb_command { #define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ -#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ +#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ #define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */ #define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */ @@ -313,6 +313,4 @@ struct sisusb_command { #define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) #define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) - #endif /* SISUSB_H */ - From 22b2c526e70741ce8a244cab339fe0f56ace8cb6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:31 -0400 Subject: [PATCH 2666/2804] USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_init.c Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_init.c | 262 ++++++++++++----------- 1 file changed, 133 insertions(+), 129 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 5d8358295e71..273de5d0934e 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -55,18 +55,17 @@ /* POINTER INITIALIZATION */ /*********************************************/ -static void -SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) +static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) { - SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; - SiS_Pr->SiS_StandTable = SiSUSB_StandTable; + SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; + SiS_Pr->SiS_StandTable = SiSUSB_StandTable; - SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; - SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; - SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; - SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; + SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; + SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; - SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; + SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; } /*********************************************/ @@ -75,21 +74,20 @@ SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) static void SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short data) + unsigned short index, unsigned short data) { sisusb_setidxreg(SiS_Pr->sisusb, port, index, data); } static void SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short data) + unsigned short data) { sisusb_setreg(SiS_Pr->sisusb, port, data); } static unsigned char -SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index) +SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index) { u8 data; @@ -110,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port) static void SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND, - unsigned short DataOR) + unsigned short index, unsigned short DataAND, + unsigned short DataOR) { sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR); } static void SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND) + unsigned short index, unsigned short DataAND) { sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND); } static void -SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, - unsigned short index, unsigned short DataOR) +SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index, unsigned short DataOR) { sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR); } @@ -134,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, /* HELPER: DisplayOn, DisplayOff */ /*********************************************/ -static void -SiS_DisplayOn(struct SiS_Private *SiS_Pr) +static void SiS_DisplayOn(struct SiS_Private *SiS_Pr) { SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF); } @@ -144,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr) /* HELPER: Init Port Addresses */ /*********************************************/ -static void -SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) +static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) { SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; @@ -168,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) /* HELPER: GetSysFlags */ /*********************************************/ -static void -SiS_GetSysFlags(struct SiS_Private *SiS_Pr) +static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr) { SiS_Pr->SiS_MyCR63 = 0x63; } @@ -178,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr) /* HELPER: Init PCI & Engines */ /*********************************************/ -static void -SiSInitPCIetc(struct SiS_Private *SiS_Pr) +static void SiSInitPCIetc(struct SiS_Private *SiS_Pr) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1); /* - Enable 2D (0x40) @@ -195,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr) /* HELPER: SET SEGMENT REGISTERS */ /*********************************************/ -static void -SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -209,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -223,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) { SiS_SetSegRegLower(SiS_Pr, value); SiS_SetSegRegUpper(SiS_Pr, value); } -static void -SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) { SiS_SetSegmentReg(SiS_Pr, 0); } @@ -247,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetSegmentReg(SiS_Pr, value); } -static void -SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) { SiS_SetSegmentRegOver(SiS_Pr, 0); } -static void -SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) { SiS_ResetSegmentReg(SiS_Pr); SiS_ResetSegmentRegOver(SiS_Pr); @@ -266,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) static int SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, - unsigned short *ModeIdIndex) + unsigned short *ModeIdIndex) { if ((*ModeNo) <= 0x13) { @@ -277,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, } else { - for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { + for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + (*ModeNo)) break; - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + 0xFF) return 0; } @@ -295,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, /* HELPER: ENABLE CRT1 */ /*********************************************/ -static void -SiS_HandleCRT1(struct SiS_Private *SiS_Pr) +static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr) { /* Enable CRT1 gating */ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf); @@ -308,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr) static unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { - static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; + static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; unsigned short modeflag; short index; @@ -321,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } index = (modeflag & ModeTypeMask) - ModeEGA; - if (index < 0) index = 0; + if (index < 0) + index = 0; return ColorDepth[index]; } @@ -331,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short xres, temp, colordepth, infoflag; @@ -368,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata); - for(i = 2; i <= 4; i++) { - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; + for (i = 2; i <= 4; i++) { + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata); } } @@ -398,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); - for(i = 0; i <= 0x18; i++) { + for (i = 0; i <= 0x18; i++) { CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata); } @@ -414,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char ARdata; unsigned short i; - for(i = 0; i <= 0x13; i++) { + for (i = 0; i <= 0x13; i++) { ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i); @@ -439,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char GRdata; unsigned short i; - for(i = 0; i <= 0x08; i++) { + for (i = 0; i <= 0x08; i++) { GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata); } @@ -454,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) /* CLEAR EXTENDED REGISTERS */ /*********************************************/ -static void -SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { int i; - for(i = 0x0A; i <= 0x0E; i++) { + for (i = 0x0A; i <= 0x0E; i++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00); } @@ -472,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) static unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short rrti, i, index, temp; if (ModeNo <= 0x13) return 0xFFFF; - index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F; - if (index > 0) index--; + index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F; + if (index > 0) + index--; rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID; @@ -490,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo) break; - temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; + temp = + SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; if (temp < SiS_Pr->SiS_ModeType) break; i++; index--; - } while(index != 0xFFFF); + } while (index != 0xFFFF); i--; @@ -507,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SYNC */ /*********************************************/ -static void -SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) +static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) { unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8; sync &= 0xC0; @@ -522,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) static void SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { - unsigned char index; + unsigned char index; unsigned short temp, i, j, modeflag; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC; - for(i = 0,j = 0; i <= 7; i++, j++) { + for (i = 0, j = 0; i <= 7; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x10; i <= 10; i++, j++) { + for (j = 0x10; i <= 10; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x15; i <= 12; i++, j++) { + for (j = 0x15; i <= 12; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x0A; i <= 15; i++, j++) { + for (j = 0x0A; i <= 15; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp); temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; - if (modeflag & DoubleScanMode) temp |= 0x80; + if (modeflag & DoubleScanMode) + temp |= 0x80; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp); if (SiS_Pr->SiS_ModeType > ModeVGA) @@ -569,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti); - unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; + unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; unsigned short temp; temp = (du >> 8) & 0x0f; @@ -580,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF)); - if (infoflag & InterlaceMode) du >>= 1; + if (infoflag & InterlaceMode) + du >>= 1; du <<= 5; temp = (du >> 8) & 0xff; - if (du & 0xff) temp++; + if (du & 0xff) + temp++; temp++; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp); } @@ -595,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B; unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01); } /*********************************************/ @@ -614,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short mi) + unsigned short mi) { unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; @@ -639,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short data = 0, VCLK = 0, index = 0; @@ -648,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; } - if (VCLK >= 166) data |= 0x0c; + if (VCLK >= 166) + data |= 0x0c; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data); if (VCLK >= 166) @@ -668,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short data, infoflag = 0, modeflag; @@ -688,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, data |= 0x02; data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); } - if (infoflag & InterlaceMode) data |= 0x20; + if (infoflag & InterlaceMode) + data |= 0x20; } SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data); data = 0; if (infoflag & InterlaceMode) { /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ - unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3; - unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5; + unsigned short hrs = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) + - 3; + unsigned short hto = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + + 5; data = hrs - (hto >> 1) + 3; } SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF)); @@ -739,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, - unsigned short shiftflag, unsigned short dl, unsigned short ah, - unsigned short al, unsigned short dh) + unsigned short shiftflag, unsigned short dl, unsigned short ah, + unsigned short al, unsigned short dh) { unsigned short d1, d2, d3; switch (dl) { - case 0: - d1 = dh; d2 = ah; d3 = al; - break; - case 1: - d1 = ah; d2 = al; d3 = dh; - break; - default: - d1 = al; d2 = dh; d3 = ah; + case 0: + d1 = dh; + d2 = ah; + d3 = al; + break; + case 1: + d1 = ah; + d2 = al; + d3 = dh; + break; + default: + d1 = al; + d2 = dh; + d3 = ah; } SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag)); SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag)); @@ -760,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, } static void -SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi) +SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short mi) { unsigned short data, data2, time, i, j, k, m, n, o; unsigned short si, di, bx, sf; @@ -794,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi SiS_SetRegByte(SiS_Pr, DACAddr, 0x00); - for(i = 0; i < j; i++) { + for (i = 0; i < j; i++) { data = table[i]; - for(k = 0; k < 3; k++) { + for (k = 0; k < 3; k++) { data2 = 0; - if (data & 0x01) data2 += 0x2A; - if (data & 0x02) data2 += 0x15; + if (data & 0x01) + data2 += 0x2A; + if (data & 0x02) + data2 += 0x15; SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf)); data >>= 2; } } if (time == 256) { - for(i = 16; i < 32; i++) { + for (i = 16; i < 32; i++) { data = table[i] << sf; - for(k = 0; k < 3; k++) + for (k = 0; k < 3; k++) SiS_SetRegByte(SiS_Pr, DACData, data); } si = 32; - for(m = 0; m < 9; m++) { + for (m = 0; m < 9; m++) { di = si; bx = si + 4; - for(n = 0; n < 3; n++) { - for(o = 0; o < 5; o++) { + for (n = 0; n < 3; n++) { + for (o = 0; o < 5; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[bx], table[si]); + table[di], table[bx], + table[si]); si++; } si -= 2; - for(o = 0; o < 3; o++) { + for (o = 0; o < 3; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[si], table[bx]); + table[di], table[si], + table[bx]); si--; } } - si += 5; + si += 5; } } } @@ -839,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi static void SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short StandTableIndex, rrti; @@ -880,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SiSSetMode() */ /*********************************************/ -int -SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { unsigned short ModeIdIndex; - unsigned long BaseAddr = SiS_Pr->IOAddress; + unsigned long BaseAddr = SiS_Pr->IOAddress; SiSUSB_InitPtr(SiS_Pr); SiSUSBRegInit(SiS_Pr, BaseAddr); @@ -900,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) ModeNo &= 0x7f; SiS_Pr->SiS_ModeType = - SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; + SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; SiS_Pr->SiS_SetFlag = LowModeTests; @@ -918,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) return 1; } -int -SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) { unsigned short ModeNo = 0; int i; @@ -951,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) } #endif /* INCL_SISUSB_CON */ - - - - From 7c59901421e22cff3fa9b8ea83e7a2fe37951497 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:32 -0400 Subject: [PATCH 2667/2804] USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_init.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_init.h | 1311 +++++++++++----------- 1 file changed, 655 insertions(+), 656 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index d47301eaca7a..c46ce42d4489 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -76,21 +76,21 @@ #define CRT2Mode 0x0800 #define HalfDCLK 0x1000 #define NoSupportSimuTV 0x2000 -#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ +#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ #define DoubleScanMode 0x8000 /* Infoflag */ #define SupportTV 0x0008 #define SupportTV1024 0x0800 #define SupportCHTV 0x0800 -#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ +#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 #define SupportYPbPr750p 0x1000 #define SupportLCD 0x0020 #define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ -#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ -#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ -#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ +#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ +#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ +#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ #define InterlaceMode 0x0080 #define SyncPP 0x0000 #define SyncPN 0x4000 @@ -129,7 +129,7 @@ #define SIS_RI_856x480 19 #define SIS_RI_1280x768 20 #define SIS_RI_1400x1050 21 -#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ +#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ #define SIS_RI_848x480 23 #define SIS_RI_1360x768 24 #define SIS_RI_1024x600 25 @@ -147,691 +147,691 @@ #define SIS_CRT2_PORT_04 0x04 - 0x30 /* Mode numbers */ -static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; -static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; -static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; -static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; -static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; -static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; -static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; -static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; -static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; -static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; -static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; -static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; -static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; -static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; -static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; -static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; -static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; -static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; -static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; -static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25}; -static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; +static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f }; +static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 }; +static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 }; +static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c }; +static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e }; +static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 }; +static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 }; +static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 }; +static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 }; +static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 }; +static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 }; +static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e }; +static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 }; +static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f }; +static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 }; +static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 }; +static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 }; +static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b }; +static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 }; +static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 }; +static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 }; -static const unsigned char SiS_MDA_DAC[] = -{ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +static const unsigned char SiS_MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F }; -static const unsigned char SiS_CGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_EGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, - 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, - 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, - 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, - 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, - 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, - 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, + 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, + 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, + 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, + 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, + 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, + 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_VGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, - 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, - 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, - 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, - 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, - 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, - 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, - 0x0B,0x0C,0x0D,0x0F,0x10 +static const unsigned char SiS_VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, + 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, + 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, + 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, + 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, + 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, + 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, + 0x0B, 0x0C, 0x0D, 0x0F, 0x10 }; -static const struct SiS_St SiSUSB_SModeIDTable[] = -{ - {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40}, - {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +static const struct SiS_St SiSUSB_SModeIDTable[] = { + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; -static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = -{ - { 640,400}, - { 640,350}, - { 720,400}, - { 720,350}, - { 640,480} +static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} }; -static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = -{ - { 320, 200, 8, 8}, /* 0x00 */ - { 320, 240, 8, 8}, /* 0x01 */ - { 320, 400, 8, 8}, /* 0x02 */ - { 400, 300, 8, 8}, /* 0x03 */ - { 512, 384, 8, 8}, /* 0x04 */ - { 640, 400, 8,16}, /* 0x05 */ - { 640, 480, 8,16}, /* 0x06 */ - { 800, 600, 8,16}, /* 0x07 */ - { 1024, 768, 8,16}, /* 0x08 */ - { 1280,1024, 8,16}, /* 0x09 */ - { 1600,1200, 8,16}, /* 0x0a */ - { 1920,1440, 8,16}, /* 0x0b */ - { 2048,1536, 8,16}, /* 0x0c */ - { 720, 480, 8,16}, /* 0x0d */ - { 720, 576, 8,16}, /* 0x0e */ - { 1280, 960, 8,16}, /* 0x0f */ - { 800, 480, 8,16}, /* 0x10 */ - { 1024, 576, 8,16}, /* 0x11 */ - { 1280, 720, 8,16}, /* 0x12 */ - { 856, 480, 8,16}, /* 0x13 */ - { 1280, 768, 8,16}, /* 0x14 */ - { 1400,1050, 8,16}, /* 0x15 */ - { 1152, 864, 8,16}, /* 0x16 */ - { 848, 480, 8,16}, /* 0x17 */ - { 1360, 768, 8,16}, /* 0x18 */ - { 1024, 600, 8,16}, /* 0x19 */ - { 1152, 768, 8,16}, /* 0x1a */ - { 768, 576, 8,16}, /* 0x1b */ - { 1360,1024, 8,16}, /* 0x1c */ - { 1680,1050, 8,16}, /* 0x1d */ - { 1280, 800, 8,16}, /* 0x1e */ - { 1920,1080, 8,16}, /* 0x1f */ - { 960, 540, 8,16}, /* 0x20 */ - { 960, 600, 8,16} /* 0x21 */ +static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = { + {320, 200, 8, 8}, /* 0x00 */ + {320, 240, 8, 8}, /* 0x01 */ + {320, 400, 8, 8}, /* 0x02 */ + {400, 300, 8, 8}, /* 0x03 */ + {512, 384, 8, 8}, /* 0x04 */ + {640, 400, 8, 16}, /* 0x05 */ + {640, 480, 8, 16}, /* 0x06 */ + {800, 600, 8, 16}, /* 0x07 */ + {1024, 768, 8, 16}, /* 0x08 */ + {1280, 1024, 8, 16}, /* 0x09 */ + {1600, 1200, 8, 16}, /* 0x0a */ + {1920, 1440, 8, 16}, /* 0x0b */ + {2048, 1536, 8, 16}, /* 0x0c */ + {720, 480, 8, 16}, /* 0x0d */ + {720, 576, 8, 16}, /* 0x0e */ + {1280, 960, 8, 16}, /* 0x0f */ + {800, 480, 8, 16}, /* 0x10 */ + {1024, 576, 8, 16}, /* 0x11 */ + {1280, 720, 8, 16}, /* 0x12 */ + {856, 480, 8, 16}, /* 0x13 */ + {1280, 768, 8, 16}, /* 0x14 */ + {1400, 1050, 8, 16}, /* 0x15 */ + {1152, 864, 8, 16}, /* 0x16 */ + {848, 480, 8, 16}, /* 0x17 */ + {1360, 768, 8, 16}, /* 0x18 */ + {1024, 600, 8, 16}, /* 0x19 */ + {1152, 768, 8, 16}, /* 0x1a */ + {768, 576, 8, 16}, /* 0x1b */ + {1360, 1024, 8, 16}, /* 0x1c */ + {1680, 1050, 8, 16}, /* 0x1d */ + {1280, 800, 8, 16}, /* 0x1e */ + {1920, 1080, 8, 16}, /* 0x1f */ + {960, 540, 8, 16}, /* 0x20 */ + {960, 600, 8, 16} /* 0x21 */ }; -static const struct SiS_StandTable SiSUSB_StandTable[] = -{ +static const struct SiS_StandTable SiSUSB_StandTable[] = { /* MD_3_400 - mode 0x03 - 400 */ { - 0x50,0x18,0x10,0x1000, - { 0x00,0x03,0x00,0x02 }, - 0x67, - { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, - 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x0c,0x00,0x0f,0x08 }, - { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff } - }, + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff} + }, /* Generic for VGA and higher */ { - 0x00,0x00,0x00,0x0000, - { 0x01,0x0f,0x00,0x0e }, - 0x23, - { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, - 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x01,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff } - } + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff} + } }; -static const struct SiS_Ext SiSUSB_EModeIDTable[] = -{ - {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ - {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ - {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ - {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ - {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ - {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ - {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ - {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */ - {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */ - {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */ - {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */ - {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */ - {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */ - {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */ - {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */ - {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */ - {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */ - {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */ - {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */ - {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */ - {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */ - {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */ - {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */ - {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */ - {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */ - {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */ - {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */ - {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */ - {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */ - {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */ - {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */ - {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */ - {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */ - {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */ - {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */ - {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */ - {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */ - {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */ - {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */ - {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */ - {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */ - {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */ - {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */ - {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */ - {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */ - {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */ - {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */ - {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */ - {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */ - {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */ - {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */ - {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} +static const struct SiS_Ext SiSUSB_EModeIDTable[] = { + {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */ + {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */ + {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */ + {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */ + {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */ + {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */ + {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */ + {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */ + {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */ + {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */ + {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */ + {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */ + {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */ + {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */ + {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */ + {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */ + {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */ + {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */ + {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */ + {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */ + {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */ + {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */ + {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */ + {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */ + {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */ + {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */ + {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */ + {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */ + {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */ + {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */ + {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */ + {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */ + {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */ + {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */ + {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */ + {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */ + {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */ + {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */ + {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */ + {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */ + {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */ + {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */ + {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */ + {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */ + {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */ + {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */ + {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */ + {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */ + {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */ + {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */ + {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */ + {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1} }; -static const struct SiS_Ext2 SiSUSB_RefIndex[] = -{ - {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ - {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ - {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ - {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ - {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ - {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ - {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ - {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ - {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ - {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ - {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ - {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ - {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ - {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ - {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ - {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ - {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ - {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ - {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ - {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ - {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ - {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ - {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ - {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ - {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ - {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ - {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ - {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ - {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ - {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ - {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ - {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ - {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ - {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ - {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ - {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ - {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ - {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ - {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ - {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ - {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ - {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ - {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ - {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ - {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ - {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ - {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ - {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */ - {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */ - {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */ - {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */ - {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ - {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ - {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ - {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00} +static const struct SiS_Ext2 SiSUSB_RefIndex[] = { + {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ + {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ + {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ + {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ + {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ + {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ + {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ + {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ + {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ + {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ + {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ + {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ + {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ + {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ + {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ + {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ + {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ + {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ + {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ + {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ + {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ + {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ + {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ + {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ + {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ + {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ + {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ + {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ + {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ + {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ + {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ + {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ + {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ + {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ + {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ + {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ + {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ + {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ + {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */ + {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ + {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ + {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00} }; -static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = -{ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, /* 0x0 */ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x1 */ - {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, - 0x01}}, /* 0x2 */ - {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, - 0x01}}, /* 0x3 */ - {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, /* 0x4 */ - {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, - 0x00}}, /* 0x5 */ - {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, - 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, - 0x00}}, /* 0x6 */ - {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, - 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, - 0x00}}, /* 0x7 */ - {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x00}}, /* 0x8 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x61}}, /* 0x9 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, - 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, - 0x61}}, /* 0xa */ - {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, - 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, - 0x61}}, /* 0xb */ - {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, - 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, - 0x00}}, /* 0xc */ - {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, - 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0xd */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, - 0x01}}, /* 0xe */ - {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, - 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, - 0x01}}, /* 0xf */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, - 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, - 0x01}}, /* 0x10 */ - {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, - 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, - 0x01}}, /* 0x11 */ - {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, - 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, - 0x61}}, /* 0x12 */ - {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, - 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, - 0x61}}, /* 0x13 */ - {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, - 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, - 0x61}}, /* 0x14 */ - {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, - 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, - 0x00}}, /* 0x15 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x16 */ - {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x17 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, - 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, - 0x01}}, /* 0x18 */ - {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, - 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, - 0x01}}, /* 0x19 */ - {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, - 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, - 0x62}}, /* 0x1a */ - {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, - 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, - 0x62}}, /* 0x1b */ - {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, - 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, - 0x00}}, /* 0x1c */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1d */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1e */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, - 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, - 0x01}}, /* 0x1f */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x20 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x21 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x22 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x23 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x24 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x25 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x26 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x27 */ - {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, - 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, - 0x63}}, /* 0x28 */ - {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, - 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, - 0x63}}, /* 0x29 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2a */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2b */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2c */ - {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, - 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, - 0x44}}, /* 0x2d */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, - 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, - 0x44}}, /* 0x2e */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, - 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, - 0x44}}, /* 0x2f */ - {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, - 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, - 0x44}}, /* 0x30 */ - {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, - 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, - 0x00}}, /* 0x31 */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, - 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, - 0x01}}, /* 0x32 */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, - 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, - 0x01}}, /* 0x33 */ - {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, - 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, - 0x01}}, /* 0x34 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, - 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, - 0x01}}, /* 0x35 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, - 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x36 */ - {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, - 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, - 0x01}}, /* 0x37 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x38 */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x39 */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, - 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, - 0x01}}, /* 0x3a */ - {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, - 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, - 0x01}}, /* 0x3b */ - {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, /* 0x3c */ - {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, /* 0x3d */ - {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, - 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, - 0x00}}, /* 0x3e */ - {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, - 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x3f */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, - 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x40 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x41 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, - 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, - 0x01}}, /* 0x42 */ - {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, - 0x00}}, /* 0x43 */ - {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, - 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, - 0x01}}, /* 0x44 */ - {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x45 */ - {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, - 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, - 0x00}}, /* 0x46 */ - {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x47 */ - {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, - 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x48 */ - {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, - 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, - 0x01}}, /* 0x49 */ - {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, - 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, - 0x01}}, /* 0x4a */ - {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, - 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, - 0x00}}, /* 0x4b */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, - 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, - 0x01}}, /* 0x4c */ - {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x4e */ - {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, - 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, - 0x21}}, /* 0x4f */ - {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, - 0x20}}, /* 0x50 */ - {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, - 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00, - 0x61}}, /* 0x51 */ - {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, - 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02, - 0x41}}, /* 0x52 */ - {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, - 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02, - 0x01}}, /* 0x53 */ - {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, - 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, - 0x41}} /* 0x54 */ +static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}}, /* 0x0 */ + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x1 */ + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, /* 0x2 */ + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, /* 0x3 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, /* 0x4 */ + {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05, + 0x00}}, /* 0x5 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01, + 0x00}}, /* 0x6 */ + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, /* 0x7 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, /* 0x8 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x61}}, /* 0x9 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}}, /* 0xa */ + {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05, + 0x61}}, /* 0xb */ + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, + 0x00}}, /* 0xc */ + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, /* 0xd */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, /* 0xe */ + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, /* 0xf */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, /* 0x10 */ + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, /* 0x11 */ + {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}}, /* 0x12 */ + {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}}, /* 0x13 */ + {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}}, /* 0x14 */ + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, /* 0x15 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x16 */ + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x17 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, /* 0x18 */ + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, /* 0x19 */ + {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1a */ + {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1b */ + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, /* 0x1c */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1d */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1e */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1f */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x20 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x21 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x22 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x23 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x24 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x25 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x26 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x27 */ + {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x28 */ + {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x29 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2a */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2b */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2c */ + {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2d */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2e */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2f */ + {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x30 */ + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, /* 0x31 */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, /* 0x32 */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, /* 0x33 */ + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, /* 0x34 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, /* 0x35 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x36 */ + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, /* 0x37 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x38 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x39 */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, /* 0x3a */ + {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, /* 0x3b */ + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x3c */ + {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, /* 0x3d */ + {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, + 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, + 0x00}}, /* 0x3e */ + {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, + 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x3f */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1, + 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x40 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x41 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5, + 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07, + 0x01}}, /* 0x42 */ + {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03, + 0x00}}, /* 0x43 */ + {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef, + 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07, + 0x01}}, /* 0x44 */ + {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x45 */ + {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E, + 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06, + 0x00}}, /* 0x46 */ + {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x47 */ + {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E, + 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x48 */ + {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd, + 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03, + 0x01}}, /* 0x49 */ + {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff, + 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03, + 0x01}}, /* 0x4a */ + {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10, + 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03, + 0x00}}, /* 0x4b */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07, + 0x01}}, /* 0x4c */ + {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x4e */ + {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff, + 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07, + 0x21}}, /* 0x4f */ + {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c, + 0x20}}, /* 0x50 */ + {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0, + 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00, + 0x61}}, /* 0x51 */ + {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0, + 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02, + 0x41}}, /* 0x52 */ + {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0, + 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02, + 0x01}}, /* 0x53 */ + {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff, + 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07, + 0x41}} /* 0x54 */ }; -static const struct SiS_VCLKData SiSUSB_VCLKData[] = -{ - { 0x1b,0xe1, 25}, /* 0x00 */ - { 0x4e,0xe4, 28}, /* 0x01 */ - { 0x57,0xe4, 31}, /* 0x02 */ - { 0xc3,0xc8, 36}, /* 0x03 */ - { 0x42,0xe2, 40}, /* 0x04 */ - { 0xfe,0xcd, 43}, /* 0x05 */ - { 0x5d,0xc4, 44}, /* 0x06 */ - { 0x52,0xe2, 49}, /* 0x07 */ - { 0x53,0xe2, 50}, /* 0x08 */ - { 0x74,0x67, 52}, /* 0x09 */ - { 0x6d,0x66, 56}, /* 0x0a */ - { 0x5a,0x64, 65}, /* 0x0b */ - { 0x46,0x44, 67}, /* 0x0c */ - { 0xb1,0x46, 68}, /* 0x0d */ - { 0xd3,0x4a, 72}, /* 0x0e */ - { 0x29,0x61, 75}, /* 0x0f */ - { 0x6e,0x46, 76}, /* 0x10 */ - { 0x2b,0x61, 78}, /* 0x11 */ - { 0x31,0x42, 79}, /* 0x12 */ - { 0xab,0x44, 83}, /* 0x13 */ - { 0x46,0x25, 84}, /* 0x14 */ - { 0x78,0x29, 86}, /* 0x15 */ - { 0x62,0x44, 94}, /* 0x16 */ - { 0x2b,0x41,104}, /* 0x17 */ - { 0x3a,0x23,105}, /* 0x18 */ - { 0x70,0x44,108}, /* 0x19 */ - { 0x3c,0x23,109}, /* 0x1a */ - { 0x5e,0x43,113}, /* 0x1b */ - { 0xbc,0x44,116}, /* 0x1c */ - { 0xe0,0x46,132}, /* 0x1d */ - { 0x54,0x42,135}, /* 0x1e */ - { 0xea,0x2a,139}, /* 0x1f */ - { 0x41,0x22,157}, /* 0x20 */ - { 0x70,0x24,162}, /* 0x21 */ - { 0x30,0x21,175}, /* 0x22 */ - { 0x4e,0x22,189}, /* 0x23 */ - { 0xde,0x26,194}, /* 0x24 */ - { 0x62,0x06,202}, /* 0x25 */ - { 0x3f,0x03,229}, /* 0x26 */ - { 0xb8,0x06,234}, /* 0x27 */ - { 0x34,0x02,253}, /* 0x28 */ - { 0x58,0x04,255}, /* 0x29 */ - { 0x24,0x01,265}, /* 0x2a */ - { 0x9b,0x02,267}, /* 0x2b */ - { 0x70,0x05,270}, /* 0x2c */ - { 0x25,0x01,272}, /* 0x2d */ - { 0x9c,0x02,277}, /* 0x2e */ - { 0x27,0x01,286}, /* 0x2f */ - { 0x3c,0x02,291}, /* 0x30 */ - { 0xef,0x0a,292}, /* 0x31 */ - { 0xf6,0x0a,310}, /* 0x32 */ - { 0x95,0x01,315}, /* 0x33 */ - { 0xf0,0x09,324}, /* 0x34 */ - { 0xfe,0x0a,331}, /* 0x35 */ - { 0xf3,0x09,332}, /* 0x36 */ - { 0xea,0x08,340}, /* 0x37 */ - { 0xe8,0x07,376}, /* 0x38 */ - { 0xde,0x06,389}, /* 0x39 */ - { 0x52,0x2a, 54}, /* 0x3a 301 TV */ - { 0x52,0x6a, 27}, /* 0x3b 301 TV */ - { 0x62,0x24, 70}, /* 0x3c 301 TV */ - { 0x62,0x64, 70}, /* 0x3d 301 TV */ - { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ - { 0x20,0x26, 33}, /* 0x3f 301 TV */ - { 0x31,0xc2, 39}, /* 0x40 */ - { 0x60,0x36, 30}, /* 0x41 Chrontel */ - { 0x40,0x4a, 28}, /* 0x42 Chrontel */ - { 0x9f,0x46, 44}, /* 0x43 Chrontel */ - { 0x97,0x2c, 26}, /* 0x44 */ - { 0x44,0xe4, 25}, /* 0x45 Chrontel */ - { 0x7e,0x32, 47}, /* 0x46 Chrontel */ - { 0x8a,0x24, 31}, /* 0x47 Chrontel */ - { 0x97,0x2c, 26}, /* 0x48 Chrontel */ - { 0xce,0x3c, 39}, /* 0x49 */ - { 0x52,0x4a, 36}, /* 0x4a Chrontel */ - { 0x34,0x61, 95}, /* 0x4b */ - { 0x78,0x27,108}, /* 0x4c - was 102 */ - { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ - { 0x41,0x4e, 21}, /* 0x4e */ - { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ - { 0x19,0x42, 42}, /* 0x50 */ - { 0x54,0x46, 58}, /* 0x51 Chrontel */ - { 0x25,0x42, 61}, /* 0x52 */ - { 0x44,0x44, 66}, /* 0x53 Chrontel */ - { 0x3a,0x62, 70}, /* 0x54 Chrontel */ - { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ - { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ - { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ - { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ - { 0x52,0x07,149}, /* 0x59 1280x960-85 */ - { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ - { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ - { 0x45,0x25, 83}, /* 0x5c 1280x800 */ - { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ - { 0x70,0x24,162}, /* 0x5e 1600x1200 */ - { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ - { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ - { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ - { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ - { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ - { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ - { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ - { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ - { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ - { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ - { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ - { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ - { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ - { 0x45,0x25, 83}, /* 0x6c 1280x800 */ - { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ - { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ - { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ - { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ - { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ +static const struct SiS_VCLKData SiSUSB_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x00 */ + {0x4e, 0xe4, 28}, /* 0x01 */ + {0x57, 0xe4, 31}, /* 0x02 */ + {0xc3, 0xc8, 36}, /* 0x03 */ + {0x42, 0xe2, 40}, /* 0x04 */ + {0xfe, 0xcd, 43}, /* 0x05 */ + {0x5d, 0xc4, 44}, /* 0x06 */ + {0x52, 0xe2, 49}, /* 0x07 */ + {0x53, 0xe2, 50}, /* 0x08 */ + {0x74, 0x67, 52}, /* 0x09 */ + {0x6d, 0x66, 56}, /* 0x0a */ + {0x5a, 0x64, 65}, /* 0x0b */ + {0x46, 0x44, 67}, /* 0x0c */ + {0xb1, 0x46, 68}, /* 0x0d */ + {0xd3, 0x4a, 72}, /* 0x0e */ + {0x29, 0x61, 75}, /* 0x0f */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a 301 TV */ + {0x52, 0x6a, 27}, /* 0x3b 301 TV */ + {0x62, 0x24, 70}, /* 0x3c 301 TV */ + {0x62, 0x64, 70}, /* 0x3d 301 TV */ + {0xa8, 0x4c, 30}, /* 0x3e 301 TV */ + {0x20, 0x26, 33}, /* 0x3f 301 TV */ + {0x31, 0xc2, 39}, /* 0x40 */ + {0x60, 0x36, 30}, /* 0x41 Chrontel */ + {0x40, 0x4a, 28}, /* 0x42 Chrontel */ + {0x9f, 0x46, 44}, /* 0x43 Chrontel */ + {0x97, 0x2c, 26}, /* 0x44 */ + {0x44, 0xe4, 25}, /* 0x45 Chrontel */ + {0x7e, 0x32, 47}, /* 0x46 Chrontel */ + {0x8a, 0x24, 31}, /* 0x47 Chrontel */ + {0x97, 0x2c, 26}, /* 0x48 Chrontel */ + {0xce, 0x3c, 39}, /* 0x49 */ + {0x52, 0x4a, 36}, /* 0x4a Chrontel */ + {0x34, 0x61, 95}, /* 0x4b */ + {0x78, 0x27, 108}, /* 0x4c - was 102 */ + {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + {0x41, 0x4e, 21}, /* 0x4e */ + {0xa1, 0x4a, 29}, /* 0x4f Chrontel */ + {0x19, 0x42, 42}, /* 0x50 */ + {0x54, 0x46, 58}, /* 0x51 Chrontel */ + {0x25, 0x42, 61}, /* 0x52 */ + {0x44, 0x44, 66}, /* 0x53 Chrontel */ + {0x3a, 0x62, 70}, /* 0x54 Chrontel */ + {0x62, 0xc6, 34}, /* 0x55 848x480-60 */ + {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */ + {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + {0x52, 0x07, 149}, /* 0x59 1280x960-85 */ + {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */ + {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */ + {0x45, 0x25, 83}, /* 0x5c 1280x800 */ + {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */ + {0x70, 0x24, 162}, /* 0x5e 1600x1200 */ + {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */ + {0x63, 0x46, 68}, /* 0x60 1280x768_2 */ + {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */ + {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + {0x70, 0x28, 90}, /* 0x64 1152x864@60 */ + {0x41, 0xc4, 32}, /* 0x65 848x480@60 */ + {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */ + {0x76, 0xe7, 27}, /* 0x67 720x480@60 */ + {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */ + {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */ + {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */ + {0x45, 0x25, 83}, /* 0x6c 1280x800 */ + {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */ + {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */ + {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + {0x2b, 0xc2, 35} /* 0x71 768@576@60 */ }; -int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); -int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); -extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); -extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data); -extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 data); -extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 *data); -extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand, u8 myor); -extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 myor); -extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand); +extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); +extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data); +extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 data); +extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 * data); +extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand, u8 myor); +extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 myor); +extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand); void sisusb_delete(struct kref *kref); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); -int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); +int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t *bytes_written); + u32 dest, int length, size_t * bytes_written); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, - u8 *arg, int cmapsz, int ch512, int dorecalc, + u8 * arg, int cmapsz, int ch512, int dorecalc, struct vc_data *c, int fh, int uplock); void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); @@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb); void sisusb_init_concode(void); #endif - From ecb8b190bcf49e67a6bd955340ecc07d243b6efa Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 16:04:56 -0400 Subject: [PATCH 2668/2804] USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_struct.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_struct.h | 140 ++++++++++----------- 1 file changed, 66 insertions(+), 74 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index 9def598192c2..1c4240e802c1 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -52,85 +52,78 @@ #define _SISUSB_STRUCT_H_ struct SiS_St { - unsigned char St_ModeID; - unsigned short St_ModeFlag; - unsigned char St_StTableIndex; - unsigned char St_CRT2CRTC; - unsigned char St_ResInfo; - unsigned char VB_StTVFlickerIndex; - unsigned char VB_StTVEdgeIndex; - unsigned char VB_StTVYFilterIndex; - unsigned char St_PDC; + unsigned char St_ModeID; + unsigned short St_ModeFlag; + unsigned char St_StTableIndex; + unsigned char St_CRT2CRTC; + unsigned char St_ResInfo; + unsigned char VB_StTVFlickerIndex; + unsigned char VB_StTVEdgeIndex; + unsigned char VB_StTVYFilterIndex; + unsigned char St_PDC; }; -struct SiS_StandTable -{ - unsigned char CRT_COLS; - unsigned char ROWS; - unsigned char CHAR_HEIGHT; - unsigned short CRT_LEN; - unsigned char SR[4]; - unsigned char MISC; - unsigned char CRTC[0x19]; - unsigned char ATTR[0x14]; - unsigned char GRC[9]; +struct SiS_StandTable { + unsigned char CRT_COLS; + unsigned char ROWS; + unsigned char CHAR_HEIGHT; + unsigned short CRT_LEN; + unsigned char SR[4]; + unsigned char MISC; + unsigned char CRTC[0x19]; + unsigned char ATTR[0x14]; + unsigned char GRC[9]; }; struct SiS_StResInfo_S { - unsigned short HTotal; - unsigned short VTotal; + unsigned short HTotal; + unsigned short VTotal; }; -struct SiS_Ext -{ - unsigned char Ext_ModeID; - unsigned short Ext_ModeFlag; - unsigned short Ext_VESAID; - unsigned char Ext_RESINFO; - unsigned char VB_ExtTVFlickerIndex; - unsigned char VB_ExtTVEdgeIndex; - unsigned char VB_ExtTVYFilterIndex; - unsigned char VB_ExtTVYFilterIndexROM661; - unsigned char REFindex; - char ROMMODEIDX661; +struct SiS_Ext { + unsigned char Ext_ModeID; + unsigned short Ext_ModeFlag; + unsigned short Ext_VESAID; + unsigned char Ext_RESINFO; + unsigned char VB_ExtTVFlickerIndex; + unsigned char VB_ExtTVEdgeIndex; + unsigned char VB_ExtTVYFilterIndex; + unsigned char VB_ExtTVYFilterIndexROM661; + unsigned char REFindex; + char ROMMODEIDX661; }; -struct SiS_Ext2 -{ - unsigned short Ext_InfoFlag; - unsigned char Ext_CRT1CRTC; - unsigned char Ext_CRTVCLK; - unsigned char Ext_CRT2CRTC; - unsigned char Ext_CRT2CRTC_NS; - unsigned char ModeID; - unsigned short XRes; - unsigned short YRes; - unsigned char Ext_PDC; - unsigned char Ext_FakeCRT2CRTC; - unsigned char Ext_FakeCRT2Clk; +struct SiS_Ext2 { + unsigned short Ext_InfoFlag; + unsigned char Ext_CRT1CRTC; + unsigned char Ext_CRTVCLK; + unsigned char Ext_CRT2CRTC; + unsigned char Ext_CRT2CRTC_NS; + unsigned char ModeID; + unsigned short XRes; + unsigned short YRes; + unsigned char Ext_PDC; + unsigned char Ext_FakeCRT2CRTC; + unsigned char Ext_FakeCRT2Clk; }; -struct SiS_CRT1Table -{ - unsigned char CR[17]; +struct SiS_CRT1Table { + unsigned char CR[17]; }; -struct SiS_VCLKData -{ - unsigned char SR2B,SR2C; - unsigned short CLOCK; +struct SiS_VCLKData { + unsigned char SR2B, SR2C; + unsigned short CLOCK; }; -struct SiS_ModeResInfo -{ - unsigned short HTotal; - unsigned short VTotal; - unsigned char XChar; - unsigned char YChar; +struct SiS_ModeResInfo { + unsigned short HTotal; + unsigned short VTotal; + unsigned char XChar; + unsigned char YChar; }; -struct SiS_Private -{ +struct SiS_Private { void *sisusb; unsigned long IOAddress; @@ -151,19 +144,18 @@ struct SiS_Private unsigned long SiS_P3da; unsigned long SiS_Part1Port; - unsigned char SiS_MyCR63; - unsigned short SiS_CRT1Mode; - unsigned short SiS_ModeType; - unsigned short SiS_SetFlag; + unsigned char SiS_MyCR63; + unsigned short SiS_CRT1Mode; + unsigned short SiS_ModeType; + unsigned short SiS_SetFlag; - const struct SiS_StandTable *SiS_StandTable; - const struct SiS_St *SiS_SModeIDTable; - const struct SiS_Ext *SiS_EModeIDTable; - const struct SiS_Ext2 *SiS_RefIndex; - const struct SiS_CRT1Table *SiS_CRT1Table; - const struct SiS_VCLKData *SiS_VCLKData; - const struct SiS_ModeResInfo *SiS_ModeResInfo; + const struct SiS_StandTable *SiS_StandTable; + const struct SiS_St *SiS_SModeIDTable; + const struct SiS_Ext *SiS_EModeIDTable; + const struct SiS_Ext2 *SiS_RefIndex; + const struct SiS_CRT1Table *SiS_CRT1Table; + const struct SiS_VCLKData *SiS_VCLKData; + const struct SiS_ModeResInfo *SiS_ModeResInfo; }; #endif - From 7b5cd5fefbe023625a7ff7604e8beb9a15a9efab Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 15 Aug 2007 10:38:12 -0400 Subject: [PATCH 2669/2804] USB: SisUSB2VGA: Convert printk to dev_* macros This patch convert printk entries to dev_* macros, this provide better debugging and better readability to the code. Signed-off-by: Felipe Balbi Cc: Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 111 +++++++----------------- drivers/usb/misc/sisusbvga/sisusb_con.c | 13 ++- 2 files changed, 36 insertions(+), 88 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 558b94fd209d..4d6b89336e63 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1003,16 +1003,10 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, if (ret) { msgcount++; if (msgcount < 500) - printk(KERN_ERR - "sisusbvga[%d]: Wrote %zd of " - "%d bytes, error %d\n", - sisusb->minor, *bytes_written, - length, ret); + dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n", + *bytes_written, length, ret); else if (msgcount == 500) - printk(KERN_ERR - "sisusbvga[%d]: Too many errors" - ", logging stopped\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n"); } addr += (*bytes_written); length -= (*bytes_written); @@ -1389,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb) sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); for(i = 1; i <= 7; i++) { - printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i); + dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i); sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy); for(j = 0; j < i; j++) { - printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]); + dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]); } } } @@ -2111,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb) if (ramtype <= 1) { ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab); if (iret) { - printk(KERN_ERR "sisusbvga[%d]: RAM size " - "detection failed, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* TODO */ } } else { - printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* *** TODO *** */ } @@ -2192,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb) break; } - printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n", - sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1, + dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1, ramtypetext2[ramtype], bw); } @@ -2453,8 +2441,7 @@ sisusb_open(struct inode *inode, struct file *file) int subminor = iminor(inode); if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - printk(KERN_ERR "sisusb[%d]: Failed to find interface\n", - subminor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to find interface\n"); return -ENODEV; } @@ -2477,18 +2464,12 @@ sisusb_open(struct inode *inode, struct file *file) if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { if (sisusb_init_gfxdevice(sisusb, 0)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to initialize " - "device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n"); return -EIO; } } else { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Device not attached to " - "USB 2.0 hub\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n"); return -EIO; } } @@ -2529,7 +2510,6 @@ static int sisusb_release(struct inode *inode, struct file *file) { struct sisusb_usb_data *sisusb; - int myminor; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) return -ENODEV; @@ -2542,8 +2522,6 @@ sisusb_release(struct inode *inode, struct file *file) sisusb_kill_all_busy(sisusb); } - myminor = sisusb->minor; - sisusb->isopen = 0; file->private_data = NULL; @@ -3126,17 +3104,13 @@ static int sisusb_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct sisusb_usb_data *sisusb; int retval = 0, i; - const char *memfail = - KERN_ERR - "sisusbvga[%d]: Failed to allocate memory for %s buffer\n"; - printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n", + dev_info(&dev->dev, "USB2VGA dongle found at address %d\n", dev->devnum); /* Allocate memory for our private */ if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { - printk(KERN_ERR - "sisusb: Failed to allocate memory for private data\n"); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n"); return -ENOMEM; } kref_init(&sisusb->kref); @@ -3145,8 +3119,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Register device */ if ((retval = usb_register_dev(intf, &usb_sisusb_class))) { - printk(KERN_ERR - "sisusb: Failed to get a minor for device %d\n", + dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n", dev->devnum); retval = -ENODEV; goto error_1; @@ -3164,7 +3137,7 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->ibufsize = SISUSB_IBUF_SIZE; if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE, GFP_KERNEL, &sisusb->transfer_dma_in))) { - printk(memfail, "input", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer"); retval = -ENOMEM; goto error_2; } @@ -3176,7 +3149,7 @@ static int sisusb_probe(struct usb_interface *intf, GFP_KERNEL, &sisusb->transfer_dma_out[i]))) { if (i == 0) { - printk(memfail, "output", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n"); retval = -ENOMEM; goto error_3; } @@ -3188,9 +3161,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate URBs */ if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_3; } @@ -3198,9 +3169,7 @@ static int sisusb_probe(struct usb_interface *intf, for (i = 0; i < sisusb->numobufs; i++) { if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_4; } @@ -3209,15 +3178,12 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->urbstatus[i] = 0; } - printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n", - sisusb->minor, sisusb->numobufs); + dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); #ifdef INCL_SISUSB_CON /* Allocate our SiS_Pr */ if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate SiS_Pr\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n"); } #endif @@ -3239,10 +3205,7 @@ static int sisusb_probe(struct usb_interface *intf, ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL); ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL); if (ret) - printk(KERN_ERR - "sisusbvga[%d]: Error registering ioctl32 " - "translations\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n"); else sisusb->ioctl32registered = 1; } @@ -3258,23 +3221,17 @@ static int sisusb_probe(struct usb_interface *intf, initscreen = 0; #endif if (sisusb_init_gfxdevice(sisusb, initscreen)) - printk(KERN_ERR - "sisusbvga[%d]: Failed to early " - "initialize device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n"); } else - printk(KERN_INFO - "sisusbvga[%d]: Not attached to USB 2.0 hub, " - "deferring init\n", - sisusb->minor); + dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n"); sisusb->ready = 1; #ifdef SISUSBENDIANTEST - printk(KERN_DEBUG "sisusb: *** RWTEST ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n"); sisusb_testreadwrite(sisusb); - printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); #endif #ifdef INCL_SISUSB_CON @@ -3297,7 +3254,6 @@ error_1: static void sisusb_disconnect(struct usb_interface *intf) { struct sisusb_usb_data *sisusb; - int minor; /* This should *not* happen */ if (!(sisusb = usb_get_intfdata(intf))) @@ -3307,8 +3263,6 @@ static void sisusb_disconnect(struct usb_interface *intf) sisusb_console_exit(sisusb); #endif - minor = sisusb->minor; - usb_deregister_dev(intf, &usb_sisusb_class); mutex_lock(&sisusb->lock); @@ -3327,10 +3281,7 @@ static void sisusb_disconnect(struct usb_interface *intf) ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG); ret |= unregister_ioctl32_conversion(SISUSB_COMMAND); if (ret) { - printk(KERN_ERR - "sisusbvga[%d]: Error unregistering " - "ioctl32 translations\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n"); } } #endif @@ -3343,7 +3294,7 @@ static void sisusb_disconnect(struct usb_interface *intf) /* decrement our usage count */ kref_put(&sisusb->kref, sisusb_delete); - printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor); + dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n"); } static struct usb_device_id sisusb_table [] = { @@ -3368,6 +3319,7 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { int retval; + struct sisusb_usb_data *sisusb; #ifdef INCL_SISUSB_CON sisusb_init_concode(); @@ -3375,10 +3327,9 @@ static int __init usb_sisusb_init(void) if (!(retval = usb_register(&sisusb_driver))) { - printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n", - SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL); - printk(KERN_INFO - "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); + dev_info(&sisusb->sisusb_dev->dev, "Driver version %d.%d.%d\n", SISUSB_VERSION, + SISUSB_REVISION, SISUSB_PATCHLEVEL); + dev_info(&sisusb->sisusb_dev->dev, "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 20938cd09ed4..43722e5a49d1 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -537,7 +538,7 @@ sisusbcon_switch(struct vc_data *c) */ if (c->vc_origin == (unsigned long)c->vc_screenbuf) { mutex_unlock(&sisusb->lock); - printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n"); return 0; } @@ -1428,7 +1429,7 @@ static const struct consw sisusb_dummy_con = { int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) { - int i, ret, minor = sisusb->minor; + int i, ret; mutex_lock(&sisusb->lock); @@ -1461,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Set up text mode (and upload default font) */ if (sisusb_reset_text_mode(sisusb, 1)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to set up text mode\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n"); return 1; } @@ -1484,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Allocate screen buffer */ if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate screen buffer\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n"); return 1; } From fc401e697f8c00ad1178a6758e86e3881dfa3181 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 13 Aug 2007 22:50:13 -0700 Subject: [PATCH 2670/2804] usblp: mutex in usblp_check_status Add a mutex to protect the ->statusbuf. Not really an issue, because CUPS is single-threaded when it talks to the printer, but I feel safer this way. This should be deadlock-free, but I kept this as a separate patch in case someone ends running a git bisect. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 9696668e5752..2c4a359355ba 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -345,16 +345,17 @@ static int usblp_check_status(struct usblp *usblp, int err) unsigned char status, newerr = 0; int error; - error = usblp_read_status (usblp, usblp->statusbuf); - if (error < 0) { + mutex_lock(&usblp->mut); + if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { + mutex_unlock(&usblp->mut); if (printk_ratelimit()) printk(KERN_ERR "usblp%d: error %d reading printer status\n", usblp->minor, error); return 0; } - status = *usblp->statusbuf; + mutex_unlock(&usblp->mut); if (~status & LP_PERRORP) newerr = 3; From 283face86b002e670053e9189604852ccb81d357 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 13 Aug 2007 22:54:29 -0700 Subject: [PATCH 2671/2804] usblp: Cosmetics This is a small bunch of cosmetic fixes: - Timeout is not a write timeout anymore, rename - Condition in poll was confusingly backwards, invert and simplify - The comment log gave a wrong impression of version 0.13, terminate it. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 2c4a359355ba..3a0f8186d4bf 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -28,6 +28,7 @@ * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) * v0.13 - alloc space for statusbuf ( not on stack); * use usb_buffer_alloc() for read buf & write buf; + * none - Maintained in Linux kernel after v0.13 */ /* @@ -114,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 -#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */ +#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */ #define USBLP_FIRST_PROTOCOL 1 #define USBLP_LAST_PROTOCOL 3 @@ -260,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT); + request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", request, !!dir, recip, value, index, len, retval); return retval < 0 ? retval : 0; @@ -479,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->rwait, wait); poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); - ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); + ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) | + ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } From 30c7431de3631d6a5482a87b7c2453b937e8aa51 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:33:40 -0700 Subject: [PATCH 2672/2804] usbmon: Update pipe removal to suit my taste This is a set of small updates to Alan's work to make the code more to my liking. Mostly premature optimizations, but also direction of control transfers in the binary interface was always out. Signed-off-by: Pete Zaitcev Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 44 ++++++++++++-------------------------- drivers/usb/mon/mon_text.c | 8 +++---- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 0b0d77c669da..5185e93dedef 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, #define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) +static unsigned char xfer_to_pipe[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + static struct class *mon_bin_class; static dev_t mon_bin_dev0; static struct cdev mon_bin_cdev; @@ -388,11 +392,13 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, char ev_type) { + const struct usb_endpoint_descriptor *epd = &urb->ep->desc; unsigned long flags; struct timeval ts; unsigned int urb_length; unsigned int offset; unsigned int length; + unsigned char dir; struct mon_bin_hdr *ep; char data_tag = 0; @@ -415,11 +421,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, length = 0; data_tag = '<'; } + /* Cannot rely on endpoint number in case of control ep.0 */ + dir = USB_DIR_IN; } else { if (ev_type == 'C') { length = 0; data_tag = '>'; } + dir = 0; } if (rp->mmap_active) @@ -440,21 +449,8 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - switch (usb_endpoint_type(&urb->ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ep->xfer_type = PIPE_CONTROL; - break; - case USB_ENDPOINT_XFER_BULK: - ep->xfer_type = PIPE_BULK; - break; - case USB_ENDPOINT_XFER_INT: - ep->xfer_type = PIPE_INTERRUPT; - break; - default: - ep->xfer_type = PIPE_ISOCHRONOUS; - break; - } - ep->epnum = urb->ep->desc.bEndpointAddress; + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)]; + ep->epnum = dir | usb_endpoint_num(epd); ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; @@ -512,21 +508,9 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - switch (usb_endpoint_type(&urb->ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ep->xfer_type = PIPE_CONTROL; - break; - case USB_ENDPOINT_XFER_BULK: - ep->xfer_type = PIPE_BULK; - break; - case USB_ENDPOINT_XFER_INT: - ep->xfer_type = PIPE_INTERRUPT; - break; - default: - ep->xfer_type = PIPE_ISOCHRONOUS; - break; - } - ep->epnum = urb->ep->desc.bEndpointAddress; + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)]; + ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0; + ep->epnum |= usb_endpoint_num(&urb->ep->desc); ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 9d0070ceef52..a74069c2e82b 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -52,10 +52,11 @@ struct mon_event_text { int type; /* submit, complete, etc. */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; - int xfertype; int busnum; - int devnum; - int epnum; + char devnum; + char epnum; + char is_in; + char xfertype; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -63,7 +64,6 @@ struct mon_event_text { int error_count; char setup_flag; char data_flag; - char is_in; int numdesc; /* Full number */ struct mon_iso_desc isodesc[ISODESC_MAX]; unsigned char setup[SETUP_MAX]; From cdd5a8fd24f5be43417a25c6feb8e7ebdce63098 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:37:51 -0700 Subject: [PATCH 2673/2804] usbmon: Drop DMA mapping for setup packet Setup packet must be visible in virtual space. There's absolutely no good reason to implement any kind of zero-copy transfer of 8 bytes, and the documentation in usb.h is explicit about it. So, drop DMA remapping. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 4 ---- drivers/usb/mon/mon_text.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 5185e93dedef..3d6f03819ffd 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -361,10 +361,6 @@ static inline char mon_bin_get_setup(unsigned char *setupb, if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); - } if (urb->setup_packet == NULL) return 'Z'; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index a74069c2e82b..663a702a17dd 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -127,10 +127,6 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX); - } if (urb->setup_packet == NULL) return 'Z'; /* '0' would be not as pretty. */ From c36d54ab380fb8edeaa22776af869c64bfda43bd Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:42:53 -0700 Subject: [PATCH 2674/2804] usbmon: Smooth the core code Two things: - mbus can be NULL (in case of bus removal while reader is reading) - Remove a useless assignment Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_main.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index e58f761d060f..2e317bd79e92 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -148,18 +148,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) { struct mon_bus *mbus; - mbus = ubus->mon_bus; - if (mbus == NULL) { - /* - * This should not happen. - * At this point we do not even know the bus number... - */ - printk(KERN_ERR TAG ": Null mon bus in URB, address %p\n", - urb); - return; - } - - mon_bus_complete(mbus, urb); + if ((mbus = ubus->mon_bus) != NULL) + mon_bus_complete(mbus, urb); mon_bus_complete(&mon_bus0, urb); } @@ -170,7 +160,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) */ static void mon_stop(struct mon_bus *mbus) { - struct usb_bus *ubus = mbus->u_bus; + struct usb_bus *ubus; struct list_head *p; if (mbus == &mon_bus0) { From 42cb967fd01b1f50374fdfa811f86db103eea532 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 13:19:16 -0700 Subject: [PATCH 2675/2804] usblp: Fix a double kfree If submit fails, slab hits a BUG() because of a double kfree. The today's lesson is, you cannot just slap USB_FREE_BUFFER on code without adjusting the error paths. The patch is made bigger by opportunistic refactoring. Signed-Off-By: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 3a0f8186d4bf..ad632f2d6f94 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -686,10 +686,30 @@ done: return retval; } +static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) +{ + struct urb *urb; + char *writebuf; + + if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) + return NULL; + if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { + kfree(writebuf); + return NULL; + } + + usb_fill_bulk_urb(urb, usblp->dev, + usb_sndbulkpipe(usblp->dev, + usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), + writebuf, transfer_length, usblp_bulk_write, usblp); + urb->transfer_flags |= URB_FREE_BUFFER; + + return urb; +} + static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - char *writebuf; struct urb *writeurb; int rv; int transfer_length; @@ -710,18 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t transfer_length = USBLP_BUF_SIZE; rv = -ENOMEM; - if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL) - goto raise_buf; - if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) + if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) goto raise_urb; - usb_fill_bulk_urb(writeurb, usblp->dev, - usb_sndbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), - writebuf, transfer_length, usblp_bulk_write, usblp); - writeurb->transfer_flags |= URB_FREE_BUFFER; usb_anchor_urb(writeurb, &usblp->urbs); - if (copy_from_user(writebuf, + if (copy_from_user(writeurb->transfer_buffer, buffer + writecount, transfer_length)) { rv = -EFAULT; goto raise_badaddr; @@ -780,8 +793,6 @@ raise_badaddr: usb_unanchor_urb(writeurb); usb_free_urb(writeurb); raise_urb: - kfree(writebuf); -raise_buf: raise_wait: collect_error: /* Out of raise sequence */ mutex_unlock(&usblp->wmut); From 3f6ff6ef044bc7078daa01412c911015d6cbaa39 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 10 Aug 2007 14:53:34 -0700 Subject: [PATCH 2676/2804] USB: kl5kusb105: witch to new speed API Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/kl5kusb105.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5a4127e62c4a..90e3216abd1f 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port, #endif } - switch(cflag & CBAUD) { - case B0: /* handled below */ + switch(tty_get_baud_rate(port->tty)) { + case 0: /* handled below */ break; - case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200; + case 1200: + priv->cfg.baudrate = kl5kusb105a_sio_b1200; break; - case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400; + case 2400: + priv->cfg.baudrate = kl5kusb105a_sio_b2400; break; - case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800; + case 4800: + priv->cfg.baudrate = kl5kusb105a_sio_b4800; break; - case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600; + case 9600: + priv->cfg.baudrate = kl5kusb105a_sio_b9600; break; - case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200; + case 19200: + priv->cfg.baudrate = kl5kusb105a_sio_b19200; break; - case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400; + case 38400: + priv->cfg.baudrate = kl5kusb105a_sio_b38400; break; - case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600; + case 57600: + priv->cfg.baudrate = kl5kusb105a_sio_b57600; break; - case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200; + case 115200: + priv->cfg.baudrate = kl5kusb105a_sio_b115200; break; default: err("KLSI USB->Serial converter:" From b3aceb2bab988e514e65dd37f385221a095ad477 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 10 Aug 2007 14:53:35 -0700 Subject: [PATCH 2677/2804] USB: mct_u232-convert-to-proper-speed-handling-api-fix Make Pete happy Cc: Alan Cox Cc: Pete Zaitcev Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mct_u232.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index e08c9bb403d8..0dc99f75bb09 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value } } else { switch (value) { - case 300: break; - case 600: break; - case 1200: break; - case 2400: break; - case 4800: break; - case 9600: break; - case 19200: break; - case 38400: break; - case 57600: break; - case 115200: break; - default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); - value = 9600; + case 300: break; + case 600: break; + case 1200: break; + case 2400: break; + case 4800: break; + case 9600: break; + case 19200: break; + case 38400: break; + case 57600: break; + case 115200: break; + default: + err("MCT USB-RS232: unsupported baudrate request 0x%x," + " using default of B9600", value); + value = 9600; } return 115200/value; } From 5280d6083a77cc06a8c8360a2c461fd12d780fb8 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 10 Aug 2007 14:53:35 -0700 Subject: [PATCH 2678/2804] USB: ftdi-elan.c: kmalloc + memset conversion to kzalloc drivers/usb/misc/ftdi-elan.c | 121253 -> 121196 (-57 bytes) drivers/usb/misc/ftdi-elan.o | 209425 -> 209265 (-160 bytes) Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 538b535e955b..d3d8cd6ff103 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface, size_t buffer_size; int i; int retval = -ENOMEM; - struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (ftdi == NULL) { + struct usb_ftdi *ftdi; + + ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); + if (!ftdi) { printk(KERN_ERR "Out of memory\n"); return -ENOMEM; } - memset(ftdi, 0x00, sizeof(struct usb_ftdi)); + mutex_lock(&ftdi_module_lock); list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); ftdi->sequence_num = ++ftdi_instances; From 60b69a966fddeb3bdd79712d52b34b8696a27f88 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 10 Aug 2007 14:53:37 -0700 Subject: [PATCH 2679/2804] usb: remove redundant memset from amd5536udc Remove redundant memset() call from udc_pci_probe(). No functional change. Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 714156ca8fe4..e95ffc9eee3d 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3244,7 +3244,6 @@ static int udc_pci_probe( retval = -ENOMEM; goto finished; } - memset(dev, 0, sizeof(struct udc)); /* pci setup */ if (pci_enable_device(pdev) < 0) { From f6c1ceaa3844b7a7787816cc97d15b9fea8b0909 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 16 Aug 2007 16:02:08 +0200 Subject: [PATCH 2680/2804] USB: missing test for ESHUTDOWN in adutux driver this driver lacks a test for unlink due to ESHUTDOWN Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index e9fdbc8997b3..5131cbfb2f52 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb) spin_lock(&dev->buflock); if (status != 0) { - if ((status != -ENOENT) && (status != -ECONNRESET)) { + if ((status != -ENOENT) && (status != -ECONNRESET) && + (status != -ESHUTDOWN)) { dbg(1," %s : nonzero status received: %d", __FUNCTION__, status); } From f311cf58bd04adc683067f8d66daa5925b80f082 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 14 Aug 2007 23:22:50 +0200 Subject: [PATCH 2681/2804] USB: ark3116.c: fix check-after-use The Coverity checker spotted that we'd have already oops'ed if one of these was NULL. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ark3116.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index c9fd486c1c7d..2a8e537cb046 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if (!port->tty || !port->tty->termios) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - spin_lock_irqsave(&priv->lock, flags); if (!priv->termios_initialized) { *(port->tty->termios) = tty_std_termios; From e39ab592f182cd0be48acc4ad49f93ef4100017c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 16 Aug 2007 16:17:49 -0400 Subject: [PATCH 2682/2804] USB: remove unnecessary tests in isp116x and sl811 This patch (as962) cleans up some code I forgot to remove earlier in the isp116x and sl811 HCDs. There is no longer any need to check for unlink-during-submit; it can't happen since the endpoint queues are now under the protection of the HCD-private spinlock. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp116x-hcd.c | 6 ------ drivers/usb/host/sl811-hcd.c | 10 ---------- 2 files changed, 16 deletions(-) diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index d5027dc75a57..f2b5d6281c5d 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -815,12 +815,6 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } } - /* in case of unlink-during-submit */ - if (urb->status != -EINPROGRESS) { - finish_request(isp116x, ep, urb); - ret = 0; - goto fail; - } urb->hcpriv = hep; start_atl_transfers(isp116x); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 3d3a63d002c5..15a93f946afd 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -957,17 +957,7 @@ static int sl811h_urb_enqueue( sofirq_on(sl811); } - /* in case of unlink-during-submit */ - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - finish_request(sl811, ep, urb, 0); - retval = 0; - goto fail; - } urb->hcpriv = hep; - spin_unlock(&urb->lock); - start_transfer(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); fail: From c8e463796c7ae6d8dda39b0c7eb3d627600ffe2e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:23:12 +0200 Subject: [PATCH 2683/2804] UEAGLE: Eagle IV chipset support Add support to newest chipset of eagle family. It is compatible with older chipsets at USB level. However DSP firmware and CMVs (Configuration and Management Variables) have different format of data and are sent/received by different way. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 1195 ++++++++++++++++++++++++++++------ 1 file changed, 980 insertions(+), 215 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 29807d048b04..b5e8cbad223b 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -107,12 +107,42 @@ #define uea_info(usb_dev, format,args...) \ dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args) -struct uea_cmvs { +struct intr_pkt; + +/* cmv's from firmware */ +struct uea_cmvs_v1 { u32 address; u16 offset; u32 data; } __attribute__ ((packed)); +struct uea_cmvs_v2 { + u32 group; + u32 address; + u32 offset; + u32 data; +} __attribute__ ((packed)); + +/* information about currently processed cmv */ +struct cmv_dsc_e1 { + u8 function; + u16 idx; + u32 address; + u16 offset; +}; + +struct cmv_dsc_e4 { + u16 function; + u16 offset; + u16 address; + u16 group; +}; + +union cmv_dsc { + struct cmv_dsc_e1 e1; + struct cmv_dsc_e4 e4; +}; + struct uea_softc { struct usb_device *usb_dev; struct usbatm_data *usbatm; @@ -127,8 +157,11 @@ struct uea_softc { struct task_struct *kthread; u32 data; + u32 data1; wait_queue_head_t cmv_ack_wait; + int cmv_ack; + union cmv_dsc cmv_dsc; struct work_struct task; u16 pageno; @@ -137,10 +170,10 @@ struct uea_softc { const struct firmware *dsp_firm; struct urb *urb_int; - u8 cmv_function; - u16 cmv_idx; - u32 cmv_address; - u16 cmv_offset; + void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *); + void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *); + int (*stat) (struct uea_softc *); + int (*send_cmvs) (struct uea_softc *); /* keep in sync with eaglectl */ struct uea_stats { @@ -187,12 +220,12 @@ struct uea_softc { #define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */ #define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */ -/* - * Eagle III Pid - */ #define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */ #define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */ +#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */ +#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */ + /* * USR USB IDs */ @@ -212,7 +245,8 @@ enum { ADI930 = 0, EAGLE_I, EAGLE_II, - EAGLE_III + EAGLE_III, + EAGLE_IV }; /* macros for both struct usb_device_id and struct uea_softc */ @@ -228,8 +262,11 @@ enum { #define GET_STATUS(data) \ ((data >> 8) & 0xf) + #define IS_OPERATIONAL(sc) \ - (GET_STATUS(sc->stats.phy.state) == 2) + ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \ + (GET_STATUS(sc->stats.phy.state) == 2) : \ + (sc->stats.phy.state == 7)) /* * Set of macros to handle unaligned data in the firmware blob. @@ -259,7 +296,8 @@ enum { #define UEA_INTR_PIPE 0x04 #define UEA_ISO_DATA_PIPE 0x08 -#define UEA_SET_BLOCK 0x0001 +#define UEA_E1_SET_BLOCK 0x0001 +#define UEA_E4_SET_BLOCK 0x002c #define UEA_SET_MODE 0x0003 #define UEA_SET_2183_DATA 0x0004 #define UEA_SET_TIMEOUT 0x0011 @@ -275,71 +313,179 @@ enum { #define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000) #define UEA_MPRX_MAILBOX (0x3fdf | 0x4000) -/* structure describing a block within a DSP page */ -struct block_info { +/* block information in eagle4 dsp firmware */ +struct block_index { + __le32 PageOffset; + __le32 NotLastBlock; + __le32 dummy; + __le32 PageSize; + __le32 PageAddress; + __le16 dummy1; + __le16 PageNumber; +} __attribute__ ((packed)); + +#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000) +#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4) + +#define E4_L1_STRING_HEADER 0x10 +#define E4_MAX_PAGE_NUMBER 0x58 +#define E4_NO_SWAPPAGE_HEADERS 0x31 + +/* l1_code is eagle4 dsp firmware format */ +struct l1_code { + u8 string_header[E4_L1_STRING_HEADER]; + u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER]; + struct block_index page_header[E4_NO_SWAPPAGE_HEADERS]; + u8 code [0]; +} __attribute__ ((packed)); + +/* structures describing a block within a DSP page */ +struct block_info_e1 { __le16 wHdr; -#define UEA_BIHDR 0xabcd __le16 wAddress; __le16 wSize; __le16 wOvlOffset; __le16 wOvl; /* overlay */ __le16 wLast; } __attribute__ ((packed)); -#define BLOCK_INFO_SIZE 12 +#define E1_BLOCK_INFO_SIZE 12 -/* structure representing a CMV (Configuration and Management Variable) */ -struct cmv { - __le16 wPreamble; -#define PREAMBLE 0x535c - __u8 bDirection; -#define MODEMTOHOST 0x01 -#define HOSTTOMODEM 0x10 - __u8 bFunction; -#define FUNCTION_TYPE(f) ((f) >> 4) -#define MEMACCESS 0x1 -#define ADSLDIRECTIVE 0x7 +struct block_info_e4 { + __be16 wHdr; + __u8 bBootPage; + __u8 bPageNumber; + __be32 dwSize; + __be32 dwAddress; + __be16 wReserved; +} __attribute__ ((packed)); +#define E4_BLOCK_INFO_SIZE 14 + +#define UEA_BIHDR 0xabcd +#define UEA_RESERVED 0xffff + +/* constants describing cmv type */ +#define E1_PREAMBLE 0x535c +#define E1_MODEMTOHOST 0x01 +#define E1_HOSTTOMODEM 0x10 + +#define E1_MEMACCESS 0x1 +#define E1_ADSLDIRECTIVE 0x7 +#define E1_FUNCTION_TYPE(f) ((f) >> 4) +#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f) + +#define E4_MEMACCESS 0 +#define E4_ADSLDIRECTIVE 0xf +#define E4_FUNCTION_TYPE(f) ((f) >> 8) +#define E4_FUNCTION_SIZE(f) ((f) & 0x0f) +#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f) -#define FUNCTION_SUBTYPE(f) ((f) & 0x0f) /* for MEMACCESS */ -#define REQUESTREAD 0x0 -#define REQUESTWRITE 0x1 -#define REPLYREAD 0x2 -#define REPLYWRITE 0x3 -/* for ADSLDIRECTIVE */ -#define KERNELREADY 0x0 -#define MODEMREADY 0x1 +#define E1_REQUESTREAD 0x0 +#define E1_REQUESTWRITE 0x1 +#define E1_REPLYREAD 0x2 +#define E1_REPLYWRITE 0x3 -#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) - __le16 wIndex; - __le32 dwSymbolicAddress; -#define MAKESA(a, b, c, d) \ +#define E4_REQUESTREAD 0x0 +#define E4_REQUESTWRITE 0x4 +#define E4_REPLYREAD (E4_REQUESTREAD | 1) +#define E4_REPLYWRITE (E4_REQUESTWRITE | 1) + +/* for ADSLDIRECTIVE */ +#define E1_KERNELREADY 0x0 +#define E1_MODEMREADY 0x1 + +#define E4_KERNELREADY 0x0 +#define E4_MODEMREADY 0x1 + +#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) +#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf)) + +#define E1_MAKESA(a, b, c, d) \ (((c) & 0xff) << 24 | \ ((d) & 0xff) << 16 | \ ((a) & 0xff) << 8 | \ ((b) & 0xff)) -#define GETSA1(a) ((a >> 8) & 0xff) -#define GETSA2(a) (a & 0xff) -#define GETSA3(a) ((a >> 24) & 0xff) -#define GETSA4(a) ((a >> 16) & 0xff) -#define SA_CNTL MAKESA('C', 'N', 'T', 'L') -#define SA_DIAG MAKESA('D', 'I', 'A', 'G') -#define SA_INFO MAKESA('I', 'N', 'F', 'O') -#define SA_OPTN MAKESA('O', 'P', 'T', 'N') -#define SA_RATE MAKESA('R', 'A', 'T', 'E') -#define SA_STAT MAKESA('S', 'T', 'A', 'T') +#define E1_GETSA1(a) ((a >> 8) & 0xff) +#define E1_GETSA2(a) (a & 0xff) +#define E1_GETSA3(a) ((a >> 24) & 0xff) +#define E1_GETSA4(a) ((a >> 16) & 0xff) + +#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L') +#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G') +#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O') +#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N') +#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E') +#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T') + +#define E4_SA_CNTL 1 +#define E4_SA_STAT 2 +#define E4_SA_INFO 3 +#define E4_SA_TEST 4 +#define E4_SA_OPTN 5 +#define E4_SA_RATE 6 +#define E4_SA_DIAG 7 +#define E4_SA_CNFG 8 + +/* structures representing a CMV (Configuration and Management Variable) */ +struct cmv_e1 { + __le16 wPreamble; + __u8 bDirection; + __u8 bFunction; + __le16 wIndex; + __le32 dwSymbolicAddress; __le16 wOffsetAddress; __le32 dwData; } __attribute__ ((packed)); -#define CMV_SIZE 16 -/* structure representing swap information */ -struct swap_info { +struct cmv_e4 { + __be16 wGroup; + __be16 wFunction; + __be16 wOffset; + __be16 wAddress; + __be32 dwData [6]; +} __attribute__ ((packed)); + +/* structures representing swap information */ +struct swap_info_e1 { __u8 bSwapPageNo; __u8 bOvl; /* overlay */ } __attribute__ ((packed)); -/* structure representing interrupt data */ +struct swap_info_e4 { + __u8 bSwapPageNo; +} __attribute__ ((packed)); + +/* structures representing interrupt data */ +#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo +#define e1_bOvl u.e1.s1.swapinfo.bOvl +#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo + +#define INT_LOADSWAPPAGE 0x0001 +#define INT_INCOMINGCMV 0x0002 + +union intr_data_e1 { + struct { + struct swap_info_e1 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e1 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + +union intr_data_e4 { + struct { + struct swap_info_e4 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e4 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + struct intr_pkt { __u8 bType; __u8 bNotification; @@ -347,27 +493,18 @@ struct intr_pkt { __le16 wIndex; __le16 wLength; __le16 wInterrupt; -#define INT_LOADSWAPPAGE 0x0001 -#define INT_INCOMINGCMV 0x0002 union { - struct { - struct swap_info swapinfo; - __le16 wDataSize; - } __attribute__ ((packed)) s1; - - struct { - struct cmv cmv; - __le16 wDataSize; - } __attribute__ ((packed)) s2; - } __attribute__ ((packed)) u; -#define bSwapPageNo u.s1.swapinfo.bSwapPageNo -#define bOvl u.s1.swapinfo.bOvl + union intr_data_e1 e1; + union intr_data_e4 e4; + } u; } __attribute__ ((packed)); -#define INTR_PKT_SIZE 28 + +#define E1_INTR_PKT_SIZE 28 +#define E4_INTR_PKT_SIZE 64 static struct usb_driver uea_driver; static DEFINE_MUTEX(uea_mutex); -static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"}; +static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"}; static int modem_index; static unsigned int debug; @@ -519,6 +656,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) case EAGLE_III: fw_name = FW_DIR "eagleIII.fw"; break; + case EAGLE_IV: + fw_name = FW_DIR "eagleIV.fw"; + break; } ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); @@ -537,7 +677,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) /* * Make sure that the DSP code provided is safe to use. */ -static int check_dsp(u8 *dsp, unsigned int len) +static int check_dsp_e1(u8 *dsp, unsigned int len) { u8 pagecount, blockcount; u16 blocksize; @@ -588,6 +728,51 @@ static int check_dsp(u8 *dsp, unsigned int len) return 0; } +static int check_dsp_e4(u8 *dsp, int len) +{ + int i; + struct l1_code *p = (struct l1_code *) dsp; + unsigned int sum = p->code - dsp; + + if (len < sum) + return 1; + + if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 && + strcmp("STRATIPHY ANEXB", p->string_header) != 0) + return 1; + + for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) { + struct block_index *blockidx; + u8 blockno = p->page_number_to_block_index[i]; + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + continue; + + do { + u64 l; + + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + return 1; + + blockidx = &p->page_header[blockno++]; + if ((u8 *)(blockidx + 1) - dsp >= len) + return 1; + + if (le16_to_cpu(blockidx->PageNumber) != i) + return 1; + + l = E4_PAGE_BYTES(blockidx->PageSize); + sum += l; + l += le32_to_cpu(blockidx->PageOffset); + if (l > len) + return 1; + + /* zero is zero regardless endianes */ + } while (blockidx->NotLastBlock); + } + + return (sum == len) ? 0 : 1; +} + /* * send data to the idma pipe * */ @@ -624,7 +809,12 @@ static int request_dsp(struct uea_softc *sc) int ret; char *dsp_name; - if (UEA_CHIP_VERSION(sc) == ADI930) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (IS_ISDN(sc->usb_dev)) + dsp_name = FW_DIR "DSP4i.bin"; + else + dsp_name = FW_DIR "DSP4p.bin"; + } else if (UEA_CHIP_VERSION(sc) == ADI930) { if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSP9i.bin"; else @@ -640,11 +830,16 @@ static int request_dsp(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "requesting firmware %s failed with error %d\n", - dsp_name, ret); + dsp_name, ret); return ret; } - if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size); + else + ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size); + + if (ret) { uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", dsp_name); release_firmware(sc->dsp_firm); @@ -658,12 +853,12 @@ static int request_dsp(struct uea_softc *sc) /* * The uea_load_page() function must be called within a process context */ -static void uea_load_page(struct work_struct *work) +static void uea_load_page_e1(struct work_struct *work) { struct uea_softc *sc = container_of(work, struct uea_softc, task); u16 pageno = sc->pageno; u16 ovl = sc->ovl; - struct block_info bi; + struct block_info_e1 bi; u8 *p; u8 pagecount, blockcount; @@ -716,7 +911,7 @@ static void uea_load_page(struct work_struct *work) bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0); /* send block info through the IDMA pipe */ - if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE)) + if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE)) goto bad2; /* send block data through the IDMA pipe */ @@ -735,6 +930,103 @@ bad1: uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); } +static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) +{ + struct block_info_e4 bi; + struct block_index *blockidx; + struct l1_code *p = (struct l1_code *) sc->dsp_firm->data; + u8 blockno = p->page_number_to_block_index[pageno]; + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = boot; + bi.bPageNumber = pageno; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + + do { + u8 *blockoffset; + unsigned int blocksize; + + blockidx = &p->page_header[blockno]; + blocksize = E4_PAGE_BYTES(blockidx->PageSize); + blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset); + + bi.dwSize = cpu_to_be32(blocksize); + bi.dwAddress = swab32(blockidx->PageAddress); + + uea_dbg(INS_TO_USBDEV(sc), + "sending block %u for DSP page %u size %u adress %x\n", + blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress)); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + goto bad; + + /* send block data through the IDMA pipe */ + if (uea_idma_write(sc, blockoffset, blocksize)) + goto bad; + + blockno++; + } while (blockidx->NotLastBlock); + + return; + +bad: + uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno); + return; +} + +static void uea_load_page_e4(struct work_struct *work) +{ + struct uea_softc *sc = container_of(work, struct uea_softc, task); + u8 pageno = sc->pageno; + int i; + struct block_info_e4 bi; + struct l1_code *p; + + uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno); + + /* reload firmware when reboot start and it's loaded already */ + if (pageno == 0 && sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + + if (sc->dsp_firm == NULL && request_dsp(sc) < 0) + return; + + p = (struct l1_code *) sc->dsp_firm->data; + if (pageno >= p->page_header[0].PageNumber) { + uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); + return; + } + + if (pageno != 0) { + __uea_load_page_e4(sc, pageno, 0); + return; + } + + uea_dbg(INS_TO_USBDEV(sc), + "sending Main DSP page %u\n", p->page_header[0].PageNumber); + + for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) { + if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize)) + __uea_load_page_e4(sc, i, 1); + } + + uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n"); + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = 0; + bi.bPageNumber = 0xff; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize)); + bi.dwAddress = swab32(p->page_header[0].PageAddress); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n"); +} + static inline void wake_up_cmv_ack(struct uea_softc *sc) { BUG_ON(sc->cmv_ack); @@ -792,33 +1084,34 @@ static int uea_request(struct uea_softc *sc, return 0; } -static int uea_cmv(struct uea_softc *sc, +static int uea_cmv_e1(struct uea_softc *sc, u8 function, u32 address, u16 offset, u32 data) { - struct cmv cmv; + struct cmv_e1 cmv; int ret; uea_enters(INS_TO_USBDEV(sc)); uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " "offset : 0x%04x, data : 0x%08x\n", - FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function), - GETSA1(address), GETSA2(address), GETSA3(address), - GETSA4(address), offset, data); - /* we send a request, but we expect a reply */ - sc->cmv_function = function | 0x2; - sc->cmv_idx++; - sc->cmv_address = address; - sc->cmv_offset = offset; + E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function), + E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address), + E1_GETSA4(address), offset, data); - cmv.wPreamble = cpu_to_le16(PREAMBLE); - cmv.bDirection = HOSTTOMODEM; + /* we send a request, but we expect a reply */ + sc->cmv_dsc.e1.function = function | 0x2; + sc->cmv_dsc.e1.idx++; + sc->cmv_dsc.e1.address = address; + sc->cmv_dsc.e1.offset = offset; + + cmv.wPreamble = cpu_to_le16(E1_PREAMBLE); + cmv.bDirection = E1_HOSTTOMODEM; cmv.bFunction = function; - cmv.wIndex = cpu_to_le16(sc->cmv_idx); + cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); - ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv); + ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); if (ret < 0) return ret; ret = wait_cmv_ack(sc); @@ -826,10 +1119,44 @@ static int uea_cmv(struct uea_softc *sc, return ret; } -static inline int uea_read_cmv(struct uea_softc *sc, +static int uea_cmv_e4(struct uea_softc *sc, + u16 function, u16 group, u16 address, u16 offset, u32 data) +{ + struct cmv_e4 cmv; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + memset(&cmv, 0, sizeof(cmv)); + + uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, " + "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n", + E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function), + group, address, offset, data); + + /* we send a request, but we expect a reply */ + sc->cmv_dsc.e4.function = function | (0x1 << 4); + sc->cmv_dsc.e4.offset = offset; + sc->cmv_dsc.e4.address = address; + sc->cmv_dsc.e4.group = group; + + cmv.wFunction = cpu_to_be16(function); + cmv.wGroup = cpu_to_be16(group); + cmv.wAddress = cpu_to_be16(address); + cmv.wOffset = cpu_to_be16(offset); + cmv.dwData[0] = cpu_to_be32(data); + + ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); + if (ret < 0) + return ret; + ret = wait_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return ret; +} + +static inline int uea_read_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 *data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD), address, offset, 0); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -840,10 +1167,27 @@ static inline int uea_read_cmv(struct uea_softc *sc, return ret; } -static inline int uea_write_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 *data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size), + group, address, offset, 0); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "reading cmv failed with error %d\n", ret); + else { + *data = sc->data; + /* size is in 16-bit word quantities */ + if (size > 2) + *(data + 1) = sc->data1; + } + return ret; +} + +static inline int uea_write_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE), address, offset, data); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -852,12 +1196,48 @@ static inline int uea_write_cmv(struct uea_softc *sc, return ret; } +static inline int uea_write_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size), + group, address, offset, data); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "writing cmv failed with error %d\n", ret); + + return ret; +} + +static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) +{ + int ret; + u16 timeout; + + /* in bulk mode the modem have problem with high rate + * changing internal timing could improve things, but the + * value is misterious. + * ADI930 don't support it (-EPIPE error). + */ + + if (UEA_CHIP_VERSION(sc) == ADI930 || + use_iso[sc->modem_index] > 0 || + sc->stats.phy.dsrate == dsrate) + return; + + /* Original timming (1Mbit/s) from ADI (used in windows driver) */ + timeout = (dsrate <= 1024*1024) ? 0 : 1; + ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n", + timeout, ret < 0 ? " failed" : ""); + +} + /* * Monitor the modem and update the stat * return 0 if everything is ok * return < 0 if an error occurs (-EAGAIN reboot needed) */ -static int uea_stat(struct uea_softc *sc) +static int uea_stat_e1(struct uea_softc *sc) { u32 data; int ret; @@ -865,7 +1245,7 @@ static int uea_stat(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); data = sc->stats.phy.state; - ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state); + ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state); if (ret < 0) return ret; @@ -885,7 +1265,7 @@ static int uea_stat(struct uea_softc *sc) case 3: /* fail ... */ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" - " (may be try other cmv/dsp)\n"); + " (may be try other cmv/dsp)\n"); return -EAGAIN; case 4 ... 6: /* test state */ @@ -923,7 +1303,7 @@ static int uea_stat(struct uea_softc *sc) /* wake up processes waiting for synchronization */ wake_up(&sc->sync_q); - ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags); if (ret < 0) return ret; sc->stats.phy.mflags |= sc->stats.phy.flags; @@ -937,105 +1317,223 @@ static int uea_stat(struct uea_softc *sc) return 0; } - ret = uea_read_cmv(sc, SA_RATE, 0, &data); + ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data); if (ret < 0) return ret; - /* in bulk mode the modem have problem with high rate - * changing internal timing could improve things, but the - * value is misterious. - * ADI930 don't support it (-EPIPE error). - */ - if (UEA_CHIP_VERSION(sc) != ADI930 - && !use_iso[sc->modem_index] - && sc->stats.phy.dsrate != (data >> 16) * 32) { - /* Original timming from ADI(used in windows driver) - * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits - */ - u16 timeout = (data <= 0x20ffff) ? 0 : 1; - ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); - uea_info(INS_TO_USBDEV(sc), - "setting new timeout %d%s\n", timeout, - ret < 0?" failed":""); - } + uea_set_bulk_timeout(sc, (data >> 16) * 32); sc->stats.phy.dsrate = (data >> 16) * 32; sc->stats.phy.usrate = (data & 0xffff) * 32; UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); - ret = uea_read_cmv(sc, SA_DIAG, 23, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data); if (ret < 0) return ret; sc->stats.phy.dsattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 47, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data); if (ret < 0) return ret; sc->stats.phy.usattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe); if (ret < 0) return ret; return 0; } -static int request_cmvs(struct uea_softc *sc, - struct uea_cmvs **cmvs, const struct firmware **fw) +static int uea_stat_e4(struct uea_softc *sc) { - int ret, size; - u8 *data; - char *file; - char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + u32 data; + u32 tmp_arr[2]; + int ret; + uea_enters(INS_TO_USBDEV(sc)); + data = sc->stats.phy.state; + + /* XXX only need to be done before operationnal... */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state); + if (ret < 0) + return ret; + + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n"); + return 0; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n"); + return 0; + case 0x2: /* fail ... */ + uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" + " (may be try other cmv/dsp)\n"); + return -EAGAIN; + case 0x7: /* operational */ + break; + default: + uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state); + return 0; + } + + if (data != 7) { + uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "modem operational\n"); + + /* release the dsp firmware as it is not needed until + * the next failure + */ + if (sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + } + + /* always update it as atm layer could not be init when we switch to + * operational state + */ + UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND); + + /* wake up processes waiting for synchronization */ + wake_up(&sc->sync_q); + + /* TODO improve this state machine : + * we need some CMV info : what they do and their unit + * we should find the equivalent of eagle3- CMV + */ + /* check flags */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags); + if (ret < 0) + return ret; + sc->stats.phy.mflags |= sc->stats.phy.flags; + + /* in case of a flags ( for example delineation LOSS (& 0x10)), + * we check the status again in order to detect the failure earlier + */ + if (sc->stats.phy.flags) { + uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", + sc->stats.phy.flags); + if (sc->stats.phy.flags & 1) //delineation LOSS + return -EAGAIN; + if (sc->stats.phy.flags & 0x4000) //Reset Flag + return -EAGAIN; + return 0; + } + + /* rate data may be in upper or lower half of 64 bit word, strange */ + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + sc->stats.phy.usrate = data / 1000; + + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + uea_set_bulk_timeout(sc, data / 1000); + sc->stats.phy.dsrate = data / 1000; + UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.usattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsmargin = data / 2; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.usmargin = data / 10; + + return 0; +} + +static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) +{ + char file_arr[] = "CMVxy.bin"; + char *file; + + /* set proper name corresponding modem version and line type */ if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) - file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; + file_arr[3] = '9'; + else if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + file_arr[3] = '4'; else - file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; + file_arr[3] = 'e'; + + file_arr[4] = IS_ISDN(sc->usb_dev) ? 'i' : 'p'; + file = file_arr; } else file = cmv_file[sc->modem_index]; strcpy(cmv_name, FW_DIR); - strlcat(cmv_name, file, sizeof(cmv_name)); + strlcat(cmv_name, file, FIRMWARE_NAME_MAX); + if (ver == 2) + strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX); +} +static int request_cmvs_old(struct uea_softc *sc, + void **cmvs, const struct firmware **fw) +{ + int ret, size; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + + cmvs_file_name(sc, cmv_name, 1); ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), @@ -1045,16 +1543,197 @@ static int request_cmvs(struct uea_softc *sc, } data = (u8 *) (*fw)->data; - size = *data * sizeof(struct uea_cmvs) + 1; - if (size != (*fw)->size) { - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", - cmv_name); - release_firmware(*fw); - return -EILSEQ; + size = (*fw)->size; + if (size < 1) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v1) + 1) + goto err_fw_corrupted; + + *cmvs = (void *)(data + 1); + return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int request_cmvs(struct uea_softc *sc, + void **cmvs, const struct firmware **fw, int *ver) +{ + int ret, size; + u32 crc; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + + cmvs_file_name(sc, cmv_name, 2); + ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); + if (ret < 0) { + /* if caller can handle old version, try to provide it */ + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, " + "try to get older cmvs\n", cmv_name); + return request_cmvs_old(sc, cmvs, fw); + } + uea_err(INS_TO_USBDEV(sc), + "requesting firmware %s failed with error %d\n", + cmv_name, ret); + return ret; } - *cmvs = (struct uea_cmvs *)(data + 1); + size = (*fw)->size; + data = (u8 *) (*fw)->data; + if (size < 4 || strncmp(data, "cmv2", 4) != 0) { + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, " + "try to get older cmvs\n", cmv_name); + release_firmware(*fw); + return request_cmvs_old(sc, cmvs, fw); + } + goto err_fw_corrupted; + } + + *ver = 2; + + data += 4; + size -= 4; + if (size < 5) + goto err_fw_corrupted; + + crc = FW_GET_LONG(data); + data += 4; + size -= 4; + if (crc32_be(0, data, size) != crc) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v2) + 1) + goto err_fw_corrupted; + + *cmvs = (void *) (data + 1); return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int uea_send_cmvs_e1(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 1; // we can handle v1 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 1) { + struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr; + + uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, " + "please update your firmware\n"); + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address), + FW_GET_WORD(&cmvs_v1[i].offset), + FW_GET_LONG(&cmvs_v1[i].data)); + if (ret < 0) + goto out; + } + } else if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address), + (u16) FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; +} + +static int uea_send_cmvs_e4(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 2; // we can only handle v2 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + /* XXX don't read the 3th byte as it is always 6 */ + ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e4(sc, 1, + FW_GET_LONG(&cmvs_v2[i].group), + FW_GET_LONG(&cmvs_v2[i].address), + FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; } /* Start boot post firmware modem: @@ -1066,9 +1745,7 @@ static int request_cmvs(struct uea_softc *sc, static int uea_start_reset(struct uea_softc *sc) { u16 zero = 0; /* ;-) */ - int i, len, ret; - struct uea_cmvs *cmvs; - const struct firmware *cmvs_fw; + int ret; uea_enters(INS_TO_USBDEV(sc)); uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); @@ -1098,13 +1775,20 @@ static int uea_start_reset(struct uea_softc *sc) /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); - /* clear tx and rx mailboxes */ - uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + if (UEA_CHIP_VERSION(sc) != EAGLE_IV) { + /* clear tx and rx mailboxes */ + uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + } msleep(1000); - sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY); + + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1); + else + sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY); + /* demask interrupt */ sc->booting = 0; @@ -1120,38 +1804,10 @@ static int uea_start_reset(struct uea_softc *sc) uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n"); - /* Enter in R-IDLE (cmv) until instructed otherwise */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 1); + ret = sc->send_cmvs(sc); if (ret < 0) return ret; - /* Dump firmware version */ - ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); - if (ret < 0) - return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); - - /* get options */ - ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); - if (ret < 0) - return ret; - - /* send options */ - for (i = 0; i < len; i++) { - ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address), - FW_GET_WORD(&cmvs[i].offset), - FW_GET_LONG(&cmvs[i].data)); - if (ret < 0) - goto out; - } - /* Enter in R-ACT-REQ */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 2); - uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); - uea_info(INS_TO_USBDEV(sc), "Modem started, " - "waiting synchronization\n"); -out: - release_firmware(cmvs_fw); sc->reset = 0; uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1174,7 +1830,7 @@ static int uea_kthread(void *data) if (ret < 0 || sc->reset) ret = uea_start_reset(sc); if (!ret) - ret = uea_stat(sc); + ret = sc->stat(sc); if (ret != -EAGAIN) msleep_interruptible(1000); if (try_to_freeze()) @@ -1234,7 +1890,6 @@ static int load_XILINX_firmware(struct uea_softc *sc) if (ret < 0) uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret); - err1: release_firmware(fw_entry); err0: @@ -1243,40 +1898,41 @@ err0: } /* The modem send us an ack. First with check if it right */ -static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) +static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) { + struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1; + struct cmv_e1 *cmv = &intr->u.e1.s2.cmv; + uea_enters(INS_TO_USBDEV(sc)); - if (le16_to_cpu(cmv->wPreamble) != PREAMBLE) + if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE) goto bad1; - if (cmv->bDirection != MODEMTOHOST) + if (cmv->bDirection != E1_MODEMTOHOST) goto bad1; /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to * the first MEMACESS cmv. Ignore it... */ - if (cmv->bFunction != sc->cmv_function) { + if (cmv->bFunction != dsc->function) { if (UEA_CHIP_VERSION(sc) == ADI930 - && cmv->bFunction == MAKEFUNCTION(2, 2)) { - cmv->wIndex = cpu_to_le16(sc->cmv_idx); - put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress); - cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset); - } - else + && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { + cmv->wIndex = cpu_to_le16(dsc->idx); + put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress); + cmv->wOffsetAddress = cpu_to_le16(dsc->offset); + } else goto bad2; } - if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) { + if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) { wake_up_cmv_ack(sc); uea_leaves(INS_TO_USBDEV(sc)); return; } /* in case of MEMACCESS */ - if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx || - le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != - sc->cmv_address - || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset) + if (le16_to_cpu(cmv->wIndex) != dsc->idx || + le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address || + le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2; sc->data = le32_to_cpu(get_unaligned(&cmv->dwData)); @@ -1289,8 +1945,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) bad2: uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," "Function : %d, Subfunction : %d\n", - FUNCTION_TYPE(cmv->bFunction), - FUNCTION_SUBTYPE(cmv->bFunction)); + E1_FUNCTION_TYPE(cmv->bFunction), + E1_FUNCTION_SUBTYPE(cmv->bFunction)); uea_leaves(INS_TO_USBDEV(sc)); return; @@ -1301,6 +1957,61 @@ bad1: uea_leaves(INS_TO_USBDEV(sc)); } +/* The modem send us an ack. First with check if it right */ +static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4; + struct cmv_e4 *cmv = &intr->u.e4.s2.cmv; + + uea_enters(INS_TO_USBDEV(sc)); + uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n", + be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction), + be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress), + be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1])); + + if (be16_to_cpu(cmv->wFunction) != dsc->function) + goto bad2; + + if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) { + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + } + + /* in case of MEMACCESS */ + if (be16_to_cpu(cmv->wOffset) != dsc->offset || + be16_to_cpu(cmv->wGroup) != dsc->group || + be16_to_cpu(cmv->wAddress) != dsc->address) + goto bad2; + + sc->data = be32_to_cpu(cmv->dwData[0]); + sc->data1 = be32_to_cpu(cmv->dwData[1]); + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + +bad2: + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + "Function : %d, Subfunction : %d\n", + E4_FUNCTION_TYPE(cmv->wFunction), + E4_FUNCTION_SUBTYPE(cmv->wFunction)); + uea_leaves(INS_TO_USBDEV(sc)); + return; +} + +static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e1_bSwapPageNo; + sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; + schedule_work(&sc->task); +} + +static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e4_bSwapPageNo; + schedule_work(&sc->task); +} + /* * interrupt handler */ @@ -1326,13 +2037,11 @@ static void uea_intr(struct urb *urb) switch (le16_to_cpu(intr->wInterrupt)) { case INT_LOADSWAPPAGE: - sc->pageno = intr->bSwapPageNo; - sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4; - schedule_work(&sc->task); + sc->schedule_load_page(sc, intr); break; case INT_INCOMINGCMV: - uea_dispatch_cmv(sc, &intr->u.s2.cmv); + sc->dispatch_cmv(sc, intr); break; default: @@ -1349,19 +2058,34 @@ resubmit: */ static int uea_boot(struct uea_softc *sc) { - int ret; + int ret, size; struct intr_pkt *intr; uea_enters(INS_TO_USBDEV(sc)); - INIT_WORK(&sc->task, uea_load_page); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + size = E4_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e4; + sc->schedule_load_page = uea_schedule_load_page_e4; + sc->stat = uea_stat_e4; + sc->send_cmvs = uea_send_cmvs_e4; + INIT_WORK(&sc->task, uea_load_page_e4); + } else { + size = E1_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e1; + sc->schedule_load_page = uea_schedule_load_page_e1; + sc->stat = uea_stat_e1; + sc->send_cmvs = uea_send_cmvs_e1; + INIT_WORK(&sc->task, uea_load_page_e1); + } + init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); - intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL); + intr = kmalloc(size, GFP_KERNEL); if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); @@ -1377,7 +2101,7 @@ static int uea_boot(struct uea_softc *sc) usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), - intr, INTR_PKT_SIZE, uea_intr, sc, + intr, size, uea_intr, sc, sc->usb_dev->actconfig->interface[0]->altsetting[0]. endpoint[0].desc.bInterval); @@ -1487,6 +2211,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at char *buf) { int ret = -ENODEV; + int modem_state; struct uea_softc *sc; mutex_lock(&uea_mutex); @@ -1494,7 +2219,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at if (!sc) goto out; - switch (GET_STATUS(sc->stats.phy.state)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + modem_state = 0; + break; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + modem_state = 1; + break; + case 0x7: /* operational */ + modem_state = 2; + break; + case 0x2: /* fail ... */ + modem_state = 3; + break; + default: /* unknown */ + modem_state = 4; + break; + } + } else + modem_state = GET_STATUS(sc->stats.phy.state); + + switch (modem_state) { case 0: ret = sprintf(buf, "Modem is booting\n"); break; @@ -1504,9 +2256,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at case 2: ret = sprintf(buf, "Modem is operational\n"); break; - default: + case 3: ret = sprintf(buf, "Modem synchronization failed\n"); break; + default: + ret = sprintf(buf, "Modem state is unknown\n"); + break; } out: mutex_unlock(&uea_mutex); @@ -1520,18 +2275,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr, { int ret = -ENODEV; struct uea_softc *sc; + char *delin = "GOOD"; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; - if (sc->stats.phy.flags & 0x0C00) - ret = sprintf(buf, "ERROR\n"); - else if (sc->stats.phy.flags & 0x0030) - ret = sprintf(buf, "LOSS\n"); - else - ret = sprintf(buf, "GOOD\n"); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (sc->stats.phy.flags & 0x4000) + delin = "RESET"; + else if (sc->stats.phy.flags & 0x0001) + delin = "LOSS"; + } else { + if (sc->stats.phy.flags & 0x0C00) + delin = "ERROR"; + else if (sc->stats.phy.flags & 0x0030) + delin = "LOSS"; + } + + ret = sprintf(buf, "%s\n", delin); out: mutex_unlock(&uea_mutex); return ret; @@ -1803,6 +2566,8 @@ static const struct usb_device_id uea_ids[] = { {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, + {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, From 603cf6087c5f3ee054bb257195b023848d26d76f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:01 +0200 Subject: [PATCH 2684/2804] UEAGLE: Devolo and Elsa chipsets support Support for Devolo and Elsa chipsets. These chipsets have no information about ADSL annex (line type) encoded in USB descriptors. Driver try to get this information from USB VID and PID or it can be explicitly set by the user through module parameter. Thanks to Johann Hanne, whose make most of this patch. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 114 +++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 26 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index b5e8cbad223b..2cdabd3421e2 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -149,6 +149,9 @@ struct uea_softc { int modem_index; unsigned int driver_info; + int annex; +#define ANNEXA 0 +#define ANNEXB 1 int booting; int reset; @@ -207,10 +210,34 @@ struct uea_softc { #define ELSA_PID_PSTFIRM 0x3350 #define ELSA_PID_PREFIRM 0x3351 +#define ELSA_PID_A_PREFIRM 0x3352 +#define ELSA_PID_A_PSTFIRM 0x3353 +#define ELSA_PID_B_PREFIRM 0x3362 +#define ELSA_PID_B_PSTFIRM 0x3363 + /* - * Sagem USB IDs + * Devolo IDs : pots if (pid & 0x10) */ -#define EAGLE_VID 0x1110 +#define DEVOLO_VID 0x1039 +#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110 +#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111 + +#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100 +#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101 + +#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130 +#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131 + +#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120 +#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121 + +/* + * Reference design USB IDs + */ +#define ANALOG_VID 0x1110 +#define ADI930_PID_PREFIRM 0x9001 +#define ADI930_PID_PSTFIRM 0x9000 + #define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */ #define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */ @@ -241,6 +268,9 @@ struct uea_softc { #define PREFIRM 0 #define PSTFIRM (1<<7) +#define AUTO_ANNEX_A (1<<8) +#define AUTO_ANNEX_B (1<<9) + enum { ADI930 = 0, EAGLE_I, @@ -255,8 +285,8 @@ enum { #define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf) -#define IS_ISDN(usb_dev) \ - (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) +#define IS_ISDN(x) \ + ((x)->annex & ANNEXB) #define INS_TO_USBDEV(ins) ins->usb_dev @@ -511,6 +541,7 @@ static unsigned int debug; static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1}; static int sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; +static int annex[NB_MODEM]; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); @@ -521,6 +552,9 @@ MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); module_param_array(cmv_file, charp, NULL, 0644); MODULE_PARM_DESC(cmv_file, "file name with configuration and management variables"); +module_param_array(annex, uint, NULL, 0644); +MODULE_PARM_DESC(annex, + "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); #define UPDATE_ATM_STAT(type, val) \ do { \ @@ -810,17 +844,17 @@ static int request_dsp(struct uea_softc *sc) char *dsp_name; if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP4i.bin"; else dsp_name = FW_DIR "DSP4p.bin"; } else if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; @@ -1515,7 +1549,7 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) else file_arr[3] = 'e'; - file_arr[4] = IS_ISDN(sc->usb_dev) ? 'i' : 'p'; + file_arr[4] = IS_ISDN(sc) ? 'i' : 'p'; file = file_arr; } else file = cmv_file[sc->modem_index]; @@ -2459,6 +2493,19 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0; sc->driver_info = id->driver_info; + /* first try to use module parameter */ + if (annex[sc->modem_index] == 1) + sc->annex = ANNEXA; + else if (annex[sc->modem_index] == 2) + sc->annex = ANNEXB; + /* try to autodetect annex */ + else if (sc->driver_info & AUTO_ANNEX_A) + sc->annex = ANNEXA; + else if (sc->driver_info & AUTO_ANNEX_B) + sc->annex = ANNEXB; + else + sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; + /* ADI930 don't support iso */ if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { int i; @@ -2520,10 +2567,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", - le16_to_cpu(usb->descriptor.idVendor), - le16_to_cpu(usb->descriptor.idProduct), - chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); + uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n", + le16_to_cpu(usb->descriptor.idVendor), + le16_to_cpu(usb->descriptor.idProduct), + le16_to_cpu(usb->descriptor.bcdDevice), + chip_name[UEA_CHIP_VERSION(id)]); usb_reset_device(usb); @@ -2556,26 +2604,40 @@ static void uea_disconnect(struct usb_interface *intf) * List of supported VID/PID */ static const struct usb_device_id uea_ids[] = { + {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, {USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {} }; From 503add467d4dd2355fe16ebffa7f6d5e9fcd10a8 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:06 +0200 Subject: [PATCH 2685/2804] UEAGLE: Allow user to choose input interface alternate setting Let's user control how much USB bus bandwidth will be reserved by ueagle-atm device. This make possible to share bus with other devices when ueagle-atm driver works in isochronous mode. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 2cdabd3421e2..dee5f798946c 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -538,15 +538,16 @@ static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", static int modem_index; static unsigned int debug; -static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1}; +static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF}; static int sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; static int annex[NB_MODEM]; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); -module_param_array(use_iso, bool, NULL, 0644); -MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic"); +module_param_array(altsetting, uint, NULL, 0644); +MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, " + "1=isoc slowest, ... , 8=isoc fastest (default)"); module_param_array(sync_wait, bool, NULL, 0644); MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); module_param_array(cmv_file, charp, NULL, 0644); @@ -1254,7 +1255,7 @@ static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) */ if (UEA_CHIP_VERSION(sc) == ADI930 || - use_iso[sc->modem_index] > 0 || + altsetting[sc->modem_index] > 0 || sc->stats.phy.dsrate == dsrate) return; @@ -2459,6 +2460,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, struct usb_device *usb = interface_to_usbdev(intf); struct uea_softc *sc; int ret, ifnum = intf->altsetting->desc.bInterfaceNumber; + unsigned int alt; uea_enters(usb); @@ -2506,22 +2508,16 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, else sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; + alt = altsetting[sc->modem_index]; /* ADI930 don't support iso */ - if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { - int i; - - /* try set fastest alternate for inbound traffic interface */ - for (i = FASTEST_ISO_INTF; i > 0; i--) - if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0) - break; - - if (i > 0) { - uea_dbg(usb, "set alternate %d for 2 interface\n", i); + if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) { + if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) { + uea_dbg(usb, "set alternate %u for 2 interface\n", alt); uea_info(usb, "using iso mode\n"); usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ; } else { - uea_err(usb, "setting any alternate failed for " - "2 interface, using bulk mode\n"); + uea_err(usb, "setting alternate %u failed for " + "2 interface, using bulk mode\n", alt); } } From 04ea02f5746a2e01a38edae2de3eafc40eac17aa Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:10 +0200 Subject: [PATCH 2686/2804] UEAGLE: Avoid keyboard driver blocking Ueagle-atm driver load DSP firmware in function, which is running from common workqueue. In some (error) circumstances loading firmware may sleep for long periods (even 60 seconds, depending on timeout). This block keyboard driver, which also use common workqueue. To fix problem use custom workqueue in ueagle-atm. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index dee5f798946c..648c6b79ff41 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -167,6 +167,7 @@ struct uea_softc { union cmv_dsc cmv_dsc; struct work_struct task; + struct workqueue_struct *work_q; u16 pageno; u16 ovl; @@ -1830,7 +1831,7 @@ static int uea_start_reset(struct uea_softc *sc) /* start loading DSP */ sc->pageno = 0; sc->ovl = 0; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); /* wait for modem ready CMV */ ret = wait_cmv_ack(sc); @@ -2038,13 +2039,13 @@ static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *int { sc->pageno = intr->e1_bSwapPageNo; sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); } static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr) { sc->pageno = intr->e4_bSwapPageNo; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); } /* @@ -2117,6 +2118,13 @@ static int uea_boot(struct uea_softc *sc) init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); + sc->work_q = create_workqueue("ueagle-dsp"); + if (!sc->work_q) { + uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n"); + uea_leaves(INS_TO_USBDEV(sc)); + return -ENOMEM; + } + if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); @@ -2124,14 +2132,13 @@ static int uea_boot(struct uea_softc *sc) if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); - uea_leaves(INS_TO_USBDEV(sc)); - return -ENOMEM; + goto err0; } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); if (!sc->urb_int) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); - goto err; + goto err1; } usb_fill_int_urb(sc->urb_int, sc->usb_dev, @@ -2144,7 +2151,7 @@ static int uea_boot(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "urb submition failed with error %d\n", ret); - goto err; + goto err1; } sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); @@ -2158,10 +2165,12 @@ static int uea_boot(struct uea_softc *sc) err2: usb_kill_urb(sc->urb_int); -err: +err1: usb_free_urb(sc->urb_int); sc->urb_int = NULL; kfree(intr); +err0: + destroy_workqueue(sc->work_q); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM; } @@ -2176,15 +2185,15 @@ static void uea_stop(struct uea_softc *sc) ret = kthread_stop(sc->kthread); uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret); - /* stop any pending boot process */ - flush_scheduled_work(); - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); usb_kill_urb(sc->urb_int); kfree(sc->urb_int->transfer_buffer); usb_free_urb(sc->urb_int); + /* stop any pending boot process, when no one can schedule work */ + destroy_workqueue(sc->work_q); + if (sc->dsp_firm) release_firmware(sc->dsp_firm); uea_leaves(INS_TO_USBDEV(sc)); From 337427f91f844ebe84442dc0b5e24577a8139600 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:14 +0200 Subject: [PATCH 2687/2804] UEAGLE: Do not sleep when device is disconnected Do not sleep in kernel thread when device is disconnected, this make faster suspending and module unloading. Use one wait queue for sleeping. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 648c6b79ff41..4aa41a97bf6f 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -161,7 +161,6 @@ struct uea_softc { struct task_struct *kthread; u32 data; u32 data1; - wait_queue_head_t cmv_ack_wait; int cmv_ack; union cmv_dsc cmv_dsc; @@ -558,6 +557,15 @@ module_param_array(annex, uint, NULL, 0644); MODULE_PARM_DESC(annex, "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); +#define uea_wait(sc, cond, timeo) \ +({ \ + int _r = wait_event_interruptible_timeout(sc->sync_q, \ + (cond) || kthread_should_stop(), timeo); \ + if (kthread_should_stop()) \ + _r = -ENODEV; \ + _r; \ +}) + #define UPDATE_ATM_STAT(type, val) \ do { \ if (sc->usbatm->atm_dev) \ @@ -1067,13 +1075,13 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc) { BUG_ON(sc->cmv_ack); sc->cmv_ack = 1; - wake_up(&sc->cmv_ack_wait); + wake_up(&sc->sync_q); } static inline int wait_cmv_ack(struct uea_softc *sc) { - int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, - sc->cmv_ack, ACK_TIMEOUT); + int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT); + sc->cmv_ack = 0; uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", @@ -1806,7 +1814,9 @@ static int uea_start_reset(struct uea_softc *sc) uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL); /* original driver use 200ms, but windows driver use 100ms */ - msleep(100); + ret = uea_wait(sc, 0, msecs_to_jiffies(100)); + if (ret < 0) + return ret; /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); @@ -1818,7 +1828,9 @@ static int uea_start_reset(struct uea_softc *sc) uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); } - msleep(1000); + ret = uea_wait(sc, 0, msecs_to_jiffies(1000)); + if (ret < 0) + return ret; if (UEA_CHIP_VERSION(sc) == EAGLE_IV) sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1); @@ -1868,7 +1880,7 @@ static int uea_kthread(void *data) if (!ret) ret = sc->stat(sc); if (ret != -EAGAIN) - msleep_interruptible(1000); + uea_wait(sc, 0, msecs_to_jiffies(1000)); if (try_to_freeze()) uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " "please unplug/replug your modem\n"); @@ -2116,7 +2128,6 @@ static int uea_boot(struct uea_softc *sc) } init_waitqueue_head(&sc->sync_q); - init_waitqueue_head(&sc->cmv_ack_wait); sc->work_q = create_workqueue("ueagle-dsp"); if (!sc->work_q) { From 0eb0226c9d819fd2af31ae4fc52bbca81c215369 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:19 +0200 Subject: [PATCH 2688/2804] UEAGLE: Cosmetic Update copyrights and remove not necessary warning (ueagle-atm works well on suspend/resume). Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 4aa41a97bf6f..389c5b164eb2 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2,7 +2,8 @@ * Copyright (c) 2003, 2004 * Damien Bergamini . All rights reserved. * - * Copyright (c) 2005 Matthieu Castet + * Copyright (c) 2005-2007 Matthieu Castet + * Copyright (c) 2005-2007 Stanislaw Gruszka * * 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 @@ -1881,9 +1882,7 @@ static int uea_kthread(void *data) ret = sc->stat(sc); if (ret != -EAGAIN) uea_wait(sc, 0, msecs_to_jiffies(1000)); - if (try_to_freeze()) - uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " - "please unplug/replug your modem\n"); + try_to_freeze(); } uea_leaves(INS_TO_USBDEV(sc)); return ret; From af1c51fcb2aea23ec2dfe73b7d66515d1622e689 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 20 Aug 2007 18:13:27 -0700 Subject: [PATCH 2689/2804] USB: EHCI restart speedup It is not necessary to powerdown the ports on ehci_pci_reinit() when the chip reset already did that. Removing this saves 20ms during restart after poweroff paths (which OLPC uses a lot). To ensure driver startup then behaves consistently, force a reset during driver startup. (Not doing this was an accident of some previous changes to the init sequence.) Make the corresponding change in the PS3 support. It's not clear what ehci-fsl should do here; it has similar code to the PS3. Signed-off-by: Marcelo Tosatti Signed-off-by: David Brownell Cc: Acked-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 5 +---- drivers/usb/host/ehci-ps3.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index a7816e392a85..ad0d4965f2fb 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if (!retval) ehci_dbg(ehci, "MWI active\n"); - ehci_port_power(ehci, 0); - return 0; } @@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) break; } - if (ehci_is_TDI(ehci)) - ehci_reset(ehci); + ehci_reset(ehci); /* at least the Genesys GL880S needs fixup here */ temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 829fe649a981..03a6b2f4e6ed 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd) if (result) return result; - ehci_port_power(ehci, 0); + ehci_reset(ehci); return result; } From dfd1e53777afe1050e3a0a3f0dd063a64242b818 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:36:52 -0400 Subject: [PATCH 2690/2804] USB: minor fixes for r8a66597 driver This patch (as967) makes a few relatively minor changes to the r8a66597 driver: finish_request() does nothing but call done(), so merge the two routines. Detect and report -EOVERFLOW errors. Fix the calculation that checks for short packets. Signed-off-by: Alan Stern CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 40 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 94bb229df3bc..49cf998c172a 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1109,8 +1109,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) } /* this function must be called with interrupt disabled */ -static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) +static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, + u16 pipenum, struct urb *urb) +__releases(r8a66597->lock) __acquires(r8a66597->lock) { int restart = 0; struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); @@ -1151,14 +1152,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, } } -/* this function must be called with interrupt disabled */ -static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) -__releases(r8a66597->lock) __acquires(r8a66597->lock) -{ - done(r8a66597, td, pipenum, urb); -} - static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) { u16 tmp; @@ -1167,6 +1160,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); struct urb *urb; int finish = 0; + int status = 0; if (unlikely(!td)) return; @@ -1185,7 +1179,6 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) /* prepare parameters */ rcv_len = tmp & DTLN; - bufsize = td->maxpacket; if (usb_pipeisoc(urb->pipe)) { buf = (u16 *)(urb->transfer_buffer + urb->iso_frame_desc[td->iso_cnt].offset); @@ -1194,25 +1187,30 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf = (void *)urb->transfer_buffer + urb->actual_length; urb_len = urb->transfer_buffer_length - urb->actual_length; } - if (rcv_len < bufsize) - size = min(rcv_len, urb_len); - else - size = min(bufsize, urb_len); + bufsize = min(urb_len, (int) td->maxpacket); + if (rcv_len <= bufsize) { + size = rcv_len; + } else { + size = bufsize; + status = -EOVERFLOW; + finish = 1; + } /* update parameters */ urb->actual_length += size; if (rcv_len == 0) td->zero_packet = 1; - if ((size % td->maxpacket) > 0) { + if (rcv_len < bufsize) { td->short_packet = 1; if (urb->transfer_buffer_length != urb->actual_length && urb->transfer_flags & URB_SHORT_NOT_OK) - td->urb->status = -EREMOTEIO; + status = -EREMOTEIO; } if (usb_pipeisoc(urb->pipe)) { urb->iso_frame_desc[td->iso_cnt].actual_length = size; - urb->iso_frame_desc[td->iso_cnt].status = 0; + urb->iso_frame_desc[td->iso_cnt].status = status; td->iso_cnt++; + finish = 0; } /* check transfer finish */ @@ -1233,7 +1231,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) if (finish && pipenum != 0) { if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; + td->urb->status = status; finish_request(r8a66597, td, pipenum, urb); } } @@ -1807,7 +1805,7 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, td->pipenum); disable_irq_empty(r8a66597, td->pipenum); - done(r8a66597, td, td->pipenum, urb); + finish_request(r8a66597, td, td->pipenum, urb); } done: spin_unlock_irqrestore(&r8a66597->lock, flags); @@ -1841,7 +1839,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, td = r8a66597_get_td(r8a66597, pipenum); if (td) urb = td->urb; - done(r8a66597, td, pipenum, urb); + finish_request(r8a66597, td, pipenum, urb); kfree(hep->hcpriv); hep->hcpriv = NULL; spin_unlock_irqrestore(&r8a66597->lock, flags); From ee7d1f3f0c32d8abe9627aa73dc62ee5bf2daf7f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:37:50 -0400 Subject: [PATCH 2691/2804] USB: remove Iso status value in uhci-hcd This patch (968) changes the way uhci-hcd reports status for Isochronous URBs. Until now urb->status has been set to the last detected error code. But other HCDs don't do this; they leave the status set to 0 and report errors only in the individual iso packet descriptors. So this patch removes the extra computation and makes uhci-hcd behave like the others. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.h | 1 - drivers/usb/host/uhci-q.c | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 1b3d23406ac4..e46d2b0203cb 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -146,7 +146,6 @@ struct uhci_qh { short phase; /* Between 0 and period-1 */ short load; /* Periodic time requirement, in us */ unsigned int iso_frame; /* Frame # for iso_packet_desc */ - int iso_status; /* Status for Isochronous URBs */ int state; /* QH_STATE_xxx; see above */ int type; /* Queue type (control, bulk, etc) */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index bff200cb3d2e..793a04685ef4 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1324,7 +1324,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, if (list_empty(&qh->queue)) { qh->iso_packet_desc = &urb->iso_frame_desc[0]; qh->iso_frame = urb->start_frame; - qh->iso_status = 0; } qh->skel = SKEL_ISO; @@ -1361,18 +1360,15 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) qh->iso_packet_desc->actual_length = actlength; qh->iso_packet_desc->status = status; } - - if (status) { + if (status) urb->error_count++; - qh->iso_status = status; - } uhci_remove_td_from_urbp(td); uhci_free_td(uhci, td); qh->iso_frame += qh->period; ++qh->iso_packet_desc; } - return qh->iso_status; + return 0; } static int uhci_urb_enqueue(struct usb_hcd *hcd, @@ -1517,7 +1513,6 @@ __acquires(uhci->lock) qh->iso_packet_desc = &nurb->iso_frame_desc[0]; qh->iso_frame = nurb->start_frame; - qh->iso_status = 0; } /* Take the URB off the QH's queue. If the queue is now empty, @@ -1586,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) } uhci_giveback_urb(uhci, qh, urb); - if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC) + if (status < 0) break; } From b0d9efba3ec53468984aecef8eeaf079089f2e5a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:39:21 -0400 Subject: [PATCH 2692/2804] USB: centralize -EREMOTEIO handling This patch (as969) continues the ongoing changes to the way HCDs report URB statuses. The programming interface has been simplified by making usbcore responsible for clearing urb->hcpriv and for setting -EREMOTEIO status when an URB with the URB_SHORT_NOT_OK flag ends up as a short transfer. By moving the work out of the HCDs, this removes a fair amount of repeated code. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 9 +++++++-- drivers/usb/gadget/dummy_hcd.c | 9 ++------- drivers/usb/host/ehci-q.c | 7 ++++--- drivers/usb/host/isp116x-hcd.c | 8 +------- drivers/usb/host/ohci-q.c | 11 ----------- drivers/usb/host/r8a66597-hcd.c | 7 +------ drivers/usb/host/sl811-hcd.c | 14 +++----------- drivers/usb/host/u132-hcd.c | 5 ----- drivers/usb/host/uhci-q.c | 8 -------- 9 files changed, 18 insertions(+), 60 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a853f63b9254..22a098b318c0 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -366,6 +366,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) spin_unlock_irq(&hcd_root_hub_lock); if (status) return status; + urb->hcpriv = hcd; /* Indicate it's queued */ cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; @@ -579,7 +580,6 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) hcd->poll_pending = 0; hcd->status_urb = NULL; urb->status = 0; - urb->hcpriv = NULL; urb->actual_length = length; memcpy(urb->transfer_buffer, buffer, length); @@ -675,7 +675,6 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) del_timer (&hcd->rh_timer); if (urb == hcd->status_urb) { hcd->status_urb = NULL; - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); @@ -1192,6 +1191,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); unmap_urb_for_dma(hcd, urb); + urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); if (urb->reject) @@ -1265,6 +1265,11 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); + urb->hcpriv = NULL; + if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + urb->actual_length < urb->transfer_buffer_length && + !urb->status)) + urb->status = -EREMOTEIO; /* pass ownership to the completion handler */ urb->complete (urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c441d10c087e..0cb032526ca2 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1099,8 +1099,7 @@ top: * * partially filling a buffer optionally blocks queue advances * (so completion handlers can clean up the queue) but we don't - * need to emulate such data-in-flight. so we only show part - * of the URB_SHORT_NOT_OK effect: completion status. + * need to emulate such data-in-flight. */ if (is_short) { if (host_len == dev_len) { @@ -1111,10 +1110,7 @@ top: if (dev_len > host_len) maybe_set_status (urb, -EOVERFLOW); else - maybe_set_status (urb, - (urb->transfer_flags - & URB_SHORT_NOT_OK) - ? -EREMOTEIO : 0); + maybe_set_status (urb, 0); } else if (!to_host) { maybe_set_status (urb, 0); if (host_len > dev_len) @@ -1516,7 +1512,6 @@ restart: continue; return_urb: - urb->hcpriv = NULL; list_del (&urbp->urbp_list); kfree (urbp); if (ep) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 1da2de4d34ed..e80b5c417d74 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -232,7 +232,6 @@ __acquires(ehci->lock) } spin_lock (&urb->lock); - urb->hcpriv = NULL; switch (urb->status) { case -EINPROGRESS: /* success */ urb->status = 0; @@ -395,8 +394,10 @@ halt: /* remove it from the queue */ spin_lock (&urb->lock); qtd_copy_status (ehci, urb, qtd->length, token); - do_status = (urb->status == -EREMOTEIO) - && usb_pipecontrol (urb->pipe); + if (unlikely(urb->status == -EREMOTEIO)) { + do_status = usb_pipecontrol(urb->pipe); + urb->status = 0; + } spin_unlock (&urb->lock); if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index f2b5d6281c5d..c2919dbc3f54 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -282,7 +282,6 @@ __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; - urb->hcpriv = NULL; ep->error_count = 0; if (usb_pipecontrol(urb->pipe)) @@ -446,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) if (PTD_GET_ACTIVE(ptd) || (cc != TD_CC_NOERROR && cc < 0x0E)) break; - if ((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length) - status = -EREMOTEIO; - else - status = 0; + status = 0; ep->nextpid = 0; break; default: diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 889c0720743b..8aad6199cdcc 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -43,21 +43,10 @@ __acquires(ohci->lock) // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - urb->hcpriv = NULL; spin_lock (&urb->lock); if (likely (urb->status == -EINPROGRESS)) urb->status = 0; - /* report short control reads right even though the data TD always - * has TD_R set. (much simpler, but creates the 1-td limit.) - */ - if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK) - && unlikely (usb_pipecontrol (urb->pipe)) - && urb->actual_length < urb->transfer_buffer_length - && usb_pipein (urb->pipe) - && urb->status == 0) { - urb->status = -EREMOTEIO; - } spin_unlock (&urb->lock); switch (usb_pipetype (urb->pipe)) { diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 49cf998c172a..60248b01ce14 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -783,7 +783,6 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) if (urb) { urb->status = -ENODEV; - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); @@ -1134,7 +1133,6 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) if (usb_pipeisoc(urb->pipe)) urb->start_frame = r8a66597_get_frame(hcd); - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); @@ -1202,9 +1200,6 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) td->zero_packet = 1; if (rcv_len < bufsize) { td->short_packet = 1; - if (urb->transfer_buffer_length != urb->actual_length && - urb->transfer_flags & URB_SHORT_NOT_OK) - status = -EREMOTEIO; } if (usb_pipeisoc(urb->pipe)) { urb->iso_frame_desc[td->iso_cnt].actual_length = size; @@ -1214,7 +1209,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) } /* check transfer finish */ - if (check_transfer_finish(td, urb)) { + if (finish || check_transfer_finish(td, urb)) { pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); finish = 1; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 15a93f946afd..e90953a9c9fb 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -438,7 +438,6 @@ static void finish_request( spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - urb->hcpriv = NULL; spin_unlock(&urb->lock); usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); @@ -545,17 +544,10 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), buf, len); usb_dotoggle(udev, ep->epnum, 0); - if (urb->actual_length == urb->transfer_buffer_length) + if (urb->actual_length == urb->transfer_buffer_length + || len < ep->maxpacket) urbstat = 0; - else if (len < ep->maxpacket) { - if (urb->transfer_flags & URB_SHORT_NOT_OK) - urbstat = -EREMOTEIO; - else - urbstat = 0; - } - if (usb_pipecontrol(urb->pipe) - && (urbstat == -EREMOTEIO - || urbstat == 0)) { + if (usb_pipecontrol(urb->pipe) && urbstat == 0) { /* NOTE if the status stage STALLs (why?), * this reports the wrong urb status. diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index c87660b5edc3..1381275d448f 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -519,7 +519,6 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; urb->status = status; - urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -560,7 +559,6 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; urb->status = status; - urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -2430,7 +2428,6 @@ static int dequeue_from_overflow_chain(struct u132 *u132, list_del(scan); endp->queue_size -= 1; urb->error_count = 0; - urb->hcpriv = NULL; usb_hcd_giveback_urb(hcd, urb); return 0; } else @@ -2472,7 +2469,6 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, endp->edset_flush = 1; u132_endp_queue_work(u132, endp, 0); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - urb->hcpriv = NULL; return 0; } else { spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); @@ -2517,7 +2513,6 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, irqs); kfree(urbq); } urb->error_count = 0; - urb->hcpriv = NULL; usb_hcd_giveback_urb(hcd, urb); return 0; } else if (list_empty(&endp->urb_more)) { diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 793a04685ef4..fbc3af392c26 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, uhci_free_td(uhci, td); } - urbp->urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } @@ -1494,13 +1493,6 @@ __acquires(uhci->lock) * unlinked first. Regardless, don't confuse people with a * negative length. */ urb->actual_length = max(urb->actual_length, 0); - - /* Report erroneous short transfers */ - if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length && - urb->status == 0)) - urb->status = -EREMOTEIO; } /* When giving back the first URB in an Isochronous queue, From eb23105462304fd35571fd0cab1de7aec79a9ec5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:40:36 -0400 Subject: [PATCH 2693/2804] USB: add urb->unlinked field This patch (as970) adds a new urb->unlinked field, which is used to store the status of unlinked URBs since we can't use urb->status for that purpose any more. To help simplify the HCDs, usbcore will check urb->unlinked before calling the completion handler; if the value is set it will automatically override the status reported by the HCD. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 19 +++-- drivers/usb/gadget/dummy_hcd.c | 8 +-- drivers/usb/host/ehci-q.c | 29 ++++---- drivers/usb/host/isp116x-hcd.c | 5 +- drivers/usb/host/ohci-q.c | 5 +- drivers/usb/host/r8a66597-hcd.c | 24 ++----- drivers/usb/host/sl811-hcd.c | 5 +- drivers/usb/host/u132-hcd.c | 124 ++++++++++++++++---------------- drivers/usb/host/uhci-debug.c | 4 +- drivers/usb/host/uhci-q.c | 9 +-- include/linux/usb.h | 1 + 11 files changed, 108 insertions(+), 125 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 22a098b318c0..ec17fc4d2861 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -532,8 +532,7 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. @@ -1024,6 +1023,7 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: + urb->unlinked = 0; list_add_tail(&urb->urb_list, &urb->ep->urb_list); break; default: @@ -1071,9 +1071,9 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, /* Any status except -EINPROGRESS means something already started to * unlink this URB from the hardware. So there's no more work to do. */ - if (urb->status != -EINPROGRESS) + if (urb->unlinked) return -EBUSY; - urb->status = status; + urb->unlinked = status; /* IRQ setup can easily be broken so that USB controllers * never get completion IRQs ... maybe even the ones we need to @@ -1259,6 +1259,10 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * (and is done using urb->hcpriv). It also released all HCD locks; * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. + * + * If @urb was unlinked, the value of @urb->status will be overridden by + * @urb->unlinked. Erroneous short transfers are detected in case + * the HCD hasn't checked for them. */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { @@ -1266,7 +1270,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); urb->hcpriv = NULL; - if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + if (unlikely(urb->unlinked)) + urb->status = urb->unlinked; + else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && urb->actual_length < urb->transfer_buffer_length && !urb->status)) urb->status = -EREMOTEIO; @@ -1305,8 +1311,7 @@ rescan: list_for_each_entry (urb, &ep->urb_list, urb_list) { int is_in; - /* the urb may already have been unlinked */ - if (urb->status != -EINPROGRESS) + if (urb->unlinked) continue; usb_get_urb (urb); is_in = usb_urb_dir_in(urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 0cb032526ca2..f2b124cf3206 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1029,8 +1029,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) static void maybe_set_status (struct urb *urb, int status) { spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock (&urb->lock); } @@ -1257,10 +1256,9 @@ restart: int type; urb = urbp->urb; - if (urb->status != -EINPROGRESS) { - /* likely it was just unlinked */ + if (urb->unlinked) goto return_urb; - } else if (dum->rh_state != DUMMY_RH_RUNNING) + else if (dum->rh_state != DUMMY_RH_RUNNING) continue; type = usb_pipetype (urb->pipe); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index e80b5c417d74..a8f5408c161d 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -151,7 +151,7 @@ static void qtd_copy_status ( urb->actual_length += length - QTD_LENGTH (token); /* don't modify error codes */ - if (unlikely (urb->status != -EINPROGRESS)) + if (unlikely(urb->unlinked)) return; /* force cleanup after short read; not always an error */ @@ -232,21 +232,14 @@ __acquires(ehci->lock) } spin_lock (&urb->lock); - switch (urb->status) { - case -EINPROGRESS: /* success */ - urb->status = 0; - default: /* fault */ - COUNT (ehci->stats.complete); - break; - case -EREMOTEIO: /* fault or normal */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + if (unlikely(urb->unlinked)) { + COUNT(ehci->stats.unlink); + } else { + if (likely(urb->status == -EINPROGRESS || + (urb->status == -EREMOTEIO && + !(urb->transfer_flags & URB_SHORT_NOT_OK)))) urb->status = 0; - COUNT (ehci->stats.complete); - break; - case -ECONNRESET: /* canceled */ - case -ENOENT: - COUNT (ehci->stats.unlink); - break; + COUNT(ehci->stats.complete); } spin_unlock (&urb->lock); @@ -364,7 +357,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. */ - if (likely (urb->status == -EINPROGRESS)) + if (likely(urb->status == -EINPROGRESS && + !urb->unlinked)) continue; /* issue status after short control reads */ @@ -395,7 +389,8 @@ halt: spin_lock (&urb->lock); qtd_copy_status (ehci, urb, qtd->length, token); if (unlikely(urb->status == -EREMOTEIO)) { - do_status = usb_pipecontrol(urb->pipe); + do_status = (!urb->unlinked && + usb_pipecontrol(urb->pipe)); urb->status = 0; } spin_unlock (&urb->lock); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index c2919dbc3f54..35b3507ff401 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -455,11 +455,10 @@ static void postproc_atl_queue(struct isp116x *isp116x) done: if (status != -EINPROGRESS) { spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock(&urb->lock); } - if (urb->status != -EINPROGRESS) + if (urb->status != -EINPROGRESS || urb->unlinked) finish_request(isp116x, ep, urb); } } diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 8aad6199cdcc..3c793fad178d 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -758,8 +758,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = TD_CC_NOERROR; if (cc != TD_CC_NOERROR && cc < 0x0E) { spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error [cc]; + urb->status = cc_to_error[cc]; spin_unlock (&urb->lock); } @@ -972,7 +971,7 @@ rescan_this: urb = td->urb; urb_priv = td->urb->hcpriv; - if (urb->status == -EINPROGRESS) { + if (!urb->unlinked) { prev = &td->hwNextTD; continue; } diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 60248b01ce14..98b9e0547544 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1118,7 +1118,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) r8a66597->timeout_map &= ~(1 << pipenum); if (likely(td)) { - if (td->set_address && urb->status != 0) + if (td->set_address && (urb->status != 0 || urb->unlinked)) r8a66597->address_map &= ~(1 << urb->setup_packet[2]); pipe_toggle_save(r8a66597, td->pipe, urb); @@ -1225,8 +1225,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) } if (finish && pipenum != 0) { - if (td->urb->status == -EINPROGRESS) - td->urb->status = status; + td->urb->status = status; finish_request(r8a66597, td, pipenum, urb); } } @@ -1308,32 +1307,24 @@ static void check_next_phase(struct r8a66597 *r8a66597) switch (td->type) { case USB_PID_IN: case USB_PID_OUT: - if (urb->status != -EINPROGRESS) { - finish = 1; - break; - } if (check_transfer_finish(td, urb)) td->type = USB_PID_ACK; break; case USB_PID_SETUP: - if (urb->status != -EINPROGRESS) - finish = 1; - else if (urb->transfer_buffer_length == urb->actual_length) { + if (urb->transfer_buffer_length == urb->actual_length) td->type = USB_PID_ACK; - urb->status = 0; - } else if (usb_pipeout(urb->pipe)) + else if (usb_pipeout(urb->pipe)) td->type = USB_PID_OUT; else td->type = USB_PID_IN; break; case USB_PID_ACK: finish = 1; - if (urb->status == -EINPROGRESS) - urb->status = 0; + urb->status = 0; break; } - if (finish) + if (finish || urb->unlinked) finish_request(r8a66597, td, 0, urb); else start_transfer(r8a66597, td); @@ -1418,8 +1409,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) if ((tmp & INBUFM) == 0) { disable_irq_empty(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; + td->urb->status = 0; finish_request(r8a66597, td, pipenum, td->urb); } } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index e90953a9c9fb..f0fa94148d9d 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -436,8 +436,7 @@ static void finish_request( ep->nextpid = USB_PID_SETUP; spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock(&urb->lock); usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); @@ -598,7 +597,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank, status, ep, urbstat); } - if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS)) + if (urb && (urbstat != -EINPROGRESS || urb->unlinked)) finish_request(sl811, ep, urb, urbstat); } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 1381275d448f..db800a434b83 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -645,12 +645,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -716,8 +716,8 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -744,12 +744,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; urb->actual_length += len; endp->toggle_bits = toggle_bits; @@ -768,8 +768,8 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -797,12 +797,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -871,8 +871,8 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -898,18 +898,18 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -936,12 +936,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; u8 *b = buf; @@ -980,8 +980,8 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1007,18 +1007,18 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1045,12 +1045,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { if (usb_pipein(urb->pipe)) { int retval; struct u132_ring *ring = endp->ring; @@ -1077,8 +1077,8 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1106,20 +1106,20 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { u132->addr[0].address = 0; endp->usb_addr = udev->usb_addr; up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1145,12 +1145,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1162,8 +1162,8 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1189,18 +1189,18 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1227,12 +1227,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; @@ -1251,8 +1251,8 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1279,12 +1279,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1296,8 +1296,8 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -2279,8 +2279,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, , u132->going); return -ENODEV; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); return -ESHUTDOWN; } else { u8 usb_addr = usb_pipedevice(urb->pipe); diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 1497371583b9..20cc58b97807 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); out += sprintf(out, " Actlen=%d", urbp->urb->actual_length); - if (urbp->urb->status != -EINPROGRESS) - out += sprintf(out, " Status=%d", urbp->urb->status); + if (urbp->urb->unlinked) + out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked); out += sprintf(out, "\n"); i = nactive = ninactive = 0; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index fbc3af392c26..bab567266559 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1557,15 +1557,12 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) break; spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) /* Not dequeued */ - urb->status = status; - else - status = ECONNRESET; /* Not -ECONNRESET */ + urb->status = status; spin_unlock(&urb->lock); /* Dequeued but completed URBs can't be given back unless * the QH is stopped or has finished unlinking. */ - if (status == ECONNRESET) { + if (urb->unlinked) { if (QH_FINISHED_UNLINKING(qh)) qh->is_stopped = 1; else if (!qh->is_stopped) @@ -1588,7 +1585,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) restart: list_for_each_entry(urbp, &qh->queue, node) { urb = urbp->urb; - if (urb->status != -EINPROGRESS) { + if (urb->unlinked) { /* Fix up the TD links and save the toggles for * non-Isochronous queues. For Isochronous queues, diff --git a/include/linux/usb.h b/include/linux/usb.h index 92d63c6b6fc6..5c7b79088add 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1245,6 +1245,7 @@ struct urb void *hcpriv; /* private data for host controller */ atomic_t use_count; /* concurrent submissions counter */ u8 reject; /* submissions will fail */ + int unlinked; /* unlink error code */ /* public: documented fields in the urb that can be used by drivers */ struct list_head urb_list; /* list head for use by the urb's From ed6e52829c113ca18f042ac55cc77b1b90745eab Mon Sep 17 00:00:00 2001 From: "Andrew M. Bishop" Date: Tue, 21 Aug 2007 19:08:56 +0100 Subject: [PATCH 2694/2804] USB: ftdi_sio: Handle FT232RL devices like FT232BM devices Handle the FT232RL device type in exactly the same way as FT232BM devices (FT232RL detection was added around kernel 2.6.20 but not code for handling it). Signed-off-by: Andrew M. Bishop Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 2d045857b181..e4c248c98e84 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) { + if (priv->chip_type == FT232BM || + priv->chip_type == FT2232C || + priv->chip_type == FT232RL) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) case FT8U232AM: case FT232BM: case FT2232C: + case FT232RL: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, From 1f5a3d0f34fd5719081c6b8f3dbbcbe328d4da31 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 22 Aug 2007 13:06:53 -0400 Subject: [PATCH 2695/2804] USB: fix mistake in usb_hcd_giveback_urb This patch (as971) fixes a small mistake: The URB's completion status needs to be adjusted before the URB is passed to usmon_urb_complete(), not afterward. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ec17fc4d2861..8b17babf5c55 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1266,9 +1266,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete (&hcd->self, urb); - usb_unanchor_urb(urb); urb->hcpriv = NULL; if (unlikely(urb->unlinked)) urb->status = urb->unlinked; @@ -1277,6 +1274,10 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) !urb->status)) urb->status = -EREMOTEIO; + unmap_urb_for_dma(hcd, urb); + usbmon_urb_complete(&hcd->self, urb); + usb_unanchor_urb(urb); + /* pass ownership to the completion handler */ urb->complete (urb); atomic_dec (&urb->use_count); From 6e8fe43b26085a64327d1cbb751ab895f3ad3f5d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 22 Aug 2007 13:08:40 -0400 Subject: [PATCH 2696/2804] USB: avoid the donelist after an error in ohci-hcd This patch (as972) changes ohci-hcd so that after an error occurs, the remaining TDs for the URB will be skipped over entirely instead of going through the donelist. This enables the driver to give back the URB as soon as the error is detected, avoiding the need to store the error status in urb->status. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-q.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 3c793fad178d..860e55ff67a1 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -783,10 +783,10 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) /*-------------------------------------------------------------------------*/ -static inline struct td * -ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) +static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) { struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); @@ -798,13 +798,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) wmb (); ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); - /* put any later tds from this urb onto the donelist, after 'td', - * order won't matter here: no errors, and nothing was transferred. - * also patch the ed so it looks as if those tds completed normally. + /* Get rid of all later tds from this urb. We don't have + * to be careful: no errors and nothing was transferred. + * Also patch the ed so it looks as if those tds completed normally. */ while (tmp != &ed->td_list) { struct td *next; - __hc32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; @@ -819,14 +818,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) * then we need to leave the control STATUS packet queued * and clear ED_SKIP. */ - info = next->hwINFO; - info |= cpu_to_hc32 (ohci, TD_DONE); - info &= ~cpu_to_hc32 (ohci, TD_CC); - next->hwINFO = info; - - next->next_dl_td = rev; - rev = next; + list_del(&next->td_list); + urb_priv->td_cnt++; ed->hwHeadP = next->hwNextTD | toggle; } @@ -852,8 +846,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) hc32_to_cpu (ohci, td->hwINFO), cc, cc_to_error [cc]); } - - return rev; } /* replies to the request have to be on a FIFO basis so @@ -890,7 +882,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) */ if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) - td_rev = ed_halted (ohci, td, cc, td_rev); + ed_halted(ohci, td, cc); td->next_dl_td = td_rev; td_rev = td; From c4e41562e09961df6ba72b49269793d21c0034dc Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:06:48 +0100 Subject: [PATCH 2697/2804] USB: cp2101: Coding style police Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 33f6ee50b8d3..883625126d6b 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -521,7 +521,7 @@ static void cp2101_set_termios (struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if ((!port->tty) || (!port->tty->termios)) { + if (!port->tty || !port->tty->termios) { dbg("%s - no tty structures", __FUNCTION__); return; } From 94d0f7eac77a84da2cee41b8038796891f75f09e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:09:16 +0100 Subject: [PATCH 2698/2804] USB: kobil_sct: Rework driver No hardware but this driver is currently totally broken so we can't make it much worse. Remove all tbe broken invalid termios handling and replace it with a proper set_termios method. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/kobil_sct.c | 144 +++++++++++++-------------------- 1 file changed, 55 insertions(+), 89 deletions(-) diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 02a86dbc0e97..6f224195bd25 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void kobil_read_int_callback( struct urb *urb ); static void kobil_write_callback( struct urb *purb ); +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old); static struct usb_device_id id_table [] = { @@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = { .attach = kobil_startup, .shutdown = kobil_shutdown, .ioctl = kobil_ioctl, + .set_termios = kobil_set_termios, .tiocmget = kobil_tiocmget, .tiocmset = kobil_tiocmset, .open = kobil_open, @@ -137,7 +139,6 @@ struct kobil_private { int cur_pos; // index of the next char to send in buf __u16 device_type; int line_state; - struct ktermios internal_termios; }; @@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial) static int kobil_open (struct usb_serial_port *port, struct file *filp) { - int i, result = 0; + int result = 0; struct kobil_private *priv; unsigned char *transfer_buffer; int transfer_buffer_length = 8; @@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) - // set up internal termios structure - priv->internal_termios.c_iflag = port->tty->termios->c_iflag; - priv->internal_termios.c_oflag = port->tty->termios->c_oflag; - priv->internal_termios.c_cflag = port->tty->termios->c_cflag; - priv->internal_termios.c_lflag = port->tty->termios->c_lflag; - - for (i=0; iinternal_termios.c_cc[i] = port->tty->termios->c_cc[i]; - } - // allocate memory for transfer buffer transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { @@ -607,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, return (result < 0) ? result : 0; } - -static int kobil_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old) { struct kobil_private * priv; int result; unsigned short urb_val = 0; - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - char *settings; - void __user *user_arg = (void __user *)arg; + int c_cflag = port->tty->termios->c_cflag; + speed_t speed; + void * settings; priv = usb_get_serial_port_data(port); - if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) // This device doesn't support ioctl calls - return 0; - } + return; - switch (cmd) { - case TCGETS: // 0x5401 - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (kernel_termios_to_user_termios((struct ktermios __user *)arg, - &priv->internal_termios)) - return -EFAULT; - return 0; - - case TCSETS: // 0x5402 - if (!(port->tty->termios)) { - dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); - return -ENOTTY; - } - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (user_termios_to_kernel_termios(&priv->internal_termios, - (struct ktermios __user *)arg)) - return -EFAULT; - - settings = kzalloc(50, GFP_KERNEL); - if (! settings) { - return -ENOBUFS; - } - - switch (priv->internal_termios.c_cflag & CBAUD) { - case B1200: + switch (speed = tty_get_baud_rate(port->tty)) { + case 1200: urb_val = SUSBCR_SBR_1200; - strcat(settings, "1200 "); break; - case B9600: + case 9600: default: urb_val = SUSBCR_SBR_9600; - strcat(settings, "9600 "); break; - } + } + urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; - urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; - strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit "); + settings = kzalloc(50, GFP_KERNEL); + if (! settings) + return; - if (priv->internal_termios.c_cflag & PARENB) { - if (priv->internal_termios.c_cflag & PARODD) { - urb_val |= SUSBCR_SPASB_OddParity; - strcat(settings, "Odd Parity"); - } else { - urb_val |= SUSBCR_SPASB_EvenParity; - strcat(settings, "Even Parity"); - } + sprintf(settings, "%d ", speed); + + if (c_cflag & PARENB) { + if (c_cflag & PARODD) { + urb_val |= SUSBCR_SPASB_OddParity; + strcat(settings, "Odd Parity"); } else { - urb_val |= SUSBCR_SPASB_NoParity; - strcat(settings, "No Parity"); + urb_val |= SUSBCR_SPASB_EvenParity; + strcat(settings, "Even Parity"); } - dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings ); + } else { + urb_val |= SUSBCR_SPASB_NoParity; + strcat(settings, "No Parity"); + } - result = usb_control_msg( port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0 ), - SUSBCRequest_SetBaudRateParityAndStopBits, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - urb_val, - 0, - settings, - 0, - KOBIL_TIMEOUT - ); + result = usb_control_msg( port->serial->dev, + usb_rcvctrlpipe(port->serial->dev, 0 ), + SUSBCRequest_SetBaudRateParityAndStopBits, + USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, + urb_val, + 0, + settings, + 0, + KOBIL_TIMEOUT + ); + kfree(settings); +} - dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result); - kfree(settings); +static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct kobil_private * priv = usb_get_serial_port_data(port); + unsigned char *transfer_buffer; + int transfer_buffer_length = 8; + int result; + + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) + // This device doesn't support ioctl calls return 0; + switch (cmd) { case TCFLSH: // 0x540B transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); - if (! transfer_buffer) { + if (! transfer_buffer) return -ENOBUFS; - } result = usb_control_msg( port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0 ), @@ -716,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, ); dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result); - kfree(transfer_buffer); - return ((result < 0) ? -EFAULT : 0); - + return (result < 0) ? -EFAULT : 0; + default: + return -ENOIOCTLCMD; } - return -ENOIOCTLCMD; } - static int __init kobil_init (void) { int retval; From 12943f097e5a4a0550f52f98ab8f476435e2ce15 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 16:27:50 -0400 Subject: [PATCH 2699/2804] USB: less-restrictive command checking in g-file-storage This patch (as983) makes a test for minimum-length command sizes in g_file_storage less restrictive. It doesn't matter because commands with bad lengths will be detected later on anyway, and doing it like this makes the driver interoperable with certain buggy hosts such as the JVC HiFi (reported by Samuel Hangouet). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 9998cd7af418..0551140010ee 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2964,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) /* Is the CBW meaningful? */ if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || - cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) { + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); From fdf99c9ec10cb9cd44be3ac0bd007a49ac6dc751 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 23 Aug 2007 15:55:34 -0700 Subject: [PATCH 2700/2804] USB: fix memory leak in berry_charge driver This fixes a small memory leak that happens every time the device is plugged in. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/berry_charge.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c index 92c1d2768df9..24e2dc3148a4 100644 --- a/drivers/usb/misc/berry_charge.c +++ b/drivers/usb/misc/berry_charge.c @@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 2) { dev_err(&udev->dev, "First magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Sending second magic command\n"); @@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 0) { dev_err(&udev->dev, "Second magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Calling set_configuration\n"); @@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); +exit: + kfree(dummy_buffer); return retval; } @@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); + kfree(dummy_buffer); return retval; } From ce0d9325b19555f05b08cbb1ea4c2393eec188ec Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 24 Aug 2007 20:22:52 +0400 Subject: [PATCH 2701/2804] usb-serial: show port number in sysfs Some usb-serial devices (e.g. certain Edgeport models) have more than one serial port on the same USB device/interface. Currently the only way to distinguish these ports in userspace is by their minor device number: the driver makes them consecutive and in stable order. However, for the purpose of stable naming with udev this is insufficient: when udev handles the ADD event for one of the ports it doesn't know what minor number the other one has. To make stable naming easier, export the port number via sysfs. Signed-off-by: Roman Kagan Signed-off-by: Dmitry Guryanov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/bus.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index a47a24f8820d..0b14aea8ebd5 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr return 0; } +static ssize_t show_port_number(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_serial_port *port = to_usb_serial_port(dev); + + return sprintf(buf, "%d\n", port->number - port->serial->minor); +} + +static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL); + static int usb_serial_device_probe (struct device *dev) { struct usb_serial_driver *driver; @@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev) goto exit; } + retval = device_create_file(dev, &dev_attr_port_number); + if (retval) + goto exit; + minor = port->number; tty_register_device (usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, @@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev) return -ENODEV; } + device_remove_file(&port->dev, &dev_attr_port_number); + driver = port->serial->type; if (driver->port_remove) { if (!try_module_get(driver->driver.owner)) { From 092a212e8e3eb49ab7360d652f457d0a360d5383 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Fri, 24 Aug 2007 12:19:22 +0200 Subject: [PATCH 2702/2804] USB: usbmon doc update - mention new wildcard ('0') bus Update usbmon documentation, mentioning the "zero" (wildcard) bus. Possibly, in my first hunk, the 'either ... or ...' should be rephrased a bit to be expressed better. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Pete Zaitcev Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/usbmon.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index 53ae866ae37b..2917ce4ffdc4 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -34,9 +34,12 @@ if usbmon is built into the kernel. Verify that bus sockets are present. # ls /sys/kernel/debug/usbmon -1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u +0s 0t 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u # +Now you can choose to either use the sockets numbered '0' (to capture packets on +all buses), and skip to step #3, or find the bus used by your device with step #2. + 2. Find which bus connects to the desired device Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to @@ -56,6 +59,10 @@ Bus=03 means it's bus 3. # cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out +to listen on a single bus, otherwise, to listen on all buses, type: + +# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out + This process will be reading until killed. Naturally, the output can be redirected to a desirable location. This is preferred, because it is going to be quite long. From b84d2bf07ffb962733ba56307c61539a301a742e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 02:35:14 +0200 Subject: [PATCH 2703/2804] usb: avoid redundant cast of kmalloc() return value in OTi-6858 driver In drivers/usb/serial/oti6858.c::pl2303_buf_alloc() the return value of kmalloc() is being cast to "struct pl2303_buf *", but that need not be done here since kmalloc() returns "void *". Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/oti6858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 64f3f66a7a35..d19861166b50 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) if (size == 0) return NULL; - pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); if (pb == NULL) return NULL; From e7beb667842ad0f6ec95a22e7c88e71dfbd60649 Mon Sep 17 00:00:00 2001 From: Andreas Loibl Date: Fri, 24 Aug 2007 01:51:11 +0200 Subject: [PATCH 2704/2804] usb: serial/pl2303: support for BenQ Siemens Mobile Phone EF81 This patch adds support for the BenQ Mobile Phone EF81 to pl2303 Signed-off-by: Andreas Loibl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f9f85f56f0db..1da57fd9ea23 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index f9a71d0c102e..c39bace5cbcc 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -59,6 +59,7 @@ #define SIEMENS_PRODUCT_ID_SX1 0x0001 #define SIEMENS_PRODUCT_ID_X65 0x0003 #define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 #define SYNTECH_VENDOR_ID 0x0745 #define SYNTECH_PRODUCT_ID 0x0001 From 4d2f110c51eec853c50f68cf068888a77551c8d3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:10 -0400 Subject: [PATCH 2705/2804] USB: reorganize urb->status use in dummy-hcd This patch (as973) reorganizes the way dummy-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 53 +++++++++++++++------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f2b124cf3206..c1af7bab26f0 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1026,16 +1026,10 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) return rc; } -static void maybe_set_status (struct urb *urb, int status) -{ - spin_lock (&urb->lock); - urb->status = status; - spin_unlock (&urb->lock); -} - /* transfer up to a frame's worth; caller must own lock */ static int -transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) +transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, + int *status) { struct dummy_request *req; @@ -1103,15 +1097,15 @@ top: if (is_short) { if (host_len == dev_len) { req->req.status = 0; - maybe_set_status (urb, 0); + *status = 0; } else if (to_host) { req->req.status = 0; if (dev_len > host_len) - maybe_set_status (urb, -EOVERFLOW); + *status = -EOVERFLOW; else - maybe_set_status (urb, 0); + *status = 0; } else if (!to_host) { - maybe_set_status (urb, 0); + *status = 0; if (host_len > dev_len) req->req.status = -EOVERFLOW; else @@ -1125,9 +1119,8 @@ top: req->req.status = 0; if (urb->transfer_buffer_length == urb->actual_length && !(urb->transfer_flags - & URB_ZERO_PACKET)) { - maybe_set_status (urb, 0); - } + & URB_ZERO_PACKET)) + *status = 0; } /* device side completion --> continuable */ @@ -1143,7 +1136,7 @@ top: } /* host side completion --> terminate */ - if (urb->status != -EINPROGRESS) + if (*status != -EINPROGRESS) break; /* rescan to continue with any other queued i/o */ @@ -1254,6 +1247,7 @@ restart: u8 address; struct dummy_ep *ep = NULL; int type; + int status = -EINPROGRESS; urb = urbp->urb; if (urb->unlinked) @@ -1279,7 +1273,7 @@ restart: dev_dbg (dummy_dev(dum), "no ep configured for urb %p\n", urb); - maybe_set_status (urb, -EPROTO); + status = -EPROTO; goto return_urb; } @@ -1294,7 +1288,7 @@ restart: /* NOTE: must not be iso! */ dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", ep->ep.name, urb); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; goto return_urb; } /* FIXME make sure both ends agree on maxpacket */ @@ -1312,7 +1306,7 @@ restart: w_value = le16_to_cpu(setup.wValue); if (le16_to_cpu(setup.wLength) != urb->transfer_buffer_length) { - maybe_set_status (urb, -EOVERFLOW); + status = -EOVERFLOW; goto return_urb; } @@ -1342,7 +1336,7 @@ restart: if (setup.bRequestType != Dev_Request) break; dum->address = w_value; - maybe_set_status (urb, 0); + status = 0; dev_dbg (udc_dev(dum), "set_address = %d\n", w_value); value = 0; @@ -1369,7 +1363,7 @@ restart: if (value == 0) { dum->devstatus |= (1 << w_value); - maybe_set_status (urb, 0); + status = 0; } } else if (setup.bRequestType == Ep_Request) { @@ -1381,7 +1375,7 @@ restart: } ep2->halted = 1; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_CLEAR_FEATURE: @@ -1391,7 +1385,7 @@ restart: dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); value = 0; - maybe_set_status (urb, 0); + status = 0; break; default: value = -EOPNOTSUPP; @@ -1406,7 +1400,7 @@ restart: } ep2->halted = 0; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_GET_STATUS: @@ -1443,7 +1437,7 @@ restart: urb->actual_length = min (2, urb->transfer_buffer_length); value = 0; - maybe_set_status (urb, 0); + status = 0; } break; } @@ -1470,7 +1464,7 @@ restart: dev_dbg (udc_dev(dum), "setup --> %d\n", value); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; urb->actual_length = 0; } @@ -1487,7 +1481,7 @@ restart: * report random errors, to debug drivers. */ limit = max (limit, periodic_bytes (dum, ep)); - maybe_set_status (urb, -ENOSYS); + status = -ENOSYS; break; case PIPE_INTERRUPT: @@ -1501,12 +1495,12 @@ restart: default: treat_control_like_bulk: ep->last_io = jiffies; - total = transfer (dum, urb, ep, limit); + total = transfer(dum, urb, ep, limit, &status); break; } /* incomplete transfer? */ - if (urb->status == -EINPROGRESS) + if (status == -EINPROGRESS) continue; return_urb: @@ -1517,6 +1511,7 @@ return_urb: usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); + urb->status = status; usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); spin_lock (&dum->lock); From 14c04c0f88f228fee1f412be91d6edcb935c78aa Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:19 -0400 Subject: [PATCH 2706/2804] USB: reorganize urb->status use in ehci-hcd This patch (as974) reorganizes the way ehci-hcd sets urb->status. It now keeps the information in a local variable until the last moment. The patch also simplifies the handling of -EREMOTEIO, since the only use of that code is to set the do_status flag. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 62 +++++++++++++++++++---------------- drivers/usb/host/ehci-sched.c | 4 +-- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index a8f5408c161d..794d27e07807 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ -static void qtd_copy_status ( +static int qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, size_t length, u32 token ) { + int status = -EINPROGRESS; + /* count IN/OUT bytes, not SETUP (even short packets) */ if (likely (QTD_PID (token) != 2)) urb->actual_length += length - QTD_LENGTH (token); /* don't modify error codes */ if (unlikely(urb->unlinked)) - return; + return status; /* force cleanup after short read; not always an error */ if (unlikely (IS_SHORT_READ (token))) - urb->status = -EREMOTEIO; + status = -EREMOTEIO; /* serious "can't proceed" faults reported by the hardware */ if (token & QTD_STS_HALT) { if (token & QTD_STS_BABBLE) { /* FIXME "must" disable babbling device's port too */ - urb->status = -EOVERFLOW; + status = -EOVERFLOW; } else if (token & QTD_STS_MMF) { /* fs/ls interrupt xfer missed the complete-split */ - urb->status = -EPROTO; + status = -EPROTO; } else if (token & QTD_STS_DBE) { - urb->status = (QTD_PID (token) == 1) /* IN ? */ + status = (QTD_PID (token) == 1) /* IN ? */ ? -ENOSR /* hc couldn't read data */ : -ECOMM; /* hc couldn't write data */ } else if (token & QTD_STS_XACT) { /* timeout, bad crc, wrong PID, etc; retried */ if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else { ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", urb->dev->devpath, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out"); - urb->status = -EPROTO; + status = -EPROTO; } /* CERR nonzero + no errors + halt --> stall */ } else if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else /* unknown */ - urb->status = -EPROTO; + status = -EPROTO; ehci_vdbg (ehci, "dev%d ep%d%s qtd token %08x --> status %d\n", usb_pipedevice (urb->pipe), usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - token, urb->status); + token, status); /* if async CSPLIT failed, try cleaning out the TT buffer */ - if (urb->status != -EPIPE + if (status != -EPIPE && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) @@ -212,10 +214,12 @@ static void qtd_copy_status ( usb_hub_tt_clear_buffer (urb->dev, urb->pipe); } } + + return status; } static void -ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) +ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) __releases(ehci->lock) __acquires(ehci->lock) { @@ -231,17 +235,13 @@ __acquires(ehci->lock) qh_put (qh); } - spin_lock (&urb->lock); if (unlikely(urb->unlinked)) { COUNT(ehci->stats.unlink); } else { - if (likely(urb->status == -EINPROGRESS || - (urb->status == -EREMOTEIO && - !(urb->transfer_flags & URB_SHORT_NOT_OK)))) - urb->status = 0; + if (likely(status == -EINPROGRESS)) + status = 0; COUNT(ehci->stats.complete); } - spin_unlock (&urb->lock); #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -249,13 +249,14 @@ __acquires(ehci->lock) __FUNCTION__, urb->dev->devpath, urb, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - urb->status, + status, urb->actual_length, urb->transfer_buffer_length); #endif /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); + urb->status = status; usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); spin_lock (&ehci->lock); } @@ -276,6 +277,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qtd *last = NULL, *end = qh->dummy; struct list_head *entry, *tmp; + int last_status = -EINPROGRESS; int stopped; unsigned count = 0; int do_status = 0; @@ -304,6 +306,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) struct ehci_qtd *qtd; struct urb *urb; u32 token = 0; + int qtd_status; qtd = list_entry (entry, struct ehci_qtd, qtd_list); urb = qtd->urb; @@ -311,11 +314,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* clean up any state from previous QTD ...*/ if (last) { if (likely (last->urb != urb)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; } ehci_qtd_free (ehci, last); last = NULL; + last_status = -EINPROGRESS; } /* ignore urbs submitted during completions we reported */ @@ -351,13 +355,13 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) stopped = 1; if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) - urb->status = -ESHUTDOWN; + last_status = -ESHUTDOWN; /* ignore active urbs unless some previous qtd * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. */ - if (likely(urb->status == -EINPROGRESS && + if (likely(last_status == -EINPROGRESS && !urb->unlinked)) continue; @@ -386,14 +390,14 @@ halt: } /* remove it from the queue */ - spin_lock (&urb->lock); - qtd_copy_status (ehci, urb, qtd->length, token); - if (unlikely(urb->status == -EREMOTEIO)) { + qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); + if (unlikely(qtd_status == -EREMOTEIO)) { do_status = (!urb->unlinked && usb_pipecontrol(urb->pipe)); - urb->status = 0; + qtd_status = 0; } - spin_unlock (&urb->lock); + if (likely(last_status == -EINPROGRESS)) + last_status = qtd_status; if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { last = list_entry (qtd->qtd_list.prev, @@ -406,7 +410,7 @@ halt: /* last urb's completion might still need calling */ if (likely (last != NULL)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; ehci_qtd_free (ehci, last); } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 8b267b3fd2bb..80d99bce2b38 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1627,7 +1627,7 @@ itd_complete ( /* give urb back to the driver ... can be out-of-order */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -2000,7 +2000,7 @@ sitd_complete ( /* give urb back to the driver */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ From 55d8496837cf124f68656e4242a5e20eb592fd54 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:34 -0400 Subject: [PATCH 2707/2804] USB: reorganize urb->status use in ohci-hcd This patch (as975) reorganizes the way ohci-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-dbg.c | 8 ++++---- drivers/usb/host/ohci-hcd.c | 15 +++++++-------- drivers/usb/host/ohci-q.c | 38 +++++++++++++++++-------------------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index f61c6cdd06f2..ebab5ce8f5ce 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -24,7 +24,7 @@ * small: 0) header + data packets 1) just header */ static void __maybe_unused -urb_print (struct urb * urb, char * str, int small) +urb_print(struct urb * urb, char * str, int small, int status) { unsigned int pipe= urb->pipe; @@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small) } #ifndef OHCI_VERBOSE_DEBUG - if (urb->status != 0) + if (status != 0) #endif dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", str, @@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_flags, urb->actual_length, urb->transfer_buffer_length, - urb->status); + status); #ifdef OHCI_VERBOSE_DEBUG if (!small) { @@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_buffer_length: urb->actual_length; for (i = 0; i < 16 && i < len; i++) printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); - printk ("%s stat:%d\n", i < len? "...": "", urb->status); + printk ("%s stat:%d\n", i < len? "...": "", status); } } #endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6b06ab69938f..f7c6ced2bc03 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -129,7 +129,7 @@ static int ohci_urb_enqueue ( int retval = 0; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "SUB", usb_pipein (pipe)); + urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); #endif /* every endpoint has a ed, locate and maybe (re)initialize it */ @@ -240,8 +240,8 @@ fail: } /* - * decouple the URB from the HC queues (TDs, urb_priv); it's - * already marked using urb->status. reporting is always done + * decouple the URB from the HC queues (TDs, urb_priv). + * reporting is always done * asynchronously, and we might be dealing with an urb that's * partially transferred, or an ED with other urbs being unlinked. */ @@ -252,7 +252,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) int rc; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "UNLINK", 1); + urb_print(urb, "UNLINK", 1, status); #endif spin_lock_irqsave (&ohci->lock, flags); @@ -277,7 +277,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) * any more ... just clean up every urb's memory. */ if (urb->hcpriv) - finish_urb (ohci, urb); + finish_urb(ohci, urb, status); } spin_unlock_irqrestore (&ohci->lock, flags); return rc; @@ -927,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci) ed, ed->state); } - spin_lock (&urb->lock); - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); + if (!urb->unlinked) + urb->unlinked = -ESHUTDOWN; } finish_unlinks (ohci, 0); spin_unlock_irq(&ohci->lock); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 860e55ff67a1..13d31edd1a86 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -36,18 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) * PRECONDITION: ohci lock held, irqs blocked. */ static void -finish_urb (struct ohci_hcd *ohci, struct urb *urb) +finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - - spin_lock (&urb->lock); - if (likely (urb->status == -EINPROGRESS)) - urb->status = 0; - spin_unlock (&urb->lock); + if (likely(status == -EINPROGRESS)) + status = 0; switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: @@ -59,12 +56,13 @@ __acquires(ohci->lock) } #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "RET", usb_pipeout (urb->pipe)); + urb_print(urb, "RET", usb_pipeout (urb->pipe), status); #endif /* urb->complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); + urb->status = status; usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); spin_lock (&ohci->lock); @@ -702,19 +700,18 @@ static void td_submit_urb ( * Done List handling functions *-------------------------------------------------------------------------*/ -/* calculate transfer length/status and update the urb - * PRECONDITION: irqsafe (only for urb->status locking) - */ -static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) +/* calculate transfer length/status and update the urb */ +static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) { u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO); int cc = 0; + int status = -EINPROGRESS; list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW (ohci, td, 0); + u16 tdPSW = ohci_hwPSW(ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that @@ -723,7 +720,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = (tdPSW >> 12) & 0xF; if (tdINFO & TD_CC) /* hc didn't touch? */ - return; + return status; if (usb_pipeout (urb->pipe)) dlen = urb->iso_frame_desc [td->index].length; @@ -756,11 +753,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR && cc < 0x0E) { - spin_lock (&urb->lock); - urb->status = cc_to_error[cc]; - spin_unlock (&urb->lock); - } + if (cc != TD_CC_NOERROR && cc < 0x0E) + status = cc_to_error[cc]; /* count all non-empty packets except control SETUP packet */ if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { @@ -779,6 +773,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb->actual_length, urb->transfer_buffer_length); } + return status; } /*-------------------------------------------------------------------------*/ @@ -979,7 +974,7 @@ rescan_this: /* if URB is done, clean up */ if (urb_priv->td_cnt == urb_priv->length) { modified = completed = 1; - finish_urb (ohci, urb); + finish_urb(ohci, urb, 0); } } if (completed && !list_empty (&ed->td_list)) @@ -1062,14 +1057,15 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) struct urb *urb = td->urb; urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; + int status; /* update URB's length and status from TD */ - td_done(ohci, urb, td); + status = td_done(ohci, urb, td); urb_priv->td_cnt++; /* If all this urb's TDs are done, call complete() */ if (urb_priv->td_cnt == urb_priv->length) - finish_urb(ohci, urb); + finish_urb(ohci, urb, status); /* clean schedule: unlink EDs that are no longer busy */ if (list_empty(&ed->td_list)) { From 65e51098d9094c7e840b6d6291867b95538d9442 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:47 -0400 Subject: [PATCH 2708/2804] USB: reorganize urb->status use in sl811-hcd This patch (as976) reorganizes the way sl811-hcd sets urb->status. It now keeps the information in a local variable until the last moment. The patch also improves the handling of faults during the status stage of a control transfer, since it no longer needs to retain the error information from the earlier stages. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/sl811-hcd.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index f0fa94148d9d..515152809d37 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -435,11 +435,8 @@ static void finish_request( if (usb_pipecontrol(urb->pipe)) ep->nextpid = USB_PID_SETUP; - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); + urb->status = status; spin_unlock(&sl811->lock); usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); spin_lock(&sl811->lock); @@ -537,27 +534,20 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank + SL11H_XFERCNTREG); if (len > ep->length) { len = ep->length; - urb->status = -EOVERFLOW; + urbstat = -EOVERFLOW; } urb->actual_length += len; sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), buf, len); usb_dotoggle(udev, ep->epnum, 0); - if (urb->actual_length == urb->transfer_buffer_length - || len < ep->maxpacket) - urbstat = 0; - if (usb_pipecontrol(urb->pipe) && urbstat == 0) { - - /* NOTE if the status stage STALLs (why?), - * this reports the wrong urb status. - */ - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = urbstat; - spin_unlock(&urb->lock); - - urb = NULL; - ep->nextpid = USB_PID_ACK; + if (urbstat == -EINPROGRESS && + (len < ep->maxpacket || + urb->actual_length == + urb->transfer_buffer_length)) { + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_ACK; + else + urbstat = 0; } break; case USB_PID_SETUP: @@ -597,7 +587,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank, status, ep, urbstat); } - if (urb && (urbstat != -EINPROGRESS || urb->unlinked)) + if (urbstat != -EINPROGRESS || urb->unlinked) finish_request(sl811, ep, urb, urbstat); } From 888fda47051716765175d0008450126c837adb32 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:41:18 -0400 Subject: [PATCH 2709/2804] USB: reorganize urb->status use in r8a66597-hcd This patch (as977) reorganizes the way r8a66597-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Parts of this patch were written by Yoshihiro Shimoda. Signed-off-by: Alan Stern CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 61 ++++++++++++++++----------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 98b9e0547544..fea6036771f6 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1109,7 +1109,7 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) /* this function must be called with interrupt disabled */ static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) + u16 pipenum, struct urb *urb, int status) __releases(r8a66597->lock) __acquires(r8a66597->lock) { int restart = 0; @@ -1118,7 +1118,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) r8a66597->timeout_map &= ~(1 << pipenum); if (likely(td)) { - if (td->set_address && (urb->status != 0 || urb->unlinked)) + if (td->set_address && (status != 0 || urb->unlinked)) r8a66597->address_map &= ~(1 << urb->setup_packet[2]); pipe_toggle_save(r8a66597, td->pipe, urb); @@ -1135,6 +1135,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); + urb->status = status; spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&r8a66597->lock); @@ -1167,11 +1168,10 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("in fifo not ready (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, -EPIPE); return; } @@ -1224,10 +1224,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf, size); } - if (finish && pipenum != 0) { - td->urb->status = status; - finish_request(r8a66597, td, pipenum, urb); - } + if (finish && pipenum != 0) + finish_request(r8a66597, td, pipenum, urb, status); } static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) @@ -1245,11 +1243,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("out write fifo not ready. (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, urb, -EPIPE); return; } @@ -1294,7 +1291,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) } -static void check_next_phase(struct r8a66597 *r8a66597) +static void check_next_phase(struct r8a66597 *r8a66597, int status) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0); struct urb *urb; @@ -1320,28 +1317,28 @@ static void check_next_phase(struct r8a66597 *r8a66597) break; case USB_PID_ACK: finish = 1; - urb->status = 0; break; } - if (finish || urb->unlinked) - finish_request(r8a66597, td, 0, urb); + if (finish || status != 0 || urb->unlinked) + finish_request(r8a66597, td, 0, urb, status); else start_transfer(r8a66597, td); } -static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum) +static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); - if (td && td->urb) { + if (td) { u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID; if (pid == PID_NAK) - td->urb->status = -ECONNRESET; + return -ECONNRESET; else - td->urb->status = -EPIPE; + return -EPIPE; } + return 0; } static void irq_pipe_ready(struct r8a66597 *r8a66597) @@ -1360,7 +1357,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597) packet_read(r8a66597, 0); else pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1394,7 +1391,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) td = r8a66597_get_td(r8a66597, 0); if (td && td->type != USB_PID_OUT) disable_irq_empty(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1409,8 +1406,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) if ((tmp & INBUFM) == 0) { disable_irq_empty(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - td->urb->status = 0; - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, + 0); } } } @@ -1421,15 +1418,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) u16 check; u16 pipenum; u16 mask; + int status; mask = r8a66597_read(r8a66597, NRDYSTS) & r8a66597_read(r8a66597, NRDYENB); r8a66597_write(r8a66597, ~mask, NRDYSTS); if (mask & NRDY0) { cfifo_change(r8a66597, 0); - set_urb_error(r8a66597, 0); + status = get_urb_error(r8a66597, 0); pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, status); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1440,10 +1438,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) if (unlikely(!td)) continue; - set_urb_error(r8a66597, pipenum); + status = get_urb_error(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); pipe_stop(r8a66597, td->pipe); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, status); } } } @@ -1463,6 +1461,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) u16 intsts0, intsts1, intsts2; u16 intenb0, intenb1, intenb2; u16 mask0, mask1, mask2; + int status; spin_lock(&r8a66597->lock); @@ -1506,12 +1505,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) } if (mask1 & SIGN) { r8a66597_write(r8a66597, ~SIGN, INTSTS1); - set_urb_error(r8a66597, 0); - check_next_phase(r8a66597); + status = get_urb_error(r8a66597, 0); + check_next_phase(r8a66597, status); } if (mask1 & SACK) { r8a66597_write(r8a66597, ~SACK, INTSTS1); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } } if (mask0) { @@ -1790,7 +1789,7 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, td->pipenum); disable_irq_empty(r8a66597, td->pipenum); - finish_request(r8a66597, td, td->pipenum, urb); + finish_request(r8a66597, td, td->pipenum, urb, status); } done: spin_unlock_irqrestore(&r8a66597->lock, flags); @@ -1824,7 +1823,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, td = r8a66597_get_td(r8a66597, pipenum); if (td) urb = td->urb; - finish_request(r8a66597, td, pipenum, urb); + finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN); kfree(hep->hcpriv); hep->hcpriv = NULL; spin_unlock_irqrestore(&r8a66597->lock, flags); From 9347d51c52afcf1a77d2104f162cf8a085624c83 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:41:41 -0400 Subject: [PATCH 2710/2804] USB: reorganize urb->status use in usbmon This patch (as978) reorganizes the way usbmon uses urb->status. It now accepts the status value as an argument. Signed-off-by: Alan Stern Acked-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hcd.h | 10 ++++++---- drivers/usb/mon/mon_bin.c | 10 +++++----- drivers/usb/mon/mon_main.c | 11 ++++++----- drivers/usb/mon/mon_text.c | 10 +++++----- drivers/usb/mon/usb_mon.h | 2 +- 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 8b17babf5c55..4ac021e42cd8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1275,7 +1275,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) urb->status = -EREMOTEIO; unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb); + usbmon_urb_complete(&hcd->self, urb, urb->status); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 745be2566f62..729b7a03acd8 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -413,7 +413,7 @@ static inline void usbfs_cleanup(void) { } struct usb_mon_operations { void (*urb_submit)(struct usb_bus *bus, struct urb *urb); void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); - void (*urb_complete)(struct usb_bus *bus, struct urb *urb); + void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status); /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ }; @@ -432,10 +432,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, (*mon_ops->urb_submit_error)(bus, urb, error); } -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) { if (bus->monitored) - (*mon_ops->urb_complete)(bus, urb); + (*mon_ops->urb_complete)(bus, urb, status); } int usb_mon_register(struct usb_mon_operations *ops); @@ -446,7 +447,8 @@ void usb_mon_deregister(void); static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, int error) {} -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) {} #endif /* CONFIG_USB_MON */ diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 3d6f03819ffd..f06e4e2b49d3 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -386,7 +386,7 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, } static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { const struct usb_endpoint_descriptor *epd = &urb->ep->desc; unsigned long flags; @@ -452,7 +452,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; ep->ts_usec = ts.tv_usec; - ep->status = urb->status; + ep->status = status; ep->len_urb = urb_length; ep->len_cap = length; @@ -475,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, static void mon_bin_submit(void *data, struct urb *urb) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'S'); + mon_bin_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_bin_complete(void *data, struct urb *urb) +static void mon_bin_complete(void *data, struct urb *urb, int status) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'C'); + mon_bin_event(rp, urb, 'C', status); } static void mon_bin_error(void *data, struct urb *urb, int error) diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 2e317bd79e92..b371ffd39d36 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) /* */ -static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) +static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, + int status) { unsigned long flags; struct list_head *pos; @@ -139,18 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); - r->rnf_complete(r->r_data, urb); + r->rnf_complete(r->r_data, urb, status); } spin_unlock_irqrestore(&mbus->lock, flags); } -static void mon_complete(struct usb_bus *ubus, struct urb *urb) +static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) { struct mon_bus *mbus; if ((mbus = ubus->mon_bus) != NULL) - mon_bus_complete(mbus, urb); - mon_bus_complete(&mon_bus0, urb); + mon_bus_complete(mbus, urb, status); + mon_bus_complete(&mon_bus0, urb, status); } /* int (*unlink_urb) (struct urb *urb, int status); */ diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 663a702a17dd..ebb04ac4857b 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -183,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void) } static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { struct mon_event_text *ep; unsigned int stamp; @@ -210,7 +210,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ - ep->status = urb->status; + ep->status = status; if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; @@ -248,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, static void mon_text_submit(void *data, struct urb *urb) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'S'); + mon_text_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_text_complete(void *data, struct urb *urb) +static void mon_text_complete(void *data, struct urb *urb, int status) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'C'); + mon_text_event(rp, urb, 'C', status); } static void mon_text_error(void *data, struct urb *urb, int error) diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index f68ad6d99ad7..f5d84ff8c101 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -46,7 +46,7 @@ struct mon_reader { void (*rnf_submit)(void *data, struct urb *urb); void (*rnf_error)(void *data, struct urb *urb, int error); - void (*rnf_complete)(void *data, struct urb *urb); + void (*rnf_complete)(void *data, struct urb *urb, int status); }; void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); From 4a00027dcb088bf90fa8fb14a7e8ba3506d78f22 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:24 -0400 Subject: [PATCH 2711/2804] USB: Eliminate urb->status usage! This patch (as979) removes the last vestiges of urb->status from the host controller drivers and the root-hub emulator. Now the field doesn't get set until just before the URB's completion routine is called. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 22 ++++++++++---------- drivers/usb/core/hcd.h | 3 ++- drivers/usb/gadget/dummy_hcd.c | 3 +-- drivers/usb/host/ehci-q.c | 3 +-- drivers/usb/host/isp116x-hcd.c | 15 +++++--------- drivers/usb/host/ohci-q.c | 3 +-- drivers/usb/host/r8a66597-hcd.c | 8 +++----- drivers/usb/host/sl811-hcd.c | 3 +-- drivers/usb/host/u132-hcd.c | 36 ++++++++++++++++----------------- drivers/usb/host/uhci-hcd.h | 15 -------------- drivers/usb/host/uhci-q.c | 12 ++++------- 11 files changed, 46 insertions(+), 77 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 4ac021e42cd8..1c5e5d35e08d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -532,7 +532,6 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - urb->status = status; usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. @@ -540,7 +539,7 @@ error: * RT-friendly. */ spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&hcd_root_hub_lock); spin_unlock_irq(&hcd_root_hub_lock); @@ -578,13 +577,12 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) if (urb) { hcd->poll_pending = 0; hcd->status_urb = NULL; - urb->status = 0; urb->actual_length = length; memcpy(urb->transfer_buffer, buffer, length); usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, 0); spin_lock(&hcd_root_hub_lock); } else { length = 0; @@ -677,7 +675,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&hcd_root_hub_lock); } } @@ -1252,6 +1250,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. + * @status: completion status code for the URB. * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its @@ -1260,25 +1259,26 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. * - * If @urb was unlinked, the value of @urb->status will be overridden by + * If @urb was unlinked, the value of @status will be overridden by * @urb->unlinked. Erroneous short transfers are detected in case * the HCD hasn't checked for them. */ -void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) +void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { urb->hcpriv = NULL; if (unlikely(urb->unlinked)) - urb->status = urb->unlinked; + status = urb->unlinked; else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && urb->actual_length < urb->transfer_buffer_length && - !urb->status)) - urb->status = -EREMOTEIO; + !status)) + status = -EREMOTEIO; unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb, urb->status); + usbmon_urb_complete(&hcd->self, urb, status); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ + urb->status = status; urb->complete (urb); atomic_dec (&urb->use_count); if (unlikely (urb->reject)) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 729b7a03acd8..0fc7b95259f5 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -217,7 +217,8 @@ extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); -extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); +extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, + int status); extern void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c1af7bab26f0..58e4d7208805 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1511,8 +1511,7 @@ return_urb: usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); - urb->status = status; - usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); + usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); spin_lock (&dum->lock); goto restart; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 794d27e07807..b10f39c047e9 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -256,8 +256,7 @@ __acquires(ehci->lock) /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); - urb->status = status; - usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); + usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); spin_lock (&ehci->lock); } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 35b3507ff401..c27417f5b9d8 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -277,7 +277,7 @@ static void preproc_atl_queue(struct isp116x *isp116x) processed urbs. */ static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, - struct urb *urb) + struct urb *urb, int status) __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; @@ -291,7 +291,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock) usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); spin_unlock(&isp116x->lock); - usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); + usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status); spin_lock(&isp116x->lock); /* take idle endpoints out of the schedule */ @@ -453,13 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x) } done: - if (status != -EINPROGRESS) { - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - } - if (urb->status != -EINPROGRESS || urb->unlinked) - finish_request(isp116x, ep, urb); + if (status != -EINPROGRESS || urb->unlinked) + finish_request(isp116x, ep, urb, status); } } @@ -853,7 +848,7 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, } if (urb) - finish_request(isp116x, ep, urb); + finish_request(isp116x, ep, urb, status); done: spin_unlock_irqrestore(&isp116x->lock, flags); return rc; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 13d31edd1a86..51817322232b 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -62,8 +62,7 @@ __acquires(ohci->lock) /* urb->complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); - urb->status = status; - usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); + usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status); spin_lock (&ohci->lock); /* stop periodic dma if it's not needed */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fea6036771f6..fd00f1e33fb5 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -782,12 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) kfree(td); if (urb) { - urb->status = -ENODEV; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb); + usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, + -ENODEV); spin_lock(&r8a66597->lock); } break; @@ -1134,10 +1134,8 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) urb->start_frame = r8a66597_get_frame(hcd); usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); - - urb->status = status; spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&r8a66597->lock); } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 515152809d37..94d859aa73f8 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -436,9 +436,8 @@ static void finish_request( ep->nextpid = USB_PID_SETUP; usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); - urb->status = status; spin_unlock(&sl811->lock); - usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); + usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status); spin_lock(&sl811->lock); /* leave active endpoints in the schedule */ diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index db800a434b83..2b379a78d0d5 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -518,7 +518,6 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, unsigned long irqs; struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; - urb->status = status; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -542,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, u132_ring_queue_work(u132, ring, 0); up(&u132->scheduler_lock); u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -558,7 +557,6 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, unsigned long irqs; struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; - urb->status = status; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -575,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, endp->active = 0; spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } usb_hcd_giveback_urb(hcd, urb); + } usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -719,7 +717,7 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -771,7 +769,7 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -874,7 +872,7 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -911,7 +909,7 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -983,7 +981,7 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1020,7 +1018,7 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1080,7 +1078,7 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1121,7 +1119,7 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1165,7 +1163,7 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1202,7 +1200,7 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1254,7 +1252,7 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1299,7 +1297,7 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -2428,7 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132, list_del(scan); endp->queue_size -= 1; urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, 0); return 0; } else continue; @@ -2472,7 +2470,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, return 0; } else { spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, urb->status); + u132_hcd_abandon_urb(u132, endp, urb, status); return 0; } } else { @@ -2513,7 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, irqs); kfree(urbq); } urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { dev_err(&u132->platform_dev->dev, "urb=%p not found in " diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index e46d2b0203cb..340d6ed3e6e9 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -456,21 +456,6 @@ struct urb_priv { }; -/* - * Locking in uhci.c - * - * Almost everything relating to the hardware schedule and processing - * of URBs is protected by uhci->lock. urb->status is protected by - * urb->lock; that's the one exception. - * - * To prevent deadlocks, never lock uhci->lock while holding urb->lock. - * The safe order of locking is: - * - * #1 uhci->lock - * #2 urb->lock - */ - - /* Some special IDs */ #define PCI_VENDOR_ID_GENESYS 0x17a0 diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index bab567266559..e5d60d5b105a 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1480,7 +1480,7 @@ done: * Finish unlinking an URB and give it back */ static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct urb *urb) + struct urb *urb, int status) __releases(uhci->lock) __acquires(uhci->lock) { @@ -1520,7 +1520,7 @@ __acquires(uhci->lock) usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); + usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status); spin_lock(&uhci->lock); /* If the queue is now empty, we can unlink the QH and give up its @@ -1556,10 +1556,6 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) if (status == -EINPROGRESS) break; - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - /* Dequeued but completed URBs can't be given back unless * the QH is stopped or has finished unlinking. */ if (urb->unlinked) { @@ -1569,7 +1565,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) return; } - uhci_giveback_urb(uhci, qh, urb); + uhci_giveback_urb(uhci, qh, urb, status); if (status < 0) break; } @@ -1594,7 +1590,7 @@ restart: qh->is_stopped = 0; return; } - uhci_giveback_urb(uhci, qh, urb); + uhci_giveback_urb(uhci, qh, urb, 0); goto restart; } } From 1431d2a44ccf68a547094976f363f94177ab00c6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:39 -0400 Subject: [PATCH 2712/2804] USB: get rid of urb->lock Now that urb->status isn't used, urb->lock doesn't protect anything. This patch (as980) removes it and replaces it with a private mutex in the one remaining place it was still used: usb_kill_urb. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/urb.c | 11 ++++++----- include/linux/usb.h | 4 ---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 19f5f66c2733..76db76fdb4ec 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -39,7 +39,6 @@ void usb_init_urb(struct urb *urb) if (urb) { memset(urb, 0, sizeof(*urb)); kref_init(&urb->kref); - spin_lock_init(&urb->lock); INIT_LIST_HEAD(&urb->anchor_list); } } @@ -541,19 +540,21 @@ int usb_unlink_urb(struct urb *urb) */ void usb_kill_urb(struct urb *urb) { + static DEFINE_MUTEX(reject_mutex); + might_sleep(); if (!(urb && urb->dev && urb->ep)) return; - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); ++urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); usb_hcd_unlink_urb(urb, -ENOENT); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); --urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); } /** diff --git a/include/linux/usb.h b/include/linux/usb.h index 5c7b79088add..5b14b4c81fd6 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1241,7 +1241,6 @@ struct urb { /* private: usb core and host controller only fields in the urb */ struct kref kref; /* reference count of the URB */ - spinlock_t lock; /* lock for the URB */ void *hcpriv; /* private data for host controller */ atomic_t use_count; /* concurrent submissions counter */ u8 reject; /* submissions will fail */ @@ -1299,7 +1298,6 @@ static inline void usb_fill_control_urb (struct urb *urb, usb_complete_t complete_fn, void *context) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->setup_packet = setup_packet; @@ -1330,7 +1328,6 @@ static inline void usb_fill_bulk_urb (struct urb *urb, usb_complete_t complete_fn, void *context) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer = transfer_buffer; @@ -1366,7 +1363,6 @@ static inline void usb_fill_int_urb (struct urb *urb, void *context, int interval) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer = transfer_buffer; From e015268d2fcfcaef70a1ec535e6381f75aafbf81 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:52 -0400 Subject: [PATCH 2713/2804] USB: remove traces of urb->status from usbcore This patch (as981) removes the remaining nontrivial usages of urb->status from usbcore. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 8 +++++--- drivers/usb/core/hub.c | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b9f1edd6af53..e5ad76b4a738 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -71,6 +71,7 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; + int status; u32 secid; }; @@ -310,9 +311,10 @@ static void async_completed(struct urb *urb) spin_lock(&ps->lock); list_move_tail(&as->asynclist, &ps->async_completed); spin_unlock(&ps->lock); + as->status = urb->status; if (as->signr) { sinfo.si_signo = as->signr; - sinfo.si_errno = as->urb->status; + sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, @@ -1132,7 +1134,7 @@ static int processcompl(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; @@ -1246,7 +1248,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4c495c4d5053..bd08d51d7f41 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -347,11 +347,11 @@ void usb_kick_khubd(struct usb_device *hdev) static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; - int status; + int status = urb->status; int i; unsigned long bits; - switch (urb->status) { + switch (status) { case -ENOENT: /* synchronous unlink */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware going away */ @@ -359,10 +359,10 @@ static void hub_irq(struct urb *urb) default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status); + dev_dbg (hub->intfdev, "transfer --> %d\n", status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; - hub->error = urb->status; + hub->error = status; /* FALL THROUGH */ /* let khubd handle things */ From 63f991b2871bdb1431e8ff62cae2b7b94b4e5b0c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 4 Sep 2007 09:53:24 -0400 Subject: [PATCH 2714/2804] USB: fix location of statement label in dummy-hcd This patch (as984) fixes a rather elementary mistake in dummy_hcd. The new statement label should come before the spin_unlock_irqrestore, not after it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 58e4d7208805..6479a36d6f0e 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1001,8 +1001,8 @@ static int dummy_urb_enqueue ( if (!timer_pending (&dum->timer)) mod_timer (&dum->timer, jiffies + 1); - spin_unlock_irqrestore (&dum->lock, flags); done: + spin_unlock_irqrestore(&dum->lock, flags); return rc; } From d853d872c14b9adc4adad29e56cd378b291f86e0 Mon Sep 17 00:00:00 2001 From: Johann Wilhelm Date: Wed, 5 Sep 2007 13:49:29 +0200 Subject: [PATCH 2715/2804] USB: usb-storage: Initialize Huawei E220 properly This is a reworked version of this patch: http://www.mail-archive.com/linux-usb-devel%40lists.sourceforge.net/msg55094/activate_huawei_dev.patch That properly initializes the HUAWEI E220 devices into multi-port mode. Signed-off-by: Johann Wilhelm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/initializers.c | 14 ++++++++++++++ drivers/usb/storage/initializers.h | 3 +++ drivers/usb/storage/unusual_devs.h | 11 +++++++++++ 3 files changed, 28 insertions(+) diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 3a41740cad97..ee5b42aa5363 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us) return (res ? -1 : 0); } + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us) +{ + int result; + + us->iobuf[0] = 0x1; + result = usb_stor_control_msg(us, us->send_ctrl_pipe, + USB_REQ_SET_FEATURE, + USB_TYPE_STANDARD | USB_RECIP_DEVICE, + 0x01, 0x0, us->iobuf, 0x1, 1000); + US_DEBUGP("usb_control_msg performing result is %d\n", result); + return (result ? 0 : -1); +} diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index e2967a4d48a2..ad3ffd4236c2 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us); /* This function is required to activate all four slots on the UCR-61S2B * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c6b78ba815ea..94b1dd2aeb3b 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1463,6 +1463,17 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by fangxiaozhi + * and by linlei + * Patch reworked by Johann Wilhelm + * This brings the HUAWEI E220 devices into multi-port mode + */ +UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000, + "HUAWEI MOBILE", + "Mass Storage", + US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init, + 0), + /* Reported by Vilius Bilinkevicius Date: Thu, 6 Sep 2007 23:18:15 +0200 Subject: [PATCH 2716/2804] USB: ELAN U132 Host Controller Driver: convert sw_lock to mutex The ELAN U132 Host Controller Driver uses the semaphore sw_lock as mutex. Use the mutex API instead of the (binary) semaphore. Signed-off-by: Matthias Kaehlcke Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 2b379a78d0d5..ac283b09a63f 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -183,7 +183,7 @@ struct u132_ring { struct u132 { struct kref kref; struct list_head u132_list; - struct semaphore sw_lock; + struct mutex sw_lock; struct semaphore scheduler_lock; struct u132_platform_data *board; struct platform_device *platform_dev; @@ -492,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work) return; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = read_roothub_info(u132); if (retval) { struct usb_hcd *hcd = u132_to_hcd(u132); u132_disable(u132); u132->going = 1; - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_hc_died(hcd); ftdi_elan_gone_away(u132->platform_dev); u132_monitor_put_kref(u132); return; } else { u132_monitor_requeue_work(u132, 500); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } } @@ -1802,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd) dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); } else { - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(100); u132_power(u132, 0); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); } } @@ -1827,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) (pdev->dev.platform_data))->vendor; u16 device = ((struct u132_platform_data *) (pdev->dev.platform_data))->device; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(10); if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { u132->flags = OHCI_QUIRK_AMD756; @@ -1842,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) u132->going = 1; } msleep(100); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } else { dev_err(&u132->platform_dev->dev, "platform_device missing\n"); @@ -1862,13 +1862,13 @@ static int u132_hcd_reset(struct usb_hcd *hcd) return -ESHUTDOWN; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = u132_init(u132); if (retval) { u132_disable(u132); u132->going = 1; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } @@ -2865,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, return -ESHUTDOWN; } else { int retval = 0; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); switch (typeReq) { case ClearHubFeature: switch (wValue) { @@ -2928,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, stall:retval = -EPIPE; break; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } @@ -3064,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev) dev_err(&u132->platform_dev->dev, "removing device u132" ".%d\n", u132->sequence_num); msleep(100); - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); u132_monitor_cancel_work(u132); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3077,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev) u132->going += 1; printk(KERN_INFO "removing device u132.%d\n", u132->sequence_num); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_remove_hcd(hcd); u132_u132_put_kref(u132); return 0; @@ -3097,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) u132->platform_dev = pdev; u132->power = 0; u132->reset = 0; - init_MUTEX(&u132->sw_lock); + mutex_init(&u132->sw_lock); init_MUTEX(&u132->scheduler_lock); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3107,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) ring->curr_endp = NULL; INIT_DELAYED_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler); - } down(&u132->sw_lock); + } mutex_lock(&u132->sw_lock); INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); while (ports-- > 0) { struct u132_port *port = &u132->port[ports]; @@ -3137,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) while (endps-- > 0) { u132->endp[endps] = NULL; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } From 5adceac5da3d353dd1318d0482cab94a79472adf Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 17 Aug 2007 14:01:38 +0200 Subject: [PATCH 2717/2804] USB: fix errornous assumption in the usb serial framework revealed by iuu_phoenix the iuu_phoenix driver submits another URB from a completion handler. This dictates a certain order of calls to usb_kill_urb() in kill_traffic(). As other drivers may do it the other way round, we need to use both orders in kill_traffic(). This patch does so and should be merged before iuu_phoenix is merged. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 9bf01a5efc84..26e015c39a31 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); + /* + * This is tricky. + * Some drivers submit the read_urb in the + * handler for the write_urb or vice versa + * this order determines the order in which + * usb_kill_urb() must be used to reliably + * kill the URBs. As it is unknown here, + * both orders must be used in turn. + * The call below is not redundant. + */ + usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); } From e6d42f0e962390e956545aa282efb05a9d6a41d1 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Mon, 3 Sep 2007 01:37:31 +0530 Subject: [PATCH 2718/2804] USB: sisusbvga: Fix bug drivers/usb/misc/sisusbvga/sisusb.c: In function sisusb_open drivers/usb/misc/sisusbvga/sisusb.c:2444: warning: sisusb is used uninitialized in this function is a genuine bug (which will cause oops). We cannot use "sisusb" in error path for (!interface), because sisusb will itself be derived from "interface" later. Signed-off-by: Satyam Sharma Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 4d6b89336e63..033bdfe9b215 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2440,10 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file) struct usb_interface *interface; int subminor = iminor(inode); - if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to find interface\n"); + if (!(interface = usb_find_interface(&sisusb_driver, subminor))) return -ENODEV; - } if (!(sisusb = usb_get_intfdata(interface))) return -ENODEV; From 1d3ee41e9549609a6151216a0bcb06b758a64b6b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:16:13 -0700 Subject: [PATCH 2719/2804] USB: AMD5536: use pdev->revision Signed-off-by: Auke Kok Cc: Thomas Dahlmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index e95ffc9eee3d..bdd5f2284b3a 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3285,14 +3285,12 @@ static int udc_pci_probe( pci_set_drvdata(pdev, dev); - /* chip revision */ - dev->chiprev = 0; + /* chip revision for Hs AMD5536 */ + dev->chiprev = pdev->revision; pci_set_master(pdev); pci_set_mwi(pdev); - /* chip rev for Hs AMD5536 */ - pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev); /* init dma pools */ if (use_dma) { retval = init_dma_pools(dev); From 7477120e34eef65a530cfb3fea5fe612c89669e5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:35:14 -0400 Subject: [PATCH 2720/2804] USB: Get rid of annoying endpoint-release message This patch (as990) removes an annoying debugging message. Nobody really cares when endpoint pseudo-devices are released. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/endpoint.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index e0ec7045e865..7dc123d6b2d0 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev) { struct ep_device *ep_dev = to_ep_device(dev); - dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); endpoint_free_minor(ep_dev); kfree(ep_dev); } From 5ad4f71e2f19a06f738463da1f09ea7fda3a3db2 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:31:43 -0400 Subject: [PATCH 2721/2804] USB: move decision to ignore FREEZE events This patch (as987) changes the way FREEZE and PRETHAW suspend events are handled in usbcore. The decision about whether or not to ignore them for non-root devices is pushed down into the USB-device driver, instead of being made in the core code. This is appropriate, since devices exported to a virtualized guest or over a network may indeed need to handle these types of suspend, even though normal devices don't. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 9 +-------- drivers/usb/core/generic.c | 5 +++++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8da4801bb922..ca43a6f824ab 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1088,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) break; } } - if (status == 0) { - - /* Non-root devices don't need to do anything for FREEZE - * or PRETHAW. */ - if (udev->parent && (msg.event == PM_EVENT_FREEZE || - msg.event == PM_EVENT_PRETHAW)) - goto done; + if (status == 0) status = usb_suspend_device(udev, msg); - } /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 9148b69785c5..c1cb94e9f242 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -206,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) */ if (!udev->parent) rc = hcd_bus_suspend(udev); + + /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ + else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + rc = 0; else rc = usb_port_suspend(udev); + return rc; } From 95cf82f99cfbd697c15572c444bd4f54f19745b0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:33:05 -0400 Subject: [PATCH 2722/2804] USB: break apart flush_endpoint and disable_endpoint This patch (as988) breaks usb_hcd_endpoint_disable() apart into two routines. The first, usb_hcd_flush_endpoint() does the -ESHUTDOWN unlinking of all URBs in the endpoint's queue and waits for them to complete. The second, usb_hcd_disable_endpoint() -- renamed for better grammatical style -- merely calls the HCD's endpoint_disable method. The changeover is easy because the routine currently has only one caller. This separation of function will be exploited in the following patch: When a device is suspended, the core will be able to cancel all outstanding URBs for that device while leaving the HCD's endpoint-related data structures intact for later. As an added benefit, HCDs no longer need to check for existing URBs in their endpoint_disable methods. It is now guaranteed that there will be none. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 48 +++++++++++++++++++++----------------- drivers/usb/core/hcd.h | 4 +++- drivers/usb/core/message.c | 3 ++- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1c5e5d35e08d..e5874e8b8cbc 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1289,24 +1289,22 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb); /*-------------------------------------------------------------------------*/ -/* disables the endpoint: cancels any pending urbs, then synchronizes with - * the hcd to make sure all endpoint state is gone from hardware, and then - * waits until the endpoint's queue is completely drained. use for - * set_configuration, set_interface, driver removal, physical disconnect. - * - * example: a qh stored in ep->hcpriv, holding state related to endpoint - * type, maxpacket size, toggle, halt status, and scheduling. +/* Cancel all URBs pending on this endpoint and wait for the endpoint's + * queue to drain completely. The caller must first insure that no more + * URBs can be submitted for this endpoint. */ -void usb_hcd_endpoint_disable (struct usb_device *udev, +void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep) { struct usb_hcd *hcd; struct urb *urb; + if (!ep) + return; might_sleep(); hcd = bus_to_hcd(udev->bus); - /* ep is already gone from udev->ep_{in,out}[]; no more submits */ + /* No more submits can occur */ rescan: spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { @@ -1345,18 +1343,7 @@ rescan: } spin_unlock_irq(&hcd_urb_list_lock); - /* synchronize with the hardware, so old configuration state - * clears out immediately (and will be freed). - */ - if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable (hcd, ep); - - /* Wait until the endpoint queue is completely empty. Most HCDs - * will have done this already in their endpoint_disable method, - * but some might not. And there could be root-hub control URBs - * still pending since they aren't affected by the HCDs' - * endpoint_disable methods. - */ + /* Wait until the endpoint queue is completely empty */ while (!list_empty (&ep->urb_list)) { spin_lock_irq(&hcd_urb_list_lock); @@ -1376,6 +1363,25 @@ rescan: } } +/* Disables the endpoint: synchronizes with the hcd to make sure all + * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must + * have been called previously. Use for set_configuration, set_interface, + * driver removal, physical disconnect. + * + * example: a qh stored in ep->hcpriv, holding state related to endpoint + * type, maxpacket size, toggle, halt status, and scheduling. + */ +void usb_hcd_disable_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct usb_hcd *hcd; + + might_sleep(); + hcd = bus_to_hcd(udev->bus); + if (hcd->driver->endpoint_disable) + hcd->driver->endpoint_disable(hcd, ep); +} + /*-------------------------------------------------------------------------*/ /* called in any context */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 0fc7b95259f5..1396141274f1 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -219,7 +219,9 @@ extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status); -extern void usb_hcd_endpoint_disable (struct usb_device *udev, +extern void usb_hcd_flush_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); +extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d638375e22e7..98fcddba6908 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1017,7 +1017,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) } if (ep) { ep->enabled = 0; - usb_hcd_endpoint_disable(dev, ep); + usb_hcd_flush_endpoint(dev, ep); + usb_hcd_disable_endpoint(dev, ep); } } From 6840d2555afd66290be7a39b400b5e66a840b82d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:34:26 -0400 Subject: [PATCH 2723/2804] USB: flush outstanding URBs when suspending This patch (as989) makes usbcore flush all outstanding URBs for each device as the device is suspended. This will be true even when CONFIG_USB_SUSPEND is not enabled. In addition, an extra can_submit flag is added to the usb_device structure. That flag will be turned off whenever a suspend request has been received for the device, even if the device isn't actually suspended because CONFIG_USB_SUSPEND isn't set. It's no longer necessary to check for the device state being equal to USB_STATE_SUSPENDED during URB submission; that check can be replaced by a check of the can_submit flag. This also permits us to remove some questionable references to the deprecated power.power_state field. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 10 +++++++++- drivers/usb/core/hcd.c | 5 +++++ drivers/usb/core/hub.c | 9 +-------- drivers/usb/core/urb.c | 3 --- drivers/usb/core/usb.c | 1 + include/linux/usb.h | 1 + 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ca43a6f824ab..ba5bbc7eedcc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1102,9 +1102,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) if (udev->auto_pm) autosuspend_check(udev); - /* If the suspend succeeded, propagate it up the tree */ + /* If the suspend succeeded then prevent any more URB submissions, + * flush any outstanding URBs, and propagate the suspend up the tree. + */ } else { cancel_delayed_work(&udev->autosuspend); + udev->can_submit = 0; + for (i = 0; i < 16; ++i) { + usb_hcd_flush_endpoint(udev, udev->ep_out[i]); + usb_hcd_flush_endpoint(udev, udev->ep_in[i]); + } if (parent) usb_autosuspend_device(parent); } @@ -1154,6 +1161,7 @@ static int usb_resume_both(struct usb_device *udev) status = -ENODEV; goto done; } + udev->can_submit = 1; /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e5874e8b8cbc..2c79aa6ca2b4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1014,6 +1014,11 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) goto done; } + if (unlikely(!urb->dev->can_submit)) { + rc = -EHOSTUNREACH; + goto done; + } + /* * Check the host controller's state and add the URB to the * endpoint's queue. diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bd08d51d7f41..691acf2223c2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1955,14 +1955,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && msg.event == PM_EVENT_SUSPEND && -#ifdef CONFIG_USB_SUSPEND - udev->state != USB_STATE_SUSPENDED -#else - udev->dev.power.power_state.event - == PM_EVENT_ON -#endif - ) { + if (udev && udev->can_submit) { if (!hdev->auto_pm) dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 76db76fdb4ec..c20c03aaf012 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -286,9 +286,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) return -EINVAL; if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) return -ENODEV; - if (dev->bus->controller->power.power_state.event != PM_EVENT_ON - || dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; /* For now, get the endpoint from the pipe. Eventually drivers * will be required to set urb->ep directly and we will eliminate diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e5ff161776fa..8121edbd1494 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -272,6 +272,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ usb_enable_endpoint(dev, &dev->ep0); + dev->can_submit = 1; /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The diff --git a/include/linux/usb.h b/include/linux/usb.h index 5b14b4c81fd6..e5b35e0dca23 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -383,6 +383,7 @@ struct usb_device { u8 portnum; /* Parent port number (origin 1) */ u8 level; /* Number of USB hub ancestors */ + unsigned can_submit:1; /* URBs may be submitted */ unsigned discon_suspended:1; /* Disconnected while suspended */ unsigned have_langid:1; /* whether string_langid is valid */ unsigned authorized:1; /* Policy has determined we can use it */ From f7294055a7a5bf1ea7da16dffb0cb0f7a282c04b Mon Sep 17 00:00:00 2001 From: Mark Gross Date: Mon, 24 Sep 2007 09:28:14 -0700 Subject: [PATCH 2724/2804] USB: usb-skeleton leaking locks on open This weekend I was hacking around with a trivial USB driver for talking to the boot load firmware of a USB Bit Whacker. It's running the MicroChip Pic18 boot loader firmware and I'm putting together a flash program for writing new FW to the thing. Anyway in my use of the usb-skeleton.c as my starting point I discovered my test program was getting hung up after attempting to write a buffer. The application and driver where hung in a way that required me to reboot to get it to clean up so I could try again. It turned out the code path through skel_open can grap the driver's io_mutex lock and forget to release it. The following patch fixes the problem for me. Signed-off-by: Mark Gross Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 8de11deb5d14..c815a40e167f 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file) /* save our object in the file's private structure */ file->private_data = dev; + mutex_unlock(&dev->io_mutex); exit: return retval; From 0e66fb3492442faa17fc7f27a3eba35b3c811e38 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 11 Sep 2007 19:10:21 +0200 Subject: [PATCH 2725/2804] USB: always visit drivers/usb/misc/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, every driver under drivers/usb/misc/ also has to be listed in drivers/usb/Makefile. This has been forgotten more than once, and this patch changes drivers/usb/Makefile to simply always visit drivers/usb/misc/ when building the USB code. Signed-off-by: Adrian Bunk Cc: Toralf Fรถrster Acked-by: Satyam Sharma Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index cce216517ca1..516a6400db43 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -28,28 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ -obj-$(CONFIG_USB_ADUTUX) += misc/ -obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ -obj-$(CONFIG_USB_AUERSWALD) += misc/ -obj-$(CONFIG_USB_BERRY_CHARGE) += misc/ -obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ -obj-$(CONFIG_USB_CYTHERM) += misc/ -obj-$(CONFIG_USB_EMI26) += misc/ -obj-$(CONFIG_USB_EMI62) += misc/ -obj-$(CONFIG_USB_FTDI_ELAN) += misc/ -obj-$(CONFIG_USB_IDMOUSE) += misc/ -obj-$(CONFIG_USB_IOWARRIOR) += misc/ -obj-$(CONFIG_USB_LCD) += misc/ -obj-$(CONFIG_USB_LD) += misc/ -obj-$(CONFIG_USB_LED) += misc/ -obj-$(CONFIG_USB_LEGOTOWER) += misc/ -obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ -obj-$(CONFIG_USB_RIO500) += misc/ -obj-$(CONFIG_USB_SISUSBVGA) += misc/ -obj-$(CONFIG_USB_TEST) += misc/ -obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ -obj-$(CONFIG_USB_USS720) += misc/ -obj-$(CONFIG_USB_IOWARRIOR) += misc/ +obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ From ed6590a861a16276db34ee626375fa79f3369ac3 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 17 Sep 2007 20:15:53 +0200 Subject: [PATCH 2726/2804] USB: fix double frees in error code paths of ipaq driver the error code paths can be enter with buffers to freed buffers. Serial core would do a kfree() on memory already freed. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 6a3a704b5849..c1a6484f6524 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -646,11 +646,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) kfree(port->bulk_out_buffer); port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_in_buffer == NULL) { + port->bulk_out_buffer = NULL; /* prevent double free */ goto enomem; } port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_out_buffer == NULL) { kfree(port->bulk_in_buffer); + port->bulk_in_buffer = NULL; goto enomem; } port->read_urb->transfer_buffer = port->bulk_in_buffer; From 403fae78d7388876b96fbe30ccf2cb551c49ae5a Mon Sep 17 00:00:00 2001 From: jidong xiao Date: Fri, 14 Sep 2007 00:08:51 +0800 Subject: [PATCH 2727/2804] USB: fix limited_power setting mistake in hub.c This patch (jx001) fixes a variable assignment mistake in hub driver. limited_power should be set to 0 if the hub is self-powered,and 1 if the hub is bus-powered. However, the effect of the code was exactly opposite to the spec's statement for the Local Power Source field. The spec says, this field is 1 meaning Local power supply lost while this field is 0 indicating Local power supply good.(This statement is very confusing.) So this patch switchs the 0 and 1. Signed-off-by: Jason Xiao Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 691acf2223c2..481dca641ea2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2818,9 +2818,9 @@ static void hub_events(void) clear_hub_feature(hdev, C_HUB_LOCAL_POWER); if (hubstatus & HUB_STATUS_LOCAL_POWER) /* FIXME: Is this always true? */ - hub->limited_power = 0; - else hub->limited_power = 1; + else + hub->limited_power = 0; } if (hubchange & HUB_CHANGE_OVERCURRENT) { dev_dbg (hub_dev, "overcurrent change\n"); From 393e5511a5f58e82b88589f1dd2464f6b661df06 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 18 Sep 2007 10:09:32 -0400 Subject: [PATCH 2728/2804] USB: unusual_devs update for Nokia 6131 This patch (as991) updates the unusual_devs entry for the Nokia 6131 phone. As reported by Juan Ignacio Cherrutti, there's new firmware available but it still has the same old transfer-size limit. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 94b1dd2aeb3b..b0ff02955804 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -198,7 +198,7 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), /* Reported by Bardur Arantsson */ -UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, +UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610, "Nokia", "6131", US_SC_DEVICE, US_PR_DEVICE, NULL, From 7108f28465a0a37d5afc05c5ad788938423b74a7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 20 Sep 2007 12:37:50 -0400 Subject: [PATCH 2729/2804] USB: don't propagate FREEZE or PRETHAW suspends This patch (as992) fixes a recently-added bug. During a FREEZE or PRETHAW suspend notification, non-root devices don't actually get suspended. So we shouldn't tell their parent hubs that they did. (This code path used to be skipped over, until the FREEZE/PRETHAW test got moved out of usb_suspend_both() into generic_suspend().) Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ba5bbc7eedcc..3f734240e0ec 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1112,7 +1112,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) usb_hcd_flush_endpoint(udev, udev->ep_out[i]); usb_hcd_flush_endpoint(udev, udev->ep_in[i]); } - if (parent) + + /* If this is just a FREEZE or a PRETHAW, udev might + * not really be suspended. Only true suspends get + * propagated up the device tree. + */ + if (parent && udev->state == USB_STATE_SUSPENDED) usb_autosuspend_device(parent); } From a691efa9888e71232dfb4088fb8a8304ffc7b0f9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 21 Sep 2007 16:57:54 -0400 Subject: [PATCH 2730/2804] USB: remove USB_QUIRK_NO_AUTOSUSPEND This patch (as995) cleans up the remains of the former NO_AUTOSUSPEND quirk. Since autosuspend is disabled by default, we will let userspace worry about which devices can safely be suspended. Thus the lengthy series of quirk entries is no longer needed, and neither is the quirk ID. I suppose someone might eventually run across a hub that can't be suspended; let's ignore the possibility for now. The patch also cleans up the hasty way in which autosuspend gets disabled. Setting udev->autosuspend_delay to -1 wasn't quite right, because the value is always supposed to be a multiple of HZ. It's better to leave the delay value alone and set autosuspend_disabled, which is what the quirk routine used to do. Signed-off-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 81 +------------------------------------- include/linux/usb/quirks.h | 7 +--- 2 files changed, 3 insertions(+), 85 deletions(-) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ebf3dc20110a..d42c561c75f1 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, /* HP 5300/5370C scanner */ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, - /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */ - { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* SGS Thomson Microelectronics 4in1 card reader */ - { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */ - { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Benq S2W 3300U */ - { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N1240U/LiDE30 */ - { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N650U/N656U */ - { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan 1220U */ - { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */ - { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* old Cannon scanner */ - { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 1200 */ - { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 660 */ - { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Epson Perfection 1260 Photo */ - { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp - Perfection 1670 */ - { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* EPSON Perfection 2480 */ - { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp.*/ - { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2010 printer */ - { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2510 Series printer */ - { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Elsa MicroLink 56k (V.250) */ - { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Ultima Electronics Corp.*/ - { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Genesys USB-to-IDE */ - { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* USB Graphical LCD - EEH Datalink GmbH */ - { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = { /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Agfa Snapscan1212u */ - { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seagate RSS LLC */ - { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Umax [hex] Astra 3400U */ - { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Alcor multi-card reader */ - { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Canon EOS 5D in PC Connection mode */ - { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* RIM Blackberry */ - { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Apple iPhone */ - { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, { } /* terminating entry must be last */ }; -static void usb_autosuspend_quirk(struct usb_device *udev) -{ -#ifdef CONFIG_USB_SUSPEND - /* disable autosuspend, but allow the user to re-enable it via sysfs */ - udev->autosuspend_disabled = 1; -#endif -} - static const struct usb_device_id *find_id(struct usb_device *udev) { const struct usb_device_id *id = usb_quirk_list; @@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev) dev_dbg(&udev->dev, "USB quirks for this device: %x\n", udev->quirks); - /* do any special quirk handling here if needed */ - if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND) - usb_autosuspend_quirk(udev); - /* By default, disable autosuspend for all non-hubs */ #ifdef CONFIG_USB_SUSPEND if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) - udev->autosuspend_delay = -1; + udev->autosuspend_disabled = 1; #endif } diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 8da374caf582..2692ec9389ca 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -4,11 +4,8 @@ * belong here. */ -/* device must not be autosuspended */ -#define USB_QUIRK_NO_AUTOSUSPEND 0x00000001 - /* string descriptors must not be fetched using a 255-byte read */ -#define USB_QUIRK_STRING_FETCH_255 0x00000002 +#define USB_QUIRK_STRING_FETCH_255 0x00000001 /* device can't resume correctly so reset it instead */ -#define USB_QUIRK_RESET_RESUME 0x00000004 +#define USB_QUIRK_RESET_RESUME 0x00000002 From 16eb345f4d9189b59bae576ae63cba7ca77817b2 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Sat, 22 Sep 2007 20:58:12 -0700 Subject: [PATCH 2731/2804] USB: unusual_devs modification for Nikon D200 Upgrade the unusual_devs.h file to support the Nikon D200 Signed-off-by: Mike Pagano Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b0ff02955804..5129b538be90 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -341,6 +341,13 @@ UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Graber and Mike Pagano */ +UNUSUAL_DEV( 0x04b0, 0x040f, 0x0200, 0x0200, + "NIKON", + "NIKON DSC D200", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Reported by Emil Larsson */ UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101, "NIKON", From 1f4f714f88955cfb61fba0cd43fe3b07e4212257 Mon Sep 17 00:00:00 2001 From: Edouard Lafargue Date: Tue, 25 Sep 2007 10:15:36 +0200 Subject: [PATCH 2732/2804] USB: cp2101.c: add additional device ID This patch adds an additional device ID to the cp2101 USB serial driver. This device is a Gemalto Prox-PU or CU contactless card reader (ISO14443-A/B and Mifare). The reader is a standard Gemalto serial proximity reader using the Gemalto Block Protocol (see reader's documentation) bundled with a built-in CP2102 for serial/USB conversion. Signed-off-by: Edouard Lafargue (edouard@lafargue.name) Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 883625126d6b..eb7df1835c11 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*); static int debug; static struct usb_device_id id_table [] = { + { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ From 4ac0718e83821db53451614e098399004694aa81 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Tue, 25 Sep 2007 20:20:10 +0100 Subject: [PATCH 2733/2804] USB: cxacru: Use appropriate logging for errors When an error occurs, existing logging uses dbg() so the cause of a problem is hard to determine. Error conditions shouldn't only be properly reported with debugging enabled. A side effect of this change is that when an uninitialised device is started, a log message similar to the following is sent: cxacru 5-2:1.0: receive of cm 0x90 failed (-104) This is normal - the device did not respond so firmware will be loaded. Signed-off-by: Simon Arlott Acked-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 43 ++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index a73e714288e5..a51eeedc18d4 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE; if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) { - dbg("too big transfer requested"); + if (printk_ratelimit()) + usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n", + wbuflen, rbuflen); ret = -ENOMEM; goto fail; } @@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->rcv_done); ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting read urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } @@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->snd_done); ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting write urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL); if (ret < 0) { - dbg("sending cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen); if (ret < 0) { - dbg("receiving cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret); goto fail; } if (actlen % CMD_PACKET_SIZE || !actlen) { - dbg("response is not a positive multiple of %d: %#x", - CMD_PACKET_SIZE, actlen); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n", + cm, actlen); ret = -EIO; goto fail; } @@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, /* check the return status and copy the data to the output buffer, if needed */ for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) { if (rbuf[offb] != cm) { - dbg("wrong cm %#x in response", rbuf[offb]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n", + rbuf[offb], cm); ret = -EIO; goto fail; } if (rbuf[offb + 1] != CM_STATUS_SUCCESS) { - dbg("response failed: %#x", rbuf[offb + 1]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "response to cm %#x failed: %#x\n", + cm, rbuf[offb + 1]); ret = -EIO; goto fail; } @@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ for (offb = 0; offb < len; ) { int l = le32_to_cpu(buf[offb++]); if (l > stride || l > (len - offb) / 2) { - dbg("wrong data length %#x in response", l); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n", + cm, l); ret = -EIO; goto cleanup; } while (l--) { offd = le32_to_cpu(buf[offb++]); if (offd >= size) { - dbg("wrong index %#x in response", offd); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n", + offd, cm); ret = -EIO; goto cleanup; } From 6ce76104781a10554129791dc62c3104424f6d48 Mon Sep 17 00:00:00 2001 From: Frank A Kingswood Date: Wed, 22 Aug 2007 20:48:58 +0100 Subject: [PATCH 2734/2804] USB: Driver for CH341 USB-serial adaptor This patch implements a USB serial port driver for the Winchiphead CH341 USB-RS232 Converter. This chip also implements an IEEE 1284 parallel port, I2C and SPI, but that is not supported by the driver. Signed-off-by: Frank A Kingswood Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/usb-serial.txt | 11 + drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile | 1 + drivers/usb/serial/ch341.c | 352 +++++++++++++++++++++++++++++++ 4 files changed, 374 insertions(+) create mode 100644 drivers/usb/serial/ch341.c diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index 5b635ae84944..4e0b62b8566f 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -428,6 +428,17 @@ Options supported: See http://www.uuhaus.de/linux/palmconnect.html for up-to-date information on this driver. +Winchiphead CH341 Driver + + This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip + also implements an IEEE 1284 parallel port, I2C and SPI, but that is not + supported by the driver. The protocol was analyzed from the behaviour + of the Windows driver, no datasheet is available at present. + The manufacturer's website: http://www.winchiphead.com/. + For any questions or problems with this driver, please contact + frank@kingswood-consulting.co.uk. + + Generic Serial driver If your device is not one of the above listed devices, compatible with diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 43d6db696f90..99fefed77919 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN To compile this driver as a module, choose M here: the module will be called belkin_sa. +config USB_SERIAL_CH341 + tristate "USB Winchiphead CH341 Single Port Serial Driver" + depends on USB_SERIAL + help + Say Y here if you want to use a Winchiphead CH341 single port + USB to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called ch341. + config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 07a976eca6b7..d6fb384e52b2 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o +obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c new file mode 100644 index 000000000000..eb681069e24e --- /dev/null +++ b/drivers/usb/serial/ch341.c @@ -0,0 +1,352 @@ +/* + * Copyright 2007, Frank A Kingswood + * + * ch341.c implements a serial port driver for the Winchiphead CH341. + * + * The CH341 device can be used to implement an RS232 asynchronous + * serial port, an IEEE-1284 parallel printer port or a memory-like + * interface. In all cases the CH341 supports an I2C interface as well. + * This driver only supports the asynchronous serial interface. + * + * 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 DEFAULT_BAUD_RATE 2400 +#define DEFAULT_TIMEOUT 1000 + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x4348, 0x5523) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct ch341_private { + unsigned baud_rate; + u8 dtr; + u8 rts; +}; + +static int ch341_control_out(struct usb_device *dev, u8 request, + u16 value, u16 index) +{ + int r; + dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40, + (int)request, (int)value, (int)index); + + r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + value, index, NULL, 0, DEFAULT_TIMEOUT); + + return r; +} + +static int ch341_control_in(struct usb_device *dev, + u8 request, u16 value, u16 index, + char *buf, unsigned bufsize) +{ + int r; + dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40, + (int)request, (int)value, (int)index, buf, (int)bufsize); + + r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + value, index, buf, bufsize, DEFAULT_TIMEOUT); + return r; +} + +int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) +{ + short a, b; + int r; + + dbg("ch341_set_baudrate(%d)", priv->baud_rate); + switch (priv->baud_rate) { + case 2400: + a = 0xd901; + b = 0x0038; + break; + case 4800: + a = 0x6402; + b = 0x001f; + break; + case 9600: + a = 0xb202; + b = 0x0013; + break; + case 19200: + a = 0xd902; + b = 0x000d; + break; + case 38400: + a = 0x6403; + b = 0x000a; + break; + case 115200: + a = 0xcc03; + b = 0x0008; + break; + default: + return -EINVAL; + } + + r = ch341_control_out(dev, 0x9a, 0x1312, a); + if (!r) + r = ch341_control_out(dev, 0x9a, 0x0f2c, b); + + return r; +} + +int ch341_set_handshake(struct usb_device *dev, struct ch341_private *priv) +{ + dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); + return ch341_control_out(dev, 0xa4, + ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); +} + +int ch341_get_status(struct usb_device *dev) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_get_status()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size); + if ( r < 0) + goto out; + + /* Not having the datasheet for the CH341, we ignore the bytes returned + * from the device. Return error if the device did not respond in time. + */ + r = 0; + +out: kfree(buffer); + return r; +} + +/* -------------------------------------------------------------------------- */ + +int ch341_configure(struct usb_device *dev, struct ch341_private *priv) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_configure()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* expect two bytes 0x27 0x00 */ + r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0, 0); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + /* expect two bytes 0x56 0x00 */ + r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050); + if (r < 0) + goto out; + + /* expect 0xff 0xee */ + r = ch341_get_status(dev); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + r = ch341_set_handshake(dev, priv); + if (r < 0) + goto out; + + /* expect 0x9f 0xee */ + r = ch341_get_status(dev); + +out: kfree(buffer); + return r; +} + +/* allocate private data */ +static int ch341_attach(struct usb_serial *serial) +{ + struct ch341_private *priv; + int r; + + dbg("ch341_attach()"); + + /* private data */ + priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r < 0) + goto error; + + usb_set_serial_port_data(serial->port[0], priv); + return 0; + +error: kfree(priv); + return r; +} + +/* open this device, set default parameters */ +static int ch341_open(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); + int r; + + dbg("ch341_open()"); + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_handshake(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_baudrate(serial->dev, priv); + if (r) + goto out; + + r = usb_serial_generic_open(port, filp); + +out: return r; +} + +/* Old_termios contains the original termios settings and + * tty->termios contains the new setting to be used. + */ +static void ch341_set_termios(struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct ch341_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty = port->tty; + unsigned baud_rate; + + dbg("ch341_set_termios()"); + + if (!tty || !tty->termios) + return; + + baud_rate = tty_get_baud_rate(tty); + + switch (baud_rate) { + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 115200: + priv->baud_rate = baud_rate; + break; + default: + dbg("Rate %d not supported, using %d", + baud_rate, DEFAULT_BAUD_RATE); + priv->baud_rate = DEFAULT_BAUD_RATE; + } + + ch341_set_baudrate(port->serial->dev, priv); + + /* Unimplemented: + * (cflag & CSIZE) : data bits [5, 8] + * (cflag & PARENB) : parity {NONE, EVEN, ODD} + * (cflag & CSTOPB) : stop bits [1, 2] + */ +} + +static struct usb_driver ch341_driver = { + .name = "ch341", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver ch341_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ch341-uart", + }, + .id_table = id_table, + .usb_driver = &ch341_driver, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ch341_open, + .set_termios = ch341_set_termios, + .attach = ch341_attach, +}; + +static int __init ch341_init(void) +{ + int retval; + + retval = usb_serial_register(&ch341_device); + if (retval) + return retval; + retval = usb_register(&ch341_driver); + if (retval) + usb_serial_deregister(&ch341_device); + return retval; +} + +static void __exit ch341_exit(void) +{ + usb_deregister(&ch341_driver); + usb_serial_deregister(&ch341_device); +} + +module_init(ch341_init); +module_exit(ch341_exit); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +/* EOF ch341.c */ From 93b6497da99978742ffa9d9db6177397436278f5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 9 Sep 2007 22:25:04 +0200 Subject: [PATCH 2735/2804] USB: usb/serial/ch341.c: make 4 functions static This patch makes four needlessly global functions static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ch341.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index eb681069e24e..6b252ceb39a8 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -66,7 +66,8 @@ static int ch341_control_in(struct usb_device *dev, return r; } -int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) +static int ch341_set_baudrate(struct usb_device *dev, + struct ch341_private *priv) { short a, b; int r; @@ -108,14 +109,15 @@ int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) return r; } -int ch341_set_handshake(struct usb_device *dev, struct ch341_private *priv) +static int ch341_set_handshake(struct usb_device *dev, + struct ch341_private *priv) { dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); return ch341_control_out(dev, 0xa4, ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); } -int ch341_get_status(struct usb_device *dev) +static int ch341_get_status(struct usb_device *dev) { char *buffer; int r; @@ -142,7 +144,7 @@ out: kfree(buffer); /* -------------------------------------------------------------------------- */ -int ch341_configure(struct usb_device *dev, struct ch341_private *priv) +static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) { char *buffer; int r; From e3a09051a16fcdb190ad0b7dc6064904c8118409 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 3 Oct 2007 18:53:13 +0900 Subject: [PATCH 2736/2804] USB: r8a66597-hcd: fix Class or Vendor Request Fixed the problem that does not work in the case of bRequest = 0x05 in Class or Vendor Request. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fd00f1e33fb5..0a699efe6c9c 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1034,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597, pipe_start(r8a66597, td->pipe); } +static int is_set_address(unsigned char *setup_packet) +{ + if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) && + setup_packet[1] == USB_REQ_SET_ADDRESS) + return 1; + else + return 0; +} + /* this function must be called with interrupt disabled */ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) { @@ -1041,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) switch (td->type) { case USB_PID_SETUP: - if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) { + if (is_set_address(td->urb->setup_packet)) { td->set_address = 1; td->urb->setup_packet[2] = alloc_usb_address(r8a66597, td->urb); From 05eac910b69209164b1d9357bf8877a7c81b2e4e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 3 Oct 2007 18:53:28 +0900 Subject: [PATCH 2737/2804] USB: r8a66597-hcd: fix endian problem Fixed the problem that does not work in the big endian machine. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 0a699efe6c9c..64fba53c2631 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -834,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, info.pipenum = get_empty_pipenum(r8a66597, ep); info.address = get_urb_to_r8a66597_addr(r8a66597, urb); info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = ep->wMaxPacketSize; + info.maxpacket = le16_to_cpu(ep->wMaxPacketSize); info.type = get_r8a66597_type(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); info.bufnum = get_bufnum(info.pipenum); @@ -925,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, p[i], setup_addr); + r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR); @@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetPortStatus: if (wIndex > R8A66597_MAX_ROOT_HUB) goto error; - *(u32 *)buf = rh->port; + *(u32 *)buf = cpu_to_le32(rh->port); break; case SetPortFeature: if (wIndex > R8A66597_MAX_ROOT_HUB) From ca0677a29bddee35918bf3c0c55cc3badd69079e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 5 Oct 2007 15:53:12 +0900 Subject: [PATCH 2738/2804] USB: r8a66597-hcd: fix driver removing Fixed the problem that accessed register of this controller after having called iounmap(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 64fba53c2631..ae8ec4474eb8 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); del_timer_sync(&r8a66597->rh_timer); - iounmap((void *)r8a66597->reg); usb_remove_hcd(hcd); + iounmap((void *)r8a66597->reg); usb_put_hcd(hcd); return 0; } From 9dcfbd97a695a3c28a867501127fa35ac49bc805 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 2 Oct 2007 14:40:46 -0700 Subject: [PATCH 2739/2804] USB: fix gregkh-usb-usb-sisusb2vga-convert-printk-to-dev_-macros drivers/usb/misc/sisusbvga/sisusb.c: In function 'sisusb_open': drivers/usb/misc/sisusbvga/sisusb.c:2444: warning: 'sisusb' is used uninitialized in this function I can tell that'll oops just by looking at it. How come this code assume a 7,000 column xterm? :( Cc: Felipe Balbi Cc: Thomas Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 033bdfe9b215..0790829a5701 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3323,15 +3323,7 @@ static int __init usb_sisusb_init(void) sisusb_init_concode(); #endif - if (!(retval = usb_register(&sisusb_driver))) { - - dev_info(&sisusb->sisusb_dev->dev, "Driver version %d.%d.%d\n", SISUSB_VERSION, - SISUSB_REVISION, SISUSB_PATCHLEVEL); - dev_info(&sisusb->sisusb_dev->dev, "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); - - } - - return retval; + return usb_register(&sisusb_driver); } static void __exit usb_sisusb_exit(void) From 5395353e0c8272fe73ac914acd7e4add0da2bef0 Mon Sep 17 00:00:00 2001 From: Benedikt Spranger Date: Tue, 2 Oct 2007 14:40:48 -0700 Subject: [PATCH 2740/2804] usb-gadget-ether: prevent oops caused by error interrupt race Fix a longstanding race in the Ethernet gadget driver, which can cause an oops on device disconnect. The fix is just to make the TX path check whether its freelist is empty. That check is otherwise not necessary, since the queue is always stopped when that list empties (and restarted when request completion puts an entry back on that freelist). The race window starts when the network code decides to transmit a packet, and ends when hard_start_xmit() grabs the freelist lock. When disconnect() is called inside that window, it shuts down the TX queue and breaks the otherwise-solid assumption that packets are never sent through a TX queue that's stopped. Signed-off-by: Benedikt Spranger Signed-off-by: Thomas Gleixner Signed-off-by: David Brownell Signed-off-by: Andrew Morton Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index ff244f42723f..9f4fd7e849a0 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1957,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) } spin_lock_irqsave(&dev->req_lock, flags); + /* + * this freelist can be empty if an interrupt triggered disconnect() + * and reconfigured the gadget (shutting down this queue) after the + * network stack decided to xmit but before we got the spinlock. + */ + if (list_empty(&dev->tx_reqs)) { + spin_unlock_irqrestore(&dev->req_lock, flags); + return 1; + } + req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); + + /* temporarily stop TX queue when the freelist empties */ if (list_empty (&dev->tx_reqs)) netif_stop_queue (net); spin_unlock_irqrestore(&dev->req_lock, flags); From a59048d46303c4146993c37f51ed97a760fc4c0a Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 2 Oct 2007 14:40:49 -0700 Subject: [PATCH 2741/2804] USB: drivers/usb/misc/sisusbvga/sisusb.c: kill two unused variables Kill two unused variables in drivers/usb/misc/sisusbvga/sisusb.c. Signed-off-by: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 0790829a5701..9244d067cec1 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3316,8 +3316,6 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { - int retval; - struct sisusb_usb_data *sisusb; #ifdef INCL_SISUSB_CON sisusb_init_concode(); From 437f375f262417b484f28007c3e8d21bd01d0e01 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Thu, 27 Sep 2007 00:36:22 +0400 Subject: [PATCH 2742/2804] USB: serial gadget: Disable endpoints on unload After Serial gadget is being unloaded, neither serial itself, nor other gadget stuff can be loaded subsequently. Signed-off-by: Vitaly Bordug Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/serial.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index afdf71f76f7e..a2a1ebc947d2 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -1470,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) dev->dev_ctrl_req = NULL; } gs_free_ports(dev); + if (dev->dev_notify_ep) + usb_ep_disable(dev->dev_notify_ep); + if (dev->dev_in_ep) + usb_ep_disable(dev->dev_in_ep); + if (dev->dev_out_ep) + usb_ep_disable(dev->dev_out_ep); kfree(dev); set_gadget_data(gadget, NULL); } From 4d59d8a11383ebf0e0260ee481a4e766959fd7d9 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 3 Oct 2007 14:56:03 -0700 Subject: [PATCH 2743/2804] USB: Export URB statistics for powertop powertop currently tracks interrupts generated by uhci, ehci, and ohci, but it has no way of telling which USB device to blame USB bus activity on. This patch exports the number of URBs that are submitted for a given device. Cat the file 'urbnum' in /sys/bus/usb/devices/.../ Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 ++ drivers/usb/core/sysfs.c | 11 +++++++++++ drivers/usb/core/usb.c | 1 + include/linux/usb.h | 1 + 4 files changed, 15 insertions(+) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2c79aa6ca2b4..3dd997df8505 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1176,6 +1176,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) */ usb_get_urb(urb); atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); usbmon_urb_submit(&hcd->self, urb); /* NOTE requirements on root-hub callers (usbfs and the hub @@ -1197,6 +1198,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); + atomic_dec(&urb->dev->urbnum); if (urb->reject) wake_up(&usb_kill_urb_queue); usb_put_urb(urb); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index e02590297d31..b04afd06e502 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); +static ssize_t +show_urbnum(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); +} +static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); + #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND) static const char power_group[] = "power"; @@ -458,6 +468,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_bConfigurationValue.attr, &dev_attr_bmAttributes.attr, &dev_attr_bMaxPower.attr, + &dev_attr_urbnum.attr, /* device attributes */ &dev_attr_idVendor.attr, &dev_attr_idProduct.attr, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8121edbd1494..c99938d5f78e 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -266,6 +266,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.dma_mask = bus->controller->dma_mask; set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; + atomic_set(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; diff --git a/include/linux/usb.h b/include/linux/usb.h index e5b35e0dca23..c10935fdc03a 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -415,6 +415,7 @@ struct usb_device { int pm_usage_cnt; /* usage counter for autosuspend */ u32 quirks; /* quirks of the whole device */ + atomic_t urbnum; /* number of URBs submitted for the whole device */ #ifdef CONFIG_PM struct delayed_work autosuspend; /* for delayed autosuspends */ From 9454a57ab5922e5cd25321cae9d1a8cbeb3e2e85 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 4 Oct 2007 18:05:17 -0700 Subject: [PATCH 2744/2804] USB: move to Move to , reducing some of the clutter in the main include directory. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/config.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 2 +- drivers/usb/gadget/epautoconf.c | 2 +- drivers/usb/gadget/ether.c | 2 +- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/fsl_usb2_udc.c | 4 ++-- drivers/usb/gadget/gmidi.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/inode.c | 2 +- drivers/usb/gadget/lh7a40x_udc.h | 2 +- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa2xx_udc.c | 2 +- drivers/usb/gadget/s3c2410_udc.c | 2 +- drivers/usb/gadget/serial.c | 2 +- drivers/usb/gadget/usbstring.c | 2 +- drivers/usb/gadget/zero.c | 2 +- include/linux/{usb_gadget.h => usb/gadget.h} | 2 +- 21 files changed, 22 insertions(+), 22 deletions(-) rename include/linux/{usb_gadget.h => usb/gadget.h} (99%) diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index bdd5f2284b3a..1c8040602525 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -69,7 +69,7 @@ /* gadget stack */ #include -#include +#include /* udc specific */ #include "amd5536udc.h" diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 63d7d6568699..a6adf7e0f6f8 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index c6760aee1e5c..a4e54b2743f0 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -25,7 +25,7 @@ #include #include -#include +#include /** diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 6479a36d6f0e..9db2482bdfa2 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 3aa46cfa66ba..f9d07108bc30 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9f4fd7e849a0..9e732bff9df0 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 0551140010ee..73726c570a6e 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -240,7 +240,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index 89c768e2aed7..9bb7f64a85cd 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include @@ -1117,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) return 0; } -/* defined in usb_gadget.h */ +/* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, .wakeup = fsl_wakeup, diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index d2475755a206..0689189550bc 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 349b8166f34a..2ec9d196a8cf 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 129eda5358f7..47ef8bd58a00 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -37,7 +37,7 @@ #include #include -#include +#include /* diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index b3fe197e1eeb..1ecfd6366b9a 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -50,7 +50,7 @@ #include #include -#include +#include /* * Memory map diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 4b27d12f049d..ebc5536aa271 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include "m66592-udc.h" diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index c3d364ecd4f8..d5d473f8144b 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index bf2788dfb32b..87c4f50dfb61 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 1407ad1c8128..3e715082de36 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -54,7 +54,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 0be80c635c48..e3e90f8a75e7 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index a2a1ebc947d2..f5738eb8e765 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 3459ea6c6c0b..878e428a0ec1 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index ff540879ce3a..fcde5d9c87df 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -55,7 +55,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/include/linux/usb_gadget.h b/include/linux/usb/gadget.h similarity index 99% rename from include/linux/usb_gadget.h rename to include/linux/usb/gadget.h index 5ea611e48ec1..46705e91573d 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb/gadget.h @@ -1,5 +1,5 @@ /* - * + * * * We call the USB code inside a Linux-based peripheral device a "gadget" * driver, except for the hardware-specific bus glue. One USB host can From 27f5d75afaa1b65e4cc1e4ac8a2a5095d24f1576 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 4 Oct 2007 18:06:16 -0700 Subject: [PATCH 2745/2804] USB: re-remove Remove ... somehow this was recreated when the Blackfin arch was merged, instead of using which is the correct header. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- .../mach-bf537/boards/generic_board.c | 2 +- arch/blackfin/mach-bf537/boards/pnav10.c | 2 +- arch/blackfin/mach-bf537/boards/stamp.c | 2 +- include/linux/usb_sl811.h | 26 ------------------- 4 files changed, 3 insertions(+), 29 deletions(-) delete mode 100644 include/linux/usb_sl811.h diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c index 5e9d09eb8579..6668c8e4a3fc 100644 --- a/arch/blackfin/mach-bf537/boards/generic_board.c +++ b/arch/blackfin/mach-bf537/boards/generic_board.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c index 20507e92a3a4..f83a2544004d 100644 --- a/arch/blackfin/mach-bf537/boards/pnav10.c +++ b/arch/blackfin/mach-bf537/boards/pnav10.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index 47d7d4a0e73d..f42ba3aa86d7 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h deleted file mode 100644 index 4f2d012d7309..000000000000 --- a/include/linux/usb_sl811.h +++ /dev/null @@ -1,26 +0,0 @@ - -/* - * board initialization should put one of these into dev->platform_data - * and place the sl811hs onto platform_bus named "sl811-hcd". - */ - -struct sl811_platform_data { - unsigned can_wakeup:1; - - /* given port_power, msec/2 after power on till power good */ - u8 potpg; - - /* mA/2 power supplied on this port (max = default = 250) */ - u8 power; - - /* sl811 relies on an external source of VBUS current */ - void (*port_power)(struct device *dev, int is_on); - - /* pulse sl811 nRST (probably with a GPIO) */ - void (*reset)(struct device *dev); - - // some boards need something like these: - // int (*check_overcurrent)(struct device *dev); - // void (*clock_enable)(struct device *dev, int is_on); -}; - From 3046c6db575019ba4ce6b9deac352d438ddf733d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 5 Oct 2007 14:43:00 -0400 Subject: [PATCH 2746/2804] USB: unusual_devs entry for Nikon DSC D2Xs This patch (as996) adds an unusual_devs entry for the Nikon DSC D2Xs camera. Signed-off-by: Alan Stern Cc: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 5129b538be90..edf92914674a 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -362,6 +362,13 @@ UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Paul Check */ +UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D2Xs", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena and * Frank Copeland */ From d9c563626d9a136636385209d59d0c4f16c4a7ab Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 23:34:18 +0100 Subject: [PATCH 2747/2804] USB: visor: termios bits Visor has a huge complex routine which displays termios bits for debug but doesn't do anything. Get the correct behaviour by removing it all Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/visor.c | 64 -------------------------------------- 1 file changed, 64 deletions(-) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 30e08c0bcdc2..7ee087fed913 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); static void visor_read_int_callback (struct urb *urb); @@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = { .unthrottle = visor_unthrottle, .attach = clie_3_5_startup, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign return -ENOIOCTLCMD; } - -/* This function is all nice and good, but we don't change anything based on it :) */ -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) -{ - unsigned int cflag; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if ((!port->tty) || (!port->tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - - cflag = port->tty->termios->c_cflag; - - /* get the byte size */ - switch (cflag & CSIZE) { - case CS5: dbg("%s - data bits = 5", __FUNCTION__); break; - case CS6: dbg("%s - data bits = 6", __FUNCTION__); break; - case CS7: dbg("%s - data bits = 7", __FUNCTION__); break; - default: - case CS8: dbg("%s - data bits = 8", __FUNCTION__); break; - } - - /* determine the parity */ - if (cflag & PARENB) - if (cflag & PARODD) - dbg("%s - parity = odd", __FUNCTION__); - else - dbg("%s - parity = even", __FUNCTION__); - else - dbg("%s - parity = none", __FUNCTION__); - - /* figure out the stop bits requested */ - if (cflag & CSTOPB) - dbg("%s - stop bits = 2", __FUNCTION__); - else - dbg("%s - stop bits = 1", __FUNCTION__); - - - /* figure out the flow control settings */ - if (cflag & CRTSCTS) - dbg("%s - RTS/CTS is enabled", __FUNCTION__); - else - dbg("%s - RTS/CTS is disabled", __FUNCTION__); - - /* determine software flow control */ - if (I_IXOFF(port->tty)) - dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty)); - else - dbg("%s - XON/XOFF is disabled", __FUNCTION__); - - /* get the baud rate wanted */ - dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty)); - - return; -} - - static int __init visor_init (void) { int i, retval; From f621b8437d6ae502dde45797f56407e48c7a68b4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 23:22:36 +0100 Subject: [PATCH 2748/2804] USB: funsoft: Fix termios Funsoft has a bogus ioctl handler doing bogus termios handling in a bogus manner. Fortunately we can simply delete all the bogus bits and get the right default behaviour ! Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/funsoft.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 4092f6dc9efd..b5194dc7d3bb 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ktermios t; - - dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); - - if (cmd == TCSETSF) { - if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg)) - return -EFAULT; - - dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__, - t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); - - if (!(t.c_lflag & ICANON)) - return -EINVAL; - } - return -ENOIOCTLCMD; -} - static struct usb_driver funsoft_driver = { .name = "funsoft", .probe = usb_serial_probe, @@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = { .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, - .ioctl = funsoft_ioctl, }; static int __init funsoft_init(void) From 4f45426cfd6170311e116442ccd8ce0e31979237 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 9 Oct 2007 15:00:05 -0700 Subject: [PATCH 2749/2804] USB: add runtime frame_no quirk for big-endian OHCI Add OHCI big endian frame_no quirk. The frame_no value stored in the HCCA is a 16 bit field at a specific offset, but since not all CPUs can do 16-bit memory accesses it's used as a 32 bit field. And that's why big-endian OHCI must shift 16 bits ... unless the spec is not followed. Currently there's one MPC52xx platform that doesn't need the shift. This patch adds a new "big endian frame_no" quirk to control that at runtime. Signed-off-by: Valentine Barshak Acked-by: Dale Farnsworth Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-ppc-of.c | 5 ++++- drivers/usb/host/ohci-ppc-soc.c | 5 +++++ drivers/usb/host/ohci.h | 13 ++++++------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index c43b66acd4d5..0a7426920150 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) } ohci = hcd_to_ohci(hcd); - if (is_bigendian) + if (is_bigendian) { ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + if (of_device_is_compatible(dn, "mpc5200-ohci")) + ohci->flags |= OHCI_QUIRK_FRAME_NO; + } ohci_hcd_init(ohci); diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 1a2e1777ca61..f95be1896b0d 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, ohci = hcd_to_ohci(hcd); ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + +#ifdef CONFIG_PPC_MPC52xx + /* MPC52xx doesn't need frame_no shift */ + ohci->flags |= OHCI_QUIRK_FRAME_NO; +#endif ohci_hcd_init(ohci); retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index dd4d5b4dcb6c..47c5c66a282c 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -398,6 +398,7 @@ struct ohci_hcd { #define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ #define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ #define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ +#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ @@ -633,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all * hardware handles 16 bit reads. That creates a different confusion on * some big-endian SOC implementations. Same thing happens with PSW access. - * - * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over - * to arch/powerpc */ -#ifdef CONFIG_STB03xxx -#define OHCI_BE_FRAME_NO_SHIFT 16 +#ifdef CONFIG_PPC_MPC52xx +#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO) #else -#define OHCI_BE_FRAME_NO_SHIFT 0 +#define big_endian_frame_no_quirk(ohci) 0 #endif static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) @@ -649,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) u32 tmp; if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); - tmp >>= OHCI_BE_FRAME_NO_SHIFT; + if (!big_endian_frame_no_quirk(ohci)) + tmp >>= 16; } else tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no); From b24896c6b7ddb37ab20ba0bbfd0ed36a38923f67 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Oct 2007 22:04:16 -0700 Subject: [PATCH 2750/2804] USB: ehci build fixes on au1xxx, ppc-soc Cleanup: references to two PM routines (and HCD entry points) that no longer exist are swapped with their replacements. Evidently au1xxx and ppc-soc EHCI support doesn't get compiled with power management very much, or these build bugs would have been patched long ago. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-au1xxx.c | 6 ++---- drivers/usb/host/ehci-ppc-soc.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index b1d19268cb23..766ef68a0b43 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index 4f99b0eb27bc..452d4b1bc859 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) From c604e851486eabcbeb73e984279d436ce121fd5d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 9 Oct 2007 23:47:17 -0700 Subject: [PATCH 2751/2804] USB: ohci SSB bus glue This adds SSB bus glue for the USB OHCI HCD. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 13 ++ drivers/usb/host/ohci-hcd.c | 21 ++- drivers/usb/host/ohci-ssb.c | 247 ++++++++++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/ohci-ssb.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 565d6ef4c4cf..c978d622fa8a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI Enables support for PCI-bus plug-in USB controller cards. If unsure, say Y. +config USB_OHCI_HCD_SSB + bool "OHCI support for Broadcom SSB OHCI core" + depends on USB_OHCI_HCD && SSB && EXPERIMENTAL + default n + ---help--- + Support for the Sonics Silicon Backplane (SSB) attached + Broadcom USB OHCI core. + + This device is present in some embedded devices with + Broadcom based SSB bus. + + If unsure, say N. + config USB_OHCI_BIG_ENDIAN_DESC bool depends on USB_OHCI_HCD diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index f7c6ced2bc03..240c7f507541 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1033,11 +1033,17 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver #endif +#ifdef CONFIG_USB_OHCI_HCD_SSB +#include "ohci-ssb.c" +#define SSB_OHCI_DRIVER ssb_ohci_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ !defined(SA1111_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) + !defined(PS3_SYSTEM_BUS_DRIVER) && \ + !defined(SSB_OHCI_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -1082,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void) goto error_pci; #endif +#ifdef SSB_OHCI_DRIVER + retval = ssb_driver_register(&SSB_OHCI_DRIVER); + if (retval) + goto error_ssb; +#endif + return retval; /* Error path */ +#ifdef SSB_OHCI_DRIVER + error_ssb: +#endif #ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); error_pci: #endif #ifdef SA1111_DRIVER @@ -1110,6 +1126,9 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { +#ifdef SSB_OHCI_DRIVER + ssb_driver_unregister(&SSB_OHCI_DRIVER); +#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c new file mode 100644 index 000000000000..bc3e785d8c00 --- /dev/null +++ b/drivers/usb/host/ohci-ssb.c @@ -0,0 +1,247 @@ +/* + * Sonics Silicon Backplane + * Broadcom USB-core OHCI driver + * + * Copyright 2007 Michael Buesch + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include + + +#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) + +struct ssb_ohci_device { + struct ohci_hcd ohci; /* _must_ be at the beginning. */ + + u32 enable_flags; +}; + +static inline +struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) +{ + return (struct ssb_ohci_device *)(hcd->hcd_priv); +} + + +static int ssb_ohci_reset(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + ohci_hcd_init(ohci); + err = ohci_init(ohci); + + return err; +} + +static int ssb_ohci_start(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + err = ohci_run(ohci); + if (err < 0) { + ohci_err(ohci, "can't start\n"); + ohci_stop(hcd); + } + + return err; +} + +#ifdef CONFIG_PM +static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + unsigned long flags; + + spin_lock_irqsave(&ohci->lock, flags); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */ + + /* make sure snapshot being resumed re-enumerates everything */ + if (message.event == PM_EVENT_PRETHAW) + ohci_usb_reset(ohci); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + spin_unlock_irqrestore(&ohci->lock, flags); + return 0; +} + +static int ssb_ohci_hcd_resume(struct usb_hcd *hcd) +{ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + usb_hcd_resume_root_hub(hcd); + return 0; +} +#endif /* CONFIG_PM */ + +static const struct hc_driver ssb_ohci_hc_driver = { + .description = "ssb-usb-ohci", + .product_desc = "SSB OHCI Controller", + .hcd_priv_size = sizeof(struct ssb_ohci_device), + + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + .reset = ssb_ohci_reset, + .start = ssb_ohci_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + +#ifdef CONFIG_PM + .suspend = ssb_ohci_hcd_suspend, + .resume = ssb_ohci_hcd_resume, +#endif + + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + .get_frame_number = ohci_get_frame, + + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, + + .start_port_reset = ohci_start_port_reset, +}; + +static void ssb_ohci_detach(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + usb_put_hcd(hcd); + ssb_device_disable(dev, 0); +} + +static int ssb_ohci_attach(struct ssb_device *dev) +{ + struct ssb_ohci_device *ohcidev; + struct usb_hcd *hcd; + int err = -ENOMEM; + u32 tmp, flags = 0; + + if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) + flags |= SSB_OHCI_TMSLOW_HOSTMODE; + + ssb_device_enable(dev, flags); + + hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, + dev->dev->bus_id); + if (!hcd) + goto err_dev_disable; + ohcidev = hcd_to_ssb_ohci(hcd); + ohcidev->enable_flags = flags; + + tmp = ssb_read32(dev, SSB_ADMATCH0); + hcd->rsrc_start = ssb_admatch_base(tmp); + hcd->rsrc_len = ssb_admatch_size(tmp); + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) + goto err_put_hcd; + err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); + if (err) + goto err_iounmap; + + ssb_set_drvdata(dev, hcd); + + return err; + +err_iounmap: + iounmap(hcd->regs); +err_put_hcd: + usb_put_hcd(hcd); +err_dev_disable: + ssb_device_disable(dev, flags); + return err; +} + +static int ssb_ohci_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + int err; + u16 chipid_top; + + /* USBcores are only connected on embedded devices. */ + chipid_top = (dev->bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (usb_disabled()) + return -ENODEV; + + /* We currently always attach SSB_DEV_USB11_HOSTDEV + * as HOST OHCI. If we want to attach it as Client device, + * we must branch here and call into the (yet to + * be written) Client mode driver. Same for remove(). */ + + err = ssb_ohci_attach(dev); + + return err; +} + +static void ssb_ohci_remove(struct ssb_device *dev) +{ + ssb_ohci_detach(dev); +} + +#ifdef CONFIG_PM + +static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) +{ + ssb_device_disable(dev, 0); + + return 0; +} + +static int ssb_ohci_resume(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + + ssb_device_enable(dev, ohcidev->enable_flags); + + return 0; +} + +#else /* !CONFIG_PM */ +#define ssb_ohci_suspend NULL +#define ssb_ohci_resume NULL +#endif /* CONFIG_PM */ + +static const struct ssb_device_id ssb_ohci_table[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); + +static struct ssb_driver ssb_ohci_driver = { + .name = KBUILD_MODNAME, + .id_table = ssb_ohci_table, + .probe = ssb_ohci_probe, + .remove = ssb_ohci_remove, + .suspend = ssb_ohci_suspend, + .resume = ssb_ohci_resume, +}; From 914a3f3b375493eb44ad652a431939258cf34f71 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 10 Oct 2007 02:29:43 -0700 Subject: [PATCH 2752/2804] USB: add atmel_usba_udc driver This is a driver for the Atmel USBA UDC which can be found integrated on AT32AP700x AVR32 processors. For hardware documentation, please see the AT32AP7000 data sheet: http://www.atmel.com/dyn/resources/prod_documents/doc32003.pdf This is a dual speed controller (connects at high or full speed). The driver supports up to 7 control, bulk, interrupt and isochronous endpoints with some constraints. Bulk, interrupt and isochronous transfers are driven by DMA. Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 7 + drivers/usb/gadget/Kconfig | 26 +- drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/atmel_usba_udc.c | 2038 +++++++++++++++++++++++++++ drivers/usb/gadget/atmel_usba_udc.h | 350 +++++ 5 files changed, 2421 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/gadget/atmel_usba_udc.c create mode 100644 drivers/usb/gadget/atmel_usba_udc.h diff --git a/MAINTAINERS b/MAINTAINERS index c4eca56ed5bf..60e649ff6fdc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -677,6 +677,13 @@ P: Haavard Skinnemoen M: hskinnemoen@atmel.com S: Supported +ATMEL USBA UDC DRIVER +P: Haavard Skinnemoen +M: hskinnemoen@atmel.com +L: kernel@avr32linux.org +W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver +S: Supported + ATMEL WIRELESS DRIVER P: Simon Kelley M: simon@thekelleys.org.uk diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 767aed5b4bea..f81d08d6538b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES driver on a new board. Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_DEBUG_FS + boolean "Debugging information files in debugfs" + depends on USB_GADGET && DEBUG_FS + help + Some of the drivers in the "gadget" framework can expose + debugging information in files under /sys/kernel/debug/. + The information in these files may help when you're + troubleshooting or bringing up a driver on a new board. + Enable these files by choosing "Y" here. If in doubt, or + to conserve kernel memory, say "N". + config USB_GADGET_SELECTED boolean @@ -103,6 +114,20 @@ config USB_AMD5536UDC default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_ATMEL_USBA + boolean "Atmel USBA" + select USB_GADGET_DUALSPEED + depends on AVR32 + help + USBA is the integrated high-speed USB Device controller on + the AT32AP700x processors from Atmel. + +config USB_ATMEL_USBA + tristate + depends on USB_GADGET_ATMEL_USBA + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" depends on MPC834x || PPC_MPC831x @@ -228,7 +253,6 @@ config USB_LH7A40X default USB_GADGET select USB_GADGET_SELECTED - config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 1bc0f03550ce..904e57bf6112 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o +obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c new file mode 100644 index 000000000000..2bb28a583937 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -0,0 +1,2038 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "atmel_usba_udc.h" + + +static struct usba_udc the_udc; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS +#include +#include + +static int queue_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_ep *ep = inode->i_private; + struct usba_request *req, *req_copy; + struct list_head *queue_data; + + queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL); + if (!queue_data) + return -ENOMEM; + INIT_LIST_HEAD(queue_data); + + spin_lock_irq(&ep->udc->lock); + list_for_each_entry(req, &ep->queue, queue) { + req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC); + if (!req_copy) + goto fail; + memcpy(req_copy, req, sizeof(*req_copy)); + list_add_tail(&req_copy->queue, queue_data); + } + spin_unlock_irq(&ep->udc->lock); + + file->private_data = queue_data; + return 0; + +fail: + spin_unlock_irq(&ep->udc->lock); + list_for_each_entry_safe(req, req_copy, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return -ENOMEM; +} + +/* + * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0 + * + * b: buffer address + * l: buffer length + * I/i: interrupt/no interrupt + * Z/z: zero/no zero + * S/s: short ok/short not ok + * s: status + * n: nr_packets + * F/f: submitted/not submitted to FIFO + * D/d: using/not using DMA + * L/l: last transaction/not last transaction + */ +static ssize_t queue_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct list_head *queue = file->private_data; + struct usba_request *req, *tmp_req; + size_t len, remaining, actual = 0; + char tmpbuf[38]; + + if (!access_ok(VERIFY_WRITE, buf, nbytes)) + return -EFAULT; + + mutex_lock(&file->f_dentry->d_inode->i_mutex); + list_for_each_entry_safe(req, tmp_req, queue, queue) { + len = snprintf(tmpbuf, sizeof(tmpbuf), + "%8p %08x %c%c%c %5d %c%c%c\n", + req->req.buf, req->req.length, + req->req.no_interrupt ? 'i' : 'I', + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 's' : 'S', + req->req.status, + req->submitted ? 'F' : 'f', + req->using_dma ? 'D' : 'd', + req->last_transaction ? 'L' : 'l'); + len = min(len, sizeof(tmpbuf)); + if (len > nbytes) + break; + + list_del(&req->queue); + kfree(req); + + remaining = __copy_to_user(buf, tmpbuf, len); + actual += len - remaining; + if (remaining) + break; + + nbytes -= len; + buf += len; + } + mutex_unlock(&file->f_dentry->d_inode->i_mutex); + + return actual; +} + +static int queue_dbg_release(struct inode *inode, struct file *file) +{ + struct list_head *queue_data = file->private_data; + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return 0; +} + +static int regs_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_udc *udc; + unsigned int i; + u32 *data; + int ret = -ENOMEM; + + mutex_lock(&inode->i_mutex); + udc = inode->i_private; + data = kmalloc(inode->i_size, GFP_KERNEL); + if (!data) + goto out; + + spin_lock_irq(&udc->lock); + for (i = 0; i < inode->i_size / 4; i++) + data[i] = __raw_readl(udc->regs + i * 4); + spin_unlock_irq(&udc->lock); + + file->private_data = data; + ret = 0; + +out: + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static ssize_t regs_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + mutex_lock(&inode->i_mutex); + ret = simple_read_from_buffer(buf, nbytes, ppos, + file->private_data, + file->f_dentry->d_inode->i_size); + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static int regs_dbg_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +const struct file_operations queue_dbg_fops = { + .owner = THIS_MODULE, + .open = queue_dbg_open, + .llseek = no_llseek, + .read = queue_dbg_read, + .release = queue_dbg_release, +}; + +const struct file_operations regs_dbg_fops = { + .owner = THIS_MODULE, + .open = regs_dbg_open, + .llseek = generic_file_llseek, + .read = regs_dbg_read, + .release = regs_dbg_release, +}; + +static void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + struct dentry *ep_root; + + ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root); + if (!ep_root) + goto err_root; + ep->debugfs_dir = ep_root; + + ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root, + ep, &queue_dbg_fops); + if (!ep->debugfs_queue) + goto err_queue; + + if (ep->can_dma) { + ep->debugfs_dma_status + = debugfs_create_u32("dma_status", 0400, ep_root, + &ep->last_dma_status); + if (!ep->debugfs_dma_status) + goto err_dma_status; + } + if (ep_is_control(ep)) { + ep->debugfs_state + = debugfs_create_u32("state", 0400, ep_root, + &ep->state); + if (!ep->debugfs_state) + goto err_state; + } + + return; + +err_state: + if (ep->can_dma) + debugfs_remove(ep->debugfs_dma_status); +err_dma_status: + debugfs_remove(ep->debugfs_queue); +err_queue: + debugfs_remove(ep_root); +err_root: + dev_err(&ep->udc->pdev->dev, + "failed to create debugfs directory for %s\n", ep->ep.name); +} + +static void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + debugfs_remove(ep->debugfs_queue); + debugfs_remove(ep->debugfs_dma_status); + debugfs_remove(ep->debugfs_state); + debugfs_remove(ep->debugfs_dir); + ep->debugfs_dma_status = NULL; + ep->debugfs_dir = NULL; +} + +static void usba_init_debugfs(struct usba_udc *udc) +{ + struct dentry *root, *regs; + struct resource *regs_resource; + + root = debugfs_create_dir(udc->gadget.name, NULL); + if (IS_ERR(root) || !root) + goto err_root; + udc->debugfs_root = root; + + regs = debugfs_create_file("regs", 0400, root, udc, ®s_dbg_fops); + if (!regs) + goto err_regs; + + regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM, + CTRL_IOMEM_ID); + regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1; + udc->debugfs_regs = regs; + + usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); + + return; + +err_regs: + debugfs_remove(root); +err_root: + udc->debugfs_root = NULL; + dev_err(&udc->pdev->dev, "debugfs is not available\n"); +} + +static void usba_cleanup_debugfs(struct usba_udc *udc) +{ + usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0)); + debugfs_remove(udc->debugfs_regs); + debugfs_remove(udc->debugfs_root); + udc->debugfs_regs = NULL; + udc->debugfs_root = NULL; +} +#else +static inline void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + +} + +static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + +} + +static inline void usba_init_debugfs(struct usba_udc *udc) +{ + +} + +static inline void usba_cleanup_debugfs(struct usba_udc *udc) +{ + +} +#endif + +static int vbus_is_present(struct usba_udc *udc) +{ + if (udc->vbus_pin != -1) + return gpio_get_value(udc->vbus_pin); + + /* No Vbus detection: Assume always present */ + return 1; +} + +static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) +{ + unsigned long tmp; + + DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); + for (; len > 0; len -= 4, buf += 4, fifo += 4) { + tmp = *(unsigned long *)buf; + if (len >= 4) { + DBG(DBG_FIFO, " -> %08lx\n", tmp); + __raw_writel(tmp, fifo); + } else { + do { + DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); + __raw_writeb(tmp >> 24, fifo); + fifo++; + tmp <<= 8; + } while (--len); + break; + } + } +} + +static void copy_from_fifo(void *buf, void __iomem *fifo, int len) +{ + union { + unsigned long *w; + unsigned char *b; + } p; + unsigned long tmp; + + DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); + for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { + if (len >= 4) { + tmp = __raw_readl(fifo); + *p.w = tmp; + DBG(DBG_FIFO, " -> %08lx\n", tmp); + } else { + do { + tmp = __raw_readb(fifo); + *p.b = tmp; + DBG(DBG_FIFO, " -> %02lx\n", tmp); + fifo++, p.b++; + } while (--len); + } + } +} + +static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) +{ + unsigned int transaction_len; + + transaction_len = req->req.length - req->req.actual; + req->last_transaction = 1; + if (transaction_len > ep->ep.maxpacket) { + transaction_len = ep->ep.maxpacket; + req->last_transaction = 0; + } else if (transaction_len == ep->ep.maxpacket && req->req.zero) + req->last_transaction = 0; + + DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n", + ep->ep.name, req, transaction_len, + req->last_transaction ? ", done" : ""); + + copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + req->req.actual += transaction_len; +} + +static void submit_request(struct usba_ep *ep, struct usba_request *req) +{ + DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n", + ep->ep.name, req, req->req.length); + + req->req.actual = 0; + req->submitted = 1; + + if (req->using_dma) { + if (req->req.length == 0) { + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + return; + } + + if (req->req.zero) + usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET); + else + usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET); + + usba_dma_writel(ep, ADDRESS, req->req.dma); + usba_dma_writel(ep, CONTROL, req->ctrl); + } else { + next_fifo_transaction(ep, req); + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } else { + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + } + } +} + +static void submit_next_request(struct usba_ep *ep) +{ + struct usba_request *req; + + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + if (!req->submitted) + submit_request(ep, req); +} + +static void send_status(struct usba_udc *udc, struct usba_ep *ep) +{ + ep->state = STATUS_STAGE_IN; + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); +} + +static void receive_data(struct usba_ep *ep) +{ + struct usba_udc *udc = ep->udc; + struct usba_request *req; + unsigned long status; + unsigned int bytecount, nr_busy; + int is_complete = 0; + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy); + + while (nr_busy > 0) { + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + break; + } + req = list_entry(ep->queue.next, + struct usba_request, queue); + + bytecount = USBA_BFEXT(BYTE_COUNT, status); + + if (status & (1 << 31)) + is_complete = 1; + if (req->req.actual + bytecount >= req->req.length) { + is_complete = 1; + bytecount = req->req.length - req->req.actual; + } + + copy_from_fifo(req->req.buf + req->req.actual, + ep->fifo, bytecount); + req->req.actual += bytecount; + + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + + if (is_complete) { + DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name); + req->req.status = 0; + list_del_init(&req->queue); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); + } + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + if (is_complete && ep_is_control(ep)) { + send_status(udc, ep); + break; + } + } +} + +static void +request_complete(struct usba_ep *ep, struct usba_request *req, int status) +{ + struct usba_udc *udc = ep->udc; + + WARN_ON(!list_empty(&req->queue)); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + + if (req->mapped) { + dma_unmap_single( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } + + DBG(DBG_GADGET | DBG_REQ, + "%s: req %p complete: status %d, actual %u\n", + ep->ep.name, req, req->req.status, req->req.actual); + + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); +} + +static void +request_complete_list(struct usba_ep *ep, struct list_head *list, int status) +{ + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, list, queue) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } +} + +static int +usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags, ept_cfg, maxpacket; + unsigned int nr_trans; + + DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); + + maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; + + if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index) + || ep->index == 0 + || desc->bDescriptorType != USB_DT_ENDPOINT + || maxpacket == 0 + || maxpacket > ep->fifo_size) { + DBG(DBG_ERR, "ep_enable: Invalid argument"); + return -EINVAL; + } + + ep->is_isoc = 0; + ep->is_in = 0; + + if (maxpacket <= 8) + ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); + + DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", + ep->ep.name, ept_cfg, maxpacket); + + if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + ep->is_in = 1; + ept_cfg |= USBA_EPT_DIR_IN; + } + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); + break; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->can_isoc) { + DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n", + ep->ep.name); + return -EINVAL; + } + + /* + * Bits 11:12 specify number of _additional_ + * transactions per microframe. + */ + nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1; + if (nr_trans > 3) + return -EINVAL; + + ep->is_isoc = 1; + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + + /* + * Do triple-buffering on high-bandwidth iso endpoints. + */ + if (nr_trans > 1 && ep->nr_banks == 3) + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); + else + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ept_cfg |= USBA_BF(NB_TRANS, nr_trans); + break; + case USB_ENDPOINT_XFER_BULK: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + case USB_ENDPOINT_XFER_INT: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + } + + spin_lock_irqsave(&ep->udc->lock, flags); + + if (ep->desc) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + DBG(DBG_ERR, "ep%d already enabled\n", ep->index); + return -EBUSY; + } + + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + usba_ep_writel(ep, CFG, ept_cfg); + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + + if (ep->can_dma) { + u32 ctrl; + + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index) + | USBA_BF(DMA_INT, 1 << ep->index))); + ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA; + usba_ep_writel(ep, CTL_ENB, ctrl); + } else { + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index))); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index, + (unsigned long)usba_ep_readl(ep, CFG)); + DBG(DBG_HW, "INT_ENB after init: %#08lx\n", + (unsigned long)usba_readl(udc, INT_ENB)); + + return 0; +} + +static int usba_ep_disable(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + LIST_HEAD(req_list); + unsigned long flags; + + DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name); + + spin_lock_irqsave(&udc->lock, flags); + + if (!ep->desc) { + spin_unlock_irqrestore(&udc->lock, flags); + DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name); + return -EINVAL; + } + ep->desc = NULL; + + list_splice_init(&ep->queue, &req_list); + if (ep->can_dma) { + usba_dma_writel(ep, CONTROL, 0); + usba_dma_writel(ep, ADDRESS, 0); + usba_dma_readl(ep, STATUS); + } + usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); + usba_writel(udc, INT_ENB, + usba_readl(udc, INT_ENB) + & ~USBA_BF(EPT_INT, 1 << ep->index)); + + request_complete_list(ep, &req_list, -ESHUTDOWN); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static struct usb_request * +usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct usba_request *req; + + DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + req->req.dma = DMA_ADDR_INVALID; + + return &req->req; +} + +static void +usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_request *req = to_usba_req(_req); + + DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req); + + kfree(req); +} + +static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, + struct usba_request *req, gfp_t gfp_flags) +{ + unsigned long flags; + int ret; + + DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n", + ep->ep.name, req->req.length, req->req.dma, + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 'S' : 's', + req->req.no_interrupt ? 'I' : 'i'); + + if (req->req.length > 0x10000) { + /* Lengths from 0 to 65536 (inclusive) are supported */ + DBG(DBG_ERR, "invalid request length %u\n", req->req.length); + return -EINVAL; + } + + req->using_dma = 1; + + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single( + &udc->pdev->dev, req->req.buf, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 0; + } + + req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length) + | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE + | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; + + if (ep->is_in) + req->ctrl |= USBA_DMA_END_BUF_EN; + + /* + * Add this request to the queue and submit for DMA if + * possible. Check if we're still alive first -- we may have + * received a reset since last time we checked. + */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + if (list_empty(&ep->queue)) + submit_request(ep, req); + + list_add_tail(&req->queue, &ep->queue); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct usba_request *req = to_usba_req(_req); + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret; + + DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n", + ep->ep.name, req, _req->length); + + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc) + return -ESHUTDOWN; + + req->submitted = 0; + req->using_dma = 0; + req->last_transaction = 0; + + _req->status = -EINPROGRESS; + _req->actual = 0; + + if (ep->can_dma) + return queue_dma(udc, ep, req, gfp_flags); + + /* May have received a reset since last time we checked */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + list_add_tail(&req->queue, &ep->queue); + + if (ep->is_in || (ep_is_control(ep) + && (ep->state == DATA_STAGE_IN + || ep->state == STATUS_STAGE_IN))) + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + else + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static void +usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status) +{ + req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status); +} + +static int stop_dma(struct usba_ep *ep, u32 *pstatus) +{ + unsigned int timeout; + u32 status; + + /* + * Stop the DMA controller. When writing both CH_EN + * and LINK to 0, the other bits are not affected. + */ + usba_dma_writel(ep, CONTROL, 0); + + /* Wait for the FIFO to empty */ + for (timeout = 40; timeout; --timeout) { + status = usba_dma_readl(ep, STATUS); + if (!(status & USBA_DMA_CH_EN)) + break; + udelay(1); + } + + if (pstatus) + *pstatus = status; + + if (timeout == 0) { + dev_err(&ep->udc->pdev->dev, + "%s: timed out waiting for DMA FIFO to empty\n", + ep->ep.name); + return -ETIMEDOUT; + } + + return 0; +} + +static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + struct usba_request *req = to_usba_req(_req); + unsigned long flags; + u32 status; + + DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n", + ep->ep.name, req); + + spin_lock_irqsave(&udc->lock, flags); + + if (req->using_dma) { + /* + * If this request is currently being transferred, + * stop the DMA controller and reset the FIFO. + */ + if (ep->queue.next == &req->queue) { + status = usba_dma_readl(ep, STATUS); + if (status & USBA_DMA_CH_EN) + stop_dma(ep, &status); + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + + usba_writel(udc, EPT_RST, 1 << ep->index); + + usba_update_req(ep, req, status); + } + } + + /* + * Errors should stop the queue from advancing until the + * completion function returns. + */ + list_del_init(&req->queue); + + request_complete(ep, req, -ECONNRESET); + + /* Process the next request if any */ + submit_next_request(ep); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int usba_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret = 0; + + DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, + value ? "set" : "clear"); + + if (!ep->desc) { + DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", + ep->ep.name); + return -ENODEV; + } + if (ep->is_isoc) { + DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n", + ep->ep.name); + return -ENOTTY; + } + + spin_lock_irqsave(&udc->lock, flags); + + /* + * We can't halt IN endpoints while there are still data to be + * transferred + */ + if (!list_empty(&ep->queue) + || ((value && ep->is_in && (usba_ep_readl(ep, STA) + & USBA_BF(BUSY_BANKS, -1L))))) { + ret = -EAGAIN; + } else { + if (value) + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + else + usba_ep_writel(ep, CLR_STA, + USBA_FORCE_STALL | USBA_TOGGLE_CLR); + usba_ep_readl(ep, STA); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int usba_ep_fifo_status(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + + return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); +} + +static void usba_ep_fifo_flush(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + + usba_writel(udc, EPT_RST, 1 << ep->index); +} + +static const struct usb_ep_ops usba_ep_ops = { + .enable = usba_ep_enable, + .disable = usba_ep_disable, + .alloc_request = usba_ep_alloc_request, + .free_request = usba_ep_free_request, + .queue = usba_ep_queue, + .dequeue = usba_ep_dequeue, + .set_halt = usba_ep_set_halt, + .fifo_status = usba_ep_fifo_status, + .fifo_flush = usba_ep_fifo_flush, +}; + +static int usba_udc_get_frame(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + + return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); +} + +static const struct usb_gadget_ops usba_udc_ops = { + .get_frame = usba_udc_get_frame, +}; + +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ +{ \ + .ep = { \ + .ops = &usba_ep_ops, \ + .name = nam, \ + .maxpacket = maxpkt, \ + }, \ + .udc = &the_udc, \ + .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \ + .fifo_size = maxpkt, \ + .nr_banks = maxbk, \ + .index = idx, \ + .can_dma = dma, \ + .can_isoc = isoc, \ +} + +static struct usba_ep usba_ep[] = { + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1in-bulk", 1, 512, 2, 1, 1), + EP("ep2out-bulk", 2, 512, 2, 1, 1), + EP("ep3in-int", 3, 64, 3, 1, 0), + EP("ep4out-int", 4, 64, 3, 1, 0), + EP("ep5in-iso", 5, 1024, 3, 1, 1), + EP("ep6out-iso", 6, 1024, 3, 1, 1), +}; +#undef EP + +static struct usb_endpoint_descriptor usba_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = __constant_cpu_to_le16(64), + /* FIXME: I have no idea what to put here */ + .bInterval = 1, +}; + +static void nop_release(struct device *dev) +{ + +} + +static struct usba_udc the_udc = { + .gadget = { + .ops = &usba_udc_ops, + .ep0 = &usba_ep[0].ep, + .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), + .is_dualspeed = 1, + .name = "atmel_usba_udc", + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + .lock = SPIN_LOCK_UNLOCKED, +}; + +/* + * Called with interrupts disabled and udc->lock held. + */ +static void reset_all_endpoints(struct usba_udc *udc) +{ + struct usba_ep *ep; + struct usba_request *req, *tmp_req; + + usba_writel(udc, EPT_RST, ~0UL); + + ep = to_usba_ep(udc->gadget.ep0); + list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) { + list_del_init(&req->queue); + request_complete(ep, req, -ECONNRESET); + } + + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) + usba_ep_disable(&ep->ep); + } +} + +static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) +{ + struct usba_ep *ep; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return to_usba_ep(udc->gadget.ep0); + + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + + if (!ep->desc) + continue; + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) + == (wIndex & USB_ENDPOINT_NUMBER_MASK)) + return ep; + } + + return NULL; +} + +/* Called with interrupts disabled and udc->lock held */ +static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep) +{ + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + ep->state = WAIT_FOR_SETUP; +} + +static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep) +{ + if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL) + return 1; + return 0; +} + +static inline void set_address(struct usba_udc *udc, unsigned int addr) +{ + u32 regval; + + DBG(DBG_BUS, "setting address %u...\n", addr); + regval = usba_readl(udc, CTRL); + regval = USBA_BFINS(DEV_ADDR, addr, regval); + usba_writel(udc, CTRL, regval); +} + +static int do_test_mode(struct usba_udc *udc) +{ + static const char test_packet_buffer[] = { + /* JKJKJKJK * 9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* JJKKJJKK * 8 */ + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + /* JJKKJJKK * 8 */ + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + /* JJJJJJJKKKKKKK * 8 */ + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* JJJJJJJK * 8 */ + 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, + /* {JKKKKKKK * 10}, JK */ + 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E + }; + struct usba_ep *ep; + struct device *dev = &udc->pdev->dev; + int test_mode; + + test_mode = udc->test_mode; + + /* Start from a clean slate */ + reset_all_endpoints(udc); + + switch (test_mode) { + case 0x0100: + /* Test_J */ + usba_writel(udc, TST, USBA_TST_J_MODE); + dev_info(dev, "Entering Test_J mode...\n"); + break; + case 0x0200: + /* Test_K */ + usba_writel(udc, TST, USBA_TST_K_MODE); + dev_info(dev, "Entering Test_K mode...\n"); + break; + case 0x0300: + /* + * Test_SE0_NAK: Force high-speed mode and set up ep0 + * for Bulk IN transfers + */ + ep = &usba_ep[0]; + usba_writel(udc, TST, + USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH)); + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + dev_info(dev, "Entering Test_SE0_NAK mode...\n"); + } + break; + case 0x0400: + /* Test_Packet */ + ep = &usba_ep[0]; + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_Packet: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + usba_writel(udc, TST, USBA_TST_PKT_MODE); + copy_to_fifo(ep->fifo, test_packet_buffer, + sizeof(test_packet_buffer)); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + dev_info(dev, "Entering Test_Packet mode...\n"); + } + break; + default: + dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode); + return -EINVAL; + } + + return 0; +} + +/* Avoid overly long expressions */ +static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP)) + return true; + return false; +} + +static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE)) + return true; + return false; +} + +static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT)) + return true; + return false; +} + +static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, + struct usb_ctrlrequest *crq) +{ + int retval = 0;; + + switch (crq->bRequest) { + case USB_REQ_GET_STATUS: { + u16 status; + + if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { + /* Self-powered, no remote wakeup */ + status = __constant_cpu_to_le16(1 << 0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_INTERFACE)) { + status = __constant_cpu_to_le16(0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_ENDPOINT)) { + struct usba_ep *target; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + status = 0; + if (is_stalled(udc, target)) + status |= __constant_cpu_to_le16(1); + } else + goto delegate; + + /* Write directly to the FIFO. No queueing is done. */ + if (crq->wLength != __constant_cpu_to_le16(sizeof(status))) + goto stall; + ep->state = DATA_STAGE_IN; + __raw_writew(status, ep->fifo); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + break; + } + + case USB_REQ_CLEAR_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_remote_wakeup(crq)) { + /* TODO: Handle REMOTE_WAKEUP */ + } else { + /* Can't CLEAR_FEATURE TEST_MODE */ + goto stall; + } + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL); + if (target->index != 0) + usba_ep_writel(target, CLR_STA, + USBA_TOGGLE_CLR); + } else { + goto delegate; + } + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_test_mode(crq)) { + send_status(udc, ep); + ep->state = STATUS_STAGE_TEST; + udc->test_mode = le16_to_cpu(crq->wIndex); + return 0; + } else if (feature_is_dev_remote_wakeup(crq)) { + /* TODO: Handle REMOTE_WAKEUP */ + } else { + goto stall; + } + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, SET_STA, USBA_FORCE_STALL); + } else + goto delegate; + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_ADDRESS: + if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) + goto delegate; + + set_address(udc, le16_to_cpu(crq->wValue)); + send_status(udc, ep); + ep->state = STATUS_STAGE_ADDR; + break; + + default: +delegate: + spin_unlock(&udc->lock); + retval = udc->driver->setup(&udc->gadget, crq); + spin_lock(&udc->lock); + } + + return retval; + +stall: + printk(KERN_ERR + "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " + "halting endpoint...\n", + ep->ep.name, crq->bRequestType, crq->bRequest, + le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), + le16_to_cpu(crq->wLength)); + set_protocol_stall(udc, ep); + return -1; +} + +static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + +restart: + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n", + ep->ep.name, ep->state, epstatus, epctrl); + + req = NULL; + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct usba_request, queue); + + if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } + goto restart; + } + if ((epstatus & epctrl) & USBA_TX_COMPLETE) { + usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE); + + switch (ep->state) { + case DATA_STAGE_IN: + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = STATUS_STAGE_OUT; + break; + case STATUS_STAGE_ADDR: + /* Activate our new address */ + usba_writel(udc, CTRL, (usba_readl(udc, CTRL) + | USBA_FADDR_EN)); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_IN: + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + submit_next_request(ep); + } + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_TEST: + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + if (do_test_mode(udc)) + set_protocol_stall(udc, ep); + break; + default: + printk(KERN_ERR + "udc: %s: TXCOMP: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + switch (ep->state) { + case STATUS_STAGE_OUT: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + } + ep->state = WAIT_FOR_SETUP; + break; + + case DATA_STAGE_OUT: + receive_data(ep); + break; + + default: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + printk(KERN_ERR + "udc: %s: RXRDY: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if (epstatus & USBA_RX_SETUP) { + union { + struct usb_ctrlrequest crq; + unsigned long data[2]; + } crq; + unsigned int pkt_len; + int ret; + + if (ep->state != WAIT_FOR_SETUP) { + /* + * Didn't expect a SETUP packet at this + * point. Clean up any pending requests (which + * may be successful). + */ + int status = -EPROTO; + + /* + * RXRDY and TXCOMP are dropped when SETUP + * packets arrive. Just pretend we received + * the status packet. + */ + if (ep->state == STATUS_STAGE_OUT + || ep->state == STATUS_STAGE_IN) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + status = 0; + } + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } + } + + pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); + DBG(DBG_HW, "Packet length: %u\n", pkt_len); + if (pkt_len != sizeof(crq)) { + printk(KERN_WARNING "udc: Invalid packet length %u " + "(expected %lu)\n", pkt_len, sizeof(crq)); + set_protocol_stall(udc, ep); + return; + } + + DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); + copy_from_fifo(crq.data, ep->fifo, sizeof(crq)); + + /* Free up one bank in the FIFO so that we can + * generate or receive a reply right away. */ + usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP); + + /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n", + ep->state, crq.crq.bRequestType, + crq.crq.bRequest); */ + + if (crq.crq.bRequestType & USB_DIR_IN) { + /* + * The USB 2.0 spec states that "if wLength is + * zero, there is no data transfer phase." + * However, testusb #14 seems to actually + * expect a data phase even if wLength = 0... + */ + ep->state = DATA_STAGE_IN; + } else { + if (crq.crq.wLength != __constant_cpu_to_le16(0)) + ep->state = DATA_STAGE_OUT; + else + ep->state = STATUS_STAGE_IN; + } + + ret = -1; + if (ep->index == 0) + ret = handle_ep0_setup(udc, ep, &crq.crq); + else { + spin_unlock(&udc->lock); + ret = udc->driver->setup(&udc->gadget, &crq.crq); + spin_lock(&udc->lock); + } + + DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n", + crq.crq.bRequestType, crq.crq.bRequest, + le16_to_cpu(crq.crq.wLength), ep->state, ret); + + if (ret < 0) { + /* Let the host know that we failed */ + set_protocol_stall(udc, ep); + } + } +} + +static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus); + + while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name); + + if (list_empty(&ep->queue)) { + dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n"); + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + + if (req->using_dma) { + /* Send a zero-length packet */ + usba_ep_writel(ep, SET_STA, + USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_DIS, + USBA_TX_PK_RDY); + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } else { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } + } + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name); + receive_data(ep); + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + } +} + +static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 status, control, pending; + + status = usba_dma_readl(ep, STATUS); + control = usba_dma_readl(ep, CONTROL); +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + pending = status & control; + DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control); + + if (status & USBA_DMA_CH_EN) { + dev_err(&udc->pdev->dev, + "DMA_CH_EN is set after transfer is finished!\n"); + dev_err(&udc->pdev->dev, + "status=%#08x, pending=%#08x, control=%#08x\n", + status, pending, control); + + /* + * try to pretend nothing happened. We might have to + * do something here... + */ + } + + if (list_empty(&ep->queue)) + /* Might happen if a reset comes along at the right moment */ + return; + + if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) { + req = list_entry(ep->queue.next, struct usba_request, queue); + usba_update_req(ep, req, status); + + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } +} + +static irqreturn_t usba_udc_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + u32 status; + u32 dma_status; + u32 ep_status; + + spin_lock(&udc->lock); + + status = usba_readl(udc, INT_STA); + DBG(DBG_INT, "irq, status=%#08x\n", status); + + if (status & USBA_DET_SUSPEND) { + usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); + DBG(DBG_BUS, "Suspend detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->suspend) { + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } + + if (status & USBA_WAKE_UP) { + usba_writel(udc, INT_CLR, USBA_WAKE_UP); + DBG(DBG_BUS, "Wake Up CPU detected\n"); + } + + if (status & USBA_END_OF_RESUME) { + usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); + DBG(DBG_BUS, "Resume detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } + } + + dma_status = USBA_BFEXT(DMA_INT, status); + if (dma_status) { + int i; + + for (i = 1; i < USBA_NR_ENDPOINTS; i++) + if (dma_status & (1 << i)) + usba_dma_irq(udc, &usba_ep[i]); + } + + ep_status = USBA_BFEXT(EPT_INT, status); + if (ep_status) { + int i; + + for (i = 0; i < USBA_NR_ENDPOINTS; i++) + if (ep_status & (1 << i)) { + if (ep_is_control(&usba_ep[i])) + usba_control_irq(udc, &usba_ep[i]); + else + usba_ep_irq(udc, &usba_ep[i]); + } + } + + if (status & USBA_END_OF_RESET) { + struct usba_ep *ep0; + + usba_writel(udc, INT_CLR, USBA_END_OF_RESET); + reset_all_endpoints(udc); + + if (status & USBA_HIGH_SPEED) { + DBG(DBG_BUS, "High-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_HIGH; + } else { + DBG(DBG_BUS, "Full-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_FULL; + } + + ep0 = &usba_ep[0]; + ep0->desc = &usba_ep0_desc; + ep0->state = WAIT_FOR_SETUP; + usba_ep_writel(ep0, CFG, + (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL) + | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); + usba_ep_writel(ep0, CTL_ENB, + USBA_EPT_ENABLE | USBA_RX_SETUP); + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1) + | USBA_DET_SUSPEND + | USBA_END_OF_RESUME)); + + if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) + dev_warn(&udc->pdev->dev, + "WARNING: EP0 configuration is invalid!\n"); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t usba_vbus_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + int vbus; + + /* debounce */ + udelay(10); + + spin_lock(&udc->lock); + + /* May happen if Vbus pin toggles during probe() */ + if (!udc->driver) + goto out; + + vbus = gpio_get_value(udc->vbus_pin); + if (vbus != udc->vbus_prev) { + if (vbus) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } else { + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + usba_writel(udc, CTRL, 0); + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + udc->vbus_prev = vbus; + } + +out: + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + int ret; + + if (!udc->pdev) + return -ENODEV; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EBUSY; + } + + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, flags); + + clk_enable(udc->pclk); + clk_enable(udc->hclk); + + ret = driver->bind(&udc->gadget); + if (ret) { + DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", + driver->driver.name, ret); + goto err_driver_bind; + } + + DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); + + udc->vbus_prev = 0; + if (udc->vbus_pin != -1) + enable_irq(gpio_to_irq(udc->vbus_pin)); + + /* If Vbus is present, enable the controller and wait for reset */ + spin_lock_irqsave(&udc->lock, flags); + if (vbus_is_present(udc) && udc->vbus_prev == 0) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; + +err_driver_bind: + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return ret; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + + if (!udc->pdev) + return -ENODEV; + if (driver != udc->driver) + return -EINVAL; + + if (udc->vbus_pin != -1) + disable_irq(gpio_to_irq(udc->vbus_pin)); + + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + /* This will also disable the DP pullup */ + usba_writel(udc, CTRL, 0); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + + clk_disable(udc->hclk); + clk_disable(udc->pclk); + + DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +static int __init usba_udc_probe(struct platform_device *pdev) +{ + struct usba_platform_data *pdata = pdev->dev.platform_data; + struct resource *regs, *fifo; + struct clk *pclk, *hclk; + struct usba_udc *udc = &the_udc; + int irq, ret, i; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); + fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); + if (!regs || !fifo) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + pclk = clk_get(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) + return PTR_ERR(pclk); + hclk = clk_get(&pdev->dev, "hclk"); + if (IS_ERR(hclk)) { + ret = PTR_ERR(hclk); + goto err_get_hclk; + } + + udc->pdev = pdev; + udc->pclk = pclk; + udc->hclk = hclk; + udc->vbus_pin = -1; + + ret = -ENOMEM; + udc->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!udc->regs) { + dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); + goto err_map_regs; + } + dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n", + (unsigned long)regs->start, udc->regs); + udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1); + if (!udc->fifo) { + dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); + goto err_map_fifo; + } + dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n", + (unsigned long)fifo->start, udc->fifo); + + device_initialize(&udc->gadget.dev); + udc->gadget.dev.parent = &pdev->dev; + udc->gadget.dev.dma_mask = pdev->dev.dma_mask; + + platform_set_drvdata(pdev, udc); + + /* Make sure we start from a clean slate */ + clk_enable(pclk); + usba_writel(udc, CTRL, 0); + clk_disable(pclk); + + INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); + usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); + usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); + usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) { + struct usba_ep *ep = &usba_ep[i]; + + ep->ep_regs = udc->regs + USBA_EPT_BASE(i); + ep->dma_regs = udc->regs + USBA_DMA_BASE(i); + ep->fifo = udc->fifo + USBA_FIFO_BASE(i); + + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + } + + ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); + if (ret) { + dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n", + irq, ret); + goto err_request_irq; + } + udc->irq = irq; + + ret = device_add(&udc->gadget.dev); + if (ret) { + dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret); + goto err_device_add; + } + + if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) { + if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { + udc->vbus_pin = pdata->vbus_pin; + + ret = request_irq(gpio_to_irq(udc->vbus_pin), + usba_vbus_irq, 0, + "atmel_usba_udc", udc); + if (ret) { + gpio_free(udc->vbus_pin); + udc->vbus_pin = -1; + dev_warn(&udc->pdev->dev, + "failed to request vbus irq; " + "assuming always on\n"); + } else { + disable_irq(gpio_to_irq(udc->vbus_pin)); + } + } + } + + usba_init_debugfs(udc); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_init_debugfs(udc, &usba_ep[i]); + + return 0; + +err_device_add: + free_irq(irq, udc); +err_request_irq: + iounmap(udc->fifo); +err_map_fifo: + iounmap(udc->regs); +err_map_regs: + clk_put(hclk); +err_get_hclk: + clk_put(pclk); + + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __exit usba_udc_remove(struct platform_device *pdev) +{ + struct usba_udc *udc; + int i; + + udc = platform_get_drvdata(pdev); + + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_cleanup_debugfs(&usba_ep[i]); + usba_cleanup_debugfs(udc); + + if (udc->vbus_pin != -1) + gpio_free(udc->vbus_pin); + + free_irq(udc->irq, udc); + iounmap(udc->fifo); + iounmap(udc->regs); + clk_put(udc->hclk); + clk_put(udc->pclk); + + device_unregister(&udc->gadget.dev); + + return 0; +} + +static struct platform_driver udc_driver = { + .remove = __exit_p(usba_udc_remove), + .driver = { + .name = "atmel_usba_udc", + }, +}; + +static int __init udc_init(void) +{ + return platform_driver_probe(&udc_driver, usba_udc_probe); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION("Atmel USBA UDC driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h new file mode 100644 index 000000000000..f4f0f8bf812c --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -0,0 +1,350 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel 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. + */ +#ifndef __LINUX_USB_GADGET_USBA_UDC_H__ +#define __LINUX_USB_GADGET_USBA_UDC_H__ + +/* USB register offsets */ +#define USBA_CTRL 0x0000 +#define USBA_FNUM 0x0004 +#define USBA_INT_ENB 0x0010 +#define USBA_INT_STA 0x0014 +#define USBA_INT_CLR 0x0018 +#define USBA_EPT_RST 0x001c +#define USBA_TST 0x00e0 + +/* USB endpoint register offsets */ +#define USBA_EPT_CFG 0x0000 +#define USBA_EPT_CTL_ENB 0x0004 +#define USBA_EPT_CTL_DIS 0x0008 +#define USBA_EPT_CTL 0x000c +#define USBA_EPT_SET_STA 0x0014 +#define USBA_EPT_CLR_STA 0x0018 +#define USBA_EPT_STA 0x001c + +/* USB DMA register offsets */ +#define USBA_DMA_NXT_DSC 0x0000 +#define USBA_DMA_ADDRESS 0x0004 +#define USBA_DMA_CONTROL 0x0008 +#define USBA_DMA_STATUS 0x000c + +/* Bitfields in CTRL */ +#define USBA_DEV_ADDR_OFFSET 0 +#define USBA_DEV_ADDR_SIZE 7 +#define USBA_FADDR_EN (1 << 7) +#define USBA_EN_USBA (1 << 8) +#define USBA_DETACH (1 << 9) +#define USBA_REMOTE_WAKE_UP (1 << 10) + +/* Bitfields in FNUM */ +#define USBA_MICRO_FRAME_NUM_OFFSET 0 +#define USBA_MICRO_FRAME_NUM_SIZE 3 +#define USBA_FRAME_NUMBER_OFFSET 3 +#define USBA_FRAME_NUMBER_SIZE 11 +#define USBA_FRAME_NUM_ERROR (1 << 31) + +/* Bitfields in INT_ENB/INT_STA/INT_CLR */ +#define USBA_HIGH_SPEED (1 << 0) +#define USBA_DET_SUSPEND (1 << 1) +#define USBA_MICRO_SOF (1 << 2) +#define USBA_SOF (1 << 3) +#define USBA_END_OF_RESET (1 << 4) +#define USBA_WAKE_UP (1 << 5) +#define USBA_END_OF_RESUME (1 << 6) +#define USBA_UPSTREAM_RESUME (1 << 7) +#define USBA_EPT_INT_OFFSET 8 +#define USBA_EPT_INT_SIZE 16 +#define USBA_DMA_INT_OFFSET 24 +#define USBA_DMA_INT_SIZE 8 + +/* Bitfields in EPT_RST */ +#define USBA_RST_OFFSET 0 +#define USBA_RST_SIZE 16 + +/* Bitfields in USBA_TST */ +#define USBA_SPEED_CFG_OFFSET 0 +#define USBA_SPEED_CFG_SIZE 2 +#define USBA_TST_J_MODE (1 << 2) +#define USBA_TST_K_MODE (1 << 3) +#define USBA_TST_PKT_MODE (1 << 4) +#define USBA_OPMODE2 (1 << 5) + +/* Bitfields in EPT_CFG */ +#define USBA_EPT_SIZE_OFFSET 0 +#define USBA_EPT_SIZE_SIZE 3 +#define USBA_EPT_DIR_IN (1 << 3) +#define USBA_EPT_TYPE_OFFSET 4 +#define USBA_EPT_TYPE_SIZE 2 +#define USBA_BK_NUMBER_OFFSET 6 +#define USBA_BK_NUMBER_SIZE 2 +#define USBA_NB_TRANS_OFFSET 8 +#define USBA_NB_TRANS_SIZE 2 +#define USBA_EPT_MAPPED (1 << 31) + +/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */ +#define USBA_EPT_ENABLE (1 << 0) +#define USBA_AUTO_VALID (1 << 1) +#define USBA_INTDIS_DMA (1 << 3) +#define USBA_NYET_DIS (1 << 4) +#define USBA_DATAX_RX (1 << 6) +#define USBA_MDATA_RX (1 << 7) +/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */ +#define USBA_BUSY_BANK_IE (1 << 18) + +/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */ +#define USBA_FORCE_STALL (1 << 5) +#define USBA_TOGGLE_CLR (1 << 6) +#define USBA_TOGGLE_SEQ_OFFSET 6 +#define USBA_TOGGLE_SEQ_SIZE 2 +#define USBA_ERR_OVFLW (1 << 8) +#define USBA_RX_BK_RDY (1 << 9) +#define USBA_KILL_BANK (1 << 9) +#define USBA_TX_COMPLETE (1 << 10) +#define USBA_TX_PK_RDY (1 << 11) +#define USBA_ISO_ERR_TRANS (1 << 11) +#define USBA_RX_SETUP (1 << 12) +#define USBA_ISO_ERR_FLOW (1 << 12) +#define USBA_STALL_SENT (1 << 13) +#define USBA_ISO_ERR_CRC (1 << 13) +#define USBA_ISO_ERR_NBTRANS (1 << 13) +#define USBA_NAK_IN (1 << 14) +#define USBA_ISO_ERR_FLUSH (1 << 14) +#define USBA_NAK_OUT (1 << 15) +#define USBA_CURRENT_BANK_OFFSET 16 +#define USBA_CURRENT_BANK_SIZE 2 +#define USBA_BUSY_BANKS_OFFSET 18 +#define USBA_BUSY_BANKS_SIZE 2 +#define USBA_BYTE_COUNT_OFFSET 20 +#define USBA_BYTE_COUNT_SIZE 11 +#define USBA_SHORT_PACKET (1 << 31) + +/* Bitfields in DMA_CONTROL */ +#define USBA_DMA_CH_EN (1 << 0) +#define USBA_DMA_LINK (1 << 1) +#define USBA_DMA_END_TR_EN (1 << 2) +#define USBA_DMA_END_BUF_EN (1 << 3) +#define USBA_DMA_END_TR_IE (1 << 4) +#define USBA_DMA_END_BUF_IE (1 << 5) +#define USBA_DMA_DESC_LOAD_IE (1 << 6) +#define USBA_DMA_BURST_LOCK (1 << 7) +#define USBA_DMA_BUF_LEN_OFFSET 16 +#define USBA_DMA_BUF_LEN_SIZE 16 + +/* Bitfields in DMA_STATUS */ +#define USBA_DMA_CH_ACTIVE (1 << 1) +#define USBA_DMA_END_TR_ST (1 << 4) +#define USBA_DMA_END_BUF_ST (1 << 5) +#define USBA_DMA_DESC_LOAD_ST (1 << 6) + +/* Constants for SPEED_CFG */ +#define USBA_SPEED_CFG_NORMAL 0 +#define USBA_SPEED_CFG_FORCE_HIGH 2 +#define USBA_SPEED_CFG_FORCE_FULL 3 + +/* Constants for EPT_SIZE */ +#define USBA_EPT_SIZE_8 0 +#define USBA_EPT_SIZE_16 1 +#define USBA_EPT_SIZE_32 2 +#define USBA_EPT_SIZE_64 3 +#define USBA_EPT_SIZE_128 4 +#define USBA_EPT_SIZE_256 5 +#define USBA_EPT_SIZE_512 6 +#define USBA_EPT_SIZE_1024 7 + +/* Constants for EPT_TYPE */ +#define USBA_EPT_TYPE_CONTROL 0 +#define USBA_EPT_TYPE_ISO 1 +#define USBA_EPT_TYPE_BULK 2 +#define USBA_EPT_TYPE_INT 3 + +/* Constants for BK_NUMBER */ +#define USBA_BK_NUMBER_ZERO 0 +#define USBA_BK_NUMBER_ONE 1 +#define USBA_BK_NUMBER_DOUBLE 2 +#define USBA_BK_NUMBER_TRIPLE 3 + +/* Bit manipulation macros */ +#define USBA_BF(name, value) \ + (((value) & ((1 << USBA_##name##_SIZE) - 1)) \ + << USBA_##name##_OFFSET) +#define USBA_BFEXT(name, value) \ + (((value) >> USBA_##name##_OFFSET) \ + & ((1 << USBA_##name##_SIZE) - 1)) +#define USBA_BFINS(name, value, old) \ + (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \ + << USBA_##name##_OFFSET)) \ + | USBA_BF(name, value)) + +/* Register access macros */ +#define usba_readl(udc, reg) \ + __raw_readl((udc)->regs + USBA_##reg) +#define usba_writel(udc, reg, value) \ + __raw_writel((value), (udc)->regs + USBA_##reg) +#define usba_ep_readl(ep, reg) \ + __raw_readl((ep)->ep_regs + USBA_EPT_##reg) +#define usba_ep_writel(ep, reg, value) \ + __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg) +#define usba_dma_readl(ep, reg) \ + __raw_readl((ep)->dma_regs + USBA_DMA_##reg) +#define usba_dma_writel(ep, reg, value) \ + __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg) + +/* Calculate base address for a given endpoint or DMA controller */ +#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20) +#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10) +#define USBA_FIFO_BASE(x) ((x) << 16) + +/* Synth parameters */ +#define USBA_NR_ENDPOINTS 7 + +#define EP0_FIFO_SIZE 64 +#define EP0_EPT_SIZE USBA_EPT_SIZE_64 +#define EP0_NR_BANKS 1 + +/* + * REVISIT: Try to eliminate this value. Can we rely on req->mapped to + * provide this information? + */ +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +#define FIFO_IOMEM_ID 0 +#define CTRL_IOMEM_ID 1 + +#ifdef DEBUG +#define DBG_ERR 0x0001 /* report all error returns */ +#define DBG_HW 0x0002 /* debug hardware initialization */ +#define DBG_GADGET 0x0004 /* calls to/from gadget driver */ +#define DBG_INT 0x0008 /* interrupts */ +#define DBG_BUS 0x0010 /* report changes in bus state */ +#define DBG_QUEUE 0x0020 /* debug request queue processing */ +#define DBG_FIFO 0x0040 /* debug FIFO contents */ +#define DBG_DMA 0x0080 /* debug DMA handling */ +#define DBG_REQ 0x0100 /* print out queued request length */ +#define DBG_ALL 0xffff +#define DBG_NONE 0x0000 + +#define DEBUG_LEVEL (DBG_ERR) +#define DBG(level, fmt, ...) \ + do { \ + if ((level) & DEBUG_LEVEL) \ + printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \ + } while (0) +#else +#define DBG(level, fmt...) +#endif + +enum usba_ctrl_state { + WAIT_FOR_SETUP, + DATA_STAGE_IN, + DATA_STAGE_OUT, + STATUS_STAGE_IN, + STATUS_STAGE_OUT, + STATUS_STAGE_ADDR, + STATUS_STAGE_TEST, +}; +/* + EP_STATE_IDLE, + EP_STATE_SETUP, + EP_STATE_IN_DATA, + EP_STATE_OUT_DATA, + EP_STATE_SET_ADDR_STATUS, + EP_STATE_RX_STATUS, + EP_STATE_TX_STATUS, + EP_STATE_HALT, +*/ + +struct usba_dma_desc { + dma_addr_t next; + dma_addr_t addr; + u32 ctrl; +}; + +struct usba_ep { + int state; + void __iomem *ep_regs; + void __iomem *dma_regs; + void __iomem *fifo; + struct usb_ep ep; + struct usba_udc *udc; + + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + + u16 fifo_size; + u8 nr_banks; + u8 index; + unsigned int can_dma:1; + unsigned int can_isoc:1; + unsigned int is_isoc:1; + unsigned int is_in:1; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + u32 last_dma_status; + struct dentry *debugfs_dir; + struct dentry *debugfs_queue; + struct dentry *debugfs_dma_status; + struct dentry *debugfs_state; +#endif +}; + +struct usba_request { + struct usb_request req; + struct list_head queue; + + u32 ctrl; + + unsigned int submitted:1; + unsigned int last_transaction:1; + unsigned int using_dma:1; + unsigned int mapped:1; +}; + +struct usba_udc { + /* Protect hw registers from concurrent modifications */ + spinlock_t lock; + + void __iomem *regs; + void __iomem *fifo; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct platform_device *pdev; + int irq; + int vbus_pin; + struct clk *pclk; + struct clk *hclk; + + int test_mode; + int vbus_prev; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + struct dentry *debugfs_root; + struct dentry *debugfs_regs; +#endif +}; + +static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) +{ + return container_of(ep, struct usba_ep, ep); +} + +static inline struct usba_request *to_usba_req(struct usb_request *req) +{ + return container_of(req, struct usba_request, req); +} + +static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct usba_udc, gadget); +} + +#define ep_is_control(ep) ((ep)->index == 0) +#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE) + +#endif /* __LINUX_USB_GADGET_USBA_UDC_H */ From eecfb911a03a48ef5f7114246343128bd01c1b5f Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 11 Oct 2007 00:37:50 +0900 Subject: [PATCH 2753/2804] USB: Adding support for SHARP WS011SH to ipaq.c This patch supports for SHARP WS011SH[0] to ipaq.c [0]: http://www.willcom-inc.com/ja/lineup/ws/011sh/index.html (Sorry , Japanese only.) Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c1a6484f6524..e836ad07fdb9 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */ { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */ { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */ + { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */ { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ From 17f060224fb9f435c6f9306b7b61419d038def13 Mon Sep 17 00:00:00 2001 From: Richard Sharpe Date: Wed, 10 Oct 2007 10:56:28 -0700 Subject: [PATCH 2754/2804] USB: allow usbstorage to have LUNS greater than 2Tb Attached is a very small patch (several comment lines) and a one-line coded change) that allows for USB storage devices that are larger than 2TB. At the company where I work we need such support, and one of my co-workers, Jane Liu, pointed out that SCSI low-layer drivers need to specify what size CDBs they accept. After looking through the code it became obvious that the current USB Storage code accepted the default of 12-byte CDBs, so I changed it to accept 16-byte CDBs. This allows our device to work. Signed-off-by: Richard Sharpe Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 59181667066c..3451e8d03ab0 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -960,6 +960,10 @@ static int storage_probe(struct usb_interface *intf, return -ENOMEM; } + /* + * Allow 16-byte CDBs and thus > 2TB + */ + host->max_cmd_len = 16; us = host_to_us(host); memset(us, 0, sizeof(struct us_data)); mutex_init(&(us->dev_mutex)); From 32fe01985aa2cb2562f6fc171e526e279abe10db Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:27:07 -0400 Subject: [PATCH 2755/2804] USB: mutual exclusion for EHCI init and port resets This patch (as999) fixes a problem that sometimes shows up when host controller driver modules are loaded in the wrong order. If ehci-hcd happens to initialize an EHCI controller while the companion OHCI or UHCI controller is in the middle of a port reset, the reset can fail and the companion may get very confused. The patch adds an rw-semaphore and uses it to keep EHCI initialization and port resets mutually exclusive. Signed-off-by: Alan Stern Acked-by: David Brownell Cc: David Miller Cc: Dely L Sy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.h | 8 +++++++- drivers/usb/core/hub.c | 15 ++++++++++++++- drivers/usb/host/ehci-hcd.c | 8 ++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 1396141274f1..98e24194a4ab 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -19,6 +19,8 @@ #ifdef __KERNEL__ +#include + /* This file contains declarations of usbcore internals that are mostly * used or exposed by Host Controller Drivers. */ @@ -470,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, : (in_interrupt () ? "in_interrupt" : "can sleep")) -#endif /* __KERNEL__ */ +/* This rwsem is for use only by the hub driver and ehci-hcd. + * Nobody else should touch it. + */ +extern struct rw_semaphore ehci_cf_port_reset_rwsem; +#endif /* __KERNEL__ */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 481dca641ea2..d20cb545a6e4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " "first one fails"); +/* Mutual exclusion for EHCI CF initialization. This interferes with + * port reset on some companion controllers. + */ +DECLARE_RWSEM(ehci_cf_port_reset_rwsem); +EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); + static inline char *portspeed(int portstatus) { @@ -1581,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1, { int i, status; + /* Block EHCI CF initialization during the port reset. + * Some companion controllers don't like it when they mix. + */ + down_read(&ehci_cf_port_reset_rwsem); + /* Reset the port */ for (i = 0; i < PORT_RESET_TRIES; i++) { status = set_port_feature(hub->hdev, @@ -1612,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); - return status; + goto done; } dev_dbg (hub->intfdev, @@ -1625,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, "Cannot enable port %i. Maybe the USB cable is bad?\n", port1); + done: + up_read(&ehci_cf_port_reset_rwsem); return status; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index db00492588b6..c1514442883e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd) * are explicitly handed to companion controller(s), so no TT is * involved with the root hub. (Except where one is integrated, * and there's no companion controller unless maybe for USB OTG.) + * + * Turning on the CF flag will transfer ownership of all ports + * from the companions to the EHCI controller. If any of the + * companions are in the middle of a port reset at the time, it + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem + * guarantees that no resets are in progress. */ + down_write(&ehci_cf_port_reset_rwsem); hcd->state = HC_STATE_RUNNING; ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + up_write(&ehci_cf_port_reset_rwsem); temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, From 271f9e68f3450ac8d1ff3bda36581f1ec0d0cc1f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:30:12 -0400 Subject: [PATCH 2756/2804] USB: skip autosuspended devices during system resume System suspends and hibernation are supposed to be as transparent as possible. By this reasoning, if a USB device is already autosuspended before the system sleep begins then it should remain autosuspended after the system wakes up. This patch (as1001) adds a skip_sys_resume flag to the usb_device structure and uses it to avoid waking up devices which were suspended when a system sleep began. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 27 ++++++++++++++++++++------- include/linux/usb.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 3f734240e0ec..8c1eac27f2de 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1540,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev) static int usb_suspend(struct device *dev, pm_message_t message) { + struct usb_device *udev; + if (!is_usb_device(dev)) /* Ignore PM for interfaces */ return 0; - return usb_external_suspend_device(to_usb_device(dev), message); + udev = to_usb_device(dev); + + /* If udev is already suspended, we can skip this suspend and + * we should also skip the upcoming system resume. */ + if (udev->state == USB_STATE_SUSPENDED) { + udev->skip_sys_resume = 1; + return 0; + } + + udev->skip_sys_resume = 0; + return usb_external_suspend_device(udev, message); } static int usb_resume(struct device *dev) @@ -1553,13 +1565,14 @@ static int usb_resume(struct device *dev) return 0; udev = to_usb_device(dev); - /* If autoresume is disabled then we also want to prevent resume - * during system wakeup. However, a "persistent-device" reset-resume - * after power loss counts as a wakeup event. So allow a - * reset-resume to occur if remote wakeup is enabled. */ - if (udev->autoresume_disabled) { + /* If udev->skip_sys_resume is set then udev was already suspended + * when the system suspend started, so we don't want to resume + * udev during this system wakeup. However a reset-resume counts + * as a wakeup event, so allow a reset-resume to occur if remote + * wakeup is enabled. */ + if (udev->skip_sys_resume) { if (!(udev->reset_resume && udev->do_remote_wakeup)) - return -EPERM; + return -EHOSTUNREACH; } return usb_external_resume_device(udev); } diff --git a/include/linux/usb.h b/include/linux/usb.h index c10935fdc03a..c5c8f169d3cf 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -430,6 +430,7 @@ struct usb_device { unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */ unsigned autosuspend_disabled:1; /* autosuspend and autoresume */ unsigned autoresume_disabled:1; /* disabled by the user */ + unsigned skip_sys_resume:1; /* skip the next system resume */ #endif }; #define to_usb_device(d) container_of(d, struct usb_device, dev) From cd38c1e1ae5273c28a12baacaf17c1faa062661f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:24:56 -0400 Subject: [PATCH 2757/2804] USB: documentation for USB power management This patch (as998) adds documentation on how USB power management works and how to use it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/power-management.txt | 517 +++++++++++++++++++++++++ 1 file changed, 517 insertions(+) create mode 100644 Documentation/usb/power-management.txt diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt new file mode 100644 index 000000000000..97842deec471 --- /dev/null +++ b/Documentation/usb/power-management.txt @@ -0,0 +1,517 @@ + Power Management for USB + + Alan Stern + + October 5, 2007 + + + + What is Power Management? + ------------------------- + +Power Management (PM) is the practice of saving energy by suspending +parts of a computer system when they aren't being used. While a +component is "suspended" it is in a nonfunctional low-power state; it +might even be turned off completely. A suspended component can be +"resumed" (returned to a functional full-power state) when the kernel +needs to use it. (There also are forms of PM in which components are +placed in a less functional but still usable state instead of being +suspended; an example would be reducing the CPU's clock rate. This +document will not discuss those other forms.) + +When the parts being suspended include the CPU and most of the rest of +the system, we speak of it as a "system suspend". When a particular +device is turned off while the system as a whole remains running, we +call it a "dynamic suspend" (also known as a "runtime suspend" or +"selective suspend"). This document concentrates mostly on how +dynamic PM is implemented in the USB subsystem, although system PM is +covered to some extent (see Documentation/power/*.txt for more +information about system PM). + +Note: Dynamic PM support for USB is present only if the kernel was +built with CONFIG_USB_SUSPEND enabled. System PM support is present +only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION +enabled. + + + What is Remote Wakeup? + ---------------------- + +When a device has been suspended, it generally doesn't resume until +the computer tells it to. Likewise, if the entire computer has been +suspended, it generally doesn't resume until the user tells it to, say +by pressing a power button or opening the cover. + +However some devices have the capability of resuming by themselves, or +asking the kernel to resume them, or even telling the entire computer +to resume. This capability goes by several names such as "Wake On +LAN"; we will refer to it generically as "remote wakeup". When a +device is enabled for remote wakeup and it is suspended, it may resume +itself (or send a request to be resumed) in response to some external +event. Examples include a suspended keyboard resuming when a key is +pressed, or a suspended USB hub resuming when a device is plugged in. + + + When is a USB device idle? + -------------------------- + +A device is idle whenever the kernel thinks it's not busy doing +anything important and thus is a candidate for being suspended. The +exact definition depends on the device's driver; drivers are allowed +to declare that a device isn't idle even when there's no actual +communication taking place. (For example, a hub isn't considered idle +unless all the devices plugged into that hub are already suspended.) +In addition, a device isn't considered idle so long as a program keeps +its usbfs file open, whether or not any I/O is going on. + +If a USB device has no driver, its usbfs file isn't open, and it isn't +being accessed through sysfs, then it definitely is idle. + + + Forms of dynamic PM + ------------------- + +Dynamic suspends can occur in two ways: manual and automatic. +"Manual" means that the user has told the kernel to suspend a device, +whereas "automatic" means that the kernel has decided all by itself to +suspend a device. Automatic suspend is called "autosuspend" for +short. In general, a device won't be autosuspended unless it has been +idle for some minimum period of time, the so-called idle-delay time. + +Of course, nothing the kernel does on its own initiative should +prevent the computer or its devices from working properly. If a +device has been autosuspended and a program tries to use it, the +kernel will automatically resume the device (autoresume). For the +same reason, an autosuspended device will usually have remote wakeup +enabled, if the device supports remote wakeup. + +It is worth mentioning that many USB drivers don't support +autosuspend. In fact, at the time of this writing (Linux 2.6.23) the +only drivers which do support it are the hub driver, kaweth, asix, +usblp, usblcd, and usb-skeleton (which doesn't count). If a +non-supporting driver is bound to a device, the device won't be +autosuspended. In effect, the kernel pretends the device is never +idle. + +We can categorize power management events in two broad classes: +external and internal. External events are those triggered by some +agent outside the USB stack: system suspend/resume (triggered by +userspace), manual dynamic suspend/resume (also triggered by +userspace), and remote wakeup (triggered by the device). Internal +events are those triggered within the USB stack: autosuspend and +autoresume. + + + The user interface for dynamic PM + --------------------------------- + +The user interface for controlling dynamic PM is located in the power/ +subdirectory of each USB device's sysfs directory, that is, in +/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The +relevant attribute files are: wakeup, level, and autosuspend. + + power/wakeup + + This file is empty if the device does not support + remote wakeup. Otherwise the file contains either the + word "enabled" or the word "disabled", and you can + write those words to the file. The setting determines + whether or not remote wakeup will be enabled when the + device is next suspended. (If the setting is changed + while the device is suspended, the change won't take + effect until the following suspend.) + + power/level + + This file contains one of three words: "on", "auto", + or "suspend". You can write those words to the file + to change the device's setting. + + "on" means that the device should be resumed and + autosuspend is not allowed. (Of course, system + suspends are still allowed.) + + "auto" is the normal state in which the kernel is + allowed to autosuspend and autoresume the device. + + "suspend" means that the device should remain + suspended, and autoresume is not allowed. (But remote + wakeup may still be allowed, since it is controlled + separately by the power/wakeup attribute.) + + power/autosuspend + + This file contains an integer value, which is the + number of seconds the device should remain idle before + the kernel will autosuspend it (the idle-delay time). + The default is 2. 0 means to autosuspend as soon as + the device becomes idle, and -1 means never to + autosuspend. You can write a number to the file to + change the autosuspend idle-delay time. + +Writing "-1" to power/autosuspend and writing "on" to power/level do +essentially the same thing -- they both prevent the device from being +autosuspended. Yes, this is a redundancy in the API. + +(In 2.6.21 writing "0" to power/autosuspend would prevent the device +from being autosuspended; the behavior was changed in 2.6.22. The +power/autosuspend attribute did not exist prior to 2.6.21, and the +power/level attribute did not exist prior to 2.6.22.) + + + Changing the default idle-delay time + ------------------------------------ + +The default autosuspend idle-delay time is controlled by a module +parameter in usbcore. You can specify the value when usbcore is +loaded. For example, to set it to 5 seconds instead of 2 you would +do: + + modprobe usbcore autosuspend=5 + +Equivalently, you could add to /etc/modprobe.conf a line saying: + + options usbcore autosuspend=5 + +Some distributions load the usbcore module very early during the boot +process, by means of a program or script running from an initramfs +image. To alter the parameter value you would have to rebuild that +image. + +If usbcore is compiled into the kernel rather than built as a loadable +module, you can add + + usbcore.autosuspend=5 + +to the kernel's boot command line. + +Finally, the parameter value can be changed while the system is +running. If you do: + + echo 5 >/sys/module/usbcore/parameters/autosuspend + +then each new USB device will have its autosuspend idle-delay +initialized to 5. (The idle-delay values for already existing devices +will not be affected.) + +Setting the initial default idle-delay to -1 will prevent any +autosuspend of any USB device. This is a simple alternative to +disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the +added benefit of allowing you to enable autosuspend for selected +devices. + + + Warnings + -------- + +The USB specification states that all USB devices must support power +management. Nevertheless, the sad fact is that many devices do not +support it very well. You can suspend them all right, but when you +try to resume them they disconnect themselves from the USB bus or +they stop working entirely. This seems to be especially prevalent +among printers and scanners, but plenty of other types of device have +the same deficiency. + +For this reason, by default the kernel disables autosuspend (the +power/level attribute is initialized to "on") for all devices other +than hubs. Hubs, at least, appear to be reasonably well-behaved in +this regard. + +(In 2.6.21 and 2.6.22 this wasn't the case. Autosuspend was enabled +by default for almost all USB devices. A number of people experienced +problems as a result.) + +This means that non-hub devices won't be autosuspended unless the user +or a program explicitly enables it. As of this writing there aren't +any widespread programs which will do this; we hope that in the near +future device managers such as HAL will take on this added +responsibility. In the meantime you can always carry out the +necessary operations by hand or add them to a udev script. You can +also change the idle-delay time; 2 seconds is not the best choice for +every device. + +Sometimes it turns out that even when a device does work okay with +autosuspend there are still problems. For example, there are +experimental patches adding autosuspend support to the usbhid driver, +which manages keyboards and mice, among other things. Tests with a +number of keyboards showed that typing on a suspended keyboard, while +causing the keyboard to do a remote wakeup all right, would +nonetheless frequently result in lost keystrokes. Tests with mice +showed that some of them would issue a remote-wakeup request in +response to button presses but not to motion, and some in response to +neither. + +The kernel will not prevent you from enabling autosuspend on devices +that can't handle it. It is even possible in theory to damage a +device by suspending it at the wrong time -- for example, suspending a +USB hard disk might cause it to spin down without parking the heads. +(Highly unlikely, but possible.) Take care. + + + The driver interface for Power Management + ----------------------------------------- + +The requirements for a USB driver to support external power management +are pretty modest; the driver need only define + + .suspend + .resume + .reset_resume + +methods in its usb_driver structure, and the reset_resume method is +optional. The methods' jobs are quite simple: + + The suspend method is called to warn the driver that the + device is going to be suspended. If the driver returns a + negative error code, the suspend will be aborted. Normally + the driver will return 0, in which case it must cancel all + outstanding URBs (usb_kill_urb()) and not submit any more. + + The resume method is called to tell the driver that the + device has been resumed and the driver can return to normal + operation. URBs may once more be submitted. + + The reset_resume method is called to tell the driver that + the device has been resumed and it also has been reset. + The driver should redo any necessary device initialization, + since the device has probably lost most or all of its state + (although the interfaces will be in the same altsettings as + before the suspend). + +The reset_resume method is used by the USB Persist facility (see +Documentation/usb/persist.txt) and it can also be used under certain +circumstances when CONFIG_USB_PERSIST is not enabled. Currently, if a +device is reset during a resume and the driver does not have a +reset_resume method, the driver won't receive any notification about +the resume. Later kernels will call the driver's disconnect method; +2.6.23 doesn't do this. + +USB drivers are bound to interfaces, so their suspend and resume +methods get called when the interfaces are suspended or resumed. In +principle one might want to suspend some interfaces on a device (i.e., +force the drivers for those interface to stop all activity) without +suspending the other interfaces. The USB core doesn't allow this; all +interfaces are suspended when the device itself is suspended and all +interfaces are resumed when the device is resumed. It isn't possible +to suspend or resume some but not all of a device's interfaces. The +closest you can come is to unbind the interfaces' drivers. + + + The driver interface for autosuspend and autoresume + --------------------------------------------------- + +To support autosuspend and autoresume, a driver should implement all +three of the methods listed above. In addition, a driver indicates +that it supports autosuspend by setting the .supports_autosuspend flag +in its usb_driver structure. It is then responsible for informing the +USB core whenever one of its interfaces becomes busy or idle. The +driver does so by calling these three functions: + + int usb_autopm_get_interface(struct usb_interface *intf); + void usb_autopm_put_interface(struct usb_interface *intf); + int usb_autopm_set_interface(struct usb_interface *intf); + +The functions work by maintaining a counter in the usb_interface +structure. When intf->pm_usage_count is > 0 then the interface is +deemed to be busy, and the kernel will not autosuspend the interface's +device. When intf->pm_usage_count is <= 0 then the interface is +considered to be idle, and the kernel may autosuspend the device. + +(There is a similar pm_usage_count field in struct usb_device, +associated with the device itself rather than any of its interfaces. +This field is used only by the USB core.) + +The driver owns intf->pm_usage_count; it can modify the value however +and whenever it likes. A nice aspect of the usb_autopm_* routines is +that the changes they make are protected by the usb_device structure's +PM mutex (udev->pm_mutex); however drivers may change pm_usage_count +without holding the mutex. + + usb_autopm_get_interface() increments pm_usage_count and + attempts an autoresume if the new value is > 0 and the + device is suspended. + + usb_autopm_put_interface() decrements pm_usage_count and + attempts an autosuspend if the new value is <= 0 and the + device isn't suspended. + + usb_autopm_set_interface() leaves pm_usage_count alone. + It attempts an autoresume if the value is > 0 and the device + is suspended, and it attempts an autosuspend if the value is + <= 0 and the device isn't suspended. + +There also are a couple of utility routines drivers can use: + + usb_autopm_enable() sets pm_usage_cnt to 1 and then calls + usb_autopm_set_interface(), which will attempt an autoresume. + + usb_autopm_disable() sets pm_usage_cnt to 0 and then calls + usb_autopm_set_interface(), which will attempt an autosuspend. + +The conventional usage pattern is that a driver calls +usb_autopm_get_interface() in its open routine and +usb_autopm_put_interface() in its close or release routine. But +other patterns are possible. + +The autosuspend attempts mentioned above will often fail for one +reason or another. For example, the power/level attribute might be +set to "on", or another interface in the same device might not be +idle. This is perfectly normal. If the reason for failure was that +the device hasn't been idle for long enough, a delayed workqueue +routine is automatically set up to carry out the operation when the +autosuspend idle-delay has expired. + +Autoresume attempts also can fail. This will happen if power/level is +set to "suspend" or if the device doesn't manage to resume properly. +Unlike autosuspend, there's no delay for an autoresume. + + + Other parts of the driver interface + ----------------------------------- + +Sometimes a driver needs to make sure that remote wakeup is enabled +during autosuspend. For example, there's not much point +autosuspending a keyboard if the user can't cause the keyboard to do a +remote wakeup by typing on it. If the driver sets +intf->needs_remote_wakeup to 1, the kernel won't autosuspend the +device if remote wakeup isn't available or has been disabled through +the power/wakeup attribute. (If the device is already autosuspended, +though, setting this flag won't cause the kernel to autoresume it. +Normally a driver would set this flag in its probe method, at which +time the device is guaranteed not to be autosuspended.) + +The usb_autopm_* routines have to run in a sleepable process context; +they must not be called from an interrupt handler or while holding a +spinlock. In fact, the entire autosuspend mechanism is not well geared +toward interrupt-driven operation. However there is one thing a +driver can do in an interrupt handler: + + usb_mark_last_busy(struct usb_device *udev); + +This sets udev->last_busy to the current time. udev->last_busy is the +field used for idle-delay calculations; updating it will cause any +pending autosuspend to be moved back. The usb_autopm_* routines will +also set the last_busy field to the current time. + +Calling urb_mark_last_busy() from within an URB completion handler is +subject to races: The kernel may have just finished deciding the +device has been idle for long enough but not yet gotten around to +calling the driver's suspend method. The driver would have to be +responsible for synchronizing its suspend method with its URB +completion handler and causing the autosuspend to fail with -EBUSY if +an URB had completed too recently. + +External suspend calls should never be allowed to fail in this way, +only autosuspend calls. The driver can tell them apart by checking +udev->auto_pm; this flag will be set to 1 for internal PM events +(autosuspend or autoresume) and 0 for external PM events. + +Many of the ingredients in the autosuspend framework are oriented +towards interfaces: The usb_interface structure contains the +pm_usage_cnt field, and the usb_autopm_* routines take an interface +pointer as their argument. But somewhat confusingly, a few of the +pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device +structure instead. Drivers need to keep this straight; they can call +interface_to_usbdev() to find the device structure for a given +interface. + + + Locking requirements + -------------------- + +All three suspend/resume methods are always called while holding the +usb_device's PM mutex. For external events -- but not necessarily for +autosuspend or autoresume -- the device semaphore (udev->dev.sem) will +also be held. This implies that external suspend/resume events are +mutually exclusive with calls to probe, disconnect, pre_reset, and +post_reset; the USB core guarantees that this is true of internal +suspend/resume events as well. + +If a driver wants to block all suspend/resume calls during some +critical section, it can simply acquire udev->pm_mutex. +Alternatively, if the critical section might call some of the +usb_autopm_* routines, the driver can avoid deadlock by doing: + + down(&udev->dev.sem); + rc = usb_autopm_get_interface(intf); + +and at the end of the critical section: + + if (!rc) + usb_autopm_put_interface(intf); + up(&udev->dev.sem); + +Holding the device semaphore will block all external PM calls, and the +usb_autopm_get_interface() will prevent any internal PM calls, even if +it fails. (Exercise: Why?) + +The rules for locking order are: + + Never acquire any device semaphore while holding any PM mutex. + + Never acquire udev->pm_mutex while holding the PM mutex for + a device that isn't a descendant of udev. + +In other words, PM mutexes should only be acquired going up the device +tree, and they should be acquired only after locking all the device +semaphores you need to hold. These rules don't matter to drivers very +much; they usually affect just the USB core. + +Still, drivers do need to be careful. For example, many drivers use a +private mutex to synchronize their normal I/O activities with their +disconnect method. Now if the driver supports autosuspend then it +must call usb_autopm_put_interface() from somewhere -- maybe from its +close method. It should make the call while holding the private mutex, +since a driver shouldn't call any of the usb_autopm_* functions for an +interface from which it has been unbound. + +But the usb_autpm_* routines always acquire the device's PM mutex, and +consequently the locking order has to be: private mutex first, PM +mutex second. Since the suspend method is always called with the PM +mutex held, it mustn't try to acquire the private mutex. It has to +synchronize with the driver's I/O activities in some other way. + + + Interaction between dynamic PM and system PM + -------------------------------------------- + +Dynamic power management and system power management can interact in +a couple of ways. + +Firstly, a device may already be manually suspended or autosuspended +when a system suspend occurs. Since system suspends are supposed to +be as transparent as possible, the device should remain suspended +following the system resume. The 2.6.23 kernel obeys this principle +for manually suspended devices but not for autosuspended devices; they +do get resumed when the system wakes up. (Presumably they will be +autosuspended again after their idle-delay time expires.) In later +kernels this behavior will be fixed. + +(There is an exception. If a device would undergo a reset-resume +instead of a normal resume, and the device is enabled for remote +wakeup, then the reset-resume takes place even if the device was +already suspended when the system suspend began. The justification is +that a reset-resume is a kind of remote-wakeup event. Or to put it +another way, a device which needs a reset won't be able to generate +normal remote-wakeup signals, so it ought to be resumed immediately.) + +Secondly, a dynamic power-management event may occur as a system +suspend is underway. The window for this is short, since system +suspends don't take long (a few seconds usually), but it can happen. +For example, a suspended device may send a remote-wakeup signal while +the system is suspending. The remote wakeup may succeed, which would +cause the system suspend to abort. If the remote wakeup doesn't +succeed, it may still remain active and thus cause the system to +resume as soon as the system suspend is complete. Or the remote +wakeup may fail and get lost. Which outcome occurs depends on timing +and on the hardware and firmware design. + +More interestingly, a device might undergo a manual resume or +autoresume during system suspend. With current kernels this shouldn't +happen, because manual resumes must be initiated by userspace and +autoresumes happen in response to I/O requests, but all user processes +and I/O should be quiescent during a system suspend -- thanks to the +freezer. However there are plans to do away with the freezer, which +would mean these things would become possible. If and when this comes +about, the USB core will carefully arrange matters so that either type +of resume will block until the entire system has resumed. From 063a2da8f01806906f7d7b1a1424b9afddebc443 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:24:06 -0400 Subject: [PATCH 2758/2804] USB: serial core should respect driver requirements This patch (as997) fixes a bug in the USB serial core. The core needs to pay attention to drivers' requirements regarding the number and type of endpoints a device has. At the same time, the patch changes the NUM_DONT_CARE constant (which is stored in a single-byte field) from -1 to a safer, unsigned value. It also improves the kerneldoc for several fields in the usb_serial_driver structure. Finally, the patch replaces a list_for_each() with list_for_each_entry(). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 31 ++++++++++++++++++++++--------- include/linux/usb/serial.h | 20 +++++++++++++------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 26e015c39a31..4b1bd7def4a5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -662,16 +662,14 @@ exit: static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { - struct list_head *p; const struct usb_device_id *id; - struct usb_serial_driver *t; + struct usb_serial_driver *drv; /* Check if the usb id matches a known device */ - list_for_each(p, &usb_serial_driver_list) { - t = list_entry(p, struct usb_serial_driver, driver_list); - id = get_iface_id(t, iface); + list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { + id = get_iface_id(drv, iface); if (id) - return t; + return drv; } return NULL; @@ -811,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface, /* END HORRIBLE HACK FOR PL2303 */ #endif - /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", type->description); - #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; @@ -847,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface, serial->num_interrupt_in = num_interrupt_in; serial->num_interrupt_out = num_interrupt_out; + /* check that the device meets the driver's requirements */ + if ((type->num_interrupt_in != NUM_DONT_CARE && + type->num_interrupt_in != num_interrupt_in) + || (type->num_interrupt_out != NUM_DONT_CARE && + type->num_interrupt_out != num_interrupt_out) + || (type->num_bulk_in != NUM_DONT_CARE && + type->num_bulk_in != num_bulk_in) + || (type->num_bulk_out != NUM_DONT_CARE && + type->num_bulk_out != num_bulk_out)) { + dbg("wrong number of endpoints"); + kfree(serial); + return -EIO; + } + + /* found all that we need */ + dev_info(&interface->dev, "%s converter detected\n", + type->description); + /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ max_endpoints = max(num_bulk_in, num_bulk_out); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index e8b8928232c8..488ce128885c 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -141,7 +141,7 @@ struct usb_serial { }; #define to_usb_serial(d) container_of(d, struct usb_serial, kref) -#define NUM_DONT_CARE (-1) +#define NUM_DONT_CARE 99 /* get and set the serial private data pointer helper functions */ static inline void *usb_get_serial_data (struct usb_serial *serial) @@ -160,12 +160,18 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) * in the syslog messages when a device is inserted or removed. * @id_table: pointer to a list of usb_device_id structures that define all * of the devices this structure can support. - * @num_interrupt_in: the number of interrupt in endpoints this device will - * have. - * @num_interrupt_out: the number of interrupt out endpoints this device will - * have. - * @num_bulk_in: the number of bulk in endpoints this device will have. - * @num_bulk_out: the number of bulk out endpoints this device will have. + * @num_interrupt_in: If a device doesn't have this many interrupt-in + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_interrupt_out: If a device doesn't have this many interrupt-out + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_bulk_in: If a device doesn't have this many bulk-in + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_bulk_out: If a device doesn't have this many bulk-out + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) * @num_ports: the number of different ports this device will have. * @calc_num_ports: pointer to a function to determine how many ports this * device has dynamically. It will be called after the probe() From d466a9190ff1ceddfee50686e61d63590fc820d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ortwin=20Gl=C3=BCck?= Date: Thu, 11 Oct 2007 17:29:43 +0200 Subject: [PATCH 2759/2804] USB: Nikon D40X unusual_devs entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not surprisingly the Nikon D40X DSC needs the same quirks as the D40, but it has a separate ID. See http://bugs.gentoo.org/show_bug.cgi?id=191431 From: Ortwin Glรผck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index edf92914674a..9b656ec427d0 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -369,6 +369,13 @@ UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Shan Destromp (shansan@gmail.com) */ +UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D40X", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena and * Frank Copeland */ From 58ed7b94d98245fbad54a0af7ea3317ab1dd6876 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 11 Oct 2007 13:40:30 -0700 Subject: [PATCH 2760/2804] atmel_usba_udc: Keep track of the device status Keep track of the device status (as returned by the GET_STATUS request) and allow it to be manipulated by set_selfpowered() as well as SET_FEATURE/CLEAR_FEATURE (for remote wakeup) Implement the wakeup() op, which refuses to do anything if the DEVICE_REMOTE_WAKEUP feature wasn't set by the host. Now this driver passes USBCV (at least, with gadget zero). Fix one more locking bug; lockdep is every developer's friend. Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/atmel_usba_udc.c | 57 ++++++++++++++++++++++++----- drivers/usb/gadget/atmel_usba_udc.h | 4 +- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 2bb28a583937..4fb5ff469574 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -989,8 +989,44 @@ static int usba_udc_get_frame(struct usb_gadget *gadget) return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); } +static int usba_udc_wakeup(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + u32 ctrl; + int ret = -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + ctrl = usba_readl(udc, CTRL); + usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + if (is_selfpowered) + udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; + else + udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + static const struct usb_gadget_ops usba_udc_ops = { - .get_frame = usba_udc_get_frame, + .get_frame = usba_udc_get_frame, + .wakeup = usba_udc_wakeup, + .set_selfpowered = usba_udc_set_selfpowered, }; #define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ @@ -1068,8 +1104,11 @@ static void reset_all_endpoints(struct usba_udc *udc) } list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) + if (ep->desc) { + spin_unlock(&udc->lock); usba_ep_disable(&ep->ep); + spin_lock(&udc->lock); + } } } @@ -1238,8 +1277,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, u16 status; if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { - /* Self-powered, no remote wakeup */ - status = __constant_cpu_to_le16(1 << 0); + status = cpu_to_le16(udc->devstatus); } else if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_INTERFACE)) { status = __constant_cpu_to_le16(0); @@ -1268,12 +1306,12 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, case USB_REQ_CLEAR_FEATURE: { if (crq->bRequestType == USB_RECIP_DEVICE) { - if (feature_is_dev_remote_wakeup(crq)) { - /* TODO: Handle REMOTE_WAKEUP */ - } else { + if (feature_is_dev_remote_wakeup(crq)) + udc->devstatus + &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); + else /* Can't CLEAR_FEATURE TEST_MODE */ goto stall; - } } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { struct usba_ep *target; @@ -1304,7 +1342,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, udc->test_mode = le16_to_cpu(crq->wIndex); return 0; } else if (feature_is_dev_remote_wakeup(crq)) { - /* TODO: Handle REMOTE_WAKEUP */ + udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP; } else { goto stall; } @@ -1791,6 +1829,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) return -EBUSY; } + udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; udc->driver = driver; udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index f4f0f8bf812c..a68304e31a68 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -320,7 +320,9 @@ struct usba_udc { struct clk *pclk; struct clk *hclk; - int test_mode; + u16 devstatus; + + u16 test_mode; int vbus_prev; #ifdef CONFIG_USB_GADGET_DEBUG_FS From d1aa3e6aa8edfeb864af7c930523d9e588b28bea Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 11 Oct 2007 16:47:36 -0400 Subject: [PATCH 2761/2804] USB: fix race in autosuspend reschedule This patch (as1002) fixes a small race which can occur when a driver expects usbcore to reschedule an autosuspend request. If the request arrives too late, it won't be rescheduled. The patch adds an extra argument to autosuspend_check(), indicating that a reschedule is needed no matter how much time has elapsed. It also tries to avoid letting asynchronous changes to the value of jiffies cause a delay to become negative, by caching a local copy of the current time. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8c1eac27f2de..c27bc080d84e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -950,11 +950,11 @@ done: #ifdef CONFIG_USB_SUSPEND /* Internal routine to check whether we may autosuspend a device. */ -static int autosuspend_check(struct usb_device *udev) +static int autosuspend_check(struct usb_device *udev, int reschedule) { int i; struct usb_interface *intf; - unsigned long suspend_time; + unsigned long suspend_time, j; /* For autosuspend, fail fast if anything is in use or autosuspend * is disabled. Also fail if any interfaces require remote wakeup @@ -996,20 +996,20 @@ static int autosuspend_check(struct usb_device *udev) } /* If everything is okay but the device hasn't been idle for long - * enough, queue a delayed autosuspend request. + * enough, queue a delayed autosuspend request. If the device + * _has_ been idle for long enough and the reschedule flag is set, + * likewise queue a delayed (1 second) autosuspend request. */ - if (time_after(suspend_time, jiffies)) { + j = jiffies; + if (time_before(j, suspend_time)) + reschedule = 1; + else + suspend_time = j + HZ; + if (reschedule) { if (!timer_pending(&udev->autosuspend.timer)) { - - /* The value of jiffies may change between the - * time_after() comparison above and the subtraction - * below. That's okay; the system behaves sanely - * when a timer is registered for the present moment - * or for the past. - */ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - round_jiffies_relative(suspend_time - jiffies)); - } + round_jiffies_relative(suspend_time - j)); + } return -EAGAIN; } return 0; @@ -1017,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev) #else -static inline int autosuspend_check(struct usb_device *udev) +static inline int autosuspend_check(struct usb_device *udev, int reschedule) { return 0; } @@ -1074,7 +1074,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->auto_pm) { - status = autosuspend_check(udev); + status = autosuspend_check(udev, 0); if (status < 0) goto done; } @@ -1100,7 +1100,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* Try another autosuspend when the interfaces aren't busy */ if (udev->auto_pm) - autosuspend_check(udev); + autosuspend_check(udev, status == -EBUSY); /* If the suspend succeeded then prevent any more URB submissions, * flush any outstanding URBs, and propagate the suspend up the tree. From 73a985a140cd0f1b17fa1438af0359d6b9b32b16 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 19:14:28 +0200 Subject: [PATCH 2762/2804] PCI Hotplug: cpqphp_ctrl.c: kmalloc + memset conversion to kzalloc drivers/pci/hotplug/cpqphp_ctrl.c | 79698 -> 79638 (-60 bytes) drivers/pci/hotplug/cpqphp_ctrl.o | 192896 -> 192736 (-160 bytes) Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpqphp_ctrl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 37d72f123a80..dcafa2aaef8a 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -973,16 +973,13 @@ struct pci_func *cpqhp_slot_create(u8 busnumber) struct pci_func *new_slot; struct pci_func *next; - new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); - + new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL); if (new_slot == NULL) { /* I'm not dead yet! * You will be. */ return new_slot; } - memset(new_slot, 0, sizeof(struct pci_func)); - new_slot->next = NULL; new_slot->configured = 1; From 89913bf77a60fdb6ff204a670d3e191848a7b2c8 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:30 -0700 Subject: [PATCH 2763/2804] pciehp: remove CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE Remove unnecessary CONFIG_HOTPLUG_PCI_PCIE_EVENT_MODE. The CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE option is not needed because polling mechanism can be enabled through 'pciehp_poll_mode' module option. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_core.c | 4 ---- drivers/pci/pcie/Kconfig | 9 --------- 2 files changed, 13 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index e5d3f0b4f45a..3d692a971218 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -540,10 +540,6 @@ static int __init pcied_init(void) { int retval = 0; -#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE - pciehp_poll_mode = 1; -#endif - retval = pcie_port_service_register(&hpdriver_portdrv); dbg("pcie_port_service_register = %d\n", retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 0ad92a8ad8b1..287a9311716c 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -25,13 +25,4 @@ config HOTPLUG_PCI_PCIE When in doubt, say N. -config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE - bool "Use polling mechanism for hot-plug events (for testing purpose)" - depends on HOTPLUG_PCI_PCIE - help - Say Y here if you want to use the polling mechanism for hot-plug - events for early platform testing. - - When in doubt, say N. - source "drivers/pci/pcie/aer/Kconfig" From 1cf53d5ddb93b77ce1e277da85fe695e4c2a667d Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 9 Aug 2007 16:09:31 -0700 Subject: [PATCH 2764/2804] PCI Hotplug: pciehp: Dont check bridge control on remove When removing a device with a bridge on it, only read the bridge control register if the adapter is actually present. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_pci.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 854aaea09e4d..8f2b25c49f84 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -243,9 +243,10 @@ int pciehp_configure_device(struct slot *p_slot) int pciehp_unconfigure_device(struct slot *p_slot) { - int rc = 0; + int ret, rc = 0; int j; u8 bctl = 0; + u8 presence = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, @@ -263,12 +264,17 @@ int pciehp_unconfigure_device(struct slot *p_slot) continue; } if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); - if (bctl & PCI_BRIDGE_CTL_VGA) { - err("Cannot remove display device %s\n", + ret = p_slot->hpc_ops->get_adapter_status(p_slot, + &presence); + if (!ret && presence) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, + &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + err("Cannot remove display device %s\n", pci_name(temp)); - pci_dev_put(temp); - continue; + pci_dev_put(temp); + continue; + } } } pci_remove_bus_device(temp); From 57d90c027641169b0724f94d355704e28895bcd6 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 9 Aug 2007 16:09:32 -0700 Subject: [PATCH 2765/2804] PCI Hotplug: pciehp: Request control over PCI Express Capability as well as Native hotplug According to the PCI firmware spec (3.0), the OS must claim control over the PCI Express Capability bits in addition to the PCI Express Native Hot Plug feature when executing _OSC. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 016eea94a8a5..dbd04660babb 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1138,6 +1138,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) dbg("Trying to get hotplug control for %s \n", (char *)string.pointer); status = pci_osc_control_set(handle, + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); if (status == AE_NOT_FOUND) status = acpi_run_oshp(handle); From c8426483776d913c5bdc3d698a7633496a885b78 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:33 -0700 Subject: [PATCH 2766/2804] pciehp: remove DBG_XXX_ROUTINE This patch removes DBG_ENTER_ROUTIN, DBG_LEAVE_ROUTINE and related code, which seem no longer needed. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 111 ++----------------------------- 1 file changed, 5 insertions(+), 106 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index dbd04660babb..f6143175de71 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -39,37 +39,6 @@ #include "../pci.h" #include "pciehp.h" -#ifdef DEBUG -#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ -#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ -#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ -#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ -#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) -#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) -/* Redefine this flagword to set debug level */ -#define DEBUG_LEVEL DBG_K_STANDARD - -#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; - -#define DBG_PRINT( dbg_flags, args... ) \ - do { \ - if ( DEBUG_LEVEL & ( dbg_flags ) ) \ - { \ - int len; \ - len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ - __FILE__, __LINE__, __FUNCTION__ ); \ - sprintf( __dbg_str_buf + len, args ); \ - printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ - } \ - } while (0) - -#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); -#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); -#else -#define DEFINE_DBG_BUFFER -#define DBG_ENTER_ROUTINE -#define DBG_LEAVE_ROUTINE -#endif /* DEBUG */ static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); @@ -221,8 +190,6 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) #define EMI_STATE 0x0080 #define EMI_STATUS_BIT 7 -DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ - static irqreturn_t pcie_isr(int irq, void *dev_id); static void start_int_poll_timer(struct controller *ctrl, int sec); @@ -231,8 +198,6 @@ static void int_poll_timeout(unsigned long data) { struct controller *ctrl = (struct controller *)data; - DBG_ENTER_ROUTINE - /* Poll for interrupt events. regs == NULL => polling */ pcie_isr(0, ctrl); @@ -289,8 +254,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) u16 slot_ctrl; unsigned long flags; - DBG_ENTER_ROUTINE - mutex_lock(&ctrl->ctrl_lock); retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); @@ -332,7 +295,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) retval = pcie_wait_cmd(ctrl); out: mutex_unlock(&ctrl->ctrl_lock); - DBG_LEAVE_ROUTINE return retval; } @@ -341,8 +303,6 @@ static int hpc_check_lnk_status(struct controller *ctrl) u16 lnk_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); @@ -357,7 +317,6 @@ static int hpc_check_lnk_status(struct controller *ctrl) return retval; } - DBG_LEAVE_ROUTINE return retval; } @@ -368,8 +327,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) u16 slot_ctrl; u8 atten_led_state; int retval = 0; - - DBG_ENTER_ROUTINE retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { @@ -400,7 +357,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) break; } - DBG_LEAVE_ROUTINE return 0; } @@ -410,8 +366,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) u16 slot_ctrl; u8 pwr_state; int retval = 0; - - DBG_ENTER_ROUTINE retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { @@ -435,7 +389,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) break; } - DBG_LEAVE_ROUTINE return retval; } @@ -446,8 +399,6 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); @@ -456,7 +407,6 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; - DBG_LEAVE_ROUTINE return 0; } @@ -467,8 +417,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) u8 card_state; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); @@ -477,7 +425,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) card_state = (u8)((slot_status & PRSN_STATE) >> 6); *status = (card_state == 1) ? 1 : 0; - DBG_LEAVE_ROUTINE return 0; } @@ -488,8 +435,6 @@ static int hpc_query_power_fault(struct slot *slot) u8 pwr_fault; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot check for power fault\n", __FUNCTION__); @@ -497,7 +442,6 @@ static int hpc_query_power_fault(struct slot *slot) } pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); - DBG_LEAVE_ROUTINE return pwr_fault; } @@ -507,8 +451,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status) u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s : Cannot check EMI status\n", __FUNCTION__); @@ -516,7 +458,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status) } *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT; - DBG_LEAVE_ROUTINE return retval; } @@ -526,8 +467,6 @@ static int hpc_toggle_emi(struct slot *slot) u16 cmd_mask; int rc; - DBG_ENTER_ROUTINE - slot_cmd = EMI_CTRL; cmd_mask = EMI_CTRL; if (!pciehp_poll_mode) { @@ -537,7 +476,7 @@ static int hpc_toggle_emi(struct slot *slot) rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); slot->last_emi_toggle = get_seconds(); - DBG_LEAVE_ROUTINE + return rc; } @@ -548,8 +487,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) u16 cmd_mask; int rc; - DBG_ENTER_ROUTINE - cmd_mask = ATTN_LED_CTRL; switch (value) { case 0 : /* turn off */ @@ -573,7 +510,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE return rc; } @@ -584,8 +520,6 @@ static void hpc_set_green_led_on(struct slot *slot) u16 slot_cmd; u16 cmd_mask; - DBG_ENTER_ROUTINE - slot_cmd = 0x0100; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -597,8 +531,6 @@ static void hpc_set_green_led_on(struct slot *slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return; } static void hpc_set_green_led_off(struct slot *slot) @@ -607,8 +539,6 @@ static void hpc_set_green_led_off(struct slot *slot) u16 slot_cmd; u16 cmd_mask; - DBG_ENTER_ROUTINE - slot_cmd = 0x0300; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -619,9 +549,6 @@ static void hpc_set_green_led_off(struct slot *slot) pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - - DBG_LEAVE_ROUTINE - return; } static void hpc_set_green_led_blink(struct slot *slot) @@ -630,8 +557,6 @@ static void hpc_set_green_led_blink(struct slot *slot) u16 slot_cmd; u16 cmd_mask; - DBG_ENTER_ROUTINE - slot_cmd = 0x0200; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -643,14 +568,10 @@ static void hpc_set_green_led_blink(struct slot *slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return; } static void hpc_release_ctlr(struct controller *ctrl) { - DBG_ENTER_ROUTINE - if (pciehp_poll_mode) del_timer(&ctrl->poll_timer); else @@ -662,8 +583,6 @@ static void hpc_release_ctlr(struct controller *ctrl) */ if (atomic_dec_and_test(&pciehp_num_controllers)) destroy_workqueue(pciehp_wq); - - DBG_LEAVE_ROUTINE } static int hpc_power_on_slot(struct slot * slot) @@ -674,8 +593,6 @@ static int hpc_power_on_slot(struct slot * slot) u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); /* Clear sticky power-fault bit from previous power failures */ @@ -719,8 +636,6 @@ static int hpc_power_on_slot(struct slot * slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return retval; } @@ -731,8 +646,6 @@ static int hpc_power_off_slot(struct slot * slot) u16 cmd_mask; int retval = 0; - DBG_ENTER_ROUTINE - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); slot_cmd = POWER_OFF; @@ -764,8 +677,6 @@ static int hpc_power_off_slot(struct slot * slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return retval; } @@ -915,8 +826,6 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) u32 lnk_cap; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { err("%s: Cannot read LNKCAP register\n", __FUNCTION__); @@ -934,7 +843,7 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) *value = lnk_speed; dbg("Max link speed = %d\n", lnk_speed); - DBG_LEAVE_ROUTINE + return retval; } @@ -945,8 +854,6 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value u32 lnk_cap; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { err("%s: Cannot read LNKCAP register\n", __FUNCTION__); @@ -985,7 +892,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value *value = lnk_wdth; dbg("Max link width = %d\n", lnk_wdth); - DBG_LEAVE_ROUTINE + return retval; } @@ -996,8 +903,6 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) int retval = 0; u16 lnk_status; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); @@ -1015,7 +920,7 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) *value = lnk_speed; dbg("Current link speed = %d\n", lnk_speed); - DBG_LEAVE_ROUTINE + return retval; } @@ -1026,8 +931,6 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value int retval = 0; u16 lnk_status; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); @@ -1066,7 +969,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value *value = lnk_wdth; dbg("Current link width = %d\n", lnk_wdth); - DBG_LEAVE_ROUTINE + return retval; } @@ -1177,8 +1080,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) u16 slot_status, slot_ctrl; struct pci_dev *pdev; - DBG_ENTER_ROUTINE - pdev = dev->port; ctrl->pci_dev = pdev; /* save pci_dev in context */ @@ -1376,7 +1277,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ctrl->hpc_ops = &pciehp_hpc_ops; - DBG_LEAVE_ROUTINE return 0; /* We end up here for the many possible ways to fail this API. */ @@ -1396,6 +1296,5 @@ abort_free_irq: free_irq(ctrl->pci_dev->irq, ctrl); abort_free_ctlr: - DBG_LEAVE_ROUTINE return -1; } From 71ad556dadcd303b4d32e9b890dcf1ccfbe9aeb3 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:34 -0700 Subject: [PATCH 2767/2804] pciehp: remove trailing whitespace from pciehp_hpc.c Remove trailing whitespaces from pciehp_hpc.c. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index f6143175de71..2e501f73c3b6 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -129,10 +129,10 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) /* Link Width Encoding */ #define LNK_X1 0x01 #define LNK_X2 0x02 -#define LNK_X4 0x04 +#define LNK_X4 0x04 #define LNK_X8 0x08 #define LNK_X12 0x0C -#define LNK_X16 0x10 +#define LNK_X16 0x10 #define LNK_X32 0x20 /*Field definitions of Link Status Register */ @@ -262,7 +262,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) goto out; } - if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { + if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue the next command according to spec. Just print out the error message */ @@ -310,7 +310,7 @@ static int hpc_check_lnk_status(struct controller *ctrl) } dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status); - if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || + if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || !(lnk_status & NEG_LINK_WD)) { err("%s : Link Training Error occurs \n", __FUNCTION__); retval = -1; @@ -382,7 +382,7 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) *status = 1; break; case 1: - *status = 0; + *status = 0; break; default: *status = 0xFF; @@ -405,7 +405,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) return retval; } - *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; + *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; return 0; } @@ -441,7 +441,7 @@ static int hpc_query_power_fault(struct slot *slot) return retval; } pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); - + return pwr_fault; } @@ -509,7 +509,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - + return rc; } @@ -519,7 +519,7 @@ static void hpc_set_green_led_on(struct slot *slot) struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; - + slot_cmd = 0x0100; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -556,7 +556,7 @@ static void hpc_set_green_led_blink(struct slot *slot) struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; - + slot_cmd = 0x0200; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -736,7 +736,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) } dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", __FUNCTION__, slot_status); - + /* Clear command complete interrupt caused by this write */ temp_word = 0x1f; rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); @@ -746,10 +746,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_NONE; } } - + if (intr_loc & CMD_COMPLETED) { - /* - * Command Complete Interrupt Pending + /* + * Command Complete Interrupt Pending */ ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); @@ -803,7 +803,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) __FUNCTION__); return IRQ_NONE; } - + /* Clear command complete interrupt caused by this write */ temp_word = 0x1F; rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); @@ -815,7 +815,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n", __FUNCTION__, temp_word); } - + return IRQ_HANDLED; } @@ -936,7 +936,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } - + switch ((lnk_status & 0x03F0) >> 4){ case 0: lnk_wdth = PCIE_LNK_WIDTH_RESRV; @@ -988,12 +988,12 @@ static struct hpc_ops pciehp_hpc_ops = { .get_cur_bus_speed = hpc_get_cur_lnk_speed, .get_max_lnk_width = hpc_get_max_lnk_width, .get_cur_lnk_width = hpc_get_cur_lnk_width, - + .query_power_fault = hpc_query_power_fault, .green_led_on = hpc_set_green_led_on, .green_led_off = hpc_set_green_led_off, .green_led_blink = hpc_set_green_led_blink, - + .release_ctlr = hpc_release_ctlr, .check_lnk_status = hpc_check_lnk_status, }; @@ -1144,7 +1144,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) (unsigned long long)pci_resource_start(pdev, rc), (unsigned long long)pci_resource_len(pdev, rc)); - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); mutex_init(&ctrl->crit_sect); @@ -1232,14 +1232,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) if (ATTN_BUTTN(slot_cap)) intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - + if (POWER_CTRL(slot_cap)) intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - + if (MRL_SENS(slot_cap)) intr_enable = intr_enable | MRL_DETECT_ENABLE; - temp_word = (temp_word & ~intr_enable) | intr_enable; + temp_word = (temp_word & ~intr_enable) | intr_enable; if (pciehp_poll_mode) { temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; @@ -1258,14 +1258,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } - + temp_word = 0x1F; /* Clear all events */ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } - + if (pciehp_force) { dbg("Bypassing BIOS check for pciehp use on %s\n", pci_name(ctrl->pci_dev)); From a073a8267400be2bd8acf808a45bc3ab01cf1b20 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:35 -0700 Subject: [PATCH 2768/2804] pciehp: remove trailing whitespace from pciehp_core.c Remove trailing whitespaces from pciehp_core.c. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_core.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 3d692a971218..6462ac3b405f 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -304,8 +304,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); hotplug_slot->info->attention_status = status; - - if (ATTN_LED(slot->ctrl->ctrlcap)) + + if (ATTN_LED(slot->ctrl->ctrlcap)) slot->hpc_ops->set_attention_status(slot, status); return 0; @@ -405,7 +405,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - + retval = slot->hpc_ops->get_max_bus_speed(slot, value); if (retval < 0) *value = PCI_SPEED_UNKNOWN; @@ -419,7 +419,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - + retval = slot->hpc_ops->get_cur_bus_speed(slot, value); if (retval < 0) *value = PCI_SPEED_UNKNOWN; @@ -434,7 +434,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ struct slot *t_slot; u8 value; struct pci_dev *pdev; - + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { err("%s : out of memory\n", __FUNCTION__); @@ -502,23 +502,23 @@ static void pciehp_remove (struct pcie_device *dev) #ifdef CONFIG_PM static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) { - printk("%s ENTRY\n", __FUNCTION__); + printk("%s ENTRY\n", __FUNCTION__); return 0; } static int pciehp_resume (struct pcie_device *dev) { - printk("%s ENTRY\n", __FUNCTION__); + printk("%s ENTRY\n", __FUNCTION__); return 0; } #endif -static struct pcie_port_service_id port_pci_ids[] = { { - .vendor = PCI_ANY_ID, +static struct pcie_port_service_id port_pci_ids[] = { { + .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .port_type = PCIE_ANY_PORT, .service_type = PCIE_PORT_SERVICE_HP, - .driver_data = 0, + .driver_data = 0, }, { /* end: all zeroes */ } }; static const char device_name[] = "hpdriver"; From 36ed27b07b873db06c10d2f8f41aa17be6803fdd Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:36 -0700 Subject: [PATCH 2769/2804] pciehp: remove trailing whitespace from pciehp_ctrl.c Remove trailing whitespaces from pciehp_ctrl.c. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_ctrl.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 98e541ffef3d..c8cb49c5a752 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -173,7 +173,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) return 1; } -/* The following routines constitute the bulk of the +/* The following routines constitute the bulk of the hotplug controller logic */ @@ -181,7 +181,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl->ctrlcap)) { - if (pslot->hpc_ops->power_off_slot(pslot)) { + if (pslot->hpc_ops->power_off_slot(pslot)) { err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); return; @@ -189,7 +189,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) } if (PWR_LED(ctrl->ctrlcap)) - pslot->hpc_ops->green_led_off(pslot); + pslot->hpc_ops->green_led_off(pslot); if (ATTN_LED(ctrl->ctrlcap)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { @@ -231,7 +231,7 @@ static int board_added(struct slot *p_slot) if (retval) return retval; } - + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_blink(p_slot); @@ -548,7 +548,7 @@ int pciehp_enable_slot(struct slot *p_slot) mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%s)\n", __FUNCTION__, @@ -557,8 +557,8 @@ int pciehp_enable_slot(struct slot *p_slot) return -ENODEV; } } - - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + + if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%s)\n", __FUNCTION__, @@ -593,7 +593,7 @@ int pciehp_disable_slot(struct slot *p_slot) /* Check to see if (latch closed, card present, power on) */ mutex_lock(&p_slot->ctrl->crit_sect); - if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { + if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: no adapter on slot(%s)\n", __FUNCTION__, @@ -603,7 +603,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%s)\n", __FUNCTION__, @@ -613,7 +613,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%s)\n", __FUNCTION__, From 9fe8164536c4fa6e630c706c667a2c6e8456d143 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:37 -0700 Subject: [PATCH 2770/2804] pciehp: remove trailing whitespace form pciehp_pci.c Remove trailing whitespaces from pciehp_pci.c. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 8f2b25c49f84..c424aded13fb 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -280,12 +280,12 @@ int pciehp_unconfigure_device(struct slot *p_slot) pci_remove_bus_device(temp); pci_dev_put(temp); } - /* + /* * Some PCI Express root ports require fixup after hot-plug operation. */ - if (pcie_mch_quirk) + if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev); - + return rc; } From 40730d1042c595b1e84b28e40021f2c1377b4f8b Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:38 -0700 Subject: [PATCH 2771/2804] pciehp: minor cleanups for pciehp_hpc.c Minor cleanups for pciehp_hpc.c. The 80 column rules, removing unnecessary lines, and so on. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 47 ++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 2e501f73c3b6..06d025b8b13f 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -203,7 +203,7 @@ static void int_poll_timeout(unsigned long data) init_timer(&ctrl->poll_timer); if (!pciehp_poll_time) - pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ + pciehp_poll_time = 2; /* default polling interval is 2 sec */ start_int_poll_timer(ctrl, pciehp_poll_time); } @@ -320,7 +320,6 @@ static int hpc_check_lnk_status(struct controller *ctrl) return retval; } - static int hpc_get_attention_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; @@ -392,7 +391,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) return retval; } - static int hpc_get_latch_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; @@ -513,7 +511,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) return rc; } - static void hpc_set_green_led_on(struct slot *slot) { struct controller *ctrl = slot->ctrl; @@ -695,8 +692,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_NONE; } - intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED | - PRSN_DETECT_CHANGED | CMD_COMPLETED ); + intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | + MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED); intr_loc = slot_status & intr_detect; @@ -718,7 +715,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", __FUNCTION__, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + temp_word = (temp_word & ~HP_INTR_ENABLE & + ~CMD_CMPL_INTR_ENABLE) | 0x00; rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { err("%s: Cannot write to SLOTCTRL register\n", @@ -819,7 +817,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) +static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed; @@ -847,7 +845,8 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) return retval; } -static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value) +static int hpc_get_max_lnk_width(struct slot *slot, + enum pcie_link_width *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth; @@ -896,7 +895,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value return retval; } -static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) +static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; @@ -924,7 +923,8 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) return retval; } -static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value) +static int hpc_get_cur_lnk_width(struct slot *slot, + enum pcie_link_width *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; @@ -1067,8 +1067,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) } #endif - - int pcie_init(struct controller * ctrl, struct pcie_device *dev) { int rc; @@ -1103,9 +1101,11 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: CAPREG offset %x cap_reg %x\n", __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); - if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) + if (((cap_reg & SLOT_IMPL) == 0) || + (((cap_reg & DEV_PORT_TYPE) != 0x0040) && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { - dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__); + dbg("%s : This is not a root port or the port is not " + "connected to a slot\n", __FUNCTION__); goto abort_free_ctlr; } @@ -1138,14 +1138,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); - for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) + for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) if (pci_resource_len(pdev, rc) > 0) dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, (unsigned long long)pci_resource_start(pdev, rc), (unsigned long long)pci_resource_len(pdev, rc)); - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->ctrl_lock); @@ -1169,7 +1170,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: SLOTCTRL %x value read %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | + 0x00; rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { @@ -1247,7 +1249,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; } - /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ + /* + * Unmask Hot-plug Interrupt Enable for the interrupt + * notification mechanism case. + */ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); @@ -1279,7 +1284,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) return 0; - /* We end up here for the many possible ways to fail this API. */ + /* We end up here for the many possible ways to fail this API. */ abort_disable_intr: rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (!rc) { From 229f5afded86bf3819b7b67e57c62813ca0648a7 Mon Sep 17 00:00:00 2001 From: vignesh babu Date: Mon, 13 Aug 2007 18:23:14 +0530 Subject: [PATCH 2772/2804] PCI: is_power_of_2 in drivers/pci/pci.c Replacing n & (n - 1) for power of 2 check by is_power_of_2(n) Signed-off-by: vignesh babu Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 37c00f6fd801..19a64a36ecab 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* isa_dma_bridge_buggy */ #include "pci.h" @@ -1454,7 +1455,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) int cap, err = -EINVAL; u32 stat, cmd, v, o; - if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1))) + if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc)) goto out; v = ffs(mmrbc) - 10; @@ -1526,7 +1527,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) int cap, err = -EINVAL; u16 ctl, v; - if (rq < 128 || rq > 4096 || (rq & (rq-1))) + if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) goto out; v = (ffs(rq) - 8) << 12; From 2d100fe8f6ebe5e4335b26f3749bb0b7f706d1f9 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 14 Aug 2007 16:07:00 -0700 Subject: [PATCH 2773/2804] pci: hotplug: ibmphp: convert to kthread Convert ibmphp to new kthread api Signed-off-by: Kristen Carlson Accardi Cc: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/ibmphp_hpc.c | 57 +++++++------------------------- 1 file changed, 12 insertions(+), 45 deletions(-) diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index d06ccb69e411..c31e7bf34502 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -35,7 +35,7 @@ #include #include #include - +#include #include "ibmphp.h" static int to_debug = 0; @@ -101,12 +101,11 @@ static int to_debug = 0; //---------------------------------------------------------------------------- // global variables //---------------------------------------------------------------------------- -static int ibmphp_shutdown; -static int tid_poll; static struct mutex sem_hpcaccess; // lock access to HPC static struct semaphore semOperations; // lock all operations and // access to data structures static struct semaphore sem_exit; // make sure polling thread goes away +static struct task_struct *ibmphp_poll_thread; //---------------------------------------------------------------------------- // local function prototypes //---------------------------------------------------------------------------- @@ -116,10 +115,9 @@ static u8 hpc_writecmdtoindex (u8, u8); static u8 hpc_readcmdtoindex (u8, u8); static void get_hpc_access (void); static void free_hpc_access (void); -static void poll_hpc (void); +static int poll_hpc(void *data); static int process_changeinstatus (struct slot *, struct slot *); static int process_changeinlatch (u8, u8, struct controller *); -static int hpc_poll_thread (void *); static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *); //---------------------------------------------------------------------------- @@ -137,8 +135,6 @@ void __init ibmphp_hpc_initvars (void) init_MUTEX (&semOperations); init_MUTEX_LOCKED (&sem_exit); to_debug = 0; - ibmphp_shutdown = 0; - tid_poll = 0; debug ("%s - Exit\n", __FUNCTION__); } @@ -819,7 +815,7 @@ void ibmphp_unlock_operations (void) #define POLL_LATCH_REGISTER 0 #define POLL_SLOTS 1 #define POLL_SLEEP 2 -static void poll_hpc (void) +static int poll_hpc(void *data) { struct slot myslot; struct slot *pslot = NULL; @@ -833,10 +829,7 @@ static void poll_hpc (void) debug ("%s - Entry\n", __FUNCTION__); - while (!ibmphp_shutdown) { - if (ibmphp_shutdown) - break; - + while (!kthread_should_stop()) { /* try to get the lock to do some kind of hardware access */ down (&semOperations); @@ -896,7 +889,7 @@ static void poll_hpc (void) up (&semOperations); msleep(POLL_INTERVAL_SEC * 1000); - if (ibmphp_shutdown) + if (kthread_should_stop()) break; down (&semOperations); @@ -915,6 +908,7 @@ static void poll_hpc (void) } up (&sem_exit); debug ("%s - Exit\n", __FUNCTION__); + return 0; } @@ -1049,29 +1043,6 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) return rc; } -/*---------------------------------------------------------------------- -* Name: hpc_poll_thread -* -* Action: polling -* -* Return 0 -* Value: -*---------------------------------------------------------------------*/ -static int hpc_poll_thread (void *data) -{ - debug ("%s - Entry\n", __FUNCTION__); - - daemonize("hpc_poll"); - allow_signal(SIGKILL); - - poll_hpc (); - - tid_poll = 0; - debug ("%s - Exit\n", __FUNCTION__); - return 0; -} - - /*---------------------------------------------------------------------- * Name: ibmphp_hpc_start_poll_thread * @@ -1079,18 +1050,14 @@ static int hpc_poll_thread (void *data) *---------------------------------------------------------------------*/ int __init ibmphp_hpc_start_poll_thread (void) { - int rc = 0; - debug ("%s - Entry\n", __FUNCTION__); - tid_poll = kernel_thread (hpc_poll_thread, NULL, 0); - if (tid_poll < 0) { + ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll"); + if (IS_ERR(ibmphp_poll_thread)) { err ("%s - Error, thread not started\n", __FUNCTION__); - rc = -1; + return PTR_ERR(ibmphp_poll_thread); } - - debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc); - return rc; + return 0; } /*---------------------------------------------------------------------- @@ -1102,7 +1069,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void) { debug ("%s - Entry\n", __FUNCTION__); - ibmphp_shutdown = 1; + kthread_stop(ibmphp_poll_thread); debug ("before locking operations \n"); ibmphp_lock_operations (); debug ("after locking operations \n"); From fa007d8bebc5d812a445c48664b5bcad81f1351c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 14 Aug 2007 16:17:15 -0700 Subject: [PATCH 2774/2804] pci: hotplug: cpqphp: convert to kthread infrastructure Signed-off-by: Christoph Hellwig Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpqphp_ctrl.c | 69 ++++++++++--------------------- 1 file changed, 21 insertions(+), 48 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index dcafa2aaef8a..3ef0a4875a62 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "cpqphp.h" static u32 configure_new_device(struct controller* ctrl, struct pci_func *func, @@ -45,34 +46,20 @@ static int configure_new_function(struct controller* ctrl, struct pci_func *func u8 behind_bridge, struct resource_lists *resources); static void interrupt_event_handler(struct controller *ctrl); -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ -static int event_finished; -static unsigned long pushbutton_pending; /* = 0 */ -/* things needed for the long_delay function */ -static struct semaphore delay_sem; -static wait_queue_head_t delay_wait; +static struct task_struct *cpqhp_event_thread; +static unsigned long pushbutton_pending; /* = 0 */ /* delay is in jiffies to wait for */ static void long_delay(int delay) { - DECLARE_WAITQUEUE(wait, current); - - /* only allow 1 customer into the delay queue at once - * yes this makes some people wait even longer, but who really cares? - * this is for _huge_ delays to make the hardware happy as the - * signals bounce around + /* + * XXX(hch): if someone is bored please convert all callers + * to call msleep_interruptible directly. They really want + * to specify timeouts in natural units and spend a lot of + * effort converting them to jiffies.. */ - down (&delay_sem); - - init_waitqueue_head(&delay_wait); - - add_wait_queue(&delay_wait, &wait); msleep_interruptible(jiffies_to_msecs(delay)); - remove_wait_queue(&delay_wait, &wait); - - up(&delay_sem); } @@ -955,8 +942,8 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data) } if (schedule_flag) { - up(&event_semaphore); - dbg("Signal event_semaphore\n"); + wake_up_process(cpqhp_event_thread); + dbg("Waking even thread"); } return IRQ_HANDLED; } @@ -1735,7 +1722,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control static void pushbutton_helper_thread(unsigned long data) { pushbutton_pending = data; - up(&event_semaphore); + wake_up_process(cpqhp_event_thread); } @@ -1744,13 +1731,13 @@ static int event_thread(void* data) { struct controller *ctrl; - daemonize("phpd_event"); - while (1) { dbg("!!!!event_thread sleeping\n"); - down_interruptible (&event_semaphore); - dbg("event_thread woken finished = %d\n", event_finished); - if (event_finished) break; + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + + if (kthread_should_stop()) + break; /* Do stuff here */ if (pushbutton_pending) cpqhp_pushbutton_thread(pushbutton_pending); @@ -1759,38 +1746,24 @@ static int event_thread(void* data) interrupt_event_handler(ctrl); } dbg("event_thread signals exit\n"); - up(&event_exit); return 0; } - int cpqhp_event_start_thread(void) { - int pid; - - /* initialize our semaphores */ - init_MUTEX(&delay_sem); - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&event_exit); - event_finished=0; - - pid = kernel_thread(event_thread, NULL, 0); - if (pid < 0) { + cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event"); + if (IS_ERR(cpqhp_event_thread)) { err ("Can't start up our event thread\n"); - return -1; + return PTR_ERR(cpqhp_event_thread); } - dbg("Our event thread pid = %d\n", pid); + return 0; } void cpqhp_event_stop_thread(void) { - event_finished = 1; - dbg("event_thread finish command given\n"); - up(&event_semaphore); - dbg("wait for event_thread to exit\n"); - down(&event_exit); + kthread_stop(cpqhp_event_thread); } From aa24886e379d2b641c5117e178b15ce1d5d366ba Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 10 Aug 2007 13:10:27 -0700 Subject: [PATCH 2775/2804] dma_free_coherent() needs irqs enabled (sigh) On at least ARM (and I'm told MIPS too) dma_free_coherent() has a newish call context requirement: unlike its dma_alloc_coherent() sibling, it may not be called with IRQs disabled. (This was new behavior on ARM as of late 2005, caused by ARM SMP updates.) This little surprise can be annoyingly driver-visible. Since it looks like that restriction won't be removed, this patch changes the definition of the API to include that requirement. Also, to help catch nonportable drivers, it updates the x86 and swiotlb versions to include the relevant warnings. (I already observed that it trips on the bus_reset_tasklet of the new firewire_ohci driver.) Signed-off-by: David Brownell Cc: David Miller Acked-by: Russell King Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- Documentation/DMA-API.txt | 3 +++ arch/x86/kernel/pci-dma_32.c | 3 ++- arch/x86/kernel/pci-dma_64.c | 1 + lib/swiotlb.c | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index cc7a8c39fb6f..b939ebb62871 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -68,6 +68,9 @@ size and dma_handle must all be the same as those passed into the consistent allocate. cpu_addr must be the virtual address returned by the consistent allocate. +Note that unlike their sibling allocation calls, these routines +may only be called with IRQs enabled. + Part Ib - Using small dma-coherent buffers ------------------------------------------ diff --git a/arch/x86/kernel/pci-dma_32.c b/arch/x86/kernel/pci-dma_32.c index 048f09b62553..0aae2f3847a5 100644 --- a/arch/x86/kernel/pci-dma_32.c +++ b/arch/x86/kernel/pci-dma_32.c @@ -63,7 +63,8 @@ void dma_free_coherent(struct device *dev, size_t size, { struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; int order = get_order(size); - + + WARN_ON(irqs_disabled()); /* for portability */ if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; diff --git a/arch/x86/kernel/pci-dma_64.c b/arch/x86/kernel/pci-dma_64.c index 29711445c818..9576a2eb375e 100644 --- a/arch/x86/kernel/pci-dma_64.c +++ b/arch/x86/kernel/pci-dma_64.c @@ -167,6 +167,7 @@ EXPORT_SYMBOL(dma_alloc_coherent); void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t bus) { + WARN_ON(irqs_disabled()); /* for portability */ if (dma_ops->unmap_single) dma_ops->unmap_single(dev, bus, size, 0); free_pages((unsigned long)vaddr, get_order(size)); diff --git a/lib/swiotlb.c b/lib/swiotlb.c index a7381d55663a..30c1400e749e 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -497,6 +497,7 @@ void swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { + WARN_ON(irqs_disabled()); if (!(vaddr >= (void *)io_tlb_start && vaddr < (void *)io_tlb_end)) free_pages((unsigned long) vaddr, get_order(size)); From 3d034aecd8b70d34388a4e40ca50af0d014223e1 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 7 Aug 2007 13:13:18 +0400 Subject: [PATCH 2776/2804] PCI: pci_get_device call from interrupt in reboot fixups The following calltrace is possible now: handle_sysrq machine_emergency_restart mach_reboot_fixups pci_get_device pci_get_subsys down_read The patch skips reboot fixup if called from sysrq-B code. Signed-off-by: Denis V. Lunev Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/reboot_fixups_32.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kernel/reboot_fixups_32.c b/arch/x86/kernel/reboot_fixups_32.c index 03e1cce58f49..139eb03490f5 100644 --- a/arch/x86/kernel/reboot_fixups_32.c +++ b/arch/x86/kernel/reboot_fixups_32.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -56,6 +57,11 @@ void mach_reboot_fixups(void) struct pci_dev *dev; int i; + /* we can be called from sysrq-B code. In such a case it is + * prohibited to dig PCI */ + if (in_interrupt()) + return; + for (i=0; i < ARRAY_SIZE(fixups_table); i++) { cur = &(fixups_table[i]); dev = pci_get_device(cur->vendor, cur->device, NULL); From b205f6b2679c7fcf761ed726de8093ca69b6c26e Mon Sep 17 00:00:00 2001 From: Thomas Backlund Date: Fri, 10 Aug 2007 14:42:15 -0700 Subject: [PATCH 2777/2804] i386: add support for picopower irq router MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for PicoPower PT86C523 IRQ router to be used with the in-kernel yenta driver for CardBus. With this patch cardbus works on e.g. Dell Latitude XPi P150CD. Initial patch for kernel 2.4 series by Sune Mรธlgaard http://molgaard.org/code/linux-2.4.31-picopower.patch Ported to 2.6.20 by Chmouel Boudjnah (http://www.chmouel.com) Testing and confirmation that it works by Austin Acton Cleaned up a little for inclusion in a 2.6.21-rc7 based kernel. Added some more cleanups according to CodingStyle, as noted by Randy Dunlap on LKML. [akpm@linux-foundation.org: build fixes] Signed-off-by: Thomas Backlund Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/irq.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 3 +++ 2 files changed, 42 insertions(+) diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index d98c6b096f8e..c52150fdf82b 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -492,6 +492,26 @@ static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq return 1; } +/* + * PicoPower PT86C523 + */ +static int pirq_pico_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + outb(0x10 + ((pirq - 1) >> 1), 0x24); + return ((pirq - 1) & 1) ? (inb(0x26) >> 4) : (inb(0x26) & 0xf); +} + +static int pirq_pico_set(struct pci_dev *router, struct pci_dev *dev, int pirq, + int irq) +{ + unsigned int x; + outb(0x10 + ((pirq - 1) >> 1), 0x24); + x = inb(0x26); + x = ((pirq - 1) & 1) ? ((x & 0x0f) | (irq << 4)) : ((x & 0xf0) | (irq)); + outb(x, 0x26); + return 1; +} + #ifdef CONFIG_PCI_BIOS static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) @@ -721,6 +741,24 @@ static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, return 1; } +static __init int pico_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch (device) { + case PCI_DEVICE_ID_PICOPOWER_PT86C523: + r->name = "PicoPower PT86C523"; + r->get = pirq_pico_get; + r->set = pirq_pico_set; + return 1; + + case PCI_DEVICE_ID_PICOPOWER_PT86C523BBP: + r->name = "PicoPower PT86C523 rev. BB+"; + r->get = pirq_pico_get; + r->set = pirq_pico_set; + return 1; + } + return 0; +} + static __initdata struct irq_router_handler pirq_routers[] = { { PCI_VENDOR_ID_INTEL, intel_router_probe }, { PCI_VENDOR_ID_AL, ali_router_probe }, @@ -732,6 +770,7 @@ static __initdata struct irq_router_handler pirq_routers[] = { { PCI_VENDOR_ID_VLSI, vlsi_router_probe }, { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe }, { PCI_VENDOR_ID_AMD, amd_router_probe }, + { PCI_VENDOR_ID_PICOPOWER, pico_router_probe }, /* Someone with docs needs to add the ATI Radeon IGP */ { 0, NULL } }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3948708c42ca..c88234d46506 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -829,6 +829,9 @@ #define PCI_DEVICE_ID_UMC_UM8886BF 0x673a #define PCI_DEVICE_ID_UMC_UM8886A 0x886a +#define PCI_VENDOR_ID_PICOPOWER 0x1066 +#define PCI_DEVICE_ID_PICOPOWER_PT86C523 0x0002 +#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP 0x8002 #define PCI_VENDOR_ID_MYLEX 0x1069 #define PCI_DEVICE_ID_MYLEX_DAC960_P 0x0001 From 9f672153ba921fdc6d4ef5ca8f6e65ac58cc970c Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 21 Aug 2007 17:49:07 -0600 Subject: [PATCH 2778/2804] PCI: Add missing PCI capability IDs These IDs are in pciutils, but haven't been added to the kernel yet. Signed-off-by: Alex Chiang Signed-off-by: Matthew Wilcox Signed-off-by: Greg Kroah-Hartman --- include/linux/pci_regs.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 423d592c55d5..4a24ee368a11 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -202,8 +202,12 @@ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ #define PCI_CAP_ID_HT 0x08 /* HyperTransport */ -#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ +#define PCI_CAP_ID_DBG 0x0A /* Debug port */ +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ +#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ From 3799a4e7d8867cfbb137d417beb126d5a2302607 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:17:38 -0700 Subject: [PATCH 2779/2804] cpqphp: Use PCI_CLASS_REVISION instead of PCI_REVISION_ID for read While PCI_CLASS_REVISION and PCI_REVISION_ID are identical, the code here discards the revision content and is only interested in the class number. Signed-off-by: Auke Kok Cc: Krosten Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpqphp_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 2305cc450a45..a96b739b2d35 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -549,7 +549,7 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) * slot. */ bus->number = tbus; pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), - PCI_REVISION_ID, &work); + PCI_CLASS_REVISION, &work); if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_dword(bus, From aa288d4d6bc7d150bab3a5be954979a09633ccdd Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:17:47 -0700 Subject: [PATCH 2780/2804] PCI: quirk amd_8131_mmrbc: Omit reading pci revision ID Signed-off-by: Auke Kok Cc: Peter Oruba Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 50f2dd9e1bb2..70f196f77c17 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -629,12 +629,9 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk */ static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev) { - unsigned char revid; - - pci_read_config_byte(dev, PCI_REVISION_ID, &revid); - if (dev->subordinate && revid <= 0x12) { + if (dev->subordinate && dev->revision <= 0x12) { printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X " - "MMRBC\n", revid); + "MMRBC\n", dev->revision); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC; } } From 651472fbff71df39d3d734de31bca6e5412a688b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:18:10 -0700 Subject: [PATCH 2781/2804] PCI: quirk_vt82c586_acpi: Omit reading PCI revision ID Signed-off-by: Auke Kok Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 70f196f77c17..3b0bb3268bbd 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -472,11 +472,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ */ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) { - u8 rev; u32 region; - pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); - if (rev & 0x10) { + if (dev->revision & 0x10) { pci_read_config_dword(dev, 0x48, ®ion); region &= PCI_BASE_ADDRESS_IO_MASK; quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI"); From 346ca04d050ac48ceb8e4a6b1c76c2d7fd5d1a6a Mon Sep 17 00:00:00 2001 From: Johannes Goecke Date: Mon, 10 Sep 2007 10:46:52 +0200 Subject: [PATCH 2782/2804] PCI: re-enable onboard sound on "MSI K8T Neo2-FIR" On the "MSI K8T Neo2-FIR" board the BIOS disables the onboard soundcard, if a second PCI soundcard is present. This patch sets the korrect register bit to enable the onboard sound. Removed old code in /drivers/pci/quirks.c that only checks for the PCI-ID and fires on any Board with VIA 8237. New code in /arch/i386/pci/fixup.c checks the DMI-tables and only runs on the specific board. Signed-off-by: Johannes Goecke Acked-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/fixup.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/quirks.c | 32 ------------------------------ 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index c82cbf4c7226..6cff66dd0c91 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -353,6 +353,53 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); + +static struct dmi_system_id __devinitdata msi_k8t_dmi_table[] = { + { + .ident = "MSI-K8T-Neo2Fir", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MSI"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-6702E"), + }, + }, + {} +}; + +/* + * The AMD-Athlon64 board MSI "K8T Neo2-FIR" disables the onboard sound + * card if a PCI-soundcard is added. + * + * The BIOS only gives options "DISABLED" and "AUTO". This code sets + * the corresponding register-value to enable the soundcard. + * + * The soundcard is only enabled, if the mainborad is identified + * via DMI-tables and the soundcard is detected to be off. + */ +static void __devinit pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev) +{ + unsigned char val; + if (!dmi_check_system(msi_k8t_dmi_table)) + return; /* only applies to MSI K8T Neo2-FIR */ + + pci_read_config_byte(dev, 0x50, &val); + if (val & 0x40) { + pci_write_config_byte(dev, 0x50, val & (~0x40)); + + /* verify the change for status output */ + pci_read_config_byte(dev, 0x50, &val); + if (val & 0x40) + printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, " + "can't enable onboard soundcard!\n"); + else + printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, " + "enabled onboard soundcard.\n"); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, + pci_fixup_msi_k8t_onboard_sound); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, + pci_fixup_msi_k8t_onboard_sound); + /* * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. * diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 3b0bb3268bbd..59d4da2734c1 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -925,38 +925,6 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge ); -/* - * On the MSI-K8T-Neo2Fir Board, the internal Soundcard is disabled - * when a PCI-Soundcard is added. The BIOS only gives Options - * "Disabled" and "AUTO". This Quirk Sets the corresponding - * Register-Value to enable the Soundcard. - * - * FIXME: Presently this quirk will run on anything that has an 8237 - * which isn't correct, we need to check DMI tables or something in - * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it - * runs everywhere at present we suppress the printk output in most - * irrelevant cases. - */ -static void k8t_sound_hostbridge(struct pci_dev *dev) -{ - unsigned char val; - - pci_read_config_byte(dev, 0x50, &val); - if (val == 0xc8) { - /* Assume it's probably a MSI-K8T-Neo2Fir */ - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n"); - pci_write_config_byte(dev, 0x50, val & (~0x40)); - - /* Verify the Change for Status output */ - pci_read_config_byte(dev, 0x50, &val); - if (val & 0x40) - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n"); - else - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n"); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); /* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge From 4904e23b6b37c748a35bb2bd14ea325d0592e671 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 20 Sep 2007 12:48:23 +1000 Subject: [PATCH 2783/2804] PCI: Remove no longer correct documentation regarding MSI vector assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MSI vector reservation system described in Documentation/MSI-HOWTO.txt was removed by Eric in 92db6d10bc1bc43330a4c540fa5b64c83d9d865f. Remove the references to it in the documentation. While we're here ยง 5.5.1 refers to x86 hardware requirements, so make that clear. Signed-off-by: Michael Ellerman Cc: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman --- Documentation/MSI-HOWTO.txt | 69 +++---------------------------------- 1 file changed, 4 insertions(+), 65 deletions(-) diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt index 0d8240774fca..a51f693c1541 100644 --- a/Documentation/MSI-HOWTO.txt +++ b/Documentation/MSI-HOWTO.txt @@ -241,68 +241,7 @@ address space of the MSI-X table/MSI-X PBA. Otherwise, the PCI subsystem will fail enabling MSI-X on its hardware device when it calls the function pci_enable_msix(). -5.3.2 Handling MSI-X allocation - -Determining the number of MSI-X vectors allocated to a function is -dependent on the number of MSI capable devices and MSI-X capable -devices populated in the system. The policy of allocating MSI-X -vectors to a function is defined as the following: - -#of MSI-X vectors allocated to a function = (x - y)/z where - -x = The number of available PCI vector resources by the time - the device driver calls pci_enable_msix(). The PCI vector - resources is the sum of the number of unassigned vectors - (new) and the number of released vectors when any MSI/MSI-X - device driver switches its hardware device back to a legacy - mode or is hot-removed. The number of unassigned vectors - may exclude some vectors reserved, as defined in parameter - NR_HP_RESERVED_VECTORS, for the case where the system is - capable of supporting hot-add/hot-remove operations. Users - may change the value defined in NR_HR_RESERVED_VECTORS to - meet their specific needs. - -y = The number of MSI capable devices populated in the system. - This policy ensures that each MSI capable device has its - vector reserved to avoid the case where some MSI-X capable - drivers may attempt to claim all available vector resources. - -z = The number of MSI-X capable devices populated in the system. - This policy ensures that maximum (x - y) is distributed - evenly among MSI-X capable devices. - -Note that the PCI subsystem scans y and z during a bus enumeration. -When the PCI subsystem completes configuring MSI/MSI-X capability -structure of a device as requested by its device driver, y/z is -decremented accordingly. - -5.3.3 Handling MSI-X shortages - -For the case where fewer MSI-X vectors are allocated to a function -than requested, the function pci_enable_msix() will return the -maximum number of MSI-X vectors available to the caller. A device -driver may re-send its request with fewer or equal vectors indicated -in the return. For example, if a device driver requests 5 vectors, but -the number of available vectors is 3 vectors, a value of 3 will be -returned as a result of pci_enable_msix() call. A function could be -designed for its driver to use only 3 MSI-X table entries as -different combinations as ABC--, A-B-C, A--CB, etc. Note that this -patch does not support multiple entries with the same vector. Such -attempt by a device driver to use 5 MSI-X table entries with 3 vectors -as ABBCC, AABCC, BCCBA, etc will result as a failure by the function -pci_enable_msix(). Below are the reasons why supporting multiple -entries with the same vector is an undesirable solution. - - - The PCI subsystem cannot determine the entry that - generated the message to mask/unmask MSI while handling - software driver ISR. Attempting to walk through all MSI-X - table entries (2048 max) to mask/unmask any match vector - is an undesirable solution. - - - Walking through all MSI-X table entries (2048 max) to handle - SMP affinity of any match vector is an undesirable solution. - -5.3.4 API pci_enable_msix +5.3.2 API pci_enable_msix int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) @@ -339,7 +278,7 @@ a failure. This failure may be a result of duplicate entries specified in second argument, or a result of no available vector, or a result of failing to initialize MSI-X table entries. -5.3.5 API pci_disable_msix +5.3.3 API pci_disable_msix void pci_disable_msix(struct pci_dev *dev) @@ -349,7 +288,7 @@ always call free_irq() on all MSI-X vectors it has done request_irq() on before calling this API. Failure to do so results in a BUG_ON() and a device will be left with MSI-X enabled and leaks its vectors. -5.3.6 MSI-X mode vs. legacy mode diagram +5.3.4 MSI-X mode vs. legacy mode diagram The below diagram shows the events which switch the interrupt mode on the MSI-X capable device function between MSI-X mode and @@ -407,7 +346,7 @@ between MSI mod MSI-X mode during a run-time. MSI/MSI-X support requires support from both system hardware and individual hardware device functions. -5.5.1 System hardware support +5.5.1 Required x86 hardware support Since the target of MSI address is the local APIC CPU, enabling MSI/MSI-X support in the Linux kernel is dependent on whether existing From 5b1ea82fa245d4be6409cdba7e522ecb0b966b3c Mon Sep 17 00:00:00 2001 From: Juha Laiho Date: Thu, 13 Sep 2007 21:21:34 +0300 Subject: [PATCH 2784/2804] PCI: i386: Compaq EVO N800c needs PCI bus renumbering Force PCI bus renumbering for Compaq EVO N800c laptop, in order to get the cardbus slot recognised. Signed-off-by: Juha Laiho Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/common.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 07d5223442bf..7c4d75e3c5f3 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -287,6 +287,16 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), }, }, +#ifdef __i386__ + { + .callback = assign_all_busses, + .ident = "Compaq EVO N800c", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME, "EVO N800c"), + }, + }, +#endif {} }; From a56bc69a182f501582557af7fad5bc882b1c856c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 14 Sep 2007 15:33:13 +1000 Subject: [PATCH 2785/2804] PCI: Fix incorrect argument order to list_add_tail() in PCI dynamic ID code The code for dynamically assigning new ids to PCI drivers, store_new_id(), calls list_add_tail() with the list head and new node arguments in reversed order. The result is that every new id written essentially overwrites the previous list of ids. Caught with the help of Rusty's "horribly bad" list_node patch: http://lkml.org/lkml/2007/6/10/10 Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 004bc2487270..c43ecedce673 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -54,7 +54,6 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) if (!dynid) return -ENOMEM; - INIT_LIST_HEAD(&dynid->node); dynid->id.vendor = vendor; dynid->id.device = device; dynid->id.subvendor = subvendor; @@ -65,7 +64,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) driver_data : 0UL; spin_lock(&pdrv->dynids.lock); - list_add_tail(&pdrv->dynids.list, &dynid->node); + list_add_tail(&dynid->node, &pdrv->dynids.list); spin_unlock(&pdrv->dynids.lock); if (get_driver(&pdrv->driver)) { From cbf5d9e6b9bcf03291cbb51db144b3e2773a8a2d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 3 Oct 2007 11:15:11 -0700 Subject: [PATCH 2786/2804] MSI: Use correct data offset for 32-bit MSI in read_msi_msg() While reading the MSI code trying to find a reason why MSI wouldn't work for devices that have a 32-bit MSI address capability, I noticed that read_msi_msg() seems to read the message data from the wrong offset in this case. Signed-off-by: Roland Dreier Acked-by: Eric W. Biederman Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index be1df85e5e2d..87e01615053d 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -132,7 +132,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) pci_read_config_word(dev, msi_data_reg(pos, 1), &data); } else { msg->address_hi = 0; - pci_read_config_word(dev, msi_data_reg(pos, 1), &data); + pci_read_config_word(dev, msi_data_reg(pos, 0), &data); } msg->data = data; break; From fd6e732186ab522c812ab19c2c5e5befb8ec8115 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 2 Oct 2007 14:19:23 -0700 Subject: [PATCH 2787/2804] PCI: fix IDE legacy mode resources I got the following error on MIPS Cobalt. PCI: Unable to reserve I/O region #1:8@f00001f0 for device 0000:00:09.1 pata_via 0000:00:09.1: failed to request/iomap BARs for port 0 (errno=-16) PCI: Unable to reserve I/O region #3:8@f0000170 for device 0000:00:09.1 pata_via 0000:00:09.1: failed to request/iomap BARs for port 1 (errno=-16) pata_via 0000:00:09.1: no available native port The legacy mode IDE resources set the following order. pci_setup_device() Legacy mode ATA controllers have fixed addresses. IDE resources: 0x1F0-0x1F7, 0x3F6, 0x170-0x177, 0x376 | V pcibios_fixup_bus() MIPS Cobalt PCI bus regions have the -0x10000000 offset from PCI resources. pcibios_fixup_bus() fix PCI bus regions. 0x1F0 - 0x10000000 = 0xF00001F0 | V ata_pci_init_one() PCI: Unable to reserve I/O region #1:8@f00001f0 for device 0000:00:09.1 In some architectures, PCI bus regions have the offset from PCI resources. For this reason, pci_setup_device() should set PCI bus regions to dev->resource[]. [akpm@linux-foundation.org: use struct initialiser] Signed-off-by: Yoichi Yuasa Cc: Alan Cox Cc: Greg KH Cc: Bartlomiej Zolnierkiewicz Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 48 +++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 171ca712e523..40e571d3c392 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -744,22 +744,46 @@ static int pci_setup_device(struct pci_dev * dev) */ if (class == PCI_CLASS_STORAGE_IDE) { u8 progif; + struct pci_bus_region region; + pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); if ((progif & 1) == 0) { - dev->resource[0].start = 0x1F0; - dev->resource[0].end = 0x1F7; - dev->resource[0].flags = LEGACY_IO_RESOURCE; - dev->resource[1].start = 0x3F6; - dev->resource[1].end = 0x3F6; - dev->resource[1].flags = LEGACY_IO_RESOURCE; + struct resource resource = { + .start = 0x1F0, + .end = 0x1F7, + .flags = LEGACY_IO_RESOURCE, + }; + + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[0].start = region.start; + dev->resource[0].end = region.end; + dev->resource[0].flags = resource.flags; + resource.start = 0x3F6; + resource.end = 0x3F6; + resource.flags = LEGACY_IO_RESOURCE; + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[1].start = region.start; + dev->resource[1].end = region.end; + dev->resource[1].flags = resource.flags; } if ((progif & 4) == 0) { - dev->resource[2].start = 0x170; - dev->resource[2].end = 0x177; - dev->resource[2].flags = LEGACY_IO_RESOURCE; - dev->resource[3].start = 0x376; - dev->resource[3].end = 0x376; - dev->resource[3].flags = LEGACY_IO_RESOURCE; + struct resource resource = { + .start = 0x170, + .end = 0x177, + .flags = LEGACY_IO_RESOURCE, + }; + + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[2].start = region.start; + dev->resource[2].end = region.end; + dev->resource[2].flags = resource.flags; + resource.start = 0x376; + resource.end = 0x376; + resource.flags = LEGACY_IO_RESOURCE; + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[3].start = region.start; + dev->resource[3].end = region.end; + dev->resource[3].flags = resource.flags; } } break; From 7f785763660e75c9eddaddea3d618696af4ae3a2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 5 Oct 2007 13:17:58 -0700 Subject: [PATCH 2788/2804] pci: implement "pci=noaer" For cases in which CONFIG_PCIEAER=y (such as distro kernels), allow users to disable PCIE Advanced Error Reporting by using "pci=noaer" on the kernel command line. This can be used to work around hardware or (kernel) software problems. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 4 ++++ drivers/pci/pci.c | 2 ++ drivers/pci/pci.h | 6 ++++++ drivers/pci/pcie/aer/aerdrv.c | 9 +++++++++ 4 files changed, 21 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a57c1f216b21..3f0173f45019 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -68,6 +68,7 @@ parameter is applicable: PARIDE The ParIDE (parallel port IDE) subsystem is enabled. PARISC The PA-RISC architecture is enabled. PCI PCI bus support is enabled. + PCIE PCI Express support is enabled. PCMCIA The PCMCIA subsystem is enabled. PNP Plug & Play support is enabled. PPC PowerPC architecture is enabled. @@ -1270,6 +1271,9 @@ and is between 256 and 4096 characters. It is defined in the file Mechanism 1. conf2 [X86-32] Force use of PCI Configuration Mechanism 2. + noaer [PCIE] If the PCIEAER kernel config parameter is + enabled, this kernel boot option can be used to + disable the use of PCIE advanced error reporting. nommconf [X86-32,X86_64] Disable use of MMCONFIG for PCI Configuration nomsi [MSI] If the PCI_MSI kernel config parameter is diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 19a64a36ecab..2dd5c282fabe 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1586,6 +1586,8 @@ static int __devinit pci_setup(char *str) if (*str && (str = pcibios_setup(str)) && *str) { if (!strcmp(str, "nomsi")) { pci_no_msi(); + } else if (!strcmp(str, "noaer")) { + pci_no_aer(); } else if (!strncmp(str, "cbiosize=", 9)) { pci_cardbus_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "cbmemsize=", 10)) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4c36e80f6d26..5360d73d4941 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -52,6 +52,12 @@ void pci_restore_msi_state(struct pci_dev *dev); static inline void pci_restore_msi_state(struct pci_dev *dev) {} #endif +#ifdef CONFIG_PCIEAER +void pci_no_aer(void); +#else +static inline void pci_no_aer(void) { } +#endif + static inline int pci_no_d1d2(struct pci_dev *dev) { unsigned int parent_dstates = 0; diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index ad90a01b0dfc..7a62f7dd9009 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -81,6 +81,13 @@ static struct pcie_port_service_driver aerdriver = { .reset_link = aer_root_reset, }; +static int pcie_aer_disable; + +void pci_no_aer(void) +{ + pcie_aer_disable = 1; /* has priority over 'forceload' */ +} + /** * aer_irq - Root Port's ISR * @irq: IRQ assigned to Root Port @@ -327,6 +334,8 @@ static void aer_error_resume(struct pci_dev *dev) **/ static int __init aer_service_init(void) { + if (pcie_aer_disable) + return -ENXIO; return pcie_port_service_register(&aerdriver); } From cd68602f36ceb65b24a9abcae10ca04a933c07fd Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 27 Sep 2007 13:41:16 -0700 Subject: [PATCH 2789/2804] pci: use size stored in proc_dir_entry for proc bus files On pci_proc_attach_device(), the size of the PCI configuration space is stored in the proc_dir_entry as the size of the file. Thus, the procfs interface to PCI devices should use it instead of the device directly. Signed-off-by: David Rientjes Signed-off-by: Greg Kroah-Hartman --- drivers/pci/proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 90adc62d07ff..73714db6995e 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -60,7 +60,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp */ if (capable(CAP_SYS_ADMIN)) - size = dev->cfg_size; + size = dp->size; else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) size = 128; else @@ -133,7 +133,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof const struct proc_dir_entry *dp = PDE(ino); struct pci_dev *dev = dp->data; int pos = *ppos; - int size = dev->cfg_size; + int size = dp->size; int cnt; if (pos >= size) From ecb3908046ce9ce7feb44e2c2cf77ccdbe231f70 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 27 Sep 2007 13:41:17 -0700 Subject: [PATCH 2790/2804] pci: write file size to inode on proc bus file write When a /proc/bus/pci file is written to, the size of that PCI device's configuration space must be written to the inode. Otherwise, it is possible for the file to specify a size of 0 on stat if a task is holding the same file open. Signed-off-by: David Rientjes Signed-off-by: Greg Kroah-Hartman --- drivers/pci/proc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 73714db6995e..716439e25dd2 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -129,7 +129,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) { - const struct inode *ino = file->f_path.dentry->d_inode; + struct inode *ino = file->f_path.dentry->d_inode; const struct proc_dir_entry *dp = PDE(ino); struct pci_dev *dev = dp->data; int pos = *ppos; @@ -193,6 +193,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof } *ppos = pos; + i_size_write(ino, dp->size); return nbytes; } From 8fa5913d54f3b1e09948e6a0db34da887e05ff1f Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Wed, 3 Oct 2007 15:55:51 -0700 Subject: [PATCH 2791/2804] PCI: remove transparent bridge sizing Remove transparent bridge sizing. Due to code in pci_read_bridge_bases() [drivers/pci/probe.c] the child bus of a transparent bridge already has access to the parent bus resources so transparent bridge sizing appears unnecessary. The bridge sizing includes alignment and granularity adjustments that can cause significantly more memory to be reserved from the parant bus than required by devices on the child bus and allotted by _CRS. Signed-off-by: Gary Hade Signed-off-by: Greg Kroah-Hartman --- drivers/pci/setup-bus.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 5e5191ec8de6..401e03c920bd 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -472,7 +472,12 @@ void pci_bus_size_bridges(struct pci_bus *bus) break; case PCI_CLASS_BRIDGE_PCI: + /* don't size subtractive decoding (transparent) + * PCI-to-PCI bridges */ + if (bus->self->transparent) + break; pci_bridge_check_ranges(bus); + /* fall through */ default: pbus_size_io(bus); /* If the bridge supports prefetchable range, size it From 036fff4cf732c4d69f99a2915924935705744b00 Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Wed, 3 Oct 2007 15:56:14 -0700 Subject: [PATCH 2792/2804] PCI: skip ISA ioresource alignment on some systems Skip ISA ioresource alignment on some systems To conserve limited PCI i/o resource on some IBM multi-node systems, the BIOS allocates (via _CRS) and expects the kernel to use addresses in ranges currently excluded by pcibios_align_resource() [i386/pci/i386.c]. This change allows the kernel to use the currently excluded address ranges on the IBM x3800, x3850, and x3950. Signed-off-by: Gary Hade Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/acpi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ arch/x86/pci/i386.c | 13 +++++++++++++ arch/x86/pci/pci.h | 1 + drivers/pci/probe.c | 4 ++-- 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index bc8a44bddaa7..1dd6f3fc077d 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -2,15 +2,57 @@ #include #include #include +#include #include #include "pci.h" +static int __devinit can_skip_ioresource_align(struct dmi_system_id *d) +{ + pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; + printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident); + return 0; +} + +static struct dmi_system_id acpi_pciprobe_dmi_table[] = { +/* + * Systems where PCI IO resource ISA alignment can be skipped + * when the ISA enable bit in the bridge control is not set + */ + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3800", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3800"), + }, + }, + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3850", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3850"), + }, + }, + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3950"), + }, + }, + {} +}; + struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) { struct pci_bus *bus; struct pci_sysdata *sd; int pxm; + dmi_check_system(acpi_pciprobe_dmi_table); + /* Allocate per-root-bus (not per bus) arch-specific data. * TODO: leak; this memory is never freed. * It's arguable whether it's worth the trouble to care. diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index bcd2f94b732c..055187bc255a 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -33,6 +33,15 @@ #include "pci.h" +static int +skip_isa_ioresource_align(struct pci_dev *dev) { + + if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) && + (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_NO_ISA)) + return 1; + return 0; +} + /* * We need to avoid collisions with `mirrored' VGA ports * and other strange ISA hardware, so we always want the @@ -50,9 +59,13 @@ void pcibios_align_resource(void *data, struct resource *res, resource_size_t size, resource_size_t align) { + struct pci_dev *dev = data; + if (res->flags & IORESOURCE_IO) { resource_size_t start = res->start; + if (skip_isa_ioresource_align(dev)) + return; if (start & 0x300) { start = (start + 0x3ff) & ~0x3ff; res->start = start; diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 8c66f275756f..057f335fa3f6 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h @@ -26,6 +26,7 @@ #define PCI_ASSIGN_ROMS 0x1000 #define PCI_BIOS_IRQ_SCAN 0x2000 #define PCI_ASSIGN_ALL_BUSSES 0x4000 +#define PCI_CAN_SKIP_ISA_ALIGN 0x8000 extern unsigned int pci_probe; extern unsigned long pirq_table_addr; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 40e571d3c392..59d6c3092812 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -544,7 +544,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass goto out; child->primary = buses & 0xFF; child->subordinate = (buses >> 16) & 0xFF; - child->bridge_ctl = bctl; + child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; cmax = pci_scan_child_bus(child); if (cmax > max) @@ -597,7 +597,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); if (!is_cardbus) { - child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA; + child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; /* * Adjust subordinate busnr in parent buses. * We do this before scanning for children because From fd64cb4606cbdd592b7119e82341d4ae5b56f2cc Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Wed, 3 Oct 2007 15:56:30 -0700 Subject: [PATCH 2793/2804] PCI: avoid P2P prefetch window for expansion ROMs Avoid creating P2P prefetch window for expansion ROMs Because of the future possibility that P2P prefetch windows will contain address ranges above 4GB some BIOSes are providing space in the P2P non-prefetch windows for expansion ROMs. This is due to expansion ROM BAR 32-bit limitation. When expansion ROM BARs without BIOS assigned address(es) are currently found behind a P2P bridge, the kernel attempts to create a P2P prefetch window for them even though space for them has already been provided in the non-prefetch window. _CRS on some systems with certain resource conservation conscious BIOSes may not provide the extra 1MB or more memory resource needed for the expansion ROM motivated prefetch window causing resource allocation errors. This change corrects the problem by removing IORESOURCE_PREFETCH from the expansion ROM flags initialization. It also removes IORESOURCE_CACHEABLE which seems inappropriate if only non-cacheable memory is available. Signed-off-by: Gary Hade Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 59d6c3092812..3112024bdc2a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -276,8 +276,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK); if (sz) { res->flags = (l & IORESOURCE_ROM_ENABLE) | - IORESOURCE_MEM | IORESOURCE_PREFETCH | - IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + IORESOURCE_MEM | IORESOURCE_READONLY; res->start = l & PCI_ROM_ADDRESS_MASK; res->end = res->start + (unsigned long) sz; } From 62f420f828249f686aaae949ac3439d1304a759a Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Wed, 3 Oct 2007 15:56:51 -0700 Subject: [PATCH 2794/2804] PCI: use _CRS for PCI resource allocation Use _CRS for PCI resource allocation This patch resolves an issue where incorrect PCI memory and i/o ranges are being assigned to hotplugged PCI devices on some IBM systems. The resource mis-allocation not only makes the PCI device unuseable but often makes the entire system unuseable due to resulting machine checks. The hotplug capable PCI slots on the affected systems are not located under a standard P2P bridge but are instead located under PCI root bridges or subtractive decode P2P bridges. For example, the IBM x3850 contains 2 hotplug capable PCI-X slots and 4 hotplug capable PCIe slots with the PCI-X slots each located under a PCI root bridge and the PCIe slots each located under a subtractive decode P2P bridge. The current i386/x86_64 PCI resource allocation code does not use _CRS returned resource information. No other resource information source is available for slots that are not below a standard P2P bridge so incorrect ranges are being allocated from e820 hole causing the bad result. This patch causes the kernel to use _CRS returned resource info. It is roughly based on a change provided by Matthew Wilcox for the ia64 kernel in 2005. Due to possible buggy BIOS factor and possible yet to be discovered kernel issues the function is disabled by default and can be enabled with pci=use_crs. Signed-off-by: Gary Hade Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 2 + arch/x86/pci/acpi.c | 139 ++++++++++++++++++++++++++++ arch/x86/pci/common.c | 3 + arch/x86/pci/pci.h | 1 + 4 files changed, 145 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 3f0173f45019..e9acd5540d29 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1318,6 +1318,8 @@ and is between 256 and 4096 characters. It is defined in the file IRQ routing is enabled. noacpi [X86-32] Do not use ACPI for IRQ routing or for PCI scanning. + use_crs [X86-32] Use _CRS for PCI resource + allocation. routeirq Do IRQ routing for all PCI devices. This is normally done in pci_enable_device(), so this option is a temporary workaround diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 1dd6f3fc077d..c6fd3a6afa42 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -45,6 +45,142 @@ static struct dmi_system_id acpi_pciprobe_dmi_table[] = { {} }; +struct pci_root_info { + char *name; + unsigned int res_num; + struct resource *res; + struct pci_bus *bus; + int busnum; +}; + +static acpi_status +resource_to_addr(struct acpi_resource *resource, + struct acpi_resource_address64 *addr) +{ + acpi_status status; + + status = acpi_resource_to_address64(resource, addr); + if (ACPI_SUCCESS(status) && + (addr->resource_type == ACPI_MEMORY_RANGE || + addr->resource_type == ACPI_IO_RANGE) && + addr->address_length > 0 && + addr->producer_consumer == ACPI_PRODUCER) { + return AE_OK; + } + return AE_ERROR; +} + +static acpi_status +count_resource(struct acpi_resource *acpi_res, void *data) +{ + struct pci_root_info *info = data; + struct acpi_resource_address64 addr; + acpi_status status; + + status = resource_to_addr(acpi_res, &addr); + if (ACPI_SUCCESS(status)) + info->res_num++; + return AE_OK; +} + +static acpi_status +setup_resource(struct acpi_resource *acpi_res, void *data) +{ + struct pci_root_info *info = data; + struct resource *res; + struct acpi_resource_address64 addr; + acpi_status status; + unsigned long flags; + struct resource *root; + + status = resource_to_addr(acpi_res, &addr); + if (!ACPI_SUCCESS(status)) + return AE_OK; + + if (addr.resource_type == ACPI_MEMORY_RANGE) { + root = &iomem_resource; + flags = IORESOURCE_MEM; + if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY) + flags |= IORESOURCE_PREFETCH; + } else if (addr.resource_type == ACPI_IO_RANGE) { + root = &ioport_resource; + flags = IORESOURCE_IO; + } else + return AE_OK; + + res = &info->res[info->res_num]; + res->name = info->name; + res->flags = flags; + res->start = addr.minimum + addr.translation_offset; + res->end = res->start + addr.address_length - 1; + res->child = NULL; + + if (insert_resource(root, res)) { + printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx " + "from %s for %s\n", (unsigned long) res->start, + (unsigned long) res->end, root->name, info->name); + } else { + info->bus->resource[info->res_num] = res; + info->res_num++; + } + return AE_OK; +} + +static void +adjust_transparent_bridge_resources(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + int i; + u16 class = dev->class >> 8; + + if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) { + for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) + dev->subordinate->resource[i] = + dev->bus->resource[i - 3]; + } + } +} + +static void +get_current_resources(struct acpi_device *device, int busnum, + struct pci_bus *bus) +{ + struct pci_root_info info; + size_t size; + + info.bus = bus; + info.res_num = 0; + acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, + &info); + if (!info.res_num) + return; + + size = sizeof(*info.res) * info.res_num; + info.res = kmalloc(size, GFP_KERNEL); + if (!info.res) + goto res_alloc_fail; + + info.name = kmalloc(12, GFP_KERNEL); + if (!info.name) + goto name_alloc_fail; + sprintf(info.name, "PCI Bus #%02x", busnum); + + info.res_num = 0; + acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, + &info); + if (info.res_num) + adjust_transparent_bridge_resources(bus); + + return; + +name_alloc_fail: + kfree(info.res); +res_alloc_fail: + return; +} + struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) { struct pci_bus *bus; @@ -89,6 +225,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do } } #endif + + if (bus && (pci_probe & PCI_USE__CRS)) + get_current_resources(device, busnum, bus); return bus; } diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 7c4d75e3c5f3..7d6a9a5aa7cd 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -436,6 +436,9 @@ char * __devinit pcibios_setup(char *str) } else if (!strcmp(str, "assign-busses")) { pci_probe |= PCI_ASSIGN_ALL_BUSSES; return NULL; + } else if (!strcmp(str, "use_crs")) { + pci_probe |= PCI_USE__CRS; + return NULL; } else if (!strcmp(str, "routeirq")) { pci_routeirq = 1; return NULL; diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 057f335fa3f6..ac56d3916c50 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h @@ -27,6 +27,7 @@ #define PCI_BIOS_IRQ_SCAN 0x2000 #define PCI_ASSIGN_ALL_BUSSES 0x4000 #define PCI_CAN_SKIP_ISA_ALIGN 0x8000 +#define PCI_USE__CRS 0x10000 extern unsigned int pci_probe; extern unsigned long pirq_table_addr; From 11949255d9433ea6c0908b7390ec4faecd1d4cf0 Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Mon, 8 Oct 2007 16:24:16 -0700 Subject: [PATCH 2795/2804] PCI: modify PCI bridge control ISA flag for clarity Modify PCI Bridge Control ISA flag for clarity This patch changes PCI_BRIDGE_CTL_NO_ISA to PCI_BRIDGE_CTL_ISA and modifies it's clarifying comment and locations where used. The change reduces the chance of future confusion since it makes the set/unset meaning of the bit the same in both the bridge control register and bridge_ctl field of the pci_bus struct. Signed-off-by: Gary Hade Acked-by: Linas Vepstas Cc: Ivan Kokshaysky Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/i386.c | 2 +- drivers/pci/probe.c | 4 ++-- include/linux/pci_regs.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 055187bc255a..42ba0e2da1a0 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -37,7 +37,7 @@ static int skip_isa_ioresource_align(struct pci_dev *dev) { if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) && - (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_NO_ISA)) + !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA)) return 1; return 0; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3112024bdc2a..5db6b6690b59 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -543,7 +543,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass goto out; child->primary = buses & 0xFF; child->subordinate = (buses >> 16) & 0xFF; - child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; + child->bridge_ctl = bctl; cmax = pci_scan_child_bus(child); if (cmax > max) @@ -596,7 +596,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); if (!is_cardbus) { - child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; + child->bridge_ctl = bctl; /* * Adjust subordinate busnr in parent buses. * We do this before scanning for children because diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 4a24ee368a11..c1914a8b94a9 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -147,7 +147,7 @@ #define PCI_BRIDGE_CONTROL 0x3e #define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ #define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ -#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */ +#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ #define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ #define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ #define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ From 32a2eea795643929a43cbbba00d8c4a176b309bf Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 11 Oct 2007 16:57:27 -0400 Subject: [PATCH 2796/2804] PCI: Add 'nodomains' boot option, and pci_domains_supported global * Introduce pci_domains_supported global, hardcoded to zero if !CONFIG_PCI_DOMAINS. * Introduce 'nodomains' boot option, which clears pci_domains_supported on platforms that enable it by default (x86, x86-64, and others when they are converted to use this). Signed-off-by: Jeff Garzik Cc: Andi Kleen Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 2 ++ drivers/pci/pci.c | 13 +++++++++++++ include/linux/pci.h | 7 +++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e9acd5540d29..d006e8b66ffa 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1274,6 +1274,8 @@ and is between 256 and 4096 characters. It is defined in the file noaer [PCIE] If the PCIEAER kernel config parameter is enabled, this kernel boot option can be used to disable the use of PCIE advanced error reporting. + nodomains [PCI] Disable support for multiple PCI + root domains (aka PCI segments, in ACPI-speak). nommconf [X86-32,X86_64] Disable use of MMCONFIG for PCI Configuration nomsi [MSI] If the PCI_MSI kernel config parameter is diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2dd5c282fabe..728b3c863d87 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -23,6 +23,10 @@ unsigned int pci_pm_d3_delay = 10; +#ifdef CONFIG_PCI_DOMAINS +int pci_domains_supported = 1; +#endif + #define DEFAULT_CARDBUS_IO_SIZE (256) #define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024) /* pci=cbmemsize=nnM,cbiosize=nn can override this */ @@ -1567,6 +1571,13 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags) return bars; } +static void __devinit pci_no_domains(void) +{ +#ifdef CONFIG_PCI_DOMAINS + pci_domains_supported = 0; +#endif +} + static int __devinit pci_init(void) { struct pci_dev *dev = NULL; @@ -1588,6 +1599,8 @@ static int __devinit pci_setup(char *str) pci_no_msi(); } else if (!strcmp(str, "noaer")) { pci_no_aer(); + } else if (!strcmp(str, "nodomains")) { + pci_no_domains(); } else if (!strncmp(str, "cbiosize=", 9)) { pci_cardbus_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "cbmemsize=", 10)) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 038a0dc7273a..768b93359f90 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -685,13 +685,16 @@ extern void pci_unblock_user_cfg_access(struct pci_dev *dev); * a PCI domain is defined to be a set of PCI busses which share * configuration space. */ -#ifndef CONFIG_PCI_DOMAINS +#ifdef CONFIG_PCI_DOMAINS +extern int pci_domains_supported; +#else +enum { pci_domains_supported = 0 }; static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } -#endif +#endif /* CONFIG_PCI_DOMAINS */ #else /* CONFIG_PCI is not enabled */ From a79e4198d1effbba040e9bf407a95fc9b3418789 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 11 Oct 2007 16:58:30 -0400 Subject: [PATCH 2797/2804] PCI: X86: Introduce and enable PCI domain support * fix bug in pci_read() and pci_write() which prevented PCI domain support from working (hardcoded domain 0). * unconditionally enable CONFIG_PCI_DOMAINS * implement pci_domain_nr() and pci_proc_domain(), as required of all arches when CONFIG_PCI_DOMAINS is enabled. * store domain in struct pci_sysdata, as assigned by ACPI * support "pci=nodomains" Signed-off-by: Jeff Garzik Cc: Andi Kleen Signed-off-by: Greg Kroah-Hartman --- arch/i386/Kconfig | 5 +++++ arch/x86/pci/acpi.c | 13 +++++++------ arch/x86/pci/common.c | 6 ++++-- arch/x86_64/Kconfig | 5 +++++ include/asm-x86/pci_32.h | 12 ++++++++++++ include/asm-x86/pci_64.h | 12 ++++++++++++ 6 files changed, 45 insertions(+), 8 deletions(-) diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 2d85e4b87307..515abb98d41d 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -1137,6 +1137,11 @@ config PCI_MMCONFIG depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY) default y +config PCI_DOMAINS + bool + depends on PCI + default y + source "drivers/pci/pcie/Kconfig" source "drivers/pci/Kconfig" diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index c6fd3a6afa42..27a391da9a98 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -189,6 +189,12 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do dmi_check_system(acpi_pciprobe_dmi_table); + if (domain && !pci_domains_supported) { + printk(KERN_WARNING "PCI: Multiple domains not supported " + "(dom %d, bus %d)\n", domain, busnum); + return NULL; + } + /* Allocate per-root-bus (not per bus) arch-specific data. * TODO: leak; this memory is never freed. * It's arguable whether it's worth the trouble to care. @@ -199,12 +205,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do return NULL; } - if (domain != 0) { - printk(KERN_WARNING "PCI: Multiple domains not supported\n"); - kfree(sd); - return NULL; - } - + sd->domain = domain; sd->node = -1; pxm = acpi_get_pxm(device->handle); diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 7d6a9a5aa7cd..2d71bbc411d2 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -29,12 +29,14 @@ struct pci_raw_ops *raw_pci_ops; static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - return raw_pci_ops->read(0, bus->number, devfn, where, size, value); + return raw_pci_ops->read(pci_domain_nr(bus), bus->number, + devfn, where, size, value); } static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - return raw_pci_ops->write(0, bus->number, devfn, where, size, value); + return raw_pci_ops->write(pci_domain_nr(bus), bus->number, + devfn, where, size, value); } struct pci_ops pci_root_ops = { diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index b1b98e614f7c..04d324cc72d8 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -724,6 +724,11 @@ config PCI_MMCONFIG bool "Support mmconfig PCI config space access" depends on PCI && ACPI +config PCI_DOMAINS + bool + depends on PCI + default y + source "drivers/pci/pcie/Kconfig" source "drivers/pci/Kconfig" diff --git a/include/asm-x86/pci_32.h b/include/asm-x86/pci_32.h index 4fcacc711385..0d91605cd1e2 100644 --- a/include/asm-x86/pci_32.h +++ b/include/asm-x86/pci_32.h @@ -5,12 +5,24 @@ #ifdef __KERNEL__ struct pci_sysdata { + int domain; /* PCI domain */ int node; /* NUMA node */ }; /* scan a bus after allocating a pci_sysdata for it */ extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); +static inline int pci_domain_nr(struct pci_bus *bus) +{ + struct pci_sysdata *sd = bus->sysdata; + return sd->domain; +} + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} + #include /* for struct page */ /* Can be used to override the logic in pci_scan_bus for skipping diff --git a/include/asm-x86/pci_64.h b/include/asm-x86/pci_64.h index 5da8cb0c0599..0a123d6a820f 100644 --- a/include/asm-x86/pci_64.h +++ b/include/asm-x86/pci_64.h @@ -6,12 +6,24 @@ #ifdef __KERNEL__ struct pci_sysdata { + int domain; /* PCI domain */ int node; /* NUMA node */ void* iommu; /* IOMMU private data */ }; extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); +static inline int pci_domain_nr(struct pci_bus *bus) +{ + struct pci_sysdata *sd = bus->sysdata; + return sd->domain; +} + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} + #ifdef CONFIG_CALGARY_IOMMU static inline void* pci_iommu(struct pci_bus *bus) { From f3e6f164c2389853432454c89b316a8ab7485e2f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 12 Oct 2007 14:07:23 -0700 Subject: [PATCH 2798/2804] PCI: merge almost all of pci_32.h and pci_64.h together It was just duplicated code... Signed-off-by: Greg Kroah-Hartman --- include/asm-x86/pci.h | 90 ++++++++++++++++++++++++++++++++++++++++ include/asm-x86/pci_32.h | 70 ------------------------------- include/asm-x86/pci_64.h | 68 ------------------------------ 3 files changed, 90 insertions(+), 138 deletions(-) diff --git a/include/asm-x86/pci.h b/include/asm-x86/pci.h index a8cac8c2cde7..e88361966347 100644 --- a/include/asm-x86/pci.h +++ b/include/asm-x86/pci.h @@ -1,5 +1,95 @@ +#ifndef __x86_PCI_H +#define __x86_PCI_H + +#include /* for struct page */ +#include +#include +#include +#include +#include + + +#ifdef __KERNEL__ + +struct pci_sysdata { + int domain; /* PCI domain */ + int node; /* NUMA node */ +#ifdef CONFIG_X86_64 + void* iommu; /* IOMMU private data */ +#endif +}; + +/* scan a bus after allocating a pci_sysdata for it */ +extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); + +static inline int pci_domain_nr(struct pci_bus *bus) +{ + struct pci_sysdata *sd = bus->sysdata; + return sd->domain; +} + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} + + +/* Can be used to override the logic in pci_scan_bus for skipping + already-configured bus numbers - to be used for buggy BIOSes + or architectures with incomplete PCI setup by the loader */ + +#ifdef CONFIG_PCI +extern unsigned int pcibios_assign_all_busses(void); +#else +#define pcibios_assign_all_busses() 0 +#endif +#define pcibios_scan_all_fns(a, b) 0 + +extern unsigned long pci_mem_start; +#define PCIBIOS_MIN_IO 0x1000 +#define PCIBIOS_MIN_MEM (pci_mem_start) + +#define PCIBIOS_MIN_CARDBUS_IO 0x4000 + +void pcibios_config_init(void); +struct pci_bus * pcibios_scan_root(int bus); + +void pcibios_set_master(struct pci_dev *dev); +void pcibios_penalize_isa_irq(int irq, int active); +struct irq_routing_table *pcibios_get_irq_routing_table(void); +int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); + + +#define HAVE_PCI_MMAP +extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine); + + +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + + +#endif /* __KERNEL__ */ + #ifdef CONFIG_X86_32 # include "pci_32.h" #else # include "pci_64.h" +#endif + +/* implement the pci_ DMA API in terms of the generic device dma_ one */ +#include + +/* generic pci stuff */ +#include + + + #endif diff --git a/include/asm-x86/pci_32.h b/include/asm-x86/pci_32.h index 0d91605cd1e2..8c4c3a0368e2 100644 --- a/include/asm-x86/pci_32.h +++ b/include/asm-x86/pci_32.h @@ -4,62 +4,11 @@ #ifdef __KERNEL__ -struct pci_sysdata { - int domain; /* PCI domain */ - int node; /* NUMA node */ -}; - -/* scan a bus after allocating a pci_sysdata for it */ -extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); - -static inline int pci_domain_nr(struct pci_bus *bus) -{ - struct pci_sysdata *sd = bus->sysdata; - return sd->domain; -} - -static inline int pci_proc_domain(struct pci_bus *bus) -{ - return pci_domain_nr(bus); -} - -#include /* for struct page */ - -/* Can be used to override the logic in pci_scan_bus for skipping - already-configured bus numbers - to be used for buggy BIOSes - or architectures with incomplete PCI setup by the loader */ - -#ifdef CONFIG_PCI -extern unsigned int pcibios_assign_all_busses(void); -#else -#define pcibios_assign_all_busses() 0 -#endif -#define pcibios_scan_all_fns(a, b) 0 - -extern unsigned long pci_mem_start; -#define PCIBIOS_MIN_IO 0x1000 -#define PCIBIOS_MIN_MEM (pci_mem_start) - -#define PCIBIOS_MIN_CARDBUS_IO 0x4000 - -void pcibios_config_init(void); -struct pci_bus * pcibios_scan_root(int bus); - -void pcibios_set_master(struct pci_dev *dev); -void pcibios_penalize_isa_irq(int irq, int active); -struct irq_routing_table *pcibios_get_irq_routing_table(void); -int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); /* Dynamic DMA mapping stuff. * i386 has everything mapped statically. */ -#include -#include -#include -#include -#include - struct pci_dev; /* The PCI address space does equal the physical memory @@ -76,27 +25,8 @@ struct pci_dev; #define pci_unmap_len(PTR, LEN_NAME) (0) #define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) -#define HAVE_PCI_MMAP -extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, int write_combine); - - -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif #endif /* __KERNEL__ */ -/* implement the pci_ DMA API in terms of the generic device dma_ one */ -#include - -/* generic pci stuff */ -#include #endif /* __i386_PCI_H */ diff --git a/include/asm-x86/pci_64.h b/include/asm-x86/pci_64.h index 0a123d6a820f..9baa46d9f594 100644 --- a/include/asm-x86/pci_64.h +++ b/include/asm-x86/pci_64.h @@ -1,28 +1,9 @@ #ifndef __x8664_PCI_H #define __x8664_PCI_H -#include #ifdef __KERNEL__ -struct pci_sysdata { - int domain; /* PCI domain */ - int node; /* NUMA node */ - void* iommu; /* IOMMU private data */ -}; - -extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); - -static inline int pci_domain_nr(struct pci_bus *bus) -{ - struct pci_sysdata *sd = bus->sysdata; - return sd->domain; -} - -static inline int pci_proc_domain(struct pci_bus *bus) -{ - return pci_domain_nr(bus); -} #ifdef CONFIG_CALGARY_IOMMU static inline void* pci_iommu(struct pci_bus *bus) @@ -38,40 +19,11 @@ static inline void set_pci_iommu(struct pci_bus *bus, void *val) } #endif /* CONFIG_CALGARY_IOMMU */ -#include /* for struct page */ -/* Can be used to override the logic in pci_scan_bus for skipping - already-configured bus numbers - to be used for buggy BIOSes - or architectures with incomplete PCI setup by the loader */ - -#ifdef CONFIG_PCI -extern unsigned int pcibios_assign_all_busses(void); -#else -#define pcibios_assign_all_busses() 0 -#endif -#define pcibios_scan_all_fns(a, b) 0 - -extern unsigned long pci_mem_start; -#define PCIBIOS_MIN_IO 0x1000 -#define PCIBIOS_MIN_MEM (pci_mem_start) - -#define PCIBIOS_MIN_CARDBUS_IO 0x4000 - -void pcibios_config_init(void); -struct pci_bus * pcibios_scan_root(int bus); extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value); extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value); -void pcibios_set_master(struct pci_dev *dev); -void pcibios_penalize_isa_irq(int irq, int active); -struct irq_routing_table *pcibios_get_irq_routing_table(void); -int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); -#include -#include -#include -#include -#include extern void pci_iommu_alloc(void); extern int iommu_setup(char *opt); @@ -112,27 +64,7 @@ extern int iommu_setup(char *opt); #endif -#include - -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - -#define HAVE_PCI_MMAP -extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, int write_combine); - #endif /* __KERNEL__ */ -/* generic pci stuff */ -#ifdef CONFIG_PCI -#include -#endif #endif /* __x8664_PCI_H */ From 8bd0983e05757e5c1f7a3342cd09badae93c167d Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 13 Oct 2007 01:01:08 +0200 Subject: [PATCH 2799/2804] Update maintainers file Since there is no x86-64 architecture anymore it cannot be maintained. Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- MAINTAINERS | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 60e649ff6fdc..0fdb8a50b921 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1776,8 +1776,8 @@ M: venkatesh.pallipadi@intel.com S: Maintained HPET: x86_64 -P: Andi Kleen and Vojtech Pavlik -M: andi@firstfloor.org and vojtech@suse.cz +P: Vojtech Pavlik +M: vojtech@suse.cz S: Maintained HPET: ACPI hpet.c @@ -4265,14 +4265,6 @@ P: Ingo Molnar M: mingo@redhat.com S: Maintained -X86-64 port -P: Andi Kleen -M: ak@suse.de -L: discuss@x86-64.org -W: http://www.x86-64.org -T: quilt ftp://ftp.firstfloor.org/pub/ak/x86_64/quilt-current -S: Maintained - YAM DRIVER FOR AX.25 P: Jean-Paul Roubelat M: jpr@f6fbb.org From 2b9e0aae1d50e880c58d46788e5e3ebd89d75d62 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 12 Oct 2007 17:58:36 -0700 Subject: [PATCH 2800/2804] Only enable BLOCK_COMPAT if COMPAT is needed IOW, it needs to depend on both CONFIG_BLOCK and CONFIG_COMPAT. Signed-off-by: Linus Torvalds --- block/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/block/Kconfig b/block/Kconfig index e10895647f72..9bda7bc80307 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -62,10 +62,11 @@ config BLK_DEV_BSG protocols (e.g. Task Management Functions and SMP in Serial Attached SCSI). -config BLOCK_COMPAT - bool - default y - endif # BLOCK +config BLOCK_COMPAT + bool + depends on BLOCK && COMPAT + default y + source block/Kconfig.iosched From df1bdc0667eb3132fe60b3562347ca9133694ee0 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sat, 13 Oct 2007 03:06:00 +0200 Subject: [PATCH 2801/2804] x86: fence oostores on 64-bit movnt* instructions are not strongly ordered with respect to other stores, so if we are to assume stores are strongly ordered in the rest of the 64 bit code, we must fence these off (see similar examples in 32 bit code). [ The AMD memory ordering document seems to say that nontemporal stores can also pass earlier regular stores, so maybe we need sfences _before_ movnt* everywhere too? ] Signed-off-by: Nick Piggin Signed-off-by: Linus Torvalds --- arch/x86/lib/copy_user_nocache_64.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S index 4620efb12f13..5196762b3b0e 100644 --- a/arch/x86/lib/copy_user_nocache_64.S +++ b/arch/x86/lib/copy_user_nocache_64.S @@ -117,6 +117,7 @@ ENTRY(__copy_user_nocache) popq %rbx CFI_ADJUST_CFA_OFFSET -8 CFI_RESTORE rbx + sfence ret CFI_RESTORE_STATE From 4071c718555d955a35e9651f77086096ad87d498 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sat, 13 Oct 2007 03:06:55 +0200 Subject: [PATCH 2802/2804] x86: fix IO write barrier wmb() on x86 must always include a barrier, because stores can go out of order in many cases when dealing with devices (eg. WC memory). Signed-off-by: Nick Piggin Signed-off-by: Linus Torvalds --- include/asm-x86/system_32.h | 15 ++++++--------- include/asm-x86/system_64.h | 6 +----- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/include/asm-x86/system_32.h b/include/asm-x86/system_32.h index d69ba937e092..8b15bd3057c9 100644 --- a/include/asm-x86/system_32.h +++ b/include/asm-x86/system_32.h @@ -216,6 +216,7 @@ static inline unsigned long get_limit(unsigned long segment) #define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) #define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2) +#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM) /** * read_barrier_depends - Flush all pending reads that subsequents reads @@ -271,18 +272,14 @@ static inline unsigned long get_limit(unsigned long segment) #define read_barrier_depends() do { } while(0) -#ifdef CONFIG_X86_OOSTORE -/* Actually there are no OOO store capable CPUs for now that do SSE, - but make it already an possibility. */ -#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM) -#else -#define wmb() __asm__ __volatile__ ("": : :"memory") -#endif - #ifdef CONFIG_SMP #define smp_mb() mb() #define smp_rmb() rmb() -#define smp_wmb() wmb() +#ifdef CONFIG_X86_OOSTORE +# define smp_wmb() wmb() +#else +# define smp_wmb() barrier() +#endif #define smp_read_barrier_depends() read_barrier_depends() #define set_mb(var, value) do { (void) xchg(&var, value); } while (0) #else diff --git a/include/asm-x86/system_64.h b/include/asm-x86/system_64.h index 02175aa1d16a..eff730b11926 100644 --- a/include/asm-x86/system_64.h +++ b/include/asm-x86/system_64.h @@ -159,12 +159,8 @@ static inline void write_cr8(unsigned long val) */ #define mb() asm volatile("mfence":::"memory") #define rmb() asm volatile("lfence":::"memory") - -#ifdef CONFIG_UNORDERED_IO #define wmb() asm volatile("sfence" ::: "memory") -#else -#define wmb() asm volatile("" ::: "memory") -#endif + #define read_barrier_depends() do {} while(0) #define set_mb(var, value) do { (void) xchg(&var, value); } while (0) From b6c7347fffa655a3000d9d41640d222c19fc3065 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sat, 13 Oct 2007 03:07:38 +0200 Subject: [PATCH 2803/2804] x86: optimise barriers According to latest memory ordering specification documents from Intel and AMD, both manufacturers are committed to in-order loads from cacheable memory for the x86 architecture. Hence, smp_rmb() may be a simple barrier. Also according to those documents, and according to existing practice in Linux (eg. spin_unlock doesn't enforce ordering), stores to cacheable memory are visible in program order too. Special string stores are safe -- their constituent stores may be out of order, but they must complete in order WRT surrounding stores. Nontemporal stores to WB memory can go out of order, and so they should be fenced explicitly to make them appear in-order WRT other stores. Hence, smp_wmb() may be a simple barrier. http://developer.intel.com/products/processor/manuals/318147.pdf http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24593.pdf In userspace microbenchmarks on a core2 system, fence instructions range anywhere from around 15 cycles to 50, which may not be totally insignificant in performance critical paths (code size will go down too). However the primary motivation for this is to have the canonical barrier implementation for x86 architecture. smp_rmb on buggy pentium pros remains a locked op, which is apparently required. Signed-off-by: Nick Piggin Signed-off-by: Linus Torvalds --- include/asm-x86/system_32.h | 6 +++++- include/asm-x86/system_64.h | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/asm-x86/system_32.h b/include/asm-x86/system_32.h index 8b15bd3057c9..e7e5d426fef5 100644 --- a/include/asm-x86/system_32.h +++ b/include/asm-x86/system_32.h @@ -274,7 +274,11 @@ static inline unsigned long get_limit(unsigned long segment) #ifdef CONFIG_SMP #define smp_mb() mb() -#define smp_rmb() rmb() +#ifdef CONFIG_X86_PPRO_FENCE +# define smp_rmb() rmb() +#else +# define smp_rmb() barrier() +#endif #ifdef CONFIG_X86_OOSTORE # define smp_wmb() wmb() #else diff --git a/include/asm-x86/system_64.h b/include/asm-x86/system_64.h index eff730b11926..5022aecc333d 100644 --- a/include/asm-x86/system_64.h +++ b/include/asm-x86/system_64.h @@ -141,8 +141,8 @@ static inline void write_cr8(unsigned long val) #ifdef CONFIG_SMP #define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() wmb() +#define smp_rmb() barrier() +#define smp_wmb() barrier() #define smp_read_barrier_depends() do {} while(0) #else #define smp_mb() barrier() From 752097cec53eea111d087c545179b421e2bde98a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 12 Oct 2007 22:34:40 -0400 Subject: [PATCH 2804/2804] x86/pci/acpi: fix DMI const-ification fallout Fix DMI const-ification fallout that appeared when merging subsystem trees. Signed-off-by: Jeff Garzik Signed-off-by: Linus Torvalds --- arch/x86/pci/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 27a391da9a98..2d88f7c6d6ac 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -6,7 +6,7 @@ #include #include "pci.h" -static int __devinit can_skip_ioresource_align(struct dmi_system_id *d) +static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d) { pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);